diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 50ab5538fc5..00000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,38 +0,0 @@ -version: "{build}" - -branches: - except: - - /^travis.*$/ - -clone_depth: 10 - -image: - - Visual Studio 2019 - -environment: - matrix: - - ARCH: x64 - CONFIG: Release - - ARCH: Win32 - CONFIG: Release - - ARCH: x64 - CONFIG: Debug - -build_script: - - md build - - cd build - - cmake -A %ARCH% -DPK3_QUIET_ZIPDIR=YES .. - - cmake --build . --config %CONFIG% -- -maxcpucount -verbosity:minimal - -after_build: - - set OUTPUT_DIR=%APPVEYOR_BUILD_FOLDER%\build\%CONFIG%\ - - 7z a ..\gzdoom.zip "%OUTPUT_DIR%gzdoom.exe" "%OUTPUT_DIR%*.pk3" - -artifacts: - - path: gzdoom.zip - -notifications: - - provider: Email - on_build_success: false - on_build_failure: false - on_build_status_changed: false diff --git a/.devcontainer/GZDoom.dockerfile b/.devcontainer/GZDoom.dockerfile new file mode 100644 index 00000000000..da2440913d2 --- /dev/null +++ b/.devcontainer/GZDoom.dockerfile @@ -0,0 +1,16 @@ +FROM ubuntu:latest +LABEL org.opencontainers.image.authors="CandiceJoy " +LABEL author="CandiceJoy" +LABEL description="GZDoom compilation image (Designed for GZDoom 4.11pre)" +LABEL verion="4.11pre" + +# Update these as needed +ENV GZ_ZMUSIC_URL="https://github.com/coelckers/ZMusic.git" +ENV GZ_ZMUSIC_COMMIT="75d2994b4b1fd6891b20819375075a2976ee34de" +ENV GZ_PACKAGES="build-essential git cmake libsdl2-dev libvpx-dev" + +# Update package lists and install package-based build dependencies +RUN apt-get update; apt-get install -y $GZ_PACKAGES + +# Install ZMusic +RUN git clone $GZ_ZMUSIC_URL; git reset --hard $GZ_ZMUSIC_COMMIT; cd ZMusic; cmake . -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr; make; make install diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..9bcbdd2f9f5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,6 @@ +{ + "build":{ "dockerfile": "GZDoom.dockerfile" }, + "name": "GZDoom", + "features": { + } +} diff --git a/.gitattributes b/.gitattributes index 949b845f178..a01ef98a581 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,10 +12,10 @@ *.asm text *.S text -*.vcproj text eol=crlf -*.sln text eol=crlf -*.bat text eol=crlf -*.rc text eol=crlf +*.vcproj text +*.sln text +*.bat text +*.rc text *.txt text language.* text @@ -25,3 +25,4 @@ language.* text *.lmp binary *.flac binary *.dat binary +*.ico binary diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000000..7ed0af7ce69 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,124 @@ +name: Bug Report +description: File a Bug report +title: '[BUG] ' +labels: bug +#assignees: 'anonymous@temp' + +body: + - type: markdown + attributes: + value: | + ## Please fill out forms as cleanly as possible. + #### Make sure that you have + * properly edited & filled in the title of this bug report + - type: input + id: version + attributes: + label: GZDoom version + description: | + What version are you using? + Run `gzdoom --version` or check in the console in game. + Make sure to update to latest [release](https://github.com/coelckers/gzdoom/releases) version and test again before continuing. + placeholder: "ex: GZDoom 4.0.0, Git version, Branch, other" + validations: + required: false + - type: dropdown + id: gameid + attributes: + label: Which game are you running with GZDoom? + multiple: false + options: + - Doom + - Doom 2 + - Heretic + - Hexen + - Strife + - Other + validations: + required: false + - type: dropdown + id: OS + attributes: + label: What Operating System are you using? + multiple: false + options: + - Windows 11 + - Windows 10 + - Windows 8 + - Windows 7 + - Windows Other + - Mac OS + - Linux x86 + - Linux x86_64 + - Linux ARM (Raspberry Pi) + - Other + validations: + required: false + - type: input + id: os_detail + attributes: + label: Please describe your specific OS version + description: Other details + placeholder: "Windows 11 Home/Pro/Server/etc, Mac OSX version, Debian 10/11/etc, Ubuntu 18/20/etc, Arch, etc." + validations: + required: false + - type: input + id: hardware + attributes: + label: Relevant hardware info + description: Hardware + placeholder: "CPU, GPU, device brand/model: e.g. Intel, AMD, Nvidia, etc" + validations: + required: false + - type: checkboxes + id: checked + attributes: + label: Have you checked that no other similar issue already exists? + description: Searched issues before creating report? + options: + - label: I have searched and not found similar issues. + required: true + - type: textarea + id: description + attributes: + label: A clear and concise description of what the bug is. + description: Describe what happens, what software were you running? _Include a small mod demonstrating the bug, or a screenshot if possible_ + placeholder: "How & When does this occur?" + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce the behaviour. + description: How can we reproduce this? + placeholder: "Explain how to reproduce" + value: | + Explain how to reproduce + 1. + 2. + 3. + validations: + required: false + - type: textarea + id: config_file + attributes: + label: Your configuration + description: | + Share the config file(s) you've been using to run the program. (`gzdoom.ini`) + Please avoid pasting the full config, _use attachments or links_ in a [Gist](https://gist.github.com/) + placeholder: "example: cl_autorun=true" + render: ini # syntax highlighting + validations: + required: false + - type: textarea + id: log + attributes: + label: Provide a Log + description: Please avoid pasting the full log, _use attachments or links_ in a [Gist](https://gist.github.com/) + placeholder: "Copy & paste error log section or provide link" + validations: + required: false + - type: markdown + attributes: + value: | + * Make sure you have properly filled in the title of this bug report diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000000..60c7440fe58 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,107 @@ +name: Feature Request +description: Suggest an idea (a new feature or other improvement) for this project +title: '[Feature] ' +labels: enhancement +#assignees: 'anonymous@temp' + +body: + - type: markdown + attributes: + value: | + ## Please fill out forms as cleanly as possible. + #### Make sure that you have + * properly edited & filled in the title of this bug report + - type: input + id: version + attributes: + label: GZDoom version + description: | + What version are you using? + Run `gzdoom --version` or check in the console in game. + Make sure to update to latest [release](https://github.com/coelckers/gzdoom/releases) version and test again before continuing. + placeholder: "ex: GZDoom 4.0.0, Git version, Branch, other" + validations: + required: false + - type: dropdown + id: gameid + attributes: + label: Which game are you running with GZDoom? + multiple: false + options: + - Doom + - Doom 2 + - Heretic + - Hexen + - Strife + - Other + validations: + required: false + - type: dropdown + id: OS + attributes: + label: What Operating System are you using? + multiple: false + options: + - Windows 11 + - Windows 10 + - Windows 8 + - Windows 7 + - Windows Other + - Mac OS + - Linux x86 + - Linux x86_64 + - Linux ARM (Raspberry Pi) + - Other + validations: + required: false + - type: input + id: other + attributes: + label: If Other OS, please describe + description: Other details + placeholder: "Windows, Mac OSX version, Debian, Ubuntu, Arch, etc." + validations: + required: false + - type: input + id: hardware + attributes: + label: Relevant hardware info + description: Hardware + placeholder: "CPU, GPU, device brand/model: e.g. Intel, AMD, Nvidia, etc" + validations: + required: false + - type: textarea + id: related + attributes: + label: Is your feature request related to a problem? Please describe. + description: Related + placeholder: "Ex. I'm always frustrated when" + validations: + required: true + - type: textarea + id: solution + attributes: + label: Describe the solution you'd like + placeholder: "Ex. How can we make it better?" + validations: + required: false + - type: textarea + id: alternative + attributes: + label: Describe alternatives you've considered + description: A clear and concise description of any alternative solutions or features you've considered. + placeholder: "Similar idea or software" + validations: + required: false + - type: textarea + id: additional + attributes: + label: Add any other context or screenshots about the feature request here. + description: Screenshots or Links? + placeholder: "Ex. Screenshot or Link" + validations: + required: false + - type: markdown + attributes: + value: | + * Make sure you have properly filled in the title of this feature request diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml new file mode 100644 index 00000000000..885c3292102 --- /dev/null +++ b/.github/workflows/appimage.yml @@ -0,0 +1,53 @@ +name: Continuous Integration + +on: [push, pull_request] + +jobs: + build-appimage: + name: Linux Clang 12 | AppImage + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Install GZDoom dependencies + run: | + sudo apt-get update + sudo apt-get install clang-12 libsdl2-dev libvpx-dev libwebp-dev cmake -y + - name: Install appimage-builder dependencies + run: | + sudo apt-get install binutils coreutils desktop-file-utils fakeroot fuse libgdk-pixbuf2.0-dev patchelf -y + sudo apt-get install python3-pip python3-setuptools squashfs-tools strace util-linux zsync -y + sudo apt-get install imagemagick-6.q16hdri -y + - name: Install appimage-builder + run: | + python3 -m pip install --upgrade pip + pip install appimage-builder + - name: Build zmusic dependency + run: | + git clone -b 1.1.12 https://github.com/ZDoom/ZMusic.git zmusic_build + mkdir ./zmusic_build/build + cd ./zmusic_build/build + cmake -DCMAKE_BUILD_TYPE=Release .. + cmake --build . + cd ../../ + mkdir -p ./AppDir/zmusic/lib + mkdir ./AppDir/zmusic/include + mv ./zmusic_build/build/source/libzmusic* ./AppDir/zmusic/lib/ + mv ./zmusic_build/include/zmusic.h ./AppDir/zmusic/include/ + - name: Configure + run: cmake -B AppDir -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_PREFIX_PATH=`pwd`/AppDir/zmusic -DPK3_QUIET_ZIPDIR=ON -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 . + - name: Build + shell: bash + run: | + export MAKEFLAGS=--keep-going + cmake --build AppDir --config Release --parallel `nproc` + cp ./AppDir/zmusic/lib/* ./AppDir/ + mkdir -p ./AppDir/usr/share/icons + convert ./src/win32/icon1.ico[0] -flatten ./AppDir/usr/share/icons/game_icon.png + - name: Build AppImage + run: | + appimage-builder --skip-tests + - uses: actions/upload-artifact@v2 + with: + name: AppImage + path: './*.AppImage*' diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml new file mode 100644 index 00000000000..aa323c9399b --- /dev/null +++ b/.github/workflows/continuous_integration.yml @@ -0,0 +1,128 @@ +name: Continuous Integration + +on: [push, pull_request] + +jobs: + build: + name: ${{ matrix.config.name }} | ${{ matrix.config.build_type }} + runs-on: ${{ matrix.config.os }} + strategy: + fail-fast: false + matrix: + config: + - name: Visual Studio 2022 + os: windows-2022 + extra_options: -DCMAKE_TOOLCHAIN_FILE=build/vcpkg/scripts/buildsystems/vcpkg.cmake + build_type: Release + + - name: Visual Studio 2022 + os: windows-2022 + extra_options: -DCMAKE_TOOLCHAIN_FILE=build/vcpkg/scripts/buildsystems/vcpkg.cmake + build_type: Debug + + - name: Visual Studio 2019 + os: windows-2019 + extra_options: -DCMAKE_TOOLCHAIN_FILE=build/vcpkg/scripts/buildsystems/vcpkg.cmake + build_type: Release + + - name: macOS + os: macos-12 + deps_cmdline: brew install libvpx webp + build_type: Release + + - name: macOS + os: macos-12 + extra_options: -G Xcode -DDYN_OPENAL=OFF + deps_cmdline: brew install libvpx webp + build_type: Debug + + - name: Linux GCC 9 + os: ubuntu-22.04 + extra_options: -DCMAKE_C_COMPILER=gcc-9 -DCMAKE_CXX_COMPILER=g++-9 + deps_cmdline: sudo apt update && sudo apt install libsdl2-dev libvpx-dev libgtk2.0-dev libwebp-dev + build_type: RelWithDebInfo + + - name: Linux GCC 12 + os: ubuntu-22.04 + extra_options: -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 + deps_cmdline: sudo apt update && sudo apt install libsdl2-dev libvpx-dev libgtk-3-dev libwebp-dev + build_type: MinSizeRel + + - name: Linux Clang 11 + os: ubuntu-22.04 + extra_options: -DCMAKE_C_COMPILER=clang-11 -DCMAKE_CXX_COMPILER=clang++-11 -DDYN_OPENAL=OFF + deps_cmdline: sudo apt update && sudo apt install clang-11 libsdl2-dev libvpx-dev libopenal-dev libwebp-dev + build_type: Debug + + - name: Linux Clang 15 + os: ubuntu-22.04 + extra_options: -DCMAKE_C_COMPILER=clang-15 -DCMAKE_CXX_COMPILER=clang++-15 + deps_cmdline: sudo apt update && sudo apt install clang-15 libsdl2-dev libvpx-dev libwebp-dev + build_type: Release + + steps: + - uses: actions/checkout@v4 + + - name: Install Dependencies + shell: bash + run: | + if [[ -n "${{ matrix.config.deps_cmdline }}" ]]; then + eval ${{ matrix.config.deps_cmdline }} + fi + mkdir build + if [[ "${{ runner.os }}" == 'macOS' ]]; then + export ZMUSIC_PACKAGE=zmusic-1.1.9-macos.tar.xz + elif [[ "${{ runner.os }}" == 'Linux' ]]; then + export ZMUSIC_PACKAGE=zmusic-1.1.9-linux.tar.xz + fi + if [[ -n "${ZMUSIC_PACKAGE}" ]]; then + cd build + wget -q "https://github.com/coelckers/gzdoom/releases/download/ci_deps/${ZMUSIC_PACKAGE}" + tar -xf "${ZMUSIC_PACKAGE}" + fi + + - name: Setup vcpkg + uses: lukka/run-vcpkg@v11 + if: runner.os == 'Windows' + with: + vcpkgDirectory: '${{ github.workspace }}/build/vcpkg' + vcpkgGitCommitId: '2c401863dd54a640aeb26ed736c55489c079323b' + + - name: Configure + shell: bash + run: | + cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DCMAKE_PREFIX_PATH=`pwd`/build/zmusic -DPK3_QUIET_ZIPDIR=ON ${{ matrix.config.extra_options }} . + + - name: Build + shell: bash + run: | + export MAKEFLAGS=--keep-going + cmake --build build --config ${{ matrix.config.build_type }} --parallel 3 + + - name: Create Package + if: runner.os == 'Windows' # Remove to make packages of all targets + shell: bash + run: | + cd build + mkdir package + if [[ "${{ runner.os }}" == 'Windows' ]]; then + cp ${{ matrix.config.build_type }}/gzdoom.exe ${{ matrix.config.build_type }}/*.pk3 package + elif [[ "${{ runner.os }}" == 'macOS' ]]; then + cp -r gzdoom.app package + elif [[ "${{ runner.os }}" == 'Linux' ]]; then + cp gzdoom *.pk3 package + fi + + - name: Upload Package + if: runner.os == 'Windows' # Remove to store packages of all targets + uses: actions/upload-artifact@v3 + with: + path: build/package + name: ${{ matrix.config.name }} ${{ matrix.config.build_type }} + + - name: List Build Directory + if: always() + shell: bash + run: | + git status + ls -lR build diff --git a/.gitignore b/.gitignore index 5ef035d17b9..6e9e5b9de1e 100644 --- a/.gitignore +++ b/.gitignore @@ -18,10 +18,17 @@ /build /llvm .vs +.idea +.vscode /src/gl/unused /mapfiles_release/*.map +/AppDir +/appimage-build +*.AppImage .DS_Store /build_vc2017-32 /build2 /build_vc2019-64 /build_vc2019-32 +/build__ +gzdoom-crash.log diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1c0f22a191c..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,163 +0,0 @@ -language: cpp -dist: xenial -os: linux - -branches: - except: - - /^appveyor.*$/ - -git: - depth: 10 - -jobs: - include: - - name: "Xcode 8" - os: osx - osx_image: xcode8 - env: - - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_OSX_SYSROOT=macosx10.12" - - - name: "Xcode 11.3" - os: osx - osx_image: xcode11.3 - env: - - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release" - - - name: "Visual Studio 2017 32-bit" - os: windows - env: - - CMAKE_OPTIONS="-A Win32" - - - name: "Visual Studio 2017 64-bit" - os: windows - env: - - CMAKE_OPTIONS="-A x64" - - - name: "GCC 4.9" - compiler: gcc - env: - - GCC_VERSION=4.9 - - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized" - addons: - apt: - packages: - - g++-4.9 - - libsdl2-dev - - libgtk2.0-dev - - - name: "GCC 6" - compiler: gcc - env: - - GCC_VERSION=6 - - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized" - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - - libsdl2-dev - - libgtk2.0-dev - - - name: "GCC 8" - compiler: gcc - env: - - GCC_VERSION=8 - - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough" - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-8 - - libsdl2-dev - - libgtk-3-dev - - - name: "GCC 9" - compiler: gcc - env: - - GCC_VERSION=9 - - CMAKE_OPTIONS="-DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough" - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-9 - - libsdl2-dev - - - name: "Clang 3.6" - compiler: clang - env: - - CLANG_VERSION=3.6 - - CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo" - addons: - apt: - packages: - - clang-3.6 - - libsdl2-dev - - libgtk2.0-dev - - - name: "Clang 9" - os: linux - compiler: clang - env: - - CLANG_VERSION=9 - - CMAKE_OPTIONS="-DDYN_OPENAL=NO -DDYN_SNDFILE=NO -DDYN_MPG123=NO -DDYN_FLUIDSYNTH=NO" - addons: - apt: - sources: - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - packages: - - clang-9 - - libsdl2-dev - - libgme-dev - - libopenal-dev - - libmpg123-dev - - libsndfile-dev - - libfluidsynth-dev - - libgtk-3-dev - -before_install: - - if [ -n "$GCC_VERSION" ]; then export CC="gcc-${GCC_VERSION}" CXX="g++-${GCC_VERSION}"; fi - - if [ -n "$CLANG_VERSION" ]; then export CC="clang-${CLANG_VERSION}" CXX="clang++-${CLANG_VERSION}"; fi - - $CC --version - - $CXX --version - -before_script: - - mkdir build - - cd build - - git clone https://github.com/coelckers/ZMusic.git - - cd ZMusic - - git checkout 1.0.0 - - cd .. - - mkdir zmusic_build - - cd zmusic_build - - cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=`pwd`/../zmusic_install ../ZMusic - - | - if [[ $TRAVIS_OS_NAME == 'windows' ]]; then - cmake --build . --target install --config Release -- -maxcpucount -verbosity:minimal - else - cmake --build . --target install -- --jobs=2 --keep-going - fi - - cd .. - -script: - - | - cmake ${CMAKE_OPTIONS} \ - -DCMAKE_PREFIX_PATH=`pwd`/zmusic_install \ - -DFORCE_INTERNAL_ZLIB=YES \ - -DFORCE_INTERNAL_JPEG=YES \ - -DFORCE_INTERNAL_BZIP2=YES \ - -DPK3_QUIET_ZIPDIR=YES \ - .. - - | - if [[ $TRAVIS_OS_NAME == 'windows' ]]; then - cmake --build . --config Release -- -maxcpucount -verbosity:minimal - else - cmake --build . -- --jobs=2 --keep-going - fi - -notifications: - email: false diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml new file mode 100644 index 00000000000..6f9ebcc3bd0 --- /dev/null +++ b/AppImageBuilder.yml @@ -0,0 +1,45 @@ +# appimage-builder recipe see https://appimage-builder.readthedocs.io for details +version: 1 +AppDir: + path: ./AppDir + app_info: + id: com.GZDoom.app + name: GZDoom + icon: game_icon.png + version: latest + exec: ./gzdoom + exec_args: $@ + apt: + arch: amd64 + allow_unauthenticated: true + sources: + - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy main restricted + - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates main restricted + include: [] + files: + include: [] + exclude: + - usr/share/man + - usr/share/doc/*/README.* + - usr/share/doc/*/changelog.* + - usr/share/doc/*/NEWS.* + - usr/share/doc/*/TODO.* + test: + fedora-30: + image: appimagecrafters/tests-env:fedora-30 + command: ./AppRun + debian-stable: + image: appimagecrafters/tests-env:debian-stable + command: ./AppRun + archlinux-latest: + image: appimagecrafters/tests-env:archlinux-latest + command: ./AppRun + centos-7: + image: appimagecrafters/tests-env:centos-7 + command: ./AppRun + ubuntu-xenial: + image: appimagecrafters/tests-env:ubuntu-xenial + command: ./AppRun +AppImage: + arch: x86_64 + update-information: guess diff --git a/CMakeLists.txt b/CMakeLists.txt index cb7b6576417..0ac374e55b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,4 @@ -cmake_minimum_required( VERSION 2.8.7 ) -project(GZDoom) +cmake_minimum_required( VERSION 3.16 ) if( COMMAND cmake_policy ) if( POLICY CMP0011 ) @@ -8,8 +7,47 @@ if( COMMAND cmake_policy ) if( POLICY CMP0054 ) cmake_policy( SET CMP0054 NEW ) endif() + if ( POLICY CMP0067 ) + cmake_policy( SET CMP0067 NEW ) + endif() + if ( POLICY CMP0091 ) + cmake_policy( SET CMP0091 NEW ) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() +endif() + +if (LIBVPX_VCPKG) + list(APPEND VCPKG_MANIFEST_FEATURES "vcpkg-libvpx") endif() +if (OPENAL_SOFT_VCPKG) + list(APPEND VCPKG_MANIFEST_FEATURES "vcpkg-openal-soft") +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR (NOT CMAKE_SYSTEM_NAME AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")) + # Force static triplet on Windows + set(VCPKG_TARGET_TRIPLET "x64-windows-static") +endif() + +project(GZDoom) + +if (WIN32 AND VCPKG_TOOLCHAIN) + option(LIBVPX_VCPKG "Use libvpx from vcpkg" OFF) +endif() + +if (VCPKG_TOOLCHAIN) + option(OPENAL_SOFT_VCPKG "Use OpenAL from vcpkg" OFF) +endif() + +if (NOT VCPKG_TOOLCHAIN) + set(VCPKG_MANIFEST_FEATURES) +endif() + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + + list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ) include( FindPackageHandleStandardArgs ) @@ -66,7 +104,7 @@ function( add_pk3 PK3_NAME PK3_DIR ) # Phase 1: Create a list of all source files for this PK3 archive, except # for a couple of strife image file names that confuse CMake. file(GLOB_RECURSE PK3_SRCS ${PK3_DIR}/*) - # Exclude from the source list some gzdoom .png files with brackets in the + # Exclude from the source list some files with brackets in the # file names here, because they confuse CMake. # This only affects the list of source files shown in the IDE. # It does not actually remove the files from the PK3 archive. @@ -127,25 +165,25 @@ else() endif() # Replacement variables for a possible long list of C/C++ compilers compatible with GCC -if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" ) +if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" MATCHES "Clang" ) set( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE TRUE ) else() set( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE FALSE ) endif() -if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - set( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE TRUE ) +if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) + set( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE TRUE ) else() - set( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE FALSE ) + set( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE FALSE ) endif() -if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) +if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." ) endif() # Fast math flags, required by some subprojects set( ZD_FASTMATH_FLAG "" ) -if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) +if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( ZD_FASTMATH_FLAG "-ffast-math -ffp-contract=fast" ) elseif( MSVC ) set( ZD_FASTMATH_FLAG "/fp:fast" ) @@ -156,6 +194,7 @@ macro( use_fast_math ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ZD_FASTMATH_FLAG}" ) endmacro() + include( CheckFunctionExists ) macro( require_stricmp ) @@ -175,18 +214,19 @@ endmacro() option( NO_OPENAL "Disable OpenAL sound support" OFF ) find_package( BZip2 ) -find_package( JPEG ) -find_package( ZLIB ) +find_package( VPX ) include( TargetArch ) -target_architecture(ZDOOM_TARGET_ARCH) +target_architecture(TARGET_ARCHITECTURE) -if( ${ZDOOM_TARGET_ARCH} MATCHES "x86_64" ) +if( ${TARGET_ARCHITECTURE} MATCHES "x86_64" ) set( HAVE_VM_JIT ON ) - option (HAVE_VULKAN "Enable Vulkan support" ON) endif() +option (HAVE_VULKAN "Enable Vulkan support" ON) +option (HAVE_GLES2 "Enable GLES2 support" ON) + # no, we're not using external asmjit for now, we made too many modifications to our's. # if the asmjit author uses our changes then we'll update this. @@ -194,7 +234,6 @@ endif() # find_package( asmjit ) #endif() - if( MSVC ) # Eliminate unreferenced functions and data # Perform identical COMDAT folding @@ -203,68 +242,52 @@ if( MSVC ) # String pooling # Function-level linking # Disable run-time type information + set( ALL_C_FLAGS "/GF /Gy /permissive- /utf-8" ) + if ( HAVE_VULKAN ) - set( ALL_C_FLAGS "/GF /Gy /GR- /permissive- /DHAVE_VULKAN" ) - else() - set( ALL_C_FLAGS "/GF /Gy /GR- /permissive-" ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} /DHAVE_VULKAN" ) + endif() + + if ( HAVE_GLES2 ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} /DHAVE_GLES2" ) endif() # Use SSE 2 as minimum always as the true color drawers needs it for __vectorcall #set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2") # This is already the default -# if( CMAKE_SIZEOF_VOID_P MATCHES "4") -# # SSE2 option (to allow x87 in 32 bit and disallow extended feature sets which have not yet been checked for precision) -# option (ZDOOM_USE_SSE2 "Use SSE2 instruction set") -# if (ZDOOM_USE_SSE2) -# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2") -# else () -# if (MSVC_VERSION GREATER 1699) -# # On Visual C++ 2012 and later SSE2 is the default, so we need to switch it off explicitly -# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:IA32") -# endif () -# endif () -# else() -# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2") -# endif() # Avoid CRT DLL dependancies in release builds, optionally generate assembly output for checking crash locations. option( ZDOOM_GENERATE_ASM "Generate assembly output." OFF ) if( ZDOOM_GENERATE_ASM ) - set( REL_C_FLAGS "/MT /Oy /Oi /FAcs /GS-" ) + set( REL_C_FLAGS "/Oy /Oi /FAcs /GS-" ) else() - set( REL_C_FLAGS "/MT /Oy /Oi /GS-" ) + set( REL_C_FLAGS "/Oy /Oi /GS-" ) endif() # Debug allocations in debug builds - set( DEB_C_FLAGS "/D _CRTDBG_MAP_ALLOC /MTd" ) + set( DEB_C_FLAGS "/D _CRTDBG_MAP_ALLOC" ) # Disable warnings for unsecure CRT functions from VC8+ - set( ALL_C_FLAGS "${ALL_C_FLAGS} /wd4996 /DUNICODE /D_UNICODE /D_WIN32_WINNT=0x0600" ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} /DUNICODE /D_UNICODE /D_WIN32_WINNT=0x0600 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS" ) - # The CMake configurations set /GR and /MD by default, which conflict with our settings. - string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} ) - string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL} ) - string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ) string(REPLACE "/Ob1 " "/Ob2 " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ) - string(REPLACE "/MDd " " " CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG} ) - string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} ) - string(REPLACE "/MD " " " CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL} ) - string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO} ) - string(REPLACE "/MDd " " " CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG} ) - string(REPLACE " /GR" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ) else() set( REL_LINKER_FLAGS "" ) + set( ALL_C_FLAGS "-ffp-contract=off" ) + if ( HAVE_VULKAN ) - set( ALL_C_FLAGS "-ffp-contract=off -DHAVE_VULKAN" ) - else() - set( ALL_C_FLAGS "-ffp-contract=off" ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} -DHAVE_VULKAN" ) + endif() + + if ( HAVE_GLES2 ) + set( ALL_C_FLAGS "${ALL_C_FLAGS} -DHAVE_GLES2" ) endif() if ( UNIX ) include(CheckSymbolExists) - check_symbol_exists( "fts_set" "fts.h" HAVE_FTS ) + check_symbol_exists( "fts_set" "sys/types.h;sys/stat.h;fts.h" HAVE_FTS ) if ( NOT HAVE_FTS ) include ( FindPkgConfig ) pkg_check_modules( MUSL_FTS musl-fts ) @@ -281,13 +304,8 @@ else() if( APPLE ) - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9") - if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) - # With standard Apple tools -stdlib=libc++ needs to be specified in order to get - # C++11 support using SDKs 10.7 and 10.8. - set( CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}" ) - set( CMAKE_EXE_LINKER_FLAGS "-stdlib=libc++ ${CMAKE_EXE_LINKER_FLAGS}" ) - elseif( CMAKE_CXX_COMPILER_ID STREQUAL "GNU" ) + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13") + if( CMAKE_CXX_COMPILER_ID STREQUAL "GNU" ) # If we're compiling with a custom GCC on the Mac (which we know since g++-4.2 doesn't support C++11) statically link libgcc. set( ALL_C_FLAGS "-static-libgcc" ) endif() @@ -314,28 +332,21 @@ set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" ) -option(FORCE_INTERNAL_ZLIB "Use internal zlib") -option(FORCE_INTERNAL_JPEG "Use internal jpeg") option(FORCE_INTERNAL_BZIP2 "Use internal bzip2") option(FORCE_INTERNAL_ASMJIT "Use internal asmjit" ON) mark_as_advanced( FORCE_INTERNAL_ASMJIT ) if (HAVE_VULKAN) - add_subdirectory( libraries/glslang/glslang) - add_subdirectory( libraries/glslang/spirv ) - add_subdirectory( libraries/glslang/OGLCompilersDLL ) + add_subdirectory( libraries/ZVulkan ) endif() -if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB ) - message( STATUS "Using system zlib, includes found at ${ZLIB_INCLUDE_DIR}" ) -else() - message( STATUS "Using internal zlib" ) - set( SKIP_INSTALL_ALL TRUE ) # Avoid installing zlib alongside zdoom - add_subdirectory( libraries/zlib ) - set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib ) - set( ZLIB_LIBRARIES z ) - set( ZLIB_LIBRARY z ) -endif() +add_subdirectory( libraries/ZWidget ) +add_subdirectory( libraries/webp ) + +add_subdirectory( libraries/discordrpc EXCLUDE_FROM_ALL ) +set( DRPC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/discordrpc/include" ) +set( DRPC_LIBRARIES discord-rpc ) +set( DRPC_LIBRARY discord-rpc ) if( HAVE_VM_JIT AND UNIX ) check_symbol_exists( "backtrace" "execinfo.h" HAVE_BACKTRACE ) @@ -347,6 +358,7 @@ if( HAVE_VM_JIT AND UNIX ) else( HAVE_LIBEXECINFO ) set( HAVE_VM_JIT NO ) endif( HAVE_LIBEXECINFO ) + set( CMAKE_REQUIRED_FLAGS ) endif( NOT HAVE_BACKTRACE ) endif( HAVE_VM_JIT AND UNIX ) @@ -363,16 +375,6 @@ if( ${HAVE_VM_JIT} ) endif() endif() -if( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG ) - message( STATUS "Using system jpeg library, includes found at ${JPEG_INCLUDE_DIR}" ) -else() - message( STATUS "Using internal jpeg library" ) - add_subdirectory( libraries/jpeg ) - set( JPEG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/jpeg ) - set( JPEG_LIBRARIES jpeg ) - set( JPEG_LIBRARY jpeg ) -endif() - if( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 ) message( STATUS "Using system bzip2 library, includes found at ${BZIP2_INCLUDE_DIR}" ) else() @@ -383,7 +385,6 @@ else() set( BZIP2_LIBRARY bz2 ) endif() - set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/lzma/C" ) if( NOT CMAKE_CROSSCOMPILING ) @@ -405,12 +406,13 @@ install(DIRECTORY docs/ option( DYN_OPENAL "Dynamically load OpenAL" ON ) add_subdirectory( libraries/lzma ) +add_subdirectory( libraries/miniz ) add_subdirectory( tools ) -add_subdirectory( libraries/gdtoa ) add_subdirectory( wadsrc ) add_subdirectory( wadsrc_bm ) add_subdirectory( wadsrc_lights ) add_subdirectory( wadsrc_extra ) +add_subdirectory( wadsrc_widepix ) add_subdirectory( src ) if( NOT CMAKE_CROSSCOMPILING ) diff --git a/README.md b/README.md index f543f0d8d3f..7268877ea31 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Welcome to GZDoom! -[![Build Status](https://ci.appveyor.com/api/projects/status/github/coelckers/gzdoom?branch=master&svg=true)](https://ci.appveyor.com/project/coelckers/gzdoom) [![Build Status](https://travis-ci.org/coelckers/gzdoom.svg?branch=master)](https://travis-ci.org/coelckers/gzdoom) +[![Continuous Integration](https://github.com/ZDoom/gzdoom/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/ZDoom/gzdoom/actions/workflows/continuous_integration.yml) ## GZDoom is a modder-friendly OpenGL and Vulkan source port based on the DOOM engine -Copyright (c) 1998-2019 ZDoom + GZDoom teams, and contributors +Copyright (c) 1998-2023 ZDoom + GZDoom teams, and contributors Doom Source (c) 1997 id Software, Raven Software, and contributors Please see license files for individual contributor licenses -Special thanks to Coraline of the 3DGE team for allowing us to use her README.md as a template for this one. +Special thanks to Coraline of the EDGE team for allowing us to use her [README.md](https://github.com/3dfxdev/EDGE/blob/master/README.md) as a template for this one. ### Licensed under the GPL v3 ##### https://www.gnu.org/licenses/quick-guide-gplv3.en.html @@ -20,3 +20,9 @@ Special thanks to Coraline of the 3DGE team for allowing us to use her README.md To build GZDoom, please see the [wiki](https://zdoom.org/wiki/) and see the "Programmer's Corner" on the bottom-right corner of the page to build for your platform. +# Resources +- https://zdoom.org/ - Home Page +- https://forum.zdoom.org/ - Forum +- https://zdoom.org/wiki/ - Wiki +- https://dsc.gg/zdoom - Discord Server +- https://docs.google.com/spreadsheets/d/1pvwXEgytkor9SClCiDn4j5AH7FedyXS-ocCbsuQIXDU/edit?usp=sharing - Translation sheet (Google Docs) diff --git a/auto-setup-linux.sh b/auto-setup-linux.sh new file mode 100755 index 00000000000..a54677478d7 --- /dev/null +++ b/auto-setup-linux.sh @@ -0,0 +1,104 @@ +#!/bin/bash +#** +#** auto-setup-linux.sh +#** Automatic (easy) setup and build script for Linux +#** +#** Note that this script assumes you have both 'git' and 'cmake' installed properly and in your PATH! +#** This script also assumes you have installed a build system that cmake can automatically detect. +#** Such as GCC or Clang. Requires appropriate supporting libraries installed too! +#** Without these items, this script will FAIL! So make sure you have your build environment properly +#** set up in order for this script to succeed. +#** +#** The purpose of this script is to get someone easily going with a full working compile of GZDoom. +#** This allows anyone to make simple changes or tweaks to the engine as they see fit and easily +#** compile their own copy without having to follow complex instructions to get it working. +#** Every build environment is different, and every computer system is different - this should work +#** in most typical systems under Windows but it may fail under certain types of systems or conditions. +#** Not guaranteed to work and your mileage will vary. +#** +#** Prerequisite Packages used in testing (from Linux Mint-XFCE): +#** nasm autoconf libtool libsystemd-dev clang-15 libx11-dev libsdl2-dev libgtk-3-dev +#** +#**--------------------------------------------------------------------------- +#** Copyright 2024 Rachael Alexanderson and the GZDoom team +#** All rights reserved. +#** +#** Redistribution and use in source and binary forms, with or without +#** modification, are permitted provided that the following conditions +#** are met: +#** +#** 1. Redistributions of source code must retain the above copyright +#** notice, this list of conditions and the following disclaimer. +#** 2. 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. +#** 3. The name of the author may not be used to endorse or promote products +#** derived from this software without specific prior written permission. +#** +#** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +#**--------------------------------------------------------------------------- +#** + +# -- Always operate within the build folder +BUILDFOLDER=$(dirname "$0")/build + +if [ ! -d "$BUILDFOLDER" ]; then + mkdir "$BUILDFOLDER" +fi +cd "$BUILDFOLDER" + +if [ -d "vcpkg" ]; then + git -C ./vcpkg pull +fi +if [ ! -d "vcpkg" ]; then + git clone https://github.com/microsoft/vcpkg +fi +if [ -d "zmusic" ]; then + git -C ./zmusic fetch +fi +if [ ! -d "zmusic" ]; then + git clone https://github.com/zdoom/zmusic +fi +if [ -d "zmusic" ]; then + git -C ./zmusic checkout 1.1.12 +fi + +if [ ! -d "zmusic/build" ]; then + mkdir zmusic/build +fi +if [ ! -d "vcpkg_installed" ]; then + mkdir vcpkg_installed +fi + +cmake -S ./zmusic -B ./zmusic/build \ + -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_LIBSNDFILE=1 \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DVCPKG_INSTALLLED_DIR=../vcpkg_installed/ +pushd ./zmusic/build +make -j $(nproc) +popd + +cmake -S .. -B . \ + -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DVCPKG_INSTALLLED_DIR=./vcpkg_installed/ +make -j $(nproc); rc=$? + +# -- If successful, show the build +if [ $rc -eq 0 ]; then + if [ -f gzdoom ]; then + xdg-open . + fi +fi + +exit $rc diff --git a/auto-setup-windows-arm.cmd b/auto-setup-windows-arm.cmd new file mode 100644 index 00000000000..efefa157c8f --- /dev/null +++ b/auto-setup-windows-arm.cmd @@ -0,0 +1,89 @@ +@echo off +goto aftercopyright + +** +** auto-setup-windows-arm.cmd +** Automatic (easy) setup and build script for Windows ARM (cross compiling on x64) - please have a +** build of x64 in your build folder ready before executing this script! +** +** Note that this script assumes you have both 'git' and 'cmake' installed properly and in your PATH! +** This script also assumes you have installed a build system that cmake can automatically detect. +** Such as Visual Studio Community. Requires appropriate SDK installed too! +** Without these items, this script will FAIL! So make sure you have your build environment properly +** set up in order for this script to succeed. +** +** The purpose of this script is to get someone easily going with a full working compile of GZDoom. +** This allows anyone to make simple changes or tweaks to the engine as they see fit and easily +** compile their own copy without having to follow complex instructions to get it working. +** Every build environment is different, and every computer system is different - this should work +** in most typical systems under Windows but it may fail under certain types of systems or conditions. +** Not guaranteed to work and your mileage will vary. +** +**--------------------------------------------------------------------------- +** Copyright 2024 Rachael Alexanderson and the GZDoom team +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** + +:aftercopyright + + +setlocal +rem -- Always operate within the build-arm folder +if not exist "%~dp0\build-arm" mkdir "%~dp0\build-arm" +pushd "%~dp0\build-arm" + +if exist ..\build\vcpkg if exist ..\build\vcpkg\* git -C ../build/vcpkg pull +if not exist ..\build\vcpkg goto :nobuild + +if exist zmusic if exist zmusic\* git -C ./zmusic pull +if not exist zmusic git clone https://github.com/zdoom/zmusic + +mkdir "%~dp0\build-arm\zmusic\build" +mkdir "%~dp0\build-arm\vcpkg_installed" + +cmake -A ARM64 -S ./zmusic -B ./zmusic/build ^ + -DCMAKE_TOOLCHAIN_FILE=../../build/vcpkg/scripts/buildsystems/vcpkg.cmake ^ + -DVCPKG_LIBSNDFILE=1 ^ + -DVCPKG_INSTALLLED_DIR=../vcpkg_installed/ ^ + -DCMAKE_CROSSCOMPILING=TRUE +cmake --build ./zmusic/build --config Release -- -maxcpucount -verbosity:minimal + +cmake -A ARM64 -S .. -B . ^ + -DCMAKE_TOOLCHAIN_FILE=../build/vcpkg/scripts/buildsystems/vcpkg.cmake ^ + -DZMUSIC_INCLUDE_DIR=./zmusic/include ^ + -DZMUSIC_LIBRARIES=./zmusic/build/source/Release/zmusic.lib ^ + -DVCPKG_INSTALLLED_DIR=./vcpkg_installed/ ^ + -DFORCE_CROSSCOMPILE=TRUE ^ + -DIMPORT_EXECUTABLES=../build/ImportExecutables.cmake +cmake --build . --config RelWithDebInfo -- -maxcpucount -verbosity:minimal + +rem -- If successful, show the build +if exist RelWithDebInfo\gzdoom.exe explorer.exe RelWithDebInfo + +goto :eof +:nobuild +echo Please use auto-setup-windows.cmd to create an x64 build first! diff --git a/auto-setup-windows.cmd b/auto-setup-windows.cmd new file mode 100644 index 00000000000..38a16d8d735 --- /dev/null +++ b/auto-setup-windows.cmd @@ -0,0 +1,82 @@ +@echo off +goto aftercopyright + +** +** auto-setup-windows.cmd +** Automatic (easy) setup and build script for Windows +** +** Note that this script assumes you have both 'git' and 'cmake' installed properly and in your PATH! +** This script also assumes you have installed a build system that cmake can automatically detect. +** Such as Visual Studio Community. Requires appropriate SDK installed too! +** Without these items, this script will FAIL! So make sure you have your build environment properly +** set up in order for this script to succeed. +** +** The purpose of this script is to get someone easily going with a full working compile of GZDoom. +** This allows anyone to make simple changes or tweaks to the engine as they see fit and easily +** compile their own copy without having to follow complex instructions to get it working. +** Every build environment is different, and every computer system is different - this should work +** in most typical systems under Windows but it may fail under certain types of systems or conditions. +** Not guaranteed to work and your mileage will vary. +** +**--------------------------------------------------------------------------- +** Copyright 2023-2024 Rachael Alexanderson and the GZDoom team +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** + +:aftercopyright + +setlocal enableextensions + +rem -- Always operate within the build folder +if not exist "%~dp0\build" mkdir "%~dp0\build" +pushd "%~dp0\build" + +if exist vcpkg if exist vcpkg\* git -C ./vcpkg pull +if not exist vcpkg git clone https://github.com/microsoft/vcpkg + +if exist zmusic if exist vcpkg\* git -C ./zmusic pull +if not exist zmusic git clone https://github.com/zdoom/zmusic + +if not exist "%~dp0\build\zmusic\build" mkdir "%~dp0\build\zmusic\build" +if not exist "%~dp0\build\vcpkg_installed" mkdir "%~dp0\build\vcpkg_installed" + +cmake -A x64 -S ./zmusic -B ./zmusic/build ^ + -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ^ + -DVCPKG_LIBSNDFILE=1 ^ + -DVCPKG_INSTALLLED_DIR=../vcpkg_installed/ +cmake --build ./zmusic/build --config Release -- -maxcpucount -verbosity:minimal + +cmake -A x64 -S .. -B . ^ + -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake ^ + -DZMUSIC_INCLUDE_DIR=./zmusic/include ^ + -DZMUSIC_LIBRARIES=./zmusic/build/source/Release/zmusic.lib ^ + -DVCPKG_INSTALLLED_DIR=./vcpkg_installed/ +cmake --build . --config RelWithDebInfo -- -maxcpucount -verbosity:minimal + +rem -- If successful, show the build +if not errorlevel 1 if exist RelWithDebInfo\gzdoom.exe explorer.exe RelWithDebInfo + diff --git a/bin/windows/vpx/include/vpx/vp8.h b/bin/windows/vpx/include/vpx/vp8.h new file mode 100644 index 00000000000..8a035f97707 --- /dev/null +++ b/bin/windows/vpx/include/vpx/vp8.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/*!\defgroup vp8 VP8 + * \ingroup codecs + * VP8 is vpx's newest video compression algorithm that uses motion + * compensated prediction, Discrete Cosine Transform (DCT) coding of the + * prediction error signal and context dependent entropy coding techniques + * based on arithmetic principles. It features: + * - YUV 4:2:0 image format + * - Macro-block based coding (16x16 luma plus two 8x8 chroma) + * - 1/4 (1/8) pixel accuracy motion compensated prediction + * - 4x4 DCT transform + * - 128 level linear quantizer + * - In loop deblocking filter + * - Context-based entropy coding + * + * @{ + */ +/*!\file + * \brief Provides controls common to both the VP8 encoder and decoder. + */ +#ifndef VPX_VP8_H_ +#define VPX_VP8_H_ + +#include "./vpx_codec.h" +#include "./vpx_image.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*!\brief Control functions + * + * The set of macros define the control functions of VP8 interface + */ +enum vp8_com_control_id { + VP8_SET_REFERENCE = 1, /**< pass in an external frame into decoder to be used as reference frame */ + VP8_COPY_REFERENCE = 2, /**< get a copy of reference frame from the decoder */ + VP8_SET_POSTPROC = 3, /**< set the decoder's post processing settings */ + VP8_SET_DBG_COLOR_REF_FRAME = 4, /**< set the reference frames to color for each macroblock */ + VP8_SET_DBG_COLOR_MB_MODES = 5, /**< set which macro block modes to color */ + VP8_SET_DBG_COLOR_B_MODES = 6, /**< set which blocks modes to color */ + VP8_SET_DBG_DISPLAY_MV = 7, /**< set which motion vector modes to draw */ + + /* TODO(jkoleszar): The encoder incorrectly reuses some of these values (5+) + * for its control ids. These should be migrated to something like the + * VP8_DECODER_CTRL_ID_START range next time we're ready to break the ABI. + */ + VP9_GET_REFERENCE = 128, /**< get a pointer to a reference frame */ + VP8_COMMON_CTRL_ID_MAX, + VP8_DECODER_CTRL_ID_START = 256 +}; + +/*!\brief post process flags + * + * The set of macros define VP8 decoder post processing flags + */ +enum vp8_postproc_level { + VP8_NOFILTERING = 0, + VP8_DEBLOCK = 1 << 0, + VP8_DEMACROBLOCK = 1 << 1, + VP8_ADDNOISE = 1 << 2, + VP8_DEBUG_TXT_FRAME_INFO = 1 << 3, /**< print frame information */ + VP8_DEBUG_TXT_MBLK_MODES = 1 << 4, /**< print macro block modes over each macro block */ + VP8_DEBUG_TXT_DC_DIFF = 1 << 5, /**< print dc diff for each macro block */ + VP8_DEBUG_TXT_RATE_INFO = 1 << 6, /**< print video rate info (encoder only) */ + VP8_MFQE = 1 << 10 +}; + +/*!\brief post process flags + * + * This define a structure that describe the post processing settings. For + * the best objective measure (using the PSNR metric) set post_proc_flag + * to VP8_DEBLOCK and deblocking_level to 1. + */ + +typedef struct vp8_postproc_cfg { + int post_proc_flag; /**< the types of post processing to be done, should be combination of "vp8_postproc_level" */ + int deblocking_level; /**< the strength of deblocking, valid range [0, 16] */ + int noise_level; /**< the strength of additive noise, valid range [0, 16] */ +} vp8_postproc_cfg_t; + +/*!\brief reference frame type + * + * The set of macros define the type of VP8 reference frames + */ +typedef enum vpx_ref_frame_type { + VP8_LAST_FRAME = 1, + VP8_GOLD_FRAME = 2, + VP8_ALTR_FRAME = 4 +} vpx_ref_frame_type_t; + +/*!\brief reference frame data struct + * + * Define the data struct to access vp8 reference frames. + */ +typedef struct vpx_ref_frame { + vpx_ref_frame_type_t frame_type; /**< which reference frame */ + vpx_image_t img; /**< reference frame data in image format */ +} vpx_ref_frame_t; + +/*!\brief VP9 specific reference frame data struct + * + * Define the data struct to access vp9 reference frames. + */ +typedef struct vp9_ref_frame { + int idx; /**< frame index to get (input) */ + vpx_image_t img; /**< img structure to populate (output) */ +} vp9_ref_frame_t; + +/*!\cond */ +/*!\brief vp8 decoder control function parameter type + * + * defines the data type for each of VP8 decoder control function requires + */ +VPX_CTRL_USE_TYPE(VP8_SET_REFERENCE, vpx_ref_frame_t *) +#define VPX_CTRL_VP8_SET_REFERENCE +VPX_CTRL_USE_TYPE(VP8_COPY_REFERENCE, vpx_ref_frame_t *) +#define VPX_CTRL_VP8_COPY_REFERENCE +VPX_CTRL_USE_TYPE(VP8_SET_POSTPROC, vp8_postproc_cfg_t *) +#define VPX_CTRL_VP8_SET_POSTPROC +VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_REF_FRAME, int) +#define VPX_CTRL_VP8_SET_DBG_COLOR_REF_FRAME +VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_MB_MODES, int) +#define VPX_CTRL_VP8_SET_DBG_COLOR_MB_MODES +VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_B_MODES, int) +#define VPX_CTRL_VP8_SET_DBG_COLOR_B_MODES +VPX_CTRL_USE_TYPE(VP8_SET_DBG_DISPLAY_MV, int) +#define VPX_CTRL_VP8_SET_DBG_DISPLAY_MV +VPX_CTRL_USE_TYPE(VP9_GET_REFERENCE, vp9_ref_frame_t *) +#define VPX_CTRL_VP9_GET_REFERENCE + +/*!\endcond */ +/*! @} - end defgroup vp8 */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // VPX_VP8_H_ diff --git a/bin/windows/vpx/include/vpx/vp8dx.h b/bin/windows/vpx/include/vpx/vp8dx.h new file mode 100644 index 00000000000..67c97bb6c9a --- /dev/null +++ b/bin/windows/vpx/include/vpx/vp8dx.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\defgroup vp8_decoder WebM VP8/VP9 Decoder + * \ingroup vp8 + * + * @{ + */ +/*!\file + * \brief Provides definitions for using VP8 or VP9 within the vpx Decoder + * interface. + */ +#ifndef VPX_VP8DX_H_ +#define VPX_VP8DX_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Include controls common to both the encoder and decoder */ +#include "./vp8.h" + +/*!\name Algorithm interface for VP8 + * + * This interface provides the capability to decode VP8 streams. + * @{ + */ +extern vpx_codec_iface_t vpx_codec_vp8_dx_algo; +extern vpx_codec_iface_t *vpx_codec_vp8_dx(void); +/*!@} - end algorithm interface member group*/ + +/*!\name Algorithm interface for VP9 + * + * This interface provides the capability to decode VP9 streams. + * @{ + */ +extern vpx_codec_iface_t vpx_codec_vp9_dx_algo; +extern vpx_codec_iface_t *vpx_codec_vp9_dx(void); +/*!@} - end algorithm interface member group*/ + +/*!\enum vp8_dec_control_id + * \brief VP8 decoder control functions + * + * This set of macros define the control functions available for the VP8 + * decoder interface. + * + * \sa #vpx_codec_control + */ +enum vp8_dec_control_id { + /** control function to get info on which reference frames were updated + * by the last decode + */ + VP8D_GET_LAST_REF_UPDATES = VP8_DECODER_CTRL_ID_START, + + /** check if the indicated frame is corrupted */ + VP8D_GET_FRAME_CORRUPTED, + + /** control function to get info on which reference frames were used + * by the last decode + */ + VP8D_GET_LAST_REF_USED, + + /** decryption function to decrypt encoded buffer data immediately + * before decoding. Takes a vpx_decrypt_init, which contains + * a callback function and opaque context pointer. + */ + VPXD_SET_DECRYPTOR, + VP8D_SET_DECRYPTOR = VPXD_SET_DECRYPTOR, + + /** control function to get the dimensions that the current frame is decoded + * at. This may be different to the intended display size for the frame as + * specified in the wrapper or frame header (see VP9D_GET_DISPLAY_SIZE). */ + VP9D_GET_FRAME_SIZE, + + /** control function to get the current frame's intended display dimensions + * (as specified in the wrapper or frame header). This may be different to + * the decoded dimensions of this frame (see VP9D_GET_FRAME_SIZE). */ + VP9D_GET_DISPLAY_SIZE, + + /** control function to get the bit depth of the stream. */ + VP9D_GET_BIT_DEPTH, + + /** control function to set the byte alignment of the planes in the reference + * buffers. Valid values are power of 2, from 32 to 1024. A value of 0 sets + * legacy alignment. I.e. Y plane is aligned to 32 bytes, U plane directly + * follows Y plane, and V plane directly follows U plane. Default value is 0. + */ + VP9_SET_BYTE_ALIGNMENT, + + /** control function to invert the decoding order to from right to left. The + * function is used in a test to confirm the decoding independence of tile + * columns. The function may be used in application where this order + * of decoding is desired. + * + * TODO(yaowu): Rework the unit test that uses this control, and in a future + * release, this test-only control shall be removed. + */ + VP9_INVERT_TILE_DECODE_ORDER, + + /** control function to set the skip loop filter flag. Valid values are + * integers. The decoder will skip the loop filter when its value is set to + * nonzero. If the loop filter is skipped the decoder may accumulate decode + * artifacts. The default value is 0. + */ + VP9_SET_SKIP_LOOP_FILTER, + + VP8_DECODER_CTRL_ID_MAX +}; + +/** Decrypt n bytes of data from input -> output, using the decrypt_state + * passed in VPXD_SET_DECRYPTOR. + */ +typedef void (*vpx_decrypt_cb)(void *decrypt_state, const unsigned char *input, + unsigned char *output, int count); + +/*!\brief Structure to hold decryption state + * + * Defines a structure to hold the decryption state and access function. + */ +typedef struct vpx_decrypt_init { + /*! Decrypt callback. */ + vpx_decrypt_cb decrypt_cb; + + /*! Decryption state. */ + void *decrypt_state; +} vpx_decrypt_init; + +/*!\brief A deprecated alias for vpx_decrypt_init. + */ +typedef vpx_decrypt_init vp8_decrypt_init; + + +/*!\cond */ +/*!\brief VP8 decoder control function parameter type + * + * Defines the data types that VP8D control functions take. Note that + * additional common controls are defined in vp8.h + * + */ + + +VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES, int *) +#define VPX_CTRL_VP8D_GET_LAST_REF_UPDATES +VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED, int *) +#define VPX_CTRL_VP8D_GET_FRAME_CORRUPTED +VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED, int *) +#define VPX_CTRL_VP8D_GET_LAST_REF_USED +VPX_CTRL_USE_TYPE(VPXD_SET_DECRYPTOR, vpx_decrypt_init *) +#define VPX_CTRL_VPXD_SET_DECRYPTOR +VPX_CTRL_USE_TYPE(VP8D_SET_DECRYPTOR, vpx_decrypt_init *) +#define VPX_CTRL_VP8D_SET_DECRYPTOR +VPX_CTRL_USE_TYPE(VP9D_GET_DISPLAY_SIZE, int *) +#define VPX_CTRL_VP9D_GET_DISPLAY_SIZE +VPX_CTRL_USE_TYPE(VP9D_GET_BIT_DEPTH, unsigned int *) +#define VPX_CTRL_VP9D_GET_BIT_DEPTH +VPX_CTRL_USE_TYPE(VP9D_GET_FRAME_SIZE, int *) +#define VPX_CTRL_VP9D_GET_FRAME_SIZE +VPX_CTRL_USE_TYPE(VP9_INVERT_TILE_DECODE_ORDER, int) +#define VPX_CTRL_VP9_INVERT_TILE_DECODE_ORDER + +/*!\endcond */ +/*! @} - end defgroup vp8_decoder */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // VPX_VP8DX_H_ diff --git a/bin/windows/vpx/include/vpx/vpx_codec.h b/bin/windows/vpx/include/vpx/vpx_codec.h new file mode 100644 index 00000000000..b6037bb4d7a --- /dev/null +++ b/bin/windows/vpx/include/vpx/vpx_codec.h @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\defgroup codec Common Algorithm Interface + * This abstraction allows applications to easily support multiple video + * formats with minimal code duplication. This section describes the interface + * common to all codecs (both encoders and decoders). + * @{ + */ + +/*!\file + * \brief Describes the codec algorithm interface to applications. + * + * This file describes the interface between an application and a + * video codec algorithm. + * + * An application instantiates a specific codec instance by using + * vpx_codec_init() and a pointer to the algorithm's interface structure: + *
+ *     my_app.c:
+ *       extern vpx_codec_iface_t my_codec;
+ *       {
+ *           vpx_codec_ctx_t algo;
+ *           res = vpx_codec_init(&algo, &my_codec);
+ *       }
+ *     
+ * + * Once initialized, the instance is manged using other functions from + * the vpx_codec_* family. + */ +#ifndef VPX_VPX_CODEC_H_ +#define VPX_VPX_CODEC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "./vpx_integer.h" +#include "./vpx_image.h" + + /*!\brief Decorator indicating a function is deprecated */ +#ifndef DEPRECATED +#if defined(__GNUC__) && __GNUC__ +#define DEPRECATED __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED +#else +#define DEPRECATED +#endif +#endif /* DEPRECATED */ + +#ifndef DECLSPEC_DEPRECATED +#if defined(__GNUC__) && __GNUC__ +#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */ +#elif defined(_MSC_VER) +#define DECLSPEC_DEPRECATED __declspec(deprecated) /**< \copydoc #DEPRECATED */ +#else +#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */ +#endif +#endif /* DECLSPEC_DEPRECATED */ + + /*!\brief Decorator indicating a function is potentially unused */ +#ifdef UNUSED +#elif defined(__GNUC__) || defined(__clang__) +#define UNUSED __attribute__ ((unused)) +#else +#define UNUSED +#endif + + /*!\brief Current ABI version number + * + * \internal + * If this file is altered in any way that changes the ABI, this value + * must be bumped. Examples include, but are not limited to, changing + * types, removing or reassigning enums, adding/removing/rearranging + * fields to structures + */ +#define VPX_CODEC_ABI_VERSION (3 + VPX_IMAGE_ABI_VERSION) /**<\hideinitializer*/ + + /*!\brief Algorithm return codes */ + typedef enum { + /*!\brief Operation completed without error */ + VPX_CODEC_OK, + + /*!\brief Unspecified error */ + VPX_CODEC_ERROR, + + /*!\brief Memory operation failed */ + VPX_CODEC_MEM_ERROR, + + /*!\brief ABI version mismatch */ + VPX_CODEC_ABI_MISMATCH, + + /*!\brief Algorithm does not have required capability */ + VPX_CODEC_INCAPABLE, + + /*!\brief The given bitstream is not supported. + * + * The bitstream was unable to be parsed at the highest level. The decoder + * is unable to proceed. This error \ref SHOULD be treated as fatal to the + * stream. */ + VPX_CODEC_UNSUP_BITSTREAM, + + /*!\brief Encoded bitstream uses an unsupported feature + * + * The decoder does not implement a feature required by the encoder. This + * return code should only be used for features that prevent future + * pictures from being properly decoded. This error \ref MAY be treated as + * fatal to the stream or \ref MAY be treated as fatal to the current GOP. + */ + VPX_CODEC_UNSUP_FEATURE, + + /*!\brief The coded data for this stream is corrupt or incomplete + * + * There was a problem decoding the current frame. This return code + * should only be used for failures that prevent future pictures from + * being properly decoded. This error \ref MAY be treated as fatal to the + * stream or \ref MAY be treated as fatal to the current GOP. If decoding + * is continued for the current GOP, artifacts may be present. + */ + VPX_CODEC_CORRUPT_FRAME, + + /*!\brief An application-supplied parameter is not valid. + * + */ + VPX_CODEC_INVALID_PARAM, + + /*!\brief An iterator reached the end of list. + * + */ + VPX_CODEC_LIST_END + + } + vpx_codec_err_t; + + + /*! \brief Codec capabilities bitfield + * + * Each codec advertises the capabilities it supports as part of its + * ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces + * or functionality, and are not required to be supported. + * + * The available flags are specified by VPX_CODEC_CAP_* defines. + */ + typedef long vpx_codec_caps_t; +#define VPX_CODEC_CAP_DECODER 0x1 /**< Is a decoder */ +#define VPX_CODEC_CAP_ENCODER 0x2 /**< Is an encoder */ + + + /*! \brief Initialization-time Feature Enabling + * + * Certain codec features must be known at initialization time, to allow for + * proper memory allocation. + * + * The available flags are specified by VPX_CODEC_USE_* defines. + */ + typedef long vpx_codec_flags_t; + + + /*!\brief Codec interface structure. + * + * Contains function pointers and other data private to the codec + * implementation. This structure is opaque to the application. + */ + typedef const struct vpx_codec_iface vpx_codec_iface_t; + + + /*!\brief Codec private data structure. + * + * Contains data private to the codec implementation. This structure is opaque + * to the application. + */ + typedef struct vpx_codec_priv vpx_codec_priv_t; + + + /*!\brief Iterator + * + * Opaque storage used for iterating over lists. + */ + typedef const void *vpx_codec_iter_t; + + + /*!\brief Codec context structure + * + * All codecs \ref MUST support this context structure fully. In general, + * this data should be considered private to the codec algorithm, and + * not be manipulated or examined by the calling application. Applications + * may reference the 'name' member to get a printable description of the + * algorithm. + */ + typedef struct vpx_codec_ctx { + const char *name; /**< Printable interface name */ + vpx_codec_iface_t *iface; /**< Interface pointers */ + vpx_codec_err_t err; /**< Last returned error */ + const char *err_detail; /**< Detailed info, if available */ + vpx_codec_flags_t init_flags; /**< Flags passed at init time */ + union { + /**< Decoder Configuration Pointer */ + const struct vpx_codec_dec_cfg *dec; + /**< Encoder Configuration Pointer */ + const struct vpx_codec_enc_cfg *enc; + const void *raw; + } config; /**< Configuration pointer aliasing union */ + vpx_codec_priv_t *priv; /**< Algorithm private storage */ + } vpx_codec_ctx_t; + + /*!\brief Bit depth for codec + * * + * This enumeration determines the bit depth of the codec. + */ + typedef enum vpx_bit_depth { + VPX_BITS_8 = 8, /**< 8 bits */ + VPX_BITS_10 = 10, /**< 10 bits */ + VPX_BITS_12 = 12, /**< 12 bits */ + } vpx_bit_depth_t; + + /* + * Library Version Number Interface + * + * For example, see the following sample return values: + * vpx_codec_version() (1<<16 | 2<<8 | 3) + * vpx_codec_version_str() "v1.2.3-rc1-16-gec6a1ba" + * vpx_codec_version_extra_str() "rc1-16-gec6a1ba" + */ + + /*!\brief Return the version information (as an integer) + * + * Returns a packed encoding of the library version number. This will only include + * the major.minor.patch component of the version number. Note that this encoded + * value should be accessed through the macros provided, as the encoding may change + * in the future. + * + */ + int vpx_codec_version(void); +#define VPX_VERSION_MAJOR(v) ((v>>16)&0xff) /**< extract major from packed version */ +#define VPX_VERSION_MINOR(v) ((v>>8)&0xff) /**< extract minor from packed version */ +#define VPX_VERSION_PATCH(v) ((v>>0)&0xff) /**< extract patch from packed version */ + + /*!\brief Return the version major number */ +#define vpx_codec_version_major() ((vpx_codec_version()>>16)&0xff) + + /*!\brief Return the version minor number */ +#define vpx_codec_version_minor() ((vpx_codec_version()>>8)&0xff) + + /*!\brief Return the version patch number */ +#define vpx_codec_version_patch() ((vpx_codec_version()>>0)&0xff) + + + /*!\brief Return the version information (as a string) + * + * Returns a printable string containing the full library version number. This may + * contain additional text following the three digit version number, as to indicate + * release candidates, prerelease versions, etc. + * + */ + const char *vpx_codec_version_str(void); + + + /*!\brief Return the version information (as a string) + * + * Returns a printable "extra string". This is the component of the string returned + * by vpx_codec_version_str() following the three digit version number. + * + */ + const char *vpx_codec_version_extra_str(void); + + + /*!\brief Return the build configuration + * + * Returns a printable string containing an encoded version of the build + * configuration. This may be useful to vpx support. + * + */ + const char *vpx_codec_build_config(void); + + + /*!\brief Return the name for a given interface + * + * Returns a human readable string for name of the given codec interface. + * + * \param[in] iface Interface pointer + * + */ + const char *vpx_codec_iface_name(vpx_codec_iface_t *iface); + + + /*!\brief Convert error number to printable string + * + * Returns a human readable string for the last error returned by the + * algorithm. The returned error will be one line and will not contain + * any newline characters. + * + * + * \param[in] err Error number. + * + */ + const char *vpx_codec_err_to_string(vpx_codec_err_t err); + + + /*!\brief Retrieve error synopsis for codec context + * + * Returns a human readable string for the last error returned by the + * algorithm. The returned error will be one line and will not contain + * any newline characters. + * + * + * \param[in] ctx Pointer to this instance's context. + * + */ + const char *vpx_codec_error(vpx_codec_ctx_t *ctx); + + + /*!\brief Retrieve detailed error information for codec context + * + * Returns a human readable string providing detailed information about + * the last error. + * + * \param[in] ctx Pointer to this instance's context. + * + * \retval NULL + * No detailed information is available. + */ + const char *vpx_codec_error_detail(vpx_codec_ctx_t *ctx); + + + /* REQUIRED FUNCTIONS + * + * The following functions are required to be implemented for all codecs. + * They represent the base case functionality expected of all codecs. + */ + + /*!\brief Destroy a codec instance + * + * Destroys a codec context, freeing any associated memory buffers. + * + * \param[in] ctx Pointer to this instance's context + * + * \retval #VPX_CODEC_OK + * The codec algorithm initialized. + * \retval #VPX_CODEC_MEM_ERROR + * Memory allocation failed. + */ + vpx_codec_err_t vpx_codec_destroy(vpx_codec_ctx_t *ctx); + + + /*!\brief Get the capabilities of an algorithm. + * + * Retrieves the capabilities bitfield from the algorithm's interface. + * + * \param[in] iface Pointer to the algorithm interface + * + */ + vpx_codec_caps_t vpx_codec_get_caps(vpx_codec_iface_t *iface); + + + /*!\brief Control algorithm + * + * This function is used to exchange algorithm specific data with the codec + * instance. This can be used to implement features specific to a particular + * algorithm. + * + * This wrapper function dispatches the request to the helper function + * associated with the given ctrl_id. It tries to call this function + * transparently, but will return #VPX_CODEC_ERROR if the request could not + * be dispatched. + * + * Note that this function should not be used directly. Call the + * #vpx_codec_control wrapper macro instead. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] ctrl_id Algorithm specific control identifier + * + * \retval #VPX_CODEC_OK + * The control request was processed. + * \retval #VPX_CODEC_ERROR + * The control request was not processed. + * \retval #VPX_CODEC_INVALID_PARAM + * The data was not valid. + */ + vpx_codec_err_t vpx_codec_control_(vpx_codec_ctx_t *ctx, + int ctrl_id, + ...); +#if defined(VPX_DISABLE_CTRL_TYPECHECKS) && VPX_DISABLE_CTRL_TYPECHECKS +# define vpx_codec_control(ctx,id,data) vpx_codec_control_(ctx,id,data) +# define VPX_CTRL_USE_TYPE(id, typ) +# define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) +# define VPX_CTRL_VOID(id, typ) + +#else + /*!\brief vpx_codec_control wrapper macro + * + * This macro allows for type safe conversions across the variadic parameter + * to vpx_codec_control_(). + * + * \internal + * It works by dispatching the call to the control function through a wrapper + * function named with the id parameter. + */ +# define vpx_codec_control(ctx,id,data) vpx_codec_control_##id(ctx,id,data)\ + /**<\hideinitializer*/ + + + /*!\brief vpx_codec_control type definition macro + * + * This macro allows for type safe conversions across the variadic parameter + * to vpx_codec_control_(). It defines the type of the argument for a given + * control identifier. + * + * \internal + * It defines a static function with + * the correctly typed arguments as a wrapper to the type-unsafe internal + * function. + */ +# define VPX_CTRL_USE_TYPE(id, typ) \ + static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t*, int, typ) UNUSED;\ + \ + static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id, typ data) {\ + return vpx_codec_control_(ctx, ctrl_id, data);\ + } /**<\hideinitializer*/ + + + /*!\brief vpx_codec_control deprecated type definition macro + * + * Like #VPX_CTRL_USE_TYPE, but indicates that the specified control is + * deprecated and should not be used. Consult the documentation for your + * codec for more information. + * + * \internal + * It defines a static function with the correctly typed arguments as a + * wrapper to the type-unsafe internal function. + */ +# define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) \ + DECLSPEC_DEPRECATED static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t*, int, typ) DEPRECATED UNUSED;\ + \ + DECLSPEC_DEPRECATED static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id, typ data) {\ + return vpx_codec_control_(ctx, ctrl_id, data);\ + } /**<\hideinitializer*/ + + + /*!\brief vpx_codec_control void type definition macro + * + * This macro allows for type safe conversions across the variadic parameter + * to vpx_codec_control_(). It indicates that a given control identifier takes + * no argument. + * + * \internal + * It defines a static function without a data argument as a wrapper to the + * type-unsafe internal function. + */ +# define VPX_CTRL_VOID(id) \ + static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t*, int) UNUSED;\ + \ + static vpx_codec_err_t \ + vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id) {\ + return vpx_codec_control_(ctx, ctrl_id);\ + } /**<\hideinitializer*/ + + +#endif + + /*!@} - end defgroup codec*/ +#ifdef __cplusplus +} +#endif +#endif // VPX_VPX_CODEC_H_ + diff --git a/bin/windows/vpx/include/vpx/vpx_decoder.h b/bin/windows/vpx/include/vpx/vpx_decoder.h new file mode 100644 index 00000000000..62fd9197564 --- /dev/null +++ b/bin/windows/vpx/include/vpx/vpx_decoder.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef VPX_VPX_DECODER_H_ +#define VPX_VPX_DECODER_H_ + +/*!\defgroup decoder Decoder Algorithm Interface + * \ingroup codec + * This abstraction allows applications using this decoder to easily support + * multiple video formats with minimal code duplication. This section describes + * the interface common to all decoders. + * @{ + */ + +/*!\file + * \brief Describes the decoder algorithm interface to applications. + * + * This file describes the interface between an application and a + * video decoder algorithm. + * + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "./vpx_codec.h" +#include "./vpx_frame_buffer.h" + + /*!\brief Current ABI version number + * + * \internal + * If this file is altered in any way that changes the ABI, this value + * must be bumped. Examples include, but are not limited to, changing + * types, removing or reassigning enums, adding/removing/rearranging + * fields to structures + */ +#define VPX_DECODER_ABI_VERSION (3 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/ + + /*! \brief Decoder capabilities bitfield + * + * Each decoder advertises the capabilities it supports as part of its + * ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces + * or functionality, and are not required to be supported by a decoder. + * + * The available flags are specified by VPX_CODEC_CAP_* defines. + */ +#define VPX_CODEC_CAP_PUT_SLICE 0x10000 /**< Will issue put_slice callbacks */ +#define VPX_CODEC_CAP_PUT_FRAME 0x20000 /**< Will issue put_frame callbacks */ +#define VPX_CODEC_CAP_POSTPROC 0x40000 /**< Can postprocess decoded frame */ +#define VPX_CODEC_CAP_ERROR_CONCEALMENT 0x80000 /**< Can conceal errors due to + packet loss */ +#define VPX_CODEC_CAP_INPUT_FRAGMENTS 0x100000 /**< Can receive encoded frames + one fragment at a time */ + + /*! \brief Initialization-time Feature Enabling + * + * Certain codec features must be known at initialization time, to allow for + * proper memory allocation. + * + * The available flags are specified by VPX_CODEC_USE_* defines. + */ +#define VPX_CODEC_CAP_FRAME_THREADING 0x200000 /**< Can support frame-based + multi-threading */ +#define VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER 0x400000 /**< Can support external + frame buffers */ + +#define VPX_CODEC_USE_POSTPROC 0x10000 /**< Postprocess decoded frame */ +#define VPX_CODEC_USE_ERROR_CONCEALMENT 0x20000 /**< Conceal errors in decoded + frames */ +#define VPX_CODEC_USE_INPUT_FRAGMENTS 0x40000 /**< The input frame should be + passed to the decoder one + fragment at a time */ +#define VPX_CODEC_USE_FRAME_THREADING 0x80000 /**< Enable frame-based + multi-threading */ + + /*!\brief Stream properties + * + * This structure is used to query or set properties of the decoded + * stream. Algorithms may extend this structure with data specific + * to their bitstream by setting the sz member appropriately. + */ + typedef struct vpx_codec_stream_info { + unsigned int sz; /**< Size of this structure */ + unsigned int w; /**< Width (or 0 for unknown/default) */ + unsigned int h; /**< Height (or 0 for unknown/default) */ + unsigned int is_kf; /**< Current frame is a keyframe */ + } vpx_codec_stream_info_t; + + /* REQUIRED FUNCTIONS + * + * The following functions are required to be implemented for all decoders. + * They represent the base case functionality expected of all decoders. + */ + + + /*!\brief Initialization Configurations + * + * This structure is used to pass init time configuration options to the + * decoder. + */ + typedef struct vpx_codec_dec_cfg { + unsigned int threads; /**< Maximum number of threads to use, default 1 */ + unsigned int w; /**< Width */ + unsigned int h; /**< Height */ + } vpx_codec_dec_cfg_t; /**< alias for struct vpx_codec_dec_cfg */ + + + /*!\brief Initialize a decoder instance + * + * Initializes a decoder context using the given interface. Applications + * should call the vpx_codec_dec_init convenience macro instead of this + * function directly, to ensure that the ABI version number parameter + * is properly initialized. + * + * If the library was configured with --disable-multithread, this call + * is not thread safe and should be guarded with a lock if being used + * in a multithreaded context. + * + * \param[in] ctx Pointer to this instance's context. + * \param[in] iface Pointer to the algorithm interface to use. + * \param[in] cfg Configuration to use, if known. May be NULL. + * \param[in] flags Bitfield of VPX_CODEC_USE_* flags + * \param[in] ver ABI version number. Must be set to + * VPX_DECODER_ABI_VERSION + * \retval #VPX_CODEC_OK + * The decoder algorithm initialized. + * \retval #VPX_CODEC_MEM_ERROR + * Memory allocation failed. + */ + vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx, + vpx_codec_iface_t *iface, + const vpx_codec_dec_cfg_t *cfg, + vpx_codec_flags_t flags, + int ver); + + /*!\brief Convenience macro for vpx_codec_dec_init_ver() + * + * Ensures the ABI version parameter is properly set. + */ +#define vpx_codec_dec_init(ctx, iface, cfg, flags) \ + vpx_codec_dec_init_ver(ctx, iface, cfg, flags, VPX_DECODER_ABI_VERSION) + + + /*!\brief Parse stream info from a buffer + * + * Performs high level parsing of the bitstream. Construction of a decoder + * context is not necessary. Can be used to determine if the bitstream is + * of the proper format, and to extract information from the stream. + * + * \param[in] iface Pointer to the algorithm interface + * \param[in] data Pointer to a block of data to parse + * \param[in] data_sz Size of the data buffer + * \param[in,out] si Pointer to stream info to update. The size member + * \ref MUST be properly initialized, but \ref MAY be + * clobbered by the algorithm. This parameter \ref MAY + * be NULL. + * + * \retval #VPX_CODEC_OK + * Bitstream is parsable and stream information updated + */ + vpx_codec_err_t vpx_codec_peek_stream_info(vpx_codec_iface_t *iface, + const uint8_t *data, + unsigned int data_sz, + vpx_codec_stream_info_t *si); + + + /*!\brief Return information about the current stream. + * + * Returns information about the stream that has been parsed during decoding. + * + * \param[in] ctx Pointer to this instance's context + * \param[in,out] si Pointer to stream info to update. The size member + * \ref MUST be properly initialized, but \ref MAY be + * clobbered by the algorithm. This parameter \ref MAY + * be NULL. + * + * \retval #VPX_CODEC_OK + * Bitstream is parsable and stream information updated + */ + vpx_codec_err_t vpx_codec_get_stream_info(vpx_codec_ctx_t *ctx, + vpx_codec_stream_info_t *si); + + + /*!\brief Decode data + * + * Processes a buffer of coded data. If the processing results in a new + * decoded frame becoming available, PUT_SLICE and PUT_FRAME events may be + * generated, as appropriate. Encoded data \ref MUST be passed in DTS (decode + * time stamp) order. Frames produced will always be in PTS (presentation + * time stamp) order. + * If the decoder is configured with VPX_CODEC_USE_INPUT_FRAGMENTS enabled, + * data and data_sz can contain a fragment of the encoded frame. Fragment + * \#n must contain at least partition \#n, but can also contain subsequent + * partitions (\#n+1 - \#n+i), and if so, fragments \#n+1, .., \#n+i must + * be empty. When no more data is available, this function should be called + * with NULL as data and 0 as data_sz. The memory passed to this function + * must be available until the frame has been decoded. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] data Pointer to this block of new coded data. If + * NULL, a VPX_CODEC_CB_PUT_FRAME event is posted + * for the previously decoded frame. + * \param[in] data_sz Size of the coded data, in bytes. + * \param[in] user_priv Application specific data to associate with + * this frame. + * \param[in] deadline Soft deadline the decoder should attempt to meet, + * in us. Set to zero for unlimited. + * + * \return Returns #VPX_CODEC_OK if the coded data was processed completely + * and future pictures can be decoded without error. Otherwise, + * see the descriptions of the other error codes in ::vpx_codec_err_t + * for recoverability capabilities. + */ + vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx, + const uint8_t *data, + unsigned int data_sz, + void *user_priv, + long deadline); + + + /*!\brief Decoded frames iterator + * + * Iterates over a list of the frames available for display. The iterator + * storage should be initialized to NULL to start the iteration. Iteration is + * complete when this function returns NULL. + * + * The list of available frames becomes valid upon completion of the + * vpx_codec_decode call, and remains valid until the next call to vpx_codec_decode. + * + * \param[in] ctx Pointer to this instance's context + * \param[in,out] iter Iterator storage, initialized to NULL + * + * \return Returns a pointer to an image, if one is ready for display. Frames + * produced will always be in PTS (presentation time stamp) order. + */ + vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t *ctx, + vpx_codec_iter_t *iter); + + + /*!\defgroup cap_put_frame Frame-Based Decoding Functions + * + * The following functions are required to be implemented for all decoders + * that advertise the VPX_CODEC_CAP_PUT_FRAME capability. Calling these functions + * for codecs that don't advertise this capability will result in an error + * code being returned, usually VPX_CODEC_ERROR + * @{ + */ + + /*!\brief put frame callback prototype + * + * This callback is invoked by the decoder to notify the application of + * the availability of decoded image data. + */ + typedef void (*vpx_codec_put_frame_cb_fn_t)(void *user_priv, + const vpx_image_t *img); + + + /*!\brief Register for notification of frame completion. + * + * Registers a given function to be called when a decoded frame is + * available. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] cb Pointer to the callback function + * \param[in] user_priv User's private data + * + * \retval #VPX_CODEC_OK + * Callback successfully registered. + * \retval #VPX_CODEC_ERROR + * Decoder context not initialized, or algorithm not capable of + * posting slice completion. + */ + vpx_codec_err_t vpx_codec_register_put_frame_cb(vpx_codec_ctx_t *ctx, + vpx_codec_put_frame_cb_fn_t cb, + void *user_priv); + + + /*!@} - end defgroup cap_put_frame */ + + /*!\defgroup cap_put_slice Slice-Based Decoding Functions + * + * The following functions are required to be implemented for all decoders + * that advertise the VPX_CODEC_CAP_PUT_SLICE capability. Calling these functions + * for codecs that don't advertise this capability will result in an error + * code being returned, usually VPX_CODEC_ERROR + * @{ + */ + + /*!\brief put slice callback prototype + * + * This callback is invoked by the decoder to notify the application of + * the availability of partially decoded image data. The + */ + typedef void (*vpx_codec_put_slice_cb_fn_t)(void *user_priv, + const vpx_image_t *img, + const vpx_image_rect_t *valid, + const vpx_image_rect_t *update); + + + /*!\brief Register for notification of slice completion. + * + * Registers a given function to be called when a decoded slice is + * available. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] cb Pointer to the callback function + * \param[in] user_priv User's private data + * + * \retval #VPX_CODEC_OK + * Callback successfully registered. + * \retval #VPX_CODEC_ERROR + * Decoder context not initialized, or algorithm not capable of + * posting slice completion. + */ + vpx_codec_err_t vpx_codec_register_put_slice_cb(vpx_codec_ctx_t *ctx, + vpx_codec_put_slice_cb_fn_t cb, + void *user_priv); + + + /*!@} - end defgroup cap_put_slice*/ + + /*!\defgroup cap_external_frame_buffer External Frame Buffer Functions + * + * The following section is required to be implemented for all decoders + * that advertise the VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER capability. + * Calling this function for codecs that don't advertise this capability + * will result in an error code being returned, usually VPX_CODEC_ERROR. + * + * \note + * Currently this only works with VP9. + * @{ + */ + + /*!\brief Pass in external frame buffers for the decoder to use. + * + * Registers functions to be called when libvpx needs a frame buffer + * to decode the current frame and a function to be called when libvpx does + * not internally reference the frame buffer. This set function must + * be called before the first call to decode or libvpx will assume the + * default behavior of allocating frame buffers internally. + * + * \param[in] ctx Pointer to this instance's context + * \param[in] cb_get Pointer to the get callback function + * \param[in] cb_release Pointer to the release callback function + * \param[in] cb_priv Callback's private data + * + * \retval #VPX_CODEC_OK + * External frame buffers will be used by libvpx. + * \retval #VPX_CODEC_INVALID_PARAM + * One or more of the callbacks were NULL. + * \retval #VPX_CODEC_ERROR + * Decoder context not initialized, or algorithm not capable of + * using external frame buffers. + * + * \note + * When decoding VP9, the application may be required to pass in at least + * #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS external frame + * buffers. + */ + vpx_codec_err_t vpx_codec_set_frame_buffer_functions( + vpx_codec_ctx_t *ctx, + vpx_get_frame_buffer_cb_fn_t cb_get, + vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv); + + /*!@} - end defgroup cap_external_frame_buffer */ + + /*!@} - end defgroup decoder*/ +#ifdef __cplusplus +} +#endif +#endif // VPX_VPX_DECODER_H_ + diff --git a/bin/windows/vpx/include/vpx/vpx_frame_buffer.h b/bin/windows/vpx/include/vpx/vpx_frame_buffer.h new file mode 100644 index 00000000000..9036459af0a --- /dev/null +++ b/bin/windows/vpx/include/vpx/vpx_frame_buffer.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VPX_VPX_FRAME_BUFFER_H_ +#define VPX_VPX_FRAME_BUFFER_H_ + +/*!\file + * \brief Describes the decoder external frame buffer interface. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "./vpx_integer.h" + +/*!\brief The maximum number of work buffers used by libvpx. + * Support maximum 4 threads to decode video in parallel. + * Each thread will use one work buffer. + * TODO(hkuang): Add support to set number of worker threads dynamically. + */ +#define VPX_MAXIMUM_WORK_BUFFERS 8 + +/*!\brief The maximum number of reference buffers that a VP9 encoder may use. + */ +#define VP9_MAXIMUM_REF_BUFFERS 8 + +/*!\brief External frame buffer + * + * This structure holds allocated frame buffers used by the decoder. + */ +typedef struct vpx_codec_frame_buffer { + uint8_t *data; /**< Pointer to the data buffer */ + size_t size; /**< Size of data in bytes */ + void *priv; /**< Frame's private data */ +} vpx_codec_frame_buffer_t; + +/*!\brief get frame buffer callback prototype + * + * This callback is invoked by the decoder to retrieve data for the frame + * buffer in order for the decode call to complete. The callback must + * allocate at least min_size in bytes and assign it to fb->data. The callback + * must zero out all the data allocated. Then the callback must set fb->size + * to the allocated size. The application does not need to align the allocated + * data. The callback is triggered when the decoder needs a frame buffer to + * decode a compressed image into. This function may be called more than once + * for every call to vpx_codec_decode. The application may set fb->priv to + * some data which will be passed back in the ximage and the release function + * call. |fb| is guaranteed to not be NULL. On success the callback must + * return 0. Any failure the callback must return a value less than 0. + * + * \param[in] priv Callback's private data + * \param[in] new_size Size in bytes needed by the buffer + * \param[in,out] fb Pointer to vpx_codec_frame_buffer_t + */ +typedef int (*vpx_get_frame_buffer_cb_fn_t)( + void *priv, size_t min_size, vpx_codec_frame_buffer_t *fb); + +/*!\brief release frame buffer callback prototype + * + * This callback is invoked by the decoder when the frame buffer is not + * referenced by any other buffers. |fb| is guaranteed to not be NULL. On + * success the callback must return 0. Any failure the callback must return + * a value less than 0. + * + * \param[in] priv Callback's private data + * \param[in] fb Pointer to vpx_codec_frame_buffer_t + */ +typedef int (*vpx_release_frame_buffer_cb_fn_t)( + void *priv, vpx_codec_frame_buffer_t *fb); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // VPX_VPX_FRAME_BUFFER_H_ diff --git a/bin/windows/vpx/include/vpx/vpx_image.h b/bin/windows/vpx/include/vpx/vpx_image.h new file mode 100644 index 00000000000..7958c69806e --- /dev/null +++ b/bin/windows/vpx/include/vpx/vpx_image.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/*!\file + * \brief Describes the vpx image descriptor and associated operations + * + */ +#ifndef VPX_VPX_IMAGE_H_ +#define VPX_VPX_IMAGE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + /*!\brief Current ABI version number + * + * \internal + * If this file is altered in any way that changes the ABI, this value + * must be bumped. Examples include, but are not limited to, changing + * types, removing or reassigning enums, adding/removing/rearranging + * fields to structures + */ +#define VPX_IMAGE_ABI_VERSION (4) /**<\hideinitializer*/ + + +#define VPX_IMG_FMT_PLANAR 0x100 /**< Image is a planar format. */ +#define VPX_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U in memory. */ +#define VPX_IMG_FMT_HAS_ALPHA 0x400 /**< Image has an alpha channel. */ +#define VPX_IMG_FMT_HIGHBITDEPTH 0x800 /**< Image uses 16bit framebuffer. */ + + /*!\brief List of supported image formats */ + typedef enum vpx_img_fmt { + VPX_IMG_FMT_NONE, + VPX_IMG_FMT_RGB24, /**< 24 bit per pixel packed RGB */ + VPX_IMG_FMT_RGB32, /**< 32 bit per pixel packed 0RGB */ + VPX_IMG_FMT_RGB565, /**< 16 bit per pixel, 565 */ + VPX_IMG_FMT_RGB555, /**< 16 bit per pixel, 555 */ + VPX_IMG_FMT_UYVY, /**< UYVY packed YUV */ + VPX_IMG_FMT_YUY2, /**< YUYV packed YUV */ + VPX_IMG_FMT_YVYU, /**< YVYU packed YUV */ + VPX_IMG_FMT_BGR24, /**< 24 bit per pixel packed BGR */ + VPX_IMG_FMT_RGB32_LE, /**< 32 bit packed BGR0 */ + VPX_IMG_FMT_ARGB, /**< 32 bit packed ARGB, alpha=255 */ + VPX_IMG_FMT_ARGB_LE, /**< 32 bit packed BGRA, alpha=255 */ + VPX_IMG_FMT_RGB565_LE, /**< 16 bit per pixel, gggbbbbb rrrrrggg */ + VPX_IMG_FMT_RGB555_LE, /**< 16 bit per pixel, gggbbbbb 0rrrrrgg */ + VPX_IMG_FMT_YV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 1, /**< planar YVU */ + VPX_IMG_FMT_I420 = VPX_IMG_FMT_PLANAR | 2, + VPX_IMG_FMT_VPXYV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 3, /** < planar 4:2:0 format with vpx color space */ + VPX_IMG_FMT_VPXI420 = VPX_IMG_FMT_PLANAR | 4, + VPX_IMG_FMT_I422 = VPX_IMG_FMT_PLANAR | 5, + VPX_IMG_FMT_I444 = VPX_IMG_FMT_PLANAR | 6, + VPX_IMG_FMT_I440 = VPX_IMG_FMT_PLANAR | 7, + VPX_IMG_FMT_444A = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_HAS_ALPHA | 6, + VPX_IMG_FMT_I42016 = VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGHBITDEPTH, + VPX_IMG_FMT_I42216 = VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGHBITDEPTH, + VPX_IMG_FMT_I44416 = VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGHBITDEPTH, + VPX_IMG_FMT_I44016 = VPX_IMG_FMT_I440 | VPX_IMG_FMT_HIGHBITDEPTH + } vpx_img_fmt_t; /**< alias for enum vpx_img_fmt */ + + /*!\brief List of supported color spaces */ + typedef enum vpx_color_space { + VPX_CS_UNKNOWN = 0, /**< Unknown */ + VPX_CS_BT_601 = 1, /**< BT.601 */ + VPX_CS_BT_709 = 2, /**< BT.709 */ + VPX_CS_SMPTE_170 = 3, /**< SMPTE.170 */ + VPX_CS_SMPTE_240 = 4, /**< SMPTE.240 */ + VPX_CS_BT_2020 = 5, /**< BT.2020 */ + VPX_CS_RESERVED = 6, /**< Reserved */ + VPX_CS_SRGB = 7 /**< sRGB */ + } vpx_color_space_t; /**< alias for enum vpx_color_space */ + + /*!\brief List of supported color range */ + typedef enum vpx_color_range { + VPX_CR_STUDIO_RANGE = 0, /**< Y [16..235], UV [16..240] */ + VPX_CR_FULL_RANGE = 1 /**< YUV/RGB [0..255] */ + } vpx_color_range_t; /**< alias for enum vpx_color_range */ + + /**\brief Image Descriptor */ + typedef struct vpx_image { + vpx_img_fmt_t fmt; /**< Image Format */ + vpx_color_space_t cs; /**< Color Space */ + vpx_color_range_t range; /**< Color Range */ + + /* Image storage dimensions */ + unsigned int w; /**< Stored image width */ + unsigned int h; /**< Stored image height */ + unsigned int bit_depth; /**< Stored image bit-depth */ + + /* Image display dimensions */ + unsigned int d_w; /**< Displayed image width */ + unsigned int d_h; /**< Displayed image height */ + + /* Image intended rendering dimensions */ + unsigned int r_w; /**< Intended rendering image width */ + unsigned int r_h; /**< Intended rendering image height */ + + /* Chroma subsampling info */ + unsigned int x_chroma_shift; /**< subsampling order, X */ + unsigned int y_chroma_shift; /**< subsampling order, Y */ + + /* Image data pointers. */ +#define VPX_PLANE_PACKED 0 /**< To be used for all packed formats */ +#define VPX_PLANE_Y 0 /**< Y (Luminance) plane */ +#define VPX_PLANE_U 1 /**< U (Chroma) plane */ +#define VPX_PLANE_V 2 /**< V (Chroma) plane */ +#define VPX_PLANE_ALPHA 3 /**< A (Transparency) plane */ + unsigned char *planes[4]; /**< pointer to the top left pixel for each plane */ + int stride[4]; /**< stride between rows for each plane */ + + int bps; /**< bits per sample (for packed formats) */ + + /* The following member may be set by the application to associate data + * with this image. + */ + void *user_priv; /**< may be set by the application to associate data + * with this image. */ + + /* The following members should be treated as private. */ + unsigned char *img_data; /**< private */ + int img_data_owner; /**< private */ + int self_allocd; /**< private */ + + void *fb_priv; /**< Frame buffer data associated with the image. */ + } vpx_image_t; /**< alias for struct vpx_image */ + + /**\brief Representation of a rectangle on a surface */ + typedef struct vpx_image_rect { + unsigned int x; /**< leftmost column */ + unsigned int y; /**< topmost row */ + unsigned int w; /**< width */ + unsigned int h; /**< height */ + } vpx_image_rect_t; /**< alias for struct vpx_image_rect */ + + /*!\brief Open a descriptor, allocating storage for the underlying image + * + * Returns a descriptor for storing an image of the given format. The + * storage for the descriptor is allocated on the heap. + * + * \param[in] img Pointer to storage for descriptor. If this parameter + * is NULL, the storage for the descriptor will be + * allocated on the heap. + * \param[in] fmt Format for the image + * \param[in] d_w Width of the image + * \param[in] d_h Height of the image + * \param[in] align Alignment, in bytes, of the image buffer and + * each row in the image(stride). + * + * \return Returns a pointer to the initialized image descriptor. If the img + * parameter is non-null, the value of the img parameter will be + * returned. + */ + vpx_image_t *vpx_img_alloc(vpx_image_t *img, + vpx_img_fmt_t fmt, + unsigned int d_w, + unsigned int d_h, + unsigned int align); + + /*!\brief Open a descriptor, using existing storage for the underlying image + * + * Returns a descriptor for storing an image of the given format. The + * storage for descriptor has been allocated elsewhere, and a descriptor is + * desired to "wrap" that storage. + * + * \param[in] img Pointer to storage for descriptor. If this parameter + * is NULL, the storage for the descriptor will be + * allocated on the heap. + * \param[in] fmt Format for the image + * \param[in] d_w Width of the image + * \param[in] d_h Height of the image + * \param[in] align Alignment, in bytes, of each row in the image. + * \param[in] img_data Storage to use for the image + * + * \return Returns a pointer to the initialized image descriptor. If the img + * parameter is non-null, the value of the img parameter will be + * returned. + */ + vpx_image_t *vpx_img_wrap(vpx_image_t *img, + vpx_img_fmt_t fmt, + unsigned int d_w, + unsigned int d_h, + unsigned int align, + unsigned char *img_data); + + + /*!\brief Set the rectangle identifying the displayed portion of the image + * + * Updates the displayed rectangle (aka viewport) on the image surface to + * match the specified coordinates and size. + * + * \param[in] img Image descriptor + * \param[in] x leftmost column + * \param[in] y topmost row + * \param[in] w width + * \param[in] h height + * + * \return 0 if the requested rectangle is valid, nonzero otherwise. + */ + int vpx_img_set_rect(vpx_image_t *img, + unsigned int x, + unsigned int y, + unsigned int w, + unsigned int h); + + + /*!\brief Flip the image vertically (top for bottom) + * + * Adjusts the image descriptor's pointers and strides to make the image + * be referenced upside-down. + * + * \param[in] img Image descriptor + */ + void vpx_img_flip(vpx_image_t *img); + + /*!\brief Close an image descriptor + * + * Frees all allocated storage associated with an image descriptor. + * + * \param[in] img Image descriptor + */ + void vpx_img_free(vpx_image_t *img); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // VPX_VPX_IMAGE_H_ diff --git a/bin/windows/vpx/include/vpx/vpx_integer.h b/bin/windows/vpx/include/vpx/vpx_integer.h new file mode 100644 index 00000000000..829c9d132c8 --- /dev/null +++ b/bin/windows/vpx/include/vpx/vpx_integer.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef VPX_VPX_INTEGER_H_ +#define VPX_VPX_INTEGER_H_ + +/* get ptrdiff_t, size_t, wchar_t, NULL */ +#include + +#if defined(_MSC_VER) +#define VPX_FORCE_INLINE __forceinline +#define VPX_INLINE __inline +#else +#define VPX_FORCE_INLINE __inline__ __attribute__(always_inline) +// TODO(jbb): Allow a way to force inline off for older compilers. +#define VPX_INLINE inline +#endif + +#if (defined(_MSC_VER) && (_MSC_VER < 1600)) || defined(VPX_EMULATE_INTTYPES) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#if (defined(_MSC_VER) && (_MSC_VER < 1600)) +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#define INT64_MAX _I64_MAX +#define INT32_MAX _I32_MAX +#define INT32_MIN _I32_MIN +#define INT16_MAX _I16_MAX +#define INT16_MIN _I16_MIN +#endif + +#ifndef _UINTPTR_T_DEFINED +typedef size_t uintptr_t; +#endif + +#else + +/* Most platforms have the C99 standard integer types. */ + +#if defined(__cplusplus) +# if !defined(__STDC_FORMAT_MACROS) +# define __STDC_FORMAT_MACROS +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS +# endif +#endif // __cplusplus + +#include + +#endif + +/* VS2010 defines stdint.h, but not inttypes.h */ +#if defined(_MSC_VER) && _MSC_VER < 1800 +#define PRId64 "I64d" +#else +#include +#endif + +#endif // VPX_VPX_INTEGER_H_ diff --git a/bin/windows/vpx/lib/32/libcompat-to-msvc.lib b/bin/windows/vpx/lib/32/libcompat-to-msvc.lib new file mode 100644 index 00000000000..6ec8b870e27 Binary files /dev/null and b/bin/windows/vpx/lib/32/libcompat-to-msvc.lib differ diff --git a/bin/windows/vpx/lib/32/libvpx.lib b/bin/windows/vpx/lib/32/libvpx.lib new file mode 100644 index 00000000000..1a9753e32c4 Binary files /dev/null and b/bin/windows/vpx/lib/32/libvpx.lib differ diff --git a/bin/windows/vpx/lib/64/libcompat-to-msvc.lib b/bin/windows/vpx/lib/64/libcompat-to-msvc.lib new file mode 100644 index 00000000000..5428547cca8 Binary files /dev/null and b/bin/windows/vpx/lib/64/libcompat-to-msvc.lib differ diff --git a/bin/windows/vpx/lib/64/libvpx.lib b/bin/windows/vpx/lib/64/libvpx.lib new file mode 100644 index 00000000000..3b552c027da Binary files /dev/null and b/bin/windows/vpx/lib/64/libvpx.lib differ diff --git a/bin/windows/vpx/lib/arm64/libvpx.lib b/bin/windows/vpx/lib/arm64/libvpx.lib new file mode 100644 index 00000000000..17f7a3294b4 Binary files /dev/null and b/bin/windows/vpx/lib/arm64/libvpx.lib differ diff --git a/bin/windows/vpx/lib/instructions.txt b/bin/windows/vpx/lib/instructions.txt new file mode 100644 index 00000000000..a028c759571 --- /dev/null +++ b/bin/windows/vpx/lib/instructions.txt @@ -0,0 +1,44 @@ +Instructions for Building EDuke32's Library Dependencies Targeting Win32 and Win64 +================================================================================== + +First, follow these instructions: http://wiki.eduke32.com/wiki/Building_EDuke32_on_Windows + +Download the latest sources from the link provided. + +The build output listed as "Desired Results" is what EDuke32 needs to function. + +The desired results for each library in some cases may need to be installed to the compiler. "x depends on the results of y to compile" means that the build output of x must be added to the compiler in this way. Copy files listed in each category to the appropriate destinations. Unless otherwise noted, do NOT copy the ".dll.a" file or else the final product may depend on external DLLs (which you may actually want). + +For MinGW (MinGW32): +from the compiler root (ex. C:/MinGW/) + * headers: include/ + * libraries: lib/ + +For MinGW-w64: +from the compiler root (ex. C:/MinGW-w64/mingw32-dw2/) + * headers: -w64-mingw32/include/ + * libraries: -w64-mingw32/lib/ + +Binaries (if mentioned) need to be present with the finished EDuke32 executables. They are not needed during compilation. + +NB: Text formatted as code blocks are commands to be pasted into the Windows command prompt. +http://wiki.eduke32.com/wiki/Working_with_the_Windows_Command_Prompt + +[//]: # (Plain text readers: This refers to lines beginning with exactly four spaces.) + + +libvpx +------ +### Prerequisites ### +Download the binary of yasm (http://yasm.tortall.net/) for your host system architecture. Both builds target both architectures. +The build environment needs pr.exe (https://mingw-lib.googlecode.com/files/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2). +### Download ### + * Instructions: http://www.webmproject.org/code/ + * Stable: http://downloads.webmproject.org/releases/webm/ + * Git: https://chromium.googlesource.com/webm/libvpx +### Build ### + sh ./configure --disable-vp8-encoder --disable-vp9-encoder --disable-multithread --disable-spatial-resampling --as=yasm && make libvpx.a +### Desired Results ### + * headers: vpx/vp8.h vpx/vp8dx.h vpx/vpx_codec.h vpx/vpx_decoder.h vpx/vpx_frame_buffer.h vpx/vpx_image.h vpx/vpx_integer.h + * libraries: libvpx.a + diff --git a/bin/windows/vpx/src/_dbg_LOAD_IMAGE.h b/bin/windows/vpx/src/_dbg_LOAD_IMAGE.h new file mode 100644 index 00000000000..0568f301685 --- /dev/null +++ b/bin/windows/vpx/src/_dbg_LOAD_IMAGE.h @@ -0,0 +1,55 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#ifndef _dbg_LOAD_IMAGE_h +#define _dbg_LOAD_IMAGE_h + +#ifndef WINAPI +#define WINAPI __stdcall +#endif + +#define IMAGEAPI DECLSPEC_IMPORT WINAPI +#define DBHLP_DEPRECIATED __declspec(deprecated) + +#define DBHLPAPI IMAGEAPI + +#ifndef EBACKTRACE_MINGW32 + +#define IMAGE_SEPARATION (64*1024) + + typedef struct _LOADED_IMAGE { + PSTR ModuleName; + HANDLE hFile; + PUCHAR MappedAddress; +#ifdef _IMAGEHLP64 + PIMAGE_NT_HEADERS64 FileHeader; +#else + PIMAGE_NT_HEADERS32 FileHeader; +#endif + PIMAGE_SECTION_HEADER LastRvaSection; + ULONG NumberOfSections; + PIMAGE_SECTION_HEADER Sections; + ULONG Characteristics; + BOOLEAN fSystemImage; + BOOLEAN fDOSImage; + BOOLEAN fReadOnly; + UCHAR Version; + LIST_ENTRY Links; + ULONG SizeOfImage; + } LOADED_IMAGE,*PLOADED_IMAGE; + +#endif + +#define MAX_SYM_NAME 2000 + + typedef struct _MODLOAD_DATA { + DWORD ssize; + DWORD ssig; + PVOID data; + DWORD size; + DWORD flags; + } MODLOAD_DATA,*PMODLOAD_DATA; + +#endif diff --git a/bin/windows/vpx/src/_dbg_common.h b/bin/windows/vpx/src/_dbg_common.h new file mode 100644 index 00000000000..2c412e4ccad --- /dev/null +++ b/bin/windows/vpx/src/_dbg_common.h @@ -0,0 +1,2051 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#ifndef _dbg_common_h +#define _dbg_common_h + +// from _mingw_mac.h +#ifndef __MINGW_EXTENSION +#if defined(__GNUC__) || defined(__GNUG__) +#define __MINGW_EXTENSION __extension__ +#else +#define __MINGW_EXTENSION +#endif +#endif + +/* Special case nameless struct/union. */ +#ifndef __C89_NAMELESS +#define __C89_NAMELESS __MINGW_EXTENSION + +#define __C89_NAMELESSSTRUCTNAME +#define __C89_NAMELESSUNIONNAME +#endif + +#include "_dbg_LOAD_IMAGE.h" + +// from winnt.h +#if defined(UNICODE) + typedef LPWSTR LPTCH,PTCH; + typedef LPWSTR PTSTR,LPTSTR; + typedef LPCWSTR PCTSTR,LPCTSTR; + typedef LPUWSTR PUTSTR,LPUTSTR; + typedef LPCUWSTR PCUTSTR,LPCUTSTR; + typedef LPWSTR LP; +#else + typedef LPSTR LPTCH,PTCH; + typedef LPSTR PTSTR,LPTSTR,PUTSTR,LPUTSTR; + typedef LPCSTR PCTSTR,LPCTSTR,PCUTSTR,LPCUTSTR; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + typedef WINBOOL (CALLBACK *PFIND_DEBUG_FILE_CALLBACK)(HANDLE FileHandle,PCSTR FileName,PVOID CallerData); + typedef WINBOOL (CALLBACK *PFIND_DEBUG_FILE_CALLBACKW)(HANDLE FileHandle,PCWSTR FileName,PVOID CallerData); + typedef WINBOOL (CALLBACK *PFINDFILEINPATHCALLBACK)(PCSTR filename,PVOID context); + typedef WINBOOL (CALLBACK *PFINDFILEINPATHCALLBACKW)(PCWSTR filename,PVOID context); + typedef WINBOOL (CALLBACK *PFIND_EXE_FILE_CALLBACK)(HANDLE FileHandle,PCSTR FileName,PVOID CallerData); + typedef WINBOOL (CALLBACK *PFIND_EXE_FILE_CALLBACKW)(HANDLE FileHandle,PCWSTR FileName,PVOID CallerData); + + typedef WINBOOL (WINAPI *PSYMBOLSERVERPROC)(LPCSTR,LPCSTR,PVOID,DWORD,DWORD,LPSTR); + typedef WINBOOL (WINAPI *PSYMBOLSERVEROPENPROC)(VOID); + typedef WINBOOL (WINAPI *PSYMBOLSERVERCLOSEPROC)(VOID); + typedef WINBOOL (WINAPI *PSYMBOLSERVERSETOPTIONSPROC)(UINT_PTR,ULONG64); + typedef WINBOOL (CALLBACK WINAPI *PSYMBOLSERVERCALLBACKPROC)(UINT_PTR action,ULONG64 data,ULONG64 context); + typedef UINT_PTR (WINAPI *PSYMBOLSERVERGETOPTIONSPROC)(); + typedef WINBOOL (WINAPI *PSYMBOLSERVERPINGPROC)(LPCSTR); + +#ifndef EBACKTRACE_MINGW32 + HANDLE IMAGEAPI FindDebugInfoFile(PCSTR FileName,PCSTR SymbolPath,PSTR DebugFilePath); +#endif + HANDLE IMAGEAPI FindDebugInfoFileEx(PCSTR FileName,PCSTR SymbolPath,PSTR DebugFilePath,PFIND_DEBUG_FILE_CALLBACK Callback,PVOID CallerData); + HANDLE IMAGEAPI FindDebugInfoFileExW(PCWSTR FileName,PCWSTR SymbolPath,PWSTR DebugFilePath,PFIND_DEBUG_FILE_CALLBACKW Callback,PVOID CallerData); + WINBOOL IMAGEAPI SymFindFileInPath(HANDLE hprocess,PCSTR SearchPath,PCSTR FileName,PVOID id,DWORD two,DWORD three,DWORD flags,LPSTR FoundFile,PFINDFILEINPATHCALLBACK callback,PVOID context); + WINBOOL IMAGEAPI SymFindFileInPathW(HANDLE hprocess,PCWSTR SearchPath,PCWSTR FileName,PVOID id,DWORD two,DWORD three,DWORD flags,LPSTR FoundFile,PFINDFILEINPATHCALLBACKW callback,PVOID context); +#ifndef EBACKTRACE_MINGW32 + HANDLE IMAGEAPI FindExecutableImage(PCSTR FileName,PCSTR SymbolPath,PSTR ImageFilePath); +#endif + HANDLE IMAGEAPI FindExecutableImageEx(PCSTR FileName,PCSTR SymbolPath,PSTR ImageFilePath,PFIND_EXE_FILE_CALLBACK Callback,PVOID CallerData); + HANDLE IMAGEAPI FindExecutableImageExW(PCWSTR FileName,PCWSTR SymbolPath,PWSTR ImageFilePath,PFIND_EXE_FILE_CALLBACKW Callback,PVOID CallerData); + PIMAGE_NT_HEADERS IMAGEAPI ImageNtHeader(PVOID Base); + PVOID IMAGEAPI ImageDirectoryEntryToDataEx(PVOID Base,BOOLEAN MappedAsImage,USHORT DirectoryEntry,PULONG Size,PIMAGE_SECTION_HEADER *FoundHeader); + PVOID IMAGEAPI ImageDirectoryEntryToData(PVOID Base,BOOLEAN MappedAsImage,USHORT DirectoryEntry,PULONG Size); + PIMAGE_SECTION_HEADER IMAGEAPI ImageRvaToSection(PIMAGE_NT_HEADERS NtHeaders,PVOID Base,ULONG Rva); + PVOID IMAGEAPI ImageRvaToVa(PIMAGE_NT_HEADERS NtHeaders,PVOID Base,ULONG Rva,PIMAGE_SECTION_HEADER *LastRvaSection); + +#define SSRVOPT_CALLBACK 0x0001 +#define SSRVOPT_DWORD 0x0002 +#define SSRVOPT_DWORDPTR 0x0004 +#define SSRVOPT_GUIDPTR 0x0008 +#define SSRVOPT_OLDGUIDPTR 0x0010 +#define SSRVOPT_UNATTENDED 0x0020 +#define SSRVOPT_NOCOPY 0x0040 +#define SSRVOPT_PARENTWIN 0x0080 +#define SSRVOPT_PARAMTYPE 0x0100 +#define SSRVOPT_SECURE 0x0200 +#define SSRVOPT_TRACE 0x0400 +#define SSRVOPT_SETCONTEXT 0x0800 +#define SSRVOPT_PROXY 0x1000 +#define SSRVOPT_DOWNSTREAM_STORE 0x2000 +#define SSRVOPT_RESET ((ULONG_PTR)-1) + +#define SSRVACTION_TRACE 1 +#define SSRVACTION_QUERYCANCEL 2 +#define SSRVACTION_EVENT 3 + +#if !defined _WIN64 && !defined EBACKTRACE_MINGW32 + typedef struct _IMAGE_DEBUG_INFORMATION { + LIST_ENTRY List; + DWORD ReservedSize; + PVOID ReservedMappedBase; + USHORT ReservedMachine; + USHORT ReservedCharacteristics; + DWORD ReservedCheckSum; + DWORD ImageBase; + DWORD SizeOfImage; + DWORD ReservedNumberOfSections; + PIMAGE_SECTION_HEADER ReservedSections; + DWORD ReservedExportedNamesSize; + PSTR ReservedExportedNames; + DWORD ReservedNumberOfFunctionTableEntries; + PIMAGE_FUNCTION_ENTRY ReservedFunctionTableEntries; + DWORD ReservedLowestFunctionStartingAddress; + DWORD ReservedHighestFunctionEndingAddress; + DWORD ReservedNumberOfFpoTableEntries; + PFPO_DATA ReservedFpoTableEntries; + DWORD SizeOfCoffSymbols; + PIMAGE_COFF_SYMBOLS_HEADER CoffSymbols; + DWORD ReservedSizeOfCodeViewSymbols; + PVOID ReservedCodeViewSymbols; + PSTR ImageFilePath; + PSTR ImageFileName; + PSTR ReservedDebugFilePath; + DWORD ReservedTimeDateStamp; + WINBOOL ReservedRomImage; + PIMAGE_DEBUG_DIRECTORY ReservedDebugDirectory; + DWORD ReservedNumberOfDebugDirectories; + DWORD ReservedOriginalFunctionTableBaseAddress; + DWORD Reserved[2]; + } IMAGE_DEBUG_INFORMATION,*PIMAGE_DEBUG_INFORMATION; + + PIMAGE_DEBUG_INFORMATION IMAGEAPI MapDebugInformation(HANDLE FileHandle,PSTR FileName,PSTR SymbolPath,DWORD ImageBase); + WINBOOL IMAGEAPI UnmapDebugInformation(PIMAGE_DEBUG_INFORMATION DebugInfo); +#endif + + typedef WINBOOL (CALLBACK *PENUMDIRTREE_CALLBACK)(LPCSTR FilePath,PVOID CallerData); + + WINBOOL IMAGEAPI SearchTreeForFile(PSTR RootPath,PSTR InputPathName,PSTR OutputPathBuffer); + WINBOOL IMAGEAPI SearchTreeForFileW(PWSTR RootPath,PWSTR InputPathName,PWSTR OutputPathBuffer); + WINBOOL IMAGEAPI EnumDirTree(HANDLE hProcess,PSTR RootPath,PSTR InputPathName,PSTR OutputPathBuffer,PENUMDIRTREE_CALLBACK Callback,PVOID CallbackData); + WINBOOL IMAGEAPI MakeSureDirectoryPathExists(PCSTR DirPath); + +#ifndef EBACKTRACE_MINGW32 +#define UNDNAME_COMPLETE (0x0000) +#define UNDNAME_NO_LEADING_UNDERSCORES (0x0001) +#define UNDNAME_NO_MS_KEYWORDS (0x0002) +#define UNDNAME_NO_FUNCTION_RETURNS (0x0004) +#define UNDNAME_NO_ALLOCATION_MODEL (0x0008) +#define UNDNAME_NO_ALLOCATION_LANGUAGE (0x0010) +#define UNDNAME_NO_MS_THISTYPE (0x0020) +#define UNDNAME_NO_CV_THISTYPE (0x0040) +#define UNDNAME_NO_THISTYPE (0x0060) +#define UNDNAME_NO_ACCESS_SPECIFIERS (0x0080) +#define UNDNAME_NO_THROW_SIGNATURES (0x0100) +#define UNDNAME_NO_MEMBER_TYPE (0x0200) +#define UNDNAME_NO_RETURN_UDT_MODEL (0x0400) +#define UNDNAME_32_BIT_DECODE (0x0800) +#define UNDNAME_NAME_ONLY (0x1000) +#define UNDNAME_NO_ARGUMENTS (0x2000) +#define UNDNAME_NO_SPECIAL_SYMS (0x4000) + +#define UNDNAME_NO_ARGUMENTS (0x2000) +#define UNDNAME_NO_SPECIAL_SYMS (0x4000) +#endif + + DWORD IMAGEAPI WINAPI UnDecorateSymbolName(PCSTR DecoratedName,PSTR UnDecoratedName,DWORD UndecoratedLength,DWORD Flags); + DWORD IMAGEAPI WINAPI UnDecorateSymbolNameW(PCWSTR DecoratedName,PWSTR UnDecoratedName,DWORD UndecoratedLength,DWORD Flags); + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define UnDecorateSymbolName UnDecorateSymbolNameW +#endif + +#define DBHHEADER_DEBUGDIRS 0x1 +#define DBHHEADER_CVMISC 0x2 + + typedef struct _MODLOAD_CVMISC { + DWORD oCV; + size_t cCV; + DWORD oMisc; + size_t cMisc; + DWORD dtImage; + DWORD cImage; + } MODLOAD_CVMISC, *PMODLOAD_CVMISC; + +#ifndef EBACKTRACE_MINGW32 + typedef enum { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat + } ADDRESS_MODE; +#endif + + typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; + } ADDRESS64,*LPADDRESS64; + +#ifdef _IMAGEHLP64 +#define ADDRESS ADDRESS64 +#define LPADDRESS LPADDRESS64 +#elif !defined(EBACKTRACE_MINGW32) + typedef struct _tagADDRESS { + DWORD Offset; + WORD Segment; + ADDRESS_MODE Mode; + } ADDRESS,*LPADDRESS; + + static __inline void Address32To64(LPADDRESS a32,LPADDRESS64 a64) { + a64->Offset = (ULONG64)(LONG64)(LONG)a32->Offset; + a64->Segment = a32->Segment; + a64->Mode = a32->Mode; + } + + static __inline void Address64To32(LPADDRESS64 a64,LPADDRESS a32) { + a32->Offset = (ULONG)a64->Offset; + a32->Segment = a64->Segment; + a32->Mode = a64->Mode; + } +#endif + + typedef struct _KDHELP64 { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 KiUserExceptionDispatcher; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD64 Reserved[5]; + } KDHELP64,*PKDHELP64; + +#ifdef _IMAGEHLP64 +#define KDHELP KDHELP64 +#define PKDHELP PKDHELP64 +#elif !defined(EBACKTRACE_MINGW32) + typedef struct _KDHELP { + DWORD Thread; + DWORD ThCallbackStack; + DWORD NextCallback; + DWORD FramePointer; + DWORD KiCallUserMode; + DWORD KeUserCallbackDispatcher; + DWORD SystemRangeStart; + DWORD ThCallbackBStore; + DWORD KiUserExceptionDispatcher; + DWORD StackBase; + DWORD StackLimit; + DWORD Reserved[5]; + } KDHELP,*PKDHELP; + + static __inline void KdHelp32To64(PKDHELP p32,PKDHELP64 p64) { + p64->Thread = p32->Thread; + p64->ThCallbackStack = p32->ThCallbackStack; + p64->NextCallback = p32->NextCallback; + p64->FramePointer = p32->FramePointer; + p64->KiCallUserMode = p32->KiCallUserMode; + p64->KeUserCallbackDispatcher = p32->KeUserCallbackDispatcher; + p64->SystemRangeStart = p32->SystemRangeStart; + p64->KiUserExceptionDispatcher = p32->KiUserExceptionDispatcher; + p64->StackBase = p32->StackBase; + p64->StackLimit = p32->StackLimit; + } +#endif + + typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; + ADDRESS64 AddrReturn; + ADDRESS64 AddrFrame; + ADDRESS64 AddrStack; + ADDRESS64 AddrBStore; + PVOID FuncTableEntry; + DWORD64 Params[4]; + WINBOOL Far; + WINBOOL Virtual; + DWORD64 Reserved[3]; + KDHELP64 KdHelp; + } STACKFRAME64,*LPSTACKFRAME64; + +#ifdef _IMAGEHLP64 +#define STACKFRAME STACKFRAME64 +#define LPSTACKFRAME LPSTACKFRAME64 +#elif !defined(EBACKTRACE_MINGW32) + typedef struct _tagSTACKFRAME { + ADDRESS AddrPC; + ADDRESS AddrReturn; + ADDRESS AddrFrame; + ADDRESS AddrStack; + PVOID FuncTableEntry; + DWORD Params[4]; + WINBOOL Far; + WINBOOL Virtual; + DWORD Reserved[3]; + KDHELP KdHelp; + ADDRESS AddrBStore; + } STACKFRAME,*LPSTACKFRAME; +#endif + + typedef WINBOOL (WINAPI *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,DWORD64 qwBaseAddress,PVOID lpBuffer,DWORD nSize,LPDWORD lpNumberOfBytesRead); + typedef PVOID (WINAPI *PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE hProcess,DWORD64 AddrBase); + typedef DWORD64 (WINAPI *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess,DWORD64 Address); + typedef DWORD64 (WINAPI *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,HANDLE hThread,LPADDRESS64 lpaddr); + + WINBOOL IMAGEAPI StackWalk64(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); + +#ifdef _IMAGEHLP64 +#define PREAD_PROCESS_MEMORY_ROUTINE PREAD_PROCESS_MEMORY_ROUTINE64 +#define PFUNCTION_TABLE_ACCESS_ROUTINE PFUNCTION_TABLE_ACCESS_ROUTINE64 +#define PGET_MODULE_BASE_ROUTINE PGET_MODULE_BASE_ROUTINE64 +#define PTRANSLATE_ADDRESS_ROUTINE PTRANSLATE_ADDRESS_ROUTINE64 +#define StackWalk StackWalk64 +#elif !defined(EBACKTRACE_MINGW32) + typedef WINBOOL (WINAPI *PREAD_PROCESS_MEMORY_ROUTINE)(HANDLE hProcess,DWORD lpBaseAddress,PVOID lpBuffer,DWORD nSize,PDWORD lpNumberOfBytesRead); + typedef PVOID (WINAPI *PFUNCTION_TABLE_ACCESS_ROUTINE)(HANDLE hProcess,DWORD AddrBase); + typedef DWORD (WINAPI *PGET_MODULE_BASE_ROUTINE)(HANDLE hProcess,DWORD Address); + typedef DWORD (WINAPI *PTRANSLATE_ADDRESS_ROUTINE)(HANDLE hProcess,HANDLE hThread,LPADDRESS lpaddr); + + WINBOOL IMAGEAPI StackWalk(DWORD MachineType,HANDLE hProcess,HANDLE hThread,LPSTACKFRAME StackFrame,PVOID ContextRecord,PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,PGET_MODULE_BASE_ROUTINE +GetModuleBaseRoutine,PTRANSLATE_ADDRESS_ROUTINE TranslateAddress); +#endif + +#ifndef EBACKTRACE_MINGW32 +#define API_VERSION_NUMBER 11 + + typedef struct API_VERSION { + USHORT MajorVersion; + USHORT MinorVersion; + USHORT Revision; + USHORT Reserved; + } API_VERSION,*LPAPI_VERSION; +#endif + + LPAPI_VERSION IMAGEAPI ImagehlpApiVersion(VOID); + LPAPI_VERSION IMAGEAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion); + DWORD IMAGEAPI GetTimestampForLoadedLibrary(HMODULE Module); + + typedef WINBOOL (CALLBACK *PSYM_ENUMMODULES_CALLBACK64)(PCSTR ModuleName,DWORD64 BaseOfDll,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYM_ENUMMODULES_CALLBACKW64)(PCWSTR ModuleName,DWORD64 BaseOfDll,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK64)(PCSTR SymbolName,DWORD64 SymbolAddress,ULONG SymbolSize,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK64W)(PCWSTR SymbolName,DWORD64 SymbolAddress,ULONG SymbolSize,PVOID UserContext); + typedef WINBOOL (CALLBACK *PENUMLOADED_MODULES_CALLBACK64)(PCSTR ModuleName,DWORD64 ModuleBase,ULONG ModuleSize,PVOID UserContext); + typedef WINBOOL (CALLBACK *PENUMLOADED_MODULES_CALLBACKW64)(PCWSTR ModuleName,DWORD64 ModuleBase,ULONG ModuleSize,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYMBOL_REGISTERED_CALLBACK64)(HANDLE hProcess,ULONG ActionCode,ULONG64 CallbackData,ULONG64 UserContext); + typedef PVOID (CALLBACK *PSYMBOL_FUNCENTRY_CALLBACK)(HANDLE hProcess,DWORD AddrBase,PVOID UserContext); + typedef PVOID (CALLBACK *PSYMBOL_FUNCENTRY_CALLBACK64)(HANDLE hProcess,ULONG64 AddrBase,ULONG64 UserContext); + +#ifdef _IMAGEHLP64 +#define PSYM_ENUMMODULES_CALLBACK PSYM_ENUMMODULES_CALLBACK64 +#define PSYM_ENUMSYMBOLS_CALLBACK PSYM_ENUMSYMBOLS_CALLBACK64 +#define PSYM_ENUMSYMBOLS_CALLBACKW PSYM_ENUMSYMBOLS_CALLBACK64W +#define PENUMLOADED_MODULES_CALLBACK PENUMLOADED_MODULES_CALLBACK64 +#define PSYMBOL_REGISTERED_CALLBACK PSYMBOL_REGISTERED_CALLBACK64 +#define PSYMBOL_FUNCENTRY_CALLBACK PSYMBOL_FUNCENTRY_CALLBACK64 +#elif !defined(EBACKTRACE_MINGW32) + typedef WINBOOL (CALLBACK *PSYM_ENUMMODULES_CALLBACK)(PCSTR ModuleName,ULONG BaseOfDll,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK)(PCSTR SymbolName,ULONG SymbolAddress,ULONG SymbolSize,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYM_ENUMSYMBOLS_CALLBACKW)(PCWSTR SymbolName,ULONG SymbolAddress,ULONG SymbolSize,PVOID UserContext); + typedef WINBOOL (CALLBACK *PENUMLOADED_MODULES_CALLBACK)(PCSTR ModuleName,ULONG ModuleBase,ULONG ModuleSize,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYMBOL_REGISTERED_CALLBACK)(HANDLE hProcess,ULONG ActionCode,PVOID CallbackData,PVOID UserContext); +#endif + +#define SYMFLAG_VALUEPRESENT 0x00000001 +#define SYMFLAG_REGISTER 0x00000008 +#define SYMFLAG_REGREL 0x00000010 +#define SYMFLAG_FRAMEREL 0x00000020 +#define SYMFLAG_PARAMETER 0x00000040 +#define SYMFLAG_LOCAL 0x00000080 +#define SYMFLAG_CONSTANT 0x00000100 +#define SYMFLAG_EXPORT 0x00000200 +#define SYMFLAG_FORWARDER 0x00000400 +#define SYMFLAG_FUNCTION 0x00000800 +#define SYMFLAG_VIRTUAL 0x00001000 +#define SYMFLAG_THUNK 0x00002000 +#define SYMFLAG_TLSREL 0x00004000 + +#ifndef EBACKTRACE_MINGW32 + typedef enum { + SymNone = 0, + SymCoff, + SymCv, + SymPdb, + SymExport, + SymDeferred, + SymSym, + SymDia, + SymVirtual, + NumSymTypes + } SYM_TYPE; +#endif + + typedef struct _IMAGEHLP_SYMBOL64 { + DWORD SizeOfStruct; + DWORD64 Address; + DWORD Size; + DWORD Flags; + DWORD MaxNameLength; + CHAR Name[1]; + } IMAGEHLP_SYMBOL64,*PIMAGEHLP_SYMBOL64; + + typedef struct _IMAGEHLP_SYMBOL64_PACKAGE { + IMAGEHLP_SYMBOL64 sym; + CHAR name[MAX_SYM_NAME + 1]; + } IMAGEHLP_SYMBOL64_PACKAGE,*PIMAGEHLP_SYMBOL64_PACKAGE; + +#ifdef _IMAGEHLP64 + +#define IMAGEHLP_SYMBOL IMAGEHLP_SYMBOL64 +#define PIMAGEHLP_SYMBOL PIMAGEHLP_SYMBOL64 +#define IMAGEHLP_SYMBOL_PACKAGE IMAGEHLP_SYMBOL64_PACKAGE +#define PIMAGEHLP_SYMBOL_PACKAGE PIMAGEHLP_SYMBOL64_PACKAGE +#elif !defined(EBACKTRACE_MINGW32) + + typedef struct _IMAGEHLP_SYMBOL { + DWORD SizeOfStruct; + DWORD Address; + DWORD Size; + DWORD Flags; + DWORD MaxNameLength; + CHAR Name[1]; + } IMAGEHLP_SYMBOL,*PIMAGEHLP_SYMBOL; + + typedef struct _IMAGEHLP_SYMBOL_PACKAGE { + IMAGEHLP_SYMBOL sym; + CHAR name[MAX_SYM_NAME + 1]; + } IMAGEHLP_SYMBOL_PACKAGE,*PIMAGEHLP_SYMBOL_PACKAGE; +#endif + + typedef struct _IMAGEHLP_MODULE64 { + DWORD SizeOfStruct; + DWORD64 BaseOfImage; + DWORD ImageSize; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD NumSyms; + SYM_TYPE SymType; + CHAR ModuleName[32]; + CHAR ImageName[256]; + CHAR LoadedImageName[256]; + CHAR LoadedPdbName[256]; + DWORD CVSig; + CHAR CVData[MAX_PATH*3]; + DWORD PdbSig; + GUID PdbSig70; + DWORD PdbAge; + WINBOOL PdbUnmatched; + WINBOOL DbgUnmatched; + WINBOOL LineNumbers; + WINBOOL GlobalSymbols; + WINBOOL TypeInfo; + WINBOOL SourceIndexed; + WINBOOL Publics; + } IMAGEHLP_MODULE64,*PIMAGEHLP_MODULE64; + + typedef struct _IMAGEHLP_MODULE64W { + DWORD SizeOfStruct; + DWORD64 BaseOfImage; + DWORD ImageSize; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD NumSyms; + SYM_TYPE SymType; + WCHAR ModuleName[32]; + WCHAR ImageName[256]; + WCHAR LoadedImageName[256]; + WCHAR LoadedPdbName[256]; + DWORD CVSig; + WCHAR CVData[MAX_PATH*3]; + DWORD PdbSig; + GUID PdbSig70; + DWORD PdbAge; + WINBOOL PdbUnmatched; + WINBOOL DbgUnmatched; + WINBOOL LineNumbers; + WINBOOL GlobalSymbols; + WINBOOL TypeInfo; + WINBOOL SourceIndexed; + WINBOOL Publics; + } IMAGEHLP_MODULEW64,*PIMAGEHLP_MODULEW64; + +#ifdef _IMAGEHLP64 +#define IMAGEHLP_MODULE IMAGEHLP_MODULE64 +#define PIMAGEHLP_MODULE PIMAGEHLP_MODULE64 +#define IMAGEHLP_MODULEW IMAGEHLP_MODULEW64 +#define PIMAGEHLP_MODULEW PIMAGEHLP_MODULEW64 +#elif !defined(EBACKTRACE_MINGW32) + typedef struct _IMAGEHLP_MODULE { + DWORD SizeOfStruct; + DWORD BaseOfImage; + DWORD ImageSize; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD NumSyms; + SYM_TYPE SymType; + CHAR ModuleName[32]; + CHAR ImageName[256]; + CHAR LoadedImageName[256]; + } IMAGEHLP_MODULE,*PIMAGEHLP_MODULE; + + typedef struct _IMAGEHLP_MODULEW { + DWORD SizeOfStruct; + DWORD BaseOfImage; + DWORD ImageSize; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD NumSyms; + SYM_TYPE SymType; + WCHAR ModuleName[32]; + WCHAR ImageName[256]; + WCHAR LoadedImageName[256]; + } IMAGEHLP_MODULEW,*PIMAGEHLP_MODULEW; +#endif + + typedef struct _IMAGEHLP_LINE64 { + DWORD SizeOfStruct; + PVOID Key; + DWORD LineNumber; + PCHAR FileName; + DWORD64 Address; + } IMAGEHLP_LINE64,*PIMAGEHLP_LINE64; + + typedef struct _IMAGEHLP_LINEW64 { + DWORD SizeOfStruct; + PVOID Key; + DWORD LineNumber; + PWSTR FileName; + DWORD64 Address; + } IMAGEHLP_LINEW64, *PIMAGEHLP_LINEW64; + +#ifdef _IMAGEHLP64 +#define IMAGEHLP_LINE IMAGEHLP_LINE64 +#define PIMAGEHLP_LINE PIMAGEHLP_LINE64 +#elif !defined(EBACKTRACE_MINGW32) + typedef struct _IMAGEHLP_LINE { + DWORD SizeOfStruct; + PVOID Key; + DWORD LineNumber; + PCHAR FileName; + DWORD Address; + } IMAGEHLP_LINE,*PIMAGEHLP_LINE; +#endif + + typedef struct _SOURCEFILE { + DWORD64 ModBase; + PCHAR FileName; + } SOURCEFILE,*PSOURCEFILE; + + typedef struct _SOURCEFILEW { + DWORD64 ModBase; + PWCHAR FileName; + } SOURCEFILEW,*PSOURCEFILEW; + +#ifndef EBACKTRACE_MINGW32 +#define CBA_DEFERRED_SYMBOL_LOAD_START 0x00000001 +#define CBA_DEFERRED_SYMBOL_LOAD_COMPLETE 0x00000002 +#define CBA_DEFERRED_SYMBOL_LOAD_FAILURE 0x00000003 +#define CBA_SYMBOLS_UNLOADED 0x00000004 +#define CBA_DUPLICATE_SYMBOL 0x00000005 +#define CBA_READ_MEMORY 0x00000006 +#define CBA_DEFERRED_SYMBOL_LOAD_CANCEL 0x00000007 +#define CBA_SET_OPTIONS 0x00000008 +#define CBA_EVENT 0x00000010 +#define CBA_DEFERRED_SYMBOL_LOAD_PARTIAL 0x00000020 +#define CBA_DEBUG_INFO 0x10000000 +#define CBA_SRCSRV_INFO 0x20000000 +#define CBA_SRCSRV_EVENT 0x40000000 +#endif + + typedef struct _IMAGEHLP_CBA_READ_MEMORY { + DWORD64 addr; + PVOID buf; + DWORD bytes; + DWORD *bytesread; + } IMAGEHLP_CBA_READ_MEMORY,*PIMAGEHLP_CBA_READ_MEMORY; + + enum { + sevInfo = 0, + sevProblem, + sevAttn, + sevFatal, + sevMax + }; + + typedef struct _IMAGEHLP_CBA_EVENT { + DWORD severity; + DWORD code; + PCHAR desc; + PVOID object; + } IMAGEHLP_CBA_EVENT,*PIMAGEHLP_CBA_EVENT; + + typedef struct _IMAGEHLP_DEFERRED_SYMBOL_LOAD64 { + DWORD SizeOfStruct; + DWORD64 BaseOfImage; + DWORD CheckSum; + DWORD TimeDateStamp; + CHAR FileName[MAX_PATH]; + BOOLEAN Reparse; + HANDLE hFile; + DWORD Flags; + } IMAGEHLP_DEFERRED_SYMBOL_LOAD64,*PIMAGEHLP_DEFERRED_SYMBOL_LOAD64; + +#define DSLFLAG_MISMATCHED_PDB 0x1 +#define DSLFLAG_MISMATCHED_DBG 0x2 + +#ifdef _IMAGEHLP64 +#define IMAGEHLP_DEFERRED_SYMBOL_LOAD IMAGEHLP_DEFERRED_SYMBOL_LOAD64 +#define PIMAGEHLP_DEFERRED_SYMBOL_LOAD PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 +#elif !defined(EBACKTRACE_MINGW32) + typedef struct _IMAGEHLP_DEFERRED_SYMBOL_LOAD { + DWORD SizeOfStruct; + DWORD BaseOfImage; + DWORD CheckSum; + DWORD TimeDateStamp; + CHAR FileName[MAX_PATH]; + BOOLEAN Reparse; + HANDLE hFile; + } IMAGEHLP_DEFERRED_SYMBOL_LOAD,*PIMAGEHLP_DEFERRED_SYMBOL_LOAD; +#endif + + typedef struct _IMAGEHLP_DUPLICATE_SYMBOL64 { + DWORD SizeOfStruct; + DWORD NumberOfDups; + PIMAGEHLP_SYMBOL64 Symbol; + DWORD SelectedSymbol; + } IMAGEHLP_DUPLICATE_SYMBOL64,*PIMAGEHLP_DUPLICATE_SYMBOL64; + +#ifdef _IMAGEHLP64 +#define IMAGEHLP_DUPLICATE_SYMBOL IMAGEHLP_DUPLICATE_SYMBOL64 +#define PIMAGEHLP_DUPLICATE_SYMBOL PIMAGEHLP_DUPLICATE_SYMBOL64 +#elif !defined(EBACKTRACE_MINGW32) + typedef struct _IMAGEHLP_DUPLICATE_SYMBOL { + DWORD SizeOfStruct; + DWORD NumberOfDups; + PIMAGEHLP_SYMBOL Symbol; + DWORD SelectedSymbol; + } IMAGEHLP_DUPLICATE_SYMBOL,*PIMAGEHLP_DUPLICATE_SYMBOL; +#endif + +typedef struct _SYMSRV_INDEX_INFO { + DWORD sizeofstruct; + CHAR file[MAX_PATH +1]; + WINBOOL stripped; + DWORD timestamp; + DWORD size; + CHAR dbgfile[MAX_PATH +1]; + CHAR pdbfile[MAX_PATH + 1]; + GUID guid; + DWORD sig; + DWORD age; +} SYMSRV_INDEX_INFO, *PSYMSRV_INDEX_INFO; + +typedef struct _SYMSRV_INDEX_INFOW { + DWORD sizeofstruct; + WCHAR file[MAX_PATH +1]; + WINBOOL stripped; + DWORD timestamp; + DWORD size; + WCHAR dbgfile[MAX_PATH +1]; + WCHAR pdbfile[MAX_PATH + 1]; + GUID guid; + DWORD sig; + DWORD age; +} SYMSRV_INDEX_INFOW, *PSYMSRV_INDEX_INFOW; + + WINBOOL IMAGEAPI SymSetParentWindow(HWND hwnd); + PCHAR IMAGEAPI SymSetHomeDirectory(HANDLE hProcess,PCSTR dir); + PCHAR IMAGEAPI SymSetHomeDirectoryW(HANDLE hProcess,PCWSTR dir); + PCHAR IMAGEAPI SymGetHomeDirectory(DWORD type,PSTR dir,size_t size); + PWCHAR IMAGEAPI SymGetHomeDirectoryW(DWORD type,PWSTR dir,size_t size); + +#define hdBase 0 +#define hdSym 1 +#define hdSrc 2 +#define hdMax 3 + +#ifndef EBACKTRACE_MINGW32 +#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_NO_PROMPTS 0x00080000 +#define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 +#define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 +#define SYMOPT_FAVOR_COMPRESSED 0x00800000 +#define SYMOPT_FLAT_DIRECTORY 0x00400000 +#define SYMOPT_IGNORE_IMAGEDIR 0x00200000 +#define SYMOPT_OVERWRITE 0x00100000 + +#define SYMOPT_DEBUG 0x80000000 +#endif + + DWORD IMAGEAPI SymSetOptions(DWORD SymOptions); + DWORD IMAGEAPI SymGetOptions(VOID); + WINBOOL IMAGEAPI SymCleanup(HANDLE hProcess); + WINBOOL IMAGEAPI SymMatchString(PCSTR string,PCSTR expression,WINBOOL fCase); + WINBOOL IMAGEAPI SymMatchStringW(PCWSTR string,PCWSTR expression,WINBOOL fCase); + + typedef WINBOOL (CALLBACK *PSYM_ENUMSOURCEFILES_CALLBACK)(PSOURCEFILE pSourceFile,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYM_ENUMSOURCEFILES_CALLBACKW)(PSOURCEFILEW pSourceFile,PVOID UserContext); +#define PSYM_ENUMSOURCFILES_CALLBACK PSYM_ENUMSOURCEFILES_CALLBACK + + WINBOOL IMAGEAPI SymEnumSourceFiles(HANDLE hProcess,ULONG64 ModBase,PCSTR Mask,PSYM_ENUMSOURCEFILES_CALLBACK cbSrcFiles,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumSourceFilesW(HANDLE hProcess,ULONG64 ModBase,PCWSTR Mask,PSYM_ENUMSOURCEFILES_CALLBACKW cbSrcFiles,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumerateModules64(HANDLE hProcess,PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumerateModulesW64(HANDLE hProcess,PSYM_ENUMMODULES_CALLBACKW64 EnumModulesCallback,PVOID UserContext); + +#ifdef _IMAGEHLP64 +#define SymEnumerateModules SymEnumerateModules64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymEnumerateModules(HANDLE hProcess,PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,PVOID UserContext); +#endif + + WINBOOL IMAGEAPI SymEnumerateSymbols64(HANDLE hProcess,DWORD64 BaseOfDll,PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumerateSymbolsW64(HANDLE hProcess,DWORD64 BaseOfDll,PSYM_ENUMSYMBOLS_CALLBACK64W EnumSymbolsCallback,PVOID UserContext); + +#ifdef _IMAGEHLP64 +#define SymEnumerateSymbols SymEnumerateSymbols64 +#define SymEnumerateSymbolsW SymEnumerateSymbolsW64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymEnumerateSymbols(HANDLE hProcess,DWORD BaseOfDll,PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumerateSymbolsW(HANDLE hProcess,DWORD BaseOfDll,PSYM_ENUMSYMBOLS_CALLBACKW EnumSymbolsCallback,PVOID UserContext); +#endif + + WINBOOL IMAGEAPI EnumerateLoadedModules64(HANDLE hProcess,PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback,PVOID UserContext); + WINBOOL IMAGEAPI EnumerateLoadedModulesW64(HANDLE hProcess,PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback,PVOID UserContext); + +#ifdef DBGHELP_TRANSLATE_TCHAR + #define EnumerateLoadedModules64 EnumerateLoadedModulesW64 +#endif + +#ifdef _IMAGEHLP64 +#define EnumerateLoadedModules EnumerateLoadedModules64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI EnumerateLoadedModules(HANDLE hProcess,PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,PVOID UserContext); +#endif + + PVOID IMAGEAPI SymFunctionTableAccess64(HANDLE hProcess,DWORD64 AddrBase); + +#ifdef _IMAGEHLP64 +#define SymFunctionTableAccess SymFunctionTableAccess64 +#elif !defined(EBACKTRACE_MINGW32) + PVOID IMAGEAPI SymFunctionTableAccess(HANDLE hProcess,DWORD AddrBase); +#endif + + WINBOOL IMAGEAPI SymGetModuleInfo64(HANDLE hProcess,DWORD64 qwAddr,PIMAGEHLP_MODULE64 ModuleInfo); + WINBOOL IMAGEAPI SymGetModuleInfoW64(HANDLE hProcess,DWORD64 qwAddr,PIMAGEHLP_MODULEW64 ModuleInfo); + +#ifdef _IMAGEHLP64 +#define SymGetModuleInfo SymGetModuleInfo64 +#define SymGetModuleInfoW SymGetModuleInfoW64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetModuleInfo(HANDLE hProcess,DWORD dwAddr,PIMAGEHLP_MODULE ModuleInfo); + WINBOOL IMAGEAPI SymGetModuleInfoW(HANDLE hProcess,DWORD dwAddr,PIMAGEHLP_MODULEW ModuleInfo); +#endif + + DWORD64 IMAGEAPI SymGetModuleBase64(HANDLE hProcess,DWORD64 qwAddr); + +#ifdef _IMAGEHLP64 +#define SymGetModuleBase SymGetModuleBase64 +#elif !defined(EBACKTRACE_MINGW32) + DWORD IMAGEAPI SymGetModuleBase(HANDLE hProcess,DWORD dwAddr); +#endif + + WINBOOL IMAGEAPI SymGetSymNext64(HANDLE hProcess,PIMAGEHLP_SYMBOL64 Symbol); + +#ifdef _IMAGEHLP64 +#define SymGetSymNext SymGetSymNext64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetSymNext(HANDLE hProcess,PIMAGEHLP_SYMBOL Symbol); +#endif + + WINBOOL IMAGEAPI SymGetSymPrev64(HANDLE hProcess,PIMAGEHLP_SYMBOL64 Symbol); + +#ifdef _IMAGEHLP64 +#define SymGetSymPrev SymGetSymPrev64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetSymPrev(HANDLE hProcess,PIMAGEHLP_SYMBOL Symbol); +#endif + + typedef struct _SRCCODEINFO { + DWORD SizeOfStruct; + PVOID Key; + DWORD64 ModBase; + CHAR Obj[MAX_PATH + 1]; + CHAR FileName[MAX_PATH + 1]; + DWORD LineNumber; + DWORD64 Address; + } SRCCODEINFO,*PSRCCODEINFO; + + typedef struct _SRCCODEINFOW { + DWORD SizeOfStruct; + PVOID Key; + DWORD64 ModBase; + WCHAR Obj[MAX_PATH + 1]; + WCHAR FileName[MAX_PATH + 1]; + DWORD LineNumber; + DWORD64 Address; + } SRCCODEINFOW,*PSRCCODEINFOW; + + typedef WINBOOL (CALLBACK *PSYM_ENUMLINES_CALLBACK)(PSRCCODEINFO LineInfo,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYM_ENUMLINES_CALLBACKW)(PSRCCODEINFOW LineInfo,PVOID UserContext); + + WINBOOL IMAGEAPI SymEnumLines(HANDLE hProcess,ULONG64 Base,PCSTR Obj,PCSTR File,PSYM_ENUMLINES_CALLBACK EnumLinesCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumLinesW(HANDLE hProcess,ULONG64 Base,PCWSTR Obj,PCSTR File,PSYM_ENUMLINES_CALLBACKW EnumLinesCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymGetLineFromAddr64(HANDLE hProcess,DWORD64 qwAddr,PDWORD pdwDisplacement,PIMAGEHLP_LINE64 Line64); + WINBOOL IMAGEAPI SymGetLineFromAddrW64(HANDLE hProcess,DWORD64 qwAddr,PDWORD pdwDisplacement,PIMAGEHLP_LINEW64 Line64); + +#ifdef _IMAGEHLP64 +#define SymGetLineFromAddr SymGetLineFromAddr64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetLineFromAddr(HANDLE hProcess,DWORD dwAddr,PDWORD pdwDisplacement,PIMAGEHLP_LINE Line); +#endif + + WINBOOL IMAGEAPI SymGetLineFromName64(HANDLE hProcess,PCSTR ModuleName,PCSTR FileName,DWORD dwLineNumber,PLONG plDisplacement,PIMAGEHLP_LINE64 Line); + WINBOOL IMAGEAPI SymGetLineFromNameW64(HANDLE hProcess,PCWSTR ModuleName,PCWSTR FileName,DWORD dwLineNumber,PLONG plDisplacement,PIMAGEHLP_LINEW64 Line); + +#ifdef _IMAGEHLP64 +#define SymGetLineFromName SymGetLineFromName64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetLineFromName(HANDLE hProcess,PCSTR ModuleName,PCSTR FileName,DWORD dwLineNumber,PLONG plDisplacement,PIMAGEHLP_LINE Line); +#endif + + WINBOOL IMAGEAPI SymGetLineNext64(HANDLE hProcess,PIMAGEHLP_LINE64 Line); + WINBOOL IMAGEAPI SymGetLineNextW64(HANDLE hProcess,PIMAGEHLP_LINEW64 Line); + +#ifdef _IMAGEHLP64 +#define SymGetLineNext SymGetLineNext64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetLineNext(HANDLE hProcess,PIMAGEHLP_LINE Line); +#endif + + WINBOOL IMAGEAPI SymGetLinePrev64(HANDLE hProcess,PIMAGEHLP_LINE64 Line); + WINBOOL IMAGEAPI SymGetLinePrevW64(HANDLE hProcess,PIMAGEHLP_LINEW64 Line); + +#ifdef _IMAGEHLP64 +#define SymGetLinePrev SymGetLinePrev64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetLinePrev(HANDLE hProcess,PIMAGEHLP_LINE Line); +#endif + +#ifndef EBACKTRACE_MINGW32 + WINBOOL IMAGEAPI SymMatchFileName(PCSTR FileName,PCSTR Match,PSTR *FileNameStop,PSTR *MatchStop); +#endif + WINBOOL IMAGEAPI SymMatchFileNameW(PCWSTR FileName,PCWSTR Match,PWSTR *FileNameStop,PWSTR *MatchStop); +#ifndef EBACKTRACE_MINGW32 + WINBOOL IMAGEAPI SymInitialize(HANDLE hProcess,PCSTR UserSearchPath,WINBOOL fInvadeProcess); +#endif + WINBOOL IMAGEAPI SymInitializeW(HANDLE hProcess,PCWSTR UserSearchPath,WINBOOL fInvadeProcess); +#ifndef EBACKTRACE_MINGW32 + WINBOOL IMAGEAPI SymGetSearchPath(HANDLE hProcess,PSTR SearchPath,DWORD SearchPathLength); +#endif + WINBOOL IMAGEAPI SymGetSearchPathW(HANDLE hProcess,PWSTR SearchPath,DWORD SearchPathLength); +#ifndef EBACKTRACE_MINGW32 + WINBOOL IMAGEAPI SymSetSearchPath(HANDLE hProcess,PCSTR SearchPath); +#endif + WINBOOL IMAGEAPI SymSetSearchPathW(HANDLE hProcess,PCWSTR SearchPath); + DWORD64 IMAGEAPI SymLoadModule64(HANDLE hProcess,HANDLE hFile,PSTR ImageName,PSTR ModuleName,DWORD64 BaseOfDll,DWORD SizeOfDll); + +#define SLMFLAG_VIRTUAL 0x1 + + DWORD64 IMAGEAPI SymLoadModuleEx(HANDLE hProcess,HANDLE hFile,PCSTR ImageName,PCSTR ModuleName,DWORD64 BaseOfDll,DWORD DllSize,PMODLOAD_DATA Data,DWORD Flags); + DWORD64 IMAGEAPI SymLoadModuleExW(HANDLE hProcess,HANDLE hFile,PCWSTR ImageName,PCWSTR ModuleName,DWORD64 BaseOfDll,DWORD DllSize,PMODLOAD_DATA Data,DWORD Flags); + +#ifdef _IMAGEHLP64 +#define SymLoadModule SymLoadModule64 +#elif !defined(EBACKTRACE_MINGW32) + DWORD IMAGEAPI SymLoadModule(HANDLE hProcess,HANDLE hFile,PCSTR ImageName,PCSTR ModuleName,DWORD BaseOfDll,DWORD SizeOfDll); +#endif + + WINBOOL IMAGEAPI SymUnloadModule64(HANDLE hProcess,DWORD64 BaseOfDll); + +#ifdef _IMAGEHLP64 +#define SymUnloadModule SymUnloadModule64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymUnloadModule(HANDLE hProcess,DWORD BaseOfDll); +#endif + + WINBOOL IMAGEAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym,PSTR UnDecName,DWORD UnDecNameLength); + +#ifdef _IMAGEHLP64 +#define SymUnDName SymUnDName64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymUnDName(PIMAGEHLP_SYMBOL sym,PSTR UnDecName,DWORD UnDecNameLength); +#endif + + WINBOOL IMAGEAPI SymRegisterCallback64(HANDLE hProcess,PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,ULONG64 UserContext); + WINBOOL IMAGEAPI SymRegisterCallback64W(HANDLE hProcess,PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,ULONG64 UserContext); + + WINBOOL IMAGEAPI SymRegisterFunctionEntryCallback64(HANDLE hProcess,PSYMBOL_FUNCENTRY_CALLBACK64 CallbackFunction,ULONG64 UserContext); + +#ifdef _IMAGEHLP64 +#define SymRegisterCallback SymRegisterCallback64 +#define SymRegisterFunctionEntryCallback SymRegisterFunctionEntryCallback64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymRegisterCallback(HANDLE hProcess,PSYMBOL_REGISTERED_CALLBACK CallbackFunction,PVOID UserContext); + WINBOOL IMAGEAPI SymRegisterFunctionEntryCallback(HANDLE hProcess,PSYMBOL_FUNCENTRY_CALLBACK CallbackFunction,PVOID UserContext); +#endif + + typedef struct _IMAGEHLP_SYMBOL_SRC { + DWORD sizeofstruct; + DWORD type; + char file[MAX_PATH]; + } IMAGEHLP_SYMBOL_SRC,*PIMAGEHLP_SYMBOL_SRC; + + typedef struct _MODULE_TYPE_INFO { + USHORT dataLength; + USHORT leaf; + BYTE data[1]; + } MODULE_TYPE_INFO,*PMODULE_TYPE_INFO; + + typedef struct _SYMBOL_INFO { + ULONG SizeOfStruct; + ULONG TypeIndex; + ULONG64 Reserved[2]; + ULONG info; + ULONG Size; + ULONG64 ModBase; + ULONG Flags; + ULONG64 Value; + ULONG64 Address; + ULONG Register; + ULONG Scope; + ULONG Tag; + ULONG NameLen; + ULONG MaxNameLen; + CHAR Name[1]; + } SYMBOL_INFO,*PSYMBOL_INFO; + + typedef struct _SYMBOL_INFOW { + ULONG SizeOfStruct; + ULONG TypeIndex; + ULONG64 Reserved[2]; + ULONG info; + ULONG Size; + ULONG64 ModBase; + ULONG Flags; + ULONG64 Value; + ULONG64 Address; + ULONG Register; + ULONG Scope; + ULONG Tag; + ULONG NameLen; + ULONG MaxNameLen; + WCHAR Name[1]; + } SYMBOL_INFOW,*PSYMBOL_INFOW; + +#define SYMFLAG_CLR_TOKEN 0x00040000 +#define SYMFLAG_CONSTANT 0x00000100 +#define SYMFLAG_EXPORT 0x00000200 +#define SYMFLAG_FORWARDER 0x00000400 +#define SYMFLAG_FRAMEREL 0x00000020 +#define SYMFLAG_FUNCTION 0x00000800 +#define SYMFLAG_ILREL 0x00010000 +#define SYMFLAG_LOCAL 0x00000080 +#define SYMFLAG_METADATA 0x00020000 +#define SYMFLAG_PARAMETER 0x00000040 +#define SYMFLAG_REGISTER 0x00000008 +#define SYMFLAG_REGREL 0x00000010 +#define SYMFLAG_SLOT 0x00008000 +#define SYMFLAG_THUNK 0x00002000 +#define SYMFLAG_TLSREL 0x00004000 +#define SYMFLAG_VALUEPRESENT 0x00000001 +#define SYMFLAG_VIRTUAL 0x00001000 + + typedef struct _SYMBOL_INFO_PACKAGE { + SYMBOL_INFO si; + CHAR name[MAX_SYM_NAME + 1]; + } SYMBOL_INFO_PACKAGE,*PSYMBOL_INFO_PACKAGE; + + typedef struct _IMAGEHLP_STACK_FRAME { + ULONG64 InstructionOffset; + ULONG64 ReturnOffset; + ULONG64 FrameOffset; + ULONG64 StackOffset; + ULONG64 BackingStoreOffset; + ULONG64 FuncTableEntry; + ULONG64 Params[4]; + ULONG64 Reserved[5]; + WINBOOL Virtual; + ULONG Reserved2; + } IMAGEHLP_STACK_FRAME,*PIMAGEHLP_STACK_FRAME; + + typedef VOID IMAGEHLP_CONTEXT,*PIMAGEHLP_CONTEXT; + + WINBOOL IMAGEAPI SymSetContext(HANDLE hProcess,PIMAGEHLP_STACK_FRAME StackFrame,PIMAGEHLP_CONTEXT Context); + WINBOOL IMAGEAPI SymFromAddr(HANDLE hProcess,DWORD64 Address,PDWORD64 Displacement,PSYMBOL_INFO Symbol); + WINBOOL IMAGEAPI SymFromAddrW(HANDLE hProcess,DWORD64 Address,PDWORD64 Displacement,PSYMBOL_INFOW Symbol); + WINBOOL IMAGEAPI SymFromToken(HANDLE hProcess,DWORD64 Base,DWORD Token,PSYMBOL_INFO Symbol); + WINBOOL IMAGEAPI SymFromTokenW(HANDLE hProcess,DWORD64 Base,DWORD Token,PSYMBOL_INFOW Symbol); + WINBOOL IMAGEAPI SymFromName(HANDLE hProcess,PCSTR Name,PSYMBOL_INFO Symbol); + WINBOOL IMAGEAPI SymFromNameW(HANDLE hProcess,PCWSTR Name,PSYMBOL_INFOW Symbol); + + typedef WINBOOL (CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACK)(PSYMBOL_INFO pSymInfo,ULONG SymbolSize,PVOID UserContext); + typedef WINBOOL (CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACKW)(PSYMBOL_INFOW pSymInfo,ULONG SymbolSize,PVOID UserContext); + + WINBOOL IMAGEAPI SymEnumSymbols(HANDLE hProcess,ULONG64 BaseOfDll,PCSTR Mask,PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumSymbolsW(HANDLE hProcess,ULONG64 BaseOfDll,PCWSTR Mask,PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumSymbolsForAddr(HANDLE hProcess,DWORD64 Address,PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumSymbolsForAddrW(HANDLE hProcess,DWORD64 Address,PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,PVOID UserContext); + +#define SYMENUMFLAG_FULLSRCH 1 +#define SYMENUMFLAG_SPEEDSRCH 2 + + typedef enum _IMAGEHLP_SYMBOL_TYPE_INFO { + TI_GET_SYMTAG, + TI_GET_SYMNAME, + TI_GET_LENGTH, + TI_GET_TYPE, + TI_GET_TYPEID, + TI_GET_BASETYPE, + TI_GET_ARRAYINDEXTYPEID, + TI_FINDCHILDREN, + TI_GET_DATAKIND, + TI_GET_ADDRESSOFFSET, + TI_GET_OFFSET, + TI_GET_VALUE, + TI_GET_COUNT, + TI_GET_CHILDRENCOUNT, + TI_GET_BITPOSITION, + TI_GET_VIRTUALBASECLASS, + TI_GET_VIRTUALTABLESHAPEID, + TI_GET_VIRTUALBASEPOINTEROFFSET, + TI_GET_CLASSPARENTID, + TI_GET_NESTED, + TI_GET_SYMINDEX, + TI_GET_LEXICALPARENT, + TI_GET_ADDRESS, + TI_GET_THISADJUST, + TI_GET_UDTKIND, + TI_IS_EQUIV_TO, + TI_GET_CALLING_CONVENTION + } IMAGEHLP_SYMBOL_TYPE_INFO; + + typedef struct _TI_FINDCHILDREN_PARAMS { + ULONG Count; + ULONG Start; + ULONG ChildId[1]; + } TI_FINDCHILDREN_PARAMS; + + WINBOOL IMAGEAPI SymGetTypeInfo(HANDLE hProcess,DWORD64 ModBase,ULONG TypeId,IMAGEHLP_SYMBOL_TYPE_INFO GetType,PVOID pInfo); + WINBOOL IMAGEAPI SymEnumTypes(HANDLE hProcess,ULONG64 BaseOfDll,PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymEnumTypesW(HANDLE hProcess,ULONG64 BaseOfDll,PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,PVOID UserContext); + WINBOOL IMAGEAPI SymGetTypeFromName(HANDLE hProcess,ULONG64 BaseOfDll,PCSTR Name,PSYMBOL_INFO Symbol); + WINBOOL IMAGEAPI SymGetTypeFromNameW(HANDLE hProcess,ULONG64 BaseOfDll,PCWSTR Name,PSYMBOL_INFOW Symbol); + WINBOOL IMAGEAPI SymAddSymbol(HANDLE hProcess,ULONG64 BaseOfDll,PCSTR Name,DWORD64 Address,DWORD Size,DWORD Flags); + WINBOOL IMAGEAPI SymAddSymbolW(HANDLE hProcess,ULONG64 BaseOfDll,PCWSTR Name,DWORD64 Address,DWORD Size,DWORD Flags); + WINBOOL IMAGEAPI SymDeleteSymbol(HANDLE hProcess,ULONG64 BaseOfDll,PCSTR Name,DWORD64 Address,DWORD Flags); + WINBOOL IMAGEAPI SymDeleteSymbolW(HANDLE hProcess,ULONG64 BaseOfDll,PCWSTR Name,DWORD64 Address,DWORD Flags); + + typedef WINBOOL (WINAPI *PDBGHELP_CREATE_USER_DUMP_CALLBACK)(DWORD DataType,PVOID *Data,LPDWORD DataLength,PVOID UserData); + + WINBOOL WINAPI DbgHelpCreateUserDump(LPCSTR FileName,PDBGHELP_CREATE_USER_DUMP_CALLBACK Callback,PVOID UserData); + WINBOOL WINAPI DbgHelpCreateUserDumpW(LPCWSTR FileName,PDBGHELP_CREATE_USER_DUMP_CALLBACK Callback,PVOID UserData); + WINBOOL IMAGEAPI SymGetSymFromAddr64(HANDLE hProcess,DWORD64 qwAddr,PDWORD64 pdwDisplacement,PIMAGEHLP_SYMBOL64 Symbol); + +#ifdef _IMAGEHLP64 +#define SymGetSymFromAddr SymGetSymFromAddr64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetSymFromAddr(HANDLE hProcess,DWORD dwAddr,PDWORD pdwDisplacement,PIMAGEHLP_SYMBOL Symbol); +#endif + + WINBOOL IMAGEAPI SymGetSymFromName64(HANDLE hProcess,PCSTR Name,PIMAGEHLP_SYMBOL64 Symbol); + +#ifdef _IMAGEHLP64 +#define SymGetSymFromName SymGetSymFromName64 +#elif !defined(EBACKTRACE_MINGW32) + WINBOOL IMAGEAPI SymGetSymFromName(HANDLE hProcess,PCSTR Name,PIMAGEHLP_SYMBOL Symbol); +#endif + + DBHLP_DEPRECIATED WINBOOL IMAGEAPI FindFileInPath(HANDLE hprocess,PCSTR SearchPath,PCSTR FileName,PVOID id,DWORD two,DWORD three,DWORD flags,PSTR FilePath); + DBHLP_DEPRECIATED WINBOOL IMAGEAPI FindFileInSearchPath(HANDLE hprocess,PCSTR SearchPath,PCSTR FileName,DWORD one,DWORD two,DWORD three,PSTR FilePath); + DBHLP_DEPRECIATED WINBOOL IMAGEAPI SymEnumSym(HANDLE hProcess,ULONG64 BaseOfDll,PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,PVOID UserContext); + +#ifdef __cplusplus +} +#endif + +#ifndef EBACKTRACE_MINGW32 +#define SYMF_OMAP_GENERATED 0x00000001 +#define SYMF_OMAP_MODIFIED 0x00000002 +#define SYMF_REGISTER 0x00000008 +#define SYMF_REGREL 0x00000010 +#define SYMF_FRAMEREL 0x00000020 +#define SYMF_PARAMETER 0x00000040 +#define SYMF_LOCAL 0x00000080 +#define SYMF_CONSTANT 0x00000100 +#define SYMF_EXPORT 0x00000200 +#define SYMF_FORWARDER 0x00000400 +#define SYMF_FUNCTION 0x00000800 +#define SYMF_VIRTUAL 0x00001000 +#define SYMF_THUNK 0x00002000 +#define SYMF_TLSREL 0x00004000 +#endif + +#define IMAGEHLP_SYMBOL_INFO_VALUEPRESENT 1 +#define IMAGEHLP_SYMBOL_INFO_REGISTER SYMF_REGISTER +#define IMAGEHLP_SYMBOL_INFO_REGRELATIVE SYMF_REGREL +#define IMAGEHLP_SYMBOL_INFO_FRAMERELATIVE SYMF_FRAMEREL +#define IMAGEHLP_SYMBOL_INFO_PARAMETER SYMF_PARAMETER +#define IMAGEHLP_SYMBOL_INFO_LOCAL SYMF_LOCAL +#define IMAGEHLP_SYMBOL_INFO_CONSTANT SYMF_CONSTANT +#define IMAGEHLP_SYMBOL_FUNCTION SYMF_FUNCTION +#define IMAGEHLP_SYMBOL_VIRTUAL SYMF_VIRTUAL +#define IMAGEHLP_SYMBOL_THUNK SYMF_THUNK +#define IMAGEHLP_SYMBOL_INFO_TLSRELATIVE SYMF_TLSREL + +#include + +#define MINIDUMP_SIGNATURE ('PMDM') +#define MINIDUMP_VERSION (42899) + typedef DWORD RVA; + typedef ULONG64 RVA64; + + typedef struct _MINIDUMP_LOCATION_DESCRIPTOR { + ULONG32 DataSize; + RVA Rva; + } MINIDUMP_LOCATION_DESCRIPTOR; + + typedef struct _MINIDUMP_LOCATION_DESCRIPTOR64 { + ULONG64 DataSize; + RVA64 Rva; + } MINIDUMP_LOCATION_DESCRIPTOR64; + + typedef struct _MINIDUMP_MEMORY_DESCRIPTOR { + ULONG64 StartOfMemoryRange; + MINIDUMP_LOCATION_DESCRIPTOR Memory; + } MINIDUMP_MEMORY_DESCRIPTOR,*PMINIDUMP_MEMORY_DESCRIPTOR; + + typedef struct _MINIDUMP_MEMORY_DESCRIPTOR64 { + ULONG64 StartOfMemoryRange; + ULONG64 DataSize; + } MINIDUMP_MEMORY_DESCRIPTOR64,*PMINIDUMP_MEMORY_DESCRIPTOR64; + + typedef struct _MINIDUMP_HEADER { + ULONG32 Signature; + ULONG32 Version; + ULONG32 NumberOfStreams; + RVA StreamDirectoryRva; + ULONG32 CheckSum; + __C89_NAMELESS union { + ULONG32 Reserved; + ULONG32 TimeDateStamp; + }; + ULONG64 Flags; + } MINIDUMP_HEADER,*PMINIDUMP_HEADER; + + typedef struct _MINIDUMP_DIRECTORY { + ULONG32 StreamType; + MINIDUMP_LOCATION_DESCRIPTOR Location; + } MINIDUMP_DIRECTORY,*PMINIDUMP_DIRECTORY; + + typedef struct _MINIDUMP_STRING { + ULONG32 Length; + WCHAR Buffer[0]; + } MINIDUMP_STRING,*PMINIDUMP_STRING; + + typedef enum _MINIDUMP_STREAM_TYPE { + UnusedStream = 0, + ReservedStream0 = 1, + ReservedStream1 = 2, + ThreadListStream = 3, + ModuleListStream = 4, + MemoryListStream = 5, + ExceptionStream = 6, + SystemInfoStream = 7, + ThreadExListStream = 8, + Memory64ListStream = 9, + CommentStreamA = 10, + CommentStreamW = 11, + HandleDataStream = 12, + FunctionTableStream = 13, + UnloadedModuleListStream = 14, + MiscInfoStream = 15, + LastReservedStream = 0xffff + } MINIDUMP_STREAM_TYPE; + + typedef union _CPU_INFORMATION { + struct { + ULONG32 VendorId[3]; + ULONG32 VersionInformation; + ULONG32 FeatureInformation; + ULONG32 AMDExtendedCpuFeatures; + } X86CpuInfo; + struct { + ULONG64 ProcessorFeatures[2]; + } OtherCpuInfo; + } CPU_INFORMATION,*PCPU_INFORMATION; + + typedef struct _MINIDUMP_SYSTEM_INFO { + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + __C89_NAMELESS union { + USHORT Reserved0; + __C89_NAMELESS struct { + UCHAR NumberOfProcessors; + UCHAR ProductType; + }; + }; + ULONG32 MajorVersion; + ULONG32 MinorVersion; + ULONG32 BuildNumber; + ULONG32 PlatformId; + RVA CSDVersionRva; + __C89_NAMELESS union { + ULONG32 Reserved1; + __C89_NAMELESS struct { + USHORT SuiteMask; + USHORT Reserved2; + }; + }; + CPU_INFORMATION Cpu; + } MINIDUMP_SYSTEM_INFO,*PMINIDUMP_SYSTEM_INFO; + + C_ASSERT(sizeof(((PPROCESS_INFORMATION)0)->dwThreadId)==4); + + typedef struct _MINIDUMP_THREAD { + ULONG32 ThreadId; + ULONG32 SuspendCount; + ULONG32 PriorityClass; + ULONG32 Priority; + ULONG64 Teb; + MINIDUMP_MEMORY_DESCRIPTOR Stack; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; + } MINIDUMP_THREAD,*PMINIDUMP_THREAD; + + typedef struct _MINIDUMP_THREAD_LIST { + ULONG32 NumberOfThreads; + MINIDUMP_THREAD Threads[0]; + } MINIDUMP_THREAD_LIST,*PMINIDUMP_THREAD_LIST; + + typedef struct _MINIDUMP_THREAD_EX { + ULONG32 ThreadId; + ULONG32 SuspendCount; + ULONG32 PriorityClass; + ULONG32 Priority; + ULONG64 Teb; + MINIDUMP_MEMORY_DESCRIPTOR Stack; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; + MINIDUMP_MEMORY_DESCRIPTOR BackingStore; + } MINIDUMP_THREAD_EX,*PMINIDUMP_THREAD_EX; + + typedef struct _MINIDUMP_THREAD_EX_LIST { + ULONG32 NumberOfThreads; + MINIDUMP_THREAD_EX Threads[0]; + } MINIDUMP_THREAD_EX_LIST,*PMINIDUMP_THREAD_EX_LIST; + + typedef struct _MINIDUMP_EXCEPTION { + ULONG32 ExceptionCode; + ULONG32 ExceptionFlags; + ULONG64 ExceptionRecord; + ULONG64 ExceptionAddress; + ULONG32 NumberParameters; + ULONG32 __unusedAlignment; + ULONG64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } MINIDUMP_EXCEPTION,*PMINIDUMP_EXCEPTION; + + typedef struct MINIDUMP_EXCEPTION_STREAM { + ULONG32 ThreadId; + ULONG32 __alignment; + MINIDUMP_EXCEPTION ExceptionRecord; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; + } MINIDUMP_EXCEPTION_STREAM,*PMINIDUMP_EXCEPTION_STREAM; + + typedef struct _MINIDUMP_MODULE { + ULONG64 BaseOfImage; + ULONG32 SizeOfImage; + ULONG32 CheckSum; + ULONG32 TimeDateStamp; + RVA ModuleNameRva; + VS_FIXEDFILEINFO VersionInfo; + MINIDUMP_LOCATION_DESCRIPTOR CvRecord; + MINIDUMP_LOCATION_DESCRIPTOR MiscRecord; + ULONG64 Reserved0; + ULONG64 Reserved1; + } MINIDUMP_MODULE,*PMINIDUMP_MODULE; + + typedef struct _MINIDUMP_MODULE_LIST { + ULONG32 NumberOfModules; + MINIDUMP_MODULE Modules[0]; + } MINIDUMP_MODULE_LIST,*PMINIDUMP_MODULE_LIST; + + typedef struct _MINIDUMP_MEMORY_LIST { + ULONG32 NumberOfMemoryRanges; + MINIDUMP_MEMORY_DESCRIPTOR MemoryRanges[0]; + } MINIDUMP_MEMORY_LIST,*PMINIDUMP_MEMORY_LIST; + + typedef struct _MINIDUMP_MEMORY64_LIST { + ULONG64 NumberOfMemoryRanges; + RVA64 BaseRva; + MINIDUMP_MEMORY_DESCRIPTOR64 MemoryRanges[0]; + } MINIDUMP_MEMORY64_LIST,*PMINIDUMP_MEMORY64_LIST; + + typedef struct _MINIDUMP_EXCEPTION_INFORMATION { + DWORD ThreadId; + PEXCEPTION_POINTERS ExceptionPointers; + WINBOOL ClientPointers; + } MINIDUMP_EXCEPTION_INFORMATION,*PMINIDUMP_EXCEPTION_INFORMATION; + + typedef struct _MINIDUMP_EXCEPTION_INFORMATION64 { + DWORD ThreadId; + ULONG64 ExceptionRecord; + ULONG64 ContextRecord; + WINBOOL ClientPointers; + } MINIDUMP_EXCEPTION_INFORMATION64,*PMINIDUMP_EXCEPTION_INFORMATION64; + + typedef struct _MINIDUMP_HANDLE_DESCRIPTOR { + ULONG64 Handle; + RVA TypeNameRva; + RVA ObjectNameRva; + ULONG32 Attributes; + ULONG32 GrantedAccess; + ULONG32 HandleCount; + ULONG32 PointerCount; + } MINIDUMP_HANDLE_DESCRIPTOR,*PMINIDUMP_HANDLE_DESCRIPTOR; + + typedef struct _MINIDUMP_HANDLE_DATA_STREAM { + ULONG32 SizeOfHeader; + ULONG32 SizeOfDescriptor; + ULONG32 NumberOfDescriptors; + ULONG32 Reserved; + } MINIDUMP_HANDLE_DATA_STREAM,*PMINIDUMP_HANDLE_DATA_STREAM; + + typedef struct _MINIDUMP_FUNCTION_TABLE_DESCRIPTOR { + ULONG64 MinimumAddress; + ULONG64 MaximumAddress; + ULONG64 BaseAddress; + ULONG32 EntryCount; + ULONG32 SizeOfAlignPad; + } MINIDUMP_FUNCTION_TABLE_DESCRIPTOR,*PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR; + + typedef struct _MINIDUMP_FUNCTION_TABLE_STREAM { + ULONG32 SizeOfHeader; + ULONG32 SizeOfDescriptor; + ULONG32 SizeOfNativeDescriptor; + ULONG32 SizeOfFunctionEntry; + ULONG32 NumberOfDescriptors; + ULONG32 SizeOfAlignPad; + } MINIDUMP_FUNCTION_TABLE_STREAM,*PMINIDUMP_FUNCTION_TABLE_STREAM; + + typedef struct _MINIDUMP_UNLOADED_MODULE { + ULONG64 BaseOfImage; + ULONG32 SizeOfImage; + ULONG32 CheckSum; + ULONG32 TimeDateStamp; + RVA ModuleNameRva; + } MINIDUMP_UNLOADED_MODULE,*PMINIDUMP_UNLOADED_MODULE; + + typedef struct _MINIDUMP_UNLOADED_MODULE_LIST { + ULONG32 SizeOfHeader; + ULONG32 SizeOfEntry; + ULONG32 NumberOfEntries; + } MINIDUMP_UNLOADED_MODULE_LIST,*PMINIDUMP_UNLOADED_MODULE_LIST; + +#define MINIDUMP_MISC1_PROCESS_ID 0x00000001 +#define MINIDUMP_MISC1_PROCESS_TIMES 0x00000002 +#define MINIDUMP_MISC1_PROCESSOR_POWER_INFO 0x00000004 + + typedef struct _MINIDUMP_MISC_INFO { + ULONG32 SizeOfInfo; + ULONG32 Flags1; + ULONG32 ProcessId; + ULONG32 ProcessCreateTime; + ULONG32 ProcessUserTime; + ULONG32 ProcessKernelTime; + } MINIDUMP_MISC_INFO,*PMINIDUMP_MISC_INFO; + + typedef struct _MINIDUMP_USER_RECORD { + ULONG32 Type; + MINIDUMP_LOCATION_DESCRIPTOR Memory; + } MINIDUMP_USER_RECORD,*PMINIDUMP_USER_RECORD; + + typedef struct _MINIDUMP_USER_STREAM { + ULONG32 Type; + ULONG BufferSize; + PVOID Buffer; + } MINIDUMP_USER_STREAM,*PMINIDUMP_USER_STREAM; + + typedef struct _MINIDUMP_USER_STREAM_INFORMATION { + ULONG UserStreamCount; + PMINIDUMP_USER_STREAM UserStreamArray; + } MINIDUMP_USER_STREAM_INFORMATION,*PMINIDUMP_USER_STREAM_INFORMATION; + + typedef enum _MINIDUMP_CALLBACK_TYPE { + ModuleCallback, + ThreadCallback, + ThreadExCallback, + IncludeThreadCallback, + IncludeModuleCallback, + MemoryCallback, + CancelCallback, + WriteKernelMinidumpCallback, + KernelMinidumpStatusCallback, + RemoveMemoryCallback, + IncludeVmRegionCallback, + IoStartCallback, + IoWriteAllCallback, + IoFinishCallback, + ReadMemoryFailureCallback, + SecondaryFlagsCallback + } MINIDUMP_CALLBACK_TYPE; + + typedef struct _MINIDUMP_THREAD_CALLBACK { + ULONG ThreadId; + HANDLE ThreadHandle; + CONTEXT Context; + ULONG SizeOfContext; + ULONG64 StackBase; + ULONG64 StackEnd; + } MINIDUMP_THREAD_CALLBACK,*PMINIDUMP_THREAD_CALLBACK; + + typedef struct _MINIDUMP_THREAD_EX_CALLBACK { + ULONG ThreadId; + HANDLE ThreadHandle; + CONTEXT Context; + ULONG SizeOfContext; + ULONG64 StackBase; + ULONG64 StackEnd; + ULONG64 BackingStoreBase; + ULONG64 BackingStoreEnd; + } MINIDUMP_THREAD_EX_CALLBACK,*PMINIDUMP_THREAD_EX_CALLBACK; + + typedef struct _MINIDUMP_INCLUDE_THREAD_CALLBACK { + ULONG ThreadId; + } MINIDUMP_INCLUDE_THREAD_CALLBACK,*PMINIDUMP_INCLUDE_THREAD_CALLBACK; + + typedef enum _THREAD_WRITE_FLAGS { + ThreadWriteThread = 0x0001, + ThreadWriteStack = 0x0002, + ThreadWriteContext = 0x0004, + ThreadWriteBackingStore = 0x0008, + ThreadWriteInstructionWindow = 0x0010, + ThreadWriteThreadData = 0x0020, + ThreadWriteThreadInfo = 0x0040 + } THREAD_WRITE_FLAGS; + + typedef struct _MINIDUMP_MODULE_CALLBACK { + PWCHAR FullPath; + ULONG64 BaseOfImage; + ULONG SizeOfImage; + ULONG CheckSum; + ULONG TimeDateStamp; + VS_FIXEDFILEINFO VersionInfo; + PVOID CvRecord; + ULONG SizeOfCvRecord; + PVOID MiscRecord; + ULONG SizeOfMiscRecord; + } MINIDUMP_MODULE_CALLBACK,*PMINIDUMP_MODULE_CALLBACK; + + typedef struct _MINIDUMP_INCLUDE_MODULE_CALLBACK { + ULONG64 BaseOfImage; + } MINIDUMP_INCLUDE_MODULE_CALLBACK,*PMINIDUMP_INCLUDE_MODULE_CALLBACK; + + typedef enum _MODULE_WRITE_FLAGS { + ModuleWriteModule = 0x0001, + ModuleWriteDataSeg = 0x0002, + ModuleWriteMiscRecord = 0x0004, + ModuleWriteCvRecord = 0x0008, + ModuleReferencedByMemory = 0x0010, + ModuleWriteTlsData = 0x0020, + ModuleWriteCodeSegs = 0x0040 + } MODULE_WRITE_FLAGS; + + typedef enum _MINIDUMP_SECONDARY_FLAGS { + MiniSecondaryWithoutPowerInfo = 0x00000001 + } MINIDUMP_SECONDARY_FLAGS; + + typedef struct _MINIDUMP_CALLBACK_INPUT { + ULONG ProcessId; + HANDLE ProcessHandle; + ULONG CallbackType; + __C89_NAMELESS union { + MINIDUMP_THREAD_CALLBACK Thread; + MINIDUMP_THREAD_EX_CALLBACK ThreadEx; + MINIDUMP_MODULE_CALLBACK Module; + MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; + MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; + }; + } MINIDUMP_CALLBACK_INPUT,*PMINIDUMP_CALLBACK_INPUT; + +typedef struct _MINIDUMP_MEMORY_INFO { + ULONG64 BaseAddress; + ULONG64 AllocationBase; + ULONG32 AllocationProtect; + ULONG32 __alignment1; + ULONG64 RegionSize; + ULONG32 State; + ULONG32 Protect; + ULONG32 Type; + ULONG32 __alignment2; +} MINIDUMP_MEMORY_INFO, *PMINIDUMP_MEMORY_INFO; + +typedef struct _MINIDUMP_MISC_INFO_2 { + ULONG32 SizeOfInfo; + ULONG32 Flags1; + ULONG32 ProcessId; + ULONG32 ProcessCreateTime; + ULONG32 ProcessUserTime; + ULONG32 ProcessKernelTime; + ULONG32 ProcessorMaxMhz; + ULONG32 ProcessorCurrentMhz; + ULONG32 ProcessorMhzLimit; + ULONG32 ProcessorMaxIdleState; + ULONG32 ProcessorCurrentIdleState; +} MINIDUMP_MISC_INFO_2, *PMINIDUMP_MISC_INFO_2; + +typedef struct _MINIDUMP_MEMORY_INFO_LIST { + ULONG SizeOfHeader; + ULONG SizeOfEntry; + ULONG64 NumberOfEntries; +} MINIDUMP_MEMORY_INFO_LIST, *PMINIDUMP_MEMORY_INFO_LIST; + + typedef struct _MINIDUMP_CALLBACK_OUTPUT { + __C89_NAMELESS union { + ULONG ModuleWriteFlags; + ULONG ThreadWriteFlags; + ULONG SecondaryFlags; + __C89_NAMELESS struct { + ULONG64 MemoryBase; + ULONG MemorySize; + }; + __C89_NAMELESS struct { + WINBOOL CheckCancel; + WINBOOL Cancel; + }; + HANDLE Handle; + }; + __C89_NAMELESS struct { + MINIDUMP_MEMORY_INFO VmRegion; + WINBOOL Continue; + }; + HRESULT Status; + } MINIDUMP_CALLBACK_OUTPUT, *PMINIDUMP_CALLBACK_OUTPUT; + + typedef enum _MINIDUMP_TYPE { + MiniDumpNormal = 0x00000000, + MiniDumpWithDataSegs = 0x00000001, + MiniDumpWithFullMemory = 0x00000002, + MiniDumpWithHandleData = 0x00000004, + MiniDumpFilterMemory = 0x00000008, + MiniDumpScanMemory = 0x00000010, + MiniDumpWithUnloadedModules = 0x00000020, + MiniDumpWithIndirectlyReferencedMemory = 0x00000040, + MiniDumpFilterModulePaths = 0x00000080, + MiniDumpWithProcessThreadData = 0x00000100, + MiniDumpWithPrivateReadWriteMemory = 0x00000200, + MiniDumpWithoutOptionalData = 0x00000400, + MiniDumpWithFullMemoryInfo = 0x00000800, + MiniDumpWithThreadInfo = 0x00001000, + MiniDumpWithCodeSegs = 0x00002000, + MiniDumpWithoutAuxiliaryState = 0x00004000, + MiniDumpWithFullAuxiliaryState = 0x00008000, + MiniDumpWithPrivateWriteCopyMemory = 0x00010000, + MiniDumpIgnoreInaccessibleMemory = 0x00020000, + MiniDumpWithTokenInformation = 0x00040000 + } MINIDUMP_TYPE; + +#define MINIDUMP_THREAD_INFO_ERROR_THREAD 0x00000001 +#define MINIDUMP_THREAD_INFO_WRITING_THREAD 0x00000002 +#define MINIDUMP_THREAD_INFO_EXITED_THREAD 0x00000004 +#define MINIDUMP_THREAD_INFO_INVALID_INFO 0x00000008 +#define MINIDUMP_THREAD_INFO_INVALID_CONTEXT 0x00000010 +#define MINIDUMP_THREAD_INFO_INVALID_TEB 0x00000020 + +typedef struct _MINIDUMP_THREAD_INFO { + ULONG32 ThreadId; + ULONG32 DumpFlags; + ULONG32 DumpError; + ULONG32 ExitStatus; + ULONG64 CreateTime; + ULONG64 ExitTime; + ULONG64 KernelTime; + ULONG64 UserTime; + ULONG64 StartAddress; + ULONG64 Affinity; +} MINIDUMP_THREAD_INFO, *PMINIDUMP_THREAD_INFO; + +typedef struct _MINIDUMP_THREAD_INFO_LIST { + ULONG SizeOfHeader; + ULONG SizeOfEntry; + ULONG NumberOfEntries; +} MINIDUMP_THREAD_INFO_LIST, *PMINIDUMP_THREAD_INFO_LIST; + +#ifdef __cplusplus +extern "C" { +#endif + + typedef WINBOOL (WINAPI *MINIDUMP_CALLBACK_ROUTINE)(PVOID CallbackParam,CONST PMINIDUMP_CALLBACK_INPUT CallbackInput,PMINIDUMP_CALLBACK_OUTPUT CallbackOutput); + + typedef struct _MINIDUMP_CALLBACK_INFORMATION { + MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; + PVOID CallbackParam; + } MINIDUMP_CALLBACK_INFORMATION,*PMINIDUMP_CALLBACK_INFORMATION; + +#define RVA_TO_ADDR(Mapping,Rva) ((PVOID)(((ULONG_PTR) (Mapping)) + (Rva))) + + WINBOOL WINAPI MiniDumpWriteDump(HANDLE hProcess,DWORD ProcessId,HANDLE hFile,MINIDUMP_TYPE DumpType,CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); + WINBOOL WINAPI MiniDumpReadDumpStream(PVOID BaseOfDump,ULONG StreamNumber,PMINIDUMP_DIRECTORY *Dir,PVOID *StreamPointer,ULONG *StreamSize); + +WINBOOL WINAPI EnumerateLoadedModulesEx( + HANDLE hProcess, + PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback, + PVOID UserContext +); + +WINBOOL WINAPI EnumerateLoadedModulesExW( + HANDLE hProcess, + PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback, + PVOID UserContext +); + +WINBOOL WINAPI SymAddSourceStream( + HANDLE hProcess, + ULONG64 Base, + PCSTR StreamFile, + PBYTE Buffer, + size_t Size +); + +WINBOOL WINAPI SymAddSourceStreamW( + HANDLE hProcess, + ULONG64 Base, + PCWSTR StreamFile, + PBYTE Buffer, + size_t Size +); + +WINBOOL WINAPI SymEnumSourceLines( + HANDLE hProcess, + ULONG64 Base, + PCSTR Obj, + PCSTR File, + DWORD Line, + DWORD Flags, + PSYM_ENUMLINES_CALLBACK EnumLinesCallback, + PVOID UserContext +); + +WINBOOL WINAPI SymEnumSourceLinesW( + HANDLE hProcess, + ULONG64 Base, + PCWSTR Obj, + PCWSTR File, + DWORD Line, + DWORD Flags, + PSYM_ENUMLINES_CALLBACKW EnumLinesCallback, + PVOID UserContext +); + +WINBOOL WINAPI SymEnumTypesByName( + HANDLE hProcess, + ULONG64 BaseOfDll, + PCSTR mask, + PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + PVOID UserContext +); + +WINBOOL WINAPI SymEnumTypesByNameW( + HANDLE hProcess, + ULONG64 BaseOfDll, + PCSTR mask, + PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + PVOID UserContext +); + +HANDLE WINAPI SymFindDebugInfoFile( + HANDLE hProcess, + PCSTR FileName, + PSTR DebugFilePath, + PFIND_DEBUG_FILE_CALLBACK Callback, + PVOID CallerData +); + +HANDLE WINAPI SymFindDebugInfoFileW( + HANDLE hProcess, + PCWSTR FileName, + PWSTR DebugFilePath, + PFIND_DEBUG_FILE_CALLBACKW Callback, + PVOID CallerData +); + +HANDLE WINAPI SymFindExecutableImage( + HANDLE hProcess, + PCSTR FileName, + PSTR ImageFilePath, + PFIND_EXE_FILE_CALLBACK Callback, + PVOID CallerData +); + +HANDLE WINAPI SymFindExecutableImageW( + HANDLE hProcess, + PCWSTR FileName, + PWSTR ImageFilePath, + PFIND_EXE_FILE_CALLBACKW Callback, + PVOID CallerData +); + +WINBOOL WINAPI SymFromIndex( + HANDLE hProcess, + ULONG64 BaseOfDll, + DWORD Index, + PSYMBOL_INFO Symbol +); + +WINBOOL WINAPI SymFromIndexW( + HANDLE hProcess, + ULONG64 BaseOfDll, + DWORD Index, + PSYMBOL_INFOW Symbol +); + +WINBOOL WINAPI SymGetScope( + HANDLE hProcess, + ULONG64 BaseOfDll, + DWORD Index, + PSYMBOL_INFO Symbol +); + +WINBOOL WINAPI SymGetScopeW( + HANDLE hProcess, + ULONG64 BaseOfDll, + DWORD Index, + PSYMBOL_INFOW Symbol +); + +WINBOOL WINAPI SymGetSourceFileFromToken( + HANDLE hProcess, + PVOID Token, + PCSTR Params, + PSTR FilePath, + DWORD Size +); + +WINBOOL WINAPI SymGetSourceFileFromTokenW( + HANDLE hProcess, + PVOID Token, + PCWSTR Params, + PWSTR FilePath, + DWORD Size +); + +WINBOOL WINAPI SymGetSourceFileToken( + HANDLE hProcess, + ULONG64 Base, + PCSTR FileSpec, + PVOID *Token, + DWORD *Size +); + +WINBOOL WINAPI SymGetSourceFileTokenW( + HANDLE hProcess, + ULONG64 Base, + PCWSTR FileSpec, + PVOID *Token, + DWORD *Size +); + +WINBOOL WINAPI SymGetSourceFile( + HANDLE hProcess, + ULONG64 Base, + PCSTR Params, + PCSTR FileSpec, + PSTR FilePath, + DWORD Size +); + +WINBOOL WINAPI SymGetSourceFileW( + HANDLE hProcess, + ULONG64 Base, + PCWSTR Params, + PCWSTR FileSpec, + PWSTR FilePath, + DWORD Size +); + +WINBOOL WINAPI SymGetSourceVarFromToken( + HANDLE hProcess, + PVOID Token, + PCSTR Params, + PCSTR VarName, + PSTR Value, + DWORD Size +); + +WINBOOL WINAPI SymGetSourceVarFromTokenW( + HANDLE hProcess, + PVOID Token, + PCWSTR Params, + PCWSTR VarName, + PWSTR Value, + DWORD Size +); + +WINBOOL WINAPI SymGetSymbolFile( + HANDLE hProcess, + PCSTR SymPath, + PCSTR ImageFile, + DWORD Type, + PSTR SymbolFile, + size_t cSymbolFile, + PSTR DbgFile, + size_t cDbgFile +); + +WINBOOL WINAPI SymGetSymbolFileW( + HANDLE hProcess, + PCWSTR SymPath, + PCWSTR ImageFile, + DWORD Type, + PWSTR SymbolFile, + size_t cSymbolFile, + PWSTR DbgFile, + size_t cDbgFile +); + +WINBOOL WINAPI SymNext( + HANDLE hProcess, + PSYMBOL_INFO Symbol +); + +WINBOOL WINAPI SymNextW( + HANDLE hProcess, + PSYMBOL_INFOW Symbol +); + +WINBOOL WINAPI SymPrev( + HANDLE hProcess, + PSYMBOL_INFO Symbol +); + +WINBOOL WINAPI SymPrevW( + HANDLE hProcess, + PSYMBOL_INFOW Symbol +); + +WINBOOL WINAPI SymRefreshModuleList( + HANDLE hProcess +); + +#define SYMSEARCH_MASKOBJS 0x01 +#define SYMSEARCH_RECURSE 0x02 +#define SYMSEARCH_GLOBALSONLY 0x04 +#define SYMSEARCH_ALLITEMS 0x08 + +WINBOOL WINAPI SymSearch( + HANDLE hProcess, + ULONG64 BaseOfDll, + DWORD Index, + DWORD SymTag, + PCSTR Mask, + DWORD64 Address, + PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + PVOID UserContext, + DWORD Options +); + +WINBOOL WINAPI SymSearchW( + HANDLE hProcess, + ULONG64 BaseOfDll, + DWORD Index, + DWORD SymTag, + PCWSTR Mask, + DWORD64 Address, + PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + PVOID UserContext, + DWORD Options +); + +WINBOOL WINAPI SymSrvGetFileIndexString( + HANDLE hProcess, + PCSTR SrvPath, + PCSTR File, + PSTR Index, + size_t Size, + DWORD Flags +); + +WINBOOL WINAPI SymSrvGetFileIndexStringW( + HANDLE hProcess, + PCWSTR SrvPath, + PCWSTR File, + PWSTR Index, + size_t Size, + DWORD Flags +); + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define SymSrvGetFileIndexString SymSrvGetFileIndexStringW +#endif + +WINBOOL WINAPI SymSrvGetFileIndexInfo( + PCSTR File, + PSYMSRV_INDEX_INFO Info, + DWORD Flags +); + +WINBOOL WINAPI SymSrvGetFileIndexInfoW( + PCWSTR File, + PSYMSRV_INDEX_INFOW Info, + DWORD Flags +); + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define SymSrvGetFileIndexInfo SymSrvGetFileIndexInfoW +#endif + +WINBOOL WINAPI SymSrvGetFileIndexes( + PCTSTR File, + GUID *Id, + DWORD *Val1, + DWORD *Val2, + DWORD Flags +); + +WINBOOL WINAPI SymSrvGetFileIndexesW( + PCWSTR File, + GUID *Id, + DWORD *Val1, + DWORD *Val2, + DWORD Flags +); + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define SymSrvGetFileIndexes SymSrvGetFileIndexesW +#endif + +PCSTR WINAPI SymSrvGetSupplement( + HANDLE hProcess, + PCSTR SymPath, + PCSTR Node, + PCSTR File +); + +PCWSTR WINAPI SymSrvGetSupplementW( + HANDLE hProcess, + PCWSTR SymPath, + PCWSTR Node, + PCWSTR File +); + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define SymSrvGetSupplement SymSrvGetSupplementW +#endif + +WINBOOL WINAPI SymSrvIsStore( + HANDLE hProcess, + PCSTR path +); + +WINBOOL WINAPI SymSrvIsStoreW( + HANDLE hProcess, + PCWSTR path +); + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define SymSrvIsStore SymSrvIsStoreW +#endif + +PCSTR WINAPI SymSrvStoreFile( + HANDLE hProcess, + PCSTR SrvPath, + PCSTR File, + DWORD Flags +); + +PCWSTR WINAPI SymSrvStoreFileW( + HANDLE hProcess, + PCWSTR SrvPath, + PCWSTR File, + DWORD Flags +); + +#define SYMSTOREOPT_COMPRESS 0x01 +#define SYMSTOREOPT_OVERWRITE 0x02 +#define SYMSTOREOPT_RETURNINDEX 0x04 +#define SYMSTOREOPT_POINTER 0x08 +#define SYMSTOREOPT_PASS_IF_EXISTS 0x40 + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define SymSrvStoreFile SymSrvStoreFileW +#endif + +PCSTR WINAPI SymSrvStoreSupplement( + HANDLE hProcess, + const PCTSTR SymPath, + PCSTR Node, + PCSTR File, + DWORD Flags +); + +PCWSTR WINAPI SymSrvStoreSupplementW( + HANDLE hProcess, + const PCWSTR SymPath, + PCWSTR Node, + PCWSTR File, + DWORD Flags +); + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define SymSrvStoreSupplement SymSrvStoreSupplementW +#endif + +PCSTR WINAPI SymSrvDeltaName( + HANDLE hProcess, + PCSTR SymPath, + PCSTR Type, + PCSTR File1, + PCSTR File2 +); + +PCWSTR WINAPI SymSrvDeltaNameW( + HANDLE hProcess, + PCWSTR SymPath, + PCWSTR Type, + PCWSTR File1, + PCWSTR File2 +); + +#ifdef DBGHELP_TRANSLATE_TCHAR +#define SymSrvDeltaName SymSrvDeltaNameW +#endif + +#include + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bin/windows/vpx/src/backtrace.c b/bin/windows/vpx/src/backtrace.c new file mode 100644 index 00000000000..4bbe88bbe9d --- /dev/null +++ b/bin/windows/vpx/src/backtrace.c @@ -0,0 +1,702 @@ +/* + Copyright (c) 2010 , + Cloud Wu . All rights reserved. + + http://www.codingnow.com + + Use, modification and distribution are subject to the "New BSD License" + as listed at . + + filename: backtrace.c + + build command: gcc -O2 -shared -Wall -o backtrace.dll backtrace.c -lbfd -liberty -limagehlp + + how to use: Call LoadLibraryA("backtrace.dll"); at beginning of your program . + + */ + +/* modified from original for EDuke32 */ + +// warnings cleaned up, ported to 64-bit, and heavily extended by Hendricks266 + +#include +#include +#include + +// Tenuous: MinGW provides _IMAGEHLP_H while MinGW-w64 defines _IMAGEHLP_. +#ifdef _IMAGEHLP_H +# define EBACKTRACE_MINGW32 +#endif +#ifdef _IMAGEHLP_ +# define EBACKTRACE_MINGW_W64 +#endif +#if defined(EBACKTRACE_MINGW32) && !defined(EBACKTRACE_MINGW_W64) +# include "_dbg_common.h" +#endif + +#ifndef PACKAGE +# define PACKAGE EBACKTRACE1 +#endif +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION 1 +#endif + +#if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(_WIN64) +# define EBACKTRACE64 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#ifndef DBG_PRINTEXCEPTION_C +# define DBG_PRINTEXCEPTION_C (0x40010006) +#endif +#ifndef MS_VC_EXCEPTION +# define MS_VC_EXCEPTION 1080890248 +#endif + +#if defined __GNUC__ || defined __clang__ +# define ATTRIBUTE(attrlist) __attribute__(attrlist) +#else +# define ATTRIBUTE(attrlist) +#endif + +#define BUFFER_MAX (16*1024) + +struct bfd_ctx { + bfd * handle; + asymbol ** symbol; +}; + +struct bfd_set { + char * name; + struct bfd_ctx * bc; + struct bfd_set *next; +}; + +struct find_info { + asymbol **symbol; + bfd_vma counter; + const char *file; + const char *func; + unsigned line; +}; + +struct output_buffer { + char * buf; + size_t sz; + size_t ptr; +}; + +static void +output_init(struct output_buffer *ob, char * buf, size_t sz) +{ + ob->buf = buf; + ob->sz = sz; + ob->ptr = 0; + ob->buf[0] = '\0'; +} + +static void +output_print(struct output_buffer *ob, const char * format, ...) +{ + va_list ap; + + if (ob->sz == ob->ptr) + return; + ob->buf[ob->ptr] = '\0'; + va_start(ap,format); + vsnprintf(ob->buf + ob->ptr , ob->sz - ob->ptr , format, ap); + va_end(ap); + + ob->ptr = strlen(ob->buf + ob->ptr) + ob->ptr; +} + +static void +lookup_section(bfd *abfd, asection *sec, void *opaque_data) +{ + struct find_info *data = opaque_data; + bfd_vma vma; + + if (data->func) + return; + + if (!(bfd_get_section_flags(abfd, sec) & SEC_ALLOC)) + return; + + vma = bfd_get_section_vma(abfd, sec); + if (data->counter < vma || vma + bfd_get_section_size(sec) <= data->counter) + return; + + bfd_find_nearest_line(abfd, sec, data->symbol, data->counter - vma, &(data->file), &(data->func), &(data->line)); +} + +static void +find(struct bfd_ctx * b, DWORD offset, const char **file, const char **func, unsigned *line) +{ + struct find_info data; + data.func = NULL; + data.symbol = b->symbol; + data.counter = offset; + data.file = NULL; + data.func = NULL; + data.line = 0; + + bfd_map_over_sections(b->handle, &lookup_section, &data); + if (file) { + *file = data.file; + } + if (func) { + *func = data.func; + } + if (line) { + *line = data.line; + } +} + +static int +init_bfd_ctx(struct bfd_ctx *bc, const char * procname, struct output_buffer *ob) +{ + int r1, r2, r3; + bfd *b; + void *symbol_table; + unsigned dummy = 0; + bc->handle = NULL; + bc->symbol = NULL; + + b = bfd_openr(procname, 0); + if (!b) { + output_print(ob,"Failed to open bfd from (%s)\n" , procname); + return 1; + } + + r1 = bfd_check_format(b, bfd_object); + r2 = bfd_check_format_matches(b, bfd_object, NULL); + r3 = bfd_get_file_flags(b) & HAS_SYMS; + + if (!(r1 && r2 && r3)) { + bfd_close(b); + if (!(r1 && r2)) + output_print(ob,"Failed to init bfd from (%s): %d %d %d\n", procname, r1, r2, r3); + return 1; + } + + if (bfd_read_minisymbols(b, FALSE, &symbol_table, &dummy) == 0) { + if (bfd_read_minisymbols(b, TRUE, &symbol_table, &dummy) < 0) { + free(symbol_table); + bfd_close(b); + output_print(ob,"Failed to read symbols from (%s)\n", procname); + return 1; + } + } + + bc->handle = b; + bc->symbol = symbol_table; + + return 0; +} + +static void +close_bfd_ctx(struct bfd_ctx *bc) +{ + if (bc) { + if (bc->symbol) { + free(bc->symbol); + } + if (bc->handle) { + bfd_close(bc->handle); + } + } +} + +static struct bfd_ctx * +get_bc(struct output_buffer *ob , struct bfd_set *set , const char *procname) +{ + struct bfd_ctx bc; + while(set->name) { + if (strcmp(set->name , procname) == 0) { + return set->bc; + } + set = set->next; + } + if (init_bfd_ctx(&bc, procname , ob)) { + return NULL; + } + set->next = calloc(1, sizeof(*set)); + set->bc = malloc(sizeof(struct bfd_ctx)); + memcpy(set->bc, &bc, sizeof(bc)); + set->name = strdup(procname); + + return set->bc; +} + +static void +release_set(struct bfd_set *set) +{ + while(set) { + struct bfd_set * temp = set->next; + if (set->name) + free(set->name); + close_bfd_ctx(set->bc); + free(set); + set = temp; + } +} + +static char procname[MAX_PATH]; + +#ifdef EBACKTRACE64 +# define MachineType IMAGE_FILE_MACHINE_AMD64 +# define MAYBE64(x) x ## 64 +#else +# define MachineType IMAGE_FILE_MACHINE_I386 +# define MAYBE64(x) x +#endif + +static void +_backtrace(struct output_buffer *ob, struct bfd_set *set, int depth , LPCONTEXT context) +{ + MAYBE64(STACKFRAME) frame; + HANDLE process, thread; + char symbol_buffer[sizeof(MAYBE64(IMAGEHLP_SYMBOL)) + 255]; + char module_name_raw[MAX_PATH]; + struct bfd_ctx *bc = NULL; + + GetModuleFileNameA(NULL, procname, sizeof procname); + + memset(&frame,0,sizeof(frame)); + +#ifdef EBACKTRACE64 + frame.AddrPC.Offset = context->Rip; + frame.AddrStack.Offset = context->Rsp; + frame.AddrFrame.Offset = context->Rbp; +#else + frame.AddrPC.Offset = context->Eip; + frame.AddrStack.Offset = context->Esp; + frame.AddrFrame.Offset = context->Ebp; +#endif + + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Mode = AddrModeFlat; + + process = GetCurrentProcess(); + thread = GetCurrentThread(); + + while(MAYBE64(StackWalk)(MachineType, + process, + thread, + &frame, + context, + NULL, + MAYBE64(SymFunctionTableAccess), + MAYBE64(SymGetModuleBase), NULL)) { + MAYBE64(IMAGEHLP_SYMBOL) *symbol; + MAYBE64(DWORD) module_base; + const char * module_name = "[unknown module]"; + + const char * file = NULL; + const char * func = NULL; + unsigned line = 0; + + --depth; + if (depth < 0) + break; + + symbol = (MAYBE64(IMAGEHLP_SYMBOL) *)symbol_buffer; + symbol->SizeOfStruct = (sizeof *symbol) + 255; + symbol->MaxNameLength = 254; + + module_base = MAYBE64(SymGetModuleBase)(process, frame.AddrPC.Offset); + + if (module_base && + GetModuleFileNameA((HINSTANCE)(intptr_t)module_base, module_name_raw, MAX_PATH)) { + module_name = module_name_raw; + bc = get_bc(ob, set, module_name); + } + + if (bc) { + find(bc,frame.AddrPC.Offset,&file,&func,&line); + } + + if (file == NULL) { + MAYBE64(DWORD) dummy = 0; + if (MAYBE64(SymGetSymFromAddr)(process, frame.AddrPC.Offset, &dummy, symbol)) { + file = symbol->Name; + } + else { + file = "[unknown file]"; + } + } + + output_print(ob,"0x%p : %s : %s", frame.AddrPC.Offset, module_name, file); + if (func != NULL) + output_print(ob, " (%d) : in function (%s)", line, func); + output_print(ob, "\n"); + } +} + +static LPTSTR FormatErrorMessage(DWORD dwMessageId) +{ + LPTSTR lpBuffer = NULL; + + // adapted from http://stackoverflow.com/a/455533 + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM + |FORMAT_MESSAGE_ALLOCATE_BUFFER + |FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwMessageId, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) + (LPTSTR)&lpBuffer, + 0, + NULL); + + return lpBuffer; // must be LocalFree()'d by caller +} + +static LPTSTR FormatExceptionCodeMessage(DWORD dwMessageId) +{ + LPTSTR lpBuffer = NULL; + + FormatMessage( + FORMAT_MESSAGE_FROM_HMODULE + |FORMAT_MESSAGE_ALLOCATE_BUFFER + |FORMAT_MESSAGE_IGNORE_INSERTS, + GetModuleHandleA("ntdll.dll"), + dwMessageId, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) + (LPTSTR)&lpBuffer, + 0, + NULL); + + return lpBuffer; // must be LocalFree()'d by caller +} + + +// adapted from http://www.catch22.net/tuts/custom-messagebox +static HHOOK hMsgBoxHook; + +LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode < 0) + return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam); + + switch (nCode) + { + case HCBT_ACTIVATE: + { + // Get handle to the message box! + HWND hwnd = (HWND)wParam; + + // Do customization! + SetWindowTextA(GetDlgItem(hwnd, IDYES), "Quit"); + SetWindowTextA(GetDlgItem(hwnd, IDNO), "Continue"); + SetWindowTextA(GetDlgItem(hwnd, IDCANCEL), "Ignore"); + return 0; + } + break; + } + + // Call the next hook, if there is one + return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam); +} + +int ExceptionMessage(TCHAR *szText, TCHAR *szCaption) +{ + int retval; + + // Install a window hook, so we can intercept the message-box + // creation, and customize it + hMsgBoxHook = SetWindowsHookEx( + WH_CBT, + CBTProc, + NULL, + GetCurrentThreadId() // Only install for THIS thread!!! + ); + + // Display a standard message box + retval = MessageBoxA(NULL, szText, szCaption, MB_YESNOCANCEL|MB_ICONERROR|MB_TASKMODAL); + + // remove the window hook + UnhookWindowsHookEx(hMsgBoxHook); + + return retval; +} + +static char crashlogfilename[MAX_PATH] = "crash.log"; +static char propername[MAX_PATH] = "this application"; + +__declspec(dllexport) void SetTechnicalName(const char* input) +{ + snprintf(crashlogfilename, MAX_PATH, "%s.crash.log", input); +} +__declspec(dllexport) void SetProperName(const char* input) +{ + strncpy(propername, input, MAX_PATH); +} + +static char * g_output = NULL; +static PVOID g_prev = NULL; + +static LONG WINAPI +exception_filter(LPEXCEPTION_POINTERS info) +{ + struct output_buffer ob; + int logfd, written, msgboxID; + PEXCEPTION_RECORD exception; + BOOL initialized = FALSE; + char *ExceptionPrinted; + + for (exception = info->ExceptionRecord; exception != NULL; exception = exception->ExceptionRecord) + { +#if 0 + if (exception->ExceptionFlags & EXCEPTION_NONCONTINUABLE) + continuable = FALSE; +#endif + + switch (exception->ExceptionCode) + { + case EXCEPTION_BREAKPOINT: + case EXCEPTION_SINGLE_STEP: + case DBG_CONTROL_C: + case DBG_PRINTEXCEPTION_C: + case MS_VC_EXCEPTION: + break; + default: + { + LPTSTR ExceptionCodeMsg = FormatExceptionCodeMessage(exception->ExceptionCode); + // The message for this exception code is broken. + LPTSTR ExceptionText = exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ? "Access violation." : ExceptionCodeMsg; + + if (!initialized) + { + output_init(&ob, g_output, BUFFER_MAX); + initialized = TRUE; + } + + output_print(&ob, "Caught exception 0x%08X at 0x%p: %s\n", exception->ExceptionCode, exception->ExceptionAddress, ExceptionText); + + LocalFree(ExceptionCodeMsg); + } + break; + } + } + + if (!initialized) + return EXCEPTION_CONTINUE_SEARCH; // EXCEPTION_CONTINUE_EXECUTION + + ExceptionPrinted = (char*)calloc(strlen(g_output) + 37 + 2*MAX_PATH, sizeof(char)); + strcpy(ExceptionPrinted, g_output); + strcat(ExceptionPrinted, "\nPlease send "); + strcat(ExceptionPrinted, crashlogfilename); + strcat(ExceptionPrinted, " to the maintainers of "); + strcat(ExceptionPrinted, propername); + strcat(ExceptionPrinted, "."); + + { + DWORD error = 0; + BOOL SymInitialized = SymInitialize(GetCurrentProcess(), NULL, TRUE); + + if (!SymInitialized) + { + LPTSTR errorText; + + error = GetLastError(); + errorText = FormatErrorMessage(error); + output_print(&ob, "SymInitialize() failed with error %d: %s\n", error, errorText); + LocalFree(errorText); + } + + if (SymInitialized || error == 87) + { + struct bfd_set *set = calloc(1,sizeof(*set)); + bfd_init(); + _backtrace(&ob , set , 128 , info->ContextRecord); + release_set(set); + + SymCleanup(GetCurrentProcess()); + } + } + + logfd = open(crashlogfilename, O_APPEND | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + + if (logfd) { + time_t curtime; + struct tm *curltime; + const char *theasctime; + const char *finistr = "---------------\n"; + + while ((written = write(logfd, g_output, strlen(g_output)))) { + g_output += written; + } + + curtime = time(NULL); + curltime = localtime(&curtime); + theasctime = curltime ? asctime(curltime) : NULL; + + if (theasctime) + write(logfd, theasctime, strlen(theasctime)); + write(logfd, finistr, strlen(finistr)); + close(logfd); + } + + //fputs(g_output, stderr); + + msgboxID = ExceptionMessage(ExceptionPrinted, propername); + + free(ExceptionPrinted); + + switch (msgboxID) + { + case IDYES: + exit(0xBAC); + break; + case IDNO: + break; + case IDCANCEL: + return EXCEPTION_CONTINUE_EXECUTION; + break; + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +static void +backtrace_register(void) +{ + if (g_output == NULL) { + g_output = malloc(BUFFER_MAX); + g_prev = AddVectoredExceptionHandler(1, exception_filter); + } +} + +static void +backtrace_unregister(void) +{ + if (g_output) { + free(g_output); + RemoveVectoredExceptionHandler(g_prev); + g_prev = NULL; + g_output = NULL; + } +} + +BOOL WINAPI +DllMain(HINSTANCE hinstDLL ATTRIBUTE((unused)), DWORD dwReason, LPVOID lpvReserved ATTRIBUTE((unused))) +{ + switch (dwReason) { + case DLL_PROCESS_ATTACH: + backtrace_register(); + break; + case DLL_PROCESS_DETACH: + backtrace_unregister(); + break; + } + return TRUE; +} + + +/* cut dependence on libintl... libbfd needs this */ +char *libintl_dgettext (const char *domain_name ATTRIBUTE((unused)), const char *msgid ATTRIBUTE((unused))) +{ + static char buf[1024] = "XXX placeholder XXX"; + return buf; +} + +int __printf__ ( const char * format, ... ); +int libintl_fprintf ( FILE * stream, const char * format, ... ); +int libintl_sprintf ( char * str, const char * format, ... ); +int libintl_snprintf ( char *buffer, int buf_size, const char *format, ... ); +int libintl_vprintf ( const char * format, va_list arg ); +int libintl_vfprintf ( FILE * stream, const char * format, va_list arg ); +int libintl_vsprintf ( char * str, const char * format, va_list arg ); + +int __printf__ ( const char * format, ... ) +{ + int value; + va_list arg; + va_start(arg, format); + value = vprintf ( format, arg ); + va_end(arg); + return value; +} + +int libintl_fprintf ( FILE * stream, const char * format, ... ) +{ + int value; + va_list arg; + va_start(arg, format); + value = vfprintf ( stream, format, arg ); + va_end(arg); + return value; +} +int libintl_sprintf ( char * str, const char * format, ... ) +{ + int value; + va_list arg; + va_start(arg, format); + value = vsprintf ( str, format, arg ); + va_end(arg); + return value; +} +int libintl_snprintf ( char *buffer, int buf_size, const char *format, ... ) +{ + int value; + va_list arg; + va_start(arg, format); + value = vsnprintf ( buffer, buf_size, format, arg ); + va_end(arg); + return value; +} +int libintl_vprintf ( const char * format, va_list arg ) +{ + return vprintf ( format, arg ); +} +int libintl_vfprintf ( FILE * stream, const char * format, va_list arg ) +{ + return vfprintf ( stream, format, arg ); +} +int libintl_vsprintf ( char * str, const char * format, va_list arg ) +{ + return vsprintf ( str, format, arg ); +} + +/* cut dependence on zlib... libbfd needs this */ + +int compress (unsigned char *dest ATTRIBUTE((unused)), unsigned long destLen ATTRIBUTE((unused)), const unsigned char source ATTRIBUTE((unused)), unsigned long sourceLen ATTRIBUTE((unused))) +{ + return 0; +} +unsigned long compressBound (unsigned long sourceLen) +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; +} +int inflateEnd(void *strm ATTRIBUTE((unused))) +{ + return 0; +} +int inflateInit_(void *strm ATTRIBUTE((unused)), const char *version ATTRIBUTE((unused)), int stream_size ATTRIBUTE((unused))) +{ + return 0; +} +int inflateReset(void *strm ATTRIBUTE((unused))) +{ + return 0; +} +int inflate(void *strm ATTRIBUTE((unused)), int flush ATTRIBUTE((unused))) +{ + return 0; +} diff --git a/bin/windows/vpx/src/compat-to-msvc/Makefile b/bin/windows/vpx/src/compat-to-msvc/Makefile new file mode 100644 index 00000000000..7c5f3760de4 --- /dev/null +++ b/bin/windows/vpx/src/compat-to-msvc/Makefile @@ -0,0 +1,22 @@ + +o=o + +NAME:=libcompat-to-msvc + + +%.$o: %.c + gcc -Wall -Wextra -O3 -c $< -o $@ + +%.$o: %.S + gcc -c $< -o $@ + +OBJS=dll_math.$o io_math.$o dll_dependency.$o vsnprintf.$o + +.INTERMEDIATE: $(OBJS) + +$(NAME).a: $(OBJS) + ar rc $@ $^ + ranlib $@ + +clean: + -rm -f *.a *.o diff --git a/bin/windows/vpx/src/compat-to-msvc/dll_dependency.S b/bin/windows/vpx/src/compat-to-msvc/dll_dependency.S new file mode 100644 index 00000000000..31fd95c8223 --- /dev/null +++ b/bin/windows/vpx/src/compat-to-msvc/dll_dependency.S @@ -0,0 +1,88 @@ +/* Implementation for gcc's internal stack-allocation routines. */ +.global ___chkstk +.global __alloca + +.global ___chkstk_ms +___chkstk_ms: +#ifdef _WIN64 + pushq %rax + pushq %rcx + cmpq $0x1000, %rax + leaq 24(%rsp), %rcx + jb .Lchkstk_ms_end +.Lchkstk_ms_loop: + subq $0x1000, %rcx + subq $0x1000, %rax + orq $0x0, (%rcx) + cmpq $0x1000, %rax + ja .Lchkstk_ms_loop +.Lchkstk_ms_end: + subq %rax, %rcx + orq $0x0, (%rcx) + popq %rcx + popq %rax + ret +#else + pushl %eax + pushl %ecx + cmpl $0x1000, %eax + leal 12(%esp), %ecx + jb chkstk_ms_end +chkstk_ms_loop: + subl $0x1000, %ecx + subl $0x1000, %eax + orl $0x0, (%ecx) + cmpl $0x1000, %eax + ja chkstk_ms_loop +chkstk_ms_end: + subl %eax, %ecx + orl $0x0, (%ecx) + popl %ecx + popl %eax + ret +#endif + +#ifdef _WIN64 +__alloca: + movq %rcx, %rax +.align 4 +___chkstk: + popq %r11 + movq %rsp, %r10 + cmpq $0x1000, %rax + jb .Lchkstk_end +.Lchkstk_loop: + subq $0x1000, %r10 + subq $0x1000, %rax + orl $0x0, (%r10) + cmpq $0x1000, %rax + ja .Lchkstk_loop +.Lchkstk_end: + subq %rax, %r10 + movq %rsp, %rax + orl $0x0, (%r10) + movq %r10, %rsp + pushq %r11 + ret +#else +___chkstk: +__alloca: + pushl %ecx + leal 8(%esp), %ecx + cmpl $0x1000, %eax /* > 4k ?*/ + jb chkstk_end +chkstk_loop: + subl $0x1000, %ecx + subl $0x1000, %eax + orl $0x0, (%ecx) + cmpl $0x1000, %eax + ja chkstk_loop +chkstk_end: + subl %eax, %ecx + orl $0x0, (%ecx) + movl %esp, %eax + movl %ecx, %esp + movl (%eax), %ecx + pushl 4(%eax) + ret +#endif diff --git a/bin/windows/vpx/src/compat-to-msvc/dll_math.c b/bin/windows/vpx/src/compat-to-msvc/dll_math.c new file mode 100644 index 00000000000..966fb99d711 --- /dev/null +++ b/bin/windows/vpx/src/compat-to-msvc/dll_math.c @@ -0,0 +1,572 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#ifndef _LIBKERN_QUAD_H_ +#define _LIBKERN_QUAD_H_ + +/* + * Quad arithmetic. + * + * This library makes the following assumptions: + * + * - The type long long (aka quad_t) exists. + * + * - A quad variable is exactly twice as long as `long'. + * + * - The machine's arithmetic is two's complement. + * + * This library can provide 128-bit arithmetic on a machine with 128-bit + * quads and 64-bit longs, for instance, or 96-bit arithmetic on machines + * with 48-bit longs. + */ +/* +#include +#include +#include +#include +*/ + +#include +typedef long long quad_t; +typedef unsigned long long u_quad_t; +typedef unsigned long u_long; +#ifndef CHAR_BIT +# define CHAR_BIT __CHAR_BIT__ +#endif + +/* + * Define the order of 32-bit words in 64-bit words. + * For little endian only. + */ +#define _QUAD_HIGHWORD 1 +#define _QUAD_LOWWORD 0 + +/* + * Depending on the desired operation, we view a `long long' (aka quad_t) in + * one or more of the following formats. + */ +union uu { + quad_t q; /* as a (signed) quad */ + quad_t uq; /* as an unsigned quad */ + long sl[2]; /* as two signed longs */ + u_long ul[2]; /* as two unsigned longs */ +}; + +/* + * Define high and low longwords. + */ +#define H _QUAD_HIGHWORD +#define L _QUAD_LOWWORD + +/* + * Total number of bits in a quad_t and in the pieces that make it up. + * These are used for shifting, and also below for halfword extraction + * and assembly. + */ +#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT) +#define LONG_BITS (sizeof(long) * CHAR_BIT) +#define HALF_BITS (sizeof(long) * CHAR_BIT / 2) + +/* + * Extract high and low shortwords from longword, and move low shortword of + * longword to upper half of long, i.e., produce the upper longword of + * ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.) + * + * These are used in the multiply code, to split a longword into upper + * and lower halves, and to reassemble a product as a quad_t, shifted left + * (sizeof(long)*CHAR_BIT/2). + */ +#define HHALF(x) ((x) >> HALF_BITS) +#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1)) +#define LHUP(x) ((x) << HALF_BITS) + +typedef unsigned int qshift_t; + +quad_t __ashldi3(quad_t, qshift_t); +quad_t __ashrdi3(quad_t, qshift_t); +int __cmpdi2(quad_t a, quad_t b); +quad_t __divdi3(quad_t a, quad_t b); +quad_t __lshrdi3(quad_t, qshift_t); +quad_t __moddi3(quad_t a, quad_t b); +u_quad_t __qdivrem(u_quad_t u, u_quad_t v, u_quad_t *rem); +u_quad_t __udivdi3(u_quad_t a, u_quad_t b); +u_quad_t __umoddi3(u_quad_t a, u_quad_t b); +int __ucmpdi2(u_quad_t a, u_quad_t b); + +#endif /* !_LIBKERN_QUAD_H_ */ + +#if defined (_X86_) && !defined (__x86_64__) +/* + * Shift a (signed) quad value left (arithmetic shift left). + * This is the same as logical shift left! + */ +quad_t +__ashldi3(a, shift) + quad_t a; + qshift_t shift; +{ + union uu aa; + + aa.q = a; + if (shift >= LONG_BITS) { + aa.ul[H] = shift >= QUAD_BITS ? 0 : + aa.ul[L] << (shift - LONG_BITS); + aa.ul[L] = 0; + } else if (shift > 0) { + aa.ul[H] = (aa.ul[H] << shift) | + (aa.ul[L] >> (LONG_BITS - shift)); + aa.ul[L] <<= shift; + } + return (aa.q); +} + +/* + * Shift a (signed) quad value right (arithmetic shift right). + */ +quad_t +__ashrdi3(a, shift) + quad_t a; + qshift_t shift; +{ + union uu aa; + + aa.q = a; + if (shift >= LONG_BITS) { + long s; + + /* + * Smear bits rightward using the machine's right-shift + * method, whether that is sign extension or zero fill, + * to get the `sign word' s. Note that shifting by + * LONG_BITS is undefined, so we shift (LONG_BITS-1), + * then 1 more, to get our answer. + */ + s = (aa.sl[H] >> (LONG_BITS - 1)) >> 1; + aa.ul[L] = shift >= QUAD_BITS ? s : + aa.sl[H] >> (shift - LONG_BITS); + aa.ul[H] = s; + } else if (shift > 0) { + aa.ul[L] = (aa.ul[L] >> shift) | + (aa.ul[H] << (LONG_BITS - shift)); + aa.sl[H] >>= shift; + } + return (aa.q); +} + +/* + * Return 0, 1, or 2 as a <, =, > b respectively. + * Both a and b are considered signed---which means only the high word is + * signed. + */ +int +__cmpdi2(a, b) + quad_t a, b; +{ + union uu aa, bb; + + aa.q = a; + bb.q = b; + return (aa.sl[H] < bb.sl[H] ? 0 : aa.sl[H] > bb.sl[H] ? 2 : + aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1); +} + +/* + * Divide two signed quads. + * ??? if -1/2 should produce -1 on this machine, this code is wrong + */ +quad_t +__divdi3(a, b) + quad_t a, b; +{ + u_quad_t ua, ub, uq; + int neg; + + if (a < 0) + ua = -(u_quad_t)a, neg = 1; + else + ua = a, neg = 0; + if (b < 0) + ub = -(u_quad_t)b, neg ^= 1; + else + ub = b; + uq = __qdivrem(ua, ub, (u_quad_t *)0); + return (neg ? -uq : uq); +} + +/* + * Shift an (unsigned) quad value right (logical shift right). + */ +quad_t +__lshrdi3(a, shift) + quad_t a; + qshift_t shift; +{ + union uu aa; + + aa.q = a; + if (shift >= LONG_BITS) { + aa.ul[L] = shift >= QUAD_BITS ? 0 : + aa.ul[H] >> (shift - LONG_BITS); + aa.ul[H] = 0; + } else if (shift > 0) { + aa.ul[L] = (aa.ul[L] >> shift) | + (aa.ul[H] << (LONG_BITS - shift)); + aa.ul[H] >>= shift; + } + return (aa.q); +} + +/* + * Return remainder after dividing two signed quads. + * + * XXX + * If -1/2 should produce -1 on this machine, this code is wrong. + */ +quad_t +__moddi3(a, b) + quad_t a, b; +{ + u_quad_t ua, ub, ur; + int neg; + + if (a < 0) + ua = -(u_quad_t)a, neg = 1; + else + ua = a, neg = 0; + if (b < 0) + ub = -(u_quad_t)b; + else + ub = b; + (void)__qdivrem(ua, ub, &ur); + return (neg ? -ur : ur); +} + + +/* + * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed), + * section 4.3.1, pp. 257--259. + */ + +#define B (1 << HALF_BITS) /* digit base */ + +/* Combine two `digits' to make a single two-digit number. */ +#define COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b)) + +/* select a type for digits in base B: use unsigned short if they fit */ +#if ULONG_MAX == 0xffffffff && USHRT_MAX >= 0xffff +typedef unsigned short digit; +#else +typedef u_long digit; +#endif + +/* + * Shift p[0]..p[len] left `sh' bits, ignoring any bits that + * `fall out' the left (there never will be any such anyway). + * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. + */ +static void +__shl(register digit *p, register int len, register int sh) +{ + register int i; + + for (i = 0; i < len; i++) + p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh)); + p[i] = LHALF(p[i] << sh); +} + +/* + * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v. + * + * We do this in base 2-sup-HALF_BITS, so that all intermediate products + * fit within u_long. As a consequence, the maximum length dividend and + * divisor are 4 `digits' in this base (they are shorter if they have + * leading zeros). + */ +u_quad_t +__qdivrem(uq, vq, arq) + u_quad_t uq, vq, *arq; +{ + union uu tmp; + digit *u, *v, *q; + register digit v1, v2; + u_long qhat, rhat, t; + int m, n, d, j, i; + digit uspace[5], vspace[5], qspace[5]; + + /* + * Take care of special cases: divide by zero, and u < v. + */ + if (vq == 0) { + /* divide by zero. */ + static volatile const unsigned int zero = 0; + + tmp.ul[H] = tmp.ul[L] = 1 / zero; + if (arq) + *arq = uq; + return (tmp.q); + } + if (uq < vq) { + if (arq) + *arq = uq; + return (0); + } + u = &uspace[0]; + v = &vspace[0]; + q = &qspace[0]; + + /* + * Break dividend and divisor into digits in base B, then + * count leading zeros to determine m and n. When done, we + * will have: + * u = (u[1]u[2]...u[m+n]) sub B + * v = (v[1]v[2]...v[n]) sub B + * v[1] != 0 + * 1 < n <= 4 (if n = 1, we use a different division algorithm) + * m >= 0 (otherwise u < v, which we already checked) + * m + n = 4 + * and thus + * m = 4 - n <= 2 + */ + tmp.uq = uq; + u[0] = 0; + u[1] = HHALF(tmp.ul[H]); + u[2] = LHALF(tmp.ul[H]); + u[3] = HHALF(tmp.ul[L]); + u[4] = LHALF(tmp.ul[L]); + tmp.uq = vq; + v[1] = HHALF(tmp.ul[H]); + v[2] = LHALF(tmp.ul[H]); + v[3] = HHALF(tmp.ul[L]); + v[4] = LHALF(tmp.ul[L]); + for (n = 4; v[1] == 0; v++) { + if (--n == 1) { + u_long rbj; /* r*B+u[j] (not root boy jim) */ + digit q1, q2, q3, q4; + + /* + * Change of plan, per exercise 16. + * r = 0; + * for j = 1..4: + * q[j] = floor((r*B + u[j]) / v), + * r = (r*B + u[j]) % v; + * We unroll this completely here. + */ + t = v[2]; /* nonzero, by definition */ + q1 = u[1] / t; + rbj = COMBINE(u[1] % t, u[2]); + q2 = rbj / t; + rbj = COMBINE(rbj % t, u[3]); + q3 = rbj / t; + rbj = COMBINE(rbj % t, u[4]); + q4 = rbj / t; + if (arq) + *arq = rbj % t; + tmp.ul[H] = COMBINE(q1, q2); + tmp.ul[L] = COMBINE(q3, q4); + return (tmp.q); + } + } + + /* + * By adjusting q once we determine m, we can guarantee that + * there is a complete four-digit quotient at &qspace[1] when + * we finally stop. + */ + for (m = 4 - n; u[1] == 0; u++) + m--; + for (i = 4 - m; --i >= 0;) + q[i] = 0; + q += 4 - m; + + /* + * Here we run Program D, translated from MIX to C and acquiring + * a few minor changes. + * + * D1: choose multiplier 1 << d to ensure v[1] >= B/2. + */ + d = 0; + for (t = v[1]; t < B / 2; t <<= 1) + d++; + if (d > 0) { + __shl(&u[0], m + n, d); /* u <<= d */ + __shl(&v[1], n - 1, d); /* v <<= d */ + } + /* + * D2: j = 0. + */ + j = 0; + v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ + v2 = v[2]; /* for D3 */ + do { + register digit uj0, uj1, uj2; + + /* + * D3: Calculate qhat (\^q, in TeX notation). + * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and + * let rhat = (u[j]*B + u[j+1]) mod v[1]. + * While rhat < B and v[2]*qhat > rhat*B+u[j+2], + * decrement qhat and increase rhat correspondingly. + * Note that if rhat >= B, v[2]*qhat < rhat*B. + */ + uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ + uj1 = u[j + 1]; /* for D3 only */ + uj2 = u[j + 2]; /* for D3 only */ + if (uj0 == v1) { + qhat = B; + rhat = uj1; + goto qhat_too_big; + } else { + u_long nn = COMBINE(uj0, uj1); + qhat = nn / v1; + rhat = nn % v1; + } + while (v2 * qhat > COMBINE(rhat, uj2)) { + qhat_too_big: + qhat--; + if ((rhat += v1) >= B) + break; + } + /* + * D4: Multiply and subtract. + * The variable `t' holds any borrows across the loop. + * We split this up so that we do not require v[0] = 0, + * and to eliminate a final special case. + */ + for (t = 0, i = n; i > 0; i--) { + t = u[i + j] - v[i] * qhat - t; + u[i + j] = LHALF(t); + t = (B - HHALF(t)) & (B - 1); + } + t = u[j] - t; + u[j] = LHALF(t); + /* + * D5: test remainder. + * There is a borrow if and only if HHALF(t) is nonzero; + * in that (rare) case, qhat was too large (by exactly 1). + * Fix it by adding v[1..n] to u[j..j+n]. + */ + if (HHALF(t)) { + qhat--; + for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ + t += u[i + j] + v[i]; + u[i + j] = LHALF(t); + t = HHALF(t); + } + u[j] = LHALF(u[j] + t); + } + q[j] = qhat; + } while (++j <= m); /* D7: loop on j. */ + + /* + * If caller wants the remainder, we have to calculate it as + * u[m..m+n] >> d (this is at most n digits and thus fits in + * u[m+1..m+n], but we may need more source digits). + */ + if (arq) { + if (d) { + for (i = m + n; i > m; --i) + u[i] = (u[i] >> d) | + LHALF(u[i - 1] << (HALF_BITS - d)); + u[i] = 0; + } + tmp.ul[H] = COMBINE(uspace[1], uspace[2]); + tmp.ul[L] = COMBINE(uspace[3], uspace[4]); + *arq = tmp.q; + } + + tmp.ul[H] = COMBINE(qspace[1], qspace[2]); + tmp.ul[L] = COMBINE(qspace[3], qspace[4]); + return (tmp.q); +} + +/* + * Return 0, 1, or 2 as a <, =, > b respectively. + * Neither a nor b are considered signed. + */ +int +__ucmpdi2(a, b) + u_quad_t a, b; +{ + union uu aa, bb; + + aa.uq = a; + bb.uq = b; + return (aa.ul[H] < bb.ul[H] ? 0 : aa.ul[H] > bb.ul[H] ? 2 : + aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1); +} + +/* + * Divide two unsigned quads. + */ +u_quad_t +__udivdi3(a, b) + u_quad_t a, b; +{ + + return (__qdivrem(a, b, (u_quad_t *)0)); +} + +/* + * Return remainder after dividing two unsigned quads. + */ +u_quad_t +__umoddi3(a, b) + u_quad_t a, b; +{ + u_quad_t r; + + (void)__qdivrem(a, b, &r); + return (r); +} + +/* + * Divide two unsigned quads. + * This function is new in GCC 7. + */ +u_quad_t +__udivmoddi4(a, b, rem) + u_quad_t a, b, *rem; +{ + u_quad_t ua, ub, uq, ur; + + ua = a; + ub = b; + uq = __qdivrem(ua, ub, &ur); + if (rem) + *rem = ur; + return uq; +} +#else +static int __attribute__((unused)) dummy; +#endif /* defined (_X86_) && !defined (__x86_64__) */ + diff --git a/bin/windows/vpx/src/compat-to-msvc/io_math.c b/bin/windows/vpx/src/compat-to-msvc/io_math.c new file mode 100644 index 00000000000..39d5a8e3943 --- /dev/null +++ b/bin/windows/vpx/src/compat-to-msvc/io_math.c @@ -0,0 +1,39 @@ +// Some libraries expect these functions, for which Visual Studio (pre-2013) falls down on the job. + +#include +#include + +#ifndef _MSC_VER +# include +int64_t _ftelli64( + FILE *stream +); +int _fseeki64( + FILE *stream, + int64_t offset, + int origin +); +#endif + +int fseeko(FILE *fp, off_t offset, int whence) +{ + return _fseeki64(fp, (int64_t)offset, whence); +} +int fseeko64(FILE *fp, off64_t offset, int whence) +{ + return _fseeki64(fp, (int64_t)offset, whence); +} + +off_t ftello(FILE *stream) +{ + return (off_t)_ftelli64(stream); +} +off64_t ftello64(FILE *stream) +{ + return (off64_t)_ftelli64(stream); +} + +long lround(double d) +{ + return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5)); +} diff --git a/bin/windows/vpx/src/compat-to-msvc/vsnprintf.c b/bin/windows/vpx/src/compat-to-msvc/vsnprintf.c new file mode 100644 index 00000000000..15de014c4ac --- /dev/null +++ b/bin/windows/vpx/src/compat-to-msvc/vsnprintf.c @@ -0,0 +1,19 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#define __CRT__NO_INLINE +#include +#include + +extern int __cdecl _vsnprintf(char * __restrict__, size_t, const char * __restrict__, va_list); + +int __cdecl __ms_vsnprintf (char * __restrict__ s, size_t n, const char * __restrict__ format, va_list arg) +{ + return _vsnprintf(s, n, format, arg); +} +int __cdecl __mingw_vsnprintf (char * __restrict__ s, size_t n, const char * __restrict__ format, va_list arg) +{ + return _vsnprintf(s, n, format, arg); +} diff --git a/bin/windows/zmusic/arm64/zmusic.lib b/bin/windows/zmusic/arm64/zmusic.lib new file mode 100644 index 00000000000..4827759367a Binary files /dev/null and b/bin/windows/zmusic/arm64/zmusic.lib differ diff --git a/bin/windows/zmusic/include/zmusic.h b/bin/windows/zmusic/include/zmusic.h index 0dd186c15f6..7422b58da26 100644 --- a/bin/windows/zmusic/include/zmusic.h +++ b/bin/windows/zmusic/include/zmusic.h @@ -29,7 +29,8 @@ typedef enum EMIDIType_ MIDI_MIDI, MIDI_HMI, MIDI_XMI, - MIDI_MUS + MIDI_MUS, + MIDI_MIDS } EMIDIType; typedef enum EMidiDevice_ @@ -66,7 +67,8 @@ typedef struct SoundStreamInfo_ typedef enum SampleType_ { SampleType_UInt8, - SampleType_Int16 + SampleType_Int16, + SampleType_Float32 } SampleType; typedef enum ChannelConfig_ @@ -75,6 +77,15 @@ typedef enum ChannelConfig_ ChannelConfig_Stereo } ChannelConfig; +typedef struct SoundStreamInfoEx_ +{ + int mBufferSize; // If mBufferSize is 0, the song doesn't use streaming but plays through a different interface. + int mSampleRate; + SampleType mSampleType; + ChannelConfig mChannelConfig; +} SoundStreamInfoEx; + + typedef enum EIntConfigKey_ { zmusic_adl_chips_count, @@ -263,14 +274,14 @@ typedef struct ZMusicConfigurationSetting_ #ifndef ZMUSIC_INTERNAL -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(ZMUSIC_STATIC) #define DLL_IMPORT _declspec(dllimport) -#else // !_MSC_VER +#else #define DLL_IMPORT -#endif // _MSC_VER +#endif // Note that the internal 'class' definitions are not C compatible! -typedef struct { int zm1; } *ZMusic_MidiSource; -typedef struct { int zm2; } *ZMusic_MusicStream; +typedef struct _ZMusic_MidiSource_Struct { int zm1; } *ZMusic_MidiSource; +typedef struct _ZMusic_MusicStream_Struct { int zm2; } *ZMusic_MusicStream; struct SoundDecoder; #endif @@ -313,10 +324,12 @@ extern "C" DLL_IMPORT void ZMusic_Close(ZMusic_MusicStream song); DLL_IMPORT zmusic_bool ZMusic_SetSubsong(ZMusic_MusicStream song, int subsong); DLL_IMPORT zmusic_bool ZMusic_IsLooping(ZMusic_MusicStream song); + DLL_IMPORT int ZMusic_GetDeviceType(ZMusic_MusicStream song); DLL_IMPORT zmusic_bool ZMusic_IsMIDI(ZMusic_MusicStream song); DLL_IMPORT void ZMusic_VolumeChanged(ZMusic_MusicStream song); DLL_IMPORT zmusic_bool ZMusic_WriteSMF(ZMusic_MidiSource source, const char* fn, int looplimit); DLL_IMPORT void ZMusic_GetStreamInfo(ZMusic_MusicStream song, SoundStreamInfo *info); + DLL_IMPORT void ZMusic_GetStreamInfoEx(ZMusic_MusicStream song, SoundStreamInfoEx *info); // Configuration interface. The return value specifies if a music restart is needed. // RealValue should be written back to the CVAR or whatever other method the client uses to store configuration state. DLL_IMPORT zmusic_bool ChangeMusicSettingInt(EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue); @@ -404,6 +417,7 @@ typedef zmusic_bool (*pfn_ZMusic_IsMIDI)(ZMusic_MusicStream song); typedef void (*pfn_ZMusic_VolumeChanged)(ZMusic_MusicStream song); typedef zmusic_bool (*pfn_ZMusic_WriteSMF)(ZMusic_MidiSource source, const char* fn, int looplimit); typedef void (*pfn_ZMusic_GetStreamInfo)(ZMusic_MusicStream song, SoundStreamInfo *info); +typedef void (*pfn_ZMusic_GetStreamInfoEx)(ZMusic_MusicStream song, SoundStreamInfoEx *info); typedef zmusic_bool (*pfn_ChangeMusicSettingInt)(EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue); typedef zmusic_bool (*pfn_ChangeMusicSettingFloat)(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue); typedef zmusic_bool (*pfn_ChangeMusicSettingString)(EStringConfigKey key, ZMusic_MusicStream song, const char* value); @@ -417,4 +431,4 @@ typedef const ZMusicMidiOutDevice *(*pfn_ZMusic_GetMidiDevices)(int *pAmount); -#endif \ No newline at end of file +#endif diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index f759f99380c..02c6bba0676 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -1,3 +1,6 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + # Locate SDL2 library # This module defines # SDL2_LIBRARY, the name of the library to link against @@ -57,19 +60,6 @@ # was not created for redistribution, and exists temporarily pending official # SDL2 CMake modules. -#============================================================================= -# Copyright 2003-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - FIND_PATH(SDL2_INCLUDE_DIR SDL.h HINTS $ENV{SDL2DIR} diff --git a/cmake/FindVPX.cmake b/cmake/FindVPX.cmake new file mode 100644 index 00000000000..160ff061817 --- /dev/null +++ b/cmake/FindVPX.cmake @@ -0,0 +1,8 @@ + +find_path(VPX_INCLUDE_DIR NAMES vpx/vp8dx.h vpx/vpx_decoder.h) +find_library(VPX_LIBRARIES NAMES vpx) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(VPX DEFAULT_MSG VPX_LIBRARIES VPX_INCLUDE_DIR) + +mark_as_advanced(VPX_INCLUDE_DIR VPX_LIBRARIES) diff --git a/cmake/FindZMusic.cmake b/cmake/FindZMusic.cmake index dd0c9296dd2..43754a80790 100644 --- a/cmake/FindZMusic.cmake +++ b/cmake/FindZMusic.cmake @@ -10,9 +10,15 @@ if(ZMUSIC_INCLUDE_DIR AND ZMUSIC_LIBRARIES) set(ZMUSIC_FIND_QUIETLY TRUE) endif() -find_path(ZMUSIC_INCLUDE_DIR zmusic.h) +find_path(ZMUSIC_INCLUDE_DIR zmusic.h + HINTS + ${CMAKE_SOURCE_DIR}/build/zmusic/include +) -find_library(ZMUSIC_LIBRARIES NAMES zmusic) +find_library(ZMUSIC_LIBRARIES NAMES zmusic + HINTS + ${CMAKE_SOURCE_DIR}/build/zmusic/build/source +) mark_as_advanced(ZMUSIC_LIBRARIES ZMUSIC_INCLUDE_DIR) # handle the QUIETLY and REQUIRED arguments and set ZMUSIC_FOUND to TRUE if diff --git a/cmake/TargetArch.cmake b/cmake/TargetArch.cmake index 198aa9c0523..31e2e048de9 100644 --- a/cmake/TargetArch.cmake +++ b/cmake/TargetArch.cmake @@ -29,7 +29,7 @@ # "There are many more known variants/revisions that we do not handle/detect." set(archdetect_c_code " -#if defined(__arm__) || defined(__TARGET_ARCH_ARM) +#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM64) || defined (__aarch64__) #if defined(__ARM_ARCH_7__) \\ || defined(__ARM_ARCH_7A__) \\ || defined(__ARM_ARCH_7R__) \\ @@ -48,6 +48,8 @@ set(archdetect_c_code " #elif defined(__ARM_ARCH_5TEJ__) \\ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5) #error cmake_ARCH armv5 + #elif defined(_M_ARM64) || defined (__aarch64__) + #error cmake_ARCH arm64 #else #error cmake_ARCH arm #endif @@ -96,6 +98,8 @@ function(target_architecture output_var) set(osx_arch_x86_64 TRUE) elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support) set(osx_arch_ppc64 TRUE) + elseif("${osx_arch}" STREQUAL "arm64") + set(osx_arch_arm64 TRUE) else() message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}") endif() @@ -117,6 +121,10 @@ function(target_architecture output_var) if(osx_arch_ppc64) list(APPEND ARCH ppc64) endif() + + if(osx_arch_arm64) + list(APPEND ARCH arm64) + endif() else() file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}") diff --git a/docs/console.html b/docs/console.html index d5ca0a735b0..7fb5d4c8c57 100644 --- a/docs/console.html +++ b/docs/console.html @@ -2361,6 +2361,11 @@

Other commands and cvars

of a music lump or file on disk (which need not have been specified with the -file parameter). +
changeskill skill
+
Changes the current skill of the game. The skill change will take + effect at the next map change. The skill must be a number. The default skill + levels range from 0 to 4 inclusive. +
chase
Turns the chasecom on and off. This command also works while watching demos, so you can bind it to a key and watch demos in the third @@ -3177,6 +3182,7 @@

C

centerview
changemap
changemus
+ changeskill
chase
chase_dist
chase_height
diff --git a/docs/licenses/README.TXT b/docs/licenses/README.TXT index 53d939b06ea..46d84c26b1f 100644 --- a/docs/licenses/README.TXT +++ b/docs/licenses/README.TXT @@ -9,7 +9,7 @@ GPL v3 with permission. The majority of original code uses a BSD-like lincese. See bsd.txt. The OpenGL renderer is released under the LGPL v3, except some bits -of code that were inherited fro ZDoomGL. +of code that were inherited from ZDoomGL. Some code was taken from the Eternity Engine. Copyright (c) James Haley, Stephen McGranahan, et al. @@ -31,4 +31,4 @@ version used by the foobar2000 component foo_dumb as of mid-2008, found at http://kode54.foobar2000.org/. All script code in gzdoom.pk3 is licensed under the GPL v3 unless noted -otherwise. \ No newline at end of file +otherwise. diff --git a/fm_banks/GENMIDI-readme.txt b/fm_banks/GENMIDI-readme.txt new file mode 100644 index 00000000000..5ab2fec0d40 --- /dev/null +++ b/fm_banks/GENMIDI-readme.txt @@ -0,0 +1,106 @@ +DMXOPL3 +================================================================== +https://github.com/sneakernets/DMXOPL +================================================================== + +New and improved DMX GENMIDI for Doom and sourceports, taking full advantage of +the OPL3 waveforms. This takes things up a notch in terms of timbre. + +# Summary +This is a GENMIDI patch for DMX for OPL3 FM synthesis. This patch aims to remedy +the "weak" default instruments to better match the Roland Sound Canvas, most +notably the SC-55 and SC-88. Recommended minimum setup for no note-cuts is +ZDoom 2.8.1 with DOSBOX OPL3 emulator core, with 6 chips emulated. + +======FAQ====== +# Why OPL3 only? +OPL3 has four additional waveforms - Alternating Sine, Camel Sine, Square, and +Logarithmic Square (Sawtooth). The most interesting of these is the Square wave, +for obvious reasons! This will benefit percussion instruments immensely. + +# What did you use for this project? + +Hex Editors, OPL3 Bank Editor, Fraggle's Python scripts, Adlib Tracker II, +Edlib, ADLMidi. I also used the following keyboards and devices: + +- Yamaha PSR-3 for basic voice ideas +- Yamaha PSS-50 for layered voice ideas +- Yamaha DX-7 +- Commodore 64 Music Module +- VRC7 and related chips +- Sound Blaster 16 +- Yamaha PCI cards +- Sounds from various SEGA MegaDrive games + +=======WOPL FAQ======= +# What's the difference between the WOPL version and the DMX version? +The main difference is with a few instruments that had to be tweaked to work +with DMX. Most of these changes are negligible for General MIDI stuff. To hear +what I intended DMXOPL to sound like in Doom, you'll have to wait for Eternity +Engine's ADLMIDI support to be finalized. + +# Any plans for GS/XG support? +Yes. This will take considerable time, and voices will be added as I come across +them in my MIDI files. You can check the progress on those through the XG and GS +branches that I will make (or have already made). As I think the GM set is solid +enough now, save for just a handful of instruments, I can start work on the +other banks. + +# Will the WOPL version be usable on any other FM chips? +Depends on the chip, but more than likely the answer is no. YMF262 (and the OPL* +family for that matter) operate differently than most of the other FM chips, and +wouldn't likely transfer over to DX-7 or other instruments without considerable +work, if they would work at all. + + +# Is the best way to listen to this really through an emulator? +Yes, unfortunately. Unless someone makes an FM chip that can handle 128+ +channels, this is likely never to change. If you're using this in your music +projects and you still want to use the real thing, I recommend recording one +track at a time and throwing the result in your favorite DAW - just be sure to +put a highpass filter set to a really low value (I recommend 5 Hz) to get rid +of the offset garbage, lest your mix splatter like crazy. + +======Credits====== +* Wohlstand, for the OPL3BankEditor +* Bisqwuit, for ADLMidi +* Fraggle, for Chocolate Doom and GENMIDI research, as well as the Python scripts +* SubZ3ro, for AdLib Tracker II +* Esselfortium, for the encouragement and support +* Jimmy, who will include this in the next Adventures of Square release +* The Fat Man, who created the famous 2-op and 4-op patches everyone knows +* Diode Milliampere, who made FM synth popular again +* Patchouli, for keeping my spirits up +* Graf Zahl, for continuing ZDoom as GZDoom +* Randi, for implementing the OPL Emulation in ZDoom +* Fisk, for miscellaneous feedback and MIDIs to test +* Stewboy, for the Ancient Aliens MIDIs to test +* Xaser, who said this patch passes the "Angry Scientist test" +* Minigunner, just because +* Altazimuth, who claims it'll be in Eternity someday (this is now true) +* MTrop +* Quasar, for Eternity Engine +* Glaice, for patch advice +* BlastFrog, for patch advice +* Vogons Forums, for the OPL-3 Research and tools +* AtariAge, for C64 Sound module preset banks +* NintendoAge +* John Chowning, the father of FM synthesis. I hope he can hear this someday. + +## Extra Thanks to: +* Doomworld Forums and the respective IRC/DISCORD channels +* The 4th Modulator DISCORD channels +* Giest118, who installed Doom again to listen to this +* Nuke.YKT, for testing this in Raptor, and for the Nuked OPL core +* kode54, who added this to Cog and FB2K, thank you! +* Patch93, who contributed various patches +* OlPainless, who contributed various patches +* Papiezak, who contributed various of patches +* Infurnus, for support +* Leileilol, for support +* MaliceX, for support +* Kuschelmonster, for support +* Anyone who makes music with this thing! + + YMF262 forever. + diff --git a/fm_banks/GENMIDI.GS.wopl b/fm_banks/GENMIDI.GS.wopl index fb9646f947f..90f1ab9a54b 100644 Binary files a/fm_banks/GENMIDI.GS.wopl and b/fm_banks/GENMIDI.GS.wopl differ diff --git a/fm_banks/LINKS.txt b/fm_banks/LINKS.txt new file mode 100644 index 00000000000..4a5f592a306 --- /dev/null +++ b/fm_banks/LINKS.txt @@ -0,0 +1 @@ +https://github.com/Wohlstand/OPN2BankEditor diff --git a/fm_banks/Tomsoft-readme.txt b/fm_banks/Tomsoft-readme.txt new file mode 100644 index 00000000000..13746830a98 --- /dev/null +++ b/fm_banks/Tomsoft-readme.txt @@ -0,0 +1,15 @@ +Bank was imported by a hacky way from the Tomsoft's SegaMusic program +by TommyXie (Xie Rong Chun): +- the dummy MIDI file was created that contains all 128 instruments in GM order +- the Sega emulator playable BIN file was generated +- the GYM dump was generated from the playback of that dummy instrument +- OPN2 Bank Editor was used to scan GYM file for instruments and import all of +them. + +The work woth done by Jean-Pierre Cimalando: +https://github.com/Wohlstand/OPN2BankEditor/issues/44 + +Then, the bank was tuned by Wohlstand: +- Corrected note offsets to align octaves of all instruments +- Merged with xg.wopn to provide the set of percussions. + diff --git a/fm_banks/Tomsoft.wopn b/fm_banks/Tomsoft.wopn new file mode 100644 index 00000000000..92ccabfb048 Binary files /dev/null and b/fm_banks/Tomsoft.wopn differ diff --git a/fm_banks/fmmidi-readme.txt b/fm_banks/fmmidi-readme.txt new file mode 100644 index 00000000000..dd667687d34 --- /dev/null +++ b/fm_banks/fmmidi-readme.txt @@ -0,0 +1,7 @@ +A bank, created from hardcoded instruments, extracted from "fmmidi" project + +http://unhaut.x10host.com/fmmidi/ + +It's license: +This program is released under the "three clauses" BSD license + diff --git a/fm_banks/fmmidi.wopn b/fm_banks/fmmidi.wopn new file mode 100644 index 00000000000..0bf663f2e35 Binary files /dev/null and b/fm_banks/fmmidi.wopn differ diff --git a/fm_banks/gems-fmlib-gmize-readme.txt b/fm_banks/gems-fmlib-gmize-readme.txt new file mode 100644 index 00000000000..7265179246c --- /dev/null +++ b/fm_banks/gems-fmlib-gmize-readme.txt @@ -0,0 +1,8 @@ +This bank was created by Wohlstand from imported instruments from the standard +set of insruments pre-included with GEMS program which was a official Sega +music creation system. Original set was not GM. Therefore, imported instruments +are was organized to provide a proper GM set. + +Some instruments was a bit modified, some melodic instruments and percussions +are was taken from Wohlstand's xg.wopn bank. + diff --git a/fm_banks/gems-fmlib-gmize.wopn b/fm_banks/gems-fmlib-gmize.wopn new file mode 100644 index 00000000000..5b6c79d62f9 Binary files /dev/null and b/fm_banks/gems-fmlib-gmize.wopn differ diff --git a/fm_banks/gs-by-papiezak-and-sneakernets-readme.txt b/fm_banks/gs-by-papiezak-and-sneakernets-readme.txt new file mode 100644 index 00000000000..96a41fedcd5 --- /dev/null +++ b/fm_banks/gs-by-papiezak-and-sneakernets-readme.txt @@ -0,0 +1,25 @@ +============= +https://github.com/sneakernets/DMXOPN2 +https://github.com/papiezak/DMXOPN2 +============= + +== DMXOPN2 == + +No-nonsense patches for YM2612. + + +== About == + +After much work on my DMXOPL project, I noticed that a lot of presets that +I created were not compatible with the YM2612, which was the chip I started +with, but quickly dropped. In response, I decided to rectify this by recreating +the best patches from DMXOPL to OPN2 format. Don't expect miracles, as this is +more of a learning experience so I can start working on expanding my FM synth +knowledge. + +I chose the name "DMX" not because it works with DMX, but that it will +(hopefully) be of the same quality as the DMXOPL patch. Yeah, not very +descriptive, but names aren't everything. + +Watch this space. + diff --git a/fm_banks/readme.txt b/fm_banks/readme.txt new file mode 100644 index 00000000000..4d7994a2299 --- /dev/null +++ b/fm_banks/readme.txt @@ -0,0 +1,14 @@ +This bank (gm.wopn and xg.wopn) is made by me. I have imported some instruments from various +VGM files, ported from OPL3 banks, or remixed them. + +This bank can be freely used, modified, shared with any purposes. + +License for this bank - MIT + +To edit this bank and other banks in WOPN format, you can use this editor +which I created for that: https://github.com/Wohlstand/OPN2BankEditor + +============================================================================== + +Vitaliy Novichkov "Wohlstand", 2017-2018 + diff --git a/fm_banks/xg.wopn b/fm_banks/xg.wopn new file mode 100644 index 00000000000..38208b255b4 Binary files /dev/null and b/fm_banks/xg.wopn differ diff --git a/libraries/ZVulkan/CMakeLists.txt b/libraries/ZVulkan/CMakeLists.txt new file mode 100644 index 00000000000..3b47b7b6863 --- /dev/null +++ b/libraries/ZVulkan/CMakeLists.txt @@ -0,0 +1,210 @@ +cmake_minimum_required(VERSION 3.15) +project(zvulkan) + +option( VULKAN_USE_XLIB "Use Vulkan xlib (X11) WSI integration" ON ) +option( VULKAN_USE_WAYLAND "Use Vulkan Wayland WSI integration" OFF ) + +if ( VULKAN_USE_XLIB ) + add_definitions( -DVULKAN_USE_XLIB=1 ) +else() + if (VULKAN_USE_WAYLAND) + add_definitions( -DVULKAN_USE_WAYLAND=1 ) + endif() +endif() + +set(ZVULKAN_SOURCES + src/vulkanbuilders.cpp + src/vulkandevice.cpp + src/vulkaninstance.cpp + src/vulkansurface.cpp + src/vulkanswapchain.cpp + src/vk_mem_alloc/vk_mem_alloc.cpp + src/vk_mem_alloc/vk_mem_alloc.natvis + src/volk/volk.c + src/glslang/glslang/MachineIndependent/SymbolTable.h + src/glslang/glslang/MachineIndependent/propagateNoContraction.cpp + src/glslang/glslang/MachineIndependent/PoolAlloc.cpp + src/glslang/glslang/MachineIndependent/Intermediate.cpp + src/glslang/glslang/MachineIndependent/gl_types.h + src/glslang/glslang/MachineIndependent/parseVersions.h + src/glslang/glslang/MachineIndependent/attribute.cpp + src/glslang/glslang/MachineIndependent/Scan.cpp + src/glslang/glslang/MachineIndependent/iomapper.h + src/glslang/glslang/MachineIndependent/ParseHelper.h + src/glslang/glslang/MachineIndependent/glslang_tab.cpp.h + src/glslang/glslang/MachineIndependent/SymbolTable.cpp + src/glslang/glslang/MachineIndependent/RemoveTree.cpp + src/glslang/glslang/MachineIndependent/Versions.h + src/glslang/glslang/MachineIndependent/reflection.cpp + src/glslang/glslang/MachineIndependent/LiveTraverser.h + src/glslang/glslang/MachineIndependent/iomapper.cpp + src/glslang/glslang/MachineIndependent/intermOut.cpp + src/glslang/glslang/MachineIndependent/Versions.cpp + src/glslang/glslang/MachineIndependent/Initialize.h + src/glslang/glslang/MachineIndependent/linkValidate.cpp + src/glslang/glslang/MachineIndependent/InfoSink.cpp + src/glslang/glslang/MachineIndependent/Constant.cpp + src/glslang/glslang/MachineIndependent/IntermTraverse.cpp + src/glslang/glslang/MachineIndependent/propagateNoContraction.h + src/glslang/glslang/MachineIndependent/glslang_tab.cpp + src/glslang/glslang/MachineIndependent/ShaderLang.cpp + src/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp + src/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h + src/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp + src/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp + src/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp + src/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp + src/glslang/glslang/MachineIndependent/preprocessor/PpContext.h + src/glslang/glslang/MachineIndependent/attribute.h + src/glslang/glslang/MachineIndependent/localintermediate.h + src/glslang/glslang/MachineIndependent/parseConst.cpp + src/glslang/glslang/MachineIndependent/Initialize.cpp + src/glslang/glslang/MachineIndependent/limits.cpp + src/glslang/glslang/MachineIndependent/ParseContextBase.cpp + src/glslang/glslang/MachineIndependent/RemoveTree.h + src/glslang/glslang/MachineIndependent/ParseHelper.cpp + src/glslang/glslang/MachineIndependent/Scan.h + src/glslang/glslang/MachineIndependent/reflection.h + src/glslang/glslang/MachineIndependent/ScanContext.h + src/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp + src/glslang/glslang/OSDependent/osinclude.h + src/glslang/glslang/GenericCodeGen/Link.cpp + src/glslang/glslang/GenericCodeGen/CodeGen.cpp + src/glslang/glslang/Public/ShaderLang.h + src/glslang/glslang/Include/ConstantUnion.h + src/glslang/glslang/Include/InitializeGlobals.h + src/glslang/glslang/Include/Common.h + src/glslang/glslang/Include/PoolAlloc.h + src/glslang/glslang/Include/arrays.h + src/glslang/glslang/Include/ShHandle.h + src/glslang/glslang/Include/InfoSink.h + src/glslang/glslang/Include/ResourceLimits.h + src/glslang/glslang/Include/Types.h + src/glslang/glslang/Include/BaseTypes.h + src/glslang/glslang/Include/intermediate.h + src/glslang/glslang/Include/SpirvIntrinsics.h + src/glslang/glslang/Include/build_info.h + src/glslang/glslang/OSDependent/osinclude.h + src/glslang/spirv/Logger.h + src/glslang/spirv/GlslangToSpv.cpp + src/glslang/spirv/SPVRemapper.h + src/glslang/spirv/GLSL.ext.EXT.h + src/glslang/spirv/hex_float.h + src/glslang/spirv/doc.cpp + src/glslang/spirv/disassemble.cpp + src/glslang/spirv/SpvPostProcess.cpp + src/glslang/spirv/bitutils.h + src/glslang/spirv/InReadableOrder.cpp + src/glslang/spirv/GLSL.ext.AMD.h + src/glslang/spirv/GLSL.ext.NV.h + src/glslang/spirv/SPVRemapper.cpp + src/glslang/spirv/SpvBuilder.h + src/glslang/spirv/GLSL.ext.KHR.h + src/glslang/spirv/disassemble.h + src/glslang/spirv/SpvBuilder.cpp + src/glslang/spirv/GlslangToSpv.h + src/glslang/spirv/doc.h + src/glslang/spirv/SpvTools.cpp + src/glslang/spirv/spvIR.h + src/glslang/spirv/Logger.cpp + src/glslang/spirv/SpvTools.h + src/glslang/spirv/GLSL.std.450.h + src/glslang/spirv/NonSemanticDebugPrintf.h + src/glslang/OGLCompilersDLL/InitializeDll.cpp + src/glslang/OGLCompilersDLL/InitializeDll.h +) + +set(ZVULKAN_INCLUDES + include/zvulkan/vulkanbuilders.h + include/zvulkan/vulkancompatibledevice.h + include/zvulkan/vulkandevice.h + include/zvulkan/vulkaninstance.h + include/zvulkan/vulkanobjects.h + include/zvulkan/vulkansurface.h + include/zvulkan/vulkanswapchain.h + include/zvulkan/volk/volk.h + include/zvulkan/vk_mem_alloc/vk_mem_alloc.h +) + +set(ZVULKAN_WIN32_SOURCES + src/glslang/glslang/OSDependent/Windows/ossource.cpp +) + +set(ZVULKAN_UNIX_SOURCES + src/glslang/glslang/OSDependent/Unix/ossource.cpp +) + +set(VULKAN_INCLUDES + include/vulkan/vk_enum_string_helper.h + include/vulkan/vk_icd.h + include/vulkan/vk_layer.h + include/vulkan/vk_layer_dispatch_table.h + include/vulkan/vk_platform.h + include/vulkan/vk_sdk_platform.h + include/vulkan/vulkan.h + include/vulkan/vulkan_android.h + include/vulkan/vulkan_beta.h + include/vulkan/vulkan_core.h + include/vulkan/vulkan_directfb.h + include/vulkan/vulkan_fuchsia.h + include/vulkan/vulkan_ggp.h + include/vulkan/vulkan_ios.h + include/vulkan/vulkan_macos.h + include/vulkan/vulkan_metal.h + include/vulkan/vulkan_mir.h + include/vulkan/vulkan_screen.h + include/vulkan/vulkan_vi.h + include/vulkan/vulkan_wayland.h + include/vulkan/vulkan_win32.h + include/vulkan/vulkan_xcb.h + include/vulkan/vulkan_xlib.h + include/vulkan/vulkan_xlib_xrandr.h +) + +source_group("src" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/.+") +source_group("src\\glslang" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/.+") +source_group("src\\glslang\\glslang" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/.+") +source_group("src\\glslang\\glslang\\GenericCodeGen" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/GenericCodeGen/.+") +source_group("src\\glslang\\glslang\\Include" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/Include/.+") +source_group("src\\glslang\\glslang\\MachineIndependent" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/MachineIndependent/.+") +source_group("src\\glslang\\glslang\\MachineIndependent\\preprocessor" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/MachineIndependent/preprocessor/.+") +source_group("src\\glslang\\glslang\\OSDependent" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/OSDependent/.+") +source_group("src\\glslang\\glslang\\OSDependent\\Unix" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/OSDependent/Unix/.+") +source_group("src\\glslang\\glslang\\OSDependent\\Web" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/OSDependent/Web/.+") +source_group("src\\glslang\\glslang\\OSDependent\\Windows" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/OSDependent/Windows/.+") +source_group("src\\glslang\\glslang\\Public" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/glslang/Public/.+") +source_group("src\\glslang\\OGLCompilersDLL" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/OGLCompilersDLL/.+") +source_group("src\\glslang\\spirv" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/glslang/spirv/.+") +source_group("src\\vk_mem_alloc" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/vk_mem_alloc/.+") +source_group("src\\volk" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/volk/.+") +source_group("include" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zvulkan/.+") +source_group("include\\vk_mem_alloc" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zvulkan/vk_mem_alloc/.+") +source_group("include\\volk" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zvulkan/volk/.+") + +include_directories(include include/zvulkan src) + +if(WIN32) + set(ZVULKAN_SOURCES ${ZVULKAN_SOURCES} ${ZVULKAN_WIN32_SOURCES}) + add_definitions(-DUNICODE -D_UNICODE) +else() + set(ZVULKAN_SOURCES ${ZVULKAN_SOURCES} ${ZVULKAN_UNIX_SOURCES}) + set(ZVULKAN_LIBS ${CMAKE_DL_LIBS} -ldl) + add_definitions(-DUNIX -D_UNIX) + add_link_options(-pthread) +endif() + +if(MSVC) + # Use all cores for compilation + set(CMAKE_CXX_FLAGS "/MP ${CMAKE_CXX_FLAGS}") + + # Ignore warnings in third party code + #set_source_files_properties(${ZVULKAN_SOURCES} PROPERTIES COMPILE_FLAGS "/wd4244 /wd4267 /wd4005 /wd4018 -D_CRT_SECURE_NO_WARNINGS") +endif() + +add_library(zvulkan STATIC ${ZVULKAN_SOURCES} ${ZVULKAN_INCLUDES} ${VULKAN_INCLUDES}) +target_link_libraries(zvulkan ${ZVULKAN_LIBS}) +set_target_properties(zvulkan PROPERTIES CXX_STANDARD 17) + +if(MSVC) + set_property(TARGET zvulkan PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +endif() diff --git a/libraries/ZVulkan/LICENSE.md b/libraries/ZVulkan/LICENSE.md new file mode 100644 index 00000000000..6685241c006 --- /dev/null +++ b/libraries/ZVulkan/LICENSE.md @@ -0,0 +1,90 @@ +# License information + +## License for ZVulkan itself + + // Copyright (c) 2016-2022 Magnus Norddahl + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + +## License for src/vk_mem_alloc + + // Copyright (c) 2017-2018 Advanced Micro Devices, Inc. All rights reserved. + // + // 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. + // + +## License for src/volk + + /** + * Copyright (c) 2018-2019 Arseny Kapoulkine + * + * 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. + */ + +## License for include/zvulkan/vulkan + + /* + ** Copyright (c) 2015-2019 The Khronos Group Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +## License for src/glslang + + See src/glslang/LICENSE.txt diff --git a/libraries/ZVulkan/README.md b/libraries/ZVulkan/README.md new file mode 100644 index 00000000000..391082b5c12 --- /dev/null +++ b/libraries/ZVulkan/README.md @@ -0,0 +1,2 @@ +# ZVulkan +A framework for building vulkan applications diff --git a/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std.h b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std.h new file mode 100644 index 00000000000..ef7eaf745e5 --- /dev/null +++ b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std.h @@ -0,0 +1,312 @@ +#ifndef VULKAN_VIDEO_CODEC_H264STD_H_ +#define VULKAN_VIDEO_CODEC_H264STD_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h264std is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h264std 1 +#include "vulkan_video_codecs_common.h" +#define STD_VIDEO_H264_CPB_CNT_LIST_SIZE 32 +#define STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS 6 +#define STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS 16 +#define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS 6 +#define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS 64 +#define STD_VIDEO_H264_MAX_NUM_LIST_REF 32 +#define STD_VIDEO_H264_MAX_CHROMA_PLANES 2 +#define STD_VIDEO_H264_NO_REFERENCE_PICTURE 0xFF + +typedef enum StdVideoH264ChromaFormatIdc { + STD_VIDEO_H264_CHROMA_FORMAT_IDC_MONOCHROME = 0, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_420 = 1, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_422 = 2, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_444 = 3, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264ChromaFormatIdc; + +typedef enum StdVideoH264ProfileIdc { + STD_VIDEO_H264_PROFILE_IDC_BASELINE = 66, + STD_VIDEO_H264_PROFILE_IDC_MAIN = 77, + STD_VIDEO_H264_PROFILE_IDC_HIGH = 100, + STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE = 244, + STD_VIDEO_H264_PROFILE_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_PROFILE_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264ProfileIdc; + +typedef enum StdVideoH264LevelIdc { + STD_VIDEO_H264_LEVEL_IDC_1_0 = 0, + STD_VIDEO_H264_LEVEL_IDC_1_1 = 1, + STD_VIDEO_H264_LEVEL_IDC_1_2 = 2, + STD_VIDEO_H264_LEVEL_IDC_1_3 = 3, + STD_VIDEO_H264_LEVEL_IDC_2_0 = 4, + STD_VIDEO_H264_LEVEL_IDC_2_1 = 5, + STD_VIDEO_H264_LEVEL_IDC_2_2 = 6, + STD_VIDEO_H264_LEVEL_IDC_3_0 = 7, + STD_VIDEO_H264_LEVEL_IDC_3_1 = 8, + STD_VIDEO_H264_LEVEL_IDC_3_2 = 9, + STD_VIDEO_H264_LEVEL_IDC_4_0 = 10, + STD_VIDEO_H264_LEVEL_IDC_4_1 = 11, + STD_VIDEO_H264_LEVEL_IDC_4_2 = 12, + STD_VIDEO_H264_LEVEL_IDC_5_0 = 13, + STD_VIDEO_H264_LEVEL_IDC_5_1 = 14, + STD_VIDEO_H264_LEVEL_IDC_5_2 = 15, + STD_VIDEO_H264_LEVEL_IDC_6_0 = 16, + STD_VIDEO_H264_LEVEL_IDC_6_1 = 17, + STD_VIDEO_H264_LEVEL_IDC_6_2 = 18, + STD_VIDEO_H264_LEVEL_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_LEVEL_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264LevelIdc; + +typedef enum StdVideoH264PocType { + STD_VIDEO_H264_POC_TYPE_0 = 0, + STD_VIDEO_H264_POC_TYPE_1 = 1, + STD_VIDEO_H264_POC_TYPE_2 = 2, + STD_VIDEO_H264_POC_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_POC_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264PocType; + +typedef enum StdVideoH264AspectRatioIdc { + STD_VIDEO_H264_ASPECT_RATIO_IDC_UNSPECIFIED = 0, + STD_VIDEO_H264_ASPECT_RATIO_IDC_SQUARE = 1, + STD_VIDEO_H264_ASPECT_RATIO_IDC_12_11 = 2, + STD_VIDEO_H264_ASPECT_RATIO_IDC_10_11 = 3, + STD_VIDEO_H264_ASPECT_RATIO_IDC_16_11 = 4, + STD_VIDEO_H264_ASPECT_RATIO_IDC_40_33 = 5, + STD_VIDEO_H264_ASPECT_RATIO_IDC_24_11 = 6, + STD_VIDEO_H264_ASPECT_RATIO_IDC_20_11 = 7, + STD_VIDEO_H264_ASPECT_RATIO_IDC_32_11 = 8, + STD_VIDEO_H264_ASPECT_RATIO_IDC_80_33 = 9, + STD_VIDEO_H264_ASPECT_RATIO_IDC_18_11 = 10, + STD_VIDEO_H264_ASPECT_RATIO_IDC_15_11 = 11, + STD_VIDEO_H264_ASPECT_RATIO_IDC_64_33 = 12, + STD_VIDEO_H264_ASPECT_RATIO_IDC_160_99 = 13, + STD_VIDEO_H264_ASPECT_RATIO_IDC_4_3 = 14, + STD_VIDEO_H264_ASPECT_RATIO_IDC_3_2 = 15, + STD_VIDEO_H264_ASPECT_RATIO_IDC_2_1 = 16, + STD_VIDEO_H264_ASPECT_RATIO_IDC_EXTENDED_SAR = 255, + STD_VIDEO_H264_ASPECT_RATIO_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_ASPECT_RATIO_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264AspectRatioIdc; + +typedef enum StdVideoH264WeightedBipredIdc { + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_DEFAULT = 0, + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_EXPLICIT = 1, + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_IMPLICIT = 2, + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264WeightedBipredIdc; + +typedef enum StdVideoH264ModificationOfPicNumsIdc { + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_SUBTRACT = 0, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_ADD = 1, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_LONG_TERM = 2, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_END = 3, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264ModificationOfPicNumsIdc; + +typedef enum StdVideoH264MemMgmtControlOp { + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_END = 0, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_SHORT_TERM = 1, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_LONG_TERM = 2, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_LONG_TERM = 3, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_SET_MAX_LONG_TERM_INDEX = 4, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_ALL = 5, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_CURRENT_AS_LONG_TERM = 6, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264MemMgmtControlOp; + +typedef enum StdVideoH264CabacInitIdc { + STD_VIDEO_H264_CABAC_INIT_IDC_0 = 0, + STD_VIDEO_H264_CABAC_INIT_IDC_1 = 1, + STD_VIDEO_H264_CABAC_INIT_IDC_2 = 2, + STD_VIDEO_H264_CABAC_INIT_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_CABAC_INIT_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264CabacInitIdc; + +typedef enum StdVideoH264DisableDeblockingFilterIdc { + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_DISABLED = 0, + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_ENABLED = 1, + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_PARTIAL = 2, + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264DisableDeblockingFilterIdc; + +typedef enum StdVideoH264SliceType { + STD_VIDEO_H264_SLICE_TYPE_P = 0, + STD_VIDEO_H264_SLICE_TYPE_B = 1, + STD_VIDEO_H264_SLICE_TYPE_I = 2, + STD_VIDEO_H264_SLICE_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_SLICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264SliceType; + +typedef enum StdVideoH264PictureType { + STD_VIDEO_H264_PICTURE_TYPE_P = 0, + STD_VIDEO_H264_PICTURE_TYPE_B = 1, + STD_VIDEO_H264_PICTURE_TYPE_I = 2, + STD_VIDEO_H264_PICTURE_TYPE_IDR = 5, + STD_VIDEO_H264_PICTURE_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_PICTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264PictureType; + +typedef enum StdVideoH264NonVclNaluType { + STD_VIDEO_H264_NON_VCL_NALU_TYPE_SPS = 0, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_PPS = 1, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_AUD = 2, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_PREFIX = 3, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_END_OF_SEQUENCE = 4, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_END_OF_STREAM = 5, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_PRECODED = 6, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264NonVclNaluType; +typedef struct StdVideoH264SpsVuiFlags { + uint32_t aspect_ratio_info_present_flag : 1; + uint32_t overscan_info_present_flag : 1; + uint32_t overscan_appropriate_flag : 1; + uint32_t video_signal_type_present_flag : 1; + uint32_t video_full_range_flag : 1; + uint32_t color_description_present_flag : 1; + uint32_t chroma_loc_info_present_flag : 1; + uint32_t timing_info_present_flag : 1; + uint32_t fixed_frame_rate_flag : 1; + uint32_t bitstream_restriction_flag : 1; + uint32_t nal_hrd_parameters_present_flag : 1; + uint32_t vcl_hrd_parameters_present_flag : 1; +} StdVideoH264SpsVuiFlags; + +typedef struct StdVideoH264HrdParameters { + uint8_t cpb_cnt_minus1; + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + uint8_t reserved1; + uint32_t bit_rate_value_minus1[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; + uint32_t cpb_size_value_minus1[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; + uint8_t cbr_flag[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; + uint32_t initial_cpb_removal_delay_length_minus1; + uint32_t cpb_removal_delay_length_minus1; + uint32_t dpb_output_delay_length_minus1; + uint32_t time_offset_length; +} StdVideoH264HrdParameters; + +typedef struct StdVideoH264SequenceParameterSetVui { + StdVideoH264SpsVuiFlags flags; + StdVideoH264AspectRatioIdc aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + uint8_t video_format; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + uint32_t num_units_in_tick; + uint32_t time_scale; + uint8_t max_num_reorder_frames; + uint8_t max_dec_frame_buffering; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + uint32_t reserved1; + const StdVideoH264HrdParameters* pHrdParameters; +} StdVideoH264SequenceParameterSetVui; + +typedef struct StdVideoH264SpsFlags { + uint32_t constraint_set0_flag : 1; + uint32_t constraint_set1_flag : 1; + uint32_t constraint_set2_flag : 1; + uint32_t constraint_set3_flag : 1; + uint32_t constraint_set4_flag : 1; + uint32_t constraint_set5_flag : 1; + uint32_t direct_8x8_inference_flag : 1; + uint32_t mb_adaptive_frame_field_flag : 1; + uint32_t frame_mbs_only_flag : 1; + uint32_t delta_pic_order_always_zero_flag : 1; + uint32_t separate_colour_plane_flag : 1; + uint32_t gaps_in_frame_num_value_allowed_flag : 1; + uint32_t qpprime_y_zero_transform_bypass_flag : 1; + uint32_t frame_cropping_flag : 1; + uint32_t seq_scaling_matrix_present_flag : 1; + uint32_t vui_parameters_present_flag : 1; +} StdVideoH264SpsFlags; + +typedef struct StdVideoH264ScalingLists { + uint16_t scaling_list_present_mask; + uint16_t use_default_scaling_matrix_mask; + uint8_t ScalingList4x4[STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS][STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS]; + uint8_t ScalingList8x8[STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS][STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS]; +} StdVideoH264ScalingLists; + +typedef struct StdVideoH264SequenceParameterSet { + StdVideoH264SpsFlags flags; + StdVideoH264ProfileIdc profile_idc; + StdVideoH264LevelIdc level_idc; + StdVideoH264ChromaFormatIdc chroma_format_idc; + uint8_t seq_parameter_set_id; + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + uint8_t log2_max_frame_num_minus4; + StdVideoH264PocType pic_order_cnt_type; + int32_t offset_for_non_ref_pic; + int32_t offset_for_top_to_bottom_field; + uint8_t log2_max_pic_order_cnt_lsb_minus4; + uint8_t num_ref_frames_in_pic_order_cnt_cycle; + uint8_t max_num_ref_frames; + uint8_t reserved1; + uint32_t pic_width_in_mbs_minus1; + uint32_t pic_height_in_map_units_minus1; + uint32_t frame_crop_left_offset; + uint32_t frame_crop_right_offset; + uint32_t frame_crop_top_offset; + uint32_t frame_crop_bottom_offset; + uint32_t reserved2; + const int32_t* pOffsetForRefFrame; + const StdVideoH264ScalingLists* pScalingLists; + const StdVideoH264SequenceParameterSetVui* pSequenceParameterSetVui; +} StdVideoH264SequenceParameterSet; + +typedef struct StdVideoH264PpsFlags { + uint32_t transform_8x8_mode_flag : 1; + uint32_t redundant_pic_cnt_present_flag : 1; + uint32_t constrained_intra_pred_flag : 1; + uint32_t deblocking_filter_control_present_flag : 1; + uint32_t weighted_pred_flag : 1; + uint32_t bottom_field_pic_order_in_frame_present_flag : 1; + uint32_t entropy_coding_mode_flag : 1; + uint32_t pic_scaling_matrix_present_flag : 1; +} StdVideoH264PpsFlags; + +typedef struct StdVideoH264PictureParameterSet { + StdVideoH264PpsFlags flags; + uint8_t seq_parameter_set_id; + uint8_t pic_parameter_set_id; + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + StdVideoH264WeightedBipredIdc weighted_bipred_idc; + int8_t pic_init_qp_minus26; + int8_t pic_init_qs_minus26; + int8_t chroma_qp_index_offset; + int8_t second_chroma_qp_index_offset; + const StdVideoH264ScalingLists* pScalingLists; +} StdVideoH264PictureParameterSet; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std_decode.h b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std_decode.h new file mode 100644 index 00000000000..dd24112e2cf --- /dev/null +++ b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std_decode.h @@ -0,0 +1,77 @@ +#ifndef VULKAN_VIDEO_CODEC_H264STD_DECODE_H_ +#define VULKAN_VIDEO_CODEC_H264STD_DECODE_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h264std_decode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h264std_decode 1 +#include "vulkan_video_codec_h264std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_decode" +#define STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE 2 + +typedef enum StdVideoDecodeH264FieldOrderCount { + STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_TOP = 0, + STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_BOTTOM = 1, + STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_INVALID = 0x7FFFFFFF, + STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_MAX_ENUM = 0x7FFFFFFF +} StdVideoDecodeH264FieldOrderCount; +typedef struct StdVideoDecodeH264PictureInfoFlags { + uint32_t field_pic_flag : 1; + uint32_t is_intra : 1; + uint32_t IdrPicFlag : 1; + uint32_t bottom_field_flag : 1; + uint32_t is_reference : 1; + uint32_t complementary_field_pair : 1; +} StdVideoDecodeH264PictureInfoFlags; + +typedef struct StdVideoDecodeH264PictureInfo { + StdVideoDecodeH264PictureInfoFlags flags; + uint8_t seq_parameter_set_id; + uint8_t pic_parameter_set_id; + uint8_t reserved1; + uint8_t reserved2; + uint16_t frame_num; + uint16_t idr_pic_id; + int32_t PicOrderCnt[STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE]; +} StdVideoDecodeH264PictureInfo; + +typedef struct StdVideoDecodeH264ReferenceInfoFlags { + uint32_t top_field_flag : 1; + uint32_t bottom_field_flag : 1; + uint32_t used_for_long_term_reference : 1; + uint32_t is_non_existing : 1; +} StdVideoDecodeH264ReferenceInfoFlags; + +typedef struct StdVideoDecodeH264ReferenceInfo { + StdVideoDecodeH264ReferenceInfoFlags flags; + uint16_t FrameNum; + uint16_t reserved; + int32_t PicOrderCnt[STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE]; +} StdVideoDecodeH264ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std_encode.h b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std_encode.h new file mode 100644 index 00000000000..58b8bdb2f6e --- /dev/null +++ b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h264std_encode.h @@ -0,0 +1,147 @@ +#ifndef VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_ +#define VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h264std_encode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h264std_encode 1 +#include "vulkan_video_codec_h264std.h" +// Vulkan 0.9 provisional Vulkan video H.264 encode std specification version number +#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_0_9_11 VK_MAKE_VIDEO_STD_VERSION(0, 9, 11) + +#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_0_9_11 +#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_encode" +typedef struct StdVideoEncodeH264WeightTableFlags { + uint32_t luma_weight_l0_flag; + uint32_t chroma_weight_l0_flag; + uint32_t luma_weight_l1_flag; + uint32_t chroma_weight_l1_flag; +} StdVideoEncodeH264WeightTableFlags; + +typedef struct StdVideoEncodeH264WeightTable { + StdVideoEncodeH264WeightTableFlags flags; + uint8_t luma_log2_weight_denom; + uint8_t chroma_log2_weight_denom; + int8_t luma_weight_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + int8_t luma_offset_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + int8_t chroma_weight_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; + int8_t chroma_offset_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; + int8_t luma_weight_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + int8_t luma_offset_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + int8_t chroma_weight_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; + int8_t chroma_offset_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; +} StdVideoEncodeH264WeightTable; + +typedef struct StdVideoEncodeH264SliceHeaderFlags { + uint32_t direct_spatial_mv_pred_flag : 1; + uint32_t num_ref_idx_active_override_flag : 1; + uint32_t reserved : 30; +} StdVideoEncodeH264SliceHeaderFlags; + +typedef struct StdVideoEncodeH264PictureInfoFlags { + uint32_t IdrPicFlag : 1; + uint32_t is_reference : 1; + uint32_t no_output_of_prior_pics_flag : 1; + uint32_t long_term_reference_flag : 1; + uint32_t adaptive_ref_pic_marking_mode_flag : 1; + uint32_t reserved : 27; +} StdVideoEncodeH264PictureInfoFlags; + +typedef struct StdVideoEncodeH264ReferenceInfoFlags { + uint32_t used_for_long_term_reference : 1; + uint32_t reserved : 31; +} StdVideoEncodeH264ReferenceInfoFlags; + +typedef struct StdVideoEncodeH264ReferenceListsInfoFlags { + uint32_t ref_pic_list_modification_flag_l0 : 1; + uint32_t ref_pic_list_modification_flag_l1 : 1; + uint32_t reserved : 30; +} StdVideoEncodeH264ReferenceListsInfoFlags; + +typedef struct StdVideoEncodeH264RefListModEntry { + StdVideoH264ModificationOfPicNumsIdc modification_of_pic_nums_idc; + uint16_t abs_diff_pic_num_minus1; + uint16_t long_term_pic_num; +} StdVideoEncodeH264RefListModEntry; + +typedef struct StdVideoEncodeH264RefPicMarkingEntry { + StdVideoH264MemMgmtControlOp memory_management_control_operation; + uint16_t difference_of_pic_nums_minus1; + uint16_t long_term_pic_num; + uint16_t long_term_frame_idx; + uint16_t max_long_term_frame_idx_plus1; +} StdVideoEncodeH264RefPicMarkingEntry; + +typedef struct StdVideoEncodeH264ReferenceListsInfo { + StdVideoEncodeH264ReferenceListsInfoFlags flags; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + uint8_t RefPicList0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + uint8_t RefPicList1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + uint8_t refList0ModOpCount; + uint8_t refList1ModOpCount; + uint8_t refPicMarkingOpCount; + uint8_t reserved1[7]; + const StdVideoEncodeH264RefListModEntry* pRefList0ModOperations; + const StdVideoEncodeH264RefListModEntry* pRefList1ModOperations; + const StdVideoEncodeH264RefPicMarkingEntry* pRefPicMarkingOperations; +} StdVideoEncodeH264ReferenceListsInfo; + +typedef struct StdVideoEncodeH264PictureInfo { + StdVideoEncodeH264PictureInfoFlags flags; + uint8_t seq_parameter_set_id; + uint8_t pic_parameter_set_id; + uint16_t idr_pic_id; + StdVideoH264PictureType primary_pic_type; + uint32_t frame_num; + int32_t PicOrderCnt; + uint8_t temporal_id; + uint8_t reserved1[3]; + const StdVideoEncodeH264ReferenceListsInfo* pRefLists; +} StdVideoEncodeH264PictureInfo; + +typedef struct StdVideoEncodeH264ReferenceInfo { + StdVideoEncodeH264ReferenceInfoFlags flags; + StdVideoH264PictureType primary_pic_type; + uint32_t FrameNum; + int32_t PicOrderCnt; + uint16_t long_term_pic_num; + uint16_t long_term_frame_idx; + uint8_t temporal_id; +} StdVideoEncodeH264ReferenceInfo; + +typedef struct StdVideoEncodeH264SliceHeader { + StdVideoEncodeH264SliceHeaderFlags flags; + uint32_t first_mb_in_slice; + StdVideoH264SliceType slice_type; + int8_t slice_alpha_c0_offset_div2; + int8_t slice_beta_offset_div2; + int8_t slice_qp_delta; + uint8_t reserved1; + StdVideoH264CabacInitIdc cabac_init_idc; + StdVideoH264DisableDeblockingFilterIdc disable_deblocking_filter_idc; + const StdVideoEncodeH264WeightTable* pWeightTable; +} StdVideoEncodeH264SliceHeader; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std.h b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std.h new file mode 100644 index 00000000000..ff5d0dacbf6 --- /dev/null +++ b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std.h @@ -0,0 +1,446 @@ +#ifndef VULKAN_VIDEO_CODEC_H265STD_H_ +#define VULKAN_VIDEO_CODEC_H265STD_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h265std is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h265std 1 +#include "vulkan_video_codecs_common.h" +#define STD_VIDEO_H265_CPB_CNT_LIST_SIZE 32 +#define STD_VIDEO_H265_SUBLAYERS_LIST_SIZE 7 +#define STD_VIDEO_H265_SCALING_LIST_4X4_NUM_LISTS 6 +#define STD_VIDEO_H265_SCALING_LIST_4X4_NUM_ELEMENTS 16 +#define STD_VIDEO_H265_SCALING_LIST_8X8_NUM_LISTS 6 +#define STD_VIDEO_H265_SCALING_LIST_8X8_NUM_ELEMENTS 64 +#define STD_VIDEO_H265_SCALING_LIST_16X16_NUM_LISTS 6 +#define STD_VIDEO_H265_SCALING_LIST_16X16_NUM_ELEMENTS 64 +#define STD_VIDEO_H265_SCALING_LIST_32X32_NUM_LISTS 2 +#define STD_VIDEO_H265_SCALING_LIST_32X32_NUM_ELEMENTS 64 +#define STD_VIDEO_H265_CHROMA_QP_OFFSET_LIST_SIZE 6 +#define STD_VIDEO_H265_CHROMA_QP_OFFSET_TILE_COLS_LIST_SIZE 19 +#define STD_VIDEO_H265_CHROMA_QP_OFFSET_TILE_ROWS_LIST_SIZE 21 +#define STD_VIDEO_H265_PREDICTOR_PALETTE_COMPONENTS_LIST_SIZE 3 +#define STD_VIDEO_H265_PREDICTOR_PALETTE_COMP_ENTRIES_LIST_SIZE 128 +#define STD_VIDEO_H265_MAX_NUM_LIST_REF 15 +#define STD_VIDEO_H265_MAX_CHROMA_PLANES 2 +#define STD_VIDEO_H265_MAX_SHORT_TERM_REF_PIC_SETS 64 +#define STD_VIDEO_H265_MAX_DPB_SIZE 16 +#define STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS 32 +#define STD_VIDEO_H265_MAX_LONG_TERM_PICS 16 +#define STD_VIDEO_H265_MAX_DELTA_POC 48 +#define STD_VIDEO_H265_NO_REFERENCE_PICTURE 0xFF + +typedef enum StdVideoH265ChromaFormatIdc { + STD_VIDEO_H265_CHROMA_FORMAT_IDC_MONOCHROME = 0, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_420 = 1, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_422 = 2, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_444 = 3, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265ChromaFormatIdc; + +typedef enum StdVideoH265ProfileIdc { + STD_VIDEO_H265_PROFILE_IDC_MAIN = 1, + STD_VIDEO_H265_PROFILE_IDC_MAIN_10 = 2, + STD_VIDEO_H265_PROFILE_IDC_MAIN_STILL_PICTURE = 3, + STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS = 4, + STD_VIDEO_H265_PROFILE_IDC_SCC_EXTENSIONS = 9, + STD_VIDEO_H265_PROFILE_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_PROFILE_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265ProfileIdc; + +typedef enum StdVideoH265LevelIdc { + STD_VIDEO_H265_LEVEL_IDC_1_0 = 0, + STD_VIDEO_H265_LEVEL_IDC_2_0 = 1, + STD_VIDEO_H265_LEVEL_IDC_2_1 = 2, + STD_VIDEO_H265_LEVEL_IDC_3_0 = 3, + STD_VIDEO_H265_LEVEL_IDC_3_1 = 4, + STD_VIDEO_H265_LEVEL_IDC_4_0 = 5, + STD_VIDEO_H265_LEVEL_IDC_4_1 = 6, + STD_VIDEO_H265_LEVEL_IDC_5_0 = 7, + STD_VIDEO_H265_LEVEL_IDC_5_1 = 8, + STD_VIDEO_H265_LEVEL_IDC_5_2 = 9, + STD_VIDEO_H265_LEVEL_IDC_6_0 = 10, + STD_VIDEO_H265_LEVEL_IDC_6_1 = 11, + STD_VIDEO_H265_LEVEL_IDC_6_2 = 12, + STD_VIDEO_H265_LEVEL_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_LEVEL_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265LevelIdc; + +typedef enum StdVideoH265SliceType { + STD_VIDEO_H265_SLICE_TYPE_B = 0, + STD_VIDEO_H265_SLICE_TYPE_P = 1, + STD_VIDEO_H265_SLICE_TYPE_I = 2, + STD_VIDEO_H265_SLICE_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_SLICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265SliceType; + +typedef enum StdVideoH265PictureType { + STD_VIDEO_H265_PICTURE_TYPE_P = 0, + STD_VIDEO_H265_PICTURE_TYPE_B = 1, + STD_VIDEO_H265_PICTURE_TYPE_I = 2, + STD_VIDEO_H265_PICTURE_TYPE_IDR = 3, + STD_VIDEO_H265_PICTURE_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_PICTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265PictureType; + +typedef enum StdVideoH265AspectRatioIdc { + STD_VIDEO_H265_ASPECT_RATIO_IDC_UNSPECIFIED = 0, + STD_VIDEO_H265_ASPECT_RATIO_IDC_SQUARE = 1, + STD_VIDEO_H265_ASPECT_RATIO_IDC_12_11 = 2, + STD_VIDEO_H265_ASPECT_RATIO_IDC_10_11 = 3, + STD_VIDEO_H265_ASPECT_RATIO_IDC_16_11 = 4, + STD_VIDEO_H265_ASPECT_RATIO_IDC_40_33 = 5, + STD_VIDEO_H265_ASPECT_RATIO_IDC_24_11 = 6, + STD_VIDEO_H265_ASPECT_RATIO_IDC_20_11 = 7, + STD_VIDEO_H265_ASPECT_RATIO_IDC_32_11 = 8, + STD_VIDEO_H265_ASPECT_RATIO_IDC_80_33 = 9, + STD_VIDEO_H265_ASPECT_RATIO_IDC_18_11 = 10, + STD_VIDEO_H265_ASPECT_RATIO_IDC_15_11 = 11, + STD_VIDEO_H265_ASPECT_RATIO_IDC_64_33 = 12, + STD_VIDEO_H265_ASPECT_RATIO_IDC_160_99 = 13, + STD_VIDEO_H265_ASPECT_RATIO_IDC_4_3 = 14, + STD_VIDEO_H265_ASPECT_RATIO_IDC_3_2 = 15, + STD_VIDEO_H265_ASPECT_RATIO_IDC_2_1 = 16, + STD_VIDEO_H265_ASPECT_RATIO_IDC_EXTENDED_SAR = 255, + STD_VIDEO_H265_ASPECT_RATIO_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_ASPECT_RATIO_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265AspectRatioIdc; +typedef struct StdVideoH265DecPicBufMgr { + uint32_t max_latency_increase_plus1[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + uint8_t max_dec_pic_buffering_minus1[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + uint8_t max_num_reorder_pics[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; +} StdVideoH265DecPicBufMgr; + +typedef struct StdVideoH265SubLayerHrdParameters { + uint32_t bit_rate_value_minus1[STD_VIDEO_H265_CPB_CNT_LIST_SIZE]; + uint32_t cpb_size_value_minus1[STD_VIDEO_H265_CPB_CNT_LIST_SIZE]; + uint32_t cpb_size_du_value_minus1[STD_VIDEO_H265_CPB_CNT_LIST_SIZE]; + uint32_t bit_rate_du_value_minus1[STD_VIDEO_H265_CPB_CNT_LIST_SIZE]; + uint32_t cbr_flag; +} StdVideoH265SubLayerHrdParameters; + +typedef struct StdVideoH265HrdFlags { + uint32_t nal_hrd_parameters_present_flag : 1; + uint32_t vcl_hrd_parameters_present_flag : 1; + uint32_t sub_pic_hrd_params_present_flag : 1; + uint32_t sub_pic_cpb_params_in_pic_timing_sei_flag : 1; + uint32_t fixed_pic_rate_general_flag : 8; + uint32_t fixed_pic_rate_within_cvs_flag : 8; + uint32_t low_delay_hrd_flag : 8; +} StdVideoH265HrdFlags; + +typedef struct StdVideoH265HrdParameters { + StdVideoH265HrdFlags flags; + uint8_t tick_divisor_minus2; + uint8_t du_cpb_removal_delay_increment_length_minus1; + uint8_t dpb_output_delay_du_length_minus1; + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + uint8_t cpb_size_du_scale; + uint8_t initial_cpb_removal_delay_length_minus1; + uint8_t au_cpb_removal_delay_length_minus1; + uint8_t dpb_output_delay_length_minus1; + uint8_t cpb_cnt_minus1[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + uint16_t elemental_duration_in_tc_minus1[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + uint16_t reserved[3]; + const StdVideoH265SubLayerHrdParameters* pSubLayerHrdParametersNal; + const StdVideoH265SubLayerHrdParameters* pSubLayerHrdParametersVcl; +} StdVideoH265HrdParameters; + +typedef struct StdVideoH265VpsFlags { + uint32_t vps_temporal_id_nesting_flag : 1; + uint32_t vps_sub_layer_ordering_info_present_flag : 1; + uint32_t vps_timing_info_present_flag : 1; + uint32_t vps_poc_proportional_to_timing_flag : 1; +} StdVideoH265VpsFlags; + +typedef struct StdVideoH265ProfileTierLevelFlags { + uint32_t general_tier_flag : 1; + uint32_t general_progressive_source_flag : 1; + uint32_t general_interlaced_source_flag : 1; + uint32_t general_non_packed_constraint_flag : 1; + uint32_t general_frame_only_constraint_flag : 1; +} StdVideoH265ProfileTierLevelFlags; + +typedef struct StdVideoH265ProfileTierLevel { + StdVideoH265ProfileTierLevelFlags flags; + StdVideoH265ProfileIdc general_profile_idc; + StdVideoH265LevelIdc general_level_idc; +} StdVideoH265ProfileTierLevel; + +typedef struct StdVideoH265VideoParameterSet { + StdVideoH265VpsFlags flags; + uint8_t vps_video_parameter_set_id; + uint8_t vps_max_sub_layers_minus1; + uint8_t reserved1; + uint8_t reserved2; + uint32_t vps_num_units_in_tick; + uint32_t vps_time_scale; + uint32_t vps_num_ticks_poc_diff_one_minus1; + uint32_t reserved3; + const StdVideoH265DecPicBufMgr* pDecPicBufMgr; + const StdVideoH265HrdParameters* pHrdParameters; + const StdVideoH265ProfileTierLevel* pProfileTierLevel; +} StdVideoH265VideoParameterSet; + +typedef struct StdVideoH265ScalingLists { + uint8_t ScalingList4x4[STD_VIDEO_H265_SCALING_LIST_4X4_NUM_LISTS][STD_VIDEO_H265_SCALING_LIST_4X4_NUM_ELEMENTS]; + uint8_t ScalingList8x8[STD_VIDEO_H265_SCALING_LIST_8X8_NUM_LISTS][STD_VIDEO_H265_SCALING_LIST_8X8_NUM_ELEMENTS]; + uint8_t ScalingList16x16[STD_VIDEO_H265_SCALING_LIST_16X16_NUM_LISTS][STD_VIDEO_H265_SCALING_LIST_16X16_NUM_ELEMENTS]; + uint8_t ScalingList32x32[STD_VIDEO_H265_SCALING_LIST_32X32_NUM_LISTS][STD_VIDEO_H265_SCALING_LIST_32X32_NUM_ELEMENTS]; + uint8_t ScalingListDCCoef16x16[STD_VIDEO_H265_SCALING_LIST_16X16_NUM_LISTS]; + uint8_t ScalingListDCCoef32x32[STD_VIDEO_H265_SCALING_LIST_32X32_NUM_LISTS]; +} StdVideoH265ScalingLists; + +typedef struct StdVideoH265SpsVuiFlags { + uint32_t aspect_ratio_info_present_flag : 1; + uint32_t overscan_info_present_flag : 1; + uint32_t overscan_appropriate_flag : 1; + uint32_t video_signal_type_present_flag : 1; + uint32_t video_full_range_flag : 1; + uint32_t colour_description_present_flag : 1; + uint32_t chroma_loc_info_present_flag : 1; + uint32_t neutral_chroma_indication_flag : 1; + uint32_t field_seq_flag : 1; + uint32_t frame_field_info_present_flag : 1; + uint32_t default_display_window_flag : 1; + uint32_t vui_timing_info_present_flag : 1; + uint32_t vui_poc_proportional_to_timing_flag : 1; + uint32_t vui_hrd_parameters_present_flag : 1; + uint32_t bitstream_restriction_flag : 1; + uint32_t tiles_fixed_structure_flag : 1; + uint32_t motion_vectors_over_pic_boundaries_flag : 1; + uint32_t restricted_ref_pic_lists_flag : 1; +} StdVideoH265SpsVuiFlags; + +typedef struct StdVideoH265SequenceParameterSetVui { + StdVideoH265SpsVuiFlags flags; + StdVideoH265AspectRatioIdc aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + uint8_t video_format; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coeffs; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + uint8_t reserved1; + uint8_t reserved2; + uint16_t def_disp_win_left_offset; + uint16_t def_disp_win_right_offset; + uint16_t def_disp_win_top_offset; + uint16_t def_disp_win_bottom_offset; + uint32_t vui_num_units_in_tick; + uint32_t vui_time_scale; + uint32_t vui_num_ticks_poc_diff_one_minus1; + uint16_t min_spatial_segmentation_idc; + uint16_t reserved3; + uint8_t max_bytes_per_pic_denom; + uint8_t max_bits_per_min_cu_denom; + uint8_t log2_max_mv_length_horizontal; + uint8_t log2_max_mv_length_vertical; + const StdVideoH265HrdParameters* pHrdParameters; +} StdVideoH265SequenceParameterSetVui; + +typedef struct StdVideoH265PredictorPaletteEntries { + uint16_t PredictorPaletteEntries[STD_VIDEO_H265_PREDICTOR_PALETTE_COMPONENTS_LIST_SIZE][STD_VIDEO_H265_PREDICTOR_PALETTE_COMP_ENTRIES_LIST_SIZE]; +} StdVideoH265PredictorPaletteEntries; + +typedef struct StdVideoH265SpsFlags { + uint32_t sps_temporal_id_nesting_flag : 1; + uint32_t separate_colour_plane_flag : 1; + uint32_t conformance_window_flag : 1; + uint32_t sps_sub_layer_ordering_info_present_flag : 1; + uint32_t scaling_list_enabled_flag : 1; + uint32_t sps_scaling_list_data_present_flag : 1; + uint32_t amp_enabled_flag : 1; + uint32_t sample_adaptive_offset_enabled_flag : 1; + uint32_t pcm_enabled_flag : 1; + uint32_t pcm_loop_filter_disabled_flag : 1; + uint32_t long_term_ref_pics_present_flag : 1; + uint32_t sps_temporal_mvp_enabled_flag : 1; + uint32_t strong_intra_smoothing_enabled_flag : 1; + uint32_t vui_parameters_present_flag : 1; + uint32_t sps_extension_present_flag : 1; + uint32_t sps_range_extension_flag : 1; + uint32_t transform_skip_rotation_enabled_flag : 1; + uint32_t transform_skip_context_enabled_flag : 1; + uint32_t implicit_rdpcm_enabled_flag : 1; + uint32_t explicit_rdpcm_enabled_flag : 1; + uint32_t extended_precision_processing_flag : 1; + uint32_t intra_smoothing_disabled_flag : 1; + uint32_t high_precision_offsets_enabled_flag : 1; + uint32_t persistent_rice_adaptation_enabled_flag : 1; + uint32_t cabac_bypass_alignment_enabled_flag : 1; + uint32_t sps_scc_extension_flag : 1; + uint32_t sps_curr_pic_ref_enabled_flag : 1; + uint32_t palette_mode_enabled_flag : 1; + uint32_t sps_palette_predictor_initializers_present_flag : 1; + uint32_t intra_boundary_filtering_disabled_flag : 1; +} StdVideoH265SpsFlags; + +typedef struct StdVideoH265ShortTermRefPicSetFlags { + uint32_t inter_ref_pic_set_prediction_flag : 1; + uint32_t delta_rps_sign : 1; +} StdVideoH265ShortTermRefPicSetFlags; + +typedef struct StdVideoH265ShortTermRefPicSet { + StdVideoH265ShortTermRefPicSetFlags flags; + uint32_t delta_idx_minus1; + uint16_t use_delta_flag; + uint16_t abs_delta_rps_minus1; + uint16_t used_by_curr_pic_flag; + uint16_t used_by_curr_pic_s0_flag; + uint16_t used_by_curr_pic_s1_flag; + uint16_t reserved1; + uint8_t reserved2; + uint8_t reserved3; + uint8_t num_negative_pics; + uint8_t num_positive_pics; + uint16_t delta_poc_s0_minus1[STD_VIDEO_H265_MAX_DPB_SIZE]; + uint16_t delta_poc_s1_minus1[STD_VIDEO_H265_MAX_DPB_SIZE]; +} StdVideoH265ShortTermRefPicSet; + +typedef struct StdVideoH265LongTermRefPicsSps { + uint32_t used_by_curr_pic_lt_sps_flag; + uint32_t lt_ref_pic_poc_lsb_sps[STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS]; +} StdVideoH265LongTermRefPicsSps; + +typedef struct StdVideoH265SequenceParameterSet { + StdVideoH265SpsFlags flags; + StdVideoH265ChromaFormatIdc chroma_format_idc; + uint32_t pic_width_in_luma_samples; + uint32_t pic_height_in_luma_samples; + uint8_t sps_video_parameter_set_id; + uint8_t sps_max_sub_layers_minus1; + uint8_t sps_seq_parameter_set_id; + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + uint8_t log2_max_pic_order_cnt_lsb_minus4; + uint8_t log2_min_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_luma_coding_block_size; + uint8_t log2_min_luma_transform_block_size_minus2; + uint8_t log2_diff_max_min_luma_transform_block_size; + uint8_t max_transform_hierarchy_depth_inter; + uint8_t max_transform_hierarchy_depth_intra; + uint8_t num_short_term_ref_pic_sets; + uint8_t num_long_term_ref_pics_sps; + uint8_t pcm_sample_bit_depth_luma_minus1; + uint8_t pcm_sample_bit_depth_chroma_minus1; + uint8_t log2_min_pcm_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_pcm_luma_coding_block_size; + uint8_t reserved1; + uint8_t reserved2; + uint8_t palette_max_size; + uint8_t delta_palette_max_predictor_size; + uint8_t motion_vector_resolution_control_idc; + uint8_t sps_num_palette_predictor_initializers_minus1; + uint32_t conf_win_left_offset; + uint32_t conf_win_right_offset; + uint32_t conf_win_top_offset; + uint32_t conf_win_bottom_offset; + const StdVideoH265ProfileTierLevel* pProfileTierLevel; + const StdVideoH265DecPicBufMgr* pDecPicBufMgr; + const StdVideoH265ScalingLists* pScalingLists; + const StdVideoH265ShortTermRefPicSet* pShortTermRefPicSet; + const StdVideoH265LongTermRefPicsSps* pLongTermRefPicsSps; + const StdVideoH265SequenceParameterSetVui* pSequenceParameterSetVui; + const StdVideoH265PredictorPaletteEntries* pPredictorPaletteEntries; +} StdVideoH265SequenceParameterSet; + +typedef struct StdVideoH265PpsFlags { + uint32_t dependent_slice_segments_enabled_flag : 1; + uint32_t output_flag_present_flag : 1; + uint32_t sign_data_hiding_enabled_flag : 1; + uint32_t cabac_init_present_flag : 1; + uint32_t constrained_intra_pred_flag : 1; + uint32_t transform_skip_enabled_flag : 1; + uint32_t cu_qp_delta_enabled_flag : 1; + uint32_t pps_slice_chroma_qp_offsets_present_flag : 1; + uint32_t weighted_pred_flag : 1; + uint32_t weighted_bipred_flag : 1; + uint32_t transquant_bypass_enabled_flag : 1; + uint32_t tiles_enabled_flag : 1; + uint32_t entropy_coding_sync_enabled_flag : 1; + uint32_t uniform_spacing_flag : 1; + uint32_t loop_filter_across_tiles_enabled_flag : 1; + uint32_t pps_loop_filter_across_slices_enabled_flag : 1; + uint32_t deblocking_filter_control_present_flag : 1; + uint32_t deblocking_filter_override_enabled_flag : 1; + uint32_t pps_deblocking_filter_disabled_flag : 1; + uint32_t pps_scaling_list_data_present_flag : 1; + uint32_t lists_modification_present_flag : 1; + uint32_t slice_segment_header_extension_present_flag : 1; + uint32_t pps_extension_present_flag : 1; + uint32_t cross_component_prediction_enabled_flag : 1; + uint32_t chroma_qp_offset_list_enabled_flag : 1; + uint32_t pps_curr_pic_ref_enabled_flag : 1; + uint32_t residual_adaptive_colour_transform_enabled_flag : 1; + uint32_t pps_slice_act_qp_offsets_present_flag : 1; + uint32_t pps_palette_predictor_initializers_present_flag : 1; + uint32_t monochrome_palette_flag : 1; + uint32_t pps_range_extension_flag : 1; +} StdVideoH265PpsFlags; + +typedef struct StdVideoH265PictureParameterSet { + StdVideoH265PpsFlags flags; + uint8_t pps_pic_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + uint8_t sps_video_parameter_set_id; + uint8_t num_extra_slice_header_bits; + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + int8_t init_qp_minus26; + uint8_t diff_cu_qp_delta_depth; + int8_t pps_cb_qp_offset; + int8_t pps_cr_qp_offset; + int8_t pps_beta_offset_div2; + int8_t pps_tc_offset_div2; + uint8_t log2_parallel_merge_level_minus2; + uint8_t log2_max_transform_skip_block_size_minus2; + uint8_t diff_cu_chroma_qp_offset_depth; + uint8_t chroma_qp_offset_list_len_minus1; + int8_t cb_qp_offset_list[STD_VIDEO_H265_CHROMA_QP_OFFSET_LIST_SIZE]; + int8_t cr_qp_offset_list[STD_VIDEO_H265_CHROMA_QP_OFFSET_LIST_SIZE]; + uint8_t log2_sao_offset_scale_luma; + uint8_t log2_sao_offset_scale_chroma; + int8_t pps_act_y_qp_offset_plus5; + int8_t pps_act_cb_qp_offset_plus5; + int8_t pps_act_cr_qp_offset_plus3; + uint8_t pps_num_palette_predictor_initializers; + uint8_t luma_bit_depth_entry_minus8; + uint8_t chroma_bit_depth_entry_minus8; + uint8_t num_tile_columns_minus1; + uint8_t num_tile_rows_minus1; + uint8_t reserved1; + uint8_t reserved2; + uint16_t column_width_minus1[STD_VIDEO_H265_CHROMA_QP_OFFSET_TILE_COLS_LIST_SIZE]; + uint16_t row_height_minus1[STD_VIDEO_H265_CHROMA_QP_OFFSET_TILE_ROWS_LIST_SIZE]; + uint32_t reserved3; + const StdVideoH265ScalingLists* pScalingLists; + const StdVideoH265PredictorPaletteEntries* pPredictorPaletteEntries; +} StdVideoH265PictureParameterSet; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std_decode.h b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std_decode.h new file mode 100644 index 00000000000..75cf4d0946f --- /dev/null +++ b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std_decode.h @@ -0,0 +1,67 @@ +#ifndef VULKAN_VIDEO_CODEC_H265STD_DECODE_H_ +#define VULKAN_VIDEO_CODEC_H265STD_DECODE_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h265std_decode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h265std_decode 1 +#include "vulkan_video_codec_h265std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_decode" +#define STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE 8 +typedef struct StdVideoDecodeH265PictureInfoFlags { + uint32_t IrapPicFlag : 1; + uint32_t IdrPicFlag : 1; + uint32_t IsReference : 1; + uint32_t short_term_ref_pic_set_sps_flag : 1; +} StdVideoDecodeH265PictureInfoFlags; + +typedef struct StdVideoDecodeH265PictureInfo { + StdVideoDecodeH265PictureInfoFlags flags; + uint8_t sps_video_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + uint8_t pps_pic_parameter_set_id; + uint8_t NumDeltaPocsOfRefRpsIdx; + int32_t PicOrderCntVal; + uint16_t NumBitsForSTRefPicSetInSlice; + uint16_t reserved; + uint8_t RefPicSetStCurrBefore[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; + uint8_t RefPicSetStCurrAfter[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; + uint8_t RefPicSetLtCurr[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; +} StdVideoDecodeH265PictureInfo; + +typedef struct StdVideoDecodeH265ReferenceInfoFlags { + uint32_t used_for_long_term_reference : 1; + uint32_t unused_for_reference : 1; +} StdVideoDecodeH265ReferenceInfoFlags; + +typedef struct StdVideoDecodeH265ReferenceInfo { + StdVideoDecodeH265ReferenceInfoFlags flags; + int32_t PicOrderCntVal; +} StdVideoDecodeH265ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std_encode.h b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std_encode.h new file mode 100644 index 00000000000..2a7024caba8 --- /dev/null +++ b/libraries/ZVulkan/include/vk_video/vulkan_video_codec_h265std_encode.h @@ -0,0 +1,157 @@ +#ifndef VULKAN_VIDEO_CODEC_H265STD_ENCODE_H_ +#define VULKAN_VIDEO_CODEC_H265STD_ENCODE_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h265std_encode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h265std_encode 1 +#include "vulkan_video_codec_h265std.h" +// Vulkan 0.9 provisional Vulkan video H.265 encode std specification version number +#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_0_9_12 VK_MAKE_VIDEO_STD_VERSION(0, 9, 12) + +#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_0_9_12 +#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_encode" +typedef struct StdVideoEncodeH265WeightTableFlags { + uint16_t luma_weight_l0_flag; + uint16_t chroma_weight_l0_flag; + uint16_t luma_weight_l1_flag; + uint16_t chroma_weight_l1_flag; +} StdVideoEncodeH265WeightTableFlags; + +typedef struct StdVideoEncodeH265WeightTable { + StdVideoEncodeH265WeightTableFlags flags; + uint8_t luma_log2_weight_denom; + int8_t delta_chroma_log2_weight_denom; + int8_t delta_luma_weight_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + int8_t luma_offset_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + int8_t delta_chroma_weight_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES]; + int8_t delta_chroma_offset_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES]; + int8_t delta_luma_weight_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + int8_t luma_offset_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + int8_t delta_chroma_weight_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES]; + int8_t delta_chroma_offset_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES]; +} StdVideoEncodeH265WeightTable; + +typedef struct StdVideoEncodeH265SliceSegmentHeaderFlags { + uint32_t first_slice_segment_in_pic_flag : 1; + uint32_t dependent_slice_segment_flag : 1; + uint32_t slice_sao_luma_flag : 1; + uint32_t slice_sao_chroma_flag : 1; + uint32_t num_ref_idx_active_override_flag : 1; + uint32_t mvd_l1_zero_flag : 1; + uint32_t cabac_init_flag : 1; + uint32_t cu_chroma_qp_offset_enabled_flag : 1; + uint32_t deblocking_filter_override_flag : 1; + uint32_t slice_deblocking_filter_disabled_flag : 1; + uint32_t collocated_from_l0_flag : 1; + uint32_t slice_loop_filter_across_slices_enabled_flag : 1; + uint32_t reserved : 20; +} StdVideoEncodeH265SliceSegmentHeaderFlags; + +typedef struct StdVideoEncodeH265SliceSegmentHeader { + StdVideoEncodeH265SliceSegmentHeaderFlags flags; + StdVideoH265SliceType slice_type; + uint32_t slice_segment_address; + uint8_t collocated_ref_idx; + uint8_t MaxNumMergeCand; + int8_t slice_cb_qp_offset; + int8_t slice_cr_qp_offset; + int8_t slice_beta_offset_div2; + int8_t slice_tc_offset_div2; + int8_t slice_act_y_qp_offset; + int8_t slice_act_cb_qp_offset; + int8_t slice_act_cr_qp_offset; + int8_t slice_qp_delta; + uint16_t reserved1; + const StdVideoEncodeH265WeightTable* pWeightTable; +} StdVideoEncodeH265SliceSegmentHeader; + +typedef struct StdVideoEncodeH265ReferenceListsInfoFlags { + uint32_t ref_pic_list_modification_flag_l0 : 1; + uint32_t ref_pic_list_modification_flag_l1 : 1; + uint32_t reserved : 30; +} StdVideoEncodeH265ReferenceListsInfoFlags; + +typedef struct StdVideoEncodeH265ReferenceListsInfo { + StdVideoEncodeH265ReferenceListsInfoFlags flags; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + uint8_t RefPicList0[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + uint8_t RefPicList1[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + uint8_t list_entry_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + uint8_t list_entry_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF]; +} StdVideoEncodeH265ReferenceListsInfo; + +typedef struct StdVideoEncodeH265PictureInfoFlags { + uint32_t is_reference : 1; + uint32_t IrapPicFlag : 1; + uint32_t used_for_long_term_reference : 1; + uint32_t discardable_flag : 1; + uint32_t cross_layer_bla_flag : 1; + uint32_t pic_output_flag : 1; + uint32_t no_output_of_prior_pics_flag : 1; + uint32_t short_term_ref_pic_set_sps_flag : 1; + uint32_t slice_temporal_mvp_enabled_flag : 1; + uint32_t reserved : 23; +} StdVideoEncodeH265PictureInfoFlags; + +typedef struct StdVideoEncodeH265LongTermRefPics { + uint8_t num_long_term_sps; + uint8_t num_long_term_pics; + uint8_t lt_idx_sps[STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS]; + uint8_t poc_lsb_lt[STD_VIDEO_H265_MAX_LONG_TERM_PICS]; + uint16_t used_by_curr_pic_lt_flag; + uint8_t delta_poc_msb_present_flag[STD_VIDEO_H265_MAX_DELTA_POC]; + uint8_t delta_poc_msb_cycle_lt[STD_VIDEO_H265_MAX_DELTA_POC]; +} StdVideoEncodeH265LongTermRefPics; + +typedef struct StdVideoEncodeH265PictureInfo { + StdVideoEncodeH265PictureInfoFlags flags; + StdVideoH265PictureType pic_type; + uint8_t sps_video_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + uint8_t pps_pic_parameter_set_id; + uint8_t short_term_ref_pic_set_idx; + int32_t PicOrderCntVal; + uint8_t TemporalId; + uint8_t reserved1[7]; + const StdVideoEncodeH265ReferenceListsInfo* pRefLists; + const StdVideoH265ShortTermRefPicSet* pShortTermRefPicSet; + const StdVideoEncodeH265LongTermRefPics* pLongTermRefPics; +} StdVideoEncodeH265PictureInfo; + +typedef struct StdVideoEncodeH265ReferenceInfoFlags { + uint32_t used_for_long_term_reference : 1; + uint32_t unused_for_reference : 1; + uint32_t reserved : 30; +} StdVideoEncodeH265ReferenceInfoFlags; + +typedef struct StdVideoEncodeH265ReferenceInfo { + StdVideoEncodeH265ReferenceInfoFlags flags; + StdVideoH265PictureType pic_type; + int32_t PicOrderCntVal; + uint8_t TemporalId; +} StdVideoEncodeH265ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vk_video/vulkan_video_codecs_common.h b/libraries/ZVulkan/include/vk_video/vulkan_video_codecs_common.h new file mode 100644 index 00000000000..6568975ee3e --- /dev/null +++ b/libraries/ZVulkan/include/vk_video/vulkan_video_codecs_common.h @@ -0,0 +1,36 @@ +#ifndef VULKAN_VIDEO_CODECS_COMMON_H_ +#define VULKAN_VIDEO_CODECS_COMMON_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codecs_common is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codecs_common 1 +#if !defined(VK_NO_STDINT_H) + #include +#endif + +#define VK_MAKE_VIDEO_STD_VERSION(major, minor, patch) \ + ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vk_enum_string_helper.h b/libraries/ZVulkan/include/vulkan/vk_enum_string_helper.h new file mode 100644 index 00000000000..e82bb6ce4e9 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vk_enum_string_helper.h @@ -0,0 +1,8448 @@ +// *** THIS FILE IS GENERATED - DO NOT EDIT *** +// See helper_file_generator.py for modifications + + +/*************************************************************************** + * + * Copyright (c) 2015-2021 The Khronos Group Inc. + * Copyright (c) 2015-2021 Valve Corporation + * Copyright (c) 2015-2021 LunarG, Inc. + * Copyright (c) 2015-2021 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Mark Lobodzinski + * Author: Courtney Goeltzenleuchter + * Author: Tobin Ehlis + * Author: Chris Forbes + * Author: John Zulauf + * + ****************************************************************************/ + + +#pragma once +#ifdef _MSC_VER +#pragma warning( disable : 4065 ) +#endif + +#include +#include + + +static inline const char* string_VkResult(VkResult input_value) +{ + switch (input_value) + { + case VK_ERROR_DEVICE_LOST: + return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_EXTENSION_NOT_PRESENT: + return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: + return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: + return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_FRAGMENTATION: + return "VK_ERROR_FRAGMENTATION"; + case VK_ERROR_FRAGMENTED_POOL: + return "VK_ERROR_FRAGMENTED_POOL"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: + return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VK_ERROR_INCOMPATIBLE_DRIVER: + return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_INITIALIZATION_FAILED: + return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: + return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: + return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; + case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: + return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"; + case VK_ERROR_INVALID_SHADER_NV: + return "VK_ERROR_INVALID_SHADER_NV"; + case VK_ERROR_LAYER_NOT_PRESENT: + return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_MEMORY_MAP_FAILED: + return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_ERROR_NOT_PERMITTED_EXT: + return "VK_ERROR_NOT_PERMITTED_EXT"; + case VK_ERROR_OUT_OF_DATE_KHR: + return "VK_ERROR_OUT_OF_DATE_KHR"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_OUT_OF_HOST_MEMORY: + return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_POOL_MEMORY: + return "VK_ERROR_OUT_OF_POOL_MEMORY"; + case VK_ERROR_SURFACE_LOST_KHR: + return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_ERROR_TOO_MANY_OBJECTS: + return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_UNKNOWN: + return "VK_ERROR_UNKNOWN"; + case VK_ERROR_VALIDATION_FAILED_EXT: + return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VK_EVENT_RESET: + return "VK_EVENT_RESET"; + case VK_EVENT_SET: + return "VK_EVENT_SET"; + case VK_INCOMPLETE: + return "VK_INCOMPLETE"; + case VK_NOT_READY: + return "VK_NOT_READY"; + case VK_OPERATION_DEFERRED_KHR: + return "VK_OPERATION_DEFERRED_KHR"; + case VK_OPERATION_NOT_DEFERRED_KHR: + return "VK_OPERATION_NOT_DEFERRED_KHR"; + case VK_PIPELINE_COMPILE_REQUIRED_EXT: + return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; + case VK_SUBOPTIMAL_KHR: + return "VK_SUBOPTIMAL_KHR"; + case VK_SUCCESS: + return "VK_SUCCESS"; + case VK_THREAD_DONE_KHR: + return "VK_THREAD_DONE_KHR"; + case VK_THREAD_IDLE_KHR: + return "VK_THREAD_IDLE_KHR"; + case VK_TIMEOUT: + return "VK_TIMEOUT"; + default: + return "Unhandled VkResult"; + } +} + +static inline const char* string_VkStructureType(VkStructureType input_value) +{ + switch (input_value) + { + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV"; + case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR: + return "VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR"; + case VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR: + return "VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR"; + case VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR: + return "VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR"; + case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID: + return "VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID"; + case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID: + return "VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID"; + case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID: + return "VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID"; + case VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_APPLICATION_INFO: + return "VK_STRUCTURE_TYPE_APPLICATION_INFO"; + case VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2: + return "VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2"; + case VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT: + return "VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT"; + case VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2: + return "VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2"; + case VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT: + return "VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT"; + case VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV: + return "VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV"; + case VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO: + return "VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO"; + case VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO: + return "VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO"; + case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO: + return "VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO"; + case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO: + return "VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO"; + case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR: + return "VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR"; + case VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO: + return "VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO"; + case VK_STRUCTURE_TYPE_BIND_SPARSE_INFO: + return "VK_STRUCTURE_TYPE_BIND_SPARSE_INFO"; + case VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR: + return "VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR"; + case VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO: + return "VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO"; + case VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO: + return "VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO"; + case VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR: + return "VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR"; + case VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER: + return "VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER"; + case VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR: + return "VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR"; + case VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2: + return "VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2"; + case VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO: + return "VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO"; + case VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO: + return "VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO"; + case VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT: + return "VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT"; + case VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV: + return "VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV"; + case VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV: + return "VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV"; + case VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO: + return "VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO"; + case VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO: + return "VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO"; + case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT: + return "VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT"; + case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO: + return "VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO"; + case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM: + return "VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM"; + case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV: + return "VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV"; + case VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR: + return "VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR"; + case VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO: + return "VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO"; + case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT: + return "VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT"; + case VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR: + return "VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR"; + case VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR: + return "VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR"; + case VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM: + return "VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM"; + case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET: + return "VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET"; + case VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR: + return "VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR"; + case VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX: + return "VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX"; + case VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX: + return "VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX"; + case VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX: + return "VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX"; + case VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR: + return "VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR"; + case VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT"; + case VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT"; + case VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV: + return "VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV"; + case VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR: + return "VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT"; + case VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO: + return "VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO: + return "VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR: + return "VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR"; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR: + return "VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR"; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO: + return "VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO: + return "VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO: + return "VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD: + return "VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD"; + case VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT: + return "VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT"; + case VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2: + return "VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2"; + case VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT: + return "VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT"; + case VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR: + return "VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR"; + case VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD: + return "VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD"; + case VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR: + return "VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR"; + case VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR: + return "VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR"; + case VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT: + return "VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT"; + case VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR: + return "VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR"; + case VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR: + return "VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR"; + case VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: + return "VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT"; + case VK_STRUCTURE_TYPE_EVENT_CREATE_INFO: + return "VK_STRUCTURE_TYPE_EVENT_CREATE_INFO"; + case VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: + return "VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO"; + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV: + return "VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV"; + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV: + return "VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV"; + case VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES: + return "VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES"; + case VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES: + return "VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES"; + case VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID: + return "VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID"; + case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: + return "VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES"; + case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO: + return "VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO"; + case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES: + return "VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES"; + case VK_STRUCTURE_TYPE_FENCE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_FENCE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR: + return "VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR"; + case VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2: + return "VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2"; + case VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR: + return "VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR"; + case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO: + return "VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO"; + case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO: + return "VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO"; + case VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO: + return "VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO"; + case VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV: + return "VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV"; + case VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV: + return "VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV"; + case VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV: + return "VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV"; + case VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV: + return "VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV"; + case VK_STRUCTURE_TYPE_GEOMETRY_NV: + return "VK_STRUCTURE_TYPE_GEOMETRY_NV"; + case VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV: + return "VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV"; + case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_HDR_METADATA_EXT: + return "VK_STRUCTURE_TYPE_HDR_METADATA_EXT"; + case VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA: + return "VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA"; + case VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR: + return "VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR"; + case VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR: + return "VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR"; + case VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: + return "VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO"; + case VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2: + return "VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2"; + case VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER: + return "VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER"; + case VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR: + return "VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR"; + case VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2: + return "VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2"; + case VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO: + return "VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO"; + case VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR: + return "VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR"; + case VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2: + return "VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2"; + case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX: + return "VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX"; + case VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT: + return "VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT"; + case VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO: + return "VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO"; + case VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX: + return "VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX"; + case VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID: + return "VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID"; + case VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR: + return "VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR"; + case VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR: + return "VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR"; + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: + return "VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT"; + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV: + return "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV"; + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA: + return "VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA"; + case VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR: + return "VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR"; + case VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA: + return "VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA"; + case VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV: + return "VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV"; + case VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL: + return "VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL"; + case VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK: + return "VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK"; + case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK: + return "VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK"; + case VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE: + return "VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE"; + case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO: + return "VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO"; + case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO: + return "VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO"; + case VK_STRUCTURE_TYPE_MEMORY_BARRIER: + return "VK_STRUCTURE_TYPE_MEMORY_BARRIER"; + case VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR: + return "VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR"; + case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: + return "VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO"; + case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: + return "VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS"; + case VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR"; + case VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID: + return "VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID"; + case VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR: + return "VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR"; + case VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV: + return "VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV"; + case VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA: + return "VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA"; + case VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO: + return "VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO"; + case VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2: + return "VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2"; + case VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR"; + case VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA: + return "VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA"; + case VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE: + return "VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE"; + case VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL: + return "VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL"; + case VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR: + return "VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR"; + case VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR: + return "VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR"; + case VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL: + return "VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL"; + case VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL: + return "VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL"; + case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: + return "VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR"; + case VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL: + return "VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR: + return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR"; + case VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD: + return "VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD"; + case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR: + return "VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR"; + case VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR"; + case VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR: + return "VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR"; + case VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR: + return "VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR"; + case VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD: + return "VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD"; + case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP: + return "VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP"; + case VK_STRUCTURE_TYPE_PRESENT_ID_KHR: + return "VK_STRUCTURE_TYPE_PRESENT_ID_KHR"; + case VK_STRUCTURE_TYPE_PRESENT_INFO_KHR: + return "VK_STRUCTURE_TYPE_PRESENT_INFO_KHR"; + case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR: + return "VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR"; + case VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE: + return "VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE"; + case VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO: + return "VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO"; + case VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO: + return "VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO"; + case VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL: + return "VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL"; + case VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV: + return "VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV"; + case VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV: + return "VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV"; + case VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT: + return "VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT"; + case VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2: + return "VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2"; + case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV: + return "VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV"; + case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO: + return "VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO"; + case VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO: + return "VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO"; + case VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO: + return "VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO"; + case VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2: + return "VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2"; + case VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO: + return "VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO"; + case VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO: + return "VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO"; + case VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT: + return "VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT"; + case VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM: + return "VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM"; + case VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO: + return "VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO"; + case VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO: + return "VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO"; + case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: + return "VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES"; + case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO: + return "VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO"; + case VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT: + return "VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT"; + case VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX: + return "VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX"; + case VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR: + return "VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR"; + case VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR: + return "VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR"; + case VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA: + return "VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA"; + case VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO: + return "VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO"; + case VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR: + return "VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR"; + case VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO: + return "VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO"; + case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO: + return "VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO"; + case VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR: + return "VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR"; + case VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2: + return "VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2"; + case VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2: + return "VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2"; + case VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP: + return "VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP"; + case VK_STRUCTURE_TYPE_SUBMIT_INFO: + return "VK_STRUCTURE_TYPE_SUBMIT_INFO"; + case VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR: + return "VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR"; + case VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO: + return "VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO"; + case VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2: + return "VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2"; + case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2: + return "VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2"; + case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE: + return "VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE"; + case VK_STRUCTURE_TYPE_SUBPASS_END_INFO: + return "VK_STRUCTURE_TYPE_SUBPASS_END_INFO"; + case VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI: + return "VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI"; + case VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT: + return "VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT"; + case VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR: + return "VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR"; + case VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT: + return "VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT"; + case VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR: + return "VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR"; + case VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT: + return "VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT"; + case VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT: + return "VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT"; + case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: + return "VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR"; + case VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD: + return "VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD"; + case VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD: + return "VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD"; + case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: + return "VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO"; + case VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT"; + case VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT: + return "VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT"; + case VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT: + return "VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT"; + case VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT: + return "VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT"; + case VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT: + return "VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_BIND_MEMORY_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_BIND_MEMORY_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_CREATE_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_CREATE_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_GET_MEMORY_PROPERTIES_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_GET_MEMORY_PROPERTIES_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_PROFILES_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_PROFILES_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + case VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN: + return "VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN"; + case VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR: + return "VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR"; + case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV: + return "VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV"; + case VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET: + return "VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET"; + case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR: + return "VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR"; + case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV: + return "VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV"; + case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT: + return "VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT"; + case VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR"; + case VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR: + return "VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR"; + default: + return "Unhandled VkStructureType"; + } +} + +static inline const char* string_VkAccessFlagBits(VkAccessFlagBits input_value) +{ + switch (input_value) + { + case VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR: + return "VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR"; + case VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR: + return "VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR"; + case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: + return "VK_ACCESS_COLOR_ATTACHMENT_READ_BIT"; + case VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT: + return "VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT"; + case VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: + return "VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT"; + case VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV: + return "VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV"; + case VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV: + return "VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV"; + case VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT: + return "VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT"; + case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: + return "VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT"; + case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: + return "VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT"; + case VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT: + return "VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT"; + case VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR: + return "VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR"; + case VK_ACCESS_HOST_READ_BIT: + return "VK_ACCESS_HOST_READ_BIT"; + case VK_ACCESS_HOST_WRITE_BIT: + return "VK_ACCESS_HOST_WRITE_BIT"; + case VK_ACCESS_INDEX_READ_BIT: + return "VK_ACCESS_INDEX_READ_BIT"; + case VK_ACCESS_INDIRECT_COMMAND_READ_BIT: + return "VK_ACCESS_INDIRECT_COMMAND_READ_BIT"; + case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: + return "VK_ACCESS_INPUT_ATTACHMENT_READ_BIT"; + case VK_ACCESS_MEMORY_READ_BIT: + return "VK_ACCESS_MEMORY_READ_BIT"; + case VK_ACCESS_MEMORY_WRITE_BIT: + return "VK_ACCESS_MEMORY_WRITE_BIT"; + case VK_ACCESS_NONE_KHR: + return "VK_ACCESS_NONE_KHR"; + case VK_ACCESS_SHADER_READ_BIT: + return "VK_ACCESS_SHADER_READ_BIT"; + case VK_ACCESS_SHADER_WRITE_BIT: + return "VK_ACCESS_SHADER_WRITE_BIT"; + case VK_ACCESS_TRANSFER_READ_BIT: + return "VK_ACCESS_TRANSFER_READ_BIT"; + case VK_ACCESS_TRANSFER_WRITE_BIT: + return "VK_ACCESS_TRANSFER_WRITE_BIT"; + case VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT: + return "VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT"; + case VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT: + return "VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT"; + case VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT: + return "VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT"; + case VK_ACCESS_UNIFORM_READ_BIT: + return "VK_ACCESS_UNIFORM_READ_BIT"; + case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: + return "VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT"; + default: + return "Unhandled VkAccessFlagBits"; + } +} + +static inline std::string string_VkAccessFlags(VkAccessFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkAccessFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkAccessFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkImageLayout(VkImageLayout input_value) +{ + switch (input_value) + { + case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR: + return "VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR"; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL"; + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL: + return "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL"; + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + return "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL"; + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: + return "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL"; + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + return "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL"; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + return "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL"; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + return "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL"; + case VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT: + return "VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT"; + case VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR: + return "VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR"; + case VK_IMAGE_LAYOUT_GENERAL: + return "VK_IMAGE_LAYOUT_GENERAL"; + case VK_IMAGE_LAYOUT_PREINITIALIZED: + return "VK_IMAGE_LAYOUT_PREINITIALIZED"; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + return "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR"; + case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR: + return "VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR"; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL"; + case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR: + return "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR"; + case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL: + return "VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL"; + case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: + return "VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL"; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return "VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL"; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + return "VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL"; + case VK_IMAGE_LAYOUT_UNDEFINED: + return "VK_IMAGE_LAYOUT_UNDEFINED"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR: + return "VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR: + return "VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR: + return "VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR: + return "VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR: + return "VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR: + return "VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkImageLayout"; + } +} + +static inline const char* string_VkImageAspectFlagBits(VkImageAspectFlagBits input_value) +{ + switch (input_value) + { + case VK_IMAGE_ASPECT_COLOR_BIT: + return "VK_IMAGE_ASPECT_COLOR_BIT"; + case VK_IMAGE_ASPECT_DEPTH_BIT: + return "VK_IMAGE_ASPECT_DEPTH_BIT"; + case VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT: + return "VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT"; + case VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT: + return "VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT"; + case VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT: + return "VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT"; + case VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT: + return "VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT"; + case VK_IMAGE_ASPECT_METADATA_BIT: + return "VK_IMAGE_ASPECT_METADATA_BIT"; + case VK_IMAGE_ASPECT_PLANE_0_BIT: + return "VK_IMAGE_ASPECT_PLANE_0_BIT"; + case VK_IMAGE_ASPECT_PLANE_1_BIT: + return "VK_IMAGE_ASPECT_PLANE_1_BIT"; + case VK_IMAGE_ASPECT_PLANE_2_BIT: + return "VK_IMAGE_ASPECT_PLANE_2_BIT"; + case VK_IMAGE_ASPECT_STENCIL_BIT: + return "VK_IMAGE_ASPECT_STENCIL_BIT"; + default: + return "Unhandled VkImageAspectFlagBits"; + } +} + +static inline std::string string_VkImageAspectFlags(VkImageAspectFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkImageAspectFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkImageAspectFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkObjectType(VkObjectType input_value) +{ + switch (input_value) + { + case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR: + return "VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR"; + case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV: + return "VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV"; + case VK_OBJECT_TYPE_BUFFER: + return "VK_OBJECT_TYPE_BUFFER"; + case VK_OBJECT_TYPE_BUFFER_VIEW: + return "VK_OBJECT_TYPE_BUFFER_VIEW"; + case VK_OBJECT_TYPE_COMMAND_BUFFER: + return "VK_OBJECT_TYPE_COMMAND_BUFFER"; + case VK_OBJECT_TYPE_COMMAND_POOL: + return "VK_OBJECT_TYPE_COMMAND_POOL"; + case VK_OBJECT_TYPE_CU_FUNCTION_NVX: + return "VK_OBJECT_TYPE_CU_FUNCTION_NVX"; + case VK_OBJECT_TYPE_CU_MODULE_NVX: + return "VK_OBJECT_TYPE_CU_MODULE_NVX"; + case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: + return "VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT"; + case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: + return "VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT"; + case VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR: + return "VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR"; + case VK_OBJECT_TYPE_DESCRIPTOR_POOL: + return "VK_OBJECT_TYPE_DESCRIPTOR_POOL"; + case VK_OBJECT_TYPE_DESCRIPTOR_SET: + return "VK_OBJECT_TYPE_DESCRIPTOR_SET"; + case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT: + return "VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT"; + case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE: + return "VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE"; + case VK_OBJECT_TYPE_DEVICE: + return "VK_OBJECT_TYPE_DEVICE"; + case VK_OBJECT_TYPE_DEVICE_MEMORY: + return "VK_OBJECT_TYPE_DEVICE_MEMORY"; + case VK_OBJECT_TYPE_DISPLAY_KHR: + return "VK_OBJECT_TYPE_DISPLAY_KHR"; + case VK_OBJECT_TYPE_DISPLAY_MODE_KHR: + return "VK_OBJECT_TYPE_DISPLAY_MODE_KHR"; + case VK_OBJECT_TYPE_EVENT: + return "VK_OBJECT_TYPE_EVENT"; + case VK_OBJECT_TYPE_FENCE: + return "VK_OBJECT_TYPE_FENCE"; + case VK_OBJECT_TYPE_FRAMEBUFFER: + return "VK_OBJECT_TYPE_FRAMEBUFFER"; + case VK_OBJECT_TYPE_IMAGE: + return "VK_OBJECT_TYPE_IMAGE"; + case VK_OBJECT_TYPE_IMAGE_VIEW: + return "VK_OBJECT_TYPE_IMAGE_VIEW"; + case VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV: + return "VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV"; + case VK_OBJECT_TYPE_INSTANCE: + return "VK_OBJECT_TYPE_INSTANCE"; + case VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL: + return "VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL"; + case VK_OBJECT_TYPE_PHYSICAL_DEVICE: + return "VK_OBJECT_TYPE_PHYSICAL_DEVICE"; + case VK_OBJECT_TYPE_PIPELINE: + return "VK_OBJECT_TYPE_PIPELINE"; + case VK_OBJECT_TYPE_PIPELINE_CACHE: + return "VK_OBJECT_TYPE_PIPELINE_CACHE"; + case VK_OBJECT_TYPE_PIPELINE_LAYOUT: + return "VK_OBJECT_TYPE_PIPELINE_LAYOUT"; + case VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT: + return "VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT"; + case VK_OBJECT_TYPE_QUERY_POOL: + return "VK_OBJECT_TYPE_QUERY_POOL"; + case VK_OBJECT_TYPE_QUEUE: + return "VK_OBJECT_TYPE_QUEUE"; + case VK_OBJECT_TYPE_RENDER_PASS: + return "VK_OBJECT_TYPE_RENDER_PASS"; + case VK_OBJECT_TYPE_SAMPLER: + return "VK_OBJECT_TYPE_SAMPLER"; + case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION: + return "VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION"; + case VK_OBJECT_TYPE_SEMAPHORE: + return "VK_OBJECT_TYPE_SEMAPHORE"; + case VK_OBJECT_TYPE_SHADER_MODULE: + return "VK_OBJECT_TYPE_SHADER_MODULE"; + case VK_OBJECT_TYPE_SURFACE_KHR: + return "VK_OBJECT_TYPE_SURFACE_KHR"; + case VK_OBJECT_TYPE_SWAPCHAIN_KHR: + return "VK_OBJECT_TYPE_SWAPCHAIN_KHR"; + case VK_OBJECT_TYPE_UNKNOWN: + return "VK_OBJECT_TYPE_UNKNOWN"; + case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: + return "VK_OBJECT_TYPE_VALIDATION_CACHE_EXT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_OBJECT_TYPE_VIDEO_SESSION_KHR: + return "VK_OBJECT_TYPE_VIDEO_SESSION_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR: + return "VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkObjectType"; + } +} + +static inline const char* string_VkPipelineCacheHeaderVersion(VkPipelineCacheHeaderVersion input_value) +{ + switch (input_value) + { + case VK_PIPELINE_CACHE_HEADER_VERSION_ONE: + return "VK_PIPELINE_CACHE_HEADER_VERSION_ONE"; + default: + return "Unhandled VkPipelineCacheHeaderVersion"; + } +} + +static inline const char* string_VkVendorId(VkVendorId input_value) +{ + switch (input_value) + { + case VK_VENDOR_ID_CODEPLAY: + return "VK_VENDOR_ID_CODEPLAY"; + case VK_VENDOR_ID_KAZAN: + return "VK_VENDOR_ID_KAZAN"; + case VK_VENDOR_ID_MESA: + return "VK_VENDOR_ID_MESA"; + case VK_VENDOR_ID_POCL: + return "VK_VENDOR_ID_POCL"; + case VK_VENDOR_ID_VIV: + return "VK_VENDOR_ID_VIV"; + case VK_VENDOR_ID_VSI: + return "VK_VENDOR_ID_VSI"; + default: + return "Unhandled VkVendorId"; + } +} + +static inline const char* string_VkSystemAllocationScope(VkSystemAllocationScope input_value) +{ + switch (input_value) + { + case VK_SYSTEM_ALLOCATION_SCOPE_CACHE: + return "VK_SYSTEM_ALLOCATION_SCOPE_CACHE"; + case VK_SYSTEM_ALLOCATION_SCOPE_COMMAND: + return "VK_SYSTEM_ALLOCATION_SCOPE_COMMAND"; + case VK_SYSTEM_ALLOCATION_SCOPE_DEVICE: + return "VK_SYSTEM_ALLOCATION_SCOPE_DEVICE"; + case VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE: + return "VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE"; + case VK_SYSTEM_ALLOCATION_SCOPE_OBJECT: + return "VK_SYSTEM_ALLOCATION_SCOPE_OBJECT"; + default: + return "Unhandled VkSystemAllocationScope"; + } +} + +static inline const char* string_VkInternalAllocationType(VkInternalAllocationType input_value) +{ + switch (input_value) + { + case VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE: + return "VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE"; + default: + return "Unhandled VkInternalAllocationType"; + } +} + +static inline const char* string_VkFormat(VkFormat input_value) +{ + switch (input_value) + { + case VK_FORMAT_A1R5G5B5_UNORM_PACK16: + return "VK_FORMAT_A1R5G5B5_UNORM_PACK16"; + case VK_FORMAT_A2B10G10R10_SINT_PACK32: + return "VK_FORMAT_A2B10G10R10_SINT_PACK32"; + case VK_FORMAT_A2B10G10R10_SNORM_PACK32: + return "VK_FORMAT_A2B10G10R10_SNORM_PACK32"; + case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: + return "VK_FORMAT_A2B10G10R10_SSCALED_PACK32"; + case VK_FORMAT_A2B10G10R10_UINT_PACK32: + return "VK_FORMAT_A2B10G10R10_UINT_PACK32"; + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + return "VK_FORMAT_A2B10G10R10_UNORM_PACK32"; + case VK_FORMAT_A2B10G10R10_USCALED_PACK32: + return "VK_FORMAT_A2B10G10R10_USCALED_PACK32"; + case VK_FORMAT_A2R10G10B10_SINT_PACK32: + return "VK_FORMAT_A2R10G10B10_SINT_PACK32"; + case VK_FORMAT_A2R10G10B10_SNORM_PACK32: + return "VK_FORMAT_A2R10G10B10_SNORM_PACK32"; + case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: + return "VK_FORMAT_A2R10G10B10_SSCALED_PACK32"; + case VK_FORMAT_A2R10G10B10_UINT_PACK32: + return "VK_FORMAT_A2R10G10B10_UINT_PACK32"; + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + return "VK_FORMAT_A2R10G10B10_UNORM_PACK32"; + case VK_FORMAT_A2R10G10B10_USCALED_PACK32: + return "VK_FORMAT_A2R10G10B10_USCALED_PACK32"; + case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: + return "VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT"; + case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: + return "VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT"; + case VK_FORMAT_A8B8G8R8_SINT_PACK32: + return "VK_FORMAT_A8B8G8R8_SINT_PACK32"; + case VK_FORMAT_A8B8G8R8_SNORM_PACK32: + return "VK_FORMAT_A8B8G8R8_SNORM_PACK32"; + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + return "VK_FORMAT_A8B8G8R8_SRGB_PACK32"; + case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: + return "VK_FORMAT_A8B8G8R8_SSCALED_PACK32"; + case VK_FORMAT_A8B8G8R8_UINT_PACK32: + return "VK_FORMAT_A8B8G8R8_UINT_PACK32"; + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + return "VK_FORMAT_A8B8G8R8_UNORM_PACK32"; + case VK_FORMAT_A8B8G8R8_USCALED_PACK32: + return "VK_FORMAT_A8B8G8R8_USCALED_PACK32"; + case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: + return "VK_FORMAT_ASTC_10x10_SRGB_BLOCK"; + case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: + return "VK_FORMAT_ASTC_10x10_UNORM_BLOCK"; + case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: + return "VK_FORMAT_ASTC_10x5_SRGB_BLOCK"; + case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: + return "VK_FORMAT_ASTC_10x5_UNORM_BLOCK"; + case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: + return "VK_FORMAT_ASTC_10x6_SRGB_BLOCK"; + case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: + return "VK_FORMAT_ASTC_10x6_UNORM_BLOCK"; + case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: + return "VK_FORMAT_ASTC_10x8_SRGB_BLOCK"; + case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: + return "VK_FORMAT_ASTC_10x8_UNORM_BLOCK"; + case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: + return "VK_FORMAT_ASTC_12x10_SRGB_BLOCK"; + case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: + return "VK_FORMAT_ASTC_12x10_UNORM_BLOCK"; + case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: + return "VK_FORMAT_ASTC_12x12_SRGB_BLOCK"; + case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: + return "VK_FORMAT_ASTC_12x12_UNORM_BLOCK"; + case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: + return "VK_FORMAT_ASTC_4x4_SRGB_BLOCK"; + case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: + return "VK_FORMAT_ASTC_4x4_UNORM_BLOCK"; + case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: + return "VK_FORMAT_ASTC_5x4_SRGB_BLOCK"; + case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: + return "VK_FORMAT_ASTC_5x4_UNORM_BLOCK"; + case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: + return "VK_FORMAT_ASTC_5x5_SRGB_BLOCK"; + case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: + return "VK_FORMAT_ASTC_5x5_UNORM_BLOCK"; + case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: + return "VK_FORMAT_ASTC_6x5_SRGB_BLOCK"; + case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: + return "VK_FORMAT_ASTC_6x5_UNORM_BLOCK"; + case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: + return "VK_FORMAT_ASTC_6x6_SRGB_BLOCK"; + case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: + return "VK_FORMAT_ASTC_6x6_UNORM_BLOCK"; + case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: + return "VK_FORMAT_ASTC_8x5_SRGB_BLOCK"; + case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: + return "VK_FORMAT_ASTC_8x5_UNORM_BLOCK"; + case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: + return "VK_FORMAT_ASTC_8x6_SRGB_BLOCK"; + case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: + return "VK_FORMAT_ASTC_8x6_UNORM_BLOCK"; + case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT: + return "VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT"; + case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: + return "VK_FORMAT_ASTC_8x8_SRGB_BLOCK"; + case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: + return "VK_FORMAT_ASTC_8x8_UNORM_BLOCK"; + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + return "VK_FORMAT_B10G11R11_UFLOAT_PACK32"; + case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: + return "VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16"; + case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: + return "VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16"; + case VK_FORMAT_B16G16R16G16_422_UNORM: + return "VK_FORMAT_B16G16R16G16_422_UNORM"; + case VK_FORMAT_B4G4R4A4_UNORM_PACK16: + return "VK_FORMAT_B4G4R4A4_UNORM_PACK16"; + case VK_FORMAT_B5G5R5A1_UNORM_PACK16: + return "VK_FORMAT_B5G5R5A1_UNORM_PACK16"; + case VK_FORMAT_B5G6R5_UNORM_PACK16: + return "VK_FORMAT_B5G6R5_UNORM_PACK16"; + case VK_FORMAT_B8G8R8A8_SINT: + return "VK_FORMAT_B8G8R8A8_SINT"; + case VK_FORMAT_B8G8R8A8_SNORM: + return "VK_FORMAT_B8G8R8A8_SNORM"; + case VK_FORMAT_B8G8R8A8_SRGB: + return "VK_FORMAT_B8G8R8A8_SRGB"; + case VK_FORMAT_B8G8R8A8_SSCALED: + return "VK_FORMAT_B8G8R8A8_SSCALED"; + case VK_FORMAT_B8G8R8A8_UINT: + return "VK_FORMAT_B8G8R8A8_UINT"; + case VK_FORMAT_B8G8R8A8_UNORM: + return "VK_FORMAT_B8G8R8A8_UNORM"; + case VK_FORMAT_B8G8R8A8_USCALED: + return "VK_FORMAT_B8G8R8A8_USCALED"; + case VK_FORMAT_B8G8R8G8_422_UNORM: + return "VK_FORMAT_B8G8R8G8_422_UNORM"; + case VK_FORMAT_B8G8R8_SINT: + return "VK_FORMAT_B8G8R8_SINT"; + case VK_FORMAT_B8G8R8_SNORM: + return "VK_FORMAT_B8G8R8_SNORM"; + case VK_FORMAT_B8G8R8_SRGB: + return "VK_FORMAT_B8G8R8_SRGB"; + case VK_FORMAT_B8G8R8_SSCALED: + return "VK_FORMAT_B8G8R8_SSCALED"; + case VK_FORMAT_B8G8R8_UINT: + return "VK_FORMAT_B8G8R8_UINT"; + case VK_FORMAT_B8G8R8_UNORM: + return "VK_FORMAT_B8G8R8_UNORM"; + case VK_FORMAT_B8G8R8_USCALED: + return "VK_FORMAT_B8G8R8_USCALED"; + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + return "VK_FORMAT_BC1_RGBA_SRGB_BLOCK"; + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + return "VK_FORMAT_BC1_RGBA_UNORM_BLOCK"; + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + return "VK_FORMAT_BC1_RGB_SRGB_BLOCK"; + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + return "VK_FORMAT_BC1_RGB_UNORM_BLOCK"; + case VK_FORMAT_BC2_SRGB_BLOCK: + return "VK_FORMAT_BC2_SRGB_BLOCK"; + case VK_FORMAT_BC2_UNORM_BLOCK: + return "VK_FORMAT_BC2_UNORM_BLOCK"; + case VK_FORMAT_BC3_SRGB_BLOCK: + return "VK_FORMAT_BC3_SRGB_BLOCK"; + case VK_FORMAT_BC3_UNORM_BLOCK: + return "VK_FORMAT_BC3_UNORM_BLOCK"; + case VK_FORMAT_BC4_SNORM_BLOCK: + return "VK_FORMAT_BC4_SNORM_BLOCK"; + case VK_FORMAT_BC4_UNORM_BLOCK: + return "VK_FORMAT_BC4_UNORM_BLOCK"; + case VK_FORMAT_BC5_SNORM_BLOCK: + return "VK_FORMAT_BC5_SNORM_BLOCK"; + case VK_FORMAT_BC5_UNORM_BLOCK: + return "VK_FORMAT_BC5_UNORM_BLOCK"; + case VK_FORMAT_BC6H_SFLOAT_BLOCK: + return "VK_FORMAT_BC6H_SFLOAT_BLOCK"; + case VK_FORMAT_BC6H_UFLOAT_BLOCK: + return "VK_FORMAT_BC6H_UFLOAT_BLOCK"; + case VK_FORMAT_BC7_SRGB_BLOCK: + return "VK_FORMAT_BC7_SRGB_BLOCK"; + case VK_FORMAT_BC7_UNORM_BLOCK: + return "VK_FORMAT_BC7_UNORM_BLOCK"; + case VK_FORMAT_D16_UNORM: + return "VK_FORMAT_D16_UNORM"; + case VK_FORMAT_D16_UNORM_S8_UINT: + return "VK_FORMAT_D16_UNORM_S8_UINT"; + case VK_FORMAT_D24_UNORM_S8_UINT: + return "VK_FORMAT_D24_UNORM_S8_UINT"; + case VK_FORMAT_D32_SFLOAT: + return "VK_FORMAT_D32_SFLOAT"; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return "VK_FORMAT_D32_SFLOAT_S8_UINT"; + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + return "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32"; + case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: + return "VK_FORMAT_EAC_R11G11_SNORM_BLOCK"; + case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: + return "VK_FORMAT_EAC_R11G11_UNORM_BLOCK"; + case VK_FORMAT_EAC_R11_SNORM_BLOCK: + return "VK_FORMAT_EAC_R11_SNORM_BLOCK"; + case VK_FORMAT_EAC_R11_UNORM_BLOCK: + return "VK_FORMAT_EAC_R11_UNORM_BLOCK"; + case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + return "VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK"; + case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + return "VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK"; + case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: + return "VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK"; + case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + return "VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK"; + case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + return "VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK"; + case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + return "VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK"; + case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: + return "VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16"; + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: + return "VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16"; + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: + return "VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16"; + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT: + return "VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT"; + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: + return "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16"; + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: + return "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16"; + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: + return "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16"; + case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: + return "VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16"; + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: + return "VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16"; + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: + return "VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16"; + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT: + return "VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT"; + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: + return "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16"; + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: + return "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16"; + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: + return "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16"; + case VK_FORMAT_G16B16G16R16_422_UNORM: + return "VK_FORMAT_G16B16G16R16_422_UNORM"; + case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: + return "VK_FORMAT_G16_B16R16_2PLANE_420_UNORM"; + case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: + return "VK_FORMAT_G16_B16R16_2PLANE_422_UNORM"; + case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT: + return "VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT"; + case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: + return "VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM"; + case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: + return "VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM"; + case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: + return "VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM"; + case VK_FORMAT_G8B8G8R8_422_UNORM: + return "VK_FORMAT_G8B8G8R8_422_UNORM"; + case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: + return "VK_FORMAT_G8_B8R8_2PLANE_420_UNORM"; + case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: + return "VK_FORMAT_G8_B8R8_2PLANE_422_UNORM"; + case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT: + return "VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT"; + case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + return "VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM"; + case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: + return "VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM"; + case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: + return "VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM"; + case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + return "VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG"; + case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + return "VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG"; + case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + return "VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG"; + case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + return "VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG"; + case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + return "VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG"; + case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + return "VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG"; + case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + return "VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG"; + case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + return "VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG"; + case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: + return "VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16"; + case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: + return "VK_FORMAT_R10X6G10X6_UNORM_2PACK16"; + case VK_FORMAT_R10X6_UNORM_PACK16: + return "VK_FORMAT_R10X6_UNORM_PACK16"; + case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: + return "VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16"; + case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: + return "VK_FORMAT_R12X4G12X4_UNORM_2PACK16"; + case VK_FORMAT_R12X4_UNORM_PACK16: + return "VK_FORMAT_R12X4_UNORM_PACK16"; + case VK_FORMAT_R16G16B16A16_SFLOAT: + return "VK_FORMAT_R16G16B16A16_SFLOAT"; + case VK_FORMAT_R16G16B16A16_SINT: + return "VK_FORMAT_R16G16B16A16_SINT"; + case VK_FORMAT_R16G16B16A16_SNORM: + return "VK_FORMAT_R16G16B16A16_SNORM"; + case VK_FORMAT_R16G16B16A16_SSCALED: + return "VK_FORMAT_R16G16B16A16_SSCALED"; + case VK_FORMAT_R16G16B16A16_UINT: + return "VK_FORMAT_R16G16B16A16_UINT"; + case VK_FORMAT_R16G16B16A16_UNORM: + return "VK_FORMAT_R16G16B16A16_UNORM"; + case VK_FORMAT_R16G16B16A16_USCALED: + return "VK_FORMAT_R16G16B16A16_USCALED"; + case VK_FORMAT_R16G16B16_SFLOAT: + return "VK_FORMAT_R16G16B16_SFLOAT"; + case VK_FORMAT_R16G16B16_SINT: + return "VK_FORMAT_R16G16B16_SINT"; + case VK_FORMAT_R16G16B16_SNORM: + return "VK_FORMAT_R16G16B16_SNORM"; + case VK_FORMAT_R16G16B16_SSCALED: + return "VK_FORMAT_R16G16B16_SSCALED"; + case VK_FORMAT_R16G16B16_UINT: + return "VK_FORMAT_R16G16B16_UINT"; + case VK_FORMAT_R16G16B16_UNORM: + return "VK_FORMAT_R16G16B16_UNORM"; + case VK_FORMAT_R16G16B16_USCALED: + return "VK_FORMAT_R16G16B16_USCALED"; + case VK_FORMAT_R16G16_SFLOAT: + return "VK_FORMAT_R16G16_SFLOAT"; + case VK_FORMAT_R16G16_SINT: + return "VK_FORMAT_R16G16_SINT"; + case VK_FORMAT_R16G16_SNORM: + return "VK_FORMAT_R16G16_SNORM"; + case VK_FORMAT_R16G16_SSCALED: + return "VK_FORMAT_R16G16_SSCALED"; + case VK_FORMAT_R16G16_UINT: + return "VK_FORMAT_R16G16_UINT"; + case VK_FORMAT_R16G16_UNORM: + return "VK_FORMAT_R16G16_UNORM"; + case VK_FORMAT_R16G16_USCALED: + return "VK_FORMAT_R16G16_USCALED"; + case VK_FORMAT_R16_SFLOAT: + return "VK_FORMAT_R16_SFLOAT"; + case VK_FORMAT_R16_SINT: + return "VK_FORMAT_R16_SINT"; + case VK_FORMAT_R16_SNORM: + return "VK_FORMAT_R16_SNORM"; + case VK_FORMAT_R16_SSCALED: + return "VK_FORMAT_R16_SSCALED"; + case VK_FORMAT_R16_UINT: + return "VK_FORMAT_R16_UINT"; + case VK_FORMAT_R16_UNORM: + return "VK_FORMAT_R16_UNORM"; + case VK_FORMAT_R16_USCALED: + return "VK_FORMAT_R16_USCALED"; + case VK_FORMAT_R32G32B32A32_SFLOAT: + return "VK_FORMAT_R32G32B32A32_SFLOAT"; + case VK_FORMAT_R32G32B32A32_SINT: + return "VK_FORMAT_R32G32B32A32_SINT"; + case VK_FORMAT_R32G32B32A32_UINT: + return "VK_FORMAT_R32G32B32A32_UINT"; + case VK_FORMAT_R32G32B32_SFLOAT: + return "VK_FORMAT_R32G32B32_SFLOAT"; + case VK_FORMAT_R32G32B32_SINT: + return "VK_FORMAT_R32G32B32_SINT"; + case VK_FORMAT_R32G32B32_UINT: + return "VK_FORMAT_R32G32B32_UINT"; + case VK_FORMAT_R32G32_SFLOAT: + return "VK_FORMAT_R32G32_SFLOAT"; + case VK_FORMAT_R32G32_SINT: + return "VK_FORMAT_R32G32_SINT"; + case VK_FORMAT_R32G32_UINT: + return "VK_FORMAT_R32G32_UINT"; + case VK_FORMAT_R32_SFLOAT: + return "VK_FORMAT_R32_SFLOAT"; + case VK_FORMAT_R32_SINT: + return "VK_FORMAT_R32_SINT"; + case VK_FORMAT_R32_UINT: + return "VK_FORMAT_R32_UINT"; + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + return "VK_FORMAT_R4G4B4A4_UNORM_PACK16"; + case VK_FORMAT_R4G4_UNORM_PACK8: + return "VK_FORMAT_R4G4_UNORM_PACK8"; + case VK_FORMAT_R5G5B5A1_UNORM_PACK16: + return "VK_FORMAT_R5G5B5A1_UNORM_PACK16"; + case VK_FORMAT_R5G6B5_UNORM_PACK16: + return "VK_FORMAT_R5G6B5_UNORM_PACK16"; + case VK_FORMAT_R64G64B64A64_SFLOAT: + return "VK_FORMAT_R64G64B64A64_SFLOAT"; + case VK_FORMAT_R64G64B64A64_SINT: + return "VK_FORMAT_R64G64B64A64_SINT"; + case VK_FORMAT_R64G64B64A64_UINT: + return "VK_FORMAT_R64G64B64A64_UINT"; + case VK_FORMAT_R64G64B64_SFLOAT: + return "VK_FORMAT_R64G64B64_SFLOAT"; + case VK_FORMAT_R64G64B64_SINT: + return "VK_FORMAT_R64G64B64_SINT"; + case VK_FORMAT_R64G64B64_UINT: + return "VK_FORMAT_R64G64B64_UINT"; + case VK_FORMAT_R64G64_SFLOAT: + return "VK_FORMAT_R64G64_SFLOAT"; + case VK_FORMAT_R64G64_SINT: + return "VK_FORMAT_R64G64_SINT"; + case VK_FORMAT_R64G64_UINT: + return "VK_FORMAT_R64G64_UINT"; + case VK_FORMAT_R64_SFLOAT: + return "VK_FORMAT_R64_SFLOAT"; + case VK_FORMAT_R64_SINT: + return "VK_FORMAT_R64_SINT"; + case VK_FORMAT_R64_UINT: + return "VK_FORMAT_R64_UINT"; + case VK_FORMAT_R8G8B8A8_SINT: + return "VK_FORMAT_R8G8B8A8_SINT"; + case VK_FORMAT_R8G8B8A8_SNORM: + return "VK_FORMAT_R8G8B8A8_SNORM"; + case VK_FORMAT_R8G8B8A8_SRGB: + return "VK_FORMAT_R8G8B8A8_SRGB"; + case VK_FORMAT_R8G8B8A8_SSCALED: + return "VK_FORMAT_R8G8B8A8_SSCALED"; + case VK_FORMAT_R8G8B8A8_UINT: + return "VK_FORMAT_R8G8B8A8_UINT"; + case VK_FORMAT_R8G8B8A8_UNORM: + return "VK_FORMAT_R8G8B8A8_UNORM"; + case VK_FORMAT_R8G8B8A8_USCALED: + return "VK_FORMAT_R8G8B8A8_USCALED"; + case VK_FORMAT_R8G8B8_SINT: + return "VK_FORMAT_R8G8B8_SINT"; + case VK_FORMAT_R8G8B8_SNORM: + return "VK_FORMAT_R8G8B8_SNORM"; + case VK_FORMAT_R8G8B8_SRGB: + return "VK_FORMAT_R8G8B8_SRGB"; + case VK_FORMAT_R8G8B8_SSCALED: + return "VK_FORMAT_R8G8B8_SSCALED"; + case VK_FORMAT_R8G8B8_UINT: + return "VK_FORMAT_R8G8B8_UINT"; + case VK_FORMAT_R8G8B8_UNORM: + return "VK_FORMAT_R8G8B8_UNORM"; + case VK_FORMAT_R8G8B8_USCALED: + return "VK_FORMAT_R8G8B8_USCALED"; + case VK_FORMAT_R8G8_SINT: + return "VK_FORMAT_R8G8_SINT"; + case VK_FORMAT_R8G8_SNORM: + return "VK_FORMAT_R8G8_SNORM"; + case VK_FORMAT_R8G8_SRGB: + return "VK_FORMAT_R8G8_SRGB"; + case VK_FORMAT_R8G8_SSCALED: + return "VK_FORMAT_R8G8_SSCALED"; + case VK_FORMAT_R8G8_UINT: + return "VK_FORMAT_R8G8_UINT"; + case VK_FORMAT_R8G8_UNORM: + return "VK_FORMAT_R8G8_UNORM"; + case VK_FORMAT_R8G8_USCALED: + return "VK_FORMAT_R8G8_USCALED"; + case VK_FORMAT_R8_SINT: + return "VK_FORMAT_R8_SINT"; + case VK_FORMAT_R8_SNORM: + return "VK_FORMAT_R8_SNORM"; + case VK_FORMAT_R8_SRGB: + return "VK_FORMAT_R8_SRGB"; + case VK_FORMAT_R8_SSCALED: + return "VK_FORMAT_R8_SSCALED"; + case VK_FORMAT_R8_UINT: + return "VK_FORMAT_R8_UINT"; + case VK_FORMAT_R8_UNORM: + return "VK_FORMAT_R8_UNORM"; + case VK_FORMAT_R8_USCALED: + return "VK_FORMAT_R8_USCALED"; + case VK_FORMAT_S8_UINT: + return "VK_FORMAT_S8_UINT"; + case VK_FORMAT_UNDEFINED: + return "VK_FORMAT_UNDEFINED"; + case VK_FORMAT_X8_D24_UNORM_PACK32: + return "VK_FORMAT_X8_D24_UNORM_PACK32"; + default: + return "Unhandled VkFormat"; + } +} + +static inline const char* string_VkFormatFeatureFlagBits(VkFormatFeatureFlagBits input_value) +{ + switch (input_value) + { + case VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR: + return "VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR"; + case VK_FORMAT_FEATURE_BLIT_DST_BIT: + return "VK_FORMAT_FEATURE_BLIT_DST_BIT"; + case VK_FORMAT_FEATURE_BLIT_SRC_BIT: + return "VK_FORMAT_FEATURE_BLIT_SRC_BIT"; + case VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT: + return "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT"; + case VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT: + return "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT"; + case VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT: + return "VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT"; + case VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT: + return "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"; + case VK_FORMAT_FEATURE_DISJOINT_BIT: + return "VK_FORMAT_FEATURE_DISJOINT_BIT"; + case VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT: + return "VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT"; + case VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR: + return "VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"; + case VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT: + return "VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT"; + case VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT: + return "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT"; + case VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG: + return "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG"; + case VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT: + return "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT"; + case VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT: + return "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT"; + case VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT: + return "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT"; + case VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT: + return "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT"; + case VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT: + return "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT"; + case VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT: + return "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT"; + case VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT: + return "VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT"; + case VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT: + return "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT"; + case VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT: + return "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"; + case VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT: + return "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT"; + case VK_FORMAT_FEATURE_TRANSFER_DST_BIT: + return "VK_FORMAT_FEATURE_TRANSFER_DST_BIT"; + case VK_FORMAT_FEATURE_TRANSFER_SRC_BIT: + return "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT"; + case VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT: + return "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT"; + case VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT: + return "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_FORMAT_FEATURE_VIDEO_DECODE_DPB_BIT_KHR: + return "VK_FORMAT_FEATURE_VIDEO_DECODE_DPB_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_FORMAT_FEATURE_VIDEO_DECODE_OUTPUT_BIT_KHR: + return "VK_FORMAT_FEATURE_VIDEO_DECODE_OUTPUT_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_FORMAT_FEATURE_VIDEO_ENCODE_DPB_BIT_KHR: + return "VK_FORMAT_FEATURE_VIDEO_ENCODE_DPB_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_FORMAT_FEATURE_VIDEO_ENCODE_INPUT_BIT_KHR: + return "VK_FORMAT_FEATURE_VIDEO_ENCODE_INPUT_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkFormatFeatureFlagBits"; + } +} + +static inline std::string string_VkFormatFeatureFlags(VkFormatFeatureFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkFormatFeatureFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkFormatFeatureFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkImageCreateFlagBits(VkImageCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT: + return "VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT"; + case VK_IMAGE_CREATE_ALIAS_BIT: + return "VK_IMAGE_CREATE_ALIAS_BIT"; + case VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT: + return "VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT"; + case VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV: + return "VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV"; + case VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT: + return "VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT"; + case VK_IMAGE_CREATE_DISJOINT_BIT: + return "VK_IMAGE_CREATE_DISJOINT_BIT"; + case VK_IMAGE_CREATE_EXTENDED_USAGE_BIT: + return "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT"; + case VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT: + return "VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT"; + case VK_IMAGE_CREATE_PROTECTED_BIT: + return "VK_IMAGE_CREATE_PROTECTED_BIT"; + case VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT: + return "VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT"; + case VK_IMAGE_CREATE_SPARSE_ALIASED_BIT: + return "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT"; + case VK_IMAGE_CREATE_SPARSE_BINDING_BIT: + return "VK_IMAGE_CREATE_SPARSE_BINDING_BIT"; + case VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT: + return "VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT"; + case VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT: + return "VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT"; + case VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT: + return "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT"; + default: + return "Unhandled VkImageCreateFlagBits"; + } +} + +static inline std::string string_VkImageCreateFlags(VkImageCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkImageCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkImageCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSampleCountFlagBits(VkSampleCountFlagBits input_value) +{ + switch (input_value) + { + case VK_SAMPLE_COUNT_16_BIT: + return "VK_SAMPLE_COUNT_16_BIT"; + case VK_SAMPLE_COUNT_1_BIT: + return "VK_SAMPLE_COUNT_1_BIT"; + case VK_SAMPLE_COUNT_2_BIT: + return "VK_SAMPLE_COUNT_2_BIT"; + case VK_SAMPLE_COUNT_32_BIT: + return "VK_SAMPLE_COUNT_32_BIT"; + case VK_SAMPLE_COUNT_4_BIT: + return "VK_SAMPLE_COUNT_4_BIT"; + case VK_SAMPLE_COUNT_64_BIT: + return "VK_SAMPLE_COUNT_64_BIT"; + case VK_SAMPLE_COUNT_8_BIT: + return "VK_SAMPLE_COUNT_8_BIT"; + default: + return "Unhandled VkSampleCountFlagBits"; + } +} + +static inline std::string string_VkSampleCountFlags(VkSampleCountFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSampleCountFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSampleCountFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkImageTiling(VkImageTiling input_value) +{ + switch (input_value) + { + case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT: + return "VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT"; + case VK_IMAGE_TILING_LINEAR: + return "VK_IMAGE_TILING_LINEAR"; + case VK_IMAGE_TILING_OPTIMAL: + return "VK_IMAGE_TILING_OPTIMAL"; + default: + return "Unhandled VkImageTiling"; + } +} + +static inline const char* string_VkImageType(VkImageType input_value) +{ + switch (input_value) + { + case VK_IMAGE_TYPE_1D: + return "VK_IMAGE_TYPE_1D"; + case VK_IMAGE_TYPE_2D: + return "VK_IMAGE_TYPE_2D"; + case VK_IMAGE_TYPE_3D: + return "VK_IMAGE_TYPE_3D"; + default: + return "Unhandled VkImageType"; + } +} + +static inline const char* string_VkImageUsageFlagBits(VkImageUsageFlagBits input_value) +{ + switch (input_value) + { + case VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT: + return "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT"; + case VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT: + return "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT"; + case VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT: + return "VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT"; + case VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR: + return "VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"; + case VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT: + return "VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT"; + case VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI: + return "VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI"; + case VK_IMAGE_USAGE_SAMPLED_BIT: + return "VK_IMAGE_USAGE_SAMPLED_BIT"; + case VK_IMAGE_USAGE_STORAGE_BIT: + return "VK_IMAGE_USAGE_STORAGE_BIT"; + case VK_IMAGE_USAGE_TRANSFER_DST_BIT: + return "VK_IMAGE_USAGE_TRANSFER_DST_BIT"; + case VK_IMAGE_USAGE_TRANSFER_SRC_BIT: + return "VK_IMAGE_USAGE_TRANSFER_SRC_BIT"; + case VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: + return "VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR: + return "VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR: + return "VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR: + return "VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR: + return "VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR: + return "VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR: + return "VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkImageUsageFlagBits"; + } +} + +static inline std::string string_VkImageUsageFlags(VkImageUsageFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkImageUsageFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkImageUsageFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkMemoryHeapFlagBits(VkMemoryHeapFlagBits input_value) +{ + switch (input_value) + { + case VK_MEMORY_HEAP_DEVICE_LOCAL_BIT: + return "VK_MEMORY_HEAP_DEVICE_LOCAL_BIT"; + case VK_MEMORY_HEAP_MULTI_INSTANCE_BIT: + return "VK_MEMORY_HEAP_MULTI_INSTANCE_BIT"; + default: + return "Unhandled VkMemoryHeapFlagBits"; + } +} + +static inline std::string string_VkMemoryHeapFlags(VkMemoryHeapFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkMemoryHeapFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkMemoryHeapFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkMemoryPropertyFlagBits(VkMemoryPropertyFlagBits input_value) +{ + switch (input_value) + { + case VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD: + return "VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD"; + case VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT: + return "VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT"; + case VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD: + return "VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD"; + case VK_MEMORY_PROPERTY_HOST_CACHED_BIT: + return "VK_MEMORY_PROPERTY_HOST_CACHED_BIT"; + case VK_MEMORY_PROPERTY_HOST_COHERENT_BIT: + return "VK_MEMORY_PROPERTY_HOST_COHERENT_BIT"; + case VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT: + return "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT"; + case VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT: + return "VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT"; + case VK_MEMORY_PROPERTY_PROTECTED_BIT: + return "VK_MEMORY_PROPERTY_PROTECTED_BIT"; + case VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV: + return "VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV"; + default: + return "Unhandled VkMemoryPropertyFlagBits"; + } +} + +static inline std::string string_VkMemoryPropertyFlags(VkMemoryPropertyFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkMemoryPropertyFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkMemoryPropertyFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkPhysicalDeviceType(VkPhysicalDeviceType input_value) +{ + switch (input_value) + { + case VK_PHYSICAL_DEVICE_TYPE_CPU: + return "VK_PHYSICAL_DEVICE_TYPE_CPU"; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + return "VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU"; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + return "VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU"; + case VK_PHYSICAL_DEVICE_TYPE_OTHER: + return "VK_PHYSICAL_DEVICE_TYPE_OTHER"; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + return "VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU"; + default: + return "Unhandled VkPhysicalDeviceType"; + } +} + +static inline const char* string_VkQueueFlagBits(VkQueueFlagBits input_value) +{ + switch (input_value) + { + case VK_QUEUE_COMPUTE_BIT: + return "VK_QUEUE_COMPUTE_BIT"; + case VK_QUEUE_GRAPHICS_BIT: + return "VK_QUEUE_GRAPHICS_BIT"; + case VK_QUEUE_PROTECTED_BIT: + return "VK_QUEUE_PROTECTED_BIT"; + case VK_QUEUE_SPARSE_BINDING_BIT: + return "VK_QUEUE_SPARSE_BINDING_BIT"; + case VK_QUEUE_TRANSFER_BIT: + return "VK_QUEUE_TRANSFER_BIT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_QUEUE_VIDEO_DECODE_BIT_KHR: + return "VK_QUEUE_VIDEO_DECODE_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_QUEUE_VIDEO_ENCODE_BIT_KHR: + return "VK_QUEUE_VIDEO_ENCODE_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkQueueFlagBits"; + } +} + +static inline std::string string_VkQueueFlags(VkQueueFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkQueueFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkQueueFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkDeviceQueueCreateFlagBits(VkDeviceQueueCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT: + return "VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT"; + default: + return "Unhandled VkDeviceQueueCreateFlagBits"; + } +} + +static inline std::string string_VkDeviceQueueCreateFlags(VkDeviceQueueCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDeviceQueueCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDeviceQueueCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkPipelineStageFlagBits(VkPipelineStageFlagBits input_value) +{ + switch (input_value) + { + case VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR: + return "VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR"; + case VK_PIPELINE_STAGE_ALL_COMMANDS_BIT: + return "VK_PIPELINE_STAGE_ALL_COMMANDS_BIT"; + case VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT: + return "VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT"; + case VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT: + return "VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT"; + case VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT: + return "VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT"; + case VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV: + return "VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV"; + case VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT: + return "VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT"; + case VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT: + return "VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT"; + case VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT: + return "VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT"; + case VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT: + return "VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT"; + case VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT: + return "VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT"; + case VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT: + return "VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT"; + case VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR: + return "VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"; + case VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT: + return "VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT"; + case VK_PIPELINE_STAGE_HOST_BIT: + return "VK_PIPELINE_STAGE_HOST_BIT"; + case VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT: + return "VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT"; + case VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV: + return "VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV"; + case VK_PIPELINE_STAGE_NONE_KHR: + return "VK_PIPELINE_STAGE_NONE_KHR"; + case VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR: + return "VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR"; + case VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV: + return "VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV"; + case VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT: + return "VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT"; + case VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT: + return "VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT"; + case VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT: + return "VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT"; + case VK_PIPELINE_STAGE_TRANSFER_BIT: + return "VK_PIPELINE_STAGE_TRANSFER_BIT"; + case VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT: + return "VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT"; + case VK_PIPELINE_STAGE_VERTEX_INPUT_BIT: + return "VK_PIPELINE_STAGE_VERTEX_INPUT_BIT"; + case VK_PIPELINE_STAGE_VERTEX_SHADER_BIT: + return "VK_PIPELINE_STAGE_VERTEX_SHADER_BIT"; + default: + return "Unhandled VkPipelineStageFlagBits"; + } +} + +static inline std::string string_VkPipelineStageFlags(VkPipelineStageFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPipelineStageFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPipelineStageFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSparseMemoryBindFlagBits(VkSparseMemoryBindFlagBits input_value) +{ + switch (input_value) + { + case VK_SPARSE_MEMORY_BIND_METADATA_BIT: + return "VK_SPARSE_MEMORY_BIND_METADATA_BIT"; + default: + return "Unhandled VkSparseMemoryBindFlagBits"; + } +} + +static inline std::string string_VkSparseMemoryBindFlags(VkSparseMemoryBindFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSparseMemoryBindFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSparseMemoryBindFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSparseImageFormatFlagBits(VkSparseImageFormatFlagBits input_value) +{ + switch (input_value) + { + case VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT: + return "VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT"; + case VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT: + return "VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT"; + case VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT: + return "VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT"; + default: + return "Unhandled VkSparseImageFormatFlagBits"; + } +} + +static inline std::string string_VkSparseImageFormatFlags(VkSparseImageFormatFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSparseImageFormatFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSparseImageFormatFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkFenceCreateFlagBits(VkFenceCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_FENCE_CREATE_SIGNALED_BIT: + return "VK_FENCE_CREATE_SIGNALED_BIT"; + default: + return "Unhandled VkFenceCreateFlagBits"; + } +} + +static inline std::string string_VkFenceCreateFlags(VkFenceCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkFenceCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkFenceCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkEventCreateFlagBits(VkEventCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR: + return "VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR"; + default: + return "Unhandled VkEventCreateFlagBits"; + } +} + +static inline std::string string_VkEventCreateFlags(VkEventCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkEventCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkEventCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkQueryPipelineStatisticFlagBits(VkQueryPipelineStatisticFlagBits input_value) +{ + switch (input_value) + { + case VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT"; + case VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT: + return "VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT"; + default: + return "Unhandled VkQueryPipelineStatisticFlagBits"; + } +} + +static inline std::string string_VkQueryPipelineStatisticFlags(VkQueryPipelineStatisticFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkQueryPipelineStatisticFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkQueryPipelineStatisticFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkQueryType(VkQueryType input_value) +{ + switch (input_value) + { + case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR: + return "VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR"; + case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV: + return "VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV"; + case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR: + return "VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR"; + case VK_QUERY_TYPE_OCCLUSION: + return "VK_QUERY_TYPE_OCCLUSION"; + case VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL: + return "VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL"; + case VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR: + return "VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR"; + case VK_QUERY_TYPE_PIPELINE_STATISTICS: + return "VK_QUERY_TYPE_PIPELINE_STATISTICS"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR: + return "VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + case VK_QUERY_TYPE_TIMESTAMP: + return "VK_QUERY_TYPE_TIMESTAMP"; + case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT: + return "VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_QUERY_TYPE_VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR: + return "VK_QUERY_TYPE_VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkQueryType"; + } +} + +static inline const char* string_VkQueryResultFlagBits(VkQueryResultFlagBits input_value) +{ + switch (input_value) + { + case VK_QUERY_RESULT_64_BIT: + return "VK_QUERY_RESULT_64_BIT"; + case VK_QUERY_RESULT_PARTIAL_BIT: + return "VK_QUERY_RESULT_PARTIAL_BIT"; + case VK_QUERY_RESULT_WAIT_BIT: + return "VK_QUERY_RESULT_WAIT_BIT"; + case VK_QUERY_RESULT_WITH_AVAILABILITY_BIT: + return "VK_QUERY_RESULT_WITH_AVAILABILITY_BIT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_QUERY_RESULT_WITH_STATUS_BIT_KHR: + return "VK_QUERY_RESULT_WITH_STATUS_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkQueryResultFlagBits"; + } +} + +static inline std::string string_VkQueryResultFlags(VkQueryResultFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkQueryResultFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkQueryResultFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkBufferCreateFlagBits(VkBufferCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT: + return "VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT"; + case VK_BUFFER_CREATE_PROTECTED_BIT: + return "VK_BUFFER_CREATE_PROTECTED_BIT"; + case VK_BUFFER_CREATE_SPARSE_ALIASED_BIT: + return "VK_BUFFER_CREATE_SPARSE_ALIASED_BIT"; + case VK_BUFFER_CREATE_SPARSE_BINDING_BIT: + return "VK_BUFFER_CREATE_SPARSE_BINDING_BIT"; + case VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT: + return "VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT"; + default: + return "Unhandled VkBufferCreateFlagBits"; + } +} + +static inline std::string string_VkBufferCreateFlags(VkBufferCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkBufferCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkBufferCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkBufferUsageFlagBits(VkBufferUsageFlagBits input_value) +{ + switch (input_value) + { + case VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR: + return "VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR"; + case VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR: + return "VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR"; + case VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT: + return "VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT"; + case VK_BUFFER_USAGE_INDEX_BUFFER_BIT: + return "VK_BUFFER_USAGE_INDEX_BUFFER_BIT"; + case VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT: + return "VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT"; + case VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR: + return "VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR"; + case VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT: + return "VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT"; + case VK_BUFFER_USAGE_STORAGE_BUFFER_BIT: + return "VK_BUFFER_USAGE_STORAGE_BUFFER_BIT"; + case VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT: + return "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT"; + case VK_BUFFER_USAGE_TRANSFER_DST_BIT: + return "VK_BUFFER_USAGE_TRANSFER_DST_BIT"; + case VK_BUFFER_USAGE_TRANSFER_SRC_BIT: + return "VK_BUFFER_USAGE_TRANSFER_SRC_BIT"; + case VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT: + return "VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT"; + case VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT: + return "VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT"; + case VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT: + return "VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT"; + case VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT: + return "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT"; + case VK_BUFFER_USAGE_VERTEX_BUFFER_BIT: + return "VK_BUFFER_USAGE_VERTEX_BUFFER_BIT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR: + return "VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR: + return "VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR: + return "VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR: + return "VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkBufferUsageFlagBits"; + } +} + +static inline std::string string_VkBufferUsageFlags(VkBufferUsageFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkBufferUsageFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkBufferUsageFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSharingMode(VkSharingMode input_value) +{ + switch (input_value) + { + case VK_SHARING_MODE_CONCURRENT: + return "VK_SHARING_MODE_CONCURRENT"; + case VK_SHARING_MODE_EXCLUSIVE: + return "VK_SHARING_MODE_EXCLUSIVE"; + default: + return "Unhandled VkSharingMode"; + } +} + +static inline const char* string_VkComponentSwizzle(VkComponentSwizzle input_value) +{ + switch (input_value) + { + case VK_COMPONENT_SWIZZLE_A: + return "VK_COMPONENT_SWIZZLE_A"; + case VK_COMPONENT_SWIZZLE_B: + return "VK_COMPONENT_SWIZZLE_B"; + case VK_COMPONENT_SWIZZLE_G: + return "VK_COMPONENT_SWIZZLE_G"; + case VK_COMPONENT_SWIZZLE_IDENTITY: + return "VK_COMPONENT_SWIZZLE_IDENTITY"; + case VK_COMPONENT_SWIZZLE_ONE: + return "VK_COMPONENT_SWIZZLE_ONE"; + case VK_COMPONENT_SWIZZLE_R: + return "VK_COMPONENT_SWIZZLE_R"; + case VK_COMPONENT_SWIZZLE_ZERO: + return "VK_COMPONENT_SWIZZLE_ZERO"; + default: + return "Unhandled VkComponentSwizzle"; + } +} + +static inline const char* string_VkImageViewCreateFlagBits(VkImageViewCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT: + return "VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT"; + case VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT: + return "VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT"; + default: + return "Unhandled VkImageViewCreateFlagBits"; + } +} + +static inline std::string string_VkImageViewCreateFlags(VkImageViewCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkImageViewCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkImageViewCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkImageViewType(VkImageViewType input_value) +{ + switch (input_value) + { + case VK_IMAGE_VIEW_TYPE_1D: + return "VK_IMAGE_VIEW_TYPE_1D"; + case VK_IMAGE_VIEW_TYPE_1D_ARRAY: + return "VK_IMAGE_VIEW_TYPE_1D_ARRAY"; + case VK_IMAGE_VIEW_TYPE_2D: + return "VK_IMAGE_VIEW_TYPE_2D"; + case VK_IMAGE_VIEW_TYPE_2D_ARRAY: + return "VK_IMAGE_VIEW_TYPE_2D_ARRAY"; + case VK_IMAGE_VIEW_TYPE_3D: + return "VK_IMAGE_VIEW_TYPE_3D"; + case VK_IMAGE_VIEW_TYPE_CUBE: + return "VK_IMAGE_VIEW_TYPE_CUBE"; + case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: + return "VK_IMAGE_VIEW_TYPE_CUBE_ARRAY"; + default: + return "Unhandled VkImageViewType"; + } +} + +static inline const char* string_VkPipelineCacheCreateFlagBits(VkPipelineCacheCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT: + return "VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT"; + default: + return "Unhandled VkPipelineCacheCreateFlagBits"; + } +} + +static inline std::string string_VkPipelineCacheCreateFlags(VkPipelineCacheCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPipelineCacheCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPipelineCacheCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkBlendFactor(VkBlendFactor input_value) +{ + switch (input_value) + { + case VK_BLEND_FACTOR_CONSTANT_ALPHA: + return "VK_BLEND_FACTOR_CONSTANT_ALPHA"; + case VK_BLEND_FACTOR_CONSTANT_COLOR: + return "VK_BLEND_FACTOR_CONSTANT_COLOR"; + case VK_BLEND_FACTOR_DST_ALPHA: + return "VK_BLEND_FACTOR_DST_ALPHA"; + case VK_BLEND_FACTOR_DST_COLOR: + return "VK_BLEND_FACTOR_DST_COLOR"; + case VK_BLEND_FACTOR_ONE: + return "VK_BLEND_FACTOR_ONE"; + case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: + return "VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA"; + case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: + return "VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR"; + case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: + return "VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA"; + case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR: + return "VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR"; + case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA: + return "VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA"; + case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR: + return "VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR"; + case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: + return "VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA"; + case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: + return "VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR"; + case VK_BLEND_FACTOR_SRC1_ALPHA: + return "VK_BLEND_FACTOR_SRC1_ALPHA"; + case VK_BLEND_FACTOR_SRC1_COLOR: + return "VK_BLEND_FACTOR_SRC1_COLOR"; + case VK_BLEND_FACTOR_SRC_ALPHA: + return "VK_BLEND_FACTOR_SRC_ALPHA"; + case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE: + return "VK_BLEND_FACTOR_SRC_ALPHA_SATURATE"; + case VK_BLEND_FACTOR_SRC_COLOR: + return "VK_BLEND_FACTOR_SRC_COLOR"; + case VK_BLEND_FACTOR_ZERO: + return "VK_BLEND_FACTOR_ZERO"; + default: + return "Unhandled VkBlendFactor"; + } +} + +static inline const char* string_VkBlendOp(VkBlendOp input_value) +{ + switch (input_value) + { + case VK_BLEND_OP_ADD: + return "VK_BLEND_OP_ADD"; + case VK_BLEND_OP_BLUE_EXT: + return "VK_BLEND_OP_BLUE_EXT"; + case VK_BLEND_OP_COLORBURN_EXT: + return "VK_BLEND_OP_COLORBURN_EXT"; + case VK_BLEND_OP_COLORDODGE_EXT: + return "VK_BLEND_OP_COLORDODGE_EXT"; + case VK_BLEND_OP_CONTRAST_EXT: + return "VK_BLEND_OP_CONTRAST_EXT"; + case VK_BLEND_OP_DARKEN_EXT: + return "VK_BLEND_OP_DARKEN_EXT"; + case VK_BLEND_OP_DIFFERENCE_EXT: + return "VK_BLEND_OP_DIFFERENCE_EXT"; + case VK_BLEND_OP_DST_ATOP_EXT: + return "VK_BLEND_OP_DST_ATOP_EXT"; + case VK_BLEND_OP_DST_EXT: + return "VK_BLEND_OP_DST_EXT"; + case VK_BLEND_OP_DST_IN_EXT: + return "VK_BLEND_OP_DST_IN_EXT"; + case VK_BLEND_OP_DST_OUT_EXT: + return "VK_BLEND_OP_DST_OUT_EXT"; + case VK_BLEND_OP_DST_OVER_EXT: + return "VK_BLEND_OP_DST_OVER_EXT"; + case VK_BLEND_OP_EXCLUSION_EXT: + return "VK_BLEND_OP_EXCLUSION_EXT"; + case VK_BLEND_OP_GREEN_EXT: + return "VK_BLEND_OP_GREEN_EXT"; + case VK_BLEND_OP_HARDLIGHT_EXT: + return "VK_BLEND_OP_HARDLIGHT_EXT"; + case VK_BLEND_OP_HARDMIX_EXT: + return "VK_BLEND_OP_HARDMIX_EXT"; + case VK_BLEND_OP_HSL_COLOR_EXT: + return "VK_BLEND_OP_HSL_COLOR_EXT"; + case VK_BLEND_OP_HSL_HUE_EXT: + return "VK_BLEND_OP_HSL_HUE_EXT"; + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: + return "VK_BLEND_OP_HSL_LUMINOSITY_EXT"; + case VK_BLEND_OP_HSL_SATURATION_EXT: + return "VK_BLEND_OP_HSL_SATURATION_EXT"; + case VK_BLEND_OP_INVERT_EXT: + return "VK_BLEND_OP_INVERT_EXT"; + case VK_BLEND_OP_INVERT_OVG_EXT: + return "VK_BLEND_OP_INVERT_OVG_EXT"; + case VK_BLEND_OP_INVERT_RGB_EXT: + return "VK_BLEND_OP_INVERT_RGB_EXT"; + case VK_BLEND_OP_LIGHTEN_EXT: + return "VK_BLEND_OP_LIGHTEN_EXT"; + case VK_BLEND_OP_LINEARBURN_EXT: + return "VK_BLEND_OP_LINEARBURN_EXT"; + case VK_BLEND_OP_LINEARDODGE_EXT: + return "VK_BLEND_OP_LINEARDODGE_EXT"; + case VK_BLEND_OP_LINEARLIGHT_EXT: + return "VK_BLEND_OP_LINEARLIGHT_EXT"; + case VK_BLEND_OP_MAX: + return "VK_BLEND_OP_MAX"; + case VK_BLEND_OP_MIN: + return "VK_BLEND_OP_MIN"; + case VK_BLEND_OP_MINUS_CLAMPED_EXT: + return "VK_BLEND_OP_MINUS_CLAMPED_EXT"; + case VK_BLEND_OP_MINUS_EXT: + return "VK_BLEND_OP_MINUS_EXT"; + case VK_BLEND_OP_MULTIPLY_EXT: + return "VK_BLEND_OP_MULTIPLY_EXT"; + case VK_BLEND_OP_OVERLAY_EXT: + return "VK_BLEND_OP_OVERLAY_EXT"; + case VK_BLEND_OP_PINLIGHT_EXT: + return "VK_BLEND_OP_PINLIGHT_EXT"; + case VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT: + return "VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT"; + case VK_BLEND_OP_PLUS_CLAMPED_EXT: + return "VK_BLEND_OP_PLUS_CLAMPED_EXT"; + case VK_BLEND_OP_PLUS_DARKER_EXT: + return "VK_BLEND_OP_PLUS_DARKER_EXT"; + case VK_BLEND_OP_PLUS_EXT: + return "VK_BLEND_OP_PLUS_EXT"; + case VK_BLEND_OP_RED_EXT: + return "VK_BLEND_OP_RED_EXT"; + case VK_BLEND_OP_REVERSE_SUBTRACT: + return "VK_BLEND_OP_REVERSE_SUBTRACT"; + case VK_BLEND_OP_SCREEN_EXT: + return "VK_BLEND_OP_SCREEN_EXT"; + case VK_BLEND_OP_SOFTLIGHT_EXT: + return "VK_BLEND_OP_SOFTLIGHT_EXT"; + case VK_BLEND_OP_SRC_ATOP_EXT: + return "VK_BLEND_OP_SRC_ATOP_EXT"; + case VK_BLEND_OP_SRC_EXT: + return "VK_BLEND_OP_SRC_EXT"; + case VK_BLEND_OP_SRC_IN_EXT: + return "VK_BLEND_OP_SRC_IN_EXT"; + case VK_BLEND_OP_SRC_OUT_EXT: + return "VK_BLEND_OP_SRC_OUT_EXT"; + case VK_BLEND_OP_SRC_OVER_EXT: + return "VK_BLEND_OP_SRC_OVER_EXT"; + case VK_BLEND_OP_SUBTRACT: + return "VK_BLEND_OP_SUBTRACT"; + case VK_BLEND_OP_VIVIDLIGHT_EXT: + return "VK_BLEND_OP_VIVIDLIGHT_EXT"; + case VK_BLEND_OP_XOR_EXT: + return "VK_BLEND_OP_XOR_EXT"; + case VK_BLEND_OP_ZERO_EXT: + return "VK_BLEND_OP_ZERO_EXT"; + default: + return "Unhandled VkBlendOp"; + } +} + +static inline const char* string_VkColorComponentFlagBits(VkColorComponentFlagBits input_value) +{ + switch (input_value) + { + case VK_COLOR_COMPONENT_A_BIT: + return "VK_COLOR_COMPONENT_A_BIT"; + case VK_COLOR_COMPONENT_B_BIT: + return "VK_COLOR_COMPONENT_B_BIT"; + case VK_COLOR_COMPONENT_G_BIT: + return "VK_COLOR_COMPONENT_G_BIT"; + case VK_COLOR_COMPONENT_R_BIT: + return "VK_COLOR_COMPONENT_R_BIT"; + default: + return "Unhandled VkColorComponentFlagBits"; + } +} + +static inline std::string string_VkColorComponentFlags(VkColorComponentFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkColorComponentFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkColorComponentFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkCompareOp(VkCompareOp input_value) +{ + switch (input_value) + { + case VK_COMPARE_OP_ALWAYS: + return "VK_COMPARE_OP_ALWAYS"; + case VK_COMPARE_OP_EQUAL: + return "VK_COMPARE_OP_EQUAL"; + case VK_COMPARE_OP_GREATER: + return "VK_COMPARE_OP_GREATER"; + case VK_COMPARE_OP_GREATER_OR_EQUAL: + return "VK_COMPARE_OP_GREATER_OR_EQUAL"; + case VK_COMPARE_OP_LESS: + return "VK_COMPARE_OP_LESS"; + case VK_COMPARE_OP_LESS_OR_EQUAL: + return "VK_COMPARE_OP_LESS_OR_EQUAL"; + case VK_COMPARE_OP_NEVER: + return "VK_COMPARE_OP_NEVER"; + case VK_COMPARE_OP_NOT_EQUAL: + return "VK_COMPARE_OP_NOT_EQUAL"; + default: + return "Unhandled VkCompareOp"; + } +} + +static inline const char* string_VkPipelineCreateFlagBits(VkPipelineCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT: + return "VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT"; + case VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR: + return "VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR"; + case VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR: + return "VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR"; + case VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV: + return "VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV"; + case VK_PIPELINE_CREATE_DERIVATIVE_BIT: + return "VK_PIPELINE_CREATE_DERIVATIVE_BIT"; + case VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT: + return "VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT"; + case VK_PIPELINE_CREATE_DISPATCH_BASE_BIT: + return "VK_PIPELINE_CREATE_DISPATCH_BASE_BIT"; + case VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT: + return "VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT"; + case VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT: + return "VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT"; + case VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV: + return "VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV"; + case VK_PIPELINE_CREATE_LIBRARY_BIT_KHR: + return "VK_PIPELINE_CREATE_LIBRARY_BIT_KHR"; + case VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV: + return "VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV"; + case VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR: + return "VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR"; + case VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR: + return "VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR"; + case VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR: + return "VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR"; + case VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR: + return "VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR"; + case VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR: + return "VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR"; + case VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR: + return "VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR"; + case VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR: + return "VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR"; + case VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT: + return "VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT"; + default: + return "Unhandled VkPipelineCreateFlagBits"; + } +} + +static inline std::string string_VkPipelineCreateFlags(VkPipelineCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPipelineCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPipelineCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkPipelineShaderStageCreateFlagBits(VkPipelineShaderStageCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT: + return "VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT"; + case VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT: + return "VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT"; + default: + return "Unhandled VkPipelineShaderStageCreateFlagBits"; + } +} + +static inline std::string string_VkPipelineShaderStageCreateFlags(VkPipelineShaderStageCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPipelineShaderStageCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPipelineShaderStageCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkShaderStageFlagBits(VkShaderStageFlagBits input_value) +{ + switch (input_value) + { + case VK_SHADER_STAGE_ALL: + return "VK_SHADER_STAGE_ALL"; + case VK_SHADER_STAGE_ALL_GRAPHICS: + return "VK_SHADER_STAGE_ALL_GRAPHICS"; + case VK_SHADER_STAGE_ANY_HIT_BIT_KHR: + return "VK_SHADER_STAGE_ANY_HIT_BIT_KHR"; + case VK_SHADER_STAGE_CALLABLE_BIT_KHR: + return "VK_SHADER_STAGE_CALLABLE_BIT_KHR"; + case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR: + return "VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR"; + case VK_SHADER_STAGE_COMPUTE_BIT: + return "VK_SHADER_STAGE_COMPUTE_BIT"; + case VK_SHADER_STAGE_FRAGMENT_BIT: + return "VK_SHADER_STAGE_FRAGMENT_BIT"; + case VK_SHADER_STAGE_GEOMETRY_BIT: + return "VK_SHADER_STAGE_GEOMETRY_BIT"; + case VK_SHADER_STAGE_INTERSECTION_BIT_KHR: + return "VK_SHADER_STAGE_INTERSECTION_BIT_KHR"; + case VK_SHADER_STAGE_MESH_BIT_NV: + return "VK_SHADER_STAGE_MESH_BIT_NV"; + case VK_SHADER_STAGE_MISS_BIT_KHR: + return "VK_SHADER_STAGE_MISS_BIT_KHR"; + case VK_SHADER_STAGE_RAYGEN_BIT_KHR: + return "VK_SHADER_STAGE_RAYGEN_BIT_KHR"; + case VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI: + return "VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI"; + case VK_SHADER_STAGE_TASK_BIT_NV: + return "VK_SHADER_STAGE_TASK_BIT_NV"; + case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: + return "VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT"; + case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: + return "VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT"; + case VK_SHADER_STAGE_VERTEX_BIT: + return "VK_SHADER_STAGE_VERTEX_BIT"; + default: + return "Unhandled VkShaderStageFlagBits"; + } +} + +static inline std::string string_VkShaderStageFlags(VkShaderStageFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkShaderStageFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkShaderStageFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkCullModeFlagBits(VkCullModeFlagBits input_value) +{ + switch (input_value) + { + case VK_CULL_MODE_BACK_BIT: + return "VK_CULL_MODE_BACK_BIT"; + case VK_CULL_MODE_FRONT_AND_BACK: + return "VK_CULL_MODE_FRONT_AND_BACK"; + case VK_CULL_MODE_FRONT_BIT: + return "VK_CULL_MODE_FRONT_BIT"; + case VK_CULL_MODE_NONE: + return "VK_CULL_MODE_NONE"; + default: + return "Unhandled VkCullModeFlagBits"; + } +} + +static inline std::string string_VkCullModeFlags(VkCullModeFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkCullModeFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkCullModeFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkDynamicState(VkDynamicState input_value) +{ + switch (input_value) + { + case VK_DYNAMIC_STATE_BLEND_CONSTANTS: + return "VK_DYNAMIC_STATE_BLEND_CONSTANTS"; + case VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT: + return "VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT"; + case VK_DYNAMIC_STATE_CULL_MODE_EXT: + return "VK_DYNAMIC_STATE_CULL_MODE_EXT"; + case VK_DYNAMIC_STATE_DEPTH_BIAS: + return "VK_DYNAMIC_STATE_DEPTH_BIAS"; + case VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT: + return "VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT"; + case VK_DYNAMIC_STATE_DEPTH_BOUNDS: + return "VK_DYNAMIC_STATE_DEPTH_BOUNDS"; + case VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT: + return "VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT"; + case VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT: + return "VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT"; + case VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT: + return "VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT"; + case VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT: + return "VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT"; + case VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT: + return "VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT"; + case VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV: + return "VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV"; + case VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR: + return "VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR"; + case VK_DYNAMIC_STATE_FRONT_FACE_EXT: + return "VK_DYNAMIC_STATE_FRONT_FACE_EXT"; + case VK_DYNAMIC_STATE_LINE_STIPPLE_EXT: + return "VK_DYNAMIC_STATE_LINE_STIPPLE_EXT"; + case VK_DYNAMIC_STATE_LINE_WIDTH: + return "VK_DYNAMIC_STATE_LINE_WIDTH"; + case VK_DYNAMIC_STATE_LOGIC_OP_EXT: + return "VK_DYNAMIC_STATE_LOGIC_OP_EXT"; + case VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT: + return "VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT"; + case VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT: + return "VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT"; + case VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT: + return "VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT"; + case VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT: + return "VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT"; + case VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR: + return "VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR"; + case VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT: + return "VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT"; + case VK_DYNAMIC_STATE_SCISSOR: + return "VK_DYNAMIC_STATE_SCISSOR"; + case VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT: + return "VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT"; + case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: + return "VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK"; + case VK_DYNAMIC_STATE_STENCIL_OP_EXT: + return "VK_DYNAMIC_STATE_STENCIL_OP_EXT"; + case VK_DYNAMIC_STATE_STENCIL_REFERENCE: + return "VK_DYNAMIC_STATE_STENCIL_REFERENCE"; + case VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT: + return "VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT"; + case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK: + return "VK_DYNAMIC_STATE_STENCIL_WRITE_MASK"; + case VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT: + return "VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT"; + case VK_DYNAMIC_STATE_VERTEX_INPUT_EXT: + return "VK_DYNAMIC_STATE_VERTEX_INPUT_EXT"; + case VK_DYNAMIC_STATE_VIEWPORT: + return "VK_DYNAMIC_STATE_VIEWPORT"; + case VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV: + return "VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV"; + case VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV: + return "VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV"; + case VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT: + return "VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT"; + case VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV: + return "VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV"; + default: + return "Unhandled VkDynamicState"; + } +} + +static inline const char* string_VkFrontFace(VkFrontFace input_value) +{ + switch (input_value) + { + case VK_FRONT_FACE_CLOCKWISE: + return "VK_FRONT_FACE_CLOCKWISE"; + case VK_FRONT_FACE_COUNTER_CLOCKWISE: + return "VK_FRONT_FACE_COUNTER_CLOCKWISE"; + default: + return "Unhandled VkFrontFace"; + } +} + +static inline const char* string_VkVertexInputRate(VkVertexInputRate input_value) +{ + switch (input_value) + { + case VK_VERTEX_INPUT_RATE_INSTANCE: + return "VK_VERTEX_INPUT_RATE_INSTANCE"; + case VK_VERTEX_INPUT_RATE_VERTEX: + return "VK_VERTEX_INPUT_RATE_VERTEX"; + default: + return "Unhandled VkVertexInputRate"; + } +} + +static inline const char* string_VkPrimitiveTopology(VkPrimitiveTopology input_value) +{ + switch (input_value) + { + case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: + return "VK_PRIMITIVE_TOPOLOGY_LINE_LIST"; + case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: + return "VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY"; + case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: + return "VK_PRIMITIVE_TOPOLOGY_LINE_STRIP"; + case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: + return "VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY"; + case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: + return "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST"; + case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: + return "VK_PRIMITIVE_TOPOLOGY_POINT_LIST"; + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: + return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN"; + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: + return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST"; + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: + return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY"; + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: + return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP"; + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: + return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY"; + default: + return "Unhandled VkPrimitiveTopology"; + } +} + +static inline const char* string_VkPolygonMode(VkPolygonMode input_value) +{ + switch (input_value) + { + case VK_POLYGON_MODE_FILL: + return "VK_POLYGON_MODE_FILL"; + case VK_POLYGON_MODE_FILL_RECTANGLE_NV: + return "VK_POLYGON_MODE_FILL_RECTANGLE_NV"; + case VK_POLYGON_MODE_LINE: + return "VK_POLYGON_MODE_LINE"; + case VK_POLYGON_MODE_POINT: + return "VK_POLYGON_MODE_POINT"; + default: + return "Unhandled VkPolygonMode"; + } +} + +static inline const char* string_VkStencilOp(VkStencilOp input_value) +{ + switch (input_value) + { + case VK_STENCIL_OP_DECREMENT_AND_CLAMP: + return "VK_STENCIL_OP_DECREMENT_AND_CLAMP"; + case VK_STENCIL_OP_DECREMENT_AND_WRAP: + return "VK_STENCIL_OP_DECREMENT_AND_WRAP"; + case VK_STENCIL_OP_INCREMENT_AND_CLAMP: + return "VK_STENCIL_OP_INCREMENT_AND_CLAMP"; + case VK_STENCIL_OP_INCREMENT_AND_WRAP: + return "VK_STENCIL_OP_INCREMENT_AND_WRAP"; + case VK_STENCIL_OP_INVERT: + return "VK_STENCIL_OP_INVERT"; + case VK_STENCIL_OP_KEEP: + return "VK_STENCIL_OP_KEEP"; + case VK_STENCIL_OP_REPLACE: + return "VK_STENCIL_OP_REPLACE"; + case VK_STENCIL_OP_ZERO: + return "VK_STENCIL_OP_ZERO"; + default: + return "Unhandled VkStencilOp"; + } +} + +static inline const char* string_VkLogicOp(VkLogicOp input_value) +{ + switch (input_value) + { + case VK_LOGIC_OP_AND: + return "VK_LOGIC_OP_AND"; + case VK_LOGIC_OP_AND_INVERTED: + return "VK_LOGIC_OP_AND_INVERTED"; + case VK_LOGIC_OP_AND_REVERSE: + return "VK_LOGIC_OP_AND_REVERSE"; + case VK_LOGIC_OP_CLEAR: + return "VK_LOGIC_OP_CLEAR"; + case VK_LOGIC_OP_COPY: + return "VK_LOGIC_OP_COPY"; + case VK_LOGIC_OP_COPY_INVERTED: + return "VK_LOGIC_OP_COPY_INVERTED"; + case VK_LOGIC_OP_EQUIVALENT: + return "VK_LOGIC_OP_EQUIVALENT"; + case VK_LOGIC_OP_INVERT: + return "VK_LOGIC_OP_INVERT"; + case VK_LOGIC_OP_NAND: + return "VK_LOGIC_OP_NAND"; + case VK_LOGIC_OP_NOR: + return "VK_LOGIC_OP_NOR"; + case VK_LOGIC_OP_NO_OP: + return "VK_LOGIC_OP_NO_OP"; + case VK_LOGIC_OP_OR: + return "VK_LOGIC_OP_OR"; + case VK_LOGIC_OP_OR_INVERTED: + return "VK_LOGIC_OP_OR_INVERTED"; + case VK_LOGIC_OP_OR_REVERSE: + return "VK_LOGIC_OP_OR_REVERSE"; + case VK_LOGIC_OP_SET: + return "VK_LOGIC_OP_SET"; + case VK_LOGIC_OP_XOR: + return "VK_LOGIC_OP_XOR"; + default: + return "Unhandled VkLogicOp"; + } +} + +static inline const char* string_VkBorderColor(VkBorderColor input_value) +{ + switch (input_value) + { + case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT: + return "VK_BORDER_COLOR_FLOAT_CUSTOM_EXT"; + case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK: + return "VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK"; + case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE: + return "VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE"; + case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: + return "VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK"; + case VK_BORDER_COLOR_INT_CUSTOM_EXT: + return "VK_BORDER_COLOR_INT_CUSTOM_EXT"; + case VK_BORDER_COLOR_INT_OPAQUE_BLACK: + return "VK_BORDER_COLOR_INT_OPAQUE_BLACK"; + case VK_BORDER_COLOR_INT_OPAQUE_WHITE: + return "VK_BORDER_COLOR_INT_OPAQUE_WHITE"; + case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK: + return "VK_BORDER_COLOR_INT_TRANSPARENT_BLACK"; + default: + return "Unhandled VkBorderColor"; + } +} + +static inline const char* string_VkFilter(VkFilter input_value) +{ + switch (input_value) + { + case VK_FILTER_CUBIC_IMG: + return "VK_FILTER_CUBIC_IMG"; + case VK_FILTER_LINEAR: + return "VK_FILTER_LINEAR"; + case VK_FILTER_NEAREST: + return "VK_FILTER_NEAREST"; + default: + return "Unhandled VkFilter"; + } +} + +static inline const char* string_VkSamplerAddressMode(VkSamplerAddressMode input_value) +{ + switch (input_value) + { + case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + return "VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER"; + case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + return "VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE"; + case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + return "VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT"; + case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: + return "VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE"; + case VK_SAMPLER_ADDRESS_MODE_REPEAT: + return "VK_SAMPLER_ADDRESS_MODE_REPEAT"; + default: + return "Unhandled VkSamplerAddressMode"; + } +} + +static inline const char* string_VkSamplerCreateFlagBits(VkSamplerCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT: + return "VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT"; + case VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT: + return "VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT"; + default: + return "Unhandled VkSamplerCreateFlagBits"; + } +} + +static inline std::string string_VkSamplerCreateFlags(VkSamplerCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSamplerCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSamplerCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSamplerMipmapMode(VkSamplerMipmapMode input_value) +{ + switch (input_value) + { + case VK_SAMPLER_MIPMAP_MODE_LINEAR: + return "VK_SAMPLER_MIPMAP_MODE_LINEAR"; + case VK_SAMPLER_MIPMAP_MODE_NEAREST: + return "VK_SAMPLER_MIPMAP_MODE_NEAREST"; + default: + return "Unhandled VkSamplerMipmapMode"; + } +} + +static inline const char* string_VkDescriptorPoolCreateFlagBits(VkDescriptorPoolCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT: + return "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT"; + case VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE: + return "VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE"; + case VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT: + return "VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT"; + default: + return "Unhandled VkDescriptorPoolCreateFlagBits"; + } +} + +static inline std::string string_VkDescriptorPoolCreateFlags(VkDescriptorPoolCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDescriptorPoolCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDescriptorPoolCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkDescriptorType(VkDescriptorType input_value) +{ + switch (input_value) + { + case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: + return "VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR"; + case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV: + return "VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV"; + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + return "VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER"; + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: + return "VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT"; + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + return "VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT"; + case VK_DESCRIPTOR_TYPE_MUTABLE_VALVE: + return "VK_DESCRIPTOR_TYPE_MUTABLE_VALVE"; + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + return "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE"; + case VK_DESCRIPTOR_TYPE_SAMPLER: + return "VK_DESCRIPTOR_TYPE_SAMPLER"; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + return "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER"; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + return "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC"; + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + return "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"; + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + return "VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER"; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + return "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER"; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + return "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC"; + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + return "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER"; + default: + return "Unhandled VkDescriptorType"; + } +} + +static inline const char* string_VkDescriptorSetLayoutCreateFlagBits(VkDescriptorSetLayoutCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE: + return "VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE"; + case VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR: + return "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR"; + case VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT: + return "VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT"; + default: + return "Unhandled VkDescriptorSetLayoutCreateFlagBits"; + } +} + +static inline std::string string_VkDescriptorSetLayoutCreateFlags(VkDescriptorSetLayoutCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDescriptorSetLayoutCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDescriptorSetLayoutCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkAttachmentDescriptionFlagBits(VkAttachmentDescriptionFlagBits input_value) +{ + switch (input_value) + { + case VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT: + return "VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT"; + default: + return "Unhandled VkAttachmentDescriptionFlagBits"; + } +} + +static inline std::string string_VkAttachmentDescriptionFlags(VkAttachmentDescriptionFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkAttachmentDescriptionFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkAttachmentDescriptionFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkAttachmentLoadOp(VkAttachmentLoadOp input_value) +{ + switch (input_value) + { + case VK_ATTACHMENT_LOAD_OP_CLEAR: + return "VK_ATTACHMENT_LOAD_OP_CLEAR"; + case VK_ATTACHMENT_LOAD_OP_DONT_CARE: + return "VK_ATTACHMENT_LOAD_OP_DONT_CARE"; + case VK_ATTACHMENT_LOAD_OP_LOAD: + return "VK_ATTACHMENT_LOAD_OP_LOAD"; + case VK_ATTACHMENT_LOAD_OP_NONE_EXT: + return "VK_ATTACHMENT_LOAD_OP_NONE_EXT"; + default: + return "Unhandled VkAttachmentLoadOp"; + } +} + +static inline const char* string_VkAttachmentStoreOp(VkAttachmentStoreOp input_value) +{ + switch (input_value) + { + case VK_ATTACHMENT_STORE_OP_DONT_CARE: + return "VK_ATTACHMENT_STORE_OP_DONT_CARE"; + case VK_ATTACHMENT_STORE_OP_NONE_EXT: + return "VK_ATTACHMENT_STORE_OP_NONE_EXT"; + case VK_ATTACHMENT_STORE_OP_STORE: + return "VK_ATTACHMENT_STORE_OP_STORE"; + default: + return "Unhandled VkAttachmentStoreOp"; + } +} + +static inline const char* string_VkDependencyFlagBits(VkDependencyFlagBits input_value) +{ + switch (input_value) + { + case VK_DEPENDENCY_BY_REGION_BIT: + return "VK_DEPENDENCY_BY_REGION_BIT"; + case VK_DEPENDENCY_DEVICE_GROUP_BIT: + return "VK_DEPENDENCY_DEVICE_GROUP_BIT"; + case VK_DEPENDENCY_VIEW_LOCAL_BIT: + return "VK_DEPENDENCY_VIEW_LOCAL_BIT"; + default: + return "Unhandled VkDependencyFlagBits"; + } +} + +static inline std::string string_VkDependencyFlags(VkDependencyFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDependencyFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDependencyFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkFramebufferCreateFlagBits(VkFramebufferCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT: + return "VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT"; + default: + return "Unhandled VkFramebufferCreateFlagBits"; + } +} + +static inline std::string string_VkFramebufferCreateFlags(VkFramebufferCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkFramebufferCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkFramebufferCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkPipelineBindPoint(VkPipelineBindPoint input_value) +{ + switch (input_value) + { + case VK_PIPELINE_BIND_POINT_COMPUTE: + return "VK_PIPELINE_BIND_POINT_COMPUTE"; + case VK_PIPELINE_BIND_POINT_GRAPHICS: + return "VK_PIPELINE_BIND_POINT_GRAPHICS"; + case VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR: + return "VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR"; + case VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI: + return "VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI"; + default: + return "Unhandled VkPipelineBindPoint"; + } +} + +static inline const char* string_VkRenderPassCreateFlagBits(VkRenderPassCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM: + return "VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM"; + default: + return "Unhandled VkRenderPassCreateFlagBits"; + } +} + +static inline std::string string_VkRenderPassCreateFlags(VkRenderPassCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkRenderPassCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkRenderPassCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSubpassDescriptionFlagBits(VkSubpassDescriptionFlagBits input_value) +{ + switch (input_value) + { + case VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM: + return "VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM"; + case VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX: + return "VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX"; + case VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX: + return "VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX"; + case VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM: + return "VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM"; + default: + return "Unhandled VkSubpassDescriptionFlagBits"; + } +} + +static inline std::string string_VkSubpassDescriptionFlags(VkSubpassDescriptionFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSubpassDescriptionFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSubpassDescriptionFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkCommandPoolCreateFlagBits(VkCommandPoolCreateFlagBits input_value) +{ + switch (input_value) + { + case VK_COMMAND_POOL_CREATE_PROTECTED_BIT: + return "VK_COMMAND_POOL_CREATE_PROTECTED_BIT"; + case VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT: + return "VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT"; + case VK_COMMAND_POOL_CREATE_TRANSIENT_BIT: + return "VK_COMMAND_POOL_CREATE_TRANSIENT_BIT"; + default: + return "Unhandled VkCommandPoolCreateFlagBits"; + } +} + +static inline std::string string_VkCommandPoolCreateFlags(VkCommandPoolCreateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkCommandPoolCreateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkCommandPoolCreateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkCommandPoolResetFlagBits(VkCommandPoolResetFlagBits input_value) +{ + switch (input_value) + { + case VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT: + return "VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT"; + default: + return "Unhandled VkCommandPoolResetFlagBits"; + } +} + +static inline std::string string_VkCommandPoolResetFlags(VkCommandPoolResetFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkCommandPoolResetFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkCommandPoolResetFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkCommandBufferLevel(VkCommandBufferLevel input_value) +{ + switch (input_value) + { + case VK_COMMAND_BUFFER_LEVEL_PRIMARY: + return "VK_COMMAND_BUFFER_LEVEL_PRIMARY"; + case VK_COMMAND_BUFFER_LEVEL_SECONDARY: + return "VK_COMMAND_BUFFER_LEVEL_SECONDARY"; + default: + return "Unhandled VkCommandBufferLevel"; + } +} + +static inline const char* string_VkCommandBufferUsageFlagBits(VkCommandBufferUsageFlagBits input_value) +{ + switch (input_value) + { + case VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT: + return "VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT"; + case VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT: + return "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT"; + case VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT: + return "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT"; + default: + return "Unhandled VkCommandBufferUsageFlagBits"; + } +} + +static inline std::string string_VkCommandBufferUsageFlags(VkCommandBufferUsageFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkCommandBufferUsageFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkCommandBufferUsageFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkQueryControlFlagBits(VkQueryControlFlagBits input_value) +{ + switch (input_value) + { + case VK_QUERY_CONTROL_PRECISE_BIT: + return "VK_QUERY_CONTROL_PRECISE_BIT"; + default: + return "Unhandled VkQueryControlFlagBits"; + } +} + +static inline std::string string_VkQueryControlFlags(VkQueryControlFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkQueryControlFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkQueryControlFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkCommandBufferResetFlagBits(VkCommandBufferResetFlagBits input_value) +{ + switch (input_value) + { + case VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT: + return "VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT"; + default: + return "Unhandled VkCommandBufferResetFlagBits"; + } +} + +static inline std::string string_VkCommandBufferResetFlags(VkCommandBufferResetFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkCommandBufferResetFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkCommandBufferResetFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkIndexType(VkIndexType input_value) +{ + switch (input_value) + { + case VK_INDEX_TYPE_NONE_KHR: + return "VK_INDEX_TYPE_NONE_KHR"; + case VK_INDEX_TYPE_UINT16: + return "VK_INDEX_TYPE_UINT16"; + case VK_INDEX_TYPE_UINT32: + return "VK_INDEX_TYPE_UINT32"; + case VK_INDEX_TYPE_UINT8_EXT: + return "VK_INDEX_TYPE_UINT8_EXT"; + default: + return "Unhandled VkIndexType"; + } +} + +static inline const char* string_VkStencilFaceFlagBits(VkStencilFaceFlagBits input_value) +{ + switch (input_value) + { + case VK_STENCIL_FACE_BACK_BIT: + return "VK_STENCIL_FACE_BACK_BIT"; + case VK_STENCIL_FACE_FRONT_AND_BACK: + return "VK_STENCIL_FACE_FRONT_AND_BACK"; + case VK_STENCIL_FACE_FRONT_BIT: + return "VK_STENCIL_FACE_FRONT_BIT"; + default: + return "Unhandled VkStencilFaceFlagBits"; + } +} + +static inline std::string string_VkStencilFaceFlags(VkStencilFaceFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkStencilFaceFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkStencilFaceFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSubpassContents(VkSubpassContents input_value) +{ + switch (input_value) + { + case VK_SUBPASS_CONTENTS_INLINE: + return "VK_SUBPASS_CONTENTS_INLINE"; + case VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS: + return "VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS"; + default: + return "Unhandled VkSubpassContents"; + } +} + +static inline const char* string_VkSubgroupFeatureFlagBits(VkSubgroupFeatureFlagBits input_value) +{ + switch (input_value) + { + case VK_SUBGROUP_FEATURE_ARITHMETIC_BIT: + return "VK_SUBGROUP_FEATURE_ARITHMETIC_BIT"; + case VK_SUBGROUP_FEATURE_BALLOT_BIT: + return "VK_SUBGROUP_FEATURE_BALLOT_BIT"; + case VK_SUBGROUP_FEATURE_BASIC_BIT: + return "VK_SUBGROUP_FEATURE_BASIC_BIT"; + case VK_SUBGROUP_FEATURE_CLUSTERED_BIT: + return "VK_SUBGROUP_FEATURE_CLUSTERED_BIT"; + case VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV: + return "VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV"; + case VK_SUBGROUP_FEATURE_QUAD_BIT: + return "VK_SUBGROUP_FEATURE_QUAD_BIT"; + case VK_SUBGROUP_FEATURE_SHUFFLE_BIT: + return "VK_SUBGROUP_FEATURE_SHUFFLE_BIT"; + case VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT: + return "VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT"; + case VK_SUBGROUP_FEATURE_VOTE_BIT: + return "VK_SUBGROUP_FEATURE_VOTE_BIT"; + default: + return "Unhandled VkSubgroupFeatureFlagBits"; + } +} + +static inline std::string string_VkSubgroupFeatureFlags(VkSubgroupFeatureFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSubgroupFeatureFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSubgroupFeatureFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkPeerMemoryFeatureFlagBits(VkPeerMemoryFeatureFlagBits input_value) +{ + switch (input_value) + { + case VK_PEER_MEMORY_FEATURE_COPY_DST_BIT: + return "VK_PEER_MEMORY_FEATURE_COPY_DST_BIT"; + case VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT: + return "VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT"; + case VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT: + return "VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT"; + case VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT: + return "VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT"; + default: + return "Unhandled VkPeerMemoryFeatureFlagBits"; + } +} + +static inline std::string string_VkPeerMemoryFeatureFlags(VkPeerMemoryFeatureFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPeerMemoryFeatureFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPeerMemoryFeatureFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkMemoryAllocateFlagBits(VkMemoryAllocateFlagBits input_value) +{ + switch (input_value) + { + case VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT: + return "VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT"; + case VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT: + return "VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT"; + case VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT: + return "VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT"; + default: + return "Unhandled VkMemoryAllocateFlagBits"; + } +} + +static inline std::string string_VkMemoryAllocateFlags(VkMemoryAllocateFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkMemoryAllocateFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkMemoryAllocateFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkPointClippingBehavior(VkPointClippingBehavior input_value) +{ + switch (input_value) + { + case VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES: + return "VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES"; + case VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY: + return "VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY"; + default: + return "Unhandled VkPointClippingBehavior"; + } +} + +static inline const char* string_VkTessellationDomainOrigin(VkTessellationDomainOrigin input_value) +{ + switch (input_value) + { + case VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT: + return "VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT"; + case VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT: + return "VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT"; + default: + return "Unhandled VkTessellationDomainOrigin"; + } +} + +static inline const char* string_VkSamplerYcbcrModelConversion(VkSamplerYcbcrModelConversion input_value) +{ + switch (input_value) + { + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY"; + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020"; + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601"; + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709"; + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY"; + default: + return "Unhandled VkSamplerYcbcrModelConversion"; + } +} + +static inline const char* string_VkSamplerYcbcrRange(VkSamplerYcbcrRange input_value) +{ + switch (input_value) + { + case VK_SAMPLER_YCBCR_RANGE_ITU_FULL: + return "VK_SAMPLER_YCBCR_RANGE_ITU_FULL"; + case VK_SAMPLER_YCBCR_RANGE_ITU_NARROW: + return "VK_SAMPLER_YCBCR_RANGE_ITU_NARROW"; + default: + return "Unhandled VkSamplerYcbcrRange"; + } +} + +static inline const char* string_VkChromaLocation(VkChromaLocation input_value) +{ + switch (input_value) + { + case VK_CHROMA_LOCATION_COSITED_EVEN: + return "VK_CHROMA_LOCATION_COSITED_EVEN"; + case VK_CHROMA_LOCATION_MIDPOINT: + return "VK_CHROMA_LOCATION_MIDPOINT"; + default: + return "Unhandled VkChromaLocation"; + } +} + +static inline const char* string_VkDescriptorUpdateTemplateType(VkDescriptorUpdateTemplateType input_value) +{ + switch (input_value) + { + case VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET: + return "VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET"; + case VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR: + return "VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR"; + default: + return "Unhandled VkDescriptorUpdateTemplateType"; + } +} + +static inline const char* string_VkExternalMemoryHandleTypeFlagBits(VkExternalMemoryHandleTypeFlagBits input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA"; + default: + return "Unhandled VkExternalMemoryHandleTypeFlagBits"; + } +} + +static inline std::string string_VkExternalMemoryHandleTypeFlags(VkExternalMemoryHandleTypeFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalMemoryHandleTypeFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalMemoryHandleTypeFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalMemoryFeatureFlagBits(VkExternalMemoryFeatureFlagBits input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT: + return "VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT"; + case VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT: + return "VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT"; + case VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT: + return "VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT"; + default: + return "Unhandled VkExternalMemoryFeatureFlagBits"; + } +} + +static inline std::string string_VkExternalMemoryFeatureFlags(VkExternalMemoryFeatureFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalMemoryFeatureFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalMemoryFeatureFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalFenceHandleTypeFlagBits(VkExternalFenceHandleTypeFlagBits input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: + return "VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT"; + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return "VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT"; + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + return "VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"; + case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: + return "VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT"; + default: + return "Unhandled VkExternalFenceHandleTypeFlagBits"; + } +} + +static inline std::string string_VkExternalFenceHandleTypeFlags(VkExternalFenceHandleTypeFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalFenceHandleTypeFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalFenceHandleTypeFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalFenceFeatureFlagBits(VkExternalFenceFeatureFlagBits input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT: + return "VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT"; + case VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT: + return "VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT"; + default: + return "Unhandled VkExternalFenceFeatureFlagBits"; + } +} + +static inline std::string string_VkExternalFenceFeatureFlags(VkExternalFenceFeatureFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalFenceFeatureFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalFenceFeatureFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkFenceImportFlagBits(VkFenceImportFlagBits input_value) +{ + switch (input_value) + { + case VK_FENCE_IMPORT_TEMPORARY_BIT: + return "VK_FENCE_IMPORT_TEMPORARY_BIT"; + default: + return "Unhandled VkFenceImportFlagBits"; + } +} + +static inline std::string string_VkFenceImportFlags(VkFenceImportFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkFenceImportFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkFenceImportFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSemaphoreImportFlagBits(VkSemaphoreImportFlagBits input_value) +{ + switch (input_value) + { + case VK_SEMAPHORE_IMPORT_TEMPORARY_BIT: + return "VK_SEMAPHORE_IMPORT_TEMPORARY_BIT"; + default: + return "Unhandled VkSemaphoreImportFlagBits"; + } +} + +static inline std::string string_VkSemaphoreImportFlags(VkSemaphoreImportFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSemaphoreImportFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSemaphoreImportFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalSemaphoreHandleTypeFlagBits(VkExternalSemaphoreHandleTypeFlagBits input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA"; + default: + return "Unhandled VkExternalSemaphoreHandleTypeFlagBits"; + } +} + +static inline std::string string_VkExternalSemaphoreHandleTypeFlags(VkExternalSemaphoreHandleTypeFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalSemaphoreHandleTypeFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalSemaphoreHandleTypeFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalSemaphoreFeatureFlagBits(VkExternalSemaphoreFeatureFlagBits input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT: + return "VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT"; + case VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT: + return "VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT"; + default: + return "Unhandled VkExternalSemaphoreFeatureFlagBits"; + } +} + +static inline std::string string_VkExternalSemaphoreFeatureFlags(VkExternalSemaphoreFeatureFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalSemaphoreFeatureFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalSemaphoreFeatureFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkDriverId(VkDriverId input_value) +{ + switch (input_value) + { + case VK_DRIVER_ID_AMD_OPEN_SOURCE: + return "VK_DRIVER_ID_AMD_OPEN_SOURCE"; + case VK_DRIVER_ID_AMD_PROPRIETARY: + return "VK_DRIVER_ID_AMD_PROPRIETARY"; + case VK_DRIVER_ID_ARM_PROPRIETARY: + return "VK_DRIVER_ID_ARM_PROPRIETARY"; + case VK_DRIVER_ID_BROADCOM_PROPRIETARY: + return "VK_DRIVER_ID_BROADCOM_PROPRIETARY"; + case VK_DRIVER_ID_COREAVI_PROPRIETARY: + return "VK_DRIVER_ID_COREAVI_PROPRIETARY"; + case VK_DRIVER_ID_GGP_PROPRIETARY: + return "VK_DRIVER_ID_GGP_PROPRIETARY"; + case VK_DRIVER_ID_GOOGLE_SWIFTSHADER: + return "VK_DRIVER_ID_GOOGLE_SWIFTSHADER"; + case VK_DRIVER_ID_IMAGINATION_PROPRIETARY: + return "VK_DRIVER_ID_IMAGINATION_PROPRIETARY"; + case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA: + return "VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA"; + case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS: + return "VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS"; + case VK_DRIVER_ID_JUICE_PROPRIETARY: + return "VK_DRIVER_ID_JUICE_PROPRIETARY"; + case VK_DRIVER_ID_MESA_LLVMPIPE: + return "VK_DRIVER_ID_MESA_LLVMPIPE"; + case VK_DRIVER_ID_MESA_RADV: + return "VK_DRIVER_ID_MESA_RADV"; + case VK_DRIVER_ID_MOLTENVK: + return "VK_DRIVER_ID_MOLTENVK"; + case VK_DRIVER_ID_NVIDIA_PROPRIETARY: + return "VK_DRIVER_ID_NVIDIA_PROPRIETARY"; + case VK_DRIVER_ID_QUALCOMM_PROPRIETARY: + return "VK_DRIVER_ID_QUALCOMM_PROPRIETARY"; + case VK_DRIVER_ID_VERISILICON_PROPRIETARY: + return "VK_DRIVER_ID_VERISILICON_PROPRIETARY"; + default: + return "Unhandled VkDriverId"; + } +} + +static inline const char* string_VkShaderFloatControlsIndependence(VkShaderFloatControlsIndependence input_value) +{ + switch (input_value) + { + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY: + return "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY"; + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL: + return "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL"; + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE: + return "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE"; + default: + return "Unhandled VkShaderFloatControlsIndependence"; + } +} + +static inline const char* string_VkResolveModeFlagBits(VkResolveModeFlagBits input_value) +{ + switch (input_value) + { + case VK_RESOLVE_MODE_AVERAGE_BIT: + return "VK_RESOLVE_MODE_AVERAGE_BIT"; + case VK_RESOLVE_MODE_MAX_BIT: + return "VK_RESOLVE_MODE_MAX_BIT"; + case VK_RESOLVE_MODE_MIN_BIT: + return "VK_RESOLVE_MODE_MIN_BIT"; + case VK_RESOLVE_MODE_NONE: + return "VK_RESOLVE_MODE_NONE"; + case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT: + return "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT"; + default: + return "Unhandled VkResolveModeFlagBits"; + } +} + +static inline std::string string_VkResolveModeFlags(VkResolveModeFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkResolveModeFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkResolveModeFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkDescriptorBindingFlagBits(VkDescriptorBindingFlagBits input_value) +{ + switch (input_value) + { + case VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT: + return "VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT"; + case VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT: + return "VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT"; + case VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT: + return "VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT"; + case VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT: + return "VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT"; + default: + return "Unhandled VkDescriptorBindingFlagBits"; + } +} + +static inline std::string string_VkDescriptorBindingFlags(VkDescriptorBindingFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDescriptorBindingFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDescriptorBindingFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSamplerReductionMode(VkSamplerReductionMode input_value) +{ + switch (input_value) + { + case VK_SAMPLER_REDUCTION_MODE_MAX: + return "VK_SAMPLER_REDUCTION_MODE_MAX"; + case VK_SAMPLER_REDUCTION_MODE_MIN: + return "VK_SAMPLER_REDUCTION_MODE_MIN"; + case VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE: + return "VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE"; + default: + return "Unhandled VkSamplerReductionMode"; + } +} + +static inline const char* string_VkSemaphoreType(VkSemaphoreType input_value) +{ + switch (input_value) + { + case VK_SEMAPHORE_TYPE_BINARY: + return "VK_SEMAPHORE_TYPE_BINARY"; + case VK_SEMAPHORE_TYPE_TIMELINE: + return "VK_SEMAPHORE_TYPE_TIMELINE"; + default: + return "Unhandled VkSemaphoreType"; + } +} + +static inline const char* string_VkSemaphoreWaitFlagBits(VkSemaphoreWaitFlagBits input_value) +{ + switch (input_value) + { + case VK_SEMAPHORE_WAIT_ANY_BIT: + return "VK_SEMAPHORE_WAIT_ANY_BIT"; + default: + return "Unhandled VkSemaphoreWaitFlagBits"; + } +} + +static inline std::string string_VkSemaphoreWaitFlags(VkSemaphoreWaitFlags input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSemaphoreWaitFlagBits(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSemaphoreWaitFlagBits(static_cast(0))); + return ret; +} + +static inline const char* string_VkSurfaceTransformFlagBitsKHR(VkSurfaceTransformFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: + return "VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR"; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: + return "VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR"; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: + return "VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR"; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: + return "VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR"; + case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: + return "VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR"; + case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: + return "VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR"; + case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: + return "VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR"; + case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: + return "VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR"; + case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: + return "VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR"; + default: + return "Unhandled VkSurfaceTransformFlagBitsKHR"; + } +} + +static inline std::string string_VkSurfaceTransformFlagsKHR(VkSurfaceTransformFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSurfaceTransformFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSurfaceTransformFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkPresentModeKHR(VkPresentModeKHR input_value) +{ + switch (input_value) + { + case VK_PRESENT_MODE_FIFO_KHR: + return "VK_PRESENT_MODE_FIFO_KHR"; + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + return "VK_PRESENT_MODE_FIFO_RELAXED_KHR"; + case VK_PRESENT_MODE_IMMEDIATE_KHR: + return "VK_PRESENT_MODE_IMMEDIATE_KHR"; + case VK_PRESENT_MODE_MAILBOX_KHR: + return "VK_PRESENT_MODE_MAILBOX_KHR"; + case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: + return "VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR"; + case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: + return "VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR"; + default: + return "Unhandled VkPresentModeKHR"; + } +} + +static inline const char* string_VkColorSpaceKHR(VkColorSpaceKHR input_value) +{ + switch (input_value) + { + case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT: + return "VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT"; + case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT: + return "VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT"; + case VK_COLOR_SPACE_BT2020_LINEAR_EXT: + return "VK_COLOR_SPACE_BT2020_LINEAR_EXT"; + case VK_COLOR_SPACE_BT709_LINEAR_EXT: + return "VK_COLOR_SPACE_BT709_LINEAR_EXT"; + case VK_COLOR_SPACE_BT709_NONLINEAR_EXT: + return "VK_COLOR_SPACE_BT709_NONLINEAR_EXT"; + case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT: + return "VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT"; + case VK_COLOR_SPACE_DISPLAY_NATIVE_AMD: + return "VK_COLOR_SPACE_DISPLAY_NATIVE_AMD"; + case VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT: + return "VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT"; + case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT: + return "VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT"; + case VK_COLOR_SPACE_DOLBYVISION_EXT: + return "VK_COLOR_SPACE_DOLBYVISION_EXT"; + case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT: + return "VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT"; + case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT: + return "VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT"; + case VK_COLOR_SPACE_HDR10_HLG_EXT: + return "VK_COLOR_SPACE_HDR10_HLG_EXT"; + case VK_COLOR_SPACE_HDR10_ST2084_EXT: + return "VK_COLOR_SPACE_HDR10_ST2084_EXT"; + case VK_COLOR_SPACE_PASS_THROUGH_EXT: + return "VK_COLOR_SPACE_PASS_THROUGH_EXT"; + case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: + return "VK_COLOR_SPACE_SRGB_NONLINEAR_KHR"; + default: + return "Unhandled VkColorSpaceKHR"; + } +} + +static inline const char* string_VkCompositeAlphaFlagBitsKHR(VkCompositeAlphaFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR: + return "VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR"; + case VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR: + return "VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR"; + case VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR: + return "VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR"; + case VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR: + return "VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR"; + default: + return "Unhandled VkCompositeAlphaFlagBitsKHR"; + } +} + +static inline std::string string_VkCompositeAlphaFlagsKHR(VkCompositeAlphaFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkCompositeAlphaFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkCompositeAlphaFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkSwapchainCreateFlagBitsKHR(VkSwapchainCreateFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR: + return "VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR"; + case VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR: + return "VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR"; + case VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR: + return "VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR"; + default: + return "Unhandled VkSwapchainCreateFlagBitsKHR"; + } +} + +static inline std::string string_VkSwapchainCreateFlagsKHR(VkSwapchainCreateFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSwapchainCreateFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSwapchainCreateFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkDeviceGroupPresentModeFlagBitsKHR(VkDeviceGroupPresentModeFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR: + return "VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR"; + case VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR: + return "VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR"; + case VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR: + return "VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR"; + case VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR: + return "VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR"; + default: + return "Unhandled VkDeviceGroupPresentModeFlagBitsKHR"; + } +} + +static inline std::string string_VkDeviceGroupPresentModeFlagsKHR(VkDeviceGroupPresentModeFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDeviceGroupPresentModeFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDeviceGroupPresentModeFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkDisplayPlaneAlphaFlagBitsKHR(VkDisplayPlaneAlphaFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR: + return "VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR"; + case VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR: + return "VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR"; + case VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR: + return "VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR"; + case VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR: + return "VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR"; + default: + return "Unhandled VkDisplayPlaneAlphaFlagBitsKHR"; + } +} + +static inline std::string string_VkDisplayPlaneAlphaFlagsKHR(VkDisplayPlaneAlphaFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDisplayPlaneAlphaFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDisplayPlaneAlphaFlagBitsKHR(static_cast(0))); + return ret; +} + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoCodecOperationFlagBitsKHR(VkVideoCodecOperationFlagBitsKHR input_value) +{ + switch (input_value) + { +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_EXT: + return "VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_EXT: + return "VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT: + return "VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT"; +#endif // VK_ENABLE_BETA_EXTENSIONS + case VK_VIDEO_CODEC_OPERATION_INVALID_BIT_KHR: + return "VK_VIDEO_CODEC_OPERATION_INVALID_BIT_KHR"; + default: + return "Unhandled VkVideoCodecOperationFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoCodecOperationFlagsKHR(VkVideoCodecOperationFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoCodecOperationFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoCodecOperationFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoChromaSubsamplingFlagBitsKHR(VkVideoChromaSubsamplingFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR: + return "VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR"; + case VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR: + return "VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR"; + case VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR: + return "VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR"; + case VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_BIT_KHR: + return "VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_BIT_KHR"; + case VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR: + return "VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR"; + default: + return "Unhandled VkVideoChromaSubsamplingFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoChromaSubsamplingFlagsKHR(VkVideoChromaSubsamplingFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoChromaSubsamplingFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoChromaSubsamplingFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoComponentBitDepthFlagBitsKHR(VkVideoComponentBitDepthFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR: + return "VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR"; + case VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR: + return "VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR"; + case VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR: + return "VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR"; + case VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR: + return "VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR"; + default: + return "Unhandled VkVideoComponentBitDepthFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoComponentBitDepthFlagsKHR(VkVideoComponentBitDepthFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoComponentBitDepthFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoComponentBitDepthFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoCapabilityFlagBitsKHR(VkVideoCapabilityFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR: + return "VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR"; + case VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR: + return "VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR"; + default: + return "Unhandled VkVideoCapabilityFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoCapabilityFlagsKHR(VkVideoCapabilityFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoCapabilityFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoCapabilityFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoSessionCreateFlagBitsKHR(VkVideoSessionCreateFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_SESSION_CREATE_DEFAULT_KHR: + return "VK_VIDEO_SESSION_CREATE_DEFAULT_KHR"; + case VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR: + return "VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR"; + default: + return "Unhandled VkVideoSessionCreateFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoSessionCreateFlagsKHR(VkVideoSessionCreateFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoSessionCreateFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoSessionCreateFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoCodingControlFlagBitsKHR(VkVideoCodingControlFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_CODING_CONTROL_DEFAULT_KHR: + return "VK_VIDEO_CODING_CONTROL_DEFAULT_KHR"; + case VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR: + return "VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR"; + default: + return "Unhandled VkVideoCodingControlFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoCodingControlFlagsKHR(VkVideoCodingControlFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoCodingControlFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoCodingControlFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoCodingQualityPresetFlagBitsKHR(VkVideoCodingQualityPresetFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_CODING_QUALITY_PRESET_DEFAULT_BIT_KHR: + return "VK_VIDEO_CODING_QUALITY_PRESET_DEFAULT_BIT_KHR"; + case VK_VIDEO_CODING_QUALITY_PRESET_NORMAL_BIT_KHR: + return "VK_VIDEO_CODING_QUALITY_PRESET_NORMAL_BIT_KHR"; + case VK_VIDEO_CODING_QUALITY_PRESET_POWER_BIT_KHR: + return "VK_VIDEO_CODING_QUALITY_PRESET_POWER_BIT_KHR"; + case VK_VIDEO_CODING_QUALITY_PRESET_QUALITY_BIT_KHR: + return "VK_VIDEO_CODING_QUALITY_PRESET_QUALITY_BIT_KHR"; + default: + return "Unhandled VkVideoCodingQualityPresetFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoCodingQualityPresetFlagsKHR(VkVideoCodingQualityPresetFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoCodingQualityPresetFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoCodingQualityPresetFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkQueryResultStatusKHR(VkQueryResultStatusKHR input_value) +{ + switch (input_value) + { + case VK_QUERY_RESULT_STATUS_COMPLETE_KHR: + return "VK_QUERY_RESULT_STATUS_COMPLETE_KHR"; + case VK_QUERY_RESULT_STATUS_ERROR_KHR: + return "VK_QUERY_RESULT_STATUS_ERROR_KHR"; + case VK_QUERY_RESULT_STATUS_NOT_READY_KHR: + return "VK_QUERY_RESULT_STATUS_NOT_READY_KHR"; + default: + return "Unhandled VkQueryResultStatusKHR"; + } +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoDecodeFlagBitsKHR(VkVideoDecodeFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_DECODE_DEFAULT_KHR: + return "VK_VIDEO_DECODE_DEFAULT_KHR"; + case VK_VIDEO_DECODE_RESERVED_0_BIT_KHR: + return "VK_VIDEO_DECODE_RESERVED_0_BIT_KHR"; + default: + return "Unhandled VkVideoDecodeFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoDecodeFlagsKHR(VkVideoDecodeFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoDecodeFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoDecodeFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkPeerMemoryFeatureFlagBitsKHR(VkPeerMemoryFeatureFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_PEER_MEMORY_FEATURE_COPY_DST_BIT: + return "VK_PEER_MEMORY_FEATURE_COPY_DST_BIT"; + case VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT: + return "VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT"; + case VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT: + return "VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT"; + case VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT: + return "VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT"; + default: + return "Unhandled VkPeerMemoryFeatureFlagBitsKHR"; + } +} + +static inline std::string string_VkPeerMemoryFeatureFlagsKHR(VkPeerMemoryFeatureFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPeerMemoryFeatureFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPeerMemoryFeatureFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkMemoryAllocateFlagBitsKHR(VkMemoryAllocateFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT: + return "VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT"; + case VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT: + return "VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT"; + case VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT: + return "VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT"; + default: + return "Unhandled VkMemoryAllocateFlagBitsKHR"; + } +} + +static inline std::string string_VkMemoryAllocateFlagsKHR(VkMemoryAllocateFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkMemoryAllocateFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkMemoryAllocateFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalMemoryHandleTypeFlagBitsKHR(VkExternalMemoryHandleTypeFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA"; + default: + return "Unhandled VkExternalMemoryHandleTypeFlagBitsKHR"; + } +} + +static inline std::string string_VkExternalMemoryHandleTypeFlagsKHR(VkExternalMemoryHandleTypeFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalMemoryHandleTypeFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalMemoryHandleTypeFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalMemoryFeatureFlagBitsKHR(VkExternalMemoryFeatureFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT: + return "VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT"; + case VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT: + return "VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT"; + case VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT: + return "VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT"; + default: + return "Unhandled VkExternalMemoryFeatureFlagBitsKHR"; + } +} + +static inline std::string string_VkExternalMemoryFeatureFlagsKHR(VkExternalMemoryFeatureFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalMemoryFeatureFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalMemoryFeatureFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalSemaphoreHandleTypeFlagBitsKHR(VkExternalSemaphoreHandleTypeFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT"; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA: + return "VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA"; + default: + return "Unhandled VkExternalSemaphoreHandleTypeFlagBitsKHR"; + } +} + +static inline std::string string_VkExternalSemaphoreHandleTypeFlagsKHR(VkExternalSemaphoreHandleTypeFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalSemaphoreHandleTypeFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalSemaphoreHandleTypeFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalSemaphoreFeatureFlagBitsKHR(VkExternalSemaphoreFeatureFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT: + return "VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT"; + case VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT: + return "VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT"; + default: + return "Unhandled VkExternalSemaphoreFeatureFlagBitsKHR"; + } +} + +static inline std::string string_VkExternalSemaphoreFeatureFlagsKHR(VkExternalSemaphoreFeatureFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalSemaphoreFeatureFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalSemaphoreFeatureFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkSemaphoreImportFlagBitsKHR(VkSemaphoreImportFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_SEMAPHORE_IMPORT_TEMPORARY_BIT: + return "VK_SEMAPHORE_IMPORT_TEMPORARY_BIT"; + default: + return "Unhandled VkSemaphoreImportFlagBitsKHR"; + } +} + +static inline std::string string_VkSemaphoreImportFlagsKHR(VkSemaphoreImportFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSemaphoreImportFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSemaphoreImportFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkDescriptorUpdateTemplateTypeKHR(VkDescriptorUpdateTemplateTypeKHR input_value) +{ + switch (input_value) + { + case VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET: + return "VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET"; + case VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR: + return "VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR"; + default: + return "Unhandled VkDescriptorUpdateTemplateTypeKHR"; + } +} + +static inline const char* string_VkExternalFenceHandleTypeFlagBitsKHR(VkExternalFenceHandleTypeFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: + return "VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT"; + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return "VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT"; + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + return "VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"; + case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: + return "VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT"; + default: + return "Unhandled VkExternalFenceHandleTypeFlagBitsKHR"; + } +} + +static inline std::string string_VkExternalFenceHandleTypeFlagsKHR(VkExternalFenceHandleTypeFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalFenceHandleTypeFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalFenceHandleTypeFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalFenceFeatureFlagBitsKHR(VkExternalFenceFeatureFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT: + return "VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT"; + case VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT: + return "VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT"; + default: + return "Unhandled VkExternalFenceFeatureFlagBitsKHR"; + } +} + +static inline std::string string_VkExternalFenceFeatureFlagsKHR(VkExternalFenceFeatureFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalFenceFeatureFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalFenceFeatureFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkFenceImportFlagBitsKHR(VkFenceImportFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_FENCE_IMPORT_TEMPORARY_BIT: + return "VK_FENCE_IMPORT_TEMPORARY_BIT"; + default: + return "Unhandled VkFenceImportFlagBitsKHR"; + } +} + +static inline std::string string_VkFenceImportFlagsKHR(VkFenceImportFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkFenceImportFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkFenceImportFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkPerformanceCounterUnitKHR(VkPerformanceCounterUnitKHR input_value) +{ + switch (input_value) + { + case VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_BYTES_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_BYTES_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_BYTES_PER_SECOND_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_BYTES_PER_SECOND_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_KELVIN_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_KELVIN_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_NANOSECONDS_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_NANOSECONDS_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR"; + case VK_PERFORMANCE_COUNTER_UNIT_WATTS_KHR: + return "VK_PERFORMANCE_COUNTER_UNIT_WATTS_KHR"; + default: + return "Unhandled VkPerformanceCounterUnitKHR"; + } +} + +static inline const char* string_VkPerformanceCounterScopeKHR(VkPerformanceCounterScopeKHR input_value) +{ + switch (input_value) + { + case VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR: + return "VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR"; + case VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR: + return "VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR"; + case VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR: + return "VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR"; + default: + return "Unhandled VkPerformanceCounterScopeKHR"; + } +} + +static inline const char* string_VkPerformanceCounterStorageKHR(VkPerformanceCounterStorageKHR input_value) +{ + switch (input_value) + { + case VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR: + return "VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR"; + case VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR: + return "VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR"; + case VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR: + return "VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR"; + case VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR: + return "VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR"; + case VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR: + return "VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR"; + case VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR: + return "VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR"; + default: + return "Unhandled VkPerformanceCounterStorageKHR"; + } +} + +static inline const char* string_VkPerformanceCounterDescriptionFlagBitsKHR(VkPerformanceCounterDescriptionFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR: + return "VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR"; + case VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR: + return "VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR"; + default: + return "Unhandled VkPerformanceCounterDescriptionFlagBitsKHR"; + } +} + +static inline std::string string_VkPerformanceCounterDescriptionFlagsKHR(VkPerformanceCounterDescriptionFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPerformanceCounterDescriptionFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPerformanceCounterDescriptionFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkPointClippingBehaviorKHR(VkPointClippingBehaviorKHR input_value) +{ + switch (input_value) + { + case VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES: + return "VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES"; + case VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY: + return "VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY"; + default: + return "Unhandled VkPointClippingBehaviorKHR"; + } +} + +static inline const char* string_VkTessellationDomainOriginKHR(VkTessellationDomainOriginKHR input_value) +{ + switch (input_value) + { + case VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT: + return "VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT"; + case VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT: + return "VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT"; + default: + return "Unhandled VkTessellationDomainOriginKHR"; + } +} + +static inline const char* string_VkSamplerYcbcrModelConversionKHR(VkSamplerYcbcrModelConversionKHR input_value) +{ + switch (input_value) + { + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY"; + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020"; + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601"; + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709"; + case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY: + return "VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY"; + default: + return "Unhandled VkSamplerYcbcrModelConversionKHR"; + } +} + +static inline const char* string_VkSamplerYcbcrRangeKHR(VkSamplerYcbcrRangeKHR input_value) +{ + switch (input_value) + { + case VK_SAMPLER_YCBCR_RANGE_ITU_FULL: + return "VK_SAMPLER_YCBCR_RANGE_ITU_FULL"; + case VK_SAMPLER_YCBCR_RANGE_ITU_NARROW: + return "VK_SAMPLER_YCBCR_RANGE_ITU_NARROW"; + default: + return "Unhandled VkSamplerYcbcrRangeKHR"; + } +} + +static inline const char* string_VkChromaLocationKHR(VkChromaLocationKHR input_value) +{ + switch (input_value) + { + case VK_CHROMA_LOCATION_COSITED_EVEN: + return "VK_CHROMA_LOCATION_COSITED_EVEN"; + case VK_CHROMA_LOCATION_MIDPOINT: + return "VK_CHROMA_LOCATION_MIDPOINT"; + default: + return "Unhandled VkChromaLocationKHR"; + } +} + +static inline const char* string_VkDriverIdKHR(VkDriverIdKHR input_value) +{ + switch (input_value) + { + case VK_DRIVER_ID_AMD_OPEN_SOURCE: + return "VK_DRIVER_ID_AMD_OPEN_SOURCE"; + case VK_DRIVER_ID_AMD_PROPRIETARY: + return "VK_DRIVER_ID_AMD_PROPRIETARY"; + case VK_DRIVER_ID_ARM_PROPRIETARY: + return "VK_DRIVER_ID_ARM_PROPRIETARY"; + case VK_DRIVER_ID_BROADCOM_PROPRIETARY: + return "VK_DRIVER_ID_BROADCOM_PROPRIETARY"; + case VK_DRIVER_ID_COREAVI_PROPRIETARY: + return "VK_DRIVER_ID_COREAVI_PROPRIETARY"; + case VK_DRIVER_ID_GGP_PROPRIETARY: + return "VK_DRIVER_ID_GGP_PROPRIETARY"; + case VK_DRIVER_ID_GOOGLE_SWIFTSHADER: + return "VK_DRIVER_ID_GOOGLE_SWIFTSHADER"; + case VK_DRIVER_ID_IMAGINATION_PROPRIETARY: + return "VK_DRIVER_ID_IMAGINATION_PROPRIETARY"; + case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA: + return "VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA"; + case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS: + return "VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS"; + case VK_DRIVER_ID_JUICE_PROPRIETARY: + return "VK_DRIVER_ID_JUICE_PROPRIETARY"; + case VK_DRIVER_ID_MESA_LLVMPIPE: + return "VK_DRIVER_ID_MESA_LLVMPIPE"; + case VK_DRIVER_ID_MESA_RADV: + return "VK_DRIVER_ID_MESA_RADV"; + case VK_DRIVER_ID_MOLTENVK: + return "VK_DRIVER_ID_MOLTENVK"; + case VK_DRIVER_ID_NVIDIA_PROPRIETARY: + return "VK_DRIVER_ID_NVIDIA_PROPRIETARY"; + case VK_DRIVER_ID_QUALCOMM_PROPRIETARY: + return "VK_DRIVER_ID_QUALCOMM_PROPRIETARY"; + case VK_DRIVER_ID_VERISILICON_PROPRIETARY: + return "VK_DRIVER_ID_VERISILICON_PROPRIETARY"; + default: + return "Unhandled VkDriverIdKHR"; + } +} + +static inline const char* string_VkShaderFloatControlsIndependenceKHR(VkShaderFloatControlsIndependenceKHR input_value) +{ + switch (input_value) + { + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY: + return "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY"; + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL: + return "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL"; + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE: + return "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE"; + default: + return "Unhandled VkShaderFloatControlsIndependenceKHR"; + } +} + +static inline const char* string_VkResolveModeFlagBitsKHR(VkResolveModeFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_RESOLVE_MODE_AVERAGE_BIT: + return "VK_RESOLVE_MODE_AVERAGE_BIT"; + case VK_RESOLVE_MODE_MAX_BIT: + return "VK_RESOLVE_MODE_MAX_BIT"; + case VK_RESOLVE_MODE_MIN_BIT: + return "VK_RESOLVE_MODE_MIN_BIT"; + case VK_RESOLVE_MODE_NONE: + return "VK_RESOLVE_MODE_NONE"; + case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT: + return "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT"; + default: + return "Unhandled VkResolveModeFlagBitsKHR"; + } +} + +static inline std::string string_VkResolveModeFlagsKHR(VkResolveModeFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkResolveModeFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkResolveModeFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkSemaphoreTypeKHR(VkSemaphoreTypeKHR input_value) +{ + switch (input_value) + { + case VK_SEMAPHORE_TYPE_BINARY: + return "VK_SEMAPHORE_TYPE_BINARY"; + case VK_SEMAPHORE_TYPE_TIMELINE: + return "VK_SEMAPHORE_TYPE_TIMELINE"; + default: + return "Unhandled VkSemaphoreTypeKHR"; + } +} + +static inline const char* string_VkSemaphoreWaitFlagBitsKHR(VkSemaphoreWaitFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_SEMAPHORE_WAIT_ANY_BIT: + return "VK_SEMAPHORE_WAIT_ANY_BIT"; + default: + return "Unhandled VkSemaphoreWaitFlagBitsKHR"; + } +} + +static inline std::string string_VkSemaphoreWaitFlagsKHR(VkSemaphoreWaitFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSemaphoreWaitFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSemaphoreWaitFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkFragmentShadingRateCombinerOpKHR(VkFragmentShadingRateCombinerOpKHR input_value) +{ + switch (input_value) + { + case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR: + return "VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR"; + case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR: + return "VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR"; + case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR: + return "VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR"; + case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR: + return "VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR"; + case VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR: + return "VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR"; + default: + return "Unhandled VkFragmentShadingRateCombinerOpKHR"; + } +} + +static inline const char* string_VkPipelineExecutableStatisticFormatKHR(VkPipelineExecutableStatisticFormatKHR input_value) +{ + switch (input_value) + { + case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR: + return "VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR"; + case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR: + return "VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR"; + case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR: + return "VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR"; + case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR: + return "VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR"; + default: + return "Unhandled VkPipelineExecutableStatisticFormatKHR"; + } +} + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoEncodeFlagBitsKHR(VkVideoEncodeFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_ENCODE_DEFAULT_KHR: + return "VK_VIDEO_ENCODE_DEFAULT_KHR"; + case VK_VIDEO_ENCODE_RESERVED_0_BIT_KHR: + return "VK_VIDEO_ENCODE_RESERVED_0_BIT_KHR"; + default: + return "Unhandled VkVideoEncodeFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoEncodeFlagsKHR(VkVideoEncodeFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoEncodeFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoEncodeFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoEncodeRateControlFlagBitsKHR(VkVideoEncodeRateControlFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_ENCODE_RATE_CONTROL_DEFAULT_KHR: + return "VK_VIDEO_ENCODE_RATE_CONTROL_DEFAULT_KHR"; + case VK_VIDEO_ENCODE_RATE_CONTROL_RESET_BIT_KHR: + return "VK_VIDEO_ENCODE_RATE_CONTROL_RESET_BIT_KHR"; + default: + return "Unhandled VkVideoEncodeRateControlFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoEncodeRateControlFlagsKHR(VkVideoEncodeRateControlFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoEncodeRateControlFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoEncodeRateControlFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoEncodeRateControlModeFlagBitsKHR(VkVideoEncodeRateControlModeFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR: + return "VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR"; + case VK_VIDEO_ENCODE_RATE_CONTROL_MODE_NONE_BIT_KHR: + return "VK_VIDEO_ENCODE_RATE_CONTROL_MODE_NONE_BIT_KHR"; + case VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR: + return "VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR"; + default: + return "Unhandled VkVideoEncodeRateControlModeFlagBitsKHR"; + } +} + +static inline std::string string_VkVideoEncodeRateControlModeFlagsKHR(VkVideoEncodeRateControlModeFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoEncodeRateControlModeFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoEncodeRateControlModeFlagBitsKHR(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkPipelineStageFlagBits2KHR(uint64_t input_value) +{ + switch (input_value) + { + case VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR: + return "VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR"; + case VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR: + return "VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR"; + case VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR: + return "VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR"; + case VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR: + return "VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR"; + case VK_PIPELINE_STAGE_2_BLIT_BIT_KHR: + return "VK_PIPELINE_STAGE_2_BLIT_BIT_KHR"; + case VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR: + return "VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR"; + case VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR: + return "VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR"; + case VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR: + return "VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR"; + case VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV: + return "VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV"; + case VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR: + return "VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR"; + case VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT: + return "VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT"; + case VK_PIPELINE_STAGE_2_COPY_BIT_KHR: + return "VK_PIPELINE_STAGE_2_COPY_BIT_KHR"; + case VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR: + return "VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR"; + case VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR: + return "VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR"; + case VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT: + return "VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT"; + case VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR: + return "VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR"; + case VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR: + return "VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"; + case VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR: + return "VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR"; + case VK_PIPELINE_STAGE_2_HOST_BIT_KHR: + return "VK_PIPELINE_STAGE_2_HOST_BIT_KHR"; + case VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR: + return "VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR"; + case VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI: + return "VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI"; + case VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR: + return "VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR"; + case VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV: + return "VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV"; + case VK_PIPELINE_STAGE_2_NONE_KHR: + return "VK_PIPELINE_STAGE_2_NONE_KHR"; + case VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR: + return "VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR"; + case VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR: + return "VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR"; + case VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR: + return "VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR"; + case VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI: + return "VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI"; + case VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV: + return "VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV"; + case VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR: + return "VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR"; + case VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR: + return "VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR"; + case VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR: + return "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR"; + case VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT: + return "VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT"; + case VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR: + return "VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR"; + case VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR: + return "VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR"; + case VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR: + return "VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR: + return "VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR: + return "VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkPipelineStageFlagBits2KHR"; + } +} + +static inline std::string string_VkPipelineStageFlags2KHR(VkPipelineStageFlags2KHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPipelineStageFlagBits2KHR(static_cast(1ULL << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPipelineStageFlagBits2KHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkAccessFlagBits2KHR(uint64_t input_value) +{ + switch (input_value) + { + case VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR: + return "VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR"; + case VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR: + return "VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR"; + case VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR: + return "VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR"; + case VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT: + return "VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT"; + case VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR: + return "VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR"; + case VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV: + return "VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV"; + case VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV: + return "VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV"; + case VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT: + return "VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT"; + case VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR: + return "VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR"; + case VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR: + return "VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR"; + case VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT: + return "VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT"; + case VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR: + return "VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR"; + case VK_ACCESS_2_HOST_READ_BIT_KHR: + return "VK_ACCESS_2_HOST_READ_BIT_KHR"; + case VK_ACCESS_2_HOST_WRITE_BIT_KHR: + return "VK_ACCESS_2_HOST_WRITE_BIT_KHR"; + case VK_ACCESS_2_INDEX_READ_BIT_KHR: + return "VK_ACCESS_2_INDEX_READ_BIT_KHR"; + case VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR: + return "VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR"; + case VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR: + return "VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR"; + case VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI: + return "VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI"; + case VK_ACCESS_2_MEMORY_READ_BIT_KHR: + return "VK_ACCESS_2_MEMORY_READ_BIT_KHR"; + case VK_ACCESS_2_MEMORY_WRITE_BIT_KHR: + return "VK_ACCESS_2_MEMORY_WRITE_BIT_KHR"; + case VK_ACCESS_2_NONE_KHR: + return "VK_ACCESS_2_NONE_KHR"; + case VK_ACCESS_2_SHADER_READ_BIT_KHR: + return "VK_ACCESS_2_SHADER_READ_BIT_KHR"; + case VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR: + return "VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR"; + case VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR: + return "VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR"; + case VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR: + return "VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR"; + case VK_ACCESS_2_SHADER_WRITE_BIT_KHR: + return "VK_ACCESS_2_SHADER_WRITE_BIT_KHR"; + case VK_ACCESS_2_TRANSFER_READ_BIT_KHR: + return "VK_ACCESS_2_TRANSFER_READ_BIT_KHR"; + case VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR: + return "VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR"; + case VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT: + return "VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT"; + case VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT: + return "VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT"; + case VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT: + return "VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT"; + case VK_ACCESS_2_UNIFORM_READ_BIT_KHR: + return "VK_ACCESS_2_UNIFORM_READ_BIT_KHR"; + case VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR: + return "VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR: + return "VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR: + return "VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR: + return "VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR: + return "VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR"; +#endif // VK_ENABLE_BETA_EXTENSIONS + default: + return "Unhandled VkAccessFlagBits2KHR"; + } +} + +static inline std::string string_VkAccessFlags2KHR(VkAccessFlags2KHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkAccessFlagBits2KHR(static_cast(1ULL << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkAccessFlagBits2KHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkSubmitFlagBitsKHR(VkSubmitFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_SUBMIT_PROTECTED_BIT_KHR: + return "VK_SUBMIT_PROTECTED_BIT_KHR"; + default: + return "Unhandled VkSubmitFlagBitsKHR"; + } +} + +static inline std::string string_VkSubmitFlagsKHR(VkSubmitFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSubmitFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSubmitFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkDebugReportFlagBitsEXT(VkDebugReportFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_DEBUG_REPORT_DEBUG_BIT_EXT: + return "VK_DEBUG_REPORT_DEBUG_BIT_EXT"; + case VK_DEBUG_REPORT_ERROR_BIT_EXT: + return "VK_DEBUG_REPORT_ERROR_BIT_EXT"; + case VK_DEBUG_REPORT_INFORMATION_BIT_EXT: + return "VK_DEBUG_REPORT_INFORMATION_BIT_EXT"; + case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT: + return "VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT"; + case VK_DEBUG_REPORT_WARNING_BIT_EXT: + return "VK_DEBUG_REPORT_WARNING_BIT_EXT"; + default: + return "Unhandled VkDebugReportFlagBitsEXT"; + } +} + +static inline std::string string_VkDebugReportFlagsEXT(VkDebugReportFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDebugReportFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDebugReportFlagBitsEXT(static_cast(0))); + return ret; +} + +static inline const char* string_VkDebugReportObjectTypeEXT(VkDebugReportObjectTypeEXT input_value) +{ + switch (input_value) + { + case VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT: + return "VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT"; + default: + return "Unhandled VkDebugReportObjectTypeEXT"; + } +} + +static inline const char* string_VkRasterizationOrderAMD(VkRasterizationOrderAMD input_value) +{ + switch (input_value) + { + case VK_RASTERIZATION_ORDER_RELAXED_AMD: + return "VK_RASTERIZATION_ORDER_RELAXED_AMD"; + case VK_RASTERIZATION_ORDER_STRICT_AMD: + return "VK_RASTERIZATION_ORDER_STRICT_AMD"; + default: + return "Unhandled VkRasterizationOrderAMD"; + } +} + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoEncodeH264CapabilityFlagBitsEXT(VkVideoEncodeH264CapabilityFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_VIDEO_ENCODE_H264_CAPABILITY_CABAC_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_CABAC_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_CAVLC_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_CAVLC_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_CHROMA_QP_OFFSET_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_CHROMA_QP_OFFSET_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_DISABLED_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_DISABLED_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_ENABLED_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_ENABLED_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_PARTIAL_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_PARTIAL_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_EVENLY_DISTRIBUTED_SLICE_SIZE_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_EVENLY_DISTRIBUTED_SLICE_SIZE_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_MULTIPLE_SLICE_PER_FRAME_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_MULTIPLE_SLICE_PER_FRAME_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_SECOND_CHROMA_QP_OFFSET_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_SECOND_CHROMA_QP_OFFSET_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_TRANSFORM_8X8_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_TRANSFORM_8X8_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_CAPABILITY_WEIGHTED_BI_PRED_IMPLICIT_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CAPABILITY_WEIGHTED_BI_PRED_IMPLICIT_BIT_EXT"; + default: + return "Unhandled VkVideoEncodeH264CapabilityFlagBitsEXT"; + } +} + +static inline std::string string_VkVideoEncodeH264CapabilityFlagsEXT(VkVideoEncodeH264CapabilityFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoEncodeH264CapabilityFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoEncodeH264CapabilityFlagBitsEXT(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoEncodeH264InputModeFlagBitsEXT(VkVideoEncodeH264InputModeFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_VIDEO_ENCODE_H264_INPUT_MODE_FRAME_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_INPUT_MODE_FRAME_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_INPUT_MODE_NON_VCL_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_INPUT_MODE_NON_VCL_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_INPUT_MODE_SLICE_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_INPUT_MODE_SLICE_BIT_EXT"; + default: + return "Unhandled VkVideoEncodeH264InputModeFlagBitsEXT"; + } +} + +static inline std::string string_VkVideoEncodeH264InputModeFlagsEXT(VkVideoEncodeH264InputModeFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoEncodeH264InputModeFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoEncodeH264InputModeFlagBitsEXT(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoEncodeH264OutputModeFlagBitsEXT(VkVideoEncodeH264OutputModeFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_VIDEO_ENCODE_H264_OUTPUT_MODE_FRAME_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_OUTPUT_MODE_FRAME_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_OUTPUT_MODE_NON_VCL_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_OUTPUT_MODE_NON_VCL_BIT_EXT"; + case VK_VIDEO_ENCODE_H264_OUTPUT_MODE_SLICE_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_OUTPUT_MODE_SLICE_BIT_EXT"; + default: + return "Unhandled VkVideoEncodeH264OutputModeFlagBitsEXT"; + } +} + +static inline std::string string_VkVideoEncodeH264OutputModeFlagsEXT(VkVideoEncodeH264OutputModeFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoEncodeH264OutputModeFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoEncodeH264OutputModeFlagBitsEXT(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoEncodeH264CreateFlagBitsEXT(VkVideoEncodeH264CreateFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_VIDEO_ENCODE_H264_CREATE_DEFAULT_EXT: + return "VK_VIDEO_ENCODE_H264_CREATE_DEFAULT_EXT"; + case VK_VIDEO_ENCODE_H264_CREATE_RESERVED_0_BIT_EXT: + return "VK_VIDEO_ENCODE_H264_CREATE_RESERVED_0_BIT_EXT"; + default: + return "Unhandled VkVideoEncodeH264CreateFlagBitsEXT"; + } +} + +static inline std::string string_VkVideoEncodeH264CreateFlagsEXT(VkVideoEncodeH264CreateFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoEncodeH264CreateFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoEncodeH264CreateFlagBitsEXT(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + + +#ifdef VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkVideoDecodeH264PictureLayoutFlagBitsEXT(VkVideoDecodeH264PictureLayoutFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_EXT: + return "VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_EXT"; + case VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_SEPARATE_PLANES_BIT_EXT: + return "VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_SEPARATE_PLANES_BIT_EXT"; + case VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_EXT: + return "VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_EXT"; + default: + return "Unhandled VkVideoDecodeH264PictureLayoutFlagBitsEXT"; + } +} + +static inline std::string string_VkVideoDecodeH264PictureLayoutFlagsEXT(VkVideoDecodeH264PictureLayoutFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkVideoDecodeH264PictureLayoutFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkVideoDecodeH264PictureLayoutFlagBitsEXT(static_cast(0))); + return ret; +} +#endif // VK_ENABLE_BETA_EXTENSIONS + +static inline const char* string_VkShaderInfoTypeAMD(VkShaderInfoTypeAMD input_value) +{ + switch (input_value) + { + case VK_SHADER_INFO_TYPE_BINARY_AMD: + return "VK_SHADER_INFO_TYPE_BINARY_AMD"; + case VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD: + return "VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD"; + case VK_SHADER_INFO_TYPE_STATISTICS_AMD: + return "VK_SHADER_INFO_TYPE_STATISTICS_AMD"; + default: + return "Unhandled VkShaderInfoTypeAMD"; + } +} + +static inline const char* string_VkExternalMemoryHandleTypeFlagBitsNV(VkExternalMemoryHandleTypeFlagBitsNV input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV"; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV: + return "VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV"; + default: + return "Unhandled VkExternalMemoryHandleTypeFlagBitsNV"; + } +} + +static inline std::string string_VkExternalMemoryHandleTypeFlagsNV(VkExternalMemoryHandleTypeFlagsNV input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalMemoryHandleTypeFlagBitsNV(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalMemoryHandleTypeFlagBitsNV(static_cast(0))); + return ret; +} + +static inline const char* string_VkExternalMemoryFeatureFlagBitsNV(VkExternalMemoryFeatureFlagBitsNV input_value) +{ + switch (input_value) + { + case VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV: + return "VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV"; + case VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV: + return "VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV"; + case VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV: + return "VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV"; + default: + return "Unhandled VkExternalMemoryFeatureFlagBitsNV"; + } +} + +static inline std::string string_VkExternalMemoryFeatureFlagsNV(VkExternalMemoryFeatureFlagsNV input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkExternalMemoryFeatureFlagBitsNV(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkExternalMemoryFeatureFlagBitsNV(static_cast(0))); + return ret; +} + +static inline const char* string_VkValidationCheckEXT(VkValidationCheckEXT input_value) +{ + switch (input_value) + { + case VK_VALIDATION_CHECK_ALL_EXT: + return "VK_VALIDATION_CHECK_ALL_EXT"; + case VK_VALIDATION_CHECK_SHADERS_EXT: + return "VK_VALIDATION_CHECK_SHADERS_EXT"; + default: + return "Unhandled VkValidationCheckEXT"; + } +} + +static inline const char* string_VkConditionalRenderingFlagBitsEXT(VkConditionalRenderingFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT: + return "VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT"; + default: + return "Unhandled VkConditionalRenderingFlagBitsEXT"; + } +} + +static inline std::string string_VkConditionalRenderingFlagsEXT(VkConditionalRenderingFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkConditionalRenderingFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkConditionalRenderingFlagBitsEXT(static_cast(0))); + return ret; +} + +static inline const char* string_VkSurfaceCounterFlagBitsEXT(VkSurfaceCounterFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_SURFACE_COUNTER_VBLANK_BIT_EXT: + return "VK_SURFACE_COUNTER_VBLANK_BIT_EXT"; + default: + return "Unhandled VkSurfaceCounterFlagBitsEXT"; + } +} + +static inline std::string string_VkSurfaceCounterFlagsEXT(VkSurfaceCounterFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkSurfaceCounterFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkSurfaceCounterFlagBitsEXT(static_cast(0))); + return ret; +} + +static inline const char* string_VkDisplayPowerStateEXT(VkDisplayPowerStateEXT input_value) +{ + switch (input_value) + { + case VK_DISPLAY_POWER_STATE_OFF_EXT: + return "VK_DISPLAY_POWER_STATE_OFF_EXT"; + case VK_DISPLAY_POWER_STATE_ON_EXT: + return "VK_DISPLAY_POWER_STATE_ON_EXT"; + case VK_DISPLAY_POWER_STATE_SUSPEND_EXT: + return "VK_DISPLAY_POWER_STATE_SUSPEND_EXT"; + default: + return "Unhandled VkDisplayPowerStateEXT"; + } +} + +static inline const char* string_VkDeviceEventTypeEXT(VkDeviceEventTypeEXT input_value) +{ + switch (input_value) + { + case VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT: + return "VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT"; + default: + return "Unhandled VkDeviceEventTypeEXT"; + } +} + +static inline const char* string_VkDisplayEventTypeEXT(VkDisplayEventTypeEXT input_value) +{ + switch (input_value) + { + case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT: + return "VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT"; + default: + return "Unhandled VkDisplayEventTypeEXT"; + } +} + +static inline const char* string_VkViewportCoordinateSwizzleNV(VkViewportCoordinateSwizzleNV input_value) +{ + switch (input_value) + { + case VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV: + return "VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV"; + case VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV: + return "VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV"; + case VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV: + return "VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV"; + case VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV: + return "VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV"; + case VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV: + return "VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV"; + case VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV: + return "VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV"; + case VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV: + return "VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV"; + case VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV: + return "VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV"; + default: + return "Unhandled VkViewportCoordinateSwizzleNV"; + } +} + +static inline const char* string_VkDiscardRectangleModeEXT(VkDiscardRectangleModeEXT input_value) +{ + switch (input_value) + { + case VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT: + return "VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT"; + case VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT: + return "VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT"; + default: + return "Unhandled VkDiscardRectangleModeEXT"; + } +} + +static inline const char* string_VkConservativeRasterizationModeEXT(VkConservativeRasterizationModeEXT input_value) +{ + switch (input_value) + { + case VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT: + return "VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT"; + case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT: + return "VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT"; + case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT: + return "VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT"; + default: + return "Unhandled VkConservativeRasterizationModeEXT"; + } +} + +static inline const char* string_VkDebugUtilsMessageSeverityFlagBitsEXT(VkDebugUtilsMessageSeverityFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + return "VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT"; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + return "VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT"; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + return "VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT"; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + return "VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT"; + default: + return "Unhandled VkDebugUtilsMessageSeverityFlagBitsEXT"; + } +} + +static inline std::string string_VkDebugUtilsMessageSeverityFlagsEXT(VkDebugUtilsMessageSeverityFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDebugUtilsMessageSeverityFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDebugUtilsMessageSeverityFlagBitsEXT(static_cast(0))); + return ret; +} + +static inline const char* string_VkDebugUtilsMessageTypeFlagBitsEXT(VkDebugUtilsMessageTypeFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: + return "VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT"; + case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: + return "VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT"; + case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: + return "VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT"; + default: + return "Unhandled VkDebugUtilsMessageTypeFlagBitsEXT"; + } +} + +static inline std::string string_VkDebugUtilsMessageTypeFlagsEXT(VkDebugUtilsMessageTypeFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDebugUtilsMessageTypeFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDebugUtilsMessageTypeFlagBitsEXT(static_cast(0))); + return ret; +} + +static inline const char* string_VkSamplerReductionModeEXT(VkSamplerReductionModeEXT input_value) +{ + switch (input_value) + { + case VK_SAMPLER_REDUCTION_MODE_MAX: + return "VK_SAMPLER_REDUCTION_MODE_MAX"; + case VK_SAMPLER_REDUCTION_MODE_MIN: + return "VK_SAMPLER_REDUCTION_MODE_MIN"; + case VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE: + return "VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE"; + default: + return "Unhandled VkSamplerReductionModeEXT"; + } +} + +static inline const char* string_VkBlendOverlapEXT(VkBlendOverlapEXT input_value) +{ + switch (input_value) + { + case VK_BLEND_OVERLAP_CONJOINT_EXT: + return "VK_BLEND_OVERLAP_CONJOINT_EXT"; + case VK_BLEND_OVERLAP_DISJOINT_EXT: + return "VK_BLEND_OVERLAP_DISJOINT_EXT"; + case VK_BLEND_OVERLAP_UNCORRELATED_EXT: + return "VK_BLEND_OVERLAP_UNCORRELATED_EXT"; + default: + return "Unhandled VkBlendOverlapEXT"; + } +} + +static inline const char* string_VkCoverageModulationModeNV(VkCoverageModulationModeNV input_value) +{ + switch (input_value) + { + case VK_COVERAGE_MODULATION_MODE_ALPHA_NV: + return "VK_COVERAGE_MODULATION_MODE_ALPHA_NV"; + case VK_COVERAGE_MODULATION_MODE_NONE_NV: + return "VK_COVERAGE_MODULATION_MODE_NONE_NV"; + case VK_COVERAGE_MODULATION_MODE_RGBA_NV: + return "VK_COVERAGE_MODULATION_MODE_RGBA_NV"; + case VK_COVERAGE_MODULATION_MODE_RGB_NV: + return "VK_COVERAGE_MODULATION_MODE_RGB_NV"; + default: + return "Unhandled VkCoverageModulationModeNV"; + } +} + +static inline const char* string_VkValidationCacheHeaderVersionEXT(VkValidationCacheHeaderVersionEXT input_value) +{ + switch (input_value) + { + case VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT: + return "VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT"; + default: + return "Unhandled VkValidationCacheHeaderVersionEXT"; + } +} + +static inline const char* string_VkDescriptorBindingFlagBitsEXT(VkDescriptorBindingFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT: + return "VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT"; + case VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT: + return "VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT"; + case VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT: + return "VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT"; + case VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT: + return "VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT"; + default: + return "Unhandled VkDescriptorBindingFlagBitsEXT"; + } +} + +static inline std::string string_VkDescriptorBindingFlagsEXT(VkDescriptorBindingFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDescriptorBindingFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDescriptorBindingFlagBitsEXT(static_cast(0))); + return ret; +} + +static inline const char* string_VkShadingRatePaletteEntryNV(VkShadingRatePaletteEntryNV input_value) +{ + switch (input_value) + { + case VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV"; + case VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV: + return "VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV"; + default: + return "Unhandled VkShadingRatePaletteEntryNV"; + } +} + +static inline const char* string_VkCoarseSampleOrderTypeNV(VkCoarseSampleOrderTypeNV input_value) +{ + switch (input_value) + { + case VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV: + return "VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV"; + case VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV: + return "VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV"; + case VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV: + return "VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV"; + case VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV: + return "VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV"; + default: + return "Unhandled VkCoarseSampleOrderTypeNV"; + } +} + +static inline const char* string_VkRayTracingShaderGroupTypeKHR(VkRayTracingShaderGroupTypeKHR input_value) +{ + switch (input_value) + { + case VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR: + return "VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR"; + case VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR: + return "VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR"; + case VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR: + return "VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR"; + default: + return "Unhandled VkRayTracingShaderGroupTypeKHR"; + } +} + +static inline const char* string_VkRayTracingShaderGroupTypeNV(VkRayTracingShaderGroupTypeNV input_value) +{ + switch (input_value) + { + case VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR: + return "VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR"; + case VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR: + return "VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR"; + case VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR: + return "VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR"; + default: + return "Unhandled VkRayTracingShaderGroupTypeNV"; + } +} + +static inline const char* string_VkGeometryTypeKHR(VkGeometryTypeKHR input_value) +{ + switch (input_value) + { + case VK_GEOMETRY_TYPE_AABBS_KHR: + return "VK_GEOMETRY_TYPE_AABBS_KHR"; + case VK_GEOMETRY_TYPE_INSTANCES_KHR: + return "VK_GEOMETRY_TYPE_INSTANCES_KHR"; + case VK_GEOMETRY_TYPE_TRIANGLES_KHR: + return "VK_GEOMETRY_TYPE_TRIANGLES_KHR"; + default: + return "Unhandled VkGeometryTypeKHR"; + } +} + +static inline const char* string_VkGeometryTypeNV(VkGeometryTypeNV input_value) +{ + switch (input_value) + { + case VK_GEOMETRY_TYPE_AABBS_KHR: + return "VK_GEOMETRY_TYPE_AABBS_KHR"; + case VK_GEOMETRY_TYPE_INSTANCES_KHR: + return "VK_GEOMETRY_TYPE_INSTANCES_KHR"; + case VK_GEOMETRY_TYPE_TRIANGLES_KHR: + return "VK_GEOMETRY_TYPE_TRIANGLES_KHR"; + default: + return "Unhandled VkGeometryTypeNV"; + } +} + +static inline const char* string_VkAccelerationStructureTypeKHR(VkAccelerationStructureTypeKHR input_value) +{ + switch (input_value) + { + case VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR: + return "VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR"; + case VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR: + return "VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR"; + case VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR: + return "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR"; + default: + return "Unhandled VkAccelerationStructureTypeKHR"; + } +} + +static inline const char* string_VkAccelerationStructureTypeNV(VkAccelerationStructureTypeNV input_value) +{ + switch (input_value) + { + case VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR: + return "VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR"; + case VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR: + return "VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR"; + case VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR: + return "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR"; + default: + return "Unhandled VkAccelerationStructureTypeNV"; + } +} + +static inline const char* string_VkGeometryFlagBitsKHR(VkGeometryFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR: + return "VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR"; + case VK_GEOMETRY_OPAQUE_BIT_KHR: + return "VK_GEOMETRY_OPAQUE_BIT_KHR"; + default: + return "Unhandled VkGeometryFlagBitsKHR"; + } +} + +static inline std::string string_VkGeometryFlagsKHR(VkGeometryFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkGeometryFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkGeometryFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkGeometryFlagBitsNV(VkGeometryFlagBitsNV input_value) +{ + switch (input_value) + { + case VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR: + return "VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR"; + case VK_GEOMETRY_OPAQUE_BIT_KHR: + return "VK_GEOMETRY_OPAQUE_BIT_KHR"; + default: + return "Unhandled VkGeometryFlagBitsNV"; + } +} + +static inline std::string string_VkGeometryFlagsNV(VkGeometryFlagsNV input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkGeometryFlagBitsNV(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkGeometryFlagBitsNV(static_cast(0))); + return ret; +} + +static inline const char* string_VkGeometryInstanceFlagBitsKHR(VkGeometryInstanceFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR: + return "VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR"; + case VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR: + return "VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR"; + case VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR: + return "VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR"; + case VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR: + return "VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR"; + default: + return "Unhandled VkGeometryInstanceFlagBitsKHR"; + } +} + +static inline std::string string_VkGeometryInstanceFlagsKHR(VkGeometryInstanceFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkGeometryInstanceFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkGeometryInstanceFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkGeometryInstanceFlagBitsNV(VkGeometryInstanceFlagBitsNV input_value) +{ + switch (input_value) + { + case VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR: + return "VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR"; + case VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR: + return "VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR"; + case VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR: + return "VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR"; + case VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR: + return "VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR"; + default: + return "Unhandled VkGeometryInstanceFlagBitsNV"; + } +} + +static inline std::string string_VkGeometryInstanceFlagsNV(VkGeometryInstanceFlagsNV input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkGeometryInstanceFlagBitsNV(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkGeometryInstanceFlagBitsNV(static_cast(0))); + return ret; +} + +static inline const char* string_VkBuildAccelerationStructureFlagBitsKHR(VkBuildAccelerationStructureFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV: + return "VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV"; + case VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR"; + default: + return "Unhandled VkBuildAccelerationStructureFlagBitsKHR"; + } +} + +static inline std::string string_VkBuildAccelerationStructureFlagsKHR(VkBuildAccelerationStructureFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkBuildAccelerationStructureFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkBuildAccelerationStructureFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkBuildAccelerationStructureFlagBitsNV(VkBuildAccelerationStructureFlagBitsNV input_value) +{ + switch (input_value) + { + case VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV: + return "VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV"; + case VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR"; + default: + return "Unhandled VkBuildAccelerationStructureFlagBitsNV"; + } +} + +static inline std::string string_VkBuildAccelerationStructureFlagsNV(VkBuildAccelerationStructureFlagsNV input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkBuildAccelerationStructureFlagBitsNV(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkBuildAccelerationStructureFlagBitsNV(static_cast(0))); + return ret; +} + +static inline const char* string_VkCopyAccelerationStructureModeKHR(VkCopyAccelerationStructureModeKHR input_value) +{ + switch (input_value) + { + case VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR: + return "VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR"; + case VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR: + return "VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR"; + case VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR: + return "VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR"; + case VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR: + return "VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR"; + default: + return "Unhandled VkCopyAccelerationStructureModeKHR"; + } +} + +static inline const char* string_VkCopyAccelerationStructureModeNV(VkCopyAccelerationStructureModeNV input_value) +{ + switch (input_value) + { + case VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR: + return "VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR"; + case VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR: + return "VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR"; + case VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR: + return "VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR"; + case VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR: + return "VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR"; + default: + return "Unhandled VkCopyAccelerationStructureModeNV"; + } +} + +static inline const char* string_VkAccelerationStructureMemoryRequirementsTypeNV(VkAccelerationStructureMemoryRequirementsTypeNV input_value) +{ + switch (input_value) + { + case VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV: + return "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV"; + case VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV: + return "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV"; + case VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV: + return "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV"; + default: + return "Unhandled VkAccelerationStructureMemoryRequirementsTypeNV"; + } +} + +static inline const char* string_VkQueueGlobalPriorityEXT(VkQueueGlobalPriorityEXT input_value) +{ + switch (input_value) + { + case VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT: + return "VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT"; + case VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT: + return "VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT"; + case VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT: + return "VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT"; + case VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT: + return "VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT"; + default: + return "Unhandled VkQueueGlobalPriorityEXT"; + } +} + +static inline const char* string_VkTimeDomainEXT(VkTimeDomainEXT input_value) +{ + switch (input_value) + { + case VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT: + return "VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT"; + case VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT: + return "VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT"; + case VK_TIME_DOMAIN_DEVICE_EXT: + return "VK_TIME_DOMAIN_DEVICE_EXT"; + case VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT: + return "VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT"; + default: + return "Unhandled VkTimeDomainEXT"; + } +} + +static inline const char* string_VkMemoryOverallocationBehaviorAMD(VkMemoryOverallocationBehaviorAMD input_value) +{ + switch (input_value) + { + case VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD: + return "VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD"; + case VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD: + return "VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD"; + case VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD: + return "VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD"; + default: + return "Unhandled VkMemoryOverallocationBehaviorAMD"; + } +} + +static inline const char* string_VkPipelineCreationFeedbackFlagBitsEXT(VkPipelineCreationFeedbackFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT: + return "VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT"; + case VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT: + return "VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT"; + case VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT: + return "VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT"; + default: + return "Unhandled VkPipelineCreationFeedbackFlagBitsEXT"; + } +} + +static inline std::string string_VkPipelineCreationFeedbackFlagsEXT(VkPipelineCreationFeedbackFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkPipelineCreationFeedbackFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkPipelineCreationFeedbackFlagBitsEXT(static_cast(0))); + return ret; +} + +static inline const char* string_VkPerformanceConfigurationTypeINTEL(VkPerformanceConfigurationTypeINTEL input_value) +{ + switch (input_value) + { + case VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL: + return "VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL"; + default: + return "Unhandled VkPerformanceConfigurationTypeINTEL"; + } +} + +static inline const char* string_VkQueryPoolSamplingModeINTEL(VkQueryPoolSamplingModeINTEL input_value) +{ + switch (input_value) + { + case VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL: + return "VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL"; + default: + return "Unhandled VkQueryPoolSamplingModeINTEL"; + } +} + +static inline const char* string_VkPerformanceOverrideTypeINTEL(VkPerformanceOverrideTypeINTEL input_value) +{ + switch (input_value) + { + case VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL: + return "VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL"; + case VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL: + return "VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL"; + default: + return "Unhandled VkPerformanceOverrideTypeINTEL"; + } +} + +static inline const char* string_VkPerformanceParameterTypeINTEL(VkPerformanceParameterTypeINTEL input_value) +{ + switch (input_value) + { + case VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL: + return "VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL"; + case VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL: + return "VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL"; + default: + return "Unhandled VkPerformanceParameterTypeINTEL"; + } +} + +static inline const char* string_VkPerformanceValueTypeINTEL(VkPerformanceValueTypeINTEL input_value) +{ + switch (input_value) + { + case VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL: + return "VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL"; + case VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL: + return "VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL"; + case VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL: + return "VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL"; + case VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL: + return "VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL"; + case VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL: + return "VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL"; + default: + return "Unhandled VkPerformanceValueTypeINTEL"; + } +} + +static inline const char* string_VkToolPurposeFlagBitsEXT(VkToolPurposeFlagBitsEXT input_value) +{ + switch (input_value) + { + case VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT: + return "VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT"; + case VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT: + return "VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT"; + case VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT: + return "VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT"; + case VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT: + return "VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT"; + case VK_TOOL_PURPOSE_PROFILING_BIT_EXT: + return "VK_TOOL_PURPOSE_PROFILING_BIT_EXT"; + case VK_TOOL_PURPOSE_TRACING_BIT_EXT: + return "VK_TOOL_PURPOSE_TRACING_BIT_EXT"; + case VK_TOOL_PURPOSE_VALIDATION_BIT_EXT: + return "VK_TOOL_PURPOSE_VALIDATION_BIT_EXT"; + default: + return "Unhandled VkToolPurposeFlagBitsEXT"; + } +} + +static inline std::string string_VkToolPurposeFlagsEXT(VkToolPurposeFlagsEXT input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkToolPurposeFlagBitsEXT(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkToolPurposeFlagBitsEXT(static_cast(0))); + return ret; +} + +static inline const char* string_VkValidationFeatureEnableEXT(VkValidationFeatureEnableEXT input_value) +{ + switch (input_value) + { + case VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT: + return "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT"; + case VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT: + return "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT"; + case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT: + return "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT"; + case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT: + return "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT"; + case VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT: + return "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT"; + default: + return "Unhandled VkValidationFeatureEnableEXT"; + } +} + +static inline const char* string_VkValidationFeatureDisableEXT(VkValidationFeatureDisableEXT input_value) +{ + switch (input_value) + { + case VK_VALIDATION_FEATURE_DISABLE_ALL_EXT: + return "VK_VALIDATION_FEATURE_DISABLE_ALL_EXT"; + case VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT: + return "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT"; + case VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT: + return "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT"; + case VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT: + return "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT"; + case VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT: + return "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT"; + case VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT: + return "VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT"; + case VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT: + return "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT"; + case VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT: + return "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT"; + default: + return "Unhandled VkValidationFeatureDisableEXT"; + } +} + +static inline const char* string_VkComponentTypeNV(VkComponentTypeNV input_value) +{ + switch (input_value) + { + case VK_COMPONENT_TYPE_FLOAT16_NV: + return "VK_COMPONENT_TYPE_FLOAT16_NV"; + case VK_COMPONENT_TYPE_FLOAT32_NV: + return "VK_COMPONENT_TYPE_FLOAT32_NV"; + case VK_COMPONENT_TYPE_FLOAT64_NV: + return "VK_COMPONENT_TYPE_FLOAT64_NV"; + case VK_COMPONENT_TYPE_SINT16_NV: + return "VK_COMPONENT_TYPE_SINT16_NV"; + case VK_COMPONENT_TYPE_SINT32_NV: + return "VK_COMPONENT_TYPE_SINT32_NV"; + case VK_COMPONENT_TYPE_SINT64_NV: + return "VK_COMPONENT_TYPE_SINT64_NV"; + case VK_COMPONENT_TYPE_SINT8_NV: + return "VK_COMPONENT_TYPE_SINT8_NV"; + case VK_COMPONENT_TYPE_UINT16_NV: + return "VK_COMPONENT_TYPE_UINT16_NV"; + case VK_COMPONENT_TYPE_UINT32_NV: + return "VK_COMPONENT_TYPE_UINT32_NV"; + case VK_COMPONENT_TYPE_UINT64_NV: + return "VK_COMPONENT_TYPE_UINT64_NV"; + case VK_COMPONENT_TYPE_UINT8_NV: + return "VK_COMPONENT_TYPE_UINT8_NV"; + default: + return "Unhandled VkComponentTypeNV"; + } +} + +static inline const char* string_VkScopeNV(VkScopeNV input_value) +{ + switch (input_value) + { + case VK_SCOPE_DEVICE_NV: + return "VK_SCOPE_DEVICE_NV"; + case VK_SCOPE_QUEUE_FAMILY_NV: + return "VK_SCOPE_QUEUE_FAMILY_NV"; + case VK_SCOPE_SUBGROUP_NV: + return "VK_SCOPE_SUBGROUP_NV"; + case VK_SCOPE_WORKGROUP_NV: + return "VK_SCOPE_WORKGROUP_NV"; + default: + return "Unhandled VkScopeNV"; + } +} + +static inline const char* string_VkCoverageReductionModeNV(VkCoverageReductionModeNV input_value) +{ + switch (input_value) + { + case VK_COVERAGE_REDUCTION_MODE_MERGE_NV: + return "VK_COVERAGE_REDUCTION_MODE_MERGE_NV"; + case VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV: + return "VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV"; + default: + return "Unhandled VkCoverageReductionModeNV"; + } +} + +static inline const char* string_VkProvokingVertexModeEXT(VkProvokingVertexModeEXT input_value) +{ + switch (input_value) + { + case VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT: + return "VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT"; + case VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT: + return "VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT"; + default: + return "Unhandled VkProvokingVertexModeEXT"; + } +} + + +#ifdef VK_USE_PLATFORM_WIN32_KHR + +static inline const char* string_VkFullScreenExclusiveEXT(VkFullScreenExclusiveEXT input_value) +{ + switch (input_value) + { + case VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT: + return "VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT"; + case VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT: + return "VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT"; + case VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT: + return "VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT"; + case VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT: + return "VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT"; + default: + return "Unhandled VkFullScreenExclusiveEXT"; + } +} +#endif // VK_USE_PLATFORM_WIN32_KHR + +static inline const char* string_VkLineRasterizationModeEXT(VkLineRasterizationModeEXT input_value) +{ + switch (input_value) + { + case VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT: + return "VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT"; + case VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT: + return "VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT"; + case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT: + return "VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT"; + case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT: + return "VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT"; + default: + return "Unhandled VkLineRasterizationModeEXT"; + } +} + +static inline const char* string_VkIndirectStateFlagBitsNV(VkIndirectStateFlagBitsNV input_value) +{ + switch (input_value) + { + case VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV: + return "VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV"; + default: + return "Unhandled VkIndirectStateFlagBitsNV"; + } +} + +static inline std::string string_VkIndirectStateFlagsNV(VkIndirectStateFlagsNV input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkIndirectStateFlagBitsNV(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkIndirectStateFlagBitsNV(static_cast(0))); + return ret; +} + +static inline const char* string_VkIndirectCommandsTokenTypeNV(VkIndirectCommandsTokenTypeNV input_value) +{ + switch (input_value) + { + case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV: + return "VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV"; + case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV: + return "VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV"; + case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV: + return "VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV"; + case VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV: + return "VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV"; + case VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV: + return "VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV"; + case VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV: + return "VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV"; + case VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV: + return "VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV"; + case VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV: + return "VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV"; + default: + return "Unhandled VkIndirectCommandsTokenTypeNV"; + } +} + +static inline const char* string_VkIndirectCommandsLayoutUsageFlagBitsNV(VkIndirectCommandsLayoutUsageFlagBitsNV input_value) +{ + switch (input_value) + { + case VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV: + return "VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV"; + case VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV: + return "VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV"; + case VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV: + return "VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV"; + default: + return "Unhandled VkIndirectCommandsLayoutUsageFlagBitsNV"; + } +} + +static inline std::string string_VkIndirectCommandsLayoutUsageFlagsNV(VkIndirectCommandsLayoutUsageFlagsNV input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkIndirectCommandsLayoutUsageFlagBitsNV(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkIndirectCommandsLayoutUsageFlagBitsNV(static_cast(0))); + return ret; +} + +static inline const char* string_VkDeviceMemoryReportEventTypeEXT(VkDeviceMemoryReportEventTypeEXT input_value) +{ + switch (input_value) + { + case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT: + return "VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT"; + case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT: + return "VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT"; + case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT: + return "VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT"; + case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT: + return "VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT"; + case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT: + return "VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT"; + default: + return "Unhandled VkDeviceMemoryReportEventTypeEXT"; + } +} + +static inline const char* string_VkDeviceDiagnosticsConfigFlagBitsNV(VkDeviceDiagnosticsConfigFlagBitsNV input_value) +{ + switch (input_value) + { + case VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV: + return "VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV"; + case VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV: + return "VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV"; + case VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV: + return "VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV"; + default: + return "Unhandled VkDeviceDiagnosticsConfigFlagBitsNV"; + } +} + +static inline std::string string_VkDeviceDiagnosticsConfigFlagsNV(VkDeviceDiagnosticsConfigFlagsNV input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkDeviceDiagnosticsConfigFlagBitsNV(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkDeviceDiagnosticsConfigFlagBitsNV(static_cast(0))); + return ret; +} + +static inline const char* string_VkFragmentShadingRateTypeNV(VkFragmentShadingRateTypeNV input_value) +{ + switch (input_value) + { + case VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV: + return "VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV"; + case VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV: + return "VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV"; + default: + return "Unhandled VkFragmentShadingRateTypeNV"; + } +} + +static inline const char* string_VkFragmentShadingRateNV(VkFragmentShadingRateNV input_value) +{ + switch (input_value) + { + case VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV: + return "VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV"; + case VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV: + return "VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV"; + case VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV: + return "VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV"; + case VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV: + return "VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV"; + case VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV: + return "VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV"; + case VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV: + return "VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV"; + case VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV: + return "VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV"; + case VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV: + return "VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV"; + case VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV: + return "VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV"; + case VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV: + return "VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV"; + case VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV: + return "VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV"; + case VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV: + return "VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV"; + default: + return "Unhandled VkFragmentShadingRateNV"; + } +} + +static inline const char* string_VkAccelerationStructureMotionInstanceTypeNV(VkAccelerationStructureMotionInstanceTypeNV input_value) +{ + switch (input_value) + { + case VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV: + return "VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV"; + case VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV: + return "VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV"; + case VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV: + return "VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV"; + default: + return "Unhandled VkAccelerationStructureMotionInstanceTypeNV"; + } +} + +static inline const char* string_VkBuildAccelerationStructureModeKHR(VkBuildAccelerationStructureModeKHR input_value) +{ + switch (input_value) + { + case VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR"; + case VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR: + return "VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR"; + default: + return "Unhandled VkBuildAccelerationStructureModeKHR"; + } +} + +static inline const char* string_VkAccelerationStructureBuildTypeKHR(VkAccelerationStructureBuildTypeKHR input_value) +{ + switch (input_value) + { + case VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR: + return "VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR"; + case VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR: + return "VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR"; + case VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR: + return "VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR"; + default: + return "Unhandled VkAccelerationStructureBuildTypeKHR"; + } +} + +static inline const char* string_VkAccelerationStructureCreateFlagBitsKHR(VkAccelerationStructureCreateFlagBitsKHR input_value) +{ + switch (input_value) + { + case VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR: + return "VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR"; + case VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV: + return "VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV"; + default: + return "Unhandled VkAccelerationStructureCreateFlagBitsKHR"; + } +} + +static inline std::string string_VkAccelerationStructureCreateFlagsKHR(VkAccelerationStructureCreateFlagsKHR input_value) +{ + std::string ret; + int index = 0; + while(input_value) { + if (input_value & 1) { + if( !ret.empty()) ret.append("|"); + ret.append(string_VkAccelerationStructureCreateFlagBitsKHR(static_cast(1U << index))); + } + ++index; + input_value >>= 1; + } + if( ret.empty()) ret.append(string_VkAccelerationStructureCreateFlagBitsKHR(static_cast(0))); + return ret; +} + +static inline const char* string_VkAccelerationStructureCompatibilityKHR(VkAccelerationStructureCompatibilityKHR input_value) +{ + switch (input_value) + { + case VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR: + return "VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR"; + case VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR: + return "VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR"; + default: + return "Unhandled VkAccelerationStructureCompatibilityKHR"; + } +} + +static inline const char* string_VkShaderGroupShaderKHR(VkShaderGroupShaderKHR input_value) +{ + switch (input_value) + { + case VK_SHADER_GROUP_SHADER_ANY_HIT_KHR: + return "VK_SHADER_GROUP_SHADER_ANY_HIT_KHR"; + case VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR: + return "VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR"; + case VK_SHADER_GROUP_SHADER_GENERAL_KHR: + return "VK_SHADER_GROUP_SHADER_GENERAL_KHR"; + case VK_SHADER_GROUP_SHADER_INTERSECTION_KHR: + return "VK_SHADER_GROUP_SHADER_INTERSECTION_KHR"; + default: + return "Unhandled VkShaderGroupShaderKHR"; + } +} + +static inline const char * GetPhysDevFeatureString(uint32_t index) { + const char * IndexToPhysDevFeatureString[] = { + "robustBufferAccess", + "fullDrawIndexUint32", + "imageCubeArray", + "independentBlend", + "geometryShader", + "tessellationShader", + "sampleRateShading", + "dualSrcBlend", + "logicOp", + "multiDrawIndirect", + "drawIndirectFirstInstance", + "depthClamp", + "depthBiasClamp", + "fillModeNonSolid", + "depthBounds", + "wideLines", + "largePoints", + "alphaToOne", + "multiViewport", + "samplerAnisotropy", + "textureCompressionETC2", + "textureCompressionASTC_LDR", + "textureCompressionBC", + "occlusionQueryPrecise", + "pipelineStatisticsQuery", + "vertexPipelineStoresAndAtomics", + "fragmentStoresAndAtomics", + "shaderTessellationAndGeometryPointSize", + "shaderImageGatherExtended", + "shaderStorageImageExtendedFormats", + "shaderStorageImageMultisample", + "shaderStorageImageReadWithoutFormat", + "shaderStorageImageWriteWithoutFormat", + "shaderUniformBufferArrayDynamicIndexing", + "shaderSampledImageArrayDynamicIndexing", + "shaderStorageBufferArrayDynamicIndexing", + "shaderStorageImageArrayDynamicIndexing", + "shaderClipDistance", + "shaderCullDistance", + "shaderFloat64", + "shaderInt64", + "shaderInt16", + "shaderResourceResidency", + "shaderResourceMinLod", + "sparseBinding", + "sparseResidencyBuffer", + "sparseResidencyImage2D", + "sparseResidencyImage3D", + "sparseResidency2Samples", + "sparseResidency4Samples", + "sparseResidency8Samples", + "sparseResidency16Samples", + "sparseResidencyAliased", + "variableMultisampleRate", + "inheritedQueries", + }; + + return IndexToPhysDevFeatureString[index]; +} + +static inline bool IsDuplicatePnext(VkStructureType input_value) +{ + switch (input_value) + { + case VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT: + case VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT: + case VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT: + return true; + default: + return false; + } +} diff --git a/libraries/ZVulkan/include/vulkan/vk_icd.h b/libraries/ZVulkan/include/vulkan/vk_icd.h new file mode 100644 index 00000000000..59204a3419f --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vk_icd.h @@ -0,0 +1,244 @@ +/* + * Copyright 2015-2023 The Khronos Group Inc. + * Copyright 2015-2023 Valve Corporation + * Copyright 2015-2023 LunarG, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "vulkan.h" +#include + +// Loader-ICD version negotiation API. Versions add the following features: +// Version 0 - Initial. Doesn't support vk_icdGetInstanceProcAddr +// or vk_icdNegotiateLoaderICDInterfaceVersion. +// Version 1 - Add support for vk_icdGetInstanceProcAddr. +// Version 2 - Add Loader/ICD Interface version negotiation +// via vk_icdNegotiateLoaderICDInterfaceVersion. +// Version 3 - Add ICD creation/destruction of KHR_surface objects. +// Version 4 - Add unknown physical device extension querying via +// vk_icdGetPhysicalDeviceProcAddr. +// Version 5 - Tells ICDs that the loader is now paying attention to the +// application version of Vulkan passed into the ApplicationInfo +// structure during vkCreateInstance. This will tell the ICD +// that if the loader is older, it should automatically fail a +// call for any API version > 1.0. Otherwise, the loader will +// manually determine if it can support the expected version. +// Version 6 - Add support for vk_icdEnumerateAdapterPhysicalDevices. +// Version 7 - If an ICD supports any of the following functions, they must be +// queryable with vk_icdGetInstanceProcAddr: +// vk_icdNegotiateLoaderICDInterfaceVersion +// vk_icdGetPhysicalDeviceProcAddr +// vk_icdEnumerateAdapterPhysicalDevices (Windows only) +// In addition, these functions no longer need to be exported directly. +// This version allows drivers provided through the extension +// VK_LUNARG_direct_driver_loading be able to support the entire +// Driver-Loader interface. + +#define CURRENT_LOADER_ICD_INTERFACE_VERSION 7 +#define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0 +#define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4 + +// Old typedefs that don't follow a proper naming convention but are preserved for compatibility +typedef VkResult(VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion); +// This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this +// file directly, it won't be found. +#ifndef PFN_GetPhysicalDeviceProcAddr +typedef PFN_vkVoidFunction(VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char *pName); +#endif + +// Typedefs for loader/ICD interface +typedef VkResult (VKAPI_PTR *PFN_vk_icdNegotiateLoaderICDInterfaceVersion)(uint32_t* pVersion); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vk_icdGetInstanceProcAddr)(VkInstance instance, const char* pName); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vk_icdGetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName); +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef VkResult (VKAPI_PTR *PFN_vk_icdEnumerateAdapterPhysicalDevices)(VkInstance instance, LUID adapterLUID, + uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +#endif + +// Prototypes for loader/ICD interface +#if !defined(VK_NO_PROTOTYPES) +#ifdef __cplusplus +extern "C" { +#endif + VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pVersion); + VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName); + VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char* pName); +#if defined(VK_USE_PLATFORM_WIN32_KHR) + VKAPI_ATTR VkResult VKAPI_CALL vk_icdEnumerateAdapterPhysicalDevices(VkInstance instance, LUID adapterLUID, + uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +#endif +#ifdef __cplusplus +} +#endif +#endif + +/* + * The ICD must reserve space for a pointer for the loader's dispatch + * table, at the start of . + * The ICD must initialize this variable using the SET_LOADER_MAGIC_VALUE macro. + */ + +#define ICD_LOADER_MAGIC 0x01CDC0DE + +typedef union { + uintptr_t loaderMagic; + void *loaderData; +} VK_LOADER_DATA; + +static inline void set_loader_magic_value(void *pNewObject) { + VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject; + loader_info->loaderMagic = ICD_LOADER_MAGIC; +} + +static inline bool valid_loader_magic_value(void *pNewObject) { + const VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject; + return (loader_info->loaderMagic & 0xffffffff) == ICD_LOADER_MAGIC; +} + +/* + * Windows and Linux ICDs will treat VkSurfaceKHR as a pointer to a struct that + * contains the platform-specific connection and surface information. + */ +typedef enum { + VK_ICD_WSI_PLATFORM_MIR, + VK_ICD_WSI_PLATFORM_WAYLAND, + VK_ICD_WSI_PLATFORM_WIN32, + VK_ICD_WSI_PLATFORM_XCB, + VK_ICD_WSI_PLATFORM_XLIB, + VK_ICD_WSI_PLATFORM_ANDROID, + VK_ICD_WSI_PLATFORM_MACOS, + VK_ICD_WSI_PLATFORM_IOS, + VK_ICD_WSI_PLATFORM_DISPLAY, + VK_ICD_WSI_PLATFORM_HEADLESS, + VK_ICD_WSI_PLATFORM_METAL, + VK_ICD_WSI_PLATFORM_DIRECTFB, + VK_ICD_WSI_PLATFORM_VI, + VK_ICD_WSI_PLATFORM_GGP, + VK_ICD_WSI_PLATFORM_SCREEN, + VK_ICD_WSI_PLATFORM_FUCHSIA, +} VkIcdWsiPlatform; + +typedef struct { + VkIcdWsiPlatform platform; +} VkIcdSurfaceBase; + +#ifdef VK_USE_PLATFORM_MIR_KHR +typedef struct { + VkIcdSurfaceBase base; + MirConnection *connection; + MirSurface *mirSurface; +} VkIcdSurfaceMir; +#endif // VK_USE_PLATFORM_MIR_KHR + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +typedef struct { + VkIcdSurfaceBase base; + struct wl_display *display; + struct wl_surface *surface; +} VkIcdSurfaceWayland; +#endif // VK_USE_PLATFORM_WAYLAND_KHR + +#ifdef VK_USE_PLATFORM_WIN32_KHR +typedef struct { + VkIcdSurfaceBase base; + HINSTANCE hinstance; + HWND hwnd; +} VkIcdSurfaceWin32; +#endif // VK_USE_PLATFORM_WIN32_KHR + +#ifdef VK_USE_PLATFORM_XCB_KHR +typedef struct { + VkIcdSurfaceBase base; + xcb_connection_t *connection; + xcb_window_t window; +} VkIcdSurfaceXcb; +#endif // VK_USE_PLATFORM_XCB_KHR + +#ifdef VK_USE_PLATFORM_XLIB_KHR +typedef struct { + VkIcdSurfaceBase base; + Display *dpy; + Window window; +} VkIcdSurfaceXlib; +#endif // VK_USE_PLATFORM_XLIB_KHR + +#ifdef VK_USE_PLATFORM_DIRECTFB_EXT +typedef struct { + VkIcdSurfaceBase base; + IDirectFB *dfb; + IDirectFBSurface *surface; +} VkIcdSurfaceDirectFB; +#endif // VK_USE_PLATFORM_DIRECTFB_EXT + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +typedef struct { + VkIcdSurfaceBase base; + struct ANativeWindow *window; +} VkIcdSurfaceAndroid; +#endif // VK_USE_PLATFORM_ANDROID_KHR + +#ifdef VK_USE_PLATFORM_MACOS_MVK +typedef struct { + VkIcdSurfaceBase base; + const void *pView; +} VkIcdSurfaceMacOS; +#endif // VK_USE_PLATFORM_MACOS_MVK + +#ifdef VK_USE_PLATFORM_IOS_MVK +typedef struct { + VkIcdSurfaceBase base; + const void *pView; +} VkIcdSurfaceIOS; +#endif // VK_USE_PLATFORM_IOS_MVK + +#ifdef VK_USE_PLATFORM_GGP +typedef struct { + VkIcdSurfaceBase base; + GgpStreamDescriptor streamDescriptor; +} VkIcdSurfaceGgp; +#endif // VK_USE_PLATFORM_GGP + +typedef struct { + VkIcdSurfaceBase base; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkIcdSurfaceDisplay; + +typedef struct { + VkIcdSurfaceBase base; +} VkIcdSurfaceHeadless; + +#ifdef VK_USE_PLATFORM_METAL_EXT +typedef struct { + VkIcdSurfaceBase base; + const CAMetalLayer *pLayer; +} VkIcdSurfaceMetal; +#endif // VK_USE_PLATFORM_METAL_EXT + +#ifdef VK_USE_PLATFORM_VI_NN +typedef struct { + VkIcdSurfaceBase base; + void *window; +} VkIcdSurfaceVi; +#endif // VK_USE_PLATFORM_VI_NN + +#ifdef VK_USE_PLATFORM_SCREEN_QNX +typedef struct { + VkIcdSurfaceBase base; + struct _screen_context *context; + struct _screen_window *window; +} VkIcdSurfaceScreen; +#endif // VK_USE_PLATFORM_SCREEN_QNX + +#ifdef VK_USE_PLATFORM_FUCHSIA +typedef struct { + VkIcdSurfaceBase base; +} VkIcdSurfaceImagePipe; +#endif // VK_USE_PLATFORM_FUCHSIA diff --git a/src/rendering/vulkan/thirdparty/vulkan/vk_layer.h b/libraries/ZVulkan/include/vulkan/vk_layer.h similarity index 84% rename from src/rendering/vulkan/thirdparty/vulkan/vk_layer.h rename to libraries/ZVulkan/include/vulkan/vk_layer.h index fa765200897..19d88fce4ba 100644 --- a/src/rendering/vulkan/thirdparty/vulkan/vk_layer.h +++ b/libraries/ZVulkan/include/vulkan/vk_layer.h @@ -1,39 +1,18 @@ -// -// File: vk_layer.h -// /* - * Copyright (c) 2015-2017 The Khronos Group Inc. - * Copyright (c) 2015-2017 Valve Corporation - * Copyright (c) 2015-2017 LunarG, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2015-2023 The Khronos Group Inc. + * Copyright 2015-2023 Valve Corporation + * Copyright 2015-2023 LunarG, Inc. * + * SPDX-License-Identifier: Apache-2.0 */ +#pragma once /* Need to define dispatch table * Core struct can then have ptr to dispatch table at the top * Along with object ptrs for current and next OBJ */ -#pragma once -#include "vulkan.h" -#if defined(__GNUC__) && __GNUC__ >= 4 -#define VK_LAYER_EXPORT __attribute__((visibility("default"))) -#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) -#define VK_LAYER_EXPORT __attribute__((visibility("default"))) -#else -#define VK_LAYER_EXPORT -#endif +#include "vulkan_core.h" #define MAX_NUM_UNKNOWN_EXTS 250 @@ -83,7 +62,8 @@ typedef VkResult(VKAPI_PTR *PFN_PhysDevExt)(VkPhysicalDevice phys_device); typedef enum VkLayerFunction_ { VK_LAYER_LINK_INFO = 0, VK_LOADER_DATA_CALLBACK = 1, - VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK = 2 + VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK = 2, + VK_LOADER_FEATURES = 3, } VkLayerFunction; typedef struct VkLayerInstanceLink_ { @@ -111,6 +91,12 @@ typedef VkResult (VKAPI_PTR *PFN_vkSetDeviceLoaderData)(VkDevice device, typedef VkResult (VKAPI_PTR *PFN_vkLayerCreateDevice)(VkInstance instance, VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, PFN_vkGetInstanceProcAddr layerGIPA, PFN_vkGetDeviceProcAddr *nextGDPA); typedef void (VKAPI_PTR *PFN_vkLayerDestroyDevice)(VkDevice physicalDevice, const VkAllocationCallbacks *pAllocator, PFN_vkDestroyDevice destroyFunction); + +typedef enum VkLoaderFeastureFlagBits { + VK_LOADER_FEATURE_PHYSICAL_DEVICE_SORTING = 0x00000001, +} VkLoaderFlagBits; +typedef VkFlags VkLoaderFeatureFlags; + typedef struct { VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO const void *pNext; @@ -119,9 +105,10 @@ typedef struct { VkLayerInstanceLink *pLayerInfo; PFN_vkSetInstanceLoaderData pfnSetInstanceLoaderData; struct { - PFN_vkLayerCreateDevice pfnLayerCreateDevice; - PFN_vkLayerDestroyDevice pfnLayerDestroyDevice; - } layerDevice; + PFN_vkLayerCreateDevice pfnLayerCreateDevice; + PFN_vkLayerDestroyDevice pfnLayerDestroyDevice; + } layerDevice; + VkLoaderFeatureFlags loaderFeatures; } u; } VkLayerInstanceCreateInfo; diff --git a/src/rendering/vulkan/thirdparty/vulkan/vk_layer_dispatch_table.h b/libraries/ZVulkan/include/vulkan/vk_layer_dispatch_table.h similarity index 100% rename from src/rendering/vulkan/thirdparty/vulkan/vk_layer_dispatch_table.h rename to libraries/ZVulkan/include/vulkan/vk_layer_dispatch_table.h diff --git a/src/rendering/vulkan/thirdparty/vulkan/vk_platform.h b/libraries/ZVulkan/include/vulkan/vk_platform.h similarity index 79% rename from src/rendering/vulkan/thirdparty/vulkan/vk_platform.h rename to libraries/ZVulkan/include/vulkan/vk_platform.h index 7289299240a..ed67a6004a8 100644 --- a/src/rendering/vulkan/thirdparty/vulkan/vk_platform.h +++ b/libraries/ZVulkan/include/vulkan/vk_platform.h @@ -2,19 +2,9 @@ // File: vk_platform.h // /* -** Copyright (c) 2014-2017 The Khronos Group Inc. +** Copyright 2014-2023 The Khronos Group Inc. ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. +** SPDX-License-Identifier: Apache-2.0 */ @@ -52,7 +42,7 @@ extern "C" #define VKAPI_CALL __stdcall #define VKAPI_PTR VKAPI_CALL #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 - #error "Vulkan isn't supported for the 'armeabi' NDK ABI" + #error "Vulkan is not supported for the 'armeabi' NDK ABI" #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" // calling convention, i.e. float parameters are passed in registers. This @@ -68,7 +58,9 @@ extern "C" #define VKAPI_PTR #endif -#include +#if !defined(VK_NO_STDDEF_H) + #include +#endif // !defined(VK_NO_STDDEF_H) #if !defined(VK_NO_STDINT_H) #if defined(_MSC_VER) && (_MSC_VER < 1600) diff --git a/src/rendering/vulkan/thirdparty/vulkan/vk_sdk_platform.h b/libraries/ZVulkan/include/vulkan/vk_sdk_platform.h similarity index 100% rename from src/rendering/vulkan/thirdparty/vulkan/vk_sdk_platform.h rename to libraries/ZVulkan/include/vulkan/vk_sdk_platform.h diff --git a/libraries/ZVulkan/include/vulkan/vulkan.h b/libraries/ZVulkan/include/vulkan/vulkan.h new file mode 100644 index 00000000000..426cff58d72 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan.h @@ -0,0 +1,99 @@ +#ifndef VULKAN_H_ +#define VULKAN_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +#include "vk_platform.h" +#include "vulkan_core.h" + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +#include "vulkan_android.h" +#endif + +#ifdef VK_USE_PLATFORM_FUCHSIA +#include +#include "vulkan_fuchsia.h" +#endif + +#ifdef VK_USE_PLATFORM_IOS_MVK +#include "vulkan_ios.h" +#endif + + +#ifdef VK_USE_PLATFORM_MACOS_MVK +#include "vulkan_macos.h" +#endif + +#ifdef VK_USE_PLATFORM_METAL_EXT +#include "vulkan_metal.h" +#endif + +#ifdef VK_USE_PLATFORM_VI_NN +#include "vulkan_vi.h" +#endif + + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#include "vulkan_wayland.h" +#endif + + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#include +#include "vulkan_win32.h" +#endif + + +#ifdef VK_USE_PLATFORM_XCB_KHR +#include +#include "vulkan_xcb.h" +#endif + + +#ifdef VK_USE_PLATFORM_XLIB_KHR +#include +#include "vulkan_xlib.h" +#endif + + +#ifdef VK_USE_PLATFORM_DIRECTFB_EXT +#include +#include "vulkan_directfb.h" +#endif + + +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT +#include +#include +#include "vulkan_xlib_xrandr.h" +#endif + + +#ifdef VK_USE_PLATFORM_GGP +#include +#include "vulkan_ggp.h" +#endif + + +#ifdef VK_USE_PLATFORM_SCREEN_QNX +#include +#include "vulkan_screen.h" +#endif + + +#ifdef VK_USE_PLATFORM_SCI +#include +#include +#include "vulkan_sci.h" +#endif + + +#ifdef VK_ENABLE_BETA_EXTENSIONS +#include "vulkan_beta.h" +#endif + +#endif // VULKAN_H_ diff --git a/libraries/ZVulkan/include/vulkan/vulkan_android.h b/libraries/ZVulkan/include/vulkan/vulkan_android.h new file mode 100644 index 00000000000..40b3c67ba6e --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_android.h @@ -0,0 +1,153 @@ +#ifndef VULKAN_ANDROID_H_ +#define VULKAN_ANDROID_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_android_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_android_surface 1 +struct ANativeWindow; +#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 +#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" +typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; +typedef struct VkAndroidSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkAndroidSurfaceCreateFlagsKHR flags; + struct ANativeWindow* window; +} VkAndroidSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( + VkInstance instance, + const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +// VK_ANDROID_external_memory_android_hardware_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_ANDROID_external_memory_android_hardware_buffer 1 +struct AHardwareBuffer; +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 5 +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" +typedef struct VkAndroidHardwareBufferUsageANDROID { + VkStructureType sType; + void* pNext; + uint64_t androidHardwareBufferUsage; +} VkAndroidHardwareBufferUsageANDROID; + +typedef struct VkAndroidHardwareBufferPropertiesANDROID { + VkStructureType sType; + void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkAndroidHardwareBufferPropertiesANDROID; + +typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkAndroidHardwareBufferFormatPropertiesANDROID; + +typedef struct VkImportAndroidHardwareBufferInfoANDROID { + VkStructureType sType; + const void* pNext; + struct AHardwareBuffer* buffer; +} VkImportAndroidHardwareBufferInfoANDROID; + +typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkMemoryGetAndroidHardwareBufferInfoANDROID; + +typedef struct VkExternalFormatANDROID { + VkStructureType sType; + void* pNext; + uint64_t externalFormat; +} VkExternalFormatANDROID; + +typedef struct VkAndroidHardwareBufferFormatProperties2ANDROID { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags2 formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkAndroidHardwareBufferFormatProperties2ANDROID; + +typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID( + VkDevice device, + const struct AHardwareBuffer* buffer, + VkAndroidHardwareBufferPropertiesANDROID* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID( + VkDevice device, + const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, + struct AHardwareBuffer** pBuffer); +#endif + + +// VK_ANDROID_external_format_resolve is a preprocessor guard. Do not pass it to API calls. +#define VK_ANDROID_external_format_resolve 1 +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_SPEC_VERSION 1 +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_EXTENSION_NAME "VK_ANDROID_external_format_resolve" +typedef struct VkPhysicalDeviceExternalFormatResolveFeaturesANDROID { + VkStructureType sType; + void* pNext; + VkBool32 externalFormatResolve; +} VkPhysicalDeviceExternalFormatResolveFeaturesANDROID; + +typedef struct VkPhysicalDeviceExternalFormatResolvePropertiesANDROID { + VkStructureType sType; + void* pNext; + VkBool32 nullColorAttachmentWithExternalFormatResolve; + VkChromaLocation externalFormatResolveChromaOffsetX; + VkChromaLocation externalFormatResolveChromaOffsetY; +} VkPhysicalDeviceExternalFormatResolvePropertiesANDROID; + +typedef struct VkAndroidHardwareBufferFormatResolvePropertiesANDROID { + VkStructureType sType; + void* pNext; + VkFormat colorAttachmentFormat; +} VkAndroidHardwareBufferFormatResolvePropertiesANDROID; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_beta.h b/libraries/ZVulkan/include/vulkan/vulkan_beta.h new file mode 100644 index 00000000000..1871651d267 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_beta.h @@ -0,0 +1,813 @@ +#ifndef VULKAN_BETA_H_ +#define VULKAN_BETA_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_portability_subset is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_portability_subset 1 +#define VK_KHR_PORTABILITY_SUBSET_SPEC_VERSION 1 +#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset" +typedef struct VkPhysicalDevicePortabilitySubsetFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 constantAlphaColorBlendFactors; + VkBool32 events; + VkBool32 imageViewFormatReinterpretation; + VkBool32 imageViewFormatSwizzle; + VkBool32 imageView2DOn3DImage; + VkBool32 multisampleArrayImage; + VkBool32 mutableComparisonSamplers; + VkBool32 pointPolygons; + VkBool32 samplerMipLodBias; + VkBool32 separateStencilMaskRef; + VkBool32 shaderSampleRateInterpolationFunctions; + VkBool32 tessellationIsolines; + VkBool32 tessellationPointMode; + VkBool32 triangleFans; + VkBool32 vertexAttributeAccessBeyondStride; +} VkPhysicalDevicePortabilitySubsetFeaturesKHR; + +typedef struct VkPhysicalDevicePortabilitySubsetPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t minVertexInputBindingStrideAlignment; +} VkPhysicalDevicePortabilitySubsetPropertiesKHR; + + + +// VK_KHR_video_encode_queue is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_queue 1 +#define VK_KHR_VIDEO_ENCODE_QUEUE_SPEC_VERSION 10 +#define VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME "VK_KHR_video_encode_queue" + +typedef enum VkVideoEncodeTuningModeKHR { + VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_TUNING_MODE_HIGH_QUALITY_KHR = 1, + VK_VIDEO_ENCODE_TUNING_MODE_LOW_LATENCY_KHR = 2, + VK_VIDEO_ENCODE_TUNING_MODE_ULTRA_LOW_LATENCY_KHR = 3, + VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR = 4, + VK_VIDEO_ENCODE_TUNING_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeTuningModeKHR; +typedef VkFlags VkVideoEncodeFlagsKHR; + +typedef enum VkVideoEncodeCapabilityFlagBitsKHR { + VK_VIDEO_ENCODE_CAPABILITY_PRECEDING_EXTERNALLY_ENCODED_BYTES_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_CAPABILITY_INSUFFICIENT_BITSTREAM_BUFFER_RANGE_DETECTION_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeCapabilityFlagBitsKHR; +typedef VkFlags VkVideoEncodeCapabilityFlagsKHR; + +typedef enum VkVideoEncodeRateControlModeFlagBitsKHR { + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeRateControlModeFlagBitsKHR; +typedef VkFlags VkVideoEncodeRateControlModeFlagsKHR; + +typedef enum VkVideoEncodeFeedbackFlagBitsKHR { + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_HAS_OVERRIDES_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_FEEDBACK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeFeedbackFlagBitsKHR; +typedef VkFlags VkVideoEncodeFeedbackFlagsKHR; + +typedef enum VkVideoEncodeUsageFlagBitsKHR { + VK_VIDEO_ENCODE_USAGE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_USAGE_TRANSCODING_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_USAGE_STREAMING_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_USAGE_RECORDING_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_USAGE_CONFERENCING_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_USAGE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeUsageFlagBitsKHR; +typedef VkFlags VkVideoEncodeUsageFlagsKHR; + +typedef enum VkVideoEncodeContentFlagBitsKHR { + VK_VIDEO_ENCODE_CONTENT_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_CONTENT_CAMERA_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_CONTENT_DESKTOP_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_CONTENT_RENDERED_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_CONTENT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeContentFlagBitsKHR; +typedef VkFlags VkVideoEncodeContentFlagsKHR; +typedef VkFlags VkVideoEncodeRateControlFlagsKHR; +typedef struct VkVideoEncodeInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeFlagsKHR flags; + VkBuffer dstBuffer; + VkDeviceSize dstBufferOffset; + VkDeviceSize dstBufferRange; + VkVideoPictureResourceInfoKHR srcPictureResource; + const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot; + uint32_t referenceSlotCount; + const VkVideoReferenceSlotInfoKHR* pReferenceSlots; + uint32_t precedingExternallyEncodedBytes; +} VkVideoEncodeInfoKHR; + +typedef struct VkVideoEncodeCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeCapabilityFlagsKHR flags; + VkVideoEncodeRateControlModeFlagsKHR rateControlModes; + uint32_t maxRateControlLayers; + uint64_t maxBitrate; + uint32_t maxQualityLevels; + VkExtent2D encodeInputPictureGranularity; + VkVideoEncodeFeedbackFlagsKHR supportedEncodeFeedbackFlags; +} VkVideoEncodeCapabilitiesKHR; + +typedef struct VkQueryPoolVideoEncodeFeedbackCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeFeedbackFlagsKHR encodeFeedbackFlags; +} VkQueryPoolVideoEncodeFeedbackCreateInfoKHR; + +typedef struct VkVideoEncodeUsageInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeUsageFlagsKHR videoUsageHints; + VkVideoEncodeContentFlagsKHR videoContentHints; + VkVideoEncodeTuningModeKHR tuningMode; +} VkVideoEncodeUsageInfoKHR; + +typedef struct VkVideoEncodeRateControlLayerInfoKHR { + VkStructureType sType; + const void* pNext; + uint64_t averageBitrate; + uint64_t maxBitrate; + uint32_t frameRateNumerator; + uint32_t frameRateDenominator; +} VkVideoEncodeRateControlLayerInfoKHR; + +typedef struct VkVideoEncodeRateControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeRateControlFlagsKHR flags; + VkVideoEncodeRateControlModeFlagBitsKHR rateControlMode; + uint32_t layerCount; + const VkVideoEncodeRateControlLayerInfoKHR* pLayers; + uint32_t virtualBufferSizeInMs; + uint32_t initialVirtualBufferSizeInMs; +} VkVideoEncodeRateControlInfoKHR; + +typedef struct VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR { + VkStructureType sType; + const void* pNext; + const VkVideoProfileInfoKHR* pVideoProfile; + uint32_t qualityLevel; +} VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR; + +typedef struct VkVideoEncodeQualityLevelPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeRateControlModeFlagBitsKHR preferredRateControlMode; + uint32_t preferredRateControlLayerCount; +} VkVideoEncodeQualityLevelPropertiesKHR; + +typedef struct VkVideoEncodeQualityLevelInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t qualityLevel; +} VkVideoEncodeQualityLevelInfoKHR; + +typedef struct VkVideoEncodeSessionParametersGetInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoSessionParametersKHR videoSessionParameters; +} VkVideoEncodeSessionParametersGetInfoKHR; + +typedef struct VkVideoEncodeSessionParametersFeedbackInfoKHR { + VkStructureType sType; + void* pNext; + VkBool32 hasOverrides; +} VkVideoEncodeSessionParametersFeedbackInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo, VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetEncodedVideoSessionParametersKHR)(VkDevice device, const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo, VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo, size_t* pDataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdEncodeVideoKHR)(VkCommandBuffer commandBuffer, const VkVideoEncodeInfoKHR* pEncodeInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo, + VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetEncodedVideoSessionParametersKHR( + VkDevice device, + const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo, + VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo, + size_t* pDataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdEncodeVideoKHR( + VkCommandBuffer commandBuffer, + const VkVideoEncodeInfoKHR* pEncodeInfo); +#endif + + +// VK_EXT_video_encode_h264 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_video_encode_h264 1 +#include "vk_video/vulkan_video_codec_h264std.h" +#include "vk_video/vulkan_video_codec_h264std_encode.h" +#define VK_EXT_VIDEO_ENCODE_H264_SPEC_VERSION 12 +#define VK_EXT_VIDEO_ENCODE_H264_EXTENSION_NAME "VK_EXT_video_encode_h264" + +typedef enum VkVideoEncodeH264CapabilityFlagBitsEXT { + VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_EXT = 0x00000001, + VK_VIDEO_ENCODE_H264_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_EXT = 0x00000002, + VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_EXT = 0x00000004, + VK_VIDEO_ENCODE_H264_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_EXT = 0x00000008, + VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_EXT = 0x00000010, + VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_EXT = 0x00000020, + VK_VIDEO_ENCODE_H264_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_EXT = 0x00000040, + VK_VIDEO_ENCODE_H264_CAPABILITY_PER_SLICE_CONSTANT_QP_BIT_EXT = 0x00000080, + VK_VIDEO_ENCODE_H264_CAPABILITY_GENERATE_PREFIX_NALU_BIT_EXT = 0x00000100, + VK_VIDEO_ENCODE_H264_CAPABILITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkVideoEncodeH264CapabilityFlagBitsEXT; +typedef VkFlags VkVideoEncodeH264CapabilityFlagsEXT; + +typedef enum VkVideoEncodeH264StdFlagBitsEXT { + VK_VIDEO_ENCODE_H264_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_EXT = 0x00000001, + VK_VIDEO_ENCODE_H264_STD_QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG_SET_BIT_EXT = 0x00000002, + VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_EXT = 0x00000004, + VK_VIDEO_ENCODE_H264_STD_CHROMA_QP_INDEX_OFFSET_BIT_EXT = 0x00000008, + VK_VIDEO_ENCODE_H264_STD_SECOND_CHROMA_QP_INDEX_OFFSET_BIT_EXT = 0x00000010, + VK_VIDEO_ENCODE_H264_STD_PIC_INIT_QP_MINUS26_BIT_EXT = 0x00000020, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_PRED_FLAG_SET_BIT_EXT = 0x00000040, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_EXPLICIT_BIT_EXT = 0x00000080, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_IMPLICIT_BIT_EXT = 0x00000100, + VK_VIDEO_ENCODE_H264_STD_TRANSFORM_8X8_MODE_FLAG_SET_BIT_EXT = 0x00000200, + VK_VIDEO_ENCODE_H264_STD_DIRECT_SPATIAL_MV_PRED_FLAG_UNSET_BIT_EXT = 0x00000400, + VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_UNSET_BIT_EXT = 0x00000800, + VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_SET_BIT_EXT = 0x00001000, + VK_VIDEO_ENCODE_H264_STD_DIRECT_8X8_INFERENCE_FLAG_UNSET_BIT_EXT = 0x00002000, + VK_VIDEO_ENCODE_H264_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_EXT = 0x00004000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_DISABLED_BIT_EXT = 0x00008000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_ENABLED_BIT_EXT = 0x00010000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_PARTIAL_BIT_EXT = 0x00020000, + VK_VIDEO_ENCODE_H264_STD_SLICE_QP_DELTA_BIT_EXT = 0x00080000, + VK_VIDEO_ENCODE_H264_STD_DIFFERENT_SLICE_QP_DELTA_BIT_EXT = 0x00100000, + VK_VIDEO_ENCODE_H264_STD_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkVideoEncodeH264StdFlagBitsEXT; +typedef VkFlags VkVideoEncodeH264StdFlagsEXT; + +typedef enum VkVideoEncodeH264RateControlFlagBitsEXT { + VK_VIDEO_ENCODE_H264_RATE_CONTROL_ATTEMPT_HRD_COMPLIANCE_BIT_EXT = 0x00000001, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REGULAR_GOP_BIT_EXT = 0x00000002, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_EXT = 0x00000004, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_EXT = 0x00000008, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_TEMPORAL_LAYER_PATTERN_DYADIC_BIT_EXT = 0x00000010, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkVideoEncodeH264RateControlFlagBitsEXT; +typedef VkFlags VkVideoEncodeH264RateControlFlagsEXT; +typedef struct VkVideoEncodeH264CapabilitiesEXT { + VkStructureType sType; + void* pNext; + VkVideoEncodeH264CapabilityFlagsEXT flags; + StdVideoH264LevelIdc maxLevelIdc; + uint32_t maxSliceCount; + uint32_t maxPPictureL0ReferenceCount; + uint32_t maxBPictureL0ReferenceCount; + uint32_t maxL1ReferenceCount; + uint32_t maxTemporalLayerCount; + VkBool32 expectDyadicTemporalLayerPattern; + int32_t minQp; + int32_t maxQp; + VkBool32 prefersGopRemainingFrames; + VkBool32 requiresGopRemainingFrames; + VkVideoEncodeH264StdFlagsEXT stdSyntaxFlags; +} VkVideoEncodeH264CapabilitiesEXT; + +typedef struct VkVideoEncodeH264QpEXT { + int32_t qpI; + int32_t qpP; + int32_t qpB; +} VkVideoEncodeH264QpEXT; + +typedef struct VkVideoEncodeH264QualityLevelPropertiesEXT { + VkStructureType sType; + void* pNext; + VkVideoEncodeH264RateControlFlagsEXT preferredRateControlFlags; + uint32_t preferredGopFrameCount; + uint32_t preferredIdrPeriod; + uint32_t preferredConsecutiveBFrameCount; + uint32_t preferredTemporalLayerCount; + VkVideoEncodeH264QpEXT preferredConstantQp; + uint32_t preferredMaxL0ReferenceCount; + uint32_t preferredMaxL1ReferenceCount; + VkBool32 preferredStdEntropyCodingModeFlag; +} VkVideoEncodeH264QualityLevelPropertiesEXT; + +typedef struct VkVideoEncodeH264SessionCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 useMaxLevelIdc; + StdVideoH264LevelIdc maxLevelIdc; +} VkVideoEncodeH264SessionCreateInfoEXT; + +typedef struct VkVideoEncodeH264SessionParametersAddInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t stdSPSCount; + const StdVideoH264SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH264PictureParameterSet* pStdPPSs; +} VkVideoEncodeH264SessionParametersAddInfoEXT; + +typedef struct VkVideoEncodeH264SessionParametersCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoEncodeH264SessionParametersAddInfoEXT* pParametersAddInfo; +} VkVideoEncodeH264SessionParametersCreateInfoEXT; + +typedef struct VkVideoEncodeH264SessionParametersGetInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 writeStdSPS; + VkBool32 writeStdPPS; + uint32_t stdSPSId; + uint32_t stdPPSId; +} VkVideoEncodeH264SessionParametersGetInfoEXT; + +typedef struct VkVideoEncodeH264SessionParametersFeedbackInfoEXT { + VkStructureType sType; + void* pNext; + VkBool32 hasStdSPSOverrides; + VkBool32 hasStdPPSOverrides; +} VkVideoEncodeH264SessionParametersFeedbackInfoEXT; + +typedef struct VkVideoEncodeH264NaluSliceInfoEXT { + VkStructureType sType; + const void* pNext; + int32_t constantQp; + const StdVideoEncodeH264SliceHeader* pStdSliceHeader; +} VkVideoEncodeH264NaluSliceInfoEXT; + +typedef struct VkVideoEncodeH264PictureInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t naluSliceEntryCount; + const VkVideoEncodeH264NaluSliceInfoEXT* pNaluSliceEntries; + const StdVideoEncodeH264PictureInfo* pStdPictureInfo; + VkBool32 generatePrefixNalu; +} VkVideoEncodeH264PictureInfoEXT; + +typedef struct VkVideoEncodeH264DpbSlotInfoEXT { + VkStructureType sType; + const void* pNext; + const StdVideoEncodeH264ReferenceInfo* pStdReferenceInfo; +} VkVideoEncodeH264DpbSlotInfoEXT; + +typedef struct VkVideoEncodeH264ProfileInfoEXT { + VkStructureType sType; + const void* pNext; + StdVideoH264ProfileIdc stdProfileIdc; +} VkVideoEncodeH264ProfileInfoEXT; + +typedef struct VkVideoEncodeH264RateControlInfoEXT { + VkStructureType sType; + const void* pNext; + VkVideoEncodeH264RateControlFlagsEXT flags; + uint32_t gopFrameCount; + uint32_t idrPeriod; + uint32_t consecutiveBFrameCount; + uint32_t temporalLayerCount; +} VkVideoEncodeH264RateControlInfoEXT; + +typedef struct VkVideoEncodeH264FrameSizeEXT { + uint32_t frameISize; + uint32_t framePSize; + uint32_t frameBSize; +} VkVideoEncodeH264FrameSizeEXT; + +typedef struct VkVideoEncodeH264RateControlLayerInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 useMinQp; + VkVideoEncodeH264QpEXT minQp; + VkBool32 useMaxQp; + VkVideoEncodeH264QpEXT maxQp; + VkBool32 useMaxFrameSize; + VkVideoEncodeH264FrameSizeEXT maxFrameSize; +} VkVideoEncodeH264RateControlLayerInfoEXT; + +typedef struct VkVideoEncodeH264GopRemainingFrameInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 useGopRemainingFrames; + uint32_t gopRemainingI; + uint32_t gopRemainingP; + uint32_t gopRemainingB; +} VkVideoEncodeH264GopRemainingFrameInfoEXT; + + + +// VK_EXT_video_encode_h265 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_video_encode_h265 1 +#include "vk_video/vulkan_video_codec_h265std.h" +#include "vk_video/vulkan_video_codec_h265std_encode.h" +#define VK_EXT_VIDEO_ENCODE_H265_SPEC_VERSION 12 +#define VK_EXT_VIDEO_ENCODE_H265_EXTENSION_NAME "VK_EXT_video_encode_h265" + +typedef enum VkVideoEncodeH265CapabilityFlagBitsEXT { + VK_VIDEO_ENCODE_H265_CAPABILITY_HRD_COMPLIANCE_BIT_EXT = 0x00000001, + VK_VIDEO_ENCODE_H265_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_EXT = 0x00000002, + VK_VIDEO_ENCODE_H265_CAPABILITY_ROW_UNALIGNED_SLICE_SEGMENT_BIT_EXT = 0x00000004, + VK_VIDEO_ENCODE_H265_CAPABILITY_DIFFERENT_SLICE_SEGMENT_TYPE_BIT_EXT = 0x00000008, + VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_EXT = 0x00000010, + VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_EXT = 0x00000020, + VK_VIDEO_ENCODE_H265_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_EXT = 0x00000040, + VK_VIDEO_ENCODE_H265_CAPABILITY_PER_SLICE_SEGMENT_CONSTANT_QP_BIT_EXT = 0x00000080, + VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_TILES_PER_SLICE_SEGMENT_BIT_EXT = 0x00000100, + VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_SLICE_SEGMENTS_PER_TILE_BIT_EXT = 0x00000200, + VK_VIDEO_ENCODE_H265_CAPABILITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkVideoEncodeH265CapabilityFlagBitsEXT; +typedef VkFlags VkVideoEncodeH265CapabilityFlagsEXT; + +typedef enum VkVideoEncodeH265StdFlagBitsEXT { + VK_VIDEO_ENCODE_H265_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_EXT = 0x00000001, + VK_VIDEO_ENCODE_H265_STD_SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG_SET_BIT_EXT = 0x00000002, + VK_VIDEO_ENCODE_H265_STD_SCALING_LIST_DATA_PRESENT_FLAG_SET_BIT_EXT = 0x00000004, + VK_VIDEO_ENCODE_H265_STD_PCM_ENABLED_FLAG_SET_BIT_EXT = 0x00000008, + VK_VIDEO_ENCODE_H265_STD_SPS_TEMPORAL_MVP_ENABLED_FLAG_SET_BIT_EXT = 0x00000010, + VK_VIDEO_ENCODE_H265_STD_INIT_QP_MINUS26_BIT_EXT = 0x00000020, + VK_VIDEO_ENCODE_H265_STD_WEIGHTED_PRED_FLAG_SET_BIT_EXT = 0x00000040, + VK_VIDEO_ENCODE_H265_STD_WEIGHTED_BIPRED_FLAG_SET_BIT_EXT = 0x00000080, + VK_VIDEO_ENCODE_H265_STD_LOG2_PARALLEL_MERGE_LEVEL_MINUS2_BIT_EXT = 0x00000100, + VK_VIDEO_ENCODE_H265_STD_SIGN_DATA_HIDING_ENABLED_FLAG_SET_BIT_EXT = 0x00000200, + VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_SET_BIT_EXT = 0x00000400, + VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_UNSET_BIT_EXT = 0x00000800, + VK_VIDEO_ENCODE_H265_STD_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG_SET_BIT_EXT = 0x00001000, + VK_VIDEO_ENCODE_H265_STD_TRANSQUANT_BYPASS_ENABLED_FLAG_SET_BIT_EXT = 0x00002000, + VK_VIDEO_ENCODE_H265_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_EXT = 0x00004000, + VK_VIDEO_ENCODE_H265_STD_ENTROPY_CODING_SYNC_ENABLED_FLAG_SET_BIT_EXT = 0x00008000, + VK_VIDEO_ENCODE_H265_STD_DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_SET_BIT_EXT = 0x00010000, + VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG_SET_BIT_EXT = 0x00020000, + VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENT_FLAG_SET_BIT_EXT = 0x00040000, + VK_VIDEO_ENCODE_H265_STD_SLICE_QP_DELTA_BIT_EXT = 0x00080000, + VK_VIDEO_ENCODE_H265_STD_DIFFERENT_SLICE_QP_DELTA_BIT_EXT = 0x00100000, + VK_VIDEO_ENCODE_H265_STD_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkVideoEncodeH265StdFlagBitsEXT; +typedef VkFlags VkVideoEncodeH265StdFlagsEXT; + +typedef enum VkVideoEncodeH265CtbSizeFlagBitsEXT { + VK_VIDEO_ENCODE_H265_CTB_SIZE_16_BIT_EXT = 0x00000001, + VK_VIDEO_ENCODE_H265_CTB_SIZE_32_BIT_EXT = 0x00000002, + VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_EXT = 0x00000004, + VK_VIDEO_ENCODE_H265_CTB_SIZE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkVideoEncodeH265CtbSizeFlagBitsEXT; +typedef VkFlags VkVideoEncodeH265CtbSizeFlagsEXT; + +typedef enum VkVideoEncodeH265TransformBlockSizeFlagBitsEXT { + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_EXT = 0x00000001, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_8_BIT_EXT = 0x00000002, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_16_BIT_EXT = 0x00000004, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_32_BIT_EXT = 0x00000008, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkVideoEncodeH265TransformBlockSizeFlagBitsEXT; +typedef VkFlags VkVideoEncodeH265TransformBlockSizeFlagsEXT; + +typedef enum VkVideoEncodeH265RateControlFlagBitsEXT { + VK_VIDEO_ENCODE_H265_RATE_CONTROL_ATTEMPT_HRD_COMPLIANCE_BIT_EXT = 0x00000001, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REGULAR_GOP_BIT_EXT = 0x00000002, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_EXT = 0x00000004, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_EXT = 0x00000008, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_TEMPORAL_SUB_LAYER_PATTERN_DYADIC_BIT_EXT = 0x00000010, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkVideoEncodeH265RateControlFlagBitsEXT; +typedef VkFlags VkVideoEncodeH265RateControlFlagsEXT; +typedef struct VkVideoEncodeH265CapabilitiesEXT { + VkStructureType sType; + void* pNext; + VkVideoEncodeH265CapabilityFlagsEXT flags; + StdVideoH265LevelIdc maxLevelIdc; + uint32_t maxSliceSegmentCount; + VkExtent2D maxTiles; + VkVideoEncodeH265CtbSizeFlagsEXT ctbSizes; + VkVideoEncodeH265TransformBlockSizeFlagsEXT transformBlockSizes; + uint32_t maxPPictureL0ReferenceCount; + uint32_t maxBPictureL0ReferenceCount; + uint32_t maxL1ReferenceCount; + uint32_t maxSubLayerCount; + VkBool32 expectDyadicTemporalSubLayerPattern; + int32_t minQp; + int32_t maxQp; + VkBool32 prefersGopRemainingFrames; + VkBool32 requiresGopRemainingFrames; + VkVideoEncodeH265StdFlagsEXT stdSyntaxFlags; +} VkVideoEncodeH265CapabilitiesEXT; + +typedef struct VkVideoEncodeH265SessionCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 useMaxLevelIdc; + StdVideoH265LevelIdc maxLevelIdc; +} VkVideoEncodeH265SessionCreateInfoEXT; + +typedef struct VkVideoEncodeH265QpEXT { + int32_t qpI; + int32_t qpP; + int32_t qpB; +} VkVideoEncodeH265QpEXT; + +typedef struct VkVideoEncodeH265QualityLevelPropertiesEXT { + VkStructureType sType; + void* pNext; + VkVideoEncodeH265RateControlFlagsEXT preferredRateControlFlags; + uint32_t preferredGopFrameCount; + uint32_t preferredIdrPeriod; + uint32_t preferredConsecutiveBFrameCount; + uint32_t preferredSubLayerCount; + VkVideoEncodeH265QpEXT preferredConstantQp; + uint32_t preferredMaxL0ReferenceCount; + uint32_t preferredMaxL1ReferenceCount; +} VkVideoEncodeH265QualityLevelPropertiesEXT; + +typedef struct VkVideoEncodeH265SessionParametersAddInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t stdVPSCount; + const StdVideoH265VideoParameterSet* pStdVPSs; + uint32_t stdSPSCount; + const StdVideoH265SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH265PictureParameterSet* pStdPPSs; +} VkVideoEncodeH265SessionParametersAddInfoEXT; + +typedef struct VkVideoEncodeH265SessionParametersCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t maxStdVPSCount; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoEncodeH265SessionParametersAddInfoEXT* pParametersAddInfo; +} VkVideoEncodeH265SessionParametersCreateInfoEXT; + +typedef struct VkVideoEncodeH265SessionParametersGetInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 writeStdVPS; + VkBool32 writeStdSPS; + VkBool32 writeStdPPS; + uint32_t stdVPSId; + uint32_t stdSPSId; + uint32_t stdPPSId; +} VkVideoEncodeH265SessionParametersGetInfoEXT; + +typedef struct VkVideoEncodeH265SessionParametersFeedbackInfoEXT { + VkStructureType sType; + void* pNext; + VkBool32 hasStdVPSOverrides; + VkBool32 hasStdSPSOverrides; + VkBool32 hasStdPPSOverrides; +} VkVideoEncodeH265SessionParametersFeedbackInfoEXT; + +typedef struct VkVideoEncodeH265NaluSliceSegmentInfoEXT { + VkStructureType sType; + const void* pNext; + int32_t constantQp; + const StdVideoEncodeH265SliceSegmentHeader* pStdSliceSegmentHeader; +} VkVideoEncodeH265NaluSliceSegmentInfoEXT; + +typedef struct VkVideoEncodeH265PictureInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t naluSliceSegmentEntryCount; + const VkVideoEncodeH265NaluSliceSegmentInfoEXT* pNaluSliceSegmentEntries; + const StdVideoEncodeH265PictureInfo* pStdPictureInfo; +} VkVideoEncodeH265PictureInfoEXT; + +typedef struct VkVideoEncodeH265DpbSlotInfoEXT { + VkStructureType sType; + const void* pNext; + const StdVideoEncodeH265ReferenceInfo* pStdReferenceInfo; +} VkVideoEncodeH265DpbSlotInfoEXT; + +typedef struct VkVideoEncodeH265ProfileInfoEXT { + VkStructureType sType; + const void* pNext; + StdVideoH265ProfileIdc stdProfileIdc; +} VkVideoEncodeH265ProfileInfoEXT; + +typedef struct VkVideoEncodeH265RateControlInfoEXT { + VkStructureType sType; + const void* pNext; + VkVideoEncodeH265RateControlFlagsEXT flags; + uint32_t gopFrameCount; + uint32_t idrPeriod; + uint32_t consecutiveBFrameCount; + uint32_t subLayerCount; +} VkVideoEncodeH265RateControlInfoEXT; + +typedef struct VkVideoEncodeH265FrameSizeEXT { + uint32_t frameISize; + uint32_t framePSize; + uint32_t frameBSize; +} VkVideoEncodeH265FrameSizeEXT; + +typedef struct VkVideoEncodeH265RateControlLayerInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 useMinQp; + VkVideoEncodeH265QpEXT minQp; + VkBool32 useMaxQp; + VkVideoEncodeH265QpEXT maxQp; + VkBool32 useMaxFrameSize; + VkVideoEncodeH265FrameSizeEXT maxFrameSize; +} VkVideoEncodeH265RateControlLayerInfoEXT; + +typedef struct VkVideoEncodeH265GopRemainingFrameInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 useGopRemainingFrames; + uint32_t gopRemainingI; + uint32_t gopRemainingP; + uint32_t gopRemainingB; +} VkVideoEncodeH265GopRemainingFrameInfoEXT; + + + +// VK_AMDX_shader_enqueue is a preprocessor guard. Do not pass it to API calls. +#define VK_AMDX_shader_enqueue 1 +#define VK_AMDX_SHADER_ENQUEUE_SPEC_VERSION 1 +#define VK_AMDX_SHADER_ENQUEUE_EXTENSION_NAME "VK_AMDX_shader_enqueue" +#define VK_SHADER_INDEX_UNUSED_AMDX (~0U) +typedef struct VkPhysicalDeviceShaderEnqueueFeaturesAMDX { + VkStructureType sType; + void* pNext; + VkBool32 shaderEnqueue; +} VkPhysicalDeviceShaderEnqueueFeaturesAMDX; + +typedef struct VkPhysicalDeviceShaderEnqueuePropertiesAMDX { + VkStructureType sType; + void* pNext; + uint32_t maxExecutionGraphDepth; + uint32_t maxExecutionGraphShaderOutputNodes; + uint32_t maxExecutionGraphShaderPayloadSize; + uint32_t maxExecutionGraphShaderPayloadCount; + uint32_t executionGraphDispatchAddressAlignment; +} VkPhysicalDeviceShaderEnqueuePropertiesAMDX; + +typedef struct VkExecutionGraphPipelineScratchSizeAMDX { + VkStructureType sType; + void* pNext; + VkDeviceSize size; +} VkExecutionGraphPipelineScratchSizeAMDX; + +typedef struct VkExecutionGraphPipelineCreateInfoAMDX { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineLibraryCreateInfoKHR* pLibraryInfo; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkExecutionGraphPipelineCreateInfoAMDX; + +typedef union VkDeviceOrHostAddressConstAMDX { + VkDeviceAddress deviceAddress; + const void* hostAddress; +} VkDeviceOrHostAddressConstAMDX; + +typedef struct VkDispatchGraphInfoAMDX { + uint32_t nodeIndex; + uint32_t payloadCount; + VkDeviceOrHostAddressConstAMDX payloads; + uint64_t payloadStride; +} VkDispatchGraphInfoAMDX; + +typedef struct VkDispatchGraphCountInfoAMDX { + uint32_t count; + VkDeviceOrHostAddressConstAMDX infos; + uint64_t stride; +} VkDispatchGraphCountInfoAMDX; + +typedef struct VkPipelineShaderStageNodeCreateInfoAMDX { + VkStructureType sType; + const void* pNext; + const char* pName; + uint32_t index; +} VkPipelineShaderStageNodeCreateInfoAMDX; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateExecutionGraphPipelinesAMDX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkExecutionGraphPipelineCreateInfoAMDX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetExecutionGraphPipelineScratchSizeAMDX)(VkDevice device, VkPipeline executionGraph, VkExecutionGraphPipelineScratchSizeAMDX* pSizeInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetExecutionGraphPipelineNodeIndexAMDX)(VkDevice device, VkPipeline executionGraph, const VkPipelineShaderStageNodeCreateInfoAMDX* pNodeInfo, uint32_t* pNodeIndex); +typedef void (VKAPI_PTR *PFN_vkCmdInitializeGraphScratchMemoryAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchGraphAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, const VkDispatchGraphCountInfoAMDX* pCountInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchGraphIndirectAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, const VkDispatchGraphCountInfoAMDX* pCountInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchGraphIndirectCountAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceAddress countInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateExecutionGraphPipelinesAMDX( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkExecutionGraphPipelineCreateInfoAMDX* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetExecutionGraphPipelineScratchSizeAMDX( + VkDevice device, + VkPipeline executionGraph, + VkExecutionGraphPipelineScratchSizeAMDX* pSizeInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetExecutionGraphPipelineNodeIndexAMDX( + VkDevice device, + VkPipeline executionGraph, + const VkPipelineShaderStageNodeCreateInfoAMDX* pNodeInfo, + uint32_t* pNodeIndex); + +VKAPI_ATTR void VKAPI_CALL vkCmdInitializeGraphScratchMemoryAMDX( + VkCommandBuffer commandBuffer, + VkDeviceAddress scratch); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchGraphAMDX( + VkCommandBuffer commandBuffer, + VkDeviceAddress scratch, + const VkDispatchGraphCountInfoAMDX* pCountInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchGraphIndirectAMDX( + VkCommandBuffer commandBuffer, + VkDeviceAddress scratch, + const VkDispatchGraphCountInfoAMDX* pCountInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchGraphIndirectCountAMDX( + VkCommandBuffer commandBuffer, + VkDeviceAddress scratch, + VkDeviceAddress countInfo); +#endif + + +// VK_NV_displacement_micromap is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_displacement_micromap 1 +#define VK_NV_DISPLACEMENT_MICROMAP_SPEC_VERSION 2 +#define VK_NV_DISPLACEMENT_MICROMAP_EXTENSION_NAME "VK_NV_displacement_micromap" + +typedef enum VkDisplacementMicromapFormatNV { + VK_DISPLACEMENT_MICROMAP_FORMAT_64_TRIANGLES_64_BYTES_NV = 1, + VK_DISPLACEMENT_MICROMAP_FORMAT_256_TRIANGLES_128_BYTES_NV = 2, + VK_DISPLACEMENT_MICROMAP_FORMAT_1024_TRIANGLES_128_BYTES_NV = 3, + VK_DISPLACEMENT_MICROMAP_FORMAT_MAX_ENUM_NV = 0x7FFFFFFF +} VkDisplacementMicromapFormatNV; +typedef struct VkPhysicalDeviceDisplacementMicromapFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 displacementMicromap; +} VkPhysicalDeviceDisplacementMicromapFeaturesNV; + +typedef struct VkPhysicalDeviceDisplacementMicromapPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxDisplacementMicromapSubdivisionLevel; +} VkPhysicalDeviceDisplacementMicromapPropertiesNV; + +typedef struct VkAccelerationStructureTrianglesDisplacementMicromapNV { + VkStructureType sType; + void* pNext; + VkFormat displacementBiasAndScaleFormat; + VkFormat displacementVectorFormat; + VkDeviceOrHostAddressConstKHR displacementBiasAndScaleBuffer; + VkDeviceSize displacementBiasAndScaleStride; + VkDeviceOrHostAddressConstKHR displacementVectorBuffer; + VkDeviceSize displacementVectorStride; + VkDeviceOrHostAddressConstKHR displacedMicromapPrimitiveFlags; + VkDeviceSize displacedMicromapPrimitiveFlagsStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + uint32_t usageCountsCount; + const VkMicromapUsageEXT* pUsageCounts; + const VkMicromapUsageEXT* const* ppUsageCounts; + VkMicromapEXT micromap; +} VkAccelerationStructureTrianglesDisplacementMicromapNV; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_core.h b/libraries/ZVulkan/include/vulkan/vulkan_core.h new file mode 100644 index 00000000000..71c28745414 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_core.h @@ -0,0 +1,18595 @@ +#ifndef VULKAN_CORE_H_ +#define VULKAN_CORE_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_VERSION_1_0 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_0 1 +#include "vk_platform.h" + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + + +#ifndef VK_USE_64_BIT_PTR_DEFINES + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64) + #define VK_USE_64_BIT_PTR_DEFINES 1 + #else + #define VK_USE_64_BIT_PTR_DEFINES 0 + #endif +#endif + + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)) + #define VK_NULL_HANDLE nullptr + #else + #define VK_NULL_HANDLE ((void*)0) + #endif + #else + #define VK_NULL_HANDLE 0ULL + #endif +#endif +#ifndef VK_NULL_HANDLE + #define VK_NULL_HANDLE 0 +#endif + + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; + #else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; + #endif +#endif + +#define VK_MAKE_API_VERSION(variant, major, minor, patch) \ + ((((uint32_t)(variant)) << 29U) | (((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) + +// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. +//#define VK_API_VERSION VK_MAKE_API_VERSION(0, 1, 0, 0) // Patch version should always be set to 0 + +// Vulkan 1.0 version number +#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0 + +// Version of this file +#define VK_HEADER_VERSION 270 + +// Complete version of this file +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION) + +// DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead. +#define VK_MAKE_VERSION(major, minor, patch) \ + ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) + +// DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22U) + +// DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead. +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) + +// DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead. +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) + +#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29U) +#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22U) & 0x7FU) +#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) +#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) +typedef uint32_t VkBool32; +typedef uint64_t VkDeviceAddress; +typedef uint64_t VkDeviceSize; +typedef uint32_t VkFlags; +typedef uint32_t VkSampleMask; +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_HANDLE(VkPhysicalDevice) +VK_DEFINE_HANDLE(VkDevice) +VK_DEFINE_HANDLE(VkQueue) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) +VK_DEFINE_HANDLE(VkCommandBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) +#define VK_ATTACHMENT_UNUSED (~0U) +#define VK_FALSE 0U +#define VK_LOD_CLAMP_NONE 1000.0F +#define VK_QUEUE_FAMILY_IGNORED (~0U) +#define VK_REMAINING_ARRAY_LAYERS (~0U) +#define VK_REMAINING_MIP_LEVELS (~0U) +#define VK_SUBPASS_EXTERNAL (~0U) +#define VK_TRUE 1U +#define VK_WHOLE_SIZE (~0ULL) +#define VK_MAX_MEMORY_TYPES 32U +#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256U +#define VK_UUID_SIZE 16U +#define VK_MAX_EXTENSION_NAME_SIZE 256U +#define VK_MAX_DESCRIPTION_SIZE 256U +#define VK_MAX_MEMORY_HEAPS 16U + +typedef enum VkResult { + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_FRAGMENTED_POOL = -12, + VK_ERROR_UNKNOWN = -13, + VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000, + VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, + VK_ERROR_FRAGMENTATION = -1000161000, + VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, + VK_PIPELINE_COMPILE_REQUIRED = 1000297000, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, + VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, + VK_ERROR_INVALID_SHADER_NV = -1000012000, + VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR = -1000023000, + VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR = -1000023001, + VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR = -1000023002, + VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR = -1000023003, + VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR = -1000023004, + VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR = -1000023005, + VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, + VK_ERROR_NOT_PERMITTED_KHR = -1000174001, + VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, + VK_THREAD_IDLE_KHR = 1000268000, + VK_THREAD_DONE_KHR = 1000268001, + VK_OPERATION_DEFERRED_KHR = 1000268002, + VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR = -1000299000, +#endif + VK_ERROR_COMPRESSION_EXHAUSTED_EXT = -1000338000, + VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT = 1000482000, + VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, + VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, + VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, + VK_ERROR_NOT_PERMITTED_EXT = VK_ERROR_NOT_PERMITTED_KHR, + VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + VK_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_RESULT_MAX_ENUM = 0x7FFFFFFF +} VkResult; + +typedef enum VkStructureType { + VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, + VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, + VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, + VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, + VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, + VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, + VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, + VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000, + VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES = 50, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES = 51, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES = 52, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO = 1000147000, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2 = 1000109000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2 = 1000109001, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2 = 1000109002, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2 = 1000109003, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2 = 1000109004, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO = 1000109005, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO = 1000109006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES = 1000177000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES = 1000196000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES = 1000180000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES = 1000082000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES = 1000197000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO = 1000161000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES = 1000161001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES = 1000161002, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO = 1000161003, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT = 1000161004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES = 1000199000, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE = 1000199001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES = 1000221000, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO = 1000246000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES = 1000130000, + VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO = 1000130001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES = 1000211000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES = 1000108000, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO = 1000108001, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO = 1000108002, + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO = 1000108003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES = 1000175000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES = 1000241000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT = 1000241001, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT = 1000241002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES = 1000261000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES = 1000207000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES = 1000207001, + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO = 1000207002, + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO = 1000207003, + VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO = 1000207004, + VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO = 1000207005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO = 1000244001, + VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, + VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES = 53, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES = 54, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO = 1000192000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES = 1000215000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES = 1000245000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES = 1000295000, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO = 1000295001, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO = 1000295002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES = 1000297000, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 = 1000314000, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 = 1000314001, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 = 1000314002, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO = 1000314003, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2 = 1000314004, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO = 1000314005, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO = 1000314006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES = 1000314007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES = 1000325000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES = 1000335000, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2 = 1000337000, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2 = 1000337001, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2 = 1000337002, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2 = 1000337003, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2 = 1000337004, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2 = 1000337005, + VK_STRUCTURE_TYPE_BUFFER_COPY_2 = 1000337006, + VK_STRUCTURE_TYPE_IMAGE_COPY_2 = 1000337007, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2 = 1000337008, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2 = 1000337009, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2 = 1000337010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES = 1000225000, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO = 1000225001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES = 1000225002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES = 1000138000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES = 1000138001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK = 1000138002, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO = 1000138003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES = 1000066000, + VK_STRUCTURE_TYPE_RENDERING_INFO = 1000044000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO = 1000044001, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO = 1000044002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES = 1000044003, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO = 1000044004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES = 1000280000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES = 1000280001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES = 1000281001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3 = 1000360000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES = 1000413000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 1000413001, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS = 1000413002, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS = 1000413003, + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, + VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, + VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, + VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, + VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, + VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, + VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, + VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, + VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, + VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR = 1000023000, + VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR = 1000023001, + VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR = 1000023002, + VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR = 1000023003, + VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR = 1000023004, + VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR = 1000023005, + VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000023006, + VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR = 1000023007, + VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR = 1000023008, + VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR = 1000023009, + VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR = 1000023010, + VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR = 1000023011, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR = 1000023012, + VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR = 1000023013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR = 1000023014, + VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR = 1000023015, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_KHR = 1000023016, + VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR = 1000024000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR = 1000024001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR = 1000024002, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, + VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX = 1000029000, + VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX = 1000029001, + VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX = 1000029002, + VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT = 1000038000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PICTURE_INFO_EXT = 1000038003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038004, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_INFO_EXT = 1000038005, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_GOP_REMAINING_FRAME_INFO_EXT = 1000038006, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_EXT = 1000038007, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_EXT = 1000038008, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT = 1000038009, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT = 1000038010, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_QUALITY_LEVEL_PROPERTIES_EXT = 1000038011, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_EXT = 1000038012, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_FEEDBACK_INFO_EXT = 1000038013, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_EXT = 1000039000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000039001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000039002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PICTURE_INFO_EXT = 1000039003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_EXT = 1000039004, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_INFO_EXT = 1000039005, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_GOP_REMAINING_FRAME_INFO_EXT = 1000039006, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_EXT = 1000039007, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_EXT = 1000039009, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_EXT = 1000039010, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_CREATE_INFO_EXT = 1000039011, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_QUALITY_LEVEL_PROPERTIES_EXT = 1000039012, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_GET_INFO_EXT = 1000039013, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_FEEDBACK_INFO_EXT = 1000039014, +#endif + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_KHR = 1000040000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR = 1000040001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR = 1000040003, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000040004, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR = 1000040005, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR = 1000040006, + VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000044006, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT = 1000044007, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD = 1000044008, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX = 1000044009, + VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, + VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, + VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, + VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, + VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT = 1000068000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT = 1000068001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT = 1000068002, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, + VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, + VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000, + VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001, + VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002, + VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, + VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, + VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, + VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000, + VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, + VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001, + VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002, + VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, + VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, + VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, + VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RELAXED_LINE_RASTERIZATION_FEATURES_IMG = 1000110000, + VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, + VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, + VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, + VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, + VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000, + VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR = 1000116000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR = 1000116001, + VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR = 1000116002, + VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR = 1000116003, + VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR = 1000116005, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, + VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, + VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR = 1000121000, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001, + VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR = 1000121003, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004, + VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000, + VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002, + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002, + VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, + VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID = 1000129006, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ENQUEUE_FEATURES_AMDX = 1000134000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ENQUEUE_PROPERTIES_AMDX = 1000134001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_EXECUTION_GRAPH_PIPELINE_SCRATCH_SIZE_AMDX = 1000134002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_EXECUTION_GRAPH_PIPELINE_CREATE_INFO_AMDX = 1000134003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_NODE_CREATE_INFO_AMDX = 1000134004, +#endif + VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, + VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, + VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, + VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000150007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR = 1000150009, + VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, + VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR = 1000150013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR = 1000347001, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR = 1000348013, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT = 1000158006, + VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, + VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR = 1000163000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR = 1000163001, +#endif + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, + VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, + VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, + VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, + VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, + VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, + VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR = 1000181000, + VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR = 1000187000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000187001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR = 1000187002, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR = 1000187003, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_KHR = 1000187004, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR = 1000187005, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR = 1000174000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR = 1000388000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR = 1000388001, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, + VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL = 1000209000, + VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL = 1000210000, + VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL = 1000210001, + VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL = 1000210002, + VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL = 1000210003, + VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL = 1000210004, + VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL = 1000210005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, + VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, + VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, + VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, + VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, + VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR = 1000226003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, + VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, + VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR = 1000239000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, + VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR = 1000248000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV = 1000250000, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV = 1000250001, + VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV = 1000250002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT = 1000254000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT = 1000254001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT = 1000254002, + VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, + VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, + VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, + VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR = 1000269001, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR = 1000269003, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT = 1000270000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES_EXT = 1000270001, + VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT = 1000270002, + VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT = 1000270003, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT = 1000270004, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT = 1000270005, + VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT = 1000270006, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO_EXT = 1000270007, + VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE_EXT = 1000270008, + VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT = 1000270009, + VK_STRUCTURE_TYPE_MEMORY_MAP_INFO_KHR = 1000271000, + VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR = 1000271001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT = 1000274000, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT = 1000274001, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT = 1000274002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT = 1000275000, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT = 1000275001, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT = 1000275002, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT = 1000275003, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT = 1000275004, + VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT = 1000275005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, + VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV = 1000277003, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV = 1000277004, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV = 1000277005, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, + VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_BIAS_CONTROL_FEATURES_EXT = 1000283000, + VK_STRUCTURE_TYPE_DEPTH_BIAS_INFO_EXT = 1000283001, + VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT = 1000283002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT = 1000284000, + VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT = 1000284001, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT = 1000284002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = 1000286000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = 1000286001, + VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, + VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV = 1000292000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV = 1000292001, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV = 1000292002, + VK_STRUCTURE_TYPE_PRESENT_ID_KHR = 1000294000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR = 1000299000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR = 1000299001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR = 1000299002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR = 1000299003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_USAGE_INFO_KHR = 1000299004, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_QUERY_POOL_VIDEO_ENCODE_FEEDBACK_CREATE_INFO_KHR = 1000299005, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR = 1000299006, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_PROPERTIES_KHR = 1000299007, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR = 1000299008, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_GET_INFO_KHR = 1000299009, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_FEEDBACK_INFO_KHR = 1000299010, +#endif + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, + VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, + VK_STRUCTURE_TYPE_CUDA_MODULE_CREATE_INFO_NV = 1000307000, + VK_STRUCTURE_TYPE_CUDA_FUNCTION_CREATE_INFO_NV = 1000307001, + VK_STRUCTURE_TYPE_CUDA_LAUNCH_INFO_NV = 1000307002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_FEATURES_NV = 1000307003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_PROPERTIES_NV = 1000307004, + VK_STRUCTURE_TYPE_QUERY_LOW_LATENCY_SUPPORT_NV = 1000310000, + VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT = 1000311000, + VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT = 1000311001, + VK_STRUCTURE_TYPE_EXPORT_METAL_DEVICE_INFO_EXT = 1000311002, + VK_STRUCTURE_TYPE_EXPORT_METAL_COMMAND_QUEUE_INFO_EXT = 1000311003, + VK_STRUCTURE_TYPE_EXPORT_METAL_BUFFER_INFO_EXT = 1000311004, + VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT = 1000311005, + VK_STRUCTURE_TYPE_EXPORT_METAL_TEXTURE_INFO_EXT = 1000311006, + VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT = 1000311007, + VK_STRUCTURE_TYPE_EXPORT_METAL_IO_SURFACE_INFO_EXT = 1000311008, + VK_STRUCTURE_TYPE_IMPORT_METAL_IO_SURFACE_INFO_EXT = 1000311009, + VK_STRUCTURE_TYPE_EXPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311010, + VK_STRUCTURE_TYPE_IMPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311011, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV = 1000314009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT = 1000316000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT = 1000316001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT = 1000316002, + VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT = 1000316003, + VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT = 1000316004, + VK_STRUCTURE_TYPE_BUFFER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316005, + VK_STRUCTURE_TYPE_IMAGE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316006, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316007, + VK_STRUCTURE_TYPE_SAMPLER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316008, + VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT = 1000316010, + VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT = 1000316011, + VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT = 1000316012, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT = 1000320000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT = 1000320001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT = 1000320002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD = 1000321000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR = 1000203000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR = 1000322000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV = 1000327000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV = 1000327001, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV = 1000327002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT = 1000328000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT = 1000328001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, + VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT = 1000338000, + VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT = 1000338001, + VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT = 1000338004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT = 1000339000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT = 1000341000, + VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT = 1000341001, + VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT = 1000341002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT = 1000344000, + VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000, + VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, + VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT = 1000353000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT = 1000354000, + VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT = 1000354001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT = 1000355000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT = 1000355001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT = 1000356000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364000, + VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA = 1000364001, + VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364002, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365000, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA = 1000366000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA = 1000366001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA = 1000366002, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA = 1000366003, + VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA = 1000366004, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA = 1000366005, + VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA = 1000366006, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA = 1000366007, + VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA = 1000366008, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA = 1000366009, + VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI = 1000369000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI = 1000369001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI = 1000369002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI = 1000370000, + VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV = 1000371000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV = 1000371001, + VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT = 1000372000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT = 1000372001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT = 1000375000, + VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT = 1000375001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT = 1000376000, + VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT = 1000376001, + VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT = 1000376002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000, + VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT = 1000382000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR = 1000386000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT = 1000391000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT = 1000391001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT = 1000393000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_FEATURES_EXT = 1000395000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT = 1000395001, + VK_STRUCTURE_TYPE_MICROMAP_BUILD_INFO_EXT = 1000396000, + VK_STRUCTURE_TYPE_MICROMAP_VERSION_INFO_EXT = 1000396001, + VK_STRUCTURE_TYPE_COPY_MICROMAP_INFO_EXT = 1000396002, + VK_STRUCTURE_TYPE_COPY_MICROMAP_TO_MEMORY_INFO_EXT = 1000396003, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_MICROMAP_INFO_EXT = 1000396004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT = 1000396005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT = 1000396006, + VK_STRUCTURE_TYPE_MICROMAP_CREATE_INFO_EXT = 1000396007, + VK_STRUCTURE_TYPE_MICROMAP_BUILD_SIZES_INFO_EXT = 1000396008, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT = 1000396009, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISPLACEMENT_MICROMAP_FEATURES_NV = 1000397000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISPLACEMENT_MICROMAP_PROPERTIES_NV = 1000397001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_DISPLACEMENT_MICROMAP_NV = 1000397002, +#endif + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_FEATURES_HUAWEI = 1000404000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI = 1000404001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000, + VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM = 1000415000, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_SHADER_CORE_CONTROL_CREATE_INFO_ARM = 1000417000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_FEATURES_ARM = 1000417001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM = 1000417002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_SLICED_VIEW_OF_3D_FEATURES_EXT = 1000418000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_SLICED_CREATE_INFO_EXT = 1000418001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE = 1000420001, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT = 1000421000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT = 1000422000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = 1000425000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = 1000425001, + VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = 1000425002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV = 1000426000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV = 1000426001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV = 1000427000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV = 1000427001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_COMPUTE_FEATURES_NV = 1000428000, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_INDIRECT_BUFFER_INFO_NV = 1000428001, + VK_STRUCTURE_TYPE_PIPELINE_INDIRECT_DEVICE_ADDRESS_INFO_NV = 1000428002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT = 1000437000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM = 1000440000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM = 1000440001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM = 1000440002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_FEATURES_EXT = 1000451000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT = 1000451001, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXT = 1000453000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT = 1000455000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT = 1000455001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT = 1000458000, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT = 1000458001, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000458002, + VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT = 1000458003, + VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG = 1000459000, + VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG = 1000459001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT = 1000462000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT = 1000462001, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT = 1000462002, + VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT = 1000462003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT = 1000342000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV = 1000464000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV = 1000464001, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV = 1000464002, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_NV = 1000464003, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV = 1000464004, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_EXECUTE_INFO_NV = 1000464005, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV = 1000464010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT = 1000465000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT = 1000466000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_FEATURES_ANDROID = 1000468000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR = 1000470000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR = 1000470001, + VK_STRUCTURE_TYPE_RENDERING_AREA_INFO_KHR = 1000470003, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO_KHR = 1000470004, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR = 1000338002, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_KHR = 1000338003, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR = 1000470005, + VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR = 1000470006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_POSITION_FETCH_FEATURES_KHR = 1000481000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT = 1000482000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT = 1000482001, + VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT = 1000482002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM = 1000484000, + VK_STRUCTURE_TYPE_TILE_PROPERTIES_QCOM = 1000484001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_AMIGO_PROFILING_FEATURES_SEC = 1000485000, + VK_STRUCTURE_TYPE_AMIGO_PROFILING_SUBMIT_INFO_SEC = 1000485001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM = 1000488000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV = 1000490000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV = 1000490001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_FEATURES_NV = 1000492000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV = 1000492001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT = 1000351000, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT = 1000351002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM = 1000497000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM = 1000497001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_LIBRARY_GROUP_HANDLES_FEATURES_EXT = 1000498000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT = 1000499000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV = 1000505000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_INFO_NV = 1000505001, + VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV = 1000505002, + VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV = 1000505003, + VK_STRUCTURE_TYPE_LATENCY_TIMINGS_FRAME_REPORT_NV = 1000505004, + VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV = 1000505005, + VK_STRUCTURE_TYPE_OUT_OF_BAND_QUEUE_TYPE_INFO_NV = 1000505006, + VK_STRUCTURE_TYPE_SWAPCHAIN_LATENCY_CREATE_INFO_NV = 1000505007, + VK_STRUCTURE_TYPE_LATENCY_SURFACE_CAPABILITIES_NV = 1000505008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR = 1000506000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_RENDER_AREAS_FEATURES_QCOM = 1000510000, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_RENDER_AREAS_RENDER_PASS_BEGIN_INFO_QCOM = 1000510001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_FEATURES_QCOM = 1000518000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM = 1000518001, + VK_STRUCTURE_TYPE_SAMPLER_BLOCK_MATCH_WINDOW_CREATE_INFO_QCOM = 1000518002, + VK_STRUCTURE_TYPE_SAMPLER_CUBIC_WEIGHTS_CREATE_INFO_QCOM = 1000519000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_WEIGHTS_FEATURES_QCOM = 1000519001, + VK_STRUCTURE_TYPE_BLIT_IMAGE_CUBIC_WEIGHTS_INFO_QCOM = 1000519002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_DEGAMMA_FEATURES_QCOM = 1000520000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_YCBCR_DEGAMMA_CREATE_INFO_QCOM = 1000520001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_CLAMP_FEATURES_QCOM = 1000521000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_FEATURES_EXT = 1000524000, + VK_STRUCTURE_TYPE_SCREEN_BUFFER_PROPERTIES_QNX = 1000529000, + VK_STRUCTURE_TYPE_SCREEN_BUFFER_FORMAT_PROPERTIES_QNX = 1000529001, + VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX = 1000529002, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_QNX = 1000529003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX = 1000529004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT = 1000530000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV = 1000546000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, + VK_STRUCTURE_TYPE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INFO, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_NV = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, + VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL = VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, + VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_EXT = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_EXT = VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3, + VK_STRUCTURE_TYPE_PIPELINE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_SHADER_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkStructureType; + +typedef enum VkPipelineCacheHeaderVersion { + VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, + VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheHeaderVersion; + +typedef enum VkImageLayout { + VK_IMAGE_LAYOUT_UNDEFINED = 0, + VK_IMAGE_LAYOUT_GENERAL = 1, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, + VK_IMAGE_LAYOUT_PREINITIALIZED = 8, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL = 1000241000, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL = 1000314000, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL = 1000314001, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, + VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR = 1000024000, + VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR = 1000024001, + VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR = 1000024002, + VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, + VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR = 1000164003, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR = 1000299000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR = 1000299001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR = 1000299002, +#endif + VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT = 1000339000, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF +} VkImageLayout; + +typedef enum VkObjectType { + VK_OBJECT_TYPE_UNKNOWN = 0, + VK_OBJECT_TYPE_INSTANCE = 1, + VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2, + VK_OBJECT_TYPE_DEVICE = 3, + VK_OBJECT_TYPE_QUEUE = 4, + VK_OBJECT_TYPE_SEMAPHORE = 5, + VK_OBJECT_TYPE_COMMAND_BUFFER = 6, + VK_OBJECT_TYPE_FENCE = 7, + VK_OBJECT_TYPE_DEVICE_MEMORY = 8, + VK_OBJECT_TYPE_BUFFER = 9, + VK_OBJECT_TYPE_IMAGE = 10, + VK_OBJECT_TYPE_EVENT = 11, + VK_OBJECT_TYPE_QUERY_POOL = 12, + VK_OBJECT_TYPE_BUFFER_VIEW = 13, + VK_OBJECT_TYPE_IMAGE_VIEW = 14, + VK_OBJECT_TYPE_SHADER_MODULE = 15, + VK_OBJECT_TYPE_PIPELINE_CACHE = 16, + VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17, + VK_OBJECT_TYPE_RENDER_PASS = 18, + VK_OBJECT_TYPE_PIPELINE = 19, + VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20, + VK_OBJECT_TYPE_SAMPLER = 21, + VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22, + VK_OBJECT_TYPE_DESCRIPTOR_SET = 23, + VK_OBJECT_TYPE_FRAMEBUFFER = 24, + VK_OBJECT_TYPE_COMMAND_POOL = 25, + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT = 1000295000, + VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, + VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, + VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, + VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, + VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, + VK_OBJECT_TYPE_VIDEO_SESSION_KHR = 1000023000, + VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR = 1000023001, + VK_OBJECT_TYPE_CU_MODULE_NVX = 1000029000, + VK_OBJECT_TYPE_CU_FUNCTION_NVX = 1000029001, + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, + VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, + VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, + VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, + VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, + VK_OBJECT_TYPE_CUDA_MODULE_NV = 1000307000, + VK_OBJECT_TYPE_CUDA_FUNCTION_NV = 1000307001, + VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA = 1000366000, + VK_OBJECT_TYPE_MICROMAP_EXT = 1000396000, + VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV = 1000464000, + VK_OBJECT_TYPE_SHADER_EXT = 1000482000, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = VK_OBJECT_TYPE_PRIVATE_DATA_SLOT, + VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkObjectType; + +typedef enum VkVendorId { + VK_VENDOR_ID_VIV = 0x10001, + VK_VENDOR_ID_VSI = 0x10002, + VK_VENDOR_ID_KAZAN = 0x10003, + VK_VENDOR_ID_CODEPLAY = 0x10004, + VK_VENDOR_ID_MESA = 0x10005, + VK_VENDOR_ID_POCL = 0x10006, + VK_VENDOR_ID_MOBILEYE = 0x10007, + VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF +} VkVendorId; + +typedef enum VkSystemAllocationScope { + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, + VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, + VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF +} VkSystemAllocationScope; + +typedef enum VkInternalAllocationType { + VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, + VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkInternalAllocationType; + +typedef enum VkFormat { + VK_FORMAT_UNDEFINED = 0, + VK_FORMAT_R4G4_UNORM_PACK8 = 1, + VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, + VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, + VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, + VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, + VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, + VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, + VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, + VK_FORMAT_R8_UNORM = 9, + VK_FORMAT_R8_SNORM = 10, + VK_FORMAT_R8_USCALED = 11, + VK_FORMAT_R8_SSCALED = 12, + VK_FORMAT_R8_UINT = 13, + VK_FORMAT_R8_SINT = 14, + VK_FORMAT_R8_SRGB = 15, + VK_FORMAT_R8G8_UNORM = 16, + VK_FORMAT_R8G8_SNORM = 17, + VK_FORMAT_R8G8_USCALED = 18, + VK_FORMAT_R8G8_SSCALED = 19, + VK_FORMAT_R8G8_UINT = 20, + VK_FORMAT_R8G8_SINT = 21, + VK_FORMAT_R8G8_SRGB = 22, + VK_FORMAT_R8G8B8_UNORM = 23, + VK_FORMAT_R8G8B8_SNORM = 24, + VK_FORMAT_R8G8B8_USCALED = 25, + VK_FORMAT_R8G8B8_SSCALED = 26, + VK_FORMAT_R8G8B8_UINT = 27, + VK_FORMAT_R8G8B8_SINT = 28, + VK_FORMAT_R8G8B8_SRGB = 29, + VK_FORMAT_B8G8R8_UNORM = 30, + VK_FORMAT_B8G8R8_SNORM = 31, + VK_FORMAT_B8G8R8_USCALED = 32, + VK_FORMAT_B8G8R8_SSCALED = 33, + VK_FORMAT_B8G8R8_UINT = 34, + VK_FORMAT_B8G8R8_SINT = 35, + VK_FORMAT_B8G8R8_SRGB = 36, + VK_FORMAT_R8G8B8A8_UNORM = 37, + VK_FORMAT_R8G8B8A8_SNORM = 38, + VK_FORMAT_R8G8B8A8_USCALED = 39, + VK_FORMAT_R8G8B8A8_SSCALED = 40, + VK_FORMAT_R8G8B8A8_UINT = 41, + VK_FORMAT_R8G8B8A8_SINT = 42, + VK_FORMAT_R8G8B8A8_SRGB = 43, + VK_FORMAT_B8G8R8A8_UNORM = 44, + VK_FORMAT_B8G8R8A8_SNORM = 45, + VK_FORMAT_B8G8R8A8_USCALED = 46, + VK_FORMAT_B8G8R8A8_SSCALED = 47, + VK_FORMAT_B8G8R8A8_UINT = 48, + VK_FORMAT_B8G8R8A8_SINT = 49, + VK_FORMAT_B8G8R8A8_SRGB = 50, + VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, + VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, + VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, + VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, + VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, + VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, + VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, + VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, + VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, + VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, + VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, + VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, + VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, + VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, + VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, + VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, + VK_FORMAT_R16_UNORM = 70, + VK_FORMAT_R16_SNORM = 71, + VK_FORMAT_R16_USCALED = 72, + VK_FORMAT_R16_SSCALED = 73, + VK_FORMAT_R16_UINT = 74, + VK_FORMAT_R16_SINT = 75, + VK_FORMAT_R16_SFLOAT = 76, + VK_FORMAT_R16G16_UNORM = 77, + VK_FORMAT_R16G16_SNORM = 78, + VK_FORMAT_R16G16_USCALED = 79, + VK_FORMAT_R16G16_SSCALED = 80, + VK_FORMAT_R16G16_UINT = 81, + VK_FORMAT_R16G16_SINT = 82, + VK_FORMAT_R16G16_SFLOAT = 83, + VK_FORMAT_R16G16B16_UNORM = 84, + VK_FORMAT_R16G16B16_SNORM = 85, + VK_FORMAT_R16G16B16_USCALED = 86, + VK_FORMAT_R16G16B16_SSCALED = 87, + VK_FORMAT_R16G16B16_UINT = 88, + VK_FORMAT_R16G16B16_SINT = 89, + VK_FORMAT_R16G16B16_SFLOAT = 90, + VK_FORMAT_R16G16B16A16_UNORM = 91, + VK_FORMAT_R16G16B16A16_SNORM = 92, + VK_FORMAT_R16G16B16A16_USCALED = 93, + VK_FORMAT_R16G16B16A16_SSCALED = 94, + VK_FORMAT_R16G16B16A16_UINT = 95, + VK_FORMAT_R16G16B16A16_SINT = 96, + VK_FORMAT_R16G16B16A16_SFLOAT = 97, + VK_FORMAT_R32_UINT = 98, + VK_FORMAT_R32_SINT = 99, + VK_FORMAT_R32_SFLOAT = 100, + VK_FORMAT_R32G32_UINT = 101, + VK_FORMAT_R32G32_SINT = 102, + VK_FORMAT_R32G32_SFLOAT = 103, + VK_FORMAT_R32G32B32_UINT = 104, + VK_FORMAT_R32G32B32_SINT = 105, + VK_FORMAT_R32G32B32_SFLOAT = 106, + VK_FORMAT_R32G32B32A32_UINT = 107, + VK_FORMAT_R32G32B32A32_SINT = 108, + VK_FORMAT_R32G32B32A32_SFLOAT = 109, + VK_FORMAT_R64_UINT = 110, + VK_FORMAT_R64_SINT = 111, + VK_FORMAT_R64_SFLOAT = 112, + VK_FORMAT_R64G64_UINT = 113, + VK_FORMAT_R64G64_SINT = 114, + VK_FORMAT_R64G64_SFLOAT = 115, + VK_FORMAT_R64G64B64_UINT = 116, + VK_FORMAT_R64G64B64_SINT = 117, + VK_FORMAT_R64G64B64_SFLOAT = 118, + VK_FORMAT_R64G64B64A64_UINT = 119, + VK_FORMAT_R64G64B64A64_SINT = 120, + VK_FORMAT_R64G64B64A64_SFLOAT = 121, + VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, + VK_FORMAT_D16_UNORM = 124, + VK_FORMAT_X8_D24_UNORM_PACK32 = 125, + VK_FORMAT_D32_SFLOAT = 126, + VK_FORMAT_S8_UINT = 127, + VK_FORMAT_D16_UNORM_S8_UINT = 128, + VK_FORMAT_D24_UNORM_S8_UINT = 129, + VK_FORMAT_D32_SFLOAT_S8_UINT = 130, + VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, + VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, + VK_FORMAT_BC2_UNORM_BLOCK = 135, + VK_FORMAT_BC2_SRGB_BLOCK = 136, + VK_FORMAT_BC3_UNORM_BLOCK = 137, + VK_FORMAT_BC3_SRGB_BLOCK = 138, + VK_FORMAT_BC4_UNORM_BLOCK = 139, + VK_FORMAT_BC4_SNORM_BLOCK = 140, + VK_FORMAT_BC5_UNORM_BLOCK = 141, + VK_FORMAT_BC5_SNORM_BLOCK = 142, + VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, + VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, + VK_FORMAT_BC7_UNORM_BLOCK = 145, + VK_FORMAT_BC7_SRGB_BLOCK = 146, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, + VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, + VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, + VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, + VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, + VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, + VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, + VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003, + VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013, + VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, + VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, + VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, + VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, + VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, + VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, + VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, + VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, + VK_FORMAT_R16G16_S10_5_NV = 1000464000, + VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = 1000470000, + VK_FORMAT_A8_UNORM_KHR = 1000470001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK, + VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, + VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, + VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM, + VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, + VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = VK_FORMAT_A4R4G4B4_UNORM_PACK16, + VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = VK_FORMAT_A4B4G4R4_UNORM_PACK16, + VK_FORMAT_MAX_ENUM = 0x7FFFFFFF +} VkFormat; + +typedef enum VkImageTiling { + VK_IMAGE_TILING_OPTIMAL = 0, + VK_IMAGE_TILING_LINEAR = 1, + VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, + VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF +} VkImageTiling; + +typedef enum VkImageType { + VK_IMAGE_TYPE_1D = 0, + VK_IMAGE_TYPE_2D = 1, + VK_IMAGE_TYPE_3D = 2, + VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageType; + +typedef enum VkPhysicalDeviceType { + VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, + VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, + VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, + VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, + VK_PHYSICAL_DEVICE_TYPE_CPU = 4, + VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkPhysicalDeviceType; + +typedef enum VkQueryType { + VK_QUERY_TYPE_OCCLUSION = 0, + VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, + VK_QUERY_TYPE_TIMESTAMP = 2, + VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR = 1000023000, + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, + VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR = 1000116000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000150000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150001, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, + VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR = 1000299000, +#endif + VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT = 1000328000, + VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT = 1000382000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR = 1000386000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR = 1000386001, + VK_QUERY_TYPE_MICROMAP_SERIALIZATION_SIZE_EXT = 1000396000, + VK_QUERY_TYPE_MICROMAP_COMPACTED_SIZE_EXT = 1000396001, + VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkQueryType; + +typedef enum VkSharingMode { + VK_SHARING_MODE_EXCLUSIVE = 0, + VK_SHARING_MODE_CONCURRENT = 1, + VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSharingMode; + +typedef enum VkComponentSwizzle { + VK_COMPONENT_SWIZZLE_IDENTITY = 0, + VK_COMPONENT_SWIZZLE_ZERO = 1, + VK_COMPONENT_SWIZZLE_ONE = 2, + VK_COMPONENT_SWIZZLE_R = 3, + VK_COMPONENT_SWIZZLE_G = 4, + VK_COMPONENT_SWIZZLE_B = 5, + VK_COMPONENT_SWIZZLE_A = 6, + VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF +} VkComponentSwizzle; + +typedef enum VkImageViewType { + VK_IMAGE_VIEW_TYPE_1D = 0, + VK_IMAGE_VIEW_TYPE_2D = 1, + VK_IMAGE_VIEW_TYPE_3D = 2, + VK_IMAGE_VIEW_TYPE_CUBE = 3, + VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, + VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, + VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageViewType; + +typedef enum VkBlendFactor { + VK_BLEND_FACTOR_ZERO = 0, + VK_BLEND_FACTOR_ONE = 1, + VK_BLEND_FACTOR_SRC_COLOR = 2, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, + VK_BLEND_FACTOR_DST_COLOR = 4, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, + VK_BLEND_FACTOR_SRC_ALPHA = 6, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, + VK_BLEND_FACTOR_DST_ALPHA = 8, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, + VK_BLEND_FACTOR_CONSTANT_COLOR = 10, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, + VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, + VK_BLEND_FACTOR_SRC1_COLOR = 15, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, + VK_BLEND_FACTOR_SRC1_ALPHA = 17, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, + VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF +} VkBlendFactor; + +typedef enum VkBlendOp { + VK_BLEND_OP_ADD = 0, + VK_BLEND_OP_SUBTRACT = 1, + VK_BLEND_OP_REVERSE_SUBTRACT = 2, + VK_BLEND_OP_MIN = 3, + VK_BLEND_OP_MAX = 4, + VK_BLEND_OP_ZERO_EXT = 1000148000, + VK_BLEND_OP_SRC_EXT = 1000148001, + VK_BLEND_OP_DST_EXT = 1000148002, + VK_BLEND_OP_SRC_OVER_EXT = 1000148003, + VK_BLEND_OP_DST_OVER_EXT = 1000148004, + VK_BLEND_OP_SRC_IN_EXT = 1000148005, + VK_BLEND_OP_DST_IN_EXT = 1000148006, + VK_BLEND_OP_SRC_OUT_EXT = 1000148007, + VK_BLEND_OP_DST_OUT_EXT = 1000148008, + VK_BLEND_OP_SRC_ATOP_EXT = 1000148009, + VK_BLEND_OP_DST_ATOP_EXT = 1000148010, + VK_BLEND_OP_XOR_EXT = 1000148011, + VK_BLEND_OP_MULTIPLY_EXT = 1000148012, + VK_BLEND_OP_SCREEN_EXT = 1000148013, + VK_BLEND_OP_OVERLAY_EXT = 1000148014, + VK_BLEND_OP_DARKEN_EXT = 1000148015, + VK_BLEND_OP_LIGHTEN_EXT = 1000148016, + VK_BLEND_OP_COLORDODGE_EXT = 1000148017, + VK_BLEND_OP_COLORBURN_EXT = 1000148018, + VK_BLEND_OP_HARDLIGHT_EXT = 1000148019, + VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020, + VK_BLEND_OP_DIFFERENCE_EXT = 1000148021, + VK_BLEND_OP_EXCLUSION_EXT = 1000148022, + VK_BLEND_OP_INVERT_EXT = 1000148023, + VK_BLEND_OP_INVERT_RGB_EXT = 1000148024, + VK_BLEND_OP_LINEARDODGE_EXT = 1000148025, + VK_BLEND_OP_LINEARBURN_EXT = 1000148026, + VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027, + VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028, + VK_BLEND_OP_PINLIGHT_EXT = 1000148029, + VK_BLEND_OP_HARDMIX_EXT = 1000148030, + VK_BLEND_OP_HSL_HUE_EXT = 1000148031, + VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032, + VK_BLEND_OP_HSL_COLOR_EXT = 1000148033, + VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034, + VK_BLEND_OP_PLUS_EXT = 1000148035, + VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036, + VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037, + VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038, + VK_BLEND_OP_MINUS_EXT = 1000148039, + VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040, + VK_BLEND_OP_CONTRAST_EXT = 1000148041, + VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, + VK_BLEND_OP_RED_EXT = 1000148043, + VK_BLEND_OP_GREEN_EXT = 1000148044, + VK_BLEND_OP_BLUE_EXT = 1000148045, + VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF +} VkBlendOp; + +typedef enum VkCompareOp { + VK_COMPARE_OP_NEVER = 0, + VK_COMPARE_OP_LESS = 1, + VK_COMPARE_OP_EQUAL = 2, + VK_COMPARE_OP_LESS_OR_EQUAL = 3, + VK_COMPARE_OP_GREATER = 4, + VK_COMPARE_OP_NOT_EQUAL = 5, + VK_COMPARE_OP_GREATER_OR_EQUAL = 6, + VK_COMPARE_OP_ALWAYS = 7, + VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF +} VkCompareOp; + +typedef enum VkDynamicState { + VK_DYNAMIC_STATE_VIEWPORT = 0, + VK_DYNAMIC_STATE_SCISSOR = 1, + VK_DYNAMIC_STATE_LINE_WIDTH = 2, + VK_DYNAMIC_STATE_DEPTH_BIAS = 3, + VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, + VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, + VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_CULL_MODE = 1000267000, + VK_DYNAMIC_STATE_FRONT_FACE = 1000267001, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY = 1000267002, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT = 1000267003, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT = 1000267004, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE = 1000267005, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE = 1000267006, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE = 1000267007, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP = 1000267008, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE = 1000267009, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE = 1000267010, + VK_DYNAMIC_STATE_STENCIL_OP = 1000267011, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE = 1000377001, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE = 1000377002, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE = 1000377004, + VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_ENABLE_EXT = 1000099001, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_MODE_EXT = 1000099002, + VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, + VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR = 1000347000, + VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, + VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, + VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_ENABLE_NV = 1000205000, + VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, + VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR = 1000226000, + VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = 1000259000, + VK_DYNAMIC_STATE_VERTEX_INPUT_EXT = 1000352000, + VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT = 1000377000, + VK_DYNAMIC_STATE_LOGIC_OP_EXT = 1000377003, + VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT = 1000381000, + VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT = 1000455002, + VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT = 1000455003, + VK_DYNAMIC_STATE_POLYGON_MODE_EXT = 1000455004, + VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT = 1000455005, + VK_DYNAMIC_STATE_SAMPLE_MASK_EXT = 1000455006, + VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT = 1000455007, + VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT = 1000455008, + VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT = 1000455009, + VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT = 1000455010, + VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT = 1000455011, + VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT = 1000455012, + VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT = 1000455013, + VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT = 1000455014, + VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT = 1000455015, + VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT = 1000455016, + VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT = 1000455017, + VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT = 1000455018, + VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT = 1000455019, + VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT = 1000455020, + VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT = 1000455021, + VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT = 1000455022, + VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV = 1000455023, + VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV = 1000455024, + VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV = 1000455025, + VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV = 1000455026, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV = 1000455027, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV = 1000455028, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV = 1000455029, + VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV = 1000455030, + VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV = 1000455031, + VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV = 1000455032, + VK_DYNAMIC_STATE_ATTACHMENT_FEEDBACK_LOOP_ENABLE_EXT = 1000524000, + VK_DYNAMIC_STATE_CULL_MODE_EXT = VK_DYNAMIC_STATE_CULL_MODE, + VK_DYNAMIC_STATE_FRONT_FACE_EXT = VK_DYNAMIC_STATE_FRONT_FACE, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = VK_DYNAMIC_STATE_DEPTH_COMPARE_OP, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_OP_EXT = VK_DYNAMIC_STATE_STENCIL_OP, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT = VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT = VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE, + VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF +} VkDynamicState; + +typedef enum VkFrontFace { + VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, + VK_FRONT_FACE_CLOCKWISE = 1, + VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF +} VkFrontFace; + +typedef enum VkVertexInputRate { + VK_VERTEX_INPUT_RATE_VERTEX = 0, + VK_VERTEX_INPUT_RATE_INSTANCE = 1, + VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF +} VkVertexInputRate; + +typedef enum VkPrimitiveTopology { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, + VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF +} VkPrimitiveTopology; + +typedef enum VkPolygonMode { + VK_POLYGON_MODE_FILL = 0, + VK_POLYGON_MODE_LINE = 1, + VK_POLYGON_MODE_POINT = 2, + VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, + VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF +} VkPolygonMode; + +typedef enum VkStencilOp { + VK_STENCIL_OP_KEEP = 0, + VK_STENCIL_OP_ZERO = 1, + VK_STENCIL_OP_REPLACE = 2, + VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, + VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, + VK_STENCIL_OP_INVERT = 5, + VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, + VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, + VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF +} VkStencilOp; + +typedef enum VkLogicOp { + VK_LOGIC_OP_CLEAR = 0, + VK_LOGIC_OP_AND = 1, + VK_LOGIC_OP_AND_REVERSE = 2, + VK_LOGIC_OP_COPY = 3, + VK_LOGIC_OP_AND_INVERTED = 4, + VK_LOGIC_OP_NO_OP = 5, + VK_LOGIC_OP_XOR = 6, + VK_LOGIC_OP_OR = 7, + VK_LOGIC_OP_NOR = 8, + VK_LOGIC_OP_EQUIVALENT = 9, + VK_LOGIC_OP_INVERT = 10, + VK_LOGIC_OP_OR_REVERSE = 11, + VK_LOGIC_OP_COPY_INVERTED = 12, + VK_LOGIC_OP_OR_INVERTED = 13, + VK_LOGIC_OP_NAND = 14, + VK_LOGIC_OP_SET = 15, + VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF +} VkLogicOp; + +typedef enum VkBorderColor { + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, + VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, + VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, + VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, + VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, + VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, + VK_BORDER_COLOR_FLOAT_CUSTOM_EXT = 1000287003, + VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004, + VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF +} VkBorderColor; + +typedef enum VkFilter { + VK_FILTER_NEAREST = 0, + VK_FILTER_LINEAR = 1, + VK_FILTER_CUBIC_EXT = 1000015000, + VK_FILTER_CUBIC_IMG = VK_FILTER_CUBIC_EXT, + VK_FILTER_MAX_ENUM = 0x7FFFFFFF +} VkFilter; + +typedef enum VkSamplerAddressMode { + VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, + VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerAddressMode; + +typedef enum VkSamplerMipmapMode { + VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, + VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, + VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerMipmapMode; + +typedef enum VkDescriptorType { + VK_DESCRIPTOR_TYPE_SAMPLER = 0, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, + VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, + VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, + VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM = 1000440000, + VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM = 1000440001, + VK_DESCRIPTOR_TYPE_MUTABLE_EXT = 1000351000, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, + VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = VK_DESCRIPTOR_TYPE_MUTABLE_EXT, + VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorType; + +typedef enum VkAttachmentLoadOp { + VK_ATTACHMENT_LOAD_OP_LOAD = 0, + VK_ATTACHMENT_LOAD_OP_CLEAR = 1, + VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, + VK_ATTACHMENT_LOAD_OP_NONE_EXT = 1000400000, + VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentLoadOp; + +typedef enum VkAttachmentStoreOp { + VK_ATTACHMENT_STORE_OP_STORE = 0, + VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, + VK_ATTACHMENT_STORE_OP_NONE = 1000301000, + VK_ATTACHMENT_STORE_OP_NONE_KHR = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_QCOM = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_EXT = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentStoreOp; + +typedef enum VkPipelineBindPoint { + VK_PIPELINE_BIND_POINT_GRAPHICS = 0, + VK_PIPELINE_BIND_POINT_COMPUTE = 1, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_PIPELINE_BIND_POINT_EXECUTION_GRAPH_AMDX = 1000134000, +#endif + VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR = 1000165000, + VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI = 1000369003, + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, + VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF +} VkPipelineBindPoint; + +typedef enum VkCommandBufferLevel { + VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, + VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, + VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferLevel; + +typedef enum VkIndexType { + VK_INDEX_TYPE_UINT16 = 0, + VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_NONE_KHR = 1000165000, + VK_INDEX_TYPE_UINT8_EXT = 1000265000, + VK_INDEX_TYPE_NONE_NV = VK_INDEX_TYPE_NONE_KHR, + VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkIndexType; + +typedef enum VkSubpassContents { + VK_SUBPASS_CONTENTS_INLINE = 0, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, + VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_EXT = 1000451000, + VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF +} VkSubpassContents; + +typedef enum VkAccessFlagBits { + VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, + VK_ACCESS_INDEX_READ_BIT = 0x00000002, + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, + VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, + VK_ACCESS_SHADER_READ_BIT = 0x00000020, + VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, + VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, + VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, + VK_ACCESS_HOST_READ_BIT = 0x00002000, + VK_ACCESS_HOST_WRITE_BIT = 0x00004000, + VK_ACCESS_MEMORY_READ_BIT = 0x00008000, + VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_NONE = 0, + VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, + VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, + VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000, + VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000, + VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000, + VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000, + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000, + VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, + VK_ACCESS_NONE_KHR = VK_ACCESS_NONE, + VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAccessFlagBits; +typedef VkFlags VkAccessFlags; + +typedef enum VkImageAspectFlagBits { + VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, + VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, + VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, + VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, + VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, + VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, + VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, + VK_IMAGE_ASPECT_NONE = 0, + VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, + VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, + VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400, + VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, + VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, + VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, + VK_IMAGE_ASPECT_NONE_KHR = VK_IMAGE_ASPECT_NONE, + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageAspectFlagBits; +typedef VkFlags VkImageAspectFlags; + +typedef enum VkFormatFeatureFlagBits { + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, + VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, + VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, + VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, + VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, + VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, + VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, + VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000, + VK_FORMAT_FEATURE_VIDEO_DECODE_OUTPUT_BIT_KHR = 0x02000000, + VK_FORMAT_FEATURE_VIDEO_DECODE_DPB_BIT_KHR = 0x04000000, + VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000, + VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000, + VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_FORMAT_FEATURE_VIDEO_ENCODE_INPUT_BIT_KHR = 0x08000000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_FORMAT_FEATURE_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000, +#endif + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, + VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, + VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFormatFeatureFlagBits; +typedef VkFlags VkFormatFeatureFlags; + +typedef enum VkImageCreateFlagBits { + VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, + VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, + VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, + VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, + VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, + VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, + VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000, + VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, + VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000, + VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00010000, + VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 0x00040000, + VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT = 0x00020000, + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM = 0x00008000, + VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, + VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT, + VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT, + VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageCreateFlagBits; +typedef VkFlags VkImageCreateFlags; + +typedef enum VkSampleCountFlagBits { + VK_SAMPLE_COUNT_1_BIT = 0x00000001, + VK_SAMPLE_COUNT_2_BIT = 0x00000002, + VK_SAMPLE_COUNT_4_BIT = 0x00000004, + VK_SAMPLE_COUNT_8_BIT = 0x00000008, + VK_SAMPLE_COUNT_16_BIT = 0x00000010, + VK_SAMPLE_COUNT_32_BIT = 0x00000020, + VK_SAMPLE_COUNT_64_BIT = 0x00000040, + VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSampleCountFlagBits; +typedef VkFlags VkSampleCountFlags; + +typedef enum VkImageUsageFlagBits { + VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, + VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, + VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR = 0x00000400, + VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR = 0x00000800, + VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR = 0x00001000, + VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200, + VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00000100, + VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT = 0x00400000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00002000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00004000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR = 0x00008000, +#endif + VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x00080000, + VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI = 0x00040000, + VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM = 0x00100000, + VK_IMAGE_USAGE_SAMPLE_BLOCK_MATCH_BIT_QCOM = 0x00200000, + VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, + VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageUsageFlagBits; +typedef VkFlags VkImageUsageFlags; + +typedef enum VkInstanceCreateFlagBits { + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; +typedef VkFlags VkInstanceCreateFlags; + +typedef enum VkMemoryHeapFlagBits { + VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, + VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryHeapFlagBits; +typedef VkFlags VkMemoryHeapFlags; + +typedef enum VkMemoryPropertyFlagBits { + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, + VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, + VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD = 0x00000040, + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 0x00000080, + VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV = 0x00000100, + VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryPropertyFlagBits; +typedef VkFlags VkMemoryPropertyFlags; + +typedef enum VkQueueFlagBits { + VK_QUEUE_GRAPHICS_BIT = 0x00000001, + VK_QUEUE_COMPUTE_BIT = 0x00000002, + VK_QUEUE_TRANSFER_BIT = 0x00000004, + VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, + VK_QUEUE_PROTECTED_BIT = 0x00000010, + VK_QUEUE_VIDEO_DECODE_BIT_KHR = 0x00000020, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_QUEUE_VIDEO_ENCODE_BIT_KHR = 0x00000040, +#endif + VK_QUEUE_OPTICAL_FLOW_BIT_NV = 0x00000100, + VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueueFlagBits; +typedef VkFlags VkQueueFlags; +typedef VkFlags VkDeviceCreateFlags; + +typedef enum VkDeviceQueueCreateFlagBits { + VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, + VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDeviceQueueCreateFlagBits; +typedef VkFlags VkDeviceQueueCreateFlags; + +typedef enum VkPipelineStageFlagBits { + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, + VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, + VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, + VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, + VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_NONE = 0, + VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, + VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 0x00200000, + VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, + VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 0x00020000, + VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT = 0x00080000, + VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT = 0x00100000, + VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT, + VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT, + VK_PIPELINE_STAGE_NONE_KHR = VK_PIPELINE_STAGE_NONE, + VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineStageFlagBits; +typedef VkFlags VkPipelineStageFlags; +typedef VkFlags VkMemoryMapFlags; + +typedef enum VkSparseMemoryBindFlagBits { + VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, + VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseMemoryBindFlagBits; +typedef VkFlags VkSparseMemoryBindFlags; + +typedef enum VkSparseImageFormatFlagBits { + VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, + VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, + VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, + VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseImageFormatFlagBits; +typedef VkFlags VkSparseImageFormatFlags; + +typedef enum VkFenceCreateFlagBits { + VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, + VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceCreateFlagBits; +typedef VkFlags VkFenceCreateFlags; +typedef VkFlags VkSemaphoreCreateFlags; + +typedef enum VkEventCreateFlagBits { + VK_EVENT_CREATE_DEVICE_ONLY_BIT = 0x00000001, + VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR = VK_EVENT_CREATE_DEVICE_ONLY_BIT, + VK_EVENT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkEventCreateFlagBits; +typedef VkFlags VkEventCreateFlags; + +typedef enum VkQueryPipelineStatisticFlagBits { + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, + VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT = 0x00000800, + VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT = 0x00001000, + VK_QUERY_PIPELINE_STATISTIC_CLUSTER_CULLING_SHADER_INVOCATIONS_BIT_HUAWEI = 0x00002000, + VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryPipelineStatisticFlagBits; +typedef VkFlags VkQueryPipelineStatisticFlags; +typedef VkFlags VkQueryPoolCreateFlags; + +typedef enum VkQueryResultFlagBits { + VK_QUERY_RESULT_64_BIT = 0x00000001, + VK_QUERY_RESULT_WAIT_BIT = 0x00000002, + VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, + VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, + VK_QUERY_RESULT_WITH_STATUS_BIT_KHR = 0x00000010, + VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryResultFlagBits; +typedef VkFlags VkQueryResultFlags; + +typedef enum VkBufferCreateFlagBits { + VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000010, + VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000020, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferCreateFlagBits; +typedef VkFlags VkBufferCreateFlags; + +typedef enum VkBufferUsageFlagBits { + VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT = 0x00020000, + VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR = 0x00002000, + VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR = 0x00004000, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, + VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUFFER_USAGE_EXECUTION_GRAPH_SCRATCH_BIT_AMDX = 0x02000000, +#endif + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 0x00080000, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 0x00100000, + VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00008000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00010000, +#endif + VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 0x00200000, + VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00400000, + VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 0x04000000, + VK_BUFFER_USAGE_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 0x00800000, + VK_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT = 0x01000000, + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferUsageFlagBits; +typedef VkFlags VkBufferUsageFlags; +typedef VkFlags VkBufferViewCreateFlags; + +typedef enum VkImageViewCreateFlagBits { + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 0x00000001, + VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000004, + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT = 0x00000002, + VK_IMAGE_VIEW_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageViewCreateFlagBits; +typedef VkFlags VkImageViewCreateFlags; +typedef VkFlags VkShaderModuleCreateFlags; + +typedef enum VkPipelineCacheCreateFlagBits { + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, + VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheCreateFlagBits; +typedef VkFlags VkPipelineCacheCreateFlags; + +typedef enum VkColorComponentFlagBits { + VK_COLOR_COMPONENT_R_BIT = 0x00000001, + VK_COLOR_COMPONENT_G_BIT = 0x00000002, + VK_COLOR_COMPONENT_B_BIT = 0x00000004, + VK_COLOR_COMPONENT_A_BIT = 0x00000008, + VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkColorComponentFlagBits; +typedef VkFlags VkColorComponentFlags; + +typedef enum VkPipelineCreateFlagBits { + VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, + VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, + VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, + VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 0x00000010, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 0x00000100, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT = 0x00000200, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00200000, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 0x00400000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 0x00004000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 0x00008000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 0x00010000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 0x00020000, + VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 0x00001000, + VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR = 0x00002000, + VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 0x00080000, + VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, + VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR = 0x00000040, + VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080, + VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00040000, + VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 0x00000800, + VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 0x20000000, + VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 0x00800000, + VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT = 0x00000400, + VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV = 0x00100000, + VK_PIPELINE_CREATE_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x02000000, + VK_PIPELINE_CREATE_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x04000000, + VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 0x01000000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_PIPELINE_CREATE_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 0x10000000, +#endif + VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT = 0x08000000, + VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT = 0x40000000, + VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT, + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, + VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT, + VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreateFlagBits; +typedef VkFlags VkPipelineCreateFlags; + +typedef enum VkPipelineShaderStageCreateFlagBits { + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT = 0x00000001, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT = 0x00000002, + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineShaderStageCreateFlagBits; +typedef VkFlags VkPipelineShaderStageCreateFlags; + +typedef enum VkShaderStageFlagBits { + VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, + VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, + VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, + VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, + VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, + VK_SHADER_STAGE_ALL = 0x7FFFFFFF, + VK_SHADER_STAGE_RAYGEN_BIT_KHR = 0x00000100, + VK_SHADER_STAGE_ANY_HIT_BIT_KHR = 0x00000200, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR = 0x00000400, + VK_SHADER_STAGE_MISS_BIT_KHR = 0x00000800, + VK_SHADER_STAGE_INTERSECTION_BIT_KHR = 0x00001000, + VK_SHADER_STAGE_CALLABLE_BIT_KHR = 0x00002000, + VK_SHADER_STAGE_TASK_BIT_EXT = 0x00000040, + VK_SHADER_STAGE_MESH_BIT_EXT = 0x00000080, + VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI = 0x00004000, + VK_SHADER_STAGE_CLUSTER_CULLING_BIT_HUAWEI = 0x00080000, + VK_SHADER_STAGE_RAYGEN_BIT_NV = VK_SHADER_STAGE_RAYGEN_BIT_KHR, + VK_SHADER_STAGE_ANY_HIT_BIT_NV = VK_SHADER_STAGE_ANY_HIT_BIT_KHR, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, + VK_SHADER_STAGE_MISS_BIT_NV = VK_SHADER_STAGE_MISS_BIT_KHR, + VK_SHADER_STAGE_INTERSECTION_BIT_NV = VK_SHADER_STAGE_INTERSECTION_BIT_KHR, + VK_SHADER_STAGE_CALLABLE_BIT_NV = VK_SHADER_STAGE_CALLABLE_BIT_KHR, + VK_SHADER_STAGE_TASK_BIT_NV = VK_SHADER_STAGE_TASK_BIT_EXT, + VK_SHADER_STAGE_MESH_BIT_NV = VK_SHADER_STAGE_MESH_BIT_EXT, + VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkShaderStageFlagBits; + +typedef enum VkCullModeFlagBits { + VK_CULL_MODE_NONE = 0, + VK_CULL_MODE_FRONT_BIT = 0x00000001, + VK_CULL_MODE_BACK_BIT = 0x00000002, + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, + VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCullModeFlagBits; +typedef VkFlags VkCullModeFlags; +typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef VkFlags VkPipelineRasterizationStateCreateFlags; +typedef VkFlags VkPipelineMultisampleStateCreateFlags; + +typedef enum VkPipelineDepthStencilStateCreateFlagBits { + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 0x00000001, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 0x00000002, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineDepthStencilStateCreateFlagBits; +typedef VkFlags VkPipelineDepthStencilStateCreateFlags; + +typedef enum VkPipelineColorBlendStateCreateFlagBits { + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT = 0x00000001, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineColorBlendStateCreateFlagBits; +typedef VkFlags VkPipelineColorBlendStateCreateFlags; +typedef VkFlags VkPipelineDynamicStateCreateFlags; + +typedef enum VkPipelineLayoutCreateFlagBits { + VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT = 0x00000002, + VK_PIPELINE_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineLayoutCreateFlagBits; +typedef VkFlags VkPipelineLayoutCreateFlags; +typedef VkFlags VkShaderStageFlags; + +typedef enum VkSamplerCreateFlagBits { + VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001, + VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002, + VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000008, + VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT = 0x00000004, + VK_SAMPLER_CREATE_IMAGE_PROCESSING_BIT_QCOM = 0x00000010, + VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSamplerCreateFlagBits; +typedef VkFlags VkSamplerCreateFlags; + +typedef enum VkDescriptorPoolCreateFlagBits { + VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 0x00000002, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT = 0x00000004, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV = 0x00000008, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV = 0x00000010, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT, + VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorPoolCreateFlagBits; +typedef VkFlags VkDescriptorPoolCreateFlags; +typedef VkFlags VkDescriptorPoolResetFlags; + +typedef enum VkDescriptorSetLayoutCreateFlagBits { + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 0x00000002, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00000010, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT = 0x00000020, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00000080, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT = 0x00000004, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorSetLayoutCreateFlagBits; +typedef VkFlags VkDescriptorSetLayoutCreateFlags; + +typedef enum VkAttachmentDescriptionFlagBits { + VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, + VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentDescriptionFlagBits; +typedef VkFlags VkAttachmentDescriptionFlags; + +typedef enum VkDependencyFlagBits { + VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, + VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, + VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, + VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT = 0x00000008, + VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT, + VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT, + VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDependencyFlagBits; +typedef VkFlags VkDependencyFlags; + +typedef enum VkFramebufferCreateFlagBits { + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT = 0x00000001, + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, + VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFramebufferCreateFlagBits; +typedef VkFlags VkFramebufferCreateFlags; + +typedef enum VkRenderPassCreateFlagBits { + VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 0x00000002, + VK_RENDER_PASS_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkRenderPassCreateFlagBits; +typedef VkFlags VkRenderPassCreateFlags; + +typedef enum VkSubpassDescriptionFlagBits { + VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001, + VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002, + VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = 0x00000004, + VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 0x00000008, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT = 0x00000010, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 0x00000020, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 0x00000040, + VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000080, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT, + VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubpassDescriptionFlagBits; +typedef VkFlags VkSubpassDescriptionFlags; + +typedef enum VkCommandPoolCreateFlagBits { + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, + VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, + VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolCreateFlagBits; +typedef VkFlags VkCommandPoolCreateFlags; + +typedef enum VkCommandPoolResetFlagBits { + VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolResetFlagBits; +typedef VkFlags VkCommandPoolResetFlags; + +typedef enum VkCommandBufferUsageFlagBits { + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, + VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, + VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferUsageFlagBits; +typedef VkFlags VkCommandBufferUsageFlags; + +typedef enum VkQueryControlFlagBits { + VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, + VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryControlFlagBits; +typedef VkFlags VkQueryControlFlags; + +typedef enum VkCommandBufferResetFlagBits { + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferResetFlagBits; +typedef VkFlags VkCommandBufferResetFlags; + +typedef enum VkStencilFaceFlagBits { + VK_STENCIL_FACE_FRONT_BIT = 0x00000001, + VK_STENCIL_FACE_BACK_BIT = 0x00000002, + VK_STENCIL_FACE_FRONT_AND_BACK = 0x00000003, + VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK, + VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkStencilFaceFlagBits; +typedef VkFlags VkStencilFaceFlags; +typedef struct VkExtent2D { + uint32_t width; + uint32_t height; +} VkExtent2D; + +typedef struct VkExtent3D { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkExtent3D; + +typedef struct VkOffset2D { + int32_t x; + int32_t y; +} VkOffset2D; + +typedef struct VkOffset3D { + int32_t x; + int32_t y; + int32_t z; +} VkOffset3D; + +typedef struct VkRect2D { + VkOffset2D offset; + VkExtent2D extent; +} VkRect2D; + +typedef struct VkBaseInStructure { + VkStructureType sType; + const struct VkBaseInStructure* pNext; +} VkBaseInStructure; + +typedef struct VkBaseOutStructure { + VkStructureType sType; + struct VkBaseOutStructure* pNext; +} VkBaseOutStructure; + +typedef struct VkBufferMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier; + +typedef struct VkDispatchIndirectCommand { + uint32_t x; + uint32_t y; + uint32_t z; +} VkDispatchIndirectCommand; + +typedef struct VkDrawIndexedIndirectCommand { + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; +} VkDrawIndexedIndirectCommand; + +typedef struct VkDrawIndirectCommand { + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t firstVertex; + uint32_t firstInstance; +} VkDrawIndirectCommand; + +typedef struct VkImageSubresourceRange { + VkImageAspectFlags aspectMask; + uint32_t baseMipLevel; + uint32_t levelCount; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceRange; + +typedef struct VkImageMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier; + +typedef struct VkMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; +} VkMemoryBarrier; + +typedef struct VkPipelineCacheHeaderVersionOne { + uint32_t headerSize; + VkPipelineCacheHeaderVersion headerVersion; + uint32_t vendorID; + uint32_t deviceID; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; +} VkPipelineCacheHeaderVersionOne; + +typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkFreeFunction)( + void* pUserData, + void* pMemory); + +typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); +typedef struct VkAllocationCallbacks { + void* pUserData; + PFN_vkAllocationFunction pfnAllocation; + PFN_vkReallocationFunction pfnReallocation; + PFN_vkFreeFunction pfnFree; + PFN_vkInternalAllocationNotification pfnInternalAllocation; + PFN_vkInternalFreeNotification pfnInternalFree; +} VkAllocationCallbacks; + +typedef struct VkApplicationInfo { + VkStructureType sType; + const void* pNext; + const char* pApplicationName; + uint32_t applicationVersion; + const char* pEngineName; + uint32_t engineVersion; + uint32_t apiVersion; +} VkApplicationInfo; + +typedef struct VkFormatProperties { + VkFormatFeatureFlags linearTilingFeatures; + VkFormatFeatureFlags optimalTilingFeatures; + VkFormatFeatureFlags bufferFeatures; +} VkFormatProperties; + +typedef struct VkImageFormatProperties { + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArrayLayers; + VkSampleCountFlags sampleCounts; + VkDeviceSize maxResourceSize; +} VkImageFormatProperties; + +typedef struct VkInstanceCreateInfo { + VkStructureType sType; + const void* pNext; + VkInstanceCreateFlags flags; + const VkApplicationInfo* pApplicationInfo; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; +} VkInstanceCreateInfo; + +typedef struct VkMemoryHeap { + VkDeviceSize size; + VkMemoryHeapFlags flags; +} VkMemoryHeap; + +typedef struct VkMemoryType { + VkMemoryPropertyFlags propertyFlags; + uint32_t heapIndex; +} VkMemoryType; + +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; + +typedef struct VkPhysicalDeviceLimits { + uint32_t maxImageDimension1D; + uint32_t maxImageDimension2D; + uint32_t maxImageDimension3D; + uint32_t maxImageDimensionCube; + uint32_t maxImageArrayLayers; + uint32_t maxTexelBufferElements; + uint32_t maxUniformBufferRange; + uint32_t maxStorageBufferRange; + uint32_t maxPushConstantsSize; + uint32_t maxMemoryAllocationCount; + uint32_t maxSamplerAllocationCount; + VkDeviceSize bufferImageGranularity; + VkDeviceSize sparseAddressSpaceSize; + uint32_t maxBoundDescriptorSets; + uint32_t maxPerStageDescriptorSamplers; + uint32_t maxPerStageDescriptorUniformBuffers; + uint32_t maxPerStageDescriptorStorageBuffers; + uint32_t maxPerStageDescriptorSampledImages; + uint32_t maxPerStageDescriptorStorageImages; + uint32_t maxPerStageDescriptorInputAttachments; + uint32_t maxPerStageResources; + uint32_t maxDescriptorSetSamplers; + uint32_t maxDescriptorSetUniformBuffers; + uint32_t maxDescriptorSetUniformBuffersDynamic; + uint32_t maxDescriptorSetStorageBuffers; + uint32_t maxDescriptorSetStorageBuffersDynamic; + uint32_t maxDescriptorSetSampledImages; + uint32_t maxDescriptorSetStorageImages; + uint32_t maxDescriptorSetInputAttachments; + uint32_t maxVertexInputAttributes; + uint32_t maxVertexInputBindings; + uint32_t maxVertexInputAttributeOffset; + uint32_t maxVertexInputBindingStride; + uint32_t maxVertexOutputComponents; + uint32_t maxTessellationGenerationLevel; + uint32_t maxTessellationPatchSize; + uint32_t maxTessellationControlPerVertexInputComponents; + uint32_t maxTessellationControlPerVertexOutputComponents; + uint32_t maxTessellationControlPerPatchOutputComponents; + uint32_t maxTessellationControlTotalOutputComponents; + uint32_t maxTessellationEvaluationInputComponents; + uint32_t maxTessellationEvaluationOutputComponents; + uint32_t maxGeometryShaderInvocations; + uint32_t maxGeometryInputComponents; + uint32_t maxGeometryOutputComponents; + uint32_t maxGeometryOutputVertices; + uint32_t maxGeometryTotalOutputComponents; + uint32_t maxFragmentInputComponents; + uint32_t maxFragmentOutputAttachments; + uint32_t maxFragmentDualSrcAttachments; + uint32_t maxFragmentCombinedOutputResources; + uint32_t maxComputeSharedMemorySize; + uint32_t maxComputeWorkGroupCount[3]; + uint32_t maxComputeWorkGroupInvocations; + uint32_t maxComputeWorkGroupSize[3]; + uint32_t subPixelPrecisionBits; + uint32_t subTexelPrecisionBits; + uint32_t mipmapPrecisionBits; + uint32_t maxDrawIndexedIndexValue; + uint32_t maxDrawIndirectCount; + float maxSamplerLodBias; + float maxSamplerAnisotropy; + uint32_t maxViewports; + uint32_t maxViewportDimensions[2]; + float viewportBoundsRange[2]; + uint32_t viewportSubPixelBits; + size_t minMemoryMapAlignment; + VkDeviceSize minTexelBufferOffsetAlignment; + VkDeviceSize minUniformBufferOffsetAlignment; + VkDeviceSize minStorageBufferOffsetAlignment; + int32_t minTexelOffset; + uint32_t maxTexelOffset; + int32_t minTexelGatherOffset; + uint32_t maxTexelGatherOffset; + float minInterpolationOffset; + float maxInterpolationOffset; + uint32_t subPixelInterpolationOffsetBits; + uint32_t maxFramebufferWidth; + uint32_t maxFramebufferHeight; + uint32_t maxFramebufferLayers; + VkSampleCountFlags framebufferColorSampleCounts; + VkSampleCountFlags framebufferDepthSampleCounts; + VkSampleCountFlags framebufferStencilSampleCounts; + VkSampleCountFlags framebufferNoAttachmentsSampleCounts; + uint32_t maxColorAttachments; + VkSampleCountFlags sampledImageColorSampleCounts; + VkSampleCountFlags sampledImageIntegerSampleCounts; + VkSampleCountFlags sampledImageDepthSampleCounts; + VkSampleCountFlags sampledImageStencilSampleCounts; + VkSampleCountFlags storageImageSampleCounts; + uint32_t maxSampleMaskWords; + VkBool32 timestampComputeAndGraphics; + float timestampPeriod; + uint32_t maxClipDistances; + uint32_t maxCullDistances; + uint32_t maxCombinedClipAndCullDistances; + uint32_t discreteQueuePriorities; + float pointSizeRange[2]; + float lineWidthRange[2]; + float pointSizeGranularity; + float lineWidthGranularity; + VkBool32 strictLines; + VkBool32 standardSampleLocations; + VkDeviceSize optimalBufferCopyOffsetAlignment; + VkDeviceSize optimalBufferCopyRowPitchAlignment; + VkDeviceSize nonCoherentAtomSize; +} VkPhysicalDeviceLimits; + +typedef struct VkPhysicalDeviceMemoryProperties { + uint32_t memoryTypeCount; + VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; + uint32_t memoryHeapCount; + VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryProperties; + +typedef struct VkPhysicalDeviceSparseProperties { + VkBool32 residencyStandard2DBlockShape; + VkBool32 residencyStandard2DMultisampleBlockShape; + VkBool32 residencyStandard3DBlockShape; + VkBool32 residencyAlignedMipSize; + VkBool32 residencyNonResidentStrict; +} VkPhysicalDeviceSparseProperties; + +typedef struct VkPhysicalDeviceProperties { + uint32_t apiVersion; + uint32_t driverVersion; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceType deviceType; + char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; + VkPhysicalDeviceLimits limits; + VkPhysicalDeviceSparseProperties sparseProperties; +} VkPhysicalDeviceProperties; + +typedef struct VkQueueFamilyProperties { + VkQueueFlags queueFlags; + uint32_t queueCount; + uint32_t timestampValidBits; + VkExtent3D minImageTransferGranularity; +} VkQueueFamilyProperties; + +typedef struct VkDeviceQueueCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueCount; + const float* pQueuePriorities; +} VkDeviceQueueCreateInfo; + +typedef struct VkDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceCreateFlags flags; + uint32_t queueCreateInfoCount; + const VkDeviceQueueCreateInfo* pQueueCreateInfos; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; + const VkPhysicalDeviceFeatures* pEnabledFeatures; +} VkDeviceCreateInfo; + +typedef struct VkExtensionProperties { + char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; +} VkExtensionProperties; + +typedef struct VkLayerProperties { + char layerName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; + uint32_t implementationVersion; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkLayerProperties; + +typedef struct VkSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + const VkPipelineStageFlags* pWaitDstStageMask; + uint32_t commandBufferCount; + const VkCommandBuffer* pCommandBuffers; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkSubmitInfo; + +typedef struct VkMappedMemoryRange { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMappedMemoryRange; + +typedef struct VkMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeIndex; +} VkMemoryAllocateInfo; + +typedef struct VkMemoryRequirements { + VkDeviceSize size; + VkDeviceSize alignment; + uint32_t memoryTypeBits; +} VkMemoryRequirements; + +typedef struct VkSparseMemoryBind { + VkDeviceSize resourceOffset; + VkDeviceSize size; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseMemoryBind; + +typedef struct VkSparseBufferMemoryBindInfo { + VkBuffer buffer; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseBufferMemoryBindInfo; + +typedef struct VkSparseImageOpaqueMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseImageOpaqueMemoryBindInfo; + +typedef struct VkImageSubresource { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t arrayLayer; +} VkImageSubresource; + +typedef struct VkSparseImageMemoryBind { + VkImageSubresource subresource; + VkOffset3D offset; + VkExtent3D extent; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseImageMemoryBind; + +typedef struct VkSparseImageMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseImageMemoryBind* pBinds; +} VkSparseImageMemoryBindInfo; + +typedef struct VkBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t bufferBindCount; + const VkSparseBufferMemoryBindInfo* pBufferBinds; + uint32_t imageOpaqueBindCount; + const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; + uint32_t imageBindCount; + const VkSparseImageMemoryBindInfo* pImageBinds; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkBindSparseInfo; + +typedef struct VkSparseImageFormatProperties { + VkImageAspectFlags aspectMask; + VkExtent3D imageGranularity; + VkSparseImageFormatFlags flags; +} VkSparseImageFormatProperties; + +typedef struct VkSparseImageMemoryRequirements { + VkSparseImageFormatProperties formatProperties; + uint32_t imageMipTailFirstLod; + VkDeviceSize imageMipTailSize; + VkDeviceSize imageMipTailOffset; + VkDeviceSize imageMipTailStride; +} VkSparseImageMemoryRequirements; + +typedef struct VkFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkFenceCreateFlags flags; +} VkFenceCreateInfo; + +typedef struct VkSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreCreateFlags flags; +} VkSemaphoreCreateInfo; + +typedef struct VkEventCreateInfo { + VkStructureType sType; + const void* pNext; + VkEventCreateFlags flags; +} VkEventCreateInfo; + +typedef struct VkQueryPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkQueryPoolCreateFlags flags; + VkQueryType queryType; + uint32_t queryCount; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkQueryPoolCreateInfo; + +typedef struct VkBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkDeviceSize size; + VkBufferUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkBufferCreateInfo; + +typedef struct VkBufferViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferViewCreateFlags flags; + VkBuffer buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize range; +} VkBufferViewCreateInfo; + +typedef struct VkImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageType imageType; + VkFormat format; + VkExtent3D extent; + uint32_t mipLevels; + uint32_t arrayLayers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkImageLayout initialLayout; +} VkImageCreateInfo; + +typedef struct VkSubresourceLayout { + VkDeviceSize offset; + VkDeviceSize size; + VkDeviceSize rowPitch; + VkDeviceSize arrayPitch; + VkDeviceSize depthPitch; +} VkSubresourceLayout; + +typedef struct VkComponentMapping { + VkComponentSwizzle r; + VkComponentSwizzle g; + VkComponentSwizzle b; + VkComponentSwizzle a; +} VkComponentMapping; + +typedef struct VkImageViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageViewCreateFlags flags; + VkImage image; + VkImageViewType viewType; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresourceRange; +} VkImageViewCreateInfo; + +typedef struct VkShaderModuleCreateInfo { + VkStructureType sType; + const void* pNext; + VkShaderModuleCreateFlags flags; + size_t codeSize; + const uint32_t* pCode; +} VkShaderModuleCreateInfo; + +typedef struct VkPipelineCacheCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCacheCreateFlags flags; + size_t initialDataSize; + const void* pInitialData; +} VkPipelineCacheCreateInfo; + +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; + +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry* pMapEntries; + size_t dataSize; + const void* pData; +} VkSpecializationInfo; + +typedef struct VkPipelineShaderStageCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineShaderStageCreateFlags flags; + VkShaderStageFlagBits stage; + VkShaderModule module; + const char* pName; + const VkSpecializationInfo* pSpecializationInfo; +} VkPipelineShaderStageCreateInfo; + +typedef struct VkComputePipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + VkPipelineShaderStageCreateInfo stage; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkComputePipelineCreateInfo; + +typedef struct VkVertexInputBindingDescription { + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; +} VkVertexInputBindingDescription; + +typedef struct VkVertexInputAttributeDescription { + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription; + +typedef struct VkPipelineVertexInputStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineVertexInputStateCreateFlags flags; + uint32_t vertexBindingDescriptionCount; + const VkVertexInputBindingDescription* pVertexBindingDescriptions; + uint32_t vertexAttributeDescriptionCount; + const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; +} VkPipelineVertexInputStateCreateInfo; + +typedef struct VkPipelineInputAssemblyStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineInputAssemblyStateCreateFlags flags; + VkPrimitiveTopology topology; + VkBool32 primitiveRestartEnable; +} VkPipelineInputAssemblyStateCreateInfo; + +typedef struct VkPipelineTessellationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineTessellationStateCreateFlags flags; + uint32_t patchControlPoints; +} VkPipelineTessellationStateCreateInfo; + +typedef struct VkViewport { + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; +} VkViewport; + +typedef struct VkPipelineViewportStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineViewportStateCreateFlags flags; + uint32_t viewportCount; + const VkViewport* pViewports; + uint32_t scissorCount; + const VkRect2D* pScissors; +} VkPipelineViewportStateCreateInfo; + +typedef struct VkPipelineRasterizationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateCreateFlags flags; + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} VkPipelineRasterizationStateCreateInfo; + +typedef struct VkPipelineMultisampleStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineMultisampleStateCreateFlags flags; + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask* pSampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} VkPipelineMultisampleStateCreateInfo; + +typedef struct VkStencilOpState { + VkStencilOp failOp; + VkStencilOp passOp; + VkStencilOp depthFailOp; + VkCompareOp compareOp; + uint32_t compareMask; + uint32_t writeMask; + uint32_t reference; +} VkStencilOpState; + +typedef struct VkPipelineDepthStencilStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDepthStencilStateCreateFlags flags; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} VkPipelineDepthStencilStateCreateInfo; + +typedef struct VkPipelineColorBlendAttachmentState { + VkBool32 blendEnable; + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; + VkColorComponentFlags colorWriteMask; +} VkPipelineColorBlendAttachmentState; + +typedef struct VkPipelineColorBlendStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineColorBlendStateCreateFlags flags; + VkBool32 logicOpEnable; + VkLogicOp logicOp; + uint32_t attachmentCount; + const VkPipelineColorBlendAttachmentState* pAttachments; + float blendConstants[4]; +} VkPipelineColorBlendStateCreateInfo; + +typedef struct VkPipelineDynamicStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDynamicStateCreateFlags flags; + uint32_t dynamicStateCount; + const VkDynamicState* pDynamicStates; +} VkPipelineDynamicStateCreateInfo; + +typedef struct VkGraphicsPipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; + const VkPipelineViewportStateCreateInfo* pViewportState; + const VkPipelineRasterizationStateCreateInfo* pRasterizationState; + const VkPipelineMultisampleStateCreateInfo* pMultisampleState; + const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; + const VkPipelineColorBlendStateCreateInfo* pColorBlendState; + const VkPipelineDynamicStateCreateInfo* pDynamicState; + VkPipelineLayout layout; + VkRenderPass renderPass; + uint32_t subpass; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkGraphicsPipelineCreateInfo; + +typedef struct VkPushConstantRange { + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; +} VkPushConstantRange; + +typedef struct VkPipelineLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineLayoutCreateFlags flags; + uint32_t setLayoutCount; + const VkDescriptorSetLayout* pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange* pPushConstantRanges; +} VkPipelineLayoutCreateInfo; + +typedef struct VkSamplerCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerCreateFlags flags; + VkFilter magFilter; + VkFilter minFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + float mipLodBias; + VkBool32 anisotropyEnable; + float maxAnisotropy; + VkBool32 compareEnable; + VkCompareOp compareOp; + float minLod; + float maxLod; + VkBorderColor borderColor; + VkBool32 unnormalizedCoordinates; +} VkSamplerCreateInfo; + +typedef struct VkCopyDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet srcSet; + uint32_t srcBinding; + uint32_t srcArrayElement; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; +} VkCopyDescriptorSet; + +typedef struct VkDescriptorBufferInfo { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize range; +} VkDescriptorBufferInfo; + +typedef struct VkDescriptorImageInfo { + VkSampler sampler; + VkImageView imageView; + VkImageLayout imageLayout; +} VkDescriptorImageInfo; + +typedef struct VkDescriptorPoolSize { + VkDescriptorType type; + uint32_t descriptorCount; +} VkDescriptorPoolSize; + +typedef struct VkDescriptorPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPoolCreateFlags flags; + uint32_t maxSets; + uint32_t poolSizeCount; + const VkDescriptorPoolSize* pPoolSizes; +} VkDescriptorPoolCreateInfo; + +typedef struct VkDescriptorSetAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPool descriptorPool; + uint32_t descriptorSetCount; + const VkDescriptorSetLayout* pSetLayouts; +} VkDescriptorSetAllocateInfo; + +typedef struct VkDescriptorSetLayoutBinding { + uint32_t binding; + VkDescriptorType descriptorType; + uint32_t descriptorCount; + VkShaderStageFlags stageFlags; + const VkSampler* pImmutableSamplers; +} VkDescriptorSetLayoutBinding; + +typedef struct VkDescriptorSetLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorSetLayoutCreateFlags flags; + uint32_t bindingCount; + const VkDescriptorSetLayoutBinding* pBindings; +} VkDescriptorSetLayoutCreateInfo; + +typedef struct VkWriteDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + const VkDescriptorImageInfo* pImageInfo; + const VkDescriptorBufferInfo* pBufferInfo; + const VkBufferView* pTexelBufferView; +} VkWriteDescriptorSet; + +typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription; + +typedef struct VkAttachmentReference { + uint32_t attachment; + VkImageLayout layout; +} VkAttachmentReference; + +typedef struct VkFramebufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkFramebufferCreateFlags flags; + VkRenderPass renderPass; + uint32_t attachmentCount; + const VkImageView* pAttachments; + uint32_t width; + uint32_t height; + uint32_t layers; +} VkFramebufferCreateInfo; + +typedef struct VkSubpassDescription { + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t inputAttachmentCount; + const VkAttachmentReference* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference* pColorAttachments; + const VkAttachmentReference* pResolveAttachments; + const VkAttachmentReference* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription; + +typedef struct VkSubpassDependency { + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; +} VkSubpassDependency; + +typedef struct VkRenderPassCreateInfo { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency* pDependencies; +} VkRenderPassCreateInfo; + +typedef struct VkCommandPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPoolCreateFlags flags; + uint32_t queueFamilyIndex; +} VkCommandPoolCreateInfo; + +typedef struct VkCommandBufferAllocateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPool commandPool; + VkCommandBufferLevel level; + uint32_t commandBufferCount; +} VkCommandBufferAllocateInfo; + +typedef struct VkCommandBufferInheritanceInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + uint32_t subpass; + VkFramebuffer framebuffer; + VkBool32 occlusionQueryEnable; + VkQueryControlFlags queryFlags; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkCommandBufferInheritanceInfo; + +typedef struct VkCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + VkCommandBufferUsageFlags flags; + const VkCommandBufferInheritanceInfo* pInheritanceInfo; +} VkCommandBufferBeginInfo; + +typedef struct VkBufferCopy { + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy; + +typedef struct VkImageSubresourceLayers { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceLayers; + +typedef struct VkBufferImageCopy { + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy; + +typedef union VkClearColorValue { + float float32[4]; + int32_t int32[4]; + uint32_t uint32[4]; +} VkClearColorValue; + +typedef struct VkClearDepthStencilValue { + float depth; + uint32_t stencil; +} VkClearDepthStencilValue; + +typedef union VkClearValue { + VkClearColorValue color; + VkClearDepthStencilValue depthStencil; +} VkClearValue; + +typedef struct VkClearAttachment { + VkImageAspectFlags aspectMask; + uint32_t colorAttachment; + VkClearValue clearValue; +} VkClearAttachment; + +typedef struct VkClearRect { + VkRect2D rect; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkClearRect; + +typedef struct VkImageBlit { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit; + +typedef struct VkImageCopy { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy; + +typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve; + +typedef struct VkRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + VkFramebuffer framebuffer; + VkRect2D renderArea; + uint32_t clearValueCount; + const VkClearValue* pClearValues; +} VkRenderPassBeginInfo; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); +typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); +typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); +typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); +typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); +typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); +typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); +typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); +typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); +typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); +typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); +typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); +typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); +typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); +typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); +typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); +typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); +typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); +typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); +typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); +typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( + const VkInstanceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkInstance* pInstance); + +VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( + VkInstance instance, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( + VkInstance instance, + uint32_t* pPhysicalDeviceCount, + VkPhysicalDevice* pPhysicalDevices); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkImageFormatProperties* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties* pMemoryProperties); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( + VkInstance instance, + const char* pName); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( + VkDevice device, + const char* pName); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( + VkPhysicalDevice physicalDevice, + const VkDeviceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDevice* pDevice); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( + VkDevice device, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( + VkPhysicalDevice physicalDevice, + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( + VkDevice device, + uint32_t queueFamilyIndex, + uint32_t queueIndex, + VkQueue* pQueue); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo* pSubmits, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( + VkQueue queue); + +VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( + VkDevice device); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( + VkDevice device, + const VkMemoryAllocateInfo* pAllocateInfo, + const VkAllocationCallbacks* pAllocator, + VkDeviceMemory* pMemory); + +VKAPI_ATTR void VKAPI_CALL vkFreeMemory( + VkDevice device, + VkDeviceMemory memory, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + void** ppData); + +VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( + VkDevice device, + VkDeviceMemory memory); + +VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize* pCommittedMemoryInBytes); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( + VkDevice device, + VkBuffer buffer, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( + VkDevice device, + VkImage image, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( + VkDevice device, + VkBuffer buffer, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( + VkDevice device, + VkImage image, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( + VkDevice device, + VkImage image, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkSampleCountFlagBits samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( + VkQueue queue, + uint32_t bindInfoCount, + const VkBindSparseInfo* pBindInfo, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( + VkDevice device, + const VkFenceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFence( + VkDevice device, + VkFence fence, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( + VkDevice device, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences, + VkBool32 waitAll, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( + VkDevice device, + const VkSemaphoreCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSemaphore* pSemaphore); + +VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( + VkDevice device, + VkSemaphore semaphore, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( + VkDevice device, + const VkEventCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkEvent* pEvent); + +VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( + VkDevice device, + VkEvent event, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( + VkDevice device, + const VkQueryPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkQueryPool* pQueryPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( + VkDevice device, + VkQueryPool queryPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + size_t dataSize, + void* pData, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( + VkDevice device, + const VkBufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBuffer* pBuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( + VkDevice device, + VkBuffer buffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( + VkDevice device, + const VkBufferViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBufferView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( + VkDevice device, + VkBufferView bufferView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( + VkDevice device, + const VkImageCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImage* pImage); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImage( + VkDevice device, + VkImage image, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( + VkDevice device, + VkImage image, + const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( + VkDevice device, + const VkImageViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImageView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( + VkDevice device, + VkImageView imageView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( + VkDevice device, + const VkShaderModuleCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkShaderModule* pShaderModule); + +VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( + VkDevice device, + VkShaderModule shaderModule, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( + VkDevice device, + const VkPipelineCacheCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineCache* pPipelineCache); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( + VkDevice device, + VkPipelineCache pipelineCache, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( + VkDevice device, + VkPipelineCache pipelineCache, + size_t* pDataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( + VkDevice device, + VkPipelineCache dstCache, + uint32_t srcCacheCount, + const VkPipelineCache* pSrcCaches); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkGraphicsPipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkComputePipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( + VkDevice device, + VkPipeline pipeline, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( + VkDevice device, + const VkPipelineLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineLayout* pPipelineLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( + VkDevice device, + VkPipelineLayout pipelineLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( + VkDevice device, + const VkSamplerCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSampler* pSampler); + +VKAPI_ATTR void VKAPI_CALL vkDestroySampler( + VkDevice device, + VkSampler sampler, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorSetLayout* pSetLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( + VkDevice device, + VkDescriptorSetLayout descriptorSetLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( + VkDevice device, + const VkDescriptorPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorPool* pDescriptorPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + VkDescriptorPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( + VkDevice device, + const VkDescriptorSetAllocateInfo* pAllocateInfo, + VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( + VkDevice device, + VkDescriptorPool descriptorPool, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( + VkDevice device, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet* pDescriptorCopies); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( + VkDevice device, + const VkFramebufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFramebuffer* pFramebuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( + VkDevice device, + VkFramebuffer framebuffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( + VkDevice device, + const VkRenderPassCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( + VkDevice device, + VkRenderPass renderPass, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( + VkDevice device, + VkRenderPass renderPass, + VkExtent2D* pGranularity); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( + VkDevice device, + const VkCommandPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCommandPool* pCommandPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( + VkDevice device, + VkCommandPool commandPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( + VkDevice device, + const VkCommandBufferAllocateInfo* pAllocateInfo, + VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( + VkDevice device, + VkCommandPool commandPool, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( + VkCommandBuffer commandBuffer, + const VkCommandBufferBeginInfo* pBeginInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( + VkCommandBuffer commandBuffer, + VkCommandBufferResetFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( + VkCommandBuffer commandBuffer, + uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( + VkCommandBuffer commandBuffer, + float lineWidth); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( + VkCommandBuffer commandBuffer, + float depthBiasConstantFactor, + float depthBiasClamp, + float depthBiasSlopeFactor); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( + VkCommandBuffer commandBuffer, + const float blendConstants[4]); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( + VkCommandBuffer commandBuffer, + float minDepthBounds, + float maxDepthBounds); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t compareMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t writeMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t reference); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t* pDynamicOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdDraw( + VkCommandBuffer commandBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( + VkCommandBuffer commandBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( + VkCommandBuffer commandBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkFilter filter); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize size, + uint32_t data); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearColorValue* pColor, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue* pDepthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkClearAttachment* pAttachments, + uint32_t rectCount, + const VkClearRect* pRects); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageResolve* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( + VkCommandBuffer commandBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t offset, + uint32_t size, + const void* pValues); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( + VkCommandBuffer commandBuffer, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( + VkCommandBuffer commandBuffer, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); +#endif + + +// VK_VERSION_1_1 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_1 1 +// Vulkan 1.1 version number +#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)// Patch version should always be set to 0 + +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) +#define VK_MAX_DEVICE_GROUP_SIZE 32U +#define VK_LUID_SIZE 8U +#define VK_QUEUE_FAMILY_EXTERNAL (~1U) + +typedef enum VkPointClippingBehavior { + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, + VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPointClippingBehavior; + +typedef enum VkTessellationDomainOrigin { + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF +} VkTessellationDomainOrigin; + +typedef enum VkSamplerYcbcrModelConversion { + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF +} VkSamplerYcbcrModelConversion; + +typedef enum VkSamplerYcbcrRange { + VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, + VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, + VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerYcbcrRange; + +typedef enum VkChromaLocation { + VK_CHROMA_LOCATION_COSITED_EVEN = 0, + VK_CHROMA_LOCATION_MIDPOINT = 1, + VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, + VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, + VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF +} VkChromaLocation; + +typedef enum VkDescriptorUpdateTemplateType { + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorUpdateTemplateType; + +typedef enum VkSubgroupFeatureFlagBits { + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; + +typedef enum VkPeerMemoryFeatureFlagBits { + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT, + VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPeerMemoryFeatureFlagBits; +typedef VkFlags VkPeerMemoryFeatureFlags; + +typedef enum VkMemoryAllocateFlagBits { + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT = 0x00000002, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000004, + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryAllocateFlagBits; +typedef VkFlags VkMemoryAllocateFlags; +typedef VkFlags VkCommandPoolTrimFlags; +typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; + +typedef enum VkExternalMemoryHandleTypeFlagBits { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 0x00000400, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA = 0x00000800, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV = 0x00001000, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX = 0x00004000, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalMemoryHandleTypeFlagBits; +typedef VkFlags VkExternalMemoryHandleTypeFlags; + +typedef enum VkExternalMemoryFeatureFlagBits { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalMemoryFeatureFlagBits; +typedef VkFlags VkExternalMemoryFeatureFlags; + +typedef enum VkExternalFenceHandleTypeFlagBits { + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalFenceHandleTypeFlagBits; +typedef VkFlags VkExternalFenceHandleTypeFlags; + +typedef enum VkExternalFenceFeatureFlagBits { + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalFenceFeatureFlagBits; +typedef VkFlags VkExternalFenceFeatureFlags; + +typedef enum VkFenceImportFlagBits { + VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, + VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT, + VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceImportFlagBits; +typedef VkFlags VkFenceImportFlags; + +typedef enum VkSemaphoreImportFlagBits { + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, + VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreImportFlagBits; +typedef VkFlags VkSemaphoreImportFlags; + +typedef enum VkExternalSemaphoreHandleTypeFlagBits { + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA = 0x00000080, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalSemaphoreHandleTypeFlagBits; +typedef VkFlags VkExternalSemaphoreHandleTypeFlags; + +typedef enum VkExternalSemaphoreFeatureFlagBits { + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalSemaphoreFeatureFlagBits; +typedef VkFlags VkExternalSemaphoreFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties { + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; + +typedef struct VkBindBufferMemoryInfo { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindBufferMemoryInfo; + +typedef struct VkBindImageMemoryInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindImageMemoryInfo; + +typedef struct VkPhysicalDevice16BitStorageFeatures { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; +} VkPhysicalDevice16BitStorageFeatures; + +typedef struct VkMemoryDedicatedRequirements { + VkStructureType sType; + void* pNext; + VkBool32 prefersDedicatedAllocation; + VkBool32 requiresDedicatedAllocation; +} VkMemoryDedicatedRequirements; + +typedef struct VkMemoryDedicatedAllocateInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkBuffer buffer; +} VkMemoryDedicatedAllocateInfo; + +typedef struct VkMemoryAllocateFlagsInfo { + VkStructureType sType; + const void* pNext; + VkMemoryAllocateFlags flags; + uint32_t deviceMask; +} VkMemoryAllocateFlagsInfo; + +typedef struct VkDeviceGroupRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceMask; + uint32_t deviceRenderAreaCount; + const VkRect2D* pDeviceRenderAreas; +} VkDeviceGroupRenderPassBeginInfo; + +typedef struct VkDeviceGroupCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceMask; +} VkDeviceGroupCommandBufferBeginInfo; + +typedef struct VkDeviceGroupSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const uint32_t* pWaitSemaphoreDeviceIndices; + uint32_t commandBufferCount; + const uint32_t* pCommandBufferDeviceMasks; + uint32_t signalSemaphoreCount; + const uint32_t* pSignalSemaphoreDeviceIndices; +} VkDeviceGroupSubmitInfo; + +typedef struct VkDeviceGroupBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t resourceDeviceIndex; + uint32_t memoryDeviceIndex; +} VkDeviceGroupBindSparseInfo; + +typedef struct VkBindBufferMemoryDeviceGroupInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindBufferMemoryDeviceGroupInfo; + +typedef struct VkBindImageMemoryDeviceGroupInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; + uint32_t splitInstanceBindRegionCount; + const VkRect2D* pSplitInstanceBindRegions; +} VkBindImageMemoryDeviceGroupInfo; + +typedef struct VkPhysicalDeviceGroupProperties { + VkStructureType sType; + void* pNext; + uint32_t physicalDeviceCount; + VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; + VkBool32 subsetAllocation; +} VkPhysicalDeviceGroupProperties; + +typedef struct VkDeviceGroupDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t physicalDeviceCount; + const VkPhysicalDevice* pPhysicalDevices; +} VkDeviceGroupDeviceCreateInfo; + +typedef struct VkBufferMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferMemoryRequirementsInfo2; + +typedef struct VkImageMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageMemoryRequirementsInfo2; + +typedef struct VkImageSparseMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageSparseMemoryRequirementsInfo2; + +typedef struct VkMemoryRequirements2 { + VkStructureType sType; + void* pNext; + VkMemoryRequirements memoryRequirements; +} VkMemoryRequirements2; + +typedef struct VkSparseImageMemoryRequirements2 { + VkStructureType sType; + void* pNext; + VkSparseImageMemoryRequirements memoryRequirements; +} VkSparseImageMemoryRequirements2; + +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2; + +typedef struct VkPhysicalDeviceProperties2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceProperties properties; +} VkPhysicalDeviceProperties2; + +typedef struct VkFormatProperties2 { + VkStructureType sType; + void* pNext; + VkFormatProperties formatProperties; +} VkFormatProperties2; + +typedef struct VkImageFormatProperties2 { + VkStructureType sType; + void* pNext; + VkImageFormatProperties imageFormatProperties; +} VkImageFormatProperties2; + +typedef struct VkPhysicalDeviceImageFormatInfo2 { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkImageCreateFlags flags; +} VkPhysicalDeviceImageFormatInfo2; + +typedef struct VkQueueFamilyProperties2 { + VkStructureType sType; + void* pNext; + VkQueueFamilyProperties queueFamilyProperties; +} VkQueueFamilyProperties2; + +typedef struct VkPhysicalDeviceMemoryProperties2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceMemoryProperties memoryProperties; +} VkPhysicalDeviceMemoryProperties2; + +typedef struct VkSparseImageFormatProperties2 { + VkStructureType sType; + void* pNext; + VkSparseImageFormatProperties properties; +} VkSparseImageFormatProperties2; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkSampleCountFlagBits samples; + VkImageUsageFlags usage; + VkImageTiling tiling; +} VkPhysicalDeviceSparseImageFormatInfo2; + +typedef struct VkPhysicalDevicePointClippingProperties { + VkStructureType sType; + void* pNext; + VkPointClippingBehavior pointClippingBehavior; +} VkPhysicalDevicePointClippingProperties; + +typedef struct VkInputAttachmentAspectReference { + uint32_t subpass; + uint32_t inputAttachmentIndex; + VkImageAspectFlags aspectMask; +} VkInputAttachmentAspectReference; + +typedef struct VkRenderPassInputAttachmentAspectCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t aspectReferenceCount; + const VkInputAttachmentAspectReference* pAspectReferences; +} VkRenderPassInputAttachmentAspectCreateInfo; + +typedef struct VkImageViewUsageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags usage; +} VkImageViewUsageCreateInfo; + +typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkTessellationDomainOrigin domainOrigin; +} VkPipelineTessellationDomainOriginStateCreateInfo; + +typedef struct VkRenderPassMultiviewCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t subpassCount; + const uint32_t* pViewMasks; + uint32_t dependencyCount; + const int32_t* pViewOffsets; + uint32_t correlationMaskCount; + const uint32_t* pCorrelationMasks; +} VkRenderPassMultiviewCreateInfo; + +typedef struct VkPhysicalDeviceMultiviewFeatures { + VkStructureType sType; + void* pNext; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; +} VkPhysicalDeviceMultiviewFeatures; + +typedef struct VkPhysicalDeviceMultiviewProperties { + VkStructureType sType; + void* pNext; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; +} VkPhysicalDeviceMultiviewProperties; + +typedef struct VkPhysicalDeviceVariablePointersFeatures { + VkStructureType sType; + void* pNext; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; +} VkPhysicalDeviceVariablePointersFeatures; + +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryFeatures { + VkStructureType sType; + void* pNext; + VkBool32 protectedMemory; +} VkPhysicalDeviceProtectedMemoryFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryProperties { + VkStructureType sType; + void* pNext; + VkBool32 protectedNoFault; +} VkPhysicalDeviceProtectedMemoryProperties; + +typedef struct VkDeviceQueueInfo2 { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} VkDeviceQueueInfo2; + +typedef struct VkProtectedSubmitInfo { + VkStructureType sType; + const void* pNext; + VkBool32 protectedSubmit; +} VkProtectedSubmitInfo; + +typedef struct VkSamplerYcbcrConversionCreateInfo { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkSamplerYcbcrModelConversion ycbcrModel; + VkSamplerYcbcrRange ycbcrRange; + VkComponentMapping components; + VkChromaLocation xChromaOffset; + VkChromaLocation yChromaOffset; + VkFilter chromaFilter; + VkBool32 forceExplicitReconstruction; +} VkSamplerYcbcrConversionCreateInfo; + +typedef struct VkSamplerYcbcrConversionInfo { + VkStructureType sType; + const void* pNext; + VkSamplerYcbcrConversion conversion; +} VkSamplerYcbcrConversionInfo; + +typedef struct VkBindImagePlaneMemoryInfo { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits planeAspect; +} VkBindImagePlaneMemoryInfo; + +typedef struct VkImagePlaneMemoryRequirementsInfo { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits planeAspect; +} VkImagePlaneMemoryRequirementsInfo; + +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { + VkStructureType sType; + void* pNext; + VkBool32 samplerYcbcrConversion; +} VkPhysicalDeviceSamplerYcbcrConversionFeatures; + +typedef struct VkSamplerYcbcrConversionImageFormatProperties { + VkStructureType sType; + void* pNext; + uint32_t combinedImageSamplerDescriptorCount; +} VkSamplerYcbcrConversionImageFormatProperties; + +typedef struct VkDescriptorUpdateTemplateEntry { + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + size_t offset; + size_t stride; +} VkDescriptorUpdateTemplateEntry; + +typedef struct VkDescriptorUpdateTemplateCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorUpdateTemplateCreateFlags flags; + uint32_t descriptorUpdateEntryCount; + const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries; + VkDescriptorUpdateTemplateType templateType; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineBindPoint pipelineBindPoint; + VkPipelineLayout pipelineLayout; + uint32_t set; +} VkDescriptorUpdateTemplateCreateInfo; + +typedef struct VkExternalMemoryProperties { + VkExternalMemoryFeatureFlags externalMemoryFeatures; + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlags compatibleHandleTypes; +} VkExternalMemoryProperties; + +typedef struct VkPhysicalDeviceExternalImageFormatInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalImageFormatInfo; + +typedef struct VkExternalImageFormatProperties { + VkStructureType sType; + void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalImageFormatProperties; + +typedef struct VkPhysicalDeviceExternalBufferInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkBufferUsageFlags usage; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalBufferInfo; + +typedef struct VkExternalBufferProperties { + VkStructureType sType; + void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalBufferProperties; + +typedef struct VkPhysicalDeviceIDProperties { + VkStructureType sType; + void* pNext; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceLUID[VK_LUID_SIZE]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; +} VkPhysicalDeviceIDProperties; + +typedef struct VkExternalMemoryImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryImageCreateInfo; + +typedef struct VkExternalMemoryBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryBufferCreateInfo; + +typedef struct VkExportMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExportMemoryAllocateInfo; + +typedef struct VkPhysicalDeviceExternalFenceInfo { + VkStructureType sType; + const void* pNext; + VkExternalFenceHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalFenceInfo; + +typedef struct VkExternalFenceProperties { + VkStructureType sType; + void* pNext; + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; + VkExternalFenceHandleTypeFlags compatibleHandleTypes; + VkExternalFenceFeatureFlags externalFenceFeatures; +} VkExternalFenceProperties; + +typedef struct VkExportFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalFenceHandleTypeFlags handleTypes; +} VkExportFenceCreateInfo; + +typedef struct VkExportSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalSemaphoreHandleTypeFlags handleTypes; +} VkExportSemaphoreCreateInfo; + +typedef struct VkPhysicalDeviceExternalSemaphoreInfo { + VkStructureType sType; + const void* pNext; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalSemaphoreInfo; + +typedef struct VkExternalSemaphoreProperties { + VkStructureType sType; + void* pNext; + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; +} VkExternalSemaphoreProperties; + +typedef struct VkPhysicalDeviceMaintenance3Properties { + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; + +typedef struct VkDescriptorSetLayoutSupport { + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; + +typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceShaderDrawParametersFeatures; + +typedef VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t* pApiVersion); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion( + uint32_t* pApiVersion); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2( + VkDevice device, + uint32_t bindInfoCount, + const VkBindBufferMemoryInfo* pBindInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2( + VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfo* pBindInfos); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask( + VkCommandBuffer commandBuffer, + uint32_t deviceMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBase( + VkCommandBuffer commandBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2( + VkDevice device, + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2( + VkDevice device, + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2* pMemoryProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2( + VkDevice device, + const VkDeviceQueueInfo2* pQueueInfo, + VkQueue* pQueue); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSamplerYcbcrConversion* pYcbcrConversion); + +VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversion( + VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate( + VkDevice device, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplate( + VkDevice device, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplate( + VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport); +#endif + + +// VK_VERSION_1_2 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_2 1 +// Vulkan 1.2 version number +#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)// Patch version should always be set to 0 + +#define VK_MAX_DRIVER_NAME_SIZE 256U +#define VK_MAX_DRIVER_INFO_SIZE 256U + +typedef enum VkDriverId { + VK_DRIVER_ID_AMD_PROPRIETARY = 1, + VK_DRIVER_ID_AMD_OPEN_SOURCE = 2, + VK_DRIVER_ID_MESA_RADV = 3, + VK_DRIVER_ID_NVIDIA_PROPRIETARY = 4, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS = 5, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA = 6, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY = 7, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY = 8, + VK_DRIVER_ID_ARM_PROPRIETARY = 9, + VK_DRIVER_ID_GOOGLE_SWIFTSHADER = 10, + VK_DRIVER_ID_GGP_PROPRIETARY = 11, + VK_DRIVER_ID_BROADCOM_PROPRIETARY = 12, + VK_DRIVER_ID_MESA_LLVMPIPE = 13, + VK_DRIVER_ID_MOLTENVK = 14, + VK_DRIVER_ID_COREAVI_PROPRIETARY = 15, + VK_DRIVER_ID_JUICE_PROPRIETARY = 16, + VK_DRIVER_ID_VERISILICON_PROPRIETARY = 17, + VK_DRIVER_ID_MESA_TURNIP = 18, + VK_DRIVER_ID_MESA_V3DV = 19, + VK_DRIVER_ID_MESA_PANVK = 20, + VK_DRIVER_ID_SAMSUNG_PROPRIETARY = 21, + VK_DRIVER_ID_MESA_VENUS = 22, + VK_DRIVER_ID_MESA_DOZEN = 23, + VK_DRIVER_ID_MESA_NVK = 24, + VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA = 25, + VK_DRIVER_ID_MESA_AGXV = 26, + VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, + VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, + VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, + VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = VK_DRIVER_ID_NVIDIA_PROPRIETARY, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = VK_DRIVER_ID_IMAGINATION_PROPRIETARY, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = VK_DRIVER_ID_QUALCOMM_PROPRIETARY, + VK_DRIVER_ID_ARM_PROPRIETARY_KHR = VK_DRIVER_ID_ARM_PROPRIETARY, + VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = VK_DRIVER_ID_GOOGLE_SWIFTSHADER, + VK_DRIVER_ID_GGP_PROPRIETARY_KHR = VK_DRIVER_ID_GGP_PROPRIETARY, + VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY, + VK_DRIVER_ID_MAX_ENUM = 0x7FFFFFFF +} VkDriverId; + +typedef enum VkShaderFloatControlsIndependence { + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY = 0, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL = 1, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE = 2, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM = 0x7FFFFFFF +} VkShaderFloatControlsIndependence; + +typedef enum VkSamplerReductionMode { + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE = 0, + VK_SAMPLER_REDUCTION_MODE_MIN = 1, + VK_SAMPLER_REDUCTION_MODE_MAX = 2, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_RANGECLAMP_QCOM = 1000521000, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, + VK_SAMPLER_REDUCTION_MODE_MIN_EXT = VK_SAMPLER_REDUCTION_MODE_MIN, + VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX, + VK_SAMPLER_REDUCTION_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerReductionMode; + +typedef enum VkSemaphoreType { + VK_SEMAPHORE_TYPE_BINARY = 0, + VK_SEMAPHORE_TYPE_TIMELINE = 1, + VK_SEMAPHORE_TYPE_BINARY_KHR = VK_SEMAPHORE_TYPE_BINARY, + VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE, + VK_SEMAPHORE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreType; + +typedef enum VkResolveModeFlagBits { + VK_RESOLVE_MODE_NONE = 0, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT = 0x00000001, + VK_RESOLVE_MODE_AVERAGE_BIT = 0x00000002, + VK_RESOLVE_MODE_MIN_BIT = 0x00000004, + VK_RESOLVE_MODE_MAX_BIT = 0x00000008, + VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID = 0x00000010, + VK_RESOLVE_MODE_NONE_KHR = VK_RESOLVE_MODE_NONE, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, + VK_RESOLVE_MODE_AVERAGE_BIT_KHR = VK_RESOLVE_MODE_AVERAGE_BIT, + VK_RESOLVE_MODE_MIN_BIT_KHR = VK_RESOLVE_MODE_MIN_BIT, + VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT, + VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkResolveModeFlagBits; +typedef VkFlags VkResolveModeFlags; + +typedef enum VkDescriptorBindingFlagBits { + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT = 0x00000001, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT = 0x00000002, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT = 0x00000004, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT = 0x00000008, + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, + VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorBindingFlagBits; +typedef VkFlags VkDescriptorBindingFlags; + +typedef enum VkSemaphoreWaitFlagBits { + VK_SEMAPHORE_WAIT_ANY_BIT = 0x00000001, + VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT, + VK_SEMAPHORE_WAIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreWaitFlagBits; +typedef VkFlags VkSemaphoreWaitFlags; +typedef struct VkPhysicalDeviceVulkan11Features { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; + VkBool32 protectedMemory; + VkBool32 samplerYcbcrConversion; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceVulkan11Features; + +typedef struct VkPhysicalDeviceVulkan11Properties { + VkStructureType sType; + void* pNext; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceLUID[VK_LUID_SIZE]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; + uint32_t subgroupSize; + VkShaderStageFlags subgroupSupportedStages; + VkSubgroupFeatureFlags subgroupSupportedOperations; + VkBool32 subgroupQuadOperationsInAllStages; + VkPointClippingBehavior pointClippingBehavior; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; + VkBool32 protectedNoFault; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceVulkan11Properties; + +typedef struct VkPhysicalDeviceVulkan12Features { + VkStructureType sType; + void* pNext; + VkBool32 samplerMirrorClampToEdge; + VkBool32 drawIndirectCount; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; + VkBool32 descriptorIndexing; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; + VkBool32 samplerFilterMinmax; + VkBool32 scalarBlockLayout; + VkBool32 imagelessFramebuffer; + VkBool32 uniformBufferStandardLayout; + VkBool32 shaderSubgroupExtendedTypes; + VkBool32 separateDepthStencilLayouts; + VkBool32 hostQueryReset; + VkBool32 timelineSemaphore; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; + VkBool32 shaderOutputViewportIndex; + VkBool32 shaderOutputLayer; + VkBool32 subgroupBroadcastDynamicId; +} VkPhysicalDeviceVulkan12Features; + +typedef struct VkConformanceVersion { + uint8_t major; + uint8_t minor; + uint8_t subminor; + uint8_t patch; +} VkConformanceVersion; + +typedef struct VkPhysicalDeviceVulkan12Properties { + VkStructureType sType; + void* pNext; + VkDriverId driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; + VkConformanceVersion conformanceVersion; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; + uint64_t maxTimelineSemaphoreValueDifference; + VkSampleCountFlags framebufferIntegerColorSampleCounts; +} VkPhysicalDeviceVulkan12Properties; + +typedef struct VkImageFormatListCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t viewFormatCount; + const VkFormat* pViewFormats; +} VkImageFormatListCreateInfo; + +typedef struct VkAttachmentDescription2 { + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2; + +typedef struct VkAttachmentReference2 { + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2; + +typedef struct VkSubpassDescription2 { + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2* pColorAttachments; + const VkAttachmentReference2* pResolveAttachments; + const VkAttachmentReference2* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2; + +typedef struct VkSubpassDependency2 { + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2; + +typedef struct VkRenderPassCreateInfo2 { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2; + +typedef struct VkSubpassBeginInfo { + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfo; + +typedef struct VkSubpassEndInfo { + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfo; + +typedef struct VkPhysicalDevice8BitStorageFeatures { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeatures; + +typedef struct VkPhysicalDeviceDriverProperties { + VkStructureType sType; + void* pNext; + VkDriverId driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; + VkConformanceVersion conformanceVersion; +} VkPhysicalDeviceDriverProperties; + +typedef struct VkPhysicalDeviceShaderAtomicInt64Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; +} VkPhysicalDeviceShaderAtomicInt64Features; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceShaderFloat16Int8Features; + +typedef struct VkPhysicalDeviceFloatControlsProperties { + VkStructureType sType; + void* pNext; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; +} VkPhysicalDeviceFloatControlsProperties; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t bindingCount; + const VkDescriptorBindingFlags* pBindingFlags; +} VkDescriptorSetLayoutBindingFlagsCreateInfo; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; +} VkPhysicalDeviceDescriptorIndexingFeatures; + +typedef struct VkPhysicalDeviceDescriptorIndexingProperties { + VkStructureType sType; + void* pNext; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; +} VkPhysicalDeviceDescriptorIndexingProperties; + +typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo { + VkStructureType sType; + const void* pNext; + uint32_t descriptorSetCount; + const uint32_t* pDescriptorCounts; +} VkDescriptorSetVariableDescriptorCountAllocateInfo; + +typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupport { + VkStructureType sType; + void* pNext; + uint32_t maxVariableDescriptorCount; +} VkDescriptorSetVariableDescriptorCountLayoutSupport; + +typedef struct VkSubpassDescriptionDepthStencilResolve { + VkStructureType sType; + const void* pNext; + VkResolveModeFlagBits depthResolveMode; + VkResolveModeFlagBits stencilResolveMode; + const VkAttachmentReference2* pDepthStencilResolveAttachment; +} VkSubpassDescriptionDepthStencilResolve; + +typedef struct VkPhysicalDeviceDepthStencilResolveProperties { + VkStructureType sType; + void* pNext; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; +} VkPhysicalDeviceDepthStencilResolveProperties; + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures { + VkStructureType sType; + void* pNext; + VkBool32 scalarBlockLayout; +} VkPhysicalDeviceScalarBlockLayoutFeatures; + +typedef struct VkImageStencilUsageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags stencilUsage; +} VkImageStencilUsageCreateInfo; + +typedef struct VkSamplerReductionModeCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerReductionMode reductionMode; +} VkSamplerReductionModeCreateInfo; + +typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties { + VkStructureType sType; + void* pNext; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; +} VkPhysicalDeviceSamplerFilterMinmaxProperties; + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures { + VkStructureType sType; + void* pNext; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; +} VkPhysicalDeviceVulkanMemoryModelFeatures; + +typedef struct VkPhysicalDeviceImagelessFramebufferFeatures { + VkStructureType sType; + void* pNext; + VkBool32 imagelessFramebuffer; +} VkPhysicalDeviceImagelessFramebufferFeatures; + +typedef struct VkFramebufferAttachmentImageInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageUsageFlags usage; + uint32_t width; + uint32_t height; + uint32_t layerCount; + uint32_t viewFormatCount; + const VkFormat* pViewFormats; +} VkFramebufferAttachmentImageInfo; + +typedef struct VkFramebufferAttachmentsCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t attachmentImageInfoCount; + const VkFramebufferAttachmentImageInfo* pAttachmentImageInfos; +} VkFramebufferAttachmentsCreateInfo; + +typedef struct VkRenderPassAttachmentBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t attachmentCount; + const VkImageView* pAttachments; +} VkRenderPassAttachmentBeginInfo; + +typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures { + VkStructureType sType; + void* pNext; + VkBool32 uniformBufferStandardLayout; +} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; + +typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupExtendedTypes; +} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; + +typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures { + VkStructureType sType; + void* pNext; + VkBool32 separateDepthStencilLayouts; +} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; + +typedef struct VkAttachmentReferenceStencilLayout { + VkStructureType sType; + void* pNext; + VkImageLayout stencilLayout; +} VkAttachmentReferenceStencilLayout; + +typedef struct VkAttachmentDescriptionStencilLayout { + VkStructureType sType; + void* pNext; + VkImageLayout stencilInitialLayout; + VkImageLayout stencilFinalLayout; +} VkAttachmentDescriptionStencilLayout; + +typedef struct VkPhysicalDeviceHostQueryResetFeatures { + VkStructureType sType; + void* pNext; + VkBool32 hostQueryReset; +} VkPhysicalDeviceHostQueryResetFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures { + VkStructureType sType; + void* pNext; + VkBool32 timelineSemaphore; +} VkPhysicalDeviceTimelineSemaphoreFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreProperties { + VkStructureType sType; + void* pNext; + uint64_t maxTimelineSemaphoreValueDifference; +} VkPhysicalDeviceTimelineSemaphoreProperties; + +typedef struct VkSemaphoreTypeCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreType semaphoreType; + uint64_t initialValue; +} VkSemaphoreTypeCreateInfo; + +typedef struct VkTimelineSemaphoreSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreValueCount; + const uint64_t* pWaitSemaphoreValues; + uint32_t signalSemaphoreValueCount; + const uint64_t* pSignalSemaphoreValues; +} VkTimelineSemaphoreSubmitInfo; + +typedef struct VkSemaphoreWaitInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreWaitFlags flags; + uint32_t semaphoreCount; + const VkSemaphore* pSemaphores; + const uint64_t* pValues; +} VkSemaphoreWaitInfo; + +typedef struct VkSemaphoreSignalInfo { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + uint64_t value; +} VkSemaphoreSignalInfo; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures { + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeatures; + +typedef struct VkBufferDeviceAddressInfo { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfo; + +typedef struct VkBufferOpaqueCaptureAddressCreateInfo { + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfo; + +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo { + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfo; + +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfo; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2)(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkResetQueryPool)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValue)(VkDevice device, VkSemaphore semaphore, uint64_t* pValue); +typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphores)(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphore)(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddress)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddress)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCount( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCount( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2( + VkDevice device, + const VkRenderPassCreateInfo2* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + const VkSubpassBeginInfo* pSubpassBeginInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2( + VkCommandBuffer commandBuffer, + const VkSubpassBeginInfo* pSubpassBeginInfo, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2( + VkCommandBuffer commandBuffer, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkResetQueryPool( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreCounterValue( + VkDevice device, + VkSemaphore semaphore, + uint64_t* pValue); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitSemaphores( + VkDevice device, + const VkSemaphoreWaitInfo* pWaitInfo, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkSignalSemaphore( + VkDevice device, + const VkSemaphoreSignalInfo* pSignalInfo); + +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddress( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddress( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddress( + VkDevice device, + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); +#endif + + +// VK_VERSION_1_3 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_3 1 +// Vulkan 1.3 version number +#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)// Patch version should always be set to 0 + +typedef uint64_t VkFlags64; +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlot) + +typedef enum VkPipelineCreationFeedbackFlagBits { + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT = 0x00000001, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT = 0x00000002, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT = 0x00000004, + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT, + VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreationFeedbackFlagBits; +typedef VkFlags VkPipelineCreationFeedbackFlags; + +typedef enum VkToolPurposeFlagBits { + VK_TOOL_PURPOSE_VALIDATION_BIT = 0x00000001, + VK_TOOL_PURPOSE_PROFILING_BIT = 0x00000002, + VK_TOOL_PURPOSE_TRACING_BIT = 0x00000004, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT = 0x00000008, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT = 0x00000010, + VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 0x00000020, + VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 0x00000040, + VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = VK_TOOL_PURPOSE_VALIDATION_BIT, + VK_TOOL_PURPOSE_PROFILING_BIT_EXT = VK_TOOL_PURPOSE_PROFILING_BIT, + VK_TOOL_PURPOSE_TRACING_BIT_EXT = VK_TOOL_PURPOSE_TRACING_BIT, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT, + VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkToolPurposeFlagBits; +typedef VkFlags VkToolPurposeFlags; +typedef VkFlags VkPrivateDataSlotCreateFlags; +typedef VkFlags64 VkPipelineStageFlags2; + +// Flag bits for VkPipelineStageFlagBits2 +typedef VkFlags64 VkPipelineStageFlagBits2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE = 0ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE_KHR = 0ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT = 0x00000001ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 0x00000001ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT = 0x00000002ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 0x00000002ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT = 0x00000004ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 0x00000004ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT = 0x00000008ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 0x00000008ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 0x00000010ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 0x00000020ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT = 0x00000040ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 0x00000040ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT = 0x00000080ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 0x00000080ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT = 0x00000100ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 0x00000100ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT = 0x00000200ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 0x00000200ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 0x00000400ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT = 0x00000800ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 0x00000800ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT = 0x00002000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 0x00002000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT = 0x00004000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 0x00004000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT = 0x00008000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 0x00008000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT = 0x00010000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 0x00010000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT = 0x100000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 0x100000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT = 0x200000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 0x200000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT = 0x400000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 0x400000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT = 0x800000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 0x800000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT = 0x1000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 0x1000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT = 0x2000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 0x2000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT = 0x4000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 0x4000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR = 0x04000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR = 0x08000000ULL; +#endif +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 0x00020000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV = 0x00400000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR = 0x00200000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV = 0x00200000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 0x00080000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 0x00100000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT = 0x00080000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT = 0x00100000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADER_BIT_HUAWEI = 0x8000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 0x8000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 0x10000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR = 0x10000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT = 0x40000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLUSTER_CULLING_SHADER_BIT_HUAWEI = 0x20000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV = 0x20000000ULL; + +typedef VkFlags64 VkAccessFlags2; + +// Flag bits for VkAccessFlagBits2 +typedef VkFlags64 VkAccessFlagBits2; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE = 0ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE_KHR = 0ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT = 0x00000001ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 0x00000001ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT = 0x00000002ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT_KHR = 0x00000002ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 0x00000004ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT = 0x00000008ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 0x00000008ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT = 0x00000010ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 0x00000010ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT = 0x00000020ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT_KHR = 0x00000020ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT = 0x00000040ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 0x00000040ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT = 0x00000080ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 0x00000080ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 0x00000100ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 0x00000200ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 0x00000400ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT = 0x00000800ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 0x00000800ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT = 0x00001000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 0x00001000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT = 0x00002000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT_KHR = 0x00002000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT = 0x00004000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT_KHR = 0x00004000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT = 0x00008000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT_KHR = 0x00008000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT = 0x00010000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 0x00010000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT = 0x100000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 0x100000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT = 0x200000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 0x200000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 0x400000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 0x400000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR = 0x800000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR = 0x1000000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR = 0x2000000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR = 0x4000000000ULL; +#endif +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT = 0x20000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI = 0x8000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR = 0x10000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_READ_BIT_EXT = 0x100000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT = 0x200000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_READ_BIT_NV = 0x40000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_WRITE_BIT_NV = 0x80000000000ULL; + + +typedef enum VkSubmitFlagBits { + VK_SUBMIT_PROTECTED_BIT = 0x00000001, + VK_SUBMIT_PROTECTED_BIT_KHR = VK_SUBMIT_PROTECTED_BIT, + VK_SUBMIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubmitFlagBits; +typedef VkFlags VkSubmitFlags; + +typedef enum VkRenderingFlagBits { + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 0x00000001, + VK_RENDERING_SUSPENDING_BIT = 0x00000002, + VK_RENDERING_RESUMING_BIT = 0x00000004, + VK_RENDERING_CONTENTS_INLINE_BIT_EXT = 0x00000010, + VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000008, + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, + VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT, + VK_RENDERING_RESUMING_BIT_KHR = VK_RENDERING_RESUMING_BIT, + VK_RENDERING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkRenderingFlagBits; +typedef VkFlags VkRenderingFlags; +typedef VkFlags64 VkFormatFeatureFlags2; + +// Flag bits for VkFormatFeatureFlagBits2 +typedef VkFlags64 VkFormatFeatureFlagBits2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT = 0x00000001ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR = 0x00000001ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT = 0x00000002ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR = 0x00000002ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT_KHR = 0x00000004ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 0x00000008ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT = 0x00000010ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 0x00000010ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT_KHR = 0x00000020ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT = 0x00000040ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT_KHR = 0x00000040ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT = 0x00000080ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT_KHR = 0x00000080ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT_KHR = 0x00000100ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR = 0x00000200ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT = 0x00000400ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT_KHR = 0x00000400ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT = 0x00000800ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT_KHR = 0x00000800ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT_KHR = 0x00001000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT = 0x00002000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT = 0x00004000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT_KHR = 0x00004000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT = 0x00008000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT_KHR = 0x00008000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT_KHR = 0x00010000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 0x00020000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 0x00040000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 0x00080000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 0x00100000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 0x00200000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT = 0x00400000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT_KHR = 0x00400000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT = 0x00800000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR = 0x00800000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT = 0x80000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR = 0x80000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT = 0x100000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR = 0x100000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT = 0x200000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR = 0x200000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_DECODE_OUTPUT_BIT_KHR = 0x02000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_DECODE_DPB_BIT_KHR = 0x04000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT = 0x400000000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR = 0x08000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000ULL; +#endif +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV = 0x4000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM = 0x400000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM = 0x800000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_BIT_QCOM = 0x1000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BOX_FILTER_SAMPLED_BIT_QCOM = 0x2000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_IMAGE_BIT_NV = 0x10000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_VECTOR_BIT_NV = 0x20000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_COST_BIT_NV = 0x40000000000ULL; + +typedef struct VkPhysicalDeviceVulkan13Features { + VkStructureType sType; + void* pNext; + VkBool32 robustImageAccess; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; + VkBool32 pipelineCreationCacheControl; + VkBool32 privateData; + VkBool32 shaderDemoteToHelperInvocation; + VkBool32 shaderTerminateInvocation; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; + VkBool32 synchronization2; + VkBool32 textureCompressionASTC_HDR; + VkBool32 shaderZeroInitializeWorkgroupMemory; + VkBool32 dynamicRendering; + VkBool32 shaderIntegerDotProduct; + VkBool32 maintenance4; +} VkPhysicalDeviceVulkan13Features; + +typedef struct VkPhysicalDeviceVulkan13Properties { + VkStructureType sType; + void* pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; + uint32_t maxInlineUniformTotalSize; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceVulkan13Properties; + +typedef struct VkPipelineCreationFeedback { + VkPipelineCreationFeedbackFlags flags; + uint64_t duration; +} VkPipelineCreationFeedback; + +typedef struct VkPipelineCreationFeedbackCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreationFeedback* pPipelineCreationFeedback; + uint32_t pipelineStageCreationFeedbackCount; + VkPipelineCreationFeedback* pPipelineStageCreationFeedbacks; +} VkPipelineCreationFeedbackCreateInfo; + +typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderTerminateInvocation; +} VkPhysicalDeviceShaderTerminateInvocationFeatures; + +typedef struct VkPhysicalDeviceToolProperties { + VkStructureType sType; + void* pNext; + char name[VK_MAX_EXTENSION_NAME_SIZE]; + char version[VK_MAX_EXTENSION_NAME_SIZE]; + VkToolPurposeFlags purposes; + char description[VK_MAX_DESCRIPTION_SIZE]; + char layer[VK_MAX_EXTENSION_NAME_SIZE]; +} VkPhysicalDeviceToolProperties; + +typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderDemoteToHelperInvocation; +} VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures; + +typedef struct VkPhysicalDevicePrivateDataFeatures { + VkStructureType sType; + void* pNext; + VkBool32 privateData; +} VkPhysicalDevicePrivateDataFeatures; + +typedef struct VkDevicePrivateDataCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t privateDataSlotRequestCount; +} VkDevicePrivateDataCreateInfo; + +typedef struct VkPrivateDataSlotCreateInfo { + VkStructureType sType; + const void* pNext; + VkPrivateDataSlotCreateFlags flags; +} VkPrivateDataSlotCreateInfo; + +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures { + VkStructureType sType; + void* pNext; + VkBool32 pipelineCreationCacheControl; +} VkPhysicalDevicePipelineCreationCacheControlFeatures; + +typedef struct VkMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; +} VkMemoryBarrier2; + +typedef struct VkBufferMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier2; + +typedef struct VkImageMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier2; + +typedef struct VkDependencyInfo { + VkStructureType sType; + const void* pNext; + VkDependencyFlags dependencyFlags; + uint32_t memoryBarrierCount; + const VkMemoryBarrier2* pMemoryBarriers; + uint32_t bufferMemoryBarrierCount; + const VkBufferMemoryBarrier2* pBufferMemoryBarriers; + uint32_t imageMemoryBarrierCount; + const VkImageMemoryBarrier2* pImageMemoryBarriers; +} VkDependencyInfo; + +typedef struct VkSemaphoreSubmitInfo { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + uint64_t value; + VkPipelineStageFlags2 stageMask; + uint32_t deviceIndex; +} VkSemaphoreSubmitInfo; + +typedef struct VkCommandBufferSubmitInfo { + VkStructureType sType; + const void* pNext; + VkCommandBuffer commandBuffer; + uint32_t deviceMask; +} VkCommandBufferSubmitInfo; + +typedef struct VkSubmitInfo2 { + VkStructureType sType; + const void* pNext; + VkSubmitFlags flags; + uint32_t waitSemaphoreInfoCount; + const VkSemaphoreSubmitInfo* pWaitSemaphoreInfos; + uint32_t commandBufferInfoCount; + const VkCommandBufferSubmitInfo* pCommandBufferInfos; + uint32_t signalSemaphoreInfoCount; + const VkSemaphoreSubmitInfo* pSignalSemaphoreInfos; +} VkSubmitInfo2; + +typedef struct VkPhysicalDeviceSynchronization2Features { + VkStructureType sType; + void* pNext; + VkBool32 synchronization2; +} VkPhysicalDeviceSynchronization2Features; + +typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderZeroInitializeWorkgroupMemory; +} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures; + +typedef struct VkPhysicalDeviceImageRobustnessFeatures { + VkStructureType sType; + void* pNext; + VkBool32 robustImageAccess; +} VkPhysicalDeviceImageRobustnessFeatures; + +typedef struct VkBufferCopy2 { + VkStructureType sType; + const void* pNext; + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy2; + +typedef struct VkCopyBufferInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer srcBuffer; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferCopy2* pRegions; +} VkCopyBufferInfo2; + +typedef struct VkImageCopy2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy2; + +typedef struct VkCopyImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2* pRegions; +} VkCopyImageInfo2; + +typedef struct VkBufferImageCopy2 { + VkStructureType sType; + const void* pNext; + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy2; + +typedef struct VkCopyBufferToImageInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer srcBuffer; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkBufferImageCopy2* pRegions; +} VkCopyBufferToImageInfo2; + +typedef struct VkCopyImageToBufferInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferImageCopy2* pRegions; +} VkCopyImageToBufferInfo2; + +typedef struct VkImageBlit2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit2; + +typedef struct VkBlitImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageBlit2* pRegions; + VkFilter filter; +} VkBlitImageInfo2; + +typedef struct VkImageResolve2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve2; + +typedef struct VkResolveImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageResolve2* pRegions; +} VkResolveImageInfo2; + +typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures { + VkStructureType sType; + void* pNext; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; +} VkPhysicalDeviceSubgroupSizeControlFeatures; + +typedef struct VkPhysicalDeviceSubgroupSizeControlProperties { + VkStructureType sType; + void* pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; +} VkPhysicalDeviceSubgroupSizeControlProperties; + +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo { + VkStructureType sType; + void* pNext; + uint32_t requiredSubgroupSize; +} VkPipelineShaderStageRequiredSubgroupSizeCreateInfo; + +typedef struct VkPhysicalDeviceInlineUniformBlockFeatures { + VkStructureType sType; + void* pNext; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; +} VkPhysicalDeviceInlineUniformBlockFeatures; + +typedef struct VkPhysicalDeviceInlineUniformBlockProperties { + VkStructureType sType; + void* pNext; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; +} VkPhysicalDeviceInlineUniformBlockProperties; + +typedef struct VkWriteDescriptorSetInlineUniformBlock { + VkStructureType sType; + const void* pNext; + uint32_t dataSize; + const void* pData; +} VkWriteDescriptorSetInlineUniformBlock; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t maxInlineUniformBlockBindings; +} VkDescriptorPoolInlineUniformBlockCreateInfo; + +typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures { + VkStructureType sType; + void* pNext; + VkBool32 textureCompressionASTC_HDR; +} VkPhysicalDeviceTextureCompressionASTCHDRFeatures; + +typedef struct VkRenderingAttachmentInfo { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkResolveModeFlagBits resolveMode; + VkImageView resolveImageView; + VkImageLayout resolveImageLayout; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkClearValue clearValue; +} VkRenderingAttachmentInfo; + +typedef struct VkRenderingInfo { + VkStructureType sType; + const void* pNext; + VkRenderingFlags flags; + VkRect2D renderArea; + uint32_t layerCount; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkRenderingAttachmentInfo* pColorAttachments; + const VkRenderingAttachmentInfo* pDepthAttachment; + const VkRenderingAttachmentInfo* pStencilAttachment; +} VkRenderingInfo; + +typedef struct VkPipelineRenderingCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkPipelineRenderingCreateInfo; + +typedef struct VkPhysicalDeviceDynamicRenderingFeatures { + VkStructureType sType; + void* pNext; + VkBool32 dynamicRendering; +} VkPhysicalDeviceDynamicRenderingFeatures; + +typedef struct VkCommandBufferInheritanceRenderingInfo { + VkStructureType sType; + const void* pNext; + VkRenderingFlags flags; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; + VkSampleCountFlagBits rasterizationSamples; +} VkCommandBufferInheritanceRenderingInfo; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderIntegerDotProduct; +} VkPhysicalDeviceShaderIntegerDotProductFeatures; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties { + VkStructureType sType; + void* pNext; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; +} VkPhysicalDeviceShaderIntegerDotProductProperties; + +typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties { + VkStructureType sType; + void* pNext; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; +} VkPhysicalDeviceTexelBufferAlignmentProperties; + +typedef struct VkFormatProperties3 { + VkStructureType sType; + void* pNext; + VkFormatFeatureFlags2 linearTilingFeatures; + VkFormatFeatureFlags2 optimalTilingFeatures; + VkFormatFeatureFlags2 bufferFeatures; +} VkFormatProperties3; + +typedef struct VkPhysicalDeviceMaintenance4Features { + VkStructureType sType; + void* pNext; + VkBool32 maintenance4; +} VkPhysicalDeviceMaintenance4Features; + +typedef struct VkPhysicalDeviceMaintenance4Properties { + VkStructureType sType; + void* pNext; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceMaintenance4Properties; + +typedef struct VkDeviceBufferMemoryRequirements { + VkStructureType sType; + const void* pNext; + const VkBufferCreateInfo* pCreateInfo; +} VkDeviceBufferMemoryRequirements; + +typedef struct VkDeviceImageMemoryRequirements { + VkStructureType sType; + const void* pNext; + const VkImageCreateInfo* pCreateInfo; + VkImageAspectFlagBits planeAspect; +} VkDeviceImageMemoryRequirements; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolProperties)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolProperties* pToolProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlot)(VkDevice device, const VkPrivateDataSlotCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlot* pPrivateDataSlot); +typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlot)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); +typedef void (VKAPI_PTR *PFN_vkGetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t* pData); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, const VkDependencyInfo* pDependencyInfos); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2)(VkCommandBuffer commandBuffer, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2* pSubmits, VkFence fence); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2* pCopyBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2* pCopyImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2* pBlitImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2* pResolveImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRendering)(VkCommandBuffer commandBuffer, const VkRenderingInfo* pRenderingInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRendering)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdSetCullMode)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetFrontFace)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveTopology)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWithCount)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissorWithCount)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers2)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes, const VkDeviceSize* pStrides); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthWriteEnable)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthCompareOp)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBoundsTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilTestEnable)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilOp)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizerDiscardEnable)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBiasEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartEnable)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); +typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirements)(VkDevice device, const VkDeviceBufferMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSparseMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceToolProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pToolCount, + VkPhysicalDeviceToolProperties* pToolProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePrivateDataSlot( + VkDevice device, + const VkPrivateDataSlotCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlot* pPrivateDataSlot); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPrivateDataSlot( + VkDevice device, + VkPrivateDataSlot privateDataSlot, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetPrivateData( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t data); + +VKAPI_ATTR void VKAPI_CALL vkGetPrivateData( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent2( + VkCommandBuffer commandBuffer, + VkEvent event, + const VkDependencyInfo* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent2( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags2 stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents2( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + const VkDependencyInfo* pDependencyInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier2( + VkCommandBuffer commandBuffer, + const VkDependencyInfo* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp2( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2 stage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit2( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo2* pSubmits, + VkFence fence); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer2( + VkCommandBuffer commandBuffer, + const VkCopyBufferInfo2* pCopyBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage2( + VkCommandBuffer commandBuffer, + const VkCopyImageInfo2* pCopyImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage2( + VkCommandBuffer commandBuffer, + const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer2( + VkCommandBuffer commandBuffer, + const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage2( + VkCommandBuffer commandBuffer, + const VkBlitImageInfo2* pBlitImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage2( + VkCommandBuffer commandBuffer, + const VkResolveImageInfo2* pResolveImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRendering( + VkCommandBuffer commandBuffer, + const VkRenderingInfo* pRenderingInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRendering( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCullMode( + VkCommandBuffer commandBuffer, + VkCullModeFlags cullMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetFrontFace( + VkCommandBuffer commandBuffer, + VkFrontFace frontFace); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveTopology( + VkCommandBuffer commandBuffer, + VkPrimitiveTopology primitiveTopology); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWithCount( + VkCommandBuffer commandBuffer, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissorWithCount( + VkCommandBuffer commandBuffer, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers2( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthWriteEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthWriteEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthCompareOp( + VkCommandBuffer commandBuffer, + VkCompareOp depthCompareOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBoundsTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthBoundsTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 stencilTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilOp( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizerDiscardEnable( + VkCommandBuffer commandBuffer, + VkBool32 rasterizerDiscardEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBiasEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthBiasEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveRestartEnable( + VkCommandBuffer commandBuffer, + VkBool32 primitiveRestartEnable); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceBufferMemoryRequirements( + VkDevice device, + const VkDeviceBufferMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageMemoryRequirements( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirements( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +#endif + + +// VK_KHR_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_surface 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) +#define VK_KHR_SURFACE_SPEC_VERSION 25 +#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" + +typedef enum VkPresentModeKHR { + VK_PRESENT_MODE_IMMEDIATE_KHR = 0, + VK_PRESENT_MODE_MAILBOX_KHR = 1, + VK_PRESENT_MODE_FIFO_KHR = 2, + VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, + VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPresentModeKHR; + +typedef enum VkColorSpaceKHR { + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, + VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, + VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104003, + VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, + VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, + VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, + VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, + VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, + VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, + VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010, + VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, + VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, + VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, + VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, + VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, + VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, + VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkColorSpaceKHR; + +typedef enum VkSurfaceTransformFlagBitsKHR { + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, + VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, + VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, + VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, + VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSurfaceTransformFlagBitsKHR; + +typedef enum VkCompositeAlphaFlagBitsKHR { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, + VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCompositeAlphaFlagBitsKHR; +typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; +typedef struct VkSurfaceCapabilitiesKHR { + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; +} VkSurfaceCapabilitiesKHR; + +typedef struct VkSurfaceFormatKHR { + VkFormat format; + VkColorSpaceKHR colorSpace; +} VkSurfaceFormatKHR; + +typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( + VkInstance instance, + VkSurfaceKHR surface, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32* pSupported); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormatKHR* pSurfaceFormats); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes); +#endif + + +// VK_KHR_swapchain is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_swapchain 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) +#define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 +#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" + +typedef enum VkSwapchainCreateFlagBitsKHR { + VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001, + VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, + VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 0x00000004, + VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT = 0x00000008, + VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSwapchainCreateFlagBitsKHR; +typedef VkFlags VkSwapchainCreateFlagsKHR; + +typedef enum VkDeviceGroupPresentModeFlagBitsKHR { + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, + VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, + VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, + VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDeviceGroupPresentModeFlagBitsKHR; +typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; +typedef struct VkSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainCreateFlagsKHR flags; + VkSurfaceKHR surface; + uint32_t minImageCount; + VkFormat imageFormat; + VkColorSpaceKHR imageColorSpace; + VkExtent2D imageExtent; + uint32_t imageArrayLayers; + VkImageUsageFlags imageUsage; + VkSharingMode imageSharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkSurfaceTransformFlagBitsKHR preTransform; + VkCompositeAlphaFlagBitsKHR compositeAlpha; + VkPresentModeKHR presentMode; + VkBool32 clipped; + VkSwapchainKHR oldSwapchain; +} VkSwapchainCreateInfoKHR; + +typedef struct VkPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t swapchainCount; + const VkSwapchainKHR* pSwapchains; + const uint32_t* pImageIndices; + VkResult* pResults; +} VkPresentInfoKHR; + +typedef struct VkImageSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; +} VkImageSwapchainCreateInfoKHR; + +typedef struct VkBindImageMemorySwapchainInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndex; +} VkBindImageMemorySwapchainInfoKHR; + +typedef struct VkAcquireNextImageInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint64_t timeout; + VkSemaphore semaphore; + VkFence fence; + uint32_t deviceMask; +} VkAcquireNextImageInfoKHR; + +typedef struct VkDeviceGroupPresentCapabilitiesKHR { + VkStructureType sType; + void* pNext; + uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE]; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupPresentCapabilitiesKHR; + +typedef struct VkDeviceGroupPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const uint32_t* pDeviceMasks; + VkDeviceGroupPresentModeFlagBitsKHR mode; +} VkDeviceGroupPresentInfoKHR; + +typedef struct VkDeviceGroupSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupSwapchainCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); +typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); +typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( + VkDevice device, + const VkSwapchainCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchain); + +VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( + VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pSwapchainImageCount, + VkImage* pSwapchainImages); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t timeout, + VkSemaphore semaphore, + VkFence fence, + uint32_t* pImageIndex); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( + VkQueue queue, + const VkPresentInfoKHR* pPresentInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR( + VkDevice device, + VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR( + VkDevice device, + VkSurfaceKHR surface, + VkDeviceGroupPresentModeFlagsKHR* pModes); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR( + VkDevice device, + const VkAcquireNextImageInfoKHR* pAcquireInfo, + uint32_t* pImageIndex); +#endif + + +// VK_KHR_display is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_display 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) +#define VK_KHR_DISPLAY_SPEC_VERSION 23 +#define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" +typedef VkFlags VkDisplayModeCreateFlagsKHR; + +typedef enum VkDisplayPlaneAlphaFlagBitsKHR { + VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, + VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDisplayPlaneAlphaFlagBitsKHR; +typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; +typedef struct VkDisplayModeParametersKHR { + VkExtent2D visibleRegion; + uint32_t refreshRate; +} VkDisplayModeParametersKHR; + +typedef struct VkDisplayModeCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeCreateFlagsKHR flags; + VkDisplayModeParametersKHR parameters; +} VkDisplayModeCreateInfoKHR; + +typedef struct VkDisplayModePropertiesKHR { + VkDisplayModeKHR displayMode; + VkDisplayModeParametersKHR parameters; +} VkDisplayModePropertiesKHR; + +typedef struct VkDisplayPlaneCapabilitiesKHR { + VkDisplayPlaneAlphaFlagsKHR supportedAlpha; + VkOffset2D minSrcPosition; + VkOffset2D maxSrcPosition; + VkExtent2D minSrcExtent; + VkExtent2D maxSrcExtent; + VkOffset2D minDstPosition; + VkOffset2D maxDstPosition; + VkExtent2D minDstExtent; + VkExtent2D maxDstExtent; +} VkDisplayPlaneCapabilitiesKHR; + +typedef struct VkDisplayPlanePropertiesKHR { + VkDisplayKHR currentDisplay; + uint32_t currentStackIndex; +} VkDisplayPlanePropertiesKHR; + +typedef struct VkDisplayPropertiesKHR { + VkDisplayKHR display; + const char* displayName; + VkExtent2D physicalDimensions; + VkExtent2D physicalResolution; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkBool32 planeReorderPossible; + VkBool32 persistentContent; +} VkDisplayPropertiesKHR; + +typedef struct VkDisplaySurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplaySurfaceCreateFlagsKHR flags; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkDisplaySurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlanePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( + VkPhysicalDevice physicalDevice, + uint32_t planeIndex, + uint32_t* pDisplayCount, + VkDisplayKHR* pDisplays); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDisplayModeKHR* pMode); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayModeKHR mode, + uint32_t planeIndex, + VkDisplayPlaneCapabilitiesKHR* pCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( + VkInstance instance, + const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +// VK_KHR_display_swapchain is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_display_swapchain 1 +#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 10 +#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" +typedef struct VkDisplayPresentInfoKHR { + VkStructureType sType; + const void* pNext; + VkRect2D srcRect; + VkRect2D dstRect; + VkBool32 persistent; +} VkDisplayPresentInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( + VkDevice device, + uint32_t swapchainCount, + const VkSwapchainCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchains); +#endif + + +// VK_KHR_sampler_mirror_clamp_to_edge is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_sampler_mirror_clamp_to_edge 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 3 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" + + +// VK_KHR_video_queue is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_queue 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkVideoSessionKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkVideoSessionParametersKHR) +#define VK_KHR_VIDEO_QUEUE_SPEC_VERSION 8 +#define VK_KHR_VIDEO_QUEUE_EXTENSION_NAME "VK_KHR_video_queue" + +typedef enum VkQueryResultStatusKHR { + VK_QUERY_RESULT_STATUS_ERROR_KHR = -1, + VK_QUERY_RESULT_STATUS_NOT_READY_KHR = 0, + VK_QUERY_RESULT_STATUS_COMPLETE_KHR = 1, + VK_QUERY_RESULT_STATUS_INSUFFICIENT_BITSTREAM_BUFFER_RANGE_KHR = -1000299000, + VK_QUERY_RESULT_STATUS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkQueryResultStatusKHR; + +typedef enum VkVideoCodecOperationFlagBitsKHR { + VK_VIDEO_CODEC_OPERATION_NONE_KHR = 0, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT = 0x00010000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_EXT = 0x00020000, +#endif + VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR = 0x00000001, + VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR = 0x00000002, + VK_VIDEO_CODEC_OPERATION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoCodecOperationFlagBitsKHR; +typedef VkFlags VkVideoCodecOperationFlagsKHR; + +typedef enum VkVideoChromaSubsamplingFlagBitsKHR { + VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_KHR = 0, + VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR = 0x00000001, + VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR = 0x00000002, + VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR = 0x00000004, + VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR = 0x00000008, + VK_VIDEO_CHROMA_SUBSAMPLING_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoChromaSubsamplingFlagBitsKHR; +typedef VkFlags VkVideoChromaSubsamplingFlagsKHR; + +typedef enum VkVideoComponentBitDepthFlagBitsKHR { + VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR = 0, + VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR = 0x00000001, + VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR = 0x00000004, + VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR = 0x00000010, + VK_VIDEO_COMPONENT_BIT_DEPTH_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoComponentBitDepthFlagBitsKHR; +typedef VkFlags VkVideoComponentBitDepthFlagsKHR; + +typedef enum VkVideoCapabilityFlagBitsKHR { + VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR = 0x00000001, + VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR = 0x00000002, + VK_VIDEO_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoCapabilityFlagBitsKHR; +typedef VkFlags VkVideoCapabilityFlagsKHR; + +typedef enum VkVideoSessionCreateFlagBitsKHR { + VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR = 0x00000001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_PARAMETER_OPTIMIZATIONS_BIT_KHR = 0x00000002, +#endif + VK_VIDEO_SESSION_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoSessionCreateFlagBitsKHR; +typedef VkFlags VkVideoSessionCreateFlagsKHR; +typedef VkFlags VkVideoSessionParametersCreateFlagsKHR; +typedef VkFlags VkVideoBeginCodingFlagsKHR; +typedef VkFlags VkVideoEndCodingFlagsKHR; + +typedef enum VkVideoCodingControlFlagBitsKHR { + VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR = 0x00000001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_VIDEO_CODING_CONTROL_ENCODE_RATE_CONTROL_BIT_KHR = 0x00000002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_VIDEO_CODING_CONTROL_ENCODE_QUALITY_LEVEL_BIT_KHR = 0x00000004, +#endif + VK_VIDEO_CODING_CONTROL_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoCodingControlFlagBitsKHR; +typedef VkFlags VkVideoCodingControlFlagsKHR; +typedef struct VkQueueFamilyQueryResultStatusPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 queryResultStatusSupport; +} VkQueueFamilyQueryResultStatusPropertiesKHR; + +typedef struct VkQueueFamilyVideoPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoCodecOperationFlagsKHR videoCodecOperations; +} VkQueueFamilyVideoPropertiesKHR; + +typedef struct VkVideoProfileInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoCodecOperationFlagBitsKHR videoCodecOperation; + VkVideoChromaSubsamplingFlagsKHR chromaSubsampling; + VkVideoComponentBitDepthFlagsKHR lumaBitDepth; + VkVideoComponentBitDepthFlagsKHR chromaBitDepth; +} VkVideoProfileInfoKHR; + +typedef struct VkVideoProfileListInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t profileCount; + const VkVideoProfileInfoKHR* pProfiles; +} VkVideoProfileListInfoKHR; + +typedef struct VkVideoCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoCapabilityFlagsKHR flags; + VkDeviceSize minBitstreamBufferOffsetAlignment; + VkDeviceSize minBitstreamBufferSizeAlignment; + VkExtent2D pictureAccessGranularity; + VkExtent2D minCodedExtent; + VkExtent2D maxCodedExtent; + uint32_t maxDpbSlots; + uint32_t maxActiveReferencePictures; + VkExtensionProperties stdHeaderVersion; +} VkVideoCapabilitiesKHR; + +typedef struct VkPhysicalDeviceVideoFormatInfoKHR { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags imageUsage; +} VkPhysicalDeviceVideoFormatInfoKHR; + +typedef struct VkVideoFormatPropertiesKHR { + VkStructureType sType; + void* pNext; + VkFormat format; + VkComponentMapping componentMapping; + VkImageCreateFlags imageCreateFlags; + VkImageType imageType; + VkImageTiling imageTiling; + VkImageUsageFlags imageUsageFlags; +} VkVideoFormatPropertiesKHR; + +typedef struct VkVideoPictureResourceInfoKHR { + VkStructureType sType; + const void* pNext; + VkOffset2D codedOffset; + VkExtent2D codedExtent; + uint32_t baseArrayLayer; + VkImageView imageViewBinding; +} VkVideoPictureResourceInfoKHR; + +typedef struct VkVideoReferenceSlotInfoKHR { + VkStructureType sType; + const void* pNext; + int32_t slotIndex; + const VkVideoPictureResourceInfoKHR* pPictureResource; +} VkVideoReferenceSlotInfoKHR; + +typedef struct VkVideoSessionMemoryRequirementsKHR { + VkStructureType sType; + void* pNext; + uint32_t memoryBindIndex; + VkMemoryRequirements memoryRequirements; +} VkVideoSessionMemoryRequirementsKHR; + +typedef struct VkBindVideoSessionMemoryInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t memoryBindIndex; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkDeviceSize memorySize; +} VkBindVideoSessionMemoryInfoKHR; + +typedef struct VkVideoSessionCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t queueFamilyIndex; + VkVideoSessionCreateFlagsKHR flags; + const VkVideoProfileInfoKHR* pVideoProfile; + VkFormat pictureFormat; + VkExtent2D maxCodedExtent; + VkFormat referencePictureFormat; + uint32_t maxDpbSlots; + uint32_t maxActiveReferencePictures; + const VkExtensionProperties* pStdHeaderVersion; +} VkVideoSessionCreateInfoKHR; + +typedef struct VkVideoSessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoSessionParametersCreateFlagsKHR flags; + VkVideoSessionParametersKHR videoSessionParametersTemplate; + VkVideoSessionKHR videoSession; +} VkVideoSessionParametersCreateInfoKHR; + +typedef struct VkVideoSessionParametersUpdateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t updateSequenceCount; +} VkVideoSessionParametersUpdateInfoKHR; + +typedef struct VkVideoBeginCodingInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoBeginCodingFlagsKHR flags; + VkVideoSessionKHR videoSession; + VkVideoSessionParametersKHR videoSessionParameters; + uint32_t referenceSlotCount; + const VkVideoReferenceSlotInfoKHR* pReferenceSlots; +} VkVideoBeginCodingInfoKHR; + +typedef struct VkVideoEndCodingInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEndCodingFlagsKHR flags; +} VkVideoEndCodingInfoKHR; + +typedef struct VkVideoCodingControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoCodingControlFlagsKHR flags; +} VkVideoCodingControlInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceVideoCapabilitiesKHR)(VkPhysicalDevice physicalDevice, const VkVideoProfileInfoKHR* pVideoProfile, VkVideoCapabilitiesKHR* pCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceVideoFormatPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoFormatInfoKHR* pVideoFormatInfo, uint32_t* pVideoFormatPropertyCount, VkVideoFormatPropertiesKHR* pVideoFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateVideoSessionKHR)(VkDevice device, const VkVideoSessionCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkVideoSessionKHR* pVideoSession); +typedef void (VKAPI_PTR *PFN_vkDestroyVideoSessionKHR)(VkDevice device, VkVideoSessionKHR videoSession, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetVideoSessionMemoryRequirementsKHR)(VkDevice device, VkVideoSessionKHR videoSession, uint32_t* pMemoryRequirementsCount, VkVideoSessionMemoryRequirementsKHR* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindVideoSessionMemoryKHR)(VkDevice device, VkVideoSessionKHR videoSession, uint32_t bindSessionMemoryInfoCount, const VkBindVideoSessionMemoryInfoKHR* pBindSessionMemoryInfos); +typedef VkResult (VKAPI_PTR *PFN_vkCreateVideoSessionParametersKHR)(VkDevice device, const VkVideoSessionParametersCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkVideoSessionParametersKHR* pVideoSessionParameters); +typedef VkResult (VKAPI_PTR *PFN_vkUpdateVideoSessionParametersKHR)(VkDevice device, VkVideoSessionParametersKHR videoSessionParameters, const VkVideoSessionParametersUpdateInfoKHR* pUpdateInfo); +typedef void (VKAPI_PTR *PFN_vkDestroyVideoSessionParametersKHR)(VkDevice device, VkVideoSessionParametersKHR videoSessionParameters, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdBeginVideoCodingKHR)(VkCommandBuffer commandBuffer, const VkVideoBeginCodingInfoKHR* pBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndVideoCodingKHR)(VkCommandBuffer commandBuffer, const VkVideoEndCodingInfoKHR* pEndCodingInfo); +typedef void (VKAPI_PTR *PFN_vkCmdControlVideoCodingKHR)(VkCommandBuffer commandBuffer, const VkVideoCodingControlInfoKHR* pCodingControlInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceVideoCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + const VkVideoProfileInfoKHR* pVideoProfile, + VkVideoCapabilitiesKHR* pCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceVideoFormatPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceVideoFormatInfoKHR* pVideoFormatInfo, + uint32_t* pVideoFormatPropertyCount, + VkVideoFormatPropertiesKHR* pVideoFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateVideoSessionKHR( + VkDevice device, + const VkVideoSessionCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkVideoSessionKHR* pVideoSession); + +VKAPI_ATTR void VKAPI_CALL vkDestroyVideoSessionKHR( + VkDevice device, + VkVideoSessionKHR videoSession, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetVideoSessionMemoryRequirementsKHR( + VkDevice device, + VkVideoSessionKHR videoSession, + uint32_t* pMemoryRequirementsCount, + VkVideoSessionMemoryRequirementsKHR* pMemoryRequirements); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindVideoSessionMemoryKHR( + VkDevice device, + VkVideoSessionKHR videoSession, + uint32_t bindSessionMemoryInfoCount, + const VkBindVideoSessionMemoryInfoKHR* pBindSessionMemoryInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateVideoSessionParametersKHR( + VkDevice device, + const VkVideoSessionParametersCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkVideoSessionParametersKHR* pVideoSessionParameters); + +VKAPI_ATTR VkResult VKAPI_CALL vkUpdateVideoSessionParametersKHR( + VkDevice device, + VkVideoSessionParametersKHR videoSessionParameters, + const VkVideoSessionParametersUpdateInfoKHR* pUpdateInfo); + +VKAPI_ATTR void VKAPI_CALL vkDestroyVideoSessionParametersKHR( + VkDevice device, + VkVideoSessionParametersKHR videoSessionParameters, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginVideoCodingKHR( + VkCommandBuffer commandBuffer, + const VkVideoBeginCodingInfoKHR* pBeginInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndVideoCodingKHR( + VkCommandBuffer commandBuffer, + const VkVideoEndCodingInfoKHR* pEndCodingInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdControlVideoCodingKHR( + VkCommandBuffer commandBuffer, + const VkVideoCodingControlInfoKHR* pCodingControlInfo); +#endif + + +// VK_KHR_video_decode_queue is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_queue 1 +#define VK_KHR_VIDEO_DECODE_QUEUE_SPEC_VERSION 7 +#define VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME "VK_KHR_video_decode_queue" + +typedef enum VkVideoDecodeCapabilityFlagBitsKHR { + VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR = 0x00000001, + VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR = 0x00000002, + VK_VIDEO_DECODE_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoDecodeCapabilityFlagBitsKHR; +typedef VkFlags VkVideoDecodeCapabilityFlagsKHR; + +typedef enum VkVideoDecodeUsageFlagBitsKHR { + VK_VIDEO_DECODE_USAGE_DEFAULT_KHR = 0, + VK_VIDEO_DECODE_USAGE_TRANSCODING_BIT_KHR = 0x00000001, + VK_VIDEO_DECODE_USAGE_OFFLINE_BIT_KHR = 0x00000002, + VK_VIDEO_DECODE_USAGE_STREAMING_BIT_KHR = 0x00000004, + VK_VIDEO_DECODE_USAGE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoDecodeUsageFlagBitsKHR; +typedef VkFlags VkVideoDecodeUsageFlagsKHR; +typedef VkFlags VkVideoDecodeFlagsKHR; +typedef struct VkVideoDecodeCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoDecodeCapabilityFlagsKHR flags; +} VkVideoDecodeCapabilitiesKHR; + +typedef struct VkVideoDecodeUsageInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoDecodeUsageFlagsKHR videoUsageHints; +} VkVideoDecodeUsageInfoKHR; + +typedef struct VkVideoDecodeInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoDecodeFlagsKHR flags; + VkBuffer srcBuffer; + VkDeviceSize srcBufferOffset; + VkDeviceSize srcBufferRange; + VkVideoPictureResourceInfoKHR dstPictureResource; + const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot; + uint32_t referenceSlotCount; + const VkVideoReferenceSlotInfoKHR* pReferenceSlots; +} VkVideoDecodeInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdDecodeVideoKHR)(VkCommandBuffer commandBuffer, const VkVideoDecodeInfoKHR* pDecodeInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDecodeVideoKHR( + VkCommandBuffer commandBuffer, + const VkVideoDecodeInfoKHR* pDecodeInfo); +#endif + + +// VK_KHR_video_decode_h264 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_h264 1 +#include "vk_video/vulkan_video_codec_h264std.h" +#include "vk_video/vulkan_video_codec_h264std_decode.h" +#define VK_KHR_VIDEO_DECODE_H264_SPEC_VERSION 8 +#define VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME "VK_KHR_video_decode_h264" + +typedef enum VkVideoDecodeH264PictureLayoutFlagBitsKHR { + VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR = 0, + VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_KHR = 0x00000001, + VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_SEPARATE_PLANES_BIT_KHR = 0x00000002, + VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoDecodeH264PictureLayoutFlagBitsKHR; +typedef VkFlags VkVideoDecodeH264PictureLayoutFlagsKHR; +typedef struct VkVideoDecodeH264ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoH264ProfileIdc stdProfileIdc; + VkVideoDecodeH264PictureLayoutFlagBitsKHR pictureLayout; +} VkVideoDecodeH264ProfileInfoKHR; + +typedef struct VkVideoDecodeH264CapabilitiesKHR { + VkStructureType sType; + void* pNext; + StdVideoH264LevelIdc maxLevelIdc; + VkOffset2D fieldOffsetGranularity; +} VkVideoDecodeH264CapabilitiesKHR; + +typedef struct VkVideoDecodeH264SessionParametersAddInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t stdSPSCount; + const StdVideoH264SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH264PictureParameterSet* pStdPPSs; +} VkVideoDecodeH264SessionParametersAddInfoKHR; + +typedef struct VkVideoDecodeH264SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoDecodeH264SessionParametersAddInfoKHR* pParametersAddInfo; +} VkVideoDecodeH264SessionParametersCreateInfoKHR; + +typedef struct VkVideoDecodeH264PictureInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeH264PictureInfo* pStdPictureInfo; + uint32_t sliceCount; + const uint32_t* pSliceOffsets; +} VkVideoDecodeH264PictureInfoKHR; + +typedef struct VkVideoDecodeH264DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeH264ReferenceInfo* pStdReferenceInfo; +} VkVideoDecodeH264DpbSlotInfoKHR; + + + +// VK_KHR_dynamic_rendering is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_dynamic_rendering 1 +#define VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME "VK_KHR_dynamic_rendering" +typedef VkRenderingFlags VkRenderingFlagsKHR; + +typedef VkRenderingFlagBits VkRenderingFlagBitsKHR; + +typedef VkRenderingInfo VkRenderingInfoKHR; + +typedef VkRenderingAttachmentInfo VkRenderingAttachmentInfoKHR; + +typedef VkPipelineRenderingCreateInfo VkPipelineRenderingCreateInfoKHR; + +typedef VkPhysicalDeviceDynamicRenderingFeatures VkPhysicalDeviceDynamicRenderingFeaturesKHR; + +typedef VkCommandBufferInheritanceRenderingInfo VkCommandBufferInheritanceRenderingInfoKHR; + +typedef struct VkRenderingFragmentShadingRateAttachmentInfoKHR { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkExtent2D shadingRateAttachmentTexelSize; +} VkRenderingFragmentShadingRateAttachmentInfoKHR; + +typedef struct VkRenderingFragmentDensityMapAttachmentInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; +} VkRenderingFragmentDensityMapAttachmentInfoEXT; + +typedef struct VkAttachmentSampleCountInfoAMD { + VkStructureType sType; + const void* pNext; + uint32_t colorAttachmentCount; + const VkSampleCountFlagBits* pColorAttachmentSamples; + VkSampleCountFlagBits depthStencilAttachmentSamples; +} VkAttachmentSampleCountInfoAMD; + +typedef VkAttachmentSampleCountInfoAMD VkAttachmentSampleCountInfoNV; + +typedef struct VkMultiviewPerViewAttributesInfoNVX { + VkStructureType sType; + const void* pNext; + VkBool32 perViewAttributes; + VkBool32 perViewAttributesPositionXOnly; +} VkMultiviewPerViewAttributesInfoNVX; + +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderingKHR)(VkCommandBuffer commandBuffer, const VkRenderingInfo* pRenderingInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderingKHR)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderingKHR( + VkCommandBuffer commandBuffer, + const VkRenderingInfo* pRenderingInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderingKHR( + VkCommandBuffer commandBuffer); +#endif + + +// VK_KHR_multiview is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_multiview 1 +#define VK_KHR_MULTIVIEW_SPEC_VERSION 1 +#define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" +typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR; + +typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; + +typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR; + + + +// VK_KHR_get_physical_device_properties2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_get_physical_device_properties2 1 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 2 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" +typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; + +typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR; + +typedef VkFormatProperties2 VkFormatProperties2KHR; + +typedef VkImageFormatProperties2 VkImageFormatProperties2KHR; + +typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; + +typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; + +typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR; + +typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; + +typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2* pMemoryProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties2* pProperties); +#endif + + +// VK_KHR_device_group is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_device_group 1 +#define VK_KHR_DEVICE_GROUP_SPEC_VERSION 4 +#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" +typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR; + +typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; + +typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR; + +typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; + +typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; + +typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR; + +typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR; + +typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR; + +typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR; + +typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR; + +typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHR( + VkCommandBuffer commandBuffer, + uint32_t deviceMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR( + VkCommandBuffer commandBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); +#endif + + +// VK_KHR_shader_draw_parameters is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_draw_parameters 1 +#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 +#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" + + +// VK_KHR_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance1 1 +#define VK_KHR_MAINTENANCE_1_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_maintenance1" +#define VK_KHR_MAINTENANCE1_SPEC_VERSION VK_KHR_MAINTENANCE_1_SPEC_VERSION +#define VK_KHR_MAINTENANCE1_EXTENSION_NAME VK_KHR_MAINTENANCE_1_EXTENSION_NAME +typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; + +typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlags flags); +#endif + + +// VK_KHR_device_group_creation is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_device_group_creation 1 +#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 +#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" +#define VK_MAX_DEVICE_GROUP_SIZE_KHR VK_MAX_DEVICE_GROUP_SIZE +typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; + +typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +#endif + + +// VK_KHR_external_memory_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_memory_capabilities 1 +#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" +#define VK_LUID_SIZE_KHR VK_LUID_SIZE +typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR; + +typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; + +typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR; + +typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; + +typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; + +typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR; + +typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; + +typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; + +typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR; + +typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties); +#endif + + +// VK_KHR_external_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_memory 1 +#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory" +#define VK_QUEUE_FAMILY_EXTERNAL_KHR VK_QUEUE_FAMILY_EXTERNAL +typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; + +typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; + +typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; + + + +// VK_KHR_external_memory_fd is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_memory_fd 1 +#define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd" +typedef struct VkImportMemoryFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + int fd; +} VkImportMemoryFdInfoKHR; + +typedef struct VkMemoryFdPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryFdPropertiesKHR; + +typedef struct VkMemoryGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR( + VkDevice device, + const VkMemoryGetFdInfoKHR* pGetFdInfo, + int* pFd); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + int fd, + VkMemoryFdPropertiesKHR* pMemoryFdProperties); +#endif + + +// VK_KHR_external_semaphore_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_semaphore_capabilities 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" +typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR; + +typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; + +typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR; + +typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; + +typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR; + +typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +#endif + + +// VK_KHR_external_semaphore is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_semaphore 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore" +typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR; + +typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; + +typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; + + + +// VK_KHR_external_semaphore_fd is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_semaphore_fd 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd" +typedef struct VkImportSemaphoreFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + int fd; +} VkImportSemaphoreFdInfoKHR; + +typedef struct VkSemaphoreGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHR( + VkDevice device, + const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR( + VkDevice device, + const VkSemaphoreGetFdInfoKHR* pGetFdInfo, + int* pFd); +#endif + + +// VK_KHR_push_descriptor is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_push_descriptor 1 +#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 +#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" +typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t maxPushDescriptors; +} VkPhysicalDevicePushDescriptorPropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t set, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( + VkCommandBuffer commandBuffer, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + VkPipelineLayout layout, + uint32_t set, + const void* pData); +#endif + + +// VK_KHR_shader_float16_int8 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_float16_int8 1 +#define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" +typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; + +typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; + + + +// VK_KHR_16bit_storage is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_16bit_storage 1 +#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" +typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; + + + +// VK_KHR_incremental_present is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_incremental_present 1 +#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 2 +#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" +typedef struct VkRectLayerKHR { + VkOffset2D offset; + VkExtent2D extent; + uint32_t layer; +} VkRectLayerKHR; + +typedef struct VkPresentRegionKHR { + uint32_t rectangleCount; + const VkRectLayerKHR* pRectangles; +} VkPresentRegionKHR; + +typedef struct VkPresentRegionsKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentRegionKHR* pRegions; +} VkPresentRegionsKHR; + + + +// VK_KHR_descriptor_update_template is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_descriptor_update_template 1 +typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR; + +#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 +#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" +typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; + +typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR; + +typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR; + +typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR( + VkDevice device, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR( + VkDevice device, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR( + VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void* pData); +#endif + + +// VK_KHR_imageless_framebuffer is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_imageless_framebuffer 1 +#define VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION 1 +#define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME "VK_KHR_imageless_framebuffer" +typedef VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; + +typedef VkFramebufferAttachmentsCreateInfo VkFramebufferAttachmentsCreateInfoKHR; + +typedef VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; + +typedef VkRenderPassAttachmentBeginInfo VkRenderPassAttachmentBeginInfoKHR; + + + +// VK_KHR_create_renderpass2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_create_renderpass2 1 +#define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 +#define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" +typedef VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; + +typedef VkAttachmentDescription2 VkAttachmentDescription2KHR; + +typedef VkAttachmentReference2 VkAttachmentReference2KHR; + +typedef VkSubpassDescription2 VkSubpassDescription2KHR; + +typedef VkSubpassDependency2 VkSubpassDependency2KHR; + +typedef VkSubpassBeginInfo VkSubpassBeginInfoKHR; + +typedef VkSubpassEndInfo VkSubpassEndInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2KHR( + VkDevice device, + const VkRenderPassCreateInfo2* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2KHR( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + const VkSubpassBeginInfo* pSubpassBeginInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2KHR( + VkCommandBuffer commandBuffer, + const VkSubpassBeginInfo* pSubpassBeginInfo, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2KHR( + VkCommandBuffer commandBuffer, + const VkSubpassEndInfo* pSubpassEndInfo); +#endif + + +// VK_KHR_shared_presentable_image is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shared_presentable_image 1 +#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 +#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" +typedef struct VkSharedPresentSurfaceCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkImageUsageFlags sharedPresentSupportedUsageFlags; +} VkSharedPresentSurfaceCapabilitiesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR( + VkDevice device, + VkSwapchainKHR swapchain); +#endif + + +// VK_KHR_external_fence_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_fence_capabilities 1 +#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" +typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR; + +typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; + +typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR; + +typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; + +typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR; + +typedef VkExternalFenceProperties VkExternalFencePropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties); +#endif + + +// VK_KHR_external_fence is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_fence 1 +#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" +typedef VkFenceImportFlags VkFenceImportFlagsKHR; + +typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR; + +typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; + + + +// VK_KHR_external_fence_fd is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_fence_fd 1 +#define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd" +typedef struct VkImportFenceFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + int fd; +} VkImportFenceFdInfoKHR; + +typedef struct VkFenceGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkExternalFenceHandleTypeFlagBits handleType; +} VkFenceGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceFdKHR( + VkDevice device, + const VkImportFenceFdInfoKHR* pImportFenceFdInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR( + VkDevice device, + const VkFenceGetFdInfoKHR* pGetFdInfo, + int* pFd); +#endif + + +// VK_KHR_performance_query is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_performance_query 1 +#define VK_KHR_PERFORMANCE_QUERY_SPEC_VERSION 1 +#define VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME "VK_KHR_performance_query" + +typedef enum VkPerformanceCounterUnitKHR { + VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR = 0, + VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR = 1, + VK_PERFORMANCE_COUNTER_UNIT_NANOSECONDS_KHR = 2, + VK_PERFORMANCE_COUNTER_UNIT_BYTES_KHR = 3, + VK_PERFORMANCE_COUNTER_UNIT_BYTES_PER_SECOND_KHR = 4, + VK_PERFORMANCE_COUNTER_UNIT_KELVIN_KHR = 5, + VK_PERFORMANCE_COUNTER_UNIT_WATTS_KHR = 6, + VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR = 7, + VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR = 8, + VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR = 9, + VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10, + VK_PERFORMANCE_COUNTER_UNIT_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterUnitKHR; + +typedef enum VkPerformanceCounterScopeKHR { + VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR = 0, + VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR = 1, + VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR = 2, + VK_QUERY_SCOPE_COMMAND_BUFFER_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR, + VK_QUERY_SCOPE_RENDER_PASS_KHR = VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR, + VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR, + VK_PERFORMANCE_COUNTER_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterScopeKHR; + +typedef enum VkPerformanceCounterStorageKHR { + VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR = 0, + VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR = 1, + VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR = 2, + VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR = 3, + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR = 4, + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5, + VK_PERFORMANCE_COUNTER_STORAGE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterStorageKHR; + +typedef enum VkPerformanceCounterDescriptionFlagBitsKHR { + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR = 0x00000001, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR = 0x00000002, + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterDescriptionFlagBitsKHR; +typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; + +typedef enum VkAcquireProfilingLockFlagBitsKHR { + VK_ACQUIRE_PROFILING_LOCK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAcquireProfilingLockFlagBitsKHR; +typedef VkFlags VkAcquireProfilingLockFlagsKHR; +typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 performanceCounterQueryPools; + VkBool32 performanceCounterMultipleQueryPools; +} VkPhysicalDevicePerformanceQueryFeaturesKHR; + +typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 allowCommandBufferQueryCopies; +} VkPhysicalDevicePerformanceQueryPropertiesKHR; + +typedef struct VkPerformanceCounterKHR { + VkStructureType sType; + void* pNext; + VkPerformanceCounterUnitKHR unit; + VkPerformanceCounterScopeKHR scope; + VkPerformanceCounterStorageKHR storage; + uint8_t uuid[VK_UUID_SIZE]; +} VkPerformanceCounterKHR; + +typedef struct VkPerformanceCounterDescriptionKHR { + VkStructureType sType; + void* pNext; + VkPerformanceCounterDescriptionFlagsKHR flags; + char name[VK_MAX_DESCRIPTION_SIZE]; + char category[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkPerformanceCounterDescriptionKHR; + +typedef struct VkQueryPoolPerformanceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t queueFamilyIndex; + uint32_t counterIndexCount; + const uint32_t* pCounterIndices; +} VkQueryPoolPerformanceCreateInfoKHR; + +typedef union VkPerformanceCounterResultKHR { + int32_t int32; + int64_t int64; + uint32_t uint32; + uint64_t uint64; + float float32; + double float64; +} VkPerformanceCounterResultKHR; + +typedef struct VkAcquireProfilingLockInfoKHR { + VkStructureType sType; + const void* pNext; + VkAcquireProfilingLockFlagsKHR flags; + uint64_t timeout; +} VkAcquireProfilingLockInfoKHR; + +typedef struct VkPerformanceQuerySubmitInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t counterPassIndex; +} VkPerformanceQuerySubmitInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t* pCounterCount, VkPerformanceCounterKHR* pCounters, VkPerformanceCounterDescriptionKHR* pCounterDescriptions); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)(VkPhysicalDevice physicalDevice, const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo, uint32_t* pNumPasses); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireProfilingLockKHR)(VkDevice device, const VkAcquireProfilingLockInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkReleaseProfilingLockKHR)(VkDevice device); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + uint32_t* pCounterCount, + VkPerformanceCounterKHR* pCounters, + VkPerformanceCounterDescriptionKHR* pCounterDescriptions); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR( + VkPhysicalDevice physicalDevice, + const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo, + uint32_t* pNumPasses); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireProfilingLockKHR( + VkDevice device, + const VkAcquireProfilingLockInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkReleaseProfilingLockKHR( + VkDevice device); +#endif + + +// VK_KHR_maintenance2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance2 1 +#define VK_KHR_MAINTENANCE_2_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_maintenance2" +#define VK_KHR_MAINTENANCE2_SPEC_VERSION VK_KHR_MAINTENANCE_2_SPEC_VERSION +#define VK_KHR_MAINTENANCE2_EXTENSION_NAME VK_KHR_MAINTENANCE_2_EXTENSION_NAME +typedef VkPointClippingBehavior VkPointClippingBehaviorKHR; + +typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR; + +typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; + +typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; + +typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; + +typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; + +typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR; + + + +// VK_KHR_get_surface_capabilities2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_get_surface_capabilities2 1 +#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" +typedef struct VkPhysicalDeviceSurfaceInfo2KHR { + VkStructureType sType; + const void* pNext; + VkSurfaceKHR surface; +} VkPhysicalDeviceSurfaceInfo2KHR; + +typedef struct VkSurfaceCapabilities2KHR { + VkStructureType sType; + void* pNext; + VkSurfaceCapabilitiesKHR surfaceCapabilities; +} VkSurfaceCapabilities2KHR; + +typedef struct VkSurfaceFormat2KHR { + VkStructureType sType; + void* pNext; + VkSurfaceFormatKHR surfaceFormat; +} VkSurfaceFormat2KHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + VkSurfaceCapabilities2KHR* pSurfaceCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormat2KHR* pSurfaceFormats); +#endif + + +// VK_KHR_variable_pointers is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_variable_pointers 1 +#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 +#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; + +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; + + + +// VK_KHR_get_display_properties2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_get_display_properties2 1 +#define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2" +typedef struct VkDisplayProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPropertiesKHR displayProperties; +} VkDisplayProperties2KHR; + +typedef struct VkDisplayPlaneProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPlanePropertiesKHR displayPlaneProperties; +} VkDisplayPlaneProperties2KHR; + +typedef struct VkDisplayModeProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayModePropertiesKHR displayModeProperties; +} VkDisplayModeProperties2KHR; + +typedef struct VkDisplayPlaneInfo2KHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeKHR mode; + uint32_t planeIndex; +} VkDisplayPlaneInfo2KHR; + +typedef struct VkDisplayPlaneCapabilities2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPlaneCapabilitiesKHR capabilities; +} VkDisplayPlaneCapabilities2KHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlaneProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModeProperties2KHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModeProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, VkDisplayPlaneCapabilities2KHR* pCapabilities); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlaneProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlaneProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModeProperties2KHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModeProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilities2KHR( + VkPhysicalDevice physicalDevice, + const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR* pCapabilities); +#endif + + +// VK_KHR_dedicated_allocation is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_dedicated_allocation 1 +#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 +#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" +typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; + +typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; + + + +// VK_KHR_storage_buffer_storage_class is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_storage_buffer_storage_class 1 +#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1 +#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class" + + +// VK_KHR_relaxed_block_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_relaxed_block_layout 1 +#define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" + + +// VK_KHR_get_memory_requirements2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_get_memory_requirements2 1 +#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1 +#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" +typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR; + +typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR; + +typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR; + +typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; + +typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; + +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR( + VkDevice device, + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR( + VkDevice device, + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +#endif + + +// VK_KHR_image_format_list is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_image_format_list 1 +#define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 +#define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" +typedef VkImageFormatListCreateInfo VkImageFormatListCreateInfoKHR; + + + +// VK_KHR_sampler_ycbcr_conversion is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_sampler_ycbcr_conversion 1 +typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR; + +#define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 14 +#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" +typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; + +typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; + +typedef VkChromaLocation VkChromaLocationKHR; + +typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; + +typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR; + +typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR; + +typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR; + +typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; + +typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSamplerYcbcrConversion* pYcbcrConversion); + +VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR( + VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks* pAllocator); +#endif + + +// VK_KHR_bind_memory2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_bind_memory2 1 +#define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 +#define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" +typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; + +typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR( + VkDevice device, + uint32_t bindInfoCount, + const VkBindBufferMemoryInfo* pBindInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR( + VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfo* pBindInfos); +#endif + + +// VK_KHR_maintenance3 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance3 1 +#define VK_KHR_MAINTENANCE_3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_3_EXTENSION_NAME "VK_KHR_maintenance3" +#define VK_KHR_MAINTENANCE3_SPEC_VERSION VK_KHR_MAINTENANCE_3_SPEC_VERSION +#define VK_KHR_MAINTENANCE3_EXTENSION_NAME VK_KHR_MAINTENANCE_3_EXTENSION_NAME +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; + +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport); +#endif + + +// VK_KHR_draw_indirect_count is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_draw_indirect_count 1 +#define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 +#define VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_KHR_draw_indirect_count" +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountKHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountKHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + + +// VK_KHR_shader_subgroup_extended_types is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_subgroup_extended_types 1 +#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_SPEC_VERSION 1 +#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME "VK_KHR_shader_subgroup_extended_types" +typedef VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; + + + +// VK_KHR_8bit_storage is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_8bit_storage 1 +#define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" +typedef VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; + + + +// VK_KHR_shader_atomic_int64 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_atomic_int64 1 +#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" +typedef VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; + + + +// VK_KHR_shader_clock is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_clock 1 +#define VK_KHR_SHADER_CLOCK_SPEC_VERSION 1 +#define VK_KHR_SHADER_CLOCK_EXTENSION_NAME "VK_KHR_shader_clock" +typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupClock; + VkBool32 shaderDeviceClock; +} VkPhysicalDeviceShaderClockFeaturesKHR; + + + +// VK_KHR_video_decode_h265 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_h265 1 +#include "vk_video/vulkan_video_codec_h265std.h" +#include "vk_video/vulkan_video_codec_h265std_decode.h" +#define VK_KHR_VIDEO_DECODE_H265_SPEC_VERSION 7 +#define VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME "VK_KHR_video_decode_h265" +typedef struct VkVideoDecodeH265ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoH265ProfileIdc stdProfileIdc; +} VkVideoDecodeH265ProfileInfoKHR; + +typedef struct VkVideoDecodeH265CapabilitiesKHR { + VkStructureType sType; + void* pNext; + StdVideoH265LevelIdc maxLevelIdc; +} VkVideoDecodeH265CapabilitiesKHR; + +typedef struct VkVideoDecodeH265SessionParametersAddInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t stdVPSCount; + const StdVideoH265VideoParameterSet* pStdVPSs; + uint32_t stdSPSCount; + const StdVideoH265SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH265PictureParameterSet* pStdPPSs; +} VkVideoDecodeH265SessionParametersAddInfoKHR; + +typedef struct VkVideoDecodeH265SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxStdVPSCount; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoDecodeH265SessionParametersAddInfoKHR* pParametersAddInfo; +} VkVideoDecodeH265SessionParametersCreateInfoKHR; + +typedef struct VkVideoDecodeH265PictureInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeH265PictureInfo* pStdPictureInfo; + uint32_t sliceSegmentCount; + const uint32_t* pSliceSegmentOffsets; +} VkVideoDecodeH265PictureInfoKHR; + +typedef struct VkVideoDecodeH265DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeH265ReferenceInfo* pStdReferenceInfo; +} VkVideoDecodeH265DpbSlotInfoKHR; + + + +// VK_KHR_global_priority is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_global_priority 1 +#define VK_MAX_GLOBAL_PRIORITY_SIZE_KHR 16U +#define VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION 1 +#define VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME "VK_KHR_global_priority" + +typedef enum VkQueueGlobalPriorityKHR { + VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR = 128, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR = 256, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR = 512, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR = 1024, + VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR, + VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_KHR = 0x7FFFFFFF +} VkQueueGlobalPriorityKHR; +typedef struct VkDeviceQueueGlobalPriorityCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkQueueGlobalPriorityKHR globalPriority; +} VkDeviceQueueGlobalPriorityCreateInfoKHR; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 globalPriorityQuery; +} VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR; + +typedef struct VkQueueFamilyGlobalPriorityPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t priorityCount; + VkQueueGlobalPriorityKHR priorities[VK_MAX_GLOBAL_PRIORITY_SIZE_KHR]; +} VkQueueFamilyGlobalPriorityPropertiesKHR; + + + +// VK_KHR_driver_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_driver_properties 1 +#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" +#define VK_MAX_DRIVER_NAME_SIZE_KHR VK_MAX_DRIVER_NAME_SIZE +#define VK_MAX_DRIVER_INFO_SIZE_KHR VK_MAX_DRIVER_INFO_SIZE +typedef VkDriverId VkDriverIdKHR; + +typedef VkConformanceVersion VkConformanceVersionKHR; + +typedef VkPhysicalDeviceDriverProperties VkPhysicalDeviceDriverPropertiesKHR; + + + +// VK_KHR_shader_float_controls is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_float_controls 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 4 +#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" +typedef VkShaderFloatControlsIndependence VkShaderFloatControlsIndependenceKHR; + +typedef VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; + + + +// VK_KHR_depth_stencil_resolve is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_depth_stencil_resolve 1 +#define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 +#define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" +typedef VkResolveModeFlagBits VkResolveModeFlagBitsKHR; + +typedef VkResolveModeFlags VkResolveModeFlagsKHR; + +typedef VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; + +typedef VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; + + + +// VK_KHR_swapchain_mutable_format is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_swapchain_mutable_format 1 +#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 +#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" + + +// VK_KHR_timeline_semaphore is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_timeline_semaphore 1 +#define VK_KHR_TIMELINE_SEMAPHORE_SPEC_VERSION 2 +#define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME "VK_KHR_timeline_semaphore" +typedef VkSemaphoreType VkSemaphoreTypeKHR; + +typedef VkSemaphoreWaitFlagBits VkSemaphoreWaitFlagBitsKHR; + +typedef VkSemaphoreWaitFlags VkSemaphoreWaitFlagsKHR; + +typedef VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; + +typedef VkPhysicalDeviceTimelineSemaphoreProperties VkPhysicalDeviceTimelineSemaphorePropertiesKHR; + +typedef VkSemaphoreTypeCreateInfo VkSemaphoreTypeCreateInfoKHR; + +typedef VkTimelineSemaphoreSubmitInfo VkTimelineSemaphoreSubmitInfoKHR; + +typedef VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; + +typedef VkSemaphoreSignalInfo VkSemaphoreSignalInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValueKHR)(VkDevice device, VkSemaphore semaphore, uint64_t* pValue); +typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphoresKHR)(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphoreKHR)(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreCounterValueKHR( + VkDevice device, + VkSemaphore semaphore, + uint64_t* pValue); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitSemaphoresKHR( + VkDevice device, + const VkSemaphoreWaitInfo* pWaitInfo, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkSignalSemaphoreKHR( + VkDevice device, + const VkSemaphoreSignalInfo* pSignalInfo); +#endif + + +// VK_KHR_vulkan_memory_model is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_vulkan_memory_model 1 +#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 3 +#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" +typedef VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; + + + +// VK_KHR_shader_terminate_invocation is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_terminate_invocation 1 +#define VK_KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION 1 +#define VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME "VK_KHR_shader_terminate_invocation" +typedef VkPhysicalDeviceShaderTerminateInvocationFeatures VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR; + + + +// VK_KHR_fragment_shading_rate is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_fragment_shading_rate 1 +#define VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION 2 +#define VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME "VK_KHR_fragment_shading_rate" + +typedef enum VkFragmentShadingRateCombinerOpKHR { + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR = 0, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR = 1, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR = 2, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR = 3, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR = 4, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_ENUM_KHR = 0x7FFFFFFF +} VkFragmentShadingRateCombinerOpKHR; +typedef struct VkFragmentShadingRateAttachmentInfoKHR { + VkStructureType sType; + const void* pNext; + const VkAttachmentReference2* pFragmentShadingRateAttachment; + VkExtent2D shadingRateAttachmentTexelSize; +} VkFragmentShadingRateAttachmentInfoKHR; + +typedef struct VkPipelineFragmentShadingRateStateCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkExtent2D fragmentSize; + VkFragmentShadingRateCombinerOpKHR combinerOps[2]; +} VkPipelineFragmentShadingRateStateCreateInfoKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRateFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 pipelineFragmentShadingRate; + VkBool32 primitiveFragmentShadingRate; + VkBool32 attachmentFragmentShadingRate; +} VkPhysicalDeviceFragmentShadingRateFeaturesKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR { + VkStructureType sType; + void* pNext; + VkExtent2D minFragmentShadingRateAttachmentTexelSize; + VkExtent2D maxFragmentShadingRateAttachmentTexelSize; + uint32_t maxFragmentShadingRateAttachmentTexelSizeAspectRatio; + VkBool32 primitiveFragmentShadingRateWithMultipleViewports; + VkBool32 layeredShadingRateAttachments; + VkBool32 fragmentShadingRateNonTrivialCombinerOps; + VkExtent2D maxFragmentSize; + uint32_t maxFragmentSizeAspectRatio; + uint32_t maxFragmentShadingRateCoverageSamples; + VkSampleCountFlagBits maxFragmentShadingRateRasterizationSamples; + VkBool32 fragmentShadingRateWithShaderDepthStencilWrites; + VkBool32 fragmentShadingRateWithSampleMask; + VkBool32 fragmentShadingRateWithShaderSampleMask; + VkBool32 fragmentShadingRateWithConservativeRasterization; + VkBool32 fragmentShadingRateWithFragmentShaderInterlock; + VkBool32 fragmentShadingRateWithCustomSampleLocations; + VkBool32 fragmentShadingRateStrictMultiplyCombiner; +} VkPhysicalDeviceFragmentShadingRatePropertiesKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRateKHR { + VkStructureType sType; + void* pNext; + VkSampleCountFlags sampleCounts; + VkExtent2D fragmentSize; +} VkPhysicalDeviceFragmentShadingRateKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR* pFragmentShadingRates); +typedef void (VKAPI_PTR *PFN_vkCmdSetFragmentShadingRateKHR)(VkCommandBuffer commandBuffer, const VkExtent2D* pFragmentSize, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceFragmentShadingRatesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pFragmentShadingRateCount, + VkPhysicalDeviceFragmentShadingRateKHR* pFragmentShadingRates); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetFragmentShadingRateKHR( + VkCommandBuffer commandBuffer, + const VkExtent2D* pFragmentSize, + const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); +#endif + + +// VK_KHR_spirv_1_4 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_spirv_1_4 1 +#define VK_KHR_SPIRV_1_4_SPEC_VERSION 1 +#define VK_KHR_SPIRV_1_4_EXTENSION_NAME "VK_KHR_spirv_1_4" + + +// VK_KHR_surface_protected_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_surface_protected_capabilities 1 +#define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME "VK_KHR_surface_protected_capabilities" +typedef struct VkSurfaceProtectedCapabilitiesKHR { + VkStructureType sType; + const void* pNext; + VkBool32 supportsProtected; +} VkSurfaceProtectedCapabilitiesKHR; + + + +// VK_KHR_separate_depth_stencil_layouts is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_separate_depth_stencil_layouts 1 +#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION 1 +#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME "VK_KHR_separate_depth_stencil_layouts" +typedef VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; + +typedef VkAttachmentReferenceStencilLayout VkAttachmentReferenceStencilLayoutKHR; + +typedef VkAttachmentDescriptionStencilLayout VkAttachmentDescriptionStencilLayoutKHR; + + + +// VK_KHR_present_wait is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_present_wait 1 +#define VK_KHR_PRESENT_WAIT_SPEC_VERSION 1 +#define VK_KHR_PRESENT_WAIT_EXTENSION_NAME "VK_KHR_present_wait" +typedef struct VkPhysicalDevicePresentWaitFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 presentWait; +} VkPhysicalDevicePresentWaitFeaturesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkWaitForPresentKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t presentId, uint64_t timeout); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkWaitForPresentKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t presentId, + uint64_t timeout); +#endif + + +// VK_KHR_uniform_buffer_standard_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_uniform_buffer_standard_layout 1 +#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout" +typedef VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; + + + +// VK_KHR_buffer_device_address is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_buffer_device_address 1 +#define VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 1 +#define VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_KHR_buffer_device_address" +typedef VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; + +typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoKHR; + +typedef VkBufferOpaqueCaptureAddressCreateInfo VkBufferOpaqueCaptureAddressCreateInfoKHR; + +typedef VkMemoryOpaqueCaptureAddressAllocateInfo VkMemoryOpaqueCaptureAddressAllocateInfoKHR; + +typedef VkDeviceMemoryOpaqueCaptureAddressInfo VkDeviceMemoryOpaqueCaptureAddressInfoKHR; + +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressKHR( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddressKHR( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddressKHR( + VkDevice device, + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); +#endif + + +// VK_KHR_deferred_host_operations is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_deferred_host_operations 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) +#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 4 +#define VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME "VK_KHR_deferred_host_operations" +typedef VkResult (VKAPI_PTR *PFN_vkCreateDeferredOperationKHR)(VkDevice device, const VkAllocationCallbacks* pAllocator, VkDeferredOperationKHR* pDeferredOperation); +typedef void (VKAPI_PTR *PFN_vkDestroyDeferredOperationKHR)(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks* pAllocator); +typedef uint32_t (VKAPI_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeferredOperationResultKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (VKAPI_PTR *PFN_vkDeferredOperationJoinKHR)(VkDevice device, VkDeferredOperationKHR operation); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDeferredOperationKHR( + VkDevice device, + const VkAllocationCallbacks* pAllocator, + VkDeferredOperationKHR* pDeferredOperation); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDeferredOperationKHR( + VkDevice device, + VkDeferredOperationKHR operation, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR uint32_t VKAPI_CALL vkGetDeferredOperationMaxConcurrencyKHR( + VkDevice device, + VkDeferredOperationKHR operation); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeferredOperationResultKHR( + VkDevice device, + VkDeferredOperationKHR operation); + +VKAPI_ATTR VkResult VKAPI_CALL vkDeferredOperationJoinKHR( + VkDevice device, + VkDeferredOperationKHR operation); +#endif + + +// VK_KHR_pipeline_executable_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_pipeline_executable_properties 1 +#define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME "VK_KHR_pipeline_executable_properties" + +typedef enum VkPipelineExecutableStatisticFormatKHR { + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR = 0, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR = 1, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR = 2, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPipelineExecutableStatisticFormatKHR; +typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 pipelineExecutableInfo; +} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR; + +typedef struct VkPipelineInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipeline pipeline; +} VkPipelineInfoKHR; + +typedef struct VkPipelineExecutablePropertiesKHR { + VkStructureType sType; + void* pNext; + VkShaderStageFlags stages; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + uint32_t subgroupSize; +} VkPipelineExecutablePropertiesKHR; + +typedef struct VkPipelineExecutableInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipeline pipeline; + uint32_t executableIndex; +} VkPipelineExecutableInfoKHR; + +typedef union VkPipelineExecutableStatisticValueKHR { + VkBool32 b32; + int64_t i64; + uint64_t u64; + double f64; +} VkPipelineExecutableStatisticValueKHR; + +typedef struct VkPipelineExecutableStatisticKHR { + VkStructureType sType; + void* pNext; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkPipelineExecutableStatisticFormatKHR format; + VkPipelineExecutableStatisticValueKHR value; +} VkPipelineExecutableStatisticKHR; + +typedef struct VkPipelineExecutableInternalRepresentationKHR { + VkStructureType sType; + void* pNext; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkBool32 isText; + size_t dataSize; + void* pData; +} VkPipelineExecutableInternalRepresentationKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutablePropertiesKHR)(VkDevice device, const VkPipelineInfoKHR* pPipelineInfo, uint32_t* pExecutableCount, VkPipelineExecutablePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutableStatisticsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR* pExecutableInfo, uint32_t* pStatisticCount, VkPipelineExecutableStatisticKHR* pStatistics); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutableInternalRepresentationsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR* pExecutableInfo, uint32_t* pInternalRepresentationCount, VkPipelineExecutableInternalRepresentationKHR* pInternalRepresentations); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutablePropertiesKHR( + VkDevice device, + const VkPipelineInfoKHR* pPipelineInfo, + uint32_t* pExecutableCount, + VkPipelineExecutablePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableStatisticsKHR( + VkDevice device, + const VkPipelineExecutableInfoKHR* pExecutableInfo, + uint32_t* pStatisticCount, + VkPipelineExecutableStatisticKHR* pStatistics); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableInternalRepresentationsKHR( + VkDevice device, + const VkPipelineExecutableInfoKHR* pExecutableInfo, + uint32_t* pInternalRepresentationCount, + VkPipelineExecutableInternalRepresentationKHR* pInternalRepresentations); +#endif + + +// VK_KHR_map_memory2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_map_memory2 1 +#define VK_KHR_MAP_MEMORY_2_SPEC_VERSION 1 +#define VK_KHR_MAP_MEMORY_2_EXTENSION_NAME "VK_KHR_map_memory2" +typedef VkFlags VkMemoryUnmapFlagsKHR; +typedef struct VkMemoryMapInfoKHR { + VkStructureType sType; + const void* pNext; + VkMemoryMapFlags flags; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMemoryMapInfoKHR; + +typedef struct VkMemoryUnmapInfoKHR { + VkStructureType sType; + const void* pNext; + VkMemoryUnmapFlagsKHR flags; + VkDeviceMemory memory; +} VkMemoryUnmapInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkMapMemory2KHR)(VkDevice device, const VkMemoryMapInfoKHR* pMemoryMapInfo, void** ppData); +typedef VkResult (VKAPI_PTR *PFN_vkUnmapMemory2KHR)(VkDevice device, const VkMemoryUnmapInfoKHR* pMemoryUnmapInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory2KHR( + VkDevice device, + const VkMemoryMapInfoKHR* pMemoryMapInfo, + void** ppData); + +VKAPI_ATTR VkResult VKAPI_CALL vkUnmapMemory2KHR( + VkDevice device, + const VkMemoryUnmapInfoKHR* pMemoryUnmapInfo); +#endif + + +// VK_KHR_shader_integer_dot_product is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_integer_dot_product 1 +#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION 1 +#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME "VK_KHR_shader_integer_dot_product" +typedef VkPhysicalDeviceShaderIntegerDotProductFeatures VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR; + +typedef VkPhysicalDeviceShaderIntegerDotProductProperties VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR; + + + +// VK_KHR_pipeline_library is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_pipeline_library 1 +#define VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME "VK_KHR_pipeline_library" +typedef struct VkPipelineLibraryCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t libraryCount; + const VkPipeline* pLibraries; +} VkPipelineLibraryCreateInfoKHR; + + + +// VK_KHR_shader_non_semantic_info is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_non_semantic_info 1 +#define VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION 1 +#define VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME "VK_KHR_shader_non_semantic_info" + + +// VK_KHR_present_id is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_present_id 1 +#define VK_KHR_PRESENT_ID_SPEC_VERSION 1 +#define VK_KHR_PRESENT_ID_EXTENSION_NAME "VK_KHR_present_id" +typedef struct VkPresentIdKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const uint64_t* pPresentIds; +} VkPresentIdKHR; + +typedef struct VkPhysicalDevicePresentIdFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 presentId; +} VkPhysicalDevicePresentIdFeaturesKHR; + + + +// VK_KHR_synchronization2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_synchronization2 1 +#define VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION 1 +#define VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME "VK_KHR_synchronization2" +typedef VkPipelineStageFlags2 VkPipelineStageFlags2KHR; + +typedef VkPipelineStageFlagBits2 VkPipelineStageFlagBits2KHR; + +typedef VkAccessFlags2 VkAccessFlags2KHR; + +typedef VkAccessFlagBits2 VkAccessFlagBits2KHR; + +typedef VkSubmitFlagBits VkSubmitFlagBitsKHR; + +typedef VkSubmitFlags VkSubmitFlagsKHR; + +typedef VkMemoryBarrier2 VkMemoryBarrier2KHR; + +typedef VkBufferMemoryBarrier2 VkBufferMemoryBarrier2KHR; + +typedef VkImageMemoryBarrier2 VkImageMemoryBarrier2KHR; + +typedef VkDependencyInfo VkDependencyInfoKHR; + +typedef VkSubmitInfo2 VkSubmitInfo2KHR; + +typedef VkSemaphoreSubmitInfo VkSemaphoreSubmitInfoKHR; + +typedef VkCommandBufferSubmitInfo VkCommandBufferSubmitInfoKHR; + +typedef VkPhysicalDeviceSynchronization2Features VkPhysicalDeviceSynchronization2FeaturesKHR; + +typedef struct VkQueueFamilyCheckpointProperties2NV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags2 checkpointExecutionStageMask; +} VkQueueFamilyCheckpointProperties2NV; + +typedef struct VkCheckpointData2NV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags2 stage; + void* pCheckpointMarker; +} VkCheckpointData2NV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2KHR)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, const VkDependencyInfo* pDependencyInfos); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2KHR)(VkCommandBuffer commandBuffer, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2KHR)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2KHR)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2* pSubmits, VkFence fence); +typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); +typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointData2NV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointData2NV* pCheckpointData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent2KHR( + VkCommandBuffer commandBuffer, + VkEvent event, + const VkDependencyInfo* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent2KHR( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags2 stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents2KHR( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + const VkDependencyInfo* pDependencyInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier2KHR( + VkCommandBuffer commandBuffer, + const VkDependencyInfo* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp2KHR( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2 stage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit2KHR( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo2* pSubmits, + VkFence fence); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarker2AMD( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2 stage, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + uint32_t marker); + +VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointData2NV( + VkQueue queue, + uint32_t* pCheckpointDataCount, + VkCheckpointData2NV* pCheckpointData); +#endif + + +// VK_KHR_fragment_shader_barycentric is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_fragment_shader_barycentric 1 +#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_KHR_fragment_shader_barycentric" +typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShaderBarycentric; +} VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR; + +typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 triStripVertexOrderIndependentOfProvokingVertex; +} VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR; + + + +// VK_KHR_shader_subgroup_uniform_control_flow is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_subgroup_uniform_control_flow 1 +#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_SPEC_VERSION 1 +#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_EXTENSION_NAME "VK_KHR_shader_subgroup_uniform_control_flow" +typedef struct VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupUniformControlFlow; +} VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR; + + + +// VK_KHR_zero_initialize_workgroup_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_zero_initialize_workgroup_memory 1 +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION 1 +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME "VK_KHR_zero_initialize_workgroup_memory" +typedef VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR; + + + +// VK_KHR_workgroup_memory_explicit_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_workgroup_memory_explicit_layout 1 +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME "VK_KHR_workgroup_memory_explicit_layout" +typedef struct VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 workgroupMemoryExplicitLayout; + VkBool32 workgroupMemoryExplicitLayoutScalarBlockLayout; + VkBool32 workgroupMemoryExplicitLayout8BitAccess; + VkBool32 workgroupMemoryExplicitLayout16BitAccess; +} VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR; + + + +// VK_KHR_copy_commands2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_copy_commands2 1 +#define VK_KHR_COPY_COMMANDS_2_SPEC_VERSION 1 +#define VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME "VK_KHR_copy_commands2" +typedef VkCopyBufferInfo2 VkCopyBufferInfo2KHR; + +typedef VkCopyImageInfo2 VkCopyImageInfo2KHR; + +typedef VkCopyBufferToImageInfo2 VkCopyBufferToImageInfo2KHR; + +typedef VkCopyImageToBufferInfo2 VkCopyImageToBufferInfo2KHR; + +typedef VkBlitImageInfo2 VkBlitImageInfo2KHR; + +typedef VkResolveImageInfo2 VkResolveImageInfo2KHR; + +typedef VkBufferCopy2 VkBufferCopy2KHR; + +typedef VkImageCopy2 VkImageCopy2KHR; + +typedef VkImageBlit2 VkImageBlit2KHR; + +typedef VkBufferImageCopy2 VkBufferImageCopy2KHR; + +typedef VkImageResolve2 VkImageResolve2KHR; + +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2* pCopyBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2* pCopyImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2KHR)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2* pBlitImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2KHR)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2* pResolveImageInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer2KHR( + VkCommandBuffer commandBuffer, + const VkCopyBufferInfo2* pCopyBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage2KHR( + VkCommandBuffer commandBuffer, + const VkCopyImageInfo2* pCopyImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage2KHR( + VkCommandBuffer commandBuffer, + const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer2KHR( + VkCommandBuffer commandBuffer, + const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage2KHR( + VkCommandBuffer commandBuffer, + const VkBlitImageInfo2* pBlitImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage2KHR( + VkCommandBuffer commandBuffer, + const VkResolveImageInfo2* pResolveImageInfo); +#endif + + +// VK_KHR_format_feature_flags2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_format_feature_flags2 1 +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION 2 +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME "VK_KHR_format_feature_flags2" +typedef VkFormatFeatureFlags2 VkFormatFeatureFlags2KHR; + +typedef VkFormatFeatureFlagBits2 VkFormatFeatureFlagBits2KHR; + +typedef VkFormatProperties3 VkFormatProperties3KHR; + + + +// VK_KHR_ray_tracing_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_ray_tracing_maintenance1 1 +#define VK_KHR_RAY_TRACING_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_ray_tracing_maintenance1" +typedef struct VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingMaintenance1; + VkBool32 rayTracingPipelineTraceRaysIndirect2; +} VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR; + +typedef struct VkTraceRaysIndirectCommand2KHR { + VkDeviceAddress raygenShaderRecordAddress; + VkDeviceSize raygenShaderRecordSize; + VkDeviceAddress missShaderBindingTableAddress; + VkDeviceSize missShaderBindingTableSize; + VkDeviceSize missShaderBindingTableStride; + VkDeviceAddress hitShaderBindingTableAddress; + VkDeviceSize hitShaderBindingTableSize; + VkDeviceSize hitShaderBindingTableStride; + VkDeviceAddress callableShaderBindingTableAddress; + VkDeviceSize callableShaderBindingTableSize; + VkDeviceSize callableShaderBindingTableStride; + uint32_t width; + uint32_t height; + uint32_t depth; +} VkTraceRaysIndirectCommand2KHR; + +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirect2KHR)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysIndirect2KHR( + VkCommandBuffer commandBuffer, + VkDeviceAddress indirectDeviceAddress); +#endif + + +// VK_KHR_portability_enumeration is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_portability_enumeration 1 +#define VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION 1 +#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration" + + +// VK_KHR_maintenance4 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance4 1 +#define VK_KHR_MAINTENANCE_4_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4" +typedef VkPhysicalDeviceMaintenance4Features VkPhysicalDeviceMaintenance4FeaturesKHR; + +typedef VkPhysicalDeviceMaintenance4Properties VkPhysicalDeviceMaintenance4PropertiesKHR; + +typedef VkDeviceBufferMemoryRequirements VkDeviceBufferMemoryRequirementsKHR; + +typedef VkDeviceImageMemoryRequirements VkDeviceImageMemoryRequirementsKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirementsKHR)(VkDevice device, const VkDeviceBufferMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceBufferMemoryRequirementsKHR( + VkDevice device, + const VkDeviceBufferMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageMemoryRequirementsKHR( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirementsKHR( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +#endif + + +// VK_KHR_maintenance5 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance5 1 +#define VK_KHR_MAINTENANCE_5_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_5_EXTENSION_NAME "VK_KHR_maintenance5" +typedef VkFlags64 VkPipelineCreateFlags2KHR; + +// Flag bits for VkPipelineCreateFlagBits2KHR +typedef VkFlags64 VkPipelineCreateFlagBits2KHR; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT_KHR = 0x00000001ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT_KHR = 0x00000002ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_DERIVATIVE_BIT_KHR = 0x00000004ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_DISPATCH_BASE_BIT_KHR = 0x00000010ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_DEFER_COMPILE_BIT_NV = 0x00000020ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_CAPTURE_STATISTICS_BIT_KHR = 0x00000040ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_KHR = 0x00000100ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR = 0x00000200ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_LINK_TIME_OPTIMIZATION_BIT_EXT = 0x00000400ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 0x00800000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR = 0x00000800ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 0x00001000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_AABBS_BIT_KHR = 0x00002000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 0x00004000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 0x00008000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 0x00010000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 0x00020000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 0x00080000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_NV = 0x00040000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_ALLOW_MOTION_BIT_NV = 0x00100000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00200000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 0x00400000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 0x01000000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x02000000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x04000000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT_EXT = 0x08000000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT = 0x40000000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 0x10000000ULL; +static const VkPipelineCreateFlagBits2KHR VK_PIPELINE_CREATE_2_DESCRIPTOR_BUFFER_BIT_EXT = 0x20000000ULL; + +typedef VkFlags64 VkBufferUsageFlags2KHR; + +// Flag bits for VkBufferUsageFlagBits2KHR +typedef VkFlags64 VkBufferUsageFlagBits2KHR; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT_KHR = 0x00000001ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_TRANSFER_DST_BIT_KHR = 0x00000002ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 0x00000004ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 0x00000008ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT_KHR = 0x00000010ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR = 0x00000020ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT_KHR = 0x00000040ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT_KHR = 0x00000080ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT_KHR = 0x00000100ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_EXECUTION_GRAPH_SCRATCH_BIT_AMDX = 0x02000000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_RAY_TRACING_BIT_NV = 0x00000400ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_VIDEO_DECODE_SRC_BIT_KHR = 0x00002000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_VIDEO_DECODE_DST_BIT_KHR = 0x00004000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_VIDEO_ENCODE_DST_BIT_KHR = 0x00008000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_VIDEO_ENCODE_SRC_BIT_KHR = 0x00010000ULL; +#endif +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT_KHR = 0x00020000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 0x00080000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 0x00100000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 0x00200000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00400000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 0x04000000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 0x00800000ULL; +static const VkBufferUsageFlagBits2KHR VK_BUFFER_USAGE_2_MICROMAP_STORAGE_BIT_EXT = 0x01000000ULL; + +typedef struct VkPhysicalDeviceMaintenance5FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 maintenance5; +} VkPhysicalDeviceMaintenance5FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance5PropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 earlyFragmentMultisampleCoverageAfterSampleCounting; + VkBool32 earlyFragmentSampleMaskTestBeforeSampleCounting; + VkBool32 depthStencilSwizzleOneSupport; + VkBool32 polygonModePointSize; + VkBool32 nonStrictSinglePixelWideLinesUseParallelogram; + VkBool32 nonStrictWideLinesUseParallelogram; +} VkPhysicalDeviceMaintenance5PropertiesKHR; + +typedef struct VkRenderingAreaInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkRenderingAreaInfoKHR; + +typedef struct VkImageSubresource2KHR { + VkStructureType sType; + void* pNext; + VkImageSubresource imageSubresource; +} VkImageSubresource2KHR; + +typedef struct VkDeviceImageSubresourceInfoKHR { + VkStructureType sType; + const void* pNext; + const VkImageCreateInfo* pCreateInfo; + const VkImageSubresource2KHR* pSubresource; +} VkDeviceImageSubresourceInfoKHR; + +typedef struct VkSubresourceLayout2KHR { + VkStructureType sType; + void* pNext; + VkSubresourceLayout subresourceLayout; +} VkSubresourceLayout2KHR; + +typedef struct VkPipelineCreateFlags2CreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags2KHR flags; +} VkPipelineCreateFlags2CreateInfoKHR; + +typedef struct VkBufferUsageFlags2CreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkBufferUsageFlags2KHR usage; +} VkBufferUsageFlags2CreateInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer2KHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkIndexType indexType); +typedef void (VKAPI_PTR *PFN_vkGetRenderingAreaGranularityKHR)(VkDevice device, const VkRenderingAreaInfoKHR* pRenderingAreaInfo, VkExtent2D* pGranularity); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSubresourceLayoutKHR)(VkDevice device, const VkDeviceImageSubresourceInfoKHR* pInfo, VkSubresourceLayout2KHR* pLayout); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout2KHR)(VkDevice device, VkImage image, const VkImageSubresource2KHR* pSubresource, VkSubresourceLayout2KHR* pLayout); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer2KHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkDeviceSize size, + VkIndexType indexType); + +VKAPI_ATTR void VKAPI_CALL vkGetRenderingAreaGranularityKHR( + VkDevice device, + const VkRenderingAreaInfoKHR* pRenderingAreaInfo, + VkExtent2D* pGranularity); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSubresourceLayoutKHR( + VkDevice device, + const VkDeviceImageSubresourceInfoKHR* pInfo, + VkSubresourceLayout2KHR* pLayout); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout2KHR( + VkDevice device, + VkImage image, + const VkImageSubresource2KHR* pSubresource, + VkSubresourceLayout2KHR* pLayout); +#endif + + +// VK_KHR_ray_tracing_position_fetch is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_ray_tracing_position_fetch 1 +#define VK_KHR_RAY_TRACING_POSITION_FETCH_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_POSITION_FETCH_EXTENSION_NAME "VK_KHR_ray_tracing_position_fetch" +typedef struct VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingPositionFetch; +} VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR; + + + +// VK_KHR_cooperative_matrix is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_cooperative_matrix 1 +#define VK_KHR_COOPERATIVE_MATRIX_SPEC_VERSION 2 +#define VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_KHR_cooperative_matrix" + +typedef enum VkComponentTypeKHR { + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_FLOAT16_NV = VK_COMPONENT_TYPE_FLOAT16_KHR, + VK_COMPONENT_TYPE_FLOAT32_NV = VK_COMPONENT_TYPE_FLOAT32_KHR, + VK_COMPONENT_TYPE_FLOAT64_NV = VK_COMPONENT_TYPE_FLOAT64_KHR, + VK_COMPONENT_TYPE_SINT8_NV = VK_COMPONENT_TYPE_SINT8_KHR, + VK_COMPONENT_TYPE_SINT16_NV = VK_COMPONENT_TYPE_SINT16_KHR, + VK_COMPONENT_TYPE_SINT32_NV = VK_COMPONENT_TYPE_SINT32_KHR, + VK_COMPONENT_TYPE_SINT64_NV = VK_COMPONENT_TYPE_SINT64_KHR, + VK_COMPONENT_TYPE_UINT8_NV = VK_COMPONENT_TYPE_UINT8_KHR, + VK_COMPONENT_TYPE_UINT16_NV = VK_COMPONENT_TYPE_UINT16_KHR, + VK_COMPONENT_TYPE_UINT32_NV = VK_COMPONENT_TYPE_UINT32_KHR, + VK_COMPONENT_TYPE_UINT64_NV = VK_COMPONENT_TYPE_UINT64_KHR, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; + +typedef enum VkScopeKHR { + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_DEVICE_NV = VK_SCOPE_DEVICE_KHR, + VK_SCOPE_WORKGROUP_NV = VK_SCOPE_WORKGROUP_KHR, + VK_SCOPE_SUBGROUP_NV = VK_SCOPE_SUBGROUP_KHR, + VK_SCOPE_QUEUE_FAMILY_NV = VK_SCOPE_QUEUE_FAMILY_KHR, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef struct VkCooperativeMatrixPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; + +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; + +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR { + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesKHR* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkCooperativeMatrixPropertiesKHR* pProperties); +#endif + + +// VK_EXT_debug_report is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_debug_report 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 10 +#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" + +typedef enum VkDebugReportObjectTypeEXT { + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, + VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, + VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, + VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, + VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, + VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, + VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, + VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, + VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, + VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, + VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, + VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, + VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, + VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT = 1000029000, + VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT = 1000029001, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000150000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_MODULE_NV = 1000307000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_FUNCTION_NV = 1000307001, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT = 1000366000, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportObjectTypeEXT; + +typedef enum VkDebugReportFlagBitsEXT { + VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, + VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, + VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, + VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, + VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportFlagBitsEXT; +typedef VkFlags VkDebugReportFlagsEXT; +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); + +typedef struct VkDebugReportCallbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT pfnCallback; + void* pUserData; +} VkDebugReportCallbackCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); +typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( + VkInstance instance, + const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugReportCallbackEXT* pCallback); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( + VkInstance instance, + VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( + VkInstance instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage); +#endif + + +// VK_NV_glsl_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_glsl_shader 1 +#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 +#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" + + +// VK_EXT_depth_range_unrestricted is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_range_unrestricted 1 +#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 +#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted" + + +// VK_IMG_filter_cubic is a preprocessor guard. Do not pass it to API calls. +#define VK_IMG_filter_cubic 1 +#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 +#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" + + +// VK_AMD_rasterization_order is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_rasterization_order 1 +#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 +#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" + +typedef enum VkRasterizationOrderAMD { + VK_RASTERIZATION_ORDER_STRICT_AMD = 0, + VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, + VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF +} VkRasterizationOrderAMD; +typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { + VkStructureType sType; + const void* pNext; + VkRasterizationOrderAMD rasterizationOrder; +} VkPipelineRasterizationStateRasterizationOrderAMD; + + + +// VK_AMD_shader_trinary_minmax is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_trinary_minmax 1 +#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 +#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" + + +// VK_AMD_shader_explicit_vertex_parameter is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_explicit_vertex_parameter 1 +#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 +#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" + + +// VK_EXT_debug_marker is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_debug_marker 1 +#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 +#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" +typedef struct VkDebugMarkerObjectNameInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportObjectTypeEXT objectType; + uint64_t object; + const char* pObjectName; +} VkDebugMarkerObjectNameInfoEXT; + +typedef struct VkDebugMarkerObjectTagInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportObjectTypeEXT objectType; + uint64_t object; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkDebugMarkerObjectTagInfoEXT; + +typedef struct VkDebugMarkerMarkerInfoEXT { + VkStructureType sType; + const void* pNext; + const char* pMarkerName; + float color[4]; +} VkDebugMarkerMarkerInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT* pTagInfo); +typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT* pNameInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT( + VkDevice device, + const VkDebugMarkerObjectTagInfoEXT* pTagInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT( + VkDevice device, + const VkDebugMarkerObjectNameInfoEXT* pNameInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT( + VkCommandBuffer commandBuffer, + const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT( + VkCommandBuffer commandBuffer, + const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +#endif + + +// VK_AMD_gcn_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_gcn_shader 1 +#define VK_AMD_GCN_SHADER_SPEC_VERSION 1 +#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" + + +// VK_NV_dedicated_allocation is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_dedicated_allocation 1 +#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 +#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" +typedef struct VkDedicatedAllocationImageCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationImageCreateInfoNV; + +typedef struct VkDedicatedAllocationBufferCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationBufferCreateInfoNV; + +typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { + VkStructureType sType; + const void* pNext; + VkImage image; + VkBuffer buffer; +} VkDedicatedAllocationMemoryAllocateInfoNV; + + + +// VK_EXT_transform_feedback is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_transform_feedback 1 +#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" +typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; +typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 transformFeedback; + VkBool32 geometryStreams; +} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxTransformFeedbackStreams; + uint32_t maxTransformFeedbackBuffers; + VkDeviceSize maxTransformFeedbackBufferSize; + uint32_t maxTransformFeedbackStreamDataSize; + uint32_t maxTransformFeedbackBufferDataSize; + uint32_t maxTransformFeedbackBufferDataStride; + VkBool32 transformFeedbackQueries; + VkBool32 transformFeedbackStreamsLinesTriangles; + VkBool32 transformFeedbackRasterizationStreamSelect; + VkBool32 transformFeedbackDraw; +} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + +typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateStreamCreateFlagsEXT flags; + uint32_t rasterizationStream; +} VkPipelineRasterizationStateStreamCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes); +typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags, + uint32_t index); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + uint32_t index); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT( + VkCommandBuffer commandBuffer, + uint32_t instanceCount, + uint32_t firstInstance, + VkBuffer counterBuffer, + VkDeviceSize counterBufferOffset, + uint32_t counterOffset, + uint32_t vertexStride); +#endif + + +// VK_NVX_binary_import is a preprocessor guard. Do not pass it to API calls. +#define VK_NVX_binary_import 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuModuleNVX) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuFunctionNVX) +#define VK_NVX_BINARY_IMPORT_SPEC_VERSION 1 +#define VK_NVX_BINARY_IMPORT_EXTENSION_NAME "VK_NVX_binary_import" +typedef struct VkCuModuleCreateInfoNVX { + VkStructureType sType; + const void* pNext; + size_t dataSize; + const void* pData; +} VkCuModuleCreateInfoNVX; + +typedef struct VkCuFunctionCreateInfoNVX { + VkStructureType sType; + const void* pNext; + VkCuModuleNVX module; + const char* pName; +} VkCuFunctionCreateInfoNVX; + +typedef struct VkCuLaunchInfoNVX { + VkStructureType sType; + const void* pNext; + VkCuFunctionNVX function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void* const * pParams; + size_t extraCount; + const void* const * pExtras; +} VkCuLaunchInfoNVX; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateCuModuleNVX)(VkDevice device, const VkCuModuleCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCuModuleNVX* pModule); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCuFunctionNVX)(VkDevice device, const VkCuFunctionCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCuFunctionNVX* pFunction); +typedef void (VKAPI_PTR *PFN_vkDestroyCuModuleNVX)(VkDevice device, VkCuModuleNVX module, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDestroyCuFunctionNVX)(VkDevice device, VkCuFunctionNVX function, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdCuLaunchKernelNVX)(VkCommandBuffer commandBuffer, const VkCuLaunchInfoNVX* pLaunchInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCuModuleNVX( + VkDevice device, + const VkCuModuleCreateInfoNVX* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCuModuleNVX* pModule); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCuFunctionNVX( + VkDevice device, + const VkCuFunctionCreateInfoNVX* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCuFunctionNVX* pFunction); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCuModuleNVX( + VkDevice device, + VkCuModuleNVX module, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCuFunctionNVX( + VkDevice device, + VkCuFunctionNVX function, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkCmdCuLaunchKernelNVX( + VkCommandBuffer commandBuffer, + const VkCuLaunchInfoNVX* pLaunchInfo); +#endif + + +// VK_NVX_image_view_handle is a preprocessor guard. Do not pass it to API calls. +#define VK_NVX_image_view_handle 1 +#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 2 +#define VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME "VK_NVX_image_view_handle" +typedef struct VkImageViewHandleInfoNVX { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkDescriptorType descriptorType; + VkSampler sampler; +} VkImageViewHandleInfoNVX; + +typedef struct VkImageViewAddressPropertiesNVX { + VkStructureType sType; + void* pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; +} VkImageViewAddressPropertiesNVX; + +typedef uint32_t (VKAPI_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice device, const VkImageViewHandleInfoNVX* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewAddressNVX)(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR uint32_t VKAPI_CALL vkGetImageViewHandleNVX( + VkDevice device, + const VkImageViewHandleInfoNVX* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageViewAddressNVX( + VkDevice device, + VkImageView imageView, + VkImageViewAddressPropertiesNVX* pProperties); +#endif + + +// VK_AMD_draw_indirect_count is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_draw_indirect_count 1 +#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 2 +#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + + +// VK_AMD_negative_viewport_height is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_negative_viewport_height 1 +#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 +#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" + + +// VK_AMD_gpu_shader_half_float is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_gpu_shader_half_float 1 +#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 2 +#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" + + +// VK_AMD_shader_ballot is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_ballot 1 +#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 +#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" + + +// VK_AMD_texture_gather_bias_lod is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_texture_gather_bias_lod 1 +#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 +#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" +typedef struct VkTextureLODGatherFormatPropertiesAMD { + VkStructureType sType; + void* pNext; + VkBool32 supportsTextureGatherLODBiasAMD; +} VkTextureLODGatherFormatPropertiesAMD; + + + +// VK_AMD_shader_info is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_info 1 +#define VK_AMD_SHADER_INFO_SPEC_VERSION 1 +#define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info" + +typedef enum VkShaderInfoTypeAMD { + VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, + VK_SHADER_INFO_TYPE_BINARY_AMD = 1, + VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, + VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkShaderInfoTypeAMD; +typedef struct VkShaderResourceUsageAMD { + uint32_t numUsedVgprs; + uint32_t numUsedSgprs; + uint32_t ldsSizePerLocalWorkGroup; + size_t ldsUsageSizeInBytes; + size_t scratchMemUsageInBytes; +} VkShaderResourceUsageAMD; + +typedef struct VkShaderStatisticsInfoAMD { + VkShaderStageFlags shaderStageMask; + VkShaderResourceUsageAMD resourceUsage; + uint32_t numPhysicalVgprs; + uint32_t numPhysicalSgprs; + uint32_t numAvailableVgprs; + uint32_t numAvailableSgprs; + uint32_t computeWorkGroupSize[3]; +} VkShaderStatisticsInfoAMD; + +typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t* pInfoSize, void* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderInfoAMD( + VkDevice device, + VkPipeline pipeline, + VkShaderStageFlagBits shaderStage, + VkShaderInfoTypeAMD infoType, + size_t* pInfoSize, + void* pInfo); +#endif + + +// VK_AMD_shader_image_load_store_lod is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_image_load_store_lod 1 +#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1 +#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod" + + +// VK_NV_corner_sampled_image is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_corner_sampled_image 1 +#define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 +#define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" +typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cornerSampledImage; +} VkPhysicalDeviceCornerSampledImageFeaturesNV; + + + +// VK_IMG_format_pvrtc is a preprocessor guard. Do not pass it to API calls. +#define VK_IMG_format_pvrtc 1 +#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 +#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" + + +// VK_NV_external_memory_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_external_memory_capabilities 1 +#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" + +typedef enum VkExternalMemoryHandleTypeFlagBitsNV { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkExternalMemoryHandleTypeFlagBitsNV; +typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; + +typedef enum VkExternalMemoryFeatureFlagBitsNV { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkExternalMemoryFeatureFlagBitsNV; +typedef VkFlags VkExternalMemoryFeatureFlagsNV; +typedef struct VkExternalImageFormatPropertiesNV { + VkImageFormatProperties imageFormatProperties; + VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; + VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; +} VkExternalImageFormatPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkExternalMemoryHandleTypeFlagsNV externalHandleType, + VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); +#endif + + +// VK_NV_external_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_external_memory 1 +#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" +typedef struct VkExternalMemoryImageCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExternalMemoryImageCreateInfoNV; + +typedef struct VkExportMemoryAllocateInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExportMemoryAllocateInfoNV; + + + +// VK_EXT_validation_flags is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_validation_flags 1 +#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 2 +#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" + +typedef enum VkValidationCheckEXT { + VK_VALIDATION_CHECK_ALL_EXT = 0, + VK_VALIDATION_CHECK_SHADERS_EXT = 1, + VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationCheckEXT; +typedef struct VkValidationFlagsEXT { + VkStructureType sType; + const void* pNext; + uint32_t disabledValidationCheckCount; + const VkValidationCheckEXT* pDisabledValidationChecks; +} VkValidationFlagsEXT; + + + +// VK_EXT_shader_subgroup_ballot is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_subgroup_ballot 1 +#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" + + +// VK_EXT_shader_subgroup_vote is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_subgroup_vote 1 +#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" + + +// VK_EXT_texture_compression_astc_hdr is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_texture_compression_astc_hdr 1 +#define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_SPEC_VERSION 1 +#define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME "VK_EXT_texture_compression_astc_hdr" +typedef VkPhysicalDeviceTextureCompressionASTCHDRFeatures VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; + + + +// VK_EXT_astc_decode_mode is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_astc_decode_mode 1 +#define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 +#define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" +typedef struct VkImageViewASTCDecodeModeEXT { + VkStructureType sType; + const void* pNext; + VkFormat decodeMode; +} VkImageViewASTCDecodeModeEXT; + +typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 decodeModeSharedExponent; +} VkPhysicalDeviceASTCDecodeFeaturesEXT; + + + +// VK_EXT_pipeline_robustness is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_robustness 1 +#define VK_EXT_PIPELINE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_pipeline_robustness" + +typedef enum VkPipelineRobustnessBufferBehaviorEXT { + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT = 0, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT = 1, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT = 2, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT = 3, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPipelineRobustnessBufferBehaviorEXT; + +typedef enum VkPipelineRobustnessImageBehaviorEXT { + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT = 0, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED_EXT = 1, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT = 2, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT = 3, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPipelineRobustnessImageBehaviorEXT; +typedef struct VkPhysicalDevicePipelineRobustnessFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pipelineRobustness; +} VkPhysicalDevicePipelineRobustnessFeaturesEXT; + +typedef struct VkPhysicalDevicePipelineRobustnessPropertiesEXT { + VkStructureType sType; + void* pNext; + VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessStorageBuffers; + VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessUniformBuffers; + VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessVertexInputs; + VkPipelineRobustnessImageBehaviorEXT defaultRobustnessImages; +} VkPhysicalDevicePipelineRobustnessPropertiesEXT; + +typedef struct VkPipelineRobustnessCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRobustnessBufferBehaviorEXT storageBuffers; + VkPipelineRobustnessBufferBehaviorEXT uniformBuffers; + VkPipelineRobustnessBufferBehaviorEXT vertexInputs; + VkPipelineRobustnessImageBehaviorEXT images; +} VkPipelineRobustnessCreateInfoEXT; + + + +// VK_EXT_conditional_rendering is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_conditional_rendering 1 +#define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 2 +#define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" + +typedef enum VkConditionalRenderingFlagBitsEXT { + VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001, + VK_CONDITIONAL_RENDERING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkConditionalRenderingFlagBitsEXT; +typedef VkFlags VkConditionalRenderingFlagsEXT; +typedef struct VkConditionalRenderingBeginInfoEXT { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; + VkDeviceSize offset; + VkConditionalRenderingFlagsEXT flags; +} VkConditionalRenderingBeginInfoEXT; + +typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 conditionalRendering; + VkBool32 inheritedConditionalRendering; +} VkPhysicalDeviceConditionalRenderingFeaturesEXT; + +typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 conditionalRenderingEnable; +} VkCommandBufferInheritanceConditionalRenderingInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); +typedef void (VKAPI_PTR *PFN_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginConditionalRenderingEXT( + VkCommandBuffer commandBuffer, + const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndConditionalRenderingEXT( + VkCommandBuffer commandBuffer); +#endif + + +// VK_NV_clip_space_w_scaling is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_clip_space_w_scaling 1 +#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 +#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" +typedef struct VkViewportWScalingNV { + float xcoeff; + float ycoeff; +} VkViewportWScalingNV; + +typedef struct VkPipelineViewportWScalingStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 viewportWScalingEnable; + uint32_t viewportCount; + const VkViewportWScalingNV* pViewportWScalings; +} VkPipelineViewportWScalingStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewportWScalingNV* pViewportWScalings); +#endif + + +// VK_EXT_direct_mode_display is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_direct_mode_display 1 +#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" +typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display); +#endif + + +// VK_EXT_display_surface_counter is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_display_surface_counter 1 +#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 +#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" + +typedef enum VkSurfaceCounterFlagBitsEXT { + VK_SURFACE_COUNTER_VBLANK_BIT_EXT = 0x00000001, + VK_SURFACE_COUNTER_VBLANK_EXT = VK_SURFACE_COUNTER_VBLANK_BIT_EXT, + VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSurfaceCounterFlagBitsEXT; +typedef VkFlags VkSurfaceCounterFlagsEXT; +typedef struct VkSurfaceCapabilities2EXT { + VkStructureType sType; + void* pNext; + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; + VkSurfaceCounterFlagsEXT supportedSurfaceCounters; +} VkSurfaceCapabilities2EXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilities2EXT* pSurfaceCapabilities); +#endif + + +// VK_EXT_display_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_display_control 1 +#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" + +typedef enum VkDisplayPowerStateEXT { + VK_DISPLAY_POWER_STATE_OFF_EXT = 0, + VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, + VK_DISPLAY_POWER_STATE_ON_EXT = 2, + VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDisplayPowerStateEXT; + +typedef enum VkDeviceEventTypeEXT { + VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, + VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceEventTypeEXT; + +typedef enum VkDisplayEventTypeEXT { + VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, + VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDisplayEventTypeEXT; +typedef struct VkDisplayPowerInfoEXT { + VkStructureType sType; + const void* pNext; + VkDisplayPowerStateEXT powerState; +} VkDisplayPowerInfoEXT; + +typedef struct VkDeviceEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceEventTypeEXT deviceEvent; +} VkDeviceEventInfoEXT; + +typedef struct VkDisplayEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkDisplayEventTypeEXT displayEvent; +} VkDisplayEventInfoEXT; + +typedef struct VkSwapchainCounterCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkSurfaceCounterFlagsEXT surfaceCounters; +} VkSwapchainCounterCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT( + VkDevice device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT* pDisplayPowerInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT( + VkDevice device, + const VkDeviceEventInfoEXT* pDeviceEventInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT( + VkDevice device, + VkDisplayKHR display, + const VkDisplayEventInfoEXT* pDisplayEventInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT( + VkDevice device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT counter, + uint64_t* pCounterValue); +#endif + + +// VK_GOOGLE_display_timing is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_display_timing 1 +#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1 +#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing" +typedef struct VkRefreshCycleDurationGOOGLE { + uint64_t refreshDuration; +} VkRefreshCycleDurationGOOGLE; + +typedef struct VkPastPresentationTimingGOOGLE { + uint32_t presentID; + uint64_t desiredPresentTime; + uint64_t actualPresentTime; + uint64_t earliestPresentTime; + uint64_t presentMargin; +} VkPastPresentationTimingGOOGLE; + +typedef struct VkPresentTimeGOOGLE { + uint32_t presentID; + uint64_t desiredPresentTime; +} VkPresentTimeGOOGLE; + +typedef struct VkPresentTimesInfoGOOGLE { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentTimeGOOGLE* pTimes; +} VkPresentTimesInfoGOOGLE; + +typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE( + VkDevice device, + VkSwapchainKHR swapchain, + VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pPresentationTimingCount, + VkPastPresentationTimingGOOGLE* pPresentationTimings); +#endif + + +// VK_NV_sample_mask_override_coverage is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_sample_mask_override_coverage 1 +#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 +#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" + + +// VK_NV_geometry_shader_passthrough is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_geometry_shader_passthrough 1 +#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 +#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" + + +// VK_NV_viewport_array2 is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_viewport_array2 1 +#define VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME "VK_NV_viewport_array2" +#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION +#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME + + +// VK_NVX_multiview_per_view_attributes is a preprocessor guard. Do not pass it to API calls. +#define VK_NVX_multiview_per_view_attributes 1 +#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1 +#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes" +typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { + VkStructureType sType; + void* pNext; + VkBool32 perViewPositionAllComponents; +} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; + + + +// VK_NV_viewport_swizzle is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_viewport_swizzle 1 +#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" + +typedef enum VkViewportCoordinateSwizzleNV { + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, + VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF +} VkViewportCoordinateSwizzleNV; +typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; +typedef struct VkViewportSwizzleNV { + VkViewportCoordinateSwizzleNV x; + VkViewportCoordinateSwizzleNV y; + VkViewportCoordinateSwizzleNV z; + VkViewportCoordinateSwizzleNV w; +} VkViewportSwizzleNV; + +typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineViewportSwizzleStateCreateFlagsNV flags; + uint32_t viewportCount; + const VkViewportSwizzleNV* pViewportSwizzles; +} VkPipelineViewportSwizzleStateCreateInfoNV; + + + +// VK_EXT_discard_rectangles is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_discard_rectangles 1 +#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 2 +#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" + +typedef enum VkDiscardRectangleModeEXT { + VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, + VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, + VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDiscardRectangleModeEXT; +typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxDiscardRectangles; +} VkPhysicalDeviceDiscardRectanglePropertiesEXT; + +typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineDiscardRectangleStateCreateFlagsEXT flags; + VkDiscardRectangleModeEXT discardRectangleMode; + uint32_t discardRectangleCount; + const VkRect2D* pDiscardRectangles; +} VkPipelineDiscardRectangleStateCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles); +typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 discardRectangleEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleModeEXT)(VkCommandBuffer commandBuffer, VkDiscardRectangleModeEXT discardRectangleMode); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT( + VkCommandBuffer commandBuffer, + uint32_t firstDiscardRectangle, + uint32_t discardRectangleCount, + const VkRect2D* pDiscardRectangles); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 discardRectangleEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleModeEXT( + VkCommandBuffer commandBuffer, + VkDiscardRectangleModeEXT discardRectangleMode); +#endif + + +// VK_EXT_conservative_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_conservative_rasterization 1 +#define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1 +#define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" + +typedef enum VkConservativeRasterizationModeEXT { + VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, + VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, + VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, + VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkConservativeRasterizationModeEXT; +typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { + VkStructureType sType; + void* pNext; + float primitiveOverestimationSize; + float maxExtraPrimitiveOverestimationSize; + float extraPrimitiveOverestimationSizeGranularity; + VkBool32 primitiveUnderestimation; + VkBool32 conservativePointAndLineRasterization; + VkBool32 degenerateTrianglesRasterized; + VkBool32 degenerateLinesRasterized; + VkBool32 fullyCoveredFragmentShaderInputVariable; + VkBool32 conservativeRasterizationPostDepthCoverage; +} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; + +typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; + VkConservativeRasterizationModeEXT conservativeRasterizationMode; + float extraPrimitiveOverestimationSize; +} VkPipelineRasterizationConservativeStateCreateInfoEXT; + + + +// VK_EXT_depth_clip_enable is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_clip_enable 1 +#define VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME "VK_EXT_depth_clip_enable" +typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthClipEnable; +} VkPhysicalDeviceDepthClipEnableFeaturesEXT; + +typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; + VkBool32 depthClipEnable; +} VkPipelineRasterizationDepthClipStateCreateInfoEXT; + + + +// VK_EXT_swapchain_colorspace is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_swapchain_colorspace 1 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 4 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" + + +// VK_EXT_hdr_metadata is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_hdr_metadata 1 +#define VK_EXT_HDR_METADATA_SPEC_VERSION 2 +#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" +typedef struct VkXYColorEXT { + float x; + float y; +} VkXYColorEXT; + +typedef struct VkHdrMetadataEXT { + VkStructureType sType; + const void* pNext; + VkXYColorEXT displayPrimaryRed; + VkXYColorEXT displayPrimaryGreen; + VkXYColorEXT displayPrimaryBlue; + VkXYColorEXT whitePoint; + float maxLuminance; + float minLuminance; + float maxContentLightLevel; + float maxFrameAverageLightLevel; +} VkHdrMetadataEXT; + +typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT( + VkDevice device, + uint32_t swapchainCount, + const VkSwapchainKHR* pSwapchains, + const VkHdrMetadataEXT* pMetadata); +#endif + + +// VK_IMG_relaxed_line_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_IMG_relaxed_line_rasterization 1 +#define VK_IMG_RELAXED_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_IMG_RELAXED_LINE_RASTERIZATION_EXTENSION_NAME "VK_IMG_relaxed_line_rasterization" +typedef struct VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG { + VkStructureType sType; + void* pNext; + VkBool32 relaxedLineRasterization; +} VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG; + + + +// VK_EXT_external_memory_dma_buf is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_external_memory_dma_buf 1 +#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf" + + +// VK_EXT_queue_family_foreign is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_queue_family_foreign 1 +#define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 +#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" +#define VK_QUEUE_FAMILY_FOREIGN_EXT (~2U) + + +// VK_EXT_debug_utils is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_debug_utils 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) +#define VK_EXT_DEBUG_UTILS_SPEC_VERSION 2 +#define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" +typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; + +typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugUtilsMessageSeverityFlagBitsEXT; + +typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001, + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002, + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004, + VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT = 0x00000008, + VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugUtilsMessageTypeFlagBitsEXT; +typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; +typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; +typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; +typedef struct VkDebugUtilsLabelEXT { + VkStructureType sType; + const void* pNext; + const char* pLabelName; + float color[4]; +} VkDebugUtilsLabelEXT; + +typedef struct VkDebugUtilsObjectNameInfoEXT { + VkStructureType sType; + const void* pNext; + VkObjectType objectType; + uint64_t objectHandle; + const char* pObjectName; +} VkDebugUtilsObjectNameInfoEXT; + +typedef struct VkDebugUtilsMessengerCallbackDataEXT { + VkStructureType sType; + const void* pNext; + VkDebugUtilsMessengerCallbackDataFlagsEXT flags; + const char* pMessageIdName; + int32_t messageIdNumber; + const char* pMessage; + uint32_t queueLabelCount; + const VkDebugUtilsLabelEXT* pQueueLabels; + uint32_t cmdBufLabelCount; + const VkDebugUtilsLabelEXT* pCmdBufLabels; + uint32_t objectCount; + const VkDebugUtilsObjectNameInfoEXT* pObjects; +} VkDebugUtilsMessengerCallbackDataEXT; + +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData); + +typedef struct VkDebugUtilsMessengerCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugUtilsMessengerCreateFlagsEXT flags; + VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; + VkDebugUtilsMessageTypeFlagsEXT messageType; + PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback; + void* pUserData; +} VkDebugUtilsMessengerCreateInfoEXT; + +typedef struct VkDebugUtilsObjectTagInfoEXT { + VkStructureType sType; + const void* pNext; + VkObjectType objectType; + uint64_t objectHandle; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkDebugUtilsObjectTagInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice device, const VkDebugUtilsObjectNameInfoEXT* pNameInfo); +typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice device, const VkDebugUtilsObjectTagInfoEXT* pTagInfo); +typedef void (VKAPI_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue); +typedef void (VKAPI_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger); +typedef void (VKAPI_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectNameEXT( + VkDevice device, + const VkDebugUtilsObjectNameInfoEXT* pNameInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectTagEXT( + VkDevice device, + const VkDebugUtilsObjectTagInfoEXT* pTagInfo); + +VKAPI_ATTR void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT( + VkQueue queue, + const VkDebugUtilsLabelEXT* pLabelInfo); + +VKAPI_ATTR void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT( + VkQueue queue); + +VKAPI_ATTR void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT( + VkQueue queue, + const VkDebugUtilsLabelEXT* pLabelInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer, + const VkDebugUtilsLabelEXT* pLabelInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdInsertDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer, + const VkDebugUtilsLabelEXT* pLabelInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( + VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugUtilsMessengerEXT* pMessenger); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT( + VkInstance instance, + VkDebugUtilsMessengerEXT messenger, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT( + VkInstance instance, + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); +#endif + + +// VK_EXT_sampler_filter_minmax is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_sampler_filter_minmax 1 +#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 2 +#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" +typedef VkSamplerReductionMode VkSamplerReductionModeEXT; + +typedef VkSamplerReductionModeCreateInfo VkSamplerReductionModeCreateInfoEXT; + +typedef VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; + + + +// VK_AMD_gpu_shader_int16 is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_gpu_shader_int16 1 +#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 2 +#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16" + + +// VK_AMD_mixed_attachment_samples is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_mixed_attachment_samples 1 +#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1 +#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples" + + +// VK_AMD_shader_fragment_mask is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_fragment_mask 1 +#define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1 +#define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" + + +// VK_EXT_inline_uniform_block is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_inline_uniform_block 1 +#define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 +#define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" +typedef VkPhysicalDeviceInlineUniformBlockFeatures VkPhysicalDeviceInlineUniformBlockFeaturesEXT; + +typedef VkPhysicalDeviceInlineUniformBlockProperties VkPhysicalDeviceInlineUniformBlockPropertiesEXT; + +typedef VkWriteDescriptorSetInlineUniformBlock VkWriteDescriptorSetInlineUniformBlockEXT; + +typedef VkDescriptorPoolInlineUniformBlockCreateInfo VkDescriptorPoolInlineUniformBlockCreateInfoEXT; + + + +// VK_EXT_shader_stencil_export is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_stencil_export 1 +#define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 +#define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" + + +// VK_EXT_sample_locations is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_sample_locations 1 +#define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1 +#define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations" +typedef struct VkSampleLocationEXT { + float x; + float y; +} VkSampleLocationEXT; + +typedef struct VkSampleLocationsInfoEXT { + VkStructureType sType; + const void* pNext; + VkSampleCountFlagBits sampleLocationsPerPixel; + VkExtent2D sampleLocationGridSize; + uint32_t sampleLocationsCount; + const VkSampleLocationEXT* pSampleLocations; +} VkSampleLocationsInfoEXT; + +typedef struct VkAttachmentSampleLocationsEXT { + uint32_t attachmentIndex; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkAttachmentSampleLocationsEXT; + +typedef struct VkSubpassSampleLocationsEXT { + uint32_t subpassIndex; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkSubpassSampleLocationsEXT; + +typedef struct VkRenderPassSampleLocationsBeginInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t attachmentInitialSampleLocationsCount; + const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations; + uint32_t postSubpassSampleLocationsCount; + const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations; +} VkRenderPassSampleLocationsBeginInfoEXT; + +typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 sampleLocationsEnable; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkPipelineSampleLocationsStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { + VkStructureType sType; + void* pNext; + VkSampleCountFlags sampleLocationSampleCounts; + VkExtent2D maxSampleLocationGridSize; + float sampleLocationCoordinateRange[2]; + uint32_t sampleLocationSubPixelBits; + VkBool32 variableSampleLocations; +} VkPhysicalDeviceSampleLocationsPropertiesEXT; + +typedef struct VkMultisamplePropertiesEXT { + VkStructureType sType; + void* pNext; + VkExtent2D maxSampleLocationGridSize; +} VkMultisamplePropertiesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT* pSampleLocationsInfo); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT* pMultisampleProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEXT( + VkCommandBuffer commandBuffer, + const VkSampleLocationsInfoEXT* pSampleLocationsInfo); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMultisamplePropertiesEXT( + VkPhysicalDevice physicalDevice, + VkSampleCountFlagBits samples, + VkMultisamplePropertiesEXT* pMultisampleProperties); +#endif + + +// VK_EXT_blend_operation_advanced is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_blend_operation_advanced 1 +#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 +#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" + +typedef enum VkBlendOverlapEXT { + VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, + VK_BLEND_OVERLAP_DISJOINT_EXT = 1, + VK_BLEND_OVERLAP_CONJOINT_EXT = 2, + VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBlendOverlapEXT; +typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 advancedBlendCoherentOperations; +} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; + +typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t advancedBlendMaxColorAttachments; + VkBool32 advancedBlendIndependentBlend; + VkBool32 advancedBlendNonPremultipliedSrcColor; + VkBool32 advancedBlendNonPremultipliedDstColor; + VkBool32 advancedBlendCorrelatedOverlap; + VkBool32 advancedBlendAllOperations; +} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; + +typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; +} VkPipelineColorBlendAdvancedStateCreateInfoEXT; + + + +// VK_NV_fragment_coverage_to_color is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_fragment_coverage_to_color 1 +#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color" +typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; +typedef struct VkPipelineCoverageToColorStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageToColorStateCreateFlagsNV flags; + VkBool32 coverageToColorEnable; + uint32_t coverageToColorLocation; +} VkPipelineCoverageToColorStateCreateInfoNV; + + + +// VK_NV_framebuffer_mixed_samples is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_framebuffer_mixed_samples 1 +#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 +#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" + +typedef enum VkCoverageModulationModeNV { + VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, + VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, + VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, + VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, + VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoverageModulationModeNV; +typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; +typedef struct VkPipelineCoverageModulationStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageModulationStateCreateFlagsNV flags; + VkCoverageModulationModeNV coverageModulationMode; + VkBool32 coverageModulationTableEnable; + uint32_t coverageModulationTableCount; + const float* pCoverageModulationTable; +} VkPipelineCoverageModulationStateCreateInfoNV; + + + +// VK_NV_fill_rectangle is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_fill_rectangle 1 +#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 +#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" + + +// VK_NV_shader_sm_builtins is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shader_sm_builtins 1 +#define VK_NV_SHADER_SM_BUILTINS_SPEC_VERSION 1 +#define VK_NV_SHADER_SM_BUILTINS_EXTENSION_NAME "VK_NV_shader_sm_builtins" +typedef struct VkPhysicalDeviceShaderSMBuiltinsPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t shaderSMCount; + uint32_t shaderWarpsPerSM; +} VkPhysicalDeviceShaderSMBuiltinsPropertiesNV; + +typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shaderSMBuiltins; +} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; + + + +// VK_EXT_post_depth_coverage is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_post_depth_coverage 1 +#define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 +#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" + + +// VK_EXT_image_drm_format_modifier is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_drm_format_modifier 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 2 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" +typedef struct VkDrmFormatModifierPropertiesEXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags drmFormatModifierTilingFeatures; +} VkDrmFormatModifierPropertiesEXT; + +typedef struct VkDrmFormatModifierPropertiesListEXT { + VkStructureType sType; + void* pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesListEXT; + +typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkPhysicalDeviceImageDrmFormatModifierInfoEXT; + +typedef struct VkImageDrmFormatModifierListCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t drmFormatModifierCount; + const uint64_t* pDrmFormatModifiers; +} VkImageDrmFormatModifierListCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + const VkSubresourceLayout* pPlaneLayouts; +} VkImageDrmFormatModifierExplicitCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierPropertiesEXT { + VkStructureType sType; + void* pNext; + uint64_t drmFormatModifier; +} VkImageDrmFormatModifierPropertiesEXT; + +typedef struct VkDrmFormatModifierProperties2EXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags2 drmFormatModifierTilingFeatures; +} VkDrmFormatModifierProperties2EXT; + +typedef struct VkDrmFormatModifierPropertiesList2EXT { + VkStructureType sType; + void* pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierProperties2EXT* pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesList2EXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT( + VkDevice device, + VkImage image, + VkImageDrmFormatModifierPropertiesEXT* pProperties); +#endif + + +// VK_EXT_validation_cache is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_validation_cache 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) +#define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 +#define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" + +typedef enum VkValidationCacheHeaderVersionEXT { + VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, + VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationCacheHeaderVersionEXT; +typedef VkFlags VkValidationCacheCreateFlagsEXT; +typedef struct VkValidationCacheCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkValidationCacheCreateFlagsEXT flags; + size_t initialDataSize; + const void* pInitialData; +} VkValidationCacheCreateInfoEXT; + +typedef struct VkShaderModuleValidationCacheCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkValidationCacheEXT validationCache; +} VkShaderModuleValidationCacheCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache); +typedef void (VKAPI_PTR *PFN_vkDestroyValidationCacheEXT)(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT* pSrcCaches); +typedef VkResult (VKAPI_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize, void* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateValidationCacheEXT( + VkDevice device, + const VkValidationCacheCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkValidationCacheEXT* pValidationCache); + +VKAPI_ATTR void VKAPI_CALL vkDestroyValidationCacheEXT( + VkDevice device, + VkValidationCacheEXT validationCache, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkMergeValidationCachesEXT( + VkDevice device, + VkValidationCacheEXT dstCache, + uint32_t srcCacheCount, + const VkValidationCacheEXT* pSrcCaches); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT( + VkDevice device, + VkValidationCacheEXT validationCache, + size_t* pDataSize, + void* pData); +#endif + + +// VK_EXT_descriptor_indexing is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_descriptor_indexing 1 +#define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 +#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" +typedef VkDescriptorBindingFlagBits VkDescriptorBindingFlagBitsEXT; + +typedef VkDescriptorBindingFlags VkDescriptorBindingFlagsEXT; + +typedef VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; + +typedef VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; + +typedef VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; + +typedef VkDescriptorSetVariableDescriptorCountAllocateInfo VkDescriptorSetVariableDescriptorCountAllocateInfoEXT; + +typedef VkDescriptorSetVariableDescriptorCountLayoutSupport VkDescriptorSetVariableDescriptorCountLayoutSupportEXT; + + + +// VK_EXT_shader_viewport_index_layer is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_viewport_index_layer 1 +#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 +#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" + + +// VK_NV_shading_rate_image is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shading_rate_image 1 +#define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 +#define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image" + +typedef enum VkShadingRatePaletteEntryNV { + VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV = 0, + VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV = 1, + VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV = 2, + VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV = 3, + VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV = 4, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV = 5, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV = 6, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV = 7, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, + VK_SHADING_RATE_PALETTE_ENTRY_MAX_ENUM_NV = 0x7FFFFFFF +} VkShadingRatePaletteEntryNV; + +typedef enum VkCoarseSampleOrderTypeNV { + VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, + VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, + VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, + VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, + VK_COARSE_SAMPLE_ORDER_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoarseSampleOrderTypeNV; +typedef struct VkShadingRatePaletteNV { + uint32_t shadingRatePaletteEntryCount; + const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries; +} VkShadingRatePaletteNV; + +typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 shadingRateImageEnable; + uint32_t viewportCount; + const VkShadingRatePaletteNV* pShadingRatePalettes; +} VkPipelineViewportShadingRateImageStateCreateInfoNV; + +typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shadingRateImage; + VkBool32 shadingRateCoarseSampleOrder; +} VkPhysicalDeviceShadingRateImageFeaturesNV; + +typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV { + VkStructureType sType; + void* pNext; + VkExtent2D shadingRateTexelSize; + uint32_t shadingRatePaletteSize; + uint32_t shadingRateMaxCoarseSamples; +} VkPhysicalDeviceShadingRateImagePropertiesNV; + +typedef struct VkCoarseSampleLocationNV { + uint32_t pixelX; + uint32_t pixelY; + uint32_t sample; +} VkCoarseSampleLocationNV; + +typedef struct VkCoarseSampleOrderCustomNV { + VkShadingRatePaletteEntryNV shadingRate; + uint32_t sampleCount; + uint32_t sampleLocationCount; + const VkCoarseSampleLocationNV* pSampleLocations; +} VkCoarseSampleOrderCustomNV; + +typedef struct VkPipelineViewportCoarseSampleOrderStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkCoarseSampleOrderTypeNV sampleOrderType; + uint32_t customSampleOrderCount; + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders; +} VkPipelineViewportCoarseSampleOrderStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdBindShadingRateImageNV)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV* pShadingRatePalettes); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindShadingRateImageNV( + VkCommandBuffer commandBuffer, + VkImageView imageView, + VkImageLayout imageLayout); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportShadingRatePaletteNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkShadingRatePaletteNV* pShadingRatePalettes); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoarseSampleOrderNV( + VkCommandBuffer commandBuffer, + VkCoarseSampleOrderTypeNV sampleOrderType, + uint32_t customSampleOrderCount, + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); +#endif + + +// VK_NV_ray_tracing is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_ray_tracing 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) +#define VK_NV_RAY_TRACING_SPEC_VERSION 3 +#define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" +#define VK_SHADER_UNUSED_KHR (~0U) +#define VK_SHADER_UNUSED_NV VK_SHADER_UNUSED_KHR + +typedef enum VkRayTracingShaderGroupTypeKHR { + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR = 0, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR = 1, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR = 2, + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkRayTracingShaderGroupTypeKHR; +typedef VkRayTracingShaderGroupTypeKHR VkRayTracingShaderGroupTypeNV; + + +typedef enum VkGeometryTypeKHR { + VK_GEOMETRY_TYPE_TRIANGLES_KHR = 0, + VK_GEOMETRY_TYPE_AABBS_KHR = 1, + VK_GEOMETRY_TYPE_INSTANCES_KHR = 2, + VK_GEOMETRY_TYPE_TRIANGLES_NV = VK_GEOMETRY_TYPE_TRIANGLES_KHR, + VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR, + VK_GEOMETRY_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryTypeKHR; +typedef VkGeometryTypeKHR VkGeometryTypeNV; + + +typedef enum VkAccelerationStructureTypeKHR { + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR = 0, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR = 1, + VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR = 2, + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureTypeKHR; +typedef VkAccelerationStructureTypeKHR VkAccelerationStructureTypeNV; + + +typedef enum VkCopyAccelerationStructureModeKHR { + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR = 0, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR = 1, + VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR = 2, + VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR = 3, + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCopyAccelerationStructureModeKHR; +typedef VkCopyAccelerationStructureModeKHR VkCopyAccelerationStructureModeNV; + + +typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMemoryRequirementsTypeNV; + +typedef enum VkGeometryFlagBitsKHR { + VK_GEOMETRY_OPAQUE_BIT_KHR = 0x00000001, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR = 0x00000002, + VK_GEOMETRY_OPAQUE_BIT_NV = VK_GEOMETRY_OPAQUE_BIT_KHR, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR, + VK_GEOMETRY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryFlagBitsKHR; +typedef VkFlags VkGeometryFlagsKHR; +typedef VkGeometryFlagsKHR VkGeometryFlagsNV; + +typedef VkGeometryFlagBitsKHR VkGeometryFlagBitsNV; + + +typedef enum VkGeometryInstanceFlagBitsKHR { + VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR = 0x00000001, + VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR = 0x00000002, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR = 0x00000004, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR = 0x00000008, + VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_EXT = 0x00000010, + VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_EXT = 0x00000020, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR, + VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryInstanceFlagBitsKHR; +typedef VkFlags VkGeometryInstanceFlagsKHR; +typedef VkGeometryInstanceFlagsKHR VkGeometryInstanceFlagsNV; + +typedef VkGeometryInstanceFlagBitsKHR VkGeometryInstanceFlagBitsNV; + + +typedef enum VkBuildAccelerationStructureFlagBitsKHR { + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR = 0x00000001, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR = 0x00000002, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR = 0x00000004, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR = 0x00000008, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR = 0x00000010, + VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV = 0x00000020, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_EXT = 0x00000040, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_EXT = 0x00000080, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT = 0x00000100, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISPLACEMENT_MICROMAP_UPDATE_NV = 0x00000200, +#endif + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DATA_ACCESS_KHR = 0x00000800, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureFlagBitsKHR; +typedef VkFlags VkBuildAccelerationStructureFlagsKHR; +typedef VkBuildAccelerationStructureFlagsKHR VkBuildAccelerationStructureFlagsNV; + +typedef VkBuildAccelerationStructureFlagBitsKHR VkBuildAccelerationStructureFlagBitsNV; + +typedef struct VkRayTracingShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeKHR type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; +} VkRayTracingShaderGroupCreateInfoNV; + +typedef struct VkRayTracingPipelineCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoNV* pGroups; + uint32_t maxRecursionDepth; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoNV; + +typedef struct VkGeometryTrianglesNV { + VkStructureType sType; + const void* pNext; + VkBuffer vertexData; + VkDeviceSize vertexOffset; + uint32_t vertexCount; + VkDeviceSize vertexStride; + VkFormat vertexFormat; + VkBuffer indexData; + VkDeviceSize indexOffset; + uint32_t indexCount; + VkIndexType indexType; + VkBuffer transformData; + VkDeviceSize transformOffset; +} VkGeometryTrianglesNV; + +typedef struct VkGeometryAABBNV { + VkStructureType sType; + const void* pNext; + VkBuffer aabbData; + uint32_t numAABBs; + uint32_t stride; + VkDeviceSize offset; +} VkGeometryAABBNV; + +typedef struct VkGeometryDataNV { + VkGeometryTrianglesNV triangles; + VkGeometryAABBNV aabbs; +} VkGeometryDataNV; + +typedef struct VkGeometryNV { + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + VkGeometryDataNV geometry; + VkGeometryFlagsKHR flags; +} VkGeometryNV; + +typedef struct VkAccelerationStructureInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeNV type; + VkBuildAccelerationStructureFlagsNV flags; + uint32_t instanceCount; + uint32_t geometryCount; + const VkGeometryNV* pGeometries; +} VkAccelerationStructureInfoNV; + +typedef struct VkAccelerationStructureCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceSize compactedSize; + VkAccelerationStructureInfoNV info; +} VkAccelerationStructureCreateInfoNV; + +typedef struct VkBindAccelerationStructureMemoryInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureNV accelerationStructure; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindAccelerationStructureMemoryInfoNV; + +typedef struct VkWriteDescriptorSetAccelerationStructureNV { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureNV* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureNV; + +typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureMemoryRequirementsTypeNV type; + VkAccelerationStructureNV accelerationStructure; +} VkAccelerationStructureMemoryRequirementsInfoNV; + +typedef struct VkPhysicalDeviceRayTracingPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxTriangleCount; + uint32_t maxDescriptorSetAccelerationStructures; +} VkPhysicalDeviceRayTracingPropertiesNV; + +typedef struct VkTransformMatrixKHR { + float matrix[3][4]; +} VkTransformMatrixKHR; + +typedef VkTransformMatrixKHR VkTransformMatrixNV; + +typedef struct VkAabbPositionsKHR { + float minX; + float minY; + float minZ; + float maxX; + float maxY; + float maxZ; +} VkAabbPositionsKHR; + +typedef VkAabbPositionsKHR VkAabbPositionsNV; + +typedef struct VkAccelerationStructureInstanceKHR { + VkTransformMatrixKHR transform; + uint32_t instanceCustomIndex:24; + uint32_t mask:8; + uint32_t instanceShaderBindingTableRecordOffset:24; + VkGeometryInstanceFlagsKHR flags:8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureInstanceKHR; + +typedef VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeKHR mode); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV( + VkDevice device, + const VkAccelerationStructureCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureNV* pAccelerationStructure); + +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV( + VkDevice device, + VkAccelerationStructureNV accelerationStructure, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV( + VkDevice device, + const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, + VkMemoryRequirements2KHR* pMemoryRequirements); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV( + VkDevice device, + uint32_t bindInfoCount, + const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV( + VkCommandBuffer commandBuffer, + const VkAccelerationStructureInfoNV* pInfo, + VkBuffer instanceData, + VkDeviceSize instanceOffset, + VkBool32 update, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkBuffer scratch, + VkDeviceSize scratchOffset); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV( + VkCommandBuffer commandBuffer, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkCopyAccelerationStructureModeKHR mode); + +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV( + VkCommandBuffer commandBuffer, + VkBuffer raygenShaderBindingTableBuffer, + VkDeviceSize raygenShaderBindingOffset, + VkBuffer missShaderBindingTableBuffer, + VkDeviceSize missShaderBindingOffset, + VkDeviceSize missShaderBindingStride, + VkBuffer hitShaderBindingTableBuffer, + VkDeviceSize hitShaderBindingOffset, + VkDeviceSize hitShaderBindingStride, + VkBuffer callableShaderBindingTableBuffer, + VkDeviceSize callableShaderBindingOffset, + VkDeviceSize callableShaderBindingStride, + uint32_t width, + uint32_t height, + uint32_t depth); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoNV* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV( + VkDevice device, + VkAccelerationStructureNV accelerationStructure, + size_t dataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV( + VkCommandBuffer commandBuffer, + uint32_t accelerationStructureCount, + const VkAccelerationStructureNV* pAccelerationStructures, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); + +VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV( + VkDevice device, + VkPipeline pipeline, + uint32_t shader); +#endif + + +// VK_NV_representative_fragment_test is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_representative_fragment_test 1 +#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 2 +#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" +typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 representativeFragmentTest; +} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; + +typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 representativeFragmentTestEnable; +} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; + + + +// VK_EXT_filter_cubic is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_filter_cubic 1 +#define VK_EXT_FILTER_CUBIC_SPEC_VERSION 3 +#define VK_EXT_FILTER_CUBIC_EXTENSION_NAME "VK_EXT_filter_cubic" +typedef struct VkPhysicalDeviceImageViewImageFormatInfoEXT { + VkStructureType sType; + void* pNext; + VkImageViewType imageViewType; +} VkPhysicalDeviceImageViewImageFormatInfoEXT; + +typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 filterCubic; + VkBool32 filterCubicMinmax; +} VkFilterCubicImageViewImageFormatPropertiesEXT; + + + +// VK_QCOM_render_pass_shader_resolve is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_render_pass_shader_resolve 1 +#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_SPEC_VERSION 4 +#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME "VK_QCOM_render_pass_shader_resolve" + + +// VK_EXT_global_priority is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_global_priority 1 +#define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 +#define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" +typedef VkQueueGlobalPriorityKHR VkQueueGlobalPriorityEXT; + +typedef VkDeviceQueueGlobalPriorityCreateInfoKHR VkDeviceQueueGlobalPriorityCreateInfoEXT; + + + +// VK_EXT_external_memory_host is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_external_memory_host 1 +#define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" +typedef struct VkImportMemoryHostPointerInfoEXT { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + void* pHostPointer; +} VkImportMemoryHostPointerInfoEXT; + +typedef struct VkMemoryHostPointerPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryHostPointerPropertiesEXT; + +typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize minImportedHostPointerAlignment; +} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void* pHostPointer, VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + const void* pHostPointer, + VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); +#endif + + +// VK_AMD_buffer_marker is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_buffer_marker 1 +#define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 +#define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" +typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarkerAMD( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + uint32_t marker); +#endif + + +// VK_AMD_pipeline_compiler_control is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_pipeline_compiler_control 1 +#define VK_AMD_PIPELINE_COMPILER_CONTROL_SPEC_VERSION 1 +#define VK_AMD_PIPELINE_COMPILER_CONTROL_EXTENSION_NAME "VK_AMD_pipeline_compiler_control" + +typedef enum VkPipelineCompilerControlFlagBitsAMD { + VK_PIPELINE_COMPILER_CONTROL_FLAG_BITS_MAX_ENUM_AMD = 0x7FFFFFFF +} VkPipelineCompilerControlFlagBitsAMD; +typedef VkFlags VkPipelineCompilerControlFlagsAMD; +typedef struct VkPipelineCompilerControlCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkPipelineCompilerControlFlagsAMD compilerControlFlags; +} VkPipelineCompilerControlCreateInfoAMD; + + + +// VK_EXT_calibrated_timestamps is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_calibrated_timestamps 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 2 +#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" + +typedef enum VkTimeDomainEXT { + VK_TIME_DOMAIN_DEVICE_EXT = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, + VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} VkTimeDomainEXT; +typedef struct VkCalibratedTimestampInfoEXT { + VkStructureType sType; + const void* pNext; + VkTimeDomainEXT timeDomain; +} VkCalibratedTimestampInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains); +typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pTimeDomainCount, + VkTimeDomainEXT* pTimeDomains); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT( + VkDevice device, + uint32_t timestampCount, + const VkCalibratedTimestampInfoEXT* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation); +#endif + + +// VK_AMD_shader_core_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_core_properties 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 2 +#define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" +typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { + VkStructureType sType; + void* pNext; + uint32_t shaderEngineCount; + uint32_t shaderArraysPerEngineCount; + uint32_t computeUnitsPerShaderArray; + uint32_t simdPerComputeUnit; + uint32_t wavefrontsPerSimd; + uint32_t wavefrontSize; + uint32_t sgprsPerSimd; + uint32_t minSgprAllocation; + uint32_t maxSgprAllocation; + uint32_t sgprAllocationGranularity; + uint32_t vgprsPerSimd; + uint32_t minVgprAllocation; + uint32_t maxVgprAllocation; + uint32_t vgprAllocationGranularity; +} VkPhysicalDeviceShaderCorePropertiesAMD; + + + +// VK_AMD_memory_overallocation_behavior is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_memory_overallocation_behavior 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" + +typedef enum VkMemoryOverallocationBehaviorAMD { + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF +} VkMemoryOverallocationBehaviorAMD; +typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkMemoryOverallocationBehaviorAMD overallocationBehavior; +} VkDeviceMemoryOverallocationCreateInfoAMD; + + + +// VK_EXT_vertex_attribute_divisor is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_vertex_attribute_divisor 1 +#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 +#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" +typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxVertexAttribDivisor; +} VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT; + +typedef struct VkVertexInputBindingDivisorDescriptionEXT { + uint32_t binding; + uint32_t divisor; +} VkVertexInputBindingDivisorDescriptionEXT; + +typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t vertexBindingDivisorCount; + const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors; +} VkPipelineVertexInputDivisorStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; +} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; + + + +// VK_EXT_pipeline_creation_feedback is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_creation_feedback 1 +#define VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME "VK_EXT_pipeline_creation_feedback" +typedef VkPipelineCreationFeedbackFlagBits VkPipelineCreationFeedbackFlagBitsEXT; + +typedef VkPipelineCreationFeedbackFlags VkPipelineCreationFeedbackFlagsEXT; + +typedef VkPipelineCreationFeedbackCreateInfo VkPipelineCreationFeedbackCreateInfoEXT; + +typedef VkPipelineCreationFeedback VkPipelineCreationFeedbackEXT; + + + +// VK_NV_shader_subgroup_partitioned is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shader_subgroup_partitioned 1 +#define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1 +#define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned" + + +// VK_NV_compute_shader_derivatives is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_compute_shader_derivatives 1 +#define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" +typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 computeDerivativeGroupQuads; + VkBool32 computeDerivativeGroupLinear; +} VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; + + + +// VK_NV_mesh_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_mesh_shader 1 +#define VK_NV_MESH_SHADER_SPEC_VERSION 1 +#define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" +typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 taskShader; + VkBool32 meshShader; +} VkPhysicalDeviceMeshShaderFeaturesNV; + +typedef struct VkPhysicalDeviceMeshShaderPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxDrawMeshTasksCount; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxTaskWorkGroupSize[3]; + uint32_t maxTaskTotalMemorySize; + uint32_t maxTaskOutputCount; + uint32_t maxMeshWorkGroupInvocations; + uint32_t maxMeshWorkGroupSize[3]; + uint32_t maxMeshTotalMemorySize; + uint32_t maxMeshOutputVertices; + uint32_t maxMeshOutputPrimitives; + uint32_t maxMeshMultiviewViewCount; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; +} VkPhysicalDeviceMeshShaderPropertiesNV; + +typedef struct VkDrawMeshTasksIndirectCommandNV { + uint32_t taskCount; + uint32_t firstTask; +} VkDrawMeshTasksIndirectCommandNV; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksNV)(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksNV( + VkCommandBuffer commandBuffer, + uint32_t taskCount, + uint32_t firstTask); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectNV( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountNV( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + + +// VK_NV_fragment_shader_barycentric is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_fragment_shader_barycentric 1 +#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" +typedef VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; + + + +// VK_NV_shader_image_footprint is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shader_image_footprint 1 +#define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 2 +#define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" +typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 imageFootprint; +} VkPhysicalDeviceShaderImageFootprintFeaturesNV; + + + +// VK_NV_scissor_exclusive is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_scissor_exclusive 1 +#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 2 +#define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" +typedef struct VkPipelineViewportExclusiveScissorStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t exclusiveScissorCount; + const VkRect2D* pExclusiveScissors; +} VkPipelineViewportExclusiveScissorStateCreateInfoNV; + +typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 exclusiveScissor; +} VkPhysicalDeviceExclusiveScissorFeaturesNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetExclusiveScissorEnableNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkBool32* pExclusiveScissorEnables); +typedef void (VKAPI_PTR *PFN_vkCmdSetExclusiveScissorNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D* pExclusiveScissors); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetExclusiveScissorEnableNV( + VkCommandBuffer commandBuffer, + uint32_t firstExclusiveScissor, + uint32_t exclusiveScissorCount, + const VkBool32* pExclusiveScissorEnables); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetExclusiveScissorNV( + VkCommandBuffer commandBuffer, + uint32_t firstExclusiveScissor, + uint32_t exclusiveScissorCount, + const VkRect2D* pExclusiveScissors); +#endif + + +// VK_NV_device_diagnostic_checkpoints is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_device_diagnostic_checkpoints 1 +#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 +#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" +typedef struct VkQueueFamilyCheckpointPropertiesNV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags checkpointExecutionStageMask; +} VkQueueFamilyCheckpointPropertiesNV; + +typedef struct VkCheckpointDataNV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlagBits stage; + void* pCheckpointMarker; +} VkCheckpointDataNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer commandBuffer, const void* pCheckpointMarker); +typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointDataNV* pCheckpointData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCheckpointNV( + VkCommandBuffer commandBuffer, + const void* pCheckpointMarker); + +VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointDataNV( + VkQueue queue, + uint32_t* pCheckpointDataCount, + VkCheckpointDataNV* pCheckpointData); +#endif + + +// VK_INTEL_shader_integer_functions2 is a preprocessor guard. Do not pass it to API calls. +#define VK_INTEL_shader_integer_functions2 1 +#define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_SPEC_VERSION 1 +#define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_EXTENSION_NAME "VK_INTEL_shader_integer_functions2" +typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL { + VkStructureType sType; + void* pNext; + VkBool32 shaderIntegerFunctions2; +} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL; + + + +// VK_INTEL_performance_query is a preprocessor guard. Do not pass it to API calls. +#define VK_INTEL_performance_query 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) +#define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 2 +#define VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME "VK_INTEL_performance_query" + +typedef enum VkPerformanceConfigurationTypeINTEL { + VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0, + VK_PERFORMANCE_CONFIGURATION_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceConfigurationTypeINTEL; + +typedef enum VkQueryPoolSamplingModeINTEL { + VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0, + VK_QUERY_POOL_SAMPLING_MODE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkQueryPoolSamplingModeINTEL; + +typedef enum VkPerformanceOverrideTypeINTEL { + VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL = 0, + VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1, + VK_PERFORMANCE_OVERRIDE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceOverrideTypeINTEL; + +typedef enum VkPerformanceParameterTypeINTEL { + VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL = 0, + VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1, + VK_PERFORMANCE_PARAMETER_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceParameterTypeINTEL; + +typedef enum VkPerformanceValueTypeINTEL { + VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL = 0, + VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL = 1, + VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL = 2, + VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL = 3, + VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4, + VK_PERFORMANCE_VALUE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceValueTypeINTEL; +typedef union VkPerformanceValueDataINTEL { + uint32_t value32; + uint64_t value64; + float valueFloat; + VkBool32 valueBool; + const char* valueString; +} VkPerformanceValueDataINTEL; + +typedef struct VkPerformanceValueINTEL { + VkPerformanceValueTypeINTEL type; + VkPerformanceValueDataINTEL data; +} VkPerformanceValueINTEL; + +typedef struct VkInitializePerformanceApiInfoINTEL { + VkStructureType sType; + const void* pNext; + void* pUserData; +} VkInitializePerformanceApiInfoINTEL; + +typedef struct VkQueryPoolPerformanceQueryCreateInfoINTEL { + VkStructureType sType; + const void* pNext; + VkQueryPoolSamplingModeINTEL performanceCountersSampling; +} VkQueryPoolPerformanceQueryCreateInfoINTEL; + +typedef VkQueryPoolPerformanceQueryCreateInfoINTEL VkQueryPoolCreateInfoINTEL; + +typedef struct VkPerformanceMarkerInfoINTEL { + VkStructureType sType; + const void* pNext; + uint64_t marker; +} VkPerformanceMarkerInfoINTEL; + +typedef struct VkPerformanceStreamMarkerInfoINTEL { + VkStructureType sType; + const void* pNext; + uint32_t marker; +} VkPerformanceStreamMarkerInfoINTEL; + +typedef struct VkPerformanceOverrideInfoINTEL { + VkStructureType sType; + const void* pNext; + VkPerformanceOverrideTypeINTEL type; + VkBool32 enable; + uint64_t parameter; +} VkPerformanceOverrideInfoINTEL; + +typedef struct VkPerformanceConfigurationAcquireInfoINTEL { + VkStructureType sType; + const void* pNext; + VkPerformanceConfigurationTypeINTEL type; +} VkPerformanceConfigurationAcquireInfoINTEL; + +typedef VkResult (VKAPI_PTR *PFN_vkInitializePerformanceApiINTEL)(VkDevice device, const VkInitializePerformanceApiInfoINTEL* pInitializeInfo); +typedef void (VKAPI_PTR *PFN_vkUninitializePerformanceApiINTEL)(VkDevice device); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL* pMarkerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceStreamMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceOverrideINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL* pOverrideInfo); +typedef VkResult (VKAPI_PTR *PFN_vkAcquirePerformanceConfigurationINTEL)(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo, VkPerformanceConfigurationINTEL* pConfiguration); +typedef VkResult (VKAPI_PTR *PFN_vkReleasePerformanceConfigurationINTEL)(VkDevice device, VkPerformanceConfigurationINTEL configuration); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSetPerformanceConfigurationINTEL)(VkQueue queue, VkPerformanceConfigurationINTEL configuration); +typedef VkResult (VKAPI_PTR *PFN_vkGetPerformanceParameterINTEL)(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL* pValue); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkInitializePerformanceApiINTEL( + VkDevice device, + const VkInitializePerformanceApiInfoINTEL* pInitializeInfo); + +VKAPI_ATTR void VKAPI_CALL vkUninitializePerformanceApiINTEL( + VkDevice device); + +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceMarkerINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceMarkerInfoINTEL* pMarkerInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceStreamMarkerINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceOverrideINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceOverrideInfoINTEL* pOverrideInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquirePerformanceConfigurationINTEL( + VkDevice device, + const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo, + VkPerformanceConfigurationINTEL* pConfiguration); + +VKAPI_ATTR VkResult VKAPI_CALL vkReleasePerformanceConfigurationINTEL( + VkDevice device, + VkPerformanceConfigurationINTEL configuration); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSetPerformanceConfigurationINTEL( + VkQueue queue, + VkPerformanceConfigurationINTEL configuration); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPerformanceParameterINTEL( + VkDevice device, + VkPerformanceParameterTypeINTEL parameter, + VkPerformanceValueINTEL* pValue); +#endif + + +// VK_EXT_pci_bus_info is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pci_bus_info 1 +#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 +#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" +typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t pciDomain; + uint32_t pciBus; + uint32_t pciDevice; + uint32_t pciFunction; +} VkPhysicalDevicePCIBusInfoPropertiesEXT; + + + +// VK_AMD_display_native_hdr is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_display_native_hdr 1 +#define VK_AMD_DISPLAY_NATIVE_HDR_SPEC_VERSION 1 +#define VK_AMD_DISPLAY_NATIVE_HDR_EXTENSION_NAME "VK_AMD_display_native_hdr" +typedef struct VkDisplayNativeHdrSurfaceCapabilitiesAMD { + VkStructureType sType; + void* pNext; + VkBool32 localDimmingSupport; +} VkDisplayNativeHdrSurfaceCapabilitiesAMD; + +typedef struct VkSwapchainDisplayNativeHdrCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkBool32 localDimmingEnable; +} VkSwapchainDisplayNativeHdrCreateInfoAMD; + +typedef void (VKAPI_PTR *PFN_vkSetLocalDimmingAMD)(VkDevice device, VkSwapchainKHR swapChain, VkBool32 localDimmingEnable); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetLocalDimmingAMD( + VkDevice device, + VkSwapchainKHR swapChain, + VkBool32 localDimmingEnable); +#endif + + +// VK_EXT_fragment_density_map is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_fragment_density_map 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 2 +#define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" +typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMap; + VkBool32 fragmentDensityMapDynamic; + VkBool32 fragmentDensityMapNonSubsampledImages; +} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { + VkStructureType sType; + void* pNext; + VkExtent2D minFragmentDensityTexelSize; + VkExtent2D maxFragmentDensityTexelSize; + VkBool32 fragmentDensityInvocations; +} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; + +typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkAttachmentReference fragmentDensityMapAttachment; +} VkRenderPassFragmentDensityMapCreateInfoEXT; + + + +// VK_EXT_scalar_block_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_scalar_block_layout 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" +typedef VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; + + + +// VK_GOOGLE_hlsl_functionality1 is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_hlsl_functionality1 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME + + +// VK_GOOGLE_decorate_string is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_decorate_string 1 +#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 +#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" + + +// VK_EXT_subgroup_size_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_subgroup_size_control 1 +#define VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION 2 +#define VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME "VK_EXT_subgroup_size_control" +typedef VkPhysicalDeviceSubgroupSizeControlFeatures VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; + +typedef VkPhysicalDeviceSubgroupSizeControlProperties VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; + +typedef VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; + + + +// VK_AMD_shader_core_properties2 is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_core_properties2 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_2_SPEC_VERSION 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_2_EXTENSION_NAME "VK_AMD_shader_core_properties2" + +typedef enum VkShaderCorePropertiesFlagBitsAMD { + VK_SHADER_CORE_PROPERTIES_FLAG_BITS_MAX_ENUM_AMD = 0x7FFFFFFF +} VkShaderCorePropertiesFlagBitsAMD; +typedef VkFlags VkShaderCorePropertiesFlagsAMD; +typedef struct VkPhysicalDeviceShaderCoreProperties2AMD { + VkStructureType sType; + void* pNext; + VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; + uint32_t activeComputeUnitCount; +} VkPhysicalDeviceShaderCoreProperties2AMD; + + + +// VK_AMD_device_coherent_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_device_coherent_memory 1 +#define VK_AMD_DEVICE_COHERENT_MEMORY_SPEC_VERSION 1 +#define VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME "VK_AMD_device_coherent_memory" +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD { + VkStructureType sType; + void* pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; + + + +// VK_EXT_shader_image_atomic_int64 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_image_atomic_int64 1 +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME "VK_EXT_shader_image_atomic_int64" +typedef struct VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderImageInt64Atomics; + VkBool32 sparseImageInt64Atomics; +} VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT; + + + +// VK_EXT_memory_budget is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_memory_budget 1 +#define VK_EXT_MEMORY_BUDGET_SPEC_VERSION 1 +#define VK_EXT_MEMORY_BUDGET_EXTENSION_NAME "VK_EXT_memory_budget" +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; + + + +// VK_EXT_memory_priority is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_memory_priority 1 +#define VK_EXT_MEMORY_PRIORITY_SPEC_VERSION 1 +#define VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME "VK_EXT_memory_priority" +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; + +typedef struct VkMemoryPriorityAllocateInfoEXT { + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; + + + +// VK_NV_dedicated_allocation_image_aliasing is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_dedicated_allocation_image_aliasing 1 +#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION 1 +#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME "VK_NV_dedicated_allocation_image_aliasing" +typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 dedicatedAllocationImageAliasing; +} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; + + + +// VK_EXT_buffer_device_address is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_buffer_device_address 1 +#define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 +#define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; + +typedef VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; + +typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoEXT; + +typedef struct VkBufferDeviceAddressCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceAddress deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; + +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressEXT( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); +#endif + + +// VK_EXT_tooling_info is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_tooling_info 1 +#define VK_EXT_TOOLING_INFO_SPEC_VERSION 1 +#define VK_EXT_TOOLING_INFO_EXTENSION_NAME "VK_EXT_tooling_info" +typedef VkToolPurposeFlagBits VkToolPurposeFlagBitsEXT; + +typedef VkToolPurposeFlags VkToolPurposeFlagsEXT; + +typedef VkPhysicalDeviceToolProperties VkPhysicalDeviceToolPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolProperties* pToolProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceToolPropertiesEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pToolCount, + VkPhysicalDeviceToolProperties* pToolProperties); +#endif + + +// VK_EXT_separate_stencil_usage is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_separate_stencil_usage 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" +typedef VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; + + + +// VK_EXT_validation_features is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_validation_features 1 +#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 5 +#define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" + +typedef enum VkValidationFeatureEnableEXT { + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2, + VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT = 3, + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT = 4, + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; + +typedef enum VkValidationFeatureDisableEXT { + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT = 7, + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; +typedef struct VkValidationFeaturesEXT { + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; + + + +// VK_NV_cooperative_matrix is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cooperative_matrix 1 +#define VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_NV_cooperative_matrix" +typedef VkComponentTypeKHR VkComponentTypeNV; + +typedef VkScopeKHR VkScopeNV; + +typedef struct VkCooperativeMatrixPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; + +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; + +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV { + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesNV( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkCooperativeMatrixPropertiesNV* pProperties); +#endif + + +// VK_NV_coverage_reduction_mode is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_coverage_reduction_mode 1 +#define VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION 1 +#define VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME "VK_NV_coverage_reduction_mode" + +typedef enum VkCoverageReductionModeNV { + VK_COVERAGE_REDUCTION_MODE_MERGE_NV = 0, + VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1, + VK_COVERAGE_REDUCTION_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoverageReductionModeNV; +typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; +typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 coverageReductionMode; +} VkPhysicalDeviceCoverageReductionModeFeaturesNV; + +typedef struct VkPipelineCoverageReductionStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageReductionStateCreateFlagsNV flags; + VkCoverageReductionModeNV coverageReductionMode; +} VkPipelineCoverageReductionStateCreateInfoNV; + +typedef struct VkFramebufferMixedSamplesCombinationNV { + VkStructureType sType; + void* pNext; + VkCoverageReductionModeNV coverageReductionMode; + VkSampleCountFlagBits rasterizationSamples; + VkSampleCountFlags depthStencilSamples; + VkSampleCountFlags colorSamples; +} VkFramebufferMixedSamplesCombinationNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)(VkPhysicalDevice physicalDevice, uint32_t* pCombinationCount, VkFramebufferMixedSamplesCombinationNV* pCombinations); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV( + VkPhysicalDevice physicalDevice, + uint32_t* pCombinationCount, + VkFramebufferMixedSamplesCombinationNV* pCombinations); +#endif + + +// VK_EXT_fragment_shader_interlock is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_fragment_shader_interlock 1 +#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME "VK_EXT_fragment_shader_interlock" +typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShaderSampleInterlock; + VkBool32 fragmentShaderPixelInterlock; + VkBool32 fragmentShaderShadingRateInterlock; +} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; + + + +// VK_EXT_ycbcr_image_arrays is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_ycbcr_image_arrays 1 +#define VK_EXT_YCBCR_IMAGE_ARRAYS_SPEC_VERSION 1 +#define VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME "VK_EXT_ycbcr_image_arrays" +typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 ycbcrImageArrays; +} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; + + + +// VK_EXT_provoking_vertex is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_provoking_vertex 1 +#define VK_EXT_PROVOKING_VERTEX_SPEC_VERSION 1 +#define VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME "VK_EXT_provoking_vertex" + +typedef enum VkProvokingVertexModeEXT { + VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT = 0, + VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT = 1, + VK_PROVOKING_VERTEX_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkProvokingVertexModeEXT; +typedef struct VkPhysicalDeviceProvokingVertexFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 provokingVertexLast; + VkBool32 transformFeedbackPreservesProvokingVertex; +} VkPhysicalDeviceProvokingVertexFeaturesEXT; + +typedef struct VkPhysicalDeviceProvokingVertexPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 provokingVertexModePerPipeline; + VkBool32 transformFeedbackPreservesTriangleFanProvokingVertex; +} VkPhysicalDeviceProvokingVertexPropertiesEXT; + +typedef struct VkPipelineRasterizationProvokingVertexStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkProvokingVertexModeEXT provokingVertexMode; +} VkPipelineRasterizationProvokingVertexStateCreateInfoEXT; + + + +// VK_EXT_headless_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_headless_surface 1 +#define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 1 +#define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface" +typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; +typedef struct VkHeadlessSurfaceCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkHeadlessSurfaceCreateFlagsEXT flags; +} VkHeadlessSurfaceCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance instance, const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateHeadlessSurfaceEXT( + VkInstance instance, + const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +// VK_EXT_line_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_line_rasterization 1 +#define VK_EXT_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME "VK_EXT_line_rasterization" + +typedef enum VkLineRasterizationModeEXT { + VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = 0, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = 1, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = 2, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = 3, + VK_LINE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkLineRasterizationModeEXT; +typedef struct VkPhysicalDeviceLineRasterizationFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; +} VkPhysicalDeviceLineRasterizationFeaturesEXT; + +typedef struct VkPhysicalDeviceLineRasterizationPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t lineSubPixelPrecisionBits; +} VkPhysicalDeviceLineRasterizationPropertiesEXT; + +typedef struct VkPipelineRasterizationLineStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkLineRasterizationModeEXT lineRasterizationMode; + VkBool32 stippledLineEnable; + uint32_t lineStippleFactor; + uint16_t lineStipplePattern; +} VkPipelineRasterizationLineStateCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleEXT)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleEXT( + VkCommandBuffer commandBuffer, + uint32_t lineStippleFactor, + uint16_t lineStipplePattern); +#endif + + +// VK_EXT_shader_atomic_float is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_atomic_float 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_SPEC_VERSION 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME "VK_EXT_shader_atomic_float" +typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferFloat32Atomics; + VkBool32 shaderBufferFloat32AtomicAdd; + VkBool32 shaderBufferFloat64Atomics; + VkBool32 shaderBufferFloat64AtomicAdd; + VkBool32 shaderSharedFloat32Atomics; + VkBool32 shaderSharedFloat32AtomicAdd; + VkBool32 shaderSharedFloat64Atomics; + VkBool32 shaderSharedFloat64AtomicAdd; + VkBool32 shaderImageFloat32Atomics; + VkBool32 shaderImageFloat32AtomicAdd; + VkBool32 sparseImageFloat32Atomics; + VkBool32 sparseImageFloat32AtomicAdd; +} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT; + + + +// VK_EXT_host_query_reset is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_host_query_reset 1 +#define VK_EXT_HOST_QUERY_RESET_SPEC_VERSION 1 +#define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME "VK_EXT_host_query_reset" +typedef VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkResetQueryPoolEXT)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkResetQueryPoolEXT( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); +#endif + + +// VK_EXT_index_type_uint8 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_index_type_uint8 1 +#define VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION 1 +#define VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_EXT_index_type_uint8" +typedef struct VkPhysicalDeviceIndexTypeUint8FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 indexTypeUint8; +} VkPhysicalDeviceIndexTypeUint8FeaturesEXT; + + + +// VK_EXT_extended_dynamic_state is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_extended_dynamic_state 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_extended_dynamic_state" +typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 extendedDynamicState; +} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetCullModeEXT)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetFrontFaceEXT)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveTopologyEXT)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissorWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers2EXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes, const VkDeviceSize* pStrides); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthWriteEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthCompareOpEXT)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBoundsTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilOpEXT)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCullModeEXT( + VkCommandBuffer commandBuffer, + VkCullModeFlags cullMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetFrontFaceEXT( + VkCommandBuffer commandBuffer, + VkFrontFace frontFace); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveTopologyEXT( + VkCommandBuffer commandBuffer, + VkPrimitiveTopology primitiveTopology); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWithCountEXT( + VkCommandBuffer commandBuffer, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissorWithCountEXT( + VkCommandBuffer commandBuffer, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers2EXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthWriteEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthWriteEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthCompareOpEXT( + VkCommandBuffer commandBuffer, + VkCompareOp depthCompareOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBoundsTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthBoundsTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 stencilTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilOpEXT( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp); +#endif + + +// VK_EXT_host_image_copy is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_host_image_copy 1 +#define VK_EXT_HOST_IMAGE_COPY_SPEC_VERSION 1 +#define VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME "VK_EXT_host_image_copy" + +typedef enum VkHostImageCopyFlagBitsEXT { + VK_HOST_IMAGE_COPY_MEMCPY_EXT = 0x00000001, + VK_HOST_IMAGE_COPY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkHostImageCopyFlagBitsEXT; +typedef VkFlags VkHostImageCopyFlagsEXT; +typedef struct VkPhysicalDeviceHostImageCopyFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 hostImageCopy; +} VkPhysicalDeviceHostImageCopyFeaturesEXT; + +typedef struct VkPhysicalDeviceHostImageCopyPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t copySrcLayoutCount; + VkImageLayout* pCopySrcLayouts; + uint32_t copyDstLayoutCount; + VkImageLayout* pCopyDstLayouts; + uint8_t optimalTilingLayoutUUID[VK_UUID_SIZE]; + VkBool32 identicalMemoryTypeRequirements; +} VkPhysicalDeviceHostImageCopyPropertiesEXT; + +typedef struct VkMemoryToImageCopyEXT { + VkStructureType sType; + const void* pNext; + const void* pHostPointer; + uint32_t memoryRowLength; + uint32_t memoryImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkMemoryToImageCopyEXT; + +typedef struct VkImageToMemoryCopyEXT { + VkStructureType sType; + const void* pNext; + void* pHostPointer; + uint32_t memoryRowLength; + uint32_t memoryImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkImageToMemoryCopyEXT; + +typedef struct VkCopyMemoryToImageInfoEXT { + VkStructureType sType; + const void* pNext; + VkHostImageCopyFlagsEXT flags; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkMemoryToImageCopyEXT* pRegions; +} VkCopyMemoryToImageInfoEXT; + +typedef struct VkCopyImageToMemoryInfoEXT { + VkStructureType sType; + const void* pNext; + VkHostImageCopyFlagsEXT flags; + VkImage srcImage; + VkImageLayout srcImageLayout; + uint32_t regionCount; + const VkImageToMemoryCopyEXT* pRegions; +} VkCopyImageToMemoryInfoEXT; + +typedef struct VkCopyImageToImageInfoEXT { + VkStructureType sType; + const void* pNext; + VkHostImageCopyFlagsEXT flags; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2* pRegions; +} VkCopyImageToImageInfoEXT; + +typedef struct VkHostImageLayoutTransitionInfoEXT { + VkStructureType sType; + const void* pNext; + VkImage image; + VkImageLayout oldLayout; + VkImageLayout newLayout; + VkImageSubresourceRange subresourceRange; +} VkHostImageLayoutTransitionInfoEXT; + +typedef struct VkSubresourceHostMemcpySizeEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize size; +} VkSubresourceHostMemcpySizeEXT; + +typedef struct VkHostImageCopyDevicePerformanceQueryEXT { + VkStructureType sType; + void* pNext; + VkBool32 optimalDeviceAccess; + VkBool32 identicalMemoryLayout; +} VkHostImageCopyDevicePerformanceQueryEXT; + +typedef VkSubresourceLayout2KHR VkSubresourceLayout2EXT; + +typedef VkImageSubresource2KHR VkImageSubresource2EXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToImageEXT)(VkDevice device, const VkCopyMemoryToImageInfoEXT* pCopyMemoryToImageInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyImageToMemoryEXT)(VkDevice device, const VkCopyImageToMemoryInfoEXT* pCopyImageToMemoryInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyImageToImageEXT)(VkDevice device, const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo); +typedef VkResult (VKAPI_PTR *PFN_vkTransitionImageLayoutEXT)(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfoEXT* pTransitions); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout2EXT)(VkDevice device, VkImage image, const VkImageSubresource2KHR* pSubresource, VkSubresourceLayout2KHR* pLayout); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToImageEXT( + VkDevice device, + const VkCopyMemoryToImageInfoEXT* pCopyMemoryToImageInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyImageToMemoryEXT( + VkDevice device, + const VkCopyImageToMemoryInfoEXT* pCopyImageToMemoryInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyImageToImageEXT( + VkDevice device, + const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkTransitionImageLayoutEXT( + VkDevice device, + uint32_t transitionCount, + const VkHostImageLayoutTransitionInfoEXT* pTransitions); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout2EXT( + VkDevice device, + VkImage image, + const VkImageSubresource2KHR* pSubresource, + VkSubresourceLayout2KHR* pLayout); +#endif + + +// VK_EXT_shader_atomic_float2 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_atomic_float2 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_2_SPEC_VERSION 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME "VK_EXT_shader_atomic_float2" +typedef struct VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferFloat16Atomics; + VkBool32 shaderBufferFloat16AtomicAdd; + VkBool32 shaderBufferFloat16AtomicMinMax; + VkBool32 shaderBufferFloat32AtomicMinMax; + VkBool32 shaderBufferFloat64AtomicMinMax; + VkBool32 shaderSharedFloat16Atomics; + VkBool32 shaderSharedFloat16AtomicAdd; + VkBool32 shaderSharedFloat16AtomicMinMax; + VkBool32 shaderSharedFloat32AtomicMinMax; + VkBool32 shaderSharedFloat64AtomicMinMax; + VkBool32 shaderImageFloat32AtomicMinMax; + VkBool32 sparseImageFloat32AtomicMinMax; +} VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT; + + + +// VK_EXT_surface_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_surface_maintenance1 1 +#define VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_surface_maintenance1" + +typedef enum VkPresentScalingFlagBitsEXT { + VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT = 0x00000001, + VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT = 0x00000002, + VK_PRESENT_SCALING_STRETCH_BIT_EXT = 0x00000004, + VK_PRESENT_SCALING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPresentScalingFlagBitsEXT; +typedef VkFlags VkPresentScalingFlagsEXT; + +typedef enum VkPresentGravityFlagBitsEXT { + VK_PRESENT_GRAVITY_MIN_BIT_EXT = 0x00000001, + VK_PRESENT_GRAVITY_MAX_BIT_EXT = 0x00000002, + VK_PRESENT_GRAVITY_CENTERED_BIT_EXT = 0x00000004, + VK_PRESENT_GRAVITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPresentGravityFlagBitsEXT; +typedef VkFlags VkPresentGravityFlagsEXT; +typedef struct VkSurfacePresentModeEXT { + VkStructureType sType; + void* pNext; + VkPresentModeKHR presentMode; +} VkSurfacePresentModeEXT; + +typedef struct VkSurfacePresentScalingCapabilitiesEXT { + VkStructureType sType; + void* pNext; + VkPresentScalingFlagsEXT supportedPresentScaling; + VkPresentGravityFlagsEXT supportedPresentGravityX; + VkPresentGravityFlagsEXT supportedPresentGravityY; + VkExtent2D minScaledImageExtent; + VkExtent2D maxScaledImageExtent; +} VkSurfacePresentScalingCapabilitiesEXT; + +typedef struct VkSurfacePresentModeCompatibilityEXT { + VkStructureType sType; + void* pNext; + uint32_t presentModeCount; + VkPresentModeKHR* pPresentModes; +} VkSurfacePresentModeCompatibilityEXT; + + + +// VK_EXT_swapchain_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_swapchain_maintenance1 1 +#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_swapchain_maintenance1" +typedef struct VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 swapchainMaintenance1; +} VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT; + +typedef struct VkSwapchainPresentFenceInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkFence* pFences; +} VkSwapchainPresentFenceInfoEXT; + +typedef struct VkSwapchainPresentModesCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t presentModeCount; + const VkPresentModeKHR* pPresentModes; +} VkSwapchainPresentModesCreateInfoEXT; + +typedef struct VkSwapchainPresentModeInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentModeKHR* pPresentModes; +} VkSwapchainPresentModeInfoEXT; + +typedef struct VkSwapchainPresentScalingCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPresentScalingFlagsEXT scalingBehavior; + VkPresentGravityFlagsEXT presentGravityX; + VkPresentGravityFlagsEXT presentGravityY; +} VkSwapchainPresentScalingCreateInfoEXT; + +typedef struct VkReleaseSwapchainImagesInfoEXT { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndexCount; + const uint32_t* pImageIndices; +} VkReleaseSwapchainImagesInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkReleaseSwapchainImagesEXT)(VkDevice device, const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseSwapchainImagesEXT( + VkDevice device, + const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo); +#endif + + +// VK_EXT_shader_demote_to_helper_invocation is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_demote_to_helper_invocation 1 +#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION 1 +#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME "VK_EXT_shader_demote_to_helper_invocation" +typedef VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; + + + +// VK_NV_device_generated_commands is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_device_generated_commands 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV) +#define VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 +#define VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NV_device_generated_commands" + +typedef enum VkIndirectCommandsTokenTypeNV { + VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV = 0, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV = 1, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV = 2, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV = 3, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV = 4, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV = 1000328000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NV = 1000428003, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NV = 1000428004, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectCommandsTokenTypeNV; + +typedef enum VkIndirectStateFlagBitsNV { + VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 0x00000001, + VK_INDIRECT_STATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectStateFlagBitsNV; +typedef VkFlags VkIndirectStateFlagsNV; + +typedef enum VkIndirectCommandsLayoutUsageFlagBitsNV { + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV = 0x00000001, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV = 0x00000002, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 0x00000004, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectCommandsLayoutUsageFlagBitsNV; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxGraphicsShaderGroupCount; + uint32_t maxIndirectSequenceCount; + uint32_t maxIndirectCommandsTokenCount; + uint32_t maxIndirectCommandsStreamCount; + uint32_t maxIndirectCommandsTokenOffset; + uint32_t maxIndirectCommandsStreamStride; + uint32_t minSequencesCountBufferOffsetAlignment; + uint32_t minSequencesIndexBufferOffsetAlignment; + uint32_t minIndirectCommandsBufferOffsetAlignment; +} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV; + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 deviceGeneratedCommands; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; + +typedef struct VkGraphicsShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; +} VkGraphicsShaderGroupCreateInfoNV; + +typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t groupCount; + const VkGraphicsShaderGroupCreateInfoNV* pGroups; + uint32_t pipelineCount; + const VkPipeline* pPipelines; +} VkGraphicsPipelineShaderGroupsCreateInfoNV; + +typedef struct VkBindShaderGroupIndirectCommandNV { + uint32_t groupIndex; +} VkBindShaderGroupIndirectCommandNV; + +typedef struct VkBindIndexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandNV; + +typedef struct VkBindVertexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandNV; + +typedef struct VkSetStateFlagsIndirectCommandNV { + uint32_t data; +} VkSetStateFlagsIndirectCommandNV; + +typedef struct VkIndirectCommandsStreamNV { + VkBuffer buffer; + VkDeviceSize offset; +} VkIndirectCommandsStreamNV; + +typedef struct VkIndirectCommandsLayoutTokenNV { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsTokenTypeNV tokenType; + uint32_t stream; + uint32_t offset; + uint32_t vertexBindingUnit; + VkBool32 vertexDynamicStride; + VkPipelineLayout pushconstantPipelineLayout; + VkShaderStageFlags pushconstantShaderStageFlags; + uint32_t pushconstantOffset; + uint32_t pushconstantSize; + VkIndirectStateFlagsNV indirectStateFlags; + uint32_t indexTypeCount; + const VkIndexType* pIndexTypes; + const uint32_t* pIndexTypeValues; +} VkIndirectCommandsLayoutTokenNV; + +typedef struct VkIndirectCommandsLayoutCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsLayoutUsageFlagsNV flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenNV* pTokens; + uint32_t streamCount; + const uint32_t* pStreamStrides; +} VkIndirectCommandsLayoutCreateInfoNV; + +typedef struct VkGeneratedCommandsInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t streamCount; + const VkIndirectCommandsStreamNV* pStreams; + uint32_t sequencesCount; + VkBuffer preprocessBuffer; + VkDeviceSize preprocessOffset; + VkDeviceSize preprocessSize; + VkBuffer sequencesCountBuffer; + VkDeviceSize sequencesCountOffset; + VkBuffer sequencesIndexBuffer; + VkDeviceSize sequencesIndexOffset; +} VkGeneratedCommandsInfoNV; + +typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t maxSequencesCount; +} VkGeneratedCommandsMemoryRequirementsInfoNV; + +typedef void (VKAPI_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsNV)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdPreprocessGeneratedCommandsNV)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteGeneratedCommandsNV)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipelineShaderGroupNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex); +typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNV)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNV* pIndirectCommandsLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNV)(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetGeneratedCommandsMemoryRequirementsNV( + VkDevice device, + const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkCmdPreprocessGeneratedCommandsNV( + VkCommandBuffer commandBuffer, + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteGeneratedCommandsNV( + VkCommandBuffer commandBuffer, + VkBool32 isPreprocessed, + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipelineShaderGroupNV( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline, + uint32_t groupIndex); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNV( + VkDevice device, + const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkIndirectCommandsLayoutNV* pIndirectCommandsLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNV( + VkDevice device, + VkIndirectCommandsLayoutNV indirectCommandsLayout, + const VkAllocationCallbacks* pAllocator); +#endif + + +// VK_NV_inherited_viewport_scissor is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_inherited_viewport_scissor 1 +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_SPEC_VERSION 1 +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME "VK_NV_inherited_viewport_scissor" +typedef struct VkPhysicalDeviceInheritedViewportScissorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 inheritedViewportScissor2D; +} VkPhysicalDeviceInheritedViewportScissorFeaturesNV; + +typedef struct VkCommandBufferInheritanceViewportScissorInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 viewportScissor2D; + uint32_t viewportDepthCount; + const VkViewport* pViewportDepths; +} VkCommandBufferInheritanceViewportScissorInfoNV; + + + +// VK_EXT_texel_buffer_alignment is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_texel_buffer_alignment 1 +#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION 1 +#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME "VK_EXT_texel_buffer_alignment" +typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 texelBufferAlignment; +} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; + +typedef VkPhysicalDeviceTexelBufferAlignmentProperties VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; + + + +// VK_QCOM_render_pass_transform is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_render_pass_transform 1 +#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 3 +#define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform" +typedef struct VkRenderPassTransformBeginInfoQCOM { + VkStructureType sType; + void* pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkRenderPassTransformBeginInfoQCOM; + +typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM { + VkStructureType sType; + void* pNext; + VkSurfaceTransformFlagBitsKHR transform; + VkRect2D renderArea; +} VkCommandBufferInheritanceRenderPassTransformInfoQCOM; + + + +// VK_EXT_depth_bias_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_bias_control 1 +#define VK_EXT_DEPTH_BIAS_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME "VK_EXT_depth_bias_control" + +typedef enum VkDepthBiasRepresentationEXT { + VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT = 0, + VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT = 1, + VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT = 2, + VK_DEPTH_BIAS_REPRESENTATION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDepthBiasRepresentationEXT; +typedef struct VkPhysicalDeviceDepthBiasControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthBiasControl; + VkBool32 leastRepresentableValueForceUnormRepresentation; + VkBool32 floatRepresentation; + VkBool32 depthBiasExact; +} VkPhysicalDeviceDepthBiasControlFeaturesEXT; + +typedef struct VkDepthBiasInfoEXT { + VkStructureType sType; + const void* pNext; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; +} VkDepthBiasInfoEXT; + +typedef struct VkDepthBiasRepresentationInfoEXT { + VkStructureType sType; + const void* pNext; + VkDepthBiasRepresentationEXT depthBiasRepresentation; + VkBool32 depthBiasExact; +} VkDepthBiasRepresentationInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias2EXT)(VkCommandBuffer commandBuffer, const VkDepthBiasInfoEXT* pDepthBiasInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias2EXT( + VkCommandBuffer commandBuffer, + const VkDepthBiasInfoEXT* pDepthBiasInfo); +#endif + + +// VK_EXT_device_memory_report is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_device_memory_report 1 +#define VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION 2 +#define VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME "VK_EXT_device_memory_report" + +typedef enum VkDeviceMemoryReportEventTypeEXT { + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT = 0, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT = 1, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT = 2, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT = 3, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT = 4, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceMemoryReportEventTypeEXT; +typedef VkFlags VkDeviceMemoryReportFlagsEXT; +typedef struct VkPhysicalDeviceDeviceMemoryReportFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 deviceMemoryReport; +} VkPhysicalDeviceDeviceMemoryReportFeaturesEXT; + +typedef struct VkDeviceMemoryReportCallbackDataEXT { + VkStructureType sType; + void* pNext; + VkDeviceMemoryReportFlagsEXT flags; + VkDeviceMemoryReportEventTypeEXT type; + uint64_t memoryObjectId; + VkDeviceSize size; + VkObjectType objectType; + uint64_t objectHandle; + uint32_t heapIndex; +} VkDeviceMemoryReportCallbackDataEXT; + +typedef void (VKAPI_PTR *PFN_vkDeviceMemoryReportCallbackEXT)( + const VkDeviceMemoryReportCallbackDataEXT* pCallbackData, + void* pUserData); + +typedef struct VkDeviceDeviceMemoryReportCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceMemoryReportFlagsEXT flags; + PFN_vkDeviceMemoryReportCallbackEXT pfnUserCallback; + void* pUserData; +} VkDeviceDeviceMemoryReportCreateInfoEXT; + + + +// VK_EXT_acquire_drm_display is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_acquire_drm_display 1 +#define VK_EXT_ACQUIRE_DRM_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_drm_display" +typedef VkResult (VKAPI_PTR *PFN_vkAcquireDrmDisplayEXT)(VkPhysicalDevice physicalDevice, int32_t drmFd, VkDisplayKHR display); +typedef VkResult (VKAPI_PTR *PFN_vkGetDrmDisplayEXT)(VkPhysicalDevice physicalDevice, int32_t drmFd, uint32_t connectorId, VkDisplayKHR* display); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireDrmDisplayEXT( + VkPhysicalDevice physicalDevice, + int32_t drmFd, + VkDisplayKHR display); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDrmDisplayEXT( + VkPhysicalDevice physicalDevice, + int32_t drmFd, + uint32_t connectorId, + VkDisplayKHR* display); +#endif + + +// VK_EXT_robustness2 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_robustness2 1 +#define VK_EXT_ROBUSTNESS_2_SPEC_VERSION 1 +#define VK_EXT_ROBUSTNESS_2_EXTENSION_NAME "VK_EXT_robustness2" +typedef struct VkPhysicalDeviceRobustness2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 robustBufferAccess2; + VkBool32 robustImageAccess2; + VkBool32 nullDescriptor; +} VkPhysicalDeviceRobustness2FeaturesEXT; + +typedef struct VkPhysicalDeviceRobustness2PropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize robustStorageBufferAccessSizeAlignment; + VkDeviceSize robustUniformBufferAccessSizeAlignment; +} VkPhysicalDeviceRobustness2PropertiesEXT; + + + +// VK_EXT_custom_border_color is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_custom_border_color 1 +#define VK_EXT_CUSTOM_BORDER_COLOR_SPEC_VERSION 12 +#define VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME "VK_EXT_custom_border_color" +typedef struct VkSamplerCustomBorderColorCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkClearColorValue customBorderColor; + VkFormat format; +} VkSamplerCustomBorderColorCreateInfoEXT; + +typedef struct VkPhysicalDeviceCustomBorderColorPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxCustomBorderColorSamplers; +} VkPhysicalDeviceCustomBorderColorPropertiesEXT; + +typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 customBorderColors; + VkBool32 customBorderColorWithoutFormat; +} VkPhysicalDeviceCustomBorderColorFeaturesEXT; + + + +// VK_GOOGLE_user_type is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_user_type 1 +#define VK_GOOGLE_USER_TYPE_SPEC_VERSION 1 +#define VK_GOOGLE_USER_TYPE_EXTENSION_NAME "VK_GOOGLE_user_type" + + +// VK_NV_present_barrier is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_present_barrier 1 +#define VK_NV_PRESENT_BARRIER_SPEC_VERSION 1 +#define VK_NV_PRESENT_BARRIER_EXTENSION_NAME "VK_NV_present_barrier" +typedef struct VkPhysicalDevicePresentBarrierFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 presentBarrier; +} VkPhysicalDevicePresentBarrierFeaturesNV; + +typedef struct VkSurfaceCapabilitiesPresentBarrierNV { + VkStructureType sType; + void* pNext; + VkBool32 presentBarrierSupported; +} VkSurfaceCapabilitiesPresentBarrierNV; + +typedef struct VkSwapchainPresentBarrierCreateInfoNV { + VkStructureType sType; + void* pNext; + VkBool32 presentBarrierEnable; +} VkSwapchainPresentBarrierCreateInfoNV; + + + +// VK_EXT_private_data is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_private_data 1 +typedef VkPrivateDataSlot VkPrivateDataSlotEXT; + +#define VK_EXT_PRIVATE_DATA_SPEC_VERSION 1 +#define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data" +typedef VkPrivateDataSlotCreateFlags VkPrivateDataSlotCreateFlagsEXT; + +typedef VkPhysicalDevicePrivateDataFeatures VkPhysicalDevicePrivateDataFeaturesEXT; + +typedef VkDevicePrivateDataCreateInfo VkDevicePrivateDataCreateInfoEXT; + +typedef VkPrivateDataSlotCreateInfo VkPrivateDataSlotCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlot* pPrivateDataSlot); +typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); +typedef void (VKAPI_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePrivateDataSlotEXT( + VkDevice device, + const VkPrivateDataSlotCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlot* pPrivateDataSlot); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPrivateDataSlotEXT( + VkDevice device, + VkPrivateDataSlot privateDataSlot, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t data); + +VKAPI_ATTR void VKAPI_CALL vkGetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t* pData); +#endif + + +// VK_EXT_pipeline_creation_cache_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_creation_cache_control 1 +#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION 3 +#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME "VK_EXT_pipeline_creation_cache_control" +typedef VkPhysicalDevicePipelineCreationCacheControlFeatures VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; + + + +// VK_NV_device_diagnostics_config is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_device_diagnostics_config 1 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 2 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME "VK_NV_device_diagnostics_config" + +typedef enum VkDeviceDiagnosticsConfigFlagBitsNV { + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV = 0x00000001, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV = 0x00000002, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 0x00000004, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_ERROR_REPORTING_BIT_NV = 0x00000008, + VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkDeviceDiagnosticsConfigFlagBitsNV; +typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; +typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 diagnosticsConfig; +} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; + +typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceDiagnosticsConfigFlagsNV flags; +} VkDeviceDiagnosticsConfigCreateInfoNV; + + + +// VK_QCOM_render_pass_store_ops is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_render_pass_store_ops 1 +#define VK_QCOM_RENDER_PASS_STORE_OPS_SPEC_VERSION 2 +#define VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" + + +// VK_NV_cuda_kernel_launch is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cuda_kernel_launch 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaModuleNV) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaFunctionNV) +#define VK_NV_CUDA_KERNEL_LAUNCH_SPEC_VERSION 2 +#define VK_NV_CUDA_KERNEL_LAUNCH_EXTENSION_NAME "VK_NV_cuda_kernel_launch" +typedef struct VkCudaModuleCreateInfoNV { + VkStructureType sType; + const void* pNext; + size_t dataSize; + const void* pData; +} VkCudaModuleCreateInfoNV; + +typedef struct VkCudaFunctionCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkCudaModuleNV module; + const char* pName; +} VkCudaFunctionCreateInfoNV; + +typedef struct VkCudaLaunchInfoNV { + VkStructureType sType; + const void* pNext; + VkCudaFunctionNV function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void* const * pParams; + size_t extraCount; + const void* const * pExtras; +} VkCudaLaunchInfoNV; + +typedef struct VkPhysicalDeviceCudaKernelLaunchFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cudaKernelLaunchFeatures; +} VkPhysicalDeviceCudaKernelLaunchFeaturesNV; + +typedef struct VkPhysicalDeviceCudaKernelLaunchPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t computeCapabilityMinor; + uint32_t computeCapabilityMajor; +} VkPhysicalDeviceCudaKernelLaunchPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateCudaModuleNV)(VkDevice device, const VkCudaModuleCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCudaModuleNV* pModule); +typedef VkResult (VKAPI_PTR *PFN_vkGetCudaModuleCacheNV)(VkDevice device, VkCudaModuleNV module, size_t* pCacheSize, void* pCacheData); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCudaFunctionNV)(VkDevice device, const VkCudaFunctionCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCudaFunctionNV* pFunction); +typedef void (VKAPI_PTR *PFN_vkDestroyCudaModuleNV)(VkDevice device, VkCudaModuleNV module, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDestroyCudaFunctionNV)(VkDevice device, VkCudaFunctionNV function, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdCudaLaunchKernelNV)(VkCommandBuffer commandBuffer, const VkCudaLaunchInfoNV* pLaunchInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCudaModuleNV( + VkDevice device, + const VkCudaModuleCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCudaModuleNV* pModule); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetCudaModuleCacheNV( + VkDevice device, + VkCudaModuleNV module, + size_t* pCacheSize, + void* pCacheData); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCudaFunctionNV( + VkDevice device, + const VkCudaFunctionCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCudaFunctionNV* pFunction); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCudaModuleNV( + VkDevice device, + VkCudaModuleNV module, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCudaFunctionNV( + VkDevice device, + VkCudaFunctionNV function, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkCmdCudaLaunchKernelNV( + VkCommandBuffer commandBuffer, + const VkCudaLaunchInfoNV* pLaunchInfo); +#endif + + +// VK_NV_low_latency is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_low_latency 1 +#define VK_NV_LOW_LATENCY_SPEC_VERSION 1 +#define VK_NV_LOW_LATENCY_EXTENSION_NAME "VK_NV_low_latency" +typedef struct VkQueryLowLatencySupportNV { + VkStructureType sType; + const void* pNext; + void* pQueriedLowLatencyData; +} VkQueryLowLatencySupportNV; + + + +// VK_EXT_descriptor_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_descriptor_buffer 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) +#define VK_EXT_DESCRIPTOR_BUFFER_SPEC_VERSION 1 +#define VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME "VK_EXT_descriptor_buffer" +typedef struct VkPhysicalDeviceDescriptorBufferPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 combinedImageSamplerDescriptorSingleArray; + VkBool32 bufferlessPushDescriptors; + VkBool32 allowSamplerImageViewPostSubmitCreation; + VkDeviceSize descriptorBufferOffsetAlignment; + uint32_t maxDescriptorBufferBindings; + uint32_t maxResourceDescriptorBufferBindings; + uint32_t maxSamplerDescriptorBufferBindings; + uint32_t maxEmbeddedImmutableSamplerBindings; + uint32_t maxEmbeddedImmutableSamplers; + size_t bufferCaptureReplayDescriptorDataSize; + size_t imageCaptureReplayDescriptorDataSize; + size_t imageViewCaptureReplayDescriptorDataSize; + size_t samplerCaptureReplayDescriptorDataSize; + size_t accelerationStructureCaptureReplayDescriptorDataSize; + size_t samplerDescriptorSize; + size_t combinedImageSamplerDescriptorSize; + size_t sampledImageDescriptorSize; + size_t storageImageDescriptorSize; + size_t uniformTexelBufferDescriptorSize; + size_t robustUniformTexelBufferDescriptorSize; + size_t storageTexelBufferDescriptorSize; + size_t robustStorageTexelBufferDescriptorSize; + size_t uniformBufferDescriptorSize; + size_t robustUniformBufferDescriptorSize; + size_t storageBufferDescriptorSize; + size_t robustStorageBufferDescriptorSize; + size_t inputAttachmentDescriptorSize; + size_t accelerationStructureDescriptorSize; + VkDeviceSize maxSamplerDescriptorBufferRange; + VkDeviceSize maxResourceDescriptorBufferRange; + VkDeviceSize samplerDescriptorBufferAddressSpaceSize; + VkDeviceSize resourceDescriptorBufferAddressSpaceSize; + VkDeviceSize descriptorBufferAddressSpaceSize; +} VkPhysicalDeviceDescriptorBufferPropertiesEXT; + +typedef struct VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT { + VkStructureType sType; + void* pNext; + size_t combinedImageSamplerDensityMapDescriptorSize; +} VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT; + +typedef struct VkPhysicalDeviceDescriptorBufferFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 descriptorBuffer; + VkBool32 descriptorBufferCaptureReplay; + VkBool32 descriptorBufferImageLayoutIgnored; + VkBool32 descriptorBufferPushDescriptors; +} VkPhysicalDeviceDescriptorBufferFeaturesEXT; + +typedef struct VkDescriptorAddressInfoEXT { + VkStructureType sType; + void* pNext; + VkDeviceAddress address; + VkDeviceSize range; + VkFormat format; +} VkDescriptorAddressInfoEXT; + +typedef struct VkDescriptorBufferBindingInfoEXT { + VkStructureType sType; + void* pNext; + VkDeviceAddress address; + VkBufferUsageFlags usage; +} VkDescriptorBufferBindingInfoEXT; + +typedef struct VkDescriptorBufferBindingPushDescriptorBufferHandleEXT { + VkStructureType sType; + void* pNext; + VkBuffer buffer; +} VkDescriptorBufferBindingPushDescriptorBufferHandleEXT; + +typedef union VkDescriptorDataEXT { + const VkSampler* pSampler; + const VkDescriptorImageInfo* pCombinedImageSampler; + const VkDescriptorImageInfo* pInputAttachmentImage; + const VkDescriptorImageInfo* pSampledImage; + const VkDescriptorImageInfo* pStorageImage; + const VkDescriptorAddressInfoEXT* pUniformTexelBuffer; + const VkDescriptorAddressInfoEXT* pStorageTexelBuffer; + const VkDescriptorAddressInfoEXT* pUniformBuffer; + const VkDescriptorAddressInfoEXT* pStorageBuffer; + VkDeviceAddress accelerationStructure; +} VkDescriptorDataEXT; + +typedef struct VkDescriptorGetInfoEXT { + VkStructureType sType; + const void* pNext; + VkDescriptorType type; + VkDescriptorDataEXT data; +} VkDescriptorGetInfoEXT; + +typedef struct VkBufferCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferCaptureDescriptorDataInfoEXT; + +typedef struct VkImageCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageCaptureDescriptorDataInfoEXT; + +typedef struct VkImageViewCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageView imageView; +} VkImageViewCaptureDescriptorDataInfoEXT; + +typedef struct VkSamplerCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkSampler sampler; +} VkSamplerCaptureDescriptorDataInfoEXT; + +typedef struct VkOpaqueCaptureDescriptorDataCreateInfoEXT { + VkStructureType sType; + const void* pNext; + const void* opaqueCaptureDescriptorData; +} VkOpaqueCaptureDescriptorDataCreateInfoEXT; + +typedef struct VkAccelerationStructureCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR accelerationStructure; + VkAccelerationStructureNV accelerationStructureNV; +} VkAccelerationStructureCaptureDescriptorDataInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSizeEXT)(VkDevice device, VkDescriptorSetLayout layout, VkDeviceSize* pLayoutSizeInBytes); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutBindingOffsetEXT)(VkDevice device, VkDescriptorSetLayout layout, uint32_t binding, VkDeviceSize* pOffset); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorEXT)(VkDevice device, const VkDescriptorGetInfoEXT* pDescriptorInfo, size_t dataSize, void* pDescriptor); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t bufferCount, const VkDescriptorBufferBindingInfoEXT* pBindingInfos); +typedef void (VKAPI_PTR *PFN_vkCmdSetDescriptorBufferOffsetsEXT)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount, const uint32_t* pBufferIndices, const VkDeviceSize* pOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set); +typedef VkResult (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkBufferCaptureDescriptorDataInfoEXT* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageCaptureDescriptorDataInfoEXT* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkSamplerCaptureDescriptorDataInfoEXT* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkAccelerationStructureCaptureDescriptorDataInfoEXT* pInfo, void* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSizeEXT( + VkDevice device, + VkDescriptorSetLayout layout, + VkDeviceSize* pLayoutSizeInBytes); + +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutBindingOffsetEXT( + VkDevice device, + VkDescriptorSetLayout layout, + uint32_t binding, + VkDeviceSize* pOffset); + +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorEXT( + VkDevice device, + const VkDescriptorGetInfoEXT* pDescriptorInfo, + size_t dataSize, + void* pDescriptor); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorBuffersEXT( + VkCommandBuffer commandBuffer, + uint32_t bufferCount, + const VkDescriptorBufferBindingInfoEXT* pBindingInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDescriptorBufferOffsetsEXT( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t setCount, + const uint32_t* pBufferIndices, + const VkDeviceSize* pOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorBufferEmbeddedSamplersEXT( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t set); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetBufferOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkBufferCaptureDescriptorDataInfoEXT* pInfo, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkImageCaptureDescriptorDataInfoEXT* pInfo, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageViewOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkImageViewCaptureDescriptorDataInfoEXT* pInfo, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSamplerOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkSamplerCaptureDescriptorDataInfoEXT* pInfo, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkAccelerationStructureCaptureDescriptorDataInfoEXT* pInfo, + void* pData); +#endif + + +// VK_EXT_graphics_pipeline_library is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_graphics_pipeline_library 1 +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION 1 +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME "VK_EXT_graphics_pipeline_library" + +typedef enum VkGraphicsPipelineLibraryFlagBitsEXT { + VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT = 0x00000001, + VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT = 0x00000002, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT = 0x00000004, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT = 0x00000008, + VK_GRAPHICS_PIPELINE_LIBRARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkGraphicsPipelineLibraryFlagBitsEXT; +typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT; +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 graphicsPipelineLibrary; +} VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT; + +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 graphicsPipelineLibraryFastLinking; + VkBool32 graphicsPipelineLibraryIndependentInterpolationDecoration; +} VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT; + +typedef struct VkGraphicsPipelineLibraryCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkGraphicsPipelineLibraryFlagsEXT flags; +} VkGraphicsPipelineLibraryCreateInfoEXT; + + + +// VK_AMD_shader_early_and_late_fragment_tests is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_early_and_late_fragment_tests 1 +#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_SPEC_VERSION 1 +#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_EXTENSION_NAME "VK_AMD_shader_early_and_late_fragment_tests" +typedef struct VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD { + VkStructureType sType; + void* pNext; + VkBool32 shaderEarlyAndLateFragmentTests; +} VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD; + + + +// VK_NV_fragment_shading_rate_enums is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_fragment_shading_rate_enums 1 +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME "VK_NV_fragment_shading_rate_enums" + +typedef enum VkFragmentShadingRateTypeNV { + VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV = 0, + VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV = 1, + VK_FRAGMENT_SHADING_RATE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateTypeNV; + +typedef enum VkFragmentShadingRateNV { + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV = 0, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV = 1, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV = 4, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV = 5, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV = 6, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV = 10, + VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV = 11, + VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV = 12, + VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV = 13, + VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV = 14, + VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV = 15, + VK_FRAGMENT_SHADING_RATE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateNV; +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShadingRateEnums; + VkBool32 supersampleFragmentShadingRates; + VkBool32 noInvocationFragmentShadingRates; +} VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV; + +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV { + VkStructureType sType; + void* pNext; + VkSampleCountFlagBits maxFragmentShadingRateInvocationCount; +} VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV; + +typedef struct VkPipelineFragmentShadingRateEnumStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkFragmentShadingRateTypeNV shadingRateType; + VkFragmentShadingRateNV shadingRate; + VkFragmentShadingRateCombinerOpKHR combinerOps[2]; +} VkPipelineFragmentShadingRateEnumStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetFragmentShadingRateEnumNV)(VkCommandBuffer commandBuffer, VkFragmentShadingRateNV shadingRate, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetFragmentShadingRateEnumNV( + VkCommandBuffer commandBuffer, + VkFragmentShadingRateNV shadingRate, + const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); +#endif + + +// VK_NV_ray_tracing_motion_blur is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_ray_tracing_motion_blur 1 +#define VK_NV_RAY_TRACING_MOTION_BLUR_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME "VK_NV_ray_tracing_motion_blur" + +typedef enum VkAccelerationStructureMotionInstanceTypeNV { + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV = 0, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV = 1, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV = 2, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMotionInstanceTypeNV; +typedef VkFlags VkAccelerationStructureMotionInfoFlagsNV; +typedef VkFlags VkAccelerationStructureMotionInstanceFlagsNV; +typedef union VkDeviceOrHostAddressConstKHR { + VkDeviceAddress deviceAddress; + const void* hostAddress; +} VkDeviceOrHostAddressConstKHR; + +typedef struct VkAccelerationStructureGeometryMotionTrianglesDataNV { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR vertexData; +} VkAccelerationStructureGeometryMotionTrianglesDataNV; + +typedef struct VkAccelerationStructureMotionInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t maxInstances; + VkAccelerationStructureMotionInfoFlagsNV flags; +} VkAccelerationStructureMotionInfoNV; + +typedef struct VkAccelerationStructureMatrixMotionInstanceNV { + VkTransformMatrixKHR transformT0; + VkTransformMatrixKHR transformT1; + uint32_t instanceCustomIndex:24; + uint32_t mask:8; + uint32_t instanceShaderBindingTableRecordOffset:24; + VkGeometryInstanceFlagsKHR flags:8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureMatrixMotionInstanceNV; + +typedef struct VkSRTDataNV { + float sx; + float a; + float b; + float pvx; + float sy; + float c; + float pvy; + float sz; + float pvz; + float qx; + float qy; + float qz; + float qw; + float tx; + float ty; + float tz; +} VkSRTDataNV; + +typedef struct VkAccelerationStructureSRTMotionInstanceNV { + VkSRTDataNV transformT0; + VkSRTDataNV transformT1; + uint32_t instanceCustomIndex:24; + uint32_t mask:8; + uint32_t instanceShaderBindingTableRecordOffset:24; + VkGeometryInstanceFlagsKHR flags:8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureSRTMotionInstanceNV; + +typedef union VkAccelerationStructureMotionInstanceDataNV { + VkAccelerationStructureInstanceKHR staticInstance; + VkAccelerationStructureMatrixMotionInstanceNV matrixMotionInstance; + VkAccelerationStructureSRTMotionInstanceNV srtMotionInstance; +} VkAccelerationStructureMotionInstanceDataNV; + +typedef struct VkAccelerationStructureMotionInstanceNV { + VkAccelerationStructureMotionInstanceTypeNV type; + VkAccelerationStructureMotionInstanceFlagsNV flags; + VkAccelerationStructureMotionInstanceDataNV data; +} VkAccelerationStructureMotionInstanceNV; + +typedef struct VkPhysicalDeviceRayTracingMotionBlurFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingMotionBlur; + VkBool32 rayTracingMotionBlurPipelineTraceRaysIndirect; +} VkPhysicalDeviceRayTracingMotionBlurFeaturesNV; + + + +// VK_EXT_ycbcr_2plane_444_formats is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_ycbcr_2plane_444_formats 1 +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_SPEC_VERSION 1 +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_EXTENSION_NAME "VK_EXT_ycbcr_2plane_444_formats" +typedef struct VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 ycbcr2plane444Formats; +} VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT; + + + +// VK_EXT_fragment_density_map2 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_fragment_density_map2 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_2_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_2_EXTENSION_NAME "VK_EXT_fragment_density_map2" +typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMapDeferred; +} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 subsampledLoads; + VkBool32 subsampledCoarseReconstructionEarlyAccess; + uint32_t maxSubsampledArrayLayers; + uint32_t maxDescriptorSetSubsampledSamplers; +} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT; + + + +// VK_QCOM_rotated_copy_commands is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_rotated_copy_commands 1 +#define VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION 1 +#define VK_QCOM_ROTATED_COPY_COMMANDS_EXTENSION_NAME "VK_QCOM_rotated_copy_commands" +typedef struct VkCopyCommandTransformInfoQCOM { + VkStructureType sType; + const void* pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkCopyCommandTransformInfoQCOM; + + + +// VK_EXT_image_robustness is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_robustness 1 +#define VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_image_robustness" +typedef VkPhysicalDeviceImageRobustnessFeatures VkPhysicalDeviceImageRobustnessFeaturesEXT; + + + +// VK_EXT_image_compression_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_compression_control 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME "VK_EXT_image_compression_control" + +typedef enum VkImageCompressionFlagBitsEXT { + VK_IMAGE_COMPRESSION_DEFAULT_EXT = 0, + VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT = 0x00000001, + VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT = 0x00000002, + VK_IMAGE_COMPRESSION_DISABLED_EXT = 0x00000004, + VK_IMAGE_COMPRESSION_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkImageCompressionFlagBitsEXT; +typedef VkFlags VkImageCompressionFlagsEXT; + +typedef enum VkImageCompressionFixedRateFlagBitsEXT { + VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT = 0, + VK_IMAGE_COMPRESSION_FIXED_RATE_1BPC_BIT_EXT = 0x00000001, + VK_IMAGE_COMPRESSION_FIXED_RATE_2BPC_BIT_EXT = 0x00000002, + VK_IMAGE_COMPRESSION_FIXED_RATE_3BPC_BIT_EXT = 0x00000004, + VK_IMAGE_COMPRESSION_FIXED_RATE_4BPC_BIT_EXT = 0x00000008, + VK_IMAGE_COMPRESSION_FIXED_RATE_5BPC_BIT_EXT = 0x00000010, + VK_IMAGE_COMPRESSION_FIXED_RATE_6BPC_BIT_EXT = 0x00000020, + VK_IMAGE_COMPRESSION_FIXED_RATE_7BPC_BIT_EXT = 0x00000040, + VK_IMAGE_COMPRESSION_FIXED_RATE_8BPC_BIT_EXT = 0x00000080, + VK_IMAGE_COMPRESSION_FIXED_RATE_9BPC_BIT_EXT = 0x00000100, + VK_IMAGE_COMPRESSION_FIXED_RATE_10BPC_BIT_EXT = 0x00000200, + VK_IMAGE_COMPRESSION_FIXED_RATE_11BPC_BIT_EXT = 0x00000400, + VK_IMAGE_COMPRESSION_FIXED_RATE_12BPC_BIT_EXT = 0x00000800, + VK_IMAGE_COMPRESSION_FIXED_RATE_13BPC_BIT_EXT = 0x00001000, + VK_IMAGE_COMPRESSION_FIXED_RATE_14BPC_BIT_EXT = 0x00002000, + VK_IMAGE_COMPRESSION_FIXED_RATE_15BPC_BIT_EXT = 0x00004000, + VK_IMAGE_COMPRESSION_FIXED_RATE_16BPC_BIT_EXT = 0x00008000, + VK_IMAGE_COMPRESSION_FIXED_RATE_17BPC_BIT_EXT = 0x00010000, + VK_IMAGE_COMPRESSION_FIXED_RATE_18BPC_BIT_EXT = 0x00020000, + VK_IMAGE_COMPRESSION_FIXED_RATE_19BPC_BIT_EXT = 0x00040000, + VK_IMAGE_COMPRESSION_FIXED_RATE_20BPC_BIT_EXT = 0x00080000, + VK_IMAGE_COMPRESSION_FIXED_RATE_21BPC_BIT_EXT = 0x00100000, + VK_IMAGE_COMPRESSION_FIXED_RATE_22BPC_BIT_EXT = 0x00200000, + VK_IMAGE_COMPRESSION_FIXED_RATE_23BPC_BIT_EXT = 0x00400000, + VK_IMAGE_COMPRESSION_FIXED_RATE_24BPC_BIT_EXT = 0x00800000, + VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkImageCompressionFixedRateFlagBitsEXT; +typedef VkFlags VkImageCompressionFixedRateFlagsEXT; +typedef struct VkPhysicalDeviceImageCompressionControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 imageCompressionControl; +} VkPhysicalDeviceImageCompressionControlFeaturesEXT; + +typedef struct VkImageCompressionControlEXT { + VkStructureType sType; + const void* pNext; + VkImageCompressionFlagsEXT flags; + uint32_t compressionControlPlaneCount; + VkImageCompressionFixedRateFlagsEXT* pFixedRateFlags; +} VkImageCompressionControlEXT; + +typedef struct VkImageCompressionPropertiesEXT { + VkStructureType sType; + void* pNext; + VkImageCompressionFlagsEXT imageCompressionFlags; + VkImageCompressionFixedRateFlagsEXT imageCompressionFixedRateFlags; +} VkImageCompressionPropertiesEXT; + + + +// VK_EXT_attachment_feedback_loop_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_attachment_feedback_loop_layout 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_SPEC_VERSION 2 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_layout" +typedef struct VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 attachmentFeedbackLoopLayout; +} VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT; + + + +// VK_EXT_4444_formats is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_4444_formats 1 +#define VK_EXT_4444_FORMATS_SPEC_VERSION 1 +#define VK_EXT_4444_FORMATS_EXTENSION_NAME "VK_EXT_4444_formats" +typedef struct VkPhysicalDevice4444FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 formatA4R4G4B4; + VkBool32 formatA4B4G4R4; +} VkPhysicalDevice4444FormatsFeaturesEXT; + + + +// VK_EXT_device_fault is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_device_fault 1 +#define VK_EXT_DEVICE_FAULT_SPEC_VERSION 2 +#define VK_EXT_DEVICE_FAULT_EXTENSION_NAME "VK_EXT_device_fault" + +typedef enum VkDeviceFaultAddressTypeEXT { + VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT = 0, + VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT = 1, + VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT = 2, + VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT = 3, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT = 4, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT = 5, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT = 6, + VK_DEVICE_FAULT_ADDRESS_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceFaultAddressTypeEXT; + +typedef enum VkDeviceFaultVendorBinaryHeaderVersionEXT { + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT = 1, + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceFaultVendorBinaryHeaderVersionEXT; +typedef struct VkPhysicalDeviceFaultFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 deviceFault; + VkBool32 deviceFaultVendorBinary; +} VkPhysicalDeviceFaultFeaturesEXT; + +typedef struct VkDeviceFaultCountsEXT { + VkStructureType sType; + void* pNext; + uint32_t addressInfoCount; + uint32_t vendorInfoCount; + VkDeviceSize vendorBinarySize; +} VkDeviceFaultCountsEXT; + +typedef struct VkDeviceFaultAddressInfoEXT { + VkDeviceFaultAddressTypeEXT addressType; + VkDeviceAddress reportedAddress; + VkDeviceSize addressPrecision; +} VkDeviceFaultAddressInfoEXT; + +typedef struct VkDeviceFaultVendorInfoEXT { + char description[VK_MAX_DESCRIPTION_SIZE]; + uint64_t vendorFaultCode; + uint64_t vendorFaultData; +} VkDeviceFaultVendorInfoEXT; + +typedef struct VkDeviceFaultInfoEXT { + VkStructureType sType; + void* pNext; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkDeviceFaultAddressInfoEXT* pAddressInfos; + VkDeviceFaultVendorInfoEXT* pVendorInfos; + void* pVendorBinaryData; +} VkDeviceFaultInfoEXT; + +typedef struct VkDeviceFaultVendorBinaryHeaderVersionOneEXT { + uint32_t headerSize; + VkDeviceFaultVendorBinaryHeaderVersionEXT headerVersion; + uint32_t vendorID; + uint32_t deviceID; + uint32_t driverVersion; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; + uint32_t applicationNameOffset; + uint32_t applicationVersion; + uint32_t engineNameOffset; + uint32_t engineVersion; + uint32_t apiVersion; +} VkDeviceFaultVendorBinaryHeaderVersionOneEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceFaultInfoEXT)(VkDevice device, VkDeviceFaultCountsEXT* pFaultCounts, VkDeviceFaultInfoEXT* pFaultInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceFaultInfoEXT( + VkDevice device, + VkDeviceFaultCountsEXT* pFaultCounts, + VkDeviceFaultInfoEXT* pFaultInfo); +#endif + + +// VK_ARM_rasterization_order_attachment_access is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_rasterization_order_attachment_access 1 +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_ARM_rasterization_order_attachment_access" +typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 rasterizationOrderColorAttachmentAccess; + VkBool32 rasterizationOrderDepthAttachmentAccess; + VkBool32 rasterizationOrderStencilAttachmentAccess; +} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT; + +typedef VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM; + + + +// VK_EXT_rgba10x6_formats is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_rgba10x6_formats 1 +#define VK_EXT_RGBA10X6_FORMATS_SPEC_VERSION 1 +#define VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME "VK_EXT_rgba10x6_formats" +typedef struct VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 formatRgba10x6WithoutYCbCrSampler; +} VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT; + + + +// VK_VALVE_mutable_descriptor_type is a preprocessor guard. Do not pass it to API calls. +#define VK_VALVE_mutable_descriptor_type 1 +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_VALVE_mutable_descriptor_type" +typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 mutableDescriptorType; +} VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT; + +typedef VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE; + +typedef struct VkMutableDescriptorTypeListEXT { + uint32_t descriptorTypeCount; + const VkDescriptorType* pDescriptorTypes; +} VkMutableDescriptorTypeListEXT; + +typedef VkMutableDescriptorTypeListEXT VkMutableDescriptorTypeListVALVE; + +typedef struct VkMutableDescriptorTypeCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t mutableDescriptorTypeListCount; + const VkMutableDescriptorTypeListEXT* pMutableDescriptorTypeLists; +} VkMutableDescriptorTypeCreateInfoEXT; + +typedef VkMutableDescriptorTypeCreateInfoEXT VkMutableDescriptorTypeCreateInfoVALVE; + + + +// VK_EXT_vertex_input_dynamic_state is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_vertex_input_dynamic_state 1 +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_SPEC_VERSION 2 +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_vertex_input_dynamic_state" +typedef struct VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 vertexInputDynamicState; +} VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT; + +typedef struct VkVertexInputBindingDescription2EXT { + VkStructureType sType; + void* pNext; + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; + uint32_t divisor; +} VkVertexInputBindingDescription2EXT; + +typedef struct VkVertexInputAttributeDescription2EXT { + VkStructureType sType; + void* pNext; + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription2EXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetVertexInputEXT)(VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions, uint32_t vertexAttributeDescriptionCount, const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetVertexInputEXT( + VkCommandBuffer commandBuffer, + uint32_t vertexBindingDescriptionCount, + const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions, + uint32_t vertexAttributeDescriptionCount, + const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions); +#endif + + +// VK_EXT_physical_device_drm is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_physical_device_drm 1 +#define VK_EXT_PHYSICAL_DEVICE_DRM_SPEC_VERSION 1 +#define VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME "VK_EXT_physical_device_drm" +typedef struct VkPhysicalDeviceDrmPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 hasPrimary; + VkBool32 hasRender; + int64_t primaryMajor; + int64_t primaryMinor; + int64_t renderMajor; + int64_t renderMinor; +} VkPhysicalDeviceDrmPropertiesEXT; + + + +// VK_EXT_device_address_binding_report is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_device_address_binding_report 1 +#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_SPEC_VERSION 1 +#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_EXTENSION_NAME "VK_EXT_device_address_binding_report" + +typedef enum VkDeviceAddressBindingTypeEXT { + VK_DEVICE_ADDRESS_BINDING_TYPE_BIND_EXT = 0, + VK_DEVICE_ADDRESS_BINDING_TYPE_UNBIND_EXT = 1, + VK_DEVICE_ADDRESS_BINDING_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceAddressBindingTypeEXT; + +typedef enum VkDeviceAddressBindingFlagBitsEXT { + VK_DEVICE_ADDRESS_BINDING_INTERNAL_OBJECT_BIT_EXT = 0x00000001, + VK_DEVICE_ADDRESS_BINDING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceAddressBindingFlagBitsEXT; +typedef VkFlags VkDeviceAddressBindingFlagsEXT; +typedef struct VkPhysicalDeviceAddressBindingReportFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 reportAddressBinding; +} VkPhysicalDeviceAddressBindingReportFeaturesEXT; + +typedef struct VkDeviceAddressBindingCallbackDataEXT { + VkStructureType sType; + void* pNext; + VkDeviceAddressBindingFlagsEXT flags; + VkDeviceAddress baseAddress; + VkDeviceSize size; + VkDeviceAddressBindingTypeEXT bindingType; +} VkDeviceAddressBindingCallbackDataEXT; + + + +// VK_EXT_depth_clip_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_clip_control 1 +#define VK_EXT_DEPTH_CLIP_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clip_control" +typedef struct VkPhysicalDeviceDepthClipControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthClipControl; +} VkPhysicalDeviceDepthClipControlFeaturesEXT; + +typedef struct VkPipelineViewportDepthClipControlCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 negativeOneToOne; +} VkPipelineViewportDepthClipControlCreateInfoEXT; + + + +// VK_EXT_primitive_topology_list_restart is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_primitive_topology_list_restart 1 +#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME "VK_EXT_primitive_topology_list_restart" +typedef struct VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 primitiveTopologyListRestart; + VkBool32 primitiveTopologyPatchListRestart; +} VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT; + + + +// VK_HUAWEI_subpass_shading is a preprocessor guard. Do not pass it to API calls. +#define VK_HUAWEI_subpass_shading 1 +#define VK_HUAWEI_SUBPASS_SHADING_SPEC_VERSION 3 +#define VK_HUAWEI_SUBPASS_SHADING_EXTENSION_NAME "VK_HUAWEI_subpass_shading" +typedef struct VkSubpassShadingPipelineCreateInfoHUAWEI { + VkStructureType sType; + void* pNext; + VkRenderPass renderPass; + uint32_t subpass; +} VkSubpassShadingPipelineCreateInfoHUAWEI; + +typedef struct VkPhysicalDeviceSubpassShadingFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 subpassShading; +} VkPhysicalDeviceSubpassShadingFeaturesHUAWEI; + +typedef struct VkPhysicalDeviceSubpassShadingPropertiesHUAWEI { + VkStructureType sType; + void* pNext; + uint32_t maxSubpassShadingWorkgroupSizeAspectRatio; +} VkPhysicalDeviceSubpassShadingPropertiesHUAWEI; + +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)(VkDevice device, VkRenderPass renderpass, VkExtent2D* pMaxWorkgroupSize); +typedef void (VKAPI_PTR *PFN_vkCmdSubpassShadingHUAWEI)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI( + VkDevice device, + VkRenderPass renderpass, + VkExtent2D* pMaxWorkgroupSize); + +VKAPI_ATTR void VKAPI_CALL vkCmdSubpassShadingHUAWEI( + VkCommandBuffer commandBuffer); +#endif + + +// VK_HUAWEI_invocation_mask is a preprocessor guard. Do not pass it to API calls. +#define VK_HUAWEI_invocation_mask 1 +#define VK_HUAWEI_INVOCATION_MASK_SPEC_VERSION 1 +#define VK_HUAWEI_INVOCATION_MASK_EXTENSION_NAME "VK_HUAWEI_invocation_mask" +typedef struct VkPhysicalDeviceInvocationMaskFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 invocationMask; +} VkPhysicalDeviceInvocationMaskFeaturesHUAWEI; + +typedef void (VKAPI_PTR *PFN_vkCmdBindInvocationMaskHUAWEI)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindInvocationMaskHUAWEI( + VkCommandBuffer commandBuffer, + VkImageView imageView, + VkImageLayout imageLayout); +#endif + + +// VK_NV_external_memory_rdma is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_external_memory_rdma 1 +typedef void* VkRemoteAddressNV; +#define VK_NV_EXTERNAL_MEMORY_RDMA_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_RDMA_EXTENSION_NAME "VK_NV_external_memory_rdma" +typedef struct VkMemoryGetRemoteAddressInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetRemoteAddressInfoNV; + +typedef struct VkPhysicalDeviceExternalMemoryRDMAFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 externalMemoryRDMA; +} VkPhysicalDeviceExternalMemoryRDMAFeaturesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryRemoteAddressNV)(VkDevice device, const VkMemoryGetRemoteAddressInfoNV* pMemoryGetRemoteAddressInfo, VkRemoteAddressNV* pAddress); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryRemoteAddressNV( + VkDevice device, + const VkMemoryGetRemoteAddressInfoNV* pMemoryGetRemoteAddressInfo, + VkRemoteAddressNV* pAddress); +#endif + + +// VK_EXT_pipeline_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_properties 1 +#define VK_EXT_PIPELINE_PROPERTIES_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_PROPERTIES_EXTENSION_NAME "VK_EXT_pipeline_properties" +typedef VkPipelineInfoKHR VkPipelineInfoEXT; + +typedef struct VkPipelinePropertiesIdentifierEXT { + VkStructureType sType; + void* pNext; + uint8_t pipelineIdentifier[VK_UUID_SIZE]; +} VkPipelinePropertiesIdentifierEXT; + +typedef struct VkPhysicalDevicePipelinePropertiesFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pipelinePropertiesIdentifier; +} VkPhysicalDevicePipelinePropertiesFeaturesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelinePropertiesEXT)(VkDevice device, const VkPipelineInfoEXT* pPipelineInfo, VkBaseOutStructure* pPipelineProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelinePropertiesEXT( + VkDevice device, + const VkPipelineInfoEXT* pPipelineInfo, + VkBaseOutStructure* pPipelineProperties); +#endif + + +// VK_EXT_frame_boundary is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_frame_boundary 1 +#define VK_EXT_FRAME_BOUNDARY_SPEC_VERSION 1 +#define VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME "VK_EXT_frame_boundary" + +typedef enum VkFrameBoundaryFlagBitsEXT { + VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT = 0x00000001, + VK_FRAME_BOUNDARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkFrameBoundaryFlagBitsEXT; +typedef VkFlags VkFrameBoundaryFlagsEXT; +typedef struct VkPhysicalDeviceFrameBoundaryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 frameBoundary; +} VkPhysicalDeviceFrameBoundaryFeaturesEXT; + +typedef struct VkFrameBoundaryEXT { + VkStructureType sType; + const void* pNext; + VkFrameBoundaryFlagsEXT flags; + uint64_t frameID; + uint32_t imageCount; + const VkImage* pImages; + uint32_t bufferCount; + const VkBuffer* pBuffers; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkFrameBoundaryEXT; + + + +// VK_EXT_multisampled_render_to_single_sampled is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_multisampled_render_to_single_sampled 1 +#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_SPEC_VERSION 1 +#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME "VK_EXT_multisampled_render_to_single_sampled" +typedef struct VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 multisampledRenderToSingleSampled; +} VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT; + +typedef struct VkSubpassResolvePerformanceQueryEXT { + VkStructureType sType; + void* pNext; + VkBool32 optimal; +} VkSubpassResolvePerformanceQueryEXT; + +typedef struct VkMultisampledRenderToSingleSampledInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 multisampledRenderToSingleSampledEnable; + VkSampleCountFlagBits rasterizationSamples; +} VkMultisampledRenderToSingleSampledInfoEXT; + + + +// VK_EXT_extended_dynamic_state2 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_extended_dynamic_state2 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME "VK_EXT_extended_dynamic_state2" +typedef struct VkPhysicalDeviceExtendedDynamicState2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 extendedDynamicState2; + VkBool32 extendedDynamicState2LogicOp; + VkBool32 extendedDynamicState2PatchControlPoints; +} VkPhysicalDeviceExtendedDynamicState2FeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetPatchControlPointsEXT)(VkCommandBuffer commandBuffer, uint32_t patchControlPoints); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizerDiscardEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBiasEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetLogicOpEXT)(VkCommandBuffer commandBuffer, VkLogicOp logicOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetPatchControlPointsEXT( + VkCommandBuffer commandBuffer, + uint32_t patchControlPoints); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizerDiscardEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 rasterizerDiscardEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBiasEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthBiasEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLogicOpEXT( + VkCommandBuffer commandBuffer, + VkLogicOp logicOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveRestartEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 primitiveRestartEnable); +#endif + + +// VK_EXT_color_write_enable is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_color_write_enable 1 +#define VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION 1 +#define VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME "VK_EXT_color_write_enable" +typedef struct VkPhysicalDeviceColorWriteEnableFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 colorWriteEnable; +} VkPhysicalDeviceColorWriteEnableFeaturesEXT; + +typedef struct VkPipelineColorWriteCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t attachmentCount; + const VkBool32* pColorWriteEnables; +} VkPipelineColorWriteCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetColorWriteEnableEXT)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32* pColorWriteEnables); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorWriteEnableEXT( + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkBool32* pColorWriteEnables); +#endif + + +// VK_EXT_primitives_generated_query is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_primitives_generated_query 1 +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME "VK_EXT_primitives_generated_query" +typedef struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 primitivesGeneratedQuery; + VkBool32 primitivesGeneratedQueryWithRasterizerDiscard; + VkBool32 primitivesGeneratedQueryWithNonZeroStreams; +} VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT; + + + +// VK_EXT_global_priority_query is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_global_priority_query 1 +#define VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION 1 +#define VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME "VK_EXT_global_priority_query" +#define VK_MAX_GLOBAL_PRIORITY_SIZE_EXT VK_MAX_GLOBAL_PRIORITY_SIZE_KHR +typedef VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT; + +typedef VkQueueFamilyGlobalPriorityPropertiesKHR VkQueueFamilyGlobalPriorityPropertiesEXT; + + + +// VK_EXT_image_view_min_lod is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_view_min_lod 1 +#define VK_EXT_IMAGE_VIEW_MIN_LOD_SPEC_VERSION 1 +#define VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME "VK_EXT_image_view_min_lod" +typedef struct VkPhysicalDeviceImageViewMinLodFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 minLod; +} VkPhysicalDeviceImageViewMinLodFeaturesEXT; + +typedef struct VkImageViewMinLodCreateInfoEXT { + VkStructureType sType; + const void* pNext; + float minLod; +} VkImageViewMinLodCreateInfoEXT; + + + +// VK_EXT_multi_draw is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_multi_draw 1 +#define VK_EXT_MULTI_DRAW_SPEC_VERSION 1 +#define VK_EXT_MULTI_DRAW_EXTENSION_NAME "VK_EXT_multi_draw" +typedef struct VkPhysicalDeviceMultiDrawFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 multiDraw; +} VkPhysicalDeviceMultiDrawFeaturesEXT; + +typedef struct VkPhysicalDeviceMultiDrawPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxMultiDrawCount; +} VkPhysicalDeviceMultiDrawPropertiesEXT; + +typedef struct VkMultiDrawInfoEXT { + uint32_t firstVertex; + uint32_t vertexCount; +} VkMultiDrawInfoEXT; + +typedef struct VkMultiDrawIndexedInfoEXT { + uint32_t firstIndex; + uint32_t indexCount; + int32_t vertexOffset; +} VkMultiDrawIndexedInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawMultiEXT)(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT* pVertexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMultiIndexedEXT)(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawIndexedInfoEXT* pIndexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, const int32_t* pVertexOffset); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMultiEXT( + VkCommandBuffer commandBuffer, + uint32_t drawCount, + const VkMultiDrawInfoEXT* pVertexInfo, + uint32_t instanceCount, + uint32_t firstInstance, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMultiIndexedEXT( + VkCommandBuffer commandBuffer, + uint32_t drawCount, + const VkMultiDrawIndexedInfoEXT* pIndexInfo, + uint32_t instanceCount, + uint32_t firstInstance, + uint32_t stride, + const int32_t* pVertexOffset); +#endif + + +// VK_EXT_image_2d_view_of_3d is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_2d_view_of_3d 1 +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_2d_view_of_3d" +typedef struct VkPhysicalDeviceImage2DViewOf3DFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 image2DViewOf3D; + VkBool32 sampler2DViewOf3D; +} VkPhysicalDeviceImage2DViewOf3DFeaturesEXT; + + + +// VK_EXT_shader_tile_image is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_tile_image 1 +#define VK_EXT_SHADER_TILE_IMAGE_SPEC_VERSION 1 +#define VK_EXT_SHADER_TILE_IMAGE_EXTENSION_NAME "VK_EXT_shader_tile_image" +typedef struct VkPhysicalDeviceShaderTileImageFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderTileImageColorReadAccess; + VkBool32 shaderTileImageDepthReadAccess; + VkBool32 shaderTileImageStencilReadAccess; +} VkPhysicalDeviceShaderTileImageFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderTileImagePropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderTileImageCoherentReadAccelerated; + VkBool32 shaderTileImageReadSampleFromPixelRateInvocation; + VkBool32 shaderTileImageReadFromHelperInvocation; +} VkPhysicalDeviceShaderTileImagePropertiesEXT; + + + +// VK_EXT_opacity_micromap is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_opacity_micromap 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkMicromapEXT) +#define VK_EXT_OPACITY_MICROMAP_SPEC_VERSION 2 +#define VK_EXT_OPACITY_MICROMAP_EXTENSION_NAME "VK_EXT_opacity_micromap" + +typedef enum VkMicromapTypeEXT { + VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT = 0, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_MICROMAP_TYPE_DISPLACEMENT_MICROMAP_NV = 1000397000, +#endif + VK_MICROMAP_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkMicromapTypeEXT; + +typedef enum VkBuildMicromapModeEXT { + VK_BUILD_MICROMAP_MODE_BUILD_EXT = 0, + VK_BUILD_MICROMAP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBuildMicromapModeEXT; + +typedef enum VkCopyMicromapModeEXT { + VK_COPY_MICROMAP_MODE_CLONE_EXT = 0, + VK_COPY_MICROMAP_MODE_SERIALIZE_EXT = 1, + VK_COPY_MICROMAP_MODE_DESERIALIZE_EXT = 2, + VK_COPY_MICROMAP_MODE_COMPACT_EXT = 3, + VK_COPY_MICROMAP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkCopyMicromapModeEXT; + +typedef enum VkOpacityMicromapFormatEXT { + VK_OPACITY_MICROMAP_FORMAT_2_STATE_EXT = 1, + VK_OPACITY_MICROMAP_FORMAT_4_STATE_EXT = 2, + VK_OPACITY_MICROMAP_FORMAT_MAX_ENUM_EXT = 0x7FFFFFFF +} VkOpacityMicromapFormatEXT; + +typedef enum VkOpacityMicromapSpecialIndexEXT { + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT = -1, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT = -2, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_EXT = -3, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT = -4, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_MAX_ENUM_EXT = 0x7FFFFFFF +} VkOpacityMicromapSpecialIndexEXT; + +typedef enum VkAccelerationStructureCompatibilityKHR { + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR = 0, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR = 1, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCompatibilityKHR; + +typedef enum VkAccelerationStructureBuildTypeKHR { + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR = 0, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR = 1, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureBuildTypeKHR; + +typedef enum VkBuildMicromapFlagBitsEXT { + VK_BUILD_MICROMAP_PREFER_FAST_TRACE_BIT_EXT = 0x00000001, + VK_BUILD_MICROMAP_PREFER_FAST_BUILD_BIT_EXT = 0x00000002, + VK_BUILD_MICROMAP_ALLOW_COMPACTION_BIT_EXT = 0x00000004, + VK_BUILD_MICROMAP_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBuildMicromapFlagBitsEXT; +typedef VkFlags VkBuildMicromapFlagsEXT; + +typedef enum VkMicromapCreateFlagBitsEXT { + VK_MICROMAP_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = 0x00000001, + VK_MICROMAP_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkMicromapCreateFlagBitsEXT; +typedef VkFlags VkMicromapCreateFlagsEXT; +typedef struct VkMicromapUsageEXT { + uint32_t count; + uint32_t subdivisionLevel; + uint32_t format; +} VkMicromapUsageEXT; + +typedef union VkDeviceOrHostAddressKHR { + VkDeviceAddress deviceAddress; + void* hostAddress; +} VkDeviceOrHostAddressKHR; + +typedef struct VkMicromapBuildInfoEXT { + VkStructureType sType; + const void* pNext; + VkMicromapTypeEXT type; + VkBuildMicromapFlagsEXT flags; + VkBuildMicromapModeEXT mode; + VkMicromapEXT dstMicromap; + uint32_t usageCountsCount; + const VkMicromapUsageEXT* pUsageCounts; + const VkMicromapUsageEXT* const* ppUsageCounts; + VkDeviceOrHostAddressConstKHR data; + VkDeviceOrHostAddressKHR scratchData; + VkDeviceOrHostAddressConstKHR triangleArray; + VkDeviceSize triangleArrayStride; +} VkMicromapBuildInfoEXT; + +typedef struct VkMicromapCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkMicromapCreateFlagsEXT createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkMicromapTypeEXT type; + VkDeviceAddress deviceAddress; +} VkMicromapCreateInfoEXT; + +typedef struct VkPhysicalDeviceOpacityMicromapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 micromap; + VkBool32 micromapCaptureReplay; + VkBool32 micromapHostCommands; +} VkPhysicalDeviceOpacityMicromapFeaturesEXT; + +typedef struct VkPhysicalDeviceOpacityMicromapPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxOpacity2StateSubdivisionLevel; + uint32_t maxOpacity4StateSubdivisionLevel; +} VkPhysicalDeviceOpacityMicromapPropertiesEXT; + +typedef struct VkMicromapVersionInfoEXT { + VkStructureType sType; + const void* pNext; + const uint8_t* pVersionData; +} VkMicromapVersionInfoEXT; + +typedef struct VkCopyMicromapToMemoryInfoEXT { + VkStructureType sType; + const void* pNext; + VkMicromapEXT src; + VkDeviceOrHostAddressKHR dst; + VkCopyMicromapModeEXT mode; +} VkCopyMicromapToMemoryInfoEXT; + +typedef struct VkCopyMemoryToMicromapInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR src; + VkMicromapEXT dst; + VkCopyMicromapModeEXT mode; +} VkCopyMemoryToMicromapInfoEXT; + +typedef struct VkCopyMicromapInfoEXT { + VkStructureType sType; + const void* pNext; + VkMicromapEXT src; + VkMicromapEXT dst; + VkCopyMicromapModeEXT mode; +} VkCopyMicromapInfoEXT; + +typedef struct VkMicromapBuildSizesInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceSize micromapSize; + VkDeviceSize buildScratchSize; + VkBool32 discardable; +} VkMicromapBuildSizesInfoEXT; + +typedef struct VkAccelerationStructureTrianglesOpacityMicromapEXT { + VkStructureType sType; + void* pNext; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + uint32_t usageCountsCount; + const VkMicromapUsageEXT* pUsageCounts; + const VkMicromapUsageEXT* const* ppUsageCounts; + VkMicromapEXT micromap; +} VkAccelerationStructureTrianglesOpacityMicromapEXT; + +typedef struct VkMicromapTriangleEXT { + uint32_t dataOffset; + uint16_t subdivisionLevel; + uint16_t format; +} VkMicromapTriangleEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMicromapEXT)(VkDevice device, const VkMicromapCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkMicromapEXT* pMicromap); +typedef void (VKAPI_PTR *PFN_vkDestroyMicromapEXT)(VkDevice device, VkMicromapEXT micromap, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdBuildMicromapsEXT)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkMicromapBuildInfoEXT* pInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBuildMicromapsEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkMicromapBuildInfoEXT* pInfos); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMicromapEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapInfoEXT* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMicromapToMemoryEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapToMemoryInfoEXT* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToMicromapEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToMicromapInfoEXT* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkWriteMicromapsPropertiesEXT)(VkDevice device, uint32_t micromapCount, const VkMicromapEXT* pMicromaps, VkQueryType queryType, size_t dataSize, void* pData, size_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMicromapEXT)(VkCommandBuffer commandBuffer, const VkCopyMicromapInfoEXT* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMicromapToMemoryEXT)(VkCommandBuffer commandBuffer, const VkCopyMicromapToMemoryInfoEXT* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToMicromapEXT)(VkCommandBuffer commandBuffer, const VkCopyMemoryToMicromapInfoEXT* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteMicromapsPropertiesEXT)(VkCommandBuffer commandBuffer, uint32_t micromapCount, const VkMicromapEXT* pMicromaps, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (VKAPI_PTR *PFN_vkGetDeviceMicromapCompatibilityEXT)(VkDevice device, const VkMicromapVersionInfoEXT* pVersionInfo, VkAccelerationStructureCompatibilityKHR* pCompatibility); +typedef void (VKAPI_PTR *PFN_vkGetMicromapBuildSizesEXT)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkMicromapBuildInfoEXT* pBuildInfo, VkMicromapBuildSizesInfoEXT* pSizeInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMicromapEXT( + VkDevice device, + const VkMicromapCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkMicromapEXT* pMicromap); + +VKAPI_ATTR void VKAPI_CALL vkDestroyMicromapEXT( + VkDevice device, + VkMicromapEXT micromap, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildMicromapsEXT( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkMicromapBuildInfoEXT* pInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkBuildMicromapsEXT( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + uint32_t infoCount, + const VkMicromapBuildInfoEXT* pInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMicromapEXT( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMicromapInfoEXT* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMicromapToMemoryEXT( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMicromapToMemoryInfoEXT* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToMicromapEXT( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMemoryToMicromapInfoEXT* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkWriteMicromapsPropertiesEXT( + VkDevice device, + uint32_t micromapCount, + const VkMicromapEXT* pMicromaps, + VkQueryType queryType, + size_t dataSize, + void* pData, + size_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMicromapEXT( + VkCommandBuffer commandBuffer, + const VkCopyMicromapInfoEXT* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMicromapToMemoryEXT( + VkCommandBuffer commandBuffer, + const VkCopyMicromapToMemoryInfoEXT* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToMicromapEXT( + VkCommandBuffer commandBuffer, + const VkCopyMemoryToMicromapInfoEXT* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteMicromapsPropertiesEXT( + VkCommandBuffer commandBuffer, + uint32_t micromapCount, + const VkMicromapEXT* pMicromaps, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceMicromapCompatibilityEXT( + VkDevice device, + const VkMicromapVersionInfoEXT* pVersionInfo, + VkAccelerationStructureCompatibilityKHR* pCompatibility); + +VKAPI_ATTR void VKAPI_CALL vkGetMicromapBuildSizesEXT( + VkDevice device, + VkAccelerationStructureBuildTypeKHR buildType, + const VkMicromapBuildInfoEXT* pBuildInfo, + VkMicromapBuildSizesInfoEXT* pSizeInfo); +#endif + + +// VK_EXT_load_store_op_none is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_load_store_op_none 1 +#define VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION 1 +#define VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_EXT_load_store_op_none" + + +// VK_HUAWEI_cluster_culling_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_HUAWEI_cluster_culling_shader 1 +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_SPEC_VERSION 2 +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_EXTENSION_NAME "VK_HUAWEI_cluster_culling_shader" +typedef struct VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 clustercullingShader; + VkBool32 multiviewClusterCullingShader; +} VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI; + +typedef struct VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI { + VkStructureType sType; + void* pNext; + uint32_t maxWorkGroupCount[3]; + uint32_t maxWorkGroupSize[3]; + uint32_t maxOutputClusterCount; + VkDeviceSize indirectBufferOffsetAlignment; +} VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawClusterHUAWEI)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (VKAPI_PTR *PFN_vkCmdDrawClusterIndirectHUAWEI)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawClusterHUAWEI( + VkCommandBuffer commandBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawClusterIndirectHUAWEI( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset); +#endif + + +// VK_EXT_border_color_swizzle is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_border_color_swizzle 1 +#define VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION 1 +#define VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME "VK_EXT_border_color_swizzle" +typedef struct VkPhysicalDeviceBorderColorSwizzleFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 borderColorSwizzle; + VkBool32 borderColorSwizzleFromImage; +} VkPhysicalDeviceBorderColorSwizzleFeaturesEXT; + +typedef struct VkSamplerBorderColorComponentMappingCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkComponentMapping components; + VkBool32 srgb; +} VkSamplerBorderColorComponentMappingCreateInfoEXT; + + + +// VK_EXT_pageable_device_local_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pageable_device_local_memory 1 +#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_SPEC_VERSION 1 +#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME "VK_EXT_pageable_device_local_memory" +typedef struct VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pageableDeviceLocalMemory; +} VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkSetDeviceMemoryPriorityEXT)(VkDevice device, VkDeviceMemory memory, float priority); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetDeviceMemoryPriorityEXT( + VkDevice device, + VkDeviceMemory memory, + float priority); +#endif + + +// VK_ARM_shader_core_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_shader_core_properties 1 +#define VK_ARM_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 +#define VK_ARM_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_ARM_shader_core_properties" +typedef struct VkPhysicalDeviceShaderCorePropertiesARM { + VkStructureType sType; + void* pNext; + uint32_t pixelRate; + uint32_t texelRate; + uint32_t fmaRate; +} VkPhysicalDeviceShaderCorePropertiesARM; + + + +// VK_ARM_scheduling_controls is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_scheduling_controls 1 +#define VK_ARM_SCHEDULING_CONTROLS_SPEC_VERSION 1 +#define VK_ARM_SCHEDULING_CONTROLS_EXTENSION_NAME "VK_ARM_scheduling_controls" +typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; + +typedef enum VkPhysicalDeviceSchedulingControlsFlagBitsARM { + VK_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_SHADER_CORE_COUNT_ARM = 0x00000001, + VK_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_FLAG_BITS_MAX_ENUM_ARM = 0x7FFFFFFF +} VkPhysicalDeviceSchedulingControlsFlagBitsARM; +typedef struct VkDeviceQueueShaderCoreControlCreateInfoARM { + VkStructureType sType; + void* pNext; + uint32_t shaderCoreCount; +} VkDeviceQueueShaderCoreControlCreateInfoARM; + +typedef struct VkPhysicalDeviceSchedulingControlsFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 schedulingControls; +} VkPhysicalDeviceSchedulingControlsFeaturesARM; + +typedef struct VkPhysicalDeviceSchedulingControlsPropertiesARM { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceSchedulingControlsFlagsARM schedulingControlsFlags; +} VkPhysicalDeviceSchedulingControlsPropertiesARM; + + + +// VK_EXT_image_sliced_view_of_3d is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_sliced_view_of_3d 1 +#define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_sliced_view_of_3d" +#define VK_REMAINING_3D_SLICES_EXT (~0U) +typedef struct VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 imageSlicedViewOf3D; +} VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT; + +typedef struct VkImageViewSlicedCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t sliceOffset; + uint32_t sliceCount; +} VkImageViewSlicedCreateInfoEXT; + + + +// VK_VALVE_descriptor_set_host_mapping is a preprocessor guard. Do not pass it to API calls. +#define VK_VALVE_descriptor_set_host_mapping 1 +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_SPEC_VERSION 1 +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_EXTENSION_NAME "VK_VALVE_descriptor_set_host_mapping" +typedef struct VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE { + VkStructureType sType; + void* pNext; + VkBool32 descriptorSetHostMapping; +} VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE; + +typedef struct VkDescriptorSetBindingReferenceVALVE { + VkStructureType sType; + const void* pNext; + VkDescriptorSetLayout descriptorSetLayout; + uint32_t binding; +} VkDescriptorSetBindingReferenceVALVE; + +typedef struct VkDescriptorSetLayoutHostMappingInfoVALVE { + VkStructureType sType; + void* pNext; + size_t descriptorOffset; + uint32_t descriptorSize; +} VkDescriptorSetLayoutHostMappingInfoVALVE; + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)(VkDevice device, const VkDescriptorSetBindingReferenceVALVE* pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE* pHostMapping); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetHostMappingVALVE)(VkDevice device, VkDescriptorSet descriptorSet, void** ppData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutHostMappingInfoVALVE( + VkDevice device, + const VkDescriptorSetBindingReferenceVALVE* pBindingReference, + VkDescriptorSetLayoutHostMappingInfoVALVE* pHostMapping); + +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetHostMappingVALVE( + VkDevice device, + VkDescriptorSet descriptorSet, + void** ppData); +#endif + + +// VK_EXT_depth_clamp_zero_one is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_clamp_zero_one 1 +#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_EXT_depth_clamp_zero_one" +typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthClampZeroOne; +} VkPhysicalDeviceDepthClampZeroOneFeaturesEXT; + + + +// VK_EXT_non_seamless_cube_map is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_non_seamless_cube_map 1 +#define VK_EXT_NON_SEAMLESS_CUBE_MAP_SPEC_VERSION 1 +#define VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME "VK_EXT_non_seamless_cube_map" +typedef struct VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 nonSeamlessCubeMap; +} VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT; + + + +// VK_QCOM_fragment_density_map_offset is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_fragment_density_map_offset 1 +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 1 +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_QCOM_fragment_density_map_offset" +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMapOffset; +} VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM { + VkStructureType sType; + void* pNext; + VkExtent2D fragmentDensityOffsetGranularity; +} VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM; + +typedef struct VkSubpassFragmentDensityMapOffsetEndInfoQCOM { + VkStructureType sType; + const void* pNext; + uint32_t fragmentDensityOffsetCount; + const VkOffset2D* pFragmentDensityOffsets; +} VkSubpassFragmentDensityMapOffsetEndInfoQCOM; + + + +// VK_NV_copy_memory_indirect is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_copy_memory_indirect 1 +#define VK_NV_COPY_MEMORY_INDIRECT_SPEC_VERSION 1 +#define VK_NV_COPY_MEMORY_INDIRECT_EXTENSION_NAME "VK_NV_copy_memory_indirect" +typedef struct VkCopyMemoryIndirectCommandNV { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize size; +} VkCopyMemoryIndirectCommandNV; + +typedef struct VkCopyMemoryToImageIndirectCommandNV { + VkDeviceAddress srcAddress; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkCopyMemoryToImageIndirectCommandNV; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 indirectCopy; +} VkPhysicalDeviceCopyMemoryIndirectFeaturesNV; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectPropertiesNV { + VkStructureType sType; + void* pNext; + VkQueueFlags supportedQueues; +} VkPhysicalDeviceCopyMemoryIndirectPropertiesNV; + +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryIndirectNV)(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToImageIndirectNV)(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageSubresourceLayers* pImageSubresources); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryIndirectNV( + VkCommandBuffer commandBuffer, + VkDeviceAddress copyBufferAddress, + uint32_t copyCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToImageIndirectNV( + VkCommandBuffer commandBuffer, + VkDeviceAddress copyBufferAddress, + uint32_t copyCount, + uint32_t stride, + VkImage dstImage, + VkImageLayout dstImageLayout, + const VkImageSubresourceLayers* pImageSubresources); +#endif + + +// VK_NV_memory_decompression is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_memory_decompression 1 +#define VK_NV_MEMORY_DECOMPRESSION_SPEC_VERSION 1 +#define VK_NV_MEMORY_DECOMPRESSION_EXTENSION_NAME "VK_NV_memory_decompression" + +// Flag bits for VkMemoryDecompressionMethodFlagBitsNV +typedef VkFlags64 VkMemoryDecompressionMethodFlagBitsNV; +static const VkMemoryDecompressionMethodFlagBitsNV VK_MEMORY_DECOMPRESSION_METHOD_GDEFLATE_1_0_BIT_NV = 0x00000001ULL; + +typedef VkFlags64 VkMemoryDecompressionMethodFlagsNV; +typedef struct VkDecompressMemoryRegionNV { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize compressedSize; + VkDeviceSize decompressedSize; + VkMemoryDecompressionMethodFlagsNV decompressionMethod; +} VkDecompressMemoryRegionNV; + +typedef struct VkPhysicalDeviceMemoryDecompressionFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 memoryDecompression; +} VkPhysicalDeviceMemoryDecompressionFeaturesNV; + +typedef struct VkPhysicalDeviceMemoryDecompressionPropertiesNV { + VkStructureType sType; + void* pNext; + VkMemoryDecompressionMethodFlagsNV decompressionMethods; + uint64_t maxDecompressionIndirectCount; +} VkPhysicalDeviceMemoryDecompressionPropertiesNV; + +typedef void (VKAPI_PTR *PFN_vkCmdDecompressMemoryNV)(VkCommandBuffer commandBuffer, uint32_t decompressRegionCount, const VkDecompressMemoryRegionNV* pDecompressMemoryRegions); +typedef void (VKAPI_PTR *PFN_vkCmdDecompressMemoryIndirectCountNV)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectCommandsAddress, VkDeviceAddress indirectCommandsCountAddress, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDecompressMemoryNV( + VkCommandBuffer commandBuffer, + uint32_t decompressRegionCount, + const VkDecompressMemoryRegionNV* pDecompressMemoryRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdDecompressMemoryIndirectCountNV( + VkCommandBuffer commandBuffer, + VkDeviceAddress indirectCommandsAddress, + VkDeviceAddress indirectCommandsCountAddress, + uint32_t stride); +#endif + + +// VK_NV_device_generated_commands_compute is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_device_generated_commands_compute 1 +#define VK_NV_DEVICE_GENERATED_COMMANDS_COMPUTE_SPEC_VERSION 2 +#define VK_NV_DEVICE_GENERATED_COMMANDS_COMPUTE_EXTENSION_NAME "VK_NV_device_generated_commands_compute" +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 deviceGeneratedCompute; + VkBool32 deviceGeneratedComputePipelines; + VkBool32 deviceGeneratedComputeCaptureReplay; +} VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV; + +typedef struct VkComputePipelineIndirectBufferInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; + VkDeviceAddress pipelineDeviceAddressCaptureReplay; +} VkComputePipelineIndirectBufferInfoNV; + +typedef struct VkPipelineIndirectDeviceAddressInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; +} VkPipelineIndirectDeviceAddressInfoNV; + +typedef struct VkBindPipelineIndirectCommandNV { + VkDeviceAddress pipelineAddress; +} VkBindPipelineIndirectCommandNV; + +typedef void (VKAPI_PTR *PFN_vkGetPipelineIndirectMemoryRequirementsNV)(VkDevice device, const VkComputePipelineCreateInfo* pCreateInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdUpdatePipelineIndirectBufferNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetPipelineIndirectDeviceAddressNV)(VkDevice device, const VkPipelineIndirectDeviceAddressInfoNV* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPipelineIndirectMemoryRequirementsNV( + VkDevice device, + const VkComputePipelineCreateInfo* pCreateInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkCmdUpdatePipelineIndirectBufferNV( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline); + +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetPipelineIndirectDeviceAddressNV( + VkDevice device, + const VkPipelineIndirectDeviceAddressInfoNV* pInfo); +#endif + + +// VK_NV_linear_color_attachment is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_linear_color_attachment 1 +#define VK_NV_LINEAR_COLOR_ATTACHMENT_SPEC_VERSION 1 +#define VK_NV_LINEAR_COLOR_ATTACHMENT_EXTENSION_NAME "VK_NV_linear_color_attachment" +typedef struct VkPhysicalDeviceLinearColorAttachmentFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 linearColorAttachment; +} VkPhysicalDeviceLinearColorAttachmentFeaturesNV; + + + +// VK_GOOGLE_surfaceless_query is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_surfaceless_query 1 +#define VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION 2 +#define VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME "VK_GOOGLE_surfaceless_query" + + +// VK_EXT_image_compression_control_swapchain is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_compression_control_swapchain 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME "VK_EXT_image_compression_control_swapchain" +typedef struct VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 imageCompressionControlSwapchain; +} VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT; + + + +// VK_QCOM_image_processing is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_image_processing 1 +#define VK_QCOM_IMAGE_PROCESSING_SPEC_VERSION 1 +#define VK_QCOM_IMAGE_PROCESSING_EXTENSION_NAME "VK_QCOM_image_processing" +typedef struct VkImageViewSampleWeightCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkOffset2D filterCenter; + VkExtent2D filterSize; + uint32_t numPhases; +} VkImageViewSampleWeightCreateInfoQCOM; + +typedef struct VkPhysicalDeviceImageProcessingFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 textureSampleWeighted; + VkBool32 textureBoxFilter; + VkBool32 textureBlockMatch; +} VkPhysicalDeviceImageProcessingFeaturesQCOM; + +typedef struct VkPhysicalDeviceImageProcessingPropertiesQCOM { + VkStructureType sType; + void* pNext; + uint32_t maxWeightFilterPhases; + VkExtent2D maxWeightFilterDimension; + VkExtent2D maxBlockMatchRegion; + VkExtent2D maxBoxFilterBlockSize; +} VkPhysicalDeviceImageProcessingPropertiesQCOM; + + + +// VK_EXT_nested_command_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_nested_command_buffer 1 +#define VK_EXT_NESTED_COMMAND_BUFFER_SPEC_VERSION 1 +#define VK_EXT_NESTED_COMMAND_BUFFER_EXTENSION_NAME "VK_EXT_nested_command_buffer" +typedef struct VkPhysicalDeviceNestedCommandBufferFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 nestedCommandBuffer; + VkBool32 nestedCommandBufferRendering; + VkBool32 nestedCommandBufferSimultaneousUse; +} VkPhysicalDeviceNestedCommandBufferFeaturesEXT; + +typedef struct VkPhysicalDeviceNestedCommandBufferPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxCommandBufferNestingLevel; +} VkPhysicalDeviceNestedCommandBufferPropertiesEXT; + + + +// VK_EXT_external_memory_acquire_unmodified is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_external_memory_acquire_unmodified 1 +#define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXTENSION_NAME "VK_EXT_external_memory_acquire_unmodified" +typedef struct VkExternalMemoryAcquireUnmodifiedEXT { + VkStructureType sType; + const void* pNext; + VkBool32 acquireUnmodifiedMemory; +} VkExternalMemoryAcquireUnmodifiedEXT; + + + +// VK_EXT_extended_dynamic_state3 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_extended_dynamic_state3 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_SPEC_VERSION 2 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME "VK_EXT_extended_dynamic_state3" +typedef struct VkPhysicalDeviceExtendedDynamicState3FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 extendedDynamicState3TessellationDomainOrigin; + VkBool32 extendedDynamicState3DepthClampEnable; + VkBool32 extendedDynamicState3PolygonMode; + VkBool32 extendedDynamicState3RasterizationSamples; + VkBool32 extendedDynamicState3SampleMask; + VkBool32 extendedDynamicState3AlphaToCoverageEnable; + VkBool32 extendedDynamicState3AlphaToOneEnable; + VkBool32 extendedDynamicState3LogicOpEnable; + VkBool32 extendedDynamicState3ColorBlendEnable; + VkBool32 extendedDynamicState3ColorBlendEquation; + VkBool32 extendedDynamicState3ColorWriteMask; + VkBool32 extendedDynamicState3RasterizationStream; + VkBool32 extendedDynamicState3ConservativeRasterizationMode; + VkBool32 extendedDynamicState3ExtraPrimitiveOverestimationSize; + VkBool32 extendedDynamicState3DepthClipEnable; + VkBool32 extendedDynamicState3SampleLocationsEnable; + VkBool32 extendedDynamicState3ColorBlendAdvanced; + VkBool32 extendedDynamicState3ProvokingVertexMode; + VkBool32 extendedDynamicState3LineRasterizationMode; + VkBool32 extendedDynamicState3LineStippleEnable; + VkBool32 extendedDynamicState3DepthClipNegativeOneToOne; + VkBool32 extendedDynamicState3ViewportWScalingEnable; + VkBool32 extendedDynamicState3ViewportSwizzle; + VkBool32 extendedDynamicState3CoverageToColorEnable; + VkBool32 extendedDynamicState3CoverageToColorLocation; + VkBool32 extendedDynamicState3CoverageModulationMode; + VkBool32 extendedDynamicState3CoverageModulationTableEnable; + VkBool32 extendedDynamicState3CoverageModulationTable; + VkBool32 extendedDynamicState3CoverageReductionMode; + VkBool32 extendedDynamicState3RepresentativeFragmentTestEnable; + VkBool32 extendedDynamicState3ShadingRateImageEnable; +} VkPhysicalDeviceExtendedDynamicState3FeaturesEXT; + +typedef struct VkPhysicalDeviceExtendedDynamicState3PropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 dynamicPrimitiveTopologyUnrestricted; +} VkPhysicalDeviceExtendedDynamicState3PropertiesEXT; + +typedef struct VkColorBlendEquationEXT { + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; +} VkColorBlendEquationEXT; + +typedef struct VkColorBlendAdvancedEXT { + VkBlendOp advancedBlendOp; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; + VkBool32 clampResults; +} VkColorBlendAdvancedEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetTessellationDomainOriginEXT)(VkCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClampEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetPolygonModeEXT)(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizationSamplesEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples); +typedef void (VKAPI_PTR *PFN_vkCmdSetSampleMaskEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits samples, const VkSampleMask* pSampleMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetAlphaToCoverageEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 alphaToCoverageEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetAlphaToOneEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 alphaToOneEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetLogicOpEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 logicOpEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendEnableEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkBool32* pColorBlendEnables); +typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendEquationEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendEquationEXT* pColorBlendEquations); +typedef void (VKAPI_PTR *PFN_vkCmdSetColorWriteMaskEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorComponentFlags* pColorWriteMasks); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizationStreamEXT)(VkCommandBuffer commandBuffer, uint32_t rasterizationStream); +typedef void (VKAPI_PTR *PFN_vkCmdSetConservativeRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkConservativeRasterizationModeEXT conservativeRasterizationMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT)(VkCommandBuffer commandBuffer, float extraPrimitiveOverestimationSize); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClipEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClipEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 sampleLocationsEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendAdvancedEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendAdvancedEXT* pColorBlendAdvanced); +typedef void (VKAPI_PTR *PFN_vkCmdSetProvokingVertexModeEXT)(VkCommandBuffer commandBuffer, VkProvokingVertexModeEXT provokingVertexMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkLineRasterizationModeEXT lineRasterizationMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stippledLineEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClipNegativeOneToOneEXT)(VkCommandBuffer commandBuffer, VkBool32 negativeOneToOne); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingEnableNV)(VkCommandBuffer commandBuffer, VkBool32 viewportWScalingEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportSwizzleNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportSwizzleNV* pViewportSwizzles); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageToColorEnableNV)(VkCommandBuffer commandBuffer, VkBool32 coverageToColorEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageToColorLocationNV)(VkCommandBuffer commandBuffer, uint32_t coverageToColorLocation); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationModeNV)(VkCommandBuffer commandBuffer, VkCoverageModulationModeNV coverageModulationMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationTableEnableNV)(VkCommandBuffer commandBuffer, VkBool32 coverageModulationTableEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationTableNV)(VkCommandBuffer commandBuffer, uint32_t coverageModulationTableCount, const float* pCoverageModulationTable); +typedef void (VKAPI_PTR *PFN_vkCmdSetShadingRateImageEnableNV)(VkCommandBuffer commandBuffer, VkBool32 shadingRateImageEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetRepresentativeFragmentTestEnableNV)(VkCommandBuffer commandBuffer, VkBool32 representativeFragmentTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageReductionModeNV)(VkCommandBuffer commandBuffer, VkCoverageReductionModeNV coverageReductionMode); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetTessellationDomainOriginEXT( + VkCommandBuffer commandBuffer, + VkTessellationDomainOrigin domainOrigin); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthClampEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthClampEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPolygonModeEXT( + VkCommandBuffer commandBuffer, + VkPolygonMode polygonMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizationSamplesEXT( + VkCommandBuffer commandBuffer, + VkSampleCountFlagBits rasterizationSamples); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleMaskEXT( + VkCommandBuffer commandBuffer, + VkSampleCountFlagBits samples, + const VkSampleMask* pSampleMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetAlphaToCoverageEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 alphaToCoverageEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetAlphaToOneEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 alphaToOneEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLogicOpEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 logicOpEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorBlendEnableEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkBool32* pColorBlendEnables); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorBlendEquationEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorBlendEquationEXT* pColorBlendEquations); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorWriteMaskEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorComponentFlags* pColorWriteMasks); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizationStreamEXT( + VkCommandBuffer commandBuffer, + uint32_t rasterizationStream); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetConservativeRasterizationModeEXT( + VkCommandBuffer commandBuffer, + VkConservativeRasterizationModeEXT conservativeRasterizationMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetExtraPrimitiveOverestimationSizeEXT( + VkCommandBuffer commandBuffer, + float extraPrimitiveOverestimationSize); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthClipEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthClipEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 sampleLocationsEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorBlendAdvancedEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorBlendAdvancedEXT* pColorBlendAdvanced); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetProvokingVertexModeEXT( + VkCommandBuffer commandBuffer, + VkProvokingVertexModeEXT provokingVertexMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineRasterizationModeEXT( + VkCommandBuffer commandBuffer, + VkLineRasterizationModeEXT lineRasterizationMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 stippledLineEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthClipNegativeOneToOneEXT( + VkCommandBuffer commandBuffer, + VkBool32 negativeOneToOne); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 viewportWScalingEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportSwizzleNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewportSwizzleNV* pViewportSwizzles); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageToColorEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 coverageToColorEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageToColorLocationNV( + VkCommandBuffer commandBuffer, + uint32_t coverageToColorLocation); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageModulationModeNV( + VkCommandBuffer commandBuffer, + VkCoverageModulationModeNV coverageModulationMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageModulationTableEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 coverageModulationTableEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageModulationTableNV( + VkCommandBuffer commandBuffer, + uint32_t coverageModulationTableCount, + const float* pCoverageModulationTable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetShadingRateImageEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 shadingRateImageEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRepresentativeFragmentTestEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 representativeFragmentTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageReductionModeNV( + VkCommandBuffer commandBuffer, + VkCoverageReductionModeNV coverageReductionMode); +#endif + + +// VK_EXT_subpass_merge_feedback is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_subpass_merge_feedback 1 +#define VK_EXT_SUBPASS_MERGE_FEEDBACK_SPEC_VERSION 2 +#define VK_EXT_SUBPASS_MERGE_FEEDBACK_EXTENSION_NAME "VK_EXT_subpass_merge_feedback" + +typedef enum VkSubpassMergeStatusEXT { + VK_SUBPASS_MERGE_STATUS_MERGED_EXT = 0, + VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT = 1, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SIDE_EFFECTS_EXT = 2, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SAMPLES_MISMATCH_EXT = 3, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_VIEWS_MISMATCH_EXT = 4, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_ALIASING_EXT = 5, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPENDENCIES_EXT = 6, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INCOMPATIBLE_INPUT_ATTACHMENT_EXT = 7, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_TOO_MANY_ATTACHMENTS_EXT = 8, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INSUFFICIENT_STORAGE_EXT = 9, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPTH_STENCIL_COUNT_EXT = 10, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_RESOLVE_ATTACHMENT_REUSE_EXT = 11, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT = 12, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_UNSPECIFIED_EXT = 13, + VK_SUBPASS_MERGE_STATUS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSubpassMergeStatusEXT; +typedef struct VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 subpassMergeFeedback; +} VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT; + +typedef struct VkRenderPassCreationControlEXT { + VkStructureType sType; + const void* pNext; + VkBool32 disallowMerging; +} VkRenderPassCreationControlEXT; + +typedef struct VkRenderPassCreationFeedbackInfoEXT { + uint32_t postMergeSubpassCount; +} VkRenderPassCreationFeedbackInfoEXT; + +typedef struct VkRenderPassCreationFeedbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkRenderPassCreationFeedbackInfoEXT* pRenderPassFeedback; +} VkRenderPassCreationFeedbackCreateInfoEXT; + +typedef struct VkRenderPassSubpassFeedbackInfoEXT { + VkSubpassMergeStatusEXT subpassMergeStatus; + char description[VK_MAX_DESCRIPTION_SIZE]; + uint32_t postMergeIndex; +} VkRenderPassSubpassFeedbackInfoEXT; + +typedef struct VkRenderPassSubpassFeedbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkRenderPassSubpassFeedbackInfoEXT* pSubpassFeedback; +} VkRenderPassSubpassFeedbackCreateInfoEXT; + + + +// VK_LUNARG_direct_driver_loading is a preprocessor guard. Do not pass it to API calls. +#define VK_LUNARG_direct_driver_loading 1 +#define VK_LUNARG_DIRECT_DRIVER_LOADING_SPEC_VERSION 1 +#define VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME "VK_LUNARG_direct_driver_loading" + +typedef enum VkDirectDriverLoadingModeLUNARG { + VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG = 0, + VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG = 1, + VK_DIRECT_DRIVER_LOADING_MODE_MAX_ENUM_LUNARG = 0x7FFFFFFF +} VkDirectDriverLoadingModeLUNARG; +typedef VkFlags VkDirectDriverLoadingFlagsLUNARG; +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddrLUNARG)( + VkInstance instance, const char* pName); + +typedef struct VkDirectDriverLoadingInfoLUNARG { + VkStructureType sType; + void* pNext; + VkDirectDriverLoadingFlagsLUNARG flags; + PFN_vkGetInstanceProcAddrLUNARG pfnGetInstanceProcAddr; +} VkDirectDriverLoadingInfoLUNARG; + +typedef struct VkDirectDriverLoadingListLUNARG { + VkStructureType sType; + const void* pNext; + VkDirectDriverLoadingModeLUNARG mode; + uint32_t driverCount; + const VkDirectDriverLoadingInfoLUNARG* pDrivers; +} VkDirectDriverLoadingListLUNARG; + + + +// VK_EXT_shader_module_identifier is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_module_identifier 1 +#define VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT 32U +#define VK_EXT_SHADER_MODULE_IDENTIFIER_SPEC_VERSION 1 +#define VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME "VK_EXT_shader_module_identifier" +typedef struct VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderModuleIdentifier; +} VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT { + VkStructureType sType; + void* pNext; + uint8_t shaderModuleIdentifierAlgorithmUUID[VK_UUID_SIZE]; +} VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT; + +typedef struct VkPipelineShaderStageModuleIdentifierCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t identifierSize; + const uint8_t* pIdentifier; +} VkPipelineShaderStageModuleIdentifierCreateInfoEXT; + +typedef struct VkShaderModuleIdentifierEXT { + VkStructureType sType; + void* pNext; + uint32_t identifierSize; + uint8_t identifier[VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT]; +} VkShaderModuleIdentifierEXT; + +typedef void (VKAPI_PTR *PFN_vkGetShaderModuleIdentifierEXT)(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT* pIdentifier); +typedef void (VKAPI_PTR *PFN_vkGetShaderModuleCreateInfoIdentifierEXT)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModuleIdentifierEXT* pIdentifier); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetShaderModuleIdentifierEXT( + VkDevice device, + VkShaderModule shaderModule, + VkShaderModuleIdentifierEXT* pIdentifier); + +VKAPI_ATTR void VKAPI_CALL vkGetShaderModuleCreateInfoIdentifierEXT( + VkDevice device, + const VkShaderModuleCreateInfo* pCreateInfo, + VkShaderModuleIdentifierEXT* pIdentifier); +#endif + + +// VK_EXT_rasterization_order_attachment_access is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_rasterization_order_attachment_access 1 +#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_EXT_rasterization_order_attachment_access" + + +// VK_NV_optical_flow is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_optical_flow 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkOpticalFlowSessionNV) +#define VK_NV_OPTICAL_FLOW_SPEC_VERSION 1 +#define VK_NV_OPTICAL_FLOW_EXTENSION_NAME "VK_NV_optical_flow" + +typedef enum VkOpticalFlowPerformanceLevelNV { + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV = 1, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV = 2, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV = 3, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowPerformanceLevelNV; + +typedef enum VkOpticalFlowSessionBindingPointNV { + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_INPUT_NV = 1, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_REFERENCE_NV = 2, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_HINT_NV = 3, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_FLOW_VECTOR_NV = 4, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_FLOW_VECTOR_NV = 5, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_COST_NV = 6, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_COST_NV = 7, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_GLOBAL_FLOW_NV = 8, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowSessionBindingPointNV; + +typedef enum VkOpticalFlowGridSizeFlagBitsNV { + VK_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV = 0x00000001, + VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV = 0x00000002, + VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV = 0x00000004, + VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV = 0x00000008, + VK_OPTICAL_FLOW_GRID_SIZE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowGridSizeFlagBitsNV; +typedef VkFlags VkOpticalFlowGridSizeFlagsNV; + +typedef enum VkOpticalFlowUsageFlagBitsNV { + VK_OPTICAL_FLOW_USAGE_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_USAGE_INPUT_BIT_NV = 0x00000001, + VK_OPTICAL_FLOW_USAGE_OUTPUT_BIT_NV = 0x00000002, + VK_OPTICAL_FLOW_USAGE_HINT_BIT_NV = 0x00000004, + VK_OPTICAL_FLOW_USAGE_COST_BIT_NV = 0x00000008, + VK_OPTICAL_FLOW_USAGE_GLOBAL_FLOW_BIT_NV = 0x00000010, + VK_OPTICAL_FLOW_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowUsageFlagBitsNV; +typedef VkFlags VkOpticalFlowUsageFlagsNV; + +typedef enum VkOpticalFlowSessionCreateFlagBitsNV { + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_HINT_BIT_NV = 0x00000001, + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_COST_BIT_NV = 0x00000002, + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_GLOBAL_FLOW_BIT_NV = 0x00000004, + VK_OPTICAL_FLOW_SESSION_CREATE_ALLOW_REGIONS_BIT_NV = 0x00000008, + VK_OPTICAL_FLOW_SESSION_CREATE_BOTH_DIRECTIONS_BIT_NV = 0x00000010, + VK_OPTICAL_FLOW_SESSION_CREATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowSessionCreateFlagBitsNV; +typedef VkFlags VkOpticalFlowSessionCreateFlagsNV; + +typedef enum VkOpticalFlowExecuteFlagBitsNV { + VK_OPTICAL_FLOW_EXECUTE_DISABLE_TEMPORAL_HINTS_BIT_NV = 0x00000001, + VK_OPTICAL_FLOW_EXECUTE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowExecuteFlagBitsNV; +typedef VkFlags VkOpticalFlowExecuteFlagsNV; +typedef struct VkPhysicalDeviceOpticalFlowFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 opticalFlow; +} VkPhysicalDeviceOpticalFlowFeaturesNV; + +typedef struct VkPhysicalDeviceOpticalFlowPropertiesNV { + VkStructureType sType; + void* pNext; + VkOpticalFlowGridSizeFlagsNV supportedOutputGridSizes; + VkOpticalFlowGridSizeFlagsNV supportedHintGridSizes; + VkBool32 hintSupported; + VkBool32 costSupported; + VkBool32 bidirectionalFlowSupported; + VkBool32 globalFlowSupported; + uint32_t minWidth; + uint32_t minHeight; + uint32_t maxWidth; + uint32_t maxHeight; + uint32_t maxNumRegionsOfInterest; +} VkPhysicalDeviceOpticalFlowPropertiesNV; + +typedef struct VkOpticalFlowImageFormatInfoNV { + VkStructureType sType; + const void* pNext; + VkOpticalFlowUsageFlagsNV usage; +} VkOpticalFlowImageFormatInfoNV; + +typedef struct VkOpticalFlowImageFormatPropertiesNV { + VkStructureType sType; + const void* pNext; + VkFormat format; +} VkOpticalFlowImageFormatPropertiesNV; + +typedef struct VkOpticalFlowSessionCreateInfoNV { + VkStructureType sType; + void* pNext; + uint32_t width; + uint32_t height; + VkFormat imageFormat; + VkFormat flowVectorFormat; + VkFormat costFormat; + VkOpticalFlowGridSizeFlagsNV outputGridSize; + VkOpticalFlowGridSizeFlagsNV hintGridSize; + VkOpticalFlowPerformanceLevelNV performanceLevel; + VkOpticalFlowSessionCreateFlagsNV flags; +} VkOpticalFlowSessionCreateInfoNV; + +typedef struct VkOpticalFlowSessionCreatePrivateDataInfoNV { + VkStructureType sType; + void* pNext; + uint32_t id; + uint32_t size; + const void* pPrivateData; +} VkOpticalFlowSessionCreatePrivateDataInfoNV; + +typedef struct VkOpticalFlowExecuteInfoNV { + VkStructureType sType; + void* pNext; + VkOpticalFlowExecuteFlagsNV flags; + uint32_t regionCount; + const VkRect2D* pRegions; +} VkOpticalFlowExecuteInfoNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV)(VkPhysicalDevice physicalDevice, const VkOpticalFlowImageFormatInfoNV* pOpticalFlowImageFormatInfo, uint32_t* pFormatCount, VkOpticalFlowImageFormatPropertiesNV* pImageFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateOpticalFlowSessionNV)(VkDevice device, const VkOpticalFlowSessionCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkOpticalFlowSessionNV* pSession); +typedef void (VKAPI_PTR *PFN_vkDestroyOpticalFlowSessionNV)(VkDevice device, VkOpticalFlowSessionNV session, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkBindOpticalFlowSessionImageNV)(VkDevice device, VkOpticalFlowSessionNV session, VkOpticalFlowSessionBindingPointNV bindingPoint, VkImageView view, VkImageLayout layout); +typedef void (VKAPI_PTR *PFN_vkCmdOpticalFlowExecuteNV)(VkCommandBuffer commandBuffer, VkOpticalFlowSessionNV session, const VkOpticalFlowExecuteInfoNV* pExecuteInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceOpticalFlowImageFormatsNV( + VkPhysicalDevice physicalDevice, + const VkOpticalFlowImageFormatInfoNV* pOpticalFlowImageFormatInfo, + uint32_t* pFormatCount, + VkOpticalFlowImageFormatPropertiesNV* pImageFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateOpticalFlowSessionNV( + VkDevice device, + const VkOpticalFlowSessionCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkOpticalFlowSessionNV* pSession); + +VKAPI_ATTR void VKAPI_CALL vkDestroyOpticalFlowSessionNV( + VkDevice device, + VkOpticalFlowSessionNV session, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindOpticalFlowSessionImageNV( + VkDevice device, + VkOpticalFlowSessionNV session, + VkOpticalFlowSessionBindingPointNV bindingPoint, + VkImageView view, + VkImageLayout layout); + +VKAPI_ATTR void VKAPI_CALL vkCmdOpticalFlowExecuteNV( + VkCommandBuffer commandBuffer, + VkOpticalFlowSessionNV session, + const VkOpticalFlowExecuteInfoNV* pExecuteInfo); +#endif + + +// VK_EXT_legacy_dithering is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_legacy_dithering 1 +#define VK_EXT_LEGACY_DITHERING_SPEC_VERSION 1 +#define VK_EXT_LEGACY_DITHERING_EXTENSION_NAME "VK_EXT_legacy_dithering" +typedef struct VkPhysicalDeviceLegacyDitheringFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 legacyDithering; +} VkPhysicalDeviceLegacyDitheringFeaturesEXT; + + + +// VK_EXT_pipeline_protected_access is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_protected_access 1 +#define VK_EXT_PIPELINE_PROTECTED_ACCESS_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME "VK_EXT_pipeline_protected_access" +typedef struct VkPhysicalDevicePipelineProtectedAccessFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pipelineProtectedAccess; +} VkPhysicalDevicePipelineProtectedAccessFeaturesEXT; + + + +// VK_EXT_shader_object is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_object 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderEXT) +#define VK_EXT_SHADER_OBJECT_SPEC_VERSION 1 +#define VK_EXT_SHADER_OBJECT_EXTENSION_NAME "VK_EXT_shader_object" + +typedef enum VkShaderCodeTypeEXT { + VK_SHADER_CODE_TYPE_BINARY_EXT = 0, + VK_SHADER_CODE_TYPE_SPIRV_EXT = 1, + VK_SHADER_CODE_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkShaderCodeTypeEXT; + +typedef enum VkShaderCreateFlagBitsEXT { + VK_SHADER_CREATE_LINK_STAGE_BIT_EXT = 0x00000001, + VK_SHADER_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = 0x00000002, + VK_SHADER_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = 0x00000004, + VK_SHADER_CREATE_NO_TASK_SHADER_BIT_EXT = 0x00000008, + VK_SHADER_CREATE_DISPATCH_BASE_BIT_EXT = 0x00000010, + VK_SHADER_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_EXT = 0x00000020, + VK_SHADER_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 0x00000040, + VK_SHADER_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkShaderCreateFlagBitsEXT; +typedef VkFlags VkShaderCreateFlagsEXT; +typedef struct VkPhysicalDeviceShaderObjectFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderObject; +} VkPhysicalDeviceShaderObjectFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderObjectPropertiesEXT { + VkStructureType sType; + void* pNext; + uint8_t shaderBinaryUUID[VK_UUID_SIZE]; + uint32_t shaderBinaryVersion; +} VkPhysicalDeviceShaderObjectPropertiesEXT; + +typedef struct VkShaderCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkShaderCreateFlagsEXT flags; + VkShaderStageFlagBits stage; + VkShaderStageFlags nextStage; + VkShaderCodeTypeEXT codeType; + size_t codeSize; + const void* pCode; + const char* pName; + uint32_t setLayoutCount; + const VkDescriptorSetLayout* pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange* pPushConstantRanges; + const VkSpecializationInfo* pSpecializationInfo; +} VkShaderCreateInfoEXT; + +typedef VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkShaderRequiredSubgroupSizeCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateShadersEXT)(VkDevice device, uint32_t createInfoCount, const VkShaderCreateInfoEXT* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkShaderEXT* pShaders); +typedef void (VKAPI_PTR *PFN_vkDestroyShaderEXT)(VkDevice device, VkShaderEXT shader, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetShaderBinaryDataEXT)(VkDevice device, VkShaderEXT shader, size_t* pDataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdBindShadersEXT)(VkCommandBuffer commandBuffer, uint32_t stageCount, const VkShaderStageFlagBits* pStages, const VkShaderEXT* pShaders); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateShadersEXT( + VkDevice device, + uint32_t createInfoCount, + const VkShaderCreateInfoEXT* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkShaderEXT* pShaders); + +VKAPI_ATTR void VKAPI_CALL vkDestroyShaderEXT( + VkDevice device, + VkShaderEXT shader, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderBinaryDataEXT( + VkDevice device, + VkShaderEXT shader, + size_t* pDataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindShadersEXT( + VkCommandBuffer commandBuffer, + uint32_t stageCount, + const VkShaderStageFlagBits* pStages, + const VkShaderEXT* pShaders); +#endif + + +// VK_QCOM_tile_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_tile_properties 1 +#define VK_QCOM_TILE_PROPERTIES_SPEC_VERSION 1 +#define VK_QCOM_TILE_PROPERTIES_EXTENSION_NAME "VK_QCOM_tile_properties" +typedef struct VkPhysicalDeviceTilePropertiesFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 tileProperties; +} VkPhysicalDeviceTilePropertiesFeaturesQCOM; + +typedef struct VkTilePropertiesQCOM { + VkStructureType sType; + void* pNext; + VkExtent3D tileSize; + VkExtent2D apronSize; + VkOffset2D origin; +} VkTilePropertiesQCOM; + +typedef VkResult (VKAPI_PTR *PFN_vkGetFramebufferTilePropertiesQCOM)(VkDevice device, VkFramebuffer framebuffer, uint32_t* pPropertiesCount, VkTilePropertiesQCOM* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDynamicRenderingTilePropertiesQCOM)(VkDevice device, const VkRenderingInfo* pRenderingInfo, VkTilePropertiesQCOM* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetFramebufferTilePropertiesQCOM( + VkDevice device, + VkFramebuffer framebuffer, + uint32_t* pPropertiesCount, + VkTilePropertiesQCOM* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDynamicRenderingTilePropertiesQCOM( + VkDevice device, + const VkRenderingInfo* pRenderingInfo, + VkTilePropertiesQCOM* pProperties); +#endif + + +// VK_SEC_amigo_profiling is a preprocessor guard. Do not pass it to API calls. +#define VK_SEC_amigo_profiling 1 +#define VK_SEC_AMIGO_PROFILING_SPEC_VERSION 1 +#define VK_SEC_AMIGO_PROFILING_EXTENSION_NAME "VK_SEC_amigo_profiling" +typedef struct VkPhysicalDeviceAmigoProfilingFeaturesSEC { + VkStructureType sType; + void* pNext; + VkBool32 amigoProfiling; +} VkPhysicalDeviceAmigoProfilingFeaturesSEC; + +typedef struct VkAmigoProfilingSubmitInfoSEC { + VkStructureType sType; + const void* pNext; + uint64_t firstDrawTimestamp; + uint64_t swapBufferTimestamp; +} VkAmigoProfilingSubmitInfoSEC; + + + +// VK_QCOM_multiview_per_view_viewports is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_multiview_per_view_viewports 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_SPEC_VERSION 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME "VK_QCOM_multiview_per_view_viewports" +typedef struct VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 multiviewPerViewViewports; +} VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM; + + + +// VK_NV_ray_tracing_invocation_reorder is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_ray_tracing_invocation_reorder 1 +#define VK_NV_RAY_TRACING_INVOCATION_REORDER_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME "VK_NV_ray_tracing_invocation_reorder" + +typedef enum VkRayTracingInvocationReorderModeNV { + VK_RAY_TRACING_INVOCATION_REORDER_MODE_NONE_NV = 0, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_REORDER_NV = 1, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingInvocationReorderModeNV; +typedef struct VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV { + VkStructureType sType; + void* pNext; + VkRayTracingInvocationReorderModeNV rayTracingInvocationReorderReorderingHint; +} VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV; + +typedef struct VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingInvocationReorder; +} VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV; + + + +// VK_NV_extended_sparse_address_space is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_extended_sparse_address_space 1 +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_SPEC_VERSION 1 +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_EXTENSION_NAME "VK_NV_extended_sparse_address_space" +typedef struct VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 extendedSparseAddressSpace; +} VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV; + +typedef struct VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV { + VkStructureType sType; + void* pNext; + VkDeviceSize extendedSparseAddressSpaceSize; + VkImageUsageFlags extendedSparseImageUsageFlags; + VkBufferUsageFlags extendedSparseBufferUsageFlags; +} VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV; + + + +// VK_EXT_mutable_descriptor_type is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_mutable_descriptor_type 1 +#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 +#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_EXT_mutable_descriptor_type" + + +// VK_ARM_shader_core_builtins is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_shader_core_builtins 1 +#define VK_ARM_SHADER_CORE_BUILTINS_SPEC_VERSION 2 +#define VK_ARM_SHADER_CORE_BUILTINS_EXTENSION_NAME "VK_ARM_shader_core_builtins" +typedef struct VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 shaderCoreBuiltins; +} VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM; + +typedef struct VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM { + VkStructureType sType; + void* pNext; + uint64_t shaderCoreMask; + uint32_t shaderCoreCount; + uint32_t shaderWarpsPerCore; +} VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM; + + + +// VK_EXT_pipeline_library_group_handles is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_library_group_handles 1 +#define VK_EXT_PIPELINE_LIBRARY_GROUP_HANDLES_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_LIBRARY_GROUP_HANDLES_EXTENSION_NAME "VK_EXT_pipeline_library_group_handles" +typedef struct VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pipelineLibraryGroupHandles; +} VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT; + + + +// VK_EXT_dynamic_rendering_unused_attachments is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_dynamic_rendering_unused_attachments 1 +#define VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_SPEC_VERSION 1 +#define VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME "VK_EXT_dynamic_rendering_unused_attachments" +typedef struct VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 dynamicRenderingUnusedAttachments; +} VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT; + + + +// VK_NV_low_latency2 is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_low_latency2 1 +#define VK_NV_LOW_LATENCY_2_SPEC_VERSION 1 +#define VK_NV_LOW_LATENCY_2_EXTENSION_NAME "VK_NV_low_latency2" + +typedef enum VkLatencyMarkerNV { + VK_LATENCY_MARKER_SIMULATION_START_NV = 0, + VK_LATENCY_MARKER_SIMULATION_END_NV = 1, + VK_LATENCY_MARKER_RENDERSUBMIT_START_NV = 2, + VK_LATENCY_MARKER_RENDERSUBMIT_END_NV = 3, + VK_LATENCY_MARKER_PRESENT_START_NV = 4, + VK_LATENCY_MARKER_PRESENT_END_NV = 5, + VK_LATENCY_MARKER_INPUT_SAMPLE_NV = 6, + VK_LATENCY_MARKER_TRIGGER_FLASH_NV = 7, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_START_NV = 8, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_END_NV = 9, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_START_NV = 10, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_END_NV = 11, + VK_LATENCY_MARKER_MAX_ENUM_NV = 0x7FFFFFFF +} VkLatencyMarkerNV; + +typedef enum VkOutOfBandQueueTypeNV { + VK_OUT_OF_BAND_QUEUE_TYPE_RENDER_NV = 0, + VK_OUT_OF_BAND_QUEUE_TYPE_PRESENT_NV = 1, + VK_OUT_OF_BAND_QUEUE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkOutOfBandQueueTypeNV; +typedef struct VkLatencySleepModeInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 lowLatencyMode; + VkBool32 lowLatencyBoost; + uint32_t minimumIntervalUs; +} VkLatencySleepModeInfoNV; + +typedef struct VkLatencySleepInfoNV { + VkStructureType sType; + const void* pNext; + VkSemaphore signalSemaphore; + uint64_t value; +} VkLatencySleepInfoNV; + +typedef struct VkSetLatencyMarkerInfoNV { + VkStructureType sType; + const void* pNext; + uint64_t presentID; + VkLatencyMarkerNV marker; +} VkSetLatencyMarkerInfoNV; + +typedef struct VkLatencyTimingsFrameReportNV { + VkStructureType sType; + const void* pNext; + uint64_t presentID; + uint64_t inputSampleTimeUs; + uint64_t simStartTimeUs; + uint64_t simEndTimeUs; + uint64_t renderSubmitStartTimeUs; + uint64_t renderSubmitEndTimeUs; + uint64_t presentStartTimeUs; + uint64_t presentEndTimeUs; + uint64_t driverStartTimeUs; + uint64_t driverEndTimeUs; + uint64_t osRenderQueueStartTimeUs; + uint64_t osRenderQueueEndTimeUs; + uint64_t gpuRenderStartTimeUs; + uint64_t gpuRenderEndTimeUs; +} VkLatencyTimingsFrameReportNV; + +typedef struct VkGetLatencyMarkerInfoNV { + VkStructureType sType; + const void* pNext; + VkLatencyTimingsFrameReportNV* pTimings; +} VkGetLatencyMarkerInfoNV; + +typedef struct VkLatencySubmissionPresentIdNV { + VkStructureType sType; + const void* pNext; + uint64_t presentID; +} VkLatencySubmissionPresentIdNV; + +typedef struct VkSwapchainLatencyCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 latencyModeEnable; +} VkSwapchainLatencyCreateInfoNV; + +typedef struct VkOutOfBandQueueTypeInfoNV { + VkStructureType sType; + const void* pNext; + VkOutOfBandQueueTypeNV queueType; +} VkOutOfBandQueueTypeInfoNV; + +typedef struct VkLatencySurfaceCapabilitiesNV { + VkStructureType sType; + const void* pNext; + uint32_t presentModeCount; + VkPresentModeKHR* pPresentModes; +} VkLatencySurfaceCapabilitiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkSetLatencySleepModeNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV* pSleepModeInfo); +typedef VkResult (VKAPI_PTR *PFN_vkLatencySleepNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV* pSleepInfo); +typedef void (VKAPI_PTR *PFN_vkSetLatencyMarkerNV)(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV* pLatencyMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkGetLatencyTimingsNV)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pTimingCount, VkGetLatencyMarkerInfoNV* pLatencyMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkQueueNotifyOutOfBandNV)(VkQueue queue, const VkOutOfBandQueueTypeInfoNV* pQueueTypeInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetLatencySleepModeNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkLatencySleepModeInfoNV* pSleepModeInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkLatencySleepNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkLatencySleepInfoNV* pSleepInfo); + +VKAPI_ATTR void VKAPI_CALL vkSetLatencyMarkerNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkSetLatencyMarkerInfoNV* pLatencyMarkerInfo); + +VKAPI_ATTR void VKAPI_CALL vkGetLatencyTimingsNV( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pTimingCount, + VkGetLatencyMarkerInfoNV* pLatencyMarkerInfo); + +VKAPI_ATTR void VKAPI_CALL vkQueueNotifyOutOfBandNV( + VkQueue queue, + const VkOutOfBandQueueTypeInfoNV* pQueueTypeInfo); +#endif + + +// VK_QCOM_multiview_per_view_render_areas is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_multiview_per_view_render_areas 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_SPEC_VERSION 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_EXTENSION_NAME "VK_QCOM_multiview_per_view_render_areas" +typedef struct VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 multiviewPerViewRenderAreas; +} VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM; + +typedef struct VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM { + VkStructureType sType; + const void* pNext; + uint32_t perViewRenderAreaCount; + const VkRect2D* pPerViewRenderAreas; +} VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM; + + + +// VK_QCOM_image_processing2 is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_image_processing2 1 +#define VK_QCOM_IMAGE_PROCESSING_2_SPEC_VERSION 1 +#define VK_QCOM_IMAGE_PROCESSING_2_EXTENSION_NAME "VK_QCOM_image_processing2" + +typedef enum VkBlockMatchWindowCompareModeQCOM { + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MIN_QCOM = 0, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_QCOM = 1, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkBlockMatchWindowCompareModeQCOM; +typedef struct VkPhysicalDeviceImageProcessing2FeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 textureBlockMatch2; +} VkPhysicalDeviceImageProcessing2FeaturesQCOM; + +typedef struct VkPhysicalDeviceImageProcessing2PropertiesQCOM { + VkStructureType sType; + void* pNext; + VkExtent2D maxBlockMatchWindow; +} VkPhysicalDeviceImageProcessing2PropertiesQCOM; + +typedef struct VkSamplerBlockMatchWindowCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkExtent2D windowExtent; + VkBlockMatchWindowCompareModeQCOM windowCompareMode; +} VkSamplerBlockMatchWindowCreateInfoQCOM; + + + +// VK_QCOM_filter_cubic_weights is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_filter_cubic_weights 1 +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_SPEC_VERSION 1 +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_EXTENSION_NAME "VK_QCOM_filter_cubic_weights" + +typedef enum VkCubicFilterWeightsQCOM { + VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM = 0, + VK_CUBIC_FILTER_WEIGHTS_ZERO_TANGENT_CARDINAL_QCOM = 1, + VK_CUBIC_FILTER_WEIGHTS_B_SPLINE_QCOM = 2, + VK_CUBIC_FILTER_WEIGHTS_MITCHELL_NETRAVALI_QCOM = 3, + VK_CUBIC_FILTER_WEIGHTS_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkCubicFilterWeightsQCOM; +typedef struct VkPhysicalDeviceCubicWeightsFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 selectableCubicWeights; +} VkPhysicalDeviceCubicWeightsFeaturesQCOM; + +typedef struct VkSamplerCubicWeightsCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkSamplerCubicWeightsCreateInfoQCOM; + +typedef struct VkBlitImageCubicWeightsInfoQCOM { + VkStructureType sType; + const void* pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkBlitImageCubicWeightsInfoQCOM; + + + +// VK_QCOM_ycbcr_degamma is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_ycbcr_degamma 1 +#define VK_QCOM_YCBCR_DEGAMMA_SPEC_VERSION 1 +#define VK_QCOM_YCBCR_DEGAMMA_EXTENSION_NAME "VK_QCOM_ycbcr_degamma" +typedef struct VkPhysicalDeviceYcbcrDegammaFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 ycbcrDegamma; +} VkPhysicalDeviceYcbcrDegammaFeaturesQCOM; + +typedef struct VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM { + VkStructureType sType; + void* pNext; + VkBool32 enableYDegamma; + VkBool32 enableCbCrDegamma; +} VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM; + + + +// VK_QCOM_filter_cubic_clamp is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_filter_cubic_clamp 1 +#define VK_QCOM_FILTER_CUBIC_CLAMP_SPEC_VERSION 1 +#define VK_QCOM_FILTER_CUBIC_CLAMP_EXTENSION_NAME "VK_QCOM_filter_cubic_clamp" +typedef struct VkPhysicalDeviceCubicClampFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 cubicRangeClamp; +} VkPhysicalDeviceCubicClampFeaturesQCOM; + + + +// VK_EXT_attachment_feedback_loop_dynamic_state is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_attachment_feedback_loop_dynamic_state 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_dynamic_state" +typedef struct VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 attachmentFeedbackLoopDynamicState; +} VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT)(VkCommandBuffer commandBuffer, VkImageAspectFlags aspectMask); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetAttachmentFeedbackLoopEnableEXT( + VkCommandBuffer commandBuffer, + VkImageAspectFlags aspectMask); +#endif + + +// VK_MSFT_layered_driver is a preprocessor guard. Do not pass it to API calls. +#define VK_MSFT_layered_driver 1 +#define VK_MSFT_LAYERED_DRIVER_SPEC_VERSION 1 +#define VK_MSFT_LAYERED_DRIVER_EXTENSION_NAME "VK_MSFT_layered_driver" + +typedef enum VkLayeredDriverUnderlyingApiMSFT { + VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT = 0, + VK_LAYERED_DRIVER_UNDERLYING_API_D3D12_MSFT = 1, + VK_LAYERED_DRIVER_UNDERLYING_API_MAX_ENUM_MSFT = 0x7FFFFFFF +} VkLayeredDriverUnderlyingApiMSFT; +typedef struct VkPhysicalDeviceLayeredDriverPropertiesMSFT { + VkStructureType sType; + void* pNext; + VkLayeredDriverUnderlyingApiMSFT underlyingAPI; +} VkPhysicalDeviceLayeredDriverPropertiesMSFT; + + + +// VK_NV_descriptor_pool_overallocation is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_descriptor_pool_overallocation 1 +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_SPEC_VERSION 1 +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME "VK_NV_descriptor_pool_overallocation" +typedef struct VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 descriptorPoolOverallocation; +} VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV; + + + +// VK_KHR_acceleration_structure is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_acceleration_structure 1 +#define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 13 +#define VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_KHR_acceleration_structure" + +typedef enum VkBuildAccelerationStructureModeKHR { + VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR = 0, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR = 1, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureModeKHR; + +typedef enum VkAccelerationStructureCreateFlagBitsKHR { + VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = 0x00000001, + VK_ACCELERATION_STRUCTURE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000008, + VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV = 0x00000004, + VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCreateFlagBitsKHR; +typedef VkFlags VkAccelerationStructureCreateFlagsKHR; +typedef struct VkAccelerationStructureBuildRangeInfoKHR { + uint32_t primitiveCount; + uint32_t primitiveOffset; + uint32_t firstVertex; + uint32_t transformOffset; +} VkAccelerationStructureBuildRangeInfoKHR; + +typedef struct VkAccelerationStructureGeometryTrianglesDataKHR { + VkStructureType sType; + const void* pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + uint32_t maxVertex; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceOrHostAddressConstKHR transformData; +} VkAccelerationStructureGeometryTrianglesDataKHR; + +typedef struct VkAccelerationStructureGeometryAabbsDataKHR { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR data; + VkDeviceSize stride; +} VkAccelerationStructureGeometryAabbsDataKHR; + +typedef struct VkAccelerationStructureGeometryInstancesDataKHR { + VkStructureType sType; + const void* pNext; + VkBool32 arrayOfPointers; + VkDeviceOrHostAddressConstKHR data; +} VkAccelerationStructureGeometryInstancesDataKHR; + +typedef union VkAccelerationStructureGeometryDataKHR { + VkAccelerationStructureGeometryTrianglesDataKHR triangles; + VkAccelerationStructureGeometryAabbsDataKHR aabbs; + VkAccelerationStructureGeometryInstancesDataKHR instances; +} VkAccelerationStructureGeometryDataKHR; + +typedef struct VkAccelerationStructureGeometryKHR { + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + VkAccelerationStructureGeometryDataKHR geometry; + VkGeometryFlagsKHR flags; +} VkAccelerationStructureGeometryKHR; + +typedef struct VkAccelerationStructureBuildGeometryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeKHR type; + VkBuildAccelerationStructureFlagsKHR flags; + VkBuildAccelerationStructureModeKHR mode; + VkAccelerationStructureKHR srcAccelerationStructure; + VkAccelerationStructureKHR dstAccelerationStructure; + uint32_t geometryCount; + const VkAccelerationStructureGeometryKHR* pGeometries; + const VkAccelerationStructureGeometryKHR* const* ppGeometries; + VkDeviceOrHostAddressKHR scratchData; +} VkAccelerationStructureBuildGeometryInfoKHR; + +typedef struct VkAccelerationStructureCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureCreateFlagsKHR createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkAccelerationStructureTypeKHR type; + VkDeviceAddress deviceAddress; +} VkAccelerationStructureCreateInfoKHR; + +typedef struct VkWriteDescriptorSetAccelerationStructureKHR { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureKHR* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureKHR; + +typedef struct VkPhysicalDeviceAccelerationStructureFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 accelerationStructure; + VkBool32 accelerationStructureCaptureReplay; + VkBool32 accelerationStructureIndirectBuild; + VkBool32 accelerationStructureHostCommands; + VkBool32 descriptorBindingAccelerationStructureUpdateAfterBind; +} VkPhysicalDeviceAccelerationStructureFeaturesKHR; + +typedef struct VkPhysicalDeviceAccelerationStructurePropertiesKHR { + VkStructureType sType; + void* pNext; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxPrimitiveCount; + uint32_t maxPerStageDescriptorAccelerationStructures; + uint32_t maxPerStageDescriptorUpdateAfterBindAccelerationStructures; + uint32_t maxDescriptorSetAccelerationStructures; + uint32_t maxDescriptorSetUpdateAfterBindAccelerationStructures; + uint32_t minAccelerationStructureScratchOffsetAlignment; +} VkPhysicalDeviceAccelerationStructurePropertiesKHR; + +typedef struct VkAccelerationStructureDeviceAddressInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR accelerationStructure; +} VkAccelerationStructureDeviceAddressInfoKHR; + +typedef struct VkAccelerationStructureVersionInfoKHR { + VkStructureType sType; + const void* pNext; + const uint8_t* pVersionData; +} VkAccelerationStructureVersionInfoKHR; + +typedef struct VkCopyAccelerationStructureToMemoryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR src; + VkDeviceOrHostAddressKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureToMemoryInfoKHR; + +typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyMemoryToAccelerationStructureInfoKHR; + +typedef struct VkCopyAccelerationStructureInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureInfoKHR; + +typedef struct VkAccelerationStructureBuildSizesInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceSize accelerationStructureSize; + VkDeviceSize updateScratchSize; + VkDeviceSize buildScratchSize; +} VkAccelerationStructureBuildSizesInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureKHR)(VkDevice device, const VkAccelerationStructureCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureKHR* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructuresKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructuresIndirectKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkDeviceAddress* pIndirectDeviceAddresses, const uint32_t* pIndirectStrides, const uint32_t* const* ppMaxPrimitiveCounts); +typedef VkResult (VKAPI_PTR *PFN_vkBuildAccelerationStructuresKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); +typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkWriteAccelerationStructuresPropertiesKHR)(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, size_t dataSize, void* pData, size_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureToMemoryKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetAccelerationStructureDeviceAddressKHR)(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (VKAPI_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice device, const VkAccelerationStructureVersionInfoKHR* pVersionInfo, VkAccelerationStructureCompatibilityKHR* pCompatibility); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureBuildSizesKHR)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkAccelerationStructureBuildGeometryInfoKHR* pBuildInfo, const uint32_t* pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureKHR( + VkDevice device, + const VkAccelerationStructureCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureKHR* pAccelerationStructure); + +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureKHR( + VkDevice device, + VkAccelerationStructureKHR accelerationStructure, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructuresKHR( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructuresIndirectKHR( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkDeviceAddress* pIndirectDeviceAddresses, + const uint32_t* pIndirectStrides, + const uint32_t* const* ppMaxPrimitiveCounts); + +VKAPI_ATTR VkResult VKAPI_CALL vkBuildAccelerationStructuresKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyAccelerationStructureKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyAccelerationStructureToMemoryKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToAccelerationStructureKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkWriteAccelerationStructuresPropertiesKHR( + VkDevice device, + uint32_t accelerationStructureCount, + const VkAccelerationStructureKHR* pAccelerationStructures, + VkQueryType queryType, + size_t dataSize, + void* pData, + size_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureToMemoryKHR( + VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetAccelerationStructureDeviceAddressKHR( + VkDevice device, + const VkAccelerationStructureDeviceAddressInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesKHR( + VkCommandBuffer commandBuffer, + uint32_t accelerationStructureCount, + const VkAccelerationStructureKHR* pAccelerationStructures, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceAccelerationStructureCompatibilityKHR( + VkDevice device, + const VkAccelerationStructureVersionInfoKHR* pVersionInfo, + VkAccelerationStructureCompatibilityKHR* pCompatibility); + +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureBuildSizesKHR( + VkDevice device, + VkAccelerationStructureBuildTypeKHR buildType, + const VkAccelerationStructureBuildGeometryInfoKHR* pBuildInfo, + const uint32_t* pMaxPrimitiveCounts, + VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); +#endif + + +// VK_KHR_ray_tracing_pipeline is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_ray_tracing_pipeline 1 +#define VK_KHR_RAY_TRACING_PIPELINE_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME "VK_KHR_ray_tracing_pipeline" + +typedef enum VkShaderGroupShaderKHR { + VK_SHADER_GROUP_SHADER_GENERAL_KHR = 0, + VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR = 1, + VK_SHADER_GROUP_SHADER_ANY_HIT_KHR = 2, + VK_SHADER_GROUP_SHADER_INTERSECTION_KHR = 3, + VK_SHADER_GROUP_SHADER_MAX_ENUM_KHR = 0x7FFFFFFF +} VkShaderGroupShaderKHR; +typedef struct VkRayTracingShaderGroupCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeKHR type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; + const void* pShaderGroupCaptureReplayHandle; +} VkRayTracingShaderGroupCreateInfoKHR; + +typedef struct VkRayTracingPipelineInterfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxPipelineRayPayloadSize; + uint32_t maxPipelineRayHitAttributeSize; +} VkRayTracingPipelineInterfaceCreateInfoKHR; + +typedef struct VkRayTracingPipelineCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoKHR* pGroups; + uint32_t maxPipelineRayRecursionDepth; + const VkPipelineLibraryCreateInfoKHR* pLibraryInfo; + const VkRayTracingPipelineInterfaceCreateInfoKHR* pLibraryInterface; + const VkPipelineDynamicStateCreateInfo* pDynamicState; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelineFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingPipeline; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplay; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplayMixed; + VkBool32 rayTracingPipelineTraceRaysIndirect; + VkBool32 rayTraversalPrimitiveCulling; +} VkPhysicalDeviceRayTracingPipelineFeaturesKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelinePropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRayRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint32_t shaderGroupHandleCaptureReplaySize; + uint32_t maxRayDispatchInvocationCount; + uint32_t shaderGroupHandleAlignment; + uint32_t maxRayHitAttributeSize; +} VkPhysicalDeviceRayTracingPipelinePropertiesKHR; + +typedef struct VkStridedDeviceAddressRegionKHR { + VkDeviceAddress deviceAddress; + VkDeviceSize stride; + VkDeviceSize size; +} VkStridedDeviceAddressRegionKHR; + +typedef struct VkTraceRaysIndirectCommandKHR { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkTraceRaysIndirectCommandKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, VkDeviceAddress indirectDeviceAddress); +typedef VkDeviceSize (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupStackSizeKHR)(VkDevice device, VkPipeline pipeline, uint32_t group, VkShaderGroupShaderKHR groupShader); +typedef void (VKAPI_PTR *PFN_vkCmdSetRayTracingPipelineStackSizeKHR)(VkCommandBuffer commandBuffer, uint32_t pipelineStackSize); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysKHR( + VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, + uint32_t width, + uint32_t height, + uint32_t depth); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysIndirectKHR( + VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, + VkDeviceAddress indirectDeviceAddress); + +VKAPI_ATTR VkDeviceSize VKAPI_CALL vkGetRayTracingShaderGroupStackSizeKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t group, + VkShaderGroupShaderKHR groupShader); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRayTracingPipelineStackSizeKHR( + VkCommandBuffer commandBuffer, + uint32_t pipelineStackSize); +#endif + + +// VK_KHR_ray_query is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_ray_query 1 +#define VK_KHR_RAY_QUERY_SPEC_VERSION 1 +#define VK_KHR_RAY_QUERY_EXTENSION_NAME "VK_KHR_ray_query" +typedef struct VkPhysicalDeviceRayQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayQuery; +} VkPhysicalDeviceRayQueryFeaturesKHR; + + + +// VK_EXT_mesh_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_mesh_shader 1 +#define VK_EXT_MESH_SHADER_SPEC_VERSION 1 +#define VK_EXT_MESH_SHADER_EXTENSION_NAME "VK_EXT_mesh_shader" +typedef struct VkPhysicalDeviceMeshShaderFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 taskShader; + VkBool32 meshShader; + VkBool32 multiviewMeshShader; + VkBool32 primitiveFragmentShadingRateMeshShader; + VkBool32 meshShaderQueries; +} VkPhysicalDeviceMeshShaderFeaturesEXT; + +typedef struct VkPhysicalDeviceMeshShaderPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxTaskWorkGroupTotalCount; + uint32_t maxTaskWorkGroupCount[3]; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxTaskWorkGroupSize[3]; + uint32_t maxTaskPayloadSize; + uint32_t maxTaskSharedMemorySize; + uint32_t maxTaskPayloadAndSharedMemorySize; + uint32_t maxMeshWorkGroupTotalCount; + uint32_t maxMeshWorkGroupCount[3]; + uint32_t maxMeshWorkGroupInvocations; + uint32_t maxMeshWorkGroupSize[3]; + uint32_t maxMeshSharedMemorySize; + uint32_t maxMeshPayloadAndSharedMemorySize; + uint32_t maxMeshOutputMemorySize; + uint32_t maxMeshPayloadAndOutputMemorySize; + uint32_t maxMeshOutputComponents; + uint32_t maxMeshOutputVertices; + uint32_t maxMeshOutputPrimitives; + uint32_t maxMeshOutputLayers; + uint32_t maxMeshMultiviewViewCount; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; + uint32_t maxPreferredTaskWorkGroupInvocations; + uint32_t maxPreferredMeshWorkGroupInvocations; + VkBool32 prefersLocalInvocationVertexOutput; + VkBool32 prefersLocalInvocationPrimitiveOutput; + VkBool32 prefersCompactVertexOutput; + VkBool32 prefersCompactPrimitiveOutput; +} VkPhysicalDeviceMeshShaderPropertiesEXT; + +typedef struct VkDrawMeshTasksIndirectCommandEXT { + uint32_t groupCountX; + uint32_t groupCountY; + uint32_t groupCountZ; +} VkDrawMeshTasksIndirectCommandEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksEXT)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksEXT( + VkCommandBuffer commandBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectEXT( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountEXT( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_directfb.h b/libraries/ZVulkan/include/vulkan/vulkan_directfb.h new file mode 100644 index 00000000000..1f11a082736 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_directfb.h @@ -0,0 +1,55 @@ +#ifndef VULKAN_DIRECTFB_H_ +#define VULKAN_DIRECTFB_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_EXT_directfb_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_directfb_surface 1 +#define VK_EXT_DIRECTFB_SURFACE_SPEC_VERSION 1 +#define VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME "VK_EXT_directfb_surface" +typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT; +typedef struct VkDirectFBSurfaceCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDirectFBSurfaceCreateFlagsEXT flags; + IDirectFB* dfb; + IDirectFBSurface* surface; +} VkDirectFBSurfaceCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDirectFBSurfaceEXT)(VkInstance instance, const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, IDirectFB* dfb); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDirectFBSurfaceEXT( + VkInstance instance, + const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceDirectFBPresentationSupportEXT( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + IDirectFB* dfb); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_fuchsia.h b/libraries/ZVulkan/include/vulkan/vulkan_fuchsia.h new file mode 100644 index 00000000000..76e1564832e --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_fuchsia.h @@ -0,0 +1,262 @@ +#ifndef VULKAN_FUCHSIA_H_ +#define VULKAN_FUCHSIA_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_FUCHSIA_imagepipe_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_FUCHSIA_imagepipe_surface 1 +#define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1 +#define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface" +typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; +typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkImagePipeSurfaceCreateFlagsFUCHSIA flags; + zx_handle_t imagePipeHandle; +} VkImagePipeSurfaceCreateInfoFUCHSIA; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateImagePipeSurfaceFUCHSIA)(VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImagePipeSurfaceFUCHSIA( + VkInstance instance, + const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +// VK_FUCHSIA_external_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_FUCHSIA_external_memory 1 +#define VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME "VK_FUCHSIA_external_memory" +typedef struct VkImportMemoryZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + zx_handle_t handle; +} VkImportMemoryZirconHandleInfoFUCHSIA; + +typedef struct VkMemoryZirconHandlePropertiesFUCHSIA { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryZirconHandlePropertiesFUCHSIA; + +typedef struct VkMemoryGetZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetZirconHandleInfoFUCHSIA; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryZirconHandleFUCHSIA)(VkDevice device, const VkMemoryGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo, zx_handle_t* pZirconHandle); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, zx_handle_t zirconHandle, VkMemoryZirconHandlePropertiesFUCHSIA* pMemoryZirconHandleProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryZirconHandleFUCHSIA( + VkDevice device, + const VkMemoryGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo, + zx_handle_t* pZirconHandle); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryZirconHandlePropertiesFUCHSIA( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + zx_handle_t zirconHandle, + VkMemoryZirconHandlePropertiesFUCHSIA* pMemoryZirconHandleProperties); +#endif + + +// VK_FUCHSIA_external_semaphore is a preprocessor guard. Do not pass it to API calls. +#define VK_FUCHSIA_external_semaphore 1 +#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 +#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_FUCHSIA_external_semaphore" +typedef struct VkImportSemaphoreZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + zx_handle_t zirconHandle; +} VkImportSemaphoreZirconHandleInfoFUCHSIA; + +typedef struct VkSemaphoreGetZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetZirconHandleInfoFUCHSIA; + +typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreZirconHandleFUCHSIA)(VkDevice device, const VkImportSemaphoreZirconHandleInfoFUCHSIA* pImportSemaphoreZirconHandleInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreZirconHandleFUCHSIA)(VkDevice device, const VkSemaphoreGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo, zx_handle_t* pZirconHandle); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreZirconHandleFUCHSIA( + VkDevice device, + const VkImportSemaphoreZirconHandleInfoFUCHSIA* pImportSemaphoreZirconHandleInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreZirconHandleFUCHSIA( + VkDevice device, + const VkSemaphoreGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo, + zx_handle_t* pZirconHandle); +#endif + + +// VK_FUCHSIA_buffer_collection is a preprocessor guard. Do not pass it to API calls. +#define VK_FUCHSIA_buffer_collection 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferCollectionFUCHSIA) +#define VK_FUCHSIA_BUFFER_COLLECTION_SPEC_VERSION 2 +#define VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME "VK_FUCHSIA_buffer_collection" +typedef VkFlags VkImageFormatConstraintsFlagsFUCHSIA; + +typedef enum VkImageConstraintsInfoFlagBitsFUCHSIA { + VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_RARELY_FUCHSIA = 0x00000001, + VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_OFTEN_FUCHSIA = 0x00000002, + VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_RARELY_FUCHSIA = 0x00000004, + VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_OFTEN_FUCHSIA = 0x00000008, + VK_IMAGE_CONSTRAINTS_INFO_PROTECTED_OPTIONAL_FUCHSIA = 0x00000010, + VK_IMAGE_CONSTRAINTS_INFO_FLAG_BITS_MAX_ENUM_FUCHSIA = 0x7FFFFFFF +} VkImageConstraintsInfoFlagBitsFUCHSIA; +typedef VkFlags VkImageConstraintsInfoFlagsFUCHSIA; +typedef struct VkBufferCollectionCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + zx_handle_t collectionToken; +} VkBufferCollectionCreateInfoFUCHSIA; + +typedef struct VkImportMemoryBufferCollectionFUCHSIA { + VkStructureType sType; + const void* pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkImportMemoryBufferCollectionFUCHSIA; + +typedef struct VkBufferCollectionImageCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkBufferCollectionImageCreateInfoFUCHSIA; + +typedef struct VkBufferCollectionConstraintsInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + uint32_t minBufferCount; + uint32_t maxBufferCount; + uint32_t minBufferCountForCamping; + uint32_t minBufferCountForDedicatedSlack; + uint32_t minBufferCountForSharedSlack; +} VkBufferCollectionConstraintsInfoFUCHSIA; + +typedef struct VkBufferConstraintsInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkBufferCreateInfo createInfo; + VkFormatFeatureFlags requiredFormatFeatures; + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints; +} VkBufferConstraintsInfoFUCHSIA; + +typedef struct VkBufferCollectionBufferCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkBufferCollectionBufferCreateInfoFUCHSIA; + +typedef struct VkSysmemColorSpaceFUCHSIA { + VkStructureType sType; + const void* pNext; + uint32_t colorSpace; +} VkSysmemColorSpaceFUCHSIA; + +typedef struct VkBufferCollectionPropertiesFUCHSIA { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; + uint32_t bufferCount; + uint32_t createInfoIndex; + uint64_t sysmemPixelFormat; + VkFormatFeatureFlags formatFeatures; + VkSysmemColorSpaceFUCHSIA sysmemColorSpaceIndex; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkBufferCollectionPropertiesFUCHSIA; + +typedef struct VkImageFormatConstraintsInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkImageCreateInfo imageCreateInfo; + VkFormatFeatureFlags requiredFormatFeatures; + VkImageFormatConstraintsFlagsFUCHSIA flags; + uint64_t sysmemPixelFormat; + uint32_t colorSpaceCount; + const VkSysmemColorSpaceFUCHSIA* pColorSpaces; +} VkImageFormatConstraintsInfoFUCHSIA; + +typedef struct VkImageConstraintsInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + uint32_t formatConstraintsCount; + const VkImageFormatConstraintsInfoFUCHSIA* pFormatConstraints; + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints; + VkImageConstraintsInfoFlagsFUCHSIA flags; +} VkImageConstraintsInfoFUCHSIA; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferCollectionFUCHSIA)(VkDevice device, const VkBufferCollectionCreateInfoFUCHSIA* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferCollectionFUCHSIA* pCollection); +typedef VkResult (VKAPI_PTR *PFN_vkSetBufferCollectionImageConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo); +typedef VkResult (VKAPI_PTR *PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo); +typedef void (VKAPI_PTR *PFN_vkDestroyBufferCollectionFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetBufferCollectionPropertiesFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, VkBufferCollectionPropertiesFUCHSIA* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferCollectionFUCHSIA( + VkDevice device, + const VkBufferCollectionCreateInfoFUCHSIA* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBufferCollectionFUCHSIA* pCollection); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetBufferCollectionImageConstraintsFUCHSIA( + VkDevice device, + VkBufferCollectionFUCHSIA collection, + const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetBufferCollectionBufferConstraintsFUCHSIA( + VkDevice device, + VkBufferCollectionFUCHSIA collection, + const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBufferCollectionFUCHSIA( + VkDevice device, + VkBufferCollectionFUCHSIA collection, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetBufferCollectionPropertiesFUCHSIA( + VkDevice device, + VkBufferCollectionFUCHSIA collection, + VkBufferCollectionPropertiesFUCHSIA* pProperties); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_ggp.h b/libraries/ZVulkan/include/vulkan/vulkan_ggp.h new file mode 100644 index 00000000000..9783aa3b38b --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_ggp.h @@ -0,0 +1,60 @@ +#ifndef VULKAN_GGP_H_ +#define VULKAN_GGP_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_GGP_stream_descriptor_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_GGP_stream_descriptor_surface 1 +#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION 1 +#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME "VK_GGP_stream_descriptor_surface" +typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; +typedef struct VkStreamDescriptorSurfaceCreateInfoGGP { + VkStructureType sType; + const void* pNext; + VkStreamDescriptorSurfaceCreateFlagsGGP flags; + GgpStreamDescriptor streamDescriptor; +} VkStreamDescriptorSurfaceCreateInfoGGP; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateStreamDescriptorSurfaceGGP)(VkInstance instance, const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateStreamDescriptorSurfaceGGP( + VkInstance instance, + const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +// VK_GGP_frame_token is a preprocessor guard. Do not pass it to API calls. +#define VK_GGP_frame_token 1 +#define VK_GGP_FRAME_TOKEN_SPEC_VERSION 1 +#define VK_GGP_FRAME_TOKEN_EXTENSION_NAME "VK_GGP_frame_token" +typedef struct VkPresentFrameTokenGGP { + VkStructureType sType; + const void* pNext; + GgpFrameToken frameToken; +} VkPresentFrameTokenGGP; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_ios.h b/libraries/ZVulkan/include/vulkan/vulkan_ios.h new file mode 100644 index 00000000000..211429ff456 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_ios.h @@ -0,0 +1,48 @@ +#ifndef VULKAN_IOS_H_ +#define VULKAN_IOS_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_MVK_ios_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_MVK_ios_surface 1 +#define VK_MVK_IOS_SURFACE_SPEC_VERSION 3 +#define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface" +typedef VkFlags VkIOSSurfaceCreateFlagsMVK; +typedef struct VkIOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void* pNext; + VkIOSSurfaceCreateFlagsMVK flags; + const void* pView; +} VkIOSSurfaceCreateInfoMVK; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK( + VkInstance instance, + const VkIOSSurfaceCreateInfoMVK* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_macos.h b/libraries/ZVulkan/include/vulkan/vulkan_macos.h new file mode 100644 index 00000000000..c6509cc8cf3 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_macos.h @@ -0,0 +1,48 @@ +#ifndef VULKAN_MACOS_H_ +#define VULKAN_MACOS_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_MVK_macos_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_MVK_macos_surface 1 +#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3 +#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" +typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; +typedef struct VkMacOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void* pNext; + VkMacOSSurfaceCreateFlagsMVK flags; + const void* pView; +} VkMacOSSurfaceCreateInfoMVK; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK( + VkInstance instance, + const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_metal.h b/libraries/ZVulkan/include/vulkan/vulkan_metal.h new file mode 100644 index 00000000000..94563a003a2 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_metal.h @@ -0,0 +1,195 @@ +#ifndef VULKAN_METAL_H_ +#define VULKAN_METAL_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_EXT_metal_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_metal_surface 1 +#ifdef __OBJC__ +@class CAMetalLayer; +#else +typedef void CAMetalLayer; +#endif + +#define VK_EXT_METAL_SURFACE_SPEC_VERSION 1 +#define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface" +typedef VkFlags VkMetalSurfaceCreateFlagsEXT; +typedef struct VkMetalSurfaceCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkMetalSurfaceCreateFlagsEXT flags; + const CAMetalLayer* pLayer; +} VkMetalSurfaceCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMetalSurfaceEXT)(VkInstance instance, const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMetalSurfaceEXT( + VkInstance instance, + const VkMetalSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +// VK_EXT_metal_objects is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_metal_objects 1 +#ifdef __OBJC__ +@protocol MTLDevice; +typedef id MTLDevice_id; +#else +typedef void* MTLDevice_id; +#endif + +#ifdef __OBJC__ +@protocol MTLCommandQueue; +typedef id MTLCommandQueue_id; +#else +typedef void* MTLCommandQueue_id; +#endif + +#ifdef __OBJC__ +@protocol MTLBuffer; +typedef id MTLBuffer_id; +#else +typedef void* MTLBuffer_id; +#endif + +#ifdef __OBJC__ +@protocol MTLTexture; +typedef id MTLTexture_id; +#else +typedef void* MTLTexture_id; +#endif + +typedef struct __IOSurface* IOSurfaceRef; +#ifdef __OBJC__ +@protocol MTLSharedEvent; +typedef id MTLSharedEvent_id; +#else +typedef void* MTLSharedEvent_id; +#endif + +#define VK_EXT_METAL_OBJECTS_SPEC_VERSION 1 +#define VK_EXT_METAL_OBJECTS_EXTENSION_NAME "VK_EXT_metal_objects" + +typedef enum VkExportMetalObjectTypeFlagBitsEXT { + VK_EXPORT_METAL_OBJECT_TYPE_METAL_DEVICE_BIT_EXT = 0x00000001, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_COMMAND_QUEUE_BIT_EXT = 0x00000002, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT = 0x00000004, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT = 0x00000008, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT = 0x00000010, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT = 0x00000020, + VK_EXPORT_METAL_OBJECT_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkExportMetalObjectTypeFlagBitsEXT; +typedef VkFlags VkExportMetalObjectTypeFlagsEXT; +typedef struct VkExportMetalObjectCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkExportMetalObjectTypeFlagBitsEXT exportObjectType; +} VkExportMetalObjectCreateInfoEXT; + +typedef struct VkExportMetalObjectsInfoEXT { + VkStructureType sType; + const void* pNext; +} VkExportMetalObjectsInfoEXT; + +typedef struct VkExportMetalDeviceInfoEXT { + VkStructureType sType; + const void* pNext; + MTLDevice_id mtlDevice; +} VkExportMetalDeviceInfoEXT; + +typedef struct VkExportMetalCommandQueueInfoEXT { + VkStructureType sType; + const void* pNext; + VkQueue queue; + MTLCommandQueue_id mtlCommandQueue; +} VkExportMetalCommandQueueInfoEXT; + +typedef struct VkExportMetalBufferInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + MTLBuffer_id mtlBuffer; +} VkExportMetalBufferInfoEXT; + +typedef struct VkImportMetalBufferInfoEXT { + VkStructureType sType; + const void* pNext; + MTLBuffer_id mtlBuffer; +} VkImportMetalBufferInfoEXT; + +typedef struct VkExportMetalTextureInfoEXT { + VkStructureType sType; + const void* pNext; + VkImage image; + VkImageView imageView; + VkBufferView bufferView; + VkImageAspectFlagBits plane; + MTLTexture_id mtlTexture; +} VkExportMetalTextureInfoEXT; + +typedef struct VkImportMetalTextureInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits plane; + MTLTexture_id mtlTexture; +} VkImportMetalTextureInfoEXT; + +typedef struct VkExportMetalIOSurfaceInfoEXT { + VkStructureType sType; + const void* pNext; + VkImage image; + IOSurfaceRef ioSurface; +} VkExportMetalIOSurfaceInfoEXT; + +typedef struct VkImportMetalIOSurfaceInfoEXT { + VkStructureType sType; + const void* pNext; + IOSurfaceRef ioSurface; +} VkImportMetalIOSurfaceInfoEXT; + +typedef struct VkExportMetalSharedEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkEvent event; + MTLSharedEvent_id mtlSharedEvent; +} VkExportMetalSharedEventInfoEXT; + +typedef struct VkImportMetalSharedEventInfoEXT { + VkStructureType sType; + const void* pNext; + MTLSharedEvent_id mtlSharedEvent; +} VkImportMetalSharedEventInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkExportMetalObjectsEXT)(VkDevice device, VkExportMetalObjectsInfoEXT* pMetalObjectsInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkExportMetalObjectsEXT( + VkDevice device, + VkExportMetalObjectsInfoEXT* pMetalObjectsInfo); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_mir.h b/libraries/ZVulkan/include/vulkan/vulkan_mir.h similarity index 100% rename from src/rendering/vulkan/thirdparty/vulkan/vulkan_mir.h rename to libraries/ZVulkan/include/vulkan/vulkan_mir.h diff --git a/libraries/ZVulkan/include/vulkan/vulkan_screen.h b/libraries/ZVulkan/include/vulkan/vulkan_screen.h new file mode 100644 index 00000000000..981738f7385 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_screen.h @@ -0,0 +1,108 @@ +#ifndef VULKAN_SCREEN_H_ +#define VULKAN_SCREEN_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_QNX_screen_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_QNX_screen_surface 1 +#define VK_QNX_SCREEN_SURFACE_SPEC_VERSION 1 +#define VK_QNX_SCREEN_SURFACE_EXTENSION_NAME "VK_QNX_screen_surface" +typedef VkFlags VkScreenSurfaceCreateFlagsQNX; +typedef struct VkScreenSurfaceCreateInfoQNX { + VkStructureType sType; + const void* pNext; + VkScreenSurfaceCreateFlagsQNX flags; + struct _screen_context* context; + struct _screen_window* window; +} VkScreenSurfaceCreateInfoQNX; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateScreenSurfaceQNX)(VkInstance instance, const VkScreenSurfaceCreateInfoQNX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct _screen_window* window); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateScreenSurfaceQNX( + VkInstance instance, + const VkScreenSurfaceCreateInfoQNX* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceScreenPresentationSupportQNX( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + struct _screen_window* window); +#endif + + +// VK_QNX_external_memory_screen_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_QNX_external_memory_screen_buffer 1 +#define VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_SPEC_VERSION 1 +#define VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME "VK_QNX_external_memory_screen_buffer" +typedef struct VkScreenBufferPropertiesQNX { + VkStructureType sType; + void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkScreenBufferPropertiesQNX; + +typedef struct VkScreenBufferFormatPropertiesQNX { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + uint64_t screenUsage; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkScreenBufferFormatPropertiesQNX; + +typedef struct VkImportScreenBufferInfoQNX { + VkStructureType sType; + const void* pNext; + struct _screen_buffer* buffer; +} VkImportScreenBufferInfoQNX; + +typedef struct VkExternalFormatQNX { + VkStructureType sType; + void* pNext; + uint64_t externalFormat; +} VkExternalFormatQNX; + +typedef struct VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX { + VkStructureType sType; + void* pNext; + VkBool32 screenBufferImport; +} VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX; + +typedef VkResult (VKAPI_PTR *PFN_vkGetScreenBufferPropertiesQNX)(VkDevice device, const struct _screen_buffer* buffer, VkScreenBufferPropertiesQNX* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetScreenBufferPropertiesQNX( + VkDevice device, + const struct _screen_buffer* buffer, + VkScreenBufferPropertiesQNX* pProperties); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_vi.h b/libraries/ZVulkan/include/vulkan/vulkan_vi.h new file mode 100644 index 00000000000..c9227e82268 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_vi.h @@ -0,0 +1,48 @@ +#ifndef VULKAN_VI_H_ +#define VULKAN_VI_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_NN_vi_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_NN_vi_surface 1 +#define VK_NN_VI_SURFACE_SPEC_VERSION 1 +#define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface" +typedef VkFlags VkViSurfaceCreateFlagsNN; +typedef struct VkViSurfaceCreateInfoNN { + VkStructureType sType; + const void* pNext; + VkViSurfaceCreateFlagsNN flags; + void* window; +} VkViSurfaceCreateInfoNN; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN( + VkInstance instance, + const VkViSurfaceCreateInfoNN* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_wayland.h b/libraries/ZVulkan/include/vulkan/vulkan_wayland.h new file mode 100644 index 00000000000..c93b2178725 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_wayland.h @@ -0,0 +1,55 @@ +#ifndef VULKAN_WAYLAND_H_ +#define VULKAN_WAYLAND_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_wayland_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_wayland_surface 1 +#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6 +#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; +typedef struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR( + VkInstance instance, + const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + struct wl_display* display); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_win32.h b/libraries/ZVulkan/include/vulkan/vulkan_win32.h similarity index 87% rename from src/rendering/vulkan/thirdparty/vulkan/vulkan_win32.h rename to libraries/ZVulkan/include/vulkan/vulkan_win32.h index a61a7d885c2..fae3b8532c5 100644 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_win32.h +++ b/libraries/ZVulkan/include/vulkan/vulkan_win32.h @@ -1,24 +1,10 @@ #ifndef VULKAN_WIN32_H_ #define VULKAN_WIN32_H_ 1 -#ifdef __cplusplus -extern "C" { -#endif - /* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Copyright 2015-2023 The Khronos Group Inc. ** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. +** SPDX-License-Identifier: Apache-2.0 */ /* @@ -27,7 +13,13 @@ extern "C" { */ +#ifdef __cplusplus +extern "C" { +#endif + + +// VK_KHR_win32_surface is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_win32_surface 1 #define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6 #define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" @@ -56,6 +48,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( #endif +// VK_KHR_external_memory_win32 is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_external_memory_win32 1 #define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32" @@ -105,6 +98,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR( #endif +// VK_KHR_win32_keyed_mutex is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_win32_keyed_mutex 1 #define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1 #define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex" @@ -122,6 +116,7 @@ typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR { +// VK_KHR_external_semaphore_win32 is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_external_semaphore_win32 1 #define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32" @@ -174,6 +169,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHR( #endif +// VK_KHR_external_fence_win32 is a preprocessor guard. Do not pass it to API calls. #define VK_KHR_external_fence_win32 1 #define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32" @@ -217,6 +213,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceWin32HandleKHR( #endif +// VK_NV_external_memory_win32 is a preprocessor guard. Do not pass it to API calls. #define VK_NV_external_memory_win32 1 #define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 #define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32" @@ -245,8 +242,9 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV( #endif +// VK_NV_win32_keyed_mutex is a preprocessor guard. Do not pass it to API calls. #define VK_NV_win32_keyed_mutex 1 -#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1 +#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 2 #define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex" typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { VkStructureType sType; @@ -262,8 +260,9 @@ typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { +// VK_EXT_full_screen_exclusive is a preprocessor guard. Do not pass it to API calls. #define VK_EXT_full_screen_exclusive 1 -#define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 3 +#define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4 #define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive" typedef enum VkFullScreenExclusiveEXT { @@ -271,9 +270,6 @@ typedef enum VkFullScreenExclusiveEXT { VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1, VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2, VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3, - VK_FULL_SCREEN_EXCLUSIVE_BEGIN_RANGE_EXT = VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT, - VK_FULL_SCREEN_EXCLUSIVE_END_RANGE_EXT = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT, - VK_FULL_SCREEN_EXCLUSIVE_RANGE_SIZE_EXT = (VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT - VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT + 1), VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF } VkFullScreenExclusiveEXT; typedef struct VkSurfaceFullScreenExclusiveInfoEXT { @@ -320,6 +316,25 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModes2EXT( VkDeviceGroupPresentModeFlagsKHR* pModes); #endif + +// VK_NV_acquire_winrt_display is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_acquire_winrt_display 1 +#define VK_NV_ACQUIRE_WINRT_DISPLAY_SPEC_VERSION 1 +#define VK_NV_ACQUIRE_WINRT_DISPLAY_EXTENSION_NAME "VK_NV_acquire_winrt_display" +typedef VkResult (VKAPI_PTR *PFN_vkAcquireWinrtDisplayNV)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); +typedef VkResult (VKAPI_PTR *PFN_vkGetWinrtDisplayNV)(VkPhysicalDevice physicalDevice, uint32_t deviceRelativeId, VkDisplayKHR* pDisplay); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireWinrtDisplayNV( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetWinrtDisplayNV( + VkPhysicalDevice physicalDevice, + uint32_t deviceRelativeId, + VkDisplayKHR* pDisplay); +#endif + #ifdef __cplusplus } #endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_xcb.h b/libraries/ZVulkan/include/vulkan/vulkan_xcb.h new file mode 100644 index 00000000000..de7405524a9 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_xcb.h @@ -0,0 +1,56 @@ +#ifndef VULKAN_XCB_H_ +#define VULKAN_XCB_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_xcb_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_xcb_surface 1 +#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( + VkInstance instance, + const VkXcbSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_xlib.h b/libraries/ZVulkan/include/vulkan/vulkan_xlib.h new file mode 100644 index 00000000000..1aa632f2efb --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_xlib.h @@ -0,0 +1,56 @@ +#ifndef VULKAN_XLIB_H_ +#define VULKAN_XLIB_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_xlib_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_xlib_surface 1 +#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( + VkInstance instance, + const VkXlibSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + Display* dpy, + VisualID visualID); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/vulkan/vulkan_xlib_xrandr.h b/libraries/ZVulkan/include/vulkan/vulkan_xlib_xrandr.h new file mode 100644 index 00000000000..e164ffc91e7 --- /dev/null +++ b/libraries/ZVulkan/include/vulkan/vulkan_xlib_xrandr.h @@ -0,0 +1,46 @@ +#ifndef VULKAN_XLIB_XRANDR_H_ +#define VULKAN_XLIB_XRANDR_H_ 1 + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_EXT_acquire_xlib_display is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_acquire_xlib_display 1 +#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display" +typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display); +typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT( + VkPhysicalDevice physicalDevice, + Display* dpy, + VkDisplayKHR display); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT( + VkPhysicalDevice physicalDevice, + Display* dpy, + RROutput rrOutput, + VkDisplayKHR* pDisplay); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/ZVulkan/include/zvulkan/vk_mem_alloc/vk_mem_alloc.h b/libraries/ZVulkan/include/zvulkan/vk_mem_alloc/vk_mem_alloc.h new file mode 100644 index 00000000000..39f9d9d42ed --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/vk_mem_alloc/vk_mem_alloc.h @@ -0,0 +1,19559 @@ +// +// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved. +// +// 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. +// + +#ifndef AMD_VULKAN_MEMORY_ALLOCATOR_H +#define AMD_VULKAN_MEMORY_ALLOCATOR_H + +/** \mainpage Vulkan Memory Allocator + +Version 3.0.1 (2022-05-26) + +Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved. \n +License: MIT + +API documentation divided into groups: [Modules](modules.html) + +\section main_table_of_contents Table of contents + +- User guide + - \subpage quick_start + - [Project setup](@ref quick_start_project_setup) + - [Initialization](@ref quick_start_initialization) + - [Resource allocation](@ref quick_start_resource_allocation) + - \subpage choosing_memory_type + - [Usage](@ref choosing_memory_type_usage) + - [Required and preferred flags](@ref choosing_memory_type_required_preferred_flags) + - [Explicit memory types](@ref choosing_memory_type_explicit_memory_types) + - [Custom memory pools](@ref choosing_memory_type_custom_memory_pools) + - [Dedicated allocations](@ref choosing_memory_type_dedicated_allocations) + - \subpage memory_mapping + - [Mapping functions](@ref memory_mapping_mapping_functions) + - [Persistently mapped memory](@ref memory_mapping_persistently_mapped_memory) + - [Cache flush and invalidate](@ref memory_mapping_cache_control) + - \subpage staying_within_budget + - [Querying for budget](@ref staying_within_budget_querying_for_budget) + - [Controlling memory usage](@ref staying_within_budget_controlling_memory_usage) + - \subpage resource_aliasing + - \subpage custom_memory_pools + - [Choosing memory type index](@ref custom_memory_pools_MemTypeIndex) + - [Linear allocation algorithm](@ref linear_algorithm) + - [Free-at-once](@ref linear_algorithm_free_at_once) + - [Stack](@ref linear_algorithm_stack) + - [Double stack](@ref linear_algorithm_double_stack) + - [Ring buffer](@ref linear_algorithm_ring_buffer) + - \subpage defragmentation + - \subpage statistics + - [Numeric statistics](@ref statistics_numeric_statistics) + - [JSON dump](@ref statistics_json_dump) + - \subpage allocation_annotation + - [Allocation user data](@ref allocation_user_data) + - [Allocation names](@ref allocation_names) + - \subpage virtual_allocator + - \subpage debugging_memory_usage + - [Memory initialization](@ref debugging_memory_usage_initialization) + - [Margins](@ref debugging_memory_usage_margins) + - [Corruption detection](@ref debugging_memory_usage_corruption_detection) + - \subpage opengl_interop +- \subpage usage_patterns + - [GPU-only resource](@ref usage_patterns_gpu_only) + - [Staging copy for upload](@ref usage_patterns_staging_copy_upload) + - [Readback](@ref usage_patterns_readback) + - [Advanced data uploading](@ref usage_patterns_advanced_data_uploading) + - [Other use cases](@ref usage_patterns_other_use_cases) +- \subpage configuration + - [Pointers to Vulkan functions](@ref config_Vulkan_functions) + - [Custom host memory allocator](@ref custom_memory_allocator) + - [Device memory allocation callbacks](@ref allocation_callbacks) + - [Device heap memory limit](@ref heap_memory_limit) +- Extension support + - \subpage vk_khr_dedicated_allocation + - \subpage enabling_buffer_device_address + - \subpage vk_ext_memory_priority + - \subpage vk_amd_device_coherent_memory +- \subpage general_considerations + - [Thread safety](@ref general_considerations_thread_safety) + - [Versioning and compatibility](@ref general_considerations_versioning_and_compatibility) + - [Validation layer warnings](@ref general_considerations_validation_layer_warnings) + - [Allocation algorithm](@ref general_considerations_allocation_algorithm) + - [Features not supported](@ref general_considerations_features_not_supported) + +\section main_see_also See also + +- [**Product page on GPUOpen**](https://gpuopen.com/gaming-product/vulkan-memory-allocator/) +- [**Source repository on GitHub**](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) + +\defgroup group_init Library initialization + +\brief API elements related to the initialization and management of the entire library, especially #VmaAllocator object. + +\defgroup group_alloc Memory allocation + +\brief API elements related to the allocation, deallocation, and management of Vulkan memory, buffers, images. +Most basic ones being: vmaCreateBuffer(), vmaCreateImage(). + +\defgroup group_virtual Virtual allocator + +\brief API elements related to the mechanism of \ref virtual_allocator - using the core allocation algorithm +for user-defined purpose without allocating any real GPU memory. + +\defgroup group_stats Statistics + +\brief API elements that query current status of the allocator, from memory usage, budget, to full dump of the internal state in JSON format. +See documentation chapter: \ref statistics. +*/ + + +#ifdef __cplusplus +#include +extern "C" { +#endif + +#ifndef VULKAN_H_ + #include +#endif + +// Define this macro to declare maximum supported Vulkan version in format AAABBBCCC, +// where AAA = major, BBB = minor, CCC = patch. +// If you want to use version > 1.0, it still needs to be enabled via VmaAllocatorCreateInfo::vulkanApiVersion. +#if !defined(VMA_VULKAN_VERSION) + #if defined(VK_VERSION_1_3) + #define VMA_VULKAN_VERSION 1003000 + #elif defined(VK_VERSION_1_2) + #define VMA_VULKAN_VERSION 1002000 + #elif defined(VK_VERSION_1_1) + #define VMA_VULKAN_VERSION 1001000 + #else + #define VMA_VULKAN_VERSION 1000000 + #endif +#endif + +#if defined(__ANDROID__) && defined(VK_NO_PROTOTYPES) && VMA_STATIC_VULKAN_FUNCTIONS + extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; + extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; + extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; + extern PFN_vkAllocateMemory vkAllocateMemory; + extern PFN_vkFreeMemory vkFreeMemory; + extern PFN_vkMapMemory vkMapMemory; + extern PFN_vkUnmapMemory vkUnmapMemory; + extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; + extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; + extern PFN_vkBindBufferMemory vkBindBufferMemory; + extern PFN_vkBindImageMemory vkBindImageMemory; + extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; + extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; + extern PFN_vkCreateBuffer vkCreateBuffer; + extern PFN_vkDestroyBuffer vkDestroyBuffer; + extern PFN_vkCreateImage vkCreateImage; + extern PFN_vkDestroyImage vkDestroyImage; + extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; + #if VMA_VULKAN_VERSION >= 1001000 + extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; + extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; + extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; + extern PFN_vkBindImageMemory2 vkBindImageMemory2; + extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; + #endif // #if VMA_VULKAN_VERSION >= 1001000 +#endif // #if defined(__ANDROID__) && VMA_STATIC_VULKAN_FUNCTIONS && VK_NO_PROTOTYPES + +#if !defined(VMA_DEDICATED_ALLOCATION) + #if VK_KHR_get_memory_requirements2 && VK_KHR_dedicated_allocation + #define VMA_DEDICATED_ALLOCATION 1 + #else + #define VMA_DEDICATED_ALLOCATION 0 + #endif +#endif + +#if !defined(VMA_BIND_MEMORY2) + #if VK_KHR_bind_memory2 + #define VMA_BIND_MEMORY2 1 + #else + #define VMA_BIND_MEMORY2 0 + #endif +#endif + +#if !defined(VMA_MEMORY_BUDGET) + #if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) + #define VMA_MEMORY_BUDGET 1 + #else + #define VMA_MEMORY_BUDGET 0 + #endif +#endif + +// Defined to 1 when VK_KHR_buffer_device_address device extension or equivalent core Vulkan 1.2 feature is defined in its headers. +#if !defined(VMA_BUFFER_DEVICE_ADDRESS) + #if VK_KHR_buffer_device_address || VMA_VULKAN_VERSION >= 1002000 + #define VMA_BUFFER_DEVICE_ADDRESS 1 + #else + #define VMA_BUFFER_DEVICE_ADDRESS 0 + #endif +#endif + +// Defined to 1 when VK_EXT_memory_priority device extension is defined in Vulkan headers. +#if !defined(VMA_MEMORY_PRIORITY) + #if VK_EXT_memory_priority + #define VMA_MEMORY_PRIORITY 1 + #else + #define VMA_MEMORY_PRIORITY 0 + #endif +#endif + +// Defined to 1 when VK_KHR_external_memory device extension is defined in Vulkan headers. +#if !defined(VMA_EXTERNAL_MEMORY) + #if VK_KHR_external_memory + #define VMA_EXTERNAL_MEMORY 1 + #else + #define VMA_EXTERNAL_MEMORY 0 + #endif +#endif + +// Define these macros to decorate all public functions with additional code, +// before and after returned type, appropriately. This may be useful for +// exporting the functions when compiling VMA as a separate library. Example: +// #define VMA_CALL_PRE __declspec(dllexport) +// #define VMA_CALL_POST __cdecl +#ifndef VMA_CALL_PRE + #define VMA_CALL_PRE +#endif +#ifndef VMA_CALL_POST + #define VMA_CALL_POST +#endif + +// Define this macro to decorate pointers with an attribute specifying the +// length of the array they point to if they are not null. +// +// The length may be one of +// - The name of another parameter in the argument list where the pointer is declared +// - The name of another member in the struct where the pointer is declared +// - The name of a member of a struct type, meaning the value of that member in +// the context of the call. For example +// VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount"), +// this means the number of memory heaps available in the device associated +// with the VmaAllocator being dealt with. +#ifndef VMA_LEN_IF_NOT_NULL + #define VMA_LEN_IF_NOT_NULL(len) +#endif + +// The VMA_NULLABLE macro is defined to be _Nullable when compiling with Clang. +// see: https://clang.llvm.org/docs/AttributeReference.html#nullable +#ifndef VMA_NULLABLE + #ifdef __clang__ + #define VMA_NULLABLE _Nullable + #else + #define VMA_NULLABLE + #endif +#endif + +// The VMA_NOT_NULL macro is defined to be _Nonnull when compiling with Clang. +// see: https://clang.llvm.org/docs/AttributeReference.html#nonnull +#ifndef VMA_NOT_NULL + #ifdef __clang__ + #define VMA_NOT_NULL _Nonnull + #else + #define VMA_NOT_NULL + #endif +#endif + +// If non-dispatchable handles are represented as pointers then we can give +// then nullability annotations +#ifndef VMA_NOT_NULL_NON_DISPATCHABLE + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VMA_NOT_NULL_NON_DISPATCHABLE VMA_NOT_NULL + #else + #define VMA_NOT_NULL_NON_DISPATCHABLE + #endif +#endif + +#ifndef VMA_NULLABLE_NON_DISPATCHABLE + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VMA_NULLABLE_NON_DISPATCHABLE VMA_NULLABLE + #else + #define VMA_NULLABLE_NON_DISPATCHABLE + #endif +#endif + +#ifndef VMA_STATS_STRING_ENABLED + #define VMA_STATS_STRING_ENABLED 1 +#endif + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// INTERFACE +// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Sections for managing code placement in file, only for development purposes e.g. for convenient folding inside an IDE. +#ifndef _VMA_ENUM_DECLARATIONS + +/** +\addtogroup group_init +@{ +*/ + +/// Flags for created #VmaAllocator. +typedef enum VmaAllocatorCreateFlagBits +{ + /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. + + Using this flag may increase performance because internal mutexes are not used. + */ + VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, + /** \brief Enables usage of VK_KHR_dedicated_allocation extension. + + The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. + When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. + + Using this extension will automatically allocate dedicated blocks of memory for + some buffers and images instead of suballocating place for them out of bigger + memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT + flag) when it is recommended by the driver. It may improve performance on some + GPUs. + + You may set this flag only if you found out that following device extensions are + supported, you enabled them while creating Vulkan device passed as + VmaAllocatorCreateInfo::device, and you want them to be used internally by this + library: + + - VK_KHR_get_memory_requirements2 (device extension) + - VK_KHR_dedicated_allocation (device extension) + + When this flag is set, you can experience following warnings reported by Vulkan + validation layer. You can ignore them. + + > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. + */ + VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, + /** + Enables usage of VK_KHR_bind_memory2 extension. + + The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. + When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. + + You may set this flag only if you found out that this device extension is supported, + you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + and you want it to be used internally by this library. + + The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`, + which allow to pass a chain of `pNext` structures while binding. + This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2(). + */ + VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT = 0x00000004, + /** + Enables usage of VK_EXT_memory_budget extension. + + You may set this flag only if you found out that this device extension is supported, + you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + and you want it to be used internally by this library, along with another instance extension + VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted). + + The extension provides query for current memory usage and budget, which will probably + be more accurate than an estimation used by the library otherwise. + */ + VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT = 0x00000008, + /** + Enables usage of VK_AMD_device_coherent_memory extension. + + You may set this flag only if you: + + - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device, + - want it to be used internally by this library. + + The extension and accompanying device feature provide access to memory types with + `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags. + They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR. + + When the extension is not enabled, such memory types are still enumerated, but their usage is illegal. + To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type, + returning `VK_ERROR_FEATURE_NOT_PRESENT`. + */ + VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT = 0x00000010, + /** + Enables usage of "buffer device address" feature, which allows you to use function + `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader. + + You may set this flag only if you: + + 1. (For Vulkan version < 1.2) Found as available and enabled device extension + VK_KHR_buffer_device_address. + This extension is promoted to core Vulkan 1.2. + 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress`. + + When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` using VMA. + The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT` to + allocated memory blocks wherever it might be needed. + + For more information, see documentation chapter \ref enabling_buffer_device_address. + */ + VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT = 0x00000020, + /** + Enables usage of VK_EXT_memory_priority extension in the library. + + You may set this flag only if you found available and enabled this device extension, + along with `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority == VK_TRUE`, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + + When this flag is used, VmaAllocationCreateInfo::priority and VmaPoolCreateInfo::priority + are used to set priorities of allocated Vulkan memory. Without it, these variables are ignored. + + A priority must be a floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. + Larger values are higher priority. The granularity of the priorities is implementation-dependent. + It is automatically passed to every call to `vkAllocateMemory` done by the library using structure `VkMemoryPriorityAllocateInfoEXT`. + The value to be used for default priority is 0.5. + For more details, see the documentation of the VK_EXT_memory_priority extension. + */ + VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT = 0x00000040, + + VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaAllocatorCreateFlagBits; +/// See #VmaAllocatorCreateFlagBits. +typedef VkFlags VmaAllocatorCreateFlags; + +/** @} */ + +/** +\addtogroup group_alloc +@{ +*/ + +/// \brief Intended usage of the allocated memory. +typedef enum VmaMemoryUsage +{ + /** No intended memory usage specified. + Use other members of VmaAllocationCreateInfo to specify your requirements. + */ + VMA_MEMORY_USAGE_UNKNOWN = 0, + /** + \deprecated Obsolete, preserved for backward compatibility. + Prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_GPU_ONLY = 1, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` and `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`. + */ + VMA_MEMORY_USAGE_CPU_ONLY = 2, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_CPU_TO_GPU = 3, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`. + */ + VMA_MEMORY_USAGE_GPU_TO_CPU = 4, + /** + \deprecated Obsolete, preserved for backward compatibility. + Prefers not `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_CPU_COPY = 5, + /** + Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`. + Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation. + + Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`. + + Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + */ + VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = 6, + /** + Selects best memory type automatically. + This flag is recommended for most common use cases. + + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. + + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO = 7, + /** + Selects best memory type automatically with preference for GPU (device) memory. + + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. + + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE = 8, + /** + Selects best memory type automatically with preference for CPU (host) memory. + + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. + + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO_PREFER_HOST = 9, + + VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF +} VmaMemoryUsage; + +/// Flags to be passed as VmaAllocationCreateInfo::flags. +typedef enum VmaAllocationCreateFlagBits +{ + /** \brief Set this flag if the allocation should have its own memory block. + + Use it for special, big resources, like fullscreen images used as attachments. + */ + VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, + + /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. + + If new allocation cannot be placed in any of the existing blocks, allocation + fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. + + You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and + #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. + */ + VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, + /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. + + Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. + + It is valid to use this flag for allocation made from memory type that is not + `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is + useful if you need an allocation that is efficient to use on GPU + (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that + support it (e.g. Intel GPU). + */ + VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, + /** \deprecated Preserved for backward compatibility. Consider using vmaSetAllocationName() instead. + + Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a + null-terminated string. Instead of copying pointer value, a local copy of the + string is made and stored in allocation's `pName`. The string is automatically + freed together with the allocation. It is also used in vmaBuildStatsString(). + */ + VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, + /** Allocation will be created from upper stack in a double stack pool. + + This flag is only allowed for custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT flag. + */ + VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040, + /** Create both buffer/image and allocation, but don't bind them together. + It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions. + The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage(). + Otherwise it is ignored. + + If you want to make sure the new buffer/image is not tied to the new memory allocation + through `VkMemoryDedicatedAllocateInfoKHR` structure in case the allocation ends up in its own memory block, + use also flag #VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT. + */ + VMA_ALLOCATION_CREATE_DONT_BIND_BIT = 0x00000080, + /** Create allocation only if additional device memory required for it, if any, won't exceed + memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + */ + VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, + /** \brief Set this flag if the allocated memory will have aliasing resources. + + Usage of this flag prevents supplying `VkMemoryDedicatedAllocateInfoKHR` when #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT is specified. + Otherwise created dedicated memory will not be suitable for aliasing resources, resulting in Vulkan Validation Layer errors. + */ + VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT = 0x00000200, + /** + Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). + + - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, + you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. + - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. + This includes allocations created in \ref custom_memory_pools. + + Declares that mapped memory will only be written sequentially, e.g. using `memcpy()` or a loop writing number-by-number, + never read or accessed randomly, so a memory type can be selected that is uncached and write-combined. + + \warning Violating this declaration may work correctly, but will likely be very slow. + Watch out for implicit reads introduced by doing e.g. `pMappedData[i] += x;` + Better prepare your data in a local variable and `memcpy()` it to the mapped pointer all at once. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT = 0x00000400, + /** + Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). + + - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, + you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. + - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. + This includes allocations created in \ref custom_memory_pools. + + Declares that mapped memory can be read, written, and accessed in random order, + so a `HOST_CACHED` memory type is required. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT = 0x00000800, + /** + Together with #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT, + it says that despite request for host access, a not-`HOST_VISIBLE` memory type can be selected + if it may improve performance. + + By using this flag, you declare that you will check if the allocation ended up in a `HOST_VISIBLE` memory type + (e.g. using vmaGetAllocationMemoryProperties()) and if not, you will create some "staging" buffer and + issue an explicit transfer to write/read your data. + To prepare for this possibility, don't forget to add appropriate flags like + `VK_BUFFER_USAGE_TRANSFER_DST_BIT`, `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` to the parameters of created buffer or image. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT = 0x00001000, + /** Allocation strategy that chooses smallest possible free range for the allocation + to minimize memory usage and fragmentation, possibly at the expense of allocation time. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = 0x00010000, + /** Allocation strategy that chooses first suitable free range for the allocation - + not necessarily in terms of the smallest offset but the one that is easiest and fastest to find + to minimize allocation time, possibly at the expense of allocation quality. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = 0x00020000, + /** Allocation strategy that chooses always the lowest offset in available space. + This is not the most efficient strategy but achieves highly packed data. + Used internally by defragmentation, not recomended in typical usage. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = 0x00040000, + /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT. + */ + VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, + /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT. + */ + VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, + /** A bit mask to extract only `STRATEGY` bits from entire set of flags. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MASK = + VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT | + VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT | + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + + VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaAllocationCreateFlagBits; +/// See #VmaAllocationCreateFlagBits. +typedef VkFlags VmaAllocationCreateFlags; + +/// Flags to be passed as VmaPoolCreateInfo::flags. +typedef enum VmaPoolCreateFlagBits +{ + /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. + + This is an optional optimization flag. + + If you always allocate using vmaCreateBuffer(), vmaCreateImage(), + vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator + knows exact type of your allocations so it can handle Buffer-Image Granularity + in the optimal way. + + If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), + exact type of such allocations is not known, so allocator must be conservative + in handling Buffer-Image Granularity, which can lead to suboptimal allocation + (wasted memory). In that case, if you can make sure you always allocate only + buffers and linear images or only optimal images out of this pool, use this flag + to make allocator disregard Buffer-Image Granularity and so make allocations + faster and more optimal. + */ + VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, + + /** \brief Enables alternative, linear allocation algorithm in this pool. + + Specify this flag to enable linear allocation algorithm, which always creates + new allocations after last one and doesn't reuse space from allocations freed in + between. It trades memory consumption for simplified algorithm and data + structure, which has better performance and uses less memory for metadata. + + By using this flag, you can achieve behavior of free-at-once, stack, + ring buffer, and double stack. + For details, see documentation chapter \ref linear_algorithm. + */ + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004, + + /** Bit mask to extract only `ALGORITHM` bits from entire set of flags. + */ + VMA_POOL_CREATE_ALGORITHM_MASK = + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT, + + VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaPoolCreateFlagBits; +/// Flags to be passed as VmaPoolCreateInfo::flags. See #VmaPoolCreateFlagBits. +typedef VkFlags VmaPoolCreateFlags; + +/// Flags to be passed as VmaDefragmentationInfo::flags. +typedef enum VmaDefragmentationFlagBits +{ + /* \brief Use simple but fast algorithm for defragmentation. + May not achieve best results but will require least time to compute and least allocations to copy. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT = 0x1, + /* \brief Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified. + Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT = 0x2, + /* \brief Perform full defragmentation of memory. + Can result in notably more time to compute and allocations to copy, but will achieve best memory packing. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT = 0x4, + /** \brief Use the most roboust algorithm at the cost of time to compute and number of copies to make. + Only available when bufferImageGranularity is greater than 1, since it aims to reduce + alignment issues between different types of resources. + Otherwise falls back to same behavior as #VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT = 0x8, + + /// A bit mask to extract only `ALGORITHM` bits from entire set of flags. + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK = + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT | + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT | + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT | + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT, + + VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaDefragmentationFlagBits; +/// See #VmaDefragmentationFlagBits. +typedef VkFlags VmaDefragmentationFlags; + +/// Operation performed on single defragmentation move. See structure #VmaDefragmentationMove. +typedef enum VmaDefragmentationMoveOperation +{ + /// Buffer/image has been recreated at `dstTmpAllocation`, data has been copied, old buffer/image has been destroyed. `srcAllocation` should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass(). + VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY = 0, + /// Set this value if you cannot move the allocation. New place reserved at `dstTmpAllocation` will be freed. `srcAllocation` will remain unchanged. + VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1, + /// Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved at `dstTmpAllocation` will be freed, along with `srcAllocation`, which will be destroyed. + VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2, +} VmaDefragmentationMoveOperation; + +/** @} */ + +/** +\addtogroup group_virtual +@{ +*/ + +/// Flags to be passed as VmaVirtualBlockCreateInfo::flags. +typedef enum VmaVirtualBlockCreateFlagBits +{ + /** \brief Enables alternative, linear allocation algorithm in this virtual block. + + Specify this flag to enable linear allocation algorithm, which always creates + new allocations after last one and doesn't reuse space from allocations freed in + between. It trades memory consumption for simplified algorithm and data + structure, which has better performance and uses less memory for metadata. + + By using this flag, you can achieve behavior of free-at-once, stack, + ring buffer, and double stack. + For details, see documentation chapter \ref linear_algorithm. + */ + VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT = 0x00000001, + + /** \brief Bit mask to extract only `ALGORITHM` bits from entire set of flags. + */ + VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK = + VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT, + + VMA_VIRTUAL_BLOCK_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaVirtualBlockCreateFlagBits; +/// Flags to be passed as VmaVirtualBlockCreateInfo::flags. See #VmaVirtualBlockCreateFlagBits. +typedef VkFlags VmaVirtualBlockCreateFlags; + +/// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. +typedef enum VmaVirtualAllocationCreateFlagBits +{ + /** \brief Allocation will be created from upper stack in a double stack pool. + + This flag is only allowed for virtual blocks created with #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT flag. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT, + /** \brief Allocation strategy that tries to minimize memory usage. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, + /** \brief Allocation strategy that tries to minimize allocation time. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, + /** Allocation strategy that chooses always the lowest offset in available space. + This is not the most efficient strategy but achieves highly packed data. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + /** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags. + + These strategy flags are binary compatible with equivalent flags in #VmaAllocationCreateFlagBits. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MASK, + + VMA_VIRTUAL_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaVirtualAllocationCreateFlagBits; +/// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. See #VmaVirtualAllocationCreateFlagBits. +typedef VkFlags VmaVirtualAllocationCreateFlags; + +/** @} */ + +#endif // _VMA_ENUM_DECLARATIONS + +#ifndef _VMA_DATA_TYPES_DECLARATIONS + +/** +\addtogroup group_init +@{ */ + +/** \struct VmaAllocator +\brief Represents main object of this library initialized. + +Fill structure #VmaAllocatorCreateInfo and call function vmaCreateAllocator() to create it. +Call function vmaDestroyAllocator() to destroy it. + +It is recommended to create just one object of this type per `VkDevice` object, +right after Vulkan is initialized and keep it alive until before Vulkan device is destroyed. +*/ +VK_DEFINE_HANDLE(VmaAllocator) + +/** @} */ + +/** +\addtogroup group_alloc +@{ +*/ + +/** \struct VmaPool +\brief Represents custom memory pool + +Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. +Call function vmaDestroyPool() to destroy it. + +For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). +*/ +VK_DEFINE_HANDLE(VmaPool) + +/** \struct VmaAllocation +\brief Represents single memory allocation. + +It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type +plus unique offset. + +There are multiple ways to create such object. +You need to fill structure VmaAllocationCreateInfo. +For more information see [Choosing memory type](@ref choosing_memory_type). + +Although the library provides convenience functions that create Vulkan buffer or image, +allocate memory for it and bind them together, +binding of the allocation to a buffer or an image is out of scope of the allocation itself. +Allocation object can exist without buffer/image bound, +binding can be done manually by the user, and destruction of it can be done +independently of destruction of the allocation. + +The object also remembers its size and some other information. +To retrieve this information, use function vmaGetAllocationInfo() and inspect +returned structure VmaAllocationInfo. +*/ +VK_DEFINE_HANDLE(VmaAllocation) + +/** \struct VmaDefragmentationContext +\brief An opaque object that represents started defragmentation process. + +Fill structure #VmaDefragmentationInfo and call function vmaBeginDefragmentation() to create it. +Call function vmaEndDefragmentation() to destroy it. +*/ +VK_DEFINE_HANDLE(VmaDefragmentationContext) + +/** @} */ + +/** +\addtogroup group_virtual +@{ +*/ + +/** \struct VmaVirtualAllocation +\brief Represents single memory allocation done inside VmaVirtualBlock. + +Use it as a unique identifier to virtual allocation within the single block. + +Use value `VK_NULL_HANDLE` to represent a null/invalid allocation. +*/ +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaVirtualAllocation); + +/** @} */ + +/** +\addtogroup group_virtual +@{ +*/ + +/** \struct VmaVirtualBlock +\brief Handle to a virtual block object that allows to use core allocation algorithm without allocating any real GPU memory. + +Fill in #VmaVirtualBlockCreateInfo structure and use vmaCreateVirtualBlock() to create it. Use vmaDestroyVirtualBlock() to destroy it. +For more information, see documentation chapter \ref virtual_allocator. + +This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally. +*/ +VK_DEFINE_HANDLE(VmaVirtualBlock) + +/** @} */ + +/** +\addtogroup group_init +@{ +*/ + +/// Callback function called after successful vkAllocateMemory. +typedef void (VKAPI_PTR* PFN_vmaAllocateDeviceMemoryFunction)( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryType, + VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, + VkDeviceSize size, + void* VMA_NULLABLE pUserData); + +/// Callback function called before vkFreeMemory. +typedef void (VKAPI_PTR* PFN_vmaFreeDeviceMemoryFunction)( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryType, + VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, + VkDeviceSize size, + void* VMA_NULLABLE pUserData); + +/** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. + +Provided for informative purpose, e.g. to gather statistics about number of +allocations or total amount of memory allocated in Vulkan. + +Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. +*/ +typedef struct VmaDeviceMemoryCallbacks +{ + /// Optional, can be null. + PFN_vmaAllocateDeviceMemoryFunction VMA_NULLABLE pfnAllocate; + /// Optional, can be null. + PFN_vmaFreeDeviceMemoryFunction VMA_NULLABLE pfnFree; + /// Optional, can be null. + void* VMA_NULLABLE pUserData; +} VmaDeviceMemoryCallbacks; + +/** \brief Pointers to some Vulkan functions - a subset used by the library. + +Used in VmaAllocatorCreateInfo::pVulkanFunctions. +*/ +typedef struct VmaVulkanFunctions +{ + /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. + PFN_vkGetInstanceProcAddr VMA_NULLABLE vkGetInstanceProcAddr; + /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. + PFN_vkGetDeviceProcAddr VMA_NULLABLE vkGetDeviceProcAddr; + PFN_vkGetPhysicalDeviceProperties VMA_NULLABLE vkGetPhysicalDeviceProperties; + PFN_vkGetPhysicalDeviceMemoryProperties VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties; + PFN_vkAllocateMemory VMA_NULLABLE vkAllocateMemory; + PFN_vkFreeMemory VMA_NULLABLE vkFreeMemory; + PFN_vkMapMemory VMA_NULLABLE vkMapMemory; + PFN_vkUnmapMemory VMA_NULLABLE vkUnmapMemory; + PFN_vkFlushMappedMemoryRanges VMA_NULLABLE vkFlushMappedMemoryRanges; + PFN_vkInvalidateMappedMemoryRanges VMA_NULLABLE vkInvalidateMappedMemoryRanges; + PFN_vkBindBufferMemory VMA_NULLABLE vkBindBufferMemory; + PFN_vkBindImageMemory VMA_NULLABLE vkBindImageMemory; + PFN_vkGetBufferMemoryRequirements VMA_NULLABLE vkGetBufferMemoryRequirements; + PFN_vkGetImageMemoryRequirements VMA_NULLABLE vkGetImageMemoryRequirements; + PFN_vkCreateBuffer VMA_NULLABLE vkCreateBuffer; + PFN_vkDestroyBuffer VMA_NULLABLE vkDestroyBuffer; + PFN_vkCreateImage VMA_NULLABLE vkCreateImage; + PFN_vkDestroyImage VMA_NULLABLE vkDestroyImage; + PFN_vkCmdCopyBuffer VMA_NULLABLE vkCmdCopyBuffer; +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + /// Fetch "vkGetBufferMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetBufferMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. + PFN_vkGetBufferMemoryRequirements2KHR VMA_NULLABLE vkGetBufferMemoryRequirements2KHR; + /// Fetch "vkGetImageMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetImageMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. + PFN_vkGetImageMemoryRequirements2KHR VMA_NULLABLE vkGetImageMemoryRequirements2KHR; +#endif +#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 + /// Fetch "vkBindBufferMemory2" on Vulkan >= 1.1, fetch "vkBindBufferMemory2KHR" when using VK_KHR_bind_memory2 extension. + PFN_vkBindBufferMemory2KHR VMA_NULLABLE vkBindBufferMemory2KHR; + /// Fetch "vkBindImageMemory2" on Vulkan >= 1.1, fetch "vkBindImageMemory2KHR" when using VK_KHR_bind_memory2 extension. + PFN_vkBindImageMemory2KHR VMA_NULLABLE vkBindImageMemory2KHR; +#endif +#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 + PFN_vkGetPhysicalDeviceMemoryProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties2KHR; +#endif +#if VMA_VULKAN_VERSION >= 1003000 + /// Fetch from "vkGetDeviceBufferMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceBufferMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. + PFN_vkGetDeviceBufferMemoryRequirements VMA_NULLABLE vkGetDeviceBufferMemoryRequirements; + /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. + PFN_vkGetDeviceImageMemoryRequirements VMA_NULLABLE vkGetDeviceImageMemoryRequirements; +#endif +} VmaVulkanFunctions; + +/// Description of a Allocator to be created. +typedef struct VmaAllocatorCreateInfo +{ + /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. + VmaAllocatorCreateFlags flags; + /// Vulkan physical device. + /** It must be valid throughout whole lifetime of created allocator. */ + VkPhysicalDevice VMA_NOT_NULL physicalDevice; + /// Vulkan device. + /** It must be valid throughout whole lifetime of created allocator. */ + VkDevice VMA_NOT_NULL device; + /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. + /** Set to 0 to use default, which is currently 256 MiB. */ + VkDeviceSize preferredLargeHeapBlockSize; + /// Custom CPU memory allocation callbacks. Optional. + /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ + const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; + /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. + /** Optional, can be null. */ + const VmaDeviceMemoryCallbacks* VMA_NULLABLE pDeviceMemoryCallbacks; + /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. + + If not NULL, it must be a pointer to an array of + `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on + maximum number of bytes that can be allocated out of particular Vulkan memory + heap. + + Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that + heap. This is also the default in case of `pHeapSizeLimit` = NULL. + + If there is a limit defined for a heap: + + - If user tries to allocate more memory from that heap using this allocator, + the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the + value of this limit will be reported instead when using vmaGetMemoryProperties(). + + Warning! Using this feature may not be equivalent to installing a GPU with + smaller amount of memory, because graphics driver doesn't necessary fail new + allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is + exceeded. It may return success and just silently migrate some device memory + blocks to system RAM. This driver behavior can also be controlled using + VK_AMD_memory_overallocation_behavior extension. + */ + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pHeapSizeLimit; + + /** \brief Pointers to Vulkan functions. Can be null. + + For details see [Pointers to Vulkan functions](@ref config_Vulkan_functions). + */ + const VmaVulkanFunctions* VMA_NULLABLE pVulkanFunctions; + /** \brief Handle to Vulkan instance object. + + Starting from version 3.0.0 this member is no longer optional, it must be set! + */ + VkInstance VMA_NOT_NULL instance; + /** \brief Optional. The highest version of Vulkan that the application is designed to use. + + It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. + The patch version number specified is ignored. Only the major and minor versions are considered. + It must be less or equal (preferably equal) to value as passed to `vkCreateInstance` as `VkApplicationInfo::apiVersion`. + Only versions 1.0, 1.1, 1.2, 1.3 are supported by the current implementation. + Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. + */ + uint32_t vulkanApiVersion; +#if VMA_EXTERNAL_MEMORY + /** \brief Either null or a pointer to an array of external memory handle types for each Vulkan memory type. + + If not NULL, it must be a pointer to an array of `VkPhysicalDeviceMemoryProperties::memoryTypeCount` + elements, defining external memory handle types of particular Vulkan memory type, + to be passed using `VkExportMemoryAllocateInfoKHR`. + + Any of the elements may be equal to 0, which means not to use `VkExportMemoryAllocateInfoKHR` on this memory type. + This is also the default in case of `pTypeExternalMemoryHandleTypes` = NULL. + */ + const VkExternalMemoryHandleTypeFlagsKHR* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryTypeCount") pTypeExternalMemoryHandleTypes; +#endif // #if VMA_EXTERNAL_MEMORY +} VmaAllocatorCreateInfo; + +/// Information about existing #VmaAllocator object. +typedef struct VmaAllocatorInfo +{ + /** \brief Handle to Vulkan instance object. + + This is the same value as has been passed through VmaAllocatorCreateInfo::instance. + */ + VkInstance VMA_NOT_NULL instance; + /** \brief Handle to Vulkan physical device object. + + This is the same value as has been passed through VmaAllocatorCreateInfo::physicalDevice. + */ + VkPhysicalDevice VMA_NOT_NULL physicalDevice; + /** \brief Handle to Vulkan device object. + + This is the same value as has been passed through VmaAllocatorCreateInfo::device. + */ + VkDevice VMA_NOT_NULL device; +} VmaAllocatorInfo; + +/** @} */ + +/** +\addtogroup group_stats +@{ +*/ + +/** \brief Calculated statistics of memory usage e.g. in a specific memory type, heap, custom pool, or total. + +These are fast to calculate. +See functions: vmaGetHeapBudgets(), vmaGetPoolStatistics(). +*/ +typedef struct VmaStatistics +{ + /** \brief Number of `VkDeviceMemory` objects - Vulkan memory blocks allocated. + */ + uint32_t blockCount; + /** \brief Number of #VmaAllocation objects allocated. + + Dedicated allocations have their own blocks, so each one adds 1 to `allocationCount` as well as `blockCount`. + */ + uint32_t allocationCount; + /** \brief Number of bytes allocated in `VkDeviceMemory` blocks. + + \note To avoid confusion, please be aware that what Vulkan calls an "allocation" - a whole `VkDeviceMemory` object + (e.g. as in `VkPhysicalDeviceLimits::maxMemoryAllocationCount`) is called a "block" in VMA, while VMA calls + "allocation" a #VmaAllocation object that represents a memory region sub-allocated from such block, usually for a single buffer or image. + */ + VkDeviceSize blockBytes; + /** \brief Total number of bytes occupied by all #VmaAllocation objects. + + Always less or equal than `blockBytes`. + Difference `(blockBytes - allocationBytes)` is the amount of memory allocated from Vulkan + but unused by any #VmaAllocation. + */ + VkDeviceSize allocationBytes; +} VmaStatistics; + +/** \brief More detailed statistics than #VmaStatistics. + +These are slower to calculate. Use for debugging purposes. +See functions: vmaCalculateStatistics(), vmaCalculatePoolStatistics(). + +Previous version of the statistics API provided averages, but they have been removed +because they can be easily calculated as: + +\code +VkDeviceSize allocationSizeAvg = detailedStats.statistics.allocationBytes / detailedStats.statistics.allocationCount; +VkDeviceSize unusedBytes = detailedStats.statistics.blockBytes - detailedStats.statistics.allocationBytes; +VkDeviceSize unusedRangeSizeAvg = unusedBytes / detailedStats.unusedRangeCount; +\endcode +*/ +typedef struct VmaDetailedStatistics +{ + /// Basic statistics. + VmaStatistics statistics; + /// Number of free ranges of memory between allocations. + uint32_t unusedRangeCount; + /// Smallest allocation size. `VK_WHOLE_SIZE` if there are 0 allocations. + VkDeviceSize allocationSizeMin; + /// Largest allocation size. 0 if there are 0 allocations. + VkDeviceSize allocationSizeMax; + /// Smallest empty range size. `VK_WHOLE_SIZE` if there are 0 empty ranges. + VkDeviceSize unusedRangeSizeMin; + /// Largest empty range size. 0 if there are 0 empty ranges. + VkDeviceSize unusedRangeSizeMax; +} VmaDetailedStatistics; + +/** \brief General statistics from current state of the Allocator - +total memory usage across all memory heaps and types. + +These are slower to calculate. Use for debugging purposes. +See function vmaCalculateStatistics(). +*/ +typedef struct VmaTotalStatistics +{ + VmaDetailedStatistics memoryType[VK_MAX_MEMORY_TYPES]; + VmaDetailedStatistics memoryHeap[VK_MAX_MEMORY_HEAPS]; + VmaDetailedStatistics total; +} VmaTotalStatistics; + +/** \brief Statistics of current memory usage and available budget for a specific memory heap. + +These are fast to calculate. +See function vmaGetHeapBudgets(). +*/ +typedef struct VmaBudget +{ + /** \brief Statistics fetched from the library. + */ + VmaStatistics statistics; + /** \brief Estimated current memory usage of the program, in bytes. + + Fetched from system using VK_EXT_memory_budget extension if enabled. + + It might be different than `statistics.blockBytes` (usually higher) due to additional implicit objects + also occupying the memory, like swapchain, pipelines, descriptor heaps, command buffers, or + `VkDeviceMemory` blocks allocated outside of this library, if any. + */ + VkDeviceSize usage; + /** \brief Estimated amount of memory available to the program, in bytes. + + Fetched from system using VK_EXT_memory_budget extension if enabled. + + It might be different (most probably smaller) than `VkMemoryHeap::size[heapIndex]` due to factors + external to the program, decided by the operating system. + Difference `budget - usage` is the amount of additional memory that can probably + be allocated without problems. Exceeding the budget may result in various problems. + */ + VkDeviceSize budget; +} VmaBudget; + +/** @} */ + +/** +\addtogroup group_alloc +@{ +*/ + +/** \brief Parameters of new #VmaAllocation. + +To be used with functions like vmaCreateBuffer(), vmaCreateImage(), and many others. +*/ +typedef struct VmaAllocationCreateInfo +{ + /// Use #VmaAllocationCreateFlagBits enum. + VmaAllocationCreateFlags flags; + /** \brief Intended usage of memory. + + You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n + If `pool` is not null, this member is ignored. + */ + VmaMemoryUsage usage; + /** \brief Flags that must be set in a Memory Type chosen for an allocation. + + Leave 0 if you specify memory requirements in other way. \n + If `pool` is not null, this member is ignored.*/ + VkMemoryPropertyFlags requiredFlags; + /** \brief Flags that preferably should be set in a memory type chosen for an allocation. + + Set to 0 if no additional flags are preferred. \n + If `pool` is not null, this member is ignored. */ + VkMemoryPropertyFlags preferredFlags; + /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. + + Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if + it meets other requirements specified by this structure, with no further + restrictions on memory type index. \n + If `pool` is not null, this member is ignored. + */ + uint32_t memoryTypeBits; + /** \brief Pool that this allocation should be created in. + + Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: + `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. + */ + VmaPool VMA_NULLABLE pool; + /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). + + If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either + null or pointer to a null-terminated string. The string will be then copied to + internal buffer, so it doesn't need to be valid after allocation call. + */ + void* VMA_NULLABLE pUserData; + /** \brief A floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. + + It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object + and this allocation ends up as dedicated or is explicitly forced as dedicated using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + Otherwise, it has the priority of a memory block where it is placed and this variable is ignored. + */ + float priority; +} VmaAllocationCreateInfo; + +/// Describes parameter of created #VmaPool. +typedef struct VmaPoolCreateInfo +{ + /** \brief Vulkan memory type index to allocate this pool from. + */ + uint32_t memoryTypeIndex; + /** \brief Use combination of #VmaPoolCreateFlagBits. + */ + VmaPoolCreateFlags flags; + /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. Optional. + + Specify nonzero to set explicit, constant size of memory blocks used by this + pool. + + Leave 0 to use default and let the library manage block sizes automatically. + Sizes of particular blocks may vary. + In this case, the pool will also support dedicated allocations. + */ + VkDeviceSize blockSize; + /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. + + Set to 0 to have no preallocated blocks and allow the pool be completely empty. + */ + size_t minBlockCount; + /** \brief Maximum number of blocks that can be allocated in this pool. Optional. + + Set to 0 to use default, which is `SIZE_MAX`, which means no limit. + + Set to same value as VmaPoolCreateInfo::minBlockCount to have fixed amount of memory allocated + throughout whole lifetime of this pool. + */ + size_t maxBlockCount; + /** \brief A floating-point value between 0 and 1, indicating the priority of the allocations in this pool relative to other memory allocations. + + It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object. + Otherwise, this variable is ignored. + */ + float priority; + /** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0. + + Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two. + It can be useful in cases where alignment returned by Vulkan by functions like `vkGetBufferMemoryRequirements` is not enough, + e.g. when doing interop with OpenGL. + */ + VkDeviceSize minAllocationAlignment; + /** \brief Additional `pNext` chain to be attached to `VkMemoryAllocateInfo` used for every allocation made by this pool. Optional. + + Optional, can be null. If not null, it must point to a `pNext` chain of structures that can be attached to `VkMemoryAllocateInfo`. + It can be useful for special needs such as adding `VkExportMemoryAllocateInfoKHR`. + Structures pointed by this member must remain alive and unchanged for the whole lifetime of the custom pool. + + Please note that some structures, e.g. `VkMemoryPriorityAllocateInfoEXT`, `VkMemoryDedicatedAllocateInfoKHR`, + can be attached automatically by this library when using other, more convenient of its features. + */ + void* VMA_NULLABLE pMemoryAllocateNext; +} VmaPoolCreateInfo; + +/** @} */ + +/** +\addtogroup group_alloc +@{ +*/ + +/// Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). +typedef struct VmaAllocationInfo +{ + /** \brief Memory type index that this allocation was allocated from. + + It never changes. + */ + uint32_t memoryType; + /** \brief Handle to Vulkan memory object. + + Same memory object can be shared by multiple allocations. + + It can change after the allocation is moved during \ref defragmentation. + */ + VkDeviceMemory VMA_NULLABLE_NON_DISPATCHABLE deviceMemory; + /** \brief Offset in `VkDeviceMemory` object to the beginning of this allocation, in bytes. `(deviceMemory, offset)` pair is unique to this allocation. + + You usually don't need to use this offset. If you create a buffer or an image together with the allocation using e.g. function + vmaCreateBuffer(), vmaCreateImage(), functions that operate on these resources refer to the beginning of the buffer or image, + not entire device memory block. Functions like vmaMapMemory(), vmaBindBufferMemory() also refer to the beginning of the allocation + and apply this offset automatically. + + It can change after the allocation is moved during \ref defragmentation. + */ + VkDeviceSize offset; + /** \brief Size of this allocation, in bytes. + + It never changes. + + \note Allocation size returned in this variable may be greater than the size + requested for the resource e.g. as `VkBufferCreateInfo::size`. Whole size of the + allocation is accessible for operations on memory e.g. using a pointer after + mapping with vmaMapMemory(), but operations on the resource e.g. using + `vkCmdCopyBuffer` must be limited to the size of the resource. + */ + VkDeviceSize size; + /** \brief Pointer to the beginning of this allocation as mapped data. + + If the allocation hasn't been mapped using vmaMapMemory() and hasn't been + created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value is null. + + It can change after call to vmaMapMemory(), vmaUnmapMemory(). + It can also change after the allocation is moved during \ref defragmentation. + */ + void* VMA_NULLABLE pMappedData; + /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). + + It can change after call to vmaSetAllocationUserData() for this allocation. + */ + void* VMA_NULLABLE pUserData; + /** \brief Custom allocation name that was set with vmaSetAllocationName(). + + It can change after call to vmaSetAllocationName() for this allocation. + + Another way to set custom name is to pass it in VmaAllocationCreateInfo::pUserData with + additional flag #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT set [DEPRECATED]. + */ + const char* VMA_NULLABLE pName; +} VmaAllocationInfo; + +/** \brief Parameters for defragmentation. + +To be used with function vmaBeginDefragmentation(). +*/ +typedef struct VmaDefragmentationInfo +{ + /// \brief Use combination of #VmaDefragmentationFlagBits. + VmaDefragmentationFlags flags; + /** \brief Custom pool to be defragmented. + + If null then default pools will undergo defragmentation process. + */ + VmaPool VMA_NULLABLE pool; + /** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places. + + `0` means no limit. + */ + VkDeviceSize maxBytesPerPass; + /** \brief Maximum number of allocations that can be moved during single pass to a different place. + + `0` means no limit. + */ + uint32_t maxAllocationsPerPass; +} VmaDefragmentationInfo; + +/// Single move of an allocation to be done for defragmentation. +typedef struct VmaDefragmentationMove +{ + /// Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it. + VmaDefragmentationMoveOperation operation; + /// Allocation that should be moved. + VmaAllocation VMA_NOT_NULL srcAllocation; + /** \brief Temporary allocation pointing to destination memory that will replace `srcAllocation`. + + \warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass, + to be used for binding new buffer/image to the destination memory using e.g. vmaBindBufferMemory(). + vmaEndDefragmentationPass() will destroy it and make `srcAllocation` point to this memory. + */ + VmaAllocation VMA_NOT_NULL dstTmpAllocation; +} VmaDefragmentationMove; + +/** \brief Parameters for incremental defragmentation steps. + +To be used with function vmaBeginDefragmentationPass(). +*/ +typedef struct VmaDefragmentationPassMoveInfo +{ + /// Number of elements in the `pMoves` array. + uint32_t moveCount; + /** \brief Array of moves to be performed by the user in the current defragmentation pass. + + Pointer to an array of `moveCount` elements, owned by VMA, created in vmaBeginDefragmentationPass(), destroyed in vmaEndDefragmentationPass(). + + For each element, you should: + + 1. Create a new buffer/image in the place pointed by VmaDefragmentationMove::dstMemory + VmaDefragmentationMove::dstOffset. + 2. Copy data from the VmaDefragmentationMove::srcAllocation e.g. using `vkCmdCopyBuffer`, `vkCmdCopyImage`. + 3. Make sure these commands finished executing on the GPU. + 4. Destroy the old buffer/image. + + Only then you can finish defragmentation pass by calling vmaEndDefragmentationPass(). + After this call, the allocation will point to the new place in memory. + + Alternatively, if you cannot move specific allocation, you can set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. + + Alternatively, if you decide you want to completely remove the allocation: + + 1. Destroy its buffer/image. + 2. Set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY. + + Then, after vmaEndDefragmentationPass() the allocation will be freed. + */ + VmaDefragmentationMove* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(moveCount) pMoves; +} VmaDefragmentationPassMoveInfo; + +/// Statistics returned for defragmentation process in function vmaEndDefragmentation(). +typedef struct VmaDefragmentationStats +{ + /// Total number of bytes that have been copied while moving allocations to different places. + VkDeviceSize bytesMoved; + /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects. + VkDeviceSize bytesFreed; + /// Number of allocations that have been moved to different places. + uint32_t allocationsMoved; + /// Number of empty `VkDeviceMemory` objects that have been released to the system. + uint32_t deviceMemoryBlocksFreed; +} VmaDefragmentationStats; + +/** @} */ + +/** +\addtogroup group_virtual +@{ +*/ + +/// Parameters of created #VmaVirtualBlock object to be passed to vmaCreateVirtualBlock(). +typedef struct VmaVirtualBlockCreateInfo +{ + /** \brief Total size of the virtual block. + + Sizes can be expressed in bytes or any units you want as long as you are consistent in using them. + For example, if you allocate from some array of structures, 1 can mean single instance of entire structure. + */ + VkDeviceSize size; + + /** \brief Use combination of #VmaVirtualBlockCreateFlagBits. + */ + VmaVirtualBlockCreateFlags flags; + + /** \brief Custom CPU memory allocation callbacks. Optional. + + Optional, can be null. When specified, they will be used for all CPU-side memory allocations. + */ + const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; +} VmaVirtualBlockCreateInfo; + +/// Parameters of created virtual allocation to be passed to vmaVirtualAllocate(). +typedef struct VmaVirtualAllocationCreateInfo +{ + /** \brief Size of the allocation. + + Cannot be zero. + */ + VkDeviceSize size; + /** \brief Required alignment of the allocation. Optional. + + Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset. + */ + VkDeviceSize alignment; + /** \brief Use combination of #VmaVirtualAllocationCreateFlagBits. + */ + VmaVirtualAllocationCreateFlags flags; + /** \brief Custom pointer to be associated with the allocation. Optional. + + It can be any value and can be used for user-defined purposes. It can be fetched or changed later. + */ + void* VMA_NULLABLE pUserData; +} VmaVirtualAllocationCreateInfo; + +/// Parameters of an existing virtual allocation, returned by vmaGetVirtualAllocationInfo(). +typedef struct VmaVirtualAllocationInfo +{ + /** \brief Offset of the allocation. + + Offset at which the allocation was made. + */ + VkDeviceSize offset; + /** \brief Size of the allocation. + + Same value as passed in VmaVirtualAllocationCreateInfo::size. + */ + VkDeviceSize size; + /** \brief Custom pointer associated with the allocation. + + Same value as passed in VmaVirtualAllocationCreateInfo::pUserData or to vmaSetVirtualAllocationUserData(). + */ + void* VMA_NULLABLE pUserData; +} VmaVirtualAllocationInfo; + +/** @} */ + +#endif // _VMA_DATA_TYPES_DECLARATIONS + +#ifndef _VMA_FUNCTION_HEADERS + +/** +\addtogroup group_init +@{ +*/ + +/// Creates #VmaAllocator object. +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( + const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocator VMA_NULLABLE* VMA_NOT_NULL pAllocator); + +/// Destroys allocator object. +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( + VmaAllocator VMA_NULLABLE allocator); + +/** \brief Returns information about existing #VmaAllocator object - handle to Vulkan device etc. + +It might be useful if you want to keep just the #VmaAllocator handle and fetch other required handles to +`VkPhysicalDevice`, `VkDevice` etc. every time using this function. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocatorInfo* VMA_NOT_NULL pAllocatorInfo); + +/** +PhysicalDeviceProperties are fetched from physicalDevice by the allocator. +You can access it here, without fetching it again on your own. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( + VmaAllocator VMA_NOT_NULL allocator, + const VkPhysicalDeviceProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceProperties); + +/** +PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. +You can access it here, without fetching it again on your own. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + const VkPhysicalDeviceMemoryProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceMemoryProperties); + +/** +\brief Given Memory Type Index, returns Property Flags of this memory type. + +This is just a convenience function. Same information can be obtained using +vmaGetMemoryProperties(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeIndex, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); + +/** \brief Sets index of the current frame. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t frameIndex); + +/** @} */ + +/** +\addtogroup group_stats +@{ +*/ + +/** \brief Retrieves statistics from current state of the Allocator. + +This function is called "calculate" not "get" because it has to traverse all +internal data structures, so it may be quite slow. Use it for debugging purposes. +For faster but more brief statistics suitable to be called every frame or every allocation, +use vmaGetHeapBudgets(). + +Note that when using allocator from multiple threads, returned information may immediately +become outdated. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaTotalStatistics* VMA_NOT_NULL pStats); + +/** \brief Retrieves information about current memory usage and budget for all memory heaps. + +\param allocator +\param[out] pBudgets Must point to array with number of elements at least equal to number of memory heaps in physical device used. + +This function is called "get" not "calculate" because it is very fast, suitable to be called +every frame or every allocation. For more detailed statistics use vmaCalculateStatistics(). + +Note that when using allocator from multiple threads, returned information may immediately +become outdated. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( + VmaAllocator VMA_NOT_NULL allocator, + VmaBudget* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pBudgets); + +/** @} */ + +/** +\addtogroup group_alloc +@{ +*/ + +/** +\brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. + +This algorithm tries to find a memory type that: + +- Is allowed by memoryTypeBits. +- Contains all the flags from pAllocationCreateInfo->requiredFlags. +- Matches intended usage. +- Has as many flags from pAllocationCreateInfo->preferredFlags as possible. + +\return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result +from this function or any other allocating function probably means that your +device doesn't support any memory type with requested features for the specific +type of resource you want to use it for. Please check parameters of your +resource, like image layout (OPTIMAL versus LINEAR) or mip level count. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + +/** +\brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. + +It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. +It internally creates a temporary, dummy buffer that never has memory bound. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + +/** +\brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. + +It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. +It internally creates a temporary, dummy image that never has memory bound. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( + VmaAllocator VMA_NOT_NULL allocator, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + +/** \brief Allocates Vulkan device memory and creates #VmaPool object. + +\param allocator Allocator object. +\param pCreateInfo Parameters of pool to create. +\param[out] pPool Handle to created pool. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( + VmaAllocator VMA_NOT_NULL allocator, + const VmaPoolCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaPool VMA_NULLABLE* VMA_NOT_NULL pPool); + +/** \brief Destroys #VmaPool object and frees Vulkan device memory. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NULLABLE pool); + +/** @} */ + +/** +\addtogroup group_stats +@{ +*/ + +/** \brief Retrieves statistics of existing #VmaPool object. + +\param allocator Allocator object. +\param pool Pool object. +\param[out] pPoolStats Statistics of specified pool. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + VmaStatistics* VMA_NOT_NULL pPoolStats); + +/** \brief Retrieves detailed statistics of existing #VmaPool object. + +\param allocator Allocator object. +\param pool Pool object. +\param[out] pPoolStats Statistics of specified pool. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + VmaDetailedStatistics* VMA_NOT_NULL pPoolStats); + +/** @} */ + +/** +\addtogroup group_alloc +@{ +*/ + +/** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions. + +Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, +`VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is +`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). + +Possible return values: + +- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool. +- `VK_SUCCESS` - corruption detection has been performed and succeeded. +- `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. + `VMA_ASSERT` is also fired in that case. +- Other value: Error returned by Vulkan, e.g. memory mapping failure. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool); + +/** \brief Retrieves name of a custom pool. + +After the call `ppName` is either null or points to an internally-owned null-terminated string +containing name of the pool that was previously set. The pointer becomes invalid when the pool is +destroyed or its name is changed using vmaSetPoolName(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + const char* VMA_NULLABLE* VMA_NOT_NULL ppName); + +/** \brief Sets name of a custom pool. + +`pName` can be either null or pointer to a null-terminated string with new name for the pool. +Function makes internal copy of the string, so it can be changed or freed immediately after this call. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + const char* VMA_NULLABLE pName); + +/** \brief General purpose memory allocation. + +\param allocator +\param pVkMemoryRequirements +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + +You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). + +It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), +vmaCreateBuffer(), vmaCreateImage() instead whenever possible. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( + VmaAllocator VMA_NOT_NULL allocator, + const VkMemoryRequirements* VMA_NOT_NULL pVkMemoryRequirements, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief General purpose memory allocation for multiple allocation objects at once. + +\param allocator Allocator object. +\param pVkMemoryRequirements Memory requirements for each allocation. +\param pCreateInfo Creation parameters for each allocation. +\param allocationCount Number of allocations to make. +\param[out] pAllocations Pointer to array that will be filled with handles to created allocations. +\param[out] pAllocationInfo Optional. Pointer to array that will be filled with parameters of created allocations. + +You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). + +Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. +It is just a general purpose allocation function able to make multiple allocations at once. +It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times. + +All allocations are made using same parameters. All of them are created out of the same memory pool and type. +If any allocation fails, all allocations already made within this function call are also freed, so that when +returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( + VmaAllocator VMA_NOT_NULL allocator, + const VkMemoryRequirements* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pVkMemoryRequirements, + const VmaAllocationCreateInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pCreateInfo, + size_t allocationCount, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations, + VmaAllocationInfo* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationInfo); + +/** \brief Allocates memory suitable for given `VkBuffer`. + +\param allocator +\param buffer +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + +It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindBufferMemory(). + +This is a special-purpose function. In most cases you should use vmaCreateBuffer(). + +You must free the allocation using vmaFreeMemory() when no longer needed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Allocates memory suitable for given `VkImage`. + +\param allocator +\param image +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + +It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindImageMemory(). + +This is a special-purpose function. In most cases you should use vmaCreateImage(). + +You must free the allocation using vmaFreeMemory() when no longer needed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). + +Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( + VmaAllocator VMA_NOT_NULL allocator, + const VmaAllocation VMA_NULLABLE allocation); + +/** \brief Frees memory and destroys multiple allocations. + +Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. +It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(), +vmaAllocateMemoryPages() and other functions. +It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times. + +Allocations in `pAllocations` array can come from any memory pools and types. +Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( + VmaAllocator VMA_NOT_NULL allocator, + size_t allocationCount, + const VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations); + +/** \brief Returns current information about specified allocation. + +Current paramteres of given allocation are returned in `pAllocationInfo`. + +Although this function doesn't lock any mutex, so it should be quite efficient, +you should avoid calling it too often. +You can retrieve same VmaAllocationInfo structure while creating your resource, from function +vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change +(e.g. due to defragmentation). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo); + +/** \brief Sets pUserData in given allocation to new value. + +The value of pointer `pUserData` is copied to allocation's `pUserData`. +It is opaque, so you can use it however you want - e.g. +as a pointer, ordinal number or some handle to you own data. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + void* VMA_NULLABLE pUserData); + +/** \brief Sets pName in given allocation to new value. + +`pName` must be either null, or pointer to a null-terminated string. The function +makes local copy of the string and sets it as allocation's `pName`. String +passed as pName doesn't need to be valid for whole lifetime of the allocation - +you can free it after this call. String previously pointed by allocation's +`pName` is freed from memory. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const char* VMA_NULLABLE pName); + +/** +\brief Given an allocation, returns Property Flags of its memory type. + +This is just a convenience function. Same information can be obtained using +vmaGetAllocationInfo() + vmaGetMemoryProperties(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); + +/** \brief Maps memory represented by given allocation and returns pointer to it. + +Maps memory represented by given allocation to make it accessible to CPU code. +When succeeded, `*ppData` contains pointer to first byte of this memory. + +\warning +If the allocation is part of a bigger `VkDeviceMemory` block, returned pointer is +correctly offsetted to the beginning of region assigned to this particular allocation. +Unlike the result of `vkMapMemory`, it points to the allocation, not to the beginning of the whole block. +You should not add VmaAllocationInfo::offset to it! + +Mapping is internally reference-counted and synchronized, so despite raw Vulkan +function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` +multiple times simultaneously, it is safe to call this function on allocations +assigned to the same memory block. Actual Vulkan memory will be mapped on first +mapping and unmapped on last unmapping. + +If the function succeeded, you must call vmaUnmapMemory() to unmap the +allocation when mapping is no longer needed or before freeing the allocation, at +the latest. + +It also safe to call this function multiple times on the same allocation. You +must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). + +It is also safe to call this function on allocation created with +#VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. +You must still call vmaUnmapMemory() same number of times as you called +vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the +"0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. + +This function fails when used on allocation made in memory type that is not +`HOST_VISIBLE`. + +This function doesn't automatically flush or invalidate caches. +If the allocation is made from a memory types that is not `HOST_COHERENT`, +you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + void* VMA_NULLABLE* VMA_NOT_NULL ppData); + +/** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). + +For details, see description of vmaMapMemory(). + +This function doesn't automatically flush or invalidate caches. +If the allocation is made from a memory types that is not `HOST_COHERENT`, +you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation); + +/** \brief Flushes memory of given allocation. + +Calls `vkFlushMappedMemoryRanges()` for memory associated with given range of given allocation. +It needs to be called after writing to a mapped memory for memory types that are not `HOST_COHERENT`. +Unmap operation doesn't do that automatically. + +- `offset` must be relative to the beginning of allocation. +- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. +- `offset` and `size` don't have to be aligned. + They are internally rounded down/up to multiply of `nonCoherentAtomSize`. +- If `size` is 0, this call is ignored. +- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, + this call is ignored. + +Warning! `offset` and `size` are relative to the contents of given `allocation`. +If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. +Do not pass allocation's offset as `offset`!!! + +This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize offset, + VkDeviceSize size); + +/** \brief Invalidates memory of given allocation. + +Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range of given allocation. +It needs to be called before reading from a mapped memory for memory types that are not `HOST_COHERENT`. +Map operation doesn't do that automatically. + +- `offset` must be relative to the beginning of allocation. +- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. +- `offset` and `size` don't have to be aligned. + They are internally rounded down/up to multiply of `nonCoherentAtomSize`. +- If `size` is 0, this call is ignored. +- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, + this call is ignored. + +Warning! `offset` and `size` are relative to the contents of given `allocation`. +If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. +Do not pass allocation's offset as `offset`!!! + +This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if +it is called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize offset, + VkDeviceSize size); + +/** \brief Flushes memory of given set of allocations. + +Calls `vkFlushMappedMemoryRanges()` for memory associated with given ranges of given allocations. +For more information, see documentation of vmaFlushAllocation(). + +\param allocator +\param allocationCount +\param allocations +\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all ofsets are zero. +\param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. + +This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t allocationCount, + const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); + +/** \brief Invalidates memory of given set of allocations. + +Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given ranges of given allocations. +For more information, see documentation of vmaInvalidateAllocation(). + +\param allocator +\param allocationCount +\param allocations +\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all ofsets are zero. +\param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. + +This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t allocationCount, + const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); + +/** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. + +\param allocator +\param memoryTypeBits Bit mask, where each bit set means that a memory type with that index should be checked. + +Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, +`VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are +`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). + +Possible return values: + +- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types. +- `VK_SUCCESS` - corruption detection has been performed and succeeded. +- `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. + `VMA_ASSERT` is also fired in that case. +- Other value: Error returned by Vulkan, e.g. memory mapping failure. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeBits); + +/** \brief Begins defragmentation process. + +\param allocator Allocator object. +\param pInfo Structure filled with parameters of defragmentation. +\param[out] pContext Context object that must be passed to vmaEndDefragmentation() to finish defragmentation. +\returns +- `VK_SUCCESS` if defragmentation can begin. +- `VK_ERROR_FEATURE_NOT_PRESENT` if defragmentation is not supported. + +For more information about defragmentation, see documentation chapter: +[Defragmentation](@ref defragmentation). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( + VmaAllocator VMA_NOT_NULL allocator, + const VmaDefragmentationInfo* VMA_NOT_NULL pInfo, + VmaDefragmentationContext VMA_NULLABLE* VMA_NOT_NULL pContext); + +/** \brief Ends defragmentation process. + +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param[out] pStats Optional stats for the defragmentation. Can be null. + +Use this function to finish defragmentation started by vmaBeginDefragmentation(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationStats* VMA_NULLABLE pStats); + +/** \brief Starts single defragmentation pass. + +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param[out] pPassInfo Computed informations for current pass. +\returns +- `VK_SUCCESS` if no more moves are possible. Then you can omit call to vmaEndDefragmentationPass() and simply end whole defragmentation. +- `VK_INCOMPLETE` if there are pending moves returned in `pPassInfo`. You need to perform them, call vmaEndDefragmentationPass(), + and then preferably try another pass with vmaBeginDefragmentationPass(). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); + +/** \brief Ends single defragmentation pass. + +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param pPassInfo Computed informations for current pass filled by vmaBeginDefragmentationPass() and possibly modified by you. + +Returns `VK_SUCCESS` if no more moves are possible or `VK_INCOMPLETE` if more defragmentations are possible. + +Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`. +After this call: + +- Allocations at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY + (which is the default) will be pointing to the new destination place. +- Allocation at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY + will be freed. + +If no more moves are possible you can end whole defragmentation. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); + +/** \brief Binds buffer to allocation. + +Binds specified buffer to region of memory represented by specified allocation. +Gets `VkDeviceMemory` handle and offset from the allocation. +If you want to create a buffer, allocate memory for it and bind them together separately, +you should use this function for binding instead of standard `vkBindBufferMemory()`, +because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple +allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously +(which is illegal in Vulkan). + +It is recommended to use function vmaCreateBuffer() instead of this one. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer); + +/** \brief Binds buffer to allocation with additional parameters. + +\param allocator +\param allocation +\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. +\param buffer +\param pNext A chain of structures to be attached to `VkBindBufferMemoryInfoKHR` structure used internally. Normally it should be null. + +This function is similar to vmaBindBufferMemory(), but it provides additional parameters. + +If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag +or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, + const void* VMA_NULLABLE pNext); + +/** \brief Binds image to allocation. + +Binds specified image to region of memory represented by specified allocation. +Gets `VkDeviceMemory` handle and offset from the allocation. +If you want to create an image, allocate memory for it and bind them together separately, +you should use this function for binding instead of standard `vkBindImageMemory()`, +because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple +allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously +(which is illegal in Vulkan). + +It is recommended to use function vmaCreateImage() instead of this one. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image); + +/** \brief Binds image to allocation with additional parameters. + +\param allocator +\param allocation +\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. +\param image +\param pNext A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null. + +This function is similar to vmaBindImageMemory(), but it provides additional parameters. + +If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag +or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, + const void* VMA_NULLABLE pNext); + +/** \brief Creates a new `VkBuffer`, allocates and binds memory for it. + +\param allocator +\param pBufferCreateInfo +\param pAllocationCreateInfo +\param[out] pBuffer Buffer that was created. +\param[out] pAllocation Allocation that was created. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + +This function automatically: + +-# Creates buffer. +-# Allocates appropriate memory for it. +-# Binds the buffer with the memory. + +If any of these operations fail, buffer and allocation are not created, +returned value is negative error code, `*pBuffer` and `*pAllocation` are null. + +If the function succeeded, you must destroy both buffer and allocation when you +no longer need them using either convenience function vmaDestroyBuffer() or +separately, using `vkDestroyBuffer()` and vmaFreeMemory(). + +If #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, +VK_KHR_dedicated_allocation extension is used internally to query driver whether +it requires or prefers the new buffer to have dedicated allocation. If yes, +and if dedicated allocation is possible +(#VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated +allocation for this buffer, just like when using +#VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + +\note This function creates a new `VkBuffer`. Sub-allocation of parts of one large buffer, +although recommended as a good practice, is out of scope of this library and could be implemented +by the user as a higher-level logic on top of VMA. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Creates a buffer with additional minimum alignment. + +Similar to vmaCreateBuffer() but provides additional parameter `minAlignment` which allows to specify custom, +minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g. +for interop with OpenGL. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkDeviceSize minAlignment, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Creates a new `VkBuffer`, binds already created memory for it. + +\param allocator +\param allocation Allocation that provides memory to be used for binding new buffer to it. +\param pBufferCreateInfo +\param[out] pBuffer Buffer that was created. + +This function automatically: + +-# Creates buffer. +-# Binds the buffer with the supplied memory. + +If any of these operations fail, buffer is not created, +returned value is negative error code and `*pBuffer` is null. + +If the function succeeded, you must destroy the buffer when you +no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding +allocation you can use convenience function vmaDestroyBuffer(). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); + +/** \brief Destroys Vulkan buffer and frees allocated memory. + +This is just a convenience function equivalent to: + +\code +vkDestroyBuffer(device, buffer, allocationCallbacks); +vmaFreeMemory(allocator, allocation); +\endcode + +It it safe to pass null as buffer and/or allocation. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer, + VmaAllocation VMA_NULLABLE allocation); + +/// Function similar to vmaCreateBuffer(). +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( + VmaAllocator VMA_NOT_NULL allocator, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/// Function similar to vmaCreateAliasingBuffer(). +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); + +/** \brief Destroys Vulkan image and frees allocated memory. + +This is just a convenience function equivalent to: + +\code +vkDestroyImage(device, image, allocationCallbacks); +vmaFreeMemory(allocator, allocation); +\endcode + +It it safe to pass null as image and/or allocation. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NULLABLE_NON_DISPATCHABLE image, + VmaAllocation VMA_NULLABLE allocation); + +/** @} */ + +/** +\addtogroup group_virtual +@{ +*/ + +/** \brief Creates new #VmaVirtualBlock object. + +\param pCreateInfo Parameters for creation. +\param[out] pVirtualBlock Returned virtual block object or `VMA_NULL` if creation failed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( + const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock); + +/** \brief Destroys #VmaVirtualBlock object. + +Please note that you should consciously handle virtual allocations that could remain unfreed in the block. +You should either free them individually using vmaVirtualFree() or call vmaClearVirtualBlock() +if you are sure this is what you want. If you do neither, an assert is called. + +If you keep pointers to some additional metadata associated with your virtual allocations in their `pUserData`, +don't forget to free them. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock( + VmaVirtualBlock VMA_NULLABLE virtualBlock); + +/** \brief Returns true of the #VmaVirtualBlock is empty - contains 0 virtual allocations and has all its space available for new allocations. +*/ +VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty( + VmaVirtualBlock VMA_NOT_NULL virtualBlock); + +/** \brief Returns information about a specific virtual allocation within a virtual block, like its size and `pUserData` pointer. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo); + +/** \brief Allocates new virtual allocation inside given #VmaVirtualBlock. + +If the allocation fails due to not enough free space available, `VK_ERROR_OUT_OF_DEVICE_MEMORY` is returned +(despite the function doesn't ever allocate actual GPU memory). +`pAllocation` is then set to `VK_NULL_HANDLE` and `pOffset`, if not null, it set to `UINT64_MAX`. + +\param virtualBlock Virtual block +\param pCreateInfo Parameters for the allocation +\param[out] pAllocation Returned handle of the new allocation +\param[out] pOffset Returned offset of the new allocation. Optional, can be null. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + const VmaVirtualAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pAllocation, + VkDeviceSize* VMA_NULLABLE pOffset); + +/** \brief Frees virtual allocation inside given #VmaVirtualBlock. + +It is correct to call this function with `allocation == VK_NULL_HANDLE` - it does nothing. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation); + +/** \brief Frees all virtual allocations inside given #VmaVirtualBlock. + +You must either call this function or free each virtual allocation individually with vmaVirtualFree() +before destroying a virtual block. Otherwise, an assert is called. + +If you keep pointer to some additional metadata associated with your virtual allocation in its `pUserData`, +don't forget to free it as well. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock( + VmaVirtualBlock VMA_NOT_NULL virtualBlock); + +/** \brief Changes custom pointer associated with given virtual allocation. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, + void* VMA_NULLABLE pUserData); + +/** \brief Calculates and returns statistics about virtual allocations and memory usage in given #VmaVirtualBlock. + +This function is fast to call. For more detailed statistics, see vmaCalculateVirtualBlockStatistics(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaStatistics* VMA_NOT_NULL pStats); + +/** \brief Calculates and returns detailed statistics about virtual allocations and memory usage in given #VmaVirtualBlock. + +This function is slow to call. Use for debugging purposes. +For less detailed statistics, see vmaGetVirtualBlockStatistics(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaDetailedStatistics* VMA_NOT_NULL pStats); + +/** @} */ + +#if VMA_STATS_STRING_ENABLED +/** +\addtogroup group_stats +@{ +*/ + +/** \brief Builds and returns a null-terminated string in JSON format with information about given #VmaVirtualBlock. +\param virtualBlock Virtual block. +\param[out] ppStatsString Returned string. +\param detailedMap Pass `VK_FALSE` to only obtain statistics as returned by vmaCalculateVirtualBlockStatistics(). Pass `VK_TRUE` to also obtain full list of allocations and free spaces. + +Returned string must be freed using vmaFreeVirtualBlockStatsString(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, + VkBool32 detailedMap); + +/// Frees a string returned by vmaBuildVirtualBlockStatsString(). +VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE pStatsString); + +/** \brief Builds and returns statistics as a null-terminated string in JSON format. +\param allocator +\param[out] ppStatsString Must be freed using vmaFreeStatsString() function. +\param detailedMap +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( + VmaAllocator VMA_NOT_NULL allocator, + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, + VkBool32 detailedMap); + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( + VmaAllocator VMA_NOT_NULL allocator, + char* VMA_NULLABLE pStatsString); + +/** @} */ + +#endif // VMA_STATS_STRING_ENABLED + +#endif // _VMA_FUNCTION_HEADERS + +#ifdef __cplusplus +} +#endif + +#endif // AMD_VULKAN_MEMORY_ALLOCATOR_H + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION +// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// For Visual Studio IntelliSense. +#if defined(__cplusplus) && defined(__INTELLISENSE__) +#define VMA_IMPLEMENTATION +#endif + +#ifdef VMA_IMPLEMENTATION +#undef VMA_IMPLEMENTATION + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #include // For functions like __popcnt, _BitScanForward etc. +#endif +#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 + #include // For std::popcount +#endif + +/******************************************************************************* +CONFIGURATION SECTION + +Define some of these macros before each #include of this header or change them +here if you need other then default behavior depending on your environment. +*/ +#ifndef _VMA_CONFIGURATION + +/* +Define this macro to 1 to make the library fetch pointers to Vulkan functions +internally, like: + + vulkanFunctions.vkAllocateMemory = &vkAllocateMemory; +*/ +#if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES) + #define VMA_STATIC_VULKAN_FUNCTIONS 1 +#endif + +/* +Define this macro to 1 to make the library fetch pointers to Vulkan functions +internally, like: + + vulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkGetDeviceProcAddr(device, "vkAllocateMemory"); + +To use this feature in new versions of VMA you now have to pass +VmaVulkanFunctions::vkGetInstanceProcAddr and vkGetDeviceProcAddr as +VmaAllocatorCreateInfo::pVulkanFunctions. Other members can be null. +*/ +#if !defined(VMA_DYNAMIC_VULKAN_FUNCTIONS) + #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#endif + +#ifndef VMA_USE_STL_SHARED_MUTEX + // Compiler conforms to C++17. + #if __cplusplus >= 201703L + #define VMA_USE_STL_SHARED_MUTEX 1 + // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus + // Otherwise it is always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2. + #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L + #define VMA_USE_STL_SHARED_MUTEX 1 + #else + #define VMA_USE_STL_SHARED_MUTEX 0 + #endif +#endif + +/* +Define this macro to include custom header files without having to edit this file directly, e.g.: + + // Inside of "my_vma_configuration_user_includes.h": + + #include "my_custom_assert.h" // for MY_CUSTOM_ASSERT + #include "my_custom_min.h" // for my_custom_min + #include + #include + + // Inside a different file, which includes "vk_mem_alloc.h": + + #define VMA_CONFIGURATION_USER_INCLUDES_H "my_vma_configuration_user_includes.h" + #define VMA_ASSERT(expr) MY_CUSTOM_ASSERT(expr) + #define VMA_MIN(v1, v2) (my_custom_min(v1, v2)) + #include "vk_mem_alloc.h" + ... + +The following headers are used in this CONFIGURATION section only, so feel free to +remove them if not needed. +*/ +#if !defined(VMA_CONFIGURATION_USER_INCLUDES_H) + #include // for assert + #include // for min, max + #include +#else + #include VMA_CONFIGURATION_USER_INCLUDES_H +#endif + +#ifndef VMA_NULL + // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0. + #define VMA_NULL nullptr +#endif + +#if defined(__ANDROID_API__) && (__ANDROID_API__ < 16) +#include +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + // alignment must be >= sizeof(void*) + if(alignment < sizeof(void*)) + { + alignment = sizeof(void*); + } + + return memalign(alignment, size); +} +#elif defined(__APPLE__) || defined(__ANDROID__) || (defined(__linux__) && defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC)) +#include + +#if defined(__APPLE__) +#include +#endif + +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + // Unfortunately, aligned_alloc causes VMA to crash due to it returning null pointers. (At least under 11.4) + // Therefore, for now disable this specific exception until a proper solution is found. + //#if defined(__APPLE__) && (defined(MAC_OS_X_VERSION_10_16) || defined(__IPHONE_14_0)) + //#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 + // // For C++14, usr/include/malloc/_malloc.h declares aligned_alloc()) only + // // with the MacOSX11.0 SDK in Xcode 12 (which is what adds + // // MAC_OS_X_VERSION_10_16), even though the function is marked + // // availabe for 10.15. That is why the preprocessor checks for 10.16 but + // // the __builtin_available checks for 10.15. + // // People who use C++17 could call aligned_alloc with the 10.15 SDK already. + // if (__builtin_available(macOS 10.15, iOS 13, *)) + // return aligned_alloc(alignment, size); + //#endif + //#endif + + // alignment must be >= sizeof(void*) + if(alignment < sizeof(void*)) + { + alignment = sizeof(void*); + } + + void *pointer; + if(posix_memalign(&pointer, alignment, size) == 0) + return pointer; + return VMA_NULL; +} +#elif defined(_WIN32) +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + return _aligned_malloc(size, alignment); +} +#else +static void* vma_aligned_alloc(size_t alignment, size_t size) +{ + return aligned_alloc(alignment, size); +} +#endif + +#if defined(_WIN32) +static void vma_aligned_free(void* ptr) +{ + _aligned_free(ptr); +} +#else +static void vma_aligned_free(void* VMA_NULLABLE ptr) +{ + free(ptr); +} +#endif + +// If your compiler is not compatible with C++11 and definition of +// aligned_alloc() function is missing, uncommeting following line may help: + +//#include + +// Normal assert to check for programmer's errors, especially in Debug configuration. +#ifndef VMA_ASSERT + #ifdef NDEBUG + #define VMA_ASSERT(expr) + #else + #define VMA_ASSERT(expr) assert(expr) + #endif +#endif + +// Assert that will be called very often, like inside data structures e.g. operator[]. +// Making it non-empty can make program slow. +#ifndef VMA_HEAVY_ASSERT + #ifdef NDEBUG + #define VMA_HEAVY_ASSERT(expr) + #else + #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) + #endif +#endif + +#ifndef VMA_ALIGN_OF + #define VMA_ALIGN_OF(type) (__alignof(type)) +#endif + +#ifndef VMA_SYSTEM_ALIGNED_MALLOC + #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size)) +#endif + +#ifndef VMA_SYSTEM_ALIGNED_FREE + // VMA_SYSTEM_FREE is the old name, but might have been defined by the user + #if defined(VMA_SYSTEM_FREE) + #define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr) + #else + #define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr) + #endif +#endif + +#ifndef VMA_COUNT_BITS_SET + // Returns number of bits set to 1 in (v) + #define VMA_COUNT_BITS_SET(v) VmaCountBitsSet(v) +#endif + +#ifndef VMA_BITSCAN_LSB + // Scans integer for index of first nonzero value from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX + #define VMA_BITSCAN_LSB(mask) VmaBitScanLSB(mask) +#endif + +#ifndef VMA_BITSCAN_MSB + // Scans integer for index of first nonzero value from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX + #define VMA_BITSCAN_MSB(mask) VmaBitScanMSB(mask) +#endif + +#ifndef VMA_MIN + #define VMA_MIN(v1, v2) ((std::min)((v1), (v2))) +#endif + +#ifndef VMA_MAX + #define VMA_MAX(v1, v2) ((std::max)((v1), (v2))) +#endif + +#ifndef VMA_SWAP + #define VMA_SWAP(v1, v2) std::swap((v1), (v2)) +#endif + +#ifndef VMA_SORT + #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) +#endif + +#ifndef VMA_DEBUG_LOG + #define VMA_DEBUG_LOG(format, ...) + /* + #define VMA_DEBUG_LOG(format, ...) do { \ + printf(format, __VA_ARGS__); \ + printf("\n"); \ + } while(false) + */ +#endif + +// Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString. +#if VMA_STATS_STRING_ENABLED + static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num) + { + snprintf(outStr, strLen, "%u", static_cast(num)); + } + static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num) + { + snprintf(outStr, strLen, "%llu", static_cast(num)); + } + static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr) + { + snprintf(outStr, strLen, "%p", ptr); + } +#endif + +#ifndef VMA_MUTEX + class VmaMutex + { + public: + void Lock() { m_Mutex.lock(); } + void Unlock() { m_Mutex.unlock(); } + bool TryLock() { return m_Mutex.try_lock(); } + private: + std::mutex m_Mutex; + }; + #define VMA_MUTEX VmaMutex +#endif + +// Read-write mutex, where "read" is shared access, "write" is exclusive access. +#ifndef VMA_RW_MUTEX + #if VMA_USE_STL_SHARED_MUTEX + // Use std::shared_mutex from C++17. + #include + class VmaRWMutex + { + public: + void LockRead() { m_Mutex.lock_shared(); } + void UnlockRead() { m_Mutex.unlock_shared(); } + bool TryLockRead() { return m_Mutex.try_lock_shared(); } + void LockWrite() { m_Mutex.lock(); } + void UnlockWrite() { m_Mutex.unlock(); } + bool TryLockWrite() { return m_Mutex.try_lock(); } + private: + std::shared_mutex m_Mutex; + }; + #define VMA_RW_MUTEX VmaRWMutex + #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600 + // Use SRWLOCK from WinAPI. + // Minimum supported client = Windows Vista, server = Windows Server 2008. + class VmaRWMutex + { + public: + VmaRWMutex() { InitializeSRWLock(&m_Lock); } + void LockRead() { AcquireSRWLockShared(&m_Lock); } + void UnlockRead() { ReleaseSRWLockShared(&m_Lock); } + bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; } + void LockWrite() { AcquireSRWLockExclusive(&m_Lock); } + void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); } + bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; } + private: + SRWLOCK m_Lock; + }; + #define VMA_RW_MUTEX VmaRWMutex + #else + // Less efficient fallback: Use normal mutex. + class VmaRWMutex + { + public: + void LockRead() { m_Mutex.Lock(); } + void UnlockRead() { m_Mutex.Unlock(); } + bool TryLockRead() { return m_Mutex.TryLock(); } + void LockWrite() { m_Mutex.Lock(); } + void UnlockWrite() { m_Mutex.Unlock(); } + bool TryLockWrite() { return m_Mutex.TryLock(); } + private: + VMA_MUTEX m_Mutex; + }; + #define VMA_RW_MUTEX VmaRWMutex + #endif // #if VMA_USE_STL_SHARED_MUTEX +#endif // #ifndef VMA_RW_MUTEX + +/* +If providing your own implementation, you need to implement a subset of std::atomic. +*/ +#ifndef VMA_ATOMIC_UINT32 + #include + #define VMA_ATOMIC_UINT32 std::atomic +#endif + +#ifndef VMA_ATOMIC_UINT64 + #include + #define VMA_ATOMIC_UINT64 std::atomic +#endif + +#ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY + /** + Every allocation will have its own memory block. + Define to 1 for debugging purposes only. + */ + #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) +#endif + +#ifndef VMA_MIN_ALIGNMENT + /** + Minimum alignment of all allocations, in bytes. + Set to more than 1 for debugging purposes. Must be power of two. + */ + #ifdef VMA_DEBUG_ALIGNMENT // Old name + #define VMA_MIN_ALIGNMENT VMA_DEBUG_ALIGNMENT + #else + #define VMA_MIN_ALIGNMENT (1) + #endif +#endif + +#ifndef VMA_DEBUG_MARGIN + /** + Minimum margin after every allocation, in bytes. + Set nonzero for debugging purposes only. + */ + #define VMA_DEBUG_MARGIN (0) +#endif + +#ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS + /** + Define this macro to 1 to automatically fill new allocations and destroyed + allocations with some bit pattern. + */ + #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0) +#endif + +#ifndef VMA_DEBUG_DETECT_CORRUPTION + /** + Define this macro to 1 together with non-zero value of VMA_DEBUG_MARGIN to + enable writing magic value to the margin after every allocation and + validating it, so that memory corruptions (out-of-bounds writes) are detected. + */ + #define VMA_DEBUG_DETECT_CORRUPTION (0) +#endif + +#ifndef VMA_DEBUG_GLOBAL_MUTEX + /** + Set this to 1 for debugging purposes only, to enable single mutex protecting all + entry calls to the library. Can be useful for debugging multithreading issues. + */ + #define VMA_DEBUG_GLOBAL_MUTEX (0) +#endif + +#ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY + /** + Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity. + Set to more than 1 for debugging purposes only. Must be power of two. + */ + #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) +#endif + +#ifndef VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT + /* + Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount + and return error instead of leaving up to Vulkan implementation what to do in such cases. + */ + #define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0) +#endif + +#ifndef VMA_SMALL_HEAP_MAX_SIZE + /// Maximum size of a memory heap in Vulkan to consider it "small". + #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) +#endif + +#ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE + /// Default size of a block allocated as single VkDeviceMemory from a "large" heap. + #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) +#endif + +/* +Mapping hysteresis is a logic that launches when vmaMapMemory/vmaUnmapMemory is called +or a persistently mapped allocation is created and destroyed several times in a row. +It keeps additional +1 mapping of a device memory block to prevent calling actual +vkMapMemory/vkUnmapMemory too many times, which may improve performance and help +tools like RenderDOc. +*/ +#ifndef VMA_MAPPING_HYSTERESIS_ENABLED + #define VMA_MAPPING_HYSTERESIS_ENABLED 1 +#endif + +#ifndef VMA_CLASS_NO_COPY + #define VMA_CLASS_NO_COPY(className) \ + private: \ + className(const className&) = delete; \ + className& operator=(const className&) = delete; +#endif + +#define VMA_VALIDATE(cond) do { if(!(cond)) { \ + VMA_ASSERT(0 && "Validation failed: " #cond); \ + return false; \ + } } while(false) + +/******************************************************************************* +END OF CONFIGURATION +*/ +#endif // _VMA_CONFIGURATION + + +static const uint8_t VMA_ALLOCATION_FILL_PATTERN_CREATED = 0xDC; +static const uint8_t VMA_ALLOCATION_FILL_PATTERN_DESTROYED = 0xEF; +// Decimal 2139416166, float NaN, little-endian binary 66 E6 84 7F. +static const uint32_t VMA_CORRUPTION_DETECTION_MAGIC_VALUE = 0x7F84E666; + +// Copy of some Vulkan definitions so we don't need to check their existence just to handle few constants. +static const uint32_t VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY = 0x00000040; +static const uint32_t VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY = 0x00000080; +static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000; +static const uint32_t VK_IMAGE_CREATE_DISJOINT_BIT_COPY = 0x00000200; +static const int32_t VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT_COPY = 1000158000; +static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u; +static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32; +static const uint32_t VMA_VENDOR_ID_AMD = 4098; + +// This one is tricky. Vulkan specification defines this code as available since +// Vulkan 1.0, but doesn't actually define it in Vulkan SDK earlier than 1.2.131. +// See pull request #207. +#define VK_ERROR_UNKNOWN_COPY ((VkResult)-13) + + +#if VMA_STATS_STRING_ENABLED +// Correspond to values of enum VmaSuballocationType. +static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = +{ + "FREE", + "UNKNOWN", + "BUFFER", + "IMAGE_UNKNOWN", + "IMAGE_LINEAR", + "IMAGE_OPTIMAL", +}; +#endif + +static VkAllocationCallbacks VmaEmptyAllocationCallbacks = + { VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL }; + + +#ifndef _VMA_ENUM_DECLARATIONS + +enum VmaSuballocationType +{ + VMA_SUBALLOCATION_TYPE_FREE = 0, + VMA_SUBALLOCATION_TYPE_UNKNOWN = 1, + VMA_SUBALLOCATION_TYPE_BUFFER = 2, + VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3, + VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4, + VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5, + VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF +}; + +enum VMA_CACHE_OPERATION +{ + VMA_CACHE_FLUSH, + VMA_CACHE_INVALIDATE +}; + +enum class VmaAllocationRequestType +{ + Normal, + TLSF, + // Used by "Linear" algorithm. + UpperAddress, + EndOf1st, + EndOf2nd, +}; + +#endif // _VMA_ENUM_DECLARATIONS + +#ifndef _VMA_FORWARD_DECLARATIONS +// Opaque handle used by allocation algorithms to identify single allocation in any conforming way. +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaAllocHandle); + +struct VmaMutexLock; +struct VmaMutexLockRead; +struct VmaMutexLockWrite; + +template +struct AtomicTransactionalIncrement; + +template +struct VmaStlAllocator; + +template +class VmaVector; + +template +class VmaSmallVector; + +template +class VmaPoolAllocator; + +template +struct VmaListItem; + +template +class VmaRawList; + +template +class VmaList; + +template +class VmaIntrusiveLinkedList; + +// Unused in this version +#if 0 +template +struct VmaPair; +template +struct VmaPairFirstLess; + +template +class VmaMap; +#endif + +#if VMA_STATS_STRING_ENABLED +class VmaStringBuilder; +class VmaJsonWriter; +#endif + +class VmaDeviceMemoryBlock; + +struct VmaDedicatedAllocationListItemTraits; +class VmaDedicatedAllocationList; + +struct VmaSuballocation; +struct VmaSuballocationOffsetLess; +struct VmaSuballocationOffsetGreater; +struct VmaSuballocationItemSizeLess; + +typedef VmaList> VmaSuballocationList; + +struct VmaAllocationRequest; + +class VmaBlockMetadata; +class VmaBlockMetadata_Linear; +class VmaBlockMetadata_TLSF; + +class VmaBlockVector; + +struct VmaPoolListItemTraits; + +struct VmaCurrentBudgetData; + +class VmaAllocationObjectAllocator; + +#endif // _VMA_FORWARD_DECLARATIONS + + +#ifndef _VMA_FUNCTIONS + +/* +Returns number of bits set to 1 in (v). + +On specific platforms and compilers you can use instrinsics like: + +Visual Studio: + return __popcnt(v); +GCC, Clang: + return static_cast(__builtin_popcount(v)); + +Define macro VMA_COUNT_BITS_SET to provide your optimized implementation. +But you need to check in runtime whether user's CPU supports these, as some old processors don't. +*/ +static inline uint32_t VmaCountBitsSet(uint32_t v) +{ +#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 + return std::popcount(v); +#else + uint32_t c = v - ((v >> 1) & 0x55555555); + c = ((c >> 2) & 0x33333333) + (c & 0x33333333); + c = ((c >> 4) + c) & 0x0F0F0F0F; + c = ((c >> 8) + c) & 0x00FF00FF; + c = ((c >> 16) + c) & 0x0000FFFF; + return c; +#endif +} + +static inline uint8_t VmaBitScanLSB(uint64_t mask) +{ +#if defined(_MSC_VER) && defined(_WIN64) + unsigned long pos; + if (_BitScanForward64(&pos, mask)) + return static_cast(pos); + return UINT8_MAX; +#elif defined __GNUC__ || defined __clang__ + return static_cast(__builtin_ffsll(mask)) - 1U; +#else + uint8_t pos = 0; + uint64_t bit = 1; + do + { + if (mask & bit) + return pos; + bit <<= 1; + } while (pos++ < 63); + return UINT8_MAX; +#endif +} + +static inline uint8_t VmaBitScanLSB(uint32_t mask) +{ +#ifdef _MSC_VER + unsigned long pos; + if (_BitScanForward(&pos, mask)) + return static_cast(pos); + return UINT8_MAX; +#elif defined __GNUC__ || defined __clang__ + return static_cast(__builtin_ffs(mask)) - 1U; +#else + uint8_t pos = 0; + uint32_t bit = 1; + do + { + if (mask & bit) + return pos; + bit <<= 1; + } while (pos++ < 31); + return UINT8_MAX; +#endif +} + +static inline uint8_t VmaBitScanMSB(uint64_t mask) +{ +#if defined(_MSC_VER) && defined(_WIN64) + unsigned long pos; + if (_BitScanReverse64(&pos, mask)) + return static_cast(pos); +#elif defined __GNUC__ || defined __clang__ + if (mask) + return 63 - static_cast(__builtin_clzll(mask)); +#else + uint8_t pos = 63; + uint64_t bit = 1ULL << 63; + do + { + if (mask & bit) + return pos; + bit >>= 1; + } while (pos-- > 0); +#endif + return UINT8_MAX; +} + +static inline uint8_t VmaBitScanMSB(uint32_t mask) +{ +#ifdef _MSC_VER + unsigned long pos; + if (_BitScanReverse(&pos, mask)) + return static_cast(pos); +#elif defined __GNUC__ || defined __clang__ + if (mask) + return 31 - static_cast(__builtin_clz(mask)); +#else + uint8_t pos = 31; + uint32_t bit = 1UL << 31; + do + { + if (mask & bit) + return pos; + bit >>= 1; + } while (pos-- > 0); +#endif + return UINT8_MAX; +} + +/* +Returns true if given number is a power of two. +T must be unsigned integer number or signed integer but always nonnegative. +For 0 returns true. +*/ +template +inline bool VmaIsPow2(T x) +{ + return (x & (x - 1)) == 0; +} + +// Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16. +// Use types like uint32_t, uint64_t as T. +template +static inline T VmaAlignUp(T val, T alignment) +{ + VMA_HEAVY_ASSERT(VmaIsPow2(alignment)); + return (val + alignment - 1) & ~(alignment - 1); +} + +// Aligns given value down to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 8. +// Use types like uint32_t, uint64_t as T. +template +static inline T VmaAlignDown(T val, T alignment) +{ + VMA_HEAVY_ASSERT(VmaIsPow2(alignment)); + return val & ~(alignment - 1); +} + +// Division with mathematical rounding to nearest number. +template +static inline T VmaRoundDiv(T x, T y) +{ + return (x + (y / (T)2)) / y; +} + +// Divide by 'y' and round up to nearest integer. +template +static inline T VmaDivideRoundingUp(T x, T y) +{ + return (x + y - (T)1) / y; +} + +// Returns smallest power of 2 greater or equal to v. +static inline uint32_t VmaNextPow2(uint32_t v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +static inline uint64_t VmaNextPow2(uint64_t v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v |= v >> 32; + v++; + return v; +} + +// Returns largest power of 2 less or equal to v. +static inline uint32_t VmaPrevPow2(uint32_t v) +{ + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v = v ^ (v >> 1); + return v; +} + +static inline uint64_t VmaPrevPow2(uint64_t v) +{ + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v |= v >> 32; + v = v ^ (v >> 1); + return v; +} + +static inline bool VmaStrIsEmpty(const char* pStr) +{ + return pStr == VMA_NULL || *pStr == '\0'; +} + +/* +Returns true if two memory blocks occupy overlapping pages. +ResourceA must be in less memory offset than ResourceB. + +Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)" +chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity". +*/ +static inline bool VmaBlocksOnSamePage( + VkDeviceSize resourceAOffset, + VkDeviceSize resourceASize, + VkDeviceSize resourceBOffset, + VkDeviceSize pageSize) +{ + VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0); + VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1; + VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1); + VkDeviceSize resourceBStart = resourceBOffset; + VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1); + return resourceAEndPage == resourceBStartPage; +} + +/* +Returns true if given suballocation types could conflict and must respect +VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer +or linear image and another one is optimal image. If type is unknown, behave +conservatively. +*/ +static inline bool VmaIsBufferImageGranularityConflict( + VmaSuballocationType suballocType1, + VmaSuballocationType suballocType2) +{ + if (suballocType1 > suballocType2) + { + VMA_SWAP(suballocType1, suballocType2); + } + + switch (suballocType1) + { + case VMA_SUBALLOCATION_TYPE_FREE: + return false; + case VMA_SUBALLOCATION_TYPE_UNKNOWN: + return true; + case VMA_SUBALLOCATION_TYPE_BUFFER: + return + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; + case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN: + return + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR || + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; + case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR: + return + suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; + case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL: + return false; + default: + VMA_ASSERT(0); + return true; + } +} + +static void VmaWriteMagicValue(void* pData, VkDeviceSize offset) +{ +#if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION + uint32_t* pDst = (uint32_t*)((char*)pData + offset); + const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t); + for (size_t i = 0; i < numberCount; ++i, ++pDst) + { + *pDst = VMA_CORRUPTION_DETECTION_MAGIC_VALUE; + } +#else + // no-op +#endif +} + +static bool VmaValidateMagicValue(const void* pData, VkDeviceSize offset) +{ +#if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION + const uint32_t* pSrc = (const uint32_t*)((const char*)pData + offset); + const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t); + for (size_t i = 0; i < numberCount; ++i, ++pSrc) + { + if (*pSrc != VMA_CORRUPTION_DETECTION_MAGIC_VALUE) + { + return false; + } + } +#endif + return true; +} + +/* +Fills structure with parameters of an example buffer to be used for transfers +during GPU memory defragmentation. +*/ +static void VmaFillGpuDefragmentationBufferCreateInfo(VkBufferCreateInfo& outBufCreateInfo) +{ + memset(&outBufCreateInfo, 0, sizeof(outBufCreateInfo)); + outBufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + outBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + outBufCreateInfo.size = (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE; // Example size. +} + + +/* +Performs binary search and returns iterator to first element that is greater or +equal to (key), according to comparison (cmp). + +Cmp should return true if first argument is less than second argument. + +Returned value is the found element, if present in the collection or place where +new element with value (key) should be inserted. +*/ +template +static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp) +{ + size_t down = 0, up = (end - beg); + while (down < up) + { + const size_t mid = down + (up - down) / 2; // Overflow-safe midpoint calculation + if (cmp(*(beg + mid), key)) + { + down = mid + 1; + } + else + { + up = mid; + } + } + return beg + down; +} + +template +IterT VmaBinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp) +{ + IterT it = VmaBinaryFindFirstNotLess( + beg, end, value, cmp); + if (it == end || + (!cmp(*it, value) && !cmp(value, *it))) + { + return it; + } + return end; +} + +/* +Returns true if all pointers in the array are not-null and unique. +Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT. +T must be pointer type, e.g. VmaAllocation, VmaPool. +*/ +template +static bool VmaValidatePointerArray(uint32_t count, const T* arr) +{ + for (uint32_t i = 0; i < count; ++i) + { + const T iPtr = arr[i]; + if (iPtr == VMA_NULL) + { + return false; + } + for (uint32_t j = i + 1; j < count; ++j) + { + if (iPtr == arr[j]) + { + return false; + } + } + } + return true; +} + +template +static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct) +{ + newStruct->pNext = mainStruct->pNext; + mainStruct->pNext = newStruct; +} + +// This is the main algorithm that guides the selection of a memory type best for an allocation - +// converts usage to required/preferred/not preferred flags. +static bool FindMemoryPreferences( + bool isIntegratedGPU, + const VmaAllocationCreateInfo& allocCreateInfo, + VkFlags bufImgUsage, // VkBufferCreateInfo::usage or VkImageCreateInfo::usage. UINT32_MAX if unknown. + VkMemoryPropertyFlags& outRequiredFlags, + VkMemoryPropertyFlags& outPreferredFlags, + VkMemoryPropertyFlags& outNotPreferredFlags) +{ + outRequiredFlags = allocCreateInfo.requiredFlags; + outPreferredFlags = allocCreateInfo.preferredFlags; + outNotPreferredFlags = 0; + + switch(allocCreateInfo.usage) + { + case VMA_MEMORY_USAGE_UNKNOWN: + break; + case VMA_MEMORY_USAGE_GPU_ONLY: + if(!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + { + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + break; + case VMA_MEMORY_USAGE_CPU_ONLY: + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + break; + case VMA_MEMORY_USAGE_CPU_TO_GPU: + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + if(!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + { + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + break; + case VMA_MEMORY_USAGE_GPU_TO_CPU: + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + outPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + break; + case VMA_MEMORY_USAGE_CPU_COPY: + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + break; + case VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED: + outRequiredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + break; + case VMA_MEMORY_USAGE_AUTO: + case VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE: + case VMA_MEMORY_USAGE_AUTO_PREFER_HOST: + { + if(bufImgUsage == UINT32_MAX) + { + VMA_ASSERT(0 && "VMA_MEMORY_USAGE_AUTO* values can only be used with functions like vmaCreateBuffer, vmaCreateImage so that the details of the created resource are known."); + return false; + } + // This relies on values of VK_IMAGE_USAGE_TRANSFER* being the same VK_BUFFER_IMAGE_TRANSFER*. + const bool deviceAccess = (bufImgUsage & ~(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) != 0; + const bool hostAccessSequentialWrite = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT) != 0; + const bool hostAccessRandom = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT) != 0; + const bool hostAccessAllowTransferInstead = (allocCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT) != 0; + const bool preferDevice = allocCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + const bool preferHost = allocCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST; + + // CPU random access - e.g. a buffer written to or transferred from GPU to read back on CPU. + if(hostAccessRandom) + { + if(!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) + { + // Nice if it will end up in HOST_VISIBLE, but more importantly prefer DEVICE_LOCAL. + // Omitting HOST_VISIBLE here is intentional. + // In case there is DEVICE_LOCAL | HOST_VISIBLE | HOST_CACHED, it will pick that one. + // Otherwise, this will give same weight to DEVICE_LOCAL as HOST_VISIBLE | HOST_CACHED and select the former if occurs first on the list. + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + else + { + // Always CPU memory, cached. + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + } + // CPU sequential write - may be CPU or host-visible GPU memory, uncached and write-combined. + else if(hostAccessSequentialWrite) + { + // Want uncached and write-combined. + outNotPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + + if(!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) + { + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + } + else + { + outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + // Direct GPU access, CPU sequential write (e.g. a dynamic uniform buffer updated every frame) + if(deviceAccess) + { + // Could go to CPU memory or GPU BAR/unified. Up to the user to decide. If no preference, choose GPU memory. + if(preferHost) + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + else + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + // GPU no direct access, CPU sequential write (e.g. an upload buffer to be transferred to the GPU) + else + { + // Could go to CPU memory or GPU BAR/unified. Up to the user to decide. If no preference, choose CPU memory. + if(preferDevice) + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + else + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + } + } + // No CPU access + else + { + // GPU access, no CPU access (e.g. a color attachment image) - prefer GPU memory + if(deviceAccess) + { + // ...unless there is a clear preference from the user not to do so. + if(preferHost) + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + else + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + // No direct GPU access, no CPU access, just transfers. + // It may be staging copy intended for e.g. preserving image for next frame (then better GPU memory) or + // a "swap file" copy to free some GPU memory (then better CPU memory). + // Up to the user to decide. If no preferece, assume the former and choose GPU memory. + if(preferHost) + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + else + outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + break; + } + default: + VMA_ASSERT(0); + } + + // Avoid DEVICE_COHERENT unless explicitly requested. + if(((allocCreateInfo.requiredFlags | allocCreateInfo.preferredFlags) & + (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0) + { + outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Memory allocation + +static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment) +{ + void* result = VMA_NULL; + if ((pAllocationCallbacks != VMA_NULL) && + (pAllocationCallbacks->pfnAllocation != VMA_NULL)) + { + result = (*pAllocationCallbacks->pfnAllocation)( + pAllocationCallbacks->pUserData, + size, + alignment, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } + else + { + result = VMA_SYSTEM_ALIGNED_MALLOC(size, alignment); + } + VMA_ASSERT(result != VMA_NULL && "CPU memory allocation failed."); + return result; +} + +static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr) +{ + if ((pAllocationCallbacks != VMA_NULL) && + (pAllocationCallbacks->pfnFree != VMA_NULL)) + { + (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr); + } + else + { + VMA_SYSTEM_ALIGNED_FREE(ptr); + } +} + +template +static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks) +{ + return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T)); +} + +template +static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count) +{ + return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T)); +} + +#define vma_new(allocator, type) new(VmaAllocate(allocator))(type) + +#define vma_new_array(allocator, type, count) new(VmaAllocateArray((allocator), (count)))(type) + +template +static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr) +{ + ptr->~T(); + VmaFree(pAllocationCallbacks, ptr); +} + +template +static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count) +{ + if (ptr != VMA_NULL) + { + for (size_t i = count; i--; ) + { + ptr[i].~T(); + } + VmaFree(pAllocationCallbacks, ptr); + } +} + +static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr) +{ + if (srcStr != VMA_NULL) + { + const size_t len = strlen(srcStr); + char* const result = vma_new_array(allocs, char, len + 1); + memcpy(result, srcStr, len + 1); + return result; + } + return VMA_NULL; +} + +#if VMA_STATS_STRING_ENABLED +static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr, size_t strLen) +{ + if (srcStr != VMA_NULL) + { + char* const result = vma_new_array(allocs, char, strLen + 1); + memcpy(result, srcStr, strLen); + result[strLen] = '\0'; + return result; + } + return VMA_NULL; +} +#endif // VMA_STATS_STRING_ENABLED + +static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str) +{ + if (str != VMA_NULL) + { + const size_t len = strlen(str); + vma_delete_array(allocs, str, len + 1); + } +} + +template +size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value) +{ + const size_t indexToInsert = VmaBinaryFindFirstNotLess( + vector.data(), + vector.data() + vector.size(), + value, + CmpLess()) - vector.data(); + VmaVectorInsert(vector, indexToInsert, value); + return indexToInsert; +} + +template +bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value) +{ + CmpLess comparator; + typename VectorT::iterator it = VmaBinaryFindFirstNotLess( + vector.begin(), + vector.end(), + value, + comparator); + if ((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it)) + { + size_t indexToRemove = it - vector.begin(); + VmaVectorRemove(vector, indexToRemove); + return true; + } + return false; +} +#endif // _VMA_FUNCTIONS + +#ifndef _VMA_STATISTICS_FUNCTIONS + +static void VmaClearStatistics(VmaStatistics& outStats) +{ + outStats.blockCount = 0; + outStats.allocationCount = 0; + outStats.blockBytes = 0; + outStats.allocationBytes = 0; +} + +static void VmaAddStatistics(VmaStatistics& inoutStats, const VmaStatistics& src) +{ + inoutStats.blockCount += src.blockCount; + inoutStats.allocationCount += src.allocationCount; + inoutStats.blockBytes += src.blockBytes; + inoutStats.allocationBytes += src.allocationBytes; +} + +static void VmaClearDetailedStatistics(VmaDetailedStatistics& outStats) +{ + VmaClearStatistics(outStats.statistics); + outStats.unusedRangeCount = 0; + outStats.allocationSizeMin = VK_WHOLE_SIZE; + outStats.allocationSizeMax = 0; + outStats.unusedRangeSizeMin = VK_WHOLE_SIZE; + outStats.unusedRangeSizeMax = 0; +} + +static void VmaAddDetailedStatisticsAllocation(VmaDetailedStatistics& inoutStats, VkDeviceSize size) +{ + inoutStats.statistics.allocationCount++; + inoutStats.statistics.allocationBytes += size; + inoutStats.allocationSizeMin = VMA_MIN(inoutStats.allocationSizeMin, size); + inoutStats.allocationSizeMax = VMA_MAX(inoutStats.allocationSizeMax, size); +} + +static void VmaAddDetailedStatisticsUnusedRange(VmaDetailedStatistics& inoutStats, VkDeviceSize size) +{ + inoutStats.unusedRangeCount++; + inoutStats.unusedRangeSizeMin = VMA_MIN(inoutStats.unusedRangeSizeMin, size); + inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, size); +} + +static void VmaAddDetailedStatistics(VmaDetailedStatistics& inoutStats, const VmaDetailedStatistics& src) +{ + VmaAddStatistics(inoutStats.statistics, src.statistics); + inoutStats.unusedRangeCount += src.unusedRangeCount; + inoutStats.allocationSizeMin = VMA_MIN(inoutStats.allocationSizeMin, src.allocationSizeMin); + inoutStats.allocationSizeMax = VMA_MAX(inoutStats.allocationSizeMax, src.allocationSizeMax); + inoutStats.unusedRangeSizeMin = VMA_MIN(inoutStats.unusedRangeSizeMin, src.unusedRangeSizeMin); + inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, src.unusedRangeSizeMax); +} + +#endif // _VMA_STATISTICS_FUNCTIONS + +#ifndef _VMA_MUTEX_LOCK +// Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope). +struct VmaMutexLock +{ + VMA_CLASS_NO_COPY(VmaMutexLock) +public: + VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) : + m_pMutex(useMutex ? &mutex : VMA_NULL) + { + if (m_pMutex) { m_pMutex->Lock(); } + } + ~VmaMutexLock() { if (m_pMutex) { m_pMutex->Unlock(); } } + +private: + VMA_MUTEX* m_pMutex; +}; + +// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading. +struct VmaMutexLockRead +{ + VMA_CLASS_NO_COPY(VmaMutexLockRead) +public: + VmaMutexLockRead(VMA_RW_MUTEX& mutex, bool useMutex) : + m_pMutex(useMutex ? &mutex : VMA_NULL) + { + if (m_pMutex) { m_pMutex->LockRead(); } + } + ~VmaMutexLockRead() { if (m_pMutex) { m_pMutex->UnlockRead(); } } + +private: + VMA_RW_MUTEX* m_pMutex; +}; + +// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing. +struct VmaMutexLockWrite +{ + VMA_CLASS_NO_COPY(VmaMutexLockWrite) +public: + VmaMutexLockWrite(VMA_RW_MUTEX& mutex, bool useMutex) + : m_pMutex(useMutex ? &mutex : VMA_NULL) + { + if (m_pMutex) { m_pMutex->LockWrite(); } + } + ~VmaMutexLockWrite() { if (m_pMutex) { m_pMutex->UnlockWrite(); } } + +private: + VMA_RW_MUTEX* m_pMutex; +}; + +#if VMA_DEBUG_GLOBAL_MUTEX + static VMA_MUTEX gDebugGlobalMutex; + #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); +#else + #define VMA_DEBUG_GLOBAL_MUTEX_LOCK +#endif +#endif // _VMA_MUTEX_LOCK + +#ifndef _VMA_ATOMIC_TRANSACTIONAL_INCREMENT +// An object that increments given atomic but decrements it back in the destructor unless Commit() is called. +template +struct AtomicTransactionalIncrement +{ +public: + typedef std::atomic AtomicT; + + ~AtomicTransactionalIncrement() + { + if(m_Atomic) + --(*m_Atomic); + } + + void Commit() { m_Atomic = nullptr; } + T Increment(AtomicT* atomic) + { + m_Atomic = atomic; + return m_Atomic->fetch_add(1); + } + +private: + AtomicT* m_Atomic = nullptr; +}; +#endif // _VMA_ATOMIC_TRANSACTIONAL_INCREMENT + +#ifndef _VMA_STL_ALLOCATOR +// STL-compatible allocator. +template +struct VmaStlAllocator +{ + const VkAllocationCallbacks* const m_pCallbacks; + typedef T value_type; + + VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) {} + template + VmaStlAllocator(const VmaStlAllocator& src) : m_pCallbacks(src.m_pCallbacks) {} + VmaStlAllocator(const VmaStlAllocator&) = default; + VmaStlAllocator& operator=(const VmaStlAllocator&) = delete; + + T* allocate(size_t n) { return VmaAllocateArray(m_pCallbacks, n); } + void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); } + + template + bool operator==(const VmaStlAllocator& rhs) const + { + return m_pCallbacks == rhs.m_pCallbacks; + } + template + bool operator!=(const VmaStlAllocator& rhs) const + { + return m_pCallbacks != rhs.m_pCallbacks; + } +}; +#endif // _VMA_STL_ALLOCATOR + +#ifndef _VMA_VECTOR +/* Class with interface compatible with subset of std::vector. +T must be POD because constructors and destructors are not called and memcpy is +used for these objects. */ +template +class VmaVector +{ +public: + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + + VmaVector(const AllocatorT& allocator); + VmaVector(size_t count, const AllocatorT& allocator); + // This version of the constructor is here for compatibility with pre-C++14 std::vector. + // value is unused. + VmaVector(size_t count, const T& value, const AllocatorT& allocator) : VmaVector(count, allocator) {} + VmaVector(const VmaVector& src); + VmaVector& operator=(const VmaVector& rhs); + ~VmaVector() { VmaFree(m_Allocator.m_pCallbacks, m_pArray); } + + bool empty() const { return m_Count == 0; } + size_t size() const { return m_Count; } + T* data() { return m_pArray; } + T& front() { VMA_HEAVY_ASSERT(m_Count > 0); return m_pArray[0]; } + T& back() { VMA_HEAVY_ASSERT(m_Count > 0); return m_pArray[m_Count - 1]; } + const T* data() const { return m_pArray; } + const T& front() const { VMA_HEAVY_ASSERT(m_Count > 0); return m_pArray[0]; } + const T& back() const { VMA_HEAVY_ASSERT(m_Count > 0); return m_pArray[m_Count - 1]; } + + iterator begin() { return m_pArray; } + iterator end() { return m_pArray + m_Count; } + const_iterator cbegin() const { return m_pArray; } + const_iterator cend() const { return m_pArray + m_Count; } + const_iterator begin() const { return cbegin(); } + const_iterator end() const { return cend(); } + + void pop_front() { VMA_HEAVY_ASSERT(m_Count > 0); remove(0); } + void pop_back() { VMA_HEAVY_ASSERT(m_Count > 0); resize(size() - 1); } + void push_front(const T& src) { insert(0, src); } + + void push_back(const T& src); + void reserve(size_t newCapacity, bool freeMemory = false); + void resize(size_t newCount); + void clear() { resize(0); } + void shrink_to_fit(); + void insert(size_t index, const T& src); + void remove(size_t index); + + T& operator[](size_t index) { VMA_HEAVY_ASSERT(index < m_Count); return m_pArray[index]; } + const T& operator[](size_t index) const { VMA_HEAVY_ASSERT(index < m_Count); return m_pArray[index]; } + +private: + AllocatorT m_Allocator; + T* m_pArray; + size_t m_Count; + size_t m_Capacity; +}; + +#ifndef _VMA_VECTOR_FUNCTIONS +template +VmaVector::VmaVector(const AllocatorT& allocator) + : m_Allocator(allocator), + m_pArray(VMA_NULL), + m_Count(0), + m_Capacity(0) {} + +template +VmaVector::VmaVector(size_t count, const AllocatorT& allocator) + : m_Allocator(allocator), + m_pArray(count ? (T*)VmaAllocateArray(allocator.m_pCallbacks, count) : VMA_NULL), + m_Count(count), + m_Capacity(count) {} + +template +VmaVector::VmaVector(const VmaVector& src) + : m_Allocator(src.m_Allocator), + m_pArray(src.m_Count ? (T*)VmaAllocateArray(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL), + m_Count(src.m_Count), + m_Capacity(src.m_Count) +{ + if (m_Count != 0) + { + memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T)); + } +} + +template +VmaVector& VmaVector::operator=(const VmaVector& rhs) +{ + if (&rhs != this) + { + resize(rhs.m_Count); + if (m_Count != 0) + { + memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T)); + } + } + return *this; +} + +template +void VmaVector::push_back(const T& src) +{ + const size_t newIndex = size(); + resize(newIndex + 1); + m_pArray[newIndex] = src; +} + +template +void VmaVector::reserve(size_t newCapacity, bool freeMemory) +{ + newCapacity = VMA_MAX(newCapacity, m_Count); + + if ((newCapacity < m_Capacity) && !freeMemory) + { + newCapacity = m_Capacity; + } + + if (newCapacity != m_Capacity) + { + T* const newArray = newCapacity ? VmaAllocateArray(m_Allocator, newCapacity) : VMA_NULL; + if (m_Count != 0) + { + memcpy(newArray, m_pArray, m_Count * sizeof(T)); + } + VmaFree(m_Allocator.m_pCallbacks, m_pArray); + m_Capacity = newCapacity; + m_pArray = newArray; + } +} + +template +void VmaVector::resize(size_t newCount) +{ + size_t newCapacity = m_Capacity; + if (newCount > m_Capacity) + { + newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8)); + } + + if (newCapacity != m_Capacity) + { + T* const newArray = newCapacity ? VmaAllocateArray(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL; + const size_t elementsToCopy = VMA_MIN(m_Count, newCount); + if (elementsToCopy != 0) + { + memcpy(newArray, m_pArray, elementsToCopy * sizeof(T)); + } + VmaFree(m_Allocator.m_pCallbacks, m_pArray); + m_Capacity = newCapacity; + m_pArray = newArray; + } + + m_Count = newCount; +} + +template +void VmaVector::shrink_to_fit() +{ + if (m_Capacity > m_Count) + { + T* newArray = VMA_NULL; + if (m_Count > 0) + { + newArray = VmaAllocateArray(m_Allocator.m_pCallbacks, m_Count); + memcpy(newArray, m_pArray, m_Count * sizeof(T)); + } + VmaFree(m_Allocator.m_pCallbacks, m_pArray); + m_Capacity = m_Count; + m_pArray = newArray; + } +} + +template +void VmaVector::insert(size_t index, const T& src) +{ + VMA_HEAVY_ASSERT(index <= m_Count); + const size_t oldCount = size(); + resize(oldCount + 1); + if (index < oldCount) + { + memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T)); + } + m_pArray[index] = src; +} + +template +void VmaVector::remove(size_t index) +{ + VMA_HEAVY_ASSERT(index < m_Count); + const size_t oldCount = size(); + if (index < oldCount - 1) + { + memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T)); + } + resize(oldCount - 1); +} +#endif // _VMA_VECTOR_FUNCTIONS + +template +static void VmaVectorInsert(VmaVector& vec, size_t index, const T& item) +{ + vec.insert(index, item); +} + +template +static void VmaVectorRemove(VmaVector& vec, size_t index) +{ + vec.remove(index); +} +#endif // _VMA_VECTOR + +#ifndef _VMA_SMALL_VECTOR +/* +This is a vector (a variable-sized array), optimized for the case when the array is small. + +It contains some number of elements in-place, which allows it to avoid heap allocation +when the actual number of elements is below that threshold. This allows normal "small" +cases to be fast without losing generality for large inputs. +*/ +template +class VmaSmallVector +{ +public: + typedef T value_type; + typedef T* iterator; + + VmaSmallVector(const AllocatorT& allocator); + VmaSmallVector(size_t count, const AllocatorT& allocator); + template + VmaSmallVector(const VmaSmallVector&) = delete; + template + VmaSmallVector& operator=(const VmaSmallVector&) = delete; + ~VmaSmallVector() = default; + + bool empty() const { return m_Count == 0; } + size_t size() const { return m_Count; } + T* data() { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; } + T& front() { VMA_HEAVY_ASSERT(m_Count > 0); return data()[0]; } + T& back() { VMA_HEAVY_ASSERT(m_Count > 0); return data()[m_Count - 1]; } + const T* data() const { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; } + const T& front() const { VMA_HEAVY_ASSERT(m_Count > 0); return data()[0]; } + const T& back() const { VMA_HEAVY_ASSERT(m_Count > 0); return data()[m_Count - 1]; } + + iterator begin() { return data(); } + iterator end() { return data() + m_Count; } + + void pop_front() { VMA_HEAVY_ASSERT(m_Count > 0); remove(0); } + void pop_back() { VMA_HEAVY_ASSERT(m_Count > 0); resize(size() - 1); } + void push_front(const T& src) { insert(0, src); } + + void push_back(const T& src); + void resize(size_t newCount, bool freeMemory = false); + void clear(bool freeMemory = false); + void insert(size_t index, const T& src); + void remove(size_t index); + + T& operator[](size_t index) { VMA_HEAVY_ASSERT(index < m_Count); return data()[index]; } + const T& operator[](size_t index) const { VMA_HEAVY_ASSERT(index < m_Count); return data()[index]; } + +private: + size_t m_Count; + T m_StaticArray[N]; // Used when m_Size <= N + VmaVector m_DynamicArray; // Used when m_Size > N +}; + +#ifndef _VMA_SMALL_VECTOR_FUNCTIONS +template +VmaSmallVector::VmaSmallVector(const AllocatorT& allocator) + : m_Count(0), + m_DynamicArray(allocator) {} + +template +VmaSmallVector::VmaSmallVector(size_t count, const AllocatorT& allocator) + : m_Count(count), + m_DynamicArray(count > N ? count : 0, allocator) {} + +template +void VmaSmallVector::push_back(const T& src) +{ + const size_t newIndex = size(); + resize(newIndex + 1); + data()[newIndex] = src; +} + +template +void VmaSmallVector::resize(size_t newCount, bool freeMemory) +{ + if (newCount > N && m_Count > N) + { + // Any direction, staying in m_DynamicArray + m_DynamicArray.resize(newCount); + if (freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } + } + else if (newCount > N && m_Count <= N) + { + // Growing, moving from m_StaticArray to m_DynamicArray + m_DynamicArray.resize(newCount); + if (m_Count > 0) + { + memcpy(m_DynamicArray.data(), m_StaticArray, m_Count * sizeof(T)); + } + } + else if (newCount <= N && m_Count > N) + { + // Shrinking, moving from m_DynamicArray to m_StaticArray + if (newCount > 0) + { + memcpy(m_StaticArray, m_DynamicArray.data(), newCount * sizeof(T)); + } + m_DynamicArray.resize(0); + if (freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } + } + else + { + // Any direction, staying in m_StaticArray - nothing to do here + } + m_Count = newCount; +} + +template +void VmaSmallVector::clear(bool freeMemory) +{ + m_DynamicArray.clear(); + if (freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } + m_Count = 0; +} + +template +void VmaSmallVector::insert(size_t index, const T& src) +{ + VMA_HEAVY_ASSERT(index <= m_Count); + const size_t oldCount = size(); + resize(oldCount + 1); + T* const dataPtr = data(); + if (index < oldCount) + { + // I know, this could be more optimal for case where memmove can be memcpy directly from m_StaticArray to m_DynamicArray. + memmove(dataPtr + (index + 1), dataPtr + index, (oldCount - index) * sizeof(T)); + } + dataPtr[index] = src; +} + +template +void VmaSmallVector::remove(size_t index) +{ + VMA_HEAVY_ASSERT(index < m_Count); + const size_t oldCount = size(); + if (index < oldCount - 1) + { + // I know, this could be more optimal for case where memmove can be memcpy directly from m_DynamicArray to m_StaticArray. + T* const dataPtr = data(); + memmove(dataPtr + index, dataPtr + (index + 1), (oldCount - index - 1) * sizeof(T)); + } + resize(oldCount - 1); +} +#endif // _VMA_SMALL_VECTOR_FUNCTIONS +#endif // _VMA_SMALL_VECTOR + +#ifndef _VMA_POOL_ALLOCATOR +/* +Allocator for objects of type T using a list of arrays (pools) to speed up +allocation. Number of elements that can be allocated is not bounded because +allocator can create multiple blocks. +*/ +template +class VmaPoolAllocator +{ + VMA_CLASS_NO_COPY(VmaPoolAllocator) +public: + VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity); + ~VmaPoolAllocator(); + template T* Alloc(Types&&... args); + void Free(T* ptr); + +private: + union Item + { + uint32_t NextFreeIndex; + alignas(T) char Value[sizeof(T)]; + }; + struct ItemBlock + { + Item* pItems; + uint32_t Capacity; + uint32_t FirstFreeIndex; + }; + + const VkAllocationCallbacks* m_pAllocationCallbacks; + const uint32_t m_FirstBlockCapacity; + VmaVector> m_ItemBlocks; + + ItemBlock& CreateNewBlock(); +}; + +#ifndef _VMA_POOL_ALLOCATOR_FUNCTIONS +template +VmaPoolAllocator::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity) + : m_pAllocationCallbacks(pAllocationCallbacks), + m_FirstBlockCapacity(firstBlockCapacity), + m_ItemBlocks(VmaStlAllocator(pAllocationCallbacks)) +{ + VMA_ASSERT(m_FirstBlockCapacity > 1); +} + +template +VmaPoolAllocator::~VmaPoolAllocator() +{ + for (size_t i = m_ItemBlocks.size(); i--;) + vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity); + m_ItemBlocks.clear(); +} + +template +template T* VmaPoolAllocator::Alloc(Types&&... args) +{ + for (size_t i = m_ItemBlocks.size(); i--; ) + { + ItemBlock& block = m_ItemBlocks[i]; + // This block has some free items: Use first one. + if (block.FirstFreeIndex != UINT32_MAX) + { + Item* const pItem = &block.pItems[block.FirstFreeIndex]; + block.FirstFreeIndex = pItem->NextFreeIndex; + T* result = (T*)&pItem->Value; + new(result)T(std::forward(args)...); // Explicit constructor call. + return result; + } + } + + // No block has free item: Create new one and use it. + ItemBlock& newBlock = CreateNewBlock(); + Item* const pItem = &newBlock.pItems[0]; + newBlock.FirstFreeIndex = pItem->NextFreeIndex; + T* result = (T*)&pItem->Value; + new(result) T(std::forward(args)...); // Explicit constructor call. + return result; +} + +template +void VmaPoolAllocator::Free(T* ptr) +{ + // Search all memory blocks to find ptr. + for (size_t i = m_ItemBlocks.size(); i--; ) + { + ItemBlock& block = m_ItemBlocks[i]; + + // Casting to union. + Item* pItemPtr; + memcpy(&pItemPtr, &ptr, sizeof(pItemPtr)); + + // Check if pItemPtr is in address range of this block. + if ((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity)) + { + ptr->~T(); // Explicit destructor call. + const uint32_t index = static_cast(pItemPtr - block.pItems); + pItemPtr->NextFreeIndex = block.FirstFreeIndex; + block.FirstFreeIndex = index; + return; + } + } + VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool."); +} + +template +typename VmaPoolAllocator::ItemBlock& VmaPoolAllocator::CreateNewBlock() +{ + const uint32_t newBlockCapacity = m_ItemBlocks.empty() ? + m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2; + + const ItemBlock newBlock = + { + vma_new_array(m_pAllocationCallbacks, Item, newBlockCapacity), + newBlockCapacity, + 0 + }; + + m_ItemBlocks.push_back(newBlock); + + // Setup singly-linked list of all free items in this block. + for (uint32_t i = 0; i < newBlockCapacity - 1; ++i) + newBlock.pItems[i].NextFreeIndex = i + 1; + newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX; + return m_ItemBlocks.back(); +} +#endif // _VMA_POOL_ALLOCATOR_FUNCTIONS +#endif // _VMA_POOL_ALLOCATOR + +#ifndef _VMA_RAW_LIST +template +struct VmaListItem +{ + VmaListItem* pPrev; + VmaListItem* pNext; + T Value; +}; + +// Doubly linked list. +template +class VmaRawList +{ + VMA_CLASS_NO_COPY(VmaRawList) +public: + typedef VmaListItem ItemType; + + VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks); + // Intentionally not calling Clear, because that would be unnecessary + // computations to return all items to m_ItemAllocator as free. + ~VmaRawList() = default; + + size_t GetCount() const { return m_Count; } + bool IsEmpty() const { return m_Count == 0; } + + ItemType* Front() { return m_pFront; } + ItemType* Back() { return m_pBack; } + const ItemType* Front() const { return m_pFront; } + const ItemType* Back() const { return m_pBack; } + + ItemType* PushFront(); + ItemType* PushBack(); + ItemType* PushFront(const T& value); + ItemType* PushBack(const T& value); + void PopFront(); + void PopBack(); + + // Item can be null - it means PushBack. + ItemType* InsertBefore(ItemType* pItem); + // Item can be null - it means PushFront. + ItemType* InsertAfter(ItemType* pItem); + ItemType* InsertBefore(ItemType* pItem, const T& value); + ItemType* InsertAfter(ItemType* pItem, const T& value); + + void Clear(); + void Remove(ItemType* pItem); + +private: + const VkAllocationCallbacks* const m_pAllocationCallbacks; + VmaPoolAllocator m_ItemAllocator; + ItemType* m_pFront; + ItemType* m_pBack; + size_t m_Count; +}; + +#ifndef _VMA_RAW_LIST_FUNCTIONS +template +VmaRawList::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) + : m_pAllocationCallbacks(pAllocationCallbacks), + m_ItemAllocator(pAllocationCallbacks, 128), + m_pFront(VMA_NULL), + m_pBack(VMA_NULL), + m_Count(0) {} + +template +VmaListItem* VmaRawList::PushFront() +{ + ItemType* const pNewItem = m_ItemAllocator.Alloc(); + pNewItem->pPrev = VMA_NULL; + if (IsEmpty()) + { + pNewItem->pNext = VMA_NULL; + m_pFront = pNewItem; + m_pBack = pNewItem; + m_Count = 1; + } + else + { + pNewItem->pNext = m_pFront; + m_pFront->pPrev = pNewItem; + m_pFront = pNewItem; + ++m_Count; + } + return pNewItem; +} + +template +VmaListItem* VmaRawList::PushBack() +{ + ItemType* const pNewItem = m_ItemAllocator.Alloc(); + pNewItem->pNext = VMA_NULL; + if(IsEmpty()) + { + pNewItem->pPrev = VMA_NULL; + m_pFront = pNewItem; + m_pBack = pNewItem; + m_Count = 1; + } + else + { + pNewItem->pPrev = m_pBack; + m_pBack->pNext = pNewItem; + m_pBack = pNewItem; + ++m_Count; + } + return pNewItem; +} + +template +VmaListItem* VmaRawList::PushFront(const T& value) +{ + ItemType* const pNewItem = PushFront(); + pNewItem->Value = value; + return pNewItem; +} + +template +VmaListItem* VmaRawList::PushBack(const T& value) +{ + ItemType* const pNewItem = PushBack(); + pNewItem->Value = value; + return pNewItem; +} + +template +void VmaRawList::PopFront() +{ + VMA_HEAVY_ASSERT(m_Count > 0); + ItemType* const pFrontItem = m_pFront; + ItemType* const pNextItem = pFrontItem->pNext; + if (pNextItem != VMA_NULL) + { + pNextItem->pPrev = VMA_NULL; + } + m_pFront = pNextItem; + m_ItemAllocator.Free(pFrontItem); + --m_Count; +} + +template +void VmaRawList::PopBack() +{ + VMA_HEAVY_ASSERT(m_Count > 0); + ItemType* const pBackItem = m_pBack; + ItemType* const pPrevItem = pBackItem->pPrev; + if(pPrevItem != VMA_NULL) + { + pPrevItem->pNext = VMA_NULL; + } + m_pBack = pPrevItem; + m_ItemAllocator.Free(pBackItem); + --m_Count; +} + +template +void VmaRawList::Clear() +{ + if (IsEmpty() == false) + { + ItemType* pItem = m_pBack; + while (pItem != VMA_NULL) + { + ItemType* const pPrevItem = pItem->pPrev; + m_ItemAllocator.Free(pItem); + pItem = pPrevItem; + } + m_pFront = VMA_NULL; + m_pBack = VMA_NULL; + m_Count = 0; + } +} + +template +void VmaRawList::Remove(ItemType* pItem) +{ + VMA_HEAVY_ASSERT(pItem != VMA_NULL); + VMA_HEAVY_ASSERT(m_Count > 0); + + if(pItem->pPrev != VMA_NULL) + { + pItem->pPrev->pNext = pItem->pNext; + } + else + { + VMA_HEAVY_ASSERT(m_pFront == pItem); + m_pFront = pItem->pNext; + } + + if(pItem->pNext != VMA_NULL) + { + pItem->pNext->pPrev = pItem->pPrev; + } + else + { + VMA_HEAVY_ASSERT(m_pBack == pItem); + m_pBack = pItem->pPrev; + } + + m_ItemAllocator.Free(pItem); + --m_Count; +} + +template +VmaListItem* VmaRawList::InsertBefore(ItemType* pItem) +{ + if(pItem != VMA_NULL) + { + ItemType* const prevItem = pItem->pPrev; + ItemType* const newItem = m_ItemAllocator.Alloc(); + newItem->pPrev = prevItem; + newItem->pNext = pItem; + pItem->pPrev = newItem; + if(prevItem != VMA_NULL) + { + prevItem->pNext = newItem; + } + else + { + VMA_HEAVY_ASSERT(m_pFront == pItem); + m_pFront = newItem; + } + ++m_Count; + return newItem; + } + else + return PushBack(); +} + +template +VmaListItem* VmaRawList::InsertAfter(ItemType* pItem) +{ + if(pItem != VMA_NULL) + { + ItemType* const nextItem = pItem->pNext; + ItemType* const newItem = m_ItemAllocator.Alloc(); + newItem->pNext = nextItem; + newItem->pPrev = pItem; + pItem->pNext = newItem; + if(nextItem != VMA_NULL) + { + nextItem->pPrev = newItem; + } + else + { + VMA_HEAVY_ASSERT(m_pBack == pItem); + m_pBack = newItem; + } + ++m_Count; + return newItem; + } + else + return PushFront(); +} + +template +VmaListItem* VmaRawList::InsertBefore(ItemType* pItem, const T& value) +{ + ItemType* const newItem = InsertBefore(pItem); + newItem->Value = value; + return newItem; +} + +template +VmaListItem* VmaRawList::InsertAfter(ItemType* pItem, const T& value) +{ + ItemType* const newItem = InsertAfter(pItem); + newItem->Value = value; + return newItem; +} +#endif // _VMA_RAW_LIST_FUNCTIONS +#endif // _VMA_RAW_LIST + +#ifndef _VMA_LIST +template +class VmaList +{ + VMA_CLASS_NO_COPY(VmaList) +public: + class reverse_iterator; + class const_iterator; + class const_reverse_iterator; + + class iterator + { + friend class const_iterator; + friend class VmaList; + public: + iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + iterator(const reverse_iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + + T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } + T* operator->() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return &m_pItem->Value; } + + bool operator==(const iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } + bool operator!=(const iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } + + iterator operator++(int) { iterator result = *this; ++*this; return result; } + iterator operator--(int) { iterator result = *this; --*this; return result; } + + iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pNext; return *this; } + iterator& operator--(); + + private: + VmaRawList* m_pList; + VmaListItem* m_pItem; + + iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + }; + class reverse_iterator + { + friend class const_reverse_iterator; + friend class VmaList; + public: + reverse_iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + reverse_iterator(const iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + + T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } + T* operator->() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return &m_pItem->Value; } + + bool operator==(const reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } + bool operator!=(const reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } + + reverse_iterator operator++(int) { reverse_iterator result = *this; ++* this; return result; } + reverse_iterator operator--(int) { reverse_iterator result = *this; --* this; return result; } + + reverse_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pPrev; return *this; } + reverse_iterator& operator--(); + + private: + VmaRawList* m_pList; + VmaListItem* m_pItem; + + reverse_iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + }; + class const_iterator + { + friend class VmaList; + public: + const_iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + const_iterator(const iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + const_iterator(const reverse_iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + + iterator drop_const() { return { const_cast*>(m_pList), const_cast*>(m_pItem) }; } + + const T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } + const T* operator->() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return &m_pItem->Value; } + + bool operator==(const const_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } + bool operator!=(const const_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } + + const_iterator operator++(int) { const_iterator result = *this; ++* this; return result; } + const_iterator operator--(int) { const_iterator result = *this; --* this; return result; } + + const_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pNext; return *this; } + const_iterator& operator--(); + + private: + const VmaRawList* m_pList; + const VmaListItem* m_pItem; + + const_iterator(const VmaRawList* pList, const VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + }; + class const_reverse_iterator + { + friend class VmaList; + public: + const_reverse_iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + const_reverse_iterator(const reverse_iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + const_reverse_iterator(const iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} + + reverse_iterator drop_const() { return { const_cast*>(m_pList), const_cast*>(m_pItem) }; } + + const T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } + const T* operator->() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return &m_pItem->Value; } + + bool operator==(const const_reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } + bool operator!=(const const_reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } + + const_reverse_iterator operator++(int) { const_reverse_iterator result = *this; ++* this; return result; } + const_reverse_iterator operator--(int) { const_reverse_iterator result = *this; --* this; return result; } + + const_reverse_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pPrev; return *this; } + const_reverse_iterator& operator--(); + + private: + const VmaRawList* m_pList; + const VmaListItem* m_pItem; + + const_reverse_iterator(const VmaRawList* pList, const VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + }; + + VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) {} + + bool empty() const { return m_RawList.IsEmpty(); } + size_t size() const { return m_RawList.GetCount(); } + + iterator begin() { return iterator(&m_RawList, m_RawList.Front()); } + iterator end() { return iterator(&m_RawList, VMA_NULL); } + + const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); } + const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); } + + const_iterator begin() const { return cbegin(); } + const_iterator end() const { return cend(); } + + reverse_iterator rbegin() { return reverse_iterator(&m_RawList, m_RawList.Back()); } + reverse_iterator rend() { return reverse_iterator(&m_RawList, VMA_NULL); } + + const_reverse_iterator crbegin() const { return const_reverse_iterator(&m_RawList, m_RawList.Back()); } + const_reverse_iterator crend() const { return const_reverse_iterator(&m_RawList, VMA_NULL); } + + const_reverse_iterator rbegin() const { return crbegin(); } + const_reverse_iterator rend() const { return crend(); } + + void push_back(const T& value) { m_RawList.PushBack(value); } + iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); } + + void clear() { m_RawList.Clear(); } + void erase(iterator it) { m_RawList.Remove(it.m_pItem); } + +private: + VmaRawList m_RawList; +}; + +#ifndef _VMA_LIST_FUNCTIONS +template +typename VmaList::iterator& VmaList::iterator::operator--() +{ + if (m_pItem != VMA_NULL) + { + m_pItem = m_pItem->pPrev; + } + else + { + VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); + m_pItem = m_pList->Back(); + } + return *this; +} + +template +typename VmaList::reverse_iterator& VmaList::reverse_iterator::operator--() +{ + if (m_pItem != VMA_NULL) + { + m_pItem = m_pItem->pNext; + } + else + { + VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); + m_pItem = m_pList->Front(); + } + return *this; +} + +template +typename VmaList::const_iterator& VmaList::const_iterator::operator--() +{ + if (m_pItem != VMA_NULL) + { + m_pItem = m_pItem->pPrev; + } + else + { + VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); + m_pItem = m_pList->Back(); + } + return *this; +} + +template +typename VmaList::const_reverse_iterator& VmaList::const_reverse_iterator::operator--() +{ + if (m_pItem != VMA_NULL) + { + m_pItem = m_pItem->pNext; + } + else + { + VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); + m_pItem = m_pList->Back(); + } + return *this; +} +#endif // _VMA_LIST_FUNCTIONS +#endif // _VMA_LIST + +#ifndef _VMA_INTRUSIVE_LINKED_LIST +/* +Expected interface of ItemTypeTraits: +struct MyItemTypeTraits +{ + typedef MyItem ItemType; + static ItemType* GetPrev(const ItemType* item) { return item->myPrevPtr; } + static ItemType* GetNext(const ItemType* item) { return item->myNextPtr; } + static ItemType*& AccessPrev(ItemType* item) { return item->myPrevPtr; } + static ItemType*& AccessNext(ItemType* item) { return item->myNextPtr; } +}; +*/ +template +class VmaIntrusiveLinkedList +{ +public: + typedef typename ItemTypeTraits::ItemType ItemType; + static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); } + static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); } + + // Movable, not copyable. + VmaIntrusiveLinkedList() = default; + VmaIntrusiveLinkedList(VmaIntrusiveLinkedList && src); + VmaIntrusiveLinkedList(const VmaIntrusiveLinkedList&) = delete; + VmaIntrusiveLinkedList& operator=(VmaIntrusiveLinkedList&& src); + VmaIntrusiveLinkedList& operator=(const VmaIntrusiveLinkedList&) = delete; + ~VmaIntrusiveLinkedList() { VMA_HEAVY_ASSERT(IsEmpty()); } + + size_t GetCount() const { return m_Count; } + bool IsEmpty() const { return m_Count == 0; } + ItemType* Front() { return m_Front; } + ItemType* Back() { return m_Back; } + const ItemType* Front() const { return m_Front; } + const ItemType* Back() const { return m_Back; } + + void PushBack(ItemType* item); + void PushFront(ItemType* item); + ItemType* PopBack(); + ItemType* PopFront(); + + // MyItem can be null - it means PushBack. + void InsertBefore(ItemType* existingItem, ItemType* newItem); + // MyItem can be null - it means PushFront. + void InsertAfter(ItemType* existingItem, ItemType* newItem); + void Remove(ItemType* item); + void RemoveAll(); + +private: + ItemType* m_Front = VMA_NULL; + ItemType* m_Back = VMA_NULL; + size_t m_Count = 0; +}; + +#ifndef _VMA_INTRUSIVE_LINKED_LIST_FUNCTIONS +template +VmaIntrusiveLinkedList::VmaIntrusiveLinkedList(VmaIntrusiveLinkedList&& src) + : m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count) +{ + src.m_Front = src.m_Back = VMA_NULL; + src.m_Count = 0; +} + +template +VmaIntrusiveLinkedList& VmaIntrusiveLinkedList::operator=(VmaIntrusiveLinkedList&& src) +{ + if (&src != this) + { + VMA_HEAVY_ASSERT(IsEmpty()); + m_Front = src.m_Front; + m_Back = src.m_Back; + m_Count = src.m_Count; + src.m_Front = src.m_Back = VMA_NULL; + src.m_Count = 0; + } + return *this; +} + +template +void VmaIntrusiveLinkedList::PushBack(ItemType* item) +{ + VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL); + if (IsEmpty()) + { + m_Front = item; + m_Back = item; + m_Count = 1; + } + else + { + ItemTypeTraits::AccessPrev(item) = m_Back; + ItemTypeTraits::AccessNext(m_Back) = item; + m_Back = item; + ++m_Count; + } +} + +template +void VmaIntrusiveLinkedList::PushFront(ItemType* item) +{ + VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL); + if (IsEmpty()) + { + m_Front = item; + m_Back = item; + m_Count = 1; + } + else + { + ItemTypeTraits::AccessNext(item) = m_Front; + ItemTypeTraits::AccessPrev(m_Front) = item; + m_Front = item; + ++m_Count; + } +} + +template +typename VmaIntrusiveLinkedList::ItemType* VmaIntrusiveLinkedList::PopBack() +{ + VMA_HEAVY_ASSERT(m_Count > 0); + ItemType* const backItem = m_Back; + ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem); + if (prevItem != VMA_NULL) + { + ItemTypeTraits::AccessNext(prevItem) = VMA_NULL; + } + m_Back = prevItem; + --m_Count; + ItemTypeTraits::AccessPrev(backItem) = VMA_NULL; + ItemTypeTraits::AccessNext(backItem) = VMA_NULL; + return backItem; +} + +template +typename VmaIntrusiveLinkedList::ItemType* VmaIntrusiveLinkedList::PopFront() +{ + VMA_HEAVY_ASSERT(m_Count > 0); + ItemType* const frontItem = m_Front; + ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem); + if (nextItem != VMA_NULL) + { + ItemTypeTraits::AccessPrev(nextItem) = VMA_NULL; + } + m_Front = nextItem; + --m_Count; + ItemTypeTraits::AccessPrev(frontItem) = VMA_NULL; + ItemTypeTraits::AccessNext(frontItem) = VMA_NULL; + return frontItem; +} + +template +void VmaIntrusiveLinkedList::InsertBefore(ItemType* existingItem, ItemType* newItem) +{ + VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL); + if (existingItem != VMA_NULL) + { + ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem); + ItemTypeTraits::AccessPrev(newItem) = prevItem; + ItemTypeTraits::AccessNext(newItem) = existingItem; + ItemTypeTraits::AccessPrev(existingItem) = newItem; + if (prevItem != VMA_NULL) + { + ItemTypeTraits::AccessNext(prevItem) = newItem; + } + else + { + VMA_HEAVY_ASSERT(m_Front == existingItem); + m_Front = newItem; + } + ++m_Count; + } + else + PushBack(newItem); +} + +template +void VmaIntrusiveLinkedList::InsertAfter(ItemType* existingItem, ItemType* newItem) +{ + VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL); + if (existingItem != VMA_NULL) + { + ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem); + ItemTypeTraits::AccessNext(newItem) = nextItem; + ItemTypeTraits::AccessPrev(newItem) = existingItem; + ItemTypeTraits::AccessNext(existingItem) = newItem; + if (nextItem != VMA_NULL) + { + ItemTypeTraits::AccessPrev(nextItem) = newItem; + } + else + { + VMA_HEAVY_ASSERT(m_Back == existingItem); + m_Back = newItem; + } + ++m_Count; + } + else + return PushFront(newItem); +} + +template +void VmaIntrusiveLinkedList::Remove(ItemType* item) +{ + VMA_HEAVY_ASSERT(item != VMA_NULL && m_Count > 0); + if (ItemTypeTraits::GetPrev(item) != VMA_NULL) + { + ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item); + } + else + { + VMA_HEAVY_ASSERT(m_Front == item); + m_Front = ItemTypeTraits::GetNext(item); + } + + if (ItemTypeTraits::GetNext(item) != VMA_NULL) + { + ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item); + } + else + { + VMA_HEAVY_ASSERT(m_Back == item); + m_Back = ItemTypeTraits::GetPrev(item); + } + ItemTypeTraits::AccessPrev(item) = VMA_NULL; + ItemTypeTraits::AccessNext(item) = VMA_NULL; + --m_Count; +} + +template +void VmaIntrusiveLinkedList::RemoveAll() +{ + if (!IsEmpty()) + { + ItemType* item = m_Back; + while (item != VMA_NULL) + { + ItemType* const prevItem = ItemTypeTraits::AccessPrev(item); + ItemTypeTraits::AccessPrev(item) = VMA_NULL; + ItemTypeTraits::AccessNext(item) = VMA_NULL; + item = prevItem; + } + m_Front = VMA_NULL; + m_Back = VMA_NULL; + m_Count = 0; + } +} +#endif // _VMA_INTRUSIVE_LINKED_LIST_FUNCTIONS +#endif // _VMA_INTRUSIVE_LINKED_LIST + +// Unused in this version. +#if 0 + +#ifndef _VMA_PAIR +template +struct VmaPair +{ + T1 first; + T2 second; + + VmaPair() : first(), second() {} + VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) {} +}; + +template +struct VmaPairFirstLess +{ + bool operator()(const VmaPair& lhs, const VmaPair& rhs) const + { + return lhs.first < rhs.first; + } + bool operator()(const VmaPair& lhs, const FirstT& rhsFirst) const + { + return lhs.first < rhsFirst; + } +}; +#endif // _VMA_PAIR + +#ifndef _VMA_MAP +/* Class compatible with subset of interface of std::unordered_map. +KeyT, ValueT must be POD because they will be stored in VmaVector. +*/ +template +class VmaMap +{ +public: + typedef VmaPair PairType; + typedef PairType* iterator; + + VmaMap(const VmaStlAllocator& allocator) : m_Vector(allocator) {} + + iterator begin() { return m_Vector.begin(); } + iterator end() { return m_Vector.end(); } + size_t size() { return m_Vector.size(); } + + void insert(const PairType& pair); + iterator find(const KeyT& key); + void erase(iterator it); + +private: + VmaVector< PairType, VmaStlAllocator> m_Vector; +}; + +#ifndef _VMA_MAP_FUNCTIONS +template +void VmaMap::insert(const PairType& pair) +{ + const size_t indexToInsert = VmaBinaryFindFirstNotLess( + m_Vector.data(), + m_Vector.data() + m_Vector.size(), + pair, + VmaPairFirstLess()) - m_Vector.data(); + VmaVectorInsert(m_Vector, indexToInsert, pair); +} + +template +VmaPair* VmaMap::find(const KeyT& key) +{ + PairType* it = VmaBinaryFindFirstNotLess( + m_Vector.data(), + m_Vector.data() + m_Vector.size(), + key, + VmaPairFirstLess()); + if ((it != m_Vector.end()) && (it->first == key)) + { + return it; + } + else + { + return m_Vector.end(); + } +} + +template +void VmaMap::erase(iterator it) +{ + VmaVectorRemove(m_Vector, it - m_Vector.begin()); +} +#endif // _VMA_MAP_FUNCTIONS +#endif // _VMA_MAP + +#endif // #if 0 + +#if !defined(_VMA_STRING_BUILDER) && VMA_STATS_STRING_ENABLED +class VmaStringBuilder +{ +public: + VmaStringBuilder(const VkAllocationCallbacks* allocationCallbacks) : m_Data(VmaStlAllocator(allocationCallbacks)) {} + ~VmaStringBuilder() = default; + + size_t GetLength() const { return m_Data.size(); } + const char* GetData() const { return m_Data.data(); } + void AddNewLine() { Add('\n'); } + void Add(char ch) { m_Data.push_back(ch); } + + void Add(const char* pStr); + void AddNumber(uint32_t num); + void AddNumber(uint64_t num); + void AddPointer(const void* ptr); + +private: + VmaVector> m_Data; +}; + +#ifndef _VMA_STRING_BUILDER_FUNCTIONS +void VmaStringBuilder::Add(const char* pStr) +{ + const size_t strLen = strlen(pStr); + if (strLen > 0) + { + const size_t oldCount = m_Data.size(); + m_Data.resize(oldCount + strLen); + memcpy(m_Data.data() + oldCount, pStr, strLen); + } +} + +void VmaStringBuilder::AddNumber(uint32_t num) +{ + char buf[11]; + buf[10] = '\0'; + char* p = &buf[10]; + do + { + *--p = '0' + (num % 10); + num /= 10; + } while (num); + Add(p); +} + +void VmaStringBuilder::AddNumber(uint64_t num) +{ + char buf[21]; + buf[20] = '\0'; + char* p = &buf[20]; + do + { + *--p = '0' + (num % 10); + num /= 10; + } while (num); + Add(p); +} + +void VmaStringBuilder::AddPointer(const void* ptr) +{ + char buf[21]; + VmaPtrToStr(buf, sizeof(buf), ptr); + Add(buf); +} +#endif //_VMA_STRING_BUILDER_FUNCTIONS +#endif // _VMA_STRING_BUILDER + +#if !defined(_VMA_JSON_WRITER) && VMA_STATS_STRING_ENABLED +/* +Allows to conveniently build a correct JSON document to be written to the +VmaStringBuilder passed to the constructor. +*/ +class VmaJsonWriter +{ + VMA_CLASS_NO_COPY(VmaJsonWriter) +public: + // sb - string builder to write the document to. Must remain alive for the whole lifetime of this object. + VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb); + ~VmaJsonWriter(); + + // Begins object by writing "{". + // Inside an object, you must call pairs of WriteString and a value, e.g.: + // j.BeginObject(true); j.WriteString("A"); j.WriteNumber(1); j.WriteString("B"); j.WriteNumber(2); j.EndObject(); + // Will write: { "A": 1, "B": 2 } + void BeginObject(bool singleLine = false); + // Ends object by writing "}". + void EndObject(); + + // Begins array by writing "[". + // Inside an array, you can write a sequence of any values. + void BeginArray(bool singleLine = false); + // Ends array by writing "[". + void EndArray(); + + // Writes a string value inside "". + // pStr can contain any ANSI characters, including '"', new line etc. - they will be properly escaped. + void WriteString(const char* pStr); + + // Begins writing a string value. + // Call BeginString, ContinueString, ContinueString, ..., EndString instead of + // WriteString to conveniently build the string content incrementally, made of + // parts including numbers. + void BeginString(const char* pStr = VMA_NULL); + // Posts next part of an open string. + void ContinueString(const char* pStr); + // Posts next part of an open string. The number is converted to decimal characters. + void ContinueString(uint32_t n); + void ContinueString(uint64_t n); + void ContinueString_Size(size_t n); + // Posts next part of an open string. Pointer value is converted to characters + // using "%p" formatting - shown as hexadecimal number, e.g.: 000000081276Ad00 + void ContinueString_Pointer(const void* ptr); + // Ends writing a string value by writing '"'. + void EndString(const char* pStr = VMA_NULL); + + // Writes a number value. + void WriteNumber(uint32_t n); + void WriteNumber(uint64_t n); + void WriteSize(size_t n); + // Writes a boolean value - false or true. + void WriteBool(bool b); + // Writes a null value. + void WriteNull(); + +private: + enum COLLECTION_TYPE + { + COLLECTION_TYPE_OBJECT, + COLLECTION_TYPE_ARRAY, + }; + struct StackItem + { + COLLECTION_TYPE type; + uint32_t valueCount; + bool singleLineMode; + }; + + static const char* const INDENT; + + VmaStringBuilder& m_SB; + VmaVector< StackItem, VmaStlAllocator > m_Stack; + bool m_InsideString; + + // Write size_t for less than 64bits + void WriteSize(size_t n, std::integral_constant) { m_SB.AddNumber(static_cast(n)); } + // Write size_t for 64bits + void WriteSize(size_t n, std::integral_constant) { m_SB.AddNumber(static_cast(n)); } + + void BeginValue(bool isString); + void WriteIndent(bool oneLess = false); +}; +const char* const VmaJsonWriter::INDENT = " "; + +#ifndef _VMA_JSON_WRITER_FUNCTIONS +VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) + : m_SB(sb), + m_Stack(VmaStlAllocator(pAllocationCallbacks)), + m_InsideString(false) {} + +VmaJsonWriter::~VmaJsonWriter() +{ + VMA_ASSERT(!m_InsideString); + VMA_ASSERT(m_Stack.empty()); +} + +void VmaJsonWriter::BeginObject(bool singleLine) +{ + VMA_ASSERT(!m_InsideString); + + BeginValue(false); + m_SB.Add('{'); + + StackItem item; + item.type = COLLECTION_TYPE_OBJECT; + item.valueCount = 0; + item.singleLineMode = singleLine; + m_Stack.push_back(item); +} + +void VmaJsonWriter::EndObject() +{ + VMA_ASSERT(!m_InsideString); + + WriteIndent(true); + m_SB.Add('}'); + + VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT); + m_Stack.pop_back(); +} + +void VmaJsonWriter::BeginArray(bool singleLine) +{ + VMA_ASSERT(!m_InsideString); + + BeginValue(false); + m_SB.Add('['); + + StackItem item; + item.type = COLLECTION_TYPE_ARRAY; + item.valueCount = 0; + item.singleLineMode = singleLine; + m_Stack.push_back(item); +} + +void VmaJsonWriter::EndArray() +{ + VMA_ASSERT(!m_InsideString); + + WriteIndent(true); + m_SB.Add(']'); + + VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY); + m_Stack.pop_back(); +} + +void VmaJsonWriter::WriteString(const char* pStr) +{ + BeginString(pStr); + EndString(); +} + +void VmaJsonWriter::BeginString(const char* pStr) +{ + VMA_ASSERT(!m_InsideString); + + BeginValue(true); + m_SB.Add('"'); + m_InsideString = true; + if (pStr != VMA_NULL && pStr[0] != '\0') + { + ContinueString(pStr); + } +} + +void VmaJsonWriter::ContinueString(const char* pStr) +{ + VMA_ASSERT(m_InsideString); + + const size_t strLen = strlen(pStr); + for (size_t i = 0; i < strLen; ++i) + { + char ch = pStr[i]; + if (ch == '\\') + { + m_SB.Add("\\\\"); + } + else if (ch == '"') + { + m_SB.Add("\\\""); + } + else if (ch >= 32) + { + m_SB.Add(ch); + } + else switch (ch) + { + case '\b': + m_SB.Add("\\b"); + break; + case '\f': + m_SB.Add("\\f"); + break; + case '\n': + m_SB.Add("\\n"); + break; + case '\r': + m_SB.Add("\\r"); + break; + case '\t': + m_SB.Add("\\t"); + break; + default: + VMA_ASSERT(0 && "Character not currently supported."); + break; + } + } +} + +void VmaJsonWriter::ContinueString(uint32_t n) +{ + VMA_ASSERT(m_InsideString); + m_SB.AddNumber(n); +} + +void VmaJsonWriter::ContinueString(uint64_t n) +{ + VMA_ASSERT(m_InsideString); + m_SB.AddNumber(n); +} + +void VmaJsonWriter::ContinueString_Size(size_t n) +{ + VMA_ASSERT(m_InsideString); + // Fix for AppleClang incorrect type casting + // TODO: Change to if constexpr when C++17 used as minimal standard + WriteSize(n, std::is_same{}); +} + +void VmaJsonWriter::ContinueString_Pointer(const void* ptr) +{ + VMA_ASSERT(m_InsideString); + m_SB.AddPointer(ptr); +} + +void VmaJsonWriter::EndString(const char* pStr) +{ + VMA_ASSERT(m_InsideString); + if (pStr != VMA_NULL && pStr[0] != '\0') + { + ContinueString(pStr); + } + m_SB.Add('"'); + m_InsideString = false; +} + +void VmaJsonWriter::WriteNumber(uint32_t n) +{ + VMA_ASSERT(!m_InsideString); + BeginValue(false); + m_SB.AddNumber(n); +} + +void VmaJsonWriter::WriteNumber(uint64_t n) +{ + VMA_ASSERT(!m_InsideString); + BeginValue(false); + m_SB.AddNumber(n); +} + +void VmaJsonWriter::WriteSize(size_t n) +{ + VMA_ASSERT(!m_InsideString); + BeginValue(false); + // Fix for AppleClang incorrect type casting + // TODO: Change to if constexpr when C++17 used as minimal standard + WriteSize(n, std::is_same{}); +} + +void VmaJsonWriter::WriteBool(bool b) +{ + VMA_ASSERT(!m_InsideString); + BeginValue(false); + m_SB.Add(b ? "true" : "false"); +} + +void VmaJsonWriter::WriteNull() +{ + VMA_ASSERT(!m_InsideString); + BeginValue(false); + m_SB.Add("null"); +} + +void VmaJsonWriter::BeginValue(bool isString) +{ + if (!m_Stack.empty()) + { + StackItem& currItem = m_Stack.back(); + if (currItem.type == COLLECTION_TYPE_OBJECT && + currItem.valueCount % 2 == 0) + { + VMA_ASSERT(isString); + } + + if (currItem.type == COLLECTION_TYPE_OBJECT && + currItem.valueCount % 2 != 0) + { + m_SB.Add(": "); + } + else if (currItem.valueCount > 0) + { + m_SB.Add(", "); + WriteIndent(); + } + else + { + WriteIndent(); + } + ++currItem.valueCount; + } +} + +void VmaJsonWriter::WriteIndent(bool oneLess) +{ + if (!m_Stack.empty() && !m_Stack.back().singleLineMode) + { + m_SB.AddNewLine(); + + size_t count = m_Stack.size(); + if (count > 0 && oneLess) + { + --count; + } + for (size_t i = 0; i < count; ++i) + { + m_SB.Add(INDENT); + } + } +} +#endif // _VMA_JSON_WRITER_FUNCTIONS + +static void VmaPrintDetailedStatistics(VmaJsonWriter& json, const VmaDetailedStatistics& stat) +{ + json.BeginObject(); + + json.WriteString("BlockCount"); + json.WriteNumber(stat.statistics.blockCount); + json.WriteString("BlockBytes"); + json.WriteNumber(stat.statistics.blockBytes); + json.WriteString("AllocationCount"); + json.WriteNumber(stat.statistics.allocationCount); + json.WriteString("AllocationBytes"); + json.WriteNumber(stat.statistics.allocationBytes); + json.WriteString("UnusedRangeCount"); + json.WriteNumber(stat.unusedRangeCount); + + if (stat.statistics.allocationCount > 1) + { + json.WriteString("AllocationSizeMin"); + json.WriteNumber(stat.allocationSizeMin); + json.WriteString("AllocationSizeMax"); + json.WriteNumber(stat.allocationSizeMax); + } + if (stat.unusedRangeCount > 1) + { + json.WriteString("UnusedRangeSizeMin"); + json.WriteNumber(stat.unusedRangeSizeMin); + json.WriteString("UnusedRangeSizeMax"); + json.WriteNumber(stat.unusedRangeSizeMax); + } + json.EndObject(); +} +#endif // _VMA_JSON_WRITER + +#ifndef _VMA_MAPPING_HYSTERESIS + +class VmaMappingHysteresis +{ + VMA_CLASS_NO_COPY(VmaMappingHysteresis) +public: + VmaMappingHysteresis() = default; + + uint32_t GetExtraMapping() const { return m_ExtraMapping; } + + // Call when Map was called. + // Returns true if switched to extra +1 mapping reference count. + bool PostMap() + { +#if VMA_MAPPING_HYSTERESIS_ENABLED + if(m_ExtraMapping == 0) + { + ++m_MajorCounter; + if(m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING) + { + m_ExtraMapping = 1; + m_MajorCounter = 0; + m_MinorCounter = 0; + return true; + } + } + else // m_ExtraMapping == 1 + PostMinorCounter(); +#endif // #if VMA_MAPPING_HYSTERESIS_ENABLED + return false; + } + + // Call when Unmap was called. + void PostUnmap() + { +#if VMA_MAPPING_HYSTERESIS_ENABLED + if(m_ExtraMapping == 0) + ++m_MajorCounter; + else // m_ExtraMapping == 1 + PostMinorCounter(); +#endif // #if VMA_MAPPING_HYSTERESIS_ENABLED + } + + // Call when allocation was made from the memory block. + void PostAlloc() + { +#if VMA_MAPPING_HYSTERESIS_ENABLED + if(m_ExtraMapping == 1) + ++m_MajorCounter; + else // m_ExtraMapping == 0 + PostMinorCounter(); +#endif // #if VMA_MAPPING_HYSTERESIS_ENABLED + } + + // Call when allocation was freed from the memory block. + // Returns true if switched to extra -1 mapping reference count. + bool PostFree() + { +#if VMA_MAPPING_HYSTERESIS_ENABLED + if(m_ExtraMapping == 1) + { + ++m_MajorCounter; + if(m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING && + m_MajorCounter > m_MinorCounter + 1) + { + m_ExtraMapping = 0; + m_MajorCounter = 0; + m_MinorCounter = 0; + return true; + } + } + else // m_ExtraMapping == 0 + PostMinorCounter(); +#endif // #if VMA_MAPPING_HYSTERESIS_ENABLED + return false; + } + +private: + static const int32_t COUNTER_MIN_EXTRA_MAPPING = 7; + + uint32_t m_MinorCounter = 0; + uint32_t m_MajorCounter = 0; + uint32_t m_ExtraMapping = 0; // 0 or 1. + + void PostMinorCounter() + { + if(m_MinorCounter < m_MajorCounter) + { + ++m_MinorCounter; + } + else if(m_MajorCounter > 0) + { + --m_MajorCounter; + --m_MinorCounter; + } + } +}; + +#endif // _VMA_MAPPING_HYSTERESIS + +#ifndef _VMA_DEVICE_MEMORY_BLOCK +/* +Represents a single block of device memory (`VkDeviceMemory`) with all the +data about its regions (aka suballocations, #VmaAllocation), assigned and free. + +Thread-safety: +- Access to m_pMetadata must be externally synchronized. +- Map, Unmap, Bind* are synchronized internally. +*/ +class VmaDeviceMemoryBlock +{ + VMA_CLASS_NO_COPY(VmaDeviceMemoryBlock) +public: + VmaBlockMetadata* m_pMetadata; + + VmaDeviceMemoryBlock(VmaAllocator hAllocator); + ~VmaDeviceMemoryBlock(); + + // Always call after construction. + void Init( + VmaAllocator hAllocator, + VmaPool hParentPool, + uint32_t newMemoryTypeIndex, + VkDeviceMemory newMemory, + VkDeviceSize newSize, + uint32_t id, + uint32_t algorithm, + VkDeviceSize bufferImageGranularity); + // Always call before destruction. + void Destroy(VmaAllocator allocator); + + VmaPool GetParentPool() const { return m_hParentPool; } + VkDeviceMemory GetDeviceMemory() const { return m_hMemory; } + uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } + uint32_t GetId() const { return m_Id; } + void* GetMappedData() const { return m_pMappedData; } + uint32_t GetMapRefCount() const { return m_MapCount; } + + // Call when allocation/free was made from m_pMetadata. + // Used for m_MappingHysteresis. + void PostAlloc() { m_MappingHysteresis.PostAlloc(); } + void PostFree(VmaAllocator hAllocator); + + // Validates all data structures inside this object. If not valid, returns false. + bool Validate() const; + VkResult CheckCorruption(VmaAllocator hAllocator); + + // ppData can be null. + VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData); + void Unmap(VmaAllocator hAllocator, uint32_t count); + + VkResult WriteMagicValueAfterAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize); + VkResult ValidateMagicValueAfterAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize); + + VkResult BindBufferMemory( + const VmaAllocator hAllocator, + const VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkBuffer hBuffer, + const void* pNext); + VkResult BindImageMemory( + const VmaAllocator hAllocator, + const VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkImage hImage, + const void* pNext); + +private: + VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. + uint32_t m_MemoryTypeIndex; + uint32_t m_Id; + VkDeviceMemory m_hMemory; + + /* + Protects access to m_hMemory so it is not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory. + Also protects m_MapCount, m_pMappedData. + Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex. + */ + VMA_MUTEX m_MapAndBindMutex; + VmaMappingHysteresis m_MappingHysteresis; + uint32_t m_MapCount; + void* m_pMappedData; +}; +#endif // _VMA_DEVICE_MEMORY_BLOCK + +#ifndef _VMA_ALLOCATION_T +struct VmaAllocation_T +{ + friend struct VmaDedicatedAllocationListItemTraits; + + enum FLAGS + { + FLAG_PERSISTENT_MAP = 0x01, + FLAG_MAPPING_ALLOWED = 0x02, + }; + +public: + enum ALLOCATION_TYPE + { + ALLOCATION_TYPE_NONE, + ALLOCATION_TYPE_BLOCK, + ALLOCATION_TYPE_DEDICATED, + }; + + // This struct is allocated using VmaPoolAllocator. + VmaAllocation_T(bool mappingAllowed); + ~VmaAllocation_T(); + + void InitBlockAllocation( + VmaDeviceMemoryBlock* block, + VmaAllocHandle allocHandle, + VkDeviceSize alignment, + VkDeviceSize size, + uint32_t memoryTypeIndex, + VmaSuballocationType suballocationType, + bool mapped); + // pMappedData not null means allocation is created with MAPPED flag. + void InitDedicatedAllocation( + VmaPool hParentPool, + uint32_t memoryTypeIndex, + VkDeviceMemory hMemory, + VmaSuballocationType suballocationType, + void* pMappedData, + VkDeviceSize size); + + ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; } + VkDeviceSize GetAlignment() const { return m_Alignment; } + VkDeviceSize GetSize() const { return m_Size; } + void* GetUserData() const { return m_pUserData; } + const char* GetName() const { return m_pName; } + VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; } + + VmaDeviceMemoryBlock* GetBlock() const { VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); return m_BlockAllocation.m_Block; } + uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } + bool IsPersistentMap() const { return (m_Flags & FLAG_PERSISTENT_MAP) != 0; } + bool IsMappingAllowed() const { return (m_Flags & FLAG_MAPPING_ALLOWED) != 0; } + + void SetUserData(VmaAllocator hAllocator, void* pUserData) { m_pUserData = pUserData; } + void SetName(VmaAllocator hAllocator, const char* pName); + void FreeName(VmaAllocator hAllocator); + uint8_t SwapBlockAllocation(VmaAllocator hAllocator, VmaAllocation allocation); + VmaAllocHandle GetAllocHandle() const; + VkDeviceSize GetOffset() const; + VmaPool GetParentPool() const; + VkDeviceMemory GetMemory() const; + void* GetMappedData() const; + + void BlockAllocMap(); + void BlockAllocUnmap(); + VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData); + void DedicatedAllocUnmap(VmaAllocator hAllocator); + +#if VMA_STATS_STRING_ENABLED + uint32_t GetBufferImageUsage() const { return m_BufferImageUsage; } + + void InitBufferImageUsage(uint32_t bufferImageUsage); + void PrintParameters(class VmaJsonWriter& json) const; +#endif + +private: + // Allocation out of VmaDeviceMemoryBlock. + struct BlockAllocation + { + VmaDeviceMemoryBlock* m_Block; + VmaAllocHandle m_AllocHandle; + }; + // Allocation for an object that has its own private VkDeviceMemory. + struct DedicatedAllocation + { + VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. + VkDeviceMemory m_hMemory; + void* m_pMappedData; // Not null means memory is mapped. + VmaAllocation_T* m_Prev; + VmaAllocation_T* m_Next; + }; + union + { + // Allocation out of VmaDeviceMemoryBlock. + BlockAllocation m_BlockAllocation; + // Allocation for an object that has its own private VkDeviceMemory. + DedicatedAllocation m_DedicatedAllocation; + }; + + VkDeviceSize m_Alignment; + VkDeviceSize m_Size; + void* m_pUserData; + char* m_pName; + uint32_t m_MemoryTypeIndex; + uint8_t m_Type; // ALLOCATION_TYPE + uint8_t m_SuballocationType; // VmaSuballocationType + // Reference counter for vmaMapMemory()/vmaUnmapMemory(). + uint8_t m_MapCount; + uint8_t m_Flags; // enum FLAGS +#if VMA_STATS_STRING_ENABLED + uint32_t m_BufferImageUsage; // 0 if unknown. +#endif +}; +#endif // _VMA_ALLOCATION_T + +#ifndef _VMA_DEDICATED_ALLOCATION_LIST_ITEM_TRAITS +struct VmaDedicatedAllocationListItemTraits +{ + typedef VmaAllocation_T ItemType; + + static ItemType* GetPrev(const ItemType* item) + { + VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + return item->m_DedicatedAllocation.m_Prev; + } + static ItemType* GetNext(const ItemType* item) + { + VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + return item->m_DedicatedAllocation.m_Next; + } + static ItemType*& AccessPrev(ItemType* item) + { + VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + return item->m_DedicatedAllocation.m_Prev; + } + static ItemType*& AccessNext(ItemType* item) + { + VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + return item->m_DedicatedAllocation.m_Next; + } +}; +#endif // _VMA_DEDICATED_ALLOCATION_LIST_ITEM_TRAITS + +#ifndef _VMA_DEDICATED_ALLOCATION_LIST +/* +Stores linked list of VmaAllocation_T objects. +Thread-safe, synchronized internally. +*/ +class VmaDedicatedAllocationList +{ +public: + VmaDedicatedAllocationList() {} + ~VmaDedicatedAllocationList(); + + void Init(bool useMutex) { m_UseMutex = useMutex; } + bool Validate(); + + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats); + void AddStatistics(VmaStatistics& inoutStats); +#if VMA_STATS_STRING_ENABLED + // Writes JSON array with the list of allocations. + void BuildStatsString(VmaJsonWriter& json); +#endif + + bool IsEmpty(); + void Register(VmaAllocation alloc); + void Unregister(VmaAllocation alloc); + +private: + typedef VmaIntrusiveLinkedList DedicatedAllocationLinkedList; + + bool m_UseMutex = true; + VMA_RW_MUTEX m_Mutex; + DedicatedAllocationLinkedList m_AllocationList; +}; + +#ifndef _VMA_DEDICATED_ALLOCATION_LIST_FUNCTIONS + +VmaDedicatedAllocationList::~VmaDedicatedAllocationList() +{ + VMA_HEAVY_ASSERT(Validate()); + + if (!m_AllocationList.IsEmpty()) + { + VMA_ASSERT(false && "Unfreed dedicated allocations found!"); + } +} + +bool VmaDedicatedAllocationList::Validate() +{ + const size_t declaredCount = m_AllocationList.GetCount(); + size_t actualCount = 0; + VmaMutexLockRead lock(m_Mutex, m_UseMutex); + for (VmaAllocation alloc = m_AllocationList.Front(); + alloc != VMA_NULL; alloc = m_AllocationList.GetNext(alloc)) + { + ++actualCount; + } + VMA_VALIDATE(actualCount == declaredCount); + + return true; +} + +void VmaDedicatedAllocationList::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) +{ + for(auto* item = m_AllocationList.Front(); item != nullptr; item = DedicatedAllocationLinkedList::GetNext(item)) + { + const VkDeviceSize size = item->GetSize(); + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += size; + VmaAddDetailedStatisticsAllocation(inoutStats, item->GetSize()); + } +} + +void VmaDedicatedAllocationList::AddStatistics(VmaStatistics& inoutStats) +{ + VmaMutexLockRead lock(m_Mutex, m_UseMutex); + + const uint32_t allocCount = (uint32_t)m_AllocationList.GetCount(); + inoutStats.blockCount += allocCount; + inoutStats.allocationCount += allocCount; + + for(auto* item = m_AllocationList.Front(); item != nullptr; item = DedicatedAllocationLinkedList::GetNext(item)) + { + const VkDeviceSize size = item->GetSize(); + inoutStats.blockBytes += size; + inoutStats.allocationBytes += size; + } +} + +#if VMA_STATS_STRING_ENABLED +void VmaDedicatedAllocationList::BuildStatsString(VmaJsonWriter& json) +{ + VmaMutexLockRead lock(m_Mutex, m_UseMutex); + json.BeginArray(); + for (VmaAllocation alloc = m_AllocationList.Front(); + alloc != VMA_NULL; alloc = m_AllocationList.GetNext(alloc)) + { + json.BeginObject(true); + alloc->PrintParameters(json); + json.EndObject(); + } + json.EndArray(); +} +#endif // VMA_STATS_STRING_ENABLED + +bool VmaDedicatedAllocationList::IsEmpty() +{ + VmaMutexLockRead lock(m_Mutex, m_UseMutex); + return m_AllocationList.IsEmpty(); +} + +void VmaDedicatedAllocationList::Register(VmaAllocation alloc) +{ + VmaMutexLockWrite lock(m_Mutex, m_UseMutex); + m_AllocationList.PushBack(alloc); +} + +void VmaDedicatedAllocationList::Unregister(VmaAllocation alloc) +{ + VmaMutexLockWrite lock(m_Mutex, m_UseMutex); + m_AllocationList.Remove(alloc); +} +#endif // _VMA_DEDICATED_ALLOCATION_LIST_FUNCTIONS +#endif // _VMA_DEDICATED_ALLOCATION_LIST + +#ifndef _VMA_SUBALLOCATION +/* +Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as +allocated memory block or free. +*/ +struct VmaSuballocation +{ + VkDeviceSize offset; + VkDeviceSize size; + void* userData; + VmaSuballocationType type; +}; + +// Comparator for offsets. +struct VmaSuballocationOffsetLess +{ + bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const + { + return lhs.offset < rhs.offset; + } +}; + +struct VmaSuballocationOffsetGreater +{ + bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const + { + return lhs.offset > rhs.offset; + } +}; + +struct VmaSuballocationItemSizeLess +{ + bool operator()(const VmaSuballocationList::iterator lhs, + const VmaSuballocationList::iterator rhs) const + { + return lhs->size < rhs->size; + } + + bool operator()(const VmaSuballocationList::iterator lhs, + VkDeviceSize rhsSize) const + { + return lhs->size < rhsSize; + } +}; +#endif // _VMA_SUBALLOCATION + +#ifndef _VMA_ALLOCATION_REQUEST +/* +Parameters of planned allocation inside a VmaDeviceMemoryBlock. +item points to a FREE suballocation. +*/ +struct VmaAllocationRequest +{ + VmaAllocHandle allocHandle; + VkDeviceSize size; + VmaSuballocationList::iterator item; + void* customData; + uint64_t algorithmData; + VmaAllocationRequestType type; +}; +#endif // _VMA_ALLOCATION_REQUEST + +#ifndef _VMA_BLOCK_METADATA +/* +Data structure used for bookkeeping of allocations and unused ranges of memory +in a single VkDeviceMemory block. +*/ +class VmaBlockMetadata +{ +public: + // pAllocationCallbacks, if not null, must be owned externally - alive and unchanged for the whole lifetime of this object. + VmaBlockMetadata(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata() = default; + + virtual void Init(VkDeviceSize size) { m_Size = size; } + bool IsVirtual() const { return m_IsVirtual; } + VkDeviceSize GetSize() const { return m_Size; } + + // Validates all data structures inside this object. If not valid, returns false. + virtual bool Validate() const = 0; + virtual size_t GetAllocationCount() const = 0; + virtual size_t GetFreeRegionsCount() const = 0; + virtual VkDeviceSize GetSumFreeSize() const = 0; + // Returns true if this block is empty - contains only single free suballocation. + virtual bool IsEmpty() const = 0; + virtual void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) = 0; + virtual VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const = 0; + virtual void* GetAllocationUserData(VmaAllocHandle allocHandle) const = 0; + + virtual VmaAllocHandle GetAllocationListBegin() const = 0; + virtual VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const = 0; + virtual VkDeviceSize GetNextFreeRegionSize(VmaAllocHandle alloc) const = 0; + + // Shouldn't modify blockCount. + virtual void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const = 0; + virtual void AddStatistics(VmaStatistics& inoutStats) const = 0; + +#if VMA_STATS_STRING_ENABLED + virtual void PrintDetailedMap(class VmaJsonWriter& json) const = 0; +#endif + + // Tries to find a place for suballocation with given parameters inside this block. + // If succeeded, fills pAllocationRequest and returns true. + // If failed, returns false. + virtual bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* or VMA_ALLOCATION_INTERNAL_STRATEGY_* flags. + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) = 0; + + virtual VkResult CheckCorruption(const void* pBlockData) = 0; + + // Makes actual allocation based on request. Request must already be checked and valid. + virtual void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) = 0; + + // Frees suballocation assigned to given memory region. + virtual void Free(VmaAllocHandle allocHandle) = 0; + + // Frees all allocations. + // Careful! Don't call it if there are VmaAllocation objects owned by userData of cleared allocations! + virtual void Clear() = 0; + + virtual void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) = 0; + virtual void DebugLogAllAllocations() const = 0; + +protected: + const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; } + VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; } + VkDeviceSize GetDebugMargin() const { return IsVirtual() ? 0 : VMA_DEBUG_MARGIN; } + + void DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size, void* userData) const; +#if VMA_STATS_STRING_ENABLED + // mapRefCount == UINT32_MAX means unspecified. + void PrintDetailedMap_Begin(class VmaJsonWriter& json, + VkDeviceSize unusedBytes, + size_t allocationCount, + size_t unusedRangeCount) const; + void PrintDetailedMap_Allocation(class VmaJsonWriter& json, + VkDeviceSize offset, VkDeviceSize size, void* userData) const; + void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json, + VkDeviceSize offset, + VkDeviceSize size) const; + void PrintDetailedMap_End(class VmaJsonWriter& json) const; +#endif + +private: + VkDeviceSize m_Size; + const VkAllocationCallbacks* m_pAllocationCallbacks; + const VkDeviceSize m_BufferImageGranularity; + const bool m_IsVirtual; +}; + +#ifndef _VMA_BLOCK_METADATA_FUNCTIONS +VmaBlockMetadata::VmaBlockMetadata(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : m_Size(0), + m_pAllocationCallbacks(pAllocationCallbacks), + m_BufferImageGranularity(bufferImageGranularity), + m_IsVirtual(isVirtual) {} + +void VmaBlockMetadata::DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size, void* userData) const +{ + if (IsVirtual()) + { + VMA_DEBUG_LOG("UNFREED VIRTUAL ALLOCATION; Offset: %llu; Size: %llu; UserData: %p", offset, size, userData); + } + else + { + VMA_ASSERT(userData != VMA_NULL); + VmaAllocation allocation = reinterpret_cast(userData); + + userData = allocation->GetUserData(); + const char* name = allocation->GetName(); + +#if VMA_STATS_STRING_ENABLED + VMA_DEBUG_LOG("UNFREED ALLOCATION; Offset: %llu; Size: %llu; UserData: %p; Name: %s; Type: %s; Usage: %u", + offset, size, userData, name ? name : "vma_empty", + VMA_SUBALLOCATION_TYPE_NAMES[allocation->GetSuballocationType()], + allocation->GetBufferImageUsage()); +#else + VMA_DEBUG_LOG("UNFREED ALLOCATION; Offset: %llu; Size: %llu; UserData: %p; Name: %s; Type: %u", + offset, size, userData, name ? name : "vma_empty", + (uint32_t)allocation->GetSuballocationType()); +#endif // VMA_STATS_STRING_ENABLED + } + +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json, + VkDeviceSize unusedBytes, size_t allocationCount, size_t unusedRangeCount) const +{ + json.WriteString("TotalBytes"); + json.WriteNumber(GetSize()); + + json.WriteString("UnusedBytes"); + json.WriteSize(unusedBytes); + + json.WriteString("Allocations"); + json.WriteSize(allocationCount); + + json.WriteString("UnusedRanges"); + json.WriteSize(unusedRangeCount); + + json.WriteString("Suballocations"); + json.BeginArray(); +} + +void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json, + VkDeviceSize offset, VkDeviceSize size, void* userData) const +{ + json.BeginObject(true); + + json.WriteString("Offset"); + json.WriteNumber(offset); + + if (IsVirtual()) + { + json.WriteString("Size"); + json.WriteNumber(size); + if (userData) + { + json.WriteString("CustomData"); + json.BeginString(); + json.ContinueString_Pointer(userData); + json.EndString(); + } + } + else + { + ((VmaAllocation)userData)->PrintParameters(json); + } + + json.EndObject(); +} + +void VmaBlockMetadata::PrintDetailedMap_UnusedRange(class VmaJsonWriter& json, + VkDeviceSize offset, VkDeviceSize size) const +{ + json.BeginObject(true); + + json.WriteString("Offset"); + json.WriteNumber(offset); + + json.WriteString("Type"); + json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[VMA_SUBALLOCATION_TYPE_FREE]); + + json.WriteString("Size"); + json.WriteNumber(size); + + json.EndObject(); +} + +void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) const +{ + json.EndArray(); +} +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_BLOCK_METADATA_FUNCTIONS +#endif // _VMA_BLOCK_METADATA + +#ifndef _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY +// Before deleting object of this class remember to call 'Destroy()' +class VmaBlockBufferImageGranularity final +{ +public: + struct ValidationContext + { + const VkAllocationCallbacks* allocCallbacks; + uint16_t* pageAllocs; + }; + + VmaBlockBufferImageGranularity(VkDeviceSize bufferImageGranularity); + ~VmaBlockBufferImageGranularity(); + + bool IsEnabled() const { return m_BufferImageGranularity > MAX_LOW_BUFFER_IMAGE_GRANULARITY; } + + void Init(const VkAllocationCallbacks* pAllocationCallbacks, VkDeviceSize size); + // Before destroying object you must call free it's memory + void Destroy(const VkAllocationCallbacks* pAllocationCallbacks); + + void RoundupAllocRequest(VmaSuballocationType allocType, + VkDeviceSize& inOutAllocSize, + VkDeviceSize& inOutAllocAlignment) const; + + bool CheckConflictAndAlignUp(VkDeviceSize& inOutAllocOffset, + VkDeviceSize allocSize, + VkDeviceSize blockOffset, + VkDeviceSize blockSize, + VmaSuballocationType allocType) const; + + void AllocPages(uint8_t allocType, VkDeviceSize offset, VkDeviceSize size); + void FreePages(VkDeviceSize offset, VkDeviceSize size); + void Clear(); + + ValidationContext StartValidation(const VkAllocationCallbacks* pAllocationCallbacks, + bool isVirutal) const; + bool Validate(ValidationContext& ctx, VkDeviceSize offset, VkDeviceSize size) const; + bool FinishValidation(ValidationContext& ctx) const; + +private: + static const uint16_t MAX_LOW_BUFFER_IMAGE_GRANULARITY = 256; + + struct RegionInfo + { + uint8_t allocType; + uint16_t allocCount; + }; + + VkDeviceSize m_BufferImageGranularity; + uint32_t m_RegionCount; + RegionInfo* m_RegionInfo; + + uint32_t GetStartPage(VkDeviceSize offset) const { return OffsetToPageIndex(offset & ~(m_BufferImageGranularity - 1)); } + uint32_t GetEndPage(VkDeviceSize offset, VkDeviceSize size) const { return OffsetToPageIndex((offset + size - 1) & ~(m_BufferImageGranularity - 1)); } + + uint32_t OffsetToPageIndex(VkDeviceSize offset) const; + void AllocPage(RegionInfo& page, uint8_t allocType); +}; + +#ifndef _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY_FUNCTIONS +VmaBlockBufferImageGranularity::VmaBlockBufferImageGranularity(VkDeviceSize bufferImageGranularity) + : m_BufferImageGranularity(bufferImageGranularity), + m_RegionCount(0), + m_RegionInfo(VMA_NULL) {} + +VmaBlockBufferImageGranularity::~VmaBlockBufferImageGranularity() +{ + VMA_ASSERT(m_RegionInfo == VMA_NULL && "Free not called before destroying object!"); +} + +void VmaBlockBufferImageGranularity::Init(const VkAllocationCallbacks* pAllocationCallbacks, VkDeviceSize size) +{ + if (IsEnabled()) + { + m_RegionCount = static_cast(VmaDivideRoundingUp(size, m_BufferImageGranularity)); + m_RegionInfo = vma_new_array(pAllocationCallbacks, RegionInfo, m_RegionCount); + memset(m_RegionInfo, 0, m_RegionCount * sizeof(RegionInfo)); + } +} + +void VmaBlockBufferImageGranularity::Destroy(const VkAllocationCallbacks* pAllocationCallbacks) +{ + if (m_RegionInfo) + { + vma_delete_array(pAllocationCallbacks, m_RegionInfo, m_RegionCount); + m_RegionInfo = VMA_NULL; + } +} + +void VmaBlockBufferImageGranularity::RoundupAllocRequest(VmaSuballocationType allocType, + VkDeviceSize& inOutAllocSize, + VkDeviceSize& inOutAllocAlignment) const +{ + if (m_BufferImageGranularity > 1 && + m_BufferImageGranularity <= MAX_LOW_BUFFER_IMAGE_GRANULARITY) + { + if (allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN || + allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || + allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL) + { + inOutAllocAlignment = VMA_MAX(inOutAllocAlignment, m_BufferImageGranularity); + inOutAllocSize = VmaAlignUp(inOutAllocSize, m_BufferImageGranularity); + } + } +} + +bool VmaBlockBufferImageGranularity::CheckConflictAndAlignUp(VkDeviceSize& inOutAllocOffset, + VkDeviceSize allocSize, + VkDeviceSize blockOffset, + VkDeviceSize blockSize, + VmaSuballocationType allocType) const +{ + if (IsEnabled()) + { + uint32_t startPage = GetStartPage(inOutAllocOffset); + if (m_RegionInfo[startPage].allocCount > 0 && + VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[startPage].allocType), allocType)) + { + inOutAllocOffset = VmaAlignUp(inOutAllocOffset, m_BufferImageGranularity); + if (blockSize < allocSize + inOutAllocOffset - blockOffset) + return true; + ++startPage; + } + uint32_t endPage = GetEndPage(inOutAllocOffset, allocSize); + if (endPage != startPage && + m_RegionInfo[endPage].allocCount > 0 && + VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[endPage].allocType), allocType)) + { + return true; + } + } + return false; +} + +void VmaBlockBufferImageGranularity::AllocPages(uint8_t allocType, VkDeviceSize offset, VkDeviceSize size) +{ + if (IsEnabled()) + { + uint32_t startPage = GetStartPage(offset); + AllocPage(m_RegionInfo[startPage], allocType); + + uint32_t endPage = GetEndPage(offset, size); + if (startPage != endPage) + AllocPage(m_RegionInfo[endPage], allocType); + } +} + +void VmaBlockBufferImageGranularity::FreePages(VkDeviceSize offset, VkDeviceSize size) +{ + if (IsEnabled()) + { + uint32_t startPage = GetStartPage(offset); + --m_RegionInfo[startPage].allocCount; + if (m_RegionInfo[startPage].allocCount == 0) + m_RegionInfo[startPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; + uint32_t endPage = GetEndPage(offset, size); + if (startPage != endPage) + { + --m_RegionInfo[endPage].allocCount; + if (m_RegionInfo[endPage].allocCount == 0) + m_RegionInfo[endPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; + } + } +} + +void VmaBlockBufferImageGranularity::Clear() +{ + if (m_RegionInfo) + memset(m_RegionInfo, 0, m_RegionCount * sizeof(RegionInfo)); +} + +VmaBlockBufferImageGranularity::ValidationContext VmaBlockBufferImageGranularity::StartValidation( + const VkAllocationCallbacks* pAllocationCallbacks, bool isVirutal) const +{ + ValidationContext ctx{ pAllocationCallbacks, VMA_NULL }; + if (!isVirutal && IsEnabled()) + { + ctx.pageAllocs = vma_new_array(pAllocationCallbacks, uint16_t, m_RegionCount); + memset(ctx.pageAllocs, 0, m_RegionCount * sizeof(uint16_t)); + } + return ctx; +} + +bool VmaBlockBufferImageGranularity::Validate(ValidationContext& ctx, + VkDeviceSize offset, VkDeviceSize size) const +{ + if (IsEnabled()) + { + uint32_t start = GetStartPage(offset); + ++ctx.pageAllocs[start]; + VMA_VALIDATE(m_RegionInfo[start].allocCount > 0); + + uint32_t end = GetEndPage(offset, size); + if (start != end) + { + ++ctx.pageAllocs[end]; + VMA_VALIDATE(m_RegionInfo[end].allocCount > 0); + } + } + return true; +} + +bool VmaBlockBufferImageGranularity::FinishValidation(ValidationContext& ctx) const +{ + // Check proper page structure + if (IsEnabled()) + { + VMA_ASSERT(ctx.pageAllocs != VMA_NULL && "Validation context not initialized!"); + + for (uint32_t page = 0; page < m_RegionCount; ++page) + { + VMA_VALIDATE(ctx.pageAllocs[page] == m_RegionInfo[page].allocCount); + } + vma_delete_array(ctx.allocCallbacks, ctx.pageAllocs, m_RegionCount); + ctx.pageAllocs = VMA_NULL; + } + return true; +} + +uint32_t VmaBlockBufferImageGranularity::OffsetToPageIndex(VkDeviceSize offset) const +{ + return static_cast(offset >> VMA_BITSCAN_MSB(m_BufferImageGranularity)); +} + +void VmaBlockBufferImageGranularity::AllocPage(RegionInfo& page, uint8_t allocType) +{ + // When current alloc type is free then it can be overriden by new type + if (page.allocCount == 0 || (page.allocCount > 0 && page.allocType == VMA_SUBALLOCATION_TYPE_FREE)) + page.allocType = allocType; + + ++page.allocCount; +} +#endif // _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY_FUNCTIONS +#endif // _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY + +#if 0 +#ifndef _VMA_BLOCK_METADATA_GENERIC +class VmaBlockMetadata_Generic : public VmaBlockMetadata +{ + friend class VmaDefragmentationAlgorithm_Generic; + friend class VmaDefragmentationAlgorithm_Fast; + VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic) +public: + VmaBlockMetadata_Generic(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata_Generic() = default; + + size_t GetAllocationCount() const override { return m_Suballocations.size() - m_FreeCount; } + VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize; } + bool IsEmpty() const override { return (m_Suballocations.size() == 1) && (m_FreeCount == 1); } + void Free(VmaAllocHandle allocHandle) override { FreeSuballocation(FindAtOffset((VkDeviceSize)allocHandle - 1)); } + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; }; + + void Init(VkDeviceSize size) override; + bool Validate() const override; + + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; + void AddStatistics(VmaStatistics& inoutStats) const override; + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const override; +#endif + + bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) override; + + VkResult CheckCorruption(const void* pBlockData) override; + + void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) override; + + void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; + void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; + VmaAllocHandle GetAllocationListBegin() const override; + VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; + void Clear() override; + void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; + void DebugLogAllAllocations() const override; + +private: + uint32_t m_FreeCount; + VkDeviceSize m_SumFreeSize; + VmaSuballocationList m_Suballocations; + // Suballocations that are free. Sorted by size, ascending. + VmaVector> m_FreeSuballocationsBySize; + + VkDeviceSize AlignAllocationSize(VkDeviceSize size) const { return IsVirtual() ? size : VmaAlignUp(size, (VkDeviceSize)16); } + + VmaSuballocationList::iterator FindAtOffset(VkDeviceSize offset) const; + bool ValidateFreeSuballocationList() const; + + // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem. + // If yes, fills pOffset and returns true. If no, returns false. + bool CheckAllocation( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + VmaSuballocationList::const_iterator suballocItem, + VmaAllocHandle* pAllocHandle) const; + + // Given free suballocation, it merges it with following one, which must also be free. + void MergeFreeWithNext(VmaSuballocationList::iterator item); + // Releases given suballocation, making it free. + // Merges it with adjacent free suballocations if applicable. + // Returns iterator to new free suballocation at this place. + VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem); + // Given free suballocation, it inserts it into sorted list of + // m_FreeSuballocationsBySize if it is suitable. + void RegisterFreeSuballocation(VmaSuballocationList::iterator item); + // Given free suballocation, it removes it from sorted list of + // m_FreeSuballocationsBySize if it is suitable. + void UnregisterFreeSuballocation(VmaSuballocationList::iterator item); +}; + +#ifndef _VMA_BLOCK_METADATA_GENERIC_FUNCTIONS +VmaBlockMetadata_Generic::VmaBlockMetadata_Generic(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), + m_FreeCount(0), + m_SumFreeSize(0), + m_Suballocations(VmaStlAllocator(pAllocationCallbacks)), + m_FreeSuballocationsBySize(VmaStlAllocator(pAllocationCallbacks)) {} + +void VmaBlockMetadata_Generic::Init(VkDeviceSize size) +{ + VmaBlockMetadata::Init(size); + + m_FreeCount = 1; + m_SumFreeSize = size; + + VmaSuballocation suballoc = {}; + suballoc.offset = 0; + suballoc.size = size; + suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + + m_Suballocations.push_back(suballoc); + m_FreeSuballocationsBySize.push_back(m_Suballocations.begin()); +} + +bool VmaBlockMetadata_Generic::Validate() const +{ + VMA_VALIDATE(!m_Suballocations.empty()); + + // Expected offset of new suballocation as calculated from previous ones. + VkDeviceSize calculatedOffset = 0; + // Expected number of free suballocations as calculated from traversing their list. + uint32_t calculatedFreeCount = 0; + // Expected sum size of free suballocations as calculated from traversing their list. + VkDeviceSize calculatedSumFreeSize = 0; + // Expected number of free suballocations that should be registered in + // m_FreeSuballocationsBySize calculated from traversing their list. + size_t freeSuballocationsToRegister = 0; + // True if previous visited suballocation was free. + bool prevFree = false; + + const VkDeviceSize debugMargin = GetDebugMargin(); + + for (const auto& subAlloc : m_Suballocations) + { + // Actual offset of this suballocation doesn't match expected one. + VMA_VALIDATE(subAlloc.offset == calculatedOffset); + + const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE); + // Two adjacent free suballocations are invalid. They should be merged. + VMA_VALIDATE(!prevFree || !currFree); + + VmaAllocation alloc = (VmaAllocation)subAlloc.userData; + if (!IsVirtual()) + { + VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); + } + + if (currFree) + { + calculatedSumFreeSize += subAlloc.size; + ++calculatedFreeCount; + ++freeSuballocationsToRegister; + + // Margin required between allocations - every free space must be at least that large. + VMA_VALIDATE(subAlloc.size >= debugMargin); + } + else + { + if (!IsVirtual()) + { + VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == subAlloc.offset + 1); + VMA_VALIDATE(alloc->GetSize() == subAlloc.size); + } + + // Margin required between allocations - previous allocation must be free. + VMA_VALIDATE(debugMargin == 0 || prevFree); + } + + calculatedOffset += subAlloc.size; + prevFree = currFree; + } + + // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't + // match expected one. + VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister); + + VkDeviceSize lastSize = 0; + for (size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i) + { + VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i]; + + // Only free suballocations can be registered in m_FreeSuballocationsBySize. + VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE); + // They must be sorted by size ascending. + VMA_VALIDATE(suballocItem->size >= lastSize); + + lastSize = suballocItem->size; + } + + // Check if totals match calculated values. + VMA_VALIDATE(ValidateFreeSuballocationList()); + VMA_VALIDATE(calculatedOffset == GetSize()); + VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize); + VMA_VALIDATE(calculatedFreeCount == m_FreeCount); + + return true; +} + +void VmaBlockMetadata_Generic::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const +{ + const uint32_t rangeCount = (uint32_t)m_Suballocations.size(); + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += GetSize(); + + for (const auto& suballoc : m_Suballocations) + { + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); + else + VmaAddDetailedStatisticsUnusedRange(inoutStats, suballoc.size); + } +} + +void VmaBlockMetadata_Generic::AddStatistics(VmaStatistics& inoutStats) const +{ + inoutStats.blockCount++; + inoutStats.allocationCount += (uint32_t)m_Suballocations.size() - m_FreeCount; + inoutStats.blockBytes += GetSize(); + inoutStats.allocationBytes += GetSize() - m_SumFreeSize; +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const +{ + PrintDetailedMap_Begin(json, + m_SumFreeSize, // unusedBytes + m_Suballocations.size() - (size_t)m_FreeCount, // allocationCount + m_FreeCount, // unusedRangeCount + mapRefCount); + + for (const auto& suballoc : m_Suballocations) + { + if (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE) + { + PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size); + } + else + { + PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); + } + } + + PrintDetailedMap_End(json); +} +#endif // VMA_STATS_STRING_ENABLED + +bool VmaBlockMetadata_Generic::CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + VMA_ASSERT(allocSize > 0); + VMA_ASSERT(!upperAddress); + VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(pAllocationRequest != VMA_NULL); + VMA_HEAVY_ASSERT(Validate()); + + allocSize = AlignAllocationSize(allocSize); + + pAllocationRequest->type = VmaAllocationRequestType::Normal; + pAllocationRequest->size = allocSize; + + const VkDeviceSize debugMargin = GetDebugMargin(); + + // There is not enough total free space in this block to fulfill the request: Early return. + if (m_SumFreeSize < allocSize + debugMargin) + { + return false; + } + + // New algorithm, efficiently searching freeSuballocationsBySize. + const size_t freeSuballocCount = m_FreeSuballocationsBySize.size(); + if (freeSuballocCount > 0) + { + if (strategy == 0 || + strategy == VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT) + { + // Find first free suballocation with size not less than allocSize + debugMargin. + VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( + m_FreeSuballocationsBySize.data(), + m_FreeSuballocationsBySize.data() + freeSuballocCount, + allocSize + debugMargin, + VmaSuballocationItemSizeLess()); + size_t index = it - m_FreeSuballocationsBySize.data(); + for (; index < freeSuballocCount; ++index) + { + if (CheckAllocation( + allocSize, + allocAlignment, + allocType, + m_FreeSuballocationsBySize[index], + &pAllocationRequest->allocHandle)) + { + pAllocationRequest->item = m_FreeSuballocationsBySize[index]; + return true; + } + } + } + else if (strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET) + { + for (VmaSuballocationList::iterator it = m_Suballocations.begin(); + it != m_Suballocations.end(); + ++it) + { + if (it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation( + allocSize, + allocAlignment, + allocType, + it, + &pAllocationRequest->allocHandle)) + { + pAllocationRequest->item = it; + return true; + } + } + } + else + { + VMA_ASSERT(strategy & (VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT | VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT )); + // Search staring from biggest suballocations. + for (size_t index = freeSuballocCount; index--; ) + { + if (CheckAllocation( + allocSize, + allocAlignment, + allocType, + m_FreeSuballocationsBySize[index], + &pAllocationRequest->allocHandle)) + { + pAllocationRequest->item = m_FreeSuballocationsBySize[index]; + return true; + } + } + } + } + + return false; +} + +VkResult VmaBlockMetadata_Generic::CheckCorruption(const void* pBlockData) +{ + for (auto& suballoc : m_Suballocations) + { + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + { + if (!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); + return VK_ERROR_UNKNOWN_COPY; + } + } + } + + return VK_SUCCESS; +} + +void VmaBlockMetadata_Generic::Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) +{ + VMA_ASSERT(request.type == VmaAllocationRequestType::Normal); + VMA_ASSERT(request.item != m_Suballocations.end()); + VmaSuballocation& suballoc = *request.item; + // Given suballocation is a free block. + VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + + // Given offset is inside this suballocation. + VMA_ASSERT((VkDeviceSize)request.allocHandle - 1 >= suballoc.offset); + const VkDeviceSize paddingBegin = (VkDeviceSize)request.allocHandle - suballoc.offset - 1; + VMA_ASSERT(suballoc.size >= paddingBegin + request.size); + const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - request.size; + + // Unregister this free suballocation from m_FreeSuballocationsBySize and update + // it to become used. + UnregisterFreeSuballocation(request.item); + + suballoc.offset = (VkDeviceSize)request.allocHandle - 1; + suballoc.size = request.size; + suballoc.type = type; + suballoc.userData = userData; + + // If there are any free bytes remaining at the end, insert new free suballocation after current one. + if (paddingEnd) + { + VmaSuballocation paddingSuballoc = {}; + paddingSuballoc.offset = suballoc.offset + suballoc.size; + paddingSuballoc.size = paddingEnd; + paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + VmaSuballocationList::iterator next = request.item; + ++next; + const VmaSuballocationList::iterator paddingEndItem = + m_Suballocations.insert(next, paddingSuballoc); + RegisterFreeSuballocation(paddingEndItem); + } + + // If there are any free bytes remaining at the beginning, insert new free suballocation before current one. + if (paddingBegin) + { + VmaSuballocation paddingSuballoc = {}; + paddingSuballoc.offset = suballoc.offset - paddingBegin; + paddingSuballoc.size = paddingBegin; + paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + const VmaSuballocationList::iterator paddingBeginItem = + m_Suballocations.insert(request.item, paddingSuballoc); + RegisterFreeSuballocation(paddingBeginItem); + } + + // Update totals. + m_FreeCount = m_FreeCount - 1; + if (paddingBegin > 0) + { + ++m_FreeCount; + } + if (paddingEnd > 0) + { + ++m_FreeCount; + } + m_SumFreeSize -= request.size; +} + +void VmaBlockMetadata_Generic::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) +{ + outInfo.offset = (VkDeviceSize)allocHandle - 1; + const VmaSuballocation& suballoc = *FindAtOffset(outInfo.offset); + outInfo.size = suballoc.size; + outInfo.pUserData = suballoc.userData; +} + +void* VmaBlockMetadata_Generic::GetAllocationUserData(VmaAllocHandle allocHandle) const +{ + return FindAtOffset((VkDeviceSize)allocHandle - 1)->userData; +} + +VmaAllocHandle VmaBlockMetadata_Generic::GetAllocationListBegin() const +{ + if (IsEmpty()) + return VK_NULL_HANDLE; + + for (const auto& suballoc : m_Suballocations) + { + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + return (VmaAllocHandle)(suballoc.offset + 1); + } + VMA_ASSERT(false && "Should contain at least 1 allocation!"); + return VK_NULL_HANDLE; +} + +VmaAllocHandle VmaBlockMetadata_Generic::GetNextAllocation(VmaAllocHandle prevAlloc) const +{ + VmaSuballocationList::const_iterator prev = FindAtOffset((VkDeviceSize)prevAlloc - 1); + + for (VmaSuballocationList::const_iterator it = ++prev; it != m_Suballocations.end(); ++it) + { + if (it->type != VMA_SUBALLOCATION_TYPE_FREE) + return (VmaAllocHandle)(it->offset + 1); + } + return VK_NULL_HANDLE; +} + +void VmaBlockMetadata_Generic::Clear() +{ + const VkDeviceSize size = GetSize(); + + VMA_ASSERT(IsVirtual()); + m_FreeCount = 1; + m_SumFreeSize = size; + m_Suballocations.clear(); + m_FreeSuballocationsBySize.clear(); + + VmaSuballocation suballoc = {}; + suballoc.offset = 0; + suballoc.size = size; + suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + m_Suballocations.push_back(suballoc); + + m_FreeSuballocationsBySize.push_back(m_Suballocations.begin()); +} + +void VmaBlockMetadata_Generic::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) +{ + VmaSuballocation& suballoc = *FindAtOffset((VkDeviceSize)allocHandle - 1); + suballoc.userData = userData; +} + +void VmaBlockMetadata_Generic::DebugLogAllAllocations() const +{ + for (const auto& suballoc : m_Suballocations) + { + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + DebugLogAllocation(suballoc.offset, suballoc.size, suballoc.userData); + } +} + +VmaSuballocationList::iterator VmaBlockMetadata_Generic::FindAtOffset(VkDeviceSize offset) const +{ + VMA_HEAVY_ASSERT(!m_Suballocations.empty()); + const VkDeviceSize last = m_Suballocations.rbegin()->offset; + if (last == offset) + return m_Suballocations.rbegin().drop_const(); + const VkDeviceSize first = m_Suballocations.begin()->offset; + if (first == offset) + return m_Suballocations.begin().drop_const(); + + const size_t suballocCount = m_Suballocations.size(); + const VkDeviceSize step = (last - first + m_Suballocations.begin()->size) / suballocCount; + auto findSuballocation = [&](auto begin, auto end) -> VmaSuballocationList::iterator + { + for (auto suballocItem = begin; + suballocItem != end; + ++suballocItem) + { + if (suballocItem->offset == offset) + return suballocItem.drop_const(); + } + VMA_ASSERT(false && "Not found!"); + return m_Suballocations.end().drop_const(); + }; + // If requested offset is closer to the end of range, search from the end + if (offset - first > suballocCount * step / 2) + { + return findSuballocation(m_Suballocations.rbegin(), m_Suballocations.rend()); + } + return findSuballocation(m_Suballocations.begin(), m_Suballocations.end()); +} + +bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const +{ + VkDeviceSize lastSize = 0; + for (size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i) + { + const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i]; + + VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE); + VMA_VALIDATE(it->size >= lastSize); + lastSize = it->size; + } + return true; +} + +bool VmaBlockMetadata_Generic::CheckAllocation( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + VmaSuballocationList::const_iterator suballocItem, + VmaAllocHandle* pAllocHandle) const +{ + VMA_ASSERT(allocSize > 0); + VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(suballocItem != m_Suballocations.cend()); + VMA_ASSERT(pAllocHandle != VMA_NULL); + + const VkDeviceSize debugMargin = GetDebugMargin(); + const VkDeviceSize bufferImageGranularity = GetBufferImageGranularity(); + + const VmaSuballocation& suballoc = *suballocItem; + VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + + // Size of this suballocation is too small for this request: Early return. + if (suballoc.size < allocSize) + { + return false; + } + + // Start from offset equal to beginning of this suballocation. + VkDeviceSize offset = suballoc.offset + (suballocItem == m_Suballocations.cbegin() ? 0 : GetDebugMargin()); + + // Apply debugMargin from the end of previous alloc. + if (debugMargin > 0) + { + offset += debugMargin; + } + + // Apply alignment. + offset = VmaAlignUp(offset, allocAlignment); + + // Check previous suballocations for BufferImageGranularity conflicts. + // Make bigger alignment if necessary. + if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment) + { + bool bufferImageGranularityConflict = false; + VmaSuballocationList::const_iterator prevSuballocItem = suballocItem; + while (prevSuballocItem != m_Suballocations.cbegin()) + { + --prevSuballocItem; + const VmaSuballocation& prevSuballoc = *prevSuballocItem; + if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) + { + bufferImageGranularityConflict = true; + break; + } + } + else + // Already on previous page. + break; + } + if (bufferImageGranularityConflict) + { + offset = VmaAlignUp(offset, bufferImageGranularity); + } + } + + // Calculate padding at the beginning based on current offset. + const VkDeviceSize paddingBegin = offset - suballoc.offset; + + // Fail if requested size plus margin after is bigger than size of this suballocation. + if (paddingBegin + allocSize + debugMargin > suballoc.size) + { + return false; + } + + // Check next suballocations for BufferImageGranularity conflicts. + // If conflict exists, allocation cannot be made here. + if (allocSize % bufferImageGranularity || offset % bufferImageGranularity) + { + VmaSuballocationList::const_iterator nextSuballocItem = suballocItem; + ++nextSuballocItem; + while (nextSuballocItem != m_Suballocations.cend()) + { + const VmaSuballocation& nextSuballoc = *nextSuballocItem; + if (VmaBlocksOnSamePage(offset, allocSize, nextSuballoc.offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) + { + return false; + } + } + else + { + // Already on next page. + break; + } + ++nextSuballocItem; + } + } + + *pAllocHandle = (VmaAllocHandle)(offset + 1); + // All tests passed: Success. pAllocHandle is already filled. + return true; +} + +void VmaBlockMetadata_Generic::MergeFreeWithNext(VmaSuballocationList::iterator item) +{ + VMA_ASSERT(item != m_Suballocations.end()); + VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); + + VmaSuballocationList::iterator nextItem = item; + ++nextItem; + VMA_ASSERT(nextItem != m_Suballocations.end()); + VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE); + + item->size += nextItem->size; + --m_FreeCount; + m_Suballocations.erase(nextItem); +} + +VmaSuballocationList::iterator VmaBlockMetadata_Generic::FreeSuballocation(VmaSuballocationList::iterator suballocItem) +{ + // Change this suballocation to be marked as free. + VmaSuballocation& suballoc = *suballocItem; + suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + suballoc.userData = VMA_NULL; + + // Update totals. + ++m_FreeCount; + m_SumFreeSize += suballoc.size; + + // Merge with previous and/or next suballocation if it's also free. + bool mergeWithNext = false; + bool mergeWithPrev = false; + + VmaSuballocationList::iterator nextItem = suballocItem; + ++nextItem; + if ((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)) + { + mergeWithNext = true; + } + + VmaSuballocationList::iterator prevItem = suballocItem; + if (suballocItem != m_Suballocations.begin()) + { + --prevItem; + if (prevItem->type == VMA_SUBALLOCATION_TYPE_FREE) + { + mergeWithPrev = true; + } + } + + if (mergeWithNext) + { + UnregisterFreeSuballocation(nextItem); + MergeFreeWithNext(suballocItem); + } + + if (mergeWithPrev) + { + UnregisterFreeSuballocation(prevItem); + MergeFreeWithNext(prevItem); + RegisterFreeSuballocation(prevItem); + return prevItem; + } + else + { + RegisterFreeSuballocation(suballocItem); + return suballocItem; + } +} + +void VmaBlockMetadata_Generic::RegisterFreeSuballocation(VmaSuballocationList::iterator item) +{ + VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(item->size > 0); + + // You may want to enable this validation at the beginning or at the end of + // this function, depending on what do you want to check. + VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); + + if (m_FreeSuballocationsBySize.empty()) + { + m_FreeSuballocationsBySize.push_back(item); + } + else + { + VmaVectorInsertSorted(m_FreeSuballocationsBySize, item); + } + + //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); +} + +void VmaBlockMetadata_Generic::UnregisterFreeSuballocation(VmaSuballocationList::iterator item) +{ + VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(item->size > 0); + + // You may want to enable this validation at the beginning or at the end of + // this function, depending on what do you want to check. + VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); + + VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( + m_FreeSuballocationsBySize.data(), + m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(), + item, + VmaSuballocationItemSizeLess()); + for (size_t index = it - m_FreeSuballocationsBySize.data(); + index < m_FreeSuballocationsBySize.size(); + ++index) + { + if (m_FreeSuballocationsBySize[index] == item) + { + VmaVectorRemove(m_FreeSuballocationsBySize, index); + return; + } + VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found."); + } + VMA_ASSERT(0 && "Not found."); + + //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); +} +#endif // _VMA_BLOCK_METADATA_GENERIC_FUNCTIONS +#endif // _VMA_BLOCK_METADATA_GENERIC +#endif // #if 0 + +#ifndef _VMA_BLOCK_METADATA_LINEAR +/* +Allocations and their references in internal data structure look like this: + +if(m_2ndVectorMode == SECOND_VECTOR_EMPTY): + + 0 +-------+ + | | + | | + | | + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount] + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount + 1] + +-------+ + | ... | + +-------+ + | Alloc | 1st[1st.size() - 1] + +-------+ + | | + | | + | | +GetSize() +-------+ + +if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER): + + 0 +-------+ + | Alloc | 2nd[0] + +-------+ + | Alloc | 2nd[1] + +-------+ + | ... | + +-------+ + | Alloc | 2nd[2nd.size() - 1] + +-------+ + | | + | | + | | + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount] + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount + 1] + +-------+ + | ... | + +-------+ + | Alloc | 1st[1st.size() - 1] + +-------+ + | | +GetSize() +-------+ + +if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK): + + 0 +-------+ + | | + | | + | | + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount] + +-------+ + | Alloc | 1st[m_1stNullItemsBeginCount + 1] + +-------+ + | ... | + +-------+ + | Alloc | 1st[1st.size() - 1] + +-------+ + | | + | | + | | + +-------+ + | Alloc | 2nd[2nd.size() - 1] + +-------+ + | ... | + +-------+ + | Alloc | 2nd[1] + +-------+ + | Alloc | 2nd[0] +GetSize() +-------+ + +*/ +class VmaBlockMetadata_Linear : public VmaBlockMetadata +{ + VMA_CLASS_NO_COPY(VmaBlockMetadata_Linear) +public: + VmaBlockMetadata_Linear(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata_Linear() = default; + + VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize; } + bool IsEmpty() const override { return GetAllocationCount() == 0; } + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; }; + + void Init(VkDeviceSize size) override; + bool Validate() const override; + size_t GetAllocationCount() const override; + size_t GetFreeRegionsCount() const override; + + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; + void AddStatistics(VmaStatistics& inoutStats) const override; + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json) const override; +#endif + + bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) override; + + VkResult CheckCorruption(const void* pBlockData) override; + + void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) override; + + void Free(VmaAllocHandle allocHandle) override; + void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; + void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; + VmaAllocHandle GetAllocationListBegin() const override; + VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; + VkDeviceSize GetNextFreeRegionSize(VmaAllocHandle alloc) const override; + void Clear() override; + void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; + void DebugLogAllAllocations() const override; + +private: + /* + There are two suballocation vectors, used in ping-pong way. + The one with index m_1stVectorIndex is called 1st. + The one with index (m_1stVectorIndex ^ 1) is called 2nd. + 2nd can be non-empty only when 1st is not empty. + When 2nd is not empty, m_2ndVectorMode indicates its mode of operation. + */ + typedef VmaVector> SuballocationVectorType; + + enum SECOND_VECTOR_MODE + { + SECOND_VECTOR_EMPTY, + /* + Suballocations in 2nd vector are created later than the ones in 1st, but they + all have smaller offset. + */ + SECOND_VECTOR_RING_BUFFER, + /* + Suballocations in 2nd vector are upper side of double stack. + They all have offsets higher than those in 1st vector. + Top of this stack means smaller offsets, but higher indices in this vector. + */ + SECOND_VECTOR_DOUBLE_STACK, + }; + + VkDeviceSize m_SumFreeSize; + SuballocationVectorType m_Suballocations0, m_Suballocations1; + uint32_t m_1stVectorIndex; + SECOND_VECTOR_MODE m_2ndVectorMode; + // Number of items in 1st vector with hAllocation = null at the beginning. + size_t m_1stNullItemsBeginCount; + // Number of other items in 1st vector with hAllocation = null somewhere in the middle. + size_t m_1stNullItemsMiddleCount; + // Number of items in 2nd vector with hAllocation = null. + size_t m_2ndNullItemsCount; + + SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; } + SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; } + const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; } + const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; } + + VmaSuballocation& FindSuballocation(VkDeviceSize offset) const; + bool ShouldCompact1st() const; + void CleanupAfterFree(); + + bool CreateAllocationRequest_LowerAddress( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest); + bool CreateAllocationRequest_UpperAddress( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest); +}; + +#ifndef _VMA_BLOCK_METADATA_LINEAR_FUNCTIONS +VmaBlockMetadata_Linear::VmaBlockMetadata_Linear(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), + m_SumFreeSize(0), + m_Suballocations0(VmaStlAllocator(pAllocationCallbacks)), + m_Suballocations1(VmaStlAllocator(pAllocationCallbacks)), + m_1stVectorIndex(0), + m_2ndVectorMode(SECOND_VECTOR_EMPTY), + m_1stNullItemsBeginCount(0), + m_1stNullItemsMiddleCount(0), + m_2ndNullItemsCount(0) {} + +void VmaBlockMetadata_Linear::Init(VkDeviceSize size) +{ + VmaBlockMetadata::Init(size); + m_SumFreeSize = size; +} + +bool VmaBlockMetadata_Linear::Validate() const +{ + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + + VMA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY)); + VMA_VALIDATE(!suballocations1st.empty() || + suballocations2nd.empty() || + m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER); + + if (!suballocations1st.empty()) + { + // Null item at the beginning should be accounted into m_1stNullItemsBeginCount. + VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].type != VMA_SUBALLOCATION_TYPE_FREE); + // Null item at the end should be just pop_back(). + VMA_VALIDATE(suballocations1st.back().type != VMA_SUBALLOCATION_TYPE_FREE); + } + if (!suballocations2nd.empty()) + { + // Null item at the end should be just pop_back(). + VMA_VALIDATE(suballocations2nd.back().type != VMA_SUBALLOCATION_TYPE_FREE); + } + + VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size()); + VMA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size()); + + VkDeviceSize sumUsedSize = 0; + const size_t suballoc1stCount = suballocations1st.size(); + const VkDeviceSize debugMargin = GetDebugMargin(); + VkDeviceSize offset = 0; + + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + const size_t suballoc2ndCount = suballocations2nd.size(); + size_t nullItem2ndCount = 0; + for (size_t i = 0; i < suballoc2ndCount; ++i) + { + const VmaSuballocation& suballoc = suballocations2nd[i]; + const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + + VmaAllocation const alloc = (VmaAllocation)suballoc.userData; + if (!IsVirtual()) + { + VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); + } + VMA_VALIDATE(suballoc.offset >= offset); + + if (!currFree) + { + if (!IsVirtual()) + { + VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == suballoc.offset + 1); + VMA_VALIDATE(alloc->GetSize() == suballoc.size); + } + sumUsedSize += suballoc.size; + } + else + { + ++nullItem2ndCount; + } + + offset = suballoc.offset + suballoc.size + debugMargin; + } + + VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount); + } + + for (size_t i = 0; i < m_1stNullItemsBeginCount; ++i) + { + const VmaSuballocation& suballoc = suballocations1st[i]; + VMA_VALIDATE(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE && + suballoc.userData == VMA_NULL); + } + + size_t nullItem1stCount = m_1stNullItemsBeginCount; + + for (size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i) + { + const VmaSuballocation& suballoc = suballocations1st[i]; + const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + + VmaAllocation const alloc = (VmaAllocation)suballoc.userData; + if (!IsVirtual()) + { + VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); + } + VMA_VALIDATE(suballoc.offset >= offset); + VMA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree); + + if (!currFree) + { + if (!IsVirtual()) + { + VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == suballoc.offset + 1); + VMA_VALIDATE(alloc->GetSize() == suballoc.size); + } + sumUsedSize += suballoc.size; + } + else + { + ++nullItem1stCount; + } + + offset = suballoc.offset + suballoc.size + debugMargin; + } + VMA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount); + + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + const size_t suballoc2ndCount = suballocations2nd.size(); + size_t nullItem2ndCount = 0; + for (size_t i = suballoc2ndCount; i--; ) + { + const VmaSuballocation& suballoc = suballocations2nd[i]; + const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); + + VmaAllocation const alloc = (VmaAllocation)suballoc.userData; + if (!IsVirtual()) + { + VMA_VALIDATE(currFree == (alloc == VK_NULL_HANDLE)); + } + VMA_VALIDATE(suballoc.offset >= offset); + + if (!currFree) + { + if (!IsVirtual()) + { + VMA_VALIDATE((VkDeviceSize)alloc->GetAllocHandle() == suballoc.offset + 1); + VMA_VALIDATE(alloc->GetSize() == suballoc.size); + } + sumUsedSize += suballoc.size; + } + else + { + ++nullItem2ndCount; + } + + offset = suballoc.offset + suballoc.size + debugMargin; + } + + VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount); + } + + VMA_VALIDATE(offset <= GetSize()); + VMA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize); + + return true; +} + +size_t VmaBlockMetadata_Linear::GetAllocationCount() const +{ + return AccessSuballocations1st().size() - m_1stNullItemsBeginCount - m_1stNullItemsMiddleCount + + AccessSuballocations2nd().size() - m_2ndNullItemsCount; +} + +size_t VmaBlockMetadata_Linear::GetFreeRegionsCount() const +{ + // Function only used for defragmentation, which is disabled for this algorithm + VMA_ASSERT(0); + return SIZE_MAX; +} + +void VmaBlockMetadata_Linear::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const +{ + const VkDeviceSize size = GetSize(); + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + const size_t suballoc1stCount = suballocations1st.size(); + const size_t suballoc2ndCount = suballocations2nd.size(); + + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += size; + + VkDeviceSize lastOffset = 0; + + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; + size_t nextAlloc2ndIndex = 0; + while (lastOffset < freeSpace2ndTo1stEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc2ndIndex < suballoc2ndCount && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + ++nextAlloc2ndIndex; + } + + // Found non-null allocation. + if (nextAlloc2ndIndex < suballoc2ndCount) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc2ndIndex; + } + // We are at the end. + else + { + // There is free space from lastOffset to freeSpace2ndTo1stEnd. + if (lastOffset < freeSpace2ndTo1stEnd) + { + const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } + + // End of loop. + lastOffset = freeSpace2ndTo1stEnd; + } + } + } + + size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; + const VkDeviceSize freeSpace1stTo2ndEnd = + m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; + while (lastOffset < freeSpace1stTo2ndEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc1stIndex < suballoc1stCount && + suballocations1st[nextAlloc1stIndex].userData == VMA_NULL) + { + ++nextAlloc1stIndex; + } + + // Found non-null allocation. + if (nextAlloc1stIndex < suballoc1stCount) + { + const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc1stIndex; + } + // We are at the end. + else + { + // There is free space from lastOffset to freeSpace1stTo2ndEnd. + if (lastOffset < freeSpace1stTo2ndEnd) + { + const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } + + // End of loop. + lastOffset = freeSpace1stTo2ndEnd; + } + } + + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; + while (lastOffset < size) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc2ndIndex != SIZE_MAX && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + --nextAlloc2ndIndex; + } + + // Found non-null allocation. + if (nextAlloc2ndIndex != SIZE_MAX) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + VmaAddDetailedStatisticsAllocation(inoutStats, suballoc.size); + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + --nextAlloc2ndIndex; + } + // We are at the end. + else + { + // There is free space from lastOffset to size. + if (lastOffset < size) + { + const VkDeviceSize unusedRangeSize = size - lastOffset; + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize); + } + + // End of loop. + lastOffset = size; + } + } + } +} + +void VmaBlockMetadata_Linear::AddStatistics(VmaStatistics& inoutStats) const +{ + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + const VkDeviceSize size = GetSize(); + const size_t suballoc1stCount = suballocations1st.size(); + const size_t suballoc2ndCount = suballocations2nd.size(); + + inoutStats.blockCount++; + inoutStats.blockBytes += size; + inoutStats.allocationBytes += size - m_SumFreeSize; + + VkDeviceSize lastOffset = 0; + + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; + size_t nextAlloc2ndIndex = m_1stNullItemsBeginCount; + while (lastOffset < freeSpace2ndTo1stEnd) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex < suballoc2ndCount && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + ++nextAlloc2ndIndex; + } + + // Found non-null allocation. + if (nextAlloc2ndIndex < suballoc2ndCount) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++inoutStats.allocationCount; + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < freeSpace2ndTo1stEnd) + { + // There is free space from lastOffset to freeSpace2ndTo1stEnd. + const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; + } + + // End of loop. + lastOffset = freeSpace2ndTo1stEnd; + } + } + } + + size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; + const VkDeviceSize freeSpace1stTo2ndEnd = + m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; + while (lastOffset < freeSpace1stTo2ndEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc1stIndex < suballoc1stCount && + suballocations1st[nextAlloc1stIndex].userData == VMA_NULL) + { + ++nextAlloc1stIndex; + } + + // Found non-null allocation. + if (nextAlloc1stIndex < suballoc1stCount) + { + const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++inoutStats.allocationCount; + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc1stIndex; + } + // We are at the end. + else + { + if (lastOffset < freeSpace1stTo2ndEnd) + { + // There is free space from lastOffset to freeSpace1stTo2ndEnd. + const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; + } + + // End of loop. + lastOffset = freeSpace1stTo2ndEnd; + } + } + + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; + while (lastOffset < size) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex != SIZE_MAX && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + --nextAlloc2ndIndex; + } + + // Found non-null allocation. + if (nextAlloc2ndIndex != SIZE_MAX) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++inoutStats.allocationCount; + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + --nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < size) + { + // There is free space from lastOffset to size. + const VkDeviceSize unusedRangeSize = size - lastOffset; + } + + // End of loop. + lastOffset = size; + } + } + } +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const +{ + const VkDeviceSize size = GetSize(); + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + const size_t suballoc1stCount = suballocations1st.size(); + const size_t suballoc2ndCount = suballocations2nd.size(); + + // FIRST PASS + + size_t unusedRangeCount = 0; + VkDeviceSize usedBytes = 0; + + VkDeviceSize lastOffset = 0; + + size_t alloc2ndCount = 0; + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; + size_t nextAlloc2ndIndex = 0; + while (lastOffset < freeSpace2ndTo1stEnd) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex < suballoc2ndCount && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + ++nextAlloc2ndIndex; + } + + // Found non-null allocation. + if (nextAlloc2ndIndex < suballoc2ndCount) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + ++unusedRangeCount; + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++alloc2ndCount; + usedBytes += suballoc.size; + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < freeSpace2ndTo1stEnd) + { + // There is free space from lastOffset to freeSpace2ndTo1stEnd. + ++unusedRangeCount; + } + + // End of loop. + lastOffset = freeSpace2ndTo1stEnd; + } + } + } + + size_t nextAlloc1stIndex = m_1stNullItemsBeginCount; + size_t alloc1stCount = 0; + const VkDeviceSize freeSpace1stTo2ndEnd = + m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size; + while (lastOffset < freeSpace1stTo2ndEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc1stIndex < suballoc1stCount && + suballocations1st[nextAlloc1stIndex].userData == VMA_NULL) + { + ++nextAlloc1stIndex; + } + + // Found non-null allocation. + if (nextAlloc1stIndex < suballoc1stCount) + { + const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + ++unusedRangeCount; + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++alloc1stCount; + usedBytes += suballoc.size; + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc1stIndex; + } + // We are at the end. + else + { + if (lastOffset < size) + { + // There is free space from lastOffset to freeSpace1stTo2ndEnd. + ++unusedRangeCount; + } + + // End of loop. + lastOffset = freeSpace1stTo2ndEnd; + } + } + + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; + while (lastOffset < size) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex != SIZE_MAX && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + --nextAlloc2ndIndex; + } + + // Found non-null allocation. + if (nextAlloc2ndIndex != SIZE_MAX) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + ++unusedRangeCount; + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + ++alloc2ndCount; + usedBytes += suballoc.size; + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + --nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < size) + { + // There is free space from lastOffset to size. + ++unusedRangeCount; + } + + // End of loop. + lastOffset = size; + } + } + } + + const VkDeviceSize unusedBytes = size - usedBytes; + PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount); + + // SECOND PASS + lastOffset = 0; + + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset; + size_t nextAlloc2ndIndex = 0; + while (lastOffset < freeSpace2ndTo1stEnd) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex < suballoc2ndCount && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + ++nextAlloc2ndIndex; + } + + // Found non-null allocation. + if (nextAlloc2ndIndex < suballoc2ndCount) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < freeSpace2ndTo1stEnd) + { + // There is free space from lastOffset to freeSpace2ndTo1stEnd. + const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } + + // End of loop. + lastOffset = freeSpace2ndTo1stEnd; + } + } + } + + nextAlloc1stIndex = m_1stNullItemsBeginCount; + while (lastOffset < freeSpace1stTo2ndEnd) + { + // Find next non-null allocation or move nextAllocIndex to the end. + while (nextAlloc1stIndex < suballoc1stCount && + suballocations1st[nextAlloc1stIndex].userData == VMA_NULL) + { + ++nextAlloc1stIndex; + } + + // Found non-null allocation. + if (nextAlloc1stIndex < suballoc1stCount) + { + const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + ++nextAlloc1stIndex; + } + // We are at the end. + else + { + if (lastOffset < freeSpace1stTo2ndEnd) + { + // There is free space from lastOffset to freeSpace1stTo2ndEnd. + const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } + + // End of loop. + lastOffset = freeSpace1stTo2ndEnd; + } + } + + if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + size_t nextAlloc2ndIndex = suballocations2nd.size() - 1; + while (lastOffset < size) + { + // Find next non-null allocation or move nextAlloc2ndIndex to the end. + while (nextAlloc2ndIndex != SIZE_MAX && + suballocations2nd[nextAlloc2ndIndex].userData == VMA_NULL) + { + --nextAlloc2ndIndex; + } + + // Found non-null allocation. + if (nextAlloc2ndIndex != SIZE_MAX) + { + const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex]; + + // 1. Process free space before this allocation. + if (lastOffset < suballoc.offset) + { + // There is free space from lastOffset to suballoc.offset. + const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } + + // 2. Process this allocation. + // There is allocation with suballoc.offset, suballoc.size. + PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData); + + // 3. Prepare for next iteration. + lastOffset = suballoc.offset + suballoc.size; + --nextAlloc2ndIndex; + } + // We are at the end. + else + { + if (lastOffset < size) + { + // There is free space from lastOffset to size. + const VkDeviceSize unusedRangeSize = size - lastOffset; + PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize); + } + + // End of loop. + lastOffset = size; + } + } + } + + PrintDetailedMap_End(json); +} +#endif // VMA_STATS_STRING_ENABLED + +bool VmaBlockMetadata_Linear::CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + VMA_ASSERT(allocSize > 0); + VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); + VMA_ASSERT(pAllocationRequest != VMA_NULL); + VMA_HEAVY_ASSERT(Validate()); + pAllocationRequest->size = allocSize; + return upperAddress ? + CreateAllocationRequest_UpperAddress( + allocSize, allocAlignment, allocType, strategy, pAllocationRequest) : + CreateAllocationRequest_LowerAddress( + allocSize, allocAlignment, allocType, strategy, pAllocationRequest); +} + +VkResult VmaBlockMetadata_Linear::CheckCorruption(const void* pBlockData) +{ + VMA_ASSERT(!IsVirtual()); + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + for (size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i) + { + const VmaSuballocation& suballoc = suballocations1st[i]; + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + { + if (!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); + return VK_ERROR_UNKNOWN_COPY; + } + } + } + + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + for (size_t i = 0, count = suballocations2nd.size(); i < count; ++i) + { + const VmaSuballocation& suballoc = suballocations2nd[i]; + if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) + { + if (!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); + return VK_ERROR_UNKNOWN_COPY; + } + } + } + + return VK_SUCCESS; +} + +void VmaBlockMetadata_Linear::Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) +{ + const VkDeviceSize offset = (VkDeviceSize)request.allocHandle - 1; + const VmaSuballocation newSuballoc = { offset, request.size, userData, type }; + + switch (request.type) + { + case VmaAllocationRequestType::UpperAddress: + { + VMA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER && + "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer."); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + suballocations2nd.push_back(newSuballoc); + m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK; + } + break; + case VmaAllocationRequestType::EndOf1st: + { + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + + VMA_ASSERT(suballocations1st.empty() || + offset >= suballocations1st.back().offset + suballocations1st.back().size); + // Check if it fits before the end of the block. + VMA_ASSERT(offset + request.size <= GetSize()); + + suballocations1st.push_back(newSuballoc); + } + break; + case VmaAllocationRequestType::EndOf2nd: + { + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector. + VMA_ASSERT(!suballocations1st.empty() && + offset + request.size <= suballocations1st[m_1stNullItemsBeginCount].offset); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + + switch (m_2ndVectorMode) + { + case SECOND_VECTOR_EMPTY: + // First allocation from second part ring buffer. + VMA_ASSERT(suballocations2nd.empty()); + m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER; + break; + case SECOND_VECTOR_RING_BUFFER: + // 2-part ring buffer is already started. + VMA_ASSERT(!suballocations2nd.empty()); + break; + case SECOND_VECTOR_DOUBLE_STACK: + VMA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack."); + break; + default: + VMA_ASSERT(0); + } + + suballocations2nd.push_back(newSuballoc); + } + break; + default: + VMA_ASSERT(0 && "CRITICAL INTERNAL ERROR."); + } + + m_SumFreeSize -= newSuballoc.size; +} + +void VmaBlockMetadata_Linear::Free(VmaAllocHandle allocHandle) +{ + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + VkDeviceSize offset = (VkDeviceSize)allocHandle - 1; + + if (!suballocations1st.empty()) + { + // First allocation: Mark it as next empty at the beginning. + VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount]; + if (firstSuballoc.offset == offset) + { + firstSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; + firstSuballoc.userData = VMA_NULL; + m_SumFreeSize += firstSuballoc.size; + ++m_1stNullItemsBeginCount; + CleanupAfterFree(); + return; + } + } + + // Last allocation in 2-part ring buffer or top of upper stack (same logic). + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER || + m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + VmaSuballocation& lastSuballoc = suballocations2nd.back(); + if (lastSuballoc.offset == offset) + { + m_SumFreeSize += lastSuballoc.size; + suballocations2nd.pop_back(); + CleanupAfterFree(); + return; + } + } + // Last allocation in 1st vector. + else if (m_2ndVectorMode == SECOND_VECTOR_EMPTY) + { + VmaSuballocation& lastSuballoc = suballocations1st.back(); + if (lastSuballoc.offset == offset) + { + m_SumFreeSize += lastSuballoc.size; + suballocations1st.pop_back(); + CleanupAfterFree(); + return; + } + } + + VmaSuballocation refSuballoc; + refSuballoc.offset = offset; + // Rest of members stays uninitialized intentionally for better performance. + + // Item from the middle of 1st vector. + { + const SuballocationVectorType::iterator it = VmaBinaryFindSorted( + suballocations1st.begin() + m_1stNullItemsBeginCount, + suballocations1st.end(), + refSuballoc, + VmaSuballocationOffsetLess()); + if (it != suballocations1st.end()) + { + it->type = VMA_SUBALLOCATION_TYPE_FREE; + it->userData = VMA_NULL; + ++m_1stNullItemsMiddleCount; + m_SumFreeSize += it->size; + CleanupAfterFree(); + return; + } + } + + if (m_2ndVectorMode != SECOND_VECTOR_EMPTY) + { + // Item from the middle of 2nd vector. + const SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ? + VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) : + VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater()); + if (it != suballocations2nd.end()) + { + it->type = VMA_SUBALLOCATION_TYPE_FREE; + it->userData = VMA_NULL; + ++m_2ndNullItemsCount; + m_SumFreeSize += it->size; + CleanupAfterFree(); + return; + } + } + + VMA_ASSERT(0 && "Allocation to free not found in linear allocator!"); +} + +void VmaBlockMetadata_Linear::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) +{ + outInfo.offset = (VkDeviceSize)allocHandle - 1; + VmaSuballocation& suballoc = FindSuballocation(outInfo.offset); + outInfo.size = suballoc.size; + outInfo.pUserData = suballoc.userData; +} + +void* VmaBlockMetadata_Linear::GetAllocationUserData(VmaAllocHandle allocHandle) const +{ + return FindSuballocation((VkDeviceSize)allocHandle - 1).userData; +} + +VmaAllocHandle VmaBlockMetadata_Linear::GetAllocationListBegin() const +{ + // Function only used for defragmentation, which is disabled for this algorithm + VMA_ASSERT(0); + return VK_NULL_HANDLE; +} + +VmaAllocHandle VmaBlockMetadata_Linear::GetNextAllocation(VmaAllocHandle prevAlloc) const +{ + // Function only used for defragmentation, which is disabled for this algorithm + VMA_ASSERT(0); + return VK_NULL_HANDLE; +} + +VkDeviceSize VmaBlockMetadata_Linear::GetNextFreeRegionSize(VmaAllocHandle alloc) const +{ + // Function only used for defragmentation, which is disabled for this algorithm + VMA_ASSERT(0); + return 0; +} + +void VmaBlockMetadata_Linear::Clear() +{ + m_SumFreeSize = GetSize(); + m_Suballocations0.clear(); + m_Suballocations1.clear(); + // Leaving m_1stVectorIndex unchanged - it doesn't matter. + m_2ndVectorMode = SECOND_VECTOR_EMPTY; + m_1stNullItemsBeginCount = 0; + m_1stNullItemsMiddleCount = 0; + m_2ndNullItemsCount = 0; +} + +void VmaBlockMetadata_Linear::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) +{ + VmaSuballocation& suballoc = FindSuballocation((VkDeviceSize)allocHandle - 1); + suballoc.userData = userData; +} + +void VmaBlockMetadata_Linear::DebugLogAllAllocations() const +{ + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + for (auto it = suballocations1st.begin() + m_1stNullItemsBeginCount; it != suballocations1st.end(); ++it) + if (it->type != VMA_SUBALLOCATION_TYPE_FREE) + DebugLogAllocation(it->offset, it->size, it->userData); + + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + for (auto it = suballocations2nd.begin(); it != suballocations2nd.end(); ++it) + if (it->type != VMA_SUBALLOCATION_TYPE_FREE) + DebugLogAllocation(it->offset, it->size, it->userData); +} + +VmaSuballocation& VmaBlockMetadata_Linear::FindSuballocation(VkDeviceSize offset) const +{ + const SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + + VmaSuballocation refSuballoc; + refSuballoc.offset = offset; + // Rest of members stays uninitialized intentionally for better performance. + + // Item from the 1st vector. + { + SuballocationVectorType::const_iterator it = VmaBinaryFindSorted( + suballocations1st.begin() + m_1stNullItemsBeginCount, + suballocations1st.end(), + refSuballoc, + VmaSuballocationOffsetLess()); + if (it != suballocations1st.end()) + { + return const_cast(*it); + } + } + + if (m_2ndVectorMode != SECOND_VECTOR_EMPTY) + { + // Rest of members stays uninitialized intentionally for better performance. + SuballocationVectorType::const_iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ? + VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) : + VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater()); + if (it != suballocations2nd.end()) + { + return const_cast(*it); + } + } + + VMA_ASSERT(0 && "Allocation not found in linear allocator!"); + return const_cast(suballocations1st.back()); // Should never occur. +} + +bool VmaBlockMetadata_Linear::ShouldCompact1st() const +{ + const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount; + const size_t suballocCount = AccessSuballocations1st().size(); + return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3; +} + +void VmaBlockMetadata_Linear::CleanupAfterFree() +{ + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + + if (IsEmpty()) + { + suballocations1st.clear(); + suballocations2nd.clear(); + m_1stNullItemsBeginCount = 0; + m_1stNullItemsMiddleCount = 0; + m_2ndNullItemsCount = 0; + m_2ndVectorMode = SECOND_VECTOR_EMPTY; + } + else + { + const size_t suballoc1stCount = suballocations1st.size(); + const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount; + VMA_ASSERT(nullItem1stCount <= suballoc1stCount); + + // Find more null items at the beginning of 1st vector. + while (m_1stNullItemsBeginCount < suballoc1stCount && + suballocations1st[m_1stNullItemsBeginCount].type == VMA_SUBALLOCATION_TYPE_FREE) + { + ++m_1stNullItemsBeginCount; + --m_1stNullItemsMiddleCount; + } + + // Find more null items at the end of 1st vector. + while (m_1stNullItemsMiddleCount > 0 && + suballocations1st.back().type == VMA_SUBALLOCATION_TYPE_FREE) + { + --m_1stNullItemsMiddleCount; + suballocations1st.pop_back(); + } + + // Find more null items at the end of 2nd vector. + while (m_2ndNullItemsCount > 0 && + suballocations2nd.back().type == VMA_SUBALLOCATION_TYPE_FREE) + { + --m_2ndNullItemsCount; + suballocations2nd.pop_back(); + } + + // Find more null items at the beginning of 2nd vector. + while (m_2ndNullItemsCount > 0 && + suballocations2nd[0].type == VMA_SUBALLOCATION_TYPE_FREE) + { + --m_2ndNullItemsCount; + VmaVectorRemove(suballocations2nd, 0); + } + + if (ShouldCompact1st()) + { + const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount; + size_t srcIndex = m_1stNullItemsBeginCount; + for (size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex) + { + while (suballocations1st[srcIndex].type == VMA_SUBALLOCATION_TYPE_FREE) + { + ++srcIndex; + } + if (dstIndex != srcIndex) + { + suballocations1st[dstIndex] = suballocations1st[srcIndex]; + } + ++srcIndex; + } + suballocations1st.resize(nonNullItemCount); + m_1stNullItemsBeginCount = 0; + m_1stNullItemsMiddleCount = 0; + } + + // 2nd vector became empty. + if (suballocations2nd.empty()) + { + m_2ndVectorMode = SECOND_VECTOR_EMPTY; + } + + // 1st vector became empty. + if (suballocations1st.size() - m_1stNullItemsBeginCount == 0) + { + suballocations1st.clear(); + m_1stNullItemsBeginCount = 0; + + if (!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + // Swap 1st with 2nd. Now 2nd is empty. + m_2ndVectorMode = SECOND_VECTOR_EMPTY; + m_1stNullItemsMiddleCount = m_2ndNullItemsCount; + while (m_1stNullItemsBeginCount < suballocations2nd.size() && + suballocations2nd[m_1stNullItemsBeginCount].type == VMA_SUBALLOCATION_TYPE_FREE) + { + ++m_1stNullItemsBeginCount; + --m_1stNullItemsMiddleCount; + } + m_2ndNullItemsCount = 0; + m_1stVectorIndex ^= 1; + } + } + } + + VMA_HEAVY_ASSERT(Validate()); +} + +bool VmaBlockMetadata_Linear::CreateAllocationRequest_LowerAddress( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + const VkDeviceSize blockSize = GetSize(); + const VkDeviceSize debugMargin = GetDebugMargin(); + const VkDeviceSize bufferImageGranularity = GetBufferImageGranularity(); + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + + if (m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + // Try to allocate at the end of 1st vector. + + VkDeviceSize resultBaseOffset = 0; + if (!suballocations1st.empty()) + { + const VmaSuballocation& lastSuballoc = suballocations1st.back(); + resultBaseOffset = lastSuballoc.offset + lastSuballoc.size + debugMargin; + } + + // Start from offset equal to beginning of free space. + VkDeviceSize resultOffset = resultBaseOffset; + + // Apply alignment. + resultOffset = VmaAlignUp(resultOffset, allocAlignment); + + // Check previous suballocations for BufferImageGranularity conflicts. + // Make bigger alignment if necessary. + if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations1st.empty()) + { + bool bufferImageGranularityConflict = false; + for (size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; ) + { + const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex]; + if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) + { + bufferImageGranularityConflict = true; + break; + } + } + else + // Already on previous page. + break; + } + if (bufferImageGranularityConflict) + { + resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity); + } + } + + const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? + suballocations2nd.back().offset : blockSize; + + // There is enough free space at the end after alignment. + if (resultOffset + allocSize + debugMargin <= freeSpaceEnd) + { + // Check next suballocations for BufferImageGranularity conflicts. + // If conflict exists, allocation cannot be made here. + if ((allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity) && m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK) + { + for (size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; ) + { + const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex]; + if (VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) + { + return false; + } + } + else + { + // Already on previous page. + break; + } + } + } + + // All tests passed: Success. + pAllocationRequest->allocHandle = (VmaAllocHandle)(resultOffset + 1); + // pAllocationRequest->item, customData unused. + pAllocationRequest->type = VmaAllocationRequestType::EndOf1st; + return true; + } + } + + // Wrap-around to end of 2nd vector. Try to allocate there, watching for the + // beginning of 1st vector as the end of free space. + if (m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + VMA_ASSERT(!suballocations1st.empty()); + + VkDeviceSize resultBaseOffset = 0; + if (!suballocations2nd.empty()) + { + const VmaSuballocation& lastSuballoc = suballocations2nd.back(); + resultBaseOffset = lastSuballoc.offset + lastSuballoc.size + debugMargin; + } + + // Start from offset equal to beginning of free space. + VkDeviceSize resultOffset = resultBaseOffset; + + // Apply alignment. + resultOffset = VmaAlignUp(resultOffset, allocAlignment); + + // Check previous suballocations for BufferImageGranularity conflicts. + // Make bigger alignment if necessary. + if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty()) + { + bool bufferImageGranularityConflict = false; + for (size_t prevSuballocIndex = suballocations2nd.size(); prevSuballocIndex--; ) + { + const VmaSuballocation& prevSuballoc = suballocations2nd[prevSuballocIndex]; + if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) + { + bufferImageGranularityConflict = true; + break; + } + } + else + // Already on previous page. + break; + } + if (bufferImageGranularityConflict) + { + resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity); + } + } + + size_t index1st = m_1stNullItemsBeginCount; + + // There is enough free space at the end after alignment. + if ((index1st == suballocations1st.size() && resultOffset + allocSize + debugMargin <= blockSize) || + (index1st < suballocations1st.size() && resultOffset + allocSize + debugMargin <= suballocations1st[index1st].offset)) + { + // Check next suballocations for BufferImageGranularity conflicts. + // If conflict exists, allocation cannot be made here. + if (allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity) + { + for (size_t nextSuballocIndex = index1st; + nextSuballocIndex < suballocations1st.size(); + nextSuballocIndex++) + { + const VmaSuballocation& nextSuballoc = suballocations1st[nextSuballocIndex]; + if (VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) + { + return false; + } + } + else + { + // Already on next page. + break; + } + } + } + + // All tests passed: Success. + pAllocationRequest->allocHandle = (VmaAllocHandle)(resultOffset + 1); + pAllocationRequest->type = VmaAllocationRequestType::EndOf2nd; + // pAllocationRequest->item, customData unused. + return true; + } + } + + return false; +} + +bool VmaBlockMetadata_Linear::CreateAllocationRequest_UpperAddress( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + const VkDeviceSize blockSize = GetSize(); + const VkDeviceSize bufferImageGranularity = GetBufferImageGranularity(); + SuballocationVectorType& suballocations1st = AccessSuballocations1st(); + SuballocationVectorType& suballocations2nd = AccessSuballocations2nd(); + + if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER) + { + VMA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer."); + return false; + } + + // Try to allocate before 2nd.back(), or end of block if 2nd.empty(). + if (allocSize > blockSize) + { + return false; + } + VkDeviceSize resultBaseOffset = blockSize - allocSize; + if (!suballocations2nd.empty()) + { + const VmaSuballocation& lastSuballoc = suballocations2nd.back(); + resultBaseOffset = lastSuballoc.offset - allocSize; + if (allocSize > lastSuballoc.offset) + { + return false; + } + } + + // Start from offset equal to end of free space. + VkDeviceSize resultOffset = resultBaseOffset; + + const VkDeviceSize debugMargin = GetDebugMargin(); + + // Apply debugMargin at the end. + if (debugMargin > 0) + { + if (resultOffset < debugMargin) + { + return false; + } + resultOffset -= debugMargin; + } + + // Apply alignment. + resultOffset = VmaAlignDown(resultOffset, allocAlignment); + + // Check next suballocations from 2nd for BufferImageGranularity conflicts. + // Make bigger alignment if necessary. + if (bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty()) + { + bool bufferImageGranularityConflict = false; + for (size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; ) + { + const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex]; + if (VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(nextSuballoc.type, allocType)) + { + bufferImageGranularityConflict = true; + break; + } + } + else + // Already on previous page. + break; + } + if (bufferImageGranularityConflict) + { + resultOffset = VmaAlignDown(resultOffset, bufferImageGranularity); + } + } + + // There is enough free space. + const VkDeviceSize endOf1st = !suballocations1st.empty() ? + suballocations1st.back().offset + suballocations1st.back().size : + 0; + if (endOf1st + debugMargin <= resultOffset) + { + // Check previous suballocations for BufferImageGranularity conflicts. + // If conflict exists, allocation cannot be made here. + if (bufferImageGranularity > 1) + { + for (size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; ) + { + const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex]; + if (VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity)) + { + if (VmaIsBufferImageGranularityConflict(allocType, prevSuballoc.type)) + { + return false; + } + } + else + { + // Already on next page. + break; + } + } + } + + // All tests passed: Success. + pAllocationRequest->allocHandle = (VmaAllocHandle)(resultOffset + 1); + // pAllocationRequest->item unused. + pAllocationRequest->type = VmaAllocationRequestType::UpperAddress; + return true; + } + + return false; +} +#endif // _VMA_BLOCK_METADATA_LINEAR_FUNCTIONS +#endif // _VMA_BLOCK_METADATA_LINEAR + +#if 0 +#ifndef _VMA_BLOCK_METADATA_BUDDY +/* +- GetSize() is the original size of allocated memory block. +- m_UsableSize is this size aligned down to a power of two. + All allocations and calculations happen relative to m_UsableSize. +- GetUnusableSize() is the difference between them. + It is reported as separate, unused range, not available for allocations. + +Node at level 0 has size = m_UsableSize. +Each next level contains nodes with size 2 times smaller than current level. +m_LevelCount is the maximum number of levels to use in the current object. +*/ +class VmaBlockMetadata_Buddy : public VmaBlockMetadata +{ + VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy) +public: + VmaBlockMetadata_Buddy(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata_Buddy(); + + size_t GetAllocationCount() const override { return m_AllocationCount; } + VkDeviceSize GetSumFreeSize() const override { return m_SumFreeSize + GetUnusableSize(); } + bool IsEmpty() const override { return m_Root->type == Node::TYPE_FREE; } + VkResult CheckCorruption(const void* pBlockData) override { return VK_ERROR_FEATURE_NOT_PRESENT; } + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle - 1; }; + void DebugLogAllAllocations() const override { DebugLogAllAllocationNode(m_Root, 0); } + + void Init(VkDeviceSize size) override; + bool Validate() const override; + + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; + void AddStatistics(VmaStatistics& inoutStats) const override; + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const override; +#endif + + bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) override; + + void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) override; + + void Free(VmaAllocHandle allocHandle) override; + void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; + void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; + VmaAllocHandle GetAllocationListBegin() const override; + VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; + void Clear() override; + void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; + +private: + static const size_t MAX_LEVELS = 48; + + struct ValidationContext + { + size_t calculatedAllocationCount = 0; + size_t calculatedFreeCount = 0; + VkDeviceSize calculatedSumFreeSize = 0; + }; + struct Node + { + VkDeviceSize offset; + enum TYPE + { + TYPE_FREE, + TYPE_ALLOCATION, + TYPE_SPLIT, + TYPE_COUNT + } type; + Node* parent; + Node* buddy; + + union + { + struct + { + Node* prev; + Node* next; + } free; + struct + { + void* userData; + } allocation; + struct + { + Node* leftChild; + } split; + }; + }; + + // Size of the memory block aligned down to a power of two. + VkDeviceSize m_UsableSize; + uint32_t m_LevelCount; + VmaPoolAllocator m_NodeAllocator; + Node* m_Root; + struct + { + Node* front; + Node* back; + } m_FreeList[MAX_LEVELS]; + + // Number of nodes in the tree with type == TYPE_ALLOCATION. + size_t m_AllocationCount; + // Number of nodes in the tree with type == TYPE_FREE. + size_t m_FreeCount; + // Doesn't include space wasted due to internal fragmentation - allocation sizes are just aligned up to node sizes. + // Doesn't include unusable size. + VkDeviceSize m_SumFreeSize; + + VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; } + VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; } + + VkDeviceSize AlignAllocationSize(VkDeviceSize size) const + { + if (!IsVirtual()) + { + size = VmaAlignUp(size, (VkDeviceSize)16); + } + return VmaNextPow2(size); + } + Node* FindAllocationNode(VkDeviceSize offset, uint32_t& outLevel) const; + void DeleteNodeChildren(Node* node); + bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const; + uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const; + void AddNodeToDetailedStatistics(VmaDetailedStatistics& inoutStats, const Node* node, VkDeviceSize levelNodeSize) const; + // Adds node to the front of FreeList at given level. + // node->type must be FREE. + // node->free.prev, next can be undefined. + void AddToFreeListFront(uint32_t level, Node* node); + // Removes node from FreeList at given level. + // node->type must be FREE. + // node->free.prev, next stay untouched. + void RemoveFromFreeList(uint32_t level, Node* node); + void DebugLogAllAllocationNode(Node* node, uint32_t level) const; + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const; +#endif +}; + +#ifndef _VMA_BLOCK_METADATA_BUDDY_FUNCTIONS +VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), + m_NodeAllocator(pAllocationCallbacks, 32), // firstBlockCapacity + m_Root(VMA_NULL), + m_AllocationCount(0), + m_FreeCount(1), + m_SumFreeSize(0) +{ + memset(m_FreeList, 0, sizeof(m_FreeList)); +} + +VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy() +{ + DeleteNodeChildren(m_Root); + m_NodeAllocator.Free(m_Root); +} + +void VmaBlockMetadata_Buddy::Init(VkDeviceSize size) +{ + VmaBlockMetadata::Init(size); + + m_UsableSize = VmaPrevPow2(size); + m_SumFreeSize = m_UsableSize; + + // Calculate m_LevelCount. + const VkDeviceSize minNodeSize = IsVirtual() ? 1 : 16; + m_LevelCount = 1; + while (m_LevelCount < MAX_LEVELS && + LevelToNodeSize(m_LevelCount) >= minNodeSize) + { + ++m_LevelCount; + } + + Node* rootNode = m_NodeAllocator.Alloc(); + rootNode->offset = 0; + rootNode->type = Node::TYPE_FREE; + rootNode->parent = VMA_NULL; + rootNode->buddy = VMA_NULL; + + m_Root = rootNode; + AddToFreeListFront(0, rootNode); +} + +bool VmaBlockMetadata_Buddy::Validate() const +{ + // Validate tree. + ValidationContext ctx; + if (!ValidateNode(ctx, VMA_NULL, m_Root, 0, LevelToNodeSize(0))) + { + VMA_VALIDATE(false && "ValidateNode failed."); + } + VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount); + VMA_VALIDATE(m_SumFreeSize == ctx.calculatedSumFreeSize); + + // Validate free node lists. + for (uint32_t level = 0; level < m_LevelCount; ++level) + { + VMA_VALIDATE(m_FreeList[level].front == VMA_NULL || + m_FreeList[level].front->free.prev == VMA_NULL); + + for (Node* node = m_FreeList[level].front; + node != VMA_NULL; + node = node->free.next) + { + VMA_VALIDATE(node->type == Node::TYPE_FREE); + + if (node->free.next == VMA_NULL) + { + VMA_VALIDATE(m_FreeList[level].back == node); + } + else + { + VMA_VALIDATE(node->free.next->free.prev == node); + } + } + } + + // Validate that free lists ar higher levels are empty. + for (uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level) + { + VMA_VALIDATE(m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL); + } + + return true; +} + +void VmaBlockMetadata_Buddy::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const +{ + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += GetSize(); + + AddNodeToDetailedStatistics(inoutStats, m_Root, LevelToNodeSize(0)); + + const VkDeviceSize unusableSize = GetUnusableSize(); + if (unusableSize > 0) + VmaAddDetailedStatisticsUnusedRange(inoutStats, unusableSize); +} + +void VmaBlockMetadata_Buddy::AddStatistics(VmaStatistics& inoutStats) const +{ + inoutStats.blockCount++; + inoutStats.allocationCount += (uint32_t)m_AllocationCount; + inoutStats.blockBytes += GetSize(); + inoutStats.allocationBytes += GetSize() - m_SumFreeSize; +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json, uint32_t mapRefCount) const +{ + VmaDetailedStatistics stats; + VmaClearDetailedStatistics(stats); + AddDetailedStatistics(stats); + + PrintDetailedMap_Begin( + json, + stats.statistics.blockBytes - stats.statistics.allocationBytes, + stats.statistics.allocationCount, + stats.unusedRangeCount, + mapRefCount); + + PrintDetailedMapNode(json, m_Root, LevelToNodeSize(0)); + + const VkDeviceSize unusableSize = GetUnusableSize(); + if (unusableSize > 0) + { + PrintDetailedMap_UnusedRange(json, + m_UsableSize, // offset + unusableSize); // size + } + + PrintDetailedMap_End(json); +} +#endif // VMA_STATS_STRING_ENABLED + +bool VmaBlockMetadata_Buddy::CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm."); + + allocSize = AlignAllocationSize(allocSize); + + // Simple way to respect bufferImageGranularity. May be optimized some day. + // Whenever it might be an OPTIMAL image... + if (allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN || + allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || + allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL) + { + allocAlignment = VMA_MAX(allocAlignment, GetBufferImageGranularity()); + allocSize = VmaAlignUp(allocSize, GetBufferImageGranularity()); + } + + if (allocSize > m_UsableSize) + { + return false; + } + + const uint32_t targetLevel = AllocSizeToLevel(allocSize); + for (uint32_t level = targetLevel; level--; ) + { + for (Node* freeNode = m_FreeList[level].front; + freeNode != VMA_NULL; + freeNode = freeNode->free.next) + { + if (freeNode->offset % allocAlignment == 0) + { + pAllocationRequest->type = VmaAllocationRequestType::Normal; + pAllocationRequest->allocHandle = (VmaAllocHandle)(freeNode->offset + 1); + pAllocationRequest->size = allocSize; + pAllocationRequest->customData = (void*)(uintptr_t)level; + return true; + } + } + } + + return false; +} + +void VmaBlockMetadata_Buddy::Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) +{ + VMA_ASSERT(request.type == VmaAllocationRequestType::Normal); + + const uint32_t targetLevel = AllocSizeToLevel(request.size); + uint32_t currLevel = (uint32_t)(uintptr_t)request.customData; + + Node* currNode = m_FreeList[currLevel].front; + VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); + const VkDeviceSize offset = (VkDeviceSize)request.allocHandle - 1; + while (currNode->offset != offset) + { + currNode = currNode->free.next; + VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE); + } + + // Go down, splitting free nodes. + while (currLevel < targetLevel) + { + // currNode is already first free node at currLevel. + // Remove it from list of free nodes at this currLevel. + RemoveFromFreeList(currLevel, currNode); + + const uint32_t childrenLevel = currLevel + 1; + + // Create two free sub-nodes. + Node* leftChild = m_NodeAllocator.Alloc(); + Node* rightChild = m_NodeAllocator.Alloc(); + + leftChild->offset = currNode->offset; + leftChild->type = Node::TYPE_FREE; + leftChild->parent = currNode; + leftChild->buddy = rightChild; + + rightChild->offset = currNode->offset + LevelToNodeSize(childrenLevel); + rightChild->type = Node::TYPE_FREE; + rightChild->parent = currNode; + rightChild->buddy = leftChild; + + // Convert current currNode to split type. + currNode->type = Node::TYPE_SPLIT; + currNode->split.leftChild = leftChild; + + // Add child nodes to free list. Order is important! + AddToFreeListFront(childrenLevel, rightChild); + AddToFreeListFront(childrenLevel, leftChild); + + ++m_FreeCount; + ++currLevel; + currNode = m_FreeList[currLevel].front; + + /* + We can be sure that currNode, as left child of node previously split, + also fulfills the alignment requirement. + */ + } + + // Remove from free list. + VMA_ASSERT(currLevel == targetLevel && + currNode != VMA_NULL && + currNode->type == Node::TYPE_FREE); + RemoveFromFreeList(currLevel, currNode); + + // Convert to allocation node. + currNode->type = Node::TYPE_ALLOCATION; + currNode->allocation.userData = userData; + + ++m_AllocationCount; + --m_FreeCount; + m_SumFreeSize -= request.size; +} + +void VmaBlockMetadata_Buddy::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) +{ + uint32_t level = 0; + outInfo.offset = (VkDeviceSize)allocHandle - 1; + const Node* const node = FindAllocationNode(outInfo.offset, level); + outInfo.size = LevelToNodeSize(level); + outInfo.pUserData = node->allocation.userData; +} + +void* VmaBlockMetadata_Buddy::GetAllocationUserData(VmaAllocHandle allocHandle) const +{ + uint32_t level = 0; + const Node* const node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); + return node->allocation.userData; +} + +VmaAllocHandle VmaBlockMetadata_Buddy::GetAllocationListBegin() const +{ + // Function only used for defragmentation, which is disabled for this algorithm + return VK_NULL_HANDLE; +} + +VmaAllocHandle VmaBlockMetadata_Buddy::GetNextAllocation(VmaAllocHandle prevAlloc) const +{ + // Function only used for defragmentation, which is disabled for this algorithm + return VK_NULL_HANDLE; +} + +void VmaBlockMetadata_Buddy::DeleteNodeChildren(Node* node) +{ + if (node->type == Node::TYPE_SPLIT) + { + DeleteNodeChildren(node->split.leftChild->buddy); + DeleteNodeChildren(node->split.leftChild); + const VkAllocationCallbacks* allocationCallbacks = GetAllocationCallbacks(); + m_NodeAllocator.Free(node->split.leftChild->buddy); + m_NodeAllocator.Free(node->split.leftChild); + } +} + +void VmaBlockMetadata_Buddy::Clear() +{ + DeleteNodeChildren(m_Root); + m_Root->type = Node::TYPE_FREE; + m_AllocationCount = 0; + m_FreeCount = 1; + m_SumFreeSize = m_UsableSize; +} + +void VmaBlockMetadata_Buddy::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) +{ + uint32_t level = 0; + Node* const node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); + node->allocation.userData = userData; +} + +VmaBlockMetadata_Buddy::Node* VmaBlockMetadata_Buddy::FindAllocationNode(VkDeviceSize offset, uint32_t& outLevel) const +{ + Node* node = m_Root; + VkDeviceSize nodeOffset = 0; + outLevel = 0; + VkDeviceSize levelNodeSize = LevelToNodeSize(0); + while (node->type == Node::TYPE_SPLIT) + { + const VkDeviceSize nextLevelNodeSize = levelNodeSize >> 1; + if (offset < nodeOffset + nextLevelNodeSize) + { + node = node->split.leftChild; + } + else + { + node = node->split.leftChild->buddy; + nodeOffset += nextLevelNodeSize; + } + ++outLevel; + levelNodeSize = nextLevelNodeSize; + } + + VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION); + return node; +} + +bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const +{ + VMA_VALIDATE(level < m_LevelCount); + VMA_VALIDATE(curr->parent == parent); + VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL)); + VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr); + switch (curr->type) + { + case Node::TYPE_FREE: + // curr->free.prev, next are validated separately. + ctx.calculatedSumFreeSize += levelNodeSize; + ++ctx.calculatedFreeCount; + break; + case Node::TYPE_ALLOCATION: + ++ctx.calculatedAllocationCount; + if (!IsVirtual()) + { + VMA_VALIDATE(curr->allocation.userData != VMA_NULL); + } + break; + case Node::TYPE_SPLIT: + { + const uint32_t childrenLevel = level + 1; + const VkDeviceSize childrenLevelNodeSize = levelNodeSize >> 1; + const Node* const leftChild = curr->split.leftChild; + VMA_VALIDATE(leftChild != VMA_NULL); + VMA_VALIDATE(leftChild->offset == curr->offset); + if (!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize)) + { + VMA_VALIDATE(false && "ValidateNode for left child failed."); + } + const Node* const rightChild = leftChild->buddy; + VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize); + if (!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize)) + { + VMA_VALIDATE(false && "ValidateNode for right child failed."); + } + } + break; + default: + return false; + } + + return true; +} + +uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const +{ + // I know this could be optimized somehow e.g. by using std::log2p1 from C++20. + uint32_t level = 0; + VkDeviceSize currLevelNodeSize = m_UsableSize; + VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1; + while (allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount) + { + ++level; + currLevelNodeSize >>= 1; + nextLevelNodeSize >>= 1; + } + return level; +} + +void VmaBlockMetadata_Buddy::Free(VmaAllocHandle allocHandle) +{ + uint32_t level = 0; + Node* node = FindAllocationNode((VkDeviceSize)allocHandle - 1, level); + + ++m_FreeCount; + --m_AllocationCount; + m_SumFreeSize += LevelToNodeSize(level); + + node->type = Node::TYPE_FREE; + + // Join free nodes if possible. + while (level > 0 && node->buddy->type == Node::TYPE_FREE) + { + RemoveFromFreeList(level, node->buddy); + Node* const parent = node->parent; + + m_NodeAllocator.Free(node->buddy); + m_NodeAllocator.Free(node); + parent->type = Node::TYPE_FREE; + + node = parent; + --level; + --m_FreeCount; + } + + AddToFreeListFront(level, node); +} + +void VmaBlockMetadata_Buddy::AddNodeToDetailedStatistics(VmaDetailedStatistics& inoutStats, const Node* node, VkDeviceSize levelNodeSize) const +{ + switch (node->type) + { + case Node::TYPE_FREE: + VmaAddDetailedStatisticsUnusedRange(inoutStats, levelNodeSize); + break; + case Node::TYPE_ALLOCATION: + VmaAddDetailedStatisticsAllocation(inoutStats, levelNodeSize); + break; + case Node::TYPE_SPLIT: + { + const VkDeviceSize childrenNodeSize = levelNodeSize / 2; + const Node* const leftChild = node->split.leftChild; + AddNodeToDetailedStatistics(inoutStats, leftChild, childrenNodeSize); + const Node* const rightChild = leftChild->buddy; + AddNodeToDetailedStatistics(inoutStats, rightChild, childrenNodeSize); + } + break; + default: + VMA_ASSERT(0); + } +} + +void VmaBlockMetadata_Buddy::AddToFreeListFront(uint32_t level, Node* node) +{ + VMA_ASSERT(node->type == Node::TYPE_FREE); + + // List is empty. + Node* const frontNode = m_FreeList[level].front; + if (frontNode == VMA_NULL) + { + VMA_ASSERT(m_FreeList[level].back == VMA_NULL); + node->free.prev = node->free.next = VMA_NULL; + m_FreeList[level].front = m_FreeList[level].back = node; + } + else + { + VMA_ASSERT(frontNode->free.prev == VMA_NULL); + node->free.prev = VMA_NULL; + node->free.next = frontNode; + frontNode->free.prev = node; + m_FreeList[level].front = node; + } +} + +void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node) +{ + VMA_ASSERT(m_FreeList[level].front != VMA_NULL); + + // It is at the front. + if (node->free.prev == VMA_NULL) + { + VMA_ASSERT(m_FreeList[level].front == node); + m_FreeList[level].front = node->free.next; + } + else + { + Node* const prevFreeNode = node->free.prev; + VMA_ASSERT(prevFreeNode->free.next == node); + prevFreeNode->free.next = node->free.next; + } + + // It is at the back. + if (node->free.next == VMA_NULL) + { + VMA_ASSERT(m_FreeList[level].back == node); + m_FreeList[level].back = node->free.prev; + } + else + { + Node* const nextFreeNode = node->free.next; + VMA_ASSERT(nextFreeNode->free.prev == node); + nextFreeNode->free.prev = node->free.prev; + } +} + +void VmaBlockMetadata_Buddy::DebugLogAllAllocationNode(Node* node, uint32_t level) const +{ + switch (node->type) + { + case Node::TYPE_FREE: + break; + case Node::TYPE_ALLOCATION: + DebugLogAllocation(node->offset, LevelToNodeSize(level), node->allocation.userData); + break; + case Node::TYPE_SPLIT: + { + ++level; + DebugLogAllAllocationNode(node->split.leftChild, level); + DebugLogAllAllocationNode(node->split.leftChild->buddy, level); + } + break; + default: + VMA_ASSERT(0); + } +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const +{ + switch (node->type) + { + case Node::TYPE_FREE: + PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize); + break; + case Node::TYPE_ALLOCATION: + PrintDetailedMap_Allocation(json, node->offset, levelNodeSize, node->allocation.userData); + break; + case Node::TYPE_SPLIT: + { + const VkDeviceSize childrenNodeSize = levelNodeSize / 2; + const Node* const leftChild = node->split.leftChild; + PrintDetailedMapNode(json, leftChild, childrenNodeSize); + const Node* const rightChild = leftChild->buddy; + PrintDetailedMapNode(json, rightChild, childrenNodeSize); + } + break; + default: + VMA_ASSERT(0); + } +} +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_BLOCK_METADATA_BUDDY_FUNCTIONS +#endif // _VMA_BLOCK_METADATA_BUDDY +#endif // #if 0 + +#ifndef _VMA_BLOCK_METADATA_TLSF +// To not search current larger region if first allocation won't succeed and skip to smaller range +// use with VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT as strategy in CreateAllocationRequest(). +// When fragmentation and reusal of previous blocks doesn't matter then use with +// VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT for fastest alloc time possible. +class VmaBlockMetadata_TLSF : public VmaBlockMetadata +{ + VMA_CLASS_NO_COPY(VmaBlockMetadata_TLSF) +public: + VmaBlockMetadata_TLSF(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual); + virtual ~VmaBlockMetadata_TLSF(); + + size_t GetAllocationCount() const override { return m_AllocCount; } + size_t GetFreeRegionsCount() const override { return m_BlocksFreeCount + 1; } + VkDeviceSize GetSumFreeSize() const override { return m_BlocksFreeSize + m_NullBlock->size; } + bool IsEmpty() const override { return m_NullBlock->offset == 0; } + VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; }; + + void Init(VkDeviceSize size) override; + bool Validate() const override; + + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const override; + void AddStatistics(VmaStatistics& inoutStats) const override; + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json) const override; +#endif + + bool CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) override; + + VkResult CheckCorruption(const void* pBlockData) override; + void Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) override; + + void Free(VmaAllocHandle allocHandle) override; + void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override; + void* GetAllocationUserData(VmaAllocHandle allocHandle) const override; + VmaAllocHandle GetAllocationListBegin() const override; + VmaAllocHandle GetNextAllocation(VmaAllocHandle prevAlloc) const override; + VkDeviceSize GetNextFreeRegionSize(VmaAllocHandle alloc) const override; + void Clear() override; + void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override; + void DebugLogAllAllocations() const override; + +private: + // According to original paper it should be preferable 4 or 5: + // M. Masmano, I. Ripoll, A. Crespo, and J. Real "TLSF: a New Dynamic Memory Allocator for Real-Time Systems" + // http://www.gii.upv.es/tlsf/files/ecrts04_tlsf.pdf + static const uint8_t SECOND_LEVEL_INDEX = 5; + static const uint16_t SMALL_BUFFER_SIZE = 256; + static const uint32_t INITIAL_BLOCK_ALLOC_COUNT = 16; + static const uint8_t MEMORY_CLASS_SHIFT = 7; + static const uint8_t MAX_MEMORY_CLASSES = 65 - MEMORY_CLASS_SHIFT; + + class Block + { + public: + VkDeviceSize offset; + VkDeviceSize size; + Block* prevPhysical; + Block* nextPhysical; + + void MarkFree() { prevFree = VMA_NULL; } + void MarkTaken() { prevFree = this; } + bool IsFree() const { return prevFree != this; } + void*& UserData() { VMA_HEAVY_ASSERT(!IsFree()); return userData; } + Block*& PrevFree() { return prevFree; } + Block*& NextFree() { VMA_HEAVY_ASSERT(IsFree()); return nextFree; } + + private: + Block* prevFree; // Address of the same block here indicates that block is taken + union + { + Block* nextFree; + void* userData; + }; + }; + + size_t m_AllocCount; + // Total number of free blocks besides null block + size_t m_BlocksFreeCount; + // Total size of free blocks excluding null block + VkDeviceSize m_BlocksFreeSize; + uint32_t m_IsFreeBitmap; + uint8_t m_MemoryClasses; + uint32_t m_InnerIsFreeBitmap[MAX_MEMORY_CLASSES]; + uint32_t m_ListsCount; + /* + * 0: 0-3 lists for small buffers + * 1+: 0-(2^SLI-1) lists for normal buffers + */ + Block** m_FreeList; + VmaPoolAllocator m_BlockAllocator; + Block* m_NullBlock; + VmaBlockBufferImageGranularity m_GranularityHandler; + + uint8_t SizeToMemoryClass(VkDeviceSize size) const; + uint16_t SizeToSecondIndex(VkDeviceSize size, uint8_t memoryClass) const; + uint32_t GetListIndex(uint8_t memoryClass, uint16_t secondIndex) const; + uint32_t GetListIndex(VkDeviceSize size) const; + + void RemoveFreeBlock(Block* block); + void InsertFreeBlock(Block* block); + void MergeBlock(Block* block, Block* prev); + + Block* FindFreeBlock(VkDeviceSize size, uint32_t& listIndex) const; + bool CheckBlock( + Block& block, + uint32_t listIndex, + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + VmaAllocationRequest* pAllocationRequest); +}; + +#ifndef _VMA_BLOCK_METADATA_TLSF_FUNCTIONS +VmaBlockMetadata_TLSF::VmaBlockMetadata_TLSF(const VkAllocationCallbacks* pAllocationCallbacks, + VkDeviceSize bufferImageGranularity, bool isVirtual) + : VmaBlockMetadata(pAllocationCallbacks, bufferImageGranularity, isVirtual), + m_AllocCount(0), + m_BlocksFreeCount(0), + m_BlocksFreeSize(0), + m_IsFreeBitmap(0), + m_MemoryClasses(0), + m_ListsCount(0), + m_FreeList(VMA_NULL), + m_BlockAllocator(pAllocationCallbacks, INITIAL_BLOCK_ALLOC_COUNT), + m_NullBlock(VMA_NULL), + m_GranularityHandler(bufferImageGranularity) {} + +VmaBlockMetadata_TLSF::~VmaBlockMetadata_TLSF() +{ + if (m_FreeList) + vma_delete_array(GetAllocationCallbacks(), m_FreeList, m_ListsCount); + m_GranularityHandler.Destroy(GetAllocationCallbacks()); +} + +void VmaBlockMetadata_TLSF::Init(VkDeviceSize size) +{ + VmaBlockMetadata::Init(size); + + if (!IsVirtual()) + m_GranularityHandler.Init(GetAllocationCallbacks(), size); + + m_NullBlock = m_BlockAllocator.Alloc(); + m_NullBlock->size = size; + m_NullBlock->offset = 0; + m_NullBlock->prevPhysical = VMA_NULL; + m_NullBlock->nextPhysical = VMA_NULL; + m_NullBlock->MarkFree(); + m_NullBlock->NextFree() = VMA_NULL; + m_NullBlock->PrevFree() = VMA_NULL; + uint8_t memoryClass = SizeToMemoryClass(size); + uint16_t sli = SizeToSecondIndex(size, memoryClass); + m_ListsCount = (memoryClass == 0 ? 0 : (memoryClass - 1) * (1UL << SECOND_LEVEL_INDEX) + sli) + 1; + if (IsVirtual()) + m_ListsCount += 1UL << SECOND_LEVEL_INDEX; + else + m_ListsCount += 4; + + m_MemoryClasses = memoryClass + 2; + memset(m_InnerIsFreeBitmap, 0, MAX_MEMORY_CLASSES * sizeof(uint32_t)); + + m_FreeList = vma_new_array(GetAllocationCallbacks(), Block*, m_ListsCount); + memset(m_FreeList, 0, m_ListsCount * sizeof(Block*)); +} + +bool VmaBlockMetadata_TLSF::Validate() const +{ + VMA_VALIDATE(GetSumFreeSize() <= GetSize()); + + VkDeviceSize calculatedSize = m_NullBlock->size; + VkDeviceSize calculatedFreeSize = m_NullBlock->size; + size_t allocCount = 0; + size_t freeCount = 0; + + // Check integrity of free lists + for (uint32_t list = 0; list < m_ListsCount; ++list) + { + Block* block = m_FreeList[list]; + if (block != VMA_NULL) + { + VMA_VALIDATE(block->IsFree()); + VMA_VALIDATE(block->PrevFree() == VMA_NULL); + while (block->NextFree()) + { + VMA_VALIDATE(block->NextFree()->IsFree()); + VMA_VALIDATE(block->NextFree()->PrevFree() == block); + block = block->NextFree(); + } + } + } + + VkDeviceSize nextOffset = m_NullBlock->offset; + auto validateCtx = m_GranularityHandler.StartValidation(GetAllocationCallbacks(), IsVirtual()); + + VMA_VALIDATE(m_NullBlock->nextPhysical == VMA_NULL); + if (m_NullBlock->prevPhysical) + { + VMA_VALIDATE(m_NullBlock->prevPhysical->nextPhysical == m_NullBlock); + } + // Check all blocks + for (Block* prev = m_NullBlock->prevPhysical; prev != VMA_NULL; prev = prev->prevPhysical) + { + VMA_VALIDATE(prev->offset + prev->size == nextOffset); + nextOffset = prev->offset; + calculatedSize += prev->size; + + uint32_t listIndex = GetListIndex(prev->size); + if (prev->IsFree()) + { + ++freeCount; + // Check if free block belongs to free list + Block* freeBlock = m_FreeList[listIndex]; + VMA_VALIDATE(freeBlock != VMA_NULL); + + bool found = false; + do + { + if (freeBlock == prev) + found = true; + + freeBlock = freeBlock->NextFree(); + } while (!found && freeBlock != VMA_NULL); + + VMA_VALIDATE(found); + calculatedFreeSize += prev->size; + } + else + { + ++allocCount; + // Check if taken block is not on a free list + Block* freeBlock = m_FreeList[listIndex]; + while (freeBlock) + { + VMA_VALIDATE(freeBlock != prev); + freeBlock = freeBlock->NextFree(); + } + + if (!IsVirtual()) + { + VMA_VALIDATE(m_GranularityHandler.Validate(validateCtx, prev->offset, prev->size)); + } + } + + if (prev->prevPhysical) + { + VMA_VALIDATE(prev->prevPhysical->nextPhysical == prev); + } + } + + if (!IsVirtual()) + { + VMA_VALIDATE(m_GranularityHandler.FinishValidation(validateCtx)); + } + + VMA_VALIDATE(nextOffset == 0); + VMA_VALIDATE(calculatedSize == GetSize()); + VMA_VALIDATE(calculatedFreeSize == GetSumFreeSize()); + VMA_VALIDATE(allocCount == m_AllocCount); + VMA_VALIDATE(freeCount == m_BlocksFreeCount); + + return true; +} + +void VmaBlockMetadata_TLSF::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) const +{ + inoutStats.statistics.blockCount++; + inoutStats.statistics.blockBytes += GetSize(); + if (m_NullBlock->size > 0) + VmaAddDetailedStatisticsUnusedRange(inoutStats, m_NullBlock->size); + + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + { + if (block->IsFree()) + VmaAddDetailedStatisticsUnusedRange(inoutStats, block->size); + else + VmaAddDetailedStatisticsAllocation(inoutStats, block->size); + } +} + +void VmaBlockMetadata_TLSF::AddStatistics(VmaStatistics& inoutStats) const +{ + inoutStats.blockCount++; + inoutStats.allocationCount += (uint32_t)m_AllocCount; + inoutStats.blockBytes += GetSize(); + inoutStats.allocationBytes += GetSize() - GetSumFreeSize(); +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockMetadata_TLSF::PrintDetailedMap(class VmaJsonWriter& json) const +{ + size_t blockCount = m_AllocCount + m_BlocksFreeCount; + VmaStlAllocator allocator(GetAllocationCallbacks()); + VmaVector> blockList(blockCount, allocator); + + size_t i = blockCount; + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + { + blockList[--i] = block; + } + VMA_ASSERT(i == 0); + + VmaDetailedStatistics stats; + VmaClearDetailedStatistics(stats); + AddDetailedStatistics(stats); + + PrintDetailedMap_Begin(json, + stats.statistics.blockBytes - stats.statistics.allocationBytes, + stats.statistics.allocationCount, + stats.unusedRangeCount); + + for (; i < blockCount; ++i) + { + Block* block = blockList[i]; + if (block->IsFree()) + PrintDetailedMap_UnusedRange(json, block->offset, block->size); + else + PrintDetailedMap_Allocation(json, block->offset, block->size, block->UserData()); + } + if (m_NullBlock->size > 0) + PrintDetailedMap_UnusedRange(json, m_NullBlock->offset, m_NullBlock->size); + + PrintDetailedMap_End(json); +} +#endif + +bool VmaBlockMetadata_TLSF::CreateAllocationRequest( + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + bool upperAddress, + VmaSuballocationType allocType, + uint32_t strategy, + VmaAllocationRequest* pAllocationRequest) +{ + VMA_ASSERT(allocSize > 0 && "Cannot allocate empty block!"); + VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm."); + + // For small granularity round up + if (!IsVirtual()) + m_GranularityHandler.RoundupAllocRequest(allocType, allocSize, allocAlignment); + + allocSize += GetDebugMargin(); + // Quick check for too small pool + if (allocSize > GetSumFreeSize()) + return false; + + // If no free blocks in pool then check only null block + if (m_BlocksFreeCount == 0) + return CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest); + + // Round up to the next block + VkDeviceSize sizeForNextList = allocSize; + VkDeviceSize smallSizeStep = SMALL_BUFFER_SIZE / (IsVirtual() ? 1 << SECOND_LEVEL_INDEX : 4); + if (allocSize > SMALL_BUFFER_SIZE) + { + sizeForNextList += (1ULL << (VMA_BITSCAN_MSB(allocSize) - SECOND_LEVEL_INDEX)); + } + else if (allocSize > SMALL_BUFFER_SIZE - smallSizeStep) + sizeForNextList = SMALL_BUFFER_SIZE + 1; + else + sizeForNextList += smallSizeStep; + + uint32_t nextListIndex = 0; + uint32_t prevListIndex = 0; + Block* nextListBlock = VMA_NULL; + Block* prevListBlock = VMA_NULL; + + // Check blocks according to strategies + if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT) + { + // Quick check for larger block first + nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex); + if (nextListBlock != VMA_NULL && CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + + // If not fitted then null block + if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + + // Null block failed, search larger bucket + while (nextListBlock) + { + if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + nextListBlock = nextListBlock->NextFree(); + } + + // Failed again, check best fit bucket + prevListBlock = FindFreeBlock(allocSize, prevListIndex); + while (prevListBlock) + { + if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + prevListBlock = prevListBlock->NextFree(); + } + } + else if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT) + { + // Check best fit bucket + prevListBlock = FindFreeBlock(allocSize, prevListIndex); + while (prevListBlock) + { + if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + prevListBlock = prevListBlock->NextFree(); + } + + // If failed check null block + if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + + // Check larger bucket + nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex); + while (nextListBlock) + { + if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + nextListBlock = nextListBlock->NextFree(); + } + } + else if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT ) + { + // Perform search from the start + VmaStlAllocator allocator(GetAllocationCallbacks()); + VmaVector> blockList(m_BlocksFreeCount, allocator); + + size_t i = m_BlocksFreeCount; + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + { + if (block->IsFree() && block->size >= allocSize) + blockList[--i] = block; + } + + for (; i < m_BlocksFreeCount; ++i) + { + Block& block = *blockList[i]; + if (CheckBlock(block, GetListIndex(block.size), allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + } + + // If failed check null block + if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + + // Whole range searched, no more memory + return false; + } + else + { + // Check larger bucket + nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex); + while (nextListBlock) + { + if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + nextListBlock = nextListBlock->NextFree(); + } + + // If failed check null block + if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + + // Check best fit bucket + prevListBlock = FindFreeBlock(allocSize, prevListIndex); + while (prevListBlock) + { + if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + prevListBlock = prevListBlock->NextFree(); + } + } + + // Worst case, full search has to be done + while (++nextListIndex < m_ListsCount) + { + nextListBlock = m_FreeList[nextListIndex]; + while (nextListBlock) + { + if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, allocType, pAllocationRequest)) + return true; + nextListBlock = nextListBlock->NextFree(); + } + } + + // No more memory sadly + return false; +} + +VkResult VmaBlockMetadata_TLSF::CheckCorruption(const void* pBlockData) +{ + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + { + if (!block->IsFree()) + { + if (!VmaValidateMagicValue(pBlockData, block->offset + block->size)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!"); + return VK_ERROR_UNKNOWN_COPY; + } + } + } + + return VK_SUCCESS; +} + +void VmaBlockMetadata_TLSF::Alloc( + const VmaAllocationRequest& request, + VmaSuballocationType type, + void* userData) +{ + VMA_ASSERT(request.type == VmaAllocationRequestType::TLSF); + + // Get block and pop it from the free list + Block* currentBlock = (Block*)request.allocHandle; + VkDeviceSize offset = request.algorithmData; + VMA_ASSERT(currentBlock != VMA_NULL); + VMA_ASSERT(currentBlock->offset <= offset); + + if (currentBlock != m_NullBlock) + RemoveFreeBlock(currentBlock); + + VkDeviceSize debugMargin = GetDebugMargin(); + VkDeviceSize misssingAlignment = offset - currentBlock->offset; + + // Append missing alignment to prev block or create new one + if (misssingAlignment) + { + Block* prevBlock = currentBlock->prevPhysical; + VMA_ASSERT(prevBlock != VMA_NULL && "There should be no missing alignment at offset 0!"); + + if (prevBlock->IsFree() && prevBlock->size != debugMargin) + { + uint32_t oldList = GetListIndex(prevBlock->size); + prevBlock->size += misssingAlignment; + // Check if new size crosses list bucket + if (oldList != GetListIndex(prevBlock->size)) + { + prevBlock->size -= misssingAlignment; + RemoveFreeBlock(prevBlock); + prevBlock->size += misssingAlignment; + InsertFreeBlock(prevBlock); + } + else + m_BlocksFreeSize += misssingAlignment; + } + else + { + Block* newBlock = m_BlockAllocator.Alloc(); + currentBlock->prevPhysical = newBlock; + prevBlock->nextPhysical = newBlock; + newBlock->prevPhysical = prevBlock; + newBlock->nextPhysical = currentBlock; + newBlock->size = misssingAlignment; + newBlock->offset = currentBlock->offset; + newBlock->MarkTaken(); + + InsertFreeBlock(newBlock); + } + + currentBlock->size -= misssingAlignment; + currentBlock->offset += misssingAlignment; + } + + VkDeviceSize size = request.size + debugMargin; + if (currentBlock->size == size) + { + if (currentBlock == m_NullBlock) + { + // Setup new null block + m_NullBlock = m_BlockAllocator.Alloc(); + m_NullBlock->size = 0; + m_NullBlock->offset = currentBlock->offset + size; + m_NullBlock->prevPhysical = currentBlock; + m_NullBlock->nextPhysical = VMA_NULL; + m_NullBlock->MarkFree(); + m_NullBlock->PrevFree() = VMA_NULL; + m_NullBlock->NextFree() = VMA_NULL; + currentBlock->nextPhysical = m_NullBlock; + currentBlock->MarkTaken(); + } + } + else + { + VMA_ASSERT(currentBlock->size > size && "Proper block already found, shouldn't find smaller one!"); + + // Create new free block + Block* newBlock = m_BlockAllocator.Alloc(); + newBlock->size = currentBlock->size - size; + newBlock->offset = currentBlock->offset + size; + newBlock->prevPhysical = currentBlock; + newBlock->nextPhysical = currentBlock->nextPhysical; + currentBlock->nextPhysical = newBlock; + currentBlock->size = size; + + if (currentBlock == m_NullBlock) + { + m_NullBlock = newBlock; + m_NullBlock->MarkFree(); + m_NullBlock->NextFree() = VMA_NULL; + m_NullBlock->PrevFree() = VMA_NULL; + currentBlock->MarkTaken(); + } + else + { + newBlock->nextPhysical->prevPhysical = newBlock; + newBlock->MarkTaken(); + InsertFreeBlock(newBlock); + } + } + currentBlock->UserData() = userData; + + if (debugMargin > 0) + { + currentBlock->size -= debugMargin; + Block* newBlock = m_BlockAllocator.Alloc(); + newBlock->size = debugMargin; + newBlock->offset = currentBlock->offset + currentBlock->size; + newBlock->prevPhysical = currentBlock; + newBlock->nextPhysical = currentBlock->nextPhysical; + newBlock->MarkTaken(); + currentBlock->nextPhysical->prevPhysical = newBlock; + currentBlock->nextPhysical = newBlock; + InsertFreeBlock(newBlock); + } + + if (!IsVirtual()) + m_GranularityHandler.AllocPages((uint8_t)(uintptr_t)request.customData, + currentBlock->offset, currentBlock->size); + ++m_AllocCount; +} + +void VmaBlockMetadata_TLSF::Free(VmaAllocHandle allocHandle) +{ + Block* block = (Block*)allocHandle; + Block* next = block->nextPhysical; + VMA_ASSERT(!block->IsFree() && "Block is already free!"); + + if (!IsVirtual()) + m_GranularityHandler.FreePages(block->offset, block->size); + --m_AllocCount; + + VkDeviceSize debugMargin = GetDebugMargin(); + if (debugMargin > 0) + { + RemoveFreeBlock(next); + MergeBlock(next, block); + block = next; + next = next->nextPhysical; + } + + // Try merging + Block* prev = block->prevPhysical; + if (prev != VMA_NULL && prev->IsFree() && prev->size != debugMargin) + { + RemoveFreeBlock(prev); + MergeBlock(block, prev); + } + + if (!next->IsFree()) + InsertFreeBlock(block); + else if (next == m_NullBlock) + MergeBlock(m_NullBlock, block); + else + { + RemoveFreeBlock(next); + MergeBlock(next, block); + InsertFreeBlock(next); + } +} + +void VmaBlockMetadata_TLSF::GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) +{ + Block* block = (Block*)allocHandle; + VMA_ASSERT(!block->IsFree() && "Cannot get allocation info for free block!"); + outInfo.offset = block->offset; + outInfo.size = block->size; + outInfo.pUserData = block->UserData(); +} + +void* VmaBlockMetadata_TLSF::GetAllocationUserData(VmaAllocHandle allocHandle) const +{ + Block* block = (Block*)allocHandle; + VMA_ASSERT(!block->IsFree() && "Cannot get user data for free block!"); + return block->UserData(); +} + +VmaAllocHandle VmaBlockMetadata_TLSF::GetAllocationListBegin() const +{ + if (m_AllocCount == 0) + return VK_NULL_HANDLE; + + for (Block* block = m_NullBlock->prevPhysical; block; block = block->prevPhysical) + { + if (!block->IsFree()) + return (VmaAllocHandle)block; + } + VMA_ASSERT(false && "If m_AllocCount > 0 then should find any allocation!"); + return VK_NULL_HANDLE; +} + +VmaAllocHandle VmaBlockMetadata_TLSF::GetNextAllocation(VmaAllocHandle prevAlloc) const +{ + Block* startBlock = (Block*)prevAlloc; + VMA_ASSERT(!startBlock->IsFree() && "Incorrect block!"); + + for (Block* block = startBlock->prevPhysical; block; block = block->prevPhysical) + { + if (!block->IsFree()) + return (VmaAllocHandle)block; + } + return VK_NULL_HANDLE; +} + +VkDeviceSize VmaBlockMetadata_TLSF::GetNextFreeRegionSize(VmaAllocHandle alloc) const +{ + Block* block = (Block*)alloc; + VMA_ASSERT(!block->IsFree() && "Incorrect block!"); + + if (block->prevPhysical) + return block->prevPhysical->IsFree() ? block->prevPhysical->size : 0; + return 0; +} + +void VmaBlockMetadata_TLSF::Clear() +{ + m_AllocCount = 0; + m_BlocksFreeCount = 0; + m_BlocksFreeSize = 0; + m_IsFreeBitmap = 0; + m_NullBlock->offset = 0; + m_NullBlock->size = GetSize(); + Block* block = m_NullBlock->prevPhysical; + m_NullBlock->prevPhysical = VMA_NULL; + while (block) + { + Block* prev = block->prevPhysical; + m_BlockAllocator.Free(block); + block = prev; + } + memset(m_FreeList, 0, m_ListsCount * sizeof(Block*)); + memset(m_InnerIsFreeBitmap, 0, m_MemoryClasses * sizeof(uint32_t)); + m_GranularityHandler.Clear(); +} + +void VmaBlockMetadata_TLSF::SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) +{ + Block* block = (Block*)allocHandle; + VMA_ASSERT(!block->IsFree() && "Trying to set user data for not allocated block!"); + block->UserData() = userData; +} + +void VmaBlockMetadata_TLSF::DebugLogAllAllocations() const +{ + for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical) + if (!block->IsFree()) + DebugLogAllocation(block->offset, block->size, block->UserData()); +} + +uint8_t VmaBlockMetadata_TLSF::SizeToMemoryClass(VkDeviceSize size) const +{ + if (size > SMALL_BUFFER_SIZE) + return VMA_BITSCAN_MSB(size) - MEMORY_CLASS_SHIFT; + return 0; +} + +uint16_t VmaBlockMetadata_TLSF::SizeToSecondIndex(VkDeviceSize size, uint8_t memoryClass) const +{ + if (memoryClass == 0) + { + if (IsVirtual()) + return static_cast((size - 1) / 8); + else + return static_cast((size - 1) / 64); + } + return static_cast((size >> (memoryClass + MEMORY_CLASS_SHIFT - SECOND_LEVEL_INDEX)) ^ (1U << SECOND_LEVEL_INDEX)); +} + +uint32_t VmaBlockMetadata_TLSF::GetListIndex(uint8_t memoryClass, uint16_t secondIndex) const +{ + if (memoryClass == 0) + return secondIndex; + + const uint32_t index = static_cast(memoryClass - 1) * (1 << SECOND_LEVEL_INDEX) + secondIndex; + if (IsVirtual()) + return index + (1 << SECOND_LEVEL_INDEX); + else + return index + 4; +} + +uint32_t VmaBlockMetadata_TLSF::GetListIndex(VkDeviceSize size) const +{ + uint8_t memoryClass = SizeToMemoryClass(size); + return GetListIndex(memoryClass, SizeToSecondIndex(size, memoryClass)); +} + +void VmaBlockMetadata_TLSF::RemoveFreeBlock(Block* block) +{ + VMA_ASSERT(block != m_NullBlock); + VMA_ASSERT(block->IsFree()); + + if (block->NextFree() != VMA_NULL) + block->NextFree()->PrevFree() = block->PrevFree(); + if (block->PrevFree() != VMA_NULL) + block->PrevFree()->NextFree() = block->NextFree(); + else + { + uint8_t memClass = SizeToMemoryClass(block->size); + uint16_t secondIndex = SizeToSecondIndex(block->size, memClass); + uint32_t index = GetListIndex(memClass, secondIndex); + VMA_ASSERT(m_FreeList[index] == block); + m_FreeList[index] = block->NextFree(); + if (block->NextFree() == VMA_NULL) + { + m_InnerIsFreeBitmap[memClass] &= ~(1U << secondIndex); + if (m_InnerIsFreeBitmap[memClass] == 0) + m_IsFreeBitmap &= ~(1UL << memClass); + } + } + block->MarkTaken(); + block->UserData() = VMA_NULL; + --m_BlocksFreeCount; + m_BlocksFreeSize -= block->size; +} + +void VmaBlockMetadata_TLSF::InsertFreeBlock(Block* block) +{ + VMA_ASSERT(block != m_NullBlock); + VMA_ASSERT(!block->IsFree() && "Cannot insert block twice!"); + + uint8_t memClass = SizeToMemoryClass(block->size); + uint16_t secondIndex = SizeToSecondIndex(block->size, memClass); + uint32_t index = GetListIndex(memClass, secondIndex); + VMA_ASSERT(index < m_ListsCount); + block->PrevFree() = VMA_NULL; + block->NextFree() = m_FreeList[index]; + m_FreeList[index] = block; + if (block->NextFree() != VMA_NULL) + block->NextFree()->PrevFree() = block; + else + { + m_InnerIsFreeBitmap[memClass] |= 1U << secondIndex; + m_IsFreeBitmap |= 1UL << memClass; + } + ++m_BlocksFreeCount; + m_BlocksFreeSize += block->size; +} + +void VmaBlockMetadata_TLSF::MergeBlock(Block* block, Block* prev) +{ + VMA_ASSERT(block->prevPhysical == prev && "Cannot merge seperate physical regions!"); + VMA_ASSERT(!prev->IsFree() && "Cannot merge block that belongs to free list!"); + + block->offset = prev->offset; + block->size += prev->size; + block->prevPhysical = prev->prevPhysical; + if (block->prevPhysical) + block->prevPhysical->nextPhysical = block; + m_BlockAllocator.Free(prev); +} + +VmaBlockMetadata_TLSF::Block* VmaBlockMetadata_TLSF::FindFreeBlock(VkDeviceSize size, uint32_t& listIndex) const +{ + uint8_t memoryClass = SizeToMemoryClass(size); + uint32_t innerFreeMap = m_InnerIsFreeBitmap[memoryClass] & (~0U << SizeToSecondIndex(size, memoryClass)); + if (!innerFreeMap) + { + // Check higher levels for avaiable blocks + uint32_t freeMap = m_IsFreeBitmap & (~0UL << (memoryClass + 1)); + if (!freeMap) + return VMA_NULL; // No more memory avaible + + // Find lowest free region + memoryClass = VMA_BITSCAN_LSB(freeMap); + innerFreeMap = m_InnerIsFreeBitmap[memoryClass]; + VMA_ASSERT(innerFreeMap != 0); + } + // Find lowest free subregion + listIndex = GetListIndex(memoryClass, VMA_BITSCAN_LSB(innerFreeMap)); + VMA_ASSERT(m_FreeList[listIndex]); + return m_FreeList[listIndex]; +} + +bool VmaBlockMetadata_TLSF::CheckBlock( + Block& block, + uint32_t listIndex, + VkDeviceSize allocSize, + VkDeviceSize allocAlignment, + VmaSuballocationType allocType, + VmaAllocationRequest* pAllocationRequest) +{ + VMA_ASSERT(block.IsFree() && "Block is already taken!"); + + VkDeviceSize alignedOffset = VmaAlignUp(block.offset, allocAlignment); + if (block.size < allocSize + alignedOffset - block.offset) + return false; + + // Check for granularity conflicts + if (!IsVirtual() && + m_GranularityHandler.CheckConflictAndAlignUp(alignedOffset, allocSize, block.offset, block.size, allocType)) + return false; + + // Alloc successful + pAllocationRequest->type = VmaAllocationRequestType::TLSF; + pAllocationRequest->allocHandle = (VmaAllocHandle)█ + pAllocationRequest->size = allocSize - GetDebugMargin(); + pAllocationRequest->customData = (void*)allocType; + pAllocationRequest->algorithmData = alignedOffset; + + // Place block at the start of list if it's normal block + if (listIndex != m_ListsCount && block.PrevFree()) + { + block.PrevFree()->NextFree() = block.NextFree(); + if (block.NextFree()) + block.NextFree()->PrevFree() = block.PrevFree(); + block.PrevFree() = VMA_NULL; + block.NextFree() = m_FreeList[listIndex]; + m_FreeList[listIndex] = █ + if (block.NextFree()) + block.NextFree()->PrevFree() = █ + } + + return true; +} +#endif // _VMA_BLOCK_METADATA_TLSF_FUNCTIONS +#endif // _VMA_BLOCK_METADATA_TLSF + +#ifndef _VMA_BLOCK_VECTOR +/* +Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific +Vulkan memory type. + +Synchronized internally with a mutex. +*/ +class VmaBlockVector +{ + friend struct VmaDefragmentationContext_T; + VMA_CLASS_NO_COPY(VmaBlockVector) +public: + VmaBlockVector( + VmaAllocator hAllocator, + VmaPool hParentPool, + uint32_t memoryTypeIndex, + VkDeviceSize preferredBlockSize, + size_t minBlockCount, + size_t maxBlockCount, + VkDeviceSize bufferImageGranularity, + bool explicitBlockSize, + uint32_t algorithm, + float priority, + VkDeviceSize minAllocationAlignment, + void* pMemoryAllocateNext); + ~VmaBlockVector(); + + VmaAllocator GetAllocator() const { return m_hAllocator; } + VmaPool GetParentPool() const { return m_hParentPool; } + bool IsCustomPool() const { return m_hParentPool != VMA_NULL; } + uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } + VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; } + VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; } + uint32_t GetAlgorithm() const { return m_Algorithm; } + bool HasExplicitBlockSize() const { return m_ExplicitBlockSize; } + float GetPriority() const { return m_Priority; } + const void* GetAllocationNextPtr() const { return m_pMemoryAllocateNext; } + // To be used only while the m_Mutex is locked. Used during defragmentation. + size_t GetBlockCount() const { return m_Blocks.size(); } + // To be used only while the m_Mutex is locked. Used during defragmentation. + VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; } + VMA_RW_MUTEX &GetMutex() { return m_Mutex; } + + VkResult CreateMinBlocks(); + void AddStatistics(VmaStatistics& inoutStats); + void AddDetailedStatistics(VmaDetailedStatistics& inoutStats); + bool IsEmpty(); + bool IsCorruptionDetectionEnabled() const; + + VkResult Allocate( + VkDeviceSize size, + VkDeviceSize alignment, + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + size_t allocationCount, + VmaAllocation* pAllocations); + + void Free(const VmaAllocation hAllocation); + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json); +#endif + + VkResult CheckCorruption(); + +private: + const VmaAllocator m_hAllocator; + const VmaPool m_hParentPool; + const uint32_t m_MemoryTypeIndex; + const VkDeviceSize m_PreferredBlockSize; + const size_t m_MinBlockCount; + const size_t m_MaxBlockCount; + const VkDeviceSize m_BufferImageGranularity; + const bool m_ExplicitBlockSize; + const uint32_t m_Algorithm; + const float m_Priority; + const VkDeviceSize m_MinAllocationAlignment; + + void* const m_pMemoryAllocateNext; + VMA_RW_MUTEX m_Mutex; + // Incrementally sorted by sumFreeSize, ascending. + VmaVector> m_Blocks; + uint32_t m_NextBlockId; + bool m_IncrementalSort = true; + + void SetIncrementalSort(bool val) { m_IncrementalSort = val; } + + VkDeviceSize CalcMaxBlockSize() const; + // Finds and removes given block from vector. + void Remove(VmaDeviceMemoryBlock* pBlock); + // Performs single step in sorting m_Blocks. They may not be fully sorted + // after this call. + void IncrementallySortBlocks(); + void SortByFreeSize(); + + VkResult AllocatePage( + VkDeviceSize size, + VkDeviceSize alignment, + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + VmaAllocation* pAllocation); + + VkResult AllocateFromBlock( + VmaDeviceMemoryBlock* pBlock, + VkDeviceSize size, + VkDeviceSize alignment, + VmaAllocationCreateFlags allocFlags, + void* pUserData, + VmaSuballocationType suballocType, + uint32_t strategy, + VmaAllocation* pAllocation); + + VkResult CommitAllocationRequest( + VmaAllocationRequest& allocRequest, + VmaDeviceMemoryBlock* pBlock, + VkDeviceSize alignment, + VmaAllocationCreateFlags allocFlags, + void* pUserData, + VmaSuballocationType suballocType, + VmaAllocation* pAllocation); + + VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex); + bool HasEmptyBlock(); +}; +#endif // _VMA_BLOCK_VECTOR + +#ifndef _VMA_DEFRAGMENTATION_CONTEXT +struct VmaDefragmentationContext_T +{ + VMA_CLASS_NO_COPY(VmaDefragmentationContext_T) +public: + VmaDefragmentationContext_T( + VmaAllocator hAllocator, + const VmaDefragmentationInfo& info); + ~VmaDefragmentationContext_T(); + + void GetStats(VmaDefragmentationStats& outStats) { outStats = m_GlobalStats; } + + VkResult DefragmentPassBegin(VmaDefragmentationPassMoveInfo& moveInfo); + VkResult DefragmentPassEnd(VmaDefragmentationPassMoveInfo& moveInfo); + +private: + // Max number of allocations to ignore due to size constraints before ending single pass + static const uint8_t MAX_ALLOCS_TO_IGNORE = 16; + enum class CounterStatus { Pass, Ignore, End }; + + struct FragmentedBlock + { + uint32_t data; + VmaDeviceMemoryBlock* block; + }; + struct StateBalanced + { + VkDeviceSize avgFreeSize = 0; + VkDeviceSize avgAllocSize = UINT64_MAX; + }; + struct StateExtensive + { + enum class Operation : uint8_t + { + FindFreeBlockBuffer, FindFreeBlockTexture, FindFreeBlockAll, + MoveBuffers, MoveTextures, MoveAll, + Cleanup, Done + }; + + Operation operation = Operation::FindFreeBlockTexture; + size_t firstFreeBlock = SIZE_MAX; + }; + struct MoveAllocationData + { + VkDeviceSize size; + VkDeviceSize alignment; + VmaSuballocationType type; + VmaAllocationCreateFlags flags; + VmaDefragmentationMove move = {}; + }; + + const VkDeviceSize m_MaxPassBytes; + const uint32_t m_MaxPassAllocations; + + VmaStlAllocator m_MoveAllocator; + VmaVector> m_Moves; + + uint8_t m_IgnoredAllocs = 0; + uint32_t m_Algorithm; + uint32_t m_BlockVectorCount; + VmaBlockVector* m_PoolBlockVector; + VmaBlockVector** m_pBlockVectors; + size_t m_ImmovableBlockCount = 0; + VmaDefragmentationStats m_GlobalStats = { 0 }; + VmaDefragmentationStats m_PassStats = { 0 }; + void* m_AlgorithmState = VMA_NULL; + + static MoveAllocationData GetMoveData(VmaAllocHandle handle, VmaBlockMetadata* metadata); + CounterStatus CheckCounters(VkDeviceSize bytes); + bool IncrementCounters(VkDeviceSize bytes); + bool ReallocWithinBlock(VmaBlockVector& vector, VmaDeviceMemoryBlock* block); + bool AllocInOtherBlock(size_t start, size_t end, MoveAllocationData& data, VmaBlockVector& vector); + + bool ComputeDefragmentation(VmaBlockVector& vector, size_t index); + bool ComputeDefragmentation_Fast(VmaBlockVector& vector); + bool ComputeDefragmentation_Balanced(VmaBlockVector& vector, size_t index, bool update); + bool ComputeDefragmentation_Full(VmaBlockVector& vector); + bool ComputeDefragmentation_Extensive(VmaBlockVector& vector, size_t index); + + void UpdateVectorStatistics(VmaBlockVector& vector, StateBalanced& state); + bool MoveDataToFreeBlocks(VmaSuballocationType currentType, + VmaBlockVector& vector, size_t firstFreeBlock, + bool& texturePresent, bool& bufferPresent, bool& otherPresent); +}; +#endif // _VMA_DEFRAGMENTATION_CONTEXT + +#ifndef _VMA_POOL_T +struct VmaPool_T +{ + friend struct VmaPoolListItemTraits; + VMA_CLASS_NO_COPY(VmaPool_T) +public: + VmaBlockVector m_BlockVector; + VmaDedicatedAllocationList m_DedicatedAllocations; + + VmaPool_T( + VmaAllocator hAllocator, + const VmaPoolCreateInfo& createInfo, + VkDeviceSize preferredBlockSize); + ~VmaPool_T(); + + uint32_t GetId() const { return m_Id; } + void SetId(uint32_t id) { VMA_ASSERT(m_Id == 0); m_Id = id; } + + const char* GetName() const { return m_Name; } + void SetName(const char* pName); + +#if VMA_STATS_STRING_ENABLED + //void PrintDetailedMap(class VmaStringBuilder& sb); +#endif + +private: + uint32_t m_Id; + char* m_Name; + VmaPool_T* m_PrevPool = VMA_NULL; + VmaPool_T* m_NextPool = VMA_NULL; +}; + +struct VmaPoolListItemTraits +{ + typedef VmaPool_T ItemType; + + static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; } + static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; } + static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; } + static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; } +}; +#endif // _VMA_POOL_T + +#ifndef _VMA_CURRENT_BUDGET_DATA +struct VmaCurrentBudgetData +{ + VMA_ATOMIC_UINT32 m_BlockCount[VK_MAX_MEMORY_HEAPS]; + VMA_ATOMIC_UINT32 m_AllocationCount[VK_MAX_MEMORY_HEAPS]; + VMA_ATOMIC_UINT64 m_BlockBytes[VK_MAX_MEMORY_HEAPS]; + VMA_ATOMIC_UINT64 m_AllocationBytes[VK_MAX_MEMORY_HEAPS]; + +#if VMA_MEMORY_BUDGET + VMA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch; + VMA_RW_MUTEX m_BudgetMutex; + uint64_t m_VulkanUsage[VK_MAX_MEMORY_HEAPS]; + uint64_t m_VulkanBudget[VK_MAX_MEMORY_HEAPS]; + uint64_t m_BlockBytesAtBudgetFetch[VK_MAX_MEMORY_HEAPS]; +#endif // VMA_MEMORY_BUDGET + + VmaCurrentBudgetData(); + + void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize); + void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize); +}; + +#ifndef _VMA_CURRENT_BUDGET_DATA_FUNCTIONS +VmaCurrentBudgetData::VmaCurrentBudgetData() +{ + for (uint32_t heapIndex = 0; heapIndex < VK_MAX_MEMORY_HEAPS; ++heapIndex) + { + m_BlockCount[heapIndex] = 0; + m_AllocationCount[heapIndex] = 0; + m_BlockBytes[heapIndex] = 0; + m_AllocationBytes[heapIndex] = 0; +#if VMA_MEMORY_BUDGET + m_VulkanUsage[heapIndex] = 0; + m_VulkanBudget[heapIndex] = 0; + m_BlockBytesAtBudgetFetch[heapIndex] = 0; +#endif + } + +#if VMA_MEMORY_BUDGET + m_OperationsSinceBudgetFetch = 0; +#endif +} + +void VmaCurrentBudgetData::AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize) +{ + m_AllocationBytes[heapIndex] += allocationSize; + ++m_AllocationCount[heapIndex]; +#if VMA_MEMORY_BUDGET + ++m_OperationsSinceBudgetFetch; +#endif +} + +void VmaCurrentBudgetData::RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize) +{ + VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); + m_AllocationBytes[heapIndex] -= allocationSize; + VMA_ASSERT(m_AllocationCount[heapIndex] > 0); + --m_AllocationCount[heapIndex]; +#if VMA_MEMORY_BUDGET + ++m_OperationsSinceBudgetFetch; +#endif +} +#endif // _VMA_CURRENT_BUDGET_DATA_FUNCTIONS +#endif // _VMA_CURRENT_BUDGET_DATA + +#ifndef _VMA_ALLOCATION_OBJECT_ALLOCATOR +/* +Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAllocation_T objects. +*/ +class VmaAllocationObjectAllocator +{ + VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator) +public: + VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) + : m_Allocator(pAllocationCallbacks, 1024) {} + + template VmaAllocation Allocate(Types&&... args); + void Free(VmaAllocation hAlloc); + +private: + VMA_MUTEX m_Mutex; + VmaPoolAllocator m_Allocator; +}; + +template +VmaAllocation VmaAllocationObjectAllocator::Allocate(Types&&... args) +{ + VmaMutexLock mutexLock(m_Mutex); + return m_Allocator.Alloc(std::forward(args)...); +} + +void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc) +{ + VmaMutexLock mutexLock(m_Mutex); + m_Allocator.Free(hAlloc); +} +#endif // _VMA_ALLOCATION_OBJECT_ALLOCATOR + +#ifndef _VMA_VIRTUAL_BLOCK_T +struct VmaVirtualBlock_T +{ + VMA_CLASS_NO_COPY(VmaVirtualBlock_T) +public: + const bool m_AllocationCallbacksSpecified; + const VkAllocationCallbacks m_AllocationCallbacks; + + VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo); + ~VmaVirtualBlock_T(); + + VkResult Init() { return VK_SUCCESS; } + bool IsEmpty() const { return m_Metadata->IsEmpty(); } + void Free(VmaVirtualAllocation allocation) { m_Metadata->Free((VmaAllocHandle)allocation); } + void SetAllocationUserData(VmaVirtualAllocation allocation, void* userData) { m_Metadata->SetAllocationUserData((VmaAllocHandle)allocation, userData); } + void Clear() { m_Metadata->Clear(); } + + const VkAllocationCallbacks* GetAllocationCallbacks() const; + void GetAllocationInfo(VmaVirtualAllocation allocation, VmaVirtualAllocationInfo& outInfo); + VkResult Allocate(const VmaVirtualAllocationCreateInfo& createInfo, VmaVirtualAllocation& outAllocation, + VkDeviceSize* outOffset); + void GetStatistics(VmaStatistics& outStats) const; + void CalculateDetailedStatistics(VmaDetailedStatistics& outStats) const; +#if VMA_STATS_STRING_ENABLED + void BuildStatsString(bool detailedMap, VmaStringBuilder& sb) const; +#endif + +private: + VmaBlockMetadata* m_Metadata; +}; + +#ifndef _VMA_VIRTUAL_BLOCK_T_FUNCTIONS +VmaVirtualBlock_T::VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo) + : m_AllocationCallbacksSpecified(createInfo.pAllocationCallbacks != VMA_NULL), + m_AllocationCallbacks(createInfo.pAllocationCallbacks != VMA_NULL ? *createInfo.pAllocationCallbacks : VmaEmptyAllocationCallbacks) +{ + const uint32_t algorithm = createInfo.flags & VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK; + switch (algorithm) + { + default: + VMA_ASSERT(0); + case 0: + m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_TLSF)(VK_NULL_HANDLE, 1, true); + break; + case VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT: + m_Metadata = vma_new(GetAllocationCallbacks(), VmaBlockMetadata_Linear)(VK_NULL_HANDLE, 1, true); + break; + } + + m_Metadata->Init(createInfo.size); +} + +VmaVirtualBlock_T::~VmaVirtualBlock_T() +{ + // Define macro VMA_DEBUG_LOG to receive the list of the unfreed allocations + if (!m_Metadata->IsEmpty()) + m_Metadata->DebugLogAllAllocations(); + // This is the most important assert in the entire library. + // Hitting it means you have some memory leak - unreleased virtual allocations. + VMA_ASSERT(m_Metadata->IsEmpty() && "Some virtual allocations were not freed before destruction of this virtual block!"); + + vma_delete(GetAllocationCallbacks(), m_Metadata); +} + +const VkAllocationCallbacks* VmaVirtualBlock_T::GetAllocationCallbacks() const +{ + return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : VMA_NULL; +} + +void VmaVirtualBlock_T::GetAllocationInfo(VmaVirtualAllocation allocation, VmaVirtualAllocationInfo& outInfo) +{ + m_Metadata->GetAllocationInfo((VmaAllocHandle)allocation, outInfo); +} + +VkResult VmaVirtualBlock_T::Allocate(const VmaVirtualAllocationCreateInfo& createInfo, VmaVirtualAllocation& outAllocation, + VkDeviceSize* outOffset) +{ + VmaAllocationRequest request = {}; + if (m_Metadata->CreateAllocationRequest( + createInfo.size, // allocSize + VMA_MAX(createInfo.alignment, (VkDeviceSize)1), // allocAlignment + (createInfo.flags & VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0, // upperAddress + VMA_SUBALLOCATION_TYPE_UNKNOWN, // allocType - unimportant + createInfo.flags & VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK, // strategy + &request)) + { + m_Metadata->Alloc(request, + VMA_SUBALLOCATION_TYPE_UNKNOWN, // type - unimportant + createInfo.pUserData); + outAllocation = (VmaVirtualAllocation)request.allocHandle; + if(outOffset) + *outOffset = m_Metadata->GetAllocationOffset(request.allocHandle); + return VK_SUCCESS; + } + outAllocation = (VmaVirtualAllocation)VK_NULL_HANDLE; + if (outOffset) + *outOffset = UINT64_MAX; + return VK_ERROR_OUT_OF_DEVICE_MEMORY; +} + +void VmaVirtualBlock_T::GetStatistics(VmaStatistics& outStats) const +{ + VmaClearStatistics(outStats); + m_Metadata->AddStatistics(outStats); +} + +void VmaVirtualBlock_T::CalculateDetailedStatistics(VmaDetailedStatistics& outStats) const +{ + VmaClearDetailedStatistics(outStats); + m_Metadata->AddDetailedStatistics(outStats); +} + +#if VMA_STATS_STRING_ENABLED +void VmaVirtualBlock_T::BuildStatsString(bool detailedMap, VmaStringBuilder& sb) const +{ + VmaJsonWriter json(GetAllocationCallbacks(), sb); + json.BeginObject(); + + VmaDetailedStatistics stats; + CalculateDetailedStatistics(stats); + + json.WriteString("Stats"); + VmaPrintDetailedStatistics(json, stats); + + if (detailedMap) + { + json.WriteString("Details"); + json.BeginObject(); + m_Metadata->PrintDetailedMap(json); + json.EndObject(); + } + + json.EndObject(); +} +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_VIRTUAL_BLOCK_T_FUNCTIONS +#endif // _VMA_VIRTUAL_BLOCK_T + + +// Main allocator object. +struct VmaAllocator_T +{ + VMA_CLASS_NO_COPY(VmaAllocator_T) +public: + bool m_UseMutex; + uint32_t m_VulkanApiVersion; + bool m_UseKhrDedicatedAllocation; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0). + bool m_UseKhrBindMemory2; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0). + bool m_UseExtMemoryBudget; + bool m_UseAmdDeviceCoherentMemory; + bool m_UseKhrBufferDeviceAddress; + bool m_UseExtMemoryPriority; + VkDevice m_hDevice; + VkInstance m_hInstance; + bool m_AllocationCallbacksSpecified; + VkAllocationCallbacks m_AllocationCallbacks; + VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks; + VmaAllocationObjectAllocator m_AllocationObjectAllocator; + + // Each bit (1 << i) is set if HeapSizeLimit is enabled for that heap, so cannot allocate more than the heap size. + uint32_t m_HeapSizeLimitMask; + + VkPhysicalDeviceProperties m_PhysicalDeviceProperties; + VkPhysicalDeviceMemoryProperties m_MemProps; + + // Default pools. + VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES]; + VmaDedicatedAllocationList m_DedicatedAllocations[VK_MAX_MEMORY_TYPES]; + + VmaCurrentBudgetData m_Budget; + VMA_ATOMIC_UINT32 m_DeviceMemoryCount; // Total number of VkDeviceMemory objects. + + VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo); + VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo); + ~VmaAllocator_T(); + + const VkAllocationCallbacks* GetAllocationCallbacks() const + { + return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : VMA_NULL; + } + const VmaVulkanFunctions& GetVulkanFunctions() const + { + return m_VulkanFunctions; + } + + VkPhysicalDevice GetPhysicalDevice() const { return m_PhysicalDevice; } + + VkDeviceSize GetBufferImageGranularity() const + { + return VMA_MAX( + static_cast(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY), + m_PhysicalDeviceProperties.limits.bufferImageGranularity); + } + + uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; } + uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; } + + uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const + { + VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount); + return m_MemProps.memoryTypes[memTypeIndex].heapIndex; + } + // True when specific memory type is HOST_VISIBLE but not HOST_COHERENT. + bool IsMemoryTypeNonCoherent(uint32_t memTypeIndex) const + { + return (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + } + // Minimum alignment for all allocations in specific memory type. + VkDeviceSize GetMemoryTypeMinAlignment(uint32_t memTypeIndex) const + { + return IsMemoryTypeNonCoherent(memTypeIndex) ? + VMA_MAX((VkDeviceSize)VMA_MIN_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) : + (VkDeviceSize)VMA_MIN_ALIGNMENT; + } + + bool IsIntegratedGpu() const + { + return m_PhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; + } + + uint32_t GetGlobalMemoryTypeBits() const { return m_GlobalMemoryTypeBits; } + + void GetBufferMemoryRequirements( + VkBuffer hBuffer, + VkMemoryRequirements& memReq, + bool& requiresDedicatedAllocation, + bool& prefersDedicatedAllocation) const; + void GetImageMemoryRequirements( + VkImage hImage, + VkMemoryRequirements& memReq, + bool& requiresDedicatedAllocation, + bool& prefersDedicatedAllocation) const; + VkResult FindMemoryTypeIndex( + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkFlags bufImgUsage, // VkBufferCreateInfo::usage or VkImageCreateInfo::usage. UINT32_MAX if unknown. + uint32_t* pMemoryTypeIndex) const; + + // Main allocation function. + VkResult AllocateMemory( + const VkMemoryRequirements& vkMemReq, + bool requiresDedicatedAllocation, + bool prefersDedicatedAllocation, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, // UINT32_MAX if unknown. + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + size_t allocationCount, + VmaAllocation* pAllocations); + + // Main deallocation function. + void FreeMemory( + size_t allocationCount, + const VmaAllocation* pAllocations); + + void CalculateStatistics(VmaTotalStatistics* pStats); + + void GetHeapBudgets( + VmaBudget* outBudgets, uint32_t firstHeap, uint32_t heapCount); + +#if VMA_STATS_STRING_ENABLED + void PrintDetailedMap(class VmaJsonWriter& json); +#endif + + void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo); + + VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool); + void DestroyPool(VmaPool pool); + void GetPoolStatistics(VmaPool pool, VmaStatistics* pPoolStats); + void CalculatePoolStatistics(VmaPool pool, VmaDetailedStatistics* pPoolStats); + + void SetCurrentFrameIndex(uint32_t frameIndex); + uint32_t GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); } + + VkResult CheckPoolCorruption(VmaPool hPool); + VkResult CheckCorruption(uint32_t memoryTypeBits); + + // Call to Vulkan function vkAllocateMemory with accompanying bookkeeping. + VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory); + // Call to Vulkan function vkFreeMemory with accompanying bookkeeping. + void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory); + // Call to Vulkan function vkBindBufferMemory or vkBindBufferMemory2KHR. + VkResult BindVulkanBuffer( + VkDeviceMemory memory, + VkDeviceSize memoryOffset, + VkBuffer buffer, + const void* pNext); + // Call to Vulkan function vkBindImageMemory or vkBindImageMemory2KHR. + VkResult BindVulkanImage( + VkDeviceMemory memory, + VkDeviceSize memoryOffset, + VkImage image, + const void* pNext); + + VkResult Map(VmaAllocation hAllocation, void** ppData); + void Unmap(VmaAllocation hAllocation); + + VkResult BindBufferMemory( + VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkBuffer hBuffer, + const void* pNext); + VkResult BindImageMemory( + VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkImage hImage, + const void* pNext); + + VkResult FlushOrInvalidateAllocation( + VmaAllocation hAllocation, + VkDeviceSize offset, VkDeviceSize size, + VMA_CACHE_OPERATION op); + VkResult FlushOrInvalidateAllocations( + uint32_t allocationCount, + const VmaAllocation* allocations, + const VkDeviceSize* offsets, const VkDeviceSize* sizes, + VMA_CACHE_OPERATION op); + + void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern); + + /* + Returns bit mask of memory types that can support defragmentation on GPU as + they support creation of required buffer for copy operations. + */ + uint32_t GetGpuDefragmentationMemoryTypeBits(); + +#if VMA_EXTERNAL_MEMORY + VkExternalMemoryHandleTypeFlagsKHR GetExternalMemoryHandleTypeFlags(uint32_t memTypeIndex) const + { + return m_TypeExternalMemoryHandleTypes[memTypeIndex]; + } +#endif // #if VMA_EXTERNAL_MEMORY + +private: + VkDeviceSize m_PreferredLargeHeapBlockSize; + + VkPhysicalDevice m_PhysicalDevice; + VMA_ATOMIC_UINT32 m_CurrentFrameIndex; + VMA_ATOMIC_UINT32 m_GpuDefragmentationMemoryTypeBits; // UINT32_MAX means uninitialized. +#if VMA_EXTERNAL_MEMORY + VkExternalMemoryHandleTypeFlagsKHR m_TypeExternalMemoryHandleTypes[VK_MAX_MEMORY_TYPES]; +#endif // #if VMA_EXTERNAL_MEMORY + + VMA_RW_MUTEX m_PoolsMutex; + typedef VmaIntrusiveLinkedList PoolList; + // Protected by m_PoolsMutex. + PoolList m_Pools; + uint32_t m_NextPoolId; + + VmaVulkanFunctions m_VulkanFunctions; + + // Global bit mask AND-ed with any memoryTypeBits to disallow certain memory types. + uint32_t m_GlobalMemoryTypeBits; + + void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions); + +#if VMA_STATIC_VULKAN_FUNCTIONS == 1 + void ImportVulkanFunctions_Static(); +#endif + + void ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions); + +#if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1 + void ImportVulkanFunctions_Dynamic(); +#endif + + void ValidateVulkanFunctions(); + + VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex); + + VkResult AllocateMemoryOfType( + VmaPool pool, + VkDeviceSize size, + VkDeviceSize alignment, + bool dedicatedPreferred, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + const VmaAllocationCreateInfo& createInfo, + uint32_t memTypeIndex, + VmaSuballocationType suballocType, + VmaDedicatedAllocationList& dedicatedAllocations, + VmaBlockVector& blockVector, + size_t allocationCount, + VmaAllocation* pAllocations); + + // Helper function only to be used inside AllocateDedicatedMemory. + VkResult AllocateDedicatedMemoryPage( + VmaPool pool, + VkDeviceSize size, + VmaSuballocationType suballocType, + uint32_t memTypeIndex, + const VkMemoryAllocateInfo& allocInfo, + bool map, + bool isUserDataString, + bool isMappingAllowed, + void* pUserData, + VmaAllocation* pAllocation); + + // Allocates and registers new VkDeviceMemory specifically for dedicated allocations. + VkResult AllocateDedicatedMemory( + VmaPool pool, + VkDeviceSize size, + VmaSuballocationType suballocType, + VmaDedicatedAllocationList& dedicatedAllocations, + uint32_t memTypeIndex, + bool map, + bool isUserDataString, + bool isMappingAllowed, + bool canAliasMemory, + void* pUserData, + float priority, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + size_t allocationCount, + VmaAllocation* pAllocations, + const void* pNextChain = nullptr); + + void FreeDedicatedMemory(const VmaAllocation allocation); + + VkResult CalcMemTypeParams( + VmaAllocationCreateInfo& outCreateInfo, + uint32_t memTypeIndex, + VkDeviceSize size, + size_t allocationCount); + VkResult CalcAllocationParams( + VmaAllocationCreateInfo& outCreateInfo, + bool dedicatedRequired, + bool dedicatedPreferred); + + /* + Calculates and returns bit mask of memory types that can support defragmentation + on GPU as they support creation of required buffer for copy operations. + */ + uint32_t CalculateGpuDefragmentationMemoryTypeBits() const; + uint32_t CalculateGlobalMemoryTypeBits() const; + + bool GetFlushOrInvalidateRange( + VmaAllocation allocation, + VkDeviceSize offset, VkDeviceSize size, + VkMappedMemoryRange& outRange) const; + +#if VMA_MEMORY_BUDGET + void UpdateVulkanBudget(); +#endif // #if VMA_MEMORY_BUDGET +}; + + +#ifndef _VMA_MEMORY_FUNCTIONS +static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment) +{ + return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment); +} + +static void VmaFree(VmaAllocator hAllocator, void* ptr) +{ + VmaFree(&hAllocator->m_AllocationCallbacks, ptr); +} + +template +static T* VmaAllocate(VmaAllocator hAllocator) +{ + return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T)); +} + +template +static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count) +{ + return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T)); +} + +template +static void vma_delete(VmaAllocator hAllocator, T* ptr) +{ + if(ptr != VMA_NULL) + { + ptr->~T(); + VmaFree(hAllocator, ptr); + } +} + +template +static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count) +{ + if(ptr != VMA_NULL) + { + for(size_t i = count; i--; ) + ptr[i].~T(); + VmaFree(hAllocator, ptr); + } +} +#endif // _VMA_MEMORY_FUNCTIONS + +#ifndef _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS +VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) + : m_pMetadata(VMA_NULL), + m_MemoryTypeIndex(UINT32_MAX), + m_Id(0), + m_hMemory(VK_NULL_HANDLE), + m_MapCount(0), + m_pMappedData(VMA_NULL) {} + +VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock() +{ + VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped."); + VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); +} + +void VmaDeviceMemoryBlock::Init( + VmaAllocator hAllocator, + VmaPool hParentPool, + uint32_t newMemoryTypeIndex, + VkDeviceMemory newMemory, + VkDeviceSize newSize, + uint32_t id, + uint32_t algorithm, + VkDeviceSize bufferImageGranularity) +{ + VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); + + m_hParentPool = hParentPool; + m_MemoryTypeIndex = newMemoryTypeIndex; + m_Id = id; + m_hMemory = newMemory; + + switch (algorithm) + { + case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT: + m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator->GetAllocationCallbacks(), + bufferImageGranularity, false); // isVirtual + break; + default: + VMA_ASSERT(0); + // Fall-through. + case 0: + m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_TLSF)(hAllocator->GetAllocationCallbacks(), + bufferImageGranularity, false); // isVirtual + } + m_pMetadata->Init(newSize); +} + +void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator) +{ + // Define macro VMA_DEBUG_LOG to receive the list of the unfreed allocations + if (!m_pMetadata->IsEmpty()) + m_pMetadata->DebugLogAllAllocations(); + // This is the most important assert in the entire library. + // Hitting it means you have some memory leak - unreleased VmaAllocation objects. + VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!"); + + VMA_ASSERT(m_hMemory != VK_NULL_HANDLE); + allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory); + m_hMemory = VK_NULL_HANDLE; + + vma_delete(allocator, m_pMetadata); + m_pMetadata = VMA_NULL; +} + +void VmaDeviceMemoryBlock::PostFree(VmaAllocator hAllocator) +{ + if(m_MappingHysteresis.PostFree()) + { + VMA_ASSERT(m_MappingHysteresis.GetExtraMapping() == 0); + if (m_MapCount == 0) + { + m_pMappedData = VMA_NULL; + (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); + } + } +} + +bool VmaDeviceMemoryBlock::Validate() const +{ + VMA_VALIDATE((m_hMemory != VK_NULL_HANDLE) && + (m_pMetadata->GetSize() != 0)); + + return m_pMetadata->Validate(); +} + +VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator) +{ + void* pData = nullptr; + VkResult res = Map(hAllocator, 1, &pData); + if (res != VK_SUCCESS) + { + return res; + } + + res = m_pMetadata->CheckCorruption(pData); + + Unmap(hAllocator, 1); + + return res; +} + +VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData) +{ + if (count == 0) + { + return VK_SUCCESS; + } + + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + const uint32_t oldTotalMapCount = m_MapCount + m_MappingHysteresis.GetExtraMapping(); + m_MappingHysteresis.PostMap(); + if (oldTotalMapCount != 0) + { + m_MapCount += count; + VMA_ASSERT(m_pMappedData != VMA_NULL); + if (ppData != VMA_NULL) + { + *ppData = m_pMappedData; + } + return VK_SUCCESS; + } + else + { + VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)( + hAllocator->m_hDevice, + m_hMemory, + 0, // offset + VK_WHOLE_SIZE, + 0, // flags + &m_pMappedData); + if (result == VK_SUCCESS) + { + if (ppData != VMA_NULL) + { + *ppData = m_pMappedData; + } + m_MapCount = count; + } + return result; + } +} + +void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count) +{ + if (count == 0) + { + return; + } + + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + if (m_MapCount >= count) + { + m_MapCount -= count; + const uint32_t totalMapCount = m_MapCount + m_MappingHysteresis.GetExtraMapping(); + if (totalMapCount == 0) + { + m_pMappedData = VMA_NULL; + (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); + } + m_MappingHysteresis.PostUnmap(); + } + else + { + VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped."); + } +} + +VkResult VmaDeviceMemoryBlock::WriteMagicValueAfterAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize) +{ + VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION); + + void* pData; + VkResult res = Map(hAllocator, 1, &pData); + if (res != VK_SUCCESS) + { + return res; + } + + VmaWriteMagicValue(pData, allocOffset + allocSize); + + Unmap(hAllocator, 1); + return VK_SUCCESS; +} + +VkResult VmaDeviceMemoryBlock::ValidateMagicValueAfterAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize) +{ + VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION); + + void* pData; + VkResult res = Map(hAllocator, 1, &pData); + if (res != VK_SUCCESS) + { + return res; + } + + if (!VmaValidateMagicValue(pData, allocOffset + allocSize)) + { + VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER FREED ALLOCATION!"); + } + + Unmap(hAllocator, 1); + return VK_SUCCESS; +} + +VkResult VmaDeviceMemoryBlock::BindBufferMemory( + const VmaAllocator hAllocator, + const VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkBuffer hBuffer, + const void* pNext) +{ + VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK && + hAllocation->GetBlock() == this); + VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() && + "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?"); + const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset; + // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads. + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + return hAllocator->BindVulkanBuffer(m_hMemory, memoryOffset, hBuffer, pNext); +} + +VkResult VmaDeviceMemoryBlock::BindImageMemory( + const VmaAllocator hAllocator, + const VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkImage hImage, + const void* pNext) +{ + VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK && + hAllocation->GetBlock() == this); + VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() && + "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?"); + const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset; + // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads. + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext); +} +#endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS + +#ifndef _VMA_ALLOCATION_T_FUNCTIONS +VmaAllocation_T::VmaAllocation_T(bool mappingAllowed) + : m_Alignment{ 1 }, + m_Size{ 0 }, + m_pUserData{ VMA_NULL }, + m_pName{ VMA_NULL }, + m_MemoryTypeIndex{ 0 }, + m_Type{ (uint8_t)ALLOCATION_TYPE_NONE }, + m_SuballocationType{ (uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN }, + m_MapCount{ 0 }, + m_Flags{ 0 } +{ + if(mappingAllowed) + m_Flags |= (uint8_t)FLAG_MAPPING_ALLOWED; + +#if VMA_STATS_STRING_ENABLED + m_BufferImageUsage = 0; +#endif +} + +VmaAllocation_T::~VmaAllocation_T() +{ + VMA_ASSERT(m_MapCount == 0 && "Allocation was not unmapped before destruction."); + + // Check if owned string was freed. + VMA_ASSERT(m_pName == VMA_NULL); +} + +void VmaAllocation_T::InitBlockAllocation( + VmaDeviceMemoryBlock* block, + VmaAllocHandle allocHandle, + VkDeviceSize alignment, + VkDeviceSize size, + uint32_t memoryTypeIndex, + VmaSuballocationType suballocationType, + bool mapped) +{ + VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); + VMA_ASSERT(block != VMA_NULL); + m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK; + m_Alignment = alignment; + m_Size = size; + m_MemoryTypeIndex = memoryTypeIndex; + if(mapped) + { + VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); + m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; + } + m_SuballocationType = (uint8_t)suballocationType; + m_BlockAllocation.m_Block = block; + m_BlockAllocation.m_AllocHandle = allocHandle; +} + +void VmaAllocation_T::InitDedicatedAllocation( + VmaPool hParentPool, + uint32_t memoryTypeIndex, + VkDeviceMemory hMemory, + VmaSuballocationType suballocationType, + void* pMappedData, + VkDeviceSize size) +{ + VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); + VMA_ASSERT(hMemory != VK_NULL_HANDLE); + m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED; + m_Alignment = 0; + m_Size = size; + m_MemoryTypeIndex = memoryTypeIndex; + m_SuballocationType = (uint8_t)suballocationType; + if(pMappedData != VMA_NULL) + { + VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); + m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; + } + m_DedicatedAllocation.m_hParentPool = hParentPool; + m_DedicatedAllocation.m_hMemory = hMemory; + m_DedicatedAllocation.m_pMappedData = pMappedData; + m_DedicatedAllocation.m_Prev = VMA_NULL; + m_DedicatedAllocation.m_Next = VMA_NULL; +} + +void VmaAllocation_T::SetName(VmaAllocator hAllocator, const char* pName) +{ + VMA_ASSERT(pName == VMA_NULL || pName != m_pName); + + FreeName(hAllocator); + + if (pName != VMA_NULL) + m_pName = VmaCreateStringCopy(hAllocator->GetAllocationCallbacks(), pName); +} + +uint8_t VmaAllocation_T::SwapBlockAllocation(VmaAllocator hAllocator, VmaAllocation allocation) +{ + VMA_ASSERT(allocation != VMA_NULL); + VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); + VMA_ASSERT(allocation->m_Type == ALLOCATION_TYPE_BLOCK); + + if (m_MapCount != 0) + m_BlockAllocation.m_Block->Unmap(hAllocator, m_MapCount); + + m_BlockAllocation.m_Block->m_pMetadata->SetAllocationUserData(m_BlockAllocation.m_AllocHandle, allocation); + VMA_SWAP(m_BlockAllocation, allocation->m_BlockAllocation); + m_BlockAllocation.m_Block->m_pMetadata->SetAllocationUserData(m_BlockAllocation.m_AllocHandle, this); + +#if VMA_STATS_STRING_ENABLED + VMA_SWAP(m_BufferImageUsage, allocation->m_BufferImageUsage); +#endif + return m_MapCount; +} + +VmaAllocHandle VmaAllocation_T::GetAllocHandle() const +{ + switch (m_Type) + { + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_AllocHandle; + case ALLOCATION_TYPE_DEDICATED: + return VK_NULL_HANDLE; + default: + VMA_ASSERT(0); + return VK_NULL_HANDLE; + } +} + +VkDeviceSize VmaAllocation_T::GetOffset() const +{ + switch (m_Type) + { + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_Block->m_pMetadata->GetAllocationOffset(m_BlockAllocation.m_AllocHandle); + case ALLOCATION_TYPE_DEDICATED: + return 0; + default: + VMA_ASSERT(0); + return 0; + } +} + +VmaPool VmaAllocation_T::GetParentPool() const +{ + switch (m_Type) + { + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_Block->GetParentPool(); + case ALLOCATION_TYPE_DEDICATED: + return m_DedicatedAllocation.m_hParentPool; + default: + VMA_ASSERT(0); + return VK_NULL_HANDLE; + } +} + +VkDeviceMemory VmaAllocation_T::GetMemory() const +{ + switch (m_Type) + { + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_Block->GetDeviceMemory(); + case ALLOCATION_TYPE_DEDICATED: + return m_DedicatedAllocation.m_hMemory; + default: + VMA_ASSERT(0); + return VK_NULL_HANDLE; + } +} + +void* VmaAllocation_T::GetMappedData() const +{ + switch (m_Type) + { + case ALLOCATION_TYPE_BLOCK: + if (m_MapCount != 0 || IsPersistentMap()) + { + void* pBlockData = m_BlockAllocation.m_Block->GetMappedData(); + VMA_ASSERT(pBlockData != VMA_NULL); + return (char*)pBlockData + GetOffset(); + } + else + { + return VMA_NULL; + } + break; + case ALLOCATION_TYPE_DEDICATED: + VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0 || IsPersistentMap())); + return m_DedicatedAllocation.m_pMappedData; + default: + VMA_ASSERT(0); + return VMA_NULL; + } +} + +void VmaAllocation_T::BlockAllocMap() +{ + VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK); + VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); + + if (m_MapCount < 0xFF) + { + ++m_MapCount; + } + else + { + VMA_ASSERT(0 && "Allocation mapped too many times simultaneously."); + } +} + +void VmaAllocation_T::BlockAllocUnmap() +{ + VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK); + + if (m_MapCount > 0) + { + --m_MapCount; + } + else + { + VMA_ASSERT(0 && "Unmapping allocation not previously mapped."); + } +} + +VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData) +{ + VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); + VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); + + if (m_MapCount != 0 || IsPersistentMap()) + { + if (m_MapCount < 0xFF) + { + VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL); + *ppData = m_DedicatedAllocation.m_pMappedData; + ++m_MapCount; + return VK_SUCCESS; + } + else + { + VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously."); + return VK_ERROR_MEMORY_MAP_FAILED; + } + } + else + { + VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)( + hAllocator->m_hDevice, + m_DedicatedAllocation.m_hMemory, + 0, // offset + VK_WHOLE_SIZE, + 0, // flags + ppData); + if (result == VK_SUCCESS) + { + m_DedicatedAllocation.m_pMappedData = *ppData; + m_MapCount = 1; + } + return result; + } +} + +void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator) +{ + VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); + + if (m_MapCount > 0) + { + --m_MapCount; + if (m_MapCount == 0 && !IsPersistentMap()) + { + m_DedicatedAllocation.m_pMappedData = VMA_NULL; + (*hAllocator->GetVulkanFunctions().vkUnmapMemory)( + hAllocator->m_hDevice, + m_DedicatedAllocation.m_hMemory); + } + } + else + { + VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped."); + } +} + +#if VMA_STATS_STRING_ENABLED +void VmaAllocation_T::InitBufferImageUsage(uint32_t bufferImageUsage) +{ + VMA_ASSERT(m_BufferImageUsage == 0); + m_BufferImageUsage = bufferImageUsage; +} + +void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const +{ + json.WriteString("Type"); + json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[m_SuballocationType]); + + json.WriteString("Size"); + json.WriteNumber(m_Size); + json.WriteString("Usage"); + json.WriteNumber(m_BufferImageUsage); + + if (m_pUserData != VMA_NULL) + { + json.WriteString("CustomData"); + json.BeginString(); + json.ContinueString_Pointer(m_pUserData); + json.EndString(); + } + if (m_pName != VMA_NULL) + { + json.WriteString("Name"); + json.WriteString(m_pName); + } +} +#endif // VMA_STATS_STRING_ENABLED + +void VmaAllocation_T::FreeName(VmaAllocator hAllocator) +{ + if(m_pName) + { + VmaFreeString(hAllocator->GetAllocationCallbacks(), m_pName); + m_pName = VMA_NULL; + } +} +#endif // _VMA_ALLOCATION_T_FUNCTIONS + +#ifndef _VMA_BLOCK_VECTOR_FUNCTIONS +VmaBlockVector::VmaBlockVector( + VmaAllocator hAllocator, + VmaPool hParentPool, + uint32_t memoryTypeIndex, + VkDeviceSize preferredBlockSize, + size_t minBlockCount, + size_t maxBlockCount, + VkDeviceSize bufferImageGranularity, + bool explicitBlockSize, + uint32_t algorithm, + float priority, + VkDeviceSize minAllocationAlignment, + void* pMemoryAllocateNext) + : m_hAllocator(hAllocator), + m_hParentPool(hParentPool), + m_MemoryTypeIndex(memoryTypeIndex), + m_PreferredBlockSize(preferredBlockSize), + m_MinBlockCount(minBlockCount), + m_MaxBlockCount(maxBlockCount), + m_BufferImageGranularity(bufferImageGranularity), + m_ExplicitBlockSize(explicitBlockSize), + m_Algorithm(algorithm), + m_Priority(priority), + m_MinAllocationAlignment(minAllocationAlignment), + m_pMemoryAllocateNext(pMemoryAllocateNext), + m_Blocks(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), + m_NextBlockId(0) {} + +VmaBlockVector::~VmaBlockVector() +{ + for (size_t i = m_Blocks.size(); i--; ) + { + m_Blocks[i]->Destroy(m_hAllocator); + vma_delete(m_hAllocator, m_Blocks[i]); + } +} + +VkResult VmaBlockVector::CreateMinBlocks() +{ + for (size_t i = 0; i < m_MinBlockCount; ++i) + { + VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL); + if (res != VK_SUCCESS) + { + return res; + } + } + return VK_SUCCESS; +} + +void VmaBlockVector::AddStatistics(VmaStatistics& inoutStats) +{ + VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); + + const size_t blockCount = m_Blocks.size(); + for (uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) + { + const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pBlock); + VMA_HEAVY_ASSERT(pBlock->Validate()); + pBlock->m_pMetadata->AddStatistics(inoutStats); + } +} + +void VmaBlockVector::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) +{ + VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); + + const size_t blockCount = m_Blocks.size(); + for (uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) + { + const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pBlock); + VMA_HEAVY_ASSERT(pBlock->Validate()); + pBlock->m_pMetadata->AddDetailedStatistics(inoutStats); + } +} + +bool VmaBlockVector::IsEmpty() +{ + VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); + return m_Blocks.empty(); +} + +bool VmaBlockVector::IsCorruptionDetectionEnabled() const +{ + const uint32_t requiredMemFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + return (VMA_DEBUG_DETECT_CORRUPTION != 0) && + (VMA_DEBUG_MARGIN > 0) && + (m_Algorithm == 0 || m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) && + (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags; +} + +VkResult VmaBlockVector::Allocate( + VkDeviceSize size, + VkDeviceSize alignment, + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + size_t allocationCount, + VmaAllocation* pAllocations) +{ + size_t allocIndex; + VkResult res = VK_SUCCESS; + + alignment = VMA_MAX(alignment, m_MinAllocationAlignment); + + if (IsCorruptionDetectionEnabled()) + { + size = VmaAlignUp(size, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE)); + alignment = VmaAlignUp(alignment, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE)); + } + + { + VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex); + for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + { + res = AllocatePage( + size, + alignment, + createInfo, + suballocType, + pAllocations + allocIndex); + if (res != VK_SUCCESS) + { + break; + } + } + } + + if (res != VK_SUCCESS) + { + // Free all already created allocations. + while (allocIndex--) + Free(pAllocations[allocIndex]); + memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); + } + + return res; +} + +VkResult VmaBlockVector::AllocatePage( + VkDeviceSize size, + VkDeviceSize alignment, + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + VmaAllocation* pAllocation) +{ + const bool isUpperAddress = (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0; + + VkDeviceSize freeMemory; + { + const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex); + VmaBudget heapBudget = {}; + m_hAllocator->GetHeapBudgets(&heapBudget, heapIndex, 1); + freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0; + } + + const bool canFallbackToDedicated = !HasExplicitBlockSize() && + (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0; + const bool canCreateNewBlock = + ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) && + (m_Blocks.size() < m_MaxBlockCount) && + (freeMemory >= size || !canFallbackToDedicated); + uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK; + + // Upper address can only be used with linear allocator and within single memory block. + if (isUpperAddress && + (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT || m_MaxBlockCount > 1)) + { + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + // Early reject: requested allocation size is larger that maximum block size for this block vector. + if (size + VMA_DEBUG_MARGIN > m_PreferredBlockSize) + { + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + + // 1. Search existing allocations. Try to allocate. + if (m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) + { + // Use only last block. + if (!m_Blocks.empty()) + { + VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks.back(); + VMA_ASSERT(pCurrBlock); + VkResult res = AllocateFromBlock( + pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) + { + VMA_DEBUG_LOG(" Returned from last block #%u", pCurrBlock->GetId()); + IncrementallySortBlocks(); + return VK_SUCCESS; + } + } + } + else + { + if (strategy != VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT) // MIN_MEMORY or default + { + const bool isHostVisible = + (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; + if(isHostVisible) + { + const bool isMappingAllowed = (createInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0; + /* + For non-mappable allocations, check blocks that are not mapped first. + For mappable allocations, check blocks that are already mapped first. + This way, having many blocks, we will separate mappable and non-mappable allocations, + hopefully limiting the number of blocks that are mapped, which will help tools like RenderDoc. + */ + for(size_t mappingI = 0; mappingI < 2; ++mappingI) + { + // Forward order in m_Blocks - prefer blocks with smallest amount of free space. + for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) + { + VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pCurrBlock); + const bool isBlockMapped = pCurrBlock->GetMappedData() != VMA_NULL; + if((mappingI == 0) == (isMappingAllowed == isBlockMapped)) + { + VkResult res = AllocateFromBlock( + pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) + { + VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId()); + IncrementallySortBlocks(); + return VK_SUCCESS; + } + } + } + } + } + else + { + // Forward order in m_Blocks - prefer blocks with smallest amount of free space. + for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) + { + VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pCurrBlock); + VkResult res = AllocateFromBlock( + pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) + { + VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId()); + IncrementallySortBlocks(); + return VK_SUCCESS; + } + } + } + } + else // VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT + { + // Backward order in m_Blocks - prefer blocks with largest amount of free space. + for (size_t blockIndex = m_Blocks.size(); blockIndex--; ) + { + VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pCurrBlock); + VkResult res = AllocateFromBlock(pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) + { + VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId()); + IncrementallySortBlocks(); + return VK_SUCCESS; + } + } + } + } + + // 2. Try to create new block. + if (canCreateNewBlock) + { + // Calculate optimal size for new block. + VkDeviceSize newBlockSize = m_PreferredBlockSize; + uint32_t newBlockSizeShift = 0; + const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3; + + if (!m_ExplicitBlockSize) + { + // Allocate 1/8, 1/4, 1/2 as first blocks. + const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize(); + for (uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i) + { + const VkDeviceSize smallerNewBlockSize = newBlockSize / 2; + if (smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2) + { + newBlockSize = smallerNewBlockSize; + ++newBlockSizeShift; + } + else + { + break; + } + } + } + + size_t newBlockIndex = 0; + VkResult res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ? + CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY; + // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize. + if (!m_ExplicitBlockSize) + { + while (res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX) + { + const VkDeviceSize smallerNewBlockSize = newBlockSize / 2; + if (smallerNewBlockSize >= size) + { + newBlockSize = smallerNewBlockSize; + ++newBlockSizeShift; + res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ? + CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + else + { + break; + } + } + } + + if (res == VK_SUCCESS) + { + VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex]; + VMA_ASSERT(pBlock->m_pMetadata->GetSize() >= size); + + res = AllocateFromBlock( + pBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); + if (res == VK_SUCCESS) + { + VMA_DEBUG_LOG(" Created new block #%u Size=%llu", pBlock->GetId(), newBlockSize); + IncrementallySortBlocks(); + return VK_SUCCESS; + } + else + { + // Allocation from new block failed, possibly due to VMA_DEBUG_MARGIN or alignment. + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + } + } + + return VK_ERROR_OUT_OF_DEVICE_MEMORY; +} + +void VmaBlockVector::Free(const VmaAllocation hAllocation) +{ + VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL; + + bool budgetExceeded = false; + { + const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex); + VmaBudget heapBudget = {}; + m_hAllocator->GetHeapBudgets(&heapBudget, heapIndex, 1); + budgetExceeded = heapBudget.usage >= heapBudget.budget; + } + + // Scope for lock. + { + VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex); + + VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock(); + + if (IsCorruptionDetectionEnabled()) + { + VkResult res = pBlock->ValidateMagicValueAfterAllocation(m_hAllocator, hAllocation->GetOffset(), hAllocation->GetSize()); + VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to validate magic value."); + } + + if (hAllocation->IsPersistentMap()) + { + pBlock->Unmap(m_hAllocator, 1); + } + + const bool hadEmptyBlockBeforeFree = HasEmptyBlock(); + pBlock->m_pMetadata->Free(hAllocation->GetAllocHandle()); + pBlock->PostFree(m_hAllocator); + VMA_HEAVY_ASSERT(pBlock->Validate()); + + VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex); + + const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount; + // pBlock became empty after this deallocation. + if (pBlock->m_pMetadata->IsEmpty()) + { + // Already had empty block. We don't want to have two, so delete this one. + if ((hadEmptyBlockBeforeFree || budgetExceeded) && canDeleteBlock) + { + pBlockToDelete = pBlock; + Remove(pBlock); + } + // else: We now have one empty block - leave it. A hysteresis to avoid allocating whole block back and forth. + } + // pBlock didn't become empty, but we have another empty block - find and free that one. + // (This is optional, heuristics.) + else if (hadEmptyBlockBeforeFree && canDeleteBlock) + { + VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back(); + if (pLastBlock->m_pMetadata->IsEmpty()) + { + pBlockToDelete = pLastBlock; + m_Blocks.pop_back(); + } + } + + IncrementallySortBlocks(); + } + + // Destruction of a free block. Deferred until this point, outside of mutex + // lock, for performance reason. + if (pBlockToDelete != VMA_NULL) + { + VMA_DEBUG_LOG(" Deleted empty block #%u", pBlockToDelete->GetId()); + pBlockToDelete->Destroy(m_hAllocator); + vma_delete(m_hAllocator, pBlockToDelete); + } + + m_hAllocator->m_Budget.RemoveAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), hAllocation->GetSize()); + m_hAllocator->m_AllocationObjectAllocator.Free(hAllocation); +} + +VkDeviceSize VmaBlockVector::CalcMaxBlockSize() const +{ + VkDeviceSize result = 0; + for (size_t i = m_Blocks.size(); i--; ) + { + result = VMA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize()); + if (result >= m_PreferredBlockSize) + { + break; + } + } + return result; +} + +void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock) +{ + for (uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) + { + if (m_Blocks[blockIndex] == pBlock) + { + VmaVectorRemove(m_Blocks, blockIndex); + return; + } + } + VMA_ASSERT(0); +} + +void VmaBlockVector::IncrementallySortBlocks() +{ + if (!m_IncrementalSort) + return; + if (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) + { + // Bubble sort only until first swap. + for (size_t i = 1; i < m_Blocks.size(); ++i) + { + if (m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize()) + { + VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]); + return; + } + } + } +} + +void VmaBlockVector::SortByFreeSize() +{ + VMA_SORT(m_Blocks.begin(), m_Blocks.end(), + [](VmaDeviceMemoryBlock* b1, VmaDeviceMemoryBlock* b2) -> bool + { + return b1->m_pMetadata->GetSumFreeSize() < b2->m_pMetadata->GetSumFreeSize(); + }); +} + +VkResult VmaBlockVector::AllocateFromBlock( + VmaDeviceMemoryBlock* pBlock, + VkDeviceSize size, + VkDeviceSize alignment, + VmaAllocationCreateFlags allocFlags, + void* pUserData, + VmaSuballocationType suballocType, + uint32_t strategy, + VmaAllocation* pAllocation) +{ + const bool isUpperAddress = (allocFlags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0; + + VmaAllocationRequest currRequest = {}; + if (pBlock->m_pMetadata->CreateAllocationRequest( + size, + alignment, + isUpperAddress, + suballocType, + strategy, + &currRequest)) + { + return CommitAllocationRequest(currRequest, pBlock, alignment, allocFlags, pUserData, suballocType, pAllocation); + } + return VK_ERROR_OUT_OF_DEVICE_MEMORY; +} + +VkResult VmaBlockVector::CommitAllocationRequest( + VmaAllocationRequest& allocRequest, + VmaDeviceMemoryBlock* pBlock, + VkDeviceSize alignment, + VmaAllocationCreateFlags allocFlags, + void* pUserData, + VmaSuballocationType suballocType, + VmaAllocation* pAllocation) +{ + const bool mapped = (allocFlags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0; + const bool isUserDataString = (allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0; + const bool isMappingAllowed = (allocFlags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0; + + pBlock->PostAlloc(); + // Allocate from pCurrBlock. + if (mapped) + { + VkResult res = pBlock->Map(m_hAllocator, 1, VMA_NULL); + if (res != VK_SUCCESS) + { + return res; + } + } + + *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(isMappingAllowed); + pBlock->m_pMetadata->Alloc(allocRequest, suballocType, *pAllocation); + (*pAllocation)->InitBlockAllocation( + pBlock, + allocRequest.allocHandle, + alignment, + allocRequest.size, // Not size, as actual allocation size may be larger than requested! + m_MemoryTypeIndex, + suballocType, + mapped); + VMA_HEAVY_ASSERT(pBlock->Validate()); + if (isUserDataString) + (*pAllocation)->SetName(m_hAllocator, (const char*)pUserData); + else + (*pAllocation)->SetUserData(m_hAllocator, pUserData); + m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), allocRequest.size); + if (VMA_DEBUG_INITIALIZE_ALLOCATIONS) + { + m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); + } + if (IsCorruptionDetectionEnabled()) + { + VkResult res = pBlock->WriteMagicValueAfterAllocation(m_hAllocator, (*pAllocation)->GetOffset(), allocRequest.size); + VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value."); + } + return VK_SUCCESS; +} + +VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex) +{ + VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocInfo.pNext = m_pMemoryAllocateNext; + allocInfo.memoryTypeIndex = m_MemoryTypeIndex; + allocInfo.allocationSize = blockSize; + +#if VMA_BUFFER_DEVICE_ADDRESS + // Every standalone block can potentially contain a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - always enable the feature. + VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR }; + if (m_hAllocator->m_UseKhrBufferDeviceAddress) + { + allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo); + } +#endif // VMA_BUFFER_DEVICE_ADDRESS + +#if VMA_MEMORY_PRIORITY + VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT }; + if (m_hAllocator->m_UseExtMemoryPriority) + { + VMA_ASSERT(m_Priority >= 0.f && m_Priority <= 1.f); + priorityInfo.priority = m_Priority; + VmaPnextChainPushFront(&allocInfo, &priorityInfo); + } +#endif // VMA_MEMORY_PRIORITY + +#if VMA_EXTERNAL_MEMORY + // Attach VkExportMemoryAllocateInfoKHR if necessary. + VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR }; + exportMemoryAllocInfo.handleTypes = m_hAllocator->GetExternalMemoryHandleTypeFlags(m_MemoryTypeIndex); + if (exportMemoryAllocInfo.handleTypes != 0) + { + VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo); + } +#endif // VMA_EXTERNAL_MEMORY + + VkDeviceMemory mem = VK_NULL_HANDLE; + VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem); + if (res < 0) + { + return res; + } + + // New VkDeviceMemory successfully created. + + // Create new Allocation for it. + VmaDeviceMemoryBlock* const pBlock = vma_new(m_hAllocator, VmaDeviceMemoryBlock)(m_hAllocator); + pBlock->Init( + m_hAllocator, + m_hParentPool, + m_MemoryTypeIndex, + mem, + allocInfo.allocationSize, + m_NextBlockId++, + m_Algorithm, + m_BufferImageGranularity); + + m_Blocks.push_back(pBlock); + if (pNewBlockIndex != VMA_NULL) + { + *pNewBlockIndex = m_Blocks.size() - 1; + } + + return VK_SUCCESS; +} + +bool VmaBlockVector::HasEmptyBlock() +{ + for (size_t index = 0, count = m_Blocks.size(); index < count; ++index) + { + VmaDeviceMemoryBlock* const pBlock = m_Blocks[index]; + if (pBlock->m_pMetadata->IsEmpty()) + { + return true; + } + } + return false; +} + +#if VMA_STATS_STRING_ENABLED +void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json) +{ + VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); + + + json.BeginObject(); + for (size_t i = 0; i < m_Blocks.size(); ++i) + { + json.BeginString(); + json.ContinueString(m_Blocks[i]->GetId()); + json.EndString(); + + json.BeginObject(); + json.WriteString("MapRefCount"); + json.WriteNumber(m_Blocks[i]->GetMapRefCount()); + + m_Blocks[i]->m_pMetadata->PrintDetailedMap(json); + json.EndObject(); + } + json.EndObject(); +} +#endif // VMA_STATS_STRING_ENABLED + +VkResult VmaBlockVector::CheckCorruption() +{ + if (!IsCorruptionDetectionEnabled()) + { + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex); + for (uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) + { + VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; + VMA_ASSERT(pBlock); + VkResult res = pBlock->CheckCorruption(m_hAllocator); + if (res != VK_SUCCESS) + { + return res; + } + } + return VK_SUCCESS; +} + +#endif // _VMA_BLOCK_VECTOR_FUNCTIONS + +#ifndef _VMA_DEFRAGMENTATION_CONTEXT_FUNCTIONS +VmaDefragmentationContext_T::VmaDefragmentationContext_T( + VmaAllocator hAllocator, + const VmaDefragmentationInfo& info) + : m_MaxPassBytes(info.maxBytesPerPass == 0 ? VK_WHOLE_SIZE : info.maxBytesPerPass), + m_MaxPassAllocations(info.maxAllocationsPerPass == 0 ? UINT32_MAX : info.maxAllocationsPerPass), + m_MoveAllocator(hAllocator->GetAllocationCallbacks()), + m_Moves(m_MoveAllocator) +{ + m_Algorithm = info.flags & VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK; + + if (info.pool != VMA_NULL) + { + m_BlockVectorCount = 1; + m_PoolBlockVector = &info.pool->m_BlockVector; + m_pBlockVectors = &m_PoolBlockVector; + m_PoolBlockVector->SetIncrementalSort(false); + m_PoolBlockVector->SortByFreeSize(); + } + else + { + m_BlockVectorCount = hAllocator->GetMemoryTypeCount(); + m_PoolBlockVector = VMA_NULL; + m_pBlockVectors = hAllocator->m_pBlockVectors; + for (uint32_t i = 0; i < m_BlockVectorCount; ++i) + { + VmaBlockVector* vector = m_pBlockVectors[i]; + if (vector != VMA_NULL) + { + vector->SetIncrementalSort(false); + vector->SortByFreeSize(); + } + } + } + + switch (m_Algorithm) + { + case 0: // Default algorithm + m_Algorithm = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT; + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: + { + m_AlgorithmState = vma_new_array(hAllocator, StateBalanced, m_BlockVectorCount); + break; + } + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + { + if (hAllocator->GetBufferImageGranularity() > 1) + { + m_AlgorithmState = vma_new_array(hAllocator, StateExtensive, m_BlockVectorCount); + } + break; + } + } +} + +VmaDefragmentationContext_T::~VmaDefragmentationContext_T() +{ + if (m_PoolBlockVector != VMA_NULL) + { + m_PoolBlockVector->SetIncrementalSort(true); + } + else + { + for (uint32_t i = 0; i < m_BlockVectorCount; ++i) + { + VmaBlockVector* vector = m_pBlockVectors[i]; + if (vector != VMA_NULL) + vector->SetIncrementalSort(true); + } + } + + if (m_AlgorithmState) + { + switch (m_Algorithm) + { + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: + vma_delete_array(m_MoveAllocator.m_pCallbacks, reinterpret_cast(m_AlgorithmState), m_BlockVectorCount); + break; + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + vma_delete_array(m_MoveAllocator.m_pCallbacks, reinterpret_cast(m_AlgorithmState), m_BlockVectorCount); + break; + default: + VMA_ASSERT(0); + } + } +} + +VkResult VmaDefragmentationContext_T::DefragmentPassBegin(VmaDefragmentationPassMoveInfo& moveInfo) +{ + if (m_PoolBlockVector != VMA_NULL) + { + VmaMutexLockWrite lock(m_PoolBlockVector->GetMutex(), m_PoolBlockVector->GetAllocator()->m_UseMutex); + + if (m_PoolBlockVector->GetBlockCount() > 1) + ComputeDefragmentation(*m_PoolBlockVector, 0); + else if (m_PoolBlockVector->GetBlockCount() == 1) + ReallocWithinBlock(*m_PoolBlockVector, m_PoolBlockVector->GetBlock(0)); + } + else + { + for (uint32_t i = 0; i < m_BlockVectorCount; ++i) + { + if (m_pBlockVectors[i] != VMA_NULL) + { + VmaMutexLockWrite lock(m_pBlockVectors[i]->GetMutex(), m_pBlockVectors[i]->GetAllocator()->m_UseMutex); + + if (m_pBlockVectors[i]->GetBlockCount() > 1) + { + if (ComputeDefragmentation(*m_pBlockVectors[i], i)) + break; + } + else if (m_pBlockVectors[i]->GetBlockCount() == 1) + { + if (ReallocWithinBlock(*m_pBlockVectors[i], m_pBlockVectors[i]->GetBlock(0))) + break; + } + } + } + } + + moveInfo.moveCount = static_cast(m_Moves.size()); + if (moveInfo.moveCount > 0) + { + moveInfo.pMoves = m_Moves.data(); + return VK_INCOMPLETE; + } + + moveInfo.pMoves = VMA_NULL; + return VK_SUCCESS; +} + +VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMoveInfo& moveInfo) +{ + VMA_ASSERT(moveInfo.moveCount > 0 ? moveInfo.pMoves != VMA_NULL : true); + + VkResult result = VK_SUCCESS; + VmaStlAllocator blockAllocator(m_MoveAllocator.m_pCallbacks); + VmaVector> immovableBlocks(blockAllocator); + VmaVector> mappedBlocks(blockAllocator); + + VmaAllocator allocator = VMA_NULL; + for (uint32_t i = 0; i < moveInfo.moveCount; ++i) + { + VmaDefragmentationMove& move = moveInfo.pMoves[i]; + size_t prevCount = 0, currentCount = 0; + VkDeviceSize freedBlockSize = 0; + + uint32_t vectorIndex; + VmaBlockVector* vector; + if (m_PoolBlockVector != VMA_NULL) + { + vectorIndex = 0; + vector = m_PoolBlockVector; + } + else + { + vectorIndex = move.srcAllocation->GetMemoryTypeIndex(); + vector = m_pBlockVectors[vectorIndex]; + VMA_ASSERT(vector != VMA_NULL); + } + + switch (move.operation) + { + case VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY: + { + uint8_t mapCount = move.srcAllocation->SwapBlockAllocation(vector->m_hAllocator, move.dstTmpAllocation); + if (mapCount > 0) + { + allocator = vector->m_hAllocator; + VmaDeviceMemoryBlock* newMapBlock = move.srcAllocation->GetBlock(); + bool notPresent = true; + for (FragmentedBlock& block : mappedBlocks) + { + if (block.block == newMapBlock) + { + notPresent = false; + block.data += mapCount; + break; + } + } + if (notPresent) + mappedBlocks.push_back({ mapCount, newMapBlock }); + } + + // Scope for locks, Free have it's own lock + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + prevCount = vector->GetBlockCount(); + freedBlockSize = move.dstTmpAllocation->GetBlock()->m_pMetadata->GetSize(); + } + vector->Free(move.dstTmpAllocation); + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + currentCount = vector->GetBlockCount(); + } + + result = VK_INCOMPLETE; + break; + } + case VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE: + { + m_PassStats.bytesMoved -= move.srcAllocation->GetSize(); + --m_PassStats.allocationsMoved; + vector->Free(move.dstTmpAllocation); + + VmaDeviceMemoryBlock* newBlock = move.srcAllocation->GetBlock(); + bool notPresent = true; + for (const FragmentedBlock& block : immovableBlocks) + { + if (block.block == newBlock) + { + notPresent = false; + break; + } + } + if (notPresent) + immovableBlocks.push_back({ vectorIndex, newBlock }); + break; + } + case VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY: + { + m_PassStats.bytesMoved -= move.srcAllocation->GetSize(); + --m_PassStats.allocationsMoved; + // Scope for locks, Free have it's own lock + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + prevCount = vector->GetBlockCount(); + freedBlockSize = move.srcAllocation->GetBlock()->m_pMetadata->GetSize(); + } + vector->Free(move.srcAllocation); + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + currentCount = vector->GetBlockCount(); + } + freedBlockSize *= prevCount - currentCount; + + VkDeviceSize dstBlockSize; + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + dstBlockSize = move.dstTmpAllocation->GetBlock()->m_pMetadata->GetSize(); + } + vector->Free(move.dstTmpAllocation); + { + VmaMutexLockRead lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + freedBlockSize += dstBlockSize * (currentCount - vector->GetBlockCount()); + currentCount = vector->GetBlockCount(); + } + + result = VK_INCOMPLETE; + break; + } + default: + VMA_ASSERT(0); + } + + if (prevCount > currentCount) + { + size_t freedBlocks = prevCount - currentCount; + m_PassStats.deviceMemoryBlocksFreed += static_cast(freedBlocks); + m_PassStats.bytesFreed += freedBlockSize; + } + + switch (m_Algorithm) + { + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + { + if (m_AlgorithmState != VMA_NULL) + { + // Avoid unnecessary tries to allocate when new free block is avaiable + StateExtensive& state = reinterpret_cast(m_AlgorithmState)[vectorIndex]; + if (state.firstFreeBlock != SIZE_MAX) + { + const size_t diff = prevCount - currentCount; + if (state.firstFreeBlock >= diff) + { + state.firstFreeBlock -= diff; + if (state.firstFreeBlock != 0) + state.firstFreeBlock -= vector->GetBlock(state.firstFreeBlock - 1)->m_pMetadata->IsEmpty(); + } + else + state.firstFreeBlock = 0; + } + } + } + } + } + moveInfo.moveCount = 0; + moveInfo.pMoves = VMA_NULL; + m_Moves.clear(); + + // Update stats + m_GlobalStats.allocationsMoved += m_PassStats.allocationsMoved; + m_GlobalStats.bytesFreed += m_PassStats.bytesFreed; + m_GlobalStats.bytesMoved += m_PassStats.bytesMoved; + m_GlobalStats.deviceMemoryBlocksFreed += m_PassStats.deviceMemoryBlocksFreed; + m_PassStats = { 0 }; + + // Move blocks with immovable allocations according to algorithm + if (immovableBlocks.size() > 0) + { + switch (m_Algorithm) + { + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + { + if (m_AlgorithmState != VMA_NULL) + { + bool swapped = false; + // Move to the start of free blocks range + for (const FragmentedBlock& block : immovableBlocks) + { + StateExtensive& state = reinterpret_cast(m_AlgorithmState)[block.data]; + if (state.operation != StateExtensive::Operation::Cleanup) + { + VmaBlockVector* vector = m_pBlockVectors[block.data]; + VmaMutexLockWrite lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + + for (size_t i = 0, count = vector->GetBlockCount() - m_ImmovableBlockCount; i < count; ++i) + { + if (vector->GetBlock(i) == block.block) + { + VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[vector->GetBlockCount() - ++m_ImmovableBlockCount]); + if (state.firstFreeBlock != SIZE_MAX) + { + if (i + 1 < state.firstFreeBlock) + { + if (state.firstFreeBlock > 1) + VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[--state.firstFreeBlock]); + else + --state.firstFreeBlock; + } + } + swapped = true; + break; + } + } + } + } + if (swapped) + result = VK_INCOMPLETE; + break; + } + } + default: + { + // Move to the begining + for (const FragmentedBlock& block : immovableBlocks) + { + VmaBlockVector* vector = m_pBlockVectors[block.data]; + VmaMutexLockWrite lock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + + for (size_t i = m_ImmovableBlockCount; i < vector->GetBlockCount(); ++i) + { + if (vector->GetBlock(i) == block.block) + { + VMA_SWAP(vector->m_Blocks[i], vector->m_Blocks[m_ImmovableBlockCount++]); + break; + } + } + } + break; + } + } + } + + // Bulk-map destination blocks + for (const FragmentedBlock& block : mappedBlocks) + { + VkResult res = block.block->Map(allocator, block.data, VMA_NULL); + VMA_ASSERT(res == VK_SUCCESS); + } + return result; +} + +bool VmaDefragmentationContext_T::ComputeDefragmentation(VmaBlockVector& vector, size_t index) +{ + switch (m_Algorithm) + { + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT: + return ComputeDefragmentation_Fast(vector); + default: + VMA_ASSERT(0); + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT: + return ComputeDefragmentation_Balanced(vector, index, true); + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT: + return ComputeDefragmentation_Full(vector); + case VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT: + return ComputeDefragmentation_Extensive(vector, index); + } +} + +VmaDefragmentationContext_T::MoveAllocationData VmaDefragmentationContext_T::GetMoveData( + VmaAllocHandle handle, VmaBlockMetadata* metadata) +{ + MoveAllocationData moveData; + moveData.move.srcAllocation = (VmaAllocation)metadata->GetAllocationUserData(handle); + moveData.size = moveData.move.srcAllocation->GetSize(); + moveData.alignment = moveData.move.srcAllocation->GetAlignment(); + moveData.type = moveData.move.srcAllocation->GetSuballocationType(); + moveData.flags = 0; + + if (moveData.move.srcAllocation->IsPersistentMap()) + moveData.flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + if (moveData.move.srcAllocation->IsMappingAllowed()) + moveData.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; + + return moveData; +} + +VmaDefragmentationContext_T::CounterStatus VmaDefragmentationContext_T::CheckCounters(VkDeviceSize bytes) +{ + // Ignore allocation if will exceed max size for copy + if (m_PassStats.bytesMoved + bytes > m_MaxPassBytes) + { + if (++m_IgnoredAllocs < MAX_ALLOCS_TO_IGNORE) + return CounterStatus::Ignore; + else + return CounterStatus::End; + } + return CounterStatus::Pass; +} + +bool VmaDefragmentationContext_T::IncrementCounters(VkDeviceSize bytes) +{ + m_PassStats.bytesMoved += bytes; + // Early return when max found + if (++m_PassStats.allocationsMoved >= m_MaxPassAllocations || m_PassStats.bytesMoved >= m_MaxPassBytes) + { + VMA_ASSERT(m_PassStats.allocationsMoved == m_MaxPassAllocations || + m_PassStats.bytesMoved == m_MaxPassBytes && "Exceeded maximal pass threshold!"); + return true; + } + return false; +} + +bool VmaDefragmentationContext_T::ReallocWithinBlock(VmaBlockVector& vector, VmaDeviceMemoryBlock* block) +{ + VmaBlockMetadata* metadata = block->m_pMetadata; + + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) + { + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + default: + VMA_ASSERT(0); + case CounterStatus::Pass: + break; + } + + VkDeviceSize offset = moveData.move.srcAllocation->GetOffset(); + if (offset != 0 && metadata->GetSumFreeSize() >= moveData.size) + { + VmaAllocationRequest request = {}; + if (metadata->CreateAllocationRequest( + moveData.size, + moveData.alignment, + false, + moveData.type, + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + &request)) + { + if (metadata->GetAllocationOffset(request.allocHandle) < offset) + { + if (vector.CommitAllocationRequest( + request, + block, + moveData.alignment, + moveData.flags, + this, + moveData.type, + &moveData.move.dstTmpAllocation) == VK_SUCCESS) + { + m_Moves.push_back(moveData.move); + if (IncrementCounters(moveData.size)) + return true; + } + } + } + } + } + return false; +} + +bool VmaDefragmentationContext_T::AllocInOtherBlock(size_t start, size_t end, MoveAllocationData& data, VmaBlockVector& vector) +{ + for (; start < end; ++start) + { + VmaDeviceMemoryBlock* dstBlock = vector.GetBlock(start); + if (dstBlock->m_pMetadata->GetSumFreeSize() >= data.size) + { + if (vector.AllocateFromBlock(dstBlock, + data.size, + data.alignment, + data.flags, + this, + data.type, + 0, + &data.move.dstTmpAllocation) == VK_SUCCESS) + { + m_Moves.push_back(data.move); + if (IncrementCounters(data.size)) + return true; + break; + } + } + } + return false; +} + +bool VmaDefragmentationContext_T::ComputeDefragmentation_Fast(VmaBlockVector& vector) +{ + // Move only between blocks + + // Go through allocations in last blocks and try to fit them inside first ones + for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i) + { + VmaBlockMetadata* metadata = vector.GetBlock(i)->m_pMetadata; + + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) + { + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + default: + VMA_ASSERT(0); + case CounterStatus::Pass: + break; + } + + // Check all previous blocks for free space + if (AllocInOtherBlock(0, i, moveData, vector)) + return true; + } + } + return false; +} + +bool VmaDefragmentationContext_T::ComputeDefragmentation_Balanced(VmaBlockVector& vector, size_t index, bool update) +{ + // Go over every allocation and try to fit it in previous blocks at lowest offsets, + // if not possible: realloc within single block to minimize offset (exclude offset == 0), + // but only if there are noticable gaps between them (some heuristic, ex. average size of allocation in block) + VMA_ASSERT(m_AlgorithmState != VMA_NULL); + + StateBalanced& vectorState = reinterpret_cast(m_AlgorithmState)[index]; + if (update && vectorState.avgAllocSize == UINT64_MAX) + UpdateVectorStatistics(vector, vectorState); + + const size_t startMoveCount = m_Moves.size(); + VkDeviceSize minimalFreeRegion = vectorState.avgFreeSize / 2; + for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i) + { + VmaDeviceMemoryBlock* block = vector.GetBlock(i); + VmaBlockMetadata* metadata = block->m_pMetadata; + VkDeviceSize prevFreeRegionSize = 0; + + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) + { + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + default: + VMA_ASSERT(0); + case CounterStatus::Pass: + break; + } + + // Check all previous blocks for free space + const size_t prevMoveCount = m_Moves.size(); + if (AllocInOtherBlock(0, i, moveData, vector)) + return true; + + VkDeviceSize nextFreeRegionSize = metadata->GetNextFreeRegionSize(handle); + // If no room found then realloc within block for lower offset + VkDeviceSize offset = moveData.move.srcAllocation->GetOffset(); + if (prevMoveCount == m_Moves.size() && offset != 0 && metadata->GetSumFreeSize() >= moveData.size) + { + // Check if realloc will make sense + if (prevFreeRegionSize >= minimalFreeRegion || + nextFreeRegionSize >= minimalFreeRegion || + moveData.size <= vectorState.avgFreeSize || + moveData.size <= vectorState.avgAllocSize) + { + VmaAllocationRequest request = {}; + if (metadata->CreateAllocationRequest( + moveData.size, + moveData.alignment, + false, + moveData.type, + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + &request)) + { + if (metadata->GetAllocationOffset(request.allocHandle) < offset) + { + if (vector.CommitAllocationRequest( + request, + block, + moveData.alignment, + moveData.flags, + this, + moveData.type, + &moveData.move.dstTmpAllocation) == VK_SUCCESS) + { + m_Moves.push_back(moveData.move); + if (IncrementCounters(moveData.size)) + return true; + } + } + } + } + } + prevFreeRegionSize = nextFreeRegionSize; + } + } + + // No moves perfomed, update statistics to current vector state + if (startMoveCount == m_Moves.size() && !update) + { + vectorState.avgAllocSize = UINT64_MAX; + return ComputeDefragmentation_Balanced(vector, index, false); + } + return false; +} + +bool VmaDefragmentationContext_T::ComputeDefragmentation_Full(VmaBlockVector& vector) +{ + // Go over every allocation and try to fit it in previous blocks at lowest offsets, + // if not possible: realloc within single block to minimize offset (exclude offset == 0) + + for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i) + { + VmaDeviceMemoryBlock* block = vector.GetBlock(i); + VmaBlockMetadata* metadata = block->m_pMetadata; + + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) + { + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + default: + VMA_ASSERT(0); + case CounterStatus::Pass: + break; + } + + // Check all previous blocks for free space + const size_t prevMoveCount = m_Moves.size(); + if (AllocInOtherBlock(0, i, moveData, vector)) + return true; + + // If no room found then realloc within block for lower offset + VkDeviceSize offset = moveData.move.srcAllocation->GetOffset(); + if (prevMoveCount == m_Moves.size() && offset != 0 && metadata->GetSumFreeSize() >= moveData.size) + { + VmaAllocationRequest request = {}; + if (metadata->CreateAllocationRequest( + moveData.size, + moveData.alignment, + false, + moveData.type, + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + &request)) + { + if (metadata->GetAllocationOffset(request.allocHandle) < offset) + { + if (vector.CommitAllocationRequest( + request, + block, + moveData.alignment, + moveData.flags, + this, + moveData.type, + &moveData.move.dstTmpAllocation) == VK_SUCCESS) + { + m_Moves.push_back(moveData.move); + if (IncrementCounters(moveData.size)) + return true; + } + } + } + } + } + } + return false; +} + +bool VmaDefragmentationContext_T::ComputeDefragmentation_Extensive(VmaBlockVector& vector, size_t index) +{ + // First free single block, then populate it to the brim, then free another block, and so on + + // Fallback to previous algorithm since without granularity conflicts it can achieve max packing + if (vector.m_BufferImageGranularity == 1) + return ComputeDefragmentation_Full(vector); + + VMA_ASSERT(m_AlgorithmState != VMA_NULL); + + StateExtensive& vectorState = reinterpret_cast(m_AlgorithmState)[index]; + + bool texturePresent = false, bufferPresent = false, otherPresent = false; + switch (vectorState.operation) + { + case StateExtensive::Operation::Done: // Vector defragmented + return false; + case StateExtensive::Operation::FindFreeBlockBuffer: + case StateExtensive::Operation::FindFreeBlockTexture: + case StateExtensive::Operation::FindFreeBlockAll: + { + // No more blocks to free, just perform fast realloc and move to cleanup + if (vectorState.firstFreeBlock == 0) + { + vectorState.operation = StateExtensive::Operation::Cleanup; + return ComputeDefragmentation_Fast(vector); + } + + // No free blocks, have to clear last one + size_t last = (vectorState.firstFreeBlock == SIZE_MAX ? vector.GetBlockCount() : vectorState.firstFreeBlock) - 1; + VmaBlockMetadata* freeMetadata = vector.GetBlock(last)->m_pMetadata; + + const size_t prevMoveCount = m_Moves.size(); + for (VmaAllocHandle handle = freeMetadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = freeMetadata->GetNextAllocation(handle)) + { + MoveAllocationData moveData = GetMoveData(handle, freeMetadata); + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + default: + VMA_ASSERT(0); + case CounterStatus::Pass: + break; + } + + // Check all previous blocks for free space + if (AllocInOtherBlock(0, last, moveData, vector)) + { + // Full clear performed already + if (prevMoveCount != m_Moves.size() && freeMetadata->GetNextAllocation(handle) == VK_NULL_HANDLE) + reinterpret_cast(m_AlgorithmState)[index] = last; + return true; + } + } + + if (prevMoveCount == m_Moves.size()) + { + // Cannot perform full clear, have to move data in other blocks around + if (last != 0) + { + for (size_t i = last - 1; i; --i) + { + if (ReallocWithinBlock(vector, vector.GetBlock(i))) + return true; + } + } + + if (prevMoveCount == m_Moves.size()) + { + // No possible reallocs within blocks, try to move them around fast + return ComputeDefragmentation_Fast(vector); + } + } + else + { + switch (vectorState.operation) + { + case StateExtensive::Operation::FindFreeBlockBuffer: + vectorState.operation = StateExtensive::Operation::MoveBuffers; + break; + default: + VMA_ASSERT(0); + case StateExtensive::Operation::FindFreeBlockTexture: + vectorState.operation = StateExtensive::Operation::MoveTextures; + break; + case StateExtensive::Operation::FindFreeBlockAll: + vectorState.operation = StateExtensive::Operation::MoveAll; + break; + } + vectorState.firstFreeBlock = last; + // Nothing done, block found without reallocations, can perform another reallocs in same pass + return ComputeDefragmentation_Extensive(vector, index); + } + break; + } + case StateExtensive::Operation::MoveTextures: + { + if (MoveDataToFreeBlocks(VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL, vector, + vectorState.firstFreeBlock, texturePresent, bufferPresent, otherPresent)) + { + if (texturePresent) + { + vectorState.operation = StateExtensive::Operation::FindFreeBlockTexture; + return ComputeDefragmentation_Extensive(vector, index); + } + + if (!bufferPresent && !otherPresent) + { + vectorState.operation = StateExtensive::Operation::Cleanup; + break; + } + + // No more textures to move, check buffers + vectorState.operation = StateExtensive::Operation::MoveBuffers; + bufferPresent = false; + otherPresent = false; + } + else + break; + } + case StateExtensive::Operation::MoveBuffers: + { + if (MoveDataToFreeBlocks(VMA_SUBALLOCATION_TYPE_BUFFER, vector, + vectorState.firstFreeBlock, texturePresent, bufferPresent, otherPresent)) + { + if (bufferPresent) + { + vectorState.operation = StateExtensive::Operation::FindFreeBlockBuffer; + return ComputeDefragmentation_Extensive(vector, index); + } + + if (!otherPresent) + { + vectorState.operation = StateExtensive::Operation::Cleanup; + break; + } + + // No more buffers to move, check all others + vectorState.operation = StateExtensive::Operation::MoveAll; + otherPresent = false; + } + else + break; + } + case StateExtensive::Operation::MoveAll: + { + if (MoveDataToFreeBlocks(VMA_SUBALLOCATION_TYPE_FREE, vector, + vectorState.firstFreeBlock, texturePresent, bufferPresent, otherPresent)) + { + if (otherPresent) + { + vectorState.operation = StateExtensive::Operation::FindFreeBlockBuffer; + return ComputeDefragmentation_Extensive(vector, index); + } + // Everything moved + vectorState.operation = StateExtensive::Operation::Cleanup; + } + break; + } + case StateExtensive::Operation::Cleanup: + // Cleanup is handled below so that other operations may reuse the cleanup code. This case is here to prevent the unhandled enum value warning (C4062). + break; + } + + if (vectorState.operation == StateExtensive::Operation::Cleanup) + { + // All other work done, pack data in blocks even tighter if possible + const size_t prevMoveCount = m_Moves.size(); + for (size_t i = 0; i < vector.GetBlockCount(); ++i) + { + if (ReallocWithinBlock(vector, vector.GetBlock(i))) + return true; + } + + if (prevMoveCount == m_Moves.size()) + vectorState.operation = StateExtensive::Operation::Done; + } + return false; +} + +void VmaDefragmentationContext_T::UpdateVectorStatistics(VmaBlockVector& vector, StateBalanced& state) +{ + size_t allocCount = 0; + size_t freeCount = 0; + state.avgFreeSize = 0; + state.avgAllocSize = 0; + + for (size_t i = 0; i < vector.GetBlockCount(); ++i) + { + VmaBlockMetadata* metadata = vector.GetBlock(i)->m_pMetadata; + + allocCount += metadata->GetAllocationCount(); + freeCount += metadata->GetFreeRegionsCount(); + state.avgFreeSize += metadata->GetSumFreeSize(); + state.avgAllocSize += metadata->GetSize(); + } + + state.avgAllocSize = (state.avgAllocSize - state.avgFreeSize) / allocCount; + state.avgFreeSize /= freeCount; +} + +bool VmaDefragmentationContext_T::MoveDataToFreeBlocks(VmaSuballocationType currentType, + VmaBlockVector& vector, size_t firstFreeBlock, + bool& texturePresent, bool& bufferPresent, bool& otherPresent) +{ + const size_t prevMoveCount = m_Moves.size(); + for (size_t i = firstFreeBlock ; i;) + { + VmaDeviceMemoryBlock* block = vector.GetBlock(--i); + VmaBlockMetadata* metadata = block->m_pMetadata; + + for (VmaAllocHandle handle = metadata->GetAllocationListBegin(); + handle != VK_NULL_HANDLE; + handle = metadata->GetNextAllocation(handle)) + { + MoveAllocationData moveData = GetMoveData(handle, metadata); + // Ignore newly created allocations by defragmentation algorithm + if (moveData.move.srcAllocation->GetUserData() == this) + continue; + switch (CheckCounters(moveData.move.srcAllocation->GetSize())) + { + case CounterStatus::Ignore: + continue; + case CounterStatus::End: + return true; + default: + VMA_ASSERT(0); + case CounterStatus::Pass: + break; + } + + // Move only single type of resources at once + if (!VmaIsBufferImageGranularityConflict(moveData.type, currentType)) + { + // Try to fit allocation into free blocks + if (AllocInOtherBlock(firstFreeBlock, vector.GetBlockCount(), moveData, vector)) + return false; + } + + if (!VmaIsBufferImageGranularityConflict(moveData.type, VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL)) + texturePresent = true; + else if (!VmaIsBufferImageGranularityConflict(moveData.type, VMA_SUBALLOCATION_TYPE_BUFFER)) + bufferPresent = true; + else + otherPresent = true; + } + } + return prevMoveCount == m_Moves.size(); +} +#endif // _VMA_DEFRAGMENTATION_CONTEXT_FUNCTIONS + +#ifndef _VMA_POOL_T_FUNCTIONS +VmaPool_T::VmaPool_T( + VmaAllocator hAllocator, + const VmaPoolCreateInfo& createInfo, + VkDeviceSize preferredBlockSize) + : m_BlockVector( + hAllocator, + this, // hParentPool + createInfo.memoryTypeIndex, + createInfo.blockSize != 0 ? createInfo.blockSize : preferredBlockSize, + createInfo.minBlockCount, + createInfo.maxBlockCount, + (createInfo.flags& VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(), + createInfo.blockSize != 0, // explicitBlockSize + createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm + createInfo.priority, + VMA_MAX(hAllocator->GetMemoryTypeMinAlignment(createInfo.memoryTypeIndex), createInfo.minAllocationAlignment), + createInfo.pMemoryAllocateNext), + m_Id(0), + m_Name(VMA_NULL) {} + +VmaPool_T::~VmaPool_T() +{ + VMA_ASSERT(m_PrevPool == VMA_NULL && m_NextPool == VMA_NULL); +} + +void VmaPool_T::SetName(const char* pName) +{ + const VkAllocationCallbacks* allocs = m_BlockVector.GetAllocator()->GetAllocationCallbacks(); + VmaFreeString(allocs, m_Name); + + if (pName != VMA_NULL) + { + m_Name = VmaCreateStringCopy(allocs, pName); + } + else + { + m_Name = VMA_NULL; + } +} +#endif // _VMA_POOL_T_FUNCTIONS + +#ifndef _VMA_ALLOCATOR_T_FUNCTIONS +VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : + m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0), + m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0), + m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0), + m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0), + m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0), + m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0), + m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0), + m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), + m_hDevice(pCreateInfo->device), + m_hInstance(pCreateInfo->instance), + m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), + m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ? + *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks), + m_AllocationObjectAllocator(&m_AllocationCallbacks), + m_HeapSizeLimitMask(0), + m_DeviceMemoryCount(0), + m_PreferredLargeHeapBlockSize(0), + m_PhysicalDevice(pCreateInfo->physicalDevice), + m_GpuDefragmentationMemoryTypeBits(UINT32_MAX), + m_NextPoolId(0), + m_GlobalMemoryTypeBits(UINT32_MAX) +{ + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + m_UseKhrDedicatedAllocation = false; + m_UseKhrBindMemory2 = false; + } + + if(VMA_DEBUG_DETECT_CORRUPTION) + { + // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it. + VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0); + } + + VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance); + + if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0)) + { +#if !(VMA_DEDICATED_ALLOCATION) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros."); + } +#endif +#if !(VMA_BIND_MEMORY2) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros."); + } +#endif + } +#if !(VMA_MEMORY_BUDGET) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros."); + } +#endif +#if !(VMA_BUFFER_DEVICE_ADDRESS) + if(m_UseKhrBufferDeviceAddress) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); + } +#endif +#if VMA_VULKAN_VERSION < 1002000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0)) + { + VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros."); + } +#endif +#if VMA_VULKAN_VERSION < 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros."); + } +#endif +#if !(VMA_MEMORY_PRIORITY) + if(m_UseExtMemoryPriority) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); + } +#endif + + memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); + memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); + memset(&m_MemProps, 0, sizeof(m_MemProps)); + + memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors)); + memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions)); + +#if VMA_EXTERNAL_MEMORY + memset(&m_TypeExternalMemoryHandleTypes, 0, sizeof(m_TypeExternalMemoryHandleTypes)); +#endif // #if VMA_EXTERNAL_MEMORY + + if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) + { + m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData; + m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate; + m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree; + } + + ImportVulkanFunctions(pCreateInfo->pVulkanFunctions); + + (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); + (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); + + VMA_ASSERT(VmaIsPow2(VMA_MIN_ALIGNMENT)); + VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY)); + VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.bufferImageGranularity)); + VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.nonCoherentAtomSize)); + + m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ? + pCreateInfo->preferredLargeHeapBlockSize : static_cast(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE); + + m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits(); + +#if VMA_EXTERNAL_MEMORY + if(pCreateInfo->pTypeExternalMemoryHandleTypes != VMA_NULL) + { + memcpy(m_TypeExternalMemoryHandleTypes, pCreateInfo->pTypeExternalMemoryHandleTypes, + sizeof(VkExternalMemoryHandleTypeFlagsKHR) * GetMemoryTypeCount()); + } +#endif // #if VMA_EXTERNAL_MEMORY + + if(pCreateInfo->pHeapSizeLimit != VMA_NULL) + { + for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) + { + const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex]; + if(limit != VK_WHOLE_SIZE) + { + m_HeapSizeLimitMask |= 1u << heapIndex; + if(limit < m_MemProps.memoryHeaps[heapIndex].size) + { + m_MemProps.memoryHeaps[heapIndex].size = limit; + } + } + } + } + + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + // Create only supported types + if((m_GlobalMemoryTypeBits & (1u << memTypeIndex)) != 0) + { + const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex); + m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)( + this, + VK_NULL_HANDLE, // hParentPool + memTypeIndex, + preferredBlockSize, + 0, + SIZE_MAX, + GetBufferImageGranularity(), + false, // explicitBlockSize + 0, // algorithm + 0.5f, // priority (0.5 is the default per Vulkan spec) + GetMemoryTypeMinAlignment(memTypeIndex), // minAllocationAlignment + VMA_NULL); // // pMemoryAllocateNext + // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here, + // becase minBlockCount is 0. + } + } +} + +VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo) +{ + VkResult res = VK_SUCCESS; + +#if VMA_MEMORY_BUDGET + if(m_UseExtMemoryBudget) + { + UpdateVulkanBudget(); + } +#endif // #if VMA_MEMORY_BUDGET + + return res; +} + +VmaAllocator_T::~VmaAllocator_T() +{ + VMA_ASSERT(m_Pools.IsEmpty()); + + for(size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; ) + { + vma_delete(this, m_pBlockVectors[memTypeIndex]); + } +} + +void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions) +{ +#if VMA_STATIC_VULKAN_FUNCTIONS == 1 + ImportVulkanFunctions_Static(); +#endif + + if(pVulkanFunctions != VMA_NULL) + { + ImportVulkanFunctions_Custom(pVulkanFunctions); + } + +#if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1 + ImportVulkanFunctions_Dynamic(); +#endif + + ValidateVulkanFunctions(); +} + +#if VMA_STATIC_VULKAN_FUNCTIONS == 1 + +void VmaAllocator_T::ImportVulkanFunctions_Static() +{ + // Vulkan 1.0 + m_VulkanFunctions.vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vkGetInstanceProcAddr; + m_VulkanFunctions.vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetDeviceProcAddr; + m_VulkanFunctions.vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)vkGetPhysicalDeviceProperties; + m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetPhysicalDeviceMemoryProperties; + m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory; + m_VulkanFunctions.vkFreeMemory = (PFN_vkFreeMemory)vkFreeMemory; + m_VulkanFunctions.vkMapMemory = (PFN_vkMapMemory)vkMapMemory; + m_VulkanFunctions.vkUnmapMemory = (PFN_vkUnmapMemory)vkUnmapMemory; + m_VulkanFunctions.vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)vkFlushMappedMemoryRanges; + m_VulkanFunctions.vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)vkInvalidateMappedMemoryRanges; + m_VulkanFunctions.vkBindBufferMemory = (PFN_vkBindBufferMemory)vkBindBufferMemory; + m_VulkanFunctions.vkBindImageMemory = (PFN_vkBindImageMemory)vkBindImageMemory; + m_VulkanFunctions.vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)vkGetBufferMemoryRequirements; + m_VulkanFunctions.vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)vkGetImageMemoryRequirements; + m_VulkanFunctions.vkCreateBuffer = (PFN_vkCreateBuffer)vkCreateBuffer; + m_VulkanFunctions.vkDestroyBuffer = (PFN_vkDestroyBuffer)vkDestroyBuffer; + m_VulkanFunctions.vkCreateImage = (PFN_vkCreateImage)vkCreateImage; + m_VulkanFunctions.vkDestroyImage = (PFN_vkDestroyImage)vkDestroyImage; + m_VulkanFunctions.vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)vkCmdCopyBuffer; + + // Vulkan 1.1 +#if VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2)vkGetBufferMemoryRequirements2; + m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2; + m_VulkanFunctions.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)vkBindBufferMemory2; + m_VulkanFunctions.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)vkBindImageMemory2; + m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2; + } +#endif + +#if VMA_VULKAN_VERSION >= 1003000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + { + m_VulkanFunctions.vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements)vkGetDeviceBufferMemoryRequirements; + m_VulkanFunctions.vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)vkGetDeviceImageMemoryRequirements; + } +#endif +} + +#endif // VMA_STATIC_VULKAN_FUNCTIONS == 1 + +void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions) +{ + VMA_ASSERT(pVulkanFunctions != VMA_NULL); + +#define VMA_COPY_IF_NOT_NULL(funcName) \ + if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName; + + VMA_COPY_IF_NOT_NULL(vkGetInstanceProcAddr); + VMA_COPY_IF_NOT_NULL(vkGetDeviceProcAddr); + VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties); + VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties); + VMA_COPY_IF_NOT_NULL(vkAllocateMemory); + VMA_COPY_IF_NOT_NULL(vkFreeMemory); + VMA_COPY_IF_NOT_NULL(vkMapMemory); + VMA_COPY_IF_NOT_NULL(vkUnmapMemory); + VMA_COPY_IF_NOT_NULL(vkFlushMappedMemoryRanges); + VMA_COPY_IF_NOT_NULL(vkInvalidateMappedMemoryRanges); + VMA_COPY_IF_NOT_NULL(vkBindBufferMemory); + VMA_COPY_IF_NOT_NULL(vkBindImageMemory); + VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements); + VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements); + VMA_COPY_IF_NOT_NULL(vkCreateBuffer); + VMA_COPY_IF_NOT_NULL(vkDestroyBuffer); + VMA_COPY_IF_NOT_NULL(vkCreateImage); + VMA_COPY_IF_NOT_NULL(vkDestroyImage); + VMA_COPY_IF_NOT_NULL(vkCmdCopyBuffer); + +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR); + VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR); +#endif + +#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 + VMA_COPY_IF_NOT_NULL(vkBindBufferMemory2KHR); + VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR); +#endif + +#if VMA_MEMORY_BUDGET + VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR); +#endif + +#if VMA_VULKAN_VERSION >= 1003000 + VMA_COPY_IF_NOT_NULL(vkGetDeviceBufferMemoryRequirements); + VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements); +#endif + +#undef VMA_COPY_IF_NOT_NULL +} + +#if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1 + +void VmaAllocator_T::ImportVulkanFunctions_Dynamic() +{ + VMA_ASSERT(m_VulkanFunctions.vkGetInstanceProcAddr && m_VulkanFunctions.vkGetDeviceProcAddr && + "To use VMA_DYNAMIC_VULKAN_FUNCTIONS in new versions of VMA you now have to pass " + "VmaVulkanFunctions::vkGetInstanceProcAddr and vkGetDeviceProcAddr as VmaAllocatorCreateInfo::pVulkanFunctions. " + "Other members can be null."); + +#define VMA_FETCH_INSTANCE_FUNC(memberName, functionPointerType, functionNameString) \ + if(m_VulkanFunctions.memberName == VMA_NULL) \ + m_VulkanFunctions.memberName = \ + (functionPointerType)m_VulkanFunctions.vkGetInstanceProcAddr(m_hInstance, functionNameString); +#define VMA_FETCH_DEVICE_FUNC(memberName, functionPointerType, functionNameString) \ + if(m_VulkanFunctions.memberName == VMA_NULL) \ + m_VulkanFunctions.memberName = \ + (functionPointerType)m_VulkanFunctions.vkGetDeviceProcAddr(m_hDevice, functionNameString); + + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties, PFN_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties, PFN_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties"); + VMA_FETCH_DEVICE_FUNC(vkAllocateMemory, PFN_vkAllocateMemory, "vkAllocateMemory"); + VMA_FETCH_DEVICE_FUNC(vkFreeMemory, PFN_vkFreeMemory, "vkFreeMemory"); + VMA_FETCH_DEVICE_FUNC(vkMapMemory, PFN_vkMapMemory, "vkMapMemory"); + VMA_FETCH_DEVICE_FUNC(vkUnmapMemory, PFN_vkUnmapMemory, "vkUnmapMemory"); + VMA_FETCH_DEVICE_FUNC(vkFlushMappedMemoryRanges, PFN_vkFlushMappedMemoryRanges, "vkFlushMappedMemoryRanges"); + VMA_FETCH_DEVICE_FUNC(vkInvalidateMappedMemoryRanges, PFN_vkInvalidateMappedMemoryRanges, "vkInvalidateMappedMemoryRanges"); + VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory, PFN_vkBindBufferMemory, "vkBindBufferMemory"); + VMA_FETCH_DEVICE_FUNC(vkBindImageMemory, PFN_vkBindImageMemory, "vkBindImageMemory"); + VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements, PFN_vkGetBufferMemoryRequirements, "vkGetBufferMemoryRequirements"); + VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements, PFN_vkGetImageMemoryRequirements, "vkGetImageMemoryRequirements"); + VMA_FETCH_DEVICE_FUNC(vkCreateBuffer, PFN_vkCreateBuffer, "vkCreateBuffer"); + VMA_FETCH_DEVICE_FUNC(vkDestroyBuffer, PFN_vkDestroyBuffer, "vkDestroyBuffer"); + VMA_FETCH_DEVICE_FUNC(vkCreateImage, PFN_vkCreateImage, "vkCreateImage"); + VMA_FETCH_DEVICE_FUNC(vkDestroyImage, PFN_vkDestroyImage, "vkDestroyImage"); + VMA_FETCH_DEVICE_FUNC(vkCmdCopyBuffer, PFN_vkCmdCopyBuffer, "vkCmdCopyBuffer"); + +#if VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2"); + VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2"); + VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2, "vkBindBufferMemory2"); + VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2, "vkBindImageMemory2"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2"); + } +#endif + +#if VMA_DEDICATED_ALLOCATION + if(m_UseKhrDedicatedAllocation) + { + VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR"); + VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR"); + } +#endif + +#if VMA_BIND_MEMORY2 + if(m_UseKhrBindMemory2) + { + VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2KHR, "vkBindBufferMemory2KHR"); + VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2KHR, "vkBindImageMemory2KHR"); + } +#endif // #if VMA_BIND_MEMORY2 + +#if VMA_MEMORY_BUDGET + if(m_UseExtMemoryBudget) + { + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); + } +#endif // #if VMA_MEMORY_BUDGET + +#if VMA_VULKAN_VERSION >= 1003000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + { + VMA_FETCH_DEVICE_FUNC(vkGetDeviceBufferMemoryRequirements, PFN_vkGetDeviceBufferMemoryRequirements, "vkGetDeviceBufferMemoryRequirements"); + VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirements, "vkGetDeviceImageMemoryRequirements"); + } +#endif + +#undef VMA_FETCH_DEVICE_FUNC +#undef VMA_FETCH_INSTANCE_FUNC +} + +#endif // VMA_DYNAMIC_VULKAN_FUNCTIONS == 1 + +void VmaAllocator_T::ValidateVulkanFunctions() +{ + VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkFlushMappedMemoryRanges != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkInvalidateMappedMemoryRanges != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL); + +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation) + { + VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL); + } +#endif + +#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2) + { + VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL); + } +#endif + +#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 + if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); + } +#endif + +#if VMA_VULKAN_VERSION >= 1003000 + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + { + VMA_ASSERT(m_VulkanFunctions.vkGetDeviceBufferMemoryRequirements != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetDeviceImageMemoryRequirements != VMA_NULL); + } +#endif +} + +VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex) +{ + const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); + const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; + const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE; + return VmaAlignUp(isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize, (VkDeviceSize)32); +} + +VkResult VmaAllocator_T::AllocateMemoryOfType( + VmaPool pool, + VkDeviceSize size, + VkDeviceSize alignment, + bool dedicatedPreferred, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + const VmaAllocationCreateInfo& createInfo, + uint32_t memTypeIndex, + VmaSuballocationType suballocType, + VmaDedicatedAllocationList& dedicatedAllocations, + VmaBlockVector& blockVector, + size_t allocationCount, + VmaAllocation* pAllocations) +{ + VMA_ASSERT(pAllocations != VMA_NULL); + VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size); + + VmaAllocationCreateInfo finalCreateInfo = createInfo; + VkResult res = CalcMemTypeParams( + finalCreateInfo, + memTypeIndex, + size, + allocationCount); + if(res != VK_SUCCESS) + return res; + + if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) + { + return AllocateDedicatedMemory( + pool, + size, + suballocType, + dedicatedAllocations, + memTypeIndex, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, + (finalCreateInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0, + finalCreateInfo.pUserData, + finalCreateInfo.priority, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + allocationCount, + pAllocations, + blockVector.GetAllocationNextPtr()); + } + else + { + const bool canAllocateDedicated = + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 && + (pool == VK_NULL_HANDLE || !blockVector.HasExplicitBlockSize()); + + if(canAllocateDedicated) + { + // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size. + if(size > blockVector.GetPreferredBlockSize() / 2) + { + dedicatedPreferred = true; + } + // Protection against creating each allocation as dedicated when we reach or exceed heap size/budget, + // which can quickly deplete maxMemoryAllocationCount: Don't prefer dedicated allocations when above + // 3/4 of the maximum allocation count. + if(m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4) + { + dedicatedPreferred = false; + } + + if(dedicatedPreferred) + { + res = AllocateDedicatedMemory( + pool, + size, + suballocType, + dedicatedAllocations, + memTypeIndex, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, + (finalCreateInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0, + finalCreateInfo.pUserData, + finalCreateInfo.priority, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + allocationCount, + pAllocations, + blockVector.GetAllocationNextPtr()); + if(res == VK_SUCCESS) + { + // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here. + VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); + return VK_SUCCESS; + } + } + } + + res = blockVector.Allocate( + size, + alignment, + finalCreateInfo, + suballocType, + allocationCount, + pAllocations); + if(res == VK_SUCCESS) + return VK_SUCCESS; + + // Try dedicated memory. + if(canAllocateDedicated && !dedicatedPreferred) + { + res = AllocateDedicatedMemory( + pool, + size, + suballocType, + dedicatedAllocations, + memTypeIndex, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, + (finalCreateInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0, + (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT) != 0, + finalCreateInfo.pUserData, + finalCreateInfo.priority, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + allocationCount, + pAllocations, + blockVector.GetAllocationNextPtr()); + if(res == VK_SUCCESS) + { + // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here. + VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); + return VK_SUCCESS; + } + } + // Everything failed: Return error code. + VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); + return res; + } +} + +VkResult VmaAllocator_T::AllocateDedicatedMemory( + VmaPool pool, + VkDeviceSize size, + VmaSuballocationType suballocType, + VmaDedicatedAllocationList& dedicatedAllocations, + uint32_t memTypeIndex, + bool map, + bool isUserDataString, + bool isMappingAllowed, + bool canAliasMemory, + void* pUserData, + float priority, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + size_t allocationCount, + VmaAllocation* pAllocations, + const void* pNextChain) +{ + VMA_ASSERT(allocationCount > 0 && pAllocations); + + VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocInfo.memoryTypeIndex = memTypeIndex; + allocInfo.allocationSize = size; + allocInfo.pNext = pNextChain; + +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; + if(!canAliasMemory) + { + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + if(dedicatedBuffer != VK_NULL_HANDLE) + { + VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE); + dedicatedAllocInfo.buffer = dedicatedBuffer; + VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); + } + else if(dedicatedImage != VK_NULL_HANDLE) + { + dedicatedAllocInfo.image = dedicatedImage; + VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); + } + } + } +#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + +#if VMA_BUFFER_DEVICE_ADDRESS + VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR }; + if(m_UseKhrBufferDeviceAddress) + { + bool canContainBufferWithDeviceAddress = true; + if(dedicatedBuffer != VK_NULL_HANDLE) + { + canContainBufferWithDeviceAddress = dedicatedBufferImageUsage == UINT32_MAX || // Usage flags unknown + (dedicatedBufferImageUsage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) != 0; + } + else if(dedicatedImage != VK_NULL_HANDLE) + { + canContainBufferWithDeviceAddress = false; + } + if(canContainBufferWithDeviceAddress) + { + allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo); + } + } +#endif // #if VMA_BUFFER_DEVICE_ADDRESS + +#if VMA_MEMORY_PRIORITY + VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT }; + if(m_UseExtMemoryPriority) + { + VMA_ASSERT(priority >= 0.f && priority <= 1.f); + priorityInfo.priority = priority; + VmaPnextChainPushFront(&allocInfo, &priorityInfo); + } +#endif // #if VMA_MEMORY_PRIORITY + +#if VMA_EXTERNAL_MEMORY + // Attach VkExportMemoryAllocateInfoKHR if necessary. + VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR }; + exportMemoryAllocInfo.handleTypes = GetExternalMemoryHandleTypeFlags(memTypeIndex); + if(exportMemoryAllocInfo.handleTypes != 0) + { + VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo); + } +#endif // #if VMA_EXTERNAL_MEMORY + + size_t allocIndex; + VkResult res = VK_SUCCESS; + for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + { + res = AllocateDedicatedMemoryPage( + pool, + size, + suballocType, + memTypeIndex, + allocInfo, + map, + isUserDataString, + isMappingAllowed, + pUserData, + pAllocations + allocIndex); + if(res != VK_SUCCESS) + { + break; + } + } + + if(res == VK_SUCCESS) + { + for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + { + dedicatedAllocations.Register(pAllocations[allocIndex]); + } + VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex); + } + else + { + // Free all already created allocations. + while(allocIndex--) + { + VmaAllocation currAlloc = pAllocations[allocIndex]; + VkDeviceMemory hMemory = currAlloc->GetMemory(); + + /* + There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory + before vkFreeMemory. + + if(currAlloc->GetMappedData() != VMA_NULL) + { + (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory); + } + */ + + FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory); + m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize()); + m_AllocationObjectAllocator.Free(currAlloc); + } + + memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); + } + + return res; +} + +VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( + VmaPool pool, + VkDeviceSize size, + VmaSuballocationType suballocType, + uint32_t memTypeIndex, + const VkMemoryAllocateInfo& allocInfo, + bool map, + bool isUserDataString, + bool isMappingAllowed, + void* pUserData, + VmaAllocation* pAllocation) +{ + VkDeviceMemory hMemory = VK_NULL_HANDLE; + VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory); + if(res < 0) + { + VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); + return res; + } + + void* pMappedData = VMA_NULL; + if(map) + { + res = (*m_VulkanFunctions.vkMapMemory)( + m_hDevice, + hMemory, + 0, + VK_WHOLE_SIZE, + 0, + &pMappedData); + if(res < 0) + { + VMA_DEBUG_LOG(" vkMapMemory FAILED"); + FreeVulkanMemory(memTypeIndex, size, hMemory); + return res; + } + } + + *pAllocation = m_AllocationObjectAllocator.Allocate(isMappingAllowed); + (*pAllocation)->InitDedicatedAllocation(pool, memTypeIndex, hMemory, suballocType, pMappedData, size); + if (isUserDataString) + (*pAllocation)->SetName(this, (const char*)pUserData); + else + (*pAllocation)->SetUserData(this, pUserData); + m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size); + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) + { + FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); + } + + return VK_SUCCESS; +} + +void VmaAllocator_T::GetBufferMemoryRequirements( + VkBuffer hBuffer, + VkMemoryRequirements& memReq, + bool& requiresDedicatedAllocation, + bool& prefersDedicatedAllocation) const +{ +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR }; + memReqInfo.buffer = hBuffer; + + VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR }; + + VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR }; + VmaPnextChainPushFront(&memReq2, &memDedicatedReq); + + (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2); + + memReq = memReq2.memoryRequirements; + requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); + prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + } + else +#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + { + (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq); + requiresDedicatedAllocation = false; + prefersDedicatedAllocation = false; + } +} + +void VmaAllocator_T::GetImageMemoryRequirements( + VkImage hImage, + VkMemoryRequirements& memReq, + bool& requiresDedicatedAllocation, + bool& prefersDedicatedAllocation) const +{ +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR }; + memReqInfo.image = hImage; + + VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR }; + + VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR }; + VmaPnextChainPushFront(&memReq2, &memDedicatedReq); + + (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2); + + memReq = memReq2.memoryRequirements; + requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); + prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + } + else +#endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + { + (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq); + requiresDedicatedAllocation = false; + prefersDedicatedAllocation = false; + } +} + +VkResult VmaAllocator_T::FindMemoryTypeIndex( + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkFlags bufImgUsage, + uint32_t* pMemoryTypeIndex) const +{ + memoryTypeBits &= GetGlobalMemoryTypeBits(); + + if(pAllocationCreateInfo->memoryTypeBits != 0) + { + memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits; + } + + VkMemoryPropertyFlags requiredFlags = 0, preferredFlags = 0, notPreferredFlags = 0; + if(!FindMemoryPreferences( + IsIntegratedGpu(), + *pAllocationCreateInfo, + bufImgUsage, + requiredFlags, preferredFlags, notPreferredFlags)) + { + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + *pMemoryTypeIndex = UINT32_MAX; + uint32_t minCost = UINT32_MAX; + for(uint32_t memTypeIndex = 0, memTypeBit = 1; + memTypeIndex < GetMemoryTypeCount(); + ++memTypeIndex, memTypeBit <<= 1) + { + // This memory type is acceptable according to memoryTypeBits bitmask. + if((memTypeBit & memoryTypeBits) != 0) + { + const VkMemoryPropertyFlags currFlags = + m_MemProps.memoryTypes[memTypeIndex].propertyFlags; + // This memory type contains requiredFlags. + if((requiredFlags & ~currFlags) == 0) + { + // Calculate cost as number of bits from preferredFlags not present in this memory type. + uint32_t currCost = VMA_COUNT_BITS_SET(preferredFlags & ~currFlags) + + VMA_COUNT_BITS_SET(currFlags & notPreferredFlags); + // Remember memory type with lowest cost. + if(currCost < minCost) + { + *pMemoryTypeIndex = memTypeIndex; + if(currCost == 0) + { + return VK_SUCCESS; + } + minCost = currCost; + } + } + } + } + return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT; +} + +VkResult VmaAllocator_T::CalcMemTypeParams( + VmaAllocationCreateInfo& inoutCreateInfo, + uint32_t memTypeIndex, + VkDeviceSize size, + size_t allocationCount) +{ + // If memory type is not HOST_VISIBLE, disable MAPPED. + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && + (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + { + inoutCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; + } + + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && + (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0) + { + const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); + VmaBudget heapBudget = {}; + GetHeapBudgets(&heapBudget, heapIndex, 1); + if(heapBudget.usage + size * allocationCount > heapBudget.budget) + { + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + } + return VK_SUCCESS; +} + +VkResult VmaAllocator_T::CalcAllocationParams( + VmaAllocationCreateInfo& inoutCreateInfo, + bool dedicatedRequired, + bool dedicatedPreferred) +{ + VMA_ASSERT((inoutCreateInfo.flags & + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != + (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT) && + "Specifying both flags VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT and VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT is incorrect."); + VMA_ASSERT((((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT) == 0 || + (inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0)) && + "Specifying VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT requires also VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT."); + if(inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST) + { + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0) + { + VMA_ASSERT((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0 && + "When using VMA_ALLOCATION_CREATE_MAPPED_BIT and usage = VMA_MEMORY_USAGE_AUTO*, you must also specify VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT."); + } + } + + // If memory is lazily allocated, it should be always dedicated. + if(dedicatedRequired || + inoutCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED) + { + inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + } + + if(inoutCreateInfo.pool != VK_NULL_HANDLE) + { + if(inoutCreateInfo.pool->m_BlockVector.HasExplicitBlockSize() && + (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) + { + VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT while current custom pool doesn't support dedicated allocations."); + return VK_ERROR_FEATURE_NOT_PRESENT; + } + inoutCreateInfo.priority = inoutCreateInfo.pool->m_BlockVector.GetPriority(); + } + + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && + (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) + { + VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense."); + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + if(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY && + (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) + { + inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + } + + // Non-auto USAGE values imply HOST_ACCESS flags. + // And so does VMA_MEMORY_USAGE_UNKNOWN because it is used with custom pools. + // Which specific flag is used doesn't matter. They change things only when used with VMA_MEMORY_USAGE_AUTO*. + // Otherwise they just protect from assert on mapping. + if(inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO && + inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE && + inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO_PREFER_HOST) + { + if((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) == 0) + { + inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; + } + } + + return VK_SUCCESS; +} + +VkResult VmaAllocator_T::AllocateMemory( + const VkMemoryRequirements& vkMemReq, + bool requiresDedicatedAllocation, + bool prefersDedicatedAllocation, + VkBuffer dedicatedBuffer, + VkImage dedicatedImage, + VkFlags dedicatedBufferImageUsage, + const VmaAllocationCreateInfo& createInfo, + VmaSuballocationType suballocType, + size_t allocationCount, + VmaAllocation* pAllocations) +{ + memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount); + + VMA_ASSERT(VmaIsPow2(vkMemReq.alignment)); + + if(vkMemReq.size == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + + VmaAllocationCreateInfo createInfoFinal = createInfo; + VkResult res = CalcAllocationParams(createInfoFinal, requiresDedicatedAllocation, prefersDedicatedAllocation); + if(res != VK_SUCCESS) + return res; + + if(createInfoFinal.pool != VK_NULL_HANDLE) + { + VmaBlockVector& blockVector = createInfoFinal.pool->m_BlockVector; + return AllocateMemoryOfType( + createInfoFinal.pool, + vkMemReq.size, + vkMemReq.alignment, + prefersDedicatedAllocation, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + createInfoFinal, + blockVector.GetMemoryTypeIndex(), + suballocType, + createInfoFinal.pool->m_DedicatedAllocations, + blockVector, + allocationCount, + pAllocations); + } + else + { + // Bit mask of memory Vulkan types acceptable for this allocation. + uint32_t memoryTypeBits = vkMemReq.memoryTypeBits; + uint32_t memTypeIndex = UINT32_MAX; + res = FindMemoryTypeIndex(memoryTypeBits, &createInfoFinal, dedicatedBufferImageUsage, &memTypeIndex); + // Can't find any single memory type matching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT. + if(res != VK_SUCCESS) + return res; + do + { + VmaBlockVector* blockVector = m_pBlockVectors[memTypeIndex]; + VMA_ASSERT(blockVector && "Trying to use unsupported memory type!"); + res = AllocateMemoryOfType( + VK_NULL_HANDLE, + vkMemReq.size, + vkMemReq.alignment, + requiresDedicatedAllocation || prefersDedicatedAllocation, + dedicatedBuffer, + dedicatedImage, + dedicatedBufferImageUsage, + createInfoFinal, + memTypeIndex, + suballocType, + m_DedicatedAllocations[memTypeIndex], + *blockVector, + allocationCount, + pAllocations); + // Allocation succeeded + if(res == VK_SUCCESS) + return VK_SUCCESS; + + // Remove old memTypeIndex from list of possibilities. + memoryTypeBits &= ~(1u << memTypeIndex); + // Find alternative memTypeIndex. + res = FindMemoryTypeIndex(memoryTypeBits, &createInfoFinal, dedicatedBufferImageUsage, &memTypeIndex); + } while(res == VK_SUCCESS); + + // No other matching memory type index could be found. + // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once. + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } +} + +void VmaAllocator_T::FreeMemory( + size_t allocationCount, + const VmaAllocation* pAllocations) +{ + VMA_ASSERT(pAllocations); + + for(size_t allocIndex = allocationCount; allocIndex--; ) + { + VmaAllocation allocation = pAllocations[allocIndex]; + + if(allocation != VK_NULL_HANDLE) + { + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) + { + FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED); + } + + allocation->FreeName(this); + + switch(allocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaBlockVector* pBlockVector = VMA_NULL; + VmaPool hPool = allocation->GetParentPool(); + if(hPool != VK_NULL_HANDLE) + { + pBlockVector = &hPool->m_BlockVector; + } + else + { + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + pBlockVector = m_pBlockVectors[memTypeIndex]; + VMA_ASSERT(pBlockVector && "Trying to free memory of unsupported type!"); + } + pBlockVector->Free(allocation); + } + break; + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + FreeDedicatedMemory(allocation); + break; + default: + VMA_ASSERT(0); + } + } + } +} + +void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) +{ + // Initialize. + VmaClearDetailedStatistics(pStats->total); + for(uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) + VmaClearDetailedStatistics(pStats->memoryType[i]); + for(uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) + VmaClearDetailedStatistics(pStats->memoryHeap[i]); + + // Process default pools. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; + if (pBlockVector != VMA_NULL) + pBlockVector->AddDetailedStatistics(pStats->memoryType[memTypeIndex]); + } + + // Process custom pools. + { + VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); + for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) + { + VmaBlockVector& blockVector = pool->m_BlockVector; + const uint32_t memTypeIndex = blockVector.GetMemoryTypeIndex(); + blockVector.AddDetailedStatistics(pStats->memoryType[memTypeIndex]); + pool->m_DedicatedAllocations.AddDetailedStatistics(pStats->memoryType[memTypeIndex]); + } + } + + // Process dedicated allocations. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + m_DedicatedAllocations[memTypeIndex].AddDetailedStatistics(pStats->memoryType[memTypeIndex]); + } + + // Sum from memory types to memory heaps. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + const uint32_t memHeapIndex = m_MemProps.memoryTypes[memTypeIndex].heapIndex; + VmaAddDetailedStatistics(pStats->memoryHeap[memHeapIndex], pStats->memoryType[memTypeIndex]); + } + + // Sum from memory heaps to total. + for(uint32_t memHeapIndex = 0; memHeapIndex < GetMemoryHeapCount(); ++memHeapIndex) + VmaAddDetailedStatistics(pStats->total, pStats->memoryHeap[memHeapIndex]); + + VMA_ASSERT(pStats->total.statistics.allocationCount == 0 || + pStats->total.allocationSizeMax >= pStats->total.allocationSizeMin); + VMA_ASSERT(pStats->total.unusedRangeCount == 0 || + pStats->total.unusedRangeSizeMax >= pStats->total.unusedRangeSizeMin); +} + +void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, uint32_t heapCount) +{ +#if VMA_MEMORY_BUDGET + if(m_UseExtMemoryBudget) + { + if(m_Budget.m_OperationsSinceBudgetFetch < 30) + { + VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex); + for(uint32_t i = 0; i < heapCount; ++i, ++outBudgets) + { + const uint32_t heapIndex = firstHeap + i; + + outBudgets->statistics.blockCount = m_Budget.m_BlockCount[heapIndex]; + outBudgets->statistics.allocationCount = m_Budget.m_AllocationCount[heapIndex]; + outBudgets->statistics.blockBytes = m_Budget.m_BlockBytes[heapIndex]; + outBudgets->statistics.allocationBytes = m_Budget.m_AllocationBytes[heapIndex]; + + if(m_Budget.m_VulkanUsage[heapIndex] + outBudgets->statistics.blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]) + { + outBudgets->usage = m_Budget.m_VulkanUsage[heapIndex] + + outBudgets->statistics.blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; + } + else + { + outBudgets->usage = 0; + } + + // Have to take MIN with heap size because explicit HeapSizeLimit is included in it. + outBudgets->budget = VMA_MIN( + m_Budget.m_VulkanBudget[heapIndex], m_MemProps.memoryHeaps[heapIndex].size); + } + } + else + { + UpdateVulkanBudget(); // Outside of mutex lock + GetHeapBudgets(outBudgets, firstHeap, heapCount); // Recursion + } + } + else +#endif + { + for(uint32_t i = 0; i < heapCount; ++i, ++outBudgets) + { + const uint32_t heapIndex = firstHeap + i; + + outBudgets->statistics.blockCount = m_Budget.m_BlockCount[heapIndex]; + outBudgets->statistics.allocationCount = m_Budget.m_AllocationCount[heapIndex]; + outBudgets->statistics.blockBytes = m_Budget.m_BlockBytes[heapIndex]; + outBudgets->statistics.allocationBytes = m_Budget.m_AllocationBytes[heapIndex]; + + outBudgets->usage = outBudgets->statistics.blockBytes; + outBudgets->budget = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics. + } + } +} + +void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo) +{ + pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex(); + pAllocationInfo->deviceMemory = hAllocation->GetMemory(); + pAllocationInfo->offset = hAllocation->GetOffset(); + pAllocationInfo->size = hAllocation->GetSize(); + pAllocationInfo->pMappedData = hAllocation->GetMappedData(); + pAllocationInfo->pUserData = hAllocation->GetUserData(); + pAllocationInfo->pName = hAllocation->GetName(); +} + +VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool) +{ + VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags); + + VmaPoolCreateInfo newCreateInfo = *pCreateInfo; + + // Protection against uninitialized new structure member. If garbage data are left there, this pointer dereference would crash. + if(pCreateInfo->pMemoryAllocateNext) + { + VMA_ASSERT(((const VkBaseInStructure*)pCreateInfo->pMemoryAllocateNext)->sType != 0); + } + + if(newCreateInfo.maxBlockCount == 0) + { + newCreateInfo.maxBlockCount = SIZE_MAX; + } + if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + // Memory type index out of range or forbidden. + if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() || + ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0) + { + return VK_ERROR_FEATURE_NOT_PRESENT; + } + if(newCreateInfo.minAllocationAlignment > 0) + { + VMA_ASSERT(VmaIsPow2(newCreateInfo.minAllocationAlignment)); + } + + const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex); + + *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize); + + VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks(); + if(res != VK_SUCCESS) + { + vma_delete(this, *pPool); + *pPool = VMA_NULL; + return res; + } + + // Add to m_Pools. + { + VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex); + (*pPool)->SetId(m_NextPoolId++); + m_Pools.PushBack(*pPool); + } + + return VK_SUCCESS; +} + +void VmaAllocator_T::DestroyPool(VmaPool pool) +{ + // Remove from m_Pools. + { + VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex); + m_Pools.Remove(pool); + } + + vma_delete(this, pool); +} + +void VmaAllocator_T::GetPoolStatistics(VmaPool pool, VmaStatistics* pPoolStats) +{ + VmaClearStatistics(*pPoolStats); + pool->m_BlockVector.AddStatistics(*pPoolStats); + pool->m_DedicatedAllocations.AddStatistics(*pPoolStats); +} + +void VmaAllocator_T::CalculatePoolStatistics(VmaPool pool, VmaDetailedStatistics* pPoolStats) +{ + VmaClearDetailedStatistics(*pPoolStats); + pool->m_BlockVector.AddDetailedStatistics(*pPoolStats); + pool->m_DedicatedAllocations.AddDetailedStatistics(*pPoolStats); +} + +void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex) +{ + m_CurrentFrameIndex.store(frameIndex); + +#if VMA_MEMORY_BUDGET + if(m_UseExtMemoryBudget) + { + UpdateVulkanBudget(); + } +#endif // #if VMA_MEMORY_BUDGET +} + +VkResult VmaAllocator_T::CheckPoolCorruption(VmaPool hPool) +{ + return hPool->m_BlockVector.CheckCorruption(); +} + +VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits) +{ + VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT; + + // Process default pools. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; + if(pBlockVector != VMA_NULL) + { + VkResult localRes = pBlockVector->CheckCorruption(); + switch(localRes) + { + case VK_ERROR_FEATURE_NOT_PRESENT: + break; + case VK_SUCCESS: + finalRes = VK_SUCCESS; + break; + default: + return localRes; + } + } + } + + // Process custom pools. + { + VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); + for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) + { + if(((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0) + { + VkResult localRes = pool->m_BlockVector.CheckCorruption(); + switch(localRes) + { + case VK_ERROR_FEATURE_NOT_PRESENT: + break; + case VK_SUCCESS: + finalRes = VK_SUCCESS; + break; + default: + return localRes; + } + } + } + } + + return finalRes; +} + +VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory) +{ + AtomicTransactionalIncrement deviceMemoryCountIncrement; + const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount); +#if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT + if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount) + { + return VK_ERROR_TOO_MANY_OBJECTS; + } +#endif + + const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex); + + // HeapSizeLimit is in effect for this heap. + if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0) + { + const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; + VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex]; + for(;;) + { + const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize; + if(blockBytesAfterAllocation > heapSize) + { + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation)) + { + break; + } + } + } + else + { + m_Budget.m_BlockBytes[heapIndex] += pAllocateInfo->allocationSize; + } + ++m_Budget.m_BlockCount[heapIndex]; + + // VULKAN CALL vkAllocateMemory. + VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory); + + if(res == VK_SUCCESS) + { +#if VMA_MEMORY_BUDGET + ++m_Budget.m_OperationsSinceBudgetFetch; +#endif + + // Informative callback. + if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) + { + (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData); + } + + deviceMemoryCountIncrement.Commit(); + } + else + { + --m_Budget.m_BlockCount[heapIndex]; + m_Budget.m_BlockBytes[heapIndex] -= pAllocateInfo->allocationSize; + } + + return res; +} + +void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory) +{ + // Informative callback. + if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL) + { + (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData); + } + + // VULKAN CALL vkFreeMemory. + (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks()); + + const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memoryType); + --m_Budget.m_BlockCount[heapIndex]; + m_Budget.m_BlockBytes[heapIndex] -= size; + + --m_DeviceMemoryCount; +} + +VkResult VmaAllocator_T::BindVulkanBuffer( + VkDeviceMemory memory, + VkDeviceSize memoryOffset, + VkBuffer buffer, + const void* pNext) +{ + if(pNext != VMA_NULL) + { +#if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 + if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && + m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL) + { + VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR }; + bindBufferMemoryInfo.pNext = pNext; + bindBufferMemoryInfo.buffer = buffer; + bindBufferMemoryInfo.memory = memory; + bindBufferMemoryInfo.memoryOffset = memoryOffset; + return (*m_VulkanFunctions.vkBindBufferMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo); + } + else +#endif // #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 + { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + } + else + { + return (*m_VulkanFunctions.vkBindBufferMemory)(m_hDevice, buffer, memory, memoryOffset); + } +} + +VkResult VmaAllocator_T::BindVulkanImage( + VkDeviceMemory memory, + VkDeviceSize memoryOffset, + VkImage image, + const void* pNext) +{ + if(pNext != VMA_NULL) + { +#if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 + if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && + m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL) + { + VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR }; + bindBufferMemoryInfo.pNext = pNext; + bindBufferMemoryInfo.image = image; + bindBufferMemoryInfo.memory = memory; + bindBufferMemoryInfo.memoryOffset = memoryOffset; + return (*m_VulkanFunctions.vkBindImageMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo); + } + else +#endif // #if VMA_BIND_MEMORY2 + { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + } + else + { + return (*m_VulkanFunctions.vkBindImageMemory)(m_hDevice, image, memory, memoryOffset); + } +} + +VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) +{ + switch(hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + char *pBytes = VMA_NULL; + VkResult res = pBlock->Map(this, 1, (void**)&pBytes); + if(res == VK_SUCCESS) + { + *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset(); + hAllocation->BlockAllocMap(); + } + return res; + } + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + return hAllocation->DedicatedAllocMap(this, ppData); + default: + VMA_ASSERT(0); + return VK_ERROR_MEMORY_MAP_FAILED; + } +} + +void VmaAllocator_T::Unmap(VmaAllocation hAllocation) +{ + switch(hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + hAllocation->BlockAllocUnmap(); + pBlock->Unmap(this, 1); + } + break; + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + hAllocation->DedicatedAllocUnmap(this); + break; + default: + VMA_ASSERT(0); + } +} + +VkResult VmaAllocator_T::BindBufferMemory( + VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkBuffer hBuffer, + const void* pNext) +{ + VkResult res = VK_SUCCESS; + switch(hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext); + break; + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + VMA_ASSERT(pBlock && "Binding buffer to allocation that doesn't belong to any block."); + res = pBlock->BindBufferMemory(this, hAllocation, allocationLocalOffset, hBuffer, pNext); + break; + } + default: + VMA_ASSERT(0); + } + return res; +} + +VkResult VmaAllocator_T::BindImageMemory( + VmaAllocation hAllocation, + VkDeviceSize allocationLocalOffset, + VkImage hImage, + const void* pNext) +{ + VkResult res = VK_SUCCESS; + switch(hAllocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext); + break; + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock(); + VMA_ASSERT(pBlock && "Binding image to allocation that doesn't belong to any block."); + res = pBlock->BindImageMemory(this, hAllocation, allocationLocalOffset, hImage, pNext); + break; + } + default: + VMA_ASSERT(0); + } + return res; +} + +VkResult VmaAllocator_T::FlushOrInvalidateAllocation( + VmaAllocation hAllocation, + VkDeviceSize offset, VkDeviceSize size, + VMA_CACHE_OPERATION op) +{ + VkResult res = VK_SUCCESS; + + VkMappedMemoryRange memRange = {}; + if(GetFlushOrInvalidateRange(hAllocation, offset, size, memRange)) + { + switch(op) + { + case VMA_CACHE_FLUSH: + res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange); + break; + case VMA_CACHE_INVALIDATE: + res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, 1, &memRange); + break; + default: + VMA_ASSERT(0); + } + } + // else: Just ignore this call. + return res; +} + +VkResult VmaAllocator_T::FlushOrInvalidateAllocations( + uint32_t allocationCount, + const VmaAllocation* allocations, + const VkDeviceSize* offsets, const VkDeviceSize* sizes, + VMA_CACHE_OPERATION op) +{ + typedef VmaStlAllocator RangeAllocator; + typedef VmaSmallVector RangeVector; + RangeVector ranges = RangeVector(RangeAllocator(GetAllocationCallbacks())); + + for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + { + const VmaAllocation alloc = allocations[allocIndex]; + const VkDeviceSize offset = offsets != VMA_NULL ? offsets[allocIndex] : 0; + const VkDeviceSize size = sizes != VMA_NULL ? sizes[allocIndex] : VK_WHOLE_SIZE; + VkMappedMemoryRange newRange; + if(GetFlushOrInvalidateRange(alloc, offset, size, newRange)) + { + ranges.push_back(newRange); + } + } + + VkResult res = VK_SUCCESS; + if(!ranges.empty()) + { + switch(op) + { + case VMA_CACHE_FLUSH: + res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data()); + break; + case VMA_CACHE_INVALIDATE: + res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data()); + break; + default: + VMA_ASSERT(0); + } + } + // else: Just ignore this call. + return res; +} + +void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation) +{ + VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); + + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + VmaPool parentPool = allocation->GetParentPool(); + if(parentPool == VK_NULL_HANDLE) + { + // Default pool + m_DedicatedAllocations[memTypeIndex].Unregister(allocation); + } + else + { + // Custom pool + parentPool->m_DedicatedAllocations.Unregister(allocation); + } + + VkDeviceMemory hMemory = allocation->GetMemory(); + + /* + There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory + before vkFreeMemory. + + if(allocation->GetMappedData() != VMA_NULL) + { + (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory); + } + */ + + FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory); + + m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize()); + m_AllocationObjectAllocator.Free(allocation); + + VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex); +} + +uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const +{ + VkBufferCreateInfo dummyBufCreateInfo; + VmaFillGpuDefragmentationBufferCreateInfo(dummyBufCreateInfo); + + uint32_t memoryTypeBits = 0; + + // Create buffer. + VkBuffer buf = VK_NULL_HANDLE; + VkResult res = (*GetVulkanFunctions().vkCreateBuffer)( + m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf); + if(res == VK_SUCCESS) + { + // Query for supported memory types. + VkMemoryRequirements memReq; + (*GetVulkanFunctions().vkGetBufferMemoryRequirements)(m_hDevice, buf, &memReq); + memoryTypeBits = memReq.memoryTypeBits; + + // Destroy buffer. + (*GetVulkanFunctions().vkDestroyBuffer)(m_hDevice, buf, GetAllocationCallbacks()); + } + + return memoryTypeBits; +} + +uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const +{ + // Make sure memory information is already fetched. + VMA_ASSERT(GetMemoryTypeCount() > 0); + + uint32_t memoryTypeBits = UINT32_MAX; + + if(!m_UseAmdDeviceCoherentMemory) + { + // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD. + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0) + { + memoryTypeBits &= ~(1u << memTypeIndex); + } + } + } + + return memoryTypeBits; +} + +bool VmaAllocator_T::GetFlushOrInvalidateRange( + VmaAllocation allocation, + VkDeviceSize offset, VkDeviceSize size, + VkMappedMemoryRange& outRange) const +{ + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex)) + { + const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize; + const VkDeviceSize allocationSize = allocation->GetSize(); + VMA_ASSERT(offset <= allocationSize); + + outRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + outRange.pNext = VMA_NULL; + outRange.memory = allocation->GetMemory(); + + switch(allocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); + if(size == VK_WHOLE_SIZE) + { + outRange.size = allocationSize - outRange.offset; + } + else + { + VMA_ASSERT(offset + size <= allocationSize); + outRange.size = VMA_MIN( + VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize), + allocationSize - outRange.offset); + } + break; + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + // 1. Still within this allocation. + outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); + if(size == VK_WHOLE_SIZE) + { + size = allocationSize - offset; + } + else + { + VMA_ASSERT(offset + size <= allocationSize); + } + outRange.size = VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize); + + // 2. Adjust to whole block. + const VkDeviceSize allocationOffset = allocation->GetOffset(); + VMA_ASSERT(allocationOffset % nonCoherentAtomSize == 0); + const VkDeviceSize blockSize = allocation->GetBlock()->m_pMetadata->GetSize(); + outRange.offset += allocationOffset; + outRange.size = VMA_MIN(outRange.size, blockSize - outRange.offset); + + break; + } + default: + VMA_ASSERT(0); + } + return true; + } + return false; +} + +#if VMA_MEMORY_BUDGET +void VmaAllocator_T::UpdateVulkanBudget() +{ + VMA_ASSERT(m_UseExtMemoryBudget); + + VkPhysicalDeviceMemoryProperties2KHR memProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR }; + + VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT }; + VmaPnextChainPushFront(&memProps, &budgetProps); + + GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties2KHR(m_PhysicalDevice, &memProps); + + { + VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex); + + for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) + { + m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex]; + m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex]; + m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load(); + + // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size. + if(m_Budget.m_VulkanBudget[heapIndex] == 0) + { + m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics. + } + else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size) + { + m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size; + } + if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0) + { + m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; + } + } + m_Budget.m_OperationsSinceBudgetFetch = 0; + } +} +#endif // VMA_MEMORY_BUDGET + +void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern) +{ + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS && + hAllocation->IsMappingAllowed() && + (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) + { + void* pData = VMA_NULL; + VkResult res = Map(hAllocation, &pData); + if(res == VK_SUCCESS) + { + memset(pData, (int)pattern, (size_t)hAllocation->GetSize()); + FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH); + Unmap(hAllocation); + } + else + { + VMA_ASSERT(0 && "VMA_DEBUG_INITIALIZE_ALLOCATIONS is enabled, but couldn't map memory to fill allocation."); + } + } +} + +uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits() +{ + uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load(); + if(memoryTypeBits == UINT32_MAX) + { + memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits(); + m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits); + } + return memoryTypeBits; +} + +#if VMA_STATS_STRING_ENABLED +void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json) +{ + json.WriteString("DefaultPools"); + json.BeginObject(); + { + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + VmaBlockVector* pBlockVector = m_pBlockVectors[memTypeIndex]; + VmaDedicatedAllocationList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex]; + if (pBlockVector != VMA_NULL) + { + json.BeginString("Type "); + json.ContinueString(memTypeIndex); + json.EndString(); + json.BeginObject(); + { + json.WriteString("PreferredBlockSize"); + json.WriteNumber(pBlockVector->GetPreferredBlockSize()); + + json.WriteString("Blocks"); + pBlockVector->PrintDetailedMap(json); + + json.WriteString("DedicatedAllocations"); + dedicatedAllocList.BuildStatsString(json); + } + json.EndObject(); + } + } + } + json.EndObject(); + + json.WriteString("CustomPools"); + json.BeginObject(); + { + VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); + if (!m_Pools.IsEmpty()) + { + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + { + bool displayType = true; + size_t index = 0; + for (VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) + { + VmaBlockVector& blockVector = pool->m_BlockVector; + if (blockVector.GetMemoryTypeIndex() == memTypeIndex) + { + if (displayType) + { + json.BeginString("Type "); + json.ContinueString(memTypeIndex); + json.EndString(); + json.BeginArray(); + displayType = false; + } + + json.BeginObject(); + { + json.WriteString("Name"); + json.BeginString(); + json.ContinueString_Size(index++); + if (pool->GetName()) + { + json.ContinueString(" - "); + json.ContinueString(pool->GetName()); + } + json.EndString(); + + json.WriteString("PreferredBlockSize"); + json.WriteNumber(blockVector.GetPreferredBlockSize()); + + json.WriteString("Blocks"); + blockVector.PrintDetailedMap(json); + + json.WriteString("DedicatedAllocations"); + pool->m_DedicatedAllocations.BuildStatsString(json); + } + json.EndObject(); + } + } + + if (!displayType) + json.EndArray(); + } + } + } + json.EndObject(); +} +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_ALLOCATOR_T_FUNCTIONS + + +#ifndef _VMA_PUBLIC_INTERFACE +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( + const VmaAllocatorCreateInfo* pCreateInfo, + VmaAllocator* pAllocator) +{ + VMA_ASSERT(pCreateInfo && pAllocator); + VMA_ASSERT(pCreateInfo->vulkanApiVersion == 0 || + (VK_VERSION_MAJOR(pCreateInfo->vulkanApiVersion) == 1 && VK_VERSION_MINOR(pCreateInfo->vulkanApiVersion) <= 3)); + VMA_DEBUG_LOG("vmaCreateAllocator"); + *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo); + VkResult result = (*pAllocator)->Init(pCreateInfo); + if(result < 0) + { + vma_delete(pCreateInfo->pAllocationCallbacks, *pAllocator); + *pAllocator = VK_NULL_HANDLE; + } + return result; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( + VmaAllocator allocator) +{ + if(allocator != VK_NULL_HANDLE) + { + VMA_DEBUG_LOG("vmaDestroyAllocator"); + VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks; // Have to copy the callbacks when destroying. + vma_delete(&allocationCallbacks, allocator); + } +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaAllocatorInfo* pAllocatorInfo) +{ + VMA_ASSERT(allocator && pAllocatorInfo); + pAllocatorInfo->instance = allocator->m_hInstance; + pAllocatorInfo->physicalDevice = allocator->GetPhysicalDevice(); + pAllocatorInfo->device = allocator->m_hDevice; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( + VmaAllocator allocator, + const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties) +{ + VMA_ASSERT(allocator && ppPhysicalDeviceProperties); + *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( + VmaAllocator allocator, + const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties) +{ + VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties); + *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( + VmaAllocator allocator, + uint32_t memoryTypeIndex, + VkMemoryPropertyFlags* pFlags) +{ + VMA_ASSERT(allocator && pFlags); + VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount()); + *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( + VmaAllocator allocator, + uint32_t frameIndex) +{ + VMA_ASSERT(allocator); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->SetCurrentFrameIndex(frameIndex); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( + VmaAllocator allocator, + VmaTotalStatistics* pStats) +{ + VMA_ASSERT(allocator && pStats); + VMA_DEBUG_GLOBAL_MUTEX_LOCK + allocator->CalculateStatistics(pStats); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( + VmaAllocator allocator, + VmaBudget* pBudgets) +{ + VMA_ASSERT(allocator && pBudgets); + VMA_DEBUG_GLOBAL_MUTEX_LOCK + allocator->GetHeapBudgets(pBudgets, 0, allocator->GetMemoryHeapCount()); +} + +#if VMA_STATS_STRING_ENABLED + +VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( + VmaAllocator allocator, + char** ppStatsString, + VkBool32 detailedMap) +{ + VMA_ASSERT(allocator && ppStatsString); + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VmaStringBuilder sb(allocator->GetAllocationCallbacks()); + { + VmaBudget budgets[VK_MAX_MEMORY_HEAPS]; + allocator->GetHeapBudgets(budgets, 0, allocator->GetMemoryHeapCount()); + + VmaTotalStatistics stats; + allocator->CalculateStatistics(&stats); + + VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb); + json.BeginObject(); + { + json.WriteString("General"); + json.BeginObject(); + { + const VkPhysicalDeviceProperties& deviceProperties = allocator->m_PhysicalDeviceProperties; + const VkPhysicalDeviceMemoryProperties& memoryProperties = allocator->m_MemProps; + + json.WriteString("API"); + json.WriteString("Vulkan"); + + json.WriteString("apiVersion"); + json.BeginString(); + json.ContinueString(VK_API_VERSION_MAJOR(deviceProperties.apiVersion)); + json.ContinueString("."); + json.ContinueString(VK_API_VERSION_MINOR(deviceProperties.apiVersion)); + json.ContinueString("."); + json.ContinueString(VK_API_VERSION_PATCH(deviceProperties.apiVersion)); + json.EndString(); + + json.WriteString("GPU"); + json.WriteString(deviceProperties.deviceName); + json.WriteString("deviceType"); + json.WriteNumber(static_cast(deviceProperties.deviceType)); + + json.WriteString("maxMemoryAllocationCount"); + json.WriteNumber(deviceProperties.limits.maxMemoryAllocationCount); + json.WriteString("bufferImageGranularity"); + json.WriteNumber(deviceProperties.limits.bufferImageGranularity); + json.WriteString("nonCoherentAtomSize"); + json.WriteNumber(deviceProperties.limits.nonCoherentAtomSize); + + json.WriteString("memoryHeapCount"); + json.WriteNumber(memoryProperties.memoryHeapCount); + json.WriteString("memoryTypeCount"); + json.WriteNumber(memoryProperties.memoryTypeCount); + } + json.EndObject(); + } + { + json.WriteString("Total"); + VmaPrintDetailedStatistics(json, stats.total); + } + { + json.WriteString("MemoryInfo"); + json.BeginObject(); + { + for (uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex) + { + json.BeginString("Heap "); + json.ContinueString(heapIndex); + json.EndString(); + json.BeginObject(); + { + const VkMemoryHeap& heapInfo = allocator->m_MemProps.memoryHeaps[heapIndex]; + json.WriteString("Flags"); + json.BeginArray(true); + { + if (heapInfo.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) + json.WriteString("DEVICE_LOCAL"); + #if VMA_VULKAN_VERSION >= 1001000 + if (heapInfo.flags & VK_MEMORY_HEAP_MULTI_INSTANCE_BIT) + json.WriteString("MULTI_INSTANCE"); + #endif + + VkMemoryHeapFlags flags = heapInfo.flags & + ~(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT + #if VMA_VULKAN_VERSION >= 1001000 + | VK_MEMORY_HEAP_MULTI_INSTANCE_BIT + #endif + ); + if (flags != 0) + json.WriteNumber(flags); + } + json.EndArray(); + + json.WriteString("Size"); + json.WriteNumber(heapInfo.size); + + json.WriteString("Budget"); + json.BeginObject(); + { + json.WriteString("BudgetBytes"); + json.WriteNumber(budgets[heapIndex].budget); + json.WriteString("UsageBytes"); + json.WriteNumber(budgets[heapIndex].usage); + } + json.EndObject(); + + json.WriteString("Stats"); + VmaPrintDetailedStatistics(json, stats.memoryHeap[heapIndex]); + + json.WriteString("MemoryPools"); + json.BeginObject(); + { + for (uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex) + { + if (allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex) + { + json.BeginString("Type "); + json.ContinueString(typeIndex); + json.EndString(); + json.BeginObject(); + { + json.WriteString("Flags"); + json.BeginArray(true); + { + VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags; + if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + json.WriteString("DEVICE_LOCAL"); + if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + json.WriteString("HOST_VISIBLE"); + if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) + json.WriteString("HOST_COHERENT"); + if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) + json.WriteString("HOST_CACHED"); + if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) + json.WriteString("LAZILY_ALLOCATED"); + #if VMA_VULKAN_VERSION >= 1001000 + if (flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) + json.WriteString("PROTECTED"); + #endif + #if VK_AMD_device_coherent_memory + if (flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) + json.WriteString("DEVICE_COHERENT_AMD"); + if (flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) + json.WriteString("DEVICE_UNCACHED_AMD"); + #endif + + flags &= ~(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT + #if VMA_VULKAN_VERSION >= 1001000 + | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT + #endif + #if VK_AMD_device_coherent_memory + | VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY + | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY + #endif + | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + | VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + if (flags != 0) + json.WriteNumber(flags); + } + json.EndArray(); + + json.WriteString("Stats"); + VmaPrintDetailedStatistics(json, stats.memoryType[typeIndex]); + } + json.EndObject(); + } + } + + } + json.EndObject(); + } + json.EndObject(); + } + } + json.EndObject(); + } + + if (detailedMap == VK_TRUE) + allocator->PrintDetailedMap(json); + + json.EndObject(); + } + + *ppStatsString = VmaCreateStringCopy(allocator->GetAllocationCallbacks(), sb.GetData(), sb.GetLength()); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( + VmaAllocator allocator, + char* pStatsString) +{ + if(pStatsString != VMA_NULL) + { + VMA_ASSERT(allocator); + VmaFreeString(allocator->GetAllocationCallbacks(), pStatsString); + } +} + +#endif // VMA_STATS_STRING_ENABLED + +/* +This function is not protected by any mutex because it just reads immutable data. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( + VmaAllocator allocator, + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + uint32_t* pMemoryTypeIndex) +{ + VMA_ASSERT(allocator != VK_NULL_HANDLE); + VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); + VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); + + return allocator->FindMemoryTypeIndex(memoryTypeBits, pAllocationCreateInfo, UINT32_MAX, pMemoryTypeIndex); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( + VmaAllocator allocator, + const VkBufferCreateInfo* pBufferCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + uint32_t* pMemoryTypeIndex) +{ + VMA_ASSERT(allocator != VK_NULL_HANDLE); + VMA_ASSERT(pBufferCreateInfo != VMA_NULL); + VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); + VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); + + const VkDevice hDev = allocator->m_hDevice; + const VmaVulkanFunctions* funcs = &allocator->GetVulkanFunctions(); + VkResult res; + +#if VMA_VULKAN_VERSION >= 1003000 + if(funcs->vkGetDeviceBufferMemoryRequirements) + { + // Can query straight from VkBufferCreateInfo :) + VkDeviceBufferMemoryRequirements devBufMemReq = {VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS}; + devBufMemReq.pCreateInfo = pBufferCreateInfo; + + VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; + (*funcs->vkGetDeviceBufferMemoryRequirements)(hDev, &devBufMemReq, &memReq); + + res = allocator->FindMemoryTypeIndex( + memReq.memoryRequirements.memoryTypeBits, pAllocationCreateInfo, pBufferCreateInfo->usage, pMemoryTypeIndex); + } + else +#endif // #if VMA_VULKAN_VERSION >= 1003000 + { + // Must create a dummy buffer to query :( + VkBuffer hBuffer = VK_NULL_HANDLE; + res = funcs->vkCreateBuffer( + hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer); + if(res == VK_SUCCESS) + { + VkMemoryRequirements memReq = {}; + funcs->vkGetBufferMemoryRequirements(hDev, hBuffer, &memReq); + + res = allocator->FindMemoryTypeIndex( + memReq.memoryTypeBits, pAllocationCreateInfo, pBufferCreateInfo->usage, pMemoryTypeIndex); + + funcs->vkDestroyBuffer( + hDev, hBuffer, allocator->GetAllocationCallbacks()); + } + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( + VmaAllocator allocator, + const VkImageCreateInfo* pImageCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + uint32_t* pMemoryTypeIndex) +{ + VMA_ASSERT(allocator != VK_NULL_HANDLE); + VMA_ASSERT(pImageCreateInfo != VMA_NULL); + VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); + VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); + + const VkDevice hDev = allocator->m_hDevice; + const VmaVulkanFunctions* funcs = &allocator->GetVulkanFunctions(); + VkResult res; + +#if VMA_VULKAN_VERSION >= 1003000 + if(funcs->vkGetDeviceImageMemoryRequirements) + { + // Can query straight from VkImageCreateInfo :) + VkDeviceImageMemoryRequirements devImgMemReq = {VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS}; + devImgMemReq.pCreateInfo = pImageCreateInfo; + VMA_ASSERT(pImageCreateInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT_COPY && (pImageCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT_COPY) == 0 && + "Cannot use this VkImageCreateInfo with vmaFindMemoryTypeIndexForImageInfo as I don't know what to pass as VkDeviceImageMemoryRequirements::planeAspect."); + + VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; + (*funcs->vkGetDeviceImageMemoryRequirements)(hDev, &devImgMemReq, &memReq); + + res = allocator->FindMemoryTypeIndex( + memReq.memoryRequirements.memoryTypeBits, pAllocationCreateInfo, pImageCreateInfo->usage, pMemoryTypeIndex); + } + else +#endif // #if VMA_VULKAN_VERSION >= 1003000 + { + // Must create a dummy image to query :( + VkImage hImage = VK_NULL_HANDLE; + res = funcs->vkCreateImage( + hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage); + if(res == VK_SUCCESS) + { + VkMemoryRequirements memReq = {}; + funcs->vkGetImageMemoryRequirements(hDev, hImage, &memReq); + + res = allocator->FindMemoryTypeIndex( + memReq.memoryTypeBits, pAllocationCreateInfo, pImageCreateInfo->usage, pMemoryTypeIndex); + + funcs->vkDestroyImage( + hDev, hImage, allocator->GetAllocationCallbacks()); + } + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( + VmaAllocator allocator, + const VmaPoolCreateInfo* pCreateInfo, + VmaPool* pPool) +{ + VMA_ASSERT(allocator && pCreateInfo && pPool); + + VMA_DEBUG_LOG("vmaCreatePool"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->CreatePool(pCreateInfo, pPool); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( + VmaAllocator allocator, + VmaPool pool) +{ + VMA_ASSERT(allocator); + + if(pool == VK_NULL_HANDLE) + { + return; + } + + VMA_DEBUG_LOG("vmaDestroyPool"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->DestroyPool(pool); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( + VmaAllocator allocator, + VmaPool pool, + VmaStatistics* pPoolStats) +{ + VMA_ASSERT(allocator && pool && pPoolStats); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->GetPoolStatistics(pool, pPoolStats); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( + VmaAllocator allocator, + VmaPool pool, + VmaDetailedStatistics* pPoolStats) +{ + VMA_ASSERT(allocator && pool && pPoolStats); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->CalculatePoolStatistics(pool, pPoolStats); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool) +{ + VMA_ASSERT(allocator && pool); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VMA_DEBUG_LOG("vmaCheckPoolCorruption"); + + return allocator->CheckPoolCorruption(pool); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( + VmaAllocator allocator, + VmaPool pool, + const char** ppName) +{ + VMA_ASSERT(allocator && pool && ppName); + + VMA_DEBUG_LOG("vmaGetPoolName"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *ppName = pool->GetName(); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( + VmaAllocator allocator, + VmaPool pool, + const char* pName) +{ + VMA_ASSERT(allocator && pool); + + VMA_DEBUG_LOG("vmaSetPoolName"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + pool->SetName(pName); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( + VmaAllocator allocator, + const VkMemoryRequirements* pVkMemoryRequirements, + const VmaAllocationCreateInfo* pCreateInfo, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation); + + VMA_DEBUG_LOG("vmaAllocateMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VkResult result = allocator->AllocateMemory( + *pVkMemoryRequirements, + false, // requiresDedicatedAllocation + false, // prefersDedicatedAllocation + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + UINT32_MAX, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_UNKNOWN, + 1, // allocationCount + pAllocation); + + if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return result; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( + VmaAllocator allocator, + const VkMemoryRequirements* pVkMemoryRequirements, + const VmaAllocationCreateInfo* pCreateInfo, + size_t allocationCount, + VmaAllocation* pAllocations, + VmaAllocationInfo* pAllocationInfo) +{ + if(allocationCount == 0) + { + return VK_SUCCESS; + } + + VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations); + + VMA_DEBUG_LOG("vmaAllocateMemoryPages"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VkResult result = allocator->AllocateMemory( + *pVkMemoryRequirements, + false, // requiresDedicatedAllocation + false, // prefersDedicatedAllocation + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + UINT32_MAX, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_UNKNOWN, + allocationCount, + pAllocations); + + if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) + { + for(size_t i = 0; i < allocationCount; ++i) + { + allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i); + } + } + + return result; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( + VmaAllocator allocator, + VkBuffer buffer, + const VmaAllocationCreateInfo* pCreateInfo, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation); + + VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetBufferMemoryRequirements(buffer, vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation); + + VkResult result = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + buffer, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + UINT32_MAX, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_BUFFER, + 1, // allocationCount + pAllocation); + + if(pAllocationInfo && result == VK_SUCCESS) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return result; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( + VmaAllocator allocator, + VkImage image, + const VmaAllocationCreateInfo* pCreateInfo, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation); + + VMA_DEBUG_LOG("vmaAllocateMemoryForImage"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetImageMemoryRequirements(image, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + + VkResult result = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + VK_NULL_HANDLE, // dedicatedBuffer + image, // dedicatedImage + UINT32_MAX, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN, + 1, // allocationCount + pAllocation); + + if(pAllocationInfo && result == VK_SUCCESS) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return result; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( + VmaAllocator allocator, + VmaAllocation allocation) +{ + VMA_ASSERT(allocator); + + if(allocation == VK_NULL_HANDLE) + { + return; + } + + VMA_DEBUG_LOG("vmaFreeMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->FreeMemory( + 1, // allocationCount + &allocation); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( + VmaAllocator allocator, + size_t allocationCount, + const VmaAllocation* pAllocations) +{ + if(allocationCount == 0) + { + return; + } + + VMA_ASSERT(allocator); + + VMA_DEBUG_LOG("vmaFreeMemoryPages"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->FreeMemory(allocationCount, pAllocations); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( + VmaAllocator allocator, + VmaAllocation allocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && allocation && pAllocationInfo); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->GetAllocationInfo(allocation, pAllocationInfo); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( + VmaAllocator allocator, + VmaAllocation allocation, + void* pUserData) +{ + VMA_ASSERT(allocator && allocation); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocation->SetUserData(allocator, pUserData); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const char* VMA_NULLABLE pName) +{ + allocation->SetName(allocator, pName); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags) +{ + VMA_ASSERT(allocator && allocation && pFlags); + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + *pFlags = allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( + VmaAllocator allocator, + VmaAllocation allocation, + void** ppData) +{ + VMA_ASSERT(allocator && allocation && ppData); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->Map(allocation, ppData); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( + VmaAllocator allocator, + VmaAllocation allocation) +{ + VMA_ASSERT(allocator && allocation); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + allocator->Unmap(allocation); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( + VmaAllocator allocator, + VmaAllocation allocation, + VkDeviceSize offset, + VkDeviceSize size) +{ + VMA_ASSERT(allocator && allocation); + + VMA_DEBUG_LOG("vmaFlushAllocation"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); + + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( + VmaAllocator allocator, + VmaAllocation allocation, + VkDeviceSize offset, + VkDeviceSize size) +{ + VMA_ASSERT(allocator && allocation); + + VMA_DEBUG_LOG("vmaInvalidateAllocation"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); + + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( + VmaAllocator allocator, + uint32_t allocationCount, + const VmaAllocation* allocations, + const VkDeviceSize* offsets, + const VkDeviceSize* sizes) +{ + VMA_ASSERT(allocator); + + if(allocationCount == 0) + { + return VK_SUCCESS; + } + + VMA_ASSERT(allocations); + + VMA_DEBUG_LOG("vmaFlushAllocations"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH); + + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( + VmaAllocator allocator, + uint32_t allocationCount, + const VmaAllocation* allocations, + const VkDeviceSize* offsets, + const VkDeviceSize* sizes) +{ + VMA_ASSERT(allocator); + + if(allocationCount == 0) + { + return VK_SUCCESS; + } + + VMA_ASSERT(allocations); + + VMA_DEBUG_LOG("vmaInvalidateAllocations"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE); + + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( + VmaAllocator allocator, + uint32_t memoryTypeBits) +{ + VMA_ASSERT(allocator); + + VMA_DEBUG_LOG("vmaCheckCorruption"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->CheckCorruption(memoryTypeBits); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( + VmaAllocator allocator, + const VmaDefragmentationInfo* pInfo, + VmaDefragmentationContext* pContext) +{ + VMA_ASSERT(allocator && pInfo && pContext); + + VMA_DEBUG_LOG("vmaBeginDefragmentation"); + + if (pInfo->pool != VMA_NULL) + { + // Check if run on supported algorithms + if (pInfo->pool->m_BlockVector.GetAlgorithm() & VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *pContext = vma_new(allocator, VmaDefragmentationContext_T)(allocator, *pInfo); + return VK_SUCCESS; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( + VmaAllocator allocator, + VmaDefragmentationContext context, + VmaDefragmentationStats* pStats) +{ + VMA_ASSERT(allocator && context); + + VMA_DEBUG_LOG("vmaEndDefragmentation"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + if (pStats) + context->GetStats(*pStats); + vma_delete(allocator, context); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo) +{ + VMA_ASSERT(context && pPassInfo); + + VMA_DEBUG_LOG("vmaBeginDefragmentationPass"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return context->DefragmentPassBegin(*pPassInfo); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo) +{ + VMA_ASSERT(context && pPassInfo); + + VMA_DEBUG_LOG("vmaEndDefragmentationPass"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return context->DefragmentPassEnd(*pPassInfo); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( + VmaAllocator allocator, + VmaAllocation allocation, + VkBuffer buffer) +{ + VMA_ASSERT(allocator && allocation && buffer); + + VMA_DEBUG_LOG("vmaBindBufferMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( + VmaAllocator allocator, + VmaAllocation allocation, + VkDeviceSize allocationLocalOffset, + VkBuffer buffer, + const void* pNext) +{ + VMA_ASSERT(allocator && allocation && buffer); + + VMA_DEBUG_LOG("vmaBindBufferMemory2"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( + VmaAllocator allocator, + VmaAllocation allocation, + VkImage image) +{ + VMA_ASSERT(allocator && allocation && image); + + VMA_DEBUG_LOG("vmaBindImageMemory"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->BindImageMemory(allocation, 0, image, VMA_NULL); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( + VmaAllocator allocator, + VmaAllocation allocation, + VkDeviceSize allocationLocalOffset, + VkImage image, + const void* pNext) +{ + VMA_ASSERT(allocator && allocation && image); + + VMA_DEBUG_LOG("vmaBindImageMemory2"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + return allocator->BindImageMemory(allocation, allocationLocalOffset, image, pNext); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( + VmaAllocator allocator, + const VkBufferCreateInfo* pBufferCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkBuffer* pBuffer, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation); + + if(pBufferCreateInfo->size == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + !allocator->m_UseKhrBufferDeviceAddress) + { + VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_LOG("vmaCreateBuffer"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *pBuffer = VK_NULL_HANDLE; + *pAllocation = VK_NULL_HANDLE; + + // 1. Create VkBuffer. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( + allocator->m_hDevice, + pBufferCreateInfo, + allocator->GetAllocationCallbacks(), + pBuffer); + if(res >= 0) + { + // 2. vkGetBufferMemoryRequirements. + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + + // 3. Allocate memory using allocator. + res = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + *pBuffer, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + pBufferCreateInfo->usage, // dedicatedBufferImageUsage + *pAllocationCreateInfo, + VMA_SUBALLOCATION_TYPE_BUFFER, + 1, // allocationCount + pAllocation); + + if(res >= 0) + { + // 3. Bind buffer with memory. + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + { + res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); + } + if(res >= 0) + { + // All steps succeeded. + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage); + #endif + if(pAllocationInfo != VMA_NULL) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return VK_SUCCESS; + } + allocator->FreeMemory( + 1, // allocationCount + pAllocation); + *pAllocation = VK_NULL_HANDLE; + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + *pBuffer = VK_NULL_HANDLE; + return res; + } + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + *pBuffer = VK_NULL_HANDLE; + return res; + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( + VmaAllocator allocator, + const VkBufferCreateInfo* pBufferCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkDeviceSize minAlignment, + VkBuffer* pBuffer, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && VmaIsPow2(minAlignment) && pBuffer && pAllocation); + + if(pBufferCreateInfo->size == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + !allocator->m_UseKhrBufferDeviceAddress) + { + VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_LOG("vmaCreateBufferWithAlignment"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *pBuffer = VK_NULL_HANDLE; + *pAllocation = VK_NULL_HANDLE; + + // 1. Create VkBuffer. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( + allocator->m_hDevice, + pBufferCreateInfo, + allocator->GetAllocationCallbacks(), + pBuffer); + if(res >= 0) + { + // 2. vkGetBufferMemoryRequirements. + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + + // 2a. Include minAlignment + vkMemReq.alignment = VMA_MAX(vkMemReq.alignment, minAlignment); + + // 3. Allocate memory using allocator. + res = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + *pBuffer, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + pBufferCreateInfo->usage, // dedicatedBufferImageUsage + *pAllocationCreateInfo, + VMA_SUBALLOCATION_TYPE_BUFFER, + 1, // allocationCount + pAllocation); + + if(res >= 0) + { + // 3. Bind buffer with memory. + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + { + res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); + } + if(res >= 0) + { + // All steps succeeded. + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage); + #endif + if(pAllocationInfo != VMA_NULL) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return VK_SUCCESS; + } + allocator->FreeMemory( + 1, // allocationCount + pAllocation); + *pAllocation = VK_NULL_HANDLE; + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + *pBuffer = VK_NULL_HANDLE; + return res; + } + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + *pBuffer = VK_NULL_HANDLE; + return res; + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer) +{ + VMA_ASSERT(allocator && pBufferCreateInfo && pBuffer && allocation); + + VMA_DEBUG_LOG("vmaCreateAliasingBuffer"); + + *pBuffer = VK_NULL_HANDLE; + + if (pBufferCreateInfo->size == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + if ((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + !allocator->m_UseKhrBufferDeviceAddress) + { + VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + // 1. Create VkBuffer. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( + allocator->m_hDevice, + pBufferCreateInfo, + allocator->GetAllocationCallbacks(), + pBuffer); + if (res >= 0) + { + // 2. Bind buffer with memory. + res = allocator->BindBufferMemory(allocation, 0, *pBuffer, VMA_NULL); + if (res >= 0) + { + return VK_SUCCESS; + } + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); + } + return res; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( + VmaAllocator allocator, + VkBuffer buffer, + VmaAllocation allocation) +{ + VMA_ASSERT(allocator); + + if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) + { + return; + } + + VMA_DEBUG_LOG("vmaDestroyBuffer"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + if(buffer != VK_NULL_HANDLE) + { + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks()); + } + + if(allocation != VK_NULL_HANDLE) + { + allocator->FreeMemory( + 1, // allocationCount + &allocation); + } +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( + VmaAllocator allocator, + const VkImageCreateInfo* pImageCreateInfo, + const VmaAllocationCreateInfo* pAllocationCreateInfo, + VkImage* pImage, + VmaAllocation* pAllocation, + VmaAllocationInfo* pAllocationInfo) +{ + VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation); + + if(pImageCreateInfo->extent.width == 0 || + pImageCreateInfo->extent.height == 0 || + pImageCreateInfo->extent.depth == 0 || + pImageCreateInfo->mipLevels == 0 || + pImageCreateInfo->arrayLayers == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_LOG("vmaCreateImage"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + *pImage = VK_NULL_HANDLE; + *pAllocation = VK_NULL_HANDLE; + + // 1. Create VkImage. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( + allocator->m_hDevice, + pImageCreateInfo, + allocator->GetAllocationCallbacks(), + pImage); + if(res >= 0) + { + VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ? + VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL : + VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR; + + // 2. Allocate memory using allocator. + VkMemoryRequirements vkMemReq = {}; + bool requiresDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; + allocator->GetImageMemoryRequirements(*pImage, vkMemReq, + requiresDedicatedAllocation, prefersDedicatedAllocation); + + res = allocator->AllocateMemory( + vkMemReq, + requiresDedicatedAllocation, + prefersDedicatedAllocation, + VK_NULL_HANDLE, // dedicatedBuffer + *pImage, // dedicatedImage + pImageCreateInfo->usage, // dedicatedBufferImageUsage + *pAllocationCreateInfo, + suballocType, + 1, // allocationCount + pAllocation); + + if(res >= 0) + { + // 3. Bind image with memory. + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + { + res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL); + } + if(res >= 0) + { + // All steps succeeded. + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferImageUsage(pImageCreateInfo->usage); + #endif + if(pAllocationInfo != VMA_NULL) + { + allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); + } + + return VK_SUCCESS; + } + allocator->FreeMemory( + 1, // allocationCount + pAllocation); + *pAllocation = VK_NULL_HANDLE; + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); + *pImage = VK_NULL_HANDLE; + return res; + } + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); + *pImage = VK_NULL_HANDLE; + return res; + } + return res; +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage) +{ + VMA_ASSERT(allocator && pImageCreateInfo && pImage && allocation); + + *pImage = VK_NULL_HANDLE; + + VMA_DEBUG_LOG("vmaCreateImage"); + + if (pImageCreateInfo->extent.width == 0 || + pImageCreateInfo->extent.height == 0 || + pImageCreateInfo->extent.depth == 0 || + pImageCreateInfo->mipLevels == 0 || + pImageCreateInfo->arrayLayers == 0) + { + return VK_ERROR_INITIALIZATION_FAILED; + } + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + // 1. Create VkImage. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( + allocator->m_hDevice, + pImageCreateInfo, + allocator->GetAllocationCallbacks(), + pImage); + if (res >= 0) + { + // 2. Bind image with memory. + res = allocator->BindImageMemory(allocation, 0, *pImage, VMA_NULL); + if (res >= 0) + { + return VK_SUCCESS; + } + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); + } + return res; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NULLABLE_NON_DISPATCHABLE image, + VmaAllocation VMA_NULLABLE allocation) +{ + VMA_ASSERT(allocator); + + if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) + { + return; + } + + VMA_DEBUG_LOG("vmaDestroyImage"); + + VMA_DEBUG_GLOBAL_MUTEX_LOCK + + if(image != VK_NULL_HANDLE) + { + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks()); + } + if(allocation != VK_NULL_HANDLE) + { + allocator->FreeMemory( + 1, // allocationCount + &allocation); + } +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( + const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualBlock VMA_NULLABLE * VMA_NOT_NULL pVirtualBlock) +{ + VMA_ASSERT(pCreateInfo && pVirtualBlock); + VMA_ASSERT(pCreateInfo->size > 0); + VMA_DEBUG_LOG("vmaCreateVirtualBlock"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + *pVirtualBlock = vma_new(pCreateInfo->pAllocationCallbacks, VmaVirtualBlock_T)(*pCreateInfo); + VkResult res = (*pVirtualBlock)->Init(); + if(res < 0) + { + vma_delete(pCreateInfo->pAllocationCallbacks, *pVirtualBlock); + *pVirtualBlock = VK_NULL_HANDLE; + } + return res; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock(VmaVirtualBlock VMA_NULLABLE virtualBlock) +{ + if(virtualBlock != VK_NULL_HANDLE) + { + VMA_DEBUG_LOG("vmaDestroyVirtualBlock"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + VkAllocationCallbacks allocationCallbacks = virtualBlock->m_AllocationCallbacks; // Have to copy the callbacks when destroying. + vma_delete(&allocationCallbacks, virtualBlock); + } +} + +VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty(VmaVirtualBlock VMA_NOT_NULL virtualBlock) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_LOG("vmaIsVirtualBlockEmpty"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + return virtualBlock->IsEmpty() ? VK_TRUE : VK_FALSE; +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pVirtualAllocInfo != VMA_NULL); + VMA_DEBUG_LOG("vmaGetVirtualAllocationInfo"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->GetAllocationInfo(allocation, *pVirtualAllocInfo); +} + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + const VmaVirtualAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pAllocation, + VkDeviceSize* VMA_NULLABLE pOffset) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pCreateInfo != VMA_NULL && pAllocation != VMA_NULL); + VMA_DEBUG_LOG("vmaVirtualAllocate"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + return virtualBlock->Allocate(*pCreateInfo, *pAllocation, pOffset); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(VmaVirtualBlock VMA_NOT_NULL virtualBlock, VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation) +{ + if(allocation != VK_NULL_HANDLE) + { + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_LOG("vmaVirtualFree"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->Free(allocation); + } +} + +VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock(VmaVirtualBlock VMA_NOT_NULL virtualBlock) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_LOG("vmaClearVirtualBlock"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->Clear(); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, void* VMA_NULLABLE pUserData) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_LOG("vmaSetVirtualAllocationUserData"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->SetAllocationUserData(allocation, pUserData); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaStatistics* VMA_NOT_NULL pStats) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pStats != VMA_NULL); + VMA_DEBUG_LOG("vmaGetVirtualBlockStatistics"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->GetStatistics(*pStats); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaDetailedStatistics* VMA_NOT_NULL pStats) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pStats != VMA_NULL); + VMA_DEBUG_LOG("vmaCalculateVirtualBlockStatistics"); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + virtualBlock->CalculateDetailedStatistics(*pStats); +} + +#if VMA_STATS_STRING_ENABLED + +VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE * VMA_NOT_NULL ppStatsString, VkBool32 detailedMap) +{ + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && ppStatsString != VMA_NULL); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + const VkAllocationCallbacks* allocationCallbacks = virtualBlock->GetAllocationCallbacks(); + VmaStringBuilder sb(allocationCallbacks); + virtualBlock->BuildStatsString(detailedMap != VK_FALSE, sb); + *ppStatsString = VmaCreateStringCopy(allocationCallbacks, sb.GetData(), sb.GetLength()); +} + +VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE pStatsString) +{ + if(pStatsString != VMA_NULL) + { + VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + VmaFreeString(virtualBlock->GetAllocationCallbacks(), pStatsString); + } +} +#endif // VMA_STATS_STRING_ENABLED +#endif // _VMA_PUBLIC_INTERFACE +#endif // VMA_IMPLEMENTATION + +/** +\page quick_start Quick start + +\section quick_start_project_setup Project setup + +Vulkan Memory Allocator comes in form of a "stb-style" single header file. +You don't need to build it as a separate library project. +You can add this file directly to your project and submit it to code repository next to your other source files. + +"Single header" doesn't mean that everything is contained in C/C++ declarations, +like it tends to be in case of inline functions or C++ templates. +It means that implementation is bundled with interface in a single file and needs to be extracted using preprocessor macro. +If you don't do it properly, you will get linker errors. + +To do it properly: + +-# Include "vk_mem_alloc.h" file in each CPP file where you want to use the library. + This includes declarations of all members of the library. +-# In exactly one CPP file define following macro before this include. + It enables also internal definitions. + +\code +#define VMA_IMPLEMENTATION +#include "vk_mem_alloc.h" +\endcode + +It may be a good idea to create dedicated CPP file just for this purpose. + +This library includes header ``, which in turn +includes `` on Windows. If you need some specific macros defined +before including these headers (like `WIN32_LEAN_AND_MEAN` or +`WINVER` for Windows, `VK_USE_PLATFORM_WIN32_KHR` for Vulkan), you must define +them before every `#include` of this library. + +This library is written in C++, but has C-compatible interface. +Thus you can include and use vk_mem_alloc.h in C or C++ code, but full +implementation with `VMA_IMPLEMENTATION` macro must be compiled as C++, NOT as C. +Some features of C++14 used. STL containers, RTTI, or C++ exceptions are not used. + + +\section quick_start_initialization Initialization + +At program startup: + +-# Initialize Vulkan to have `VkPhysicalDevice`, `VkDevice` and `VkInstance` object. +-# Fill VmaAllocatorCreateInfo structure and create #VmaAllocator object by + calling vmaCreateAllocator(). + +Only members `physicalDevice`, `device`, `instance` are required. +However, you should inform the library which Vulkan version do you use by setting +VmaAllocatorCreateInfo::vulkanApiVersion and which extensions did you enable +by setting VmaAllocatorCreateInfo::flags (like #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT for VK_KHR_buffer_device_address). +Otherwise, VMA would use only features of Vulkan 1.0 core with no extensions. + +You may need to configure importing Vulkan functions. There are 3 ways to do this: + +-# **If you link with Vulkan static library** (e.g. "vulkan-1.lib" on Windows): + - You don't need to do anything. + - VMA will use these, as macro `VMA_STATIC_VULKAN_FUNCTIONS` is defined to 1 by default. +-# **If you want VMA to fetch pointers to Vulkan functions dynamically** using `vkGetInstanceProcAddr`, + `vkGetDeviceProcAddr` (this is the option presented in the example below): + - Define `VMA_STATIC_VULKAN_FUNCTIONS` to 0, `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 1. + - Provide pointers to these two functions via VmaVulkanFunctions::vkGetInstanceProcAddr, + VmaVulkanFunctions::vkGetDeviceProcAddr. + - The library will fetch pointers to all other functions it needs internally. +-# **If you fetch pointers to all Vulkan functions in a custom way**, e.g. using some loader like + [Volk](https://github.com/zeux/volk): + - Define `VMA_STATIC_VULKAN_FUNCTIONS` and `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 0. + - Pass these pointers via structure #VmaVulkanFunctions. + +\code +VmaVulkanFunctions vulkanFunctions = {}; +vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr; +vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr; + +VmaAllocatorCreateInfo allocatorCreateInfo = {}; +allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2; +allocatorCreateInfo.physicalDevice = physicalDevice; +allocatorCreateInfo.device = device; +allocatorCreateInfo.instance = instance; +allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; + +VmaAllocator allocator; +vmaCreateAllocator(&allocatorCreateInfo, &allocator); +\endcode + + +\section quick_start_resource_allocation Resource allocation + +When you want to create a buffer or image: + +-# Fill `VkBufferCreateInfo` / `VkImageCreateInfo` structure. +-# Fill VmaAllocationCreateInfo structure. +-# Call vmaCreateBuffer() / vmaCreateImage() to get `VkBuffer`/`VkImage` with memory + already allocated and bound to it, plus #VmaAllocation objects that represents its underlying memory. + +\code +VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufferInfo.size = 65536; +bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.usage = VMA_MEMORY_USAGE_AUTO; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); +\endcode + +Don't forget to destroy your objects when no longer needed: + +\code +vmaDestroyBuffer(allocator, buffer, allocation); +vmaDestroyAllocator(allocator); +\endcode + + +\page choosing_memory_type Choosing memory type + +Physical devices in Vulkan support various combinations of memory heaps and +types. Help with choosing correct and optimal memory type for your specific +resource is one of the key features of this library. You can use it by filling +appropriate members of VmaAllocationCreateInfo structure, as described below. +You can also combine multiple methods. + +-# If you just want to find memory type index that meets your requirements, you + can use function: vmaFindMemoryTypeIndexForBufferInfo(), + vmaFindMemoryTypeIndexForImageInfo(), vmaFindMemoryTypeIndex(). +-# If you want to allocate a region of device memory without association with any + specific image or buffer, you can use function vmaAllocateMemory(). Usage of + this function is not recommended and usually not needed. + vmaAllocateMemoryPages() function is also provided for creating multiple allocations at once, + which may be useful for sparse binding. +-# If you already have a buffer or an image created, you want to allocate memory + for it and then you will bind it yourself, you can use function + vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(). + For binding you should use functions: vmaBindBufferMemory(), vmaBindImageMemory() + or their extended versions: vmaBindBufferMemory2(), vmaBindImageMemory2(). +-# **This is the easiest and recommended way to use this library:** + If you want to create a buffer or an image, allocate memory for it and bind + them together, all in one call, you can use function vmaCreateBuffer(), + vmaCreateImage(). + +When using 3. or 4., the library internally queries Vulkan for memory types +supported for that buffer or image (function `vkGetBufferMemoryRequirements()`) +and uses only one of these types. + +If no memory type can be found that meets all the requirements, these functions +return `VK_ERROR_FEATURE_NOT_PRESENT`. + +You can leave VmaAllocationCreateInfo structure completely filled with zeros. +It means no requirements are specified for memory type. +It is valid, although not very useful. + +\section choosing_memory_type_usage Usage + +The easiest way to specify memory requirements is to fill member +VmaAllocationCreateInfo::usage using one of the values of enum #VmaMemoryUsage. +It defines high level, common usage types. +Since version 3 of the library, it is recommended to use #VMA_MEMORY_USAGE_AUTO to let it select best memory type for your resource automatically. + +For example, if you want to create a uniform buffer that will be filled using +transfer only once or infrequently and then used for rendering every frame as a uniform buffer, you can +do it using following code. The buffer will most likely end up in a memory type with +`VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT` to be fast to access by the GPU device. + +\code +VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufferInfo.size = 65536; +bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.usage = VMA_MEMORY_USAGE_AUTO; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); +\endcode + +If you have a preference for putting the resource in GPU (device) memory or CPU (host) memory +on systems with discrete graphics card that have the memories separate, you can use +#VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE or #VMA_MEMORY_USAGE_AUTO_PREFER_HOST. + +When using `VMA_MEMORY_USAGE_AUTO*` while you want to map the allocated memory, +you also need to specify one of the host access flags: +#VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +This will help the library decide about preferred memory type to ensure it has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` +so you can map it. + +For example, a staging buffer that will be filled via mapped pointer and then +used as a source of transfer to the buffer decribed previously can be created like this. +It will likely and up in a memory type that is `HOST_VISIBLE` and `HOST_COHERENT` +but not `HOST_CACHED` (meaning uncached, write-combined) and not `DEVICE_LOCAL` (meaning system RAM). + +\code +VkBufferCreateInfo stagingBufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +stagingBufferInfo.size = 65536; +stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + +VmaAllocationCreateInfo stagingAllocInfo = {}; +stagingAllocInfo.usage = VMA_MEMORY_USAGE_AUTO; +stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + +VkBuffer stagingBuffer; +VmaAllocation stagingAllocation; +vmaCreateBuffer(allocator, &stagingBufferInfo, &stagingAllocInfo, &stagingBuffer, &stagingAllocation, nullptr); +\endcode + +For more examples of creating different kinds of resources, see chapter \ref usage_patterns. + +Usage values `VMA_MEMORY_USAGE_AUTO*` are legal to use only when the library knows +about the resource being created by having `VkBufferCreateInfo` / `VkImageCreateInfo` passed, +so they work with functions like: vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo() etc. +If you allocate raw memory using function vmaAllocateMemory(), you have to use other means of selecting +memory type, as decribed below. + +\note +Old usage values (`VMA_MEMORY_USAGE_GPU_ONLY`, `VMA_MEMORY_USAGE_CPU_ONLY`, +`VMA_MEMORY_USAGE_CPU_TO_GPU`, `VMA_MEMORY_USAGE_GPU_TO_CPU`, `VMA_MEMORY_USAGE_CPU_COPY`) +are still available and work same way as in previous versions of the library +for backward compatibility, but they are not recommended. + +\section choosing_memory_type_required_preferred_flags Required and preferred flags + +You can specify more detailed requirements by filling members +VmaAllocationCreateInfo::requiredFlags and VmaAllocationCreateInfo::preferredFlags +with a combination of bits from enum `VkMemoryPropertyFlags`. For example, +if you want to create a buffer that will be persistently mapped on host (so it +must be `HOST_VISIBLE`) and preferably will also be `HOST_COHERENT` and `HOST_CACHED`, +use following code: + +\code +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; +allocInfo.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; +allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); +\endcode + +A memory type is chosen that has all the required flags and as many preferred +flags set as possible. + +Value passed in VmaAllocationCreateInfo::usage is internally converted to a set of required and preferred flags, +plus some extra "magic" (heuristics). + +\section choosing_memory_type_explicit_memory_types Explicit memory types + +If you inspected memory types available on the physical device and you have +a preference for memory types that you want to use, you can fill member +VmaAllocationCreateInfo::memoryTypeBits. It is a bit mask, where each bit set +means that a memory type with that index is allowed to be used for the +allocation. Special value 0, just like `UINT32_MAX`, means there are no +restrictions to memory type index. + +Please note that this member is NOT just a memory type index. +Still you can use it to choose just one, specific memory type. +For example, if you already determined that your buffer should be created in +memory type 2, use following code: + +\code +uint32_t memoryTypeIndex = 2; + +VmaAllocationCreateInfo allocInfo = {}; +allocInfo.memoryTypeBits = 1u << memoryTypeIndex; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); +\endcode + + +\section choosing_memory_type_custom_memory_pools Custom memory pools + +If you allocate from custom memory pool, all the ways of specifying memory +requirements described above are not applicable and the aforementioned members +of VmaAllocationCreateInfo structure are ignored. Memory type is selected +explicitly when creating the pool and then used to make all the allocations from +that pool. For further details, see \ref custom_memory_pools. + +\section choosing_memory_type_dedicated_allocations Dedicated allocations + +Memory for allocations is reserved out of larger block of `VkDeviceMemory` +allocated from Vulkan internally. That is the main feature of this whole library. +You can still request a separate memory block to be created for an allocation, +just like you would do in a trivial solution without using any allocator. +In that case, a buffer or image is always bound to that memory at offset 0. +This is called a "dedicated allocation". +You can explicitly request it by using flag #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. +The library can also internally decide to use dedicated allocation in some cases, e.g.: + +- When the size of the allocation is large. +- When [VK_KHR_dedicated_allocation](@ref vk_khr_dedicated_allocation) extension is enabled + and it reports that dedicated allocation is required or recommended for the resource. +- When allocation of next big memory block fails due to not enough device memory, + but allocation with the exact requested size succeeds. + + +\page memory_mapping Memory mapping + +To "map memory" in Vulkan means to obtain a CPU pointer to `VkDeviceMemory`, +to be able to read from it or write to it in CPU code. +Mapping is possible only of memory allocated from a memory type that has +`VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. +Functions `vkMapMemory()`, `vkUnmapMemory()` are designed for this purpose. +You can use them directly with memory allocated by this library, +but it is not recommended because of following issue: +Mapping the same `VkDeviceMemory` block multiple times is illegal - only one mapping at a time is allowed. +This includes mapping disjoint regions. Mapping is not reference-counted internally by Vulkan. +Because of this, Vulkan Memory Allocator provides following facilities: + +\note If you want to be able to map an allocation, you need to specify one of the flags +#VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT +in VmaAllocationCreateInfo::flags. These flags are required for an allocation to be mappable +when using #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` enum values. +For other usage values they are ignored and every such allocation made in `HOST_VISIBLE` memory type is mappable, +but they can still be used for consistency. + +\section memory_mapping_mapping_functions Mapping functions + +The library provides following functions for mapping of a specific #VmaAllocation: vmaMapMemory(), vmaUnmapMemory(). +They are safer and more convenient to use than standard Vulkan functions. +You can map an allocation multiple times simultaneously - mapping is reference-counted internally. +You can also map different allocations simultaneously regardless of whether they use the same `VkDeviceMemory` block. +The way it is implemented is that the library always maps entire memory block, not just region of the allocation. +For further details, see description of vmaMapMemory() function. +Example: + +\code +// Having these objects initialized: +struct ConstantBuffer +{ + ... +}; +ConstantBuffer constantBufferData = ... + +VmaAllocator allocator = ... +VkBuffer constantBuffer = ... +VmaAllocation constantBufferAllocation = ... + +// You can map and fill your buffer using following code: + +void* mappedData; +vmaMapMemory(allocator, constantBufferAllocation, &mappedData); +memcpy(mappedData, &constantBufferData, sizeof(constantBufferData)); +vmaUnmapMemory(allocator, constantBufferAllocation); +\endcode + +When mapping, you may see a warning from Vulkan validation layer similar to this one: + +Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used. + +It happens because the library maps entire `VkDeviceMemory` block, where different +types of images and buffers may end up together, especially on GPUs with unified memory like Intel. +You can safely ignore it if you are sure you access only memory of the intended +object that you wanted to map. + + +\section memory_mapping_persistently_mapped_memory Persistently mapped memory + +Kepping your memory persistently mapped is generally OK in Vulkan. +You don't need to unmap it before using its data on the GPU. +The library provides a special feature designed for that: +Allocations made with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag set in +VmaAllocationCreateInfo::flags stay mapped all the time, +so you can just access CPU pointer to it any time +without a need to call any "map" or "unmap" function. +Example: + +\code +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = sizeof(ConstantBuffer); +bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + +VkBuffer buf; +VmaAllocation alloc; +VmaAllocationInfo allocInfo; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); + +// Buffer is already mapped. You can access its memory. +memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); +\endcode + +\note #VMA_ALLOCATION_CREATE_MAPPED_BIT by itself doesn't guarantee that the allocation will end up +in a mappable memory type. +For this, you need to also specify #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or +#VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +#VMA_ALLOCATION_CREATE_MAPPED_BIT only guarantees that if the memory is `HOST_VISIBLE`, the allocation will be mapped on creation. +For an example of how to make use of this fact, see section \ref usage_patterns_advanced_data_uploading. + +\section memory_mapping_cache_control Cache flush and invalidate + +Memory in Vulkan doesn't need to be unmapped before using it on GPU, +but unless a memory types has `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` flag set, +you need to manually **invalidate** cache before reading of mapped pointer +and **flush** cache after writing to mapped pointer. +Map/unmap operations don't do that automatically. +Vulkan provides following functions for this purpose `vkFlushMappedMemoryRanges()`, +`vkInvalidateMappedMemoryRanges()`, but this library provides more convenient +functions that refer to given allocation object: vmaFlushAllocation(), +vmaInvalidateAllocation(), +or multiple objects at once: vmaFlushAllocations(), vmaInvalidateAllocations(). + +Regions of memory specified for flush/invalidate must be aligned to +`VkPhysicalDeviceLimits::nonCoherentAtomSize`. This is automatically ensured by the library. +In any memory type that is `HOST_VISIBLE` but not `HOST_COHERENT`, all allocations +within blocks are aligned to this value, so their offsets are always multiply of +`nonCoherentAtomSize` and two different allocations never share same "line" of this size. + +Also, Windows drivers from all 3 PC GPU vendors (AMD, Intel, NVIDIA) +currently provide `HOST_COHERENT` flag on all memory types that are +`HOST_VISIBLE`, so on PC you may not need to bother. + + +\page staying_within_budget Staying within budget + +When developing a graphics-intensive game or program, it is important to avoid allocating +more GPU memory than it is physically available. When the memory is over-committed, +various bad things can happen, depending on the specific GPU, graphics driver, and +operating system: + +- It may just work without any problems. +- The application may slow down because some memory blocks are moved to system RAM + and the GPU has to access them through PCI Express bus. +- A new allocation may take very long time to complete, even few seconds, and possibly + freeze entire system. +- The new allocation may fail with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. +- It may even result in GPU crash (TDR), observed as `VK_ERROR_DEVICE_LOST` + returned somewhere later. + +\section staying_within_budget_querying_for_budget Querying for budget + +To query for current memory usage and available budget, use function vmaGetHeapBudgets(). +Returned structure #VmaBudget contains quantities expressed in bytes, per Vulkan memory heap. + +Please note that this function returns different information and works faster than +vmaCalculateStatistics(). vmaGetHeapBudgets() can be called every frame or even before every +allocation, while vmaCalculateStatistics() is intended to be used rarely, +only to obtain statistical information, e.g. for debugging purposes. + +It is recommended to use VK_EXT_memory_budget device extension to obtain information +about the budget from Vulkan device. VMA is able to use this extension automatically. +When not enabled, the allocator behaves same way, but then it estimates current usage +and available budget based on its internal information and Vulkan memory heap sizes, +which may be less precise. In order to use this extension: + +1. Make sure extensions VK_EXT_memory_budget and VK_KHR_get_physical_device_properties2 + required by it are available and enable them. Please note that the first is a device + extension and the second is instance extension! +2. Use flag #VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT when creating #VmaAllocator object. +3. Make sure to call vmaSetCurrentFrameIndex() every frame. Budget is queried from + Vulkan inside of it to avoid overhead of querying it with every allocation. + +\section staying_within_budget_controlling_memory_usage Controlling memory usage + +There are many ways in which you can try to stay within the budget. + +First, when making new allocation requires allocating a new memory block, the library +tries not to exceed the budget automatically. If a block with default recommended size +(e.g. 256 MB) would go over budget, a smaller block is allocated, possibly even +dedicated memory for just this resource. + +If the size of the requested resource plus current memory usage is more than the +budget, by default the library still tries to create it, leaving it to the Vulkan +implementation whether the allocation succeeds or fails. You can change this behavior +by using #VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT flag. With it, the allocation is +not made if it would exceed the budget or if the budget is already exceeded. +VMA then tries to make the allocation from the next eligible Vulkan memory type. +The all of them fail, the call then fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. +Example usage pattern may be to pass the #VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT flag +when creating resources that are not essential for the application (e.g. the texture +of a specific object) and not to pass it when creating critically important resources +(e.g. render targets). + +On AMD graphics cards there is a custom vendor extension available: VK_AMD_memory_overallocation_behavior +that allows to control the behavior of the Vulkan implementation in out-of-memory cases - +whether it should fail with an error code or still allow the allocation. +Usage of this extension involves only passing extra structure on Vulkan device creation, +so it is out of scope of this library. + +Finally, you can also use #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT flag to make sure +a new allocation is created only when it fits inside one of the existing memory blocks. +If it would require to allocate a new block, if fails instead with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. +This also ensures that the function call is very fast because it never goes to Vulkan +to obtain a new block. + +\note Creating \ref custom_memory_pools with VmaPoolCreateInfo::minBlockCount +set to more than 0 will currently try to allocate memory blocks without checking whether they +fit within budget. + + +\page resource_aliasing Resource aliasing (overlap) + +New explicit graphics APIs (Vulkan and Direct3D 12), thanks to manual memory +management, give an opportunity to alias (overlap) multiple resources in the +same region of memory - a feature not available in the old APIs (Direct3D 11, OpenGL). +It can be useful to save video memory, but it must be used with caution. + +For example, if you know the flow of your whole render frame in advance, you +are going to use some intermediate textures or buffers only during a small range of render passes, +and you know these ranges don't overlap in time, you can bind these resources to +the same place in memory, even if they have completely different parameters (width, height, format etc.). + +![Resource aliasing (overlap)](../gfx/Aliasing.png) + +Such scenario is possible using VMA, but you need to create your images manually. +Then you need to calculate parameters of an allocation to be made using formula: + +- allocation size = max(size of each image) +- allocation alignment = max(alignment of each image) +- allocation memoryTypeBits = bitwise AND(memoryTypeBits of each image) + +Following example shows two different images bound to the same place in memory, +allocated to fit largest of them. + +\code +// A 512x512 texture to be sampled. +VkImageCreateInfo img1CreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; +img1CreateInfo.imageType = VK_IMAGE_TYPE_2D; +img1CreateInfo.extent.width = 512; +img1CreateInfo.extent.height = 512; +img1CreateInfo.extent.depth = 1; +img1CreateInfo.mipLevels = 10; +img1CreateInfo.arrayLayers = 1; +img1CreateInfo.format = VK_FORMAT_R8G8B8A8_SRGB; +img1CreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; +img1CreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +img1CreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; +img1CreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + +// A full screen texture to be used as color attachment. +VkImageCreateInfo img2CreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; +img2CreateInfo.imageType = VK_IMAGE_TYPE_2D; +img2CreateInfo.extent.width = 1920; +img2CreateInfo.extent.height = 1080; +img2CreateInfo.extent.depth = 1; +img2CreateInfo.mipLevels = 1; +img2CreateInfo.arrayLayers = 1; +img2CreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; +img2CreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; +img2CreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +img2CreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +img2CreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + +VkImage img1; +res = vkCreateImage(device, &img1CreateInfo, nullptr, &img1); +VkImage img2; +res = vkCreateImage(device, &img2CreateInfo, nullptr, &img2); + +VkMemoryRequirements img1MemReq; +vkGetImageMemoryRequirements(device, img1, &img1MemReq); +VkMemoryRequirements img2MemReq; +vkGetImageMemoryRequirements(device, img2, &img2MemReq); + +VkMemoryRequirements finalMemReq = {}; +finalMemReq.size = std::max(img1MemReq.size, img2MemReq.size); +finalMemReq.alignment = std::max(img1MemReq.alignment, img2MemReq.alignment); +finalMemReq.memoryTypeBits = img1MemReq.memoryTypeBits & img2MemReq.memoryTypeBits; +// Validate if(finalMemReq.memoryTypeBits != 0) + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + +VmaAllocation alloc; +res = vmaAllocateMemory(allocator, &finalMemReq, &allocCreateInfo, &alloc, nullptr); + +res = vmaBindImageMemory(allocator, alloc, img1); +res = vmaBindImageMemory(allocator, alloc, img2); + +// You can use img1, img2 here, but not at the same time! + +vmaFreeMemory(allocator, alloc); +vkDestroyImage(allocator, img2, nullptr); +vkDestroyImage(allocator, img1, nullptr); +\endcode + +Remember that using resources that alias in memory requires proper synchronization. +You need to issue a memory barrier to make sure commands that use `img1` and `img2` +don't overlap on GPU timeline. +You also need to treat a resource after aliasing as uninitialized - containing garbage data. +For example, if you use `img1` and then want to use `img2`, you need to issue +an image memory barrier for `img2` with `oldLayout` = `VK_IMAGE_LAYOUT_UNDEFINED`. + +Additional considerations: + +- Vulkan also allows to interpret contents of memory between aliasing resources consistently in some cases. +See chapter 11.8. "Memory Aliasing" of Vulkan specification or `VK_IMAGE_CREATE_ALIAS_BIT` flag. +- You can create more complex layout where different images and buffers are bound +at different offsets inside one large allocation. For example, one can imagine +a big texture used in some render passes, aliasing with a set of many small buffers +used between in some further passes. To bind a resource at non-zero offset in an allocation, +use vmaBindBufferMemory2() / vmaBindImageMemory2(). +- Before allocating memory for the resources you want to alias, check `memoryTypeBits` +returned in memory requirements of each resource to make sure the bits overlap. +Some GPUs may expose multiple memory types suitable e.g. only for buffers or +images with `COLOR_ATTACHMENT` usage, so the sets of memory types supported by your +resources may be disjoint. Aliasing them is not possible in that case. + + +\page custom_memory_pools Custom memory pools + +A memory pool contains a number of `VkDeviceMemory` blocks. +The library automatically creates and manages default pool for each memory type available on the device. +Default memory pool automatically grows in size. +Size of allocated blocks is also variable and managed automatically. + +You can create custom pool and allocate memory out of it. +It can be useful if you want to: + +- Keep certain kind of allocations separate from others. +- Enforce particular, fixed size of Vulkan memory blocks. +- Limit maximum amount of Vulkan memory allocated for that pool. +- Reserve minimum or fixed amount of Vulkan memory always preallocated for that pool. +- Use extra parameters for a set of your allocations that are available in #VmaPoolCreateInfo but not in + #VmaAllocationCreateInfo - e.g., custom minimum alignment, custom `pNext` chain. +- Perform defragmentation on a specific subset of your allocations. + +To use custom memory pools: + +-# Fill VmaPoolCreateInfo structure. +-# Call vmaCreatePool() to obtain #VmaPool handle. +-# When making an allocation, set VmaAllocationCreateInfo::pool to this handle. + You don't need to specify any other parameters of this structure, like `usage`. + +Example: + +\code +// Find memoryTypeIndex for the pool. +VkBufferCreateInfo sampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +sampleBufCreateInfo.size = 0x10000; // Doesn't matter. +sampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo sampleAllocCreateInfo = {}; +sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + +uint32_t memTypeIndex; +VkResult res = vmaFindMemoryTypeIndexForBufferInfo(allocator, + &sampleBufCreateInfo, &sampleAllocCreateInfo, &memTypeIndex); +// Check res... + +// Create a pool that can have at most 2 blocks, 128 MiB each. +VmaPoolCreateInfo poolCreateInfo = {}; +poolCreateInfo.memoryTypeIndex = memTypeIndex; +poolCreateInfo.blockSize = 128ull * 1024 * 1024; +poolCreateInfo.maxBlockCount = 2; + +VmaPool pool; +res = vmaCreatePool(allocator, &poolCreateInfo, &pool); +// Check res... + +// Allocate a buffer out of it. +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = 1024; +bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.pool = pool; + +VkBuffer buf; +VmaAllocation alloc; +res = vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, nullptr); +// Check res... +\endcode + +You have to free all allocations made from this pool before destroying it. + +\code +vmaDestroyBuffer(allocator, buf, alloc); +vmaDestroyPool(allocator, pool); +\endcode + +New versions of this library support creating dedicated allocations in custom pools. +It is supported only when VmaPoolCreateInfo::blockSize = 0. +To use this feature, set VmaAllocationCreateInfo::pool to the pointer to your custom pool and +VmaAllocationCreateInfo::flags to #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + +\note Excessive use of custom pools is a common mistake when using this library. +Custom pools may be useful for special purposes - when you want to +keep certain type of resources separate e.g. to reserve minimum amount of memory +for them or limit maximum amount of memory they can occupy. For most +resources this is not needed and so it is not recommended to create #VmaPool +objects and allocations out of them. Allocating from the default pool is sufficient. + + +\section custom_memory_pools_MemTypeIndex Choosing memory type index + +When creating a pool, you must explicitly specify memory type index. +To find the one suitable for your buffers or images, you can use helper functions +vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo(). +You need to provide structures with example parameters of buffers or images +that you are going to create in that pool. + +\code +VkBufferCreateInfo exampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +exampleBufCreateInfo.size = 1024; // Doesn't matter +exampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + +uint32_t memTypeIndex; +vmaFindMemoryTypeIndexForBufferInfo(allocator, &exampleBufCreateInfo, &allocCreateInfo, &memTypeIndex); + +VmaPoolCreateInfo poolCreateInfo = {}; +poolCreateInfo.memoryTypeIndex = memTypeIndex; +// ... +\endcode + +When creating buffers/images allocated in that pool, provide following parameters: + +- `VkBufferCreateInfo`: Prefer to pass same parameters as above. + Otherwise you risk creating resources in a memory type that is not suitable for them, which may result in undefined behavior. + Using different `VK_BUFFER_USAGE_` flags may work, but you shouldn't create images in a pool intended for buffers + or the other way around. +- VmaAllocationCreateInfo: You don't need to pass same parameters. Fill only `pool` member. + Other members are ignored anyway. + +\section linear_algorithm Linear allocation algorithm + +Each Vulkan memory block managed by this library has accompanying metadata that +keeps track of used and unused regions. By default, the metadata structure and +algorithm tries to find best place for new allocations among free regions to +optimize memory usage. This way you can allocate and free objects in any order. + +![Default allocation algorithm](../gfx/Linear_allocator_1_algo_default.png) + +Sometimes there is a need to use simpler, linear allocation algorithm. You can +create custom pool that uses such algorithm by adding flag +#VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT to VmaPoolCreateInfo::flags while creating +#VmaPool object. Then an alternative metadata management is used. It always +creates new allocations after last one and doesn't reuse free regions after +allocations freed in the middle. It results in better allocation performance and +less memory consumed by metadata. + +![Linear allocation algorithm](../gfx/Linear_allocator_2_algo_linear.png) + +With this one flag, you can create a custom pool that can be used in many ways: +free-at-once, stack, double stack, and ring buffer. See below for details. +You don't need to specify explicitly which of these options you are going to use - it is detected automatically. + +\subsection linear_algorithm_free_at_once Free-at-once + +In a pool that uses linear algorithm, you still need to free all the allocations +individually, e.g. by using vmaFreeMemory() or vmaDestroyBuffer(). You can free +them in any order. New allocations are always made after last one - free space +in the middle is not reused. However, when you release all the allocation and +the pool becomes empty, allocation starts from the beginning again. This way you +can use linear algorithm to speed up creation of allocations that you are going +to release all at once. + +![Free-at-once](../gfx/Linear_allocator_3_free_at_once.png) + +This mode is also available for pools created with VmaPoolCreateInfo::maxBlockCount +value that allows multiple memory blocks. + +\subsection linear_algorithm_stack Stack + +When you free an allocation that was created last, its space can be reused. +Thanks to this, if you always release allocations in the order opposite to their +creation (LIFO - Last In First Out), you can achieve behavior of a stack. + +![Stack](../gfx/Linear_allocator_4_stack.png) + +This mode is also available for pools created with VmaPoolCreateInfo::maxBlockCount +value that allows multiple memory blocks. + +\subsection linear_algorithm_double_stack Double stack + +The space reserved by a custom pool with linear algorithm may be used by two +stacks: + +- First, default one, growing up from offset 0. +- Second, "upper" one, growing down from the end towards lower offsets. + +To make allocation from the upper stack, add flag #VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT +to VmaAllocationCreateInfo::flags. + +![Double stack](../gfx/Linear_allocator_7_double_stack.png) + +Double stack is available only in pools with one memory block - +VmaPoolCreateInfo::maxBlockCount must be 1. Otherwise behavior is undefined. + +When the two stacks' ends meet so there is not enough space between them for a +new allocation, such allocation fails with usual +`VK_ERROR_OUT_OF_DEVICE_MEMORY` error. + +\subsection linear_algorithm_ring_buffer Ring buffer + +When you free some allocations from the beginning and there is not enough free space +for a new one at the end of a pool, allocator's "cursor" wraps around to the +beginning and starts allocation there. Thanks to this, if you always release +allocations in the same order as you created them (FIFO - First In First Out), +you can achieve behavior of a ring buffer / queue. + +![Ring buffer](../gfx/Linear_allocator_5_ring_buffer.png) + +Ring buffer is available only in pools with one memory block - +VmaPoolCreateInfo::maxBlockCount must be 1. Otherwise behavior is undefined. + +\note \ref defragmentation is not supported in custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT. + + +\page defragmentation Defragmentation + +Interleaved allocations and deallocations of many objects of varying size can +cause fragmentation over time, which can lead to a situation where the library is unable +to find a continuous range of free memory for a new allocation despite there is +enough free space, just scattered across many small free ranges between existing +allocations. + +To mitigate this problem, you can use defragmentation feature. +It doesn't happen automatically though and needs your cooperation, +because VMA is a low level library that only allocates memory. +It cannot recreate buffers and images in a new place as it doesn't remember the contents of `VkBufferCreateInfo` / `VkImageCreateInfo` structures. +It cannot copy their contents as it doesn't record any commands to a command buffer. + +Example: + +\code +VmaDefragmentationInfo defragInfo = {}; +defragInfo.pool = myPool; +defragInfo.flags = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT; + +VmaDefragmentationContext defragCtx; +VkResult res = vmaBeginDefragmentation(allocator, &defragInfo, &defragCtx); +// Check res... + +for(;;) +{ + VmaDefragmentationPassMoveInfo pass; + res = vmaBeginDefragmentationPass(allocator, defragCtx, &pass); + if(res == VK_SUCCESS) + break; + else if(res != VK_INCOMPLETE) + // Handle error... + + for(uint32_t i = 0; i < pass.moveCount; ++i) + { + // Inspect pass.pMoves[i].srcAllocation, identify what buffer/image it represents. + VmaAllocationInfo allocInfo; + vmaGetAllocationInfo(allocator, pMoves[i].srcAllocation, &allocInfo); + MyEngineResourceData* resData = (MyEngineResourceData*)allocInfo.pUserData; + + // Recreate and bind this buffer/image at: pass.pMoves[i].dstMemory, pass.pMoves[i].dstOffset. + VkImageCreateInfo imgCreateInfo = ... + VkImage newImg; + res = vkCreateImage(device, &imgCreateInfo, nullptr, &newImg); + // Check res... + res = vmaBindImageMemory(allocator, pMoves[i].dstTmpAllocation, newImg); + // Check res... + + // Issue a vkCmdCopyBuffer/vkCmdCopyImage to copy its content to the new place. + vkCmdCopyImage(cmdBuf, resData->img, ..., newImg, ...); + } + + // Make sure the copy commands finished executing. + vkWaitForFences(...); + + // Destroy old buffers/images bound with pass.pMoves[i].srcAllocation. + for(uint32_t i = 0; i < pass.moveCount; ++i) + { + // ... + vkDestroyImage(device, resData->img, nullptr); + } + + // Update appropriate descriptors to point to the new places... + + res = vmaEndDefragmentationPass(allocator, defragCtx, &pass); + if(res == VK_SUCCESS) + break; + else if(res != VK_INCOMPLETE) + // Handle error... +} + +vmaEndDefragmentation(allocator, defragCtx, nullptr); +\endcode + +Although functions like vmaCreateBuffer(), vmaCreateImage(), vmaDestroyBuffer(), vmaDestroyImage() +create/destroy an allocation and a buffer/image at once, these are just a shortcut for +creating the resource, allocating memory, and binding them together. +Defragmentation works on memory allocations only. You must handle the rest manually. +Defragmentation is an iterative process that should repreat "passes" as long as related functions +return `VK_INCOMPLETE` not `VK_SUCCESS`. +In each pass: + +1. vmaBeginDefragmentationPass() function call: + - Calculates and returns the list of allocations to be moved in this pass. + Note this can be a time-consuming process. + - Reserves destination memory for them by creating temporary destination allocations + that you can query for their `VkDeviceMemory` + offset using vmaGetAllocationInfo(). +2. Inside the pass, **you should**: + - Inspect the returned list of allocations to be moved. + - Create new buffers/images and bind them at the returned destination temporary allocations. + - Copy data from source to destination resources if necessary. + - Destroy the source buffers/images, but NOT their allocations. +3. vmaEndDefragmentationPass() function call: + - Frees the source memory reserved for the allocations that are moved. + - Modifies source #VmaAllocation objects that are moved to point to the destination reserved memory. + - Frees `VkDeviceMemory` blocks that became empty. + +Unlike in previous iterations of the defragmentation API, there is no list of "movable" allocations passed as a parameter. +Defragmentation algorithm tries to move all suitable allocations. +You can, however, refuse to move some of them inside a defragmentation pass, by setting +`pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. +This is not recommended and may result in suboptimal packing of the allocations after defragmentation. +If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool. + +Inside a pass, for each allocation that should be moved: + +- You should copy its data from the source to the destination place by calling e.g. `vkCmdCopyBuffer()`, `vkCmdCopyImage()`. + - You need to make sure these commands finished executing before destroying the source buffers/images and before calling vmaEndDefragmentationPass(). +- If a resource doesn't contain any meaningful data, e.g. it is a transient color attachment image to be cleared, + filled, and used temporarily in each rendering frame, you can just recreate this image + without copying its data. +- If the resource is in `HOST_VISIBLE` and `HOST_CACHED` memory, you can copy its data on the CPU + using `memcpy()`. +- If you cannot move the allocation, you can set `pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. + This will cancel the move. + - vmaEndDefragmentationPass() will then free the destination memory + not the source memory of the allocation, leaving it unchanged. +- If you decide the allocation is unimportant and can be destroyed instead of moved (e.g. it wasn't used for long time), + you can set `pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY. + - vmaEndDefragmentationPass() will then free both source and destination memory, and will destroy the source #VmaAllocation object. + +You can defragment a specific custom pool by setting VmaDefragmentationInfo::pool +(like in the example above) or all the default pools by setting this member to null. + +Defragmentation is always performed in each pool separately. +Allocations are never moved between different Vulkan memory types. +The size of the destination memory reserved for a moved allocation is the same as the original one. +Alignment of an allocation as it was determined using `vkGetBufferMemoryRequirements()` etc. is also respected after defragmentation. +Buffers/images should be recreated with the same `VkBufferCreateInfo` / `VkImageCreateInfo` parameters as the original ones. + +You can perform the defragmentation incrementally to limit the number of allocations and bytes to be moved +in each pass, e.g. to call it in sync with render frames and not to experience too big hitches. +See members: VmaDefragmentationInfo::maxBytesPerPass, VmaDefragmentationInfo::maxAllocationsPerPass. + +It is also safe to perform the defragmentation asynchronously to render frames and other Vulkan and VMA +usage, possibly from multiple threads, with the exception that allocations +returned in VmaDefragmentationPassMoveInfo::pMoves shouldn't be destroyed until the defragmentation pass is ended. + +Mapping is preserved on allocations that are moved during defragmentation. +Whether through #VMA_ALLOCATION_CREATE_MAPPED_BIT or vmaMapMemory(), the allocations +are mapped at their new place. Of course, pointer to the mapped data changes, so it needs to be queried +using VmaAllocationInfo::pMappedData. + +\note Defragmentation is not supported in custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT. + + +\page statistics Statistics + +This library contains several functions that return information about its internal state, +especially the amount of memory allocated from Vulkan. + +\section statistics_numeric_statistics Numeric statistics + +If you need to obtain basic statistics about memory usage per heap, together with current budget, +you can call function vmaGetHeapBudgets() and inspect structure #VmaBudget. +This is useful to keep track of memory usage and stay withing budget +(see also \ref staying_within_budget). +Example: + +\code +uint32_t heapIndex = ... + +VmaBudget budgets[VK_MAX_MEMORY_HEAPS]; +vmaGetHeapBudgets(allocator, budgets); + +printf("My heap currently has %u allocations taking %llu B,\n", + budgets[heapIndex].statistics.allocationCount, + budgets[heapIndex].statistics.allocationBytes); +printf("allocated out of %u Vulkan device memory blocks taking %llu B,\n", + budgets[heapIndex].statistics.blockCount, + budgets[heapIndex].statistics.blockBytes); +printf("Vulkan reports total usage %llu B with budget %llu B.\n", + budgets[heapIndex].usage, + budgets[heapIndex].budget); +\endcode + +You can query for more detailed statistics per memory heap, type, and totals, +including minimum and maximum allocation size and unused range size, +by calling function vmaCalculateStatistics() and inspecting structure #VmaTotalStatistics. +This function is slower though, as it has to traverse all the internal data structures, +so it should be used only for debugging purposes. + +You can query for statistics of a custom pool using function vmaGetPoolStatistics() +or vmaCalculatePoolStatistics(). + +You can query for information about a specific allocation using function vmaGetAllocationInfo(). +It fill structure #VmaAllocationInfo. + +\section statistics_json_dump JSON dump + +You can dump internal state of the allocator to a string in JSON format using function vmaBuildStatsString(). +The result is guaranteed to be correct JSON. +It uses ANSI encoding. +Any strings provided by user (see [Allocation names](@ref allocation_names)) +are copied as-is and properly escaped for JSON, so if they use UTF-8, ISO-8859-2 or any other encoding, +this JSON string can be treated as using this encoding. +It must be freed using function vmaFreeStatsString(). + +The format of this JSON string is not part of official documentation of the library, +but it will not change in backward-incompatible way without increasing library major version number +and appropriate mention in changelog. + +The JSON string contains all the data that can be obtained using vmaCalculateStatistics(). +It can also contain detailed map of allocated memory blocks and their regions - +free and occupied by allocations. +This allows e.g. to visualize the memory or assess fragmentation. + + +\page allocation_annotation Allocation names and user data + +\section allocation_user_data Allocation user data + +You can annotate allocations with your own information, e.g. for debugging purposes. +To do that, fill VmaAllocationCreateInfo::pUserData field when creating +an allocation. It is an opaque `void*` pointer. You can use it e.g. as a pointer, +some handle, index, key, ordinal number or any other value that would associate +the allocation with your custom metadata. +It it useful to identify appropriate data structures in your engine given #VmaAllocation, +e.g. when doing \ref defragmentation. + +\code +VkBufferCreateInfo bufCreateInfo = ... + +MyBufferMetadata* pMetadata = CreateBufferMetadata(); + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.pUserData = pMetadata; + +VkBuffer buffer; +VmaAllocation allocation; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buffer, &allocation, nullptr); +\endcode + +The pointer may be later retrieved as VmaAllocationInfo::pUserData: + +\code +VmaAllocationInfo allocInfo; +vmaGetAllocationInfo(allocator, allocation, &allocInfo); +MyBufferMetadata* pMetadata = (MyBufferMetadata*)allocInfo.pUserData; +\endcode + +It can also be changed using function vmaSetAllocationUserData(). + +Values of (non-zero) allocations' `pUserData` are printed in JSON report created by +vmaBuildStatsString() in hexadecimal form. + +\section allocation_names Allocation names + +An allocation can also carry a null-terminated string, giving a name to the allocation. +To set it, call vmaSetAllocationName(). +The library creates internal copy of the string, so the pointer you pass doesn't need +to be valid for whole lifetime of the allocation. You can free it after the call. + +\code +std::string imageName = "Texture: "; +imageName += fileName; +vmaSetAllocationName(allocator, allocation, imageName.c_str()); +\endcode + +The string can be later retrieved by inspecting VmaAllocationInfo::pName. +It is also printed in JSON report created by vmaBuildStatsString(). + +\note Setting string name to VMA allocation doesn't automatically set it to the Vulkan buffer or image created with it. +You must do it manually using an extension like VK_EXT_debug_utils, which is independent of this library. + + +\page virtual_allocator Virtual allocator + +As an extra feature, the core allocation algorithm of the library is exposed through a simple and convenient API of "virtual allocator". +It doesn't allocate any real GPU memory. It just keeps track of used and free regions of a "virtual block". +You can use it to allocate your own memory or other objects, even completely unrelated to Vulkan. +A common use case is sub-allocation of pieces of one large GPU buffer. + +\section virtual_allocator_creating_virtual_block Creating virtual block + +To use this functionality, there is no main "allocator" object. +You don't need to have #VmaAllocator object created. +All you need to do is to create a separate #VmaVirtualBlock object for each block of memory you want to be managed by the allocator: + +-# Fill in #VmaVirtualBlockCreateInfo structure. +-# Call vmaCreateVirtualBlock(). Get new #VmaVirtualBlock object. + +Example: + +\code +VmaVirtualBlockCreateInfo blockCreateInfo = {}; +blockCreateInfo.size = 1048576; // 1 MB + +VmaVirtualBlock block; +VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &block); +\endcode + +\section virtual_allocator_making_virtual_allocations Making virtual allocations + +#VmaVirtualBlock object contains internal data structure that keeps track of free and occupied regions +using the same code as the main Vulkan memory allocator. +Similarly to #VmaAllocation for standard GPU allocations, there is #VmaVirtualAllocation type +that represents an opaque handle to an allocation withing the virtual block. + +In order to make such allocation: + +-# Fill in #VmaVirtualAllocationCreateInfo structure. +-# Call vmaVirtualAllocate(). Get new #VmaVirtualAllocation object that represents the allocation. + You can also receive `VkDeviceSize offset` that was assigned to the allocation. + +Example: + +\code +VmaVirtualAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.size = 4096; // 4 KB + +VmaVirtualAllocation alloc; +VkDeviceSize offset; +res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc, &offset); +if(res == VK_SUCCESS) +{ + // Use the 4 KB of your memory starting at offset. +} +else +{ + // Allocation failed - no space for it could be found. Handle this error! +} +\endcode + +\section virtual_allocator_deallocation Deallocation + +When no longer needed, an allocation can be freed by calling vmaVirtualFree(). +You can only pass to this function an allocation that was previously returned by vmaVirtualAllocate() +called for the same #VmaVirtualBlock. + +When whole block is no longer needed, the block object can be released by calling vmaDestroyVirtualBlock(). +All allocations must be freed before the block is destroyed, which is checked internally by an assert. +However, if you don't want to call vmaVirtualFree() for each allocation, you can use vmaClearVirtualBlock() to free them all at once - +a feature not available in normal Vulkan memory allocator. Example: + +\code +vmaVirtualFree(block, alloc); +vmaDestroyVirtualBlock(block); +\endcode + +\section virtual_allocator_allocation_parameters Allocation parameters + +You can attach a custom pointer to each allocation by using vmaSetVirtualAllocationUserData(). +Its default value is null. +It can be used to store any data that needs to be associated with that allocation - e.g. an index, a handle, or a pointer to some +larger data structure containing more information. Example: + +\code +struct CustomAllocData +{ + std::string m_AllocName; +}; +CustomAllocData* allocData = new CustomAllocData(); +allocData->m_AllocName = "My allocation 1"; +vmaSetVirtualAllocationUserData(block, alloc, allocData); +\endcode + +The pointer can later be fetched, along with allocation offset and size, by passing the allocation handle to function +vmaGetVirtualAllocationInfo() and inspecting returned structure #VmaVirtualAllocationInfo. +If you allocated a new object to be used as the custom pointer, don't forget to delete that object before freeing the allocation! +Example: + +\code +VmaVirtualAllocationInfo allocInfo; +vmaGetVirtualAllocationInfo(block, alloc, &allocInfo); +delete (CustomAllocData*)allocInfo.pUserData; + +vmaVirtualFree(block, alloc); +\endcode + +\section virtual_allocator_alignment_and_units Alignment and units + +It feels natural to express sizes and offsets in bytes. +If an offset of an allocation needs to be aligned to a multiply of some number (e.g. 4 bytes), you can fill optional member +VmaVirtualAllocationCreateInfo::alignment to request it. Example: + +\code +VmaVirtualAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.size = 4096; // 4 KB +allocCreateInfo.alignment = 4; // Returned offset must be a multiply of 4 B + +VmaVirtualAllocation alloc; +res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc, nullptr); +\endcode + +Alignments of different allocations made from one block may vary. +However, if all alignments and sizes are always multiply of some size e.g. 4 B or `sizeof(MyDataStruct)`, +you can express all sizes, alignments, and offsets in multiples of that size instead of individual bytes. +It might be more convenient, but you need to make sure to use this new unit consistently in all the places: + +- VmaVirtualBlockCreateInfo::size +- VmaVirtualAllocationCreateInfo::size and VmaVirtualAllocationCreateInfo::alignment +- Using offset returned by vmaVirtualAllocate() or in VmaVirtualAllocationInfo::offset + +\section virtual_allocator_statistics Statistics + +You can obtain statistics of a virtual block using vmaGetVirtualBlockStatistics() +(to get brief statistics that are fast to calculate) +or vmaCalculateVirtualBlockStatistics() (to get more detailed statistics, slower to calculate). +The functions fill structures #VmaStatistics, #VmaDetailedStatistics respectively - same as used by the normal Vulkan memory allocator. +Example: + +\code +VmaStatistics stats; +vmaGetVirtualBlockStatistics(block, &stats); +printf("My virtual block has %llu bytes used by %u virtual allocations\n", + stats.allocationBytes, stats.allocationCount); +\endcode + +You can also request a full list of allocations and free regions as a string in JSON format by calling +vmaBuildVirtualBlockStatsString(). +Returned string must be later freed using vmaFreeVirtualBlockStatsString(). +The format of this string differs from the one returned by the main Vulkan allocator, but it is similar. + +\section virtual_allocator_additional_considerations Additional considerations + +The "virtual allocator" functionality is implemented on a level of individual memory blocks. +Keeping track of a whole collection of blocks, allocating new ones when out of free space, +deleting empty ones, and deciding which one to try first for a new allocation must be implemented by the user. + +Alternative allocation algorithms are supported, just like in custom pools of the real GPU memory. +See enum #VmaVirtualBlockCreateFlagBits to learn how to specify them (e.g. #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT). +You can find their description in chapter \ref custom_memory_pools. +Allocation strategies are also supported. +See enum #VmaVirtualAllocationCreateFlagBits to learn how to specify them (e.g. #VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT). + +Following features are supported only by the allocator of the real GPU memory and not by virtual allocations: +buffer-image granularity, `VMA_DEBUG_MARGIN`, `VMA_MIN_ALIGNMENT`. + + +\page debugging_memory_usage Debugging incorrect memory usage + +If you suspect a bug with memory usage, like usage of uninitialized memory or +memory being overwritten out of bounds of an allocation, +you can use debug features of this library to verify this. + +\section debugging_memory_usage_initialization Memory initialization + +If you experience a bug with incorrect and nondeterministic data in your program and you suspect uninitialized memory to be used, +you can enable automatic memory initialization to verify this. +To do it, define macro `VMA_DEBUG_INITIALIZE_ALLOCATIONS` to 1. + +\code +#define VMA_DEBUG_INITIALIZE_ALLOCATIONS 1 +#include "vk_mem_alloc.h" +\endcode + +It makes memory of new allocations initialized to bit pattern `0xDCDCDCDC`. +Before an allocation is destroyed, its memory is filled with bit pattern `0xEFEFEFEF`. +Memory is automatically mapped and unmapped if necessary. + +If you find these values while debugging your program, good chances are that you incorrectly +read Vulkan memory that is allocated but not initialized, or already freed, respectively. + +Memory initialization works only with memory types that are `HOST_VISIBLE` and with allocations that can be mapped. +It works also with dedicated allocations. + +\section debugging_memory_usage_margins Margins + +By default, allocations are laid out in memory blocks next to each other if possible +(considering required alignment, `bufferImageGranularity`, and `nonCoherentAtomSize`). + +![Allocations without margin](../gfx/Margins_1.png) + +Define macro `VMA_DEBUG_MARGIN` to some non-zero value (e.g. 16) to enforce specified +number of bytes as a margin after every allocation. + +\code +#define VMA_DEBUG_MARGIN 16 +#include "vk_mem_alloc.h" +\endcode + +![Allocations with margin](../gfx/Margins_2.png) + +If your bug goes away after enabling margins, it means it may be caused by memory +being overwritten outside of allocation boundaries. It is not 100% certain though. +Change in application behavior may also be caused by different order and distribution +of allocations across memory blocks after margins are applied. + +Margins work with all types of memory. + +Margin is applied only to allocations made out of memory blocks and not to dedicated +allocations, which have their own memory block of specific size. +It is thus not applied to allocations made using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT flag +or those automatically decided to put into dedicated allocations, e.g. due to its +large size or recommended by VK_KHR_dedicated_allocation extension. + +Margins appear in [JSON dump](@ref statistics_json_dump) as part of free space. + +Note that enabling margins increases memory usage and fragmentation. + +Margins do not apply to \ref virtual_allocator. + +\section debugging_memory_usage_corruption_detection Corruption detection + +You can additionally define macro `VMA_DEBUG_DETECT_CORRUPTION` to 1 to enable validation +of contents of the margins. + +\code +#define VMA_DEBUG_MARGIN 16 +#define VMA_DEBUG_DETECT_CORRUPTION 1 +#include "vk_mem_alloc.h" +\endcode + +When this feature is enabled, number of bytes specified as `VMA_DEBUG_MARGIN` +(it must be multiply of 4) after every allocation is filled with a magic number. +This idea is also know as "canary". +Memory is automatically mapped and unmapped if necessary. + +This number is validated automatically when the allocation is destroyed. +If it is not equal to the expected value, `VMA_ASSERT()` is executed. +It clearly means that either CPU or GPU overwritten the memory outside of boundaries of the allocation, +which indicates a serious bug. + +You can also explicitly request checking margins of all allocations in all memory blocks +that belong to specified memory types by using function vmaCheckCorruption(), +or in memory blocks that belong to specified custom pool, by using function +vmaCheckPoolCorruption(). + +Margin validation (corruption detection) works only for memory types that are +`HOST_VISIBLE` and `HOST_COHERENT`. + + +\page opengl_interop OpenGL Interop + +VMA provides some features that help with interoperability with OpenGL. + +\section opengl_interop_exporting_memory Exporting memory + +If you want to attach `VkExportMemoryAllocateInfoKHR` structure to `pNext` chain of memory allocations made by the library: + +It is recommended to create \ref custom_memory_pools for such allocations. +Define and fill in your `VkExportMemoryAllocateInfoKHR` structure and attach it to VmaPoolCreateInfo::pMemoryAllocateNext +while creating the custom pool. +Please note that the structure must remain alive and unchanged for the whole lifetime of the #VmaPool, +not only while creating it, as no copy of the structure is made, +but its original pointer is used for each allocation instead. + +If you want to export all memory allocated by the library from certain memory types, +also dedicated allocations or other allocations made from default pools, +an alternative solution is to fill in VmaAllocatorCreateInfo::pTypeExternalMemoryHandleTypes. +It should point to an array with `VkExternalMemoryHandleTypeFlagsKHR` to be automatically passed by the library +through `VkExportMemoryAllocateInfoKHR` on each allocation made from a specific memory type. +Please note that new versions of the library also support dedicated allocations created in custom pools. + +You should not mix these two methods in a way that allows to apply both to the same memory type. +Otherwise, `VkExportMemoryAllocateInfoKHR` structure would be attached twice to the `pNext` chain of `VkMemoryAllocateInfo`. + + +\section opengl_interop_custom_alignment Custom alignment + +Buffers or images exported to a different API like OpenGL may require a different alignment, +higher than the one used by the library automatically, queried from functions like `vkGetBufferMemoryRequirements`. +To impose such alignment: + +It is recommended to create \ref custom_memory_pools for such allocations. +Set VmaPoolCreateInfo::minAllocationAlignment member to the minimum alignment required for each allocation +to be made out of this pool. +The alignment actually used will be the maximum of this member and the alignment returned for the specific buffer or image +from a function like `vkGetBufferMemoryRequirements`, which is called by VMA automatically. + +If you want to create a buffer with a specific minimum alignment out of default pools, +use special function vmaCreateBufferWithAlignment(), which takes additional parameter `minAlignment`. + +Note the problem of alignment affects only resources placed inside bigger `VkDeviceMemory` blocks and not dedicated +allocations, as these, by definition, always have alignment = 0 because the resource is bound to the beginning of its dedicated block. +Contrary to Direct3D 12, Vulkan doesn't have a concept of alignment of the entire memory block passed on its allocation. + + +\page usage_patterns Recommended usage patterns + +Vulkan gives great flexibility in memory allocation. +This chapter shows the most common patterns. + +See also slides from talk: +[Sawicki, Adam. Advanced Graphics Techniques Tutorial: Memory management in Vulkan and DX12. Game Developers Conference, 2018](https://www.gdcvault.com/play/1025458/Advanced-Graphics-Techniques-Tutorial-New) + + +\section usage_patterns_gpu_only GPU-only resource + +When: +Any resources that you frequently write and read on GPU, +e.g. images used as color attachments (aka "render targets"), depth-stencil attachments, +images/buffers used as storage image/buffer (aka "Unordered Access View (UAV)"). + +What to do: +Let the library select the optimal memory type, which will likely have `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + +\code +VkImageCreateInfo imgCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; +imgCreateInfo.imageType = VK_IMAGE_TYPE_2D; +imgCreateInfo.extent.width = 3840; +imgCreateInfo.extent.height = 2160; +imgCreateInfo.extent.depth = 1; +imgCreateInfo.mipLevels = 1; +imgCreateInfo.arrayLayers = 1; +imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; +imgCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; +imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +imgCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; +allocCreateInfo.priority = 1.0f; + +VkImage img; +VmaAllocation alloc; +vmaCreateImage(allocator, &imgCreateInfo, &allocCreateInfo, &img, &alloc, nullptr); +\endcode + +Also consider: +Consider creating them as dedicated allocations using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, +especially if they are large or if you plan to destroy and recreate them with different sizes +e.g. when display resolution changes. +Prefer to create such resources first and all other GPU resources (like textures and vertex buffers) later. +When VK_EXT_memory_priority extension is enabled, it is also worth setting high priority to such allocation +to decrease chances to be evicted to system memory by the operating system. + +\section usage_patterns_staging_copy_upload Staging copy for upload + +When: +A "staging" buffer than you want to map and fill from CPU code, then use as a source od transfer +to some GPU resource. + +What to do: +Use flag #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT. +Let the library select the optimal memory type, which will always have `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`. + +\code +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = 65536; +bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + +VkBuffer buf; +VmaAllocation alloc; +VmaAllocationInfo allocInfo; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); + +... + +memcpy(allocInfo.pMappedData, myData, myDataSize); +\endcode + +Also consider: +You can map the allocation using vmaMapMemory() or you can create it as persistenly mapped +using #VMA_ALLOCATION_CREATE_MAPPED_BIT, as in the example above. + + +\section usage_patterns_readback Readback + +When: +Buffers for data written by or transferred from the GPU that you want to read back on the CPU, +e.g. results of some computations. + +What to do: +Use flag #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +Let the library select the optimal memory type, which will always have `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` +and `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`. + +\code +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = 65536; +bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + +VkBuffer buf; +VmaAllocation alloc; +VmaAllocationInfo allocInfo; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); + +... + +const float* downloadedData = (const float*)allocInfo.pMappedData; +\endcode + + +\section usage_patterns_advanced_data_uploading Advanced data uploading + +For resources that you frequently write on CPU via mapped pointer and +freqnently read on GPU e.g. as a uniform buffer (also called "dynamic"), multiple options are possible: + +-# Easiest solution is to have one copy of the resource in `HOST_VISIBLE` memory, + even if it means system RAM (not `DEVICE_LOCAL`) on systems with a discrete graphics card, + and make the device reach out to that resource directly. + - Reads performed by the device will then go through PCI Express bus. + The performace of this access may be limited, but it may be fine depending on the size + of this resource (whether it is small enough to quickly end up in GPU cache) and the sparsity + of access. +-# On systems with unified memory (e.g. AMD APU or Intel integrated graphics, mobile chips), + a memory type may be available that is both `HOST_VISIBLE` (available for mapping) and `DEVICE_LOCAL` + (fast to access from the GPU). Then, it is likely the best choice for such type of resource. +-# Systems with a discrete graphics card and separate video memory may or may not expose + a memory type that is both `HOST_VISIBLE` and `DEVICE_LOCAL`, also known as Base Address Register (BAR). + If they do, it represents a piece of VRAM (or entire VRAM, if ReBAR is enabled in the motherboard BIOS) + that is available to CPU for mapping. + - Writes performed by the host to that memory go through PCI Express bus. + The performance of these writes may be limited, but it may be fine, especially on PCIe 4.0, + as long as rules of using uncached and write-combined memory are followed - only sequential writes and no reads. +-# Finally, you may need or prefer to create a separate copy of the resource in `DEVICE_LOCAL` memory, + a separate "staging" copy in `HOST_VISIBLE` memory and perform an explicit transfer command between them. + +Thankfully, VMA offers an aid to create and use such resources in the the way optimal +for the current Vulkan device. To help the library make the best choice, +use flag #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT together with +#VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT. +It will then prefer a memory type that is both `DEVICE_LOCAL` and `HOST_VISIBLE` (integrated memory or BAR), +but if no such memory type is available or allocation from it fails +(PC graphics cards have only 256 MB of BAR by default, unless ReBAR is supported and enabled in BIOS), +it will fall back to `DEVICE_LOCAL` memory for fast GPU access. +It is then up to you to detect that the allocation ended up in a memory type that is not `HOST_VISIBLE`, +so you need to create another "staging" allocation and perform explicit transfers. + +\code +VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; +bufCreateInfo.size = 65536; +bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + +VkBuffer buf; +VmaAllocation alloc; +VmaAllocationInfo allocInfo; +vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); + +VkMemoryPropertyFlags memPropFlags; +vmaGetAllocationMemoryProperties(allocator, alloc, &memPropFlags); + +if(memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) +{ + // Allocation ended up in a mappable memory and is already mapped - write to it directly. + + // [Executed in runtime]: + memcpy(allocInfo.pMappedData, myData, myDataSize); +} +else +{ + // Allocation ended up in a non-mappable memory - need to transfer. + VkBufferCreateInfo stagingBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + stagingBufCreateInfo.size = 65536; + stagingBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + VmaAllocationCreateInfo stagingAllocCreateInfo = {}; + stagingAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + stagingAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + + VkBuffer stagingBuf; + VmaAllocation stagingAlloc; + VmaAllocationInfo stagingAllocInfo; + vmaCreateBuffer(allocator, &stagingBufCreateInfo, &stagingAllocCreateInfo, + &stagingBuf, &stagingAlloc, stagingAllocInfo); + + // [Executed in runtime]: + memcpy(stagingAllocInfo.pMappedData, myData, myDataSize); + //vkCmdPipelineBarrier: VK_ACCESS_HOST_WRITE_BIT --> VK_ACCESS_TRANSFER_READ_BIT + VkBufferCopy bufCopy = { + 0, // srcOffset + 0, // dstOffset, + myDataSize); // size + vkCmdCopyBuffer(cmdBuf, stagingBuf, buf, 1, &bufCopy); +} +\endcode + +\section usage_patterns_other_use_cases Other use cases + +Here are some other, less obvious use cases and their recommended settings: + +- An image that is used only as transfer source and destination, but it should stay on the device, + as it is used to temporarily store a copy of some texture, e.g. from the current to the next frame, + for temporal antialiasing or other temporal effects. + - Use `VkImageCreateInfo::usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT` + - Use VmaAllocationCreateInfo::usage = #VMA_MEMORY_USAGE_AUTO +- An image that is used only as transfer source and destination, but it should be placed + in the system RAM despite it doesn't need to be mapped, because it serves as a "swap" copy to evict + least recently used textures from VRAM. + - Use `VkImageCreateInfo::usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT` + - Use VmaAllocationCreateInfo::usage = #VMA_MEMORY_USAGE_AUTO_PREFER_HOST, + as VMA needs a hint here to differentiate from the previous case. +- A buffer that you want to map and write from the CPU, directly read from the GPU + (e.g. as a uniform or vertex buffer), but you have a clear preference to place it in device or + host memory due to its large size. + - Use `VkBufferCreateInfo::usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT` + - Use VmaAllocationCreateInfo::usage = #VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE or #VMA_MEMORY_USAGE_AUTO_PREFER_HOST + - Use VmaAllocationCreateInfo::flags = #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT + + +\page configuration Configuration + +Please check "CONFIGURATION SECTION" in the code to find macros that you can define +before each include of this file or change directly in this file to provide +your own implementation of basic facilities like assert, `min()` and `max()` functions, +mutex, atomic etc. +The library uses its own implementation of containers by default, but you can switch to using +STL containers instead. + +For example, define `VMA_ASSERT(expr)` before including the library to provide +custom implementation of the assertion, compatible with your project. +By default it is defined to standard C `assert(expr)` in `_DEBUG` configuration +and empty otherwise. + +\section config_Vulkan_functions Pointers to Vulkan functions + +There are multiple ways to import pointers to Vulkan functions in the library. +In the simplest case you don't need to do anything. +If the compilation or linking of your program or the initialization of the #VmaAllocator +doesn't work for you, you can try to reconfigure it. + +First, the allocator tries to fetch pointers to Vulkan functions linked statically, +like this: + +\code +m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory; +\endcode + +If you want to disable this feature, set configuration macro: `#define VMA_STATIC_VULKAN_FUNCTIONS 0`. + +Second, you can provide the pointers yourself by setting member VmaAllocatorCreateInfo::pVulkanFunctions. +You can fetch them e.g. using functions `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` or +by using a helper library like [volk](https://github.com/zeux/volk). + +Third, VMA tries to fetch remaining pointers that are still null by calling +`vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` on its own. +You need to only fill in VmaVulkanFunctions::vkGetInstanceProcAddr and VmaVulkanFunctions::vkGetDeviceProcAddr. +Other pointers will be fetched automatically. +If you want to disable this feature, set configuration macro: `#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0`. + +Finally, all the function pointers required by the library (considering selected +Vulkan version and enabled extensions) are checked with `VMA_ASSERT` if they are not null. + + +\section custom_memory_allocator Custom host memory allocator + +If you use custom allocator for CPU memory rather than default operator `new` +and `delete` from C++, you can make this library using your allocator as well +by filling optional member VmaAllocatorCreateInfo::pAllocationCallbacks. These +functions will be passed to Vulkan, as well as used by the library itself to +make any CPU-side allocations. + +\section allocation_callbacks Device memory allocation callbacks + +The library makes calls to `vkAllocateMemory()` and `vkFreeMemory()` internally. +You can setup callbacks to be informed about these calls, e.g. for the purpose +of gathering some statistics. To do it, fill optional member +VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. + +\section heap_memory_limit Device heap memory limit + +When device memory of certain heap runs out of free space, new allocations may +fail (returning error code) or they may succeed, silently pushing some existing_ +memory blocks from GPU VRAM to system RAM (which degrades performance). This +behavior is implementation-dependent - it depends on GPU vendor and graphics +driver. + +On AMD cards it can be controlled while creating Vulkan device object by using +VK_AMD_memory_overallocation_behavior extension, if available. + +Alternatively, if you want to test how your program behaves with limited amount of Vulkan device +memory available without switching your graphics card to one that really has +smaller VRAM, you can use a feature of this library intended for this purpose. +To do it, fill optional member VmaAllocatorCreateInfo::pHeapSizeLimit. + + + +\page vk_khr_dedicated_allocation VK_KHR_dedicated_allocation + +VK_KHR_dedicated_allocation is a Vulkan extension which can be used to improve +performance on some GPUs. It augments Vulkan API with possibility to query +driver whether it prefers particular buffer or image to have its own, dedicated +allocation (separate `VkDeviceMemory` block) for better efficiency - to be able +to do some internal optimizations. The extension is supported by this library. +It will be used automatically when enabled. + +It has been promoted to core Vulkan 1.1, so if you use eligible Vulkan version +and inform VMA about it by setting VmaAllocatorCreateInfo::vulkanApiVersion, +you are all set. + +Otherwise, if you want to use it as an extension: + +1 . When creating Vulkan device, check if following 2 device extensions are +supported (call `vkEnumerateDeviceExtensionProperties()`). +If yes, enable them (fill `VkDeviceCreateInfo::ppEnabledExtensionNames`). + +- VK_KHR_get_memory_requirements2 +- VK_KHR_dedicated_allocation + +If you enabled these extensions: + +2 . Use #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag when creating +your #VmaAllocator to inform the library that you enabled required extensions +and you want the library to use them. + +\code +allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; + +vmaCreateAllocator(&allocatorInfo, &allocator); +\endcode + +That is all. The extension will be automatically used whenever you create a +buffer using vmaCreateBuffer() or image using vmaCreateImage(). + +When using the extension together with Vulkan Validation Layer, you will receive +warnings like this: + +_vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer._ + +It is OK, you should just ignore it. It happens because you use function +`vkGetBufferMemoryRequirements2KHR()` instead of standard +`vkGetBufferMemoryRequirements()`, while the validation layer seems to be +unaware of it. + +To learn more about this extension, see: + +- [VK_KHR_dedicated_allocation in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap50.html#VK_KHR_dedicated_allocation) +- [VK_KHR_dedicated_allocation unofficial manual](http://asawicki.info/articles/VK_KHR_dedicated_allocation.php5) + + + +\page vk_ext_memory_priority VK_EXT_memory_priority + +VK_EXT_memory_priority is a device extension that allows to pass additional "priority" +value to Vulkan memory allocations that the implementation may use prefer certain +buffers and images that are critical for performance to stay in device-local memory +in cases when the memory is over-subscribed, while some others may be moved to the system memory. + +VMA offers convenient usage of this extension. +If you enable it, you can pass "priority" parameter when creating allocations or custom pools +and the library automatically passes the value to Vulkan using this extension. + +If you want to use this extension in connection with VMA, follow these steps: + +\section vk_ext_memory_priority_initialization Initialization + +1) Call `vkEnumerateDeviceExtensionProperties` for the physical device. +Check if the extension is supported - if returned array of `VkExtensionProperties` contains "VK_EXT_memory_priority". + +2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. +Attach additional structure `VkPhysicalDeviceMemoryPriorityFeaturesEXT` to `VkPhysicalDeviceFeatures2::pNext` to be returned. +Check if the device feature is really supported - check if `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority` is true. + +3) While creating device with `vkCreateDevice`, enable this extension - add "VK_EXT_memory_priority" +to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. + +4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. +Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. +Enable this device feature - attach additional structure `VkPhysicalDeviceMemoryPriorityFeaturesEXT` to +`VkPhysicalDeviceFeatures2::pNext` chain and set its member `memoryPriority` to `VK_TRUE`. + +5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you +have enabled this extension and feature - add #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT +to VmaAllocatorCreateInfo::flags. + +\section vk_ext_memory_priority_usage Usage + +When using this extension, you should initialize following member: + +- VmaAllocationCreateInfo::priority when creating a dedicated allocation with #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. +- VmaPoolCreateInfo::priority when creating a custom pool. + +It should be a floating-point value between `0.0f` and `1.0f`, where recommended default is `0.5f`. +Memory allocated with higher value can be treated by the Vulkan implementation as higher priority +and so it can have lower chances of being pushed out to system memory, experiencing degraded performance. + +It might be a good idea to create performance-critical resources like color-attachment or depth-stencil images +as dedicated and set high priority to them. For example: + +\code +VkImageCreateInfo imgCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; +imgCreateInfo.imageType = VK_IMAGE_TYPE_2D; +imgCreateInfo.extent.width = 3840; +imgCreateInfo.extent.height = 2160; +imgCreateInfo.extent.depth = 1; +imgCreateInfo.mipLevels = 1; +imgCreateInfo.arrayLayers = 1; +imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; +imgCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; +imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +imgCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + +VmaAllocationCreateInfo allocCreateInfo = {}; +allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; +allocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; +allocCreateInfo.priority = 1.0f; + +VkImage img; +VmaAllocation alloc; +vmaCreateImage(allocator, &imgCreateInfo, &allocCreateInfo, &img, &alloc, nullptr); +\endcode + +`priority` member is ignored in the following situations: + +- Allocations created in custom pools: They inherit the priority, along with all other allocation parameters + from the parametrs passed in #VmaPoolCreateInfo when the pool was created. +- Allocations created in default pools: They inherit the priority from the parameters + VMA used when creating default pools, which means `priority == 0.5f`. + + +\page vk_amd_device_coherent_memory VK_AMD_device_coherent_memory + +VK_AMD_device_coherent_memory is a device extension that enables access to +additional memory types with `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and +`VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flag. It is useful mostly for +allocation of buffers intended for writing "breadcrumb markers" in between passes +or draw calls, which in turn are useful for debugging GPU crash/hang/TDR cases. + +When the extension is available but has not been enabled, Vulkan physical device +still exposes those memory types, but their usage is forbidden. VMA automatically +takes care of that - it returns `VK_ERROR_FEATURE_NOT_PRESENT` when an attempt +to allocate memory of such type is made. + +If you want to use this extension in connection with VMA, follow these steps: + +\section vk_amd_device_coherent_memory_initialization Initialization + +1) Call `vkEnumerateDeviceExtensionProperties` for the physical device. +Check if the extension is supported - if returned array of `VkExtensionProperties` contains "VK_AMD_device_coherent_memory". + +2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. +Attach additional structure `VkPhysicalDeviceCoherentMemoryFeaturesAMD` to `VkPhysicalDeviceFeatures2::pNext` to be returned. +Check if the device feature is really supported - check if `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true. + +3) While creating device with `vkCreateDevice`, enable this extension - add "VK_AMD_device_coherent_memory" +to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. + +4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. +Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. +Enable this device feature - attach additional structure `VkPhysicalDeviceCoherentMemoryFeaturesAMD` to +`VkPhysicalDeviceFeatures2::pNext` and set its member `deviceCoherentMemory` to `VK_TRUE`. + +5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you +have enabled this extension and feature - add #VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT +to VmaAllocatorCreateInfo::flags. + +\section vk_amd_device_coherent_memory_usage Usage + +After following steps described above, you can create VMA allocations and custom pools +out of the special `DEVICE_COHERENT` and `DEVICE_UNCACHED` memory types on eligible +devices. There are multiple ways to do it, for example: + +- You can request or prefer to allocate out of such memory types by adding + `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` to VmaAllocationCreateInfo::requiredFlags + or VmaAllocationCreateInfo::preferredFlags. Those flags can be freely mixed with + other ways of \ref choosing_memory_type, like setting VmaAllocationCreateInfo::usage. +- If you manually found memory type index to use for this purpose, force allocation + from this specific index by setting VmaAllocationCreateInfo::memoryTypeBits `= 1u << index`. + +\section vk_amd_device_coherent_memory_more_information More information + +To learn more about this extension, see [VK_AMD_device_coherent_memory in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_device_coherent_memory.html) + +Example use of this extension can be found in the code of the sample and test suite +accompanying this library. + + +\page enabling_buffer_device_address Enabling buffer device address + +Device extension VK_KHR_buffer_device_address +allow to fetch raw GPU pointer to a buffer and pass it for usage in a shader code. +It has been promoted to core Vulkan 1.2. + +If you want to use this feature in connection with VMA, follow these steps: + +\section enabling_buffer_device_address_initialization Initialization + +1) (For Vulkan version < 1.2) Call `vkEnumerateDeviceExtensionProperties` for the physical device. +Check if the extension is supported - if returned array of `VkExtensionProperties` contains +"VK_KHR_buffer_device_address". + +2) Call `vkGetPhysicalDeviceFeatures2` for the physical device instead of old `vkGetPhysicalDeviceFeatures`. +Attach additional structure `VkPhysicalDeviceBufferDeviceAddressFeatures*` to `VkPhysicalDeviceFeatures2::pNext` to be returned. +Check if the device feature is really supported - check if `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress` is true. + +3) (For Vulkan version < 1.2) While creating device with `vkCreateDevice`, enable this extension - add +"VK_KHR_buffer_device_address" to the list passed as `VkDeviceCreateInfo::ppEnabledExtensionNames`. + +4) While creating the device, also don't set `VkDeviceCreateInfo::pEnabledFeatures`. +Fill in `VkPhysicalDeviceFeatures2` structure instead and pass it as `VkDeviceCreateInfo::pNext`. +Enable this device feature - attach additional structure `VkPhysicalDeviceBufferDeviceAddressFeatures*` to +`VkPhysicalDeviceFeatures2::pNext` and set its member `bufferDeviceAddress` to `VK_TRUE`. + +5) While creating #VmaAllocator with vmaCreateAllocator() inform VMA that you +have enabled this feature - add #VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT +to VmaAllocatorCreateInfo::flags. + +\section enabling_buffer_device_address_usage Usage + +After following steps described above, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*` using VMA. +The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT*` to +allocated memory blocks wherever it might be needed. + +Please note that the library supports only `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT*`. +The second part of this functionality related to "capture and replay" is not supported, +as it is intended for usage in debugging tools like RenderDoc, not in everyday Vulkan usage. + +\section enabling_buffer_device_address_more_information More information + +To learn more about this extension, see [VK_KHR_buffer_device_address in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap46.html#VK_KHR_buffer_device_address) + +Example use of this extension can be found in the code of the sample and test suite +accompanying this library. + +\page general_considerations General considerations + +\section general_considerations_thread_safety Thread safety + +- The library has no global state, so separate #VmaAllocator objects can be used + independently. + There should be no need to create multiple such objects though - one per `VkDevice` is enough. +- By default, all calls to functions that take #VmaAllocator as first parameter + are safe to call from multiple threads simultaneously because they are + synchronized internally when needed. + This includes allocation and deallocation from default memory pool, as well as custom #VmaPool. +- When the allocator is created with #VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT + flag, calls to functions that take such #VmaAllocator object must be + synchronized externally. +- Access to a #VmaAllocation object must be externally synchronized. For example, + you must not call vmaGetAllocationInfo() and vmaMapMemory() from different + threads at the same time if you pass the same #VmaAllocation object to these + functions. +- #VmaVirtualBlock is not safe to be used from multiple threads simultaneously. + +\section general_considerations_versioning_and_compatibility Versioning and compatibility + +The library uses [**Semantic Versioning**](https://semver.org/), +which means version numbers follow convention: Major.Minor.Patch (e.g. 2.3.0), where: + +- Incremented Patch version means a release is backward- and forward-compatible, + introducing only some internal improvements, bug fixes, optimizations etc. + or changes that are out of scope of the official API described in this documentation. +- Incremented Minor version means a release is backward-compatible, + so existing code that uses the library should continue to work, while some new + symbols could have been added: new structures, functions, new values in existing + enums and bit flags, new structure members, but not new function parameters. +- Incrementing Major version means a release could break some backward compatibility. + +All changes between official releases are documented in file "CHANGELOG.md". + +\warning Backward compatiblity is considered on the level of C++ source code, not binary linkage. +Adding new members to existing structures is treated as backward compatible if initializing +the new members to binary zero results in the old behavior. +You should always fully initialize all library structures to zeros and not rely on their +exact binary size. + +\section general_considerations_validation_layer_warnings Validation layer warnings + +When using this library, you can meet following types of warnings issued by +Vulkan validation layer. They don't necessarily indicate a bug, so you may need +to just ignore them. + +- *vkBindBufferMemory(): Binding memory to buffer 0xeb8e4 but vkGetBufferMemoryRequirements() has not been called on that buffer.* + - It happens when VK_KHR_dedicated_allocation extension is enabled. + `vkGetBufferMemoryRequirements2KHR` function is used instead, while validation layer seems to be unaware of it. +- *Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used.* + - It happens when you map a buffer or image, because the library maps entire + `VkDeviceMemory` block, where different types of images and buffers may end + up together, especially on GPUs with unified memory like Intel. +- *Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug.* + - It may happen when you use [defragmentation](@ref defragmentation). + +\section general_considerations_allocation_algorithm Allocation algorithm + +The library uses following algorithm for allocation, in order: + +-# Try to find free range of memory in existing blocks. +-# If failed, try to create a new block of `VkDeviceMemory`, with preferred block size. +-# If failed, try to create such block with size / 2, size / 4, size / 8. +-# If failed, try to allocate separate `VkDeviceMemory` for this allocation, + just like when you use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. +-# If failed, choose other memory type that meets the requirements specified in + VmaAllocationCreateInfo and go to point 1. +-# If failed, return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + +\section general_considerations_features_not_supported Features not supported + +Features deliberately excluded from the scope of this library: + +-# **Data transfer.** Uploading (streaming) and downloading data of buffers and images + between CPU and GPU memory and related synchronization is responsibility of the user. + Defining some "texture" object that would automatically stream its data from a + staging copy in CPU memory to GPU memory would rather be a feature of another, + higher-level library implemented on top of VMA. + VMA doesn't record any commands to a `VkCommandBuffer`. It just allocates memory. +-# **Recreation of buffers and images.** Although the library has functions for + buffer and image creation: vmaCreateBuffer(), vmaCreateImage(), you need to + recreate these objects yourself after defragmentation. That is because the big + structures `VkBufferCreateInfo`, `VkImageCreateInfo` are not stored in + #VmaAllocation object. +-# **Handling CPU memory allocation failures.** When dynamically creating small C++ + objects in CPU memory (not Vulkan memory), allocation failures are not checked + and handled gracefully, because that would complicate code significantly and + is usually not needed in desktop PC applications anyway. + Success of an allocation is just checked with an assert. +-# **Code free of any compiler warnings.** Maintaining the library to compile and + work correctly on so many different platforms is hard enough. Being free of + any warnings, on any version of any compiler, is simply not feasible. + There are many preprocessor macros that make some variables unused, function parameters unreferenced, + or conditional expressions constant in some configurations. + The code of this library should not be bigger or more complicated just to silence these warnings. + It is recommended to disable such warnings instead. +-# This is a C++ library with C interface. **Bindings or ports to any other programming languages** are welcome as external projects but + are not going to be included into this repository. +*/ diff --git a/libraries/ZVulkan/include/zvulkan/volk/volk.h b/libraries/ZVulkan/include/zvulkan/volk/volk.h new file mode 100644 index 00000000000..47fbed2391d --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/volk/volk.h @@ -0,0 +1,1985 @@ +/** + * volk + * + * Copyright (C) 2018-2023, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at https://github.com/zeux/volk + * + * This library is distributed under the MIT License. See notice at the end of this file. + */ +/* clang-format off */ +#ifndef VOLK_H_ +#define VOLK_H_ + +#if defined(VULKAN_H_) && !defined(VK_NO_PROTOTYPES) +# error To use volk, you need to define VK_NO_PROTOTYPES before including vulkan.h +#endif + +/* VOLK_GENERATE_VERSION_DEFINE */ +#define VOLK_HEADER_VERSION 270 +/* VOLK_GENERATE_VERSION_DEFINE */ + +#ifndef VK_NO_PROTOTYPES +# define VK_NO_PROTOTYPES +#endif + +#ifndef VULKAN_H_ +# ifdef VOLK_VULKAN_H_PATH +# include VOLK_VULKAN_H_PATH +# elif defined(VK_USE_PLATFORM_WIN32_KHR) +# include +# include + + /* When VK_USE_PLATFORM_WIN32_KHR is defined, instead of including vulkan.h directly, we include individual parts of the SDK + * This is necessary to avoid including which is very heavy - it takes 200ms to parse without WIN32_LEAN_AND_MEAN + * and 100ms to parse with it. vulkan_win32.h only needs a few symbols that are easy to redefine ourselves. + */ + typedef unsigned long DWORD; + typedef const wchar_t* LPCWSTR; + typedef void* HANDLE; + typedef struct HINSTANCE__* HINSTANCE; + typedef struct HWND__* HWND; + typedef struct HMONITOR__* HMONITOR; + typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES; + +# include + +# ifdef VK_ENABLE_BETA_EXTENSIONS +# include +# endif +# else +# include +# endif +#endif + +/* Disable several extensions on earlier SDKs because later SDKs introduce a backwards incompatible change to function signatures */ +#if VK_HEADER_VERSION < 140 +# undef VK_NVX_image_view_handle +#endif +#if VK_HEADER_VERSION < 184 +# undef VK_HUAWEI_subpass_shading +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct VolkDeviceTable; + +/** + * Initialize library by loading Vulkan loader; call this function before creating the Vulkan instance. + * + * Returns VK_SUCCESS on success and VK_ERROR_INITIALIZATION_FAILED otherwise. + */ +VkResult volkInitialize(void); + +/** + * Initialize library by providing a custom handler to load global symbols. + * + * This function can be used instead of volkInitialize. + * The handler function pointer will be asked to load global Vulkan symbols which require no instance + * (such as vkCreateInstance, vkEnumerateInstance* and vkEnumerateInstanceVersion if available). + */ +void volkInitializeCustom(PFN_vkGetInstanceProcAddr handler); + +/** + * Finalize library by unloading Vulkan loader and resetting global symbols to NULL. + */ +void volkFinalize(void); + +/** + * Get Vulkan instance version supported by the Vulkan loader, or 0 if Vulkan isn't supported + * + * Returns 0 if volkInitialize wasn't called or failed. + */ +uint32_t volkGetInstanceVersion(void); + +/** + * Load global function pointers using application-created VkInstance; call this function after creating the Vulkan instance. + */ +void volkLoadInstance(VkInstance instance); + +/** + * Load global function pointers using application-created VkInstance; call this function after creating the Vulkan instance. + * Skips loading device-based function pointers, requires usage of volkLoadDevice afterwards. + */ +void volkLoadInstanceOnly(VkInstance instance); + +/** + * Load global function pointers using application-created VkDevice; call this function after creating the Vulkan device. + * + * Note: this is not suitable for applications that want to use multiple VkDevice objects concurrently. + */ +void volkLoadDevice(VkDevice device); + +/** + * Return last VkInstance for which global function pointers have been loaded via volkLoadInstance(), + * or VK_NULL_HANDLE if volkLoadInstance() has not been called. + */ +VkInstance volkGetLoadedInstance(void); + +/** + * Return last VkDevice for which global function pointers have been loaded via volkLoadDevice(), + * or VK_NULL_HANDLE if volkLoadDevice() has not been called. + */ +VkDevice volkGetLoadedDevice(void); + +/** + * Load function pointers using application-created VkDevice into a table. + * Application should use function pointers from that table instead of using global function pointers. + */ +void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device); + +/** + * Device-specific function pointer table + */ +struct VolkDeviceTable +{ + /* VOLK_GENERATE_DEVICE_TABLE */ +#if defined(VK_VERSION_1_0) + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; + PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; + PFN_vkAllocateMemory vkAllocateMemory; + PFN_vkBeginCommandBuffer vkBeginCommandBuffer; + PFN_vkBindBufferMemory vkBindBufferMemory; + PFN_vkBindImageMemory vkBindImageMemory; + PFN_vkCmdBeginQuery vkCmdBeginQuery; + PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; + PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; + PFN_vkCmdBindPipeline vkCmdBindPipeline; + PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; + PFN_vkCmdBlitImage vkCmdBlitImage; + PFN_vkCmdClearAttachments vkCmdClearAttachments; + PFN_vkCmdClearColorImage vkCmdClearColorImage; + PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; + PFN_vkCmdCopyBuffer vkCmdCopyBuffer; + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; + PFN_vkCmdCopyImage vkCmdCopyImage; + PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; + PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; + PFN_vkCmdDispatch vkCmdDispatch; + PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; + PFN_vkCmdDraw vkCmdDraw; + PFN_vkCmdDrawIndexed vkCmdDrawIndexed; + PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; + PFN_vkCmdDrawIndirect vkCmdDrawIndirect; + PFN_vkCmdEndQuery vkCmdEndQuery; + PFN_vkCmdEndRenderPass vkCmdEndRenderPass; + PFN_vkCmdExecuteCommands vkCmdExecuteCommands; + PFN_vkCmdFillBuffer vkCmdFillBuffer; + PFN_vkCmdNextSubpass vkCmdNextSubpass; + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; + PFN_vkCmdPushConstants vkCmdPushConstants; + PFN_vkCmdResetEvent vkCmdResetEvent; + PFN_vkCmdResetQueryPool vkCmdResetQueryPool; + PFN_vkCmdResolveImage vkCmdResolveImage; + PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; + PFN_vkCmdSetDepthBias vkCmdSetDepthBias; + PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; + PFN_vkCmdSetEvent vkCmdSetEvent; + PFN_vkCmdSetLineWidth vkCmdSetLineWidth; + PFN_vkCmdSetScissor vkCmdSetScissor; + PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; + PFN_vkCmdSetStencilReference vkCmdSetStencilReference; + PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; + PFN_vkCmdSetViewport vkCmdSetViewport; + PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; + PFN_vkCmdWaitEvents vkCmdWaitEvents; + PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; + PFN_vkCreateBuffer vkCreateBuffer; + PFN_vkCreateBufferView vkCreateBufferView; + PFN_vkCreateCommandPool vkCreateCommandPool; + PFN_vkCreateComputePipelines vkCreateComputePipelines; + PFN_vkCreateDescriptorPool vkCreateDescriptorPool; + PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; + PFN_vkCreateEvent vkCreateEvent; + PFN_vkCreateFence vkCreateFence; + PFN_vkCreateFramebuffer vkCreateFramebuffer; + PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; + PFN_vkCreateImage vkCreateImage; + PFN_vkCreateImageView vkCreateImageView; + PFN_vkCreatePipelineCache vkCreatePipelineCache; + PFN_vkCreatePipelineLayout vkCreatePipelineLayout; + PFN_vkCreateQueryPool vkCreateQueryPool; + PFN_vkCreateRenderPass vkCreateRenderPass; + PFN_vkCreateSampler vkCreateSampler; + PFN_vkCreateSemaphore vkCreateSemaphore; + PFN_vkCreateShaderModule vkCreateShaderModule; + PFN_vkDestroyBuffer vkDestroyBuffer; + PFN_vkDestroyBufferView vkDestroyBufferView; + PFN_vkDestroyCommandPool vkDestroyCommandPool; + PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; + PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; + PFN_vkDestroyDevice vkDestroyDevice; + PFN_vkDestroyEvent vkDestroyEvent; + PFN_vkDestroyFence vkDestroyFence; + PFN_vkDestroyFramebuffer vkDestroyFramebuffer; + PFN_vkDestroyImage vkDestroyImage; + PFN_vkDestroyImageView vkDestroyImageView; + PFN_vkDestroyPipeline vkDestroyPipeline; + PFN_vkDestroyPipelineCache vkDestroyPipelineCache; + PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; + PFN_vkDestroyQueryPool vkDestroyQueryPool; + PFN_vkDestroyRenderPass vkDestroyRenderPass; + PFN_vkDestroySampler vkDestroySampler; + PFN_vkDestroySemaphore vkDestroySemaphore; + PFN_vkDestroyShaderModule vkDestroyShaderModule; + PFN_vkDeviceWaitIdle vkDeviceWaitIdle; + PFN_vkEndCommandBuffer vkEndCommandBuffer; + PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; + PFN_vkFreeCommandBuffers vkFreeCommandBuffers; + PFN_vkFreeDescriptorSets vkFreeDescriptorSets; + PFN_vkFreeMemory vkFreeMemory; + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; + PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; + PFN_vkGetDeviceQueue vkGetDeviceQueue; + PFN_vkGetEventStatus vkGetEventStatus; + PFN_vkGetFenceStatus vkGetFenceStatus; + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; + PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; + PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; + PFN_vkGetPipelineCacheData vkGetPipelineCacheData; + PFN_vkGetQueryPoolResults vkGetQueryPoolResults; + PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; + PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; + PFN_vkMapMemory vkMapMemory; + PFN_vkMergePipelineCaches vkMergePipelineCaches; + PFN_vkQueueBindSparse vkQueueBindSparse; + PFN_vkQueueSubmit vkQueueSubmit; + PFN_vkQueueWaitIdle vkQueueWaitIdle; + PFN_vkResetCommandBuffer vkResetCommandBuffer; + PFN_vkResetCommandPool vkResetCommandPool; + PFN_vkResetDescriptorPool vkResetDescriptorPool; + PFN_vkResetEvent vkResetEvent; + PFN_vkResetFences vkResetFences; + PFN_vkSetEvent vkSetEvent; + PFN_vkUnmapMemory vkUnmapMemory; + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; + PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + PFN_vkBindBufferMemory2 vkBindBufferMemory2; + PFN_vkBindImageMemory2 vkBindImageMemory2; + PFN_vkCmdDispatchBase vkCmdDispatchBase; + PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; + PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; + PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; + PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; + PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; + PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; + PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; + PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; + PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; + PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; + PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; + PFN_vkTrimCommandPool vkTrimCommandPool; + PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; + PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; + PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; + PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; + PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; + PFN_vkCreateRenderPass2 vkCreateRenderPass2; + PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; + PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; + PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; + PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; + PFN_vkResetQueryPool vkResetQueryPool; + PFN_vkSignalSemaphore vkSignalSemaphore; + PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) + PFN_vkCmdBeginRendering vkCmdBeginRendering; + PFN_vkCmdBindVertexBuffers2 vkCmdBindVertexBuffers2; + PFN_vkCmdBlitImage2 vkCmdBlitImage2; + PFN_vkCmdCopyBuffer2 vkCmdCopyBuffer2; + PFN_vkCmdCopyBufferToImage2 vkCmdCopyBufferToImage2; + PFN_vkCmdCopyImage2 vkCmdCopyImage2; + PFN_vkCmdCopyImageToBuffer2 vkCmdCopyImageToBuffer2; + PFN_vkCmdEndRendering vkCmdEndRendering; + PFN_vkCmdPipelineBarrier2 vkCmdPipelineBarrier2; + PFN_vkCmdResetEvent2 vkCmdResetEvent2; + PFN_vkCmdResolveImage2 vkCmdResolveImage2; + PFN_vkCmdSetCullMode vkCmdSetCullMode; + PFN_vkCmdSetDepthBiasEnable vkCmdSetDepthBiasEnable; + PFN_vkCmdSetDepthBoundsTestEnable vkCmdSetDepthBoundsTestEnable; + PFN_vkCmdSetDepthCompareOp vkCmdSetDepthCompareOp; + PFN_vkCmdSetDepthTestEnable vkCmdSetDepthTestEnable; + PFN_vkCmdSetDepthWriteEnable vkCmdSetDepthWriteEnable; + PFN_vkCmdSetEvent2 vkCmdSetEvent2; + PFN_vkCmdSetFrontFace vkCmdSetFrontFace; + PFN_vkCmdSetPrimitiveRestartEnable vkCmdSetPrimitiveRestartEnable; + PFN_vkCmdSetPrimitiveTopology vkCmdSetPrimitiveTopology; + PFN_vkCmdSetRasterizerDiscardEnable vkCmdSetRasterizerDiscardEnable; + PFN_vkCmdSetScissorWithCount vkCmdSetScissorWithCount; + PFN_vkCmdSetStencilOp vkCmdSetStencilOp; + PFN_vkCmdSetStencilTestEnable vkCmdSetStencilTestEnable; + PFN_vkCmdSetViewportWithCount vkCmdSetViewportWithCount; + PFN_vkCmdWaitEvents2 vkCmdWaitEvents2; + PFN_vkCmdWriteTimestamp2 vkCmdWriteTimestamp2; + PFN_vkCreatePrivateDataSlot vkCreatePrivateDataSlot; + PFN_vkDestroyPrivateDataSlot vkDestroyPrivateDataSlot; + PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements; + PFN_vkGetDeviceImageMemoryRequirements vkGetDeviceImageMemoryRequirements; + PFN_vkGetDeviceImageSparseMemoryRequirements vkGetDeviceImageSparseMemoryRequirements; + PFN_vkGetPrivateData vkGetPrivateData; + PFN_vkQueueSubmit2 vkQueueSubmit2; + PFN_vkSetPrivateData vkSetPrivateData; +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMDX_shader_enqueue) + PFN_vkCmdDispatchGraphAMDX vkCmdDispatchGraphAMDX; + PFN_vkCmdDispatchGraphIndirectAMDX vkCmdDispatchGraphIndirectAMDX; + PFN_vkCmdDispatchGraphIndirectCountAMDX vkCmdDispatchGraphIndirectCountAMDX; + PFN_vkCmdInitializeGraphScratchMemoryAMDX vkCmdInitializeGraphScratchMemoryAMDX; + PFN_vkCreateExecutionGraphPipelinesAMDX vkCreateExecutionGraphPipelinesAMDX; + PFN_vkGetExecutionGraphPipelineNodeIndexAMDX vkGetExecutionGraphPipelineNodeIndexAMDX; + PFN_vkGetExecutionGraphPipelineScratchSizeAMDX vkGetExecutionGraphPipelineScratchSizeAMDX; +#endif /* defined(VK_AMDX_shader_enqueue) */ +#if defined(VK_AMD_buffer_marker) + PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; + PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; + PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_attachment_feedback_loop_dynamic_state) + PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT vkCmdSetAttachmentFeedbackLoopEnableEXT; +#endif /* defined(VK_EXT_attachment_feedback_loop_dynamic_state) */ +#if defined(VK_EXT_buffer_device_address) + PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) + PFN_vkCmdSetColorWriteEnableEXT vkCmdSetColorWriteEnableEXT; +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) + PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; + PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; + PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; + PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; + PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; + PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_depth_bias_control) + PFN_vkCmdSetDepthBias2EXT vkCmdSetDepthBias2EXT; +#endif /* defined(VK_EXT_depth_bias_control) */ +#if defined(VK_EXT_descriptor_buffer) + PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT vkCmdBindDescriptorBufferEmbeddedSamplersEXT; + PFN_vkCmdBindDescriptorBuffersEXT vkCmdBindDescriptorBuffersEXT; + PFN_vkCmdSetDescriptorBufferOffsetsEXT vkCmdSetDescriptorBufferOffsetsEXT; + PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT vkGetBufferOpaqueCaptureDescriptorDataEXT; + PFN_vkGetDescriptorEXT vkGetDescriptorEXT; + PFN_vkGetDescriptorSetLayoutBindingOffsetEXT vkGetDescriptorSetLayoutBindingOffsetEXT; + PFN_vkGetDescriptorSetLayoutSizeEXT vkGetDescriptorSetLayoutSizeEXT; + PFN_vkGetImageOpaqueCaptureDescriptorDataEXT vkGetImageOpaqueCaptureDescriptorDataEXT; + PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT vkGetImageViewOpaqueCaptureDescriptorDataEXT; + PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT vkGetSamplerOpaqueCaptureDescriptorDataEXT; +#endif /* defined(VK_EXT_descriptor_buffer) */ +#if defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) + PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT; +#endif /* defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) */ +#if defined(VK_EXT_device_fault) + PFN_vkGetDeviceFaultInfoEXT vkGetDeviceFaultInfoEXT; +#endif /* defined(VK_EXT_device_fault) */ +#if defined(VK_EXT_discard_rectangles) + PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 + PFN_vkCmdSetDiscardRectangleEnableEXT vkCmdSetDiscardRectangleEnableEXT; + PFN_vkCmdSetDiscardRectangleModeEXT vkCmdSetDiscardRectangleModeEXT; +#endif /* defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 */ +#if defined(VK_EXT_display_control) + PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; + PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; + PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; + PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_external_memory_host) + PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; + PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_image_copy) + PFN_vkCopyImageToImageEXT vkCopyImageToImageEXT; + PFN_vkCopyImageToMemoryEXT vkCopyImageToMemoryEXT; + PFN_vkCopyMemoryToImageEXT vkCopyMemoryToImageEXT; + PFN_vkTransitionImageLayoutEXT vkTransitionImageLayoutEXT; +#endif /* defined(VK_EXT_host_image_copy) */ +#if defined(VK_EXT_host_query_reset) + PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) + PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_mesh_shader) + PFN_vkCmdDrawMeshTasksEXT vkCmdDrawMeshTasksEXT; + PFN_vkCmdDrawMeshTasksIndirectCountEXT vkCmdDrawMeshTasksIndirectCountEXT; + PFN_vkCmdDrawMeshTasksIndirectEXT vkCmdDrawMeshTasksIndirectEXT; +#endif /* defined(VK_EXT_mesh_shader) */ +#if defined(VK_EXT_metal_objects) + PFN_vkExportMetalObjectsEXT vkExportMetalObjectsEXT; +#endif /* defined(VK_EXT_metal_objects) */ +#if defined(VK_EXT_multi_draw) + PFN_vkCmdDrawMultiEXT vkCmdDrawMultiEXT; + PFN_vkCmdDrawMultiIndexedEXT vkCmdDrawMultiIndexedEXT; +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_opacity_micromap) + PFN_vkBuildMicromapsEXT vkBuildMicromapsEXT; + PFN_vkCmdBuildMicromapsEXT vkCmdBuildMicromapsEXT; + PFN_vkCmdCopyMemoryToMicromapEXT vkCmdCopyMemoryToMicromapEXT; + PFN_vkCmdCopyMicromapEXT vkCmdCopyMicromapEXT; + PFN_vkCmdCopyMicromapToMemoryEXT vkCmdCopyMicromapToMemoryEXT; + PFN_vkCmdWriteMicromapsPropertiesEXT vkCmdWriteMicromapsPropertiesEXT; + PFN_vkCopyMemoryToMicromapEXT vkCopyMemoryToMicromapEXT; + PFN_vkCopyMicromapEXT vkCopyMicromapEXT; + PFN_vkCopyMicromapToMemoryEXT vkCopyMicromapToMemoryEXT; + PFN_vkCreateMicromapEXT vkCreateMicromapEXT; + PFN_vkDestroyMicromapEXT vkDestroyMicromapEXT; + PFN_vkGetDeviceMicromapCompatibilityEXT vkGetDeviceMicromapCompatibilityEXT; + PFN_vkGetMicromapBuildSizesEXT vkGetMicromapBuildSizesEXT; + PFN_vkWriteMicromapsPropertiesEXT vkWriteMicromapsPropertiesEXT; +#endif /* defined(VK_EXT_opacity_micromap) */ +#if defined(VK_EXT_pageable_device_local_memory) + PFN_vkSetDeviceMemoryPriorityEXT vkSetDeviceMemoryPriorityEXT; +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) + PFN_vkGetPipelinePropertiesEXT vkGetPipelinePropertiesEXT; +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) + PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; + PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; + PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; + PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_shader_module_identifier) + PFN_vkGetShaderModuleCreateInfoIdentifierEXT vkGetShaderModuleCreateInfoIdentifierEXT; + PFN_vkGetShaderModuleIdentifierEXT vkGetShaderModuleIdentifierEXT; +#endif /* defined(VK_EXT_shader_module_identifier) */ +#if defined(VK_EXT_shader_object) + PFN_vkCmdBindShadersEXT vkCmdBindShadersEXT; + PFN_vkCreateShadersEXT vkCreateShadersEXT; + PFN_vkDestroyShaderEXT vkDestroyShaderEXT; + PFN_vkGetShaderBinaryDataEXT vkGetShaderBinaryDataEXT; +#endif /* defined(VK_EXT_shader_object) */ +#if defined(VK_EXT_swapchain_maintenance1) + PFN_vkReleaseSwapchainImagesEXT vkReleaseSwapchainImagesEXT; +#endif /* defined(VK_EXT_swapchain_maintenance1) */ +#if defined(VK_EXT_transform_feedback) + PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; + PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; + PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; + PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; + PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; + PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; + PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; + PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; + PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_FUCHSIA_buffer_collection) + PFN_vkCreateBufferCollectionFUCHSIA vkCreateBufferCollectionFUCHSIA; + PFN_vkDestroyBufferCollectionFUCHSIA vkDestroyBufferCollectionFUCHSIA; + PFN_vkGetBufferCollectionPropertiesFUCHSIA vkGetBufferCollectionPropertiesFUCHSIA; + PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA vkSetBufferCollectionBufferConstraintsFUCHSIA; + PFN_vkSetBufferCollectionImageConstraintsFUCHSIA vkSetBufferCollectionImageConstraintsFUCHSIA; +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) + PFN_vkGetMemoryZirconHandleFUCHSIA vkGetMemoryZirconHandleFUCHSIA; + PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA vkGetMemoryZirconHandlePropertiesFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) + PFN_vkGetSemaphoreZirconHandleFUCHSIA vkGetSemaphoreZirconHandleFUCHSIA; + PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_GOOGLE_display_timing) + PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; + PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_cluster_culling_shader) + PFN_vkCmdDrawClusterHUAWEI vkCmdDrawClusterHUAWEI; + PFN_vkCmdDrawClusterIndirectHUAWEI vkCmdDrawClusterIndirectHUAWEI; +#endif /* defined(VK_HUAWEI_cluster_culling_shader) */ +#if defined(VK_HUAWEI_invocation_mask) + PFN_vkCmdBindInvocationMaskHUAWEI vkCmdBindInvocationMaskHUAWEI; +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) + PFN_vkCmdSubpassShadingHUAWEI vkCmdSubpassShadingHUAWEI; + PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI; +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) + PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; + PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; + PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; + PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; + PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; + PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; + PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; + PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; + PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) + PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR; + PFN_vkCmdBuildAccelerationStructuresIndirectKHR vkCmdBuildAccelerationStructuresIndirectKHR; + PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; + PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; + PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; + PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; + PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; + PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; + PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; + PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; + PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; + PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; + PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; + PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; + PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; + PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_bind_memory2) + PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; + PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; + PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_copy_commands2) + PFN_vkCmdBlitImage2KHR vkCmdBlitImage2KHR; + PFN_vkCmdCopyBuffer2KHR vkCmdCopyBuffer2KHR; + PFN_vkCmdCopyBufferToImage2KHR vkCmdCopyBufferToImage2KHR; + PFN_vkCmdCopyImage2KHR vkCmdCopyImage2KHR; + PFN_vkCmdCopyImageToBuffer2KHR vkCmdCopyImageToBuffer2KHR; + PFN_vkCmdResolveImage2KHR vkCmdResolveImage2KHR; +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) + PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; + PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; + PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; + PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; + PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; + PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; + PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; + PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; + PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; + PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; + PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) + PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR; + PFN_vkCmdEndRenderingKHR vkCmdEndRenderingKHR; +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_fd) + PFN_vkGetFenceFdKHR vkGetFenceFdKHR; + PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; + PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; + PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; + PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; + PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; + PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) + PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR; +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_memory_requirements2) + PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; + PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; + PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) + PFN_vkGetDeviceBufferMemoryRequirementsKHR vkGetDeviceBufferMemoryRequirementsKHR; + PFN_vkGetDeviceImageMemoryRequirementsKHR vkGetDeviceImageMemoryRequirementsKHR; + PFN_vkGetDeviceImageSparseMemoryRequirementsKHR vkGetDeviceImageSparseMemoryRequirementsKHR; +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_maintenance5) + PFN_vkCmdBindIndexBuffer2KHR vkCmdBindIndexBuffer2KHR; + PFN_vkGetDeviceImageSubresourceLayoutKHR vkGetDeviceImageSubresourceLayoutKHR; + PFN_vkGetImageSubresourceLayout2KHR vkGetImageSubresourceLayout2KHR; + PFN_vkGetRenderingAreaGranularityKHR vkGetRenderingAreaGranularityKHR; +#endif /* defined(VK_KHR_maintenance5) */ +#if defined(VK_KHR_map_memory2) + PFN_vkMapMemory2KHR vkMapMemory2KHR; + PFN_vkUnmapMemory2KHR vkUnmapMemory2KHR; +#endif /* defined(VK_KHR_map_memory2) */ +#if defined(VK_KHR_performance_query) + PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; + PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; + PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; + PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) + PFN_vkWaitForPresentKHR vkWaitForPresentKHR; +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) + PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) + PFN_vkCmdTraceRaysIndirect2KHR vkCmdTraceRaysIndirect2KHR; +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) + PFN_vkCmdSetRayTracingPipelineStackSizeKHR vkCmdSetRayTracingPipelineStackSizeKHR; + PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; + PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; + PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; + PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; + PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; + PFN_vkGetRayTracingShaderGroupStackSizeKHR vkGetRayTracingShaderGroupStackSizeKHR; +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; + PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) + PFN_vkCmdPipelineBarrier2KHR vkCmdPipelineBarrier2KHR; + PFN_vkCmdResetEvent2KHR vkCmdResetEvent2KHR; + PFN_vkCmdSetEvent2KHR vkCmdSetEvent2KHR; + PFN_vkCmdWaitEvents2KHR vkCmdWaitEvents2KHR; + PFN_vkCmdWriteTimestamp2KHR vkCmdWriteTimestamp2KHR; + PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR; +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) + PFN_vkCmdWriteBufferMarker2AMD vkCmdWriteBufferMarker2AMD; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) + PFN_vkGetQueueCheckpointData2NV vkGetQueueCheckpointData2NV; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) + PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; + PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; + PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) + PFN_vkCmdDecodeVideoKHR vkCmdDecodeVideoKHR; +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) + PFN_vkCmdEncodeVideoKHR vkCmdEncodeVideoKHR; + PFN_vkGetEncodedVideoSessionParametersKHR vkGetEncodedVideoSessionParametersKHR; +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) + PFN_vkBindVideoSessionMemoryKHR vkBindVideoSessionMemoryKHR; + PFN_vkCmdBeginVideoCodingKHR vkCmdBeginVideoCodingKHR; + PFN_vkCmdControlVideoCodingKHR vkCmdControlVideoCodingKHR; + PFN_vkCmdEndVideoCodingKHR vkCmdEndVideoCodingKHR; + PFN_vkCreateVideoSessionKHR vkCreateVideoSessionKHR; + PFN_vkCreateVideoSessionParametersKHR vkCreateVideoSessionParametersKHR; + PFN_vkDestroyVideoSessionKHR vkDestroyVideoSessionKHR; + PFN_vkDestroyVideoSessionParametersKHR vkDestroyVideoSessionParametersKHR; + PFN_vkGetVideoSessionMemoryRequirementsKHR vkGetVideoSessionMemoryRequirementsKHR; + PFN_vkUpdateVideoSessionParametersKHR vkUpdateVideoSessionParametersKHR; +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_NVX_binary_import) + PFN_vkCmdCuLaunchKernelNVX vkCmdCuLaunchKernelNVX; + PFN_vkCreateCuFunctionNVX vkCreateCuFunctionNVX; + PFN_vkCreateCuModuleNVX vkCreateCuModuleNVX; + PFN_vkDestroyCuFunctionNVX vkDestroyCuFunctionNVX; + PFN_vkDestroyCuModuleNVX vkDestroyCuModuleNVX; +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) + PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; + PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_copy_memory_indirect) + PFN_vkCmdCopyMemoryIndirectNV vkCmdCopyMemoryIndirectNV; + PFN_vkCmdCopyMemoryToImageIndirectNV vkCmdCopyMemoryToImageIndirectNV; +#endif /* defined(VK_NV_copy_memory_indirect) */ +#if defined(VK_NV_cuda_kernel_launch) + PFN_vkCmdCudaLaunchKernelNV vkCmdCudaLaunchKernelNV; + PFN_vkCreateCudaFunctionNV vkCreateCudaFunctionNV; + PFN_vkCreateCudaModuleNV vkCreateCudaModuleNV; + PFN_vkDestroyCudaFunctionNV vkDestroyCudaFunctionNV; + PFN_vkDestroyCudaModuleNV vkDestroyCudaModuleNV; + PFN_vkGetCudaModuleCacheNV vkGetCudaModuleCacheNV; +#endif /* defined(VK_NV_cuda_kernel_launch) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; + PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; + PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; + PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; + PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; + PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; + PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_device_generated_commands_compute) + PFN_vkCmdUpdatePipelineIndirectBufferNV vkCmdUpdatePipelineIndirectBufferNV; + PFN_vkGetPipelineIndirectDeviceAddressNV vkGetPipelineIndirectDeviceAddressNV; + PFN_vkGetPipelineIndirectMemoryRequirementsNV vkGetPipelineIndirectMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands_compute) */ +#if defined(VK_NV_external_memory_rdma) + PFN_vkGetMemoryRemoteAddressNV vkGetMemoryRemoteAddressNV; +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) + PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) + PFN_vkCmdSetFragmentShadingRateEnumNV vkCmdSetFragmentShadingRateEnumNV; +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_low_latency2) + PFN_vkGetLatencyTimingsNV vkGetLatencyTimingsNV; + PFN_vkLatencySleepNV vkLatencySleepNV; + PFN_vkQueueNotifyOutOfBandNV vkQueueNotifyOutOfBandNV; + PFN_vkSetLatencyMarkerNV vkSetLatencyMarkerNV; + PFN_vkSetLatencySleepModeNV vkSetLatencySleepModeNV; +#endif /* defined(VK_NV_low_latency2) */ +#if defined(VK_NV_memory_decompression) + PFN_vkCmdDecompressMemoryIndirectCountNV vkCmdDecompressMemoryIndirectCountNV; + PFN_vkCmdDecompressMemoryNV vkCmdDecompressMemoryNV; +#endif /* defined(VK_NV_memory_decompression) */ +#if defined(VK_NV_mesh_shader) + PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; + PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; + PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_optical_flow) + PFN_vkBindOpticalFlowSessionImageNV vkBindOpticalFlowSessionImageNV; + PFN_vkCmdOpticalFlowExecuteNV vkCmdOpticalFlowExecuteNV; + PFN_vkCreateOpticalFlowSessionNV vkCreateOpticalFlowSessionNV; + PFN_vkDestroyOpticalFlowSessionNV vkDestroyOpticalFlowSessionNV; +#endif /* defined(VK_NV_optical_flow) */ +#if defined(VK_NV_ray_tracing) + PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; + PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; + PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; + PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; + PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; + PFN_vkCompileDeferredNV vkCompileDeferredNV; + PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; + PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; + PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; + PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; + PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; + PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 + PFN_vkCmdSetExclusiveScissorEnableNV vkCmdSetExclusiveScissorEnableNV; +#endif /* defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 */ +#if defined(VK_NV_scissor_exclusive) + PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; + PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; + PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_QCOM_tile_properties) + PFN_vkGetDynamicRenderingTilePropertiesQCOM vkGetDynamicRenderingTilePropertiesQCOM; + PFN_vkGetFramebufferTilePropertiesQCOM vkGetFramebufferTilePropertiesQCOM; +#endif /* defined(VK_QCOM_tile_properties) */ +#if defined(VK_QNX_external_memory_screen_buffer) + PFN_vkGetScreenBufferPropertiesQNX vkGetScreenBufferPropertiesQNX; +#endif /* defined(VK_QNX_external_memory_screen_buffer) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) + PFN_vkGetDescriptorSetHostMappingVALVE vkGetDescriptorSetHostMappingVALVE; + PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE vkGetDescriptorSetLayoutHostMappingInfoVALVE; +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) + PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; + PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; + PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; + PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; + PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; + PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; + PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; + PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; + PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; + PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; + PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; + PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) + PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT; + PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT; + PFN_vkCmdSetPatchControlPointsEXT vkCmdSetPatchControlPointsEXT; + PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT; + PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) + PFN_vkCmdSetAlphaToCoverageEnableEXT vkCmdSetAlphaToCoverageEnableEXT; + PFN_vkCmdSetAlphaToOneEnableEXT vkCmdSetAlphaToOneEnableEXT; + PFN_vkCmdSetColorBlendAdvancedEXT vkCmdSetColorBlendAdvancedEXT; + PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT; + PFN_vkCmdSetColorBlendEquationEXT vkCmdSetColorBlendEquationEXT; + PFN_vkCmdSetColorWriteMaskEXT vkCmdSetColorWriteMaskEXT; + PFN_vkCmdSetConservativeRasterizationModeEXT vkCmdSetConservativeRasterizationModeEXT; + PFN_vkCmdSetDepthClampEnableEXT vkCmdSetDepthClampEnableEXT; + PFN_vkCmdSetDepthClipEnableEXT vkCmdSetDepthClipEnableEXT; + PFN_vkCmdSetDepthClipNegativeOneToOneEXT vkCmdSetDepthClipNegativeOneToOneEXT; + PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT vkCmdSetExtraPrimitiveOverestimationSizeEXT; + PFN_vkCmdSetLineRasterizationModeEXT vkCmdSetLineRasterizationModeEXT; + PFN_vkCmdSetLineStippleEnableEXT vkCmdSetLineStippleEnableEXT; + PFN_vkCmdSetLogicOpEnableEXT vkCmdSetLogicOpEnableEXT; + PFN_vkCmdSetPolygonModeEXT vkCmdSetPolygonModeEXT; + PFN_vkCmdSetProvokingVertexModeEXT vkCmdSetProvokingVertexModeEXT; + PFN_vkCmdSetRasterizationSamplesEXT vkCmdSetRasterizationSamplesEXT; + PFN_vkCmdSetRasterizationStreamEXT vkCmdSetRasterizationStreamEXT; + PFN_vkCmdSetSampleLocationsEnableEXT vkCmdSetSampleLocationsEnableEXT; + PFN_vkCmdSetSampleMaskEXT vkCmdSetSampleMaskEXT; + PFN_vkCmdSetTessellationDomainOriginEXT vkCmdSetTessellationDomainOriginEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) + PFN_vkCmdSetViewportWScalingEnableNV vkCmdSetViewportWScalingEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) + PFN_vkCmdSetViewportSwizzleNV vkCmdSetViewportSwizzleNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) + PFN_vkCmdSetCoverageToColorEnableNV vkCmdSetCoverageToColorEnableNV; + PFN_vkCmdSetCoverageToColorLocationNV vkCmdSetCoverageToColorLocationNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) + PFN_vkCmdSetCoverageModulationModeNV vkCmdSetCoverageModulationModeNV; + PFN_vkCmdSetCoverageModulationTableEnableNV vkCmdSetCoverageModulationTableEnableNV; + PFN_vkCmdSetCoverageModulationTableNV vkCmdSetCoverageModulationTableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) + PFN_vkCmdSetShadingRateImageEnableNV vkCmdSetShadingRateImageEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) + PFN_vkCmdSetRepresentativeFragmentTestEnableNV vkCmdSetRepresentativeFragmentTestEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) + PFN_vkCmdSetCoverageReductionModeNV vkCmdSetCoverageReductionModeNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) + PFN_vkGetImageSubresourceLayout2EXT vkGetImageSubresourceLayout2EXT; +#endif /* (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) */ +#if (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) + PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT; +#endif /* (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; + PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_DEVICE_TABLE */ +}; + +/* VOLK_GENERATE_PROTOTYPES_H */ +#if defined(VK_VERSION_1_0) +extern PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; +extern PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; +extern PFN_vkAllocateMemory vkAllocateMemory; +extern PFN_vkBeginCommandBuffer vkBeginCommandBuffer; +extern PFN_vkBindBufferMemory vkBindBufferMemory; +extern PFN_vkBindImageMemory vkBindImageMemory; +extern PFN_vkCmdBeginQuery vkCmdBeginQuery; +extern PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; +extern PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; +extern PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; +extern PFN_vkCmdBindPipeline vkCmdBindPipeline; +extern PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; +extern PFN_vkCmdBlitImage vkCmdBlitImage; +extern PFN_vkCmdClearAttachments vkCmdClearAttachments; +extern PFN_vkCmdClearColorImage vkCmdClearColorImage; +extern PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; +extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; +extern PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; +extern PFN_vkCmdCopyImage vkCmdCopyImage; +extern PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; +extern PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; +extern PFN_vkCmdDispatch vkCmdDispatch; +extern PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; +extern PFN_vkCmdDraw vkCmdDraw; +extern PFN_vkCmdDrawIndexed vkCmdDrawIndexed; +extern PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; +extern PFN_vkCmdDrawIndirect vkCmdDrawIndirect; +extern PFN_vkCmdEndQuery vkCmdEndQuery; +extern PFN_vkCmdEndRenderPass vkCmdEndRenderPass; +extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands; +extern PFN_vkCmdFillBuffer vkCmdFillBuffer; +extern PFN_vkCmdNextSubpass vkCmdNextSubpass; +extern PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; +extern PFN_vkCmdPushConstants vkCmdPushConstants; +extern PFN_vkCmdResetEvent vkCmdResetEvent; +extern PFN_vkCmdResetQueryPool vkCmdResetQueryPool; +extern PFN_vkCmdResolveImage vkCmdResolveImage; +extern PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; +extern PFN_vkCmdSetDepthBias vkCmdSetDepthBias; +extern PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; +extern PFN_vkCmdSetEvent vkCmdSetEvent; +extern PFN_vkCmdSetLineWidth vkCmdSetLineWidth; +extern PFN_vkCmdSetScissor vkCmdSetScissor; +extern PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; +extern PFN_vkCmdSetStencilReference vkCmdSetStencilReference; +extern PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; +extern PFN_vkCmdSetViewport vkCmdSetViewport; +extern PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; +extern PFN_vkCmdWaitEvents vkCmdWaitEvents; +extern PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; +extern PFN_vkCreateBuffer vkCreateBuffer; +extern PFN_vkCreateBufferView vkCreateBufferView; +extern PFN_vkCreateCommandPool vkCreateCommandPool; +extern PFN_vkCreateComputePipelines vkCreateComputePipelines; +extern PFN_vkCreateDescriptorPool vkCreateDescriptorPool; +extern PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; +extern PFN_vkCreateDevice vkCreateDevice; +extern PFN_vkCreateEvent vkCreateEvent; +extern PFN_vkCreateFence vkCreateFence; +extern PFN_vkCreateFramebuffer vkCreateFramebuffer; +extern PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; +extern PFN_vkCreateImage vkCreateImage; +extern PFN_vkCreateImageView vkCreateImageView; +extern PFN_vkCreateInstance vkCreateInstance; +extern PFN_vkCreatePipelineCache vkCreatePipelineCache; +extern PFN_vkCreatePipelineLayout vkCreatePipelineLayout; +extern PFN_vkCreateQueryPool vkCreateQueryPool; +extern PFN_vkCreateRenderPass vkCreateRenderPass; +extern PFN_vkCreateSampler vkCreateSampler; +extern PFN_vkCreateSemaphore vkCreateSemaphore; +extern PFN_vkCreateShaderModule vkCreateShaderModule; +extern PFN_vkDestroyBuffer vkDestroyBuffer; +extern PFN_vkDestroyBufferView vkDestroyBufferView; +extern PFN_vkDestroyCommandPool vkDestroyCommandPool; +extern PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; +extern PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; +extern PFN_vkDestroyDevice vkDestroyDevice; +extern PFN_vkDestroyEvent vkDestroyEvent; +extern PFN_vkDestroyFence vkDestroyFence; +extern PFN_vkDestroyFramebuffer vkDestroyFramebuffer; +extern PFN_vkDestroyImage vkDestroyImage; +extern PFN_vkDestroyImageView vkDestroyImageView; +extern PFN_vkDestroyInstance vkDestroyInstance; +extern PFN_vkDestroyPipeline vkDestroyPipeline; +extern PFN_vkDestroyPipelineCache vkDestroyPipelineCache; +extern PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; +extern PFN_vkDestroyQueryPool vkDestroyQueryPool; +extern PFN_vkDestroyRenderPass vkDestroyRenderPass; +extern PFN_vkDestroySampler vkDestroySampler; +extern PFN_vkDestroySemaphore vkDestroySemaphore; +extern PFN_vkDestroyShaderModule vkDestroyShaderModule; +extern PFN_vkDeviceWaitIdle vkDeviceWaitIdle; +extern PFN_vkEndCommandBuffer vkEndCommandBuffer; +extern PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; +extern PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; +extern PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; +extern PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; +extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; +extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; +extern PFN_vkFreeCommandBuffers vkFreeCommandBuffers; +extern PFN_vkFreeDescriptorSets vkFreeDescriptorSets; +extern PFN_vkFreeMemory vkFreeMemory; +extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; +extern PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; +extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +extern PFN_vkGetDeviceQueue vkGetDeviceQueue; +extern PFN_vkGetEventStatus vkGetEventStatus; +extern PFN_vkGetFenceStatus vkGetFenceStatus; +extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; +extern PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; +extern PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; +extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; +extern PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; +extern PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; +extern PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; +extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; +extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; +extern PFN_vkGetPipelineCacheData vkGetPipelineCacheData; +extern PFN_vkGetQueryPoolResults vkGetQueryPoolResults; +extern PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; +extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; +extern PFN_vkMapMemory vkMapMemory; +extern PFN_vkMergePipelineCaches vkMergePipelineCaches; +extern PFN_vkQueueBindSparse vkQueueBindSparse; +extern PFN_vkQueueSubmit vkQueueSubmit; +extern PFN_vkQueueWaitIdle vkQueueWaitIdle; +extern PFN_vkResetCommandBuffer vkResetCommandBuffer; +extern PFN_vkResetCommandPool vkResetCommandPool; +extern PFN_vkResetDescriptorPool vkResetDescriptorPool; +extern PFN_vkResetEvent vkResetEvent; +extern PFN_vkResetFences vkResetFences; +extern PFN_vkSetEvent vkSetEvent; +extern PFN_vkUnmapMemory vkUnmapMemory; +extern PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; +extern PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) +extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; +extern PFN_vkBindImageMemory2 vkBindImageMemory2; +extern PFN_vkCmdDispatchBase vkCmdDispatchBase; +extern PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; +extern PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; +extern PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; +extern PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; +extern PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; +extern PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; +extern PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups; +extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; +extern PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; +extern PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; +extern PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; +extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; +extern PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; +extern PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties; +extern PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties; +extern PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties; +extern PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; +extern PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2; +extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; +extern PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2; +extern PFN_vkTrimCommandPool vkTrimCommandPool; +extern PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) +extern PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; +extern PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; +extern PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; +extern PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; +extern PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; +extern PFN_vkCreateRenderPass2 vkCreateRenderPass2; +extern PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; +extern PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; +extern PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; +extern PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; +extern PFN_vkResetQueryPool vkResetQueryPool; +extern PFN_vkSignalSemaphore vkSignalSemaphore; +extern PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) +extern PFN_vkCmdBeginRendering vkCmdBeginRendering; +extern PFN_vkCmdBindVertexBuffers2 vkCmdBindVertexBuffers2; +extern PFN_vkCmdBlitImage2 vkCmdBlitImage2; +extern PFN_vkCmdCopyBuffer2 vkCmdCopyBuffer2; +extern PFN_vkCmdCopyBufferToImage2 vkCmdCopyBufferToImage2; +extern PFN_vkCmdCopyImage2 vkCmdCopyImage2; +extern PFN_vkCmdCopyImageToBuffer2 vkCmdCopyImageToBuffer2; +extern PFN_vkCmdEndRendering vkCmdEndRendering; +extern PFN_vkCmdPipelineBarrier2 vkCmdPipelineBarrier2; +extern PFN_vkCmdResetEvent2 vkCmdResetEvent2; +extern PFN_vkCmdResolveImage2 vkCmdResolveImage2; +extern PFN_vkCmdSetCullMode vkCmdSetCullMode; +extern PFN_vkCmdSetDepthBiasEnable vkCmdSetDepthBiasEnable; +extern PFN_vkCmdSetDepthBoundsTestEnable vkCmdSetDepthBoundsTestEnable; +extern PFN_vkCmdSetDepthCompareOp vkCmdSetDepthCompareOp; +extern PFN_vkCmdSetDepthTestEnable vkCmdSetDepthTestEnable; +extern PFN_vkCmdSetDepthWriteEnable vkCmdSetDepthWriteEnable; +extern PFN_vkCmdSetEvent2 vkCmdSetEvent2; +extern PFN_vkCmdSetFrontFace vkCmdSetFrontFace; +extern PFN_vkCmdSetPrimitiveRestartEnable vkCmdSetPrimitiveRestartEnable; +extern PFN_vkCmdSetPrimitiveTopology vkCmdSetPrimitiveTopology; +extern PFN_vkCmdSetRasterizerDiscardEnable vkCmdSetRasterizerDiscardEnable; +extern PFN_vkCmdSetScissorWithCount vkCmdSetScissorWithCount; +extern PFN_vkCmdSetStencilOp vkCmdSetStencilOp; +extern PFN_vkCmdSetStencilTestEnable vkCmdSetStencilTestEnable; +extern PFN_vkCmdSetViewportWithCount vkCmdSetViewportWithCount; +extern PFN_vkCmdWaitEvents2 vkCmdWaitEvents2; +extern PFN_vkCmdWriteTimestamp2 vkCmdWriteTimestamp2; +extern PFN_vkCreatePrivateDataSlot vkCreatePrivateDataSlot; +extern PFN_vkDestroyPrivateDataSlot vkDestroyPrivateDataSlot; +extern PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements; +extern PFN_vkGetDeviceImageMemoryRequirements vkGetDeviceImageMemoryRequirements; +extern PFN_vkGetDeviceImageSparseMemoryRequirements vkGetDeviceImageSparseMemoryRequirements; +extern PFN_vkGetPhysicalDeviceToolProperties vkGetPhysicalDeviceToolProperties; +extern PFN_vkGetPrivateData vkGetPrivateData; +extern PFN_vkQueueSubmit2 vkQueueSubmit2; +extern PFN_vkSetPrivateData vkSetPrivateData; +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMDX_shader_enqueue) +extern PFN_vkCmdDispatchGraphAMDX vkCmdDispatchGraphAMDX; +extern PFN_vkCmdDispatchGraphIndirectAMDX vkCmdDispatchGraphIndirectAMDX; +extern PFN_vkCmdDispatchGraphIndirectCountAMDX vkCmdDispatchGraphIndirectCountAMDX; +extern PFN_vkCmdInitializeGraphScratchMemoryAMDX vkCmdInitializeGraphScratchMemoryAMDX; +extern PFN_vkCreateExecutionGraphPipelinesAMDX vkCreateExecutionGraphPipelinesAMDX; +extern PFN_vkGetExecutionGraphPipelineNodeIndexAMDX vkGetExecutionGraphPipelineNodeIndexAMDX; +extern PFN_vkGetExecutionGraphPipelineScratchSizeAMDX vkGetExecutionGraphPipelineScratchSizeAMDX; +#endif /* defined(VK_AMDX_shader_enqueue) */ +#if defined(VK_AMD_buffer_marker) +extern PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) +extern PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) +extern PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; +extern PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) +extern PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) +extern PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; +extern PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_acquire_drm_display) +extern PFN_vkAcquireDrmDisplayEXT vkAcquireDrmDisplayEXT; +extern PFN_vkGetDrmDisplayEXT vkGetDrmDisplayEXT; +#endif /* defined(VK_EXT_acquire_drm_display) */ +#if defined(VK_EXT_acquire_xlib_display) +extern PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; +extern PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_attachment_feedback_loop_dynamic_state) +extern PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT vkCmdSetAttachmentFeedbackLoopEnableEXT; +#endif /* defined(VK_EXT_attachment_feedback_loop_dynamic_state) */ +#if defined(VK_EXT_buffer_device_address) +extern PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) +extern PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +extern PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) +extern PFN_vkCmdSetColorWriteEnableEXT vkCmdSetColorWriteEnableEXT; +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) +extern PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; +extern PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) +extern PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; +extern PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; +extern PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; +extern PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; +extern PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_debug_report) +extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +extern PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; +extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) +extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +extern PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; +extern PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; +extern PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; +extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; +extern PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT; +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_depth_bias_control) +extern PFN_vkCmdSetDepthBias2EXT vkCmdSetDepthBias2EXT; +#endif /* defined(VK_EXT_depth_bias_control) */ +#if defined(VK_EXT_descriptor_buffer) +extern PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT vkCmdBindDescriptorBufferEmbeddedSamplersEXT; +extern PFN_vkCmdBindDescriptorBuffersEXT vkCmdBindDescriptorBuffersEXT; +extern PFN_vkCmdSetDescriptorBufferOffsetsEXT vkCmdSetDescriptorBufferOffsetsEXT; +extern PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT vkGetBufferOpaqueCaptureDescriptorDataEXT; +extern PFN_vkGetDescriptorEXT vkGetDescriptorEXT; +extern PFN_vkGetDescriptorSetLayoutBindingOffsetEXT vkGetDescriptorSetLayoutBindingOffsetEXT; +extern PFN_vkGetDescriptorSetLayoutSizeEXT vkGetDescriptorSetLayoutSizeEXT; +extern PFN_vkGetImageOpaqueCaptureDescriptorDataEXT vkGetImageOpaqueCaptureDescriptorDataEXT; +extern PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT vkGetImageViewOpaqueCaptureDescriptorDataEXT; +extern PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT vkGetSamplerOpaqueCaptureDescriptorDataEXT; +#endif /* defined(VK_EXT_descriptor_buffer) */ +#if defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) +extern PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT; +#endif /* defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) */ +#if defined(VK_EXT_device_fault) +extern PFN_vkGetDeviceFaultInfoEXT vkGetDeviceFaultInfoEXT; +#endif /* defined(VK_EXT_device_fault) */ +#if defined(VK_EXT_direct_mode_display) +extern PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) +extern PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT; +extern PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT; +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_discard_rectangles) +extern PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 +extern PFN_vkCmdSetDiscardRectangleEnableEXT vkCmdSetDiscardRectangleEnableEXT; +extern PFN_vkCmdSetDiscardRectangleModeEXT vkCmdSetDiscardRectangleModeEXT; +#endif /* defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 */ +#if defined(VK_EXT_display_control) +extern PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; +extern PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; +extern PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; +extern PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_display_surface_counter) +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT; +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_external_memory_host) +extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) +extern PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; +extern PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT vkGetPhysicalDeviceSurfacePresentModes2EXT; +extern PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) +extern PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_headless_surface) +extern PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT; +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_host_image_copy) +extern PFN_vkCopyImageToImageEXT vkCopyImageToImageEXT; +extern PFN_vkCopyImageToMemoryEXT vkCopyImageToMemoryEXT; +extern PFN_vkCopyMemoryToImageEXT vkCopyMemoryToImageEXT; +extern PFN_vkTransitionImageLayoutEXT vkTransitionImageLayoutEXT; +#endif /* defined(VK_EXT_host_image_copy) */ +#if defined(VK_EXT_host_query_reset) +extern PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) +extern PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) +extern PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_mesh_shader) +extern PFN_vkCmdDrawMeshTasksEXT vkCmdDrawMeshTasksEXT; +extern PFN_vkCmdDrawMeshTasksIndirectCountEXT vkCmdDrawMeshTasksIndirectCountEXT; +extern PFN_vkCmdDrawMeshTasksIndirectEXT vkCmdDrawMeshTasksIndirectEXT; +#endif /* defined(VK_EXT_mesh_shader) */ +#if defined(VK_EXT_metal_objects) +extern PFN_vkExportMetalObjectsEXT vkExportMetalObjectsEXT; +#endif /* defined(VK_EXT_metal_objects) */ +#if defined(VK_EXT_metal_surface) +extern PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_multi_draw) +extern PFN_vkCmdDrawMultiEXT vkCmdDrawMultiEXT; +extern PFN_vkCmdDrawMultiIndexedEXT vkCmdDrawMultiIndexedEXT; +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_opacity_micromap) +extern PFN_vkBuildMicromapsEXT vkBuildMicromapsEXT; +extern PFN_vkCmdBuildMicromapsEXT vkCmdBuildMicromapsEXT; +extern PFN_vkCmdCopyMemoryToMicromapEXT vkCmdCopyMemoryToMicromapEXT; +extern PFN_vkCmdCopyMicromapEXT vkCmdCopyMicromapEXT; +extern PFN_vkCmdCopyMicromapToMemoryEXT vkCmdCopyMicromapToMemoryEXT; +extern PFN_vkCmdWriteMicromapsPropertiesEXT vkCmdWriteMicromapsPropertiesEXT; +extern PFN_vkCopyMemoryToMicromapEXT vkCopyMemoryToMicromapEXT; +extern PFN_vkCopyMicromapEXT vkCopyMicromapEXT; +extern PFN_vkCopyMicromapToMemoryEXT vkCopyMicromapToMemoryEXT; +extern PFN_vkCreateMicromapEXT vkCreateMicromapEXT; +extern PFN_vkDestroyMicromapEXT vkDestroyMicromapEXT; +extern PFN_vkGetDeviceMicromapCompatibilityEXT vkGetDeviceMicromapCompatibilityEXT; +extern PFN_vkGetMicromapBuildSizesEXT vkGetMicromapBuildSizesEXT; +extern PFN_vkWriteMicromapsPropertiesEXT vkWriteMicromapsPropertiesEXT; +#endif /* defined(VK_EXT_opacity_micromap) */ +#if defined(VK_EXT_pageable_device_local_memory) +extern PFN_vkSetDeviceMemoryPriorityEXT vkSetDeviceMemoryPriorityEXT; +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) +extern PFN_vkGetPipelinePropertiesEXT vkGetPipelinePropertiesEXT; +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) +extern PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; +extern PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; +extern PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; +extern PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) +extern PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +extern PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_shader_module_identifier) +extern PFN_vkGetShaderModuleCreateInfoIdentifierEXT vkGetShaderModuleCreateInfoIdentifierEXT; +extern PFN_vkGetShaderModuleIdentifierEXT vkGetShaderModuleIdentifierEXT; +#endif /* defined(VK_EXT_shader_module_identifier) */ +#if defined(VK_EXT_shader_object) +extern PFN_vkCmdBindShadersEXT vkCmdBindShadersEXT; +extern PFN_vkCreateShadersEXT vkCreateShadersEXT; +extern PFN_vkDestroyShaderEXT vkDestroyShaderEXT; +extern PFN_vkGetShaderBinaryDataEXT vkGetShaderBinaryDataEXT; +#endif /* defined(VK_EXT_shader_object) */ +#if defined(VK_EXT_swapchain_maintenance1) +extern PFN_vkReleaseSwapchainImagesEXT vkReleaseSwapchainImagesEXT; +#endif /* defined(VK_EXT_swapchain_maintenance1) */ +#if defined(VK_EXT_tooling_info) +extern PFN_vkGetPhysicalDeviceToolPropertiesEXT vkGetPhysicalDeviceToolPropertiesEXT; +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_EXT_transform_feedback) +extern PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; +extern PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; +extern PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; +extern PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; +extern PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; +extern PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) +extern PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; +extern PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; +extern PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; +extern PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_FUCHSIA_buffer_collection) +extern PFN_vkCreateBufferCollectionFUCHSIA vkCreateBufferCollectionFUCHSIA; +extern PFN_vkDestroyBufferCollectionFUCHSIA vkDestroyBufferCollectionFUCHSIA; +extern PFN_vkGetBufferCollectionPropertiesFUCHSIA vkGetBufferCollectionPropertiesFUCHSIA; +extern PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA vkSetBufferCollectionBufferConstraintsFUCHSIA; +extern PFN_vkSetBufferCollectionImageConstraintsFUCHSIA vkSetBufferCollectionImageConstraintsFUCHSIA; +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) +extern PFN_vkGetMemoryZirconHandleFUCHSIA vkGetMemoryZirconHandleFUCHSIA; +extern PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA vkGetMemoryZirconHandlePropertiesFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) +extern PFN_vkGetSemaphoreZirconHandleFUCHSIA vkGetSemaphoreZirconHandleFUCHSIA; +extern PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_FUCHSIA_imagepipe_surface) +extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) +extern PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP; +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_GOOGLE_display_timing) +extern PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; +extern PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_cluster_culling_shader) +extern PFN_vkCmdDrawClusterHUAWEI vkCmdDrawClusterHUAWEI; +extern PFN_vkCmdDrawClusterIndirectHUAWEI vkCmdDrawClusterIndirectHUAWEI; +#endif /* defined(VK_HUAWEI_cluster_culling_shader) */ +#if defined(VK_HUAWEI_invocation_mask) +extern PFN_vkCmdBindInvocationMaskHUAWEI vkCmdBindInvocationMaskHUAWEI; +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) +extern PFN_vkCmdSubpassShadingHUAWEI vkCmdSubpassShadingHUAWEI; +extern PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI; +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) +extern PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; +extern PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; +extern PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; +extern PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; +extern PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; +extern PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; +extern PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; +extern PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; +extern PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) +extern PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR; +extern PFN_vkCmdBuildAccelerationStructuresIndirectKHR vkCmdBuildAccelerationStructuresIndirectKHR; +extern PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; +extern PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; +extern PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; +extern PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; +extern PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; +extern PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; +extern PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; +extern PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; +extern PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; +extern PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; +extern PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; +extern PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; +extern PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; +extern PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_android_surface) +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_bind_memory2) +extern PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; +extern PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) +extern PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; +extern PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; +extern PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_cooperative_matrix) +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; +#endif /* defined(VK_KHR_cooperative_matrix) */ +#if defined(VK_KHR_copy_commands2) +extern PFN_vkCmdBlitImage2KHR vkCmdBlitImage2KHR; +extern PFN_vkCmdCopyBuffer2KHR vkCmdCopyBuffer2KHR; +extern PFN_vkCmdCopyBufferToImage2KHR vkCmdCopyBufferToImage2KHR; +extern PFN_vkCmdCopyImage2KHR vkCmdCopyImage2KHR; +extern PFN_vkCmdCopyImageToBuffer2KHR vkCmdCopyImageToBuffer2KHR; +extern PFN_vkCmdResolveImage2KHR vkCmdResolveImage2KHR; +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) +extern PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; +extern PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; +extern PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; +extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) +extern PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; +extern PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; +extern PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; +extern PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; +extern PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) +extern PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; +extern PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; +extern PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) +extern PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; +extern PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; +extern PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_device_group_creation) +extern PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR; +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) +extern PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; +extern PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; +extern PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +extern PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; +extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_display_swapchain) +extern PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) +extern PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; +extern PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) +extern PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR; +extern PFN_vkCmdEndRenderingKHR vkCmdEndRenderingKHR; +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_capabilities) +extern PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR vkGetPhysicalDeviceExternalFencePropertiesKHR; +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_fence_fd) +extern PFN_vkGetFenceFdKHR vkGetFenceFdKHR; +extern PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) +extern PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; +extern PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_capabilities) +extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_memory_fd) +extern PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; +extern PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) +extern PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; +extern PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_capabilities) +extern PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR vkGetPhysicalDeviceExternalSemaphorePropertiesKHR; +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_external_semaphore_fd) +extern PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; +extern PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) +extern PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; +extern PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) +extern PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR; +extern PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR; +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_display_properties2) +extern PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR; +extern PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR; +extern PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR; +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_memory_requirements2) +extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; +extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; +extern PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_get_physical_device_properties2) +extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) +extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_maintenance1) +extern PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) +extern PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) +extern PFN_vkGetDeviceBufferMemoryRequirementsKHR vkGetDeviceBufferMemoryRequirementsKHR; +extern PFN_vkGetDeviceImageMemoryRequirementsKHR vkGetDeviceImageMemoryRequirementsKHR; +extern PFN_vkGetDeviceImageSparseMemoryRequirementsKHR vkGetDeviceImageSparseMemoryRequirementsKHR; +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_maintenance5) +extern PFN_vkCmdBindIndexBuffer2KHR vkCmdBindIndexBuffer2KHR; +extern PFN_vkGetDeviceImageSubresourceLayoutKHR vkGetDeviceImageSubresourceLayoutKHR; +extern PFN_vkGetImageSubresourceLayout2KHR vkGetImageSubresourceLayout2KHR; +extern PFN_vkGetRenderingAreaGranularityKHR vkGetRenderingAreaGranularityKHR; +#endif /* defined(VK_KHR_maintenance5) */ +#if defined(VK_KHR_map_memory2) +extern PFN_vkMapMemory2KHR vkMapMemory2KHR; +extern PFN_vkUnmapMemory2KHR vkUnmapMemory2KHR; +#endif /* defined(VK_KHR_map_memory2) */ +#if defined(VK_KHR_performance_query) +extern PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; +extern PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR; +extern PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR; +extern PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) +extern PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; +extern PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; +extern PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) +extern PFN_vkWaitForPresentKHR vkWaitForPresentKHR; +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) +extern PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) +extern PFN_vkCmdTraceRaysIndirect2KHR vkCmdTraceRaysIndirect2KHR; +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) +extern PFN_vkCmdSetRayTracingPipelineStackSizeKHR vkCmdSetRayTracingPipelineStackSizeKHR; +extern PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; +extern PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; +extern PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; +extern PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; +extern PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; +extern PFN_vkGetRayTracingShaderGroupStackSizeKHR vkGetRayTracingShaderGroupStackSizeKHR; +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) +extern PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; +extern PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) +extern PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_surface) +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_swapchain) +extern PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; +extern PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; +extern PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; +extern PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; +extern PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) +extern PFN_vkCmdPipelineBarrier2KHR vkCmdPipelineBarrier2KHR; +extern PFN_vkCmdResetEvent2KHR vkCmdResetEvent2KHR; +extern PFN_vkCmdSetEvent2KHR vkCmdSetEvent2KHR; +extern PFN_vkCmdWaitEvents2KHR vkCmdWaitEvents2KHR; +extern PFN_vkCmdWriteTimestamp2KHR vkCmdWriteTimestamp2KHR; +extern PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR; +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) +extern PFN_vkCmdWriteBufferMarker2AMD vkCmdWriteBufferMarker2AMD; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) +extern PFN_vkGetQueueCheckpointData2NV vkGetQueueCheckpointData2NV; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) +extern PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; +extern PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; +extern PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) +extern PFN_vkCmdDecodeVideoKHR vkCmdDecodeVideoKHR; +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) +extern PFN_vkCmdEncodeVideoKHR vkCmdEncodeVideoKHR; +extern PFN_vkGetEncodedVideoSessionParametersKHR vkGetEncodedVideoSessionParametersKHR; +extern PFN_vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR; +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) +extern PFN_vkBindVideoSessionMemoryKHR vkBindVideoSessionMemoryKHR; +extern PFN_vkCmdBeginVideoCodingKHR vkCmdBeginVideoCodingKHR; +extern PFN_vkCmdControlVideoCodingKHR vkCmdControlVideoCodingKHR; +extern PFN_vkCmdEndVideoCodingKHR vkCmdEndVideoCodingKHR; +extern PFN_vkCreateVideoSessionKHR vkCreateVideoSessionKHR; +extern PFN_vkCreateVideoSessionParametersKHR vkCreateVideoSessionParametersKHR; +extern PFN_vkDestroyVideoSessionKHR vkDestroyVideoSessionKHR; +extern PFN_vkDestroyVideoSessionParametersKHR vkDestroyVideoSessionParametersKHR; +extern PFN_vkGetPhysicalDeviceVideoCapabilitiesKHR vkGetPhysicalDeviceVideoCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceVideoFormatPropertiesKHR vkGetPhysicalDeviceVideoFormatPropertiesKHR; +extern PFN_vkGetVideoSessionMemoryRequirementsKHR vkGetVideoSessionMemoryRequirementsKHR; +extern PFN_vkUpdateVideoSessionParametersKHR vkUpdateVideoSessionParametersKHR; +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_KHR_wayland_surface) +extern PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; +extern PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) +extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +extern PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) +extern PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; +extern PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) +extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; +extern PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) +extern PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK; +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) +extern PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) +extern PFN_vkCreateViSurfaceNN vkCreateViSurfaceNN; +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NVX_binary_import) +extern PFN_vkCmdCuLaunchKernelNVX vkCmdCuLaunchKernelNVX; +extern PFN_vkCreateCuFunctionNVX vkCreateCuFunctionNVX; +extern PFN_vkCreateCuModuleNVX vkCreateCuModuleNVX; +extern PFN_vkDestroyCuFunctionNVX vkDestroyCuFunctionNVX; +extern PFN_vkDestroyCuModuleNVX vkDestroyCuModuleNVX; +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) +extern PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; +extern PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_acquire_winrt_display) +extern PFN_vkAcquireWinrtDisplayNV vkAcquireWinrtDisplayNV; +extern PFN_vkGetWinrtDisplayNV vkGetWinrtDisplayNV; +#endif /* defined(VK_NV_acquire_winrt_display) */ +#if defined(VK_NV_clip_space_w_scaling) +extern PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_cooperative_matrix) +extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_copy_memory_indirect) +extern PFN_vkCmdCopyMemoryIndirectNV vkCmdCopyMemoryIndirectNV; +extern PFN_vkCmdCopyMemoryToImageIndirectNV vkCmdCopyMemoryToImageIndirectNV; +#endif /* defined(VK_NV_copy_memory_indirect) */ +#if defined(VK_NV_coverage_reduction_mode) +extern PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV; +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_cuda_kernel_launch) +extern PFN_vkCmdCudaLaunchKernelNV vkCmdCudaLaunchKernelNV; +extern PFN_vkCreateCudaFunctionNV vkCreateCudaFunctionNV; +extern PFN_vkCreateCudaModuleNV vkCreateCudaModuleNV; +extern PFN_vkDestroyCudaFunctionNV vkDestroyCudaFunctionNV; +extern PFN_vkDestroyCudaModuleNV vkDestroyCudaModuleNV; +extern PFN_vkGetCudaModuleCacheNV vkGetCudaModuleCacheNV; +#endif /* defined(VK_NV_cuda_kernel_launch) */ +#if defined(VK_NV_device_diagnostic_checkpoints) +extern PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; +extern PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) +extern PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; +extern PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; +extern PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; +extern PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; +extern PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; +extern PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_device_generated_commands_compute) +extern PFN_vkCmdUpdatePipelineIndirectBufferNV vkCmdUpdatePipelineIndirectBufferNV; +extern PFN_vkGetPipelineIndirectDeviceAddressNV vkGetPipelineIndirectDeviceAddressNV; +extern PFN_vkGetPipelineIndirectMemoryRequirementsNV vkGetPipelineIndirectMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands_compute) */ +#if defined(VK_NV_external_memory_capabilities) +extern PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV vkGetPhysicalDeviceExternalImageFormatPropertiesNV; +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if defined(VK_NV_external_memory_rdma) +extern PFN_vkGetMemoryRemoteAddressNV vkGetMemoryRemoteAddressNV; +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) +extern PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) +extern PFN_vkCmdSetFragmentShadingRateEnumNV vkCmdSetFragmentShadingRateEnumNV; +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_low_latency2) +extern PFN_vkGetLatencyTimingsNV vkGetLatencyTimingsNV; +extern PFN_vkLatencySleepNV vkLatencySleepNV; +extern PFN_vkQueueNotifyOutOfBandNV vkQueueNotifyOutOfBandNV; +extern PFN_vkSetLatencyMarkerNV vkSetLatencyMarkerNV; +extern PFN_vkSetLatencySleepModeNV vkSetLatencySleepModeNV; +#endif /* defined(VK_NV_low_latency2) */ +#if defined(VK_NV_memory_decompression) +extern PFN_vkCmdDecompressMemoryIndirectCountNV vkCmdDecompressMemoryIndirectCountNV; +extern PFN_vkCmdDecompressMemoryNV vkCmdDecompressMemoryNV; +#endif /* defined(VK_NV_memory_decompression) */ +#if defined(VK_NV_mesh_shader) +extern PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; +extern PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; +extern PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_optical_flow) +extern PFN_vkBindOpticalFlowSessionImageNV vkBindOpticalFlowSessionImageNV; +extern PFN_vkCmdOpticalFlowExecuteNV vkCmdOpticalFlowExecuteNV; +extern PFN_vkCreateOpticalFlowSessionNV vkCreateOpticalFlowSessionNV; +extern PFN_vkDestroyOpticalFlowSessionNV vkDestroyOpticalFlowSessionNV; +extern PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV vkGetPhysicalDeviceOpticalFlowImageFormatsNV; +#endif /* defined(VK_NV_optical_flow) */ +#if defined(VK_NV_ray_tracing) +extern PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; +extern PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; +extern PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; +extern PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; +extern PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; +extern PFN_vkCompileDeferredNV vkCompileDeferredNV; +extern PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; +extern PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; +extern PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; +extern PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; +extern PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; +extern PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 +extern PFN_vkCmdSetExclusiveScissorEnableNV vkCmdSetExclusiveScissorEnableNV; +#endif /* defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 */ +#if defined(VK_NV_scissor_exclusive) +extern PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) +extern PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; +extern PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; +extern PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_QCOM_tile_properties) +extern PFN_vkGetDynamicRenderingTilePropertiesQCOM vkGetDynamicRenderingTilePropertiesQCOM; +extern PFN_vkGetFramebufferTilePropertiesQCOM vkGetFramebufferTilePropertiesQCOM; +#endif /* defined(VK_QCOM_tile_properties) */ +#if defined(VK_QNX_external_memory_screen_buffer) +extern PFN_vkGetScreenBufferPropertiesQNX vkGetScreenBufferPropertiesQNX; +#endif /* defined(VK_QNX_external_memory_screen_buffer) */ +#if defined(VK_QNX_screen_surface) +extern PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX; +extern PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX; +#endif /* defined(VK_QNX_screen_surface) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) +extern PFN_vkGetDescriptorSetHostMappingVALVE vkGetDescriptorSetHostMappingVALVE; +extern PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE vkGetDescriptorSetLayoutHostMappingInfoVALVE; +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) +extern PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; +extern PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; +extern PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; +extern PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; +extern PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; +extern PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; +extern PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; +extern PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; +extern PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; +extern PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; +extern PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; +extern PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) +extern PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT; +extern PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT; +extern PFN_vkCmdSetPatchControlPointsEXT vkCmdSetPatchControlPointsEXT; +extern PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT; +extern PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) +extern PFN_vkCmdSetAlphaToCoverageEnableEXT vkCmdSetAlphaToCoverageEnableEXT; +extern PFN_vkCmdSetAlphaToOneEnableEXT vkCmdSetAlphaToOneEnableEXT; +extern PFN_vkCmdSetColorBlendAdvancedEXT vkCmdSetColorBlendAdvancedEXT; +extern PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT; +extern PFN_vkCmdSetColorBlendEquationEXT vkCmdSetColorBlendEquationEXT; +extern PFN_vkCmdSetColorWriteMaskEXT vkCmdSetColorWriteMaskEXT; +extern PFN_vkCmdSetConservativeRasterizationModeEXT vkCmdSetConservativeRasterizationModeEXT; +extern PFN_vkCmdSetDepthClampEnableEXT vkCmdSetDepthClampEnableEXT; +extern PFN_vkCmdSetDepthClipEnableEXT vkCmdSetDepthClipEnableEXT; +extern PFN_vkCmdSetDepthClipNegativeOneToOneEXT vkCmdSetDepthClipNegativeOneToOneEXT; +extern PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT vkCmdSetExtraPrimitiveOverestimationSizeEXT; +extern PFN_vkCmdSetLineRasterizationModeEXT vkCmdSetLineRasterizationModeEXT; +extern PFN_vkCmdSetLineStippleEnableEXT vkCmdSetLineStippleEnableEXT; +extern PFN_vkCmdSetLogicOpEnableEXT vkCmdSetLogicOpEnableEXT; +extern PFN_vkCmdSetPolygonModeEXT vkCmdSetPolygonModeEXT; +extern PFN_vkCmdSetProvokingVertexModeEXT vkCmdSetProvokingVertexModeEXT; +extern PFN_vkCmdSetRasterizationSamplesEXT vkCmdSetRasterizationSamplesEXT; +extern PFN_vkCmdSetRasterizationStreamEXT vkCmdSetRasterizationStreamEXT; +extern PFN_vkCmdSetSampleLocationsEnableEXT vkCmdSetSampleLocationsEnableEXT; +extern PFN_vkCmdSetSampleMaskEXT vkCmdSetSampleMaskEXT; +extern PFN_vkCmdSetTessellationDomainOriginEXT vkCmdSetTessellationDomainOriginEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) +extern PFN_vkCmdSetViewportWScalingEnableNV vkCmdSetViewportWScalingEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) +extern PFN_vkCmdSetViewportSwizzleNV vkCmdSetViewportSwizzleNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) +extern PFN_vkCmdSetCoverageToColorEnableNV vkCmdSetCoverageToColorEnableNV; +extern PFN_vkCmdSetCoverageToColorLocationNV vkCmdSetCoverageToColorLocationNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) +extern PFN_vkCmdSetCoverageModulationModeNV vkCmdSetCoverageModulationModeNV; +extern PFN_vkCmdSetCoverageModulationTableEnableNV vkCmdSetCoverageModulationTableEnableNV; +extern PFN_vkCmdSetCoverageModulationTableNV vkCmdSetCoverageModulationTableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) +extern PFN_vkCmdSetShadingRateImageEnableNV vkCmdSetShadingRateImageEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) +extern PFN_vkCmdSetRepresentativeFragmentTestEnableNV vkCmdSetRepresentativeFragmentTestEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) +extern PFN_vkCmdSetCoverageReductionModeNV vkCmdSetCoverageReductionModeNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) +extern PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) +extern PFN_vkGetImageSubresourceLayout2EXT vkGetImageSubresourceLayout2EXT; +#endif /* (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) */ +#if (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) +extern PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT; +#endif /* (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) +extern PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +extern PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; +extern PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +extern PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +extern PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +/* VOLK_GENERATE_PROTOTYPES_H */ + +#ifdef __cplusplus +} +#endif + +#endif + +#ifdef VOLK_IMPLEMENTATION +#undef VOLK_IMPLEMENTATION +/* Prevent tools like dependency checkers from detecting a cyclic dependency */ +#define VOLK_SOURCE "volk.c" +#include VOLK_SOURCE +#endif + +/** + * Copyright (c) 2018-2023 Arseny Kapoulkine + * + * 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. +*/ +/* clang-format on */ diff --git a/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h b/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h new file mode 100644 index 00000000000..4e116766951 --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h @@ -0,0 +1,580 @@ +#pragma once + +#include "vulkanobjects.h" +#include +#include + +class VulkanCompatibleDevice; + +class VulkanInstanceBuilder +{ +public: + VulkanInstanceBuilder(); + + VulkanInstanceBuilder& ApiVersionsToTry(const std::vector& versions); + VulkanInstanceBuilder& RequireExtension(const std::string& extensionName); + VulkanInstanceBuilder& RequireSurfaceExtensions(bool enable = true); + VulkanInstanceBuilder& OptionalExtension(const std::string& extensionName); + VulkanInstanceBuilder& DebugLayer(bool enable = true); + + std::shared_ptr Create(); + +private: + std::vector apiVersionsToTry; + std::set requiredExtensions; + std::set optionalExtensions; + bool debugLayer = false; +}; + +#ifdef VK_USE_PLATFORM_WIN32_KHR + +class VulkanSurfaceBuilder +{ +public: + VulkanSurfaceBuilder(); + + VulkanSurfaceBuilder& Win32Window(HWND handle); + + std::shared_ptr Create(std::shared_ptr instance); + +private: + HWND hwnd = {}; +}; + +#endif + +class VulkanDeviceBuilder +{ +public: + VulkanDeviceBuilder(); + + VulkanDeviceBuilder& RequireExtension(const std::string& extensionName); + VulkanDeviceBuilder& OptionalExtension(const std::string& extensionName); + VulkanDeviceBuilder& OptionalRayQuery(); + VulkanDeviceBuilder& OptionalDescriptorIndexing(); + VulkanDeviceBuilder& Surface(std::shared_ptr surface); + VulkanDeviceBuilder& SelectDevice(int index); + + std::vector FindDevices(const std::shared_ptr& instance); + std::shared_ptr Create(std::shared_ptr instance); + +private: + std::set requiredDeviceExtensions; + std::set optionalDeviceExtensions; + std::shared_ptr surface; + int deviceIndex = 0; +}; + +class VulkanSwapChainBuilder +{ +public: + VulkanSwapChainBuilder(); + + std::shared_ptr Create(VulkanDevice* device); +}; + +class CommandPoolBuilder +{ +public: + CommandPoolBuilder(); + + CommandPoolBuilder& QueueFamily(int index); + CommandPoolBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice* device); + +private: + const char* debugName = nullptr; + int queueFamilyIndex = -1; +}; + +class SemaphoreBuilder +{ +public: + SemaphoreBuilder(); + + SemaphoreBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice* device); + +private: + const char* debugName = nullptr; +}; + +class FenceBuilder +{ +public: + FenceBuilder(); + + FenceBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice* device); + +private: + const char* debugName = nullptr; +}; + +class ImageBuilder +{ +public: + ImageBuilder(); + + ImageBuilder& Size(int width, int height, int miplevels = 1, int arrayLayers = 1); + ImageBuilder& Samples(VkSampleCountFlagBits samples); + ImageBuilder& Format(VkFormat format); + ImageBuilder& Usage(VkImageUsageFlags imageUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0); + ImageBuilder& MemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0); + ImageBuilder& LinearTiling(); + ImageBuilder& DebugName(const char* name) { debugName = name; return *this; } + + bool IsFormatSupported(VulkanDevice *device, VkFormatFeatureFlags bufferFeatures = 0); + + std::unique_ptr Create(VulkanDevice *device, VkDeviceSize* allocatedBytes = nullptr); + std::unique_ptr TryCreate(VulkanDevice *device); + +private: + VkImageCreateInfo imageInfo = {}; + VmaAllocationCreateInfo allocInfo = {}; + const char* debugName = nullptr; +}; + +class ImageViewBuilder +{ +public: + ImageViewBuilder(); + + ImageViewBuilder& Type(VkImageViewType type); + ImageViewBuilder& Image(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int mipLevel = 0, int arrayLayer = 0, int levelCount = 0, int layerCount = 0); + ImageViewBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkImageViewCreateInfo viewInfo = {}; + const char* debugName = nullptr; +}; + +class SamplerBuilder +{ +public: + SamplerBuilder(); + + SamplerBuilder& AddressMode(VkSamplerAddressMode addressMode); + SamplerBuilder& AddressMode(VkSamplerAddressMode u, VkSamplerAddressMode v, VkSamplerAddressMode w); + SamplerBuilder& MinFilter(VkFilter minFilter); + SamplerBuilder& MagFilter(VkFilter magFilter); + SamplerBuilder& MipmapMode(VkSamplerMipmapMode mode); + SamplerBuilder& Anisotropy(float maxAnisotropy); + SamplerBuilder& MipLodBias(float bias); + SamplerBuilder& MaxLod(float value); + SamplerBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkSamplerCreateInfo samplerInfo = {}; + const char* debugName = nullptr; +}; + +class BufferBuilder +{ +public: + BufferBuilder(); + + BufferBuilder& Size(size_t size); + BufferBuilder& Usage(VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0); + BufferBuilder& MemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0); + BufferBuilder& MinAlignment(VkDeviceSize memoryAlignment); + BufferBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkBufferCreateInfo bufferInfo = {}; + VmaAllocationCreateInfo allocInfo = {}; + const char* debugName = nullptr; + VkDeviceSize minAlignment = 0; +}; + +enum class ShaderType +{ + Vertex, + TessControl, + TessEvaluation, + Geometry, + Fragment, + Compute +}; + +class ShaderIncludeResult +{ +public: + ShaderIncludeResult(std::string name, std::string text) : name(std::move(name)), text(std::move(text)) { } + ShaderIncludeResult(std::string error) : text(std::move(error)) { } + + std::string name; // fully resolved name of the included header file + std::string text; // the file contents - or include error message if name is empty +}; + +class ShaderBuilder +{ +public: + ShaderBuilder(); + + static void Init(); + static void Deinit(); + + ShaderBuilder& Type(ShaderType type); + ShaderBuilder& AddSource(const std::string& name, const std::string& code); + + ShaderBuilder& OnIncludeSystem(std::function onIncludeSystem); + ShaderBuilder& OnIncludeLocal(std::function onIncludeLocal); + + ShaderBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(const char *shadername, VulkanDevice *device); + +private: + std::vector> sources; + std::function onIncludeSystem; + std::function onIncludeLocal; + int stage = 0; + const char* debugName = nullptr; + friend class ShaderBuilderIncluderImpl; +}; + +class AccelerationStructureBuilder +{ +public: + AccelerationStructureBuilder(); + + AccelerationStructureBuilder& Type(VkAccelerationStructureTypeKHR type); + AccelerationStructureBuilder& Buffer(VulkanBuffer* buffer, VkDeviceSize size); + AccelerationStructureBuilder& Buffer(VulkanBuffer* buffer, VkDeviceSize offset, VkDeviceSize size); + AccelerationStructureBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice* device); + +private: + VkAccelerationStructureCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR }; + const char* debugName = nullptr; +}; + +class ComputePipelineBuilder +{ +public: + ComputePipelineBuilder(); + + ComputePipelineBuilder& Cache(VulkanPipelineCache* cache); + ComputePipelineBuilder& Layout(VulkanPipelineLayout *layout); + ComputePipelineBuilder& ComputeShader(VulkanShader *shader); + ComputePipelineBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkComputePipelineCreateInfo pipelineInfo = {}; + VkPipelineShaderStageCreateInfo stageInfo = {}; + VulkanPipelineCache* cache = nullptr; + const char* debugName = nullptr; +}; + +class DescriptorSetLayoutBuilder +{ +public: + DescriptorSetLayoutBuilder(); + + DescriptorSetLayoutBuilder& Flags(VkDescriptorSetLayoutCreateFlags flags); + DescriptorSetLayoutBuilder& AddBinding(int binding, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags, VkDescriptorBindingFlags flags = 0); + DescriptorSetLayoutBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkDescriptorSetLayoutCreateInfo layoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT }; + std::vector bindings; + std::vector bindingFlags; + const char* debugName = nullptr; +}; + +class DescriptorPoolBuilder +{ +public: + DescriptorPoolBuilder(); + + DescriptorPoolBuilder& Flags(VkDescriptorPoolCreateFlags flags); + DescriptorPoolBuilder& MaxSets(int value); + DescriptorPoolBuilder& AddPoolSize(VkDescriptorType type, int count); + DescriptorPoolBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + std::vector poolSizes; + VkDescriptorPoolCreateInfo poolInfo = {}; + const char* debugName = nullptr; +}; + +class QueryPoolBuilder +{ +public: + QueryPoolBuilder(); + + QueryPoolBuilder& QueryType(VkQueryType type, int count, VkQueryPipelineStatisticFlags pipelineStatistics = 0); + QueryPoolBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkQueryPoolCreateInfo poolInfo = {}; + const char* debugName = nullptr; +}; + +class FramebufferBuilder +{ +public: + FramebufferBuilder(); + + FramebufferBuilder& RenderPass(VulkanRenderPass *renderPass); + FramebufferBuilder& AddAttachment(VulkanImageView *view); + FramebufferBuilder& AddAttachment(VkImageView view); + FramebufferBuilder& Size(int width, int height, int layers = 1); + FramebufferBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkFramebufferCreateInfo framebufferInfo = {}; + std::vector attachments; + const char* debugName = nullptr; +}; + +class ColorBlendAttachmentBuilder +{ +public: + ColorBlendAttachmentBuilder(); + + ColorBlendAttachmentBuilder& ColorWriteMask(VkColorComponentFlags mask); + ColorBlendAttachmentBuilder& AdditiveBlendMode(); + ColorBlendAttachmentBuilder& AlphaBlendMode(); + ColorBlendAttachmentBuilder& BlendMode(VkBlendOp op, VkBlendFactor src, VkBlendFactor dst); + + VkPipelineColorBlendAttachmentState Create() { return colorBlendAttachment; } + +private: + VkPipelineColorBlendAttachmentState colorBlendAttachment = { }; +}; + +class GraphicsPipelineBuilder +{ +public: + GraphicsPipelineBuilder(); + + GraphicsPipelineBuilder& Cache(VulkanPipelineCache* cache); + GraphicsPipelineBuilder& Subpass(int subpass); + GraphicsPipelineBuilder& Layout(VulkanPipelineLayout *layout); + GraphicsPipelineBuilder& RenderPass(VulkanRenderPass *renderPass); + GraphicsPipelineBuilder& Topology(VkPrimitiveTopology topology); + GraphicsPipelineBuilder& Viewport(float x, float y, float width, float height, float minDepth = 0.0f, float maxDepth = 1.0f); + GraphicsPipelineBuilder& Scissor(int x, int y, int width, int height); + GraphicsPipelineBuilder& RasterizationSamples(VkSampleCountFlagBits samples); + + GraphicsPipelineBuilder& Cull(VkCullModeFlags cullMode, VkFrontFace frontFace); + GraphicsPipelineBuilder& DepthStencilEnable(bool test, bool write, bool stencil); + GraphicsPipelineBuilder& DepthFunc(VkCompareOp func); + GraphicsPipelineBuilder& DepthClampEnable(bool value); + GraphicsPipelineBuilder& DepthBias(bool enable, float biasConstantFactor, float biasClamp, float biasSlopeFactor); + GraphicsPipelineBuilder& Stencil(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp, uint32_t compareMask, uint32_t writeMask, uint32_t reference); + + GraphicsPipelineBuilder& AddColorBlendAttachment(VkPipelineColorBlendAttachmentState state); + + GraphicsPipelineBuilder& AddVertexShader(VulkanShader *shader); + GraphicsPipelineBuilder& AddFragmentShader(VulkanShader *shader); + + GraphicsPipelineBuilder& AddVertexBufferBinding(int index, size_t stride); + GraphicsPipelineBuilder& AddVertexAttribute(int location, int binding, VkFormat format, size_t offset); + + GraphicsPipelineBuilder& AddDynamicState(VkDynamicState state); + + GraphicsPipelineBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkGraphicsPipelineCreateInfo pipelineInfo = { }; + VkPipelineVertexInputStateCreateInfo vertexInputInfo = { }; + VkPipelineInputAssemblyStateCreateInfo inputAssembly = { }; + VkViewport viewport = { }; + VkRect2D scissor = { }; + VkPipelineViewportStateCreateInfo viewportState = { }; + VkPipelineRasterizationStateCreateInfo rasterizer = { }; + VkPipelineMultisampleStateCreateInfo multisampling = { }; + VkPipelineColorBlendStateCreateInfo colorBlending = { }; + VkPipelineDepthStencilStateCreateInfo depthStencil = { }; + VkPipelineDynamicStateCreateInfo dynamicState = {}; + + std::vector shaderStages; + std::vector colorBlendAttachments; + std::vector vertexInputBindings; + std::vector vertexInputAttributes; + std::vector dynamicStates; + + VulkanPipelineCache* cache = nullptr; + const char* debugName = nullptr; +}; + +class PipelineLayoutBuilder +{ +public: + PipelineLayoutBuilder(); + + PipelineLayoutBuilder& AddSetLayout(VulkanDescriptorSetLayout *setLayout); + PipelineLayoutBuilder& AddPushConstantRange(VkShaderStageFlags stageFlags, size_t offset, size_t size); + + PipelineLayoutBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + std::vector setLayouts; + std::vector pushConstantRanges; + const char* debugName = nullptr; +}; + +class PipelineCacheBuilder +{ +public: + PipelineCacheBuilder(); + + PipelineCacheBuilder& InitialData(const void* data, size_t size); + PipelineCacheBuilder& Flags(VkPipelineCacheCreateFlags flags); + + PipelineCacheBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice* device); + +private: + VkPipelineCacheCreateInfo pipelineCacheInfo = {}; + std::vector initData; + const char* debugName = nullptr; +}; + +class RenderPassBuilder +{ +public: + RenderPassBuilder(); + + RenderPassBuilder& AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkImageLayout initialLayout, VkImageLayout finalLayout); + RenderPassBuilder& AddDepthStencilAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkAttachmentLoadOp stencilLoad, VkAttachmentStoreOp stencilStore, VkImageLayout initialLayout, VkImageLayout finalLayout); + + RenderPassBuilder& AddExternalSubpassDependency(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); + + RenderPassBuilder& AddSubpass(); + RenderPassBuilder& AddSubpassColorAttachmentRef(uint32_t index, VkImageLayout layout); + RenderPassBuilder& AddSubpassDepthStencilAttachmentRef(uint32_t index, VkImageLayout layout); + + RenderPassBuilder& DebugName(const char* name) { debugName = name; return *this; } + + std::unique_ptr Create(VulkanDevice *device); + +private: + VkRenderPassCreateInfo renderPassInfo = { }; + + std::vector attachments; + std::vector dependencies; + std::vector subpasses; + + struct SubpassData + { + std::vector colorRefs; + VkAttachmentReference depthRef = { }; + }; + + std::vector> subpassData; + + const char* debugName = nullptr; +}; + +class PipelineBarrier +{ +public: + PipelineBarrier& AddMemory(VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); + PipelineBarrier& AddBuffer(VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); + PipelineBarrier& AddBuffer(VulkanBuffer *buffer, VkDeviceSize offset, VkDeviceSize size, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); + PipelineBarrier& AddImage(VulkanImage *image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1, int baseArrayLayer = 0, int layerCount = 1); + PipelineBarrier& AddImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1, int baseArrayLayer = 0, int layerCount = 1); + PipelineBarrier& AddQueueTransfer(int srcFamily, int dstFamily, VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); + PipelineBarrier& AddQueueTransfer(int srcFamily, int dstFamily, VulkanImage *image, VkImageLayout layout, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1); + + void Execute(VulkanCommandBuffer *commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags = 0); + +private: + std::vector memoryBarriers; + std::vector bufferMemoryBarriers; + std::vector imageMemoryBarriers; +}; + +class QueueSubmit +{ +public: + QueueSubmit(); + + QueueSubmit& AddCommandBuffer(VulkanCommandBuffer *buffer); + QueueSubmit& AddWait(VkPipelineStageFlags waitStageMask, VulkanSemaphore *semaphore); + QueueSubmit& AddSignal(VulkanSemaphore *semaphore); + void Execute(VulkanDevice *device, VkQueue queue, VulkanFence *fence = nullptr); + +private: + VkSubmitInfo submitInfo = {}; + std::vector waitSemaphores; + std::vector waitStages; + std::vector signalSemaphores; + std::vector commandBuffers; +}; + +class WriteDescriptors +{ +public: + WriteDescriptors& AddBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer); + WriteDescriptors& AddBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer, size_t offset, size_t range); + WriteDescriptors& AddStorageImage(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VkImageLayout imageLayout); + WriteDescriptors& AddCombinedImageSampler(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VulkanSampler *sampler, VkImageLayout imageLayout); + WriteDescriptors& AddCombinedImageSampler(VulkanDescriptorSet* descriptorSet, int binding, int arrayIndex, VulkanImageView* view, VulkanSampler* sampler, VkImageLayout imageLayout); + WriteDescriptors& AddAccelerationStructure(VulkanDescriptorSet* descriptorSet, int binding, VulkanAccelerationStructure* accelStruct); + void Execute(VulkanDevice *device); + +private: + struct WriteExtra + { + VkDescriptorImageInfo imageInfo; + VkDescriptorBufferInfo bufferInfo; + VkBufferView bufferView; + VkWriteDescriptorSetAccelerationStructureKHR accelStruct; + }; + + std::vector writes; + std::vector> writeExtras; +}; + +class BufferTransfer +{ +public: + BufferTransfer& AddBuffer(VulkanBuffer* buffer, size_t offset, const void* data, size_t size); + BufferTransfer& AddBuffer(VulkanBuffer* buffer, const void* data, size_t size); + BufferTransfer& AddBuffer(VulkanBuffer* buffer, const void* data0, size_t size0, const void* data1, size_t size1); + std::unique_ptr Execute(VulkanDevice* device, VulkanCommandBuffer* cmdbuffer); + +private: + struct BufferCopy + { + VulkanBuffer* buffer; + size_t offset; + const void* data0; + size_t size0; + const void* data1; + size_t size1; + }; + std::vector bufferCopies; +}; diff --git a/libraries/ZVulkan/include/zvulkan/vulkancompatibledevice.h b/libraries/ZVulkan/include/zvulkan/vulkancompatibledevice.h new file mode 100644 index 00000000000..9a2cd5e424b --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/vulkancompatibledevice.h @@ -0,0 +1,19 @@ +#pragma once + +#include "vulkaninstance.h" + +class VulkanSurface; + +class VulkanCompatibleDevice +{ +public: + VulkanPhysicalDevice* Device = nullptr; + + int GraphicsFamily = -1; + int PresentFamily = -1; + + bool GraphicsTimeQueries = false; + + std::set EnabledDeviceExtensions; + VulkanDeviceFeatures EnabledFeatures; +}; diff --git a/libraries/ZVulkan/include/zvulkan/vulkandevice.h b/libraries/ZVulkan/include/zvulkan/vulkandevice.h new file mode 100644 index 00000000000..c7d0822d632 --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/vulkandevice.h @@ -0,0 +1,52 @@ +#pragma once + +#include "vulkaninstance.h" + +#include +#include +#include +#include +#include + +class VulkanSwapChain; +class VulkanSemaphore; +class VulkanFence; +class VulkanPhysicalDevice; +class VulkanSurface; +class VulkanCompatibleDevice; + +class VulkanDevice +{ +public: + VulkanDevice(std::shared_ptr instance, std::shared_ptr surface, const VulkanCompatibleDevice& selectedDevice); + ~VulkanDevice(); + + std::set EnabledDeviceExtensions; + VulkanDeviceFeatures EnabledFeatures; + + VulkanPhysicalDevice PhysicalDevice; + + std::shared_ptr Instance; + std::shared_ptr Surface; + + VkDevice device = VK_NULL_HANDLE; + VmaAllocator allocator = VK_NULL_HANDLE; + + VkQueue GraphicsQueue = VK_NULL_HANDLE; + VkQueue PresentQueue = VK_NULL_HANDLE; + + int GraphicsFamily = -1; + int PresentFamily = -1; + bool GraphicsTimeQueries = false; + + bool SupportsExtension(const char* ext) const; + + void SetObjectName(const char* name, uint64_t handle, VkObjectType type); + +private: + bool DebugLayerActive = false; + + void CreateDevice(); + void CreateAllocator(); + void ReleaseResources(); +}; diff --git a/libraries/ZVulkan/include/zvulkan/vulkaninstance.h b/libraries/ZVulkan/include/zvulkan/vulkaninstance.h new file mode 100644 index 00000000000..1074ce4203f --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/vulkaninstance.h @@ -0,0 +1,103 @@ +#pragma once + +#if defined(_WIN32) +#define VK_USE_PLATFORM_WIN32_KHR +#elif defined(__APPLE__) +#define VK_USE_PLATFORM_MACOS_MVK +#define VK_USE_PLATFORM_METAL_EXT +#endif + +#include "volk/volk.h" +#include "vk_mem_alloc/vk_mem_alloc.h" + +#if defined(_WIN32) +#undef min +#undef max +#endif + +#include +#include +#include +#include +#include + +class VulkanDeviceFeatures +{ +public: + VkPhysicalDeviceFeatures Features = {}; + VkPhysicalDeviceBufferDeviceAddressFeatures BufferDeviceAddress = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES }; + VkPhysicalDeviceAccelerationStructureFeaturesKHR AccelerationStructure = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR }; + VkPhysicalDeviceRayQueryFeaturesKHR RayQuery = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR }; + VkPhysicalDeviceDescriptorIndexingFeatures DescriptorIndexing = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT }; +}; + +class VulkanDeviceProperties +{ +public: + VkPhysicalDeviceProperties Properties = {}; + VkPhysicalDeviceMemoryProperties Memory = {}; + VkPhysicalDeviceAccelerationStructurePropertiesKHR AccelerationStructure = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR }; + VkPhysicalDeviceDescriptorIndexingProperties DescriptorIndexing = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT }; + VkPhysicalDeviceLayeredDriverPropertiesMSFT LayeredDriver = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT }; +}; + +class VulkanPhysicalDevice +{ +public: + VkPhysicalDevice Device = VK_NULL_HANDLE; + std::vector Extensions; + std::vector QueueFamilies; + VulkanDeviceProperties Properties; + VulkanDeviceFeatures Features; +}; + +class VulkanInstance +{ +public: + VulkanInstance(std::vector apiVersionsToTry, std::set requiredExtensions, std::set optionalExtensions, bool wantDebugLayer); + ~VulkanInstance(); + + std::vector ApiVersionsToTry; + + std::set RequiredExtensions; + std::set OptionalExtensions; + + std::vector AvailableLayers; + std::vector AvailableExtensions; + + std::set EnabledValidationLayers; + std::set EnabledExtensions; + + std::vector PhysicalDevices; + + uint32_t ApiVersion = {}; + VkInstance Instance = VK_NULL_HANDLE; + + bool DebugLayerActive = false; + +private: + bool WantDebugLayer = false; + VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; + + void CreateInstance(); + void ReleaseResources(); + + static void InitVolk(); + static std::vector GetAvailableLayers(); + static std::vector GetExtensions(); + static std::vector GetPhysicalDevices(VkInstance instance, uint32_t apiVersion); + + static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); + static std::vector SplitString(const std::string& s, const std::string& seperator); +}; + +std::string VkResultToString(VkResult result); + +void VulkanPrintLog(const char* typestr, const std::string& msg); +void VulkanError(const char* text); + +inline void CheckVulkanError(VkResult result, const char* text) +{ + if (result >= VK_SUCCESS) return; + VulkanError((text + std::string(": ") + VkResultToString(result)).c_str()); +} diff --git a/libraries/ZVulkan/include/zvulkan/vulkanobjects.h b/libraries/ZVulkan/include/zvulkan/vulkanobjects.h new file mode 100644 index 00000000000..c7842f67013 --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/vulkanobjects.h @@ -0,0 +1,1234 @@ +#pragma once + +#include "vulkandevice.h" + +class VulkanCommandPool; +class VulkanDescriptorPool; +class VulkanCommandBuffer; + +class VulkanSemaphore +{ +public: + VulkanSemaphore(VulkanDevice *device); + ~VulkanSemaphore(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)semaphore, VK_OBJECT_TYPE_SEMAPHORE); } + + VulkanDevice *device = nullptr; + VkSemaphore semaphore = VK_NULL_HANDLE; + +private: + VulkanSemaphore(const VulkanSemaphore &) = delete; + VulkanSemaphore &operator=(const VulkanSemaphore &) = delete; +}; + +class VulkanFence +{ +public: + VulkanFence(VulkanDevice *device); + ~VulkanFence(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)fence, VK_OBJECT_TYPE_FENCE); } + + VulkanDevice *device = nullptr; + VkFence fence = VK_NULL_HANDLE; + +private: + VulkanFence(const VulkanFence &) = delete; + VulkanFence &operator=(const VulkanFence &) = delete; +}; + +class VulkanBuffer +{ +public: + VulkanBuffer(VulkanDevice *device, VkBuffer buffer, VmaAllocation allocation, size_t size); + ~VulkanBuffer(); + + VkDeviceAddress GetDeviceAddress() + { + VkBufferDeviceAddressInfo info = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO }; + info.buffer = buffer; + return vkGetBufferDeviceAddress(device->device, &info); + } + +#ifdef _DEBUG + void SetDebugName(const char* name) { debugName = name; device->SetObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER); } + std::string debugName; +#else + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER); } +#endif + + VulkanDevice *device = nullptr; + + VkBuffer buffer; + VmaAllocation allocation; + size_t size = 0; + + void *Map(size_t offset, size_t size); + void Unmap(); + +private: + VulkanBuffer(const VulkanBuffer &) = delete; + VulkanBuffer &operator=(const VulkanBuffer &) = delete; +}; + +class VulkanFramebuffer +{ +public: + VulkanFramebuffer(VulkanDevice *device, VkFramebuffer framebuffer); + ~VulkanFramebuffer(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)framebuffer, VK_OBJECT_TYPE_FRAMEBUFFER); } + + VulkanDevice *device; + VkFramebuffer framebuffer; + +private: + VulkanFramebuffer(const VulkanFramebuffer &) = delete; + VulkanFramebuffer &operator=(const VulkanFramebuffer &) = delete; +}; + +class VulkanImage +{ +public: + VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels, int layerCount); + ~VulkanImage(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)image, VK_OBJECT_TYPE_IMAGE); } + + VkImage image = VK_NULL_HANDLE; + int width = 0; + int height = 0; + int mipLevels = 1; + int layerCount = 1; + + void *Map(size_t offset, size_t size); + void Unmap(); + +private: + VulkanDevice *device = nullptr; + VmaAllocation allocation; + + VulkanImage(const VulkanImage &) = delete; + VulkanImage &operator=(const VulkanImage &) = delete; +}; + +class VulkanImageView +{ +public: + VulkanImageView(VulkanDevice *device, VkImageView view); + ~VulkanImageView(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)view, VK_OBJECT_TYPE_IMAGE_VIEW); } + + VkImageView view = VK_NULL_HANDLE; + +private: + VulkanImageView(const VulkanImageView &) = delete; + VulkanImageView &operator=(const VulkanImageView &) = delete; + + VulkanDevice *device = nullptr; +}; + +class VulkanSampler +{ +public: + VulkanSampler(VulkanDevice *device, VkSampler sampler); + ~VulkanSampler(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)sampler, VK_OBJECT_TYPE_SAMPLER); } + + VkSampler sampler = VK_NULL_HANDLE; + +private: + VulkanSampler(const VulkanSampler &) = delete; + VulkanSampler &operator=(const VulkanSampler &) = delete; + + VulkanDevice *device = nullptr; +}; + +class VulkanShader +{ +public: + VulkanShader(VulkanDevice *device, VkShaderModule module); + ~VulkanShader(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)module, VK_OBJECT_TYPE_SHADER_MODULE); } + + VkShaderModule module = VK_NULL_HANDLE; + +private: + VulkanDevice *device = nullptr; + + VulkanShader(const VulkanShader &) = delete; + VulkanShader &operator=(const VulkanShader &) = delete; +}; + +class VulkanDescriptorSetLayout +{ +public: + VulkanDescriptorSetLayout(VulkanDevice *device, VkDescriptorSetLayout layout); + ~VulkanDescriptorSetLayout(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)layout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT); } + + VulkanDevice *device; + VkDescriptorSetLayout layout; + +private: + VulkanDescriptorSetLayout(const VulkanDescriptorSetLayout &) = delete; + VulkanDescriptorSetLayout &operator=(const VulkanDescriptorSetLayout &) = delete; +}; + +class VulkanDescriptorSet +{ +public: + VulkanDescriptorSet(VulkanDevice *device, VulkanDescriptorPool *pool, VkDescriptorSet set); + ~VulkanDescriptorSet(); + +#ifdef _DEBUG + void SetDebugName(const char* name) { debugName = name; device->SetObjectName(name, (uint64_t)set, VK_OBJECT_TYPE_DESCRIPTOR_SET); } + std::string debugName; +#else + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)set, VK_OBJECT_TYPE_DESCRIPTOR_SET); } +#endif + + VulkanDevice *device; + VulkanDescriptorPool *pool; + VkDescriptorSet set; + +private: + VulkanDescriptorSet(const VulkanDescriptorSet &) = delete; + VulkanDescriptorSet &operator=(const VulkanDescriptorSet &) = delete; +}; + +class VulkanDescriptorPool +{ +public: + VulkanDescriptorPool(VulkanDevice *device, VkDescriptorPool pool); + ~VulkanDescriptorPool(); + +#ifdef _DEBUG + void SetDebugName(const char* name) { debugName = name; device->SetObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_DESCRIPTOR_POOL); } + std::string debugName; +#else + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_DESCRIPTOR_POOL); } +#endif + + std::unique_ptr tryAllocate(VulkanDescriptorSetLayout *layout); + std::unique_ptr tryAllocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount); + std::unique_ptr allocate(VulkanDescriptorSetLayout *layout); + std::unique_ptr allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount); + + VulkanDevice *device; + VkDescriptorPool pool; + +private: + enum class AllocType { TryAllocate, AlwaysAllocate }; + std::unique_ptr allocate(VulkanDescriptorSetLayout* layout, AllocType allocType); + std::unique_ptr allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount, AllocType allocType); + + VulkanDescriptorPool(const VulkanDescriptorPool &) = delete; + VulkanDescriptorPool &operator=(const VulkanDescriptorPool &) = delete; +}; + +class VulkanQueryPool +{ +public: + VulkanQueryPool(VulkanDevice *device, VkQueryPool pool); + ~VulkanQueryPool(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_QUERY_POOL); } + + bool getResults(uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *data, VkDeviceSize stride, VkQueryResultFlags flags); + + VulkanDevice *device = nullptr; + VkQueryPool pool = VK_NULL_HANDLE; + +private: + VulkanQueryPool(const VulkanQueryPool &) = delete; + VulkanQueryPool &operator=(const VulkanQueryPool &) = delete; +}; + +class VulkanAccelerationStructure +{ +public: + VulkanAccelerationStructure(VulkanDevice* device, VkAccelerationStructureKHR accelstruct); + ~VulkanAccelerationStructure(); + + VkDeviceAddress GetDeviceAddress() + { + VkAccelerationStructureDeviceAddressInfoKHR addressInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR }; + addressInfo.accelerationStructure = accelstruct; + return vkGetAccelerationStructureDeviceAddressKHR(device->device, &addressInfo); + } + + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)accelstruct, VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR); } + + VulkanDevice* device; + VkAccelerationStructureKHR accelstruct; + +private: + VulkanAccelerationStructure(const VulkanAccelerationStructure&) = delete; + VulkanAccelerationStructure& operator=(const VulkanAccelerationStructure&) = delete; +}; + +class VulkanPipeline +{ +public: + VulkanPipeline(VulkanDevice *device, VkPipeline pipeline); + ~VulkanPipeline(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)pipeline, VK_OBJECT_TYPE_PIPELINE); } + + VulkanDevice *device; + VkPipeline pipeline; + +private: + VulkanPipeline(const VulkanPipeline &) = delete; + VulkanPipeline &operator=(const VulkanPipeline &) = delete; +}; + +class VulkanPipelineLayout +{ +public: + VulkanPipelineLayout(VulkanDevice *device, VkPipelineLayout layout); + ~VulkanPipelineLayout(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT); } + + VulkanDevice *device; + VkPipelineLayout layout; + +private: + VulkanPipelineLayout(const VulkanPipelineLayout &) = delete; + VulkanPipelineLayout &operator=(const VulkanPipelineLayout &) = delete; +}; + +class VulkanPipelineCache +{ +public: + VulkanPipelineCache(VulkanDevice* device, VkPipelineCache cache); + ~VulkanPipelineCache(); + + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)cache, VK_OBJECT_TYPE_PIPELINE_CACHE); } + + std::vector GetCacheData(); + + VulkanDevice* device; + VkPipelineCache cache; + +private: + VulkanPipelineCache(const VulkanPipelineCache&) = delete; + VulkanPipelineCache& operator=(const VulkanPipelineCache&) = delete; +}; + +class VulkanRenderPass +{ +public: + VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass); + ~VulkanRenderPass(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)renderPass, VK_OBJECT_TYPE_RENDER_PASS); } + + VulkanDevice *device; + VkRenderPass renderPass; + +private: + VulkanRenderPass(const VulkanRenderPass &) = delete; + VulkanRenderPass &operator=(const VulkanRenderPass &) = delete; +}; + +class RenderPassBegin +{ +public: + RenderPassBegin(); + + RenderPassBegin& RenderPass(VulkanRenderPass* renderpass); + RenderPassBegin& RenderArea(int x, int y, int width, int height); + RenderPassBegin& Framebuffer(VulkanFramebuffer* framebuffer); + RenderPassBegin& AddClearColor(float r, float g, float b, float a); + RenderPassBegin& AddClearDepth(float value); + RenderPassBegin& AddClearStencil(int value); + RenderPassBegin& AddClearDepthStencil(float depthValue, int stencilValue); + + void Execute(VulkanCommandBuffer* cmdbuffer, VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE); + + VkRenderPassBeginInfo renderPassInfo = {}; + +private: + std::vector clearValues; +}; + +class VulkanCommandBuffer +{ +public: + VulkanCommandBuffer(VulkanCommandPool *pool); + ~VulkanCommandBuffer(); + + void SetDebugName(const char *name); + + void begin(); + void end(); + + void bindPipeline(VkPipelineBindPoint pipelineBindPoint, VulkanPipeline *pipeline); + void bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); + void setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); + void setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); + void setLineWidth(float lineWidth); + void setDepthBias(float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); + void setBlendConstants(const float blendConstants[4]); + void setDepthBounds(float minDepthBounds, float maxDepthBounds); + void setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t compareMask); + void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t writeMask); + void setStencilReference(VkStencilFaceFlags faceMask, uint32_t reference); + void bindDescriptorSet(VkPipelineBindPoint pipelineBindPoint, VulkanPipelineLayout *layout, uint32_t setIndex, VulkanDescriptorSet *descriptorSet, uint32_t dynamicOffsetCount = 0, const uint32_t* pDynamicOffsets = nullptr); + void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); + void bindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); + void bindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); + void draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); + void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); + void drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); + void drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); + void dispatch(uint32_t x, uint32_t y, uint32_t z); + void dispatchIndirect(VkBuffer buffer, VkDeviceSize offset); + void copyBuffer(VulkanBuffer *srcBuffer, VulkanBuffer *dstBuffer, VkDeviceSize srcOffset = 0, VkDeviceSize dstOffset = 0, VkDeviceSize size = VK_WHOLE_SIZE); + void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); + void copyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); + void blitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); + void copyBufferToImage(VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); + void copyImageToBuffer(VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); + void updateBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); + void fillBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); + void clearColorImage(VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); + void clearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); + void clearAttachments(uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); + void resolveImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); + void setEvent(VkEvent event, VkPipelineStageFlags stageMask); + void resetEvent(VkEvent event, VkPipelineStageFlags stageMask); + void waitEvents(uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); + void pipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); + void beginQuery(VulkanQueryPool *queryPool, uint32_t query, VkQueryControlFlags flags); + void beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); + void endQuery(VulkanQueryPool *queryPool, uint32_t query); + void endQuery(VkQueryPool queryPool, uint32_t query); + void resetQueryPool(VulkanQueryPool *queryPool, uint32_t firstQuery, uint32_t queryCount); + void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); + void writeTimestamp(VkPipelineStageFlagBits pipelineStage, VulkanQueryPool *queryPool, uint32_t query); + void writeTimestamp(VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); + void copyQueryPoolResults(VulkanQueryPool *queryPool, uint32_t firstQuery, uint32_t queryCount, VulkanBuffer *dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); + void copyQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); + void pushConstants(VulkanPipelineLayout *layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); + void pushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); + void beginRenderPass(const RenderPassBegin &renderPassBegin, VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE); + void beginRenderPass(const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); + void nextSubpass(VkSubpassContents contents); + void endRenderPass(); + void executeCommands(uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); + + void buildAccelerationStructures(uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); + void traceRays(const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); + void writeAccelerationStructuresProperties(uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); + + void debugFullPipelineBarrier(); + + VkCommandBuffer buffer = nullptr; + +private: + VulkanCommandPool *pool = nullptr; + + VulkanCommandBuffer(const VulkanCommandBuffer &) = delete; + VulkanCommandBuffer &operator=(const VulkanCommandBuffer &) = delete; +}; + +class VulkanCommandPool +{ +public: + VulkanCommandPool(VulkanDevice *device, int queueFamilyIndex); + ~VulkanCommandPool(); + + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_COMMAND_POOL); } + + std::unique_ptr createBuffer(); + + VkCommandPool pool = VK_NULL_HANDLE; + +private: + VulkanDevice *device = nullptr; + + VulkanCommandPool(const VulkanCommandPool &) = delete; + VulkanCommandPool &operator=(const VulkanCommandPool &) = delete; + + friend class VulkanCommandBuffer; +}; + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanSemaphore::VulkanSemaphore(VulkanDevice *device) : device(device) +{ + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VkResult result = vkCreateSemaphore(device->device, &semaphoreInfo, nullptr, &semaphore); + CheckVulkanError(result, "Could not create semaphore"); +} + +inline VulkanSemaphore::~VulkanSemaphore() +{ + vkDestroySemaphore(device->device, semaphore, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanFence::VulkanFence(VulkanDevice *device) : device(device) +{ + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + VkResult result = vkCreateFence(device->device, &fenceInfo, nullptr, &fence); + CheckVulkanError(result, "Could not create fence!"); +} + +inline VulkanFence::~VulkanFence() +{ + vkDestroyFence(device->device, fence, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanBuffer::VulkanBuffer(VulkanDevice *device, VkBuffer buffer, VmaAllocation allocation, size_t size) : device(device), buffer(buffer), allocation(allocation), size(size) +{ +} + +inline VulkanBuffer::~VulkanBuffer() +{ + vmaDestroyBuffer(device->allocator, buffer, allocation); +} + +inline void *VulkanBuffer::Map(size_t offset, size_t size) +{ + void *data; + VkResult result = vmaMapMemory(device->allocator, allocation, &data); + return (result == VK_SUCCESS) ? ((uint8_t*)data) + offset : nullptr; +} + +inline void VulkanBuffer::Unmap() +{ + vmaUnmapMemory(device->allocator, allocation); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanCommandPool::VulkanCommandPool(VulkanDevice *device, int queueFamilyIndex) : device(device) +{ + VkCommandPoolCreateInfo poolInfo = {}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = queueFamilyIndex; + poolInfo.flags = 0; + + VkResult result = vkCreateCommandPool(device->device, &poolInfo, nullptr, &pool); + CheckVulkanError(result, "Could not create command pool"); +} + +inline VulkanCommandPool::~VulkanCommandPool() +{ + vkDestroyCommandPool(device->device, pool, nullptr); +} + +inline std::unique_ptr VulkanCommandPool::createBuffer() +{ + return std::make_unique(this); +} + +///////////////////////////////////////////////////////////////////////////// + +inline RenderPassBegin::RenderPassBegin() +{ + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; +} + +inline RenderPassBegin& RenderPassBegin::RenderPass(VulkanRenderPass* renderPass) +{ + renderPassInfo.renderPass = renderPass->renderPass; + return *this; +} + +inline RenderPassBegin& RenderPassBegin::RenderArea(int x, int y, int width, int height) +{ + renderPassInfo.renderArea.offset.x = x; + renderPassInfo.renderArea.offset.y = y; + renderPassInfo.renderArea.extent.width = width; + renderPassInfo.renderArea.extent.height = height; + return *this; +} + +inline RenderPassBegin& RenderPassBegin::Framebuffer(VulkanFramebuffer* framebuffer) +{ + renderPassInfo.framebuffer = framebuffer->framebuffer; + return *this; +} + +inline RenderPassBegin& RenderPassBegin::AddClearColor(float r, float g, float b, float a) +{ + VkClearValue clearValue = { }; + clearValue.color = { r, g, b, a }; + clearValues.push_back(clearValue); + + renderPassInfo.clearValueCount = (uint32_t)clearValues.size(); + renderPassInfo.pClearValues = clearValues.data(); + return *this; +} + +inline RenderPassBegin& RenderPassBegin::AddClearDepth(float value) +{ + VkClearValue clearValue = { }; + clearValue.depthStencil.depth = value; + clearValues.push_back(clearValue); + + renderPassInfo.clearValueCount = (uint32_t)clearValues.size(); + renderPassInfo.pClearValues = clearValues.data(); + return *this; +} + +inline RenderPassBegin& RenderPassBegin::AddClearStencil(int value) +{ + VkClearValue clearValue = { }; + clearValue.depthStencil.stencil = value; + clearValues.push_back(clearValue); + + renderPassInfo.clearValueCount = (uint32_t)clearValues.size(); + renderPassInfo.pClearValues = clearValues.data(); + return *this; +} + +inline RenderPassBegin& RenderPassBegin::AddClearDepthStencil(float depthValue, int stencilValue) +{ + VkClearValue clearValue = { }; + clearValue.depthStencil.depth = depthValue; + clearValue.depthStencil.stencil = stencilValue; + clearValues.push_back(clearValue); + + renderPassInfo.clearValueCount = (uint32_t)clearValues.size(); + renderPassInfo.pClearValues = clearValues.data(); + return *this; +} + +inline void RenderPassBegin::Execute(VulkanCommandBuffer* cmdbuffer, VkSubpassContents contents) +{ + cmdbuffer->beginRenderPass(&renderPassInfo, contents); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanCommandBuffer::VulkanCommandBuffer(VulkanCommandPool *pool) : pool(pool) +{ + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = pool->pool; + allocInfo.commandBufferCount = 1; + + VkResult result = vkAllocateCommandBuffers(pool->device->device, &allocInfo, &buffer); + CheckVulkanError(result, "Could not create command buffer"); +} + +inline VulkanCommandBuffer::~VulkanCommandBuffer() +{ + vkFreeCommandBuffers(pool->device->device, pool->pool, 1, &buffer); +} + +inline void VulkanCommandBuffer::begin() +{ + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + beginInfo.pInheritanceInfo = nullptr; + + VkResult result = vkBeginCommandBuffer(buffer, &beginInfo); + CheckVulkanError(result, "Could not begin recording command buffer"); +} + +inline void VulkanCommandBuffer::end() +{ + VkResult result = vkEndCommandBuffer(buffer); + CheckVulkanError(result, "Could not end command buffer recording"); +} + +inline void VulkanCommandBuffer::debugFullPipelineBarrier() +{ + VkMemoryBarrier barrier = { }; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + barrier.srcAccessMask = + VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + barrier.dstAccessMask = + VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + + vkCmdPipelineBarrier(buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); +} + +inline void VulkanCommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint, VulkanPipeline *pipeline) +{ + bindPipeline(pipelineBindPoint, pipeline->pipeline); +} + +inline void VulkanCommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) +{ + vkCmdBindPipeline(buffer, pipelineBindPoint, pipeline); +} + +inline void VulkanCommandBuffer::setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports) +{ + vkCmdSetViewport(buffer, firstViewport, viewportCount, pViewports); +} + +inline void VulkanCommandBuffer::setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors) +{ + vkCmdSetScissor(buffer, firstScissor, scissorCount, pScissors); +} + +inline void VulkanCommandBuffer::setLineWidth(float lineWidth) +{ + vkCmdSetLineWidth(buffer, lineWidth); +} + +inline void VulkanCommandBuffer::setDepthBias(float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) +{ + vkCmdSetDepthBias(buffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor); +} + +inline void VulkanCommandBuffer::setBlendConstants(const float blendConstants[4]) +{ + vkCmdSetBlendConstants(buffer, blendConstants); +} + +inline void VulkanCommandBuffer::setDepthBounds(float minDepthBounds, float maxDepthBounds) +{ + vkCmdSetDepthBounds(buffer, minDepthBounds, maxDepthBounds); +} + +inline void VulkanCommandBuffer::setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t compareMask) +{ + vkCmdSetStencilCompareMask(buffer, faceMask, compareMask); +} + +inline void VulkanCommandBuffer::setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t writeMask) +{ + vkCmdSetStencilWriteMask(buffer, faceMask, writeMask); +} + +inline void VulkanCommandBuffer::setStencilReference(VkStencilFaceFlags faceMask, uint32_t reference) +{ + vkCmdSetStencilReference(buffer, faceMask, reference); +} + +inline void VulkanCommandBuffer::bindDescriptorSet(VkPipelineBindPoint pipelineBindPoint, VulkanPipelineLayout *layout, uint32_t setIndex, VulkanDescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets) +{ + bindDescriptorSets(pipelineBindPoint, layout->layout, setIndex, 1, &descriptorSet->set, dynamicOffsetCount, pDynamicOffsets); +} + +inline void VulkanCommandBuffer::bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets) +{ + vkCmdBindDescriptorSets(buffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); +} + +inline void VulkanCommandBuffer::bindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) +{ + vkCmdBindIndexBuffer(this->buffer, buffer, offset, indexType); +} + +inline void VulkanCommandBuffer::bindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) +{ + vkCmdBindVertexBuffers(buffer, firstBinding, bindingCount, pBuffers, pOffsets); +} + +inline void VulkanCommandBuffer::draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) +{ + vkCmdDraw(buffer, vertexCount, instanceCount, firstVertex, firstInstance); +} + +inline void VulkanCommandBuffer::drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) +{ + vkCmdDrawIndexed(buffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); +} + +inline void VulkanCommandBuffer::drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) +{ + vkCmdDrawIndirect(this->buffer, buffer, offset, drawCount, stride); +} + +inline void VulkanCommandBuffer::drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) +{ + vkCmdDrawIndexedIndirect(this->buffer, buffer, offset, drawCount, stride); +} + +inline void VulkanCommandBuffer::dispatch(uint32_t x, uint32_t y, uint32_t z) +{ + vkCmdDispatch(buffer, x, y, z); +} + +inline void VulkanCommandBuffer::dispatchIndirect(VkBuffer buffer, VkDeviceSize offset) +{ + vkCmdDispatchIndirect(this->buffer, buffer, offset); +} + +inline void VulkanCommandBuffer::copyBuffer(VulkanBuffer *srcBuffer, VulkanBuffer *dstBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size) +{ + VkBufferCopy region = { }; + region.srcOffset = srcOffset; + region.dstOffset = dstOffset; + region.size = (size == VK_WHOLE_SIZE) ? dstBuffer->size : size; + copyBuffer(srcBuffer->buffer, dstBuffer->buffer, 1, ®ion); +} + +inline void VulkanCommandBuffer::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions) +{ + vkCmdCopyBuffer(buffer, srcBuffer, dstBuffer, regionCount, pRegions); +} + +inline void VulkanCommandBuffer::copyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions) +{ + vkCmdCopyImage(buffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); +} + +inline void VulkanCommandBuffer::blitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter) +{ + vkCmdBlitImage(buffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter); +} + +inline void VulkanCommandBuffer::copyBufferToImage(VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions) +{ + vkCmdCopyBufferToImage(buffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions); +} + +inline void VulkanCommandBuffer::copyImageToBuffer(VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions) +{ + vkCmdCopyImageToBuffer(buffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions); +} + +inline void VulkanCommandBuffer::updateBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData) +{ + vkCmdUpdateBuffer(buffer, dstBuffer, dstOffset, dataSize, pData); +} + +inline void VulkanCommandBuffer::fillBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) +{ + vkCmdFillBuffer(buffer, dstBuffer, dstOffset, size, data); +} + +inline void VulkanCommandBuffer::clearColorImage(VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) +{ + vkCmdClearColorImage(buffer, image, imageLayout, pColor, rangeCount, pRanges); +} + +inline void VulkanCommandBuffer::clearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) +{ + vkCmdClearDepthStencilImage(buffer, image, imageLayout, pDepthStencil, rangeCount, pRanges); +} + +inline void VulkanCommandBuffer::clearAttachments(uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects) +{ + vkCmdClearAttachments(buffer, attachmentCount, pAttachments, rectCount, pRects); +} + +inline void VulkanCommandBuffer::resolveImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions) +{ + vkCmdResolveImage(buffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); +} + +inline void VulkanCommandBuffer::setEvent(VkEvent event, VkPipelineStageFlags stageMask) +{ + vkCmdSetEvent(buffer, event, stageMask); +} + +inline void VulkanCommandBuffer::resetEvent(VkEvent event, VkPipelineStageFlags stageMask) +{ + vkCmdResetEvent(buffer, event, stageMask); +} + +inline void VulkanCommandBuffer::waitEvents(uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) +{ + vkCmdWaitEvents(buffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); +} + +inline void VulkanCommandBuffer::pipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) +{ + vkCmdPipelineBarrier(buffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); +} + +inline void VulkanCommandBuffer::beginQuery(VulkanQueryPool *queryPool, uint32_t query, VkQueryControlFlags flags) +{ + beginQuery(queryPool->pool, query, flags); +} + +inline void VulkanCommandBuffer::beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags) +{ + vkCmdBeginQuery(buffer, queryPool, query, flags); +} + +inline void VulkanCommandBuffer::endQuery(VulkanQueryPool *queryPool, uint32_t query) +{ + endQuery(queryPool->pool, query); +} + +inline void VulkanCommandBuffer::endQuery(VkQueryPool queryPool, uint32_t query) +{ + vkCmdEndQuery(buffer, queryPool, query); +} + +inline void VulkanCommandBuffer::resetQueryPool(VulkanQueryPool *queryPool, uint32_t firstQuery, uint32_t queryCount) +{ + resetQueryPool(queryPool->pool, firstQuery, queryCount); +} + +inline void VulkanCommandBuffer::resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) +{ + vkCmdResetQueryPool(buffer, queryPool, firstQuery, queryCount); +} + +inline void VulkanCommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipelineStage, VulkanQueryPool *queryPool, uint32_t query) +{ + writeTimestamp(pipelineStage, queryPool->pool, query); +} + +inline void VulkanCommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query) +{ + vkCmdWriteTimestamp(buffer, pipelineStage, queryPool, query); +} + +inline void VulkanCommandBuffer::copyQueryPoolResults(VulkanQueryPool *queryPool, uint32_t firstQuery, uint32_t queryCount, VulkanBuffer *dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) +{ + copyQueryPoolResults(queryPool->pool, firstQuery, queryCount, dstBuffer->buffer, dstOffset, stride, flags); +} + +inline void VulkanCommandBuffer::copyQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) +{ + vkCmdCopyQueryPoolResults(buffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride, flags); +} + +inline void VulkanCommandBuffer::pushConstants(VulkanPipelineLayout *layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues) +{ + pushConstants(layout->layout, stageFlags, offset, size, pValues); +} + +inline void VulkanCommandBuffer::pushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues) +{ + vkCmdPushConstants(buffer, layout, stageFlags, offset, size, pValues); +} + +inline void VulkanCommandBuffer::beginRenderPass(const RenderPassBegin &renderPassBegin, VkSubpassContents contents) +{ + beginRenderPass(&renderPassBegin.renderPassInfo, contents); +} + +inline void VulkanCommandBuffer::beginRenderPass(const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) +{ + vkCmdBeginRenderPass(buffer, pRenderPassBegin, contents); +} + +inline void VulkanCommandBuffer::nextSubpass(VkSubpassContents contents) +{ + vkCmdNextSubpass(buffer, contents); +} + +inline void VulkanCommandBuffer::endRenderPass() +{ + vkCmdEndRenderPass(buffer); +} + +inline void VulkanCommandBuffer::executeCommands(uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) +{ + vkCmdExecuteCommands(buffer, commandBufferCount, pCommandBuffers); +} + +inline void VulkanCommandBuffer::buildAccelerationStructures(uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos) +{ + vkCmdBuildAccelerationStructuresKHR(buffer, infoCount, pInfos, ppBuildRangeInfos); +} + +inline void VulkanCommandBuffer::traceRays(const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth) +{ + vkCmdTraceRaysKHR(buffer, pRaygenShaderBindingTable, pMissShaderBindingTable, pHitShaderBindingTable, pCallableShaderBindingTable, width, height, depth); +} + +inline void VulkanCommandBuffer::writeAccelerationStructuresProperties(uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery) +{ + vkCmdWriteAccelerationStructuresPropertiesKHR(buffer, accelerationStructureCount, pAccelerationStructures, queryType, queryPool, firstQuery); +} + +inline void VulkanCommandBuffer::SetDebugName(const char *name) +{ + pool->device->SetObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_COMMAND_BUFFER); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanShader::VulkanShader(VulkanDevice *device, VkShaderModule module) : module(module), device(device) +{ +} + +inline VulkanShader::~VulkanShader() +{ + vkDestroyShaderModule(device->device, module, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(VulkanDevice *device, VkDescriptorSetLayout layout) : device(device), layout(layout) +{ +} + +inline VulkanDescriptorSetLayout::~VulkanDescriptorSetLayout() +{ + vkDestroyDescriptorSetLayout(device->device, layout, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanDescriptorSet::VulkanDescriptorSet(VulkanDevice *device, VulkanDescriptorPool *pool, VkDescriptorSet set) : device(device), pool(pool), set(set) +{ +} + +inline VulkanDescriptorSet::~VulkanDescriptorSet() +{ + vkFreeDescriptorSets(device->device, pool->pool, 1, &set); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanDescriptorPool::VulkanDescriptorPool(VulkanDevice *device, VkDescriptorPool pool) : device(device), pool(pool) +{ +} + +inline VulkanDescriptorPool::~VulkanDescriptorPool() +{ + vkDestroyDescriptorPool(device->device, pool, nullptr); +} + +inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout* layout, AllocType allocType) +{ + VkDescriptorSetAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + allocInfo.descriptorPool = pool; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &layout->layout; + + VkDescriptorSet descriptorSet; + VkResult result = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet); + if (allocType == AllocType::TryAllocate && result != VK_SUCCESS) + return nullptr; + else + CheckVulkanError(result, "Could not allocate descriptor sets"); + return std::make_unique(device, this, descriptorSet); +} + +inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount, AllocType allocType) +{ + VkDescriptorSetAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + VkDescriptorSetVariableDescriptorCountAllocateInfoEXT countInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT }; + allocInfo.descriptorPool = pool; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &layout->layout; + allocInfo.pNext = &countInfo; + countInfo.descriptorSetCount = 1; + countInfo.pDescriptorCounts = &bindlessCount; + + VkDescriptorSet descriptorSet; + VkResult result = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet); + if (allocType == AllocType::TryAllocate && result != VK_SUCCESS) + return nullptr; + else + CheckVulkanError(result, "Could not allocate descriptor sets"); + return std::make_unique(device, this, descriptorSet); +} + +inline std::unique_ptr VulkanDescriptorPool::tryAllocate(VulkanDescriptorSetLayout *layout) +{ + return allocate(layout, AllocType::TryAllocate); +} + +inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout *layout) +{ + return allocate(layout, AllocType::AlwaysAllocate); +} + +inline std::unique_ptr VulkanDescriptorPool::tryAllocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount) +{ + return allocate(layout, bindlessCount, AllocType::TryAllocate); +} + +inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount) +{ + return allocate(layout, bindlessCount, AllocType::AlwaysAllocate); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanQueryPool::VulkanQueryPool(VulkanDevice *device, VkQueryPool pool) : device(device), pool(pool) +{ +} + +inline VulkanQueryPool::~VulkanQueryPool() +{ + vkDestroyQueryPool(device->device, pool, nullptr); +} + +inline bool VulkanQueryPool::getResults(uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *data, VkDeviceSize stride, VkQueryResultFlags flags) +{ + VkResult result = vkGetQueryPoolResults(device->device, pool, firstQuery, queryCount, dataSize, data, stride, flags); + CheckVulkanError(result, "vkGetQueryPoolResults failed"); + return result == VK_SUCCESS; +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanFramebuffer::VulkanFramebuffer(VulkanDevice *device, VkFramebuffer framebuffer) : device(device), framebuffer(framebuffer) +{ +} + +inline VulkanFramebuffer::~VulkanFramebuffer() +{ + vkDestroyFramebuffer(device->device, framebuffer, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanImage::VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels, int layerCount) : image(image), width(width), height(height), mipLevels(mipLevels), layerCount(layerCount), device(device), allocation(allocation) +{ +} + +inline VulkanImage::~VulkanImage() +{ + if (allocation) + vmaDestroyImage(device->allocator, image, allocation); +} + +inline void *VulkanImage::Map(size_t offset, size_t size) +{ + void *data; + VkResult result = vmaMapMemory(device->allocator, allocation, &data); + return (result == VK_SUCCESS) ? ((uint8_t*)data) + offset : nullptr; +} + +inline void VulkanImage::Unmap() +{ + vmaUnmapMemory(device->allocator, allocation); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanImageView::VulkanImageView(VulkanDevice *device, VkImageView view) : view(view), device(device) +{ +} + +inline VulkanImageView::~VulkanImageView() +{ + vkDestroyImageView(device->device, view, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanSampler::VulkanSampler(VulkanDevice *device, VkSampler sampler) : sampler(sampler), device(device) +{ +} + +inline VulkanSampler::~VulkanSampler() +{ + vkDestroySampler(device->device, sampler, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanAccelerationStructure::VulkanAccelerationStructure(VulkanDevice* device, VkAccelerationStructureKHR accelstruct) + : device(device), accelstruct(accelstruct) +{ +} + +inline VulkanAccelerationStructure::~VulkanAccelerationStructure() +{ + vkDestroyAccelerationStructureKHR(device->device, accelstruct, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanPipeline::VulkanPipeline(VulkanDevice *device, VkPipeline pipeline) : device(device), pipeline(pipeline) +{ +} + +inline VulkanPipeline::~VulkanPipeline() +{ + vkDestroyPipeline(device->device, pipeline, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanPipelineLayout::VulkanPipelineLayout(VulkanDevice *device, VkPipelineLayout layout) : device(device), layout(layout) +{ +} + +inline VulkanPipelineLayout::~VulkanPipelineLayout() +{ + vkDestroyPipelineLayout(device->device, layout, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanPipelineCache::VulkanPipelineCache(VulkanDevice* device, VkPipelineCache cache) : device(device), cache(cache) +{ +} + +inline VulkanPipelineCache::~VulkanPipelineCache() +{ + vkDestroyPipelineCache(device->device, cache, nullptr); +} + +inline std::vector VulkanPipelineCache::GetCacheData() +{ + size_t dataSize = 0; + VkResult result = vkGetPipelineCacheData(device->device, cache, &dataSize, nullptr); + CheckVulkanError(result, "Could not get cache data size"); + + std::vector buffer; + buffer.resize(dataSize); + result = vkGetPipelineCacheData(device->device, cache, &dataSize, buffer.data()); + if (result == VK_INCOMPLETE) + VulkanError("Could not get cache data (incomplete)"); + CheckVulkanError(result, "Could not get cache data"); + buffer.resize(dataSize); + return buffer; +} + +///////////////////////////////////////////////////////////////////////////// + +inline VulkanRenderPass::VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass) : device(device), renderPass(renderPass) +{ +} + +inline VulkanRenderPass::~VulkanRenderPass() +{ + vkDestroyRenderPass(device->device, renderPass, nullptr); +} diff --git a/libraries/ZVulkan/include/zvulkan/vulkansurface.h b/libraries/ZVulkan/include/zvulkan/vulkansurface.h new file mode 100644 index 00000000000..398bfd39aa3 --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/vulkansurface.h @@ -0,0 +1,20 @@ +#pragma once + +#include "vulkaninstance.h" + +class VulkanSurface +{ +public: + VulkanSurface(std::shared_ptr instance, VkSurfaceKHR surface); + ~VulkanSurface(); + + std::shared_ptr Instance; + VkSurfaceKHR Surface = VK_NULL_HANDLE; + +#ifdef VK_USE_PLATFORM_WIN32_KHR + + VulkanSurface(std::shared_ptr instance, HWND window); + HWND Window = 0; + +#endif +}; diff --git a/libraries/ZVulkan/include/zvulkan/vulkanswapchain.h b/libraries/ZVulkan/include/zvulkan/vulkanswapchain.h new file mode 100644 index 00000000000..6c5e97db0e2 --- /dev/null +++ b/libraries/ZVulkan/include/zvulkan/vulkanswapchain.h @@ -0,0 +1,61 @@ +#pragma once + +#include "vulkandevice.h" +#include "vulkanobjects.h" + +class VulkanSemaphore; +class VulkanFence; + +class VulkanSurfaceCapabilities +{ +public: + VkSurfaceCapabilitiesKHR Capabilites = { }; +#ifdef WIN32 + VkSurfaceCapabilitiesFullScreenExclusiveEXT FullScreenExclusive = { VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT }; +#else + struct { void* pNext = nullptr; VkBool32 fullScreenExclusiveSupported = 0; } FullScreenExclusive; +#endif + std::vector PresentModes; + std::vector Formats; +}; + +class VulkanSwapChain +{ +public: + VulkanSwapChain(VulkanDevice* device); + ~VulkanSwapChain(); + + void Create(int width, int height, int imageCount, bool vsync, bool hdr, bool exclusivefullscreen); + bool Lost() const { return lost; } + + int Width() const { return actualExtent.width; } + int Height() const { return actualExtent.height; } + VkSurfaceFormatKHR Format() const { return format; } + + int ImageCount() const { return (int)images.size(); } + VulkanImage* GetImage(int index) { return images[index].get(); } + VulkanImageView* GetImageView(int index) { return views[index].get(); } + + int AcquireImage(VulkanSemaphore* semaphore = nullptr, VulkanFence* fence = nullptr); + void QueuePresent(int imageIndex, VulkanSemaphore* semaphore = nullptr); + +private: + void SelectFormat(const VulkanSurfaceCapabilities& caps, bool hdr); + + bool CreateSwapchain(int width, int height, int imageCount, bool vsync, bool hdr, bool exclusivefullscreen); + + VulkanSurfaceCapabilities GetSurfaceCapabilities(bool exclusivefullscreen); + + VulkanDevice* device = nullptr; + bool lost = true; + + VkExtent2D actualExtent = {}; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + VkSurfaceFormatKHR format = {}; + VkPresentModeKHR presentMode; + std::vector> images; + std::vector> views; + + VulkanSwapChain(const VulkanSwapChain&) = delete; + VulkanSwapChain& operator=(const VulkanSwapChain&) = delete; +}; diff --git a/libraries/ZVulkan/src/glslang/LICENSE.txt b/libraries/ZVulkan/src/glslang/LICENSE.txt new file mode 100644 index 00000000000..054e68a4614 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/LICENSE.txt @@ -0,0 +1,1016 @@ +Here, glslang proper means core GLSL parsing, HLSL parsing, and SPIR-V code +generation. Glslang proper requires use of a number of licenses, one that covers +preprocessing and others that covers non-preprocessing. + +Bison was removed long ago. You can build glslang from the source grammar, +using tools of your choice, without using bison or any bison files. + +Other parts, outside of glslang proper, include: + +- gl_types.h, only needed for OpenGL-like reflection, and can be left out of + a parse and codegen project. See it for its license. + +- update_glslang_sources.py, which is not part of the project proper and does + not need to be used. + +- the SPIR-V "remapper", which is optional, but has the same license as + glslang proper + +- Google tests and SPIR-V tools, and anything in the external subdirectory + are external and optional; see them for their respective licenses. + +-------------------------------------------------------------------------------- + +The core of glslang-proper, minus the preprocessor is licenced as follows: + +-------------------------------------------------------------------------------- +3-Clause BSD License +-------------------------------------------------------------------------------- + +// +// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) +// +// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. +// + + +-------------------------------------------------------------------------------- +2-Clause BSD License +-------------------------------------------------------------------------------- + +Copyright 2020 The Khronos Group Inc + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. 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 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 HOLDER 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. + + +-------------------------------------------------------------------------------- +The MIT License +-------------------------------------------------------------------------------- + +Copyright 2020 The Khronos Group Inc + +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. + + +-------------------------------------------------------------------------------- +APACHE LICENSE, VERSION 2.0 +-------------------------------------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +-------------------------------------------------------------------------------- +GPL 3 with special bison exception +-------------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + +Bison Exception + +As a special exception, you may create a larger work that contains part or all +of the Bison parser skeleton and distribute that work under terms of your +choice, so long as that work isn't itself a parser generator using the skeleton +or a modified version thereof as a parser skeleton. Alternatively, if you +modify or redistribute the parser skeleton itself, you may (at your option) +remove this special exception, which will cause the skeleton and the resulting +Bison output files to be licensed under the GNU General Public License without +this special exception. + +This special exception was added by the Free Software Foundation in version +2.2 of Bison. + + END OF TERMS AND CONDITIONS + +-------------------------------------------------------------------------------- +================================================================================ +-------------------------------------------------------------------------------- + +The preprocessor has the core licenses stated above, plus additional licences: + +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +/* +** Copyright (c) 2014-2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and/or associated documentation files (the "Materials"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are 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 Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE 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 MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ diff --git a/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp b/libraries/ZVulkan/src/glslang/OGLCompilersDLL/InitializeDll.cpp similarity index 100% rename from libraries/glslang/OGLCompilersDLL/InitializeDll.cpp rename to libraries/ZVulkan/src/glslang/OGLCompilersDLL/InitializeDll.cpp diff --git a/libraries/glslang/OGLCompilersDLL/InitializeDll.h b/libraries/ZVulkan/src/glslang/OGLCompilersDLL/InitializeDll.h similarity index 100% rename from libraries/glslang/OGLCompilersDLL/InitializeDll.h rename to libraries/ZVulkan/src/glslang/OGLCompilersDLL/InitializeDll.h diff --git a/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp b/libraries/ZVulkan/src/glslang/glslang/GenericCodeGen/CodeGen.cpp similarity index 100% rename from libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp rename to libraries/ZVulkan/src/glslang/glslang/GenericCodeGen/CodeGen.cpp diff --git a/libraries/glslang/glslang/GenericCodeGen/Link.cpp b/libraries/ZVulkan/src/glslang/glslang/GenericCodeGen/Link.cpp similarity index 100% rename from libraries/glslang/glslang/GenericCodeGen/Link.cpp rename to libraries/ZVulkan/src/glslang/glslang/GenericCodeGen/Link.cpp diff --git a/libraries/glslang/glslang/Include/BaseTypes.h b/libraries/ZVulkan/src/glslang/glslang/Include/BaseTypes.h similarity index 87% rename from libraries/glslang/glslang/Include/BaseTypes.h rename to libraries/ZVulkan/src/glslang/glslang/Include/BaseTypes.h index 6d4b4ff8e37..c8203c22329 100644 --- a/libraries/glslang/glslang/Include/BaseTypes.h +++ b/libraries/ZVulkan/src/glslang/glslang/Include/BaseTypes.h @@ -2,6 +2,7 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -61,8 +62,13 @@ enum TBasicType { EbtSampler, EbtStruct, EbtBlock, - EbtAccStructNV, + EbtAccStruct, EbtReference, + EbtRayQuery, +#ifndef GLSLANG_WEB + // SPIR-V type defined by spirv_type + EbtSpirvType, +#endif // HLSL types that live only temporarily. EbtString, @@ -89,12 +95,15 @@ enum TStorageQualifier { EvqUniform, // read only, shared with app EvqBuffer, // read/write, shared with app EvqShared, // compute shader's read/write 'shared' qualifier +#ifndef GLSLANG_WEB + EvqSpirvStorageClass, // spirv_storage_class +#endif - EvqPayloadNV, - EvqPayloadInNV, - EvqHitAttrNV, - EvqCallableDataNV, - EvqCallableDataInNV, + EvqPayload, + EvqPayloadIn, + EvqHitAttr, + EvqCallableData, + EvqCallableDataIn, // parameters EvqIn, // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter @@ -226,9 +235,15 @@ enum TBuiltInVariable { EbvViewIndex, EbvDeviceIndex, + EbvShadingRateKHR, + EbvPrimitiveShadingRateKHR, + EbvFragSizeEXT, EbvFragInvocationCountEXT, + EbvSecondaryFragDataEXT, + EbvSecondaryFragColorEXT, + EbvViewportMaskNV, EbvSecondaryPositionNV, EbvSecondaryViewportMaskNV, @@ -238,20 +253,24 @@ enum TBuiltInVariable { EbvFragmentSizeNV, EbvInvocationsPerPixelNV, // ray tracing - EbvLaunchIdNV, - EbvLaunchSizeNV, - EbvInstanceCustomIndexNV, - EbvWorldRayOriginNV, - EbvWorldRayDirectionNV, - EbvObjectRayOriginNV, - EbvObjectRayDirectionNV, - EbvRayTminNV, - EbvRayTmaxNV, - EbvHitTNV, - EbvHitKindNV, - EbvObjectToWorldNV, - EbvWorldToObjectNV, - EbvIncomingRayFlagsNV, + EbvLaunchId, + EbvLaunchSize, + EbvInstanceCustomIndex, + EbvGeometryIndex, + EbvWorldRayOrigin, + EbvWorldRayDirection, + EbvObjectRayOrigin, + EbvObjectRayDirection, + EbvRayTmin, + EbvRayTmax, + EbvHitT, + EbvHitKind, + EbvObjectToWorld, + EbvObjectToWorld3x4, + EbvWorldToObject, + EbvWorldToObject3x4, + EbvIncomingRayFlags, + EbvCurrentRayTimeNV, // barycentrics EbvBaryCoordNV, EbvBaryCoordNoPerspNV, @@ -310,6 +329,9 @@ __inline const char* GetStorageQualifierString(TStorageQualifier q) case EvqGlobal: return "global"; break; case EvqConst: return "const"; break; case EvqConstReadOnly: return "const (read only)"; break; +#ifndef GLSLANG_WEB + case EvqSpirvStorageClass: return "spirv_storage_class"; break; +#endif case EvqVaryingIn: return "in"; break; case EvqVaryingOut: return "out"; break; case EvqUniform: return "uniform"; break; @@ -328,11 +350,11 @@ __inline const char* GetStorageQualifierString(TStorageQualifier q) case EvqPointCoord: return "gl_PointCoord"; break; case EvqFragColor: return "fragColor"; break; case EvqFragDepth: return "gl_FragDepth"; break; - case EvqPayloadNV: return "rayPayloadNV"; break; - case EvqPayloadInNV: return "rayPayloadInNV"; break; - case EvqHitAttrNV: return "hitAttributeNV"; break; - case EvqCallableDataNV: return "callableDataNV"; break; - case EvqCallableDataInNV: return "callableDataInNV"; break; + case EvqPayload: return "rayPayloadNV"; break; + case EvqPayloadIn: return "rayPayloadInNV"; break; + case EvqHitAttr: return "hitAttributeNV"; break; + case EvqCallableData: return "callableDataNV"; break; + case EvqCallableDataIn: return "callableDataInNV"; break; default: return "unknown qualifier"; } } @@ -428,6 +450,9 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvFragSizeEXT: return "FragSizeEXT"; case EbvFragInvocationCountEXT: return "FragInvocationCountEXT"; + case EbvSecondaryFragDataEXT: return "SecondaryFragDataEXT"; + case EbvSecondaryFragColorEXT: return "SecondaryFragColorEXT"; + case EbvViewportMaskNV: return "ViewportMaskNV"; case EbvSecondaryPositionNV: return "SecondaryPositionNV"; case EbvSecondaryViewportMaskNV: return "SecondaryViewportMaskNV"; @@ -436,20 +461,22 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvFragFullyCoveredNV: return "FragFullyCoveredNV"; case EbvFragmentSizeNV: return "FragmentSizeNV"; case EbvInvocationsPerPixelNV: return "InvocationsPerPixelNV"; - case EbvLaunchIdNV: return "LaunchIdNV"; - case EbvLaunchSizeNV: return "LaunchSizeNV"; - case EbvInstanceCustomIndexNV: return "InstanceCustomIndexNV"; - case EbvWorldRayOriginNV: return "WorldRayOriginNV"; - case EbvWorldRayDirectionNV: return "WorldRayDirectionNV"; - case EbvObjectRayOriginNV: return "ObjectRayOriginNV"; - case EbvObjectRayDirectionNV: return "ObjectRayDirectionNV"; - case EbvRayTminNV: return "ObjectRayTminNV"; - case EbvRayTmaxNV: return "ObjectRayTmaxNV"; - case EbvHitTNV: return "HitTNV"; - case EbvHitKindNV: return "HitKindNV"; - case EbvIncomingRayFlagsNV: return "IncomingRayFlagsNV"; - case EbvObjectToWorldNV: return "ObjectToWorldNV"; - case EbvWorldToObjectNV: return "WorldToObjectNV"; + case EbvLaunchId: return "LaunchIdNV"; + case EbvLaunchSize: return "LaunchSizeNV"; + case EbvInstanceCustomIndex: return "InstanceCustomIndexNV"; + case EbvGeometryIndex: return "GeometryIndexEXT"; + case EbvWorldRayOrigin: return "WorldRayOriginNV"; + case EbvWorldRayDirection: return "WorldRayDirectionNV"; + case EbvObjectRayOrigin: return "ObjectRayOriginNV"; + case EbvObjectRayDirection: return "ObjectRayDirectionNV"; + case EbvRayTmin: return "ObjectRayTminNV"; + case EbvRayTmax: return "ObjectRayTmaxNV"; + case EbvHitT: return "HitTNV"; + case EbvHitKind: return "HitKindNV"; + case EbvIncomingRayFlags: return "IncomingRayFlagsNV"; + case EbvObjectToWorld: return "ObjectToWorldNV"; + case EbvWorldToObject: return "WorldToObjectNV"; + case EbvCurrentRayTimeNV: return "CurrentRayTimeNV"; case EbvBaryCoordNV: return "BaryCoordNV"; case EbvBaryCoordNoPerspNV: return "BaryCoordNoPerspNV"; @@ -468,6 +495,9 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvWarpID: return "WarpIDNV"; case EbvSMID: return "SMIDNV"; + case EbvShadingRateKHR: return "ShadingRateKHR"; + case EbvPrimitiveShadingRateKHR: return "PrimitiveShadingRateKHR"; + default: return "unknown built-in variable"; } } diff --git a/libraries/glslang/glslang/Include/Common.h b/libraries/ZVulkan/src/glslang/glslang/Include/Common.h similarity index 96% rename from libraries/glslang/glslang/Include/Common.h rename to libraries/ZVulkan/src/glslang/glslang/Include/Common.h index ddc1f564347..87ec92f279e 100644 --- a/libraries/glslang/glslang/Include/Common.h +++ b/libraries/ZVulkan/src/glslang/glslang/Include/Common.h @@ -37,6 +37,18 @@ #ifndef _COMMON_INCLUDED_ #define _COMMON_INCLUDED_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if defined(__ANDROID__) || (defined(_MSC_VER) && _MSC_VER < 1700) #include @@ -94,18 +106,6 @@ std::string to_string(const T& val) { #pragma warning(disable : 4201) // nameless union #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "PoolAlloc.h" // @@ -196,6 +196,10 @@ template , class PRED = std::equal_t class TUnorderedMap : public std::unordered_map > > { }; +template > +class TSet : public std::set > { +}; + // // Persistent string memory. Should only be used for strings that survive // across compiles/links. @@ -288,6 +292,18 @@ template bool IsMultipleOfPow2(T number, int powerOf2) return ! (number & (powerOf2 - 1)); } +// Returns log2 of an integer power of 2. +// T should be integral. +template int IntLog2(T n) +{ + assert(IsPow2(n)); + int result = 0; + while ((T(1) << result) != n) { + result++; + } + return result; +} + } // end namespace glslang #endif // _COMMON_INCLUDED_ diff --git a/libraries/glslang/glslang/Include/ConstantUnion.h b/libraries/ZVulkan/src/glslang/glslang/Include/ConstantUnion.h similarity index 99% rename from libraries/glslang/glslang/Include/ConstantUnion.h rename to libraries/ZVulkan/src/glslang/glslang/Include/ConstantUnion.h index 76b2d9c08b7..c4ffb85771b 100644 --- a/libraries/glslang/glslang/Include/ConstantUnion.h +++ b/libraries/ZVulkan/src/glslang/glslang/Include/ConstantUnion.h @@ -921,7 +921,7 @@ class TConstUnionArray { else unionArray = new TConstUnionVector(size); } - TConstUnionArray(const TConstUnionArray& a) : unionArray(a.unionArray) { } + TConstUnionArray(const TConstUnionArray& a) = default; TConstUnionArray(const TConstUnionArray& a, int start, int size) { unionArray = new TConstUnionVector(size); diff --git a/libraries/glslang/glslang/Include/InfoSink.h b/libraries/ZVulkan/src/glslang/glslang/Include/InfoSink.h similarity index 100% rename from libraries/glslang/glslang/Include/InfoSink.h rename to libraries/ZVulkan/src/glslang/glslang/Include/InfoSink.h diff --git a/libraries/glslang/glslang/Include/InitializeGlobals.h b/libraries/ZVulkan/src/glslang/glslang/Include/InitializeGlobals.h similarity index 100% rename from libraries/glslang/glslang/Include/InitializeGlobals.h rename to libraries/ZVulkan/src/glslang/glslang/Include/InitializeGlobals.h diff --git a/libraries/glslang/glslang/Include/PoolAlloc.h b/libraries/ZVulkan/src/glslang/glslang/Include/PoolAlloc.h similarity index 100% rename from libraries/glslang/glslang/Include/PoolAlloc.h rename to libraries/ZVulkan/src/glslang/glslang/Include/PoolAlloc.h diff --git a/libraries/glslang/glslang/Include/ResourceLimits.h b/libraries/ZVulkan/src/glslang/glslang/Include/ResourceLimits.h similarity index 99% rename from libraries/glslang/glslang/Include/ResourceLimits.h rename to libraries/ZVulkan/src/glslang/glslang/Include/ResourceLimits.h index 106b21d9ca8..b670cf163f2 100644 --- a/libraries/glslang/glslang/Include/ResourceLimits.h +++ b/libraries/ZVulkan/src/glslang/glslang/Include/ResourceLimits.h @@ -142,6 +142,7 @@ struct TBuiltInResource { int maxTaskWorkGroupSizeY_NV; int maxTaskWorkGroupSizeZ_NV; int maxMeshViewCountNV; + int maxDualSourceDrawBuffersEXT; TLimits limits; }; diff --git a/libraries/glslang/glslang/Include/ShHandle.h b/libraries/ZVulkan/src/glslang/glslang/Include/ShHandle.h similarity index 100% rename from libraries/glslang/glslang/Include/ShHandle.h rename to libraries/ZVulkan/src/glslang/glslang/Include/ShHandle.h diff --git a/libraries/ZVulkan/src/glslang/glslang/Include/SpirvIntrinsics.h b/libraries/ZVulkan/src/glslang/glslang/Include/SpirvIntrinsics.h new file mode 100644 index 00000000000..e7a999d4086 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/Include/SpirvIntrinsics.h @@ -0,0 +1,136 @@ +// +// Copyright(C) 2021 Advanced Micro Devices, Inc. +// +// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. +// + +#pragma once + +#ifndef GLSLANG_WEB + +// +// GL_EXT_spirv_intrinsics +// +#include "Common.h" + +namespace glslang { + +class TIntermTyped; +class TIntermConstantUnion; +class TType; + +// SPIR-V requirements +struct TSpirvRequirement { + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) + + // capability = [..] + TSet extensions; + // extension = [..] + TSet capabilities; +}; + +// SPIR-V execution modes +struct TSpirvExecutionMode { + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) + + // spirv_execution_mode + TMap> modes; + // spirv_execution_mode_id + TMap > modeIds; +}; + +// SPIR-V decorations +struct TSpirvDecorate { + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) + + // spirv_decorate + TMap > decorates; + // spirv_decorate_id + TMap > decorateIds; + // spirv_decorate_string + TMap > decorateStrings; +}; + +// SPIR-V instruction +struct TSpirvInstruction { + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) + + TSpirvInstruction() { set = ""; id = -1; } + + bool operator==(const TSpirvInstruction& rhs) const { return set == rhs.set && id == rhs.id; } + bool operator!=(const TSpirvInstruction& rhs) const { return !operator==(rhs); } + + // spirv_instruction + TString set; + int id; +}; + +// SPIR-V type parameter +struct TSpirvTypeParameter { + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) + + TSpirvTypeParameter(const TIntermConstantUnion* arg) { isConstant = true; constant = arg; } + TSpirvTypeParameter(const TType* arg) { isConstant = false; type = arg; } + + bool operator==(const TSpirvTypeParameter& rhs) const + { + return isConstant == rhs.isConstant && ((isConstant && constant == rhs.constant) || (!isConstant && type == rhs.type)); + } + bool operator!=(const TSpirvTypeParameter& rhs) const { return !operator==(rhs); } + + bool isConstant; + union { + const TIntermConstantUnion* constant; + const TType* type; + }; +}; + +typedef TVector TSpirvTypeParameters; + +// SPIR-V type +struct TSpirvType { + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) + + bool operator==(const TSpirvType& rhs) const + { + return spirvInst == rhs.spirvInst && typeParams == rhs.typeParams; + } + bool operator!=(const TSpirvType& rhs) const { return !operator==(rhs); } + + // spirv_type + TSpirvInstruction spirvInst; + TSpirvTypeParameters typeParams; +}; + +} // end namespace glslang + +#endif // GLSLANG_WEB diff --git a/libraries/glslang/glslang/Include/Types.h b/libraries/ZVulkan/src/glslang/glslang/Include/Types.h similarity index 89% rename from libraries/glslang/glslang/Include/Types.h rename to libraries/ZVulkan/src/glslang/glslang/Include/Types.h index 3572099e3d9..a6bf191d75f 100644 --- a/libraries/glslang/glslang/Include/Types.h +++ b/libraries/ZVulkan/src/glslang/glslang/Include/Types.h @@ -3,6 +3,7 @@ // Copyright (C) 2012-2016 LunarG, Inc. // Copyright (C) 2015-2016 Google, Inc. // Copyright (C) 2017 ARM Limited. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -43,11 +44,14 @@ #include "../Include/BaseTypes.h" #include "../Public/ShaderLang.h" #include "arrays.h" +#include "SpirvIntrinsics.h" #include namespace glslang { +class TIntermAggregate; + const int GlslangMaxTypeLength = 200; // TODO: need to print block/struct one member per line, so this can stay bounded const char* const AnonymousPrefix = "anon@"; // for something like a block whose members can be directly accessed @@ -114,6 +118,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler, #endif bool is1D() const { return dim == Esd1D; } + bool is2D() const { return dim == Esd2D; } bool isBuffer() const { return dim == EsdBuffer; } bool isRect() const { return dim == EsdRect; } bool isSubpass() const { return dim == EsdSubpass; } @@ -405,6 +410,7 @@ enum TLayoutFormat { ElfRg8i, ElfR16i, ElfR8i, + ElfR64i, ElfIntGuard, // to help with comparisons @@ -422,6 +428,7 @@ enum TLayoutFormat { ElfRg8ui, ElfR16ui, ElfR8ui, + ElfR64ui, ElfCount }; @@ -472,6 +479,17 @@ enum TInterlockOrdering { EioCount, }; +enum TShaderInterface +{ + // Includes both uniform blocks and buffer blocks + EsiUniform = 0, + EsiInput, + EsiOutput, + EsiNone, + + EsiCount +}; + class TQualifier { public: static const int layoutNotSet = -1; @@ -484,7 +502,11 @@ class TQualifier { declaredBuiltIn = EbvNone; #ifndef GLSLANG_WEB noContraction = false; + nullInit = false; + spirvByReference = false; + spirvLiteral = false; #endif + defaultBlock = false; } // drop qualifiers that don't belong in a temporary variable @@ -497,7 +519,15 @@ class TQualifier { clearMemory(); specConstant = false; nonUniform = false; + nullInit = false; + defaultBlock = false; clearLayout(); +#ifndef GLSLANG_WEB + spirvStorageClass = -1; + spirvDecorate = nullptr; + spirvByReference = false; + spirvLiteral = false; +#endif } void clearInterstage() @@ -532,6 +562,7 @@ class TQualifier { queuefamilycoherent = false; workgroupcoherent = false; subgroupcoherent = false; + shadercallcoherent = false; nonprivate = false; volatil = false; restrict = false; @@ -553,6 +584,8 @@ class TQualifier { // having a constant_id is not sufficient: expressions have no id, but are still specConstant bool specConstant : 1; bool nonUniform : 1; + bool explicitOffset : 1; + bool defaultBlock : 1; // default blocks with matching names have structures merged when linking #ifdef GLSLANG_WEB bool isWriteOnly() const { return false; } @@ -571,6 +604,12 @@ class TQualifier { bool isNoContraction() const { return false; } void setNoContraction() { } bool isPervertexNV() const { return false; } + void setNullInit() { } + bool isNullInit() const { return false; } + void setSpirvByReference() { } + bool isSpirvByReference() { return false; } + void setSpirvLiteral() { } + bool isSpirvLiteral() { return false; } #else bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects bool nopersp : 1; @@ -590,7 +629,11 @@ class TQualifier { bool queuefamilycoherent : 1; bool workgroupcoherent : 1; bool subgroupcoherent : 1; + bool shadercallcoherent : 1; bool nonprivate : 1; + bool nullInit : 1; + bool spirvByReference : 1; + bool spirvLiteral : 1; bool isWriteOnly() const { return writeonly; } bool isReadOnly() const { return readonly; } bool isRestrict() const { return restrict; } @@ -599,11 +642,11 @@ class TQualifier { bool isSample() const { return sample; } bool isMemory() const { - return subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly || nonprivate; + return shadercallcoherent || subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly || nonprivate; } bool isMemoryQualifierImageAndSSBOOnly() const { - return subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly; + return shadercallcoherent || subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly; } bool bufferReferenceNeedsVulkanMemoryModel() const { @@ -626,6 +669,12 @@ class TQualifier { bool isNoContraction() const { return noContraction; } void setNoContraction() { noContraction = true; } bool isPervertexNV() const { return pervertexNV; } + void setNullInit() { nullInit = true; } + bool isNullInit() const { return nullInit; } + void setSpirvByReference() { spirvByReference = true; } + bool isSpirvByReference() const { return spirvByReference; } + void setSpirvLiteral() { spirvLiteral = true; } + bool isSpirvLiteral() const { return spirvLiteral; } #endif bool isPipeInput() const @@ -731,6 +780,46 @@ class TQualifier { } } + TBlockStorageClass getBlockStorage() const { + if (storage == EvqUniform && !isPushConstant()) { + return EbsUniform; + } + else if (storage == EvqUniform) { + return EbsPushConstant; + } + else if (storage == EvqBuffer) { + return EbsStorageBuffer; + } + return EbsNone; + } + + void setBlockStorage(TBlockStorageClass newBacking) { +#ifndef GLSLANG_WEB + layoutPushConstant = (newBacking == EbsPushConstant); +#endif + switch (newBacking) { + case EbsUniform : + if (layoutPacking == ElpStd430) { + // std430 would not be valid + layoutPacking = ElpStd140; + } + storage = EvqUniform; + break; + case EbsStorageBuffer : + storage = EvqBuffer; + break; +#ifndef GLSLANG_WEB + case EbsPushConstant : + storage = EvqUniform; + layoutSet = TQualifier::layoutSetEnd; + layoutBinding = TQualifier::layoutBindingEnd; + break; +#endif + default: + break; + } + } + #ifdef GLSLANG_WEB bool isPerView() const { return false; } bool isTaskMemory() const { return false; } @@ -739,6 +828,12 @@ class TQualifier { bool isPerPrimitive() const { return perPrimitiveNV; } bool isPerView() const { return perViewNV; } bool isTaskMemory() const { return perTaskNV; } + bool isAnyPayload() const { + return storage == EvqPayload || storage == EvqPayloadIn; + } + bool isAnyCallable() const { + return storage == EvqCallableData || storage == EvqCallableDataIn; + } // True if this type of IO is supposed to be arrayed with extra level for per-vertex data bool isArrayedIo(EShLanguage language) const @@ -773,7 +868,7 @@ class TQualifier { layoutViewportRelative = false; // -2048 as the default value indicating layoutSecondaryViewportRelative is not set layoutSecondaryViewportRelativeOffset = -2048; - layoutShaderRecordNV = false; + layoutShaderRecord = false; layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd; layoutFormat = ElfNone; #endif @@ -812,7 +907,7 @@ class TQualifier { hasAnyLocation() || hasStream() || hasFormat() || - isShaderRecordNV() || + isShaderRecord() || isPushConstant() || hasBufferReference(); } @@ -821,6 +916,7 @@ class TQualifier { return hasNonXfbLayout() || hasXfb(); } + TLayoutMatrix layoutMatrix : 3; TLayoutPacking layoutPacking : 4; int layoutOffset; @@ -871,7 +967,11 @@ class TQualifier { bool layoutPassthrough; bool layoutViewportRelative; int layoutSecondaryViewportRelativeOffset; - bool layoutShaderRecordNV; + bool layoutShaderRecord; + + // GL_EXT_spirv_intrinsics + int spirvStorageClass; + TSpirvDecorate* spirvDecorate; #endif bool hasUniformLayout() const @@ -942,7 +1042,7 @@ class TQualifier { bool hasAttachment() const { return false; } TLayoutFormat getFormat() const { return ElfNone; } bool isPushConstant() const { return false; } - bool isShaderRecordNV() const { return false; } + bool isShaderRecord() const { return false; } bool hasBufferReference() const { return false; } bool hasBufferReferenceAlign() const { return false; } bool isNonUniform() const { return false; } @@ -993,7 +1093,7 @@ class TQualifier { } TLayoutFormat getFormat() const { return layoutFormat; } bool isPushConstant() const { return layoutPushConstant; } - bool isShaderRecordNV() const { return layoutShaderRecordNV; } + bool isShaderRecord() const { return layoutShaderRecord; } bool hasBufferReference() const { return layoutBufferReference; } bool hasBufferReferenceAlign() const { @@ -1003,6 +1103,15 @@ class TQualifier { { return nonUniform; } + + // GL_EXT_spirv_intrinsics + bool hasSprivDecorate() const { return spirvDecorate != nullptr; } + void setSpirvDecorate(int decoration, const TIntermAggregate* args = nullptr); + void setSpirvDecorateId(int decoration, const TIntermAggregate* args); + void setSpirvDecorateString(int decoration, const TIntermAggregate* args); + const TSpirvDecorate& getSpirvDecorate() const { assert(spirvDecorate); return *spirvDecorate; } + TSpirvDecorate& getSpirvDecorate() { assert(spirvDecorate); return *spirvDecorate; } + TString getSpirvDecorateQualifierString() const; #endif bool hasSpecConstantId() const { @@ -1101,6 +1210,8 @@ class TQualifier { case ElfR32ui: return "r32ui"; case ElfR16ui: return "r16ui"; case ElfR8ui: return "r8ui"; + case ElfR64ui: return "r64ui"; + case ElfR64i: return "r64i"; default: return "none"; } } @@ -1219,6 +1330,7 @@ struct TShaderQualifiers { bool layoutDerivativeGroupQuads; // true if layout derivative_group_quadsNV set bool layoutDerivativeGroupLinear; // true if layout derivative_group_linearNV set int primitives; // mesh shader "max_primitives"DerivativeGroupLinear; // true if layout derivative_group_linearNV set + bool layoutPrimitiveCulling; // true if layout primitive_culling set TLayoutDepth getDepth() const { return layoutDepth; } #else TLayoutDepth getDepth() const { return EldNone; } @@ -1252,6 +1364,7 @@ struct TShaderQualifiers { layoutOverrideCoverage = false; layoutDerivativeGroupQuads = false; layoutDerivativeGroupLinear = false; + layoutPrimitiveCulling = false; primitives = TQualifier::layoutNotSet; interlockOrdering = EioNone; #endif @@ -1315,6 +1428,8 @@ struct TShaderQualifiers { primitives = src.primitives; if (src.interlockOrdering != EioNone) interlockOrdering = src.interlockOrdering; + if (src.layoutPrimitiveCulling) + layoutPrimitiveCulling = src.layoutPrimitiveCulling; #endif } }; @@ -1341,6 +1456,10 @@ class TPublicType { const TType* userDef; TSourceLoc loc; TArraySizes* typeParameters; +#ifndef GLSLANG_WEB + // SPIR-V type defined by spirv_type directive + TSpirvType* spirvType; +#endif #ifdef GLSLANG_WEB bool isCoopmat() const { return false; } @@ -1359,6 +1478,9 @@ class TPublicType { loc = l; typeParameters = nullptr; coopmat = false; +#ifndef GLSLANG_WEB + spirvType = nullptr; +#endif } void initQualifiers(bool global = false) @@ -1395,6 +1517,11 @@ class TPublicType { return matrixCols == 0 && vectorSize == 1 && arraySizes == nullptr && userDef == nullptr; } +#ifndef GLSLANG_WEB + // GL_EXT_spirv_intrinsics + void setSpirvType(const TSpirvInstruction& spirvInst, const TSpirvTypeParameters* typeParams = nullptr); +#endif + // "Image" is a superset of "Subpass" bool isImage() const { return basicType == EbtSampler && sampler.isImage(); } bool isSubpass() const { return basicType == EbtSampler && sampler.isSubpass(); } @@ -1412,6 +1539,9 @@ class TType { bool isVector = false) : basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1), coopmat(false), arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr) +#ifndef GLSLANG_WEB + , spirvType(nullptr) +#endif { sampler.clear(); qualifier.clear(); @@ -1423,6 +1553,9 @@ class TType { bool isVector = false) : basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1), coopmat(false), arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr) +#ifndef GLSLANG_WEB + , spirvType(nullptr) +#endif { sampler.clear(); qualifier.clear(); @@ -1436,6 +1569,9 @@ class TType { basicType(p.basicType), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false), coopmat(p.coopmat), arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(p.typeParameters) +#ifndef GLSLANG_WEB + , spirvType(p.spirvType) +#endif { if (basicType == EbtSampler) sampler = p.sampler; @@ -1470,6 +1606,9 @@ class TType { basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false), arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr), sampler(sampler), typeParameters(nullptr) +#ifndef GLSLANG_WEB + , spirvType(nullptr) +#endif { qualifier.clear(); qualifier.storage = q; @@ -1520,6 +1659,9 @@ class TType { TType(TTypeList* userDef, const TString& n) : basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr) +#ifndef GLSLANG_WEB + , spirvType(nullptr) +#endif { sampler.clear(); qualifier.clear(); @@ -1529,6 +1671,9 @@ class TType { TType(TTypeList* userDef, const TString& n, const TQualifier& q) : basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false), qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr) +#ifndef GLSLANG_WEB + , spirvType(nullptr) +#endif { sampler.clear(); typeName = NewPoolTString(n.c_str()); @@ -1537,6 +1682,9 @@ class TType { explicit TType(TBasicType t, const TType &p, const TString& n) : basicType(t), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr) +#ifndef GLSLANG_WEB + , spirvType(nullptr) +#endif { assert(t == EbtReference); typeName = NewPoolTString(n.c_str()); @@ -1567,6 +1715,9 @@ class TType { referentType = copyOf.referentType; } typeParameters = copyOf.typeParameters; +#ifndef GLSLANG_WEB + spirvType = copyOf.spirvType; +#endif coopmat = copyOf.isCoopMat(); } @@ -1612,6 +1763,23 @@ class TType { assert(fieldName); return *fieldName; } + TShaderInterface getShaderInterface() const + { + if (basicType != EbtBlock) + return EsiNone; + + switch (qualifier.storage) { + default: + return EsiNone; + case EvqVaryingIn: + return EsiInput; + case EvqVaryingOut: + return EsiOutput; + case EvqUniform: + case EvqBuffer: + return EsiUniform; + } + } virtual TBasicType getBasicType() const { return basicType; } virtual const TSampler& getSampler() const { return sampler; } @@ -1640,6 +1808,7 @@ class TType { virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); } virtual bool isScalarOrVec1() const { return isScalar() || vector1; } + virtual bool isScalarOrVector() const { return !isMatrix() && !isStruct() && !isArray(); } virtual bool isVector() const { return vectorSize > 1 || vector1; } virtual bool isMatrix() const { return matrixCols ? true : false; } virtual bool isArray() const { return arraySizes != nullptr; } @@ -1670,7 +1839,7 @@ class TType { } virtual bool isOpaque() const { return basicType == EbtSampler #ifndef GLSLANG_WEB - || basicType == EbtAtomicUint || basicType == EbtAccStructNV + || basicType == EbtAtomicUint || basicType == EbtAccStruct || basicType == EbtRayQuery #endif ; } virtual bool isBuiltIn() const { return getQualifier().builtIn != EbvNone; } @@ -1918,8 +2087,6 @@ class TType { } } - - const char* getBasicString() const { return TType::getBasicString(basicType); @@ -1946,8 +2113,11 @@ class TType { case EbtAtomicUint: return "atomic_uint"; case EbtStruct: return "structure"; case EbtBlock: return "block"; - case EbtAccStructNV: return "accelerationStructureNV"; + case EbtAccStruct: return "accelerationStructureNV"; + case EbtRayQuery: return "rayQueryEXT"; case EbtReference: return "reference"; + case EbtString: return "string"; + case EbtSpirvType: return "spirv_type"; #endif default: return "unknown type"; } @@ -1968,6 +2138,9 @@ class TType { const auto appendUint = [&](unsigned int u) { typeString.append(std::to_string(u).c_str()); }; const auto appendInt = [&](int i) { typeString.append(std::to_string(i).c_str()); }; + if (qualifier.hasSprivDecorate()) + appendStr(qualifier.getSpirvDecorateQualifierString().c_str()); + if (qualifier.hasLayout()) { // To reduce noise, skip this if the only layout is an xfb_buffer // with no triggering xfb_offset. @@ -2056,7 +2229,7 @@ class TType { appendStr(" layoutSecondaryViewportRelativeOffset="); appendInt(qualifier.layoutSecondaryViewportRelativeOffset); } - if (qualifier.layoutShaderRecordNV) + if (qualifier.layoutShaderRecord) appendStr(" shaderRecordNV"); appendStr(")"); @@ -2099,6 +2272,8 @@ class TType { appendStr(" workgroupcoherent"); if (qualifier.subgroupcoherent) appendStr(" subgroupcoherent"); + if (qualifier.shadercallcoherent) + appendStr(" shadercallcoherent"); if (qualifier.nonprivate) appendStr(" nonprivate"); if (qualifier.volatil) @@ -2113,6 +2288,12 @@ class TType { appendStr(" specialization-constant"); if (qualifier.nonUniform) appendStr(" nonuniform"); + if (qualifier.isNullInit()) + appendStr(" null-init"); + if (qualifier.isSpirvByReference()) + appendStr(" spirv_by_reference"); + if (qualifier.isSpirvLiteral()) + appendStr(" spirv_literal"); appendStr(" "); appendStr(getStorageQualifierString()); if (isArray()) { @@ -2232,6 +2413,17 @@ class TType { name += ';' ; } + // These variables are inconsistently declared inside and outside of gl_PerVertex in glslang right now. + // They are declared inside of 'in gl_PerVertex', but sitting as standalone when they are 'out'puts. + bool isInconsistentGLPerVertexMember(const TString& name) const + { + if (name == "gl_SecondaryPositionNV" || + name == "gl_PositionPerViewNV") + return true; + return false; + } + + // Do two structure types match? They could be declared independently, // in different places, but still might satisfy the definition of matching. // From the spec: @@ -2247,22 +2439,48 @@ class TType { (isStruct() && right.isStruct() && structure == right.structure)) return true; - // Both being nullptr was caught above, now they both have to be structures of the same number of elements - if (!isStruct() || !right.isStruct() || - structure->size() != right.structure->size()) - return false; - // Structure names have to match if (*typeName != *right.typeName) return false; - // Compare the names and types of all the members, which have to match - for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->getFieldName() != (*right.structure)[i].type->getFieldName()) - return false; + // There are inconsistencies with how gl_PerVertex is setup. For now ignore those as errors if they + // are known inconsistencies. + bool isGLPerVertex = *typeName == "gl_PerVertex"; - if (*(*structure)[i].type != *(*right.structure)[i].type) - return false; + // Both being nullptr was caught above, now they both have to be structures of the same number of elements + if (!isStruct() || !right.isStruct() || + (structure->size() != right.structure->size() && !isGLPerVertex)) + return false; + + // Compare the names and types of all the members, which have to match + for (size_t li = 0, ri = 0; li < structure->size() || ri < right.structure->size(); ++li, ++ri) { + if (li < structure->size() && ri < right.structure->size()) { + if ((*structure)[li].type->getFieldName() == (*right.structure)[ri].type->getFieldName()) { + if (*(*structure)[li].type != *(*right.structure)[ri].type) + return false; + } else { + // If one of the members is something that's inconsistently declared, skip over it + // for now. + if (isGLPerVertex) { + if (isInconsistentGLPerVertexMember((*structure)[li].type->getFieldName())) { + ri--; + continue; + } else if (isInconsistentGLPerVertexMember((*right.structure)[ri].type->getFieldName())) { + li--; + continue; + } + } else { + return false; + } + } + // If we get here, then there should only be inconsistently declared members left + } else if (li < structure->size()) { + if (!isInconsistentGLPerVertexMember((*structure)[li].type->getFieldName())) + return false; + } else { + if (!isInconsistentGLPerVertexMember((*right.structure)[ri].type->getFieldName())) + return false; + } } return true; @@ -2312,6 +2530,15 @@ class TType { (typeParameters != nullptr && right.typeParameters != nullptr && *typeParameters == *right.typeParameters)); } +#ifndef GLSLANG_WEB + // See if two type's SPIR-V type contents match + bool sameSpirvType(const TType& right) const + { + return ((spirvType == nullptr && right.spirvType == nullptr) || + (spirvType != nullptr && right.spirvType != nullptr && *spirvType == *right.spirvType)); + } +#endif + // See if two type's elements match in all ways except basic type bool sameElementShape(const TType& right) const { @@ -2350,7 +2577,11 @@ class TType { // See if two types match in all ways (just the actual type, not qualification) bool operator==(const TType& right) const { +#ifndef GLSLANG_WEB + return sameElementType(right) && sameArrayness(right) && sameTypeParameters(right) && sameSpirvType(right); +#else return sameElementType(right) && sameArrayness(right) && sameTypeParameters(right); +#endif } bool operator!=(const TType& right) const @@ -2369,6 +2600,10 @@ class TType { return 0; } +#ifndef GLSLANG_WEB + const TSpirvType& getSpirvType() const { assert(spirvType); return *spirvType; } +#endif + protected: // Require consumer to pick between deep copy and shallow copy. TType(const TType& type); @@ -2381,6 +2616,19 @@ class TType { { shallowCopy(copyOf); +#ifndef GLSLANG_WEB + // GL_EXT_spirv_intrinsics + if (copyOf.qualifier.spirvDecorate) { + qualifier.spirvDecorate = new TSpirvDecorate; + *qualifier.spirvDecorate = *copyOf.qualifier.spirvDecorate; + } + + if (copyOf.spirvType) { + spirvType = new TSpirvType; + *spirvType = *copyOf.spirvType; + } +#endif + if (copyOf.arraySizes) { arraySizes = new TArraySizes; *arraySizes = *copyOf.arraySizes; @@ -2440,6 +2688,9 @@ class TType { TString *typeName; // for structure type name TSampler sampler; TArraySizes* typeParameters;// nullptr unless a parameterized type; can be shared across types +#ifndef GLSLANG_WEB + TSpirvType* spirvType; // SPIR-V type defined by spirv_type directive +#endif }; } // end namespace glslang diff --git a/libraries/glslang/glslang/Include/arrays.h b/libraries/ZVulkan/src/glslang/glslang/Include/arrays.h similarity index 100% rename from libraries/glslang/glslang/Include/arrays.h rename to libraries/ZVulkan/src/glslang/glslang/Include/arrays.h diff --git a/libraries/ZVulkan/src/glslang/glslang/Include/build_info.h b/libraries/ZVulkan/src/glslang/glslang/Include/build_info.h new file mode 100644 index 00000000000..661c4a3c1c4 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/Include/build_info.h @@ -0,0 +1,62 @@ +// Copyright (C) 2020 The Khronos Group Inc. +// +// 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 The Khronos Group Inc. 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 HOLDERS 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. + +#ifndef GLSLANG_BUILD_INFO +#define GLSLANG_BUILD_INFO + +#define GLSLANG_VERSION_MAJOR 11 +#define GLSLANG_VERSION_MINOR 6 +#define GLSLANG_VERSION_PATCH 0 +#define GLSLANG_VERSION_FLAVOR "" + +#define GLSLANG_VERSION_GREATER_THAN(major, minor, patch) \ + (((major) > GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ + (((minor) > GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ + ((patch) > GLSLANG_VERSION_PATCH))))) + +#define GLSLANG_VERSION_GREATER_OR_EQUAL_TO(major, minor, patch) \ + (((major) > GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ + (((minor) > GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ + ((patch) >= GLSLANG_VERSION_PATCH))))) + +#define GLSLANG_VERSION_LESS_THAN(major, minor, patch) \ + (((major) < GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ + (((minor) < GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ + ((patch) < GLSLANG_VERSION_PATCH))))) + +#define GLSLANG_VERSION_LESS_OR_EQUAL_TO(major, minor, patch) \ + (((major) < GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ + (((minor) < GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ + ((patch) <= GLSLANG_VERSION_PATCH))))) + +#endif // GLSLANG_BUILD_INFO diff --git a/libraries/glslang/glslang/Include/intermediate.h b/libraries/ZVulkan/src/glslang/glslang/Include/intermediate.h similarity index 95% rename from libraries/glslang/glslang/Include/intermediate.h rename to libraries/ZVulkan/src/glslang/glslang/Include/intermediate.h index 29d58ca635e..1e6ab4aa7aa 100644 --- a/libraries/glslang/glslang/Include/intermediate.h +++ b/libraries/ZVulkan/src/glslang/glslang/Include/intermediate.h @@ -2,6 +2,7 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2016 LunarG, Inc. // Copyright (C) 2017 ARM Limited. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -70,6 +71,9 @@ enum TOperator { EOpFunctionCall, EOpFunction, // For function definition EOpParameters, // an aggregate listing the parameters to a function +#ifndef GLSLANG_WEB + EOpSpirvInst, +#endif // // Unary operators @@ -279,6 +283,12 @@ enum TOperator { EOpConvUvec2ToPtr, EOpConvPtrToUvec2, + // uint64_t -> accelerationStructureEXT + EOpConvUint64ToAccStruct, + + // uvec2 -> accelerationStructureEXT + EOpConvUvec2ToAccStruct, + // // binary operations // @@ -586,6 +596,7 @@ enum TOperator { EOpTime, EOpAtomicAdd, + EOpAtomicSubtract, EOpAtomicMin, EOpAtomicMax, EOpAtomicAnd, @@ -621,17 +632,22 @@ enum TOperator { EOpIsHelperInvocation, + EOpDebugPrintf, + // // Branch // - EOpKill, // Fragment only + EOpKill, // Fragment only + EOpTerminateInvocation, // Fragment only + EOpDemote, // Fragment only + EOpTerminateRayKHR, // Any-hit only + EOpIgnoreIntersectionKHR, // Any-hit only EOpReturn, EOpBreak, EOpContinue, EOpCase, EOpDefault, - EOpDemote, // Fragment only // // Constructors @@ -748,6 +764,7 @@ enum TOperator { EOpConstructNonuniform, // expected to be transformed away, not present in final AST EOpConstructReference, EOpConstructCooperativeMatrix, + EOpConstructAccStruct, EOpConstructGuardEnd, // @@ -909,11 +926,43 @@ enum TOperator { EOpMul32x16, EOpTraceNV, - EOpReportIntersectionNV, + EOpTraceRayMotionNV, + EOpTraceKHR, + EOpReportIntersection, EOpIgnoreIntersectionNV, EOpTerminateRayNV, EOpExecuteCallableNV, + EOpExecuteCallableKHR, EOpWritePackedPrimitiveIndices4x8NV, + + // + // GL_EXT_ray_query operations + // + + EOpRayQueryInitialize, + EOpRayQueryTerminate, + EOpRayQueryGenerateIntersection, + EOpRayQueryConfirmIntersection, + EOpRayQueryProceed, + EOpRayQueryGetIntersectionType, + EOpRayQueryGetRayTMin, + EOpRayQueryGetRayFlags, + EOpRayQueryGetIntersectionT, + EOpRayQueryGetIntersectionInstanceCustomIndex, + EOpRayQueryGetIntersectionInstanceId, + EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset, + EOpRayQueryGetIntersectionGeometryIndex, + EOpRayQueryGetIntersectionPrimitiveIndex, + EOpRayQueryGetIntersectionBarycentrics, + EOpRayQueryGetIntersectionFrontFace, + EOpRayQueryGetIntersectionCandidateAABBOpaque, + EOpRayQueryGetIntersectionObjectRayDirection, + EOpRayQueryGetIntersectionObjectRayOrigin, + EOpRayQueryGetWorldRayDirection, + EOpRayQueryGetWorldRayOrigin, + EOpRayQueryGetIntersectionObjectToWorld, + EOpRayQueryGetIntersectionWorldToObject, + // // HLSL operations // @@ -1091,6 +1140,8 @@ class TIntermTyped : public TIntermNode { virtual TBasicType getBasicType() const { return type.getBasicType(); } virtual TQualifier& getQualifier() { return type.getQualifier(); } virtual const TQualifier& getQualifier() const { return type.getQualifier(); } + virtual TArraySizes* getArraySizes() { return type.getArraySizes(); } + virtual const TArraySizes* getArraySizes() const { return type.getArraySizes(); } virtual void propagatePrecision(TPrecisionQualifier); virtual int getVectorSize() const { return type.getVectorSize(); } virtual int getMatrixCols() const { return type.getMatrixCols(); } @@ -1199,6 +1250,7 @@ class TIntermBranch : public TIntermNode { TOperator getFlowOp() const { return flowOp; } TIntermTyped* getExpression() const { return expression; } void setExpression(TIntermTyped* pExpression) { expression = pExpression; } + void updatePrecision(TPrecisionQualifier parentPrecision); protected: TOperator flowOp; TIntermTyped* expression; @@ -1230,15 +1282,15 @@ class TIntermSymbol : public TIntermTyped { // if symbol is initialized as symbol(sym), the memory comes from the pool allocator of sym. If sym comes from // per process threadPoolAllocator, then it causes increased memory usage per compile // it is essential to use "symbol = sym" to assign to symbol - TIntermSymbol(int i, const TString& n, const TType& t) + TIntermSymbol(long long i, const TString& n, const TType& t) : TIntermTyped(t), id(i), #ifndef GLSLANG_WEB flattenSubset(-1), #endif constSubtree(nullptr) { name = n; } - virtual int getId() const { return id; } - virtual void changeId(int i) { id = i; } + virtual long long getId() const { return id; } + virtual void changeId(long long i) { id = i; } virtual const TString& getName() const { return name; } virtual void traverse(TIntermTraverser*); virtual TIntermSymbol* getAsSymbolNode() { return this; } @@ -1249,15 +1301,17 @@ class TIntermSymbol : public TIntermTyped { TIntermTyped* getConstSubtree() const { return constSubtree; } #ifndef GLSLANG_WEB void setFlattenSubset(int subset) { flattenSubset = subset; } + virtual const TString& getAccessName() const; + int getFlattenSubset() const { return flattenSubset; } // -1 means full object #endif // This is meant for cases where a node has already been constructed, and // later on, it becomes necessary to switch to a different symbol. - virtual void switchId(int newId) { id = newId; } + virtual void switchId(long long newId) { id = newId; } protected: - int id; // the unique id of the symbol this node represents + long long id; // the unique id of the symbol this node represents #ifndef GLSLANG_WEB int flattenSubset; // how deeply the flattened object rooted at id has been dereferenced #endif @@ -1566,8 +1620,15 @@ class TIntermUnary : public TIntermOperator { virtual TIntermUnary* getAsUnaryNode() { return this; } virtual const TIntermUnary* getAsUnaryNode() const { return this; } virtual void updatePrecision(); +#ifndef GLSLANG_WEB + void setSpirvInstruction(const TSpirvInstruction& inst) { spirvInst = inst; } + const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; } +#endif protected: TIntermTyped* operand; +#ifndef GLSLANG_WEB + TSpirvInstruction spirvInst; +#endif }; typedef TVector TIntermSequence; @@ -1598,6 +1659,10 @@ class TIntermAggregate : public TIntermOperator { bool getDebug() const { return debug; } void setPragmaTable(const TPragmaTable& pTable); const TPragmaTable& getPragmaTable() const { return *pragmaTable; } +#ifndef GLSLANG_WEB + void setSpirvInstruction(const TSpirvInstruction& inst) { spirvInst = inst; } + const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; } +#endif protected: TIntermAggregate(const TIntermAggregate&); // disallow copy constructor TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator @@ -1608,6 +1673,9 @@ class TIntermAggregate : public TIntermOperator { bool optimize; bool debug; TPragmaTable* pragmaTable; +#ifndef GLSLANG_WEB + TSpirvInstruction spirvInst; +#endif }; // @@ -1625,8 +1693,11 @@ class TIntermSelection : public TIntermTyped { flatten(false), dontFlatten(false) {} virtual void traverse(TIntermTraverser*); virtual TIntermTyped* getCondition() const { return condition; } + virtual void setCondition(TIntermTyped* c) { condition = c; } virtual TIntermNode* getTrueBlock() const { return trueBlock; } + virtual void setTrueBlock(TIntermTyped* tb) { trueBlock = tb; } virtual TIntermNode* getFalseBlock() const { return falseBlock; } + virtual void setFalseBlock(TIntermTyped* fb) { falseBlock = fb; } virtual TIntermSelection* getAsSelectionNode() { return this; } virtual const TIntermSelection* getAsSelectionNode() const { return this; } diff --git a/libraries/glslang/glslang/MachineIndependent/Constant.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Constant.cpp similarity index 98% rename from libraries/glslang/glslang/MachineIndependent/Constant.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Constant.cpp index 98c2666fbb7..17b496c53f9 100644 --- a/libraries/glslang/glslang/MachineIndependent/Constant.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Constant.cpp @@ -2,7 +2,7 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. -// Copyright (C) 2018 Google, Inc. +// Copyright (C) 2018-2020 Google, Inc. // // All rights reserved. // @@ -42,6 +42,10 @@ #include #include +#ifdef _MSC_VER +#pragma warning(disable: 4146) // warning C4146: unary minus operator applied to unsigned type, result still unsigned +#endif + namespace { using namespace glslang; @@ -529,7 +533,12 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EbtDouble: case EbtFloat16: case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break; - case EbtInt: newConstArray[i].setIConst(-unionArray[i].getIConst()); break; + // Note: avoid UBSAN error regarding negating 0x80000000 + case EbtInt: newConstArray[i].setIConst( + unionArray[i].getIConst() == 0x80000000 + ? -0x7FFFFFFF - 1 + : -unionArray[i].getIConst()); + break; case EbtUint: newConstArray[i].setUConst(static_cast(-static_cast(unionArray[i].getUConst()))); break; #ifndef GLSLANG_WEB case EbtInt8: newConstArray[i].setI8Const(-unionArray[i].getI8Const()); break; @@ -599,17 +608,11 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) newConstArray[i].setDConst(log(unionArray[i].getDConst())); break; case EOpExp2: - { - const double inv_log2_e = 0.69314718055994530941723212145818; - newConstArray[i].setDConst(exp(unionArray[i].getDConst() * inv_log2_e)); - break; - } + newConstArray[i].setDConst(exp2(unionArray[i].getDConst())); + break; case EOpLog2: - { - const double log2_e = 1.4426950408889634073599246810019; - newConstArray[i].setDConst(log2_e * log(unionArray[i].getDConst())); - break; - } + newConstArray[i].setDConst(log2(unionArray[i].getDConst())); + break; case EOpSqrt: newConstArray[i].setDConst(sqrt(unionArray[i].getDConst())); break; @@ -1012,6 +1015,7 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) case EOpMin: case EOpMax: case EOpMix: + case EOpMod: case EOpClamp: case EOpLessThan: case EOpGreaterThan: @@ -1074,6 +1078,14 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) case EOpPow: newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst())); break; + case EOpMod: + { + double arg0 = childConstUnions[0][arg0comp].getDConst(); + double arg1 = childConstUnions[1][arg1comp].getDConst(); + double result = arg0 - arg1 * floor(arg0 / arg1); + newConstArray[comp].setDConst(result); + break; + } case EOpMin: switch(children[0]->getAsTyped()->getBasicType()) { case EbtFloat16: diff --git a/libraries/glslang/glslang/MachineIndependent/InfoSink.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/InfoSink.cpp similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/InfoSink.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/InfoSink.cpp diff --git a/libraries/glslang/glslang/MachineIndependent/Initialize.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Initialize.cpp similarity index 87% rename from libraries/glslang/glslang/MachineIndependent/Initialize.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Initialize.cpp index 90106d922d5..823406c18df 100644 --- a/libraries/glslang/glslang/MachineIndependent/Initialize.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Initialize.cpp @@ -1,8 +1,9 @@ // // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2016 LunarG, Inc. -// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) 2015-2020 Google, Inc. // Copyright (C) 2017 ARM Limited. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -125,8 +126,6 @@ enum ArgClass { }; // Mixtures of the above, to help the function tables const ArgClass ClassV1FIOCV = (ArgClass)(ClassV1 | ClassFIO | ClassCV); -const ArgClass ClassV1FOCV = (ArgClass)(ClassV1 | ClassFO | ClassCV); -const ArgClass ClassV1CV = (ArgClass)(ClassV1 | ClassCV); const ArgClass ClassBNS = (ArgClass)(ClassB | ClassNS); const ArgClass ClassRSNS = (ArgClass)(ClassRS | ClassNS); @@ -147,17 +146,21 @@ EProfile EDesktopProfile = static_cast(ENoProfile | ECoreProfile | ECo // Declare pointers to put into the table for versioning. #ifdef GLSLANG_WEB const Versioning* Es300Desktop130 = nullptr; - const Versioning* Es310Desktop430 = nullptr; + const Versioning* Es310Desktop420 = nullptr; +#elif defined(GLSLANG_ANGLE) + const Versioning* Es300Desktop130 = nullptr; + const Versioning* Es310Desktop420 = nullptr; + const Versioning* Es310Desktop450 = nullptr; #else const Versioning Es300Desktop130Version[] = { { EEsProfile, 0, 300, 0, nullptr }, { EDesktopProfile, 0, 130, 0, nullptr }, { EBadProfile } }; const Versioning* Es300Desktop130 = &Es300Desktop130Version[0]; - const Versioning Es310Desktop430Version[] = { { EEsProfile, 0, 310, 0, nullptr }, - { EDesktopProfile, 0, 430, 0, nullptr }, + const Versioning Es310Desktop420Version[] = { { EEsProfile, 0, 310, 0, nullptr }, + { EDesktopProfile, 0, 420, 0, nullptr }, { EBadProfile } }; - const Versioning* Es310Desktop430 = &Es310Desktop430Version[0]; + const Versioning* Es310Desktop420 = &Es310Desktop420Version[0]; const Versioning Es310Desktop450Version[] = { { EEsProfile, 0, 310, 0, nullptr }, { EDesktopProfile, 0, 450, 0, nullptr }, @@ -257,14 +260,14 @@ const BuiltInFunction BaseFunctions[] = { { EOpGreaterThanEqual, "greaterThanEqual", 2, TypeU, ClassBNS, Es300Desktop130 }, { EOpVectorEqual, "equal", 2, TypeU, ClassBNS, Es300Desktop130 }, { EOpVectorNotEqual, "notEqual", 2, TypeU, ClassBNS, Es300Desktop130 }, - { EOpAtomicAdd, "atomicAdd", 2, TypeIU, ClassV1FIOCV, Es310Desktop430 }, - { EOpAtomicMin, "atomicMin", 2, TypeIU, ClassV1FIOCV, Es310Desktop430 }, - { EOpAtomicMax, "atomicMax", 2, TypeIU, ClassV1FIOCV, Es310Desktop430 }, - { EOpAtomicAnd, "atomicAnd", 2, TypeIU, ClassV1FIOCV, Es310Desktop430 }, - { EOpAtomicOr, "atomicOr", 2, TypeIU, ClassV1FIOCV, Es310Desktop430 }, - { EOpAtomicXor, "atomicXor", 2, TypeIU, ClassV1FIOCV, Es310Desktop430 }, - { EOpAtomicExchange, "atomicExchange", 2, TypeIU, ClassV1FIOCV, Es310Desktop430 }, - { EOpAtomicCompSwap, "atomicCompSwap", 3, TypeIU, ClassV1FIOCV, Es310Desktop430 }, + { EOpAtomicAdd, "atomicAdd", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, + { EOpAtomicMin, "atomicMin", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, + { EOpAtomicMax, "atomicMax", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, + { EOpAtomicAnd, "atomicAnd", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, + { EOpAtomicOr, "atomicOr", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, + { EOpAtomicXor, "atomicXor", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, + { EOpAtomicExchange, "atomicExchange", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, + { EOpAtomicCompSwap, "atomicCompSwap", 3, TypeIU, ClassV1FIOCV, Es310Desktop420 }, #ifndef GLSLANG_WEB { EOpMix, "mix", 3, TypeB, ClassRegular, Es310Desktop450 }, { EOpMix, "mix", 3, TypeIU, ClassLB, Es310Desktop450 }, @@ -416,7 +419,7 @@ void AddTabledBuiltin(TString& decls, const BuiltInFunction& function) // See if the tabled versioning information allows the current version. bool ValidVersion(const BuiltInFunction& function, int version, EProfile profile, const SpvVersion& /* spVersion */) { -#ifdef GLSLANG_WEB +#if defined(GLSLANG_WEB) || defined(GLSLANG_ANGLE) // all entries in table are valid return true; #endif @@ -480,7 +483,8 @@ void TBuiltIns::relateTabledBuiltins(int /* version */, EProfile /* profile */, inline bool IncludeLegacy(int version, EProfile profile, const SpvVersion& spvVersion) { - return profile != EEsProfile && (version <= 130 || (spvVersion.spv == 0 && ARBCompatibility) || profile == ECompatibilityProfile); + return profile != EEsProfile && (version <= 130 || (spvVersion.spv == 0 && version == 140 && ARBCompatibility) || + profile == ECompatibilityProfile); } // Construct TBuiltInParseables base class. This can be used for language-common constructs. @@ -500,12 +504,14 @@ TBuiltIns::TBuiltIns() prefixes[EbtFloat] = ""; prefixes[EbtInt] = "i"; prefixes[EbtUint] = "u"; -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) prefixes[EbtFloat16] = "f16"; prefixes[EbtInt8] = "i8"; prefixes[EbtUint8] = "u8"; prefixes[EbtInt16] = "i16"; prefixes[EbtUint16] = "u16"; + prefixes[EbtInt64] = "i64"; + prefixes[EbtUint64] = "u64"; #endif postfixes[2] = "2"; @@ -517,7 +523,9 @@ TBuiltIns::TBuiltIns() dimMap[Esd3D] = 3; dimMap[EsdCube] = 3; #ifndef GLSLANG_WEB +#ifndef GLSLANG_ANGLE dimMap[Esd1D] = 1; +#endif dimMap[EsdRect] = 2; dimMap[EsdBuffer] = 1; dimMap[EsdSubpass] = 2; // potentially unused for now @@ -542,6 +550,9 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV #ifdef GLSLANG_WEB version = 310; profile = EEsProfile; +#elif defined(GLSLANG_ANGLE) + version = 450; + profile = ECoreProfile; #endif addTabledBuiltins(version, profile, spvVersion); @@ -587,6 +598,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 fwidthCoarse(vec4 p);" ); +#ifndef GLSLANG_ANGLE TString derivativesAndControl16bits ( "float16_t dFdx(float16_t);" "f16vec2 dFdx(f16vec2);" @@ -690,7 +702,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV // // double functions added to desktop 4.00, but not fma, frexp, ldexp, or pack/unpack // - if (profile != EEsProfile && version >= 400) { + if (profile != EEsProfile && version >= 150) { // ARB_gpu_shader_fp64 commonBuiltins.append( "double sqrt(double);" @@ -920,7 +932,203 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } - if (profile != EEsProfile && version >= 450) { + if (profile == EEsProfile && version >= 310) { // Explicit Types + commonBuiltins.append( + + "float64_t sqrt(float64_t);" + "f64vec2 sqrt(f64vec2);" + "f64vec3 sqrt(f64vec3);" + "f64vec4 sqrt(f64vec4);" + + "float64_t inversesqrt(float64_t);" + "f64vec2 inversesqrt(f64vec2);" + "f64vec3 inversesqrt(f64vec3);" + "f64vec4 inversesqrt(f64vec4);" + + "float64_t abs(float64_t);" + "f64vec2 abs(f64vec2);" + "f64vec3 abs(f64vec3);" + "f64vec4 abs(f64vec4);" + + "float64_t sign(float64_t);" + "f64vec2 sign(f64vec2);" + "f64vec3 sign(f64vec3);" + "f64vec4 sign(f64vec4);" + + "float64_t floor(float64_t);" + "f64vec2 floor(f64vec2);" + "f64vec3 floor(f64vec3);" + "f64vec4 floor(f64vec4);" + + "float64_t trunc(float64_t);" + "f64vec2 trunc(f64vec2);" + "f64vec3 trunc(f64vec3);" + "f64vec4 trunc(f64vec4);" + + "float64_t round(float64_t);" + "f64vec2 round(f64vec2);" + "f64vec3 round(f64vec3);" + "f64vec4 round(f64vec4);" + + "float64_t roundEven(float64_t);" + "f64vec2 roundEven(f64vec2);" + "f64vec3 roundEven(f64vec3);" + "f64vec4 roundEven(f64vec4);" + + "float64_t ceil(float64_t);" + "f64vec2 ceil(f64vec2);" + "f64vec3 ceil(f64vec3);" + "f64vec4 ceil(f64vec4);" + + "float64_t fract(float64_t);" + "f64vec2 fract(f64vec2);" + "f64vec3 fract(f64vec3);" + "f64vec4 fract(f64vec4);" + + "float64_t mod(float64_t, float64_t);" + "f64vec2 mod(f64vec2 , float64_t);" + "f64vec3 mod(f64vec3 , float64_t);" + "f64vec4 mod(f64vec4 , float64_t);" + "f64vec2 mod(f64vec2 , f64vec2);" + "f64vec3 mod(f64vec3 , f64vec3);" + "f64vec4 mod(f64vec4 , f64vec4);" + + "float64_t modf(float64_t, out float64_t);" + "f64vec2 modf(f64vec2, out f64vec2);" + "f64vec3 modf(f64vec3, out f64vec3);" + "f64vec4 modf(f64vec4, out f64vec4);" + + "float64_t min(float64_t, float64_t);" + "f64vec2 min(f64vec2, float64_t);" + "f64vec3 min(f64vec3, float64_t);" + "f64vec4 min(f64vec4, float64_t);" + "f64vec2 min(f64vec2, f64vec2);" + "f64vec3 min(f64vec3, f64vec3);" + "f64vec4 min(f64vec4, f64vec4);" + + "float64_t max(float64_t, float64_t);" + "f64vec2 max(f64vec2 , float64_t);" + "f64vec3 max(f64vec3 , float64_t);" + "f64vec4 max(f64vec4 , float64_t);" + "f64vec2 max(f64vec2 , f64vec2);" + "f64vec3 max(f64vec3 , f64vec3);" + "f64vec4 max(f64vec4 , f64vec4);" + + "float64_t clamp(float64_t, float64_t, float64_t);" + "f64vec2 clamp(f64vec2 , float64_t, float64_t);" + "f64vec3 clamp(f64vec3 , float64_t, float64_t);" + "f64vec4 clamp(f64vec4 , float64_t, float64_t);" + "f64vec2 clamp(f64vec2 , f64vec2 , f64vec2);" + "f64vec3 clamp(f64vec3 , f64vec3 , f64vec3);" + "f64vec4 clamp(f64vec4 , f64vec4 , f64vec4);" + + "float64_t mix(float64_t, float64_t, float64_t);" + "f64vec2 mix(f64vec2, f64vec2, float64_t);" + "f64vec3 mix(f64vec3, f64vec3, float64_t);" + "f64vec4 mix(f64vec4, f64vec4, float64_t);" + "f64vec2 mix(f64vec2, f64vec2, f64vec2);" + "f64vec3 mix(f64vec3, f64vec3, f64vec3);" + "f64vec4 mix(f64vec4, f64vec4, f64vec4);" + "float64_t mix(float64_t, float64_t, bool);" + "f64vec2 mix(f64vec2, f64vec2, bvec2);" + "f64vec3 mix(f64vec3, f64vec3, bvec3);" + "f64vec4 mix(f64vec4, f64vec4, bvec4);" + + "float64_t step(float64_t, float64_t);" + "f64vec2 step(f64vec2 , f64vec2);" + "f64vec3 step(f64vec3 , f64vec3);" + "f64vec4 step(f64vec4 , f64vec4);" + "f64vec2 step(float64_t, f64vec2);" + "f64vec3 step(float64_t, f64vec3);" + "f64vec4 step(float64_t, f64vec4);" + + "float64_t smoothstep(float64_t, float64_t, float64_t);" + "f64vec2 smoothstep(f64vec2 , f64vec2 , f64vec2);" + "f64vec3 smoothstep(f64vec3 , f64vec3 , f64vec3);" + "f64vec4 smoothstep(f64vec4 , f64vec4 , f64vec4);" + "f64vec2 smoothstep(float64_t, float64_t, f64vec2);" + "f64vec3 smoothstep(float64_t, float64_t, f64vec3);" + "f64vec4 smoothstep(float64_t, float64_t, f64vec4);" + + "float64_t length(float64_t);" + "float64_t length(f64vec2);" + "float64_t length(f64vec3);" + "float64_t length(f64vec4);" + + "float64_t distance(float64_t, float64_t);" + "float64_t distance(f64vec2 , f64vec2);" + "float64_t distance(f64vec3 , f64vec3);" + "float64_t distance(f64vec4 , f64vec4);" + + "float64_t dot(float64_t, float64_t);" + "float64_t dot(f64vec2 , f64vec2);" + "float64_t dot(f64vec3 , f64vec3);" + "float64_t dot(f64vec4 , f64vec4);" + + "f64vec3 cross(f64vec3, f64vec3);" + + "float64_t normalize(float64_t);" + "f64vec2 normalize(f64vec2);" + "f64vec3 normalize(f64vec3);" + "f64vec4 normalize(f64vec4);" + + "float64_t faceforward(float64_t, float64_t, float64_t);" + "f64vec2 faceforward(f64vec2, f64vec2, f64vec2);" + "f64vec3 faceforward(f64vec3, f64vec3, f64vec3);" + "f64vec4 faceforward(f64vec4, f64vec4, f64vec4);" + + "float64_t reflect(float64_t, float64_t);" + "f64vec2 reflect(f64vec2 , f64vec2 );" + "f64vec3 reflect(f64vec3 , f64vec3 );" + "f64vec4 reflect(f64vec4 , f64vec4 );" + + "float64_t refract(float64_t, float64_t, float64_t);" + "f64vec2 refract(f64vec2 , f64vec2 , float64_t);" + "f64vec3 refract(f64vec3 , f64vec3 , float64_t);" + "f64vec4 refract(f64vec4 , f64vec4 , float64_t);" + + "f64mat2 matrixCompMult(f64mat2, f64mat2);" + "f64mat3 matrixCompMult(f64mat3, f64mat3);" + "f64mat4 matrixCompMult(f64mat4, f64mat4);" + "f64mat2x3 matrixCompMult(f64mat2x3, f64mat2x3);" + "f64mat2x4 matrixCompMult(f64mat2x4, f64mat2x4);" + "f64mat3x2 matrixCompMult(f64mat3x2, f64mat3x2);" + "f64mat3x4 matrixCompMult(f64mat3x4, f64mat3x4);" + "f64mat4x2 matrixCompMult(f64mat4x2, f64mat4x2);" + "f64mat4x3 matrixCompMult(f64mat4x3, f64mat4x3);" + + "f64mat2 outerProduct(f64vec2, f64vec2);" + "f64mat3 outerProduct(f64vec3, f64vec3);" + "f64mat4 outerProduct(f64vec4, f64vec4);" + "f64mat2x3 outerProduct(f64vec3, f64vec2);" + "f64mat3x2 outerProduct(f64vec2, f64vec3);" + "f64mat2x4 outerProduct(f64vec4, f64vec2);" + "f64mat4x2 outerProduct(f64vec2, f64vec4);" + "f64mat3x4 outerProduct(f64vec4, f64vec3);" + "f64mat4x3 outerProduct(f64vec3, f64vec4);" + + "f64mat2 transpose(f64mat2);" + "f64mat3 transpose(f64mat3);" + "f64mat4 transpose(f64mat4);" + "f64mat2x3 transpose(f64mat3x2);" + "f64mat3x2 transpose(f64mat2x3);" + "f64mat2x4 transpose(f64mat4x2);" + "f64mat4x2 transpose(f64mat2x4);" + "f64mat3x4 transpose(f64mat4x3);" + "f64mat4x3 transpose(f64mat3x4);" + + "float64_t determinant(f64mat2);" + "float64_t determinant(f64mat3);" + "float64_t determinant(f64mat4);" + + "f64mat2 inverse(f64mat2);" + "f64mat3 inverse(f64mat3);" + "f64mat4 inverse(f64mat4);" + + "\n"); + } + + if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 310)) { commonBuiltins.append( "int64_t abs(int64_t);" @@ -987,25 +1195,25 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "u64vec3 mix(u64vec3, u64vec3, bvec3);" "u64vec4 mix(u64vec4, u64vec4, bvec4);" - "int64_t doubleBitsToInt64(double);" - "i64vec2 doubleBitsToInt64(dvec2);" - "i64vec3 doubleBitsToInt64(dvec3);" - "i64vec4 doubleBitsToInt64(dvec4);" + "int64_t doubleBitsToInt64(float64_t);" + "i64vec2 doubleBitsToInt64(f64vec2);" + "i64vec3 doubleBitsToInt64(f64vec3);" + "i64vec4 doubleBitsToInt64(f64vec4);" - "uint64_t doubleBitsToUint64(double);" - "u64vec2 doubleBitsToUint64(dvec2);" - "u64vec3 doubleBitsToUint64(dvec3);" - "u64vec4 doubleBitsToUint64(dvec4);" + "uint64_t doubleBitsToUint64(float64_t);" + "u64vec2 doubleBitsToUint64(f64vec2);" + "u64vec3 doubleBitsToUint64(f64vec3);" + "u64vec4 doubleBitsToUint64(f64vec4);" - "double int64BitsToDouble(int64_t);" - "dvec2 int64BitsToDouble(i64vec2);" - "dvec3 int64BitsToDouble(i64vec3);" - "dvec4 int64BitsToDouble(i64vec4);" + "float64_t int64BitsToDouble(int64_t);" + "f64vec2 int64BitsToDouble(i64vec2);" + "f64vec3 int64BitsToDouble(i64vec3);" + "f64vec4 int64BitsToDouble(i64vec4);" - "double uint64BitsToDouble(uint64_t);" - "dvec2 uint64BitsToDouble(u64vec2);" - "dvec3 uint64BitsToDouble(u64vec3);" - "dvec4 uint64BitsToDouble(u64vec4);" + "float64_t uint64BitsToDouble(uint64_t);" + "f64vec2 uint64BitsToDouble(u64vec2);" + "f64vec3 uint64BitsToDouble(u64vec3);" + "f64vec4 uint64BitsToDouble(u64vec4);" "int64_t packInt2x32(ivec2);" "uint64_t packUint2x32(uvec2);" @@ -1054,6 +1262,16 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "bvec3 notEqual(u64vec3, u64vec3);" "bvec4 notEqual(u64vec4, u64vec4);" + "int64_t bitCount(int64_t);" + "i64vec2 bitCount(i64vec2);" + "i64vec3 bitCount(i64vec3);" + "i64vec4 bitCount(i64vec4);" + + "int64_t bitCount(uint64_t);" + "i64vec2 bitCount(u64vec2);" + "i64vec3 bitCount(u64vec3);" + "i64vec4 bitCount(u64vec4);" + "int64_t findLSB(int64_t);" "i64vec2 findLSB(i64vec2);" "i64vec3 findLSB(i64vec3);" @@ -1174,6 +1392,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n" ); } +#endif // !GLSLANG_ANGLE if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 430)) { @@ -1211,17 +1430,30 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } +#ifndef GLSLANG_ANGLE if (profile != EEsProfile && version >= 440) { commonBuiltins.append( "uint64_t atomicMin(coherent volatile inout uint64_t, uint64_t);" " int64_t atomicMin(coherent volatile inout int64_t, int64_t);" "uint64_t atomicMin(coherent volatile inout uint64_t, uint64_t, int, int, int);" " int64_t atomicMin(coherent volatile inout int64_t, int64_t, int, int, int);" + "float16_t atomicMin(coherent volatile inout float16_t, float16_t);" + "float16_t atomicMin(coherent volatile inout float16_t, float16_t, int, int, int);" + " float atomicMin(coherent volatile inout float, float);" + " float atomicMin(coherent volatile inout float, float, int, int, int);" + " double atomicMin(coherent volatile inout double, double);" + " double atomicMin(coherent volatile inout double, double, int, int, int);" "uint64_t atomicMax(coherent volatile inout uint64_t, uint64_t);" " int64_t atomicMax(coherent volatile inout int64_t, int64_t);" "uint64_t atomicMax(coherent volatile inout uint64_t, uint64_t, int, int, int);" " int64_t atomicMax(coherent volatile inout int64_t, int64_t, int, int, int);" + "float16_t atomicMax(coherent volatile inout float16_t, float16_t);" + "float16_t atomicMax(coherent volatile inout float16_t, float16_t, int, int, int);" + " float atomicMax(coherent volatile inout float, float);" + " float atomicMax(coherent volatile inout float, float, int, int, int);" + " double atomicMax(coherent volatile inout double, double);" + " double atomicMax(coherent volatile inout double, double, int, int, int);" "uint64_t atomicAnd(coherent volatile inout uint64_t, uint64_t);" " int64_t atomicAnd(coherent volatile inout int64_t, int64_t);" @@ -1242,11 +1474,23 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV " int64_t atomicAdd(coherent volatile inout int64_t, int64_t);" "uint64_t atomicAdd(coherent volatile inout uint64_t, uint64_t, int, int, int);" " int64_t atomicAdd(coherent volatile inout int64_t, int64_t, int, int, int);" + "float16_t atomicAdd(coherent volatile inout float16_t, float16_t);" + "float16_t atomicAdd(coherent volatile inout float16_t, float16_t, int, int, int);" + " float atomicAdd(coherent volatile inout float, float);" + " float atomicAdd(coherent volatile inout float, float, int, int, int);" + " double atomicAdd(coherent volatile inout double, double);" + " double atomicAdd(coherent volatile inout double, double, int, int, int);" "uint64_t atomicExchange(coherent volatile inout uint64_t, uint64_t);" " int64_t atomicExchange(coherent volatile inout int64_t, int64_t);" "uint64_t atomicExchange(coherent volatile inout uint64_t, uint64_t, int, int, int);" " int64_t atomicExchange(coherent volatile inout int64_t, int64_t, int, int, int);" + "float16_t atomicExchange(coherent volatile inout float16_t, float16_t);" + "float16_t atomicExchange(coherent volatile inout float16_t, float16_t, int, int, int);" + " float atomicExchange(coherent volatile inout float, float);" + " float atomicExchange(coherent volatile inout float, float, int, int, int);" + " double atomicExchange(coherent volatile inout double, double);" + " double atomicExchange(coherent volatile inout double, double, int, int, int);" "uint64_t atomicCompSwap(coherent volatile inout uint64_t, uint64_t, uint64_t);" " int64_t atomicCompSwap(coherent volatile inout int64_t, int64_t, int64_t);" @@ -1255,15 +1499,22 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "uint64_t atomicLoad(coherent volatile in uint64_t, int, int, int);" " int64_t atomicLoad(coherent volatile in int64_t, int, int, int);" + "float16_t atomicLoad(coherent volatile in float16_t, int, int, int);" + " float atomicLoad(coherent volatile in float, int, int, int);" + " double atomicLoad(coherent volatile in double, int, int, int);" "void atomicStore(coherent volatile out uint64_t, uint64_t, int, int, int);" "void atomicStore(coherent volatile out int64_t, int64_t, int, int, int);" + "void atomicStore(coherent volatile out float16_t, float16_t, int, int, int);" + "void atomicStore(coherent volatile out float, float, int, int, int);" + "void atomicStore(coherent volatile out double, double, int, int, int);" "\n"); } -#endif +#endif // !GLSLANG_ANGLE +#endif // !GLSLANG_WEB if ((profile == EEsProfile && version >= 300) || - (profile != EEsProfile && version >= 330)) { + (profile != EEsProfile && version >= 150)) { // GL_ARB_shader_bit_encoding commonBuiltins.append( "int floatBitsToInt(highp float value);" "ivec2 floatBitsToInt(highp vec2 value);" @@ -1298,17 +1549,28 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec3 fma(vec3, vec3, vec3 );" "vec4 fma(vec4, vec4, vec4 );" "\n"); + } - if (profile != EEsProfile) { +#ifndef GLSLANG_ANGLE + if (profile != EEsProfile && version >= 150) { // ARB_gpu_shader_fp64 commonBuiltins.append( "double fma(double, double, double);" "dvec2 fma(dvec2, dvec2, dvec2 );" "dvec3 fma(dvec3, dvec3, dvec3 );" "dvec4 fma(dvec4, dvec4, dvec4 );" "\n"); - } } + if (profile == EEsProfile && version >= 310) { // ARB_gpu_shader_fp64 + commonBuiltins.append( + "float64_t fma(float64_t, float64_t, float64_t);" + "f64vec2 fma(f64vec2, f64vec2, f64vec2 );" + "f64vec3 fma(f64vec3, f64vec3, f64vec3 );" + "f64vec4 fma(f64vec4, f64vec4, f64vec4 );" + "\n"); + } +#endif + if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 400)) { commonBuiltins.append( @@ -1325,7 +1587,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } - if (profile != EEsProfile && version >= 400) { +#ifndef GLSLANG_ANGLE + if (profile != EEsProfile && version >= 150) { // ARB_gpu_shader_fp64 commonBuiltins.append( "double frexp(double, out int);" "dvec2 frexp( dvec2, out ivec2);" @@ -1342,10 +1605,26 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + + if (profile == EEsProfile && version >= 310) { // ARB_gpu_shader_fp64 + commonBuiltins.append( + "float64_t frexp(float64_t, out int);" + "f64vec2 frexp( f64vec2, out ivec2);" + "f64vec3 frexp( f64vec3, out ivec3);" + "f64vec4 frexp( f64vec4, out ivec4);" + + "float64_t ldexp(float64_t, int);" + "f64vec2 ldexp( f64vec2, ivec2);" + "f64vec3 ldexp( f64vec3, ivec3);" + "f64vec4 ldexp( f64vec4, ivec4);" + + "\n"); + } +#endif #endif if ((profile == EEsProfile && version >= 300) || - (profile != EEsProfile && version >= 400)) { + (profile != EEsProfile && version >= 150)) { commonBuiltins.append( "highp uint packUnorm2x16(vec2);" "vec2 unpackUnorm2x16(highp uint);" @@ -1353,7 +1632,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV } if ((profile == EEsProfile && version >= 300) || - (profile != EEsProfile && version >= 420)) { + (profile != EEsProfile && version >= 150)) { commonBuiltins.append( "highp uint packSnorm2x16(vec2);" " vec2 unpackSnorm2x16(highp uint);" @@ -1365,7 +1644,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV commonBuiltins.append( "mediump vec2 unpackHalf2x16(highp uint);" "\n"); - } else if (profile != EEsProfile && version >= 420) { + } else if (profile != EEsProfile && version >= 150) { commonBuiltins.append( " vec2 unpackHalf2x16(highp uint);" "\n"); @@ -1373,7 +1652,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV #ifndef GLSLANG_WEB if ((profile == EEsProfile && version >= 310) || - (profile != EEsProfile && version >= 400)) { + (profile != EEsProfile && version >= 150)) { commonBuiltins.append( "highp uint packSnorm4x8(vec4);" "highp uint packUnorm4x8(vec4);" @@ -1385,7 +1664,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "mediump vec4 unpackSnorm4x8(highp uint);" "mediump vec4 unpackUnorm4x8(highp uint);" "\n"); - } else if (profile != EEsProfile && version >= 400) { + } else if (profile != EEsProfile && version >= 150) { commonBuiltins.append( "vec4 unpackSnorm4x8(highp uint);" "vec4 unpackUnorm4x8(highp uint);" @@ -1451,6 +1730,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV } #ifndef GLSLANG_WEB +#ifndef GLSLANG_ANGLE // // Original-style texture functions existing in all stages. // (Per-stage functions below.) @@ -1584,6 +1864,22 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + if (profile != EEsProfile && version == 450) { + commonBuiltins.append( + "uint atomicCounterAddARB(atomic_uint, uint);" + "uint atomicCounterSubtractARB(atomic_uint, uint);" + "uint atomicCounterMinARB(atomic_uint, uint);" + "uint atomicCounterMaxARB(atomic_uint, uint);" + "uint atomicCounterAndARB(atomic_uint, uint);" + "uint atomicCounterOrARB(atomic_uint, uint);" + "uint atomicCounterXorARB(atomic_uint, uint);" + "uint atomicCounterExchangeARB(atomic_uint, uint);" + "uint atomicCounterCompSwapARB(atomic_uint, uint, uint);" + + "\n"); + } + + if (profile != EEsProfile && version >= 460) { commonBuiltins.append( "uint atomicCounterAdd(atomic_uint, uint);" @@ -1599,6 +1895,37 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } } + else if (spvVersion.vulkanRelaxed) { + // + // Atomic counter functions act as aliases to normal atomic functions. + // replace definitions to take 'volatile coherent uint' instead of 'atomic_uint' + // and map to equivalent non-counter atomic op + // + if ((profile != EEsProfile && version >= 300) || + (profile == EEsProfile && version >= 310)) { + commonBuiltins.append( + "uint atomicCounterIncrement(volatile coherent uint);" + "uint atomicCounterDecrement(volatile coherent uint);" + "uint atomicCounter(volatile coherent uint);" + + "\n"); + } + if (profile != EEsProfile && version >= 460) { + commonBuiltins.append( + "uint atomicCounterAdd(volatile coherent uint, uint);" + "uint atomicCounterSubtract(volatile coherent uint, uint);" + "uint atomicCounterMin(volatile coherent uint, uint);" + "uint atomicCounterMax(volatile coherent uint, uint);" + "uint atomicCounterAnd(volatile coherent uint, uint);" + "uint atomicCounterOr(volatile coherent uint, uint);" + "uint atomicCounterXor(volatile coherent uint, uint);" + "uint atomicCounterExchange(volatile coherent uint, uint);" + "uint atomicCounterCompSwap(volatile coherent uint, uint, uint);" + + "\n"); + } + } +#endif // !GLSLANG_ANGLE // Bitfield if ((profile == EEsProfile && version >= 310) || @@ -1741,6 +2068,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } +#ifndef GLSLANG_ANGLE // GL_ARB_shader_ballot if (profile != EEsProfile && version >= 450) { commonBuiltins.append( @@ -3061,9 +3389,29 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "bool textureFootprintGradClampNV(sampler2D, vec2, vec2, vec2, float, int, bool, out gl_TextureFootprint2DNV);" "\n"); } +#endif // !GLSLANG_ANGLE + + if ((profile == EEsProfile && version >= 300 && version < 310) || + (profile != EEsProfile && version >= 150 && version < 450)) { // GL_EXT_shader_integer_mix + commonBuiltins.append("int mix(int, int, bool);" + "ivec2 mix(ivec2, ivec2, bvec2);" + "ivec3 mix(ivec3, ivec3, bvec3);" + "ivec4 mix(ivec4, ivec4, bvec4);" + "uint mix(uint, uint, bool );" + "uvec2 mix(uvec2, uvec2, bvec2);" + "uvec3 mix(uvec3, uvec3, bvec3);" + "uvec4 mix(uvec4, uvec4, bvec4);" + "bool mix(bool, bool, bool );" + "bvec2 mix(bvec2, bvec2, bvec2);" + "bvec3 mix(bvec3, bvec3, bvec3);" + "bvec4 mix(bvec4, bvec4, bvec4);" + + "\n"); + } +#ifndef GLSLANG_ANGLE // GL_AMD_gpu_shader_half_float/Explicit types - if (profile != EEsProfile && version >= 450) { + if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 310)) { commonBuiltins.append( "float16_t radians(float16_t);" "f16vec2 radians(f16vec2);" @@ -3411,7 +3759,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV } // Explicit types - if (profile != EEsProfile && version >= 450) { + if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 310)) { commonBuiltins.append( "int8_t abs(int8_t);" "i8vec2 abs(i8vec2);" @@ -3912,28 +4260,30 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "f64vec3 log2(f64vec3);" "f64vec4 log2(f64vec4);" "\n"); - } - if (profile != EEsProfile && version >= 450) { - stageBuiltins[EShLangFragment].append(derivativesAndControl64bits); - stageBuiltins[EShLangFragment].append( - "float64_t interpolateAtCentroid(float64_t);" - "f64vec2 interpolateAtCentroid(f64vec2);" - "f64vec3 interpolateAtCentroid(f64vec3);" - "f64vec4 interpolateAtCentroid(f64vec4);" + } - "float64_t interpolateAtSample(float64_t, int);" - "f64vec2 interpolateAtSample(f64vec2, int);" - "f64vec3 interpolateAtSample(f64vec3, int);" - "f64vec4 interpolateAtSample(f64vec4, int);" + if (profile != EEsProfile && version >= 450) { + stageBuiltins[EShLangFragment].append(derivativesAndControl64bits); + stageBuiltins[EShLangFragment].append( + "float64_t interpolateAtCentroid(float64_t);" + "f64vec2 interpolateAtCentroid(f64vec2);" + "f64vec3 interpolateAtCentroid(f64vec3);" + "f64vec4 interpolateAtCentroid(f64vec4);" - "float64_t interpolateAtOffset(float64_t, f64vec2);" - "f64vec2 interpolateAtOffset(f64vec2, f64vec2);" - "f64vec3 interpolateAtOffset(f64vec3, f64vec2);" - "f64vec4 interpolateAtOffset(f64vec4, f64vec2);" + "float64_t interpolateAtSample(float64_t, int);" + "f64vec2 interpolateAtSample(f64vec2, int);" + "f64vec3 interpolateAtSample(f64vec3, int);" + "f64vec4 interpolateAtSample(f64vec4, int);" - "\n"); + "float64_t interpolateAtOffset(float64_t, f64vec2);" + "f64vec2 interpolateAtOffset(f64vec2, f64vec2);" + "f64vec3 interpolateAtOffset(f64vec3, f64vec2);" + "f64vec4 interpolateAtOffset(f64vec4, f64vec2);" + + "\n"); } +#endif // !GLSLANG_ANGLE //============================================================================ // @@ -3949,6 +4299,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if (spvVersion.vulkan == 0 && IncludeLegacy(version, profile, spvVersion)) stageBuiltins[EShLangVertex].append("vec4 ftransform();"); +#ifndef GLSLANG_ANGLE // // Original-style texture Functions with lod. // @@ -4008,6 +4359,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } } +#endif // !GLSLANG_ANGLE if ((profile != EEsProfile && version >= 150) || (profile == EEsProfile && version >= 310)) { @@ -4028,7 +4380,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void EndPrimitive();" "\n"); } -#endif +#endif // !GLSLANG_WEB //============================================================================ // @@ -4067,10 +4419,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV } #ifndef GLSLANG_WEB if ((profile != EEsProfile && version >= 420) || esBarrier) { - commonBuiltins.append( - "void memoryBarrierAtomicCounter();" - "void memoryBarrierImage();" - ); + if (spvVersion.vulkan == 0 || spvVersion.vulkanRelaxed) { + commonBuiltins.append("void memoryBarrierAtomicCounter();"); + } + commonBuiltins.append("void memoryBarrierImage();"); } if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { stageBuiltins[EShLangMeshNV].append( @@ -4086,6 +4438,9 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV commonBuiltins.append("void controlBarrier(int, int, int, int);\n" "void memoryBarrier(int, int, int);\n"); + commonBuiltins.append("void debugPrintfEXT();\n"); + +#ifndef GLSLANG_ANGLE if (profile != EEsProfile && version >= 450) { // coopMatStoreNV perhaps ought to have "out" on the buf parameter, but // adding it introduces undesirable tempArgs on the stack. What we want @@ -4209,6 +4564,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } +#endif // !GLSLANG_ANGLE // GL_ARB_derivative_control if (profile != EEsProfile && version >= 400) { @@ -4246,6 +4602,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "bool helperInvocationEXT();" "\n"); +#ifndef GLSLANG_ANGLE // GL_AMD_shader_explicit_vertex_parameter if (profile != EEsProfile && version >= 450) { stageBuiltins[EShLangFragment].append( @@ -4320,37 +4677,75 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } - // Builtins for GL_NV_ray_tracing + // Builtins for GL_NV_ray_tracing/GL_NV_ray_tracing_motion_blur/GL_EXT_ray_tracing/GL_EXT_ray_query if (profile != EEsProfile && version >= 460) { - stageBuiltins[EShLangRayGenNV].append( + commonBuiltins.append("void rayQueryInitializeEXT(rayQueryEXT, accelerationStructureEXT, uint, uint, vec3, float, vec3, float);" + "void rayQueryTerminateEXT(rayQueryEXT);" + "void rayQueryGenerateIntersectionEXT(rayQueryEXT, float);" + "void rayQueryConfirmIntersectionEXT(rayQueryEXT);" + "bool rayQueryProceedEXT(rayQueryEXT);" + "uint rayQueryGetIntersectionTypeEXT(rayQueryEXT, bool);" + "float rayQueryGetRayTMinEXT(rayQueryEXT);" + "uint rayQueryGetRayFlagsEXT(rayQueryEXT);" + "vec3 rayQueryGetWorldRayOriginEXT(rayQueryEXT);" + "vec3 rayQueryGetWorldRayDirectionEXT(rayQueryEXT);" + "float rayQueryGetIntersectionTEXT(rayQueryEXT, bool);" + "int rayQueryGetIntersectionInstanceCustomIndexEXT(rayQueryEXT, bool);" + "int rayQueryGetIntersectionInstanceIdEXT(rayQueryEXT, bool);" + "uint rayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetEXT(rayQueryEXT, bool);" + "int rayQueryGetIntersectionGeometryIndexEXT(rayQueryEXT, bool);" + "int rayQueryGetIntersectionPrimitiveIndexEXT(rayQueryEXT, bool);" + "vec2 rayQueryGetIntersectionBarycentricsEXT(rayQueryEXT, bool);" + "bool rayQueryGetIntersectionFrontFaceEXT(rayQueryEXT, bool);" + "bool rayQueryGetIntersectionCandidateAABBOpaqueEXT(rayQueryEXT);" + "vec3 rayQueryGetIntersectionObjectRayDirectionEXT(rayQueryEXT, bool);" + "vec3 rayQueryGetIntersectionObjectRayOriginEXT(rayQueryEXT, bool);" + "mat4x3 rayQueryGetIntersectionObjectToWorldEXT(rayQueryEXT, bool);" + "mat4x3 rayQueryGetIntersectionWorldToObjectEXT(rayQueryEXT, bool);" + "\n"); + + stageBuiltins[EShLangRayGen].append( "void traceNV(accelerationStructureNV,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" + "void traceRayMotionNV(accelerationStructureNV,uint,uint,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void traceRayEXT(accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" "void executeCallableNV(uint, int);" + "void executeCallableEXT(uint, int);" "\n"); - stageBuiltins[EShLangIntersectNV].append( + stageBuiltins[EShLangIntersect].append( "bool reportIntersectionNV(float, uint);" + "bool reportIntersectionEXT(float, uint);" "\n"); - stageBuiltins[EShLangAnyHitNV].append( + stageBuiltins[EShLangAnyHit].append( "void ignoreIntersectionNV();" "void terminateRayNV();" "\n"); - stageBuiltins[EShLangClosestHitNV].append( + stageBuiltins[EShLangClosestHit].append( "void traceNV(accelerationStructureNV,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" + "void traceRayMotionNV(accelerationStructureNV,uint,uint,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void traceRayEXT(accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" "void executeCallableNV(uint, int);" + "void executeCallableEXT(uint, int);" "\n"); - stageBuiltins[EShLangMissNV].append( + stageBuiltins[EShLangMiss].append( "void traceNV(accelerationStructureNV,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" + "void traceRayMotionNV(accelerationStructureNV,uint,uint,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void traceRayEXT(accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" "void executeCallableNV(uint, int);" + "void executeCallableEXT(uint, int);" "\n"); - stageBuiltins[EShLangCallableNV].append( + stageBuiltins[EShLangCallable].append( "void executeCallableNV(uint, int);" + "void executeCallableEXT(uint, int);" "\n"); } +#endif // !GLSLANG_ANGLE //E_SPV_NV_compute_shader_derivatives if ((profile == EEsProfile && version >= 320) || (profile != EEsProfile && version >= 450)) { stageBuiltins[EShLangCompute].append(derivativeControls); stageBuiltins[EShLangCompute].append("\n"); } +#ifndef GLSLANG_ANGLE if (profile != EEsProfile && version >= 450) { stageBuiltins[EShLangCompute].append(derivativesAndControl16bits); stageBuiltins[EShLangCompute].append(derivativesAndControl64bits); @@ -4363,7 +4758,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void writePackedPrimitiveIndices4x8NV(uint, uint);" "\n"); } -#endif +#endif // !GLSLANG_ANGLE +#endif // !GLSLANG_WEB //============================================================================ // @@ -4400,7 +4796,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) if (spvVersion.spv == 0 && IncludeLegacy(version, profile, spvVersion)) { // // Matrix state. p. 31, 32, 37, 39, 40. @@ -4518,7 +4914,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#endif +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE //============================================================================ // @@ -4549,6 +4945,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV } #ifndef GLSLANG_WEB +#ifndef GLSLANG_ANGLE //============================================================================ // // Define the interface to the mesh/task shader. @@ -4636,6 +5033,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } } +#endif // !GLSLANG_ANGLE //============================================================================ // @@ -4748,6 +5146,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in int gl_VertexIndex;" "in int gl_InstanceIndex;" ); + + if (spvVersion.vulkan > 0 && version >= 140 && spvVersion.vulkanRelaxed) + stageBuiltins[EShLangVertex].append( + "in int gl_VertexID;" // declare with 'in' qualifier + "in int gl_InstanceID;" + ); + if (version >= 440) { stageBuiltins[EShLangVertex].append( "in int gl_BaseVertexARB;" @@ -4785,7 +5190,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "mediump float gl_PointSize;" // needs qualifier fixed later ); } else { - if (spvVersion.vulkan == 0) + if (spvVersion.vulkan == 0 || spvVersion.vulkanRelaxed) stageBuiltins[EShLangVertex].append( "in highp int gl_VertexID;" // needs qualifier fixed later "in highp int gl_InstanceID;" // needs qualifier fixed later @@ -4828,6 +5233,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangVertex].append( + "out highp int gl_PrimitiveShadingRateEXT;" // GL_EXT_fragment_shading_rate + "\n"); + } //============================================================================ // @@ -4941,6 +5351,12 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangGeometry].append( + "out highp int gl_PrimitiveShadingRateEXT;" // GL_EXT_fragment_shading_rate + "\n"); + } + //============================================================================ // // Define the interface to the tessellation control shader. @@ -5238,6 +5654,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in vec3 gl_BaryCoordNoPerspNV;" ); + if (version >= 450) + stageBuiltins[EShLangFragment].append( + "flat in int gl_ShadingRateEXT;" // GL_EXT_fragment_shading_rate + ); + } else { // ES profile @@ -5296,6 +5717,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in vec3 gl_BaryCoordNV;" "in vec3 gl_BaryCoordNoPerspNV;" ); + if (version >= 310) + stageBuiltins[EShLangFragment].append( + "flat in highp int gl_ShadingRateEXT;" // GL_EXT_fragment_shading_rate + ); } #endif @@ -5306,6 +5731,21 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV #ifndef GLSLANG_WEB + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + stageBuiltins[EShLangFragment].append( + "flat in highp int gl_DeviceIndex;" // GL_EXT_device_group + "flat in highp int gl_ViewIndex;" // GL_EXT_multiview + "\n"); + } + + if (version >= 300 /* both ES and non-ES */) { + stageBuiltins[EShLangFragment].append( + "flat in highp uint gl_ViewID_OVR;" // GL_OVR_multiview, GL_OVR_multiview2 + "\n"); + } + +#ifndef GLSLANG_ANGLE // GL_ARB_shader_ballot if (profile != EEsProfile && version >= 450) { const char* ballotDecls = @@ -5317,6 +5757,15 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in uint64_t gl_SubGroupLeMaskARB;" "in uint64_t gl_SubGroupLtMaskARB;" "\n"; + const char* rtBallotDecls = + "uniform volatile uint gl_SubGroupSizeARB;" + "in volatile uint gl_SubGroupInvocationARB;" + "in volatile uint64_t gl_SubGroupEqMaskARB;" + "in volatile uint64_t gl_SubGroupGeMaskARB;" + "in volatile uint64_t gl_SubGroupGtMaskARB;" + "in volatile uint64_t gl_SubGroupLeMaskARB;" + "in volatile uint64_t gl_SubGroupLtMaskARB;" + "\n"; const char* fragmentBallotDecls = "uniform uint gl_SubGroupSizeARB;" "flat in uint gl_SubGroupInvocationARB;" @@ -5334,14 +5783,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangFragment] .append(fragmentBallotDecls); stageBuiltins[EShLangMeshNV] .append(ballotDecls); stageBuiltins[EShLangTaskNV] .append(ballotDecls); - } - - if ((profile != EEsProfile && version >= 140) || - (profile == EEsProfile && version >= 310)) { - stageBuiltins[EShLangFragment].append( - "flat in highp int gl_DeviceIndex;" // GL_EXT_device_group - "flat in highp int gl_ViewIndex;" // GL_EXT_multiview - "\n"); + stageBuiltins[EShLangRayGen] .append(rtBallotDecls); + stageBuiltins[EShLangIntersect] .append(rtBallotDecls); + // No volatile qualifier on these builtins in any-hit + stageBuiltins[EShLangAnyHit] .append(ballotDecls); + stageBuiltins[EShLangClosestHit] .append(rtBallotDecls); + stageBuiltins[EShLangMiss] .append(rtBallotDecls); + stageBuiltins[EShLangCallable] .append(rtBallotDecls); } // GL_KHR_shader_subgroup @@ -5379,6 +5827,21 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in highp uint gl_NumSubgroups;" "in highp uint gl_SubgroupID;" "\n"; + // These builtins are volatile for RT stages + const char* rtSubgroupDecls = + "in mediump volatile uint gl_SubgroupSize;" + "in mediump volatile uint gl_SubgroupInvocationID;" + "in highp volatile uvec4 gl_SubgroupEqMask;" + "in highp volatile uvec4 gl_SubgroupGeMask;" + "in highp volatile uvec4 gl_SubgroupGtMask;" + "in highp volatile uvec4 gl_SubgroupLeMask;" + "in highp volatile uvec4 gl_SubgroupLtMask;" + // GL_NV_shader_sm_builtins + "in highp uint gl_WarpsPerSMNV;" + "in highp uint gl_SMCountNV;" + "in highp volatile uint gl_WarpIDNV;" + "in highp volatile uint gl_SMIDNV;" + "\n"; stageBuiltins[EShLangVertex] .append(subgroupDecls); stageBuiltins[EShLangTessControl] .append(subgroupDecls); @@ -5391,118 +5854,177 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangMeshNV] .append(computeSubgroupDecls); stageBuiltins[EShLangTaskNV] .append(subgroupDecls); stageBuiltins[EShLangTaskNV] .append(computeSubgroupDecls); - stageBuiltins[EShLangRayGenNV] .append(subgroupDecls); - stageBuiltins[EShLangIntersectNV] .append(subgroupDecls); - stageBuiltins[EShLangAnyHitNV] .append(subgroupDecls); - stageBuiltins[EShLangClosestHitNV] .append(subgroupDecls); - stageBuiltins[EShLangMissNV] .append(subgroupDecls); - stageBuiltins[EShLangCallableNV] .append(subgroupDecls); + stageBuiltins[EShLangRayGen] .append(rtSubgroupDecls); + stageBuiltins[EShLangIntersect] .append(rtSubgroupDecls); + // No volatile qualifier on these builtins in any-hit + stageBuiltins[EShLangAnyHit] .append(subgroupDecls); + stageBuiltins[EShLangClosestHit] .append(rtSubgroupDecls); + stageBuiltins[EShLangMiss] .append(rtSubgroupDecls); + stageBuiltins[EShLangCallable] .append(rtSubgroupDecls); } - // GL_NV_ray_tracing + // GL_NV_ray_tracing/GL_EXT_ray_tracing if (profile != EEsProfile && version >= 460) { const char *constRayFlags = "const uint gl_RayFlagsNoneNV = 0U;" + "const uint gl_RayFlagsNoneEXT = 0U;" "const uint gl_RayFlagsOpaqueNV = 1U;" + "const uint gl_RayFlagsOpaqueEXT = 1U;" "const uint gl_RayFlagsNoOpaqueNV = 2U;" + "const uint gl_RayFlagsNoOpaqueEXT = 2U;" "const uint gl_RayFlagsTerminateOnFirstHitNV = 4U;" + "const uint gl_RayFlagsTerminateOnFirstHitEXT = 4U;" "const uint gl_RayFlagsSkipClosestHitShaderNV = 8U;" + "const uint gl_RayFlagsSkipClosestHitShaderEXT = 8U;" "const uint gl_RayFlagsCullBackFacingTrianglesNV = 16U;" + "const uint gl_RayFlagsCullBackFacingTrianglesEXT = 16U;" "const uint gl_RayFlagsCullFrontFacingTrianglesNV = 32U;" + "const uint gl_RayFlagsCullFrontFacingTrianglesEXT = 32U;" "const uint gl_RayFlagsCullOpaqueNV = 64U;" + "const uint gl_RayFlagsCullOpaqueEXT = 64U;" "const uint gl_RayFlagsCullNoOpaqueNV = 128U;" + "const uint gl_RayFlagsCullNoOpaqueEXT = 128U;" + "const uint gl_RayFlagsSkipTrianglesEXT = 256U;" + "const uint gl_RayFlagsSkipAABBEXT = 512U;" + "const uint gl_HitKindFrontFacingTriangleEXT = 254U;" + "const uint gl_HitKindBackFacingTriangleEXT = 255U;" + "\n"; + + const char *constRayQueryIntersection = + "const uint gl_RayQueryCandidateIntersectionEXT = 0U;" + "const uint gl_RayQueryCommittedIntersectionEXT = 1U;" + "const uint gl_RayQueryCommittedIntersectionNoneEXT = 0U;" + "const uint gl_RayQueryCommittedIntersectionTriangleEXT = 1U;" + "const uint gl_RayQueryCommittedIntersectionGeneratedEXT = 2U;" + "const uint gl_RayQueryCandidateIntersectionTriangleEXT = 0U;" + "const uint gl_RayQueryCandidateIntersectionAABBEXT = 1U;" "\n"; + const char *rayGenDecls = "in uvec3 gl_LaunchIDNV;" + "in uvec3 gl_LaunchIDEXT;" "in uvec3 gl_LaunchSizeNV;" + "in uvec3 gl_LaunchSizeEXT;" "\n"; const char *intersectDecls = "in uvec3 gl_LaunchIDNV;" + "in uvec3 gl_LaunchIDEXT;" "in uvec3 gl_LaunchSizeNV;" + "in uvec3 gl_LaunchSizeEXT;" "in int gl_PrimitiveID;" "in int gl_InstanceID;" "in int gl_InstanceCustomIndexNV;" + "in int gl_InstanceCustomIndexEXT;" + "in int gl_GeometryIndexEXT;" "in vec3 gl_WorldRayOriginNV;" + "in vec3 gl_WorldRayOriginEXT;" "in vec3 gl_WorldRayDirectionNV;" + "in vec3 gl_WorldRayDirectionEXT;" "in vec3 gl_ObjectRayOriginNV;" + "in vec3 gl_ObjectRayOriginEXT;" "in vec3 gl_ObjectRayDirectionNV;" + "in vec3 gl_ObjectRayDirectionEXT;" "in float gl_RayTminNV;" + "in float gl_RayTminEXT;" "in float gl_RayTmaxNV;" + "in volatile float gl_RayTmaxEXT;" "in mat4x3 gl_ObjectToWorldNV;" + "in mat4x3 gl_ObjectToWorldEXT;" + "in mat3x4 gl_ObjectToWorld3x4EXT;" "in mat4x3 gl_WorldToObjectNV;" + "in mat4x3 gl_WorldToObjectEXT;" + "in mat3x4 gl_WorldToObject3x4EXT;" "in uint gl_IncomingRayFlagsNV;" + "in uint gl_IncomingRayFlagsEXT;" + "in float gl_CurrentRayTimeNV;" "\n"; const char *hitDecls = "in uvec3 gl_LaunchIDNV;" + "in uvec3 gl_LaunchIDEXT;" "in uvec3 gl_LaunchSizeNV;" + "in uvec3 gl_LaunchSizeEXT;" "in int gl_PrimitiveID;" "in int gl_InstanceID;" "in int gl_InstanceCustomIndexNV;" + "in int gl_InstanceCustomIndexEXT;" + "in int gl_GeometryIndexEXT;" "in vec3 gl_WorldRayOriginNV;" + "in vec3 gl_WorldRayOriginEXT;" "in vec3 gl_WorldRayDirectionNV;" + "in vec3 gl_WorldRayDirectionEXT;" "in vec3 gl_ObjectRayOriginNV;" + "in vec3 gl_ObjectRayOriginEXT;" "in vec3 gl_ObjectRayDirectionNV;" + "in vec3 gl_ObjectRayDirectionEXT;" "in float gl_RayTminNV;" + "in float gl_RayTminEXT;" "in float gl_RayTmaxNV;" + "in float gl_RayTmaxEXT;" "in float gl_HitTNV;" + "in float gl_HitTEXT;" "in uint gl_HitKindNV;" + "in uint gl_HitKindEXT;" "in mat4x3 gl_ObjectToWorldNV;" + "in mat4x3 gl_ObjectToWorldEXT;" + "in mat3x4 gl_ObjectToWorld3x4EXT;" "in mat4x3 gl_WorldToObjectNV;" + "in mat4x3 gl_WorldToObjectEXT;" + "in mat3x4 gl_WorldToObject3x4EXT;" "in uint gl_IncomingRayFlagsNV;" + "in uint gl_IncomingRayFlagsEXT;" + "in float gl_CurrentRayTimeNV;" "\n"; const char *missDecls = "in uvec3 gl_LaunchIDNV;" + "in uvec3 gl_LaunchIDEXT;" "in uvec3 gl_LaunchSizeNV;" + "in uvec3 gl_LaunchSizeEXT;" "in vec3 gl_WorldRayOriginNV;" + "in vec3 gl_WorldRayOriginEXT;" "in vec3 gl_WorldRayDirectionNV;" + "in vec3 gl_WorldRayDirectionEXT;" "in vec3 gl_ObjectRayOriginNV;" "in vec3 gl_ObjectRayDirectionNV;" "in float gl_RayTminNV;" + "in float gl_RayTminEXT;" "in float gl_RayTmaxNV;" + "in float gl_RayTmaxEXT;" "in uint gl_IncomingRayFlagsNV;" + "in uint gl_IncomingRayFlagsEXT;" + "in float gl_CurrentRayTimeNV;" "\n"; const char *callableDecls = "in uvec3 gl_LaunchIDNV;" + "in uvec3 gl_LaunchIDEXT;" "in uvec3 gl_LaunchSizeNV;" + "in uvec3 gl_LaunchSizeEXT;" "\n"; - stageBuiltins[EShLangRayGenNV].append(rayGenDecls); - stageBuiltins[EShLangRayGenNV].append(constRayFlags); - stageBuiltins[EShLangIntersectNV].append(intersectDecls); - stageBuiltins[EShLangIntersectNV].append(constRayFlags); + commonBuiltins.append(constRayQueryIntersection); + commonBuiltins.append(constRayFlags); - stageBuiltins[EShLangAnyHitNV].append(hitDecls); - stageBuiltins[EShLangAnyHitNV].append(constRayFlags); - - stageBuiltins[EShLangClosestHitNV].append(hitDecls); - stageBuiltins[EShLangClosestHitNV].append(constRayFlags); - - stageBuiltins[EShLangMissNV].append(missDecls); - stageBuiltins[EShLangMissNV].append(constRayFlags); - - stageBuiltins[EShLangCallableNV].append(callableDecls); - stageBuiltins[EShLangCallableNV].append(constRayFlags); + stageBuiltins[EShLangRayGen].append(rayGenDecls); + stageBuiltins[EShLangIntersect].append(intersectDecls); + stageBuiltins[EShLangAnyHit].append(hitDecls); + stageBuiltins[EShLangClosestHit].append(hitDecls); + stageBuiltins[EShLangMiss].append(missDecls); + stageBuiltins[EShLangCallable].append(callableDecls); } + if ((profile != EEsProfile && version >= 140)) { const char *deviceIndex = "in highp int gl_DeviceIndex;" // GL_EXT_device_group "\n"; - stageBuiltins[EShLangRayGenNV].append(deviceIndex); - stageBuiltins[EShLangIntersectNV].append(deviceIndex); - stageBuiltins[EShLangAnyHitNV].append(deviceIndex); - stageBuiltins[EShLangClosestHitNV].append(deviceIndex); - stageBuiltins[EShLangMissNV].append(deviceIndex); - } - - if (version >= 300 /* both ES and non-ES */) { - stageBuiltins[EShLangFragment].append( - "flat in highp uint gl_ViewID_OVR;" // GL_OVR_multiview, GL_OVR_multiview2 - "\n"); + stageBuiltins[EShLangRayGen].append(deviceIndex); + stageBuiltins[EShLangIntersect].append(deviceIndex); + stageBuiltins[EShLangAnyHit].append(deviceIndex); + stageBuiltins[EShLangClosestHit].append(deviceIndex); + stageBuiltins[EShLangMiss].append(deviceIndex); } if ((profile != EEsProfile && version >= 420) || @@ -5512,6 +6034,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV commonBuiltins.append("const int gl_ScopeSubgroup = 3;\n"); commonBuiltins.append("const int gl_ScopeInvocation = 4;\n"); commonBuiltins.append("const int gl_ScopeQueueFamily = 5;\n"); + commonBuiltins.append("const int gl_ScopeShaderCallEXT = 6;\n"); commonBuiltins.append("const int gl_SemanticsRelaxed = 0x0;\n"); commonBuiltins.append("const int gl_SemanticsAcquire = 0x2;\n"); @@ -5527,7 +6050,59 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV commonBuiltins.append("const int gl_StorageSemanticsImage = 0x800;\n"); commonBuiltins.append("const int gl_StorageSemanticsOutput = 0x1000;\n"); } -#endif + + // Adding these to common built-ins triggers an assert due to a memory corruption in related code when testing + // So instead add to each stage individually, avoiding the GLSLang bug + if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 310)) { + for (int stage=EShLangVertex; stage(stage)].append("const highp int gl_ShadingRateFlag2VerticalPixelsEXT = 1;\n"); + stageBuiltins[static_cast(stage)].append("const highp int gl_ShadingRateFlag4VerticalPixelsEXT = 2;\n"); + stageBuiltins[static_cast(stage)].append("const highp int gl_ShadingRateFlag2HorizontalPixelsEXT = 4;\n"); + stageBuiltins[static_cast(stage)].append("const highp int gl_ShadingRateFlag4HorizontalPixelsEXT = 8;\n"); + } + } + + // GL_EXT_shader_image_int64 + if ((profile != EEsProfile && version >= 420) || + (profile == EEsProfile && version >= 310)) { + + const TBasicType bTypes[] = { EbtInt64, EbtUint64 }; + for (int ms = 0; ms <= 1; ++ms) { // loop over "bool" multisample or not + for (int arrayed = 0; arrayed <= 1; ++arrayed) { // loop over "bool" arrayed or not + for (int dim = Esd1D; dim < EsdSubpass; ++dim) { // 1D, ..., buffer + if ((dim == Esd1D || dim == EsdRect) && profile == EEsProfile) + continue; + + if ((dim == Esd3D || dim == EsdRect || dim == EsdBuffer) && arrayed) + continue; + + if (dim != Esd2D && ms) + continue; + + // Loop over the bTypes + for (size_t bType = 0; bType < sizeof(bTypes)/sizeof(TBasicType); ++bType) { + // + // Now, make all the function prototypes for the type we just built... + // + TSampler sampler; + + sampler.setImage(bTypes[bType], (TSamplerDim)dim, arrayed ? true : false, + false, + ms ? true : false); + + TString typeName = sampler.getString(); + + addQueryFunctions(sampler, typeName, version, profile); + addImageFunctions(sampler, typeName, version, profile); + } + } + } + } + } +#endif // !GLSLANG_ANGLE + +#endif // !GLSLANG_WEB // printf("%s\n", commonBuiltins.c_str()); // printf("%s\n", stageBuiltins[EShLangFragment].c_str()); @@ -5545,13 +6120,16 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c // // enumerate all the types + const TBasicType bTypes[] = { EbtFloat, EbtInt, EbtUint, +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + EbtFloat16 +#endif + }; #ifdef GLSLANG_WEB - const TBasicType bTypes[] = { EbtFloat, EbtInt, EbtUint }; bool skipBuffer = true; bool skipCubeArrayed = true; const int image = 0; #else - const TBasicType bTypes[] = { EbtFloat, EbtInt, EbtUint, EbtFloat16 }; bool skipBuffer = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 140); bool skipCubeArrayed = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 130); for (int image = 0; image <= 1; ++image) // loop over "bool" image vs sampler @@ -5576,8 +6154,12 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c for (int arrayed = 0; arrayed <= 1; ++arrayed) { // loop over "bool" arrayed or not #ifdef GLSLANG_WEB for (int dim = Esd2D; dim <= EsdCube; ++dim) { // 2D, 3D, and Cube +#else +#if defined(GLSLANG_ANGLE) + for (int dim = Esd2D; dim < EsdNumDims; ++dim) { // 2D, ..., buffer, subpass #else for (int dim = Esd1D; dim < EsdNumDims; ++dim) { // 1D, ..., buffer, subpass +#endif if (dim == EsdSubpass && spvVersion.vulkan == 0) continue; if (dim == EsdSubpass && (image || shadow || arrayed)) @@ -5616,7 +6198,6 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c #endif if (shadow && (bTypes[bType] == EbtInt || bTypes[bType] == EbtUint)) continue; - // // Now, make all the function prototypes for the type we just built... // @@ -5708,7 +6289,7 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, const TString& typeName, int return; #endif - if (sampler.isImage() && ((profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 430))) + if (sampler.isImage() && ((profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 420))) return; if (profile == EEsProfile) @@ -5747,9 +6328,9 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, const TString& typeName, int // // textureQueryLod(), fragment stage only - // + // Also enabled with extension GL_ARB_texture_query_lod - if (profile != EEsProfile && version >= 400 && sampler.isCombined() && sampler.dim != EsdRect && + if (profile != EEsProfile && version >= 150 && sampler.isCombined() && sampler.dim != EsdRect && ! sampler.isMultiSample() && ! sampler.isBuffer()) { for (int f16TexAddr = 0; f16TexAddr < 2; ++f16TexAddr) { if (f16TexAddr && sampler.type != EbtFloat16) @@ -5841,8 +6422,16 @@ void TBuiltIns::addImageFunctions(TSampler sampler, const TString& typeName, int if ( profile != EEsProfile || (profile == EEsProfile && version >= 310)) { - if (sampler.type == EbtInt || sampler.type == EbtUint) { - const char* dataType = sampler.type == EbtInt ? "highp int" : "highp uint"; + if (sampler.type == EbtInt || sampler.type == EbtUint || sampler.type == EbtInt64 || sampler.type == EbtUint64 ) { + + const char* dataType; + switch (sampler.type) { + case(EbtInt): dataType = "highp int"; break; + case(EbtUint): dataType = "highp uint"; break; + case(EbtInt64): dataType = "highp int64_t"; break; + case(EbtUint64): dataType = "highp uint64_t"; break; + default: dataType = ""; + } const int numBuiltins = 7; @@ -5898,11 +6487,56 @@ void TBuiltIns::addImageFunctions(TSampler sampler, const TString& typeName, int // not int or uint // GL_ARB_ES3_1_compatibility // TODO: spec issue: are there restrictions on the kind of layout() that can be used? what about dropping memory qualifiers? - if ((profile != EEsProfile && version >= 450) || - (profile == EEsProfile && version >= 310)) { + if (profile == EEsProfile && version >= 310) { + commonBuiltins.append("float imageAtomicExchange(volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float);\n"); + } + if (profile != EEsProfile && version >= 450) { + commonBuiltins.append("float imageAtomicAdd(volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float);\n"); + + commonBuiltins.append("float imageAtomicAdd(volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float"); + commonBuiltins.append(", int, int, int);\n"); + commonBuiltins.append("float imageAtomicExchange(volatile coherent "); commonBuiltins.append(imageParams); commonBuiltins.append(", float);\n"); + + commonBuiltins.append("float imageAtomicExchange(volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float"); + commonBuiltins.append(", int, int, int);\n"); + + commonBuiltins.append("float imageAtomicLoad(readonly volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", int, int, int);\n"); + + commonBuiltins.append("void imageAtomicStore(writeonly volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float"); + commonBuiltins.append(", int, int, int);\n"); + + commonBuiltins.append("float imageAtomicMin(volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float);\n"); + + commonBuiltins.append("float imageAtomicMin(volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float"); + commonBuiltins.append(", int, int, int);\n"); + + commonBuiltins.append("float imageAtomicMax(volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float);\n"); + + commonBuiltins.append("float imageAtomicMax(volatile coherent "); + commonBuiltins.append(imageParams); + commonBuiltins.append(", float"); + commonBuiltins.append(", int, int, int);\n"); } } } @@ -5971,6 +6605,9 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, #ifdef GLSLANG_WEB profile = EEsProfile; version = 310; +#elif defined(GLSLANG_ANGLE) + profile = ECoreProfile; + version = 450; #endif // @@ -6047,7 +6684,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, continue; // loop over 16-bit floating-point texel addressing -#ifdef GLSLANG_WEB +#if defined(GLSLANG_WEB) || defined(GLSLANG_ANGLE) const int f16TexAddr = 0; #else for (int f16TexAddr = 0; f16TexAddr <= 1; ++f16TexAddr) @@ -6060,7 +6697,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, totalDims--; } // loop over "bool" lod clamp -#ifdef GLSLANG_WEB +#if defined(GLSLANG_WEB) || defined(GLSLANG_ANGLE) const int lodClamp = 0; #else for (int lodClamp = 0; lodClamp <= 1 ;++lodClamp) @@ -6072,7 +6709,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, continue; // loop over "bool" sparse or not -#ifdef GLSLANG_WEB +#if defined(GLSLANG_WEB) || defined(GLSLANG_ANGLE) const int sparse = 0; #else for (int sparse = 0; sparse <= 1; ++sparse) @@ -6127,7 +6764,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, s.append("Offset"); if (lodClamp) s.append("Clamp"); - if (lodClamp || sparse) + if (lodClamp != 0 || sparse) s.append("ARB"); s.append("("); @@ -6227,7 +6864,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, s.append(");\n"); // Add to the per-language set of built-ins - if (bias || lodClamp) { + if (!grad && (bias || lodClamp != 0)) { stageBuiltins[EShLangFragment].append(s); stageBuiltins[EShLangCompute].append(s); } else @@ -6256,6 +6893,9 @@ void TBuiltIns::addGatherFunctions(TSampler sampler, const TString& typeName, in #ifdef GLSLANG_WEB profile = EEsProfile; version = 310; +#elif defined(GLSLANG_ANGLE) + profile = ECoreProfile; + version = 450; #endif switch (sampler.dim) { @@ -6499,6 +7139,9 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf #ifdef GLSLANG_WEB version = 310; profile = EEsProfile; +#elif defined(GLSLANG_ANGLE) + version = 450; + profile = ECoreProfile; #endif // @@ -6624,9 +7267,49 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf } } + if (version >= 320) { + // tessellation + + snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlImageUniforms = %d;", resources.maxTessControlImageUniforms); + s.append(builtInConstant); + snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationImageUniforms = %d;", resources.maxTessEvaluationImageUniforms); + s.append(builtInConstant); + snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlAtomicCounters = %d;", resources.maxTessControlAtomicCounters); + s.append(builtInConstant); + snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationAtomicCounters = %d;", resources.maxTessEvaluationAtomicCounters); + s.append(builtInConstant); + snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlAtomicCounterBuffers = %d;", resources.maxTessControlAtomicCounterBuffers); + s.append(builtInConstant); + snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationAtomicCounterBuffers = %d;", resources.maxTessEvaluationAtomicCounterBuffers); + s.append(builtInConstant); + } + + if (version >= 100) { + // GL_EXT_blend_func_extended + snprintf(builtInConstant, maxSize, "const mediump int gl_MaxDualSourceDrawBuffersEXT = %d;", resources.maxDualSourceDrawBuffersEXT); + s.append(builtInConstant); + // this is here instead of with the others in initialize(version, profile) due to the dependence on gl_MaxDualSourceDrawBuffersEXT + if (language == EShLangFragment) { + s.append( + "mediump vec4 gl_SecondaryFragColorEXT;" + "mediump vec4 gl_SecondaryFragDataEXT[gl_MaxDualSourceDrawBuffersEXT];" + "\n"); + } + } } else { // non-ES profile + if (version > 400) { + snprintf(builtInConstant, maxSize, "const int gl_MaxVertexUniformVectors = %d;", resources.maxVertexUniformVectors); + s.append(builtInConstant); + + snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentUniformVectors = %d;", resources.maxFragmentUniformVectors); + s.append(builtInConstant); + + snprintf(builtInConstant, maxSize, "const int gl_MaxVaryingVectors = %d;", resources.maxVaryingVectors); + s.append(builtInConstant); + } + snprintf(builtInConstant, maxSize, "const int gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs); s.append(builtInConstant); @@ -6657,7 +7340,8 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf snprintf(builtInConstant, maxSize, "const int gl_MaxVertexUniformComponents = %d;", resources.maxVertexUniformComponents); s.append(builtInConstant); - if (version < 150 || ARBCompatibility) { + // Moved from just being deprecated into compatibility profile only as of 4.20 + if (version < 420 || profile == ECompatibilityProfile) { snprintf(builtInConstant, maxSize, "const int gl_MaxVaryingFloats = %d;", resources.maxVaryingFloats); s.append(builtInConstant); } @@ -6890,6 +7574,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append("\n"); } +#ifndef GLSLANG_ANGLE // atomic counters (some in compute below) if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 420)) { @@ -6926,6 +7611,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append("\n"); } +#endif // !GLSLANG_ANGLE // GL_ARB_cull_distance if (profile != EEsProfile && version >= 450) { @@ -6942,6 +7628,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append(builtInConstant); } +#ifndef GLSLANG_ANGLE // SPV_NV_mesh_shader if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { snprintf(builtInConstant, maxSize, "const int gl_MaxMeshOutputVerticesNV = %d;", resources.maxMeshOutputVerticesNV); @@ -6964,6 +7651,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append("\n"); } +#endif #endif s.append("\n"); @@ -7048,6 +7736,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion #ifdef GLSLANG_WEB version = 310; profile = EEsProfile; +#elif defined(GLSLANG_ANGLE) + version = 450; + profile = ECoreProfile; #endif // @@ -7075,6 +7766,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion SpecialQualifier("gl_InstanceID", EvqInstanceId, EbvInstanceId, symbolTable); } + if (spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) { + // treat these built-ins as aliases of VertexIndex and InstanceIndex + BuiltInVariable("gl_VertexID", EbvVertexIndex, symbolTable); + BuiltInVariable("gl_InstanceID", EbvInstanceIndex, symbolTable); + } + if (profile != EEsProfile) { if (version >= 440) { symbolTable.setVariableExtensions("gl_BaseVertexARB", 1, &E_GL_ARB_shader_draw_parameters); @@ -7237,7 +7934,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion case EShLangTessEvaluation: case EShLangGeometry: -#endif +#endif // !GLSLANG_WEB SpecialQualifier("gl_Position", EvqPosition, EbvPosition, symbolTable); SpecialQualifier("gl_PointSize", EvqPointSize, EbvPointSize, symbolTable); @@ -7398,7 +8095,21 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); } -#endif + + if (language == EShLangGeometry || language == EShLangVertex) { + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 450)) { + symbolTable.setVariableExtensions("gl_PrimitiveShadingRateEXT", 1, &E_GL_EXT_fragment_shading_rate); + BuiltInVariable("gl_PrimitiveShadingRateEXT", EbvPrimitiveShadingRateKHR, symbolTable); + + symbolTable.setVariableExtensions("gl_ShadingRateFlag2VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + } + } + +#endif // !GLSLANG_WEB break; case EShLangFragment: @@ -7428,6 +8139,38 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_FragStencilRefARB", EbvFragStencilRef, symbolTable); } + if (profile != EEsProfile && version < 400) { + symbolTable.setFunctionExtensions("textureQueryLod", 1, &E_GL_ARB_texture_query_lod); + } + + if (profile != EEsProfile && version >= 460) { + symbolTable.setFunctionExtensions("rayQueryInitializeEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryTerminateEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGenerateIntersectionEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryConfirmIntersectionEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryProceedEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionTypeEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionTEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetRayFlagsEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetRayTMinEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionInstanceCustomIndexEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionInstanceIdEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionGeometryIndexEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionPrimitiveIndexEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionBarycentricsEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionFrontFaceEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionCandidateAABBOpaqueEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionObjectRayDirectionEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionObjectRayOriginEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionObjectToWorldEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionWorldToObjectEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetWorldRayOriginEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetWorldRayDirectionEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setVariableExtensions("gl_RayFlagsSkipAABBEXT", 1, &E_GL_EXT_ray_flags_primitive_culling); + symbolTable.setVariableExtensions("gl_RayFlagsSkipTrianglesEXT", 1, &E_GL_EXT_ray_flags_primitive_culling); + } + if ((profile != EEsProfile && version >= 130) || (profile == EEsProfile && version >= 310)) { BuiltInVariable("gl_SampleID", EbvSampleId, symbolTable); @@ -7540,6 +8283,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("atomicCounter" , 1, &E_GL_ARB_shader_atomic_counters); } + // E_GL_ARB_shader_atomic_counter_ops + if (profile != EEsProfile && version == 450) { + symbolTable.setFunctionExtensions("atomicCounterAddARB" , 1, &E_GL_ARB_shader_atomic_counter_ops); + symbolTable.setFunctionExtensions("atomicCounterSubtractARB", 1, &E_GL_ARB_shader_atomic_counter_ops); + symbolTable.setFunctionExtensions("atomicCounterMinARB" , 1, &E_GL_ARB_shader_atomic_counter_ops); + symbolTable.setFunctionExtensions("atomicCounterMaxARB" , 1, &E_GL_ARB_shader_atomic_counter_ops); + symbolTable.setFunctionExtensions("atomicCounterAndARB" , 1, &E_GL_ARB_shader_atomic_counter_ops); + symbolTable.setFunctionExtensions("atomicCounterOrARB" , 1, &E_GL_ARB_shader_atomic_counter_ops); + symbolTable.setFunctionExtensions("atomicCounterXorARB" , 1, &E_GL_ARB_shader_atomic_counter_ops); + symbolTable.setFunctionExtensions("atomicCounterExchangeARB", 1, &E_GL_ARB_shader_atomic_counter_ops); + symbolTable.setFunctionExtensions("atomicCounterCompSwapARB", 1, &E_GL_ARB_shader_atomic_counter_ops); + } + // E_GL_ARB_derivative_control if (profile != EEsProfile && version < 450) { symbolTable.setFunctionExtensions("dFdxFine", 1, &E_GL_ARB_derivative_control); @@ -7666,6 +8422,45 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("imageAtomicCompSwap", 1, &E_GL_OES_shader_image_atomic); } + if (profile != EEsProfile && version < 330 ) { + symbolTable.setFunctionExtensions("floatBitsToInt", 1, &E_GL_ARB_shader_bit_encoding); + symbolTable.setFunctionExtensions("floatBitsToUint", 1, &E_GL_ARB_shader_bit_encoding); + symbolTable.setFunctionExtensions("intBitsToFloat", 1, &E_GL_ARB_shader_bit_encoding); + symbolTable.setFunctionExtensions("uintBitsToFloat", 1, &E_GL_ARB_shader_bit_encoding); + } + + if (profile != EEsProfile && version < 430 ) { + symbolTable.setFunctionExtensions("imageSize", 1, &E_GL_ARB_shader_image_size); + } + + // GL_ARB_shader_storage_buffer_object + if (profile != EEsProfile && version < 430 ) { + symbolTable.setFunctionExtensions("atomicAdd", 1, &E_GL_ARB_shader_storage_buffer_object); + symbolTable.setFunctionExtensions("atomicMin", 1, &E_GL_ARB_shader_storage_buffer_object); + symbolTable.setFunctionExtensions("atomicMax", 1, &E_GL_ARB_shader_storage_buffer_object); + symbolTable.setFunctionExtensions("atomicAnd", 1, &E_GL_ARB_shader_storage_buffer_object); + symbolTable.setFunctionExtensions("atomicOr", 1, &E_GL_ARB_shader_storage_buffer_object); + symbolTable.setFunctionExtensions("atomicXor", 1, &E_GL_ARB_shader_storage_buffer_object); + symbolTable.setFunctionExtensions("atomicExchange", 1, &E_GL_ARB_shader_storage_buffer_object); + symbolTable.setFunctionExtensions("atomicCompSwap", 1, &E_GL_ARB_shader_storage_buffer_object); + } + + // GL_ARB_shading_language_packing + if (profile != EEsProfile && version < 400 ) { + symbolTable.setFunctionExtensions("packUnorm2x16", 1, &E_GL_ARB_shading_language_packing); + symbolTable.setFunctionExtensions("unpackUnorm2x16", 1, &E_GL_ARB_shading_language_packing); + symbolTable.setFunctionExtensions("packSnorm4x8", 1, &E_GL_ARB_shading_language_packing); + symbolTable.setFunctionExtensions("packUnorm4x8", 1, &E_GL_ARB_shading_language_packing); + symbolTable.setFunctionExtensions("unpackSnorm4x8", 1, &E_GL_ARB_shading_language_packing); + symbolTable.setFunctionExtensions("unpackUnorm4x8", 1, &E_GL_ARB_shading_language_packing); + } + if (profile != EEsProfile && version < 420 ) { + symbolTable.setFunctionExtensions("packSnorm2x16", 1, &E_GL_ARB_shading_language_packing); + symbolTable.setFunctionExtensions("unpackSnorm2x16", 1, &E_GL_ARB_shading_language_packing); + symbolTable.setFunctionExtensions("unpackHalf2x16", 1, &E_GL_ARB_shading_language_packing); + symbolTable.setFunctionExtensions("packHalf2x16", 1, &E_GL_ARB_shading_language_packing); + } + symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview); @@ -7833,7 +8628,18 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion } symbolTable.setFunctionExtensions("helperInvocationEXT", 1, &E_GL_EXT_demote_to_helper_invocation); -#endif + + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 450)) { + symbolTable.setVariableExtensions("gl_ShadingRateEXT", 1, &E_GL_EXT_fragment_shading_rate); + BuiltInVariable("gl_ShadingRateEXT", EbvShadingRateKHR, symbolTable); + + symbolTable.setVariableExtensions("gl_ShadingRateFlag2VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + } +#endif // !GLSLANG_WEB break; case EShLangCompute: @@ -7877,7 +8683,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("groupMemoryBarrier", 1, &E_GL_ARB_compute_shader); } + symbolTable.setFunctionExtensions("controlBarrier", 1, &E_GL_KHR_memory_scope_semantics); + symbolTable.setFunctionExtensions("debugPrintfEXT", 1, &E_GL_EXT_debug_printf); // GL_ARB_shader_ballot if (profile != EEsProfile) { @@ -7963,53 +8771,110 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("dFdyCoarse", 1, &E_GL_NV_compute_shader_derivatives); symbolTable.setFunctionExtensions("fwidthCoarse", 1, &E_GL_NV_compute_shader_derivatives); } -#endif + + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 450)) { + symbolTable.setVariableExtensions("gl_ShadingRateFlag2VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + } +#endif // !GLSLANG_WEB break; -#ifndef GLSLANG_WEB - case EShLangRayGenNV: - case EShLangIntersectNV: - case EShLangAnyHitNV: - case EShLangClosestHitNV: - case EShLangMissNV: - case EShLangCallableNV: +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + case EShLangRayGen: + case EShLangIntersect: + case EShLangAnyHit: + case EShLangClosestHit: + case EShLangMiss: + case EShLangCallable: if (profile != EEsProfile && version >= 460) { + const char *rtexts[] = { E_GL_NV_ray_tracing, E_GL_EXT_ray_tracing }; symbolTable.setVariableExtensions("gl_LaunchIDNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_LaunchIDEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_LaunchSizeNV", 1, &E_GL_NV_ray_tracing); - symbolTable.setVariableExtensions("gl_PrimitiveID", 1, &E_GL_NV_ray_tracing); - symbolTable.setVariableExtensions("gl_InstanceID", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_LaunchSizeEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setVariableExtensions("gl_PrimitiveID", 2, rtexts); + symbolTable.setVariableExtensions("gl_InstanceID", 2, rtexts); symbolTable.setVariableExtensions("gl_InstanceCustomIndexNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_InstanceCustomIndexEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setVariableExtensions("gl_GeometryIndexEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_WorldRayOriginNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_WorldRayOriginEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_WorldRayDirectionNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_WorldRayDirectionEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_ObjectRayOriginNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_ObjectRayOriginEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_ObjectRayDirectionNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_ObjectRayDirectionEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_RayTminNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_RayTminEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_RayTmaxNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_RayTmaxEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_HitTNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_HitTEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_HitKindNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_HitKindEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_ObjectToWorldNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_ObjectToWorldEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setVariableExtensions("gl_ObjectToWorld3x4EXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_WorldToObjectNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_WorldToObjectEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setVariableExtensions("gl_WorldToObject3x4EXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_IncomingRayFlagsNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setVariableExtensions("gl_IncomingRayFlagsEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setVariableExtensions("gl_CurrentRayTimeNV", 1, &E_GL_NV_ray_tracing_motion_blur); symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); - BuiltInVariable("gl_LaunchIDNV", EbvLaunchIdNV, symbolTable); - BuiltInVariable("gl_LaunchSizeNV", EbvLaunchSizeNV, symbolTable); - BuiltInVariable("gl_PrimitiveID", EbvPrimitiveId, symbolTable); - BuiltInVariable("gl_InstanceID", EbvInstanceId, symbolTable); - BuiltInVariable("gl_InstanceCustomIndexNV", EbvInstanceCustomIndexNV,symbolTable); - BuiltInVariable("gl_WorldRayOriginNV", EbvWorldRayOriginNV, symbolTable); - BuiltInVariable("gl_WorldRayDirectionNV", EbvWorldRayDirectionNV, symbolTable); - BuiltInVariable("gl_ObjectRayOriginNV", EbvObjectRayOriginNV, symbolTable); - BuiltInVariable("gl_ObjectRayDirectionNV", EbvObjectRayDirectionNV, symbolTable); - BuiltInVariable("gl_RayTminNV", EbvRayTminNV, symbolTable); - BuiltInVariable("gl_RayTmaxNV", EbvRayTmaxNV, symbolTable); - BuiltInVariable("gl_HitTNV", EbvHitTNV, symbolTable); - BuiltInVariable("gl_HitKindNV", EbvHitKindNV, symbolTable); - BuiltInVariable("gl_ObjectToWorldNV", EbvObjectToWorldNV, symbolTable); - BuiltInVariable("gl_WorldToObjectNV", EbvWorldToObjectNV, symbolTable); - BuiltInVariable("gl_IncomingRayFlagsNV", EbvIncomingRayFlagsNV, symbolTable); - BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); + + symbolTable.setFunctionExtensions("traceNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setFunctionExtensions("traceRayMotionNV", 1, &E_GL_NV_ray_tracing_motion_blur); + symbolTable.setFunctionExtensions("traceRayEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setFunctionExtensions("reportIntersectionNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setFunctionExtensions("reportIntersectionEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setFunctionExtensions("ignoreIntersectionNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setFunctionExtensions("terminateRayNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setFunctionExtensions("executeCallableNV", 1, &E_GL_NV_ray_tracing); + symbolTable.setFunctionExtensions("executeCallableEXT", 1, &E_GL_EXT_ray_tracing); + + + BuiltInVariable("gl_LaunchIDNV", EbvLaunchId, symbolTable); + BuiltInVariable("gl_LaunchIDEXT", EbvLaunchId, symbolTable); + BuiltInVariable("gl_LaunchSizeNV", EbvLaunchSize, symbolTable); + BuiltInVariable("gl_LaunchSizeEXT", EbvLaunchSize, symbolTable); + BuiltInVariable("gl_PrimitiveID", EbvPrimitiveId, symbolTable); + BuiltInVariable("gl_InstanceID", EbvInstanceId, symbolTable); + BuiltInVariable("gl_InstanceCustomIndexNV", EbvInstanceCustomIndex,symbolTable); + BuiltInVariable("gl_InstanceCustomIndexEXT", EbvInstanceCustomIndex,symbolTable); + BuiltInVariable("gl_GeometryIndexEXT", EbvGeometryIndex, symbolTable); + BuiltInVariable("gl_WorldRayOriginNV", EbvWorldRayOrigin, symbolTable); + BuiltInVariable("gl_WorldRayOriginEXT", EbvWorldRayOrigin, symbolTable); + BuiltInVariable("gl_WorldRayDirectionNV", EbvWorldRayDirection, symbolTable); + BuiltInVariable("gl_WorldRayDirectionEXT", EbvWorldRayDirection, symbolTable); + BuiltInVariable("gl_ObjectRayOriginNV", EbvObjectRayOrigin, symbolTable); + BuiltInVariable("gl_ObjectRayOriginEXT", EbvObjectRayOrigin, symbolTable); + BuiltInVariable("gl_ObjectRayDirectionNV", EbvObjectRayDirection, symbolTable); + BuiltInVariable("gl_ObjectRayDirectionEXT", EbvObjectRayDirection, symbolTable); + BuiltInVariable("gl_RayTminNV", EbvRayTmin, symbolTable); + BuiltInVariable("gl_RayTminEXT", EbvRayTmin, symbolTable); + BuiltInVariable("gl_RayTmaxNV", EbvRayTmax, symbolTable); + BuiltInVariable("gl_RayTmaxEXT", EbvRayTmax, symbolTable); + BuiltInVariable("gl_HitTNV", EbvHitT, symbolTable); + BuiltInVariable("gl_HitTEXT", EbvHitT, symbolTable); + BuiltInVariable("gl_HitKindNV", EbvHitKind, symbolTable); + BuiltInVariable("gl_HitKindEXT", EbvHitKind, symbolTable); + BuiltInVariable("gl_ObjectToWorldNV", EbvObjectToWorld, symbolTable); + BuiltInVariable("gl_ObjectToWorldEXT", EbvObjectToWorld, symbolTable); + BuiltInVariable("gl_ObjectToWorld3x4EXT", EbvObjectToWorld3x4, symbolTable); + BuiltInVariable("gl_WorldToObjectNV", EbvWorldToObject, symbolTable); + BuiltInVariable("gl_WorldToObjectEXT", EbvWorldToObject, symbolTable); + BuiltInVariable("gl_WorldToObject3x4EXT", EbvWorldToObject3x4, symbolTable); + BuiltInVariable("gl_IncomingRayFlagsNV", EbvIncomingRayFlags, symbolTable); + BuiltInVariable("gl_IncomingRayFlagsEXT", EbvIncomingRayFlags, symbolTable); + BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); + BuiltInVariable("gl_CurrentRayTimeNV", EbvCurrentRayTimeNV, symbolTable); // GL_ARB_shader_ballot symbolTable.setVariableExtensions("gl_SubGroupSizeARB", 1, &E_GL_ARB_shader_ballot); @@ -8064,6 +8929,13 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); } + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 450)) { + symbolTable.setVariableExtensions("gl_ShadingRateFlag2VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + } break; case EShLangMeshNV: @@ -8208,6 +9080,14 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); } + + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 450)) { + symbolTable.setVariableExtensions("gl_ShadingRateFlag2VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + } break; case EShLangTaskNV: @@ -8308,6 +9188,13 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); } + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 450)) { + symbolTable.setVariableExtensions("gl_ShadingRateFlag2VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4VerticalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); + } break; #endif @@ -8377,6 +9264,14 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("memoryBarrierAtomicCounter", EOpMemoryBarrierAtomicCounter); symbolTable.relateToOperator("memoryBarrierImage", EOpMemoryBarrierImage); + if (spvVersion.vulkanRelaxed) { + // + // functions signature have been replaced to take uint operations on buffer variables + // remap atomic counter functions to atomic operations + // + symbolTable.relateToOperator("memoryBarrierAtomicCounter", EOpMemoryBarrierBuffer); + } + symbolTable.relateToOperator("atomicLoad", EOpAtomicLoad); symbolTable.relateToOperator("atomicStore", EOpAtomicStore); @@ -8384,12 +9279,38 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("atomicCounterDecrement", EOpAtomicCounterDecrement); symbolTable.relateToOperator("atomicCounter", EOpAtomicCounter); + if (spvVersion.vulkanRelaxed) { + // + // functions signature have been replaced to take uint operations + // remap atomic counter functions to atomic operations + // + // these atomic counter functions do not match signatures of glsl + // atomic functions, so they will be remapped to semantically + // equivalent functions in the parser + // + symbolTable.relateToOperator("atomicCounterIncrement", EOpNull); + symbolTable.relateToOperator("atomicCounterDecrement", EOpNull); + symbolTable.relateToOperator("atomicCounter", EOpNull); + } + symbolTable.relateToOperator("clockARB", EOpReadClockSubgroupKHR); symbolTable.relateToOperator("clock2x32ARB", EOpReadClockSubgroupKHR); symbolTable.relateToOperator("clockRealtimeEXT", EOpReadClockDeviceKHR); symbolTable.relateToOperator("clockRealtime2x32EXT", EOpReadClockDeviceKHR); + if (profile != EEsProfile && version == 450) { + symbolTable.relateToOperator("atomicCounterAddARB", EOpAtomicCounterAdd); + symbolTable.relateToOperator("atomicCounterSubtractARB", EOpAtomicCounterSubtract); + symbolTable.relateToOperator("atomicCounterMinARB", EOpAtomicCounterMin); + symbolTable.relateToOperator("atomicCounterMaxARB", EOpAtomicCounterMax); + symbolTable.relateToOperator("atomicCounterAndARB", EOpAtomicCounterAnd); + symbolTable.relateToOperator("atomicCounterOrARB", EOpAtomicCounterOr); + symbolTable.relateToOperator("atomicCounterXorARB", EOpAtomicCounterXor); + symbolTable.relateToOperator("atomicCounterExchangeARB", EOpAtomicCounterExchange); + symbolTable.relateToOperator("atomicCounterCompSwapARB", EOpAtomicCounterCompSwap); + } + if (profile != EEsProfile && version >= 460) { symbolTable.relateToOperator("atomicCounterAdd", EOpAtomicCounterAdd); symbolTable.relateToOperator("atomicCounterSubtract", EOpAtomicCounterSubtract); @@ -8402,6 +9323,23 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("atomicCounterCompSwap", EOpAtomicCounterCompSwap); } + if (spvVersion.vulkanRelaxed) { + // + // functions signature have been replaced to take 'uint' instead of 'atomic_uint' + // remap atomic counter functions to non-counter atomic ops so + // functions act as aliases to non-counter atomic ops + // + symbolTable.relateToOperator("atomicCounterAdd", EOpAtomicAdd); + symbolTable.relateToOperator("atomicCounterSubtract", EOpAtomicSubtract); + symbolTable.relateToOperator("atomicCounterMin", EOpAtomicMin); + symbolTable.relateToOperator("atomicCounterMax", EOpAtomicMax); + symbolTable.relateToOperator("atomicCounterAnd", EOpAtomicAnd); + symbolTable.relateToOperator("atomicCounterOr", EOpAtomicOr); + symbolTable.relateToOperator("atomicCounterXor", EOpAtomicXor); + symbolTable.relateToOperator("atomicCounterExchange", EOpAtomicExchange); + symbolTable.relateToOperator("atomicCounterCompSwap", EOpAtomicCompSwap); + } + symbolTable.relateToOperator("fma", EOpFma); symbolTable.relateToOperator("frexp", EOpFrexp); symbolTable.relateToOperator("ldexp", EOpLdexp); @@ -8426,6 +9364,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("average", EOpAverage); symbolTable.relateToOperator("averageRounded", EOpAverageRounded); symbolTable.relateToOperator("multiply32x16", EOpMul32x16); + symbolTable.relateToOperator("debugPrintfEXT", EOpDebugPrintf); + if (PureOperatorBuiltins) { symbolTable.relateToOperator("imageSize", EOpImageQuerySize); @@ -8715,6 +9655,33 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("dFdyCoarse", EOpDPdyCoarse); symbolTable.relateToOperator("fwidthCoarse", EOpFwidthCoarse); } + + if (profile != EEsProfile && version >= 460) { + symbolTable.relateToOperator("rayQueryInitializeEXT", EOpRayQueryInitialize); + symbolTable.relateToOperator("rayQueryTerminateEXT", EOpRayQueryTerminate); + symbolTable.relateToOperator("rayQueryGenerateIntersectionEXT", EOpRayQueryGenerateIntersection); + symbolTable.relateToOperator("rayQueryConfirmIntersectionEXT", EOpRayQueryConfirmIntersection); + symbolTable.relateToOperator("rayQueryProceedEXT", EOpRayQueryProceed); + symbolTable.relateToOperator("rayQueryGetIntersectionTypeEXT", EOpRayQueryGetIntersectionType); + symbolTable.relateToOperator("rayQueryGetRayTMinEXT", EOpRayQueryGetRayTMin); + symbolTable.relateToOperator("rayQueryGetRayFlagsEXT", EOpRayQueryGetRayFlags); + symbolTable.relateToOperator("rayQueryGetIntersectionTEXT", EOpRayQueryGetIntersectionT); + symbolTable.relateToOperator("rayQueryGetIntersectionInstanceCustomIndexEXT", EOpRayQueryGetIntersectionInstanceCustomIndex); + symbolTable.relateToOperator("rayQueryGetIntersectionInstanceIdEXT", EOpRayQueryGetIntersectionInstanceId); + symbolTable.relateToOperator("rayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetEXT", EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset); + symbolTable.relateToOperator("rayQueryGetIntersectionGeometryIndexEXT", EOpRayQueryGetIntersectionGeometryIndex); + symbolTable.relateToOperator("rayQueryGetIntersectionPrimitiveIndexEXT", EOpRayQueryGetIntersectionPrimitiveIndex); + symbolTable.relateToOperator("rayQueryGetIntersectionBarycentricsEXT", EOpRayQueryGetIntersectionBarycentrics); + symbolTable.relateToOperator("rayQueryGetIntersectionFrontFaceEXT", EOpRayQueryGetIntersectionFrontFace); + symbolTable.relateToOperator("rayQueryGetIntersectionCandidateAABBOpaqueEXT", EOpRayQueryGetIntersectionCandidateAABBOpaque); + symbolTable.relateToOperator("rayQueryGetIntersectionObjectRayDirectionEXT", EOpRayQueryGetIntersectionObjectRayDirection); + symbolTable.relateToOperator("rayQueryGetIntersectionObjectRayOriginEXT", EOpRayQueryGetIntersectionObjectRayOrigin); + symbolTable.relateToOperator("rayQueryGetWorldRayDirectionEXT", EOpRayQueryGetWorldRayDirection); + symbolTable.relateToOperator("rayQueryGetWorldRayOriginEXT", EOpRayQueryGetWorldRayOrigin); + symbolTable.relateToOperator("rayQueryGetIntersectionObjectToWorldEXT", EOpRayQueryGetIntersectionObjectToWorld); + symbolTable.relateToOperator("rayQueryGetIntersectionWorldToObjectEXT", EOpRayQueryGetIntersectionWorldToObject); + } + symbolTable.relateToOperator("interpolateAtCentroid", EOpInterpolateAtCentroid); symbolTable.relateToOperator("interpolateAtSample", EOpInterpolateAtSample); symbolTable.relateToOperator("interpolateAtOffset", EOpInterpolateAtOffset); @@ -8746,27 +9713,33 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("coopMatMulAddNV", EOpCooperativeMatrixMulAdd); break; - case EShLangRayGenNV: - case EShLangClosestHitNV: - case EShLangMissNV: + case EShLangRayGen: + case EShLangClosestHit: + case EShLangMiss: if (profile != EEsProfile && version >= 460) { symbolTable.relateToOperator("traceNV", EOpTraceNV); + symbolTable.relateToOperator("traceRayMotionNV", EOpTraceRayMotionNV); + symbolTable.relateToOperator("traceRayEXT", EOpTraceKHR); symbolTable.relateToOperator("executeCallableNV", EOpExecuteCallableNV); + symbolTable.relateToOperator("executeCallableEXT", EOpExecuteCallableKHR); } break; - case EShLangIntersectNV: - if (profile != EEsProfile && version >= 460) - symbolTable.relateToOperator("reportIntersectionNV", EOpReportIntersectionNV); + case EShLangIntersect: + if (profile != EEsProfile && version >= 460) { + symbolTable.relateToOperator("reportIntersectionNV", EOpReportIntersection); + symbolTable.relateToOperator("reportIntersectionEXT", EOpReportIntersection); + } break; - case EShLangAnyHitNV: + case EShLangAnyHit: if (profile != EEsProfile && version >= 460) { symbolTable.relateToOperator("ignoreIntersectionNV", EOpIgnoreIntersectionNV); symbolTable.relateToOperator("terminateRayNV", EOpTerminateRayNV); } break; - case EShLangCallableNV: + case EShLangCallable: if (profile != EEsProfile && version >= 460) { symbolTable.relateToOperator("executeCallableNV", EOpExecuteCallableNV); + symbolTable.relateToOperator("executeCallableEXT", EOpExecuteCallableKHR); } break; case EShLangMeshNV: @@ -8785,7 +9758,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion default: assert(false && "Language not supported"); } -#endif +#endif // !GLSLANG_WEB } // @@ -8800,6 +9773,10 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources) { #ifndef GLSLANG_WEB +#if defined(GLSLANG_ANGLE) + profile = ECoreProfile; + version = 450; +#endif if (profile != EEsProfile && version >= 430 && version < 440) { symbolTable.setVariableExtensions("gl_MaxTransformFeedbackBuffers", 1, &E_GL_ARB_enhanced_layouts); symbolTable.setVariableExtensions("gl_MaxTransformFeedbackInterleavedComponents", 1, &E_GL_ARB_enhanced_layouts); @@ -8823,6 +9800,16 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); SpecialQualifier("gl_FragData", EvqFragColor, EbvFragData, symbolTable); } + + // GL_EXT_blend_func_extended + if (profile == EEsProfile && version >= 100) { + symbolTable.setVariableExtensions("gl_MaxDualSourceDrawBuffersEXT", 1, &E_GL_EXT_blend_func_extended); + symbolTable.setVariableExtensions("gl_SecondaryFragColorEXT", 1, &E_GL_EXT_blend_func_extended); + symbolTable.setVariableExtensions("gl_SecondaryFragDataEXT", 1, &E_GL_EXT_blend_func_extended); + SpecialQualifier("gl_SecondaryFragColorEXT", EvqVaryingOut, EbvSecondaryFragColorEXT, symbolTable); + SpecialQualifier("gl_SecondaryFragDataEXT", EvqVaryingOut, EbvSecondaryFragDataEXT, symbolTable); + } + break; case EShLangTessControl: diff --git a/libraries/glslang/glslang/MachineIndependent/Initialize.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Initialize.h similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/Initialize.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Initialize.h diff --git a/libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/IntermTraverse.cpp similarity index 97% rename from libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/IntermTraverse.cpp index f46010b7121..553b1b5ff83 100644 --- a/libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/IntermTraverse.cpp @@ -71,6 +71,13 @@ void TIntermConstantUnion::traverse(TIntermTraverser *it) it->visitConstantUnion(this); } +const TString& TIntermSymbol::getAccessName() const { + if (getBasicType() == EbtBlock) + return getType().getTypeName(); + else + return getName(); +} + // // Traverse a binary node. // diff --git a/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Intermediate.cpp similarity index 91% rename from libraries/glslang/glslang/MachineIndependent/Intermediate.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Intermediate.cpp index d0f86e63894..02784459696 100644 --- a/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Intermediate.cpp @@ -1,7 +1,7 @@ // // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2015 LunarG, Inc. -// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) 2015-2020 Google, Inc. // Copyright (C) 2017 ARM Limited. // // All rights reserved. @@ -65,7 +65,7 @@ namespace glslang { // Returns the added node. // -TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TConstUnionArray& constArray, +TIntermSymbol* TIntermediate::addSymbol(long long id, const TString& name, const TType& type, const TConstUnionArray& constArray, TIntermTyped* constSubtree, const TSourceLoc& loc) { TIntermSymbol* node = new TIntermSymbol(id, name, type); @@ -113,14 +113,14 @@ TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc // // Returns nullptr if the working conversions and promotions could not be found. // -TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc) +TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc) { // No operations work on blocks if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock) return nullptr; // Convert "reference +/- int" and "reference - reference" to integer math - if ((op == EOpAdd || op == EOpSub) && extensionRequested(E_GL_EXT_buffer_reference2)) { + if (op == EOpAdd || op == EOpSub) { // No addressing math on struct with unsized array. if ((left->isReference() && left->getType().getReferentType()->containsUnsizedArray()) || @@ -140,43 +140,44 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType); return node; } + } - if (op == EOpAdd && right->isReference() && isTypeInt(left->getBasicType())) { - const TType& referenceType = right->getType(); - TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(right->getType()), loc, true); - right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64)); - - left = createConversion(EbtInt64, left); - left = addBinaryMath(EOpMul, left, size, loc); + if (op == EOpAdd && right->isReference() && isTypeInt(left->getBasicType())) { + const TType& referenceType = right->getType(); + TIntermConstantUnion* size = + addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(right->getType()), loc, true); + right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64)); - TIntermTyped *node = addBinaryMath(op, left, right, loc); - node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType); - return node; - } + left = createConversion(EbtInt64, left); + left = addBinaryMath(EOpMul, left, size, loc); - if (op == EOpSub && left->isReference() && right->isReference()) { - TIntermConstantUnion* size = addConstantUnion((long long)computeBufferReferenceTypeSize(left->getType()), loc, true); + TIntermTyped *node = addBinaryMath(op, left, right, loc); + node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType); + return node; + } - left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64)); - right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64)); + if (op == EOpSub && left->isReference() && right->isReference()) { + TIntermConstantUnion* size = + addConstantUnion((long long)computeBufferReferenceTypeSize(left->getType()), loc, true); - left = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, left, TType(EbtInt64)); - right = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, right, TType(EbtInt64)); + left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64)); + right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64)); - left = addBinaryMath(EOpSub, left, right, loc); + left = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, left, TType(EbtInt64)); + right = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, right, TType(EbtInt64)); - TIntermTyped *node = addBinaryMath(EOpDiv, left, size, loc); - return node; - } + left = addBinaryMath(EOpSub, left, right, loc); - // No other math operators supported on references - if (left->isReference() || right->isReference()) { - return nullptr; - } + TIntermTyped *node = addBinaryMath(EOpDiv, left, size, loc); + return node; } + // No other math operators supported on references + if (left->isReference() || right->isReference()) + return nullptr; + // Try converting the children's base types to compatible types. - auto children = addConversion(op, left, right); + auto children = addPairConversion(op, left, right); left = std::get<0>(children); right = std::get<1>(children); @@ -226,13 +227,12 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn // // Low level: add binary node (no promotions or other argument modifications) // -TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc) const +TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, + const TSourceLoc& loc) const { // build the node TIntermBinary* node = new TIntermBinary(op); - if (loc.line == 0) - loc = left->getLoc(); - node->setLoc(loc); + node->setLoc(loc.line != 0 ? loc : left->getLoc()); node->setLeft(left); node->setRight(right); @@ -242,7 +242,8 @@ TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TI // // like non-type form, but sets node's type. // -TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc, const TType& type) const +TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, + const TSourceLoc& loc, const TType& type) const { TIntermBinary* node = addBinaryNode(op, left, right, loc); node->setType(type); @@ -252,12 +253,10 @@ TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TI // // Low level: add unary node (no promotions or other argument modifications) // -TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc loc) const +TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc& loc) const { TIntermUnary* node = new TIntermUnary(op); - if (loc.line == 0) - loc = child->getLoc(); - node->setLoc(loc); + node->setLoc(loc.line != 0 ? loc : child->getLoc()); node->setOperand(child); return node; @@ -266,7 +265,8 @@ TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSo // // like non-type form, but sets node's type. // -TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc loc, const TType& type) const +TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc& loc, const TType& type) + const { TIntermUnary* node = addUnaryNode(op, child, loc); node->setType(type); @@ -281,7 +281,8 @@ TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSo // Returns nullptr if the 'right' type could not be converted to match the 'left' type, // or the resulting operation cannot be properly promoted. // -TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc) +TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, + const TSourceLoc& loc) { // No block assignment if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock) @@ -290,9 +291,7 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm // Convert "reference += int" to "reference = reference + int". We need this because the // "reference + int" calculation involves a cast back to the original type, which makes it // not an lvalue. - if ((op == EOpAddAssign || op == EOpSubAssign) && left->isReference() && - extensionRequested(E_GL_EXT_buffer_reference2)) { - + if ((op == EOpAddAssign || op == EOpSubAssign) && left->isReference()) { if (!(right->getType().isScalar() && right->getType().isIntegerDomain())) return nullptr; @@ -338,7 +337,8 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm // Returns the added node. // The caller should set the type of the returned node. // -TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc loc) +TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, + const TSourceLoc& loc) { // caller should set the type return addBinaryNode(op, base, index, loc); @@ -349,7 +349,8 @@ TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermT // // Returns the added node. // -TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSourceLoc loc) +TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, + const TSourceLoc& loc) { if (child == 0) return nullptr; @@ -495,7 +496,8 @@ TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOper // Returns an aggregate node, which could be the one passed in if // it was already an aggregate. // -TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TType& type, TSourceLoc loc) +TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TType& type, + const TSourceLoc& loc) { TIntermAggregate* aggNode; @@ -510,8 +512,6 @@ TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator o // aggNode = new TIntermAggregate(); aggNode->getSequence().push_back(node); - if (loc.line == 0) - loc = node->getLoc(); } } else aggNode = new TIntermAggregate(); @@ -520,8 +520,8 @@ TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator o // Set the operator. // aggNode->setOperator(op); - if (loc.line != 0) - aggNode->setLoc(loc); + if (loc.line != 0 || node != nullptr) + aggNode->setLoc(loc.line != 0 ? loc : node->getLoc()); aggNode->setType(type); @@ -538,7 +538,7 @@ bool TIntermediate::isConversionAllowed(TOperator op, TIntermTyped* node) const return false; case EbtAtomicUint: case EbtSampler: - case EbtAccStructNV: + case EbtAccStruct: // opaque types can be passed to functions if (op == EOpFunction) break; @@ -819,22 +819,25 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped node->getBasicType() == EbtFloat || node->getBasicType() == EbtDouble); - if (! getArithemeticInt8Enabled()) { - if (((convertTo == EbtInt8 || convertTo == EbtUint8) && ! convertFromIntTypes) || - ((node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8) && ! convertToIntTypes)) + if (((convertTo == EbtInt8 || convertTo == EbtUint8) && ! convertFromIntTypes) || + ((node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8) && ! convertToIntTypes)) { + if (! getArithemeticInt8Enabled()) { return nullptr; + } } - if (! getArithemeticInt16Enabled()) { - if (((convertTo == EbtInt16 || convertTo == EbtUint16) && ! convertFromIntTypes) || - ((node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16) && ! convertToIntTypes)) + if (((convertTo == EbtInt16 || convertTo == EbtUint16) && ! convertFromIntTypes) || + ((node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16) && ! convertToIntTypes)) { + if (! getArithemeticInt16Enabled()) { return nullptr; + } } - if (! getArithemeticFloat16Enabled()) { - if ((convertTo == EbtFloat16 && ! convertFromFloatTypes) || - (node->getBasicType() == EbtFloat16 && ! convertToFloatTypes)) + if ((convertTo == EbtFloat16 && ! convertFromFloatTypes) || + (node->getBasicType() == EbtFloat16 && ! convertToFloatTypes)) { + if (! getArithemeticFloat16Enabled()) { return nullptr; + } } #endif @@ -887,7 +890,7 @@ TIntermTyped* TIntermediate::addConversion(TBasicType convertTo, TIntermTyped* n // Returns the converted pair of nodes. // Returns when there is no conversion. std::tuple -TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) +TIntermediate::addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) { if (!isConversionAllowed(op, node0) || !isConversionAllowed(op, node1)) return std::make_tuple(nullptr, nullptr); @@ -940,7 +943,7 @@ TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* no if (node0->getBasicType() == node1->getBasicType()) return std::make_tuple(node0, node1); - promoteTo = getConversionDestinatonType(node0->getBasicType(), node1->getBasicType(), op); + promoteTo = getConversionDestinationType(node0->getBasicType(), node1->getBasicType(), op); if (std::get<0>(promoteTo) == EbtNumTypes || std::get<1>(promoteTo) == EbtNumTypes) return std::make_tuple(nullptr, nullptr); @@ -1040,64 +1043,30 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt // Note: callers are responsible for other aspects of shape, // like vector and matrix sizes. - TBasicType promoteTo; - // GL_EXT_shader_16bit_storage can't do OpConstantComposite with - // 16-bit types, so disable promotion for those types. - bool canPromoteConstant = true; - switch (op) { // // Explicit conversions (unary operations) // case EOpConstructBool: - promoteTo = EbtBool; - break; case EOpConstructFloat: - promoteTo = EbtFloat; - break; case EOpConstructInt: - promoteTo = EbtInt; - break; case EOpConstructUint: - promoteTo = EbtUint; - break; #ifndef GLSLANG_WEB case EOpConstructDouble: - promoteTo = EbtDouble; - break; case EOpConstructFloat16: - promoteTo = EbtFloat16; - canPromoteConstant = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float16); - break; case EOpConstructInt8: - promoteTo = EbtInt8; - canPromoteConstant = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int8); - break; case EOpConstructUint8: - promoteTo = EbtUint8; - canPromoteConstant = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int8); - break; case EOpConstructInt16: - promoteTo = EbtInt16; - canPromoteConstant = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int16); - break; case EOpConstructUint16: - promoteTo = EbtUint16; - canPromoteConstant = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int16); - break; case EOpConstructInt64: - promoteTo = EbtInt64; - break; case EOpConstructUint64: - promoteTo = EbtUint64; break; + #endif + // + // Implicit conversions + // case EOpLogicalNot: case EOpFunctionCall: @@ -1152,9 +1121,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt if (type.getBasicType() == node->getType().getBasicType()) return node; - if (canImplicitlyPromote(node->getBasicType(), type.getBasicType(), op)) - promoteTo = type.getBasicType(); - else + if (! canImplicitlyPromote(node->getBasicType(), type.getBasicType(), op)) return nullptr; break; @@ -1164,9 +1131,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt case EOpLeftShiftAssign: case EOpRightShiftAssign: { - if (getSource() == EShSourceHlsl && node->getType().getBasicType() == EbtBool) - promoteTo = type.getBasicType(); - else { + if (!(getSource() == EShSourceHlsl && node->getType().getBasicType() == EbtBool)) { if (isTypeInt(type.getBasicType()) && isTypeInt(node->getBasicType())) return node; else @@ -1184,13 +1149,44 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt return nullptr; } + bool canPromoteConstant = true; +#ifndef GLSLANG_WEB + // GL_EXT_shader_16bit_storage can't do OpConstantComposite with + // 16-bit types, so disable promotion for those types. + // Many issues with this, from JohnK: + // - this isn't really right to discuss SPIR-V here + // - this could easily be entirely about scalars, so is overstepping + // - we should be looking at what the shader asked for, and saying whether or + // not it can be done, in the parser, by calling requireExtensions(), not + // changing language sementics on the fly by asking what extensions are in use + // - at the time of this writing (14-Aug-2020), no test results are changed by this. + switch (op) { + case EOpConstructFloat16: + canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16); + break; + case EOpConstructInt8: + case EOpConstructUint8: + canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8); + break; + case EOpConstructInt16: + case EOpConstructUint16: + canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16); + break; + default: + break; + } +#endif + if (canPromoteConstant && node->getAsConstantUnion()) - return promoteConstantUnion(promoteTo, node->getAsConstantUnion()); + return promoteConstantUnion(type.getBasicType(), node->getAsConstantUnion()); // // Add a new newNode for the conversion. // - TIntermTyped* newNode = createConversion(promoteTo, node); + TIntermTyped* newNode = createConversion(type.getBasicType(), node); return newNode; } @@ -1620,7 +1616,7 @@ bool TIntermediate::isFPIntegralConversion(TBasicType from, TBasicType to) const // bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op) const { - if (isEsProfile() || version == 110) + if ((isEsProfile() && version < 310 ) || version == 110) return false; if (from == to) @@ -1659,46 +1655,51 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat } } - bool explicitTypesEnabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int8) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int16) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int32) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int64) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float16) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float32) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float64); - - if (explicitTypesEnabled) { - // integral promotions - if (isIntegralPromotion(from, to)) { - return true; - } - - // floating-point promotions - if (isFPPromotion(from, to)) { - return true; - } - - // integral conversions - if (isIntegralConversion(from, to)) { + if (getSource() == EShSourceHlsl) { + // HLSL + if (from == EbtBool && (to == EbtInt || to == EbtUint || to == EbtFloat)) return true; - } - - // floating-point conversions - if (isFPConversion(from, to)) { - return true; - } - - // floating-integral conversions - if (isFPIntegralConversion(from, to)) { - return true; - } - - // hlsl supported conversions - if (getSource() == EShSourceHlsl) { - if (from == EbtBool && (to == EbtInt || to == EbtUint || to == EbtFloat)) + } else { + // GLSL + if (isIntegralPromotion(from, to) || + isFPPromotion(from, to) || + isIntegralConversion(from, to) || + isFPConversion(from, to) || + isFPIntegralConversion(from, to)) { + + if (numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int32) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int64) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float32) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float64)) { return true; + } } + } + + if (isEsProfile()) { + switch (to) { + case EbtFloat: + switch (from) { + case EbtInt: + case EbtUint: + return numericFeatures.contains(TNumericFeatures::shader_implicit_conversions); + default: + return false; + } + case EbtUint: + switch (from) { + case EbtInt: + return numericFeatures.contains(TNumericFeatures::shader_implicit_conversions); + default: + return false; + } + default: + return false; + } } else { switch (to) { case EbtDouble: @@ -1708,13 +1709,14 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat case EbtInt64: case EbtUint64: case EbtFloat: - case EbtDouble: - return true; + return version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64); case EbtInt16: case EbtUint16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); + return (version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64)) && + numericFeatures.contains(TNumericFeatures::gpu_shader_int16); case EbtFloat16: - return extensionRequested(E_GL_AMD_gpu_shader_half_float); + return (version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64)) && + numericFeatures.contains(TNumericFeatures::gpu_shader_half_float); default: return false; } @@ -1722,16 +1724,14 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat switch (from) { case EbtInt: case EbtUint: - case EbtFloat: return true; case EbtBool: return getSource() == EShSourceHlsl; case EbtInt16: case EbtUint16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); + return numericFeatures.contains(TNumericFeatures::gpu_shader_int16); case EbtFloat16: - return - extensionRequested(E_GL_AMD_gpu_shader_half_float) || + return numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) || getSource() == EShSourceHlsl; default: return false; @@ -1739,25 +1739,21 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat case EbtUint: switch (from) { case EbtInt: - return version >= 400 || getSource() == EShSourceHlsl; - case EbtUint: - return true; + return version >= 400 || getSource() == EShSourceHlsl || IsRequestedExtension(E_GL_ARB_gpu_shader5); case EbtBool: return getSource() == EShSourceHlsl; case EbtInt16: case EbtUint16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); + return numericFeatures.contains(TNumericFeatures::gpu_shader_int16); default: return false; } case EbtInt: switch (from) { - case EbtInt: - return true; case EbtBool: return getSource() == EShSourceHlsl; case EbtInt16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); + return numericFeatures.contains(TNumericFeatures::gpu_shader_int16); default: return false; } @@ -1766,21 +1762,19 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat case EbtInt: case EbtUint: case EbtInt64: - case EbtUint64: return true; case EbtInt16: case EbtUint16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); + return numericFeatures.contains(TNumericFeatures::gpu_shader_int16); default: return false; } case EbtInt64: switch (from) { case EbtInt: - case EbtInt64: return true; case EbtInt16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); + return numericFeatures.contains(TNumericFeatures::gpu_shader_int16); default: return false; } @@ -1788,9 +1782,7 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat switch (from) { case EbtInt16: case EbtUint16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); - case EbtFloat16: - return extensionRequested(E_GL_AMD_gpu_shader_half_float); + return numericFeatures.contains(TNumericFeatures::gpu_shader_int16); default: break; } @@ -1798,8 +1790,7 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat case EbtUint16: switch (from) { case EbtInt16: - case EbtUint16: - return extensionRequested(E_GL_AMD_gpu_shader_int16); + return numericFeatures.contains(TNumericFeatures::gpu_shader_int16); default: break; } @@ -1926,12 +1917,14 @@ static TBasicType getCorrespondingUnsignedType(TBasicType type) // integer type corresponding to the type of the operand with signed // integer type. -std::tuple TIntermediate::getConversionDestinatonType(TBasicType type0, TBasicType type1, TOperator op) const +std::tuple TIntermediate::getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const { TBasicType res0 = EbtNumTypes; TBasicType res1 = EbtNumTypes; - if (isEsProfile() || version == 110) + if ((isEsProfile() && + (version < 310 || !numericFeatures.contains(TNumericFeatures::shader_implicit_conversions))) || + version == 110) return std::make_tuple(res0, res1); if (getSource() == EShSourceHlsl) { @@ -2305,6 +2298,10 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const case EbtReference: op = EOpConstructReference; break; + + case EbtAccStruct: + op = EOpConstructAccStruct; + break; #endif default: break; @@ -2463,7 +2460,7 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true // // Get compatible types. // - auto children = addConversion(EOpSequence, trueBlock, falseBlock); + auto children = addPairConversion(EOpSequence, trueBlock, falseBlock); trueBlock = std::get<0>(children); falseBlock = std::get<1>(children); @@ -2679,7 +2676,11 @@ TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors& selecto // 'swizzleOkay' says whether or not it is okay to consider a swizzle // a valid part of the dereference chain. // -const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay) +// 'BufferReferenceOk' says if type is buffer_reference, the routine stop to find the most left node. +// +// + +const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay , bool bufferReferenceOk) { do { const TIntermBinary* binary = node->getAsBinaryNode(); @@ -2697,6 +2698,8 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool return nullptr; } node = node->getAsBinaryNode()->getLeft(); + if (bufferReferenceOk && node->isReference()) + return node; } while (true); } @@ -2750,6 +2753,22 @@ TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expres return node; } +// Propagate precision from formal function return type to actual return type, +// and on to its subtree. +void TIntermBranch::updatePrecision(TPrecisionQualifier parentPrecision) +{ + TIntermTyped* exp = getExpression(); + if (exp == nullptr) + return; + + if (exp->getBasicType() == EbtInt || exp->getBasicType() == EbtUint || + exp->getBasicType() == EbtFloat || exp->getBasicType() == EbtFloat16) { + if (parentPrecision != EpqNone && exp->getQualifier().precision == EpqNone) { + exp->propagatePrecision(parentPrecision); + } + } +} + // // This is to be executed after the final root is put on top by the parsing // process. @@ -2774,6 +2793,9 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/) case EShTexSampTransUpgradeTextureRemoveSampler: performTextureUpgradeAndSamplerRemovalTransformation(root); break; + case EShTexSampTransCount: + assert(0); + break; } #endif @@ -2854,7 +2876,7 @@ void TIntermediate::addToCallGraph(TInfoSink& /*infoSink*/, const TString& calle return; } - callGraph.push_front(TCall(caller, callee)); + callGraph.emplace_front(caller, callee); } // @@ -3234,10 +3256,17 @@ bool TIntermediate::promoteUnary(TIntermUnary& node) return false; break; - default: - if (operand->getBasicType() != EbtFloat) + // HLSL uses this path for initial function signature finding for built-ins + // taking a single argument, which generally don't participate in + // operator-based type promotion (type conversion will occur later). + // For now, scalar argument cases are relying on the setType() call below. + if (getSource() == EShSourceHlsl) + break; + // GLSL only allows integer arguments for the cases identified above in the + // case statements. + if (operand->getBasicType() != EbtFloat) return false; } @@ -3247,9 +3276,11 @@ bool TIntermediate::promoteUnary(TIntermUnary& node) return true; } +// Propagate precision qualifiers *up* from children to parent. void TIntermUnary::updatePrecision() { - if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { + if (getBasicType() == EbtInt || getBasicType() == EbtUint || + getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { if (operand->getQualifier().precision > getQualifier().precision) getQualifier().precision = operand->getQualifier().precision; } @@ -3745,20 +3776,33 @@ bool TIntermediate::promoteAggregate(TIntermAggregate& node) return false; } +// Propagate precision qualifiers *up* from children to parent, and then +// back *down* again to the children's subtrees. void TIntermBinary::updatePrecision() { - if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { - getQualifier().precision = std::max(right->getQualifier().precision, left->getQualifier().precision); - if (getQualifier().precision != EpqNone) { - left->propagatePrecision(getQualifier().precision); - right->propagatePrecision(getQualifier().precision); - } + if (getBasicType() == EbtInt || getBasicType() == EbtUint || + getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { + if (op == EOpRightShift || op == EOpLeftShift) { + // For shifts get precision from left side only and thus no need to propagate + getQualifier().precision = left->getQualifier().precision; + } else { + getQualifier().precision = std::max(right->getQualifier().precision, left->getQualifier().precision); + if (getQualifier().precision != EpqNone) { + left->propagatePrecision(getQualifier().precision); + right->propagatePrecision(getQualifier().precision); + } + } } } +// Recursively propagate precision qualifiers *down* the subtree of the current node, +// until reaching a node that already has a precision qualifier or otherwise does +// not participate in precision propagation. void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision) { - if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtUint && getBasicType() != EbtFloat && getBasicType() != EbtFloat16)) + if (getQualifier().precision != EpqNone || + (getBasicType() != EbtInt && getBasicType() != EbtUint && + getBasicType() != EbtFloat && getBasicType() != EbtFloat16)) return; getQualifier().precision = newPrecision; diff --git a/libraries/glslang/glslang/MachineIndependent/LiveTraverser.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/LiveTraverser.h similarity index 76% rename from libraries/glslang/glslang/MachineIndependent/LiveTraverser.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/LiveTraverser.h index 7333bc964e4..9b39b5983f5 100644 --- a/libraries/glslang/glslang/MachineIndependent/LiveTraverser.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/LiveTraverser.h @@ -74,14 +74,33 @@ class TLiveTraverser : public TIntermTraverser { for (unsigned int f = 0; f < globals.size(); ++f) { TIntermAggregate* candidate = globals[f]->getAsAggregate(); if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) { - functions.push_back(candidate); + destinations.push_back(candidate); break; } } } - typedef std::list TFunctionStack; - TFunctionStack functions; + void pushGlobalReference(const TString& name) + { + TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence(); + for (unsigned int f = 0; f < globals.size(); ++f) { + TIntermAggregate* candidate = globals[f]->getAsAggregate(); + if (candidate && candidate->getOp() == EOpSequence && + candidate->getSequence().size() == 1 && + candidate->getSequence()[0]->getAsBinaryNode()) { + TIntermBinary* binary = candidate->getSequence()[0]->getAsBinaryNode(); + TIntermSymbol* symbol = binary->getLeft()->getAsSymbolNode(); + if (symbol && symbol->getQualifier().storage == EvqGlobal && + symbol->getName() == name) { + destinations.push_back(candidate); + break; + } + } + } + } + + typedef std::list TDestinationStack; + TDestinationStack destinations; protected: // To catch which function calls are not dead, and hence which functions must be visited. @@ -117,16 +136,27 @@ class TLiveTraverser : public TIntermTraverser { // and only visit each function once. void addFunctionCall(TIntermAggregate* call) { - // // just use the map to ensure we process each function at most once + // just use the map to ensure we process each function at most once if (liveFunctions.find(call->getName()) == liveFunctions.end()) { liveFunctions.insert(call->getName()); pushFunction(call->getName()); } } + void addGlobalReference(const TString& name) + { + // just use the map to ensure we process each global at most once + if (liveGlobals.find(name) == liveGlobals.end()) { + liveGlobals.insert(name); + pushGlobalReference(name); + } + } + const TIntermediate& intermediate; typedef std::unordered_set TLiveFunctions; TLiveFunctions liveFunctions; + typedef std::unordered_set TLiveGlobals; + TLiveGlobals liveGlobals; bool traverseAll; private: diff --git a/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseContextBase.cpp similarity index 80% rename from libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseContextBase.cpp index 282ecca0e07..02cca409e1e 100644 --- a/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseContextBase.cpp @@ -127,22 +127,6 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, { TIntermBinary* binaryNode = node->getAsBinaryNode(); - if (binaryNode) { - switch(binaryNode->getOp()) { - case EOpIndexDirect: - case EOpIndexIndirect: // fall through - case EOpIndexDirectStruct: // fall through - case EOpVectorSwizzle: - case EOpMatrixSwizzle: - return lValueErrorCheck(loc, op, binaryNode->getLeft()); - default: - break; - } - error(loc, " l-value required", op, "", ""); - - return true; - } - const char* symbol = nullptr; TIntermSymbol* symNode = node->getAsSymbolNode(); if (symNode != nullptr) @@ -157,11 +141,11 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, case EvqBuffer: if (node->getQualifier().isReadOnly()) message = "can't modify a readonly buffer"; - if (node->getQualifier().isShaderRecordNV()) + if (node->getQualifier().isShaderRecord()) message = "can't modify a shaderrecordnv qualified buffer"; break; - case EvqHitAttrNV: - if (language != EShLangIntersectNV) + case EvqHitAttr: + if (language != EShLangIntersect) message = "cannot modify hitAttributeNV in this stage"; break; #endif @@ -181,9 +165,12 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, case EbtAtomicUint: message = "can't modify an atomic_uint"; break; - case EbtAccStructNV: + case EbtAccStruct: message = "can't modify accelerationStructureNV"; break; + case EbtRayQuery: + message = "can't modify rayQueryEXT"; + break; #endif default: break; @@ -200,15 +187,40 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, // Everything else is okay, no error. // if (message == nullptr) + { + if (binaryNode) { + switch (binaryNode->getOp()) { + case EOpIndexDirect: + case EOpIndexIndirect: // fall through + case EOpIndexDirectStruct: // fall through + case EOpVectorSwizzle: + case EOpMatrixSwizzle: + return lValueErrorCheck(loc, op, binaryNode->getLeft()); + default: + break; + } + error(loc, " l-value required", op, "", ""); + + return true; + } return false; + } // // If we get here, we have an error and a message. // + const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true); + if (symNode) error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message); else - error(loc, " l-value required", op, "(%s)", message); + if (binaryNode && binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct) + if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName())) + error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str(), message); + else + error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getName().c_str(), message); + else + error(loc, " l-value required", op, "(%s)", message); return true; } @@ -216,28 +228,41 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, // Test for and give an error if the node can't be read from. void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) { + TIntermBinary* binaryNode = node->getAsBinaryNode(); + const TIntermSymbol* symNode = node->getAsSymbolNode(); + if (! node) return; - TIntermBinary* binaryNode = node->getAsBinaryNode(); - if (binaryNode) { - switch(binaryNode->getOp()) { - case EOpIndexDirect: - case EOpIndexIndirect: - case EOpIndexDirectStruct: - case EOpVectorSwizzle: - case EOpMatrixSwizzle: - rValueErrorCheck(loc, op, binaryNode->getLeft()); - default: - break; - } + if (node->getQualifier().isWriteOnly()) { + const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true); + + if (symNode != nullptr) + error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str()); + else if (binaryNode && + (binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct || + binaryNode->getAsOperator()->getOp() == EOpIndexDirect)) + if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName())) + error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str()); + else + error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getName().c_str()); + else + error(loc, "can't read from writeonly object: ", op, ""); - return; + } else { + if (binaryNode) { + switch (binaryNode->getOp()) { + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + case EOpVectorSwizzle: + case EOpMatrixSwizzle: + rValueErrorCheck(loc, op, binaryNode->getLeft()); + default: + break; + } + } } - - TIntermSymbol* symNode = node->getAsSymbolNode(); - if (symNode && symNode->getQualifier().isWriteOnly()) - error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str()); } // Add 'symbol' to the list of deferred linkage symbols, which @@ -576,7 +601,6 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin selector.push_back(0); } -#ifdef ENABLE_HLSL // // Make the passed-in variable information become a member of the // global uniform block. If this doesn't exist yet, make it. @@ -621,7 +645,67 @@ void TParseContextBase::growGlobalUniformBlock(const TSourceLoc& loc, TType& mem ++firstNewMember; } -#endif + +void TParseContextBase::growAtomicCounterBlock(int binding, const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) { + // Make the atomic counter block, if not yet made. + const auto &at = atomicCounterBuffers.find(binding); + if (at == atomicCounterBuffers.end()) { + atomicCounterBuffers.insert({binding, (TVariable*)nullptr }); + atomicCounterBlockFirstNewMember.insert({binding, 0}); + } + + TVariable*& atomicCounterBuffer = atomicCounterBuffers[binding]; + int& bufferNewMember = atomicCounterBlockFirstNewMember[binding]; + + if (atomicCounterBuffer == nullptr) { + TQualifier blockQualifier; + blockQualifier.clear(); + blockQualifier.storage = EvqBuffer; + + char charBuffer[512]; + if (binding != TQualifier::layoutBindingEnd) { + snprintf(charBuffer, 512, "%s_%d", getAtomicCounterBlockName(), binding); + } else { + snprintf(charBuffer, 512, "%s_0", getAtomicCounterBlockName()); + } + + TType blockType(new TTypeList, *NewPoolTString(charBuffer), blockQualifier); + setUniformBlockDefaults(blockType); + blockType.getQualifier().layoutPacking = ElpStd430; + atomicCounterBuffer = new TVariable(NewPoolTString(""), blockType, true); + // If we arn't auto mapping bindings then set the block to use the same + // binding as what the atomic was set to use + if (!intermediate.getAutoMapBindings()) { + atomicCounterBuffer->getWritableType().getQualifier().layoutBinding = binding; + } + bufferNewMember = 0; + + atomicCounterBuffer->getWritableType().getQualifier().layoutSet = atomicCounterBlockSet; + } + + // Add the requested member as a member to the global block. + TType* type = new TType; + type->shallowCopy(memberType); + type->setFieldName(memberName); + if (typeList) + type->setStruct(typeList); + TTypeLoc typeLoc = {type, loc}; + atomicCounterBuffer->getType().getWritableStruct()->push_back(typeLoc); + + // Insert into the symbol table. + if (bufferNewMember == 0) { + // This is the first request; we need a normal symbol table insert + if (symbolTable.insert(*atomicCounterBuffer)) + trackLinkage(*atomicCounterBuffer); + else + error(loc, "failed to insert the global constant buffer", "buffer", ""); + } else { + // This is a follow-on request; we need to amend the first insert + symbolTable.amend(*atomicCounterBuffer, bufferNewMember); + } + + ++bufferNewMember; +} void TParseContextBase::finish() { diff --git a/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseHelper.cpp similarity index 86% rename from libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseHelper.cpp index b9ab5c82229..b957bb87caf 100644 --- a/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseHelper.cpp @@ -3,6 +3,7 @@ // Copyright (C) 2012-2015 LunarG, Inc. // Copyright (C) 2015-2018 Google, Inc. // Copyright (C) 2017, 2019 ARM Limited. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -86,6 +87,10 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b globalInputDefaults.clear(); globalOutputDefaults.clear(); + globalSharedDefaults.clear(); + globalSharedDefaults.layoutMatrix = ElmColumnMajor; + globalSharedDefaults.layoutPacking = ElpStd430; + #ifndef GLSLANG_WEB // "Shaders in the transform // feedback capturing mode have an initial global default of @@ -220,6 +225,118 @@ void TParseContext::parserError(const char* s) error(getCurrentLoc(), "compilation terminated", "", ""); } +void TParseContext::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) +{ + bool createBlock = globalUniformBlock == nullptr; + + if (createBlock) { + globalUniformBinding = intermediate.getGlobalUniformBinding(); + globalUniformSet = intermediate.getGlobalUniformSet(); + } + + // use base class function to create/expand block + TParseContextBase::growGlobalUniformBlock(loc, memberType, memberName, typeList); + + if (spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) { + // check for a block storage override + TBlockStorageClass storageOverride = intermediate.getBlockStorageOverride(getGlobalUniformBlockName()); + TQualifier& qualifier = globalUniformBlock->getWritableType().getQualifier(); + qualifier.defaultBlock = true; + + if (storageOverride != EbsNone) { + if (createBlock) { + // Remap block storage + qualifier.setBlockStorage(storageOverride); + + // check that the change didn't create errors + blockQualifierCheck(loc, qualifier, false); + } + + // remap meber storage as well + memberType.getQualifier().setBlockStorage(storageOverride); + } + } +} + +void TParseContext::growAtomicCounterBlock(int binding, const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) +{ + bool createBlock = atomicCounterBuffers.find(binding) == atomicCounterBuffers.end(); + + if (createBlock) { + atomicCounterBlockSet = intermediate.getAtomicCounterBlockSet(); + } + + // use base class function to create/expand block + TParseContextBase::growAtomicCounterBlock(binding, loc, memberType, memberName, typeList); + TQualifier& qualifier = atomicCounterBuffers[binding]->getWritableType().getQualifier(); + qualifier.defaultBlock = true; + + if (spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) { + // check for a Block storage override + TBlockStorageClass storageOverride = intermediate.getBlockStorageOverride(getAtomicCounterBlockName()); + + if (storageOverride != EbsNone) { + if (createBlock) { + // Remap block storage + + qualifier.setBlockStorage(storageOverride); + + // check that the change didn't create errors + blockQualifierCheck(loc, qualifier, false); + } + + // remap meber storage as well + memberType.getQualifier().setBlockStorage(storageOverride); + } + } +} + +const char* TParseContext::getGlobalUniformBlockName() const +{ + const char* name = intermediate.getGlobalUniformBlockName(); + if (std::string(name) == "") + return "gl_DefaultUniformBlock"; + else + return name; +} +void TParseContext::finalizeGlobalUniformBlockLayout(TVariable&) +{ +} +void TParseContext::setUniformBlockDefaults(TType& block) const +{ + block.getQualifier().layoutPacking = ElpStd140; + block.getQualifier().layoutMatrix = ElmColumnMajor; +} + + +const char* TParseContext::getAtomicCounterBlockName() const +{ + const char* name = intermediate.getAtomicCounterBlockName(); + if (std::string(name) == "") + return "gl_AtomicCounterBlock"; + else + return name; +} +void TParseContext::finalizeAtomicCounterBlockLayout(TVariable&) +{ +} + +void TParseContext::setAtomicCounterBlockDefaults(TType& block) const +{ + block.getQualifier().layoutPacking = ElpStd430; + block.getQualifier().layoutMatrix = ElmRowMajor; +} + +void TParseContext::setInvariant(const TSourceLoc& loc, const char* builtin) { + TSymbol* symbol = symbolTable.find(builtin); + if (symbol && symbol->getType().getQualifier().isPipeOutput()) { + if (intermediate.inIoAccessed(builtin)) + warn(loc, "changing qualification after use", "invariant", builtin); + TSymbol* csymbol = symbolTable.copyUp(symbol); + csymbol->getWritableType().getQualifier().invariant = true; + } +} + void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& tokens) { #ifndef GLSLANG_WEB @@ -245,7 +362,9 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& else if (tokens[2].compare("off") == 0) contextPragma.optimize = false; else { - error(loc, "\"on\" or \"off\" expected after '(' for 'optimize' pragma", "#pragma", ""); + if(relaxedErrors()) + // If an implementation does not recognize the tokens following #pragma, then it will ignore that pragma. + warn(loc, "\"on\" or \"off\" expected after '(' for 'optimize' pragma", "#pragma", ""); return; } @@ -269,7 +388,9 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& else if (tokens[2].compare("off") == 0) contextPragma.debug = false; else { - error(loc, "\"on\" or \"off\" expected after '(' for 'debug' pragma", "#pragma", ""); + if(relaxedErrors()) + // If an implementation does not recognize the tokens following #pragma, then it will ignore that pragma. + warn(loc, "\"on\" or \"off\" expected after '(' for 'debug' pragma", "#pragma", ""); return; } @@ -293,8 +414,33 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& intermediate.setUseVariablePointers(); } else if (tokens[0].compare("once") == 0) { warn(loc, "not implemented", "#pragma once", ""); - } else if (tokens[0].compare("glslang_binary_double_output") == 0) + } else if (tokens[0].compare("glslang_binary_double_output") == 0) { intermediate.setBinaryDoubleOutput(); + } else if (spvVersion.spv > 0 && tokens[0].compare("STDGL") == 0 && + tokens[1].compare("invariant") == 0 && tokens[3].compare("all") == 0) { + intermediate.setInvariantAll(); + // Set all builtin out variables invariant if declared + setInvariant(loc, "gl_Position"); + setInvariant(loc, "gl_PointSize"); + setInvariant(loc, "gl_ClipDistance"); + setInvariant(loc, "gl_CullDistance"); + setInvariant(loc, "gl_TessLevelOuter"); + setInvariant(loc, "gl_TessLevelInner"); + setInvariant(loc, "gl_PrimitiveID"); + setInvariant(loc, "gl_Layer"); + setInvariant(loc, "gl_ViewportIndex"); + setInvariant(loc, "gl_FragDepth"); + setInvariant(loc, "gl_SampleMask"); + setInvariant(loc, "gl_ClipVertex"); + setInvariant(loc, "gl_FrontColor"); + setInvariant(loc, "gl_BackColor"); + setInvariant(loc, "gl_FrontSecondaryColor"); + setInvariant(loc, "gl_BackSecondaryColor"); + setInvariant(loc, "gl_TexCoord"); + setInvariant(loc, "gl_FogFragCoord"); + setInvariant(loc, "gl_FragColor"); + setInvariant(loc, "gl_FragData"); + } #endif } @@ -427,8 +573,18 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn #ifndef GLSLANG_WEB if (base->isReference() && ! base->isArray()) { requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference indexing"); - result = intermediate.addBinaryMath(EOpAdd, base, index, loc); - result->setType(base->getType()); + if (base->getType().getReferentType()->containsUnsizedArray()) { + error(loc, "cannot index reference to buffer containing an unsized array", "", ""); + result = nullptr; + } else { + result = intermediate.addBinaryMath(EOpAdd, base, index, loc); + if (result != nullptr) + result->setType(base->getType()); + } + if (result == nullptr) { + error(loc, "cannot index buffer reference", "", ""); + result = intermediate.addConstantUnion(0.0, EbtFloat, loc); + } return result; } if (base->getAsSymbolNode() && isIoResizeArray(base->getType())) @@ -740,8 +896,11 @@ TIntermTyped* TParseContext::handleBinaryMath(const TSourceLoc& loc, const char* } TIntermTyped* result = nullptr; - if (allowed) + if (allowed) { + if ((left->isReference() || right->isReference())) + requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference math"); result = intermediate.addBinaryMath(op, left, right, loc); + } if (result == nullptr) binaryOpError(loc, str, left->getCompleteString(), right->getCompleteString()); @@ -821,50 +980,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm TIntermTyped* result = base; if ((base->isVector() || base->isScalar()) && (base->isFloatingDomain() || base->isIntegerDomain() || base->getBasicType() == EbtBool)) { - if (base->isScalar()) { - const char* dotFeature = "scalar swizzle"; - requireProfile(loc, ~EEsProfile, dotFeature); - profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, dotFeature); - } - - TSwizzleSelectors selectors; - parseSwizzleSelector(loc, field, base->getVectorSize(), selectors); - - if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitFloat()) - requireFloat16Arithmetic(loc, ".", "can't swizzle types containing float16"); - if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitInt()) - requireInt16Arithmetic(loc, ".", "can't swizzle types containing (u)int16"); - if (base->isVector() && selectors.size() != 1 && base->getType().contains8BitInt()) - requireInt8Arithmetic(loc, ".", "can't swizzle types containing (u)int8"); - - if (base->isScalar()) { - if (selectors.size() == 1) - return result; - else { - TType type(base->getBasicType(), EvqTemporary, selectors.size()); - // Swizzle operations propagate specialization-constantness - if (base->getQualifier().isSpecConstant()) - type.getQualifier().makeSpecConstant(); - return addConstructor(loc, base, type); - } - } - - if (base->getType().getQualifier().isFrontEndConstant()) - result = intermediate.foldSwizzle(base, selectors, loc); - else { - if (selectors.size() == 1) { - TIntermTyped* index = intermediate.addConstantUnion(selectors[0], loc); - result = intermediate.addIndex(EOpIndexDirect, base, index, loc); - result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision)); - } else { - TIntermTyped* index = intermediate.addSwizzle(selectors, loc); - result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc); - result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, selectors.size())); - } - // Swizzle operations propagate specialization-constantness - if (base->getType().getQualifier().isSpecConstant()) - result->getWritableType().getQualifier().makeSpecConstant(); - } + result = handleDotSwizzle(loc, base, field); } else if (base->isStruct() || base->isReference()) { const TTypeList* fields = base->isReference() ? base->getType().getReferentType()->getStruct() : @@ -905,6 +1021,60 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm return result; } +// +// Handle seeing a base.swizzle, a subset of base.identifier in the grammar. +// +TIntermTyped* TParseContext::handleDotSwizzle(const TSourceLoc& loc, TIntermTyped* base, const TString& field) +{ + TIntermTyped* result = base; + if (base->isScalar()) { + const char* dotFeature = "scalar swizzle"; + requireProfile(loc, ~EEsProfile, dotFeature); + profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, dotFeature); + } + + TSwizzleSelectors selectors; + parseSwizzleSelector(loc, field, base->getVectorSize(), selectors); + + if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitFloat()) + requireFloat16Arithmetic(loc, ".", "can't swizzle types containing float16"); + if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitInt()) + requireInt16Arithmetic(loc, ".", "can't swizzle types containing (u)int16"); + if (base->isVector() && selectors.size() != 1 && base->getType().contains8BitInt()) + requireInt8Arithmetic(loc, ".", "can't swizzle types containing (u)int8"); + + if (base->isScalar()) { + if (selectors.size() == 1) + return result; + else { + TType type(base->getBasicType(), EvqTemporary, selectors.size()); + // Swizzle operations propagate specialization-constantness + if (base->getQualifier().isSpecConstant()) + type.getQualifier().makeSpecConstant(); + return addConstructor(loc, base, type); + } + } + + if (base->getType().getQualifier().isFrontEndConstant()) + result = intermediate.foldSwizzle(base, selectors, loc); + else { + if (selectors.size() == 1) { + TIntermTyped* index = intermediate.addConstantUnion(selectors[0], loc); + result = intermediate.addIndex(EOpIndexDirect, base, index, loc); + result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision)); + } else { + TIntermTyped* index = intermediate.addSwizzle(selectors, loc); + result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc); + result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, selectors.size())); + } + // Swizzle operations propagate specialization-constantness + if (base->getType().getQualifier().isSpecConstant()) + result->getWritableType().getQualifier().makeSpecConstant(); + } + + return result; +} + void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* base, int member, const TString& memberName) { // a block that needs extension checking is either 'base', or if arrayed, @@ -957,12 +1127,31 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct TSymbol* symbol = symbolTable.find(function.getMangledName(), &builtIn); if (symbol && symbol->getAsFunction() && builtIn) requireProfile(loc, ~EEsProfile, "redefinition of built-in function"); +#ifndef GLSLANG_WEB + // Check the validity of using spirv_literal qualifier + for (int i = 0; i < function.getParamCount(); ++i) { + if (function[i].type->getQualifier().isSpirvLiteral() && function.getBuiltInOp() != EOpSpirvInst) + error(loc, "'spirv_literal' can only be used on functions defined with 'spirv_instruction' for argument", + function.getName().c_str(), "%d", i + 1); + } + + // For function declaration with SPIR-V instruction qualifier, always ignore the built-in function and + // respect this redeclared one. + if (symbol && builtIn && function.getBuiltInOp() == EOpSpirvInst) + symbol = nullptr; +#endif const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0; if (prevDec) { if (prevDec->isPrototyped() && prototype) profileRequires(loc, EEsProfile, 300, nullptr, "multiple prototypes for same function"); if (prevDec->getType() != function.getType()) error(loc, "overloaded functions must have the same return type", function.getName().c_str(), ""); +#ifndef GLSLANG_WEB + if (prevDec->getSpirvInstruction() != function.getSpirvInstruction()) { + error(loc, "overloaded functions must have the same qualifiers", function.getName().c_str(), + "spirv_instruction"); + } +#endif for (int i = 0; i < prevDec->getParamCount(); ++i) { if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage) error(loc, "overloaded functions must have the same parameter storage qualifiers for argument", function[i].type->getStorageQualifierString(), "%d", i+1); @@ -1102,6 +1291,14 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction { TIntermTyped* result = nullptr; + if (spvVersion.vulkan != 0 && spvVersion.vulkanRelaxed) { + // allow calls that are invalid in Vulkan Semantics to be invisibily + // remapped to equivalent valid functions + result = vkRelaxedRemapFunctionCall(loc, function, arguments); + if (result) + return result; + } + if (function->getBuiltInOp() == EOpArrayLength) result = handleLengthMethod(loc, function, arguments); else if (function->getBuiltInOp() != EOpNull) { @@ -1156,6 +1353,15 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped())) error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", ""); } +#ifndef GLSLANG_WEB + if (formalQualifier.isSpirvLiteral()) { + if (!arg->getAsTyped()->getQualifier().isFrontEndConstant()) { + error(arguments->getLoc(), + "Non front-end constant expressions cannot be passed for 'spirv_literal' parameters.", + "spirv_literal", ""); + } + } +#endif const TType& argType = arg->getAsTyped()->getType(); const TQualifier& argQualifier = argType.getQualifier(); if (argQualifier.isMemory() && (argType.containsOpaque() || argType.isReference())) { @@ -1210,6 +1416,11 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction if (builtIn && fnCandidate->getBuiltInOp() != EOpNull) { // A function call mapped to a built-in operation. result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate); +#ifndef GLSLANG_WEB + } else if (fnCandidate->getBuiltInOp() == EOpSpirvInst) { + // When SPIR-V instruction qualifier is specified, the function call is still mapped to a built-in operation. + result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate); +#endif } else { // This is a function call not mapped to built-in operator. // It could still be a built-in function, but only if PureOperatorBuiltins == false. @@ -1273,7 +1484,7 @@ TIntermTyped* TParseContext::handleBuiltInFunctionCall(TSourceLoc loc, TIntermNo TIntermTyped *result = intermediate.addBuiltInFunctionCall(loc, function.getBuiltInOp(), function.getParamCount() == 1, arguments, function.getType()); - if (obeyPrecisionQualifiers()) + if (result != nullptr && obeyPrecisionQualifiers()) computeBuiltinPrecisions(*result, function); if (result == nullptr) { @@ -1287,6 +1498,35 @@ TIntermTyped* TParseContext::handleBuiltInFunctionCall(TSourceLoc loc, TIntermNo } else if (result->getAsOperator()) builtInOpCheck(loc, function, *result->getAsOperator()); +#ifndef GLSLANG_WEB + // Special handling for function call with SPIR-V instruction qualifier specified + if (function.getBuiltInOp() == EOpSpirvInst) { + if (auto agg = result->getAsAggregate()) { + // Propogate spirv_by_reference/spirv_literal from parameters to arguments + auto& sequence = agg->getSequence(); + for (unsigned i = 0; i < sequence.size(); ++i) { + if (function[i].type->getQualifier().isSpirvByReference()) + sequence[i]->getAsTyped()->getQualifier().setSpirvByReference(); + if (function[i].type->getQualifier().isSpirvLiteral()) + sequence[i]->getAsTyped()->getQualifier().setSpirvLiteral(); + } + + // Attach the function call to SPIR-V intruction + agg->setSpirvInstruction(function.getSpirvInstruction()); + } else if (auto unaryNode = result->getAsUnaryNode()) { + // Propogate spirv_by_reference/spirv_literal from parameters to arguments + if (function[0].type->getQualifier().isSpirvByReference()) + unaryNode->getOperand()->getQualifier().setSpirvByReference(); + if (function[0].type->getQualifier().isSpirvLiteral()) + unaryNode->getOperand()->getQualifier().setSpirvLiteral(); + + // Attach the function call to SPIR-V intruction + unaryNode->setSpirvInstruction(function.getSpirvInstruction()); + } else + assert(0); + } +#endif + return result; } @@ -1353,6 +1593,9 @@ void TParseContext::computeBuiltinPrecisions(TIntermTyped& node, const TFunction case EOpInterpolateAtSample: numArgs = 1; break; + case EOpDebugPrintf: + numArgs = 0; + break; default: break; } @@ -1390,23 +1633,28 @@ TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermType #endif functionReturnsValue = true; + TIntermBranch* branch = nullptr; if (currentFunctionType->getBasicType() == EbtVoid) { error(loc, "void function cannot return a value", "return", ""); - return intermediate.addBranch(EOpReturn, loc); + branch = intermediate.addBranch(EOpReturn, loc); } else if (*currentFunctionType != value->getType()) { TIntermTyped* converted = intermediate.addConversion(EOpReturn, *currentFunctionType, value); if (converted) { if (*currentFunctionType != converted->getType()) error(loc, "cannot convert return value to function return type", "return", ""); if (version < 420) - warn(loc, "type conversion on return values was not explicitly allowed until version 420", "return", ""); - return intermediate.addBranch(EOpReturn, converted, loc); + warn(loc, "type conversion on return values was not explicitly allowed until version 420", + "return", ""); + branch = intermediate.addBranch(EOpReturn, converted, loc); } else { error(loc, "type does not match, or is not convertible to, the function's return type", "return", ""); - return intermediate.addBranch(EOpReturn, value, loc); + branch = intermediate.addBranch(EOpReturn, value, loc); } } else - return intermediate.addBranch(EOpReturn, value, loc); + branch = intermediate.addBranch(EOpReturn, value, loc); + + branch->updatePrecision(currentFunctionType->getQualifier().precision); + return branch; } // See if the operation is being done in an illegal location. @@ -1650,6 +1898,14 @@ TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& funct #endif } +TIntermTyped* TParseContext::addAssign(const TSourceLoc& loc, TOperator op, TIntermTyped* left, TIntermTyped* right) +{ + if ((op == EOpAddAssign || op == EOpSubAssign) && left->isReference()) + requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "+= and -= on a buffer reference"); + + return intermediate.addAssign(op, left, right, loc); +} + void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction& fnCandidate, const TIntermOperator& callNode) { const TIntermSequence* argp = &callNode.getAsAggregate()->getSequence(); @@ -1672,9 +1928,13 @@ void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction& unsigned int semantics = 0, storageClassSemantics = 0; unsigned int semantics2 = 0, storageClassSemantics2 = 0; + const TIntermTyped* arg0 = (*argp)[0]->getAsTyped(); + const bool isMS = arg0->getBasicType() == EbtSampler && arg0->getType().getSampler().isMultiSample(); + // Grab the semantics and storage class semantics from the operands, based on opcode switch (callNode.getOp()) { case EOpAtomicAdd: + case EOpAtomicSubtract: case EOpAtomicMin: case EOpAtomicMax: case EOpAtomicAnd: @@ -1704,18 +1964,18 @@ void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction& case EOpImageAtomicXor: case EOpImageAtomicExchange: case EOpImageAtomicStore: - storageClassSemantics = (*argp)[4]->getAsConstantUnion()->getConstArray()[0].getIConst(); - semantics = (*argp)[5]->getAsConstantUnion()->getConstArray()[0].getIConst(); + storageClassSemantics = (*argp)[isMS ? 5 : 4]->getAsConstantUnion()->getConstArray()[0].getIConst(); + semantics = (*argp)[isMS ? 6 : 5]->getAsConstantUnion()->getConstArray()[0].getIConst(); break; case EOpImageAtomicLoad: - storageClassSemantics = (*argp)[3]->getAsConstantUnion()->getConstArray()[0].getIConst(); - semantics = (*argp)[4]->getAsConstantUnion()->getConstArray()[0].getIConst(); + storageClassSemantics = (*argp)[isMS ? 4 : 3]->getAsConstantUnion()->getConstArray()[0].getIConst(); + semantics = (*argp)[isMS ? 5 : 4]->getAsConstantUnion()->getConstArray()[0].getIConst(); break; case EOpImageAtomicCompSwap: - storageClassSemantics = (*argp)[5]->getAsConstantUnion()->getConstArray()[0].getIConst(); - semantics = (*argp)[6]->getAsConstantUnion()->getConstArray()[0].getIConst(); - storageClassSemantics2 = (*argp)[7]->getAsConstantUnion()->getConstArray()[0].getIConst(); - semantics2 = (*argp)[8]->getAsConstantUnion()->getConstArray()[0].getIConst(); + storageClassSemantics = (*argp)[isMS ? 6 : 5]->getAsConstantUnion()->getConstArray()[0].getIConst(); + semantics = (*argp)[isMS ? 7 : 6]->getAsConstantUnion()->getConstArray()[0].getIConst(); + storageClassSemantics2 = (*argp)[isMS ? 8 : 7]->getAsConstantUnion()->getConstArray()[0].getIConst(); + semantics2 = (*argp)[isMS ? 9 : 8]->getAsConstantUnion()->getConstArray()[0].getIConst(); break; case EOpBarrier: @@ -1933,7 +2193,13 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan profileRequires(loc, ~EEsProfile, 450, nullptr, feature); requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature); } - + // As per GL_ARB_sparse_texture2 extension "Offsets" parameter must be constant integral expression + // for sparseTextureGatherOffsetsARB just as textureGatherOffsets + if (callNode.getOp() == EOpSparseTextureGatherOffsets) { + int offsetsArg = arg0->getType().getSampler().shadow ? 3 : 2; + if (!(*argp)[offsetsArg]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "offsets", ""); + } break; } @@ -2006,18 +2272,30 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan if (arg > 0) { #ifndef GLSLANG_WEB - bool f16ShadowCompare = (*argp)[1]->getAsTyped()->getBasicType() == EbtFloat16 && arg0->getType().getSampler().shadow; + bool f16ShadowCompare = (*argp)[1]->getAsTyped()->getBasicType() == EbtFloat16 && + arg0->getType().getSampler().shadow; if (f16ShadowCompare) ++arg; #endif - if (! (*argp)[arg]->getAsConstantUnion()) + if (! (*argp)[arg]->getAsTyped()->getQualifier().isConstant()) error(loc, "argument must be compile-time constant", "texel offset", ""); - else { + else if ((*argp)[arg]->getAsConstantUnion()) { const TType& type = (*argp)[arg]->getAsTyped()->getType(); for (int c = 0; c < type.getVectorSize(); ++c) { int offset = (*argp)[arg]->getAsConstantUnion()->getConstArray()[c].getIConst(); if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset) - error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]"); + error(loc, "value is out of range:", "texel offset", + "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]"); + } + } + + if (callNode.getOp() == EOpTextureOffset) { + TSampler s = arg0->getType().getSampler(); + if (s.is2D() && s.isArrayed() && s.isShadow()) { + if (isEsProfile()) + error(loc, "TextureOffset does not support sampler2DArrayShadow : ", "sampler", "ES Profile"); + else if (version <= 420) + error(loc, "TextureOffset does not support sampler2DArrayShadow : ", "sampler", "version <= 420"); } } } @@ -2028,12 +2306,51 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan #ifndef GLSLANG_WEB case EOpTraceNV: if (!(*argp)[10]->getAsConstantUnion()) - error(loc, "argument must be compile-time constant", "payload number", ""); + error(loc, "argument must be compile-time constant", "payload number", "a"); + break; + case EOpTraceRayMotionNV: + if (!(*argp)[11]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "payload number", "a"); + break; + case EOpTraceKHR: + if (!(*argp)[10]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "payload number", "a"); + else { + unsigned int location = (*argp)[10]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (intermediate.checkLocationRT(0, location) < 0) + error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location); + } break; case EOpExecuteCallableNV: if (!(*argp)[1]->getAsConstantUnion()) error(loc, "argument must be compile-time constant", "callable data number", ""); break; + case EOpExecuteCallableKHR: + if (!(*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "callable data number", ""); + else { + unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (intermediate.checkLocationRT(1, location) < 0) + error(loc, "with layout(location =", "no callableDataEXT/callableDataInEXT declared", "%d)", location); + } + break; + + case EOpRayQueryGetIntersectionType: + case EOpRayQueryGetIntersectionT: + case EOpRayQueryGetIntersectionInstanceCustomIndex: + case EOpRayQueryGetIntersectionInstanceId: + case EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset: + case EOpRayQueryGetIntersectionGeometryIndex: + case EOpRayQueryGetIntersectionPrimitiveIndex: + case EOpRayQueryGetIntersectionBarycentrics: + case EOpRayQueryGetIntersectionFrontFace: + case EOpRayQueryGetIntersectionObjectRayDirection: + case EOpRayQueryGetIntersectionObjectRayOrigin: + case EOpRayQueryGetIntersectionObjectToWorld: + case EOpRayQueryGetIntersectionWorldToObject: + if (!(*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "committed", ""); + break; case EOpTextureQuerySamples: case EOpImageQuerySamples: @@ -2054,14 +2371,32 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan { // Make sure the image types have the correct layout() format and correct argument types const TType& imageType = arg0->getType(); - if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) { - if (imageType.getQualifier().getFormat() != ElfR32i && imageType.getQualifier().getFormat() != ElfR32ui) + if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint || + imageType.getSampler().type == EbtInt64 || imageType.getSampler().type == EbtUint64) { + if (imageType.getQualifier().getFormat() != ElfR32i && imageType.getQualifier().getFormat() != ElfR32ui && + imageType.getQualifier().getFormat() != ElfR64i && imageType.getQualifier().getFormat() != ElfR64ui) error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), ""); - } else { - if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0) + if (callNode.getType().getBasicType() == EbtInt64 && imageType.getQualifier().getFormat() != ElfR64i) + error(loc, "only supported on image with format r64i", fnCandidate.getName().c_str(), ""); + else if (callNode.getType().getBasicType() == EbtUint64 && imageType.getQualifier().getFormat() != ElfR64ui) + error(loc, "only supported on image with format r64ui", fnCandidate.getName().c_str(), ""); + } else if (imageType.getSampler().type == EbtFloat) { + if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") == 0) { + // imageAtomicExchange doesn't require an extension + } else if ((fnCandidate.getName().compare(0, 14, "imageAtomicAdd") == 0) || + (fnCandidate.getName().compare(0, 15, "imageAtomicLoad") == 0) || + (fnCandidate.getName().compare(0, 16, "imageAtomicStore") == 0)) { + requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float, fnCandidate.getName().c_str()); + } else if ((fnCandidate.getName().compare(0, 14, "imageAtomicMin") == 0) || + (fnCandidate.getName().compare(0, 14, "imageAtomicMax") == 0)) { + requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str()); + } else { error(loc, "only supported on integer images", fnCandidate.getName().c_str(), ""); - else if (imageType.getQualifier().getFormat() != ElfR32f && isEsProfile()) + } + if (imageType.getQualifier().getFormat() != ElfR32f && isEsProfile()) error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), ""); + } else { + error(loc, "not supported on this image type", fnCandidate.getName().c_str(), ""); } const size_t maxArgs = imageType.getSampler().isMultiSample() ? 5 : 4; @@ -2074,6 +2409,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan } case EOpAtomicAdd: + case EOpAtomicSubtract: case EOpAtomicMin: case EOpAtomicMax: case EOpAtomicAnd: @@ -2087,11 +2423,39 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan if (argp->size() > 3) { requireExtensions(loc, 1, &E_GL_KHR_memory_scope_semantics, fnCandidate.getName().c_str()); memorySemanticsCheck(loc, fnCandidate, callNode); + if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange || + callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpAtomicStore) && + (arg0->getType().getBasicType() == EbtFloat || + arg0->getType().getBasicType() == EbtDouble)) { + requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float, fnCandidate.getName().c_str()); + } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange || + callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpAtomicStore || + callNode.getOp() == EOpAtomicMin || callNode.getOp() == EOpAtomicMax) && + arg0->getType().isFloatingDomain()) { + requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str()); + } } else if (arg0->getType().getBasicType() == EbtInt64 || arg0->getType().getBasicType() == EbtUint64) { const char* const extensions[2] = { E_GL_NV_shader_atomic_int64, E_GL_EXT_shader_atomic_int64 }; requireExtensions(loc, 2, extensions, fnCandidate.getName().c_str()); - } + } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange) && + (arg0->getType().getBasicType() == EbtFloat || + arg0->getType().getBasicType() == EbtDouble)) { + requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float, fnCandidate.getName().c_str()); + } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange || + callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpAtomicStore || + callNode.getOp() == EOpAtomicMin || callNode.getOp() == EOpAtomicMax) && + arg0->getType().isFloatingDomain()) { + requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str()); + } + + const TIntermTyped* base = TIntermediate::findLValueBase(arg0, true , true); + const TType* refType = (base->getType().isReference()) ? base->getType().getReferentType() : nullptr; + const TQualifier& qualifier = (refType != nullptr) ? refType->getQualifier() : base->getType().getQualifier(); + if (qualifier.storage != EvqShared && qualifier.storage != EvqBuffer) + error(loc,"Atomic memory function can only be used for shader storage block member or shared variable.", + fnCandidate.getName().c_str(), ""); + break; } @@ -2172,6 +2536,28 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan memorySemanticsCheck(loc, fnCandidate, callNode); } break; + + case EOpMix: + if (profile == EEsProfile && version < 310) { + // Look for specific signatures + if ((*argp)[0]->getAsTyped()->getBasicType() != EbtFloat && + (*argp)[1]->getAsTyped()->getBasicType() != EbtFloat && + (*argp)[2]->getAsTyped()->getBasicType() == EbtBool) { + requireExtensions(loc, 1, &E_GL_EXT_shader_integer_mix, "specific signature of builtin mix"); + } + } + + if (profile != EEsProfile && version < 450) { + if ((*argp)[0]->getAsTyped()->getBasicType() != EbtFloat && + (*argp)[0]->getAsTyped()->getBasicType() != EbtDouble && + (*argp)[1]->getAsTyped()->getBasicType() != EbtFloat && + (*argp)[1]->getAsTyped()->getBasicType() != EbtDouble && + (*argp)[2]->getAsTyped()->getBasicType() == EbtBool) { + requireExtensions(loc, 1, &E_GL_EXT_shader_integer_mix, fnCandidate.getName().c_str()); + } + } + + break; #endif default: @@ -2624,6 +3010,11 @@ void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TInt if (!(symNode && symNode->getQualifier().isWriteOnly())) // base class checks if (symNode && symNode->getQualifier().isExplicitInterpolation()) error(loc, "can't read from explicitly-interpolated object: ", op, symNode->getName().c_str()); + + // local_size_{xyz} must be assigned or specialized before gl_WorkGroupSize can be assigned. + if(node->getQualifier().builtIn == EbvWorkGroupSize && + !(intermediate.isLocalSizeSet() || intermediate.isLocalSizeSpecialized())) + error(loc, "can't read from gl_WorkGroupSize before a fixed workgroup size has been declared", op, ""); } // @@ -2666,7 +3057,8 @@ void TParseContext::reservedErrorCheck(const TSourceLoc& loc, const TString& ide // "Identifiers starting with "gl_" are reserved for use by OpenGL, and may not be // declared in a shader; this results in a compile-time error." if (! symbolTable.atBuiltInLevel()) { - if (builtInName(identifier)) + if (builtInName(identifier) && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) + // The extension GL_EXT_spirv_intrinsics allows us to declare identifiers starting with "gl_". error(loc, "identifiers starting with \"gl_\" are reserved", identifier.c_str(), ""); // "__" are not supposed to be an error. ES 300 (and desktop) added the clarification: @@ -2674,7 +3066,8 @@ void TParseContext::reservedErrorCheck(const TSourceLoc& loc, const TString& ide // reserved; using such a name does not itself result in an error, but may result // in undefined behavior." // however, before that, ES tests required an error. - if (identifier.find("__") != TString::npos) { + if (identifier.find("__") != TString::npos && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) { + // The extension GL_EXT_spirv_intrinsics allows us to declare identifiers starting with "__". if (isEsProfile() && version < 300) error(loc, "identifiers containing consecutive underscores (\"__\") are reserved, and an error if version < 300", identifier.c_str(), ""); else @@ -2695,18 +3088,23 @@ void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* iden // single underscore) are also reserved, and defining such a name results in a // compile-time error." // however, before that, ES tests required an error. - if (strncmp(identifier, "GL_", 3) == 0) + if (strncmp(identifier, "GL_", 3) == 0 && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) + // The extension GL_EXT_spirv_intrinsics allows us to declare macros prefixed with "GL_". ppError(loc, "names beginning with \"GL_\" can't be (un)defined:", op, identifier); else if (strncmp(identifier, "defined", 8) == 0) - ppError(loc, "\"defined\" can't be (un)defined:", op, identifier); - else if (strstr(identifier, "__") != 0) { + if (relaxedErrors()) + ppWarn(loc, "\"defined\" is (un)defined:", op, identifier); + else + ppError(loc, "\"defined\" can't be (un)defined:", op, identifier); + else if (strstr(identifier, "__") != 0 && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) { + // The extension GL_EXT_spirv_intrinsics allows us to declare macros prefixed with "__". if (isEsProfile() && version >= 300 && (strcmp(identifier, "__LINE__") == 0 || strcmp(identifier, "__FILE__") == 0 || strcmp(identifier, "__VERSION__") == 0)) ppError(loc, "predefined names can't be (un)defined:", op, identifier); else { - if (isEsProfile() && version < 300) + if (isEsProfile() && version < 300 && !relaxedErrors()) ppError(loc, "names containing consecutive underscores are reserved, and an error if version < 300:", op, identifier); else ppWarn(loc, "names containing consecutive underscores are reserved:", op, identifier); @@ -2847,6 +3245,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T bool matrixInMatrix = false; bool arrayArg = false; bool floatArgument = false; + bool intArgument = false; for (int arg = 0; arg < function.getParamCount(); ++arg) { if (function[arg].type->isArray()) { if (function[arg].type->isUnsizedArray()) { @@ -2877,6 +3276,8 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T specConstType = true; if (function[arg].type->isFloatingDomain()) floatArgument = true; + if (function[arg].type->isIntegerDomain()) + intArgument = true; if (type.isStruct()) { if (function[arg].type->contains16BitFloat()) { requireFloat16Arithmetic(loc, "constructor", "can't construct structure containing 16-bit type"); @@ -2982,6 +3383,15 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T // and aren't making an array. makeSpecConst = ! floatArgument && ! type.isArray(); break; + + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + // This was the list of valid ones, if they aren't converting from int + // and aren't making an array. + makeSpecConst = ! intArgument && !type.isArray(); + break; + default: // anything else wasn't white-listed in the spec as a conversion makeSpecConst = false; @@ -3083,7 +3493,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T error(loc, "constructor argument does not have a type", "constructor", ""); return true; } - if (op != EOpConstructStruct && typed->getBasicType() == EbtSampler) { + if (op != EOpConstructStruct && op != EOpConstructNonuniform && typed->getBasicType() == EbtSampler) { error(loc, "cannot convert a sampler", "constructor", ""); return true; } @@ -3128,7 +3538,7 @@ bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const if (function[0].type->getBasicType() != EbtSampler || ! function[0].type->getSampler().isTexture() || function[0].type->isArray()) { - error(loc, "sampler-constructor first argument must be a scalar textureXXX type", token, ""); + error(loc, "sampler-constructor first argument must be a scalar *texture* type", token, ""); return true; } // simulate the first argument's impact on the result type, so it can be compared with the encapsulated operator!=() @@ -3136,7 +3546,8 @@ bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const texture.setCombined(false); texture.shadow = false; if (texture != function[0].type->getSampler()) { - error(loc, "sampler-constructor first argument must match type and dimensionality of constructor type", token, ""); + error(loc, "sampler-constructor first argument must be a *texture* type" + " matching the dimensionality and sampled type of the constructor", token, ""); return true; } @@ -3146,7 +3557,7 @@ bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const if ( function[1].type->getBasicType() != EbtSampler || ! function[1].type->getSampler().isPureSampler() || function[1].type->isArray()) { - error(loc, "sampler-constructor second argument must be a scalar type 'sampler'", token, ""); + error(loc, "sampler-constructor second argument must be a scalar sampler or samplerShadow", token, ""); return true; } @@ -3222,14 +3633,14 @@ void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, co error(loc, "atomic_uints can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); } -void TParseContext::accStructNVCheck(const TSourceLoc& loc, const TType& type, const TString& identifier) +void TParseContext::accStructCheck(const TSourceLoc& loc, const TType& type, const TString& identifier) { if (type.getQualifier().storage == EvqUniform) return; - if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtAccStructNV)) + if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtAccStruct)) error(loc, "non-uniform struct contains an accelerationStructureNV:", type.getBasicTypeString().c_str(), identifier.c_str()); - else if (type.getBasicType() == EbtAccStructNV && type.getQualifier().storage != EvqUniform) + else if (type.getBasicType() == EbtAccStruct && type.getQualifier().storage != EvqUniform) error(loc, "accelerationStructureNV can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); @@ -3247,7 +3658,7 @@ void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& t if (type.containsNonOpaque()) { // Vulkan doesn't allow transparent uniforms outside of blocks - if (spvVersion.vulkan > 0) + if (spvVersion.vulkan > 0 && !spvVersion.vulkanRelaxed) vulkanRemoved(loc, "non-opaque uniforms outside a block"); // OpenGL wants locations on these (unless they are getting automapped) if (spvVersion.openGl > 0 && !type.getQualifier().hasLocation() && !intermediate.getAutoMapLocations()) @@ -3260,7 +3671,7 @@ void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& t // void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType) { - globalQualifierFixCheck(publicType.loc, publicType.qualifier); + globalQualifierFixCheck(publicType.loc, publicType.qualifier, true); checkNoShaderLayouts(publicType.loc, publicType.shaderQualifiers); if (publicType.qualifier.isNonUniform()) { error(publicType.loc, "not allowed on block or structure members", "nonuniformEXT", ""); @@ -3271,7 +3682,7 @@ void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType) // // Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level. // -void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier) +void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck) { bool nonuniformOkay = false; @@ -3287,6 +3698,8 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q profileRequires(loc, ENoProfile, 130, nullptr, "out for stage outputs"); profileRequires(loc, EEsProfile, 300, nullptr, "out for stage outputs"); qualifier.storage = EvqVaryingOut; + if (intermediate.isInvariantAll()) + qualifier.invariant = true; break; case EvqInOut: qualifier.storage = EvqVaryingIn; @@ -3296,6 +3709,16 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q case EvqTemporary: nonuniformOkay = true; break; + case EvqUniform: + // According to GLSL spec: The std430 qualifier is supported only for shader storage blocks; a shader using + // the std430 qualifier on a uniform block will fail to compile. + // Only check the global declaration: layout(std430) uniform; + if (blockName == nullptr && + qualifier.layoutPacking == ElpStd430) + { + requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "default std430 layout for uniform"); + } + break; default: break; } @@ -3303,7 +3726,17 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q if (!nonuniformOkay && qualifier.isNonUniform()) error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", ""); - invariantCheck(loc, qualifier); +#ifndef GLSLANG_WEB + if (qualifier.isSpirvByReference()) + error(loc, "can only apply to parameter", "spirv_by_reference", ""); + + if (qualifier.isSpirvLiteral()) + error(loc, "can only apply to parameter", "spirv_literal", ""); +#endif + + // Storage qualifier isn't ready for memberQualifierCheck, we should skip invariantCheck for it. + if (!isMemberCheck || structNestingLevel > 0) + invariantCheck(loc, qualifier); } // @@ -3314,7 +3747,7 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali if (! symbolTable.atGlobalLevel()) return; - if (!(publicType.userDef && publicType.userDef->isReference())) { + if (!(publicType.userDef && publicType.userDef->isReference()) && !parsingBuiltins) { if (qualifier.isMemoryQualifierImageAndSSBOOnly() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer) { error(loc, "memory qualifiers cannot be used on this type", "", ""); } else if (qualifier.isMemory() && (publicType.basicType != EbtSampler) && !publicType.qualifier.isUniformOrBuffer()) { @@ -3327,6 +3760,11 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali !qualifier.hasBufferReference()) error(loc, "buffers can be declared only as blocks", "buffer", ""); + if (qualifier.storage != EvqVaryingIn && publicType.basicType == EbtDouble && + extensionTurnedOn(E_GL_ARB_vertex_attrib_64bit) && language == EShLangVertex && + version < 400) { + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 410, E_GL_ARB_gpu_shader_fp64, "vertex-shader `double` type"); + } if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut) return; @@ -3377,7 +3815,7 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali profileRequires(loc, ENoProfile, 150, nullptr, "vertex input arrays"); } if (publicType.basicType == EbtDouble) - profileRequires(loc, ~EEsProfile, 410, nullptr, "vertex-shader `double` type input"); + profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_vertex_attrib_64bit, "vertex-shader `double` type input"); if (qualifier.isAuxiliary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant) error(loc, "vertex input cannot be further qualified", "", ""); break; @@ -3513,12 +3951,14 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons dst.precision = src.precision; #ifndef GLSLANG_WEB - if (!force && ((src.coherent && (dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent)) || - (src.devicecoherent && (dst.coherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent)) || - (src.queuefamilycoherent && (dst.coherent || dst.devicecoherent || dst.workgroupcoherent || dst.subgroupcoherent)) || - (src.workgroupcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.subgroupcoherent)) || - (src.subgroupcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent)))) { - error(loc, "only one coherent/devicecoherent/queuefamilycoherent/workgroupcoherent/subgroupcoherent qualifier allowed", GetPrecisionQualifierString(src.precision), ""); + if (!force && ((src.coherent && (dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) || + (src.devicecoherent && (dst.coherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) || + (src.queuefamilycoherent && (dst.coherent || dst.devicecoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) || + (src.workgroupcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.subgroupcoherent || dst.shadercallcoherent)) || + (src.subgroupcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.shadercallcoherent)) || + (src.shadercallcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent)))) { + error(loc, "only one coherent/devicecoherent/queuefamilycoherent/workgroupcoherent/subgroupcoherent/shadercallcoherent qualifier allowed", + GetPrecisionQualifierString(src.precision), ""); } #endif // Layout qualifiers @@ -3546,6 +3986,7 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons MERGE_SINGLETON(queuefamilycoherent); MERGE_SINGLETON(workgroupcoherent); MERGE_SINGLETON(subgroupcoherent); + MERGE_SINGLETON(shadercallcoherent); MERGE_SINGLETON(nonprivate); MERGE_SINGLETON(volatil); MERGE_SINGLETON(restrict); @@ -3554,6 +3995,41 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons MERGE_SINGLETON(nonUniform); #endif +#ifndef GLSLANG_WEB + // SPIR-V storage class qualifier (GL_EXT_spirv_intrinsics) + dst.spirvStorageClass = src.spirvStorageClass; + + // SPIR-V decorate qualifiers (GL_EXT_spirv_intrinsics) + if (src.hasSprivDecorate()) { + if (dst.hasSprivDecorate()) { + const TSpirvDecorate& srcSpirvDecorate = src.getSpirvDecorate(); + TSpirvDecorate& dstSpirvDecorate = dst.getSpirvDecorate(); + for (auto& decorate : srcSpirvDecorate.decorates) { + if (dstSpirvDecorate.decorates.find(decorate.first) != dstSpirvDecorate.decorates.end()) + error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate", "(decoration=%u)", decorate.first); + else + dstSpirvDecorate.decorates.insert(decorate); + } + + for (auto& decorateId : srcSpirvDecorate.decorateIds) { + if (dstSpirvDecorate.decorateIds.find(decorateId.first) != dstSpirvDecorate.decorateIds.end()) + error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate_id", "(decoration=%u)", decorateId.first); + else + dstSpirvDecorate.decorateIds.insert(decorateId); + } + + for (auto& decorateString : srcSpirvDecorate.decorateStrings) { + if (dstSpirvDecorate.decorates.find(decorateString.first) != dstSpirvDecorate.decorates.end()) + error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate_string", "(decoration=%u)", decorateString.first); + else + dstSpirvDecorate.decorates.insert(decorateString); + } + } else { + dst.spirvDecorate = src.spirvDecorate; + } + } +#endif + if (repeated) error(loc, "replicated qualifiers", "", ""); } @@ -3967,6 +4443,9 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType if (isRuntimeLength(base)) return; + if (base.getType().getQualifier().builtIn == EbvSampleMask) + return; + // Check for last member of a bufferreference type, which is runtime sizeable // but doesn't support runtime length if (base.getType().getQualifier().storage == EvqBuffer) { @@ -3983,7 +4462,7 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType } // check for additional things allowed by GL_EXT_nonuniform_qualifier - if (base.getBasicType() == EbtSampler || base.getBasicType() == EbtAccStructNV || + if (base.getBasicType() == EbtSampler || base.getBasicType() == EbtAccStruct || base.getBasicType() == EbtRayQuery || (base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer())) requireExtensions(loc, 1, &E_GL_EXT_nonuniform_qualifier, "variable index"); else @@ -4110,6 +4589,8 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS (identifier == "gl_FragCoord" && ((nonEsRedecls && version >= 150) || esRedecls)) || identifier == "gl_ClipDistance" || identifier == "gl_CullDistance" || + identifier == "gl_ShadingRateEXT" || + identifier == "gl_PrimitiveShadingRateEXT" || identifier == "gl_FrontColor" || identifier == "gl_BackColor" || identifier == "gl_FrontSecondaryColor" || @@ -4135,8 +4616,10 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS // If it wasn't at a built-in level, then it's already been redeclared; // that is, this is a redeclaration of a redeclaration; reuse that initial // redeclaration. Otherwise, make the new one. - if (builtIn) + if (builtIn) { makeEditable(symbol); + symbolTable.amendSymbolIdLevel(*symbol); + } // Now, modify the type of the copy, as per the type of the current redeclaration. @@ -4487,6 +4970,7 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali type.getQualifier().queuefamilycoherent = qualifier.queuefamilycoherent; type.getQualifier().workgroupcoherent = qualifier.workgroupcoherent; type.getQualifier().subgroupcoherent = qualifier.subgroupcoherent; + type.getQualifier().shadercallcoherent = qualifier.shadercallcoherent; type.getQualifier().nonprivate = qualifier.nonprivate; type.getQualifier().readonly = qualifier.readonly; type.getQualifier().writeonly = qualifier.writeonly; @@ -4509,20 +4993,31 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali } if (qualifier.isNonUniform()) type.getQualifier().nonUniform = qualifier.nonUniform; +#ifndef GLSLANG_WEB + if (qualifier.isSpirvByReference()) + type.getQualifier().setSpirvByReference(); + if (qualifier.isSpirvLiteral()) { + if (type.getBasicType() == EbtFloat || type.getBasicType() == EbtInt || type.getBasicType() == EbtUint || + type.getBasicType() == EbtBool) + type.getQualifier().setSpirvLiteral(); + else + error(loc, "cannot use spirv_literal qualifier", type.getBasicTypeString().c_str(), ""); +#endif + } paramCheckFixStorage(loc, qualifier.storage, type); } void TParseContext::nestedBlockCheck(const TSourceLoc& loc) { - if (structNestingLevel > 0) + if (structNestingLevel > 0 || blockNestingLevel > 0) error(loc, "cannot nest a block definition inside a structure or block", "", ""); - ++structNestingLevel; + ++blockNestingLevel; } void TParseContext::nestedStructCheck(const TSourceLoc& loc) { - if (structNestingLevel > 0) + if (structNestingLevel > 0 || blockNestingLevel > 0) error(loc, "cannot nest a structure definition inside a structure or block", "", ""); ++structNestingLevel; } @@ -4664,7 +5159,7 @@ void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init, } // get the unique id of the loop index - int loopIndex = binaryInit->getLeft()->getAsSymbolNode()->getId(); + long long loopIndex = binaryInit->getLeft()->getAsSymbolNode()->getId(); inductiveLoopIds.insert(loopIndex); // condition's form must be "loop-index relational-operator constant-expression" @@ -4850,14 +5345,22 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi return; } if (id == TQualifier::getLayoutPackingString(ElpPacked)) { - if (spvVersion.spv != 0) - spvRemoved(loc, "packed"); + if (spvVersion.spv != 0) { + if (spvVersion.vulkanRelaxed) + return; // silently ignore qualifier + else + spvRemoved(loc, "packed"); + } publicType.qualifier.layoutPacking = ElpPacked; return; } if (id == TQualifier::getLayoutPackingString(ElpShared)) { - if (spvVersion.spv != 0) - spvRemoved(loc, "shared"); + if (spvVersion.spv != 0) { + if (spvVersion.vulkanRelaxed) + return; // silently ignore qualifier + else + spvRemoved(loc, "shared"); + } publicType.qualifier.layoutPacking = ElpShared; return; } @@ -4868,7 +5371,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi #ifndef GLSLANG_WEB if (id == TQualifier::getLayoutPackingString(ElpStd430)) { requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "std430"); - profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, "std430"); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_shader_storage_buffer_object, "std430"); profileRequires(loc, EEsProfile, 310, nullptr, "std430"); publicType.qualifier.layoutPacking = ElpStd430; return; @@ -5067,13 +5570,19 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi return; } } else { - if (language == EShLangRayGenNV || language == EShLangIntersectNV || - language == EShLangAnyHitNV || language == EShLangClosestHitNV || - language == EShLangMissNV || language == EShLangCallableNV) { - if (id == "shaderrecordnv") { - publicType.qualifier.layoutShaderRecordNV = true; + if (language == EShLangRayGen || language == EShLangIntersect || + language == EShLangAnyHit || language == EShLangClosestHit || + language == EShLangMiss || language == EShLangCallable) { + if (id == "shaderrecordnv" || id == "shaderrecordext") { + if (id == "shaderrecordnv") { + requireExtensions(loc, 1, &E_GL_NV_ray_tracing, "shader record NV"); + } else { + requireExtensions(loc, 1, &E_GL_EXT_ray_tracing, "shader record EXT"); + } + publicType.qualifier.layoutShaderRecord = true; return; } + } } if (language == EShLangCompute) { @@ -5088,6 +5597,12 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi } } } + + if (id == "primitive_culling") { + requireExtensions(loc, 1, &E_GL_EXT_ray_flags_primitive_culling, "primitive culling"); + publicType.shaderQualifiers.layoutPrimitiveCulling = true; + return; + } #endif error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), ""); @@ -5135,6 +5650,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi profileRequires(loc, EEsProfile, 310, nullptr, feature); } publicType.qualifier.layoutOffset = value; + publicType.qualifier.explicitOffset = true; if (nonLiteral) error(loc, "needs a literal integer", "offset", ""); return; @@ -5294,7 +5810,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi if (! IsPow2(value)) error(loc, "must be a power of 2", "buffer_reference_align", ""); else - publicType.qualifier.layoutBufferReferenceAlign = (unsigned int)std::log2(value); + publicType.qualifier.layoutBufferReferenceAlign = IntLog2(value); if (nonLiteral) error(loc, "needs a literal integer", "buffer_reference_align", ""); return; @@ -5347,10 +5863,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi case EShLangFragment: if (id == "index") { - requireProfile(loc, ECompatibilityProfile | ECoreProfile, "index layout qualifier on fragment output"); + requireProfile(loc, ECompatibilityProfile | ECoreProfile | EEsProfile, "index layout qualifier on fragment output"); const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location }; profileRequires(loc, ECompatibilityProfile | ECoreProfile, 330, 2, exts, "index layout qualifier on fragment output"); - + profileRequires(loc, EEsProfile ,310, E_GL_EXT_blend_func_extended, "index layout qualifier on fragment output"); // "It is also a compile-time error if a fragment shader sets a layout index to less than 0 or greater than 1." if (value < 0 || value > 1) { value = 0; @@ -5514,8 +6030,8 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie dst.layoutViewportRelative = true; if (src.layoutSecondaryViewportRelativeOffset != -2048) dst.layoutSecondaryViewportRelativeOffset = src.layoutSecondaryViewportRelativeOffset; - if (src.layoutShaderRecordNV) - dst.layoutShaderRecordNV = true; + if (src.layoutShaderRecord) + dst.layoutShaderRecord = true; if (src.pervertexNV) dst.pervertexNV = true; #endif @@ -5555,6 +6071,9 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb case EvqVaryingIn: case EvqVaryingOut: if (!type.getQualifier().isTaskMemory() && +#ifndef GLSLANG_WEB + !type.getQualifier().hasSprivDecorate() && +#endif (type.getBasicType() != EbtBlock || (!(*type.getStruct())[0].type->getQualifier().hasLocation() && (*type.getStruct())[0].type->getQualifier().builtIn == EbvNone))) @@ -5583,8 +6102,10 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb error(loc, "cannot specify on a variable declaration", "align", ""); if (qualifier.isPushConstant()) error(loc, "can only specify on a uniform block", "push_constant", ""); - if (qualifier.isShaderRecordNV()) + if (qualifier.isShaderRecord()) error(loc, "can only specify on a buffer block", "shaderRecordNV", ""); + if (qualifier.hasLocation() && type.isAtomic()) + error(loc, "cannot specify on atomic counter", "location", ""); } break; default: @@ -5614,6 +6135,11 @@ void TParseContext::layoutMemberLocationArrayCheck(const TSourceLoc& loc, bool m // Do layout error checking with respect to a type. void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) { +#ifndef GLSLANG_WEB + if (extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) + return; // Skip any check if GL_EXT_spirv_intrinsics is turned on +#endif + const TQualifier& qualifier = type.getQualifier(); // first, intra-layout qualifier-only error checking @@ -5657,11 +6183,11 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) error(loc, "cannot apply to uniform or buffer block", "location", ""); break; #ifndef GLSLANG_WEB - case EvqPayloadNV: - case EvqPayloadInNV: - case EvqHitAttrNV: - case EvqCallableDataNV: - case EvqCallableDataInNV: + case EvqPayload: + case EvqPayloadIn: + case EvqHitAttr: + case EvqCallableData: + case EvqCallableDataIn: break; #endif default: @@ -5684,6 +6210,8 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) int repeated = intermediate.addXfbBufferOffset(type); if (repeated >= 0) error(loc, "overlapping offsets at", "xfb_offset", "offset %d in buffer %d", repeated, qualifier.layoutXfbBuffer); + if (type.isUnsizedArray()) + error(loc, "unsized array", "xfb_offset", "in buffer %d", qualifier.layoutXfbBuffer); // "The offset must be a multiple of the size of the first component of the first // qualified variable or block member, or a compile-time error results. Further, if applied to an aggregate @@ -5720,16 +6248,12 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) if (type.getBasicType() == EbtSampler) { int lastBinding = qualifier.layoutBinding; if (type.isArray()) { - if (spvVersion.vulkan > 0) - lastBinding += 1; - else { + if (spvVersion.vulkan == 0) { if (type.isSizedArray()) - lastBinding += type.getCumulativeArraySize(); + lastBinding += (type.getCumulativeArraySize() - 1); else { - lastBinding += 1; #ifndef GLSLANG_WEB - if (spvVersion.vulkan == 0) - warn(loc, "assuming binding count of one for compile-time checking of binding numbers for unsized array", "[]", ""); + warn(loc, "assuming binding count of one for compile-time checking of binding numbers for unsized array", "[]", ""); #endif } } @@ -5739,7 +6263,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : ""); #endif } - if (type.isAtomic()) { + if (type.isAtomic() && !spvVersion.vulkanRelaxed) { if (qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) { error(loc, "atomic_uint binding is too large; see gl_MaxAtomicCounterBindings", "binding", ""); return; @@ -5756,7 +6280,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) if (spvVersion.spv > 0) { if (qualifier.isUniformOrBuffer()) { if (type.getBasicType() == EbtBlock && !qualifier.isPushConstant() && - !qualifier.isShaderRecordNV() && + !qualifier.isShaderRecord() && !qualifier.hasAttachment() && !qualifier.hasBufferReference()) error(loc, "uniform/buffer blocks require layout(binding=X)", "binding", ""); @@ -5813,7 +6337,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) if (qualifier.hasBufferReference() && type.getBasicType() != EbtBlock) error(loc, "can only be used with a block", "buffer_reference", ""); - if (qualifier.isShaderRecordNV() && type.getBasicType() != EbtBlock) + if (qualifier.isShaderRecord() && type.getBasicType() != EbtBlock) error(loc, "can only be used with a block", "shaderRecordNV", ""); // input attachment @@ -5853,12 +6377,28 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) } } +static bool storageCanHaveLayoutInBlock(const enum TStorageQualifier storage) +{ + switch (storage) { + case EvqUniform: + case EvqBuffer: + case EvqShared: + return true; + default: + return false; + } +} + // Do layout error checking that can be done within a layout qualifier proper, not needing to know // if there are blocks, atomic counters, variables, etc. void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier) { - if (qualifier.storage == EvqShared && qualifier.hasLayout()) - error(loc, "cannot apply layout qualifiers to a shared variable", "shared", ""); + if (qualifier.storage == EvqShared && qualifier.hasLayout()) { + if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4) { + error(loc, "shared block requires at least SPIR-V 1.4", "shared block", ""); + } + profileRequires(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shared_memory_block, "shared block"); + } // "It is a compile-time error to use *component* without also specifying the location qualifier (order does not matter)." if (qualifier.hasComponent() && ! qualifier.hasLocation()) @@ -5941,7 +6481,7 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier error(loc, "can only be used on an output", "xfb layout qualifier", ""); } if (qualifier.hasUniformLayout()) { - if (! qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory()) { + if (!storageCanHaveLayoutInBlock(qualifier.storage) && !qualifier.isTaskMemory()) { if (qualifier.hasMatrix() || qualifier.hasPacking()) error(loc, "matrix or packing qualifiers can only be used on a uniform or buffer", "layout", ""); if (qualifier.hasOffset() || qualifier.hasAlign()) @@ -5958,7 +6498,7 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier if (qualifier.storage != EvqBuffer) error(loc, "can only be used with buffer", "buffer_reference", ""); } - if (qualifier.isShaderRecordNV()) { + if (qualifier.isShaderRecord()) { if (qualifier.storage != EvqBuffer) error(loc, "can only be used with a buffer", "shaderRecordNV", ""); if (qualifier.hasBinding()) @@ -5967,7 +6507,7 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier error(loc, "cannot be used with shaderRecordNV", "set", ""); } - if (qualifier.storage == EvqHitAttrNV && qualifier.hasLayout()) { + if (qualifier.storage == EvqHitAttr && qualifier.hasLayout()) { error(loc, "cannot apply layout qualifiers to hitAttributeNV variable", "hitAttributeNV", ""); } } @@ -6018,6 +6558,8 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua error(loc, message, "num_views", ""); if (shaderQualifiers.interlockOrdering != EioNone) error(loc, message, TQualifier::getInterlockOrderingString(shaderQualifiers.interlockOrdering), ""); + if (shaderQualifiers.layoutPrimitiveCulling) + error(loc, "can only be applied as standalone", "primitive_culling", ""); #endif } @@ -6079,6 +6621,15 @@ const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunct #endif const TFunction* function = nullptr; + + // debugPrintfEXT has var args and is in the symbol table as "debugPrintfEXT()", + // mangled to "debugPrintfEXT(" + if (call.getName() == "debugPrintfEXT") { + TSymbol* symbol = symbolTable.find("debugPrintfEXT(", &builtIn); + if (symbol) + return symbol->getAsFunction(); + } + bool explicitTypesEnabled = extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types) || extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_int8) || extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_int16) || @@ -6088,10 +6639,16 @@ const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunct extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float32) || extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float64); - if (isEsProfile() || version < 120) + if (isEsProfile()) + function = (explicitTypesEnabled && version >= 310) + ? findFunctionExplicitTypes(loc, call, builtIn) + : ((extensionTurnedOn(E_GL_EXT_shader_implicit_conversions) && version >= 310) + ? findFunction120(loc, call, builtIn) + : findFunctionExact(loc, call, builtIn)); + else if (version < 120) function = findFunctionExact(loc, call, builtIn); else if (version < 400) - function = findFunction120(loc, call, builtIn); + function = extensionTurnedOn(E_GL_ARB_gpu_shader_fp64) ? findFunction400(loc, call, builtIn) : findFunction120(loc, call, builtIn); else if (explicitTypesEnabled) function = findFunctionExplicitTypes(loc, call, builtIn); else @@ -6379,26 +6936,177 @@ const TFunction* TParseContext::findFunctionExplicitTypes(const TSourceLoc& loc, return bestMatch; } +// +// Adjust function calls that aren't declared in Vulkan to a +// calls with equivalent effects +// +TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermNode* arguments) +{ + TIntermTyped* result = nullptr; + +#ifndef GLSLANG_WEB + if (function->getBuiltInOp() != EOpNull) { + return nullptr; + } + + if (function->getName() == "atomicCounterIncrement") { + // change atomicCounterIncrement into an atomicAdd of 1 + TString name("atomicAdd"); + TType uintType(EbtUint); + + TFunction realFunc(&name, function->getType()); + + for (int i = 0; i < function->getParamCount(); ++i) { + realFunc.addParameter((*function)[i]); + } + + TParameter tmpP = { 0, &uintType }; + realFunc.addParameter(tmpP); + arguments = intermediate.growAggregate(arguments, intermediate.addConstantUnion(1, loc, true)); + + result = handleFunctionCall(loc, &realFunc, arguments); + } else if (function->getName() == "atomicCounterDecrement") { + // change atomicCounterDecrement into an atomicAdd with -1 + // and subtract 1 from result, to return post-decrement value + TString name("atomicAdd"); + TType uintType(EbtUint); + + TFunction realFunc(&name, function->getType()); + + for (int i = 0; i < function->getParamCount(); ++i) { + realFunc.addParameter((*function)[i]); + } + + TParameter tmpP = { 0, &uintType }; + realFunc.addParameter(tmpP); + arguments = intermediate.growAggregate(arguments, intermediate.addConstantUnion(-1, loc, true)); + + result = handleFunctionCall(loc, &realFunc, arguments); + + // post decrement, so that it matches AtomicCounterDecrement semantics + if (result) { + result = handleBinaryMath(loc, "-", EOpSub, result, intermediate.addConstantUnion(1, loc, true)); + } + } else if (function->getName() == "atomicCounter") { + // change atomicCounter into a direct read of the variable + if (arguments->getAsTyped()) { + result = arguments->getAsTyped(); + } + } +#endif + + return result; +} + // When a declaration includes a type, but not a variable name, it can be used // to establish defaults. void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType& publicType) { #ifndef GLSLANG_WEB - if (publicType.basicType == EbtAtomicUint && publicType.qualifier.hasBinding() && - publicType.qualifier.hasOffset()) { + if (publicType.basicType == EbtAtomicUint && publicType.qualifier.hasBinding()) { if (publicType.qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) { error(loc, "atomic_uint binding is too large", "binding", ""); return; } - atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset; + if (publicType.qualifier.hasOffset()) + atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset; return; } + if (publicType.arraySizes) { + error(loc, "expect an array name", "", ""); + } + if (publicType.qualifier.hasLayout() && !publicType.qualifier.hasBufferReference()) warn(loc, "useless application of layout qualifier", "layout", ""); #endif } +bool TParseContext::vkRelaxedRemapUniformVariable(const TSourceLoc& loc, TString& identifier, const TPublicType&, + TArraySizes*, TIntermTyped* initializer, TType& type) +{ + if (parsingBuiltins || symbolTable.atBuiltInLevel() || !symbolTable.atGlobalLevel() || + type.getQualifier().storage != EvqUniform || + !(type.containsNonOpaque() +#ifndef GLSLANG_WEB + || type.getBasicType() == EbtAtomicUint +#endif + )) { + return false; + } + + if (type.getQualifier().hasLocation()) { + warn(loc, "ignoring layout qualifier for uniform", identifier.c_str(), "location"); + type.getQualifier().layoutLocation = TQualifier::layoutLocationEnd; + } + + if (initializer) { + warn(loc, "Ignoring initializer for uniform", identifier.c_str(), ""); + initializer = nullptr; + } + + if (type.isArray()) { + // do array size checks here + arraySizesCheck(loc, type.getQualifier(), type.getArraySizes(), initializer, false); + + if (arrayQualifierError(loc, type.getQualifier()) || arrayError(loc, type)) { + error(loc, "array param error", identifier.c_str(), ""); + } + } + + // do some checking on the type as it was declared + layoutTypeCheck(loc, type); + + int bufferBinding = TQualifier::layoutBindingEnd; + TVariable* updatedBlock = nullptr; + +#ifndef GLSLANG_WEB + // Convert atomic_uint into members of a buffer block + if (type.isAtomic()) { + type.setBasicType(EbtUint); + type.getQualifier().storage = EvqBuffer; + + type.getQualifier().volatil = true; + type.getQualifier().coherent = true; + + // xxTODO: use logic from fixOffset() to apply explicit member offset + bufferBinding = type.getQualifier().layoutBinding; + type.getQualifier().layoutBinding = TQualifier::layoutBindingEnd; + type.getQualifier().explicitOffset = false; + growAtomicCounterBlock(bufferBinding, loc, type, identifier, nullptr); + updatedBlock = atomicCounterBuffers[bufferBinding]; + } +#endif + + if (!updatedBlock) { + growGlobalUniformBlock(loc, type, identifier, nullptr); + updatedBlock = globalUniformBlock; + } + + // + // don't assign explicit member offsets here + // if any are assigned, need to be updated here and in the merge/link step + // fixBlockUniformOffsets(updatedBlock->getWritableType().getQualifier(), *updatedBlock->getWritableType().getWritableStruct()); + + // checks on update buffer object + layoutObjectCheck(loc, *updatedBlock); + + TSymbol* symbol = symbolTable.find(identifier); + + if (!symbol) { + if (updatedBlock == globalUniformBlock) + error(loc, "error adding uniform to default uniform block", identifier.c_str(), ""); + else + error(loc, "error adding atomic counter to atomic counter block", identifier.c_str(), ""); + return false; + } + + // merge qualifiers + mergeObjectLayoutQualifiers(updatedBlock->getWritableType().getQualifier(), type.getQualifier(), true); + + return true; +} + // // Do everything necessary to handle a variable (non-block) declaration. // Either redeclaring a variable, or making a new one, updating the symbol @@ -6420,6 +7128,12 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden type.copyArrayInnerSizes(publicType.arraySizes); arrayOfArrayVersionCheck(loc, type.getArraySizes()); + if (initializer) { + if (type.getBasicType() == EbtRayQuery) { + error(loc, "ray queries can only be initialized by using the rayQueryInitializeEXT intrinsic:", "=", identifier.c_str()); + } + } + if (type.isCoopMat()) { intermediate.setUseVulkanMemoryModel(); intermediate.setUseStorageBuffer(); @@ -6459,7 +7173,7 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden transparentOpaqueCheck(loc, type, identifier); #ifndef GLSLANG_WEB atomicUintCheck(loc, type, identifier); - accStructNVCheck(loc, type, identifier); + accStructCheck(loc, type, identifier); checkAndResizeMeshViewDim(loc, type, /*isBlockMember*/ false); #endif if (type.getQualifier().storage == EvqConst && type.containsReference()) { @@ -6478,6 +7192,22 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden if (type.getQualifier().storage == EvqShared && type.containsCoopMat()) error(loc, "qualifier", "Cooperative matrix types must not be used in shared memory", ""); + if (profile == EEsProfile) { + if (type.getQualifier().isPipeInput() && type.getBasicType() == EbtStruct) { + if (type.getQualifier().isArrayedIo(language)) { + TType perVertexType(type, 0); + if (perVertexType.containsArray() && perVertexType.containsBuiltIn() == false) { + error(loc, "A per vertex structure containing an array is not allowed as input in ES", type.getTypeName().c_str(), ""); + } + } + else if (type.containsArray() && type.containsBuiltIn() == false) { + error(loc, "A structure containing an array is not allowed as input in ES", type.getTypeName().c_str(), ""); + } + if (type.containsStructure()) + error(loc, "A structure containing an struct is not allowed as input in ES", type.getTypeName().c_str(), ""); + } + } + if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger)) error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", ""); if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.getDepth() != EldNone) @@ -6488,6 +7218,14 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden if (symbol == nullptr) reservedErrorCheck(loc, identifier); + if (symbol == nullptr && spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) { + bool remapped = vkRelaxedRemapUniformVariable(loc, identifier, publicType, arraySizes, initializer, type); + + if (remapped) { + return nullptr; + } + } + inheritGlobalDefaults(type.getQualifier()); // Declare the variable @@ -6595,6 +7333,11 @@ TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, const TString& // TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable) { + // A null initializer is an aggregate that hasn't had an op assigned yet + // (still EOpNull, no relation to nullInit), and has no children. + bool nullInit = initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull && + initializer->getAsAggregate()->getSequence().size() == 0; + // // Identifier must be of type constant, a global, or a temporary, and // starting at version 120, desktop allows uniforms to have initializers. @@ -6602,9 +7345,36 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp TStorageQualifier qualifier = variable->getType().getQualifier().storage; if (! (qualifier == EvqTemporary || qualifier == EvqGlobal || qualifier == EvqConst || (qualifier == EvqUniform && !isEsProfile() && version >= 120))) { - error(loc, " cannot initialize this type of qualifier ", variable->getType().getStorageQualifierString(), ""); + if (qualifier == EvqShared) { + // GL_EXT_null_initializer allows this for shared, if it's a null initializer + if (nullInit) { + const char* feature = "initialization with shared qualifier"; + profileRequires(loc, EEsProfile, 0, E_GL_EXT_null_initializer, feature); + profileRequires(loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, feature); + } else { + error(loc, "initializer can only be a null initializer ('{}')", "shared", ""); + } + } else { + error(loc, " cannot initialize this type of qualifier ", + variable->getType().getStorageQualifierString(), ""); + return nullptr; + } + } + + if (nullInit) { + // only some types can be null initialized + if (variable->getType().containsUnsizedArray()) { + error(loc, "null initializers can't size unsized arrays", "{}", ""); + return nullptr; + } + if (variable->getType().containsOpaque()) { + error(loc, "null initializers can't be used on opaque values", "{}", ""); + return nullptr; + } + variable->getWritableType().getQualifier().setNullInit(); return nullptr; } + arrayObjectCheck(loc, variable->getType(), "array initializer"); // @@ -6648,13 +7418,15 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp // Uniforms require a compile-time constant initializer if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) { - error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str()); + error(loc, "uniform initializers must be constant", "=", "'%s'", + variable->getType().getCompleteString().c_str()); variable->getWritableType().getQualifier().makeTemporary(); return nullptr; } // Global consts require a constant initializer (specialization constant is okay) if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) { - error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str()); + error(loc, "global const initializers must be constant", "=", "'%s'", + variable->getType().getCompleteString().c_str()); variable->getWritableType().getQualifier().makeTemporary(); return nullptr; } @@ -6674,7 +7446,8 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp // "In declarations of global variables with no storage qualifier or with a const // qualifier any initializer must be a constant expression." if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) { - const char* initFeature = "non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)"; + const char* initFeature = + "non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)"; if (isEsProfile()) { if (relaxedErrors() && ! extensionTurnedOn(E_GL_EXT_shader_non_constant_global_initializers)) warn(loc, "not allowed in this version", initFeature, ""); @@ -6688,7 +7461,8 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp // Compile-time tagging of the variable with its constant value... initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer); - if (! initializer || ! initializer->getType().getQualifier().isConstant() || variable->getType() != initializer->getType()) { + if (! initializer || ! initializer->getType().getQualifier().isConstant() || + variable->getType() != initializer->getType()) { error(loc, "non-matching or non-convertible constant type for const initializer", variable->getType().getStorageQualifierString(), ""); variable->getWritableType().getQualifier().makeTemporary(); @@ -6800,6 +7574,15 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str()); return nullptr; } + TBasicType destType = type.getBasicType(); + for (int i = 0; i < type.getVectorSize(); ++i) { + TBasicType initType = initList->getSequence()[i]->getAsTyped()->getBasicType(); + if (destType != initType && !intermediate.canImplicitlyPromote(initType, destType)) { + error(loc, "type mismatch in initializer list", "initializer list", type.getCompleteString().c_str()); + return nullptr; + } + + } } else { error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str()); return nullptr; @@ -7175,6 +7958,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T if (!node->getType().isCoopMat()) { if (type.getBasicType() != node->getType().getBasicType()) { node = intermediate.addConversion(type.getBasicType(), node); + if (node == nullptr) + return nullptr; } node = intermediate.setAggregateOperator(node, EOpConstructCooperativeMatrix, type, node->getLoc()); } else { @@ -7254,6 +8039,19 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T return node; + case EOpConstructAccStruct: + if ((node->getType().isScalar() && node->getType().getBasicType() == EbtUint64)) { + // construct acceleration structure from uint64 + requireExtensions(loc, 1, &E_GL_EXT_ray_tracing, "uint64_t conversion to acclerationStructureEXT"); + return intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUint64ToAccStruct, true, node, + type); + } else if (node->getType().isVector() && node->getType().getBasicType() == EbtUint && node->getVectorSize() == 2) { + // construct acceleration structure from uint64 + requireExtensions(loc, 1, &E_GL_EXT_ray_tracing, "uvec2 conversion to accelerationStructureEXT"); + return intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUvec2ToAccStruct, true, node, + type); + } else + return nullptr; #endif // GLSLANG_WEB default: @@ -7320,6 +8118,8 @@ void TParseContext::inheritMemoryQualifiers(const TQualifier& from, TQualifier& void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes) { + if (spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) + blockStorageRemap(loc, blockName, currentBlockQualifier); blockStageIoCheck(loc, currentBlockQualifier); blockQualifierCheck(loc, currentBlockQualifier, instanceName != nullptr); if (arraySizes != nullptr) { @@ -7334,10 +8134,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con TType& memberType = *typeList[member].type; TQualifier& memberQualifier = memberType.getQualifier(); const TSourceLoc& memberLoc = typeList[member].loc; - globalQualifierFixCheck(memberLoc, memberQualifier); if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage) error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), ""); memberQualifier.storage = currentBlockQualifier.storage; + globalQualifierFixCheck(memberLoc, memberQualifier); #ifndef GLSLANG_WEB inheritMemoryQualifiers(currentBlockQualifier, memberQualifier); if (currentBlockQualifier.perPrimitiveNV) @@ -7346,6 +8146,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con memberQualifier.perViewNV = currentBlockQualifier.perViewNV; if (currentBlockQualifier.perTaskNV) memberQualifier.perTaskNV = currentBlockQualifier.perTaskNV; + if (memberQualifier.storage == EvqSpirvStorageClass) + error(memberLoc, "member cannot have a spirv_storage_class qualifier", memberType.getFieldName().c_str(), ""); + if (memberQualifier.hasSprivDecorate() && !memberQualifier.getSpirvDecorate().decorateIds.empty()) + error(memberLoc, "member cannot have a spirv_decorate_id qualifier", memberType.getFieldName().c_str(), ""); #endif if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary())) error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), ""); @@ -7353,8 +8157,8 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con arraySizesCheck(memberLoc, currentBlockQualifier, memberType.getArraySizes(), nullptr, member == typeList.size() - 1); if (memberQualifier.hasOffset()) { if (spvVersion.spv == 0) { - requireProfile(memberLoc, ~EEsProfile, "offset on block member"); - profileRequires(memberLoc, ~EEsProfile, 440, E_GL_ARB_enhanced_layouts, "offset on block member"); + profileRequires(memberLoc, ~EEsProfile, 440, E_GL_ARB_enhanced_layouts, "\"offset\" on block member"); + profileRequires(memberLoc, EEsProfile, 300, E_GL_ARB_enhanced_layouts, "\"offset\" on block member"); } } @@ -7387,13 +8191,14 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con case EvqBuffer: defaultQualification = globalBufferDefaults; break; case EvqVaryingIn: defaultQualification = globalInputDefaults; break; case EvqVaryingOut: defaultQualification = globalOutputDefaults; break; + case EvqShared: defaultQualification = globalSharedDefaults; break; default: defaultQualification.clear(); break; } // Special case for "push_constant uniform", which has a default of std430, // contrary to normal uniform defaults, and can't have a default tracked for it. if ((currentBlockQualifier.isPushConstant() && !currentBlockQualifier.hasPacking()) || - (currentBlockQualifier.isShaderRecordNV() && !currentBlockQualifier.hasPacking())) + (currentBlockQualifier.isShaderRecord() && !currentBlockQualifier.hasPacking())) currentBlockQualifier.layoutPacking = ElpStd430; // Special case for "taskNV in/out", which has a default of std430, @@ -7493,6 +8298,8 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation); fixXfbOffsets(currentBlockQualifier, typeList); fixBlockUniformOffsets(currentBlockQualifier, typeList); + fixBlockUniformLayoutMatrix(currentBlockQualifier, &typeList, nullptr); + fixBlockUniformLayoutPacking(currentBlockQualifier, &typeList, nullptr); for (unsigned int member = 0; member < typeList.size(); ++member) layoutTypeCheck(typeList[member].loc, *typeList[member].type); @@ -7606,10 +8413,22 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con trackLinkage(variable); } +// +// allow storage type of block to be remapped at compile time +// +void TParseContext::blockStorageRemap(const TSourceLoc&, const TString* instanceName, TQualifier& qualifier) +{ + TBlockStorageClass type = intermediate.getBlockStorageOverride(instanceName->c_str()); + if (type != EbsNone) { + qualifier.setBlockStorage(type); + } +} + // Do all block-declaration checking regarding the combination of in/out/uniform/buffer // with a particular stage. void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& qualifier) { + const char *extsrt[2] = { E_GL_NV_ray_tracing, E_GL_EXT_ray_tracing }; switch (qualifier.storage) { case EvqUniform: profileRequires(loc, EEsProfile, 300, nullptr, "uniform block"); @@ -7619,7 +8438,7 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q break; case EvqBuffer: requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "buffer block"); - profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, "buffer block"); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_shader_storage_buffer_object, "buffer block"); profileRequires(loc, EEsProfile, 310, nullptr, "buffer block"); break; case EvqVaryingIn: @@ -7647,29 +8466,35 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q error(loc, "output blocks cannot be used in a task shader", "out", ""); } break; + case EvqShared: + if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4) { + error(loc, "shared block requires at least SPIR-V 1.4", "shared block", ""); + } + profileRequires(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shared_memory_block, "shared block"); + break; #ifndef GLSLANG_WEB - case EvqPayloadNV: - profileRequires(loc, ~EEsProfile, 460, E_GL_NV_ray_tracing, "rayPayloadNV block"); - requireStage(loc, (EShLanguageMask)(EShLangRayGenNVMask | EShLangAnyHitNVMask | EShLangClosestHitNVMask | EShLangMissNVMask), + case EvqPayload: + profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "rayPayloadNV block"); + requireStage(loc, (EShLanguageMask)(EShLangRayGenMask | EShLangAnyHitMask | EShLangClosestHitMask | EShLangMissMask), "rayPayloadNV block"); break; - case EvqPayloadInNV: - profileRequires(loc, ~EEsProfile, 460, E_GL_NV_ray_tracing, "rayPayloadInNV block"); - requireStage(loc, (EShLanguageMask)(EShLangAnyHitNVMask | EShLangClosestHitNVMask | EShLangMissNVMask), + case EvqPayloadIn: + profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "rayPayloadInNV block"); + requireStage(loc, (EShLanguageMask)(EShLangAnyHitMask | EShLangClosestHitMask | EShLangMissMask), "rayPayloadInNV block"); break; - case EvqHitAttrNV: - profileRequires(loc, ~EEsProfile, 460, E_GL_NV_ray_tracing, "hitAttributeNV block"); - requireStage(loc, (EShLanguageMask)(EShLangIntersectNVMask | EShLangAnyHitNVMask | EShLangClosestHitNVMask), "hitAttributeNV block"); + case EvqHitAttr: + profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "hitAttributeNV block"); + requireStage(loc, (EShLanguageMask)(EShLangIntersectMask | EShLangAnyHitMask | EShLangClosestHitMask), "hitAttributeNV block"); break; - case EvqCallableDataNV: - profileRequires(loc, ~EEsProfile, 460, E_GL_NV_ray_tracing, "callableDataNV block"); - requireStage(loc, (EShLanguageMask)(EShLangRayGenNVMask | EShLangClosestHitNVMask | EShLangMissNVMask | EShLangCallableNVMask), + case EvqCallableData: + profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "callableDataNV block"); + requireStage(loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | EShLangMissMask | EShLangCallableMask), "callableDataNV block"); break; - case EvqCallableDataInNV: - profileRequires(loc, ~EEsProfile, 460, E_GL_NV_ray_tracing, "callableDataInNV block"); - requireStage(loc, (EShLanguageMask)(EShLangCallableNVMask), "callableDataInNV block"); + case EvqCallableDataIn: + profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "callableDataInNV block"); + requireStage(loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInNV block"); break; #endif default: @@ -7708,8 +8533,8 @@ void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& error(loc, "cannot use invariant qualifier on an interface block", "invariant", ""); if (qualifier.isPushConstant()) intermediate.addPushConstantCount(); - if (qualifier.isShaderRecordNV()) - intermediate.addShaderRecordNVCount(); + if (qualifier.isShaderRecord()) + intermediate.addShaderRecordCount(); if (qualifier.isTaskMemory()) intermediate.addTaskNVCount(); } @@ -7805,7 +8630,7 @@ void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList) // void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typeList) { - if (!qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory()) + if (!storageCanHaveLayoutInBlock(qualifier.storage) && !qualifier.isTaskMemory()) return; if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430 && qualifier.layoutPacking != ElpScalar) return; @@ -7862,6 +8687,103 @@ void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typ } } +// +// Spread LayoutMatrix to uniform block member, if a uniform block member is a struct, +// we need spread LayoutMatrix to this struct member too. and keep this rule for recursive. +// +void TParseContext::fixBlockUniformLayoutMatrix(TQualifier& qualifier, TTypeList* originTypeList, + TTypeList* tmpTypeList) +{ + assert(tmpTypeList == nullptr || originTypeList->size() == tmpTypeList->size()); + for (unsigned int member = 0; member < originTypeList->size(); ++member) { + if (qualifier.layoutPacking != ElpNone) { + if (tmpTypeList == nullptr) { + if (((*originTypeList)[member].type->isMatrix() || + (*originTypeList)[member].type->getBasicType() == EbtStruct) && + (*originTypeList)[member].type->getQualifier().layoutMatrix == ElmNone) { + (*originTypeList)[member].type->getQualifier().layoutMatrix = qualifier.layoutMatrix; + } + } else { + if (((*tmpTypeList)[member].type->isMatrix() || + (*tmpTypeList)[member].type->getBasicType() == EbtStruct) && + (*tmpTypeList)[member].type->getQualifier().layoutMatrix == ElmNone) { + (*tmpTypeList)[member].type->getQualifier().layoutMatrix = qualifier.layoutMatrix; + } + } + } + + if ((*originTypeList)[member].type->getBasicType() == EbtStruct) { + TQualifier* memberQualifier = nullptr; + // block member can be declare a matrix style, so it should be update to the member's style + if ((*originTypeList)[member].type->getQualifier().layoutMatrix == ElmNone) { + memberQualifier = &qualifier; + } else { + memberQualifier = &((*originTypeList)[member].type->getQualifier()); + } + + const TType* tmpType = tmpTypeList == nullptr ? + (*originTypeList)[member].type->clone() : (*tmpTypeList)[member].type; + + fixBlockUniformLayoutMatrix(*memberQualifier, (*originTypeList)[member].type->getWritableStruct(), + tmpType->getWritableStruct()); + + const TTypeList* structure = recordStructCopy(matrixFixRecord, (*originTypeList)[member].type, tmpType); + + if (tmpTypeList == nullptr) { + (*originTypeList)[member].type->setStruct(const_cast(structure)); + } + if (tmpTypeList != nullptr) { + (*tmpTypeList)[member].type->setStruct(const_cast(structure)); + } + } + } +} + +// +// Spread LayoutPacking to matrix or aggregate block members. If a block member is a struct or +// array of struct, spread LayoutPacking recursively to its matrix or aggregate members. +// +void TParseContext::fixBlockUniformLayoutPacking(TQualifier& qualifier, TTypeList* originTypeList, + TTypeList* tmpTypeList) +{ + assert(tmpTypeList == nullptr || originTypeList->size() == tmpTypeList->size()); + for (unsigned int member = 0; member < originTypeList->size(); ++member) { + if (qualifier.layoutPacking != ElpNone) { + if (tmpTypeList == nullptr) { + if ((*originTypeList)[member].type->getQualifier().layoutPacking == ElpNone && + !(*originTypeList)[member].type->isScalarOrVector()) { + (*originTypeList)[member].type->getQualifier().layoutPacking = qualifier.layoutPacking; + } + } else { + if ((*tmpTypeList)[member].type->getQualifier().layoutPacking == ElpNone && + !(*tmpTypeList)[member].type->isScalarOrVector()) { + (*tmpTypeList)[member].type->getQualifier().layoutPacking = qualifier.layoutPacking; + } + } + } + + if ((*originTypeList)[member].type->getBasicType() == EbtStruct) { + // Deep copy the type in pool. + // Because, struct use in different block may have different layout qualifier. + // We have to new a object to distinguish between them. + const TType* tmpType = tmpTypeList == nullptr ? + (*originTypeList)[member].type->clone() : (*tmpTypeList)[member].type; + + fixBlockUniformLayoutPacking(qualifier, (*originTypeList)[member].type->getWritableStruct(), + tmpType->getWritableStruct()); + + const TTypeList* structure = recordStructCopy(packingFixRecord, (*originTypeList)[member].type, tmpType); + + if (tmpTypeList == nullptr) { + (*originTypeList)[member].type->setStruct(const_cast(structure)); + } + if (tmpTypeList != nullptr) { + (*tmpTypeList)[member].type->setStruct(const_cast(structure)); + } + } + } +} + // For an identifier that is already declared, add more qualification to it. void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, const TString& identifier) { @@ -7937,7 +8859,7 @@ void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qual bool pipeOut = qualifier.isPipeOutput(); bool pipeIn = qualifier.isPipeInput(); - if (version >= 300 || (!isEsProfile() && version >= 420)) { + if ((version >= 300 && isEsProfile()) || (!isEsProfile() && version >= 420)) { if (! pipeOut) error(loc, "can only apply to an output", "invariant", ""); } else { @@ -8170,6 +9092,16 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con { checkIoArraysConsistency(loc); } + + if (publicType.shaderQualifiers.layoutPrimitiveCulling) { + if (publicType.qualifier.storage != EvqTemporary) + error(loc, "layout qualifier can not have storage qualifiers", "primitive_culling","", ""); + else { + intermediate.setLayoutPrimitiveCulling(); + } + // Exit early as further checks are not valid + return; + } #endif const TQualifier& qualifier = publicType.qualifier; @@ -8214,8 +9146,14 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con } #endif break; + case EvqShared: + if (qualifier.hasMatrix()) + globalSharedDefaults.layoutMatrix = qualifier.layoutMatrix; + if (qualifier.hasPacking()) + globalSharedDefaults.layoutPacking = qualifier.layoutPacking; + break; default: - error(loc, "default qualifier requires 'uniform', 'buffer', 'in', or 'out' storage qualification", "", ""); + error(loc, "default qualifier requires 'uniform', 'buffer', 'in', 'out' or 'shared' storage qualification", "", ""); return; } @@ -8231,7 +9169,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con error(loc, "cannot declare a default, can only be used on a block", "buffer_reference", ""); if (qualifier.hasSpecConstantId()) error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", ""); - if (qualifier.isShaderRecordNV()) + if (qualifier.isShaderRecord()) error(loc, "cannot declare a default, can only be used on a block", "shaderRecordNV", ""); } @@ -8320,5 +9258,43 @@ TIntermNode* TParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expre return switchNode; } +// +// When a struct used in block, and has it's own layout packing, layout matrix, +// record the origin structure of a struct to map, and Record the structure copy to the copy table, +// +const TTypeList* TParseContext::recordStructCopy(TStructRecord& record, const TType* originType, const TType* tmpType) +{ + size_t memberCount = tmpType->getStruct()->size(); + size_t originHash = 0, tmpHash = 0; + std::hash hasher; + for (size_t i = 0; i < memberCount; i++) { + size_t originMemberHash = hasher(originType->getStruct()->at(i).type->getQualifier().layoutPacking + + originType->getStruct()->at(i).type->getQualifier().layoutMatrix); + size_t tmpMemberHash = hasher(tmpType->getStruct()->at(i).type->getQualifier().layoutPacking + + tmpType->getStruct()->at(i).type->getQualifier().layoutMatrix); + originHash = hasher((originHash ^ originMemberHash) << 1); + tmpHash = hasher((tmpHash ^ tmpMemberHash) << 1); + } + const TTypeList* originStruct = originType->getStruct(); + const TTypeList* tmpStruct = tmpType->getStruct(); + if (originHash != tmpHash) { + auto fixRecords = record.find(originStruct); + if (fixRecords != record.end()) { + auto fixRecord = fixRecords->second.find(tmpHash); + if (fixRecord != fixRecords->second.end()) { + return fixRecord->second; + } else { + record[originStruct][tmpHash] = tmpStruct; + return tmpStruct; + } + } else { + record[originStruct] = std::map(); + record[originStruct][tmpHash] = tmpStruct; + return tmpStruct; + } + } + return originStruct; +} + } // end namespace glslang diff --git a/libraries/glslang/glslang/MachineIndependent/ParseHelper.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseHelper.h similarity index 84% rename from libraries/glslang/glslang/MachineIndependent/ParseHelper.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseHelper.h index 39363f1a2a7..de448846530 100644 --- a/libraries/glslang/glslang/MachineIndependent/ParseHelper.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ParseHelper.h @@ -67,7 +67,8 @@ struct TPragma { class TScanContext; class TPpContext; -typedef std::set TIdSetType; +typedef std::set TIdSetType; +typedef std::map> TStructRecord; // // Sharable code (as well as what's in TParseVersions) across @@ -82,7 +83,8 @@ class TParseContextBase : public TParseVersions { : TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages), scopeMangler("::"), symbolTable(symbolTable), - statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), + statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), blockNestingLevel(0), controlFlowNestingLevel(0), + currentFunctionType(nullptr), postEntryPointReturn(false), contextPragma(true, false), beginInvocationInterlockCount(0), endInvocationInterlockCount(0), @@ -90,7 +92,8 @@ class TParseContextBase : public TParseVersions { limits(resources.limits), globalUniformBlock(nullptr), globalUniformBinding(TQualifier::layoutBindingEnd), - globalUniformSet(TQualifier::layoutSetEnd) + globalUniformSet(TQualifier::layoutSetEnd), + atomicCounterBlockSet(TQualifier::layoutSetEnd) { if (entryPoint != nullptr) sourceEntryPointName = *entryPoint; @@ -152,10 +155,11 @@ class TParseContextBase : public TParseVersions { extensionCallback(line, extension, behavior); } -#ifdef ENABLE_HLSL // Manage the global uniform block (default uniforms in GLSL, $Global in HLSL) virtual void growGlobalUniformBlock(const TSourceLoc&, TType&, const TString& memberName, TTypeList* typeList = nullptr); -#endif + + // Manage global buffer (used for backing atomic counters in GLSL when using relaxed Vulkan semantics) + virtual void growAtomicCounterBlock(int binding, const TSourceLoc&, TType&, const TString& memberName, TTypeList* typeList = nullptr); // Potentially rename shader entry point function void renameShaderFunction(TString*& name) const @@ -176,7 +180,8 @@ class TParseContextBase : public TParseVersions { TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile int statementNestingLevel; // 0 if outside all flow control or compound statements int loopNestingLevel; // 0 if outside all loops - int structNestingLevel; // 0 if outside blocks and structures + int structNestingLevel; // 0 if outside structures + int blockNestingLevel; // 0 if outside blocks int controlFlowNestingLevel; // 0 if outside all flow control const TType* currentFunctionType; // the return type of the function that's currently being parsed bool functionReturnsValue; // true if a non-void function has a return @@ -227,7 +232,25 @@ class TParseContextBase : public TParseVersions { // override this to set the language-specific name virtual const char* getGlobalUniformBlockName() const { return ""; } virtual void setUniformBlockDefaults(TType&) const { } - virtual void finalizeGlobalUniformBlockLayout(TVariable&) { } + virtual void finalizeGlobalUniformBlockLayout(TVariable&) {} + + // Manage the atomic counter block (used for atomic_uints with Vulkan-Relaxed) + TMap atomicCounterBuffers; + unsigned int atomicCounterBlockSet; + TMap atomicCounterBlockFirstNewMember; + // override this to set the language-specific name + virtual const char* getAtomicCounterBlockName() const { return ""; } + virtual void setAtomicCounterBlockDefaults(TType&) const {} + virtual void setInvariant(const TSourceLoc& loc, const char* builtin) {} + virtual void finalizeAtomicCounterBlockLayout(TVariable&) {} + bool isAtomicCounterBlock(const TSymbol& symbol) { + const TVariable* var = symbol.getAsVariable(); + if (!var) + return false; + const auto& at = atomicCounterBuffers.find(var->getType().getQualifier().layoutBinding); + return (at != atomicCounterBuffers.end() && (*at).second->getType() == var->getType()); + } + virtual void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken, const char* szExtraInfoFormat, TPrefixType prefix, va_list args); @@ -290,6 +313,9 @@ class TParseContext : public TParseContextBase { bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) override; void parserError(const char* s); // for bison's yyerror + virtual void growGlobalUniformBlock(const TSourceLoc&, TType&, const TString& memberName, TTypeList* typeList = nullptr) override; + virtual void growAtomicCounterBlock(int binding, const TSourceLoc&, TType&, const TString& memberName, TTypeList* typeList = nullptr) override; + void reservedErrorCheck(const TSourceLoc&, const TString&); void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op) override; bool lineContinuationCheck(const TSourceLoc&, bool endOfComment) override; @@ -315,6 +341,7 @@ class TParseContext : public TParseContextBase { TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode); TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field); + TIntermTyped* handleDotSwizzle(const TSourceLoc&, TIntermTyped* base, const TString& field); void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, int member, const TString& memberName); TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&); @@ -326,6 +353,7 @@ class TParseContext : public TParseContextBase { TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*); void addInputArgumentConversions(const TFunction&, TIntermNode*&) const; TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const; + TIntermTyped* addAssign(const TSourceLoc&, TOperator op, TIntermTyped* left, TIntermTyped* right); void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&); void nonOpBuiltInCheck(const TSourceLoc&, const TFunction&, TIntermAggregate&); void userFunctionCallCheck(const TSourceLoc&, TIntermAggregate&); @@ -335,6 +363,10 @@ class TParseContext : public TParseContextBase { void checkPrecisionQualifier(const TSourceLoc&, TPrecisionQualifier); void memorySemanticsCheck(const TSourceLoc&, const TFunction&, const TIntermOperator& callNode); + TIntermTyped* vkRelaxedRemapFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*); + // returns true if the variable was remapped to something else + bool vkRelaxedRemapUniformVariable(const TSourceLoc&, TString&, const TPublicType&, TArraySizes*, TIntermTyped*, TType&); + void assignError(const TSourceLoc&, const char* op, TString left, TString right); void unaryOpError(const TSourceLoc&, const char* op, TString operand); void binaryOpError(const TSourceLoc&, const char* op, TString left, TString right); @@ -358,10 +390,10 @@ class TParseContext : public TParseContextBase { void boolCheck(const TSourceLoc&, const TPublicType&); void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier, TIntermTyped* initializer); void atomicUintCheck(const TSourceLoc&, const TType&, const TString& identifier); - void accStructNVCheck(const TSourceLoc & loc, const TType & type, const TString & identifier); + void accStructCheck(const TSourceLoc & loc, const TType & type, const TString & identifier); void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier); void memberQualifierCheck(glslang::TPublicType&); - void globalQualifierFixCheck(const TSourceLoc&, TQualifier&); + void globalQualifierFixCheck(const TSourceLoc&, TQualifier&, bool isMemberCheck = false); void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&); bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType); void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force); @@ -387,7 +419,7 @@ class TParseContext : public TParseContextBase { void arrayLimitCheck(const TSourceLoc&, const TString&, int size); void limitCheck(const TSourceLoc&, int value, const char* limit, const char* feature); - void inductiveLoopBodyCheck(TIntermNode*, int loopIndexId, TSymbolTable&); + void inductiveLoopBodyCheck(TIntermNode*, long long loopIndexId, TSymbolTable&); void constantIndexExpressionCheck(TIntermNode*); void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&); @@ -412,17 +444,21 @@ class TParseContext : public TParseContextBase { TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset); void inheritMemoryQualifiers(const TQualifier& from, TQualifier& to); void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0); + void blockStorageRemap(const TSourceLoc&, const TString*, TQualifier&); void blockStageIoCheck(const TSourceLoc&, const TQualifier&); void blockQualifierCheck(const TSourceLoc&, const TQualifier&, bool instanceName); void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation); void fixXfbOffsets(TQualifier&, TTypeList&); void fixBlockUniformOffsets(TQualifier&, TTypeList&); + void fixBlockUniformLayoutMatrix(TQualifier&, TTypeList*, TTypeList*); + void fixBlockUniformLayoutPacking(TQualifier&, TTypeList*, TTypeList*); void addQualifierToExisting(const TSourceLoc&, TQualifier, const TString& identifier); void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&); void invariantCheck(const TSourceLoc&, const TQualifier&); void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body); + const TTypeList* recordStructCopy(TStructRecord&, const TType*, const TType*); #ifndef GLSLANG_WEB TAttributeType attributeFromName(const TString& name) const; @@ -435,6 +471,22 @@ class TParseContext : public TParseContextBase { void handleSwitchAttributes(const TAttributes& attributes, TIntermNode*); // Determine loop control from attributes void handleLoopAttributes(const TAttributes& attributes, TIntermNode*); + // Function attributes + void handleFunctionAttributes(const TSourceLoc&, const TAttributes&, TFunction*); + + // GL_EXT_spirv_intrinsics + TSpirvRequirement* makeSpirvRequirement(const TSourceLoc& loc, const TString& name, + const TIntermAggregate* extensions, const TIntermAggregate* capabilities); + TSpirvRequirement* mergeSpirvRequirements(const TSourceLoc& loc, TSpirvRequirement* spirvReq1, + TSpirvRequirement* spirvReq2); + TSpirvTypeParameters* makeSpirvTypeParameters(const TSourceLoc& loc, const TIntermConstantUnion* constant); + TSpirvTypeParameters* makeSpirvTypeParameters(const TPublicType& type); + TSpirvTypeParameters* mergeSpirvTypeParameters(TSpirvTypeParameters* spirvTypeParams1, + TSpirvTypeParameters* spirvTypeParams2); + TSpirvInstruction* makeSpirvInstruction(const TSourceLoc& loc, const TString& name, const TString& value); + TSpirvInstruction* makeSpirvInstruction(const TSourceLoc& loc, const TString& name, int value); + TSpirvInstruction* mergeSpirvInstruction(const TSourceLoc& loc, TSpirvInstruction* spirvInst1, + TSpirvInstruction* spirvInst2); #endif void checkAndResizeMeshViewDim(const TSourceLoc&, TType&, bool isBlockMember); @@ -453,6 +505,15 @@ class TParseContext : public TParseContextBase { void finish() override; #endif + virtual const char* getGlobalUniformBlockName() const override; + virtual void finalizeGlobalUniformBlockLayout(TVariable&) override; + virtual void setUniformBlockDefaults(TType& block) const override; + + virtual const char* getAtomicCounterBlockName() const override; + virtual void finalizeAtomicCounterBlockLayout(TVariable&) override; + virtual void setAtomicCounterBlockDefaults(TType& block) const override; + virtual void setInvariant(const TSourceLoc& loc, const char* builtin) override; + public: // // Generally, bison productions, the scanner, and the PP need read/write access to these; just give them direct access @@ -477,12 +538,15 @@ class TParseContext : public TParseContextBase { TQualifier globalUniformDefaults; TQualifier globalInputDefaults; TQualifier globalOutputDefaults; + TQualifier globalSharedDefaults; TString currentCaller; // name of last function body entered (not valid when at global scope) #ifndef GLSLANG_WEB int* atomicUintOffsets; // to become an array of the right size to hold an offset per binding point bool anyIndexLimits; TIdSetType inductiveLoopIds; TVector needsIndexLimitationChecking; + TStructRecord matrixFixRecord; + TStructRecord packingFixRecord; // // Geometry shader input arrays: diff --git a/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/PoolAlloc.cpp similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/PoolAlloc.cpp diff --git a/libraries/glslang/glslang/MachineIndependent/RemoveTree.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/RemoveTree.cpp similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/RemoveTree.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/RemoveTree.cpp diff --git a/libraries/glslang/glslang/MachineIndependent/RemoveTree.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/RemoveTree.h similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/RemoveTree.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/RemoveTree.h diff --git a/libraries/glslang/glslang/MachineIndependent/Scan.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Scan.cpp similarity index 89% rename from libraries/glslang/glslang/MachineIndependent/Scan.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Scan.cpp index 710af4ab8c7..c387aede0e6 100644 --- a/libraries/glslang/glslang/MachineIndependent/Scan.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Scan.cpp @@ -2,6 +2,8 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. +// Copyright (C) 2020 Google, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -187,17 +189,15 @@ bool TInputScanner::scanVersion(int& version, EProfile& profile, bool& notFirstT if (lookingInMiddle) { notFirstToken = true; // make forward progress by finishing off the current line plus extra new lines - if (peek() == '\n' || peek() == '\r') { - while (peek() == '\n' || peek() == '\r') - get(); - } else + if (peek() != '\n' && peek() != '\r') { do { c = get(); } while (c != EndOfInput && c != '\n' && c != '\r'); - while (peek() == '\n' || peek() == '\r') - get(); - if (peek() == EndOfInput) - return true; + } + while (peek() == '\n' || peek() == '\r') + get(); + if (peek() == EndOfInput) + return true; } lookingInMiddle = true; @@ -365,6 +365,9 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["if"] = IF; (*KeywordMap)["else"] = ELSE; (*KeywordMap)["discard"] = DISCARD; + (*KeywordMap)["terminateInvocation"] = TERMINATE_INVOCATION; + (*KeywordMap)["terminateRayEXT"] = TERMINATE_RAY; + (*KeywordMap)["ignoreIntersectionEXT"] = IGNORE_INTERSECTION; (*KeywordMap)["return"] = RETURN; (*KeywordMap)["void"] = VOID; (*KeywordMap)["bool"] = BOOL; @@ -416,6 +419,7 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["queuefamilycoherent"] = QUEUEFAMILYCOHERENT; (*KeywordMap)["workgroupcoherent"] = WORKGROUPCOHERENT; (*KeywordMap)["subgroupcoherent"] = SUBGROUPCOHERENT; + (*KeywordMap)["shadercallcoherent"] = SHADERCALLCOHERENT; (*KeywordMap)["nonprivate"] = NONPRIVATE; (*KeywordMap)["restrict"] = RESTRICT; (*KeywordMap)["readonly"] = READONLY; @@ -470,6 +474,28 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["image2DMSArray"] = IMAGE2DMSARRAY; (*KeywordMap)["iimage2DMSArray"] = IIMAGE2DMSARRAY; (*KeywordMap)["uimage2DMSArray"] = UIMAGE2DMSARRAY; + (*KeywordMap)["i64image1D"] = I64IMAGE1D; + (*KeywordMap)["u64image1D"] = U64IMAGE1D; + (*KeywordMap)["i64image2D"] = I64IMAGE2D; + (*KeywordMap)["u64image2D"] = U64IMAGE2D; + (*KeywordMap)["i64image3D"] = I64IMAGE3D; + (*KeywordMap)["u64image3D"] = U64IMAGE3D; + (*KeywordMap)["i64image2DRect"] = I64IMAGE2DRECT; + (*KeywordMap)["u64image2DRect"] = U64IMAGE2DRECT; + (*KeywordMap)["i64imageCube"] = I64IMAGECUBE; + (*KeywordMap)["u64imageCube"] = U64IMAGECUBE; + (*KeywordMap)["i64imageBuffer"] = I64IMAGEBUFFER; + (*KeywordMap)["u64imageBuffer"] = U64IMAGEBUFFER; + (*KeywordMap)["i64image1DArray"] = I64IMAGE1DARRAY; + (*KeywordMap)["u64image1DArray"] = U64IMAGE1DARRAY; + (*KeywordMap)["i64image2DArray"] = I64IMAGE2DARRAY; + (*KeywordMap)["u64image2DArray"] = U64IMAGE2DARRAY; + (*KeywordMap)["i64imageCubeArray"] = I64IMAGECUBEARRAY; + (*KeywordMap)["u64imageCubeArray"] = U64IMAGECUBEARRAY; + (*KeywordMap)["i64image2DMS"] = I64IMAGE2DMS; + (*KeywordMap)["u64image2DMS"] = U64IMAGE2DMS; + (*KeywordMap)["i64image2DMSArray"] = I64IMAGE2DMSARRAY; + (*KeywordMap)["u64image2DMSArray"] = U64IMAGE2DMSARRAY; (*KeywordMap)["double"] = DOUBLE; (*KeywordMap)["dvec2"] = DVEC2; (*KeywordMap)["dvec3"] = DVEC3; @@ -560,6 +586,18 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["f64mat4x2"] = F64MAT4X2; (*KeywordMap)["f64mat4x3"] = F64MAT4X3; (*KeywordMap)["f64mat4x4"] = F64MAT4X4; + + // GL_EXT_spirv_intrinsics + (*KeywordMap)["spirv_instruction"] = SPIRV_INSTRUCTION; + (*KeywordMap)["spirv_execution_mode"] = SPIRV_EXECUTION_MODE; + (*KeywordMap)["spirv_execution_mode_id"] = SPIRV_EXECUTION_MODE_ID; + (*KeywordMap)["spirv_decorate"] = SPIRV_DECORATE; + (*KeywordMap)["spirv_decorate_id"] = SPIRV_DECORATE_ID; + (*KeywordMap)["spirv_decorate_string"] = SPIRV_DECORATE_STRING; + (*KeywordMap)["spirv_type"] = SPIRV_TYPE; + (*KeywordMap)["spirv_storage_class"] = SPIRV_STORAGE_CLASS; + (*KeywordMap)["spirv_by_reference"] = SPIRV_BY_REFERENCE; + (*KeywordMap)["spirv_literal"] = SPIRV_LITERAL; #endif (*KeywordMap)["sampler2D"] = SAMPLER2D; @@ -704,11 +742,18 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["precise"] = PRECISE; (*KeywordMap)["rayPayloadNV"] = PAYLOADNV; + (*KeywordMap)["rayPayloadEXT"] = PAYLOADEXT; (*KeywordMap)["rayPayloadInNV"] = PAYLOADINNV; + (*KeywordMap)["rayPayloadInEXT"] = PAYLOADINEXT; (*KeywordMap)["hitAttributeNV"] = HITATTRNV; + (*KeywordMap)["hitAttributeEXT"] = HITATTREXT; (*KeywordMap)["callableDataNV"] = CALLDATANV; + (*KeywordMap)["callableDataEXT"] = CALLDATAEXT; (*KeywordMap)["callableDataInNV"] = CALLDATAINNV; + (*KeywordMap)["callableDataInEXT"] = CALLDATAINEXT; (*KeywordMap)["accelerationStructureNV"] = ACCSTRUCTNV; + (*KeywordMap)["accelerationStructureEXT"] = ACCSTRUCTEXT; + (*KeywordMap)["rayQueryEXT"] = RAYQUERYEXT; (*KeywordMap)["perprimitiveNV"] = PERPRIMITIVENV; (*KeywordMap)["perviewNV"] = PERVIEWNV; (*KeywordMap)["taskNV"] = PERTASKNV; @@ -843,6 +888,7 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token) parseContext.error(loc, "not supported", "::", ""); break; + case PpAtomConstString: parserToken->sType.lex.string = NewPoolTString(tokenText); return STRING_LITERAL; case PpAtomConstInt: parserToken->sType.lex.i = ppToken.ival; return INTCONSTANT; case PpAtomConstUint: parserToken->sType.lex.i = ppToken.ival; return UINTCONSTANT; case PpAtomConstFloat: parserToken->sType.lex.d = ppToken.dval; return FLOATCONSTANT; @@ -905,10 +951,22 @@ int TScanContext::tokenizeIdentifier() case CASE: return keyword; + case TERMINATE_INVOCATION: + if (!parseContext.extensionTurnedOn(E_GL_EXT_terminate_invocation)) + return identifierOrType(); + return keyword; + + case TERMINATE_RAY: + case IGNORE_INTERSECTION: + if (!parseContext.extensionTurnedOn(E_GL_EXT_ray_tracing)) + return identifierOrType(); + return keyword; + case BUFFER: afterBuffer = true; if ((parseContext.isEsProfile() && parseContext.version < 310) || - (!parseContext.isEsProfile() && parseContext.version < 430)) + (!parseContext.isEsProfile() && (parseContext.version < 430 && + !parseContext.extensionTurnedOn(E_GL_ARB_shader_storage_buffer_object)))) return identifierOrType(); return keyword; @@ -972,7 +1030,7 @@ int TScanContext::tokenizeIdentifier() return keyword; case PACKED: if ((parseContext.isEsProfile() && parseContext.version < 300) || - (!parseContext.isEsProfile() && parseContext.version < 330)) + (!parseContext.isEsProfile() && parseContext.version < 140)) return reservedWord(); return identifierOrType(); @@ -1014,6 +1072,23 @@ int TScanContext::tokenizeIdentifier() parseContext.extensionTurnedOn(E_GL_NV_ray_tracing)) return keyword; return identifierOrType(); + case PAYLOADEXT: + case PAYLOADINEXT: + case HITATTREXT: + case CALLDATAEXT: + case CALLDATAINEXT: + case ACCSTRUCTEXT: + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_ray_tracing) || + parseContext.extensionTurnedOn(E_GL_EXT_ray_query)) + return keyword; + return identifierOrType(); + case RAYQUERYEXT: + if (parseContext.symbolTable.atBuiltInLevel() || + (!parseContext.isEsProfile() && parseContext.version >= 460 + && parseContext.extensionTurnedOn(E_GL_EXT_ray_query))) + return keyword; + return identifierOrType(); case ATOMIC_UINT: if ((parseContext.isEsProfile() && parseContext.version >= 310) || parseContext.extensionTurnedOn(E_GL_ARB_shader_atomic_counters)) @@ -1025,6 +1100,7 @@ int TScanContext::tokenizeIdentifier() case QUEUEFAMILYCOHERENT: case WORKGROUPCOHERENT: case SUBGROUPCOHERENT: + case SHADERCALLCOHERENT: case NONPRIVATE: case RESTRICT: case READONLY: @@ -1119,6 +1195,19 @@ int TScanContext::tokenizeIdentifier() afterType = true; return firstGenerationImage(false); + case I64IMAGE1D: + case U64IMAGE1D: + case I64IMAGE1DARRAY: + case U64IMAGE1DARRAY: + case I64IMAGE2DRECT: + case U64IMAGE2DRECT: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_shader_image_int64)) { + return firstGenerationImage(false); + } + return identifierOrType(); + case IMAGEBUFFER: case IIMAGEBUFFER: case UIMAGEBUFFER: @@ -1127,6 +1216,18 @@ int TScanContext::tokenizeIdentifier() parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer)) return keyword; return firstGenerationImage(false); + + case I64IMAGEBUFFER: + case U64IMAGEBUFFER: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_shader_image_int64)) { + if ((parseContext.isEsProfile() && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer)) + return keyword; + return firstGenerationImage(false); + } + return identifierOrType(); case IMAGE2D: case IIMAGE2D: @@ -1143,6 +1244,20 @@ int TScanContext::tokenizeIdentifier() afterType = true; return firstGenerationImage(true); + case I64IMAGE2D: + case U64IMAGE2D: + case I64IMAGE3D: + case U64IMAGE3D: + case I64IMAGECUBE: + case U64IMAGECUBE: + case I64IMAGE2DARRAY: + case U64IMAGE2DARRAY: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_shader_image_int64)) + return firstGenerationImage(true); + return identifierOrType(); + case IMAGECUBEARRAY: case IIMAGECUBEARRAY: case UIMAGECUBEARRAY: @@ -1151,6 +1266,18 @@ int TScanContext::tokenizeIdentifier() parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array)) return keyword; return secondGenerationImage(); + + case I64IMAGECUBEARRAY: + case U64IMAGECUBEARRAY: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_shader_image_int64)) { + if ((parseContext.isEsProfile() && parseContext.version >= 320) || + parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array)) + return keyword; + return secondGenerationImage(); + } + return identifierOrType(); case IMAGE2DMS: case IIMAGE2DMS: @@ -1160,13 +1287,27 @@ int TScanContext::tokenizeIdentifier() case UIMAGE2DMSARRAY: afterType = true; return secondGenerationImage(); + + case I64IMAGE2DMS: + case U64IMAGE2DMS: + case I64IMAGE2DMSARRAY: + case U64IMAGE2DMSARRAY: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_shader_image_int64)) { + return secondGenerationImage(); + } + return identifierOrType(); case DOUBLE: case DVEC2: case DVEC3: case DVEC4: afterType = true; - if (parseContext.isEsProfile() || parseContext.version < 400) + if (parseContext.isEsProfile() || parseContext.version < 150 || + (!parseContext.symbolTable.atBuiltInLevel() && + (parseContext.version < 400 && !parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_fp64) && + (parseContext.version < 410 && !parseContext.extensionTurnedOn(E_GL_ARB_vertex_attrib_64bit))))) reservedWord(); return keyword; @@ -1618,6 +1759,21 @@ int TScanContext::tokenizeIdentifier() return keyword; else return identifierOrType(); + + case SPIRV_INSTRUCTION: + case SPIRV_EXECUTION_MODE: + case SPIRV_EXECUTION_MODE_ID: + case SPIRV_DECORATE: + case SPIRV_DECORATE_ID: + case SPIRV_DECORATE_STRING: + case SPIRV_TYPE: + case SPIRV_STORAGE_CLASS: + case SPIRV_BY_REFERENCE: + case SPIRV_LITERAL: + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) + return keyword; + return identifierOrType(); #endif default: @@ -1741,7 +1897,11 @@ int TScanContext::dMat() return keyword; } - if (!parseContext.isEsProfile() && parseContext.version >= 400) + if (!parseContext.isEsProfile() && (parseContext.version >= 400 || + parseContext.symbolTable.atBuiltInLevel() || + (parseContext.version >= 150 && parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_fp64)) || + (parseContext.version >= 150 && parseContext.extensionTurnedOn(E_GL_ARB_vertex_attrib_64bit) + && parseContext.language == EShLangVertex))) return keyword; if (parseContext.isForwardCompatible()) diff --git a/libraries/glslang/glslang/MachineIndependent/Scan.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Scan.h similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/Scan.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Scan.h diff --git a/libraries/glslang/glslang/MachineIndependent/ScanContext.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ScanContext.h similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/ScanContext.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ScanContext.h diff --git a/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ShaderLang.cpp similarity index 92% rename from libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ShaderLang.cpp index 44ce1c19d1a..17902b5dacd 100644 --- a/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/ShaderLang.cpp @@ -1,7 +1,7 @@ // // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2013-2016 LunarG, Inc. -// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) 2015-2020 Google, Inc. // // All rights reserved. // @@ -51,9 +51,9 @@ #include "ScanContext.h" #ifdef ENABLE_HLSL -#include "../../hlsl/hlslParseHelper.h" -#include "../../hlsl/hlslParseables.h" -#include "../../hlsl/hlslScanContext.h" +#include "../HLSL/hlslParseHelper.h" +#include "../HLSL/hlslParseables.h" +#include "../HLSL/hlslScanContext.h" #endif #include "../Include/ShHandle.h" @@ -72,6 +72,9 @@ // token to print ", but none of that seems appropriate for this file. #include "preprocessor/PpTokens.h" +// Build-time generated includes +#include "../Include/build_info.h" + namespace { // anonymous namespace for file-local functions and symbols // Total number of successful initializers of glslang: a refcount @@ -156,7 +159,7 @@ int MapVersionToIndex(int version) return index; } -const int SpvVersionCount = 3; // index range in MapSpvVersionToIndex +const int SpvVersionCount = 4; // index range in MapSpvVersionToIndex int MapSpvVersionToIndex(const SpvVersion& spvVersion) { @@ -164,8 +167,12 @@ int MapSpvVersionToIndex(const SpvVersion& spvVersion) if (spvVersion.openGl > 0) index = 1; - else if (spvVersion.vulkan > 0) - index = 2; + else if (spvVersion.vulkan > 0) { + if (!spvVersion.vulkanRelaxed) + index = 2; + else + index = 3; + } assert(index < SpvVersionCount); @@ -291,6 +298,9 @@ void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int versi #ifdef GLSLANG_WEB profile = EEsProfile; version = 310; +#elif defined(GLSLANG_ANGLE) + profile = ECoreProfile; + version = 450; #endif (*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]); @@ -312,6 +322,9 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS #ifdef GLSLANG_WEB profile = EEsProfile; version = 310; +#elif defined(GLSLANG_ANGLE) + profile = ECoreProfile; + version = 450; #endif std::unique_ptr builtInParseables(CreateBuiltInParseables(infoSink, source)); @@ -351,7 +364,6 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS (profile == EEsProfile && version >= 310)) InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, source, infoSink, commonTable, symbolTables); -#endif // check for compute if ((profile != EEsProfile && version >= 420) || @@ -359,19 +371,20 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source, infoSink, commonTable, symbolTables); +#ifndef GLSLANG_ANGLE // check for ray tracing stages if (profile != EEsProfile && version >= 450) { - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangRayGenNV, source, + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangRayGen, source, infoSink, commonTable, symbolTables); - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangIntersectNV, source, + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangIntersect, source, infoSink, commonTable, symbolTables); - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangAnyHitNV, source, + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangAnyHit, source, infoSink, commonTable, symbolTables); - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangClosestHitNV, source, + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangClosestHit, source, infoSink, commonTable, symbolTables); - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMissNV, source, + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMiss, source, infoSink, commonTable, symbolTables); - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCallableNV, source, + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCallable, source, infoSink, commonTable, symbolTables); } @@ -386,6 +399,8 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS (profile == EEsProfile && version >= 320)) InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTaskNV, source, infoSink, commonTable, symbolTables); +#endif // !GLSLANG_ANGLE +#endif // !GLSLANG_WEB return true; } @@ -487,7 +502,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp // Function to Print all builtins void DumpBuiltinSymbolTable(TInfoSink& infoSink, const TSymbolTable& symbolTable) { -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) infoSink.debug << "BuiltinSymbolTable {\n"; symbolTable.dump(infoSink, true); @@ -591,7 +606,7 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo break; } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // Correct for stage type... switch (stage) { case EShLangGeometry: @@ -623,12 +638,12 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo version = profile == EEsProfile ? 310 : 420; } break; - case EShLangRayGenNV: - case EShLangIntersectNV: - case EShLangAnyHitNV: - case EShLangClosestHitNV: - case EShLangMissNV: - case EShLangCallableNV: + case EShLangRayGen: + case EShLangIntersect: + case EShLangAnyHit: + case EShLangClosestHit: + case EShLangMiss: + case EShLangCallable: if (profile == EEsProfile || version < 460) { correct = false; infoSink.info.message(EPrefixError, "#version: ray tracing shaders require non-es profile with version 460 or above"); @@ -712,10 +727,14 @@ void TranslateEnvironment(const TEnvironment* environment, EShMessages& messages break; case EShClientVulkan: spvVersion.vulkanGlsl = environment->input.dialectVersion; + spvVersion.vulkanRelaxed = environment->input.vulkanRulesRelaxed; break; case EShClientOpenGL: spvVersion.openGl = environment->input.dialectVersion; break; + case EShClientCount: + assert(0); + break; } switch (environment->input.languageFamily) { case EShSourceNone: @@ -728,6 +747,9 @@ void TranslateEnvironment(const TEnvironment* environment, EShMessages& messages source = EShSourceHlsl; messages = static_cast(messages | EShMsgReadHlsl); break; + case EShSourceCount: + assert(0); + break; } } @@ -861,7 +883,7 @@ bool ProcessDeferred( : userInput.scanVersion(version, profile, versionNotFirstToken); bool versionNotFound = version == 0; if (forceDefaultVersionAndProfile && source == EShSourceGlsl) { -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound && (version != defaultVersion || profile != defaultProfile)) { compiler->infoSink.info << "Warning, (version, profile) forced to be (" @@ -884,10 +906,13 @@ bool ProcessDeferred( #ifdef GLSLANG_WEB profile = EEsProfile; version = 310; +#elif defined(GLSLANG_ANGLE) + profile = ECoreProfile; + version = 450; #endif bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst)); -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) bool warnVersionNotFirst = false; if (! versionWillBeError && versionNotFirstToken) { if (messages & EShMsgRelaxedErrors) @@ -929,6 +954,9 @@ bool ProcessDeferred( if (cachedTable) symbolTable->adoptLevels(*cachedTable); + if (intermediate.getUniqueId() != 0) + symbolTable->overwriteUniqueId(intermediate.getUniqueId()); + // Add built-in symbols that are potentially context dependent; // they get popped again further down. if (! AddContextSpecificSymbols(resources, compiler->infoSink, *symbolTable, version, profile, spvVersion, @@ -957,7 +985,7 @@ bool ProcessDeferred( parseContext->setLimits(*resources); if (! goodVersion) parseContext->addError(); -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) if (warnVersionNotFirst) { TSourceLoc loc; loc.init(); @@ -991,10 +1019,11 @@ bool ProcessDeferred( bool success = processingContext(*parseContext, ppContext, fullInput, versionWillBeError, *symbolTable, intermediate, optLevel, messages); + intermediate.setUniqueId(symbolTable->getMaxSymbolId()); return success; } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // Responsible for keeping track of the most recent source string and line in // the preprocessor and outputting newlines appropriately if the source string @@ -1217,14 +1246,16 @@ struct DoFullParse{ parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors. No code generated.\n\n"; } +#ifndef GLSLANG_ANGLE if (messages & EShMsgAST) intermediate.output(parseContext.infoSink, true); +#endif return success; } }; -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // Take a single compilation unit, and run the preprocessor on it. // Return: True if there were no issues found in preprocessing, // False if during preprocessing any unknown version, pragmas or @@ -1248,14 +1279,15 @@ bool PreprocessDeferred( EShMessages messages, // warnings/errors/AST; things to print out TShader::Includer& includer, TIntermediate& intermediate, // returned tree, etc. - std::string* outputString) + std::string* outputString, + TEnvironment* environment = nullptr) { DoPreprocessing parser(outputString); return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames, preamble, optLevel, resources, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, intermediate, parser, - false, includer); + false, includer, "", environment); } #endif @@ -1678,19 +1710,29 @@ int ShGetUniformLocation(const ShHandle handle, const char* name) namespace glslang { -#include "../Include/revision.h" +Version GetVersion() +{ + Version version; + version.major = GLSLANG_VERSION_MAJOR; + version.minor = GLSLANG_VERSION_MINOR; + version.patch = GLSLANG_VERSION_PATCH; + version.flavor = GLSLANG_VERSION_FLAVOR; + return version; +} #define QUOTE(s) #s #define STR(n) QUOTE(n) const char* GetEsslVersionString() { - return "OpenGL ES GLSL 3.20 glslang Khronos. " STR(GLSLANG_MINOR_VERSION) "." STR(GLSLANG_PATCH_LEVEL); + return "OpenGL ES GLSL 3.20 glslang Khronos. " STR(GLSLANG_VERSION_MAJOR) "." STR(GLSLANG_VERSION_MINOR) "." STR( + GLSLANG_VERSION_PATCH) GLSLANG_VERSION_FLAVOR; } const char* GetGlslVersionString() { - return "4.60 glslang Khronos. " STR(GLSLANG_MINOR_VERSION) "." STR(GLSLANG_PATCH_LEVEL); + return "4.60 glslang Khronos. " STR(GLSLANG_VERSION_MAJOR) "." STR(GLSLANG_VERSION_MINOR) "." STR( + GLSLANG_VERSION_PATCH) GLSLANG_VERSION_FLAVOR; } int GetKhronosToolId() @@ -1725,6 +1767,7 @@ TShader::TShader(EShLanguage s) // clear environment (avoid constructors in them for use in a C interface) environment.input.languageFamily = EShSourceNone; environment.input.dialect = EShClientNone; + environment.input.vulkanRulesRelaxed = false; environment.client.client = EShClientNone; environment.target.language = EShTargetNone; environment.target.hlslFunctionality1 = false; @@ -1771,11 +1814,18 @@ void TShader::setSourceEntryPoint(const char* name) sourceEntryPointName = name; } +// Log initial settings and transforms. +// See comment for class TProcesses. void TShader::addProcesses(const std::vector& p) { intermediate->addProcesses(p); } +void TShader::setUniqueId(unsigned long long id) +{ + intermediate->setUniqueId(id); +} + void TShader::setInvertY(bool invert) { intermediate->setInvertY(invert); } void TShader::setNanMinMaxClamp(bool useNonNan) { intermediate->setNanMinMaxClamp(useNonNan); } @@ -1824,6 +1874,15 @@ void TShader::setResourceSetBinding(const std::vector& base) { in void TShader::setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { intermediate->setTextureSamplerTransformMode(mode); } #endif +void TShader::addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing) { intermediate->addBlockStorageOverride(nameStr, backing); } + +void TShader::setGlobalUniformBlockName(const char* name) { intermediate->setGlobalUniformBlockName(name); } +void TShader::setGlobalUniformSet(unsigned int set) { intermediate->setGlobalUniformSet(set); } +void TShader::setGlobalUniformBinding(unsigned int binding) { intermediate->setGlobalUniformBinding(binding); } + +void TShader::setAtomicCounterBlockName(const char* name) { intermediate->setAtomicCounterBlockName(name); } +void TShader::setAtomicCounterBlockSet(unsigned int set) { intermediate->setAtomicCounterBlockSet(set); } + #ifdef ENABLE_HLSL // See comment above TDefaultHlslIoMapper in iomapper.cpp: void TShader::setHlslIoMapping(bool hlslIoMap) { intermediate->setHlslIoMapping(hlslIoMap); } @@ -1852,7 +1911,7 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion &environment); } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // Fill in a string with the result of preprocessing ShaderStrings // Returns true if all extensions, pragmas and version strings were valid. // @@ -1875,7 +1934,8 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources, return PreprocessDeferred(compiler, strings, numStrings, lengths, stringNames, preamble, EShOptNone, builtInResources, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, - forwardCompatible, message, includer, *intermediate, output_string); + forwardCompatible, message, includer, *intermediate, output_string, + &environment); } #endif @@ -1890,7 +1950,7 @@ const char* TShader::getInfoDebugLog() } TProgram::TProgram() : -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) reflection(0), #endif linked(false) @@ -1906,7 +1966,7 @@ TProgram::TProgram() : TProgram::~TProgram() { delete infoSink; -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) delete reflection; #endif @@ -1938,7 +1998,10 @@ bool TProgram::link(EShMessages messages) error = true; } - // TODO: Link: cross-stage error checking + if (!error) { + if (! crossStageCheck(messages)) + error = true; + } return ! error; } @@ -1953,7 +2016,7 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) if (stages[stage].size() == 0) return true; -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) int numEsShaders = 0, numNonEsShaders = 0; for (auto it = stages[stage].begin(); it != stages[stage].end(); ++it) { if ((*it)->intermediate->getProfile() == EEsProfile) { @@ -1982,7 +2045,7 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) intermediate[stage] = new TIntermediate(stage, firstIntermediate->getVersion(), firstIntermediate->getProfile()); - + intermediate[stage]->setLimits(firstIntermediate->getLimits()); // The new TIntermediate must use the same origin as the original TIntermediates. // Otherwise linking will fail due to different coordinate systems. @@ -2007,12 +2070,77 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) #endif intermediate[stage]->finalCheck(*infoSink, (messages & EShMsgKeepUncalled) != 0); +#ifndef GLSLANG_ANGLE if (messages & EShMsgAST) intermediate[stage]->output(*infoSink, true); +#endif return intermediate[stage]->getNumErrors() == 0; } +// +// Check that there are no errors in linker objects accross stages +// +// Return true if no errors. +// +bool TProgram::crossStageCheck(EShMessages) { + + // make temporary intermediates to hold the linkage symbols for each linking interface + // while we do the checks + // Independent interfaces are: + // all uniform variables and blocks + // all buffer blocks + // all in/out on a stage boundary + + TVector activeStages; + for (int s = 0; s < EShLangCount; ++s) { + if (intermediate[s]) + activeStages.push_back(intermediate[s]); + } + + // no extra linking if there is only one stage + if (! (activeStages.size() > 1)) + return true; + + // setup temporary tree to hold unfirom objects from different stages + TIntermediate* firstIntermediate = activeStages.front(); + TIntermediate uniforms(EShLangCount, + firstIntermediate->getVersion(), + firstIntermediate->getProfile()); + uniforms.setSpv(firstIntermediate->getSpv()); + + TIntermAggregate uniformObjects(EOpLinkerObjects); + TIntermAggregate root(EOpSequence); + root.getSequence().push_back(&uniformObjects); + uniforms.setTreeRoot(&root); + + bool error = false; + + // merge uniforms from all stages into a single intermediate + for (unsigned int i = 0; i < activeStages.size(); ++i) { + uniforms.mergeUniformObjects(*infoSink, *activeStages[i]); + } + error |= uniforms.getNumErrors() != 0; + + // copy final definition of global block back into each stage + for (unsigned int i = 0; i < activeStages.size(); ++i) { + // We only want to merge into already existing global uniform blocks. + // A stage that doesn't already know about the global doesn't care about it's content. + // Otherwise we end up pointing to the same object between different stages + // and that will break binding/set remappings + bool mergeExistingOnly = true; + activeStages[i]->mergeGlobalUniformBlocks(*infoSink, uniforms, mergeExistingOnly); + } + + // compare cross stage symbols for each stage boundary + for (unsigned int i = 1; i < activeStages.size(); ++i) { + activeStages[i - 1]->checkStageIO(*infoSink, *activeStages[i]); + error |= (activeStages[i - 1]->getNumErrors() != 0); + } + + return !error; +} + const char* TProgram::getInfoLog() { return infoSink->info.c_str(); @@ -2023,7 +2151,7 @@ const char* TProgram::getInfoDebugLog() return infoSink->debug.c_str(); } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // // Reflection implementation. @@ -2105,6 +2233,6 @@ bool TProgram::mapIO(TIoMapResolver* pResolver, TIoMapper* pIoMapper) return ioMapper->doMap(pResolver, *infoSink); } -#endif // GLSLANG_WEB +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE } // end namespace glslang diff --git a/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp new file mode 100644 index 00000000000..38094eaaf7c --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp @@ -0,0 +1,355 @@ +// +// Copyright(C) 2021 Advanced Micro Devices, Inc. +// +// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. +// + +#ifndef GLSLANG_WEB + +// +// GL_EXT_spirv_intrinsics +// +#include "../Include/intermediate.h" +#include "../Include/SpirvIntrinsics.h" +#include "../Include/Types.h" +#include "ParseHelper.h" + +namespace glslang { + +// +// Handle SPIR-V requirements +// +TSpirvRequirement* TParseContext::makeSpirvRequirement(const TSourceLoc& loc, const TString& name, + const TIntermAggregate* extensions, + const TIntermAggregate* capabilities) +{ + TSpirvRequirement* spirvReq = new TSpirvRequirement; + + if (name == "extensions") { + assert(extensions); + for (auto extension : extensions->getSequence()) { + assert(extension->getAsConstantUnion()); + spirvReq->extensions.insert(*extension->getAsConstantUnion()->getConstArray()[0].getSConst()); + } + } else if (name == "capabilities") { + assert(capabilities); + for (auto capability : capabilities->getSequence()) { + assert(capability->getAsConstantUnion()); + spirvReq->capabilities.insert(capability->getAsConstantUnion()->getConstArray()[0].getIConst()); + } + } else + error(loc, "unknow SPIR-V requirement", name.c_str(), ""); + + return spirvReq; +} + +TSpirvRequirement* TParseContext::mergeSpirvRequirements(const TSourceLoc& loc, TSpirvRequirement* spirvReq1, + TSpirvRequirement* spirvReq2) +{ + // Merge the second SPIR-V requirement to the first one + if (!spirvReq2->extensions.empty()) { + if (spirvReq1->extensions.empty()) + spirvReq1->extensions = spirvReq2->extensions; + else + error(loc, "too many SPIR-V requirements", "extensions", ""); + } + + if (!spirvReq2->capabilities.empty()) { + if (spirvReq1->capabilities.empty()) + spirvReq1->capabilities = spirvReq2->capabilities; + else + error(loc, "too many SPIR-V requirements", "capabilities", ""); + } + + return spirvReq1; +} + +void TIntermediate::insertSpirvRequirement(const TSpirvRequirement* spirvReq) +{ + if (!spirvRequirement) + spirvRequirement = new TSpirvRequirement; + + for (auto extension : spirvReq->extensions) + spirvRequirement->extensions.insert(extension); + + for (auto capability : spirvReq->capabilities) + spirvRequirement->capabilities.insert(capability); +} + +// +// Handle SPIR-V execution modes +// +void TIntermediate::insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args) +{ + if (!spirvExecutionMode) + spirvExecutionMode = new TSpirvExecutionMode; + + TVector extraOperands; + if (args) { + for (auto arg : args->getSequence()) { + auto extraOperand = arg->getAsConstantUnion(); + assert(extraOperand != nullptr); + extraOperands.push_back(extraOperand); + } + } + spirvExecutionMode->modes[executionMode] = extraOperands; +} + +void TIntermediate::insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args) +{ + if (!spirvExecutionMode) + spirvExecutionMode = new TSpirvExecutionMode; + + assert(args); + TVector extraOperands; + + for (auto arg : args->getSequence()) { + auto extraOperand = arg->getAsConstantUnion(); + assert(extraOperand != nullptr); + extraOperands.push_back(extraOperand); + } + spirvExecutionMode->modeIds[executionMode] = extraOperands; +} + +// +// Handle SPIR-V decorate qualifiers +// +void TQualifier::setSpirvDecorate(int decoration, const TIntermAggregate* args) +{ + if (!spirvDecorate) + spirvDecorate = new TSpirvDecorate; + + TVector extraOperands; + if (args) { + for (auto arg : args->getSequence()) { + auto extraOperand = arg->getAsConstantUnion(); + assert(extraOperand != nullptr); + extraOperands.push_back(extraOperand); + } + } + spirvDecorate->decorates[decoration] = extraOperands; +} + +void TQualifier::setSpirvDecorateId(int decoration, const TIntermAggregate* args) +{ + if (!spirvDecorate) + spirvDecorate = new TSpirvDecorate; + + assert(args); + TVector extraOperands; + for (auto arg : args->getSequence()) { + auto extraOperand = arg->getAsConstantUnion(); + assert(extraOperand != nullptr); + extraOperands.push_back(extraOperand); + } + spirvDecorate->decorateIds[decoration] = extraOperands; +} + +void TQualifier::setSpirvDecorateString(int decoration, const TIntermAggregate* args) +{ + if (!spirvDecorate) + spirvDecorate = new TSpirvDecorate; + + assert(args); + TVector extraOperands; + for (auto arg : args->getSequence()) { + auto extraOperand = arg->getAsConstantUnion(); + assert(extraOperand != nullptr); + extraOperands.push_back(extraOperand); + } + spirvDecorate->decorateStrings[decoration] = extraOperands; +} + +TString TQualifier::getSpirvDecorateQualifierString() const +{ + assert(spirvDecorate); + + TString qualifierString; + + const auto appendFloat = [&](float f) { qualifierString.append(std::to_string(f).c_str()); }; + const auto appendInt = [&](int i) { qualifierString.append(std::to_string(i).c_str()); }; + const auto appendUint = [&](unsigned int u) { qualifierString.append(std::to_string(u).c_str()); }; + const auto appendBool = [&](bool b) { qualifierString.append(std::to_string(b).c_str()); }; + const auto appendStr = [&](const char* s) { qualifierString.append(s); }; + + const auto appendDecorate = [&](const TIntermConstantUnion* constant) { + if (constant->getBasicType() == EbtFloat) { + float value = static_cast(constant->getConstArray()[0].getDConst()); + appendFloat(value); + } + else if (constant->getBasicType() == EbtInt) { + int value = constant->getConstArray()[0].getIConst(); + appendInt(value); + } + else if (constant->getBasicType() == EbtUint) { + unsigned value = constant->getConstArray()[0].getUConst(); + appendUint(value); + } + else if (constant->getBasicType() == EbtBool) { + bool value = constant->getConstArray()[0].getBConst(); + appendBool(value); + } + else if (constant->getBasicType() == EbtString) { + const TString* value = constant->getConstArray()[0].getSConst(); + appendStr(value->c_str()); + } + else + assert(0); + }; + + for (auto& decorate : spirvDecorate->decorates) { + appendStr("spirv_decorate("); + appendInt(decorate.first); + for (auto extraOperand : decorate.second) { + appendStr(", "); + appendDecorate(extraOperand); + } + appendStr(") "); + } + + for (auto& decorateId : spirvDecorate->decorateIds) { + appendStr("spirv_decorate_id("); + appendInt(decorateId.first); + for (auto extraOperand : decorateId.second) { + appendStr(", "); + appendDecorate(extraOperand); + } + appendStr(") "); + } + + for (auto& decorateString : spirvDecorate->decorateStrings) { + appendStr("spirv_decorate_string("); + appendInt(decorateString.first); + for (auto extraOperand : decorateString.second) { + appendStr(", "); + appendDecorate(extraOperand); + } + appendStr(") "); + } + + return qualifierString; +} + +// +// Handle SPIR-V type specifiers +// +void TPublicType::setSpirvType(const TSpirvInstruction& spirvInst, const TSpirvTypeParameters* typeParams) +{ + if (!spirvType) + spirvType = new TSpirvType; + + basicType = EbtSpirvType; + spirvType->spirvInst = spirvInst; + if (typeParams) + spirvType->typeParams = *typeParams; +} + +TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& loc, const TIntermConstantUnion* constant) +{ + TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters; + if (constant->getBasicType() != EbtFloat && + constant->getBasicType() != EbtInt && + constant->getBasicType() != EbtUint && + constant->getBasicType() != EbtBool && + constant->getBasicType() != EbtString) + error(loc, "this type not allowed", constant->getType().getBasicString(), ""); + else { + assert(constant); + spirvTypeParams->push_back(TSpirvTypeParameter(constant)); + } + + return spirvTypeParams; +} + +TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TPublicType& type) +{ + TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters; + spirvTypeParams->push_back(TSpirvTypeParameter(new TType(type))); + return spirvTypeParams; +} + +TSpirvTypeParameters* TParseContext::mergeSpirvTypeParameters(TSpirvTypeParameters* spirvTypeParams1, TSpirvTypeParameters* spirvTypeParams2) +{ + // Merge SPIR-V type parameters of the second one to the first one + for (const auto& spirvTypeParam : *spirvTypeParams2) + spirvTypeParams1->push_back(spirvTypeParam); + return spirvTypeParams1; +} + +// +// Handle SPIR-V instruction qualifiers +// +TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, const TString& value) +{ + TSpirvInstruction* spirvInst = new TSpirvInstruction; + if (name == "set") + spirvInst->set = value; + else + error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), ""); + + return spirvInst; +} + +TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, int value) +{ + TSpirvInstruction* spirvInstuction = new TSpirvInstruction; + if (name == "id") + spirvInstuction->id = value; + else + error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), ""); + + return spirvInstuction; +} + +TSpirvInstruction* TParseContext::mergeSpirvInstruction(const TSourceLoc& loc, TSpirvInstruction* spirvInst1, TSpirvInstruction* spirvInst2) +{ + // Merge qualifiers of the second SPIR-V instruction to those of the first one + if (!spirvInst2->set.empty()) { + if (spirvInst1->set.empty()) + spirvInst1->set = spirvInst2->set; + else + error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(set)"); + } + + if (spirvInst2->id != -1) { + if (spirvInst1->id == -1) + spirvInst1->id = spirvInst2->id; + else + error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(id)"); + } + + return spirvInst1; +} + +} // end namespace glslang + +#endif // GLSLANG_WEB diff --git a/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SymbolTable.cpp similarity index 95% rename from libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SymbolTable.cpp index 44682379f72..747b43666d1 100644 --- a/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SymbolTable.cpp @@ -3,6 +3,7 @@ // Copyright (C) 2012-2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. // Copyright (C) 2015-2018 Google, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -74,7 +75,9 @@ void TType::buildMangledName(TString& mangledName) const case EbtInt64: mangledName += "i64"; break; case EbtUint64: mangledName += "u64"; break; case EbtAtomicUint: mangledName += "au"; break; - case EbtAccStructNV: mangledName += "asnv"; break; + case EbtAccStruct: mangledName += "as"; break; + case EbtRayQuery: mangledName += "rq"; break; + case EbtSpirvType: mangledName += "spv-t"; break; #endif case EbtSampler: switch (sampler.type) { @@ -83,6 +86,8 @@ void TType::buildMangledName(TString& mangledName) const #endif case EbtInt: mangledName += "i"; break; case EbtUint: mangledName += "u"; break; + case EbtInt64: mangledName += "i64"; break; + case EbtUint64: mangledName += "u64"; break; default: break; // some compilers want this } if (sampler.isImageClass()) @@ -120,7 +125,7 @@ void TType::buildMangledName(TString& mangledName) const mangledName += "-tx-struct"; char text[16]; // plenty enough space for the small integers. - snprintf(text, sizeof(text), "%d-", sampler.getStructReturnIndex()); + snprintf(text, sizeof(text), "%u-", sampler.getStructReturnIndex()); mangledName += text; } else { switch (sampler.getVectorSize()) { @@ -144,6 +149,8 @@ void TType::buildMangledName(TString& mangledName) const if (typeName) mangledName += *typeName; for (unsigned int i = 0; i < structure->size(); ++i) { + if ((*structure)[i].type->getBasicType() == EbtVoid) + continue; mangledName += '-'; (*structure)[i].type->buildMangledName(mangledName); } @@ -164,7 +171,7 @@ void TType::buildMangledName(TString& mangledName) const for (int i = 0; i < arraySizes->getNumDims(); ++i) { if (arraySizes->getDimNode(i)) { if (arraySizes->getDimNode(i)->getAsSymbolNode()) - snprintf(buf, maxSize, "s%d", arraySizes->getDimNode(i)->getAsSymbolNode()->getId()); + snprintf(buf, maxSize, "s%lld", arraySizes->getDimNode(i)->getAsSymbolNode()->getId()); else snprintf(buf, maxSize, "s%p", arraySizes->getDimNode(i)); } else @@ -176,7 +183,7 @@ void TType::buildMangledName(TString& mangledName) const } } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // // Dump functions. @@ -384,6 +391,9 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf) implicitThis = copyOf.implicitThis; illegalImplicitThis = copyOf.illegalImplicitThis; defaultParamCount = copyOf.defaultParamCount; +#ifndef GLSLANG_WEB + spirvInst = copyOf.spirvInst; +#endif } TFunction* TFunction::clone() const diff --git a/libraries/glslang/glslang/MachineIndependent/SymbolTable.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SymbolTable.h similarity index 92% rename from libraries/glslang/glslang/MachineIndependent/SymbolTable.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SymbolTable.h index 40ca3da532c..21960930738 100644 --- a/libraries/glslang/glslang/MachineIndependent/SymbolTable.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/SymbolTable.h @@ -104,8 +104,8 @@ class TSymbol { virtual const TAnonMember* getAsAnonMember() const { return 0; } virtual const TType& getType() const = 0; virtual TType& getWritableType() = 0; - virtual void setUniqueId(int id) { uniqueId = id; } - virtual int getUniqueId() const { return uniqueId; } + virtual void setUniqueId(long long id) { uniqueId = id; } + virtual long long getUniqueId() const { return uniqueId; } virtual void setExtensions(int numExts, const char* const exts[]) { assert(extensions == 0); @@ -117,7 +117,7 @@ class TSymbol { virtual int getNumExtensions() const { return extensions == nullptr ? 0 : (int)extensions->size(); } virtual const char** getExtensions() const { return extensions->data(); } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) virtual void dump(TInfoSink& infoSink, bool complete = false) const = 0; void dumpExtensions(TInfoSink& infoSink) const; #endif @@ -130,7 +130,7 @@ class TSymbol { TSymbol& operator=(const TSymbol&); const TString *name; - unsigned int uniqueId; // For cross-scope comparing during code generation + unsigned long long uniqueId; // For cross-scope comparing during code generation // For tracking what extensions must be present // (don't use if correct version/profile is present). @@ -196,7 +196,7 @@ class TVariable : public TSymbol { } virtual const char** getMemberExtensions(int member) const { return (*memberExtensions)[member].data(); } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) virtual void dump(TInfoSink& infoSink, bool complete = false) const; #endif @@ -320,6 +320,15 @@ class TFunction : public TSymbol { virtual const TParameter& operator[](int i) const { return parameters[i]; } #ifndef GLSLANG_WEB + virtual void setSpirvInstruction(const TSpirvInstruction& inst) + { + relateToOperator(EOpSpirvInst); + spirvInst = inst; + } + virtual const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; } +#endif + +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) virtual void dump(TInfoSink& infoSink, bool complete = false) const override; #endif @@ -342,6 +351,10 @@ class TFunction : public TSymbol { // This is important for a static member function that has member variables in scope, // but is not allowed to use them, or see hidden symbols instead. int defaultParamCount; + +#ifndef GLSLANG_WEB + TSpirvInstruction spirvInst; // SPIR-V instruction qualifiers +#endif }; // @@ -381,7 +394,7 @@ class TAnonMember : public TSymbol { virtual const char** getExtensions() const override { return anonContainer.getMemberExtensions(memberNumber); } virtual int getAnonId() const { return anonId; } -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) virtual void dump(TInfoSink& infoSink, bool complete = false) const override; #endif @@ -551,7 +564,7 @@ class TSymbolTableLevel { void relateToOperator(const char* name, TOperator op); void setFunctionExtensions(const char* name, int num, const char* const extensions[]); -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) void dump(TInfoSink& infoSink, bool complete = false) const; #endif TSymbolTableLevel* clone() const; @@ -612,21 +625,28 @@ class TSymbolTable { // 3: user-shader globals // protected: + static const uint32_t LevelFlagBitOffset = 56; static const int globalLevel = 3; - bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels - bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals - bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals + static bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels + static bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals + static bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals public: bool isEmpty() { return table.size() == 0; } bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); } bool atGlobalLevel() { return isGlobalLevel(currentLevel()); } - + static bool isBuiltInSymbol(long long uniqueId) { + int level = static_cast(uniqueId >> LevelFlagBitOffset); + return isBuiltInLevel(level); + } + static constexpr uint64_t uniqueIdMask = (1LL << LevelFlagBitOffset) - 1; + static const uint32_t MaxLevelInUniqueID = 127; void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; } void setSeparateNameSpaces() { separateNameSpaces = true; } void push() { table.push_back(new TSymbolTableLevel); + updateUniqueIdLevelFlag(); } // Make a new symbol-table level to represent the scope introduced by a structure @@ -639,6 +659,7 @@ class TSymbolTable { { assert(thisSymbol.getName().size() == 0); table.push_back(new TSymbolTableLevel); + updateUniqueIdLevelFlag(); table.back()->setThisLevel(); insert(thisSymbol); } @@ -648,6 +669,7 @@ class TSymbolTable { table[currentLevel()]->getPreviousDefaultPrecisions(p); delete table.back(); table.pop_back(); + updateUniqueIdLevelFlag(); } // @@ -685,6 +707,16 @@ class TSymbolTable { return table[currentLevel()]->amend(symbol, firstNewMember); } + // Update the level info in symbol's unique ID to current level + void amendSymbolIdLevel(TSymbol& symbol) + { + // clamp level to avoid overflow + uint64_t level = (uint32_t)currentLevel() > MaxLevelInUniqueID ? MaxLevelInUniqueID : currentLevel(); + uint64_t symbolId = symbol.getUniqueId(); + symbolId &= uniqueIdMask; + symbolId |= (level << LevelFlagBitOffset); + symbol.setUniqueId(symbolId); + } // // To allocate an internal temporary, which will need to be uniquely // identified by the consumer of the AST, but never need to @@ -853,8 +885,8 @@ class TSymbolTable { } } - int getMaxSymbolId() { return uniqueId; } -#ifndef GLSLANG_WEB + long long getMaxSymbolId() { return uniqueId; } +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) void dump(TInfoSink& infoSink, bool complete = false) const; #endif void copyTable(const TSymbolTable& copyOf); @@ -867,14 +899,27 @@ class TSymbolTable { table[level]->readOnly(); } + // Add current level in the high-bits of unique id + void updateUniqueIdLevelFlag() { + // clamp level to avoid overflow + uint64_t level = (uint32_t)currentLevel() > MaxLevelInUniqueID ? MaxLevelInUniqueID : currentLevel(); + uniqueId &= uniqueIdMask; + uniqueId |= (level << LevelFlagBitOffset); + } + + void overwriteUniqueId(long long id) + { + uniqueId = id; + updateUniqueIdLevelFlag(); + } + protected: TSymbolTable(TSymbolTable&); TSymbolTable& operator=(TSymbolTableLevel&); int currentLevel() const { return static_cast(table.size()) - 1; } - std::vector table; - int uniqueId; // for unique identification in code generation + long long uniqueId; // for unique identification in code generation bool noBuiltInRedeclarations; bool separateNameSpaces; unsigned int adoptedLevels; diff --git a/libraries/glslang/glslang/MachineIndependent/Versions.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Versions.cpp similarity index 83% rename from libraries/glslang/glslang/MachineIndependent/Versions.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Versions.cpp index 23f74232b2d..097ee845529 100644 --- a/libraries/glslang/glslang/MachineIndependent/Versions.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Versions.cpp @@ -2,7 +2,8 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. -// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) 2015-2020 Google, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -63,6 +64,7 @@ // checkDeprecated() // requireNotRemoved() // requireExtensions() +// extensionRequires() // // Typically, only the first two calls are needed. They go into a code path that // implements Feature F, and will log the proper error/warning messages. Parsing @@ -77,9 +79,11 @@ // const char* const XXX_extension_X = "XXX_extension_X"; // // 2) Add extension initialization to TParseVersions::initializeExtensionBehavior(), -// the first function below: +// the first function below and optionally a entry to extensionData for additional +// error checks: // // extensionBehavior[XXX_extension_X] = EBhDisable; +// (Optional) exts[] = {XXX_extension_X, EShTargetSpv_1_4} // // 3) Add any preprocessor directives etc. in the next function, TParseVersions::getPreamble(): // @@ -139,6 +143,8 @@ // set of extensions that both enable them and are necessary, given the version of the symbol // table. (There is a different symbol table for each version.) // +// 7) If the extension has additional requirements like minimum SPIR-V version required, add them +// to extensionRequires() #include "parseVersions.h" #include "localintermediate.h" @@ -154,6 +160,22 @@ namespace glslang { // void TParseVersions::initializeExtensionBehavior() { + typedef struct { + const char *const extensionName; + EShTargetLanguageVersion minSpvVersion; + } extensionData; + + const extensionData exts[] = { {E_GL_EXT_ray_tracing, EShTargetSpv_1_4}, + {E_GL_NV_ray_tracing_motion_blur, EShTargetSpv_1_4} + }; + + for (size_t ii = 0; ii < sizeof(exts) / sizeof(exts[0]); ii++) { + // Add only extensions which require > spv1.0 to save space in map + if (exts[ii].minSpvVersion > EShTargetSpv_1_0) { + extensionMinSpv[exts[ii].extensionName] = exts[ii].minSpvVersion; + } + } + extensionBehavior[E_GL_OES_texture_3D] = EBhDisable; extensionBehavior[E_GL_OES_standard_derivatives] = EBhDisable; extensionBehavior[E_GL_EXT_frag_depth] = EBhDisable; @@ -178,12 +200,14 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_ARB_explicit_uniform_location] = EBhDisable; extensionBehavior[E_GL_ARB_shader_image_load_store] = EBhDisable; extensionBehavior[E_GL_ARB_shader_atomic_counters] = EBhDisable; + extensionBehavior[E_GL_ARB_shader_atomic_counter_ops] = EBhDisable; extensionBehavior[E_GL_ARB_shader_draw_parameters] = EBhDisable; extensionBehavior[E_GL_ARB_shader_group_vote] = EBhDisable; extensionBehavior[E_GL_ARB_derivative_control] = EBhDisable; extensionBehavior[E_GL_ARB_shader_texture_image_samples] = EBhDisable; extensionBehavior[E_GL_ARB_viewport_array] = EBhDisable; extensionBehavior[E_GL_ARB_gpu_shader_int64] = EBhDisable; + extensionBehavior[E_GL_ARB_gpu_shader_fp64] = EBhDisable; extensionBehavior[E_GL_ARB_shader_ballot] = EBhDisable; extensionBehavior[E_GL_ARB_sparse_texture2] = EBhDisable; extensionBehavior[E_GL_ARB_sparse_texture_clamp] = EBhDisable; @@ -195,6 +219,12 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_ARB_shader_clock] = EBhDisable; extensionBehavior[E_GL_ARB_uniform_buffer_object] = EBhDisable; extensionBehavior[E_GL_ARB_sample_shading] = EBhDisable; + extensionBehavior[E_GL_ARB_shader_bit_encoding] = EBhDisable; + extensionBehavior[E_GL_ARB_shader_image_size] = EBhDisable; + extensionBehavior[E_GL_ARB_shader_storage_buffer_object] = EBhDisable; + extensionBehavior[E_GL_ARB_shading_language_packing] = EBhDisable; + extensionBehavior[E_GL_ARB_texture_query_lod] = EBhDisable; + extensionBehavior[E_GL_ARB_vertex_attrib_64bit] = EBhDisable; extensionBehavior[E_GL_KHR_shader_subgroup_basic] = EBhDisable; extensionBehavior[E_GL_KHR_shader_subgroup_vote] = EBhDisable; @@ -220,9 +250,11 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_buffer_reference2] = EBhDisable; extensionBehavior[E_GL_EXT_buffer_reference_uvec2] = EBhDisable; extensionBehavior[E_GL_EXT_demote_to_helper_invocation] = EBhDisable; + extensionBehavior[E_GL_EXT_debug_printf] = EBhDisable; extensionBehavior[E_GL_EXT_shader_16bit_storage] = EBhDisable; extensionBehavior[E_GL_EXT_shader_8bit_storage] = EBhDisable; + extensionBehavior[E_GL_EXT_subgroup_uniform_control_flow] = EBhDisable; // #line and #include extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable; @@ -252,6 +284,7 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_NV_shader_subgroup_partitioned] = EBhDisable; extensionBehavior[E_GL_NV_shading_rate_image] = EBhDisable; extensionBehavior[E_GL_NV_ray_tracing] = EBhDisable; + extensionBehavior[E_GL_NV_ray_tracing_motion_blur] = EBhDisable; extensionBehavior[E_GL_NV_fragment_shader_barycentric] = EBhDisable; extensionBehavior[E_GL_NV_compute_shader_derivatives] = EBhDisable; extensionBehavior[E_GL_NV_shader_texture_footprint] = EBhDisable; @@ -277,6 +310,7 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_tessellation_point_size] = EBhDisable; extensionBehavior[E_GL_EXT_texture_buffer] = EBhDisable; extensionBehavior[E_GL_EXT_texture_cube_map_array] = EBhDisable; + extensionBehavior[E_GL_EXT_null_initializer] = EBhDisable; // OES matching AEP extensionBehavior[E_GL_OES_geometry_shader] = EBhDisable; @@ -288,11 +322,22 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_OES_tessellation_point_size] = EBhDisable; extensionBehavior[E_GL_OES_texture_buffer] = EBhDisable; extensionBehavior[E_GL_OES_texture_cube_map_array] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_integer_mix] = EBhDisable; // EXT extensions - extensionBehavior[E_GL_EXT_device_group] = EBhDisable; - extensionBehavior[E_GL_EXT_multiview] = EBhDisable; - extensionBehavior[E_GL_EXT_shader_realtime_clock] = EBhDisable; + extensionBehavior[E_GL_EXT_device_group] = EBhDisable; + extensionBehavior[E_GL_EXT_multiview] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_realtime_clock] = EBhDisable; + extensionBehavior[E_GL_EXT_ray_tracing] = EBhDisable; + extensionBehavior[E_GL_EXT_ray_query] = EBhDisable; + extensionBehavior[E_GL_EXT_ray_flags_primitive_culling] = EBhDisable; + extensionBehavior[E_GL_EXT_blend_func_extended] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_implicit_conversions] = EBhDisable; + extensionBehavior[E_GL_EXT_fragment_shading_rate] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_image_int64] = EBhDisable; + extensionBehavior[E_GL_EXT_terminate_invocation] = EBhDisable; + extensionBehavior[E_GL_EXT_shared_memory_block] = EBhDisable; + extensionBehavior[E_GL_EXT_spirv_intrinsics] = EBhDisable; // OVR extensions extensionBehavior[E_GL_OVR_multiview] = EBhDisable; @@ -313,7 +358,10 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_int16] = EBhDisable; extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_int64] = EBhDisable; extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_float16] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_atomic_float] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_atomic_float2] = EBhDisable; } + #endif // GLSLANG_WEB // Get code that is not part of a shared symbol table, is specific to this shader, @@ -335,10 +383,10 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_YUV_target 1\n" "#define GL_EXT_shader_texture_lod 1\n" "#define GL_EXT_shadow_samplers 1\n" + "#define GL_EXT_fragment_shading_rate 1\n" // AEP "#define GL_ANDROID_extension_pack_es31a 1\n" - "#define GL_KHR_blend_equation_advanced 1\n" "#define GL_OES_sample_variables 1\n" "#define GL_OES_shader_image_atomic 1\n" "#define GL_OES_shader_multisample_interpolation 1\n" @@ -352,6 +400,9 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_tessellation_point_size 1\n" "#define GL_EXT_texture_buffer 1\n" "#define GL_EXT_texture_cube_map_array 1\n" + "#define GL_EXT_shader_implicit_conversions 1\n" + "#define GL_EXT_shader_integer_mix 1\n" + "#define GL_EXT_blend_func_extended 1\n" // OES matching AEP "#define GL_OES_geometry_shader 1\n" @@ -366,11 +417,15 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_shader_non_constant_global_initializers 1\n" ; - if (isEsProfile() && version >= 300) { + if (version >= 300) { preamble += "#define GL_NV_shader_noperspective_interpolation 1\n"; } + if (version >= 310) { + preamble += "#define GL_EXT_null_initializer 1\n"; + preamble += "#define GL_EXT_subgroup_uniform_control_flow 1\n"; + } - } else { + } else { // !isEsProfile() preamble = "#define GL_FRAGMENT_PRECISION_HIGH 1\n" "#define GL_ARB_texture_rectangle 1\n" @@ -394,15 +449,22 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_ARB_shader_texture_image_samples 1\n" "#define GL_ARB_viewport_array 1\n" "#define GL_ARB_gpu_shader_int64 1\n" + "#define GL_ARB_gpu_shader_fp64 1\n" "#define GL_ARB_shader_ballot 1\n" "#define GL_ARB_sparse_texture2 1\n" "#define GL_ARB_sparse_texture_clamp 1\n" "#define GL_ARB_shader_stencil_export 1\n" "#define GL_ARB_sample_shading 1\n" + "#define GL_ARB_shader_image_size 1\n" + "#define GL_ARB_shading_language_packing 1\n" // "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members "#define GL_ARB_post_depth_coverage 1\n" "#define GL_ARB_fragment_shader_interlock 1\n" "#define GL_ARB_uniform_buffer_object 1\n" + "#define GL_ARB_shader_bit_encoding 1\n" + "#define GL_ARB_shader_storage_buffer_object 1\n" + "#define GL_ARB_texture_query_lod 1\n" + "#define GL_ARB_vertex_attrib_64bit 1\n" "#define GL_EXT_shader_non_constant_global_initializers 1\n" "#define GL_EXT_shader_image_load_formatted 1\n" "#define GL_EXT_post_depth_coverage 1\n" @@ -417,6 +479,9 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_buffer_reference2 1\n" "#define GL_EXT_buffer_reference_uvec2 1\n" "#define GL_EXT_demote_to_helper_invocation 1\n" + "#define GL_EXT_debug_printf 1\n" + "#define GL_EXT_fragment_shading_rate 1\n" + "#define GL_EXT_shared_memory_block 1\n" // GL_KHR_shader_subgroup "#define GL_KHR_shader_subgroup_basic 1\n" @@ -428,8 +493,13 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_KHR_shader_subgroup_clustered 1\n" "#define GL_KHR_shader_subgroup_quad 1\n" - "#define E_GL_EXT_shader_atomic_int64 1\n" - "#define E_GL_EXT_shader_realtime_clock 1\n" + "#define GL_EXT_shader_image_int64 1\n" + "#define GL_EXT_shader_atomic_int64 1\n" + "#define GL_EXT_shader_realtime_clock 1\n" + "#define GL_EXT_ray_tracing 1\n" + "#define GL_EXT_ray_query 1\n" + "#define GL_EXT_ray_flags_primitive_culling 1\n" + "#define GL_EXT_spirv_intrinsics 1\n" "#define GL_AMD_shader_ballot 1\n" "#define GL_AMD_shader_trinary_minmax 1\n" @@ -452,6 +522,7 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_NV_shader_subgroup_partitioned 1\n" "#define GL_NV_shading_rate_image 1\n" "#define GL_NV_ray_tracing 1\n" + "#define GL_NV_ray_tracing_motion_blur 1\n" "#define GL_NV_fragment_shader_barycentric 1\n" "#define GL_NV_compute_shader_derivatives 1\n" "#define GL_NV_shader_texture_footprint 1\n" @@ -472,6 +543,9 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_shader_subgroup_extended_types_int16 1\n" "#define GL_EXT_shader_subgroup_extended_types_int64 1\n" "#define GL_EXT_shader_subgroup_extended_types_float16 1\n" + + "#define GL_EXT_shader_atomic_float 1\n" + "#define GL_EXT_shader_atomic_float2 1\n" ; if (version >= 150) { @@ -481,6 +555,10 @@ void TParseVersions::getPreamble(std::string& preamble) if (profile == ECompatibilityProfile) preamble += "#define GL_compatibility_profile 1\n"; } + if (version >= 140) { + preamble += "#define GL_EXT_null_initializer 1\n"; + preamble += "#define GL_EXT_subgroup_uniform_control_flow 1\n"; + } #endif // GLSLANG_WEB } @@ -505,6 +583,12 @@ void TParseVersions::getPreamble(std::string& preamble) preamble += "#define GL_GOOGLE_cpp_style_line_directive 1\n" "#define GL_GOOGLE_include_directive 1\n" + "#define GL_KHR_blend_equation_advanced 1\n" + ; + + // other general extensions + preamble += + "#define GL_EXT_terminate_invocation 1\n" ; #endif @@ -527,6 +611,29 @@ void TParseVersions::getPreamble(std::string& preamble) preamble += "\n"; } #endif + +#ifndef GLSLANG_WEB + // GL_EXT_spirv_intrinsics + if (!isEsProfile()) { + switch (language) { + case EShLangVertex: preamble += "#define GL_VERTEX_SHADER 1 \n"; break; + case EShLangTessControl: preamble += "#define GL_TESSELLATION_CONTROL_SHADER 1 \n"; break; + case EShLangTessEvaluation: preamble += "#define GL_TESSELLATION_EVALUATION_SHADER 1 \n"; break; + case EShLangGeometry: preamble += "#define GL_GEOMETRY_SHADER 1 \n"; break; + case EShLangFragment: preamble += "#define GL_FRAGMENT_SHADER 1 \n"; break; + case EShLangCompute: preamble += "#define GL_COMPUTE_SHADER 1 \n"; break; + case EShLangRayGen: preamble += "#define GL_RAY_GENERATION_SHADER_EXT 1 \n"; break; + case EShLangIntersect: preamble += "#define GL_INTERSECTION_SHADER_EXT 1 \n"; break; + case EShLangAnyHit: preamble += "#define GL_ANY_HIT_SHADER_EXT 1 \n"; break; + case EShLangClosestHit: preamble += "#define GL_CLOSEST_HIT_SHADER_EXT 1 \n"; break; + case EShLangMiss: preamble += "#define GL_MISS_SHADER_EXT 1 \n"; break; + case EShLangCallable: preamble += "#define GL_CALLABLE_SHADER_EXT 1 \n"; break; + case EShLangTaskNV: preamble += "#define GL_TASK_SHADER_NV 1 \n"; break; + case EShLangMeshNV: preamble += "#define GL_MESH_SHADER_NV 1 \n"; break; + default: break; + } + } +#endif } // @@ -542,12 +649,12 @@ const char* StageName(EShLanguage stage) case EShLangTessControl: return "tessellation control"; case EShLangTessEvaluation: return "tessellation evaluation"; case EShLangGeometry: return "geometry"; - case EShLangRayGenNV: return "ray-generation"; - case EShLangIntersectNV: return "intersection"; - case EShLangAnyHitNV: return "any-hit"; - case EShLangClosestHitNV: return "closest-hit"; - case EShLangMissNV: return "miss"; - case EShLangCallableNV: return "callable"; + case EShLangRayGen: return "ray-generation"; + case EShLangIntersect: return "intersection"; + case EShLangAnyHit: return "any-hit"; + case EShLangClosestHit: return "closest-hit"; + case EShLangMiss: return "miss"; + case EShLangCallable: return "callable"; case EShLangMeshNV: return "mesh"; case EShLangTaskNV: return "task"; #endif @@ -710,7 +817,8 @@ bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExte // Use when there are no profile/version to check, it's just an error if one of the // extensions is not present. // -void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc) +void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], + const char* featureDesc) { if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return; @@ -729,7 +837,8 @@ void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, // Use by preprocessor when there are no profile/version to check, it's just an error if one of the // extensions is not present. // -void TParseVersions::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc) +void TParseVersions::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], + const char* featureDesc) { if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return; @@ -795,10 +904,14 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co error(getCurrentLoc(), "behavior not supported:", "#extension", behaviorString); return; } + bool on = behavior != EBhDisable; // check if extension is used with correct shader stage checkExtensionStage(getCurrentLoc(), extension); + // check if extension has additional requirements + extensionRequires(getCurrentLoc(), extension, behaviorString); + // update the requested extension updateExtensionBehavior(extension, behavior); @@ -861,6 +974,32 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co updateExtensionBehavior(line, "GL_EXT_shader_explicit_arithmetic_types_int64", behaviorString); else if (strcmp(extension, "GL_EXT_shader_subgroup_extended_types_float16") == 0) updateExtensionBehavior(line, "GL_EXT_shader_explicit_arithmetic_types_float16", behaviorString); + + // see if we need to update the numeric features + else if (strcmp(extension, "GL_EXT_shader_explicit_arithmetic_types") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_explicit_arithmetic_types, on); + else if (strcmp(extension, "GL_EXT_shader_explicit_arithmetic_types_int8") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_explicit_arithmetic_types_int8, on); + else if (strcmp(extension, "GL_EXT_shader_explicit_arithmetic_types_int16") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_explicit_arithmetic_types_int16, on); + else if (strcmp(extension, "GL_EXT_shader_explicit_arithmetic_types_int32") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_explicit_arithmetic_types_int32, on); + else if (strcmp(extension, "GL_EXT_shader_explicit_arithmetic_types_int64") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_explicit_arithmetic_types_int64, on); + else if (strcmp(extension, "GL_EXT_shader_explicit_arithmetic_types_float16") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_explicit_arithmetic_types_float16, on); + else if (strcmp(extension, "GL_EXT_shader_explicit_arithmetic_types_float32") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_explicit_arithmetic_types_float32, on); + else if (strcmp(extension, "GL_EXT_shader_explicit_arithmetic_types_float64") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_explicit_arithmetic_types_float64, on); + else if (strcmp(extension, "GL_EXT_shader_implicit_conversions") == 0) + intermediate.updateNumericFeature(TNumericFeatures::shader_implicit_conversions, on); + else if (strcmp(extension, "GL_ARB_gpu_shader_fp64") == 0) + intermediate.updateNumericFeature(TNumericFeatures::gpu_shader_fp64, on); + else if (strcmp(extension, "GL_AMD_gpu_shader_int16") == 0) + intermediate.updateNumericFeature(TNumericFeatures::gpu_shader_int16, on); + else if (strcmp(extension, "GL_AMD_gpu_shader_half_float") == 0) + intermediate.updateNumericFeature(TNumericFeatures::gpu_shader_half_float, on); } void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior) @@ -896,7 +1035,7 @@ void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBe } else { if (iter->second == EBhDisablePartial) warn(getCurrentLoc(), "extension is only partially supported:", "#extension", extension); - if (behavior == EBhEnable || behavior == EBhRequire) + if (behavior != EBhDisable) intermediate.addRequestedExtension(extension); iter->second = behavior; } @@ -915,6 +1054,24 @@ void TParseVersions::checkExtensionStage(const TSourceLoc& loc, const char * con } } +// Check if extension has additional requirements +void TParseVersions::extensionRequires(const TSourceLoc &loc, const char * const extension, const char *behaviorString) +{ + bool isEnabled = false; + if (!strcmp("require", behaviorString)) + isEnabled = true; + else if (!strcmp("enable", behaviorString)) + isEnabled = true; + + if (isEnabled) { + unsigned int minSpvVersion = 0; + auto iter = extensionMinSpv.find(TString(extension)); + if (iter != extensionMinSpv.end()) + minSpvVersion = iter->second; + requireSpv(loc, extension, minSpvVersion); + } +} + // Call for any operation needing full GLSL integer data-type support. void TParseVersions::fullIntegerCheck(const TSourceLoc& loc, const char* op) { @@ -925,8 +1082,13 @@ void TParseVersions::fullIntegerCheck(const TSourceLoc& loc, const char* op) // Call for any operation needing GLSL double data-type support. void TParseVersions::doubleCheck(const TSourceLoc& loc, const char* op) { - requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); - profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, nullptr, op); + + //requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); + if (language == EShLangVertex) { + const char* const f64_Extensions[] = {E_GL_ARB_gpu_shader_fp64, E_GL_ARB_vertex_attrib_64bit}; + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, 2, f64_Extensions, op); + } else + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, E_GL_ARB_gpu_shader_fp64, op); } // Call for any operation needing GLSL float16 data-type support. @@ -1146,7 +1308,7 @@ void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op) // Call for any operation removed because Vulkan SPIR-V is being generated. void TParseVersions::vulkanRemoved(const TSourceLoc& loc, const char* op) { - if (spvVersion.vulkan > 0) + if (spvVersion.vulkan > 0 && !spvVersion.vulkanRelaxed) error(loc, "not allowed when using GLSL for Vulkan", op, ""); } @@ -1167,5 +1329,12 @@ void TParseVersions::requireSpv(const TSourceLoc& loc, const char* op) error(loc, "only allowed when generating SPIR-V", op, ""); #endif } +void TParseVersions::requireSpv(const TSourceLoc& loc, const char *op, unsigned int version) +{ +#ifndef GLSLANG_WEB + if (spvVersion.spv < version) + error(loc, "not supported for current targeted SPIR-V version", op, ""); +#endif +} } // end namespace glslang diff --git a/libraries/glslang/glslang/MachineIndependent/Versions.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Versions.h similarity index 88% rename from libraries/glslang/glslang/MachineIndependent/Versions.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Versions.h index d319a2d5449..949a7a17398 100644 --- a/libraries/glslang/glslang/MachineIndependent/Versions.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/Versions.h @@ -3,6 +3,7 @@ // Copyright (C) 2012-2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. // Copyright (C) 2015-2018 Google, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -35,9 +36,12 @@ // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // + #ifndef _VERSIONS_INCLUDED_ #define _VERSIONS_INCLUDED_ +#define LAST_ELEMENT_MARKER(x) x + // // Help manage multiple profiles, versions, extensions etc. // @@ -49,12 +53,13 @@ // Don't maintain an ordinal set of enums (0,1,2,3...) to avoid all possible // defects from mixing the two different forms. // -typedef enum { +typedef enum : unsigned { EBadProfile = 0, ENoProfile = (1 << 0), // only for desktop, before profiles showed up ECoreProfile = (1 << 1), ECompatibilityProfile = (1 << 2), - EEsProfile = (1 << 3) + EEsProfile = (1 << 3), + LAST_ELEMENT_MARKER(EProfileCount), } EProfile; namespace glslang { @@ -82,11 +87,12 @@ inline const char* ProfileName(EProfile profile) // The union of all requested rule sets will be applied. // struct SpvVersion { - SpvVersion() : spv(0), vulkanGlsl(0), vulkan(0), openGl(0) {} + SpvVersion() : spv(0), vulkanGlsl(0), vulkan(0), openGl(0), vulkanRelaxed(false) {} unsigned int spv; // the version of SPIR-V to target, as defined by "word 1" of the SPIR-V binary header int vulkanGlsl; // the version of GLSL semantics for Vulkan, from GL_KHR_vulkan_glsl, for "#define VULKAN XXX" int vulkan; // the version of Vulkan, for which SPIR-V execution environment rules to use int openGl; // the version of GLSL semantics for OpenGL, from GL_ARB_gl_spirv, for "#define GL_SPIRV XXX" + bool vulkanRelaxed; // relax changes to GLSL for Vulkan, allowing some GL-specific to be compiled to Vulkan SPIR-V target }; // @@ -130,12 +136,14 @@ const char* const E_GL_ARB_explicit_attrib_location = "GL_ARB_explicit_attri const char* const E_GL_ARB_explicit_uniform_location = "GL_ARB_explicit_uniform_location"; const char* const E_GL_ARB_shader_image_load_store = "GL_ARB_shader_image_load_store"; const char* const E_GL_ARB_shader_atomic_counters = "GL_ARB_shader_atomic_counters"; +const char* const E_GL_ARB_shader_atomic_counter_ops = "GL_ARB_shader_atomic_counter_ops"; const char* const E_GL_ARB_shader_draw_parameters = "GL_ARB_shader_draw_parameters"; const char* const E_GL_ARB_shader_group_vote = "GL_ARB_shader_group_vote"; const char* const E_GL_ARB_derivative_control = "GL_ARB_derivative_control"; const char* const E_GL_ARB_shader_texture_image_samples = "GL_ARB_shader_texture_image_samples"; const char* const E_GL_ARB_viewport_array = "GL_ARB_viewport_array"; const char* const E_GL_ARB_gpu_shader_int64 = "GL_ARB_gpu_shader_int64"; +const char* const E_GL_ARB_gpu_shader_fp64 = "GL_ARB_gpu_shader_fp64"; const char* const E_GL_ARB_shader_ballot = "GL_ARB_shader_ballot"; const char* const E_GL_ARB_sparse_texture2 = "GL_ARB_sparse_texture2"; const char* const E_GL_ARB_sparse_texture_clamp = "GL_ARB_sparse_texture_clamp"; @@ -147,6 +155,12 @@ const char* const E_GL_ARB_fragment_shader_interlock = "GL_ARB_fragment_shade const char* const E_GL_ARB_shader_clock = "GL_ARB_shader_clock"; const char* const E_GL_ARB_uniform_buffer_object = "GL_ARB_uniform_buffer_object"; const char* const E_GL_ARB_sample_shading = "GL_ARB_sample_shading"; +const char* const E_GL_ARB_shader_bit_encoding = "GL_ARB_shader_bit_encoding"; +const char* const E_GL_ARB_shader_image_size = "GL_ARB_shader_image_size"; +const char* const E_GL_ARB_shader_storage_buffer_object = "GL_ARB_shader_storage_buffer_object"; +const char* const E_GL_ARB_shading_language_packing = "GL_ARB_shading_language_packing"; +const char* const E_GL_ARB_texture_query_lod = "GL_ARB_texture_query_lod"; +const char* const E_GL_ARB_vertex_attrib_64bit = "GL_ARB_vertex_attrib_64bit"; const char* const E_GL_KHR_shader_subgroup_basic = "GL_KHR_shader_subgroup_basic"; const char* const E_GL_KHR_shader_subgroup_vote = "GL_KHR_shader_subgroup_vote"; @@ -181,6 +195,18 @@ const char* const E_GL_EXT_buffer_reference2 = "GL_EXT_buffer_ref const char* const E_GL_EXT_buffer_reference_uvec2 = "GL_EXT_buffer_reference_uvec2"; const char* const E_GL_EXT_demote_to_helper_invocation = "GL_EXT_demote_to_helper_invocation"; const char* const E_GL_EXT_shader_realtime_clock = "GL_EXT_shader_realtime_clock"; +const char* const E_GL_EXT_debug_printf = "GL_EXT_debug_printf"; +const char* const E_GL_EXT_ray_tracing = "GL_EXT_ray_tracing"; +const char* const E_GL_EXT_ray_query = "GL_EXT_ray_query"; +const char* const E_GL_EXT_ray_flags_primitive_culling = "GL_EXT_ray_flags_primitive_culling"; +const char* const E_GL_EXT_blend_func_extended = "GL_EXT_blend_func_extended"; +const char* const E_GL_EXT_shader_implicit_conversions = "GL_EXT_shader_implicit_conversions"; +const char* const E_GL_EXT_fragment_shading_rate = "GL_EXT_fragment_shading_rate"; +const char* const E_GL_EXT_shader_image_int64 = "GL_EXT_shader_image_int64"; +const char* const E_GL_EXT_null_initializer = "GL_EXT_null_initializer"; +const char* const E_GL_EXT_shared_memory_block = "GL_EXT_shared_memory_block"; +const char* const E_GL_EXT_subgroup_uniform_control_flow = "GL_EXT_subgroup_uniform_control_flow"; +const char* const E_GL_EXT_spirv_intrinsics = "GL_EXT_spirv_intrinsics"; // Arrays of extensions for the above viewportEXTs duplications @@ -222,6 +248,7 @@ const char* const E_GL_NV_shader_noperspective_interpolation = "GL_NV_shader_ const char* const E_GL_NV_shader_subgroup_partitioned = "GL_NV_shader_subgroup_partitioned"; const char* const E_GL_NV_shading_rate_image = "GL_NV_shading_rate_image"; const char* const E_GL_NV_ray_tracing = "GL_NV_ray_tracing"; +const char* const E_GL_NV_ray_tracing_motion_blur = "GL_NV_ray_tracing_motion_blur"; const char* const E_GL_NV_fragment_shader_barycentric = "GL_NV_fragment_shader_barycentric"; const char* const E_GL_NV_compute_shader_derivatives = "GL_NV_compute_shader_derivatives"; const char* const E_GL_NV_shader_texture_footprint = "GL_NV_shader_texture_footprint"; @@ -252,6 +279,7 @@ const char* const E_GL_EXT_tessellation_shader = "GL_EXT_tessel const char* const E_GL_EXT_tessellation_point_size = "GL_EXT_tessellation_point_size"; const char* const E_GL_EXT_texture_buffer = "GL_EXT_texture_buffer"; const char* const E_GL_EXT_texture_cube_map_array = "GL_EXT_texture_cube_map_array"; +const char* const E_GL_EXT_shader_integer_mix = "GL_EXT_shader_integer_mix"; // OES matching AEP const char* const E_GL_OES_geometry_shader = "GL_OES_geometry_shader"; @@ -278,6 +306,10 @@ const char* const E_GL_EXT_shader_subgroup_extended_types_int8 = "GL_EXT_shad const char* const E_GL_EXT_shader_subgroup_extended_types_int16 = "GL_EXT_shader_subgroup_extended_types_int16"; const char* const E_GL_EXT_shader_subgroup_extended_types_int64 = "GL_EXT_shader_subgroup_extended_types_int64"; const char* const E_GL_EXT_shader_subgroup_extended_types_float16 = "GL_EXT_shader_subgroup_extended_types_float16"; +const char* const E_GL_EXT_terminate_invocation = "GL_EXT_terminate_invocation"; + +const char* const E_GL_EXT_shader_atomic_float = "GL_EXT_shader_atomic_float"; +const char* const E_GL_EXT_shader_atomic_float2 = "GL_EXT_shader_atomic_float2"; // Arrays of extensions for the above AEP duplications diff --git a/libraries/glslang/glslang/MachineIndependent/attribute.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/attribute.cpp similarity index 93% rename from libraries/glslang/glslang/MachineIndependent/attribute.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/attribute.cpp index 95855183493..8a92f6ae098 100644 --- a/libraries/glslang/glslang/MachineIndependent/attribute.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/attribute.cpp @@ -123,6 +123,8 @@ TAttributeType TParseContext::attributeFromName(const TString& name) const return EatPeelCount; else if (name == "partial_count") return EatPartialCount; + else if (name == "subgroup_uniform_control_flow") + return EatSubgroupUniformControlFlow; else return EatNone; } @@ -341,6 +343,29 @@ void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermN } } + +// +// Function attributes +// +void TParseContext::handleFunctionAttributes(const TSourceLoc& loc, const TAttributes& attributes, TFunction* function) +{ + for (auto it = attributes.begin(); it != attributes.end(); ++it) { + if (it->size() > 0) { + warn(loc, "attribute with arguments not recognized, skipping", "", ""); + continue; + } + + switch (it->name) { + case EatSubgroupUniformControlFlow: + intermediate.setSubgroupUniformControlFlow(); + break; + default: + warn(loc, "attribute does not apply to a function", "", ""); + break; + } + } +} + } // end namespace glslang #endif // GLSLANG_WEB diff --git a/libraries/glslang/glslang/MachineIndependent/attribute.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/attribute.h similarity index 98% rename from libraries/glslang/glslang/MachineIndependent/attribute.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/attribute.h index 38a943d2833..c5b29176c49 100644 --- a/libraries/glslang/glslang/MachineIndependent/attribute.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/attribute.h @@ -118,7 +118,8 @@ namespace glslang { EatFormatR8ui, EatFormatUnknown, EatNonWritable, - EatNonReadable + EatNonReadable, + EatSubgroupUniformControlFlow, }; class TIntermAggregate; diff --git a/libraries/glslang/glslang/MachineIndependent/gl_types.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/gl_types.h similarity index 95% rename from libraries/glslang/glslang/MachineIndependent/gl_types.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/gl_types.h index b6f613bcedc..d6c939374a8 100644 --- a/libraries/glslang/glslang/MachineIndependent/gl_types.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/gl_types.h @@ -49,9 +49,17 @@ #define GL_INT64_VEC4_ARB 0x8FEB #define GL_UNSIGNED_INT64_ARB 0x140F -#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FE5 -#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FE6 -#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FE7 +#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 +#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 +#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 +#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 + +#define GL_INT16_NV 0x8FE4 +#define GL_INT16_VEC2_NV 0x8FE5 +#define GL_INT16_VEC3_NV 0x8FE6 +#define GL_INT16_VEC4_NV 0x8FE7 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 diff --git a/libraries/glslang/glslang/MachineIndependent/glslang.m4 b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang.m4 similarity index 82% rename from libraries/glslang/glslang/MachineIndependent/glslang.m4 rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang.m4 index 20f2ba40dfa..93041ce39e5 100644 --- a/libraries/glslang/glslang/MachineIndependent/glslang.m4 +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang.m4 @@ -2,7 +2,8 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. -// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) 2015-2019 Google, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -115,6 +116,9 @@ using namespace glslang; glslang::TIntermNodePair nodePair; glslang::TIntermTyped* intermTypedNode; glslang::TAttributes* attributes; + glslang::TSpirvRequirement* spirvReq; + glslang::TSpirvInstruction* spirvInst; + glslang::TSpirvTypeParameters* spirvTypeParams; }; union { glslang::TPublicType type; @@ -204,6 +208,8 @@ GLSLANG_WEB_EXCLUDE_ON %token F64MAT4X2 F64MAT4X3 F64MAT4X4 %token ATOMIC_UINT %token ACCSTRUCTNV +%token ACCSTRUCTEXT +%token RAYQUERYEXT %token FCOOPMATNV ICOOPMATNV UCOOPMATNV // combined image/sampler @@ -239,6 +245,18 @@ GLSLANG_WEB_EXCLUDE_ON %token F16IMAGECUBE F16IMAGE1DARRAY F16IMAGE2DARRAY F16IMAGECUBEARRAY %token F16IMAGEBUFFER F16IMAGE2DMS F16IMAGE2DMSARRAY +%token I64IMAGE1D U64IMAGE1D +%token I64IMAGE2D U64IMAGE2D +%token I64IMAGE3D U64IMAGE3D +%token I64IMAGE2DRECT U64IMAGE2DRECT +%token I64IMAGECUBE U64IMAGECUBE +%token I64IMAGEBUFFER U64IMAGEBUFFER +%token I64IMAGE1DARRAY U64IMAGE1DARRAY +%token I64IMAGE2DARRAY U64IMAGE2DARRAY +%token I64IMAGECUBEARRAY U64IMAGECUBEARRAY +%token I64IMAGE2DMS U64IMAGE2DMS +%token I64IMAGE2DMSARRAY U64IMAGE2DMSARRAY + // texture without sampler %token TEXTURECUBEARRAY ITEXTURECUBEARRAY UTEXTURECUBEARRAY %token TEXTURE1D ITEXTURE1D UTEXTURE1D @@ -256,6 +274,11 @@ GLSLANG_WEB_EXCLUDE_ON %token SUBPASSINPUT SUBPASSINPUTMS ISUBPASSINPUT ISUBPASSINPUTMS USUBPASSINPUT USUBPASSINPUTMS %token F16SUBPASSINPUT F16SUBPASSINPUTMS +// spirv intrinsics +%token SPIRV_INSTRUCTION SPIRV_EXECUTION_MODE SPIRV_EXECUTION_MODE_ID +%token SPIRV_DECORATE SPIRV_DECORATE_ID SPIRV_DECORATE_STRING +%token SPIRV_TYPE SPIRV_STORAGE_CLASS SPIRV_BY_REFERENCE SPIRV_LITERAL + GLSLANG_WEB_EXCLUDE_OFF %token LEFT_OP RIGHT_OP @@ -263,6 +286,7 @@ GLSLANG_WEB_EXCLUDE_OFF %token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN %token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN %token SUB_ASSIGN +%token STRING_LITERAL %token LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT %token COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT @@ -277,6 +301,8 @@ GLSLANG_WEB_EXCLUDE_OFF %token CENTROID IN OUT INOUT %token STRUCT VOID WHILE %token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT +%token TERMINATE_INVOCATION +%token TERMINATE_RAY IGNORE_INTERSECTION %token UNIFORM SHARED BUFFER %token FLAT SMOOTH LAYOUT @@ -285,9 +311,10 @@ GLSLANG_WEB_EXCLUDE_ON %token INT64CONSTANT UINT64CONSTANT %token SUBROUTINE DEMOTE %token PAYLOADNV PAYLOADINNV HITATTRNV CALLDATANV CALLDATAINNV +%token PAYLOADEXT PAYLOADINEXT HITATTREXT CALLDATAEXT CALLDATAINEXT %token PATCH SAMPLE NONUNIFORM %token COHERENT VOLATILE RESTRICT READONLY WRITEONLY DEVICECOHERENT QUEUEFAMILYCOHERENT WORKGROUPCOHERENT -%token SUBGROUPCOHERENT NONPRIVATE +%token SUBGROUPCOHERENT NONPRIVATE SHADERCALLCOHERENT %token NOPERSPECTIVE EXPLICITINTERPAMD PERVERTEXNV PERPRIMITIVENV PERVIEWNV PERTASKNV %token PRECISE GLSLANG_WEB_EXCLUDE_OFF @@ -343,6 +370,19 @@ GLSLANG_WEB_EXCLUDE_ON %type attribute attribute_list single_attribute %type demote_statement %type initializer_list +%type spirv_requirements_list spirv_requirements_parameter +%type spirv_extension_list spirv_capability_list +%type spirv_execution_mode_qualifier +%type spirv_execution_mode_parameter_list spirv_execution_mode_parameter spirv_execution_mode_id_parameter_list +%type spirv_storage_class_qualifier +%type spirv_decorate_qualifier +%type spirv_decorate_parameter_list spirv_decorate_parameter +%type spirv_decorate_id_parameter_list +%type spirv_decorate_string_parameter_list +%type spirv_type_specifier +%type spirv_type_parameter_list spirv_type_parameter +%type spirv_instruction_qualifier +%type spirv_instruction_qualifier_list spirv_instruction_qualifier_id GLSLANG_WEB_EXCLUDE_OFF %start translation_unit @@ -377,6 +417,9 @@ primary_expression $$ = parseContext.intermediate.addConstantUnion($1.b, $1.loc, true); } GLSLANG_WEB_EXCLUDE_ON + | STRING_LITERAL { + $$ = parseContext.intermediate.addConstantUnion($1.string, $1.loc, true); + } | INT32CONSTANT { parseContext.explicitInt32Check($1.loc, "32-bit signed literal"); $$ = parseContext.intermediate.addConstantUnion($1.i, $1.loc, true); @@ -402,7 +445,9 @@ GLSLANG_WEB_EXCLUDE_ON $$ = parseContext.intermediate.addConstantUnion((unsigned short)$1.u, $1.loc, true); } | DOUBLECONSTANT { - parseContext.doubleCheck($1.loc, "double literal"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double literal"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double literal"); $$ = parseContext.intermediate.addConstantUnion($1.d, EbtDouble, $1.loc, true); } | FLOAT16CONSTANT { @@ -768,7 +813,7 @@ assignment_expression parseContext.specializationCheck($2.loc, $1->getType(), "="); parseContext.lValueErrorCheck($2.loc, "assign", $1); parseContext.rValueErrorCheck($2.loc, "assign", $3); - $$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.loc); + $$ = parseContext.addAssign($2.loc, $2.op, $1, $3); if ($$ == 0) { parseContext.assignError($2.loc, "assign", $1->getCompleteString(), $3->getCompleteString()); $$ = $1; @@ -851,6 +896,20 @@ declaration $$ = 0; // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature } +GLSLANG_WEB_EXCLUDE_ON + | spirv_instruction_qualifier function_prototype SEMICOLON { + parseContext.requireExtensions($2.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V instruction qualifier"); + $2.function->setSpirvInstruction(*$1); // Attach SPIR-V intruction qualifier + parseContext.handleFunctionDeclarator($2.loc, *$2.function, true /* prototype */); + $$ = 0; + // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature + } + | spirv_execution_mode_qualifier SEMICOLON { + parseContext.globalCheck($2.loc, "SPIR-V execution mode qualifier"); + parseContext.requireExtensions($2.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V execution mode qualifier"); + $$ = 0; + } +GLSLANG_WEB_EXCLUDE_OFF | init_declarator_list SEMICOLON { if ($1.intermNode && $1.intermNode->getAsAggregate()) $1.intermNode->getAsAggregate()->setOperator(EOpSequence); @@ -895,7 +954,7 @@ declaration block_structure : type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE { - --parseContext.structNestingLevel; + --parseContext.blockNestingLevel; parseContext.blockName = $2.string; parseContext.globalQualifierFixCheck($1.loc, $1.qualifier); parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers); @@ -920,6 +979,25 @@ function_prototype $$.function = $1; $$.loc = $2.loc; } + | function_declarator RIGHT_PAREN attribute { + $$.function = $1; + $$.loc = $2.loc; + parseContext.requireExtensions($2.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes($2.loc, *$3, $$.function); + } + | attribute function_declarator RIGHT_PAREN { + $$.function = $2; + $$.loc = $3.loc; + parseContext.requireExtensions($3.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes($3.loc, *$1, $$.function); + } + | attribute function_declarator RIGHT_PAREN attribute { + $$.function = $2; + $$.loc = $3.loc; + parseContext.requireExtensions($3.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes($3.loc, *$1, $$.function); + parseContext.handleFunctionAttributes($3.loc, *$4, $$.function); + } ; function_declarator @@ -1323,6 +1401,25 @@ GLSLANG_WEB_EXCLUDE_ON | non_uniform_qualifier { $$ = $1; } + | spirv_storage_class_qualifier { + parseContext.globalCheck($1.loc, "spirv_storage_class"); + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V storage class qualifier"); + $$ = $1; + } + | spirv_decorate_qualifier { + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V decorate qualifier"); + $$ = $1; + } + | SPIRV_BY_REFERENCE { + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "spirv_by_reference"); + $$.init($1.loc); + $$.qualifier.setSpirvByReference(); + } + | SPIRV_LITERAL { + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "spirv_by_literal"); + $$.init($1.loc); + $$.qualifier.setSpirvLiteral(); + } GLSLANG_WEB_EXCLUDE_OFF ; @@ -1413,42 +1510,81 @@ GLSLANG_WEB_EXCLUDE_ON } | HITATTRNV { parseContext.globalCheck($1.loc, "hitAttributeNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangIntersectNVMask | EShLangClosestHitNVMask - | EShLangAnyHitNVMask), "hitAttributeNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask + | EShLangAnyHitMask), "hitAttributeNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "hitAttributeNV"); $$.init($1.loc); - $$.qualifier.storage = EvqHitAttrNV; + $$.qualifier.storage = EvqHitAttr; + } + | HITATTREXT { + parseContext.globalCheck($1.loc, "hitAttributeEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask + | EShLangAnyHitMask), "hitAttributeEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "hitAttributeNV"); + $$.init($1.loc); + $$.qualifier.storage = EvqHitAttr; } | PAYLOADNV { parseContext.globalCheck($1.loc, "rayPayloadNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenNVMask | EShLangClosestHitNVMask | - EShLangAnyHitNVMask | EShLangMissNVMask), "rayPayloadNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "rayPayloadNV"); $$.init($1.loc); - $$.qualifier.storage = EvqPayloadNV; + $$.qualifier.storage = EvqPayload; + } + | PAYLOADEXT { + parseContext.globalCheck($1.loc, "rayPayloadEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "rayPayloadEXT"); + $$.init($1.loc); + $$.qualifier.storage = EvqPayload; } | PAYLOADINNV { parseContext.globalCheck($1.loc, "rayPayloadInNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangClosestHitNVMask | - EShLangAnyHitNVMask | EShLangMissNVMask), "rayPayloadInNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadInNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "rayPayloadInNV"); $$.init($1.loc); - $$.qualifier.storage = EvqPayloadInNV; + $$.qualifier.storage = EvqPayloadIn; + } + | PAYLOADINEXT { + parseContext.globalCheck($1.loc, "rayPayloadInEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadInEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "rayPayloadInEXT"); + $$.init($1.loc); + $$.qualifier.storage = EvqPayloadIn; } | CALLDATANV { parseContext.globalCheck($1.loc, "callableDataNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenNVMask | - EShLangClosestHitNVMask | EShLangMissNVMask | EShLangCallableNVMask), "callableDataNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | + EShLangClosestHitMask | EShLangMissMask | EShLangCallableMask), "callableDataNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "callableDataNV"); $$.init($1.loc); - $$.qualifier.storage = EvqCallableDataNV; + $$.qualifier.storage = EvqCallableData; + } + | CALLDATAEXT { + parseContext.globalCheck($1.loc, "callableDataEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | + EShLangClosestHitMask | EShLangMissMask | EShLangCallableMask), "callableDataEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "callableDataEXT"); + $$.init($1.loc); + $$.qualifier.storage = EvqCallableData; } | CALLDATAINNV { parseContext.globalCheck($1.loc, "callableDataInNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangCallableNVMask), "callableDataInNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "callableDataInNV"); $$.init($1.loc); - $$.qualifier.storage = EvqCallableDataInNV; + $$.qualifier.storage = EvqCallableDataIn; + } + | CALLDATAINEXT { + parseContext.globalCheck($1.loc, "callableDataInEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "callableDataInEXT"); + $$.init($1.loc); + $$.qualifier.storage = EvqCallableDataIn; } | COHERENT { $$.init($1.loc); @@ -1479,6 +1615,11 @@ GLSLANG_WEB_EXCLUDE_ON parseContext.requireExtensions($1.loc, 1, &E_GL_KHR_memory_scope_semantics, "nonprivate"); $$.qualifier.nonprivate = true; } + | SHADERCALLCOHERENT { + $$.init($1.loc); + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_ray_tracing, "shadercallcoherent"); + $$.qualifier.shadercallcoherent = true; + } | VOLATILE { $$.init($1.loc); $$.qualifier.volatil = true; @@ -1751,7 +1892,9 @@ type_specifier_nonarray } GLSLANG_WEB_EXCLUDE_ON | DOUBLE { - parseContext.doubleCheck($1.loc, "double"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; } @@ -1811,19 +1954,25 @@ GLSLANG_WEB_EXCLUDE_ON $$.basicType = EbtUint64; } | DVEC2 { - parseContext.doubleCheck($1.loc, "double vector"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double vector"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setVector(2); } | DVEC3 { - parseContext.doubleCheck($1.loc, "double vector"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double vector"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setVector(3); } | DVEC4 { - parseContext.doubleCheck($1.loc, "double vector"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double vector"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setVector(4); @@ -2027,73 +2176,97 @@ GLSLANG_WEB_EXCLUDE_ON $$.setVector(4); } | DMAT2 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(2, 2); } | DMAT3 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(3, 3); } | DMAT4 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(4, 4); } | DMAT2X2 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(2, 2); } | DMAT2X3 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(2, 3); } | DMAT2X4 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(2, 4); } | DMAT3X2 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(3, 2); } | DMAT3X3 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(3, 3); } | DMAT3X4 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(3, 4); } | DMAT4X2 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(4, 2); } | DMAT4X3 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(4, 3); } | DMAT4X4 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(4, 4); @@ -2316,7 +2489,15 @@ GLSLANG_WEB_EXCLUDE_ON } | ACCSTRUCTNV { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); - $$.basicType = EbtAccStructNV; + $$.basicType = EbtAccStruct; + } + | ACCSTRUCTEXT { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtAccStruct; + } + | RAYQUERYEXT { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtRayQuery; } | ATOMIC_UINT { parseContext.vulkanRemoved($1.loc, "atomic counter types"); @@ -3109,6 +3290,116 @@ GLSLANG_WEB_EXCLUDE_ON $$.basicType = EbtSampler; $$.sampler.setImage(EbtUint, Esd2D, true, false, true); } + | I64IMAGE1D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd1D); + } + | U64IMAGE1D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd1D); + } + | I64IMAGE2D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd2D); + } + | U64IMAGE2D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd2D); + } + | I64IMAGE3D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd3D); + } + | U64IMAGE3D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd3D); + } + | I64IMAGE2DRECT { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, EsdRect); + } + | U64IMAGE2DRECT { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, EsdRect); + } + | I64IMAGECUBE { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, EsdCube); + } + | U64IMAGECUBE { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, EsdCube); + } + | I64IMAGEBUFFER { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, EsdBuffer); + } + | U64IMAGEBUFFER { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, EsdBuffer); + } + | I64IMAGE1DARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd1D, true); + } + | U64IMAGE1DARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd1D, true); + } + | I64IMAGE2DARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd2D, true); + } + | U64IMAGE2DARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd2D, true); + } + | I64IMAGECUBEARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, EsdCube, true); + } + | U64IMAGECUBEARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, EsdCube, true); + } + | I64IMAGE2DMS { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd2D, false, false, true); + } + | U64IMAGE2DMS { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd2D, false, false, true); + } + | I64IMAGE2DMSARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd2D, true, false, true); + } + | U64IMAGE2DMSARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd2D, true, false, true); + } | SAMPLEREXTERNALOES { // GL_OES_EGL_image_external $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -3189,6 +3480,10 @@ GLSLANG_WEB_EXCLUDE_ON $$.basicType = EbtUint; $$.coopmat = true; } + | spirv_type_specifier { + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V type specifier"); + $$ = $1; + } GLSLANG_WEB_EXCLUDE_OFF | struct_specifier { $$ = $1; @@ -3357,6 +3652,12 @@ GLSLANG_WEB_EXCLUDE_ON parseContext.profileRequires($1.loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); $$ = $2; } + | LEFT_BRACE RIGHT_BRACE { + const char* initFeature = "empty { } initializer"; + parseContext.profileRequires($1.loc, EEsProfile, 0, E_GL_EXT_null_initializer, initFeature); + parseContext.profileRequires($1.loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, initFeature); + $$ = parseContext.intermediate.makeAggregate($1.loc); + } GLSLANG_WEB_EXCLUDE_OFF ; @@ -3489,6 +3790,7 @@ selection_statement } GLSLANG_WEB_EXCLUDE_ON | attribute selection_statement_nonattributed { + parseContext.requireExtensions($2->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); parseContext.handleSelectionAttributes(*$1, $2); $$ = $2; } @@ -3536,6 +3838,7 @@ switch_statement } GLSLANG_WEB_EXCLUDE_ON | attribute switch_statement_nonattributed { + parseContext.requireExtensions($2->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); parseContext.handleSwitchAttributes(*$1, $2); $$ = $2; } @@ -3600,6 +3903,7 @@ iteration_statement } GLSLANG_WEB_EXCLUDE_ON | attribute iteration_statement_nonattributed { + parseContext.requireExtensions($2->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); parseContext.handleLoopAttributes(*$1, $2); $$ = $2; } @@ -3711,6 +4015,20 @@ jump_statement parseContext.requireStage($1.loc, EShLangFragment, "discard"); $$ = parseContext.intermediate.addBranch(EOpKill, $1.loc); } + | TERMINATE_INVOCATION SEMICOLON { + parseContext.requireStage($1.loc, EShLangFragment, "terminateInvocation"); + $$ = parseContext.intermediate.addBranch(EOpTerminateInvocation, $1.loc); + } +GLSLANG_WEB_EXCLUDE_ON + | TERMINATE_RAY SEMICOLON { + parseContext.requireStage($1.loc, EShLangAnyHit, "terminateRayEXT"); + $$ = parseContext.intermediate.addBranch(EOpTerminateRayKHR, $1.loc); + } + | IGNORE_INTERSECTION SEMICOLON { + parseContext.requireStage($1.loc, EShLangAnyHit, "ignoreIntersectionEXT"); + $$ = parseContext.intermediate.addBranch(EOpIgnoreIntersectionKHR, $1.loc); + } +GLSLANG_WEB_EXCLUDE_OFF ; // Grammar Note: No 'goto'. Gotos are not supported. @@ -3748,6 +4066,14 @@ function_definition : function_prototype { $1.function = parseContext.handleFunctionDeclarator($1.loc, *$1.function, false /* not prototype */); $1.intermNode = parseContext.handleFunctionDefinition($1.loc, *$1.function); + + // For ES 100 only, according to ES shading language 100 spec: A function + // body has a scope nested inside the function's definition. + if (parseContext.profile == EEsProfile && parseContext.version == 100) + { + parseContext.symbolTable.push(); + ++parseContext.statementNestingLevel; + } } compound_statement_no_new_scope { // May be best done as post process phase on intermediate code @@ -3763,6 +4089,17 @@ function_definition $$->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize); $$->getAsAggregate()->setDebug(parseContext.contextPragma.debug); $$->getAsAggregate()->setPragmaTable(parseContext.contextPragma.pragmaTable); + + // Set currentFunctionType to empty pointer when goes outside of the function + parseContext.currentFunctionType = nullptr; + + // For ES 100 only, according to ES shading language 100 spec: A function + // body has a scope nested inside the function's definition. + if (parseContext.profile == EEsProfile && parseContext.version == 100) + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + } } ; @@ -3770,7 +4107,6 @@ GLSLANG_WEB_EXCLUDE_ON attribute : LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET { $$ = $3; - parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_control_flow_attributes, "attribute"); } attribute_list @@ -3790,4 +4126,273 @@ single_attribute } GLSLANG_WEB_EXCLUDE_OFF +GLSLANG_WEB_EXCLUDE_ON +spirv_requirements_list + : spirv_requirements_parameter { + $$ = $1; + } + | spirv_requirements_list COMMA spirv_requirements_parameter { + $$ = parseContext.mergeSpirvRequirements($2.loc, $1, $3); + } + +spirv_requirements_parameter + : IDENTIFIER EQUAL LEFT_BRACKET spirv_extension_list RIGHT_BRACKET { + $$ = parseContext.makeSpirvRequirement($2.loc, *$1.string, $4->getAsAggregate(), nullptr); + } + | IDENTIFIER EQUAL LEFT_BRACKET spirv_capability_list RIGHT_BRACKET { + $$ = parseContext.makeSpirvRequirement($2.loc, *$1.string, nullptr, $4->getAsAggregate()); + } + +spirv_extension_list + : STRING_LITERAL { + $$ = parseContext.intermediate.makeAggregate(parseContext.intermediate.addConstantUnion($1.string, $1.loc, true)); + } + | spirv_extension_list COMMA STRING_LITERAL { + $$ = parseContext.intermediate.growAggregate($1, parseContext.intermediate.addConstantUnion($3.string, $3.loc, true)); + } + +spirv_capability_list + : INTCONSTANT { + $$ = parseContext.intermediate.makeAggregate(parseContext.intermediate.addConstantUnion($1.i, $1.loc, true)); + } + | spirv_capability_list COMMA INTCONSTANT { + $$ = parseContext.intermediate.growAggregate($1, parseContext.intermediate.addConstantUnion($3.i, $3.loc, true)); + } + +spirv_execution_mode_qualifier + : SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT RIGHT_PAREN { + parseContext.intermediate.insertSpirvExecutionMode($3.i); + $$ = 0; + } + | SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN { + parseContext.intermediate.insertSpirvRequirement($3); + parseContext.intermediate.insertSpirvExecutionMode($5.i); + $$ = 0; + } + | SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvExecutionMode($3.i, $5->getAsAggregate()); + $$ = 0; + } + | SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvRequirement($3); + parseContext.intermediate.insertSpirvExecutionMode($5.i, $7->getAsAggregate()); + $$ = 0; + } + | SPIRV_EXECUTION_MODE_ID LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvExecutionModeId($3.i, $5->getAsAggregate()); + $$ = 0; + } + | SPIRV_EXECUTION_MODE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvRequirement($3); + parseContext.intermediate.insertSpirvExecutionModeId($5.i, $7->getAsAggregate()); + $$ = 0; + } + +spirv_execution_mode_parameter_list + : spirv_execution_mode_parameter { + $$ = parseContext.intermediate.makeAggregate($1); + } + | spirv_execution_mode_parameter_list COMMA spirv_execution_mode_parameter { + $$ = parseContext.intermediate.growAggregate($1, $3); + } + +spirv_execution_mode_parameter + : FLOATCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.d, EbtFloat, $1.loc, true); + } + | INTCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.i, $1.loc, true); + } + | UINTCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.u, $1.loc, true); + } + | BOOLCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.b, $1.loc, true); + } + | STRING_LITERAL { + $$ = parseContext.intermediate.addConstantUnion($1.string, $1.loc, true); + } + +spirv_execution_mode_id_parameter_list + : constant_expression { + if ($1->getBasicType() != EbtFloat && + $1->getBasicType() != EbtInt && + $1->getBasicType() != EbtUint && + $1->getBasicType() != EbtBool && + $1->getBasicType() != EbtString) + parseContext.error($1->getLoc(), "this type not allowed", $1->getType().getBasicString(), ""); + $$ = parseContext.intermediate.makeAggregate($1); + } + | spirv_execution_mode_id_parameter_list COMMA constant_expression { + if ($3->getBasicType() != EbtFloat && + $3->getBasicType() != EbtInt && + $3->getBasicType() != EbtUint && + $3->getBasicType() != EbtBool && + $3->getBasicType() != EbtString) + parseContext.error($3->getLoc(), "this type not allowed", $3->getType().getBasicString(), ""); + $$ = parseContext.intermediate.growAggregate($1, $3); + } + +spirv_storage_class_qualifier + : SPIRV_STORAGE_CLASS LEFT_PAREN INTCONSTANT RIGHT_PAREN { + $$.init($1.loc); + $$.qualifier.storage = EvqSpirvStorageClass; + $$.qualifier.spirvStorageClass = $3.i; + } + | SPIRV_STORAGE_CLASS LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN { + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.storage = EvqSpirvStorageClass; + $$.qualifier.spirvStorageClass = $5.i; + } + +spirv_decorate_qualifier + : SPIRV_DECORATE LEFT_PAREN INTCONSTANT RIGHT_PAREN{ + $$.init($1.loc); + $$.qualifier.setSpirvDecorate($3.i); + } + | SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN{ + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.setSpirvDecorate($5.i); + } + | SPIRV_DECORATE LEFT_PAREN INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN { + $$.init($1.loc); + $$.qualifier.setSpirvDecorate($3.i, $5->getAsAggregate()); + } + | SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN { + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.setSpirvDecorate($5.i, $7->getAsAggregate()); + } + | SPIRV_DECORATE_ID LEFT_PAREN INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN { + $$.init($1.loc); + $$.qualifier.setSpirvDecorateId($3.i, $5->getAsAggregate()); + } + | SPIRV_DECORATE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN { + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.setSpirvDecorateId($5.i, $7->getAsAggregate()); + } + | SPIRV_DECORATE_STRING LEFT_PAREN INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN { + $$.init($1.loc); + $$.qualifier.setSpirvDecorateString($3.i, $5->getAsAggregate()); + } + | SPIRV_DECORATE_STRING LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN { + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.setSpirvDecorateString($5.i, $7->getAsAggregate()); + } + +spirv_decorate_parameter_list + : spirv_decorate_parameter { + $$ = parseContext.intermediate.makeAggregate($1); + } + | spirv_decorate_parameter_list COMMA spirv_decorate_parameter { + $$ = parseContext.intermediate.growAggregate($1, $3); + } + +spirv_decorate_parameter + : FLOATCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.d, EbtFloat, $1.loc, true); + } + | INTCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.i, $1.loc, true); + } + | UINTCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.u, $1.loc, true); + } + | BOOLCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.b, $1.loc, true); + } + +spirv_decorate_id_parameter_list + : constant_expression { + if ($1->getBasicType() != EbtFloat && + $1->getBasicType() != EbtInt && + $1->getBasicType() != EbtUint && + $1->getBasicType() != EbtBool) + parseContext.error($1->getLoc(), "this type not allowed", $1->getType().getBasicString(), ""); + $$ = parseContext.intermediate.makeAggregate($1); + } + | spirv_decorate_id_parameter_list COMMA constant_expression { + if ($3->getBasicType() != EbtFloat && + $3->getBasicType() != EbtInt && + $3->getBasicType() != EbtUint && + $3->getBasicType() != EbtBool) + parseContext.error($3->getLoc(), "this type not allowed", $3->getType().getBasicString(), ""); + $$ = parseContext.intermediate.growAggregate($1, $3); + } + +spirv_decorate_string_parameter_list + : STRING_LITERAL { + $$ = parseContext.intermediate.makeAggregate( + parseContext.intermediate.addConstantUnion($1.string, $1.loc, true)); + } + | spirv_decorate_string_parameter_list COMMA STRING_LITERAL { + $$ = parseContext.intermediate.growAggregate($1, parseContext.intermediate.addConstantUnion($3.string, $3.loc, true)); + } + +spirv_type_specifier + : SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.setSpirvType(*$3, $5); + } + | SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.intermediate.insertSpirvRequirement($3); + $$.setSpirvType(*$5, $7); + } + | SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.setSpirvType(*$3); + } + | SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.intermediate.insertSpirvRequirement($3); + $$.setSpirvType(*$5); + } + +spirv_type_parameter_list + : spirv_type_parameter { + $$ = $1; + } + | spirv_type_parameter_list COMMA spirv_type_parameter { + $$ = parseContext.mergeSpirvTypeParameters($1, $3); + } + +spirv_type_parameter + : constant_expression { + $$ = parseContext.makeSpirvTypeParameters($1->getLoc(), $1->getAsConstantUnion()); + } + | type_specifier { + $$ = parseContext.makeSpirvTypeParameters($1); + } + +spirv_instruction_qualifier + : SPIRV_INSTRUCTION LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN { + $$ = $3; + } + | SPIRV_INSTRUCTION LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvRequirement($3); + $$ = $5; + } + +spirv_instruction_qualifier_list + : spirv_instruction_qualifier_id { + $$ = $1; + } + | spirv_instruction_qualifier_list COMMA spirv_instruction_qualifier_id { + $$ = parseContext.mergeSpirvInstruction($2.loc, $1, $3); + } + +spirv_instruction_qualifier_id + : IDENTIFIER EQUAL STRING_LITERAL { + $$ = parseContext.makeSpirvInstruction($2.loc, *$1.string, *$3.string); + } + | IDENTIFIER EQUAL INTCONSTANT { + $$ = parseContext.makeSpirvInstruction($2.loc, *$1.string, $3.i); + } +GLSLANG_WEB_EXCLUDE_OFF + %% diff --git a/libraries/glslang/glslang/MachineIndependent/glslang.y b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang.y similarity index 82% rename from libraries/glslang/glslang/MachineIndependent/glslang.y rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang.y index e263f3d7a17..b77f4617bef 100644 --- a/libraries/glslang/glslang/MachineIndependent/glslang.y +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang.y @@ -2,7 +2,8 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. -// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) 2015-2019 Google, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -115,6 +116,9 @@ using namespace glslang; glslang::TIntermNodePair nodePair; glslang::TIntermTyped* intermTypedNode; glslang::TAttributes* attributes; + glslang::TSpirvRequirement* spirvReq; + glslang::TSpirvInstruction* spirvInst; + glslang::TSpirvTypeParameters* spirvTypeParams; }; union { glslang::TPublicType type; @@ -204,6 +208,8 @@ extern int yylex(YYSTYPE*, TParseContext&); %token F64MAT4X2 F64MAT4X3 F64MAT4X4 %token ATOMIC_UINT %token ACCSTRUCTNV +%token ACCSTRUCTEXT +%token RAYQUERYEXT %token FCOOPMATNV ICOOPMATNV UCOOPMATNV // combined image/sampler @@ -239,6 +245,18 @@ extern int yylex(YYSTYPE*, TParseContext&); %token F16IMAGECUBE F16IMAGE1DARRAY F16IMAGE2DARRAY F16IMAGECUBEARRAY %token F16IMAGEBUFFER F16IMAGE2DMS F16IMAGE2DMSARRAY +%token I64IMAGE1D U64IMAGE1D +%token I64IMAGE2D U64IMAGE2D +%token I64IMAGE3D U64IMAGE3D +%token I64IMAGE2DRECT U64IMAGE2DRECT +%token I64IMAGECUBE U64IMAGECUBE +%token I64IMAGEBUFFER U64IMAGEBUFFER +%token I64IMAGE1DARRAY U64IMAGE1DARRAY +%token I64IMAGE2DARRAY U64IMAGE2DARRAY +%token I64IMAGECUBEARRAY U64IMAGECUBEARRAY +%token I64IMAGE2DMS U64IMAGE2DMS +%token I64IMAGE2DMSARRAY U64IMAGE2DMSARRAY + // texture without sampler %token TEXTURECUBEARRAY ITEXTURECUBEARRAY UTEXTURECUBEARRAY %token TEXTURE1D ITEXTURE1D UTEXTURE1D @@ -256,6 +274,11 @@ extern int yylex(YYSTYPE*, TParseContext&); %token SUBPASSINPUT SUBPASSINPUTMS ISUBPASSINPUT ISUBPASSINPUTMS USUBPASSINPUT USUBPASSINPUTMS %token F16SUBPASSINPUT F16SUBPASSINPUTMS +// spirv intrinsics +%token SPIRV_INSTRUCTION SPIRV_EXECUTION_MODE SPIRV_EXECUTION_MODE_ID +%token SPIRV_DECORATE SPIRV_DECORATE_ID SPIRV_DECORATE_STRING +%token SPIRV_TYPE SPIRV_STORAGE_CLASS SPIRV_BY_REFERENCE SPIRV_LITERAL + %token LEFT_OP RIGHT_OP @@ -263,6 +286,7 @@ extern int yylex(YYSTYPE*, TParseContext&); %token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN %token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN %token SUB_ASSIGN +%token STRING_LITERAL %token LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT %token COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT @@ -277,6 +301,8 @@ extern int yylex(YYSTYPE*, TParseContext&); %token CENTROID IN OUT INOUT %token STRUCT VOID WHILE %token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT +%token TERMINATE_INVOCATION +%token TERMINATE_RAY IGNORE_INTERSECTION %token UNIFORM SHARED BUFFER %token FLAT SMOOTH LAYOUT @@ -285,9 +311,10 @@ extern int yylex(YYSTYPE*, TParseContext&); %token INT64CONSTANT UINT64CONSTANT %token SUBROUTINE DEMOTE %token PAYLOADNV PAYLOADINNV HITATTRNV CALLDATANV CALLDATAINNV +%token PAYLOADEXT PAYLOADINEXT HITATTREXT CALLDATAEXT CALLDATAINEXT %token PATCH SAMPLE NONUNIFORM %token COHERENT VOLATILE RESTRICT READONLY WRITEONLY DEVICECOHERENT QUEUEFAMILYCOHERENT WORKGROUPCOHERENT -%token SUBGROUPCOHERENT NONPRIVATE +%token SUBGROUPCOHERENT NONPRIVATE SHADERCALLCOHERENT %token NOPERSPECTIVE EXPLICITINTERPAMD PERVERTEXNV PERPRIMITIVENV PERVIEWNV PERTASKNV %token PRECISE @@ -343,6 +370,19 @@ extern int yylex(YYSTYPE*, TParseContext&); %type attribute attribute_list single_attribute %type demote_statement %type initializer_list +%type spirv_requirements_list spirv_requirements_parameter +%type spirv_extension_list spirv_capability_list +%type spirv_execution_mode_qualifier +%type spirv_execution_mode_parameter_list spirv_execution_mode_parameter spirv_execution_mode_id_parameter_list +%type spirv_storage_class_qualifier +%type spirv_decorate_qualifier +%type spirv_decorate_parameter_list spirv_decorate_parameter +%type spirv_decorate_id_parameter_list +%type spirv_decorate_string_parameter_list +%type spirv_type_specifier +%type spirv_type_parameter_list spirv_type_parameter +%type spirv_instruction_qualifier +%type spirv_instruction_qualifier_list spirv_instruction_qualifier_id %start translation_unit @@ -377,6 +417,9 @@ primary_expression $$ = parseContext.intermediate.addConstantUnion($1.b, $1.loc, true); } + | STRING_LITERAL { + $$ = parseContext.intermediate.addConstantUnion($1.string, $1.loc, true); + } | INT32CONSTANT { parseContext.explicitInt32Check($1.loc, "32-bit signed literal"); $$ = parseContext.intermediate.addConstantUnion($1.i, $1.loc, true); @@ -402,7 +445,9 @@ primary_expression $$ = parseContext.intermediate.addConstantUnion((unsigned short)$1.u, $1.loc, true); } | DOUBLECONSTANT { - parseContext.doubleCheck($1.loc, "double literal"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double literal"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double literal"); $$ = parseContext.intermediate.addConstantUnion($1.d, EbtDouble, $1.loc, true); } | FLOAT16CONSTANT { @@ -768,7 +813,7 @@ assignment_expression parseContext.specializationCheck($2.loc, $1->getType(), "="); parseContext.lValueErrorCheck($2.loc, "assign", $1); parseContext.rValueErrorCheck($2.loc, "assign", $3); - $$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.loc); + $$ = parseContext.addAssign($2.loc, $2.op, $1, $3); if ($$ == 0) { parseContext.assignError($2.loc, "assign", $1->getCompleteString(), $3->getCompleteString()); $$ = $1; @@ -851,6 +896,20 @@ declaration $$ = 0; // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature } + + | spirv_instruction_qualifier function_prototype SEMICOLON { + parseContext.requireExtensions($2.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V instruction qualifier"); + $2.function->setSpirvInstruction(*$1); // Attach SPIR-V intruction qualifier + parseContext.handleFunctionDeclarator($2.loc, *$2.function, true /* prototype */); + $$ = 0; + // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature + } + | spirv_execution_mode_qualifier SEMICOLON { + parseContext.globalCheck($2.loc, "SPIR-V execution mode qualifier"); + parseContext.requireExtensions($2.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V execution mode qualifier"); + $$ = 0; + } + | init_declarator_list SEMICOLON { if ($1.intermNode && $1.intermNode->getAsAggregate()) $1.intermNode->getAsAggregate()->setOperator(EOpSequence); @@ -895,7 +954,7 @@ declaration block_structure : type_qualifier IDENTIFIER LEFT_BRACE { parseContext.nestedBlockCheck($1.loc); } struct_declaration_list RIGHT_BRACE { - --parseContext.structNestingLevel; + --parseContext.blockNestingLevel; parseContext.blockName = $2.string; parseContext.globalQualifierFixCheck($1.loc, $1.qualifier); parseContext.checkNoShaderLayouts($1.loc, $1.shaderQualifiers); @@ -920,6 +979,25 @@ function_prototype $$.function = $1; $$.loc = $2.loc; } + | function_declarator RIGHT_PAREN attribute { + $$.function = $1; + $$.loc = $2.loc; + parseContext.requireExtensions($2.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes($2.loc, *$3, $$.function); + } + | attribute function_declarator RIGHT_PAREN { + $$.function = $2; + $$.loc = $3.loc; + parseContext.requireExtensions($3.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes($3.loc, *$1, $$.function); + } + | attribute function_declarator RIGHT_PAREN attribute { + $$.function = $2; + $$.loc = $3.loc; + parseContext.requireExtensions($3.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes($3.loc, *$1, $$.function); + parseContext.handleFunctionAttributes($3.loc, *$4, $$.function); + } ; function_declarator @@ -1323,6 +1401,25 @@ single_type_qualifier | non_uniform_qualifier { $$ = $1; } + | spirv_storage_class_qualifier { + parseContext.globalCheck($1.loc, "spirv_storage_class"); + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V storage class qualifier"); + $$ = $1; + } + | spirv_decorate_qualifier { + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V decorate qualifier"); + $$ = $1; + } + | SPIRV_BY_REFERENCE { + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "spirv_by_reference"); + $$.init($1.loc); + $$.qualifier.setSpirvByReference(); + } + | SPIRV_LITERAL { + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "spirv_by_literal"); + $$.init($1.loc); + $$.qualifier.setSpirvLiteral(); + } ; @@ -1413,42 +1510,81 @@ storage_qualifier } | HITATTRNV { parseContext.globalCheck($1.loc, "hitAttributeNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangIntersectNVMask | EShLangClosestHitNVMask - | EShLangAnyHitNVMask), "hitAttributeNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask + | EShLangAnyHitMask), "hitAttributeNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "hitAttributeNV"); $$.init($1.loc); - $$.qualifier.storage = EvqHitAttrNV; + $$.qualifier.storage = EvqHitAttr; + } + | HITATTREXT { + parseContext.globalCheck($1.loc, "hitAttributeEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask + | EShLangAnyHitMask), "hitAttributeEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "hitAttributeNV"); + $$.init($1.loc); + $$.qualifier.storage = EvqHitAttr; } | PAYLOADNV { parseContext.globalCheck($1.loc, "rayPayloadNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenNVMask | EShLangClosestHitNVMask | - EShLangAnyHitNVMask | EShLangMissNVMask), "rayPayloadNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "rayPayloadNV"); $$.init($1.loc); - $$.qualifier.storage = EvqPayloadNV; + $$.qualifier.storage = EvqPayload; + } + | PAYLOADEXT { + parseContext.globalCheck($1.loc, "rayPayloadEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "rayPayloadEXT"); + $$.init($1.loc); + $$.qualifier.storage = EvqPayload; } | PAYLOADINNV { parseContext.globalCheck($1.loc, "rayPayloadInNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangClosestHitNVMask | - EShLangAnyHitNVMask | EShLangMissNVMask), "rayPayloadInNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadInNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "rayPayloadInNV"); $$.init($1.loc); - $$.qualifier.storage = EvqPayloadInNV; + $$.qualifier.storage = EvqPayloadIn; + } + | PAYLOADINEXT { + parseContext.globalCheck($1.loc, "rayPayloadInEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadInEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "rayPayloadInEXT"); + $$.init($1.loc); + $$.qualifier.storage = EvqPayloadIn; } | CALLDATANV { parseContext.globalCheck($1.loc, "callableDataNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenNVMask | - EShLangClosestHitNVMask | EShLangMissNVMask | EShLangCallableNVMask), "callableDataNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | + EShLangClosestHitMask | EShLangMissMask | EShLangCallableMask), "callableDataNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "callableDataNV"); $$.init($1.loc); - $$.qualifier.storage = EvqCallableDataNV; + $$.qualifier.storage = EvqCallableData; + } + | CALLDATAEXT { + parseContext.globalCheck($1.loc, "callableDataEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangRayGenMask | + EShLangClosestHitMask | EShLangMissMask | EShLangCallableMask), "callableDataEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "callableDataEXT"); + $$.init($1.loc); + $$.qualifier.storage = EvqCallableData; } | CALLDATAINNV { parseContext.globalCheck($1.loc, "callableDataInNV"); - parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangCallableNVMask), "callableDataInNV"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInNV"); parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "callableDataInNV"); $$.init($1.loc); - $$.qualifier.storage = EvqCallableDataInNV; + $$.qualifier.storage = EvqCallableDataIn; + } + | CALLDATAINEXT { + parseContext.globalCheck($1.loc, "callableDataInEXT"); + parseContext.requireStage($1.loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInEXT"); + parseContext.profileRequires($1.loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "callableDataInEXT"); + $$.init($1.loc); + $$.qualifier.storage = EvqCallableDataIn; } | COHERENT { $$.init($1.loc); @@ -1479,6 +1615,11 @@ storage_qualifier parseContext.requireExtensions($1.loc, 1, &E_GL_KHR_memory_scope_semantics, "nonprivate"); $$.qualifier.nonprivate = true; } + | SHADERCALLCOHERENT { + $$.init($1.loc); + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_ray_tracing, "shadercallcoherent"); + $$.qualifier.shadercallcoherent = true; + } | VOLATILE { $$.init($1.loc); $$.qualifier.volatil = true; @@ -1751,7 +1892,9 @@ type_specifier_nonarray } | DOUBLE { - parseContext.doubleCheck($1.loc, "double"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; } @@ -1811,19 +1954,25 @@ type_specifier_nonarray $$.basicType = EbtUint64; } | DVEC2 { - parseContext.doubleCheck($1.loc, "double vector"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double vector"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setVector(2); } | DVEC3 { - parseContext.doubleCheck($1.loc, "double vector"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double vector"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setVector(3); } | DVEC4 { - parseContext.doubleCheck($1.loc, "double vector"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double vector"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setVector(4); @@ -2027,73 +2176,97 @@ type_specifier_nonarray $$.setVector(4); } | DMAT2 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(2, 2); } | DMAT3 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(3, 3); } | DMAT4 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(4, 4); } | DMAT2X2 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(2, 2); } | DMAT2X3 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(2, 3); } | DMAT2X4 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(2, 4); } | DMAT3X2 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(3, 2); } | DMAT3X3 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(3, 3); } | DMAT3X4 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(3, 4); } | DMAT4X2 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(4, 2); } | DMAT4X3 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(4, 3); } | DMAT4X4 { - parseContext.doubleCheck($1.loc, "double matrix"); + parseContext.requireProfile($1.loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck($1.loc, "double matrix"); $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtDouble; $$.setMatrix(4, 4); @@ -2316,7 +2489,15 @@ type_specifier_nonarray } | ACCSTRUCTNV { $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); - $$.basicType = EbtAccStructNV; + $$.basicType = EbtAccStruct; + } + | ACCSTRUCTEXT { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtAccStruct; + } + | RAYQUERYEXT { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtRayQuery; } | ATOMIC_UINT { parseContext.vulkanRemoved($1.loc, "atomic counter types"); @@ -3109,6 +3290,116 @@ type_specifier_nonarray $$.basicType = EbtSampler; $$.sampler.setImage(EbtUint, Esd2D, true, false, true); } + | I64IMAGE1D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd1D); + } + | U64IMAGE1D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd1D); + } + | I64IMAGE2D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd2D); + } + | U64IMAGE2D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd2D); + } + | I64IMAGE3D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd3D); + } + | U64IMAGE3D { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd3D); + } + | I64IMAGE2DRECT { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, EsdRect); + } + | U64IMAGE2DRECT { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, EsdRect); + } + | I64IMAGECUBE { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, EsdCube); + } + | U64IMAGECUBE { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, EsdCube); + } + | I64IMAGEBUFFER { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, EsdBuffer); + } + | U64IMAGEBUFFER { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, EsdBuffer); + } + | I64IMAGE1DARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd1D, true); + } + | U64IMAGE1DARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd1D, true); + } + | I64IMAGE2DARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd2D, true); + } + | U64IMAGE2DARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd2D, true); + } + | I64IMAGECUBEARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, EsdCube, true); + } + | U64IMAGECUBEARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, EsdCube, true); + } + | I64IMAGE2DMS { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd2D, false, false, true); + } + | U64IMAGE2DMS { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd2D, false, false, true); + } + | I64IMAGE2DMSARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtInt64, Esd2D, true, false, true); + } + | U64IMAGE2DMSARRAY { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.basicType = EbtSampler; + $$.sampler.setImage(EbtUint64, Esd2D, true, false, true); + } | SAMPLEREXTERNALOES { // GL_OES_EGL_image_external $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); $$.basicType = EbtSampler; @@ -3189,6 +3480,10 @@ type_specifier_nonarray $$.basicType = EbtUint; $$.coopmat = true; } + | spirv_type_specifier { + parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V type specifier"); + $$ = $1; + } | struct_specifier { $$ = $1; @@ -3357,6 +3652,12 @@ initializer parseContext.profileRequires($1.loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); $$ = $2; } + | LEFT_BRACE RIGHT_BRACE { + const char* initFeature = "empty { } initializer"; + parseContext.profileRequires($1.loc, EEsProfile, 0, E_GL_EXT_null_initializer, initFeature); + parseContext.profileRequires($1.loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, initFeature); + $$ = parseContext.intermediate.makeAggregate($1.loc); + } ; @@ -3489,6 +3790,7 @@ selection_statement } | attribute selection_statement_nonattributed { + parseContext.requireExtensions($2->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); parseContext.handleSelectionAttributes(*$1, $2); $$ = $2; } @@ -3536,6 +3838,7 @@ switch_statement } | attribute switch_statement_nonattributed { + parseContext.requireExtensions($2->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); parseContext.handleSwitchAttributes(*$1, $2); $$ = $2; } @@ -3600,6 +3903,7 @@ iteration_statement } | attribute iteration_statement_nonattributed { + parseContext.requireExtensions($2->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); parseContext.handleLoopAttributes(*$1, $2); $$ = $2; } @@ -3711,6 +4015,20 @@ jump_statement parseContext.requireStage($1.loc, EShLangFragment, "discard"); $$ = parseContext.intermediate.addBranch(EOpKill, $1.loc); } + | TERMINATE_INVOCATION SEMICOLON { + parseContext.requireStage($1.loc, EShLangFragment, "terminateInvocation"); + $$ = parseContext.intermediate.addBranch(EOpTerminateInvocation, $1.loc); + } + + | TERMINATE_RAY SEMICOLON { + parseContext.requireStage($1.loc, EShLangAnyHit, "terminateRayEXT"); + $$ = parseContext.intermediate.addBranch(EOpTerminateRayKHR, $1.loc); + } + | IGNORE_INTERSECTION SEMICOLON { + parseContext.requireStage($1.loc, EShLangAnyHit, "ignoreIntersectionEXT"); + $$ = parseContext.intermediate.addBranch(EOpIgnoreIntersectionKHR, $1.loc); + } + ; // Grammar Note: No 'goto'. Gotos are not supported. @@ -3748,6 +4066,14 @@ function_definition : function_prototype { $1.function = parseContext.handleFunctionDeclarator($1.loc, *$1.function, false /* not prototype */); $1.intermNode = parseContext.handleFunctionDefinition($1.loc, *$1.function); + + // For ES 100 only, according to ES shading language 100 spec: A function + // body has a scope nested inside the function's definition. + if (parseContext.profile == EEsProfile && parseContext.version == 100) + { + parseContext.symbolTable.push(); + ++parseContext.statementNestingLevel; + } } compound_statement_no_new_scope { // May be best done as post process phase on intermediate code @@ -3763,6 +4089,17 @@ function_definition $$->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize); $$->getAsAggregate()->setDebug(parseContext.contextPragma.debug); $$->getAsAggregate()->setPragmaTable(parseContext.contextPragma.pragmaTable); + + // Set currentFunctionType to empty pointer when goes outside of the function + parseContext.currentFunctionType = nullptr; + + // For ES 100 only, according to ES shading language 100 spec: A function + // body has a scope nested inside the function's definition. + if (parseContext.profile == EEsProfile && parseContext.version == 100) + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + } } ; @@ -3770,7 +4107,6 @@ function_definition attribute : LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET { $$ = $3; - parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_control_flow_attributes, "attribute"); } attribute_list @@ -3790,4 +4126,273 @@ single_attribute } + +spirv_requirements_list + : spirv_requirements_parameter { + $$ = $1; + } + | spirv_requirements_list COMMA spirv_requirements_parameter { + $$ = parseContext.mergeSpirvRequirements($2.loc, $1, $3); + } + +spirv_requirements_parameter + : IDENTIFIER EQUAL LEFT_BRACKET spirv_extension_list RIGHT_BRACKET { + $$ = parseContext.makeSpirvRequirement($2.loc, *$1.string, $4->getAsAggregate(), nullptr); + } + | IDENTIFIER EQUAL LEFT_BRACKET spirv_capability_list RIGHT_BRACKET { + $$ = parseContext.makeSpirvRequirement($2.loc, *$1.string, nullptr, $4->getAsAggregate()); + } + +spirv_extension_list + : STRING_LITERAL { + $$ = parseContext.intermediate.makeAggregate(parseContext.intermediate.addConstantUnion($1.string, $1.loc, true)); + } + | spirv_extension_list COMMA STRING_LITERAL { + $$ = parseContext.intermediate.growAggregate($1, parseContext.intermediate.addConstantUnion($3.string, $3.loc, true)); + } + +spirv_capability_list + : INTCONSTANT { + $$ = parseContext.intermediate.makeAggregate(parseContext.intermediate.addConstantUnion($1.i, $1.loc, true)); + } + | spirv_capability_list COMMA INTCONSTANT { + $$ = parseContext.intermediate.growAggregate($1, parseContext.intermediate.addConstantUnion($3.i, $3.loc, true)); + } + +spirv_execution_mode_qualifier + : SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT RIGHT_PAREN { + parseContext.intermediate.insertSpirvExecutionMode($3.i); + $$ = 0; + } + | SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN { + parseContext.intermediate.insertSpirvRequirement($3); + parseContext.intermediate.insertSpirvExecutionMode($5.i); + $$ = 0; + } + | SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvExecutionMode($3.i, $5->getAsAggregate()); + $$ = 0; + } + | SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvRequirement($3); + parseContext.intermediate.insertSpirvExecutionMode($5.i, $7->getAsAggregate()); + $$ = 0; + } + | SPIRV_EXECUTION_MODE_ID LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvExecutionModeId($3.i, $5->getAsAggregate()); + $$ = 0; + } + | SPIRV_EXECUTION_MODE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvRequirement($3); + parseContext.intermediate.insertSpirvExecutionModeId($5.i, $7->getAsAggregate()); + $$ = 0; + } + +spirv_execution_mode_parameter_list + : spirv_execution_mode_parameter { + $$ = parseContext.intermediate.makeAggregate($1); + } + | spirv_execution_mode_parameter_list COMMA spirv_execution_mode_parameter { + $$ = parseContext.intermediate.growAggregate($1, $3); + } + +spirv_execution_mode_parameter + : FLOATCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.d, EbtFloat, $1.loc, true); + } + | INTCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.i, $1.loc, true); + } + | UINTCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.u, $1.loc, true); + } + | BOOLCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.b, $1.loc, true); + } + | STRING_LITERAL { + $$ = parseContext.intermediate.addConstantUnion($1.string, $1.loc, true); + } + +spirv_execution_mode_id_parameter_list + : constant_expression { + if ($1->getBasicType() != EbtFloat && + $1->getBasicType() != EbtInt && + $1->getBasicType() != EbtUint && + $1->getBasicType() != EbtBool && + $1->getBasicType() != EbtString) + parseContext.error($1->getLoc(), "this type not allowed", $1->getType().getBasicString(), ""); + $$ = parseContext.intermediate.makeAggregate($1); + } + | spirv_execution_mode_id_parameter_list COMMA constant_expression { + if ($3->getBasicType() != EbtFloat && + $3->getBasicType() != EbtInt && + $3->getBasicType() != EbtUint && + $3->getBasicType() != EbtBool && + $3->getBasicType() != EbtString) + parseContext.error($3->getLoc(), "this type not allowed", $3->getType().getBasicString(), ""); + $$ = parseContext.intermediate.growAggregate($1, $3); + } + +spirv_storage_class_qualifier + : SPIRV_STORAGE_CLASS LEFT_PAREN INTCONSTANT RIGHT_PAREN { + $$.init($1.loc); + $$.qualifier.storage = EvqSpirvStorageClass; + $$.qualifier.spirvStorageClass = $3.i; + } + | SPIRV_STORAGE_CLASS LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN { + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.storage = EvqSpirvStorageClass; + $$.qualifier.spirvStorageClass = $5.i; + } + +spirv_decorate_qualifier + : SPIRV_DECORATE LEFT_PAREN INTCONSTANT RIGHT_PAREN{ + $$.init($1.loc); + $$.qualifier.setSpirvDecorate($3.i); + } + | SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN{ + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.setSpirvDecorate($5.i); + } + | SPIRV_DECORATE LEFT_PAREN INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN { + $$.init($1.loc); + $$.qualifier.setSpirvDecorate($3.i, $5->getAsAggregate()); + } + | SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN { + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.setSpirvDecorate($5.i, $7->getAsAggregate()); + } + | SPIRV_DECORATE_ID LEFT_PAREN INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN { + $$.init($1.loc); + $$.qualifier.setSpirvDecorateId($3.i, $5->getAsAggregate()); + } + | SPIRV_DECORATE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN { + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.setSpirvDecorateId($5.i, $7->getAsAggregate()); + } + | SPIRV_DECORATE_STRING LEFT_PAREN INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN { + $$.init($1.loc); + $$.qualifier.setSpirvDecorateString($3.i, $5->getAsAggregate()); + } + | SPIRV_DECORATE_STRING LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN { + $$.init($1.loc); + parseContext.intermediate.insertSpirvRequirement($3); + $$.qualifier.setSpirvDecorateString($5.i, $7->getAsAggregate()); + } + +spirv_decorate_parameter_list + : spirv_decorate_parameter { + $$ = parseContext.intermediate.makeAggregate($1); + } + | spirv_decorate_parameter_list COMMA spirv_decorate_parameter { + $$ = parseContext.intermediate.growAggregate($1, $3); + } + +spirv_decorate_parameter + : FLOATCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.d, EbtFloat, $1.loc, true); + } + | INTCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.i, $1.loc, true); + } + | UINTCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.u, $1.loc, true); + } + | BOOLCONSTANT { + $$ = parseContext.intermediate.addConstantUnion($1.b, $1.loc, true); + } + +spirv_decorate_id_parameter_list + : constant_expression { + if ($1->getBasicType() != EbtFloat && + $1->getBasicType() != EbtInt && + $1->getBasicType() != EbtUint && + $1->getBasicType() != EbtBool) + parseContext.error($1->getLoc(), "this type not allowed", $1->getType().getBasicString(), ""); + $$ = parseContext.intermediate.makeAggregate($1); + } + | spirv_decorate_id_parameter_list COMMA constant_expression { + if ($3->getBasicType() != EbtFloat && + $3->getBasicType() != EbtInt && + $3->getBasicType() != EbtUint && + $3->getBasicType() != EbtBool) + parseContext.error($3->getLoc(), "this type not allowed", $3->getType().getBasicString(), ""); + $$ = parseContext.intermediate.growAggregate($1, $3); + } + +spirv_decorate_string_parameter_list + : STRING_LITERAL { + $$ = parseContext.intermediate.makeAggregate( + parseContext.intermediate.addConstantUnion($1.string, $1.loc, true)); + } + | spirv_decorate_string_parameter_list COMMA STRING_LITERAL { + $$ = parseContext.intermediate.growAggregate($1, parseContext.intermediate.addConstantUnion($3.string, $3.loc, true)); + } + +spirv_type_specifier + : SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.setSpirvType(*$3, $5); + } + | SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.intermediate.insertSpirvRequirement($3); + $$.setSpirvType(*$5, $7); + } + | SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + $$.setSpirvType(*$3); + } + | SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN { + $$.init($1.loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.intermediate.insertSpirvRequirement($3); + $$.setSpirvType(*$5); + } + +spirv_type_parameter_list + : spirv_type_parameter { + $$ = $1; + } + | spirv_type_parameter_list COMMA spirv_type_parameter { + $$ = parseContext.mergeSpirvTypeParameters($1, $3); + } + +spirv_type_parameter + : constant_expression { + $$ = parseContext.makeSpirvTypeParameters($1->getLoc(), $1->getAsConstantUnion()); + } + | type_specifier { + $$ = parseContext.makeSpirvTypeParameters($1); + } + +spirv_instruction_qualifier + : SPIRV_INSTRUCTION LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN { + $$ = $3; + } + | SPIRV_INSTRUCTION LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN { + parseContext.intermediate.insertSpirvRequirement($3); + $$ = $5; + } + +spirv_instruction_qualifier_list + : spirv_instruction_qualifier_id { + $$ = $1; + } + | spirv_instruction_qualifier_list COMMA spirv_instruction_qualifier_id { + $$ = parseContext.mergeSpirvInstruction($2.loc, $1, $3); + } + +spirv_instruction_qualifier_id + : IDENTIFIER EQUAL STRING_LITERAL { + $$ = parseContext.makeSpirvInstruction($2.loc, *$1.string, *$3.string); + } + | IDENTIFIER EQUAL INTCONSTANT { + $$ = parseContext.makeSpirvInstruction($2.loc, *$1.string, $3.i); + } + + %% diff --git a/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang_tab.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang_tab.cpp new file mode 100644 index 00000000000..dba06aefefb --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang_tab.cpp @@ -0,0 +1,12440 @@ +/* A Bison parser, made by GNU Bison 3.7.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output, and Bison version. */ +#define YYBISON 30704 + +/* Bison version string. */ +#define YYBISON_VERSION "3.7.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* First part of user prologue. */ +#line 69 "MachineIndependent/glslang.y" + + +/* Based on: +ANSI C Yacc grammar + +In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a +matching Lex specification) for the April 30, 1985 draft version of the +ANSI C standard. Tom Stockfisch reposted it to net.sources in 1987; that +original, as mentioned in the answer to question 17.25 of the comp.lang.c +FAQ, can be ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z. + +I intend to keep this version as close to the current C Standard grammar as +possible; please let me know if you discover discrepancies. + +Jutta Degener, 1995 +*/ + +#include "SymbolTable.h" +#include "ParseHelper.h" +#include "../Public/ShaderLang.h" +#include "attribute.h" + +using namespace glslang; + + +#line 97 "MachineIndependent/glslang_tab.cpp" + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +#include "glslang_tab.cpp.h" +/* Symbol kind. */ +enum yysymbol_kind_t +{ + YYSYMBOL_YYEMPTY = -2, + YYSYMBOL_YYEOF = 0, /* "end of file" */ + YYSYMBOL_YYerror = 1, /* error */ + YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ + YYSYMBOL_CONST = 3, /* CONST */ + YYSYMBOL_BOOL = 4, /* BOOL */ + YYSYMBOL_INT = 5, /* INT */ + YYSYMBOL_UINT = 6, /* UINT */ + YYSYMBOL_FLOAT = 7, /* FLOAT */ + YYSYMBOL_BVEC2 = 8, /* BVEC2 */ + YYSYMBOL_BVEC3 = 9, /* BVEC3 */ + YYSYMBOL_BVEC4 = 10, /* BVEC4 */ + YYSYMBOL_IVEC2 = 11, /* IVEC2 */ + YYSYMBOL_IVEC3 = 12, /* IVEC3 */ + YYSYMBOL_IVEC4 = 13, /* IVEC4 */ + YYSYMBOL_UVEC2 = 14, /* UVEC2 */ + YYSYMBOL_UVEC3 = 15, /* UVEC3 */ + YYSYMBOL_UVEC4 = 16, /* UVEC4 */ + YYSYMBOL_VEC2 = 17, /* VEC2 */ + YYSYMBOL_VEC3 = 18, /* VEC3 */ + YYSYMBOL_VEC4 = 19, /* VEC4 */ + YYSYMBOL_MAT2 = 20, /* MAT2 */ + YYSYMBOL_MAT3 = 21, /* MAT3 */ + YYSYMBOL_MAT4 = 22, /* MAT4 */ + YYSYMBOL_MAT2X2 = 23, /* MAT2X2 */ + YYSYMBOL_MAT2X3 = 24, /* MAT2X3 */ + YYSYMBOL_MAT2X4 = 25, /* MAT2X4 */ + YYSYMBOL_MAT3X2 = 26, /* MAT3X2 */ + YYSYMBOL_MAT3X3 = 27, /* MAT3X3 */ + YYSYMBOL_MAT3X4 = 28, /* MAT3X4 */ + YYSYMBOL_MAT4X2 = 29, /* MAT4X2 */ + YYSYMBOL_MAT4X3 = 30, /* MAT4X3 */ + YYSYMBOL_MAT4X4 = 31, /* MAT4X4 */ + YYSYMBOL_SAMPLER2D = 32, /* SAMPLER2D */ + YYSYMBOL_SAMPLER3D = 33, /* SAMPLER3D */ + YYSYMBOL_SAMPLERCUBE = 34, /* SAMPLERCUBE */ + YYSYMBOL_SAMPLER2DSHADOW = 35, /* SAMPLER2DSHADOW */ + YYSYMBOL_SAMPLERCUBESHADOW = 36, /* SAMPLERCUBESHADOW */ + YYSYMBOL_SAMPLER2DARRAY = 37, /* SAMPLER2DARRAY */ + YYSYMBOL_SAMPLER2DARRAYSHADOW = 38, /* SAMPLER2DARRAYSHADOW */ + YYSYMBOL_ISAMPLER2D = 39, /* ISAMPLER2D */ + YYSYMBOL_ISAMPLER3D = 40, /* ISAMPLER3D */ + YYSYMBOL_ISAMPLERCUBE = 41, /* ISAMPLERCUBE */ + YYSYMBOL_ISAMPLER2DARRAY = 42, /* ISAMPLER2DARRAY */ + YYSYMBOL_USAMPLER2D = 43, /* USAMPLER2D */ + YYSYMBOL_USAMPLER3D = 44, /* USAMPLER3D */ + YYSYMBOL_USAMPLERCUBE = 45, /* USAMPLERCUBE */ + YYSYMBOL_USAMPLER2DARRAY = 46, /* USAMPLER2DARRAY */ + YYSYMBOL_SAMPLER = 47, /* SAMPLER */ + YYSYMBOL_SAMPLERSHADOW = 48, /* SAMPLERSHADOW */ + YYSYMBOL_TEXTURE2D = 49, /* TEXTURE2D */ + YYSYMBOL_TEXTURE3D = 50, /* TEXTURE3D */ + YYSYMBOL_TEXTURECUBE = 51, /* TEXTURECUBE */ + YYSYMBOL_TEXTURE2DARRAY = 52, /* TEXTURE2DARRAY */ + YYSYMBOL_ITEXTURE2D = 53, /* ITEXTURE2D */ + YYSYMBOL_ITEXTURE3D = 54, /* ITEXTURE3D */ + YYSYMBOL_ITEXTURECUBE = 55, /* ITEXTURECUBE */ + YYSYMBOL_ITEXTURE2DARRAY = 56, /* ITEXTURE2DARRAY */ + YYSYMBOL_UTEXTURE2D = 57, /* UTEXTURE2D */ + YYSYMBOL_UTEXTURE3D = 58, /* UTEXTURE3D */ + YYSYMBOL_UTEXTURECUBE = 59, /* UTEXTURECUBE */ + YYSYMBOL_UTEXTURE2DARRAY = 60, /* UTEXTURE2DARRAY */ + YYSYMBOL_ATTRIBUTE = 61, /* ATTRIBUTE */ + YYSYMBOL_VARYING = 62, /* VARYING */ + YYSYMBOL_FLOAT16_T = 63, /* FLOAT16_T */ + YYSYMBOL_FLOAT32_T = 64, /* FLOAT32_T */ + YYSYMBOL_DOUBLE = 65, /* DOUBLE */ + YYSYMBOL_FLOAT64_T = 66, /* FLOAT64_T */ + YYSYMBOL_INT64_T = 67, /* INT64_T */ + YYSYMBOL_UINT64_T = 68, /* UINT64_T */ + YYSYMBOL_INT32_T = 69, /* INT32_T */ + YYSYMBOL_UINT32_T = 70, /* UINT32_T */ + YYSYMBOL_INT16_T = 71, /* INT16_T */ + YYSYMBOL_UINT16_T = 72, /* UINT16_T */ + YYSYMBOL_INT8_T = 73, /* INT8_T */ + YYSYMBOL_UINT8_T = 74, /* UINT8_T */ + YYSYMBOL_I64VEC2 = 75, /* I64VEC2 */ + YYSYMBOL_I64VEC3 = 76, /* I64VEC3 */ + YYSYMBOL_I64VEC4 = 77, /* I64VEC4 */ + YYSYMBOL_U64VEC2 = 78, /* U64VEC2 */ + YYSYMBOL_U64VEC3 = 79, /* U64VEC3 */ + YYSYMBOL_U64VEC4 = 80, /* U64VEC4 */ + YYSYMBOL_I32VEC2 = 81, /* I32VEC2 */ + YYSYMBOL_I32VEC3 = 82, /* I32VEC3 */ + YYSYMBOL_I32VEC4 = 83, /* I32VEC4 */ + YYSYMBOL_U32VEC2 = 84, /* U32VEC2 */ + YYSYMBOL_U32VEC3 = 85, /* U32VEC3 */ + YYSYMBOL_U32VEC4 = 86, /* U32VEC4 */ + YYSYMBOL_I16VEC2 = 87, /* I16VEC2 */ + YYSYMBOL_I16VEC3 = 88, /* I16VEC3 */ + YYSYMBOL_I16VEC4 = 89, /* I16VEC4 */ + YYSYMBOL_U16VEC2 = 90, /* U16VEC2 */ + YYSYMBOL_U16VEC3 = 91, /* U16VEC3 */ + YYSYMBOL_U16VEC4 = 92, /* U16VEC4 */ + YYSYMBOL_I8VEC2 = 93, /* I8VEC2 */ + YYSYMBOL_I8VEC3 = 94, /* I8VEC3 */ + YYSYMBOL_I8VEC4 = 95, /* I8VEC4 */ + YYSYMBOL_U8VEC2 = 96, /* U8VEC2 */ + YYSYMBOL_U8VEC3 = 97, /* U8VEC3 */ + YYSYMBOL_U8VEC4 = 98, /* U8VEC4 */ + YYSYMBOL_DVEC2 = 99, /* DVEC2 */ + YYSYMBOL_DVEC3 = 100, /* DVEC3 */ + YYSYMBOL_DVEC4 = 101, /* DVEC4 */ + YYSYMBOL_DMAT2 = 102, /* DMAT2 */ + YYSYMBOL_DMAT3 = 103, /* DMAT3 */ + YYSYMBOL_DMAT4 = 104, /* DMAT4 */ + YYSYMBOL_F16VEC2 = 105, /* F16VEC2 */ + YYSYMBOL_F16VEC3 = 106, /* F16VEC3 */ + YYSYMBOL_F16VEC4 = 107, /* F16VEC4 */ + YYSYMBOL_F16MAT2 = 108, /* F16MAT2 */ + YYSYMBOL_F16MAT3 = 109, /* F16MAT3 */ + YYSYMBOL_F16MAT4 = 110, /* F16MAT4 */ + YYSYMBOL_F32VEC2 = 111, /* F32VEC2 */ + YYSYMBOL_F32VEC3 = 112, /* F32VEC3 */ + YYSYMBOL_F32VEC4 = 113, /* F32VEC4 */ + YYSYMBOL_F32MAT2 = 114, /* F32MAT2 */ + YYSYMBOL_F32MAT3 = 115, /* F32MAT3 */ + YYSYMBOL_F32MAT4 = 116, /* F32MAT4 */ + YYSYMBOL_F64VEC2 = 117, /* F64VEC2 */ + YYSYMBOL_F64VEC3 = 118, /* F64VEC3 */ + YYSYMBOL_F64VEC4 = 119, /* F64VEC4 */ + YYSYMBOL_F64MAT2 = 120, /* F64MAT2 */ + YYSYMBOL_F64MAT3 = 121, /* F64MAT3 */ + YYSYMBOL_F64MAT4 = 122, /* F64MAT4 */ + YYSYMBOL_DMAT2X2 = 123, /* DMAT2X2 */ + YYSYMBOL_DMAT2X3 = 124, /* DMAT2X3 */ + YYSYMBOL_DMAT2X4 = 125, /* DMAT2X4 */ + YYSYMBOL_DMAT3X2 = 126, /* DMAT3X2 */ + YYSYMBOL_DMAT3X3 = 127, /* DMAT3X3 */ + YYSYMBOL_DMAT3X4 = 128, /* DMAT3X4 */ + YYSYMBOL_DMAT4X2 = 129, /* DMAT4X2 */ + YYSYMBOL_DMAT4X3 = 130, /* DMAT4X3 */ + YYSYMBOL_DMAT4X4 = 131, /* DMAT4X4 */ + YYSYMBOL_F16MAT2X2 = 132, /* F16MAT2X2 */ + YYSYMBOL_F16MAT2X3 = 133, /* F16MAT2X3 */ + YYSYMBOL_F16MAT2X4 = 134, /* F16MAT2X4 */ + YYSYMBOL_F16MAT3X2 = 135, /* F16MAT3X2 */ + YYSYMBOL_F16MAT3X3 = 136, /* F16MAT3X3 */ + YYSYMBOL_F16MAT3X4 = 137, /* F16MAT3X4 */ + YYSYMBOL_F16MAT4X2 = 138, /* F16MAT4X2 */ + YYSYMBOL_F16MAT4X3 = 139, /* F16MAT4X3 */ + YYSYMBOL_F16MAT4X4 = 140, /* F16MAT4X4 */ + YYSYMBOL_F32MAT2X2 = 141, /* F32MAT2X2 */ + YYSYMBOL_F32MAT2X3 = 142, /* F32MAT2X3 */ + YYSYMBOL_F32MAT2X4 = 143, /* F32MAT2X4 */ + YYSYMBOL_F32MAT3X2 = 144, /* F32MAT3X2 */ + YYSYMBOL_F32MAT3X3 = 145, /* F32MAT3X3 */ + YYSYMBOL_F32MAT3X4 = 146, /* F32MAT3X4 */ + YYSYMBOL_F32MAT4X2 = 147, /* F32MAT4X2 */ + YYSYMBOL_F32MAT4X3 = 148, /* F32MAT4X3 */ + YYSYMBOL_F32MAT4X4 = 149, /* F32MAT4X4 */ + YYSYMBOL_F64MAT2X2 = 150, /* F64MAT2X2 */ + YYSYMBOL_F64MAT2X3 = 151, /* F64MAT2X3 */ + YYSYMBOL_F64MAT2X4 = 152, /* F64MAT2X4 */ + YYSYMBOL_F64MAT3X2 = 153, /* F64MAT3X2 */ + YYSYMBOL_F64MAT3X3 = 154, /* F64MAT3X3 */ + YYSYMBOL_F64MAT3X4 = 155, /* F64MAT3X4 */ + YYSYMBOL_F64MAT4X2 = 156, /* F64MAT4X2 */ + YYSYMBOL_F64MAT4X3 = 157, /* F64MAT4X3 */ + YYSYMBOL_F64MAT4X4 = 158, /* F64MAT4X4 */ + YYSYMBOL_ATOMIC_UINT = 159, /* ATOMIC_UINT */ + YYSYMBOL_ACCSTRUCTNV = 160, /* ACCSTRUCTNV */ + YYSYMBOL_ACCSTRUCTEXT = 161, /* ACCSTRUCTEXT */ + YYSYMBOL_RAYQUERYEXT = 162, /* RAYQUERYEXT */ + YYSYMBOL_FCOOPMATNV = 163, /* FCOOPMATNV */ + YYSYMBOL_ICOOPMATNV = 164, /* ICOOPMATNV */ + YYSYMBOL_UCOOPMATNV = 165, /* UCOOPMATNV */ + YYSYMBOL_SAMPLERCUBEARRAY = 166, /* SAMPLERCUBEARRAY */ + YYSYMBOL_SAMPLERCUBEARRAYSHADOW = 167, /* SAMPLERCUBEARRAYSHADOW */ + YYSYMBOL_ISAMPLERCUBEARRAY = 168, /* ISAMPLERCUBEARRAY */ + YYSYMBOL_USAMPLERCUBEARRAY = 169, /* USAMPLERCUBEARRAY */ + YYSYMBOL_SAMPLER1D = 170, /* SAMPLER1D */ + YYSYMBOL_SAMPLER1DARRAY = 171, /* SAMPLER1DARRAY */ + YYSYMBOL_SAMPLER1DARRAYSHADOW = 172, /* SAMPLER1DARRAYSHADOW */ + YYSYMBOL_ISAMPLER1D = 173, /* ISAMPLER1D */ + YYSYMBOL_SAMPLER1DSHADOW = 174, /* SAMPLER1DSHADOW */ + YYSYMBOL_SAMPLER2DRECT = 175, /* SAMPLER2DRECT */ + YYSYMBOL_SAMPLER2DRECTSHADOW = 176, /* SAMPLER2DRECTSHADOW */ + YYSYMBOL_ISAMPLER2DRECT = 177, /* ISAMPLER2DRECT */ + YYSYMBOL_USAMPLER2DRECT = 178, /* USAMPLER2DRECT */ + YYSYMBOL_SAMPLERBUFFER = 179, /* SAMPLERBUFFER */ + YYSYMBOL_ISAMPLERBUFFER = 180, /* ISAMPLERBUFFER */ + YYSYMBOL_USAMPLERBUFFER = 181, /* USAMPLERBUFFER */ + YYSYMBOL_SAMPLER2DMS = 182, /* SAMPLER2DMS */ + YYSYMBOL_ISAMPLER2DMS = 183, /* ISAMPLER2DMS */ + YYSYMBOL_USAMPLER2DMS = 184, /* USAMPLER2DMS */ + YYSYMBOL_SAMPLER2DMSARRAY = 185, /* SAMPLER2DMSARRAY */ + YYSYMBOL_ISAMPLER2DMSARRAY = 186, /* ISAMPLER2DMSARRAY */ + YYSYMBOL_USAMPLER2DMSARRAY = 187, /* USAMPLER2DMSARRAY */ + YYSYMBOL_SAMPLEREXTERNALOES = 188, /* SAMPLEREXTERNALOES */ + YYSYMBOL_SAMPLEREXTERNAL2DY2YEXT = 189, /* SAMPLEREXTERNAL2DY2YEXT */ + YYSYMBOL_ISAMPLER1DARRAY = 190, /* ISAMPLER1DARRAY */ + YYSYMBOL_USAMPLER1D = 191, /* USAMPLER1D */ + YYSYMBOL_USAMPLER1DARRAY = 192, /* USAMPLER1DARRAY */ + YYSYMBOL_F16SAMPLER1D = 193, /* F16SAMPLER1D */ + YYSYMBOL_F16SAMPLER2D = 194, /* F16SAMPLER2D */ + YYSYMBOL_F16SAMPLER3D = 195, /* F16SAMPLER3D */ + YYSYMBOL_F16SAMPLER2DRECT = 196, /* F16SAMPLER2DRECT */ + YYSYMBOL_F16SAMPLERCUBE = 197, /* F16SAMPLERCUBE */ + YYSYMBOL_F16SAMPLER1DARRAY = 198, /* F16SAMPLER1DARRAY */ + YYSYMBOL_F16SAMPLER2DARRAY = 199, /* F16SAMPLER2DARRAY */ + YYSYMBOL_F16SAMPLERCUBEARRAY = 200, /* F16SAMPLERCUBEARRAY */ + YYSYMBOL_F16SAMPLERBUFFER = 201, /* F16SAMPLERBUFFER */ + YYSYMBOL_F16SAMPLER2DMS = 202, /* F16SAMPLER2DMS */ + YYSYMBOL_F16SAMPLER2DMSARRAY = 203, /* F16SAMPLER2DMSARRAY */ + YYSYMBOL_F16SAMPLER1DSHADOW = 204, /* F16SAMPLER1DSHADOW */ + YYSYMBOL_F16SAMPLER2DSHADOW = 205, /* F16SAMPLER2DSHADOW */ + YYSYMBOL_F16SAMPLER1DARRAYSHADOW = 206, /* F16SAMPLER1DARRAYSHADOW */ + YYSYMBOL_F16SAMPLER2DARRAYSHADOW = 207, /* F16SAMPLER2DARRAYSHADOW */ + YYSYMBOL_F16SAMPLER2DRECTSHADOW = 208, /* F16SAMPLER2DRECTSHADOW */ + YYSYMBOL_F16SAMPLERCUBESHADOW = 209, /* F16SAMPLERCUBESHADOW */ + YYSYMBOL_F16SAMPLERCUBEARRAYSHADOW = 210, /* F16SAMPLERCUBEARRAYSHADOW */ + YYSYMBOL_IMAGE1D = 211, /* IMAGE1D */ + YYSYMBOL_IIMAGE1D = 212, /* IIMAGE1D */ + YYSYMBOL_UIMAGE1D = 213, /* UIMAGE1D */ + YYSYMBOL_IMAGE2D = 214, /* IMAGE2D */ + YYSYMBOL_IIMAGE2D = 215, /* IIMAGE2D */ + YYSYMBOL_UIMAGE2D = 216, /* UIMAGE2D */ + YYSYMBOL_IMAGE3D = 217, /* IMAGE3D */ + YYSYMBOL_IIMAGE3D = 218, /* IIMAGE3D */ + YYSYMBOL_UIMAGE3D = 219, /* UIMAGE3D */ + YYSYMBOL_IMAGE2DRECT = 220, /* IMAGE2DRECT */ + YYSYMBOL_IIMAGE2DRECT = 221, /* IIMAGE2DRECT */ + YYSYMBOL_UIMAGE2DRECT = 222, /* UIMAGE2DRECT */ + YYSYMBOL_IMAGECUBE = 223, /* IMAGECUBE */ + YYSYMBOL_IIMAGECUBE = 224, /* IIMAGECUBE */ + YYSYMBOL_UIMAGECUBE = 225, /* UIMAGECUBE */ + YYSYMBOL_IMAGEBUFFER = 226, /* IMAGEBUFFER */ + YYSYMBOL_IIMAGEBUFFER = 227, /* IIMAGEBUFFER */ + YYSYMBOL_UIMAGEBUFFER = 228, /* UIMAGEBUFFER */ + YYSYMBOL_IMAGE1DARRAY = 229, /* IMAGE1DARRAY */ + YYSYMBOL_IIMAGE1DARRAY = 230, /* IIMAGE1DARRAY */ + YYSYMBOL_UIMAGE1DARRAY = 231, /* UIMAGE1DARRAY */ + YYSYMBOL_IMAGE2DARRAY = 232, /* IMAGE2DARRAY */ + YYSYMBOL_IIMAGE2DARRAY = 233, /* IIMAGE2DARRAY */ + YYSYMBOL_UIMAGE2DARRAY = 234, /* UIMAGE2DARRAY */ + YYSYMBOL_IMAGECUBEARRAY = 235, /* IMAGECUBEARRAY */ + YYSYMBOL_IIMAGECUBEARRAY = 236, /* IIMAGECUBEARRAY */ + YYSYMBOL_UIMAGECUBEARRAY = 237, /* UIMAGECUBEARRAY */ + YYSYMBOL_IMAGE2DMS = 238, /* IMAGE2DMS */ + YYSYMBOL_IIMAGE2DMS = 239, /* IIMAGE2DMS */ + YYSYMBOL_UIMAGE2DMS = 240, /* UIMAGE2DMS */ + YYSYMBOL_IMAGE2DMSARRAY = 241, /* IMAGE2DMSARRAY */ + YYSYMBOL_IIMAGE2DMSARRAY = 242, /* IIMAGE2DMSARRAY */ + YYSYMBOL_UIMAGE2DMSARRAY = 243, /* UIMAGE2DMSARRAY */ + YYSYMBOL_F16IMAGE1D = 244, /* F16IMAGE1D */ + YYSYMBOL_F16IMAGE2D = 245, /* F16IMAGE2D */ + YYSYMBOL_F16IMAGE3D = 246, /* F16IMAGE3D */ + YYSYMBOL_F16IMAGE2DRECT = 247, /* F16IMAGE2DRECT */ + YYSYMBOL_F16IMAGECUBE = 248, /* F16IMAGECUBE */ + YYSYMBOL_F16IMAGE1DARRAY = 249, /* F16IMAGE1DARRAY */ + YYSYMBOL_F16IMAGE2DARRAY = 250, /* F16IMAGE2DARRAY */ + YYSYMBOL_F16IMAGECUBEARRAY = 251, /* F16IMAGECUBEARRAY */ + YYSYMBOL_F16IMAGEBUFFER = 252, /* F16IMAGEBUFFER */ + YYSYMBOL_F16IMAGE2DMS = 253, /* F16IMAGE2DMS */ + YYSYMBOL_F16IMAGE2DMSARRAY = 254, /* F16IMAGE2DMSARRAY */ + YYSYMBOL_I64IMAGE1D = 255, /* I64IMAGE1D */ + YYSYMBOL_U64IMAGE1D = 256, /* U64IMAGE1D */ + YYSYMBOL_I64IMAGE2D = 257, /* I64IMAGE2D */ + YYSYMBOL_U64IMAGE2D = 258, /* U64IMAGE2D */ + YYSYMBOL_I64IMAGE3D = 259, /* I64IMAGE3D */ + YYSYMBOL_U64IMAGE3D = 260, /* U64IMAGE3D */ + YYSYMBOL_I64IMAGE2DRECT = 261, /* I64IMAGE2DRECT */ + YYSYMBOL_U64IMAGE2DRECT = 262, /* U64IMAGE2DRECT */ + YYSYMBOL_I64IMAGECUBE = 263, /* I64IMAGECUBE */ + YYSYMBOL_U64IMAGECUBE = 264, /* U64IMAGECUBE */ + YYSYMBOL_I64IMAGEBUFFER = 265, /* I64IMAGEBUFFER */ + YYSYMBOL_U64IMAGEBUFFER = 266, /* U64IMAGEBUFFER */ + YYSYMBOL_I64IMAGE1DARRAY = 267, /* I64IMAGE1DARRAY */ + YYSYMBOL_U64IMAGE1DARRAY = 268, /* U64IMAGE1DARRAY */ + YYSYMBOL_I64IMAGE2DARRAY = 269, /* I64IMAGE2DARRAY */ + YYSYMBOL_U64IMAGE2DARRAY = 270, /* U64IMAGE2DARRAY */ + YYSYMBOL_I64IMAGECUBEARRAY = 271, /* I64IMAGECUBEARRAY */ + YYSYMBOL_U64IMAGECUBEARRAY = 272, /* U64IMAGECUBEARRAY */ + YYSYMBOL_I64IMAGE2DMS = 273, /* I64IMAGE2DMS */ + YYSYMBOL_U64IMAGE2DMS = 274, /* U64IMAGE2DMS */ + YYSYMBOL_I64IMAGE2DMSARRAY = 275, /* I64IMAGE2DMSARRAY */ + YYSYMBOL_U64IMAGE2DMSARRAY = 276, /* U64IMAGE2DMSARRAY */ + YYSYMBOL_TEXTURECUBEARRAY = 277, /* TEXTURECUBEARRAY */ + YYSYMBOL_ITEXTURECUBEARRAY = 278, /* ITEXTURECUBEARRAY */ + YYSYMBOL_UTEXTURECUBEARRAY = 279, /* UTEXTURECUBEARRAY */ + YYSYMBOL_TEXTURE1D = 280, /* TEXTURE1D */ + YYSYMBOL_ITEXTURE1D = 281, /* ITEXTURE1D */ + YYSYMBOL_UTEXTURE1D = 282, /* UTEXTURE1D */ + YYSYMBOL_TEXTURE1DARRAY = 283, /* TEXTURE1DARRAY */ + YYSYMBOL_ITEXTURE1DARRAY = 284, /* ITEXTURE1DARRAY */ + YYSYMBOL_UTEXTURE1DARRAY = 285, /* UTEXTURE1DARRAY */ + YYSYMBOL_TEXTURE2DRECT = 286, /* TEXTURE2DRECT */ + YYSYMBOL_ITEXTURE2DRECT = 287, /* ITEXTURE2DRECT */ + YYSYMBOL_UTEXTURE2DRECT = 288, /* UTEXTURE2DRECT */ + YYSYMBOL_TEXTUREBUFFER = 289, /* TEXTUREBUFFER */ + YYSYMBOL_ITEXTUREBUFFER = 290, /* ITEXTUREBUFFER */ + YYSYMBOL_UTEXTUREBUFFER = 291, /* UTEXTUREBUFFER */ + YYSYMBOL_TEXTURE2DMS = 292, /* TEXTURE2DMS */ + YYSYMBOL_ITEXTURE2DMS = 293, /* ITEXTURE2DMS */ + YYSYMBOL_UTEXTURE2DMS = 294, /* UTEXTURE2DMS */ + YYSYMBOL_TEXTURE2DMSARRAY = 295, /* TEXTURE2DMSARRAY */ + YYSYMBOL_ITEXTURE2DMSARRAY = 296, /* ITEXTURE2DMSARRAY */ + YYSYMBOL_UTEXTURE2DMSARRAY = 297, /* UTEXTURE2DMSARRAY */ + YYSYMBOL_F16TEXTURE1D = 298, /* F16TEXTURE1D */ + YYSYMBOL_F16TEXTURE2D = 299, /* F16TEXTURE2D */ + YYSYMBOL_F16TEXTURE3D = 300, /* F16TEXTURE3D */ + YYSYMBOL_F16TEXTURE2DRECT = 301, /* F16TEXTURE2DRECT */ + YYSYMBOL_F16TEXTURECUBE = 302, /* F16TEXTURECUBE */ + YYSYMBOL_F16TEXTURE1DARRAY = 303, /* F16TEXTURE1DARRAY */ + YYSYMBOL_F16TEXTURE2DARRAY = 304, /* F16TEXTURE2DARRAY */ + YYSYMBOL_F16TEXTURECUBEARRAY = 305, /* F16TEXTURECUBEARRAY */ + YYSYMBOL_F16TEXTUREBUFFER = 306, /* F16TEXTUREBUFFER */ + YYSYMBOL_F16TEXTURE2DMS = 307, /* F16TEXTURE2DMS */ + YYSYMBOL_F16TEXTURE2DMSARRAY = 308, /* F16TEXTURE2DMSARRAY */ + YYSYMBOL_SUBPASSINPUT = 309, /* SUBPASSINPUT */ + YYSYMBOL_SUBPASSINPUTMS = 310, /* SUBPASSINPUTMS */ + YYSYMBOL_ISUBPASSINPUT = 311, /* ISUBPASSINPUT */ + YYSYMBOL_ISUBPASSINPUTMS = 312, /* ISUBPASSINPUTMS */ + YYSYMBOL_USUBPASSINPUT = 313, /* USUBPASSINPUT */ + YYSYMBOL_USUBPASSINPUTMS = 314, /* USUBPASSINPUTMS */ + YYSYMBOL_F16SUBPASSINPUT = 315, /* F16SUBPASSINPUT */ + YYSYMBOL_F16SUBPASSINPUTMS = 316, /* F16SUBPASSINPUTMS */ + YYSYMBOL_SPIRV_INSTRUCTION = 317, /* SPIRV_INSTRUCTION */ + YYSYMBOL_SPIRV_EXECUTION_MODE = 318, /* SPIRV_EXECUTION_MODE */ + YYSYMBOL_SPIRV_EXECUTION_MODE_ID = 319, /* SPIRV_EXECUTION_MODE_ID */ + YYSYMBOL_SPIRV_DECORATE = 320, /* SPIRV_DECORATE */ + YYSYMBOL_SPIRV_DECORATE_ID = 321, /* SPIRV_DECORATE_ID */ + YYSYMBOL_SPIRV_DECORATE_STRING = 322, /* SPIRV_DECORATE_STRING */ + YYSYMBOL_SPIRV_TYPE = 323, /* SPIRV_TYPE */ + YYSYMBOL_SPIRV_STORAGE_CLASS = 324, /* SPIRV_STORAGE_CLASS */ + YYSYMBOL_SPIRV_BY_REFERENCE = 325, /* SPIRV_BY_REFERENCE */ + YYSYMBOL_SPIRV_LITERAL = 326, /* SPIRV_LITERAL */ + YYSYMBOL_LEFT_OP = 327, /* LEFT_OP */ + YYSYMBOL_RIGHT_OP = 328, /* RIGHT_OP */ + YYSYMBOL_INC_OP = 329, /* INC_OP */ + YYSYMBOL_DEC_OP = 330, /* DEC_OP */ + YYSYMBOL_LE_OP = 331, /* LE_OP */ + YYSYMBOL_GE_OP = 332, /* GE_OP */ + YYSYMBOL_EQ_OP = 333, /* EQ_OP */ + YYSYMBOL_NE_OP = 334, /* NE_OP */ + YYSYMBOL_AND_OP = 335, /* AND_OP */ + YYSYMBOL_OR_OP = 336, /* OR_OP */ + YYSYMBOL_XOR_OP = 337, /* XOR_OP */ + YYSYMBOL_MUL_ASSIGN = 338, /* MUL_ASSIGN */ + YYSYMBOL_DIV_ASSIGN = 339, /* DIV_ASSIGN */ + YYSYMBOL_ADD_ASSIGN = 340, /* ADD_ASSIGN */ + YYSYMBOL_MOD_ASSIGN = 341, /* MOD_ASSIGN */ + YYSYMBOL_LEFT_ASSIGN = 342, /* LEFT_ASSIGN */ + YYSYMBOL_RIGHT_ASSIGN = 343, /* RIGHT_ASSIGN */ + YYSYMBOL_AND_ASSIGN = 344, /* AND_ASSIGN */ + YYSYMBOL_XOR_ASSIGN = 345, /* XOR_ASSIGN */ + YYSYMBOL_OR_ASSIGN = 346, /* OR_ASSIGN */ + YYSYMBOL_SUB_ASSIGN = 347, /* SUB_ASSIGN */ + YYSYMBOL_STRING_LITERAL = 348, /* STRING_LITERAL */ + YYSYMBOL_LEFT_PAREN = 349, /* LEFT_PAREN */ + YYSYMBOL_RIGHT_PAREN = 350, /* RIGHT_PAREN */ + YYSYMBOL_LEFT_BRACKET = 351, /* LEFT_BRACKET */ + YYSYMBOL_RIGHT_BRACKET = 352, /* RIGHT_BRACKET */ + YYSYMBOL_LEFT_BRACE = 353, /* LEFT_BRACE */ + YYSYMBOL_RIGHT_BRACE = 354, /* RIGHT_BRACE */ + YYSYMBOL_DOT = 355, /* DOT */ + YYSYMBOL_COMMA = 356, /* COMMA */ + YYSYMBOL_COLON = 357, /* COLON */ + YYSYMBOL_EQUAL = 358, /* EQUAL */ + YYSYMBOL_SEMICOLON = 359, /* SEMICOLON */ + YYSYMBOL_BANG = 360, /* BANG */ + YYSYMBOL_DASH = 361, /* DASH */ + YYSYMBOL_TILDE = 362, /* TILDE */ + YYSYMBOL_PLUS = 363, /* PLUS */ + YYSYMBOL_STAR = 364, /* STAR */ + YYSYMBOL_SLASH = 365, /* SLASH */ + YYSYMBOL_PERCENT = 366, /* PERCENT */ + YYSYMBOL_LEFT_ANGLE = 367, /* LEFT_ANGLE */ + YYSYMBOL_RIGHT_ANGLE = 368, /* RIGHT_ANGLE */ + YYSYMBOL_VERTICAL_BAR = 369, /* VERTICAL_BAR */ + YYSYMBOL_CARET = 370, /* CARET */ + YYSYMBOL_AMPERSAND = 371, /* AMPERSAND */ + YYSYMBOL_QUESTION = 372, /* QUESTION */ + YYSYMBOL_INVARIANT = 373, /* INVARIANT */ + YYSYMBOL_HIGH_PRECISION = 374, /* HIGH_PRECISION */ + YYSYMBOL_MEDIUM_PRECISION = 375, /* MEDIUM_PRECISION */ + YYSYMBOL_LOW_PRECISION = 376, /* LOW_PRECISION */ + YYSYMBOL_PRECISION = 377, /* PRECISION */ + YYSYMBOL_PACKED = 378, /* PACKED */ + YYSYMBOL_RESOURCE = 379, /* RESOURCE */ + YYSYMBOL_SUPERP = 380, /* SUPERP */ + YYSYMBOL_FLOATCONSTANT = 381, /* FLOATCONSTANT */ + YYSYMBOL_INTCONSTANT = 382, /* INTCONSTANT */ + YYSYMBOL_UINTCONSTANT = 383, /* UINTCONSTANT */ + YYSYMBOL_BOOLCONSTANT = 384, /* BOOLCONSTANT */ + YYSYMBOL_IDENTIFIER = 385, /* IDENTIFIER */ + YYSYMBOL_TYPE_NAME = 386, /* TYPE_NAME */ + YYSYMBOL_CENTROID = 387, /* CENTROID */ + YYSYMBOL_IN = 388, /* IN */ + YYSYMBOL_OUT = 389, /* OUT */ + YYSYMBOL_INOUT = 390, /* INOUT */ + YYSYMBOL_STRUCT = 391, /* STRUCT */ + YYSYMBOL_VOID = 392, /* VOID */ + YYSYMBOL_WHILE = 393, /* WHILE */ + YYSYMBOL_BREAK = 394, /* BREAK */ + YYSYMBOL_CONTINUE = 395, /* CONTINUE */ + YYSYMBOL_DO = 396, /* DO */ + YYSYMBOL_ELSE = 397, /* ELSE */ + YYSYMBOL_FOR = 398, /* FOR */ + YYSYMBOL_IF = 399, /* IF */ + YYSYMBOL_DISCARD = 400, /* DISCARD */ + YYSYMBOL_RETURN = 401, /* RETURN */ + YYSYMBOL_SWITCH = 402, /* SWITCH */ + YYSYMBOL_CASE = 403, /* CASE */ + YYSYMBOL_DEFAULT = 404, /* DEFAULT */ + YYSYMBOL_TERMINATE_INVOCATION = 405, /* TERMINATE_INVOCATION */ + YYSYMBOL_TERMINATE_RAY = 406, /* TERMINATE_RAY */ + YYSYMBOL_IGNORE_INTERSECTION = 407, /* IGNORE_INTERSECTION */ + YYSYMBOL_UNIFORM = 408, /* UNIFORM */ + YYSYMBOL_SHARED = 409, /* SHARED */ + YYSYMBOL_BUFFER = 410, /* BUFFER */ + YYSYMBOL_FLAT = 411, /* FLAT */ + YYSYMBOL_SMOOTH = 412, /* SMOOTH */ + YYSYMBOL_LAYOUT = 413, /* LAYOUT */ + YYSYMBOL_DOUBLECONSTANT = 414, /* DOUBLECONSTANT */ + YYSYMBOL_INT16CONSTANT = 415, /* INT16CONSTANT */ + YYSYMBOL_UINT16CONSTANT = 416, /* UINT16CONSTANT */ + YYSYMBOL_FLOAT16CONSTANT = 417, /* FLOAT16CONSTANT */ + YYSYMBOL_INT32CONSTANT = 418, /* INT32CONSTANT */ + YYSYMBOL_UINT32CONSTANT = 419, /* UINT32CONSTANT */ + YYSYMBOL_INT64CONSTANT = 420, /* INT64CONSTANT */ + YYSYMBOL_UINT64CONSTANT = 421, /* UINT64CONSTANT */ + YYSYMBOL_SUBROUTINE = 422, /* SUBROUTINE */ + YYSYMBOL_DEMOTE = 423, /* DEMOTE */ + YYSYMBOL_PAYLOADNV = 424, /* PAYLOADNV */ + YYSYMBOL_PAYLOADINNV = 425, /* PAYLOADINNV */ + YYSYMBOL_HITATTRNV = 426, /* HITATTRNV */ + YYSYMBOL_CALLDATANV = 427, /* CALLDATANV */ + YYSYMBOL_CALLDATAINNV = 428, /* CALLDATAINNV */ + YYSYMBOL_PAYLOADEXT = 429, /* PAYLOADEXT */ + YYSYMBOL_PAYLOADINEXT = 430, /* PAYLOADINEXT */ + YYSYMBOL_HITATTREXT = 431, /* HITATTREXT */ + YYSYMBOL_CALLDATAEXT = 432, /* CALLDATAEXT */ + YYSYMBOL_CALLDATAINEXT = 433, /* CALLDATAINEXT */ + YYSYMBOL_PATCH = 434, /* PATCH */ + YYSYMBOL_SAMPLE = 435, /* SAMPLE */ + YYSYMBOL_NONUNIFORM = 436, /* NONUNIFORM */ + YYSYMBOL_COHERENT = 437, /* COHERENT */ + YYSYMBOL_VOLATILE = 438, /* VOLATILE */ + YYSYMBOL_RESTRICT = 439, /* RESTRICT */ + YYSYMBOL_READONLY = 440, /* READONLY */ + YYSYMBOL_WRITEONLY = 441, /* WRITEONLY */ + YYSYMBOL_DEVICECOHERENT = 442, /* DEVICECOHERENT */ + YYSYMBOL_QUEUEFAMILYCOHERENT = 443, /* QUEUEFAMILYCOHERENT */ + YYSYMBOL_WORKGROUPCOHERENT = 444, /* WORKGROUPCOHERENT */ + YYSYMBOL_SUBGROUPCOHERENT = 445, /* SUBGROUPCOHERENT */ + YYSYMBOL_NONPRIVATE = 446, /* NONPRIVATE */ + YYSYMBOL_SHADERCALLCOHERENT = 447, /* SHADERCALLCOHERENT */ + YYSYMBOL_NOPERSPECTIVE = 448, /* NOPERSPECTIVE */ + YYSYMBOL_EXPLICITINTERPAMD = 449, /* EXPLICITINTERPAMD */ + YYSYMBOL_PERVERTEXNV = 450, /* PERVERTEXNV */ + YYSYMBOL_PERPRIMITIVENV = 451, /* PERPRIMITIVENV */ + YYSYMBOL_PERVIEWNV = 452, /* PERVIEWNV */ + YYSYMBOL_PERTASKNV = 453, /* PERTASKNV */ + YYSYMBOL_PRECISE = 454, /* PRECISE */ + YYSYMBOL_YYACCEPT = 455, /* $accept */ + YYSYMBOL_variable_identifier = 456, /* variable_identifier */ + YYSYMBOL_primary_expression = 457, /* primary_expression */ + YYSYMBOL_postfix_expression = 458, /* postfix_expression */ + YYSYMBOL_integer_expression = 459, /* integer_expression */ + YYSYMBOL_function_call = 460, /* function_call */ + YYSYMBOL_function_call_or_method = 461, /* function_call_or_method */ + YYSYMBOL_function_call_generic = 462, /* function_call_generic */ + YYSYMBOL_function_call_header_no_parameters = 463, /* function_call_header_no_parameters */ + YYSYMBOL_function_call_header_with_parameters = 464, /* function_call_header_with_parameters */ + YYSYMBOL_function_call_header = 465, /* function_call_header */ + YYSYMBOL_function_identifier = 466, /* function_identifier */ + YYSYMBOL_unary_expression = 467, /* unary_expression */ + YYSYMBOL_unary_operator = 468, /* unary_operator */ + YYSYMBOL_multiplicative_expression = 469, /* multiplicative_expression */ + YYSYMBOL_additive_expression = 470, /* additive_expression */ + YYSYMBOL_shift_expression = 471, /* shift_expression */ + YYSYMBOL_relational_expression = 472, /* relational_expression */ + YYSYMBOL_equality_expression = 473, /* equality_expression */ + YYSYMBOL_and_expression = 474, /* and_expression */ + YYSYMBOL_exclusive_or_expression = 475, /* exclusive_or_expression */ + YYSYMBOL_inclusive_or_expression = 476, /* inclusive_or_expression */ + YYSYMBOL_logical_and_expression = 477, /* logical_and_expression */ + YYSYMBOL_logical_xor_expression = 478, /* logical_xor_expression */ + YYSYMBOL_logical_or_expression = 479, /* logical_or_expression */ + YYSYMBOL_conditional_expression = 480, /* conditional_expression */ + YYSYMBOL_481_1 = 481, /* $@1 */ + YYSYMBOL_assignment_expression = 482, /* assignment_expression */ + YYSYMBOL_assignment_operator = 483, /* assignment_operator */ + YYSYMBOL_expression = 484, /* expression */ + YYSYMBOL_constant_expression = 485, /* constant_expression */ + YYSYMBOL_declaration = 486, /* declaration */ + YYSYMBOL_block_structure = 487, /* block_structure */ + YYSYMBOL_488_2 = 488, /* $@2 */ + YYSYMBOL_identifier_list = 489, /* identifier_list */ + YYSYMBOL_function_prototype = 490, /* function_prototype */ + YYSYMBOL_function_declarator = 491, /* function_declarator */ + YYSYMBOL_function_header_with_parameters = 492, /* function_header_with_parameters */ + YYSYMBOL_function_header = 493, /* function_header */ + YYSYMBOL_parameter_declarator = 494, /* parameter_declarator */ + YYSYMBOL_parameter_declaration = 495, /* parameter_declaration */ + YYSYMBOL_parameter_type_specifier = 496, /* parameter_type_specifier */ + YYSYMBOL_init_declarator_list = 497, /* init_declarator_list */ + YYSYMBOL_single_declaration = 498, /* single_declaration */ + YYSYMBOL_fully_specified_type = 499, /* fully_specified_type */ + YYSYMBOL_invariant_qualifier = 500, /* invariant_qualifier */ + YYSYMBOL_interpolation_qualifier = 501, /* interpolation_qualifier */ + YYSYMBOL_layout_qualifier = 502, /* layout_qualifier */ + YYSYMBOL_layout_qualifier_id_list = 503, /* layout_qualifier_id_list */ + YYSYMBOL_layout_qualifier_id = 504, /* layout_qualifier_id */ + YYSYMBOL_precise_qualifier = 505, /* precise_qualifier */ + YYSYMBOL_type_qualifier = 506, /* type_qualifier */ + YYSYMBOL_single_type_qualifier = 507, /* single_type_qualifier */ + YYSYMBOL_storage_qualifier = 508, /* storage_qualifier */ + YYSYMBOL_non_uniform_qualifier = 509, /* non_uniform_qualifier */ + YYSYMBOL_type_name_list = 510, /* type_name_list */ + YYSYMBOL_type_specifier = 511, /* type_specifier */ + YYSYMBOL_array_specifier = 512, /* array_specifier */ + YYSYMBOL_type_parameter_specifier_opt = 513, /* type_parameter_specifier_opt */ + YYSYMBOL_type_parameter_specifier = 514, /* type_parameter_specifier */ + YYSYMBOL_type_parameter_specifier_list = 515, /* type_parameter_specifier_list */ + YYSYMBOL_type_specifier_nonarray = 516, /* type_specifier_nonarray */ + YYSYMBOL_precision_qualifier = 517, /* precision_qualifier */ + YYSYMBOL_struct_specifier = 518, /* struct_specifier */ + YYSYMBOL_519_3 = 519, /* $@3 */ + YYSYMBOL_520_4 = 520, /* $@4 */ + YYSYMBOL_struct_declaration_list = 521, /* struct_declaration_list */ + YYSYMBOL_struct_declaration = 522, /* struct_declaration */ + YYSYMBOL_struct_declarator_list = 523, /* struct_declarator_list */ + YYSYMBOL_struct_declarator = 524, /* struct_declarator */ + YYSYMBOL_initializer = 525, /* initializer */ + YYSYMBOL_initializer_list = 526, /* initializer_list */ + YYSYMBOL_declaration_statement = 527, /* declaration_statement */ + YYSYMBOL_statement = 528, /* statement */ + YYSYMBOL_simple_statement = 529, /* simple_statement */ + YYSYMBOL_demote_statement = 530, /* demote_statement */ + YYSYMBOL_compound_statement = 531, /* compound_statement */ + YYSYMBOL_532_5 = 532, /* $@5 */ + YYSYMBOL_533_6 = 533, /* $@6 */ + YYSYMBOL_statement_no_new_scope = 534, /* statement_no_new_scope */ + YYSYMBOL_statement_scoped = 535, /* statement_scoped */ + YYSYMBOL_536_7 = 536, /* $@7 */ + YYSYMBOL_537_8 = 537, /* $@8 */ + YYSYMBOL_compound_statement_no_new_scope = 538, /* compound_statement_no_new_scope */ + YYSYMBOL_statement_list = 539, /* statement_list */ + YYSYMBOL_expression_statement = 540, /* expression_statement */ + YYSYMBOL_selection_statement = 541, /* selection_statement */ + YYSYMBOL_selection_statement_nonattributed = 542, /* selection_statement_nonattributed */ + YYSYMBOL_selection_rest_statement = 543, /* selection_rest_statement */ + YYSYMBOL_condition = 544, /* condition */ + YYSYMBOL_switch_statement = 545, /* switch_statement */ + YYSYMBOL_switch_statement_nonattributed = 546, /* switch_statement_nonattributed */ + YYSYMBOL_547_9 = 547, /* $@9 */ + YYSYMBOL_switch_statement_list = 548, /* switch_statement_list */ + YYSYMBOL_case_label = 549, /* case_label */ + YYSYMBOL_iteration_statement = 550, /* iteration_statement */ + YYSYMBOL_iteration_statement_nonattributed = 551, /* iteration_statement_nonattributed */ + YYSYMBOL_552_10 = 552, /* $@10 */ + YYSYMBOL_553_11 = 553, /* $@11 */ + YYSYMBOL_554_12 = 554, /* $@12 */ + YYSYMBOL_for_init_statement = 555, /* for_init_statement */ + YYSYMBOL_conditionopt = 556, /* conditionopt */ + YYSYMBOL_for_rest_statement = 557, /* for_rest_statement */ + YYSYMBOL_jump_statement = 558, /* jump_statement */ + YYSYMBOL_translation_unit = 559, /* translation_unit */ + YYSYMBOL_external_declaration = 560, /* external_declaration */ + YYSYMBOL_function_definition = 561, /* function_definition */ + YYSYMBOL_562_13 = 562, /* $@13 */ + YYSYMBOL_attribute = 563, /* attribute */ + YYSYMBOL_attribute_list = 564, /* attribute_list */ + YYSYMBOL_single_attribute = 565, /* single_attribute */ + YYSYMBOL_spirv_requirements_list = 566, /* spirv_requirements_list */ + YYSYMBOL_spirv_requirements_parameter = 567, /* spirv_requirements_parameter */ + YYSYMBOL_spirv_extension_list = 568, /* spirv_extension_list */ + YYSYMBOL_spirv_capability_list = 569, /* spirv_capability_list */ + YYSYMBOL_spirv_execution_mode_qualifier = 570, /* spirv_execution_mode_qualifier */ + YYSYMBOL_spirv_execution_mode_parameter_list = 571, /* spirv_execution_mode_parameter_list */ + YYSYMBOL_spirv_execution_mode_parameter = 572, /* spirv_execution_mode_parameter */ + YYSYMBOL_spirv_execution_mode_id_parameter_list = 573, /* spirv_execution_mode_id_parameter_list */ + YYSYMBOL_spirv_storage_class_qualifier = 574, /* spirv_storage_class_qualifier */ + YYSYMBOL_spirv_decorate_qualifier = 575, /* spirv_decorate_qualifier */ + YYSYMBOL_spirv_decorate_parameter_list = 576, /* spirv_decorate_parameter_list */ + YYSYMBOL_spirv_decorate_parameter = 577, /* spirv_decorate_parameter */ + YYSYMBOL_spirv_decorate_id_parameter_list = 578, /* spirv_decorate_id_parameter_list */ + YYSYMBOL_spirv_decorate_string_parameter_list = 579, /* spirv_decorate_string_parameter_list */ + YYSYMBOL_spirv_type_specifier = 580, /* spirv_type_specifier */ + YYSYMBOL_spirv_type_parameter_list = 581, /* spirv_type_parameter_list */ + YYSYMBOL_spirv_type_parameter = 582, /* spirv_type_parameter */ + YYSYMBOL_spirv_instruction_qualifier = 583, /* spirv_instruction_qualifier */ + YYSYMBOL_spirv_instruction_qualifier_list = 584, /* spirv_instruction_qualifier_list */ + YYSYMBOL_spirv_instruction_qualifier_id = 585 /* spirv_instruction_qualifier_id */ +}; +typedef enum yysymbol_kind_t yysymbol_kind_t; + + +/* Second part of user prologue. */ +#line 136 "MachineIndependent/glslang.y" + + +/* windows only pragma */ +#ifdef _MSC_VER + #pragma warning(disable : 4065) + #pragma warning(disable : 4127) + #pragma warning(disable : 4244) +#endif + +#define parseContext (*pParseContext) +#define yyerror(context, msg) context->parserError(msg) + +extern int yylex(YYSTYPE*, TParseContext&); + + +#line 732 "MachineIndependent/glslang_tab.cpp" + + +#ifdef short +# undef short +#endif + +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + and (if available) are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif +#endif + +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; +#else +typedef short yytype_int16; +#endif + +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; +#else +typedef short yytype_uint8; +#endif + +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; +#else +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned +# endif +#endif + +#define YYSIZE_MAXIMUM \ + YY_CAST (YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ + ? YYPTRDIFF_MAXIMUM \ + : YY_CAST (YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) + + +/* Stored state numbers (used for stacks). */ +typedef yytype_int16 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + + +#define YY_ASSERT(E) ((void) (0 && (E))) + +#if 1 + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* 1 */ + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yy_state_t yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYPTRDIFF_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYPTRDIFF_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 442 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 12453 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 455 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 131 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 684 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 930 + +/* YYMAXUTOK -- Last valid token kind. */ +#define YYMAXUTOK 709 + + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ +#define YYTRANSLATE(YYX) \ + (0 <= (YYX) && (YYX) <= YYMAXUTOK \ + ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ + : YYSYMBOL_YYUNDEF) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex. */ +static const yytype_int16 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_int16 yyrline[] = +{ + 0, 392, 392, 398, 401, 406, 409, 412, 416, 420, + 423, 427, 431, 435, 439, 443, 447, 453, 461, 464, + 467, 470, 473, 478, 486, 493, 500, 506, 510, 517, + 520, 526, 533, 543, 551, 556, 584, 593, 599, 603, + 607, 627, 628, 629, 630, 636, 637, 642, 647, 656, + 657, 662, 670, 671, 677, 686, 687, 692, 697, 702, + 710, 711, 720, 732, 733, 742, 743, 752, 753, 762, + 763, 771, 772, 780, 781, 789, 790, 790, 808, 809, + 825, 829, 833, 837, 842, 846, 850, 854, 858, 862, + 866, 873, 876, 887, 894, 900, 907, 913, 918, 925, + 929, 933, 937, 942, 947, 956, 956, 967, 971, 978, + 982, 988, 994, 1004, 1007, 1014, 1022, 1042, 1065, 1080, + 1105, 1116, 1126, 1136, 1146, 1155, 1158, 1162, 1166, 1171, + 1179, 1186, 1191, 1196, 1201, 1210, 1220, 1247, 1256, 1263, + 1271, 1278, 1285, 1293, 1303, 1310, 1321, 1327, 1330, 1337, + 1341, 1345, 1354, 1364, 1367, 1378, 1381, 1384, 1388, 1392, + 1397, 1401, 1404, 1409, 1413, 1418, 1427, 1431, 1436, 1442, + 1448, 1455, 1460, 1468, 1474, 1486, 1500, 1506, 1511, 1519, + 1527, 1535, 1543, 1551, 1559, 1567, 1575, 1582, 1589, 1593, + 1598, 1603, 1608, 1613, 1618, 1623, 1627, 1631, 1635, 1639, + 1645, 1656, 1663, 1666, 1675, 1680, 1690, 1695, 1703, 1707, + 1717, 1720, 1726, 1732, 1739, 1749, 1753, 1757, 1761, 1766, + 1770, 1775, 1780, 1785, 1790, 1795, 1800, 1805, 1810, 1815, + 1821, 1827, 1833, 1838, 1843, 1848, 1853, 1858, 1863, 1868, + 1873, 1878, 1883, 1888, 1894, 1901, 1906, 1911, 1916, 1921, + 1926, 1931, 1936, 1941, 1946, 1951, 1956, 1964, 1972, 1980, + 1986, 1992, 1998, 2004, 2010, 2016, 2022, 2028, 2034, 2040, + 2046, 2052, 2058, 2064, 2070, 2076, 2082, 2088, 2094, 2100, + 2106, 2112, 2118, 2124, 2130, 2136, 2142, 2148, 2154, 2160, + 2166, 2172, 2178, 2186, 2194, 2202, 2210, 2218, 2226, 2234, + 2242, 2250, 2258, 2266, 2274, 2280, 2286, 2292, 2298, 2304, + 2310, 2316, 2322, 2328, 2334, 2340, 2346, 2352, 2358, 2364, + 2370, 2376, 2382, 2388, 2394, 2400, 2406, 2412, 2418, 2424, + 2430, 2436, 2442, 2448, 2454, 2460, 2466, 2472, 2478, 2484, + 2490, 2494, 2498, 2502, 2507, 2513, 2518, 2523, 2528, 2533, + 2538, 2543, 2549, 2554, 2559, 2564, 2569, 2574, 2580, 2586, + 2592, 2598, 2604, 2610, 2616, 2622, 2628, 2634, 2640, 2646, + 2652, 2658, 2663, 2668, 2673, 2678, 2683, 2688, 2694, 2699, + 2704, 2709, 2714, 2719, 2724, 2729, 2735, 2740, 2745, 2750, + 2755, 2760, 2765, 2770, 2775, 2780, 2785, 2790, 2795, 2800, + 2805, 2811, 2816, 2821, 2827, 2833, 2838, 2843, 2848, 2854, + 2859, 2864, 2869, 2875, 2880, 2885, 2890, 2896, 2901, 2906, + 2911, 2917, 2923, 2929, 2935, 2940, 2946, 2952, 2958, 2963, + 2968, 2973, 2978, 2983, 2989, 2994, 2999, 3004, 3010, 3015, + 3020, 3025, 3031, 3036, 3041, 3046, 3052, 3057, 3062, 3067, + 3073, 3078, 3083, 3088, 3094, 3099, 3104, 3109, 3115, 3120, + 3125, 3130, 3136, 3141, 3146, 3151, 3157, 3162, 3167, 3172, + 3178, 3183, 3188, 3193, 3199, 3204, 3209, 3214, 3220, 3225, + 3230, 3235, 3241, 3246, 3251, 3256, 3262, 3267, 3272, 3277, + 3283, 3288, 3293, 3298, 3303, 3308, 3313, 3318, 3323, 3328, + 3333, 3338, 3343, 3348, 3353, 3358, 3363, 3368, 3373, 3378, + 3383, 3388, 3393, 3398, 3403, 3409, 3415, 3421, 3427, 3434, + 3441, 3447, 3453, 3459, 3465, 3471, 3477, 3483, 3488, 3493, + 3509, 3514, 3519, 3527, 3527, 3538, 3538, 3548, 3551, 3564, + 3586, 3613, 3617, 3623, 3628, 3639, 3643, 3649, 3655, 3666, + 3669, 3676, 3680, 3681, 3687, 3688, 3689, 3690, 3691, 3692, + 3693, 3695, 3701, 3710, 3711, 3715, 3711, 3727, 3728, 3732, + 3732, 3739, 3739, 3753, 3756, 3764, 3772, 3783, 3784, 3788, + 3792, 3800, 3807, 3811, 3819, 3823, 3836, 3840, 3848, 3848, + 3868, 3871, 3877, 3889, 3901, 3905, 3913, 3913, 3928, 3928, + 3944, 3944, 3965, 3968, 3974, 3977, 3983, 3987, 3994, 3999, + 4004, 4011, 4014, 4018, 4023, 4027, 4037, 4041, 4050, 4053, + 4057, 4066, 4066, 4108, 4113, 4116, 4121, 4124, 4131, 4134, + 4139, 4142, 4147, 4150, 4155, 4158, 4163, 4167, 4172, 4176, + 4181, 4185, 4192, 4195, 4200, 4203, 4206, 4209, 4212, 4217, + 4226, 4237, 4242, 4250, 4254, 4259, 4263, 4268, 4272, 4277, + 4281, 4288, 4291, 4296, 4299, 4302, 4305, 4310, 4318, 4328, + 4332, 4337, 4341, 4346, 4350, 4357, 4360, 4365, 4368, 4373, + 4376, 4382, 4385, 4390, 4393 +}; +#endif + +/** Accessing symbol of state STATE. */ +#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) + +#if 1 +/* The user-facing name of the symbol whose (internal) number is + YYSYMBOL. No bounds checking. */ +static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; + +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of file\"", "error", "\"invalid token\"", "CONST", "BOOL", "INT", + "UINT", "FLOAT", "BVEC2", "BVEC3", "BVEC4", "IVEC2", "IVEC3", "IVEC4", + "UVEC2", "UVEC3", "UVEC4", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", + "MAT4", "MAT2X2", "MAT2X3", "MAT2X4", "MAT3X2", "MAT3X3", "MAT3X4", + "MAT4X2", "MAT4X3", "MAT4X4", "SAMPLER2D", "SAMPLER3D", "SAMPLERCUBE", + "SAMPLER2DSHADOW", "SAMPLERCUBESHADOW", "SAMPLER2DARRAY", + "SAMPLER2DARRAYSHADOW", "ISAMPLER2D", "ISAMPLER3D", "ISAMPLERCUBE", + "ISAMPLER2DARRAY", "USAMPLER2D", "USAMPLER3D", "USAMPLERCUBE", + "USAMPLER2DARRAY", "SAMPLER", "SAMPLERSHADOW", "TEXTURE2D", "TEXTURE3D", + "TEXTURECUBE", "TEXTURE2DARRAY", "ITEXTURE2D", "ITEXTURE3D", + "ITEXTURECUBE", "ITEXTURE2DARRAY", "UTEXTURE2D", "UTEXTURE3D", + "UTEXTURECUBE", "UTEXTURE2DARRAY", "ATTRIBUTE", "VARYING", "FLOAT16_T", + "FLOAT32_T", "DOUBLE", "FLOAT64_T", "INT64_T", "UINT64_T", "INT32_T", + "UINT32_T", "INT16_T", "UINT16_T", "INT8_T", "UINT8_T", "I64VEC2", + "I64VEC3", "I64VEC4", "U64VEC2", "U64VEC3", "U64VEC4", "I32VEC2", + "I32VEC3", "I32VEC4", "U32VEC2", "U32VEC3", "U32VEC4", "I16VEC2", + "I16VEC3", "I16VEC4", "U16VEC2", "U16VEC3", "U16VEC4", "I8VEC2", + "I8VEC3", "I8VEC4", "U8VEC2", "U8VEC3", "U8VEC4", "DVEC2", "DVEC3", + "DVEC4", "DMAT2", "DMAT3", "DMAT4", "F16VEC2", "F16VEC3", "F16VEC4", + "F16MAT2", "F16MAT3", "F16MAT4", "F32VEC2", "F32VEC3", "F32VEC4", + "F32MAT2", "F32MAT3", "F32MAT4", "F64VEC2", "F64VEC3", "F64VEC4", + "F64MAT2", "F64MAT3", "F64MAT4", "DMAT2X2", "DMAT2X3", "DMAT2X4", + "DMAT3X2", "DMAT3X3", "DMAT3X4", "DMAT4X2", "DMAT4X3", "DMAT4X4", + "F16MAT2X2", "F16MAT2X3", "F16MAT2X4", "F16MAT3X2", "F16MAT3X3", + "F16MAT3X4", "F16MAT4X2", "F16MAT4X3", "F16MAT4X4", "F32MAT2X2", + "F32MAT2X3", "F32MAT2X4", "F32MAT3X2", "F32MAT3X3", "F32MAT3X4", + "F32MAT4X2", "F32MAT4X3", "F32MAT4X4", "F64MAT2X2", "F64MAT2X3", + "F64MAT2X4", "F64MAT3X2", "F64MAT3X3", "F64MAT3X4", "F64MAT4X2", + "F64MAT4X3", "F64MAT4X4", "ATOMIC_UINT", "ACCSTRUCTNV", "ACCSTRUCTEXT", + "RAYQUERYEXT", "FCOOPMATNV", "ICOOPMATNV", "UCOOPMATNV", + "SAMPLERCUBEARRAY", "SAMPLERCUBEARRAYSHADOW", "ISAMPLERCUBEARRAY", + "USAMPLERCUBEARRAY", "SAMPLER1D", "SAMPLER1DARRAY", + "SAMPLER1DARRAYSHADOW", "ISAMPLER1D", "SAMPLER1DSHADOW", "SAMPLER2DRECT", + "SAMPLER2DRECTSHADOW", "ISAMPLER2DRECT", "USAMPLER2DRECT", + "SAMPLERBUFFER", "ISAMPLERBUFFER", "USAMPLERBUFFER", "SAMPLER2DMS", + "ISAMPLER2DMS", "USAMPLER2DMS", "SAMPLER2DMSARRAY", "ISAMPLER2DMSARRAY", + "USAMPLER2DMSARRAY", "SAMPLEREXTERNALOES", "SAMPLEREXTERNAL2DY2YEXT", + "ISAMPLER1DARRAY", "USAMPLER1D", "USAMPLER1DARRAY", "F16SAMPLER1D", + "F16SAMPLER2D", "F16SAMPLER3D", "F16SAMPLER2DRECT", "F16SAMPLERCUBE", + "F16SAMPLER1DARRAY", "F16SAMPLER2DARRAY", "F16SAMPLERCUBEARRAY", + "F16SAMPLERBUFFER", "F16SAMPLER2DMS", "F16SAMPLER2DMSARRAY", + "F16SAMPLER1DSHADOW", "F16SAMPLER2DSHADOW", "F16SAMPLER1DARRAYSHADOW", + "F16SAMPLER2DARRAYSHADOW", "F16SAMPLER2DRECTSHADOW", + "F16SAMPLERCUBESHADOW", "F16SAMPLERCUBEARRAYSHADOW", "IMAGE1D", + "IIMAGE1D", "UIMAGE1D", "IMAGE2D", "IIMAGE2D", "UIMAGE2D", "IMAGE3D", + "IIMAGE3D", "UIMAGE3D", "IMAGE2DRECT", "IIMAGE2DRECT", "UIMAGE2DRECT", + "IMAGECUBE", "IIMAGECUBE", "UIMAGECUBE", "IMAGEBUFFER", "IIMAGEBUFFER", + "UIMAGEBUFFER", "IMAGE1DARRAY", "IIMAGE1DARRAY", "UIMAGE1DARRAY", + "IMAGE2DARRAY", "IIMAGE2DARRAY", "UIMAGE2DARRAY", "IMAGECUBEARRAY", + "IIMAGECUBEARRAY", "UIMAGECUBEARRAY", "IMAGE2DMS", "IIMAGE2DMS", + "UIMAGE2DMS", "IMAGE2DMSARRAY", "IIMAGE2DMSARRAY", "UIMAGE2DMSARRAY", + "F16IMAGE1D", "F16IMAGE2D", "F16IMAGE3D", "F16IMAGE2DRECT", + "F16IMAGECUBE", "F16IMAGE1DARRAY", "F16IMAGE2DARRAY", + "F16IMAGECUBEARRAY", "F16IMAGEBUFFER", "F16IMAGE2DMS", + "F16IMAGE2DMSARRAY", "I64IMAGE1D", "U64IMAGE1D", "I64IMAGE2D", + "U64IMAGE2D", "I64IMAGE3D", "U64IMAGE3D", "I64IMAGE2DRECT", + "U64IMAGE2DRECT", "I64IMAGECUBE", "U64IMAGECUBE", "I64IMAGEBUFFER", + "U64IMAGEBUFFER", "I64IMAGE1DARRAY", "U64IMAGE1DARRAY", + "I64IMAGE2DARRAY", "U64IMAGE2DARRAY", "I64IMAGECUBEARRAY", + "U64IMAGECUBEARRAY", "I64IMAGE2DMS", "U64IMAGE2DMS", "I64IMAGE2DMSARRAY", + "U64IMAGE2DMSARRAY", "TEXTURECUBEARRAY", "ITEXTURECUBEARRAY", + "UTEXTURECUBEARRAY", "TEXTURE1D", "ITEXTURE1D", "UTEXTURE1D", + "TEXTURE1DARRAY", "ITEXTURE1DARRAY", "UTEXTURE1DARRAY", "TEXTURE2DRECT", + "ITEXTURE2DRECT", "UTEXTURE2DRECT", "TEXTUREBUFFER", "ITEXTUREBUFFER", + "UTEXTUREBUFFER", "TEXTURE2DMS", "ITEXTURE2DMS", "UTEXTURE2DMS", + "TEXTURE2DMSARRAY", "ITEXTURE2DMSARRAY", "UTEXTURE2DMSARRAY", + "F16TEXTURE1D", "F16TEXTURE2D", "F16TEXTURE3D", "F16TEXTURE2DRECT", + "F16TEXTURECUBE", "F16TEXTURE1DARRAY", "F16TEXTURE2DARRAY", + "F16TEXTURECUBEARRAY", "F16TEXTUREBUFFER", "F16TEXTURE2DMS", + "F16TEXTURE2DMSARRAY", "SUBPASSINPUT", "SUBPASSINPUTMS", "ISUBPASSINPUT", + "ISUBPASSINPUTMS", "USUBPASSINPUT", "USUBPASSINPUTMS", "F16SUBPASSINPUT", + "F16SUBPASSINPUTMS", "SPIRV_INSTRUCTION", "SPIRV_EXECUTION_MODE", + "SPIRV_EXECUTION_MODE_ID", "SPIRV_DECORATE", "SPIRV_DECORATE_ID", + "SPIRV_DECORATE_STRING", "SPIRV_TYPE", "SPIRV_STORAGE_CLASS", + "SPIRV_BY_REFERENCE", "SPIRV_LITERAL", "LEFT_OP", "RIGHT_OP", "INC_OP", + "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", + "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", + "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", + "SUB_ASSIGN", "STRING_LITERAL", "LEFT_PAREN", "RIGHT_PAREN", + "LEFT_BRACKET", "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT", + "COMMA", "COLON", "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", + "STAR", "SLASH", "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", + "CARET", "AMPERSAND", "QUESTION", "INVARIANT", "HIGH_PRECISION", + "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "PACKED", "RESOURCE", + "SUPERP", "FLOATCONSTANT", "INTCONSTANT", "UINTCONSTANT", "BOOLCONSTANT", + "IDENTIFIER", "TYPE_NAME", "CENTROID", "IN", "OUT", "INOUT", "STRUCT", + "VOID", "WHILE", "BREAK", "CONTINUE", "DO", "ELSE", "FOR", "IF", + "DISCARD", "RETURN", "SWITCH", "CASE", "DEFAULT", "TERMINATE_INVOCATION", + "TERMINATE_RAY", "IGNORE_INTERSECTION", "UNIFORM", "SHARED", "BUFFER", + "FLAT", "SMOOTH", "LAYOUT", "DOUBLECONSTANT", "INT16CONSTANT", + "UINT16CONSTANT", "FLOAT16CONSTANT", "INT32CONSTANT", "UINT32CONSTANT", + "INT64CONSTANT", "UINT64CONSTANT", "SUBROUTINE", "DEMOTE", "PAYLOADNV", + "PAYLOADINNV", "HITATTRNV", "CALLDATANV", "CALLDATAINNV", "PAYLOADEXT", + "PAYLOADINEXT", "HITATTREXT", "CALLDATAEXT", "CALLDATAINEXT", "PATCH", + "SAMPLE", "NONUNIFORM", "COHERENT", "VOLATILE", "RESTRICT", "READONLY", + "WRITEONLY", "DEVICECOHERENT", "QUEUEFAMILYCOHERENT", + "WORKGROUPCOHERENT", "SUBGROUPCOHERENT", "NONPRIVATE", + "SHADERCALLCOHERENT", "NOPERSPECTIVE", "EXPLICITINTERPAMD", + "PERVERTEXNV", "PERPRIMITIVENV", "PERVIEWNV", "PERTASKNV", "PRECISE", + "$accept", "variable_identifier", "primary_expression", + "postfix_expression", "integer_expression", "function_call", + "function_call_or_method", "function_call_generic", + "function_call_header_no_parameters", + "function_call_header_with_parameters", "function_call_header", + "function_identifier", "unary_expression", "unary_operator", + "multiplicative_expression", "additive_expression", "shift_expression", + "relational_expression", "equality_expression", "and_expression", + "exclusive_or_expression", "inclusive_or_expression", + "logical_and_expression", "logical_xor_expression", + "logical_or_expression", "conditional_expression", "$@1", + "assignment_expression", "assignment_operator", "expression", + "constant_expression", "declaration", "block_structure", "$@2", + "identifier_list", "function_prototype", "function_declarator", + "function_header_with_parameters", "function_header", + "parameter_declarator", "parameter_declaration", + "parameter_type_specifier", "init_declarator_list", "single_declaration", + "fully_specified_type", "invariant_qualifier", "interpolation_qualifier", + "layout_qualifier", "layout_qualifier_id_list", "layout_qualifier_id", + "precise_qualifier", "type_qualifier", "single_type_qualifier", + "storage_qualifier", "non_uniform_qualifier", "type_name_list", + "type_specifier", "array_specifier", "type_parameter_specifier_opt", + "type_parameter_specifier", "type_parameter_specifier_list", + "type_specifier_nonarray", "precision_qualifier", "struct_specifier", + "$@3", "$@4", "struct_declaration_list", "struct_declaration", + "struct_declarator_list", "struct_declarator", "initializer", + "initializer_list", "declaration_statement", "statement", + "simple_statement", "demote_statement", "compound_statement", "$@5", + "$@6", "statement_no_new_scope", "statement_scoped", "$@7", "$@8", + "compound_statement_no_new_scope", "statement_list", + "expression_statement", "selection_statement", + "selection_statement_nonattributed", "selection_rest_statement", + "condition", "switch_statement", "switch_statement_nonattributed", "$@9", + "switch_statement_list", "case_label", "iteration_statement", + "iteration_statement_nonattributed", "$@10", "$@11", "$@12", + "for_init_statement", "conditionopt", "for_rest_statement", + "jump_statement", "translation_unit", "external_declaration", + "function_definition", "$@13", "attribute", "attribute_list", + "single_attribute", "spirv_requirements_list", + "spirv_requirements_parameter", "spirv_extension_list", + "spirv_capability_list", "spirv_execution_mode_qualifier", + "spirv_execution_mode_parameter_list", "spirv_execution_mode_parameter", + "spirv_execution_mode_id_parameter_list", + "spirv_storage_class_qualifier", "spirv_decorate_qualifier", + "spirv_decorate_parameter_list", "spirv_decorate_parameter", + "spirv_decorate_id_parameter_list", + "spirv_decorate_string_parameter_list", "spirv_type_specifier", + "spirv_type_parameter_list", "spirv_type_parameter", + "spirv_instruction_qualifier", "spirv_instruction_qualifier_list", + "spirv_instruction_qualifier_id", YY_NULLPTR +}; + +static const char * +yysymbol_name (yysymbol_kind_t yysymbol) +{ + return yytname[yysymbol]; +} +#endif + +#ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_int16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, + 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, + 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, + 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, + 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, + 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, + 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, + 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, + 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, + 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, + 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, + 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, + 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, + 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, + 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, + 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, + 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, + 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, + 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, + 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, + 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, + 705, 706, 707, 708, 709 +}; +#endif + +#define YYPACT_NINF (-863) + +#define yypact_value_is_default(Yyn) \ + ((Yyn) == YYPACT_NINF) + +#define YYTABLE_NINF (-570) + +#define yytable_value_is_error(Yyn) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 4549, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -260, -182, -177, -163, -130, + -115, -100, -89, -863, -863, -196, -863, -863, -863, -863, + -863, -324, -863, -863, -863, -863, -863, -306, -863, -863, + -863, -863, -863, -863, -77, -66, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -332, -175, + -153, -161, 7713, -266, -863, -71, -863, -863, -863, -863, + 5453, -863, -863, -863, -863, -116, -863, -863, 933, -863, + -863, 7713, -35, -863, -863, -863, 5905, -54, -139, -138, + -137, -128, -124, -54, -123, -51, 12061, -863, -15, -347, + -44, -863, -295, -863, -9, -6, 7713, -863, -863, -863, + 7713, -39, -38, -863, -303, -863, -226, -863, -863, 10762, + -3, -863, -863, -863, 1, -32, 7713, -863, -5, -8, + -1, -863, -230, -863, -219, -2, 3, 4, 5, -215, + 6, 8, 10, 11, 12, 15, -214, 13, 16, 21, + -134, -863, 17, 7713, -863, 19, -863, -212, -863, -863, + -211, 9030, -863, -273, 1385, -863, -863, -863, -863, -863, + -3, -263, -863, 9463, -236, -863, -28, -863, -106, 10762, + 10762, -863, 10762, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -264, -863, -863, -863, 23, -203, 11195, 25, + -863, 10762, -863, -863, -311, 24, -6, 29, -863, -309, + -54, -863, -20, -863, -323, 28, -118, 10762, -112, -863, + -155, -111, 10762, -103, 35, -98, -54, -863, 11628, -863, + -94, 10762, 32, -51, -863, 7713, 18, 6357, -863, 7713, + 10762, -863, -347, -863, 33, -863, -863, -72, -254, -86, + -297, -68, -13, 26, 20, 50, 49, -300, 42, 9896, + -863, 43, -863, -863, 55, 58, 60, -863, 65, 71, + 62, 10329, 73, 10762, 66, 69, 70, 72, 74, -241, + -863, -863, -41, -863, -175, 83, 85, -863, -863, -863, + -863, -863, 1837, -863, -863, -863, -863, -863, -863, -863, + -863, -863, 5001, 24, 9463, -233, 8164, -863, -863, 9463, + 7713, -863, 51, -863, -863, -863, -194, -863, -863, 10762, + 52, -863, -863, 10762, 88, -863, -863, -863, 10762, -863, + -863, -863, -315, -863, -863, -191, 82, -863, -863, -863, + -863, -863, -863, -190, -863, -187, -863, -863, -186, 86, + -863, -863, -863, -863, -169, -863, -168, -863, -167, 89, + -863, -165, 91, -157, 82, -863, 85, -156, -863, 94, + 98, -863, -863, 18, -3, -40, -863, -863, -863, 6809, + -863, -863, -863, 10762, 10762, 10762, 10762, 10762, 10762, 10762, + 10762, 10762, 10762, 10762, 10762, 10762, 10762, 10762, 10762, 10762, + 10762, 10762, -863, -863, -863, 97, -863, 2289, -863, -863, + -863, 2289, -863, 10762, -863, -863, -34, 10762, -79, -863, + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, 10762, 10762, -863, -863, -863, + -863, -863, -863, -863, 9463, -863, -863, -208, -863, 7261, + -863, -863, 99, 96, -863, -863, -863, -863, -863, -132, + -131, -863, -307, -863, -323, -863, -323, -863, 10762, 10762, + -863, -155, -863, -155, -863, 10762, 10762, -863, 93, 35, + -863, 11628, -863, 10762, -863, -863, -33, 24, 18, -863, + -863, -863, -863, -863, -72, -72, -254, -254, -86, -86, + -86, -86, -297, -297, -68, -13, 26, 20, 50, 49, + 10762, -863, 2289, 4097, 57, 3645, -154, -863, -152, -863, + -863, -863, -863, -863, 8597, -863, -863, -863, 105, -863, + 75, -863, -145, -863, -144, -863, -143, -863, -142, -863, + -141, -140, -863, -863, -863, -27, 100, 96, 76, 106, + 109, -863, -863, 4097, 107, -863, -863, -863, -863, -863, + -863, -863, -863, -863, -863, -863, 10762, -863, 101, 2741, + 10762, -863, 103, 113, 67, 112, 3193, -863, 114, -863, + 9463, -863, -863, -863, -133, 10762, 2741, 107, -863, -863, + 2289, -863, 110, 96, -863, -863, 2289, 116, -863, -863 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_int16 yydefact[] = +{ + 0, 166, 219, 217, 218, 216, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 220, 221, 222, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 345, 346, 347, 348, 349, 350, 351, 371, 372, 373, + 374, 375, 376, 377, 386, 399, 400, 387, 388, 390, + 389, 391, 392, 393, 394, 395, 396, 397, 398, 174, + 175, 245, 246, 244, 247, 254, 255, 252, 253, 250, + 251, 248, 249, 277, 278, 279, 289, 290, 291, 274, + 275, 276, 286, 287, 288, 271, 272, 273, 283, 284, + 285, 268, 269, 270, 280, 281, 282, 256, 257, 258, + 292, 293, 294, 259, 260, 261, 304, 305, 306, 262, + 263, 264, 316, 317, 318, 265, 266, 267, 328, 329, + 330, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 343, 340, 341, + 342, 524, 525, 526, 355, 356, 379, 382, 344, 353, + 354, 370, 352, 401, 402, 405, 406, 407, 409, 410, + 411, 413, 414, 415, 417, 418, 514, 515, 378, 380, + 381, 357, 358, 359, 403, 360, 364, 365, 368, 408, + 412, 416, 361, 362, 366, 367, 404, 363, 369, 448, + 450, 451, 452, 454, 455, 456, 458, 459, 460, 462, + 463, 464, 466, 467, 468, 470, 471, 472, 474, 475, + 476, 478, 479, 480, 482, 483, 484, 486, 487, 488, + 490, 491, 449, 453, 457, 461, 465, 473, 477, 481, + 469, 485, 489, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 383, 384, 385, 419, 428, + 430, 424, 429, 431, 432, 434, 435, 436, 438, 439, + 440, 442, 443, 444, 446, 447, 420, 421, 422, 433, + 423, 425, 426, 427, 437, 441, 445, 516, 517, 520, + 521, 522, 523, 518, 519, 0, 0, 0, 0, 0, + 0, 0, 0, 164, 165, 0, 620, 137, 530, 531, + 532, 0, 529, 170, 168, 169, 167, 0, 215, 171, + 172, 173, 139, 138, 0, 199, 180, 182, 178, 184, + 186, 181, 183, 179, 185, 187, 176, 177, 201, 188, + 195, 196, 197, 198, 189, 190, 191, 192, 193, 194, + 140, 141, 142, 143, 144, 145, 152, 619, 0, 621, + 0, 114, 113, 0, 125, 130, 159, 158, 156, 160, + 0, 153, 155, 161, 135, 211, 157, 528, 0, 616, + 618, 0, 0, 162, 163, 527, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, + 0, 99, 0, 94, 0, 109, 0, 121, 115, 123, + 0, 124, 0, 97, 131, 102, 0, 154, 136, 0, + 204, 210, 1, 617, 0, 0, 0, 96, 0, 0, + 0, 628, 0, 681, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 626, + 0, 624, 0, 0, 533, 149, 151, 0, 147, 202, + 0, 0, 100, 0, 0, 622, 110, 116, 120, 122, + 118, 126, 117, 0, 132, 105, 0, 103, 0, 0, + 0, 9, 0, 43, 42, 44, 41, 5, 6, 7, + 8, 2, 16, 14, 15, 17, 10, 11, 12, 13, + 3, 18, 37, 20, 25, 26, 0, 0, 30, 0, + 213, 0, 36, 34, 0, 205, 111, 0, 95, 0, + 0, 679, 0, 636, 0, 0, 0, 0, 0, 653, + 0, 0, 0, 0, 0, 0, 0, 673, 0, 651, + 0, 0, 0, 0, 98, 0, 0, 0, 537, 0, + 0, 146, 0, 200, 0, 206, 45, 49, 52, 55, + 60, 63, 65, 67, 69, 71, 73, 75, 0, 0, + 101, 564, 573, 577, 0, 0, 0, 598, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 78, 91, 0, 551, 0, 161, 135, 554, 575, 553, + 561, 552, 0, 555, 556, 579, 557, 586, 558, 559, + 594, 560, 0, 119, 0, 127, 0, 545, 134, 0, + 0, 107, 0, 104, 38, 39, 0, 22, 23, 0, + 0, 28, 27, 0, 215, 31, 33, 40, 0, 212, + 112, 683, 0, 684, 629, 0, 0, 682, 648, 644, + 645, 646, 647, 0, 642, 0, 93, 649, 0, 0, + 663, 664, 665, 666, 0, 661, 0, 667, 0, 0, + 669, 0, 0, 0, 2, 677, 678, 0, 675, 0, + 0, 623, 625, 0, 543, 0, 541, 536, 538, 0, + 150, 148, 203, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 76, 207, 208, 0, 563, 0, 596, 609, + 608, 0, 600, 0, 612, 610, 0, 0, 0, 593, + 613, 614, 615, 562, 81, 82, 84, 83, 86, 87, + 88, 89, 90, 85, 80, 0, 0, 578, 574, 576, + 580, 587, 595, 129, 0, 548, 549, 0, 133, 0, + 108, 4, 0, 24, 21, 32, 214, 632, 634, 0, + 0, 680, 0, 638, 0, 637, 0, 640, 0, 0, + 655, 0, 654, 0, 657, 0, 0, 659, 0, 0, + 674, 0, 671, 0, 652, 627, 0, 544, 0, 539, + 534, 46, 47, 48, 51, 50, 53, 54, 58, 59, + 56, 57, 61, 62, 64, 66, 68, 70, 72, 74, + 0, 209, 565, 0, 0, 0, 0, 611, 0, 592, + 79, 92, 128, 546, 0, 106, 19, 630, 0, 631, + 0, 643, 0, 650, 0, 662, 0, 668, 0, 670, + 0, 0, 676, 540, 542, 0, 0, 584, 0, 0, + 0, 603, 602, 605, 571, 588, 547, 550, 633, 635, + 639, 641, 656, 658, 660, 672, 0, 566, 0, 0, + 0, 604, 0, 0, 583, 0, 0, 581, 0, 77, + 0, 568, 597, 567, 0, 606, 0, 571, 570, 572, + 590, 585, 0, 607, 601, 582, 591, 0, 599, 589 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -863, -863, -863, -863, -863, -863, -863, -863, -863, -863, + -863, -863, -418, -863, -380, -379, -484, -382, -258, -256, + -253, -257, -252, -255, -863, -478, -863, -485, -863, -491, + -530, 14, -863, -863, -863, 7, -397, -863, -863, 44, + 53, 47, -863, -863, -400, -863, -863, -863, -863, -92, + -863, -377, -362, -863, 9, -863, 0, -414, -863, -863, + -863, -863, 150, -863, -863, -863, -546, -548, -218, -331, + -624, -863, -359, -609, -862, -863, -417, -863, -863, -427, + -426, -863, -863, 68, -719, -355, -863, -136, -863, -389, + -863, -135, -863, -863, -863, -863, -129, -863, -863, -863, + -863, -863, -863, -863, -863, 102, -863, -863, 2, -863, + -65, -234, -432, -863, -863, -863, -301, -293, -294, -863, + -863, -304, -299, -302, -298, -863, -296, -305, -863, -383, + -526 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 520, 521, 522, 782, 523, 524, 525, 526, 527, + 528, 529, 609, 531, 577, 578, 579, 580, 581, 582, + 583, 584, 585, 586, 587, 610, 840, 611, 765, 612, + 695, 613, 378, 640, 498, 614, 380, 381, 382, 427, + 428, 429, 383, 384, 385, 386, 387, 388, 477, 478, + 389, 390, 391, 392, 532, 480, 533, 483, 440, 441, + 534, 395, 396, 397, 569, 473, 567, 568, 705, 706, + 638, 777, 617, 618, 619, 620, 621, 737, 876, 912, + 904, 905, 906, 913, 622, 623, 624, 625, 907, 879, + 626, 627, 908, 927, 628, 629, 630, 843, 741, 845, + 883, 902, 903, 631, 398, 399, 400, 424, 632, 470, + 471, 450, 451, 789, 790, 402, 673, 674, 678, 403, + 404, 684, 685, 688, 691, 405, 697, 698, 406, 452, + 453 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 394, 445, 401, 588, 444, 430, 445, 379, 637, 393, + 773, 646, 776, 769, 377, 778, 667, 677, 842, 708, + 494, 530, 687, 709, 446, 668, 535, 421, 437, 446, + 466, 700, 667, 787, 720, 721, 731, 911, 475, 661, + 710, 661, 662, 655, 919, 658, 492, 417, 481, 430, + 328, 329, 330, 422, 911, 493, 481, 659, 669, 670, + 671, 672, 476, 576, 482, 647, 648, 788, 437, 676, + 722, 723, 732, 663, 676, 663, 633, 635, 589, 418, + 676, 644, 645, 676, 437, -35, 590, 649, 481, 407, + 432, 650, 676, 433, 779, 634, 565, 754, 755, 756, + 757, 758, 759, 760, 761, 762, 763, 716, 664, 717, + 746, 735, 748, 657, 664, 589, 664, 764, 589, 664, + 541, 664, 639, 664, 664, 774, 542, 495, 664, 576, + 496, 543, 844, 497, 576, 549, 557, 544, 571, 573, + 576, 550, 558, 576, 572, 574, 853, 652, 854, 637, + 852, 637, 576, 653, 637, 415, 781, 665, 783, 791, + 793, 708, 766, 795, 797, 542, 794, 408, 785, 796, + 798, 576, 409, 693, 456, 458, 460, 462, 464, 465, + 468, 800, 802, 804, 423, 807, 410, 801, 803, 805, + 565, 808, 565, 810, 812, 426, 884, 425, 885, 811, + 813, 926, 766, 437, 766, 890, 891, 892, 893, 894, + 895, 794, 798, 801, 805, 808, 813, 922, 562, 411, + 857, 859, 563, 766, 858, 860, 680, 681, 682, 683, + 887, 708, 445, 769, 412, 444, 828, 829, 830, 831, + 786, 718, 719, 454, 457, 459, 455, 455, 455, 413, + 642, 439, 846, 643, 461, 446, 848, 455, 463, 467, + 414, 455, 455, 565, 675, 724, 725, 455, 863, 677, + 679, 686, 419, 455, 455, 867, 687, 766, 849, 689, + 850, 851, 455, 420, 692, 667, 921, 455, 699, 637, + 817, 455, 713, 714, 715, 821, 822, 823, 576, 576, + 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, + 576, 576, 576, 576, 434, 766, 818, 769, 767, 819, + 676, 676, 766, 818, 447, 847, 873, 676, 676, 766, + 896, 449, 565, 676, 469, 676, 824, 825, 474, 826, + 827, 479, 832, 833, 484, 325, 490, 491, 481, 875, + 539, 536, 877, 537, 538, 540, 545, 641, 726, 546, + 547, 548, 551, 559, 552, 666, 553, 554, 555, 637, + 561, 556, 560, 651, 656, 589, 564, 570, 492, 662, + 576, 576, 431, 690, 701, 729, 730, 576, 576, 728, + 438, 393, 877, 576, 733, 576, 727, 736, 394, 393, + 401, 394, 565, 704, 738, 379, 394, 393, 401, 914, + 393, 909, 377, 448, 742, 393, 472, 739, 712, 740, + 743, 744, 747, 749, 923, 637, 431, 486, 750, 751, + 431, 752, -36, 753, -34, 393, 780, 784, -29, 393, + 792, 869, 799, 878, 814, 806, 438, 809, 815, 841, + 880, 856, 766, 888, 897, 393, 899, 889, 900, 910, + -569, 898, 915, 916, 917, 591, 446, 920, 834, 928, + 929, 835, 837, 566, 488, 836, 839, 489, 838, 487, + 711, 416, 393, 878, 616, 816, 881, 874, 918, 924, + 882, 925, 485, 615, 901, 862, 770, 771, 702, 866, + 443, 861, 865, 772, 868, 864, 446, 0, 872, 0, + 0, 870, 0, 0, 0, 871, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 660, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 696, 0, + 0, 0, 0, 0, 0, 703, 0, 566, 0, 566, + 0, 0, 0, 0, 393, 0, 393, 0, 393, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 616, 0, 0, 0, 0, 0, 0, 0, + 0, 615, 394, 0, 0, 0, 0, 0, 0, 0, + 566, 393, 0, 0, 0, 0, 0, 0, 0, 393, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 566, + 0, 0, 0, 0, 0, 0, 0, 0, 393, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 616, 0, 0, + 0, 616, 0, 0, 0, 0, 615, 0, 0, 0, + 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 566, + 0, 0, 0, 0, 0, 0, 0, 0, 393, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 696, 0, 696, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 616, 616, 0, 616, 0, 401, 0, 0, + 0, 615, 615, 0, 615, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 616, 0, 0, 0, 0, 0, 0, + 0, 0, 615, 0, 0, 0, 0, 0, 0, 616, + 0, 0, 0, 0, 0, 0, 616, 0, 615, 0, + 0, 0, 0, 0, 0, 615, 616, 0, 0, 0, + 616, 0, 0, 0, 0, 615, 616, 0, 0, 615, + 0, 0, 0, 442, 0, 615, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, + 0, 0, 326, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 327, 328, 329, 330, + 331, 0, 0, 0, 0, 0, 0, 0, 0, 332, + 333, 334, 335, 336, 337, 338, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 340, 341, 342, 343, 344, 0, 0, 0, + 0, 0, 0, 0, 0, 345, 0, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 0, 0, 499, 500, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 501, 502, 0, 325, 0, 591, 592, + 0, 0, 0, 0, 593, 503, 504, 505, 506, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 327, 328, + 329, 330, 331, 0, 0, 0, 507, 508, 509, 510, + 511, 332, 333, 334, 335, 336, 337, 338, 594, 595, + 596, 597, 0, 598, 599, 600, 601, 602, 603, 604, + 605, 606, 607, 339, 340, 341, 342, 343, 344, 512, + 513, 514, 515, 516, 517, 518, 519, 345, 608, 346, + 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 0, 0, 499, 500, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 501, 502, 0, 325, 0, + 591, 768, 0, 0, 0, 0, 593, 503, 504, 505, + 506, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 327, 328, 329, 330, 331, 0, 0, 0, 507, 508, + 509, 510, 511, 332, 333, 334, 335, 336, 337, 338, + 594, 595, 596, 597, 0, 598, 599, 600, 601, 602, + 603, 604, 605, 606, 607, 339, 340, 341, 342, 343, + 344, 512, 513, 514, 515, 516, 517, 518, 519, 345, + 608, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 0, 0, 499, 500, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 501, 502, 0, + 325, 0, 591, 0, 0, 0, 0, 0, 593, 503, + 504, 505, 506, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 327, 328, 329, 330, 331, 0, 0, 0, + 507, 508, 509, 510, 511, 332, 333, 334, 335, 336, + 337, 338, 594, 595, 596, 597, 0, 598, 599, 600, + 601, 602, 603, 604, 605, 606, 607, 339, 340, 341, + 342, 343, 344, 512, 513, 514, 515, 516, 517, 518, + 519, 345, 608, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 0, 0, + 499, 500, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 501, + 502, 0, 325, 0, 484, 0, 0, 0, 0, 0, + 593, 503, 504, 505, 506, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 327, 328, 329, 330, 331, 0, + 0, 0, 507, 508, 509, 510, 511, 332, 333, 334, + 335, 336, 337, 338, 594, 595, 596, 597, 0, 598, + 599, 600, 601, 602, 603, 604, 605, 606, 607, 339, + 340, 341, 342, 343, 344, 512, 513, 514, 515, 516, + 517, 518, 519, 345, 608, 346, 347, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 0, 0, 499, 500, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 501, 502, 0, 325, 0, 0, 0, 0, 0, + 0, 0, 593, 503, 504, 505, 506, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 327, 328, 329, 330, + 331, 0, 0, 0, 507, 508, 509, 510, 511, 332, + 333, 334, 335, 336, 337, 338, 594, 595, 596, 597, + 0, 598, 599, 600, 601, 602, 603, 604, 605, 606, + 607, 339, 340, 341, 342, 343, 344, 512, 513, 514, + 515, 516, 517, 518, 519, 345, 608, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 0, 0, 499, 500, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 501, 502, 0, 325, 0, 0, 0, + 0, 0, 0, 0, 593, 503, 504, 505, 506, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 327, 328, + 329, 330, 331, 0, 0, 0, 507, 508, 509, 510, + 511, 332, 333, 334, 335, 336, 337, 338, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 339, 340, 341, 342, 343, 344, 512, + 513, 514, 515, 516, 517, 518, 519, 345, 0, 346, + 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 0, 0, 0, 318, 319, 320, + 321, 322, 323, 324, 0, 0, 499, 500, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 501, 502, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 503, 504, 505, + 506, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 327, 328, 329, 330, 0, 0, 0, 0, 507, 508, + 509, 510, 511, 332, 333, 334, 335, 336, 337, 338, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 339, 340, 341, 342, 343, + 344, 512, 513, 514, 515, 516, 517, 518, 519, 345, + 0, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 325, 0, 0, 0, 0, 0, 0, 0, 326, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 327, 328, 329, 330, 331, 0, 0, 0, + 0, 0, 0, 0, 0, 332, 333, 334, 335, 336, + 337, 338, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 339, 340, 341, + 342, 343, 344, 0, 0, 0, 0, 0, 0, 0, + 0, 345, 0, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, + 0, 318, 319, 320, 321, 322, 323, 324, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 327, 328, 329, 330, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 332, 333, 334, + 335, 336, 337, 338, 594, 0, 0, 597, 0, 598, + 599, 0, 0, 602, 0, 0, 0, 0, 0, 339, + 340, 341, 342, 343, 344, 0, 0, 0, 0, 0, + 0, 0, 0, 345, 0, 346, 347, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 0, 0, 0, 318, 319, 320, 321, 322, 323, 324, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 435, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 327, 328, 329, 330, + 0, 0, 0, 0, 0, 0, 0, 0, 436, 332, + 333, 334, 335, 336, 337, 338, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 340, 341, 342, 343, 344, 0, 0, 0, + 0, 0, 0, 0, 0, 345, 0, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 0, 0, 0, 318, 319, 320, 321, 322, + 323, 324, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 327, 328, + 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 332, 333, 334, 335, 336, 337, 338, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 339, 340, 341, 342, 343, 344, 0, + 0, 0, 0, 0, 0, 0, 0, 345, 0, 346, + 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 0, 0, 0, 318, 319, 320, + 321, 322, 323, 324, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 707, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 327, 328, 329, 330, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 332, 333, 334, 335, 336, 337, 338, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 339, 340, 341, 342, 343, + 344, 0, 0, 0, 0, 0, 0, 0, 0, 345, + 0, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 0, 0, 0, 318, + 319, 320, 321, 322, 323, 324, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 820, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 327, 328, 329, 330, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 332, 333, 334, 335, 336, + 337, 338, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 339, 340, 341, + 342, 343, 344, 0, 0, 0, 0, 0, 0, 0, + 0, 345, 0, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, + 0, 318, 319, 320, 321, 322, 323, 324, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 855, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 327, 328, 329, 330, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 332, 333, 334, + 335, 336, 337, 338, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 339, + 340, 341, 342, 343, 344, 0, 0, 0, 0, 0, + 0, 0, 0, 345, 0, 346, 347, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 0, 0, 0, 318, 319, 320, 321, 322, 323, 324, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 327, 328, 329, 330, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 332, + 333, 334, 335, 336, 337, 338, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 340, 341, 342, 343, 344, 0, 0, 0, + 0, 0, 0, 0, 0, 345, 0, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 0, 0, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 0, 0, 0, 0, 0, 0, 321, 0, 0, + 0, 0, 0, 499, 500, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 501, 502, 0, 0, 0, 636, 775, 0, + 0, 0, 0, 0, 503, 504, 505, 506, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 507, 508, 509, 510, 511, + 332, 0, 0, 0, 0, 337, 338, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 512, 513, + 514, 515, 516, 517, 518, 519, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 358, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 0, 0, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 0, 0, 0, 0, 0, 0, + 321, 0, 0, 0, 0, 0, 499, 500, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 501, 502, 0, 0, 0, + 636, 886, 0, 0, 0, 0, 0, 503, 504, 505, + 506, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 507, 508, + 509, 510, 511, 332, 0, 0, 0, 0, 337, 338, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 512, 513, 514, 515, 516, 517, 518, 519, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 358, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 0, 0, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, + 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 0, 0, 0, + 0, 0, 0, 321, 0, 0, 0, 0, 0, 499, + 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 501, 502, + 0, 0, 575, 0, 0, 0, 0, 0, 0, 0, + 503, 504, 505, 506, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 507, 508, 509, 510, 511, 332, 0, 0, 0, + 0, 337, 338, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 512, 513, 514, 515, 516, 517, + 518, 519, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 358, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 0, 0, 0, 0, 0, 0, 321, 0, 0, 0, + 0, 0, 499, 500, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 501, 502, 0, 0, 0, 636, 0, 0, 0, + 0, 0, 0, 503, 504, 505, 506, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 507, 508, 509, 510, 511, 332, + 0, 0, 0, 0, 337, 338, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 512, 513, 514, + 515, 516, 517, 518, 519, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 358, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 0, 0, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 0, 0, 0, 0, 0, 0, 321, + 0, 0, 0, 0, 0, 499, 500, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 501, 502, 0, 0, 734, 0, + 0, 0, 0, 0, 0, 0, 503, 504, 505, 506, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 507, 508, 509, + 510, 511, 332, 0, 0, 0, 0, 337, 338, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 512, 513, 514, 515, 516, 517, 518, 519, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 358, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 0, 0, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 0, 0, 0, 0, + 0, 0, 321, 0, 0, 0, 0, 0, 499, 500, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 501, 502, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 745, 503, + 504, 505, 506, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 507, 508, 509, 510, 511, 332, 0, 0, 0, 0, + 337, 338, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 512, 513, 514, 515, 516, 517, 518, + 519, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 358, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 0, 0, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 0, + 0, 0, 0, 0, 0, 321, 0, 0, 0, 0, + 0, 499, 500, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 501, 502, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 503, 504, 505, 506, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 507, 508, 509, 510, 511, 332, 0, + 0, 0, 0, 337, 338, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 512, 513, 514, 515, + 516, 517, 518, 519, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 358, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 0, 0, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 0, 0, 0, 0, 0, 0, 321, 0, + 0, 0, 0, 0, 499, 500, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 501, 502, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 503, 504, 505, 506, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 507, 508, 509, 510, + 511, 332, 0, 0, 0, 0, 337, 654, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 512, + 513, 514, 515, 516, 517, 518, 519, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 358, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 0, + 0, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, + 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 0, 0, 0, 0, 0, + 0, 321, 0, 0, 0, 0, 0, 499, 500, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 501, 502, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 503, 504, + 505, 506, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 507, + 508, 509, 510, 694, 332, 0, 0, 0, 0, 337, + 338, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 512, 513, 514, 515, 516, 517, 518, 519, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 358, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, + 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 332, 0, 0, + 0, 0, 337, 338 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 401, 0, 481, 401, 382, 406, 0, 493, 0, + 634, 502, 636, 622, 0, 639, 542, 547, 737, 567, + 434, 439, 552, 569, 401, 348, 440, 359, 390, 406, + 413, 561, 558, 348, 331, 332, 336, 899, 385, 348, + 570, 348, 351, 528, 906, 356, 349, 353, 351, 426, + 374, 375, 376, 385, 916, 358, 351, 368, 381, 382, + 383, 384, 409, 481, 359, 329, 330, 382, 430, 547, + 367, 368, 372, 382, 552, 382, 490, 491, 351, 385, + 558, 499, 500, 561, 446, 349, 359, 351, 351, 349, + 356, 355, 570, 359, 640, 358, 473, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 361, 540, 363, + 601, 589, 603, 531, 546, 351, 548, 358, 351, 551, + 350, 553, 358, 555, 556, 358, 356, 353, 560, 547, + 356, 350, 741, 359, 552, 350, 350, 356, 350, 350, + 558, 356, 356, 561, 356, 356, 354, 350, 356, 634, + 774, 636, 570, 356, 639, 351, 350, 540, 649, 350, + 350, 709, 356, 350, 350, 356, 356, 349, 653, 356, + 356, 589, 349, 556, 408, 409, 410, 411, 412, 413, + 414, 350, 350, 350, 359, 350, 349, 356, 356, 356, + 567, 356, 569, 350, 350, 356, 350, 350, 350, 356, + 356, 920, 356, 565, 356, 350, 350, 350, 350, 350, + 350, 356, 356, 356, 356, 356, 356, 350, 352, 349, + 352, 352, 356, 356, 356, 356, 381, 382, 383, 384, + 854, 779, 632, 842, 349, 632, 720, 721, 722, 723, + 658, 327, 328, 382, 382, 382, 385, 385, 385, 349, + 356, 367, 743, 359, 382, 632, 747, 385, 382, 382, + 349, 385, 385, 640, 382, 333, 334, 385, 798, 799, + 382, 382, 349, 385, 385, 805, 806, 356, 357, 382, + 765, 766, 385, 349, 382, 811, 910, 385, 382, 774, + 704, 385, 364, 365, 366, 713, 714, 715, 716, 717, + 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, + 728, 729, 730, 731, 385, 356, 356, 926, 359, 359, + 798, 799, 356, 356, 359, 359, 359, 805, 806, 356, + 357, 385, 709, 811, 385, 813, 716, 717, 353, 718, + 719, 385, 724, 725, 353, 351, 385, 385, 351, 840, + 358, 350, 843, 385, 359, 356, 358, 385, 371, 356, + 356, 356, 356, 350, 356, 385, 356, 356, 356, 854, + 349, 356, 356, 350, 349, 351, 359, 358, 349, 351, + 798, 799, 382, 348, 352, 335, 337, 805, 806, 369, + 390, 382, 883, 811, 352, 813, 370, 354, 398, 390, + 398, 401, 779, 385, 349, 398, 406, 398, 406, 900, + 401, 896, 398, 406, 349, 406, 416, 359, 385, 359, + 349, 359, 349, 357, 915, 910, 426, 425, 359, 359, + 430, 359, 349, 359, 349, 426, 385, 385, 350, 430, + 358, 348, 356, 843, 350, 356, 446, 356, 350, 352, + 393, 352, 356, 348, 354, 446, 350, 382, 349, 358, + 353, 385, 359, 350, 397, 353, 843, 353, 726, 359, + 354, 727, 729, 473, 430, 728, 731, 430, 730, 426, + 572, 331, 473, 883, 484, 703, 845, 818, 905, 916, + 845, 917, 424, 484, 883, 796, 632, 632, 563, 803, + 398, 794, 801, 632, 806, 799, 883, -1, 813, -1, + -1, 809, -1, -1, -1, 811, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 536, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 558, -1, + -1, -1, -1, -1, -1, 565, -1, 567, -1, 569, + -1, -1, -1, -1, 565, -1, 567, -1, 569, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 622, -1, -1, -1, -1, -1, -1, -1, + -1, 622, 632, -1, -1, -1, -1, -1, -1, -1, + 640, 632, -1, -1, -1, -1, -1, -1, -1, 640, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 709, + -1, -1, -1, -1, -1, -1, -1, -1, 709, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 737, -1, -1, + -1, 741, -1, -1, -1, -1, 737, -1, -1, -1, + 741, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 779, + -1, -1, -1, -1, -1, -1, -1, -1, 779, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 811, -1, 813, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 842, 843, -1, 845, -1, 845, -1, -1, + -1, 842, 843, -1, 845, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 883, -1, -1, -1, -1, -1, -1, + -1, -1, 883, -1, -1, -1, -1, -1, -1, 899, + -1, -1, -1, -1, -1, -1, 906, -1, 899, -1, + -1, -1, -1, -1, -1, 906, 916, -1, -1, -1, + 920, -1, -1, -1, -1, 916, 926, -1, -1, 920, + -1, -1, -1, 0, -1, 926, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 351, -1, -1, -1, -1, -1, + -1, -1, 359, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 373, 374, 375, 376, + 377, -1, -1, -1, -1, -1, -1, -1, -1, 386, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 408, 409, 410, 411, 412, 413, -1, -1, -1, + -1, -1, -1, -1, -1, 422, -1, 424, 425, 426, + 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 449, 450, 451, 452, 453, 454, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, -1, -1, 329, 330, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 348, 349, -1, 351, -1, 353, 354, + -1, -1, -1, -1, 359, 360, 361, 362, 363, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 373, 374, + 375, 376, 377, -1, -1, -1, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, -1, 398, 399, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 325, 326, -1, -1, 329, 330, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 348, 349, -1, 351, -1, + 353, 354, -1, -1, -1, -1, 359, 360, 361, 362, + 363, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 373, 374, 375, 376, 377, -1, -1, -1, 381, 382, + 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, + 393, 394, 395, 396, -1, 398, 399, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, + 453, 454, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, -1, -1, 329, 330, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 348, 349, -1, + 351, -1, 353, -1, -1, -1, -1, -1, 359, 360, + 361, 362, 363, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 373, 374, 375, 376, 377, -1, -1, -1, + 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, + 391, 392, 393, 394, 395, 396, -1, 398, 399, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, + 451, 452, 453, 454, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 326, -1, -1, + 329, 330, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 348, + 349, -1, 351, -1, 353, -1, -1, -1, -1, -1, + 359, 360, 361, 362, 363, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 373, 374, 375, 376, 377, -1, + -1, -1, 381, 382, 383, 384, 385, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 396, -1, 398, + 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, + -1, -1, 329, 330, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 348, 349, -1, 351, -1, -1, -1, -1, -1, + -1, -1, 359, 360, 361, 362, 363, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 373, 374, 375, 376, + 377, -1, -1, -1, 381, 382, 383, 384, 385, 386, + 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, + -1, 398, 399, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 449, 450, 451, 452, 453, 454, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, -1, -1, 329, 330, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 348, 349, -1, 351, -1, -1, -1, + -1, -1, -1, -1, 359, 360, 361, 362, 363, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 373, 374, + 375, 376, 377, -1, -1, -1, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, -1, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, -1, -1, -1, 320, 321, 322, + 323, 324, 325, 326, -1, -1, 329, 330, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 348, 349, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 360, 361, 362, + 363, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 373, 374, 375, 376, -1, -1, -1, -1, 381, 382, + 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, + -1, 424, 425, 426, 427, 428, 429, 430, 431, 432, + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, + 453, 454, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 351, -1, -1, -1, -1, -1, -1, -1, 359, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 373, 374, 375, 376, 377, -1, -1, -1, + -1, -1, -1, -1, -1, 386, 387, 388, 389, 390, + 391, 392, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 408, 409, 410, + 411, 412, 413, -1, -1, -1, -1, -1, -1, -1, + -1, 422, -1, 424, 425, 426, 427, 428, 429, 430, + 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, + 451, 452, 453, 454, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, -1, -1, + -1, 320, 321, 322, 323, 324, 325, 326, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 373, 374, 375, 376, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 386, 387, 388, + 389, 390, 391, 392, 393, -1, -1, 396, -1, 398, + 399, -1, -1, 402, -1, -1, -1, -1, -1, 408, + 409, 410, 411, 412, 413, -1, -1, -1, -1, -1, + -1, -1, -1, 422, -1, 424, 425, 426, 427, 428, + 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + -1, -1, -1, 320, 321, 322, 323, 324, 325, 326, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 359, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 373, 374, 375, 376, + -1, -1, -1, -1, -1, -1, -1, -1, 385, 386, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 408, 409, 410, 411, 412, 413, -1, -1, -1, + -1, -1, -1, -1, -1, 422, -1, 424, 425, 426, + 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 449, 450, 451, 452, 453, 454, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, -1, -1, -1, 320, 321, 322, 323, 324, + 325, 326, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 351, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 373, 374, + 375, 376, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 386, 387, 388, 389, 390, 391, 392, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 408, 409, 410, 411, 412, 413, -1, + -1, -1, -1, -1, -1, -1, -1, 422, -1, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, -1, -1, -1, 320, 321, 322, + 323, 324, 325, 326, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 354, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 373, 374, 375, 376, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 386, 387, 388, 389, 390, 391, 392, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 408, 409, 410, 411, 412, + 413, -1, -1, -1, -1, -1, -1, -1, -1, 422, + -1, 424, 425, 426, 427, 428, 429, 430, 431, 432, + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, + 453, 454, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, -1, -1, -1, 320, + 321, 322, 323, 324, 325, 326, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 354, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 373, 374, 375, 376, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 386, 387, 388, 389, 390, + 391, 392, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 408, 409, 410, + 411, 412, 413, -1, -1, -1, -1, -1, -1, -1, + -1, 422, -1, 424, 425, 426, 427, 428, 429, 430, + 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, + 451, 452, 453, 454, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, -1, -1, + -1, 320, 321, 322, 323, 324, 325, 326, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 354, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 373, 374, 375, 376, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 386, 387, 388, + 389, 390, 391, 392, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 408, + 409, 410, 411, 412, 413, -1, -1, -1, -1, -1, + -1, -1, -1, 422, -1, 424, 425, 426, 427, 428, + 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + -1, -1, -1, 320, 321, 322, 323, 324, 325, 326, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 373, 374, 375, 376, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 386, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 408, 409, 410, 411, 412, 413, -1, -1, -1, + -1, -1, -1, -1, -1, 422, -1, 424, 425, 426, + 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 449, 450, 451, 452, 453, 454, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, -1, -1, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, -1, -1, -1, -1, -1, -1, 323, -1, -1, + -1, -1, -1, 329, 330, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 348, 349, -1, -1, -1, 353, 354, -1, + -1, -1, -1, -1, 360, 361, 362, 363, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 381, 382, 383, 384, 385, + 386, -1, -1, -1, -1, 391, 392, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 414, 415, + 416, 417, 418, 419, 420, 421, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 436, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, -1, -1, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, + 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, -1, -1, -1, -1, -1, -1, + 323, -1, -1, -1, -1, -1, 329, 330, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 348, 349, -1, -1, -1, + 353, 354, -1, -1, -1, -1, -1, 360, 361, 362, + 363, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 381, 382, + 383, 384, 385, 386, -1, -1, -1, -1, 391, 392, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 414, 415, 416, 417, 418, 419, 420, 421, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 436, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, -1, -1, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, + 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, -1, -1, -1, + -1, -1, -1, 323, -1, -1, -1, -1, -1, 329, + 330, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 348, 349, + -1, -1, 352, -1, -1, -1, -1, -1, -1, -1, + 360, 361, 362, 363, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 381, 382, 383, 384, 385, 386, -1, -1, -1, + -1, 391, 392, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 414, 415, 416, 417, 418, 419, + 420, 421, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 436, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + -1, -1, -1, -1, -1, -1, 323, -1, -1, -1, + -1, -1, 329, 330, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 348, 349, -1, -1, -1, 353, -1, -1, -1, + -1, -1, -1, 360, 361, 362, 363, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 381, 382, 383, 384, 385, 386, + -1, -1, -1, -1, 391, 392, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 414, 415, 416, + 417, 418, 419, 420, 421, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 436, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, -1, -1, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, -1, -1, -1, -1, -1, -1, 323, + -1, -1, -1, -1, -1, 329, 330, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 348, 349, -1, -1, 352, -1, + -1, -1, -1, -1, -1, -1, 360, 361, 362, 363, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 381, 382, 383, + 384, 385, 386, -1, -1, -1, -1, 391, 392, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 414, 415, 416, 417, 418, 419, 420, 421, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 436, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + -1, -1, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, -1, -1, -1, -1, + -1, -1, 323, -1, -1, -1, -1, -1, 329, 330, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 348, 349, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 359, 360, + 361, 362, 363, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 381, 382, 383, 384, 385, 386, -1, -1, -1, -1, + 391, 392, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 414, 415, 416, 417, 418, 419, 420, + 421, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 436, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, -1, -1, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, + 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, -1, + -1, -1, -1, -1, -1, 323, -1, -1, -1, -1, + -1, 329, 330, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 348, 349, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 360, 361, 362, 363, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 381, 382, 383, 384, 385, 386, -1, + -1, -1, -1, 391, 392, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 414, 415, 416, 417, + 418, 419, 420, 421, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 436, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, -1, -1, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, -1, -1, -1, -1, -1, -1, 323, -1, + -1, -1, -1, -1, 329, 330, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 348, 349, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 360, 361, 362, 363, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 381, 382, 383, 384, + 385, 386, -1, -1, -1, -1, 391, 392, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 414, + 415, 416, 417, 418, 419, 420, 421, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 436, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, -1, + -1, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, -1, -1, -1, -1, -1, + -1, 323, -1, -1, -1, -1, -1, 329, 330, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 348, 349, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 360, 361, + 362, 363, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 381, + 382, 383, 384, 385, 386, -1, -1, -1, -1, 391, + 392, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 414, 415, 416, 417, 418, 419, 420, 421, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 436, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, -1, -1, + -1, -1, -1, -1, 323, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 386, -1, -1, + -1, -1, 391, 392 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_int16 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, 351, 359, 373, 374, 375, + 376, 377, 386, 387, 388, 389, 390, 391, 392, 408, + 409, 410, 411, 412, 413, 422, 424, 425, 426, 427, + 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 449, 450, 451, 452, 453, 454, 486, 487, 490, + 491, 492, 493, 497, 498, 499, 500, 501, 502, 505, + 506, 507, 508, 509, 511, 516, 517, 518, 559, 560, + 561, 563, 570, 574, 575, 580, 583, 349, 349, 349, + 349, 349, 349, 349, 349, 351, 517, 353, 385, 349, + 349, 359, 385, 359, 562, 350, 356, 494, 495, 496, + 506, 511, 356, 359, 385, 359, 385, 507, 511, 367, + 513, 514, 0, 560, 491, 499, 506, 359, 490, 385, + 566, 567, 584, 585, 382, 385, 566, 382, 566, 382, + 566, 382, 566, 382, 566, 566, 584, 382, 566, 385, + 564, 565, 511, 520, 353, 385, 409, 503, 504, 385, + 510, 351, 359, 512, 353, 538, 563, 495, 494, 496, + 385, 385, 349, 358, 512, 353, 356, 359, 489, 329, + 330, 348, 349, 360, 361, 362, 363, 381, 382, 383, + 384, 385, 414, 415, 416, 417, 418, 419, 420, 421, + 456, 457, 458, 460, 461, 462, 463, 464, 465, 466, + 467, 468, 509, 511, 515, 512, 350, 385, 359, 358, + 356, 350, 356, 350, 356, 358, 356, 356, 356, 350, + 356, 356, 356, 356, 356, 356, 356, 350, 356, 350, + 356, 349, 352, 356, 359, 506, 511, 521, 522, 519, + 358, 350, 356, 350, 356, 352, 467, 469, 470, 471, + 472, 473, 474, 475, 476, 477, 478, 479, 480, 351, + 359, 353, 354, 359, 393, 394, 395, 396, 398, 399, + 400, 401, 402, 403, 404, 405, 406, 407, 423, 467, + 480, 482, 484, 486, 490, 509, 511, 527, 528, 529, + 530, 531, 539, 540, 541, 542, 545, 546, 549, 550, + 551, 558, 563, 512, 358, 512, 353, 482, 525, 358, + 488, 385, 356, 359, 467, 467, 484, 329, 330, 351, + 355, 350, 350, 356, 392, 482, 349, 467, 356, 368, + 563, 348, 351, 382, 567, 584, 385, 585, 348, 381, + 382, 383, 384, 571, 572, 382, 480, 485, 573, 382, + 381, 382, 383, 384, 576, 577, 382, 485, 578, 382, + 348, 579, 382, 584, 385, 485, 511, 581, 582, 382, + 485, 352, 565, 511, 385, 523, 524, 354, 522, 521, + 485, 504, 385, 364, 365, 366, 361, 363, 327, 328, + 331, 332, 367, 368, 333, 334, 371, 370, 369, 335, + 337, 336, 372, 352, 352, 480, 354, 532, 349, 359, + 359, 553, 349, 349, 359, 359, 484, 349, 484, 357, + 359, 359, 359, 359, 338, 339, 340, 341, 342, 343, + 344, 345, 346, 347, 358, 483, 356, 359, 354, 528, + 542, 546, 551, 525, 358, 354, 525, 526, 525, 521, + 385, 350, 459, 484, 385, 482, 467, 348, 382, 568, + 569, 350, 358, 350, 356, 350, 356, 350, 356, 356, + 350, 356, 350, 356, 350, 356, 356, 350, 356, 356, + 350, 356, 350, 356, 350, 350, 523, 512, 356, 359, + 354, 467, 467, 467, 469, 469, 470, 470, 471, 471, + 471, 471, 472, 472, 473, 474, 475, 476, 477, 478, + 481, 352, 539, 552, 528, 554, 484, 359, 484, 357, + 482, 482, 525, 354, 356, 354, 352, 352, 356, 352, + 356, 572, 571, 485, 573, 577, 576, 485, 578, 348, + 579, 581, 582, 359, 524, 484, 533, 484, 499, 544, + 393, 527, 540, 555, 350, 350, 354, 525, 348, 382, + 350, 350, 350, 350, 350, 350, 357, 354, 385, 350, + 349, 544, 556, 557, 535, 536, 537, 543, 547, 482, + 358, 529, 534, 538, 484, 359, 350, 397, 531, 529, + 353, 525, 350, 484, 534, 535, 539, 548, 359, 354 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_int16 yyr1[] = +{ + 0, 455, 456, 457, 457, 457, 457, 457, 457, 457, + 457, 457, 457, 457, 457, 457, 457, 457, 458, 458, + 458, 458, 458, 458, 459, 460, 461, 462, 462, 463, + 463, 464, 464, 465, 466, 466, 466, 467, 467, 467, + 467, 468, 468, 468, 468, 469, 469, 469, 469, 470, + 470, 470, 471, 471, 471, 472, 472, 472, 472, 472, + 473, 473, 473, 474, 474, 475, 475, 476, 476, 477, + 477, 478, 478, 479, 479, 480, 481, 480, 482, 482, + 483, 483, 483, 483, 483, 483, 483, 483, 483, 483, + 483, 484, 484, 485, 486, 486, 486, 486, 486, 486, + 486, 486, 486, 486, 486, 488, 487, 489, 489, 490, + 490, 490, 490, 491, 491, 492, 492, 493, 494, 494, + 495, 495, 495, 495, 496, 497, 497, 497, 497, 497, + 498, 498, 498, 498, 498, 499, 499, 500, 501, 501, + 501, 501, 501, 501, 501, 501, 502, 503, 503, 504, + 504, 504, 505, 506, 506, 507, 507, 507, 507, 507, + 507, 507, 507, 507, 507, 507, 508, 508, 508, 508, + 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, + 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, + 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, + 508, 509, 510, 510, 511, 511, 512, 512, 512, 512, + 513, 513, 514, 515, 515, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, + 517, 517, 517, 519, 518, 520, 518, 521, 521, 522, + 522, 523, 523, 524, 524, 525, 525, 525, 525, 526, + 526, 527, 528, 528, 529, 529, 529, 529, 529, 529, + 529, 529, 530, 531, 532, 533, 531, 534, 534, 536, + 535, 537, 535, 538, 538, 539, 539, 540, 540, 541, + 541, 542, 543, 543, 544, 544, 545, 545, 547, 546, + 548, 548, 549, 549, 550, 550, 552, 551, 553, 551, + 554, 551, 555, 555, 556, 556, 557, 557, 558, 558, + 558, 558, 558, 558, 558, 558, 559, 559, 560, 560, + 560, 562, 561, 563, 564, 564, 565, 565, 566, 566, + 567, 567, 568, 568, 569, 569, 570, 570, 570, 570, + 570, 570, 571, 571, 572, 572, 572, 572, 572, 573, + 573, 574, 574, 575, 575, 575, 575, 575, 575, 575, + 575, 576, 576, 577, 577, 577, 577, 578, 578, 579, + 579, 580, 580, 580, 580, 581, 581, 582, 582, 583, + 583, 584, 584, 585, 585 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_int8 yyr2[] = +{ + 0, 2, 1, 1, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, + 1, 3, 2, 2, 1, 1, 1, 2, 2, 2, + 1, 2, 3, 2, 1, 1, 1, 1, 2, 2, + 2, 1, 1, 1, 1, 1, 3, 3, 3, 1, + 3, 3, 1, 3, 3, 1, 3, 3, 3, 3, + 1, 3, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 0, 6, 1, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 1, 2, 3, 2, 2, 4, 2, + 3, 4, 2, 3, 4, 0, 6, 2, 3, 2, + 3, 3, 4, 1, 1, 2, 3, 3, 2, 3, + 2, 1, 2, 1, 1, 1, 3, 4, 6, 5, + 1, 2, 3, 5, 4, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4, 1, 3, 1, + 3, 1, 1, 1, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 4, 1, 1, 3, 2, 3, 2, 3, 3, 4, + 1, 0, 3, 1, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 6, 0, 5, 1, 2, 3, + 4, 1, 3, 1, 2, 1, 3, 4, 2, 1, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 0, 0, 5, 1, 1, 0, + 2, 0, 2, 2, 3, 1, 2, 1, 2, 1, + 2, 5, 3, 1, 1, 4, 1, 2, 0, 8, + 0, 1, 3, 2, 1, 2, 0, 6, 0, 8, + 0, 7, 1, 1, 1, 0, 2, 3, 2, 2, + 2, 3, 2, 2, 2, 2, 1, 2, 1, 1, + 1, 0, 3, 5, 1, 3, 1, 4, 1, 3, + 5, 5, 1, 3, 1, 3, 4, 6, 6, 8, + 6, 8, 1, 3, 1, 1, 1, 1, 1, 1, + 3, 4, 6, 4, 6, 6, 8, 6, 8, 6, + 8, 1, 3, 1, 1, 1, 1, 1, 3, 1, + 3, 6, 8, 4, 6, 1, 3, 1, 1, 4, + 6, 1, 3, 3, 3 +}; + + +enum { YYENOMEM = -2 }; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (pParseContext, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) + +/* Backward compatibility with an undocumented macro. + Use YYerror or YYUNDEF. */ +#define YYERRCODE YYUNDEF + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +# ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif + + +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Kind, Value, pParseContext); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext) +{ + FILE *yyoutput = yyo; + YYUSE (yyoutput); + YYUSE (pParseContext); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yykind < YYNTOKENS) + YYPRINT (yyo, yytoknum[yykind], *yyvaluep); +# endif + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ + +static void +yy_symbol_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext) +{ + YYFPRINTF (yyo, "%s %s (", + yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); + + yy_symbol_value_print (yyo, yykind, yyvaluep, pParseContext); + YYFPRINTF (yyo, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, + int yyrule, glslang::TParseContext* pParseContext) +{ + int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), + &yyvsp[(yyi + 1) - (yynrhs)], pParseContext); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, pParseContext); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) ((void) 0) +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +/* Context of a parse error. */ +typedef struct +{ + yy_state_t *yyssp; + yysymbol_kind_t yytoken; +} yypcontext_t; + +/* Put in YYARG at most YYARGN of the expected tokens given the + current YYCTX, and return the number of tokens stored in YYARG. If + YYARG is null, return the number of expected tokens (guaranteed to + be less than YYNTOKENS). Return YYENOMEM on memory exhaustion. + Return 0 if there are more than YYARGN expected tokens, yet fill + YYARG up to YYARGN. */ +static int +yypcontext_expected_tokens (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + int yyn = yypact[+*yyctx->yyssp]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (!yyarg) + ++yycount; + else if (yycount == yyargn) + return 0; + else + yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx); + } + } + if (yyarg && yycount == 0 && 0 < yyargn) + yyarg[0] = YYSYMBOL_YYEMPTY; + return yycount; +} + + + + +#ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) +# else +/* Return the length of YYSTR. */ +static YYPTRDIFF_T +yystrlen (const char *yystr) +{ + YYPTRDIFF_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +#endif + +#ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +#endif + +#ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYPTRDIFF_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYPTRDIFF_T yyn = 0; + char const *yyp = yystr; + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (yyres) + return yystpcpy (yyres, yystr) - yyres; + else + return yystrlen (yystr); +} +#endif + + +static int +yy_syntax_error_arguments (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yyctx->yytoken != YYSYMBOL_YYEMPTY) + { + int yyn; + if (yyarg) + yyarg[yycount] = yyctx->yytoken; + ++yycount; + yyn = yypcontext_expected_tokens (yyctx, + yyarg ? yyarg + 1 : yyarg, yyargn - 1); + if (yyn == YYENOMEM) + return YYENOMEM; + else + yycount += yyn; + } + return yycount; +} + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, + const yypcontext_t *yyctx) +{ + enum { YYARGS_MAX = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ + yysymbol_kind_t yyarg[YYARGS_MAX]; + /* Cumulated lengths of YYARG. */ + YYPTRDIFF_T yysize = 0; + + /* Actual size of YYARG. */ + int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX); + if (yycount == YYENOMEM) + return YYENOMEM; + + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + /* Compute error message size. Don't count the "%s"s, but reserve + room for the terminator. */ + yysize = yystrlen (yyformat) - 2 * yycount + 1; + { + int yyi; + for (yyi = 0; yyi < yycount; ++yyi) + { + YYPTRDIFF_T yysize1 + = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else + return YYENOMEM; + } + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return -1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]); + yyformat += 2; + } + else + { + ++yyp; + ++yyformat; + } + } + return 0; +} + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, + yysymbol_kind_t yykind, YYSTYPE *yyvaluep, glslang::TParseContext* pParseContext) +{ + YYUSE (yyvaluep); + YYUSE (pParseContext); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (glslang::TParseContext* pParseContext) +{ +/* Lookahead token kind. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs = 0; + + yy_state_fast_t yystate = 0; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus = 0; + + /* Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* Their size. */ + YYPTRDIFF_T yystacksize = YYINITDEPTH; + + /* The state stack: array, bottom, top. */ + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss = yyssa; + yy_state_t *yyssp = yyss; + + /* The semantic value stack: array, bottom, top. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp = yyvs; + + int yyn; + /* The return value of yyparse. */ + int yyresult; + /* Lookahead symbol kind. */ + yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + + +/*------------------------------------------------------------. +| yynewstate -- push a new state, which is found in yystate. | +`------------------------------------------------------------*/ +yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + +/*--------------------------------------------------------------------. +| yysetstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST (yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END + YY_STACK_PRINT (yyss, yyssp); + + if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + goto yyexhaustedlab; +#else + { + /* Get the current used size of the three stacks, in elements. */ + YYPTRDIFF_T yysize = yyssp - yyss + 1; + +# if defined yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + yy_state_t *yyss1 = yyss; + YYSTYPE *yyvs1 = yyvs; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * YYSIZEOF (*yyssp), + &yyvs1, yysize * YYSIZEOF (*yyvsp), + &yystacksize); + yyss = yyss1; + yyvs = yyvs1; + } +# else /* defined YYSTACK_RELOCATE */ + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yy_state_t *yyss1 = yyss; + union yyalloc *yyptr = + YY_CAST (union yyalloc *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF ((stderr, "Stack size increased to %ld\n", + YY_CAST (long, yystacksize))); + YY_IGNORE_USELESS_CAST_END + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token\n")); + yychar = yylex (&yylval, parseContext); + } + + if (yychar <= YYEOF) + { + yychar = YYEOF; + yytoken = YYSYMBOL_YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else if (yychar == YYerror) + { + /* The scanner already issued an error message, process directly + to error recovery. But do not keep the error token as + lookahead, it is too special and may lead us to an endless + loop in error recovery. */ + yychar = YYUNDEF; + yytoken = YYSYMBOL_YYerror; + goto yyerrlab1; + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + /* Discard the shifted token. */ + yychar = YYEMPTY; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: /* variable_identifier: IDENTIFIER */ +#line 392 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleVariable((yyvsp[0].lex).loc, (yyvsp[0].lex).symbol, (yyvsp[0].lex).string); + } +#line 5181 "MachineIndependent/glslang_tab.cpp" + break; + + case 3: /* primary_expression: variable_identifier */ +#line 398 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 5189 "MachineIndependent/glslang_tab.cpp" + break; + + case 4: /* primary_expression: LEFT_PAREN expression RIGHT_PAREN */ +#line 401 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); + if ((yyval.interm.intermTypedNode)->getAsConstantUnion()) + (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); + } +#line 5199 "MachineIndependent/glslang_tab.cpp" + break; + + case 5: /* primary_expression: FLOATCONSTANT */ +#line 406 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); + } +#line 5207 "MachineIndependent/glslang_tab.cpp" + break; + + case 6: /* primary_expression: INTCONSTANT */ +#line 409 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 5215 "MachineIndependent/glslang_tab.cpp" + break; + + case 7: /* primary_expression: UINTCONSTANT */ +#line 412 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 5224 "MachineIndependent/glslang_tab.cpp" + break; + + case 8: /* primary_expression: BOOLCONSTANT */ +#line 416 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); + } +#line 5232 "MachineIndependent/glslang_tab.cpp" + break; + + case 9: /* primary_expression: STRING_LITERAL */ +#line 420 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true); + } +#line 5240 "MachineIndependent/glslang_tab.cpp" + break; + + case 10: /* primary_expression: INT32CONSTANT */ +#line 423 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 5249 "MachineIndependent/glslang_tab.cpp" + break; + + case 11: /* primary_expression: UINT32CONSTANT */ +#line 427 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 5258 "MachineIndependent/glslang_tab.cpp" + break; + + case 12: /* primary_expression: INT64CONSTANT */ +#line 431 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i64, (yyvsp[0].lex).loc, true); + } +#line 5267 "MachineIndependent/glslang_tab.cpp" + break; + + case 13: /* primary_expression: UINT64CONSTANT */ +#line 435 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u64, (yyvsp[0].lex).loc, true); + } +#line 5276 "MachineIndependent/glslang_tab.cpp" + break; + + case 14: /* primary_expression: INT16CONSTANT */ +#line 439 "MachineIndependent/glslang.y" + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit integer literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((short)(yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 5285 "MachineIndependent/glslang_tab.cpp" + break; + + case 15: /* primary_expression: UINT16CONSTANT */ +#line 443 "MachineIndependent/glslang.y" + { + parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit unsigned integer literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((unsigned short)(yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 5294 "MachineIndependent/glslang_tab.cpp" + break; + + case 16: /* primary_expression: DOUBLECONSTANT */ +#line 447 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double literal"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtDouble, (yyvsp[0].lex).loc, true); + } +#line 5305 "MachineIndependent/glslang_tab.cpp" + break; + + case 17: /* primary_expression: FLOAT16CONSTANT */ +#line 453 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat16, (yyvsp[0].lex).loc, true); + } +#line 5314 "MachineIndependent/glslang_tab.cpp" + break; + + case 18: /* postfix_expression: primary_expression */ +#line 461 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 5322 "MachineIndependent/glslang_tab.cpp" + break; + + case 19: /* postfix_expression: postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET */ +#line 464 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBracketDereference((yyvsp[-2].lex).loc, (yyvsp[-3].interm.intermTypedNode), (yyvsp[-1].interm.intermTypedNode)); + } +#line 5330 "MachineIndependent/glslang_tab.cpp" + break; + + case 20: /* postfix_expression: function_call */ +#line 467 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 5338 "MachineIndependent/glslang_tab.cpp" + break; + + case 21: /* postfix_expression: postfix_expression DOT IDENTIFIER */ +#line 470 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleDotDereference((yyvsp[0].lex).loc, (yyvsp[-2].interm.intermTypedNode), *(yyvsp[0].lex).string); + } +#line 5346 "MachineIndependent/glslang_tab.cpp" + break; + + case 22: /* postfix_expression: postfix_expression INC_OP */ +#line 473 "MachineIndependent/glslang.y" + { + parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); + parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "++", (yyvsp[-1].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "++", EOpPostIncrement, (yyvsp[-1].interm.intermTypedNode)); + } +#line 5356 "MachineIndependent/glslang_tab.cpp" + break; + + case 23: /* postfix_expression: postfix_expression DEC_OP */ +#line 478 "MachineIndependent/glslang.y" + { + parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); + parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "--", (yyvsp[-1].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "--", EOpPostDecrement, (yyvsp[-1].interm.intermTypedNode)); + } +#line 5366 "MachineIndependent/glslang_tab.cpp" + break; + + case 24: /* integer_expression: expression */ +#line 486 "MachineIndependent/glslang.y" + { + parseContext.integerCheck((yyvsp[0].interm.intermTypedNode), "[]"); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 5375 "MachineIndependent/glslang_tab.cpp" + break; + + case 25: /* function_call: function_call_or_method */ +#line 493 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleFunctionCall((yyvsp[0].interm).loc, (yyvsp[0].interm).function, (yyvsp[0].interm).intermNode); + delete (yyvsp[0].interm).function; + } +#line 5384 "MachineIndependent/glslang_tab.cpp" + break; + + case 26: /* function_call_or_method: function_call_generic */ +#line 500 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[0].interm); + } +#line 5392 "MachineIndependent/glslang_tab.cpp" + break; + + case 27: /* function_call_generic: function_call_header_with_parameters RIGHT_PAREN */ +#line 506 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[-1].interm); + (yyval.interm).loc = (yyvsp[0].lex).loc; + } +#line 5401 "MachineIndependent/glslang_tab.cpp" + break; + + case 28: /* function_call_generic: function_call_header_no_parameters RIGHT_PAREN */ +#line 510 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[-1].interm); + (yyval.interm).loc = (yyvsp[0].lex).loc; + } +#line 5410 "MachineIndependent/glslang_tab.cpp" + break; + + case 29: /* function_call_header_no_parameters: function_call_header VOID */ +#line 517 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[-1].interm); + } +#line 5418 "MachineIndependent/glslang_tab.cpp" + break; + + case 30: /* function_call_header_no_parameters: function_call_header */ +#line 520 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[0].interm); + } +#line 5426 "MachineIndependent/glslang_tab.cpp" + break; + + case 31: /* function_call_header_with_parameters: function_call_header assignment_expression */ +#line 526 "MachineIndependent/glslang.y" + { + TParameter param = { 0, new TType }; + param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); + (yyvsp[-1].interm).function->addParameter(param); + (yyval.interm).function = (yyvsp[-1].interm).function; + (yyval.interm).intermNode = (yyvsp[0].interm.intermTypedNode); + } +#line 5438 "MachineIndependent/glslang_tab.cpp" + break; + + case 32: /* function_call_header_with_parameters: function_call_header_with_parameters COMMA assignment_expression */ +#line 533 "MachineIndependent/glslang.y" + { + TParameter param = { 0, new TType }; + param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); + (yyvsp[-2].interm).function->addParameter(param); + (yyval.interm).function = (yyvsp[-2].interm).function; + (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); + } +#line 5450 "MachineIndependent/glslang_tab.cpp" + break; + + case 33: /* function_call_header: function_identifier LEFT_PAREN */ +#line 543 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[-1].interm); + } +#line 5458 "MachineIndependent/glslang_tab.cpp" + break; + + case 34: /* function_identifier: type_specifier */ +#line 551 "MachineIndependent/glslang.y" + { + // Constructor + (yyval.interm).intermNode = 0; + (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); + } +#line 5468 "MachineIndependent/glslang_tab.cpp" + break; + + case 35: /* function_identifier: postfix_expression */ +#line 556 "MachineIndependent/glslang.y" + { + // + // Should be a method or subroutine call, but we haven't recognized the arguments yet. + // + (yyval.interm).function = 0; + (yyval.interm).intermNode = 0; + + TIntermMethod* method = (yyvsp[0].interm.intermTypedNode)->getAsMethodNode(); + if (method) { + (yyval.interm).function = new TFunction(&method->getMethodName(), TType(EbtInt), EOpArrayLength); + (yyval.interm).intermNode = method->getObject(); + } else { + TIntermSymbol* symbol = (yyvsp[0].interm.intermTypedNode)->getAsSymbolNode(); + if (symbol) { + parseContext.reservedErrorCheck(symbol->getLoc(), symbol->getName()); + TFunction *function = new TFunction(&symbol->getName(), TType(EbtVoid)); + (yyval.interm).function = function; + } else + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "function call, method, or subroutine call expected", "", ""); + } + + if ((yyval.interm).function == 0) { + // error recover + TString* empty = NewPoolTString(""); + (yyval.interm).function = new TFunction(empty, TType(EbtVoid), EOpNull); + } + } +#line 5500 "MachineIndependent/glslang_tab.cpp" + break; + + case 36: /* function_identifier: non_uniform_qualifier */ +#line 584 "MachineIndependent/glslang.y" + { + // Constructor + (yyval.interm).intermNode = 0; + (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); + } +#line 5510 "MachineIndependent/glslang_tab.cpp" + break; + + case 37: /* unary_expression: postfix_expression */ +#line 593 "MachineIndependent/glslang.y" + { + parseContext.variableCheck((yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + if (TIntermMethod* method = (yyvsp[0].interm.intermTypedNode)->getAsMethodNode()) + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "incomplete method syntax", method->getMethodName().c_str(), ""); + } +#line 5521 "MachineIndependent/glslang_tab.cpp" + break; + + case 38: /* unary_expression: INC_OP unary_expression */ +#line 599 "MachineIndependent/glslang.y" + { + parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "++", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "++", EOpPreIncrement, (yyvsp[0].interm.intermTypedNode)); + } +#line 5530 "MachineIndependent/glslang_tab.cpp" + break; + + case 39: /* unary_expression: DEC_OP unary_expression */ +#line 603 "MachineIndependent/glslang.y" + { + parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "--", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "--", EOpPreDecrement, (yyvsp[0].interm.intermTypedNode)); + } +#line 5539 "MachineIndependent/glslang_tab.cpp" + break; + + case 40: /* unary_expression: unary_operator unary_expression */ +#line 607 "MachineIndependent/glslang.y" + { + if ((yyvsp[-1].interm).op != EOpNull) { + char errorOp[2] = {0, 0}; + switch((yyvsp[-1].interm).op) { + case EOpNegative: errorOp[0] = '-'; break; + case EOpLogicalNot: errorOp[0] = '!'; break; + case EOpBitwiseNot: errorOp[0] = '~'; break; + default: break; // some compilers want this + } + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].interm).loc, errorOp, (yyvsp[-1].interm).op, (yyvsp[0].interm.intermTypedNode)); + } else { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + if ((yyval.interm.intermTypedNode)->getAsConstantUnion()) + (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); + } + } +#line 5560 "MachineIndependent/glslang_tab.cpp" + break; + + case 41: /* unary_operator: PLUS */ +#line 627 "MachineIndependent/glslang.y" + { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNull; } +#line 5566 "MachineIndependent/glslang_tab.cpp" + break; + + case 42: /* unary_operator: DASH */ +#line 628 "MachineIndependent/glslang.y" + { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNegative; } +#line 5572 "MachineIndependent/glslang_tab.cpp" + break; + + case 43: /* unary_operator: BANG */ +#line 629 "MachineIndependent/glslang.y" + { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLogicalNot; } +#line 5578 "MachineIndependent/glslang_tab.cpp" + break; + + case 44: /* unary_operator: TILDE */ +#line 630 "MachineIndependent/glslang.y" + { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpBitwiseNot; + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise not"); } +#line 5585 "MachineIndependent/glslang_tab.cpp" + break; + + case 45: /* multiplicative_expression: unary_expression */ +#line 636 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5591 "MachineIndependent/glslang_tab.cpp" + break; + + case 46: /* multiplicative_expression: multiplicative_expression STAR unary_expression */ +#line 637 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "*", EOpMul, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5601 "MachineIndependent/glslang_tab.cpp" + break; + + case 47: /* multiplicative_expression: multiplicative_expression SLASH unary_expression */ +#line 642 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "/", EOpDiv, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5611 "MachineIndependent/glslang_tab.cpp" + break; + + case 48: /* multiplicative_expression: multiplicative_expression PERCENT unary_expression */ +#line 647 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "%"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "%", EOpMod, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5622 "MachineIndependent/glslang_tab.cpp" + break; + + case 49: /* additive_expression: multiplicative_expression */ +#line 656 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5628 "MachineIndependent/glslang_tab.cpp" + break; + + case 50: /* additive_expression: additive_expression PLUS multiplicative_expression */ +#line 657 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "+", EOpAdd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5638 "MachineIndependent/glslang_tab.cpp" + break; + + case 51: /* additive_expression: additive_expression DASH multiplicative_expression */ +#line 662 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "-", EOpSub, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5648 "MachineIndependent/glslang_tab.cpp" + break; + + case 52: /* shift_expression: additive_expression */ +#line 670 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5654 "MachineIndependent/glslang_tab.cpp" + break; + + case 53: /* shift_expression: shift_expression LEFT_OP additive_expression */ +#line 671 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift left"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<<", EOpLeftShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5665 "MachineIndependent/glslang_tab.cpp" + break; + + case 54: /* shift_expression: shift_expression RIGHT_OP additive_expression */ +#line 677 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift right"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">>", EOpRightShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5676 "MachineIndependent/glslang_tab.cpp" + break; + + case 55: /* relational_expression: shift_expression */ +#line 686 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5682 "MachineIndependent/glslang_tab.cpp" + break; + + case 56: /* relational_expression: relational_expression LEFT_ANGLE shift_expression */ +#line 687 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<", EOpLessThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5692 "MachineIndependent/glslang_tab.cpp" + break; + + case 57: /* relational_expression: relational_expression RIGHT_ANGLE shift_expression */ +#line 692 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">", EOpGreaterThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5702 "MachineIndependent/glslang_tab.cpp" + break; + + case 58: /* relational_expression: relational_expression LE_OP shift_expression */ +#line 697 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<=", EOpLessThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5712 "MachineIndependent/glslang_tab.cpp" + break; + + case 59: /* relational_expression: relational_expression GE_OP shift_expression */ +#line 702 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">=", EOpGreaterThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5722 "MachineIndependent/glslang_tab.cpp" + break; + + case 60: /* equality_expression: relational_expression */ +#line 710 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5728 "MachineIndependent/glslang_tab.cpp" + break; + + case 61: /* equality_expression: equality_expression EQ_OP relational_expression */ +#line 711 "MachineIndependent/glslang.y" + { + parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); + parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); + parseContext.specializationCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); + parseContext.referenceCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "==", EOpEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5742 "MachineIndependent/glslang_tab.cpp" + break; + + case 62: /* equality_expression: equality_expression NE_OP relational_expression */ +#line 720 "MachineIndependent/glslang.y" + { + parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); + parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); + parseContext.specializationCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); + parseContext.referenceCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "!=", EOpNotEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5756 "MachineIndependent/glslang_tab.cpp" + break; + + case 63: /* and_expression: equality_expression */ +#line 732 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5762 "MachineIndependent/glslang_tab.cpp" + break; + + case 64: /* and_expression: and_expression AMPERSAND equality_expression */ +#line 733 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise and"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&", EOpAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5773 "MachineIndependent/glslang_tab.cpp" + break; + + case 65: /* exclusive_or_expression: and_expression */ +#line 742 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5779 "MachineIndependent/glslang_tab.cpp" + break; + + case 66: /* exclusive_or_expression: exclusive_or_expression CARET and_expression */ +#line 743 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise exclusive or"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^", EOpExclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5790 "MachineIndependent/glslang_tab.cpp" + break; + + case 67: /* inclusive_or_expression: exclusive_or_expression */ +#line 752 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5796 "MachineIndependent/glslang_tab.cpp" + break; + + case 68: /* inclusive_or_expression: inclusive_or_expression VERTICAL_BAR exclusive_or_expression */ +#line 753 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise inclusive or"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "|", EOpInclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5807 "MachineIndependent/glslang_tab.cpp" + break; + + case 69: /* logical_and_expression: inclusive_or_expression */ +#line 762 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5813 "MachineIndependent/glslang_tab.cpp" + break; + + case 70: /* logical_and_expression: logical_and_expression AND_OP inclusive_or_expression */ +#line 763 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&&", EOpLogicalAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5823 "MachineIndependent/glslang_tab.cpp" + break; + + case 71: /* logical_xor_expression: logical_and_expression */ +#line 771 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5829 "MachineIndependent/glslang_tab.cpp" + break; + + case 72: /* logical_xor_expression: logical_xor_expression XOR_OP logical_and_expression */ +#line 772 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^^", EOpLogicalXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5839 "MachineIndependent/glslang_tab.cpp" + break; + + case 73: /* logical_or_expression: logical_xor_expression */ +#line 780 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5845 "MachineIndependent/glslang_tab.cpp" + break; + + case 74: /* logical_or_expression: logical_or_expression OR_OP logical_xor_expression */ +#line 781 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "||", EOpLogicalOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 5855 "MachineIndependent/glslang_tab.cpp" + break; + + case 75: /* conditional_expression: logical_or_expression */ +#line 789 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5861 "MachineIndependent/glslang_tab.cpp" + break; + + case 76: /* $@1: %empty */ +#line 790 "MachineIndependent/glslang.y" + { + ++parseContext.controlFlowNestingLevel; + } +#line 5869 "MachineIndependent/glslang_tab.cpp" + break; + + case 77: /* conditional_expression: logical_or_expression QUESTION $@1 expression COLON assignment_expression */ +#line 793 "MachineIndependent/glslang.y" + { + --parseContext.controlFlowNestingLevel; + parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-5].interm.intermTypedNode)); + parseContext.rValueErrorCheck((yyvsp[-4].lex).loc, "?", (yyvsp[-5].interm.intermTypedNode)); + parseContext.rValueErrorCheck((yyvsp[-1].lex).loc, ":", (yyvsp[-2].interm.intermTypedNode)); + parseContext.rValueErrorCheck((yyvsp[-1].lex).loc, ":", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addSelection((yyvsp[-5].interm.intermTypedNode), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-4].lex).loc); + if ((yyval.interm.intermTypedNode) == 0) { + parseContext.binaryOpError((yyvsp[-4].lex).loc, ":", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + } +#line 5886 "MachineIndependent/glslang_tab.cpp" + break; + + case 78: /* assignment_expression: conditional_expression */ +#line 808 "MachineIndependent/glslang.y" + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 5892 "MachineIndependent/glslang_tab.cpp" + break; + + case 79: /* assignment_expression: unary_expression assignment_operator assignment_expression */ +#line 809 "MachineIndependent/glslang.y" + { + parseContext.arrayObjectCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array assignment"); + parseContext.opaqueCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); + parseContext.storage16BitAssignmentCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); + parseContext.specializationCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); + parseContext.lValueErrorCheck((yyvsp[-1].interm).loc, "assign", (yyvsp[-2].interm.intermTypedNode)); + parseContext.rValueErrorCheck((yyvsp[-1].interm).loc, "assign", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.addAssign((yyvsp[-1].interm).loc, (yyvsp[-1].interm).op, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) { + parseContext.assignError((yyvsp[-1].interm).loc, "assign", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } + } +#line 5910 "MachineIndependent/glslang_tab.cpp" + break; + + case 80: /* assignment_operator: EQUAL */ +#line 825 "MachineIndependent/glslang.y" + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpAssign; + } +#line 5919 "MachineIndependent/glslang_tab.cpp" + break; + + case 81: /* assignment_operator: MUL_ASSIGN */ +#line 829 "MachineIndependent/glslang.y" + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpMulAssign; + } +#line 5928 "MachineIndependent/glslang_tab.cpp" + break; + + case 82: /* assignment_operator: DIV_ASSIGN */ +#line 833 "MachineIndependent/glslang.y" + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpDivAssign; + } +#line 5937 "MachineIndependent/glslang_tab.cpp" + break; + + case 83: /* assignment_operator: MOD_ASSIGN */ +#line 837 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "%="); + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpModAssign; + } +#line 5947 "MachineIndependent/glslang_tab.cpp" + break; + + case 84: /* assignment_operator: ADD_ASSIGN */ +#line 842 "MachineIndependent/glslang.y" + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpAddAssign; + } +#line 5956 "MachineIndependent/glslang_tab.cpp" + break; + + case 85: /* assignment_operator: SUB_ASSIGN */ +#line 846 "MachineIndependent/glslang.y" + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpSubAssign; + } +#line 5965 "MachineIndependent/glslang_tab.cpp" + break; + + case 86: /* assignment_operator: LEFT_ASSIGN */ +#line 850 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift left assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLeftShiftAssign; + } +#line 5974 "MachineIndependent/glslang_tab.cpp" + break; + + case 87: /* assignment_operator: RIGHT_ASSIGN */ +#line 854 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift right assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpRightShiftAssign; + } +#line 5983 "MachineIndependent/glslang_tab.cpp" + break; + + case 88: /* assignment_operator: AND_ASSIGN */ +#line 858 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-and assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAndAssign; + } +#line 5992 "MachineIndependent/glslang_tab.cpp" + break; + + case 89: /* assignment_operator: XOR_ASSIGN */ +#line 862 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-xor assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpExclusiveOrAssign; + } +#line 6001 "MachineIndependent/glslang_tab.cpp" + break; + + case 90: /* assignment_operator: OR_ASSIGN */ +#line 866 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-or assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpInclusiveOrAssign; + } +#line 6010 "MachineIndependent/glslang_tab.cpp" + break; + + case 91: /* expression: assignment_expression */ +#line 873 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 6018 "MachineIndependent/glslang_tab.cpp" + break; + + case 92: /* expression: expression COMMA assignment_expression */ +#line 876 "MachineIndependent/glslang.y" + { + parseContext.samplerConstructorLocationCheck((yyvsp[-1].lex).loc, ",", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); + if ((yyval.interm.intermTypedNode) == 0) { + parseContext.binaryOpError((yyvsp[-1].lex).loc, ",", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + } +#line 6031 "MachineIndependent/glslang_tab.cpp" + break; + + case 93: /* constant_expression: conditional_expression */ +#line 887 "MachineIndependent/glslang.y" + { + parseContext.constantValueCheck((yyvsp[0].interm.intermTypedNode), ""); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 6040 "MachineIndependent/glslang_tab.cpp" + break; + + case 94: /* declaration: function_prototype SEMICOLON */ +#line 894 "MachineIndependent/glslang.y" + { + parseContext.handleFunctionDeclarator((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).function, true /* prototype */); + (yyval.interm.intermNode) = 0; + // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature + } +#line 6050 "MachineIndependent/glslang_tab.cpp" + break; + + case 95: /* declaration: spirv_instruction_qualifier function_prototype SEMICOLON */ +#line 900 "MachineIndependent/glslang.y" + { + parseContext.requireExtensions((yyvsp[-1].interm).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V instruction qualifier"); + (yyvsp[-1].interm).function->setSpirvInstruction(*(yyvsp[-2].interm.spirvInst)); // Attach SPIR-V intruction qualifier + parseContext.handleFunctionDeclarator((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).function, true /* prototype */); + (yyval.interm.intermNode) = 0; + // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature + } +#line 6062 "MachineIndependent/glslang_tab.cpp" + break; + + case 96: /* declaration: spirv_execution_mode_qualifier SEMICOLON */ +#line 907 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "SPIR-V execution mode qualifier"); + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V execution mode qualifier"); + (yyval.interm.intermNode) = 0; + } +#line 6072 "MachineIndependent/glslang_tab.cpp" + break; + + case 97: /* declaration: init_declarator_list SEMICOLON */ +#line 913 "MachineIndependent/glslang.y" + { + if ((yyvsp[-1].interm).intermNode && (yyvsp[-1].interm).intermNode->getAsAggregate()) + (yyvsp[-1].interm).intermNode->getAsAggregate()->setOperator(EOpSequence); + (yyval.interm.intermNode) = (yyvsp[-1].interm).intermNode; + } +#line 6082 "MachineIndependent/glslang_tab.cpp" + break; + + case 98: /* declaration: PRECISION precision_qualifier type_specifier SEMICOLON */ +#line 918 "MachineIndependent/glslang.y" + { + parseContext.profileRequires((yyvsp[-3].lex).loc, ENoProfile, 130, 0, "precision statement"); + // lazy setting of the previous scope's defaults, has effect only the first time it is called in a particular scope + parseContext.symbolTable.setPreviousDefaultPrecisions(&parseContext.defaultPrecision[0]); + parseContext.setDefaultPrecision((yyvsp[-3].lex).loc, (yyvsp[-1].interm.type), (yyvsp[-2].interm.type).qualifier.precision); + (yyval.interm.intermNode) = 0; + } +#line 6094 "MachineIndependent/glslang_tab.cpp" + break; + + case 99: /* declaration: block_structure SEMICOLON */ +#line 925 "MachineIndependent/glslang.y" + { + parseContext.declareBlock((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).typeList); + (yyval.interm.intermNode) = 0; + } +#line 6103 "MachineIndependent/glslang_tab.cpp" + break; + + case 100: /* declaration: block_structure IDENTIFIER SEMICOLON */ +#line 929 "MachineIndependent/glslang.y" + { + parseContext.declareBlock((yyvsp[-2].interm).loc, *(yyvsp[-2].interm).typeList, (yyvsp[-1].lex).string); + (yyval.interm.intermNode) = 0; + } +#line 6112 "MachineIndependent/glslang_tab.cpp" + break; + + case 101: /* declaration: block_structure IDENTIFIER array_specifier SEMICOLON */ +#line 933 "MachineIndependent/glslang.y" + { + parseContext.declareBlock((yyvsp[-3].interm).loc, *(yyvsp[-3].interm).typeList, (yyvsp[-2].lex).string, (yyvsp[-1].interm).arraySizes); + (yyval.interm.intermNode) = 0; + } +#line 6121 "MachineIndependent/glslang_tab.cpp" + break; + + case 102: /* declaration: type_qualifier SEMICOLON */ +#line 937 "MachineIndependent/glslang.y" + { + parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); + parseContext.updateStandaloneQualifierDefaults((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type)); + (yyval.interm.intermNode) = 0; + } +#line 6131 "MachineIndependent/glslang_tab.cpp" + break; + + case 103: /* declaration: type_qualifier IDENTIFIER SEMICOLON */ +#line 942 "MachineIndependent/glslang.y" + { + parseContext.checkNoShaderLayouts((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).shaderQualifiers); + parseContext.addQualifierToExisting((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, *(yyvsp[-1].lex).string); + (yyval.interm.intermNode) = 0; + } +#line 6141 "MachineIndependent/glslang_tab.cpp" + break; + + case 104: /* declaration: type_qualifier IDENTIFIER identifier_list SEMICOLON */ +#line 947 "MachineIndependent/glslang.y" + { + parseContext.checkNoShaderLayouts((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).shaderQualifiers); + (yyvsp[-1].interm.identifierList)->push_back((yyvsp[-2].lex).string); + parseContext.addQualifierToExisting((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).qualifier, *(yyvsp[-1].interm.identifierList)); + (yyval.interm.intermNode) = 0; + } +#line 6152 "MachineIndependent/glslang_tab.cpp" + break; + + case 105: /* $@2: %empty */ +#line 956 "MachineIndependent/glslang.y" + { parseContext.nestedBlockCheck((yyvsp[-2].interm.type).loc); } +#line 6158 "MachineIndependent/glslang_tab.cpp" + break; + + case 106: /* block_structure: type_qualifier IDENTIFIER LEFT_BRACE $@2 struct_declaration_list RIGHT_BRACE */ +#line 956 "MachineIndependent/glslang.y" + { + --parseContext.blockNestingLevel; + parseContext.blockName = (yyvsp[-4].lex).string; + parseContext.globalQualifierFixCheck((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).qualifier); + parseContext.checkNoShaderLayouts((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).shaderQualifiers); + parseContext.currentBlockQualifier = (yyvsp[-5].interm.type).qualifier; + (yyval.interm).loc = (yyvsp[-5].interm.type).loc; + (yyval.interm).typeList = (yyvsp[-1].interm.typeList); + } +#line 6172 "MachineIndependent/glslang_tab.cpp" + break; + + case 107: /* identifier_list: COMMA IDENTIFIER */ +#line 967 "MachineIndependent/glslang.y" + { + (yyval.interm.identifierList) = new TIdentifierList; + (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); + } +#line 6181 "MachineIndependent/glslang_tab.cpp" + break; + + case 108: /* identifier_list: identifier_list COMMA IDENTIFIER */ +#line 971 "MachineIndependent/glslang.y" + { + (yyval.interm.identifierList) = (yyvsp[-2].interm.identifierList); + (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); + } +#line 6190 "MachineIndependent/glslang_tab.cpp" + break; + + case 109: /* function_prototype: function_declarator RIGHT_PAREN */ +#line 978 "MachineIndependent/glslang.y" + { + (yyval.interm).function = (yyvsp[-1].interm.function); + (yyval.interm).loc = (yyvsp[0].lex).loc; + } +#line 6199 "MachineIndependent/glslang_tab.cpp" + break; + + case 110: /* function_prototype: function_declarator RIGHT_PAREN attribute */ +#line 982 "MachineIndependent/glslang.y" + { + (yyval.interm).function = (yyvsp[-2].interm.function); + (yyval.interm).loc = (yyvsp[-1].lex).loc; + parseContext.requireExtensions((yyvsp[-1].lex).loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes((yyvsp[-1].lex).loc, *(yyvsp[0].interm.attributes), (yyval.interm).function); + } +#line 6210 "MachineIndependent/glslang_tab.cpp" + break; + + case 111: /* function_prototype: attribute function_declarator RIGHT_PAREN */ +#line 988 "MachineIndependent/glslang.y" + { + (yyval.interm).function = (yyvsp[-1].interm.function); + (yyval.interm).loc = (yyvsp[0].lex).loc; + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes((yyvsp[0].lex).loc, *(yyvsp[-2].interm.attributes), (yyval.interm).function); + } +#line 6221 "MachineIndependent/glslang_tab.cpp" + break; + + case 112: /* function_prototype: attribute function_declarator RIGHT_PAREN attribute */ +#line 994 "MachineIndependent/glslang.y" + { + (yyval.interm).function = (yyvsp[-2].interm.function); + (yyval.interm).loc = (yyvsp[-1].lex).loc; + parseContext.requireExtensions((yyvsp[-1].lex).loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + parseContext.handleFunctionAttributes((yyvsp[-1].lex).loc, *(yyvsp[-3].interm.attributes), (yyval.interm).function); + parseContext.handleFunctionAttributes((yyvsp[-1].lex).loc, *(yyvsp[0].interm.attributes), (yyval.interm).function); + } +#line 6233 "MachineIndependent/glslang_tab.cpp" + break; + + case 113: /* function_declarator: function_header */ +#line 1004 "MachineIndependent/glslang.y" + { + (yyval.interm.function) = (yyvsp[0].interm.function); + } +#line 6241 "MachineIndependent/glslang_tab.cpp" + break; + + case 114: /* function_declarator: function_header_with_parameters */ +#line 1007 "MachineIndependent/glslang.y" + { + (yyval.interm.function) = (yyvsp[0].interm.function); + } +#line 6249 "MachineIndependent/glslang_tab.cpp" + break; + + case 115: /* function_header_with_parameters: function_header parameter_declaration */ +#line 1014 "MachineIndependent/glslang.y" + { + // Add the parameter + (yyval.interm.function) = (yyvsp[-1].interm.function); + if ((yyvsp[0].interm).param.type->getBasicType() != EbtVoid) + (yyvsp[-1].interm.function)->addParameter((yyvsp[0].interm).param); + else + delete (yyvsp[0].interm).param.type; + } +#line 6262 "MachineIndependent/glslang_tab.cpp" + break; + + case 116: /* function_header_with_parameters: function_header_with_parameters COMMA parameter_declaration */ +#line 1022 "MachineIndependent/glslang.y" + { + // + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + // + if ((yyvsp[0].interm).param.type->getBasicType() == EbtVoid) { + // + // This parameter > first is void + // + parseContext.error((yyvsp[-1].lex).loc, "cannot be an argument type except for '(void)'", "void", ""); + delete (yyvsp[0].interm).param.type; + } else { + // Add the parameter + (yyval.interm.function) = (yyvsp[-2].interm.function); + (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm).param); + } + } +#line 6284 "MachineIndependent/glslang_tab.cpp" + break; + + case 117: /* function_header: fully_specified_type IDENTIFIER LEFT_PAREN */ +#line 1042 "MachineIndependent/glslang.y" + { + if ((yyvsp[-2].interm.type).qualifier.storage != EvqGlobal && (yyvsp[-2].interm.type).qualifier.storage != EvqTemporary) { + parseContext.error((yyvsp[-1].lex).loc, "no qualifiers allowed for function return", + GetStorageQualifierString((yyvsp[-2].interm.type).qualifier.storage), ""); + } + if ((yyvsp[-2].interm.type).arraySizes) + parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); + + // Add the function as a prototype after parsing it (we do not support recursion) + TFunction *function; + TType type((yyvsp[-2].interm.type)); + + // Potentially rename shader entry point function. No-op most of the time. + parseContext.renameShaderFunction((yyvsp[-1].lex).string); + + // Make the function + function = new TFunction((yyvsp[-1].lex).string, type); + (yyval.interm.function) = function; + } +#line 6308 "MachineIndependent/glslang_tab.cpp" + break; + + case 118: /* parameter_declarator: type_specifier IDENTIFIER */ +#line 1065 "MachineIndependent/glslang.y" + { + if ((yyvsp[-1].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[-1].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[-1].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + parseContext.arraySizeRequiredCheck((yyvsp[-1].interm.type).loc, *(yyvsp[-1].interm.type).arraySizes); + } + if ((yyvsp[-1].interm.type).basicType == EbtVoid) { + parseContext.error((yyvsp[0].lex).loc, "illegal use of type 'void'", (yyvsp[0].lex).string->c_str(), ""); + } + parseContext.reservedErrorCheck((yyvsp[0].lex).loc, *(yyvsp[0].lex).string); + + TParameter param = {(yyvsp[0].lex).string, new TType((yyvsp[-1].interm.type))}; + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).param = param; + } +#line 6328 "MachineIndependent/glslang_tab.cpp" + break; + + case 119: /* parameter_declarator: type_specifier IDENTIFIER array_specifier */ +#line 1080 "MachineIndependent/glslang.y" + { + if ((yyvsp[-2].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); + } + TType* type = new TType((yyvsp[-2].interm.type)); + type->transferArraySizes((yyvsp[0].interm).arraySizes); + type->copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); + + parseContext.arrayOfArrayVersionCheck((yyvsp[-1].lex).loc, type->getArraySizes()); + parseContext.arraySizeRequiredCheck((yyvsp[0].interm).loc, *(yyvsp[0].interm).arraySizes); + parseContext.reservedErrorCheck((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string); + + TParameter param = { (yyvsp[-1].lex).string, type }; + + (yyval.interm).loc = (yyvsp[-1].lex).loc; + (yyval.interm).param = param; + } +#line 6352 "MachineIndependent/glslang_tab.cpp" + break; + + case 120: /* parameter_declaration: type_qualifier parameter_declarator */ +#line 1105 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[0].interm); + if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) + (yyval.interm).param.type->getQualifier().precision = (yyvsp[-1].interm.type).qualifier.precision; + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + + parseContext.checkNoShaderLayouts((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); + parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); + parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); + + } +#line 6368 "MachineIndependent/glslang_tab.cpp" + break; + + case 121: /* parameter_declaration: parameter_declarator */ +#line 1116 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[0].interm); + + parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); + parseContext.paramCheckFixStorage((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + } +#line 6380 "MachineIndependent/glslang_tab.cpp" + break; + + case 122: /* parameter_declaration: type_qualifier parameter_type_specifier */ +#line 1126 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[0].interm); + if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) + (yyval.interm).param.type->getQualifier().precision = (yyvsp[-1].interm.type).qualifier.precision; + parseContext.precisionQualifierCheck((yyvsp[-1].interm.type).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + + parseContext.checkNoShaderLayouts((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); + parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); + parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); + } +#line 6395 "MachineIndependent/glslang_tab.cpp" + break; + + case 123: /* parameter_declaration: parameter_type_specifier */ +#line 1136 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[0].interm); + + parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); + parseContext.paramCheckFixStorage((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + } +#line 6407 "MachineIndependent/glslang_tab.cpp" + break; + + case 124: /* parameter_type_specifier: type_specifier */ +#line 1146 "MachineIndependent/glslang.y" + { + TParameter param = { 0, new TType((yyvsp[0].interm.type)) }; + (yyval.interm).param = param; + if ((yyvsp[0].interm.type).arraySizes) + parseContext.arraySizeRequiredCheck((yyvsp[0].interm.type).loc, *(yyvsp[0].interm.type).arraySizes); + } +#line 6418 "MachineIndependent/glslang_tab.cpp" + break; + + case 125: /* init_declarator_list: single_declaration */ +#line 1155 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[0].interm); + } +#line 6426 "MachineIndependent/glslang_tab.cpp" + break; + + case 126: /* init_declarator_list: init_declarator_list COMMA IDENTIFIER */ +#line 1158 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[-2].interm); + parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-2].interm).type); + } +#line 6435 "MachineIndependent/glslang_tab.cpp" + break; + + case 127: /* init_declarator_list: init_declarator_list COMMA IDENTIFIER array_specifier */ +#line 1162 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[-3].interm); + parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-3].interm).type, (yyvsp[0].interm).arraySizes); + } +#line 6444 "MachineIndependent/glslang_tab.cpp" + break; + + case 128: /* init_declarator_list: init_declarator_list COMMA IDENTIFIER array_specifier EQUAL initializer */ +#line 1166 "MachineIndependent/glslang.y" + { + (yyval.interm).type = (yyvsp[-5].interm).type; + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-5].interm).type, (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-5].interm).intermNode, initNode, (yyvsp[-1].lex).loc); + } +#line 6454 "MachineIndependent/glslang_tab.cpp" + break; + + case 129: /* init_declarator_list: init_declarator_list COMMA IDENTIFIER EQUAL initializer */ +#line 1171 "MachineIndependent/glslang.y" + { + (yyval.interm).type = (yyvsp[-4].interm).type; + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-4].interm).type, 0, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-4].interm).intermNode, initNode, (yyvsp[-1].lex).loc); + } +#line 6464 "MachineIndependent/glslang_tab.cpp" + break; + + case 130: /* single_declaration: fully_specified_type */ +#line 1179 "MachineIndependent/glslang.y" + { + (yyval.interm).type = (yyvsp[0].interm.type); + (yyval.interm).intermNode = 0; + + parseContext.declareTypeDefaults((yyval.interm).loc, (yyval.interm).type); + + } +#line 6476 "MachineIndependent/glslang_tab.cpp" + break; + + case 131: /* single_declaration: fully_specified_type IDENTIFIER */ +#line 1186 "MachineIndependent/glslang.y" + { + (yyval.interm).type = (yyvsp[-1].interm.type); + (yyval.interm).intermNode = 0; + parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-1].interm.type)); + } +#line 6486 "MachineIndependent/glslang_tab.cpp" + break; + + case 132: /* single_declaration: fully_specified_type IDENTIFIER array_specifier */ +#line 1191 "MachineIndependent/glslang.y" + { + (yyval.interm).type = (yyvsp[-2].interm.type); + (yyval.interm).intermNode = 0; + parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-2].interm.type), (yyvsp[0].interm).arraySizes); + } +#line 6496 "MachineIndependent/glslang_tab.cpp" + break; + + case 133: /* single_declaration: fully_specified_type IDENTIFIER array_specifier EQUAL initializer */ +#line 1196 "MachineIndependent/glslang.y" + { + (yyval.interm).type = (yyvsp[-4].interm.type); + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-4].interm.type), (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); + } +#line 6506 "MachineIndependent/glslang_tab.cpp" + break; + + case 134: /* single_declaration: fully_specified_type IDENTIFIER EQUAL initializer */ +#line 1201 "MachineIndependent/glslang.y" + { + (yyval.interm).type = (yyvsp[-3].interm.type); + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), 0, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); + } +#line 6516 "MachineIndependent/glslang_tab.cpp" + break; + + case 135: /* fully_specified_type: type_specifier */ +#line 1210 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[0].interm.type); + + parseContext.globalQualifierTypeCheck((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier, (yyval.interm.type)); + if ((yyvsp[0].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[0].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[0].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + } + parseContext.precisionQualifierCheck((yyval.interm.type).loc, (yyval.interm.type).basicType, (yyval.interm.type).qualifier); + } +#line 6531 "MachineIndependent/glslang_tab.cpp" + break; + + case 136: /* fully_specified_type: type_qualifier type_specifier */ +#line 1220 "MachineIndependent/glslang.y" + { + parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); + parseContext.globalQualifierTypeCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, (yyvsp[0].interm.type)); + + if ((yyvsp[0].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[0].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[0].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + } + + if ((yyvsp[0].interm.type).arraySizes && parseContext.arrayQualifierError((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).qualifier)) + (yyvsp[0].interm.type).arraySizes = nullptr; + + parseContext.checkNoShaderLayouts((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); + (yyvsp[0].interm.type).shaderQualifiers.merge((yyvsp[-1].interm.type).shaderQualifiers); + parseContext.mergeQualifiers((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier, (yyvsp[-1].interm.type).qualifier, true); + parseContext.precisionQualifierCheck((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).basicType, (yyvsp[0].interm.type).qualifier); + + (yyval.interm.type) = (yyvsp[0].interm.type); + + if (! (yyval.interm.type).qualifier.isInterpolation() && + ((parseContext.language == EShLangVertex && (yyval.interm.type).qualifier.storage == EvqVaryingOut) || + (parseContext.language == EShLangFragment && (yyval.interm.type).qualifier.storage == EvqVaryingIn))) + (yyval.interm.type).qualifier.smooth = true; + } +#line 6560 "MachineIndependent/glslang_tab.cpp" + break; + + case 137: /* invariant_qualifier: INVARIANT */ +#line 1247 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "invariant"); + parseContext.profileRequires((yyval.interm.type).loc, ENoProfile, 120, 0, "invariant"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.invariant = true; + } +#line 6571 "MachineIndependent/glslang_tab.cpp" + break; + + case 138: /* interpolation_qualifier: SMOOTH */ +#line 1256 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "smooth"); + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "smooth"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "smooth"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.smooth = true; + } +#line 6583 "MachineIndependent/glslang_tab.cpp" + break; + + case 139: /* interpolation_qualifier: FLAT */ +#line 1263 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "flat"); + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "flat"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "flat"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.flat = true; + } +#line 6595 "MachineIndependent/glslang_tab.cpp" + break; + + case 140: /* interpolation_qualifier: NOPERSPECTIVE */ +#line 1271 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "noperspective"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 0, E_GL_NV_shader_noperspective_interpolation, "noperspective"); + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "noperspective"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.nopersp = true; + } +#line 6607 "MachineIndependent/glslang_tab.cpp" + break; + + case 141: /* interpolation_qualifier: EXPLICITINTERPAMD */ +#line 1278 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "__explicitInterpAMD"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECompatibilityProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.explicitInterp = true; + } +#line 6619 "MachineIndependent/glslang_tab.cpp" + break; + + case 142: /* interpolation_qualifier: PERVERTEXNV */ +#line 1285 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "pervertexNV"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 0, E_GL_NV_fragment_shader_barycentric, "fragment shader barycentric"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECompatibilityProfile, 0, E_GL_NV_fragment_shader_barycentric, "fragment shader barycentric"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 0, E_GL_NV_fragment_shader_barycentric, "fragment shader barycentric"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.pervertexNV = true; + } +#line 6632 "MachineIndependent/glslang_tab.cpp" + break; + + case 143: /* interpolation_qualifier: PERPRIMITIVENV */ +#line 1293 "MachineIndependent/glslang.y" + { + // No need for profile version or extension check. Shader stage already checks both. + parseContext.globalCheck((yyvsp[0].lex).loc, "perprimitiveNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangFragmentMask | EShLangMeshNVMask), "perprimitiveNV"); + // Fragment shader stage doesn't check for extension. So we explicitly add below extension check. + if (parseContext.language == EShLangFragment) + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_NV_mesh_shader, "perprimitiveNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.perPrimitiveNV = true; + } +#line 6647 "MachineIndependent/glslang_tab.cpp" + break; + + case 144: /* interpolation_qualifier: PERVIEWNV */ +#line 1303 "MachineIndependent/glslang.y" + { + // No need for profile version or extension check. Shader stage already checks both. + parseContext.globalCheck((yyvsp[0].lex).loc, "perviewNV"); + parseContext.requireStage((yyvsp[0].lex).loc, EShLangMeshNV, "perviewNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.perViewNV = true; + } +#line 6659 "MachineIndependent/glslang_tab.cpp" + break; + + case 145: /* interpolation_qualifier: PERTASKNV */ +#line 1310 "MachineIndependent/glslang.y" + { + // No need for profile version or extension check. Shader stage already checks both. + parseContext.globalCheck((yyvsp[0].lex).loc, "taskNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTaskNVMask | EShLangMeshNVMask), "taskNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.perTaskNV = true; + } +#line 6671 "MachineIndependent/glslang_tab.cpp" + break; + + case 146: /* layout_qualifier: LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN */ +#line 1321 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[-1].interm.type); + } +#line 6679 "MachineIndependent/glslang_tab.cpp" + break; + + case 147: /* layout_qualifier_id_list: layout_qualifier_id */ +#line 1327 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6687 "MachineIndependent/glslang_tab.cpp" + break; + + case 148: /* layout_qualifier_id_list: layout_qualifier_id_list COMMA layout_qualifier_id */ +#line 1330 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[-2].interm.type); + (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); + parseContext.mergeObjectLayoutQualifiers((yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); + } +#line 6697 "MachineIndependent/glslang_tab.cpp" + break; + + case 149: /* layout_qualifier_id: IDENTIFIER */ +#line 1337 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), *(yyvsp[0].lex).string); + } +#line 6706 "MachineIndependent/glslang_tab.cpp" + break; + + case 150: /* layout_qualifier_id: IDENTIFIER EQUAL constant_expression */ +#line 1341 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-2].lex).loc); + parseContext.setLayoutQualifier((yyvsp[-2].lex).loc, (yyval.interm.type), *(yyvsp[-2].lex).string, (yyvsp[0].interm.intermTypedNode)); + } +#line 6715 "MachineIndependent/glslang_tab.cpp" + break; + + case 151: /* layout_qualifier_id: SHARED */ +#line 1345 "MachineIndependent/glslang.y" + { // because "shared" is both an identifier and a keyword + (yyval.interm.type).init((yyvsp[0].lex).loc); + TString strShared("shared"); + parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), strShared); + } +#line 6725 "MachineIndependent/glslang_tab.cpp" + break; + + case 152: /* precise_qualifier: PRECISE */ +#line 1354 "MachineIndependent/glslang.y" + { + parseContext.profileRequires((yyval.interm.type).loc, ECoreProfile | ECompatibilityProfile, 400, E_GL_ARB_gpu_shader5, "precise"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, "precise"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.noContraction = true; + } +#line 6736 "MachineIndependent/glslang_tab.cpp" + break; + + case 153: /* type_qualifier: single_type_qualifier */ +#line 1364 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6744 "MachineIndependent/glslang_tab.cpp" + break; + + case 154: /* type_qualifier: type_qualifier single_type_qualifier */ +#line 1367 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[-1].interm.type); + if ((yyval.interm.type).basicType == EbtVoid) + (yyval.interm.type).basicType = (yyvsp[0].interm.type).basicType; + + (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); + parseContext.mergeQualifiers((yyval.interm.type).loc, (yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); + } +#line 6757 "MachineIndependent/glslang_tab.cpp" + break; + + case 155: /* single_type_qualifier: storage_qualifier */ +#line 1378 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6765 "MachineIndependent/glslang_tab.cpp" + break; + + case 156: /* single_type_qualifier: layout_qualifier */ +#line 1381 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6773 "MachineIndependent/glslang_tab.cpp" + break; + + case 157: /* single_type_qualifier: precision_qualifier */ +#line 1384 "MachineIndependent/glslang.y" + { + parseContext.checkPrecisionQualifier((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier.precision); + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6782 "MachineIndependent/glslang_tab.cpp" + break; + + case 158: /* single_type_qualifier: interpolation_qualifier */ +#line 1388 "MachineIndependent/glslang.y" + { + // allow inheritance of storage qualifier from block declaration + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6791 "MachineIndependent/glslang_tab.cpp" + break; + + case 159: /* single_type_qualifier: invariant_qualifier */ +#line 1392 "MachineIndependent/glslang.y" + { + // allow inheritance of storage qualifier from block declaration + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6800 "MachineIndependent/glslang_tab.cpp" + break; + + case 160: /* single_type_qualifier: precise_qualifier */ +#line 1397 "MachineIndependent/glslang.y" + { + // allow inheritance of storage qualifier from block declaration + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6809 "MachineIndependent/glslang_tab.cpp" + break; + + case 161: /* single_type_qualifier: non_uniform_qualifier */ +#line 1401 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6817 "MachineIndependent/glslang_tab.cpp" + break; + + case 162: /* single_type_qualifier: spirv_storage_class_qualifier */ +#line 1404 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].interm.type).loc, "spirv_storage_class"); + parseContext.requireExtensions((yyvsp[0].interm.type).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V storage class qualifier"); + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6827 "MachineIndependent/glslang_tab.cpp" + break; + + case 163: /* single_type_qualifier: spirv_decorate_qualifier */ +#line 1409 "MachineIndependent/glslang.y" + { + parseContext.requireExtensions((yyvsp[0].interm.type).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V decorate qualifier"); + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 6836 "MachineIndependent/glslang_tab.cpp" + break; + + case 164: /* single_type_qualifier: SPIRV_BY_REFERENCE */ +#line 1413 "MachineIndependent/glslang.y" + { + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_spirv_intrinsics, "spirv_by_reference"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.setSpirvByReference(); + } +#line 6846 "MachineIndependent/glslang_tab.cpp" + break; + + case 165: /* single_type_qualifier: SPIRV_LITERAL */ +#line 1418 "MachineIndependent/glslang.y" + { + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_spirv_intrinsics, "spirv_by_literal"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.setSpirvLiteral(); + } +#line 6856 "MachineIndependent/glslang_tab.cpp" + break; + + case 166: /* storage_qualifier: CONST */ +#line 1427 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqConst; // will later turn into EvqConstReadOnly, if the initializer is not constant + } +#line 6865 "MachineIndependent/glslang_tab.cpp" + break; + + case 167: /* storage_qualifier: INOUT */ +#line 1431 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "inout"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqInOut; + } +#line 6875 "MachineIndependent/glslang_tab.cpp" + break; + + case 168: /* storage_qualifier: IN */ +#line 1436 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "in"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + // whether this is a parameter "in" or a pipeline "in" will get sorted out a bit later + (yyval.interm.type).qualifier.storage = EvqIn; + } +#line 6886 "MachineIndependent/glslang_tab.cpp" + break; + + case 169: /* storage_qualifier: OUT */ +#line 1442 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "out"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + // whether this is a parameter "out" or a pipeline "out" will get sorted out a bit later + (yyval.interm.type).qualifier.storage = EvqOut; + } +#line 6897 "MachineIndependent/glslang_tab.cpp" + break; + + case 170: /* storage_qualifier: CENTROID */ +#line 1448 "MachineIndependent/glslang.y" + { + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 120, 0, "centroid"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "centroid"); + parseContext.globalCheck((yyvsp[0].lex).loc, "centroid"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.centroid = true; + } +#line 6909 "MachineIndependent/glslang_tab.cpp" + break; + + case 171: /* storage_qualifier: UNIFORM */ +#line 1455 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "uniform"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqUniform; + } +#line 6919 "MachineIndependent/glslang_tab.cpp" + break; + + case 172: /* storage_qualifier: SHARED */ +#line 1460 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "shared"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_compute_shader, "shared"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 310, 0, "shared"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangComputeMask | EShLangMeshNVMask | EShLangTaskNVMask), "shared"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqShared; + } +#line 6932 "MachineIndependent/glslang_tab.cpp" + break; + + case 173: /* storage_qualifier: BUFFER */ +#line 1468 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "buffer"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqBuffer; + } +#line 6942 "MachineIndependent/glslang_tab.cpp" + break; + + case 174: /* storage_qualifier: ATTRIBUTE */ +#line 1474 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangVertex, "attribute"); + parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "attribute"); + parseContext.checkDeprecated((yyvsp[0].lex).loc, ENoProfile, 130, "attribute"); + parseContext.requireNotRemoved((yyvsp[0].lex).loc, ECoreProfile, 420, "attribute"); + parseContext.requireNotRemoved((yyvsp[0].lex).loc, EEsProfile, 300, "attribute"); + + parseContext.globalCheck((yyvsp[0].lex).loc, "attribute"); + + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqVaryingIn; + } +#line 6959 "MachineIndependent/glslang_tab.cpp" + break; + + case 175: /* storage_qualifier: VARYING */ +#line 1486 "MachineIndependent/glslang.y" + { + parseContext.checkDeprecated((yyvsp[0].lex).loc, ENoProfile, 130, "varying"); + parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "varying"); + parseContext.requireNotRemoved((yyvsp[0].lex).loc, ECoreProfile, 420, "varying"); + parseContext.requireNotRemoved((yyvsp[0].lex).loc, EEsProfile, 300, "varying"); + + parseContext.globalCheck((yyvsp[0].lex).loc, "varying"); + + (yyval.interm.type).init((yyvsp[0].lex).loc); + if (parseContext.language == EShLangVertex) + (yyval.interm.type).qualifier.storage = EvqVaryingOut; + else + (yyval.interm.type).qualifier.storage = EvqVaryingIn; + } +#line 6978 "MachineIndependent/glslang_tab.cpp" + break; + + case 176: /* storage_qualifier: PATCH */ +#line 1500 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "patch"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTessControlMask | EShLangTessEvaluationMask), "patch"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.patch = true; + } +#line 6989 "MachineIndependent/glslang_tab.cpp" + break; + + case 177: /* storage_qualifier: SAMPLE */ +#line 1506 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "sample"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.sample = true; + } +#line 6999 "MachineIndependent/glslang_tab.cpp" + break; + + case 178: /* storage_qualifier: HITATTRNV */ +#line 1511 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "hitAttributeNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask + | EShLangAnyHitMask), "hitAttributeNV"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "hitAttributeNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqHitAttr; + } +#line 7012 "MachineIndependent/glslang_tab.cpp" + break; + + case 179: /* storage_qualifier: HITATTREXT */ +#line 1519 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "hitAttributeEXT"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask + | EShLangAnyHitMask), "hitAttributeEXT"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "hitAttributeNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqHitAttr; + } +#line 7025 "MachineIndependent/glslang_tab.cpp" + break; + + case 180: /* storage_qualifier: PAYLOADNV */ +#line 1527 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadNV"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "rayPayloadNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqPayload; + } +#line 7038 "MachineIndependent/glslang_tab.cpp" + break; + + case 181: /* storage_qualifier: PAYLOADEXT */ +#line 1535 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadEXT"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadEXT"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "rayPayloadEXT"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqPayload; + } +#line 7051 "MachineIndependent/glslang_tab.cpp" + break; + + case 182: /* storage_qualifier: PAYLOADINNV */ +#line 1543 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadInNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadInNV"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "rayPayloadInNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqPayloadIn; + } +#line 7064 "MachineIndependent/glslang_tab.cpp" + break; + + case 183: /* storage_qualifier: PAYLOADINEXT */ +#line 1551 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadInEXT"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangClosestHitMask | + EShLangAnyHitMask | EShLangMissMask), "rayPayloadInEXT"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "rayPayloadInEXT"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqPayloadIn; + } +#line 7077 "MachineIndependent/glslang_tab.cpp" + break; + + case 184: /* storage_qualifier: CALLDATANV */ +#line 1559 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | + EShLangClosestHitMask | EShLangMissMask | EShLangCallableMask), "callableDataNV"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "callableDataNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqCallableData; + } +#line 7090 "MachineIndependent/glslang_tab.cpp" + break; + + case 185: /* storage_qualifier: CALLDATAEXT */ +#line 1567 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataEXT"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | + EShLangClosestHitMask | EShLangMissMask | EShLangCallableMask), "callableDataEXT"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "callableDataEXT"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqCallableData; + } +#line 7103 "MachineIndependent/glslang_tab.cpp" + break; + + case 186: /* storage_qualifier: CALLDATAINNV */ +#line 1575 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataInNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInNV"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "callableDataInNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqCallableDataIn; + } +#line 7115 "MachineIndependent/glslang_tab.cpp" + break; + + case 187: /* storage_qualifier: CALLDATAINEXT */ +#line 1582 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataInEXT"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInEXT"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_EXT_ray_tracing, "callableDataInEXT"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqCallableDataIn; + } +#line 7127 "MachineIndependent/glslang_tab.cpp" + break; + + case 188: /* storage_qualifier: COHERENT */ +#line 1589 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.coherent = true; + } +#line 7136 "MachineIndependent/glslang_tab.cpp" + break; + + case 189: /* storage_qualifier: DEVICECOHERENT */ +#line 1593 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "devicecoherent"); + (yyval.interm.type).qualifier.devicecoherent = true; + } +#line 7146 "MachineIndependent/glslang_tab.cpp" + break; + + case 190: /* storage_qualifier: QUEUEFAMILYCOHERENT */ +#line 1598 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "queuefamilycoherent"); + (yyval.interm.type).qualifier.queuefamilycoherent = true; + } +#line 7156 "MachineIndependent/glslang_tab.cpp" + break; + + case 191: /* storage_qualifier: WORKGROUPCOHERENT */ +#line 1603 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "workgroupcoherent"); + (yyval.interm.type).qualifier.workgroupcoherent = true; + } +#line 7166 "MachineIndependent/glslang_tab.cpp" + break; + + case 192: /* storage_qualifier: SUBGROUPCOHERENT */ +#line 1608 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "subgroupcoherent"); + (yyval.interm.type).qualifier.subgroupcoherent = true; + } +#line 7176 "MachineIndependent/glslang_tab.cpp" + break; + + case 193: /* storage_qualifier: NONPRIVATE */ +#line 1613 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "nonprivate"); + (yyval.interm.type).qualifier.nonprivate = true; + } +#line 7186 "MachineIndependent/glslang_tab.cpp" + break; + + case 194: /* storage_qualifier: SHADERCALLCOHERENT */ +#line 1618 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_ray_tracing, "shadercallcoherent"); + (yyval.interm.type).qualifier.shadercallcoherent = true; + } +#line 7196 "MachineIndependent/glslang_tab.cpp" + break; + + case 195: /* storage_qualifier: VOLATILE */ +#line 1623 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.volatil = true; + } +#line 7205 "MachineIndependent/glslang_tab.cpp" + break; + + case 196: /* storage_qualifier: RESTRICT */ +#line 1627 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.restrict = true; + } +#line 7214 "MachineIndependent/glslang_tab.cpp" + break; + + case 197: /* storage_qualifier: READONLY */ +#line 1631 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.readonly = true; + } +#line 7223 "MachineIndependent/glslang_tab.cpp" + break; + + case 198: /* storage_qualifier: WRITEONLY */ +#line 1635 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.writeonly = true; + } +#line 7232 "MachineIndependent/glslang_tab.cpp" + break; + + case 199: /* storage_qualifier: SUBROUTINE */ +#line 1639 "MachineIndependent/glslang.y" + { + parseContext.spvRemoved((yyvsp[0].lex).loc, "subroutine"); + parseContext.globalCheck((yyvsp[0].lex).loc, "subroutine"); + parseContext.unimplemented((yyvsp[0].lex).loc, "subroutine"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + } +#line 7243 "MachineIndependent/glslang_tab.cpp" + break; + + case 200: /* storage_qualifier: SUBROUTINE LEFT_PAREN type_name_list RIGHT_PAREN */ +#line 1645 "MachineIndependent/glslang.y" + { + parseContext.spvRemoved((yyvsp[-3].lex).loc, "subroutine"); + parseContext.globalCheck((yyvsp[-3].lex).loc, "subroutine"); + parseContext.unimplemented((yyvsp[-3].lex).loc, "subroutine"); + (yyval.interm.type).init((yyvsp[-3].lex).loc); + } +#line 7254 "MachineIndependent/glslang_tab.cpp" + break; + + case 201: /* non_uniform_qualifier: NONUNIFORM */ +#line 1656 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.nonUniform = true; + } +#line 7263 "MachineIndependent/glslang_tab.cpp" + break; + + case 202: /* type_name_list: IDENTIFIER */ +#line 1663 "MachineIndependent/glslang.y" + { + // TODO + } +#line 7271 "MachineIndependent/glslang_tab.cpp" + break; + + case 203: /* type_name_list: type_name_list COMMA IDENTIFIER */ +#line 1666 "MachineIndependent/glslang.y" + { + // TODO: 4.0 semantics: subroutines + // 1) make sure each identifier is a type declared earlier with SUBROUTINE + // 2) save all of the identifiers for future comparison with the declared function + } +#line 7281 "MachineIndependent/glslang_tab.cpp" + break; + + case 204: /* type_specifier: type_specifier_nonarray type_parameter_specifier_opt */ +#line 1675 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[-1].interm.type); + (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); + (yyval.interm.type).typeParameters = (yyvsp[0].interm.typeParameters); + } +#line 7291 "MachineIndependent/glslang_tab.cpp" + break; + + case 205: /* type_specifier: type_specifier_nonarray type_parameter_specifier_opt array_specifier */ +#line 1680 "MachineIndependent/glslang.y" + { + parseContext.arrayOfArrayVersionCheck((yyvsp[0].interm).loc, (yyvsp[0].interm).arraySizes); + (yyval.interm.type) = (yyvsp[-2].interm.type); + (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); + (yyval.interm.type).typeParameters = (yyvsp[-1].interm.typeParameters); + (yyval.interm.type).arraySizes = (yyvsp[0].interm).arraySizes; + } +#line 7303 "MachineIndependent/glslang_tab.cpp" + break; + + case 206: /* array_specifier: LEFT_BRACKET RIGHT_BRACKET */ +#line 1690 "MachineIndependent/glslang.y" + { + (yyval.interm).loc = (yyvsp[-1].lex).loc; + (yyval.interm).arraySizes = new TArraySizes; + (yyval.interm).arraySizes->addInnerSize(); + } +#line 7313 "MachineIndependent/glslang_tab.cpp" + break; + + case 207: /* array_specifier: LEFT_BRACKET conditional_expression RIGHT_BRACKET */ +#line 1695 "MachineIndependent/glslang.y" + { + (yyval.interm).loc = (yyvsp[-2].lex).loc; + (yyval.interm).arraySizes = new TArraySizes; + + TArraySize size; + parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size, "array size"); + (yyval.interm).arraySizes->addInnerSize(size); + } +#line 7326 "MachineIndependent/glslang_tab.cpp" + break; + + case 208: /* array_specifier: array_specifier LEFT_BRACKET RIGHT_BRACKET */ +#line 1703 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[-2].interm); + (yyval.interm).arraySizes->addInnerSize(); + } +#line 7335 "MachineIndependent/glslang_tab.cpp" + break; + + case 209: /* array_specifier: array_specifier LEFT_BRACKET conditional_expression RIGHT_BRACKET */ +#line 1707 "MachineIndependent/glslang.y" + { + (yyval.interm) = (yyvsp[-3].interm); + + TArraySize size; + parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size, "array size"); + (yyval.interm).arraySizes->addInnerSize(size); + } +#line 7347 "MachineIndependent/glslang_tab.cpp" + break; + + case 210: /* type_parameter_specifier_opt: type_parameter_specifier */ +#line 1717 "MachineIndependent/glslang.y" + { + (yyval.interm.typeParameters) = (yyvsp[0].interm.typeParameters); + } +#line 7355 "MachineIndependent/glslang_tab.cpp" + break; + + case 211: /* type_parameter_specifier_opt: %empty */ +#line 1720 "MachineIndependent/glslang.y" + { + (yyval.interm.typeParameters) = 0; + } +#line 7363 "MachineIndependent/glslang_tab.cpp" + break; + + case 212: /* type_parameter_specifier: LEFT_ANGLE type_parameter_specifier_list RIGHT_ANGLE */ +#line 1726 "MachineIndependent/glslang.y" + { + (yyval.interm.typeParameters) = (yyvsp[-1].interm.typeParameters); + } +#line 7371 "MachineIndependent/glslang_tab.cpp" + break; + + case 213: /* type_parameter_specifier_list: unary_expression */ +#line 1732 "MachineIndependent/glslang.y" + { + (yyval.interm.typeParameters) = new TArraySizes; + + TArraySize size; + parseContext.arraySizeCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode), size, "type parameter"); + (yyval.interm.typeParameters)->addInnerSize(size); + } +#line 7383 "MachineIndependent/glslang_tab.cpp" + break; + + case 214: /* type_parameter_specifier_list: type_parameter_specifier_list COMMA unary_expression */ +#line 1739 "MachineIndependent/glslang.y" + { + (yyval.interm.typeParameters) = (yyvsp[-2].interm.typeParameters); + + TArraySize size; + parseContext.arraySizeCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode), size, "type parameter"); + (yyval.interm.typeParameters)->addInnerSize(size); + } +#line 7395 "MachineIndependent/glslang_tab.cpp" + break; + + case 215: /* type_specifier_nonarray: VOID */ +#line 1749 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtVoid; + } +#line 7404 "MachineIndependent/glslang_tab.cpp" + break; + + case 216: /* type_specifier_nonarray: FLOAT */ +#line 1753 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + } +#line 7413 "MachineIndependent/glslang_tab.cpp" + break; + + case 217: /* type_specifier_nonarray: INT */ +#line 1757 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + } +#line 7422 "MachineIndependent/glslang_tab.cpp" + break; + + case 218: /* type_specifier_nonarray: UINT */ +#line 1761 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + } +#line 7432 "MachineIndependent/glslang_tab.cpp" + break; + + case 219: /* type_specifier_nonarray: BOOL */ +#line 1766 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + } +#line 7441 "MachineIndependent/glslang_tab.cpp" + break; + + case 220: /* type_specifier_nonarray: VEC2 */ +#line 1770 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(2); + } +#line 7451 "MachineIndependent/glslang_tab.cpp" + break; + + case 221: /* type_specifier_nonarray: VEC3 */ +#line 1775 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(3); + } +#line 7461 "MachineIndependent/glslang_tab.cpp" + break; + + case 222: /* type_specifier_nonarray: VEC4 */ +#line 1780 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(4); + } +#line 7471 "MachineIndependent/glslang_tab.cpp" + break; + + case 223: /* type_specifier_nonarray: BVEC2 */ +#line 1785 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(2); + } +#line 7481 "MachineIndependent/glslang_tab.cpp" + break; + + case 224: /* type_specifier_nonarray: BVEC3 */ +#line 1790 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(3); + } +#line 7491 "MachineIndependent/glslang_tab.cpp" + break; + + case 225: /* type_specifier_nonarray: BVEC4 */ +#line 1795 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(4); + } +#line 7501 "MachineIndependent/glslang_tab.cpp" + break; + + case 226: /* type_specifier_nonarray: IVEC2 */ +#line 1800 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(2); + } +#line 7511 "MachineIndependent/glslang_tab.cpp" + break; + + case 227: /* type_specifier_nonarray: IVEC3 */ +#line 1805 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(3); + } +#line 7521 "MachineIndependent/glslang_tab.cpp" + break; + + case 228: /* type_specifier_nonarray: IVEC4 */ +#line 1810 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(4); + } +#line 7531 "MachineIndependent/glslang_tab.cpp" + break; + + case 229: /* type_specifier_nonarray: UVEC2 */ +#line 1815 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(2); + } +#line 7542 "MachineIndependent/glslang_tab.cpp" + break; + + case 230: /* type_specifier_nonarray: UVEC3 */ +#line 1821 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(3); + } +#line 7553 "MachineIndependent/glslang_tab.cpp" + break; + + case 231: /* type_specifier_nonarray: UVEC4 */ +#line 1827 "MachineIndependent/glslang.y" + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(4); + } +#line 7564 "MachineIndependent/glslang_tab.cpp" + break; + + case 232: /* type_specifier_nonarray: MAT2 */ +#line 1833 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 2); + } +#line 7574 "MachineIndependent/glslang_tab.cpp" + break; + + case 233: /* type_specifier_nonarray: MAT3 */ +#line 1838 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 3); + } +#line 7584 "MachineIndependent/glslang_tab.cpp" + break; + + case 234: /* type_specifier_nonarray: MAT4 */ +#line 1843 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 4); + } +#line 7594 "MachineIndependent/glslang_tab.cpp" + break; + + case 235: /* type_specifier_nonarray: MAT2X2 */ +#line 1848 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 2); + } +#line 7604 "MachineIndependent/glslang_tab.cpp" + break; + + case 236: /* type_specifier_nonarray: MAT2X3 */ +#line 1853 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 3); + } +#line 7614 "MachineIndependent/glslang_tab.cpp" + break; + + case 237: /* type_specifier_nonarray: MAT2X4 */ +#line 1858 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 4); + } +#line 7624 "MachineIndependent/glslang_tab.cpp" + break; + + case 238: /* type_specifier_nonarray: MAT3X2 */ +#line 1863 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 2); + } +#line 7634 "MachineIndependent/glslang_tab.cpp" + break; + + case 239: /* type_specifier_nonarray: MAT3X3 */ +#line 1868 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 3); + } +#line 7644 "MachineIndependent/glslang_tab.cpp" + break; + + case 240: /* type_specifier_nonarray: MAT3X4 */ +#line 1873 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 4); + } +#line 7654 "MachineIndependent/glslang_tab.cpp" + break; + + case 241: /* type_specifier_nonarray: MAT4X2 */ +#line 1878 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 2); + } +#line 7664 "MachineIndependent/glslang_tab.cpp" + break; + + case 242: /* type_specifier_nonarray: MAT4X3 */ +#line 1883 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 3); + } +#line 7674 "MachineIndependent/glslang_tab.cpp" + break; + + case 243: /* type_specifier_nonarray: MAT4X4 */ +#line 1888 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 4); + } +#line 7684 "MachineIndependent/glslang_tab.cpp" + break; + + case 244: /* type_specifier_nonarray: DOUBLE */ +#line 1894 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + } +#line 7696 "MachineIndependent/glslang_tab.cpp" + break; + + case 245: /* type_specifier_nonarray: FLOAT16_T */ +#line 1901 "MachineIndependent/glslang.y" + { + parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "float16_t", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + } +#line 7706 "MachineIndependent/glslang_tab.cpp" + break; + + case 246: /* type_specifier_nonarray: FLOAT32_T */ +#line 1906 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + } +#line 7716 "MachineIndependent/glslang_tab.cpp" + break; + + case 247: /* type_specifier_nonarray: FLOAT64_T */ +#line 1911 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + } +#line 7726 "MachineIndependent/glslang_tab.cpp" + break; + + case 248: /* type_specifier_nonarray: INT8_T */ +#line 1916 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + } +#line 7736 "MachineIndependent/glslang_tab.cpp" + break; + + case 249: /* type_specifier_nonarray: UINT8_T */ +#line 1921 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + } +#line 7746 "MachineIndependent/glslang_tab.cpp" + break; + + case 250: /* type_specifier_nonarray: INT16_T */ +#line 1926 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt16; + } +#line 7756 "MachineIndependent/glslang_tab.cpp" + break; + + case 251: /* type_specifier_nonarray: UINT16_T */ +#line 1931 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + } +#line 7766 "MachineIndependent/glslang_tab.cpp" + break; + + case 252: /* type_specifier_nonarray: INT32_T */ +#line 1936 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + } +#line 7776 "MachineIndependent/glslang_tab.cpp" + break; + + case 253: /* type_specifier_nonarray: UINT32_T */ +#line 1941 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + } +#line 7786 "MachineIndependent/glslang_tab.cpp" + break; + + case 254: /* type_specifier_nonarray: INT64_T */ +#line 1946 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt64; + } +#line 7796 "MachineIndependent/glslang_tab.cpp" + break; + + case 255: /* type_specifier_nonarray: UINT64_T */ +#line 1951 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint64; + } +#line 7806 "MachineIndependent/glslang_tab.cpp" + break; + + case 256: /* type_specifier_nonarray: DVEC2 */ +#line 1956 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(2); + } +#line 7819 "MachineIndependent/glslang_tab.cpp" + break; + + case 257: /* type_specifier_nonarray: DVEC3 */ +#line 1964 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(3); + } +#line 7832 "MachineIndependent/glslang_tab.cpp" + break; + + case 258: /* type_specifier_nonarray: DVEC4 */ +#line 1972 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(4); + } +#line 7845 "MachineIndependent/glslang_tab.cpp" + break; + + case 259: /* type_specifier_nonarray: F16VEC2 */ +#line 1980 "MachineIndependent/glslang.y" + { + parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(2); + } +#line 7856 "MachineIndependent/glslang_tab.cpp" + break; + + case 260: /* type_specifier_nonarray: F16VEC3 */ +#line 1986 "MachineIndependent/glslang.y" + { + parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(3); + } +#line 7867 "MachineIndependent/glslang_tab.cpp" + break; + + case 261: /* type_specifier_nonarray: F16VEC4 */ +#line 1992 "MachineIndependent/glslang.y" + { + parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(4); + } +#line 7878 "MachineIndependent/glslang_tab.cpp" + break; + + case 262: /* type_specifier_nonarray: F32VEC2 */ +#line 1998 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(2); + } +#line 7889 "MachineIndependent/glslang_tab.cpp" + break; + + case 263: /* type_specifier_nonarray: F32VEC3 */ +#line 2004 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(3); + } +#line 7900 "MachineIndependent/glslang_tab.cpp" + break; + + case 264: /* type_specifier_nonarray: F32VEC4 */ +#line 2010 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(4); + } +#line 7911 "MachineIndependent/glslang_tab.cpp" + break; + + case 265: /* type_specifier_nonarray: F64VEC2 */ +#line 2016 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(2); + } +#line 7922 "MachineIndependent/glslang_tab.cpp" + break; + + case 266: /* type_specifier_nonarray: F64VEC3 */ +#line 2022 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(3); + } +#line 7933 "MachineIndependent/glslang_tab.cpp" + break; + + case 267: /* type_specifier_nonarray: F64VEC4 */ +#line 2028 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(4); + } +#line 7944 "MachineIndependent/glslang_tab.cpp" + break; + + case 268: /* type_specifier_nonarray: I8VEC2 */ +#line 2034 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(2); + } +#line 7955 "MachineIndependent/glslang_tab.cpp" + break; + + case 269: /* type_specifier_nonarray: I8VEC3 */ +#line 2040 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(3); + } +#line 7966 "MachineIndependent/glslang_tab.cpp" + break; + + case 270: /* type_specifier_nonarray: I8VEC4 */ +#line 2046 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(4); + } +#line 7977 "MachineIndependent/glslang_tab.cpp" + break; + + case 271: /* type_specifier_nonarray: I16VEC2 */ +#line 2052 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt16; + (yyval.interm.type).setVector(2); + } +#line 7988 "MachineIndependent/glslang_tab.cpp" + break; + + case 272: /* type_specifier_nonarray: I16VEC3 */ +#line 2058 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt16; + (yyval.interm.type).setVector(3); + } +#line 7999 "MachineIndependent/glslang_tab.cpp" + break; + + case 273: /* type_specifier_nonarray: I16VEC4 */ +#line 2064 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt16; + (yyval.interm.type).setVector(4); + } +#line 8010 "MachineIndependent/glslang_tab.cpp" + break; + + case 274: /* type_specifier_nonarray: I32VEC2 */ +#line 2070 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(2); + } +#line 8021 "MachineIndependent/glslang_tab.cpp" + break; + + case 275: /* type_specifier_nonarray: I32VEC3 */ +#line 2076 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(3); + } +#line 8032 "MachineIndependent/glslang_tab.cpp" + break; + + case 276: /* type_specifier_nonarray: I32VEC4 */ +#line 2082 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(4); + } +#line 8043 "MachineIndependent/glslang_tab.cpp" + break; + + case 277: /* type_specifier_nonarray: I64VEC2 */ +#line 2088 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt64; + (yyval.interm.type).setVector(2); + } +#line 8054 "MachineIndependent/glslang_tab.cpp" + break; + + case 278: /* type_specifier_nonarray: I64VEC3 */ +#line 2094 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt64; + (yyval.interm.type).setVector(3); + } +#line 8065 "MachineIndependent/glslang_tab.cpp" + break; + + case 279: /* type_specifier_nonarray: I64VEC4 */ +#line 2100 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt64; + (yyval.interm.type).setVector(4); + } +#line 8076 "MachineIndependent/glslang_tab.cpp" + break; + + case 280: /* type_specifier_nonarray: U8VEC2 */ +#line 2106 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + (yyval.interm.type).setVector(2); + } +#line 8087 "MachineIndependent/glslang_tab.cpp" + break; + + case 281: /* type_specifier_nonarray: U8VEC3 */ +#line 2112 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + (yyval.interm.type).setVector(3); + } +#line 8098 "MachineIndependent/glslang_tab.cpp" + break; + + case 282: /* type_specifier_nonarray: U8VEC4 */ +#line 2118 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + (yyval.interm.type).setVector(4); + } +#line 8109 "MachineIndependent/glslang_tab.cpp" + break; + + case 283: /* type_specifier_nonarray: U16VEC2 */ +#line 2124 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(2); + } +#line 8120 "MachineIndependent/glslang_tab.cpp" + break; + + case 284: /* type_specifier_nonarray: U16VEC3 */ +#line 2130 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(3); + } +#line 8131 "MachineIndependent/glslang_tab.cpp" + break; + + case 285: /* type_specifier_nonarray: U16VEC4 */ +#line 2136 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(4); + } +#line 8142 "MachineIndependent/glslang_tab.cpp" + break; + + case 286: /* type_specifier_nonarray: U32VEC2 */ +#line 2142 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(2); + } +#line 8153 "MachineIndependent/glslang_tab.cpp" + break; + + case 287: /* type_specifier_nonarray: U32VEC3 */ +#line 2148 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(3); + } +#line 8164 "MachineIndependent/glslang_tab.cpp" + break; + + case 288: /* type_specifier_nonarray: U32VEC4 */ +#line 2154 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(4); + } +#line 8175 "MachineIndependent/glslang_tab.cpp" + break; + + case 289: /* type_specifier_nonarray: U64VEC2 */ +#line 2160 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint64; + (yyval.interm.type).setVector(2); + } +#line 8186 "MachineIndependent/glslang_tab.cpp" + break; + + case 290: /* type_specifier_nonarray: U64VEC3 */ +#line 2166 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint64; + (yyval.interm.type).setVector(3); + } +#line 8197 "MachineIndependent/glslang_tab.cpp" + break; + + case 291: /* type_specifier_nonarray: U64VEC4 */ +#line 2172 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint64; + (yyval.interm.type).setVector(4); + } +#line 8208 "MachineIndependent/glslang_tab.cpp" + break; + + case 292: /* type_specifier_nonarray: DMAT2 */ +#line 2178 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8221 "MachineIndependent/glslang_tab.cpp" + break; + + case 293: /* type_specifier_nonarray: DMAT3 */ +#line 2186 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8234 "MachineIndependent/glslang_tab.cpp" + break; + + case 294: /* type_specifier_nonarray: DMAT4 */ +#line 2194 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8247 "MachineIndependent/glslang_tab.cpp" + break; + + case 295: /* type_specifier_nonarray: DMAT2X2 */ +#line 2202 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8260 "MachineIndependent/glslang_tab.cpp" + break; + + case 296: /* type_specifier_nonarray: DMAT2X3 */ +#line 2210 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 3); + } +#line 8273 "MachineIndependent/glslang_tab.cpp" + break; + + case 297: /* type_specifier_nonarray: DMAT2X4 */ +#line 2218 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 4); + } +#line 8286 "MachineIndependent/glslang_tab.cpp" + break; + + case 298: /* type_specifier_nonarray: DMAT3X2 */ +#line 2226 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 2); + } +#line 8299 "MachineIndependent/glslang_tab.cpp" + break; + + case 299: /* type_specifier_nonarray: DMAT3X3 */ +#line 2234 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8312 "MachineIndependent/glslang_tab.cpp" + break; + + case 300: /* type_specifier_nonarray: DMAT3X4 */ +#line 2242 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 4); + } +#line 8325 "MachineIndependent/glslang_tab.cpp" + break; + + case 301: /* type_specifier_nonarray: DMAT4X2 */ +#line 2250 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 2); + } +#line 8338 "MachineIndependent/glslang_tab.cpp" + break; + + case 302: /* type_specifier_nonarray: DMAT4X3 */ +#line 2258 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 3); + } +#line 8351 "MachineIndependent/glslang_tab.cpp" + break; + + case 303: /* type_specifier_nonarray: DMAT4X4 */ +#line 2266 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8364 "MachineIndependent/glslang_tab.cpp" + break; + + case 304: /* type_specifier_nonarray: F16MAT2 */ +#line 2274 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8375 "MachineIndependent/glslang_tab.cpp" + break; + + case 305: /* type_specifier_nonarray: F16MAT3 */ +#line 2280 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8386 "MachineIndependent/glslang_tab.cpp" + break; + + case 306: /* type_specifier_nonarray: F16MAT4 */ +#line 2286 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8397 "MachineIndependent/glslang_tab.cpp" + break; + + case 307: /* type_specifier_nonarray: F16MAT2X2 */ +#line 2292 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8408 "MachineIndependent/glslang_tab.cpp" + break; + + case 308: /* type_specifier_nonarray: F16MAT2X3 */ +#line 2298 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 3); + } +#line 8419 "MachineIndependent/glslang_tab.cpp" + break; + + case 309: /* type_specifier_nonarray: F16MAT2X4 */ +#line 2304 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 4); + } +#line 8430 "MachineIndependent/glslang_tab.cpp" + break; + + case 310: /* type_specifier_nonarray: F16MAT3X2 */ +#line 2310 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 2); + } +#line 8441 "MachineIndependent/glslang_tab.cpp" + break; + + case 311: /* type_specifier_nonarray: F16MAT3X3 */ +#line 2316 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8452 "MachineIndependent/glslang_tab.cpp" + break; + + case 312: /* type_specifier_nonarray: F16MAT3X4 */ +#line 2322 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 4); + } +#line 8463 "MachineIndependent/glslang_tab.cpp" + break; + + case 313: /* type_specifier_nonarray: F16MAT4X2 */ +#line 2328 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 2); + } +#line 8474 "MachineIndependent/glslang_tab.cpp" + break; + + case 314: /* type_specifier_nonarray: F16MAT4X3 */ +#line 2334 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 3); + } +#line 8485 "MachineIndependent/glslang_tab.cpp" + break; + + case 315: /* type_specifier_nonarray: F16MAT4X4 */ +#line 2340 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8496 "MachineIndependent/glslang_tab.cpp" + break; + + case 316: /* type_specifier_nonarray: F32MAT2 */ +#line 2346 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8507 "MachineIndependent/glslang_tab.cpp" + break; + + case 317: /* type_specifier_nonarray: F32MAT3 */ +#line 2352 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8518 "MachineIndependent/glslang_tab.cpp" + break; + + case 318: /* type_specifier_nonarray: F32MAT4 */ +#line 2358 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8529 "MachineIndependent/glslang_tab.cpp" + break; + + case 319: /* type_specifier_nonarray: F32MAT2X2 */ +#line 2364 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8540 "MachineIndependent/glslang_tab.cpp" + break; + + case 320: /* type_specifier_nonarray: F32MAT2X3 */ +#line 2370 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 3); + } +#line 8551 "MachineIndependent/glslang_tab.cpp" + break; + + case 321: /* type_specifier_nonarray: F32MAT2X4 */ +#line 2376 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 4); + } +#line 8562 "MachineIndependent/glslang_tab.cpp" + break; + + case 322: /* type_specifier_nonarray: F32MAT3X2 */ +#line 2382 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 2); + } +#line 8573 "MachineIndependent/glslang_tab.cpp" + break; + + case 323: /* type_specifier_nonarray: F32MAT3X3 */ +#line 2388 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8584 "MachineIndependent/glslang_tab.cpp" + break; + + case 324: /* type_specifier_nonarray: F32MAT3X4 */ +#line 2394 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 4); + } +#line 8595 "MachineIndependent/glslang_tab.cpp" + break; + + case 325: /* type_specifier_nonarray: F32MAT4X2 */ +#line 2400 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 2); + } +#line 8606 "MachineIndependent/glslang_tab.cpp" + break; + + case 326: /* type_specifier_nonarray: F32MAT4X3 */ +#line 2406 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 3); + } +#line 8617 "MachineIndependent/glslang_tab.cpp" + break; + + case 327: /* type_specifier_nonarray: F32MAT4X4 */ +#line 2412 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8628 "MachineIndependent/glslang_tab.cpp" + break; + + case 328: /* type_specifier_nonarray: F64MAT2 */ +#line 2418 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8639 "MachineIndependent/glslang_tab.cpp" + break; + + case 329: /* type_specifier_nonarray: F64MAT3 */ +#line 2424 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8650 "MachineIndependent/glslang_tab.cpp" + break; + + case 330: /* type_specifier_nonarray: F64MAT4 */ +#line 2430 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8661 "MachineIndependent/glslang_tab.cpp" + break; + + case 331: /* type_specifier_nonarray: F64MAT2X2 */ +#line 2436 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8672 "MachineIndependent/glslang_tab.cpp" + break; + + case 332: /* type_specifier_nonarray: F64MAT2X3 */ +#line 2442 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 3); + } +#line 8683 "MachineIndependent/glslang_tab.cpp" + break; + + case 333: /* type_specifier_nonarray: F64MAT2X4 */ +#line 2448 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 4); + } +#line 8694 "MachineIndependent/glslang_tab.cpp" + break; + + case 334: /* type_specifier_nonarray: F64MAT3X2 */ +#line 2454 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 2); + } +#line 8705 "MachineIndependent/glslang_tab.cpp" + break; + + case 335: /* type_specifier_nonarray: F64MAT3X3 */ +#line 2460 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8716 "MachineIndependent/glslang_tab.cpp" + break; + + case 336: /* type_specifier_nonarray: F64MAT3X4 */ +#line 2466 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 4); + } +#line 8727 "MachineIndependent/glslang_tab.cpp" + break; + + case 337: /* type_specifier_nonarray: F64MAT4X2 */ +#line 2472 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 2); + } +#line 8738 "MachineIndependent/glslang_tab.cpp" + break; + + case 338: /* type_specifier_nonarray: F64MAT4X3 */ +#line 2478 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 3); + } +#line 8749 "MachineIndependent/glslang_tab.cpp" + break; + + case 339: /* type_specifier_nonarray: F64MAT4X4 */ +#line 2484 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8760 "MachineIndependent/glslang_tab.cpp" + break; + + case 340: /* type_specifier_nonarray: ACCSTRUCTNV */ +#line 2490 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtAccStruct; + } +#line 8769 "MachineIndependent/glslang_tab.cpp" + break; + + case 341: /* type_specifier_nonarray: ACCSTRUCTEXT */ +#line 2494 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtAccStruct; + } +#line 8778 "MachineIndependent/glslang_tab.cpp" + break; + + case 342: /* type_specifier_nonarray: RAYQUERYEXT */ +#line 2498 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtRayQuery; + } +#line 8787 "MachineIndependent/glslang_tab.cpp" + break; + + case 343: /* type_specifier_nonarray: ATOMIC_UINT */ +#line 2502 "MachineIndependent/glslang.y" + { + parseContext.vulkanRemoved((yyvsp[0].lex).loc, "atomic counter types"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtAtomicUint; + } +#line 8797 "MachineIndependent/glslang_tab.cpp" + break; + + case 344: /* type_specifier_nonarray: SAMPLER1D */ +#line 2507 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd1D); + } +#line 8807 "MachineIndependent/glslang_tab.cpp" + break; + + case 345: /* type_specifier_nonarray: SAMPLER2D */ +#line 2513 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D); + } +#line 8817 "MachineIndependent/glslang_tab.cpp" + break; + + case 346: /* type_specifier_nonarray: SAMPLER3D */ +#line 2518 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd3D); + } +#line 8827 "MachineIndependent/glslang_tab.cpp" + break; + + case 347: /* type_specifier_nonarray: SAMPLERCUBE */ +#line 2523 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdCube); + } +#line 8837 "MachineIndependent/glslang_tab.cpp" + break; + + case 348: /* type_specifier_nonarray: SAMPLER2DSHADOW */ +#line 2528 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, true); + } +#line 8847 "MachineIndependent/glslang_tab.cpp" + break; + + case 349: /* type_specifier_nonarray: SAMPLERCUBESHADOW */ +#line 2533 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdCube, false, true); + } +#line 8857 "MachineIndependent/glslang_tab.cpp" + break; + + case 350: /* type_specifier_nonarray: SAMPLER2DARRAY */ +#line 2538 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true); + } +#line 8867 "MachineIndependent/glslang_tab.cpp" + break; + + case 351: /* type_specifier_nonarray: SAMPLER2DARRAYSHADOW */ +#line 2543 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, true); + } +#line 8877 "MachineIndependent/glslang_tab.cpp" + break; + + case 352: /* type_specifier_nonarray: SAMPLER1DSHADOW */ +#line 2549 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd1D, false, true); + } +#line 8887 "MachineIndependent/glslang_tab.cpp" + break; + + case 353: /* type_specifier_nonarray: SAMPLER1DARRAY */ +#line 2554 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true); + } +#line 8897 "MachineIndependent/glslang_tab.cpp" + break; + + case 354: /* type_specifier_nonarray: SAMPLER1DARRAYSHADOW */ +#line 2559 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true, true); + } +#line 8907 "MachineIndependent/glslang_tab.cpp" + break; + + case 355: /* type_specifier_nonarray: SAMPLERCUBEARRAY */ +#line 2564 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true); + } +#line 8917 "MachineIndependent/glslang_tab.cpp" + break; + + case 356: /* type_specifier_nonarray: SAMPLERCUBEARRAYSHADOW */ +#line 2569 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true, true); + } +#line 8927 "MachineIndependent/glslang_tab.cpp" + break; + + case 357: /* type_specifier_nonarray: F16SAMPLER1D */ +#line 2574 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd1D); + } +#line 8938 "MachineIndependent/glslang_tab.cpp" + break; + + case 358: /* type_specifier_nonarray: F16SAMPLER2D */ +#line 2580 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D); + } +#line 8949 "MachineIndependent/glslang_tab.cpp" + break; + + case 359: /* type_specifier_nonarray: F16SAMPLER3D */ +#line 2586 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd3D); + } +#line 8960 "MachineIndependent/glslang_tab.cpp" + break; + + case 360: /* type_specifier_nonarray: F16SAMPLERCUBE */ +#line 2592 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdCube); + } +#line 8971 "MachineIndependent/glslang_tab.cpp" + break; + + case 361: /* type_specifier_nonarray: F16SAMPLER1DSHADOW */ +#line 2598 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, false, true); + } +#line 8982 "MachineIndependent/glslang_tab.cpp" + break; + + case 362: /* type_specifier_nonarray: F16SAMPLER2DSHADOW */ +#line 2604 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, false, true); + } +#line 8993 "MachineIndependent/glslang_tab.cpp" + break; + + case 363: /* type_specifier_nonarray: F16SAMPLERCUBESHADOW */ +#line 2610 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, false, true); + } +#line 9004 "MachineIndependent/glslang_tab.cpp" + break; + + case 364: /* type_specifier_nonarray: F16SAMPLER1DARRAY */ +#line 2616 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, true); + } +#line 9015 "MachineIndependent/glslang_tab.cpp" + break; + + case 365: /* type_specifier_nonarray: F16SAMPLER2DARRAY */ +#line 2622 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true); + } +#line 9026 "MachineIndependent/glslang_tab.cpp" + break; + + case 366: /* type_specifier_nonarray: F16SAMPLER1DARRAYSHADOW */ +#line 2628 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, true, true); + } +#line 9037 "MachineIndependent/glslang_tab.cpp" + break; + + case 367: /* type_specifier_nonarray: F16SAMPLER2DARRAYSHADOW */ +#line 2634 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true, true); + } +#line 9048 "MachineIndependent/glslang_tab.cpp" + break; + + case 368: /* type_specifier_nonarray: F16SAMPLERCUBEARRAY */ +#line 2640 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, true); + } +#line 9059 "MachineIndependent/glslang_tab.cpp" + break; + + case 369: /* type_specifier_nonarray: F16SAMPLERCUBEARRAYSHADOW */ +#line 2646 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, true, true); + } +#line 9070 "MachineIndependent/glslang_tab.cpp" + break; + + case 370: /* type_specifier_nonarray: ISAMPLER1D */ +#line 2652 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd1D); + } +#line 9080 "MachineIndependent/glslang_tab.cpp" + break; + + case 371: /* type_specifier_nonarray: ISAMPLER2D */ +#line 2658 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd2D); + } +#line 9090 "MachineIndependent/glslang_tab.cpp" + break; + + case 372: /* type_specifier_nonarray: ISAMPLER3D */ +#line 2663 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd3D); + } +#line 9100 "MachineIndependent/glslang_tab.cpp" + break; + + case 373: /* type_specifier_nonarray: ISAMPLERCUBE */ +#line 2668 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, EsdCube); + } +#line 9110 "MachineIndependent/glslang_tab.cpp" + break; + + case 374: /* type_specifier_nonarray: ISAMPLER2DARRAY */ +#line 2673 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd2D, true); + } +#line 9120 "MachineIndependent/glslang_tab.cpp" + break; + + case 375: /* type_specifier_nonarray: USAMPLER2D */ +#line 2678 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd2D); + } +#line 9130 "MachineIndependent/glslang_tab.cpp" + break; + + case 376: /* type_specifier_nonarray: USAMPLER3D */ +#line 2683 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd3D); + } +#line 9140 "MachineIndependent/glslang_tab.cpp" + break; + + case 377: /* type_specifier_nonarray: USAMPLERCUBE */ +#line 2688 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, EsdCube); + } +#line 9150 "MachineIndependent/glslang_tab.cpp" + break; + + case 378: /* type_specifier_nonarray: ISAMPLER1DARRAY */ +#line 2694 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd1D, true); + } +#line 9160 "MachineIndependent/glslang_tab.cpp" + break; + + case 379: /* type_specifier_nonarray: ISAMPLERCUBEARRAY */ +#line 2699 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, EsdCube, true); + } +#line 9170 "MachineIndependent/glslang_tab.cpp" + break; + + case 380: /* type_specifier_nonarray: USAMPLER1D */ +#line 2704 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd1D); + } +#line 9180 "MachineIndependent/glslang_tab.cpp" + break; + + case 381: /* type_specifier_nonarray: USAMPLER1DARRAY */ +#line 2709 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd1D, true); + } +#line 9190 "MachineIndependent/glslang_tab.cpp" + break; + + case 382: /* type_specifier_nonarray: USAMPLERCUBEARRAY */ +#line 2714 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, EsdCube, true); + } +#line 9200 "MachineIndependent/glslang_tab.cpp" + break; + + case 383: /* type_specifier_nonarray: TEXTURECUBEARRAY */ +#line 2719 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube, true); + } +#line 9210 "MachineIndependent/glslang_tab.cpp" + break; + + case 384: /* type_specifier_nonarray: ITEXTURECUBEARRAY */ +#line 2724 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube, true); + } +#line 9220 "MachineIndependent/glslang_tab.cpp" + break; + + case 385: /* type_specifier_nonarray: UTEXTURECUBEARRAY */ +#line 2729 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube, true); + } +#line 9230 "MachineIndependent/glslang_tab.cpp" + break; + + case 386: /* type_specifier_nonarray: USAMPLER2DARRAY */ +#line 2735 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd2D, true); + } +#line 9240 "MachineIndependent/glslang_tab.cpp" + break; + + case 387: /* type_specifier_nonarray: TEXTURE2D */ +#line 2740 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D); + } +#line 9250 "MachineIndependent/glslang_tab.cpp" + break; + + case 388: /* type_specifier_nonarray: TEXTURE3D */ +#line 2745 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, Esd3D); + } +#line 9260 "MachineIndependent/glslang_tab.cpp" + break; + + case 389: /* type_specifier_nonarray: TEXTURE2DARRAY */ +#line 2750 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true); + } +#line 9270 "MachineIndependent/glslang_tab.cpp" + break; + + case 390: /* type_specifier_nonarray: TEXTURECUBE */ +#line 2755 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube); + } +#line 9280 "MachineIndependent/glslang_tab.cpp" + break; + + case 391: /* type_specifier_nonarray: ITEXTURE2D */ +#line 2760 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D); + } +#line 9290 "MachineIndependent/glslang_tab.cpp" + break; + + case 392: /* type_specifier_nonarray: ITEXTURE3D */ +#line 2765 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, Esd3D); + } +#line 9300 "MachineIndependent/glslang_tab.cpp" + break; + + case 393: /* type_specifier_nonarray: ITEXTURECUBE */ +#line 2770 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube); + } +#line 9310 "MachineIndependent/glslang_tab.cpp" + break; + + case 394: /* type_specifier_nonarray: ITEXTURE2DARRAY */ +#line 2775 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true); + } +#line 9320 "MachineIndependent/glslang_tab.cpp" + break; + + case 395: /* type_specifier_nonarray: UTEXTURE2D */ +#line 2780 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D); + } +#line 9330 "MachineIndependent/glslang_tab.cpp" + break; + + case 396: /* type_specifier_nonarray: UTEXTURE3D */ +#line 2785 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, Esd3D); + } +#line 9340 "MachineIndependent/glslang_tab.cpp" + break; + + case 397: /* type_specifier_nonarray: UTEXTURECUBE */ +#line 2790 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube); + } +#line 9350 "MachineIndependent/glslang_tab.cpp" + break; + + case 398: /* type_specifier_nonarray: UTEXTURE2DARRAY */ +#line 2795 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true); + } +#line 9360 "MachineIndependent/glslang_tab.cpp" + break; + + case 399: /* type_specifier_nonarray: SAMPLER */ +#line 2800 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setPureSampler(false); + } +#line 9370 "MachineIndependent/glslang_tab.cpp" + break; + + case 400: /* type_specifier_nonarray: SAMPLERSHADOW */ +#line 2805 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setPureSampler(true); + } +#line 9380 "MachineIndependent/glslang_tab.cpp" + break; + + case 401: /* type_specifier_nonarray: SAMPLER2DRECT */ +#line 2811 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdRect); + } +#line 9390 "MachineIndependent/glslang_tab.cpp" + break; + + case 402: /* type_specifier_nonarray: SAMPLER2DRECTSHADOW */ +#line 2816 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdRect, false, true); + } +#line 9400 "MachineIndependent/glslang_tab.cpp" + break; + + case 403: /* type_specifier_nonarray: F16SAMPLER2DRECT */ +#line 2821 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdRect); + } +#line 9411 "MachineIndependent/glslang_tab.cpp" + break; + + case 404: /* type_specifier_nonarray: F16SAMPLER2DRECTSHADOW */ +#line 2827 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdRect, false, true); + } +#line 9422 "MachineIndependent/glslang_tab.cpp" + break; + + case 405: /* type_specifier_nonarray: ISAMPLER2DRECT */ +#line 2833 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, EsdRect); + } +#line 9432 "MachineIndependent/glslang_tab.cpp" + break; + + case 406: /* type_specifier_nonarray: USAMPLER2DRECT */ +#line 2838 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, EsdRect); + } +#line 9442 "MachineIndependent/glslang_tab.cpp" + break; + + case 407: /* type_specifier_nonarray: SAMPLERBUFFER */ +#line 2843 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdBuffer); + } +#line 9452 "MachineIndependent/glslang_tab.cpp" + break; + + case 408: /* type_specifier_nonarray: F16SAMPLERBUFFER */ +#line 2848 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, EsdBuffer); + } +#line 9463 "MachineIndependent/glslang_tab.cpp" + break; + + case 409: /* type_specifier_nonarray: ISAMPLERBUFFER */ +#line 2854 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, EsdBuffer); + } +#line 9473 "MachineIndependent/glslang_tab.cpp" + break; + + case 410: /* type_specifier_nonarray: USAMPLERBUFFER */ +#line 2859 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, EsdBuffer); + } +#line 9483 "MachineIndependent/glslang_tab.cpp" + break; + + case 411: /* type_specifier_nonarray: SAMPLER2DMS */ +#line 2864 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, false, true); + } +#line 9493 "MachineIndependent/glslang_tab.cpp" + break; + + case 412: /* type_specifier_nonarray: F16SAMPLER2DMS */ +#line 2869 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, false, false, true); + } +#line 9504 "MachineIndependent/glslang_tab.cpp" + break; + + case 413: /* type_specifier_nonarray: ISAMPLER2DMS */ +#line 2875 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd2D, false, false, true); + } +#line 9514 "MachineIndependent/glslang_tab.cpp" + break; + + case 414: /* type_specifier_nonarray: USAMPLER2DMS */ +#line 2880 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd2D, false, false, true); + } +#line 9524 "MachineIndependent/glslang_tab.cpp" + break; + + case 415: /* type_specifier_nonarray: SAMPLER2DMSARRAY */ +#line 2885 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, false, true); + } +#line 9534 "MachineIndependent/glslang_tab.cpp" + break; + + case 416: /* type_specifier_nonarray: F16SAMPLER2DMSARRAY */ +#line 2890 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true, false, true); + } +#line 9545 "MachineIndependent/glslang_tab.cpp" + break; + + case 417: /* type_specifier_nonarray: ISAMPLER2DMSARRAY */ +#line 2896 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd2D, true, false, true); + } +#line 9555 "MachineIndependent/glslang_tab.cpp" + break; + + case 418: /* type_specifier_nonarray: USAMPLER2DMSARRAY */ +#line 2901 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd2D, true, false, true); + } +#line 9565 "MachineIndependent/glslang_tab.cpp" + break; + + case 419: /* type_specifier_nonarray: TEXTURE1D */ +#line 2906 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D); + } +#line 9575 "MachineIndependent/glslang_tab.cpp" + break; + + case 420: /* type_specifier_nonarray: F16TEXTURE1D */ +#line 2911 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd1D); + } +#line 9586 "MachineIndependent/glslang_tab.cpp" + break; + + case 421: /* type_specifier_nonarray: F16TEXTURE2D */ +#line 2917 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D); + } +#line 9597 "MachineIndependent/glslang_tab.cpp" + break; + + case 422: /* type_specifier_nonarray: F16TEXTURE3D */ +#line 2923 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd3D); + } +#line 9608 "MachineIndependent/glslang_tab.cpp" + break; + + case 423: /* type_specifier_nonarray: F16TEXTURECUBE */ +#line 2929 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdCube); + } +#line 9619 "MachineIndependent/glslang_tab.cpp" + break; + + case 424: /* type_specifier_nonarray: TEXTURE1DARRAY */ +#line 2935 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D, true); + } +#line 9629 "MachineIndependent/glslang_tab.cpp" + break; + + case 425: /* type_specifier_nonarray: F16TEXTURE1DARRAY */ +#line 2940 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd1D, true); + } +#line 9640 "MachineIndependent/glslang_tab.cpp" + break; + + case 426: /* type_specifier_nonarray: F16TEXTURE2DARRAY */ +#line 2946 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, true); + } +#line 9651 "MachineIndependent/glslang_tab.cpp" + break; + + case 427: /* type_specifier_nonarray: F16TEXTURECUBEARRAY */ +#line 2952 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdCube, true); + } +#line 9662 "MachineIndependent/glslang_tab.cpp" + break; + + case 428: /* type_specifier_nonarray: ITEXTURE1D */ +#line 2958 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D); + } +#line 9672 "MachineIndependent/glslang_tab.cpp" + break; + + case 429: /* type_specifier_nonarray: ITEXTURE1DARRAY */ +#line 2963 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D, true); + } +#line 9682 "MachineIndependent/glslang_tab.cpp" + break; + + case 430: /* type_specifier_nonarray: UTEXTURE1D */ +#line 2968 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D); + } +#line 9692 "MachineIndependent/glslang_tab.cpp" + break; + + case 431: /* type_specifier_nonarray: UTEXTURE1DARRAY */ +#line 2973 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D, true); + } +#line 9702 "MachineIndependent/glslang_tab.cpp" + break; + + case 432: /* type_specifier_nonarray: TEXTURE2DRECT */ +#line 2978 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, EsdRect); + } +#line 9712 "MachineIndependent/glslang_tab.cpp" + break; + + case 433: /* type_specifier_nonarray: F16TEXTURE2DRECT */ +#line 2983 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdRect); + } +#line 9723 "MachineIndependent/glslang_tab.cpp" + break; + + case 434: /* type_specifier_nonarray: ITEXTURE2DRECT */ +#line 2989 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, EsdRect); + } +#line 9733 "MachineIndependent/glslang_tab.cpp" + break; + + case 435: /* type_specifier_nonarray: UTEXTURE2DRECT */ +#line 2994 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, EsdRect); + } +#line 9743 "MachineIndependent/glslang_tab.cpp" + break; + + case 436: /* type_specifier_nonarray: TEXTUREBUFFER */ +#line 2999 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, EsdBuffer); + } +#line 9753 "MachineIndependent/glslang_tab.cpp" + break; + + case 437: /* type_specifier_nonarray: F16TEXTUREBUFFER */ +#line 3004 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdBuffer); + } +#line 9764 "MachineIndependent/glslang_tab.cpp" + break; + + case 438: /* type_specifier_nonarray: ITEXTUREBUFFER */ +#line 3010 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, EsdBuffer); + } +#line 9774 "MachineIndependent/glslang_tab.cpp" + break; + + case 439: /* type_specifier_nonarray: UTEXTUREBUFFER */ +#line 3015 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, EsdBuffer); + } +#line 9784 "MachineIndependent/glslang_tab.cpp" + break; + + case 440: /* type_specifier_nonarray: TEXTURE2DMS */ +#line 3020 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, false, false, true); + } +#line 9794 "MachineIndependent/glslang_tab.cpp" + break; + + case 441: /* type_specifier_nonarray: F16TEXTURE2DMS */ +#line 3025 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, false, false, true); + } +#line 9805 "MachineIndependent/glslang_tab.cpp" + break; + + case 442: /* type_specifier_nonarray: ITEXTURE2DMS */ +#line 3031 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, false, false, true); + } +#line 9815 "MachineIndependent/glslang_tab.cpp" + break; + + case 443: /* type_specifier_nonarray: UTEXTURE2DMS */ +#line 3036 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, false, false, true); + } +#line 9825 "MachineIndependent/glslang_tab.cpp" + break; + + case 444: /* type_specifier_nonarray: TEXTURE2DMSARRAY */ +#line 3041 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true, false, true); + } +#line 9835 "MachineIndependent/glslang_tab.cpp" + break; + + case 445: /* type_specifier_nonarray: F16TEXTURE2DMSARRAY */ +#line 3046 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, true, false, true); + } +#line 9846 "MachineIndependent/glslang_tab.cpp" + break; + + case 446: /* type_specifier_nonarray: ITEXTURE2DMSARRAY */ +#line 3052 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true, false, true); + } +#line 9856 "MachineIndependent/glslang_tab.cpp" + break; + + case 447: /* type_specifier_nonarray: UTEXTURE2DMSARRAY */ +#line 3057 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true, false, true); + } +#line 9866 "MachineIndependent/glslang_tab.cpp" + break; + + case 448: /* type_specifier_nonarray: IMAGE1D */ +#line 3062 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D); + } +#line 9876 "MachineIndependent/glslang_tab.cpp" + break; + + case 449: /* type_specifier_nonarray: F16IMAGE1D */ +#line 3067 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd1D); + } +#line 9887 "MachineIndependent/glslang_tab.cpp" + break; + + case 450: /* type_specifier_nonarray: IIMAGE1D */ +#line 3073 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd1D); + } +#line 9897 "MachineIndependent/glslang_tab.cpp" + break; + + case 451: /* type_specifier_nonarray: UIMAGE1D */ +#line 3078 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd1D); + } +#line 9907 "MachineIndependent/glslang_tab.cpp" + break; + + case 452: /* type_specifier_nonarray: IMAGE2D */ +#line 3083 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D); + } +#line 9917 "MachineIndependent/glslang_tab.cpp" + break; + + case 453: /* type_specifier_nonarray: F16IMAGE2D */ +#line 3088 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D); + } +#line 9928 "MachineIndependent/glslang_tab.cpp" + break; + + case 454: /* type_specifier_nonarray: IIMAGE2D */ +#line 3094 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd2D); + } +#line 9938 "MachineIndependent/glslang_tab.cpp" + break; + + case 455: /* type_specifier_nonarray: UIMAGE2D */ +#line 3099 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd2D); + } +#line 9948 "MachineIndependent/glslang_tab.cpp" + break; + + case 456: /* type_specifier_nonarray: IMAGE3D */ +#line 3104 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd3D); + } +#line 9958 "MachineIndependent/glslang_tab.cpp" + break; + + case 457: /* type_specifier_nonarray: F16IMAGE3D */ +#line 3109 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd3D); + } +#line 9969 "MachineIndependent/glslang_tab.cpp" + break; + + case 458: /* type_specifier_nonarray: IIMAGE3D */ +#line 3115 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd3D); + } +#line 9979 "MachineIndependent/glslang_tab.cpp" + break; + + case 459: /* type_specifier_nonarray: UIMAGE3D */ +#line 3120 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd3D); + } +#line 9989 "MachineIndependent/glslang_tab.cpp" + break; + + case 460: /* type_specifier_nonarray: IMAGE2DRECT */ +#line 3125 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, EsdRect); + } +#line 9999 "MachineIndependent/glslang_tab.cpp" + break; + + case 461: /* type_specifier_nonarray: F16IMAGE2DRECT */ +#line 3130 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, EsdRect); + } +#line 10010 "MachineIndependent/glslang_tab.cpp" + break; + + case 462: /* type_specifier_nonarray: IIMAGE2DRECT */ +#line 3136 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, EsdRect); + } +#line 10020 "MachineIndependent/glslang_tab.cpp" + break; + + case 463: /* type_specifier_nonarray: UIMAGE2DRECT */ +#line 3141 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, EsdRect); + } +#line 10030 "MachineIndependent/glslang_tab.cpp" + break; + + case 464: /* type_specifier_nonarray: IMAGECUBE */ +#line 3146 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube); + } +#line 10040 "MachineIndependent/glslang_tab.cpp" + break; + + case 465: /* type_specifier_nonarray: F16IMAGECUBE */ +#line 3151 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, EsdCube); + } +#line 10051 "MachineIndependent/glslang_tab.cpp" + break; + + case 466: /* type_specifier_nonarray: IIMAGECUBE */ +#line 3157 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, EsdCube); + } +#line 10061 "MachineIndependent/glslang_tab.cpp" + break; + + case 467: /* type_specifier_nonarray: UIMAGECUBE */ +#line 3162 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, EsdCube); + } +#line 10071 "MachineIndependent/glslang_tab.cpp" + break; + + case 468: /* type_specifier_nonarray: IMAGEBUFFER */ +#line 3167 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, EsdBuffer); + } +#line 10081 "MachineIndependent/glslang_tab.cpp" + break; + + case 469: /* type_specifier_nonarray: F16IMAGEBUFFER */ +#line 3172 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, EsdBuffer); + } +#line 10092 "MachineIndependent/glslang_tab.cpp" + break; + + case 470: /* type_specifier_nonarray: IIMAGEBUFFER */ +#line 3178 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, EsdBuffer); + } +#line 10102 "MachineIndependent/glslang_tab.cpp" + break; + + case 471: /* type_specifier_nonarray: UIMAGEBUFFER */ +#line 3183 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, EsdBuffer); + } +#line 10112 "MachineIndependent/glslang_tab.cpp" + break; + + case 472: /* type_specifier_nonarray: IMAGE1DARRAY */ +#line 3188 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D, true); + } +#line 10122 "MachineIndependent/glslang_tab.cpp" + break; + + case 473: /* type_specifier_nonarray: F16IMAGE1DARRAY */ +#line 3193 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd1D, true); + } +#line 10133 "MachineIndependent/glslang_tab.cpp" + break; + + case 474: /* type_specifier_nonarray: IIMAGE1DARRAY */ +#line 3199 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd1D, true); + } +#line 10143 "MachineIndependent/glslang_tab.cpp" + break; + + case 475: /* type_specifier_nonarray: UIMAGE1DARRAY */ +#line 3204 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd1D, true); + } +#line 10153 "MachineIndependent/glslang_tab.cpp" + break; + + case 476: /* type_specifier_nonarray: IMAGE2DARRAY */ +#line 3209 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true); + } +#line 10163 "MachineIndependent/glslang_tab.cpp" + break; + + case 477: /* type_specifier_nonarray: F16IMAGE2DARRAY */ +#line 3214 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, true); + } +#line 10174 "MachineIndependent/glslang_tab.cpp" + break; + + case 478: /* type_specifier_nonarray: IIMAGE2DARRAY */ +#line 3220 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true); + } +#line 10184 "MachineIndependent/glslang_tab.cpp" + break; + + case 479: /* type_specifier_nonarray: UIMAGE2DARRAY */ +#line 3225 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true); + } +#line 10194 "MachineIndependent/glslang_tab.cpp" + break; + + case 480: /* type_specifier_nonarray: IMAGECUBEARRAY */ +#line 3230 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube, true); + } +#line 10204 "MachineIndependent/glslang_tab.cpp" + break; + + case 481: /* type_specifier_nonarray: F16IMAGECUBEARRAY */ +#line 3235 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, EsdCube, true); + } +#line 10215 "MachineIndependent/glslang_tab.cpp" + break; + + case 482: /* type_specifier_nonarray: IIMAGECUBEARRAY */ +#line 3241 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, EsdCube, true); + } +#line 10225 "MachineIndependent/glslang_tab.cpp" + break; + + case 483: /* type_specifier_nonarray: UIMAGECUBEARRAY */ +#line 3246 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, EsdCube, true); + } +#line 10235 "MachineIndependent/glslang_tab.cpp" + break; + + case 484: /* type_specifier_nonarray: IMAGE2DMS */ +#line 3251 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, false, false, true); + } +#line 10245 "MachineIndependent/glslang_tab.cpp" + break; + + case 485: /* type_specifier_nonarray: F16IMAGE2DMS */ +#line 3256 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, false, false, true); + } +#line 10256 "MachineIndependent/glslang_tab.cpp" + break; + + case 486: /* type_specifier_nonarray: IIMAGE2DMS */ +#line 3262 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, false, false, true); + } +#line 10266 "MachineIndependent/glslang_tab.cpp" + break; + + case 487: /* type_specifier_nonarray: UIMAGE2DMS */ +#line 3267 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, false, false, true); + } +#line 10276 "MachineIndependent/glslang_tab.cpp" + break; + + case 488: /* type_specifier_nonarray: IMAGE2DMSARRAY */ +#line 3272 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true, false, true); + } +#line 10286 "MachineIndependent/glslang_tab.cpp" + break; + + case 489: /* type_specifier_nonarray: F16IMAGE2DMSARRAY */ +#line 3277 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, true, false, true); + } +#line 10297 "MachineIndependent/glslang_tab.cpp" + break; + + case 490: /* type_specifier_nonarray: IIMAGE2DMSARRAY */ +#line 3283 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true, false, true); + } +#line 10307 "MachineIndependent/glslang_tab.cpp" + break; + + case 491: /* type_specifier_nonarray: UIMAGE2DMSARRAY */ +#line 3288 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true, false, true); + } +#line 10317 "MachineIndependent/glslang_tab.cpp" + break; + + case 492: /* type_specifier_nonarray: I64IMAGE1D */ +#line 3293 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, Esd1D); + } +#line 10327 "MachineIndependent/glslang_tab.cpp" + break; + + case 493: /* type_specifier_nonarray: U64IMAGE1D */ +#line 3298 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, Esd1D); + } +#line 10337 "MachineIndependent/glslang_tab.cpp" + break; + + case 494: /* type_specifier_nonarray: I64IMAGE2D */ +#line 3303 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, Esd2D); + } +#line 10347 "MachineIndependent/glslang_tab.cpp" + break; + + case 495: /* type_specifier_nonarray: U64IMAGE2D */ +#line 3308 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, Esd2D); + } +#line 10357 "MachineIndependent/glslang_tab.cpp" + break; + + case 496: /* type_specifier_nonarray: I64IMAGE3D */ +#line 3313 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, Esd3D); + } +#line 10367 "MachineIndependent/glslang_tab.cpp" + break; + + case 497: /* type_specifier_nonarray: U64IMAGE3D */ +#line 3318 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, Esd3D); + } +#line 10377 "MachineIndependent/glslang_tab.cpp" + break; + + case 498: /* type_specifier_nonarray: I64IMAGE2DRECT */ +#line 3323 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, EsdRect); + } +#line 10387 "MachineIndependent/glslang_tab.cpp" + break; + + case 499: /* type_specifier_nonarray: U64IMAGE2DRECT */ +#line 3328 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, EsdRect); + } +#line 10397 "MachineIndependent/glslang_tab.cpp" + break; + + case 500: /* type_specifier_nonarray: I64IMAGECUBE */ +#line 3333 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, EsdCube); + } +#line 10407 "MachineIndependent/glslang_tab.cpp" + break; + + case 501: /* type_specifier_nonarray: U64IMAGECUBE */ +#line 3338 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, EsdCube); + } +#line 10417 "MachineIndependent/glslang_tab.cpp" + break; + + case 502: /* type_specifier_nonarray: I64IMAGEBUFFER */ +#line 3343 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, EsdBuffer); + } +#line 10427 "MachineIndependent/glslang_tab.cpp" + break; + + case 503: /* type_specifier_nonarray: U64IMAGEBUFFER */ +#line 3348 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, EsdBuffer); + } +#line 10437 "MachineIndependent/glslang_tab.cpp" + break; + + case 504: /* type_specifier_nonarray: I64IMAGE1DARRAY */ +#line 3353 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, Esd1D, true); + } +#line 10447 "MachineIndependent/glslang_tab.cpp" + break; + + case 505: /* type_specifier_nonarray: U64IMAGE1DARRAY */ +#line 3358 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, Esd1D, true); + } +#line 10457 "MachineIndependent/glslang_tab.cpp" + break; + + case 506: /* type_specifier_nonarray: I64IMAGE2DARRAY */ +#line 3363 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, Esd2D, true); + } +#line 10467 "MachineIndependent/glslang_tab.cpp" + break; + + case 507: /* type_specifier_nonarray: U64IMAGE2DARRAY */ +#line 3368 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, Esd2D, true); + } +#line 10477 "MachineIndependent/glslang_tab.cpp" + break; + + case 508: /* type_specifier_nonarray: I64IMAGECUBEARRAY */ +#line 3373 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, EsdCube, true); + } +#line 10487 "MachineIndependent/glslang_tab.cpp" + break; + + case 509: /* type_specifier_nonarray: U64IMAGECUBEARRAY */ +#line 3378 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, EsdCube, true); + } +#line 10497 "MachineIndependent/glslang_tab.cpp" + break; + + case 510: /* type_specifier_nonarray: I64IMAGE2DMS */ +#line 3383 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, Esd2D, false, false, true); + } +#line 10507 "MachineIndependent/glslang_tab.cpp" + break; + + case 511: /* type_specifier_nonarray: U64IMAGE2DMS */ +#line 3388 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, Esd2D, false, false, true); + } +#line 10517 "MachineIndependent/glslang_tab.cpp" + break; + + case 512: /* type_specifier_nonarray: I64IMAGE2DMSARRAY */ +#line 3393 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt64, Esd2D, true, false, true); + } +#line 10527 "MachineIndependent/glslang_tab.cpp" + break; + + case 513: /* type_specifier_nonarray: U64IMAGE2DMSARRAY */ +#line 3398 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint64, Esd2D, true, false, true); + } +#line 10537 "MachineIndependent/glslang_tab.cpp" + break; + + case 514: /* type_specifier_nonarray: SAMPLEREXTERNALOES */ +#line 3403 "MachineIndependent/glslang.y" + { // GL_OES_EGL_image_external + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D); + (yyval.interm.type).sampler.external = true; + } +#line 10548 "MachineIndependent/glslang_tab.cpp" + break; + + case 515: /* type_specifier_nonarray: SAMPLEREXTERNAL2DY2YEXT */ +#line 3409 "MachineIndependent/glslang.y" + { // GL_EXT_YUV_target + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D); + (yyval.interm.type).sampler.yuv = true; + } +#line 10559 "MachineIndependent/glslang_tab.cpp" + break; + + case 516: /* type_specifier_nonarray: SUBPASSINPUT */ +#line 3415 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtFloat); + } +#line 10570 "MachineIndependent/glslang_tab.cpp" + break; + + case 517: /* type_specifier_nonarray: SUBPASSINPUTMS */ +#line 3421 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtFloat, true); + } +#line 10581 "MachineIndependent/glslang_tab.cpp" + break; + + case 518: /* type_specifier_nonarray: F16SUBPASSINPUT */ +#line 3427 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtFloat16); + } +#line 10593 "MachineIndependent/glslang_tab.cpp" + break; + + case 519: /* type_specifier_nonarray: F16SUBPASSINPUTMS */ +#line 3434 "MachineIndependent/glslang.y" + { + parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtFloat16, true); + } +#line 10605 "MachineIndependent/glslang_tab.cpp" + break; + + case 520: /* type_specifier_nonarray: ISUBPASSINPUT */ +#line 3441 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtInt); + } +#line 10616 "MachineIndependent/glslang_tab.cpp" + break; + + case 521: /* type_specifier_nonarray: ISUBPASSINPUTMS */ +#line 3447 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtInt, true); + } +#line 10627 "MachineIndependent/glslang_tab.cpp" + break; + + case 522: /* type_specifier_nonarray: USUBPASSINPUT */ +#line 3453 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtUint); + } +#line 10638 "MachineIndependent/glslang_tab.cpp" + break; + + case 523: /* type_specifier_nonarray: USUBPASSINPUTMS */ +#line 3459 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setSubpass(EbtUint, true); + } +#line 10649 "MachineIndependent/glslang_tab.cpp" + break; + + case 524: /* type_specifier_nonarray: FCOOPMATNV */ +#line 3465 "MachineIndependent/glslang.y" + { + parseContext.fcoopmatCheck((yyvsp[0].lex).loc, "fcoopmatNV", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).coopmat = true; + } +#line 10660 "MachineIndependent/glslang_tab.cpp" + break; + + case 525: /* type_specifier_nonarray: ICOOPMATNV */ +#line 3471 "MachineIndependent/glslang.y" + { + parseContext.intcoopmatCheck((yyvsp[0].lex).loc, "icoopmatNV", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).coopmat = true; + } +#line 10671 "MachineIndependent/glslang_tab.cpp" + break; + + case 526: /* type_specifier_nonarray: UCOOPMATNV */ +#line 3477 "MachineIndependent/glslang.y" + { + parseContext.intcoopmatCheck((yyvsp[0].lex).loc, "ucoopmatNV", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).coopmat = true; + } +#line 10682 "MachineIndependent/glslang_tab.cpp" + break; + + case 527: /* type_specifier_nonarray: spirv_type_specifier */ +#line 3483 "MachineIndependent/glslang.y" + { + parseContext.requireExtensions((yyvsp[0].interm.type).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V type specifier"); + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 10691 "MachineIndependent/glslang_tab.cpp" + break; + + case 528: /* type_specifier_nonarray: struct_specifier */ +#line 3488 "MachineIndependent/glslang.y" + { + (yyval.interm.type) = (yyvsp[0].interm.type); + (yyval.interm.type).qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + parseContext.structTypeCheck((yyval.interm.type).loc, (yyval.interm.type)); + } +#line 10701 "MachineIndependent/glslang_tab.cpp" + break; + + case 529: /* type_specifier_nonarray: TYPE_NAME */ +#line 3493 "MachineIndependent/glslang.y" + { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + if (const TVariable* variable = ((yyvsp[0].lex).symbol)->getAsVariable()) { + const TType& structure = variable->getType(); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtStruct; + (yyval.interm.type).userDef = &structure; + } else + parseContext.error((yyvsp[0].lex).loc, "expected type name", (yyvsp[0].lex).string->c_str(), ""); + } +#line 10719 "MachineIndependent/glslang_tab.cpp" + break; + + case 530: /* precision_qualifier: HIGH_PRECISION */ +#line 3509 "MachineIndependent/glslang.y" + { + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "highp precision qualifier"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqHigh); + } +#line 10729 "MachineIndependent/glslang_tab.cpp" + break; + + case 531: /* precision_qualifier: MEDIUM_PRECISION */ +#line 3514 "MachineIndependent/glslang.y" + { + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "mediump precision qualifier"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqMedium); + } +#line 10739 "MachineIndependent/glslang_tab.cpp" + break; + + case 532: /* precision_qualifier: LOW_PRECISION */ +#line 3519 "MachineIndependent/glslang.y" + { + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "lowp precision qualifier"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqLow); + } +#line 10749 "MachineIndependent/glslang_tab.cpp" + break; + + case 533: /* $@3: %empty */ +#line 3527 "MachineIndependent/glslang.y" + { parseContext.nestedStructCheck((yyvsp[-2].lex).loc); } +#line 10755 "MachineIndependent/glslang_tab.cpp" + break; + + case 534: /* struct_specifier: STRUCT IDENTIFIER LEFT_BRACE $@3 struct_declaration_list RIGHT_BRACE */ +#line 3527 "MachineIndependent/glslang.y" + { + TType* structure = new TType((yyvsp[-1].interm.typeList), *(yyvsp[-4].lex).string); + parseContext.structArrayCheck((yyvsp[-4].lex).loc, *structure); + TVariable* userTypeDef = new TVariable((yyvsp[-4].lex).string, *structure, true); + if (! parseContext.symbolTable.insert(*userTypeDef)) + parseContext.error((yyvsp[-4].lex).loc, "redefinition", (yyvsp[-4].lex).string->c_str(), "struct"); + (yyval.interm.type).init((yyvsp[-5].lex).loc); + (yyval.interm.type).basicType = EbtStruct; + (yyval.interm.type).userDef = structure; + --parseContext.structNestingLevel; + } +#line 10771 "MachineIndependent/glslang_tab.cpp" + break; + + case 535: /* $@4: %empty */ +#line 3538 "MachineIndependent/glslang.y" + { parseContext.nestedStructCheck((yyvsp[-1].lex).loc); } +#line 10777 "MachineIndependent/glslang_tab.cpp" + break; + + case 536: /* struct_specifier: STRUCT LEFT_BRACE $@4 struct_declaration_list RIGHT_BRACE */ +#line 3538 "MachineIndependent/glslang.y" + { + TType* structure = new TType((yyvsp[-1].interm.typeList), TString("")); + (yyval.interm.type).init((yyvsp[-4].lex).loc); + (yyval.interm.type).basicType = EbtStruct; + (yyval.interm.type).userDef = structure; + --parseContext.structNestingLevel; + } +#line 10789 "MachineIndependent/glslang_tab.cpp" + break; + + case 537: /* struct_declaration_list: struct_declaration */ +#line 3548 "MachineIndependent/glslang.y" + { + (yyval.interm.typeList) = (yyvsp[0].interm.typeList); + } +#line 10797 "MachineIndependent/glslang_tab.cpp" + break; + + case 538: /* struct_declaration_list: struct_declaration_list struct_declaration */ +#line 3551 "MachineIndependent/glslang.y" + { + (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); + for (unsigned int i = 0; i < (yyvsp[0].interm.typeList)->size(); ++i) { + for (unsigned int j = 0; j < (yyval.interm.typeList)->size(); ++j) { + if ((*(yyval.interm.typeList))[j].type->getFieldName() == (*(yyvsp[0].interm.typeList))[i].type->getFieldName()) + parseContext.error((*(yyvsp[0].interm.typeList))[i].loc, "duplicate member name:", "", (*(yyvsp[0].interm.typeList))[i].type->getFieldName().c_str()); + } + (yyval.interm.typeList)->push_back((*(yyvsp[0].interm.typeList))[i]); + } + } +#line 10812 "MachineIndependent/glslang_tab.cpp" + break; + + case 539: /* struct_declaration: type_specifier struct_declarator_list SEMICOLON */ +#line 3564 "MachineIndependent/glslang.y" + { + if ((yyvsp[-2].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + if (parseContext.isEsProfile()) + parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); + } + + (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); + + parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); + parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); + + for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { + TType type((yyvsp[-2].interm.type)); + type.setFieldName((*(yyval.interm.typeList))[i].type->getFieldName()); + type.transferArraySizes((*(yyval.interm.typeList))[i].type->getArraySizes()); + type.copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); + parseContext.arrayOfArrayVersionCheck((*(yyval.interm.typeList))[i].loc, type.getArraySizes()); + (*(yyval.interm.typeList))[i].type->shallowCopy(type); + } + } +#line 10839 "MachineIndependent/glslang_tab.cpp" + break; + + case 540: /* struct_declaration: type_qualifier type_specifier struct_declarator_list SEMICOLON */ +#line 3586 "MachineIndependent/glslang.y" + { + if ((yyvsp[-2].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + if (parseContext.isEsProfile()) + parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); + } + + (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); + + parseContext.memberQualifierCheck((yyvsp[-3].interm.type)); + parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); + parseContext.mergeQualifiers((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, (yyvsp[-3].interm.type).qualifier, true); + parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); + + for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { + TType type((yyvsp[-2].interm.type)); + type.setFieldName((*(yyval.interm.typeList))[i].type->getFieldName()); + type.transferArraySizes((*(yyval.interm.typeList))[i].type->getArraySizes()); + type.copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); + parseContext.arrayOfArrayVersionCheck((*(yyval.interm.typeList))[i].loc, type.getArraySizes()); + (*(yyval.interm.typeList))[i].type->shallowCopy(type); + } + } +#line 10868 "MachineIndependent/glslang_tab.cpp" + break; + + case 541: /* struct_declarator_list: struct_declarator */ +#line 3613 "MachineIndependent/glslang.y" + { + (yyval.interm.typeList) = new TTypeList; + (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); + } +#line 10877 "MachineIndependent/glslang_tab.cpp" + break; + + case 542: /* struct_declarator_list: struct_declarator_list COMMA struct_declarator */ +#line 3617 "MachineIndependent/glslang.y" + { + (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); + } +#line 10885 "MachineIndependent/glslang_tab.cpp" + break; + + case 543: /* struct_declarator: IDENTIFIER */ +#line 3623 "MachineIndependent/glslang.y" + { + (yyval.interm.typeLine).type = new TType(EbtVoid); + (yyval.interm.typeLine).loc = (yyvsp[0].lex).loc; + (yyval.interm.typeLine).type->setFieldName(*(yyvsp[0].lex).string); + } +#line 10895 "MachineIndependent/glslang_tab.cpp" + break; + + case 544: /* struct_declarator: IDENTIFIER array_specifier */ +#line 3628 "MachineIndependent/glslang.y" + { + parseContext.arrayOfArrayVersionCheck((yyvsp[-1].lex).loc, (yyvsp[0].interm).arraySizes); + + (yyval.interm.typeLine).type = new TType(EbtVoid); + (yyval.interm.typeLine).loc = (yyvsp[-1].lex).loc; + (yyval.interm.typeLine).type->setFieldName(*(yyvsp[-1].lex).string); + (yyval.interm.typeLine).type->transferArraySizes((yyvsp[0].interm).arraySizes); + } +#line 10908 "MachineIndependent/glslang_tab.cpp" + break; + + case 545: /* initializer: assignment_expression */ +#line 3639 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 10916 "MachineIndependent/glslang_tab.cpp" + break; + + case 546: /* initializer: LEFT_BRACE initializer_list RIGHT_BRACE */ +#line 3643 "MachineIndependent/glslang.y" + { + const char* initFeature = "{ } style initializers"; + parseContext.requireProfile((yyvsp[-2].lex).loc, ~EEsProfile, initFeature); + parseContext.profileRequires((yyvsp[-2].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); + (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); + } +#line 10927 "MachineIndependent/glslang_tab.cpp" + break; + + case 547: /* initializer: LEFT_BRACE initializer_list COMMA RIGHT_BRACE */ +#line 3649 "MachineIndependent/glslang.y" + { + const char* initFeature = "{ } style initializers"; + parseContext.requireProfile((yyvsp[-3].lex).loc, ~EEsProfile, initFeature); + parseContext.profileRequires((yyvsp[-3].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 10938 "MachineIndependent/glslang_tab.cpp" + break; + + case 548: /* initializer: LEFT_BRACE RIGHT_BRACE */ +#line 3655 "MachineIndependent/glslang.y" + { + const char* initFeature = "empty { } initializer"; + parseContext.profileRequires((yyvsp[-1].lex).loc, EEsProfile, 0, E_GL_EXT_null_initializer, initFeature); + parseContext.profileRequires((yyvsp[-1].lex).loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, initFeature); + (yyval.interm.intermTypedNode) = parseContext.intermediate.makeAggregate((yyvsp[-1].lex).loc); + } +#line 10949 "MachineIndependent/glslang_tab.cpp" + break; + + case 549: /* initializer_list: initializer */ +#line 3666 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate(0, (yyvsp[0].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)->getLoc()); + } +#line 10957 "MachineIndependent/glslang_tab.cpp" + break; + + case 550: /* initializer_list: initializer_list COMMA initializer */ +#line 3669 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + } +#line 10965 "MachineIndependent/glslang_tab.cpp" + break; + + case 551: /* declaration_statement: declaration */ +#line 3676 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 10971 "MachineIndependent/glslang_tab.cpp" + break; + + case 552: /* statement: compound_statement */ +#line 3680 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 10977 "MachineIndependent/glslang_tab.cpp" + break; + + case 553: /* statement: simple_statement */ +#line 3681 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 10983 "MachineIndependent/glslang_tab.cpp" + break; + + case 554: /* simple_statement: declaration_statement */ +#line 3687 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 10989 "MachineIndependent/glslang_tab.cpp" + break; + + case 555: /* simple_statement: expression_statement */ +#line 3688 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 10995 "MachineIndependent/glslang_tab.cpp" + break; + + case 556: /* simple_statement: selection_statement */ +#line 3689 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 11001 "MachineIndependent/glslang_tab.cpp" + break; + + case 557: /* simple_statement: switch_statement */ +#line 3690 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 11007 "MachineIndependent/glslang_tab.cpp" + break; + + case 558: /* simple_statement: case_label */ +#line 3691 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 11013 "MachineIndependent/glslang_tab.cpp" + break; + + case 559: /* simple_statement: iteration_statement */ +#line 3692 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 11019 "MachineIndependent/glslang_tab.cpp" + break; + + case 560: /* simple_statement: jump_statement */ +#line 3693 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 11025 "MachineIndependent/glslang_tab.cpp" + break; + + case 561: /* simple_statement: demote_statement */ +#line 3695 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 11031 "MachineIndependent/glslang_tab.cpp" + break; + + case 562: /* demote_statement: DEMOTE SEMICOLON */ +#line 3701 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "demote"); + parseContext.requireExtensions((yyvsp[-1].lex).loc, 1, &E_GL_EXT_demote_to_helper_invocation, "demote"); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDemote, (yyvsp[-1].lex).loc); + } +#line 11041 "MachineIndependent/glslang_tab.cpp" + break; + + case 563: /* compound_statement: LEFT_BRACE RIGHT_BRACE */ +#line 3710 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = 0; } +#line 11047 "MachineIndependent/glslang_tab.cpp" + break; + + case 564: /* $@5: %empty */ +#line 3711 "MachineIndependent/glslang.y" + { + parseContext.symbolTable.push(); + ++parseContext.statementNestingLevel; + } +#line 11056 "MachineIndependent/glslang_tab.cpp" + break; + + case 565: /* $@6: %empty */ +#line 3715 "MachineIndependent/glslang.y" + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + } +#line 11065 "MachineIndependent/glslang_tab.cpp" + break; + + case 566: /* compound_statement: LEFT_BRACE $@5 statement_list $@6 RIGHT_BRACE */ +#line 3719 "MachineIndependent/glslang.y" + { + if ((yyvsp[-2].interm.intermNode) && (yyvsp[-2].interm.intermNode)->getAsAggregate()) + (yyvsp[-2].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); + (yyval.interm.intermNode) = (yyvsp[-2].interm.intermNode); + } +#line 11075 "MachineIndependent/glslang_tab.cpp" + break; + + case 567: /* statement_no_new_scope: compound_statement_no_new_scope */ +#line 3727 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 11081 "MachineIndependent/glslang_tab.cpp" + break; + + case 568: /* statement_no_new_scope: simple_statement */ +#line 3728 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 11087 "MachineIndependent/glslang_tab.cpp" + break; + + case 569: /* $@7: %empty */ +#line 3732 "MachineIndependent/glslang.y" + { + ++parseContext.controlFlowNestingLevel; + } +#line 11095 "MachineIndependent/glslang_tab.cpp" + break; + + case 570: /* statement_scoped: $@7 compound_statement */ +#line 3735 "MachineIndependent/glslang.y" + { + --parseContext.controlFlowNestingLevel; + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11104 "MachineIndependent/glslang_tab.cpp" + break; + + case 571: /* $@8: %empty */ +#line 3739 "MachineIndependent/glslang.y" + { + parseContext.symbolTable.push(); + ++parseContext.statementNestingLevel; + ++parseContext.controlFlowNestingLevel; + } +#line 11114 "MachineIndependent/glslang_tab.cpp" + break; + + case 572: /* statement_scoped: $@8 simple_statement */ +#line 3744 "MachineIndependent/glslang.y" + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11125 "MachineIndependent/glslang_tab.cpp" + break; + + case 573: /* compound_statement_no_new_scope: LEFT_BRACE RIGHT_BRACE */ +#line 3753 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = 0; + } +#line 11133 "MachineIndependent/glslang_tab.cpp" + break; + + case 574: /* compound_statement_no_new_scope: LEFT_BRACE statement_list RIGHT_BRACE */ +#line 3756 "MachineIndependent/glslang.y" + { + if ((yyvsp[-1].interm.intermNode) && (yyvsp[-1].interm.intermNode)->getAsAggregate()) + (yyvsp[-1].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); + (yyval.interm.intermNode) = (yyvsp[-1].interm.intermNode); + } +#line 11143 "MachineIndependent/glslang_tab.cpp" + break; + + case 575: /* statement_list: statement */ +#line 3764 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); + if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || + (yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) { + parseContext.wrapupSwitchSubsequence(0, (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = 0; // start a fresh subsequence for what's after this case + } + } +#line 11156 "MachineIndependent/glslang_tab.cpp" + break; + + case 576: /* statement_list: statement_list statement */ +#line 3772 "MachineIndependent/glslang.y" + { + if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || + (yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) { + parseContext.wrapupSwitchSubsequence((yyvsp[-1].interm.intermNode) ? (yyvsp[-1].interm.intermNode)->getAsAggregate() : 0, (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = 0; // start a fresh subsequence for what's after this case + } else + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); + } +#line 11169 "MachineIndependent/glslang_tab.cpp" + break; + + case 577: /* expression_statement: SEMICOLON */ +#line 3783 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = 0; } +#line 11175 "MachineIndependent/glslang_tab.cpp" + break; + + case 578: /* expression_statement: expression SEMICOLON */ +#line 3784 "MachineIndependent/glslang.y" + { (yyval.interm.intermNode) = static_cast((yyvsp[-1].interm.intermTypedNode)); } +#line 11181 "MachineIndependent/glslang_tab.cpp" + break; + + case 579: /* selection_statement: selection_statement_nonattributed */ +#line 3788 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11189 "MachineIndependent/glslang_tab.cpp" + break; + + case 580: /* selection_statement: attribute selection_statement_nonattributed */ +#line 3792 "MachineIndependent/glslang.y" + { + parseContext.requireExtensions((yyvsp[0].interm.intermNode)->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); + parseContext.handleSelectionAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11199 "MachineIndependent/glslang_tab.cpp" + break; + + case 581: /* selection_statement_nonattributed: IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement */ +#line 3800 "MachineIndependent/glslang.y" + { + parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-2].interm.intermTypedNode)); + (yyval.interm.intermNode) = parseContext.intermediate.addSelection((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yyvsp[-4].lex).loc); + } +#line 11208 "MachineIndependent/glslang_tab.cpp" + break; + + case 582: /* selection_rest_statement: statement_scoped ELSE statement_scoped */ +#line 3807 "MachineIndependent/glslang.y" + { + (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode); + (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermNode); + } +#line 11217 "MachineIndependent/glslang_tab.cpp" + break; + + case 583: /* selection_rest_statement: statement_scoped */ +#line 3811 "MachineIndependent/glslang.y" + { + (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode); + (yyval.interm.nodePair).node2 = 0; + } +#line 11226 "MachineIndependent/glslang_tab.cpp" + break; + + case 584: /* condition: expression */ +#line 3819 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + parseContext.boolCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode)); + } +#line 11235 "MachineIndependent/glslang_tab.cpp" + break; + + case 585: /* condition: fully_specified_type IDENTIFIER EQUAL initializer */ +#line 3823 "MachineIndependent/glslang.y" + { + parseContext.boolCheck((yyvsp[-2].lex).loc, (yyvsp[-3].interm.type)); + + TType type((yyvsp[-3].interm.type)); + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), 0, (yyvsp[0].interm.intermTypedNode)); + if (initNode) + (yyval.interm.intermTypedNode) = initNode->getAsTyped(); + else + (yyval.interm.intermTypedNode) = 0; + } +#line 11250 "MachineIndependent/glslang_tab.cpp" + break; + + case 586: /* switch_statement: switch_statement_nonattributed */ +#line 3836 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11258 "MachineIndependent/glslang_tab.cpp" + break; + + case 587: /* switch_statement: attribute switch_statement_nonattributed */ +#line 3840 "MachineIndependent/glslang.y" + { + parseContext.requireExtensions((yyvsp[0].interm.intermNode)->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); + parseContext.handleSwitchAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11268 "MachineIndependent/glslang_tab.cpp" + break; + + case 588: /* $@9: %empty */ +#line 3848 "MachineIndependent/glslang.y" + { + // start new switch sequence on the switch stack + ++parseContext.controlFlowNestingLevel; + ++parseContext.statementNestingLevel; + parseContext.switchSequenceStack.push_back(new TIntermSequence); + parseContext.switchLevel.push_back(parseContext.statementNestingLevel); + parseContext.symbolTable.push(); + } +#line 11281 "MachineIndependent/glslang_tab.cpp" + break; + + case 589: /* switch_statement_nonattributed: SWITCH LEFT_PAREN expression RIGHT_PAREN $@9 LEFT_BRACE switch_statement_list RIGHT_BRACE */ +#line 3856 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.addSwitch((yyvsp[-7].lex).loc, (yyvsp[-5].interm.intermTypedNode), (yyvsp[-1].interm.intermNode) ? (yyvsp[-1].interm.intermNode)->getAsAggregate() : 0); + delete parseContext.switchSequenceStack.back(); + parseContext.switchSequenceStack.pop_back(); + parseContext.switchLevel.pop_back(); + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + } +#line 11295 "MachineIndependent/glslang_tab.cpp" + break; + + case 590: /* switch_statement_list: %empty */ +#line 3868 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = 0; + } +#line 11303 "MachineIndependent/glslang_tab.cpp" + break; + + case 591: /* switch_statement_list: statement_list */ +#line 3871 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11311 "MachineIndependent/glslang_tab.cpp" + break; + + case 592: /* case_label: CASE expression COLON */ +#line 3877 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = 0; + if (parseContext.switchLevel.size() == 0) + parseContext.error((yyvsp[-2].lex).loc, "cannot appear outside switch statement", "case", ""); + else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel) + parseContext.error((yyvsp[-2].lex).loc, "cannot be nested inside control flow", "case", ""); + else { + parseContext.constantValueCheck((yyvsp[-1].interm.intermTypedNode), "case"); + parseContext.integerCheck((yyvsp[-1].interm.intermTypedNode), "case"); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpCase, (yyvsp[-1].interm.intermTypedNode), (yyvsp[-2].lex).loc); + } + } +#line 11328 "MachineIndependent/glslang_tab.cpp" + break; + + case 593: /* case_label: DEFAULT COLON */ +#line 3889 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = 0; + if (parseContext.switchLevel.size() == 0) + parseContext.error((yyvsp[-1].lex).loc, "cannot appear outside switch statement", "default", ""); + else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel) + parseContext.error((yyvsp[-1].lex).loc, "cannot be nested inside control flow", "default", ""); + else + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDefault, (yyvsp[-1].lex).loc); + } +#line 11342 "MachineIndependent/glslang_tab.cpp" + break; + + case 594: /* iteration_statement: iteration_statement_nonattributed */ +#line 3901 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11350 "MachineIndependent/glslang_tab.cpp" + break; + + case 595: /* iteration_statement: attribute iteration_statement_nonattributed */ +#line 3905 "MachineIndependent/glslang.y" + { + parseContext.requireExtensions((yyvsp[0].interm.intermNode)->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); + parseContext.handleLoopAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11360 "MachineIndependent/glslang_tab.cpp" + break; + + case 596: /* $@10: %empty */ +#line 3913 "MachineIndependent/glslang.y" + { + if (! parseContext.limits.whileLoops) + parseContext.error((yyvsp[-1].lex).loc, "while loops not available", "limitation", ""); + parseContext.symbolTable.push(); + ++parseContext.loopNestingLevel; + ++parseContext.statementNestingLevel; + ++parseContext.controlFlowNestingLevel; + } +#line 11373 "MachineIndependent/glslang_tab.cpp" + break; + + case 597: /* iteration_statement_nonattributed: WHILE LEFT_PAREN $@10 condition RIGHT_PAREN statement_no_new_scope */ +#line 3921 "MachineIndependent/glslang.y" + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[0].interm.intermNode), (yyvsp[-2].interm.intermTypedNode), 0, true, (yyvsp[-5].lex).loc); + --parseContext.loopNestingLevel; + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + } +#line 11385 "MachineIndependent/glslang_tab.cpp" + break; + + case 598: /* $@11: %empty */ +#line 3928 "MachineIndependent/glslang.y" + { + ++parseContext.loopNestingLevel; + ++parseContext.statementNestingLevel; + ++parseContext.controlFlowNestingLevel; + } +#line 11395 "MachineIndependent/glslang_tab.cpp" + break; + + case 599: /* iteration_statement_nonattributed: DO $@11 statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON */ +#line 3933 "MachineIndependent/glslang.y" + { + if (! parseContext.limits.whileLoops) + parseContext.error((yyvsp[-7].lex).loc, "do-while loops not available", "limitation", ""); + + parseContext.boolCheck((yyvsp[0].lex).loc, (yyvsp[-2].interm.intermTypedNode)); + + (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[-5].interm.intermNode), (yyvsp[-2].interm.intermTypedNode), 0, false, (yyvsp[-4].lex).loc); + --parseContext.loopNestingLevel; + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + } +#line 11411 "MachineIndependent/glslang_tab.cpp" + break; + + case 600: /* $@12: %empty */ +#line 3944 "MachineIndependent/glslang.y" + { + parseContext.symbolTable.push(); + ++parseContext.loopNestingLevel; + ++parseContext.statementNestingLevel; + ++parseContext.controlFlowNestingLevel; + } +#line 11422 "MachineIndependent/glslang_tab.cpp" + break; + + case 601: /* iteration_statement_nonattributed: FOR LEFT_PAREN $@12 for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope */ +#line 3950 "MachineIndependent/glslang.y" + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[-3].interm.intermNode), (yyvsp[-5].lex).loc); + TIntermLoop* forLoop = parseContext.intermediate.addLoop((yyvsp[0].interm.intermNode), reinterpret_cast((yyvsp[-2].interm.nodePair).node1), reinterpret_cast((yyvsp[-2].interm.nodePair).node2), true, (yyvsp[-6].lex).loc); + if (! parseContext.limits.nonInductiveForLoops) + parseContext.inductiveLoopCheck((yyvsp[-6].lex).loc, (yyvsp[-3].interm.intermNode), forLoop); + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyval.interm.intermNode), forLoop, (yyvsp[-6].lex).loc); + (yyval.interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); + --parseContext.loopNestingLevel; + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + } +#line 11439 "MachineIndependent/glslang_tab.cpp" + break; + + case 602: /* for_init_statement: expression_statement */ +#line 3965 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11447 "MachineIndependent/glslang_tab.cpp" + break; + + case 603: /* for_init_statement: declaration_statement */ +#line 3968 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11455 "MachineIndependent/glslang_tab.cpp" + break; + + case 604: /* conditionopt: condition */ +#line 3974 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 11463 "MachineIndependent/glslang_tab.cpp" + break; + + case 605: /* conditionopt: %empty */ +#line 3977 "MachineIndependent/glslang.y" + { + (yyval.interm.intermTypedNode) = 0; + } +#line 11471 "MachineIndependent/glslang_tab.cpp" + break; + + case 606: /* for_rest_statement: conditionopt SEMICOLON */ +#line 3983 "MachineIndependent/glslang.y" + { + (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode); + (yyval.interm.nodePair).node2 = 0; + } +#line 11480 "MachineIndependent/glslang_tab.cpp" + break; + + case 607: /* for_rest_statement: conditionopt SEMICOLON expression */ +#line 3987 "MachineIndependent/glslang.y" + { + (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode); + (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode); + } +#line 11489 "MachineIndependent/glslang_tab.cpp" + break; + + case 608: /* jump_statement: CONTINUE SEMICOLON */ +#line 3994 "MachineIndependent/glslang.y" + { + if (parseContext.loopNestingLevel <= 0) + parseContext.error((yyvsp[-1].lex).loc, "continue statement only allowed in loops", "", ""); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpContinue, (yyvsp[-1].lex).loc); + } +#line 11499 "MachineIndependent/glslang_tab.cpp" + break; + + case 609: /* jump_statement: BREAK SEMICOLON */ +#line 3999 "MachineIndependent/glslang.y" + { + if (parseContext.loopNestingLevel + parseContext.switchSequenceStack.size() <= 0) + parseContext.error((yyvsp[-1].lex).loc, "break statement only allowed in switch and loops", "", ""); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpBreak, (yyvsp[-1].lex).loc); + } +#line 11509 "MachineIndependent/glslang_tab.cpp" + break; + + case 610: /* jump_statement: RETURN SEMICOLON */ +#line 4004 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[-1].lex).loc); + if (parseContext.currentFunctionType->getBasicType() != EbtVoid) + parseContext.error((yyvsp[-1].lex).loc, "non-void function must return a value", "return", ""); + if (parseContext.inMain) + parseContext.postEntryPointReturn = true; + } +#line 11521 "MachineIndependent/glslang_tab.cpp" + break; + + case 611: /* jump_statement: RETURN expression SEMICOLON */ +#line 4011 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.handleReturnValue((yyvsp[-2].lex).loc, (yyvsp[-1].interm.intermTypedNode)); + } +#line 11529 "MachineIndependent/glslang_tab.cpp" + break; + + case 612: /* jump_statement: DISCARD SEMICOLON */ +#line 4014 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "discard"); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpKill, (yyvsp[-1].lex).loc); + } +#line 11538 "MachineIndependent/glslang_tab.cpp" + break; + + case 613: /* jump_statement: TERMINATE_INVOCATION SEMICOLON */ +#line 4018 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "terminateInvocation"); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpTerminateInvocation, (yyvsp[-1].lex).loc); + } +#line 11547 "MachineIndependent/glslang_tab.cpp" + break; + + case 614: /* jump_statement: TERMINATE_RAY SEMICOLON */ +#line 4023 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[-1].lex).loc, EShLangAnyHit, "terminateRayEXT"); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpTerminateRayKHR, (yyvsp[-1].lex).loc); + } +#line 11556 "MachineIndependent/glslang_tab.cpp" + break; + + case 615: /* jump_statement: IGNORE_INTERSECTION SEMICOLON */ +#line 4027 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[-1].lex).loc, EShLangAnyHit, "ignoreIntersectionEXT"); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpIgnoreIntersectionKHR, (yyvsp[-1].lex).loc); + } +#line 11565 "MachineIndependent/glslang_tab.cpp" + break; + + case 616: /* translation_unit: external_declaration */ +#line 4037 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); + } +#line 11574 "MachineIndependent/glslang_tab.cpp" + break; + + case 617: /* translation_unit: translation_unit external_declaration */ +#line 4041 "MachineIndependent/glslang.y" + { + if ((yyvsp[0].interm.intermNode) != nullptr) { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); + parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); + } + } +#line 11585 "MachineIndependent/glslang_tab.cpp" + break; + + case 618: /* external_declaration: function_definition */ +#line 4050 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11593 "MachineIndependent/glslang_tab.cpp" + break; + + case 619: /* external_declaration: declaration */ +#line 4053 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 11601 "MachineIndependent/glslang_tab.cpp" + break; + + case 620: /* external_declaration: SEMICOLON */ +#line 4057 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ~EEsProfile, "extraneous semicolon"); + parseContext.profileRequires((yyvsp[0].lex).loc, ~EEsProfile, 460, nullptr, "extraneous semicolon"); + (yyval.interm.intermNode) = nullptr; + } +#line 11611 "MachineIndependent/glslang_tab.cpp" + break; + + case 621: /* $@13: %empty */ +#line 4066 "MachineIndependent/glslang.y" + { + (yyvsp[0].interm).function = parseContext.handleFunctionDeclarator((yyvsp[0].interm).loc, *(yyvsp[0].interm).function, false /* not prototype */); + (yyvsp[0].interm).intermNode = parseContext.handleFunctionDefinition((yyvsp[0].interm).loc, *(yyvsp[0].interm).function); + + // For ES 100 only, according to ES shading language 100 spec: A function + // body has a scope nested inside the function's definition. + if (parseContext.profile == EEsProfile && parseContext.version == 100) + { + parseContext.symbolTable.push(); + ++parseContext.statementNestingLevel; + } + } +#line 11628 "MachineIndependent/glslang_tab.cpp" + break; + + case 622: /* function_definition: function_prototype $@13 compound_statement_no_new_scope */ +#line 4078 "MachineIndependent/glslang.y" + { + // May be best done as post process phase on intermediate code + if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) + parseContext.error((yyvsp[-2].interm).loc, "function does not return a value:", "", (yyvsp[-2].interm).function->getName().c_str()); + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermNode)); + parseContext.intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yyvsp[-2].interm).function->getType(), (yyvsp[-2].interm).loc); + (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[-2].interm).function->getMangledName().c_str()); + + // store the pragma information for debug and optimize and other vendor specific + // information. This information can be queried from the parse tree + (yyval.interm.intermNode)->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize); + (yyval.interm.intermNode)->getAsAggregate()->setDebug(parseContext.contextPragma.debug); + (yyval.interm.intermNode)->getAsAggregate()->setPragmaTable(parseContext.contextPragma.pragmaTable); + + // Set currentFunctionType to empty pointer when goes outside of the function + parseContext.currentFunctionType = nullptr; + + // For ES 100 only, according to ES shading language 100 spec: A function + // body has a scope nested inside the function's definition. + if (parseContext.profile == EEsProfile && parseContext.version == 100) + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + } + } +#line 11659 "MachineIndependent/glslang_tab.cpp" + break; + + case 623: /* attribute: LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET */ +#line 4108 "MachineIndependent/glslang.y" + { + (yyval.interm.attributes) = (yyvsp[-2].interm.attributes); + } +#line 11667 "MachineIndependent/glslang_tab.cpp" + break; + + case 624: /* attribute_list: single_attribute */ +#line 4113 "MachineIndependent/glslang.y" + { + (yyval.interm.attributes) = (yyvsp[0].interm.attributes); + } +#line 11675 "MachineIndependent/glslang_tab.cpp" + break; + + case 625: /* attribute_list: attribute_list COMMA single_attribute */ +#line 4116 "MachineIndependent/glslang.y" + { + (yyval.interm.attributes) = parseContext.mergeAttributes((yyvsp[-2].interm.attributes), (yyvsp[0].interm.attributes)); + } +#line 11683 "MachineIndependent/glslang_tab.cpp" + break; + + case 626: /* single_attribute: IDENTIFIER */ +#line 4121 "MachineIndependent/glslang.y" + { + (yyval.interm.attributes) = parseContext.makeAttributes(*(yyvsp[0].lex).string); + } +#line 11691 "MachineIndependent/glslang_tab.cpp" + break; + + case 627: /* single_attribute: IDENTIFIER LEFT_PAREN constant_expression RIGHT_PAREN */ +#line 4124 "MachineIndependent/glslang.y" + { + (yyval.interm.attributes) = parseContext.makeAttributes(*(yyvsp[-3].lex).string, (yyvsp[-1].interm.intermTypedNode)); + } +#line 11699 "MachineIndependent/glslang_tab.cpp" + break; + + case 628: /* spirv_requirements_list: spirv_requirements_parameter */ +#line 4131 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvReq) = (yyvsp[0].interm.spirvReq); + } +#line 11707 "MachineIndependent/glslang_tab.cpp" + break; + + case 629: /* spirv_requirements_list: spirv_requirements_list COMMA spirv_requirements_parameter */ +#line 4134 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvReq) = parseContext.mergeSpirvRequirements((yyvsp[-1].lex).loc, (yyvsp[-2].interm.spirvReq), (yyvsp[0].interm.spirvReq)); + } +#line 11715 "MachineIndependent/glslang_tab.cpp" + break; + + case 630: /* spirv_requirements_parameter: IDENTIFIER EQUAL LEFT_BRACKET spirv_extension_list RIGHT_BRACKET */ +#line 4139 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvReq) = parseContext.makeSpirvRequirement((yyvsp[-3].lex).loc, *(yyvsp[-4].lex).string, (yyvsp[-1].interm.intermNode)->getAsAggregate(), nullptr); + } +#line 11723 "MachineIndependent/glslang_tab.cpp" + break; + + case 631: /* spirv_requirements_parameter: IDENTIFIER EQUAL LEFT_BRACKET spirv_capability_list RIGHT_BRACKET */ +#line 4142 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvReq) = parseContext.makeSpirvRequirement((yyvsp[-3].lex).loc, *(yyvsp[-4].lex).string, nullptr, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + } +#line 11731 "MachineIndependent/glslang_tab.cpp" + break; + + case 632: /* spirv_extension_list: STRING_LITERAL */ +#line 4147 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate(parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true)); + } +#line 11739 "MachineIndependent/glslang_tab.cpp" + break; + + case 633: /* spirv_extension_list: spirv_extension_list COMMA STRING_LITERAL */ +#line 4150 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true)); + } +#line 11747 "MachineIndependent/glslang_tab.cpp" + break; + + case 634: /* spirv_capability_list: INTCONSTANT */ +#line 4155 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate(parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true)); + } +#line 11755 "MachineIndependent/glslang_tab.cpp" + break; + + case 635: /* spirv_capability_list: spirv_capability_list COMMA INTCONSTANT */ +#line 4158 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true)); + } +#line 11763 "MachineIndependent/glslang_tab.cpp" + break; + + case 636: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT RIGHT_PAREN */ +#line 4163 "MachineIndependent/glslang.y" + { + parseContext.intermediate.insertSpirvExecutionMode((yyvsp[-1].lex).i); + (yyval.interm.intermNode) = 0; + } +#line 11772 "MachineIndependent/glslang_tab.cpp" + break; + + case 637: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ +#line 4167 "MachineIndependent/glslang.y" + { + parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); + parseContext.intermediate.insertSpirvExecutionMode((yyvsp[-1].lex).i); + (yyval.interm.intermNode) = 0; + } +#line 11782 "MachineIndependent/glslang_tab.cpp" + break; + + case 638: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN */ +#line 4172 "MachineIndependent/glslang.y" + { + parseContext.intermediate.insertSpirvExecutionMode((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + (yyval.interm.intermNode) = 0; + } +#line 11791 "MachineIndependent/glslang_tab.cpp" + break; + + case 639: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN */ +#line 4176 "MachineIndependent/glslang.y" + { + parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); + parseContext.intermediate.insertSpirvExecutionMode((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + (yyval.interm.intermNode) = 0; + } +#line 11801 "MachineIndependent/glslang_tab.cpp" + break; + + case 640: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE_ID LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN */ +#line 4181 "MachineIndependent/glslang.y" + { + parseContext.intermediate.insertSpirvExecutionModeId((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + (yyval.interm.intermNode) = 0; + } +#line 11810 "MachineIndependent/glslang_tab.cpp" + break; + + case 641: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN */ +#line 4185 "MachineIndependent/glslang.y" + { + parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); + parseContext.intermediate.insertSpirvExecutionModeId((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + (yyval.interm.intermNode) = 0; + } +#line 11820 "MachineIndependent/glslang_tab.cpp" + break; + + case 642: /* spirv_execution_mode_parameter_list: spirv_execution_mode_parameter */ +#line 4192 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); + } +#line 11828 "MachineIndependent/glslang_tab.cpp" + break; + + case 643: /* spirv_execution_mode_parameter_list: spirv_execution_mode_parameter_list COMMA spirv_execution_mode_parameter */ +#line 4195 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermNode)); + } +#line 11836 "MachineIndependent/glslang_tab.cpp" + break; + + case 644: /* spirv_execution_mode_parameter: FLOATCONSTANT */ +#line 4200 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); + } +#line 11844 "MachineIndependent/glslang_tab.cpp" + break; + + case 645: /* spirv_execution_mode_parameter: INTCONSTANT */ +#line 4203 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 11852 "MachineIndependent/glslang_tab.cpp" + break; + + case 646: /* spirv_execution_mode_parameter: UINTCONSTANT */ +#line 4206 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 11860 "MachineIndependent/glslang_tab.cpp" + break; + + case 647: /* spirv_execution_mode_parameter: BOOLCONSTANT */ +#line 4209 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); + } +#line 11868 "MachineIndependent/glslang_tab.cpp" + break; + + case 648: /* spirv_execution_mode_parameter: STRING_LITERAL */ +#line 4212 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true); + } +#line 11876 "MachineIndependent/glslang_tab.cpp" + break; + + case 649: /* spirv_execution_mode_id_parameter_list: constant_expression */ +#line 4217 "MachineIndependent/glslang.y" + { + if ((yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtFloat && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtInt && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtUint && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtBool && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtString) + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "this type not allowed", (yyvsp[0].interm.intermTypedNode)->getType().getBasicString(), ""); + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermTypedNode)); + } +#line 11890 "MachineIndependent/glslang_tab.cpp" + break; + + case 650: /* spirv_execution_mode_id_parameter_list: spirv_execution_mode_id_parameter_list COMMA constant_expression */ +#line 4226 "MachineIndependent/glslang.y" + { + if ((yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtFloat && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtInt && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtUint && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtBool && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtString) + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "this type not allowed", (yyvsp[0].interm.intermTypedNode)->getType().getBasicString(), ""); + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermTypedNode)); + } +#line 11904 "MachineIndependent/glslang_tab.cpp" + break; + + case 651: /* spirv_storage_class_qualifier: SPIRV_STORAGE_CLASS LEFT_PAREN INTCONSTANT RIGHT_PAREN */ +#line 4237 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-3].lex).loc); + (yyval.interm.type).qualifier.storage = EvqSpirvStorageClass; + (yyval.interm.type).qualifier.spirvStorageClass = (yyvsp[-1].lex).i; + } +#line 11914 "MachineIndependent/glslang_tab.cpp" + break; + + case 652: /* spirv_storage_class_qualifier: SPIRV_STORAGE_CLASS LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ +#line 4242 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-5].lex).loc); + parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); + (yyval.interm.type).qualifier.storage = EvqSpirvStorageClass; + (yyval.interm.type).qualifier.spirvStorageClass = (yyvsp[-1].lex).i; + } +#line 11925 "MachineIndependent/glslang_tab.cpp" + break; + + case 653: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN INTCONSTANT RIGHT_PAREN */ +#line 4250 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-3].lex).loc); + (yyval.interm.type).qualifier.setSpirvDecorate((yyvsp[-1].lex).i); + } +#line 11934 "MachineIndependent/glslang_tab.cpp" + break; + + case 654: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ +#line 4254 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-5].lex).loc); + parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); + (yyval.interm.type).qualifier.setSpirvDecorate((yyvsp[-1].lex).i); + } +#line 11944 "MachineIndependent/glslang_tab.cpp" + break; + + case 655: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN */ +#line 4259 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-5].lex).loc); + (yyval.interm.type).qualifier.setSpirvDecorate((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + } +#line 11953 "MachineIndependent/glslang_tab.cpp" + break; + + case 656: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN */ +#line 4263 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-7].lex).loc); + parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); + (yyval.interm.type).qualifier.setSpirvDecorate((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + } +#line 11963 "MachineIndependent/glslang_tab.cpp" + break; + + case 657: /* spirv_decorate_qualifier: SPIRV_DECORATE_ID LEFT_PAREN INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN */ +#line 4268 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-5].lex).loc); + (yyval.interm.type).qualifier.setSpirvDecorateId((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + } +#line 11972 "MachineIndependent/glslang_tab.cpp" + break; + + case 658: /* spirv_decorate_qualifier: SPIRV_DECORATE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN */ +#line 4272 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-7].lex).loc); + parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); + (yyval.interm.type).qualifier.setSpirvDecorateId((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + } +#line 11982 "MachineIndependent/glslang_tab.cpp" + break; + + case 659: /* spirv_decorate_qualifier: SPIRV_DECORATE_STRING LEFT_PAREN INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN */ +#line 4277 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-5].lex).loc); + (yyval.interm.type).qualifier.setSpirvDecorateString((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + } +#line 11991 "MachineIndependent/glslang_tab.cpp" + break; + + case 660: /* spirv_decorate_qualifier: SPIRV_DECORATE_STRING LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN */ +#line 4281 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-7].lex).loc); + parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); + (yyval.interm.type).qualifier.setSpirvDecorateString((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); + } +#line 12001 "MachineIndependent/glslang_tab.cpp" + break; + + case 661: /* spirv_decorate_parameter_list: spirv_decorate_parameter */ +#line 4288 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); + } +#line 12009 "MachineIndependent/glslang_tab.cpp" + break; + + case 662: /* spirv_decorate_parameter_list: spirv_decorate_parameter_list COMMA spirv_decorate_parameter */ +#line 4291 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermNode)); + } +#line 12017 "MachineIndependent/glslang_tab.cpp" + break; + + case 663: /* spirv_decorate_parameter: FLOATCONSTANT */ +#line 4296 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); + } +#line 12025 "MachineIndependent/glslang_tab.cpp" + break; + + case 664: /* spirv_decorate_parameter: INTCONSTANT */ +#line 4299 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 12033 "MachineIndependent/glslang_tab.cpp" + break; + + case 665: /* spirv_decorate_parameter: UINTCONSTANT */ +#line 4302 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 12041 "MachineIndependent/glslang_tab.cpp" + break; + + case 666: /* spirv_decorate_parameter: BOOLCONSTANT */ +#line 4305 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); + } +#line 12049 "MachineIndependent/glslang_tab.cpp" + break; + + case 667: /* spirv_decorate_id_parameter_list: constant_expression */ +#line 4310 "MachineIndependent/glslang.y" + { + if ((yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtFloat && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtInt && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtUint && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtBool) + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "this type not allowed", (yyvsp[0].interm.intermTypedNode)->getType().getBasicString(), ""); + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermTypedNode)); + } +#line 12062 "MachineIndependent/glslang_tab.cpp" + break; + + case 668: /* spirv_decorate_id_parameter_list: spirv_decorate_id_parameter_list COMMA constant_expression */ +#line 4318 "MachineIndependent/glslang.y" + { + if ((yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtFloat && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtInt && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtUint && + (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtBool) + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "this type not allowed", (yyvsp[0].interm.intermTypedNode)->getType().getBasicString(), ""); + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermTypedNode)); + } +#line 12075 "MachineIndependent/glslang_tab.cpp" + break; + + case 669: /* spirv_decorate_string_parameter_list: STRING_LITERAL */ +#line 4328 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate( + parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true)); + } +#line 12084 "MachineIndependent/glslang_tab.cpp" + break; + + case 670: /* spirv_decorate_string_parameter_list: spirv_decorate_string_parameter_list COMMA STRING_LITERAL */ +#line 4332 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true)); + } +#line 12092 "MachineIndependent/glslang_tab.cpp" + break; + + case 671: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN */ +#line 4337 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-5].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).setSpirvType(*(yyvsp[-3].interm.spirvInst), (yyvsp[-1].interm.spirvTypeParams)); + } +#line 12101 "MachineIndependent/glslang_tab.cpp" + break; + + case 672: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN */ +#line 4341 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-7].lex).loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); + (yyval.interm.type).setSpirvType(*(yyvsp[-3].interm.spirvInst), (yyvsp[-1].interm.spirvTypeParams)); + } +#line 12111 "MachineIndependent/glslang_tab.cpp" + break; + + case 673: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN */ +#line 4346 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-3].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).setSpirvType(*(yyvsp[-1].interm.spirvInst)); + } +#line 12120 "MachineIndependent/glslang_tab.cpp" + break; + + case 674: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN */ +#line 4350 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[-5].lex).loc, parseContext.symbolTable.atGlobalLevel()); + parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); + (yyval.interm.type).setSpirvType(*(yyvsp[-1].interm.spirvInst)); + } +#line 12130 "MachineIndependent/glslang_tab.cpp" + break; + + case 675: /* spirv_type_parameter_list: spirv_type_parameter */ +#line 4357 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvTypeParams) = (yyvsp[0].interm.spirvTypeParams); + } +#line 12138 "MachineIndependent/glslang_tab.cpp" + break; + + case 676: /* spirv_type_parameter_list: spirv_type_parameter_list COMMA spirv_type_parameter */ +#line 4360 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvTypeParams) = parseContext.mergeSpirvTypeParameters((yyvsp[-2].interm.spirvTypeParams), (yyvsp[0].interm.spirvTypeParams)); + } +#line 12146 "MachineIndependent/glslang_tab.cpp" + break; + + case 677: /* spirv_type_parameter: constant_expression */ +#line 4365 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvTypeParams) = parseContext.makeSpirvTypeParameters((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode)->getAsConstantUnion()); + } +#line 12154 "MachineIndependent/glslang_tab.cpp" + break; + + case 678: /* spirv_type_parameter: type_specifier */ +#line 4368 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvTypeParams) = parseContext.makeSpirvTypeParameters((yyvsp[0].interm.type)); + } +#line 12162 "MachineIndependent/glslang_tab.cpp" + break; + + case 679: /* spirv_instruction_qualifier: SPIRV_INSTRUCTION LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN */ +#line 4373 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvInst) = (yyvsp[-1].interm.spirvInst); + } +#line 12170 "MachineIndependent/glslang_tab.cpp" + break; + + case 680: /* spirv_instruction_qualifier: SPIRV_INSTRUCTION LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN */ +#line 4376 "MachineIndependent/glslang.y" + { + parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); + (yyval.interm.spirvInst) = (yyvsp[-1].interm.spirvInst); + } +#line 12179 "MachineIndependent/glslang_tab.cpp" + break; + + case 681: /* spirv_instruction_qualifier_list: spirv_instruction_qualifier_id */ +#line 4382 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvInst) = (yyvsp[0].interm.spirvInst); + } +#line 12187 "MachineIndependent/glslang_tab.cpp" + break; + + case 682: /* spirv_instruction_qualifier_list: spirv_instruction_qualifier_list COMMA spirv_instruction_qualifier_id */ +#line 4385 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvInst) = parseContext.mergeSpirvInstruction((yyvsp[-1].lex).loc, (yyvsp[-2].interm.spirvInst), (yyvsp[0].interm.spirvInst)); + } +#line 12195 "MachineIndependent/glslang_tab.cpp" + break; + + case 683: /* spirv_instruction_qualifier_id: IDENTIFIER EQUAL STRING_LITERAL */ +#line 4390 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvInst) = parseContext.makeSpirvInstruction((yyvsp[-1].lex).loc, *(yyvsp[-2].lex).string, *(yyvsp[0].lex).string); + } +#line 12203 "MachineIndependent/glslang_tab.cpp" + break; + + case 684: /* spirv_instruction_qualifier_id: IDENTIFIER EQUAL INTCONSTANT */ +#line 4393 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvInst) = parseContext.makeSpirvInstruction((yyvsp[-1].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[0].lex).i); + } +#line 12211 "MachineIndependent/glslang_tab.cpp" + break; + + +#line 12215 "MachineIndependent/glslang_tab.cpp" + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + { + yypcontext_t yyctx + = {yyssp, yytoken}; + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == -1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = YY_CAST (char *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); + if (yymsg) + { + yysyntax_error_status + = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + yymsgp = yymsg; + } + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = YYENOMEM; + } + } + yyerror (pParseContext, yymsgp); + if (yysyntax_error_status == YYENOMEM) + goto yyexhaustedlab; + } + } + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, pParseContext); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + /* Pop stack until we find a state that shifts the error token. */ + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYSYMBOL_YYerror; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + YY_ACCESSING_SYMBOL (yystate), yyvsp, pParseContext); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + + +#if 1 +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (pParseContext, YY_("memory exhausted")); + yyresult = 2; + goto yyreturn; +#endif + + +/*-------------------------------------------------------. +| yyreturn -- parsing is finished, clean up and return. | +`-------------------------------------------------------*/ +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, pParseContext); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, pParseContext); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + return yyresult; +} + +#line 4398 "MachineIndependent/glslang.y" + diff --git a/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang_tab.cpp.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang_tab.cpp.h new file mode 100644 index 00000000000..596a10e6d98 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/glslang_tab.cpp.h @@ -0,0 +1,568 @@ +/* A Bison parser, made by GNU Bison 3.7.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +#ifndef YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED +# define YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token kinds. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + YYEMPTY = -2, + YYEOF = 0, /* "end of file" */ + YYerror = 256, /* error */ + YYUNDEF = 257, /* "invalid token" */ + CONST = 258, /* CONST */ + BOOL = 259, /* BOOL */ + INT = 260, /* INT */ + UINT = 261, /* UINT */ + FLOAT = 262, /* FLOAT */ + BVEC2 = 263, /* BVEC2 */ + BVEC3 = 264, /* BVEC3 */ + BVEC4 = 265, /* BVEC4 */ + IVEC2 = 266, /* IVEC2 */ + IVEC3 = 267, /* IVEC3 */ + IVEC4 = 268, /* IVEC4 */ + UVEC2 = 269, /* UVEC2 */ + UVEC3 = 270, /* UVEC3 */ + UVEC4 = 271, /* UVEC4 */ + VEC2 = 272, /* VEC2 */ + VEC3 = 273, /* VEC3 */ + VEC4 = 274, /* VEC4 */ + MAT2 = 275, /* MAT2 */ + MAT3 = 276, /* MAT3 */ + MAT4 = 277, /* MAT4 */ + MAT2X2 = 278, /* MAT2X2 */ + MAT2X3 = 279, /* MAT2X3 */ + MAT2X4 = 280, /* MAT2X4 */ + MAT3X2 = 281, /* MAT3X2 */ + MAT3X3 = 282, /* MAT3X3 */ + MAT3X4 = 283, /* MAT3X4 */ + MAT4X2 = 284, /* MAT4X2 */ + MAT4X3 = 285, /* MAT4X3 */ + MAT4X4 = 286, /* MAT4X4 */ + SAMPLER2D = 287, /* SAMPLER2D */ + SAMPLER3D = 288, /* SAMPLER3D */ + SAMPLERCUBE = 289, /* SAMPLERCUBE */ + SAMPLER2DSHADOW = 290, /* SAMPLER2DSHADOW */ + SAMPLERCUBESHADOW = 291, /* SAMPLERCUBESHADOW */ + SAMPLER2DARRAY = 292, /* SAMPLER2DARRAY */ + SAMPLER2DARRAYSHADOW = 293, /* SAMPLER2DARRAYSHADOW */ + ISAMPLER2D = 294, /* ISAMPLER2D */ + ISAMPLER3D = 295, /* ISAMPLER3D */ + ISAMPLERCUBE = 296, /* ISAMPLERCUBE */ + ISAMPLER2DARRAY = 297, /* ISAMPLER2DARRAY */ + USAMPLER2D = 298, /* USAMPLER2D */ + USAMPLER3D = 299, /* USAMPLER3D */ + USAMPLERCUBE = 300, /* USAMPLERCUBE */ + USAMPLER2DARRAY = 301, /* USAMPLER2DARRAY */ + SAMPLER = 302, /* SAMPLER */ + SAMPLERSHADOW = 303, /* SAMPLERSHADOW */ + TEXTURE2D = 304, /* TEXTURE2D */ + TEXTURE3D = 305, /* TEXTURE3D */ + TEXTURECUBE = 306, /* TEXTURECUBE */ + TEXTURE2DARRAY = 307, /* TEXTURE2DARRAY */ + ITEXTURE2D = 308, /* ITEXTURE2D */ + ITEXTURE3D = 309, /* ITEXTURE3D */ + ITEXTURECUBE = 310, /* ITEXTURECUBE */ + ITEXTURE2DARRAY = 311, /* ITEXTURE2DARRAY */ + UTEXTURE2D = 312, /* UTEXTURE2D */ + UTEXTURE3D = 313, /* UTEXTURE3D */ + UTEXTURECUBE = 314, /* UTEXTURECUBE */ + UTEXTURE2DARRAY = 315, /* UTEXTURE2DARRAY */ + ATTRIBUTE = 316, /* ATTRIBUTE */ + VARYING = 317, /* VARYING */ + FLOAT16_T = 318, /* FLOAT16_T */ + FLOAT32_T = 319, /* FLOAT32_T */ + DOUBLE = 320, /* DOUBLE */ + FLOAT64_T = 321, /* FLOAT64_T */ + INT64_T = 322, /* INT64_T */ + UINT64_T = 323, /* UINT64_T */ + INT32_T = 324, /* INT32_T */ + UINT32_T = 325, /* UINT32_T */ + INT16_T = 326, /* INT16_T */ + UINT16_T = 327, /* UINT16_T */ + INT8_T = 328, /* INT8_T */ + UINT8_T = 329, /* UINT8_T */ + I64VEC2 = 330, /* I64VEC2 */ + I64VEC3 = 331, /* I64VEC3 */ + I64VEC4 = 332, /* I64VEC4 */ + U64VEC2 = 333, /* U64VEC2 */ + U64VEC3 = 334, /* U64VEC3 */ + U64VEC4 = 335, /* U64VEC4 */ + I32VEC2 = 336, /* I32VEC2 */ + I32VEC3 = 337, /* I32VEC3 */ + I32VEC4 = 338, /* I32VEC4 */ + U32VEC2 = 339, /* U32VEC2 */ + U32VEC3 = 340, /* U32VEC3 */ + U32VEC4 = 341, /* U32VEC4 */ + I16VEC2 = 342, /* I16VEC2 */ + I16VEC3 = 343, /* I16VEC3 */ + I16VEC4 = 344, /* I16VEC4 */ + U16VEC2 = 345, /* U16VEC2 */ + U16VEC3 = 346, /* U16VEC3 */ + U16VEC4 = 347, /* U16VEC4 */ + I8VEC2 = 348, /* I8VEC2 */ + I8VEC3 = 349, /* I8VEC3 */ + I8VEC4 = 350, /* I8VEC4 */ + U8VEC2 = 351, /* U8VEC2 */ + U8VEC3 = 352, /* U8VEC3 */ + U8VEC4 = 353, /* U8VEC4 */ + DVEC2 = 354, /* DVEC2 */ + DVEC3 = 355, /* DVEC3 */ + DVEC4 = 356, /* DVEC4 */ + DMAT2 = 357, /* DMAT2 */ + DMAT3 = 358, /* DMAT3 */ + DMAT4 = 359, /* DMAT4 */ + F16VEC2 = 360, /* F16VEC2 */ + F16VEC3 = 361, /* F16VEC3 */ + F16VEC4 = 362, /* F16VEC4 */ + F16MAT2 = 363, /* F16MAT2 */ + F16MAT3 = 364, /* F16MAT3 */ + F16MAT4 = 365, /* F16MAT4 */ + F32VEC2 = 366, /* F32VEC2 */ + F32VEC3 = 367, /* F32VEC3 */ + F32VEC4 = 368, /* F32VEC4 */ + F32MAT2 = 369, /* F32MAT2 */ + F32MAT3 = 370, /* F32MAT3 */ + F32MAT4 = 371, /* F32MAT4 */ + F64VEC2 = 372, /* F64VEC2 */ + F64VEC3 = 373, /* F64VEC3 */ + F64VEC4 = 374, /* F64VEC4 */ + F64MAT2 = 375, /* F64MAT2 */ + F64MAT3 = 376, /* F64MAT3 */ + F64MAT4 = 377, /* F64MAT4 */ + DMAT2X2 = 378, /* DMAT2X2 */ + DMAT2X3 = 379, /* DMAT2X3 */ + DMAT2X4 = 380, /* DMAT2X4 */ + DMAT3X2 = 381, /* DMAT3X2 */ + DMAT3X3 = 382, /* DMAT3X3 */ + DMAT3X4 = 383, /* DMAT3X4 */ + DMAT4X2 = 384, /* DMAT4X2 */ + DMAT4X3 = 385, /* DMAT4X3 */ + DMAT4X4 = 386, /* DMAT4X4 */ + F16MAT2X2 = 387, /* F16MAT2X2 */ + F16MAT2X3 = 388, /* F16MAT2X3 */ + F16MAT2X4 = 389, /* F16MAT2X4 */ + F16MAT3X2 = 390, /* F16MAT3X2 */ + F16MAT3X3 = 391, /* F16MAT3X3 */ + F16MAT3X4 = 392, /* F16MAT3X4 */ + F16MAT4X2 = 393, /* F16MAT4X2 */ + F16MAT4X3 = 394, /* F16MAT4X3 */ + F16MAT4X4 = 395, /* F16MAT4X4 */ + F32MAT2X2 = 396, /* F32MAT2X2 */ + F32MAT2X3 = 397, /* F32MAT2X3 */ + F32MAT2X4 = 398, /* F32MAT2X4 */ + F32MAT3X2 = 399, /* F32MAT3X2 */ + F32MAT3X3 = 400, /* F32MAT3X3 */ + F32MAT3X4 = 401, /* F32MAT3X4 */ + F32MAT4X2 = 402, /* F32MAT4X2 */ + F32MAT4X3 = 403, /* F32MAT4X3 */ + F32MAT4X4 = 404, /* F32MAT4X4 */ + F64MAT2X2 = 405, /* F64MAT2X2 */ + F64MAT2X3 = 406, /* F64MAT2X3 */ + F64MAT2X4 = 407, /* F64MAT2X4 */ + F64MAT3X2 = 408, /* F64MAT3X2 */ + F64MAT3X3 = 409, /* F64MAT3X3 */ + F64MAT3X4 = 410, /* F64MAT3X4 */ + F64MAT4X2 = 411, /* F64MAT4X2 */ + F64MAT4X3 = 412, /* F64MAT4X3 */ + F64MAT4X4 = 413, /* F64MAT4X4 */ + ATOMIC_UINT = 414, /* ATOMIC_UINT */ + ACCSTRUCTNV = 415, /* ACCSTRUCTNV */ + ACCSTRUCTEXT = 416, /* ACCSTRUCTEXT */ + RAYQUERYEXT = 417, /* RAYQUERYEXT */ + FCOOPMATNV = 418, /* FCOOPMATNV */ + ICOOPMATNV = 419, /* ICOOPMATNV */ + UCOOPMATNV = 420, /* UCOOPMATNV */ + SAMPLERCUBEARRAY = 421, /* SAMPLERCUBEARRAY */ + SAMPLERCUBEARRAYSHADOW = 422, /* SAMPLERCUBEARRAYSHADOW */ + ISAMPLERCUBEARRAY = 423, /* ISAMPLERCUBEARRAY */ + USAMPLERCUBEARRAY = 424, /* USAMPLERCUBEARRAY */ + SAMPLER1D = 425, /* SAMPLER1D */ + SAMPLER1DARRAY = 426, /* SAMPLER1DARRAY */ + SAMPLER1DARRAYSHADOW = 427, /* SAMPLER1DARRAYSHADOW */ + ISAMPLER1D = 428, /* ISAMPLER1D */ + SAMPLER1DSHADOW = 429, /* SAMPLER1DSHADOW */ + SAMPLER2DRECT = 430, /* SAMPLER2DRECT */ + SAMPLER2DRECTSHADOW = 431, /* SAMPLER2DRECTSHADOW */ + ISAMPLER2DRECT = 432, /* ISAMPLER2DRECT */ + USAMPLER2DRECT = 433, /* USAMPLER2DRECT */ + SAMPLERBUFFER = 434, /* SAMPLERBUFFER */ + ISAMPLERBUFFER = 435, /* ISAMPLERBUFFER */ + USAMPLERBUFFER = 436, /* USAMPLERBUFFER */ + SAMPLER2DMS = 437, /* SAMPLER2DMS */ + ISAMPLER2DMS = 438, /* ISAMPLER2DMS */ + USAMPLER2DMS = 439, /* USAMPLER2DMS */ + SAMPLER2DMSARRAY = 440, /* SAMPLER2DMSARRAY */ + ISAMPLER2DMSARRAY = 441, /* ISAMPLER2DMSARRAY */ + USAMPLER2DMSARRAY = 442, /* USAMPLER2DMSARRAY */ + SAMPLEREXTERNALOES = 443, /* SAMPLEREXTERNALOES */ + SAMPLEREXTERNAL2DY2YEXT = 444, /* SAMPLEREXTERNAL2DY2YEXT */ + ISAMPLER1DARRAY = 445, /* ISAMPLER1DARRAY */ + USAMPLER1D = 446, /* USAMPLER1D */ + USAMPLER1DARRAY = 447, /* USAMPLER1DARRAY */ + F16SAMPLER1D = 448, /* F16SAMPLER1D */ + F16SAMPLER2D = 449, /* F16SAMPLER2D */ + F16SAMPLER3D = 450, /* F16SAMPLER3D */ + F16SAMPLER2DRECT = 451, /* F16SAMPLER2DRECT */ + F16SAMPLERCUBE = 452, /* F16SAMPLERCUBE */ + F16SAMPLER1DARRAY = 453, /* F16SAMPLER1DARRAY */ + F16SAMPLER2DARRAY = 454, /* F16SAMPLER2DARRAY */ + F16SAMPLERCUBEARRAY = 455, /* F16SAMPLERCUBEARRAY */ + F16SAMPLERBUFFER = 456, /* F16SAMPLERBUFFER */ + F16SAMPLER2DMS = 457, /* F16SAMPLER2DMS */ + F16SAMPLER2DMSARRAY = 458, /* F16SAMPLER2DMSARRAY */ + F16SAMPLER1DSHADOW = 459, /* F16SAMPLER1DSHADOW */ + F16SAMPLER2DSHADOW = 460, /* F16SAMPLER2DSHADOW */ + F16SAMPLER1DARRAYSHADOW = 461, /* F16SAMPLER1DARRAYSHADOW */ + F16SAMPLER2DARRAYSHADOW = 462, /* F16SAMPLER2DARRAYSHADOW */ + F16SAMPLER2DRECTSHADOW = 463, /* F16SAMPLER2DRECTSHADOW */ + F16SAMPLERCUBESHADOW = 464, /* F16SAMPLERCUBESHADOW */ + F16SAMPLERCUBEARRAYSHADOW = 465, /* F16SAMPLERCUBEARRAYSHADOW */ + IMAGE1D = 466, /* IMAGE1D */ + IIMAGE1D = 467, /* IIMAGE1D */ + UIMAGE1D = 468, /* UIMAGE1D */ + IMAGE2D = 469, /* IMAGE2D */ + IIMAGE2D = 470, /* IIMAGE2D */ + UIMAGE2D = 471, /* UIMAGE2D */ + IMAGE3D = 472, /* IMAGE3D */ + IIMAGE3D = 473, /* IIMAGE3D */ + UIMAGE3D = 474, /* UIMAGE3D */ + IMAGE2DRECT = 475, /* IMAGE2DRECT */ + IIMAGE2DRECT = 476, /* IIMAGE2DRECT */ + UIMAGE2DRECT = 477, /* UIMAGE2DRECT */ + IMAGECUBE = 478, /* IMAGECUBE */ + IIMAGECUBE = 479, /* IIMAGECUBE */ + UIMAGECUBE = 480, /* UIMAGECUBE */ + IMAGEBUFFER = 481, /* IMAGEBUFFER */ + IIMAGEBUFFER = 482, /* IIMAGEBUFFER */ + UIMAGEBUFFER = 483, /* UIMAGEBUFFER */ + IMAGE1DARRAY = 484, /* IMAGE1DARRAY */ + IIMAGE1DARRAY = 485, /* IIMAGE1DARRAY */ + UIMAGE1DARRAY = 486, /* UIMAGE1DARRAY */ + IMAGE2DARRAY = 487, /* IMAGE2DARRAY */ + IIMAGE2DARRAY = 488, /* IIMAGE2DARRAY */ + UIMAGE2DARRAY = 489, /* UIMAGE2DARRAY */ + IMAGECUBEARRAY = 490, /* IMAGECUBEARRAY */ + IIMAGECUBEARRAY = 491, /* IIMAGECUBEARRAY */ + UIMAGECUBEARRAY = 492, /* UIMAGECUBEARRAY */ + IMAGE2DMS = 493, /* IMAGE2DMS */ + IIMAGE2DMS = 494, /* IIMAGE2DMS */ + UIMAGE2DMS = 495, /* UIMAGE2DMS */ + IMAGE2DMSARRAY = 496, /* IMAGE2DMSARRAY */ + IIMAGE2DMSARRAY = 497, /* IIMAGE2DMSARRAY */ + UIMAGE2DMSARRAY = 498, /* UIMAGE2DMSARRAY */ + F16IMAGE1D = 499, /* F16IMAGE1D */ + F16IMAGE2D = 500, /* F16IMAGE2D */ + F16IMAGE3D = 501, /* F16IMAGE3D */ + F16IMAGE2DRECT = 502, /* F16IMAGE2DRECT */ + F16IMAGECUBE = 503, /* F16IMAGECUBE */ + F16IMAGE1DARRAY = 504, /* F16IMAGE1DARRAY */ + F16IMAGE2DARRAY = 505, /* F16IMAGE2DARRAY */ + F16IMAGECUBEARRAY = 506, /* F16IMAGECUBEARRAY */ + F16IMAGEBUFFER = 507, /* F16IMAGEBUFFER */ + F16IMAGE2DMS = 508, /* F16IMAGE2DMS */ + F16IMAGE2DMSARRAY = 509, /* F16IMAGE2DMSARRAY */ + I64IMAGE1D = 510, /* I64IMAGE1D */ + U64IMAGE1D = 511, /* U64IMAGE1D */ + I64IMAGE2D = 512, /* I64IMAGE2D */ + U64IMAGE2D = 513, /* U64IMAGE2D */ + I64IMAGE3D = 514, /* I64IMAGE3D */ + U64IMAGE3D = 515, /* U64IMAGE3D */ + I64IMAGE2DRECT = 516, /* I64IMAGE2DRECT */ + U64IMAGE2DRECT = 517, /* U64IMAGE2DRECT */ + I64IMAGECUBE = 518, /* I64IMAGECUBE */ + U64IMAGECUBE = 519, /* U64IMAGECUBE */ + I64IMAGEBUFFER = 520, /* I64IMAGEBUFFER */ + U64IMAGEBUFFER = 521, /* U64IMAGEBUFFER */ + I64IMAGE1DARRAY = 522, /* I64IMAGE1DARRAY */ + U64IMAGE1DARRAY = 523, /* U64IMAGE1DARRAY */ + I64IMAGE2DARRAY = 524, /* I64IMAGE2DARRAY */ + U64IMAGE2DARRAY = 525, /* U64IMAGE2DARRAY */ + I64IMAGECUBEARRAY = 526, /* I64IMAGECUBEARRAY */ + U64IMAGECUBEARRAY = 527, /* U64IMAGECUBEARRAY */ + I64IMAGE2DMS = 528, /* I64IMAGE2DMS */ + U64IMAGE2DMS = 529, /* U64IMAGE2DMS */ + I64IMAGE2DMSARRAY = 530, /* I64IMAGE2DMSARRAY */ + U64IMAGE2DMSARRAY = 531, /* U64IMAGE2DMSARRAY */ + TEXTURECUBEARRAY = 532, /* TEXTURECUBEARRAY */ + ITEXTURECUBEARRAY = 533, /* ITEXTURECUBEARRAY */ + UTEXTURECUBEARRAY = 534, /* UTEXTURECUBEARRAY */ + TEXTURE1D = 535, /* TEXTURE1D */ + ITEXTURE1D = 536, /* ITEXTURE1D */ + UTEXTURE1D = 537, /* UTEXTURE1D */ + TEXTURE1DARRAY = 538, /* TEXTURE1DARRAY */ + ITEXTURE1DARRAY = 539, /* ITEXTURE1DARRAY */ + UTEXTURE1DARRAY = 540, /* UTEXTURE1DARRAY */ + TEXTURE2DRECT = 541, /* TEXTURE2DRECT */ + ITEXTURE2DRECT = 542, /* ITEXTURE2DRECT */ + UTEXTURE2DRECT = 543, /* UTEXTURE2DRECT */ + TEXTUREBUFFER = 544, /* TEXTUREBUFFER */ + ITEXTUREBUFFER = 545, /* ITEXTUREBUFFER */ + UTEXTUREBUFFER = 546, /* UTEXTUREBUFFER */ + TEXTURE2DMS = 547, /* TEXTURE2DMS */ + ITEXTURE2DMS = 548, /* ITEXTURE2DMS */ + UTEXTURE2DMS = 549, /* UTEXTURE2DMS */ + TEXTURE2DMSARRAY = 550, /* TEXTURE2DMSARRAY */ + ITEXTURE2DMSARRAY = 551, /* ITEXTURE2DMSARRAY */ + UTEXTURE2DMSARRAY = 552, /* UTEXTURE2DMSARRAY */ + F16TEXTURE1D = 553, /* F16TEXTURE1D */ + F16TEXTURE2D = 554, /* F16TEXTURE2D */ + F16TEXTURE3D = 555, /* F16TEXTURE3D */ + F16TEXTURE2DRECT = 556, /* F16TEXTURE2DRECT */ + F16TEXTURECUBE = 557, /* F16TEXTURECUBE */ + F16TEXTURE1DARRAY = 558, /* F16TEXTURE1DARRAY */ + F16TEXTURE2DARRAY = 559, /* F16TEXTURE2DARRAY */ + F16TEXTURECUBEARRAY = 560, /* F16TEXTURECUBEARRAY */ + F16TEXTUREBUFFER = 561, /* F16TEXTUREBUFFER */ + F16TEXTURE2DMS = 562, /* F16TEXTURE2DMS */ + F16TEXTURE2DMSARRAY = 563, /* F16TEXTURE2DMSARRAY */ + SUBPASSINPUT = 564, /* SUBPASSINPUT */ + SUBPASSINPUTMS = 565, /* SUBPASSINPUTMS */ + ISUBPASSINPUT = 566, /* ISUBPASSINPUT */ + ISUBPASSINPUTMS = 567, /* ISUBPASSINPUTMS */ + USUBPASSINPUT = 568, /* USUBPASSINPUT */ + USUBPASSINPUTMS = 569, /* USUBPASSINPUTMS */ + F16SUBPASSINPUT = 570, /* F16SUBPASSINPUT */ + F16SUBPASSINPUTMS = 571, /* F16SUBPASSINPUTMS */ + SPIRV_INSTRUCTION = 572, /* SPIRV_INSTRUCTION */ + SPIRV_EXECUTION_MODE = 573, /* SPIRV_EXECUTION_MODE */ + SPIRV_EXECUTION_MODE_ID = 574, /* SPIRV_EXECUTION_MODE_ID */ + SPIRV_DECORATE = 575, /* SPIRV_DECORATE */ + SPIRV_DECORATE_ID = 576, /* SPIRV_DECORATE_ID */ + SPIRV_DECORATE_STRING = 577, /* SPIRV_DECORATE_STRING */ + SPIRV_TYPE = 578, /* SPIRV_TYPE */ + SPIRV_STORAGE_CLASS = 579, /* SPIRV_STORAGE_CLASS */ + SPIRV_BY_REFERENCE = 580, /* SPIRV_BY_REFERENCE */ + SPIRV_LITERAL = 581, /* SPIRV_LITERAL */ + LEFT_OP = 582, /* LEFT_OP */ + RIGHT_OP = 583, /* RIGHT_OP */ + INC_OP = 584, /* INC_OP */ + DEC_OP = 585, /* DEC_OP */ + LE_OP = 586, /* LE_OP */ + GE_OP = 587, /* GE_OP */ + EQ_OP = 588, /* EQ_OP */ + NE_OP = 589, /* NE_OP */ + AND_OP = 590, /* AND_OP */ + OR_OP = 591, /* OR_OP */ + XOR_OP = 592, /* XOR_OP */ + MUL_ASSIGN = 593, /* MUL_ASSIGN */ + DIV_ASSIGN = 594, /* DIV_ASSIGN */ + ADD_ASSIGN = 595, /* ADD_ASSIGN */ + MOD_ASSIGN = 596, /* MOD_ASSIGN */ + LEFT_ASSIGN = 597, /* LEFT_ASSIGN */ + RIGHT_ASSIGN = 598, /* RIGHT_ASSIGN */ + AND_ASSIGN = 599, /* AND_ASSIGN */ + XOR_ASSIGN = 600, /* XOR_ASSIGN */ + OR_ASSIGN = 601, /* OR_ASSIGN */ + SUB_ASSIGN = 602, /* SUB_ASSIGN */ + STRING_LITERAL = 603, /* STRING_LITERAL */ + LEFT_PAREN = 604, /* LEFT_PAREN */ + RIGHT_PAREN = 605, /* RIGHT_PAREN */ + LEFT_BRACKET = 606, /* LEFT_BRACKET */ + RIGHT_BRACKET = 607, /* RIGHT_BRACKET */ + LEFT_BRACE = 608, /* LEFT_BRACE */ + RIGHT_BRACE = 609, /* RIGHT_BRACE */ + DOT = 610, /* DOT */ + COMMA = 611, /* COMMA */ + COLON = 612, /* COLON */ + EQUAL = 613, /* EQUAL */ + SEMICOLON = 614, /* SEMICOLON */ + BANG = 615, /* BANG */ + DASH = 616, /* DASH */ + TILDE = 617, /* TILDE */ + PLUS = 618, /* PLUS */ + STAR = 619, /* STAR */ + SLASH = 620, /* SLASH */ + PERCENT = 621, /* PERCENT */ + LEFT_ANGLE = 622, /* LEFT_ANGLE */ + RIGHT_ANGLE = 623, /* RIGHT_ANGLE */ + VERTICAL_BAR = 624, /* VERTICAL_BAR */ + CARET = 625, /* CARET */ + AMPERSAND = 626, /* AMPERSAND */ + QUESTION = 627, /* QUESTION */ + INVARIANT = 628, /* INVARIANT */ + HIGH_PRECISION = 629, /* HIGH_PRECISION */ + MEDIUM_PRECISION = 630, /* MEDIUM_PRECISION */ + LOW_PRECISION = 631, /* LOW_PRECISION */ + PRECISION = 632, /* PRECISION */ + PACKED = 633, /* PACKED */ + RESOURCE = 634, /* RESOURCE */ + SUPERP = 635, /* SUPERP */ + FLOATCONSTANT = 636, /* FLOATCONSTANT */ + INTCONSTANT = 637, /* INTCONSTANT */ + UINTCONSTANT = 638, /* UINTCONSTANT */ + BOOLCONSTANT = 639, /* BOOLCONSTANT */ + IDENTIFIER = 640, /* IDENTIFIER */ + TYPE_NAME = 641, /* TYPE_NAME */ + CENTROID = 642, /* CENTROID */ + IN = 643, /* IN */ + OUT = 644, /* OUT */ + INOUT = 645, /* INOUT */ + STRUCT = 646, /* STRUCT */ + VOID = 647, /* VOID */ + WHILE = 648, /* WHILE */ + BREAK = 649, /* BREAK */ + CONTINUE = 650, /* CONTINUE */ + DO = 651, /* DO */ + ELSE = 652, /* ELSE */ + FOR = 653, /* FOR */ + IF = 654, /* IF */ + DISCARD = 655, /* DISCARD */ + RETURN = 656, /* RETURN */ + SWITCH = 657, /* SWITCH */ + CASE = 658, /* CASE */ + DEFAULT = 659, /* DEFAULT */ + TERMINATE_INVOCATION = 660, /* TERMINATE_INVOCATION */ + TERMINATE_RAY = 661, /* TERMINATE_RAY */ + IGNORE_INTERSECTION = 662, /* IGNORE_INTERSECTION */ + UNIFORM = 663, /* UNIFORM */ + SHARED = 664, /* SHARED */ + BUFFER = 665, /* BUFFER */ + FLAT = 666, /* FLAT */ + SMOOTH = 667, /* SMOOTH */ + LAYOUT = 668, /* LAYOUT */ + DOUBLECONSTANT = 669, /* DOUBLECONSTANT */ + INT16CONSTANT = 670, /* INT16CONSTANT */ + UINT16CONSTANT = 671, /* UINT16CONSTANT */ + FLOAT16CONSTANT = 672, /* FLOAT16CONSTANT */ + INT32CONSTANT = 673, /* INT32CONSTANT */ + UINT32CONSTANT = 674, /* UINT32CONSTANT */ + INT64CONSTANT = 675, /* INT64CONSTANT */ + UINT64CONSTANT = 676, /* UINT64CONSTANT */ + SUBROUTINE = 677, /* SUBROUTINE */ + DEMOTE = 678, /* DEMOTE */ + PAYLOADNV = 679, /* PAYLOADNV */ + PAYLOADINNV = 680, /* PAYLOADINNV */ + HITATTRNV = 681, /* HITATTRNV */ + CALLDATANV = 682, /* CALLDATANV */ + CALLDATAINNV = 683, /* CALLDATAINNV */ + PAYLOADEXT = 684, /* PAYLOADEXT */ + PAYLOADINEXT = 685, /* PAYLOADINEXT */ + HITATTREXT = 686, /* HITATTREXT */ + CALLDATAEXT = 687, /* CALLDATAEXT */ + CALLDATAINEXT = 688, /* CALLDATAINEXT */ + PATCH = 689, /* PATCH */ + SAMPLE = 690, /* SAMPLE */ + NONUNIFORM = 691, /* NONUNIFORM */ + COHERENT = 692, /* COHERENT */ + VOLATILE = 693, /* VOLATILE */ + RESTRICT = 694, /* RESTRICT */ + READONLY = 695, /* READONLY */ + WRITEONLY = 696, /* WRITEONLY */ + DEVICECOHERENT = 697, /* DEVICECOHERENT */ + QUEUEFAMILYCOHERENT = 698, /* QUEUEFAMILYCOHERENT */ + WORKGROUPCOHERENT = 699, /* WORKGROUPCOHERENT */ + SUBGROUPCOHERENT = 700, /* SUBGROUPCOHERENT */ + NONPRIVATE = 701, /* NONPRIVATE */ + SHADERCALLCOHERENT = 702, /* SHADERCALLCOHERENT */ + NOPERSPECTIVE = 703, /* NOPERSPECTIVE */ + EXPLICITINTERPAMD = 704, /* EXPLICITINTERPAMD */ + PERVERTEXNV = 705, /* PERVERTEXNV */ + PERPRIMITIVENV = 706, /* PERPRIMITIVENV */ + PERVIEWNV = 707, /* PERVIEWNV */ + PERTASKNV = 708, /* PERTASKNV */ + PRECISE = 709 /* PRECISE */ + }; + typedef enum yytokentype yytoken_kind_t; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +union YYSTYPE +{ +#line 97 "MachineIndependent/glslang.y" + + struct { + glslang::TSourceLoc loc; + union { + glslang::TString *string; + int i; + unsigned int u; + long long i64; + unsigned long long u64; + bool b; + double d; + }; + glslang::TSymbol* symbol; + } lex; + struct { + glslang::TSourceLoc loc; + glslang::TOperator op; + union { + TIntermNode* intermNode; + glslang::TIntermNodePair nodePair; + glslang::TIntermTyped* intermTypedNode; + glslang::TAttributes* attributes; + glslang::TSpirvRequirement* spirvReq; + glslang::TSpirvInstruction* spirvInst; + glslang::TSpirvTypeParameters* spirvTypeParams; + }; + union { + glslang::TPublicType type; + glslang::TFunction* function; + glslang::TParameter param; + glslang::TTypeLoc typeLine; + glslang::TTypeList* typeList; + glslang::TArraySizes* arraySizes; + glslang::TIdentifierList* identifierList; + }; + glslang::TArraySizes* typeParameters; + } interm; + +#line 557 "MachineIndependent/glslang_tab.cpp.h" + +}; +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int yyparse (glslang::TParseContext* pParseContext); + +#endif /* !YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED */ diff --git a/libraries/glslang/glslang/MachineIndependent/intermOut.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/intermOut.cpp similarity index 93% rename from libraries/glslang/glslang/MachineIndependent/intermOut.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/intermOut.cpp index 3a93aedafb6..a0fade16c03 100644 --- a/libraries/glslang/glslang/MachineIndependent/intermOut.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/intermOut.cpp @@ -2,6 +2,7 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2016 LunarG, Inc. // Copyright (C) 2017 ARM Limited. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -35,7 +36,7 @@ // POSSIBILITY OF SUCH DAMAGE. // -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) #include "localintermediate.h" #include "../Include/InfoSink.h" @@ -437,6 +438,9 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpConvUint64ToPtr: out.debug << "Convert uint64_t to pointer"; break; case EOpConvPtrToUint64: out.debug << "Convert pointer to uint64_t"; break; + case EOpConvUint64ToAccStruct: out.debug << "Convert uint64_t to acceleration structure"; break; + case EOpConvUvec2ToAccStruct: out.debug << "Convert uvec2 to acceleration strucuture "; break; + case EOpRadians: out.debug << "radians"; break; case EOpDegrees: out.debug << "degrees"; break; case EOpSin: out.debug << "sine"; break; @@ -692,6 +696,10 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpConstructReference: out.debug << "Construct reference type"; break; +#ifndef GLSLANG_WEB + case EOpSpirvInst: out.debug << "spirv_instruction"; break; +#endif + default: out.debug.message(EPrefixError, "Bad unary op"); } @@ -828,6 +836,7 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break; case EOpConstructReference: out.debug << "Construct reference"; break; case EOpConstructCooperativeMatrix: out.debug << "Construct cooperative matrix"; break; + case EOpConstructAccStruct: out.debug << "Construct acceleration structure"; break; case EOpLessThan: out.debug << "Compare Less Than"; break; case EOpGreaterThan: out.debug << "Compare Greater Than"; break; @@ -881,6 +890,7 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpTime: out.debug << "time"; break; case EOpAtomicAdd: out.debug << "AtomicAdd"; break; + case EOpAtomicSubtract: out.debug << "AtomicSubtract"; break; case EOpAtomicMin: out.debug << "AtomicMin"; break; case EOpAtomicMax: out.debug << "AtomicMax"; break; case EOpAtomicAnd: out.debug << "AtomicAnd"; break; @@ -1079,17 +1089,51 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break; case EOpTraceNV: out.debug << "traceNV"; break; - case EOpReportIntersectionNV: out.debug << "reportIntersectionNV"; break; + case EOpTraceRayMotionNV: out.debug << "traceRayMotionNV"; break; + case EOpTraceKHR: out.debug << "traceRayKHR"; break; + case EOpReportIntersection: out.debug << "reportIntersectionNV"; break; case EOpIgnoreIntersectionNV: out.debug << "ignoreIntersectionNV"; break; + case EOpIgnoreIntersectionKHR: out.debug << "ignoreIntersectionKHR"; break; case EOpTerminateRayNV: out.debug << "terminateRayNV"; break; + case EOpTerminateRayKHR: out.debug << "terminateRayKHR"; break; case EOpExecuteCallableNV: out.debug << "executeCallableNV"; break; + case EOpExecuteCallableKHR: out.debug << "executeCallableKHR"; break; case EOpWritePackedPrimitiveIndices4x8NV: out.debug << "writePackedPrimitiveIndices4x8NV"; break; + case EOpRayQueryInitialize: out.debug << "rayQueryInitializeEXT"; break; + case EOpRayQueryTerminate: out.debug << "rayQueryTerminateEXT"; break; + case EOpRayQueryGenerateIntersection: out.debug << "rayQueryGenerateIntersectionEXT"; break; + case EOpRayQueryConfirmIntersection: out.debug << "rayQueryConfirmIntersectionEXT"; break; + case EOpRayQueryProceed: out.debug << "rayQueryProceedEXT"; break; + case EOpRayQueryGetIntersectionType: out.debug << "rayQueryGetIntersectionTypeEXT"; break; + case EOpRayQueryGetRayTMin: out.debug << "rayQueryGetRayTMinEXT"; break; + case EOpRayQueryGetRayFlags: out.debug << "rayQueryGetRayFlagsEXT"; break; + case EOpRayQueryGetIntersectionT: out.debug << "rayQueryGetIntersectionTEXT"; break; + case EOpRayQueryGetIntersectionInstanceCustomIndex: out.debug << "rayQueryGetIntersectionInstanceCustomIndexEXT"; break; + case EOpRayQueryGetIntersectionInstanceId: out.debug << "rayQueryGetIntersectionInstanceIdEXT"; break; + case EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset: out.debug << "rayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetEXT"; break; + case EOpRayQueryGetIntersectionGeometryIndex: out.debug << "rayQueryGetIntersectionGeometryIndexEXT"; break; + case EOpRayQueryGetIntersectionPrimitiveIndex: out.debug << "rayQueryGetIntersectionPrimitiveIndexEXT"; break; + case EOpRayQueryGetIntersectionBarycentrics: out.debug << "rayQueryGetIntersectionBarycentricsEXT"; break; + case EOpRayQueryGetIntersectionFrontFace: out.debug << "rayQueryGetIntersectionFrontFaceEXT"; break; + case EOpRayQueryGetIntersectionCandidateAABBOpaque: out.debug << "rayQueryGetIntersectionCandidateAABBOpaqueEXT"; break; + case EOpRayQueryGetIntersectionObjectRayDirection: out.debug << "rayQueryGetIntersectionObjectRayDirectionEXT"; break; + case EOpRayQueryGetIntersectionObjectRayOrigin: out.debug << "rayQueryGetIntersectionObjectRayOriginEXT"; break; + case EOpRayQueryGetWorldRayDirection: out.debug << "rayQueryGetWorldRayDirectionEXT"; break; + case EOpRayQueryGetWorldRayOrigin: out.debug << "rayQueryGetWorldRayOriginEXT"; break; + case EOpRayQueryGetIntersectionObjectToWorld: out.debug << "rayQueryGetIntersectionObjectToWorldEXT"; break; + case EOpRayQueryGetIntersectionWorldToObject: out.debug << "rayQueryGetIntersectionWorldToObjectEXT"; break; + case EOpCooperativeMatrixLoad: out.debug << "Load cooperative matrix"; break; case EOpCooperativeMatrixStore: out.debug << "Store cooperative matrix"; break; case EOpCooperativeMatrixMulAdd: out.debug << "MulAdd cooperative matrices"; break; case EOpIsHelperInvocation: out.debug << "IsHelperInvocation"; break; + case EOpDebugPrintf: out.debug << "Debug printf"; break; + +#ifndef GLSLANG_WEB + case EOpSpirvInst: out.debug << "spirv_instruction"; break; +#endif default: out.debug.message(EPrefixError, "Bad aggregation op"); } @@ -1295,6 +1339,9 @@ static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const out.debug << buf << "\n"; } break; + case EbtString: + out.debug << "\"" << constUnion[i].getSConst()->c_str() << "\"\n"; + break; default: out.info.message(EPrefixInternalError, "Unknown constant", node->getLoc()); break; @@ -1380,14 +1427,17 @@ bool TOutputTraverser::visitBranch(TVisit /* visit*/, TIntermBranch* node) OutputTreeText(out, node, depth); switch (node->getFlowOp()) { - case EOpKill: out.debug << "Branch: Kill"; break; - case EOpBreak: out.debug << "Branch: Break"; break; - case EOpContinue: out.debug << "Branch: Continue"; break; - case EOpReturn: out.debug << "Branch: Return"; break; - case EOpCase: out.debug << "case: "; break; - case EOpDemote: out.debug << "Demote"; break; - case EOpDefault: out.debug << "default: "; break; - default: out.debug << "Branch: Unknown Branch"; break; + case EOpKill: out.debug << "Branch: Kill"; break; + case EOpTerminateInvocation: out.debug << "Branch: TerminateInvocation"; break; + case EOpIgnoreIntersectionKHR: out.debug << "Branch: IgnoreIntersectionKHR"; break; + case EOpTerminateRayKHR: out.debug << "Branch: TerminateRayKHR"; break; + case EOpBreak: out.debug << "Branch: Break"; break; + case EOpContinue: out.debug << "Branch: Continue"; break; + case EOpReturn: out.debug << "Branch: Return"; break; + case EOpCase: out.debug << "case: "; break; + case EOpDemote: out.debug << "Demote"; break; + case EOpDefault: out.debug << "default: "; break; + default: out.debug << "Branch: Unknown Branch"; break; } if (node->getExpression()) { @@ -1446,6 +1496,9 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) if (xfbMode) infoSink.debug << "in xfb mode\n"; + if (getSubgroupUniformControlFlow()) + infoSink.debug << "subgroup_uniform_control_flow\n"; + switch (language) { case EShLangVertex: break; @@ -1536,4 +1589,4 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) } // end namespace glslang -#endif // not GLSLANG_WEB \ No newline at end of file +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/iomapper.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/iomapper.cpp new file mode 100644 index 00000000000..7e12864f361 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/iomapper.cpp @@ -0,0 +1,1663 @@ +// +// Copyright (C) 2016-2017 LunarG, Inc. +// +// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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 !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + +#include "../Include/Common.h" +#include "../Include/InfoSink.h" +#include "../Include/Types.h" + +#include "gl_types.h" +#include "iomapper.h" +#include "SymbolTable.h" + +// +// Map IO bindings. +// +// High-level algorithm for one stage: +// +// 1. Traverse all code (live+dead) to find the explicitly provided bindings. +// +// 2. Traverse (just) the live code to determine which non-provided bindings +// require auto-numbering. We do not auto-number dead ones. +// +// 3. Traverse all the code to apply the bindings: +// a. explicitly given bindings are offset according to their type +// b. implicit live bindings are auto-numbered into the holes, using +// any open binding slot. +// c. implicit dead bindings are left un-bound. +// + +namespace glslang { + +class TVarGatherTraverser : public TLiveTraverser { +public: + TVarGatherTraverser(const TIntermediate& i, bool traverseDeadCode, TVarLiveMap& inList, TVarLiveMap& outList, TVarLiveMap& uniformList) + : TLiveTraverser(i, traverseDeadCode, true, true, false) + , inputList(inList) + , outputList(outList) + , uniformList(uniformList) + { + } + + virtual void visitSymbol(TIntermSymbol* base) + { + TVarLiveMap* target = nullptr; + if (base->getQualifier().storage == EvqVaryingIn) + target = &inputList; + else if (base->getQualifier().storage == EvqVaryingOut) + target = &outputList; + else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().isPushConstant()) + target = &uniformList; + // If a global is being visited, then we should also traverse it incase it's evaluation + // ends up visiting inputs we want to tag as live + else if (base->getQualifier().storage == EvqGlobal) + addGlobalReference(base->getAccessName()); + + if (target) { + TVarEntryInfo ent = {base->getId(), base, ! traverseAll}; + ent.stage = intermediate.getStage(); + TVarLiveMap::iterator at = target->find( + ent.symbol->getAccessName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById()); + if (at != target->end() && at->second.id == ent.id) + at->second.live = at->second.live || ! traverseAll; // update live state + else + (*target)[ent.symbol->getAccessName()] = ent; + } + } + +private: + TVarLiveMap& inputList; + TVarLiveMap& outputList; + TVarLiveMap& uniformList; +}; + +class TVarSetTraverser : public TLiveTraverser +{ +public: + TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& inList, const TVarLiveMap& outList, const TVarLiveMap& uniformList) + : TLiveTraverser(i, true, true, true, false) + , inputList(inList) + , outputList(outList) + , uniformList(uniformList) + { + } + + virtual void visitSymbol(TIntermSymbol* base) { + const TVarLiveMap* source; + if (base->getQualifier().storage == EvqVaryingIn) + source = &inputList; + else if (base->getQualifier().storage == EvqVaryingOut) + source = &outputList; + else if (base->getQualifier().isUniformOrBuffer()) + source = &uniformList; + else + return; + + TVarEntryInfo ent = { base->getId() }; + // Fix a defect, when block has no instance name, we need to find its block name + TVarLiveMap::const_iterator at = source->find(base->getAccessName()); + if (at == source->end()) + return; + + if (at->second.id != ent.id) + return; + + if (at->second.newBinding != -1) + base->getWritableType().getQualifier().layoutBinding = at->second.newBinding; + if (at->second.newSet != -1) + base->getWritableType().getQualifier().layoutSet = at->second.newSet; + if (at->second.newLocation != -1) + base->getWritableType().getQualifier().layoutLocation = at->second.newLocation; + if (at->second.newComponent != -1) + base->getWritableType().getQualifier().layoutComponent = at->second.newComponent; + if (at->second.newIndex != -1) + base->getWritableType().getQualifier().layoutIndex = at->second.newIndex; + } + + private: + const TVarLiveMap& inputList; + const TVarLiveMap& outputList; + const TVarLiveMap& uniformList; +}; + +struct TNotifyUniformAdaptor +{ + EShLanguage stage; + TIoMapResolver& resolver; + inline TNotifyUniformAdaptor(EShLanguage s, TIoMapResolver& r) + : stage(s) + , resolver(r) + { + } + + inline void operator()(std::pair& entKey) + { + resolver.notifyBinding(stage, entKey.second); + } + +private: + TNotifyUniformAdaptor& operator=(TNotifyUniformAdaptor&) = delete; +}; + +struct TNotifyInOutAdaptor +{ + EShLanguage stage; + TIoMapResolver& resolver; + inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r) + : stage(s) + , resolver(r) + { + } + + inline void operator()(std::pair& entKey) + { + resolver.notifyInOut(entKey.second.stage, entKey.second); + } + +private: + TNotifyInOutAdaptor& operator=(TNotifyInOutAdaptor&) = delete; +}; + +struct TResolverUniformAdaptor { + TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TVarLiveMap* uniform[EShLangCount], TInfoSink& i, bool& e) + : stage(s) + , resolver(r) + , infoSink(i) + , error(e) + { + memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*))); + } + + inline void operator()(std::pair& entKey) { + TVarEntryInfo& ent = entKey.second; + ent.newLocation = -1; + ent.newComponent = -1; + ent.newBinding = -1; + ent.newSet = -1; + ent.newIndex = -1; + const bool isValid = resolver.validateBinding(stage, ent); + if (isValid) { + resolver.resolveSet(ent.stage, ent); + resolver.resolveBinding(ent.stage, ent); + resolver.resolveUniformLocation(ent.stage, ent); + + if (ent.newBinding != -1) { + if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) { + TString err = "mapped binding out of range: " + entKey.first; + + infoSink.info.message(EPrefixInternalError, err.c_str()); + error = true; + } + + if (ent.symbol->getQualifier().hasBinding()) { + for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) { + if (idx == ent.stage || uniformVarMap[idx] == nullptr) + continue; + auto entKey2 = uniformVarMap[idx]->find(entKey.first); + if (entKey2 != uniformVarMap[idx]->end()) { + entKey2->second.newBinding = ent.newBinding; + } + } + } + } + if (ent.newSet != -1) { + if (ent.newSet >= int(TQualifier::layoutSetEnd)) { + TString err = "mapped set out of range: " + entKey.first; + + infoSink.info.message(EPrefixInternalError, err.c_str()); + error = true; + } + if (ent.symbol->getQualifier().hasSet()) { + for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) { + if ((idx == stage) || (uniformVarMap[idx] == nullptr)) + continue; + auto entKey2 = uniformVarMap[idx]->find(entKey.first); + if (entKey2 != uniformVarMap[idx]->end()) { + entKey2->second.newSet = ent.newSet; + } + } + } + } + } else { + TString errorMsg = "Invalid binding: " + entKey.first; + infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); + error = true; + } + } + + inline void setStage(EShLanguage s) { stage = s; } + + EShLanguage stage; + TIoMapResolver& resolver; + TInfoSink& infoSink; + bool& error; + TVarLiveMap* uniformVarMap[EShLangCount]; +private: + TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&) = delete; +}; + +struct TResolverInOutAdaptor { + TResolverInOutAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e) + : stage(s) + , resolver(r) + , infoSink(i) + , error(e) + { + } + + inline void operator()(std::pair& entKey) + { + TVarEntryInfo& ent = entKey.second; + ent.newLocation = -1; + ent.newComponent = -1; + ent.newBinding = -1; + ent.newSet = -1; + ent.newIndex = -1; + const bool isValid = resolver.validateInOut(ent.stage, ent); + if (isValid) { + resolver.resolveInOutLocation(stage, ent); + resolver.resolveInOutComponent(stage, ent); + resolver.resolveInOutIndex(stage, ent); + } else { + TString errorMsg; + if (ent.symbol->getType().getQualifier().semanticName != nullptr) { + errorMsg = "Invalid shader In/Out variable semantic: "; + errorMsg += ent.symbol->getType().getQualifier().semanticName; + } else { + errorMsg = "Invalid shader In/Out variable: "; + errorMsg += ent.symbol->getName(); + } + infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); + error = true; + } + } + + inline void setStage(EShLanguage s) { stage = s; } + + EShLanguage stage; + TIoMapResolver& resolver; + TInfoSink& infoSink; + bool& error; + +private: + TResolverInOutAdaptor& operator=(TResolverInOutAdaptor&) = delete; +}; + +// The class is used for reserving explicit uniform locations and ubo/ssbo/opaque bindings +// xxTODO: maybe this logic should be moved into the resolver's "validateInOut" and "validateUniform" + +struct TSymbolValidater +{ + TSymbolValidater(TIoMapResolver& r, TInfoSink& i, TVarLiveMap* in[EShLangCount], TVarLiveMap* out[EShLangCount], + TVarLiveMap* uniform[EShLangCount], bool& hadError, EProfile profile, int version) + : resolver(r) + , infoSink(i) + , hadError(hadError) + , profile(profile) + , version(version) + { + memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*))); + memcpy(outVarMaps, out, EShLangCount * (sizeof(TVarLiveMap*))); + memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*))); + + std::map anonymousMemberMap; + std::vector usedUniformLocation; + std::vector usedUniformName; + usedUniformLocation.clear(); + usedUniformName.clear(); + for (int i = 0; i < EShLangCount; i++) { + if (uniformVarMap[i]) { + for (auto uniformVar : *uniformVarMap[i]) + { + TIntermSymbol* pSymbol = uniformVar.second.symbol; + TQualifier qualifier = uniformVar.second.symbol->getQualifier(); + TString symbolName = pSymbol->getAccessName(); + + // All the uniform needs multi-stage location check (block/default) + int uniformLocation = qualifier.layoutLocation; + + if (uniformLocation != TQualifier::layoutLocationEnd) { + // Total size of current uniform, could be block, struct or other types. + int size = TIntermediate::computeTypeUniformLocationSize(pSymbol->getType()); + + TRange locationRange(uniformLocation, uniformLocation + size - 1); + + // Combine location and component ranges + int overlapLocation = -1; + bool diffLocation = false; + + // Check for collisions, except for vertex inputs on desktop targeting OpenGL + overlapLocation = checkLocationOverlap(locationRange, usedUniformLocation, symbolName, usedUniformName, diffLocation); + + // Overlap locations of uniforms, regardless of components (multi stages) + if (overlapLocation == -1) { + usedUniformLocation.push_back(locationRange); + usedUniformName.push_back(symbolName); + } + else if (overlapLocation >= 0) { + if (diffLocation == true) { + TString err = ("Uniform location should be equal for same uniforms: " +std::to_string(overlapLocation)).c_str(); + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + break; + } + else { + TString err = ("Uniform location overlaps across stages: " + std::to_string(overlapLocation)).c_str(); + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + break; + } + } + } + + if ((uniformVar.second.symbol->getBasicType() == EbtBlock) && + IsAnonymous(uniformVar.second.symbol->getName())) + { + auto blockType = uniformVar.second.symbol->getType().getStruct(); + for (size_t memberIdx = 0; memberIdx < blockType->size(); ++memberIdx) { + auto memberName = (*blockType)[memberIdx].type->getFieldName(); + if (anonymousMemberMap.find(memberName) != anonymousMemberMap.end()) + { + if (anonymousMemberMap[memberName] != uniformVar.second.symbol->getType().getTypeName()) + { + TString err = "Invalid block member name: " + memberName; + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + break; + } + } + else + { + anonymousMemberMap[memberName] = uniformVar.second.symbol->getType().getTypeName(); + } + } + } + if (hadError) + break; + } + } + } + } + + // In case we need to new an intermediate, which costs too much + int checkLocationOverlap(const TRange& locationRange, std::vector& usedUniformLocation, const TString symbolName, std::vector& usedUniformName, bool& diffLocation) + { + for (size_t r = 0; r < usedUniformLocation.size(); ++r) { + if (usedUniformName[r] == symbolName) { + diffLocation = true; + return (usedUniformLocation[r].start == locationRange.start && + usedUniformLocation[r].last == locationRange.last) + ? -2 : std::max(locationRange.start, usedUniformLocation[r].start); + } + if (locationRange.overlap(usedUniformLocation[r])) { + // there is a collision; pick one + return std::max(locationRange.start, usedUniformLocation[r].start); + } + } + + return -1; // no collision + } + + inline void operator()(std::pair& entKey) { + TVarEntryInfo& ent1 = entKey.second; + TIntermSymbol* base = ent1.symbol; + const TType& type = ent1.symbol->getType(); + const TString& name = entKey.first; + TString mangleName1, mangleName2; + EShLanguage stage = ent1.stage; + EShLanguage preStage, currentStage, nextStage; + + preStage = EShLangCount; + for (int i = stage - 1; i >= 0; i--) { + if (inVarMaps[i] != nullptr) { + preStage = static_cast(i); + break; + } + } + currentStage = stage; + nextStage = EShLangCount; + for (int i = stage + 1; i < EShLangCount; i++) { + if (inVarMaps[i] != nullptr) { + nextStage = static_cast(i); + break; + } + } + + if (type.getQualifier().isArrayedIo(stage)) { + TType subType(type, 0); + subType.appendMangledName(mangleName1); + } else { + type.appendMangledName(mangleName1); + } + + + // basic checking that symbols match + // more extensive checking in the link stage + if (base->getQualifier().storage == EvqVaryingIn) { + // validate stage in; + if (preStage == EShLangCount) + return; + if (TSymbolTable::isBuiltInSymbol(base->getId())) + return; + if (outVarMaps[preStage] != nullptr) { + auto ent2 = outVarMaps[preStage]->find(name); + uint32_t location = base->getType().getQualifier().layoutLocation; + if (ent2 == outVarMaps[preStage]->end() && + location != glslang::TQualifier::layoutLocationEnd) { + for (auto var = outVarMaps[preStage]->begin(); var != ent2; var++) { + if (var->second.symbol->getType().getQualifier().layoutLocation == location) { + ent2 = var; + break; + } + } + } + if (ent2 != outVarMaps[preStage]->end()) { + auto& type1 = base->getType(); + auto& type2 = ent2->second.symbol->getType(); + hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false); + if (ent2->second.symbol->getType().getQualifier().isArrayedIo(preStage)) { + TType subType(ent2->second.symbol->getType(), 0); + subType.appendMangledName(mangleName2); + } else { + ent2->second.symbol->getType().appendMangledName(mangleName2); + } + + if (mangleName1 == mangleName2) { + // For ES 3.0 only, other versions have no such restrictions + // According to ES 3.0 spec: The type and presence of the interpolation qualifiers and + // storage qualifiers of variables with the same name declared in all linked shaders must + // match, otherwise the link command will fail. + if (profile == EEsProfile && version == 300) { + // Don't need to check smooth qualifier, as it uses the default interpolation mode + if (ent1.stage == EShLangFragment && type1.isBuiltIn() == false) { + if (type1.getQualifier().flat != type2.getQualifier().flat || + type1.getQualifier().nopersp != type2.getQualifier().nopersp) { + TString err = "Interpolation qualifier mismatch : " + entKey.first; + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + } + } + } + return; + } + else { + TString err = "Invalid In/Out variable type : " + entKey.first; + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + } + } + else if (!base->getType().isBuiltIn()) { + // According to spec: A link error is generated if any statically referenced input variable + // or block does not have a matching output + if (profile == EEsProfile && ent1.live) { + hadError = true; + TString errorStr = name + ": not been declare as a output variable in pre shader stage."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + } + } + return; + } + } else if (base->getQualifier().storage == EvqVaryingOut) { + // validate stage out; + if (nextStage == EShLangCount) + return; + if (TSymbolTable::isBuiltInSymbol(base->getId())) + return; + if (inVarMaps[nextStage] != nullptr) { + auto ent2 = inVarMaps[nextStage]->find(name); + if (ent2 != inVarMaps[nextStage]->end()) { + if (ent2->second.symbol->getType().getQualifier().isArrayedIo(nextStage)) { + TType subType(ent2->second.symbol->getType(), 0); + subType.appendMangledName(mangleName2); + } else { + ent2->second.symbol->getType().appendMangledName(mangleName2); + } + if (mangleName1 == mangleName2) + return; + else { + TString err = "Invalid In/Out variable type : " + entKey.first; + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + } + } + return; + } + } else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().isPushConstant()) { + // validate uniform type; + for (int i = 0; i < EShLangCount; i++) { + if (i != currentStage && outVarMaps[i] != nullptr) { + auto ent2 = uniformVarMap[i]->find(name); + if (ent2 != uniformVarMap[i]->end()) { + ent2->second.symbol->getType().appendMangledName(mangleName2); + if (mangleName1 != mangleName2) { + ent2->second.symbol->getType().sameElementType(type); + TString err = "Invalid Uniform variable type : " + entKey.first; + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + } + mangleName2.clear(); + + // validate instance name of blocks + if (hadError == false && + base->getType().getBasicType() == EbtBlock && + IsAnonymous(base->getName()) != IsAnonymous(ent2->second.symbol->getName())) { + TString err = "Matched uniform block names must also either all be lacking " + "an instance name or all having an instance name: " + entKey.first; + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + } + + // validate uniform block member qualifier and member names + auto& type1 = base->getType(); + auto& type2 = ent2->second.symbol->getType(); + if (hadError == false && base->getType().getBasicType() == EbtBlock) { + hadError = hadError || typeCheck(&type1, &type2, name.c_str(), true); + } + else { + hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false); + } + } + else if (base->getBasicType() == EbtBlock) + { + if (IsAnonymous(base->getName())) + { + // The name of anonymous block member can't same with default uniform variable. + auto blockType1 = base->getType().getStruct(); + for (size_t memberIdx = 0; memberIdx < blockType1->size(); ++memberIdx) { + auto memberName = (*blockType1)[memberIdx].type->getFieldName(); + if (uniformVarMap[i]->find(memberName) != uniformVarMap[i]->end()) + { + TString err = "Invalid Uniform variable name : " + memberName; + infoSink.info.message(EPrefixInternalError, err.c_str()); + hadError = true; + break; + } + } + } + } + } + } + } + } + + TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], *uniformVarMap[EShLangCount]; + + // Use for mark current shader stage for resolver + TIoMapResolver& resolver; + TInfoSink& infoSink; + bool& hadError; + EProfile profile; + int version; + +private: + TSymbolValidater& operator=(TSymbolValidater&) = delete; + + bool qualifierCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock) + { + bool hasError = false; + const TQualifier& qualifier1 = type1->getQualifier(); + const TQualifier& qualifier2 = type2->getQualifier(); + + if (((isBlock == false) && + (type1->getQualifier().storage == EvqUniform && type2->getQualifier().storage == EvqUniform)) || + (type1->getQualifier().storage == EvqGlobal && type2->getQualifier().storage == EvqGlobal)) { + if (qualifier1.precision != qualifier2.precision) { + hasError = true; + std::string errorStr = name + ": have precision conflict cross stage."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + } + if (qualifier1.hasFormat() && qualifier2.hasFormat()) { + if (qualifier1.layoutFormat != qualifier2.layoutFormat) { + hasError = true; + std::string errorStr = name + ": have layout format conflict cross stage."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + } + + } + } + + if (isBlock == true) { + if (qualifier1.layoutPacking != qualifier2.layoutPacking) { + hasError = true; + std::string errorStr = name + ": have layoutPacking conflict cross stage."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + } + if (qualifier1.layoutMatrix != qualifier2.layoutMatrix) { + hasError = true; + std::string errorStr = name + ": have layoutMatrix conflict cross stage."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + } + if (qualifier1.layoutOffset != qualifier2.layoutOffset) { + hasError = true; + std::string errorStr = name + ": have layoutOffset conflict cross stage."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + } + if (qualifier1.layoutAlign != qualifier2.layoutAlign) { + hasError = true; + std::string errorStr = name + ": have layoutAlign conflict cross stage."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + } + } + + return hasError; + } + + bool typeCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock) + { + bool hasError = false; + if (!(type1->isStruct() && type2->isStruct())) { + hasError = hasError || qualifierCheck(type1, type2, name, isBlock); + } + else { + if (type1->getBasicType() == EbtBlock && type2->getBasicType() == EbtBlock) + isBlock = true; + const TTypeList* typeList1 = type1->getStruct(); + const TTypeList* typeList2 = type2->getStruct(); + + std::string newName = name; + size_t memberCount = typeList1->size(); + size_t index2 = 0; + for (size_t index = 0; index < memberCount; index++, index2++) { + // Skip inactive member + if (typeList1->at(index).type->getBasicType() == EbtVoid) + continue; + while (index2 < typeList2->size() && typeList2->at(index2).type->getBasicType() == EbtVoid) { + ++index2; + } + + // TypeList1 has more members in list + if (index2 == typeList2->size()) { + std::string errorStr = name + ": struct mismatch."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + hasError = true; + break; + } + + if (typeList1->at(index).type->getFieldName() != typeList2->at(index2).type->getFieldName()) { + std::string errorStr = name + ": member name mismatch."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + hasError = true; + } + else { + newName = typeList1->at(index).type->getFieldName().c_str(); + } + hasError = hasError || typeCheck(typeList1->at(index).type, typeList2->at(index2).type, newName, isBlock); + } + + while (index2 < typeList2->size()) + { + // TypeList2 has more members + if (typeList2->at(index2).type->getBasicType() != EbtVoid) { + std::string errorStr = name + ": struct mismatch."; + infoSink.info.message(EPrefixError, errorStr.c_str()); + hasError = true; + break; + } + ++index2; + } + } + return hasError; + } +}; + +struct TSlotCollector { + TSlotCollector(TIoMapResolver& r, TInfoSink& i) : resolver(r), infoSink(i) { } + + inline void operator()(std::pair& entKey) { + resolver.reserverStorageSlot(entKey.second, infoSink); + resolver.reserverResourceSlot(entKey.second, infoSink); + } + TIoMapResolver& resolver; + TInfoSink& infoSink; + +private: + TSlotCollector& operator=(TSlotCollector&) = delete; +}; + +TDefaultIoResolverBase::TDefaultIoResolverBase(const TIntermediate& intermediate) + : intermediate(intermediate) + , nextUniformLocation(intermediate.getUniformLocationBase()) + , nextInputLocation(0) + , nextOutputLocation(0) +{ + memset(stageMask, false, sizeof(bool) * (EShLangCount + 1)); + memset(stageIntermediates, 0, sizeof(TIntermediate*) * (EShLangCount)); + stageIntermediates[intermediate.getStage()] = &intermediate; +} + +int TDefaultIoResolverBase::getBaseBinding(EShLanguage stage, TResourceType res, unsigned int set) const { + return stageIntermediates[stage] ? selectBaseBinding(stageIntermediates[stage]->getShiftBinding(res), stageIntermediates[stage]->getShiftBindingForSet(res, set)) + : selectBaseBinding(intermediate.getShiftBinding(res), intermediate.getShiftBindingForSet(res, set)); +} + +const std::vector& TDefaultIoResolverBase::getResourceSetBinding(EShLanguage stage) const { + return stageIntermediates[stage] ? stageIntermediates[stage]->getResourceSetBinding() + : intermediate.getResourceSetBinding(); +} + +bool TDefaultIoResolverBase::doAutoBindingMapping() const { return intermediate.getAutoMapBindings(); } + +bool TDefaultIoResolverBase::doAutoLocationMapping() const { return intermediate.getAutoMapLocations(); } + +TDefaultIoResolverBase::TSlotSet::iterator TDefaultIoResolverBase::findSlot(int set, int slot) { + return std::lower_bound(slots[set].begin(), slots[set].end(), slot); +} + +bool TDefaultIoResolverBase::checkEmpty(int set, int slot) { + TSlotSet::iterator at = findSlot(set, slot); + return ! (at != slots[set].end() && *at == slot); +} + +int TDefaultIoResolverBase::reserveSlot(int set, int slot, int size) { + TSlotSet::iterator at = findSlot(set, slot); + // tolerate aliasing, by not double-recording aliases + // (policy about appropriateness of the alias is higher up) + for (int i = 0; i < size; i++) { + if (at == slots[set].end() || *at != slot + i) + at = slots[set].insert(at, slot + i); + ++at; + } + return slot; +} + +int TDefaultIoResolverBase::getFreeSlot(int set, int base, int size) { + TSlotSet::iterator at = findSlot(set, base); + if (at == slots[set].end()) + return reserveSlot(set, base, size); + // look for a big enough gap + for (; at != slots[set].end(); ++at) { + if (*at - base >= size) + break; + base = *at + 1; + } + return reserveSlot(set, base, size); +} + +int TDefaultIoResolverBase::resolveSet(EShLanguage stage, TVarEntryInfo& ent) { + const TType& type = ent.symbol->getType(); + if (type.getQualifier().hasSet()) { + return ent.newSet = type.getQualifier().layoutSet; + } + // If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN) + if (getResourceSetBinding(stage).size() == 1) { + return ent.newSet = atoi(getResourceSetBinding(stage)[0].c_str()); + } + return ent.newSet = 0; +} + +int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) { + const TType& type = ent.symbol->getType(); + const char* name = ent.symbol->getAccessName().c_str(); + // kick out of not doing this + if (! doAutoLocationMapping()) { + return ent.newLocation = -1; + } + // no locations added if already present, a built-in variable, a block, or an opaque + if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock || + type.isAtomic() || (type.containsOpaque() && intermediate.getSpv().openGl == 0)) { + return ent.newLocation = -1; + } + // no locations on blocks of built-in variables + if (type.isStruct()) { + if (type.getStruct()->size() < 1) { + return ent.newLocation = -1; + } + if ((*type.getStruct())[0].type->isBuiltIn()) { + return ent.newLocation = -1; + } + } + int location = intermediate.getUniformLocationOverride(name); + if (location != -1) { + return ent.newLocation = location; + } + location = nextUniformLocation; + nextUniformLocation += TIntermediate::computeTypeUniformLocationSize(type); + return ent.newLocation = location; +} + +int TDefaultIoResolverBase::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) { + const TType& type = ent.symbol->getType(); + // kick out of not doing this + if (! doAutoLocationMapping()) { + return ent.newLocation = -1; + } + + // no locations added if already present, or a built-in variable + if (type.getQualifier().hasLocation() || type.isBuiltIn()) { + return ent.newLocation = -1; + } + + // no locations on blocks of built-in variables + if (type.isStruct()) { + if (type.getStruct()->size() < 1) { + return ent.newLocation = -1; + } + if ((*type.getStruct())[0].type->isBuiltIn()) { + return ent.newLocation = -1; + } + } + // point to the right input or output location counter + int& nextLocation = type.getQualifier().isPipeInput() ? nextInputLocation : nextOutputLocation; + // Placeholder. This does not do proper cross-stage lining up, nor + // work with mixed location/no-location declarations. + int location = nextLocation; + int typeLocationSize; + // Don’t take into account the outer-most array if the stage’s + // interface is automatically an array. + typeLocationSize = computeTypeLocationSize(type, stage); + nextLocation += typeLocationSize; + return ent.newLocation = location; +} + +int TDefaultIoResolverBase::resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) { + return ent.newComponent = -1; +} + +int TDefaultIoResolverBase::resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) { return ent.newIndex = -1; } + +uint32_t TDefaultIoResolverBase::computeTypeLocationSize(const TType& type, EShLanguage stage) { + int typeLocationSize; + // Don’t take into account the outer-most array if the stage’s + // interface is automatically an array. + if (type.getQualifier().isArrayedIo(stage)) { + TType elementType(type, 0); + typeLocationSize = TIntermediate::computeTypeLocationSize(elementType, stage); + } else { + typeLocationSize = TIntermediate::computeTypeLocationSize(type, stage); + } + return typeLocationSize; +} + +//TDefaultGlslIoResolver +TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type) { + if (isImageType(type)) { + return EResImage; + } + if (isTextureType(type)) { + return EResTexture; + } + if (isSsboType(type)) { + return EResSsbo; + } + if (isSamplerType(type)) { + return EResSampler; + } + if (isUboType(type)) { + return EResUbo; + } + return EResCount; +} + +TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate) + : TDefaultIoResolverBase(intermediate) + , preStage(EShLangCount) + , currentStage(EShLangCount) +{ } + +int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) { + const TType& type = ent.symbol->getType(); + const TString& name = ent.symbol->getAccessName(); + if (currentStage != stage) { + preStage = currentStage; + currentStage = stage; + } + // kick out if not doing this + if (! doAutoLocationMapping()) { + return ent.newLocation = -1; + } + // expand the location to each element if the symbol is a struct or array + if (type.getQualifier().hasLocation()) { + return ent.newLocation = type.getQualifier().layoutLocation; + } + // no locations added if already present, or a built-in variable + if (type.isBuiltIn()) { + return ent.newLocation = -1; + } + // no locations on blocks of built-in variables + if (type.isStruct()) { + if (type.getStruct()->size() < 1) { + return ent.newLocation = -1; + } + if ((*type.getStruct())[0].type->isBuiltIn()) { + return ent.newLocation = -1; + } + } + int typeLocationSize = computeTypeLocationSize(type, stage); + int location = type.getQualifier().layoutLocation; + bool hasLocation = false; + EShLanguage keyStage(EShLangCount); + TStorageQualifier storage; + storage = EvqInOut; + if (type.getQualifier().isPipeInput()) { + // If this symbol is a input, search pre stage's out + keyStage = preStage; + } + if (type.getQualifier().isPipeOutput()) { + // If this symbol is a output, search next stage's in + keyStage = currentStage; + } + // The in/out in current stage is not declared with location, but it is possible declared + // with explicit location in other stages, find the storageSlotMap firstly to check whether + // the in/out has location + int resourceKey = buildStorageKey(keyStage, storage); + if (! storageSlotMap[resourceKey].empty()) { + TVarSlotMap::iterator iter = storageSlotMap[resourceKey].find(name); + if (iter != storageSlotMap[resourceKey].end()) { + // If interface resource be found, set it has location and this symbol's new location + // equal the symbol's explicit location declaration in pre or next stage. + // + // vs: out vec4 a; + // fs: layout(..., location = 3,...) in vec4 a; + hasLocation = true; + location = iter->second; + // if we want deal like that: + // vs: layout(location=4) out vec4 a; + // out vec4 b; + // + // fs: in vec4 a; + // layout(location = 4) in vec4 b; + // we need retraverse the map. + } + if (! hasLocation) { + // If interface resource note found, It's mean the location in two stage are both implicit declarat. + // So we should find a new slot for this interface. + // + // vs: out vec4 a; + // fs: in vec4 a; + location = getFreeSlot(resourceKey, 0, typeLocationSize); + storageSlotMap[resourceKey][name] = location; + } + } else { + // the first interface declarated in a program. + TVarSlotMap varSlotMap; + location = getFreeSlot(resourceKey, 0, typeLocationSize); + varSlotMap[name] = location; + storageSlotMap[resourceKey] = varSlotMap; + } + //Update location + return ent.newLocation = location; +} + +int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) { + const TType& type = ent.symbol->getType(); + const TString& name = ent.symbol->getAccessName(); + // kick out of not doing this + if (! doAutoLocationMapping()) { + return ent.newLocation = -1; + } + // expand the location to each element if the symbol is a struct or array + if (type.getQualifier().hasLocation() && (type.isStruct() || type.isArray())) { + return ent.newLocation = type.getQualifier().layoutLocation; + } else { + // no locations added if already present, a built-in variable, a block, or an opaque + if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock || + type.isAtomic() || (type.containsOpaque() && intermediate.getSpv().openGl == 0)) { + return ent.newLocation = -1; + } + // no locations on blocks of built-in variables + if (type.isStruct()) { + if (type.getStruct()->size() < 1) { + return ent.newLocation = -1; + } + if ((*type.getStruct())[0].type->isBuiltIn()) { + return ent.newLocation = -1; + } + } + } + int location = intermediate.getUniformLocationOverride(name.c_str()); + if (location != -1) { + return ent.newLocation = location; + } + + int size = TIntermediate::computeTypeUniformLocationSize(type); + + // The uniform in current stage is not declared with location, but it is possible declared + // with explicit location in other stages, find the storageSlotMap firstly to check whether + // the uniform has location + bool hasLocation = false; + int resourceKey = buildStorageKey(EShLangCount, EvqUniform); + TVarSlotMap& slotMap = storageSlotMap[resourceKey]; + // Check dose shader program has uniform resource + if (! slotMap.empty()) { + // If uniform resource not empty, try find a same name uniform + TVarSlotMap::iterator iter = slotMap.find(name); + if (iter != slotMap.end()) { + // If uniform resource be found, set it has location and this symbol's new location + // equal the uniform's explicit location declaration in other stage. + // + // vs: uniform vec4 a; + // fs: layout(..., location = 3,...) uniform vec4 a; + hasLocation = true; + location = iter->second; + } + if (! hasLocation) { + // No explicit location declaration in other stage. + // So we should find a new slot for this uniform. + // + // vs: uniform vec4 a; + // fs: uniform vec4 a; + location = getFreeSlot(resourceKey, 0, computeTypeLocationSize(type, currentStage)); + storageSlotMap[resourceKey][name] = location; + } + } else { + // the first uniform declaration in a program. + TVarSlotMap varSlotMap; + location = getFreeSlot(resourceKey, 0, size); + varSlotMap[name] = location; + storageSlotMap[resourceKey] = varSlotMap; + } + return ent.newLocation = location; +} + +int TDefaultGlslIoResolver::resolveBinding(EShLanguage stage, TVarEntryInfo& ent) { + const TType& type = ent.symbol->getType(); + const TString& name = ent.symbol->getAccessName(); + // On OpenGL arrays of opaque types take a separate binding for each element + int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1; + TResourceType resource = getResourceType(type); + // don't need to handle uniform symbol, it will be handled in resolveUniformLocation + if (resource == EResUbo && type.getBasicType() != EbtBlock) { + return ent.newBinding = -1; + } + // There is no 'set' qualifier in OpenGL shading language, each resource has its own + // binding name space, so remap the 'set' to resource type which make each resource + // binding is valid from 0 to MAX_XXRESOURCE_BINDINGS + int set = intermediate.getSpv().openGl != 0 ? resource : ent.newSet; + int resourceKey = set; + if (resource < EResCount) { + if (type.getQualifier().hasBinding()) { + int newBinding = reserveSlot(resourceKey, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding, numBindings); + return ent.newBinding = newBinding; + + } else { + // The resource in current stage is not declared with binding, but it is possible declared + // with explicit binding in other stages, find the resourceSlotMap firstly to check whether + // the resource has binding, don't need to allocate if it already has a binding + bool hasBinding = false; + ent.newBinding = -1; // leave as -1 if it isn't set below + + if (! resourceSlotMap[resourceKey].empty()) { + TVarSlotMap::iterator iter = resourceSlotMap[resourceKey].find(name); + if (iter != resourceSlotMap[resourceKey].end()) { + hasBinding = true; + ent.newBinding = iter->second; + } + } + if (!hasBinding && (ent.live && doAutoBindingMapping())) { + // find free slot, the caller did make sure it passes all vars with binding + // first and now all are passed that do not have a binding and needs one + int binding = getFreeSlot(resourceKey, getBaseBinding(stage, resource, set), numBindings); + resourceSlotMap[resourceKey][name] = binding; + ent.newBinding = binding; + } + return ent.newBinding; + } + } + return ent.newBinding = -1; +} + +void TDefaultGlslIoResolver::beginResolve(EShLanguage stage) { + // reset stage state + if (stage == EShLangCount) + preStage = currentStage = stage; + // update stage state + else if (currentStage != stage) { + preStage = currentStage; + currentStage = stage; + } +} + +void TDefaultGlslIoResolver::endResolve(EShLanguage /*stage*/) { + // TODO nothing +} + +void TDefaultGlslIoResolver::beginCollect(EShLanguage stage) { + // reset stage state + if (stage == EShLangCount) + preStage = currentStage = stage; + // update stage state + else if (currentStage != stage) { + preStage = currentStage; + currentStage = stage; + } +} + +void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) { + // TODO nothing +} + +void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) { + const TType& type = ent.symbol->getType(); + const TString& name = ent.symbol->getAccessName(); + TStorageQualifier storage = type.getQualifier().storage; + EShLanguage stage(EShLangCount); + switch (storage) { + case EvqUniform: + if (type.getBasicType() != EbtBlock && type.getQualifier().hasLocation()) { + // + // Reserve the slots for the uniforms who has explicit location + int storageKey = buildStorageKey(EShLangCount, EvqUniform); + int location = type.getQualifier().layoutLocation; + TVarSlotMap& varSlotMap = storageSlotMap[storageKey]; + TVarSlotMap::iterator iter = varSlotMap.find(name); + if (iter == varSlotMap.end()) { + int numLocations = TIntermediate::computeTypeUniformLocationSize(type); + reserveSlot(storageKey, location, numLocations); + varSlotMap[name] = location; + } else { + // Allocate location by name for OpenGL driver, so the uniform in different + // stages should be declared with the same location + if (iter->second != location) { + TString errorMsg = "Invalid location: " + name; + infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); + hasError = true; + } + } + } + break; + case EvqVaryingIn: + case EvqVaryingOut: + // + // Reserve the slots for the inout who has explicit location + if (type.getQualifier().hasLocation()) { + stage = storage == EvqVaryingIn ? preStage : stage; + stage = storage == EvqVaryingOut ? currentStage : stage; + int storageKey = buildStorageKey(stage, EvqInOut); + int location = type.getQualifier().layoutLocation; + TVarSlotMap& varSlotMap = storageSlotMap[storageKey]; + TVarSlotMap::iterator iter = varSlotMap.find(name); + if (iter == varSlotMap.end()) { + int numLocations = TIntermediate::computeTypeUniformLocationSize(type); + reserveSlot(storageKey, location, numLocations); + varSlotMap[name] = location; + } else { + // Allocate location by name for OpenGL driver, so the uniform in different + // stages should be declared with the same location + if (iter->second != location) { + TString errorMsg = "Invalid location: " + name; + infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); + hasError = true; + } + } + } + break; + default: + break; + } +} + +void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) { + const TType& type = ent.symbol->getType(); + const TString& name = ent.symbol->getAccessName(); + TResourceType resource = getResourceType(type); + int set = intermediate.getSpv().openGl != 0 ? resource : resolveSet(ent.stage, ent); + int resourceKey = set; + + if (type.getQualifier().hasBinding()) { + TVarSlotMap& varSlotMap = resourceSlotMap[resourceKey]; + TVarSlotMap::iterator iter = varSlotMap.find(name); + int binding = type.getQualifier().layoutBinding + getBaseBinding(ent.stage, resource, set); + + if (iter == varSlotMap.end()) { + // Reserve the slots for the ubo, ssbo and opaques who has explicit binding + int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1; + varSlotMap[name] = binding; + reserveSlot(resourceKey, binding, numBindings); + } else { + // Allocate binding by name for OpenGL driver, so the resource in different + // stages should be declared with the same binding + if (iter->second != binding) { + TString errorMsg = "Invalid binding: " + name; + infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); + hasError = true; + } + } + } +} + +//TDefaultGlslIoResolver end + +/* + * Basic implementation of glslang::TIoMapResolver that replaces the + * previous offset behavior. + * It does the same, uses the offsets for the corresponding uniform + * types. Also respects the EOptionAutoMapBindings flag and binds + * them if needed. + */ +/* + * Default resolver + */ +struct TDefaultIoResolver : public TDefaultIoResolverBase { + TDefaultIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { } + + bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; } + + TResourceType getResourceType(const glslang::TType& type) override { + if (isImageType(type)) { + return EResImage; + } + if (isTextureType(type)) { + return EResTexture; + } + if (isSsboType(type)) { + return EResSsbo; + } + if (isSamplerType(type)) { + return EResSampler; + } + if (isUboType(type)) { + return EResUbo; + } + return EResCount; + } + + int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) override { + const TType& type = ent.symbol->getType(); + const int set = getLayoutSet(type); + // On OpenGL arrays of opaque types take a seperate binding for each element + int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1; + TResourceType resource = getResourceType(type); + if (resource < EResCount) { + if (type.getQualifier().hasBinding()) { + return ent.newBinding = reserveSlot( + set, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding, numBindings); + } else if (ent.live && doAutoBindingMapping()) { + // find free slot, the caller did make sure it passes all vars with binding + // first and now all are passed that do not have a binding and needs one + return ent.newBinding = getFreeSlot(set, getBaseBinding(stage, resource, set), numBindings); + } + } + return ent.newBinding = -1; + } +}; + +#ifdef ENABLE_HLSL +/******************************************************************************** +The following IO resolver maps types in HLSL register space, as follows: + +t - for shader resource views (SRV) + TEXTURE1D + TEXTURE1DARRAY + TEXTURE2D + TEXTURE2DARRAY + TEXTURE3D + TEXTURECUBE + TEXTURECUBEARRAY + TEXTURE2DMS + TEXTURE2DMSARRAY + STRUCTUREDBUFFER + BYTEADDRESSBUFFER + BUFFER + TBUFFER + +s - for samplers + SAMPLER + SAMPLER1D + SAMPLER2D + SAMPLER3D + SAMPLERCUBE + SAMPLERSTATE + SAMPLERCOMPARISONSTATE + +u - for unordered access views (UAV) + RWBYTEADDRESSBUFFER + RWSTRUCTUREDBUFFER + APPENDSTRUCTUREDBUFFER + CONSUMESTRUCTUREDBUFFER + RWBUFFER + RWTEXTURE1D + RWTEXTURE1DARRAY + RWTEXTURE2D + RWTEXTURE2DARRAY + RWTEXTURE3D + +b - for constant buffer views (CBV) + CBUFFER + CONSTANTBUFFER + ********************************************************************************/ +struct TDefaultHlslIoResolver : public TDefaultIoResolverBase { + TDefaultHlslIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { } + + bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; } + + TResourceType getResourceType(const glslang::TType& type) override { + if (isUavType(type)) { + return EResUav; + } + if (isSrvType(type)) { + return EResTexture; + } + if (isSamplerType(type)) { + return EResSampler; + } + if (isUboType(type)) { + return EResUbo; + } + return EResCount; + } + + int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) override { + const TType& type = ent.symbol->getType(); + const int set = getLayoutSet(type); + TResourceType resource = getResourceType(type); + if (resource < EResCount) { + if (type.getQualifier().hasBinding()) { + return ent.newBinding = reserveSlot(set, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding); + } else if (ent.live && doAutoBindingMapping()) { + // find free slot, the caller did make sure it passes all vars with binding + // first and now all are passed that do not have a binding and needs one + return ent.newBinding = getFreeSlot(set, getBaseBinding(stage, resource, set)); + } + } + return ent.newBinding = -1; + } +}; +#endif + +// Map I/O variables to provided offsets, and make bindings for +// unbound but live variables. +// +// Returns false if the input is too malformed to do this. +bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) { + bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() || + intermediate.getAutoMapLocations(); + // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce + // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true. + for (int res = 0; (res < EResCount && !somethingToDo); ++res) { + somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) || + intermediate.hasShiftBindingForSet(TResourceType(res)); + } + if (! somethingToDo && resolver == nullptr) + return true; + if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) + return false; + TIntermNode* root = intermediate.getTreeRoot(); + if (root == nullptr) + return false; + // if no resolver is provided, use the default resolver with the given shifts and auto map settings + TDefaultIoResolver defaultResolver(intermediate); +#ifdef ENABLE_HLSL + TDefaultHlslIoResolver defaultHlslResolver(intermediate); + if (resolver == nullptr) { + // TODO: use a passed in IO mapper for this + if (intermediate.usingHlslIoMapping()) + resolver = &defaultHlslResolver; + else + resolver = &defaultResolver; + } +#else + resolver = &defaultResolver; +#endif + resolver->addStage(stage, intermediate); + + TVarLiveMap inVarMap, outVarMap, uniformVarMap; + TVarLiveVector inVector, outVector, uniformVector; + TVarGatherTraverser iter_binding_all(intermediate, true, inVarMap, outVarMap, uniformVarMap); + TVarGatherTraverser iter_binding_live(intermediate, false, inVarMap, outVarMap, uniformVarMap); + root->traverse(&iter_binding_all); + iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str()); + while (! iter_binding_live.destinations.empty()) { + TIntermNode* destination = iter_binding_live.destinations.back(); + iter_binding_live.destinations.pop_back(); + destination->traverse(&iter_binding_live); + } + + // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info. + for (auto& var : inVarMap) { inVector.push_back(var); } + std::sort(inVector.begin(), inVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { + return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); + }); + for (auto& var : outVarMap) { outVector.push_back(var); } + std::sort(outVector.begin(), outVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { + return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); + }); + for (auto& var : uniformVarMap) { uniformVector.push_back(var); } + std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { + return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); + }); + bool hadError = false; + TVarLiveMap* dummyUniformVarMap[EShLangCount] = {}; + TNotifyInOutAdaptor inOutNotify(stage, *resolver); + TNotifyUniformAdaptor uniformNotify(stage, *resolver); + TResolverUniformAdaptor uniformResolve(stage, *resolver, dummyUniformVarMap, infoSink, hadError); + TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError); + resolver->beginNotifications(stage); + std::for_each(inVector.begin(), inVector.end(), inOutNotify); + std::for_each(outVector.begin(), outVector.end(), inOutNotify); + std::for_each(uniformVector.begin(), uniformVector.end(), uniformNotify); + resolver->endNotifications(stage); + resolver->beginResolve(stage); + for (auto& var : inVector) { inOutResolve(var); } + std::for_each(inVector.begin(), inVector.end(), [&inVarMap](TVarLivePair p) { + auto at = inVarMap.find(p.second.symbol->getAccessName()); + if (at != inVarMap.end() && p.second.id == at->second.id) + at->second = p.second; + }); + for (auto& var : outVector) { inOutResolve(var); } + std::for_each(outVector.begin(), outVector.end(), [&outVarMap](TVarLivePair p) { + auto at = outVarMap.find(p.second.symbol->getAccessName()); + if (at != outVarMap.end() && p.second.id == at->second.id) + at->second = p.second; + }); + std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve); + std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) { + auto at = uniformVarMap.find(p.second.symbol->getAccessName()); + if (at != uniformVarMap.end() && p.second.id == at->second.id) + at->second = p.second; + }); + resolver->endResolve(stage); + if (!hadError) { + TVarSetTraverser iter_iomap(intermediate, inVarMap, outVarMap, uniformVarMap); + root->traverse(&iter_iomap); + } + return !hadError; +} + +// Map I/O variables to provided offsets, and make bindings for +// unbound but live variables. +// +// Returns false if the input is too malformed to do this. +bool TGlslIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) { + bool somethingToDo = !intermediate.getResourceSetBinding().empty() || + intermediate.getAutoMapBindings() || + intermediate.getAutoMapLocations(); + + // Profile and version are use for symbol validate. + profile = intermediate.getProfile(); + version = intermediate.getVersion(); + + // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce + // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true. + for (int res = 0; (res < EResCount && !somethingToDo); ++res) { + somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) || + intermediate.hasShiftBindingForSet(TResourceType(res)); + } + if (! somethingToDo && resolver == nullptr) { + return true; + } + if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) { + return false; + } + TIntermNode* root = intermediate.getTreeRoot(); + if (root == nullptr) { + return false; + } + // if no resolver is provided, use the default resolver with the given shifts and auto map settings + TDefaultGlslIoResolver defaultResolver(intermediate); +#ifdef ENABLE_HLSL + TDefaultHlslIoResolver defaultHlslResolver(intermediate); + if (resolver == nullptr) { + // TODO: use a passed in IO mapper for this + if (intermediate.usingHlslIoMapping()) + resolver = &defaultHlslResolver; + else + resolver = &defaultResolver; + } +#else + if (resolver == nullptr) { + resolver = &defaultResolver; + } +#endif + resolver->addStage(stage, intermediate); + inVarMaps[stage] = new TVarLiveMap(); outVarMaps[stage] = new TVarLiveMap(); uniformVarMap[stage] = new TVarLiveMap(); + TVarGatherTraverser iter_binding_all(intermediate, true, *inVarMaps[stage], *outVarMaps[stage], + *uniformVarMap[stage]); + TVarGatherTraverser iter_binding_live(intermediate, false, *inVarMaps[stage], *outVarMaps[stage], + *uniformVarMap[stage]); + root->traverse(&iter_binding_all); + iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str()); + while (! iter_binding_live.destinations.empty()) { + TIntermNode* destination = iter_binding_live.destinations.back(); + iter_binding_live.destinations.pop_back(); + destination->traverse(&iter_binding_live); + } + + TNotifyInOutAdaptor inOutNotify(stage, *resolver); + TNotifyUniformAdaptor uniformNotify(stage, *resolver); + // Resolve current stage input symbol location with previous stage output here, + // uniform symbol, ubo, ssbo and opaque symbols are per-program resource, + // will resolve uniform symbol location and ubo/ssbo/opaque binding in doMap() + resolver->beginNotifications(stage); + std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutNotify); + std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutNotify); + std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), uniformNotify); + resolver->endNotifications(stage); + TSlotCollector slotCollector(*resolver, infoSink); + resolver->beginCollect(stage); + std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), slotCollector); + std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), slotCollector); + std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), slotCollector); + resolver->endCollect(stage); + intermediates[stage] = &intermediate; + return !hadError; +} + +bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) { + resolver->endResolve(EShLangCount); + if (!hadError) { + //Resolve uniform location, ubo/ssbo/opaque bindings across stages + TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, uniformVarMap, infoSink, hadError); + TResolverInOutAdaptor inOutResolve(EShLangCount, *resolver, infoSink, hadError); + TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps, + outVarMaps, uniformVarMap, hadError, profile, version); + + TVarLiveVector inVectors[EShLangCount]; + TVarLiveVector outVectors[EShLangCount]; + TVarLiveVector uniformVector; + + resolver->beginResolve(EShLangCount); + for (int stage = EShLangVertex; stage < EShLangCount; stage++) { + if (inVarMaps[stage] != nullptr) { + inOutResolve.setStage(EShLanguage(stage)); + + // copy vars into a sorted list + std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), + [&inVectors, stage](TVarLivePair p) { inVectors[stage].push_back(p); }); + std::sort(inVectors[stage].begin(), inVectors[stage].end(), + [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { + return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); + }); + + std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), + [&outVectors, stage](TVarLivePair p) { outVectors[stage].push_back(p); }); + std::sort(outVectors[stage].begin(), outVectors[stage].end(), + [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { + return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); + }); + + for (auto& var : inVectors[stage]) { symbolValidater(var); } + for (auto& var : inVectors[stage]) { inOutResolve(var); } + for (auto& var : outVectors[stage]) { symbolValidater(var); } + for (auto& var : outVectors[stage]) { inOutResolve(var); } + + // copy results back into maps + std::for_each(inVectors[stage].begin(), inVectors[stage].end(), + [this, stage](TVarLivePair p) { + auto at = inVarMaps[stage]->find(p.first); + if (at != inVarMaps[stage]->end()) + at->second = p.second; + }); + + std::for_each(outVectors[stage].begin(), outVectors[stage].end(), + [this, stage](TVarLivePair p) { + auto at = outVarMaps[stage]->find(p.first); + if (at != outVarMaps[stage]->end()) + at->second = p.second; + }); + + } + if (uniformVarMap[stage] != nullptr) { + uniformResolve.setStage(EShLanguage(stage)); + for (auto& var : *(uniformVarMap[stage])) { uniformVector.push_back(var); } + } + } + std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { + return TVarEntryInfo::TOrderByPriorityAndLive()(p1.second, p2.second); + }); + for (auto& var : uniformVector) { symbolValidater(var); } + for (auto& var : uniformVector) { uniformResolve(var); } + std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { + return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); + }); + resolver->endResolve(EShLangCount); + for (size_t stage = 0; stage < EShLangCount; stage++) { + if (intermediates[stage] != nullptr) { + // traverse each stage, set new location to each input/output and unifom symbol, set new binding to + // ubo, ssbo and opaque symbols + TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap; + std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) { + auto at = pUniformVarMap[stage]->find(p.second.symbol->getAccessName()); + if (at != pUniformVarMap[stage]->end() && at->second.id == p.second.id){ + int resolvedBinding = at->second.newBinding; + at->second = p.second; + if (resolvedBinding > 0) + at->second.newBinding = resolvedBinding; + } + }); + TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage], + *uniformResolve.uniformVarMap[stage]); + intermediates[stage]->getTreeRoot()->traverse(&iter_iomap); + } + } + return !hadError; + } else { + return false; + } +} + +} // end namespace glslang + +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/libraries/glslang/glslang/MachineIndependent/iomapper.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/iomapper.h similarity index 86% rename from libraries/glslang/glslang/MachineIndependent/iomapper.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/iomapper.h index 684e88d5710..07357c2ef43 100644 --- a/libraries/glslang/glslang/MachineIndependent/iomapper.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/iomapper.h @@ -33,7 +33,7 @@ // POSSIBILITY OF SUCH DAMAGE. // -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) #ifndef _IOMAPPER_INCLUDED #define _IOMAPPER_INCLUDED @@ -52,7 +52,7 @@ namespace glslang { class TIntermediate; struct TVarEntryInfo { - int id; + long long id; TIntermSymbol* symbol; bool live; int newBinding; @@ -87,6 +87,35 @@ struct TVarEntryInfo { return lPoints > rPoints; } }; + + struct TOrderByPriorityAndLive { + // ordering: + // 1) do live variables first + // 2) has both binding and set + // 3) has binding but no set + // 4) has no binding but set + // 5) has no binding and no set + inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { + + const TQualifier& lq = l.symbol->getQualifier(); + const TQualifier& rq = r.symbol->getQualifier(); + + // simple rules: + // has binding gives 2 points + // has set gives 1 point + // who has the most points is more important. + int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0); + int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0); + + if (l.live != r.live) + return l.live > r.live; + + if (lPoints != rPoints) + return lPoints > rPoints; + + return l.id < r.id; + } + }; }; // Base class for shared TIoMapResolver services, used by several derivations. @@ -107,8 +136,8 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver { void endCollect(EShLanguage) override {} void reserverResourceSlot(TVarEntryInfo& /*ent*/, TInfoSink& /*infoSink*/) override {} void reserverStorageSlot(TVarEntryInfo& /*ent*/, TInfoSink& /*infoSink*/) override {} - int getBaseBinding(TResourceType res, unsigned int set) const; - const std::vector& getResourceSetBinding() const; + int getBaseBinding(EShLanguage stage, TResourceType res, unsigned int set) const; + const std::vector& getResourceSetBinding(EShLanguage stage) const; virtual TResourceType getResourceType(const glslang::TType& type) = 0; bool doAutoBindingMapping() const; bool doAutoLocationMapping() const; @@ -122,13 +151,16 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver { int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) override; int resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) override; int resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) override; - void addStage(EShLanguage stage) override { - if (stage < EShLangCount) + void addStage(EShLanguage stage, TIntermediate& stageIntermediate) override { + if (stage < EShLangCount) { stageMask[stage] = true; + stageIntermediates[stage] = &stageIntermediate; + } } uint32_t computeTypeLocationSize(const TType& type, EShLanguage stage); TSlotSetMap slots; + bool hasError = false; protected: TDefaultIoResolverBase(TDefaultIoResolverBase&); @@ -138,6 +170,8 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver { int nextInputLocation; int nextOutputLocation; bool stageMask[EShLangCount + 1]; + const TIntermediate* stageIntermediates[EShLangCount]; + // Return descriptor set specific base if there is one, and the generic base otherwise. int selectBaseBinding(int base, int descriptorSetBase) const { return descriptorSetBase != -1 ? descriptorSetBase : base; @@ -185,7 +219,7 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver { } }; -// Defaulf I/O resolver for OpenGL +// Default I/O resolver for OpenGL struct TDefaultGlslIoResolver : public TDefaultIoResolverBase { public: typedef std::map TVarSlotMap; // @@ -237,12 +271,13 @@ typedef std::map TVarLiveMap; // In the future, if the vc++ compiler can handle such a situation, // this part of the code will be removed. struct TVarLivePair : std::pair { - TVarLivePair(std::pair& _Right) : pair(_Right.first, _Right.second) {} + TVarLivePair(const std::pair& _Right) : pair(_Right.first, _Right.second) {} TVarLivePair& operator=(const TVarLivePair& _Right) { const_cast(first) = _Right.first; second = _Right.second; return (*this); } + TVarLivePair(const TVarLivePair& src) : pair(src) { } }; typedef std::vector TVarLiveVector; @@ -264,6 +299,8 @@ class TGlslIoMapper : public TIoMapper { memset(outVarMaps, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1)); memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * (EShLangCount + 1)); memset(intermediates, 0, sizeof(TIntermediate*) * (EShLangCount + 1)); + profile = ENoProfile; + version = 0; } virtual ~TGlslIoMapper() { for (size_t stage = 0; stage < EShLangCount; stage++) { @@ -290,10 +327,12 @@ class TGlslIoMapper : public TIoMapper { *uniformVarMap[EShLangCount]; TIntermediate* intermediates[EShLangCount]; bool hadError = false; + EProfile profile; + int version; }; } // end namespace glslang #endif // _IOMAPPER_INCLUDED -#endif // GLSLANG_WEB +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/libraries/glslang/glslang/MachineIndependent/limits.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/limits.cpp similarity index 96% rename from libraries/glslang/glslang/MachineIndependent/limits.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/limits.cpp index 51d9300341b..391570579da 100644 --- a/libraries/glslang/glslang/MachineIndependent/limits.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/limits.cpp @@ -63,14 +63,14 @@ namespace glslang { class TInductiveTraverser : public TIntermTraverser { public: - TInductiveTraverser(int id, TSymbolTable& st) + TInductiveTraverser(long long id, TSymbolTable& st) : loopId(id), symbolTable(st), bad(false) { } virtual bool visitBinary(TVisit, TIntermBinary* node); virtual bool visitUnary(TVisit, TIntermUnary* node); virtual bool visitAggregate(TVisit, TIntermAggregate* node); - int loopId; // unique ID of the symbol that's the loop inductive variable + long long loopId; // unique ID of the symbol that's the loop inductive variable TSymbolTable& symbolTable; bool bad; TSourceLoc badLoc; @@ -129,7 +129,7 @@ bool TInductiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* n // // External function to call for loop check. // -void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbolTable& symbolTable) +void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, long long loopId, TSymbolTable& symbolTable) { TInductiveTraverser it(loopId, symbolTable); diff --git a/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/linkValidate.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/linkValidate.cpp new file mode 100644 index 00000000000..9656e2e7e0b --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/linkValidate.cpp @@ -0,0 +1,2171 @@ +// +// Copyright (C) 2013 LunarG, Inc. +// Copyright (C) 2017 ARM Limited. +// Copyright (C) 2015-2018 Google, Inc. +// +// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. +// + +// +// Do link-time merging and validation of intermediate representations. +// +// Basic model is that during compilation, each compilation unit (shader) is +// compiled into one TIntermediate instance. Then, at link time, multiple +// units for the same stage can be merged together, which can generate errors. +// Then, after all merging, a single instance of TIntermediate represents +// the whole stage. A final error check can be done on the resulting stage, +// even if no merging was done (i.e., the stage was only one compilation unit). +// + +#include "localintermediate.h" +#include "../Include/InfoSink.h" +#include "SymbolTable.h" + +namespace glslang { + +// +// Link-time error emitter. +// +void TIntermediate::error(TInfoSink& infoSink, const char* message) +{ +#ifndef GLSLANG_WEB + infoSink.info.prefix(EPrefixError); + infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; +#endif + + ++numErrors; +} + +// Link-time warning. +void TIntermediate::warn(TInfoSink& infoSink, const char* message) +{ +#ifndef GLSLANG_WEB + infoSink.info.prefix(EPrefixWarning); + infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; +#endif +} + +// TODO: 4.4 offset/align: "Two blocks linked together in the same program with the same block +// name must have the exact same set of members qualified with offset and their integral-constant +// expression values must be the same, or a link-time error results." + +// +// Merge the information from 'unit' into 'this' +// +void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit) +{ +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + mergeCallGraphs(infoSink, unit); + mergeModes(infoSink, unit); + mergeTrees(infoSink, unit); +#endif +} + +// +// check that link objects between stages +// +void TIntermediate::mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit) { + if (unit.treeRoot == nullptr || treeRoot == nullptr) + return; + + // Get the linker-object lists + TIntermSequence& linkerObjects = findLinkerObjects()->getSequence(); + TIntermSequence unitLinkerObjects = unit.findLinkerObjects()->getSequence(); + + // filter unitLinkerObjects to only contain uniforms + auto end = std::remove_if(unitLinkerObjects.begin(), unitLinkerObjects.end(), + [](TIntermNode* node) {return node->getAsSymbolNode()->getQualifier().storage != EvqUniform && + node->getAsSymbolNode()->getQualifier().storage != EvqBuffer; }); + unitLinkerObjects.resize(end - unitLinkerObjects.begin()); + + // merge uniforms and do error checking + bool mergeExistingOnly = false; + mergeGlobalUniformBlocks(infoSink, unit, mergeExistingOnly); + mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage()); +} + +// +// do error checking on the shader boundary in / out vars +// +void TIntermediate::checkStageIO(TInfoSink& infoSink, TIntermediate& unit) { + if (unit.treeRoot == nullptr || treeRoot == nullptr) + return; + + // Get copies of the linker-object lists + TIntermSequence linkerObjects = findLinkerObjects()->getSequence(); + TIntermSequence unitLinkerObjects = unit.findLinkerObjects()->getSequence(); + + // filter linkerObjects to only contain out variables + auto end = std::remove_if(linkerObjects.begin(), linkerObjects.end(), + [](TIntermNode* node) {return node->getAsSymbolNode()->getQualifier().storage != EvqVaryingOut; }); + linkerObjects.resize(end - linkerObjects.begin()); + + // filter unitLinkerObjects to only contain in variables + auto unitEnd = std::remove_if(unitLinkerObjects.begin(), unitLinkerObjects.end(), + [](TIntermNode* node) {return node->getAsSymbolNode()->getQualifier().storage != EvqVaryingIn; }); + unitLinkerObjects.resize(unitEnd - unitLinkerObjects.begin()); + + // do matching and error checking + mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage()); + + // TODO: final check; make sure that any statically used `in` have matching `out` written to +} + +void TIntermediate::mergeCallGraphs(TInfoSink& infoSink, TIntermediate& unit) +{ + if (unit.getNumEntryPoints() > 0) { + if (getNumEntryPoints() > 0) + error(infoSink, "can't handle multiple entry points per stage"); + else { + entryPointName = unit.getEntryPointName(); + entryPointMangledName = unit.getEntryPointMangledName(); + } + } + numEntryPoints += unit.getNumEntryPoints(); + + callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end()); +} + +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + +#define MERGE_MAX(member) member = std::max(member, unit.member) +#define MERGE_TRUE(member) if (unit.member) member = unit.member; + +void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) +{ + if (language != unit.language) + error(infoSink, "stages must match when linking into a single stage"); + + if (getSource() == EShSourceNone) + setSource(unit.getSource()); + if (getSource() != unit.getSource()) + error(infoSink, "can't link compilation units from different source languages"); + + if (treeRoot == nullptr) { + profile = unit.profile; + version = unit.version; + requestedExtensions = unit.requestedExtensions; + } else { + if ((isEsProfile()) != (unit.isEsProfile())) + error(infoSink, "Cannot cross link ES and desktop profiles"); + else if (unit.profile == ECompatibilityProfile) + profile = ECompatibilityProfile; + version = std::max(version, unit.version); + requestedExtensions.insert(unit.requestedExtensions.begin(), unit.requestedExtensions.end()); + } + + MERGE_MAX(spvVersion.spv); + MERGE_MAX(spvVersion.vulkanGlsl); + MERGE_MAX(spvVersion.vulkan); + MERGE_MAX(spvVersion.openGl); + MERGE_TRUE(spvVersion.vulkanRelaxed); + + numErrors += unit.getNumErrors(); + // Only one push_constant is allowed, mergeLinkerObjects() will ensure the push_constant + // is the same for all units. + if (numPushConstants > 1 || unit.numPushConstants > 1) + error(infoSink, "Only one push_constant block is allowed per stage"); + numPushConstants = std::min(numPushConstants + unit.numPushConstants, 1); + + if (unit.invocations != TQualifier::layoutNotSet) { + if (invocations == TQualifier::layoutNotSet) + invocations = unit.invocations; + else if (invocations != unit.invocations) + error(infoSink, "number of invocations must match between compilation units"); + } + + if (vertices == TQualifier::layoutNotSet) + vertices = unit.vertices; + else if (unit.vertices != TQualifier::layoutNotSet && vertices != unit.vertices) { + if (language == EShLangGeometry || language == EShLangMeshNV) + error(infoSink, "Contradictory layout max_vertices values"); + else if (language == EShLangTessControl) + error(infoSink, "Contradictory layout vertices values"); + else + assert(0); + } + if (primitives == TQualifier::layoutNotSet) + primitives = unit.primitives; + else if (primitives != unit.primitives) { + if (language == EShLangMeshNV) + error(infoSink, "Contradictory layout max_primitives values"); + else + assert(0); + } + + if (inputPrimitive == ElgNone) + inputPrimitive = unit.inputPrimitive; + else if (unit.inputPrimitive != ElgNone && inputPrimitive != unit.inputPrimitive) + error(infoSink, "Contradictory input layout primitives"); + + if (outputPrimitive == ElgNone) + outputPrimitive = unit.outputPrimitive; + else if (unit.outputPrimitive != ElgNone && outputPrimitive != unit.outputPrimitive) + error(infoSink, "Contradictory output layout primitives"); + + if (originUpperLeft != unit.originUpperLeft || pixelCenterInteger != unit.pixelCenterInteger) + error(infoSink, "gl_FragCoord redeclarations must match across shaders"); + + if (vertexSpacing == EvsNone) + vertexSpacing = unit.vertexSpacing; + else if (vertexSpacing != unit.vertexSpacing) + error(infoSink, "Contradictory input vertex spacing"); + + if (vertexOrder == EvoNone) + vertexOrder = unit.vertexOrder; + else if (vertexOrder != unit.vertexOrder) + error(infoSink, "Contradictory triangle ordering"); + + MERGE_TRUE(pointMode); + + for (int i = 0; i < 3; ++i) { + if (unit.localSizeNotDefault[i]) { + if (!localSizeNotDefault[i]) { + localSize[i] = unit.localSize[i]; + localSizeNotDefault[i] = true; + } + else if (localSize[i] != unit.localSize[i]) + error(infoSink, "Contradictory local size"); + } + + if (localSizeSpecId[i] == TQualifier::layoutNotSet) + localSizeSpecId[i] = unit.localSizeSpecId[i]; + else if (localSizeSpecId[i] != unit.localSizeSpecId[i]) + error(infoSink, "Contradictory local size specialization ids"); + } + + MERGE_TRUE(earlyFragmentTests); + MERGE_TRUE(postDepthCoverage); + + if (depthLayout == EldNone) + depthLayout = unit.depthLayout; + else if (depthLayout != unit.depthLayout) + error(infoSink, "Contradictory depth layouts"); + + MERGE_TRUE(depthReplacing); + MERGE_TRUE(hlslFunctionality1); + + blendEquations |= unit.blendEquations; + + MERGE_TRUE(xfbMode); + + for (size_t b = 0; b < xfbBuffers.size(); ++b) { + if (xfbBuffers[b].stride == TQualifier::layoutXfbStrideEnd) + xfbBuffers[b].stride = unit.xfbBuffers[b].stride; + else if (xfbBuffers[b].stride != unit.xfbBuffers[b].stride) + error(infoSink, "Contradictory xfb_stride"); + xfbBuffers[b].implicitStride = std::max(xfbBuffers[b].implicitStride, unit.xfbBuffers[b].implicitStride); + if (unit.xfbBuffers[b].contains64BitType) + xfbBuffers[b].contains64BitType = true; + if (unit.xfbBuffers[b].contains32BitType) + xfbBuffers[b].contains32BitType = true; + if (unit.xfbBuffers[b].contains16BitType) + xfbBuffers[b].contains16BitType = true; + // TODO: 4.4 link: enhanced layouts: compare ranges + } + + MERGE_TRUE(multiStream); + MERGE_TRUE(layoutOverrideCoverage); + MERGE_TRUE(geoPassthroughEXT); + + for (unsigned int i = 0; i < unit.shiftBinding.size(); ++i) { + if (unit.shiftBinding[i] > 0) + setShiftBinding((TResourceType)i, unit.shiftBinding[i]); + } + + for (unsigned int i = 0; i < unit.shiftBindingForSet.size(); ++i) { + for (auto it = unit.shiftBindingForSet[i].begin(); it != unit.shiftBindingForSet[i].end(); ++it) + setShiftBindingForSet((TResourceType)i, it->second, it->first); + } + + resourceSetBinding.insert(resourceSetBinding.end(), unit.resourceSetBinding.begin(), unit.resourceSetBinding.end()); + + MERGE_TRUE(autoMapBindings); + MERGE_TRUE(autoMapLocations); + MERGE_TRUE(invertY); + MERGE_TRUE(flattenUniformArrays); + MERGE_TRUE(useUnknownFormat); + MERGE_TRUE(hlslOffsets); + MERGE_TRUE(useStorageBuffer); + MERGE_TRUE(invariantAll); + MERGE_TRUE(hlslIoMapping); + + // TODO: sourceFile + // TODO: sourceText + // TODO: processes + + MERGE_TRUE(needToLegalize); + MERGE_TRUE(binaryDoubleOutput); + MERGE_TRUE(usePhysicalStorageBuffer); +} + +// +// Merge the 'unit' AST into 'this' AST. +// That includes rationalizing the unique IDs, which were set up independently, +// and might have overlaps that are not the same symbol, or might have different +// IDs for what should be the same shared symbol. +// +void TIntermediate::mergeTrees(TInfoSink& infoSink, TIntermediate& unit) +{ + if (unit.treeRoot == nullptr) + return; + + if (treeRoot == nullptr) { + treeRoot = unit.treeRoot; + return; + } + + // Getting this far means we have two existing trees to merge... + numShaderRecordBlocks += unit.numShaderRecordBlocks; + numTaskNVBlocks += unit.numTaskNVBlocks; + + // Get the top-level globals of each unit + TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence(); + TIntermSequence& unitGlobals = unit.treeRoot->getAsAggregate()->getSequence(); + + // Get the linker-object lists + TIntermSequence& linkerObjects = findLinkerObjects()->getSequence(); + const TIntermSequence& unitLinkerObjects = unit.findLinkerObjects()->getSequence(); + + // Map by global name to unique ID to rationalize the same object having + // differing IDs in different trees. + TIdMaps idMaps; + long long idShift; + seedIdMap(idMaps, idShift); + remapIds(idMaps, idShift + 1, unit); + + mergeBodies(infoSink, globals, unitGlobals); + bool mergeExistingOnly = false; + mergeGlobalUniformBlocks(infoSink, unit, mergeExistingOnly); + mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage()); + ioAccessed.insert(unit.ioAccessed.begin(), unit.ioAccessed.end()); +} + +#endif + +static const TString& getNameForIdMap(TIntermSymbol* symbol) +{ + TShaderInterface si = symbol->getType().getShaderInterface(); + if (si == EsiNone) + return symbol->getName(); + else + return symbol->getType().getTypeName(); +} + + + +// Traverser that seeds an ID map with all built-ins, and tracks the +// maximum ID used, currently using (maximum ID + 1) as new symbol id shift seed. +// Level id will keep same after shifting. +// (It would be nice to put this in a function, but that causes warnings +// on having no bodies for the copy-constructor/operator=.) +class TBuiltInIdTraverser : public TIntermTraverser { +public: + TBuiltInIdTraverser(TIdMaps& idMaps) : idMaps(idMaps), idShift(0) { } + // If it's a built in, add it to the map. + virtual void visitSymbol(TIntermSymbol* symbol) + { + const TQualifier& qualifier = symbol->getType().getQualifier(); + if (qualifier.builtIn != EbvNone) { + TShaderInterface si = symbol->getType().getShaderInterface(); + idMaps[si][getNameForIdMap(symbol)] = symbol->getId(); + } + idShift = (symbol->getId() & ~TSymbolTable::uniqueIdMask) | + std::max(idShift & TSymbolTable::uniqueIdMask, + symbol->getId() & TSymbolTable::uniqueIdMask); + } + long long getIdShift() const { return idShift; } +protected: + TBuiltInIdTraverser(TBuiltInIdTraverser&); + TBuiltInIdTraverser& operator=(TBuiltInIdTraverser&); + TIdMaps& idMaps; + long long idShift; +}; + +// Traverser that seeds an ID map with non-builtins. +// (It would be nice to put this in a function, but that causes warnings +// on having no bodies for the copy-constructor/operator=.) +class TUserIdTraverser : public TIntermTraverser { +public: + TUserIdTraverser(TIdMaps& idMaps) : idMaps(idMaps) { } + // If its a non-built-in global, add it to the map. + virtual void visitSymbol(TIntermSymbol* symbol) + { + const TQualifier& qualifier = symbol->getType().getQualifier(); + if (qualifier.builtIn == EbvNone) { + TShaderInterface si = symbol->getType().getShaderInterface(); + idMaps[si][getNameForIdMap(symbol)] = symbol->getId(); + } + } + +protected: + TUserIdTraverser(TUserIdTraverser&); + TUserIdTraverser& operator=(TUserIdTraverser&); + TIdMaps& idMaps; // over biggest id +}; + +// Initialize the the ID map with what we know of 'this' AST. +void TIntermediate::seedIdMap(TIdMaps& idMaps, long long& idShift) +{ + // all built-ins everywhere need to align on IDs and contribute to the max ID + TBuiltInIdTraverser builtInIdTraverser(idMaps); + treeRoot->traverse(&builtInIdTraverser); + idShift = builtInIdTraverser.getIdShift() & TSymbolTable::uniqueIdMask; + + // user variables in the linker object list need to align on ids + TUserIdTraverser userIdTraverser(idMaps); + findLinkerObjects()->traverse(&userIdTraverser); +} + +// Traverser to map an AST ID to what was known from the seeding AST. +// (It would be nice to put this in a function, but that causes warnings +// on having no bodies for the copy-constructor/operator=.) +class TRemapIdTraverser : public TIntermTraverser { +public: + TRemapIdTraverser(const TIdMaps& idMaps, long long idShift) : idMaps(idMaps), idShift(idShift) { } + // Do the mapping: + // - if the same symbol, adopt the 'this' ID + // - otherwise, ensure a unique ID by shifting to a new space + virtual void visitSymbol(TIntermSymbol* symbol) + { + const TQualifier& qualifier = symbol->getType().getQualifier(); + bool remapped = false; + if (qualifier.isLinkable() || qualifier.builtIn != EbvNone) { + TShaderInterface si = symbol->getType().getShaderInterface(); + auto it = idMaps[si].find(getNameForIdMap(symbol)); + if (it != idMaps[si].end()) { + uint64_t id = (symbol->getId() & ~TSymbolTable::uniqueIdMask) | + (it->second & TSymbolTable::uniqueIdMask); + symbol->changeId(id); + remapped = true; + } + } + if (!remapped) + symbol->changeId(symbol->getId() + idShift); + } +protected: + TRemapIdTraverser(TRemapIdTraverser&); + TRemapIdTraverser& operator=(TRemapIdTraverser&); + const TIdMaps& idMaps; + long long idShift; +}; + +void TIntermediate::remapIds(const TIdMaps& idMaps, long long idShift, TIntermediate& unit) +{ + // Remap all IDs to either share or be unique, as dictated by the idMap and idShift. + TRemapIdTraverser idTraverser(idMaps, idShift); + unit.getTreeRoot()->traverse(&idTraverser); +} + +// +// Merge the function bodies and global-level initializers from unitGlobals into globals. +// Will error check duplication of function bodies for the same signature. +// +void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals) +{ + // TODO: link-time performance: Processing in alphabetical order will be faster + + // Error check the global objects, not including the linker objects + for (unsigned int child = 0; child < globals.size() - 1; ++child) { + for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) { + TIntermAggregate* body = globals[child]->getAsAggregate(); + TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate(); + if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) { + error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:"); + infoSink.info << " " << globals[child]->getAsAggregate()->getName() << "\n"; + } + } + } + + // Merge the global objects, just in front of the linker objects + globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1); +} + +static inline bool isSameInterface(TIntermSymbol* symbol, EShLanguage stage, TIntermSymbol* unitSymbol, EShLanguage unitStage) { + return // 1) same stage and same shader interface + (stage == unitStage && symbol->getType().getShaderInterface() == unitSymbol->getType().getShaderInterface()) || + // 2) accross stages and both are uniform or buffer + (symbol->getQualifier().storage == EvqUniform && unitSymbol->getQualifier().storage == EvqUniform) || + (symbol->getQualifier().storage == EvqBuffer && unitSymbol->getQualifier().storage == EvqBuffer) || + // 3) in/out matched across stage boundary + (stage < unitStage && symbol->getQualifier().storage == EvqVaryingOut && unitSymbol->getQualifier().storage == EvqVaryingIn) || + (unitStage < stage && symbol->getQualifier().storage == EvqVaryingIn && unitSymbol->getQualifier().storage == EvqVaryingOut); +} + +// +// Global Unfiform block stores any default uniforms (i.e. uniforms without a block) +// If two linked stages declare the same member, they are meant to be the same uniform +// and need to be in the same block +// merge the members of different stages to allow them to be linked properly +// as a single block +// +void TIntermediate::mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& unit, bool mergeExistingOnly) +{ + TIntermSequence& linkerObjects = findLinkerObjects()->getSequence(); + TIntermSequence& unitLinkerObjects = unit.findLinkerObjects()->getSequence(); + + // build lists of default blocks from the intermediates + TIntermSequence defaultBlocks; + TIntermSequence unitDefaultBlocks; + + auto filter = [](TIntermSequence& list, TIntermNode* node) { + if (node->getAsSymbolNode()->getQualifier().defaultBlock) { + list.push_back(node); + } + }; + + std::for_each(linkerObjects.begin(), linkerObjects.end(), + [&defaultBlocks, &filter](TIntermNode* node) { + filter(defaultBlocks, node); + }); + std::for_each(unitLinkerObjects.begin(), unitLinkerObjects.end(), + [&unitDefaultBlocks, &filter](TIntermNode* node) { + filter(unitDefaultBlocks, node); + }); + + auto itUnitBlock = unitDefaultBlocks.begin(); + for (; itUnitBlock != unitDefaultBlocks.end(); itUnitBlock++) { + + bool add = !mergeExistingOnly; + auto itBlock = defaultBlocks.begin(); + + for (; itBlock != defaultBlocks.end(); itBlock++) { + TIntermSymbol* block = (*itBlock)->getAsSymbolNode(); + TIntermSymbol* unitBlock = (*itUnitBlock)->getAsSymbolNode(); + + assert(block && unitBlock); + + // if the two default blocks match, then merge their definitions + if (block->getType().getTypeName() == unitBlock->getType().getTypeName() && + block->getQualifier().storage == unitBlock->getQualifier().storage) { + add = false; + mergeBlockDefinitions(infoSink, block, unitBlock, &unit); + } + } + if (add) { + // push back on original list; won't change the size of the list we're iterating over + linkerObjects.push_back(*itUnitBlock); + } + } +} + +void TIntermediate::mergeBlockDefinitions(TInfoSink& infoSink, TIntermSymbol* block, TIntermSymbol* unitBlock, TIntermediate* unit) { + if (block->getType() == unitBlock->getType()) { + return; + } + + if (block->getType().getTypeName() != unitBlock->getType().getTypeName() || + block->getType().getBasicType() != unitBlock->getType().getBasicType() || + block->getQualifier().storage != unitBlock->getQualifier().storage || + block->getQualifier().layoutSet != unitBlock->getQualifier().layoutSet) { + // different block names likely means different blocks + return; + } + + // merge the struct + // order of declarations doesn't matter and they matched based on member name + TTypeList* memberList = block->getType().getWritableStruct(); + TTypeList* unitMemberList = unitBlock->getType().getWritableStruct(); + + // keep track of which members have changed position + // so we don't have to search the array again + std::map memberIndexUpdates; + + size_t memberListStartSize = memberList->size(); + for (unsigned int i = 0; i < unitMemberList->size(); ++i) { + bool merge = true; + for (unsigned int j = 0; j < memberListStartSize; ++j) { + if ((*memberList)[j].type->getFieldName() == (*unitMemberList)[i].type->getFieldName()) { + merge = false; + const TType* memberType = (*memberList)[j].type; + const TType* unitMemberType = (*unitMemberList)[i].type; + + // compare types + // don't need as many checks as when merging symbols, since + // initializers and most qualifiers are stripped when the member is moved into the block + if ((*memberType) != (*unitMemberType)) { + error(infoSink, "Types must match:"); + infoSink.info << " " << memberType->getFieldName() << ": "; + infoSink.info << "\"" << memberType->getCompleteString() << "\" versus "; + infoSink.info << "\"" << unitMemberType->getCompleteString() << "\"\n"; + } + + memberIndexUpdates[i] = j; + } + } + if (merge) { + memberList->push_back((*unitMemberList)[i]); + memberIndexUpdates[i] = (unsigned int)memberList->size() - 1; + } + } + + TType unitType; + unitType.shallowCopy(unitBlock->getType()); + + // update symbol node in unit tree, + // and other nodes that may reference it + class TMergeBlockTraverser : public TIntermTraverser { + public: + TMergeBlockTraverser(const glslang::TType &type, const glslang::TType& unitType, + glslang::TIntermediate& unit, + const std::map& memberIdxUpdates) : + newType(type), unitType(unitType), unit(unit), memberIndexUpdates(memberIdxUpdates) + { } + virtual ~TMergeBlockTraverser() { } + + const glslang::TType& newType; // type with modifications + const glslang::TType& unitType; // copy of original type + glslang::TIntermediate& unit; // intermediate that is being updated + const std::map& memberIndexUpdates; + + virtual void visitSymbol(TIntermSymbol* symbol) + { + glslang::TType& symType = symbol->getWritableType(); + + if (symType == unitType) { + // each symbol node has a local copy of the unitType + // if merging involves changing properties that aren't shared objects + // they should be updated in all instances + + // e.g. the struct list is a ptr to an object, so it can be updated + // once, outside the traverser + //*symType.getWritableStruct() = *newType.getStruct(); + } + + } + + virtual bool visitBinary(TVisit, glslang::TIntermBinary* node) + { + if (node->getOp() == EOpIndexDirectStruct && node->getLeft()->getType() == unitType) { + // this is a dereference to a member of the block since the + // member list changed, need to update this to point to the + // right index + assert(node->getRight()->getAsConstantUnion()); + + glslang::TIntermConstantUnion* constNode = node->getRight()->getAsConstantUnion(); + unsigned int memberIdx = constNode->getConstArray()[0].getUConst(); + unsigned int newIdx = memberIndexUpdates.at(memberIdx); + TIntermTyped* newConstNode = unit.addConstantUnion(newIdx, node->getRight()->getLoc()); + + node->setRight(newConstNode); + delete constNode; + + return true; + } + return true; + } + } finalLinkTraverser(block->getType(), unitType, *unit, memberIndexUpdates); + + // update the tree to use the new type + unit->getTreeRoot()->traverse(&finalLinkTraverser); + + // update the member list + (*unitMemberList) = (*memberList); +} + +// +// Merge the linker objects from unitLinkerObjects into linkerObjects. +// Duplication is expected and filtered out, but contradictions are an error. +// +void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects, EShLanguage unitStage) +{ + // Error check and merge the linker objects (duplicates should not be created) + std::size_t initialNumLinkerObjects = linkerObjects.size(); + for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) { + bool merge = true; + for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) { + TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode(); + TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); + assert(symbol && unitSymbol); + + bool isSameSymbol = false; + // If they are both blocks in the same shader interface, + // match by the block-name, not the identifier name. + if (symbol->getType().getBasicType() == EbtBlock && unitSymbol->getType().getBasicType() == EbtBlock) { + if (isSameInterface(symbol, getStage(), unitSymbol, unitStage)) { + isSameSymbol = symbol->getType().getTypeName() == unitSymbol->getType().getTypeName(); + } + } + else if (symbol->getName() == unitSymbol->getName()) + isSameSymbol = true; + + if (isSameSymbol) { + // filter out copy + merge = false; + + // but if one has an initializer and the other does not, update + // the initializer + if (symbol->getConstArray().empty() && ! unitSymbol->getConstArray().empty()) + symbol->setConstArray(unitSymbol->getConstArray()); + + // Similarly for binding + if (! symbol->getQualifier().hasBinding() && unitSymbol->getQualifier().hasBinding()) + symbol->getQualifier().layoutBinding = unitSymbol->getQualifier().layoutBinding; + + // Similarly for location + if (!symbol->getQualifier().hasLocation() && unitSymbol->getQualifier().hasLocation()) { + symbol->getQualifier().layoutLocation = unitSymbol->getQualifier().layoutLocation; + } + + // Update implicit array sizes + mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType()); + + // Check for consistent types/qualification/initializers etc. + mergeErrorCheck(infoSink, *symbol, *unitSymbol, unitStage); + } + // If different symbols, verify they arn't push_constant since there can only be one per stage + else if (symbol->getQualifier().isPushConstant() && unitSymbol->getQualifier().isPushConstant() && getStage() == unitStage) + error(infoSink, "Only one push_constant block is allowed per stage"); + } + if (merge) { + linkerObjects.push_back(unitLinkerObjects[unitLinkObj]); + + // for anonymous blocks, check that their members don't conflict with other names + if (unitLinkerObjects[unitLinkObj]->getAsSymbolNode()->getBasicType() == EbtBlock && + IsAnonymous(unitLinkerObjects[unitLinkObj]->getAsSymbolNode()->getName())) { + for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) { + TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode(); + TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); + assert(symbol && unitSymbol); + + auto checkName = [this, unitSymbol, &infoSink](const TString& name) { + for (unsigned int i = 0; i < unitSymbol->getType().getStruct()->size(); ++i) { + if (name == (*unitSymbol->getType().getStruct())[i].type->getFieldName()) { + error(infoSink, "Anonymous member name used for global variable or other anonymous member: "); + infoSink.info << (*unitSymbol->getType().getStruct())[i].type->getCompleteString() << "\n"; + } + } + }; + + if (isSameInterface(symbol, getStage(), unitSymbol, unitStage)) { + checkName(symbol->getName()); + + // check members of other anonymous blocks + if (symbol->getBasicType() == EbtBlock && IsAnonymous(symbol->getName())) { + for (unsigned int i = 0; i < symbol->getType().getStruct()->size(); ++i) { + checkName((*symbol->getType().getStruct())[i].type->getFieldName()); + } + } + } + } + } + } + } +} + +// TODO 4.5 link functionality: cull distance array size checking + +// Recursively merge the implicit array sizes through the objects' respective type trees. +void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType) +{ + if (type.isUnsizedArray()) { + if (unitType.isUnsizedArray()) { + type.updateImplicitArraySize(unitType.getImplicitArraySize()); + if (unitType.isArrayVariablyIndexed()) + type.setArrayVariablyIndexed(); + } else if (unitType.isSizedArray()) + type.changeOuterArraySize(unitType.getOuterArraySize()); + } + + // Type mismatches are caught and reported after this, just be careful for now. + if (! type.isStruct() || ! unitType.isStruct() || type.getStruct()->size() != unitType.getStruct()->size()) + return; + + for (int i = 0; i < (int)type.getStruct()->size(); ++i) + mergeImplicitArraySizes(*(*type.getStruct())[i].type, *(*unitType.getStruct())[i].type); +} + +// +// Compare two global objects from two compilation units and see if they match +// well enough. Rules can be different for intra- vs. cross-stage matching. +// +// This function only does one of intra- or cross-stage matching per call. +// +void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, EShLanguage unitStage) +{ +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + bool crossStage = getStage() != unitStage; + bool writeTypeComparison = false; + + // Types have to match + { + // but, we make an exception if one is an implicit array and the other is sized + // or if the array sizes differ because of the extra array dimension on some in/out boundaries + bool arraysMatch = false; + if (isIoResizeArray(symbol.getType(), getStage()) || isIoResizeArray(unitSymbol.getType(), unitStage)) { + // if the arrays have an extra dimension because of the stage. + // compare dimensions while ignoring the outer dimension + unsigned int firstDim = isIoResizeArray(symbol.getType(), getStage()) ? 1 : 0; + unsigned int numDim = symbol.getArraySizes() + ? symbol.getArraySizes()->getNumDims() : 0; + unsigned int unitFirstDim = isIoResizeArray(unitSymbol.getType(), unitStage) ? 1 : 0; + unsigned int unitNumDim = unitSymbol.getArraySizes() + ? unitSymbol.getArraySizes()->getNumDims() : 0; + arraysMatch = (numDim - firstDim) == (unitNumDim - unitFirstDim); + // check that array sizes match as well + for (unsigned int i = 0; i < (numDim - firstDim) && arraysMatch; i++) { + if (symbol.getArraySizes()->getDimSize(firstDim + i) != + unitSymbol.getArraySizes()->getDimSize(unitFirstDim + i)) { + arraysMatch = false; + break; + } + } + } + else { + arraysMatch = symbol.getType().sameArrayness(unitSymbol.getType()) || + (symbol.getType().isArray() && unitSymbol.getType().isArray() && + (symbol.getType().isUnsizedArray() || unitSymbol.getType().isUnsizedArray())); + } + + if (!symbol.getType().sameElementType(unitSymbol.getType()) || + !symbol.getType().sameTypeParameters(unitSymbol.getType()) || + !arraysMatch ) { + writeTypeComparison = true; + error(infoSink, "Types must match:"); + } + } + + // Interface block member-wise layout qualifiers have to match + if (symbol.getType().getBasicType() == EbtBlock && unitSymbol.getType().getBasicType() == EbtBlock && + symbol.getType().getStruct() && unitSymbol.getType().getStruct() && + symbol.getType().sameStructType(unitSymbol.getType())) { + for (unsigned int i = 0; i < symbol.getType().getStruct()->size(); ++i) { + const TQualifier& qualifier = (*symbol.getType().getStruct())[i].type->getQualifier(); + const TQualifier& unitQualifier = (*unitSymbol.getType().getStruct())[i].type->getQualifier(); + if (qualifier.layoutMatrix != unitQualifier.layoutMatrix || + qualifier.layoutOffset != unitQualifier.layoutOffset || + qualifier.layoutAlign != unitQualifier.layoutAlign || + qualifier.layoutLocation != unitQualifier.layoutLocation || + qualifier.layoutComponent != unitQualifier.layoutComponent) { + error(infoSink, "Interface block member layout qualifiers must match:"); + writeTypeComparison = true; + } + } + } + + bool isInOut = crossStage && + ((symbol.getQualifier().storage == EvqVaryingIn && unitSymbol.getQualifier().storage == EvqVaryingOut) || + (symbol.getQualifier().storage == EvqVaryingOut && unitSymbol.getQualifier().storage == EvqVaryingIn)); + + // Qualifiers have to (almost) match + // Storage... + if (!isInOut && symbol.getQualifier().storage != unitSymbol.getQualifier().storage) { + error(infoSink, "Storage qualifiers must match:"); + writeTypeComparison = true; + } + + // Uniform and buffer blocks must either both have an instance name, or + // must both be anonymous. The names don't need to match though. + if (symbol.getQualifier().isUniformOrBuffer() && + (IsAnonymous(symbol.getName()) != IsAnonymous(unitSymbol.getName()))) { + error(infoSink, "Matched Uniform or Storage blocks must all be anonymous," + " or all be named:"); + writeTypeComparison = true; + } + + if (symbol.getQualifier().storage == unitSymbol.getQualifier().storage && + (IsAnonymous(symbol.getName()) != IsAnonymous(unitSymbol.getName()) || + (!IsAnonymous(symbol.getName()) && symbol.getName() != unitSymbol.getName()))) { + warn(infoSink, "Matched shader interfaces are using different instance names."); + writeTypeComparison = true; + } + + // Precision... + if (!isInOut && symbol.getQualifier().precision != unitSymbol.getQualifier().precision) { + error(infoSink, "Precision qualifiers must match:"); + writeTypeComparison = true; + } + + // Invariance... + if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) { + error(infoSink, "Presence of invariant qualifier must match:"); + writeTypeComparison = true; + } + + // Precise... + if (! crossStage && symbol.getQualifier().isNoContraction() != unitSymbol.getQualifier().isNoContraction()) { + error(infoSink, "Presence of precise qualifier must match:"); + writeTypeComparison = true; + } + + // Auxiliary and interpolation... + // "interpolation qualification (e.g., flat) and auxiliary qualification (e.g. centroid) may differ. + // These mismatches are allowed between any pair of stages ... + // those provided in the fragment shader supersede those provided in previous stages." + if (!crossStage && + (symbol.getQualifier().centroid != unitSymbol.getQualifier().centroid || + symbol.getQualifier().smooth != unitSymbol.getQualifier().smooth || + symbol.getQualifier().flat != unitSymbol.getQualifier().flat || + symbol.getQualifier().isSample()!= unitSymbol.getQualifier().isSample() || + symbol.getQualifier().isPatch() != unitSymbol.getQualifier().isPatch() || + symbol.getQualifier().isNonPerspective() != unitSymbol.getQualifier().isNonPerspective())) { + error(infoSink, "Interpolation and auxiliary storage qualifiers must match:"); + writeTypeComparison = true; + } + + // Memory... + if (symbol.getQualifier().coherent != unitSymbol.getQualifier().coherent || + symbol.getQualifier().devicecoherent != unitSymbol.getQualifier().devicecoherent || + symbol.getQualifier().queuefamilycoherent != unitSymbol.getQualifier().queuefamilycoherent || + symbol.getQualifier().workgroupcoherent != unitSymbol.getQualifier().workgroupcoherent || + symbol.getQualifier().subgroupcoherent != unitSymbol.getQualifier().subgroupcoherent || + symbol.getQualifier().shadercallcoherent!= unitSymbol.getQualifier().shadercallcoherent || + symbol.getQualifier().nonprivate != unitSymbol.getQualifier().nonprivate || + symbol.getQualifier().volatil != unitSymbol.getQualifier().volatil || + symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict || + symbol.getQualifier().readonly != unitSymbol.getQualifier().readonly || + symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) { + error(infoSink, "Memory qualifiers must match:"); + writeTypeComparison = true; + } + + // Layouts... + // TODO: 4.4 enhanced layouts: Generalize to include offset/align: current spec + // requires separate user-supplied offset from actual computed offset, but + // current implementation only has one offset. + if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix || + symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking || + symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation || + symbol.getQualifier().layoutComponent != unitSymbol.getQualifier().layoutComponent || + symbol.getQualifier().layoutIndex != unitSymbol.getQualifier().layoutIndex || + symbol.getQualifier().layoutBinding != unitSymbol.getQualifier().layoutBinding || + (symbol.getQualifier().hasBinding() && (symbol.getQualifier().layoutOffset != unitSymbol.getQualifier().layoutOffset))) { + error(infoSink, "Layout qualification must match:"); + writeTypeComparison = true; + } + + // Initializers have to match, if both are present, and if we don't already know the types don't match + if (! writeTypeComparison) { + if (! symbol.getConstArray().empty() && ! unitSymbol.getConstArray().empty()) { + if (symbol.getConstArray() != unitSymbol.getConstArray()) { + error(infoSink, "Initializers must match:"); + infoSink.info << " " << symbol.getName() << "\n"; + } + } + } + + if (writeTypeComparison) { + infoSink.info << " " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus "; + if (symbol.getName() != unitSymbol.getName()) + infoSink.info << unitSymbol.getName() << ": "; + + infoSink.info << "\"" << unitSymbol.getType().getCompleteString() << "\"\n"; + } +#endif +} + +void TIntermediate::sharedBlockCheck(TInfoSink& infoSink) +{ + bool has_shared_block = false; + bool has_shared_non_block = false; + TIntermSequence& linkObjects = findLinkerObjects()->getSequence(); + for (size_t i = 0; i < linkObjects.size(); ++i) { + const TType& type = linkObjects[i]->getAsTyped()->getType(); + const TQualifier& qualifier = type.getQualifier(); + if (qualifier.storage == glslang::EvqShared) { + if (type.getBasicType() == glslang::EbtBlock) + has_shared_block = true; + else + has_shared_non_block = true; + } + } + if (has_shared_block && has_shared_non_block) + error(infoSink, "cannot mix use of shared variables inside and outside blocks"); +} + +// +// Do final link-time error checking of a complete (merged) intermediate representation. +// (Much error checking was done during merging). +// +// Also, lock in defaults of things not set, including array sizes. +// +void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled) +{ + if (getTreeRoot() == nullptr) + return; + + if (numEntryPoints < 1) { + if (getSource() == EShSourceGlsl) + error(infoSink, "Missing entry point: Each stage requires one entry point"); + else + warn(infoSink, "Entry point not found"); + } + + // recursion and missing body checking + checkCallGraphCycles(infoSink); + checkCallGraphBodies(infoSink, keepUncalled); + + // overlap/alias/missing I/O, etc. + inOutLocationCheck(infoSink); + +#ifndef GLSLANG_WEB + if (getNumPushConstants() > 1) + error(infoSink, "Only one push_constant block is allowed per stage"); + + // invocations + if (invocations == TQualifier::layoutNotSet) + invocations = 1; + + if (inIoAccessed("gl_ClipDistance") && inIoAccessed("gl_ClipVertex")) + error(infoSink, "Can only use one of gl_ClipDistance or gl_ClipVertex (gl_ClipDistance is preferred)"); + if (inIoAccessed("gl_CullDistance") && inIoAccessed("gl_ClipVertex")) + error(infoSink, "Can only use one of gl_CullDistance or gl_ClipVertex (gl_ClipDistance is preferred)"); + + if (userOutputUsed() && (inIoAccessed("gl_FragColor") || inIoAccessed("gl_FragData"))) + error(infoSink, "Cannot use gl_FragColor or gl_FragData when using user-defined outputs"); + if (inIoAccessed("gl_FragColor") && inIoAccessed("gl_FragData")) + error(infoSink, "Cannot use both gl_FragColor and gl_FragData"); + + for (size_t b = 0; b < xfbBuffers.size(); ++b) { + if (xfbBuffers[b].contains64BitType) + RoundToPow2(xfbBuffers[b].implicitStride, 8); + else if (xfbBuffers[b].contains32BitType) + RoundToPow2(xfbBuffers[b].implicitStride, 4); + else if (xfbBuffers[b].contains16BitType) + RoundToPow2(xfbBuffers[b].implicitStride, 2); + + // "It is a compile-time or link-time error to have + // any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or + // in different compilation units. While xfb_stride can be declared multiple times for the same buffer, it is a + // compile-time or link-time error to have different values specified for the stride for the same buffer." + if (xfbBuffers[b].stride != TQualifier::layoutXfbStrideEnd && xfbBuffers[b].implicitStride > xfbBuffers[b].stride) { + error(infoSink, "xfb_stride is too small to hold all buffer entries:"); + infoSink.info.prefix(EPrefixError); + infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << ", minimum stride needed: " << xfbBuffers[b].implicitStride << "\n"; + } + if (xfbBuffers[b].stride == TQualifier::layoutXfbStrideEnd) + xfbBuffers[b].stride = xfbBuffers[b].implicitStride; + + // "If the buffer is capturing any + // outputs with double-precision or 64-bit integer components, the stride must be a multiple of 8, otherwise it must be a + // multiple of 4, or a compile-time or link-time error results." + if (xfbBuffers[b].contains64BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 8)) { + error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double or 64-bit integer:"); + infoSink.info.prefix(EPrefixError); + infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n"; + } else if (xfbBuffers[b].contains32BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) { + error(infoSink, "xfb_stride must be multiple of 4:"); + infoSink.info.prefix(EPrefixError); + infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n"; + } + // "If the buffer is capturing any + // outputs with half-precision or 16-bit integer components, the stride must be a multiple of 2" + else if (xfbBuffers[b].contains16BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 2)) { + error(infoSink, "xfb_stride must be multiple of 2 for buffer holding a half float or 16-bit integer:"); + infoSink.info.prefix(EPrefixError); + infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n"; + } + + // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the + // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents." + if (xfbBuffers[b].stride > (unsigned int)(4 * resources->maxTransformFeedbackInterleavedComponents)) { + error(infoSink, "xfb_stride is too large:"); + infoSink.info.prefix(EPrefixError); + infoSink.info << " xfb_buffer " << (unsigned int)b << ", components (1/4 stride) needed are " << xfbBuffers[b].stride/4 << ", gl_MaxTransformFeedbackInterleavedComponents is " << resources->maxTransformFeedbackInterleavedComponents << "\n"; + } + } + + switch (language) { + case EShLangVertex: + break; + case EShLangTessControl: + if (vertices == TQualifier::layoutNotSet) + error(infoSink, "At least one shader must specify an output layout(vertices=...)"); + break; + case EShLangTessEvaluation: + if (getSource() == EShSourceGlsl) { + if (inputPrimitive == ElgNone) + error(infoSink, "At least one shader must specify an input layout primitive"); + if (vertexSpacing == EvsNone) + vertexSpacing = EvsEqual; + if (vertexOrder == EvoNone) + vertexOrder = EvoCcw; + } + break; + case EShLangGeometry: + if (inputPrimitive == ElgNone) + error(infoSink, "At least one shader must specify an input layout primitive"); + if (outputPrimitive == ElgNone) + error(infoSink, "At least one shader must specify an output layout primitive"); + if (vertices == TQualifier::layoutNotSet) + error(infoSink, "At least one shader must specify a layout(max_vertices = value)"); + break; + case EShLangFragment: + // for GL_ARB_post_depth_coverage, EarlyFragmentTest is set automatically in + // ParseHelper.cpp. So if we reach here, this must be GL_EXT_post_depth_coverage + // requiring explicit early_fragment_tests + if (getPostDepthCoverage() && !getEarlyFragmentTests()) + error(infoSink, "post_depth_coverage requires early_fragment_tests"); + break; + case EShLangCompute: + sharedBlockCheck(infoSink); + break; + case EShLangRayGen: + case EShLangIntersect: + case EShLangAnyHit: + case EShLangClosestHit: + case EShLangMiss: + case EShLangCallable: + if (numShaderRecordBlocks > 1) + error(infoSink, "Only one shaderRecordNV buffer block is allowed per stage"); + break; + case EShLangMeshNV: + // NV_mesh_shader doesn't allow use of both single-view and per-view builtins. + if (inIoAccessed("gl_Position") && inIoAccessed("gl_PositionPerViewNV")) + error(infoSink, "Can only use one of gl_Position or gl_PositionPerViewNV"); + if (inIoAccessed("gl_ClipDistance") && inIoAccessed("gl_ClipDistancePerViewNV")) + error(infoSink, "Can only use one of gl_ClipDistance or gl_ClipDistancePerViewNV"); + if (inIoAccessed("gl_CullDistance") && inIoAccessed("gl_CullDistancePerViewNV")) + error(infoSink, "Can only use one of gl_CullDistance or gl_CullDistancePerViewNV"); + if (inIoAccessed("gl_Layer") && inIoAccessed("gl_LayerPerViewNV")) + error(infoSink, "Can only use one of gl_Layer or gl_LayerPerViewNV"); + if (inIoAccessed("gl_ViewportMask") && inIoAccessed("gl_ViewportMaskPerViewNV")) + error(infoSink, "Can only use one of gl_ViewportMask or gl_ViewportMaskPerViewNV"); + if (outputPrimitive == ElgNone) + error(infoSink, "At least one shader must specify an output layout primitive"); + if (vertices == TQualifier::layoutNotSet) + error(infoSink, "At least one shader must specify a layout(max_vertices = value)"); + if (primitives == TQualifier::layoutNotSet) + error(infoSink, "At least one shader must specify a layout(max_primitives = value)"); + // fall through + case EShLangTaskNV: + if (numTaskNVBlocks > 1) + error(infoSink, "Only one taskNV interface block is allowed per shader"); + sharedBlockCheck(infoSink); + break; + default: + error(infoSink, "Unknown Stage."); + break; + } + + // Process the tree for any node-specific work. + class TFinalLinkTraverser : public TIntermTraverser { + public: + TFinalLinkTraverser() { } + virtual ~TFinalLinkTraverser() { } + + virtual void visitSymbol(TIntermSymbol* symbol) + { + // Implicitly size arrays. + // If an unsized array is left as unsized, it effectively + // becomes run-time sized. + symbol->getWritableType().adoptImplicitArraySizes(false); + } + } finalLinkTraverser; + + treeRoot->traverse(&finalLinkTraverser); +#endif +} + +// +// See if the call graph contains any static recursion, which is disallowed +// by the specification. +// +void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink) +{ + // Clear fields we'll use for this. + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + call->visited = false; + call->currentPath = false; + call->errorGiven = false; + } + + // + // Loop, looking for a new connected subgraph. One subgraph is handled per loop iteration. + // + + TCall* newRoot; + do { + // See if we have unvisited parts of the graph. + newRoot = 0; + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + if (! call->visited) { + newRoot = &(*call); + break; + } + } + + // If not, we are done. + if (! newRoot) + break; + + // Otherwise, we found a new subgraph, process it: + // See what all can be reached by this new root, and if any of + // that is recursive. This is done by depth-first traversals, seeing + // if a new call is found that was already in the currentPath (a back edge), + // thereby detecting recursion. + std::list stack; + newRoot->currentPath = true; // currentPath will be true iff it is on the stack + stack.push_back(newRoot); + while (! stack.empty()) { + // get a caller + TCall* call = stack.back(); + + // Add to the stack just one callee. + // This algorithm always terminates, because only !visited and !currentPath causes a push + // and all pushes change currentPath to true, and all pops change visited to true. + TGraph::iterator child = callGraph.begin(); + for (; child != callGraph.end(); ++child) { + + // If we already visited this node, its whole subgraph has already been processed, so skip it. + if (child->visited) + continue; + + if (call->callee == child->caller) { + if (child->currentPath) { + // Then, we found a back edge + if (! child->errorGiven) { + error(infoSink, "Recursion detected:"); + infoSink.info << " " << call->callee << " calling " << child->callee << "\n"; + child->errorGiven = true; + recursive = true; + } + } else { + child->currentPath = true; + stack.push_back(&(*child)); + break; + } + } + } + if (child == callGraph.end()) { + // no more callees, we bottomed out, never look at this node again + stack.back()->currentPath = false; + stack.back()->visited = true; + stack.pop_back(); + } + } // end while, meaning nothing left to process in this subtree + + } while (newRoot); // redundant loop check; should always exit via the 'break' above +} + +// +// See which functions are reachable from the entry point and which have bodies. +// Reachable ones with missing bodies are errors. +// Unreachable bodies are dead code. +// +void TIntermediate::checkCallGraphBodies(TInfoSink& infoSink, bool keepUncalled) +{ + // Clear fields we'll use for this. + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + call->visited = false; + call->calleeBodyPosition = -1; + } + + // The top level of the AST includes function definitions (bodies). + // Compare these to function calls in the call graph. + // We'll end up knowing which have bodies, and if so, + // how to map the call-graph node to the location in the AST. + TIntermSequence &functionSequence = getTreeRoot()->getAsAggregate()->getSequence(); + std::vector reachable(functionSequence.size(), true); // so that non-functions are reachable + for (int f = 0; f < (int)functionSequence.size(); ++f) { + glslang::TIntermAggregate* node = functionSequence[f]->getAsAggregate(); + if (node && (node->getOp() == glslang::EOpFunction)) { + if (node->getName().compare(getEntryPointMangledName().c_str()) != 0) + reachable[f] = false; // so that function bodies are unreachable, until proven otherwise + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + if (call->callee == node->getName()) + call->calleeBodyPosition = f; + } + } + } + + // Start call-graph traversal by visiting the entry point nodes. + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + if (call->caller.compare(getEntryPointMangledName().c_str()) == 0) + call->visited = true; + } + + // Propagate 'visited' through the call-graph to every part of the graph it + // can reach (seeded with the entry-point setting above). + bool changed; + do { + changed = false; + for (auto call1 = callGraph.begin(); call1 != callGraph.end(); ++call1) { + if (call1->visited) { + for (TGraph::iterator call2 = callGraph.begin(); call2 != callGraph.end(); ++call2) { + if (! call2->visited) { + if (call1->callee == call2->caller) { + changed = true; + call2->visited = true; + } + } + } + } + } + } while (changed); + + // Any call-graph node set to visited but without a callee body is an error. + for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { + if (call->visited) { + if (call->calleeBodyPosition == -1) { + error(infoSink, "No function definition (body) found: "); + infoSink.info << " " << call->callee << "\n"; + } else + reachable[call->calleeBodyPosition] = true; + } + } + + // Bodies in the AST not reached by the call graph are dead; + // clear them out, since they can't be reached and also can't + // be translated further due to possibility of being ill defined. + if (! keepUncalled) { + for (int f = 0; f < (int)functionSequence.size(); ++f) { + if (! reachable[f]) + functionSequence[f] = nullptr; + } + functionSequence.erase(std::remove(functionSequence.begin(), functionSequence.end(), nullptr), functionSequence.end()); + } +} + +// +// Satisfy rules for location qualifiers on inputs and outputs +// +void TIntermediate::inOutLocationCheck(TInfoSink& infoSink) +{ + // ES 3.0 requires all outputs to have location qualifiers if there is more than one output + bool fragOutWithNoLocation = false; + int numFragOut = 0; + + // TODO: linker functionality: location collision checking + + TIntermSequence& linkObjects = findLinkerObjects()->getSequence(); + for (size_t i = 0; i < linkObjects.size(); ++i) { + const TType& type = linkObjects[i]->getAsTyped()->getType(); + const TQualifier& qualifier = type.getQualifier(); + if (language == EShLangFragment) { + if (qualifier.storage == EvqVaryingOut && qualifier.builtIn == EbvNone) { + ++numFragOut; + if (!qualifier.hasAnyLocation()) + fragOutWithNoLocation = true; + } + } + } + + if (isEsProfile()) { + if (numFragOut > 1 && fragOutWithNoLocation) + error(infoSink, "when more than one fragment shader output, all must have location qualifiers"); + } +} + +TIntermAggregate* TIntermediate::findLinkerObjects() const +{ + // Get the top-level globals + TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence(); + + // Get the last member of the sequences, expected to be the linker-object lists + assert(globals.back()->getAsAggregate()->getOp() == EOpLinkerObjects); + + return globals.back()->getAsAggregate(); +} + +// See if a variable was both a user-declared output and used. +// Note: the spec discusses writing to one, but this looks at read or write, which +// is more useful, and perhaps the spec should be changed to reflect that. +bool TIntermediate::userOutputUsed() const +{ + const TIntermSequence& linkerObjects = findLinkerObjects()->getSequence(); + + bool found = false; + for (size_t i = 0; i < linkerObjects.size(); ++i) { + const TIntermSymbol& symbolNode = *linkerObjects[i]->getAsSymbolNode(); + if (symbolNode.getQualifier().storage == EvqVaryingOut && + symbolNode.getName().compare(0, 3, "gl_") != 0 && + inIoAccessed(symbolNode.getName())) { + found = true; + break; + } + } + + return found; +} + +// Accumulate locations used for inputs, outputs, and uniforms, payload and callable data +// and check for collisions as the accumulation is done. +// +// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. +// +// typeCollision is set to true if there is no direct collision, but the types in the same location +// are different. +// +int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& type, bool& typeCollision) +{ + typeCollision = false; + + int set; + int setRT; + if (qualifier.isPipeInput()) + set = 0; + else if (qualifier.isPipeOutput()) + set = 1; + else if (qualifier.storage == EvqUniform) + set = 2; + else if (qualifier.storage == EvqBuffer) + set = 3; + else if (qualifier.isAnyPayload()) + setRT = 0; + else if (qualifier.isAnyCallable()) + setRT = 1; + else + return -1; + + int size; + if (qualifier.isAnyPayload() || qualifier.isAnyCallable()) { + size = 1; + } else if (qualifier.isUniformOrBuffer() || qualifier.isTaskMemory()) { + if (type.isSizedArray()) + size = type.getCumulativeArraySize(); + else + size = 1; + } else { + // Strip off the outer array dimension for those having an extra one. + if (type.isArray() && qualifier.isArrayedIo(language)) { + TType elementType(type, 0); + size = computeTypeLocationSize(elementType, language); + } else + size = computeTypeLocationSize(type, language); + } + + // Locations, and components within locations. + // + // Almost always, dealing with components means a single location is involved. + // The exception is a dvec3. From the spec: + // + // "A dvec3 will consume all four components of the first location and components 0 and 1 of + // the second location. This leaves components 2 and 3 available for other component-qualified + // declarations." + // + // That means, without ever mentioning a component, a component range + // for a different location gets specified, if it's not a vertex shader input. (!) + // (A vertex shader input will show using only one location, even for a dvec3/4.) + // + // So, for the case of dvec3, we need two independent ioRanges. + // + // For raytracing IO (payloads and callabledata) each declaration occupies a single + // slot irrespective of type. + int collision = -1; // no collision +#ifndef GLSLANG_WEB + if (qualifier.isAnyPayload() || qualifier.isAnyCallable()) { + TRange range(qualifier.layoutLocation, qualifier.layoutLocation); + collision = checkLocationRT(setRT, qualifier.layoutLocation); + if (collision < 0) + usedIoRT[setRT].push_back(range); + } else if (size == 2 && type.getBasicType() == EbtDouble && type.getVectorSize() == 3 && + (qualifier.isPipeInput() || qualifier.isPipeOutput())) { + // Dealing with dvec3 in/out split across two locations. + // Need two io-ranges. + // The case where the dvec3 doesn't start at component 0 was previously caught as overflow. + + // First range: + TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation); + TRange componentRange(0, 3); + TIoRange range(locationRange, componentRange, type.getBasicType(), 0); + + // check for collisions + collision = checkLocationRange(set, range, type, typeCollision); + if (collision < 0) { + usedIo[set].push_back(range); + + // Second range: + TRange locationRange2(qualifier.layoutLocation + 1, qualifier.layoutLocation + 1); + TRange componentRange2(0, 1); + TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0); + + // check for collisions + collision = checkLocationRange(set, range2, type, typeCollision); + if (collision < 0) + usedIo[set].push_back(range2); + } + } else +#endif + { + // Not a dvec3 in/out split across two locations, generic path. + // Need a single IO-range block. + + TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1); + TRange componentRange(0, 3); + if (qualifier.hasComponent() || type.getVectorSize() > 0) { + int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1); + if (qualifier.hasComponent()) + componentRange.start = qualifier.layoutComponent; + componentRange.last = componentRange.start + consumedComponents - 1; + } + + // combine location and component ranges + TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.getIndex() : 0); + + // check for collisions, except for vertex inputs on desktop targeting OpenGL + if (! (!isEsProfile() && language == EShLangVertex && qualifier.isPipeInput()) || spvVersion.vulkan > 0) + collision = checkLocationRange(set, range, type, typeCollision); + + if (collision < 0) + usedIo[set].push_back(range); + } + + return collision; +} + +// Compare a new (the passed in) 'range' against the existing set, and see +// if there are any collisions. +// +// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. +// +int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TType& type, bool& typeCollision) +{ + for (size_t r = 0; r < usedIo[set].size(); ++r) { + if (range.overlap(usedIo[set][r])) { + // there is a collision; pick one + return std::max(range.location.start, usedIo[set][r].location.start); + } else if (range.location.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) { + // aliased-type mismatch + typeCollision = true; + return std::max(range.location.start, usedIo[set][r].location.start); + } + } + + return -1; // no collision +} + +int TIntermediate::checkLocationRT(int set, int location) { + TRange range(location, location); + for (size_t r = 0; r < usedIoRT[set].size(); ++r) { + if (range.overlap(usedIoRT[set][r])) { + return range.start; + } + } + return -1; // no collision +} + +// Accumulate bindings and offsets, and check for collisions +// as the accumulation is done. +// +// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. +// +int TIntermediate::addUsedOffsets(int binding, int offset, int numOffsets) +{ + TRange bindingRange(binding, binding); + TRange offsetRange(offset, offset + numOffsets - 1); + TOffsetRange range(bindingRange, offsetRange); + + // check for collisions, except for vertex inputs on desktop + for (size_t r = 0; r < usedAtomics.size(); ++r) { + if (range.overlap(usedAtomics[r])) { + // there is a collision; pick one + return std::max(offset, usedAtomics[r].offset.start); + } + } + + usedAtomics.push_back(range); + + return -1; // no collision +} + +// Accumulate used constant_id values. +// +// Return false is one was already used. +bool TIntermediate::addUsedConstantId(int id) +{ + if (usedConstantId.find(id) != usedConstantId.end()) + return false; + + usedConstantId.insert(id); + + return true; +} + +// Recursively figure out how many locations are used up by an input or output type. +// Return the size of type, as measured by "locations". +int TIntermediate::computeTypeLocationSize(const TType& type, EShLanguage stage) +{ + // "If the declared input is an array of size n and each element takes m locations, it will be assigned m * n + // consecutive locations..." + if (type.isArray()) { + // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness + // TODO: are there valid cases of having an unsized array with a location? If so, running this code too early. + TType elementType(type, 0); + if (type.isSizedArray() && !type.getQualifier().isPerView()) + return type.getOuterArraySize() * computeTypeLocationSize(elementType, stage); + else { +#ifndef GLSLANG_WEB + // unset perViewNV attributes for arrayed per-view outputs: "perviewNV vec4 v[MAX_VIEWS][3];" + elementType.getQualifier().perViewNV = false; +#endif + return computeTypeLocationSize(elementType, stage); + } + } + + // "The locations consumed by block and structure members are determined by applying the rules above + // recursively..." + if (type.isStruct()) { + int size = 0; + for (int member = 0; member < (int)type.getStruct()->size(); ++member) { + TType memberType(type, member); + size += computeTypeLocationSize(memberType, stage); + } + return size; + } + + // ES: "If a shader input is any scalar or vector type, it will consume a single location." + + // Desktop: "If a vertex shader input is any scalar or vector type, it will consume a single location. If a non-vertex + // shader input is a scalar or vector type other than dvec3 or dvec4, it will consume a single location, while + // types dvec3 or dvec4 will consume two consecutive locations. Inputs of type double and dvec2 will + // consume only a single location, in all stages." + if (type.isScalar()) + return 1; + if (type.isVector()) { + if (stage == EShLangVertex && type.getQualifier().isPipeInput()) + return 1; + if (type.getBasicType() == EbtDouble && type.getVectorSize() > 2) + return 2; + else + return 1; + } + + // "If the declared input is an n x m single- or double-precision matrix, ... + // The number of locations assigned for each matrix will be the same as + // for an n-element array of m-component vectors..." + if (type.isMatrix()) { + TType columnType(type, 0); + return type.getMatrixCols() * computeTypeLocationSize(columnType, stage); + } + + assert(0); + return 1; +} + +// Same as computeTypeLocationSize but for uniforms +int TIntermediate::computeTypeUniformLocationSize(const TType& type) +{ + // "Individual elements of a uniform array are assigned + // consecutive locations with the first element taking location + // location." + if (type.isArray()) { + // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness + TType elementType(type, 0); + if (type.isSizedArray()) { + return type.getOuterArraySize() * computeTypeUniformLocationSize(elementType); + } else { + // TODO: are there valid cases of having an implicitly-sized array with a location? If so, running this code too early. + return computeTypeUniformLocationSize(elementType); + } + } + + // "Each subsequent inner-most member or element gets incremental + // locations for the entire structure or array." + if (type.isStruct()) { + int size = 0; + for (int member = 0; member < (int)type.getStruct()->size(); ++member) { + TType memberType(type, member); + size += computeTypeUniformLocationSize(memberType); + } + return size; + } + + return 1; +} + +#ifndef GLSLANG_WEB + +// Accumulate xfb buffer ranges and check for collisions as the accumulation is done. +// +// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. +// +int TIntermediate::addXfbBufferOffset(const TType& type) +{ + const TQualifier& qualifier = type.getQualifier(); + + assert(qualifier.hasXfbOffset() && qualifier.hasXfbBuffer()); + TXfbBuffer& buffer = xfbBuffers[qualifier.layoutXfbBuffer]; + + // compute the range + unsigned int size = computeTypeXfbSize(type, buffer.contains64BitType, buffer.contains32BitType, buffer.contains16BitType); + buffer.implicitStride = std::max(buffer.implicitStride, qualifier.layoutXfbOffset + size); + TRange range(qualifier.layoutXfbOffset, qualifier.layoutXfbOffset + size - 1); + + // check for collisions + for (size_t r = 0; r < buffer.ranges.size(); ++r) { + if (range.overlap(buffer.ranges[r])) { + // there is a collision; pick an example to return + return std::max(range.start, buffer.ranges[r].start); + } + } + + buffer.ranges.push_back(range); + + return -1; // no collision +} + +// Recursively figure out how many bytes of xfb buffer are used by the given type. +// Return the size of type, in bytes. +// Sets contains64BitType to true if the type contains a 64-bit data type. +// Sets contains32BitType to true if the type contains a 32-bit data type. +// Sets contains16BitType to true if the type contains a 16-bit data type. +// N.B. Caller must set contains64BitType, contains32BitType, and contains16BitType to false before calling. +unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const +{ + // "...if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8, + // and the space taken in the buffer will be a multiple of 8. + // ...within the qualified entity, subsequent components are each + // assigned, in order, to the next available offset aligned to a multiple of + // that component's size. Aggregate types are flattened down to the component + // level to get this sequence of components." + + if (type.isSizedArray()) { + // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness + // Unsized array use to xfb should be a compile error. + TType elementType(type, 0); + return type.getOuterArraySize() * computeTypeXfbSize(elementType, contains64BitType, contains16BitType, contains16BitType); + } + + if (type.isStruct()) { + unsigned int size = 0; + bool structContains64BitType = false; + bool structContains32BitType = false; + bool structContains16BitType = false; + for (int member = 0; member < (int)type.getStruct()->size(); ++member) { + TType memberType(type, member); + // "... if applied to + // an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8, + // and the space taken in the buffer will be a multiple of 8." + bool memberContains64BitType = false; + bool memberContains32BitType = false; + bool memberContains16BitType = false; + int memberSize = computeTypeXfbSize(memberType, memberContains64BitType, memberContains32BitType, memberContains16BitType); + if (memberContains64BitType) { + structContains64BitType = true; + RoundToPow2(size, 8); + } else if (memberContains32BitType) { + structContains32BitType = true; + RoundToPow2(size, 4); + } else if (memberContains16BitType) { + structContains16BitType = true; + RoundToPow2(size, 2); + } + size += memberSize; + } + + if (structContains64BitType) { + contains64BitType = true; + RoundToPow2(size, 8); + } else if (structContains32BitType) { + contains32BitType = true; + RoundToPow2(size, 4); + } else if (structContains16BitType) { + contains16BitType = true; + RoundToPow2(size, 2); + } + return size; + } + + int numComponents; + if (type.isScalar()) + numComponents = 1; + else if (type.isVector()) + numComponents = type.getVectorSize(); + else if (type.isMatrix()) + numComponents = type.getMatrixCols() * type.getMatrixRows(); + else { + assert(0); + numComponents = 1; + } + + if (type.getBasicType() == EbtDouble || type.getBasicType() == EbtInt64 || type.getBasicType() == EbtUint64) { + contains64BitType = true; + return 8 * numComponents; + } else if (type.getBasicType() == EbtFloat16 || type.getBasicType() == EbtInt16 || type.getBasicType() == EbtUint16) { + contains16BitType = true; + return 2 * numComponents; + } else if (type.getBasicType() == EbtInt8 || type.getBasicType() == EbtUint8) + return numComponents; + else { + contains32BitType = true; + return 4 * numComponents; + } +} + +#endif + +const int baseAlignmentVec4Std140 = 16; + +// Return the size and alignment of a component of the given type. +// The size is returned in the 'size' parameter +// Return value is the alignment.. +int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size) +{ +#ifdef GLSLANG_WEB + size = 4; return 4; +#endif + + switch (type.getBasicType()) { + case EbtInt64: + case EbtUint64: + case EbtDouble: size = 8; return 8; + case EbtFloat16: size = 2; return 2; + case EbtInt8: + case EbtUint8: size = 1; return 1; + case EbtInt16: + case EbtUint16: size = 2; return 2; + case EbtReference: size = 8; return 8; + default: size = 4; return 4; + } +} + +// Implement base-alignment and size rules from section 7.6.2.2 Standard Uniform Block Layout +// Operates recursively. +// +// If std140 is true, it does the rounding up to vec4 size required by std140, +// otherwise it does not, yielding std430 rules. +// +// The size is returned in the 'size' parameter +// +// The stride is only non-0 for arrays or matrices, and is the stride of the +// top-level object nested within the type. E.g., for an array of matrices, +// it is the distances needed between matrices, despite the rules saying the +// stride comes from the flattening down to vectors. +// +// Return value is the alignment of the type. +int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor) +{ + int alignment; + + bool std140 = layoutPacking == glslang::ElpStd140; + // When using the std140 storage layout, structures will be laid out in buffer + // storage with its members stored in monotonically increasing order based on their + // location in the declaration. A structure and each structure member have a base + // offset and a base alignment, from which an aligned offset is computed by rounding + // the base offset up to a multiple of the base alignment. The base offset of the first + // member of a structure is taken from the aligned offset of the structure itself. The + // base offset of all other structure members is derived by taking the offset of the + // last basic machine unit consumed by the previous member and adding one. Each + // structure member is stored in memory at its aligned offset. The members of a top- + // level uniform block are laid out in buffer storage by treating the uniform block as + // a structure with a base offset of zero. + // + // 1. If the member is a scalar consuming N basic machine units, the base alignment is N. + // + // 2. If the member is a two- or four-component vector with components consuming N basic + // machine units, the base alignment is 2N or 4N, respectively. + // + // 3. If the member is a three-component vector with components consuming N + // basic machine units, the base alignment is 4N. + // + // 4. If the member is an array of scalars or vectors, the base alignment and array + // stride are set to match the base alignment of a single array element, according + // to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The + // array may have padding at the end; the base offset of the member following + // the array is rounded up to the next multiple of the base alignment. + // + // 5. If the member is a column-major matrix with C columns and R rows, the + // matrix is stored identically to an array of C column vectors with R + // components each, according to rule (4). + // + // 6. If the member is an array of S column-major matrices with C columns and + // R rows, the matrix is stored identically to a row of S X C column vectors + // with R components each, according to rule (4). + // + // 7. If the member is a row-major matrix with C columns and R rows, the matrix + // is stored identically to an array of R row vectors with C components each, + // according to rule (4). + // + // 8. If the member is an array of S row-major matrices with C columns and R + // rows, the matrix is stored identically to a row of S X R row vectors with C + // components each, according to rule (4). + // + // 9. If the member is a structure, the base alignment of the structure is N , where + // N is the largest base alignment value of any of its members, and rounded + // up to the base alignment of a vec4. The individual members of this substructure + // are then assigned offsets by applying this set of rules recursively, + // where the base offset of the first member of the sub-structure is equal to the + // aligned offset of the structure. The structure may have padding at the end; + // the base offset of the member following the sub-structure is rounded up to + // the next multiple of the base alignment of the structure. + // + // 10. If the member is an array of S structures, the S elements of the array are laid + // out in order, according to rule (9). + // + // Assuming, for rule 10: The stride is the same as the size of an element. + + stride = 0; + int dummyStride; + + // rules 4, 6, 8, and 10 + if (type.isArray()) { + // TODO: perf: this might be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness + TType derefType(type, 0); + alignment = getBaseAlignment(derefType, size, dummyStride, layoutPacking, rowMajor); + if (std140) + alignment = std::max(baseAlignmentVec4Std140, alignment); + RoundToPow2(size, alignment); + stride = size; // uses full matrix size for stride of an array of matrices (not quite what rule 6/8, but what's expected) + // uses the assumption for rule 10 in the comment above + // use one element to represent the last member of SSBO which is unsized array + int arraySize = (type.isUnsizedArray() && (type.getOuterArraySize() == 0)) ? 1 : type.getOuterArraySize(); + size = stride * arraySize; + return alignment; + } + + // rule 9 + if (type.getBasicType() == EbtStruct) { + const TTypeList& memberList = *type.getStruct(); + + size = 0; + int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0; + for (size_t m = 0; m < memberList.size(); ++m) { + int memberSize; + // modify just the children's view of matrix layout, if there is one for this member + TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix; + int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, dummyStride, layoutPacking, + (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor); + maxAlignment = std::max(maxAlignment, memberAlignment); + RoundToPow2(size, memberAlignment); + size += memberSize; + } + + // The structure may have padding at the end; the base offset of + // the member following the sub-structure is rounded up to the next + // multiple of the base alignment of the structure. + RoundToPow2(size, maxAlignment); + + return maxAlignment; + } + + // rule 1 + if (type.isScalar()) + return getBaseAlignmentScalar(type, size); + + // rules 2 and 3 + if (type.isVector()) { + int scalarAlign = getBaseAlignmentScalar(type, size); + switch (type.getVectorSize()) { + case 1: // HLSL has this, GLSL does not + return scalarAlign; + case 2: + size *= 2; + return 2 * scalarAlign; + default: + size *= type.getVectorSize(); + return 4 * scalarAlign; + } + } + + // rules 5 and 7 + if (type.isMatrix()) { + // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows + TType derefType(type, 0, rowMajor); + + alignment = getBaseAlignment(derefType, size, dummyStride, layoutPacking, rowMajor); + if (std140) + alignment = std::max(baseAlignmentVec4Std140, alignment); + RoundToPow2(size, alignment); + stride = size; // use intra-matrix stride for stride of a just a matrix + if (rowMajor) + size = stride * type.getMatrixRows(); + else + size = stride * type.getMatrixCols(); + + return alignment; + } + + assert(0); // all cases should be covered above + size = baseAlignmentVec4Std140; + return baseAlignmentVec4Std140; +} + +// To aid the basic HLSL rule about crossing vec4 boundaries. +bool TIntermediate::improperStraddle(const TType& type, int size, int offset) +{ + if (! type.isVector() || type.isArray()) + return false; + + return size <= 16 ? offset / 16 != (offset + size - 1) / 16 + : offset % 16 != 0; +} + +int TIntermediate::getScalarAlignment(const TType& type, int& size, int& stride, bool rowMajor) +{ + int alignment; + + stride = 0; + int dummyStride; + + if (type.isArray()) { + TType derefType(type, 0); + alignment = getScalarAlignment(derefType, size, dummyStride, rowMajor); + + stride = size; + RoundToPow2(stride, alignment); + + size = stride * (type.getOuterArraySize() - 1) + size; + return alignment; + } + + if (type.getBasicType() == EbtStruct) { + const TTypeList& memberList = *type.getStruct(); + + size = 0; + int maxAlignment = 0; + for (size_t m = 0; m < memberList.size(); ++m) { + int memberSize; + // modify just the children's view of matrix layout, if there is one for this member + TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix; + int memberAlignment = getScalarAlignment(*memberList[m].type, memberSize, dummyStride, + (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor); + maxAlignment = std::max(maxAlignment, memberAlignment); + RoundToPow2(size, memberAlignment); + size += memberSize; + } + + return maxAlignment; + } + + if (type.isScalar()) + return getBaseAlignmentScalar(type, size); + + if (type.isVector()) { + int scalarAlign = getBaseAlignmentScalar(type, size); + + size *= type.getVectorSize(); + return scalarAlign; + } + + if (type.isMatrix()) { + TType derefType(type, 0, rowMajor); + + alignment = getScalarAlignment(derefType, size, dummyStride, rowMajor); + + stride = size; // use intra-matrix stride for stride of a just a matrix + if (rowMajor) + size = stride * type.getMatrixRows(); + else + size = stride * type.getMatrixCols(); + + return alignment; + } + + assert(0); // all cases should be covered above + size = 1; + return 1; +} + +int TIntermediate::getMemberAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor) +{ + if (layoutPacking == glslang::ElpScalar) { + return getScalarAlignment(type, size, stride, rowMajor); + } else { + return getBaseAlignment(type, size, stride, layoutPacking, rowMajor); + } +} + +// shared calculation by getOffset and getOffsets +void TIntermediate::updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize) +{ + int dummyStride; + + // modify just the children's view of matrix layout, if there is one for this member + TLayoutMatrix subMatrixLayout = memberType.getQualifier().layoutMatrix; + int memberAlignment = getMemberAlignment(memberType, memberSize, dummyStride, + parentType.getQualifier().layoutPacking, + subMatrixLayout != ElmNone + ? subMatrixLayout == ElmRowMajor + : parentType.getQualifier().layoutMatrix == ElmRowMajor); + RoundToPow2(offset, memberAlignment); +} + +// Lookup or calculate the offset of a block member, using the recursively +// defined block offset rules. +int TIntermediate::getOffset(const TType& type, int index) +{ + const TTypeList& memberList = *type.getStruct(); + + // Don't calculate offset if one is present, it could be user supplied + // and different than what would be calculated. That is, this is faster, + // but not just an optimization. + if (memberList[index].type->getQualifier().hasOffset()) + return memberList[index].type->getQualifier().layoutOffset; + + int memberSize = 0; + int offset = 0; + for (int m = 0; m <= index; ++m) { + updateOffset(type, *memberList[m].type, offset, memberSize); + + if (m < index) + offset += memberSize; + } + + return offset; +} + +// Calculate the block data size. +// Block arrayness is not taken into account, each element is backed by a separate buffer. +int TIntermediate::getBlockSize(const TType& blockType) +{ + const TTypeList& memberList = *blockType.getStruct(); + int lastIndex = (int)memberList.size() - 1; + int lastOffset = getOffset(blockType, lastIndex); + + int lastMemberSize; + int dummyStride; + getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, + blockType.getQualifier().layoutPacking, + blockType.getQualifier().layoutMatrix == ElmRowMajor); + + return lastOffset + lastMemberSize; +} + +int TIntermediate::computeBufferReferenceTypeSize(const TType& type) +{ + assert(type.isReference()); + int size = getBlockSize(*type.getReferentType()); + + int align = type.getBufferReferenceAlignment(); + + if (align) { + size = (size + align - 1) & ~(align-1); + } + + return size; +} + +#ifndef GLSLANG_WEB +bool TIntermediate::isIoResizeArray(const TType& type, EShLanguage language) { + return type.isArray() && + ((language == EShLangGeometry && type.getQualifier().storage == EvqVaryingIn) || + (language == EShLangTessControl && type.getQualifier().storage == EvqVaryingOut && + ! type.getQualifier().patch) || + (language == EShLangFragment && type.getQualifier().storage == EvqVaryingIn && + type.getQualifier().pervertexNV) || + (language == EShLangMeshNV && type.getQualifier().storage == EvqVaryingOut && + !type.getQualifier().perTaskNV)); +} +#endif // not GLSLANG_WEB + +} // end namespace glslang diff --git a/libraries/glslang/glslang/MachineIndependent/localintermediate.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/localintermediate.h similarity index 77% rename from libraries/glslang/glslang/MachineIndependent/localintermediate.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/localintermediate.h index cb172e5e91f..6aa9399dcc1 100644 --- a/libraries/glslang/glslang/MachineIndependent/localintermediate.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/localintermediate.h @@ -162,7 +162,10 @@ struct TXfbBuffer { #endif // Track a set of strings describing how the module was processed. -// Using the form: +// This includes command line options, transforms, etc., ideally inclusive enough +// to reproduce the steps used to transform the input source to the output. +// E.g., see SPIR-V OpModuleProcessed. +// Each "process" or "transform" uses is expressed in the form: // process arg0 arg1 arg2 ... // process arg0 arg1 arg2 ... // where everything is textual, and there can be zero or more arguments @@ -222,6 +225,57 @@ enum ComputeDerivativeMode { LayoutDerivativeGroupLinear, // derivative_group_linearNV }; +class TIdMaps { +public: + TMap& operator[](long long i) { return maps[i]; } + const TMap& operator[](long long i) const { return maps[i]; } +private: + TMap maps[EsiCount]; +}; + +class TNumericFeatures { +public: + TNumericFeatures() : features(0) { } + TNumericFeatures(const TNumericFeatures&) = delete; + TNumericFeatures& operator=(const TNumericFeatures&) = delete; + typedef enum : unsigned int { + shader_explicit_arithmetic_types = 1 << 0, + shader_explicit_arithmetic_types_int8 = 1 << 1, + shader_explicit_arithmetic_types_int16 = 1 << 2, + shader_explicit_arithmetic_types_int32 = 1 << 3, + shader_explicit_arithmetic_types_int64 = 1 << 4, + shader_explicit_arithmetic_types_float16 = 1 << 5, + shader_explicit_arithmetic_types_float32 = 1 << 6, + shader_explicit_arithmetic_types_float64 = 1 << 7, + shader_implicit_conversions = 1 << 8, + gpu_shader_fp64 = 1 << 9, + gpu_shader_int16 = 1 << 10, + gpu_shader_half_float = 1 << 11, + } feature; + void insert(feature f) { features |= f; } + void erase(feature f) { features &= ~f; } + bool contains(feature f) const { return (features & f) != 0; } +private: + unsigned int features; +}; + +// MustBeAssigned wraps a T, asserting that it has been assigned with +// operator =() before attempting to read with operator T() or operator ->(). +// Used to catch cases where fields are read before they have been assigned. +template +class MustBeAssigned +{ +public: + MustBeAssigned() = default; + MustBeAssigned(const T& v) : value(v) {} + operator const T&() const { assert(isSet); return value; } + const T* operator ->() const { assert(isSet); return &value; } + MustBeAssigned& operator = (const T& v) { value = v; isSet = true; return *this; } +private: + T value; + bool isSet = false; +}; + // // Set of helper functions to help parse and build the tree. // @@ -229,12 +283,23 @@ class TIntermediate { public: explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : language(l), - profile(p), version(v), treeRoot(0), +#ifndef GLSLANG_ANGLE + profile(p), version(v), +#endif + treeRoot(0), + resources(TBuiltInResource{}), numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false), invertY(false), useStorageBuffer(false), + invariantAll(false), nanMinMaxClamp(false), - depthReplacing(false) + depthReplacing(false), + uniqueId(0), + globalUniformBlockName(""), + atomicCounterBlockName(""), + globalUniformBlockSet(TQualifier::layoutSetEnd), + globalUniformBlockBinding(TQualifier::layoutBindingEnd), + atomicCounterBlockSet(TQualifier::layoutSetEnd) #ifndef GLSLANG_WEB , implicitThisName("@this"), implicitCounterName("@count"), @@ -244,15 +309,16 @@ class TIntermediate { inputPrimitive(ElgNone), outputPrimitive(ElgNone), pixelCenterInteger(false), originUpperLeft(false), vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false), - postDepthCoverage(false), depthLayout(EldNone), + postDepthCoverage(false), depthLayout(EldNone), hlslFunctionality1(false), blendEquations(0), xfbMode(false), multiStream(false), layoutOverrideCoverage(false), geoPassthroughEXT(false), - numShaderRecordNVBlocks(0), + numShaderRecordBlocks(0), computeDerivativeMode(LayoutDerivativeNone), primitives(TQualifier::layoutNotSet), numTaskNVBlocks(0), + layoutPrimitiveCulling(false), autoMapBindings(false), autoMapLocations(false), flattenUniformArrays(false), @@ -263,7 +329,10 @@ class TIntermediate { textureSamplerTransformMode(EShTexSampTransKeep), needToLegalize(false), binaryDoubleOutput(false), + subgroupUniformControlFlow(false), usePhysicalStorageBuffer(false), + spirvRequirement(nullptr), + spirvExecutionMode(nullptr), uniformLocationBase(0) #endif { @@ -282,9 +351,20 @@ class TIntermediate { #endif } - void setVersion(int v) { version = v; } + void setVersion(int v) + { +#ifndef GLSLANG_ANGLE + version = v; +#endif + } + void setProfile(EProfile p) + { +#ifndef GLSLANG_ANGLE + profile = p; +#endif + } + int getVersion() const { return version; } - void setProfile(EProfile p) { profile = p; } EProfile getProfile() const { return profile; } void setSpv(const SpvVersion& s) { @@ -332,6 +412,9 @@ class TIntermediate { case EShTargetVulkan_1_1: processes.addProcess("target-env vulkan1.1"); break; + case EShTargetVulkan_1_2: + processes.addProcess("target-env vulkan1.2"); + break; default: processes.addProcess("target-env vulkanUnknown"); break; @@ -343,6 +426,9 @@ class TIntermediate { EShLanguage getStage() const { return language; } void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); } const std::set& getRequestedExtensions() const { return requestedExtensions; } + bool isRayTracingStage() const { + return language >= EShLangRayGen && language <= EShLangCallableNV; + } void setTreeRoot(TIntermNode* r) { treeRoot = r; } TIntermNode* getTreeRoot() const { return treeRoot; } @@ -351,6 +437,7 @@ class TIntermediate { int getNumErrors() const { return numErrors; } void addPushConstantCount() { ++numPushConstants; } void setLimits(const TBuiltInResource& r) { resources = r; } + const TBuiltInResource& getLimits() const { return resources; } bool postProcess(TIntermNode*, EShLanguage); void removeTree(); @@ -377,7 +464,7 @@ class TIntermediate { void setSource(EShSource s) { source = s; } EShSource getSource() const { return source; } #else - void setSource(EShSource s) { assert(s == EShSourceGlsl); } + void setSource(EShSource s) { assert(s == EShSourceGlsl); (void)s; } EShSource getSource() const { return EShSourceGlsl; } #endif @@ -388,15 +475,15 @@ class TIntermediate { TIntermSymbol* addSymbol(const TType&, const TSourceLoc&); TIntermSymbol* addSymbol(const TIntermSymbol&); TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*); - std::tuple addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1); + std::tuple addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1); TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*); TIntermTyped* addConversion(TBasicType convertTo, TIntermTyped* node) const; void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode); TIntermTyped* addShapeConversion(const TType&, TIntermTyped*); - TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc); - TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc); - TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc); - TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc); + TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); + TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); + TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&); + TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, const TSourceLoc&); TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType); bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const; bool isIntegralPromotion(TBasicType from, TBasicType to) const; @@ -410,7 +497,7 @@ class TIntermediate { TIntermAggregate* makeAggregate(TIntermNode* node); TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&); TIntermAggregate* makeAggregate(const TSourceLoc&); - TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc); + TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, const TSourceLoc&); bool areAllChildConst(TIntermAggregate* aggrNode); TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&); TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&); @@ -439,10 +526,11 @@ class TIntermediate { // Low level functions to add nodes (no conversions or other higher level transformations) // If a type is provided, the node's type will be set to it. - TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc) const; - TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, const TType&) const; - TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc) const; - TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc, const TType&) const; + TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&) const; + TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&, + const TType&) const; + TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&) const; + TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc&, const TType&) const; // Constant folding (in Constant.cpp) TIntermTyped* fold(TIntermAggregate* aggrNode); @@ -451,18 +539,30 @@ class TIntermediate { TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors& fields, const TSourceLoc&); // Tree ops - static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay); + static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay , bool BufferReferenceOk = false); // Linkage related void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&); + TIntermAggregate* findLinkerObjects() const; - void setUseStorageBuffer() - { - useStorageBuffer = true; - processes.addProcess("use-storage-buffer"); - } + void setGlobalUniformBlockName(const char* name) { globalUniformBlockName = std::string(name); } + const char* getGlobalUniformBlockName() const { return globalUniformBlockName.c_str(); } + void setGlobalUniformSet(unsigned int set) { globalUniformBlockSet = set; } + unsigned int getGlobalUniformSet() const { return globalUniformBlockSet; } + void setGlobalUniformBinding(unsigned int binding) { globalUniformBlockBinding = binding; } + unsigned int getGlobalUniformBinding() const { return globalUniformBlockBinding; } + + void setAtomicCounterBlockName(const char* name) { atomicCounterBlockName = std::string(name); } + const char* getAtomicCounterBlockName() const { return atomicCounterBlockName.c_str(); } + void setAtomicCounterBlockSet(unsigned int set) { atomicCounterBlockSet = set; } + unsigned int getAtomicCounterBlockSet() const { return atomicCounterBlockSet; } + + + void setUseStorageBuffer() { useStorageBuffer = true; } bool usingStorageBuffer() const { return useStorageBuffer; } + void setInvariantAll() { invariantAll = true; } + bool isInvariantAll() const { return invariantAll; } void setDepthReplacing() { depthReplacing = true; } bool isDepthReplacing() const { return depthReplacing; } bool setLocalSize(int dim, int size) @@ -474,6 +574,11 @@ class TIntermediate { return true; } unsigned int getLocalSize(int dim) const { return localSize[dim]; } + bool isLocalSizeSet() const + { + // Return true if any component has been set (i.e. any component is not default). + return localSizeNotDefault[0] || localSizeNotDefault[1] || localSizeNotDefault[2]; + } bool setLocalSizeSpecId(int dim, int id) { if (localSizeSpecId[dim] != TQualifier::layoutNotSet) @@ -482,6 +587,13 @@ class TIntermediate { return true; } int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; } + bool isLocalSizeSpecialized() const + { + // Return true if any component has been specialized. + return localSizeSpecId[0] != TQualifier::layoutNotSet || + localSizeSpecId[1] != TQualifier::layoutNotSet || + localSizeSpecId[2] != TQualifier::layoutNotSet; + } #ifdef GLSLANG_WEB void output(TInfoSink&, bool tree) { } @@ -500,7 +612,7 @@ class TIntermediate { bool getAutoMapBindings() const { return false; } bool getAutoMapLocations() const { return false; } int getNumPushConstants() const { return 0; } - void addShaderRecordNVCount() { } + void addShaderRecordCount() { } void addTaskNVCount() { } void setUseVulkanMemoryModel() { } bool usingVulkanMemoryModel() const { return false; } @@ -580,7 +692,7 @@ class TIntermediate { processes.addProcess("flatten-uniform-arrays"); } bool getFlattenUniformArrays() const { return flattenUniformArrays; } -#endif +#endif void setNoStorageFormat(bool b) { useUnknownFormat = b; @@ -617,7 +729,7 @@ class TIntermediate { void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; } int getNumPushConstants() const { return numPushConstants; } - void addShaderRecordNVCount() { ++numShaderRecordNVBlocks; } + void addShaderRecordCount() { ++numShaderRecordBlocks; } void addTaskNVCount() { ++numTaskNVBlocks; } bool setInvocations(int i) @@ -720,6 +832,8 @@ class TIntermediate { void setLayoutDerivativeMode(ComputeDerivativeMode mode) { computeDerivativeMode = mode; } bool hasLayoutDerivativeModeNone() const { return computeDerivativeMode != LayoutDerivativeNone; } ComputeDerivativeMode getLayoutDerivativeModeNone() const { return computeDerivativeMode; } + void setLayoutPrimitiveCulling() { layoutPrimitiveCulling = true; } + bool getLayoutPrimitiveCulling() const { return layoutPrimitiveCulling; } bool setPrimitives(int m) { if (primitives != TQualifier::layoutNotSet) @@ -756,8 +870,34 @@ class TIntermediate { void setBinaryDoubleOutput() { binaryDoubleOutput = true; } bool getBinaryDoubleOutput() { return binaryDoubleOutput; } + + void setSubgroupUniformControlFlow() { subgroupUniformControlFlow = true; } + bool getSubgroupUniformControlFlow() const { return subgroupUniformControlFlow; } + + // GL_EXT_spirv_intrinsics + void insertSpirvRequirement(const TSpirvRequirement* spirvReq); + bool hasSpirvRequirement() const { return spirvRequirement != nullptr; } + const TSpirvRequirement& getSpirvRequirement() const { return *spirvRequirement; } + void insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args = nullptr); + void insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args); + bool hasSpirvExecutionMode() const { return spirvExecutionMode != nullptr; } + const TSpirvExecutionMode& getSpirvExecutionMode() const { return *spirvExecutionMode; } #endif // GLSLANG_WEB + void addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing) + { + std::string name(nameStr); + blockBackingOverrides[name] = backing; + } + TBlockStorageClass getBlockStorageOverride(const char* nameStr) const + { + std::string name = nameStr; + auto pos = blockBackingOverrides.find(name); + if (pos == blockBackingOverrides.end()) + return EbsNone; + else + return pos->second; + } #ifdef ENABLE_HLSL void setHlslFunctionality1() { hlslFunctionality1 = true; } bool getHlslFunctionality1() const { return hlslFunctionality1; } @@ -781,10 +921,27 @@ class TIntermediate { bool usingHlslIoMapping() { return false; } #endif + bool usingScalarBlockLayout() const { + for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt) { + if (*extIt == E_GL_EXT_scalar_block_layout) + return true; + } + return false; + } + + bool IsRequestedExtension(const char* extension) const + { + return (requestedExtensions.find(extension) != requestedExtensions.end()); + } + void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee); void merge(TInfoSink&, TIntermediate&); void finalCheck(TInfoSink&, bool keepUncalled); + void mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& unit, bool mergeExistingOnly); + void mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit); + void checkStageIO(TInfoSink&, TIntermediate&); + bool buildConvertOp(TBasicType dst, TBasicType src, TOperator& convertOp) const; TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const; @@ -793,6 +950,7 @@ class TIntermediate { int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision); int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision); + int checkLocationRT(int set, int location); int addUsedOffsets(int binding, int offset, int numOffsets); bool addUsedConstantId(int id); static int computeTypeLocationSize(const TType&, EShLanguage); @@ -807,6 +965,8 @@ class TIntermediate { static int getOffset(const TType& type, int index); static int getBlockSize(const TType& blockType); static int computeBufferReferenceTypeSize(const TType&); + static bool isIoResizeArray(const TType& type, EShLanguage language); + bool promote(TIntermOperator*); void setNanMinMaxClamp(bool setting) { nanMinMaxClamp = setting; } bool getNanMinMaxClamp() const { return nanMinMaxClamp; } @@ -825,47 +985,53 @@ class TIntermediate { void addProcess(const std::string& process) { processes.addProcess(process); } void addProcessArgument(const std::string& arg) { processes.addArgument(arg); } const std::vector& getProcesses() const { return processes.getProcesses(); } + unsigned long long getUniqueId() const { return uniqueId; } + void setUniqueId(unsigned long long id) { uniqueId = id; } // Certain explicit conversions are allowed conditionally #ifdef GLSLANG_WEB bool getArithemeticInt8Enabled() const { return false; } bool getArithemeticInt16Enabled() const { return false; } bool getArithemeticFloat16Enabled() const { return false; } + void updateNumericFeature(TNumericFeatures::feature f, bool on) { } #else bool getArithemeticInt8Enabled() const { - return extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int8); + return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8); } bool getArithemeticInt16Enabled() const { - return extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_AMD_gpu_shader_int16) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int16); + return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) || + numericFeatures.contains(TNumericFeatures::gpu_shader_int16) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16); } bool getArithemeticFloat16Enabled() const { - return extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) || - extensionRequested(E_GL_AMD_gpu_shader_half_float) || - extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float16); + return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) || + numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) || + numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16); } + void updateNumericFeature(TNumericFeatures::feature f, bool on) + { on ? numericFeatures.insert(f) : numericFeatures.erase(f); } #endif protected: - TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); + TIntermSymbol* addSymbol(long long Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); void error(TInfoSink& infoSink, const char*); void warn(TInfoSink& infoSink, const char*); void mergeCallGraphs(TInfoSink&, TIntermediate&); void mergeModes(TInfoSink&, TIntermediate&); void mergeTrees(TInfoSink&, TIntermediate&); - void seedIdMap(TMap& idMap, int& maxId); - void remapIds(const TMap& idMap, int idShift, TIntermediate&); + void seedIdMap(TIdMaps& idMaps, long long& IdShift); + void remapIds(const TIdMaps& idMaps, long long idShift, TIntermediate&); void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals); - void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects); + void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects, EShLanguage); + void mergeBlockDefinitions(TInfoSink&, TIntermSymbol* block, TIntermSymbol* unitBlock, TIntermediate* unitRoot); void mergeImplicitArraySizes(TType&, const TType&); - void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage); + void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, EShLanguage); void checkCallGraphCycles(TInfoSink&); void checkCallGraphBodies(TInfoSink&, bool keepUncalled); void inOutLocationCheck(TInfoSink&); - TIntermAggregate* findLinkerObjects() const; + void sharedBlockCheck(TInfoSink&); bool userOutputUsed() const; bool isSpecializationOperation(const TIntermOperator&) const; bool isNonuniformPropagating(TOperator) const; @@ -878,17 +1044,7 @@ class TIntermediate { bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&); void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root); bool isConversionAllowed(TOperator op, TIntermTyped* node) const; - std::tuple getConversionDestinatonType(TBasicType type0, TBasicType type1, TOperator op) const; - - // JohnK: I think this function should go away. - // This data structure is just a log to pass on to back ends. - // Versioning and extensions are handled in Version.cpp, with a rich - // set of functions for querying stages, versions, extension enable/disabled, etc. -#ifdef GLSLANG_WEB - bool extensionRequested(const char *extension) const { return false; } -#else - bool extensionRequested(const char *extension) const {return requestedExtensions.find(extension) != requestedExtensions.end();} -#endif + std::tuple getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const; static const char* getResourceName(TResourceType); @@ -898,23 +1054,37 @@ class TIntermediate { typedef std::list TGraph; TGraph callGraph; +#ifdef GLSLANG_ANGLE + const EProfile profile = ECoreProfile; + const int version = 450; +#else EProfile profile; // source profile int version; // source version +#endif SpvVersion spvVersion; TIntermNode* treeRoot; std::set requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them - TBuiltInResource resources; + MustBeAssigned resources; int numEntryPoints; int numErrors; int numPushConstants; bool recursive; bool invertY; bool useStorageBuffer; + bool invariantAll; bool nanMinMaxClamp; // true if desiring min/max/clamp to favor non-NaN over NaN bool depthReplacing; int localSize[3]; bool localSizeNotDefault[3]; int localSizeSpecId[3]; + unsigned long long uniqueId; + + std::string globalUniformBlockName; + std::string atomicCounterBlockName; + unsigned int globalUniformBlockSet; + unsigned int globalUniformBlockBinding; + unsigned int atomicCounterBlockSet; + #ifndef GLSLANG_WEB public: const char* const implicitThisName; @@ -942,10 +1112,11 @@ class TIntermediate { bool multiStream; bool layoutOverrideCoverage; bool geoPassthroughEXT; - int numShaderRecordNVBlocks; + int numShaderRecordBlocks; ComputeDerivativeMode computeDerivativeMode; int primitives; int numTaskNVBlocks; + bool layoutPrimitiveCulling; // Base shift values std::array shiftBinding; @@ -968,15 +1139,23 @@ class TIntermediate { bool needToLegalize; bool binaryDoubleOutput; + bool subgroupUniformControlFlow; bool usePhysicalStorageBuffer; + TSpirvRequirement* spirvRequirement; + TSpirvExecutionMode* spirvExecutionMode; + std::unordered_map uniformLocationOverrides; int uniformLocationBase; + TNumericFeatures numericFeatures; #endif + std::unordered_map blockBackingOverrides; std::unordered_set usedConstantId; // specialization constant ids used std::vector usedAtomics; // sets of bindings used by atomic counters std::vector usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers + std::vector usedIoRT[2]; // sets of used location, one for rayPayload/rayPayloadIN and other + // for callableData/callableDataIn // set of names of statically read/written I/O that might need extra checking std::set ioAccessed; // source code of shader, useful as part of debug information diff --git a/libraries/glslang/glslang/MachineIndependent/parseConst.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/parseConst.cpp similarity index 87% rename from libraries/glslang/glslang/MachineIndependent/parseConst.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/parseConst.cpp index 1a8e6d9987c..6c182991f51 100644 --- a/libraries/glslang/glslang/MachineIndependent/parseConst.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/parseConst.cpp @@ -165,22 +165,31 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) } } } else { - // matrix from vector - int count = 0; - const int startIndex = index; + // matrix from vector or scalar int nodeComps = node->getType().computeNumComponents(); - for (int i = startIndex; i < endIndex; i++) { - if (i >= instanceSize) - return; - if (i == startIndex || (i - startIndex) % (matrixRows + 1) == 0 ) + if (nodeComps == 1) { + for (int c = 0; c < matrixCols; ++c) { + for (int r = 0; r < matrixRows; ++r) { + if (r == c) + leftUnionArray[index] = rightUnionArray[0]; + else + leftUnionArray[index].setDConst(0.0); + index++; + } + } + } else { + int count = 0; + for (int i = index; i < endIndex; i++) { + if (i >= instanceSize) + return; + + // construct the matrix in column-major order, from + // the components provided, in order leftUnionArray[i] = rightUnionArray[count]; - else - leftUnionArray[i].setDConst(0.0); - - index++; - if (nodeComps > 1) + index++; count++; + } } } } diff --git a/libraries/glslang/glslang/MachineIndependent/parseVersions.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/parseVersions.h similarity index 95% rename from libraries/glslang/glslang/MachineIndependent/parseVersions.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/parseVersions.h index aa1964fc2e5..7248354e4b6 100644 --- a/libraries/glslang/glslang/MachineIndependent/parseVersions.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/parseVersions.h @@ -58,7 +58,7 @@ class TParseVersions { const SpvVersion& spvVersion, EShLanguage language, TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) : -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) forwardCompatible(forwardCompatible), profile(profile), #endif @@ -101,6 +101,7 @@ class TParseVersions { void updateExtensionBehavior(int line, const char* const extension, const char* behavior) { } void updateExtensionBehavior(const char* const extension, TExtensionBehavior) { } void checkExtensionStage(const TSourceLoc&, const char* const extension) { } + void extensionRequires(const TSourceLoc&, const char* const extension, const char* behavior) { } void fullIntegerCheck(const TSourceLoc&, const char* op) { } void doubleCheck(const TSourceLoc&, const char* op) { } bool float16Arithmetic() { return false; } @@ -115,9 +116,14 @@ class TParseVersions { bool relaxedErrors() const { return false; } bool suppressWarnings() const { return true; } bool isForwardCompatible() const { return false; } +#else +#ifdef GLSLANG_ANGLE + const bool forwardCompatible = true; + const EProfile profile = ECoreProfile; #else bool forwardCompatible; // true if errors are to be given for use of deprecated features EProfile profile; // the declared profile in the shader (core by default) +#endif bool isEsProfile() const { return profile == EEsProfile; } void requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc); void profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, @@ -139,6 +145,7 @@ class TParseVersions { virtual bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc); virtual void checkExtensionStage(const TSourceLoc&, const char* const extension); + virtual void extensionRequires(const TSourceLoc&, const char* const extension, const char* behavior); virtual void fullIntegerCheck(const TSourceLoc&, const char* op); virtual void unimplemented(const TSourceLoc&, const char* featureDesc); @@ -170,6 +177,7 @@ class TParseVersions { virtual void vulkanRemoved(const TSourceLoc&, const char* op); virtual void requireVulkan(const TSourceLoc&, const char* op); virtual void requireSpv(const TSourceLoc&, const char* op); + virtual void requireSpv(const TSourceLoc&, const char *op, unsigned int version); #if defined(GLSLANG_WEB) && !defined(GLSLANG_WEB_DEVEL) @@ -221,7 +229,8 @@ class TParseVersions { TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree protected: - TMap extensionBehavior; // for each extension string, what its current behavior is set to + TMap extensionBehavior; // for each extension string, what its current behavior is + TMap extensionMinSpv; // for each extension string, store minimum spirv required EShMessages messages; // errors/warnings/rule-sets int numErrors; // number of compile-time errors encountered TInputScanner* currentScanner; diff --git a/libraries/glslang/glslang/MachineIndependent/pch.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/pch.h similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/pch.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/pch.h diff --git a/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp similarity index 97% rename from libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp index d7ff485c0aa..aa1e0d74516 100644 --- a/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp @@ -422,10 +422,10 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo if (! parseContext.isReadingHLSL() && isMacroInput()) { if (parseContext.relaxedErrors()) parseContext.ppWarn(ppToken->loc, "nonportable when expanded from macros for preprocessor expression", - "defined", ""); + "defined", ""); else parseContext.ppError(ppToken->loc, "cannot use in preprocessor expression when expanded from macros", - "defined", ""); + "defined", ""); } bool needclose = 0; token = scanToken(ppToken); @@ -455,6 +455,7 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo token = scanToken(ppToken); } } else { + token = tokenPaste(token, *ppToken); token = evalToToken(token, shortCircuit, res, err, ppToken); return eval(token, precedence, shortCircuit, res, err, ppToken); } @@ -621,14 +622,25 @@ int TPpContext::CPPinclude(TPpToken* ppToken) { const TSourceLoc directiveLoc = ppToken->loc; bool startWithLocalSearch = true; // to additionally include the extra "" paths - int token = scanToken(ppToken); + int token; - // handle -style #include - if (token == '<') { + // Find the first non-whitespace char after #include + int ch = getChar(); + while (ch == ' ' || ch == '\t') { + ch = getChar(); + } + if (ch == '<') { + // style startWithLocalSearch = false; token = scanHeaderName(ppToken, '>'); + } else if (ch == '"') { + // "header-name" style + token = scanHeaderName(ppToken, '"'); + } else { + // unexpected, get the full token to generate the error + ungetChar(); + token = scanToken(ppToken); } - // otherwise ppToken already has the header name and it was "header-name" style if (token != PpAtomConstString) { parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", ""); @@ -711,7 +723,9 @@ int TPpContext::CPPline(TPpToken* ppToken) const char* sourceName = nullptr; // Optional source file name. bool lineErr = false; bool fileErr = false; + disableEscapeSequences = true; token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken); + disableEscapeSequences = false; if (! lineErr) { lineToken = lineRes; if (token == '\n') @@ -754,7 +768,9 @@ int TPpContext::CPPline(TPpToken* ppToken) // Handle #error int TPpContext::CPPerror(TPpToken* ppToken) { + disableEscapeSequences = true; int token = scanToken(ppToken); + disableEscapeSequences = false; std::string message; TSourceLoc loc = ppToken->loc; @@ -1169,7 +1185,9 @@ MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, b int macroAtom = atomStrings.getAtom(ppToken->name); switch (macroAtom) { case PpAtomLineMacro: - ppToken->ival = parseContext.getCurrentLoc().line; + // Arguments which are macro have been replaced in the first stage. + if (ppToken->ival == 0) + ppToken->ival = parseContext.getCurrentLoc().line; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; @@ -1270,6 +1288,11 @@ MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, b nestStack.push_back('}'); else if (nestStack.size() > 0 && token == nestStack.back()) nestStack.pop_back(); + + //Macro replacement list is expanded in the last stage. + if (atomStrings.getAtom(ppToken->name) == PpAtomLineMacro) + ppToken->ival = parseContext.getCurrentLoc().line; + in->args[arg]->putToken(token, ppToken); tokenRecorded = true; } diff --git a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp diff --git a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp similarity index 98% rename from libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp index cc003a8d12b..1363ce2be04 100644 --- a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp @@ -87,7 +87,8 @@ namespace glslang { TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) : preamble(0), strings(0), previous_token('\n'), parseContext(pc), includer(inclr), inComment(false), rootFileName(rootFileName), - currentSourceFile(rootFileName) + currentSourceFile(rootFileName), + disableEscapeSequences(false) { ifdepth = 0; for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++) diff --git a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpContext.h similarity index 99% rename from libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpContext.h index 8470e172a22..714b5eadba4 100644 --- a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpContext.h @@ -105,13 +105,13 @@ class TPpToken { } // Used for comparing macro definitions, so checks what is relevant for that. - bool operator==(const TPpToken& right) + bool operator==(const TPpToken& right) const { return space == right.space && ival == right.ival && dval == right.dval && i64val == right.i64val && strncmp(name, right.name, MaxTokenLength) == 0; } - bool operator!=(const TPpToken& right) { return ! operator==(right); } + bool operator!=(const TPpToken& right) const { return ! operator==(right); } TSourceLoc loc; // True if a space (for white space or a removed comment) should also be @@ -695,6 +695,7 @@ class TPpContext { std::string currentSourceFile; std::istringstream strtodStream; + bool disableEscapeSequences; }; } // end namespace glslang diff --git a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp similarity index 92% rename from libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp index c293af3c1ea..ad11792002c 100644 --- a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp @@ -1026,12 +1026,80 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) case '\'': return pp->characterLiteral(ppToken); case '"': - // TODO: If this gets enhanced to handle escape sequences, or - // anything that is different than what #include needs, then - // #include needs to use scanHeaderName() for this. + // #include uses scanHeaderName() to ignore these escape sequences. ch = getch(); while (ch != '"' && ch != '\n' && ch != EndOfInput) { if (len < MaxTokenLength) { + if (ch == '\\' && !pp->disableEscapeSequences) { + int nextCh = getch(); + switch (nextCh) { + case '\'': ch = 0x27; break; + case '"': ch = 0x22; break; + case '?': ch = 0x3f; break; + case '\\': ch = 0x5c; break; + case 'a': ch = 0x07; break; + case 'b': ch = 0x08; break; + case 'f': ch = 0x0c; break; + case 'n': ch = 0x0a; break; + case 'r': ch = 0x0d; break; + case 't': ch = 0x09; break; + case 'v': ch = 0x0b; break; + case 'x': + // Hex value, arbitrary number of characters. Terminated by the first + // non-hex digit + { + int numDigits = 0; + ch = 0; + while (true) { + nextCh = getch(); + if (nextCh >= '0' && nextCh <= '9') + nextCh -= '0'; + else if (nextCh >= 'A' && nextCh <= 'F') + nextCh -= 'A' - 10; + else if (nextCh >= 'a' && nextCh <= 'f') + nextCh -= 'a' - 10; + else { + ungetch(); + break; + } + numDigits++; + ch = ch * 0x10 + nextCh; + } + if (numDigits == 0) { + pp->parseContext.ppError(ppToken->loc, "Expected hex value in escape sequence", "string", ""); + } + break; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + // Octal value, up to three octal digits + { + int numDigits = 1; + ch = nextCh - '0'; + while (numDigits < 3) { + nextCh = getch(); + if (nextCh >= '0' && nextCh <= '7') + nextCh -= '0'; + else { + ungetch(); + break; + } + numDigits++; + ch = ch * 8 + nextCh; + } + break; + } + default: + pp->parseContext.ppError(ppToken->loc, "Invalid escape sequence", "string", ""); + break; + } + } ppToken->name[len] = (char)ch; len++; ch = getch(); @@ -1120,10 +1188,14 @@ int TPpContext::tokenize(TPpToken& ppToken) continue; break; case PpAtomConstString: + // HLSL allows string literals. + // GLSL allows string literals with GL_EXT_debug_printf. if (ifdepth == 0 && parseContext.intermediate.getSource() != EShSourceHlsl) { - // HLSL allows string literals. - parseContext.ppError(ppToken.loc, "string literals not supported", "\"\"", ""); - continue; + const char* const string_literal_EXTs[] = { E_GL_EXT_debug_printf, E_GL_EXT_spirv_intrinsics }; + parseContext.requireExtensions(ppToken.loc, 2, string_literal_EXTs, "string literal"); + if (!parseContext.extensionTurnedOn(E_GL_EXT_debug_printf) && + !parseContext.extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) + continue; } break; case '\'': diff --git a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp diff --git a/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h diff --git a/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/propagateNoContraction.cpp similarity index 99% rename from libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/propagateNoContraction.cpp index 83a3230f515..9def592bafa 100644 --- a/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/propagateNoContraction.cpp @@ -867,4 +867,4 @@ void PropagateNoContraction(const glslang::TIntermediate& intermediate) } }; -#endif // GLSLANG_WEB \ No newline at end of file +#endif // GLSLANG_WEB diff --git a/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/propagateNoContraction.h similarity index 100% rename from libraries/glslang/glslang/MachineIndependent/propagateNoContraction.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/propagateNoContraction.h diff --git a/libraries/glslang/glslang/MachineIndependent/reflection.cpp b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/reflection.cpp similarity index 83% rename from libraries/glslang/glslang/MachineIndependent/reflection.cpp rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/reflection.cpp index b09367113cf..9ea48c452df 100644 --- a/libraries/glslang/glslang/MachineIndependent/reflection.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/reflection.cpp @@ -33,7 +33,7 @@ // POSSIBILITY OF SUCH DAMAGE. // -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) #include "../Include/Common.h" #include "reflection.h" @@ -77,10 +77,10 @@ namespace glslang { // This is in the glslang namespace directly so it can be a friend of TReflection. // -class TReflectionTraverser : public TLiveTraverser { +class TReflectionTraverser : public TIntermTraverser { public: TReflectionTraverser(const TIntermediate& i, TReflection& r) : - TLiveTraverser(i), reflection(r) { } + TIntermTraverser(), intermediate(i), reflection(r), updateStageMasks(true) { } virtual bool visitBinary(TVisit, TIntermBinary* node); virtual void visitSymbol(TIntermSymbol* base); @@ -92,11 +92,28 @@ class TReflectionTraverser : public TLiveTraverser { if (processedDerefs.find(&base) == processedDerefs.end()) { processedDerefs.insert(&base); + int blockIndex = -1; + int offset = -1; + TList derefs; + TString baseName = base.getName(); + + if (base.getType().getBasicType() == EbtBlock) { + offset = 0; + bool anonymous = IsAnonymous(baseName); + const TString& blockName = base.getType().getTypeName(); + + if (!anonymous) + baseName = blockName; + else + baseName = ""; + + blockIndex = addBlockName(blockName, base.getType(), intermediate.getBlockSize(base.getType())); + } + // Use a degenerate (empty) set of dereferences to immediately put as at the end of // the dereference change expected by blowUpActiveAggregate. - TList derefs; - blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0, 0, - base.getQualifier().storage, true); + blowUpActiveAggregate(base.getType(), baseName, derefs, derefs.end(), offset, blockIndex, 0, -1, 0, + base.getQualifier().storage, updateStageMasks); } } @@ -155,9 +172,9 @@ class TReflectionTraverser : public TLiveTraverser { void getOffsets(const TType& type, TVector& offsets) { const TTypeList& memberList = *type.getStruct(); - int memberSize = 0; int offset = 0; + for (size_t m = 0; m < offsets.size(); ++m) { // if the user supplied an offset, snap to it now if (memberList[m].type->getQualifier().hasOffset()) @@ -233,7 +250,7 @@ class TReflectionTraverser : public TLiveTraverser { // A value of 0 for arraySize will mean to use the full array's size. void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList& derefs, TList::const_iterator deref, int offset, int blockIndex, int arraySize, - int topLevelArrayStride, TStorageQualifier baseStorage, bool active) + int topLevelArraySize, int topLevelArrayStride, TStorageQualifier baseStorage, bool active) { // when strictArraySuffix is enabled, we closely follow the rules from ARB_program_interface_query. // Broadly: @@ -262,14 +279,15 @@ class TReflectionTraverser : public TLiveTraverser { // Visit all the indices of this array, and for each one add on the remaining dereferencing for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) { TString newBaseName = name; - if (strictArraySuffix && blockParent) + if (terminalType->getBasicType() == EbtBlock) {} + else if (strictArraySuffix && blockParent) newBaseName.append(TString("[0]")); else if (strictArraySuffix || baseType.getBasicType() != EbtBlock) newBaseName.append(TString("[") + String(i) + "]"); TList::const_iterator nextDeref = deref; ++nextDeref; blowUpActiveAggregate(*terminalType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize, - topLevelArrayStride, baseStorage, active); + topLevelArraySize, topLevelArrayStride, baseStorage, active); if (offset >= 0) offset += stride; @@ -282,9 +300,10 @@ class TReflectionTraverser : public TLiveTraverser { int stride = getArrayStride(baseType, visitNode->getLeft()->getType()); index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst(); - if (strictArraySuffix && blockParent) { + if (terminalType->getBasicType() == EbtBlock) {} + else if (strictArraySuffix && blockParent) name.append(TString("[0]")); - } else if (strictArraySuffix || baseType.getBasicType() != EbtBlock) { + else if (strictArraySuffix || baseType.getBasicType() != EbtBlock) { name.append(TString("[") + String(index) + "]"); if (offset >= 0) @@ -294,7 +313,10 @@ class TReflectionTraverser : public TLiveTraverser { if (topLevelArrayStride == 0) topLevelArrayStride = stride; - blockParent = false; + // expand top-level arrays in blocks with [0] suffix + if (topLevelArrayStride != 0 && visitNode->getLeft()->getType().isArray()) { + blockParent = false; + } break; } case EOpIndexDirectStruct: @@ -304,6 +326,12 @@ class TReflectionTraverser : public TLiveTraverser { if (name.size() > 0) name.append("."); name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName()); + + // expand non top-level arrays with [x] suffix + if (visitNode->getLeft()->getType().getBasicType() != EbtBlock && terminalType->isArray()) + { + blockParent = false; + } break; default: break; @@ -323,24 +351,27 @@ class TReflectionTraverser : public TLiveTraverser { if (offset >= 0) stride = getArrayStride(baseType, *terminalType); - if (topLevelArrayStride == 0) - topLevelArrayStride = stride; - int arrayIterateSize = std::max(terminalType->getOuterArraySize(), 1); // for top-level arrays in blocks, only expand [0] to avoid explosion of items - if (strictArraySuffix && blockParent) + if ((strictArraySuffix && blockParent) || + ((topLevelArraySize == arrayIterateSize) && (topLevelArrayStride == 0))) { arrayIterateSize = 1; + } + + if (topLevelArrayStride == 0) + topLevelArrayStride = stride; for (int i = 0; i < arrayIterateSize; ++i) { TString newBaseName = name; - newBaseName.append(TString("[") + String(i) + "]"); + if (terminalType->getBasicType() != EbtBlock) + newBaseName.append(TString("[") + String(i) + "]"); TType derefType(*terminalType, 0); if (offset >= 0) offset = baseOffset + stride * i; blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0, - topLevelArrayStride, baseStorage, active); + topLevelArraySize, topLevelArrayStride, baseStorage, active); } } else { // Visit all members of this aggregate, and for each one, @@ -369,8 +400,31 @@ class TReflectionTraverser : public TLiveTraverser { arrayStride = getArrayStride(baseType, derefType); } - blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0, - arrayStride, baseStorage, active); + if (topLevelArraySize == -1 && arrayStride == 0 && blockParent) + topLevelArraySize = 1; + + if (strictArraySuffix && blockParent) { + // if this member is an array, store the top-level array stride but start the explosion from + // the inner struct type. + if (derefType.isArray() && derefType.isStruct()) { + newBaseName.append("[0]"); + auto dimSize = derefType.isUnsizedArray() ? 0 : derefType.getArraySizes()->getDimSize(0); + blowUpActiveAggregate(TType(derefType, 0), newBaseName, derefs, derefs.end(), memberOffsets[i], + blockIndex, 0, dimSize, arrayStride, terminalType->getQualifier().storage, false); + } + else if (derefType.isArray()) { + auto dimSize = derefType.isUnsizedArray() ? 0 : derefType.getArraySizes()->getDimSize(0); + blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), memberOffsets[i], blockIndex, + 0, dimSize, 0, terminalType->getQualifier().storage, false); + } + else { + blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), memberOffsets[i], blockIndex, + 0, 1, 0, terminalType->getQualifier().storage, false); + } + } else { + blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0, + topLevelArraySize, arrayStride, baseStorage, active); + } } } @@ -406,6 +460,7 @@ class TReflectionTraverser : public TLiveTraverser { if ((reflection.options & EShReflectionSeparateBuffers) && terminalType->isAtomic()) reflection.atomicCounterUniformIndices.push_back(uniformIndex); + variables.back().topLevelArraySize = topLevelArraySize; variables.back().topLevelArrayStride = topLevelArrayStride; if ((reflection.options & EShReflectionAllBlockVariables) && active) { @@ -537,65 +592,17 @@ class TReflectionTraverser : public TLiveTraverser { if (! anonymous) baseName = blockName; - if (base->getType().isArray()) { - TType derefType(base->getType(), 0); - - assert(! anonymous); - for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e) - blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType, - intermediate.getBlockSize(base->getType())); - baseName.append(TString("[0]")); - } else - blockIndex = addBlockName(blockName, base->getType(), intermediate.getBlockSize(base->getType())); + blockIndex = addBlockName(blockName, base->getType(), intermediate.getBlockSize(base->getType())); if (reflection.options & EShReflectionAllBlockVariables) { // Use a degenerate (empty) set of dereferences to immediately put as at the end of // the dereference change expected by blowUpActiveAggregate. TList derefs; - // because we don't have any derefs, the first thing blowUpActiveAggregate will do is iterate over each - // member in the struct definition. This will lose any information about whether the parent was a buffer - // block. So if we're using strict array rules which don't expand the first child of a buffer block we - // instead iterate over the children here. - const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix); - bool blockParent = (base->getType().getBasicType() == EbtBlock && base->getQualifier().storage == EvqBuffer); - - if (strictArraySuffix && blockParent) { - TType structDerefType(base->getType(), 0); - - const TType &structType = base->getType().isArray() ? structDerefType : base->getType(); - const TTypeList& typeList = *structType.getStruct(); - - TVector memberOffsets; - - memberOffsets.resize(typeList.size()); - getOffsets(structType, memberOffsets); - - for (int i = 0; i < (int)typeList.size(); ++i) { - TType derefType(structType, i); - TString name = baseName; - if (name.size() > 0) - name.append("."); - name.append(typeList[i].type->getFieldName()); - - // if this member is an array, store the top-level array stride but start the explosion from - // the inner struct type. - if (derefType.isArray() && derefType.isStruct()) { - name.append("[0]"); - blowUpActiveAggregate(TType(derefType, 0), name, derefs, derefs.end(), memberOffsets[i], - blockIndex, 0, getArrayStride(structType, derefType), - base->getQualifier().storage, false); - } else { - blowUpActiveAggregate(derefType, name, derefs, derefs.end(), memberOffsets[i], blockIndex, - 0, 0, base->getQualifier().storage, false); - } - } - } else { - // otherwise - if we're not using strict array suffix rules, or this isn't a block so we are - // expanding root arrays anyway, just start the iteration from the base block type. - blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.end(), 0, blockIndex, 0, 0, + // otherwise - if we're not using strict array suffix rules, or this isn't a block so we are + // expanding root arrays anyway, just start the iteration from the base block type. + blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.end(), 0, blockIndex, 0, -1, 0, base->getQualifier().storage, false); - } } } @@ -626,30 +633,43 @@ class TReflectionTraverser : public TLiveTraverser { else baseName = base->getName(); } - blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize, 0, + blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize, -1, 0, base->getQualifier().storage, true); } int addBlockName(const TString& name, const TType& type, int size) { - TReflection::TMapIndexToReflection& blocks = reflection.GetBlockMapForStorage(type.getQualifier().storage); + int blockIndex = 0; + if (type.isArray()) { + TType derefType(type, 0); + for (int e = 0; e < type.getOuterArraySize(); ++e) { + int memberBlockIndex = addBlockName(name + "[" + String(e) + "]", derefType, size); + if (e == 0) + blockIndex = memberBlockIndex; + } + } else { + TReflection::TMapIndexToReflection& blocks = reflection.GetBlockMapForStorage(type.getQualifier().storage); - int blockIndex; - TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str()); - if (reflection.nameToIndex.find(name.c_str()) == reflection.nameToIndex.end()) { - blockIndex = (int)blocks.size(); - reflection.nameToIndex[name.c_str()] = blockIndex; - blocks.push_back(TObjectReflection(name.c_str(), type, -1, -1, size, -1)); + TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str()); + if (reflection.nameToIndex.find(name.c_str()) == reflection.nameToIndex.end()) { + blockIndex = (int)blocks.size(); + reflection.nameToIndex[name.c_str()] = blockIndex; + blocks.push_back(TObjectReflection(name.c_str(), type, -1, -1, size, blockIndex)); - blocks.back().numMembers = countAggregateMembers(type); + blocks.back().numMembers = countAggregateMembers(type); - EShLanguageMask& stages = blocks.back().stages; - stages = static_cast(stages | 1 << intermediate.getStage()); - } else { - blockIndex = it->second; - - EShLanguageMask& stages = blocks[blockIndex].stages; - stages = static_cast(stages | 1 << intermediate.getStage()); + if (updateStageMasks) { + EShLanguageMask& stages = blocks.back().stages; + stages = static_cast(stages | 1 << intermediate.getStage()); + } + } + else { + blockIndex = it->second; + if (updateStageMasks) { + EShLanguageMask& stages = blocks[blockIndex].stages; + stages = static_cast(stages | 1 << intermediate.getStage()); + } + } } return blockIndex; @@ -887,8 +907,8 @@ class TReflectionTraverser : public TLiveTraverser { case EbtFloat16: return GL_FLOAT16_VEC2_NV + offset; case EbtInt: return GL_INT_VEC2 + offset; case EbtUint: return GL_UNSIGNED_INT_VEC2 + offset; - case EbtInt64: return GL_INT64_ARB + offset; - case EbtUint64: return GL_UNSIGNED_INT64_ARB + offset; + case EbtInt64: return GL_INT64_VEC2_ARB + offset; + case EbtUint64: return GL_UNSIGNED_INT64_VEC2_ARB + offset; case EbtBool: return GL_BOOL_VEC2 + offset; case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER + offset; default: return 0; @@ -995,8 +1015,10 @@ class TReflectionTraverser : public TLiveTraverser { return type.isArray() ? type.getOuterArraySize() : 1; } + const TIntermediate& intermediate; TReflection& reflection; std::set processedDerefs; + bool updateStageMasks; protected: TReflectionTraverser(TReflectionTraverser&); @@ -1029,7 +1051,21 @@ bool TReflectionTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node) // To reflect non-dereferenced objects. void TReflectionTraverser::visitSymbol(TIntermSymbol* base) { - if (base->getQualifier().storage == EvqUniform) + if (base->getQualifier().storage == EvqUniform) { + if (base->getBasicType() == EbtBlock) { + if (reflection.options & EShReflectionSharedStd140UBO) { + addUniform(*base); + } + } else { + addUniform(*base); + } + } + + // #TODO add std140/layout active rules for ssbo, same with ubo. + // Storage buffer blocks will be collected and expanding in this part. + if((reflection.options & EShReflectionSharedStd140SSBO) && + (base->getQualifier().storage == EvqBuffer && base->getBasicType() == EbtBlock && + (base->getQualifier().layoutPacking == ElpStd140 || base->getQualifier().layoutPacking == ElpShared))) addUniform(*base); if ((intermediate.getStage() == reflection.firstStage && base->getQualifier().isPipeInput()) || @@ -1102,6 +1138,8 @@ void TReflection::buildCounterIndices(const TIntermediate& intermediate) if (index >= 0) indexToUniformBlock[i].counterIndex = index; } +#else + (void)intermediate; #endif } @@ -1135,15 +1173,47 @@ bool TReflection::addStage(EShLanguage stage, const TIntermediate& intermediate) TReflectionTraverser it(intermediate, *this); - // put the entry point on the list of functions to process - it.pushFunction(intermediate.getEntryPointMangledName().c_str()); - - // process all the functions - while (! it.functions.empty()) { - TIntermNode* function = it.functions.back(); - it.functions.pop_back(); - function->traverse(&it); + for (auto& sequnence : intermediate.getTreeRoot()->getAsAggregate()->getSequence()) { + if (sequnence->getAsAggregate() != nullptr) { + if (sequnence->getAsAggregate()->getOp() == glslang::EOpLinkerObjects) { + it.updateStageMasks = false; + TIntermAggregate* linkerObjects = sequnence->getAsAggregate(); + for (auto& sequnence : linkerObjects->getSequence()) { + auto pNode = sequnence->getAsSymbolNode(); + if (pNode != nullptr) { + if ((pNode->getQualifier().storage == EvqUniform && + (options & EShReflectionSharedStd140UBO)) || + (pNode->getQualifier().storage == EvqBuffer && + (options & EShReflectionSharedStd140SSBO))) { + // collect std140 and shared uniform block form AST + if ((pNode->getBasicType() == EbtBlock) && + ((pNode->getQualifier().layoutPacking == ElpStd140) || + (pNode->getQualifier().layoutPacking == ElpShared))) { + pNode->traverse(&it); + } + } + else if ((options & EShReflectionAllIOVariables) && + (pNode->getQualifier().isPipeInput() || pNode->getQualifier().isPipeOutput())) + { + pNode->traverse(&it); + } + } + } + } else { + // This traverser will travers all function in AST. + // If we want reflect uncalled function, we need set linke message EShMsgKeepUncalled. + // When EShMsgKeepUncalled been set to true, all function will be keep in AST, even it is a uncalled function. + // This will keep some uniform variables in reflection, if those uniform variables is used in these uncalled function. + // + // If we just want reflect only live node, we can use a default link message or set EShMsgKeepUncalled false. + // When linke message not been set EShMsgKeepUncalled, linker won't keep uncalled function in AST. + // So, travers all function node can equivalent to travers live function. + it.updateStageMasks = true; + sequnence->getAsAggregate()->traverse(&it); + } + } } + it.updateStageMasks = true; buildCounterIndices(intermediate); buildUniformStageMask(intermediate); @@ -1188,7 +1258,7 @@ void TReflection::dump() for (int dim=0; dim<3; ++dim) if (getLocalSize(dim) > 1) - printf("Local size %s: %d\n", axis[dim], getLocalSize(dim)); + printf("Local size %s: %u\n", axis[dim], getLocalSize(dim)); printf("\n"); } @@ -1201,4 +1271,4 @@ void TReflection::dump() } // end namespace glslang -#endif // GLSLANG_WEB +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/libraries/glslang/glslang/MachineIndependent/reflection.h b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/reflection.h similarity index 98% rename from libraries/glslang/glslang/MachineIndependent/reflection.h rename to libraries/ZVulkan/src/glslang/glslang/MachineIndependent/reflection.h index efdc8934fbd..5af4467c1fb 100644 --- a/libraries/glslang/glslang/MachineIndependent/reflection.h +++ b/libraries/ZVulkan/src/glslang/glslang/MachineIndependent/reflection.h @@ -33,7 +33,7 @@ // POSSIBILITY OF SUCH DAMAGE. // -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) #ifndef _REFLECTION_INCLUDED #define _REFLECTION_INCLUDED @@ -220,4 +220,4 @@ class TReflection { #endif // _REFLECTION_INCLUDED -#endif // GLSLANG_WEB \ No newline at end of file +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/libraries/ZVulkan/src/glslang/glslang/OSDependent/Unix/CMakeLists.txt b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Unix/CMakeLists.txt new file mode 100644 index 00000000000..354a3e9772c --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Unix/CMakeLists.txt @@ -0,0 +1,59 @@ +# Copyright (C) 2020 The Khronos Group Inc. +# +# 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 The Khronos Group Inc. 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 HOLDERS 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. + +add_library(OSDependent STATIC ossource.cpp ../osinclude.h) +set_property(TARGET OSDependent PROPERTY FOLDER glslang) +set_property(TARGET OSDependent PROPERTY POSITION_INDEPENDENT_CODE ON) + +# Link pthread +set(CMAKE_THREAD_PREFER_PTHREAD ON) +if(${CMAKE_VERSION} VERSION_LESS "3.1.0" OR CMAKE_CROSSCOMPILING) + # Needed as long as we support CMake 2.8 for Ubuntu 14.04, + # which does not support the recommended Threads::Threads target. + # https://cmake.org/cmake/help/v2.8.12/cmake.html#module:FindThreads + # Also needed when cross-compiling to work around + # https://gitlab.kitware.com/cmake/cmake/issues/16920 + find_package(Threads) + target_link_libraries(OSDependent ${CMAKE_THREAD_LIBS_INIT}) +else() + # This is the recommended way, so we use it for 3.1+. + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads) + target_link_libraries(OSDependent Threads::Threads) +endif() + +if(ENABLE_GLSLANG_INSTALL) + install(TARGETS OSDependent EXPORT OSDependentTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(EXPORT OSDependentTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake) +endif(ENABLE_GLSLANG_INSTALL) diff --git a/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Unix/ossource.cpp similarity index 100% rename from libraries/glslang/glslang/OSDependent/Unix/ossource.cpp rename to libraries/ZVulkan/src/glslang/glslang/OSDependent/Unix/ossource.cpp diff --git a/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/CMakeLists.txt b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/CMakeLists.txt new file mode 100644 index 00000000000..0f60dbcc13e --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (C) 2020 The Khronos Group Inc. +# +# 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 The Khronos Group Inc. 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 HOLDERS 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(ENABLE_GLSLANG_JS) + add_executable(glslang.js "glslang.js.cpp") + glslang_set_link_args(glslang.js) + target_link_libraries(glslang.js glslang SPIRV) + + # Link library names that start with "-" are treated as link flags. + # "-Os" should be OK in MSVC; don't use /Os because CMake won't + # treat it as a link flag. + target_link_libraries(glslang.js "-Os") + + if(EMSCRIPTEN) + set_target_properties(glslang.js PROPERTIES + OUTPUT_NAME "glslang" + SUFFIX ".js") + em_link_pre_js(glslang.js "${CMAKE_CURRENT_SOURCE_DIR}/glslang.pre.js") + + target_link_libraries(glslang.js "--llvm-lto 1") + target_link_libraries(glslang.js "--closure 1") + target_link_libraries(glslang.js "-s MODULARIZE=1") + target_link_libraries(glslang.js "-s ALLOW_MEMORY_GROWTH=1") + target_link_libraries(glslang.js "-s FILESYSTEM=0") + + if(ENABLE_EMSCRIPTEN_SINGLE_FILE) + target_link_libraries(glslang.js "-s SINGLE_FILE=1") + endif(ENABLE_EMSCRIPTEN_SINGLE_FILE) + + if(ENABLE_EMSCRIPTEN_ENVIRONMENT_NODE) + target_link_libraries(glslang.js "-s ENVIRONMENT=node -s BINARYEN_ASYNC_COMPILATION=0") + else() + target_link_libraries(glslang.js "-s ENVIRONMENT=web,worker") + endif() + + if(NOT ENABLE_EMSCRIPTEN_ENVIRONMENT_NODE) + add_custom_command(TARGET glslang.js POST_BUILD + COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/glslang.after.js >> ${CMAKE_CURRENT_BINARY_DIR}/glslang.js) + endif() + endif(EMSCRIPTEN) +endif(ENABLE_GLSLANG_JS) diff --git a/libraries/glslang/glslang/OSDependent/Web/glslang.after.js b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/glslang.after.js similarity index 100% rename from libraries/glslang/glslang/OSDependent/Web/glslang.after.js rename to libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/glslang.after.js diff --git a/libraries/glslang/glslang/OSDependent/Web/glslang.js.cpp b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/glslang.js.cpp similarity index 91% rename from libraries/glslang/glslang/OSDependent/Web/glslang.js.cpp rename to libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/glslang.js.cpp index 6cb93fe27e6..f2306a60922 100644 --- a/libraries/glslang/glslang/OSDependent/Web/glslang.js.cpp +++ b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/glslang.js.cpp @@ -141,6 +141,7 @@ const TBuiltInResource DefaultTBuiltInResource = { /* .maxTaskWorkGroupSizeY_NV = */ 1, /* .maxTaskWorkGroupSizeZ_NV = */ 1, /* .maxMeshViewCountNV = */ 4, + /* .maxDualSourceDrawBuffersEXT = */ 1, /* .limits = */ { /* .nonInductiveForLoops = */ 1, @@ -176,7 +177,12 @@ extern "C" { * If null, the compilation failed. */ EMSCRIPTEN_KEEPALIVE -void* convert_glsl_to_spirv(const char* glsl, int stage_int, bool gen_debug, uint32_t** spirv, size_t* spirv_len) +void* convert_glsl_to_spirv(const char* glsl, + int stage_int, + bool gen_debug, + glslang::EShTargetLanguageVersion spirv_version, + uint32_t** spirv, + size_t* spirv_len) { if (glsl == nullptr) { fprintf(stderr, "Input pointer null\n"); @@ -194,6 +200,18 @@ void* convert_glsl_to_spirv(const char* glsl, int stage_int, bool gen_debug, uin return nullptr; } EShLanguage stage = static_cast(stage_int); + switch (spirv_version) { + case glslang::EShTargetSpv_1_0: + case glslang::EShTargetSpv_1_1: + case glslang::EShTargetSpv_1_2: + case glslang::EShTargetSpv_1_3: + case glslang::EShTargetSpv_1_4: + case glslang::EShTargetSpv_1_5: + break; + default: + fprintf(stderr, "Invalid SPIR-V version number\n"); + return nullptr; + } if (!initialized) { glslang::InitializeProcess(); @@ -203,8 +221,8 @@ void* convert_glsl_to_spirv(const char* glsl, int stage_int, bool gen_debug, uin glslang::TShader shader(stage); shader.setStrings(&glsl, 1); shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100); - shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1); - shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3); + shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); + shader.setEnvTarget(glslang::EShTargetSpv, spirv_version); if (!shader.parse(&DefaultTBuiltInResource, 100, true, EShMsgDefault)) { fprintf(stderr, "Parse failed\n"); fprintf(stderr, "%s\n", shader.getInfoLog()); @@ -260,7 +278,7 @@ void main() { })"; uint32_t* output; size_t output_len; - void* id = convert_glsl_to_spirv(input, 4, false, &output, &output_len); + void* id = convert_glsl_to_spirv(input, 4, false, glslang::EShTargetSpv_1_0, &output, &output_len); assert(output != nullptr); assert(output_len != 0); destroy_output_buffer(id); diff --git a/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/glslang.pre.js b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/glslang.pre.js new file mode 100644 index 00000000000..46a569506d7 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Web/glslang.pre.js @@ -0,0 +1,56 @@ +Module['compileGLSLZeroCopy'] = function(glsl, shader_stage, gen_debug, spirv_version) { + gen_debug = !!gen_debug; + + var shader_stage_int; // EShLanguage + switch (shader_stage) { + case 'vertex': shader_stage_int = 0; break; + case 'fragment': shader_stage_int = 4; break; + case 'compute': shader_stage_int = 5; break; + default: + throw new Error("shader_stage must be 'vertex', 'fragment', or 'compute'."); + } + + spirv_version = spirv_version || '1.0'; + var spirv_version_int; // EShTargetLanguageVersion + switch (spirv_version) { + case '1.0': spirv_version_int = (1 << 16) | (0 << 8); break; + case '1.1': spirv_version_int = (1 << 16) | (1 << 8); break; + case '1.2': spirv_version_int = (1 << 16) | (2 << 8); break; + case '1.3': spirv_version_int = (1 << 16) | (3 << 8); break; + case '1.4': spirv_version_int = (1 << 16) | (4 << 8); break; + case '1.5': spirv_version_int = (1 << 16) | (5 << 8); break; + default: + throw new Error("spirv_version must be '1.0' ~ '1.5'."); + } + + var p_output = Module['_malloc'](4); + var p_output_len = Module['_malloc'](4); + var id = ccall('convert_glsl_to_spirv', + 'number', + ['string', 'number', 'boolean', 'number', 'number', 'number'], + [glsl, shader_stage_int, gen_debug, spirv_version_int, p_output, p_output_len]); + var output = getValue(p_output, 'i32'); + var output_len = getValue(p_output_len, 'i32'); + Module['_free'](p_output); + Module['_free'](p_output_len); + + if (id === 0) { + throw new Error('GLSL compilation failed'); + } + + var ret = {}; + var outputIndexU32 = output / 4; + ret['data'] = Module['HEAPU32'].subarray(outputIndexU32, outputIndexU32 + output_len); + ret['free'] = function() { + Module['_destroy_output_buffer'](id); + }; + + return ret; +}; + +Module['compileGLSL'] = function(glsl, shader_stage, gen_debug, spirv_version) { + var compiled = Module['compileGLSLZeroCopy'](glsl, shader_stage, gen_debug, spirv_version); + var ret = compiled['data'].slice() + compiled['free'](); + return ret; +}; diff --git a/libraries/ZVulkan/src/glslang/glslang/OSDependent/Windows/CMakeLists.txt b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Windows/CMakeLists.txt new file mode 100644 index 00000000000..9cf1b7fba38 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Windows/CMakeLists.txt @@ -0,0 +1,54 @@ +# Copyright (C) 2020 The Khronos Group Inc. +# +# 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 The Khronos Group Inc. 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 HOLDERS 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. + +set(SOURCES ossource.cpp ../osinclude.h) + +add_library(OSDependent STATIC ${SOURCES}) +set_property(TARGET OSDependent PROPERTY FOLDER glslang) +set_property(TARGET OSDependent PROPERTY POSITION_INDEPENDENT_CODE ON) + +# MinGW GCC complains about function pointer casts to void*. +# Turn that off with -fpermissive. +if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") + target_compile_options(OSDependent PRIVATE -fpermissive) +endif() + +if(WIN32) + source_group("Source" FILES ${SOURCES}) +endif(WIN32) + +if(ENABLE_GLSLANG_INSTALL) + install(TARGETS OSDependent EXPORT OSDependentTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(EXPORT OSDependentTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake) +endif(ENABLE_GLSLANG_INSTALL) diff --git a/libraries/glslang/glslang/OSDependent/Windows/main.cpp b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Windows/main.cpp similarity index 100% rename from libraries/glslang/glslang/OSDependent/Windows/main.cpp rename to libraries/ZVulkan/src/glslang/glslang/OSDependent/Windows/main.cpp diff --git a/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp b/libraries/ZVulkan/src/glslang/glslang/OSDependent/Windows/ossource.cpp similarity index 100% rename from libraries/glslang/glslang/OSDependent/Windows/ossource.cpp rename to libraries/ZVulkan/src/glslang/glslang/OSDependent/Windows/ossource.cpp diff --git a/libraries/glslang/glslang/OSDependent/osinclude.h b/libraries/ZVulkan/src/glslang/glslang/OSDependent/osinclude.h similarity index 100% rename from libraries/glslang/glslang/OSDependent/osinclude.h rename to libraries/ZVulkan/src/glslang/glslang/OSDependent/osinclude.h diff --git a/libraries/ZVulkan/src/glslang/glslang/Public/ShaderLang.h b/libraries/ZVulkan/src/glslang/glslang/Public/ShaderLang.h new file mode 100644 index 00000000000..d2a4bf40a05 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/Public/ShaderLang.h @@ -0,0 +1,970 @@ +// +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013-2016 LunarG, Inc. +// Copyright (C) 2015-2018 Google, Inc. +// +// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. +// +#ifndef _COMPILER_INTERFACE_INCLUDED_ +#define _COMPILER_INTERFACE_INCLUDED_ + +#include "../Include/ResourceLimits.h" +#include "../MachineIndependent/Versions.h" + +#include +#include + +#ifdef _WIN32 + #define C_DECL __cdecl +#else + #define C_DECL +#endif + +#ifdef GLSLANG_IS_SHARED_LIBRARY + #ifdef _WIN32 + #ifdef GLSLANG_EXPORTING + #define GLSLANG_EXPORT __declspec(dllexport) + #else + #define GLSLANG_EXPORT __declspec(dllimport) + #endif + #elif __GNUC__ >= 4 + #define GLSLANG_EXPORT __attribute__((visibility("default"))) + #endif +#endif // GLSLANG_IS_SHARED_LIBRARY + +#ifndef GLSLANG_EXPORT +#define GLSLANG_EXPORT +#endif + +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler/linker. +// + +#ifdef __cplusplus + extern "C" { +#endif + +// +// Call before doing any other compiler/linker operations. +// +// (Call once per process, not once per thread.) +// +GLSLANG_EXPORT int ShInitialize(); + +// +// Call this at process shutdown to clean up memory. +// +GLSLANG_EXPORT int ShFinalize(); + +// +// Types of languages the compiler can consume. +// +typedef enum { + EShLangVertex, + EShLangTessControl, + EShLangTessEvaluation, + EShLangGeometry, + EShLangFragment, + EShLangCompute, + EShLangRayGen, + EShLangRayGenNV = EShLangRayGen, + EShLangIntersect, + EShLangIntersectNV = EShLangIntersect, + EShLangAnyHit, + EShLangAnyHitNV = EShLangAnyHit, + EShLangClosestHit, + EShLangClosestHitNV = EShLangClosestHit, + EShLangMiss, + EShLangMissNV = EShLangMiss, + EShLangCallable, + EShLangCallableNV = EShLangCallable, + EShLangTaskNV, + EShLangMeshNV, + LAST_ELEMENT_MARKER(EShLangCount), +} EShLanguage; // would be better as stage, but this is ancient now + +typedef enum : unsigned { + EShLangVertexMask = (1 << EShLangVertex), + EShLangTessControlMask = (1 << EShLangTessControl), + EShLangTessEvaluationMask = (1 << EShLangTessEvaluation), + EShLangGeometryMask = (1 << EShLangGeometry), + EShLangFragmentMask = (1 << EShLangFragment), + EShLangComputeMask = (1 << EShLangCompute), + EShLangRayGenMask = (1 << EShLangRayGen), + EShLangRayGenNVMask = EShLangRayGenMask, + EShLangIntersectMask = (1 << EShLangIntersect), + EShLangIntersectNVMask = EShLangIntersectMask, + EShLangAnyHitMask = (1 << EShLangAnyHit), + EShLangAnyHitNVMask = EShLangAnyHitMask, + EShLangClosestHitMask = (1 << EShLangClosestHit), + EShLangClosestHitNVMask = EShLangClosestHitMask, + EShLangMissMask = (1 << EShLangMiss), + EShLangMissNVMask = EShLangMissMask, + EShLangCallableMask = (1 << EShLangCallable), + EShLangCallableNVMask = EShLangCallableMask, + EShLangTaskNVMask = (1 << EShLangTaskNV), + EShLangMeshNVMask = (1 << EShLangMeshNV), + LAST_ELEMENT_MARKER(EShLanguageMaskCount), +} EShLanguageMask; + +namespace glslang { + +class TType; + +typedef enum { + EShSourceNone, + EShSourceGlsl, // GLSL, includes ESSL (OpenGL ES GLSL) + EShSourceHlsl, // HLSL + LAST_ELEMENT_MARKER(EShSourceCount), +} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead + +typedef enum { + EShClientNone, // use when there is no client, e.g. for validation + EShClientVulkan, + EShClientOpenGL, + LAST_ELEMENT_MARKER(EShClientCount), +} EShClient; + +typedef enum { + EShTargetNone, + EShTargetSpv, // SPIR-V (preferred spelling) + EshTargetSpv = EShTargetSpv, // legacy spelling + LAST_ELEMENT_MARKER(EShTargetCount), +} EShTargetLanguage; + +typedef enum { + EShTargetVulkan_1_0 = (1 << 22), // Vulkan 1.0 + EShTargetVulkan_1_1 = (1 << 22) | (1 << 12), // Vulkan 1.1 + EShTargetVulkan_1_2 = (1 << 22) | (2 << 12), // Vulkan 1.2 + EShTargetOpenGL_450 = 450, // OpenGL + LAST_ELEMENT_MARKER(EShTargetClientVersionCount = 4), +} EShTargetClientVersion; + +typedef EShTargetClientVersion EshTargetClientVersion; + +typedef enum { + EShTargetSpv_1_0 = (1 << 16), // SPIR-V 1.0 + EShTargetSpv_1_1 = (1 << 16) | (1 << 8), // SPIR-V 1.1 + EShTargetSpv_1_2 = (1 << 16) | (2 << 8), // SPIR-V 1.2 + EShTargetSpv_1_3 = (1 << 16) | (3 << 8), // SPIR-V 1.3 + EShTargetSpv_1_4 = (1 << 16) | (4 << 8), // SPIR-V 1.4 + EShTargetSpv_1_5 = (1 << 16) | (5 << 8), // SPIR-V 1.5 + LAST_ELEMENT_MARKER(EShTargetLanguageVersionCount = 6), +} EShTargetLanguageVersion; + +struct TInputLanguage { + EShSource languageFamily; // redundant information with other input, this one overrides when not EShSourceNone + EShLanguage stage; // redundant information with other input, this one overrides when not EShSourceNone + EShClient dialect; + int dialectVersion; // version of client's language definition, not the client (when not EShClientNone) + bool vulkanRulesRelaxed; +}; + +struct TClient { + EShClient client; + EShTargetClientVersion version; // version of client itself (not the client's input dialect) +}; + +struct TTarget { + EShTargetLanguage language; + EShTargetLanguageVersion version; // version to target, if SPIR-V, defined by "word 1" of the SPIR-V header + bool hlslFunctionality1; // can target hlsl_functionality1 extension(s) +}; + +// All source/client/target versions and settings. +// Can override previous methods of setting, when items are set here. +// Expected to grow, as more are added, rather than growing parameter lists. +struct TEnvironment { + TInputLanguage input; // definition of the input language + TClient client; // what client is the overall compilation being done for? + TTarget target; // what to generate +}; + +GLSLANG_EXPORT const char* StageName(EShLanguage); + +} // end namespace glslang + +// +// Types of output the linker will create. +// +typedef enum { + EShExVertexFragment, + EShExFragment +} EShExecutable; + +// +// Optimization level for the compiler. +// +typedef enum { + EShOptNoGeneration, + EShOptNone, + EShOptSimple, // Optimizations that can be done quickly + EShOptFull, // Optimizations that will take more time + LAST_ELEMENT_MARKER(EshOptLevelCount), +} EShOptimizationLevel; + +// +// Texture and Sampler transformation mode. +// +typedef enum { + EShTexSampTransKeep, // keep textures and samplers as is (default) + EShTexSampTransUpgradeTextureRemoveSampler, // change texture w/o embeded sampler into sampled texture and throw away all samplers + LAST_ELEMENT_MARKER(EShTexSampTransCount), +} EShTextureSamplerTransformMode; + +// +// Message choices for what errors and warnings are given. +// +enum EShMessages : unsigned { + EShMsgDefault = 0, // default is to give all required errors and extra warnings + EShMsgRelaxedErrors = (1 << 0), // be liberal in accepting input + EShMsgSuppressWarnings = (1 << 1), // suppress all warnings, except those required by the specification + EShMsgAST = (1 << 2), // print the AST intermediate representation + EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation + EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V + EShMsgOnlyPreprocessor = (1 << 5), // only print out errors produced by the preprocessor + EShMsgReadHlsl = (1 << 6), // use HLSL parsing rules and semantics + EShMsgCascadingErrors = (1 << 7), // get cascading errors; risks error-recovery issues, instead of an early exit + EShMsgKeepUncalled = (1 << 8), // for testing, don't eliminate uncalled functions + EShMsgHlslOffsets = (1 << 9), // allow block offsets to follow HLSL rules instead of GLSL rules + EShMsgDebugInfo = (1 << 10), // save debug information + EShMsgHlslEnable16BitTypes = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL + EShMsgHlslLegalization = (1 << 12), // enable HLSL Legalization messages + EShMsgHlslDX9Compatible = (1 << 13), // enable HLSL DX9 compatible mode (for samplers and semantics) + EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table + LAST_ELEMENT_MARKER(EShMsgCount), +}; + +// +// Options for building reflection +// +typedef enum { + EShReflectionDefault = 0, // default is original behaviour before options were added + EShReflectionStrictArraySuffix = (1 << 0), // reflection will follow stricter rules for array-of-structs suffixes + EShReflectionBasicArraySuffix = (1 << 1), // arrays of basic types will be appended with [0] as in GL reflection + EShReflectionIntermediateIO = (1 << 2), // reflect inputs and outputs to program, even with no vertex shader + EShReflectionSeparateBuffers = (1 << 3), // buffer variables and buffer blocks are reflected separately + EShReflectionAllBlockVariables = (1 << 4), // reflect all variables in blocks, even if they are inactive + EShReflectionUnwrapIOBlocks = (1 << 5), // unwrap input/output blocks the same as with uniform blocks + EShReflectionAllIOVariables = (1 << 6), // reflect all input/output variables, even if they are inactive + EShReflectionSharedStd140SSBO = (1 << 7), // Apply std140/shared rules for ubo to ssbo + EShReflectionSharedStd140UBO = (1 << 8), // Apply std140/shared rules for ubo to ssbo + LAST_ELEMENT_MARKER(EShReflectionCount), +} EShReflectionOptions; + +// +// Build a table for bindings. This can be used for locating +// attributes, uniforms, globals, etc., as needed. +// +typedef struct { + const char* name; + int binding; +} ShBinding; + +typedef struct { + int numBindings; + ShBinding* bindings; // array of bindings +} ShBindingTable; + +// +// ShHandle held by but opaque to the driver. It is allocated, +// managed, and de-allocated by the compiler/linker. It's contents +// are defined by and used by the compiler and linker. For example, +// symbol table information and object code passed from the compiler +// to the linker can be stored where ShHandle points. +// +// If handle creation fails, 0 will be returned. +// +typedef void* ShHandle; + +// +// Driver calls these to create and destroy compiler/linker +// objects. +// +GLSLANG_EXPORT ShHandle ShConstructCompiler(const EShLanguage, int debugOptions); // one per shader +GLSLANG_EXPORT ShHandle ShConstructLinker(const EShExecutable, int debugOptions); // one per shader pair +GLSLANG_EXPORT ShHandle ShConstructUniformMap(); // one per uniform namespace (currently entire program object) +GLSLANG_EXPORT void ShDestruct(ShHandle); + +// +// The return value of ShCompile is boolean, non-zero indicating +// success. +// +// The info-log should be written by ShCompile into +// ShHandle, so it can answer future queries. +// +GLSLANG_EXPORT int ShCompile( + const ShHandle, + const char* const shaderStrings[], + const int numStrings, + const int* lengths, + const EShOptimizationLevel, + const TBuiltInResource *resources, + int debugOptions, + int defaultVersion = 110, // use 100 for ES environment, overridden by #version in shader + bool forwardCompatible = false, // give errors for use of deprecated features + EShMessages messages = EShMsgDefault // warnings and errors + ); + +GLSLANG_EXPORT int ShLinkExt( + const ShHandle, // linker object + const ShHandle h[], // compiler objects to link together + const int numHandles); + +// +// ShSetEncrpytionMethod is a place-holder for specifying +// how source code is encrypted. +// +GLSLANG_EXPORT void ShSetEncryptionMethod(ShHandle); + +// +// All the following return 0 if the information is not +// available in the object passed down, or the object is bad. +// +GLSLANG_EXPORT const char* ShGetInfoLog(const ShHandle); +GLSLANG_EXPORT const void* ShGetExecutable(const ShHandle); +GLSLANG_EXPORT int ShSetVirtualAttributeBindings(const ShHandle, const ShBindingTable*); // to detect user aliasing +GLSLANG_EXPORT int ShSetFixedAttributeBindings(const ShHandle, const ShBindingTable*); // to force any physical mappings +// +// Tell the linker to never assign a vertex attribute to this list of physical attributes +// +GLSLANG_EXPORT int ShExcludeAttributes(const ShHandle, int *attributes, int count); + +// +// Returns the location ID of the named uniform. +// Returns -1 if error. +// +GLSLANG_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char* name); + +#ifdef __cplusplus + } // end extern "C" +#endif + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// Deferred-Lowering C++ Interface +// ----------------------------------- +// +// Below is a new alternate C++ interface, which deprecates the above +// opaque handle-based interface. +// +// The below is further designed to handle multiple compilation units per stage, where +// the intermediate results, including the parse tree, are preserved until link time, +// rather than the above interface which is designed to have each compilation unit +// lowered at compile time. In the above model, linking occurs on the lowered results, +// whereas in this model intra-stage linking can occur at the parse tree +// (treeRoot in TIntermediate) level, and then a full stage can be lowered. +// + +#include +#include +#include + +class TCompiler; +class TInfoSink; + +namespace glslang { + +struct Version { + int major; + int minor; + int patch; + const char* flavor; +}; + +GLSLANG_EXPORT Version GetVersion(); +GLSLANG_EXPORT const char* GetEsslVersionString(); +GLSLANG_EXPORT const char* GetGlslVersionString(); +GLSLANG_EXPORT int GetKhronosToolId(); + +class TIntermediate; +class TProgram; +class TPoolAllocator; + +// Call this exactly once per process before using anything else +GLSLANG_EXPORT bool InitializeProcess(); + +// Call once per process to tear down everything +GLSLANG_EXPORT void FinalizeProcess(); + +// Resource type for IO resolver +enum TResourceType { + EResSampler, + EResTexture, + EResImage, + EResUbo, + EResSsbo, + EResUav, + EResCount +}; + +enum TBlockStorageClass +{ + EbsUniform = 0, + EbsStorageBuffer, + EbsPushConstant, + EbsNone, // not a uniform or buffer variable + EbsCount, +}; + +// Make one TShader per shader that you will link into a program. Then +// - provide the shader through setStrings() or setStringsWithLengths() +// - optionally call setEnv*(), see below for more detail +// - optionally use setPreamble() to set a special shader string that will be +// processed before all others but won't affect the validity of #version +// - optionally call addProcesses() for each setting/transform, +// see comment for class TProcesses +// - call parse(): source language and target environment must be selected +// either by correct setting of EShMessages sent to parse(), or by +// explicitly calling setEnv*() +// - query the info logs +// +// N.B.: Does not yet support having the same TShader instance being linked into +// multiple programs. +// +// N.B.: Destruct a linked program *before* destructing the shaders linked into it. +// +class TShader { +public: + GLSLANG_EXPORT explicit TShader(EShLanguage); + GLSLANG_EXPORT virtual ~TShader(); + GLSLANG_EXPORT void setStrings(const char* const* s, int n); + GLSLANG_EXPORT void setStringsWithLengths( + const char* const* s, const int* l, int n); + GLSLANG_EXPORT void setStringsWithLengthsAndNames( + const char* const* s, const int* l, const char* const* names, int n); + void setPreamble(const char* s) { preamble = s; } + GLSLANG_EXPORT void setEntryPoint(const char* entryPoint); + GLSLANG_EXPORT void setSourceEntryPoint(const char* sourceEntryPointName); + GLSLANG_EXPORT void addProcesses(const std::vector&); + GLSLANG_EXPORT void setUniqueId(unsigned long long id); + + // IO resolver binding data: see comments in ShaderLang.cpp + GLSLANG_EXPORT void setShiftBinding(TResourceType res, unsigned int base); + GLSLANG_EXPORT void setShiftSamplerBinding(unsigned int base); // DEPRECATED: use setShiftBinding + GLSLANG_EXPORT void setShiftTextureBinding(unsigned int base); // DEPRECATED: use setShiftBinding + GLSLANG_EXPORT void setShiftImageBinding(unsigned int base); // DEPRECATED: use setShiftBinding + GLSLANG_EXPORT void setShiftUboBinding(unsigned int base); // DEPRECATED: use setShiftBinding + GLSLANG_EXPORT void setShiftUavBinding(unsigned int base); // DEPRECATED: use setShiftBinding + GLSLANG_EXPORT void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding + GLSLANG_EXPORT void setShiftSsboBinding(unsigned int base); // DEPRECATED: use setShiftBinding + GLSLANG_EXPORT void setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set); + GLSLANG_EXPORT void setResourceSetBinding(const std::vector& base); + GLSLANG_EXPORT void setAutoMapBindings(bool map); + GLSLANG_EXPORT void setAutoMapLocations(bool map); + GLSLANG_EXPORT void addUniformLocationOverride(const char* name, int loc); + GLSLANG_EXPORT void setUniformLocationBase(int base); + GLSLANG_EXPORT void setInvertY(bool invert); +#ifdef ENABLE_HLSL + GLSLANG_EXPORT void setHlslIoMapping(bool hlslIoMap); + GLSLANG_EXPORT void setFlattenUniformArrays(bool flatten); +#endif + GLSLANG_EXPORT void setNoStorageFormat(bool useUnknownFormat); + GLSLANG_EXPORT void setNanMinMaxClamp(bool nanMinMaxClamp); + GLSLANG_EXPORT void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode); + GLSLANG_EXPORT void addBlockStorageOverride(const char* nameStr, glslang::TBlockStorageClass backing); + + GLSLANG_EXPORT void setGlobalUniformBlockName(const char* name); + GLSLANG_EXPORT void setAtomicCounterBlockName(const char* name); + GLSLANG_EXPORT void setGlobalUniformSet(unsigned int set); + GLSLANG_EXPORT void setGlobalUniformBinding(unsigned int binding); + GLSLANG_EXPORT void setAtomicCounterBlockSet(unsigned int set); + GLSLANG_EXPORT void setAtomicCounterBlockBinding(unsigned int binding); + + // For setting up the environment (cleared to nothingness in the constructor). + // These must be called so that parsing is done for the right source language and + // target environment, either indirectly through TranslateEnvironment() based on + // EShMessages et. al., or directly by the user. + // + // setEnvInput: The input source language and stage. If generating code for a + // specific client, the input client semantics to use and the + // version of that client's input semantics to use, otherwise + // use EShClientNone and version of 0, e.g. for validation mode. + // Note 'version' does not describe the target environment, + // just the version of the source dialect to compile under. + // + // See the definitions of TEnvironment, EShSource, EShLanguage, + // and EShClient for choices and more detail. + // + // setEnvClient: The client that will be hosting the execution, and it's version. + // Note 'version' is not the version of the languages involved, but + // the version of the client environment. + // Use EShClientNone and version of 0 if there is no client, e.g. + // for validation mode. + // + // See EShTargetClientVersion for choices. + // + // setEnvTarget: The language to translate to when generating code, and that + // language's version. + // Use EShTargetNone and version of 0 if there is no client, e.g. + // for validation mode. + // + void setEnvInput(EShSource lang, EShLanguage envStage, EShClient client, int version) + { + environment.input.languageFamily = lang; + environment.input.stage = envStage; + environment.input.dialect = client; + environment.input.dialectVersion = version; + } + void setEnvClient(EShClient client, EShTargetClientVersion version) + { + environment.client.client = client; + environment.client.version = version; + } + void setEnvTarget(EShTargetLanguage lang, EShTargetLanguageVersion version) + { + environment.target.language = lang; + environment.target.version = version; + } + + void getStrings(const char* const* &s, int& n) { s = strings; n = numStrings; } + +#ifdef ENABLE_HLSL + void setEnvTargetHlslFunctionality1() { environment.target.hlslFunctionality1 = true; } + bool getEnvTargetHlslFunctionality1() const { return environment.target.hlslFunctionality1; } +#else + bool getEnvTargetHlslFunctionality1() const { return false; } +#endif + + void setEnvInputVulkanRulesRelaxed() { environment.input.vulkanRulesRelaxed = true; } + bool getEnvInputVulkanRulesRelaxed() const { return environment.input.vulkanRulesRelaxed; } + + // Interface to #include handlers. + // + // To support #include, a client of Glslang does the following: + // 1. Call setStringsWithNames to set the source strings and associated + // names. For example, the names could be the names of the files + // containing the shader sources. + // 2. Call parse with an Includer. + // + // When the Glslang parser encounters an #include directive, it calls + // the Includer's include method with the requested include name + // together with the current string name. The returned IncludeResult + // contains the fully resolved name of the included source, together + // with the source text that should replace the #include directive + // in the source stream. After parsing that source, Glslang will + // release the IncludeResult object. + class Includer { + public: + // An IncludeResult contains the resolved name and content of a source + // inclusion. + struct IncludeResult { + IncludeResult(const std::string& headerName, const char* const headerData, const size_t headerLength, void* userData) : + headerName(headerName), headerData(headerData), headerLength(headerLength), userData(userData) { } + // For a successful inclusion, the fully resolved name of the requested + // include. For example, in a file system-based includer, full resolution + // should convert a relative path name into an absolute path name. + // For a failed inclusion, this is an empty string. + const std::string headerName; + // The content and byte length of the requested inclusion. The + // Includer producing this IncludeResult retains ownership of the + // storage. + // For a failed inclusion, the header + // field points to a string containing error details. + const char* const headerData; + const size_t headerLength; + // Include resolver's context. + void* userData; + protected: + IncludeResult& operator=(const IncludeResult&); + IncludeResult(); + }; + + // For both include methods below: + // + // Resolves an inclusion request by name, current source name, + // and include depth. + // On success, returns an IncludeResult containing the resolved name + // and content of the include. + // On failure, returns a nullptr, or an IncludeResult + // with an empty string for the headerName and error details in the + // header field. + // The Includer retains ownership of the contents + // of the returned IncludeResult value, and those contents must + // remain valid until the releaseInclude method is called on that + // IncludeResult object. + // + // Note "local" vs. "system" is not an "either/or": "local" is an + // extra thing to do over "system". Both might get called, as per + // the C++ specification. + + // For the "system" or <>-style includes; search the "system" paths. + virtual IncludeResult* includeSystem(const char* /*headerName*/, + const char* /*includerName*/, + size_t /*inclusionDepth*/) { return nullptr; } + + // For the "local"-only aspect of a "" include. Should not search in the + // "system" paths, because on returning a failure, the parser will + // call includeSystem() to look in the "system" locations. + virtual IncludeResult* includeLocal(const char* /*headerName*/, + const char* /*includerName*/, + size_t /*inclusionDepth*/) { return nullptr; } + + // Signals that the parser will no longer use the contents of the + // specified IncludeResult. + virtual void releaseInclude(IncludeResult*) = 0; + virtual ~Includer() {} + }; + + // Fail all Includer searches + class ForbidIncluder : public Includer { + public: + virtual void releaseInclude(IncludeResult*) override { } + }; + + GLSLANG_EXPORT bool parse( + const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, + bool forceDefaultVersionAndProfile, bool forwardCompatible, + EShMessages, Includer&); + + bool parse(const TBuiltInResource* res, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, + bool forwardCompatible, EShMessages messages) + { + TShader::ForbidIncluder includer; + return parse(res, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, includer); + } + + // Equivalent to parse() without a default profile and without forcing defaults. + bool parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages) + { + return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages); + } + + bool parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages, + Includer& includer) + { + return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages, includer); + } + + // NOTE: Doing just preprocessing to obtain a correct preprocessed shader string + // is not an officially supported or fully working path. + GLSLANG_EXPORT bool preprocess( + const TBuiltInResource* builtInResources, int defaultVersion, + EProfile defaultProfile, bool forceDefaultVersionAndProfile, + bool forwardCompatible, EShMessages message, std::string* outputString, + Includer& includer); + + GLSLANG_EXPORT const char* getInfoLog(); + GLSLANG_EXPORT const char* getInfoDebugLog(); + EShLanguage getStage() const { return stage; } + TIntermediate* getIntermediate() const { return intermediate; } + +protected: + TPoolAllocator* pool; + EShLanguage stage; + TCompiler* compiler; + TIntermediate* intermediate; + TInfoSink* infoSink; + // strings and lengths follow the standard for glShaderSource: + // strings is an array of numStrings pointers to string data. + // lengths can be null, but if not it is an array of numStrings + // integers containing the length of the associated strings. + // if lengths is null or lengths[n] < 0 the associated strings[n] is + // assumed to be null-terminated. + // stringNames is the optional names for all the strings. If stringNames + // is null, then none of the strings has name. If a certain element in + // stringNames is null, then the corresponding string does not have name. + const char* const* strings; // explicit code to compile, see previous comment + const int* lengths; + const char* const* stringNames; + int numStrings; // size of the above arrays + const char* preamble; // string of implicit code to compile before the explicitly provided code + + // a function in the source string can be renamed FROM this TO the name given in setEntryPoint. + std::string sourceEntryPointName; + + TEnvironment environment; + + friend class TProgram; + +private: + TShader& operator=(TShader&); +}; + +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + +// +// A reflection database and its interface, consistent with the OpenGL API reflection queries. +// + +// Data needed for just a single object at the granularity exchanged by the reflection API +class TObjectReflection { +public: + GLSLANG_EXPORT TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex); + + const TType* getType() const { return type; } + GLSLANG_EXPORT int getBinding() const; + GLSLANG_EXPORT void dump() const; + static TObjectReflection badReflection() { return TObjectReflection(); } + + std::string name; + int offset; + int glDefineType; + int size; // data size in bytes for a block, array size for a (non-block) object that's an array + int index; + int counterIndex; + int numMembers; + int arrayStride; // stride of an array variable + int topLevelArraySize; // size of the top-level variable in a storage buffer member + int topLevelArrayStride; // stride of the top-level variable in a storage buffer member + EShLanguageMask stages; + +protected: + TObjectReflection() + : offset(-1), glDefineType(-1), size(-1), index(-1), counterIndex(-1), numMembers(-1), arrayStride(0), + topLevelArrayStride(0), stages(EShLanguageMask(0)), type(nullptr) + { + } + + const TType* type; +}; + +class TReflection; +class TIoMapper; +struct TVarEntryInfo; + +// Allows to customize the binding layout after linking. +// All used uniform variables will invoke at least validateBinding. +// If validateBinding returned true then the other resolveBinding, +// resolveSet, and resolveLocation are invoked to resolve the binding +// and descriptor set index respectively. +// +// Invocations happen in a particular order: +// 1) all shader inputs +// 2) all shader outputs +// 3) all uniforms with binding and set already defined +// 4) all uniforms with binding but no set defined +// 5) all uniforms with set but no binding defined +// 6) all uniforms with no binding and no set defined +// +// mapIO will use this resolver in two phases. The first +// phase is a notification phase, calling the corresponging +// notifiy callbacks, this phase ends with a call to endNotifications. +// Phase two starts directly after the call to endNotifications +// and calls all other callbacks to validate and to get the +// bindings, sets, locations, component and color indices. +// +// NOTE: that still limit checks are applied to bindings and sets +// and may result in an error. +class TIoMapResolver +{ +public: + virtual ~TIoMapResolver() {} + + // Should return true if the resulting/current binding would be okay. + // Basic idea is to do aliasing binding checks with this. + virtual bool validateBinding(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Should return a value >= 0 if the current binding should be overridden. + // Return -1 if the current binding (including no binding) should be kept. + virtual int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Should return a value >= 0 if the current set should be overridden. + // Return -1 if the current set (including no set) should be kept. + virtual int resolveSet(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Should return a value >= 0 if the current location should be overridden. + // Return -1 if the current location (including no location) should be kept. + virtual int resolveUniformLocation(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Should return true if the resulting/current setup would be okay. + // Basic idea is to do aliasing checks and reject invalid semantic names. + virtual bool validateInOut(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Should return a value >= 0 if the current location should be overridden. + // Return -1 if the current location (including no location) should be kept. + virtual int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Should return a value >= 0 if the current component index should be overridden. + // Return -1 if the current component index (including no index) should be kept. + virtual int resolveInOutComponent(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Should return a value >= 0 if the current color index should be overridden. + // Return -1 if the current color index (including no index) should be kept. + virtual int resolveInOutIndex(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Notification of a uniform variable + virtual void notifyBinding(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Notification of a in or out variable + virtual void notifyInOut(EShLanguage stage, TVarEntryInfo& ent) = 0; + // Called by mapIO when it starts its notify pass for the given stage + virtual void beginNotifications(EShLanguage stage) = 0; + // Called by mapIO when it has finished the notify pass + virtual void endNotifications(EShLanguage stage) = 0; + // Called by mipIO when it starts its resolve pass for the given stage + virtual void beginResolve(EShLanguage stage) = 0; + // Called by mapIO when it has finished the resolve pass + virtual void endResolve(EShLanguage stage) = 0; + // Called by mapIO when it starts its symbol collect for teh given stage + virtual void beginCollect(EShLanguage stage) = 0; + // Called by mapIO when it has finished the symbol collect + virtual void endCollect(EShLanguage stage) = 0; + // Called by TSlotCollector to resolve storage locations or bindings + virtual void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) = 0; + // Called by TSlotCollector to resolve resource locations or bindings + virtual void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) = 0; + // Called by mapIO.addStage to set shader stage mask to mark a stage be added to this pipeline + virtual void addStage(EShLanguage stage, TIntermediate& stageIntermediate) = 0; +}; + +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE + +// Make one TProgram per set of shaders that will get linked together. Add all +// the shaders that are to be linked together. After calling shader.parse() +// for all shaders, call link(). +// +// N.B.: Destruct a linked program *before* destructing the shaders linked into it. +// +class TProgram { +public: + GLSLANG_EXPORT TProgram(); + GLSLANG_EXPORT virtual ~TProgram(); + void addShader(TShader* shader) { stages[shader->stage].push_back(shader); } + std::list& getShaders(EShLanguage stage) { return stages[stage]; } + // Link Validation interface + GLSLANG_EXPORT bool link(EShMessages); + GLSLANG_EXPORT const char* getInfoLog(); + GLSLANG_EXPORT const char* getInfoDebugLog(); + + TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; } + +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + + // Reflection Interface + + // call first, to do liveness analysis, index mapping, etc.; returns false on failure + GLSLANG_EXPORT bool buildReflection(int opts = EShReflectionDefault); + GLSLANG_EXPORT unsigned getLocalSize(int dim) const; // return dim'th local size + GLSLANG_EXPORT int getReflectionIndex(const char *name) const; + GLSLANG_EXPORT int getReflectionPipeIOIndex(const char* name, const bool inOrOut) const; + GLSLANG_EXPORT int getNumUniformVariables() const; + GLSLANG_EXPORT const TObjectReflection& getUniform(int index) const; + GLSLANG_EXPORT int getNumUniformBlocks() const; + GLSLANG_EXPORT const TObjectReflection& getUniformBlock(int index) const; + GLSLANG_EXPORT int getNumPipeInputs() const; + GLSLANG_EXPORT const TObjectReflection& getPipeInput(int index) const; + GLSLANG_EXPORT int getNumPipeOutputs() const; + GLSLANG_EXPORT const TObjectReflection& getPipeOutput(int index) const; + GLSLANG_EXPORT int getNumBufferVariables() const; + GLSLANG_EXPORT const TObjectReflection& getBufferVariable(int index) const; + GLSLANG_EXPORT int getNumBufferBlocks() const; + GLSLANG_EXPORT const TObjectReflection& getBufferBlock(int index) const; + GLSLANG_EXPORT int getNumAtomicCounters() const; + GLSLANG_EXPORT const TObjectReflection& getAtomicCounter(int index) const; + + // Legacy Reflection Interface - expressed in terms of above interface + + // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS) + int getNumLiveUniformVariables() const { return getNumUniformVariables(); } + + // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS) + int getNumLiveUniformBlocks() const { return getNumUniformBlocks(); } + + // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES) + int getNumLiveAttributes() const { return getNumPipeInputs(); } + + // can be used for glGetUniformIndices() + int getUniformIndex(const char *name) const { return getReflectionIndex(name); } + + int getPipeIOIndex(const char *name, const bool inOrOut) const + { return getReflectionPipeIOIndex(name, inOrOut); } + + // can be used for "name" part of glGetActiveUniform() + const char *getUniformName(int index) const { return getUniform(index).name.c_str(); } + + // returns the binding number + int getUniformBinding(int index) const { return getUniform(index).getBinding(); } + + // returns Shaders Stages where a Uniform is present + EShLanguageMask getUniformStages(int index) const { return getUniform(index).stages; } + + // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX) + int getUniformBlockIndex(int index) const { return getUniform(index).index; } + + // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE) + int getUniformType(int index) const { return getUniform(index).glDefineType; } + + // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET) + int getUniformBufferOffset(int index) const { return getUniform(index).offset; } + + // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE) + int getUniformArraySize(int index) const { return getUniform(index).size; } + + // returns a TType* + const TType *getUniformTType(int index) const { return getUniform(index).getType(); } + + // can be used for glGetActiveUniformBlockName() + const char *getUniformBlockName(int index) const { return getUniformBlock(index).name.c_str(); } + + // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE) + int getUniformBlockSize(int index) const { return getUniformBlock(index).size; } + + // returns the block binding number + int getUniformBlockBinding(int index) const { return getUniformBlock(index).getBinding(); } + + // returns block index of associated counter. + int getUniformBlockCounterIndex(int index) const { return getUniformBlock(index).counterIndex; } + + // returns a TType* + const TType *getUniformBlockTType(int index) const { return getUniformBlock(index).getType(); } + + // can be used for glGetActiveAttrib() + const char *getAttributeName(int index) const { return getPipeInput(index).name.c_str(); } + + // can be used for glGetActiveAttrib() + int getAttributeType(int index) const { return getPipeInput(index).glDefineType; } + + // returns a TType* + const TType *getAttributeTType(int index) const { return getPipeInput(index).getType(); } + + GLSLANG_EXPORT void dumpReflection(); + // I/O mapping: apply base offsets and map live unbound variables + // If resolver is not provided it uses the previous approach + // and respects auto assignment and offsets. + GLSLANG_EXPORT bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr); +#endif // !GLSLANG_WEB && !GLSLANG_ANGLE + +protected: + GLSLANG_EXPORT bool linkStage(EShLanguage, EShMessages); + GLSLANG_EXPORT bool crossStageCheck(EShMessages); + + TPoolAllocator* pool; + std::list stages[EShLangCount]; + TIntermediate* intermediate[EShLangCount]; + bool newedIntermediate[EShLangCount]; // track which intermediate were "new" versus reusing a singleton unit in a stage + TInfoSink* infoSink; +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + TReflection* reflection; +#endif + bool linked; + +private: + TProgram(TProgram&); + TProgram& operator=(TProgram&); +}; + +} // end namespace glslang + +#endif // _COMPILER_INTERFACE_INCLUDED_ diff --git a/libraries/ZVulkan/src/glslang/glslang/updateGrammar b/libraries/ZVulkan/src/glslang/glslang/updateGrammar new file mode 100644 index 00000000000..9209493f380 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/glslang/updateGrammar @@ -0,0 +1,49 @@ +#!/bin/bash + +# Copyright (C) 2020 The Khronos Group Inc. +# +# 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 The Khronos Group Inc. 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 HOLDERS 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 [ "$1" = 'web' ] +then + m4 -P -DGLSLANG_WEB MachineIndependent/glslang.m4 > MachineIndependent/glslang.y +elif [ "$#" -eq 0 ] +then + m4 -P MachineIndependent/glslang.m4 > MachineIndependent/glslang.y +else + echo usage: + echo $0 web + echo $0 + exit +fi + +bison --defines=MachineIndependent/glslang_tab.cpp.h -t MachineIndependent/glslang.y -o MachineIndependent/glslang_tab.cpp diff --git a/libraries/glslang/spirv/GLSL.ext.AMD.h b/libraries/ZVulkan/src/glslang/spirv/GLSL.ext.AMD.h similarity index 100% rename from libraries/glslang/spirv/GLSL.ext.AMD.h rename to libraries/ZVulkan/src/glslang/spirv/GLSL.ext.AMD.h diff --git a/libraries/glslang/spirv/GLSL.ext.EXT.h b/libraries/ZVulkan/src/glslang/spirv/GLSL.ext.EXT.h similarity index 84% rename from libraries/glslang/spirv/GLSL.ext.EXT.h rename to libraries/ZVulkan/src/glslang/spirv/GLSL.ext.EXT.h index 40164b6187f..f48f1304d65 100644 --- a/libraries/glslang/spirv/GLSL.ext.EXT.h +++ b/libraries/ZVulkan/src/glslang/spirv/GLSL.ext.EXT.h @@ -35,5 +35,9 @@ static const char* const E_SPV_EXT_shader_viewport_index_layer = "SPV_EXT_shade static const char* const E_SPV_EXT_fragment_fully_covered = "SPV_EXT_fragment_fully_covered"; static const char* const E_SPV_EXT_fragment_invocation_density = "SPV_EXT_fragment_invocation_density"; static const char* const E_SPV_EXT_demote_to_helper_invocation = "SPV_EXT_demote_to_helper_invocation"; +static const char* const E_SPV_EXT_shader_atomic_float_add = "SPV_EXT_shader_atomic_float_add"; +static const char* const E_SPV_EXT_shader_atomic_float16_add = "SPV_EXT_shader_atomic_float16_add"; +static const char* const E_SPV_EXT_shader_atomic_float_min_max = "SPV_EXT_shader_atomic_float_min_max"; +static const char* const E_SPV_EXT_shader_image_int64 = "SPV_EXT_shader_image_int64"; #endif // #ifndef GLSLextEXT_H diff --git a/libraries/glslang/spirv/GLSL.ext.KHR.h b/libraries/ZVulkan/src/glslang/spirv/GLSL.ext.KHR.h similarity index 77% rename from libraries/glslang/spirv/GLSL.ext.KHR.h rename to libraries/ZVulkan/src/glslang/spirv/GLSL.ext.KHR.h index e58e836a8d8..5eb3e944825 100644 --- a/libraries/glslang/spirv/GLSL.ext.KHR.h +++ b/libraries/ZVulkan/src/glslang/spirv/GLSL.ext.KHR.h @@ -1,5 +1,6 @@ /* -** Copyright (c) 2014-2016 The Khronos Group Inc. +** Copyright (c) 2014-2020 The Khronos Group Inc. +** Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and/or associated documentation files (the "Materials"), @@ -44,5 +45,12 @@ static const char* const E_SPV_EXT_physical_storage_buffer = "SPV_EXT_physi static const char* const E_SPV_KHR_physical_storage_buffer = "SPV_KHR_physical_storage_buffer"; static const char* const E_SPV_EXT_fragment_shader_interlock = "SPV_EXT_fragment_shader_interlock"; static const char* const E_SPV_KHR_shader_clock = "SPV_KHR_shader_clock"; +static const char* const E_SPV_KHR_non_semantic_info = "SPV_KHR_non_semantic_info"; +static const char* const E_SPV_KHR_ray_tracing = "SPV_KHR_ray_tracing"; +static const char* const E_SPV_KHR_ray_query = "SPV_KHR_ray_query"; +static const char* const E_SPV_KHR_fragment_shading_rate = "SPV_KHR_fragment_shading_rate"; +static const char* const E_SPV_KHR_terminate_invocation = "SPV_KHR_terminate_invocation"; +static const char* const E_SPV_KHR_workgroup_memory_explicit_layout = "SPV_KHR_workgroup_memory_explicit_layout"; +static const char* const E_SPV_KHR_subgroup_uniform_control_flow = "SPV_KHR_subgroup_uniform_control_flow"; #endif // #ifndef GLSLextKHR_H diff --git a/libraries/glslang/spirv/GLSL.ext.NV.h b/libraries/ZVulkan/src/glslang/spirv/GLSL.ext.NV.h similarity index 96% rename from libraries/glslang/spirv/GLSL.ext.NV.h rename to libraries/ZVulkan/src/glslang/spirv/GLSL.ext.NV.h index 50146da1043..93c98bf6269 100644 --- a/libraries/glslang/spirv/GLSL.ext.NV.h +++ b/libraries/ZVulkan/src/glslang/spirv/GLSL.ext.NV.h @@ -69,6 +69,9 @@ const char* const E_SPV_NV_mesh_shader = "SPV_NV_mesh_shader"; //SPV_NV_raytracing const char* const E_SPV_NV_ray_tracing = "SPV_NV_ray_tracing"; +//SPV_NV_ray_tracing_motion_blur +const char* const E_SPV_NV_ray_tracing_motion_blur = "SPV_NV_ray_tracing_motion_blur"; + //SPV_NV_shading_rate const char* const E_SPV_NV_shading_rate = "SPV_NV_shading_rate"; diff --git a/libraries/glslang/spirv/GLSL.std.450.h b/libraries/ZVulkan/src/glslang/spirv/GLSL.std.450.h similarity index 100% rename from libraries/glslang/spirv/GLSL.std.450.h rename to libraries/ZVulkan/src/glslang/spirv/GLSL.std.450.h diff --git a/libraries/glslang/spirv/GlslangToSpv.cpp b/libraries/ZVulkan/src/glslang/spirv/GlslangToSpv.cpp similarity index 82% rename from libraries/glslang/spirv/GlslangToSpv.cpp rename to libraries/ZVulkan/src/glslang/spirv/GlslangToSpv.cpp index 07556366229..42b084cbea1 100644 --- a/libraries/glslang/spirv/GlslangToSpv.cpp +++ b/libraries/ZVulkan/src/glslang/spirv/GlslangToSpv.cpp @@ -1,7 +1,8 @@ // // Copyright (C) 2014-2016 LunarG, Inc. -// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) 2015-2020 Google, Inc. // Copyright (C) 2017 ARM Limited. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -48,13 +49,16 @@ namespace spv { #include "GLSL.ext.EXT.h" #include "GLSL.ext.AMD.h" #include "GLSL.ext.NV.h" + #include "NonSemanticDebugPrintf.h" } // Glslang includes #include "../glslang/MachineIndependent/localintermediate.h" #include "../glslang/MachineIndependent/SymbolTable.h" #include "../glslang/Include/Common.h" -#include "../glslang/Include/revision.h" + +// Build-time generated includes +#include "../glslang/Include/build_info.h" #include #include @@ -145,6 +149,7 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier); spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier); spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier); + spv::Decoration TranslateNonUniformDecoration(const spv::Builder::AccessChain::CoherentFlags& coherentFlags); spv::Builder::AccessChain::CoherentFlags TranslateCoherent(const glslang::TType& type); spv::MemoryAccessMask TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags &coherentFlags); spv::ImageOperandsMask TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags &coherentFlags); @@ -155,6 +160,7 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const; spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector& operands) const; spv::StorageClass TranslateStorageClass(const glslang::TType&); + void TranslateLiterals(const glslang::TVector&, std::vector&) const; void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType); spv::Id createSpvVariable(const glslang::TIntermSymbol*, spv::Id forcedType); spv::Id getSampledType(const glslang::TSampler&); @@ -173,6 +179,7 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { spv::Id accessChainLoad(const glslang::TType& type); void accessChainStore(const glslang::TType& type, spv::Id rvalue); void multiTypeStore(const glslang::TType&, spv::Id rValue); + spv::Id convertLoadedBoolInUniformToUint(const glslang::TType& type, spv::Id nominalTypeId, spv::Id loadedId); glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const; int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix); int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix); @@ -185,9 +192,11 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { bool originalParam(glslang::TStorageQualifier, const glslang::TType&, bool implicitThisParam); void makeFunctions(const glslang::TIntermSequence&); void makeGlobalInitializers(const glslang::TIntermSequence&); + void collectRayTracingLinkerObjects(); void visitFunctions(const glslang::TIntermSequence&); void handleFunctionEntry(const glslang::TIntermAggregate* node); - void translateArguments(const glslang::TIntermAggregate& node, std::vector& arguments, spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); + void translateArguments(const glslang::TIntermAggregate& node, std::vector& arguments, + spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); void translateArguments(glslang::TIntermUnary& node, std::vector& arguments); spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node); spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*); @@ -196,28 +205,36 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { glslang::TBasicType typeProxy, bool reduceComparison = true); spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right); spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand, - glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); + glslang::TBasicType typeProxy, + const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy); spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand, glslang::TBasicType typeProxy); spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize); spv::Id makeSmearedConstant(spv::Id constant, int vectorSize); - spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); - spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); - spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation, spv::Id typeId, std::vector& operands); - spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); - spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); + spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, + std::vector& operands, glslang::TBasicType typeProxy, + const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); + spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, + glslang::TBasicType typeProxy); + spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation, + spv::Id typeId, std::vector& operands); + spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, + glslang::TBasicType typeProxy); + spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, + std::vector& operands, glslang::TBasicType typeProxy); spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId); spv::Id getSymbolId(const glslang::TIntermSymbol* node); void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier); spv::Id createSpvConstant(const glslang::TIntermTyped&); - spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant); + spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, + int& nextConst, bool specConstant); bool isTrivialLeaf(const glslang::TIntermTyped* node); bool isTrivial(const glslang::TIntermTyped* node); spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right); spv::Id getExtBuiltins(const char* name); - std::pair getForcedType(spv::BuiltIn, const glslang::TType&); + std::pair getForcedType(glslang::TBuiltInVariable builtIn, const glslang::TType&); spv::Id translateForcedType(spv::Id object); spv::Id createCompositeConstruct(spv::Id typeId, std::vector constituents); @@ -233,19 +250,24 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { spv::Builder builder; bool inEntryPoint; bool entryPointTerminated; - bool linkageOnly; // true when visiting the set of objects in the AST present only for establishing interface, whether or not they were statically used + bool linkageOnly; // true when visiting the set of objects in the AST present only for + // establishing interface, whether or not they were statically used std::set iOSet; // all input/output variables from either static use or declaration of interface const glslang::TIntermediate* glslangIntermediate; bool nanMinMaxClamp; // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp spv::Id stdBuiltins; - std::unordered_map extBuiltinMap; + spv::Id nonSemanticDebugPrintf; + std::unordered_map extBuiltinMap; - std::unordered_map symbolValues; - std::unordered_set rValueParameters; // set of formal function parameters passed as rValues, rather than a pointer + std::unordered_map symbolValues; + std::unordered_set rValueParameters; // set of formal function parameters passed as rValues, + // rather than a pointer std::unordered_map functionMap; std::unordered_map structMap[glslang::ElpCount][glslang::ElmCount]; // for mapping glslang block indices to spv indices (e.g., due to hidden members): - std::unordered_map > memberRemapper; + std::unordered_map> memberRemapper; + // for mapping glslang symbol struct to symbol Id + std::unordered_map glslangTypeToIdMap; std::stack breakForLoop; // false means break for switch std::unordered_map counterOriginator; // Map pointee types for EbtReference to their forward pointers @@ -254,6 +276,9 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { // requiring local translation to and from SPIR-V type on every access. // Maps AST-required-type-id> std::unordered_map forceType; + + // Used later for generating OpTraceKHR/OpExecuteCallableKHR + std::unordered_map locationToSymbol[2]; }; // @@ -265,6 +290,8 @@ spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile { #ifdef GLSLANG_WEB return spv::SourceLanguageESSL; +#elif defined(GLSLANG_ANGLE) + return spv::SourceLanguageGLSL; #endif switch (source) { @@ -297,12 +324,12 @@ spv::ExecutionModel TranslateExecutionModel(EShLanguage stage) case EShLangTessControl: return spv::ExecutionModelTessellationControl; case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation; case EShLangGeometry: return spv::ExecutionModelGeometry; - case EShLangRayGenNV: return spv::ExecutionModelRayGenerationNV; - case EShLangIntersectNV: return spv::ExecutionModelIntersectionNV; - case EShLangAnyHitNV: return spv::ExecutionModelAnyHitNV; - case EShLangClosestHitNV: return spv::ExecutionModelClosestHitNV; - case EShLangMissNV: return spv::ExecutionModelMissNV; - case EShLangCallableNV: return spv::ExecutionModelCallableNV; + case EShLangRayGen: return spv::ExecutionModelRayGenerationKHR; + case EShLangIntersect: return spv::ExecutionModelIntersectionKHR; + case EShLangAnyHit: return spv::ExecutionModelAnyHitKHR; + case EShLangClosestHit: return spv::ExecutionModelClosestHitKHR; + case EShLangMiss: return spv::ExecutionModelMissKHR; + case EShLangCallable: return spv::ExecutionModelCallableKHR; case EShLangTaskNV: return spv::ExecutionModelTaskNV; case EShLangMeshNV: return spv::ExecutionModelMeshNV; #endif @@ -355,12 +382,13 @@ spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useSto case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock; case glslang::EvqVaryingIn: return spv::DecorationBlock; case glslang::EvqVaryingOut: return spv::DecorationBlock; + case glslang::EvqShared: return spv::DecorationBlock; #ifndef GLSLANG_WEB - case glslang::EvqPayloadNV: return spv::DecorationBlock; - case glslang::EvqPayloadInNV: return spv::DecorationBlock; - case glslang::EvqHitAttrNV: return spv::DecorationBlock; - case glslang::EvqCallableDataNV: return spv::DecorationBlock; - case glslang::EvqCallableDataInNV: return spv::DecorationBlock; + case glslang::EvqPayload: return spv::DecorationBlock; + case glslang::EvqPayloadIn: return spv::DecorationBlock; + case glslang::EvqHitAttr: return spv::DecorationBlock; + case glslang::EvqCallableData: return spv::DecorationBlock; + case glslang::EvqCallableDataIn: return spv::DecorationBlock; #endif default: assert(0); @@ -372,7 +400,8 @@ spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useSto } // Translate glslang type to SPIR-V memory decorations. -void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector& memory, bool useVulkanMemoryModel) +void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector& memory, + bool useVulkanMemoryModel) { if (!useVulkanMemoryModel) { if (qualifier.isCoherent()) @@ -410,6 +439,7 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T break; case glslang::EbtBlock: switch (type.getQualifier().storage) { + case glslang::EvqShared: case glslang::EvqUniform: case glslang::EvqBuffer: switch (type.getQualifier().layoutPacking) { @@ -431,11 +461,11 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T } return spv::DecorationMax; #ifndef GLSLANG_WEB - case glslang::EvqPayloadNV: - case glslang::EvqPayloadInNV: - case glslang::EvqHitAttrNV: - case glslang::EvqCallableDataNV: - case glslang::EvqCallableDataInNV: + case glslang::EvqPayload: + case glslang::EvqPayloadIn: + case glslang::EvqHitAttr: + case glslang::EvqCallableData: + case glslang::EvqCallableDataIn: return spv::DecorationMax; #endif default: @@ -518,6 +548,20 @@ spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glsl return spv::DecorationMax; } +// If lvalue flags contains nonUniform, return SPIR-V NonUniform decoration. +spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration( + const spv::Builder::AccessChain::CoherentFlags& coherentFlags) +{ +#ifndef GLSLANG_WEB + if (coherentFlags.isNonUniform()) { + builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5); + builder.addCapability(spv::CapabilityShaderNonUniformEXT); + return spv::DecorationNonUniformEXT; + } else +#endif + return spv::DecorationMax; +} + spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess( const spv::Builder::AccessChain::CoherentFlags &coherentFlags) { @@ -527,15 +571,11 @@ spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess( if (!glslangIntermediate->usingVulkanMemoryModel() || coherentFlags.isImage) return mask; - if (coherentFlags.volatil || - coherentFlags.coherent || - coherentFlags.devicecoherent || - coherentFlags.queuefamilycoherent || - coherentFlags.workgroupcoherent || - coherentFlags.subgroupcoherent) { + if (coherentFlags.isVolatile() || coherentFlags.anyCoherent()) { mask = mask | spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask; } + if (coherentFlags.nonprivate) { mask = mask | spv::MemoryAccessNonPrivatePointerKHRMask; } @@ -560,11 +600,7 @@ spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands( return mask; if (coherentFlags.volatil || - coherentFlags.coherent || - coherentFlags.devicecoherent || - coherentFlags.queuefamilycoherent || - coherentFlags.workgroupcoherent || - coherentFlags.subgroupcoherent) { + coherentFlags.anyCoherent()) { mask = mask | spv::ImageOperandsMakeTexelAvailableKHRMask | spv::ImageOperandsMakeTexelVisibleKHRMask; } @@ -593,17 +629,15 @@ spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCohere flags.workgroupcoherent = type.getQualifier().workgroupcoherent || type.getQualifier().storage == glslang::EvqShared; flags.subgroupcoherent = type.getQualifier().subgroupcoherent; + flags.shadercallcoherent = type.getQualifier().shadercallcoherent; flags.volatil = type.getQualifier().volatil; // *coherent variables are implicitly nonprivate in GLSL flags.nonprivate = type.getQualifier().nonprivate || - flags.subgroupcoherent || - flags.workgroupcoherent || - flags.queuefamilycoherent || - flags.devicecoherent || - flags.coherent || + flags.anyCoherent() || flags.volatil; flags.isImage = type.getBasicType() == glslang::EbtSampler; #endif + flags.nonUniform = type.getQualifier().nonUniform; return flags; } @@ -624,6 +658,8 @@ spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope( scope = spv::ScopeWorkgroup; } else if (coherentFlags.subgroupcoherent) { scope = spv::ScopeSubgroup; + } else if (coherentFlags.shadercallcoherent) { + scope = spv::ScopeShaderCallKHR; } if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::ScopeDevice) { builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR); @@ -638,7 +674,8 @@ spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope( // is generated only when using the variable in an executable instruction, but not when // just declaring a struct member variable with it. This is true for PointSize, // ClipDistance, and CullDistance. -spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn, bool memberDeclaration) +spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn, + bool memberDeclaration) { switch (builtIn) { case glslang::EbvPointSize: @@ -696,13 +733,20 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI return spv::BuiltInCullDistance; case glslang::EbvViewportIndex: - builder.addCapability(spv::CapabilityMultiViewport); + if (glslangIntermediate->getStage() == EShLangGeometry || + glslangIntermediate->getStage() == EShLangFragment) { + builder.addCapability(spv::CapabilityMultiViewport); + } if (glslangIntermediate->getStage() == EShLangVertex || glslangIntermediate->getStage() == EShLangTessControl || glslangIntermediate->getStage() == EShLangTessEvaluation) { - builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5); - builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT); + if (builder.getSpvVersion() < spv::Spv_1_5) { + builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5); + builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT); + } + else + builder.addCapability(spv::CapabilityShaderViewportIndex); } return spv::BuiltInViewportIndex; @@ -721,13 +765,19 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI if (glslangIntermediate->getStage() == EShLangMeshNV) { return spv::BuiltInLayer; } - builder.addCapability(spv::CapabilityGeometry); + if (glslangIntermediate->getStage() == EShLangGeometry || + glslangIntermediate->getStage() == EShLangFragment) { + builder.addCapability(spv::CapabilityGeometry); + } if (glslangIntermediate->getStage() == EShLangVertex || glslangIntermediate->getStage() == EShLangTessControl || glslangIntermediate->getStage() == EShLangTessEvaluation) { - builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5); - builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT); + if (builder.getSpvVersion() < spv::Spv_1_5) { + builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5); + builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT); + } else + builder.addCapability(spv::CapabilityShaderLayer); } return spv::BuiltInLayer; @@ -756,6 +806,16 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI builder.addCapability(spv::CapabilityStencilExportEXT); return spv::BuiltInFragStencilRefEXT; + case glslang::EbvShadingRateKHR: + builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate); + builder.addCapability(spv::CapabilityFragmentShadingRateKHR); + return spv::BuiltInShadingRateKHR; + + case glslang::EbvPrimitiveShadingRateKHR: + builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate); + builder.addCapability(spv::CapabilityFragmentShadingRateKHR); + return spv::BuiltInPrimitiveShadingRateKHR; + case glslang::EbvInvocationId: return spv::BuiltInInvocationId; case glslang::EbvTessLevelInner: return spv::BuiltInTessLevelInner; case glslang::EbvTessLevelOuter: return spv::BuiltInTessLevelOuter; @@ -931,34 +991,52 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI return spv::BuiltInInvocationsPerPixelNV; // ray tracing - case glslang::EbvLaunchIdNV: - return spv::BuiltInLaunchIdNV; - case glslang::EbvLaunchSizeNV: - return spv::BuiltInLaunchSizeNV; - case glslang::EbvWorldRayOriginNV: - return spv::BuiltInWorldRayOriginNV; - case glslang::EbvWorldRayDirectionNV: - return spv::BuiltInWorldRayDirectionNV; - case glslang::EbvObjectRayOriginNV: - return spv::BuiltInObjectRayOriginNV; - case glslang::EbvObjectRayDirectionNV: - return spv::BuiltInObjectRayDirectionNV; - case glslang::EbvRayTminNV: - return spv::BuiltInRayTminNV; - case glslang::EbvRayTmaxNV: - return spv::BuiltInRayTmaxNV; - case glslang::EbvInstanceCustomIndexNV: - return spv::BuiltInInstanceCustomIndexNV; - case glslang::EbvHitTNV: - return spv::BuiltInHitTNV; - case glslang::EbvHitKindNV: - return spv::BuiltInHitKindNV; - case glslang::EbvObjectToWorldNV: - return spv::BuiltInObjectToWorldNV; - case glslang::EbvWorldToObjectNV: - return spv::BuiltInWorldToObjectNV; - case glslang::EbvIncomingRayFlagsNV: - return spv::BuiltInIncomingRayFlagsNV; + case glslang::EbvLaunchId: + return spv::BuiltInLaunchIdKHR; + case glslang::EbvLaunchSize: + return spv::BuiltInLaunchSizeKHR; + case glslang::EbvWorldRayOrigin: + return spv::BuiltInWorldRayOriginKHR; + case glslang::EbvWorldRayDirection: + return spv::BuiltInWorldRayDirectionKHR; + case glslang::EbvObjectRayOrigin: + return spv::BuiltInObjectRayOriginKHR; + case glslang::EbvObjectRayDirection: + return spv::BuiltInObjectRayDirectionKHR; + case glslang::EbvRayTmin: + return spv::BuiltInRayTminKHR; + case glslang::EbvRayTmax: + return spv::BuiltInRayTmaxKHR; + case glslang::EbvInstanceCustomIndex: + return spv::BuiltInInstanceCustomIndexKHR; + case glslang::EbvHitT: + { + // this is a GLSL alias of RayTmax + // in SPV_NV_ray_tracing it has a dedicated builtin + // but in SPV_KHR_ray_tracing it gets mapped to RayTmax + auto& extensions = glslangIntermediate->getRequestedExtensions(); + if (extensions.find("GL_NV_ray_tracing") != extensions.end()) { + return spv::BuiltInHitTNV; + } else { + return spv::BuiltInRayTmaxKHR; + } + } + case glslang::EbvHitKind: + return spv::BuiltInHitKindKHR; + case glslang::EbvObjectToWorld: + case glslang::EbvObjectToWorld3x4: + return spv::BuiltInObjectToWorldKHR; + case glslang::EbvWorldToObject: + case glslang::EbvWorldToObject3x4: + return spv::BuiltInWorldToObjectKHR; + case glslang::EbvIncomingRayFlags: + return spv::BuiltInIncomingRayFlagsKHR; + case glslang::EbvGeometryIndex: + return spv::BuiltInRayGeometryIndexKHR; + case glslang::EbvCurrentRayTimeNV: + builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur); + builder.addCapability(spv::CapabilityRayTracingMotionBlurNV); + return spv::BuiltInCurrentRayTimeNV; // barycentrics case glslang::EbvBaryCoordNV: @@ -1054,6 +1132,10 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy builder.addCapability(spv::CapabilityStorageImageExtendedFormats); break; + case glslang::ElfR64ui: + case glslang::ElfR64i: + builder.addExtension(spv::E_SPV_EXT_shader_image_int64); + builder.addCapability(spv::CapabilityInt64ImageEXT); default: break; } @@ -1100,11 +1182,14 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy case glslang::ElfRg8ui: return spv::ImageFormatRg8ui; case glslang::ElfR16ui: return spv::ImageFormatR16ui; case glslang::ElfR8ui: return spv::ImageFormatR8ui; + case glslang::ElfR64ui: return spv::ImageFormatR64ui; + case glslang::ElfR64i: return spv::ImageFormatR64i; default: return spv::ImageFormatMax; } } -spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(const glslang::TIntermSelection& selectionNode) const +spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl( + const glslang::TIntermSelection& selectionNode) const { if (selectionNode.getFlatten()) return spv::SelectionControlFlattenMask; @@ -1113,7 +1198,8 @@ spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(cons return spv::SelectionControlMaskNone; } -spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) const +spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) + const { if (switchNode.getFlatten()) return spv::SelectionControlFlattenMask; @@ -1167,6 +1253,12 @@ spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang: // Translate glslang type to SPIR-V storage class. spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type) { + if (type.getBasicType() == glslang::EbtRayQuery) + return spv::StorageClassPrivate; +#ifndef GLSLANG_WEB + if (type.getQualifier().isSpirvByReference()) + return spv::StorageClassFunction; +#endif if (type.getQualifier().isPipeInput()) return spv::StorageClassInput; if (type.getQualifier().isPipeOutput()) @@ -1181,8 +1273,8 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T } if (type.getQualifier().isUniformOrBuffer() && - type.getQualifier().isShaderRecordNV()) { - return spv::StorageClassShaderRecordBufferNV; + type.getQualifier().isShaderRecord()) { + return spv::StorageClassShaderRecordBufferKHR; } if (glslangIntermediate->usingStorageBuffer() && type.getQualifier().storage == glslang::EvqBuffer) { @@ -1198,17 +1290,24 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T return spv::StorageClassUniformConstant; } + if (type.getQualifier().storage == glslang::EvqShared && type.getBasicType() == glslang::EbtBlock) { + builder.addExtension(spv::E_SPV_KHR_workgroup_memory_explicit_layout); + builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayoutKHR); + return spv::StorageClassWorkgroup; + } + switch (type.getQualifier().storage) { case glslang::EvqGlobal: return spv::StorageClassPrivate; case glslang::EvqConstReadOnly: return spv::StorageClassFunction; case glslang::EvqTemporary: return spv::StorageClassFunction; case glslang::EvqShared: return spv::StorageClassWorkgroup; #ifndef GLSLANG_WEB - case glslang::EvqPayloadNV: return spv::StorageClassRayPayloadNV; - case glslang::EvqPayloadInNV: return spv::StorageClassIncomingRayPayloadNV; - case glslang::EvqHitAttrNV: return spv::StorageClassHitAttributeNV; - case glslang::EvqCallableDataNV: return spv::StorageClassCallableDataNV; - case glslang::EvqCallableDataInNV: return spv::StorageClassIncomingCallableDataNV; + case glslang::EvqPayload: return spv::StorageClassRayPayloadKHR; + case glslang::EvqPayloadIn: return spv::StorageClassIncomingRayPayloadKHR; + case glslang::EvqHitAttr: return spv::StorageClassHitAttributeKHR; + case glslang::EvqCallableData: return spv::StorageClassCallableDataKHR; + case glslang::EvqCallableDataIn: return spv::StorageClassIncomingCallableDataKHR; + case glslang::EvqSpirvStorageClass: return static_cast(type.getQualifier().spirvStorageClass); #endif default: assert(0); @@ -1218,6 +1317,52 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T return spv::StorageClassFunction; } +// Translate glslang constants to SPIR-V literals +void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVector& constants, + std::vector& literals) const +{ + for (auto constant : constants) { + if (constant->getBasicType() == glslang::EbtFloat) { + float floatValue = static_cast(constant->getConstArray()[0].getDConst()); + unsigned literal = *reinterpret_cast(&floatValue); + literals.push_back(literal); + } else if (constant->getBasicType() == glslang::EbtInt) { + unsigned literal = constant->getConstArray()[0].getIConst(); + literals.push_back(literal); + } else if (constant->getBasicType() == glslang::EbtUint) { + unsigned literal = constant->getConstArray()[0].getUConst(); + literals.push_back(literal); + } else if (constant->getBasicType() == glslang::EbtBool) { + unsigned literal = constant->getConstArray()[0].getBConst(); + literals.push_back(literal); + } else if (constant->getBasicType() == glslang::EbtString) { + auto str = constant->getConstArray()[0].getSConst()->c_str(); + unsigned literal = 0; + char* literalPtr = reinterpret_cast(&literal); + unsigned charCount = 0; + char ch = 0; + do { + ch = *(str++); + *(literalPtr++) = ch; + ++charCount; + if (charCount == 4) { + literals.push_back(literal); + literalPtr = reinterpret_cast(&literal); + charCount = 0; + } + } while (ch != 0); + + // Partial literal is padded with 0 + if (charCount > 0) { + for (; charCount < 4; ++charCount) + *(literalPtr++) = 0; + literals.push_back(literal); + } + } else + assert(0); // Unexpected type + } +} + // Add capabilities pertaining to how an array is indexed. void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType) @@ -1268,14 +1413,15 @@ bool IsDescriptorResource(const glslang::TType& type) // uniform and buffer blocks are included, unless it is a push_constant if (type.getBasicType() == glslang::EbtBlock) return type.getQualifier().isUniformOrBuffer() && - ! type.getQualifier().isShaderRecordNV() && + ! type.getQualifier().isShaderRecord() && ! type.getQualifier().isPushConstant(); // non block... // basically samplerXXX/subpass/sampler/texture are all included // if they are the global-scope-class, not the function parameter // (or local, if they ever exist) class. - if (type.getBasicType() == glslang::EbtSampler) + if (type.getBasicType() == glslang::EbtSampler || + type.getBasicType() == glslang::EbtAccStruct) return type.getQualifier().isUniformOrBuffer(); // None of the above. @@ -1318,6 +1464,8 @@ void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& pa child.workgroupcoherent = true; if (parent.subgroupcoherent) child.subgroupcoherent = true; + if (parent.shadercallcoherent) + child.shadercallcoherent = true; if (parent.nonprivate) child.nonprivate = true; if (parent.volatil) @@ -1329,6 +1477,8 @@ void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& pa if (parent.writeonly) child.writeonly = true; #endif + if (parent.nonUniform) + child.nonUniform = true; } bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier) @@ -1348,16 +1498,18 @@ bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifie // Implement the TGlslangToSpvTraverser class. // -TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate* glslangIntermediate, - spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) - : TIntermTraverser(true, false, true), - options(options), - shaderEntry(nullptr), currentFunction(nullptr), - sequenceDepth(0), logger(buildLogger), - builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger), - inEntryPoint(false), entryPointTerminated(false), linkageOnly(false), - glslangIntermediate(glslangIntermediate), - nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp()) +TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, + const glslang::TIntermediate* glslangIntermediate, + spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) : + TIntermTraverser(true, false, true), + options(options), + shaderEntry(nullptr), currentFunction(nullptr), + sequenceDepth(0), logger(buildLogger), + builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger), + inEntryPoint(false), entryPointTerminated(false), linkageOnly(false), + glslangIntermediate(glslangIntermediate), + nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp()), + nonSemanticDebugPrintf(0) { spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage()); @@ -1398,9 +1550,9 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl if (glslangIntermediate->usingPhysicalStorageBuffer()) { addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT; - builder.addIncorporatedExtension(spv::E_SPV_EXT_physical_storage_buffer, spv::Spv_1_5); + builder.addIncorporatedExtension(spv::E_SPV_KHR_physical_storage_buffer, spv::Spv_1_5); builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT); - }; + } if (glslangIntermediate->usingVulkanMemoryModel()) { memoryModel = spv::MemoryModelVulkanKHR; builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); @@ -1427,6 +1579,17 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb); } + if (glslangIntermediate->getLayoutPrimitiveCulling()) { + builder.addCapability(spv::CapabilityRayTraversalPrimitiveCullingKHR); + } + +#ifndef GLSLANG_WEB + if (glslangIntermediate->getSubgroupUniformControlFlow()) { + builder.addExtension(spv::E_SPV_KHR_subgroup_uniform_control_flow); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeSubgroupUniformControlFlowKHR); + } +#endif + unsigned int mode; switch (glslangIntermediate->getStage()) { case EShLangVertex: @@ -1452,14 +1615,16 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl builder.addExtension(spv::E_SPV_KHR_post_depth_coverage); } - if (glslangIntermediate->getDepth() != glslang::EldUnchanged && glslangIntermediate->isDepthReplacing()) + if (glslangIntermediate->isDepthReplacing()) builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing); #ifndef GLSLANG_WEB + switch(glslangIntermediate->getDepth()) { - case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break; - case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break; - default: mode = spv::ExecutionModeMax; break; + case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break; + case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break; + case glslang::EldUnchanged: mode = spv::ExecutionModeDepthUnchanged; break; + default: mode = spv::ExecutionModeMax; break; } if (mode != spv::ExecutionModeMax) builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); @@ -1493,7 +1658,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock); } #endif - break; + break; case EShLangCompute: builder.addCapability(spv::CapabilityShader); @@ -1518,7 +1683,8 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl glslang::TLayoutGeometry primitive; if (glslangIntermediate->getStage() == EShLangTessControl) { - builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, + glslangIntermediate->getVertices()); primitive = glslangIntermediate->getOutputPrimitive(); } else { primitive = glslangIntermediate->getInputPrimitive(); @@ -1580,15 +1746,24 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); break; - case EShLangRayGenNV: - case EShLangIntersectNV: - case EShLangAnyHitNV: - case EShLangClosestHitNV: - case EShLangMissNV: - case EShLangCallableNV: - builder.addCapability(spv::CapabilityRayTracingNV); - builder.addExtension("SPV_NV_ray_tracing"); + case EShLangRayGen: + case EShLangIntersect: + case EShLangAnyHit: + case EShLangClosestHit: + case EShLangMiss: + case EShLangCallable: + { + auto& extensions = glslangIntermediate->getRequestedExtensions(); + if (extensions.find("GL_NV_ray_tracing") == extensions.end()) { + builder.addCapability(spv::CapabilityRayTracingKHR); + builder.addExtension("SPV_KHR_ray_tracing"); + } + else { + builder.addCapability(spv::CapabilityRayTracingNV); + builder.addExtension("SPV_NV_ray_tracing"); + } break; + } case EShLangTaskNV: case EShLangMeshNV: builder.addCapability(spv::CapabilityMeshShadingNV); @@ -1597,8 +1772,10 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl glslangIntermediate->getLocalSize(1), glslangIntermediate->getLocalSize(2)); if (glslangIntermediate->getStage() == EShLangMeshNV) { - builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); - builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV, glslangIntermediate->getPrimitives()); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, + glslangIntermediate->getVertices()); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV, + glslangIntermediate->getPrimitives()); switch (glslangIntermediate->getOutputPrimitive()) { case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break; @@ -1615,6 +1792,53 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl default: break; } + +#ifndef GLSLANG_WEB + // + // Add SPIR-V requirements (GL_EXT_spirv_intrinsics) + // + if (glslangIntermediate->hasSpirvRequirement()) { + const glslang::TSpirvRequirement& spirvRequirement = glslangIntermediate->getSpirvRequirement(); + + // Add SPIR-V extension requirement + for (auto& extension : spirvRequirement.extensions) + builder.addExtension(extension.c_str()); + + // Add SPIR-V capability requirement + for (auto capability : spirvRequirement.capabilities) + builder.addCapability(static_cast(capability)); + } + + // + // Add SPIR-V execution mode qualifiers (GL_EXT_spirv_intrinsics) + // + if (glslangIntermediate->hasSpirvExecutionMode()) { + const glslang::TSpirvExecutionMode spirvExecutionMode = glslangIntermediate->getSpirvExecutionMode(); + + // Add spirv_execution_mode + for (auto& mode : spirvExecutionMode.modes) { + if (!mode.second.empty()) { + std::vector literals; + TranslateLiterals(mode.second, literals); + builder.addExecutionMode(shaderEntry, static_cast(mode.first), literals); + } else + builder.addExecutionMode(shaderEntry, static_cast(mode.first)); + } + + // Add spirv_execution_mode_id + for (auto& modeId : spirvExecutionMode.modeIds) { + std::vector operandIds; + assert(!modeId.second.empty()); + for (auto extraOperand : modeId.second) { + int nextConst = 0; + spv::Id operandId = createSpvConstantFromConstUnionArray( + extraOperand->getType(), extraOperand->getConstArray(), nextConst, false); + operandIds.push_back(operandId); + } + builder.addExecutionModeId(shaderEntry, static_cast(modeId.first), operandIds); + } + } +#endif } // Finish creating SPV, after the traversal is complete. @@ -1661,28 +1885,41 @@ void TGlslangToSpvTraverser::dumpSpv(std::vector& out) void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) { SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); + if (symbol->getType().isStruct()) + glslangTypeToIdMap[symbol->getType().getStruct()] = symbol->getId(); + if (symbol->getType().getQualifier().isSpecConstant()) spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); +#ifdef ENABLE_HLSL + // Skip symbol handling if it is string-typed + if (symbol->getBasicType() == glslang::EbtString) + return; +#endif + // getSymbolId() will set up all the IO decorations on the first call. // Formal function parameters were mapped during makeFunctions(). spv::Id id = getSymbolId(symbol); if (builder.isPointer(id)) { - // Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction - // Consider adding to the OpEntryPoint interface list. - // Only looking at structures if they have at least one member. - if (!symbol->getType().isStruct() || symbol->getType().getStruct()->size() > 0) { - spv::StorageClass sc = builder.getStorageClass(id); - // Before SPIR-V 1.4, we only want to include Input and Output. - // Starting with SPIR-V 1.4, we want all globals. - if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && sc != spv::StorageClassFunction) || - (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)) { - iOSet.insert(id); + if (!symbol->getType().getQualifier().isParamInput() && + !symbol->getType().getQualifier().isParamOutput()) { + // Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction + // Consider adding to the OpEntryPoint interface list. + // Only looking at structures if they have at least one member. + if (!symbol->getType().isStruct() || symbol->getType().getStruct()->size() > 0) { + spv::StorageClass sc = builder.getStorageClass(id); + // Before SPIR-V 1.4, we only want to include Input and Output. + // Starting with SPIR-V 1.4, we want all globals. + if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && builder.isGlobalStorage(id)) || + (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)) { + iOSet.insert(id); + } } } - // If the SPIR-V type is required to be different than the AST type, + // If the SPIR-V type is required to be different than the AST type + // (for ex SubgroupMasks or 3x4 ObjectToWorld/WorldToObject matrices), // translate now from the SPIR-V type to the AST type, for the consuming // operation. // Note this turns it from an l-value to an r-value. @@ -1753,6 +1990,12 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node) { builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + if (node->getLeft()->getAsSymbolNode() != nullptr && node->getLeft()->getType().isStruct()) { + glslangTypeToIdMap[node->getLeft()->getType().getStruct()] = node->getLeft()->getAsSymbolNode()->getId(); + } + if (node->getRight()->getAsSymbolNode() != nullptr && node->getRight()->getType().isStruct()) { + glslangTypeToIdMap[node->getRight()->getType().getStruct()] = node->getRight()->getAsSymbolNode()->getId(); + } SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); if (node->getType().getQualifier().isSpecConstant()) @@ -1796,9 +2039,11 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T spv::Id leftRValue = accessChainLoad(node->getLeft()->getType()); // do the operation + spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType()); + coherentFlags |= TranslateCoherent(node->getRight()->getType()); OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()), TranslateNoContractionDecoration(node->getType().getQualifier()), - TranslateNonUniformDecoration(node->getType().getQualifier()) }; + TranslateNonUniformDecoration(coherentFlags) }; rValue = createBinaryOperation(node->getOp(), decorations, convertGlslangToSpvType(node->getType()), leftRValue, rValue, node->getType().getBasicType()); @@ -1829,14 +2074,18 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector() && node->getOp() == glslang::EOpIndexDirect) { + // Swizzle is uniform so propagate uniform into access chain + spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType()); + coherentFlags.nonUniform = 0; // This is essentially a hard-coded vector swizzle of size 1, // so short circuit the access-chain stuff with a swizzle. std::vector swizzle; swizzle.push_back(glslangIndex); int dummySize; builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()), - TranslateCoherent(node->getLeft()->getType()), - glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize)); + coherentFlags, + glslangIntermediate->getBaseAlignmentScalar( + node->getLeft()->getType(), dummySize)); } else { // Load through a block reference is performed with a dot operator that @@ -1857,13 +2106,23 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T { // This may be, e.g., an anonymous block-member selection, which generally need // index remapping due to hidden members in anonymous blocks. - std::vector& remapper = memberRemapper[node->getLeft()->getType().getStruct()]; - assert(remapper.size() > 0); - spvIndex = remapper[glslangIndex]; + long long glslangId = glslangTypeToIdMap[node->getLeft()->getType().getStruct()]; + if (memberRemapper.find(glslangId) != memberRemapper.end()) { + std::vector& remapper = memberRemapper[glslangId]; + assert(remapper.size() > 0); + spvIndex = remapper[glslangIndex]; + } } + // Struct reference propagates uniform lvalue + spv::Builder::AccessChain::CoherentFlags coherentFlags = + TranslateCoherent(node->getLeft()->getType()); + coherentFlags.nonUniform = 0; + // normal case for indexing array or structure or block - builder.accessChainPush(builder.makeIntConstant(spvIndex), TranslateCoherent(node->getLeft()->getType()), node->getLeft()->getType().getBufferReferenceAlignment()); + builder.accessChainPush(builder.makeIntConstant(spvIndex), + coherentFlags, + node->getLeft()->getType().getBufferReferenceAlignment()); // Add capabilities here for accessing PointSize and clip/cull distance. // We have deferred generation of associated capabilities until now. @@ -1896,13 +2155,20 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T // restore the saved access chain builder.setAccessChain(partial); + // Only if index is nonUniform should we propagate nonUniform into access chain + spv::Builder::AccessChain::CoherentFlags index_flags = TranslateCoherent(node->getRight()->getType()); + spv::Builder::AccessChain::CoherentFlags coherent_flags = TranslateCoherent(node->getLeft()->getType()); + coherent_flags.nonUniform = index_flags.nonUniform; + if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) { int dummySize; - builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()), - TranslateCoherent(node->getLeft()->getType()), - glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize)); + builder.accessChainPushComponent( + index, convertGlslangToSpvType(node->getLeft()->getType()), coherent_flags, + glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), + dummySize)); } else - builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()), node->getLeft()->getType().getBufferReferenceAlignment()); + builder.accessChainPush(index, coherent_flags, + node->getLeft()->getType().getBufferReferenceAlignment()); } return false; case glslang::EOpVectorSwizzle: @@ -1913,7 +2179,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T int dummySize; builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()), TranslateCoherent(node->getLeft()->getType()), - glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize)); + glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), + dummySize)); } return false; case glslang::EOpMatrixSwizzle: @@ -1929,7 +2196,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T if (isTrivial(node->getRight()->getAsTyped())) break; // handle below as a normal binary operation // otherwise, we need to do dynamic short circuiting on the right operand - spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(), *node->getRight()->getAsTyped()); + spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(), + *node->getRight()->getAsTyped()); builder.clearAccessChain(); builder.setAccessChainRValue(result); } @@ -1968,24 +2236,77 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T } } +spv::Id TGlslangToSpvTraverser::convertLoadedBoolInUniformToUint(const glslang::TType& type, + spv::Id nominalTypeId, + spv::Id loadedId) +{ + if (builder.isScalarType(nominalTypeId)) { + // Conversion for bool + spv::Id boolType = builder.makeBoolType(); + if (nominalTypeId != boolType) + return builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0)); + } else if (builder.isVectorType(nominalTypeId)) { + // Conversion for bvec + int vecSize = builder.getNumTypeComponents(nominalTypeId); + spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize); + if (nominalTypeId != bvecType) + loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId, + makeSmearedConstant(builder.makeUintConstant(0), vecSize)); + } else if (builder.isArrayType(nominalTypeId)) { + // Conversion for bool array + spv::Id boolArrayTypeId = convertGlslangToSpvType(type); + if (nominalTypeId != boolArrayTypeId) + { + // Use OpCopyLogical from SPIR-V 1.4 if available. + if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) + return builder.createUnaryOp(spv::OpCopyLogical, boolArrayTypeId, loadedId); + + glslang::TType glslangElementType(type, 0); + spv::Id elementNominalTypeId = builder.getContainedTypeId(nominalTypeId); + std::vector constituents; + for (int index = 0; index < type.getOuterArraySize(); ++index) { + // get the element + spv::Id elementValue = builder.createCompositeExtract(loadedId, elementNominalTypeId, index); + + // recursively convert it + spv::Id elementConvertedValue = convertLoadedBoolInUniformToUint(glslangElementType, elementNominalTypeId, elementValue); + constituents.push_back(elementConvertedValue); + } + return builder.createCompositeConstruct(boolArrayTypeId, constituents); + } + } + + return loadedId; +} + // Figure out what, if any, type changes are needed when accessing a specific built-in. // Returns . // Also see comment for 'forceType', regarding tracking SPIR-V-required types. -std::pair TGlslangToSpvTraverser::getForcedType(spv::BuiltIn builtIn, +std::pair TGlslangToSpvTraverser::getForcedType(glslang::TBuiltInVariable glslangBuiltIn, const glslang::TType& glslangType) { - switch(builtIn) + switch(glslangBuiltIn) { - case spv::BuiltInSubgroupEqMask: - case spv::BuiltInSubgroupGeMask: - case spv::BuiltInSubgroupGtMask: - case spv::BuiltInSubgroupLeMask: - case spv::BuiltInSubgroupLtMask: { + case glslang::EbvSubGroupEqMask: + case glslang::EbvSubGroupGeMask: + case glslang::EbvSubGroupGtMask: + case glslang::EbvSubGroupLeMask: + case glslang::EbvSubGroupLtMask: { // these require changing a 64-bit scaler -> a vector of 32-bit components if (glslangType.isVector()) break; - std::pair ret(builder.makeVectorType(builder.makeUintType(32), 4), - builder.makeUintType(64)); + spv::Id ivec4_type = builder.makeVectorType(builder.makeUintType(32), 4); + spv::Id uint64_type = builder.makeUintType(64); + std::pair ret(ivec4_type, uint64_type); + return ret; + } + // There are no SPIR-V builtins defined for these and map onto original non-transposed + // builtins. During visitBinary we insert a transpose + case glslang::EbvWorldToObject3x4: + case glslang::EbvObjectToWorld3x4: { + spv::Id mat43 = builder.makeMatrixType(builder.makeFloatType(32), 4, 3); + spv::Id mat34 = builder.makeMatrixType(builder.makeFloatType(32), 3, 4); + std::pair ret(mat43, mat34); return ret; } default: @@ -2015,7 +2336,7 @@ spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object) // handle 32-bit v.xy* -> 64-bit builder.clearAccessChain(); builder.setAccessChainLValue(object); - object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, objectTypeId); + object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId); std::vector components; components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 0)); components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 1)); @@ -2026,7 +2347,15 @@ spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object) } else { logger->missingFunctionality("forcing 32-bit vector type to non 64-bit scalar"); } - } else { + } else if (builder.isMatrixType(objectTypeId)) { + // There are no SPIR-V builtins defined for 3x4 variants of ObjectToWorld/WorldToObject + // and we insert a transpose after loading the original non-transposed builtins + builder.clearAccessChain(); + builder.setAccessChainLValue(object); + object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId); + return builder.createUnaryOp(spv::OpTranspose, desiredTypeId, object); + + } else { logger->missingFunctionality("forcing non 32-bit vector type"); } @@ -2077,7 +2406,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI } else { glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft(); block->traverse(this); - unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()->getConstArray()[0].getUConst(); + unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion() + ->getConstArray()[0].getUConst(); length = builder.createArrayLength(builder.accessChainGetLValue(), member); } @@ -2103,7 +2433,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI // Does it need a swizzle inversion? If so, evaluation is inverted; // operate first on the swizzle base, then apply the swizzle. spv::Id invertedType = spv::NoType; - auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); }; + auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? + invertedType : convertGlslangToSpvType(node->getType()); }; if (node->getOp() == glslang::EOpInterpolateAtCentroid) invertedType = getInvertedSwizzleType(*node->getOperand()); @@ -2124,10 +2455,23 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI if (node->getOp() == glslang::EOpAtomicCounterIncrement || node->getOp() == glslang::EOpAtomicCounterDecrement || node->getOp() == glslang::EOpAtomicCounter || - node->getOp() == glslang::EOpInterpolateAtCentroid) { + (node->getOp() == glslang::EOpInterpolateAtCentroid && + glslangIntermediate->getSource() != glslang::EShSourceHlsl) || + node->getOp() == glslang::EOpRayQueryProceed || + node->getOp() == glslang::EOpRayQueryGetRayTMin || + node->getOp() == glslang::EOpRayQueryGetRayFlags || + node->getOp() == glslang::EOpRayQueryGetWorldRayOrigin || + node->getOp() == glslang::EOpRayQueryGetWorldRayDirection || + node->getOp() == glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque || + node->getOp() == glslang::EOpRayQueryTerminate || + node->getOp() == glslang::EOpRayQueryConfirmIntersection || + (node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference())) { operand = builder.accessChainGetLValue(); // Special case l-value operands lvalueCoherentFlags = builder.getAccessChain().coherentFlags; lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType()); + } else if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) { + // Will be translated to a literal value, make a placeholder here + operand = spv::NoResult; } else #endif { @@ -2140,11 +2484,45 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI // it could be a conversion if (! result) - result = createConversion(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType()); + result = createConversion(node->getOp(), decorations, resultType(), operand, + node->getOperand()->getBasicType()); // if not, then possibly an operation if (! result) - result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType(), lvalueCoherentFlags); + result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, + node->getOperand()->getBasicType(), lvalueCoherentFlags); + +#ifndef GLSLANG_WEB + // it could be attached to a SPIR-V intruction + if (!result) { + if (node->getOp() == glslang::EOpSpirvInst) { + const auto& spirvInst = node->getSpirvInstruction(); + if (spirvInst.set == "") { + spv::IdImmediate idImmOp = {true, operand}; + if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) { + // Translate the constant to a literal value + std::vector literals; + glslang::TVector constants; + constants.push_back(operandNode->getAsConstantUnion()); + TranslateLiterals(constants, literals); + idImmOp = {false, literals[0]}; + } + + if (node->getBasicType() == glslang::EbtVoid) + builder.createNoResultOp(static_cast(spirvInst.id), {idImmOp}); + else + result = builder.createOp(static_cast(spirvInst.id), resultType(), {idImmOp}); + } else { + result = builder.createBuiltinCall( + resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()), + spirvInst.id, {operand}); + } + + if (node->getBasicType() == glslang::EbtVoid) + return false; // done with this node + } + } +#endif if (result) { if (invertedType) { @@ -2197,7 +2575,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI // The result of operation is always stored, but conditionally the // consumed result. The consumed result is always an r-value. - builder.accessChainStore(result); + builder.accessChainStore(result, + TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags)); builder.clearAccessChain(); if (node->getOp() == glslang::EOpPreIncrement || node->getOp() == glslang::EOpPreDecrement) @@ -2215,6 +2594,12 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI case glslang::EOpEndStreamPrimitive: builder.createNoResultOp(spv::OpEndStreamPrimitive, operand); return false; + case glslang::EOpRayQueryTerminate: + builder.createNoResultOp(spv::OpRayQueryTerminateKHR, operand); + return false; + case glslang::EOpRayQueryConfirmIntersection: + builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operand); + return false; #endif default: @@ -2237,7 +2622,8 @@ spv::Id TGlslangToSpvTraverser::createCompositeConstruct(spv::Id resultTypeId, s std::vector rTypeConstituents; int numrTypeConstituents = builder.getNumTypeConstituents(rType); for (int i = 0; i < numrTypeConstituents; ++i) { - rTypeConstituents.push_back(builder.createCompositeExtract(constituent, builder.getContainedTypeId(rType, i), i)); + rTypeConstituents.push_back(builder.createCompositeExtract(constituent, + builder.getContainedTypeId(rType, i), i)); } constituents[c] = createCompositeConstruct(lType, rTypeConstituents); } else { @@ -2263,8 +2649,14 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); spv::Id result = spv::NoResult; - spv::Id invertedType = spv::NoType; // to use to override the natural type of the node - auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); }; + spv::Id invertedType = spv::NoType; // to use to override the natural type of the node + std::vector complexLvalues; // for holding swizzling l-values too complex for + // SPIR-V, for an out parameter + std::vector temporaryLvalues; // temporaries to pass, as proxies for complexLValues + + auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? + invertedType : + convertGlslangToSpvType(node->getType()); }; // try texturing result = createImageTextureFunctionCall(node); @@ -2313,6 +2705,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt // anything else gets there, so visit out of order, doing them all now. makeGlobalInitializers(node->getAsAggregate()->getSequence()); + //Pre process linker objects for ray tracing stages + if (glslangIntermediate->isRayTracingStage()) + collectRayTracingLinkerObjects(); + // Initializers are done, don't want to visit again, but functions and link objects need to be processed, // so do them manually. visitFunctions(node->getAsAggregate()->getSequence()); @@ -2368,7 +2764,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt builder.setLine(node->getLoc().line, node->getLoc().getFilename()); if (node->isUserDefined()) result = handleUserFunctionCall(node); - // assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done if (result) { builder.clearAccessChain(); builder.setAccessChainRValue(result); @@ -2504,6 +2899,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt else constructed = builder.createConstructor(precision, arguments, resultType()); + if (node->getType().getQualifier().isNonUniform()) { + builder.addDecoration(constructed, spv::DecorationNonUniformEXT); + } + builder.clearAccessChain(); builder.setAccessChainRValue(constructed); @@ -2576,6 +2975,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case glslang::EOpAtomicAdd: + case glslang::EOpAtomicSubtract: case glslang::EOpAtomicMin: case glslang::EOpAtomicMax: case glslang::EOpAtomicAnd: @@ -2622,10 +3022,43 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpIgnoreIntersectionNV: case glslang::EOpTerminateRayNV: case glslang::EOpTraceNV: + case glslang::EOpTraceRayMotionNV: + case glslang::EOpTraceKHR: case glslang::EOpExecuteCallableNV: + case glslang::EOpExecuteCallableKHR: case glslang::EOpWritePackedPrimitiveIndices4x8NV: noReturnValue = true; break; + case glslang::EOpRayQueryInitialize: + case glslang::EOpRayQueryTerminate: + case glslang::EOpRayQueryGenerateIntersection: + case glslang::EOpRayQueryConfirmIntersection: + builder.addExtension("SPV_KHR_ray_query"); + builder.addCapability(spv::CapabilityRayQueryKHR); + noReturnValue = true; + break; + case glslang::EOpRayQueryProceed: + case glslang::EOpRayQueryGetIntersectionType: + case glslang::EOpRayQueryGetRayTMin: + case glslang::EOpRayQueryGetRayFlags: + case glslang::EOpRayQueryGetIntersectionT: + case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex: + case glslang::EOpRayQueryGetIntersectionInstanceId: + case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset: + case glslang::EOpRayQueryGetIntersectionGeometryIndex: + case glslang::EOpRayQueryGetIntersectionPrimitiveIndex: + case glslang::EOpRayQueryGetIntersectionBarycentrics: + case glslang::EOpRayQueryGetIntersectionFrontFace: + case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque: + case glslang::EOpRayQueryGetIntersectionObjectRayDirection: + case glslang::EOpRayQueryGetIntersectionObjectRayOrigin: + case glslang::EOpRayQueryGetWorldRayDirection: + case glslang::EOpRayQueryGetWorldRayOrigin: + case glslang::EOpRayQueryGetIntersectionObjectToWorld: + case glslang::EOpRayQueryGetIntersectionWorldToObject: + builder.addExtension("SPV_KHR_ray_query"); + builder.addCapability(spv::CapabilityRayQueryKHR); + break; case glslang::EOpCooperativeMatrixLoad: case glslang::EOpCooperativeMatrixStore: noReturnValue = true; @@ -2637,6 +3070,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; #endif + case glslang::EOpDebugPrintf: + noReturnValue = true; + break; + default: break; } @@ -2688,7 +3125,30 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt lvalue = true; break; + case glslang::EOpRayQueryInitialize: + case glslang::EOpRayQueryTerminate: + case glslang::EOpRayQueryConfirmIntersection: + case glslang::EOpRayQueryProceed: + case glslang::EOpRayQueryGenerateIntersection: + case glslang::EOpRayQueryGetIntersectionType: + case glslang::EOpRayQueryGetIntersectionT: + case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex: + case glslang::EOpRayQueryGetIntersectionInstanceId: + case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset: + case glslang::EOpRayQueryGetIntersectionGeometryIndex: + case glslang::EOpRayQueryGetIntersectionPrimitiveIndex: + case glslang::EOpRayQueryGetIntersectionBarycentrics: + case glslang::EOpRayQueryGetIntersectionFrontFace: + case glslang::EOpRayQueryGetIntersectionObjectRayDirection: + case glslang::EOpRayQueryGetIntersectionObjectRayOrigin: + case glslang::EOpRayQueryGetIntersectionObjectToWorld: + case glslang::EOpRayQueryGetIntersectionWorldToObject: + if (arg == 0) + lvalue = true; + break; + case glslang::EOpAtomicAdd: + case glslang::EOpAtomicSubtract: case glslang::EOpAtomicMin: case glslang::EOpAtomicMax: case glslang::EOpAtomicAnd: @@ -2709,13 +3169,24 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpInterpolateAtOffset: case glslang::EOpInterpolateAtVertex: if (arg == 0) { - lvalue = true; + // If GLSL, use the address of the interpolant argument. + // If HLSL, use an internal version of OpInterolates that takes + // the rvalue of the interpolant. A fixup pass in spirv-opt + // legalization will remove the OpLoad and convert to an lvalue. + // Had to do this because legalization will only propagate a + // builtin into an rvalue. + lvalue = glslangIntermediate->getSource() != glslang::EShSourceHlsl; // Does it need a swizzle inversion? If so, evaluation is inverted; // operate first on the swizzle base, then apply the swizzle. + // That is, we transform + // + // interpolate(v.zy) -> interpolate(v).zy + // if (glslangOperands[0]->getAsOperator() && glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle) - invertedType = convertGlslangToSpvType(glslangOperands[0]->getAsBinaryNode()->getLeft()->getType()); + invertedType = convertGlslangToSpvType( + glslangOperands[0]->getAsBinaryNode()->getLeft()->getType()); } break; case glslang::EOpAtomicLoad: @@ -2750,6 +3221,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt if (arg == 1) lvalue = true; break; + case glslang::EOpSpirvInst: + if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvByReference()) + lvalue = true; + break; #endif default: break; @@ -2775,8 +3250,9 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt builder.setAccessChain(save); // Point to the first element of the array. - builder.accessChainPush(elementId, TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()), - glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment()); + builder.accessChainPush(elementId, + TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()), + glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment()); spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags; unsigned int alignment = builder.getAccessChain().alignment; @@ -2786,7 +3262,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask; if (node->getOp() == glslang::EOpCooperativeMatrixStore) memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask; - if (builder.getStorageClass(builder.getAccessChain().base) == spv::StorageClassPhysicalStorageBufferEXT) { + if (builder.getStorageClass(builder.getAccessChain().base) == + spv::StorageClassPhysicalStorageBufferEXT) { memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); } @@ -2796,8 +3273,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt memoryAccessOperands.push_back(spv::IdImmediate(false, alignment)); } - if (memoryAccess & (spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask)) { - memoryAccessOperands.push_back(spv::IdImmediate(true, builder.makeUintConstant(TranslateMemoryScope(coherentFlags)))); + if (memoryAccess & + (spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask)) { + memoryAccessOperands.push_back(spv::IdImmediate(true, + builder.makeUintConstant(TranslateMemoryScope(coherentFlags)))); } } else if (arg == 2) { continue; @@ -2805,13 +3284,62 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt } #endif + // for l-values, pass the address, for r-values, pass the value if (lvalue) { - operands.push_back(builder.accessChainGetLValue()); + if (invertedType == spv::NoType && !builder.isSpvLvalue()) { + // SPIR-V cannot represent an l-value containing a swizzle that doesn't + // reduce to a simple access chain. So, we need a temporary vector to + // receive the result, and must later swizzle that into the original + // l-value. + complexLvalues.push_back(builder.getAccessChain()); + temporaryLvalues.push_back(builder.createVariable( + spv::NoPrecision, spv::StorageClassFunction, + builder.accessChainGetInferredType(), "swizzleTemp")); + operands.push_back(temporaryLvalues.back()); + } else { + operands.push_back(builder.accessChainGetLValue()); + } lvalueCoherentFlags = builder.getAccessChain().coherentFlags; lvalueCoherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()); } else { builder.setLine(node->getLoc().line, node->getLoc().getFilename()); - operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType())); + glslang::TOperator glslangOp = node->getOp(); + if (arg == 1 && + (glslangOp == glslang::EOpRayQueryGetIntersectionType || + glslangOp == glslang::EOpRayQueryGetIntersectionT || + glslangOp == glslang::EOpRayQueryGetIntersectionInstanceCustomIndex || + glslangOp == glslang::EOpRayQueryGetIntersectionInstanceId || + glslangOp == glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset || + glslangOp == glslang::EOpRayQueryGetIntersectionGeometryIndex || + glslangOp == glslang::EOpRayQueryGetIntersectionPrimitiveIndex || + glslangOp == glslang::EOpRayQueryGetIntersectionBarycentrics || + glslangOp == glslang::EOpRayQueryGetIntersectionFrontFace || + glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayDirection || + glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayOrigin || + glslangOp == glslang::EOpRayQueryGetIntersectionObjectToWorld || + glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject + )) { + bool cond = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getBConst(); + operands.push_back(builder.makeIntConstant(cond ? 1 : 0)); + } else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR) || + (arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV) || + (arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR)) { + const int opdNum = glslangOp == glslang::EOpTraceKHR ? 10 : (glslangOp == glslang::EOpTraceRayMotionNV ? 11 : 1); + const int set = glslangOp == glslang::EOpExecuteCallableKHR ? 1 : 0; + + const int location = glslangOperands[opdNum]->getAsConstantUnion()->getConstArray()[0].getUConst(); + auto itNode = locationToSymbol[set].find(location); + visitSymbol(itNode->second); + spv::Id symId = getSymbolId(itNode->second); + operands.push_back(symId); +#ifndef GLSLANG_WEB + } else if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvLiteral()) { + // Will be translated to a literal value, make a placeholder here + operands.push_back(spv::NoResult); +#endif + } else { + operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType())); + } } } @@ -2847,7 +3375,44 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt #endif if (atomic) { // Handle all atomics - result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), lvalueCoherentFlags); + glslang::TBasicType typeProxy = (node->getOp() == glslang::EOpAtomicStore) + ? node->getSequence()[0]->getAsTyped()->getBasicType() : node->getBasicType(); + result = createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy, + lvalueCoherentFlags); +#ifndef GLSLANG_WEB + } else if (node->getOp() == glslang::EOpSpirvInst) { + const auto& spirvInst = node->getSpirvInstruction(); + if (spirvInst.set == "") { + std::vector idImmOps; + for (int i = 0; i < glslangOperands.size(); ++i) { + if (glslangOperands[i]->getAsTyped()->getQualifier().isSpirvLiteral()) { + // Translate the constant to a literal value + std::vector literals; + glslang::TVector constants; + constants.push_back(glslangOperands[i]->getAsConstantUnion()); + TranslateLiterals(constants, literals); + idImmOps.push_back({false, literals[0]}); + } else + idImmOps.push_back({true, operands[i]}); + } + + if (node->getBasicType() == glslang::EbtVoid) + builder.createNoResultOp(static_cast(spirvInst.id), idImmOps); + else + result = builder.createOp(static_cast(spirvInst.id), resultType(), idImmOps); + } else { + result = builder.createBuiltinCall( + resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()), + spirvInst.id, operands); + } + noReturnValue = node->getBasicType() == glslang::EbtVoid; +#endif + } else if (node->getOp() == glslang::EOpDebugPrintf) { + if (!nonSemanticDebugPrintf) { + nonSemanticDebugPrintf = builder.import("NonSemantic.DebugPrintf"); + } + result = builder.createBuiltinCall(builder.makeVoidType(), nonSemanticDebugPrintf, spv::NonSemanticDebugPrintfDebugPrintf, operands); + builder.addExtension(spv::E_SPV_KHR_non_semantic_info); } else { // Pass through to generic operations. switch (glslangOperands.size()) { @@ -2869,8 +3434,15 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType()); break; } - if (invertedType) + + if (invertedType != spv::NoResult) result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result); + + for (unsigned int i = 0; i < temporaryLvalues.size(); ++i) { + builder.setAccessChain(complexLvalues[i]); + builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision), + TranslateNonUniformDecoration(complexLvalues[i].coherentFlags)); + } } if (noReturnValue) @@ -2986,7 +3558,8 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang } else { // We need control flow to select the result. // TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path. - result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); + result = builder.createVariable(TranslatePrecisionDecoration(node->getType()), + spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); // Selection control: const spv::SelectionControlMask control = TranslateSelectionControl(*node); @@ -3011,8 +3584,10 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang // Execute the one side needed, as per the condition const auto executeOneSide = [&]() { // Always emit control flow. - if (node->getBasicType() != glslang::EbtVoid) - result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); + if (node->getBasicType() != glslang::EbtVoid) { + result = builder.createVariable(TranslatePrecisionDecoration(node->getType()), spv::StorageClassFunction, + convertGlslangToSpvType(node->getType())); + } // Selection control: const spv::SelectionControlMask control = TranslateSelectionControl(*node); @@ -3077,7 +3652,8 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T defaultSegment = (int)codeSegments.size(); else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) { valueIndexToSegment[caseValues.size()] = (int)codeSegments.size(); - caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst()); + caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion() + ->getConstArray()[0].getIConst()); } else codeSegments.push_back(child); } @@ -3090,7 +3666,8 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T // make the switch statement std::vector segmentBlocks; // returned, as the blocks allocated in the call - builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks); + builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, + segmentBlocks); // emit all the code in the segments breakForLoop.push(false); @@ -3110,6 +3687,11 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node) { +#ifndef GLSLANG_WEB + if (node->getQualifier().isSpirvLiteral()) + return; // Translated to a literal value, skip further processing +#endif + int nextConst = 0; spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false); @@ -3195,7 +3777,11 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T switch (node->getFlowOp()) { case glslang::EOpKill: - builder.makeDiscard(); + builder.makeStatementTerminator(spv::OpKill, "post-discard"); + break; + case glslang::EOpTerminateInvocation: + builder.addExtension(spv::E_SPV_KHR_terminate_invocation); + builder.makeStatementTerminator(spv::OpTerminateInvocation, "post-terminate-invocation"); break; case glslang::EOpBreak: if (breakForLoop.top()) @@ -3207,15 +3793,17 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T builder.createLoopContinue(); break; case glslang::EOpReturn: - if (node->getExpression()) { + if (node->getExpression() != nullptr) { const glslang::TType& glslangReturnType = node->getExpression()->getType(); spv::Id returnId = accessChainLoad(glslangReturnType); - if (builder.getTypeId(returnId) != currentFunction->getReturnType()) { + if (builder.getTypeId(returnId) != currentFunction->getReturnType() || + TranslatePrecisionDecoration(glslangReturnType) != currentFunction->getReturnPrecision()) { builder.clearAccessChain(); - spv::Id copyId = builder.createVariable(spv::StorageClassFunction, currentFunction->getReturnType()); + spv::Id copyId = builder.createVariable(currentFunction->getReturnPrecision(), + spv::StorageClassFunction, currentFunction->getReturnType()); builder.setAccessChainLValue(copyId); multiTypeStore(glslangReturnType, returnId); - returnId = builder.createLoad(copyId); + returnId = builder.createLoad(copyId, currentFunction->getReturnPrecision()); } builder.makeReturn(false, returnId); } else @@ -3230,6 +3818,12 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation); builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT); break; + case glslang::EOpTerminateRayKHR: + builder.makeStatementTerminator(spv::OpTerminateRayKHR, "post-terminateRayKHR"); + break; + case glslang::EOpIgnoreIntersectionKHR: + builder.makeStatementTerminator(spv::OpIgnoreIntersectionKHR, "post-ignoreIntersectionKHR"); + break; #endif default: @@ -3284,6 +3878,11 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* break; #endif default: + if (storageClass == spv::StorageClassWorkgroup && + node->getType().getBasicType() == glslang::EbtBlock) { + builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR); + break; + } if (node->getType().contains16BitFloat()) builder.addCapability(spv::CapabilityFloat16); if (node->getType().contains16BitInt()) @@ -3302,6 +3901,9 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* } else if (storageClass == spv::StorageClassStorageBuffer) { builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5); builder.addCapability(spv::CapabilityStorageBuffer8BitAccess); + } else if (storageClass == spv::StorageClassWorkgroup && + node->getType().getBasicType() == glslang::EbtBlock) { + builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR); } else { builder.addCapability(spv::CapabilityInt8); } @@ -3311,7 +3913,19 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* if (glslang::IsAnonymous(name)) name = ""; - return builder.createVariable(storageClass, spvType, name); + spv::Id initializer = spv::NoResult; + + if (node->getType().getQualifier().storage == glslang::EvqUniform && !node->getConstArray().empty()) { + int nextConst = 0; + initializer = createSpvConstantFromConstUnionArray(node->getType(), + node->getConstArray(), + nextConst, + false /* specConst */); + } else if (node->getType().getQualifier().isNullInit()) { + initializer = builder.makeNullConstant(spvType); + } + + return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer); } // Return type Id of the sampled type. @@ -3326,6 +3940,12 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch); builder.addCapability(spv::CapabilityFloat16ImageAMD); return builder.makeFloatType(16); + case glslang::EbtInt64: return builder.makeIntType(64); + builder.addExtension(spv::E_SPV_EXT_shader_image_int64); + builder.addCapability(spv::CapabilityFloat16ImageAMD); + case glslang::EbtUint64: return builder.makeUintType(64); + builder.addExtension(spv::E_SPV_EXT_shader_image_int64); + builder.addCapability(spv::CapabilityFloat16ImageAMD); #endif default: assert(0); @@ -3347,7 +3967,8 @@ spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyp // When inverting a swizzle with a parent op, this function // will apply the swizzle operation to a completed parent operation. -spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node, spv::Id parentResult) +spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node, + spv::Id parentResult) { std::vector swizzle; convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle); @@ -3430,8 +4051,37 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty builder.addCapability(spv::CapabilityAtomicStorage); spvType = builder.makeUintType(32); break; - case glslang::EbtAccStructNV: - spvType = builder.makeAccelerationStructureNVType(); + case glslang::EbtAccStruct: + switch (glslangIntermediate->getStage()) { + case EShLangRayGen: + case EShLangIntersect: + case EShLangAnyHit: + case EShLangClosestHit: + case EShLangMiss: + case EShLangCallable: + // these all should have the RayTracingNV/KHR capability already + break; + default: + { + auto& extensions = glslangIntermediate->getRequestedExtensions(); + if (extensions.find("GL_EXT_ray_query") != extensions.end()) { + builder.addExtension(spv::E_SPV_KHR_ray_query); + builder.addCapability(spv::CapabilityRayQueryKHR); + } + } + break; + } + spvType = builder.makeAccelerationStructureType(); + break; + case glslang::EbtRayQuery: + { + auto& extensions = glslangIntermediate->getRequestedExtensions(); + if (extensions.find("GL_EXT_ray_query") != extensions.end()) { + builder.addExtension(spv::E_SPV_KHR_ray_query); + builder.addCapability(spv::CapabilityRayQueryKHR); + } + spvType = builder.makeRayQueryType(); + } break; case glslang::EbtReference: { @@ -3483,10 +4133,84 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty // else, we haven't seen it... if (type.getBasicType() == glslang::EbtBlock) - memberRemapper[glslangMembers].resize(glslangMembers->size()); + memberRemapper[glslangTypeToIdMap[glslangMembers]].resize(glslangMembers->size()); spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier); } break; + case glslang::EbtString: + // no type used for OpString + return 0; +#ifndef GLSLANG_WEB + case glslang::EbtSpirvType: { + // GL_EXT_spirv_intrinsics + const auto& spirvType = type.getSpirvType(); + const auto& spirvInst = spirvType.spirvInst; + + std::vector operands; + for (const auto& typeParam : spirvType.typeParams) { + if (typeParam.isConstant) { + // Constant expression + if (typeParam.constant->isLiteral()) { + if (typeParam.constant->getBasicType() == glslang::EbtFloat) { + float floatValue = static_cast(typeParam.constant->getConstArray()[0].getDConst()); + unsigned literal = *reinterpret_cast(&floatValue); + operands.push_back(literal); + } else if (typeParam.constant->getBasicType() == glslang::EbtInt) { + unsigned literal = typeParam.constant->getConstArray()[0].getIConst(); + operands.push_back(literal); + } else if (typeParam.constant->getBasicType() == glslang::EbtUint) { + unsigned literal = typeParam.constant->getConstArray()[0].getUConst(); + operands.push_back(literal); + } else if (typeParam.constant->getBasicType() == glslang::EbtBool) { + unsigned literal = typeParam.constant->getConstArray()[0].getBConst(); + operands.push_back(literal); + } else if (typeParam.constant->getBasicType() == glslang::EbtString) { + auto str = typeParam.constant->getConstArray()[0].getSConst()->c_str(); + unsigned literal = 0; + char* literalPtr = reinterpret_cast(&literal); + unsigned charCount = 0; + char ch = 0; + do { + ch = *(str++); + *(literalPtr++) = ch; + ++charCount; + if (charCount == 4) { + operands.push_back(literal); + literalPtr = reinterpret_cast(&literal); + charCount = 0; + } + } while (ch != 0); + + // Partial literal is padded with 0 + if (charCount > 0) { + for (; charCount < 4; ++charCount) + *(literalPtr++) = 0; + operands.push_back(literal); + } + } else + assert(0); // Unexpected type + } else { + int nextConst = 0; + spv::Id constant = createSpvConstantFromConstUnionArray( + typeParam.constant->getType(), typeParam.constant->getConstArray(), nextConst, false); + operands.push_back(constant); + } + } else { + // Type specifier + spv::Id typeId = convertGlslangToSpvType(*typeParam.type); + operands.push_back(typeId); + } + } + + if (spirvInst.set == "") + spvType = builder.createOp(static_cast(spirvInst.id), spv::NoType, operands); + else { + spvType = builder.createBuiltinCall( + spv::NoType, getExtBuiltins(spirvInst.set.c_str()), spirvInst.id, operands); + } + break; + } +#endif default: assert(0); break; @@ -3612,22 +4336,23 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy { // Create a vector of struct types for SPIR-V to consume std::vector spvMembers; - int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks + int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, + // except sometimes for blocks std::vector > deferredForwardPointers; for (int i = 0; i < (int)glslangMembers->size(); i++) { glslang::TType& glslangMember = *(*glslangMembers)[i].type; if (glslangMember.hiddenMember()) { ++memberDelta; if (type.getBasicType() == glslang::EbtBlock) - memberRemapper[glslangMembers][i] = -1; + memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1; } else { if (type.getBasicType() == glslang::EbtBlock) { if (filterMember(glslangMember)) { memberDelta++; - memberRemapper[glslangMembers][i] = -1; + memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1; continue; } - memberRemapper[glslangMembers][i] = i - memberDelta; + memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = i - memberDelta; } // modify just this child's view of the qualifier glslang::TQualifier memberQualifier = glslangMember.getQualifier(); @@ -3648,10 +4373,12 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy deferredForwardPointers.push_back(std::make_pair(&glslangMember, memberQualifier)); } spvMembers.push_back( - convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, true)); + convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, + true)); } else { spvMembers.push_back( - convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, false)); + convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, + false)); } } } @@ -3680,12 +4407,13 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, { // Name and decorate the non-hidden members int offset = -1; - int locationOffset = 0; // for use within the members of this struct + bool memberLocationInvalid = type.isArrayOfArrays() || + (type.isArray() && (type.getQualifier().isArrayedIo(glslangIntermediate->getStage()) == false)); for (int i = 0; i < (int)glslangMembers->size(); i++) { glslang::TType& glslangMember = *(*glslangMembers)[i].type; int member = i; if (type.getBasicType() == glslang::EbtBlock) { - member = memberRemapper[glslangMembers][i]; + member = memberRemapper[glslangTypeToIdMap[glslangMembers]][i]; if (filterMember(glslangMember)) continue; } @@ -3733,13 +4461,9 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, // just track whether a member needs to be decorated. // Ignore member locations if the container is an array, as that's // ill-specified and decisions have been made to not allow this. - if (! type.isArray() && memberQualifier.hasLocation()) + if (!memberLocationInvalid && memberQualifier.hasLocation()) builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation); - if (qualifier.hasLocation()) // track for upcoming inheritance - locationOffset += glslangIntermediate->computeTypeLocationSize( - glslangMember, glslangIntermediate->getStage()); - // component, XFB, others if (glslangMember.getQualifier().hasComponent()) builder.addMemberDecoration(spvType, member, spv::DecorationComponent, @@ -3795,6 +4519,38 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV); builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough); } + + // + // Add SPIR-V decorations for members (GL_EXT_spirv_intrinsics) + // + if (glslangMember.getQualifier().hasSprivDecorate()) { + const glslang::TSpirvDecorate& spirvDecorate = glslangMember.getQualifier().getSpirvDecorate(); + + // Add spirv_decorate + for (auto& decorate : spirvDecorate.decorates) { + if (!decorate.second.empty()) { + std::vector literals; + TranslateLiterals(decorate.second, literals); + builder.addMemberDecoration(spvType, member, static_cast(decorate.first), literals); + } + else + builder.addMemberDecoration(spvType, member, static_cast(decorate.first)); + } + + // spirv_decorate_id not applied to members + assert(spirvDecorate.decorateIds.empty()); + + // Add spirv_decorate_string + for (auto& decorateString : spirvDecorate.decorateStrings) { + std::vector strings; + assert(!decorateString.second.empty()); + for (auto extraOperand : decorateString.second) { + const char* string = extraOperand->getConstArray()[0].getSConst()->c_str(); + strings.push_back(string); + } + builder.addDecoration(spvType, static_cast(decorateString.first), strings); + } + } #endif } @@ -3813,6 +4569,8 @@ spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arra glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim); if (specNode != nullptr) { builder.clearAccessChain(); + SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); + spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); specNode->traverse(this); return accessChainLoad(specNode->getAsTyped()->getType()); } @@ -3839,26 +4597,16 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type) alignment |= type.getBufferReferenceAlignment(); spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type), - TranslateNonUniformDecoration(type.getQualifier()), - nominalTypeId, - spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask), - TranslateMemoryScope(coherentFlags), - alignment); + TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags), + TranslateNonUniformDecoration(type.getQualifier()), + nominalTypeId, + spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask), + TranslateMemoryScope(coherentFlags), + alignment); // Need to convert to abstract types when necessary if (type.getBasicType() == glslang::EbtBool) { - if (builder.isScalarType(nominalTypeId)) { - // Conversion for bool - spv::Id boolType = builder.makeBoolType(); - if (nominalTypeId != boolType) - loadedId = builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0)); - } else if (builder.isVectorType(nominalTypeId)) { - // Conversion for bvec - int vecSize = builder.getNumTypeComponents(nominalTypeId); - spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize); - if (nominalTypeId != bvecType) - loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId, makeSmearedConstant(builder.makeUintConstant(0), vecSize)); - } + loadedId = convertLoadedBoolInUniformToUint(type, nominalTypeId, loadedId); } return loadedId; @@ -3905,8 +4653,9 @@ void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::I unsigned int alignment = builder.getAccessChain().alignment; alignment |= type.getBufferReferenceAlignment(); - builder.accessChainStore(rvalue, - spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerVisibleKHRMask), + builder.accessChainStore(rvalue, TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags), + spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & + ~spv::MemoryAccessMakePointerVisibleKHRMask), TranslateMemoryScope(coherentFlags), alignment); } @@ -3967,7 +4716,8 @@ void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id // set up the target storage builder.clearAccessChain(); builder.setAccessChainLValue(lValue); - builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type), type.getBufferReferenceAlignment()); + builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type), + type.getBufferReferenceAlignment()); // store the member multiTypeStore(glslangElementType, elementRValue); @@ -3987,7 +4737,8 @@ void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id // set up the target storage builder.clearAccessChain(); builder.setAccessChainLValue(lValue); - builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type), type.getBufferReferenceAlignment()); + builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type), + type.getBufferReferenceAlignment()); // store the member multiTypeStore(glslangMemberType, memberRValue); @@ -4007,6 +4758,7 @@ glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang: // has to be a uniform or buffer block or task in/out blocks if (type.getQualifier().storage != glslang::EvqUniform && type.getQualifier().storage != glslang::EvqBuffer && + type.getQualifier().storage != glslang::EvqShared && !type.getQualifier().isTaskMemory()) return glslang::ElpNone; @@ -4022,18 +4774,21 @@ glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang: } // Given an array type, returns the integer stride required for that array -int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) +int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout, + glslang::TLayoutMatrix matrixLayout) { int size; int stride; - glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor); + glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout, + matrixLayout == glslang::ElmRowMajor); return stride; } // Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix // when used as a member of an interface block -int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) +int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout, + glslang::TLayoutMatrix matrixLayout) { glslang::TType elementType; elementType.shallowCopy(matrixType); @@ -4041,7 +4796,8 @@ int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, gl int size; int stride; - glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor); + glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout, + matrixLayout == glslang::ElmRowMajor); return stride; } @@ -4052,8 +4808,8 @@ int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, gl // 'currentOffset' should be passed in already initialized, ready to modify, and reflecting // the migration of data from nextOffset -> currentOffset. It should be -1 on the first call. // -1 means a non-forced member offset (no decoration needed). -void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, - glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) +void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, + int& currentOffset, int& nextOffset, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) { // this will get a positive value when deemed necessary nextOffset = -1; @@ -4083,7 +4839,8 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType int memberSize; int dummyStride; - int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout, matrixLayout == glslang::ElmRowMajor); + int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout, + matrixLayout == glslang::ElmRowMajor); // Adjust alignment for HLSL rules // TODO: make this consistent in early phases of code: @@ -4102,7 +4859,8 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType glslang::RoundToPow2(currentOffset, memberAlignment); // Bump up to vec4 if there is a bad straddle - if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize, currentOffset)) + if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize, + currentOffset)) glslang::RoundToPow2(currentOffset, 16); nextOffset = currentOffset + memberSize; @@ -4155,8 +4913,10 @@ bool TGlslangToSpvTraverser::writableParam(glslang::TStorageQualifier qualifier) assert(qualifier == glslang::EvqIn || qualifier == glslang::EvqOut || qualifier == glslang::EvqInOut || + qualifier == glslang::EvqUniform || qualifier == glslang::EvqConstReadOnly); - return qualifier != glslang::EvqConstReadOnly; + return qualifier != glslang::EvqConstReadOnly && + qualifier != glslang::EvqUniform; } // Is parameter pass-by-original? @@ -4168,13 +4928,17 @@ bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) return paramType.getBasicType() == glslang::EbtBlock; return paramType.containsOpaque() || // sampler, etc. +#ifndef GLSLANG_WEB + paramType.getQualifier().isSpirvByReference() || // spirv_by_reference +#endif (paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO } // Make all the functions, skeletally, without actually visiting their bodies. void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions) { - const auto getParamDecorations = [&](std::vector& decorations, const glslang::TType& type, bool useVulkanMemoryModel) { + const auto getParamDecorations = [&](std::vector& decorations, const glslang::TType& type, + bool useVulkanMemoryModel) { spv::Decoration paramPrecision = TranslatePrecisionDecoration(type); if (paramPrecision != spv::NoPrecision) decorations.push_back(paramPrecision); @@ -4272,7 +5036,8 @@ void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequen builder.setBuildPoint(shaderEntry->getLastBlock()); for (int i = 0; i < (int)initializers.size(); ++i) { glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate(); - if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) { + if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != + glslang::EOpLinkerObjects) { // We're on a top-level node that's not a function. Treat as an initializer, whose // code goes into the beginning of the entry point. @@ -4280,7 +5045,39 @@ void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequen } } } +// Walk over all linker objects to create a map for payload and callable data linker objects +// and their location to be used during codegen for OpTraceKHR and OpExecuteCallableKHR +// This is done here since it is possible that these linker objects are not be referenced in the AST +void TGlslangToSpvTraverser::collectRayTracingLinkerObjects() +{ + glslang::TIntermAggregate* linkerObjects = glslangIntermediate->findLinkerObjects(); + for (auto& objSeq : linkerObjects->getSequence()) { + auto objNode = objSeq->getAsSymbolNode(); + if (objNode != nullptr) { + if (objNode->getQualifier().hasLocation()) { + unsigned int location = objNode->getQualifier().layoutLocation; + auto st = objNode->getQualifier().storage; + int set; + switch (st) + { + case glslang::EvqPayload: + case glslang::EvqPayloadIn: + set = 0; + break; + case glslang::EvqCallableData: + case glslang::EvqCallableDataIn: + set = 1; + break; + default: + set = -1; + } + if (set != -1) + locationToSymbol[set].insert(std::make_pair(location, objNode)); + } + } + } +} // Process all the functions, while skipping initializers. void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions) { @@ -4300,7 +5097,8 @@ void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate builder.setBuildPoint(functionBlock); } -void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector& arguments, spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) +void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector& arguments, + spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) { const glslang::TIntermSequence& glslangArguments = node.getSequence(); @@ -4313,7 +5111,8 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& sampler = glslangArguments[0]->getAsTyped()->getType().getSampler(); cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow; #ifndef GLSLANG_WEB - f16ShadowCompare = sampler.shadow && glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16; + f16ShadowCompare = sampler.shadow && + glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16; #endif } @@ -4422,8 +5221,10 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& } if (lvalue) { - arguments.push_back(builder.accessChainGetLValue()); + spv::Id lvalue_id = builder.accessChainGetLValue(); + arguments.push_back(lvalue_id); lvalueCoherentFlags = builder.getAccessChain().coherentFlags; + builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags)); lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType()); } else #endif @@ -4476,7 +5277,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO translateArguments(*node->getAsAggregate(), arguments, lvalueCoherentFlags); else translateArguments(*node->getAsUnaryNode(), arguments); - spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision()); + spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); spv::Builder::TextureParameters params = { }; params.sampler = arguments[0]; @@ -4486,12 +5287,15 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO const bool isUnsignedResult = node->getType().getBasicType() == glslang::EbtUint; + if (builder.isSampledImage(params.sampler) && + ((cracked.query && node->getOp() != glslang::EOpTextureQueryLod) || cracked.fragMask || cracked.fetch)) { + params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); + if (imageType.getQualifier().isNonUniform()) { + builder.addDecoration(params.sampler, spv::DecorationNonUniformEXT); + } + } // Check for queries if (cracked.query) { - // OpImageQueryLod works on a sampled image, for other queries the image has to be extracted first - if (node->getOp() != glslang::EOpTextureQueryLod && builder.isSampledImage(params.sampler)) - params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); - switch (node->getOp()) { case glslang::EOpImageQuerySize: case glslang::EOpTextureQuerySize: @@ -4520,7 +5324,10 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO int components = node->getType().getVectorSize(); - if (node->getOp() == glslang::EOpTextureFetch) { + if (node->getOp() == glslang::EOpImageLoad || + node->getOp() == glslang::EOpImageLoadLod || + node->getOp() == glslang::EOpTextureFetch || + node->getOp() == glslang::EOpTextureFetchOffset) { // These must produce 4 components, per SPIR-V spec. We'll add a conversion constructor if needed. // This will only happen through the HLSL path for operator[], so we do not have to handle e.g. // the EOpTexture/Proj/Lod/etc family. It would be harmless to do so, but would need more logic @@ -4689,7 +5496,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO operands.push_back(imageOperand); } if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) { - spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) }; + spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope( + TranslateCoherent(imageType))) }; operands.push_back(imageOperand); } @@ -4717,18 +5525,22 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO // imageAtomicStore has a void return type so base the pointer type on // the type of the value operand. if (node->getOp() == glslang::EOpImageAtomicStore) { - resultTypeId = builder.makePointer(spv::StorageClassImage, builder.getTypeId(operands[2].word)); + resultTypeId = builder.makePointer(spv::StorageClassImage, builder.getTypeId(*opIt)); } else { resultTypeId = builder.makePointer(spv::StorageClassImage, resultType()); } spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands); + if (imageType.getQualifier().nonUniform) { + builder.addDecoration(pointer, spv::DecorationNonUniformEXT); + } std::vector operands; operands.push_back(pointer); for (; opIt != arguments.end(); ++opIt) operands.push_back(*opIt); - return createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), lvalueCoherentFlags); + return createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), + lvalueCoherentFlags); } } @@ -4740,10 +5552,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO auto opIt = arguments.begin(); std::vector operands; - // Extract the image if necessary - if (builder.isSampledImage(params.sampler)) - params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); - operands.push_back(params.sampler); ++opIt; @@ -4753,7 +5561,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO std::vector comps; comps.push_back(zero); comps.push_back(zero); - operands.push_back(builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps)); + operands.push_back(builder.makeCompositeConstant( + builder.makeVectorType(builder.makeIntType(32), 2), comps)); } for (; opIt != arguments.end(); ++opIt) @@ -4803,13 +5612,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO bias = true; } - // See if the sampler param should really be just the SPV image part - if (cracked.fetch) { - // a fetch needs to have the image extracted first - if (builder.isSampledImage(params.sampler)) - params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); - } - #ifndef GLSLANG_WEB if (cracked.gather) { const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions(); @@ -4842,7 +5644,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO else dRefComp = builder.getNumComponents(params.coords) - 1; indexes.push_back(dRefComp); - params.Dref = builder.createCompositeExtract(params.coords, builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes); + params.Dref = builder.createCompositeExtract(params.coords, + builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes); } // lod @@ -4967,7 +5770,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO flags.clear(); builder.accessChainPush(builder.makeIntConstant(i), flags, 0); - builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1), i+1)); + builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1), + i+1), TranslateNonUniformDecoration(imageType.getQualifier())); } return builder.createCompositeExtract(res, resultType(), 0); } @@ -4990,10 +5794,9 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO // copy the projective coordinate if we have to if (projTargetComp != projSourceComp) { spv::Id projComp = builder.createCompositeExtract(params.coords, - builder.getScalarTypeId(builder.getTypeId(params.coords)), - projSourceComp); + builder.getScalarTypeId(builder.getTypeId(params.coords)), projSourceComp); params.coords = builder.createCompositeInsert(projComp, params.coords, - builder.getTypeId(params.coords), projTargetComp); + builder.getTypeId(params.coords), projTargetComp); } } @@ -5073,7 +5876,8 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg ++lValueCount; } else if (writableParam(qualifiers[a])) { // need space to hold the copy - arg = builder.createVariable(spv::StorageClassFunction, builder.getContainedTypeId(function->getParamType(a)), "param"); + arg = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction, + builder.getContainedTypeId(function->getParamType(a)), "param"); if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) { // need to copy the input into output space builder.setAccessChain(lValues[lValueCount]); @@ -5085,12 +5889,14 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg ++lValueCount; } else { // process r-value, which involves a copy for a type mismatch - if (function->getParamType(a) != convertGlslangToSpvType(*argTypes[a])) { - spv::Id argCopy = builder.createVariable(spv::StorageClassFunction, function->getParamType(a), "arg"); + if (function->getParamType(a) != builder.getTypeId(rValues[rValueCount]) || + TranslatePrecisionDecoration(*argTypes[a]) != function->getParamPrecision(a)) + { + spv::Id argCopy = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction, function->getParamType(a), "arg"); builder.clearAccessChain(); builder.setAccessChainLValue(argCopy); multiTypeStore(*argTypes[a], rValues[rValueCount]); - arg = builder.createLoad(argCopy); + arg = builder.createLoad(argCopy, function->getParamPrecision(a)); } else arg = rValues[rValueCount]; ++rValueCount; @@ -5101,6 +5907,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg // 3. Make the call. spv::Id result = builder.createFunctionCall(function, spvArgs); builder.setPrecision(result, TranslatePrecisionDecoration(node->getType())); + builder.addDecoration(result, TranslateNonUniformDecoration(node->getType().getQualifier())); // 4. Copy back out an "out" arguments. lValueCount = 0; @@ -5109,7 +5916,8 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg ++lValueCount; else if (writableParam(qualifiers[a])) { if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) { - spv::Id copy = builder.createLoad(spvArgs[a]); + spv::Id copy = builder.createLoad(spvArgs[a], spv::NoPrecision); + builder.addDecoration(copy, TranslateNonUniformDecoration(argTypes[a]->getQualifier())); builder.setAccessChain(lValues[lValueCount]); multiTypeStore(*argTypes[a], copy); } @@ -5354,7 +6162,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, OpD case glslang::EOpNotEqual: case glslang::EOpVectorNotEqual: if (isFloat) - binOp = spv::OpFOrdNotEqual; + binOp = spv::OpFUnordNotEqual; else if (isBool) binOp = spv::OpLogicalNotEqual; else @@ -5488,7 +6296,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecora } spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId, - spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) + spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) { spv::Op unaryOp = spv::OpNop; int extBuiltins = -1; @@ -5749,6 +6557,24 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe case glslang::EOpFwidthCoarse: unaryOp = spv::OpFwidthCoarse; break; + case glslang::EOpRayQueryProceed: + unaryOp = spv::OpRayQueryProceedKHR; + break; + case glslang::EOpRayQueryGetRayTMin: + unaryOp = spv::OpRayQueryGetRayTMinKHR; + break; + case glslang::EOpRayQueryGetRayFlags: + unaryOp = spv::OpRayQueryGetRayFlagsKHR; + break; + case glslang::EOpRayQueryGetWorldRayOrigin: + unaryOp = spv::OpRayQueryGetWorldRayOriginKHR; + break; + case glslang::EOpRayQueryGetWorldRayDirection: + unaryOp = spv::OpRayQueryGetWorldRayDirectionKHR; + break; + case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque: + unaryOp = spv::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR; + break; case glslang::EOpInterpolateAtCentroid: if (typeProxy == glslang::EbtFloat16) builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float); @@ -5879,6 +6705,11 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe case glslang::EOpConstructReference: unaryOp = spv::OpBitcast; break; + + case glslang::EOpConvUint64ToAccStruct: + case glslang::EOpConvUvec2ToAccStruct: + unaryOp = spv::OpConvertUToAccelerationStructureKHR; + break; #endif case glslang::EOpCopyObject: @@ -6034,7 +6865,7 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora case glslang::EOpConvFloatToBool: zero = builder.makeFloatConstant(0.0F); zero = makeSmearedConstant(zero, vectorSize); - return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero); + return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero); case glslang::EOpConvBoolToFloat: convOp = spv::OpSelect; zero = builder.makeFloatConstant(0.0F); @@ -6183,11 +7014,11 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora case glslang::EOpConvDoubleToBool: zero = builder.makeDoubleConstant(0.0); zero = makeSmearedConstant(zero, vectorSize); - return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero); + return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero); case glslang::EOpConvFloat16ToBool: zero = builder.makeFloat16Constant(0.0F); zero = makeSmearedConstant(zero, vectorSize); - return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero); + return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero); case glslang::EOpConvBoolToDouble: convOp = spv::OpSelect; zero = builder.makeDoubleConstant(0.0); @@ -6341,9 +7172,6 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora break; case glslang::EOpConvPtrToUvec2: case glslang::EOpConvUvec2ToPtr: - if (builder.isVector(operand)) - builder.promoteIncorporatedExtension(spv::E_SPV_EXT_physical_storage_buffer, - spv::E_SPV_KHR_physical_storage_buffer, spv::Spv_1_5); convOp = spv::OpBitcast; break; #endif @@ -6381,7 +7209,9 @@ spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vector } // For glslang ops that map to SPV atomic opCodes -spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) +spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/, + spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy, + const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) { spv::Op opCode = spv::OpNop; @@ -6390,19 +7220,58 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv case glslang::EOpImageAtomicAdd: case glslang::EOpAtomicCounterAdd: opCode = spv::OpAtomicIAdd; + if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { + opCode = spv::OpAtomicFAddEXT; + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_add); + if (typeProxy == glslang::EbtFloat16) { + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float16_add); + builder.addCapability(spv::CapabilityAtomicFloat16AddEXT); + } else if (typeProxy == glslang::EbtFloat) { + builder.addCapability(spv::CapabilityAtomicFloat32AddEXT); + } else { + builder.addCapability(spv::CapabilityAtomicFloat64AddEXT); + } + } break; + case glslang::EOpAtomicSubtract: case glslang::EOpAtomicCounterSubtract: opCode = spv::OpAtomicISub; break; case glslang::EOpAtomicMin: case glslang::EOpImageAtomicMin: case glslang::EOpAtomicCounterMin: - opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? spv::OpAtomicUMin : spv::OpAtomicSMin; + if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { + opCode = spv::OpAtomicFMinEXT; + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max); + if (typeProxy == glslang::EbtFloat16) + builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT); + else if (typeProxy == glslang::EbtFloat) + builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT); + else + builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT); + } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) { + opCode = spv::OpAtomicUMin; + } else { + opCode = spv::OpAtomicSMin; + } break; case glslang::EOpAtomicMax: case glslang::EOpImageAtomicMax: case glslang::EOpAtomicCounterMax: - opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? spv::OpAtomicUMax : spv::OpAtomicSMax; + if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { + opCode = spv::OpAtomicFMaxEXT; + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max); + if (typeProxy == glslang::EbtFloat16) + builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT); + else if (typeProxy == glslang::EbtFloat) + builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT); + else + builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT); + } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) { + opCode = spv::OpAtomicUMax; + } else { + opCode = spv::OpAtomicSMax; + } break; case glslang::EOpAtomicAnd: case glslang::EOpImageAtomicAnd: @@ -6467,7 +7336,8 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv scopeId = builder.makeUintConstant(spv::ScopeDevice); } // semantics default to relaxed - spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() && glslangIntermediate->usingVulkanMemoryModel() ? + spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() && + glslangIntermediate->usingVulkanMemoryModel() ? spv::MemorySemanticsVolatileMask : spv::MemorySemanticsMaskNone); spv::Id semanticsId2 = semanticsId; @@ -6480,20 +7350,24 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv valueId = operands[2]; if (operands.size() > 3) { scopeId = operands[3]; - semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5])); - semanticsId2 = builder.makeUintConstant(builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7])); + semanticsId = builder.makeUintConstant( + builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5])); + semanticsId2 = builder.makeUintConstant( + builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7])); } } else if (opCode == spv::OpAtomicLoad) { if (operands.size() > 1) { scopeId = operands[1]; - semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3])); + semanticsId = builder.makeUintConstant( + builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3])); } } else { // atomic store or RMW valueId = operands[1]; if (operands.size() > 2) { scopeId = operands[2]; - semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4])); + semanticsId = builder.makeUintConstant + (builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4])); } } @@ -6506,6 +7380,10 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); } + if (builder.getConstantScalar(scopeId) == spv::ScopeQueueFamily) { + builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); + } + if (glslangIntermediate->usingVulkanMemoryModel() && builder.getConstantScalar(scopeId) == spv::ScopeDevice) { builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR); } @@ -6538,7 +7416,8 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv } // Create group invocation operations. -spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy) +spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, + std::vector& operands, glslang::TBasicType typeProxy) { bool isUnsigned = isTypeUnsignedInt(typeProxy); bool isFloat = isTypeFloat(typeProxy); @@ -6752,8 +7631,10 @@ spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax || op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast || op == spv::OpSubgroupReadInvocationKHR || - op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD || op == spv::OpGroupSMinNonUniformAMD || - op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD || op == spv::OpGroupSMaxNonUniformAMD || + op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD || + op == spv::OpGroupSMinNonUniformAMD || + op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD || + op == spv::OpGroupSMaxNonUniformAMD || op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD); // Handle group invocation operations scalar by scalar. @@ -7142,7 +8023,8 @@ spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, s return builder.createOp(opCode, typeId, spvGroupOperands); } -spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy) +spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, + spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy) { bool isUnsigned = isTypeUnsignedInt(typeProxy); bool isFloat = isTypeFloat(typeProxy); @@ -7244,14 +8126,16 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: unsigned int executionScope = builder.getConstantScalar(operands[0]); unsigned int memoryScope = builder.getConstantScalar(operands[1]); unsigned int semantics = builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]); - builder.createControlBarrier((spv::Scope)executionScope, (spv::Scope)memoryScope, (spv::MemorySemanticsMask)semantics); + builder.createControlBarrier((spv::Scope)executionScope, (spv::Scope)memoryScope, + (spv::MemorySemanticsMask)semantics); if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask | spv::MemorySemanticsMakeVisibleKHRMask | spv::MemorySemanticsOutputMemoryKHRMask | spv::MemorySemanticsVolatileMask)) { builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); } - if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::ScopeDevice || memoryScope == spv::ScopeDevice)) { + if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::ScopeDevice || + memoryScope == spv::ScopeDevice)) { builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR); } return 0; @@ -7334,7 +8218,8 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: if (builder.getNumComponents(operands[0]) == 1) frexpIntType = builder.makeIntegerType(width, true); else - frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true), builder.getNumComponents(operands[0])); + frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true), + builder.getNumComponents(operands[0])); typeId = builder.makeStructResultType(typeId0, frexpIntType); consumedOperands = 1; } @@ -7437,24 +8322,116 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: libCall = spv::InterpolateAtVertexAMD; break; - case glslang::EOpReportIntersectionNV: - { + case glslang::EOpReportIntersection: typeId = builder.makeBoolType(); - opCode = spv::OpReportIntersectionNV; - } - break; + opCode = spv::OpReportIntersectionKHR; + break; case glslang::EOpTraceNV: - { builder.createNoResultOp(spv::OpTraceNV, operands); return 0; - } - break; + case glslang::EOpTraceRayMotionNV: + builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur); + builder.addCapability(spv::CapabilityRayTracingMotionBlurNV); + builder.createNoResultOp(spv::OpTraceRayMotionNV, operands); + return 0; + case glslang::EOpTraceKHR: + builder.createNoResultOp(spv::OpTraceRayKHR, operands); + return 0; case glslang::EOpExecuteCallableNV: - { builder.createNoResultOp(spv::OpExecuteCallableNV, operands); return 0; - } - break; + case glslang::EOpExecuteCallableKHR: + builder.createNoResultOp(spv::OpExecuteCallableKHR, operands); + return 0; + + case glslang::EOpRayQueryInitialize: + builder.createNoResultOp(spv::OpRayQueryInitializeKHR, operands); + return 0; + case glslang::EOpRayQueryTerminate: + builder.createNoResultOp(spv::OpRayQueryTerminateKHR, operands); + return 0; + case glslang::EOpRayQueryGenerateIntersection: + builder.createNoResultOp(spv::OpRayQueryGenerateIntersectionKHR, operands); + return 0; + case glslang::EOpRayQueryConfirmIntersection: + builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operands); + return 0; + case glslang::EOpRayQueryProceed: + typeId = builder.makeBoolType(); + opCode = spv::OpRayQueryProceedKHR; + break; + case glslang::EOpRayQueryGetIntersectionType: + typeId = builder.makeUintType(32); + opCode = spv::OpRayQueryGetIntersectionTypeKHR; + break; + case glslang::EOpRayQueryGetRayTMin: + typeId = builder.makeFloatType(32); + opCode = spv::OpRayQueryGetRayTMinKHR; + break; + case glslang::EOpRayQueryGetRayFlags: + typeId = builder.makeIntType(32); + opCode = spv::OpRayQueryGetRayFlagsKHR; + break; + case glslang::EOpRayQueryGetIntersectionT: + typeId = builder.makeFloatType(32); + opCode = spv::OpRayQueryGetIntersectionTKHR; + break; + case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex: + typeId = builder.makeIntType(32); + opCode = spv::OpRayQueryGetIntersectionInstanceCustomIndexKHR; + break; + case glslang::EOpRayQueryGetIntersectionInstanceId: + typeId = builder.makeIntType(32); + opCode = spv::OpRayQueryGetIntersectionInstanceIdKHR; + break; + case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset: + typeId = builder.makeUintType(32); + opCode = spv::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR; + break; + case glslang::EOpRayQueryGetIntersectionGeometryIndex: + typeId = builder.makeIntType(32); + opCode = spv::OpRayQueryGetIntersectionGeometryIndexKHR; + break; + case glslang::EOpRayQueryGetIntersectionPrimitiveIndex: + typeId = builder.makeIntType(32); + opCode = spv::OpRayQueryGetIntersectionPrimitiveIndexKHR; + break; + case glslang::EOpRayQueryGetIntersectionBarycentrics: + typeId = builder.makeVectorType(builder.makeFloatType(32), 2); + opCode = spv::OpRayQueryGetIntersectionBarycentricsKHR; + break; + case glslang::EOpRayQueryGetIntersectionFrontFace: + typeId = builder.makeBoolType(); + opCode = spv::OpRayQueryGetIntersectionFrontFaceKHR; + break; + case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque: + typeId = builder.makeBoolType(); + opCode = spv::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR; + break; + case glslang::EOpRayQueryGetIntersectionObjectRayDirection: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpRayQueryGetIntersectionObjectRayDirectionKHR; + break; + case glslang::EOpRayQueryGetIntersectionObjectRayOrigin: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpRayQueryGetIntersectionObjectRayOriginKHR; + break; + case glslang::EOpRayQueryGetWorldRayDirection: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpRayQueryGetWorldRayDirectionKHR; + break; + case glslang::EOpRayQueryGetWorldRayOrigin: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpRayQueryGetWorldRayOriginKHR; + break; + case glslang::EOpRayQueryGetIntersectionObjectToWorld: + typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3); + opCode = spv::OpRayQueryGetIntersectionObjectToWorldKHR; + break; + case glslang::EOpRayQueryGetIntersectionWorldToObject: + typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3); + opCode = spv::OpRayQueryGetIntersectionWorldToObjectKHR; + break; case glslang::EOpWritePackedPrimitiveIndices4x8NV: builder.createNoResultOp(spv::OpWritePackedPrimitiveIndices4x8NV, operands); return 0; @@ -7544,7 +8521,8 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId) { // GLSL memory barriers use queuefamily scope in new model, device scope in old model - spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice; + spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ? + spv::ScopeQueueFamilyKHR : spv::ScopeDevice; switch (op) { case glslang::EOpBarrier: @@ -7656,7 +8634,18 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv: case glslang::EOpTerminateRayNV: builder.createNoResultOp(spv::OpTerminateRayNV); return 0; - + case glslang::EOpRayQueryInitialize: + builder.createNoResultOp(spv::OpRayQueryInitializeKHR); + return 0; + case glslang::EOpRayQueryTerminate: + builder.createNoResultOp(spv::OpRayQueryTerminateKHR); + return 0; + case glslang::EOpRayQueryGenerateIntersection: + builder.createNoResultOp(spv::OpRayQueryGenerateIntersectionKHR); + return 0; + case glslang::EOpRayQueryConfirmIntersection: + builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR); + return 0; case glslang::EOpBeginInvocationInterlock: builder.createNoResultOp(spv::OpBeginInvocationInterlockEXT); return 0; @@ -7708,7 +8697,7 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol // it was not found, create it spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false); - auto forcedType = getForcedType(builtIn, symbol->getType()); + auto forcedType = getForcedType(symbol->getQualifier().builtIn, symbol->getType()); id = createSpvVariable(symbol, forcedType.first); symbolValues[symbol->getId()] = id; if (forcedType.second != spv::NoType) @@ -7771,16 +8760,15 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol } #ifndef GLSLANG_WEB - if (symbol->getType().isImage()) { + // Subgroup builtins which have input storage class are volatile for ray tracing stages. + if (symbol->getType().isImage() || symbol->getQualifier().isPipeInput()) { std::vector memory; - TranslateMemoryDecoration(symbol->getType().getQualifier(), memory, glslangIntermediate->usingVulkanMemoryModel()); + TranslateMemoryDecoration(symbol->getType().getQualifier(), memory, + glslangIntermediate->usingVulkanMemoryModel()); for (unsigned int i = 0; i < memory.size(); ++i) builder.addDecoration(id, memory[i]); } - // nonuniform - builder.addDecoration(id, TranslateNonUniformDecoration(symbol->getType().getQualifier())); - if (builtIn == spv::BuiltInSampleMask) { spv::Decoration decoration; // GL_NV_sample_mask_override_coverage extension @@ -7827,7 +8815,50 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol } if (symbol->isReference()) { - builder.addDecoration(id, symbol->getType().getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT); + builder.addDecoration(id, symbol->getType().getQualifier().restrict ? + spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT); + } + + // + // Add SPIR-V decorations for structure (GL_EXT_spirv_intrinsics) + // + if (symbol->getType().getQualifier().hasSprivDecorate()) { + const glslang::TSpirvDecorate& spirvDecorate = symbol->getType().getQualifier().getSpirvDecorate(); + + // Add spirv_decorate + for (auto& decorate : spirvDecorate.decorates) { + if (!decorate.second.empty()) { + std::vector literals; + TranslateLiterals(decorate.second, literals); + builder.addDecoration(id, static_cast(decorate.first), literals); + } + else + builder.addDecoration(id, static_cast(decorate.first)); + } + + // Add spirv_decorate_id + for (auto& decorateId : spirvDecorate.decorateIds) { + std::vector operandIds; + assert(!decorateId.second.empty()); + for (auto extraOperand : decorateId.second) { + int nextConst = 0; + spv::Id operandId = createSpvConstantFromConstUnionArray( + extraOperand->getType(), extraOperand->getConstArray(), nextConst, false); + operandIds.push_back(operandId); + } + builder.addDecoration(id, static_cast(decorateId.first), operandIds); + } + + // Add spirv_decorate_string + for (auto& decorateString : spirvDecorate.decorateStrings) { + std::vector strings; + assert(!decorateString.second.empty()); + for (auto extraOperand : decorateString.second) { + const char* string = extraOperand->getConstArray()[0].getSConst()->c_str(); + strings.push_back(string); + } + builder.addDecoration(id, static_cast(decorateString.first), strings); + } } #endif @@ -7889,12 +8920,25 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& n // hand off to the non-spec-constant path assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr); int nextConst = 0; - return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), - nextConst, false); + return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? + node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), + nextConst, false); } // We now know we have a specialization constant to build + // Extra capabilities may be needed. + if (node.getType().contains8BitInt()) + builder.addCapability(spv::CapabilityInt8); + if (node.getType().contains16BitFloat()) + builder.addCapability(spv::CapabilityFloat16); + if (node.getType().contains16BitInt()) + builder.addCapability(spv::CapabilityInt16); + if (node.getType().contains64BitInt()) + builder.addCapability(spv::CapabilityInt64); + if (node.getType().containsDouble()) + builder.addCapability(spv::CapabilityFloat64); + // gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants, // even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ... if (node.getType().getQualifier().builtIn == glslang::EbvWorkGroupSize) { @@ -7943,7 +8987,8 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& n // If there are not enough elements present in 'consts', 0 will be substituted; // an empty 'consts' can be used to create a fully zeroed SPIR-V constant. // -spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant) +spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, + const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant) { // vector of constants for SPIR-V std::vector spvConsts; @@ -8061,6 +9106,9 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla scalar = builder.createUnaryOp(spv::OpBitcast, typeId, scalar); break; #endif + case glslang::EbtString: + scalar = builder.getStringId(consts[nextConst].getSConst()->c_str()); + break; default: assert(0); break; @@ -8161,7 +9209,8 @@ bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node) // Emit short-circuiting code, where 'right' is never evaluated unless // the left side is true (for &&) or false (for ||). -spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left, glslang::TIntermTyped& right) +spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left, + glslang::TIntermTyped& right) { spv::Id boolTypeId = builder.makeBoolType(); @@ -8245,7 +9294,9 @@ int GetSpirvGeneratorVersion() // return 6; // revert version 5 change, which makes a different (new) kind of incorrect code, // versions 4 and 6 each generate OpArrayLength as it has long been done // return 7; // GLSL volatile keyword maps to both SPIR-V decorations Volatile and Coherent - return 8; // switch to new dead block eliminator; use OpUnreachable + // return 8; // switch to new dead block eliminator; use OpUnreachable + // return 9; // don't include opaque function parameters in OpEntryPoint global's operand list + return 10; // Generate OpFUnordNotEqual for != comparisons } // Write SPIR-V out to a binary file @@ -8265,14 +9316,15 @@ void OutputSpvBin(const std::vector& spirv, const char* baseName) // Write SPIR-V out to a text file with 32-bit hexadecimal words void OutputSpvHex(const std::vector& spirv, const char* baseName, const char* varName) { -#ifndef GLSLANG_WEB +#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) std::ofstream out; out.open(baseName, std::ios::binary | std::ios::out); if (out.fail()) printf("ERROR: Failed to open file: %s\n", baseName); - out << "\t// " << - GetSpirvGeneratorVersion() << "." << GLSLANG_MINOR_VERSION << "." << GLSLANG_PATCH_LEVEL << - std::endl; + out << "\t// " << + GetSpirvGeneratorVersion() << + GLSLANG_VERSION_MAJOR << "." << GLSLANG_VERSION_MINOR << "." << GLSLANG_VERSION_PATCH << + GLSLANG_VERSION_FLAVOR << std::endl; if (varName != nullptr) { out << "\t #pragma once" << std::endl; out << "const uint32_t " << varName << "[] = {" << std::endl; @@ -8291,6 +9343,7 @@ void OutputSpvHex(const std::vector& spirv, const char* baseName, } if (varName != nullptr) { out << "};"; + out << std::endl; } out.close(); #endif @@ -8328,10 +9381,14 @@ void GlslangToSpv(const TIntermediate& intermediate, std::vector& // If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan // eg. forward and remove memory writes of opaque types. bool prelegalization = intermediate.getSource() == EShSourceHlsl; - if ((intermediate.getSource() == EShSourceHlsl || options->optimizeSize) && !options->disableOptimizer) { - SpirvToolsLegalize(intermediate, spirv, logger, options); + if ((prelegalization || options->optimizeSize) && !options->disableOptimizer) { + SpirvToolsTransform(intermediate, spirv, logger, options); prelegalization = false; } + else if (options->stripDebugInfo) { + // Strip debug info even if optimization is disabled. + SpirvToolsStripDebugInfo(intermediate, spirv, logger); + } if (options->validate) SpirvToolsValidate(intermediate, spirv, logger, prelegalization); diff --git a/libraries/glslang/spirv/GlslangToSpv.h b/libraries/ZVulkan/src/glslang/spirv/GlslangToSpv.h similarity index 98% rename from libraries/glslang/spirv/GlslangToSpv.h rename to libraries/ZVulkan/src/glslang/spirv/GlslangToSpv.h index 3907be43b75..86e1c23bf63 100644 --- a/libraries/glslang/spirv/GlslangToSpv.h +++ b/libraries/ZVulkan/src/glslang/spirv/GlslangToSpv.h @@ -40,7 +40,7 @@ #endif #include "SpvTools.h" -#include "glslang/Include/intermediate.h" +#include "../glslang/Include/intermediate.h" #include #include diff --git a/libraries/glslang/spirv/InReadableOrder.cpp b/libraries/ZVulkan/src/glslang/spirv/InReadableOrder.cpp similarity index 100% rename from libraries/glslang/spirv/InReadableOrder.cpp rename to libraries/ZVulkan/src/glslang/spirv/InReadableOrder.cpp diff --git a/libraries/glslang/spirv/Logger.cpp b/libraries/ZVulkan/src/glslang/spirv/Logger.cpp similarity index 99% rename from libraries/glslang/spirv/Logger.cpp rename to libraries/ZVulkan/src/glslang/spirv/Logger.cpp index 7ea0c6342b7..cdc8469c447 100644 --- a/libraries/glslang/spirv/Logger.cpp +++ b/libraries/ZVulkan/src/glslang/spirv/Logger.cpp @@ -69,4 +69,4 @@ std::string SpvBuildLogger::getAllMessages() const { } // end spv namespace -#endif \ No newline at end of file +#endif diff --git a/libraries/glslang/spirv/Logger.h b/libraries/ZVulkan/src/glslang/spirv/Logger.h similarity index 100% rename from libraries/glslang/spirv/Logger.h rename to libraries/ZVulkan/src/glslang/spirv/Logger.h diff --git a/libraries/ZVulkan/src/glslang/spirv/NonSemanticDebugPrintf.h b/libraries/ZVulkan/src/glslang/spirv/NonSemanticDebugPrintf.h new file mode 100644 index 00000000000..83796d75e56 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/spirv/NonSemanticDebugPrintf.h @@ -0,0 +1,50 @@ +// Copyright (c) 2020 The Khronos Group Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and/or associated documentation files (the +// "Materials"), to deal in the Materials without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Materials, and to +// permit persons to whom the Materials are 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 Materials. +// +// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS +// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS +// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT +// https://www.khronos.org/registry/ +// +// THE MATERIALS ARE 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 +// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +// + +#ifndef SPIRV_UNIFIED1_NonSemanticDebugPrintf_H_ +#define SPIRV_UNIFIED1_NonSemanticDebugPrintf_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + NonSemanticDebugPrintfRevision = 1, + NonSemanticDebugPrintfRevision_BitWidthPadding = 0x7fffffff +}; + +enum NonSemanticDebugPrintfInstructions { + NonSemanticDebugPrintfDebugPrintf = 1, + NonSemanticDebugPrintfInstructionsMax = 0x7fffffff +}; + + +#ifdef __cplusplus +} +#endif + +#endif // SPIRV_UNIFIED1_NonSemanticDebugPrintf_H_ diff --git a/libraries/glslang/spirv/SPVRemapper.cpp b/libraries/ZVulkan/src/glslang/spirv/SPVRemapper.cpp similarity index 98% rename from libraries/glslang/spirv/SPVRemapper.cpp rename to libraries/ZVulkan/src/glslang/spirv/SPVRemapper.cpp index fd0bb8950c6..56d6d5d4a58 100644 --- a/libraries/glslang/spirv/SPVRemapper.cpp +++ b/libraries/ZVulkan/src/glslang/spirv/SPVRemapper.cpp @@ -544,6 +544,9 @@ namespace spv { // Extended instructions: currently, assume everything is an ID. // TODO: add whatever data we need for exceptions to that if (opCode == spv::OpExtInst) { + + idFn(asId(word)); // Instruction set is an ID that also needs to be mapped + word += 2; // instruction set, and instruction from set numOperands -= 2; @@ -625,6 +628,9 @@ namespace spv { break; } + case spv::OperandVariableLiteralStrings: + return nextInst; + // Execution mode might have extra literal operands. Skip them. case spv::OperandExecutionMode: return nextInst; @@ -827,7 +833,15 @@ namespace spv { [&](spv::Id& id) { if (thisOpCode != spv::OpNop) { ++idCounter; - const std::uint32_t hashval = opCounter[thisOpCode] * thisOpCode * 50047 + idCounter + fnId * 117; + const std::uint32_t hashval = + // Explicitly cast operands to unsigned int to avoid integer + // promotion to signed int followed by integer overflow, + // which would result in undefined behavior. + static_cast(opCounter[thisOpCode]) + * thisOpCode + * 50047 + + idCounter + + static_cast(fnId) * 117; if (isOldIdUnmapped(id)) localId(id, nextUnusedId(hashval % softTypeIdLimit + firstMappedID)); diff --git a/libraries/glslang/spirv/SPVRemapper.h b/libraries/ZVulkan/src/glslang/spirv/SPVRemapper.h similarity index 100% rename from libraries/glslang/spirv/SPVRemapper.h rename to libraries/ZVulkan/src/glslang/spirv/SPVRemapper.h diff --git a/libraries/glslang/spirv/SpvBuilder.cpp b/libraries/ZVulkan/src/glslang/spirv/SpvBuilder.cpp similarity index 90% rename from libraries/glslang/spirv/SpvBuilder.cpp rename to libraries/ZVulkan/src/glslang/spirv/SpvBuilder.cpp index bd208952e02..e83306ebcbf 100644 --- a/libraries/glslang/spirv/SpvBuilder.cpp +++ b/libraries/ZVulkan/src/glslang/spirv/SpvBuilder.cpp @@ -1,6 +1,7 @@ // // Copyright (C) 2014-2015 LunarG, Inc. // Copyright (C) 2015-2018 Google, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -496,7 +497,8 @@ Id Builder::makeFunctionType(Id returnType, const std::vector& paramTypes) return type->getResultId(); } -Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format) +Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, + ImageFormat format) { assert(sampled == 1 || sampled == 2); @@ -601,16 +603,31 @@ Id Builder::makeSampledImageType(Id imageType) } #ifndef GLSLANG_WEB -Id Builder::makeAccelerationStructureNVType() +Id Builder::makeAccelerationStructureType() { Instruction *type; - if (groupedTypes[OpTypeAccelerationStructureNV].size() == 0) { - type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureNV); - groupedTypes[OpTypeAccelerationStructureNV].push_back(type); + if (groupedTypes[OpTypeAccelerationStructureKHR].size() == 0) { + type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureKHR); + groupedTypes[OpTypeAccelerationStructureKHR].push_back(type); constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); } else { - type = groupedTypes[OpTypeAccelerationStructureNV].back(); + type = groupedTypes[OpTypeAccelerationStructureKHR].back(); + } + + return type->getResultId(); +} + +Id Builder::makeRayQueryType() +{ + Instruction *type; + if (groupedTypes[OpTypeRayQueryKHR].size() == 0) { + type = new Instruction(getUniqueId(), NoType, OpTypeRayQueryKHR); + groupedTypes[OpTypeRayQueryKHR].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + } else { + type = groupedTypes[OpTypeRayQueryKHR].back(); } return type->getResultId(); @@ -726,6 +743,26 @@ Id Builder::getContainedTypeId(Id typeId, int member) const } } +// Figure out the final resulting type of the access chain. +Id Builder::getResultingAccessChainType() const +{ + assert(accessChain.base != NoResult); + Id typeId = getTypeId(accessChain.base); + + assert(isPointerType(typeId)); + typeId = getContainedTypeId(typeId); + + for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) { + if (isStructType(typeId)) { + assert(isConstantScalar(accessChain.indexChain[i])); + typeId = getContainedTypeId(typeId, getConstantScalar(accessChain.indexChain[i])); + } else + typeId = getContainedTypeId(typeId, accessChain.indexChain[i]); + } + + return typeId; +} + // Return the immediately contained type of a given composite type. Id Builder::getContainedTypeId(Id typeId) const { @@ -852,6 +889,30 @@ bool Builder::isSpecConstantOpCode(Op opcode) const } } +Id Builder::makeNullConstant(Id typeId) +{ + Instruction* constant; + + // See if we already made it. + Id existing = NoResult; + for (int i = 0; i < (int)nullConstants.size(); ++i) { + constant = nullConstants[i]; + if (constant->getTypeId() == typeId) + existing = constant->getResultId(); + } + + if (existing != NoResult) + return existing; + + // Make it + Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantNull); + constantsTypesGlobals.push_back(std::unique_ptr(c)); + nullConstants.push_back(c); + module.mapInstruction(c); + + return c->getResultId(); +} + Id Builder::makeBoolConstant(bool b, bool specConstant) { Id typeId = makeBoolType(); @@ -1166,6 +1227,28 @@ void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int val executionModes.push_back(std::unique_ptr(instr)); } +void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const std::vector& literals) +{ + Instruction* instr = new Instruction(OpExecutionMode); + instr->addIdOperand(entryPoint->getId()); + instr->addImmediateOperand(mode); + for (auto literal : literals) + instr->addImmediateOperand(literal); + + executionModes.push_back(std::unique_ptr(instr)); +} + +void Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const std::vector& operandIds) +{ + Instruction* instr = new Instruction(OpExecutionModeId); + instr->addIdOperand(entryPoint->getId()); + instr->addImmediateOperand(mode); + for (auto operandId : operandIds) + instr->addIdOperand(operandId); + + executionModes.push_back(std::unique_ptr(instr)); +} + void Builder::addName(Id id, const char* string) { Instruction* name = new Instruction(OpName); @@ -1204,7 +1287,7 @@ void Builder::addDecoration(Id id, Decoration decoration, const char* s) if (decoration == spv::DecorationMax) return; - Instruction* dec = new Instruction(OpDecorateStringGOOGLE); + Instruction* dec = new Instruction(OpDecorateString); dec->addIdOperand(id); dec->addImmediateOperand(decoration); dec->addStringOperand(s); @@ -1212,6 +1295,34 @@ void Builder::addDecoration(Id id, Decoration decoration, const char* s) decorations.push_back(std::unique_ptr(dec)); } +void Builder::addDecoration(Id id, Decoration decoration, const std::vector& literals) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpDecorate); + dec->addIdOperand(id); + dec->addImmediateOperand(decoration); + for (auto literal : literals) + dec->addImmediateOperand(literal); + + decorations.push_back(std::unique_ptr(dec)); +} + +void Builder::addDecoration(Id id, Decoration decoration, const std::vector& strings) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpDecorateString); + dec->addIdOperand(id); + dec->addImmediateOperand(decoration); + for (auto string : strings) + dec->addStringOperand(string); + + decorations.push_back(std::unique_ptr(dec)); +} + void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration) { if (decoration == spv::DecorationMax) @@ -1225,6 +1336,21 @@ void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration) decorations.push_back(std::unique_ptr(dec)); } +void Builder::addDecorationId(Id id, Decoration decoration, const std::vector& operandIds) +{ + if(decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpDecorateId); + dec->addIdOperand(id); + dec->addImmediateOperand(decoration); + + for (auto operandId : operandIds) + dec->addIdOperand(operandId); + + decorations.push_back(std::unique_ptr(dec)); +} + void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num) { if (decoration == spv::DecorationMax) @@ -1254,6 +1380,36 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat decorations.push_back(std::unique_ptr(dec)); } +void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector& literals) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpMemberDecorate); + dec->addIdOperand(id); + dec->addImmediateOperand(member); + dec->addImmediateOperand(decoration); + for (auto literal : literals) + dec->addImmediateOperand(literal); + + decorations.push_back(std::unique_ptr(dec)); +} + +void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector& strings) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpMemberDecorateString); + dec->addIdOperand(id); + dec->addImmediateOperand(member); + dec->addImmediateOperand(decoration); + for (auto string : strings) + dec->addStringOperand(string); + + decorations.push_back(std::unique_ptr(dec)); +} + // Comments in header Function* Builder::makeEntryPoint(const char* entryPoint) { @@ -1270,7 +1426,8 @@ Function* Builder::makeEntryPoint(const char* entryPoint) // Comments in header Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, - const std::vector& paramTypes, const std::vector>& decorations, Block **entry) + const std::vector& paramTypes, + const std::vector>& decorations, Block **entry) { // Make the function and initial instructions in it Id typeId = makeFunctionType(returnType, paramTypes); @@ -1279,9 +1436,12 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const // Set up the precisions setPrecision(function->getId(), precision); + function->setReturnPrecision(precision); for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) { - for (int d = 0; d < (int)decorations[p].size(); ++d) + for (int d = 0; d < (int)decorations[p].size(); ++d) { addDecoration(firstParamId + p, decorations[p][d]); + function->addParamPrecision(p, decorations[p][d]); + } } // CFG @@ -1331,14 +1491,14 @@ void Builder::leaveFunction() } // Comments in header -void Builder::makeDiscard() +void Builder::makeStatementTerminator(spv::Op opcode, const char *name) { - buildPoint->addInstruction(std::unique_ptr(new Instruction(OpKill))); - createAndSetNoPredecessorBlock("post-discard"); + buildPoint->addInstruction(std::unique_ptr(new Instruction(opcode))); + createAndSetNoPredecessorBlock(name); } // Comments in header -Id Builder::createVariable(StorageClass storageClass, Id type, const char* name, Id initializer) +Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer) { Id pointerType = makePointer(storageClass, type); Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable); @@ -1360,6 +1520,7 @@ Id Builder::createVariable(StorageClass storageClass, Id type, const char* name, if (name) addName(inst->getResultId(), name); + setPrecision(inst->getResultId(), precision); return inst->getResultId(); } @@ -1373,7 +1534,8 @@ Id Builder::createUndefined(Id type) } // av/vis/nonprivate are unnecessary and illegal for some storage classes. -spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const +spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) + const { switch (sc) { case spv::StorageClassUniform: @@ -1392,7 +1554,8 @@ spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAc } // Comments in header -void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) +void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, + unsigned int alignment) { Instruction* store = new Instruction(OpStore); store->addIdOperand(lValue); @@ -1414,7 +1577,8 @@ void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAcce } // Comments in header -Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) +Id Builder::createLoad(Id lValue, spv::Decoration precision, spv::MemoryAccessMask memoryAccess, + spv::Scope scope, unsigned int alignment) { Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad); load->addIdOperand(lValue); @@ -1432,6 +1596,7 @@ Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope } buildPoint->addInstruction(std::unique_ptr(load)); + setPrecision(load->getResultId(), precision); return load->getResultId(); } @@ -1440,16 +1605,7 @@ Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector& offsets) { // Figure out the final resulting type. - spv::Id typeId = getTypeId(base); - assert(isPointerType(typeId) && offsets.size() > 0); - typeId = getContainedTypeId(typeId); - for (int i = 0; i < (int)offsets.size(); ++i) { - if (isStructType(typeId)) { - assert(isConstantScalar(offsets[i])); - typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i])); - } else - typeId = getContainedTypeId(typeId, offsets[i]); - } + Id typeId = getResultingAccessChainType(); typeId = makePointer(storageClass, typeId); // Make the instruction @@ -1495,7 +1651,8 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) // Generate code for spec constants if in spec constant operation // generation mode. if (generatingOpCodeForSpecConst) { - return createSpecConstantOp(OpCompositeExtract, typeId, std::vector(1, composite), std::vector(1, index)); + return createSpecConstantOp(OpCompositeExtract, typeId, std::vector(1, composite), + std::vector(1, index)); } Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); extract->addIdOperand(composite); @@ -1697,7 +1854,8 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector& opera return op->getResultId(); } -Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector& operands, const std::vector& literals) +Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector& operands, + const std::vector& literals) { Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp); op->addImmediateOperand((unsigned) opCode); @@ -2144,7 +2302,7 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b Op op; switch (getMostBasicTypeClass(valueType)) { case OpTypeFloat: - op = equal ? OpFOrdEqual : OpFOrdNotEqual; + op = equal ? OpFOrdEqual : OpFUnordNotEqual; break; case OpTypeInt: default: @@ -2187,7 +2345,8 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b if (constituent == 0) resultId = subResultId; else - resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision); + resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), + precision); } return resultId; @@ -2196,7 +2355,8 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b // OpCompositeConstruct Id Builder::createCompositeConstruct(Id typeId, const std::vector& constituents) { - assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size())); + assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && + getNumTypeConstituents(typeId) == (int)constituents.size())); if (generatingOpCodeForSpecConst) { // Sometime, even in spec-constant-op mode, the constant composite to be @@ -2394,7 +2554,7 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& int row = 0; int col = 0; - for (int arg = 0; arg < (int)sources.size(); ++arg) { + for (int arg = 0; arg < (int)sources.size() && col < numCols; ++arg) { Id argComp = sources[arg]; for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) { if (getNumComponents(sources[arg]) > 1) { @@ -2406,6 +2566,10 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& row = 0; col++; } + if (col == numCols) { + // If more components are provided than fit the matrix, discard the rest. + break; + } } } } @@ -2609,7 +2773,8 @@ void Builder::clearAccessChain() } // Comments in header -void Builder::accessChainPushSwizzle(std::vector& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment) +void Builder::accessChainPushSwizzle(std::vector& swizzle, Id preSwizzleBaseType, + AccessChain::CoherentFlags coherentFlags, unsigned int alignment) { accessChain.coherentFlags |= coherentFlags; accessChain.alignment |= alignment; @@ -2635,35 +2800,70 @@ void Builder::accessChainPushSwizzle(std::vector& swizzle, Id preSwizz } // Comments in header -void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) +void Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) { assert(accessChain.isRValue == false); transferAccessChainSwizzle(true); - Id base = collapseAccessChain(); - Id source = rvalue; - // dynamic component should be gone - assert(accessChain.component == NoResult); + // If a swizzle exists and is not full and is not dynamic, then the swizzle will be broken into individual stores. + if (accessChain.swizzle.size() > 0 && + getNumTypeComponents(getResultingAccessChainType()) != (int)accessChain.swizzle.size() && + accessChain.component == NoResult) { + for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) { + accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle[i])); + accessChain.instr = NoResult; - // If swizzle still exists, it is out-of-order or not full, we must load the target vector, - // extract and insert elements to perform writeMask and/or swizzle. - if (accessChain.swizzle.size() > 0) { - Id tempBaseId = createLoad(base); - source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle); - } + Id base = collapseAccessChain(); + addDecoration(base, nonUniform); + + accessChain.indexChain.pop_back(); + accessChain.instr = NoResult; - // take LSB of alignment - alignment = alignment & ~(alignment & (alignment-1)); - if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { - memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + // dynamic component should be gone + assert(accessChain.component == NoResult); + + Id source = createCompositeExtract(rvalue, getContainedTypeId(getTypeId(rvalue)), i); + + // take LSB of alignment + alignment = alignment & ~(alignment & (alignment-1)); + if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { + memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + } + + createStore(source, base, memoryAccess, scope, alignment); + } } + else { + Id base = collapseAccessChain(); + addDecoration(base, nonUniform); + + Id source = rvalue; + + // dynamic component should be gone + assert(accessChain.component == NoResult); - createStore(source, base, memoryAccess, scope, alignment); + // If swizzle still exists, it may be out-of-order, we must load the target vector, + // extract and insert elements to perform writeMask and/or swizzle. + if (accessChain.swizzle.size() > 0) { + Id tempBaseId = createLoad(base, spv::NoPrecision); + source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle); + } + + // take LSB of alignment + alignment = alignment & ~(alignment & (alignment-1)); + if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { + memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + } + + createStore(source, base, memoryAccess, scope, alignment); + } } // Comments in header -Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) +Id Builder::accessChainLoad(Decoration precision, Decoration l_nonUniform, + Decoration r_nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, + spv::Scope scope, unsigned int alignment) { Id id; @@ -2687,17 +2887,19 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu if (constant) { id = createCompositeExtract(accessChain.base, swizzleBase, indexes); + setPrecision(id, precision); } else { Id lValue = NoResult; - if (spvVersion >= Spv_1_4) { + if (spvVersion >= Spv_1_4 && isValidInitializer(accessChain.base)) { // make a new function variable for this r-value, using an initializer, // and mark it as NonWritable so that downstream it can be detected as a lookup // table - lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable", - accessChain.base); + lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base), + "indexable", accessChain.base); addDecoration(lValue, DecorationNonWritable); } else { - lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable"); + lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base), + "indexable"); // store into it createStore(accessChain.base, lValue); } @@ -2706,9 +2908,8 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu accessChain.isRValue = false; // load through the access chain - id = createLoad(collapseAccessChain()); + id = createLoad(collapseAccessChain(), precision); } - setPrecision(id, precision); } else id = accessChain.base; // no precision, it was set when this was defined } else { @@ -2721,9 +2922,14 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu } // load through the access chain - id = createLoad(collapseAccessChain(), memoryAccess, scope, alignment); - setPrecision(id, precision); - addDecoration(id, nonUniform); + id = collapseAccessChain(); + // Apply nonuniform both to the access chain and the loaded value. + // Buffer accesses need the access chain decorated, and this is where + // loaded image types get decorated. TODO: This should maybe move to + // createImageTextureFunctionCall. + addDecoration(id, l_nonUniform); + id = createLoad(id, precision, memoryAccess, scope, alignment); + addDecoration(id, r_nonUniform); } // Done, unless there are swizzles to do @@ -2744,7 +2950,7 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu if (accessChain.component != NoResult) id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision); - addDecoration(id, nonUniform); + addDecoration(id, r_nonUniform); return id; } @@ -3075,7 +3281,8 @@ void Builder::dumpSourceInstructions(std::vector& out) const dumpSourceInstructions(iItr->first, *iItr->second, out); } -void Builder::dumpInstructions(std::vector& out, const std::vector >& instructions) const +void Builder::dumpInstructions(std::vector& out, + const std::vector >& instructions) const { for (int i = 0; i < (int)instructions.size(); ++i) { instructions[i]->dump(out); diff --git a/libraries/glslang/spirv/SpvBuilder.h b/libraries/ZVulkan/src/glslang/spirv/SpvBuilder.h similarity index 82% rename from libraries/glslang/spirv/SpvBuilder.h rename to libraries/ZVulkan/src/glslang/spirv/SpvBuilder.h index 31fee975fcc..251b9ee8230 100644 --- a/libraries/glslang/spirv/SpvBuilder.h +++ b/libraries/ZVulkan/src/glslang/spirv/SpvBuilder.h @@ -1,7 +1,8 @@ // // Copyright (C) 2014-2015 LunarG, Inc. -// Copyright (C) 2015-2018 Google, Inc. +// Copyright (C) 2015-2020 Google, Inc. // Copyright (C) 2017 ARM Limited. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -94,6 +95,7 @@ class Builder { const char* file_c_str = str.c_str(); fileString->addStringOperand(file_c_str); strings.push_back(std::unique_ptr(fileString)); + module.mapInstruction(fileString); stringIds[file_c_str] = strId; return strId; } @@ -181,7 +183,9 @@ class Builder { Id makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols); // accelerationStructureNV type - Id makeAccelerationStructureNVType(); + Id makeAccelerationStructureType(); + // rayQueryEXT type + Id makeRayQueryType(); // For querying about types. Id getTypeId(Id resultId) const { return module.getTypeId(resultId); } @@ -196,7 +200,9 @@ class Builder { Id getContainedTypeId(Id typeId) const; Id getContainedTypeId(Id typeId, int) const; StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); } - ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); } + ImageFormat getImageTypeFormat(Id typeId) const + { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); } + Id getResultingAccessChainType() const; bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); } bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); } @@ -206,12 +212,17 @@ class Builder { bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); } bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); } - bool isBoolType(Id typeId) { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); } - bool isIntType(Id typeId) const { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; } - bool isUintType(Id typeId) const { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; } + bool isBoolType(Id typeId) + { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); } + bool isIntType(Id typeId) const + { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; } + bool isUintType(Id typeId) const + { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; } bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; } bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; } - bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; } + bool isScalarType(Id typeId) const + { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || + getTypeClass(typeId) == OpTypeBool; } bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; } bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; } bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; } @@ -221,7 +232,8 @@ class Builder { #else bool isCooperativeMatrixType(Id typeId)const { return getTypeClass(typeId) == OpTypeCooperativeMatrixNV; } #endif - bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); } + bool isAggregateType(Id typeId) const + { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); } bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; } bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; } bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; } @@ -233,9 +245,17 @@ class Builder { bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); } bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; } bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); } - unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); } + unsigned int getConstantScalar(Id resultId) const + { return module.getInstruction(resultId)->getImmediateOperand(0); } StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); } + bool isVariableOpCode(Op opcode) const { return opcode == OpVariable; } + bool isVariable(Id resultId) const { return isVariableOpCode(getOpCode(resultId)); } + bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClassFunction; } + bool isGlobalVariable(Id resultId) const { return isVariable(resultId) && isGlobalStorage(resultId); } + // See if a resultId is valid for use as an initializer. + bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); } + int getScalarTypeWidth(Id typeId) const { Id scalarTypeId = getScalarTypeId(typeId); @@ -274,15 +294,24 @@ class Builder { } // For making new constants (will return old constant if the requested one was already made). + Id makeNullConstant(Id typeId); Id makeBoolConstant(bool b, bool specConstant = false); - Id makeInt8Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); } - Id makeUint8Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(8), u, specConstant); } - Id makeInt16Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); } - Id makeUint16Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(16), u, specConstant); } - Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); } - Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); } - Id makeInt64Constant(long long i, bool specConstant = false) { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); } - Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); } + Id makeInt8Constant(int i, bool specConstant = false) + { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); } + Id makeUint8Constant(unsigned u, bool specConstant = false) + { return makeIntConstant(makeUintType(8), u, specConstant); } + Id makeInt16Constant(int i, bool specConstant = false) + { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); } + Id makeUint16Constant(unsigned u, bool specConstant = false) + { return makeIntConstant(makeUintType(16), u, specConstant); } + Id makeIntConstant(int i, bool specConstant = false) + { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); } + Id makeUintConstant(unsigned u, bool specConstant = false) + { return makeIntConstant(makeUintType(32), u, specConstant); } + Id makeInt64Constant(long long i, bool specConstant = false) + { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); } + Id makeUint64Constant(unsigned long long u, bool specConstant = false) + { return makeInt64Constant(makeUintType(64), u, specConstant); } Id makeFloatConstant(float f, bool specConstant = false); Id makeDoubleConstant(double d, bool specConstant = false); Id makeFloat16Constant(float f16, bool specConstant = false); @@ -294,13 +323,20 @@ class Builder { // Methods for adding information outside the CFG. Instruction* addEntryPoint(ExecutionModel, Function*, const char* name); void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1); + void addExecutionMode(Function*, ExecutionMode mode, const std::vector& literals); + void addExecutionModeId(Function*, ExecutionMode mode, const std::vector& operandIds); void addName(Id, const char* name); void addMemberName(Id, int member, const char* name); void addDecoration(Id, Decoration, int num = -1); void addDecoration(Id, Decoration, const char*); + void addDecoration(Id, Decoration, const std::vector& literals); + void addDecoration(Id, Decoration, const std::vector& strings); void addDecorationId(Id id, Decoration, Id idDecoration); + void addDecorationId(Id id, Decoration, const std::vector& operandIds); void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1); void addMemberDecoration(Id, unsigned int member, Decoration, const char*); + void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector& literals); + void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector& strings); // At the end of what block do the next create*() instructions go? void setBuildPoint(Block* bp) { buildPoint = bp; } @@ -313,8 +349,8 @@ class Builder { // Make a shader-style function, and create its entry block if entry is non-zero. // Return the function, pass back the entry. // The returned pointer is only valid for the lifetime of this builder. - Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector& paramTypes, - const std::vector>& precisions, Block **entry = 0); + Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, + const std::vector& paramTypes, const std::vector>& precisions, Block **entry = 0); // Create a return. An 'implicit' return is one not appearing in the source // code. In the case of an implicit return, no post-return block is inserted. @@ -323,20 +359,25 @@ class Builder { // Generate all the code needed to finish up a function. void leaveFunction(); - // Create a discard. - void makeDiscard(); + // Create block terminator instruction for certain statements like + // discard, terminate-invocation, terminateRayEXT, or ignoreIntersectionEXT + void makeStatementTerminator(spv::Op opcode, const char *name); // Create a global or function local or IO variable. - Id createVariable(StorageClass, Id type, const char* name = 0, Id initializer = NoResult); + Id createVariable(Decoration precision, StorageClass, Id type, const char* name = nullptr, + Id initializer = NoResult); // Create an intermediate with an undefined value. Id createUndefined(Id type); // Store into an Id and return the l-value - void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); + void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, + spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); // Load from an Id and return it - Id createLoad(Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); + Id createLoad(Id lValue, spv::Decoration precision, + spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, + spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); // Create an OpAccessChain instruction Id createAccessChain(StorageClass, Id base, const std::vector& offsets); @@ -495,7 +536,7 @@ class Builder { // recursion stack can hold the memory for it. // void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector& caseValues, - const std::vector& valueToSegment, int defaultSegment, std::vector& segmentBB); // return argument + const std::vector& valueToSegment, int defaultSegment, std::vector& segmentBB); // Add a branch to the innermost switch's merge block. void addSwitchBreak(); @@ -512,7 +553,7 @@ class Builder { Block &head, &body, &merge, &continue_target; private: LoopBlocks(); - LoopBlocks& operator=(const LoopBlocks&); + LoopBlocks& operator=(const LoopBlocks&) = delete; }; // Start a new loop and prepare the builder to generate code for it. Until @@ -569,10 +610,13 @@ class Builder { std::vector indexChain; Id instr; // cache the instruction that generates this access chain std::vector swizzle; // each std::vector element selects the next GLSL component number - Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present - Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present + Id component; // a dynamic component index, can coexist with a swizzle, + // done after the swizzle, NoResult if not present + Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; + // NoType unless a swizzle or component is present bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value - unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment. Only tracks base and (optional) component selection alignment. + unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment. + // Only tracks base and (optional) component selection alignment. // Accumulate whether anything in the chain of structures has coherent decorations. struct CoherentFlags { @@ -583,15 +627,22 @@ class Builder { CoherentFlags operator |=(const CoherentFlags &other) { return *this; } #else bool isVolatile() const { return volatil; } + bool isNonUniform() const { return nonUniform; } + bool anyCoherent() const { + return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent || + subgroupcoherent || shadercallcoherent; + } unsigned coherent : 1; unsigned devicecoherent : 1; unsigned queuefamilycoherent : 1; unsigned workgroupcoherent : 1; unsigned subgroupcoherent : 1; + unsigned shadercallcoherent : 1; unsigned nonprivate : 1; unsigned volatil : 1; unsigned isImage : 1; + unsigned nonUniform : 1; void clear() { coherent = 0; @@ -599,9 +650,11 @@ class Builder { queuefamilycoherent = 0; workgroupcoherent = 0; subgroupcoherent = 0; + shadercallcoherent = 0; nonprivate = 0; volatil = 0; isImage = 0; + nonUniform = 0; } CoherentFlags operator |=(const CoherentFlags &other) { @@ -610,9 +663,11 @@ class Builder { queuefamilycoherent |= other.queuefamilycoherent; workgroupcoherent |= other.workgroupcoherent; subgroupcoherent |= other.subgroupcoherent; + shadercallcoherent |= other.shadercallcoherent; nonprivate |= other.nonprivate; volatil |= other.volatil; isImage |= other.isImage; + nonUniform |= other.nonUniform; return *this; } #endif @@ -655,11 +710,13 @@ class Builder { } // push new swizzle onto the end of any existing swizzle, merging into a single swizzle - void accessChainPushSwizzle(std::vector& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment); + void accessChainPushSwizzle(std::vector& swizzle, Id preSwizzleBaseType, + AccessChain::CoherentFlags coherentFlags, unsigned int alignment); // push a dynamic component selection onto the access chain, only applicable with a // non-trivial swizzle or no swizzle - void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment) + void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, + unsigned int alignment) { if (accessChain.swizzle.size() != 1) { accessChain.component = component; @@ -671,10 +728,19 @@ class Builder { } // use accessChain and swizzle to store value - void accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); + void accessChainStore(Id rvalue, Decoration nonUniform, + spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, + spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); // use accessChain and swizzle to load an r-value - Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); + Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType, + spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, + unsigned int alignment = 0); + + // Return whether or not the access chain can be represented in SPIR-V + // as an l-value. + // E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be. + bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; } // get the direct pointer for an l-value Id accessChainGetLValue(); @@ -703,7 +769,8 @@ class Builder { void createBranch(Block* block); void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock); - void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, const std::vector& operands); + void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, + const std::vector& operands); // Sets to generate opcode for specialization constants. void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; } @@ -729,7 +796,8 @@ class Builder { void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector&) const; void dumpInstructions(std::vector&, const std::vector >&) const; void dumpModuleProcesses(std::vector&) const; - spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const; + spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) + const; unsigned int spvVersion; // the version of SPIR-V to emit in the header SourceLanguage source; @@ -764,10 +832,16 @@ class Builder { std::vector > externals; std::vector > functions; - // not output, internally used for quick & dirty canonical (unique) creation - std::unordered_map> groupedConstants; // map type opcodes to constant inst. - std::unordered_map> groupedStructConstants; // map struct-id to constant instructions - std::unordered_map> groupedTypes; // map type opcodes to type instructions + // not output, internally used for quick & dirty canonical (unique) creation + + // map type opcodes to constant inst. + std::unordered_map> groupedConstants; + // map struct-id to constant instructions + std::unordered_map> groupedStructConstants; + // map type opcodes to type instructions + std::unordered_map> groupedTypes; + // list of OpConstantNull instructions + std::vector nullConstants; // stack of switches std::stack switchMerges; diff --git a/libraries/glslang/spirv/SpvPostProcess.cpp b/libraries/ZVulkan/src/glslang/spirv/SpvPostProcess.cpp similarity index 93% rename from libraries/glslang/spirv/SpvPostProcess.cpp rename to libraries/ZVulkan/src/glslang/spirv/SpvPostProcess.cpp index d40174d1721..23d7b5a4611 100644 --- a/libraries/glslang/spirv/SpvPostProcess.cpp +++ b/libraries/ZVulkan/src/glslang/spirv/SpvPostProcess.cpp @@ -436,6 +436,38 @@ void Builder::postProcessFeatures() { } } } + + // If any Vulkan memory model-specific functionality is used, update the + // OpMemoryModel to match. + if (capabilities.find(spv::CapabilityVulkanMemoryModelKHR) != capabilities.end()) { + memoryModel = spv::MemoryModelVulkanKHR; + addIncorporatedExtension(spv::E_SPV_KHR_vulkan_memory_model, spv::Spv_1_5); + } + + // Add Aliased decoration if there's more than one Workgroup Block variable. + if (capabilities.find(spv::CapabilityWorkgroupMemoryExplicitLayoutKHR) != capabilities.end()) { + assert(entryPoints.size() == 1); + auto &ep = entryPoints[0]; + + std::vector workgroup_variables; + for (int i = 0; i < (int)ep->getNumOperands(); i++) { + if (!ep->isIdOperand(i)) + continue; + + const Id id = ep->getIdOperand(i); + const Instruction *instr = module.getInstruction(id); + if (instr->getOpCode() != spv::OpVariable) + continue; + + if (instr->getImmediateOperand(0) == spv::StorageClassWorkgroup) + workgroup_variables.push_back(id); + } + + if (workgroup_variables.size() > 1) { + for (size_t i = 0; i < workgroup_variables.size(); i++) + addDecoration(workgroup_variables[i], spv::DecorationAliased); + } + } } #endif diff --git a/libraries/ZVulkan/src/glslang/spirv/SpvTools.cpp b/libraries/ZVulkan/src/glslang/spirv/SpvTools.cpp new file mode 100644 index 00000000000..8acf9b139a1 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/spirv/SpvTools.cpp @@ -0,0 +1,244 @@ +// +// Copyright (C) 2014-2016 LunarG, Inc. +// Copyright (C) 2018-2020 Google, Inc. +// +// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. + +// +// Call into SPIRV-Tools to disassemble, validate, and optimize. +// + +#if ENABLE_OPT + +#include +#include + +#include "SpvTools.h" +#include "spirv-tools/optimizer.hpp" + +namespace glslang { + +// Translate glslang's view of target versioning to what SPIRV-Tools uses. +spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger) +{ + switch (spvVersion.vulkan) { + case glslang::EShTargetVulkan_1_0: + return spv_target_env::SPV_ENV_VULKAN_1_0; + case glslang::EShTargetVulkan_1_1: + switch (spvVersion.spv) { + case EShTargetSpv_1_0: + case EShTargetSpv_1_1: + case EShTargetSpv_1_2: + case EShTargetSpv_1_3: + return spv_target_env::SPV_ENV_VULKAN_1_1; + case EShTargetSpv_1_4: + return spv_target_env::SPV_ENV_VULKAN_1_1_SPIRV_1_4; + default: + logger->missingFunctionality("Target version for SPIRV-Tools validator"); + return spv_target_env::SPV_ENV_VULKAN_1_1; + } + case glslang::EShTargetVulkan_1_2: + return spv_target_env::SPV_ENV_VULKAN_1_2; + default: + break; + } + + if (spvVersion.openGl > 0) + return spv_target_env::SPV_ENV_OPENGL_4_5; + + logger->missingFunctionality("Target version for SPIRV-Tools validator"); + return spv_target_env::SPV_ENV_UNIVERSAL_1_0; +} + +// Callback passed to spvtools::Optimizer::SetMessageConsumer +void OptimizerMesssageConsumer(spv_message_level_t level, const char *source, + const spv_position_t &position, const char *message) +{ + auto &out = std::cerr; + switch (level) + { + case SPV_MSG_FATAL: + case SPV_MSG_INTERNAL_ERROR: + case SPV_MSG_ERROR: + out << "error: "; + break; + case SPV_MSG_WARNING: + out << "warning: "; + break; + case SPV_MSG_INFO: + case SPV_MSG_DEBUG: + out << "info: "; + break; + default: + break; + } + if (source) + { + out << source << ":"; + } + out << position.line << ":" << position.column << ":" << position.index << ":"; + if (message) + { + out << " " << message; + } + out << std::endl; +} + +// Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment. +void SpirvToolsDisassemble(std::ostream& out, const std::vector& spirv) +{ + SpirvToolsDisassemble(out, spirv, spv_target_env::SPV_ENV_UNIVERSAL_1_3); +} + +// Use the SPIRV-Tools disassembler to print SPIR-V with a provided SPIR-V environment. +void SpirvToolsDisassemble(std::ostream& out, const std::vector& spirv, + spv_target_env requested_context) +{ + // disassemble + spv_context context = spvContextCreate(requested_context); + spv_text text; + spv_diagnostic diagnostic = nullptr; + spvBinaryToText(context, spirv.data(), spirv.size(), + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT, + &text, &diagnostic); + + // dump + if (diagnostic == nullptr) + out << text->str; + else + spvDiagnosticPrint(diagnostic); + + // teardown + spvDiagnosticDestroy(diagnostic); + spvContextDestroy(context); +} + +// Apply the SPIRV-Tools validator to generated SPIR-V. +void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector& spirv, + spv::SpvBuildLogger* logger, bool prelegalization) +{ + // validate + spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger)); + spv_const_binary_t binary = { spirv.data(), spirv.size() }; + spv_diagnostic diagnostic = nullptr; + spv_validator_options options = spvValidatorOptionsCreate(); + spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets()); + spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization); + spvValidatorOptionsSetScalarBlockLayout(options, intermediate.usingScalarBlockLayout()); + spvValidatorOptionsSetWorkgroupScalarBlockLayout(options, intermediate.usingScalarBlockLayout()); + spvValidateWithOptions(context, options, &binary, &diagnostic); + + // report + if (diagnostic != nullptr) { + logger->error("SPIRV-Tools Validation Errors"); + logger->error(diagnostic->error); + } + + // tear down + spvValidatorOptionsDestroy(options); + spvDiagnosticDestroy(diagnostic); + spvContextDestroy(context); +} + +// Apply the SPIRV-Tools optimizer to generated SPIR-V. HLSL SPIR-V is legalized in the process. +void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector& spirv, + spv::SpvBuildLogger* logger, const SpvOptions* options) +{ + spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger); + + spvtools::Optimizer optimizer(target_env); + optimizer.SetMessageConsumer(OptimizerMesssageConsumer); + + // If debug (specifically source line info) is being generated, propagate + // line information into all SPIR-V instructions. This avoids loss of + // information when instructions are deleted or moved. Later, remove + // redundant information to minimize final SPRIR-V size. + if (options->stripDebugInfo) { + optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass()); + } + optimizer.RegisterPass(spvtools::CreateWrapOpKillPass()); + optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass()); + optimizer.RegisterPass(spvtools::CreateMergeReturnPass()); + optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass()); + optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass()); + optimizer.RegisterPass(spvtools::CreateScalarReplacementPass()); + optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass()); + optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass()); + optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass()); + optimizer.RegisterPass(spvtools::CreateSimplificationPass()); + optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); + optimizer.RegisterPass(spvtools::CreateVectorDCEPass()); + optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass()); + optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); + optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass()); + optimizer.RegisterPass(spvtools::CreateBlockMergePass()); + optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass()); + optimizer.RegisterPass(spvtools::CreateIfConversionPass()); + optimizer.RegisterPass(spvtools::CreateSimplificationPass()); + optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); + optimizer.RegisterPass(spvtools::CreateVectorDCEPass()); + optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass()); + optimizer.RegisterPass(spvtools::CreateInterpolateFixupPass()); + if (options->optimizeSize) { + optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass()); + } + optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); + optimizer.RegisterPass(spvtools::CreateCFGCleanupPass()); + + spvtools::OptimizerOptions spvOptOptions; + optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger)); + spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on + optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); +} + +// Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by +// SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if +// optimization is disabled. +void SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate, + std::vector& spirv, spv::SpvBuildLogger* logger) +{ + spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger); + + spvtools::Optimizer optimizer(target_env); + optimizer.SetMessageConsumer(OptimizerMesssageConsumer); + + optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass()); + + spvtools::OptimizerOptions spvOptOptions; + optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger)); + spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on + optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); +} + +}; // end namespace glslang + +#endif diff --git a/libraries/ZVulkan/src/glslang/spirv/SpvTools.h b/libraries/ZVulkan/src/glslang/spirv/SpvTools.h new file mode 100644 index 00000000000..d856c523691 --- /dev/null +++ b/libraries/ZVulkan/src/glslang/spirv/SpvTools.h @@ -0,0 +1,93 @@ +// +// Copyright (C) 2014-2016 LunarG, Inc. +// Copyright (C) 2018 Google, Inc. +// +// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. + +// +// Call into SPIRV-Tools to disassemble, validate, and optimize. +// + +#pragma once +#ifndef GLSLANG_SPV_TOOLS_H +#define GLSLANG_SPV_TOOLS_H + +#if ENABLE_OPT +#include +#include +#include "spirv-tools/libspirv.h" +#endif + +#include "../glslang/MachineIndependent/localintermediate.h" +#include "Logger.h" + +namespace glslang { + +struct SpvOptions { + SpvOptions() : generateDebugInfo(false), stripDebugInfo(false), disableOptimizer(true), + optimizeSize(false), disassemble(false), validate(false) { } + bool generateDebugInfo; + bool stripDebugInfo; + bool disableOptimizer; + bool optimizeSize; + bool disassemble; + bool validate; +}; + +#if ENABLE_OPT + +// Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment. +void SpirvToolsDisassemble(std::ostream& out, const std::vector& spirv); + +// Use the SPIRV-Tools disassembler to print SPIR-V with a provided SPIR-V environment. +void SpirvToolsDisassemble(std::ostream& out, const std::vector& spirv, + spv_target_env requested_context); + +// Apply the SPIRV-Tools validator to generated SPIR-V. +void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector& spirv, + spv::SpvBuildLogger*, bool prelegalization); + +// Apply the SPIRV-Tools optimizer to generated SPIR-V. HLSL SPIR-V is legalized in the process. +void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector& spirv, + spv::SpvBuildLogger*, const SpvOptions*); + +// Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by +// SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if +// optimization is disabled. +void SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate, + std::vector& spirv, spv::SpvBuildLogger*); + +#endif + +} // end namespace glslang + +#endif // GLSLANG_SPV_TOOLS_H diff --git a/libraries/glslang/spirv/bitutils.h b/libraries/ZVulkan/src/glslang/spirv/bitutils.h similarity index 100% rename from libraries/glslang/spirv/bitutils.h rename to libraries/ZVulkan/src/glslang/spirv/bitutils.h diff --git a/libraries/glslang/spirv/disassemble.cpp b/libraries/ZVulkan/src/glslang/spirv/disassemble.cpp similarity index 97% rename from libraries/glslang/spirv/disassemble.cpp rename to libraries/ZVulkan/src/glslang/spirv/disassemble.cpp index 930e7994936..73c988c5b32 100644 --- a/libraries/glslang/spirv/disassemble.cpp +++ b/libraries/ZVulkan/src/glslang/spirv/disassemble.cpp @@ -46,7 +46,6 @@ #include "disassemble.h" #include "doc.h" -#include "SpvTools.h" namespace spv { extern "C" { @@ -75,6 +74,7 @@ enum ExtInstSet { GLSLextAMDInst, GLSLextNVInst, OpenCLExtInst, + NonSemanticDebugPrintfExtInst, }; // Container class for a single instance of a SPIR-V stream, with methods for disassembly. @@ -480,8 +480,12 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, if (opCode == OpExtInst) { ExtInstSet extInstSet = GLSL450Inst; const char* name = idDescriptor[stream[word - 2]].c_str(); - if (0 == memcmp("OpenCL", name, 6)) { + if (strcmp("OpenCL.std", name) == 0) { extInstSet = OpenCLExtInst; + } else if (strcmp("OpenCL.DebugInfo.100", name) == 0) { + extInstSet = OpenCLExtInst; + } else if (strcmp("NonSemantic.DebugPrintf", name) == 0) { + extInstSet = NonSemanticDebugPrintfExtInst; } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 || strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 || strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 || @@ -505,6 +509,8 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, } else if (extInstSet == GLSLextNVInst) { out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")"; + } else if (extInstSet == NonSemanticDebugPrintfExtInst) { + out << "(DebugPrintf)"; } } break; @@ -512,6 +518,10 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, case OperandLiteralString: numOperands -= disassembleString(); break; + case OperandVariableLiteralStrings: + while (numOperands > 0) + numOperands -= disassembleString(); + return; case OperandMemoryAccess: outputMask(OperandMemoryAccess, stream[word++]); --numOperands; diff --git a/libraries/glslang/spirv/disassemble.h b/libraries/ZVulkan/src/glslang/spirv/disassemble.h similarity index 100% rename from libraries/glslang/spirv/disassemble.h rename to libraries/ZVulkan/src/glslang/spirv/disassemble.h diff --git a/libraries/glslang/spirv/doc.cpp b/libraries/ZVulkan/src/glslang/spirv/doc.cpp similarity index 86% rename from libraries/glslang/spirv/doc.cpp rename to libraries/ZVulkan/src/glslang/spirv/doc.cpp index bee5c79729d..dbdf7077a60 100644 --- a/libraries/glslang/spirv/doc.cpp +++ b/libraries/ZVulkan/src/glslang/spirv/doc.cpp @@ -1,5 +1,6 @@ // // Copyright (C) 2014-2015 LunarG, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -99,12 +100,12 @@ const char* ExecutionModelString(int model) default: return "Bad"; - case ExecutionModelRayGenerationNV: return "RayGenerationNV"; - case ExecutionModelIntersectionNV: return "IntersectionNV"; - case ExecutionModelAnyHitNV: return "AnyHitNV"; - case ExecutionModelClosestHitNV: return "ClosestHitNV"; - case ExecutionModelMissNV: return "MissNV"; - case ExecutionModelCallableNV: return "CallableNV"; + case ExecutionModelRayGenerationKHR: return "RayGenerationKHR"; + case ExecutionModelIntersectionKHR: return "IntersectionKHR"; + case ExecutionModelAnyHitKHR: return "AnyHitKHR"; + case ExecutionModelClosestHitKHR: return "ClosestHitKHR"; + case ExecutionModelMissKHR: return "MissKHR"; + case ExecutionModelCallableKHR: return "CallableKHR"; } } @@ -133,7 +134,7 @@ const char* MemoryString(int mem) } } -const int ExecutionModeCeiling = 33; +const int ExecutionModeCeiling = 40; const char* ExecutionModeString(int mode) { @@ -172,7 +173,22 @@ const char* ExecutionModeString(int mode) case 31: return "ContractionOff"; case 32: return "Bad"; - case 4446: return "PostDepthCoverage"; + case ExecutionModeInitializer: return "Initializer"; + case ExecutionModeFinalizer: return "Finalizer"; + case ExecutionModeSubgroupSize: return "SubgroupSize"; + case ExecutionModeSubgroupsPerWorkgroup: return "SubgroupsPerWorkgroup"; + case ExecutionModeSubgroupsPerWorkgroupId: return "SubgroupsPerWorkgroupId"; + case ExecutionModeLocalSizeId: return "LocalSizeId"; + case ExecutionModeLocalSizeHintId: return "LocalSizeHintId"; + + case ExecutionModePostDepthCoverage: return "PostDepthCoverage"; + case ExecutionModeDenormPreserve: return "DenormPreserve"; + case ExecutionModeDenormFlushToZero: return "DenormFlushToZero"; + case ExecutionModeSignedZeroInfNanPreserve: return "SignedZeroInfNanPreserve"; + case ExecutionModeRoundingModeRTE: return "RoundingModeRTE"; + case ExecutionModeRoundingModeRTZ: return "RoundingModeRTZ"; + case ExecutionModeStencilRefReplacingEXT: return "StencilRefReplacingEXT"; + case ExecutionModeSubgroupUniformControlFlowKHR: return "SubgroupUniformControlFlow"; case ExecutionModeOutputLinesNV: return "OutputLinesNV"; case ExecutionModeOutputPrimitivesNV: return "OutputPrimitivesNV"; @@ -187,6 +203,11 @@ const char* ExecutionModeString(int mode) case ExecutionModeShadingRateInterlockOrderedEXT: return "ShadingRateInterlockOrderedEXT"; case ExecutionModeShadingRateInterlockUnorderedEXT: return "ShadingRateInterlockUnorderedEXT"; + case ExecutionModeMaxWorkgroupSizeINTEL: return "MaxWorkgroupSizeINTEL"; + case ExecutionModeMaxWorkDimINTEL: return "MaxWorkDimINTEL"; + case ExecutionModeNoGlobalOffsetINTEL: return "NoGlobalOffsetINTEL"; + case ExecutionModeNumSIMDWorkitemsINTEL: return "NumSIMDWorkitemsINTEL"; + case ExecutionModeCeiling: default: return "Bad"; } @@ -209,12 +230,12 @@ const char* StorageClassString(int StorageClass) case 11: return "Image"; case 12: return "StorageBuffer"; - case StorageClassRayPayloadNV: return "RayPayloadNV"; - case StorageClassHitAttributeNV: return "HitAttributeNV"; - case StorageClassIncomingRayPayloadNV: return "IncomingRayPayloadNV"; - case StorageClassShaderRecordBufferNV: return "ShaderRecordBufferNV"; - case StorageClassCallableDataNV: return "CallableDataNV"; - case StorageClassIncomingCallableDataNV: return "IncomingCallableDataNV"; + case StorageClassRayPayloadKHR: return "RayPayloadKHR"; + case StorageClassHitAttributeKHR: return "HitAttributeKHR"; + case StorageClassIncomingRayPayloadKHR: return "IncomingRayPayloadKHR"; + case StorageClassShaderRecordBufferKHR: return "ShaderRecordBufferKHR"; + case StorageClassCallableDataKHR: return "CallableDataKHR"; + case StorageClassIncomingCallableDataKHR: return "IncomingCallableDataKHR"; case StorageClassPhysicalStorageBufferEXT: return "PhysicalStorageBufferEXT"; @@ -352,6 +373,8 @@ const char* BuiltInString(int builtIn) case 4424: return "BaseVertex"; case 4425: return "BaseInstance"; case 4426: return "DrawIndex"; + case 4432: return "PrimitiveShadingRateKHR"; + case 4444: return "ShadingRateKHR"; case 5014: return "FragStencilRefEXT"; case 4992: return "BaryCoordNoPerspAMD"; @@ -361,32 +384,33 @@ const char* BuiltInString(int builtIn) case 4996: return "BaryCoordSmoothCentroidAMD"; case 4997: return "BaryCoordSmoothSampleAMD"; case 4998: return "BaryCoordPullModelAMD"; - case BuiltInLaunchIdNV: return "LaunchIdNV"; - case BuiltInLaunchSizeNV: return "LaunchSizeNV"; - case BuiltInWorldRayOriginNV: return "WorldRayOriginNV"; - case BuiltInWorldRayDirectionNV: return "WorldRayDirectionNV"; - case BuiltInObjectRayOriginNV: return "ObjectRayOriginNV"; - case BuiltInObjectRayDirectionNV: return "ObjectRayDirectionNV"; - case BuiltInRayTminNV: return "RayTminNV"; - case BuiltInRayTmaxNV: return "RayTmaxNV"; - case BuiltInInstanceCustomIndexNV: return "InstanceCustomIndexNV"; - case BuiltInObjectToWorldNV: return "ObjectToWorldNV"; - case BuiltInWorldToObjectNV: return "WorldToObjectNV"; - case BuiltInHitTNV: return "HitTNV"; - case BuiltInHitKindNV: return "HitKindNV"; - case BuiltInIncomingRayFlagsNV: return "IncomingRayFlagsNV"; - case BuiltInViewportMaskNV: return "ViewportMaskNV"; - case BuiltInSecondaryPositionNV: return "SecondaryPositionNV"; - case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV"; - case BuiltInPositionPerViewNV: return "PositionPerViewNV"; - case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV"; + case BuiltInLaunchIdKHR: return "LaunchIdKHR"; + case BuiltInLaunchSizeKHR: return "LaunchSizeKHR"; + case BuiltInWorldRayOriginKHR: return "WorldRayOriginKHR"; + case BuiltInWorldRayDirectionKHR: return "WorldRayDirectionKHR"; + case BuiltInObjectRayOriginKHR: return "ObjectRayOriginKHR"; + case BuiltInObjectRayDirectionKHR: return "ObjectRayDirectionKHR"; + case BuiltInRayTminKHR: return "RayTminKHR"; + case BuiltInRayTmaxKHR: return "RayTmaxKHR"; + case BuiltInInstanceCustomIndexKHR: return "InstanceCustomIndexKHR"; + case BuiltInRayGeometryIndexKHR: return "RayGeometryIndexKHR"; + case BuiltInObjectToWorldKHR: return "ObjectToWorldKHR"; + case BuiltInWorldToObjectKHR: return "WorldToObjectKHR"; + case BuiltInHitTNV: return "HitTNV"; + case BuiltInHitKindKHR: return "HitKindKHR"; + case BuiltInIncomingRayFlagsKHR: return "IncomingRayFlagsKHR"; + case BuiltInViewportMaskNV: return "ViewportMaskNV"; + case BuiltInSecondaryPositionNV: return "SecondaryPositionNV"; + case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV"; + case BuiltInPositionPerViewNV: return "PositionPerViewNV"; + case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV"; // case BuiltInFragmentSizeNV: return "FragmentSizeNV"; // superseded by BuiltInFragSizeEXT // case BuiltInInvocationsPerPixelNV: return "InvocationsPerPixelNV"; // superseded by BuiltInFragInvocationCountEXT - case BuiltInBaryCoordNV: return "BaryCoordNV"; - case BuiltInBaryCoordNoPerspNV: return "BaryCoordNoPerspNV"; + case BuiltInBaryCoordNV: return "BaryCoordNV"; + case BuiltInBaryCoordNoPerspNV: return "BaryCoordNoPerspNV"; - case BuiltInFragSizeEXT: return "FragSizeEXT"; - case BuiltInFragInvocationCountEXT: return "FragInvocationCountEXT"; + case BuiltInFragSizeEXT: return "FragSizeEXT"; + case BuiltInFragInvocationCountEXT: return "FragInvocationCountEXT"; case 5264: return "FullyCoveredEXT"; @@ -402,6 +426,7 @@ const char* BuiltInString(int builtIn) case BuiltInSMCountNV: return "SMCountNV"; case BuiltInWarpIDNV: return "WarpIDNV"; case BuiltInSMIDNV: return "SMIDNV"; + case BuiltInCurrentRayTimeNV: return "CurrentRayTimeNV"; default: return "Bad"; } @@ -500,6 +525,8 @@ const char* ImageFormatString(int format) case 37: return "Rg8ui"; case 38: return "R16ui"; case 39: return "R8ui"; + case 40: return "R64ui"; + case 41: return "R64i"; default: return "Bad"; @@ -890,6 +917,11 @@ const char* CapabilityString(int info) case CapabilityPerViewAttributesNV: return "PerViewAttributesNV"; case CapabilityGroupNonUniformPartitionedNV: return "GroupNonUniformPartitionedNV"; case CapabilityRayTracingNV: return "RayTracingNV"; + case CapabilityRayTracingMotionBlurNV: return "RayTracingMotionBlurNV"; + case CapabilityRayTracingKHR: return "RayTracingKHR"; + case CapabilityRayQueryKHR: return "RayQueryKHR"; + case CapabilityRayTracingProvisionalKHR: return "RayTracingProvisionalKHR"; + case CapabilityRayTraversalPrimitiveCullingKHR: return "RayTraversalPrimitiveCullingKHR"; case CapabilityComputeDerivativeGroupQuadsNV: return "ComputeDerivativeGroupQuadsNV"; case CapabilityComputeDerivativeGroupLinearNV: return "ComputeDerivativeGroupLinearNV"; case CapabilityFragmentBarycentricNV: return "FragmentBarycentricNV"; @@ -928,11 +960,25 @@ const char* CapabilityString(int info) case CapabilityFragmentShaderPixelInterlockEXT: return "CapabilityFragmentShaderPixelInterlockEXT"; case CapabilityFragmentShaderShadingRateInterlockEXT: return "CapabilityFragmentShaderShadingRateInterlockEXT"; + case CapabilityFragmentShadingRateKHR: return "FragmentShadingRateKHR"; + case CapabilityDemoteToHelperInvocationEXT: return "DemoteToHelperInvocationEXT"; case CapabilityShaderClockKHR: return "ShaderClockKHR"; + case CapabilityInt64ImageEXT: return "Int64ImageEXT"; case CapabilityIntegerFunctions2INTEL: return "CapabilityIntegerFunctions2INTEL"; + case CapabilityAtomicFloat16AddEXT: return "AtomicFloat16AddEXT"; + case CapabilityAtomicFloat32AddEXT: return "AtomicFloat32AddEXT"; + case CapabilityAtomicFloat64AddEXT: return "AtomicFloat64AddEXT"; + case CapabilityAtomicFloat16MinMaxEXT: return "AtomicFloat16MinMaxEXT"; + case CapabilityAtomicFloat32MinMaxEXT: return "AtomicFloat32MinMaxEXT"; + case CapabilityAtomicFloat64MinMaxEXT: return "AtomicFloat64MinMaxEXT"; + + case CapabilityWorkgroupMemoryExplicitLayoutKHR: return "CapabilityWorkgroupMemoryExplicitLayoutKHR"; + case CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR: return "CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR"; + case CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR: return "CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR"; + default: return "Bad"; } } @@ -1264,6 +1310,7 @@ const char* OpcodeString(int op) case 320: return "OpImageSparseRead"; case OpModuleProcessed: return "OpModuleProcessed"; + case OpExecutionModeId: return "OpExecutionModeId"; case OpDecorateId: return "OpDecorateId"; case 333: return "OpGroupNonUniformElect"; @@ -1301,6 +1348,8 @@ const char* OpcodeString(int op) case 365: return "OpGroupNonUniformQuadBroadcast"; case 366: return "OpGroupNonUniformQuadSwap"; + case OpTerminateInvocation: return "OpTerminateInvocation"; + case 4421: return "OpSubgroupBallotKHR"; case 4422: return "OpSubgroupFirstInvocationKHR"; case 4428: return "OpSubgroupAllKHR"; @@ -1308,6 +1357,10 @@ const char* OpcodeString(int op) case 4430: return "OpSubgroupAllEqualKHR"; case 4432: return "OpSubgroupReadInvocationKHR"; + case OpAtomicFAddEXT: return "OpAtomicFAddEXT"; + case OpAtomicFMinEXT: return "OpAtomicFMinEXT"; + case OpAtomicFMaxEXT: return "OpAtomicFMaxEXT"; + case 5000: return "OpGroupIAddNonUniformAMD"; case 5001: return "OpGroupFAddNonUniformAMD"; case 5002: return "OpGroupFMinNonUniformAMD"; @@ -1325,16 +1378,48 @@ const char* OpcodeString(int op) case OpDecorateStringGOOGLE: return "OpDecorateStringGOOGLE"; case OpMemberDecorateStringGOOGLE: return "OpMemberDecorateStringGOOGLE"; + case OpReportIntersectionKHR: return "OpReportIntersectionKHR"; + case OpIgnoreIntersectionNV: return "OpIgnoreIntersectionNV"; + case OpIgnoreIntersectionKHR: return "OpIgnoreIntersectionKHR"; + case OpTerminateRayNV: return "OpTerminateRayNV"; + case OpTerminateRayKHR: return "OpTerminateRayKHR"; + case OpTraceNV: return "OpTraceNV"; + case OpTraceRayMotionNV: return "OpTraceRayMotionNV"; + case OpTraceRayKHR: return "OpTraceRayKHR"; + case OpTypeAccelerationStructureKHR: return "OpTypeAccelerationStructureKHR"; + case OpExecuteCallableNV: return "OpExecuteCallableNV"; + case OpExecuteCallableKHR: return "OpExecuteCallableKHR"; + case OpConvertUToAccelerationStructureKHR: return "OpConvertUToAccelerationStructureKHR"; + case OpGroupNonUniformPartitionNV: return "OpGroupNonUniformPartitionNV"; - case OpReportIntersectionNV: return "OpReportIntersectionNV"; - case OpIgnoreIntersectionNV: return "OpIgnoreIntersectionNV"; - case OpTerminateRayNV: return "OpTerminateRayNV"; - case OpTraceNV: return "OpTraceNV"; - case OpTypeAccelerationStructureNV: return "OpTypeAccelerationStructureNV"; - case OpExecuteCallableNV: return "OpExecuteCallableNV"; case OpImageSampleFootprintNV: return "OpImageSampleFootprintNV"; case OpWritePackedPrimitiveIndices4x8NV: return "OpWritePackedPrimitiveIndices4x8NV"; + case OpTypeRayQueryKHR: return "OpTypeRayQueryKHR"; + case OpRayQueryInitializeKHR: return "OpRayQueryInitializeKHR"; + case OpRayQueryTerminateKHR: return "OpRayQueryTerminateKHR"; + case OpRayQueryGenerateIntersectionKHR: return "OpRayQueryGenerateIntersectionKHR"; + case OpRayQueryConfirmIntersectionKHR: return "OpRayQueryConfirmIntersectionKHR"; + case OpRayQueryProceedKHR: return "OpRayQueryProceedKHR"; + case OpRayQueryGetIntersectionTypeKHR: return "OpRayQueryGetIntersectionTypeKHR"; + case OpRayQueryGetRayTMinKHR: return "OpRayQueryGetRayTMinKHR"; + case OpRayQueryGetRayFlagsKHR: return "OpRayQueryGetRayFlagsKHR"; + case OpRayQueryGetIntersectionTKHR: return "OpRayQueryGetIntersectionTKHR"; + case OpRayQueryGetIntersectionInstanceCustomIndexKHR: return "OpRayQueryGetIntersectionInstanceCustomIndexKHR"; + case OpRayQueryGetIntersectionInstanceIdKHR: return "OpRayQueryGetIntersectionInstanceIdKHR"; + case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: return "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR"; + case OpRayQueryGetIntersectionGeometryIndexKHR: return "OpRayQueryGetIntersectionGeometryIndexKHR"; + case OpRayQueryGetIntersectionPrimitiveIndexKHR: return "OpRayQueryGetIntersectionPrimitiveIndexKHR"; + case OpRayQueryGetIntersectionBarycentricsKHR: return "OpRayQueryGetIntersectionBarycentricsKHR"; + case OpRayQueryGetIntersectionFrontFaceKHR: return "OpRayQueryGetIntersectionFrontFaceKHR"; + case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: return "OpRayQueryGetIntersectionCandidateAABBOpaqueKHR"; + case OpRayQueryGetIntersectionObjectRayDirectionKHR: return "OpRayQueryGetIntersectionObjectRayDirectionKHR"; + case OpRayQueryGetIntersectionObjectRayOriginKHR: return "OpRayQueryGetIntersectionObjectRayOriginKHR"; + case OpRayQueryGetWorldRayDirectionKHR: return "OpRayQueryGetWorldRayDirectionKHR"; + case OpRayQueryGetWorldRayOriginKHR: return "OpRayQueryGetWorldRayOriginKHR"; + case OpRayQueryGetIntersectionObjectToWorldKHR: return "OpRayQueryGetIntersectionObjectToWorldKHR"; + case OpRayQueryGetIntersectionWorldToObjectKHR: return "OpRayQueryGetIntersectionWorldToObjectKHR"; + case OpTypeCooperativeMatrixNV: return "OpTypeCooperativeMatrixNV"; case OpCooperativeMatrixLoadNV: return "OpCooperativeMatrixLoadNV"; case OpCooperativeMatrixStoreNV: return "OpCooperativeMatrixStoreNV"; @@ -1388,6 +1473,7 @@ void Parameterize() InstructionDesc[OpMemoryModel].setResultAndType(false, false); InstructionDesc[OpEntryPoint].setResultAndType(false, false); InstructionDesc[OpExecutionMode].setResultAndType(false, false); + InstructionDesc[OpExecutionModeId].setResultAndType(false, false); InstructionDesc[OpTypeVoid].setResultAndType(true, false); InstructionDesc[OpTypeBool].setResultAndType(true, false); InstructionDesc[OpTypeInt].setResultAndType(true, false); @@ -1441,6 +1527,7 @@ void Parameterize() InstructionDesc[OpBranchConditional].setResultAndType(false, false); InstructionDesc[OpSwitch].setResultAndType(false, false); InstructionDesc[OpKill].setResultAndType(false, false); + InstructionDesc[OpTerminateInvocation].setResultAndType(false, false); InstructionDesc[OpReturn].setResultAndType(false, false); InstructionDesc[OpReturnValue].setResultAndType(false, false); InstructionDesc[OpUnreachable].setResultAndType(false, false); @@ -1574,6 +1661,10 @@ void Parameterize() InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'"); InstructionDesc[OpExecutionMode].operands.push(OperandOptionalLiteral, "See <>"); + InstructionDesc[OpExecutionModeId].operands.push(OperandId, "'Entry Point'"); + InstructionDesc[OpExecutionModeId].operands.push(OperandExecutionMode, "'Mode'"); + InstructionDesc[OpExecutionModeId].operands.push(OperandVariableIds, "See <>"); + InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'"); InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'"); @@ -1667,7 +1758,7 @@ void Parameterize() InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandId, "'Target'"); InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandDecoration, ""); - InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandLiteralString, "'Literal String'"); + InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandVariableLiteralStrings, "'Literal Strings'"); InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure Type'"); InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'"); @@ -1677,7 +1768,7 @@ void Parameterize() InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandId, "'Structure Type'"); InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandLiteralNumber, "'Member'"); InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandDecoration, ""); - InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandLiteralString, "'Literal String'"); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandVariableLiteralStrings, "'Literal Strings'"); InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration Group'"); InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Targets'"); @@ -2230,6 +2321,11 @@ void Parameterize() InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'"); InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicFAddEXT].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicFAddEXT].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicFAddEXT].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicFAddEXT].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpAtomicISub].operands.push(OperandScope, "'Scope'"); InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'"); @@ -2255,6 +2351,16 @@ void Parameterize() InstructionDesc[OpAtomicSMax].operands.push(OperandMemorySemantics, "'Semantics'"); InstructionDesc[OpAtomicSMax].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicFMinEXT].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicFMinEXT].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicFMinEXT].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicFMinEXT].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpAtomicAnd].operands.push(OperandScope, "'Scope'"); InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'"); @@ -2633,7 +2739,7 @@ void Parameterize() InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandLiteralNumber, "'Direction'"); + InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandId, "'Direction'"); InstructionDesc[OpSubgroupBallotKHR].operands.push(OperandId, "'Predicate'"); @@ -2694,9 +2800,9 @@ void Parameterize() InstructionDesc[OpGroupNonUniformPartitionNV].operands.push(OperandId, "X"); - InstructionDesc[OpTypeAccelerationStructureNV].setResultAndType(true, false); + InstructionDesc[OpTypeAccelerationStructureKHR].setResultAndType(true, false); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'NV Acceleration Structure'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'Acceleration Structure'"); InstructionDesc[OpTraceNV].operands.push(OperandId, "'Ray Flags'"); InstructionDesc[OpTraceNV].operands.push(OperandId, "'Cull Mask'"); InstructionDesc[OpTraceNV].operands.push(OperandId, "'SBT Record Offset'"); @@ -2709,17 +2815,149 @@ void Parameterize() InstructionDesc[OpTraceNV].operands.push(OperandId, "'Payload'"); InstructionDesc[OpTraceNV].setResultAndType(false, false); - InstructionDesc[OpReportIntersectionNV].operands.push(OperandId, "'Hit Parameter'"); - InstructionDesc[OpReportIntersectionNV].operands.push(OperandId, "'Hit Kind'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Flags'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Cull Mask'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Miss Index'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Origin'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Direction'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Time'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpTraceRayMotionNV].setResultAndType(false, false); + + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Flags'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Cull Mask'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Miss Index'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Origin'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Direction'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpTraceRayKHR].setResultAndType(false, false); + + InstructionDesc[OpReportIntersectionKHR].operands.push(OperandId, "'Hit Parameter'"); + InstructionDesc[OpReportIntersectionKHR].operands.push(OperandId, "'Hit Kind'"); InstructionDesc[OpIgnoreIntersectionNV].setResultAndType(false, false); + InstructionDesc[OpIgnoreIntersectionKHR].setResultAndType(false, false); + InstructionDesc[OpTerminateRayNV].setResultAndType(false, false); + + InstructionDesc[OpTerminateRayKHR].setResultAndType(false, false); InstructionDesc[OpExecuteCallableNV].operands.push(OperandId, "SBT Record Index"); InstructionDesc[OpExecuteCallableNV].operands.push(OperandId, "CallableData ID"); InstructionDesc[OpExecuteCallableNV].setResultAndType(false, false); + InstructionDesc[OpExecuteCallableKHR].operands.push(OperandId, "SBT Record Index"); + InstructionDesc[OpExecuteCallableKHR].operands.push(OperandId, "CallableData"); + InstructionDesc[OpExecuteCallableKHR].setResultAndType(false, false); + + InstructionDesc[OpConvertUToAccelerationStructureKHR].operands.push(OperandId, "Value"); + InstructionDesc[OpConvertUToAccelerationStructureKHR].setResultAndType(true, true); + + // Ray Query + InstructionDesc[OpTypeAccelerationStructureKHR].setResultAndType(true, false); + InstructionDesc[OpTypeRayQueryKHR].setResultAndType(true, false); + + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'AccelerationS'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'RayFlags'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'CullMask'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Tmin'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Tmax'"); + InstructionDesc[OpRayQueryInitializeKHR].setResultAndType(false, false); + + InstructionDesc[OpRayQueryTerminateKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryTerminateKHR].setResultAndType(false, false); + + InstructionDesc[OpRayQueryGenerateIntersectionKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGenerateIntersectionKHR].operands.push(OperandId, "'THit'"); + InstructionDesc[OpRayQueryGenerateIntersectionKHR].setResultAndType(false, false); + + InstructionDesc[OpRayQueryConfirmIntersectionKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryConfirmIntersectionKHR].setResultAndType(false, false); + + InstructionDesc[OpRayQueryProceedKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryProceedKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionTypeKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionTypeKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionTypeKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetRayTMinKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetRayTMinKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetRayFlagsKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetRayFlagsKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionTKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionTKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionTKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionCandidateAABBOpaqueKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionCandidateAABBOpaqueKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetWorldRayDirectionKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetWorldRayDirectionKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetWorldRayOriginKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetWorldRayOriginKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].setResultAndType(true, true); + InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Sampled Image'"); InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Coordinate'"); InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Granularity'"); diff --git a/libraries/glslang/spirv/doc.h b/libraries/ZVulkan/src/glslang/spirv/doc.h similarity index 99% rename from libraries/glslang/spirv/doc.h rename to libraries/ZVulkan/src/glslang/spirv/doc.h index 293256a2c68..2a0b28c6b3a 100644 --- a/libraries/glslang/spirv/doc.h +++ b/libraries/ZVulkan/src/glslang/spirv/doc.h @@ -125,6 +125,7 @@ enum OperandClass { OperandVariableLiteralId, OperandLiteralNumber, OperandLiteralString, + OperandVariableLiteralStrings, OperandSource, OperandExecutionModel, OperandAddressing, diff --git a/libraries/glslang/spirv/hex_float.h b/libraries/ZVulkan/src/glslang/spirv/hex_float.h similarity index 99% rename from libraries/glslang/spirv/hex_float.h rename to libraries/ZVulkan/src/glslang/spirv/hex_float.h index 905b21a45ad..8be8e9f7e36 100644 --- a/libraries/glslang/spirv/hex_float.h +++ b/libraries/ZVulkan/src/glslang/spirv/hex_float.h @@ -784,8 +784,8 @@ inline std::istream& ParseNormalFloat(std::istream& is, bool negate_value, if (val.isInfinity()) { // Fail the parse. Emulate standard behaviour by setting the value to // the closest normal value, and set the fail bit on the stream. - value.set_value((value.isNegative() | negate_value) ? T::lowest() - : T::max()); + value.set_value((value.isNegative() || negate_value) ? T::lowest() + : T::max()); is.setstate(std::ios_base::failbit); } return is; diff --git a/libraries/glslang/spirv/spirv.hpp b/libraries/ZVulkan/src/glslang/spirv/spirv.hpp similarity index 85% rename from libraries/glslang/spirv/spirv.hpp rename to libraries/ZVulkan/src/glslang/spirv/spirv.hpp index 1e96f7b4a96..e0fe24980d3 100644 --- a/libraries/glslang/spirv/spirv.hpp +++ b/libraries/ZVulkan/src/glslang/spirv/spirv.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Khronos Group Inc. +// Copyright (c) 2014-2020 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), @@ -49,12 +49,12 @@ namespace spv { typedef unsigned int Id; -#define SPV_VERSION 0x10400 -#define SPV_REVISION 1 +#define SPV_VERSION 0x10500 +#define SPV_REVISION 4 static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010400; -static const unsigned int Revision = 1; +static const unsigned int Version = 0x00010500; +static const unsigned int Revision = 4; static const unsigned int OpCodeMask = 0xffff; static const unsigned int WordCountShift = 16; @@ -78,11 +78,17 @@ enum ExecutionModel { ExecutionModelKernel = 6, ExecutionModelTaskNV = 5267, ExecutionModelMeshNV = 5268, + ExecutionModelRayGenerationKHR = 5313, ExecutionModelRayGenerationNV = 5313, + ExecutionModelIntersectionKHR = 5314, ExecutionModelIntersectionNV = 5314, + ExecutionModelAnyHitKHR = 5315, ExecutionModelAnyHitNV = 5315, + ExecutionModelClosestHitKHR = 5316, ExecutionModelClosestHitNV = 5316, + ExecutionModelMissKHR = 5317, ExecutionModelMissNV = 5317, + ExecutionModelCallableKHR = 5318, ExecutionModelCallableNV = 5318, ExecutionModelMax = 0x7fffffff, }; @@ -144,6 +150,7 @@ enum ExecutionMode { ExecutionModeSubgroupsPerWorkgroupId = 37, ExecutionModeLocalSizeId = 38, ExecutionModeLocalSizeHintId = 39, + ExecutionModeSubgroupUniformControlFlowKHR = 4421, ExecutionModePostDepthCoverage = 4446, ExecutionModeDenormPreserve = 4459, ExecutionModeDenormFlushToZero = 4460, @@ -162,6 +169,16 @@ enum ExecutionMode { ExecutionModeSampleInterlockUnorderedEXT = 5369, ExecutionModeShadingRateInterlockOrderedEXT = 5370, ExecutionModeShadingRateInterlockUnorderedEXT = 5371, + ExecutionModeSharedLocalMemorySizeINTEL = 5618, + ExecutionModeRoundingModeRTPINTEL = 5620, + ExecutionModeRoundingModeRTNINTEL = 5621, + ExecutionModeFloatingPointModeALTINTEL = 5622, + ExecutionModeFloatingPointModeIEEEINTEL = 5623, + ExecutionModeMaxWorkgroupSizeINTEL = 5893, + ExecutionModeMaxWorkDimINTEL = 5894, + ExecutionModeNoGlobalOffsetINTEL = 5895, + ExecutionModeNumSIMDWorkitemsINTEL = 5896, + ExecutionModeSchedulerTargetFmaxMhzINTEL = 5903, ExecutionModeMax = 0x7fffffff, }; @@ -179,14 +196,23 @@ enum StorageClass { StorageClassAtomicCounter = 10, StorageClassImage = 11, StorageClassStorageBuffer = 12, + StorageClassCallableDataKHR = 5328, StorageClassCallableDataNV = 5328, + StorageClassIncomingCallableDataKHR = 5329, StorageClassIncomingCallableDataNV = 5329, + StorageClassRayPayloadKHR = 5338, StorageClassRayPayloadNV = 5338, + StorageClassHitAttributeKHR = 5339, StorageClassHitAttributeNV = 5339, + StorageClassIncomingRayPayloadKHR = 5342, StorageClassIncomingRayPayloadNV = 5342, + StorageClassShaderRecordBufferKHR = 5343, StorageClassShaderRecordBufferNV = 5343, StorageClassPhysicalStorageBuffer = 5349, StorageClassPhysicalStorageBufferEXT = 5349, + StorageClassCodeSectionINTEL = 5605, + StorageClassDeviceOnlyINTEL = 5936, + StorageClassHostOnlyINTEL = 5937, StorageClassMax = 0x7fffffff, }; @@ -257,6 +283,8 @@ enum ImageFormat { ImageFormatRg8ui = 37, ImageFormatR16ui = 38, ImageFormatR8ui = 39, + ImageFormatR64ui = 40, + ImageFormatR64i = 41, ImageFormatMax = 0x7fffffff, }; @@ -355,6 +383,8 @@ enum FPFastMathModeShift { FPFastMathModeNSZShift = 2, FPFastMathModeAllowRecipShift = 3, FPFastMathModeFastShift = 4, + FPFastMathModeAllowContractFastINTELShift = 16, + FPFastMathModeAllowReassocINTELShift = 17, FPFastMathModeMax = 0x7fffffff, }; @@ -365,6 +395,8 @@ enum FPFastMathModeMask { FPFastMathModeNSZMask = 0x00000004, FPFastMathModeAllowRecipMask = 0x00000008, FPFastMathModeFastMask = 0x00000010, + FPFastMathModeAllowContractFastINTELMask = 0x00010000, + FPFastMathModeAllowReassocINTELMask = 0x00020000, }; enum FPRoundingMode { @@ -378,6 +410,7 @@ enum FPRoundingMode { enum LinkageType { LinkageTypeExport = 0, LinkageTypeImport = 1, + LinkageTypeLinkOnceODR = 2, LinkageTypeMax = 0x7fffffff, }; @@ -465,11 +498,45 @@ enum Decoration { DecorationRestrictPointerEXT = 5355, DecorationAliasedPointer = 5356, DecorationAliasedPointerEXT = 5356, + DecorationSIMTCallINTEL = 5599, + DecorationReferencedIndirectlyINTEL = 5602, + DecorationClobberINTEL = 5607, + DecorationSideEffectsINTEL = 5608, + DecorationVectorComputeVariableINTEL = 5624, + DecorationFuncParamIOKindINTEL = 5625, + DecorationVectorComputeFunctionINTEL = 5626, + DecorationStackCallINTEL = 5627, + DecorationGlobalVariableOffsetINTEL = 5628, DecorationCounterBuffer = 5634, DecorationHlslCounterBufferGOOGLE = 5634, DecorationHlslSemanticGOOGLE = 5635, DecorationUserSemantic = 5635, DecorationUserTypeGOOGLE = 5636, + DecorationFunctionRoundingModeINTEL = 5822, + DecorationFunctionDenormModeINTEL = 5823, + DecorationRegisterINTEL = 5825, + DecorationMemoryINTEL = 5826, + DecorationNumbanksINTEL = 5827, + DecorationBankwidthINTEL = 5828, + DecorationMaxPrivateCopiesINTEL = 5829, + DecorationSinglepumpINTEL = 5830, + DecorationDoublepumpINTEL = 5831, + DecorationMaxReplicatesINTEL = 5832, + DecorationSimpleDualPortINTEL = 5833, + DecorationMergeINTEL = 5834, + DecorationBankBitsINTEL = 5835, + DecorationForcePow2DepthINTEL = 5836, + DecorationBurstCoalesceINTEL = 5899, + DecorationCacheSizeINTEL = 5900, + DecorationDontStaticallyCoalesceINTEL = 5901, + DecorationPrefetchINTEL = 5902, + DecorationStallEnableINTEL = 5905, + DecorationFuseLoopsInFunctionINTEL = 5907, + DecorationBufferLocationINTEL = 5921, + DecorationIOPipeStorageINTEL = 5944, + DecorationFunctionFloatingPointModeINTEL = 6080, + DecorationSingleElementVectorINTEL = 6085, + DecorationVectorComputeCallableFunctionINTEL = 6087, DecorationMax = 0x7fffffff, }; @@ -528,8 +595,10 @@ enum BuiltIn { BuiltInBaseVertex = 4424, BuiltInBaseInstance = 4425, BuiltInDrawIndex = 4426, + BuiltInPrimitiveShadingRateKHR = 4432, BuiltInDeviceIndex = 4438, BuiltInViewIndex = 4440, + BuiltInShadingRateKHR = 4444, BuiltInBaryCoordNoPerspAMD = 4992, BuiltInBaryCoordNoPerspCentroidAMD = 4993, BuiltInBaryCoordNoPerspSampleAMD = 4994, @@ -558,20 +627,35 @@ enum BuiltIn { BuiltInFragmentSizeNV = 5292, BuiltInFragInvocationCountEXT = 5293, BuiltInInvocationsPerPixelNV = 5293, + BuiltInLaunchIdKHR = 5319, BuiltInLaunchIdNV = 5319, + BuiltInLaunchSizeKHR = 5320, BuiltInLaunchSizeNV = 5320, + BuiltInWorldRayOriginKHR = 5321, BuiltInWorldRayOriginNV = 5321, + BuiltInWorldRayDirectionKHR = 5322, BuiltInWorldRayDirectionNV = 5322, + BuiltInObjectRayOriginKHR = 5323, BuiltInObjectRayOriginNV = 5323, + BuiltInObjectRayDirectionKHR = 5324, BuiltInObjectRayDirectionNV = 5324, + BuiltInRayTminKHR = 5325, BuiltInRayTminNV = 5325, + BuiltInRayTmaxKHR = 5326, BuiltInRayTmaxNV = 5326, + BuiltInInstanceCustomIndexKHR = 5327, BuiltInInstanceCustomIndexNV = 5327, + BuiltInObjectToWorldKHR = 5330, BuiltInObjectToWorldNV = 5330, + BuiltInWorldToObjectKHR = 5331, BuiltInWorldToObjectNV = 5331, BuiltInHitTNV = 5332, + BuiltInHitKindKHR = 5333, BuiltInHitKindNV = 5333, + BuiltInCurrentRayTimeNV = 5334, + BuiltInIncomingRayFlagsKHR = 5351, BuiltInIncomingRayFlagsNV = 5351, + BuiltInRayGeometryIndexKHR = 5352, BuiltInWarpsPerSMNV = 5374, BuiltInSMCountNV = 5375, BuiltInWarpIDNV = 5376, @@ -601,6 +685,14 @@ enum LoopControlShift { LoopControlIterationMultipleShift = 6, LoopControlPeelCountShift = 7, LoopControlPartialCountShift = 8, + LoopControlInitiationIntervalINTELShift = 16, + LoopControlMaxConcurrencyINTELShift = 17, + LoopControlDependencyArrayINTELShift = 18, + LoopControlPipelineEnableINTELShift = 19, + LoopControlLoopCoalesceINTELShift = 20, + LoopControlMaxInterleavingINTELShift = 21, + LoopControlSpeculatedIterationsINTELShift = 22, + LoopControlNoFusionINTELShift = 23, LoopControlMax = 0x7fffffff, }; @@ -615,6 +707,14 @@ enum LoopControlMask { LoopControlIterationMultipleMask = 0x00000040, LoopControlPeelCountMask = 0x00000080, LoopControlPartialCountMask = 0x00000100, + LoopControlInitiationIntervalINTELMask = 0x00010000, + LoopControlMaxConcurrencyINTELMask = 0x00020000, + LoopControlDependencyArrayINTELMask = 0x00040000, + LoopControlPipelineEnableINTELMask = 0x00080000, + LoopControlLoopCoalesceINTELMask = 0x00100000, + LoopControlMaxInterleavingINTELMask = 0x00200000, + LoopControlSpeculatedIterationsINTELMask = 0x00400000, + LoopControlNoFusionINTELMask = 0x00800000, }; enum FunctionControlShift { @@ -709,6 +809,7 @@ enum Scope { ScopeInvocation = 4, ScopeQueueFamily = 5, ScopeQueueFamilyKHR = 5, + ScopeShaderCallKHR = 6, ScopeMax = 0x7fffffff, }; @@ -810,8 +911,12 @@ enum Capability { CapabilityGroupNonUniformQuad = 68, CapabilityShaderLayer = 69, CapabilityShaderViewportIndex = 70, + CapabilityFragmentShadingRateKHR = 4422, CapabilitySubgroupBallotKHR = 4423, CapabilityDrawParameters = 4427, + CapabilityWorkgroupMemoryExplicitLayoutKHR = 4428, + CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR = 4429, + CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR = 4430, CapabilitySubgroupVoteKHR = 4431, CapabilityStorageBuffer16BitAccess = 4433, CapabilityStorageUniformBufferBlock16 = 4433, @@ -833,11 +938,16 @@ enum Capability { CapabilitySignedZeroInfNanPreserve = 4466, CapabilityRoundingModeRTE = 4467, CapabilityRoundingModeRTZ = 4468, + CapabilityRayQueryProvisionalKHR = 4471, + CapabilityRayQueryKHR = 4472, + CapabilityRayTraversalPrimitiveCullingKHR = 4478, + CapabilityRayTracingKHR = 4479, CapabilityFloat16ImageAMD = 5008, CapabilityImageGatherBiasLodAMD = 5009, CapabilityFragmentMaskAMD = 5010, CapabilityStencilExportEXT = 5013, CapabilityImageReadWriteLodAMD = 5015, + CapabilityInt64ImageEXT = 5016, CapabilityShaderClockKHR = 5055, CapabilitySampleMaskOverrideCoverageNV = 5249, CapabilityGeometryShaderPassthroughNV = 5251, @@ -879,6 +989,7 @@ enum Capability { CapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, CapabilityRayTracingNV = 5340, + CapabilityRayTracingMotionBlurNV = 5341, CapabilityVulkanMemoryModel = 5345, CapabilityVulkanMemoryModelKHR = 5345, CapabilityVulkanMemoryModelDeviceScope = 5346, @@ -886,6 +997,7 @@ enum Capability { CapabilityPhysicalStorageBufferAddresses = 5347, CapabilityPhysicalStorageBufferAddressesEXT = 5347, CapabilityComputeDerivativeGroupLinearNV = 5350, + CapabilityRayTracingProvisionalKHR = 5353, CapabilityCooperativeMatrixNV = 5357, CapabilityFragmentShaderSampleInterlockEXT = 5363, CapabilityFragmentShaderShadingRateInterlockEXT = 5372, @@ -896,13 +1008,120 @@ enum Capability { CapabilitySubgroupBufferBlockIOINTEL = 5569, CapabilitySubgroupImageBlockIOINTEL = 5570, CapabilitySubgroupImageMediaBlockIOINTEL = 5579, + CapabilityRoundToInfinityINTEL = 5582, + CapabilityFloatingPointModeINTEL = 5583, CapabilityIntegerFunctions2INTEL = 5584, + CapabilityFunctionPointersINTEL = 5603, + CapabilityIndirectReferencesINTEL = 5604, + CapabilityAsmINTEL = 5606, + CapabilityAtomicFloat32MinMaxEXT = 5612, + CapabilityAtomicFloat64MinMaxEXT = 5613, + CapabilityAtomicFloat16MinMaxEXT = 5616, + CapabilityVectorComputeINTEL = 5617, + CapabilityVectorAnyINTEL = 5619, + CapabilityExpectAssumeKHR = 5629, CapabilitySubgroupAvcMotionEstimationINTEL = 5696, CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, + CapabilityVariableLengthArrayINTEL = 5817, + CapabilityFunctionFloatControlINTEL = 5821, + CapabilityFPGAMemoryAttributesINTEL = 5824, + CapabilityFPFastMathModeINTEL = 5837, + CapabilityArbitraryPrecisionIntegersINTEL = 5844, + CapabilityUnstructuredLoopControlsINTEL = 5886, + CapabilityFPGALoopControlsINTEL = 5888, + CapabilityKernelAttributesINTEL = 5892, + CapabilityFPGAKernelAttributesINTEL = 5897, + CapabilityFPGAMemoryAccessesINTEL = 5898, + CapabilityFPGAClusterAttributesINTEL = 5904, + CapabilityLoopFuseINTEL = 5906, + CapabilityFPGABufferLocationINTEL = 5920, + CapabilityUSMStorageClassesINTEL = 5935, + CapabilityIOPipesINTEL = 5943, + CapabilityBlockingPipesINTEL = 5945, + CapabilityFPGARegINTEL = 5948, + CapabilityAtomicFloat32AddEXT = 6033, + CapabilityAtomicFloat64AddEXT = 6034, + CapabilityLongConstantCompositeINTEL = 6089, + CapabilityAtomicFloat16AddEXT = 6095, CapabilityMax = 0x7fffffff, }; +enum RayFlagsShift { + RayFlagsOpaqueKHRShift = 0, + RayFlagsNoOpaqueKHRShift = 1, + RayFlagsTerminateOnFirstHitKHRShift = 2, + RayFlagsSkipClosestHitShaderKHRShift = 3, + RayFlagsCullBackFacingTrianglesKHRShift = 4, + RayFlagsCullFrontFacingTrianglesKHRShift = 5, + RayFlagsCullOpaqueKHRShift = 6, + RayFlagsCullNoOpaqueKHRShift = 7, + RayFlagsSkipTrianglesKHRShift = 8, + RayFlagsSkipAABBsKHRShift = 9, + RayFlagsMax = 0x7fffffff, +}; + +enum RayFlagsMask { + RayFlagsMaskNone = 0, + RayFlagsOpaqueKHRMask = 0x00000001, + RayFlagsNoOpaqueKHRMask = 0x00000002, + RayFlagsTerminateOnFirstHitKHRMask = 0x00000004, + RayFlagsSkipClosestHitShaderKHRMask = 0x00000008, + RayFlagsCullBackFacingTrianglesKHRMask = 0x00000010, + RayFlagsCullFrontFacingTrianglesKHRMask = 0x00000020, + RayFlagsCullOpaqueKHRMask = 0x00000040, + RayFlagsCullNoOpaqueKHRMask = 0x00000080, + RayFlagsSkipTrianglesKHRMask = 0x00000100, + RayFlagsSkipAABBsKHRMask = 0x00000200, +}; + +enum RayQueryIntersection { + RayQueryIntersectionRayQueryCandidateIntersectionKHR = 0, + RayQueryIntersectionRayQueryCommittedIntersectionKHR = 1, + RayQueryIntersectionMax = 0x7fffffff, +}; + +enum RayQueryCommittedIntersectionType { + RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionNoneKHR = 0, + RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionTriangleKHR = 1, + RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionGeneratedKHR = 2, + RayQueryCommittedIntersectionTypeMax = 0x7fffffff, +}; + +enum RayQueryCandidateIntersectionType { + RayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionTriangleKHR = 0, + RayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionAABBKHR = 1, + RayQueryCandidateIntersectionTypeMax = 0x7fffffff, +}; + +enum FragmentShadingRateShift { + FragmentShadingRateVertical2PixelsShift = 0, + FragmentShadingRateVertical4PixelsShift = 1, + FragmentShadingRateHorizontal2PixelsShift = 2, + FragmentShadingRateHorizontal4PixelsShift = 3, + FragmentShadingRateMax = 0x7fffffff, +}; + +enum FragmentShadingRateMask { + FragmentShadingRateMaskNone = 0, + FragmentShadingRateVertical2PixelsMask = 0x00000001, + FragmentShadingRateVertical4PixelsMask = 0x00000002, + FragmentShadingRateHorizontal2PixelsMask = 0x00000004, + FragmentShadingRateHorizontal4PixelsMask = 0x00000008, +}; + +enum FPDenormMode { + FPDenormModePreserve = 0, + FPDenormModeFlushToZero = 1, + FPDenormModeMax = 0x7fffffff, +}; + +enum FPOperationMode { + FPOperationModeIEEE = 0, + FPOperationModeALT = 1, + FPOperationModeMax = 0x7fffffff, +}; + enum Op { OpNop = 0, OpUndef = 1, @@ -1248,12 +1467,25 @@ enum Op { OpPtrEqual = 401, OpPtrNotEqual = 402, OpPtrDiff = 403, + OpTerminateInvocation = 4416, OpSubgroupBallotKHR = 4421, OpSubgroupFirstInvocationKHR = 4422, OpSubgroupAllKHR = 4428, OpSubgroupAnyKHR = 4429, OpSubgroupAllEqualKHR = 4430, OpSubgroupReadInvocationKHR = 4432, + OpTraceRayKHR = 4445, + OpExecuteCallableKHR = 4446, + OpConvertUToAccelerationStructureKHR = 4447, + OpIgnoreIntersectionKHR = 4448, + OpTerminateRayKHR = 4449, + OpTypeRayQueryKHR = 4472, + OpRayQueryInitializeKHR = 4473, + OpRayQueryTerminateKHR = 4474, + OpRayQueryGenerateIntersectionKHR = 4475, + OpRayQueryConfirmIntersectionKHR = 4476, + OpRayQueryProceedKHR = 4477, + OpRayQueryGetIntersectionTypeKHR = 4479, OpGroupIAddNonUniformAMD = 5000, OpGroupFAddNonUniformAMD = 5001, OpGroupFMinNonUniformAMD = 5002, @@ -1268,10 +1500,14 @@ enum Op { OpImageSampleFootprintNV = 5283, OpGroupNonUniformPartitionNV = 5296, OpWritePackedPrimitiveIndices4x8NV = 5299, + OpReportIntersectionKHR = 5334, OpReportIntersectionNV = 5334, OpIgnoreIntersectionNV = 5335, OpTerminateRayNV = 5336, OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, + OpTypeAccelerationStructureKHR = 5341, OpTypeAccelerationStructureNV = 5341, OpExecuteCallableNV = 5344, OpTypeCooperativeMatrixNV = 5358, @@ -1307,6 +1543,15 @@ enum Op { OpUSubSatINTEL = 5596, OpIMul32x16INTEL = 5597, OpUMul32x16INTEL = 5598, + OpConstFunctionPointerINTEL = 5600, + OpFunctionPointerCallINTEL = 5601, + OpAsmTargetINTEL = 5609, + OpAsmINTEL = 5610, + OpAsmCallINTEL = 5611, + OpAtomicFMinEXT = 5614, + OpAtomicFMaxEXT = 5615, + OpAssumeTrueKHR = 5630, + OpExpectKHR = 5631, OpDecorateString = 5632, OpDecorateStringGOOGLE = 5632, OpMemberDecorateString = 5633, @@ -1429,6 +1674,37 @@ enum Op { OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, + OpVariableLengthArrayINTEL = 5818, + OpSaveMemoryINTEL = 5819, + OpRestoreMemoryINTEL = 5820, + OpLoopControlINTEL = 5887, + OpPtrCastToCrossWorkgroupINTEL = 5934, + OpCrossWorkgroupCastToPtrINTEL = 5938, + OpReadPipeBlockingINTEL = 5946, + OpWritePipeBlockingINTEL = 5947, + OpFPGARegINTEL = 5949, + OpRayQueryGetRayTMinKHR = 6016, + OpRayQueryGetRayFlagsKHR = 6017, + OpRayQueryGetIntersectionTKHR = 6018, + OpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019, + OpRayQueryGetIntersectionInstanceIdKHR = 6020, + OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021, + OpRayQueryGetIntersectionGeometryIndexKHR = 6022, + OpRayQueryGetIntersectionPrimitiveIndexKHR = 6023, + OpRayQueryGetIntersectionBarycentricsKHR = 6024, + OpRayQueryGetIntersectionFrontFaceKHR = 6025, + OpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026, + OpRayQueryGetIntersectionObjectRayDirectionKHR = 6027, + OpRayQueryGetIntersectionObjectRayOriginKHR = 6028, + OpRayQueryGetWorldRayDirectionKHR = 6029, + OpRayQueryGetWorldRayOriginKHR = 6030, + OpRayQueryGetIntersectionObjectToWorldKHR = 6031, + OpRayQueryGetIntersectionWorldToObjectKHR = 6032, + OpAtomicFAddEXT = 6035, + OpTypeBufferSurfaceINTEL = 6086, + OpTypeStructContinuedINTEL = 6090, + OpConstantCompositeContinuedINTEL = 6091, + OpSpecConstantCompositeContinuedINTEL = 6092, OpMax = 0x7fffffff, }; @@ -1781,12 +2057,25 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpPtrEqual: *hasResult = true; *hasResultType = true; break; case OpPtrNotEqual: *hasResult = true; *hasResultType = true; break; case OpPtrDiff: *hasResult = true; *hasResultType = true; break; + case OpTerminateInvocation: *hasResult = false; *hasResultType = false; break; case OpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break; case OpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break; case OpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; + case OpTraceRayKHR: *hasResult = false; *hasResultType = false; break; + case OpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break; + case OpConvertUToAccelerationStructureKHR: *hasResult = true; *hasResultType = true; break; + case OpIgnoreIntersectionKHR: *hasResult = false; *hasResultType = false; break; + case OpTerminateRayKHR: *hasResult = false; *hasResultType = false; break; + case OpTypeRayQueryKHR: *hasResult = true; *hasResultType = false; break; + case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break; + case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break; + case OpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break; + case OpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break; + case OpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break; case OpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; case OpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; case OpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; @@ -1805,6 +2094,8 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break; case OpTraceNV: *hasResult = false; *hasResultType = false; break; + case OpTraceMotionNV: *hasResult = false; *hasResultType = false; break; + case OpTraceRayMotionNV: *hasResult = false; *hasResultType = false; break; case OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; case OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; case OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; @@ -1840,6 +2131,15 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case OpConstFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; + case OpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmTargetINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmCallINTEL: *hasResult = true; *hasResultType = true; break; + case OpAtomicFMinEXT: *hasResult = true; *hasResultType = true; break; + case OpAtomicFMaxEXT: *hasResult = true; *hasResultType = true; break; + case OpAssumeTrueKHR: *hasResult = false; *hasResultType = false; break; + case OpExpectKHR: *hasResult = true; *hasResultType = true; break; case OpDecorateString: *hasResult = false; *hasResultType = false; break; case OpMemberDecorateString: *hasResult = false; *hasResultType = false; break; case OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; @@ -1960,6 +2260,37 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; + case OpVariableLengthArrayINTEL: *hasResult = true; *hasResultType = true; break; + case OpSaveMemoryINTEL: *hasResult = true; *hasResultType = true; break; + case OpRestoreMemoryINTEL: *hasResult = false; *hasResultType = false; break; + case OpLoopControlINTEL: *hasResult = false; *hasResultType = false; break; + case OpPtrCastToCrossWorkgroupINTEL: *hasResult = true; *hasResultType = true; break; + case OpCrossWorkgroupCastToPtrINTEL: *hasResult = true; *hasResultType = true; break; + case OpReadPipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; + case OpWritePipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; + case OpFPGARegINTEL: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break; + case OpAtomicFAddEXT: *hasResult = true; *hasResultType = true; break; + case OpTypeBufferSurfaceINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeStructContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case OpConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case OpSpecConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; } } #endif /* SPV_ENABLE_UTILITY_CODE */ @@ -1974,6 +2305,8 @@ inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); } inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); } inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); } +inline RayFlagsMask operator|(RayFlagsMask a, RayFlagsMask b) { return RayFlagsMask(unsigned(a) | unsigned(b)); } +inline FragmentShadingRateMask operator|(FragmentShadingRateMask a, FragmentShadingRateMask b) { return FragmentShadingRateMask(unsigned(a) | unsigned(b)); } } // end namespace spv diff --git a/libraries/glslang/spirv/spvIR.h b/libraries/ZVulkan/src/glslang/spirv/spvIR.h similarity index 94% rename from libraries/glslang/spirv/spvIR.h rename to libraries/ZVulkan/src/glslang/spirv/spvIR.h index cf6a71159af..486e80d000f 100644 --- a/libraries/glslang/spirv/spvIR.h +++ b/libraries/ZVulkan/src/glslang/spirv/spvIR.h @@ -55,6 +55,7 @@ #include #include #include +#include namespace spv { @@ -235,8 +236,7 @@ class Block { assert(instructions.size() > 0); instructions.resize(1); successors.clear(); - Instruction* unreachable = new Instruction(OpUnreachable); - addInstruction(std::unique_ptr(unreachable)); + addInstruction(std::unique_ptr(new Instruction(OpUnreachable))); } // Change this block into a canonical dead continue target branching to the // given header ID. Delete instructions as necessary. A canonical dead continue @@ -263,6 +263,7 @@ class Block { case OpBranchConditional: case OpSwitch: case OpKill: + case OpTerminateInvocation: case OpReturn: case OpReturnValue: case OpUnreachable: @@ -352,10 +353,28 @@ class Function { const std::vector& getBlocks() const { return blocks; } void addLocalVariable(std::unique_ptr inst); Id getReturnType() const { return functionInstruction.getTypeId(); } + void setReturnPrecision(Decoration precision) + { + if (precision == DecorationRelaxedPrecision) + reducedPrecisionReturn = true; + } + Decoration getReturnPrecision() const + { return reducedPrecisionReturn ? DecorationRelaxedPrecision : NoPrecision; } void setImplicitThis() { implicitThis = true; } bool hasImplicitThis() const { return implicitThis; } + void addParamPrecision(unsigned param, Decoration precision) + { + if (precision == DecorationRelaxedPrecision) + reducedPrecisionParams.insert(param); + } + Decoration getParamPrecision(unsigned param) const + { + return reducedPrecisionParams.find(param) != reducedPrecisionParams.end() ? + DecorationRelaxedPrecision : NoPrecision; + } + void dump(std::vector& out) const { // OpFunction @@ -380,6 +399,8 @@ class Function { std::vector parameterInstructions; std::vector blocks; bool implicitThis; // true if this is a member function expecting to be passed a 'this' as the first argument + bool reducedPrecisionReturn; + std::set reducedPrecisionParams; // list of parameter indexes that need a relaxed precision arg }; // @@ -440,7 +461,8 @@ class Module { // - the OpFunction instruction // - all the OpFunctionParameter instructions __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent) - : parent(parent), functionInstruction(id, resultType, OpFunction), implicitThis(false) + : parent(parent), functionInstruction(id, resultType, OpFunction), implicitThis(false), + reducedPrecisionReturn(false) { // OpFunction functionInstruction.addImmediateOperand(FunctionControlMaskNone); diff --git a/libraries/ZVulkan/src/vk_mem_alloc/vk_mem_alloc.cpp b/libraries/ZVulkan/src/vk_mem_alloc/vk_mem_alloc.cpp new file mode 100644 index 00000000000..fb0d2347293 --- /dev/null +++ b/libraries/ZVulkan/src/vk_mem_alloc/vk_mem_alloc.cpp @@ -0,0 +1,8 @@ +#include "volk/volk.h" +#define VMA_IMPLEMENTATION +#define VMA_STATIC_VULKAN_FUNCTIONS 1 + +#define VMA_NULLABLE +#define VMA_NOT_NULL + +#include "vk_mem_alloc/vk_mem_alloc.h" diff --git a/libraries/ZVulkan/src/vk_mem_alloc/vk_mem_alloc.natvis b/libraries/ZVulkan/src/vk_mem_alloc/vk_mem_alloc.natvis new file mode 100644 index 00000000000..85c75335f80 --- /dev/null +++ b/libraries/ZVulkan/src/vk_mem_alloc/vk_mem_alloc.natvis @@ -0,0 +1,40 @@ + + + + {{ Count={m_Count} }} + + m_Count + + m_Count + m_pFront + pNext + Value + + + + + + {{ Count={m_RawList.m_Count} }} + + m_RawList.m_Count + + m_RawList.m_Count + m_RawList.m_pFront + pNext + Value + + + + + + {{ Count={m_Count} }} + + m_Count + m_Capacity + + m_Count + m_pArray + + + + \ No newline at end of file diff --git a/libraries/ZVulkan/src/volk/volk.c b/libraries/ZVulkan/src/volk/volk.c new file mode 100644 index 00000000000..67f85c7f8c0 --- /dev/null +++ b/libraries/ZVulkan/src/volk/volk.c @@ -0,0 +1,3055 @@ + +#if defined(_WIN32) +#define VK_USE_PLATFORM_WIN32_KHR +#elif defined(__APPLE__) +#define VK_USE_PLATFORM_MACOS_MVK +#define VK_USE_PLATFORM_METAL_EXT +#else +#if defined(VULKAN_USE_XLIB) +#define VK_USE_PLATFORM_XLIB_KHR +#elif defined(VULKAN_USE_WAYLAND) +#define VK_USE_PLATFORM_WAYLAND_KHR +#endif +#endif + +/* This file is part of volk library; see volk.h for version/license details */ +/* clang-format off */ +#include "volk/volk.h" + +#ifdef _WIN32 + typedef const char* LPCSTR; + typedef struct HINSTANCE__* HINSTANCE; + typedef HINSTANCE HMODULE; + #if defined(_MINWINDEF_) + /* minwindef.h defines FARPROC, and attempting to redefine it may conflict with -Wstrict-prototypes */ + #elif defined(_WIN64) + typedef __int64 (__stdcall* FARPROC)(void); + #else + typedef int (__stdcall* FARPROC)(void); + #endif +#else +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +__declspec(dllimport) HMODULE __stdcall LoadLibraryA(LPCSTR); +__declspec(dllimport) FARPROC __stdcall GetProcAddress(HMODULE, LPCSTR); +__declspec(dllimport) int __stdcall FreeLibrary(HMODULE); +#endif + +static void* loadedModule = NULL; +static VkInstance loadedInstance = VK_NULL_HANDLE; +static VkDevice loadedDevice = VK_NULL_HANDLE; + +static void volkGenLoadLoader(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadInstance(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); +static void volkGenLoadDeviceTable(struct VolkDeviceTable* table, void* context, PFN_vkVoidFunction (*load)(void*, const char*)); + +static PFN_vkVoidFunction vkGetInstanceProcAddrStub(void* context, const char* name) +{ + return vkGetInstanceProcAddr((VkInstance)context, name); +} + +static PFN_vkVoidFunction vkGetDeviceProcAddrStub(void* context, const char* name) +{ + return vkGetDeviceProcAddr((VkDevice)context, name); +} + +static PFN_vkVoidFunction nullProcAddrStub(void* context, const char* name) +{ + (void)context; + (void)name; + return NULL; +} + +VkResult volkInitialize(void) +{ +#if defined(_WIN32) + HMODULE module = LoadLibraryA("vulkan-1.dll"); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + // note: function pointer is cast through void function pointer to silence cast-function-type warning on gcc8 + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)(void(*)(void))GetProcAddress(module, "vkGetInstanceProcAddr"); +#elif defined(__APPLE__) + void* module = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libMoltenVK.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); +#else + void* module = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); + if (!module) + return VK_ERROR_INITIALIZATION_FAILED; + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); +#endif + + loadedModule = module; + volkGenLoadLoader(NULL, vkGetInstanceProcAddrStub); + + return VK_SUCCESS; +} + +void volkInitializeCustom(PFN_vkGetInstanceProcAddr handler) +{ + vkGetInstanceProcAddr = handler; + + loadedModule = NULL; + volkGenLoadLoader(NULL, vkGetInstanceProcAddrStub); +} + +void volkFinalize(void) +{ + if (loadedModule) + { +#if defined(_WIN32) + FreeLibrary((HMODULE)loadedModule); +#else + dlclose(loadedModule); +#endif + } + + vkGetInstanceProcAddr = NULL; + volkGenLoadLoader(NULL, nullProcAddrStub); + volkGenLoadInstance(NULL, nullProcAddrStub); + volkGenLoadDevice(NULL, nullProcAddrStub); + + loadedModule = NULL; + loadedInstance = VK_NULL_HANDLE; + loadedDevice = VK_NULL_HANDLE; +} + +uint32_t volkGetInstanceVersion(void) +{ +#if defined(VK_VERSION_1_1) + uint32_t apiVersion = 0; + if (vkEnumerateInstanceVersion && vkEnumerateInstanceVersion(&apiVersion) == VK_SUCCESS) + return apiVersion; +#endif + + if (vkCreateInstance) + return VK_API_VERSION_1_0; + + return 0; +} + +void volkLoadInstance(VkInstance instance) +{ + loadedInstance = instance; + volkGenLoadInstance(instance, vkGetInstanceProcAddrStub); + volkGenLoadDevice(instance, vkGetInstanceProcAddrStub); +} + +void volkLoadInstanceOnly(VkInstance instance) +{ + loadedInstance = instance; + volkGenLoadInstance(instance, vkGetInstanceProcAddrStub); +} + +VkInstance volkGetLoadedInstance(void) +{ + return loadedInstance; +} + +void volkLoadDevice(VkDevice device) +{ + loadedDevice = device; + volkGenLoadDevice(device, vkGetDeviceProcAddrStub); +} + +VkDevice volkGetLoadedDevice(void) +{ + return loadedDevice; +} + +void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device) +{ + volkGenLoadDeviceTable(table, device, vkGetDeviceProcAddrStub); +} + +static void volkGenLoadLoader(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_LOADER */ +#if defined(VK_VERSION_1_0) + vkCreateInstance = (PFN_vkCreateInstance)load(context, "vkCreateInstance"); + vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)load(context, "vkEnumerateInstanceExtensionProperties"); + vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)load(context, "vkEnumerateInstanceLayerProperties"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)load(context, "vkEnumerateInstanceVersion"); +#endif /* defined(VK_VERSION_1_1) */ + /* VOLK_GENERATE_LOAD_LOADER */ +} + +static void volkGenLoadInstance(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_INSTANCE */ +#if defined(VK_VERSION_1_0) + vkCreateDevice = (PFN_vkCreateDevice)load(context, "vkCreateDevice"); + vkDestroyInstance = (PFN_vkDestroyInstance)load(context, "vkDestroyInstance"); + vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)load(context, "vkEnumerateDeviceExtensionProperties"); + vkEnumerateDeviceLayerProperties = (PFN_vkEnumerateDeviceLayerProperties)load(context, "vkEnumerateDeviceLayerProperties"); + vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)load(context, "vkEnumeratePhysicalDevices"); + vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)load(context, "vkGetDeviceProcAddr"); + vkGetPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)load(context, "vkGetPhysicalDeviceFeatures"); + vkGetPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)load(context, "vkGetPhysicalDeviceFormatProperties"); + vkGetPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties)load(context, "vkGetPhysicalDeviceImageFormatProperties"); + vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)load(context, "vkGetPhysicalDeviceMemoryProperties"); + vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)load(context, "vkGetPhysicalDeviceProperties"); + vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)load(context, "vkGetPhysicalDeviceQueueFamilyProperties"); + vkGetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkEnumeratePhysicalDeviceGroups = (PFN_vkEnumeratePhysicalDeviceGroups)load(context, "vkEnumeratePhysicalDeviceGroups"); + vkGetPhysicalDeviceExternalBufferProperties = (PFN_vkGetPhysicalDeviceExternalBufferProperties)load(context, "vkGetPhysicalDeviceExternalBufferProperties"); + vkGetPhysicalDeviceExternalFenceProperties = (PFN_vkGetPhysicalDeviceExternalFenceProperties)load(context, "vkGetPhysicalDeviceExternalFenceProperties"); + vkGetPhysicalDeviceExternalSemaphoreProperties = (PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)load(context, "vkGetPhysicalDeviceExternalSemaphoreProperties"); + vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)load(context, "vkGetPhysicalDeviceFeatures2"); + vkGetPhysicalDeviceFormatProperties2 = (PFN_vkGetPhysicalDeviceFormatProperties2)load(context, "vkGetPhysicalDeviceFormatProperties2"); + vkGetPhysicalDeviceImageFormatProperties2 = (PFN_vkGetPhysicalDeviceImageFormatProperties2)load(context, "vkGetPhysicalDeviceImageFormatProperties2"); + vkGetPhysicalDeviceMemoryProperties2 = (PFN_vkGetPhysicalDeviceMemoryProperties2)load(context, "vkGetPhysicalDeviceMemoryProperties2"); + vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)load(context, "vkGetPhysicalDeviceProperties2"); + vkGetPhysicalDeviceQueueFamilyProperties2 = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2)load(context, "vkGetPhysicalDeviceQueueFamilyProperties2"); + vkGetPhysicalDeviceSparseImageFormatProperties2 = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties2"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_3) + vkGetPhysicalDeviceToolProperties = (PFN_vkGetPhysicalDeviceToolProperties)load(context, "vkGetPhysicalDeviceToolProperties"); +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_EXT_acquire_drm_display) + vkAcquireDrmDisplayEXT = (PFN_vkAcquireDrmDisplayEXT)load(context, "vkAcquireDrmDisplayEXT"); + vkGetDrmDisplayEXT = (PFN_vkGetDrmDisplayEXT)load(context, "vkGetDrmDisplayEXT"); +#endif /* defined(VK_EXT_acquire_drm_display) */ +#if defined(VK_EXT_acquire_xlib_display) + vkAcquireXlibDisplayEXT = (PFN_vkAcquireXlibDisplayEXT)load(context, "vkAcquireXlibDisplayEXT"); + vkGetRandROutputDisplayEXT = (PFN_vkGetRandROutputDisplayEXT)load(context, "vkGetRandROutputDisplayEXT"); +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_calibrated_timestamps) + vkGetPhysicalDeviceCalibrateableTimeDomainsEXT = (PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)load(context, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_debug_report) + vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)load(context, "vkCreateDebugReportCallbackEXT"); + vkDebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)load(context, "vkDebugReportMessageEXT"); + vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)load(context, "vkDestroyDebugReportCallbackEXT"); +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) + vkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)load(context, "vkCmdBeginDebugUtilsLabelEXT"); + vkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)load(context, "vkCmdEndDebugUtilsLabelEXT"); + vkCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)load(context, "vkCmdInsertDebugUtilsLabelEXT"); + vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)load(context, "vkCreateDebugUtilsMessengerEXT"); + vkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)load(context, "vkDestroyDebugUtilsMessengerEXT"); + vkQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)load(context, "vkQueueBeginDebugUtilsLabelEXT"); + vkQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)load(context, "vkQueueEndDebugUtilsLabelEXT"); + vkQueueInsertDebugUtilsLabelEXT = (PFN_vkQueueInsertDebugUtilsLabelEXT)load(context, "vkQueueInsertDebugUtilsLabelEXT"); + vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)load(context, "vkSetDebugUtilsObjectNameEXT"); + vkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)load(context, "vkSetDebugUtilsObjectTagEXT"); + vkSubmitDebugUtilsMessageEXT = (PFN_vkSubmitDebugUtilsMessageEXT)load(context, "vkSubmitDebugUtilsMessageEXT"); +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_direct_mode_display) + vkReleaseDisplayEXT = (PFN_vkReleaseDisplayEXT)load(context, "vkReleaseDisplayEXT"); +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) + vkCreateDirectFBSurfaceEXT = (PFN_vkCreateDirectFBSurfaceEXT)load(context, "vkCreateDirectFBSurfaceEXT"); + vkGetPhysicalDeviceDirectFBPresentationSupportEXT = (PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)load(context, "vkGetPhysicalDeviceDirectFBPresentationSupportEXT"); +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_display_surface_counter) + vkGetPhysicalDeviceSurfaceCapabilities2EXT = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)load(context, "vkGetPhysicalDeviceSurfaceCapabilities2EXT"); +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_full_screen_exclusive) + vkGetPhysicalDeviceSurfacePresentModes2EXT = (PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)load(context, "vkGetPhysicalDeviceSurfacePresentModes2EXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_headless_surface) + vkCreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT)load(context, "vkCreateHeadlessSurfaceEXT"); +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_metal_surface) + vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT)load(context, "vkCreateMetalSurfaceEXT"); +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_sample_locations) + vkGetPhysicalDeviceMultisamplePropertiesEXT = (PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)load(context, "vkGetPhysicalDeviceMultisamplePropertiesEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_tooling_info) + vkGetPhysicalDeviceToolPropertiesEXT = (PFN_vkGetPhysicalDeviceToolPropertiesEXT)load(context, "vkGetPhysicalDeviceToolPropertiesEXT"); +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_FUCHSIA_imagepipe_surface) + vkCreateImagePipeSurfaceFUCHSIA = (PFN_vkCreateImagePipeSurfaceFUCHSIA)load(context, "vkCreateImagePipeSurfaceFUCHSIA"); +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) + vkCreateStreamDescriptorSurfaceGGP = (PFN_vkCreateStreamDescriptorSurfaceGGP)load(context, "vkCreateStreamDescriptorSurfaceGGP"); +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_KHR_android_surface) + vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)load(context, "vkCreateAndroidSurfaceKHR"); +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_cooperative_matrix) + vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)load(context, "vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR"); +#endif /* defined(VK_KHR_cooperative_matrix) */ +#if defined(VK_KHR_device_group_creation) + vkEnumeratePhysicalDeviceGroupsKHR = (PFN_vkEnumeratePhysicalDeviceGroupsKHR)load(context, "vkEnumeratePhysicalDeviceGroupsKHR"); +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) + vkCreateDisplayModeKHR = (PFN_vkCreateDisplayModeKHR)load(context, "vkCreateDisplayModeKHR"); + vkCreateDisplayPlaneSurfaceKHR = (PFN_vkCreateDisplayPlaneSurfaceKHR)load(context, "vkCreateDisplayPlaneSurfaceKHR"); + vkGetDisplayModePropertiesKHR = (PFN_vkGetDisplayModePropertiesKHR)load(context, "vkGetDisplayModePropertiesKHR"); + vkGetDisplayPlaneCapabilitiesKHR = (PFN_vkGetDisplayPlaneCapabilitiesKHR)load(context, "vkGetDisplayPlaneCapabilitiesKHR"); + vkGetDisplayPlaneSupportedDisplaysKHR = (PFN_vkGetDisplayPlaneSupportedDisplaysKHR)load(context, "vkGetDisplayPlaneSupportedDisplaysKHR"); + vkGetPhysicalDeviceDisplayPlanePropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)load(context, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"); + vkGetPhysicalDeviceDisplayPropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)load(context, "vkGetPhysicalDeviceDisplayPropertiesKHR"); +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_external_fence_capabilities) + vkGetPhysicalDeviceExternalFencePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)load(context, "vkGetPhysicalDeviceExternalFencePropertiesKHR"); +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_memory_capabilities) + vkGetPhysicalDeviceExternalBufferPropertiesKHR = (PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)load(context, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_semaphore_capabilities) + vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)load(context, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"); +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_fragment_shading_rate) + vkGetPhysicalDeviceFragmentShadingRatesKHR = (PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR)load(context, "vkGetPhysicalDeviceFragmentShadingRatesKHR"); +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_display_properties2) + vkGetDisplayModeProperties2KHR = (PFN_vkGetDisplayModeProperties2KHR)load(context, "vkGetDisplayModeProperties2KHR"); + vkGetDisplayPlaneCapabilities2KHR = (PFN_vkGetDisplayPlaneCapabilities2KHR)load(context, "vkGetDisplayPlaneCapabilities2KHR"); + vkGetPhysicalDeviceDisplayPlaneProperties2KHR = (PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)load(context, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR"); + vkGetPhysicalDeviceDisplayProperties2KHR = (PFN_vkGetPhysicalDeviceDisplayProperties2KHR)load(context, "vkGetPhysicalDeviceDisplayProperties2KHR"); +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_physical_device_properties2) + vkGetPhysicalDeviceFeatures2KHR = (PFN_vkGetPhysicalDeviceFeatures2KHR)load(context, "vkGetPhysicalDeviceFeatures2KHR"); + vkGetPhysicalDeviceFormatProperties2KHR = (PFN_vkGetPhysicalDeviceFormatProperties2KHR)load(context, "vkGetPhysicalDeviceFormatProperties2KHR"); + vkGetPhysicalDeviceImageFormatProperties2KHR = (PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)load(context, "vkGetPhysicalDeviceImageFormatProperties2KHR"); + vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)load(context, "vkGetPhysicalDeviceMemoryProperties2KHR"); + vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2KHR)load(context, "vkGetPhysicalDeviceProperties2KHR"); + vkGetPhysicalDeviceQueueFamilyProperties2KHR = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)load(context, "vkGetPhysicalDeviceQueueFamilyProperties2KHR"); + vkGetPhysicalDeviceSparseImageFormatProperties2KHR = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR"); +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) + vkGetPhysicalDeviceSurfaceCapabilities2KHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"); + vkGetPhysicalDeviceSurfaceFormats2KHR = (PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)load(context, "vkGetPhysicalDeviceSurfaceFormats2KHR"); +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_performance_query) + vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR = (PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)load(context, "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR"); + vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR = (PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)load(context, "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_surface) + vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)load(context, "vkDestroySurfaceKHR"); + vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); + vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)load(context, "vkGetPhysicalDeviceSurfaceFormatsKHR"); + vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)load(context, "vkGetPhysicalDeviceSurfacePresentModesKHR"); + vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)load(context, "vkGetPhysicalDeviceSurfaceSupportKHR"); +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_video_encode_queue) + vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR = (PFN_vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR)load(context, "vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR"); +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) + vkGetPhysicalDeviceVideoCapabilitiesKHR = (PFN_vkGetPhysicalDeviceVideoCapabilitiesKHR)load(context, "vkGetPhysicalDeviceVideoCapabilitiesKHR"); + vkGetPhysicalDeviceVideoFormatPropertiesKHR = (PFN_vkGetPhysicalDeviceVideoFormatPropertiesKHR)load(context, "vkGetPhysicalDeviceVideoFormatPropertiesKHR"); +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_KHR_wayland_surface) + vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)load(context, "vkCreateWaylandSurfaceKHR"); + vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)load(context, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) + vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)load(context, "vkCreateWin32SurfaceKHR"); + vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)load(context, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) + vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)load(context, "vkCreateXcbSurfaceKHR"); + vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)load(context, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) + vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)load(context, "vkCreateXlibSurfaceKHR"); + vkGetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)load(context, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) + vkCreateIOSSurfaceMVK = (PFN_vkCreateIOSSurfaceMVK)load(context, "vkCreateIOSSurfaceMVK"); +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) + vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)load(context, "vkCreateMacOSSurfaceMVK"); +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) + vkCreateViSurfaceNN = (PFN_vkCreateViSurfaceNN)load(context, "vkCreateViSurfaceNN"); +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NV_acquire_winrt_display) + vkAcquireWinrtDisplayNV = (PFN_vkAcquireWinrtDisplayNV)load(context, "vkAcquireWinrtDisplayNV"); + vkGetWinrtDisplayNV = (PFN_vkGetWinrtDisplayNV)load(context, "vkGetWinrtDisplayNV"); +#endif /* defined(VK_NV_acquire_winrt_display) */ +#if defined(VK_NV_cooperative_matrix) + vkGetPhysicalDeviceCooperativeMatrixPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)load(context, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV"); +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_coverage_reduction_mode) + vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV = (PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)load(context, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV"); +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_external_memory_capabilities) + vkGetPhysicalDeviceExternalImageFormatPropertiesNV = (PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)load(context, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV"); +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if defined(VK_NV_optical_flow) + vkGetPhysicalDeviceOpticalFlowImageFormatsNV = (PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV)load(context, "vkGetPhysicalDeviceOpticalFlowImageFormatsNV"); +#endif /* defined(VK_NV_optical_flow) */ +#if defined(VK_QNX_screen_surface) + vkCreateScreenSurfaceQNX = (PFN_vkCreateScreenSurfaceQNX)load(context, "vkCreateScreenSurfaceQNX"); + vkGetPhysicalDeviceScreenPresentationSupportQNX = (PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX)load(context, "vkGetPhysicalDeviceScreenPresentationSupportQNX"); +#endif /* defined(VK_QNX_screen_surface) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkGetPhysicalDevicePresentRectanglesKHR = (PFN_vkGetPhysicalDevicePresentRectanglesKHR)load(context, "vkGetPhysicalDevicePresentRectanglesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_INSTANCE */ +} + +static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_DEVICE */ +#if defined(VK_VERSION_1_0) + vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers"); + vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets"); + vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory"); + vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer"); + vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory"); + vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory"); + vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery"); + vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass"); + vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets"); + vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer"); + vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline"); + vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers"); + vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage"); + vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments"); + vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage"); + vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage"); + vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer"); + vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage"); + vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage"); + vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer"); + vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults"); + vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch"); + vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect"); + vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw"); + vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed"); + vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect"); + vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect"); + vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery"); + vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass"); + vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands"); + vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer"); + vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass"); + vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier"); + vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants"); + vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent"); + vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool"); + vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage"); + vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants"); + vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias"); + vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds"); + vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent"); + vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth"); + vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor"); + vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask"); + vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference"); + vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask"); + vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport"); + vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer"); + vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents"); + vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp"); + vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer"); + vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView"); + vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool"); + vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines"); + vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool"); + vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout"); + vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent"); + vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence"); + vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer"); + vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines"); + vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage"); + vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView"); + vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache"); + vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout"); + vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool"); + vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass"); + vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler"); + vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore"); + vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule"); + vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer"); + vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView"); + vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool"); + vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool"); + vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout"); + vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice"); + vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent"); + vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence"); + vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer"); + vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage"); + vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView"); + vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline"); + vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache"); + vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout"); + vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool"); + vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass"); + vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler"); + vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore"); + vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule"); + vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle"); + vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer"); + vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges"); + vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers"); + vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets"); + vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory"); + vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements"); + vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment"); + vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue"); + vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus"); + vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus"); + vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements"); + vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements"); + vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout"); + vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData"); + vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults"); + vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity"); + vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges"); + vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory"); + vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches"); + vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse"); + vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit"); + vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle"); + vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer"); + vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool"); + vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool"); + vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent"); + vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences"); + vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent"); + vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory"); + vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets"); + vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + vkBindBufferMemory2 = (PFN_vkBindBufferMemory2)load(context, "vkBindBufferMemory2"); + vkBindImageMemory2 = (PFN_vkBindImageMemory2)load(context, "vkBindImageMemory2"); + vkCmdDispatchBase = (PFN_vkCmdDispatchBase)load(context, "vkCmdDispatchBase"); + vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask)load(context, "vkCmdSetDeviceMask"); + vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate)load(context, "vkCreateDescriptorUpdateTemplate"); + vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)load(context, "vkCreateSamplerYcbcrConversion"); + vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate)load(context, "vkDestroyDescriptorUpdateTemplate"); + vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)load(context, "vkDestroySamplerYcbcrConversion"); + vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2)load(context, "vkGetBufferMemoryRequirements2"); + vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport)load(context, "vkGetDescriptorSetLayoutSupport"); + vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures)load(context, "vkGetDeviceGroupPeerMemoryFeatures"); + vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2)load(context, "vkGetDeviceQueue2"); + vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)load(context, "vkGetImageMemoryRequirements2"); + vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2)load(context, "vkGetImageSparseMemoryRequirements2"); + vkTrimCommandPool = (PFN_vkTrimCommandPool)load(context, "vkTrimCommandPool"); + vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate)load(context, "vkUpdateDescriptorSetWithTemplate"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + vkCmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2)load(context, "vkCmdBeginRenderPass2"); + vkCmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount)load(context, "vkCmdDrawIndexedIndirectCount"); + vkCmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount)load(context, "vkCmdDrawIndirectCount"); + vkCmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2)load(context, "vkCmdEndRenderPass2"); + vkCmdNextSubpass2 = (PFN_vkCmdNextSubpass2)load(context, "vkCmdNextSubpass2"); + vkCreateRenderPass2 = (PFN_vkCreateRenderPass2)load(context, "vkCreateRenderPass2"); + vkGetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)load(context, "vkGetBufferDeviceAddress"); + vkGetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress)load(context, "vkGetBufferOpaqueCaptureAddress"); + vkGetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress)load(context, "vkGetDeviceMemoryOpaqueCaptureAddress"); + vkGetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue)load(context, "vkGetSemaphoreCounterValue"); + vkResetQueryPool = (PFN_vkResetQueryPool)load(context, "vkResetQueryPool"); + vkSignalSemaphore = (PFN_vkSignalSemaphore)load(context, "vkSignalSemaphore"); + vkWaitSemaphores = (PFN_vkWaitSemaphores)load(context, "vkWaitSemaphores"); +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) + vkCmdBeginRendering = (PFN_vkCmdBeginRendering)load(context, "vkCmdBeginRendering"); + vkCmdBindVertexBuffers2 = (PFN_vkCmdBindVertexBuffers2)load(context, "vkCmdBindVertexBuffers2"); + vkCmdBlitImage2 = (PFN_vkCmdBlitImage2)load(context, "vkCmdBlitImage2"); + vkCmdCopyBuffer2 = (PFN_vkCmdCopyBuffer2)load(context, "vkCmdCopyBuffer2"); + vkCmdCopyBufferToImage2 = (PFN_vkCmdCopyBufferToImage2)load(context, "vkCmdCopyBufferToImage2"); + vkCmdCopyImage2 = (PFN_vkCmdCopyImage2)load(context, "vkCmdCopyImage2"); + vkCmdCopyImageToBuffer2 = (PFN_vkCmdCopyImageToBuffer2)load(context, "vkCmdCopyImageToBuffer2"); + vkCmdEndRendering = (PFN_vkCmdEndRendering)load(context, "vkCmdEndRendering"); + vkCmdPipelineBarrier2 = (PFN_vkCmdPipelineBarrier2)load(context, "vkCmdPipelineBarrier2"); + vkCmdResetEvent2 = (PFN_vkCmdResetEvent2)load(context, "vkCmdResetEvent2"); + vkCmdResolveImage2 = (PFN_vkCmdResolveImage2)load(context, "vkCmdResolveImage2"); + vkCmdSetCullMode = (PFN_vkCmdSetCullMode)load(context, "vkCmdSetCullMode"); + vkCmdSetDepthBiasEnable = (PFN_vkCmdSetDepthBiasEnable)load(context, "vkCmdSetDepthBiasEnable"); + vkCmdSetDepthBoundsTestEnable = (PFN_vkCmdSetDepthBoundsTestEnable)load(context, "vkCmdSetDepthBoundsTestEnable"); + vkCmdSetDepthCompareOp = (PFN_vkCmdSetDepthCompareOp)load(context, "vkCmdSetDepthCompareOp"); + vkCmdSetDepthTestEnable = (PFN_vkCmdSetDepthTestEnable)load(context, "vkCmdSetDepthTestEnable"); + vkCmdSetDepthWriteEnable = (PFN_vkCmdSetDepthWriteEnable)load(context, "vkCmdSetDepthWriteEnable"); + vkCmdSetEvent2 = (PFN_vkCmdSetEvent2)load(context, "vkCmdSetEvent2"); + vkCmdSetFrontFace = (PFN_vkCmdSetFrontFace)load(context, "vkCmdSetFrontFace"); + vkCmdSetPrimitiveRestartEnable = (PFN_vkCmdSetPrimitiveRestartEnable)load(context, "vkCmdSetPrimitiveRestartEnable"); + vkCmdSetPrimitiveTopology = (PFN_vkCmdSetPrimitiveTopology)load(context, "vkCmdSetPrimitiveTopology"); + vkCmdSetRasterizerDiscardEnable = (PFN_vkCmdSetRasterizerDiscardEnable)load(context, "vkCmdSetRasterizerDiscardEnable"); + vkCmdSetScissorWithCount = (PFN_vkCmdSetScissorWithCount)load(context, "vkCmdSetScissorWithCount"); + vkCmdSetStencilOp = (PFN_vkCmdSetStencilOp)load(context, "vkCmdSetStencilOp"); + vkCmdSetStencilTestEnable = (PFN_vkCmdSetStencilTestEnable)load(context, "vkCmdSetStencilTestEnable"); + vkCmdSetViewportWithCount = (PFN_vkCmdSetViewportWithCount)load(context, "vkCmdSetViewportWithCount"); + vkCmdWaitEvents2 = (PFN_vkCmdWaitEvents2)load(context, "vkCmdWaitEvents2"); + vkCmdWriteTimestamp2 = (PFN_vkCmdWriteTimestamp2)load(context, "vkCmdWriteTimestamp2"); + vkCreatePrivateDataSlot = (PFN_vkCreatePrivateDataSlot)load(context, "vkCreatePrivateDataSlot"); + vkDestroyPrivateDataSlot = (PFN_vkDestroyPrivateDataSlot)load(context, "vkDestroyPrivateDataSlot"); + vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements)load(context, "vkGetDeviceBufferMemoryRequirements"); + vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)load(context, "vkGetDeviceImageMemoryRequirements"); + vkGetDeviceImageSparseMemoryRequirements = (PFN_vkGetDeviceImageSparseMemoryRequirements)load(context, "vkGetDeviceImageSparseMemoryRequirements"); + vkGetPrivateData = (PFN_vkGetPrivateData)load(context, "vkGetPrivateData"); + vkQueueSubmit2 = (PFN_vkQueueSubmit2)load(context, "vkQueueSubmit2"); + vkSetPrivateData = (PFN_vkSetPrivateData)load(context, "vkSetPrivateData"); +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMDX_shader_enqueue) + vkCmdDispatchGraphAMDX = (PFN_vkCmdDispatchGraphAMDX)load(context, "vkCmdDispatchGraphAMDX"); + vkCmdDispatchGraphIndirectAMDX = (PFN_vkCmdDispatchGraphIndirectAMDX)load(context, "vkCmdDispatchGraphIndirectAMDX"); + vkCmdDispatchGraphIndirectCountAMDX = (PFN_vkCmdDispatchGraphIndirectCountAMDX)load(context, "vkCmdDispatchGraphIndirectCountAMDX"); + vkCmdInitializeGraphScratchMemoryAMDX = (PFN_vkCmdInitializeGraphScratchMemoryAMDX)load(context, "vkCmdInitializeGraphScratchMemoryAMDX"); + vkCreateExecutionGraphPipelinesAMDX = (PFN_vkCreateExecutionGraphPipelinesAMDX)load(context, "vkCreateExecutionGraphPipelinesAMDX"); + vkGetExecutionGraphPipelineNodeIndexAMDX = (PFN_vkGetExecutionGraphPipelineNodeIndexAMDX)load(context, "vkGetExecutionGraphPipelineNodeIndexAMDX"); + vkGetExecutionGraphPipelineScratchSizeAMDX = (PFN_vkGetExecutionGraphPipelineScratchSizeAMDX)load(context, "vkGetExecutionGraphPipelineScratchSizeAMDX"); +#endif /* defined(VK_AMDX_shader_enqueue) */ +#if defined(VK_AMD_buffer_marker) + vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD)load(context, "vkCmdWriteBufferMarkerAMD"); +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + vkSetLocalDimmingAMD = (PFN_vkSetLocalDimmingAMD)load(context, "vkSetLocalDimmingAMD"); +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + vkCmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD)load(context, "vkCmdDrawIndexedIndirectCountAMD"); + vkCmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)load(context, "vkCmdDrawIndirectCountAMD"); +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + vkGetShaderInfoAMD = (PFN_vkGetShaderInfoAMD)load(context, "vkGetShaderInfoAMD"); +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)load(context, "vkGetAndroidHardwareBufferPropertiesANDROID"); + vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID)load(context, "vkGetMemoryAndroidHardwareBufferANDROID"); +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_attachment_feedback_loop_dynamic_state) + vkCmdSetAttachmentFeedbackLoopEnableEXT = (PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT)load(context, "vkCmdSetAttachmentFeedbackLoopEnableEXT"); +#endif /* defined(VK_EXT_attachment_feedback_loop_dynamic_state) */ +#if defined(VK_EXT_buffer_device_address) + vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)load(context, "vkGetBufferDeviceAddressEXT"); +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT)load(context, "vkGetCalibratedTimestampsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) + vkCmdSetColorWriteEnableEXT = (PFN_vkCmdSetColorWriteEnableEXT)load(context, "vkCmdSetColorWriteEnableEXT"); +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) + vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)load(context, "vkCmdBeginConditionalRenderingEXT"); + vkCmdEndConditionalRenderingEXT = (PFN_vkCmdEndConditionalRenderingEXT)load(context, "vkCmdEndConditionalRenderingEXT"); +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + vkCmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)load(context, "vkCmdDebugMarkerBeginEXT"); + vkCmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)load(context, "vkCmdDebugMarkerEndEXT"); + vkCmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)load(context, "vkCmdDebugMarkerInsertEXT"); + vkDebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)load(context, "vkDebugMarkerSetObjectNameEXT"); + vkDebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)load(context, "vkDebugMarkerSetObjectTagEXT"); +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_depth_bias_control) + vkCmdSetDepthBias2EXT = (PFN_vkCmdSetDepthBias2EXT)load(context, "vkCmdSetDepthBias2EXT"); +#endif /* defined(VK_EXT_depth_bias_control) */ +#if defined(VK_EXT_descriptor_buffer) + vkCmdBindDescriptorBufferEmbeddedSamplersEXT = (PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT)load(context, "vkCmdBindDescriptorBufferEmbeddedSamplersEXT"); + vkCmdBindDescriptorBuffersEXT = (PFN_vkCmdBindDescriptorBuffersEXT)load(context, "vkCmdBindDescriptorBuffersEXT"); + vkCmdSetDescriptorBufferOffsetsEXT = (PFN_vkCmdSetDescriptorBufferOffsetsEXT)load(context, "vkCmdSetDescriptorBufferOffsetsEXT"); + vkGetBufferOpaqueCaptureDescriptorDataEXT = (PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT)load(context, "vkGetBufferOpaqueCaptureDescriptorDataEXT"); + vkGetDescriptorEXT = (PFN_vkGetDescriptorEXT)load(context, "vkGetDescriptorEXT"); + vkGetDescriptorSetLayoutBindingOffsetEXT = (PFN_vkGetDescriptorSetLayoutBindingOffsetEXT)load(context, "vkGetDescriptorSetLayoutBindingOffsetEXT"); + vkGetDescriptorSetLayoutSizeEXT = (PFN_vkGetDescriptorSetLayoutSizeEXT)load(context, "vkGetDescriptorSetLayoutSizeEXT"); + vkGetImageOpaqueCaptureDescriptorDataEXT = (PFN_vkGetImageOpaqueCaptureDescriptorDataEXT)load(context, "vkGetImageOpaqueCaptureDescriptorDataEXT"); + vkGetImageViewOpaqueCaptureDescriptorDataEXT = (PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT)load(context, "vkGetImageViewOpaqueCaptureDescriptorDataEXT"); + vkGetSamplerOpaqueCaptureDescriptorDataEXT = (PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT)load(context, "vkGetSamplerOpaqueCaptureDescriptorDataEXT"); +#endif /* defined(VK_EXT_descriptor_buffer) */ +#if defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) + vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT = (PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT)load(context, "vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT"); +#endif /* defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) */ +#if defined(VK_EXT_device_fault) + vkGetDeviceFaultInfoEXT = (PFN_vkGetDeviceFaultInfoEXT)load(context, "vkGetDeviceFaultInfoEXT"); +#endif /* defined(VK_EXT_device_fault) */ +#if defined(VK_EXT_discard_rectangles) + vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT)load(context, "vkCmdSetDiscardRectangleEXT"); +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 + vkCmdSetDiscardRectangleEnableEXT = (PFN_vkCmdSetDiscardRectangleEnableEXT)load(context, "vkCmdSetDiscardRectangleEnableEXT"); + vkCmdSetDiscardRectangleModeEXT = (PFN_vkCmdSetDiscardRectangleModeEXT)load(context, "vkCmdSetDiscardRectangleModeEXT"); +#endif /* defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 */ +#if defined(VK_EXT_display_control) + vkDisplayPowerControlEXT = (PFN_vkDisplayPowerControlEXT)load(context, "vkDisplayPowerControlEXT"); + vkGetSwapchainCounterEXT = (PFN_vkGetSwapchainCounterEXT)load(context, "vkGetSwapchainCounterEXT"); + vkRegisterDeviceEventEXT = (PFN_vkRegisterDeviceEventEXT)load(context, "vkRegisterDeviceEventEXT"); + vkRegisterDisplayEventEXT = (PFN_vkRegisterDisplayEventEXT)load(context, "vkRegisterDisplayEventEXT"); +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_external_memory_host) + vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)load(context, "vkGetMemoryHostPointerPropertiesEXT"); +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + vkAcquireFullScreenExclusiveModeEXT = (PFN_vkAcquireFullScreenExclusiveModeEXT)load(context, "vkAcquireFullScreenExclusiveModeEXT"); + vkReleaseFullScreenExclusiveModeEXT = (PFN_vkReleaseFullScreenExclusiveModeEXT)load(context, "vkReleaseFullScreenExclusiveModeEXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + vkSetHdrMetadataEXT = (PFN_vkSetHdrMetadataEXT)load(context, "vkSetHdrMetadataEXT"); +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_image_copy) + vkCopyImageToImageEXT = (PFN_vkCopyImageToImageEXT)load(context, "vkCopyImageToImageEXT"); + vkCopyImageToMemoryEXT = (PFN_vkCopyImageToMemoryEXT)load(context, "vkCopyImageToMemoryEXT"); + vkCopyMemoryToImageEXT = (PFN_vkCopyMemoryToImageEXT)load(context, "vkCopyMemoryToImageEXT"); + vkTransitionImageLayoutEXT = (PFN_vkTransitionImageLayoutEXT)load(context, "vkTransitionImageLayoutEXT"); +#endif /* defined(VK_EXT_host_image_copy) */ +#if defined(VK_EXT_host_query_reset) + vkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)load(context, "vkResetQueryPoolEXT"); +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) + vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)load(context, "vkGetImageDrmFormatModifierPropertiesEXT"); +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + vkCmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT)load(context, "vkCmdSetLineStippleEXT"); +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_mesh_shader) + vkCmdDrawMeshTasksEXT = (PFN_vkCmdDrawMeshTasksEXT)load(context, "vkCmdDrawMeshTasksEXT"); + vkCmdDrawMeshTasksIndirectCountEXT = (PFN_vkCmdDrawMeshTasksIndirectCountEXT)load(context, "vkCmdDrawMeshTasksIndirectCountEXT"); + vkCmdDrawMeshTasksIndirectEXT = (PFN_vkCmdDrawMeshTasksIndirectEXT)load(context, "vkCmdDrawMeshTasksIndirectEXT"); +#endif /* defined(VK_EXT_mesh_shader) */ +#if defined(VK_EXT_metal_objects) + vkExportMetalObjectsEXT = (PFN_vkExportMetalObjectsEXT)load(context, "vkExportMetalObjectsEXT"); +#endif /* defined(VK_EXT_metal_objects) */ +#if defined(VK_EXT_multi_draw) + vkCmdDrawMultiEXT = (PFN_vkCmdDrawMultiEXT)load(context, "vkCmdDrawMultiEXT"); + vkCmdDrawMultiIndexedEXT = (PFN_vkCmdDrawMultiIndexedEXT)load(context, "vkCmdDrawMultiIndexedEXT"); +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_opacity_micromap) + vkBuildMicromapsEXT = (PFN_vkBuildMicromapsEXT)load(context, "vkBuildMicromapsEXT"); + vkCmdBuildMicromapsEXT = (PFN_vkCmdBuildMicromapsEXT)load(context, "vkCmdBuildMicromapsEXT"); + vkCmdCopyMemoryToMicromapEXT = (PFN_vkCmdCopyMemoryToMicromapEXT)load(context, "vkCmdCopyMemoryToMicromapEXT"); + vkCmdCopyMicromapEXT = (PFN_vkCmdCopyMicromapEXT)load(context, "vkCmdCopyMicromapEXT"); + vkCmdCopyMicromapToMemoryEXT = (PFN_vkCmdCopyMicromapToMemoryEXT)load(context, "vkCmdCopyMicromapToMemoryEXT"); + vkCmdWriteMicromapsPropertiesEXT = (PFN_vkCmdWriteMicromapsPropertiesEXT)load(context, "vkCmdWriteMicromapsPropertiesEXT"); + vkCopyMemoryToMicromapEXT = (PFN_vkCopyMemoryToMicromapEXT)load(context, "vkCopyMemoryToMicromapEXT"); + vkCopyMicromapEXT = (PFN_vkCopyMicromapEXT)load(context, "vkCopyMicromapEXT"); + vkCopyMicromapToMemoryEXT = (PFN_vkCopyMicromapToMemoryEXT)load(context, "vkCopyMicromapToMemoryEXT"); + vkCreateMicromapEXT = (PFN_vkCreateMicromapEXT)load(context, "vkCreateMicromapEXT"); + vkDestroyMicromapEXT = (PFN_vkDestroyMicromapEXT)load(context, "vkDestroyMicromapEXT"); + vkGetDeviceMicromapCompatibilityEXT = (PFN_vkGetDeviceMicromapCompatibilityEXT)load(context, "vkGetDeviceMicromapCompatibilityEXT"); + vkGetMicromapBuildSizesEXT = (PFN_vkGetMicromapBuildSizesEXT)load(context, "vkGetMicromapBuildSizesEXT"); + vkWriteMicromapsPropertiesEXT = (PFN_vkWriteMicromapsPropertiesEXT)load(context, "vkWriteMicromapsPropertiesEXT"); +#endif /* defined(VK_EXT_opacity_micromap) */ +#if defined(VK_EXT_pageable_device_local_memory) + vkSetDeviceMemoryPriorityEXT = (PFN_vkSetDeviceMemoryPriorityEXT)load(context, "vkSetDeviceMemoryPriorityEXT"); +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) + vkGetPipelinePropertiesEXT = (PFN_vkGetPipelinePropertiesEXT)load(context, "vkGetPipelinePropertiesEXT"); +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) + vkCreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT)load(context, "vkCreatePrivateDataSlotEXT"); + vkDestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT)load(context, "vkDestroyPrivateDataSlotEXT"); + vkGetPrivateDataEXT = (PFN_vkGetPrivateDataEXT)load(context, "vkGetPrivateDataEXT"); + vkSetPrivateDataEXT = (PFN_vkSetPrivateDataEXT)load(context, "vkSetPrivateDataEXT"); +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT)load(context, "vkCmdSetSampleLocationsEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_shader_module_identifier) + vkGetShaderModuleCreateInfoIdentifierEXT = (PFN_vkGetShaderModuleCreateInfoIdentifierEXT)load(context, "vkGetShaderModuleCreateInfoIdentifierEXT"); + vkGetShaderModuleIdentifierEXT = (PFN_vkGetShaderModuleIdentifierEXT)load(context, "vkGetShaderModuleIdentifierEXT"); +#endif /* defined(VK_EXT_shader_module_identifier) */ +#if defined(VK_EXT_shader_object) + vkCmdBindShadersEXT = (PFN_vkCmdBindShadersEXT)load(context, "vkCmdBindShadersEXT"); + vkCreateShadersEXT = (PFN_vkCreateShadersEXT)load(context, "vkCreateShadersEXT"); + vkDestroyShaderEXT = (PFN_vkDestroyShaderEXT)load(context, "vkDestroyShaderEXT"); + vkGetShaderBinaryDataEXT = (PFN_vkGetShaderBinaryDataEXT)load(context, "vkGetShaderBinaryDataEXT"); +#endif /* defined(VK_EXT_shader_object) */ +#if defined(VK_EXT_swapchain_maintenance1) + vkReleaseSwapchainImagesEXT = (PFN_vkReleaseSwapchainImagesEXT)load(context, "vkReleaseSwapchainImagesEXT"); +#endif /* defined(VK_EXT_swapchain_maintenance1) */ +#if defined(VK_EXT_transform_feedback) + vkCmdBeginQueryIndexedEXT = (PFN_vkCmdBeginQueryIndexedEXT)load(context, "vkCmdBeginQueryIndexedEXT"); + vkCmdBeginTransformFeedbackEXT = (PFN_vkCmdBeginTransformFeedbackEXT)load(context, "vkCmdBeginTransformFeedbackEXT"); + vkCmdBindTransformFeedbackBuffersEXT = (PFN_vkCmdBindTransformFeedbackBuffersEXT)load(context, "vkCmdBindTransformFeedbackBuffersEXT"); + vkCmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)load(context, "vkCmdDrawIndirectByteCountEXT"); + vkCmdEndQueryIndexedEXT = (PFN_vkCmdEndQueryIndexedEXT)load(context, "vkCmdEndQueryIndexedEXT"); + vkCmdEndTransformFeedbackEXT = (PFN_vkCmdEndTransformFeedbackEXT)load(context, "vkCmdEndTransformFeedbackEXT"); +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + vkCreateValidationCacheEXT = (PFN_vkCreateValidationCacheEXT)load(context, "vkCreateValidationCacheEXT"); + vkDestroyValidationCacheEXT = (PFN_vkDestroyValidationCacheEXT)load(context, "vkDestroyValidationCacheEXT"); + vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT)load(context, "vkGetValidationCacheDataEXT"); + vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT)load(context, "vkMergeValidationCachesEXT"); +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_FUCHSIA_buffer_collection) + vkCreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA)load(context, "vkCreateBufferCollectionFUCHSIA"); + vkDestroyBufferCollectionFUCHSIA = (PFN_vkDestroyBufferCollectionFUCHSIA)load(context, "vkDestroyBufferCollectionFUCHSIA"); + vkGetBufferCollectionPropertiesFUCHSIA = (PFN_vkGetBufferCollectionPropertiesFUCHSIA)load(context, "vkGetBufferCollectionPropertiesFUCHSIA"); + vkSetBufferCollectionBufferConstraintsFUCHSIA = (PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA)load(context, "vkSetBufferCollectionBufferConstraintsFUCHSIA"); + vkSetBufferCollectionImageConstraintsFUCHSIA = (PFN_vkSetBufferCollectionImageConstraintsFUCHSIA)load(context, "vkSetBufferCollectionImageConstraintsFUCHSIA"); +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) + vkGetMemoryZirconHandleFUCHSIA = (PFN_vkGetMemoryZirconHandleFUCHSIA)load(context, "vkGetMemoryZirconHandleFUCHSIA"); + vkGetMemoryZirconHandlePropertiesFUCHSIA = (PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA)load(context, "vkGetMemoryZirconHandlePropertiesFUCHSIA"); +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) + vkGetSemaphoreZirconHandleFUCHSIA = (PFN_vkGetSemaphoreZirconHandleFUCHSIA)load(context, "vkGetSemaphoreZirconHandleFUCHSIA"); + vkImportSemaphoreZirconHandleFUCHSIA = (PFN_vkImportSemaphoreZirconHandleFUCHSIA)load(context, "vkImportSemaphoreZirconHandleFUCHSIA"); +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_GOOGLE_display_timing) + vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE)load(context, "vkGetPastPresentationTimingGOOGLE"); + vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE)load(context, "vkGetRefreshCycleDurationGOOGLE"); +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_cluster_culling_shader) + vkCmdDrawClusterHUAWEI = (PFN_vkCmdDrawClusterHUAWEI)load(context, "vkCmdDrawClusterHUAWEI"); + vkCmdDrawClusterIndirectHUAWEI = (PFN_vkCmdDrawClusterIndirectHUAWEI)load(context, "vkCmdDrawClusterIndirectHUAWEI"); +#endif /* defined(VK_HUAWEI_cluster_culling_shader) */ +#if defined(VK_HUAWEI_invocation_mask) + vkCmdBindInvocationMaskHUAWEI = (PFN_vkCmdBindInvocationMaskHUAWEI)load(context, "vkCmdBindInvocationMaskHUAWEI"); +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) + vkCmdSubpassShadingHUAWEI = (PFN_vkCmdSubpassShadingHUAWEI)load(context, "vkCmdSubpassShadingHUAWEI"); + vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = (PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)load(context, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI"); +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) + vkAcquirePerformanceConfigurationINTEL = (PFN_vkAcquirePerformanceConfigurationINTEL)load(context, "vkAcquirePerformanceConfigurationINTEL"); + vkCmdSetPerformanceMarkerINTEL = (PFN_vkCmdSetPerformanceMarkerINTEL)load(context, "vkCmdSetPerformanceMarkerINTEL"); + vkCmdSetPerformanceOverrideINTEL = (PFN_vkCmdSetPerformanceOverrideINTEL)load(context, "vkCmdSetPerformanceOverrideINTEL"); + vkCmdSetPerformanceStreamMarkerINTEL = (PFN_vkCmdSetPerformanceStreamMarkerINTEL)load(context, "vkCmdSetPerformanceStreamMarkerINTEL"); + vkGetPerformanceParameterINTEL = (PFN_vkGetPerformanceParameterINTEL)load(context, "vkGetPerformanceParameterINTEL"); + vkInitializePerformanceApiINTEL = (PFN_vkInitializePerformanceApiINTEL)load(context, "vkInitializePerformanceApiINTEL"); + vkQueueSetPerformanceConfigurationINTEL = (PFN_vkQueueSetPerformanceConfigurationINTEL)load(context, "vkQueueSetPerformanceConfigurationINTEL"); + vkReleasePerformanceConfigurationINTEL = (PFN_vkReleasePerformanceConfigurationINTEL)load(context, "vkReleasePerformanceConfigurationINTEL"); + vkUninitializePerformanceApiINTEL = (PFN_vkUninitializePerformanceApiINTEL)load(context, "vkUninitializePerformanceApiINTEL"); +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) + vkBuildAccelerationStructuresKHR = (PFN_vkBuildAccelerationStructuresKHR)load(context, "vkBuildAccelerationStructuresKHR"); + vkCmdBuildAccelerationStructuresIndirectKHR = (PFN_vkCmdBuildAccelerationStructuresIndirectKHR)load(context, "vkCmdBuildAccelerationStructuresIndirectKHR"); + vkCmdBuildAccelerationStructuresKHR = (PFN_vkCmdBuildAccelerationStructuresKHR)load(context, "vkCmdBuildAccelerationStructuresKHR"); + vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR)load(context, "vkCmdCopyAccelerationStructureKHR"); + vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR)load(context, "vkCmdCopyAccelerationStructureToMemoryKHR"); + vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR)load(context, "vkCmdCopyMemoryToAccelerationStructureKHR"); + vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)load(context, "vkCmdWriteAccelerationStructuresPropertiesKHR"); + vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR)load(context, "vkCopyAccelerationStructureKHR"); + vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR)load(context, "vkCopyAccelerationStructureToMemoryKHR"); + vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR)load(context, "vkCopyMemoryToAccelerationStructureKHR"); + vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR)load(context, "vkCreateAccelerationStructureKHR"); + vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR)load(context, "vkDestroyAccelerationStructureKHR"); + vkGetAccelerationStructureBuildSizesKHR = (PFN_vkGetAccelerationStructureBuildSizesKHR)load(context, "vkGetAccelerationStructureBuildSizesKHR"); + vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR)load(context, "vkGetAccelerationStructureDeviceAddressKHR"); + vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)load(context, "vkGetDeviceAccelerationStructureCompatibilityKHR"); + vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR)load(context, "vkWriteAccelerationStructuresPropertiesKHR"); +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_bind_memory2) + vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)load(context, "vkBindBufferMemory2KHR"); + vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)load(context, "vkBindImageMemory2KHR"); +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressKHR)load(context, "vkGetBufferDeviceAddressKHR"); + vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR)load(context, "vkGetBufferOpaqueCaptureAddressKHR"); + vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)load(context, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_copy_commands2) + vkCmdBlitImage2KHR = (PFN_vkCmdBlitImage2KHR)load(context, "vkCmdBlitImage2KHR"); + vkCmdCopyBuffer2KHR = (PFN_vkCmdCopyBuffer2KHR)load(context, "vkCmdCopyBuffer2KHR"); + vkCmdCopyBufferToImage2KHR = (PFN_vkCmdCopyBufferToImage2KHR)load(context, "vkCmdCopyBufferToImage2KHR"); + vkCmdCopyImage2KHR = (PFN_vkCmdCopyImage2KHR)load(context, "vkCmdCopyImage2KHR"); + vkCmdCopyImageToBuffer2KHR = (PFN_vkCmdCopyImageToBuffer2KHR)load(context, "vkCmdCopyImageToBuffer2KHR"); + vkCmdResolveImage2KHR = (PFN_vkCmdResolveImage2KHR)load(context, "vkCmdResolveImage2KHR"); +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) + vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR)load(context, "vkCmdBeginRenderPass2KHR"); + vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)load(context, "vkCmdEndRenderPass2KHR"); + vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)load(context, "vkCmdNextSubpass2KHR"); + vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)load(context, "vkCreateRenderPass2KHR"); +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + vkCreateDeferredOperationKHR = (PFN_vkCreateDeferredOperationKHR)load(context, "vkCreateDeferredOperationKHR"); + vkDeferredOperationJoinKHR = (PFN_vkDeferredOperationJoinKHR)load(context, "vkDeferredOperationJoinKHR"); + vkDestroyDeferredOperationKHR = (PFN_vkDestroyDeferredOperationKHR)load(context, "vkDestroyDeferredOperationKHR"); + vkGetDeferredOperationMaxConcurrencyKHR = (PFN_vkGetDeferredOperationMaxConcurrencyKHR)load(context, "vkGetDeferredOperationMaxConcurrencyKHR"); + vkGetDeferredOperationResultKHR = (PFN_vkGetDeferredOperationResultKHR)load(context, "vkGetDeferredOperationResultKHR"); +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + vkCreateDescriptorUpdateTemplateKHR = (PFN_vkCreateDescriptorUpdateTemplateKHR)load(context, "vkCreateDescriptorUpdateTemplateKHR"); + vkDestroyDescriptorUpdateTemplateKHR = (PFN_vkDestroyDescriptorUpdateTemplateKHR)load(context, "vkDestroyDescriptorUpdateTemplateKHR"); + vkUpdateDescriptorSetWithTemplateKHR = (PFN_vkUpdateDescriptorSetWithTemplateKHR)load(context, "vkUpdateDescriptorSetWithTemplateKHR"); +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + vkCmdDispatchBaseKHR = (PFN_vkCmdDispatchBaseKHR)load(context, "vkCmdDispatchBaseKHR"); + vkCmdSetDeviceMaskKHR = (PFN_vkCmdSetDeviceMaskKHR)load(context, "vkCmdSetDeviceMaskKHR"); + vkGetDeviceGroupPeerMemoryFeaturesKHR = (PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)load(context, "vkGetDeviceGroupPeerMemoryFeaturesKHR"); +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + vkCreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)load(context, "vkCreateSharedSwapchainsKHR"); +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)load(context, "vkCmdDrawIndexedIndirectCountKHR"); + vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)load(context, "vkCmdDrawIndirectCountKHR"); +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) + vkCmdBeginRenderingKHR = (PFN_vkCmdBeginRenderingKHR)load(context, "vkCmdBeginRenderingKHR"); + vkCmdEndRenderingKHR = (PFN_vkCmdEndRenderingKHR)load(context, "vkCmdEndRenderingKHR"); +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_fd) + vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)load(context, "vkGetFenceFdKHR"); + vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)load(context, "vkImportFenceFdKHR"); +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)load(context, "vkGetFenceWin32HandleKHR"); + vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR)load(context, "vkImportFenceWin32HandleKHR"); +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)load(context, "vkGetMemoryFdKHR"); + vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)load(context, "vkGetMemoryFdPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)load(context, "vkGetMemoryWin32HandleKHR"); + vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)load(context, "vkGetMemoryWin32HandlePropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)load(context, "vkGetSemaphoreFdKHR"); + vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)load(context, "vkImportSemaphoreFdKHR"); +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)load(context, "vkGetSemaphoreWin32HandleKHR"); + vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR)load(context, "vkImportSemaphoreWin32HandleKHR"); +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) + vkCmdSetFragmentShadingRateKHR = (PFN_vkCmdSetFragmentShadingRateKHR)load(context, "vkCmdSetFragmentShadingRateKHR"); +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_memory_requirements2) + vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)load(context, "vkGetBufferMemoryRequirements2KHR"); + vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)load(context, "vkGetImageMemoryRequirements2KHR"); + vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)load(context, "vkGetImageSparseMemoryRequirements2KHR"); +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR)load(context, "vkTrimCommandPoolKHR"); +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR)load(context, "vkGetDescriptorSetLayoutSupportKHR"); +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) + vkGetDeviceBufferMemoryRequirementsKHR = (PFN_vkGetDeviceBufferMemoryRequirementsKHR)load(context, "vkGetDeviceBufferMemoryRequirementsKHR"); + vkGetDeviceImageMemoryRequirementsKHR = (PFN_vkGetDeviceImageMemoryRequirementsKHR)load(context, "vkGetDeviceImageMemoryRequirementsKHR"); + vkGetDeviceImageSparseMemoryRequirementsKHR = (PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)load(context, "vkGetDeviceImageSparseMemoryRequirementsKHR"); +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_maintenance5) + vkCmdBindIndexBuffer2KHR = (PFN_vkCmdBindIndexBuffer2KHR)load(context, "vkCmdBindIndexBuffer2KHR"); + vkGetDeviceImageSubresourceLayoutKHR = (PFN_vkGetDeviceImageSubresourceLayoutKHR)load(context, "vkGetDeviceImageSubresourceLayoutKHR"); + vkGetImageSubresourceLayout2KHR = (PFN_vkGetImageSubresourceLayout2KHR)load(context, "vkGetImageSubresourceLayout2KHR"); + vkGetRenderingAreaGranularityKHR = (PFN_vkGetRenderingAreaGranularityKHR)load(context, "vkGetRenderingAreaGranularityKHR"); +#endif /* defined(VK_KHR_maintenance5) */ +#if defined(VK_KHR_map_memory2) + vkMapMemory2KHR = (PFN_vkMapMemory2KHR)load(context, "vkMapMemory2KHR"); + vkUnmapMemory2KHR = (PFN_vkUnmapMemory2KHR)load(context, "vkUnmapMemory2KHR"); +#endif /* defined(VK_KHR_map_memory2) */ +#if defined(VK_KHR_performance_query) + vkAcquireProfilingLockKHR = (PFN_vkAcquireProfilingLockKHR)load(context, "vkAcquireProfilingLockKHR"); + vkReleaseProfilingLockKHR = (PFN_vkReleaseProfilingLockKHR)load(context, "vkReleaseProfilingLockKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + vkGetPipelineExecutableInternalRepresentationsKHR = (PFN_vkGetPipelineExecutableInternalRepresentationsKHR)load(context, "vkGetPipelineExecutableInternalRepresentationsKHR"); + vkGetPipelineExecutablePropertiesKHR = (PFN_vkGetPipelineExecutablePropertiesKHR)load(context, "vkGetPipelineExecutablePropertiesKHR"); + vkGetPipelineExecutableStatisticsKHR = (PFN_vkGetPipelineExecutableStatisticsKHR)load(context, "vkGetPipelineExecutableStatisticsKHR"); +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) + vkWaitForPresentKHR = (PFN_vkWaitForPresentKHR)load(context, "vkWaitForPresentKHR"); +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) + vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)load(context, "vkCmdPushDescriptorSetKHR"); +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) + vkCmdTraceRaysIndirect2KHR = (PFN_vkCmdTraceRaysIndirect2KHR)load(context, "vkCmdTraceRaysIndirect2KHR"); +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) + vkCmdSetRayTracingPipelineStackSizeKHR = (PFN_vkCmdSetRayTracingPipelineStackSizeKHR)load(context, "vkCmdSetRayTracingPipelineStackSizeKHR"); + vkCmdTraceRaysIndirectKHR = (PFN_vkCmdTraceRaysIndirectKHR)load(context, "vkCmdTraceRaysIndirectKHR"); + vkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR)load(context, "vkCmdTraceRaysKHR"); + vkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR)load(context, "vkCreateRayTracingPipelinesKHR"); + vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = (PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)load(context, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"); + vkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR)load(context, "vkGetRayTracingShaderGroupHandlesKHR"); + vkGetRayTracingShaderGroupStackSizeKHR = (PFN_vkGetRayTracingShaderGroupStackSizeKHR)load(context, "vkGetRayTracingShaderGroupStackSizeKHR"); +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR)load(context, "vkCreateSamplerYcbcrConversionKHR"); + vkDestroySamplerYcbcrConversionKHR = (PFN_vkDestroySamplerYcbcrConversionKHR)load(context, "vkDestroySamplerYcbcrConversionKHR"); +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + vkGetSwapchainStatusKHR = (PFN_vkGetSwapchainStatusKHR)load(context, "vkGetSwapchainStatusKHR"); +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR"); + vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR"); + vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR"); + vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR"); + vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR"); +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) + vkCmdPipelineBarrier2KHR = (PFN_vkCmdPipelineBarrier2KHR)load(context, "vkCmdPipelineBarrier2KHR"); + vkCmdResetEvent2KHR = (PFN_vkCmdResetEvent2KHR)load(context, "vkCmdResetEvent2KHR"); + vkCmdSetEvent2KHR = (PFN_vkCmdSetEvent2KHR)load(context, "vkCmdSetEvent2KHR"); + vkCmdWaitEvents2KHR = (PFN_vkCmdWaitEvents2KHR)load(context, "vkCmdWaitEvents2KHR"); + vkCmdWriteTimestamp2KHR = (PFN_vkCmdWriteTimestamp2KHR)load(context, "vkCmdWriteTimestamp2KHR"); + vkQueueSubmit2KHR = (PFN_vkQueueSubmit2KHR)load(context, "vkQueueSubmit2KHR"); +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) + vkCmdWriteBufferMarker2AMD = (PFN_vkCmdWriteBufferMarker2AMD)load(context, "vkCmdWriteBufferMarker2AMD"); +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) + vkGetQueueCheckpointData2NV = (PFN_vkGetQueueCheckpointData2NV)load(context, "vkGetQueueCheckpointData2NV"); +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) + vkGetSemaphoreCounterValueKHR = (PFN_vkGetSemaphoreCounterValueKHR)load(context, "vkGetSemaphoreCounterValueKHR"); + vkSignalSemaphoreKHR = (PFN_vkSignalSemaphoreKHR)load(context, "vkSignalSemaphoreKHR"); + vkWaitSemaphoresKHR = (PFN_vkWaitSemaphoresKHR)load(context, "vkWaitSemaphoresKHR"); +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) + vkCmdDecodeVideoKHR = (PFN_vkCmdDecodeVideoKHR)load(context, "vkCmdDecodeVideoKHR"); +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) + vkCmdEncodeVideoKHR = (PFN_vkCmdEncodeVideoKHR)load(context, "vkCmdEncodeVideoKHR"); + vkGetEncodedVideoSessionParametersKHR = (PFN_vkGetEncodedVideoSessionParametersKHR)load(context, "vkGetEncodedVideoSessionParametersKHR"); +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) + vkBindVideoSessionMemoryKHR = (PFN_vkBindVideoSessionMemoryKHR)load(context, "vkBindVideoSessionMemoryKHR"); + vkCmdBeginVideoCodingKHR = (PFN_vkCmdBeginVideoCodingKHR)load(context, "vkCmdBeginVideoCodingKHR"); + vkCmdControlVideoCodingKHR = (PFN_vkCmdControlVideoCodingKHR)load(context, "vkCmdControlVideoCodingKHR"); + vkCmdEndVideoCodingKHR = (PFN_vkCmdEndVideoCodingKHR)load(context, "vkCmdEndVideoCodingKHR"); + vkCreateVideoSessionKHR = (PFN_vkCreateVideoSessionKHR)load(context, "vkCreateVideoSessionKHR"); + vkCreateVideoSessionParametersKHR = (PFN_vkCreateVideoSessionParametersKHR)load(context, "vkCreateVideoSessionParametersKHR"); + vkDestroyVideoSessionKHR = (PFN_vkDestroyVideoSessionKHR)load(context, "vkDestroyVideoSessionKHR"); + vkDestroyVideoSessionParametersKHR = (PFN_vkDestroyVideoSessionParametersKHR)load(context, "vkDestroyVideoSessionParametersKHR"); + vkGetVideoSessionMemoryRequirementsKHR = (PFN_vkGetVideoSessionMemoryRequirementsKHR)load(context, "vkGetVideoSessionMemoryRequirementsKHR"); + vkUpdateVideoSessionParametersKHR = (PFN_vkUpdateVideoSessionParametersKHR)load(context, "vkUpdateVideoSessionParametersKHR"); +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_NVX_binary_import) + vkCmdCuLaunchKernelNVX = (PFN_vkCmdCuLaunchKernelNVX)load(context, "vkCmdCuLaunchKernelNVX"); + vkCreateCuFunctionNVX = (PFN_vkCreateCuFunctionNVX)load(context, "vkCreateCuFunctionNVX"); + vkCreateCuModuleNVX = (PFN_vkCreateCuModuleNVX)load(context, "vkCreateCuModuleNVX"); + vkDestroyCuFunctionNVX = (PFN_vkDestroyCuFunctionNVX)load(context, "vkDestroyCuFunctionNVX"); + vkDestroyCuModuleNVX = (PFN_vkDestroyCuModuleNVX)load(context, "vkDestroyCuModuleNVX"); +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) + vkGetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX)load(context, "vkGetImageViewAddressNVX"); + vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)load(context, "vkGetImageViewHandleNVX"); +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV)load(context, "vkCmdSetViewportWScalingNV"); +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_copy_memory_indirect) + vkCmdCopyMemoryIndirectNV = (PFN_vkCmdCopyMemoryIndirectNV)load(context, "vkCmdCopyMemoryIndirectNV"); + vkCmdCopyMemoryToImageIndirectNV = (PFN_vkCmdCopyMemoryToImageIndirectNV)load(context, "vkCmdCopyMemoryToImageIndirectNV"); +#endif /* defined(VK_NV_copy_memory_indirect) */ +#if defined(VK_NV_cuda_kernel_launch) + vkCmdCudaLaunchKernelNV = (PFN_vkCmdCudaLaunchKernelNV)load(context, "vkCmdCudaLaunchKernelNV"); + vkCreateCudaFunctionNV = (PFN_vkCreateCudaFunctionNV)load(context, "vkCreateCudaFunctionNV"); + vkCreateCudaModuleNV = (PFN_vkCreateCudaModuleNV)load(context, "vkCreateCudaModuleNV"); + vkDestroyCudaFunctionNV = (PFN_vkDestroyCudaFunctionNV)load(context, "vkDestroyCudaFunctionNV"); + vkDestroyCudaModuleNV = (PFN_vkDestroyCudaModuleNV)load(context, "vkDestroyCudaModuleNV"); + vkGetCudaModuleCacheNV = (PFN_vkGetCudaModuleCacheNV)load(context, "vkGetCudaModuleCacheNV"); +#endif /* defined(VK_NV_cuda_kernel_launch) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)load(context, "vkCmdSetCheckpointNV"); + vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV)load(context, "vkGetQueueCheckpointDataNV"); +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + vkCmdBindPipelineShaderGroupNV = (PFN_vkCmdBindPipelineShaderGroupNV)load(context, "vkCmdBindPipelineShaderGroupNV"); + vkCmdExecuteGeneratedCommandsNV = (PFN_vkCmdExecuteGeneratedCommandsNV)load(context, "vkCmdExecuteGeneratedCommandsNV"); + vkCmdPreprocessGeneratedCommandsNV = (PFN_vkCmdPreprocessGeneratedCommandsNV)load(context, "vkCmdPreprocessGeneratedCommandsNV"); + vkCreateIndirectCommandsLayoutNV = (PFN_vkCreateIndirectCommandsLayoutNV)load(context, "vkCreateIndirectCommandsLayoutNV"); + vkDestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV)load(context, "vkDestroyIndirectCommandsLayoutNV"); + vkGetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV)load(context, "vkGetGeneratedCommandsMemoryRequirementsNV"); +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_device_generated_commands_compute) + vkCmdUpdatePipelineIndirectBufferNV = (PFN_vkCmdUpdatePipelineIndirectBufferNV)load(context, "vkCmdUpdatePipelineIndirectBufferNV"); + vkGetPipelineIndirectDeviceAddressNV = (PFN_vkGetPipelineIndirectDeviceAddressNV)load(context, "vkGetPipelineIndirectDeviceAddressNV"); + vkGetPipelineIndirectMemoryRequirementsNV = (PFN_vkGetPipelineIndirectMemoryRequirementsNV)load(context, "vkGetPipelineIndirectMemoryRequirementsNV"); +#endif /* defined(VK_NV_device_generated_commands_compute) */ +#if defined(VK_NV_external_memory_rdma) + vkGetMemoryRemoteAddressNV = (PFN_vkGetMemoryRemoteAddressNV)load(context, "vkGetMemoryRemoteAddressNV"); +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) + vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV)load(context, "vkGetMemoryWin32HandleNV"); +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) + vkCmdSetFragmentShadingRateEnumNV = (PFN_vkCmdSetFragmentShadingRateEnumNV)load(context, "vkCmdSetFragmentShadingRateEnumNV"); +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_low_latency2) + vkGetLatencyTimingsNV = (PFN_vkGetLatencyTimingsNV)load(context, "vkGetLatencyTimingsNV"); + vkLatencySleepNV = (PFN_vkLatencySleepNV)load(context, "vkLatencySleepNV"); + vkQueueNotifyOutOfBandNV = (PFN_vkQueueNotifyOutOfBandNV)load(context, "vkQueueNotifyOutOfBandNV"); + vkSetLatencyMarkerNV = (PFN_vkSetLatencyMarkerNV)load(context, "vkSetLatencyMarkerNV"); + vkSetLatencySleepModeNV = (PFN_vkSetLatencySleepModeNV)load(context, "vkSetLatencySleepModeNV"); +#endif /* defined(VK_NV_low_latency2) */ +#if defined(VK_NV_memory_decompression) + vkCmdDecompressMemoryIndirectCountNV = (PFN_vkCmdDecompressMemoryIndirectCountNV)load(context, "vkCmdDecompressMemoryIndirectCountNV"); + vkCmdDecompressMemoryNV = (PFN_vkCmdDecompressMemoryNV)load(context, "vkCmdDecompressMemoryNV"); +#endif /* defined(VK_NV_memory_decompression) */ +#if defined(VK_NV_mesh_shader) + vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV)load(context, "vkCmdDrawMeshTasksIndirectCountNV"); + vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV)load(context, "vkCmdDrawMeshTasksIndirectNV"); + vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV)load(context, "vkCmdDrawMeshTasksNV"); +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_optical_flow) + vkBindOpticalFlowSessionImageNV = (PFN_vkBindOpticalFlowSessionImageNV)load(context, "vkBindOpticalFlowSessionImageNV"); + vkCmdOpticalFlowExecuteNV = (PFN_vkCmdOpticalFlowExecuteNV)load(context, "vkCmdOpticalFlowExecuteNV"); + vkCreateOpticalFlowSessionNV = (PFN_vkCreateOpticalFlowSessionNV)load(context, "vkCreateOpticalFlowSessionNV"); + vkDestroyOpticalFlowSessionNV = (PFN_vkDestroyOpticalFlowSessionNV)load(context, "vkDestroyOpticalFlowSessionNV"); +#endif /* defined(VK_NV_optical_flow) */ +#if defined(VK_NV_ray_tracing) + vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV)load(context, "vkBindAccelerationStructureMemoryNV"); + vkCmdBuildAccelerationStructureNV = (PFN_vkCmdBuildAccelerationStructureNV)load(context, "vkCmdBuildAccelerationStructureNV"); + vkCmdCopyAccelerationStructureNV = (PFN_vkCmdCopyAccelerationStructureNV)load(context, "vkCmdCopyAccelerationStructureNV"); + vkCmdTraceRaysNV = (PFN_vkCmdTraceRaysNV)load(context, "vkCmdTraceRaysNV"); + vkCmdWriteAccelerationStructuresPropertiesNV = (PFN_vkCmdWriteAccelerationStructuresPropertiesNV)load(context, "vkCmdWriteAccelerationStructuresPropertiesNV"); + vkCompileDeferredNV = (PFN_vkCompileDeferredNV)load(context, "vkCompileDeferredNV"); + vkCreateAccelerationStructureNV = (PFN_vkCreateAccelerationStructureNV)load(context, "vkCreateAccelerationStructureNV"); + vkCreateRayTracingPipelinesNV = (PFN_vkCreateRayTracingPipelinesNV)load(context, "vkCreateRayTracingPipelinesNV"); + vkDestroyAccelerationStructureNV = (PFN_vkDestroyAccelerationStructureNV)load(context, "vkDestroyAccelerationStructureNV"); + vkGetAccelerationStructureHandleNV = (PFN_vkGetAccelerationStructureHandleNV)load(context, "vkGetAccelerationStructureHandleNV"); + vkGetAccelerationStructureMemoryRequirementsNV = (PFN_vkGetAccelerationStructureMemoryRequirementsNV)load(context, "vkGetAccelerationStructureMemoryRequirementsNV"); + vkGetRayTracingShaderGroupHandlesNV = (PFN_vkGetRayTracingShaderGroupHandlesNV)load(context, "vkGetRayTracingShaderGroupHandlesNV"); +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 + vkCmdSetExclusiveScissorEnableNV = (PFN_vkCmdSetExclusiveScissorEnableNV)load(context, "vkCmdSetExclusiveScissorEnableNV"); +#endif /* defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 */ +#if defined(VK_NV_scissor_exclusive) + vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV)load(context, "vkCmdSetExclusiveScissorNV"); +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + vkCmdBindShadingRateImageNV = (PFN_vkCmdBindShadingRateImageNV)load(context, "vkCmdBindShadingRateImageNV"); + vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV)load(context, "vkCmdSetCoarseSampleOrderNV"); + vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV)load(context, "vkCmdSetViewportShadingRatePaletteNV"); +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_QCOM_tile_properties) + vkGetDynamicRenderingTilePropertiesQCOM = (PFN_vkGetDynamicRenderingTilePropertiesQCOM)load(context, "vkGetDynamicRenderingTilePropertiesQCOM"); + vkGetFramebufferTilePropertiesQCOM = (PFN_vkGetFramebufferTilePropertiesQCOM)load(context, "vkGetFramebufferTilePropertiesQCOM"); +#endif /* defined(VK_QCOM_tile_properties) */ +#if defined(VK_QNX_external_memory_screen_buffer) + vkGetScreenBufferPropertiesQNX = (PFN_vkGetScreenBufferPropertiesQNX)load(context, "vkGetScreenBufferPropertiesQNX"); +#endif /* defined(VK_QNX_external_memory_screen_buffer) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) + vkGetDescriptorSetHostMappingVALVE = (PFN_vkGetDescriptorSetHostMappingVALVE)load(context, "vkGetDescriptorSetHostMappingVALVE"); + vkGetDescriptorSetLayoutHostMappingInfoVALVE = (PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)load(context, "vkGetDescriptorSetLayoutHostMappingInfoVALVE"); +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) + vkCmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT)load(context, "vkCmdBindVertexBuffers2EXT"); + vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)load(context, "vkCmdSetCullModeEXT"); + vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)load(context, "vkCmdSetDepthBoundsTestEnableEXT"); + vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)load(context, "vkCmdSetDepthCompareOpEXT"); + vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)load(context, "vkCmdSetDepthTestEnableEXT"); + vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)load(context, "vkCmdSetDepthWriteEnableEXT"); + vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)load(context, "vkCmdSetFrontFaceEXT"); + vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)load(context, "vkCmdSetPrimitiveTopologyEXT"); + vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)load(context, "vkCmdSetScissorWithCountEXT"); + vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)load(context, "vkCmdSetStencilOpEXT"); + vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)load(context, "vkCmdSetStencilTestEnableEXT"); + vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)load(context, "vkCmdSetViewportWithCountEXT"); +#endif /* (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) + vkCmdSetDepthBiasEnableEXT = (PFN_vkCmdSetDepthBiasEnableEXT)load(context, "vkCmdSetDepthBiasEnableEXT"); + vkCmdSetLogicOpEXT = (PFN_vkCmdSetLogicOpEXT)load(context, "vkCmdSetLogicOpEXT"); + vkCmdSetPatchControlPointsEXT = (PFN_vkCmdSetPatchControlPointsEXT)load(context, "vkCmdSetPatchControlPointsEXT"); + vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT)load(context, "vkCmdSetPrimitiveRestartEnableEXT"); + vkCmdSetRasterizerDiscardEnableEXT = (PFN_vkCmdSetRasterizerDiscardEnableEXT)load(context, "vkCmdSetRasterizerDiscardEnableEXT"); +#endif /* (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) + vkCmdSetAlphaToCoverageEnableEXT = (PFN_vkCmdSetAlphaToCoverageEnableEXT)load(context, "vkCmdSetAlphaToCoverageEnableEXT"); + vkCmdSetAlphaToOneEnableEXT = (PFN_vkCmdSetAlphaToOneEnableEXT)load(context, "vkCmdSetAlphaToOneEnableEXT"); + vkCmdSetColorBlendAdvancedEXT = (PFN_vkCmdSetColorBlendAdvancedEXT)load(context, "vkCmdSetColorBlendAdvancedEXT"); + vkCmdSetColorBlendEnableEXT = (PFN_vkCmdSetColorBlendEnableEXT)load(context, "vkCmdSetColorBlendEnableEXT"); + vkCmdSetColorBlendEquationEXT = (PFN_vkCmdSetColorBlendEquationEXT)load(context, "vkCmdSetColorBlendEquationEXT"); + vkCmdSetColorWriteMaskEXT = (PFN_vkCmdSetColorWriteMaskEXT)load(context, "vkCmdSetColorWriteMaskEXT"); + vkCmdSetConservativeRasterizationModeEXT = (PFN_vkCmdSetConservativeRasterizationModeEXT)load(context, "vkCmdSetConservativeRasterizationModeEXT"); + vkCmdSetDepthClampEnableEXT = (PFN_vkCmdSetDepthClampEnableEXT)load(context, "vkCmdSetDepthClampEnableEXT"); + vkCmdSetDepthClipEnableEXT = (PFN_vkCmdSetDepthClipEnableEXT)load(context, "vkCmdSetDepthClipEnableEXT"); + vkCmdSetDepthClipNegativeOneToOneEXT = (PFN_vkCmdSetDepthClipNegativeOneToOneEXT)load(context, "vkCmdSetDepthClipNegativeOneToOneEXT"); + vkCmdSetExtraPrimitiveOverestimationSizeEXT = (PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT)load(context, "vkCmdSetExtraPrimitiveOverestimationSizeEXT"); + vkCmdSetLineRasterizationModeEXT = (PFN_vkCmdSetLineRasterizationModeEXT)load(context, "vkCmdSetLineRasterizationModeEXT"); + vkCmdSetLineStippleEnableEXT = (PFN_vkCmdSetLineStippleEnableEXT)load(context, "vkCmdSetLineStippleEnableEXT"); + vkCmdSetLogicOpEnableEXT = (PFN_vkCmdSetLogicOpEnableEXT)load(context, "vkCmdSetLogicOpEnableEXT"); + vkCmdSetPolygonModeEXT = (PFN_vkCmdSetPolygonModeEXT)load(context, "vkCmdSetPolygonModeEXT"); + vkCmdSetProvokingVertexModeEXT = (PFN_vkCmdSetProvokingVertexModeEXT)load(context, "vkCmdSetProvokingVertexModeEXT"); + vkCmdSetRasterizationSamplesEXT = (PFN_vkCmdSetRasterizationSamplesEXT)load(context, "vkCmdSetRasterizationSamplesEXT"); + vkCmdSetRasterizationStreamEXT = (PFN_vkCmdSetRasterizationStreamEXT)load(context, "vkCmdSetRasterizationStreamEXT"); + vkCmdSetSampleLocationsEnableEXT = (PFN_vkCmdSetSampleLocationsEnableEXT)load(context, "vkCmdSetSampleLocationsEnableEXT"); + vkCmdSetSampleMaskEXT = (PFN_vkCmdSetSampleMaskEXT)load(context, "vkCmdSetSampleMaskEXT"); + vkCmdSetTessellationDomainOriginEXT = (PFN_vkCmdSetTessellationDomainOriginEXT)load(context, "vkCmdSetTessellationDomainOriginEXT"); +#endif /* (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) + vkCmdSetViewportWScalingEnableNV = (PFN_vkCmdSetViewportWScalingEnableNV)load(context, "vkCmdSetViewportWScalingEnableNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) + vkCmdSetViewportSwizzleNV = (PFN_vkCmdSetViewportSwizzleNV)load(context, "vkCmdSetViewportSwizzleNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) + vkCmdSetCoverageToColorEnableNV = (PFN_vkCmdSetCoverageToColorEnableNV)load(context, "vkCmdSetCoverageToColorEnableNV"); + vkCmdSetCoverageToColorLocationNV = (PFN_vkCmdSetCoverageToColorLocationNV)load(context, "vkCmdSetCoverageToColorLocationNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) + vkCmdSetCoverageModulationModeNV = (PFN_vkCmdSetCoverageModulationModeNV)load(context, "vkCmdSetCoverageModulationModeNV"); + vkCmdSetCoverageModulationTableEnableNV = (PFN_vkCmdSetCoverageModulationTableEnableNV)load(context, "vkCmdSetCoverageModulationTableEnableNV"); + vkCmdSetCoverageModulationTableNV = (PFN_vkCmdSetCoverageModulationTableNV)load(context, "vkCmdSetCoverageModulationTableNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) + vkCmdSetShadingRateImageEnableNV = (PFN_vkCmdSetShadingRateImageEnableNV)load(context, "vkCmdSetShadingRateImageEnableNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) + vkCmdSetRepresentativeFragmentTestEnableNV = (PFN_vkCmdSetRepresentativeFragmentTestEnableNV)load(context, "vkCmdSetRepresentativeFragmentTestEnableNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) + vkCmdSetCoverageReductionModeNV = (PFN_vkCmdSetCoverageReductionModeNV)load(context, "vkCmdSetCoverageReductionModeNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + vkGetDeviceGroupSurfacePresentModes2EXT = (PFN_vkGetDeviceGroupSurfacePresentModes2EXT)load(context, "vkGetDeviceGroupSurfacePresentModes2EXT"); +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) + vkGetImageSubresourceLayout2EXT = (PFN_vkGetImageSubresourceLayout2EXT)load(context, "vkGetImageSubresourceLayout2EXT"); +#endif /* (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) */ +#if (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) + vkCmdSetVertexInputEXT = (PFN_vkCmdSetVertexInputEXT)load(context, "vkCmdSetVertexInputEXT"); +#endif /* (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR)load(context, "vkCmdPushDescriptorSetWithTemplateKHR"); +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)load(context, "vkGetDeviceGroupPresentCapabilitiesKHR"); + vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)load(context, "vkGetDeviceGroupSurfacePresentModesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR)load(context, "vkAcquireNextImage2KHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_DEVICE */ +} + +static void volkGenLoadDeviceTable(struct VolkDeviceTable* table, void* context, PFN_vkVoidFunction (*load)(void*, const char*)) +{ + /* VOLK_GENERATE_LOAD_DEVICE_TABLE */ +#if defined(VK_VERSION_1_0) + table->vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers"); + table->vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets"); + table->vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory"); + table->vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer"); + table->vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory"); + table->vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory"); + table->vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery"); + table->vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass"); + table->vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets"); + table->vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer"); + table->vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline"); + table->vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers"); + table->vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage"); + table->vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments"); + table->vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage"); + table->vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage"); + table->vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer"); + table->vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage"); + table->vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage"); + table->vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer"); + table->vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults"); + table->vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch"); + table->vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect"); + table->vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw"); + table->vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed"); + table->vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect"); + table->vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect"); + table->vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery"); + table->vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass"); + table->vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands"); + table->vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer"); + table->vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass"); + table->vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier"); + table->vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants"); + table->vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent"); + table->vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool"); + table->vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage"); + table->vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants"); + table->vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias"); + table->vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds"); + table->vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent"); + table->vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth"); + table->vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor"); + table->vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask"); + table->vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference"); + table->vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask"); + table->vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport"); + table->vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer"); + table->vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents"); + table->vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp"); + table->vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer"); + table->vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView"); + table->vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool"); + table->vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines"); + table->vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool"); + table->vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout"); + table->vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent"); + table->vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence"); + table->vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer"); + table->vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines"); + table->vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage"); + table->vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView"); + table->vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache"); + table->vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout"); + table->vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool"); + table->vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass"); + table->vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler"); + table->vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore"); + table->vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule"); + table->vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer"); + table->vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView"); + table->vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool"); + table->vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool"); + table->vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout"); + table->vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice"); + table->vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent"); + table->vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence"); + table->vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer"); + table->vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage"); + table->vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView"); + table->vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline"); + table->vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache"); + table->vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout"); + table->vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool"); + table->vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass"); + table->vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler"); + table->vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore"); + table->vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule"); + table->vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle"); + table->vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer"); + table->vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges"); + table->vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers"); + table->vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets"); + table->vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory"); + table->vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements"); + table->vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment"); + table->vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue"); + table->vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus"); + table->vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus"); + table->vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements"); + table->vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements"); + table->vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout"); + table->vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData"); + table->vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults"); + table->vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity"); + table->vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges"); + table->vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory"); + table->vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches"); + table->vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse"); + table->vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit"); + table->vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle"); + table->vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer"); + table->vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool"); + table->vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool"); + table->vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent"); + table->vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences"); + table->vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent"); + table->vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory"); + table->vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets"); + table->vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences"); +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) + table->vkBindBufferMemory2 = (PFN_vkBindBufferMemory2)load(context, "vkBindBufferMemory2"); + table->vkBindImageMemory2 = (PFN_vkBindImageMemory2)load(context, "vkBindImageMemory2"); + table->vkCmdDispatchBase = (PFN_vkCmdDispatchBase)load(context, "vkCmdDispatchBase"); + table->vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask)load(context, "vkCmdSetDeviceMask"); + table->vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate)load(context, "vkCreateDescriptorUpdateTemplate"); + table->vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)load(context, "vkCreateSamplerYcbcrConversion"); + table->vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate)load(context, "vkDestroyDescriptorUpdateTemplate"); + table->vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)load(context, "vkDestroySamplerYcbcrConversion"); + table->vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2)load(context, "vkGetBufferMemoryRequirements2"); + table->vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport)load(context, "vkGetDescriptorSetLayoutSupport"); + table->vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures)load(context, "vkGetDeviceGroupPeerMemoryFeatures"); + table->vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2)load(context, "vkGetDeviceQueue2"); + table->vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)load(context, "vkGetImageMemoryRequirements2"); + table->vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2)load(context, "vkGetImageSparseMemoryRequirements2"); + table->vkTrimCommandPool = (PFN_vkTrimCommandPool)load(context, "vkTrimCommandPool"); + table->vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate)load(context, "vkUpdateDescriptorSetWithTemplate"); +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) + table->vkCmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2)load(context, "vkCmdBeginRenderPass2"); + table->vkCmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount)load(context, "vkCmdDrawIndexedIndirectCount"); + table->vkCmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount)load(context, "vkCmdDrawIndirectCount"); + table->vkCmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2)load(context, "vkCmdEndRenderPass2"); + table->vkCmdNextSubpass2 = (PFN_vkCmdNextSubpass2)load(context, "vkCmdNextSubpass2"); + table->vkCreateRenderPass2 = (PFN_vkCreateRenderPass2)load(context, "vkCreateRenderPass2"); + table->vkGetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)load(context, "vkGetBufferDeviceAddress"); + table->vkGetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress)load(context, "vkGetBufferOpaqueCaptureAddress"); + table->vkGetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress)load(context, "vkGetDeviceMemoryOpaqueCaptureAddress"); + table->vkGetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue)load(context, "vkGetSemaphoreCounterValue"); + table->vkResetQueryPool = (PFN_vkResetQueryPool)load(context, "vkResetQueryPool"); + table->vkSignalSemaphore = (PFN_vkSignalSemaphore)load(context, "vkSignalSemaphore"); + table->vkWaitSemaphores = (PFN_vkWaitSemaphores)load(context, "vkWaitSemaphores"); +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) + table->vkCmdBeginRendering = (PFN_vkCmdBeginRendering)load(context, "vkCmdBeginRendering"); + table->vkCmdBindVertexBuffers2 = (PFN_vkCmdBindVertexBuffers2)load(context, "vkCmdBindVertexBuffers2"); + table->vkCmdBlitImage2 = (PFN_vkCmdBlitImage2)load(context, "vkCmdBlitImage2"); + table->vkCmdCopyBuffer2 = (PFN_vkCmdCopyBuffer2)load(context, "vkCmdCopyBuffer2"); + table->vkCmdCopyBufferToImage2 = (PFN_vkCmdCopyBufferToImage2)load(context, "vkCmdCopyBufferToImage2"); + table->vkCmdCopyImage2 = (PFN_vkCmdCopyImage2)load(context, "vkCmdCopyImage2"); + table->vkCmdCopyImageToBuffer2 = (PFN_vkCmdCopyImageToBuffer2)load(context, "vkCmdCopyImageToBuffer2"); + table->vkCmdEndRendering = (PFN_vkCmdEndRendering)load(context, "vkCmdEndRendering"); + table->vkCmdPipelineBarrier2 = (PFN_vkCmdPipelineBarrier2)load(context, "vkCmdPipelineBarrier2"); + table->vkCmdResetEvent2 = (PFN_vkCmdResetEvent2)load(context, "vkCmdResetEvent2"); + table->vkCmdResolveImage2 = (PFN_vkCmdResolveImage2)load(context, "vkCmdResolveImage2"); + table->vkCmdSetCullMode = (PFN_vkCmdSetCullMode)load(context, "vkCmdSetCullMode"); + table->vkCmdSetDepthBiasEnable = (PFN_vkCmdSetDepthBiasEnable)load(context, "vkCmdSetDepthBiasEnable"); + table->vkCmdSetDepthBoundsTestEnable = (PFN_vkCmdSetDepthBoundsTestEnable)load(context, "vkCmdSetDepthBoundsTestEnable"); + table->vkCmdSetDepthCompareOp = (PFN_vkCmdSetDepthCompareOp)load(context, "vkCmdSetDepthCompareOp"); + table->vkCmdSetDepthTestEnable = (PFN_vkCmdSetDepthTestEnable)load(context, "vkCmdSetDepthTestEnable"); + table->vkCmdSetDepthWriteEnable = (PFN_vkCmdSetDepthWriteEnable)load(context, "vkCmdSetDepthWriteEnable"); + table->vkCmdSetEvent2 = (PFN_vkCmdSetEvent2)load(context, "vkCmdSetEvent2"); + table->vkCmdSetFrontFace = (PFN_vkCmdSetFrontFace)load(context, "vkCmdSetFrontFace"); + table->vkCmdSetPrimitiveRestartEnable = (PFN_vkCmdSetPrimitiveRestartEnable)load(context, "vkCmdSetPrimitiveRestartEnable"); + table->vkCmdSetPrimitiveTopology = (PFN_vkCmdSetPrimitiveTopology)load(context, "vkCmdSetPrimitiveTopology"); + table->vkCmdSetRasterizerDiscardEnable = (PFN_vkCmdSetRasterizerDiscardEnable)load(context, "vkCmdSetRasterizerDiscardEnable"); + table->vkCmdSetScissorWithCount = (PFN_vkCmdSetScissorWithCount)load(context, "vkCmdSetScissorWithCount"); + table->vkCmdSetStencilOp = (PFN_vkCmdSetStencilOp)load(context, "vkCmdSetStencilOp"); + table->vkCmdSetStencilTestEnable = (PFN_vkCmdSetStencilTestEnable)load(context, "vkCmdSetStencilTestEnable"); + table->vkCmdSetViewportWithCount = (PFN_vkCmdSetViewportWithCount)load(context, "vkCmdSetViewportWithCount"); + table->vkCmdWaitEvents2 = (PFN_vkCmdWaitEvents2)load(context, "vkCmdWaitEvents2"); + table->vkCmdWriteTimestamp2 = (PFN_vkCmdWriteTimestamp2)load(context, "vkCmdWriteTimestamp2"); + table->vkCreatePrivateDataSlot = (PFN_vkCreatePrivateDataSlot)load(context, "vkCreatePrivateDataSlot"); + table->vkDestroyPrivateDataSlot = (PFN_vkDestroyPrivateDataSlot)load(context, "vkDestroyPrivateDataSlot"); + table->vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements)load(context, "vkGetDeviceBufferMemoryRequirements"); + table->vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)load(context, "vkGetDeviceImageMemoryRequirements"); + table->vkGetDeviceImageSparseMemoryRequirements = (PFN_vkGetDeviceImageSparseMemoryRequirements)load(context, "vkGetDeviceImageSparseMemoryRequirements"); + table->vkGetPrivateData = (PFN_vkGetPrivateData)load(context, "vkGetPrivateData"); + table->vkQueueSubmit2 = (PFN_vkQueueSubmit2)load(context, "vkQueueSubmit2"); + table->vkSetPrivateData = (PFN_vkSetPrivateData)load(context, "vkSetPrivateData"); +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMDX_shader_enqueue) + table->vkCmdDispatchGraphAMDX = (PFN_vkCmdDispatchGraphAMDX)load(context, "vkCmdDispatchGraphAMDX"); + table->vkCmdDispatchGraphIndirectAMDX = (PFN_vkCmdDispatchGraphIndirectAMDX)load(context, "vkCmdDispatchGraphIndirectAMDX"); + table->vkCmdDispatchGraphIndirectCountAMDX = (PFN_vkCmdDispatchGraphIndirectCountAMDX)load(context, "vkCmdDispatchGraphIndirectCountAMDX"); + table->vkCmdInitializeGraphScratchMemoryAMDX = (PFN_vkCmdInitializeGraphScratchMemoryAMDX)load(context, "vkCmdInitializeGraphScratchMemoryAMDX"); + table->vkCreateExecutionGraphPipelinesAMDX = (PFN_vkCreateExecutionGraphPipelinesAMDX)load(context, "vkCreateExecutionGraphPipelinesAMDX"); + table->vkGetExecutionGraphPipelineNodeIndexAMDX = (PFN_vkGetExecutionGraphPipelineNodeIndexAMDX)load(context, "vkGetExecutionGraphPipelineNodeIndexAMDX"); + table->vkGetExecutionGraphPipelineScratchSizeAMDX = (PFN_vkGetExecutionGraphPipelineScratchSizeAMDX)load(context, "vkGetExecutionGraphPipelineScratchSizeAMDX"); +#endif /* defined(VK_AMDX_shader_enqueue) */ +#if defined(VK_AMD_buffer_marker) + table->vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD)load(context, "vkCmdWriteBufferMarkerAMD"); +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) + table->vkSetLocalDimmingAMD = (PFN_vkSetLocalDimmingAMD)load(context, "vkSetLocalDimmingAMD"); +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) + table->vkCmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD)load(context, "vkCmdDrawIndexedIndirectCountAMD"); + table->vkCmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)load(context, "vkCmdDrawIndirectCountAMD"); +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) + table->vkGetShaderInfoAMD = (PFN_vkGetShaderInfoAMD)load(context, "vkGetShaderInfoAMD"); +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) + table->vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)load(context, "vkGetAndroidHardwareBufferPropertiesANDROID"); + table->vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID)load(context, "vkGetMemoryAndroidHardwareBufferANDROID"); +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_attachment_feedback_loop_dynamic_state) + table->vkCmdSetAttachmentFeedbackLoopEnableEXT = (PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT)load(context, "vkCmdSetAttachmentFeedbackLoopEnableEXT"); +#endif /* defined(VK_EXT_attachment_feedback_loop_dynamic_state) */ +#if defined(VK_EXT_buffer_device_address) + table->vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)load(context, "vkGetBufferDeviceAddressEXT"); +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) + table->vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT)load(context, "vkGetCalibratedTimestampsEXT"); +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) + table->vkCmdSetColorWriteEnableEXT = (PFN_vkCmdSetColorWriteEnableEXT)load(context, "vkCmdSetColorWriteEnableEXT"); +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) + table->vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)load(context, "vkCmdBeginConditionalRenderingEXT"); + table->vkCmdEndConditionalRenderingEXT = (PFN_vkCmdEndConditionalRenderingEXT)load(context, "vkCmdEndConditionalRenderingEXT"); +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) + table->vkCmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)load(context, "vkCmdDebugMarkerBeginEXT"); + table->vkCmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)load(context, "vkCmdDebugMarkerEndEXT"); + table->vkCmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)load(context, "vkCmdDebugMarkerInsertEXT"); + table->vkDebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)load(context, "vkDebugMarkerSetObjectNameEXT"); + table->vkDebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)load(context, "vkDebugMarkerSetObjectTagEXT"); +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_depth_bias_control) + table->vkCmdSetDepthBias2EXT = (PFN_vkCmdSetDepthBias2EXT)load(context, "vkCmdSetDepthBias2EXT"); +#endif /* defined(VK_EXT_depth_bias_control) */ +#if defined(VK_EXT_descriptor_buffer) + table->vkCmdBindDescriptorBufferEmbeddedSamplersEXT = (PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT)load(context, "vkCmdBindDescriptorBufferEmbeddedSamplersEXT"); + table->vkCmdBindDescriptorBuffersEXT = (PFN_vkCmdBindDescriptorBuffersEXT)load(context, "vkCmdBindDescriptorBuffersEXT"); + table->vkCmdSetDescriptorBufferOffsetsEXT = (PFN_vkCmdSetDescriptorBufferOffsetsEXT)load(context, "vkCmdSetDescriptorBufferOffsetsEXT"); + table->vkGetBufferOpaqueCaptureDescriptorDataEXT = (PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT)load(context, "vkGetBufferOpaqueCaptureDescriptorDataEXT"); + table->vkGetDescriptorEXT = (PFN_vkGetDescriptorEXT)load(context, "vkGetDescriptorEXT"); + table->vkGetDescriptorSetLayoutBindingOffsetEXT = (PFN_vkGetDescriptorSetLayoutBindingOffsetEXT)load(context, "vkGetDescriptorSetLayoutBindingOffsetEXT"); + table->vkGetDescriptorSetLayoutSizeEXT = (PFN_vkGetDescriptorSetLayoutSizeEXT)load(context, "vkGetDescriptorSetLayoutSizeEXT"); + table->vkGetImageOpaqueCaptureDescriptorDataEXT = (PFN_vkGetImageOpaqueCaptureDescriptorDataEXT)load(context, "vkGetImageOpaqueCaptureDescriptorDataEXT"); + table->vkGetImageViewOpaqueCaptureDescriptorDataEXT = (PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT)load(context, "vkGetImageViewOpaqueCaptureDescriptorDataEXT"); + table->vkGetSamplerOpaqueCaptureDescriptorDataEXT = (PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT)load(context, "vkGetSamplerOpaqueCaptureDescriptorDataEXT"); +#endif /* defined(VK_EXT_descriptor_buffer) */ +#if defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) + table->vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT = (PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT)load(context, "vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT"); +#endif /* defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) */ +#if defined(VK_EXT_device_fault) + table->vkGetDeviceFaultInfoEXT = (PFN_vkGetDeviceFaultInfoEXT)load(context, "vkGetDeviceFaultInfoEXT"); +#endif /* defined(VK_EXT_device_fault) */ +#if defined(VK_EXT_discard_rectangles) + table->vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT)load(context, "vkCmdSetDiscardRectangleEXT"); +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 + table->vkCmdSetDiscardRectangleEnableEXT = (PFN_vkCmdSetDiscardRectangleEnableEXT)load(context, "vkCmdSetDiscardRectangleEnableEXT"); + table->vkCmdSetDiscardRectangleModeEXT = (PFN_vkCmdSetDiscardRectangleModeEXT)load(context, "vkCmdSetDiscardRectangleModeEXT"); +#endif /* defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 */ +#if defined(VK_EXT_display_control) + table->vkDisplayPowerControlEXT = (PFN_vkDisplayPowerControlEXT)load(context, "vkDisplayPowerControlEXT"); + table->vkGetSwapchainCounterEXT = (PFN_vkGetSwapchainCounterEXT)load(context, "vkGetSwapchainCounterEXT"); + table->vkRegisterDeviceEventEXT = (PFN_vkRegisterDeviceEventEXT)load(context, "vkRegisterDeviceEventEXT"); + table->vkRegisterDisplayEventEXT = (PFN_vkRegisterDisplayEventEXT)load(context, "vkRegisterDisplayEventEXT"); +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_external_memory_host) + table->vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)load(context, "vkGetMemoryHostPointerPropertiesEXT"); +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) + table->vkAcquireFullScreenExclusiveModeEXT = (PFN_vkAcquireFullScreenExclusiveModeEXT)load(context, "vkAcquireFullScreenExclusiveModeEXT"); + table->vkReleaseFullScreenExclusiveModeEXT = (PFN_vkReleaseFullScreenExclusiveModeEXT)load(context, "vkReleaseFullScreenExclusiveModeEXT"); +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) + table->vkSetHdrMetadataEXT = (PFN_vkSetHdrMetadataEXT)load(context, "vkSetHdrMetadataEXT"); +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_host_image_copy) + table->vkCopyImageToImageEXT = (PFN_vkCopyImageToImageEXT)load(context, "vkCopyImageToImageEXT"); + table->vkCopyImageToMemoryEXT = (PFN_vkCopyImageToMemoryEXT)load(context, "vkCopyImageToMemoryEXT"); + table->vkCopyMemoryToImageEXT = (PFN_vkCopyMemoryToImageEXT)load(context, "vkCopyMemoryToImageEXT"); + table->vkTransitionImageLayoutEXT = (PFN_vkTransitionImageLayoutEXT)load(context, "vkTransitionImageLayoutEXT"); +#endif /* defined(VK_EXT_host_image_copy) */ +#if defined(VK_EXT_host_query_reset) + table->vkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)load(context, "vkResetQueryPoolEXT"); +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) + table->vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)load(context, "vkGetImageDrmFormatModifierPropertiesEXT"); +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) + table->vkCmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT)load(context, "vkCmdSetLineStippleEXT"); +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_mesh_shader) + table->vkCmdDrawMeshTasksEXT = (PFN_vkCmdDrawMeshTasksEXT)load(context, "vkCmdDrawMeshTasksEXT"); + table->vkCmdDrawMeshTasksIndirectCountEXT = (PFN_vkCmdDrawMeshTasksIndirectCountEXT)load(context, "vkCmdDrawMeshTasksIndirectCountEXT"); + table->vkCmdDrawMeshTasksIndirectEXT = (PFN_vkCmdDrawMeshTasksIndirectEXT)load(context, "vkCmdDrawMeshTasksIndirectEXT"); +#endif /* defined(VK_EXT_mesh_shader) */ +#if defined(VK_EXT_metal_objects) + table->vkExportMetalObjectsEXT = (PFN_vkExportMetalObjectsEXT)load(context, "vkExportMetalObjectsEXT"); +#endif /* defined(VK_EXT_metal_objects) */ +#if defined(VK_EXT_multi_draw) + table->vkCmdDrawMultiEXT = (PFN_vkCmdDrawMultiEXT)load(context, "vkCmdDrawMultiEXT"); + table->vkCmdDrawMultiIndexedEXT = (PFN_vkCmdDrawMultiIndexedEXT)load(context, "vkCmdDrawMultiIndexedEXT"); +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_opacity_micromap) + table->vkBuildMicromapsEXT = (PFN_vkBuildMicromapsEXT)load(context, "vkBuildMicromapsEXT"); + table->vkCmdBuildMicromapsEXT = (PFN_vkCmdBuildMicromapsEXT)load(context, "vkCmdBuildMicromapsEXT"); + table->vkCmdCopyMemoryToMicromapEXT = (PFN_vkCmdCopyMemoryToMicromapEXT)load(context, "vkCmdCopyMemoryToMicromapEXT"); + table->vkCmdCopyMicromapEXT = (PFN_vkCmdCopyMicromapEXT)load(context, "vkCmdCopyMicromapEXT"); + table->vkCmdCopyMicromapToMemoryEXT = (PFN_vkCmdCopyMicromapToMemoryEXT)load(context, "vkCmdCopyMicromapToMemoryEXT"); + table->vkCmdWriteMicromapsPropertiesEXT = (PFN_vkCmdWriteMicromapsPropertiesEXT)load(context, "vkCmdWriteMicromapsPropertiesEXT"); + table->vkCopyMemoryToMicromapEXT = (PFN_vkCopyMemoryToMicromapEXT)load(context, "vkCopyMemoryToMicromapEXT"); + table->vkCopyMicromapEXT = (PFN_vkCopyMicromapEXT)load(context, "vkCopyMicromapEXT"); + table->vkCopyMicromapToMemoryEXT = (PFN_vkCopyMicromapToMemoryEXT)load(context, "vkCopyMicromapToMemoryEXT"); + table->vkCreateMicromapEXT = (PFN_vkCreateMicromapEXT)load(context, "vkCreateMicromapEXT"); + table->vkDestroyMicromapEXT = (PFN_vkDestroyMicromapEXT)load(context, "vkDestroyMicromapEXT"); + table->vkGetDeviceMicromapCompatibilityEXT = (PFN_vkGetDeviceMicromapCompatibilityEXT)load(context, "vkGetDeviceMicromapCompatibilityEXT"); + table->vkGetMicromapBuildSizesEXT = (PFN_vkGetMicromapBuildSizesEXT)load(context, "vkGetMicromapBuildSizesEXT"); + table->vkWriteMicromapsPropertiesEXT = (PFN_vkWriteMicromapsPropertiesEXT)load(context, "vkWriteMicromapsPropertiesEXT"); +#endif /* defined(VK_EXT_opacity_micromap) */ +#if defined(VK_EXT_pageable_device_local_memory) + table->vkSetDeviceMemoryPriorityEXT = (PFN_vkSetDeviceMemoryPriorityEXT)load(context, "vkSetDeviceMemoryPriorityEXT"); +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) + table->vkGetPipelinePropertiesEXT = (PFN_vkGetPipelinePropertiesEXT)load(context, "vkGetPipelinePropertiesEXT"); +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) + table->vkCreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT)load(context, "vkCreatePrivateDataSlotEXT"); + table->vkDestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT)load(context, "vkDestroyPrivateDataSlotEXT"); + table->vkGetPrivateDataEXT = (PFN_vkGetPrivateDataEXT)load(context, "vkGetPrivateDataEXT"); + table->vkSetPrivateDataEXT = (PFN_vkSetPrivateDataEXT)load(context, "vkSetPrivateDataEXT"); +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) + table->vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT)load(context, "vkCmdSetSampleLocationsEXT"); +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_shader_module_identifier) + table->vkGetShaderModuleCreateInfoIdentifierEXT = (PFN_vkGetShaderModuleCreateInfoIdentifierEXT)load(context, "vkGetShaderModuleCreateInfoIdentifierEXT"); + table->vkGetShaderModuleIdentifierEXT = (PFN_vkGetShaderModuleIdentifierEXT)load(context, "vkGetShaderModuleIdentifierEXT"); +#endif /* defined(VK_EXT_shader_module_identifier) */ +#if defined(VK_EXT_shader_object) + table->vkCmdBindShadersEXT = (PFN_vkCmdBindShadersEXT)load(context, "vkCmdBindShadersEXT"); + table->vkCreateShadersEXT = (PFN_vkCreateShadersEXT)load(context, "vkCreateShadersEXT"); + table->vkDestroyShaderEXT = (PFN_vkDestroyShaderEXT)load(context, "vkDestroyShaderEXT"); + table->vkGetShaderBinaryDataEXT = (PFN_vkGetShaderBinaryDataEXT)load(context, "vkGetShaderBinaryDataEXT"); +#endif /* defined(VK_EXT_shader_object) */ +#if defined(VK_EXT_swapchain_maintenance1) + table->vkReleaseSwapchainImagesEXT = (PFN_vkReleaseSwapchainImagesEXT)load(context, "vkReleaseSwapchainImagesEXT"); +#endif /* defined(VK_EXT_swapchain_maintenance1) */ +#if defined(VK_EXT_transform_feedback) + table->vkCmdBeginQueryIndexedEXT = (PFN_vkCmdBeginQueryIndexedEXT)load(context, "vkCmdBeginQueryIndexedEXT"); + table->vkCmdBeginTransformFeedbackEXT = (PFN_vkCmdBeginTransformFeedbackEXT)load(context, "vkCmdBeginTransformFeedbackEXT"); + table->vkCmdBindTransformFeedbackBuffersEXT = (PFN_vkCmdBindTransformFeedbackBuffersEXT)load(context, "vkCmdBindTransformFeedbackBuffersEXT"); + table->vkCmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)load(context, "vkCmdDrawIndirectByteCountEXT"); + table->vkCmdEndQueryIndexedEXT = (PFN_vkCmdEndQueryIndexedEXT)load(context, "vkCmdEndQueryIndexedEXT"); + table->vkCmdEndTransformFeedbackEXT = (PFN_vkCmdEndTransformFeedbackEXT)load(context, "vkCmdEndTransformFeedbackEXT"); +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) + table->vkCreateValidationCacheEXT = (PFN_vkCreateValidationCacheEXT)load(context, "vkCreateValidationCacheEXT"); + table->vkDestroyValidationCacheEXT = (PFN_vkDestroyValidationCacheEXT)load(context, "vkDestroyValidationCacheEXT"); + table->vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT)load(context, "vkGetValidationCacheDataEXT"); + table->vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT)load(context, "vkMergeValidationCachesEXT"); +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_FUCHSIA_buffer_collection) + table->vkCreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA)load(context, "vkCreateBufferCollectionFUCHSIA"); + table->vkDestroyBufferCollectionFUCHSIA = (PFN_vkDestroyBufferCollectionFUCHSIA)load(context, "vkDestroyBufferCollectionFUCHSIA"); + table->vkGetBufferCollectionPropertiesFUCHSIA = (PFN_vkGetBufferCollectionPropertiesFUCHSIA)load(context, "vkGetBufferCollectionPropertiesFUCHSIA"); + table->vkSetBufferCollectionBufferConstraintsFUCHSIA = (PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA)load(context, "vkSetBufferCollectionBufferConstraintsFUCHSIA"); + table->vkSetBufferCollectionImageConstraintsFUCHSIA = (PFN_vkSetBufferCollectionImageConstraintsFUCHSIA)load(context, "vkSetBufferCollectionImageConstraintsFUCHSIA"); +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) + table->vkGetMemoryZirconHandleFUCHSIA = (PFN_vkGetMemoryZirconHandleFUCHSIA)load(context, "vkGetMemoryZirconHandleFUCHSIA"); + table->vkGetMemoryZirconHandlePropertiesFUCHSIA = (PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA)load(context, "vkGetMemoryZirconHandlePropertiesFUCHSIA"); +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) + table->vkGetSemaphoreZirconHandleFUCHSIA = (PFN_vkGetSemaphoreZirconHandleFUCHSIA)load(context, "vkGetSemaphoreZirconHandleFUCHSIA"); + table->vkImportSemaphoreZirconHandleFUCHSIA = (PFN_vkImportSemaphoreZirconHandleFUCHSIA)load(context, "vkImportSemaphoreZirconHandleFUCHSIA"); +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_GOOGLE_display_timing) + table->vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE)load(context, "vkGetPastPresentationTimingGOOGLE"); + table->vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE)load(context, "vkGetRefreshCycleDurationGOOGLE"); +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_cluster_culling_shader) + table->vkCmdDrawClusterHUAWEI = (PFN_vkCmdDrawClusterHUAWEI)load(context, "vkCmdDrawClusterHUAWEI"); + table->vkCmdDrawClusterIndirectHUAWEI = (PFN_vkCmdDrawClusterIndirectHUAWEI)load(context, "vkCmdDrawClusterIndirectHUAWEI"); +#endif /* defined(VK_HUAWEI_cluster_culling_shader) */ +#if defined(VK_HUAWEI_invocation_mask) + table->vkCmdBindInvocationMaskHUAWEI = (PFN_vkCmdBindInvocationMaskHUAWEI)load(context, "vkCmdBindInvocationMaskHUAWEI"); +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) + table->vkCmdSubpassShadingHUAWEI = (PFN_vkCmdSubpassShadingHUAWEI)load(context, "vkCmdSubpassShadingHUAWEI"); + table->vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = (PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)load(context, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI"); +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) + table->vkAcquirePerformanceConfigurationINTEL = (PFN_vkAcquirePerformanceConfigurationINTEL)load(context, "vkAcquirePerformanceConfigurationINTEL"); + table->vkCmdSetPerformanceMarkerINTEL = (PFN_vkCmdSetPerformanceMarkerINTEL)load(context, "vkCmdSetPerformanceMarkerINTEL"); + table->vkCmdSetPerformanceOverrideINTEL = (PFN_vkCmdSetPerformanceOverrideINTEL)load(context, "vkCmdSetPerformanceOverrideINTEL"); + table->vkCmdSetPerformanceStreamMarkerINTEL = (PFN_vkCmdSetPerformanceStreamMarkerINTEL)load(context, "vkCmdSetPerformanceStreamMarkerINTEL"); + table->vkGetPerformanceParameterINTEL = (PFN_vkGetPerformanceParameterINTEL)load(context, "vkGetPerformanceParameterINTEL"); + table->vkInitializePerformanceApiINTEL = (PFN_vkInitializePerformanceApiINTEL)load(context, "vkInitializePerformanceApiINTEL"); + table->vkQueueSetPerformanceConfigurationINTEL = (PFN_vkQueueSetPerformanceConfigurationINTEL)load(context, "vkQueueSetPerformanceConfigurationINTEL"); + table->vkReleasePerformanceConfigurationINTEL = (PFN_vkReleasePerformanceConfigurationINTEL)load(context, "vkReleasePerformanceConfigurationINTEL"); + table->vkUninitializePerformanceApiINTEL = (PFN_vkUninitializePerformanceApiINTEL)load(context, "vkUninitializePerformanceApiINTEL"); +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) + table->vkBuildAccelerationStructuresKHR = (PFN_vkBuildAccelerationStructuresKHR)load(context, "vkBuildAccelerationStructuresKHR"); + table->vkCmdBuildAccelerationStructuresIndirectKHR = (PFN_vkCmdBuildAccelerationStructuresIndirectKHR)load(context, "vkCmdBuildAccelerationStructuresIndirectKHR"); + table->vkCmdBuildAccelerationStructuresKHR = (PFN_vkCmdBuildAccelerationStructuresKHR)load(context, "vkCmdBuildAccelerationStructuresKHR"); + table->vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR)load(context, "vkCmdCopyAccelerationStructureKHR"); + table->vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR)load(context, "vkCmdCopyAccelerationStructureToMemoryKHR"); + table->vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR)load(context, "vkCmdCopyMemoryToAccelerationStructureKHR"); + table->vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)load(context, "vkCmdWriteAccelerationStructuresPropertiesKHR"); + table->vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR)load(context, "vkCopyAccelerationStructureKHR"); + table->vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR)load(context, "vkCopyAccelerationStructureToMemoryKHR"); + table->vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR)load(context, "vkCopyMemoryToAccelerationStructureKHR"); + table->vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR)load(context, "vkCreateAccelerationStructureKHR"); + table->vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR)load(context, "vkDestroyAccelerationStructureKHR"); + table->vkGetAccelerationStructureBuildSizesKHR = (PFN_vkGetAccelerationStructureBuildSizesKHR)load(context, "vkGetAccelerationStructureBuildSizesKHR"); + table->vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR)load(context, "vkGetAccelerationStructureDeviceAddressKHR"); + table->vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)load(context, "vkGetDeviceAccelerationStructureCompatibilityKHR"); + table->vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR)load(context, "vkWriteAccelerationStructuresPropertiesKHR"); +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_bind_memory2) + table->vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)load(context, "vkBindBufferMemory2KHR"); + table->vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)load(context, "vkBindImageMemory2KHR"); +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) + table->vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressKHR)load(context, "vkGetBufferDeviceAddressKHR"); + table->vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR)load(context, "vkGetBufferOpaqueCaptureAddressKHR"); + table->vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)load(context, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_copy_commands2) + table->vkCmdBlitImage2KHR = (PFN_vkCmdBlitImage2KHR)load(context, "vkCmdBlitImage2KHR"); + table->vkCmdCopyBuffer2KHR = (PFN_vkCmdCopyBuffer2KHR)load(context, "vkCmdCopyBuffer2KHR"); + table->vkCmdCopyBufferToImage2KHR = (PFN_vkCmdCopyBufferToImage2KHR)load(context, "vkCmdCopyBufferToImage2KHR"); + table->vkCmdCopyImage2KHR = (PFN_vkCmdCopyImage2KHR)load(context, "vkCmdCopyImage2KHR"); + table->vkCmdCopyImageToBuffer2KHR = (PFN_vkCmdCopyImageToBuffer2KHR)load(context, "vkCmdCopyImageToBuffer2KHR"); + table->vkCmdResolveImage2KHR = (PFN_vkCmdResolveImage2KHR)load(context, "vkCmdResolveImage2KHR"); +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) + table->vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR)load(context, "vkCmdBeginRenderPass2KHR"); + table->vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)load(context, "vkCmdEndRenderPass2KHR"); + table->vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)load(context, "vkCmdNextSubpass2KHR"); + table->vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)load(context, "vkCreateRenderPass2KHR"); +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) + table->vkCreateDeferredOperationKHR = (PFN_vkCreateDeferredOperationKHR)load(context, "vkCreateDeferredOperationKHR"); + table->vkDeferredOperationJoinKHR = (PFN_vkDeferredOperationJoinKHR)load(context, "vkDeferredOperationJoinKHR"); + table->vkDestroyDeferredOperationKHR = (PFN_vkDestroyDeferredOperationKHR)load(context, "vkDestroyDeferredOperationKHR"); + table->vkGetDeferredOperationMaxConcurrencyKHR = (PFN_vkGetDeferredOperationMaxConcurrencyKHR)load(context, "vkGetDeferredOperationMaxConcurrencyKHR"); + table->vkGetDeferredOperationResultKHR = (PFN_vkGetDeferredOperationResultKHR)load(context, "vkGetDeferredOperationResultKHR"); +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) + table->vkCreateDescriptorUpdateTemplateKHR = (PFN_vkCreateDescriptorUpdateTemplateKHR)load(context, "vkCreateDescriptorUpdateTemplateKHR"); + table->vkDestroyDescriptorUpdateTemplateKHR = (PFN_vkDestroyDescriptorUpdateTemplateKHR)load(context, "vkDestroyDescriptorUpdateTemplateKHR"); + table->vkUpdateDescriptorSetWithTemplateKHR = (PFN_vkUpdateDescriptorSetWithTemplateKHR)load(context, "vkUpdateDescriptorSetWithTemplateKHR"); +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) + table->vkCmdDispatchBaseKHR = (PFN_vkCmdDispatchBaseKHR)load(context, "vkCmdDispatchBaseKHR"); + table->vkCmdSetDeviceMaskKHR = (PFN_vkCmdSetDeviceMaskKHR)load(context, "vkCmdSetDeviceMaskKHR"); + table->vkGetDeviceGroupPeerMemoryFeaturesKHR = (PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)load(context, "vkGetDeviceGroupPeerMemoryFeaturesKHR"); +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_display_swapchain) + table->vkCreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)load(context, "vkCreateSharedSwapchainsKHR"); +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) + table->vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)load(context, "vkCmdDrawIndexedIndirectCountKHR"); + table->vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)load(context, "vkCmdDrawIndirectCountKHR"); +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) + table->vkCmdBeginRenderingKHR = (PFN_vkCmdBeginRenderingKHR)load(context, "vkCmdBeginRenderingKHR"); + table->vkCmdEndRenderingKHR = (PFN_vkCmdEndRenderingKHR)load(context, "vkCmdEndRenderingKHR"); +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_fd) + table->vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)load(context, "vkGetFenceFdKHR"); + table->vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)load(context, "vkImportFenceFdKHR"); +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) + table->vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)load(context, "vkGetFenceWin32HandleKHR"); + table->vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR)load(context, "vkImportFenceWin32HandleKHR"); +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_fd) + table->vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)load(context, "vkGetMemoryFdKHR"); + table->vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)load(context, "vkGetMemoryFdPropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) + table->vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)load(context, "vkGetMemoryWin32HandleKHR"); + table->vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)load(context, "vkGetMemoryWin32HandlePropertiesKHR"); +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_fd) + table->vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)load(context, "vkGetSemaphoreFdKHR"); + table->vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)load(context, "vkImportSemaphoreFdKHR"); +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) + table->vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)load(context, "vkGetSemaphoreWin32HandleKHR"); + table->vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR)load(context, "vkImportSemaphoreWin32HandleKHR"); +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) + table->vkCmdSetFragmentShadingRateKHR = (PFN_vkCmdSetFragmentShadingRateKHR)load(context, "vkCmdSetFragmentShadingRateKHR"); +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_memory_requirements2) + table->vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)load(context, "vkGetBufferMemoryRequirements2KHR"); + table->vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)load(context, "vkGetImageMemoryRequirements2KHR"); + table->vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)load(context, "vkGetImageSparseMemoryRequirements2KHR"); +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_maintenance1) + table->vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR)load(context, "vkTrimCommandPoolKHR"); +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) + table->vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR)load(context, "vkGetDescriptorSetLayoutSupportKHR"); +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) + table->vkGetDeviceBufferMemoryRequirementsKHR = (PFN_vkGetDeviceBufferMemoryRequirementsKHR)load(context, "vkGetDeviceBufferMemoryRequirementsKHR"); + table->vkGetDeviceImageMemoryRequirementsKHR = (PFN_vkGetDeviceImageMemoryRequirementsKHR)load(context, "vkGetDeviceImageMemoryRequirementsKHR"); + table->vkGetDeviceImageSparseMemoryRequirementsKHR = (PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)load(context, "vkGetDeviceImageSparseMemoryRequirementsKHR"); +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_maintenance5) + table->vkCmdBindIndexBuffer2KHR = (PFN_vkCmdBindIndexBuffer2KHR)load(context, "vkCmdBindIndexBuffer2KHR"); + table->vkGetDeviceImageSubresourceLayoutKHR = (PFN_vkGetDeviceImageSubresourceLayoutKHR)load(context, "vkGetDeviceImageSubresourceLayoutKHR"); + table->vkGetImageSubresourceLayout2KHR = (PFN_vkGetImageSubresourceLayout2KHR)load(context, "vkGetImageSubresourceLayout2KHR"); + table->vkGetRenderingAreaGranularityKHR = (PFN_vkGetRenderingAreaGranularityKHR)load(context, "vkGetRenderingAreaGranularityKHR"); +#endif /* defined(VK_KHR_maintenance5) */ +#if defined(VK_KHR_map_memory2) + table->vkMapMemory2KHR = (PFN_vkMapMemory2KHR)load(context, "vkMapMemory2KHR"); + table->vkUnmapMemory2KHR = (PFN_vkUnmapMemory2KHR)load(context, "vkUnmapMemory2KHR"); +#endif /* defined(VK_KHR_map_memory2) */ +#if defined(VK_KHR_performance_query) + table->vkAcquireProfilingLockKHR = (PFN_vkAcquireProfilingLockKHR)load(context, "vkAcquireProfilingLockKHR"); + table->vkReleaseProfilingLockKHR = (PFN_vkReleaseProfilingLockKHR)load(context, "vkReleaseProfilingLockKHR"); +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) + table->vkGetPipelineExecutableInternalRepresentationsKHR = (PFN_vkGetPipelineExecutableInternalRepresentationsKHR)load(context, "vkGetPipelineExecutableInternalRepresentationsKHR"); + table->vkGetPipelineExecutablePropertiesKHR = (PFN_vkGetPipelineExecutablePropertiesKHR)load(context, "vkGetPipelineExecutablePropertiesKHR"); + table->vkGetPipelineExecutableStatisticsKHR = (PFN_vkGetPipelineExecutableStatisticsKHR)load(context, "vkGetPipelineExecutableStatisticsKHR"); +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) + table->vkWaitForPresentKHR = (PFN_vkWaitForPresentKHR)load(context, "vkWaitForPresentKHR"); +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) + table->vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)load(context, "vkCmdPushDescriptorSetKHR"); +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) + table->vkCmdTraceRaysIndirect2KHR = (PFN_vkCmdTraceRaysIndirect2KHR)load(context, "vkCmdTraceRaysIndirect2KHR"); +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) + table->vkCmdSetRayTracingPipelineStackSizeKHR = (PFN_vkCmdSetRayTracingPipelineStackSizeKHR)load(context, "vkCmdSetRayTracingPipelineStackSizeKHR"); + table->vkCmdTraceRaysIndirectKHR = (PFN_vkCmdTraceRaysIndirectKHR)load(context, "vkCmdTraceRaysIndirectKHR"); + table->vkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR)load(context, "vkCmdTraceRaysKHR"); + table->vkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR)load(context, "vkCreateRayTracingPipelinesKHR"); + table->vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = (PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)load(context, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"); + table->vkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR)load(context, "vkGetRayTracingShaderGroupHandlesKHR"); + table->vkGetRayTracingShaderGroupStackSizeKHR = (PFN_vkGetRayTracingShaderGroupStackSizeKHR)load(context, "vkGetRayTracingShaderGroupStackSizeKHR"); +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) + table->vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR)load(context, "vkCreateSamplerYcbcrConversionKHR"); + table->vkDestroySamplerYcbcrConversionKHR = (PFN_vkDestroySamplerYcbcrConversionKHR)load(context, "vkDestroySamplerYcbcrConversionKHR"); +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) + table->vkGetSwapchainStatusKHR = (PFN_vkGetSwapchainStatusKHR)load(context, "vkGetSwapchainStatusKHR"); +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_swapchain) + table->vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR"); + table->vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR"); + table->vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR"); + table->vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR"); + table->vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR"); +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) + table->vkCmdPipelineBarrier2KHR = (PFN_vkCmdPipelineBarrier2KHR)load(context, "vkCmdPipelineBarrier2KHR"); + table->vkCmdResetEvent2KHR = (PFN_vkCmdResetEvent2KHR)load(context, "vkCmdResetEvent2KHR"); + table->vkCmdSetEvent2KHR = (PFN_vkCmdSetEvent2KHR)load(context, "vkCmdSetEvent2KHR"); + table->vkCmdWaitEvents2KHR = (PFN_vkCmdWaitEvents2KHR)load(context, "vkCmdWaitEvents2KHR"); + table->vkCmdWriteTimestamp2KHR = (PFN_vkCmdWriteTimestamp2KHR)load(context, "vkCmdWriteTimestamp2KHR"); + table->vkQueueSubmit2KHR = (PFN_vkQueueSubmit2KHR)load(context, "vkQueueSubmit2KHR"); +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) + table->vkCmdWriteBufferMarker2AMD = (PFN_vkCmdWriteBufferMarker2AMD)load(context, "vkCmdWriteBufferMarker2AMD"); +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) + table->vkGetQueueCheckpointData2NV = (PFN_vkGetQueueCheckpointData2NV)load(context, "vkGetQueueCheckpointData2NV"); +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) + table->vkGetSemaphoreCounterValueKHR = (PFN_vkGetSemaphoreCounterValueKHR)load(context, "vkGetSemaphoreCounterValueKHR"); + table->vkSignalSemaphoreKHR = (PFN_vkSignalSemaphoreKHR)load(context, "vkSignalSemaphoreKHR"); + table->vkWaitSemaphoresKHR = (PFN_vkWaitSemaphoresKHR)load(context, "vkWaitSemaphoresKHR"); +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) + table->vkCmdDecodeVideoKHR = (PFN_vkCmdDecodeVideoKHR)load(context, "vkCmdDecodeVideoKHR"); +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) + table->vkCmdEncodeVideoKHR = (PFN_vkCmdEncodeVideoKHR)load(context, "vkCmdEncodeVideoKHR"); + table->vkGetEncodedVideoSessionParametersKHR = (PFN_vkGetEncodedVideoSessionParametersKHR)load(context, "vkGetEncodedVideoSessionParametersKHR"); +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) + table->vkBindVideoSessionMemoryKHR = (PFN_vkBindVideoSessionMemoryKHR)load(context, "vkBindVideoSessionMemoryKHR"); + table->vkCmdBeginVideoCodingKHR = (PFN_vkCmdBeginVideoCodingKHR)load(context, "vkCmdBeginVideoCodingKHR"); + table->vkCmdControlVideoCodingKHR = (PFN_vkCmdControlVideoCodingKHR)load(context, "vkCmdControlVideoCodingKHR"); + table->vkCmdEndVideoCodingKHR = (PFN_vkCmdEndVideoCodingKHR)load(context, "vkCmdEndVideoCodingKHR"); + table->vkCreateVideoSessionKHR = (PFN_vkCreateVideoSessionKHR)load(context, "vkCreateVideoSessionKHR"); + table->vkCreateVideoSessionParametersKHR = (PFN_vkCreateVideoSessionParametersKHR)load(context, "vkCreateVideoSessionParametersKHR"); + table->vkDestroyVideoSessionKHR = (PFN_vkDestroyVideoSessionKHR)load(context, "vkDestroyVideoSessionKHR"); + table->vkDestroyVideoSessionParametersKHR = (PFN_vkDestroyVideoSessionParametersKHR)load(context, "vkDestroyVideoSessionParametersKHR"); + table->vkGetVideoSessionMemoryRequirementsKHR = (PFN_vkGetVideoSessionMemoryRequirementsKHR)load(context, "vkGetVideoSessionMemoryRequirementsKHR"); + table->vkUpdateVideoSessionParametersKHR = (PFN_vkUpdateVideoSessionParametersKHR)load(context, "vkUpdateVideoSessionParametersKHR"); +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_NVX_binary_import) + table->vkCmdCuLaunchKernelNVX = (PFN_vkCmdCuLaunchKernelNVX)load(context, "vkCmdCuLaunchKernelNVX"); + table->vkCreateCuFunctionNVX = (PFN_vkCreateCuFunctionNVX)load(context, "vkCreateCuFunctionNVX"); + table->vkCreateCuModuleNVX = (PFN_vkCreateCuModuleNVX)load(context, "vkCreateCuModuleNVX"); + table->vkDestroyCuFunctionNVX = (PFN_vkDestroyCuFunctionNVX)load(context, "vkDestroyCuFunctionNVX"); + table->vkDestroyCuModuleNVX = (PFN_vkDestroyCuModuleNVX)load(context, "vkDestroyCuModuleNVX"); +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) + table->vkGetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX)load(context, "vkGetImageViewAddressNVX"); + table->vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)load(context, "vkGetImageViewHandleNVX"); +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_clip_space_w_scaling) + table->vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV)load(context, "vkCmdSetViewportWScalingNV"); +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_copy_memory_indirect) + table->vkCmdCopyMemoryIndirectNV = (PFN_vkCmdCopyMemoryIndirectNV)load(context, "vkCmdCopyMemoryIndirectNV"); + table->vkCmdCopyMemoryToImageIndirectNV = (PFN_vkCmdCopyMemoryToImageIndirectNV)load(context, "vkCmdCopyMemoryToImageIndirectNV"); +#endif /* defined(VK_NV_copy_memory_indirect) */ +#if defined(VK_NV_cuda_kernel_launch) + table->vkCmdCudaLaunchKernelNV = (PFN_vkCmdCudaLaunchKernelNV)load(context, "vkCmdCudaLaunchKernelNV"); + table->vkCreateCudaFunctionNV = (PFN_vkCreateCudaFunctionNV)load(context, "vkCreateCudaFunctionNV"); + table->vkCreateCudaModuleNV = (PFN_vkCreateCudaModuleNV)load(context, "vkCreateCudaModuleNV"); + table->vkDestroyCudaFunctionNV = (PFN_vkDestroyCudaFunctionNV)load(context, "vkDestroyCudaFunctionNV"); + table->vkDestroyCudaModuleNV = (PFN_vkDestroyCudaModuleNV)load(context, "vkDestroyCudaModuleNV"); + table->vkGetCudaModuleCacheNV = (PFN_vkGetCudaModuleCacheNV)load(context, "vkGetCudaModuleCacheNV"); +#endif /* defined(VK_NV_cuda_kernel_launch) */ +#if defined(VK_NV_device_diagnostic_checkpoints) + table->vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)load(context, "vkCmdSetCheckpointNV"); + table->vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV)load(context, "vkGetQueueCheckpointDataNV"); +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) + table->vkCmdBindPipelineShaderGroupNV = (PFN_vkCmdBindPipelineShaderGroupNV)load(context, "vkCmdBindPipelineShaderGroupNV"); + table->vkCmdExecuteGeneratedCommandsNV = (PFN_vkCmdExecuteGeneratedCommandsNV)load(context, "vkCmdExecuteGeneratedCommandsNV"); + table->vkCmdPreprocessGeneratedCommandsNV = (PFN_vkCmdPreprocessGeneratedCommandsNV)load(context, "vkCmdPreprocessGeneratedCommandsNV"); + table->vkCreateIndirectCommandsLayoutNV = (PFN_vkCreateIndirectCommandsLayoutNV)load(context, "vkCreateIndirectCommandsLayoutNV"); + table->vkDestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV)load(context, "vkDestroyIndirectCommandsLayoutNV"); + table->vkGetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV)load(context, "vkGetGeneratedCommandsMemoryRequirementsNV"); +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_device_generated_commands_compute) + table->vkCmdUpdatePipelineIndirectBufferNV = (PFN_vkCmdUpdatePipelineIndirectBufferNV)load(context, "vkCmdUpdatePipelineIndirectBufferNV"); + table->vkGetPipelineIndirectDeviceAddressNV = (PFN_vkGetPipelineIndirectDeviceAddressNV)load(context, "vkGetPipelineIndirectDeviceAddressNV"); + table->vkGetPipelineIndirectMemoryRequirementsNV = (PFN_vkGetPipelineIndirectMemoryRequirementsNV)load(context, "vkGetPipelineIndirectMemoryRequirementsNV"); +#endif /* defined(VK_NV_device_generated_commands_compute) */ +#if defined(VK_NV_external_memory_rdma) + table->vkGetMemoryRemoteAddressNV = (PFN_vkGetMemoryRemoteAddressNV)load(context, "vkGetMemoryRemoteAddressNV"); +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) + table->vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV)load(context, "vkGetMemoryWin32HandleNV"); +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) + table->vkCmdSetFragmentShadingRateEnumNV = (PFN_vkCmdSetFragmentShadingRateEnumNV)load(context, "vkCmdSetFragmentShadingRateEnumNV"); +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_low_latency2) + table->vkGetLatencyTimingsNV = (PFN_vkGetLatencyTimingsNV)load(context, "vkGetLatencyTimingsNV"); + table->vkLatencySleepNV = (PFN_vkLatencySleepNV)load(context, "vkLatencySleepNV"); + table->vkQueueNotifyOutOfBandNV = (PFN_vkQueueNotifyOutOfBandNV)load(context, "vkQueueNotifyOutOfBandNV"); + table->vkSetLatencyMarkerNV = (PFN_vkSetLatencyMarkerNV)load(context, "vkSetLatencyMarkerNV"); + table->vkSetLatencySleepModeNV = (PFN_vkSetLatencySleepModeNV)load(context, "vkSetLatencySleepModeNV"); +#endif /* defined(VK_NV_low_latency2) */ +#if defined(VK_NV_memory_decompression) + table->vkCmdDecompressMemoryIndirectCountNV = (PFN_vkCmdDecompressMemoryIndirectCountNV)load(context, "vkCmdDecompressMemoryIndirectCountNV"); + table->vkCmdDecompressMemoryNV = (PFN_vkCmdDecompressMemoryNV)load(context, "vkCmdDecompressMemoryNV"); +#endif /* defined(VK_NV_memory_decompression) */ +#if defined(VK_NV_mesh_shader) + table->vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV)load(context, "vkCmdDrawMeshTasksIndirectCountNV"); + table->vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV)load(context, "vkCmdDrawMeshTasksIndirectNV"); + table->vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV)load(context, "vkCmdDrawMeshTasksNV"); +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_optical_flow) + table->vkBindOpticalFlowSessionImageNV = (PFN_vkBindOpticalFlowSessionImageNV)load(context, "vkBindOpticalFlowSessionImageNV"); + table->vkCmdOpticalFlowExecuteNV = (PFN_vkCmdOpticalFlowExecuteNV)load(context, "vkCmdOpticalFlowExecuteNV"); + table->vkCreateOpticalFlowSessionNV = (PFN_vkCreateOpticalFlowSessionNV)load(context, "vkCreateOpticalFlowSessionNV"); + table->vkDestroyOpticalFlowSessionNV = (PFN_vkDestroyOpticalFlowSessionNV)load(context, "vkDestroyOpticalFlowSessionNV"); +#endif /* defined(VK_NV_optical_flow) */ +#if defined(VK_NV_ray_tracing) + table->vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV)load(context, "vkBindAccelerationStructureMemoryNV"); + table->vkCmdBuildAccelerationStructureNV = (PFN_vkCmdBuildAccelerationStructureNV)load(context, "vkCmdBuildAccelerationStructureNV"); + table->vkCmdCopyAccelerationStructureNV = (PFN_vkCmdCopyAccelerationStructureNV)load(context, "vkCmdCopyAccelerationStructureNV"); + table->vkCmdTraceRaysNV = (PFN_vkCmdTraceRaysNV)load(context, "vkCmdTraceRaysNV"); + table->vkCmdWriteAccelerationStructuresPropertiesNV = (PFN_vkCmdWriteAccelerationStructuresPropertiesNV)load(context, "vkCmdWriteAccelerationStructuresPropertiesNV"); + table->vkCompileDeferredNV = (PFN_vkCompileDeferredNV)load(context, "vkCompileDeferredNV"); + table->vkCreateAccelerationStructureNV = (PFN_vkCreateAccelerationStructureNV)load(context, "vkCreateAccelerationStructureNV"); + table->vkCreateRayTracingPipelinesNV = (PFN_vkCreateRayTracingPipelinesNV)load(context, "vkCreateRayTracingPipelinesNV"); + table->vkDestroyAccelerationStructureNV = (PFN_vkDestroyAccelerationStructureNV)load(context, "vkDestroyAccelerationStructureNV"); + table->vkGetAccelerationStructureHandleNV = (PFN_vkGetAccelerationStructureHandleNV)load(context, "vkGetAccelerationStructureHandleNV"); + table->vkGetAccelerationStructureMemoryRequirementsNV = (PFN_vkGetAccelerationStructureMemoryRequirementsNV)load(context, "vkGetAccelerationStructureMemoryRequirementsNV"); + table->vkGetRayTracingShaderGroupHandlesNV = (PFN_vkGetRayTracingShaderGroupHandlesNV)load(context, "vkGetRayTracingShaderGroupHandlesNV"); +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 + table->vkCmdSetExclusiveScissorEnableNV = (PFN_vkCmdSetExclusiveScissorEnableNV)load(context, "vkCmdSetExclusiveScissorEnableNV"); +#endif /* defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 */ +#if defined(VK_NV_scissor_exclusive) + table->vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV)load(context, "vkCmdSetExclusiveScissorNV"); +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) + table->vkCmdBindShadingRateImageNV = (PFN_vkCmdBindShadingRateImageNV)load(context, "vkCmdBindShadingRateImageNV"); + table->vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV)load(context, "vkCmdSetCoarseSampleOrderNV"); + table->vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV)load(context, "vkCmdSetViewportShadingRatePaletteNV"); +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_QCOM_tile_properties) + table->vkGetDynamicRenderingTilePropertiesQCOM = (PFN_vkGetDynamicRenderingTilePropertiesQCOM)load(context, "vkGetDynamicRenderingTilePropertiesQCOM"); + table->vkGetFramebufferTilePropertiesQCOM = (PFN_vkGetFramebufferTilePropertiesQCOM)load(context, "vkGetFramebufferTilePropertiesQCOM"); +#endif /* defined(VK_QCOM_tile_properties) */ +#if defined(VK_QNX_external_memory_screen_buffer) + table->vkGetScreenBufferPropertiesQNX = (PFN_vkGetScreenBufferPropertiesQNX)load(context, "vkGetScreenBufferPropertiesQNX"); +#endif /* defined(VK_QNX_external_memory_screen_buffer) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) + table->vkGetDescriptorSetHostMappingVALVE = (PFN_vkGetDescriptorSetHostMappingVALVE)load(context, "vkGetDescriptorSetHostMappingVALVE"); + table->vkGetDescriptorSetLayoutHostMappingInfoVALVE = (PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)load(context, "vkGetDescriptorSetLayoutHostMappingInfoVALVE"); +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) + table->vkCmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT)load(context, "vkCmdBindVertexBuffers2EXT"); + table->vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)load(context, "vkCmdSetCullModeEXT"); + table->vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)load(context, "vkCmdSetDepthBoundsTestEnableEXT"); + table->vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)load(context, "vkCmdSetDepthCompareOpEXT"); + table->vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)load(context, "vkCmdSetDepthTestEnableEXT"); + table->vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)load(context, "vkCmdSetDepthWriteEnableEXT"); + table->vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)load(context, "vkCmdSetFrontFaceEXT"); + table->vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)load(context, "vkCmdSetPrimitiveTopologyEXT"); + table->vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)load(context, "vkCmdSetScissorWithCountEXT"); + table->vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)load(context, "vkCmdSetStencilOpEXT"); + table->vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)load(context, "vkCmdSetStencilTestEnableEXT"); + table->vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)load(context, "vkCmdSetViewportWithCountEXT"); +#endif /* (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) + table->vkCmdSetDepthBiasEnableEXT = (PFN_vkCmdSetDepthBiasEnableEXT)load(context, "vkCmdSetDepthBiasEnableEXT"); + table->vkCmdSetLogicOpEXT = (PFN_vkCmdSetLogicOpEXT)load(context, "vkCmdSetLogicOpEXT"); + table->vkCmdSetPatchControlPointsEXT = (PFN_vkCmdSetPatchControlPointsEXT)load(context, "vkCmdSetPatchControlPointsEXT"); + table->vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT)load(context, "vkCmdSetPrimitiveRestartEnableEXT"); + table->vkCmdSetRasterizerDiscardEnableEXT = (PFN_vkCmdSetRasterizerDiscardEnableEXT)load(context, "vkCmdSetRasterizerDiscardEnableEXT"); +#endif /* (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) + table->vkCmdSetAlphaToCoverageEnableEXT = (PFN_vkCmdSetAlphaToCoverageEnableEXT)load(context, "vkCmdSetAlphaToCoverageEnableEXT"); + table->vkCmdSetAlphaToOneEnableEXT = (PFN_vkCmdSetAlphaToOneEnableEXT)load(context, "vkCmdSetAlphaToOneEnableEXT"); + table->vkCmdSetColorBlendAdvancedEXT = (PFN_vkCmdSetColorBlendAdvancedEXT)load(context, "vkCmdSetColorBlendAdvancedEXT"); + table->vkCmdSetColorBlendEnableEXT = (PFN_vkCmdSetColorBlendEnableEXT)load(context, "vkCmdSetColorBlendEnableEXT"); + table->vkCmdSetColorBlendEquationEXT = (PFN_vkCmdSetColorBlendEquationEXT)load(context, "vkCmdSetColorBlendEquationEXT"); + table->vkCmdSetColorWriteMaskEXT = (PFN_vkCmdSetColorWriteMaskEXT)load(context, "vkCmdSetColorWriteMaskEXT"); + table->vkCmdSetConservativeRasterizationModeEXT = (PFN_vkCmdSetConservativeRasterizationModeEXT)load(context, "vkCmdSetConservativeRasterizationModeEXT"); + table->vkCmdSetDepthClampEnableEXT = (PFN_vkCmdSetDepthClampEnableEXT)load(context, "vkCmdSetDepthClampEnableEXT"); + table->vkCmdSetDepthClipEnableEXT = (PFN_vkCmdSetDepthClipEnableEXT)load(context, "vkCmdSetDepthClipEnableEXT"); + table->vkCmdSetDepthClipNegativeOneToOneEXT = (PFN_vkCmdSetDepthClipNegativeOneToOneEXT)load(context, "vkCmdSetDepthClipNegativeOneToOneEXT"); + table->vkCmdSetExtraPrimitiveOverestimationSizeEXT = (PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT)load(context, "vkCmdSetExtraPrimitiveOverestimationSizeEXT"); + table->vkCmdSetLineRasterizationModeEXT = (PFN_vkCmdSetLineRasterizationModeEXT)load(context, "vkCmdSetLineRasterizationModeEXT"); + table->vkCmdSetLineStippleEnableEXT = (PFN_vkCmdSetLineStippleEnableEXT)load(context, "vkCmdSetLineStippleEnableEXT"); + table->vkCmdSetLogicOpEnableEXT = (PFN_vkCmdSetLogicOpEnableEXT)load(context, "vkCmdSetLogicOpEnableEXT"); + table->vkCmdSetPolygonModeEXT = (PFN_vkCmdSetPolygonModeEXT)load(context, "vkCmdSetPolygonModeEXT"); + table->vkCmdSetProvokingVertexModeEXT = (PFN_vkCmdSetProvokingVertexModeEXT)load(context, "vkCmdSetProvokingVertexModeEXT"); + table->vkCmdSetRasterizationSamplesEXT = (PFN_vkCmdSetRasterizationSamplesEXT)load(context, "vkCmdSetRasterizationSamplesEXT"); + table->vkCmdSetRasterizationStreamEXT = (PFN_vkCmdSetRasterizationStreamEXT)load(context, "vkCmdSetRasterizationStreamEXT"); + table->vkCmdSetSampleLocationsEnableEXT = (PFN_vkCmdSetSampleLocationsEnableEXT)load(context, "vkCmdSetSampleLocationsEnableEXT"); + table->vkCmdSetSampleMaskEXT = (PFN_vkCmdSetSampleMaskEXT)load(context, "vkCmdSetSampleMaskEXT"); + table->vkCmdSetTessellationDomainOriginEXT = (PFN_vkCmdSetTessellationDomainOriginEXT)load(context, "vkCmdSetTessellationDomainOriginEXT"); +#endif /* (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) + table->vkCmdSetViewportWScalingEnableNV = (PFN_vkCmdSetViewportWScalingEnableNV)load(context, "vkCmdSetViewportWScalingEnableNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) + table->vkCmdSetViewportSwizzleNV = (PFN_vkCmdSetViewportSwizzleNV)load(context, "vkCmdSetViewportSwizzleNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) + table->vkCmdSetCoverageToColorEnableNV = (PFN_vkCmdSetCoverageToColorEnableNV)load(context, "vkCmdSetCoverageToColorEnableNV"); + table->vkCmdSetCoverageToColorLocationNV = (PFN_vkCmdSetCoverageToColorLocationNV)load(context, "vkCmdSetCoverageToColorLocationNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) + table->vkCmdSetCoverageModulationModeNV = (PFN_vkCmdSetCoverageModulationModeNV)load(context, "vkCmdSetCoverageModulationModeNV"); + table->vkCmdSetCoverageModulationTableEnableNV = (PFN_vkCmdSetCoverageModulationTableEnableNV)load(context, "vkCmdSetCoverageModulationTableEnableNV"); + table->vkCmdSetCoverageModulationTableNV = (PFN_vkCmdSetCoverageModulationTableNV)load(context, "vkCmdSetCoverageModulationTableNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) + table->vkCmdSetShadingRateImageEnableNV = (PFN_vkCmdSetShadingRateImageEnableNV)load(context, "vkCmdSetShadingRateImageEnableNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) + table->vkCmdSetRepresentativeFragmentTestEnableNV = (PFN_vkCmdSetRepresentativeFragmentTestEnableNV)load(context, "vkCmdSetRepresentativeFragmentTestEnableNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) + table->vkCmdSetCoverageReductionModeNV = (PFN_vkCmdSetCoverageReductionModeNV)load(context, "vkCmdSetCoverageReductionModeNV"); +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) + table->vkGetDeviceGroupSurfacePresentModes2EXT = (PFN_vkGetDeviceGroupSurfacePresentModes2EXT)load(context, "vkGetDeviceGroupSurfacePresentModes2EXT"); +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) + table->vkGetImageSubresourceLayout2EXT = (PFN_vkGetImageSubresourceLayout2EXT)load(context, "vkGetImageSubresourceLayout2EXT"); +#endif /* (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) */ +#if (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) + table->vkCmdSetVertexInputEXT = (PFN_vkCmdSetVertexInputEXT)load(context, "vkCmdSetVertexInputEXT"); +#endif /* (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) + table->vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR)load(context, "vkCmdPushDescriptorSetWithTemplateKHR"); +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + table->vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)load(context, "vkGetDeviceGroupPresentCapabilitiesKHR"); + table->vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)load(context, "vkGetDeviceGroupSurfacePresentModesKHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) + table->vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR)load(context, "vkAcquireNextImage2KHR"); +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ + /* VOLK_GENERATE_LOAD_DEVICE_TABLE */ +} + +#ifdef __GNUC__ +#ifdef VOLK_DEFAULT_VISIBILITY +# pragma GCC visibility push(default) +#else +# pragma GCC visibility push(hidden) +#endif +#endif + +/* VOLK_GENERATE_PROTOTYPES_C */ +#if defined(VK_VERSION_1_0) +PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; +PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; +PFN_vkAllocateMemory vkAllocateMemory; +PFN_vkBeginCommandBuffer vkBeginCommandBuffer; +PFN_vkBindBufferMemory vkBindBufferMemory; +PFN_vkBindImageMemory vkBindImageMemory; +PFN_vkCmdBeginQuery vkCmdBeginQuery; +PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; +PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; +PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; +PFN_vkCmdBindPipeline vkCmdBindPipeline; +PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; +PFN_vkCmdBlitImage vkCmdBlitImage; +PFN_vkCmdClearAttachments vkCmdClearAttachments; +PFN_vkCmdClearColorImage vkCmdClearColorImage; +PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; +PFN_vkCmdCopyBuffer vkCmdCopyBuffer; +PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; +PFN_vkCmdCopyImage vkCmdCopyImage; +PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; +PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; +PFN_vkCmdDispatch vkCmdDispatch; +PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; +PFN_vkCmdDraw vkCmdDraw; +PFN_vkCmdDrawIndexed vkCmdDrawIndexed; +PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; +PFN_vkCmdDrawIndirect vkCmdDrawIndirect; +PFN_vkCmdEndQuery vkCmdEndQuery; +PFN_vkCmdEndRenderPass vkCmdEndRenderPass; +PFN_vkCmdExecuteCommands vkCmdExecuteCommands; +PFN_vkCmdFillBuffer vkCmdFillBuffer; +PFN_vkCmdNextSubpass vkCmdNextSubpass; +PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; +PFN_vkCmdPushConstants vkCmdPushConstants; +PFN_vkCmdResetEvent vkCmdResetEvent; +PFN_vkCmdResetQueryPool vkCmdResetQueryPool; +PFN_vkCmdResolveImage vkCmdResolveImage; +PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; +PFN_vkCmdSetDepthBias vkCmdSetDepthBias; +PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; +PFN_vkCmdSetEvent vkCmdSetEvent; +PFN_vkCmdSetLineWidth vkCmdSetLineWidth; +PFN_vkCmdSetScissor vkCmdSetScissor; +PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; +PFN_vkCmdSetStencilReference vkCmdSetStencilReference; +PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; +PFN_vkCmdSetViewport vkCmdSetViewport; +PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; +PFN_vkCmdWaitEvents vkCmdWaitEvents; +PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; +PFN_vkCreateBuffer vkCreateBuffer; +PFN_vkCreateBufferView vkCreateBufferView; +PFN_vkCreateCommandPool vkCreateCommandPool; +PFN_vkCreateComputePipelines vkCreateComputePipelines; +PFN_vkCreateDescriptorPool vkCreateDescriptorPool; +PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; +PFN_vkCreateDevice vkCreateDevice; +PFN_vkCreateEvent vkCreateEvent; +PFN_vkCreateFence vkCreateFence; +PFN_vkCreateFramebuffer vkCreateFramebuffer; +PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; +PFN_vkCreateImage vkCreateImage; +PFN_vkCreateImageView vkCreateImageView; +PFN_vkCreateInstance vkCreateInstance; +PFN_vkCreatePipelineCache vkCreatePipelineCache; +PFN_vkCreatePipelineLayout vkCreatePipelineLayout; +PFN_vkCreateQueryPool vkCreateQueryPool; +PFN_vkCreateRenderPass vkCreateRenderPass; +PFN_vkCreateSampler vkCreateSampler; +PFN_vkCreateSemaphore vkCreateSemaphore; +PFN_vkCreateShaderModule vkCreateShaderModule; +PFN_vkDestroyBuffer vkDestroyBuffer; +PFN_vkDestroyBufferView vkDestroyBufferView; +PFN_vkDestroyCommandPool vkDestroyCommandPool; +PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; +PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; +PFN_vkDestroyDevice vkDestroyDevice; +PFN_vkDestroyEvent vkDestroyEvent; +PFN_vkDestroyFence vkDestroyFence; +PFN_vkDestroyFramebuffer vkDestroyFramebuffer; +PFN_vkDestroyImage vkDestroyImage; +PFN_vkDestroyImageView vkDestroyImageView; +PFN_vkDestroyInstance vkDestroyInstance; +PFN_vkDestroyPipeline vkDestroyPipeline; +PFN_vkDestroyPipelineCache vkDestroyPipelineCache; +PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; +PFN_vkDestroyQueryPool vkDestroyQueryPool; +PFN_vkDestroyRenderPass vkDestroyRenderPass; +PFN_vkDestroySampler vkDestroySampler; +PFN_vkDestroySemaphore vkDestroySemaphore; +PFN_vkDestroyShaderModule vkDestroyShaderModule; +PFN_vkDeviceWaitIdle vkDeviceWaitIdle; +PFN_vkEndCommandBuffer vkEndCommandBuffer; +PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; +PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; +PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; +PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; +PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; +PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; +PFN_vkFreeCommandBuffers vkFreeCommandBuffers; +PFN_vkFreeDescriptorSets vkFreeDescriptorSets; +PFN_vkFreeMemory vkFreeMemory; +PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; +PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; +PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +PFN_vkGetDeviceQueue vkGetDeviceQueue; +PFN_vkGetEventStatus vkGetEventStatus; +PFN_vkGetFenceStatus vkGetFenceStatus; +PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; +PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; +PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; +PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; +PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; +PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; +PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; +PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; +PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; +PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; +PFN_vkGetPipelineCacheData vkGetPipelineCacheData; +PFN_vkGetQueryPoolResults vkGetQueryPoolResults; +PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; +PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; +PFN_vkMapMemory vkMapMemory; +PFN_vkMergePipelineCaches vkMergePipelineCaches; +PFN_vkQueueBindSparse vkQueueBindSparse; +PFN_vkQueueSubmit vkQueueSubmit; +PFN_vkQueueWaitIdle vkQueueWaitIdle; +PFN_vkResetCommandBuffer vkResetCommandBuffer; +PFN_vkResetCommandPool vkResetCommandPool; +PFN_vkResetDescriptorPool vkResetDescriptorPool; +PFN_vkResetEvent vkResetEvent; +PFN_vkResetFences vkResetFences; +PFN_vkSetEvent vkSetEvent; +PFN_vkUnmapMemory vkUnmapMemory; +PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; +PFN_vkWaitForFences vkWaitForFences; +#endif /* defined(VK_VERSION_1_0) */ +#if defined(VK_VERSION_1_1) +PFN_vkBindBufferMemory2 vkBindBufferMemory2; +PFN_vkBindImageMemory2 vkBindImageMemory2; +PFN_vkCmdDispatchBase vkCmdDispatchBase; +PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; +PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; +PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; +PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; +PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; +PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; +PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups; +PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; +PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; +PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; +PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; +PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; +PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; +PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties; +PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties; +PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties; +PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; +PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2; +PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2; +PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; +PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; +PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2; +PFN_vkTrimCommandPool vkTrimCommandPool; +PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; +#endif /* defined(VK_VERSION_1_1) */ +#if defined(VK_VERSION_1_2) +PFN_vkCmdBeginRenderPass2 vkCmdBeginRenderPass2; +PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount; +PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount; +PFN_vkCmdEndRenderPass2 vkCmdEndRenderPass2; +PFN_vkCmdNextSubpass2 vkCmdNextSubpass2; +PFN_vkCreateRenderPass2 vkCreateRenderPass2; +PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress; +PFN_vkGetBufferOpaqueCaptureAddress vkGetBufferOpaqueCaptureAddress; +PFN_vkGetDeviceMemoryOpaqueCaptureAddress vkGetDeviceMemoryOpaqueCaptureAddress; +PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue; +PFN_vkResetQueryPool vkResetQueryPool; +PFN_vkSignalSemaphore vkSignalSemaphore; +PFN_vkWaitSemaphores vkWaitSemaphores; +#endif /* defined(VK_VERSION_1_2) */ +#if defined(VK_VERSION_1_3) +PFN_vkCmdBeginRendering vkCmdBeginRendering; +PFN_vkCmdBindVertexBuffers2 vkCmdBindVertexBuffers2; +PFN_vkCmdBlitImage2 vkCmdBlitImage2; +PFN_vkCmdCopyBuffer2 vkCmdCopyBuffer2; +PFN_vkCmdCopyBufferToImage2 vkCmdCopyBufferToImage2; +PFN_vkCmdCopyImage2 vkCmdCopyImage2; +PFN_vkCmdCopyImageToBuffer2 vkCmdCopyImageToBuffer2; +PFN_vkCmdEndRendering vkCmdEndRendering; +PFN_vkCmdPipelineBarrier2 vkCmdPipelineBarrier2; +PFN_vkCmdResetEvent2 vkCmdResetEvent2; +PFN_vkCmdResolveImage2 vkCmdResolveImage2; +PFN_vkCmdSetCullMode vkCmdSetCullMode; +PFN_vkCmdSetDepthBiasEnable vkCmdSetDepthBiasEnable; +PFN_vkCmdSetDepthBoundsTestEnable vkCmdSetDepthBoundsTestEnable; +PFN_vkCmdSetDepthCompareOp vkCmdSetDepthCompareOp; +PFN_vkCmdSetDepthTestEnable vkCmdSetDepthTestEnable; +PFN_vkCmdSetDepthWriteEnable vkCmdSetDepthWriteEnable; +PFN_vkCmdSetEvent2 vkCmdSetEvent2; +PFN_vkCmdSetFrontFace vkCmdSetFrontFace; +PFN_vkCmdSetPrimitiveRestartEnable vkCmdSetPrimitiveRestartEnable; +PFN_vkCmdSetPrimitiveTopology vkCmdSetPrimitiveTopology; +PFN_vkCmdSetRasterizerDiscardEnable vkCmdSetRasterizerDiscardEnable; +PFN_vkCmdSetScissorWithCount vkCmdSetScissorWithCount; +PFN_vkCmdSetStencilOp vkCmdSetStencilOp; +PFN_vkCmdSetStencilTestEnable vkCmdSetStencilTestEnable; +PFN_vkCmdSetViewportWithCount vkCmdSetViewportWithCount; +PFN_vkCmdWaitEvents2 vkCmdWaitEvents2; +PFN_vkCmdWriteTimestamp2 vkCmdWriteTimestamp2; +PFN_vkCreatePrivateDataSlot vkCreatePrivateDataSlot; +PFN_vkDestroyPrivateDataSlot vkDestroyPrivateDataSlot; +PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements; +PFN_vkGetDeviceImageMemoryRequirements vkGetDeviceImageMemoryRequirements; +PFN_vkGetDeviceImageSparseMemoryRequirements vkGetDeviceImageSparseMemoryRequirements; +PFN_vkGetPhysicalDeviceToolProperties vkGetPhysicalDeviceToolProperties; +PFN_vkGetPrivateData vkGetPrivateData; +PFN_vkQueueSubmit2 vkQueueSubmit2; +PFN_vkSetPrivateData vkSetPrivateData; +#endif /* defined(VK_VERSION_1_3) */ +#if defined(VK_AMDX_shader_enqueue) +PFN_vkCmdDispatchGraphAMDX vkCmdDispatchGraphAMDX; +PFN_vkCmdDispatchGraphIndirectAMDX vkCmdDispatchGraphIndirectAMDX; +PFN_vkCmdDispatchGraphIndirectCountAMDX vkCmdDispatchGraphIndirectCountAMDX; +PFN_vkCmdInitializeGraphScratchMemoryAMDX vkCmdInitializeGraphScratchMemoryAMDX; +PFN_vkCreateExecutionGraphPipelinesAMDX vkCreateExecutionGraphPipelinesAMDX; +PFN_vkGetExecutionGraphPipelineNodeIndexAMDX vkGetExecutionGraphPipelineNodeIndexAMDX; +PFN_vkGetExecutionGraphPipelineScratchSizeAMDX vkGetExecutionGraphPipelineScratchSizeAMDX; +#endif /* defined(VK_AMDX_shader_enqueue) */ +#if defined(VK_AMD_buffer_marker) +PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; +#endif /* defined(VK_AMD_buffer_marker) */ +#if defined(VK_AMD_display_native_hdr) +PFN_vkSetLocalDimmingAMD vkSetLocalDimmingAMD; +#endif /* defined(VK_AMD_display_native_hdr) */ +#if defined(VK_AMD_draw_indirect_count) +PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; +PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; +#endif /* defined(VK_AMD_draw_indirect_count) */ +#if defined(VK_AMD_shader_info) +PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; +#endif /* defined(VK_AMD_shader_info) */ +#if defined(VK_ANDROID_external_memory_android_hardware_buffer) +PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; +PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ +#if defined(VK_EXT_acquire_drm_display) +PFN_vkAcquireDrmDisplayEXT vkAcquireDrmDisplayEXT; +PFN_vkGetDrmDisplayEXT vkGetDrmDisplayEXT; +#endif /* defined(VK_EXT_acquire_drm_display) */ +#if defined(VK_EXT_acquire_xlib_display) +PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; +PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; +#endif /* defined(VK_EXT_acquire_xlib_display) */ +#if defined(VK_EXT_attachment_feedback_loop_dynamic_state) +PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT vkCmdSetAttachmentFeedbackLoopEnableEXT; +#endif /* defined(VK_EXT_attachment_feedback_loop_dynamic_state) */ +#if defined(VK_EXT_buffer_device_address) +PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; +#endif /* defined(VK_EXT_buffer_device_address) */ +#if defined(VK_EXT_calibrated_timestamps) +PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; +PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; +#endif /* defined(VK_EXT_calibrated_timestamps) */ +#if defined(VK_EXT_color_write_enable) +PFN_vkCmdSetColorWriteEnableEXT vkCmdSetColorWriteEnableEXT; +#endif /* defined(VK_EXT_color_write_enable) */ +#if defined(VK_EXT_conditional_rendering) +PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; +PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; +#endif /* defined(VK_EXT_conditional_rendering) */ +#if defined(VK_EXT_debug_marker) +PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; +PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; +PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; +PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; +PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; +#endif /* defined(VK_EXT_debug_marker) */ +#if defined(VK_EXT_debug_report) +PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; +PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +#endif /* defined(VK_EXT_debug_report) */ +#if defined(VK_EXT_debug_utils) +PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; +PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; +PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; +PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; +PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; +PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; +PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT; +#endif /* defined(VK_EXT_debug_utils) */ +#if defined(VK_EXT_depth_bias_control) +PFN_vkCmdSetDepthBias2EXT vkCmdSetDepthBias2EXT; +#endif /* defined(VK_EXT_depth_bias_control) */ +#if defined(VK_EXT_descriptor_buffer) +PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT vkCmdBindDescriptorBufferEmbeddedSamplersEXT; +PFN_vkCmdBindDescriptorBuffersEXT vkCmdBindDescriptorBuffersEXT; +PFN_vkCmdSetDescriptorBufferOffsetsEXT vkCmdSetDescriptorBufferOffsetsEXT; +PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT vkGetBufferOpaqueCaptureDescriptorDataEXT; +PFN_vkGetDescriptorEXT vkGetDescriptorEXT; +PFN_vkGetDescriptorSetLayoutBindingOffsetEXT vkGetDescriptorSetLayoutBindingOffsetEXT; +PFN_vkGetDescriptorSetLayoutSizeEXT vkGetDescriptorSetLayoutSizeEXT; +PFN_vkGetImageOpaqueCaptureDescriptorDataEXT vkGetImageOpaqueCaptureDescriptorDataEXT; +PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT vkGetImageViewOpaqueCaptureDescriptorDataEXT; +PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT vkGetSamplerOpaqueCaptureDescriptorDataEXT; +#endif /* defined(VK_EXT_descriptor_buffer) */ +#if defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) +PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT; +#endif /* defined(VK_EXT_descriptor_buffer) && (defined(VK_KHR_acceleration_structure) || defined(VK_NV_ray_tracing)) */ +#if defined(VK_EXT_device_fault) +PFN_vkGetDeviceFaultInfoEXT vkGetDeviceFaultInfoEXT; +#endif /* defined(VK_EXT_device_fault) */ +#if defined(VK_EXT_direct_mode_display) +PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; +#endif /* defined(VK_EXT_direct_mode_display) */ +#if defined(VK_EXT_directfb_surface) +PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT; +PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT; +#endif /* defined(VK_EXT_directfb_surface) */ +#if defined(VK_EXT_discard_rectangles) +PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; +#endif /* defined(VK_EXT_discard_rectangles) */ +#if defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 +PFN_vkCmdSetDiscardRectangleEnableEXT vkCmdSetDiscardRectangleEnableEXT; +PFN_vkCmdSetDiscardRectangleModeEXT vkCmdSetDiscardRectangleModeEXT; +#endif /* defined(VK_EXT_discard_rectangles) && VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION >= 2 */ +#if defined(VK_EXT_display_control) +PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; +PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; +PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; +PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; +#endif /* defined(VK_EXT_display_control) */ +#if defined(VK_EXT_display_surface_counter) +PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT; +#endif /* defined(VK_EXT_display_surface_counter) */ +#if defined(VK_EXT_external_memory_host) +PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; +#endif /* defined(VK_EXT_external_memory_host) */ +#if defined(VK_EXT_full_screen_exclusive) +PFN_vkAcquireFullScreenExclusiveModeEXT vkAcquireFullScreenExclusiveModeEXT; +PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT vkGetPhysicalDeviceSurfacePresentModes2EXT; +PFN_vkReleaseFullScreenExclusiveModeEXT vkReleaseFullScreenExclusiveModeEXT; +#endif /* defined(VK_EXT_full_screen_exclusive) */ +#if defined(VK_EXT_hdr_metadata) +PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; +#endif /* defined(VK_EXT_hdr_metadata) */ +#if defined(VK_EXT_headless_surface) +PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT; +#endif /* defined(VK_EXT_headless_surface) */ +#if defined(VK_EXT_host_image_copy) +PFN_vkCopyImageToImageEXT vkCopyImageToImageEXT; +PFN_vkCopyImageToMemoryEXT vkCopyImageToMemoryEXT; +PFN_vkCopyMemoryToImageEXT vkCopyMemoryToImageEXT; +PFN_vkTransitionImageLayoutEXT vkTransitionImageLayoutEXT; +#endif /* defined(VK_EXT_host_image_copy) */ +#if defined(VK_EXT_host_query_reset) +PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; +#endif /* defined(VK_EXT_host_query_reset) */ +#if defined(VK_EXT_image_drm_format_modifier) +PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; +#endif /* defined(VK_EXT_image_drm_format_modifier) */ +#if defined(VK_EXT_line_rasterization) +PFN_vkCmdSetLineStippleEXT vkCmdSetLineStippleEXT; +#endif /* defined(VK_EXT_line_rasterization) */ +#if defined(VK_EXT_mesh_shader) +PFN_vkCmdDrawMeshTasksEXT vkCmdDrawMeshTasksEXT; +PFN_vkCmdDrawMeshTasksIndirectCountEXT vkCmdDrawMeshTasksIndirectCountEXT; +PFN_vkCmdDrawMeshTasksIndirectEXT vkCmdDrawMeshTasksIndirectEXT; +#endif /* defined(VK_EXT_mesh_shader) */ +#if defined(VK_EXT_metal_objects) +PFN_vkExportMetalObjectsEXT vkExportMetalObjectsEXT; +#endif /* defined(VK_EXT_metal_objects) */ +#if defined(VK_EXT_metal_surface) +PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; +#endif /* defined(VK_EXT_metal_surface) */ +#if defined(VK_EXT_multi_draw) +PFN_vkCmdDrawMultiEXT vkCmdDrawMultiEXT; +PFN_vkCmdDrawMultiIndexedEXT vkCmdDrawMultiIndexedEXT; +#endif /* defined(VK_EXT_multi_draw) */ +#if defined(VK_EXT_opacity_micromap) +PFN_vkBuildMicromapsEXT vkBuildMicromapsEXT; +PFN_vkCmdBuildMicromapsEXT vkCmdBuildMicromapsEXT; +PFN_vkCmdCopyMemoryToMicromapEXT vkCmdCopyMemoryToMicromapEXT; +PFN_vkCmdCopyMicromapEXT vkCmdCopyMicromapEXT; +PFN_vkCmdCopyMicromapToMemoryEXT vkCmdCopyMicromapToMemoryEXT; +PFN_vkCmdWriteMicromapsPropertiesEXT vkCmdWriteMicromapsPropertiesEXT; +PFN_vkCopyMemoryToMicromapEXT vkCopyMemoryToMicromapEXT; +PFN_vkCopyMicromapEXT vkCopyMicromapEXT; +PFN_vkCopyMicromapToMemoryEXT vkCopyMicromapToMemoryEXT; +PFN_vkCreateMicromapEXT vkCreateMicromapEXT; +PFN_vkDestroyMicromapEXT vkDestroyMicromapEXT; +PFN_vkGetDeviceMicromapCompatibilityEXT vkGetDeviceMicromapCompatibilityEXT; +PFN_vkGetMicromapBuildSizesEXT vkGetMicromapBuildSizesEXT; +PFN_vkWriteMicromapsPropertiesEXT vkWriteMicromapsPropertiesEXT; +#endif /* defined(VK_EXT_opacity_micromap) */ +#if defined(VK_EXT_pageable_device_local_memory) +PFN_vkSetDeviceMemoryPriorityEXT vkSetDeviceMemoryPriorityEXT; +#endif /* defined(VK_EXT_pageable_device_local_memory) */ +#if defined(VK_EXT_pipeline_properties) +PFN_vkGetPipelinePropertiesEXT vkGetPipelinePropertiesEXT; +#endif /* defined(VK_EXT_pipeline_properties) */ +#if defined(VK_EXT_private_data) +PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT; +PFN_vkDestroyPrivateDataSlotEXT vkDestroyPrivateDataSlotEXT; +PFN_vkGetPrivateDataEXT vkGetPrivateDataEXT; +PFN_vkSetPrivateDataEXT vkSetPrivateDataEXT; +#endif /* defined(VK_EXT_private_data) */ +#if defined(VK_EXT_sample_locations) +PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; +PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT; +#endif /* defined(VK_EXT_sample_locations) */ +#if defined(VK_EXT_shader_module_identifier) +PFN_vkGetShaderModuleCreateInfoIdentifierEXT vkGetShaderModuleCreateInfoIdentifierEXT; +PFN_vkGetShaderModuleIdentifierEXT vkGetShaderModuleIdentifierEXT; +#endif /* defined(VK_EXT_shader_module_identifier) */ +#if defined(VK_EXT_shader_object) +PFN_vkCmdBindShadersEXT vkCmdBindShadersEXT; +PFN_vkCreateShadersEXT vkCreateShadersEXT; +PFN_vkDestroyShaderEXT vkDestroyShaderEXT; +PFN_vkGetShaderBinaryDataEXT vkGetShaderBinaryDataEXT; +#endif /* defined(VK_EXT_shader_object) */ +#if defined(VK_EXT_swapchain_maintenance1) +PFN_vkReleaseSwapchainImagesEXT vkReleaseSwapchainImagesEXT; +#endif /* defined(VK_EXT_swapchain_maintenance1) */ +#if defined(VK_EXT_tooling_info) +PFN_vkGetPhysicalDeviceToolPropertiesEXT vkGetPhysicalDeviceToolPropertiesEXT; +#endif /* defined(VK_EXT_tooling_info) */ +#if defined(VK_EXT_transform_feedback) +PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; +PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; +PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; +PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; +PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; +PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; +#endif /* defined(VK_EXT_transform_feedback) */ +#if defined(VK_EXT_validation_cache) +PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; +PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; +PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; +PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; +#endif /* defined(VK_EXT_validation_cache) */ +#if defined(VK_FUCHSIA_buffer_collection) +PFN_vkCreateBufferCollectionFUCHSIA vkCreateBufferCollectionFUCHSIA; +PFN_vkDestroyBufferCollectionFUCHSIA vkDestroyBufferCollectionFUCHSIA; +PFN_vkGetBufferCollectionPropertiesFUCHSIA vkGetBufferCollectionPropertiesFUCHSIA; +PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA vkSetBufferCollectionBufferConstraintsFUCHSIA; +PFN_vkSetBufferCollectionImageConstraintsFUCHSIA vkSetBufferCollectionImageConstraintsFUCHSIA; +#endif /* defined(VK_FUCHSIA_buffer_collection) */ +#if defined(VK_FUCHSIA_external_memory) +PFN_vkGetMemoryZirconHandleFUCHSIA vkGetMemoryZirconHandleFUCHSIA; +PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA vkGetMemoryZirconHandlePropertiesFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_memory) */ +#if defined(VK_FUCHSIA_external_semaphore) +PFN_vkGetSemaphoreZirconHandleFUCHSIA vkGetSemaphoreZirconHandleFUCHSIA; +PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA; +#endif /* defined(VK_FUCHSIA_external_semaphore) */ +#if defined(VK_FUCHSIA_imagepipe_surface) +PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; +#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ +#if defined(VK_GGP_stream_descriptor_surface) +PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP; +#endif /* defined(VK_GGP_stream_descriptor_surface) */ +#if defined(VK_GOOGLE_display_timing) +PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; +PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; +#endif /* defined(VK_GOOGLE_display_timing) */ +#if defined(VK_HUAWEI_cluster_culling_shader) +PFN_vkCmdDrawClusterHUAWEI vkCmdDrawClusterHUAWEI; +PFN_vkCmdDrawClusterIndirectHUAWEI vkCmdDrawClusterIndirectHUAWEI; +#endif /* defined(VK_HUAWEI_cluster_culling_shader) */ +#if defined(VK_HUAWEI_invocation_mask) +PFN_vkCmdBindInvocationMaskHUAWEI vkCmdBindInvocationMaskHUAWEI; +#endif /* defined(VK_HUAWEI_invocation_mask) */ +#if defined(VK_HUAWEI_subpass_shading) +PFN_vkCmdSubpassShadingHUAWEI vkCmdSubpassShadingHUAWEI; +PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI; +#endif /* defined(VK_HUAWEI_subpass_shading) */ +#if defined(VK_INTEL_performance_query) +PFN_vkAcquirePerformanceConfigurationINTEL vkAcquirePerformanceConfigurationINTEL; +PFN_vkCmdSetPerformanceMarkerINTEL vkCmdSetPerformanceMarkerINTEL; +PFN_vkCmdSetPerformanceOverrideINTEL vkCmdSetPerformanceOverrideINTEL; +PFN_vkCmdSetPerformanceStreamMarkerINTEL vkCmdSetPerformanceStreamMarkerINTEL; +PFN_vkGetPerformanceParameterINTEL vkGetPerformanceParameterINTEL; +PFN_vkInitializePerformanceApiINTEL vkInitializePerformanceApiINTEL; +PFN_vkQueueSetPerformanceConfigurationINTEL vkQueueSetPerformanceConfigurationINTEL; +PFN_vkReleasePerformanceConfigurationINTEL vkReleasePerformanceConfigurationINTEL; +PFN_vkUninitializePerformanceApiINTEL vkUninitializePerformanceApiINTEL; +#endif /* defined(VK_INTEL_performance_query) */ +#if defined(VK_KHR_acceleration_structure) +PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR; +PFN_vkCmdBuildAccelerationStructuresIndirectKHR vkCmdBuildAccelerationStructuresIndirectKHR; +PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; +PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; +PFN_vkCmdCopyAccelerationStructureToMemoryKHR vkCmdCopyAccelerationStructureToMemoryKHR; +PFN_vkCmdCopyMemoryToAccelerationStructureKHR vkCmdCopyMemoryToAccelerationStructureKHR; +PFN_vkCmdWriteAccelerationStructuresPropertiesKHR vkCmdWriteAccelerationStructuresPropertiesKHR; +PFN_vkCopyAccelerationStructureKHR vkCopyAccelerationStructureKHR; +PFN_vkCopyAccelerationStructureToMemoryKHR vkCopyAccelerationStructureToMemoryKHR; +PFN_vkCopyMemoryToAccelerationStructureKHR vkCopyMemoryToAccelerationStructureKHR; +PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; +PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; +PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; +PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; +PFN_vkGetDeviceAccelerationStructureCompatibilityKHR vkGetDeviceAccelerationStructureCompatibilityKHR; +PFN_vkWriteAccelerationStructuresPropertiesKHR vkWriteAccelerationStructuresPropertiesKHR; +#endif /* defined(VK_KHR_acceleration_structure) */ +#if defined(VK_KHR_android_surface) +PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif /* defined(VK_KHR_android_surface) */ +#if defined(VK_KHR_bind_memory2) +PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; +PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; +#endif /* defined(VK_KHR_bind_memory2) */ +#if defined(VK_KHR_buffer_device_address) +PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; +PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR; +PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR; +#endif /* defined(VK_KHR_buffer_device_address) */ +#if defined(VK_KHR_cooperative_matrix) +PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; +#endif /* defined(VK_KHR_cooperative_matrix) */ +#if defined(VK_KHR_copy_commands2) +PFN_vkCmdBlitImage2KHR vkCmdBlitImage2KHR; +PFN_vkCmdCopyBuffer2KHR vkCmdCopyBuffer2KHR; +PFN_vkCmdCopyBufferToImage2KHR vkCmdCopyBufferToImage2KHR; +PFN_vkCmdCopyImage2KHR vkCmdCopyImage2KHR; +PFN_vkCmdCopyImageToBuffer2KHR vkCmdCopyImageToBuffer2KHR; +PFN_vkCmdResolveImage2KHR vkCmdResolveImage2KHR; +#endif /* defined(VK_KHR_copy_commands2) */ +#if defined(VK_KHR_create_renderpass2) +PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; +PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; +PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; +PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; +#endif /* defined(VK_KHR_create_renderpass2) */ +#if defined(VK_KHR_deferred_host_operations) +PFN_vkCreateDeferredOperationKHR vkCreateDeferredOperationKHR; +PFN_vkDeferredOperationJoinKHR vkDeferredOperationJoinKHR; +PFN_vkDestroyDeferredOperationKHR vkDestroyDeferredOperationKHR; +PFN_vkGetDeferredOperationMaxConcurrencyKHR vkGetDeferredOperationMaxConcurrencyKHR; +PFN_vkGetDeferredOperationResultKHR vkGetDeferredOperationResultKHR; +#endif /* defined(VK_KHR_deferred_host_operations) */ +#if defined(VK_KHR_descriptor_update_template) +PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; +PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; +PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; +#endif /* defined(VK_KHR_descriptor_update_template) */ +#if defined(VK_KHR_device_group) +PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; +PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; +PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; +#endif /* defined(VK_KHR_device_group) */ +#if defined(VK_KHR_device_group_creation) +PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR; +#endif /* defined(VK_KHR_device_group_creation) */ +#if defined(VK_KHR_display) +PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; +PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; +PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; +PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +#endif /* defined(VK_KHR_display) */ +#if defined(VK_KHR_display_swapchain) +PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; +#endif /* defined(VK_KHR_display_swapchain) */ +#if defined(VK_KHR_draw_indirect_count) +PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; +PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; +#endif /* defined(VK_KHR_draw_indirect_count) */ +#if defined(VK_KHR_dynamic_rendering) +PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR; +PFN_vkCmdEndRenderingKHR vkCmdEndRenderingKHR; +#endif /* defined(VK_KHR_dynamic_rendering) */ +#if defined(VK_KHR_external_fence_capabilities) +PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR vkGetPhysicalDeviceExternalFencePropertiesKHR; +#endif /* defined(VK_KHR_external_fence_capabilities) */ +#if defined(VK_KHR_external_fence_fd) +PFN_vkGetFenceFdKHR vkGetFenceFdKHR; +PFN_vkImportFenceFdKHR vkImportFenceFdKHR; +#endif /* defined(VK_KHR_external_fence_fd) */ +#if defined(VK_KHR_external_fence_win32) +PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; +PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; +#endif /* defined(VK_KHR_external_fence_win32) */ +#if defined(VK_KHR_external_memory_capabilities) +PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_capabilities) */ +#if defined(VK_KHR_external_memory_fd) +PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; +PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; +#endif /* defined(VK_KHR_external_memory_fd) */ +#if defined(VK_KHR_external_memory_win32) +PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; +PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; +#endif /* defined(VK_KHR_external_memory_win32) */ +#if defined(VK_KHR_external_semaphore_capabilities) +PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR vkGetPhysicalDeviceExternalSemaphorePropertiesKHR; +#endif /* defined(VK_KHR_external_semaphore_capabilities) */ +#if defined(VK_KHR_external_semaphore_fd) +PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; +PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; +#endif /* defined(VK_KHR_external_semaphore_fd) */ +#if defined(VK_KHR_external_semaphore_win32) +PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; +PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; +#endif /* defined(VK_KHR_external_semaphore_win32) */ +#if defined(VK_KHR_fragment_shading_rate) +PFN_vkCmdSetFragmentShadingRateKHR vkCmdSetFragmentShadingRateKHR; +PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR vkGetPhysicalDeviceFragmentShadingRatesKHR; +#endif /* defined(VK_KHR_fragment_shading_rate) */ +#if defined(VK_KHR_get_display_properties2) +PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR; +PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR; +PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR; +PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR; +#endif /* defined(VK_KHR_get_display_properties2) */ +#if defined(VK_KHR_get_memory_requirements2) +PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; +PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; +PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; +#endif /* defined(VK_KHR_get_memory_requirements2) */ +#if defined(VK_KHR_get_physical_device_properties2) +PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; +PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; +PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; +PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; +PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; +PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; +#endif /* defined(VK_KHR_get_physical_device_properties2) */ +#if defined(VK_KHR_get_surface_capabilities2) +PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; +PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; +#endif /* defined(VK_KHR_get_surface_capabilities2) */ +#if defined(VK_KHR_maintenance1) +PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; +#endif /* defined(VK_KHR_maintenance1) */ +#if defined(VK_KHR_maintenance3) +PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; +#endif /* defined(VK_KHR_maintenance3) */ +#if defined(VK_KHR_maintenance4) +PFN_vkGetDeviceBufferMemoryRequirementsKHR vkGetDeviceBufferMemoryRequirementsKHR; +PFN_vkGetDeviceImageMemoryRequirementsKHR vkGetDeviceImageMemoryRequirementsKHR; +PFN_vkGetDeviceImageSparseMemoryRequirementsKHR vkGetDeviceImageSparseMemoryRequirementsKHR; +#endif /* defined(VK_KHR_maintenance4) */ +#if defined(VK_KHR_maintenance5) +PFN_vkCmdBindIndexBuffer2KHR vkCmdBindIndexBuffer2KHR; +PFN_vkGetDeviceImageSubresourceLayoutKHR vkGetDeviceImageSubresourceLayoutKHR; +PFN_vkGetImageSubresourceLayout2KHR vkGetImageSubresourceLayout2KHR; +PFN_vkGetRenderingAreaGranularityKHR vkGetRenderingAreaGranularityKHR; +#endif /* defined(VK_KHR_maintenance5) */ +#if defined(VK_KHR_map_memory2) +PFN_vkMapMemory2KHR vkMapMemory2KHR; +PFN_vkUnmapMemory2KHR vkUnmapMemory2KHR; +#endif /* defined(VK_KHR_map_memory2) */ +#if defined(VK_KHR_performance_query) +PFN_vkAcquireProfilingLockKHR vkAcquireProfilingLockKHR; +PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR; +PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR; +PFN_vkReleaseProfilingLockKHR vkReleaseProfilingLockKHR; +#endif /* defined(VK_KHR_performance_query) */ +#if defined(VK_KHR_pipeline_executable_properties) +PFN_vkGetPipelineExecutableInternalRepresentationsKHR vkGetPipelineExecutableInternalRepresentationsKHR; +PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR; +PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR; +#endif /* defined(VK_KHR_pipeline_executable_properties) */ +#if defined(VK_KHR_present_wait) +PFN_vkWaitForPresentKHR vkWaitForPresentKHR; +#endif /* defined(VK_KHR_present_wait) */ +#if defined(VK_KHR_push_descriptor) +PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; +#endif /* defined(VK_KHR_push_descriptor) */ +#if defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) +PFN_vkCmdTraceRaysIndirect2KHR vkCmdTraceRaysIndirect2KHR; +#endif /* defined(VK_KHR_ray_tracing_maintenance1) && defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_ray_tracing_pipeline) +PFN_vkCmdSetRayTracingPipelineStackSizeKHR vkCmdSetRayTracingPipelineStackSizeKHR; +PFN_vkCmdTraceRaysIndirectKHR vkCmdTraceRaysIndirectKHR; +PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; +PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; +PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; +PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; +PFN_vkGetRayTracingShaderGroupStackSizeKHR vkGetRayTracingShaderGroupStackSizeKHR; +#endif /* defined(VK_KHR_ray_tracing_pipeline) */ +#if defined(VK_KHR_sampler_ycbcr_conversion) +PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; +PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; +#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ +#if defined(VK_KHR_shared_presentable_image) +PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; +#endif /* defined(VK_KHR_shared_presentable_image) */ +#if defined(VK_KHR_surface) +PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; +PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +#endif /* defined(VK_KHR_surface) */ +#if defined(VK_KHR_swapchain) +PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; +PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; +PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; +PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; +PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif /* defined(VK_KHR_swapchain) */ +#if defined(VK_KHR_synchronization2) +PFN_vkCmdPipelineBarrier2KHR vkCmdPipelineBarrier2KHR; +PFN_vkCmdResetEvent2KHR vkCmdResetEvent2KHR; +PFN_vkCmdSetEvent2KHR vkCmdSetEvent2KHR; +PFN_vkCmdWaitEvents2KHR vkCmdWaitEvents2KHR; +PFN_vkCmdWriteTimestamp2KHR vkCmdWriteTimestamp2KHR; +PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR; +#endif /* defined(VK_KHR_synchronization2) */ +#if defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) +PFN_vkCmdWriteBufferMarker2AMD vkCmdWriteBufferMarker2AMD; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_AMD_buffer_marker) */ +#if defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) +PFN_vkGetQueueCheckpointData2NV vkGetQueueCheckpointData2NV; +#endif /* defined(VK_KHR_synchronization2) && defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_KHR_timeline_semaphore) +PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; +PFN_vkSignalSemaphoreKHR vkSignalSemaphoreKHR; +PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +#endif /* defined(VK_KHR_timeline_semaphore) */ +#if defined(VK_KHR_video_decode_queue) +PFN_vkCmdDecodeVideoKHR vkCmdDecodeVideoKHR; +#endif /* defined(VK_KHR_video_decode_queue) */ +#if defined(VK_KHR_video_encode_queue) +PFN_vkCmdEncodeVideoKHR vkCmdEncodeVideoKHR; +PFN_vkGetEncodedVideoSessionParametersKHR vkGetEncodedVideoSessionParametersKHR; +PFN_vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR; +#endif /* defined(VK_KHR_video_encode_queue) */ +#if defined(VK_KHR_video_queue) +PFN_vkBindVideoSessionMemoryKHR vkBindVideoSessionMemoryKHR; +PFN_vkCmdBeginVideoCodingKHR vkCmdBeginVideoCodingKHR; +PFN_vkCmdControlVideoCodingKHR vkCmdControlVideoCodingKHR; +PFN_vkCmdEndVideoCodingKHR vkCmdEndVideoCodingKHR; +PFN_vkCreateVideoSessionKHR vkCreateVideoSessionKHR; +PFN_vkCreateVideoSessionParametersKHR vkCreateVideoSessionParametersKHR; +PFN_vkDestroyVideoSessionKHR vkDestroyVideoSessionKHR; +PFN_vkDestroyVideoSessionParametersKHR vkDestroyVideoSessionParametersKHR; +PFN_vkGetPhysicalDeviceVideoCapabilitiesKHR vkGetPhysicalDeviceVideoCapabilitiesKHR; +PFN_vkGetPhysicalDeviceVideoFormatPropertiesKHR vkGetPhysicalDeviceVideoFormatPropertiesKHR; +PFN_vkGetVideoSessionMemoryRequirementsKHR vkGetVideoSessionMemoryRequirementsKHR; +PFN_vkUpdateVideoSessionParametersKHR vkUpdateVideoSessionParametersKHR; +#endif /* defined(VK_KHR_video_queue) */ +#if defined(VK_KHR_wayland_surface) +PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; +PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif /* defined(VK_KHR_wayland_surface) */ +#if defined(VK_KHR_win32_surface) +PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; +#endif /* defined(VK_KHR_win32_surface) */ +#if defined(VK_KHR_xcb_surface) +PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; +PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; +#endif /* defined(VK_KHR_xcb_surface) */ +#if defined(VK_KHR_xlib_surface) +PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; +PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; +#endif /* defined(VK_KHR_xlib_surface) */ +#if defined(VK_MVK_ios_surface) +PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK; +#endif /* defined(VK_MVK_ios_surface) */ +#if defined(VK_MVK_macos_surface) +PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; +#endif /* defined(VK_MVK_macos_surface) */ +#if defined(VK_NN_vi_surface) +PFN_vkCreateViSurfaceNN vkCreateViSurfaceNN; +#endif /* defined(VK_NN_vi_surface) */ +#if defined(VK_NVX_binary_import) +PFN_vkCmdCuLaunchKernelNVX vkCmdCuLaunchKernelNVX; +PFN_vkCreateCuFunctionNVX vkCreateCuFunctionNVX; +PFN_vkCreateCuModuleNVX vkCreateCuModuleNVX; +PFN_vkDestroyCuFunctionNVX vkDestroyCuFunctionNVX; +PFN_vkDestroyCuModuleNVX vkDestroyCuModuleNVX; +#endif /* defined(VK_NVX_binary_import) */ +#if defined(VK_NVX_image_view_handle) +PFN_vkGetImageViewAddressNVX vkGetImageViewAddressNVX; +PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; +#endif /* defined(VK_NVX_image_view_handle) */ +#if defined(VK_NV_acquire_winrt_display) +PFN_vkAcquireWinrtDisplayNV vkAcquireWinrtDisplayNV; +PFN_vkGetWinrtDisplayNV vkGetWinrtDisplayNV; +#endif /* defined(VK_NV_acquire_winrt_display) */ +#if defined(VK_NV_clip_space_w_scaling) +PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; +#endif /* defined(VK_NV_clip_space_w_scaling) */ +#if defined(VK_NV_cooperative_matrix) +PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; +#endif /* defined(VK_NV_cooperative_matrix) */ +#if defined(VK_NV_copy_memory_indirect) +PFN_vkCmdCopyMemoryIndirectNV vkCmdCopyMemoryIndirectNV; +PFN_vkCmdCopyMemoryToImageIndirectNV vkCmdCopyMemoryToImageIndirectNV; +#endif /* defined(VK_NV_copy_memory_indirect) */ +#if defined(VK_NV_coverage_reduction_mode) +PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV; +#endif /* defined(VK_NV_coverage_reduction_mode) */ +#if defined(VK_NV_cuda_kernel_launch) +PFN_vkCmdCudaLaunchKernelNV vkCmdCudaLaunchKernelNV; +PFN_vkCreateCudaFunctionNV vkCreateCudaFunctionNV; +PFN_vkCreateCudaModuleNV vkCreateCudaModuleNV; +PFN_vkDestroyCudaFunctionNV vkDestroyCudaFunctionNV; +PFN_vkDestroyCudaModuleNV vkDestroyCudaModuleNV; +PFN_vkGetCudaModuleCacheNV vkGetCudaModuleCacheNV; +#endif /* defined(VK_NV_cuda_kernel_launch) */ +#if defined(VK_NV_device_diagnostic_checkpoints) +PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; +PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; +#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ +#if defined(VK_NV_device_generated_commands) +PFN_vkCmdBindPipelineShaderGroupNV vkCmdBindPipelineShaderGroupNV; +PFN_vkCmdExecuteGeneratedCommandsNV vkCmdExecuteGeneratedCommandsNV; +PFN_vkCmdPreprocessGeneratedCommandsNV vkCmdPreprocessGeneratedCommandsNV; +PFN_vkCreateIndirectCommandsLayoutNV vkCreateIndirectCommandsLayoutNV; +PFN_vkDestroyIndirectCommandsLayoutNV vkDestroyIndirectCommandsLayoutNV; +PFN_vkGetGeneratedCommandsMemoryRequirementsNV vkGetGeneratedCommandsMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands) */ +#if defined(VK_NV_device_generated_commands_compute) +PFN_vkCmdUpdatePipelineIndirectBufferNV vkCmdUpdatePipelineIndirectBufferNV; +PFN_vkGetPipelineIndirectDeviceAddressNV vkGetPipelineIndirectDeviceAddressNV; +PFN_vkGetPipelineIndirectMemoryRequirementsNV vkGetPipelineIndirectMemoryRequirementsNV; +#endif /* defined(VK_NV_device_generated_commands_compute) */ +#if defined(VK_NV_external_memory_capabilities) +PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV vkGetPhysicalDeviceExternalImageFormatPropertiesNV; +#endif /* defined(VK_NV_external_memory_capabilities) */ +#if defined(VK_NV_external_memory_rdma) +PFN_vkGetMemoryRemoteAddressNV vkGetMemoryRemoteAddressNV; +#endif /* defined(VK_NV_external_memory_rdma) */ +#if defined(VK_NV_external_memory_win32) +PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; +#endif /* defined(VK_NV_external_memory_win32) */ +#if defined(VK_NV_fragment_shading_rate_enums) +PFN_vkCmdSetFragmentShadingRateEnumNV vkCmdSetFragmentShadingRateEnumNV; +#endif /* defined(VK_NV_fragment_shading_rate_enums) */ +#if defined(VK_NV_low_latency2) +PFN_vkGetLatencyTimingsNV vkGetLatencyTimingsNV; +PFN_vkLatencySleepNV vkLatencySleepNV; +PFN_vkQueueNotifyOutOfBandNV vkQueueNotifyOutOfBandNV; +PFN_vkSetLatencyMarkerNV vkSetLatencyMarkerNV; +PFN_vkSetLatencySleepModeNV vkSetLatencySleepModeNV; +#endif /* defined(VK_NV_low_latency2) */ +#if defined(VK_NV_memory_decompression) +PFN_vkCmdDecompressMemoryIndirectCountNV vkCmdDecompressMemoryIndirectCountNV; +PFN_vkCmdDecompressMemoryNV vkCmdDecompressMemoryNV; +#endif /* defined(VK_NV_memory_decompression) */ +#if defined(VK_NV_mesh_shader) +PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; +PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; +PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; +#endif /* defined(VK_NV_mesh_shader) */ +#if defined(VK_NV_optical_flow) +PFN_vkBindOpticalFlowSessionImageNV vkBindOpticalFlowSessionImageNV; +PFN_vkCmdOpticalFlowExecuteNV vkCmdOpticalFlowExecuteNV; +PFN_vkCreateOpticalFlowSessionNV vkCreateOpticalFlowSessionNV; +PFN_vkDestroyOpticalFlowSessionNV vkDestroyOpticalFlowSessionNV; +PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV vkGetPhysicalDeviceOpticalFlowImageFormatsNV; +#endif /* defined(VK_NV_optical_flow) */ +#if defined(VK_NV_ray_tracing) +PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; +PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; +PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; +PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; +PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; +PFN_vkCompileDeferredNV vkCompileDeferredNV; +PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; +PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; +PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; +PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; +PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; +PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; +#endif /* defined(VK_NV_ray_tracing) */ +#if defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 +PFN_vkCmdSetExclusiveScissorEnableNV vkCmdSetExclusiveScissorEnableNV; +#endif /* defined(VK_NV_scissor_exclusive) && VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION >= 2 */ +#if defined(VK_NV_scissor_exclusive) +PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; +#endif /* defined(VK_NV_scissor_exclusive) */ +#if defined(VK_NV_shading_rate_image) +PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; +PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; +PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; +#endif /* defined(VK_NV_shading_rate_image) */ +#if defined(VK_QCOM_tile_properties) +PFN_vkGetDynamicRenderingTilePropertiesQCOM vkGetDynamicRenderingTilePropertiesQCOM; +PFN_vkGetFramebufferTilePropertiesQCOM vkGetFramebufferTilePropertiesQCOM; +#endif /* defined(VK_QCOM_tile_properties) */ +#if defined(VK_QNX_external_memory_screen_buffer) +PFN_vkGetScreenBufferPropertiesQNX vkGetScreenBufferPropertiesQNX; +#endif /* defined(VK_QNX_external_memory_screen_buffer) */ +#if defined(VK_QNX_screen_surface) +PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX; +PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX; +#endif /* defined(VK_QNX_screen_surface) */ +#if defined(VK_VALVE_descriptor_set_host_mapping) +PFN_vkGetDescriptorSetHostMappingVALVE vkGetDescriptorSetHostMappingVALVE; +PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE vkGetDescriptorSetLayoutHostMappingInfoVALVE; +#endif /* defined(VK_VALVE_descriptor_set_host_mapping) */ +#if (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) +PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; +PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; +PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; +PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; +PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; +PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; +PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; +PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; +PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT; +PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; +PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; +PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) +PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT; +PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT; +PFN_vkCmdSetPatchControlPointsEXT vkCmdSetPatchControlPointsEXT; +PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT; +PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state2)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) +PFN_vkCmdSetAlphaToCoverageEnableEXT vkCmdSetAlphaToCoverageEnableEXT; +PFN_vkCmdSetAlphaToOneEnableEXT vkCmdSetAlphaToOneEnableEXT; +PFN_vkCmdSetColorBlendAdvancedEXT vkCmdSetColorBlendAdvancedEXT; +PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT; +PFN_vkCmdSetColorBlendEquationEXT vkCmdSetColorBlendEquationEXT; +PFN_vkCmdSetColorWriteMaskEXT vkCmdSetColorWriteMaskEXT; +PFN_vkCmdSetConservativeRasterizationModeEXT vkCmdSetConservativeRasterizationModeEXT; +PFN_vkCmdSetDepthClampEnableEXT vkCmdSetDepthClampEnableEXT; +PFN_vkCmdSetDepthClipEnableEXT vkCmdSetDepthClipEnableEXT; +PFN_vkCmdSetDepthClipNegativeOneToOneEXT vkCmdSetDepthClipNegativeOneToOneEXT; +PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT vkCmdSetExtraPrimitiveOverestimationSizeEXT; +PFN_vkCmdSetLineRasterizationModeEXT vkCmdSetLineRasterizationModeEXT; +PFN_vkCmdSetLineStippleEnableEXT vkCmdSetLineStippleEnableEXT; +PFN_vkCmdSetLogicOpEnableEXT vkCmdSetLogicOpEnableEXT; +PFN_vkCmdSetPolygonModeEXT vkCmdSetPolygonModeEXT; +PFN_vkCmdSetProvokingVertexModeEXT vkCmdSetProvokingVertexModeEXT; +PFN_vkCmdSetRasterizationSamplesEXT vkCmdSetRasterizationSamplesEXT; +PFN_vkCmdSetRasterizationStreamEXT vkCmdSetRasterizationStreamEXT; +PFN_vkCmdSetSampleLocationsEnableEXT vkCmdSetSampleLocationsEnableEXT; +PFN_vkCmdSetSampleMaskEXT vkCmdSetSampleMaskEXT; +PFN_vkCmdSetTessellationDomainOriginEXT vkCmdSetTessellationDomainOriginEXT; +#endif /* (defined(VK_EXT_extended_dynamic_state3)) || (defined(VK_EXT_shader_object)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) +PFN_vkCmdSetViewportWScalingEnableNV vkCmdSetViewportWScalingEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_clip_space_w_scaling)) || (defined(VK_EXT_shader_object) && defined(VK_NV_clip_space_w_scaling)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) +PFN_vkCmdSetViewportSwizzleNV vkCmdSetViewportSwizzleNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_viewport_swizzle)) || (defined(VK_EXT_shader_object) && defined(VK_NV_viewport_swizzle)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) +PFN_vkCmdSetCoverageToColorEnableNV vkCmdSetCoverageToColorEnableNV; +PFN_vkCmdSetCoverageToColorLocationNV vkCmdSetCoverageToColorLocationNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_fragment_coverage_to_color)) || (defined(VK_EXT_shader_object) && defined(VK_NV_fragment_coverage_to_color)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) +PFN_vkCmdSetCoverageModulationModeNV vkCmdSetCoverageModulationModeNV; +PFN_vkCmdSetCoverageModulationTableEnableNV vkCmdSetCoverageModulationTableEnableNV; +PFN_vkCmdSetCoverageModulationTableNV vkCmdSetCoverageModulationTableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_framebuffer_mixed_samples)) || (defined(VK_EXT_shader_object) && defined(VK_NV_framebuffer_mixed_samples)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) +PFN_vkCmdSetShadingRateImageEnableNV vkCmdSetShadingRateImageEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_shading_rate_image)) || (defined(VK_EXT_shader_object) && defined(VK_NV_shading_rate_image)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) +PFN_vkCmdSetRepresentativeFragmentTestEnableNV vkCmdSetRepresentativeFragmentTestEnableNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_representative_fragment_test)) || (defined(VK_EXT_shader_object) && defined(VK_NV_representative_fragment_test)) */ +#if (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) +PFN_vkCmdSetCoverageReductionModeNV vkCmdSetCoverageReductionModeNV; +#endif /* (defined(VK_EXT_extended_dynamic_state3) && defined(VK_NV_coverage_reduction_mode)) || (defined(VK_EXT_shader_object) && defined(VK_NV_coverage_reduction_mode)) */ +#if (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) +PFN_vkGetDeviceGroupSurfacePresentModes2EXT vkGetDeviceGroupSurfacePresentModes2EXT; +#endif /* (defined(VK_EXT_full_screen_exclusive) && defined(VK_KHR_device_group)) || (defined(VK_EXT_full_screen_exclusive) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) +PFN_vkGetImageSubresourceLayout2EXT vkGetImageSubresourceLayout2EXT; +#endif /* (defined(VK_EXT_host_image_copy)) || (defined(VK_EXT_image_compression_control)) */ +#if (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) +PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT; +#endif /* (defined(VK_EXT_shader_object)) || (defined(VK_EXT_vertex_input_dynamic_state)) */ +#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) +PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; +#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) || (defined(VK_KHR_push_descriptor) && defined(VK_KHR_descriptor_update_template)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; +PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; +PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) +PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; +#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ +/* VOLK_GENERATE_PROTOTYPES_C */ + +#ifdef __GNUC__ +# pragma GCC visibility pop +#endif + +#ifdef __cplusplus +} +#endif +/* clang-format on */ diff --git a/libraries/ZVulkan/src/vulkanbuilders.cpp b/libraries/ZVulkan/src/vulkanbuilders.cpp new file mode 100644 index 00000000000..be18a86327d --- /dev/null +++ b/libraries/ZVulkan/src/vulkanbuilders.cpp @@ -0,0 +1,2018 @@ +#include "vulkanbuilders.h" +#include "vulkansurface.h" +#include "vulkancompatibledevice.h" +#include "vulkanswapchain.h" +#include "glslang/glslang/Public/ShaderLang.h" +#include "glslang/spirv/GlslangToSpv.h" + +static const TBuiltInResource DefaultTBuiltInResource = { + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 4096, + /* .MaxVaryingFloats = */ 64, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 4096, + /* .MaxDrawBuffers = */ 32, + /* .MaxVertexUniformVectors = */ 128, + /* .MaxVaryingVectors = */ 8, + /* .MaxFragmentUniformVectors = */ 16, + /* .MaxVertexOutputVectors = */ 16, + /* .MaxFragmentInputVectors = */ 15, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 16, + /* .MaxComputeImageUniforms = */ 8, + /* .MaxComputeAtomicCounters = */ 8, + /* .MaxComputeAtomicCounterBuffers = */ 1, + /* .MaxVaryingComponents = */ 60, + /* .MaxVertexOutputComponents = */ 64, + /* .MaxGeometryInputComponents = */ 64, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 8, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, + /* .MaxCombinedShaderOutputResources = */ 8, + /* .MaxImageSamples = */ 0, + /* .MaxVertexImageUniforms = */ 0, + /* .MaxTessControlImageUniforms = */ 0, + /* .MaxTessEvaluationImageUniforms = */ 0, + /* .MaxGeometryImageUniforms = */ 0, + /* .MaxFragmentImageUniforms = */ 8, + /* .MaxCombinedImageUniforms = */ 8, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 0, + /* .MaxTessControlAtomicCounters = */ 0, + /* .MaxTessEvaluationAtomicCounters = */ 0, + /* .MaxGeometryAtomicCounters = */ 0, + /* .MaxFragmentAtomicCounters = */ 8, + /* .MaxCombinedAtomicCounters = */ 8, + /* .MaxAtomicCounterBindings = */ 1, + /* .MaxVertexAtomicCounterBuffers = */ 0, + /* .MaxTessControlAtomicCounterBuffers = */ 0, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, + /* .MaxGeometryAtomicCounterBuffers = */ 0, + /* .MaxFragmentAtomicCounterBuffers = */ 1, + /* .MaxCombinedAtomicCounterBuffers = */ 1, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 4, + /* .maxMeshOutputVerticesNV = */ 256, + /* .maxMeshOutputPrimitivesNV = */ 512, + /* .maxMeshWorkGroupSizeX_NV = */ 32, + /* .maxMeshWorkGroupSizeY_NV = */ 1, + /* .maxMeshWorkGroupSizeZ_NV = */ 1, + /* .maxTaskWorkGroupSizeX_NV = */ 32, + /* .maxTaskWorkGroupSizeY_NV = */ 1, + /* .maxTaskWorkGroupSizeZ_NV = */ 1, + /* .maxMeshViewCountNV = */ 4, + /* .maxDualSourceDrawBuffersEXT = */ 1, + + /* .limits = */ { + /* .nonInductiveForLoops = */ 1, + /* .whileLoops = */ 1, + /* .doWhileLoops = */ 1, + /* .generalUniformIndexing = */ 1, + /* .generalAttributeMatrixVectorIndexing = */ 1, + /* .generalVaryingIndexing = */ 1, + /* .generalSamplerIndexing = */ 1, + /* .generalVariableIndexing = */ 1, + /* .generalConstantMatrixVectorIndexing = */ 1, + } +}; + +void ShaderBuilder::Init() +{ + ShInitialize(); +} + +void ShaderBuilder::Deinit() +{ + ShFinalize(); +} + +ShaderBuilder::ShaderBuilder() +{ +} + +ShaderBuilder& ShaderBuilder::Type(ShaderType type) +{ + switch (type) + { + case ShaderType::Vertex: stage = EShLanguage::EShLangVertex; break; + case ShaderType::TessControl: stage = EShLanguage::EShLangTessControl; break; + case ShaderType::TessEvaluation: stage = EShLanguage::EShLangTessEvaluation; break; + case ShaderType::Geometry: stage = EShLanguage::EShLangGeometry; break; + case ShaderType::Fragment: stage = EShLanguage::EShLangFragment; break; + case ShaderType::Compute: stage = EShLanguage::EShLangCompute; break; + } + return *this; +} + +ShaderBuilder& ShaderBuilder::AddSource(const std::string& name, const std::string& code) +{ + sources.push_back({ name, code }); + return *this; +} + +ShaderBuilder& ShaderBuilder::OnIncludeSystem(std::function onIncludeSystem) +{ + this->onIncludeSystem = std::move(onIncludeSystem); + return *this; +} + +ShaderBuilder& ShaderBuilder::OnIncludeLocal(std::function onIncludeLocal) +{ + this->onIncludeLocal = std::move(onIncludeLocal); + return *this; +} + +class ShaderBuilderIncluderImpl : public glslang::TShader::Includer +{ +public: + ShaderBuilderIncluderImpl(ShaderBuilder* shaderBuilder) : shaderBuilder(shaderBuilder) + { + } + + IncludeResult* includeSystem(const char* headerName, const char* includerName, size_t inclusionDepth) override + { + if (!shaderBuilder->onIncludeSystem) + { + return nullptr; + } + + try + { + std::unique_ptr result; + try + { + result = std::make_unique(shaderBuilder->onIncludeSystem(headerName, includerName, inclusionDepth)); + } + catch (const std::exception& e) + { + result = std::make_unique(e.what()); + } + + if (!result || (result->name.empty() && result->text.empty())) + { + return nullptr; + } + + IncludeResult* outer = new IncludeResult(result->name, result->text.data(), result->text.size(), result.get()); + result.release(); + return outer; + } + catch (...) + { + return nullptr; + } + } + + IncludeResult* includeLocal(const char* headerName, const char* includerName, size_t inclusionDepth) override + { + if (!shaderBuilder->onIncludeLocal) + { + return nullptr; + } + + try + { + std::unique_ptr result; + try + { + result = std::make_unique(shaderBuilder->onIncludeLocal(headerName, includerName, inclusionDepth)); + } + catch (const std::exception& e) + { + result = std::make_unique(e.what()); + } + + if (!result || (result->name.empty() && result->text.empty())) + { + return nullptr; + } + + IncludeResult* outer = new IncludeResult(result->name, result->text.data(), result->text.size(), result.get()); + result.release(); + return outer; + } + catch (...) + { + return nullptr; + } + } + + void releaseInclude(IncludeResult* result) override + { + if (result) + { + delete (ShaderIncludeResult*)result->userData; + delete result; + } + } + +private: + ShaderBuilder* shaderBuilder = nullptr; +}; + +std::unique_ptr ShaderBuilder::Create(const char *shadername, VulkanDevice *device) +{ + EShLanguage stage = (EShLanguage)this->stage; + + std::vector namesC, sourcesC; + std::vector lengthsC; + for (const auto& s : sources) + { + namesC.push_back(s.first.c_str()); + sourcesC.push_back(s.second.c_str()); + lengthsC.push_back((int)s.second.size()); + } + + TBuiltInResource resources = DefaultTBuiltInResource; + + glslang::TShader shader(stage); + shader.setStringsWithLengthsAndNames(sourcesC.data(), lengthsC.data(), namesC.data(), (int)sources.size()); + shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100); + if (device->Instance->ApiVersion >= VK_API_VERSION_1_2) + { + shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2); + shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4); + } + else + { + shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); + shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); + } + + ShaderBuilderIncluderImpl includer(this); + bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules, includer); + if (!compileSuccess) + { + VulkanError((std::string("Shader compile failed: ") + shader.getInfoLog()).c_str()); + } + + glslang::TProgram program; + program.addShader(&shader); + bool linkSuccess = program.link(EShMsgDefault); + if (!linkSuccess) + { + VulkanError((std::string("Shader link failed: ") + program.getInfoLog()).c_str()); + } + + glslang::TIntermediate *intermediate = program.getIntermediate(stage); + if (!intermediate) + { + VulkanError("Internal shader compiler error"); + } + + glslang::SpvOptions spvOptions; + spvOptions.generateDebugInfo = false; + spvOptions.disableOptimizer = false; + spvOptions.optimizeSize = true; + + std::vector spirv; + spv::SpvBuildLogger logger; + glslang::GlslangToSpv(*intermediate, spirv, &logger, &spvOptions); + + VkShaderModuleCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = spirv.size() * sizeof(unsigned int); + createInfo.pCode = spirv.data(); + + VkShaderModule shaderModule; + VkResult result = vkCreateShaderModule(device->device, &createInfo, nullptr, &shaderModule); + if (result != VK_SUCCESS) + VulkanError("Could not create vulkan shader module"); + + auto obj = std::make_unique(device, shaderModule); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +CommandPoolBuilder::CommandPoolBuilder() +{ +} + +CommandPoolBuilder& CommandPoolBuilder::QueueFamily(int index) +{ + queueFamilyIndex = index; + return *this; +} + +std::unique_ptr CommandPoolBuilder::Create(VulkanDevice* device) +{ + auto obj = std::make_unique(device, queueFamilyIndex != -1 ? queueFamilyIndex : device->GraphicsFamily); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +SemaphoreBuilder::SemaphoreBuilder() +{ +} + +std::unique_ptr SemaphoreBuilder::Create(VulkanDevice* device) +{ + auto obj = std::make_unique(device); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +FenceBuilder::FenceBuilder() +{ +} + +std::unique_ptr FenceBuilder::Create(VulkanDevice* device) +{ + auto obj = std::make_unique(device); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +ImageBuilder::ImageBuilder() +{ + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.depth = 1; + imageInfo.arrayLayers = 1; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Note: must either be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.flags = 0; +} + +ImageBuilder& ImageBuilder::Size(int width, int height, int mipLevels, int arrayLayers) +{ + imageInfo.extent.width = width; + imageInfo.extent.height = height; + imageInfo.mipLevels = mipLevels; + imageInfo.arrayLayers = arrayLayers; + return *this; +} + +ImageBuilder& ImageBuilder::Samples(VkSampleCountFlagBits samples) +{ + imageInfo.samples = samples; + return *this; +} + +ImageBuilder& ImageBuilder::Format(VkFormat format) +{ + imageInfo.format = format; + return *this; +} + +ImageBuilder& ImageBuilder::LinearTiling() +{ + imageInfo.tiling = VK_IMAGE_TILING_LINEAR; + return *this; +} + +ImageBuilder& ImageBuilder::Usage(VkImageUsageFlags usage, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocFlags) +{ + imageInfo.usage = usage; + allocInfo.usage = memoryUsage; + allocInfo.flags = allocFlags; + return *this; +} + +ImageBuilder& ImageBuilder::MemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits) +{ + allocInfo.requiredFlags = requiredFlags; + allocInfo.preferredFlags = preferredFlags; + allocInfo.memoryTypeBits = memoryTypeBits; + return *this; +} + +bool ImageBuilder::IsFormatSupported(VulkanDevice* device, VkFormatFeatureFlags bufferFeatures) +{ + VkImageFormatProperties properties = { }; + VkResult result = vkGetPhysicalDeviceImageFormatProperties(device->PhysicalDevice.Device, imageInfo.format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage, imageInfo.flags, &properties); + if (result != VK_SUCCESS) return false; + if (imageInfo.extent.width > properties.maxExtent.width) return false; + if (imageInfo.extent.height > properties.maxExtent.height) return false; + if (imageInfo.extent.depth > properties.maxExtent.depth) return false; + if (imageInfo.mipLevels > properties.maxMipLevels) return false; + if (imageInfo.arrayLayers > properties.maxArrayLayers) return false; + if ((imageInfo.samples & properties.sampleCounts) != imageInfo.samples) return false; + if (bufferFeatures != 0) + { + VkFormatProperties formatProperties = { }; + vkGetPhysicalDeviceFormatProperties(device->PhysicalDevice.Device, imageInfo.format, &formatProperties); + if ((formatProperties.bufferFeatures & bufferFeatures) != bufferFeatures) + return false; + } + return true; +} + +std::unique_ptr ImageBuilder::Create(VulkanDevice* device, VkDeviceSize* allocatedBytes) +{ + VkImage image; + VmaAllocation allocation; + + VkResult result = vmaCreateImage(device->allocator, &imageInfo, &allocInfo, &image, &allocation, nullptr); + CheckVulkanError(result, "Could not create vulkan image"); + + if (allocatedBytes != nullptr) + { + VmaAllocationInfo allocatedInfo; + vmaGetAllocationInfo(device->allocator, allocation, &allocatedInfo); + + *allocatedBytes = allocatedInfo.size; + } + + auto obj = std::make_unique(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels, imageInfo.arrayLayers); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +std::unique_ptr ImageBuilder::TryCreate(VulkanDevice* device) +{ + VkImage image; + VmaAllocation allocation; + + VkResult result = vmaCreateImage(device->allocator, &imageInfo, &allocInfo, &image, &allocation, nullptr); + if (result != VK_SUCCESS) + return nullptr; + + auto obj = std::make_unique(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels, imageInfo.arrayLayers); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +ImageViewBuilder::ImageViewBuilder() +{ + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; +} + +ImageViewBuilder& ImageViewBuilder::Type(VkImageViewType type) +{ + viewInfo.viewType = type; + return *this; +} + +ImageViewBuilder& ImageViewBuilder::Image(VulkanImage* image, VkFormat format, VkImageAspectFlags aspectMask, int mipLevel, int arrayLayer, int levelCount, int layerCount) +{ + viewInfo.image = image->image; + viewInfo.format = format; + viewInfo.subresourceRange.levelCount = levelCount == 0 ? image->mipLevels : levelCount; + viewInfo.subresourceRange.aspectMask = aspectMask; + viewInfo.subresourceRange.layerCount = layerCount == 0 ? image->layerCount : layerCount; + viewInfo.subresourceRange.baseMipLevel = mipLevel; + viewInfo.subresourceRange.baseArrayLayer = arrayLayer; + return *this; +} + +std::unique_ptr ImageViewBuilder::Create(VulkanDevice* device) +{ + VkImageView view; + VkResult result = vkCreateImageView(device->device, &viewInfo, nullptr, &view); + CheckVulkanError(result, "Could not create texture image view"); + + auto obj = std::make_unique(device, view); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +SamplerBuilder::SamplerBuilder() +{ + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.maxAnisotropy = 1.0f; + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 100.0f; +} + +SamplerBuilder& SamplerBuilder::AddressMode(VkSamplerAddressMode addressMode) +{ + samplerInfo.addressModeU = addressMode; + samplerInfo.addressModeV = addressMode; + samplerInfo.addressModeW = addressMode; + return *this; +} + +SamplerBuilder& SamplerBuilder::AddressMode(VkSamplerAddressMode u, VkSamplerAddressMode v, VkSamplerAddressMode w) +{ + samplerInfo.addressModeU = u; + samplerInfo.addressModeV = v; + samplerInfo.addressModeW = w; + return *this; +} + +SamplerBuilder& SamplerBuilder::MinFilter(VkFilter minFilter) +{ + samplerInfo.minFilter = minFilter; + return *this; +} + +SamplerBuilder& SamplerBuilder::MagFilter(VkFilter magFilter) +{ + samplerInfo.magFilter = magFilter; + return *this; +} + +SamplerBuilder& SamplerBuilder::MipmapMode(VkSamplerMipmapMode mode) +{ + samplerInfo.mipmapMode = mode; + return *this; +} + +SamplerBuilder& SamplerBuilder::Anisotropy(float maxAnisotropy) +{ + samplerInfo.anisotropyEnable = VK_TRUE; + samplerInfo.maxAnisotropy = maxAnisotropy; + return *this; +} + +SamplerBuilder& SamplerBuilder::MipLodBias(float bias) +{ + samplerInfo.mipLodBias = bias; + return *this; +} + +SamplerBuilder& SamplerBuilder::MaxLod(float value) +{ + samplerInfo.maxLod = value; + return *this; +} + +std::unique_ptr SamplerBuilder::Create(VulkanDevice* device) +{ + VkSampler sampler; + VkResult result = vkCreateSampler(device->device, &samplerInfo, nullptr, &sampler); + CheckVulkanError(result, "Could not create texture sampler"); + auto obj = std::make_unique(device, sampler); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +BufferBuilder::BufferBuilder() +{ + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; +} + +BufferBuilder& BufferBuilder::Size(size_t size) +{ + bufferInfo.size = std::max(size, (size_t)16); + return *this; +} + +BufferBuilder& BufferBuilder::Usage(VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocFlags) +{ + bufferInfo.usage = bufferUsage; + allocInfo.usage = memoryUsage; + allocInfo.flags = allocFlags; + return *this; +} + +BufferBuilder& BufferBuilder::MemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits) +{ + allocInfo.requiredFlags = requiredFlags; + allocInfo.preferredFlags = preferredFlags; + allocInfo.memoryTypeBits = memoryTypeBits; + return *this; +} + +BufferBuilder& BufferBuilder::MinAlignment(VkDeviceSize memoryAlignment) +{ + minAlignment = memoryAlignment; + return *this; +} + +std::unique_ptr BufferBuilder::Create(VulkanDevice* device) +{ + VkBuffer buffer; + VmaAllocation allocation; + + if (minAlignment == 0) + { + VkResult result = vmaCreateBuffer(device->allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); + CheckVulkanError(result, "Could not allocate memory for vulkan buffer"); + } + else + { + VkResult result = vmaCreateBufferWithAlignment(device->allocator, &bufferInfo, &allocInfo, minAlignment, &buffer, &allocation, nullptr); + CheckVulkanError(result, "Could not allocate memory for vulkan buffer"); + } + + auto obj = std::make_unique(device, buffer, allocation, bufferInfo.size); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +AccelerationStructureBuilder::AccelerationStructureBuilder() +{ +} + +AccelerationStructureBuilder& AccelerationStructureBuilder::Type(VkAccelerationStructureTypeKHR type) +{ + createInfo.type = type; + return *this; +} + +AccelerationStructureBuilder& AccelerationStructureBuilder::Buffer(VulkanBuffer* buffer, VkDeviceSize size) +{ + createInfo.buffer = buffer->buffer; + createInfo.offset = 0; + createInfo.size = size; + return *this; +} + +AccelerationStructureBuilder& AccelerationStructureBuilder::Buffer(VulkanBuffer* buffer, VkDeviceSize offset, VkDeviceSize size) +{ + createInfo.buffer = buffer->buffer; + createInfo.offset = offset; + createInfo.size = size; + return *this; +} + +std::unique_ptr AccelerationStructureBuilder::Create(VulkanDevice* device) +{ + VkAccelerationStructureKHR hande = {}; + VkResult result = vkCreateAccelerationStructureKHR(device->device, &createInfo, nullptr, &hande); + if (result != VK_SUCCESS) + VulkanError("vkCreateAccelerationStructureKHR failed"); + auto obj = std::make_unique(device, hande); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +ComputePipelineBuilder::ComputePipelineBuilder() +{ + pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; +} + +ComputePipelineBuilder& ComputePipelineBuilder::Cache(VulkanPipelineCache* cache) +{ + this->cache = cache; + return *this; +} + +ComputePipelineBuilder& ComputePipelineBuilder::Layout(VulkanPipelineLayout* layout) +{ + pipelineInfo.layout = layout->layout; + return *this; +} + +ComputePipelineBuilder& ComputePipelineBuilder::ComputeShader(VulkanShader* shader) +{ + stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; + stageInfo.module = shader->module; + stageInfo.pName = "main"; + + pipelineInfo.stage = stageInfo; + return *this; +} + +std::unique_ptr ComputePipelineBuilder::Create(VulkanDevice* device) +{ + VkPipeline pipeline; + vkCreateComputePipelines(device->device, cache ? cache->cache : VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline); + auto obj = std::make_unique(device, pipeline); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder() +{ +} + +DescriptorSetLayoutBuilder& DescriptorSetLayoutBuilder::Flags(VkDescriptorSetLayoutCreateFlags flags) +{ + layoutInfo.flags = flags; + return *this; +} + +DescriptorSetLayoutBuilder& DescriptorSetLayoutBuilder::AddBinding(int index, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags, VkDescriptorBindingFlags flags) +{ + VkDescriptorSetLayoutBinding binding = { }; + binding.binding = index; + binding.descriptorType = type; + binding.descriptorCount = arrayCount; + binding.stageFlags = stageFlags; + binding.pImmutableSamplers = nullptr; + bindings.push_back(binding); + bindingFlags.push_back(flags); + + layoutInfo.bindingCount = (uint32_t)bindings.size(); + layoutInfo.pBindings = bindings.data(); + + bindingFlagsInfo.bindingCount = (uint32_t)bindings.size(); + bindingFlagsInfo.pBindingFlags = bindingFlags.data(); + + if (flags != 0) + layoutInfo.pNext = &bindingFlagsInfo; + + return *this; +} + +std::unique_ptr DescriptorSetLayoutBuilder::Create(VulkanDevice* device) +{ + VkDescriptorSetLayout layout; + VkResult result = vkCreateDescriptorSetLayout(device->device, &layoutInfo, nullptr, &layout); + CheckVulkanError(result, "Could not create descriptor set layout"); + auto obj = std::make_unique(device, layout); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +DescriptorPoolBuilder::DescriptorPoolBuilder() +{ + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.maxSets = 1; + poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; +} + +DescriptorPoolBuilder& DescriptorPoolBuilder::Flags(VkDescriptorPoolCreateFlags flags) +{ + poolInfo.flags = flags | VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + return *this; +} + +DescriptorPoolBuilder& DescriptorPoolBuilder::MaxSets(int value) +{ + poolInfo.maxSets = value; + return *this; +} + +DescriptorPoolBuilder& DescriptorPoolBuilder::AddPoolSize(VkDescriptorType type, int count) +{ + VkDescriptorPoolSize size; + size.type = type; + size.descriptorCount = count; + poolSizes.push_back(size); + + poolInfo.poolSizeCount = (uint32_t)poolSizes.size(); + poolInfo.pPoolSizes = poolSizes.data(); + return *this; +} + +std::unique_ptr DescriptorPoolBuilder::Create(VulkanDevice* device) +{ + VkDescriptorPool descriptorPool; + VkResult result = vkCreateDescriptorPool(device->device, &poolInfo, nullptr, &descriptorPool); + CheckVulkanError(result, "Could not create descriptor pool"); + auto obj = std::make_unique(device, descriptorPool); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +QueryPoolBuilder::QueryPoolBuilder() +{ + poolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; +} + +QueryPoolBuilder& QueryPoolBuilder::QueryType(VkQueryType type, int count, VkQueryPipelineStatisticFlags pipelineStatistics) +{ + poolInfo.queryType = type; + poolInfo.queryCount = count; + poolInfo.pipelineStatistics = pipelineStatistics; + return *this; +} + +std::unique_ptr QueryPoolBuilder::Create(VulkanDevice* device) +{ + VkQueryPool queryPool; + VkResult result = vkCreateQueryPool(device->device, &poolInfo, nullptr, &queryPool); + CheckVulkanError(result, "Could not create query pool"); + auto obj = std::make_unique(device, queryPool); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +FramebufferBuilder::FramebufferBuilder() +{ + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; +} + +FramebufferBuilder& FramebufferBuilder::RenderPass(VulkanRenderPass* renderPass) +{ + framebufferInfo.renderPass = renderPass->renderPass; + return *this; +} + +FramebufferBuilder& FramebufferBuilder::AddAttachment(VulkanImageView* view) +{ + attachments.push_back(view->view); + + framebufferInfo.attachmentCount = (uint32_t)attachments.size(); + framebufferInfo.pAttachments = attachments.data(); + return *this; +} + +FramebufferBuilder& FramebufferBuilder::AddAttachment(VkImageView view) +{ + attachments.push_back(view); + + framebufferInfo.attachmentCount = (uint32_t)attachments.size(); + framebufferInfo.pAttachments = attachments.data(); + return *this; +} + +FramebufferBuilder& FramebufferBuilder::Size(int width, int height, int layers) +{ + framebufferInfo.width = width; + framebufferInfo.height = height; + framebufferInfo.layers = 1; + return *this; +} + +std::unique_ptr FramebufferBuilder::Create(VulkanDevice* device) +{ + VkFramebuffer framebuffer = 0; + VkResult result = vkCreateFramebuffer(device->device, &framebufferInfo, nullptr, &framebuffer); + CheckVulkanError(result, "Could not create framebuffer"); + auto obj = std::make_unique(device, framebuffer); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + + +ColorBlendAttachmentBuilder::ColorBlendAttachmentBuilder() +{ + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.blendEnable = VK_FALSE; + colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; +} + +ColorBlendAttachmentBuilder& ColorBlendAttachmentBuilder::ColorWriteMask(VkColorComponentFlags mask) +{ + colorBlendAttachment.colorWriteMask = mask; + return *this; +} + +ColorBlendAttachmentBuilder& ColorBlendAttachmentBuilder::AdditiveBlendMode() +{ + colorBlendAttachment.blendEnable = VK_TRUE; + colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + return *this; +} + +ColorBlendAttachmentBuilder& ColorBlendAttachmentBuilder::AlphaBlendMode() +{ + colorBlendAttachment.blendEnable = VK_TRUE; + colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + return *this; +} + +ColorBlendAttachmentBuilder& ColorBlendAttachmentBuilder::BlendMode(VkBlendOp op, VkBlendFactor src, VkBlendFactor dst) +{ + colorBlendAttachment.blendEnable = VK_TRUE; + colorBlendAttachment.srcColorBlendFactor = src; + colorBlendAttachment.dstColorBlendFactor = dst; + colorBlendAttachment.colorBlendOp = op; + colorBlendAttachment.srcAlphaBlendFactor = src; + colorBlendAttachment.dstAlphaBlendFactor = dst; + colorBlendAttachment.alphaBlendOp = op; + return *this; +} + +///////////////////////////////////////////////////////////////////////////// + +GraphicsPipelineBuilder::GraphicsPipelineBuilder() +{ + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pDepthStencilState = &depthStencil; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.subpass = 0; + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + pipelineInfo.basePipelineIndex = -1; + + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 0; + vertexInputInfo.pVertexBindingDescriptions = nullptr; + vertexInputInfo.vertexAttributeDescriptionCount = 0; + vertexInputInfo.pVertexAttributeDescriptions = nullptr; + + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.minDepthBounds = 0.0f; + depthStencil.maxDepthBounds = 1.0f; + depthStencil.stencilTestEnable = VK_FALSE; + depthStencil.front = {}; + depthStencil.back = {}; + + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.logicOp = VK_LOGIC_OP_COPY; + colorBlending.blendConstants[0] = 0.0f; + colorBlending.blendConstants[1] = 0.0f; + colorBlending.blendConstants[2] = 0.0f; + colorBlending.blendConstants[3] = 0.0f; + + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::RasterizationSamples(VkSampleCountFlagBits samples) +{ + multisampling.rasterizationSamples = samples; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::Cache(VulkanPipelineCache* cache) +{ + this->cache = cache; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::Subpass(int subpass) +{ + pipelineInfo.subpass = subpass; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::Layout(VulkanPipelineLayout* layout) +{ + pipelineInfo.layout = layout->layout; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::RenderPass(VulkanRenderPass* renderPass) +{ + pipelineInfo.renderPass = renderPass->renderPass; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::Topology(VkPrimitiveTopology topology) +{ + inputAssembly.topology = topology; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::Viewport(float x, float y, float width, float height, float minDepth, float maxDepth) +{ + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = width; + viewport.height = height; + viewport.minDepth = minDepth; + viewport.maxDepth = maxDepth; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::Scissor(int x, int y, int width, int height) +{ + scissor.offset.x = x; + scissor.offset.y = y; + scissor.extent.width = width; + scissor.extent.height = height; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::Cull(VkCullModeFlags cullMode, VkFrontFace frontFace) +{ + rasterizer.cullMode = cullMode; + rasterizer.frontFace = frontFace; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::DepthStencilEnable(bool test, bool write, bool stencil) +{ + depthStencil.depthTestEnable = test ? VK_TRUE : VK_FALSE; + depthStencil.depthWriteEnable = write ? VK_TRUE : VK_FALSE; + depthStencil.stencilTestEnable = stencil ? VK_TRUE : VK_FALSE; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::Stencil(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp, uint32_t compareMask, uint32_t writeMask, uint32_t reference) +{ + depthStencil.front.failOp = failOp; + depthStencil.front.passOp = passOp; + depthStencil.front.depthFailOp = depthFailOp; + depthStencil.front.compareOp = compareOp; + depthStencil.front.compareMask = compareMask; + depthStencil.front.writeMask = writeMask; + depthStencil.front.reference = reference; + + depthStencil.back.failOp = failOp; + depthStencil.back.passOp = passOp; + depthStencil.back.depthFailOp = depthFailOp; + depthStencil.back.compareOp = compareOp; + depthStencil.back.compareMask = compareMask; + depthStencil.back.writeMask = writeMask; + depthStencil.back.reference = reference; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::DepthFunc(VkCompareOp func) +{ + depthStencil.depthCompareOp = func; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::DepthClampEnable(bool value) +{ + rasterizer.depthClampEnable = value ? VK_TRUE : VK_FALSE; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::DepthBias(bool enable, float biasConstantFactor, float biasClamp, float biasSlopeFactor) +{ + rasterizer.depthBiasEnable = enable ? VK_TRUE : VK_FALSE; + rasterizer.depthBiasConstantFactor = biasConstantFactor; + rasterizer.depthBiasClamp = biasClamp; + rasterizer.depthBiasSlopeFactor = biasSlopeFactor; + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddColorBlendAttachment(VkPipelineColorBlendAttachmentState state) +{ + colorBlendAttachments.push_back(state); + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddVertexShader(VulkanShader* shader) +{ + VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = shader->module; + vertShaderStageInfo.pName = "main"; + shaderStages.push_back(vertShaderStageInfo); + + pipelineInfo.stageCount = (uint32_t)shaderStages.size(); + pipelineInfo.pStages = shaderStages.data(); + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddFragmentShader(VulkanShader* shader) +{ + VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; + fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragShaderStageInfo.module = shader->module; + fragShaderStageInfo.pName = "main"; + shaderStages.push_back(fragShaderStageInfo); + + pipelineInfo.stageCount = (uint32_t)shaderStages.size(); + pipelineInfo.pStages = shaderStages.data(); + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddVertexBufferBinding(int index, size_t stride) +{ + VkVertexInputBindingDescription desc = {}; + desc.binding = index; + desc.stride = (uint32_t)stride; + desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + vertexInputBindings.push_back(desc); + + vertexInputInfo.vertexBindingDescriptionCount = (uint32_t)vertexInputBindings.size(); + vertexInputInfo.pVertexBindingDescriptions = vertexInputBindings.data(); + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddVertexAttribute(int location, int binding, VkFormat format, size_t offset) +{ + VkVertexInputAttributeDescription desc = { }; + desc.location = location; + desc.binding = binding; + desc.format = format; + desc.offset = (uint32_t)offset; + vertexInputAttributes.push_back(desc); + + vertexInputInfo.vertexAttributeDescriptionCount = (uint32_t)vertexInputAttributes.size(); + vertexInputInfo.pVertexAttributeDescriptions = vertexInputAttributes.data(); + return *this; +} + +GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddDynamicState(VkDynamicState state) +{ + dynamicStates.push_back(state); + dynamicState.dynamicStateCount = (uint32_t)dynamicStates.size(); + dynamicState.pDynamicStates = dynamicStates.data(); + return *this; +} + +std::unique_ptr GraphicsPipelineBuilder::Create(VulkanDevice* device) +{ + if (colorBlendAttachments.empty()) + colorBlendAttachments.push_back(ColorBlendAttachmentBuilder().Create()); + colorBlending.pAttachments = colorBlendAttachments.data(); + colorBlending.attachmentCount = (uint32_t)colorBlendAttachments.size(); + + VkPipeline pipeline = 0; + VkResult result = vkCreateGraphicsPipelines(device->device, cache ? cache->cache : VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline); + CheckVulkanError(result, "Could not create graphics pipeline"); + auto obj = std::make_unique(device, pipeline); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +PipelineLayoutBuilder::PipelineLayoutBuilder() +{ + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; +} + +PipelineLayoutBuilder& PipelineLayoutBuilder::AddSetLayout(VulkanDescriptorSetLayout* setLayout) +{ + setLayouts.push_back(setLayout->layout); + pipelineLayoutInfo.setLayoutCount = (uint32_t)setLayouts.size(); + pipelineLayoutInfo.pSetLayouts = setLayouts.data(); + return *this; +} + +PipelineLayoutBuilder& PipelineLayoutBuilder::AddPushConstantRange(VkShaderStageFlags stageFlags, size_t offset, size_t size) +{ + VkPushConstantRange range = { }; + range.stageFlags = stageFlags; + range.offset = (uint32_t)offset; + range.size = (uint32_t)size; + pushConstantRanges.push_back(range); + pipelineLayoutInfo.pushConstantRangeCount = (uint32_t)pushConstantRanges.size(); + pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data(); + return *this; +} + +std::unique_ptr PipelineLayoutBuilder::Create(VulkanDevice* device) +{ + VkPipelineLayout pipelineLayout; + VkResult result = vkCreatePipelineLayout(device->device, &pipelineLayoutInfo, nullptr, &pipelineLayout); + CheckVulkanError(result, "Could not create pipeline layout"); + auto obj = std::make_unique(device, pipelineLayout); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +PipelineCacheBuilder::PipelineCacheBuilder() +{ + pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; +} + +PipelineCacheBuilder& PipelineCacheBuilder::InitialData(const void* data, size_t size) +{ + initData.resize(size); + memcpy(initData.data(), data, size); + return *this; +} + +PipelineCacheBuilder& PipelineCacheBuilder::Flags(VkPipelineCacheCreateFlags flags) +{ + pipelineCacheInfo.flags = flags; + return *this; +} + +std::unique_ptr PipelineCacheBuilder::Create(VulkanDevice* device) +{ + pipelineCacheInfo.pInitialData = nullptr; + pipelineCacheInfo.initialDataSize = 0; + + // Check if the saved cache data is compatible with our device: + if (initData.size() >= sizeof(VkPipelineCacheHeaderVersionOne)) + { + VkPipelineCacheHeaderVersionOne* header = (VkPipelineCacheHeaderVersionOne*)initData.data(); + if (header->headerVersion == VK_PIPELINE_CACHE_HEADER_VERSION_ONE && + header->vendorID == device->PhysicalDevice.Properties.Properties.vendorID && + header->deviceID == device->PhysicalDevice.Properties.Properties.deviceID && + memcmp(header->pipelineCacheUUID, device->PhysicalDevice.Properties.Properties.pipelineCacheUUID, VK_UUID_SIZE) == 0) + { + pipelineCacheInfo.pInitialData = initData.data(); + pipelineCacheInfo.initialDataSize = initData.size(); + } + } + + VkPipelineCache pipelineCache; + VkResult result = vkCreatePipelineCache(device->device, &pipelineCacheInfo, nullptr, &pipelineCache); + CheckVulkanError(result, "Could not create pipeline cache"); + auto obj = std::make_unique(device, pipelineCache); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +RenderPassBuilder::RenderPassBuilder() +{ + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; +} + +RenderPassBuilder& RenderPassBuilder::AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkImageLayout initialLayout, VkImageLayout finalLayout) +{ + VkAttachmentDescription attachment = {}; + attachment.format = format; + attachment.samples = samples; + attachment.loadOp = load; + attachment.storeOp = store; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = initialLayout; + attachment.finalLayout = finalLayout; + attachments.push_back(attachment); + renderPassInfo.pAttachments = attachments.data(); + renderPassInfo.attachmentCount = (uint32_t)attachments.size(); + return *this; +} + +RenderPassBuilder& RenderPassBuilder::AddDepthStencilAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkAttachmentLoadOp stencilLoad, VkAttachmentStoreOp stencilStore, VkImageLayout initialLayout, VkImageLayout finalLayout) +{ + VkAttachmentDescription attachment = {}; + attachment.format = format; + attachment.samples = samples; + attachment.loadOp = load; + attachment.storeOp = store; + attachment.stencilLoadOp = stencilLoad; + attachment.stencilStoreOp = stencilStore; + attachment.initialLayout = initialLayout; + attachment.finalLayout = finalLayout; + attachments.push_back(attachment); + renderPassInfo.pAttachments = attachments.data(); + renderPassInfo.attachmentCount = (uint32_t)attachments.size(); + return *this; +} + +RenderPassBuilder& RenderPassBuilder::AddExternalSubpassDependency(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) +{ + VkSubpassDependency dependency = {}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = srcStageMask; + dependency.srcAccessMask = srcAccessMask; + dependency.dstStageMask = dstStageMask; + dependency.dstAccessMask = dstAccessMask; + + dependencies.push_back(dependency); + renderPassInfo.pDependencies = dependencies.data(); + renderPassInfo.dependencyCount = (uint32_t)dependencies.size(); + return *this; +} + +RenderPassBuilder& RenderPassBuilder::AddSubpass() +{ + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + + subpasses.push_back(subpass); + renderPassInfo.pSubpasses = subpasses.data(); + renderPassInfo.subpassCount = (uint32_t)subpasses.size(); + + subpassData.push_back(std::make_unique()); + return *this; +} + +RenderPassBuilder& RenderPassBuilder::AddSubpassColorAttachmentRef(uint32_t index, VkImageLayout layout) +{ + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.attachment = index; + colorAttachmentRef.layout = layout; + + subpassData.back()->colorRefs.push_back(colorAttachmentRef); + subpasses.back().pColorAttachments = subpassData.back()->colorRefs.data(); + subpasses.back().colorAttachmentCount = (uint32_t)subpassData.back()->colorRefs.size(); + return *this; +} + +RenderPassBuilder& RenderPassBuilder::AddSubpassDepthStencilAttachmentRef(uint32_t index, VkImageLayout layout) +{ + VkAttachmentReference& depthAttachmentRef = subpassData.back()->depthRef; + depthAttachmentRef.attachment = index; + depthAttachmentRef.layout = layout; + + VkSubpassDescription& subpass = subpasses.back(); + subpass.pDepthStencilAttachment = &depthAttachmentRef; + return *this; +} + +std::unique_ptr RenderPassBuilder::Create(VulkanDevice* device) +{ + VkRenderPass renderPass = 0; + VkResult result = vkCreateRenderPass(device->device, &renderPassInfo, nullptr, &renderPass); + CheckVulkanError(result, "Could not create render pass"); + auto obj = std::make_unique(device, renderPass); + if (debugName) + obj->SetDebugName(debugName); + return obj; +} + +///////////////////////////////////////////////////////////////////////////// + +PipelineBarrier& PipelineBarrier::AddMemory(VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) +{ + VkMemoryBarrier barrier = { }; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + barrier.srcAccessMask = srcAccessMask; + barrier.dstAccessMask = dstAccessMask; + memoryBarriers.push_back(barrier); + return *this; +} + +PipelineBarrier& PipelineBarrier::AddBuffer(VulkanBuffer* buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) +{ + return AddBuffer(buffer, 0, buffer->size, srcAccessMask, dstAccessMask); +} + +PipelineBarrier& PipelineBarrier::AddBuffer(VulkanBuffer* buffer, VkDeviceSize offset, VkDeviceSize size, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) +{ + VkBufferMemoryBarrier barrier = { }; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + barrier.srcAccessMask = srcAccessMask; + barrier.dstAccessMask = dstAccessMask; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.buffer = buffer->buffer; + barrier.offset = offset; + barrier.size = size; + bufferMemoryBarriers.push_back(barrier); + return *this; +} + +PipelineBarrier& PipelineBarrier::AddImage(VulkanImage* image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount, int baseArrayLayer, int layerCount) +{ + return AddImage(image->image, oldLayout, newLayout, srcAccessMask, dstAccessMask, aspectMask, baseMipLevel, levelCount, baseArrayLayer, layerCount); +} + +PipelineBarrier& PipelineBarrier::AddImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount, int baseArrayLayer, int layerCount) +{ + VkImageMemoryBarrier barrier = { }; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.srcAccessMask = srcAccessMask; + barrier.dstAccessMask = dstAccessMask; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange.aspectMask = aspectMask; + barrier.subresourceRange.baseMipLevel = baseMipLevel; + barrier.subresourceRange.levelCount = levelCount; + barrier.subresourceRange.baseArrayLayer = baseArrayLayer; + barrier.subresourceRange.layerCount = layerCount; + imageMemoryBarriers.push_back(barrier); + return *this; +} + +PipelineBarrier& PipelineBarrier::AddQueueTransfer(int srcFamily, int dstFamily, VulkanBuffer* buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) +{ + VkBufferMemoryBarrier barrier = { }; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + barrier.srcAccessMask = srcAccessMask; + barrier.dstAccessMask = dstAccessMask; + barrier.srcQueueFamilyIndex = srcFamily; + barrier.dstQueueFamilyIndex = dstFamily; + barrier.buffer = buffer->buffer; + barrier.offset = 0; + barrier.size = buffer->size; + bufferMemoryBarriers.push_back(barrier); + return *this; +} + +PipelineBarrier& PipelineBarrier::AddQueueTransfer(int srcFamily, int dstFamily, VulkanImage* image, VkImageLayout layout, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount) +{ + VkImageMemoryBarrier barrier = { }; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = layout; + barrier.newLayout = layout; + barrier.srcQueueFamilyIndex = srcFamily; + barrier.dstQueueFamilyIndex = dstFamily; + barrier.image = image->image; + barrier.subresourceRange.aspectMask = aspectMask; + barrier.subresourceRange.baseMipLevel = baseMipLevel; + barrier.subresourceRange.levelCount = levelCount; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + imageMemoryBarriers.push_back(barrier); + return *this; +} + +void PipelineBarrier::Execute(VulkanCommandBuffer* commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags) +{ + commandBuffer->pipelineBarrier( + srcStageMask, dstStageMask, dependencyFlags, + (uint32_t)memoryBarriers.size(), memoryBarriers.data(), + (uint32_t)bufferMemoryBarriers.size(), bufferMemoryBarriers.data(), + (uint32_t)imageMemoryBarriers.size(), imageMemoryBarriers.data()); +} + +///////////////////////////////////////////////////////////////////////////// + +QueueSubmit::QueueSubmit() +{ + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; +} + +QueueSubmit& QueueSubmit::AddCommandBuffer(VulkanCommandBuffer* buffer) +{ + commandBuffers.push_back(buffer->buffer); + submitInfo.pCommandBuffers = commandBuffers.data(); + submitInfo.commandBufferCount = (uint32_t)commandBuffers.size(); + return *this; +} + +QueueSubmit& QueueSubmit::AddWait(VkPipelineStageFlags waitStageMask, VulkanSemaphore* semaphore) +{ + waitStages.push_back(waitStageMask); + waitSemaphores.push_back(semaphore->semaphore); + + submitInfo.pWaitDstStageMask = waitStages.data(); + submitInfo.pWaitSemaphores = waitSemaphores.data(); + submitInfo.waitSemaphoreCount = (uint32_t)waitSemaphores.size(); + return *this; +} + +QueueSubmit& QueueSubmit::AddSignal(VulkanSemaphore* semaphore) +{ + signalSemaphores.push_back(semaphore->semaphore); + submitInfo.pSignalSemaphores = signalSemaphores.data(); + submitInfo.signalSemaphoreCount = (uint32_t)signalSemaphores.size(); + return *this; +} + +void QueueSubmit::Execute(VulkanDevice* device, VkQueue queue, VulkanFence* fence) +{ + VkResult result = vkQueueSubmit(device->GraphicsQueue, 1, &submitInfo, fence ? fence->fence : VK_NULL_HANDLE); + CheckVulkanError(result, "Could not submit command buffer"); +} + +///////////////////////////////////////////////////////////////////////////// + +WriteDescriptors& WriteDescriptors::AddBuffer(VulkanDescriptorSet* descriptorSet, int binding, VkDescriptorType type, VulkanBuffer* buffer) +{ + return AddBuffer(descriptorSet, binding, type, buffer, 0, buffer->size); +} + +WriteDescriptors& WriteDescriptors::AddBuffer(VulkanDescriptorSet* descriptorSet, int binding, VkDescriptorType type, VulkanBuffer* buffer, size_t offset, size_t range) +{ + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.buffer = buffer->buffer; + bufferInfo.offset = offset; + bufferInfo.range = range; + + auto extra = std::make_unique(); + extra->bufferInfo = bufferInfo; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet->set; + descriptorWrite.dstBinding = binding; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = type; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &extra->bufferInfo; + writes.push_back(descriptorWrite); + writeExtras.push_back(std::move(extra)); + return *this; +} + +WriteDescriptors& WriteDescriptors::AddStorageImage(VulkanDescriptorSet* descriptorSet, int binding, VulkanImageView* view, VkImageLayout imageLayout) +{ + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageView = view->view; + imageInfo.imageLayout = imageLayout; + + auto extra = std::make_unique(); + extra->imageInfo = imageInfo; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet->set; + descriptorWrite.dstBinding = binding; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pImageInfo = &extra->imageInfo; + writes.push_back(descriptorWrite); + writeExtras.push_back(std::move(extra)); + return *this; +} + +WriteDescriptors& WriteDescriptors::AddCombinedImageSampler(VulkanDescriptorSet* descriptorSet, int binding, VulkanImageView* view, VulkanSampler* sampler, VkImageLayout imageLayout) +{ + return AddCombinedImageSampler(descriptorSet, binding, 0, view, sampler, imageLayout); +} + +WriteDescriptors& WriteDescriptors::AddCombinedImageSampler(VulkanDescriptorSet* descriptorSet, int binding, int arrayIndex, VulkanImageView* view, VulkanSampler* sampler, VkImageLayout imageLayout) +{ + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageView = view->view; + imageInfo.sampler = sampler->sampler; + imageInfo.imageLayout = imageLayout; + + auto extra = std::make_unique(); + extra->imageInfo = imageInfo; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet->set; + descriptorWrite.dstBinding = binding; + descriptorWrite.dstArrayElement = arrayIndex; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pImageInfo = &extra->imageInfo; + writes.push_back(descriptorWrite); + writeExtras.push_back(std::move(extra)); + return *this; +} + +WriteDescriptors& WriteDescriptors::AddAccelerationStructure(VulkanDescriptorSet* descriptorSet, int binding, VulkanAccelerationStructure* accelStruct) +{ + auto extra = std::make_unique(); + extra->accelStruct = {}; + extra->accelStruct.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + extra->accelStruct.accelerationStructureCount = 1; + extra->accelStruct.pAccelerationStructures = &accelStruct->accelstruct; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet->set; + descriptorWrite.dstBinding = binding; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pNext = &extra->accelStruct; + writes.push_back(descriptorWrite); + writeExtras.push_back(std::move(extra)); + return *this; +} + +void WriteDescriptors::Execute(VulkanDevice* device) +{ + if (!writes.empty()) + vkUpdateDescriptorSets(device->device, (uint32_t)writes.size(), writes.data(), 0, nullptr); +} + +///////////////////////////////////////////////////////////////////////////// + +VulkanInstanceBuilder::VulkanInstanceBuilder() +{ + apiVersionsToTry = { VK_API_VERSION_1_2, VK_API_VERSION_1_1, VK_API_VERSION_1_0 }; + + OptionalExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME); + OptionalExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); +} + +VulkanInstanceBuilder& VulkanInstanceBuilder::ApiVersionsToTry(const std::vector& versions) +{ + apiVersionsToTry = versions; + return *this; +} + +VulkanInstanceBuilder& VulkanInstanceBuilder::RequireExtension(const std::string& extensionName) +{ + requiredExtensions.insert(extensionName); + return *this; +} + +VulkanInstanceBuilder& VulkanInstanceBuilder::RequireSurfaceExtensions(bool enable) +{ + if (enable) + { + RequireExtension(VK_KHR_SURFACE_EXTENSION_NAME); + +#if defined(VK_USE_PLATFORM_WIN32_KHR) + RequireExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_MACOS_MVK) + RequireExtension(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_XLIB_KHR) + RequireExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); +#endif + + OptionalExtension(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); // For HDR support + } + return *this; +} + +VulkanInstanceBuilder& VulkanInstanceBuilder::OptionalExtension(const std::string& extensionName) +{ + optionalExtensions.insert(extensionName); + return *this; +} + +VulkanInstanceBuilder& VulkanInstanceBuilder::DebugLayer(bool enable) +{ + debugLayer = enable; + return *this; +} + +std::shared_ptr VulkanInstanceBuilder::Create() +{ + return std::make_shared(apiVersionsToTry, requiredExtensions, optionalExtensions, debugLayer); +} + +///////////////////////////////////////////////////////////////////////////// + +#ifdef VK_USE_PLATFORM_WIN32_KHR + +VulkanSurfaceBuilder::VulkanSurfaceBuilder() +{ +} + +VulkanSurfaceBuilder& VulkanSurfaceBuilder::Win32Window(HWND hwnd) +{ + this->hwnd = hwnd; + return *this; +} + +std::shared_ptr VulkanSurfaceBuilder::Create(std::shared_ptr instance) +{ + return std::make_shared(std::move(instance), hwnd); +} + +#endif + +///////////////////////////////////////////////////////////////////////////// + +VulkanDeviceBuilder::VulkanDeviceBuilder() +{ + OptionalExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + OptionalExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); +} + +VulkanDeviceBuilder& VulkanDeviceBuilder::RequireExtension(const std::string& extensionName) +{ + requiredDeviceExtensions.insert(extensionName); + return *this; +} + +VulkanDeviceBuilder& VulkanDeviceBuilder::OptionalExtension(const std::string& extensionName) +{ + optionalDeviceExtensions.insert(extensionName); + return *this; +} + +VulkanDeviceBuilder& VulkanDeviceBuilder::OptionalRayQuery() +{ + OptionalExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); + OptionalExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); + OptionalExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); + OptionalExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME); + return *this; +} + +VulkanDeviceBuilder& VulkanDeviceBuilder::OptionalDescriptorIndexing() +{ + OptionalExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); + return *this; +} + +VulkanDeviceBuilder& VulkanDeviceBuilder::Surface(std::shared_ptr surface) +{ + if (surface) + { + RequireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); +#if defined(VK_USE_PLATFORM_WIN32_KHR) + OptionalExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME); +#endif + } + this->surface = std::move(surface); + return *this; +} + +VulkanDeviceBuilder& VulkanDeviceBuilder::SelectDevice(int index) +{ + deviceIndex = index; + return *this; +} + +std::vector VulkanDeviceBuilder::FindDevices(const std::shared_ptr& instance) +{ + std::vector supportedDevices; + + for (size_t idx = 0; idx < instance->PhysicalDevices.size(); idx++) + { + const auto& info = instance->PhysicalDevices[idx]; + + // Check if all required extensions are there + std::set requiredExtensionSearch = requiredDeviceExtensions; + for (const auto& ext : info.Extensions) + requiredExtensionSearch.erase(ext.extensionName); + if (!requiredExtensionSearch.empty()) + continue; + + // Check if all required features are there + if (info.Features.Features.samplerAnisotropy != VK_TRUE || + info.Features.Features.fragmentStoresAndAtomics != VK_TRUE || + info.Features.Features.multiDrawIndirect != VK_TRUE || + info.Features.Features.independentBlend != VK_TRUE) + continue; + + VulkanCompatibleDevice dev; + dev.Device = &instance->PhysicalDevices[idx]; + dev.EnabledDeviceExtensions = requiredDeviceExtensions; + + // Enable optional extensions we are interested in, if they are available on this device + for (const auto& ext : dev.Device->Extensions) + { + if (optionalDeviceExtensions.find(ext.extensionName) != optionalDeviceExtensions.end()) + { + dev.EnabledDeviceExtensions.insert(ext.extensionName); + } + } + + // Enable optional features we are interested in, if they are available on this device + auto& enabledFeatures = dev.EnabledFeatures; + auto& deviceFeatures = dev.Device->Features; + enabledFeatures.Features.samplerAnisotropy = deviceFeatures.Features.samplerAnisotropy; + enabledFeatures.Features.fragmentStoresAndAtomics = deviceFeatures.Features.fragmentStoresAndAtomics; + enabledFeatures.Features.depthClamp = deviceFeatures.Features.depthClamp; + enabledFeatures.Features.shaderClipDistance = deviceFeatures.Features.shaderClipDistance; + enabledFeatures.Features.multiDrawIndirect = deviceFeatures.Features.multiDrawIndirect; + enabledFeatures.Features.independentBlend = deviceFeatures.Features.independentBlend; + enabledFeatures.BufferDeviceAddress.bufferDeviceAddress = deviceFeatures.BufferDeviceAddress.bufferDeviceAddress; + enabledFeatures.AccelerationStructure.accelerationStructure = deviceFeatures.AccelerationStructure.accelerationStructure; + enabledFeatures.RayQuery.rayQuery = deviceFeatures.RayQuery.rayQuery; + enabledFeatures.DescriptorIndexing.runtimeDescriptorArray = deviceFeatures.DescriptorIndexing.runtimeDescriptorArray; + enabledFeatures.DescriptorIndexing.descriptorBindingPartiallyBound = deviceFeatures.DescriptorIndexing.descriptorBindingPartiallyBound; + enabledFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind = deviceFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind; + enabledFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount = deviceFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount; + enabledFeatures.DescriptorIndexing.shaderSampledImageArrayNonUniformIndexing = deviceFeatures.DescriptorIndexing.shaderSampledImageArrayNonUniformIndexing; + + // Figure out which queue can present + if (surface) + { + for (int i = 0; i < (int)info.QueueFamilies.size(); i++) + { + VkBool32 presentSupport = false; + VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(info.Device, i, surface->Surface, &presentSupport); + if (result == VK_SUCCESS && info.QueueFamilies[i].queueCount > 0 && presentSupport) + { + dev.PresentFamily = i; + break; + } + } + } + + // The vulkan spec states that graphics and compute queues can always do transfer. + // Furthermore the spec states that graphics queues always can do compute. + // Last, the spec makes it OPTIONAL whether the VK_QUEUE_TRANSFER_BIT is set for such queues, but they MUST support transfer. + // + // In short: pick the first graphics queue family for everything. + for (int i = 0; i < (int)info.QueueFamilies.size(); i++) + { + const auto& queueFamily = info.QueueFamilies[i]; + if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)) + { + dev.GraphicsFamily = i; + dev.GraphicsTimeQueries = queueFamily.timestampValidBits != 0; + break; + } + } + + // Only use device if we found the required graphics and present queues + if (dev.GraphicsFamily != -1 && (!surface || dev.PresentFamily != -1)) + { + supportedDevices.push_back(dev); + } + } + + // The device order returned by Vulkan can be anything. Prefer discrete > integrated > virtual gpu > cpu > other + auto sortFunc = [&](const auto& a, const auto b) + { + // Sort by GPU type first. This will ensure the "best" device is most likely to map to vk_device 0 + static const int typeSort[] = { 4, 1, 0, 2, 3 }; + int sortA = a.Device->Properties.Properties.deviceType < 5 ? typeSort[a.Device->Properties.Properties.deviceType] : (int)a.Device->Properties.Properties.deviceType; + int sortB = b.Device->Properties.Properties.deviceType < 5 ? typeSort[b.Device->Properties.Properties.deviceType] : (int)b.Device->Properties.Properties.deviceType; + if (sortA != sortB) + return sortA < sortB; + + // Any driver that is emulating vulkan (i.e. via Direct3D 12) should only be chosen as the last option within each GPU type + sortA = a.Device->Properties.LayeredDriver.underlyingAPI; + sortB = b.Device->Properties.LayeredDriver.underlyingAPI; + if (sortA != sortB) + return sortA < sortB; + + // Then sort by the device's unique ID so that vk_device uses a consistent order + int sortUUID = memcmp(a.Device->Properties.Properties.pipelineCacheUUID, b.Device->Properties.Properties.pipelineCacheUUID, VK_UUID_SIZE); + return sortUUID < 0; + }; + std::stable_sort(supportedDevices.begin(), supportedDevices.end(), sortFunc); + + return supportedDevices; +} + +std::shared_ptr VulkanDeviceBuilder::Create(std::shared_ptr instance) +{ + if (instance->PhysicalDevices.empty()) + VulkanError("No Vulkan devices found. The graphics card may have no vulkan support or the driver may be too old."); + + std::vector supportedDevices = FindDevices(instance); + if (supportedDevices.empty()) + VulkanError("No Vulkan device found supports the minimum requirements of this application"); + + size_t selected = deviceIndex; + if (selected >= supportedDevices.size()) + selected = 0; + return std::make_shared(instance, surface, supportedDevices[selected]); +} + +///////////////////////////////////////////////////////////////////////////// + +VulkanSwapChainBuilder::VulkanSwapChainBuilder() +{ +} + +std::shared_ptr VulkanSwapChainBuilder::Create(VulkanDevice* device) +{ + return std::make_shared(device); +} + +///////////////////////////////////////////////////////////////////////////// + +BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, size_t offset, const void* data, size_t size) +{ + bufferCopies.push_back({ buffer, offset, data, size, nullptr, 0 }); + return *this; +} + +BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, const void* data, size_t size) +{ + bufferCopies.push_back({ buffer, 0, data, size, nullptr, 0 }); + return *this; +} + +BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, const void* data0, size_t size0, const void* data1, size_t size1) +{ + bufferCopies.push_back({ buffer, 0, data0, size0, data1, size1 }); + return *this; +} + +std::unique_ptr BufferTransfer::Execute(VulkanDevice* device, VulkanCommandBuffer* cmdbuffer) +{ + size_t transferbuffersize = 0; + for (const auto& copy : bufferCopies) + transferbuffersize += copy.size0 + copy.size1; + + if (transferbuffersize == 0) + return nullptr; + + auto transferBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .Size(transferbuffersize) + .DebugName("BufferTransfer.transferBuffer") + .Create(device); + + uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize); + size_t pos = 0; + for (const auto& copy : bufferCopies) + { + memcpy(data + pos, copy.data0, copy.size0); + pos += copy.size0; + memcpy(data + pos, copy.data1, copy.size1); + pos += copy.size1; + } + transferBuffer->Unmap(); + + pos = 0; + for (const auto& copy : bufferCopies) + { + if (copy.size0 > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), copy.buffer, pos, copy.offset, copy.size0); + pos += copy.size0; + + if (copy.size1 > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), copy.buffer, pos, copy.offset + copy.size0, copy.size1); + pos += copy.size1; + } + + return transferBuffer; +} diff --git a/libraries/ZVulkan/src/vulkandevice.cpp b/libraries/ZVulkan/src/vulkandevice.cpp new file mode 100644 index 00000000000..0adfff5c219 --- /dev/null +++ b/libraries/ZVulkan/src/vulkandevice.cpp @@ -0,0 +1,161 @@ + +#include "vulkandevice.h" +#include "vulkanobjects.h" +#include "vulkancompatibledevice.h" +#include +#include +#include + +VulkanDevice::VulkanDevice(std::shared_ptr instance, std::shared_ptr surface, const VulkanCompatibleDevice& selectedDevice) : Instance(instance), Surface(surface) +{ + PhysicalDevice = *selectedDevice.Device; + EnabledDeviceExtensions = selectedDevice.EnabledDeviceExtensions; + EnabledFeatures = selectedDevice.EnabledFeatures; + + GraphicsFamily = selectedDevice.GraphicsFamily; + PresentFamily = selectedDevice.PresentFamily; + GraphicsTimeQueries = selectedDevice.GraphicsTimeQueries; + + try + { + CreateDevice(); + CreateAllocator(); + } + catch (...) + { + ReleaseResources(); + throw; + } +} + +VulkanDevice::~VulkanDevice() +{ + ReleaseResources(); +} + +bool VulkanDevice::SupportsExtension(const char* ext) const +{ + return + EnabledDeviceExtensions.find(ext) != EnabledDeviceExtensions.end() || + Instance->EnabledExtensions.find(ext) != Instance->EnabledExtensions.end(); +} + +void VulkanDevice::CreateAllocator() +{ + VmaAllocatorCreateInfo allocinfo = {}; + allocinfo.vulkanApiVersion = Instance->ApiVersion; + if (SupportsExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) && SupportsExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) + allocinfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; + if (SupportsExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) + allocinfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; + allocinfo.physicalDevice = PhysicalDevice.Device; + allocinfo.device = device; + allocinfo.instance = Instance->Instance; + allocinfo.preferredLargeHeapBlockSize = 64 * 1024 * 1024; + if (vmaCreateAllocator(&allocinfo, &allocator) != VK_SUCCESS) + VulkanError("Unable to create allocator"); +} + +void VulkanDevice::CreateDevice() +{ + float queuePriority = 1.0f; + std::vector queueCreateInfos; + + std::set neededFamilies; + if (GraphicsFamily != -1) + neededFamilies.insert(GraphicsFamily); + if (PresentFamily != -1) + neededFamilies.insert(PresentFamily); + + for (int index : neededFamilies) + { + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = index; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &queuePriority; + queueCreateInfos.push_back(queueCreateInfo); + } + + std::vector extensionNames; + extensionNames.reserve(EnabledDeviceExtensions.size()); + for (const auto& name : EnabledDeviceExtensions) + extensionNames.push_back(name.c_str()); + + VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; + deviceCreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size(); + deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data(); + deviceCreateInfo.enabledExtensionCount = (uint32_t)extensionNames.size(); + deviceCreateInfo.ppEnabledExtensionNames = extensionNames.data(); + deviceCreateInfo.enabledLayerCount = 0; + + VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + deviceFeatures2.features = EnabledFeatures.Features; + + void** next = const_cast(&deviceCreateInfo.pNext); + if (SupportsExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) + { + *next = &deviceFeatures2; + next = &deviceFeatures2.pNext; + } + else // vulkan 1.0 specified features in a different way + { + deviceCreateInfo.pEnabledFeatures = &deviceFeatures2.features; + } + + if (SupportsExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) + { + *next = &EnabledFeatures.BufferDeviceAddress; + next = &EnabledFeatures.BufferDeviceAddress.pNext; + } + if (SupportsExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME)) + { + *next = &EnabledFeatures.AccelerationStructure; + next = &EnabledFeatures.AccelerationStructure.pNext; + } + if (SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) + { + *next = &EnabledFeatures.RayQuery; + next = &EnabledFeatures.RayQuery.pNext; + } + if (SupportsExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)) + { + *next = &EnabledFeatures.DescriptorIndexing; + next = &EnabledFeatures.DescriptorIndexing.pNext; + } + + VkResult result = vkCreateDevice(PhysicalDevice.Device, &deviceCreateInfo, nullptr, &device); + CheckVulkanError(result, "Could not create vulkan device"); + + volkLoadDevice(device); + + if (GraphicsFamily != -1) + vkGetDeviceQueue(device, GraphicsFamily, 0, &GraphicsQueue); + if (PresentFamily != -1) + vkGetDeviceQueue(device, PresentFamily, 0, &PresentQueue); +} + +void VulkanDevice::ReleaseResources() +{ + if (device) + vkDeviceWaitIdle(device); + + if (allocator) + vmaDestroyAllocator(allocator); + + if (device) + vkDestroyDevice(device, nullptr); + device = nullptr; +} + +void VulkanDevice::SetObjectName(const char* name, uint64_t handle, VkObjectType type) +{ + if (!DebugLayerActive) return; + + VkDebugUtilsObjectNameInfoEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + info.objectHandle = handle; + info.objectType = type; + info.pObjectName = name; + vkSetDebugUtilsObjectNameEXT(device, &info); +} diff --git a/libraries/ZVulkan/src/vulkaninstance.cpp b/libraries/ZVulkan/src/vulkaninstance.cpp new file mode 100644 index 00000000000..0641d3987eb --- /dev/null +++ b/libraries/ZVulkan/src/vulkaninstance.cpp @@ -0,0 +1,412 @@ + +#include "vulkaninstance.h" +#include "vulkanbuilders.h" +#include +#include +#include +#include + +VulkanInstance::VulkanInstance(std::vector apiVersionsToTry, std::set requiredExtensions, std::set optionalExtensions, bool wantDebugLayer) + : ApiVersionsToTry(std::move(apiVersionsToTry)), RequiredExtensions(std::move(requiredExtensions)), OptionalExtensions(std::move(optionalExtensions)), WantDebugLayer(wantDebugLayer) +{ + try + { + ShaderBuilder::Init(); + InitVolk(); + CreateInstance(); + } + catch (...) + { + ReleaseResources(); + throw; + } +} + +VulkanInstance::~VulkanInstance() +{ + ReleaseResources(); +} + +void VulkanInstance::ReleaseResources() +{ + if (debugMessenger) + vkDestroyDebugUtilsMessengerEXT(Instance, debugMessenger, nullptr); + debugMessenger = VK_NULL_HANDLE; + + if (Instance) + vkDestroyInstance(Instance, nullptr); + Instance = nullptr; +} + +void VulkanInstance::InitVolk() +{ + if (volkInitialize() != VK_SUCCESS) + { + VulkanError("Unable to find Vulkan"); + } + auto iver = volkGetInstanceVersion(); + if (iver == 0) + { + VulkanError("Vulkan not supported"); + } +} + +void VulkanInstance::CreateInstance() +{ + AvailableLayers = GetAvailableLayers(); + AvailableExtensions = GetExtensions(); + EnabledExtensions = RequiredExtensions; + + std::string debugLayer = "VK_LAYER_KHRONOS_validation"; + bool debugLayerFound = false; + if (WantDebugLayer) + { + for (const VkLayerProperties& layer : AvailableLayers) + { + if (layer.layerName == debugLayer) + { + EnabledValidationLayers.insert(layer.layerName); + EnabledExtensions.insert(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + debugLayerFound = true; + break; + } + } + } + + // Enable optional instance extensions we are interested in + for (const auto& ext : AvailableExtensions) + { + if (OptionalExtensions.find(ext.extensionName) != OptionalExtensions.end()) + { + EnabledExtensions.insert(ext.extensionName); + } + } + + std::vector enabledValidationLayersCStr; + for (const std::string& layer : EnabledValidationLayers) + enabledValidationLayersCStr.push_back(layer.c_str()); + + std::vector enabledExtensionsCStr; + for (const std::string& ext : EnabledExtensions) + enabledExtensionsCStr.push_back(ext.c_str()); + + // Try get the highest vulkan version we can get + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + for (uint32_t apiVersion : ApiVersionsToTry) + { + VkApplicationInfo appInfo = {}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "VulkanDrv"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "VulkanDrv"; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = apiVersion; + + VkInstanceCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; + createInfo.enabledExtensionCount = (uint32_t)EnabledExtensions.size(); + createInfo.enabledLayerCount = (uint32_t)enabledValidationLayersCStr.size(); + createInfo.ppEnabledLayerNames = enabledValidationLayersCStr.data(); + createInfo.ppEnabledExtensionNames = enabledExtensionsCStr.data(); + + result = vkCreateInstance(&createInfo, nullptr, &Instance); + if (result >= VK_SUCCESS) + { + ApiVersion = apiVersion; + break; + } + } + CheckVulkanError(result, "Could not create vulkan instance"); + + volkLoadInstance(Instance); + + if (debugLayerFound) + { + VkDebugUtilsMessengerCreateInfoEXT dbgCreateInfo = {}; + dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + dbgCreateInfo.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + dbgCreateInfo.messageType = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + dbgCreateInfo.pfnUserCallback = DebugCallback; + dbgCreateInfo.pUserData = this; + result = vkCreateDebugUtilsMessengerEXT(Instance, &dbgCreateInfo, nullptr, &debugMessenger); + CheckVulkanError(result, "vkCreateDebugUtilsMessengerEXT failed"); + + DebugLayerActive = true; + } + + PhysicalDevices = GetPhysicalDevices(Instance, ApiVersion); +} + +std::vector VulkanInstance::GetPhysicalDevices(VkInstance instance, uint32_t apiVersion) +{ + uint32_t deviceCount = 0; + VkResult result = vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); + if (result == VK_ERROR_INITIALIZATION_FAILED) // Some drivers return this when a card does not support vulkan + return {}; + CheckVulkanError(result, "vkEnumeratePhysicalDevices failed"); + if (deviceCount == 0) + return {}; + + std::vector devices(deviceCount); + result = vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); + CheckVulkanError(result, "vkEnumeratePhysicalDevices failed (2)"); + + std::vector devinfo(deviceCount); + for (size_t i = 0; i < devices.size(); i++) + { + auto& dev = devinfo[i]; + dev.Device = devices[i]; + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(dev.Device, &queueFamilyCount, nullptr); + dev.QueueFamilies.resize(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(dev.Device, &queueFamilyCount, dev.QueueFamilies.data()); + + uint32_t deviceExtensionCount = 0; + vkEnumerateDeviceExtensionProperties(dev.Device, nullptr, &deviceExtensionCount, nullptr); + dev.Extensions.resize(deviceExtensionCount); + vkEnumerateDeviceExtensionProperties(dev.Device, nullptr, &deviceExtensionCount, dev.Extensions.data()); + + auto checkForExtension = [&](const char* name) + { + for (const auto& ext : dev.Extensions) + { + if (strcmp(ext.extensionName, name) == 0) + return true; + } + return false; + }; + + vkGetPhysicalDeviceMemoryProperties(dev.Device, &dev.Properties.Memory); + + if (apiVersion != VK_API_VERSION_1_0) + { + VkPhysicalDeviceProperties2 deviceProperties2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 }; + + void** next = const_cast(&deviceProperties2.pNext); + if (checkForExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME)) + { + *next = &dev.Properties.AccelerationStructure; + next = &dev.Properties.AccelerationStructure.pNext; + } + if (checkForExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)) + { + *next = &dev.Properties.DescriptorIndexing; + next = &dev.Properties.DescriptorIndexing.pNext; + } + if (checkForExtension(VK_MSFT_LAYERED_DRIVER_EXTENSION_NAME)) + { + *next = &dev.Properties.LayeredDriver; + next = &dev.Properties.LayeredDriver.pNext; + } + + vkGetPhysicalDeviceProperties2(dev.Device, &deviceProperties2); + dev.Properties.Properties = deviceProperties2.properties; + dev.Properties.AccelerationStructure.pNext = nullptr; + dev.Properties.DescriptorIndexing.pNext = nullptr; + dev.Properties.LayeredDriver.pNext = nullptr; + + VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + + next = const_cast(&deviceFeatures2.pNext); + if (checkForExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) + { + *next = &dev.Features.BufferDeviceAddress; + next = &dev.Features.BufferDeviceAddress.pNext; + } + if (checkForExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME)) + { + *next = &dev.Features.AccelerationStructure; + next = &dev.Features.AccelerationStructure.pNext; + } + if (checkForExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) + { + *next = &dev.Features.RayQuery; + next = &dev.Features.RayQuery.pNext; + } + if (checkForExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)) + { + *next = &dev.Features.DescriptorIndexing; + next = &dev.Features.DescriptorIndexing.pNext; + } + + vkGetPhysicalDeviceFeatures2(dev.Device, &deviceFeatures2); + dev.Features.Features = deviceFeatures2.features; + dev.Features.BufferDeviceAddress.pNext = nullptr; + dev.Features.AccelerationStructure.pNext = nullptr; + dev.Features.RayQuery.pNext = nullptr; + dev.Features.DescriptorIndexing.pNext = nullptr; + } + else + { + vkGetPhysicalDeviceProperties(dev.Device, &dev.Properties.Properties); + vkGetPhysicalDeviceFeatures(dev.Device, &dev.Features.Features); + } + } + return devinfo; +} + +std::vector VulkanInstance::GetAvailableLayers() +{ + uint32_t layerCount; + VkResult result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr); + + std::vector availableLayers(layerCount); + result = vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); + return availableLayers; +} + +std::vector VulkanInstance::GetExtensions() +{ + uint32_t extensionCount = 0; + VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); + + std::vector extensions(extensionCount); + result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); + return extensions; +} + +VkBool32 VulkanInstance::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData) +{ + VulkanInstance* instance = (VulkanInstance*)userData; + + static std::mutex mtx; + static std::set seenMessages; + static int totalMessages; + + std::unique_lock lock(mtx); + + std::string msg = callbackData->pMessage; + + // Attempt to parse the string because the default formatting is totally unreadable and half of what it writes is totally useless! + auto parts = SplitString(msg, " | "); + if (parts.size() == 3) + { + msg = parts[2]; + size_t pos = msg.find(" The Vulkan spec states:"); + if (pos != std::string::npos) + msg = msg.substr(0, pos); + + if (callbackData->objectCount > 0) + { + msg += " ("; + for (uint32_t i = 0; i < callbackData->objectCount; i++) + { + if (i > 0) + msg += ", "; + if (callbackData->pObjects[i].pObjectName) + msg += callbackData->pObjects[i].pObjectName; + else + msg += ""; + } + msg += ")"; + } + } + + bool found = seenMessages.find(msg) != seenMessages.end(); + if (!found) + { + if (totalMessages < 20) + { + totalMessages++; + seenMessages.insert(msg); + + const char* typestr; + bool showcallstack = false; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + { + typestr = "vulkan error"; + showcallstack = true; + } + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) + { + typestr = "vulkan warning"; + } + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) + { + typestr = "vulkan info"; + } + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) + { + typestr = "vulkan verbose"; + } + else + { + typestr = "vulkan"; + } + + VulkanPrintLog(typestr, msg); + } + } + + return VK_FALSE; +} + +std::vector VulkanInstance::SplitString(const std::string& s, const std::string& seperator) +{ + std::vector output; + std::string::size_type prev_pos = 0, pos = 0; + + while ((pos = s.find(seperator, pos)) != std::string::npos) + { + std::string substring(s.substr(prev_pos, pos - prev_pos)); + + output.push_back(substring); + + pos += seperator.length(); + prev_pos = pos; + } + + output.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word + return output; +} + +std::string VkResultToString(VkResult result) +{ + switch (result) + { + case VK_SUCCESS: return "success"; + case VK_NOT_READY: return "not ready"; + case VK_TIMEOUT: return "timeout"; + case VK_EVENT_SET: return "event set"; + case VK_EVENT_RESET: return "event reset"; + case VK_INCOMPLETE: return "incomplete"; + case VK_ERROR_OUT_OF_HOST_MEMORY: return "out of host memory"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "out of device memory"; + case VK_ERROR_INITIALIZATION_FAILED: return "initialization failed"; + case VK_ERROR_DEVICE_LOST: return "device lost"; + case VK_ERROR_MEMORY_MAP_FAILED: return "memory map failed"; + case VK_ERROR_LAYER_NOT_PRESENT: return "layer not present"; + case VK_ERROR_EXTENSION_NOT_PRESENT: return "extension not present"; + case VK_ERROR_FEATURE_NOT_PRESENT: return "feature not present"; + case VK_ERROR_INCOMPATIBLE_DRIVER: return "incompatible driver"; + case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: return "format not supported"; + case VK_ERROR_FRAGMENTED_POOL: return "fragmented pool"; + case VK_ERROR_OUT_OF_POOL_MEMORY: return "out of pool memory"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "invalid external handle"; + case VK_ERROR_SURFACE_LOST_KHR: return "surface lost"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "native window in use"; + case VK_SUBOPTIMAL_KHR: return "suboptimal"; + case VK_ERROR_OUT_OF_DATE_KHR: return "out of date"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "incompatible display"; + case VK_ERROR_VALIDATION_FAILED_EXT: return "validation failed"; + case VK_ERROR_INVALID_SHADER_NV: return "invalid shader"; + case VK_ERROR_FRAGMENTATION_EXT: return "fragmentation"; + case VK_ERROR_NOT_PERMITTED_EXT: return "not permitted"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "full screen exclusive mode lost"; + case VK_THREAD_IDLE_KHR: return "thread idle"; + case VK_THREAD_DONE_KHR: return "thread done"; + case VK_OPERATION_DEFERRED_KHR: return "operation deferred"; + case VK_OPERATION_NOT_DEFERRED_KHR: return "operation not deferred"; + case VK_PIPELINE_COMPILE_REQUIRED_EXT: return "pipeline compile required"; + default: break; + } + return "vkResult " + std::to_string((int)result); +} diff --git a/libraries/ZVulkan/src/vulkansurface.cpp b/libraries/ZVulkan/src/vulkansurface.cpp new file mode 100644 index 00000000000..ae6ede1072d --- /dev/null +++ b/libraries/ZVulkan/src/vulkansurface.cpp @@ -0,0 +1,27 @@ + +#include "vulkansurface.h" +#include "vulkaninstance.h" + +VulkanSurface::VulkanSurface(std::shared_ptr instance, VkSurfaceKHR surface) : Instance(std::move(instance)), Surface(surface) +{ +} + +VulkanSurface::~VulkanSurface() +{ + vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr); +} + +#ifdef VK_USE_PLATFORM_WIN32_KHR + +VulkanSurface::VulkanSurface(std::shared_ptr instance, HWND window) : Instance(std::move(instance)), Window(window) +{ + VkWin32SurfaceCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; + createInfo.hwnd = window; + createInfo.hinstance = GetModuleHandle(nullptr); + + VkResult result = vkCreateWin32SurfaceKHR(Instance->Instance, &createInfo, nullptr, &Surface); + if (result != VK_SUCCESS) + VulkanError("Could not create vulkan surface"); +} + +#endif diff --git a/libraries/ZVulkan/src/vulkanswapchain.cpp b/libraries/ZVulkan/src/vulkanswapchain.cpp new file mode 100644 index 00000000000..299913d8cf0 --- /dev/null +++ b/libraries/ZVulkan/src/vulkanswapchain.cpp @@ -0,0 +1,421 @@ + +#include "vulkanswapchain.h" +#include "vulkanobjects.h" +#include "vulkansurface.h" +#include "vulkanbuilders.h" + +VulkanSwapChain::VulkanSwapChain(VulkanDevice* device) : device(device) +{ +} + +VulkanSwapChain::~VulkanSwapChain() +{ + views.clear(); + images.clear(); + if (swapchain) + vkDestroySwapchainKHR(device->device, swapchain, nullptr); +} + +void VulkanSwapChain::Create(int width, int height, int imageCount, bool vsync, bool hdr, bool exclusivefullscreen) +{ + views.clear(); + images.clear(); + + CreateSwapchain(width, height, imageCount, vsync, hdr, exclusivefullscreen); + + if (exclusivefullscreen && lost) + { + // We could not acquire exclusive fullscreen. Fall back to normal fullsceen instead. + CreateSwapchain(width, height, imageCount, vsync, hdr, false); + } + + if (swapchain) + { + uint32_t imageCount; + VkResult result = vkGetSwapchainImagesKHR(device->device, swapchain, &imageCount, nullptr); + if (result != VK_SUCCESS) + VulkanError("vkGetSwapchainImagesKHR failed"); + + std::vector swapchainImages; + swapchainImages.resize(imageCount); + result = vkGetSwapchainImagesKHR(device->device, swapchain, &imageCount, swapchainImages.data()); + if (result != VK_SUCCESS) + VulkanError("vkGetSwapchainImagesKHR failed (2)"); + + for (VkImage vkimage : swapchainImages) + { + auto image = std::make_unique(device, vkimage, nullptr, actualExtent.width, actualExtent.height, 1, 1); + auto view = ImageViewBuilder() + .Type(VK_IMAGE_VIEW_TYPE_2D) + .Image(image.get(), format.format) + .DebugName("SwapchainImageView") + .Create(device); + images.push_back(std::move(image)); + views.push_back(std::move(view)); + } + } +} + +void VulkanSwapChain::SelectFormat(const VulkanSurfaceCapabilities& caps, bool hdr) +{ + if (caps.Formats.size() == 1 && caps.Formats.front().format == VK_FORMAT_UNDEFINED) + { + format.format = VK_FORMAT_B8G8R8A8_UNORM; + format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + return; + } + + if (hdr) + { + for (const auto& f : caps.Formats) + { + if (f.format == VK_FORMAT_R16G16B16A16_SFLOAT && f.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) + { + format = f; + return; + } + } + } + + for (const auto& f : caps.Formats) + { + if (f.format == VK_FORMAT_B8G8R8A8_UNORM && f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + format = f; + return; + } + } + + format = caps.Formats.front(); +} + +bool VulkanSwapChain::CreateSwapchain(int width, int height, int imageCount, bool vsync, bool hdr, bool exclusivefullscreen) +{ + lost = false; + + VulkanSurfaceCapabilities caps = GetSurfaceCapabilities(exclusivefullscreen); + + if (exclusivefullscreen && (caps.PresentModes.empty() || !caps.FullScreenExclusive.fullScreenExclusiveSupported)) + { + // Try again without exclusive full screen. + exclusivefullscreen = false; + caps = GetSurfaceCapabilities(exclusivefullscreen); + } + + if (caps.PresentModes.empty()) + VulkanError("No surface present modes supported"); + + bool supportsFifoRelaxed = std::find(caps.PresentModes.begin(), caps.PresentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != caps.PresentModes.end(); + bool supportsMailbox = std::find(caps.PresentModes.begin(), caps.PresentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != caps.PresentModes.end(); + bool supportsImmediate = std::find(caps.PresentModes.begin(), caps.PresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != caps.PresentModes.end(); + + presentMode = VK_PRESENT_MODE_FIFO_KHR; + if (vsync) + { + if (supportsFifoRelaxed) + presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; + } + else + { + if (exclusivefullscreen) // Exclusive full screen doesn't seem to support mailbox for some reason, even if it is advertised + { + if (supportsImmediate) + presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + else if (supportsMailbox) + presentMode = VK_PRESENT_MODE_MAILBOX_KHR; + } + else + { + /*if (supportsMailbox) + presentMode = VK_PRESENT_MODE_MAILBOX_KHR; + else*/ if (supportsImmediate) + presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + } + } + + SelectFormat(caps, hdr); + + actualExtent = { static_cast(width), static_cast(height) }; + actualExtent.width = std::max(caps.Capabilites.minImageExtent.width, std::min(caps.Capabilites.maxImageExtent.width, actualExtent.width)); + actualExtent.height = std::max(caps.Capabilites.minImageExtent.height, std::min(caps.Capabilites.maxImageExtent.height, actualExtent.height)); + if (actualExtent.width == 0 || actualExtent.height == 0) + { + if (swapchain) + vkDestroySwapchainKHR(device->device, swapchain, nullptr); + swapchain = VK_NULL_HANDLE; + lost = true; + return false; + } + + if (caps.Capabilites.maxImageCount != 0) + imageCount = std::min(caps.Capabilites.maxImageCount, (uint32_t)imageCount); + imageCount = std::max(caps.Capabilites.minImageCount, (uint32_t)imageCount); + + VkSwapchainCreateInfoKHR swapChainCreateInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; +#ifdef WIN32 + VkSurfaceFullScreenExclusiveInfoEXT exclusiveInfo = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT }; + VkSurfaceFullScreenExclusiveWin32InfoEXT exclusiveWin32Info = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT }; +#endif + + swapChainCreateInfo.surface = device->Surface->Surface; + swapChainCreateInfo.minImageCount = imageCount; + swapChainCreateInfo.imageFormat = format.format; + swapChainCreateInfo.imageColorSpace = format.colorSpace; + swapChainCreateInfo.imageExtent = actualExtent; + swapChainCreateInfo.imageArrayLayers = 1; + swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + uint32_t queueFamilyIndices[] = { (uint32_t)device->GraphicsFamily, (uint32_t)device->PresentFamily }; + if (device->GraphicsFamily != device->PresentFamily) + { + swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapChainCreateInfo.queueFamilyIndexCount = 2; + swapChainCreateInfo.pQueueFamilyIndices = queueFamilyIndices; + } + else + { + swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapChainCreateInfo.queueFamilyIndexCount = 0; + swapChainCreateInfo.pQueueFamilyIndices = nullptr; + } + + swapChainCreateInfo.preTransform = caps.Capabilites.currentTransform; + swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // If alpha channel is passed on to the DWM or not + swapChainCreateInfo.presentMode = presentMode; + swapChainCreateInfo.clipped = VK_TRUE; // Applications SHOULD set this value to VK_TRUE if they do not expect to read back the content of presentable images before presenting them or after reacquiring them, and if their fragment shaders do not have any side effects that require them to run for all pixels in the presentable image + swapChainCreateInfo.oldSwapchain = swapchain; + +#ifdef WIN32 + if (exclusivefullscreen) + { + swapChainCreateInfo.pNext = &exclusiveInfo; + exclusiveInfo.pNext = &exclusiveWin32Info; + exclusiveInfo.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT; + exclusiveWin32Info.hmonitor = MonitorFromWindow(device->Surface->Window, MONITOR_DEFAULTTONEAREST); + } +#endif + + VkResult result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapchain); + + if (swapChainCreateInfo.oldSwapchain) + vkDestroySwapchainKHR(device->device, swapChainCreateInfo.oldSwapchain, nullptr); + + if (result != VK_SUCCESS) + { + swapchain = VK_NULL_HANDLE; + lost = true; + return false; + } + +#ifdef WIN32 + if (exclusivefullscreen) + { + result = vkAcquireFullScreenExclusiveModeEXT(device->device, swapchain); + if (result != VK_SUCCESS) + { + lost = true; + } + } +#endif + + return true; +} + +int VulkanSwapChain::AcquireImage(VulkanSemaphore* semaphore, VulkanFence* fence) +{ + if (lost) + return -1; + + uint32_t imageIndex; + VkResult result = vkAcquireNextImageKHR(device->device, swapchain, 1'000'000'000, semaphore ? semaphore->semaphore : VK_NULL_HANDLE, fence ? fence->fence : VK_NULL_HANDLE, &imageIndex); + if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) + { + return imageIndex; + } + else if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT) + { + lost = true; + return -1; + } + else if (result == VK_NOT_READY || result == VK_TIMEOUT) + { + return -1; + } + else + { + VulkanError("Failed to acquire next image!"); + return -1; + } +} + +void VulkanSwapChain::QueuePresent(int imageIndex, VulkanSemaphore* semaphore) +{ + uint32_t index = imageIndex; + VkPresentInfoKHR presentInfo = {}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = semaphore ? 1 : 0; + presentInfo.pWaitSemaphores = semaphore ? &semaphore->semaphore : VK_NULL_HANDLE; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapchain; + presentInfo.pImageIndices = &index; + presentInfo.pResults = nullptr; + VkResult result = vkQueuePresentKHR(device->PresentQueue, &presentInfo); + if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) + { + return; + } + else if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_ERROR_SURFACE_LOST_KHR || result == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT) + { + lost = true; + } + else if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY) + { + // The spec says we can recover from this. + // However, if we are out of memory it is better to crash now than in some other weird place further away from the source of the problem. + + VulkanError("vkQueuePresentKHR failed: out of memory"); + } + else if (result == VK_ERROR_DEVICE_LOST) + { + VulkanError("vkQueuePresentKHR failed: device lost"); + } + else + { + VulkanError("vkQueuePresentKHR failed"); + } +} + +VulkanSurfaceCapabilities VulkanSwapChain::GetSurfaceCapabilities(bool exclusivefullscreen) +{ + // They sure made it easy to query something that isn't even time critical. Good job guys! + + VulkanSurfaceCapabilities caps; + + VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR }; +#ifdef WIN32 + VkSurfaceFullScreenExclusiveInfoEXT exclusiveInfo = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT }; + VkSurfaceFullScreenExclusiveWin32InfoEXT exclusiveWin32Info = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT }; +#endif + +#ifdef WIN32 + if (exclusivefullscreen) + { + exclusiveInfo.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT; + exclusiveWin32Info.hmonitor = MonitorFromWindow(device->Surface->Window, MONITOR_DEFAULTTONEAREST); + } +#endif + + surfaceInfo.surface = device->Surface->Surface; + + if (device->SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) + { + const void** next = &surfaceInfo.pNext; + +#ifdef WIN32 + if (exclusivefullscreen && device->SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME)) + { + *next = &exclusiveInfo; + next = const_cast(&exclusiveInfo.pNext); + + *next = &exclusiveWin32Info; + next = &exclusiveWin32Info.pNext; + } +#endif + + VkSurfaceCapabilities2KHR caps2 = { VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR }; + next = const_cast(&caps2.pNext); + +#ifdef WIN32 + if (exclusivefullscreen && device->SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME)) + { + *next = &caps.FullScreenExclusive; + next = const_cast(&caps.FullScreenExclusive.pNext); + } +#endif + + VkResult result = vkGetPhysicalDeviceSurfaceCapabilities2KHR(device->PhysicalDevice.Device, &surfaceInfo, &caps2); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfaceCapabilities2KHR failed"); + + caps.Capabilites = caps2.surfaceCapabilities; + } + else + { + VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &caps.Capabilites); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed"); + } + +#ifdef WIN32 + if (exclusivefullscreen && device->SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME)) + { + const void** next = &surfaceInfo.pNext; + + uint32_t presentModeCount = 0; + VkResult result = vkGetPhysicalDeviceSurfacePresentModes2EXT(device->PhysicalDevice.Device, &surfaceInfo, &presentModeCount, nullptr); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfacePresentModes2EXT failed"); + + if (presentModeCount > 0) + { + caps.PresentModes.resize(presentModeCount); + result = vkGetPhysicalDeviceSurfacePresentModes2EXT(device->PhysicalDevice.Device, &surfaceInfo, &presentModeCount, caps.PresentModes.data()); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfacePresentModes2EXT failed"); + } + } + else +#endif + { + uint32_t presentModeCount = 0; + VkResult result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &presentModeCount, nullptr); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); + + if (presentModeCount > 0) + { + caps.PresentModes.resize(presentModeCount); + result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &presentModeCount, caps.PresentModes.data()); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); + } + } + + if (device->SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) + { + uint32_t surfaceFormatCount = 0; + VkResult result = vkGetPhysicalDeviceSurfaceFormats2KHR(device->PhysicalDevice.Device, &surfaceInfo, &surfaceFormatCount, nullptr); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfaceFormats2KHR failed"); + + if (surfaceFormatCount > 0) + { + std::vector formats(surfaceFormatCount, { VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR }); + result = vkGetPhysicalDeviceSurfaceFormats2KHR(device->PhysicalDevice.Device, &surfaceInfo, &surfaceFormatCount, formats.data()); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfaceFormats2KHR failed"); + + for (VkSurfaceFormat2KHR& fmt : formats) + caps.Formats.push_back(fmt.surfaceFormat); + } + } + else + { + uint32_t surfaceFormatCount = 0; + VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceFormatCount, nullptr); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); + + if (surfaceFormatCount > 0) + { + caps.Formats.resize(surfaceFormatCount); + result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceFormatCount, caps.Formats.data()); + if (result != VK_SUCCESS) + VulkanError("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); + } + } + + caps.FullScreenExclusive.pNext = nullptr; + + return caps; +} diff --git a/libraries/ZWidget/CMakeLists.txt b/libraries/ZWidget/CMakeLists.txt new file mode 100644 index 00000000000..68c048e22ee --- /dev/null +++ b/libraries/ZWidget/CMakeLists.txt @@ -0,0 +1,152 @@ +cmake_minimum_required(VERSION 3.11) +project(zwidget) + +set(ZWIDGET_SOURCES + src/core/canvas.cpp + src/core/font.cpp + src/core/image.cpp + src/core/span_layout.cpp + src/core/timer.cpp + src/core/widget.cpp + src/core/utf8reader.cpp + src/core/pathfill.cpp + src/core/truetypefont.cpp + src/core/truetypefont.h + src/core/picopng/picopng.cpp + src/core/picopng/picopng.h + src/core/nanosvg/nanosvg.cpp + src/core/nanosvg/nanosvg.h + src/core/nanosvg/nanosvgrast.h + src/widgets/lineedit/lineedit.cpp + src/widgets/mainwindow/mainwindow.cpp + src/widgets/menubar/menubar.cpp + src/widgets/scrollbar/scrollbar.cpp + src/widgets/statusbar/statusbar.cpp + src/widgets/textedit/textedit.cpp + src/widgets/toolbar/toolbar.cpp + src/widgets/toolbar/toolbarbutton.cpp + src/widgets/imagebox/imagebox.cpp + src/widgets/textlabel/textlabel.cpp + src/widgets/pushbutton/pushbutton.cpp + src/widgets/checkboxlabel/checkboxlabel.cpp + src/widgets/listview/listview.cpp + src/widgets/tabwidget/tabwidget.cpp + src/window/window.cpp +) + +set(ZWIDGET_INCLUDES + include/zwidget/core/canvas.h + include/zwidget/core/colorf.h + include/zwidget/core/font.h + include/zwidget/core/image.h + include/zwidget/core/rect.h + include/zwidget/core/pathfill.h + include/zwidget/core/span_layout.h + include/zwidget/core/timer.h + include/zwidget/core/widget.h + include/zwidget/core/utf8reader.h + include/zwidget/core/resourcedata.h + include/zwidget/widgets/lineedit/lineedit.h + include/zwidget/widgets/mainwindow/mainwindow.h + include/zwidget/widgets/menubar/menubar.h + include/zwidget/widgets/scrollbar/scrollbar.h + include/zwidget/widgets/statusbar/statusbar.h + include/zwidget/widgets/textedit/textedit.h + include/zwidget/widgets/toolbar/toolbar.h + include/zwidget/widgets/toolbar/toolbarbutton.h + include/zwidget/widgets/imagebox/imagebox.h + include/zwidget/widgets/textlabel/textlabel.h + include/zwidget/widgets/pushbutton/pushbutton.h + include/zwidget/widgets/checkboxlabel/checkboxlabel.h + include/zwidget/widgets/listview/listview.h + include/zwidget/widgets/tabwidget/tabwidget.h + include/zwidget/window/window.h +) + +set(ZWIDGET_WIN32_SOURCES + src/window/win32/win32window.cpp + src/window/win32/win32window.h +) + +set(ZWIDGET_COCOA_SOURCES +) + +set(ZWIDGET_SDL2_SOURCES + src/window/sdl2/sdl2displaywindow.cpp + src/window/sdl2/sdl2displaywindow.h +) + +source_group("src" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/.+") +source_group("src\\core" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/.+") +source_group("src\\core\\picopng" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/picopng/.+") +source_group("src\\core\\nanosvg" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/nanosvg/.+") +source_group("src\\widgets" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/.+") +source_group("src\\widgets\\lineedit" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/lineedit/.+") +source_group("src\\widgets\\mainwindow" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/mainwindow/.+") +source_group("src\\widgets\\menubar" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/menubar/.+") +source_group("src\\widgets\\scrollbar" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/scrollbar/.+") +source_group("src\\widgets\\statusbar" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/statusbar/.+") +source_group("src\\widgets\\textedit" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/textedit/.+") +source_group("src\\widgets\\toolbar" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/toolbar/.+") +source_group("src\\widgets\\imagebox" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/imagebox/.+") +source_group("src\\widgets\\textlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/textlabel/.+") +source_group("src\\widgets\\pushbutton" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/pushbutton/.+") +source_group("src\\widgets\\checkboxlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/checkboxlabel/.+") +source_group("src\\widgets\\listview" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/listview/.+") +source_group("src\\widgets\\tabwidget" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/tabwidget/.+") +source_group("src\\window" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/window/.+") +source_group("include" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/.+") +source_group("include\\core" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/core/.+") +source_group("include\\widgets" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/.+") +source_group("include\\widgets\\lineedit" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/lineedit/.+") +source_group("include\\widgets\\mainwindow" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/mainwindow/.+") +source_group("include\\widgets\\menubar" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/menubar/.+") +source_group("include\\widgets\\scrollbar" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/scrollbar/.+") +source_group("include\\widgets\\statusbar" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/statusbar/.+") +source_group("include\\widgets\\textedit" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/textedit/.+") +source_group("include\\widgets\\toolbar" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/toolbar/.+") +source_group("include\\widgets\\imagebox" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/imagebox/.+") +source_group("include\\widgets\\textlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/textlabel/.+") +source_group("include\\widgets\\pushbutton" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/pushbutton/.+") +source_group("include\\widgets\\checkboxlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/checkboxlabel/.+") +source_group("include\\widgets\\listview" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/listview/.+") +source_group("include\\widgets\\tabwidget" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/tabwidget/.+") +source_group("include\\window" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/.+") +source_group("include\\window\\win32" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/win32/.+") +source_group("include\\window\\sdl2" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/sdl2/.+") + +include_directories(include include/zwidget src) + +if(WIN32) + set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_WIN32_SOURCES}) + add_definitions(-DUNICODE -D_UNICODE) + if(MINGW) + add_definitions(-DMINGW) + endif() +elseif(APPLE) + set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_COCOA_SOURCES}) + set(ZWIDGET_LIBS ${CMAKE_DL_LIBS} -ldl) + add_definitions(-DUNIX -D_UNIX) + add_link_options(-pthread) +else() + set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_SDL2_SOURCES}) + set(ZWIDGET_LIBS ${CMAKE_DL_LIBS} -ldl) + add_definitions(-DUNIX -D_UNIX) + add_link_options(-pthread) +endif() + +if(MSVC) + # Use all cores for compilation + set(CMAKE_CXX_FLAGS "/MP ${CMAKE_CXX_FLAGS}") + + # Ignore warnings in third party code + #set_source_files_properties(${ZWIDGET_SOURCES} PROPERTIES COMPILE_FLAGS "/wd4244 /wd4267 /wd4005 /wd4018 -D_CRT_SECURE_NO_WARNINGS") +endif() + +add_library(zwidget STATIC ${ZWIDGET_SOURCES} ${ZWIDGET_INCLUDES}) +target_link_libraries(zwidget ${ZWIDGET_LIBS}) +set_target_properties(zwidget PROPERTIES CXX_STANDARD 17) + +if(MSVC) + set_property(TARGET zwidget PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +endif() diff --git a/libraries/ZWidget/LICENSE.md b/libraries/ZWidget/LICENSE.md new file mode 100644 index 00000000000..fdc06221ca1 --- /dev/null +++ b/libraries/ZWidget/LICENSE.md @@ -0,0 +1,21 @@ +# License information + +## License for ZWidget itself + + // Copyright (c) 2023 Magnus Norddahl + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. diff --git a/libraries/ZWidget/README.md b/libraries/ZWidget/README.md new file mode 100644 index 00000000000..c3bb8e21941 --- /dev/null +++ b/libraries/ZWidget/README.md @@ -0,0 +1,2 @@ +# ZWidget +A framework for building user interface applications diff --git a/libraries/ZWidget/include/zwidget/core/canvas.h b/libraries/ZWidget/include/zwidget/core/canvas.h new file mode 100644 index 00000000000..a546e62cc88 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/canvas.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include + +class Font; +class Image; +class Point; +class Rect; +class Colorf; +class DisplayWindow; +struct VerticalTextPosition; + +class FontMetrics +{ +public: + double ascent = 0.0; + double descent = 0.0; + double external_leading = 0.0; + double height = 0.0; +}; + +class Canvas +{ +public: + static std::unique_ptr create(DisplayWindow* window); + + virtual ~Canvas() = default; + + virtual void begin(const Colorf& color) = 0; + virtual void end() = 0; + + virtual void begin3d() = 0; + virtual void end3d() = 0; + + virtual Point getOrigin() = 0; + virtual void setOrigin(const Point& origin) = 0; + + virtual void pushClip(const Rect& box) = 0; + virtual void popClip() = 0; + + virtual void fillRect(const Rect& box, const Colorf& color) = 0; + virtual void line(const Point& p0, const Point& p1, const Colorf& color) = 0; + + virtual void drawText(const Point& pos, const Colorf& color, const std::string& text) = 0; + virtual Rect measureText(const std::string& text) = 0; + virtual VerticalTextPosition verticalTextAlign() = 0; + + virtual void drawText(const std::shared_ptr& font, const Point& pos, const std::string& text, const Colorf& color) = 0; + virtual void drawTextEllipsis(const std::shared_ptr& font, const Point& pos, const Rect& clipBox, const std::string& text, const Colorf& color) = 0; + virtual Rect measureText(const std::shared_ptr& font, const std::string& text) = 0; + virtual FontMetrics getFontMetrics(const std::shared_ptr& font) = 0; + virtual int getCharacterIndex(const std::shared_ptr& font, const std::string& text, const Point& hitPoint) = 0; + + virtual void drawImage(const std::shared_ptr& image, const Point& pos) = 0; +}; + +struct VerticalTextPosition +{ + double top = 0.0; + double baseline = 0.0; + double bottom = 0.0; +}; diff --git a/libraries/ZWidget/include/zwidget/core/colorf.h b/libraries/ZWidget/include/zwidget/core/colorf.h new file mode 100644 index 00000000000..93521479905 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/colorf.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +class Colorf +{ +public: + Colorf() = default; + Colorf(float r, float g, float b, float a = 1.0f) : r(r), g(g), b(b), a(a) { } + + static Colorf transparent() { return { 0.0f, 0.0f, 0.0f, 0.0f }; } + + static Colorf fromRgba8(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) + { + float s = 1.0f / 255.0f; + return { r * s, g * s, b * s, a * s }; + } + + uint32_t toBgra8() const + { + uint32_t cr = (int)(std::max(std::min(r * 255.0f, 255.0f), 0.0f)); + uint32_t cg = (int)(std::max(std::min(g * 255.0f, 255.0f), 0.0f)); + uint32_t cb = (int)(std::max(std::min(b * 255.0f, 255.0f), 0.0f)); + uint32_t ca = (int)(std::max(std::min(a * 255.0f, 255.0f), 0.0f)); + return (ca << 24) | (cr << 16) | (cg << 8) | cb; + } + + bool operator==(const Colorf& v) const { return r == v.r && g == v.g && b == v.b && a == v.a; } + bool operator!=(const Colorf& v) const { return r != v.r || g != v.g || b != v.b || a != v.a; } + + float r = 0.0f; + float g = 0.0f; + float b = 0.0f; + float a = 1.0f; +}; diff --git a/libraries/ZWidget/include/zwidget/core/font.h b/libraries/ZWidget/include/zwidget/core/font.h new file mode 100644 index 00000000000..d4af3606167 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/font.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +class Font +{ +public: + virtual ~Font() = default; + + virtual const std::string& GetName() const = 0; + virtual double GetHeight() const = 0; + + static std::shared_ptr Create(const std::string& name, double height); +}; diff --git a/libraries/ZWidget/include/zwidget/core/image.h b/libraries/ZWidget/include/zwidget/core/image.h new file mode 100644 index 00000000000..4cffc195ad3 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/image.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +enum class ImageFormat +{ + R8G8B8A8, + B8G8R8A8 +}; + +class Image +{ +public: + virtual ~Image() = default; + + virtual int GetWidth() const = 0; + virtual int GetHeight() const = 0; + virtual ImageFormat GetFormat() const = 0; + virtual void* GetData() const = 0; + + static std::shared_ptr Create(int width, int height, ImageFormat format, const void* data); + static std::shared_ptr LoadResource(const std::string& resourcename, double dpiscale = 1.0); +}; diff --git a/libraries/ZWidget/include/zwidget/core/pathfill.h b/libraries/ZWidget/include/zwidget/core/pathfill.h new file mode 100644 index 00000000000..a6d749806f2 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/pathfill.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include +#include +#include "core/rect.h" + +/* +// 3x3 transform matrix +class PathFillTransform +{ +public: + PathFillTransform() { for (int i = 0; i < 9; i++) matrix[i] = 0.0f; matrix[0] = matrix[4] = matrix[8] = 1.0; } + PathFillTransform(const float* mat3x3) { for (int i = 0; i < 9; i++) matrix[i] = (double)mat3x3[i]; } + PathFillTransform(const double* mat3x3) { for (int i = 0; i < 9; i++) matrix[i] = mat3x3[i]; } + + double matrix[9]; +}; +*/ + +enum class PathFillMode +{ + alternate, + winding +}; + +enum class PathFillCommand +{ + line, + quadradic, + cubic +}; + +class PathFillSubpath +{ +public: + PathFillSubpath() : points(1) { } + + std::vector points; + std::vector commands; + bool closed = false; +}; + +class PathFillDesc +{ +public: + PathFillDesc() : subpaths(1) { } + + PathFillMode fill_mode = PathFillMode::alternate; + std::vector subpaths; + + void MoveTo(const Point& point) + { + if (!subpaths.back().commands.empty()) + { + subpaths.push_back(PathFillSubpath()); + } + subpaths.back().points.front() = point; + } + + void LineTo(const Point& point) + { + auto& subpath = subpaths.back(); + subpath.points.push_back(point); + subpath.commands.push_back(PathFillCommand::line); + } + + void BezierTo(const Point& control, const Point& point) + { + auto& subpath = subpaths.back(); + subpath.points.push_back(control); + subpath.points.push_back(point); + subpath.commands.push_back(PathFillCommand::quadradic); + } + + void BezierTo(const Point& control1, const Point& control2, const Point& point) + { + auto& subpath = subpaths.back(); + subpath.points.push_back(control1); + subpath.points.push_back(control2); + subpath.points.push_back(point); + subpath.commands.push_back(PathFillCommand::cubic); + } + + void Close() + { + if (!subpaths.back().commands.empty()) + { + subpaths.back().closed = true; + subpaths.push_back(PathFillSubpath()); + } + } + + void Rasterize(uint8_t* dest, int width, int height, bool blend = false); +}; diff --git a/libraries/ZWidget/include/zwidget/core/rect.h b/libraries/ZWidget/include/zwidget/core/rect.h new file mode 100644 index 00000000000..ad2a4e09caf --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/rect.h @@ -0,0 +1,83 @@ +#pragma once + +class Point +{ +public: + Point() = default; + Point(double x, double y) : x(x), y(y) { } + + double x = 0; + double y = 0; + + Point& operator+=(const Point& p) { x += p.x; y += p.y; return *this; } + Point& operator-=(const Point& p) { x -= p.x; y -= p.y; return *this; } +}; + +class Size +{ +public: + Size() = default; + Size(double width, double height) : width(width), height(height) { } + + double width = 0; + double height = 0; +}; + +class Rect +{ +public: + Rect() = default; + Rect(const Point& p, const Size& s) : x(p.x), y(p.y), width(s.width), height(s.height) { } + Rect(double x, double y, double width, double height) : x(x), y(y), width(width), height(height) { } + + Point pos() const { return { x, y }; } + Size size() const { return { width, height }; } + + Point topLeft() const { return { x, y }; } + Point topRight() const { return { x + width, y }; } + Point bottomLeft() const { return { x, y + height }; } + Point bottomRight() const { return { x + width, y + height }; } + + double left() const { return x; } + double top() const { return y; } + double right() const { return x + width; } + double bottom() const { return y + height; } + + static Rect xywh(double x, double y, double width, double height) { return Rect(x, y, width, height); } + static Rect ltrb(double left, double top, double right, double bottom) { return Rect(left, top, right - left, bottom - top); } + + static Rect shrink(Rect box, double left, double top, double right, double bottom) + { + box.x += left; + box.y += top; + box.width = std::max(box.width - left - right, 0.0); + box.height = std::max(box.height - bottom - top, 0.0); + return box; + } + + bool contains(const Point& p) const { return (p.x >= x && p.x < x + width) && (p.y >= y && p.y < y + height); } + + double x = 0; + double y = 0; + double width = 0; + double height = 0; +}; + +inline Point operator+(const Point& a, const Point& b) { return Point(a.x + b.x, a.y + b.y); } +inline Point operator-(const Point& a, const Point& b) { return Point(a.x - b.x, a.y - b.y); } +inline bool operator==(const Point& a, const Point& b) { return a.x == b.x && a.y == b.y; } +inline bool operator!=(const Point& a, const Point& b) { return a.x != b.x || a.y != b.y; } +inline bool operator==(const Size& a, const Size& b) { return a.width == b.width && a.height == b.height; } +inline bool operator!=(const Size& a, const Size& b) { return a.width != b.width || a.height != b.height; } +inline bool operator==(const Rect& a, const Rect& b) { return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height; } +inline bool operator!=(const Rect& a, const Rect& b) { return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height; } + +inline Point operator+(const Point& a, double b) { return Point(a.x + b, a.y + b); } +inline Point operator-(const Point& a, double b) { return Point(a.x - b, a.y - b); } +inline Point operator*(const Point& a, double b) { return Point(a.x * b, a.y * b); } +inline Point operator/(const Point& a, double b) { return Point(a.x / b, a.y / b); } + +inline Size operator+(const Size& a, double b) { return Size(a.width + b, a.height + b); } +inline Size operator-(const Size& a, double b) { return Size(a.width - b, a.height - b); } +inline Size operator*(const Size& a, double b) { return Size(a.width * b, a.height * b); } +inline Size operator/(const Size& a, double b) { return Size(a.width / b, a.height / b); } diff --git a/libraries/ZWidget/include/zwidget/core/resourcedata.h b/libraries/ZWidget/include/zwidget/core/resourcedata.h new file mode 100644 index 00000000000..f29ab261e5b --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/resourcedata.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include + +struct SingleFontData +{ + std::vector fontdata; + std::string language; +}; + +std::vector LoadWidgetFontData(const std::string& name); +std::vector LoadWidgetData(const std::string& name); diff --git a/libraries/ZWidget/include/zwidget/core/span_layout.h b/libraries/ZWidget/include/zwidget/core/span_layout.h new file mode 100644 index 00000000000..974feca405c --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/span_layout.h @@ -0,0 +1,238 @@ +#pragma once + +#include +#include + +#include "colorf.h" +#include "rect.h" +#include "font.h" +#include "canvas.h" + +class Widget; +class Image; +class Canvas; + +enum SpanAlign +{ + span_left, + span_right, + span_center, + span_justify +}; + +class SpanLayout +{ +public: + SpanLayout(); + ~SpanLayout(); + + struct HitTestResult + { + enum Type + { + no_objects_available, + outside_top, + outside_left, + outside_right, + outside_bottom, + inside + }; + + Type type = {}; + int object_id = -1; + size_t offset = 0; + }; + + void Clear(); + + void AddText(const std::string& text, std::shared_ptr font, const Colorf& color = Colorf(), int id = -1); + void AddImage(const std::shared_ptr image, double baseline_offset = 0, int id = -1); + void AddWidget(Widget* component, double baseline_offset = 0, int id = -1); + + void Layout(Canvas* canvas, double max_width); + + void SetPosition(const Point& pos); + + Size GetSize() const; + Rect GetRect() const; + + std::vector GetRectById(int id) const; + + HitTestResult HitTest(Canvas* canvas, const Point& pos); + + void DrawLayout(Canvas* canvas); + + /// Draw layout generating ellipsis for clipped text + void DrawLayoutEllipsis(Canvas* canvas, const Rect& content_rect); + + void SetComponentGeometry(); + + Size FindPreferredSize(Canvas* canvas); + + void SetSelectionRange(std::string::size_type start, std::string::size_type end); + void SetSelectionColors(const Colorf& foreground, const Colorf& background); + + void ShowCursor(); + void HideCursor(); + + void SetCursorPos(std::string::size_type pos); + void SetCursorOverwriteMode(bool enable); + void SetCursorColor(const Colorf& color); + + std::string GetCombinedText() const; + + void SetAlign(SpanAlign align); + + double GetFirstBaselineOffset(); + double GetLastBaselineOffset(); + +private: + struct TextBlock + { + size_t start = 0; + size_t end = 0; + }; + + enum ObjectType + { + object_text, + object_image, + object_component + }; + + enum FloatType + { + float_none, + float_left, + float_right + }; + + struct SpanObject + { + ObjectType type = object_text; + FloatType float_type = float_none; + + std::shared_ptr font; + Colorf color; + size_t start = 0, end = 0; + + std::shared_ptr image; + Widget* component = nullptr; + double baseline_offset = 0; + + int id = -1; + }; + + struct LineSegment + { + ObjectType type = object_text; + + std::shared_ptr font; + Colorf color; + size_t start = 0; + size_t end = 0; + double ascender = 0; + double descender = 0; + + double x_position = 0; + double width = 0; + + std::shared_ptr image; + Widget* component = nullptr; + double baseline_offset = 0; + + int id = -1; + }; + + struct Line + { + double width = 0; // Width of the entire line (including spaces) + double height = 0; + double ascender = 0; + std::vector segments; + }; + + struct TextSizeResult + { + size_t start = 0; + size_t end = 0; + double width = 0; + double height = 0; + double ascender = 0; + double descender = 0; + int objects_traversed = 0; + std::vector segments; + }; + + struct CurrentLine + { + std::vector::size_type object_index = 0; + Line cur_line; + double x_position = 0; + double y_position = 0; + }; + + struct FloatBox + { + Rect rect; + ObjectType type = object_image; + std::shared_ptr image; + Widget* component = nullptr; + int id = -1; + }; + + TextSizeResult FindTextSize(Canvas* canvas, const TextBlock& block, size_t object_index); + std::vector FindTextBlocks(); + void LayoutLines(Canvas* canvas, double max_width); + void LayoutText(Canvas* canvas, std::vector blocks, std::vector::size_type block_index, CurrentLine& current_line, double max_width); + void LayoutBlock(CurrentLine& current_line, double max_width, std::vector& blocks, std::vector::size_type block_index); + void LayoutFloatBlock(CurrentLine& current_line, double max_width); + void LayoutInlineBlock(CurrentLine& current_line, double max_width, std::vector& blocks, std::vector::size_type block_index); + void ReflowLine(CurrentLine& current_line, double max_width); + FloatBox FloatBoxLeft(FloatBox float_box, double max_width); + FloatBox FloatBoxRight(FloatBox float_box, double max_width); + FloatBox FloatBoxAny(FloatBox box, double max_width, const std::vector& floats1); + bool BoxFitsOnLine(const FloatBox& box, double max_width); + void PlaceLineSegments(CurrentLine& current_line, TextSizeResult& text_size_result); + void ForcePlaceLineSegments(CurrentLine& current_line, TextSizeResult& text_size_result, double max_width); + void NextLine(CurrentLine& current_line); + bool IsNewline(const TextBlock& block); + bool IsWhitespace(const TextBlock& block); + bool FitsOnLine(double x_position, const TextSizeResult& text_size_result, double max_width); + bool LargerThanLine(const TextSizeResult& text_size_result, double max_width); + void AlignJustify(double max_width); + void AlignCenter(double max_width); + void AlignRight(double max_width); + void DrawLayoutImage(Canvas* canvas, Line& line, LineSegment& segment, double x, double y); + void DrawLayoutText(Canvas* canvas, Line& line, LineSegment& segment, double x, double y); + + bool cursor_visible = false; + std::string::size_type cursor_pos = 0; + bool cursor_overwrite_mode = false; + Colorf cursor_color; + + std::string::size_type sel_start = 0, sel_end = 0; + Colorf sel_foreground, sel_background = Colorf::fromRgba8(153, 201, 239); + + std::string text; + std::vector objects; + std::vector lines; + Point position; + + std::vector floats_left, floats_right; + + SpanAlign alignment = span_left; + + struct LayoutCache + { + int object_index = -1; + FontMetrics metrics; + }; + LayoutCache layout_cache; + + bool is_ellipsis_draw = false; + Rect ellipsis_content_rect; + + template + static T clamp(T val, T minval, T maxval) { return std::max(std::min(val, maxval), minval); } +}; diff --git a/libraries/ZWidget/include/zwidget/core/timer.h b/libraries/ZWidget/include/zwidget/core/timer.h new file mode 100644 index 00000000000..25e6fb34612 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/timer.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +class Widget; + +class Timer +{ +public: + Timer(Widget* owner); + ~Timer(); + + void Start(int timeoutMilliseconds, bool repeat = true); + void Stop(); + + std::function FuncExpired; + +private: + Widget* OwnerObj = nullptr; + Timer* PrevTimerObj = nullptr; + Timer* NextTimerObj = nullptr; + + void* TimerId = nullptr; + + friend class Widget; +}; diff --git a/libraries/ZWidget/include/zwidget/core/utf8reader.h b/libraries/ZWidget/include/zwidget/core/utf8reader.h new file mode 100644 index 00000000000..f9c186b47d7 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/utf8reader.h @@ -0,0 +1,78 @@ +/* +** Copyright (c) 1997-2015 Mark Page +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#pragma once + +#include + +/// \brief UTF8 reader helper functions. +class UTF8Reader +{ +public: + /// Important: text is not copied by this class and must remain valid during its usage. + UTF8Reader(const std::string::value_type *text, std::string::size_type length); + + /// \brief Returns true if the current position is at the end of the string + bool is_end(); + + /// \brief Get the character at the current position + unsigned int character(); + + /// \brief Returns the length of the current character + std::string::size_type char_length(); + + /// \brief Moves position to the previous character + void prev(); + + /// \brief Moves position to the next character + void next(); + + /// \brief Moves position to the lead byte of the character + void move_to_leadbyte(); + + /// \brief Get the current position of the reader + std::string::size_type position(); + + /// \brief Set the current position of the reader + void set_position(std::string::size_type position); + + static size_t utf8_length(const std::string& text) + { + return utf8_length(text.data(), text.size()); + } + + static size_t utf8_length(const std::string::value_type* text, std::string::size_type length) + { + UTF8Reader reader(text, length); + size_t i = 0; + while (!reader.is_end()) + { + reader.next(); + i++; + } + return i; + } + +private: + std::string::size_type current_position = 0; + std::string::size_type length = 0; + const unsigned char *data = nullptr; +}; diff --git a/libraries/ZWidget/include/zwidget/core/widget.h b/libraries/ZWidget/include/zwidget/core/widget.h new file mode 100644 index 00000000000..34faa14e988 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/core/widget.h @@ -0,0 +1,192 @@ +#pragma once + +#include +#include +#include "canvas.h" +#include "rect.h" +#include "colorf.h" +#include "../window/window.h" + +class Canvas; +class Timer; + +enum class WidgetType +{ + Child, + Window, + Popup +}; + +class Widget : DisplayWindowHost +{ +public: + Widget(Widget* parent = nullptr, WidgetType type = WidgetType::Child); + virtual ~Widget(); + + void SetParent(Widget* parent); + void MoveBefore(Widget* sibling); + + std::string GetWindowTitle() const; + void SetWindowTitle(const std::string& text); + + // Icon GetWindowIcon() const; + // void SetWindowIcon(const Icon& icon); + + // Widget content box + Size GetSize() const; + double GetWidth() const { return GetSize().width; } + double GetHeight() const { return GetSize().height; } + + // Widget noncontent area + void SetNoncontentSizes(double left, double top, double right, double bottom); + double GetNoncontentLeft() const { return Noncontent.Left; } + double GetNoncontentTop() const { return Noncontent.Top; } + double GetNoncontentRight() const { return Noncontent.Right; } + double GetNoncontentBottom() const { return Noncontent.Bottom; } + + // Widget frame box + Rect GetFrameGeometry() const; + void SetFrameGeometry(const Rect& geometry); + void SetFrameGeometry(double x, double y, double width, double height) { SetFrameGeometry(Rect::xywh(x, y, width, height)); } + + void SetWindowBackground(const Colorf& color); + void SetWindowBorderColor(const Colorf& color); + void SetWindowCaptionColor(const Colorf& color); + void SetWindowCaptionTextColor(const Colorf& color); + + void SetVisible(bool enable) { if (enable) Show(); else Hide(); } + void Show(); + void ShowFullscreen(); + void ShowMaximized(); + void ShowMinimized(); + void ShowNormal(); + void Hide(); + + void ActivateWindow(); + + void Close(); + + void Update(); + void Repaint(); + + bool HasFocus(); + bool IsEnabled(); + bool IsVisible(); + bool IsHidden(); + + void SetFocus(); + void SetEnabled(bool value); + void SetDisabled(bool value) { SetEnabled(!value); } + void SetHidden(bool value) { if (value) Hide(); else Show(); } + + void LockCursor(); + void UnlockCursor(); + void SetCursor(StandardCursor cursor); + void CaptureMouse(); + void ReleaseMouseCapture(); + + bool GetKeyState(EInputKey key); + + std::string GetClipboardText(); + void SetClipboardText(const std::string& text); + + Widget* Window(); + Canvas* GetCanvas() const; + Widget* ChildAt(double x, double y) { return ChildAt(Point(x, y)); } + Widget* ChildAt(const Point& pos); + + Widget* Parent() const { return ParentObj; } + Widget* PrevSibling() const { return PrevSiblingObj; } + Widget* NextSibling() const { return NextSiblingObj; } + Widget* FirstChild() const { return FirstChildObj; } + Widget* LastChild() const { return LastChildObj; } + + Point MapFrom(const Widget* parent, const Point& pos) const; + Point MapFromGlobal(const Point& pos) const; + Point MapFromParent(const Point& pos) const { return MapFrom(Parent(), pos); } + + Point MapTo(const Widget* parent, const Point& pos) const; + Point MapToGlobal(const Point& pos) const; + Point MapToParent(const Point& pos) const { return MapTo(Parent(), pos); } + + static Size GetScreenSize(); + +protected: + virtual void OnPaintFrame(Canvas* canvas) { } + virtual void OnPaint(Canvas* canvas) { } + virtual bool OnMouseDown(const Point& pos, int key) { return false; } + virtual bool OnMouseDoubleclick(const Point& pos, int key) { return false; } + virtual bool OnMouseUp(const Point& pos, int key) { return false; } + virtual bool OnMouseWheel(const Point& pos, EInputKey key) { return false; } + virtual void OnMouseMove(const Point& pos) { } + virtual void OnMouseLeave() { } + virtual void OnRawMouseMove(int dx, int dy) { } + virtual void OnKeyChar(std::string chars) { } + virtual void OnKeyDown(EInputKey key) { } + virtual void OnKeyUp(EInputKey key) { } + virtual void OnGeometryChanged() { } + virtual void OnClose() { delete this; } + virtual void OnSetFocus() { } + virtual void OnLostFocus() { } + virtual void OnEnableChanged() { } + +private: + void DetachFromParent(); + + void Paint(Canvas* canvas); + + // DisplayWindowHost + void OnWindowPaint() override; + void OnWindowMouseMove(const Point& pos) override; + void OnWindowMouseDown(const Point& pos, EInputKey key) override; + void OnWindowMouseDoubleclick(const Point& pos, EInputKey key) override; + void OnWindowMouseUp(const Point& pos, EInputKey key) override; + void OnWindowMouseWheel(const Point& pos, EInputKey key) override; + void OnWindowRawMouseMove(int dx, int dy) override; + void OnWindowKeyChar(std::string chars) override; + void OnWindowKeyDown(EInputKey key) override; + void OnWindowKeyUp(EInputKey key) override; + void OnWindowGeometryChanged() override; + void OnWindowClose() override; + void OnWindowActivated() override; + void OnWindowDeactivated() override; + void OnWindowDpiScaleChanged() override; + + WidgetType Type = {}; + + Widget* ParentObj = nullptr; + Widget* PrevSiblingObj = nullptr; + Widget* NextSiblingObj = nullptr; + Widget* FirstChildObj = nullptr; + Widget* LastChildObj = nullptr; + + Timer* FirstTimerObj = nullptr; + + Rect FrameGeometry = Rect::xywh(0.0, 0.0, 0.0, 0.0); + Rect ContentGeometry = Rect::xywh(0.0, 0.0, 0.0, 0.0); + + Colorf WindowBackground = Colorf::fromRgba8(240, 240, 240); + + struct + { + double Left = 0.0; + double Top = 0.0; + double Right = 0.0; + double Bottom = 0.0; + } Noncontent; + + std::string WindowTitle; + std::unique_ptr DispWindow; + std::unique_ptr DispCanvas; + Widget* FocusWidget = nullptr; + Widget* CaptureWidget = nullptr; + Widget* HoverWidget = nullptr; + bool HiddenFlag = false; + + StandardCursor CurrentCursor = StandardCursor::arrow; + + Widget(const Widget&) = delete; + Widget& operator=(const Widget&) = delete; + + friend class Timer; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/checkboxlabel/checkboxlabel.h b/libraries/ZWidget/include/zwidget/widgets/checkboxlabel/checkboxlabel.h new file mode 100644 index 00000000000..c3f3fb46531 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/checkboxlabel/checkboxlabel.h @@ -0,0 +1,35 @@ + +#pragma once + +#include "../../core/widget.h" + +class CheckboxLabel : public Widget +{ +public: + CheckboxLabel(Widget* parent = nullptr); + + void SetText(const std::string& value); + const std::string& GetText() const; + + void SetChecked(bool value); + bool GetChecked() const; + void Toggle(); + + double GetPreferredHeight() const; + std::function FuncChanged; + void SetRadioStyle(bool on) { radiostyle = on; } + +protected: + void OnPaint(Canvas* canvas) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; + void OnMouseLeave() override; + void OnKeyUp(EInputKey key) override; + +private: + std::string text; + bool checked = false; + bool radiostyle = false; + bool mouseDownActive = false; + +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/imagebox/imagebox.h b/libraries/ZWidget/include/zwidget/widgets/imagebox/imagebox.h new file mode 100644 index 00000000000..e3a724381f3 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/imagebox/imagebox.h @@ -0,0 +1,21 @@ + +#pragma once + +#include "../../core/widget.h" +#include "../../core/image.h" + +class ImageBox : public Widget +{ +public: + ImageBox(Widget* parent); + + void SetImage(std::shared_ptr newImage); + + double GetPreferredHeight() const; + +protected: + void OnPaint(Canvas* canvas) override; + +private: + std::shared_ptr image; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/lineedit/lineedit.h b/libraries/ZWidget/include/zwidget/widgets/lineedit/lineedit.h new file mode 100644 index 00000000000..526d9eee91b --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/lineedit/lineedit.h @@ -0,0 +1,160 @@ + +#pragma once + +#include "../../core/widget.h" +#include "../../core/timer.h" +#include + +class LineEdit : public Widget +{ +public: + LineEdit(Widget* parent); + ~LineEdit(); + + enum Alignment + { + align_left, + align_center, + align_right + }; + + Alignment GetAlignment() const; + bool IsReadOnly() const; + bool IsLowercase() const; + bool IsUppercase() const; + bool IsPasswordMode() const; + int GetMaxLength() const; + + std::string GetText() const; + int GetTextInt() const; + float GetTextFloat() const; + + std::string GetSelection() const; + int GetSelectionStart() const; + int GetSelectionLength() const; + + int GetCursorPos() const; + Size GetTextSize(); + + Size GetTextSize(const std::string& str); + double GetPreferredContentWidth(); + double GetPreferredContentHeight(double width); + + void SetSelectAllOnFocusGain(bool enable); + void SelectAll(); + void SetAlignment(Alignment alignment); + void SetReadOnly(bool enable = true); + void SetLowercase(bool enable = true); + void SetUppercase(bool enable = true); + void SetPasswordMode(bool enable = true); + void SetNumericMode(bool enable = true, bool decimals = false); + void SetMaxLength(int length); + void SetText(const std::string& text); + void SetTextInt(int number); + void SetTextFloat(float number, int num_decimal_places = 6); + void SetSelection(int pos, int length); + void ClearSelection(); + void SetCursorPos(int pos); + void DeleteSelectedText(); + void SetInputMask(const std::string& mask); + void SetDecimalCharacter(const std::string& decimal_char); + + std::function FuncIgnoreKeyDown; + std::function FuncFilterKeyChar; + std::function FuncBeforeEditChanged; + std::function FuncAfterEditChanged; + std::function FuncSelectionChanged; + std::function FuncFocusGained; + std::function FuncFocusLost; + std::function FuncEnterPressed; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnPaint(Canvas* canvas) override; + void OnMouseMove(const Point& pos) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; + void OnKeyChar(std::string chars) override; + void OnKeyDown(EInputKey key) override; + void OnKeyUp(EInputKey key) override; + void OnGeometryChanged() override; + void OnEnableChanged() override; + void OnSetFocus() override; + void OnLostFocus() override; + +private: + void OnTimerExpired(); + void OnScrollTimerExpired(); + void UpdateTextClipping(); + + void Move(int steps, bool ctrl, bool shift); + bool InsertText(int pos, const std::string& str); + void Backspace(); + void Del(); + int GetCharacterIndex(double x); + int FindNextBreakCharacter(int pos); + int FindPreviousBreakCharacter(int pos); + std::string GetVisibleTextBeforeSelection(); + std::string GetVisibleTextAfterSelection(); + std::string GetVisibleSelectedText(); + std::string CreatePassword(std::string::size_type num_letters) const; + Size GetVisualTextSize(Canvas* canvas, int pos, int npos) const; + Size GetVisualTextSize(Canvas* canvas) const; + Rect GetCursorRect(); + Rect GetSelectionRect(); + bool InputMaskAcceptsInput(int cursor_pos, const std::string& str); + void SetSelectionStart(int start); + void SetSelectionLength(int length); + void SetTextSelection(int start, int length); + + static std::string ToFixed(float number, int num_decimal_places); + static std::string ToLower(const std::string& text); + static std::string ToUpper(const std::string& text); + + Timer* timer = nullptr; + std::string text; + Alignment alignment = align_left; + int cursor_pos = 0; + int max_length = -1; + bool mouse_selecting = false; + bool lowercase = false; + bool uppercase = false; + bool password_mode = false; + bool numeric_mode = false; + bool numeric_mode_decimals = false; + bool readonly = false; + int selection_start = -1; + int selection_length = 0; + std::string input_mask; + std::string decimal_char = "."; + + VerticalTextPosition vertical_text_align; + Timer* scroll_timer = nullptr; + + bool mouse_moves_left = false; + bool cursor_blink_visible = true; + unsigned int blink_timer = 0; + int clip_start_offset = 0; + int clip_end_offset = 0; + bool ignore_mouse_events = false; + + struct UndoInfo + { + /* set undo text when: + - added char after moving + - destructive block operation (del, cut etc) + - beginning erase + */ + std::string undo_text; + bool first_erase = false; + bool first_text_insert = false; + }; + + UndoInfo undo_info; + + bool select_all_on_focus_gain = true; + + static const std::string break_characters; + static const std::string numeric_mode_characters; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/listview/listview.h b/libraries/ZWidget/include/zwidget/widgets/listview/listview.h new file mode 100644 index 00000000000..2b150abc06c --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/listview/listview.h @@ -0,0 +1,39 @@ + +#pragma once + +#include "../../core/widget.h" +#include +#include + +class Scrollbar; + +class ListView : public Widget +{ +public: + ListView(Widget* parent = nullptr); + + void AddItem(const std::string& text); + int GetSelectedItem() const { return selectedItem; } + void SetSelectedItem(int index); + void ScrollToItem(int index); + + void Activate(); + + std::function OnChanged; + std::function OnActivated; + +protected: + void OnPaint(Canvas* canvas) override; + void OnPaintFrame(Canvas* canvas) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseWheel(const Point& pos, EInputKey key) override; + void OnKeyDown(EInputKey key) override; + void OnGeometryChanged() override; + void OnScrollbarScroll(); + + Scrollbar* scrollbar = nullptr; + + std::vector items; + int selectedItem = 0; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/mainwindow/mainwindow.h b/libraries/ZWidget/include/zwidget/widgets/mainwindow/mainwindow.h new file mode 100644 index 00000000000..abba23d6c40 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/mainwindow/mainwindow.h @@ -0,0 +1,31 @@ + +#pragma once + +#include "../../core/widget.h" + +class Menubar; +class Toolbar; +class Statusbar; + +class MainWindow : public Widget +{ +public: + MainWindow(); + ~MainWindow(); + + Menubar* GetMenubar() const { return MenubarWidget; } + Toolbar* GetToolbar() const { return ToolbarWidget; } + Statusbar* GetStatusbar() const { return StatusbarWidget; } + Widget* GetCentralWidget() const { return CentralWidget; } + + void SetCentralWidget(Widget* widget); + +protected: + void OnGeometryChanged() override; + +private: + Menubar* MenubarWidget = nullptr; + Toolbar* ToolbarWidget = nullptr; + Widget* CentralWidget = nullptr; + Statusbar* StatusbarWidget = nullptr; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/menubar/menubar.h b/libraries/ZWidget/include/zwidget/widgets/menubar/menubar.h new file mode 100644 index 00000000000..9c13283ccc1 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/menubar/menubar.h @@ -0,0 +1,14 @@ + +#pragma once + +#include "../../core/widget.h" + +class Menubar : public Widget +{ +public: + Menubar(Widget* parent); + ~Menubar(); + +protected: + void OnPaint(Canvas* canvas) override; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/pushbutton/pushbutton.h b/libraries/ZWidget/include/zwidget/widgets/pushbutton/pushbutton.h new file mode 100644 index 00000000000..b9b6c9654d7 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/pushbutton/pushbutton.h @@ -0,0 +1,35 @@ + +#pragma once + +#include "../../core/widget.h" +#include + +class PushButton : public Widget +{ +public: + PushButton(Widget* parent = nullptr); + + void SetText(const std::string& value); + const std::string& GetText() const; + + double GetPreferredHeight() const; + + void Click(); + + std::function OnClick; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnPaint(Canvas* canvas) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; + void OnMouseMove(const Point& pos) override; + void OnMouseLeave() override; + void OnKeyDown(EInputKey key) override; + void OnKeyUp(EInputKey key) override; + +private: + std::string text; + bool buttonDown = false; + bool hot = false; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/scrollbar/scrollbar.h b/libraries/ZWidget/include/zwidget/widgets/scrollbar/scrollbar.h new file mode 100644 index 00000000000..5ec95c84105 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/scrollbar/scrollbar.h @@ -0,0 +1,99 @@ + +#pragma once + +#include "../../core/widget.h" +#include "../../core/timer.h" +#include + +class Scrollbar : public Widget +{ +public: + Scrollbar(Widget* parent); + ~Scrollbar(); + + bool IsVertical() const; + bool IsHorizontal() const; + double GetMin() const; + double GetMax() const; + double GetLineStep() const; + double GetPageStep() const; + double GetPosition() const; + + void SetVertical(); + void SetHorizontal(); + + void SetMin(double scroll_min); + void SetMax(double scroll_max); + void SetLineStep(double step); + void SetPageStep(double step); + + void SetRanges(double scroll_min, double scroll_max, double line_step, double page_step); + void SetRanges(double view_size, double total_size); + + void SetPosition(double pos); + + double GetPreferredWidth() const { return 16.0; } + double GetPreferredHeight() const { return 16.0; } + + std::function FuncScroll; + std::function FuncScrollMin; + std::function FuncScrollMax; + std::function FuncScrollLineDecrement; + std::function FuncScrollLineIncrement; + std::function FuncScrollPageDecrement; + std::function FuncScrollPageIncrement; + std::function FuncScrollThumbRelease; + std::function FuncScrollThumbTrack; + std::function FuncScrollEnd; + +protected: + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; + void OnMouseMove(const Point& pos) override; + void OnMouseLeave() override; + void OnPaint(Canvas* canvas) override; + void OnEnableChanged() override; + void OnGeometryChanged() override; + +private: + bool UpdatePartPositions(); + double CalculateThumbSize(double track_size); + double CalculateThumbPosition(double thumb_size, double track_size); + Rect CreateRect(double start, double end); + void InvokeScrollEvent(std::function* event_ptr); + void OnTimerExpired(); + + bool vertical = true; + double scroll_min = 0.0; + double scroll_max = 1.0; + double line_step = 1.0; + double page_step = 10.0; + double position = 0.0; + + bool showbuttons = false; + + enum MouseDownMode + { + mouse_down_none, + mouse_down_button_decr, + mouse_down_button_incr, + mouse_down_track_decr, + mouse_down_track_incr, + mouse_down_thumb_drag + } mouse_down_mode = mouse_down_none; + + double thumb_start_position = 0.0; + Point mouse_drag_start_pos; + double thumb_start_pixel_position = 0.0; + + Timer* mouse_down_timer = nullptr; + double last_step_size = 0.0; + + Rect rect_button_decrement; + Rect rect_track_decrement; + Rect rect_thumb; + Rect rect_track_increment; + Rect rect_button_increment; + + std::function* FuncScrollOnMouseDown = nullptr; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/statusbar/statusbar.h b/libraries/ZWidget/include/zwidget/widgets/statusbar/statusbar.h new file mode 100644 index 00000000000..c03a3e282c5 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/statusbar/statusbar.h @@ -0,0 +1,19 @@ + +#pragma once + +#include "../../core/widget.h" + +class LineEdit; + +class Statusbar : public Widget +{ +public: + Statusbar(Widget* parent); + ~Statusbar(); + +protected: + void OnPaint(Canvas* canvas) override; + +private: + LineEdit* CommandEdit = nullptr; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h new file mode 100644 index 00000000000..24209402454 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h @@ -0,0 +1,124 @@ + +#pragma once + +#include "../../core/widget.h" +#include +#include +#include + +class TabBar; +class TabBarTab; +class TabWidgetStack; +class TextLabel; +class ImageBox; +class Image; + +class TabWidget : public Widget +{ +public: + TabWidget(Widget* parent); + + int AddTab(Widget* page, const std::string& label); + int AddTab(Widget* page, const std::shared_ptr& icon, const std::string& label); + + void SetTabText(int index, const std::string& text); + void SetTabText(Widget* page, const std::string& text); + void SetTabIcon(int index, const std::shared_ptr& icon); + void SetTabIcon(Widget* page, const std::shared_ptr& icon); + + int GetCurrentIndex() const; + Widget* GetCurrentWidget() const; + + int GetPageIndex(Widget* pageWidget) const; + + void SetCurrentIndex(int pageIndex); + void SetCurrentWidget(Widget* pageWidget); + + std::function OnCurrentChanged; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + void OnBarCurrentChanged(); + + TabBar* Bar = nullptr; + TabWidgetStack* PageStack = nullptr; + std::vector Pages; +}; + +class TabBar : public Widget +{ +public: + TabBar(Widget* parent); + + int AddTab(const std::string& label); + int AddTab(const std::shared_ptr& icon, const std::string& label); + + void SetTabText(int index, const std::string& text); + void SetTabIcon(int index, const std::shared_ptr& icon); + + int GetCurrentIndex() const; + void SetCurrentIndex(int pageIndex); + + double GetPreferredHeight() const { return 30.0; } + + std::function OnCurrentChanged; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + void OnTabClicked(TabBarTab* tab); + int GetTabIndex(TabBarTab* tab); + + int CurrentIndex = -1; + std::vector Tabs; +}; + +class TabBarTab : public Widget +{ +public: + TabBarTab(Widget* parent); + + void SetText(const std::string& text); + void SetIcon(const std::shared_ptr& icon); + void SetCurrent(bool value); + + double GetPreferredWidth() const; + + std::function OnClick; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; + void OnMouseMove(const Point& pos) override; + void OnMouseLeave() override; + +private: + bool IsCurrent = false; + + ImageBox* Icon = nullptr; + TextLabel* Label = nullptr; + bool hot = false; +}; + +class TabWidgetStack : public Widget +{ +public: + TabWidgetStack(Widget* parent); + + void SetCurrentWidget(Widget* widget); + Widget* GetCurrentWidget() const { return CurrentWidget; } + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + Widget* CurrentWidget = nullptr; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/textedit/textedit.h b/libraries/ZWidget/include/zwidget/widgets/textedit/textedit.h new file mode 100644 index 00000000000..ed80eec3676 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/textedit/textedit.h @@ -0,0 +1,156 @@ + +#pragma once + +#include "../../core/widget.h" +#include "../../core/timer.h" +#include "../../core/span_layout.h" +#include "../../core/font.h" +#include + +class Scrollbar; + +class TextEdit : public Widget +{ +public: + TextEdit(Widget* parent); + ~TextEdit(); + + bool IsReadOnly() const; + bool IsLowercase() const; + bool IsUppercase() const; + int GetMaxLength() const; + std::string GetText() const; + int GetLineCount() const; + std::string GetLineText(int line) const; + std::string GetSelection() const; + int GetSelectionStart() const; + int GetSelectionLength() const; + int GetCursorPos() const; + int GetCursorLineNumber() const; + double GetTotalHeight(); + + void SetSelectAllOnFocusGain(bool enable); + void SelectAll(); + void SetReadOnly(bool enable = true); + void SetLowercase(bool enable = true); + void SetUppercase(bool enable = true); + void SetMaxLength(int length); + void SetText(const std::string& text); + void AddText(const std::string& text); + void SetSelection(int pos, int length); + void ClearSelection(); + void SetCursorPos(int pos); + void DeleteSelectedText(); + void SetInputMask(const std::string& mask); + void SetCursorDrawingEnabled(bool enable); + + std::function FuncFilterKeyChar; + std::function FuncBeforeEditChanged; + std::function FuncAfterEditChanged; + std::function FuncSelectionChanged; + std::function FuncFocusGained; + std::function FuncFocusLost; + std::function FuncEnterPressed; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnPaint(Canvas* canvas) override; + void OnMouseMove(const Point& pos) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; + void OnKeyChar(std::string chars) override; + void OnKeyDown(EInputKey key) override; + void OnKeyUp(EInputKey key) override; + void OnGeometryChanged() override; + void OnEnableChanged() override; + void OnSetFocus() override; + void OnLostFocus() override; + +private: + void LayoutLines(Canvas* canvas); + + void OnTimerExpired(); + void OnScrollTimerExpired(); + void CreateComponents(); + void OnVerticalScroll(); + void UpdateVerticalScroll(); + void MoveVerticalScroll(); + double GetTotalLineHeight(); + + struct Line + { + std::string text; + SpanLayout layout; + Rect box; + bool invalidated = true; + }; + + struct ivec2 + { + ivec2() = default; + ivec2(int x, int y) : x(x), y(y) { } + int x = 0; + int y = 0; + + bool operator==(const ivec2& b) const { return x == b.x && y == b.y; } + bool operator!=(const ivec2& b) const { return x != b.x || y != b.y; } + }; + + Scrollbar* vert_scrollbar; + Timer* timer = nullptr; + std::vector lines = { Line() }; + ivec2 cursor_pos = { 0, 0 }; + int max_length = -1; + bool mouse_selecting = false; + bool lowercase = false; + bool uppercase = false; + bool readonly = false; + ivec2 selection_start = { -1, 0 }; + int selection_length = 0; + std::string input_mask; + + static std::string break_characters; + + void Move(int steps, bool shift, bool ctrl); + void InsertText(ivec2 pos, const std::string& str); + void Backspace(); + void Del(); + ivec2 GetCharacterIndex(Point mouse_wincoords); + ivec2 FindNextBreakCharacter(ivec2 pos); + ivec2 FindPreviousBreakCharacter(ivec2 pos); + bool InputMaskAcceptsInput(ivec2 cursor_pos, const std::string& str); + + std::string::size_type ToOffset(ivec2 pos) const; + ivec2 FromOffset(std::string::size_type offset) const; + + VerticalTextPosition vertical_text_align; + Timer* scroll_timer = nullptr; + + bool mouse_moves_left = false; + bool cursor_blink_visible = true; + unsigned int blink_timer = 0; + int clip_start_offset = 0; + int clip_end_offset = 0; + bool ignore_mouse_events = false; + + struct UndoInfo + { + /* set undo text when: + - added char after moving + - destructive block operation (del, cut etc) + - beginning erase + */ + + std::string undo_text; + bool first_erase = false; + bool first_text_insert = false; + } undo_info; + + bool select_all_on_focus_gain = false; + + std::shared_ptr font = Font::Create("NotoSans", 12.0); + + template + static T clamp(T val, T minval, T maxval) { return std::max(std::min(val, maxval), minval); } +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h b/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h new file mode 100644 index 00000000000..45515dfcb42 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h @@ -0,0 +1,33 @@ + +#pragma once + +#include "../../core/widget.h" + +enum TextLabelAlignment +{ + Left, + Center, + Right +}; + +class TextLabel : public Widget +{ +public: + TextLabel(Widget* parent = nullptr); + + void SetText(const std::string& value); + const std::string& GetText() const; + + void SetTextAlignment(TextLabelAlignment alignment); + TextLabelAlignment GetTextAlignment() const; + + double GetPreferredWidth() const; + double GetPreferredHeight() const; + +protected: + void OnPaint(Canvas* canvas) override; + +private: + std::string text; + TextLabelAlignment textAlignment = TextLabelAlignment::Left; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/toolbar/toolbar.h b/libraries/ZWidget/include/zwidget/widgets/toolbar/toolbar.h new file mode 100644 index 00000000000..ca0a89c0dc1 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/toolbar/toolbar.h @@ -0,0 +1,11 @@ + +#pragma once + +#include "../../core/widget.h" + +class Toolbar : public Widget +{ +public: + Toolbar(Widget* parent); + ~Toolbar(); +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/toolbar/toolbarbutton.h b/libraries/ZWidget/include/zwidget/widgets/toolbar/toolbarbutton.h new file mode 100644 index 00000000000..933a6517ed7 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/toolbar/toolbarbutton.h @@ -0,0 +1,14 @@ + +#pragma once + +#include "../../core/widget.h" + +class ToolbarButton : public Widget +{ +public: + ToolbarButton(Widget* parent); + ~ToolbarButton(); + +protected: + void OnPaint(Canvas* canvas) override; +}; diff --git a/libraries/ZWidget/include/zwidget/window/window.h b/libraries/ZWidget/include/zwidget/window/window.h new file mode 100644 index 00000000000..0539f773f8a --- /dev/null +++ b/libraries/ZWidget/include/zwidget/window/window.h @@ -0,0 +1,186 @@ +#pragma once + +#include +#include +#include +#include "../core/rect.h" + +class Engine; + +enum class StandardCursor +{ + arrow, + appstarting, + cross, + hand, + ibeam, + no, + size_all, + size_nesw, + size_ns, + size_nwse, + size_we, + uparrow, + wait +}; + +enum EInputKey +{ + IK_None, IK_LeftMouse, IK_RightMouse, IK_Cancel, + IK_MiddleMouse, IK_Unknown05, IK_Unknown06, IK_Unknown07, + IK_Backspace, IK_Tab, IK_Unknown0A, IK_Unknown0B, + IK_Unknown0C, IK_Enter, IK_Unknown0E, IK_Unknown0F, + IK_Shift, IK_Ctrl, IK_Alt, IK_Pause, + IK_CapsLock, IK_Unknown15, IK_Unknown16, IK_Unknown17, + IK_Unknown18, IK_Unknown19, IK_Unknown1A, IK_Escape, + IK_Unknown1C, IK_Unknown1D, IK_Unknown1E, IK_Unknown1F, + IK_Space, IK_PageUp, IK_PageDown, IK_End, + IK_Home, IK_Left, IK_Up, IK_Right, + IK_Down, IK_Select, IK_Print, IK_Execute, + IK_PrintScrn, IK_Insert, IK_Delete, IK_Help, + IK_0, IK_1, IK_2, IK_3, + IK_4, IK_5, IK_6, IK_7, + IK_8, IK_9, IK_Unknown3A, IK_Unknown3B, + IK_Unknown3C, IK_Unknown3D, IK_Unknown3E, IK_Unknown3F, + IK_Unknown40, IK_A, IK_B, IK_C, + IK_D, IK_E, IK_F, IK_G, + IK_H, IK_I, IK_J, IK_K, + IK_L, IK_M, IK_N, IK_O, + IK_P, IK_Q, IK_R, IK_S, + IK_T, IK_U, IK_V, IK_W, + IK_X, IK_Y, IK_Z, IK_Unknown5B, + IK_Unknown5C, IK_Unknown5D, IK_Unknown5E, IK_Unknown5F, + IK_NumPad0, IK_NumPad1, IK_NumPad2, IK_NumPad3, + IK_NumPad4, IK_NumPad5, IK_NumPad6, IK_NumPad7, + IK_NumPad8, IK_NumPad9, IK_GreyStar, IK_GreyPlus, + IK_Separator, IK_GreyMinus, IK_NumPadPeriod, IK_GreySlash, + IK_F1, IK_F2, IK_F3, IK_F4, + IK_F5, IK_F6, IK_F7, IK_F8, + IK_F9, IK_F10, IK_F11, IK_F12, + IK_F13, IK_F14, IK_F15, IK_F16, + IK_F17, IK_F18, IK_F19, IK_F20, + IK_F21, IK_F22, IK_F23, IK_F24, + IK_Unknown88, IK_Unknown89, IK_Unknown8A, IK_Unknown8B, + IK_Unknown8C, IK_Unknown8D, IK_Unknown8E, IK_Unknown8F, + IK_NumLock, IK_ScrollLock, IK_Unknown92, IK_Unknown93, + IK_Unknown94, IK_Unknown95, IK_Unknown96, IK_Unknown97, + IK_Unknown98, IK_Unknown99, IK_Unknown9A, IK_Unknown9B, + IK_Unknown9C, IK_Unknown9D, IK_Unknown9E, IK_Unknown9F, + IK_LShift, IK_RShift, IK_LControl, IK_RControl, + IK_UnknownA4, IK_UnknownA5, IK_UnknownA6, IK_UnknownA7, + IK_UnknownA8, IK_UnknownA9, IK_UnknownAA, IK_UnknownAB, + IK_UnknownAC, IK_UnknownAD, IK_UnknownAE, IK_UnknownAF, + IK_UnknownB0, IK_UnknownB1, IK_UnknownB2, IK_UnknownB3, + IK_UnknownB4, IK_UnknownB5, IK_UnknownB6, IK_UnknownB7, + IK_UnknownB8, IK_UnknownB9, IK_Semicolon, IK_Equals, + IK_Comma, IK_Minus, IK_Period, IK_Slash, + IK_Tilde, IK_UnknownC1, IK_UnknownC2, IK_UnknownC3, + IK_UnknownC4, IK_UnknownC5, IK_UnknownC6, IK_UnknownC7, + IK_Joy1, IK_Joy2, IK_Joy3, IK_Joy4, + IK_Joy5, IK_Joy6, IK_Joy7, IK_Joy8, + IK_Joy9, IK_Joy10, IK_Joy11, IK_Joy12, + IK_Joy13, IK_Joy14, IK_Joy15, IK_Joy16, + IK_UnknownD8, IK_UnknownD9, IK_UnknownDA, IK_LeftBracket, + IK_Backslash, IK_RightBracket, IK_SingleQuote, IK_UnknownDF, + IK_JoyX, IK_JoyY, IK_JoyZ, IK_JoyR, + IK_MouseX, IK_MouseY, IK_MouseZ, IK_MouseW, + IK_JoyU, IK_JoyV, IK_UnknownEA, IK_UnknownEB, + IK_MouseWheelUp, IK_MouseWheelDown, IK_Unknown10E, IK_Unknown10F, + IK_JoyPovUp, IK_JoyPovDown, IK_JoyPovLeft, IK_JoyPovRight, + IK_UnknownF4, IK_UnknownF5, IK_Attn, IK_CrSel, + IK_ExSel, IK_ErEof, IK_Play, IK_Zoom, + IK_NoName, IK_PA1, IK_OEMClear +}; + +enum EInputType +{ + IST_None, + IST_Press, + IST_Hold, + IST_Release, + IST_Axis +}; + +class KeyEvent +{ +public: + EInputKey Key; + bool Ctrl = false; + bool Alt = false; + bool Shift = false; + Point MousePos = Point(0.0, 0.0); +}; + +class DisplayWindow; + +class DisplayWindowHost +{ +public: + virtual void OnWindowPaint() = 0; + virtual void OnWindowMouseMove(const Point& pos) = 0; + virtual void OnWindowMouseDown(const Point& pos, EInputKey key) = 0; + virtual void OnWindowMouseDoubleclick(const Point& pos, EInputKey key) = 0; + virtual void OnWindowMouseUp(const Point& pos, EInputKey key) = 0; + virtual void OnWindowMouseWheel(const Point& pos, EInputKey key) = 0; + virtual void OnWindowRawMouseMove(int dx, int dy) = 0; + virtual void OnWindowKeyChar(std::string chars) = 0; + virtual void OnWindowKeyDown(EInputKey key) = 0; + virtual void OnWindowKeyUp(EInputKey key) = 0; + virtual void OnWindowGeometryChanged() = 0; + virtual void OnWindowClose() = 0; + virtual void OnWindowActivated() = 0; + virtual void OnWindowDeactivated() = 0; + virtual void OnWindowDpiScaleChanged() = 0; +}; + +class DisplayWindow +{ +public: + static std::unique_ptr Create(DisplayWindowHost* windowHost); + + static void ProcessEvents(); + static void RunLoop(); + static void ExitLoop(); + + static void* StartTimer(int timeoutMilliseconds, std::function onTimer); + static void StopTimer(void* timerID); + + static Size GetScreenSize(); + + virtual ~DisplayWindow() = default; + + virtual void SetWindowTitle(const std::string& text) = 0; + virtual void SetWindowFrame(const Rect& box) = 0; + virtual void SetClientFrame(const Rect& box) = 0; + virtual void Show() = 0; + virtual void ShowFullscreen() = 0; + virtual void ShowMaximized() = 0; + virtual void ShowMinimized() = 0; + virtual void ShowNormal() = 0; + virtual void Hide() = 0; + virtual void Activate() = 0; + virtual void ShowCursor(bool enable) = 0; + virtual void LockCursor() = 0; + virtual void UnlockCursor() = 0; + virtual void CaptureMouse() = 0; + virtual void ReleaseMouseCapture() = 0; + virtual void Update() = 0; + virtual bool GetKeyState(EInputKey key) = 0; + + virtual void SetCursor(StandardCursor cursor) = 0; + + virtual Rect GetWindowFrame() const = 0; + virtual Size GetClientSize() const = 0; + virtual int GetPixelWidth() const = 0; + virtual int GetPixelHeight() const = 0; + virtual double GetDpiScale() const = 0; + + virtual void SetBorderColor(uint32_t bgra8) = 0; + virtual void SetCaptionColor(uint32_t bgra8) = 0; + virtual void SetCaptionTextColor(uint32_t bgra8) = 0; + + virtual void PresentBitmap(int width, int height, const uint32_t* pixels) = 0; + + virtual std::string GetClipboardText() = 0; + virtual void SetClipboardText(const std::string& text) = 0; +}; diff --git a/libraries/ZWidget/src/core/canvas.cpp b/libraries/ZWidget/src/core/canvas.cpp new file mode 100644 index 00000000000..76c7a16e792 --- /dev/null +++ b/libraries/ZWidget/src/core/canvas.cpp @@ -0,0 +1,696 @@ + +#include "core/canvas.h" +#include "core/rect.h" +#include "core/colorf.h" +#include "core/utf8reader.h" +#include "core/resourcedata.h" +#include "core/image.h" +#include "core/truetypefont.h" +#include "core/pathfill.h" +#include "window/window.h" +#include +#include +#include +#include + +class CanvasTexture +{ +public: + int Width = 0; + int Height = 0; + std::vector Data; +}; + +class CanvasGlyph +{ +public: + struct + { + double leftSideBearing = 0.0; + double yOffset = 0.0; + double advanceWidth = 0.0; + } metrics; + + double u = 0.0; + double v = 0.0; + double uvwidth = 0.0f; + double uvheight = 0.0f; + std::shared_ptr texture; +}; + +class CanvasFont +{ +public: + CanvasFont(const std::string& fontname, double height, std::vector& _data) : fontname(fontname), height(height) + { + auto tdata = std::make_shared(_data); + ttf = std::make_unique(tdata); + textmetrics = ttf->GetTextMetrics(height); + } + + ~CanvasFont() + { + } + + CanvasGlyph* getGlyph(uint32_t utfchar) + { + uint32_t glyphIndex = ttf->GetGlyphIndex(utfchar); + if (glyphIndex == 0) return nullptr; + + auto& glyph = glyphs[glyphIndex]; + if (glyph) + return glyph.get(); + + glyph = std::make_unique(); + + TrueTypeGlyph ttfglyph = ttf->LoadGlyph(glyphIndex, height); + + // Create final subpixel version + int w = ttfglyph.width; + int h = ttfglyph.height; + int destwidth = (w + 2) / 3; + auto texture = std::make_shared(); + texture->Width = destwidth; + texture->Height = h; + texture->Data.resize(destwidth * h); + + uint8_t* grayscale = ttfglyph.grayscale.get(); + uint32_t* dest = (uint32_t*)texture->Data.data(); + for (int y = 0; y < h; y++) + { + uint8_t* sline = grayscale + y * w; + uint32_t* dline = dest + y * destwidth; + for (int x = 0; x < w; x += 3) + { + uint32_t values[5] = + { + x > 0 ? sline[x - 1] : 0U, + sline[x], + x + 1 < w ? sline[x + 1] : 0U, + x + 2 < w ? sline[x + 2] : 0U, + x + 3 < w ? sline[x + 3] : 0U + }; + + uint32_t red = (values[0] + values[1] + values[1] + values[2] + 2) >> 2; + uint32_t green = (values[1] + values[2] + values[2] + values[3] + 2) >> 2; + uint32_t blue = (values[2] + values[3] + values[3] + values[4] + 2) >> 2; + uint32_t alpha = (red | green | blue) ? 255 : 0; + + *(dline++) = (alpha << 24) | (red << 16) | (green << 8) | blue; + } + } + + glyph->u = 0.0; + glyph->v = 0.0; + glyph->uvwidth = destwidth; + glyph->uvheight = h; + glyph->texture = std::move(texture); + + glyph->metrics.advanceWidth = (ttfglyph.advanceWidth + 2) / 3; + glyph->metrics.leftSideBearing = (ttfglyph.leftSideBearing + 2) / 3; + glyph->metrics.yOffset = ttfglyph.yOffset; + + return glyph.get(); + } + + std::unique_ptr ttf; + + std::string fontname; + double height = 0.0; + + TrueTypeTextMetrics textmetrics; + std::unordered_map> glyphs; +}; + +class CanvasFontGroup +{ +public: + struct SingleFont + { + std::unique_ptr font; + std::string language; + }; + CanvasFontGroup(const std::string& fontname, double height) : height(height) + { + auto fontdata = LoadWidgetFontData(fontname); + fonts.resize(fontdata.size()); + for (size_t i = 0; i < fonts.size(); i++) + { + fonts[i].font = std::make_unique(fontname, height, fontdata[i].fontdata); + fonts[i].language = fontdata[i].language; + } + } + + CanvasGlyph* getGlyph(uint32_t utfchar, const char* lang = nullptr) + { + for (int i = 0; i < 2; i++) + { + for (auto& fd : fonts) + { + if (i == 1 || lang == nullptr || *lang == 0 || fd.language.empty() || fd.language == lang) + { + auto g = fd.font->getGlyph(utfchar); + if (g) return g; + } + } + } + + return nullptr; + } + + TrueTypeTextMetrics& GetTextMetrics() + { + return fonts[0].font->textmetrics; + } + + double height; + std::vector fonts; + +}; + +class BitmapCanvas : public Canvas +{ +public: + BitmapCanvas(DisplayWindow* window); + ~BitmapCanvas(); + + void begin(const Colorf& color) override; + void end() override; + + void begin3d() override; + void end3d() override; + + Point getOrigin() override; + void setOrigin(const Point& origin) override; + + void pushClip(const Rect& box) override; + void popClip() override; + + void fillRect(const Rect& box, const Colorf& color) override; + void line(const Point& p0, const Point& p1, const Colorf& color) override; + + void drawText(const Point& pos, const Colorf& color, const std::string& text) override; + Rect measureText(const std::string& text) override; + VerticalTextPosition verticalTextAlign() override; + + void drawText(const std::shared_ptr& font, const Point& pos, const std::string& text, const Colorf& color) override { drawText(pos, color, text); } + void drawTextEllipsis(const std::shared_ptr& font, const Point& pos, const Rect& clipBox, const std::string& text, const Colorf& color) override { drawText(pos, color, text); } + Rect measureText(const std::shared_ptr& font, const std::string& text) override { return measureText(text); } + FontMetrics getFontMetrics(const std::shared_ptr& font) override + { + VerticalTextPosition vtp = verticalTextAlign(); + FontMetrics metrics; + metrics.external_leading = vtp.top; + metrics.ascent = vtp.baseline - vtp.top; + metrics.descent = vtp.bottom - vtp.baseline; + metrics.height = metrics.ascent + metrics.descent; + return metrics; + } + int getCharacterIndex(const std::shared_ptr& font, const std::string& text, const Point& hitPoint) override { return 0; } + + void drawImage(const std::shared_ptr& image, const Point& pos) override; + + void drawLineUnclipped(const Point& p0, const Point& p1, const Colorf& color); + + void drawTile(CanvasTexture* texture, float x, float y, float width, float height, float u, float v, float uvwidth, float uvheight, Colorf color); + void drawGlyph(CanvasTexture* texture, float x, float y, float width, float height, float u, float v, float uvwidth, float uvheight, Colorf color); + + int getClipMinX() const; + int getClipMinY() const; + int getClipMaxX() const; + int getClipMaxY() const; + + void setLanguage(const char* lang) { language = lang; } + + std::unique_ptr createTexture(int width, int height, const void* pixels, ImageFormat format = ImageFormat::B8G8R8A8); + + template + static T clamp(T val, T minval, T maxval) { return std::max(std::min(val, maxval), minval); } + + DisplayWindow* window = nullptr; + + std::unique_ptr font; + std::unique_ptr whiteTexture; + + Point origin; + double uiscale = 1.0f; + std::vector clipStack; + + int width = 0; + int height = 0; + std::vector pixels; + + std::unordered_map, std::unique_ptr> imageTextures; + std::string language; +}; + +BitmapCanvas::BitmapCanvas(DisplayWindow* window) : window(window) +{ + uiscale = window->GetDpiScale(); + uint32_t white = 0xffffffff; + whiteTexture = createTexture(1, 1, &white); + font = std::make_unique("NotoSans", 13.0 * uiscale); +} + +BitmapCanvas::~BitmapCanvas() +{ +} + +Point BitmapCanvas::getOrigin() +{ + return origin; +} + +void BitmapCanvas::setOrigin(const Point& newOrigin) +{ + origin = newOrigin; +} + +void BitmapCanvas::pushClip(const Rect& box) +{ + if (!clipStack.empty()) + { + const Rect& clip = clipStack.back(); + + double x0 = box.x + origin.x; + double y0 = box.y + origin.y; + double x1 = x0 + box.width; + double y1 = y0 + box.height; + + x0 = std::max(x0, clip.x); + y0 = std::max(y0, clip.y); + x1 = std::min(x1, clip.x + clip.width); + y1 = std::min(y1, clip.y + clip.height); + + if (x0 < x1 && y0 < y1) + clipStack.push_back(Rect::ltrb(x0, y0, x1, y1)); + else + clipStack.push_back(Rect::xywh(0.0, 0.0, 0.0, 0.0)); + } + else + { + clipStack.push_back(box); + } +} + +void BitmapCanvas::popClip() +{ + clipStack.pop_back(); +} + +void BitmapCanvas::fillRect(const Rect& box, const Colorf& color) +{ + drawTile(whiteTexture.get(), (float)((origin.x + box.x) * uiscale), (float)((origin.y + box.y) * uiscale), (float)(box.width * uiscale), (float)(box.height * uiscale), 0.0, 0.0, 1.0, 1.0, color); +} + +void BitmapCanvas::drawImage(const std::shared_ptr& image, const Point& pos) +{ + auto& texture = imageTextures[image]; + if (!texture) + { + texture = createTexture(image->GetWidth(), image->GetHeight(), image->GetData(), image->GetFormat()); + } + Colorf color(1.0f, 1.0f, 1.0f); + drawTile(texture.get(), (float)((origin.x + pos.x) * uiscale), (float)((origin.y + pos.y) * uiscale), (float)(texture->Width * uiscale), (float)(texture->Height * uiscale), 0.0, 0.0, (float)texture->Width, (float)texture->Height, color); +} + +void BitmapCanvas::line(const Point& p0, const Point& p1, const Colorf& color) +{ + double x0 = origin.x + p0.x; + double y0 = origin.y + p0.y; + double x1 = origin.x + p1.x; + double y1 = origin.y + p1.y; + + if (clipStack.empty())// || (clipStack.back().contains({ x0, y0 }) && clipStack.back().contains({ x1, y1 }))) + { + drawLineUnclipped({ x0, y0 }, { x1, y1 }, color); + } + else + { + const Rect& clip = clipStack.back(); + + if (x0 > x1) + { + std::swap(x0, x1); + std::swap(y0, y1); + } + + if (x1 < clip.x || x0 >= clip.x + clip.width) + return; + + // Clip left edge + if (x0 < clip.x) + { + double dx = x1 - x0; + double dy = y1 - y0; + if (std::abs(dx) < 0.0001) + return; + y0 = y0 + (clip.x - x0) * dy / dx; + x0 = clip.x; + } + + // Clip right edge + if (x1 > clip.x + clip.width) + { + double dx = x1 - x0; + double dy = y1 - y0; + if (std::abs(dx) < 0.0001) + return; + y1 = y1 + (clip.x + clip.width - x1) * dy / dx; + x1 = clip.x + clip.width; + } + + if (y0 > y1) + { + std::swap(x0, x1); + std::swap(y0, y1); + } + + if (y1 < clip.y || y0 >= clip.y + clip.height) + return; + + // Clip top edge + if (y0 < clip.y) + { + double dx = x1 - x0; + double dy = y1 - y0; + if (std::abs(dy) < 0.0001) + return; + x0 = x0 + (clip.y - y0) * dx / dy; + y0 = clip.y; + } + + // Clip bottom edge + if (y1 > clip.y + clip.height) + { + double dx = x1 - x0; + double dy = y1 - y0; + if (std::abs(dy) < 0.0001) + return; + x1 = x1 + (clip.y + clip.height - y1) * dx / dy; + y1 = clip.y + clip.height; + } + + x0 = clamp(x0, clip.x, clip.x + clip.width); + x1 = clamp(x1, clip.x, clip.x + clip.width); + y0 = clamp(y0, clip.y, clip.y + clip.height); + y1 = clamp(y1, clip.y, clip.y + clip.height); + + if (x0 != x1 || y0 != y1) + drawLineUnclipped({ x0, y0 }, { x1, y1 }, color); + } +} + +void BitmapCanvas::drawText(const Point& pos, const Colorf& color, const std::string& text) +{ + double x = std::round((origin.x + pos.x) * uiscale); + double y = std::round((origin.y + pos.y) * uiscale); + + UTF8Reader reader(text.data(), text.size()); + while (!reader.is_end()) + { + CanvasGlyph* glyph = font->getGlyph(reader.character(), language.c_str()); + if (!glyph || !glyph->texture) + { + glyph = font->getGlyph(32); + } + + if (glyph->texture) + { + double gx = std::round(x + glyph->metrics.leftSideBearing); + double gy = std::round(y + glyph->metrics.yOffset); + drawGlyph(glyph->texture.get(), (float)std::round(gx), (float)std::round(gy), (float)glyph->uvwidth, (float)glyph->uvheight, (float)glyph->u, (float)glyph->v, (float)glyph->uvwidth, (float)glyph->uvheight, color); + } + + x += std::round(glyph->metrics.advanceWidth); + reader.next(); + } +} + +Rect BitmapCanvas::measureText(const std::string& text) +{ + double x = 0.0; + double y = font->GetTextMetrics().ascender - font->GetTextMetrics().descender; + + UTF8Reader reader(text.data(), text.size()); + while (!reader.is_end()) + { + CanvasGlyph* glyph = font->getGlyph(reader.character(), language.c_str()); + if (!glyph || !glyph->texture) + { + glyph = font->getGlyph(32); + } + + x += std::round(glyph->metrics.advanceWidth); + reader.next(); + } + + return Rect::xywh(0.0, 0.0, x / uiscale, y / uiscale); +} + +VerticalTextPosition BitmapCanvas::verticalTextAlign() +{ + VerticalTextPosition align; + align.top = 0.0f; + auto tm = font->GetTextMetrics(); + align.baseline = tm.ascender / uiscale; + align.bottom = (tm.ascender - tm.descender) / uiscale; + return align; +} + +std::unique_ptr BitmapCanvas::createTexture(int width, int height, const void* pixels, ImageFormat format) +{ + auto texture = std::make_unique(); + texture->Width = width; + texture->Height = height; + texture->Data.resize(width * height); + if (format == ImageFormat::B8G8R8A8) + { + memcpy(texture->Data.data(), pixels, width * height * sizeof(uint32_t)); + } + else + { + const uint32_t* src = (const uint32_t*)pixels; + uint32_t* dest = texture->Data.data(); + int count = width * height; + for (int i = 0; i < count; i++) + { + uint32_t a = (src[i] >> 24) & 0xff; + uint32_t b = (src[i] >> 16) & 0xff; + uint32_t g = (src[i] >> 8) & 0xff; + uint32_t r = src[i] & 0xff; + dest[i] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + return texture; +} + +void BitmapCanvas::drawLineUnclipped(const Point& p0, const Point& p1, const Colorf& color) +{ + if (p0.x == p1.x) + { + drawTile(whiteTexture.get(), (float)((p0.x - 0.5) * uiscale), (float)(p0.y * uiscale), (float)((p1.x + 0.5) * uiscale), (float)(p1.y * uiscale), 0.0f, 0.0f, 1.0f, 1.0f, color); + } + else if (p0.y == p1.y) + { + drawTile(whiteTexture.get(), (float)(p0.x * uiscale), (float)((p0.y - 0.5) * uiscale), (float)(p1.x * uiscale), (float)((p1.y + 0.5) * uiscale), 0.0f, 0.0f, 1.0f, 1.0f, color); + } + else + { + // To do: draw line using bresenham + } +} + +int BitmapCanvas::getClipMinX() const +{ + return clipStack.empty() ? 0 : (int)std::max(clipStack.back().x * uiscale, 0.0); +} + +int BitmapCanvas::getClipMinY() const +{ + return clipStack.empty() ? 0 : (int)std::max(clipStack.back().y * uiscale, 0.0); +} + +int BitmapCanvas::getClipMaxX() const +{ + return clipStack.empty() ? width : (int)std::min((clipStack.back().x + clipStack.back().width) * uiscale, (double)width); +} + +int BitmapCanvas::getClipMaxY() const +{ + return clipStack.empty() ? height : (int)std::min((clipStack.back().y + clipStack.back().height) * uiscale, (double)height); +} + +void BitmapCanvas::drawTile(CanvasTexture* texture, float left, float top, float width, float height, float u, float v, float uvwidth, float uvheight, Colorf color) +{ + if (width <= 0.0f || height <= 0.0f) + return; + + int swidth = texture->Width; + int sheight = texture->Height; + const uint32_t* src = texture->Data.data(); + + int dwidth = this->width; + int dheight = this->height; + uint32_t* dest = this->pixels.data(); + + int x0 = (int)left; + int x1 = (int)(left + width); + int y0 = (int)top; + int y1 = (int)(top + height); + + x0 = std::max(x0, getClipMinX()); + y0 = std::max(y0, getClipMinY()); + x1 = std::min(x1, getClipMaxX()); + y1 = std::min(y1, getClipMaxY()); + if (x1 <= x0 || y1 <= y0) + return; + + uint32_t cred = (int32_t)clamp(color.r * 256.0f, 0.0f, 256.0f); + uint32_t cgreen = (int32_t)clamp(color.g * 256.0f, 0.0f, 256.0f); + uint32_t cblue = (int32_t)clamp(color.b * 256.0f, 0.0f, 256.0f); + uint32_t calpha = (int32_t)clamp(color.a * 256.0f, 0.0f, 256.0f); + + float uscale = uvwidth / width; + float vscale = uvheight / height; + + for (int y = y0; y < y1; y++) + { + float vpix = v + vscale * (y + 0.5f - top); + const uint32_t* sline = src + ((int)vpix) * swidth; + + uint32_t* dline = dest + y * dwidth; + for (int x = x0; x < x1; x++) + { + float upix = u + uscale * (x + 0.5f - left); + uint32_t spixel = sline[(int)upix]; + uint32_t salpha = spixel >> 24; + uint32_t sred = (spixel >> 16) & 0xff; + uint32_t sgreen = (spixel >> 8) & 0xff; + uint32_t sblue = spixel & 0xff; + + uint32_t dpixel = dline[x]; + uint32_t dalpha = dpixel >> 24; + uint32_t dred = (dpixel >> 16) & 0xff; + uint32_t dgreen = (dpixel >> 8) & 0xff; + uint32_t dblue = dpixel & 0xff; + + // Pixel shade + sred = (cred * sred + 127) >> 8; + sgreen = (cgreen * sgreen + 127) >> 8; + sblue = (cblue * sblue + 127) >> 8; + salpha = (calpha * salpha + 127) >> 8; + + // Rescale from [0,255] to [0,256] + uint32_t sa = salpha + (salpha >> 7); + uint32_t sinva = 256 - sa; + + // dest.rgba = color.rgba * src.rgba * src.a + dest.rgba * (1-src.a) + uint32_t a = (salpha * sa + dalpha * sinva + 127) >> 8; + uint32_t r = (sred * sa + dred * sinva + 127) >> 8; + uint32_t g = (sgreen * sa + dgreen * sinva + 127) >> 8; + uint32_t b = (sblue * sa + dblue * sinva + 127) >> 8; + dline[x] = (a << 24) | (r << 16) | (g << 8) | b; + } + } +} + +void BitmapCanvas::drawGlyph(CanvasTexture* texture, float left, float top, float width, float height, float u, float v, float uvwidth, float uvheight, Colorf color) +{ + if (width <= 0.0f || height <= 0.0f) + return; + + int swidth = texture->Width; + int sheight = texture->Height; + const uint32_t* src = texture->Data.data(); + + int dwidth = this->width; + int dheight = this->height; + uint32_t* dest = this->pixels.data(); + + int x0 = (int)left; + int x1 = (int)(left + width); + int y0 = (int)top; + int y1 = (int)(top + height); + + x0 = std::max(x0, getClipMinX()); + y0 = std::max(y0, getClipMinY()); + x1 = std::min(x1, getClipMaxX()); + y1 = std::min(y1, getClipMaxY()); + if (x1 <= x0 || y1 <= y0) + return; + + uint32_t cred = (int32_t)clamp(color.r * 255.0f, 0.0f, 255.0f); + uint32_t cgreen = (int32_t)clamp(color.g * 255.0f, 0.0f, 255.0f); + uint32_t cblue = (int32_t)clamp(color.b * 255.0f, 0.0f, 255.0f); + + float uscale = uvwidth / width; + float vscale = uvheight / height; + + for (int y = y0; y < y1; y++) + { + float vpix = v + vscale * (y + 0.5f - top); + const uint32_t* sline = src + ((int)vpix) * swidth; + + uint32_t* dline = dest + y * dwidth; + for (int x = x0; x < x1; x++) + { + float upix = u + uscale * (x + 0.5f - left); + uint32_t spixel = sline[(int)upix]; + uint32_t sred = (spixel >> 16) & 0xff; + uint32_t sgreen = (spixel >> 8) & 0xff; + uint32_t sblue = spixel & 0xff; + + uint32_t dpixel = dline[x]; + uint32_t dred = (dpixel >> 16) & 0xff; + uint32_t dgreen = (dpixel >> 8) & 0xff; + uint32_t dblue = dpixel & 0xff; + + // Rescale from [0,255] to [0,256] + sred += sred >> 7; + sgreen += sgreen >> 7; + sblue += sblue >> 7; + + // dest.rgb = color.rgb * src.rgb + dest.rgb * (1-src.rgb) + uint32_t r = (cred * sred + dred * (256 - sred) + 127) >> 8; + uint32_t g = (cgreen * sgreen + dgreen * (256 - sgreen) + 127) >> 8; + uint32_t b = (cblue * sblue + dblue * (256 - sblue) + 127) >> 8; + dline[x] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } +} + +void BitmapCanvas::begin(const Colorf& color) +{ + uiscale = window->GetDpiScale(); + + uint32_t r = (int32_t)clamp(color.r * 255.0f, 0.0f, 255.0f); + uint32_t g = (int32_t)clamp(color.g * 255.0f, 0.0f, 255.0f); + uint32_t b = (int32_t)clamp(color.b * 255.0f, 0.0f, 255.0f); + uint32_t a = (int32_t)clamp(color.a * 255.0f, 0.0f, 255.0f); + uint32_t bgcolor = (a << 24) | (r << 16) | (g << 8) | b; + width = window->GetPixelWidth(); + height = window->GetPixelHeight(); + pixels.clear(); + pixels.resize(width * height, bgcolor); +} + +void BitmapCanvas::end() +{ + window->PresentBitmap(width, height, pixels.data()); +} + +void BitmapCanvas::begin3d() +{ +} + +void BitmapCanvas::end3d() +{ +} + +///////////////////////////////////////////////////////////////////////////// + +std::unique_ptr Canvas::create(DisplayWindow* window) +{ + return std::make_unique(window); +} diff --git a/libraries/ZWidget/src/core/font.cpp b/libraries/ZWidget/src/core/font.cpp new file mode 100644 index 00000000000..f646912a9c2 --- /dev/null +++ b/libraries/ZWidget/src/core/font.cpp @@ -0,0 +1,28 @@ + +#include "core/font.h" + +class FontImpl : public Font +{ +public: + FontImpl(const std::string& name, double height) : Name(name), Height(height) + { + } + + const std::string& GetName() const override + { + return Name; + } + + double GetHeight() const override + { + return Height; + } + + std::string Name; + double Height = 0.0; +}; + +std::shared_ptr Font::Create(const std::string& name, double height) +{ + return std::make_shared(name, height); +} diff --git a/libraries/ZWidget/src/core/image.cpp b/libraries/ZWidget/src/core/image.cpp new file mode 100644 index 00000000000..3998d78e81f --- /dev/null +++ b/libraries/ZWidget/src/core/image.cpp @@ -0,0 +1,110 @@ + +#include "core/image.h" +#include "core/resourcedata.h" +#include "picopng/picopng.h" +#include "nanosvg/nanosvg.h" +#include "nanosvg/nanosvgrast.h" +#include +#include + +class ImageImpl : public Image +{ +public: + ImageImpl(int width, int height, ImageFormat format, const void* data) : Width(width), Height(height), Format(format) + { + Data = std::make_unique(width * height); + if (data) + memcpy(Data.get(), data, width * height * sizeof(uint32_t)); + } + + int GetWidth() const override + { + return Width; + } + + int GetHeight() const override + { + return Height; + } + + ImageFormat GetFormat() const override + { + return Format; + } + + void* GetData() const override + { + return Data.get(); + } + + int Width = 0; + int Height = 0; + ImageFormat Format = {}; + std::unique_ptr Data; +}; + +std::shared_ptr Image::Create(int width, int height, ImageFormat format, const void* data) +{ + return std::make_shared(width, height, format, data); +} + +std::shared_ptr Image::LoadResource(const std::string& resourcename, double dpiscale) +{ + size_t extensionpos = resourcename.find_last_of("./\\"); + if (extensionpos == std::string::npos || resourcename[extensionpos] != '.') + throw std::runtime_error("Unsupported image format"); + std::string extension = resourcename.substr(extensionpos + 1); + for (char& c : extension) + { + if (c >= 'A' && c <= 'Z') + c = c - 'A' + 'a'; + } + + if (extension == "png") + { + auto filedata = LoadWidgetData(resourcename); + + std::vector pixels; + unsigned long width = 0, height = 0; + int result = decodePNG(pixels, width, height, (const unsigned char*)filedata.data(), filedata.size(), true); + if (result != 0) + throw std::runtime_error("Could not decode PNG file"); + + return Image::Create(width, height, ImageFormat::R8G8B8A8, pixels.data()); + } + else if (extension == "svg") + { + auto filedata = LoadWidgetData(resourcename); + filedata.push_back(0); + + NSVGimage* svgimage = nsvgParse((char*)filedata.data(), "px", (float)(96.0 * dpiscale)); + if (!svgimage) + throw std::runtime_error("Could not parse SVG file"); + + try + { + int width = (int)(svgimage->width * dpiscale); + int height = (int)(svgimage->height * dpiscale); + std::shared_ptr image = Image::Create(width, height, ImageFormat::R8G8B8A8, nullptr); + + NSVGrasterizer* rast = nsvgCreateRasterizer(); + if (!rast) + throw std::runtime_error("Could not create SVG rasterizer"); + + nsvgRasterize(rast, svgimage, 0.0f, 0.0f, (float)dpiscale, (unsigned char*)image->GetData(), width, height, width * 4); + + nsvgDeleteRasterizer(rast); + nsvgDelete(svgimage); + return image; + } + catch (...) + { + nsvgDelete(svgimage); + throw; + } + } + else + { + throw std::runtime_error("Unsupported image format"); + } +} diff --git a/libraries/ZWidget/src/core/nanosvg/nanosvg.cpp b/libraries/ZWidget/src/core/nanosvg/nanosvg.cpp new file mode 100644 index 00000000000..764b854b078 --- /dev/null +++ b/libraries/ZWidget/src/core/nanosvg/nanosvg.cpp @@ -0,0 +1,6 @@ + +#define NANOSVG_IMPLEMENTATION +#include "nanosvg.h" + +#define NANOSVGRAST_IMPLEMENTATION +#include "nanosvgrast.h" diff --git a/libraries/ZWidget/src/core/nanosvg/nanosvg.h b/libraries/ZWidget/src/core/nanosvg/nanosvg.h new file mode 100644 index 00000000000..55f9bc5ea4e --- /dev/null +++ b/libraries/ZWidget/src/core/nanosvg/nanosvg.h @@ -0,0 +1,3107 @@ +/* + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example + * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/) + * + * Arc calculation code based on canvg (https://code.google.com/p/canvg/) + * + * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + * + */ + +#ifndef NANOSVG_H +#define NANOSVG_H + +#ifndef NANOSVG_CPLUSPLUS +#ifdef __cplusplus +extern "C" { +#endif +#endif + +// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. +// +// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game. +// +// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request! +// +// The shapes in the SVG images are transformed by the viewBox and converted to specified units. +// That is, you should get the same looking data as your designed in your favorite app. +// +// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose +// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters. +// +// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. +// DPI (dots-per-inch) controls how the unit conversion is done. +// +// If you don't know or care about the units stuff, "px" and 96 should get you going. + + +/* Example Usage: + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); +*/ + +enum NSVGpaintType { + NSVG_PAINT_UNDEF = -1, + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 +}; + +enum NSVGspreadType { + NSVG_SPREAD_PAD = 0, + NSVG_SPREAD_REFLECT = 1, + NSVG_SPREAD_REPEAT = 2 +}; + +enum NSVGlineJoin { + NSVG_JOIN_MITER = 0, + NSVG_JOIN_ROUND = 1, + NSVG_JOIN_BEVEL = 2 +}; + +enum NSVGlineCap { + NSVG_CAP_BUTT = 0, + NSVG_CAP_ROUND = 1, + NSVG_CAP_SQUARE = 2 +}; + +enum NSVGfillRule { + NSVG_FILLRULE_NONZERO = 0, + NSVG_FILLRULE_EVENODD = 1 +}; + +enum NSVGflags { + NSVG_FLAGS_VISIBLE = 0x01 +}; + +typedef struct NSVGgradientStop { + unsigned int color; + float offset; +} NSVGgradientStop; + +typedef struct NSVGgradient { + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; +} NSVGgradient; + +typedef struct NSVGpaint { + signed char type; + union { + unsigned int color; + NSVGgradient* gradient; + }; +} NSVGpaint; + +typedef struct NSVGpath +{ + float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath* next; // Pointer to next path, or NULL if last element. +} NSVGpath; + +typedef struct NSVGshape +{ + char id[64]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + char fillGradient[64]; // Optional 'id' of fill gradient + char strokeGradient[64]; // Optional 'id' of stroke gradient + float xform[6]; // Root transformation for fill/stroke gradient + NSVGpath* paths; // Linked list of paths in the image. + struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +} NSVGshape; + +typedef struct NSVGimage +{ + float width; // Width of the image. + float height; // Height of the image. + NSVGshape* shapes; // Linked list of shapes in the image. +} NSVGimage; + +// Parses SVG file from a file, returns SVG image as paths. +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); + +// Parses SVG file from a null terminated string, returns SVG image as paths. +// Important note: changes the string. +NSVGimage* nsvgParse(char* input, const char* units, float dpi); + +// Duplicates a path. +NSVGpath* nsvgDuplicatePath(NSVGpath* p); + +// Deletes an image. +void nsvgDelete(NSVGimage* image); + +#ifndef NANOSVG_CPLUSPLUS +#ifdef __cplusplus +} +#endif +#endif + +#ifdef NANOSVG_IMPLEMENTATION + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4244) +#endif + +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. + +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_SLICE 2 + +#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) + +#ifdef _MSC_VER + #pragma warning (disable: 4996) // Switch off security warnings + #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings + #ifdef __cplusplus + #define NSVG_INLINE inline + #else + #define NSVG_INLINE + #endif +#else + #define NSVG_INLINE inline +#endif + + +static int nsvg__isspace(char c) +{ + return strchr(" \t\n\v\f\r", c) != 0; +} + +static int nsvg__isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } +static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } + + +// Simple XML parser + +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 +#define NSVG_XML_MAX_ATTRIBS 256 + +static void nsvg__parseContent(char* s, + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + // Trim start white spaces + while (*s && nsvg__isspace(*s)) s++; + if (!*s) return; + + if (contentCb) + (*contentCb)(ud, s); +} + +static void nsvg__parseElement(char* s, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void* ud) +{ + const char* attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char* name; + int start = 0; + int end = 0; + char quote; + + // Skip white space after the '<' + while (*s && nsvg__isspace(*s)) s++; + + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } else { + start = 1; + } + + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; + + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) s++; + if (*s) { *s++ = '\0'; } + + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { + char* name = NULL; + char* value = NULL; + + // Skip white space before the attrib name + while (*s && nsvg__isspace(*s)) s++; + if (!*s) break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') s++; + if (*s) { *s++ = '\0'; } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') s++; + if (!*s) break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) s++; + if (*s) { *s++ = '\0'; } + + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } + + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; + + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); +} + +int nsvg__parseXML(char* input, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + char* s = input; + char* mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } else { + s++; + } + } + + return 1; +} + + +/* Simple SVG parser. */ + +#define NSVG_MAX_ATTR 128 + +enum NSVGgradientUnits { + NSVG_USER_SPACE = 0, + NSVG_OBJECT_SPACE = 1 +}; + +#define NSVG_MAX_DASHES 8 + +enum NSVGunits { + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX +}; + +typedef struct NSVGcoordinate { + float value; + int units; +} NSVGcoordinate; + +typedef struct NSVGlinearData { + NSVGcoordinate x1, y1, x2, y2; +} NSVGlinearData; + +typedef struct NSVGradialData { + NSVGcoordinate cx, cy, r, fx, fy; +} NSVGradialData; + +typedef struct NSVGgradientData +{ + char id[64]; + char ref[64]; + signed char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop* stops; + struct NSVGgradientData* next; +} NSVGgradientData; + +typedef struct NSVGattrib +{ + char id[64]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[64]; + char strokeGradient[64]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; +} NSVGattrib; + +typedef struct NSVGparser +{ + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float* pts; + int npts; + int cpts; + NSVGpath* plist; + NSVGimage* image; + NSVGgradientData* gradients; + NSVGshape* shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; +} NSVGparser; + +static void nsvg__xformIdentity(float* t) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetTranslation(float* t, float tx, float ty) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = tx; t[5] = ty; +} + +static void nsvg__xformSetScale(float* t, float sx, float sy) +{ + t[0] = sx; t[1] = 0.0f; + t[2] = 0.0f; t[3] = sy; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewX(float* t, float a) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = tanf(a); t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewY(float* t, float a) +{ + t[0] = 1.0f; t[1] = tanf(a); + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetRotation(float* t, float a) +{ + float cs = cosf(a), sn = sinf(a); + t[0] = cs; t[1] = sn; + t[2] = -sn; t[3] = cs; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformMultiply(float* t, float* s) +{ + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; +} + +static void nsvg__xformInverse(float* inv, float* t) +{ + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +} + +static void nsvg__xformPremultiply(float* t, float* s) +{ + float s2[6]; + memcpy(s2, s, sizeof(float)*6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float)*6); +} + +static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2] + t[4]; + *dy = x*t[1] + y*t[3] + t[5]; +} + +static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2]; + *dy = x*t[1] + y*t[3]; +} + +#define NSVG_EPSILON (1e-12) + +static int nsvg__ptInBounds(float* pt, float* bounds) +{ + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +} + + +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) +{ + double it = 1.0-t; + return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; +} + +static void nsvg__curveBounds(float* bounds, float* curve) +{ + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float* v0 = &curve[0]; + float* v1 = &curve[2]; + float* v2 = &curve[4]; + float* v3 = &curve[6]; + + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); + + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; + + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } else { + b2ac = b*b - 4.0*c*a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); + bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); + } + } +} + +static NSVGparser* nsvg__createParser(void) +{ + NSVGparser* p; + p = (NSVGparser*)malloc(sizeof(NSVGparser)); + if (p == NULL) goto error; + memset(p, 0, sizeof(NSVGparser)); + + p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); + if (p->image == NULL) goto error; + memset(p->image, 0, sizeof(NSVGimage)); + + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0,0,0); + p->attr[0].strokeColor = NSVG_RGB(0,0,0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; + + return p; + +error: + if (p) { + if (p->image) free(p->image); + free(p); + } + return NULL; +} + +static void nsvg__deletePaths(NSVGpath* path) +{ + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } +} + +static void nsvg__deletePaint(NSVGpaint* paint) +{ + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); +} + +static void nsvg__deleteGradientData(NSVGgradientData* grad) +{ + NSVGgradientData* next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } +} + +static void nsvg__deleteParser(NSVGparser* p) +{ + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } +} + +static void nsvg__resetPath(NSVGparser* p) +{ + p->npts = 0; +} + +static void nsvg__addPoint(NSVGparser* p, float x, float y) +{ + if (p->npts+1 > p->cpts) { + p->cpts = p->cpts ? p->cpts*2 : 8; + p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); + if (!p->pts) return; + } + p->pts[p->npts*2+0] = x; + p->pts[p->npts*2+1] = y; + p->npts++; +} + +static void nsvg__moveTo(NSVGparser* p, float x, float y) +{ + if (p->npts > 0) { + p->pts[(p->npts-1)*2+0] = x; + p->pts[(p->npts-1)*2+1] = y; + } else { + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__lineTo(NSVGparser* p, float x, float y) +{ + float px,py, dx,dy; + if (p->npts > 0) { + px = p->pts[(p->npts-1)*2+0]; + py = p->pts[(p->npts-1)*2+1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); + nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) +{ + if (p->npts > 0) { + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); + } +} + +static NSVGattrib* nsvg__getAttr(NSVGparser* p) +{ + return &p->attr[p->attrHead]; +} + +static void nsvg__pushAttr(NSVGparser* p) +{ + if (p->attrHead < NSVG_MAX_ATTR-1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); + } +} + +static void nsvg__popAttr(NSVGparser* p) +{ + if (p->attrHead > 0) + p->attrHead--; +} + +static float nsvg__actualOrigX(NSVGparser* p) +{ + return p->viewMinx; +} + +static float nsvg__actualOrigY(NSVGparser* p) +{ + return p->viewMiny; +} + +static float nsvg__actualWidth(NSVGparser* p) +{ + return p->viewWidth; +} + +static float nsvg__actualHeight(NSVGparser* p) +{ + return p->viewHeight; +} + +static float nsvg__actualLength(NSVGparser* p) +{ + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w*w + h*h) / sqrtf(2.0f); +} + +static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) +{ + NSVGattrib* attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: return c.value; + case NSVG_UNITS_PX: return c.value; + case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: return c.value * p->dpi; + case NSVG_UNITS_EM: return c.value * attr->fontSize; + case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; + default: return c.value; + } + return c.value; +} + +static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) +{ + NSVGgradientData* grad = p->gradients; + if (id == NULL || *id == '\0') + return NULL; + while (grad != NULL) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; +} + +static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, float *xform, signed char* paintType) +{ + NSVGgradientData* data = NULL; + NSVGgradientData* ref = NULL; + NSVGgradientStop* stops = NULL; + NSVGgradient* grad; + float ox, oy, sw, sh, sl; + int nstops = 0; + int refIter; + + data = nsvg__findGradientData(p, id); + if (data == NULL) return NULL; + + // TODO: use ref to fill in all unset values too. + ref = data; + refIter = 0; + while (ref != NULL) { + NSVGgradientData* nextRef = NULL; + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + nextRef = nsvg__findGradientData(p, ref->ref); + if (nextRef == ref) break; // prevent infite loops on malformed data + ref = nextRef; + refIter++; + if (refIter > 32) break; // prevent infite loops on malformed data + } + if (stops == NULL) return NULL; + + grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); + if (grad == NULL) return NULL; + + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); + + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; grad->xform[1] = -dx; + grad->xform[2] = dx; grad->xform[3] = dy; + grad->xform[4] = x1; grad->xform[5] = y1; + } else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; grad->xform[1] = 0; + grad->xform[2] = 0; grad->xform[3] = r; + grad->xform[4] = cx; grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } + + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, xform); + + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); + grad->nstops = nstops; + + *paintType = data->type; + + return grad; +} + +static float nsvg__getAverageScale(float* t) +{ + float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); + float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); + return (sx + sy) * 0.5f; +} + +static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) +{ + NSVGpath* path; + float curve[4*2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts-1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } +} + +static void nsvg__addShape(NSVGparser* p) +{ + NSVGattrib* attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape* shape; + NSVGpath* path; + int i; + + if (p->plist == NULL) + return; + + shape = (NSVGshape*)malloc(sizeof(NSVGshape)); + if (shape == NULL) goto error; + memset(shape, 0, sizeof(NSVGshape)); + + memcpy(shape->id, attr->id, sizeof shape->id); + memcpy(shape->fillGradient, attr->fillGradient, sizeof shape->fillGradient); + memcpy(shape->strokeGradient, attr->strokeGradient, sizeof shape->strokeGradient); + memcpy(shape->xform, attr->xform, sizeof shape->xform); + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; + + shape->paths = p->plist; + p->plist = NULL; + + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } + + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; + } else if (attr->hasFill == 2) { + shape->fill.type = NSVG_PAINT_UNDEF; + } + + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; + } else if (attr->hasStroke == 2) { + shape->stroke.type = NSVG_PAINT_UNDEF; + } + + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; + + return; + +error: + if (shape) free(shape); +} + +static void nsvg__addPath(NSVGparser* p, char closed) +{ + NSVGattrib* attr = nsvg__getAttr(p); + NSVGpath* path = NULL; + float bounds[4]; + float* curve; + int i; + + if (p->npts < 4) + return; + + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); + + // Expect 1 + N*3 points (N = number of cubic bezier segments). + if ((p->npts % 3) != 1) + return; + + path = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (path == NULL) goto error; + memset(path, 0, sizeof(NSVGpath)); + + path->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (path->pts == NULL) goto error; + path->closed = closed; + path->npts = p->npts; + + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); + + // Find bounds + for (i = 0; i < path->npts-1; i += 3) { + curve = &path->pts[i*2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } + + path->next = p->plist; + p->plist = path; + + return; + +error: + if (path != NULL) { + if (path->pts != NULL) free(path->pts); + free(path); + } +} + +// We roll our own string to float because the std library one uses locale and messes things up. +static double nsvg__atof(const char* s) +{ + char* cur = (char*)s; + char* end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; + + // Parse optional sign + if (*cur == '+') { + cur++; + } else if (*cur == '-') { + sign = -1; + cur++; + } + + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } + + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } + + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; + + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + long expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } + + return res * sign; +} + + +static const char* nsvg__parseNumber(const char* s, char* it, const int size) +{ + const int last = size-1; + int i = 0; + + // sign + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + // integer part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) it[i++] = *s; + s++; + // fraction part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + // exponent + if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { + if (i < last) it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + it[i] = '\0'; + + return s; +} + +static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it) +{ + it[0] = '\0'; + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + if (!*s) return s; + if (*s == '0' || *s == '1') { + it[0] = *s++; + it[1] = '\0'; + return s; + } + return s; +} + +static const char* nsvg__getNextPathItem(const char* s, char* it) +{ + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + if (!*s) return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } + + return s; +} + +static unsigned int nsvg__parseColorHex(const char* str) +{ + unsigned int r=0, g=0, b=0; + if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex + return NSVG_RGB(r, g, b); + if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa + return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), .. + return NSVG_RGB(128, 128, 128); +} + +// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters). +// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors +// for backwards compatibility. Note: other image viewers return black instead. + +static unsigned int nsvg__parseColorRGB(const char* str) +{ + int i; + unsigned int rgbi[3]; + float rgbf[3]; + // try decimal integers first + if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) { + // integers failed, try percent values (float, locale independent) + const char delimiter[3] = {',', ',', ')'}; + str += 4; // skip "rgb(" + for (i = 0; i < 3; i++) { + while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces + if (*str == '+') str++; // skip '+' (don't allow '-') + if (!*str) break; + rgbf[i] = nsvg__atof(str); + + // Note 1: it would be great if nsvg__atof() returned how many + // bytes it consumed but it doesn't. We need to skip the number, + // the '%' character, spaces, and the delimiter ',' or ')'. + + // Note 2: The following code does not allow values like "33.%", + // i.e. a decimal point w/o fractional part, but this is consistent + // with other image viewers, e.g. firefox, chrome, eog, gimp. + + while (*str && nsvg__isdigit(*str)) str++; // skip integer part + if (*str == '.') { + str++; + if (!nsvg__isdigit(*str)) break; // error: no digit after '.' + while (*str && nsvg__isdigit(*str)) str++; // skip fractional part + } + if (*str == '%') str++; else break; + while (nsvg__isspace(*str)) str++; + if (*str == delimiter[i]) str++; + else break; + } + if (i == 3) { + rgbi[0] = roundf(rgbf[0] * 2.55f); + rgbi[1] = roundf(rgbf[1] * 2.55f); + rgbi[2] = roundf(rgbf[2] * 2.55f); + } else { + rgbi[0] = rgbi[1] = rgbi[2] = 128; + } + } + // clip values as the CSS spec requires + for (i = 0; i < 3; i++) { + if (rgbi[i] > 255) rgbi[i] = 255; + } + return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]); +} + +typedef struct NSVGNamedColor { + const char* name; + unsigned int color; +} NSVGNamedColor; + +NSVGNamedColor nsvg__colors[] = { + + { "red", NSVG_RGB(255, 0, 0) }, + { "green", NSVG_RGB( 0, 128, 0) }, + { "blue", NSVG_RGB( 0, 0, 255) }, + { "yellow", NSVG_RGB(255, 255, 0) }, + { "cyan", NSVG_RGB( 0, 255, 255) }, + { "magenta", NSVG_RGB(255, 0, 255) }, + { "black", NSVG_RGB( 0, 0, 0) }, + { "grey", NSVG_RGB(128, 128, 128) }, + { "gray", NSVG_RGB(128, 128, 128) }, + { "white", NSVG_RGB(255, 255, 255) }, + +#ifdef NANOSVG_ALL_COLOR_KEYWORDS + { "aliceblue", NSVG_RGB(240, 248, 255) }, + { "antiquewhite", NSVG_RGB(250, 235, 215) }, + { "aqua", NSVG_RGB( 0, 255, 255) }, + { "aquamarine", NSVG_RGB(127, 255, 212) }, + { "azure", NSVG_RGB(240, 255, 255) }, + { "beige", NSVG_RGB(245, 245, 220) }, + { "bisque", NSVG_RGB(255, 228, 196) }, + { "blanchedalmond", NSVG_RGB(255, 235, 205) }, + { "blueviolet", NSVG_RGB(138, 43, 226) }, + { "brown", NSVG_RGB(165, 42, 42) }, + { "burlywood", NSVG_RGB(222, 184, 135) }, + { "cadetblue", NSVG_RGB( 95, 158, 160) }, + { "chartreuse", NSVG_RGB(127, 255, 0) }, + { "chocolate", NSVG_RGB(210, 105, 30) }, + { "coral", NSVG_RGB(255, 127, 80) }, + { "cornflowerblue", NSVG_RGB(100, 149, 237) }, + { "cornsilk", NSVG_RGB(255, 248, 220) }, + { "crimson", NSVG_RGB(220, 20, 60) }, + { "darkblue", NSVG_RGB( 0, 0, 139) }, + { "darkcyan", NSVG_RGB( 0, 139, 139) }, + { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, + { "darkgray", NSVG_RGB(169, 169, 169) }, + { "darkgreen", NSVG_RGB( 0, 100, 0) }, + { "darkgrey", NSVG_RGB(169, 169, 169) }, + { "darkkhaki", NSVG_RGB(189, 183, 107) }, + { "darkmagenta", NSVG_RGB(139, 0, 139) }, + { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, + { "darkorange", NSVG_RGB(255, 140, 0) }, + { "darkorchid", NSVG_RGB(153, 50, 204) }, + { "darkred", NSVG_RGB(139, 0, 0) }, + { "darksalmon", NSVG_RGB(233, 150, 122) }, + { "darkseagreen", NSVG_RGB(143, 188, 143) }, + { "darkslateblue", NSVG_RGB( 72, 61, 139) }, + { "darkslategray", NSVG_RGB( 47, 79, 79) }, + { "darkslategrey", NSVG_RGB( 47, 79, 79) }, + { "darkturquoise", NSVG_RGB( 0, 206, 209) }, + { "darkviolet", NSVG_RGB(148, 0, 211) }, + { "deeppink", NSVG_RGB(255, 20, 147) }, + { "deepskyblue", NSVG_RGB( 0, 191, 255) }, + { "dimgray", NSVG_RGB(105, 105, 105) }, + { "dimgrey", NSVG_RGB(105, 105, 105) }, + { "dodgerblue", NSVG_RGB( 30, 144, 255) }, + { "firebrick", NSVG_RGB(178, 34, 34) }, + { "floralwhite", NSVG_RGB(255, 250, 240) }, + { "forestgreen", NSVG_RGB( 34, 139, 34) }, + { "fuchsia", NSVG_RGB(255, 0, 255) }, + { "gainsboro", NSVG_RGB(220, 220, 220) }, + { "ghostwhite", NSVG_RGB(248, 248, 255) }, + { "gold", NSVG_RGB(255, 215, 0) }, + { "goldenrod", NSVG_RGB(218, 165, 32) }, + { "greenyellow", NSVG_RGB(173, 255, 47) }, + { "honeydew", NSVG_RGB(240, 255, 240) }, + { "hotpink", NSVG_RGB(255, 105, 180) }, + { "indianred", NSVG_RGB(205, 92, 92) }, + { "indigo", NSVG_RGB( 75, 0, 130) }, + { "ivory", NSVG_RGB(255, 255, 240) }, + { "khaki", NSVG_RGB(240, 230, 140) }, + { "lavender", NSVG_RGB(230, 230, 250) }, + { "lavenderblush", NSVG_RGB(255, 240, 245) }, + { "lawngreen", NSVG_RGB(124, 252, 0) }, + { "lemonchiffon", NSVG_RGB(255, 250, 205) }, + { "lightblue", NSVG_RGB(173, 216, 230) }, + { "lightcoral", NSVG_RGB(240, 128, 128) }, + { "lightcyan", NSVG_RGB(224, 255, 255) }, + { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, + { "lightgray", NSVG_RGB(211, 211, 211) }, + { "lightgreen", NSVG_RGB(144, 238, 144) }, + { "lightgrey", NSVG_RGB(211, 211, 211) }, + { "lightpink", NSVG_RGB(255, 182, 193) }, + { "lightsalmon", NSVG_RGB(255, 160, 122) }, + { "lightseagreen", NSVG_RGB( 32, 178, 170) }, + { "lightskyblue", NSVG_RGB(135, 206, 250) }, + { "lightslategray", NSVG_RGB(119, 136, 153) }, + { "lightslategrey", NSVG_RGB(119, 136, 153) }, + { "lightsteelblue", NSVG_RGB(176, 196, 222) }, + { "lightyellow", NSVG_RGB(255, 255, 224) }, + { "lime", NSVG_RGB( 0, 255, 0) }, + { "limegreen", NSVG_RGB( 50, 205, 50) }, + { "linen", NSVG_RGB(250, 240, 230) }, + { "maroon", NSVG_RGB(128, 0, 0) }, + { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, + { "mediumblue", NSVG_RGB( 0, 0, 205) }, + { "mediumorchid", NSVG_RGB(186, 85, 211) }, + { "mediumpurple", NSVG_RGB(147, 112, 219) }, + { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, + { "mediumslateblue", NSVG_RGB(123, 104, 238) }, + { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, + { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, + { "mediumvioletred", NSVG_RGB(199, 21, 133) }, + { "midnightblue", NSVG_RGB( 25, 25, 112) }, + { "mintcream", NSVG_RGB(245, 255, 250) }, + { "mistyrose", NSVG_RGB(255, 228, 225) }, + { "moccasin", NSVG_RGB(255, 228, 181) }, + { "navajowhite", NSVG_RGB(255, 222, 173) }, + { "navy", NSVG_RGB( 0, 0, 128) }, + { "oldlace", NSVG_RGB(253, 245, 230) }, + { "olive", NSVG_RGB(128, 128, 0) }, + { "olivedrab", NSVG_RGB(107, 142, 35) }, + { "orange", NSVG_RGB(255, 165, 0) }, + { "orangered", NSVG_RGB(255, 69, 0) }, + { "orchid", NSVG_RGB(218, 112, 214) }, + { "palegoldenrod", NSVG_RGB(238, 232, 170) }, + { "palegreen", NSVG_RGB(152, 251, 152) }, + { "paleturquoise", NSVG_RGB(175, 238, 238) }, + { "palevioletred", NSVG_RGB(219, 112, 147) }, + { "papayawhip", NSVG_RGB(255, 239, 213) }, + { "peachpuff", NSVG_RGB(255, 218, 185) }, + { "peru", NSVG_RGB(205, 133, 63) }, + { "pink", NSVG_RGB(255, 192, 203) }, + { "plum", NSVG_RGB(221, 160, 221) }, + { "powderblue", NSVG_RGB(176, 224, 230) }, + { "purple", NSVG_RGB(128, 0, 128) }, + { "rosybrown", NSVG_RGB(188, 143, 143) }, + { "royalblue", NSVG_RGB( 65, 105, 225) }, + { "saddlebrown", NSVG_RGB(139, 69, 19) }, + { "salmon", NSVG_RGB(250, 128, 114) }, + { "sandybrown", NSVG_RGB(244, 164, 96) }, + { "seagreen", NSVG_RGB( 46, 139, 87) }, + { "seashell", NSVG_RGB(255, 245, 238) }, + { "sienna", NSVG_RGB(160, 82, 45) }, + { "silver", NSVG_RGB(192, 192, 192) }, + { "skyblue", NSVG_RGB(135, 206, 235) }, + { "slateblue", NSVG_RGB(106, 90, 205) }, + { "slategray", NSVG_RGB(112, 128, 144) }, + { "slategrey", NSVG_RGB(112, 128, 144) }, + { "snow", NSVG_RGB(255, 250, 250) }, + { "springgreen", NSVG_RGB( 0, 255, 127) }, + { "steelblue", NSVG_RGB( 70, 130, 180) }, + { "tan", NSVG_RGB(210, 180, 140) }, + { "teal", NSVG_RGB( 0, 128, 128) }, + { "thistle", NSVG_RGB(216, 191, 216) }, + { "tomato", NSVG_RGB(255, 99, 71) }, + { "turquoise", NSVG_RGB( 64, 224, 208) }, + { "violet", NSVG_RGB(238, 130, 238) }, + { "wheat", NSVG_RGB(245, 222, 179) }, + { "whitesmoke", NSVG_RGB(245, 245, 245) }, + { "yellowgreen", NSVG_RGB(154, 205, 50) }, +#endif +}; + +static unsigned int nsvg__parseColorName(const char* str) +{ + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); + + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } + + return NSVG_RGB(128, 128, 128); +} + +static unsigned int nsvg__parseColor(const char* str) +{ + size_t len = 0; + while(*str == ' ') ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); +} + +static float nsvg__parseOpacity(const char* str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) val = 0.0f; + if (val > 1.0f) val = 1.0f; + return val; +} + +static float nsvg__parseMiterLimit(const char* str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) val = 0.0f; + return val; +} + +static int nsvg__parseUnits(const char* units) +{ + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; +} + +static int nsvg__isCoordinate(const char* s) +{ + // optional sign + if (*s == '-' || *s == '+') + s++; + // must have at least one digit, or start by a dot + return (nsvg__isdigit(*s) || *s == '.'); +} + +static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) +{ + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char buf[64]; + coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); + coord.value = nsvg__atof(buf); + return coord; +} + +static NSVGcoordinate nsvg__coord(float v, int units) +{ + NSVGcoordinate coord = {v, units}; + return coord; +} + +static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) +{ + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); +} + +static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) +{ + const char* end; + const char* ptr; + char it[64]; + + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') ++end; + if (*end == 0) + return 1; + + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } else { + ++ptr; + } + } + return (int)(end - str); +} + + +static int nsvg__parseMatrix(float* xform, const char* str) +{ + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) return len; + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseTranslate(float* xform, const char* str) +{ + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = 0.0; + + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseScale(float* xform, const char* str) +{ + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewX(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewY(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseRotate(float* xform, const char* str) +{ + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); + + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } + + nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); + nsvg__xformMultiply(m, t); + + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } + + memcpy(xform, m, sizeof(float)*6); + + return len; +} + +static void nsvg__parseTransform(float* xform, const char* str) +{ + float t[6]; + int len; + nsvg__xformIdentity(xform); + while (*str) + { + if (strncmp(str, "matrix", 6) == 0) + len = nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + len = nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + len = nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + len = nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + len = nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + len = nsvg__parseSkewY(t, str); + else{ + ++str; + continue; + } + if (len != 0) { + str += len; + } else { + ++str; + continue; + } + + nsvg__xformPremultiply(xform, t); + } +} + +static void nsvg__parseUrl(char* id, const char* str) +{ + int i = 0; + str += 4; // "url("; + if (*str && *str == '#') + str++; + while (i < 63 && *str && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; +} + +static char nsvg__parseLineCap(const char* str) +{ + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseLineJoin(const char* str) +{ + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_JOIN_MITER; +} + +static char nsvg__parseFillRule(const char* str) +{ + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; +} + +static const char* nsvg__getNextDashItem(const char* s, char* it) +{ + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; +} + +static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) +{ + char item[64]; + int count = 0, i; + float sum = 0.0f; + + // Handle "none" + if (str[0] == 'n') + return 0; + + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } + + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; + + return count; +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str); + +static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) +{ + float xform[6]; + NSVGattrib* attr = nsvg__getAttr(p); + if (!attr) return 0; + + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree + + } else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, 63); + attr->id[63] = '\0'; + } else { + return 0; + } + return 1; +} + +static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) +{ + const char* str; + const char* val; + char name[512]; + char value[512]; + int n; + + str = start; + while (str < end && *str != ':') ++str; + + val = str; + + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; + ++str; + + n = (int)(str - start); + if (n > 511) n = 511; + if (n) memcpy(name, start, n); + name[n] = 0; + + while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; + + n = (int)(end - val); + if (n > 511) n = 511; + if (n) memcpy(value, val, n); + value[n] = 0; + + return nsvg__parseAttr(p, name, value); +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str) +{ + const char* start; + const char* end; + + while (*str) { + // Left Trim + while(*str && nsvg__isspace(*str)) ++str; + start = str; + while(*str && *str != ';') ++str; + end = str; + + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; + ++end; + + nsvg__parseNameValue(p, start, end); + if (*str) ++str; + } +} + +static void nsvg__parseAttribs(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) + { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } +} + +static int nsvg__getArgsPerElement(char cmd) +{ + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + case 'z': + case 'Z': + return 0; + } + return -1; +} + +static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); +} + +static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x2, y2, cx1, cy1, cx2, cy2; + + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + cx1 = 2*x1 - *cpx2; + cy1 = 2*y1 - *cpy2; + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + // Convert to cubic bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } else { + x2 = args[0]; + y2 = args[1]; + } + + cx = 2*x1 - *cpx2; + cy = 2*y1 - *cpy2; + + // Convert to cubix bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static float nsvg__sqr(float x) { return x*x; } +static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } + +static float nsvg__vecrat(float ux, float uy, float vx, float vy) +{ + return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); +} + +static float nsvg__vecang(float ux, float uy, float vx, float vy) +{ + float r = nsvg__vecrat(ux,uy, vx,vy); + if (r < -1.0f) r = -1.0f; + if (r > 1.0f) r = 1.0f; + return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); +} + +static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; + + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } else { + x2 = args[5]; + y2 = args[6]; + } + + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx*dx + dy*dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } + + sinrx = sinf(rotx); + cosrx = cosf(rotx); + + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); + sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); + if (sa < 0.0f) sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; + + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; + cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; + + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle + da = nsvg__vecang(ux,uy, vx,vy); // Delta angle + +// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; +// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; + + // Approximate the arc using cubic spline segments. + t[0] = cosrx; t[1] = sinrx; + t[2] = -sinrx; t[3] = cosrx; + t[4] = cx; t[5] = cy; + + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + // Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite) + if ((hda < 1e-3f) && (hda > -1e-3f)) + hda *= 0.5f; + else + hda = (1.0f - cosf(hda)) / sinf(hda); + kappa = fabsf(4.0f / 3.0f * hda); + if (da < 0.0f) + kappa = -kappa; + + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i/(float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } + + *cpx = x2; + *cpy = y2; +} + +static void nsvg__parsePath(NSVGparser* p, const char** attr) +{ + const char* s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + char initPoint; + float cpx, cpy, cpx2, cpy2; + const char* tmp[4]; + char closedFlag; + int i; + char item[64]; + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } + + if (s) { + nsvg__resetPath(p); + cpx = 0; cpy = 0; + cpx2 = 0; cpy2 = 0; + initPoint = 0; + closedFlag = 0; + nargs = 0; + + while (*s) { + item[0] = '\0'; + if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4)) + s = nsvg__getNextPathItemWhenArcFlag(s, item); + if (!*item) + s = nsvg__getNextPathItem(s, item); + if (!*item) break; + if (cmd != '\0' && nsvg__isCoordinate(item)) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; cpy2 = cpy; + initPoint = 1; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs-2]; + cpy = args[nargs-1]; + cpx2 = cpx; cpy2 = cpy; + } + break; + } + nargs = 0; + } + } else { + cmd = item[0]; + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } else if (initPoint == 0) { + // Do not allow other commands until initial point has been set (moveTo called once). + cmd = '\0'; + } + if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + rargs = nsvg__getArgsPerElement(cmd); + if (rargs == -1) { + // Command not recognized + cmd = '\0'; + rargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } + + nsvg__addShape(p); +} + +static void nsvg__parseRect(NSVGparser* p, const char** attr) +{ + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx < 0.0f && ry > 0.0f) rx = ry; + if (ry < 0.0f && rx > 0.0f) ry = rx; + if (rx < 0.0f) rx = 0.0f; + if (ry < 0.0f) ry = 0.0f; + if (rx > w/2.0f) rx = w/2.0f; + if (ry > h/2.0f) ry = h/2.0f; + + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); + + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x+w, y); + nsvg__lineTo(p, x+w, y+h); + nsvg__lineTo(p, x, y+h); + } else { + // Rounded rectangle + nsvg__moveTo(p, x+rx, y); + nsvg__lineTo(p, x+w-rx, y); + nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); + nsvg__lineTo(p, x+w, y+h-ry); + nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); + nsvg__lineTo(p, x+rx, y+h); + nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); + nsvg__lineTo(p, x, y+ry); + nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); + } + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseCircle(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); + } + } + + if (r > 0.0f) { + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+r, cy); + nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); + nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); + nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); + nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseEllipse(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx > 0.0f && ry > 0.0f) { + + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+rx, cy); + nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); + nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); + nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); + nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseLine(NSVGparser* p, const char** attr) +{ + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } + + nsvg__resetPath(p); + + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); + + nsvg__addPath(p, 0); + + nsvg__addShape(p); +} + +static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) +{ + int i; + const char* s; + float args[2]; + int nargs, npts = 0; + char item[64]; + + nsvg__resetPath(p); + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } + + nsvg__addPath(p, (char)closeFlag); + + nsvg__addShape(p); +} + +static void nsvg__parseSVG(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "viewBox") == 0) { + const char *s = attr[i + 1]; + char buf[64]; + s = nsvg__parseNumber(s, buf, 64); + p->viewMinx = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewMiny = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewWidth = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewHeight = nsvg__atof(buf); + } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } +} + +static void nsvg__parseGradient(NSVGparser* p, const char** attr, signed char type) +{ + int i; + NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } + + nsvg__xformIdentity(grad->xform); + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i+1], 63); + grad->id[63] = '\0'; + } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i+1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i+1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i+1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i+1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i+1]; + strncpy(grad->ref, href+1, 62); + grad->ref[62] = '\0'; + } + } + } + + grad->next = p->gradients; + p->gradients = grad; +} + +static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) +{ + NSVGattrib* curAttr = nsvg__getAttr(p); + NSVGgradientData* grad; + NSVGgradientStop* stop; + int i, idx; + + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; + + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } + + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) return; + + grad->nstops++; + grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); + if (grad->stops == NULL) return; + + // Insert + idx = grad->nstops-1; + for (i = 0; i < grad->nstops-1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops-1) { + for (i = grad->nstops-1; i > idx; i--) + grad->stops[i] = grad->stops[i-1]; + } + + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; + stop->offset = curAttr->stopOffset; +} + +static void nsvg__startElement(void* ud, const char* el, const char** attr) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } + + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } +} + +static void nsvg__endElement(void* ud, const char* el) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (strcmp(el, "g") == 0) { + nsvg__popAttr(p); + } else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } +} + +static void nsvg__content(void* ud, const char* s) +{ + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty +} + +static void nsvg__imageBounds(NSVGparser* p, float* bounds) +{ + NSVGshape* shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } +} + +static float nsvg__viewAlign(float content, float container, int type) +{ + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; +} + +static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) +{ + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply (grad->xform, t); + + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply (grad->xform, t); +} + +static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) +{ + NSVGshape* shape; + NSVGpath* path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float* pt; + + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); + + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; + + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } + + // Transform + sx *= us; + sy *= us; + avgs = (sx+sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i =0; i < path->npts; i++) { + pt = &path->pts[i*2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } + + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } + + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } +} + +static void nsvg__createGradients(NSVGparser* p) +{ + NSVGshape* shape; + + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + if (shape->fill.type == NSVG_PAINT_UNDEF) { + if (shape->fillGradient[0] != '\0') { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, shape->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient(p, shape->fillGradient, localBounds, shape->xform, &shape->fill.type); + } + if (shape->fill.type == NSVG_PAINT_UNDEF) { + shape->fill.type = NSVG_PAINT_NONE; + } + } + if (shape->stroke.type == NSVG_PAINT_UNDEF) { + if (shape->strokeGradient[0] != '\0') { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, shape->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient(p, shape->strokeGradient, localBounds, shape->xform, &shape->stroke.type); + } + if (shape->stroke.type == NSVG_PAINT_UNDEF) { + shape->stroke.type = NSVG_PAINT_NONE; + } + } + } +} + +NSVGimage* nsvgParse(char* input, const char* units, float dpi) +{ + NSVGparser* p; + NSVGimage* ret = 0; + + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; + + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + + // Create gradients after all definitions have been parsed + nsvg__createGradients(p); + + // Scale to viewBox + nsvg__scaleToViewbox(p, units); + + ret = p->image; + p->image = NULL; + + nsvg__deleteParser(p); + + return ret; +} + +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) +{ + FILE* fp = NULL; + size_t size; + char* data = NULL; + NSVGimage* image = NULL; + + fp = fopen(filename, "rb"); + if (!fp) goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char*)malloc(size+1); + if (data == NULL) goto error; + if (fread(data, 1, size, fp) != size) goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); + + return image; + +error: + if (fp) fclose(fp); + if (data) free(data); + if (image) nsvgDelete(image); + return NULL; +} + +NSVGpath* nsvgDuplicatePath(NSVGpath* p) +{ + NSVGpath* res = NULL; + + if (p == NULL) + return NULL; + + res = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (res == NULL) goto error; + memset(res, 0, sizeof(NSVGpath)); + + res->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (res->pts == NULL) goto error; + memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); + res->npts = p->npts; + + memcpy(res->bounds, p->bounds, sizeof(p->bounds)); + + res->closed = p->closed; + + return res; + +error: + if (res != NULL) { + free(res->pts); + free(res); + } + return NULL; +} + +void nsvgDelete(NSVGimage* image) +{ + NSVGshape *snext, *shape; + if (image == NULL) return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // NANOSVG_IMPLEMENTATION + +#endif // NANOSVG_H diff --git a/libraries/ZWidget/src/core/nanosvg/nanosvgrast.h b/libraries/ZWidget/src/core/nanosvg/nanosvgrast.h new file mode 100644 index 00000000000..89fae3834bd --- /dev/null +++ b/libraries/ZWidget/src/core/nanosvg/nanosvgrast.h @@ -0,0 +1,1459 @@ +/* + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The polygon rasterization is heavily based on stb_truetype rasterizer + * by Sean Barrett - http://nothings.org/ + * + */ + +#ifndef NANOSVGRAST_H +#define NANOSVGRAST_H + +#include "nanosvg.h" + +#ifndef NANOSVGRAST_CPLUSPLUS +#ifdef __cplusplus +extern "C" { +#endif +#endif + +typedef struct NSVGrasterizer NSVGrasterizer; + +/* Example Usage: + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + + // Create rasterizer (can be used to render multiple images). + struct NSVGrasterizer* rast = nsvgCreateRasterizer(); + // Allocate memory for image + unsigned char* img = malloc(w*h*4); + // Rasterize + nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4); +*/ + +// Allocated rasterizer context. +NSVGrasterizer* nsvgCreateRasterizer(void); + +// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha) +// r - pointer to rasterizer context +// image - pointer to image to rasterize +// tx,ty - image offset (applied after scaling) +// scale - image scale +// dst - pointer to destination image data, 4 bytes per pixel (RGBA) +// w - width of the image to render +// h - height of the image to render +// stride - number of bytes per scaleline in the destination buffer +void nsvgRasterize(NSVGrasterizer* r, + NSVGimage* image, float tx, float ty, float scale, + unsigned char* dst, int w, int h, int stride); + +// Deletes rasterizer context. +void nsvgDeleteRasterizer(NSVGrasterizer*); + + +#ifndef NANOSVGRAST_CPLUSPLUS +#ifdef __cplusplus +} +#endif +#endif + +#ifdef NANOSVGRAST_IMPLEMENTATION + +#include +#include +#include + +#define NSVG__SUBSAMPLES 5 +#define NSVG__FIXSHIFT 10 +#define NSVG__FIX (1 << NSVG__FIXSHIFT) +#define NSVG__FIXMASK (NSVG__FIX-1) +#define NSVG__MEMPAGE_SIZE 1024 + +typedef struct NSVGedge { + float x0,y0, x1,y1; + int dir; + struct NSVGedge* next; +} NSVGedge; + +typedef struct NSVGpoint { + float x, y; + float dx, dy; + float len; + float dmx, dmy; + unsigned char flags; +} NSVGpoint; + +typedef struct NSVGactiveEdge { + int x,dx; + float ey; + int dir; + struct NSVGactiveEdge *next; +} NSVGactiveEdge; + +typedef struct NSVGmemPage { + unsigned char mem[NSVG__MEMPAGE_SIZE]; + int size; + struct NSVGmemPage* next; +} NSVGmemPage; + +typedef struct NSVGcachedPaint { + signed char type; + char spread; + float xform[6]; + unsigned int colors[256]; +} NSVGcachedPaint; + +struct NSVGrasterizer +{ + float px, py; + + float tessTol; + float distTol; + + NSVGedge* edges; + int nedges; + int cedges; + + NSVGpoint* points; + int npoints; + int cpoints; + + NSVGpoint* points2; + int npoints2; + int cpoints2; + + NSVGactiveEdge* freelist; + NSVGmemPage* pages; + NSVGmemPage* curpage; + + unsigned char* scanline; + int cscanline; + + unsigned char* bitmap; + int width, height, stride; +}; + +NSVGrasterizer* nsvgCreateRasterizer(void) +{ + NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer)); + if (r == NULL) goto error; + memset(r, 0, sizeof(NSVGrasterizer)); + + r->tessTol = 0.25f; + r->distTol = 0.01f; + + return r; + +error: + nsvgDeleteRasterizer(r); + return NULL; +} + +void nsvgDeleteRasterizer(NSVGrasterizer* r) +{ + NSVGmemPage* p; + + if (r == NULL) return; + + p = r->pages; + while (p != NULL) { + NSVGmemPage* next = p->next; + free(p); + p = next; + } + + if (r->edges) free(r->edges); + if (r->points) free(r->points); + if (r->points2) free(r->points2); + if (r->scanline) free(r->scanline); + + free(r); +} + +static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) +{ + NSVGmemPage *newp; + + // If using existing chain, return the next page in chain + if (cur != NULL && cur->next != NULL) { + return cur->next; + } + + // Alloc new page + newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage)); + if (newp == NULL) return NULL; + memset(newp, 0, sizeof(NSVGmemPage)); + + // Add to linked list + if (cur != NULL) + cur->next = newp; + else + r->pages = newp; + + return newp; +} + +static void nsvg__resetPool(NSVGrasterizer* r) +{ + NSVGmemPage* p = r->pages; + while (p != NULL) { + p->size = 0; + p = p->next; + } + r->curpage = r->pages; +} + +static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size) +{ + unsigned char* buf; + if (size > NSVG__MEMPAGE_SIZE) return NULL; + if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) { + r->curpage = nsvg__nextPage(r, r->curpage); + } + buf = &r->curpage->mem[r->curpage->size]; + r->curpage->size += size; + return buf; +} + +static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol) +{ + float dx = x2 - x1; + float dy = y2 - y1; + return dx*dx + dy*dy < tol*tol; +} + +static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags) +{ + NSVGpoint* pt; + + if (r->npoints > 0) { + pt = &r->points[r->npoints-1]; + if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) { + pt->flags = (unsigned char)(pt->flags | flags); + return; + } + } + + if (r->npoints+1 > r->cpoints) { + r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; + r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); + if (r->points == NULL) return; + } + + pt = &r->points[r->npoints]; + pt->x = x; + pt->y = y; + pt->flags = (unsigned char)flags; + r->npoints++; +} + +static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt) +{ + if (r->npoints+1 > r->cpoints) { + r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; + r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); + if (r->points == NULL) return; + } + r->points[r->npoints] = pt; + r->npoints++; +} + +static void nsvg__duplicatePoints(NSVGrasterizer* r) +{ + if (r->npoints > r->cpoints2) { + r->cpoints2 = r->npoints; + r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2); + if (r->points2 == NULL) return; + } + + memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints); + r->npoints2 = r->npoints; +} + +static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1) +{ + NSVGedge* e; + + // Skip horizontal edges + if (y0 == y1) + return; + + if (r->nedges+1 > r->cedges) { + r->cedges = r->cedges > 0 ? r->cedges * 2 : 64; + r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges); + if (r->edges == NULL) return; + } + + e = &r->edges[r->nedges]; + r->nedges++; + + if (y0 < y1) { + e->x0 = x0; + e->y0 = y0; + e->x1 = x1; + e->y1 = y1; + e->dir = 1; + } else { + e->x0 = x1; + e->y0 = y1; + e->x1 = x0; + e->y1 = y0; + e->dir = -1; + } +} + +static float nsvg__normalize(float *x, float* y) +{ + float d = sqrtf((*x)*(*x) + (*y)*(*y)); + if (d > 1e-6f) { + float id = 1.0f / d; + *x *= id; + *y *= id; + } + return d; +} + +static float nsvg__absf(float x) { return x < 0 ? -x : x; } +static float nsvg__roundf(float x) { return (x >= 0) ? floorf(x + 0.5) : ceilf(x - 0.5); } + +static void nsvg__flattenCubicBez(NSVGrasterizer* r, + float x1, float y1, float x2, float y2, + float x3, float y3, float x4, float y4, + int level, int type) +{ + float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234; + float dx,dy,d2,d3; + + if (level > 10) return; + + x12 = (x1+x2)*0.5f; + y12 = (y1+y2)*0.5f; + x23 = (x2+x3)*0.5f; + y23 = (y2+y3)*0.5f; + x34 = (x3+x4)*0.5f; + y34 = (y3+y4)*0.5f; + x123 = (x12+x23)*0.5f; + y123 = (y12+y23)*0.5f; + + dx = x4 - x1; + dy = y4 - y1; + d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx)); + d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx)); + + if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) { + nsvg__addPathPoint(r, x4, y4, type); + return; + } + + x234 = (x23+x34)*0.5f; + y234 = (y23+y34)*0.5f; + x1234 = (x123+x234)*0.5f; + y1234 = (y123+y234)*0.5f; + + nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0); + nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type); +} + +static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) +{ + int i, j; + NSVGpath* path; + + for (path = shape->paths; path != NULL; path = path->next) { + r->npoints = 0; + // Flatten path + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + for (i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0); + } + // Close path + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + // Build edges + for (i = 0, j = r->npoints-1; i < r->npoints; j = i++) + nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y); + } +} + +enum NSVGpointFlags +{ + NSVG_PT_CORNER = 0x01, + NSVG_PT_BEVEL = 0x02, + NSVG_PT_LEFT = 0x04 +}; + +static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + float len = nsvg__normalize(&dx, &dy); + float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) +{ + float w = lineWidth * 0.5f; + float px = p->x, py = p->y; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + + nsvg__addEdge(r, lx, ly, rx, ry); + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) +{ + float w = lineWidth * 0.5f; + float px = p->x - dx*w, py = p->y - dy*w; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + + nsvg__addEdge(r, lx, ly, rx, ry); + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +#ifndef NSVG_PI +#define NSVG_PI (3.14159265358979323846264338327f) +#endif + +static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect) +{ + int i; + float w = lineWidth * 0.5f; + float px = p->x, py = p->y; + float dlx = dy, dly = -dx; + float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0; + + for (i = 0; i < ncap; i++) { + float a = (float)i/(float)(ncap-1)*NSVG_PI; + float ax = cosf(a) * w, ay = sinf(a) * w; + float x = px - dlx*ax - dx*ay; + float y = py - dly*ax - dy*ay; + + if (i > 0) + nsvg__addEdge(r, prevx, prevy, x, y); + + prevx = x; + prevy = y; + + if (i == 0) { + lx = x; ly = y; + } else if (i == ncap-1) { + rx = x; ry = y; + } + } + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w); + float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w); + float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w); + float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w); + + nsvg__addEdge(r, lx0, ly0, left->x, left->y); + nsvg__addEdge(r, lx1, ly1, lx0, ly0); + + nsvg__addEdge(r, right->x, right->y, rx0, ry0); + nsvg__addEdge(r, rx0, ry0, rx1, ry1); + + left->x = lx1; left->y = ly1; + right->x = rx1; right->y = ry1; +} + +static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float lx0, rx0, lx1, rx1; + float ly0, ry0, ly1, ry1; + + if (p1->flags & NSVG_PT_LEFT) { + lx0 = lx1 = p1->x - p1->dmx * w; + ly0 = ly1 = p1->y - p1->dmy * w; + nsvg__addEdge(r, lx1, ly1, left->x, left->y); + + rx0 = p1->x + (dlx0 * w); + ry0 = p1->y + (dly0 * w); + rx1 = p1->x + (dlx1 * w); + ry1 = p1->y + (dly1 * w); + nsvg__addEdge(r, right->x, right->y, rx0, ry0); + nsvg__addEdge(r, rx0, ry0, rx1, ry1); + } else { + lx0 = p1->x - (dlx0 * w); + ly0 = p1->y - (dly0 * w); + lx1 = p1->x - (dlx1 * w); + ly1 = p1->y - (dly1 * w); + nsvg__addEdge(r, lx0, ly0, left->x, left->y); + nsvg__addEdge(r, lx1, ly1, lx0, ly0); + + rx0 = rx1 = p1->x + p1->dmx * w; + ry0 = ry1 = p1->y + p1->dmy * w; + nsvg__addEdge(r, right->x, right->y, rx1, ry1); + } + + left->x = lx1; left->y = ly1; + right->x = rx1; right->y = ry1; +} + +static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap) +{ + int i, n; + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float a0 = atan2f(dly0, dlx0); + float a1 = atan2f(dly1, dlx1); + float da = a1 - a0; + float lx, ly, rx, ry; + + if (da < NSVG_PI) da += NSVG_PI*2; + if (da > NSVG_PI) da -= NSVG_PI*2; + + n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap); + if (n < 2) n = 2; + if (n > ncap) n = ncap; + + lx = left->x; + ly = left->y; + rx = right->x; + ry = right->y; + + for (i = 0; i < n; i++) { + float u = (float)i/(float)(n-1); + float a = a0 + u*da; + float ax = cosf(a) * w, ay = sinf(a) * w; + float lx1 = p1->x - ax, ly1 = p1->y - ay; + float rx1 = p1->x + ax, ry1 = p1->y + ay; + + nsvg__addEdge(r, lx1, ly1, lx, ly); + nsvg__addEdge(r, rx, ry, rx1, ry1); + + lx = lx1; ly = ly1; + rx = rx1; ry = ry1; + } + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w); + float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w); + + nsvg__addEdge(r, lx, ly, left->x, left->y); + nsvg__addEdge(r, right->x, right->y, rx, ry); + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static int nsvg__curveDivs(float r, float arc, float tol) +{ + float da = acosf(r / (r + tol)) * 2.0f; + int divs = (int)ceilf(arc / da); + if (divs < 2) divs = 2; + return divs; +} + +static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth) +{ + int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle. + NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0}; + NSVGpoint* p0, *p1; + int j, s, e; + + // Build stroke edges + if (closed) { + // Looping + p0 = &points[npoints-1]; + p1 = &points[0]; + s = 0; + e = npoints; + } else { + // Add cap + p0 = &points[0]; + p1 = &points[1]; + s = 1; + e = npoints-1; + } + + if (closed) { + nsvg__initClosed(&left, &right, p0, p1, lineWidth); + firstLeft = left; + firstRight = right; + } else { + // Add cap + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + nsvg__normalize(&dx, &dy); + if (lineCap == NSVG_CAP_BUTT) + nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0); + else if (lineCap == NSVG_CAP_SQUARE) + nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0); + else if (lineCap == NSVG_CAP_ROUND) + nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0); + } + + for (j = s; j < e; ++j) { + if (p1->flags & NSVG_PT_CORNER) { + if (lineJoin == NSVG_JOIN_ROUND) + nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap); + else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL)) + nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth); + else + nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth); + } else { + nsvg__straightJoin(r, &left, &right, p1, lineWidth); + } + p0 = p1++; + } + + if (closed) { + // Loop it + nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y); + nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y); + } else { + // Add cap + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + nsvg__normalize(&dx, &dy); + if (lineCap == NSVG_CAP_BUTT) + nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); + else if (lineCap == NSVG_CAP_SQUARE) + nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); + else if (lineCap == NSVG_CAP_ROUND) + nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1); + } +} + +static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin) +{ + int i, j; + NSVGpoint* p0, *p1; + + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + for (i = 0; i < r->npoints; i++) { + // Calculate segment direction and length + p0->dx = p1->x - p0->x; + p0->dy = p1->y - p0->y; + p0->len = nsvg__normalize(&p0->dx, &p0->dy); + // Advance + p0 = p1++; + } + + // calculate joins + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + for (j = 0; j < r->npoints; j++) { + float dlx0, dly0, dlx1, dly1, dmr2, cross; + dlx0 = p0->dy; + dly0 = -p0->dx; + dlx1 = p1->dy; + dly1 = -p1->dx; + // Calculate extrusions + p1->dmx = (dlx0 + dlx1) * 0.5f; + p1->dmy = (dly0 + dly1) * 0.5f; + dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy; + if (dmr2 > 0.000001f) { + float s2 = 1.0f / dmr2; + if (s2 > 600.0f) { + s2 = 600.0f; + } + p1->dmx *= s2; + p1->dmy *= s2; + } + + // Clear flags, but keep the corner. + p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0; + + // Keep track of left turns. + cross = p1->dx * p0->dy - p0->dx * p1->dy; + if (cross > 0.0f) + p1->flags |= NSVG_PT_LEFT; + + // Check to see if the corner needs to be beveled. + if (p1->flags & NSVG_PT_CORNER) { + if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) { + p1->flags |= NSVG_PT_BEVEL; + } + } + + p0 = p1++; + } +} + +static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale) +{ + int i, j, closed; + NSVGpath* path; + NSVGpoint* p0, *p1; + float miterLimit = shape->miterLimit; + int lineJoin = shape->strokeLineJoin; + int lineCap = shape->strokeLineCap; + float lineWidth = shape->strokeWidth * scale; + + for (path = shape->paths; path != NULL; path = path->next) { + // Flatten path + r->npoints = 0; + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER); + for (i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER); + } + if (r->npoints < 2) + continue; + + closed = path->closed; + + // If the first and last points are the same, remove the last, mark as closed path. + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) { + r->npoints--; + p0 = &r->points[r->npoints-1]; + closed = 1; + } + + if (shape->strokeDashCount > 0) { + int idash = 0, dashState = 1; + float totalDist = 0, dashLen, allDashLen, dashOffset; + NSVGpoint cur; + + if (closed) + nsvg__appendPathPoint(r, r->points[0]); + + // Duplicate points -> points2. + nsvg__duplicatePoints(r); + + r->npoints = 0; + cur = r->points2[0]; + nsvg__appendPathPoint(r, cur); + + // Figure out dash offset. + allDashLen = 0; + for (j = 0; j < shape->strokeDashCount; j++) + allDashLen += shape->strokeDashArray[j]; + if (shape->strokeDashCount & 1) + allDashLen *= 2.0f; + // Find location inside pattern + dashOffset = fmodf(shape->strokeDashOffset, allDashLen); + if (dashOffset < 0.0f) + dashOffset += allDashLen; + + while (dashOffset > shape->strokeDashArray[idash]) { + dashOffset -= shape->strokeDashArray[idash]; + idash = (idash + 1) % shape->strokeDashCount; + } + dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale; + + for (j = 1; j < r->npoints2; ) { + float dx = r->points2[j].x - cur.x; + float dy = r->points2[j].y - cur.y; + float dist = sqrtf(dx*dx + dy*dy); + + if ((totalDist + dist) > dashLen) { + // Calculate intermediate point + float d = (dashLen - totalDist) / dist; + float x = cur.x + dx * d; + float y = cur.y + dy * d; + nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER); + + // Stroke + if (r->npoints > 1 && dashState) { + nsvg__prepareStroke(r, miterLimit, lineJoin); + nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); + } + // Advance dash pattern + dashState = !dashState; + idash = (idash+1) % shape->strokeDashCount; + dashLen = shape->strokeDashArray[idash] * scale; + // Restart + cur.x = x; + cur.y = y; + cur.flags = NSVG_PT_CORNER; + totalDist = 0.0f; + r->npoints = 0; + nsvg__appendPathPoint(r, cur); + } else { + totalDist += dist; + cur = r->points2[j]; + nsvg__appendPathPoint(r, cur); + j++; + } + } + // Stroke any leftover path + if (r->npoints > 1 && dashState) + nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); + } else { + nsvg__prepareStroke(r, miterLimit, lineJoin); + nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth); + } + } +} + +static int nsvg__cmpEdge(const void *p, const void *q) +{ + const NSVGedge* a = (const NSVGedge*)p; + const NSVGedge* b = (const NSVGedge*)q; + + if (a->y0 < b->y0) return -1; + if (a->y0 > b->y0) return 1; + return 0; +} + + +static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint) +{ + NSVGactiveEdge* z; + + if (r->freelist != NULL) { + // Restore from freelist. + z = r->freelist; + r->freelist = z->next; + } else { + // Alloc new edge. + z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge)); + if (z == NULL) return NULL; + } + + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); +// STBTT_assert(e->y0 <= start_point); + // round dx down to avoid going too far + if (dxdy < 0) + z->dx = (int)(-nsvg__roundf(NSVG__FIX * -dxdy)); + else + z->dx = (int)nsvg__roundf(NSVG__FIX * dxdy); + z->x = (int)nsvg__roundf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); +// z->x -= off_x * FIX; + z->ey = e->y1; + z->next = 0; + z->dir = e->dir; + + return z; +} + +static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z) +{ + z->next = r->freelist; + r->freelist = z; +} + +static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax) +{ + int i = x0 >> NSVG__FIXSHIFT; + int j = x1 >> NSVG__FIXSHIFT; + if (i < *xmin) *xmin = i; + if (j > *xmax) *xmax = j; + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT)); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT)); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT)); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = (unsigned char)(scanline[i] + maxWeight); + } + } +} + +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule) +{ + // non-zero winding fill + int x0 = 0, w = 0; + + if (fillRule == NSVG_FILLRULE_NONZERO) { + // Non-zero + while (e != NULL) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->dir; + } else { + int x1 = e->x; w += e->dir; + // if we went to zero, we need to draw + if (w == 0) + nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); + } + e = e->next; + } + } else if (fillRule == NSVG_FILLRULE_EVENODD) { + // Even-odd + while (e != NULL) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w = 1; + } else { + int x1 = e->x; w = 0; + nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); + } + e = e->next; + } + } +} + +static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } + +static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24); +} + +static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u) +{ + int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); + int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8; + int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8; + int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8; + int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8; + return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); +} + +static unsigned int nsvg__applyOpacity(unsigned int c, float u) +{ + int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); + int r = (c) & 0xff; + int g = (c>>8) & 0xff; + int b = (c>>16) & 0xff; + int a = (((c>>24) & 0xff)*iu) >> 8; + return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); +} + +static inline int nsvg__div255(int x) +{ + return ((x+1) * 257) >> 16; +} + +static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, + float tx, float ty, float scale, NSVGcachedPaint* cache) +{ + + if (cache->type == NSVG_PAINT_COLOR) { + int i, cr, cg, cb, ca; + cr = cache->colors[0] & 0xff; + cg = (cache->colors[0] >> 8) & 0xff; + cb = (cache->colors[0] >> 16) & 0xff; + ca = (cache->colors[0] >> 24) & 0xff; + + for (i = 0; i < count; i++) { + int r,g,b; + int a = nsvg__div255((int)cover[0] * ca); + int ia = 255 - a; + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + } + } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) { + // TODO: spread modes. + // TODO: plenty of opportunities to optimize. + float fx, fy, dx, gy; + float* t = cache->xform; + int i, cr, cg, cb, ca; + unsigned int c; + + fx = ((float)x - tx) / scale; + fy = ((float)y - ty) / scale; + dx = 1.0f / scale; + + for (i = 0; i < count; i++) { + int r,g,b,a,ia; + gy = fx*t[1] + fy*t[3] + t[5]; + c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)]; + cr = (c) & 0xff; + cg = (c >> 8) & 0xff; + cb = (c >> 16) & 0xff; + ca = (c >> 24) & 0xff; + + a = nsvg__div255((int)cover[0] * ca); + ia = 255 - a; + + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + fx += dx; + } + } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) { + // TODO: spread modes. + // TODO: plenty of opportunities to optimize. + // TODO: focus (fx,fy) + float fx, fy, dx, gx, gy, gd; + float* t = cache->xform; + int i, cr, cg, cb, ca; + unsigned int c; + + fx = ((float)x - tx) / scale; + fy = ((float)y - ty) / scale; + dx = 1.0f / scale; + + for (i = 0; i < count; i++) { + int r,g,b,a,ia; + gx = fx*t[0] + fy*t[2] + t[4]; + gy = fx*t[1] + fy*t[3] + t[5]; + gd = sqrtf(gx*gx + gy*gy); + c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)]; + cr = (c) & 0xff; + cg = (c >> 8) & 0xff; + cb = (c >> 16) & 0xff; + ca = (c >> 24) & 0xff; + + a = nsvg__div255((int)cover[0] * ca); + ia = 255 - a; + + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + fx += dx; + } + } +} + +static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule) +{ + NSVGactiveEdge *active = NULL; + int y, s; + int e = 0; + int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline + int xmin, xmax; + + for (y = 0; y < r->height; y++) { + memset(r->scanline, 0, r->width); + xmin = r->width; + xmax = 0; + for (s = 0; s < NSVG__SUBSAMPLES; ++s) { + // find center of pixel for this scanline + float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f; + NSVGactiveEdge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + NSVGactiveEdge *z = *step; + if (z->ey <= scany) { + *step = z->next; // delete from list +// NSVG__assert(z->valid); + nsvg__freeActive(r, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for (;;) { + int changed = 0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + NSVGactiveEdge* t = *step; + NSVGactiveEdge* q = t->next; + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e < r->nedges && r->edges[e].y0 <= scany) { + if (r->edges[e].y1 > scany) { + NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany); + if (z == NULL) break; + // find insertion point + if (active == NULL) { + active = z; + } else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + NSVGactiveEdge* p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + e++; + } + + // now process all active edges in non-zero fashion + if (active != NULL) + nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule); + } + // Blit + if (xmin < 0) xmin = 0; + if (xmax > r->width-1) xmax = r->width-1; + if (xmin <= xmax) { + nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache); + } + } + +} + +static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride) +{ + int x,y; + + // Unpremultiply + for (y = 0; y < h; y++) { + unsigned char *row = &image[y*stride]; + for (x = 0; x < w; x++) { + int r = row[0], g = row[1], b = row[2], a = row[3]; + if (a != 0) { + row[0] = (unsigned char)(r*255/a); + row[1] = (unsigned char)(g*255/a); + row[2] = (unsigned char)(b*255/a); + } + row += 4; + } + } + + // Defringe + for (y = 0; y < h; y++) { + unsigned char *row = &image[y*stride]; + for (x = 0; x < w; x++) { + int r = 0, g = 0, b = 0, a = row[3], n = 0; + if (a == 0) { + if (x-1 > 0 && row[-1] != 0) { + r += row[-4]; + g += row[-3]; + b += row[-2]; + n++; + } + if (x+1 < w && row[7] != 0) { + r += row[4]; + g += row[5]; + b += row[6]; + n++; + } + if (y-1 > 0 && row[-stride+3] != 0) { + r += row[-stride]; + g += row[-stride+1]; + b += row[-stride+2]; + n++; + } + if (y+1 < h && row[stride+3] != 0) { + r += row[stride]; + g += row[stride+1]; + b += row[stride+2]; + n++; + } + if (n > 0) { + row[0] = (unsigned char)(r/n); + row[1] = (unsigned char)(g/n); + row[2] = (unsigned char)(b/n); + } + } + row += 4; + } + } +} + + +static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity) +{ + int i, j; + NSVGgradient* grad; + + cache->type = paint->type; + + if (paint->type == NSVG_PAINT_COLOR) { + cache->colors[0] = nsvg__applyOpacity(paint->color, opacity); + return; + } + + grad = paint->gradient; + + cache->spread = grad->spread; + memcpy(cache->xform, grad->xform, sizeof(float)*6); + + if (grad->nstops == 0) { + for (i = 0; i < 256; i++) + cache->colors[i] = 0; + } else if (grad->nstops == 1) { + for (i = 0; i < 256; i++) + cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity); + } else { + unsigned int ca, cb = 0; + float ua, ub, du, u; + int ia, ib, count; + + ca = nsvg__applyOpacity(grad->stops[0].color, opacity); + ua = nsvg__clampf(grad->stops[0].offset, 0, 1); + ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); + ia = (int)(ua * 255.0f); + ib = (int)(ub * 255.0f); + for (i = 0; i < ia; i++) { + cache->colors[i] = ca; + } + + for (i = 0; i < grad->nstops-1; i++) { + ca = nsvg__applyOpacity(grad->stops[i].color, opacity); + cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity); + ua = nsvg__clampf(grad->stops[i].offset, 0, 1); + ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); + ia = (int)(ua * 255.0f); + ib = (int)(ub * 255.0f); + count = ib - ia; + if (count <= 0) continue; + u = 0; + du = 1.0f / (float)count; + for (j = 0; j < count; j++) { + cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u); + u += du; + } + } + + for (i = ib; i < 256; i++) + cache->colors[i] = cb; + } + +} + +/* +static void dumpEdges(NSVGrasterizer* r, const char* name) +{ + float xmin = 0, xmax = 0, ymin = 0, ymax = 0; + NSVGedge *e = NULL; + int i; + if (r->nedges == 0) return; + FILE* fp = fopen(name, "w"); + if (fp == NULL) return; + + xmin = xmax = r->edges[0].x0; + ymin = ymax = r->edges[0].y0; + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + xmin = nsvg__minf(xmin, e->x0); + xmin = nsvg__minf(xmin, e->x1); + xmax = nsvg__maxf(xmax, e->x0); + xmax = nsvg__maxf(xmax, e->x1); + ymin = nsvg__minf(ymin, e->y0); + ymin = nsvg__minf(ymin, e->y1); + ymax = nsvg__maxf(ymax, e->y0); + ymax = nsvg__maxf(ymax, e->y1); + } + + fprintf(fp, "", xmin, ymin, (xmax - xmin), (ymax - ymin)); + + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + fprintf(fp ,"", e->x0,e->y0, e->x1,e->y1); + } + + for (i = 0; i < r->npoints; i++) { + if (i+1 < r->npoints) + fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y); + fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0"); + } + + fprintf(fp, ""); + fclose(fp); +} +*/ + +void nsvgRasterize(NSVGrasterizer* r, + NSVGimage* image, float tx, float ty, float scale, + unsigned char* dst, int w, int h, int stride) +{ + NSVGshape *shape = NULL; + NSVGedge *e = NULL; + NSVGcachedPaint cache; + int i; + + r->bitmap = dst; + r->width = w; + r->height = h; + r->stride = stride; + + if (w > r->cscanline) { + r->cscanline = w; + r->scanline = (unsigned char*)realloc(r->scanline, w); + if (r->scanline == NULL) return; + } + + for (i = 0; i < h; i++) + memset(&dst[i*stride], 0, w*4); + + for (shape = image->shapes; shape != NULL; shape = shape->next) { + if (!(shape->flags & NSVG_FLAGS_VISIBLE)) + continue; + + if (shape->fill.type != NSVG_PAINT_NONE) { + nsvg__resetPool(r); + r->freelist = NULL; + r->nedges = 0; + + nsvg__flattenShape(r, shape, scale); + + // Scale and translate edges + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + e->x0 = tx + e->x0; + e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; + e->x1 = tx + e->x1; + e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; + } + + // Rasterize edges + if (r->nedges != 0) + qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); + + // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + nsvg__initPaint(&cache, &shape->fill, shape->opacity); + + nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); + } + if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) { + nsvg__resetPool(r); + r->freelist = NULL; + r->nedges = 0; + + nsvg__flattenShapeStroke(r, shape, scale); + +// dumpEdges(r, "edge.svg"); + + // Scale and translate edges + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + e->x0 = tx + e->x0; + e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; + e->x1 = tx + e->x1; + e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; + } + + // Rasterize edges + if (r->nedges != 0) + qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); + + // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + nsvg__initPaint(&cache, &shape->stroke, shape->opacity); + + nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); + } + } + + nsvg__unpremultiplyAlpha(dst, w, h, stride); + + r->bitmap = NULL; + r->width = 0; + r->height = 0; + r->stride = 0; +} + +#endif // NANOSVGRAST_IMPLEMENTATION + +#endif // NANOSVGRAST_H diff --git a/libraries/ZWidget/src/core/pathfill.cpp b/libraries/ZWidget/src/core/pathfill.cpp new file mode 100644 index 00000000000..bac3dfb5074 --- /dev/null +++ b/libraries/ZWidget/src/core/pathfill.cpp @@ -0,0 +1,613 @@ + +#include "core/pathfill.h" +#include +#include + +static const int AntialiasLevel = 8; +static const int MaskBlockSize = 16; +static const int MaskBufferSize = MaskBlockSize * MaskBlockSize; +static const int ScanlineBlockSize = MaskBlockSize * AntialiasLevel; + +class PathScanlineEdge +{ +public: + PathScanlineEdge() = default; + PathScanlineEdge(double x, bool up_direction) : x(x), up_direction(up_direction) { } + + double x = 0.0; + bool up_direction = false; +}; + +class PathScanline +{ +public: + std::vector edges; + std::vector pixels; + + void insert_sorted(PathScanlineEdge edge) + { + edges.push_back(edge); + + for (size_t pos = edges.size() - 1; pos > 0 && edges[pos - 1].x >= edge.x; pos--) + { + PathScanlineEdge temp = edges[pos - 1]; + edges[pos - 1] = edges[pos]; + edges[pos] = temp; + } + } +}; + +class PathRasterRange +{ +public: + void Begin(const PathScanline* scanline, PathFillMode mode); + void Next(); + + bool found = false; + int x0; + int x1; + +private: + const PathScanline* scanline = nullptr; + PathFillMode mode; + size_t i = 0; + int nonzero_rule = 0; +}; + +enum class PathFillBlockResult +{ + Empty, + Partial, + Full +}; + +class PathMaskBuffer +{ +public: + void BeginRow(PathScanline* scanlines, PathFillMode mode); + PathFillBlockResult FillBlock(int xpos); + + unsigned char MaskBufferData[MaskBufferSize]; + +private: + bool IsFullBlock(int xpos) const; + + PathRasterRange Range[ScanlineBlockSize]; +}; + +class PathFillRasterizer +{ +public: + void Rasterize(const PathFillDesc& path, uint8_t* dest, int width, int height); + +private: + void Clear(); + + void Begin(double x, double y); + void QuadraticBezier(double cp1_x, double cp1_y, double cp2_x, double cp2_y); + void CubicBezier(double cp1_x, double cp1_y, double cp2_x, double cp2_y, double cp3_x, double cp3_y); + void Line(double x, double y); + void End(bool close); + + void SubdivideBezier(int level, double cp0_x, double cp0_y, double cp1_x, double cp1_y, double cp2_x, double cp2_y, double cp3_x, double cp3_y, double t0, double t1); + static Point PointOnBezier(double cp0_x, double cp0_y, double cp1_x, double cp1_y, double cp2_x, double cp2_y, double cp3_x, double cp3_y, double t); + + void Fill(PathFillMode mode, uint8_t* dest, int dest_width, int dest_height); + + struct Extent + { + Extent() : left(INT_MAX), right(0) {} + int left; + int right; + }; + + Extent FindExtent(const PathScanline* scanline, int max_width); + + double start_x = 0.0; + double start_y = 0.0; + double last_x = 0.0; + double last_y = 0.0; + + int first_scanline = 0; + int last_scanline = 0; + + int width = 0; + int height = 0; + std::vector scanlines; + + PathMaskBuffer mask_blocks; +}; + +///////////////////////////////////////////////////////////////////////////// + +void PathFillDesc::Rasterize(uint8_t* dest, int width, int height, bool blend) +{ + if (!blend) + { + memset(dest, 0, width * height); + } + PathFillRasterizer rasterizer; + rasterizer.Rasterize(*this, dest, width, height); +} + +///////////////////////////////////////////////////////////////////////////// + +void PathFillRasterizer::Rasterize(const PathFillDesc& path, uint8_t* dest, int dest_width, int dest_height) +{ + Clear(); + + // For simplicity of the code, ensure the mask is always a multiple of MaskBlockSize + int block_width = ScanlineBlockSize * ((dest_width + MaskBlockSize - 1) / MaskBlockSize); + int block_height = ScanlineBlockSize * ((dest_height + MaskBlockSize - 1) / MaskBlockSize); + + if (width != block_width || height != block_height) + { + width = block_width; + height = block_height; + + scanlines.resize(block_height); + first_scanline = scanlines.size(); + last_scanline = 0; + } + + for (const auto& subpath : path.subpaths) + { + Point start_point = subpath.points[0]; + Begin(start_point.x, start_point.y); + + size_t i = 1; + for (PathFillCommand command : subpath.commands) + { + if (command == PathFillCommand::line) + { + const Point& next_point = subpath.points[i]; + i++; + + Line(next_point.x, next_point.y); + } + else if (command == PathFillCommand::quadradic) + { + const Point& control = subpath.points[i]; + const Point& next_point = subpath.points[i + 1]; + i += 2; + + QuadraticBezier(control.x, control.y, next_point.x, next_point.y); + } + else if (command == PathFillCommand::cubic) + { + const Point& control1 = subpath.points[i]; + const Point& control2 = subpath.points[i + 1]; + const Point& next_point = subpath.points[i + 2]; + i += 3; + + CubicBezier(control1.x, control1.y, control2.x, control2.y, next_point.x, next_point.y); + } + } + + End(subpath.closed); + } + + Fill(path.fill_mode, dest, dest_width, dest_height); +} + +void PathFillRasterizer::Fill(PathFillMode mode, uint8_t* dest, int dest_width, int dest_height) +{ + if (scanlines.empty()) return; + + int start_y = first_scanline / ScanlineBlockSize * ScanlineBlockSize; + int end_y = (last_scanline + ScanlineBlockSize - 1) / ScanlineBlockSize * ScanlineBlockSize; + + for (int ypos = start_y; ypos < end_y; ypos += ScanlineBlockSize) + { + mask_blocks.BeginRow(&scanlines[ypos], mode); + + Extent extent = FindExtent(&scanlines[ypos], width); + for (int xpos = extent.left; xpos < extent.right; xpos += ScanlineBlockSize) + { + PathFillBlockResult result = mask_blocks.FillBlock(xpos); + + int dest_x = xpos / AntialiasLevel; + int dest_y = ypos / AntialiasLevel; + int count_x = std::min(dest_x + MaskBlockSize, dest_width) - dest_x; + int count_y = std::min(dest_y + MaskBlockSize, dest_height) - dest_y; + + if (result == PathFillBlockResult::Full) + { + for (int i = 0; i < count_y; i++) + { + uint8_t* dline = dest + dest_x + (dest_y + i) * dest_width; + memset(dline, 255, count_x); + } + } + else if (result == PathFillBlockResult::Partial) + { + for (int i = 0; i < count_y; i++) + { + const uint8_t* sline = mask_blocks.MaskBufferData + i * MaskBlockSize; + uint8_t* dline = dest + dest_x + (dest_y + i) * dest_width; + for (int j = 0; j < count_x; j++) + { + dline[j] = std::min((int)dline[j] + (int)sline[j], 255); + } + } + } + } + } +} + +PathFillRasterizer::Extent PathFillRasterizer::FindExtent(const PathScanline* scanline, int max_width) +{ + // Find scanline extents + Extent extent; + for (unsigned int cnt = 0; cnt < ScanlineBlockSize; cnt++, scanline++) + { + if (scanline->edges.empty()) + continue; + + extent.left = std::min(extent.left, (int)scanline->edges.front().x); + extent.right = std::max(extent.right, (int)scanline->edges.back().x); + } + extent.left = std::max(extent.left, 0); + extent.right = std::min(extent.right, max_width); + + return extent; +} + +void PathFillRasterizer::Clear() +{ + for (size_t y = first_scanline; y < last_scanline; y++) + { + auto& scanline = scanlines[y]; + if (!scanline.edges.empty()) + { + scanline.edges.clear(); + } + } + + first_scanline = scanlines.size(); + last_scanline = 0; +} + +void PathFillRasterizer::Begin(double x, double y) +{ + start_x = last_x = x; + start_y = last_y = y; +} + +void PathFillRasterizer::End(bool close) +{ + if (close) + { + Line(start_x, start_y); + } +} + +void PathFillRasterizer::QuadraticBezier(double qcp1_x, double qcp1_y, double qcp2_x, double qcp2_y) +{ + double qcp0_x = last_x; + double qcp0_y = last_y; + + // Convert to cubic: + double cp1_x = qcp0_x + 2.0 * (qcp1_x - qcp0_x) / 3.0; + double cp1_y = qcp0_y + 2.0 * (qcp1_y - qcp0_y) / 3.0; + double cp2_x = qcp1_x + (qcp2_x - qcp1_x) / 3.0; + double cp2_y = qcp1_y + (qcp2_y - qcp1_y) / 3.0; + double cp3_x = qcp2_x; + double cp3_y = qcp2_y; + CubicBezier(cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y); +} + +void PathFillRasterizer::CubicBezier(double cp1_x, double cp1_y, double cp2_x, double cp2_y, double cp3_x, double cp3_y) +{ + double cp0_x = last_x; + double cp0_y = last_y; + + double estimated_length = + std::sqrt((cp1_x - cp0_x) * (cp1_x - cp0_x) + (cp1_y - cp0_y) * (cp1_y - cp0_y)) + + std::sqrt((cp1_x - cp0_x) * (cp1_x - cp0_x) + (cp1_y - cp0_y) * (cp1_y - cp0_y)) + + std::sqrt((cp1_x - cp0_x) * (cp1_x - cp0_x) + (cp1_y - cp0_y) * (cp1_y - cp0_y)); + + double min_segs = 10.0; + double segs = estimated_length / 5.0; + int steps = (int)std::ceil(std::sqrt(segs * segs * 0.3f + min_segs)); + for (int i = 0; i < steps; i++) + { + //Point sp = PointOnBezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, i / (double)steps); + Point ep = PointOnBezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, (i + 1) / (double)steps); + Line(ep.x, ep.y); + } + + // http://ciechanowski.me/blog/2014/02/18/drawing-bezier-curves/ + // http://antigrain.com/research/adaptive_bezier/ (best method, unfortunately GPL example code) +} + +void PathFillRasterizer::SubdivideBezier(int level, double cp0_x, double cp0_y, double cp1_x, double cp1_y, double cp2_x, double cp2_y, double cp3_x, double cp3_y, double t0, double t1) +{ + const double split_angle_cos = 0.99f; + + double tc = (t0 + t1) * 0.5f; + + Point sp = PointOnBezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, t0); + Point cp = PointOnBezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, tc); + Point ep = PointOnBezier(cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, t1); + + Point sp2cp(cp.x - sp.x, cp.y - sp.y); + Point cp2ep(ep.x - cp.x, ep.y - cp.y); + + // Normalize + double len_sp2cp = std::sqrt(sp2cp.x * sp2cp.x + sp2cp.y * sp2cp.y); + double len_cp2ep = std::sqrt(cp2ep.x * cp2ep.x + cp2ep.y * cp2ep.y); + if (len_sp2cp > 0.0) { sp2cp.x /= len_sp2cp; sp2cp.y /= len_sp2cp; } + if (len_cp2ep > 0.0) { cp2ep.x /= len_cp2ep; cp2ep.y /= len_cp2ep; } + + double dot = sp2cp.x * cp2ep.x + sp2cp.y * cp2ep.y; + if (dot < split_angle_cos && level < 15) + { + SubdivideBezier(level + 1, cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, t0, tc); + SubdivideBezier(level + 1, cp0_x, cp0_y, cp1_x, cp1_y, cp2_x, cp2_y, cp3_x, cp3_y, tc, t1); + } + else + { + Line(ep.x, ep.y); + } +} + +Point PathFillRasterizer::PointOnBezier(double cp0_x, double cp0_y, double cp1_x, double cp1_y, double cp2_x, double cp2_y, double cp3_x, double cp3_y, double t) +{ + const int num_cp = 4; + + double cp_x[4] = { cp0_x, cp1_x, cp2_x, cp3_x }; + double cp_y[4] = { cp0_y, cp1_y, cp2_y, cp3_y }; + + // Perform deCasteljau iterations: + // (linear interpolate between the control points) + double a = 1.0 - t; + double b = t; + for (int j = num_cp - 1; j > 0; j--) + { + for (int i = 0; i < j; i++) + { + cp_x[i] = a * cp_x[i] + b * cp_x[i + 1]; + cp_y[i] = a * cp_y[i] + b * cp_y[i + 1]; + } + } + + return Point(cp_x[0], cp_y[0]); +} + +void PathFillRasterizer::Line(double x1, double y1) +{ + double x0 = last_x; + double y0 = last_y; + + last_x = x1; + last_y = y1; + + x0 *= static_cast(AntialiasLevel); + x1 *= static_cast(AntialiasLevel); + y0 *= static_cast(AntialiasLevel); + y1 *= static_cast(AntialiasLevel); + + bool up_direction = y1 < y0; + double dy = y1 - y0; + + constexpr const double epsilon = std::numeric_limits::epsilon(); + if (dy < -epsilon || dy > epsilon) + { + int start_y = static_cast(std::floor(std::min(y0, y1) + 0.5f)); + int end_y = static_cast(std::floor(std::max(y0, y1) - 0.5f)) + 1; + + start_y = std::max(start_y, 0); + end_y = std::min(end_y, height); + + double rcp_dy = 1.0 / dy; + + first_scanline = std::min(first_scanline, start_y); + last_scanline = std::max(last_scanline, end_y); + + for (int y = start_y; y < end_y; y++) + { + double ypos = y + 0.5f; + double x = x0 + (x1 - x0) * (ypos - y0) * rcp_dy; + scanlines[y].insert_sorted(PathScanlineEdge(x, up_direction)); + } + } +} + +///////////////////////////////////////////////////////////////////////////// + +void PathRasterRange::Begin(const PathScanline* new_scanline, PathFillMode new_mode) +{ + scanline = new_scanline; + mode = new_mode; + found = false; + i = 0; + nonzero_rule = 0; + Next(); +} + +void PathRasterRange::Next() +{ + if (i + 1 >= scanline->edges.size()) + { + found = false; + return; + } + + if (mode == PathFillMode::alternate) + { + x0 = static_cast(scanline->edges[i].x + 0.5f); + x1 = static_cast(scanline->edges[i + 1].x - 0.5f) + 1; + i += 2; + found = true; + } + else + { + x0 = static_cast(scanline->edges[i].x + 0.5f); + nonzero_rule += scanline->edges[i].up_direction ? 1 : -1; + i++; + + while (i < scanline->edges.size()) + { + nonzero_rule += scanline->edges[i].up_direction ? 1 : -1; + x1 = static_cast(scanline->edges[i].x - 0.5f) + 1; + i++; + + if (nonzero_rule == 0) + { + found = true; + return; + } + } + found = false; + } +} + +///////////////////////////////////////////////////////////////////////// + +void PathMaskBuffer::BeginRow(PathScanline* scanlines, PathFillMode mode) +{ + for (unsigned int cnt = 0; cnt < ScanlineBlockSize; cnt++) + { + Range[cnt].Begin(&scanlines[cnt], mode); + } +} + +#if 0 +PathFillBlockResult PathMaskBuffer::FillBlock(int xpos) +{ + if (IsFullBlock(xpos)) + { + return PathFillBlockResult::Full; + } + + const int block_size = MaskBlockSize / 16 * MaskBlockSize; + __m128i block[block_size]; + + for (auto& elem : block) + elem = _mm_setzero_si128(); + + for (unsigned int cnt = 0; cnt < ScanlineBlockSize; cnt++) + { + __m128i* line = &block[MaskBlockSize / 16 * (cnt / AntialiasLevel)]; + + while (range[cnt].found) + { + int x0 = range[cnt].x0; + if (x0 >= xpos + ScanlineBlockSize) + break; + int x1 = range[cnt].x1; + + x0 = max(x0, xpos); + x1 = min(x1, xpos + ScanlineBlockSize); + + if (x0 >= x1) // Done segment + { + range[cnt].next(); + } + else + { + for (int sse_block = 0; sse_block < MaskBlockSize / 16; sse_block++) + { + for (int alias_cnt = 0; alias_cnt < (AntialiasLevel); alias_cnt++) + { + __m128i start = _mm_set1_epi8((x0 + alias_cnt - xpos) / AntialiasLevel - 16 * sse_block); + __m128i end = _mm_set1_epi8((x1 + alias_cnt - xpos) / AntialiasLevel - 16 * sse_block); + __m128i x = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + + __m128i left = _mm_cmplt_epi8(x, start); + __m128i right = _mm_cmplt_epi8(x, end); + __m128i mask = _mm_andnot_si128(left, right); + __m128i add_value = _mm_and_si128(mask, _mm_set1_epi8(256 / (AntialiasLevel * AntialiasLevel))); + + line[sse_block] = _mm_adds_epu8(line[sse_block], add_value); + } + } + + range[cnt].x0 = x1; // For next time + } + } + } + + __m128i empty_status = _mm_setzero_si128(); + for (auto& elem : block) + empty_status = _mm_or_si128(empty_status, elem); + + bool empty_block = _mm_movemask_epi8(_mm_cmpeq_epi32(empty_status, _mm_setzero_si128())) == 0xffff; + if (empty_block) return PathFillBlockResult::Empty; + + for (unsigned int cnt = 0; cnt < MaskBlockSize; cnt++) + { + __m128i* input = &block[MaskBlockSize / 16 * cnt]; + __m128i* output = (__m128i*)(MaskBufferData + cnt * mask_texture_size); + + for (int sse_block = 0; sse_block < MaskBlockSize / 16; sse_block++) + _mm_storeu_si128(&output[sse_block], input[sse_block]); + } + + return PathFillBlockResult::Partial; +} + +#else + +PathFillBlockResult PathMaskBuffer::FillBlock(int xpos) +{ + if (IsFullBlock(xpos)) + { + return PathFillBlockResult::Full; + } + + memset(MaskBufferData, 0, MaskBufferSize); + + bool empty_block = true; + for (unsigned int cnt = 0; cnt < ScanlineBlockSize; cnt++) + { + unsigned char* line = MaskBufferData + MaskBlockSize * (cnt / AntialiasLevel); + while (Range[cnt].found) + { + int x0 = Range[cnt].x0; + if (x0 >= xpos + ScanlineBlockSize) + break; + int x1 = Range[cnt].x1; + + x0 = std::max(x0, xpos); + x1 = std::min(x1, xpos + ScanlineBlockSize); + + if (x0 >= x1) // Done segment + { + Range[cnt].Next(); + } + else + { + empty_block = false; + for (int x = x0 - xpos; x < x1 - xpos; x++) + { + int pixel = line[x / AntialiasLevel]; + pixel = std::min(pixel + (256 / (AntialiasLevel * AntialiasLevel)), 255); + line[x / AntialiasLevel] = pixel; + } + Range[cnt].x0 = x1; // For next time + } + } + } + + return empty_block ? PathFillBlockResult::Empty : PathFillBlockResult::Partial; +} + +#endif + +bool PathMaskBuffer::IsFullBlock(int xpos) const +{ + for (auto& elem : Range) + { + if (!elem.found) + { + return false; + } + if ((elem.x0 > xpos) || (elem.x1 < (xpos + ScanlineBlockSize - 1))) + { + return false; + } + } + return true; +} diff --git a/libraries/ZWidget/src/core/picopng/LICENSE.txt b/libraries/ZWidget/src/core/picopng/LICENSE.txt new file mode 100644 index 00000000000..a1f522f51b0 --- /dev/null +++ b/libraries/ZWidget/src/core/picopng/LICENSE.txt @@ -0,0 +1,18 @@ + // picoPNG version 20101224 + // Copyright (c) 2005-2010 Lode Vandevenne + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. diff --git a/libraries/ZWidget/src/core/picopng/picopng.cpp b/libraries/ZWidget/src/core/picopng/picopng.cpp new file mode 100644 index 00000000000..97eb3b500f6 --- /dev/null +++ b/libraries/ZWidget/src/core/picopng/picopng.cpp @@ -0,0 +1,595 @@ +#include +#include +#include + +/* +decodePNG: The picoPNG function, decodes a PNG file buffer in memory, into a raw pixel buffer. +out_image: output parameter, this will contain the raw pixels after decoding. + By default the output is 32-bit RGBA color. + The std::vector is automatically resized to the correct size. +image_width: output_parameter, this will contain the width of the image in pixels. +image_height: output_parameter, this will contain the height of the image in pixels. +in_png: pointer to the buffer of the PNG file in memory. To get it from a file on + disk, load it and store it in a memory buffer yourself first. +in_size: size of the input PNG file in bytes. +convert_to_rgba32: optional parameter, true by default. + Set to true to get the output in RGBA 32-bit (8 bit per channel) color format + no matter what color type the original PNG image had. This gives predictable, + useable data from any random input PNG. + Set to false to do no color conversion at all. The result then has the same data + type as the PNG image, which can range from 1 bit to 64 bits per pixel. + Information about the color type or palette colors are not provided. You need + to know this information yourself to be able to use the data so this only + works for trusted PNG files. Use LodePNG instead of picoPNG if you need this information. +return: 0 if success, not 0 if some error occured. +*/ +int decodePNG(std::vector& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true) +{ + // picoPNG version 20101224 + // Copyright (c) 2005-2010 Lode Vandevenne + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + // picoPNG is a PNG decoder in one C++ function of around 500 lines. Use picoPNG for + // programs that need only 1 .cpp file. Since it's a single function, it's very limited, + // it can convert a PNG to raw pixel data either converted to 32-bit RGBA color or + // with no color conversion at all. For anything more complex, another tiny library + // is available: LodePNG (lodepng.c(pp)), which is a single source and header file. + // Apologies for the compact code style, it's to make this tiny. + + static const unsigned long LENBASE[29] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258}; + static const unsigned long LENEXTRA[29] = {0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const unsigned long DISTBASE[30] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}; + static const unsigned long DISTEXTRA[30] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + static const unsigned long CLCL[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; //code length code lengths + struct Zlib //nested functions for zlib decompression + { + static unsigned long readBitFromStream(size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1; bitp++; return result;} + static unsigned long readBitsFromStream(size_t& bitp, const unsigned char* bits, size_t nbits) + { + unsigned long result = 0; + for(size_t i = 0; i < nbits; i++) result += (readBitFromStream(bitp, bits)) << i; + return result; + } + struct HuffmanTree + { + int makeFromLengths(const std::vector& bitlen, unsigned long maxbitlen) + { //make tree given the lengths + unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0; + std::vector tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0); + for(unsigned long bits = 0; bits < numcodes; bits++) blcount[bitlen[bits]]++; //count number of instances of each code length + for(unsigned long bits = 1; bits <= maxbitlen; bits++) nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1; + for(unsigned long n = 0; n < numcodes; n++) if(bitlen[n] != 0) tree1d[n] = nextcode[bitlen[n]]++; //generate all the codes + tree2d.clear(); tree2d.resize(numcodes * 2, 32767); //32767 here means the tree2d isn't filled there yet + for(unsigned long n = 0; n < numcodes; n++) //the codes + for(unsigned long i = 0; i < bitlen[n]; i++) //the bits for this code + { + unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1; + if(treepos > numcodes - 2) return 55; + if(tree2d[2 * treepos + bit] == 32767) //not yet filled in + { + if(i + 1 == bitlen[n]) { tree2d[2 * treepos + bit] = n; treepos = 0; } //last bit + else { tree2d[2 * treepos + bit] = ++nodefilled + numcodes; treepos = nodefilled; } //addresses are encoded as values > numcodes + } + else treepos = tree2d[2 * treepos + bit] - numcodes; //subtract numcodes from address to get address value + } + return 0; + } + int decode(bool& decoded, unsigned long& result, size_t& treepos, unsigned long bit) const + { //Decodes a symbol from the tree + unsigned long numcodes = (unsigned long)tree2d.size() / 2; + if(treepos >= numcodes) return 11; //error: you appeared outside the codetree + result = tree2d[2 * treepos + bit]; + decoded = (result < numcodes); + treepos = decoded ? 0 : result - numcodes; + return 0; + } + std::vector tree2d; //2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all nodes and leaves of the tree. + }; + struct Inflator + { + int error; + void inflate(std::vector& out, const std::vector& in, size_t inpos = 0) + { + size_t bp = 0, pos = 0; //bit pointer and byte pointer + error = 0; + unsigned long BFINAL = 0; + while(!BFINAL && !error) + { + if(bp >> 3 >= in.size()) { error = 52; return; } //error, bit pointer will jump past memory + BFINAL = readBitFromStream(bp, &in[inpos]); + unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); BTYPE += 2 * readBitFromStream(bp, &in[inpos]); + if(BTYPE == 3) { error = 20; return; } //error: invalid BTYPE + else if(BTYPE == 0) inflateNoCompression(out, &in[inpos], bp, pos, in.size()); + else inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE); + } + if(!error) out.resize(pos); //Only now we know the true size of out, resize it to that + } + void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) //get the tree of a deflated block with fixed tree + { + std::vector bitlen(288, 8), bitlenD(32, 5);; + for(size_t i = 144; i <= 255; i++) bitlen[i] = 9; + for(size_t i = 256; i <= 279; i++) bitlen[i] = 7; + tree.makeFromLengths(bitlen, 15); + treeD.makeFromLengths(bitlenD, 15); + } + HuffmanTree codetree, codetreeD, codelengthcodetree; //the code tree for Huffman codes, dist codes, and code length codes + unsigned long huffmanDecodeSymbol(const unsigned char* in, size_t& bp, const HuffmanTree& codetree, size_t inlength) + { //decode a single symbol from given list of bits with given code tree. return value is the symbol + bool decoded; unsigned long ct; + for(size_t treepos = 0;;) + { + if((bp & 0x07) == 0 && (bp >> 3) > inlength) { error = 10; return 0; } //error: end reached without endcode + error = codetree.decode(decoded, ct, treepos, readBitFromStream(bp, in)); if(error) return 0; //stop, an error happened + if(decoded) return ct; + } + } + void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD, const unsigned char* in, size_t& bp, size_t inlength) + { //get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree + std::vector bitlen(288, 0), bitlenD(32, 0); + if(bp >> 3 >= inlength - 2) { error = 49; return; } //the bit pointer is or will go past the memory + size_t HLIT = readBitsFromStream(bp, in, 5) + 257; //number of literal/length codes + 257 + size_t HDIST = readBitsFromStream(bp, in, 5) + 1; //number of dist codes + 1 + size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; //number of code length codes + 4 + std::vector codelengthcode(19); //lengths of tree to decode the lengths of the dynamic tree + for(size_t i = 0; i < 19; i++) codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0; + error = codelengthcodetree.makeFromLengths(codelengthcode, 7); if(error) return; + size_t i = 0, replength; + while(i < HLIT + HDIST) + { + unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength); if(error) return; + if(code <= 15) { if(i < HLIT) bitlen[i++] = code; else bitlenD[i++ - HLIT] = code; } //a length code + else if(code == 16) //repeat previous + { + if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory + replength = 3 + readBitsFromStream(bp, in, 2); + unsigned long value; //set value to the previous code + if((i - 1) < HLIT) value = bitlen[i - 1]; + else value = bitlenD[i - HLIT - 1]; + for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths + { + if(i >= HLIT + HDIST) { error = 13; return; } //error: i is larger than the amount of codes + if(i < HLIT) bitlen[i++] = value; else bitlenD[i++ - HLIT] = value; + } + } + else if(code == 17) //repeat "0" 3-10 times + { + if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory + replength = 3 + readBitsFromStream(bp, in, 3); + for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths + { + if(i >= HLIT + HDIST) { error = 14; return; } //error: i is larger than the amount of codes + if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0; + } + } + else if(code == 18) //repeat "0" 11-138 times + { + if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory + replength = 11 + readBitsFromStream(bp, in, 7); + for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths + { + if(i >= HLIT + HDIST) { error = 15; return; } //error: i is larger than the amount of codes + if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0; + } + } + else { error = 16; return; } //error: somehow an unexisting code appeared. This can never happen. + } + if(bitlen[256] == 0) { error = 64; return; } //the length of the end code 256 must be larger than 0 + error = tree.makeFromLengths(bitlen, 15); if(error) return; //now we've finally got HLIT and HDIST, so generate the code trees, and the function is done + error = treeD.makeFromLengths(bitlenD, 15); if(error) return; + } + void inflateHuffmanBlock(std::vector& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength, unsigned long btype) + { + if(btype == 1) { generateFixedTrees(codetree, codetreeD); } + else if(btype == 2) { getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength); if(error) return; } + for(;;) + { + unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength); if(error) return; + if(code == 256) return; //end code + else if(code <= 255) //literal symbol + { + if(pos >= out.size()) out.resize((pos + 1) * 2); //reserve more room + out[pos++] = (unsigned char)(code); + } + else if(code >= 257 && code <= 285) //length code + { + size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257]; + if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory + length += readBitsFromStream(bp, in, numextrabits); + unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength); if(error) return; + if(codeD > 29) { error = 18; return; } //error: invalid dist code (30-31 are never used) + unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD]; + if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory + dist += readBitsFromStream(bp, in, numextrabitsD); + size_t start = pos, back = start - dist; //backwards + if(pos + length >= out.size()) out.resize((pos + length) * 2); //reserve more room + for(size_t i = 0; i < length; i++) { out[pos++] = out[back++]; if(back >= start) back = start - dist; } + } + } + } + void inflateNoCompression(std::vector& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength) + { + while((bp & 0x7) != 0) bp++; //go to first boundary of byte + size_t p = bp / 8; + if(p >= inlength - 4) { error = 52; return; } //error, bit pointer will jump past memory + unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3]; p += 4; + if(LEN + NLEN != 65535) { error = 21; return; } //error: NLEN is not one's complement of LEN + if(pos + LEN >= out.size()) out.resize(pos + LEN); + if(p + LEN > inlength) { error = 23; return; } //error: reading outside of in buffer + for(unsigned long n = 0; n < LEN; n++) out[pos++] = in[p++]; //read LEN bytes of literal data + bp = p * 8; + } + }; + int decompress(std::vector& out, const std::vector& in) //returns error value + { + Inflator inflator; + if(in.size() < 2) { return 53; } //error, size of zlib data too small + if((in[0] * 256 + in[1]) % 31 != 0) { return 24; } //error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way + unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1; + if(CM != 8 || CINFO > 7) { return 25; } //error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec + if(FDICT != 0) { return 26; } //error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary." + inflator.inflate(out, in, 2); + return inflator.error; //note: adler32 checksum was skipped and ignored + } + }; + struct PNG //nested functions for PNG decoding + { + struct Info + { + unsigned long width, height, colorType, bitDepth, compressionMethod, filterMethod, interlaceMethod, key_r, key_g, key_b; + bool key_defined; //is a transparent color key given? + std::vector palette; + } info; + int error; + void decode(std::vector& out, const unsigned char* in, size_t size, bool convert_to_rgba32) + { + error = 0; + if(size == 0 || in == 0) { error = 48; return; } //the given data is empty + readPngHeader(&in[0], size); if(error) return; + size_t pos = 33; //first byte of the first chunk after the header + std::vector idat; //the data from idat chunks + bool IEND = false, known_type = true; + info.key_defined = false; + while(!IEND) //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer + { + if(pos + 8 >= size) { error = 30; return; } //error: size of the in buffer too small to contain next chunk + size_t chunkLength = read32bitInt(&in[pos]); pos += 4; + if(chunkLength > 2147483647) { error = 63; return; } + if(pos + chunkLength >= size) { error = 35; return; } //error: size of the in buffer too small to contain next chunk + if(in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T') //IDAT chunk, containing compressed image data + { + idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]); + pos += (4 + chunkLength); + } + else if(in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D') { pos += 4; IEND = true; } + else if(in[pos + 0] == 'P' && in[pos + 1] == 'L' && in[pos + 2] == 'T' && in[pos + 3] == 'E') //palette chunk (PLTE) + { + pos += 4; //go after the 4 letters + info.palette.resize(4 * (chunkLength / 3)); + if(info.palette.size() > (4 * 256)) { error = 38; return; } //error: palette too big + for(size_t i = 0; i < info.palette.size(); i += 4) + { + for(size_t j = 0; j < 3; j++) info.palette[i + j] = in[pos++]; //RGB + info.palette[i + 3] = 255; //alpha + } + } + else if(in[pos + 0] == 't' && in[pos + 1] == 'R' && in[pos + 2] == 'N' && in[pos + 3] == 'S') //palette transparency chunk (tRNS) + { + pos += 4; //go after the 4 letters + if(info.colorType == 3) + { + if(4 * chunkLength > info.palette.size()) { error = 39; return; } //error: more alpha values given than there are palette entries + for(size_t i = 0; i < chunkLength; i++) info.palette[4 * i + 3] = in[pos++]; + } + else if(info.colorType == 0) + { + if(chunkLength != 2) { error = 40; return; } //error: this chunk must be 2 bytes for greyscale image + info.key_defined = 1; info.key_r = info.key_g = info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2; + } + else if(info.colorType == 2) + { + if(chunkLength != 6) { error = 41; return; } //error: this chunk must be 6 bytes for RGB image + info.key_defined = 1; + info.key_r = 256 * in[pos] + in[pos + 1]; pos += 2; + info.key_g = 256 * in[pos] + in[pos + 1]; pos += 2; + info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2; + } + else { error = 42; return; } //error: tRNS chunk not allowed for other color models + } + else //it's not an implemented chunk type, so ignore it: skip over the data + { + if(!(in[pos + 0] & 32)) { error = 69; return; } //error: unknown critical chunk (5th bit of first byte of chunk type is 0) + pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk + known_type = false; + } + pos += 4; //step over CRC (which is ignored) + } + unsigned long bpp = getBpp(info); + std::vector scanlines(((info.width * (info.height * bpp + 7)) / 8) + info.height); //now the out buffer will be filled + Zlib zlib; //decompress with the Zlib decompressor + error = zlib.decompress(scanlines, idat); if(error) return; //stop if the zlib decompressor returned an error + size_t bytewidth = (bpp + 7) / 8, outlength = (info.height * info.width * bpp + 7) / 8; + out.resize(outlength); //time to fill the out buffer + unsigned char* out_ = outlength ? &out[0] : 0; //use a regular pointer to the std::vector for faster code if compiled without optimization + if(info.interlaceMethod == 0) //no interlace, just filter + { + size_t linestart = 0, linelength = (info.width * bpp + 7) / 8; //length in bytes of a scanline, excluding the filtertype byte + if(bpp >= 8) //byte per byte + for(unsigned long y = 0; y < info.height; y++) + { + unsigned long filterType = scanlines[linestart]; + const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth]; + unFilterScanline(&out_[linestart - y], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return; + linestart += (1 + linelength); //go to start of next scanline + } + else //less than 8 bits per pixel, so fill it up bit per bit + { + std::vector templine((info.width * bpp + 7) >> 3); //only used if bpp < 8 + for(size_t y = 0, obp = 0; y < info.height; y++) + { + unsigned long filterType = scanlines[linestart]; + const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth]; + unFilterScanline(&templine[0], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return; + for(size_t bp = 0; bp < info.width * bpp;) setBitOfReversedStream(obp, out_, readBitFromReversedStream(bp, &templine[0])); + linestart += (1 + linelength); //go to start of next scanline + } + } + } + else //interlaceMethod is 1 (Adam7) + { + size_t passw[7] = { (info.width + 7) / 8, (info.width + 3) / 8, (info.width + 3) / 4, (info.width + 1) / 4, (info.width + 1) / 2, (info.width + 0) / 2, (info.width + 0) / 1 }; + size_t passh[7] = { (info.height + 7) / 8, (info.height + 7) / 8, (info.height + 3) / 8, (info.height + 3) / 4, (info.height + 1) / 4, (info.height + 1) / 2, (info.height + 0) / 2 }; + size_t passstart[7] = {0}; + size_t pattern[28] = {0,4,0,2,0,1,0,0,0,4,0,2,0,1,8,8,4,4,2,2,1,8,8,8,4,4,2,2}; //values for the adam7 passes + for(int i = 0; i < 6; i++) passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8); + std::vector scanlineo((info.width * bpp + 7) / 8), scanlinen((info.width * bpp + 7) / 8); //"old" and "new" scanline + for(int i = 0; i < 7; i++) + adam7Pass(&out_[0], &scanlinen[0], &scanlineo[0], &scanlines[passstart[i]], info.width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21], passw[i], passh[i], bpp); + } + if(convert_to_rgba32 && (info.colorType != 6 || info.bitDepth != 8)) //conversion needed + { + std::vector data = out; + error = convert(out, &data[0], info, info.width, info.height); + } + } + void readPngHeader(const unsigned char* in, size_t inlength) //read the information from the header and store it in the Info + { + if(inlength < 29) { error = 27; return; } //error: the data length is smaller than the length of the header + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { error = 28; return; } //no PNG signature + if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { error = 29; return; } //error: it doesn't start with a IHDR chunk! + info.width = read32bitInt(&in[16]); info.height = read32bitInt(&in[20]); + info.bitDepth = in[24]; info.colorType = in[25]; + info.compressionMethod = in[26]; if(in[26] != 0) { error = 32; return; } //error: only compression method 0 is allowed in the specification + info.filterMethod = in[27]; if(in[27] != 0) { error = 33; return; } //error: only filter method 0 is allowed in the specification + info.interlaceMethod = in[28]; if(in[28] > 1) { error = 34; return; } //error: only interlace methods 0 and 1 exist in the specification + error = checkColorValidity(info.colorType, info.bitDepth); + } + void unFilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned long filterType, size_t length) + { + switch(filterType) + { + case 0: for(size_t i = 0; i < length; i++) recon[i] = scanline[i]; break; + case 1: + for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) for(size_t i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; + else for(size_t i = 0; i < length; i++) recon[i] = scanline[i]; + break; + case 3: + if(precon) + { + for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; + for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); + } + else + { + for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; + } + break; + case 4: + if(precon) + { + for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + paethPredictor(0, precon[i], 0); + for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]); + } + else + { + for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0); + } + break; + default: error = 36; return; //error: unexisting filter type given + } + } + void adam7Pass(unsigned char* out, unsigned char* linen, unsigned char* lineo, const unsigned char* in, unsigned long w, size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh, unsigned long bpp) + { //filter and reposition the pixels into the output when the image is Adam7 interlaced. This function can only do it after the full image is already decoded. The out buffer must have the correct allocated memory size already. + if(passw == 0) return; + size_t bytewidth = (bpp + 7) / 8, linelength = 1 + ((bpp * passw + 7) / 8); + for(unsigned long y = 0; y < passh; y++) + { + unsigned char filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo; + unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType, (w * bpp + 7) / 8); if(error) return; + if(bpp >= 8) for(size_t i = 0; i < passw; i++) for(size_t b = 0; b < bytewidth; b++) //b = current byte of this pixel + out[bytewidth * w * (passtop + spacey * y) + bytewidth * (passleft + spacex * i) + b] = linen[bytewidth * i + b]; + else for(size_t i = 0; i < passw; i++) + { + size_t obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i), bp = i * bpp; + for(size_t b = 0; b < bpp; b++) setBitOfReversedStream(obp, out, readBitFromReversedStream(bp, &linen[0])); + } + unsigned char* temp = linen; linen = lineo; lineo = temp; //swap the two buffer pointers "line old" and "line new" + } + } + static unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1; bitp++; return result;} + static unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits) + { + unsigned long result = 0; + for(size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i); + return result; + } + void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit) { bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); bitp++; } + unsigned long read32bitInt(const unsigned char* buffer) { return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; } + int checkColorValidity(unsigned long colorType, unsigned long bd) //return type is a LodePNG error code + { + if((colorType == 2 || colorType == 4 || colorType == 6)) { if(!(bd == 8 || bd == 16)) return 37; else return 0; } + else if(colorType == 0) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; else return 0; } + else if(colorType == 3) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; else return 0; } + else return 31; //unexisting color type + } + unsigned long getBpp(const Info& info) + { + if(info.colorType == 2) return (3 * info.bitDepth); + else if(info.colorType >= 4) return (info.colorType - 2) * info.bitDepth; + else return info.bitDepth; + } + int convert(std::vector& out, const unsigned char* in, Info& infoIn, unsigned long w, unsigned long h) + { //converts from any color type to 32-bit. return value = LodePNG error code + size_t numpixels = w * h, bp = 0; + out.resize(numpixels * 4); + unsigned char* out_ = out.empty() ? 0 : &out[0]; //faster if compiled without optimization + if(infoIn.bitDepth == 8 && infoIn.colorType == 0) //greyscale + for(size_t i = 0; i < numpixels; i++) + { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[i]; + out_[4 * i + 3] = (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255; + } + else if(infoIn.bitDepth == 8 && infoIn.colorType == 2) //RGB color + for(size_t i = 0; i < numpixels; i++) + { + for(size_t c = 0; c < 3; c++) out_[4 * i + c] = in[3 * i + c]; + out_[4 * i + 3] = (infoIn.key_defined == 1 && in[3 * i + 0] == infoIn.key_r && in[3 * i + 1] == infoIn.key_g && in[3 * i + 2] == infoIn.key_b) ? 0 : 255; + } + else if(infoIn.bitDepth == 8 && infoIn.colorType == 3) //indexed color (palette) + for(size_t i = 0; i < numpixels; i++) + { + if(4U * in[i] >= infoIn.palette.size()) return 46; + for(size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * in[i] + c]; //get rgb colors from the palette + } + else if(infoIn.bitDepth == 8 && infoIn.colorType == 4) //greyscale with alpha + for(size_t i = 0; i < numpixels; i++) + { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i + 0]; + out_[4 * i + 3] = in[2 * i + 1]; + } + else if(infoIn.bitDepth == 8 && infoIn.colorType == 6) for(size_t i = 0; i < numpixels; i++) for(size_t c = 0; c < 4; c++) out_[4 * i + c] = in[4 * i + c]; //RGB with alpha + else if(infoIn.bitDepth == 16 && infoIn.colorType == 0) //greyscale + for(size_t i = 0; i < numpixels; i++) + { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i]; + out_[4 * i + 3] = (infoIn.key_defined && 256U * in[i] + in[i + 1] == infoIn.key_r) ? 0 : 255; + } + else if(infoIn.bitDepth == 16 && infoIn.colorType == 2) //RGB color + for(size_t i = 0; i < numpixels; i++) + { + for(size_t c = 0; c < 3; c++) out_[4 * i + c] = in[6 * i + 2 * c]; + out_[4 * i + 3] = (infoIn.key_defined && 256U*in[6*i+0]+in[6*i+1] == infoIn.key_r && 256U*in[6*i+2]+in[6*i+3] == infoIn.key_g && 256U*in[6*i+4]+in[6*i+5] == infoIn.key_b) ? 0 : 255; + } + else if(infoIn.bitDepth == 16 && infoIn.colorType == 4) //greyscale with alpha + for(size_t i = 0; i < numpixels; i++) + { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[4 * i]; //most significant byte + out_[4 * i + 3] = in[4 * i + 2]; + } + else if(infoIn.bitDepth == 16 && infoIn.colorType == 6) for(size_t i = 0; i < numpixels; i++) for(size_t c = 0; c < 4; c++) out_[4 * i + c] = in[8 * i + 2 * c]; //RGB with alpha + else if(infoIn.bitDepth < 8 && infoIn.colorType == 0) //greyscale + for(size_t i = 0; i < numpixels; i++) + { + unsigned long value = (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * 255) / ((1 << infoIn.bitDepth) - 1); //scale value from 0 to 255 + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = (unsigned char)(value); + out_[4 * i + 3] = (infoIn.key_defined && value && ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && ((1U << infoIn.bitDepth) - 1U)) ? 0 : 255; + } + else if(infoIn.bitDepth < 8 && infoIn.colorType == 3) //palette + for(size_t i = 0; i < numpixels; i++) + { + unsigned long value = readBitsFromReversedStream(bp, in, infoIn.bitDepth); + if(4 * value >= infoIn.palette.size()) return 47; + for(size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * value + c]; //get rgb colors from the palette + } + return 0; + } + unsigned char paethPredictor(short a, short b, short c) //Paeth predicter, used by PNG filter type 4 + { + short p = a + b - c, pa = p > a ? (p - a) : (a - p), pb = p > b ? (p - b) : (b - p), pc = p > c ? (p - c) : (c - p); + return (unsigned char)((pa <= pb && pa <= pc) ? a : pb <= pc ? b : c); + } + }; + PNG decoder; decoder.decode(out_image, in_png, in_size, convert_to_rgba32); + image_width = decoder.info.width; image_height = decoder.info.height; + return decoder.error; +} + +#if 0 + + + +//an example using the PNG loading function: + +#include +#include + +void loadFile(std::vector& buffer, const std::string& filename) //designed for loading files from hard disk in an std::vector +{ + std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate); + + //get filesize + std::streamsize size = 0; + if(file.seekg(0, std::ios::end).good()) size = file.tellg(); + if(file.seekg(0, std::ios::beg).good()) size -= file.tellg(); + + //read contents of the file into the vector + if(size > 0) + { + buffer.resize((size_t)size); + file.read((char*)(&buffer[0]), size); + } + else buffer.clear(); +} + +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector buffer, image; + loadFile(buffer, filename); + unsigned long w, h; + int error = decodePNG(image, w, h, buffer.empty() ? 0 : &buffer[0], (unsigned long)buffer.size()); + + //if there's an error, display it + if(error != 0) std::cout << "error: " << error << std::endl; + + //the pixels are now in the vector "image", use it as texture, draw it, ... + + if(image.size() > 4) std::cout << "width: " << w << " height: " << h << " first pixel: " << std::hex << int(image[0]) << int(image[1]) << int(image[2]) << int(image[3]) << std::endl; +} + +/* + //this is test code, it displays the pixels of a 1 bit PNG. To use it, set the flag convert_to_rgba32 to false and load a 1-bit PNG image with a small size (so that its ASCII representation can fit in a console window) + for(int y = 0; y < h; y++) + { + for(int x = 0; x < w; x++) + { + int i = y * h + x; + std::cout << (((image[i/8] >> (7-i%8)) & 1) ? '.' : '#'); + } + std::cout << std::endl; + } +*/ + +#endif diff --git a/libraries/ZWidget/src/core/picopng/picopng.h b/libraries/ZWidget/src/core/picopng/picopng.h new file mode 100644 index 00000000000..87dc961beaf --- /dev/null +++ b/libraries/ZWidget/src/core/picopng/picopng.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +int decodePNG(std::vector& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true); diff --git a/libraries/ZWidget/src/core/span_layout.cpp b/libraries/ZWidget/src/core/span_layout.cpp new file mode 100644 index 00000000000..1b68f6ef73e --- /dev/null +++ b/libraries/ZWidget/src/core/span_layout.cpp @@ -0,0 +1,883 @@ + +#include "core/span_layout.h" +#include "core/canvas.h" +#include "core/widget.h" +#include "core/font.h" +#include "core/image.h" + +SpanLayout::SpanLayout() +{ +} + +SpanLayout::~SpanLayout() +{ +} + +void SpanLayout::Clear() +{ + objects.clear(); + text.clear(); + lines.clear(); +} + +std::vector SpanLayout::GetRectById(int id) const +{ + std::vector segment_rects; + + double x = position.x; + double y = position.y; + for (std::vector::size_type line_index = 0; line_index < lines.size(); line_index++) + { + const Line& line = lines[line_index]; + for (std::vector::size_type segment_index = 0; segment_index < line.segments.size(); segment_index++) + { + const LineSegment& segment = line.segments[segment_index]; + if (segment.id == id) + { + segment_rects.push_back(Rect(x + segment.x_position, y, segment.width, y + line.height)); + } + } + y += line.height; + } + + return segment_rects; +} + +void SpanLayout::DrawLayout(Canvas* canvas) +{ + double x = position.x; + double y = position.y; + for (std::vector::size_type line_index = 0; line_index < lines.size(); line_index++) + { + Line& line = lines[line_index]; + for (std::vector::size_type segment_index = 0; segment_index < line.segments.size(); segment_index++) + { + LineSegment& segment = line.segments[segment_index]; + switch (segment.type) + { + case object_text: + DrawLayoutText(canvas, line, segment, x, y); + break; + case object_image: + DrawLayoutImage(canvas, line, segment, x, y); + break; + case object_component: + break; + } + + } + + if (line_index + 1 == lines.size() && !line.segments.empty()) + { + LineSegment& segment = line.segments.back(); + if (cursor_visible && segment.end <= cursor_pos) + { + switch (segment.type) + { + case object_text: + { + double cursor_x = x + segment.x_position + canvas->measureText(segment.font, text.substr(segment.start, segment.end - segment.start)).width; + double cursor_width = 1; + canvas->fillRect(Rect::ltrb(cursor_x, y + line.ascender - segment.ascender, cursor_width, y + line.ascender + segment.descender), cursor_color); + } + break; + } + } + } + + y += line.height; + } +} + +void SpanLayout::DrawLayoutEllipsis(Canvas* canvas, const Rect& content_rect) +{ + is_ellipsis_draw = true; + ellipsis_content_rect = content_rect; + try + { + is_ellipsis_draw = false; + DrawLayout(canvas); + } + catch (...) + { + is_ellipsis_draw = false; + throw; + } +} + +void SpanLayout::DrawLayoutImage(Canvas* canvas, Line& line, LineSegment& segment, double x, double y) +{ + canvas->drawImage(segment.image, Point(x + segment.x_position, y + line.ascender - segment.ascender)); +} + +void SpanLayout::DrawLayoutText(Canvas* canvas, Line& line, LineSegment& segment, double x, double y) +{ + std::string segment_text = text.substr(segment.start, segment.end - segment.start); + + int length = (int)segment_text.length(); + int s1 = clamp((int)sel_start - (int)segment.start, 0, length); + int s2 = clamp((int)sel_end - (int)segment.start, 0, length); + + if (s1 != s2) + { + double xx = x + segment.x_position; + double xx0 = xx + canvas->measureText(segment.font, segment_text.substr(0, s1)).width; + double xx1 = xx0 + canvas->measureText(segment.font, segment_text.substr(s1, s2 - s1)).width; + double sel_width = canvas->measureText(segment.font, segment_text.substr(s1, s2 - s1)).width; + + canvas->fillRect(Rect::ltrb(xx0, y + line.ascender - segment.ascender, xx1, y + line.ascender + segment.descender), sel_background); + + if (cursor_visible && cursor_pos >= segment.start && cursor_pos < segment.end) + { + double cursor_x = x + segment.x_position + canvas->measureText(segment.font, text.substr(segment.start, cursor_pos - segment.start)).width; + double cursor_width = cursor_overwrite_mode ? canvas->measureText(segment.font, text.substr(cursor_pos, 1)).width : 1; + canvas->fillRect(Rect::ltrb(cursor_x, y + line.ascender - segment.ascender, cursor_x + cursor_width, y + line.ascender + segment.descender), cursor_color); + } + + if (s1 > 0) + { + if (is_ellipsis_draw) + canvas->drawTextEllipsis(segment.font, Point(xx, y + line.ascender), ellipsis_content_rect, segment_text.substr(0, s1), segment.color); + else + canvas->drawText(segment.font, Point(xx, y + line.ascender), segment_text.substr(0, s1), segment.color); + } + if (is_ellipsis_draw) + canvas->drawTextEllipsis(segment.font, Point(xx0, y + line.ascender), ellipsis_content_rect, segment_text.substr(s1, s2 - s1), sel_foreground); + else + canvas->drawText(segment.font, Point(xx0, y + line.ascender), segment_text.substr(s1, s2 - s1), sel_foreground); + xx += sel_width; + if (s2 < length) + { + if (is_ellipsis_draw) + canvas->drawTextEllipsis(segment.font, Point(xx1, y + line.ascender), ellipsis_content_rect, segment_text.substr(s2), segment.color); + else + canvas->drawText(segment.font, Point(xx1, y + line.ascender), segment_text.substr(s2), segment.color); + } + } + else + { + if (cursor_visible && cursor_pos >= segment.start && cursor_pos < segment.end) + { + double cursor_x = x + segment.x_position + canvas->measureText(segment.font, text.substr(segment.start, cursor_pos - segment.start)).width; + double cursor_width = cursor_overwrite_mode ? canvas->measureText(segment.font, text.substr(cursor_pos, 1)).width : 1; + canvas->fillRect(Rect::ltrb(cursor_x, y + line.ascender - segment.ascender, cursor_x + cursor_width, y + line.ascender + segment.descender), cursor_color); + } + + if (is_ellipsis_draw) + canvas->drawTextEllipsis(segment.font, Point(x + segment.x_position, y + line.ascender), ellipsis_content_rect, segment_text, segment.color); + else + canvas->drawText(segment.font, Point(x + segment.x_position, y + line.ascender), segment_text, segment.color); + } +} + +SpanLayout::HitTestResult SpanLayout::HitTest(Canvas* canvas, const Point& pos) +{ + SpanLayout::HitTestResult result; + + if (lines.empty()) + { + result.type = SpanLayout::HitTestResult::no_objects_available; + return result; + } + + double x = position.x; + double y = position.y; + + // Check if we are outside to the top + if (pos.y < y) + { + result.type = SpanLayout::HitTestResult::outside_top; + result.object_id = lines[0].segments[0].id; + result.offset = 0; + return result; + } + + for (std::vector::size_type line_index = 0; line_index < lines.size(); line_index++) + { + Line& line = lines[line_index]; + + // Check if we found current line + if (pos.y >= y && pos.y <= y + line.height) + { + for (std::vector::size_type segment_index = 0; segment_index < line.segments.size(); segment_index++) + { + LineSegment& segment = line.segments[segment_index]; + + // Check if we are outside to the left + if (segment_index == 0 && pos.x < x) + { + result.type = SpanLayout::HitTestResult::outside_left; + result.object_id = segment.id; + result.offset = segment.start; + return result; + } + + // Check if we are inside a segment + if (pos.x >= x + segment.x_position && pos.x <= x + segment.x_position + segment.width) + { + std::string segment_text = text.substr(segment.start, segment.end - segment.start); + Point hit_point(pos.x - x - segment.x_position, 0); + size_t offset = segment.start + canvas->getCharacterIndex(segment.font, segment_text, hit_point); + + result.type = SpanLayout::HitTestResult::inside; + result.object_id = segment.id; + result.offset = offset; + return result; + } + + // Check if we are outside to the right + if (segment_index == line.segments.size() - 1 && pos.x > x + segment.x_position + segment.width) + { + result.type = SpanLayout::HitTestResult::outside_right; + result.object_id = segment.id; + result.offset = segment.end; + return result; + } + } + } + + y += line.height; + } + + // We are outside to the bottom + const Line& last_line = lines[lines.size() - 1]; + const LineSegment& last_segment = last_line.segments[last_line.segments.size() - 1]; + + result.type = SpanLayout::HitTestResult::outside_bottom; + result.object_id = last_segment.id; + result.offset = last_segment.end; + return result; +} + +Size SpanLayout::GetSize() const +{ + return GetRect().size(); +} + +Rect SpanLayout::GetRect() const +{ + double x = position.x; + double y = position.y; + + const double max_value = 0x70000000; + double left = max_value; + double top = max_value; + double right = -max_value; + double bottom = -max_value; + + for (std::vector::size_type line_index = 0; line_index < lines.size(); line_index++) + { + const Line& line = lines[line_index]; + for (std::vector::size_type segment_index = 0; segment_index < line.segments.size(); segment_index++) + { + const LineSegment& segment = line.segments[segment_index]; + Rect area(Point(x + segment.x_position, y), Size(segment.width, line.height)); + + left = std::min(left, area.left()); + right = std::max(right, area.right()); + top = std::min(top, area.top()); + bottom = std::max(bottom, area.bottom()); + } + y += line.height; + } + if (left > right) + left = right = position.x; + + if (top > bottom) + top = bottom = position.y; + + return Rect::ltrb(left, top, right, bottom); +} + +void SpanLayout::AddText(const std::string& more_text, std::shared_ptr font, const Colorf& color, int id) +{ + SpanObject object; + object.type = object_text; + object.start = text.length(); + object.end = object.start + more_text.length(); + object.font = font; + object.color = color; + object.id = id; + objects.push_back(object); + text += more_text; +} + +void SpanLayout::AddImage(std::shared_ptr image, double baseline_offset, int id) +{ + SpanObject object; + object.type = object_image; + object.image = image; + object.baseline_offset = baseline_offset; + object.id = id; + object.start = text.length(); + object.end = object.start + 1; + objects.push_back(object); + text += "*"; +} + +void SpanLayout::AddWidget(Widget* component, double baseline_offset, int id) +{ + SpanObject object; + object.type = object_component; + object.component = component; + object.baseline_offset = baseline_offset; + object.id = id; + object.start = text.length(); + object.end = object.start + 1; + objects.push_back(object); + text += "*"; +} + +void SpanLayout::Layout(Canvas* canvas, double max_width) +{ + LayoutLines(canvas, max_width); + + switch (alignment) + { + case span_right: AlignRight(max_width); break; + case span_center: AlignCenter(max_width); break; + case span_justify: AlignJustify(max_width); break; + case span_left: + default: break; + } +} + +void SpanLayout::SetPosition(const Point& pos) +{ + position = pos; +} + +SpanLayout::TextSizeResult SpanLayout::FindTextSize(Canvas* canvas, const TextBlock& block, size_t object_index) +{ + std::shared_ptr font = objects[object_index].font; + if (layout_cache.object_index != (int)object_index) + { + layout_cache.object_index = (int)object_index; + layout_cache.metrics = canvas->getFontMetrics(font); + } + + TextSizeResult result; + result.start = block.start; + size_t pos = block.start; + double x_position = 0; + while (pos != block.end) + { + size_t end = std::min(objects[object_index].end, block.end); + std::string subtext = text.substr(pos, end - pos); + + Size text_size = canvas->measureText(font, subtext).size(); + + result.width += text_size.width; + result.height = std::max(result.height, layout_cache.metrics.height + layout_cache.metrics.external_leading); + result.ascender = std::max(result.ascender, layout_cache.metrics.ascent); + result.descender = std::max(result.descender, layout_cache.metrics.descent); + + LineSegment segment; + segment.type = object_text; + segment.start = pos; + segment.end = end; + segment.font = objects[object_index].font; + segment.color = objects[object_index].color; + segment.id = objects[object_index].id; + segment.x_position = x_position; + segment.width = text_size.width; + segment.ascender = layout_cache.metrics.ascent; + segment.descender = layout_cache.metrics.descent; + x_position += text_size.width; + result.segments.push_back(segment); + + pos = end; + if (pos == objects[object_index].end) + { + object_index++; + result.objects_traversed++; + + if (object_index < objects.size()) + { + layout_cache.object_index = (int)object_index; + font = objects[object_index].font; + layout_cache.metrics = canvas->getFontMetrics(font); + } + } + } + result.end = pos; + return result; +} + +std::vector SpanLayout::FindTextBlocks() +{ + std::vector blocks; + std::vector::iterator block_object_it; + + // Find first object that is not text: + for (block_object_it = objects.begin(); block_object_it != objects.end() && (*block_object_it).type == object_text; ++block_object_it); + + std::string::size_type pos = 0; + while (pos < text.size()) + { + // Find end of text block: + std::string::size_type end_pos; + switch (text[pos]) + { + case ' ': + case '\t': + case '\n': + end_pos = text.find_first_not_of(text[pos], pos); + break; + default: + end_pos = text.find_first_of(" \t\n", pos); + break; + } + + if (end_pos == std::string::npos) + end_pos = text.length(); + + // If we traversed past an object that is not text: + if (block_object_it != objects.end() && (*block_object_it).start < end_pos) + { + // End text block + end_pos = (*block_object_it).start; + if (end_pos > pos) + { + TextBlock block; + block.start = pos; + block.end = end_pos; + blocks.push_back(block); + } + + // Create object block: + pos = end_pos; + end_pos = pos + 1; + + TextBlock block; + block.start = pos; + block.end = end_pos; + blocks.push_back(block); + + // Find next object that is not text: + for (++block_object_it; block_object_it != objects.end() && (*block_object_it).type == object_text; ++block_object_it); + } + else + { + if (end_pos > pos) + { + TextBlock block; + block.start = pos; + block.end = end_pos; + blocks.push_back(block); + } + } + + pos = end_pos; + } + + return blocks; +} + +void SpanLayout::SetAlign(SpanAlign align) +{ + alignment = align; +} + +void SpanLayout::LayoutLines(Canvas* canvas, double max_width) +{ + lines.clear(); + if (objects.empty()) + return; + + layout_cache.metrics = {}; + layout_cache.object_index = -1; + + CurrentLine current_line; + std::vector blocks = FindTextBlocks(); + for (std::vector::size_type block_index = 0; block_index < blocks.size(); block_index++) + { + if (objects[current_line.object_index].type == object_text) + LayoutText(canvas, blocks, block_index, current_line, max_width); + else + LayoutBlock(current_line, max_width, blocks, block_index); + } + NextLine(current_line); +} + +void SpanLayout::LayoutBlock(CurrentLine& current_line, double max_width, std::vector& blocks, std::vector::size_type block_index) +{ + if (objects[current_line.object_index].float_type == float_none) + LayoutInlineBlock(current_line, max_width, blocks, block_index); + else + LayoutFloatBlock(current_line, max_width); + + current_line.object_index++; +} + +void SpanLayout::LayoutInlineBlock(CurrentLine& current_line, double max_width, std::vector& blocks, std::vector::size_type block_index) +{ + Size size; + LineSegment segment; + if (objects[current_line.object_index].type == object_image) + { + size = Size(objects[current_line.object_index].image->GetWidth(), objects[current_line.object_index].image->GetHeight()); + segment.type = object_image; + segment.image = objects[current_line.object_index].image; + } + else if (objects[current_line.object_index].type == object_component) + { + size = objects[current_line.object_index].component->GetSize(); + segment.type = object_component; + segment.component = objects[current_line.object_index].component; + } + + if (current_line.x_position + size.width > max_width) + NextLine(current_line); + + segment.x_position = current_line.x_position; + segment.width = size.width; + segment.start = blocks[block_index].start; + segment.end = blocks[block_index].end; + segment.id = objects[current_line.object_index].id; + segment.ascender = size.height - objects[current_line.object_index].baseline_offset; + current_line.cur_line.segments.push_back(segment); + current_line.cur_line.height = std::max(current_line.cur_line.height, size.height + objects[current_line.object_index].baseline_offset); + current_line.cur_line.ascender = std::max(current_line.cur_line.ascender, segment.ascender); + current_line.x_position += size.width; +} + +void SpanLayout::LayoutFloatBlock(CurrentLine& current_line, double max_width) +{ + FloatBox floatbox; + floatbox.type = objects[current_line.object_index].type; + floatbox.image = objects[current_line.object_index].image; + floatbox.component = objects[current_line.object_index].component; + floatbox.id = objects[current_line.object_index].id; + if (objects[current_line.object_index].type == object_image) + floatbox.rect = Rect::xywh(0, current_line.y_position, floatbox.image->GetWidth(), floatbox.image->GetHeight()); + else if (objects[current_line.object_index].type == object_component) + floatbox.rect = Rect::xywh(0, current_line.y_position, floatbox.component->GetWidth(), floatbox.component->GetHeight()); + + if (objects[current_line.object_index].float_type == float_left) + floats_left.push_back(FloatBoxLeft(floatbox, max_width)); + else + floats_right.push_back(FloatBoxRight(floatbox, max_width)); + + ReflowLine(current_line, max_width); +} + +void SpanLayout::ReflowLine(CurrentLine& step, double max_width) +{ +} + +SpanLayout::FloatBox SpanLayout::FloatBoxLeft(FloatBox box, double max_width) +{ + return FloatBoxAny(box, max_width, floats_left); +} + +SpanLayout::FloatBox SpanLayout::FloatBoxRight(FloatBox box, double max_width) +{ + return FloatBoxAny(box, max_width, floats_right); +} + +SpanLayout::FloatBox SpanLayout::FloatBoxAny(FloatBox box, double max_width, const std::vector& floats1) +{ + bool restart; + do + { + restart = false; + for (size_t i = 0; i < floats1.size(); i++) + { + double top = std::max(floats1[i].rect.top(), box.rect.top()); + double bottom = std::min(floats1[i].rect.bottom(), box.rect.bottom()); + if (bottom > top && box.rect.left() < floats1[i].rect.right()) + { + Size s = box.rect.size(); + box.rect.x = floats1[i].rect.x; + box.rect.width = s.width; + + if (!BoxFitsOnLine(box, max_width)) + { + box.rect.x = 0; + box.rect.width = s.width; + box.rect.y = floats1[i].rect.bottom(); + box.rect.height = s.height; + restart = true; + break; + } + } + } + } while (restart); + return box; +} + +bool SpanLayout::BoxFitsOnLine(const FloatBox& box, double max_width) +{ + for (size_t i = 0; i < floats_right.size(); i++) + { + double top = std::max(floats_right[i].rect.top(), box.rect.top()); + double bottom = std::min(floats_right[i].rect.bottom(), box.rect.bottom()); + if (bottom > top) + { + if (box.rect.right() + floats_right[i].rect.right() > max_width) + return false; + } + } + return true; +} + +void SpanLayout::LayoutText(Canvas* canvas, std::vector blocks, std::vector::size_type block_index, CurrentLine& current_line, double max_width) +{ + TextSizeResult text_size_result = FindTextSize(canvas, blocks[block_index], current_line.object_index); + current_line.object_index += text_size_result.objects_traversed; + + current_line.cur_line.width = current_line.x_position; + + if (IsNewline(blocks[block_index])) + { + current_line.cur_line.height = std::max(current_line.cur_line.height, text_size_result.height); + current_line.cur_line.ascender = std::max(current_line.cur_line.ascender, text_size_result.ascender); + NextLine(current_line); + } + else + { + if (!FitsOnLine(current_line.x_position, text_size_result, max_width) && !IsWhitespace(blocks[block_index])) + { + if (LargerThanLine(text_size_result, max_width)) + { + // force line breaks to make it fit + ForcePlaceLineSegments(current_line, text_size_result, max_width); + } + else + { + NextLine(current_line); + PlaceLineSegments(current_line, text_size_result); + } + } + else + { + PlaceLineSegments(current_line, text_size_result); + } + } +} + +void SpanLayout::NextLine(CurrentLine& current_line) +{ + current_line.cur_line.width = current_line.x_position; + for (std::vector::reverse_iterator it = current_line.cur_line.segments.rbegin(); it != current_line.cur_line.segments.rend(); ++it) + { + LineSegment& segment = *it; + if (segment.type == object_text) + { + std::string s = text.substr(segment.start, segment.end - segment.start); + if (s.find_first_not_of(" \t\r\n") != std::string::npos) + { + current_line.cur_line.width = segment.x_position + segment.width; + break; + } + else + { + // We remove the width so that GetRect() reports the correct sizes + segment.width = 0; + } + } + else + { + current_line.cur_line.width = segment.x_position + segment.width; + break; + } + } + + double height = current_line.cur_line.height; + lines.push_back(current_line.cur_line); + current_line.cur_line = Line(); + current_line.x_position = 0; + current_line.y_position += height; +} + +void SpanLayout::PlaceLineSegments(CurrentLine& current_line, TextSizeResult& text_size_result) +{ + for (std::vector::iterator it = text_size_result.segments.begin(); it != text_size_result.segments.end(); ++it) + { + LineSegment segment = *it; + segment.x_position += current_line.x_position; + current_line.cur_line.segments.push_back(segment); + } + current_line.x_position += text_size_result.width; + current_line.cur_line.height = std::max(current_line.cur_line.height, text_size_result.height); + current_line.cur_line.ascender = std::max(current_line.cur_line.ascender, text_size_result.ascender); +} + +void SpanLayout::ForcePlaceLineSegments(CurrentLine& current_line, TextSizeResult& text_size_result, double max_width) +{ + if (current_line.x_position != 0) + NextLine(current_line); + + // to do: do this properly - for now we just place the entire block on one line + PlaceLineSegments(current_line, text_size_result); +} + +bool SpanLayout::IsNewline(const TextBlock& block) +{ + return block.start != block.end && text[block.start] == '\n'; +} + +bool SpanLayout::IsWhitespace(const TextBlock& block) +{ + return block.start != block.end && text[block.start] == ' '; +} + +bool SpanLayout::FitsOnLine(double x_position, const TextSizeResult& text_size_result, double max_width) +{ + return x_position + text_size_result.width <= max_width; +} + +bool SpanLayout::LargerThanLine(const TextSizeResult& text_size_result, double max_width) +{ + return text_size_result.width > max_width; +} + +void SpanLayout::AlignRight(double max_width) +{ + for (std::vector::size_type line_index = 0; line_index < lines.size(); line_index++) + { + Line& line = lines[line_index]; + double offset = max_width - line.width; + if (offset < 0) offset = 0; + + for (std::vector::size_type segment_index = 0; segment_index < line.segments.size(); segment_index++) + { + LineSegment& segment = line.segments[segment_index]; + segment.x_position += offset; + } + } +} + +void SpanLayout::AlignCenter(double max_width) +{ + for (std::vector::size_type line_index = 0; line_index < lines.size(); line_index++) + { + Line& line = lines[line_index]; + double offset = (max_width - line.width) / 2; + if (offset < 0) offset = 0; + + for (std::vector::size_type segment_index = 0; segment_index < line.segments.size(); segment_index++) + { + LineSegment& segment = line.segments[segment_index]; + segment.x_position += offset; + } + } +} + +void SpanLayout::AlignJustify(double max_width) +{ + // Note, we do not justify the last line + for (std::vector::size_type line_index = 0; line_index + 1 < lines.size(); line_index++) + { + Line& line = lines[line_index]; + double offset = max_width - line.width; + if (offset < 0) offset = 0; + + if (line.segments.size() <= 1) // Do not justify line if only one word exists + continue; + + for (std::vector::size_type segment_index = 0; segment_index < line.segments.size(); segment_index++) + { + LineSegment& segment = line.segments[segment_index]; + segment.x_position += (offset * segment_index) / (line.segments.size() - 1); + } + } +} + +Size SpanLayout::FindPreferredSize(Canvas* canvas) +{ + LayoutLines(canvas, 0x70000000); // Feed it with a very long length so it ends up on one line + return GetRect().size(); +} + +void SpanLayout::SetSelectionRange(std::string::size_type start, std::string::size_type end) +{ + sel_start = start; + sel_end = end; + if (sel_end < sel_start) + sel_end = sel_start; +} + +void SpanLayout::SetSelectionColors(const Colorf& foreground, const Colorf& background) +{ + sel_foreground = foreground; + sel_background = background; +} + +void SpanLayout::ShowCursor() +{ + cursor_visible = true; +} + +void SpanLayout::HideCursor() +{ + cursor_visible = false; +} + +void SpanLayout::SetCursorPos(std::string::size_type pos) +{ + cursor_pos = pos; +} + +void SpanLayout::SetCursorOverwriteMode(bool enable) +{ + cursor_overwrite_mode = enable; +} + +void SpanLayout::SetCursorColor(const Colorf& color) +{ + cursor_color = color; +} + +std::string SpanLayout::GetCombinedText() const +{ + return text; +} + +void SpanLayout::SetComponentGeometry() +{ + double x = position.x; + double y = position.y; + for (size_t i = 0; i < lines.size(); i++) + { + for (size_t j = 0; j < lines[i].segments.size(); j++) + { + if (lines[i].segments[j].type == object_component) + { + Point pos(x + lines[i].segments[j].x_position, y + lines[i].ascender - lines[i].segments[j].ascender); + Size size = lines[i].segments[j].component->GetSize(); + Rect rect(pos, size); + lines[i].segments[j].component->SetFrameGeometry(rect); + } + } + y += lines[i].height; + } +} + +double SpanLayout::GetFirstBaselineOffset() +{ + if (!lines.empty()) + { + return lines.front().ascender; + } + else + { + return 0; + } +} + +double SpanLayout::GetLastBaselineOffset() +{ + if (!lines.empty()) + { + double y = 0; + for (size_t i = 0; i + 1 < lines.size(); i++) + y += lines[i].height; + return y + lines.back().ascender; + } + else + { + return 0; + } +} diff --git a/libraries/ZWidget/src/core/timer.cpp b/libraries/ZWidget/src/core/timer.cpp new file mode 100644 index 00000000000..4c748561b79 --- /dev/null +++ b/libraries/ZWidget/src/core/timer.cpp @@ -0,0 +1,43 @@ + +#include "core/timer.h" +#include "core/widget.h" +#include "window/window.h" + +Timer::Timer(Widget* owner) : OwnerObj(owner) +{ + PrevTimerObj = owner->FirstTimerObj; + if (PrevTimerObj) + PrevTimerObj->PrevTimerObj = this; + owner->FirstTimerObj = this; +} + +Timer::~Timer() +{ + if (PrevTimerObj) + PrevTimerObj->NextTimerObj = NextTimerObj; + if (NextTimerObj) + NextTimerObj->PrevTimerObj = PrevTimerObj; + if (OwnerObj->FirstTimerObj == this) + OwnerObj->FirstTimerObj = NextTimerObj; +} + +void Timer::Start(int timeoutMilliseconds, bool repeat) +{ + Stop(); + + TimerId = DisplayWindow::StartTimer(timeoutMilliseconds, [=]() { + if (!repeat) + Stop(); + if (FuncExpired) + FuncExpired(); + }); +} + +void Timer::Stop() +{ + if (TimerId != 0) + { + DisplayWindow::StopTimer(TimerId); + TimerId = 0; + } +} diff --git a/libraries/ZWidget/src/core/truetypefont.cpp b/libraries/ZWidget/src/core/truetypefont.cpp new file mode 100644 index 00000000000..3f71c058d6f --- /dev/null +++ b/libraries/ZWidget/src/core/truetypefont.cpp @@ -0,0 +1,1201 @@ + +// #define DUMP_GLYPH + +#include "core/truetypefont.h" +#include "core/pathfill.h" +#include +#include +#include + +#ifdef DUMP_GLYPH +#include +#endif + +TrueTypeFont::TrueTypeFont(std::shared_ptr& initdata, int ttcFontIndex) : data(initdata) +{ + if (data->size() > 0x7fffffff) + throw std::runtime_error("TTF file is larger than 2 gigabytes!"); + + TrueTypeFileReader reader(data->data(), data->size()); + ttf_Tag versionTag = reader.ReadTag(); + reader.Seek(0); + + if (memcmp(versionTag.data(), "ttcf", 4) == 0) // TTC header + { + ttcHeader.Load(reader); + if (ttcFontIndex >= ttcHeader.numFonts) + throw std::runtime_error("TTC font index out of bounds"); + reader.Seek(ttcHeader.tableDirectoryOffsets[ttcFontIndex]); + } + + directory.Load(reader); + + if (!directory.ContainsTTFOutlines()) + throw std::runtime_error("Only truetype outline fonts are supported"); + + // Load required tables: + + reader = directory.GetReader(data->data(), data->size(), "head"); + head.Load(reader); + + reader = directory.GetReader(data->data(), data->size(), "hhea"); + hhea.Load(reader); + + reader = directory.GetReader(data->data(), data->size(), "maxp"); + maxp.Load(reader); + + reader = directory.GetReader(data->data(), data->size(), "hmtx"); + hmtx.Load(hhea, maxp, reader); + + reader = directory.GetReader(data->data(), data->size(), "name"); + name.Load(reader); + + reader = directory.GetReader(data->data(), data->size(), "OS/2"); + os2.Load(reader); + + reader = directory.GetReader(data->data(), data->size(), "cmap"); + cmap.Load(reader); + + LoadCharacterMapEncoding(reader); + + // Load TTF Outlines: + + reader = directory.GetReader(data->data(), data->size(), "loca"); + loca.Load(head, maxp, reader); + + glyf = directory.GetRecord("glyf"); + +#ifdef DUMP_GLYPH + LoadGlyph(GetGlyphIndex('6'), 13.0); +#endif +} + +TrueTypeTextMetrics TrueTypeFont::GetTextMetrics(double height) const +{ + double scale = height / head.unitsPerEm; + + TrueTypeTextMetrics metrics; + metrics.ascender = os2.sTypoAscender * scale; + metrics.descender = os2.sTypoDescender * scale; + metrics.lineGap = os2.sTypoLineGap * scale; + return metrics; +} + +TrueTypeGlyph TrueTypeFont::LoadGlyph(uint32_t glyphIndex, double height) const +{ + double scale = height / head.unitsPerEm; + double scaleX = 3.0f; + double scaleY = -1.0f; + + ttf_uint16 advanceWidth = 0; + ttf_int16 lsb = 0; + if (glyphIndex >= hhea.numberOfHMetrics) + { + advanceWidth = hmtx.hMetrics[hhea.numberOfHMetrics - 1].advanceWidth; + lsb = hmtx.leftSideBearings[glyphIndex - hhea.numberOfHMetrics]; + } + else + { + advanceWidth = hmtx.hMetrics[glyphIndex].advanceWidth; + lsb = hmtx.hMetrics[glyphIndex].lsb; + } + + // Glyph is missing if the offset is the same as the next glyph (0 bytes glyph length) + bool missing = glyphIndex + 1 < loca.offsets.size() ? loca.offsets[glyphIndex] == loca.offsets[glyphIndex + 1] : false; + if (missing) + { + TrueTypeGlyph glyph; + + // TBD: gridfit or not? + glyph.advanceWidth = (int)std::round(advanceWidth * scale * scaleX); + glyph.leftSideBearing = (int)std::round(lsb * scale * scaleX); + glyph.yOffset = 0; + + return glyph; + } + + TTF_SimpleGlyph g; + LoadGlyph(g, glyphIndex); + + // Create glyph path: + PathFillDesc path; + path.fill_mode = PathFillMode::winding; + + int startPoint = 0; + int numberOfContours = g.endPtsOfContours.size(); + for (int i = 0; i < numberOfContours; i++) + { + int endPoint = g.endPtsOfContours[i]; + if (endPoint < startPoint) + throw std::runtime_error("Invalid glyph"); + + bool prevIsControlPoint; + bool isControlPoint = !(g.flags[endPoint] & TTF_ON_CURVE_POINT); + bool nextIsControlPoint = !(g.flags[startPoint] & TTF_ON_CURVE_POINT); + if (isControlPoint) + { + Point nextpoint(g.points[startPoint].x, g.points[startPoint].y); + if (nextIsControlPoint) + { + Point curpoint(g.points[endPoint].x, g.points[endPoint].y); + Point midpoint = (curpoint + nextpoint) / 2; + path.MoveTo(midpoint * scale); + prevIsControlPoint = isControlPoint; + } + else + { + path.MoveTo(Point(g.points[startPoint].x, g.points[startPoint].y) * scale); + prevIsControlPoint = false; + } + } + else + { + path.MoveTo(Point(g.points[endPoint].x, g.points[endPoint].y) * scale); + prevIsControlPoint = isControlPoint; + } + + int pos = startPoint; + while (pos <= endPoint) + { + int nextpos = pos + 1 <= endPoint ? pos + 1 : startPoint; + bool isControlPoint = !(g.flags[pos] & TTF_ON_CURVE_POINT); + bool nextIsControlPoint = !(g.flags[nextpos] & TTF_ON_CURVE_POINT); + Point curpoint(g.points[pos].x, g.points[pos].y); + if (isControlPoint) + { + Point nextpoint(g.points[nextpos].x, g.points[nextpos].y); + if (nextIsControlPoint) + { + Point midpoint = (curpoint + nextpoint) / 2; + path.BezierTo(curpoint * scale, midpoint * scale); + prevIsControlPoint = isControlPoint; + pos++; + } + else + { + path.BezierTo(curpoint * scale, nextpoint * scale); + prevIsControlPoint = false; + pos += 2; + } + } + else + { + if (!prevIsControlPoint) + path.LineTo(curpoint * scale); + prevIsControlPoint = isControlPoint; + pos++; + } + } + path.Close(); + + startPoint = endPoint + 1; + } + + // Transform and find the final bounding box + Point bboxMin, bboxMax; + if (!path.subpaths.front().points.empty()) + { + bboxMin = path.subpaths.front().points.front(); + bboxMax = path.subpaths.front().points.front(); + bboxMin.x *= scaleX; + bboxMin.y *= scaleY; + bboxMax.x *= scaleX; + bboxMax.y *= scaleY; + for (auto& subpath : path.subpaths) + { + for (auto& point : subpath.points) + { + point.x *= scaleX; + point.y *= scaleY; + bboxMin.x = std::min(bboxMin.x, point.x); + bboxMin.y = std::min(bboxMin.y, point.y); + bboxMax.x = std::max(bboxMax.x, point.x); + bboxMax.y = std::max(bboxMax.y, point.y); + } + } + } + + bboxMin.x = std::floor(bboxMin.x); + bboxMin.y = std::floor(bboxMin.y); + + // Reposition glyph to bitmap so it begins at (0,0) for our bitmap + for (auto& subpath : path.subpaths) + { + for (auto& point : subpath.points) + { + point.x -= bboxMin.x; + point.y -= bboxMin.y; + } + } + +#ifdef DUMP_GLYPH + std::string svgxmlstart = R"( + + + +)"; + + std::ofstream out("c:\\development\\glyph.svg"); + out << svgxmlstart; + + for (auto& subpath : path.subpaths) + { + size_t pos = 0; + out << "M" << subpath.points[pos].x << " " << subpath.points[pos].y << " "; + pos++; + for (PathFillCommand cmd : subpath.commands) + { + int count = 0; + if (cmd == PathFillCommand::line) + { + out << "L"; + count = 1; + } + else if (cmd == PathFillCommand::quadradic) + { + out << "Q"; + count = 2; + } + else if (cmd == PathFillCommand::cubic) + { + out << "C"; + count = 3; + } + + for (int i = 0; i < count; i++) + { + out << subpath.points[pos].x << " " << subpath.points[pos].y << " "; + pos++; + } + } + if (subpath.closed) + out << "Z"; + } + + out << svgxmlend; + out.close(); +#endif + + TrueTypeGlyph glyph; + + // Rasterize the glyph + glyph.width = (int)std::floor(bboxMax.x - bboxMin.x) + 1; + glyph.height = (int)std::floor(bboxMax.y - bboxMin.y) + 1; + glyph.grayscale.reset(new uint8_t[glyph.width * glyph.height]); + uint8_t* grayscale = glyph.grayscale.get(); + path.Rasterize(grayscale, glyph.width, glyph.height); + + // TBD: gridfit or not? + glyph.advanceWidth = (int)std::round(advanceWidth * scale * scaleX); + glyph.leftSideBearing = (int)std::round(bboxMin.x); + glyph.yOffset = (int)std::round(bboxMin.y); + + return glyph; +} + +void TrueTypeFont::LoadGlyph(TTF_SimpleGlyph& g, uint32_t glyphIndex, int compositeDepth) const +{ + if (glyphIndex >= loca.offsets.size()) + throw std::runtime_error("Glyph index out of bounds"); + + TrueTypeFileReader reader = glyf.GetReader(data->data(), data->size()); + reader.Seek(loca.offsets[glyphIndex]); + + ttf_int16 numberOfContours = reader.ReadInt16(); + ttf_int16 xMin = reader.ReadInt16(); + ttf_int16 yMin = reader.ReadInt16(); + ttf_int16 xMax = reader.ReadInt16(); + ttf_int16 yMax = reader.ReadInt16(); + + if (numberOfContours > 0) // Simple glyph + { + int pointsOffset = g.points.size(); + for (ttf_uint16 i = 0; i < numberOfContours; i++) + g.endPtsOfContours.push_back(pointsOffset + reader.ReadUInt16()); + + ttf_uint16 instructionLength = reader.ReadUInt16(); + std::vector instructions; + instructions.resize(instructionLength); + reader.Read(instructions.data(), instructions.size()); + + int numPoints = (int)g.endPtsOfContours.back() - pointsOffset + 1; + g.points.resize(pointsOffset + numPoints); + + while (g.flags.size() < g.points.size()) + { + ttf_uint8 flag = reader.ReadUInt8(); + if (flag & TTF_REPEAT_FLAG) + { + ttf_uint8 repeatcount = reader.ReadUInt8(); + for (ttf_uint8 i = 0; i < repeatcount; i++) + g.flags.push_back(flag); + } + g.flags.push_back(flag); + } + + for (int i = pointsOffset; i < pointsOffset + numPoints; i++) + { + if (g.flags[i] & TTF_X_SHORT_VECTOR) + { + ttf_int16 x = reader.ReadUInt8(); + g.points[i].x = (g.flags[i] & TTF_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) ? x : -x; + } + else if (g.flags[i] & TTF_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) + { + g.points[i].x = 0; + } + else + { + g.points[i].x = reader.ReadInt16(); + } + } + + for (int i = pointsOffset; i < pointsOffset + numPoints; i++) + { + if (g.flags[i] & TTF_Y_SHORT_VECTOR) + { + ttf_int16 y = reader.ReadUInt8(); + g.points[i].y = (g.flags[i] & TTF_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) ? y : -y; + } + else if (g.flags[i] & TTF_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) + { + g.points[i].y = 0; + } + else + { + g.points[i].y = reader.ReadInt16(); + } + } + + // Convert from relative coordinates to absolute + for (int i = pointsOffset + 1; i < pointsOffset + numPoints; i++) + { + g.points[i].x += g.points[i - 1].x; + g.points[i].y += g.points[i - 1].y; + } + } + else if (numberOfContours < 0) // Composite glyph + { + if (compositeDepth == 8) + throw std::runtime_error("Composite glyph recursion exceeded"); + + int parentPointsOffset = g.points.size(); + + bool weHaveInstructions = false; + while (true) + { + ttf_uint16 flags = reader.ReadUInt16(); + ttf_uint16 childGlyphIndex = reader.ReadUInt16(); + + int argument1, argument2; + if (flags & TTF_ARG_1_AND_2_ARE_WORDS) + { + if (flags & TTF_ARGS_ARE_XY_VALUES) + { + argument1 = reader.ReadInt16(); + argument2 = reader.ReadInt16(); + } + else + { + argument1 = reader.ReadUInt16(); + argument2 = reader.ReadUInt16(); + } + } + else + { + if (flags & TTF_ARGS_ARE_XY_VALUES) + { + argument1 = reader.ReadInt8(); + argument2 = reader.ReadInt8(); + } + else + { + argument1 = reader.ReadUInt8(); + argument2 = reader.ReadUInt8(); + } + } + + float mat2x2[4]; + bool transform = true; + if (flags & TTF_WE_HAVE_A_SCALE) + { + ttf_F2DOT14 scale = F2DOT14_ToFloat(reader.ReadF2DOT14()); + mat2x2[0] = scale; + mat2x2[1] = 0; + mat2x2[2] = 0; + mat2x2[3] = scale; + } + else if (flags & TTF_WE_HAVE_AN_X_AND_Y_SCALE) + { + mat2x2[0] = F2DOT14_ToFloat(reader.ReadF2DOT14()); + mat2x2[1] = 0; + mat2x2[2] = 0; + mat2x2[3] = F2DOT14_ToFloat(reader.ReadF2DOT14()); + } + else if (flags & TTF_WE_HAVE_A_TWO_BY_TWO) + { + mat2x2[0] = F2DOT14_ToFloat(reader.ReadF2DOT14()); + mat2x2[1] = F2DOT14_ToFloat(reader.ReadF2DOT14()); + mat2x2[2] = F2DOT14_ToFloat(reader.ReadF2DOT14()); + mat2x2[3] = F2DOT14_ToFloat(reader.ReadF2DOT14()); + } + else + { + transform = false; + } + + int childPointsOffset = g.points.size(); + LoadGlyph(g, childGlyphIndex, compositeDepth + 1); + + if (transform) + { + for (int i = childPointsOffset; i < g.points.size(); i++) + { + float x = g.points[i].x * mat2x2[0] + g.points[i].y * mat2x2[1]; + float y = g.points[i].x * mat2x2[2] + g.points[i].y * mat2x2[3]; + g.points[i].x = x; + g.points[i].y = y; + } + } + + float dx, dy; + + if (flags & TTF_ARGS_ARE_XY_VALUES) + { + dx = argument1; + dy = argument2; + + // Spec states we must fall back to TTF_UNSCALED_COMPONENT_OFFSET if both flags are set + if ((flags & (TTF_SCALED_COMPONENT_OFFSET | TTF_UNSCALED_COMPONENT_OFFSET)) == TTF_SCALED_COMPONENT_OFFSET) + { + float x = dx * mat2x2[0] + dy * mat2x2[1]; + float y = dx * mat2x2[2] + dy * mat2x2[3]; + dx = x; + dy = y; + } + + if (flags & TTF_ROUND_XY_TO_GRID) + { + // To do: round the offset to the pixel grid + } + } + else + { + int parentPointIndex = parentPointsOffset + argument1; + int childPointIndex = childPointsOffset + argument2; + + if ((size_t)parentPointIndex >= g.points.size() || (size_t)childPointIndex >= g.points.size()) + throw std::runtime_error("Invalid glyph offset"); + + dx = g.points[parentPointIndex].x - g.points[childPointIndex].x; + dy = g.points[parentPointIndex].y - g.points[childPointIndex].y; + } + + for (int i = childPointsOffset; i < g.points.size(); i++) + { + g.points[i].x += dx; + g.points[i].y += dy; + } + + if (flags & TTF_USE_MY_METRICS) + { + // To do: this affects lsb + rsb calculations somehow + } + + if (flags & TTF_WE_HAVE_INSTRUCTIONS) + { + weHaveInstructions = true; + } + + if (!(flags & TTF_MORE_COMPONENTS)) + break; + } + + if (weHaveInstructions) + { + ttf_uint16 instructionLength = reader.ReadUInt16(); + std::vector instructions; + instructions.resize(instructionLength); + reader.Read(instructions.data(), instructions.size()); + } + } +} + +float TrueTypeFont::F2DOT14_ToFloat(ttf_F2DOT14 v) +{ + int a = ((ttf_int16)v) >> 14; + int b = (v & 0x3fff); + return a + b / (float)0x4000; +} + +uint32_t TrueTypeFont::GetGlyphIndex(uint32_t c) const +{ + auto it = std::lower_bound(Ranges.begin(), Ranges.end(), c, [](const TTF_GlyphRange& range, uint32_t c) { return range.endCharCode < c; }); + if (it != Ranges.end() && c >= it->startCharCode && c <= it->endCharCode) + { + return it->startGlyphID + (c - it->startCharCode); + } + + it = std::lower_bound(ManyToOneRanges.begin(), ManyToOneRanges.end(), c, [](const TTF_GlyphRange& range, uint32_t c) { return range.endCharCode < c; }); + if (it != ManyToOneRanges.end() && c >= it->startCharCode && c <= it->endCharCode) + { + return it->startGlyphID; + } + return 0; +} + +void TrueTypeFont::LoadCharacterMapEncoding(TrueTypeFileReader& reader) +{ + // Look for the best encoding available that we support + + TTF_EncodingRecord record; + if (!record.subtableOffset) record = cmap.GetEncoding(3, 12); + if (!record.subtableOffset) record = cmap.GetEncoding(0, 4); + if (!record.subtableOffset) record = cmap.GetEncoding(3, 1); + if (!record.subtableOffset) record = cmap.GetEncoding(0, 3); + if (!record.subtableOffset) + throw std::runtime_error("No supported cmap encoding found in truetype file"); + + reader.Seek(record.subtableOffset); + + ttf_uint16 format = reader.ReadUInt16(); + if (format == 4) + { + TTF_CMapSubtable4 subformat; + subformat.Load(reader); + + for (uint16_t i = 0; i < subformat.segCount; i++) + { + ttf_uint16 startCode = subformat.startCode[i]; + ttf_uint16 endCode = subformat.endCode[i]; + ttf_uint16 idDelta = subformat.idDelta[i]; + ttf_uint16 idRangeOffset = subformat.idRangeOffsets[i]; + if (idRangeOffset == 0) + { + ttf_uint16 glyphId = startCode + idDelta; // Note: relies on modulo 65536 + + TTF_GlyphRange range; + range.startCharCode = startCode; + range.endCharCode = endCode; + range.startGlyphID = glyphId; + Ranges.push_back(range); + } + else if (startCode <= endCode) + { + TTF_GlyphRange range; + range.startCharCode = startCode; + bool firstGlyph = true; + for (ttf_uint16 c = startCode; c <= endCode; c++) + { + int offset = idRangeOffset / 2 + (c - startCode) - ((int)subformat.segCount - i); + if (offset >= 0 && offset < subformat.glyphIdArray.size()) + { + int glyphId = subformat.glyphIdArray[offset]; + if (firstGlyph) + { + range.startGlyphID = glyphId; + firstGlyph = false; + } + else if (range.startGlyphID + (c - range.startCharCode) != glyphId) + { + range.endCharCode = c - 1; + Ranges.push_back(range); + range.startCharCode = c; + range.startGlyphID = glyphId; + } + } + } + if (!firstGlyph) + { + range.endCharCode = endCode; + Ranges.push_back(range); + } + } + } + } + else if (format == 12 || format == 3) + { + TTF_CMapSubtable12 subformat; + subformat.Load(reader); + Ranges = std::move(subformat.groups); + } + else if (format == 13 || format == 3) + { + TTF_CMapSubtable13 subformat; + subformat.Load(reader); + ManyToOneRanges = std::move(subformat.groups); + } +} + +std::vector TrueTypeFont::GetFontNames(const std::shared_ptr& data) +{ + if (data->size() > 0x7fffffff) + throw std::runtime_error("TTF file is larger than 2 gigabytes!"); + + TrueTypeFileReader reader(data->data(), data->size()); + ttf_Tag versionTag = reader.ReadTag(); + reader.Seek(0); + + std::vector names; + if (memcmp(versionTag.data(), "ttcf", 4) == 0) // TTC header + { + TTC_Header ttcHeader; + ttcHeader.Load(reader); + + for (size_t i = 0; i < ttcHeader.tableDirectoryOffsets.size(); i++) + { + reader.Seek(ttcHeader.tableDirectoryOffsets[i]); + + TTF_TableDirectory directory; + directory.Load(reader); + + TTF_NamingTable name; + auto name_reader = directory.GetReader(data->data(), data->size(), "name"); + name.Load(name_reader); + + names.push_back(name.GetFontName()); + } + } + else + { + TTF_TableDirectory directory; + directory.Load(reader); + + TTF_NamingTable name; + auto name_reader = directory.GetReader(data->data(), data->size(), "name"); + name.Load(name_reader); + + names.push_back(name.GetFontName()); + } + return names; +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_CMapSubtable0::Load(TrueTypeFileReader& reader) +{ + length = reader.ReadUInt16(); + language = reader.ReadUInt16(); + glyphIdArray.resize(256); + reader.Read(glyphIdArray.data(), glyphIdArray.size()); +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_CMapSubtable4::Load(TrueTypeFileReader& reader) +{ + length = reader.ReadUInt16(); + language = reader.ReadUInt16(); + + segCount = reader.ReadUInt16() / 2; + ttf_uint16 searchRange = reader.ReadUInt16(); + ttf_uint16 entrySelector = reader.ReadUInt16(); + ttf_uint16 rangeShift = reader.ReadUInt16(); + + endCode.reserve(segCount); + startCode.reserve(segCount); + idDelta.reserve(segCount); + idRangeOffsets.reserve(segCount); + for (ttf_uint16 i = 0; i < segCount; i++) endCode.push_back(reader.ReadUInt16()); + reservedPad = reader.ReadUInt16(); + for (ttf_uint16 i = 0; i < segCount; i++) startCode.push_back(reader.ReadUInt16()); + for (ttf_uint16 i = 0; i < segCount; i++) idDelta.push_back(reader.ReadInt16()); + for (ttf_uint16 i = 0; i < segCount; i++) idRangeOffsets.push_back(reader.ReadUInt16()); + + int glyphIdArraySize = ((int)length - (8 + (int)segCount * 4) * sizeof(ttf_uint16)) / 2; + if (glyphIdArraySize < 0) + throw std::runtime_error("Invalid TTF cmap subtable 4 length"); + glyphIdArray.reserve(glyphIdArraySize); + for (int i = 0; i < glyphIdArraySize; i++) glyphIdArray.push_back(reader.ReadUInt16()); +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_CMapSubtable12::Load(TrueTypeFileReader& reader) +{ + reserved = reader.ReadUInt16(); + length = reader.ReadUInt32(); + language = reader.ReadUInt32(); + numGroups = reader.ReadUInt32(); + for (ttf_uint32 i = 0; i < numGroups; i++) + { + TTF_GlyphRange range; + range.startCharCode = reader.ReadUInt32(); + range.endCharCode = reader.ReadUInt32(); + range.startGlyphID = reader.ReadUInt32(); + groups.push_back(range); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_TableRecord::Load(TrueTypeFileReader& reader) +{ + tableTag = reader.ReadTag(); + checksum = reader.ReadUInt32(); + offset = reader.ReadOffset32(); + length = reader.ReadUInt32(); +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_TableDirectory::Load(TrueTypeFileReader& reader) +{ + sfntVersion = reader.ReadUInt32(); + numTables = reader.ReadUInt16(); + + // opentype spec says we can't use these for security reasons, so we pretend they never was part of the header + ttf_uint16 searchRange = reader.ReadUInt16(); + ttf_uint16 entrySelector = reader.ReadUInt16(); + ttf_uint16 rangeShift = reader.ReadUInt16(); + + for (ttf_uint16 i = 0; i < numTables; i++) + { + TTF_TableRecord record; + record.Load(reader); + tableRecords.push_back(record); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void TTC_Header::Load(TrueTypeFileReader& reader) +{ + ttcTag = reader.ReadTag(); + majorVersion = reader.ReadUInt16(); + minorVersion = reader.ReadUInt16(); + + if (!(majorVersion == 1 && minorVersion == 0) && !(majorVersion == 2 && minorVersion == 0)) + throw std::runtime_error("Unsupported TTC header version"); + + numFonts = reader.ReadUInt32(); + for (ttf_uint16 i = 0; i < numFonts; i++) + { + tableDirectoryOffsets.push_back(reader.ReadOffset32()); + } + + if (majorVersion == 2 && minorVersion == 0) + { + dsigTag = reader.ReadUInt32(); + dsigLength = reader.ReadUInt32(); + dsigOffset = reader.ReadUInt32(); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_CMap::Load(TrueTypeFileReader& reader) +{ + version = reader.ReadUInt16(); + numTables = reader.ReadUInt16(); + + for (ttf_uint16 i = 0; i < numTables; i++) + { + TTF_EncodingRecord record; + record.platformID = reader.ReadUInt16(); + record.encodingID = reader.ReadUInt16(); + record.subtableOffset = reader.ReadOffset32(); + encodingRecords.push_back(record); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_FontHeader::Load(TrueTypeFileReader& reader) +{ + majorVersion = reader.ReadUInt16(); + minorVersion = reader.ReadUInt16(); + fontRevision = reader.ReadFixed(); + checksumAdjustment = reader.ReadUInt32(); + magicNumber = reader.ReadUInt32(); + flags = reader.ReadUInt16(); + unitsPerEm = reader.ReadUInt16(); + created = reader.ReadLONGDATETIME(); + modified = reader.ReadLONGDATETIME(); + xMin = reader.ReadInt16(); + yMin = reader.ReadInt16(); + xMax = reader.ReadInt16(); + yMax = reader.ReadInt16(); + macStyle = reader.ReadUInt16(); + lowestRecPPEM = reader.ReadUInt16(); + fontDirectionHint = reader.ReadInt16(); + indexToLocFormat = reader.ReadInt16(); + glyphDataFormat = reader.ReadInt16(); +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_HorizontalHeader::Load(TrueTypeFileReader& reader) +{ + majorVersion = reader.ReadUInt16(); + minorVersion = reader.ReadUInt16(); + ascender = reader.ReadFWORD(); + descender = reader.ReadFWORD(); + lineGap = reader.ReadFWORD(); + advanceWidthMax = reader.ReadUFWORD(); + minLeftSideBearing = reader.ReadFWORD(); + minRightSideBearing = reader.ReadFWORD(); + xMaxExtent = reader.ReadFWORD(); + caretSlopeRise = reader.ReadInt16(); + caretSlopeRun = reader.ReadInt16(); + caretOffset = reader.ReadInt16(); + reserved0 = reader.ReadInt16(); + reserved1 = reader.ReadInt16(); + reserved2 = reader.ReadInt16(); + reserved3 = reader.ReadInt16(); + metricDataFormat = reader.ReadInt16(); + numberOfHMetrics = reader.ReadUInt16(); +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_HorizontalMetrics::Load(const TTF_HorizontalHeader& hhea, const TTF_MaximumProfile& maxp, TrueTypeFileReader& reader) +{ + for (ttf_uint16 i = 0; i < hhea.numberOfHMetrics; i++) + { + longHorMetric metric; + metric.advanceWidth = reader.ReadUInt16(); + metric.lsb = reader.ReadInt16(); + hMetrics.push_back(metric); + } + + int count = (int)maxp.numGlyphs - (int)hhea.numberOfHMetrics; + if (count < 0) + throw std::runtime_error("Invalid TTF file"); + + for (int i = 0; i < count; i++) + { + leftSideBearings.push_back(reader.ReadInt16()); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_MaximumProfile::Load(TrueTypeFileReader& reader) +{ + version = reader.ReadVersion16Dot16(); + numGlyphs = reader.ReadUInt16(); + + if (version == (1 << 16)) // v1 only + { + maxPoints = reader.ReadUInt16(); + maxContours = reader.ReadUInt16(); + maxCompositePoints = reader.ReadUInt16(); + maxCompositeContours = reader.ReadUInt16(); + maxZones = reader.ReadUInt16(); + maxTwilightPoints = reader.ReadUInt16(); + maxStorage = reader.ReadUInt16(); + maxFunctionDefs = reader.ReadUInt16(); + maxInstructionDefs = reader.ReadUInt16(); + maxStackElements = reader.ReadUInt16(); + maxSizeOfInstructions = reader.ReadUInt16(); + maxComponentElements = reader.ReadUInt16(); + maxComponentDepth = reader.ReadUInt16(); + } +} + +///////////////////////////////////////////////////////////////////////////// + +static std::string unicode_to_utf8(unsigned int value) +{ + char text[8]; + + if ((value < 0x80) && (value > 0)) + { + text[0] = (char)value; + text[1] = 0; + } + else if (value < 0x800) + { + text[0] = (char)(0xc0 | (value >> 6)); + text[1] = (char)(0x80 | (value & 0x3f)); + text[2] = 0; + } + else if (value < 0x10000) + { + text[0] = (char)(0xe0 | (value >> 12)); + text[1] = (char)(0x80 | ((value >> 6) & 0x3f)); + text[2] = (char)(0x80 | (value & 0x3f)); + text[3] = 0; + } + else if (value < 0x200000) + { + text[0] = (char)(0xf0 | (value >> 18)); + text[1] = (char)(0x80 | ((value >> 12) & 0x3f)); + text[2] = (char)(0x80 | ((value >> 6) & 0x3f)); + text[3] = (char)(0x80 | (value & 0x3f)); + text[4] = 0; + } + else if (value < 0x4000000) + { + text[0] = (char)(0xf8 | (value >> 24)); + text[1] = (char)(0x80 | ((value >> 18) & 0x3f)); + text[2] = (char)(0x80 | ((value >> 12) & 0x3f)); + text[3] = (char)(0x80 | ((value >> 6) & 0x3f)); + text[4] = (char)(0x80 | (value & 0x3f)); + text[5] = 0; + } + else if (value < 0x80000000) + { + text[0] = (char)(0xfc | (value >> 30)); + text[1] = (char)(0x80 | ((value >> 24) & 0x3f)); + text[2] = (char)(0x80 | ((value >> 18) & 0x3f)); + text[3] = (char)(0x80 | ((value >> 12) & 0x3f)); + text[4] = (char)(0x80 | ((value >> 6) & 0x3f)); + text[5] = (char)(0x80 | (value & 0x3f)); + text[6] = 0; + } + else + { + text[0] = 0; // Invalid wchar value + } + return text; +} + +void TTF_NamingTable::Load(TrueTypeFileReader& reader) +{ + version = reader.ReadUInt16(); + count = reader.ReadUInt16(); + storageOffset = reader.ReadOffset16(); + for (ttf_uint16 i = 0; i < count; i++) + { + NameRecord record; + record.platformID = reader.ReadUInt16(); + record.encodingID = reader.ReadUInt16(); + record.languageID = reader.ReadUInt16(); + record.nameID = reader.ReadUInt16(); + record.length = reader.ReadUInt16(); + record.stringOffset = reader.ReadOffset16(); + nameRecord.push_back(record); + } + + if (version == 1) + { + langTagCount = reader.ReadUInt16(); + for (ttf_uint16 i = 0; i < langTagCount; i++) + { + LangTagRecord record; + ttf_uint16 length; + ttf_Offset16 langTagOffset; + langTagRecord.push_back(record); + } + } + + for (NameRecord& record : nameRecord) + { + if (record.length > 0 && record.platformID == 3 && record.encodingID == 1) + { + reader.Seek(storageOffset + record.stringOffset); + ttf_uint16 ucs2len = record.length / 2; + for (ttf_uint16 i = 0; i < ucs2len; i++) + { + record.text += unicode_to_utf8(reader.ReadUInt16()); + } + } + } +} + +TTCFontName TTF_NamingTable::GetFontName() const +{ + TTCFontName fname; + for (const auto& record : nameRecord) + { + if (record.nameID == 1) fname.FamilyName = record.text; + if (record.nameID == 2) fname.SubfamilyName = record.text; + if (record.nameID == 3) fname.UniqueID = record.text; + if (record.nameID == 4) fname.FullName = record.text; + if (record.nameID == 5) fname.VersionString = record.text; + if (record.nameID == 6) fname.PostscriptName = record.text; + } + return fname; +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_OS2Windows::Load(TrueTypeFileReader& reader) +{ + version = reader.ReadUInt16(); + xAvgCharWidth = reader.ReadInt16(); + usWeightClass = reader.ReadUInt16(); + usWidthClass = reader.ReadUInt16(); + fsType = reader.ReadUInt16(); + ySubscriptXSize = reader.ReadInt16(); + ySubscriptYSize = reader.ReadInt16(); + ySubscriptXOffset = reader.ReadInt16(); + ySubscriptYOffset = reader.ReadInt16(); + ySuperscriptXSize = reader.ReadInt16(); + ySuperscriptYSize = reader.ReadInt16(); + ySuperscriptXOffset = reader.ReadInt16(); + ySuperscriptYOffset = reader.ReadInt16(); + yStrikeoutSize = reader.ReadInt16(); + yStrikeoutPosition = reader.ReadInt16(); + sFamilyClass = reader.ReadInt16(); + for (int i = 0; i < 10; i++) + { + panose[i] = reader.ReadUInt8(); + } + ulUnicodeRange1 = reader.ReadUInt32(); + ulUnicodeRange2 = reader.ReadUInt32(); + ulUnicodeRange3 = reader.ReadUInt32(); + ulUnicodeRange4 = reader.ReadUInt32(); + achVendID = reader.ReadTag(); + fsSelection = reader.ReadUInt16(); + usFirstCharIndex = reader.ReadUInt16(); + usLastCharIndex = reader.ReadUInt16(); + sTypoAscender = reader.ReadInt16(); + sTypoDescender = reader.ReadInt16(); + sTypoLineGap = reader.ReadInt16(); + if (!reader.IsEndOfData()) // may be missing in v0 due to a bug in Apple's TTF documentation + { + usWinAscent = reader.ReadUInt16(); + usWinDescent = reader.ReadUInt16(); + } + if (version >= 1) + { + ulCodePageRange1 = reader.ReadUInt32(); + ulCodePageRange2 = reader.ReadUInt32(); + } + if (version >= 2) + { + sxHeight = reader.ReadInt16(); + sCapHeight = reader.ReadInt16(); + usDefaultChar = reader.ReadUInt16(); + usBreakChar = reader.ReadUInt16(); + usMaxContext = reader.ReadUInt16(); + } + if (version >= 5) + { + usLowerOpticalPointSize = reader.ReadUInt16(); + usUpperOpticalPointSize = reader.ReadUInt16(); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void TTF_IndexToLocation::Load(const TTF_FontHeader& head, const TTF_MaximumProfile& maxp, TrueTypeFileReader& reader) +{ + int count = (int)maxp.numGlyphs + 1; + if (head.indexToLocFormat == 0) + { + offsets.reserve(count); + for (int i = 0; i < count; i++) + { + offsets.push_back((ttf_Offset32)reader.ReadOffset16() * 2); + } + } + else + { + offsets.reserve(count); + for (int i = 0; i < count; i++) + { + offsets.push_back(reader.ReadOffset32()); + } + } +} + +///////////////////////////////////////////////////////////////////////////// + +ttf_uint8 TrueTypeFileReader::ReadUInt8() +{ + ttf_uint8 v; Read(&v, 1); return v; +} + +ttf_uint16 TrueTypeFileReader::ReadUInt16() +{ + ttf_uint8 v[2]; Read(v, 2); return (((ttf_uint16)v[0]) << 8) | (ttf_uint16)v[1]; +} + +ttf_uint24 TrueTypeFileReader::ReadUInt24() +{ + ttf_uint8 v[3]; Read(v, 3); return (((ttf_uint32)v[0]) << 16) | (((ttf_uint32)v[1]) << 8) | (ttf_uint32)v[2]; +} + +ttf_uint32 TrueTypeFileReader::ReadUInt32() +{ + ttf_uint8 v[4]; Read(v, 4); return (((ttf_uint32)v[0]) << 24) | (((ttf_uint32)v[1]) << 16) | (((ttf_uint32)v[2]) << 8) | (ttf_uint32)v[3]; +} + +ttf_int8 TrueTypeFileReader::ReadInt8() +{ + return ReadUInt8(); +} + +ttf_int16 TrueTypeFileReader::ReadInt16() +{ + return ReadUInt16(); +} + +ttf_int32 TrueTypeFileReader::ReadInt32() +{ + return ReadUInt32(); +} + +ttf_Fixed TrueTypeFileReader::ReadFixed() +{ + return ReadUInt32(); +} + +ttf_UFWORD TrueTypeFileReader::ReadUFWORD() +{ + return ReadUInt16(); +} + +ttf_FWORD TrueTypeFileReader::ReadFWORD() +{ + return ReadUInt16(); +} + +ttf_F2DOT14 TrueTypeFileReader::ReadF2DOT14() +{ + return ReadUInt16(); +} + +ttf_LONGDATETIME TrueTypeFileReader::ReadLONGDATETIME() +{ + ttf_uint8 v[8]; Read(v, 8); + return + (((ttf_LONGDATETIME)v[0]) << 56) | (((ttf_LONGDATETIME)v[1]) << 48) | (((ttf_LONGDATETIME)v[2]) << 40) | (((ttf_LONGDATETIME)v[3]) << 32) | + (((ttf_LONGDATETIME)v[4]) << 24) | (((ttf_LONGDATETIME)v[5]) << 16) | (((ttf_LONGDATETIME)v[6]) << 8) | (ttf_LONGDATETIME)v[7]; +} + +ttf_Tag TrueTypeFileReader::ReadTag() +{ + ttf_Tag v; Read(v.data(), v.size()); return v; +} + +ttf_Offset16 TrueTypeFileReader::ReadOffset16() +{ + return ReadUInt16(); +} + +ttf_Offset24 TrueTypeFileReader::ReadOffset24() +{ + return ReadUInt24(); +} + +ttf_Offset32 TrueTypeFileReader::ReadOffset32() +{ + return ReadUInt32(); +} + +ttf_Version16Dot16 TrueTypeFileReader::ReadVersion16Dot16() +{ + return ReadUInt32(); +} + +void TrueTypeFileReader::Seek(size_t newpos) +{ + if (newpos > size) + throw std::runtime_error("Invalid TTF file"); + + pos = newpos; +} + +void TrueTypeFileReader::Read(void* output, size_t count) +{ + if (pos + count > size) + throw std::runtime_error("Unexpected end of TTF file"); + memcpy(output, data + pos, count); + pos += count; +} diff --git a/libraries/ZWidget/src/core/truetypefont.h b/libraries/ZWidget/src/core/truetypefont.h new file mode 100644 index 00000000000..5fd4c50997f --- /dev/null +++ b/libraries/ZWidget/src/core/truetypefont.h @@ -0,0 +1,527 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +typedef uint8_t ttf_uint8; +typedef uint16_t ttf_uint16; +typedef uint32_t ttf_uint24; // 24-bit unsigned integer +typedef uint32_t ttf_uint32; + +typedef int8_t ttf_int8; +typedef int16_t ttf_int16; +typedef int32_t ttf_int32; + +typedef uint32_t ttf_Fixed; // 32-bit signed fixed-point number (16.16) +typedef uint16_t ttf_UFWORD; // uint16 that describes a quantity in font design units +typedef int16_t ttf_FWORD; // int16 that describes a quantity in font design units +typedef uint16_t ttf_F2DOT14; // 16-bit signed fixed number with the low 14 bits of fraction (2.14) +typedef uint64_t ttf_LONGDATETIME; // number of seconds since 12:00 midnight, January 1, 1904, UTC + +typedef std::array ttf_Tag; // 4 byte identifier + +typedef uint16_t ttf_Offset16; // Short offset to a table, same as uint16, NULL offset = 0x0000 +typedef uint32_t ttf_Offset24; // 24-bit offset to a table, same as uint24, NULL offset = 0x000000 +typedef uint32_t ttf_Offset32; // Long offset to a table, same as uint32, NULL offset = 0x00000000 + +typedef uint32_t ttf_Version16Dot16; // Packed 32-bit value with major and minor version numbers + +class TrueTypeFileReader +{ +public: + TrueTypeFileReader() = default; + TrueTypeFileReader(const void* data, size_t size) : data(static_cast(data)), size(size) { } + + bool IsEndOfData() const { return pos == size; } + + ttf_uint8 ReadUInt8(); + ttf_uint16 ReadUInt16(); + ttf_uint24 ReadUInt24(); + ttf_uint32 ReadUInt32(); + ttf_int8 ReadInt8(); + ttf_int16 ReadInt16(); + ttf_int32 ReadInt32(); + ttf_Fixed ReadFixed(); + ttf_UFWORD ReadUFWORD(); + ttf_FWORD ReadFWORD(); + ttf_F2DOT14 ReadF2DOT14(); + ttf_LONGDATETIME ReadLONGDATETIME(); + ttf_Tag ReadTag(); + ttf_Offset16 ReadOffset16(); + ttf_Offset24 ReadOffset24(); + ttf_Offset32 ReadOffset32(); + ttf_Version16Dot16 ReadVersion16Dot16(); + + void Seek(size_t newpos); + void Read(void* output, size_t count); + +private: + const uint8_t* data = nullptr; + size_t size = 0; + size_t pos = 0; +}; + +struct TTF_TableRecord +{ + ttf_Tag tableTag = {}; + ttf_uint32 checksum = {}; + ttf_Offset32 offset = {}; + ttf_uint32 length = {}; + + void Load(TrueTypeFileReader& reader); + + TrueTypeFileReader GetReader(const void* filedata, size_t filesize) const + { + if ((size_t)offset + length > filesize) + throw std::runtime_error("Invalid TTF table directory record"); + + return TrueTypeFileReader((uint8_t*)filedata + offset, length); + } +}; + +struct TTF_TableDirectory +{ + ttf_uint32 sfntVersion = {}; + ttf_uint16 numTables = {}; + std::vector tableRecords; + + // To do: Apple TTF fonts allow 'true' and 'typ1' for sfntVersion as well. + bool ContainsTTFOutlines() const { return sfntVersion == 0x00010000; } + bool ContainsCFFData() const { return sfntVersion == 0x4F54544F; } + + void Load(TrueTypeFileReader& reader); + + const TTF_TableRecord& GetRecord(const char* tag) const + { + for (const auto& record : tableRecords) + { + if (memcmp(record.tableTag.data(), tag, 4) == 0) + { + return record; + } + } + throw std::runtime_error(std::string("Could not find required '") + tag + "' table entry"); + } + + TrueTypeFileReader GetReader(const void* filedata, size_t filesize, const char* tag) const + { + return GetRecord(tag).GetReader(filedata, filesize); + } +}; + +struct TTC_Header +{ + ttf_Tag ttcTag = {}; + ttf_uint16 majorVersion = {}; + ttf_uint16 minorVersion = {}; + ttf_uint32 numFonts = {}; + std::vector tableDirectoryOffsets; + + // majorVersion = 2, minorVersion = 0: + ttf_uint32 dsigTag = {}; + ttf_uint32 dsigLength = {}; + ttf_uint32 dsigOffset = {}; + + void Load(TrueTypeFileReader& reader); +}; + +struct TTF_EncodingRecord +{ + ttf_uint16 platformID = {}; + ttf_uint16 encodingID = {}; + ttf_Offset32 subtableOffset = {}; +}; + +struct TTF_CMap // 'cmap' Character to glyph mapping +{ + ttf_uint16 version = {}; + ttf_uint16 numTables = {}; + std::vector encodingRecords; // [numTables] + + void Load(TrueTypeFileReader& reader); + + TTF_EncodingRecord GetEncoding(ttf_uint16 platformID, ttf_uint16 encodingID) const + { + for (const TTF_EncodingRecord& record : encodingRecords) + { + if (record.platformID == platformID && record.encodingID == encodingID) + { + return record; + } + } + return {}; + } +}; + +struct TTF_GlyphRange +{ + ttf_uint32 startCharCode = 0; + ttf_uint32 endCharCode = 0; + ttf_uint32 startGlyphID = 0; +}; + +struct TTF_CMapSubtable0 // Byte encoding table +{ + ttf_uint16 length = {}; + ttf_uint16 language = {}; + std::vector glyphIdArray; + + void Load(TrueTypeFileReader& reader); +}; + +struct TTF_CMapSubtable4 // Segment mapping to delta values (U+0000 to U+FFFF) +{ + ttf_uint16 length = {}; + ttf_uint16 language = {}; + ttf_uint16 segCount = {}; + std::vector endCode; + ttf_uint16 reservedPad = {}; + std::vector startCode; + std::vector idDelta; + std::vector idRangeOffsets; + std::vector glyphIdArray; + + void Load(TrueTypeFileReader& reader); +}; + +struct TTF_CMapSubtable12 // Segmented coverage (U+0000 to U+10FFFF) +{ + ttf_uint16 reserved; + ttf_uint32 length; + ttf_uint32 language; + ttf_uint32 numGroups; + std::vector groups; + + void Load(TrueTypeFileReader& reader); +}; + +typedef TTF_CMapSubtable12 TTF_CMapSubtable13; // Many-to-one range mappings + +struct TTF_FontHeader // 'head' Font header +{ + ttf_uint16 majorVersion = {}; + ttf_uint16 minorVersion = {}; + ttf_Fixed fontRevision = {}; + ttf_uint32 checksumAdjustment = {}; + ttf_uint32 magicNumber = {}; + ttf_uint16 flags = {}; + ttf_uint16 unitsPerEm = {}; + ttf_LONGDATETIME created = {}; + ttf_LONGDATETIME modified = {}; + ttf_int16 xMin = {}; + ttf_int16 yMin = {}; + ttf_int16 xMax = {}; + ttf_int16 yMax = {}; + ttf_uint16 macStyle = {}; + ttf_uint16 lowestRecPPEM = {}; + ttf_int16 fontDirectionHint = {}; + ttf_int16 indexToLocFormat = {}; + ttf_int16 glyphDataFormat = {}; + + void Load(TrueTypeFileReader& reader); +}; + +struct TTF_HorizontalHeader // 'hhea' Horizontal header +{ + ttf_uint16 majorVersion = {}; + ttf_uint16 minorVersion = {}; + ttf_FWORD ascender = {}; + ttf_FWORD descender = {}; + ttf_FWORD lineGap = {}; + ttf_UFWORD advanceWidthMax = {}; + ttf_FWORD minLeftSideBearing = {}; + ttf_FWORD minRightSideBearing = {}; + ttf_FWORD xMaxExtent = {}; + ttf_int16 caretSlopeRise = {}; + ttf_int16 caretSlopeRun = {}; + ttf_int16 caretOffset = {}; + ttf_int16 reserved0 = {}; + ttf_int16 reserved1 = {}; + ttf_int16 reserved2 = {}; + ttf_int16 reserved3 = {}; + ttf_int16 metricDataFormat = {}; + ttf_uint16 numberOfHMetrics = {}; + + void Load(TrueTypeFileReader& reader); +}; + +struct TTF_MaximumProfile; + +struct TTF_HorizontalMetrics // 'hmtx' Horizontal metrics +{ + struct longHorMetric + { + ttf_uint16 advanceWidth = {}; + ttf_int16 lsb = {}; + }; + std::vector hMetrics; // [hhea.numberOfHMetrics] + std::vector leftSideBearings; // [maxp.numGlyphs - hhea.numberOfHMetrics] + + void Load(const TTF_HorizontalHeader& hhea, const TTF_MaximumProfile& maxp, TrueTypeFileReader& reader); +}; + +struct TTF_MaximumProfile // 'maxp' Maximum profile +{ + // v0.5 and v1: + ttf_Version16Dot16 version = {}; + ttf_uint16 numGlyphs = {}; + + // v1 only: + ttf_uint16 maxPoints = {}; + ttf_uint16 maxContours = {}; + ttf_uint16 maxCompositePoints = {}; + ttf_uint16 maxCompositeContours = {}; + ttf_uint16 maxZones = {}; + ttf_uint16 maxTwilightPoints = {}; + ttf_uint16 maxStorage = {}; + ttf_uint16 maxFunctionDefs = {}; + ttf_uint16 maxInstructionDefs = {}; + ttf_uint16 maxStackElements = {}; + ttf_uint16 maxSizeOfInstructions = {}; + ttf_uint16 maxComponentElements = {}; + ttf_uint16 maxComponentDepth = {}; + + void Load(TrueTypeFileReader& reader); +}; + +class TTCFontName +{ +public: + std::string FamilyName; // Arial + std::string SubfamilyName; // Regular + std::string FullName; // Arial Regular + std::string UniqueID; + std::string VersionString; + std::string PostscriptName; +}; + +struct TTF_NamingTable // 'name' Naming table +{ + struct NameRecord + { + ttf_uint16 platformID = {}; + ttf_uint16 encodingID = {}; + ttf_uint16 languageID = {}; + ttf_uint16 nameID = {}; + ttf_uint16 length = {}; + ttf_Offset16 stringOffset = {}; + std::string text; + }; + + struct LangTagRecord + { + ttf_uint16 length = {}; + ttf_Offset16 langTagOffset = {}; + }; + + // v0 and v1: + ttf_uint16 version = {}; + ttf_uint16 count = {}; + ttf_Offset16 storageOffset = {}; + std::vector nameRecord; // [count] + + // v1 only: + ttf_uint16 langTagCount = {}; + std::vector langTagRecord; // [langTagCount] + + void Load(TrueTypeFileReader& reader); + + TTCFontName GetFontName() const; +}; + +struct TTF_OS2Windows // 'OS/2' Windows specific metrics +{ + ttf_uint16 version = {}; + ttf_int16 xAvgCharWidth = {}; + ttf_uint16 usWeightClass = {}; + ttf_uint16 usWidthClass = {}; + ttf_uint16 fsType = {}; + ttf_int16 ySubscriptXSize = {}; + ttf_int16 ySubscriptYSize = {}; + ttf_int16 ySubscriptXOffset = {}; + ttf_int16 ySubscriptYOffset = {}; + ttf_int16 ySuperscriptXSize = {}; + ttf_int16 ySuperscriptYSize = {}; + ttf_int16 ySuperscriptXOffset = {}; + ttf_int16 ySuperscriptYOffset = {}; + ttf_int16 yStrikeoutSize = {}; + ttf_int16 yStrikeoutPosition = {}; + ttf_int16 sFamilyClass = {}; + ttf_uint8 panose[10] = {}; + ttf_uint32 ulUnicodeRange1 = {}; + ttf_uint32 ulUnicodeRange2 = {}; + ttf_uint32 ulUnicodeRange3 = {}; + ttf_uint32 ulUnicodeRange4 = {}; + ttf_Tag achVendID = {}; + ttf_uint16 fsSelection = {}; + ttf_uint16 usFirstCharIndex = {}; + ttf_uint16 usLastCharIndex = {}; + ttf_int16 sTypoAscender = {}; + ttf_int16 sTypoDescender = {}; + ttf_int16 sTypoLineGap = {}; + ttf_uint16 usWinAscent = {}; // may be missing in v0 due to bugs in Apple docs + ttf_uint16 usWinDescent = {}; // may be missing in v0 due to bugs in Apple docs + ttf_uint32 ulCodePageRange1 = {}; // v1 + ttf_uint32 ulCodePageRange2 = {}; + ttf_int16 sxHeight = {}; // v2, v3 and v4 + ttf_int16 sCapHeight = {}; + ttf_uint16 usDefaultChar = {}; + ttf_uint16 usBreakChar = {}; + ttf_uint16 usMaxContext = {}; + ttf_uint16 usLowerOpticalPointSize = {}; // v5 + ttf_uint16 usUpperOpticalPointSize = {}; + + void Load(TrueTypeFileReader& reader); +}; + +// Simple glyph flags: +#define TTF_ON_CURVE_POINT 0x01 +#define TTF_X_SHORT_VECTOR 0x02 +#define TTF_Y_SHORT_VECTOR 0x04 +#define TTF_REPEAT_FLAG 0x08 +#define TTF_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR 0x10 +#define TTF_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR 0x20 +#define TTF_OVERLAP_SIMPLE = 0x40 + +// Composite glyph flags: +#define TTF_ARG_1_AND_2_ARE_WORDS 0x0001 +#define TTF_ARGS_ARE_XY_VALUES 0x0002 +#define TTF_ROUND_XY_TO_GRID 0x0004 +#define TTF_WE_HAVE_A_SCALE 0x0008 +#define TTF_MORE_COMPONENTS 0x0020 +#define TTF_WE_HAVE_AN_X_AND_Y_SCALE 0x0040 +#define TTF_WE_HAVE_A_TWO_BY_TWO 0x0080 +#define TTF_WE_HAVE_INSTRUCTIONS 0x0100 +#define TTF_USE_MY_METRICS 0x0200 +#define TTF_OVERLAP_COMPOUND 0x0400 +#define TTF_SCALED_COMPONENT_OFFSET 0x0800 +#define TTF_UNSCALED_COMPONENT_OFFSET 0x1000 + +struct TTF_IndexToLocation // 'loca' Index to location +{ + std::vector offsets; + + void Load(const TTF_FontHeader& head, const TTF_MaximumProfile& maxp, TrueTypeFileReader& reader); +}; + +struct TTF_Point +{ + float x; + float y; +}; + +struct TTF_SimpleGlyph +{ + std::vector endPtsOfContours; + std::vector flags; + std::vector points; +}; + +class TrueTypeGlyph +{ +public: + int advanceWidth = 0; + int leftSideBearing = 0; + int yOffset = 0; + + int width = 0; + int height = 0; + std::unique_ptr grayscale; +}; + +class TrueTypeTextMetrics +{ +public: + double ascender = 0.0; + double descender = 0.0; + double lineGap = 0.0; +}; + +class TrueTypeFontFileData +{ +public: + TrueTypeFontFileData(std::vector& data) : dataVector(std::move(data)) + { + dataPtr = dataVector.data(); + dataSize = dataVector.size(); + } + + TrueTypeFontFileData(const void* data, size_t size, bool copyData = true) + { + dataSize = size; + if (copyData) + { + dataPtr = new uint8_t[size]; + deleteDataPtr = true; + memcpy(const_cast(dataPtr), data, size); + } + else + { + dataPtr = data; + } + } + + ~TrueTypeFontFileData() + { + if (deleteDataPtr) + { + delete[](uint8_t*)dataPtr; + } + dataPtr = nullptr; + } + + const void* data() const { return dataPtr; } + size_t size() const { return dataSize; } + +private: + std::vector dataVector; + const void* dataPtr = nullptr; + size_t dataSize = 0; + bool deleteDataPtr = false; + + TrueTypeFontFileData(const TrueTypeFontFileData&) = delete; + TrueTypeFontFileData& operator=(const TrueTypeFontFileData&) = delete; +}; + +class TrueTypeFont +{ +public: + TrueTypeFont(std::shared_ptr& data, int ttcFontIndex = 0); + + static std::vector GetFontNames(const std::shared_ptr& data); + + TrueTypeTextMetrics GetTextMetrics(double height) const; + uint32_t GetGlyphIndex(uint32_t codepoint) const; + TrueTypeGlyph LoadGlyph(uint32_t glyphIndex, double height) const; + +private: + void LoadCharacterMapEncoding(TrueTypeFileReader& reader); + void LoadGlyph(TTF_SimpleGlyph& glyph, uint32_t glyphIndex, int compositeDepth = 0) const; + static float F2DOT14_ToFloat(ttf_F2DOT14 v); + + std::shared_ptr data; + + TTC_Header ttcHeader; + TTF_TableDirectory directory; + + // Required for all OpenType fonts: + TTF_CMap cmap; + TTF_FontHeader head; + TTF_HorizontalHeader hhea; + TTF_HorizontalMetrics hmtx; + TTF_MaximumProfile maxp; + TTF_NamingTable name; + TTF_OS2Windows os2; + + // TrueType outlines: + TTF_TableRecord glyf; // Parsed on a per glyph basis using offsets from other tables + TTF_IndexToLocation loca; + + std::vector Ranges; + std::vector ManyToOneRanges; +}; diff --git a/libraries/ZWidget/src/core/utf8reader.cpp b/libraries/ZWidget/src/core/utf8reader.cpp new file mode 100644 index 00000000000..200da9fdc4e --- /dev/null +++ b/libraries/ZWidget/src/core/utf8reader.cpp @@ -0,0 +1,153 @@ +/* +** Copyright (c) 1997-2015 Mark Page +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "core/utf8reader.h" + +namespace +{ + static const char trailing_bytes_for_utf8[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 + }; + + static const unsigned char bitmask_leadbyte_for_utf8[6] = + { + 0x7f, + 0x1f, + 0x0f, + 0x07, + 0x03, + 0x01 + }; +} + +UTF8Reader::UTF8Reader(const std::string::value_type *text, std::string::size_type length) : length(length), data((unsigned char *)text) +{ +} + +bool UTF8Reader::is_end() +{ + return current_position >= length; +} + +unsigned int UTF8Reader::character() +{ + if (current_position >= length) + return 0; + + int trailing_bytes = trailing_bytes_for_utf8[data[current_position]]; + if (trailing_bytes == 0 && (data[current_position] & 0x80) == 0x80) + return '?'; + + if (current_position + 1 + trailing_bytes > length) + { + return '?'; + } + else + { + unsigned int ucs4 = (data[current_position] & bitmask_leadbyte_for_utf8[trailing_bytes]); + for (std::string::size_type i = 0; i < trailing_bytes; i++) + { + if ((data[current_position + 1 + i] & 0xC0) == 0x80) + ucs4 = (ucs4 << 6) + (data[current_position + 1 + i] & 0x3f); + else + return '?'; + } + + // To do: verify that the ucs4 value is in the range for the trailing_bytes specified in the lead byte. + + return ucs4; + } + +} + +std::string::size_type UTF8Reader::char_length() +{ + if (current_position < length) + { + int trailing_bytes = trailing_bytes_for_utf8[data[current_position]]; + if (current_position + 1 + trailing_bytes > length) + return 1; + + for (std::string::size_type i = 0; i < trailing_bytes; i++) + { + if ((data[current_position + 1 + i] & 0xC0) != 0x80) + return 1; + } + + return 1 + trailing_bytes; + } + else + { + return 0; + } +} + +void UTF8Reader::prev() +{ + if (current_position > length) + current_position = length; + + if (current_position > 0) + { + current_position--; + move_to_leadbyte(); + } +} + +void UTF8Reader::next() +{ + current_position += char_length(); + +} + +void UTF8Reader::move_to_leadbyte() +{ + if (current_position < length) + { + int lead_position = (int)current_position; + + while (lead_position > 0 && (data[lead_position] & 0xC0) == 0x80) + lead_position--; + + int trailing_bytes = trailing_bytes_for_utf8[data[lead_position]]; + if (lead_position + trailing_bytes >= current_position) + current_position = lead_position; + } + +} + +std::string::size_type UTF8Reader::position() +{ + return current_position; +} + +void UTF8Reader::set_position(std::string::size_type position) +{ + current_position = position; +} diff --git a/libraries/ZWidget/src/core/widget.cpp b/libraries/ZWidget/src/core/widget.cpp new file mode 100644 index 00000000000..2bbbf21f2e2 --- /dev/null +++ b/libraries/ZWidget/src/core/widget.cpp @@ -0,0 +1,715 @@ + +#include "core/widget.h" +#include "core/timer.h" +#include "core/colorf.h" +#include + +Widget::Widget(Widget* parent, WidgetType type) : Type(type) +{ + if (type != WidgetType::Child) + { + DispWindow = DisplayWindow::Create(this); + DispCanvas = Canvas::create(DispWindow.get()); + } + + SetParent(parent); +} + +Widget::~Widget() +{ + while (LastChildObj) + delete LastChildObj; + + while (FirstTimerObj) + delete FirstTimerObj; + + DetachFromParent(); +} + +void Widget::SetParent(Widget* newParent) +{ + if (ParentObj != newParent) + { + if (ParentObj) + DetachFromParent(); + + if (newParent) + { + PrevSiblingObj = newParent->LastChildObj; + if (PrevSiblingObj) PrevSiblingObj->NextSiblingObj = this; + newParent->LastChildObj = this; + if (!newParent->FirstChildObj) newParent->FirstChildObj = this; + ParentObj = newParent; + } + } +} + +void Widget::MoveBefore(Widget* sibling) +{ + if (sibling && sibling->ParentObj != ParentObj) throw std::runtime_error("Invalid sibling passed to Widget.MoveBefore"); + if (!ParentObj) throw std::runtime_error("Widget must have a parent before it can be moved"); + + if (NextSiblingObj != sibling) + { + Widget* p = ParentObj; + DetachFromParent(); + + ParentObj = p; + if (sibling) + { + NextSiblingObj = sibling; + PrevSiblingObj = sibling->PrevSiblingObj; + sibling->PrevSiblingObj = this; + if (PrevSiblingObj) PrevSiblingObj->NextSiblingObj = this; + if (ParentObj->FirstChildObj == sibling) ParentObj->FirstChildObj = this; + } + else + { + PrevSiblingObj = ParentObj->LastChildObj; + if (PrevSiblingObj) PrevSiblingObj->NextSiblingObj = this; + ParentObj->LastChildObj = this; + if (!ParentObj->FirstChildObj) ParentObj->FirstChildObj = this; + } + } +} + +void Widget::DetachFromParent() +{ + for (Widget* cur = ParentObj; cur; cur = cur->ParentObj) + { + if (cur->FocusWidget == this) + cur->FocusWidget = nullptr; + if (cur->CaptureWidget == this) + cur->CaptureWidget = nullptr; + if (cur->HoverWidget == this) + cur->HoverWidget = nullptr; + + if (cur->DispWindow) + break; + } + + if (PrevSiblingObj) + PrevSiblingObj->NextSiblingObj = NextSiblingObj; + if (NextSiblingObj) + NextSiblingObj->PrevSiblingObj = PrevSiblingObj; + if (ParentObj) + { + if (ParentObj->FirstChildObj == this) + ParentObj->FirstChildObj = NextSiblingObj; + if (ParentObj->LastChildObj == this) + ParentObj->LastChildObj = PrevSiblingObj; + } + PrevSiblingObj = nullptr; + NextSiblingObj = nullptr; + ParentObj = nullptr; +} + +std::string Widget::GetWindowTitle() const +{ + return WindowTitle; +} + +void Widget::SetWindowTitle(const std::string& text) +{ + if (WindowTitle != text) + { + WindowTitle = text; + if (DispWindow) + DispWindow->SetWindowTitle(WindowTitle); + } +} + +Size Widget::GetSize() const +{ + return ContentGeometry.size(); +} + +Rect Widget::GetFrameGeometry() const +{ + if (Type == WidgetType::Child) + { + return FrameGeometry; + } + else + { + return DispWindow->GetWindowFrame(); + } +} + +void Widget::SetNoncontentSizes(double left, double top, double right, double bottom) +{ + Noncontent.Left = left; + Noncontent.Top = top; + Noncontent.Right = right; + Noncontent.Bottom = bottom; +} + +void Widget::SetFrameGeometry(const Rect& geometry) +{ + if (Type == WidgetType::Child) + { + FrameGeometry = geometry; + double left = FrameGeometry.left() + Noncontent.Left; + double top = FrameGeometry.top() + Noncontent.Top; + double right = FrameGeometry.right() - Noncontent.Right; + double bottom = FrameGeometry.bottom() - Noncontent.Bottom; + left = std::min(left, FrameGeometry.right()); + top = std::min(top, FrameGeometry.bottom()); + right = std::max(right, FrameGeometry.left()); + bottom = std::max(bottom, FrameGeometry.top()); + ContentGeometry = Rect::ltrb(left, top, right, bottom); + OnGeometryChanged(); + } + else + { + DispWindow->SetWindowFrame(geometry); + } +} + +void Widget::Show() +{ + if (Type != WidgetType::Child) + { + DispWindow->Show(); + } + else if (HiddenFlag) + { + HiddenFlag = false; + Update(); + } +} + +void Widget::ShowFullscreen() +{ + if (Type != WidgetType::Child) + { + DispWindow->ShowFullscreen(); + } +} + +void Widget::ShowMaximized() +{ + if (Type != WidgetType::Child) + { + DispWindow->ShowMaximized(); + } +} + +void Widget::ShowMinimized() +{ + if (Type != WidgetType::Child) + { + DispWindow->ShowMinimized(); + } +} + +void Widget::ShowNormal() +{ + if (Type != WidgetType::Child) + { + DispWindow->ShowNormal(); + } +} + +void Widget::Hide() +{ + if (Type != WidgetType::Child) + { + if (DispWindow) + DispWindow->Hide(); + } + else if (!HiddenFlag) + { + HiddenFlag = true; + Update(); + } +} + +void Widget::ActivateWindow() +{ + if (Type != WidgetType::Child) + { + DispWindow->Activate(); + } +} + +void Widget::Close() +{ + OnClose(); +} + +void Widget::SetWindowBackground(const Colorf& color) +{ + Widget* w = Window(); + if (w && w->WindowBackground != color) + { + w->WindowBackground = color; + Update(); + } +} + +void Widget::SetWindowBorderColor(const Colorf& color) +{ + Widget* w = Window(); + if (w) + { + w->DispWindow->SetBorderColor(color.toBgra8()); + w->DispWindow->Update(); + } +} + +void Widget::SetWindowCaptionColor(const Colorf& color) +{ + Widget* w = Window(); + if (w) + { + w->DispWindow->SetCaptionColor(color.toBgra8()); + w->DispWindow->Update(); + } +} + +void Widget::SetWindowCaptionTextColor(const Colorf& color) +{ + Widget* w = Window(); + if (w) + { + w->DispWindow->SetCaptionTextColor(color.toBgra8()); + w->DispWindow->Update(); + } +} + +void Widget::Update() +{ + Widget* w = Window(); + if (w) + { + w->DispWindow->Update(); + } +} + +void Widget::Repaint() +{ + Widget* w = Window(); + w->DispCanvas->begin(WindowBackground); + w->Paint(w->DispCanvas.get()); + w->DispCanvas->end(); +} + +void Widget::Paint(Canvas* canvas) +{ + Point oldOrigin = canvas->getOrigin(); + canvas->pushClip(FrameGeometry); + canvas->setOrigin(oldOrigin + FrameGeometry.topLeft()); + OnPaintFrame(canvas); + canvas->setOrigin(oldOrigin); + canvas->popClip(); + + canvas->pushClip(ContentGeometry); + canvas->setOrigin(oldOrigin + ContentGeometry.topLeft()); + OnPaint(canvas); + for (Widget* w = FirstChild(); w != nullptr; w = w->NextSibling()) + { + if (w->Type == WidgetType::Child && !w->HiddenFlag) + w->Paint(canvas); + } + canvas->setOrigin(oldOrigin); + canvas->popClip(); +} + +bool Widget::GetKeyState(EInputKey key) +{ + Widget* window = Window(); + return window ? window->DispWindow->GetKeyState(key) : false; +} + +bool Widget::HasFocus() +{ + Widget* window = Window(); + return window ? window->FocusWidget == this : false; +} + +bool Widget::IsEnabled() +{ + return true; +} + +bool Widget::IsHidden() +{ + return !IsVisible(); +} + +bool Widget::IsVisible() +{ + if (Type != WidgetType::Child) + { + return true; // DispWindow->IsVisible(); + } + else + { + return !HiddenFlag; + } +} + +void Widget::SetFocus() +{ + Widget* window = Window(); + if (window) + { + if (window->FocusWidget) + window->FocusWidget->OnLostFocus(); + window->FocusWidget = this; + window->FocusWidget->OnSetFocus(); + window->ActivateWindow(); + } +} + +void Widget::SetEnabled(bool value) +{ +} + +void Widget::LockCursor() +{ + Widget* w = Window(); + if (w && w->CaptureWidget != this) + { + w->CaptureWidget = this; + w->DispWindow->LockCursor(); + } +} + +void Widget::UnlockCursor() +{ + Widget* w = Window(); + if (w && w->CaptureWidget != nullptr) + { + w->CaptureWidget = nullptr; + w->DispWindow->UnlockCursor(); + } +} + +void Widget::SetCursor(StandardCursor cursor) +{ + if (CurrentCursor != cursor) + { + CurrentCursor = cursor; + if (HoverWidget == this || CaptureWidget == this) + { + Widget* w = Window(); + if (w) + { + w->DispWindow->SetCursor(CurrentCursor); + } + } + } +} + +void Widget::CaptureMouse() +{ + Widget* w = Window(); + if (w && w->CaptureWidget != this) + { + w->CaptureWidget = this; + w->DispWindow->CaptureMouse(); + } +} + +void Widget::ReleaseMouseCapture() +{ + Widget* w = Window(); + if (w && w->CaptureWidget != nullptr) + { + w->CaptureWidget = nullptr; + w->DispWindow->ReleaseMouseCapture(); + } +} + +std::string Widget::GetClipboardText() +{ + Widget* w = Window(); + if (w) + return w->DispWindow->GetClipboardText(); + else + return {}; +} + +void Widget::SetClipboardText(const std::string& text) +{ + Widget* w = Window(); + if (w) + w->DispWindow->SetClipboardText(text); +} + +Widget* Widget::Window() +{ + for (Widget* w = this; w != nullptr; w = w->Parent()) + { + if (w->DispWindow) + return w; + } + return nullptr; +} + +Canvas* Widget::GetCanvas() const +{ + for (const Widget* w = this; w != nullptr; w = w->Parent()) + { + if (w->DispCanvas) + return w->DispCanvas.get(); + } + return nullptr; +} + +Widget* Widget::ChildAt(const Point& pos) +{ + for (Widget* cur = LastChild(); cur != nullptr; cur = cur->PrevSibling()) + { + if (!cur->HiddenFlag && cur->FrameGeometry.contains(pos)) + { + Widget* cur2 = cur->ChildAt(pos - cur->ContentGeometry.topLeft()); + return cur2 ? cur2 : cur; + } + } + return nullptr; +} + +Point Widget::MapFrom(const Widget* parent, const Point& pos) const +{ + Point p = pos; + for (const Widget* cur = this; cur != nullptr; cur = cur->Parent()) + { + if (cur == parent) + return p; + p -= cur->ContentGeometry.topLeft(); + } + throw std::runtime_error("MapFrom: not a parent of widget"); +} + +Point Widget::MapFromGlobal(const Point& pos) const +{ + Point p = pos; + for (const Widget* cur = this; cur != nullptr; cur = cur->Parent()) + { + if (cur->DispWindow) + { + return p - cur->GetFrameGeometry().topLeft(); + } + p -= cur->ContentGeometry.topLeft(); + } + throw std::runtime_error("MapFromGlobal: no window widget found"); +} + +Point Widget::MapTo(const Widget* parent, const Point& pos) const +{ + Point p = pos; + for (const Widget* cur = this; cur != nullptr; cur = cur->Parent()) + { + if (cur == parent) + return p; + p += cur->ContentGeometry.topLeft(); + } + throw std::runtime_error("MapTo: not a parent of widget"); +} + +Point Widget::MapToGlobal(const Point& pos) const +{ + Point p = pos; + for (const Widget* cur = this; cur != nullptr; cur = cur->Parent()) + { + if (cur->DispWindow) + { + return cur->GetFrameGeometry().topLeft() + p; + } + p += cur->ContentGeometry.topLeft(); + } + throw std::runtime_error("MapFromGlobal: no window widget found"); +} + +void Widget::OnWindowPaint() +{ + Repaint(); +} + +void Widget::OnWindowMouseMove(const Point& pos) +{ + if (CaptureWidget) + { + DispWindow->SetCursor(CaptureWidget->CurrentCursor); + CaptureWidget->OnMouseMove(CaptureWidget->MapFrom(this, pos)); + } + else + { + Widget* widget = ChildAt(pos); + if (!widget) + widget = this; + + if (HoverWidget != widget) + { + if (HoverWidget) + { + for (Widget* w = HoverWidget; w != widget && w != this; w = w->Parent()) + { + Widget* p = w->Parent(); + if (!w->FrameGeometry.contains(p->MapFrom(this, pos))) + { + w->OnMouseLeave(); + } + } + } + HoverWidget = widget; + } + + DispWindow->SetCursor(widget->CurrentCursor); + + do + { + widget->OnMouseMove(widget->MapFrom(this, pos)); + if (widget == this) + break; + widget = widget->Parent(); + } while (widget); + } +} + +void Widget::OnWindowMouseDown(const Point& pos, EInputKey key) +{ + if (CaptureWidget) + { + CaptureWidget->OnMouseDown(CaptureWidget->MapFrom(this, pos), key); + } + else + { + Widget* widget = ChildAt(pos); + if (!widget) + widget = this; + while (widget) + { + bool stopPropagation = widget->OnMouseDown(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } + } +} + +void Widget::OnWindowMouseDoubleclick(const Point& pos, EInputKey key) +{ + if (CaptureWidget) + { + CaptureWidget->OnMouseDoubleclick(CaptureWidget->MapFrom(this, pos), key); + } + else + { + Widget* widget = ChildAt(pos); + if (!widget) + widget = this; + while (widget) + { + bool stopPropagation = widget->OnMouseDoubleclick(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } + } +} + +void Widget::OnWindowMouseUp(const Point& pos, EInputKey key) +{ + if (CaptureWidget) + { + CaptureWidget->OnMouseUp(CaptureWidget->MapFrom(this, pos), key); + } + else + { + Widget* widget = ChildAt(pos); + if (!widget) + widget = this; + while (widget) + { + bool stopPropagation = widget->OnMouseUp(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } + } +} + +void Widget::OnWindowMouseWheel(const Point& pos, EInputKey key) +{ + if (CaptureWidget) + { + CaptureWidget->OnMouseWheel(CaptureWidget->MapFrom(this, pos), key); + } + else + { + Widget* widget = ChildAt(pos); + if (!widget) + widget = this; + while (widget) + { + bool stopPropagation = widget->OnMouseWheel(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } + } +} + +void Widget::OnWindowRawMouseMove(int dx, int dy) +{ + if (CaptureWidget) + { + CaptureWidget->OnRawMouseMove(dx, dy); + } + else if (FocusWidget) + { + FocusWidget->OnRawMouseMove(dx, dy); + } +} + +void Widget::OnWindowKeyChar(std::string chars) +{ + if (FocusWidget) + FocusWidget->OnKeyChar(chars); +} + +void Widget::OnWindowKeyDown(EInputKey key) +{ + if (FocusWidget) + FocusWidget->OnKeyDown(key); +} + +void Widget::OnWindowKeyUp(EInputKey key) +{ + if (FocusWidget) + FocusWidget->OnKeyUp(key); +} + +void Widget::OnWindowGeometryChanged() +{ + Size size = DispWindow->GetClientSize(); + FrameGeometry = Rect::xywh(0.0, 0.0, size.width, size.height); + ContentGeometry = FrameGeometry; + OnGeometryChanged(); +} + +void Widget::OnWindowClose() +{ + Close(); +} + +void Widget::OnWindowActivated() +{ +} + +void Widget::OnWindowDeactivated() +{ +} + +void Widget::OnWindowDpiScaleChanged() +{ +} + +Size Widget::GetScreenSize() +{ + return DisplayWindow::GetScreenSize(); +} diff --git a/libraries/ZWidget/src/widgets/checkboxlabel/checkboxlabel.cpp b/libraries/ZWidget/src/widgets/checkboxlabel/checkboxlabel.cpp new file mode 100644 index 00000000000..6cf90badf0b --- /dev/null +++ b/libraries/ZWidget/src/widgets/checkboxlabel/checkboxlabel.cpp @@ -0,0 +1,93 @@ + +#include "widgets/checkboxlabel/checkboxlabel.h" + +CheckboxLabel::CheckboxLabel(Widget* parent) : Widget(parent) +{ +} + +void CheckboxLabel::SetText(const std::string& value) +{ + if (text != value) + { + text = value; + Update(); + } +} + +const std::string& CheckboxLabel::GetText() const +{ + return text; +} + +void CheckboxLabel::SetChecked(bool value) +{ + if (value != checked) + { + checked = value; + Update(); + } +} + +bool CheckboxLabel::GetChecked() const +{ + return checked; +} + +double CheckboxLabel::GetPreferredHeight() const +{ + return 20.0; +} + +void CheckboxLabel::OnPaint(Canvas* canvas) +{ + + if (checked) + { + canvas->fillRect(Rect::xywh(0.0, GetHeight() * 0.5 - 6.0, 10.0, 10.0), Colorf::fromRgba8(100, 100, 100)); + canvas->fillRect(Rect::xywh(1.0, GetHeight() * 0.5 - 5.0, 8.0, 8.0), Colorf::fromRgba8(51, 51, 51)); + canvas->fillRect(Rect::xywh(2.0, GetHeight() * 0.5 - 4.0, 6.0, 6.0), Colorf::fromRgba8(226, 223, 219)); + } + else + { + canvas->fillRect(Rect::xywh(0.0, GetHeight() * 0.5 - 6.0, 10.0, 10.0), Colorf::fromRgba8(99, 99, 99)); + canvas->fillRect(Rect::xywh(1.0, GetHeight() * 0.5 - 5.0, 8.0, 8.0), Colorf::fromRgba8(51, 51, 51)); + } + + canvas->drawText(Point(14.0, GetHeight() - 5.0), Colorf::fromRgba8(255, 255, 255), text); +} + +bool CheckboxLabel::OnMouseDown(const Point& pos, int key) +{ + mouseDownActive = true; + SetFocus(); + return true; +} + +bool CheckboxLabel::OnMouseUp(const Point& pos, int key) +{ + if (mouseDownActive) + { + Toggle(); + } + mouseDownActive = false; + return true; +} + +void CheckboxLabel::OnMouseLeave() +{ + mouseDownActive = false; +} + +void CheckboxLabel::OnKeyUp(EInputKey key) +{ + if (key == IK_Space) + Toggle(); +} + +void CheckboxLabel::Toggle() +{ + bool oldchecked = checked; + checked = radiostyle? true : !checked; + Update(); + if (checked != oldchecked && FuncChanged) FuncChanged(checked); +} diff --git a/libraries/ZWidget/src/widgets/imagebox/imagebox.cpp b/libraries/ZWidget/src/widgets/imagebox/imagebox.cpp new file mode 100644 index 00000000000..45d35a160fb --- /dev/null +++ b/libraries/ZWidget/src/widgets/imagebox/imagebox.cpp @@ -0,0 +1,31 @@ + +#include "widgets/imagebox/imagebox.h" + +ImageBox::ImageBox(Widget* parent) : Widget(parent) +{ +} + +double ImageBox::GetPreferredHeight() const +{ + if (image) + return (double)image->GetHeight(); + else + return 0.0; +} + +void ImageBox::SetImage(std::shared_ptr newImage) +{ + if (image != newImage) + { + image = newImage; + Update(); + } +} + +void ImageBox::OnPaint(Canvas* canvas) +{ + if (image) + { + canvas->drawImage(image, Point((GetWidth() - (double)image->GetWidth()) * 0.5, (GetHeight() - (double)image->GetHeight()) * 0.5)); + } +} diff --git a/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp b/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp new file mode 100644 index 00000000000..5c90e68e191 --- /dev/null +++ b/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp @@ -0,0 +1,1191 @@ +#include +#include "widgets/lineedit/lineedit.h" +#include "core/utf8reader.h" +#include "core/colorf.h" + +LineEdit::LineEdit(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(5.0, 3.0, 5.0, 3.0); + + timer = new Timer(this); + timer->FuncExpired = [=]() { OnTimerExpired(); }; + + scroll_timer = new Timer(this); + scroll_timer->FuncExpired = [=]() { OnScrollTimerExpired(); }; + + SetCursor(StandardCursor::ibeam); +} + +LineEdit::~LineEdit() +{ +} + +bool LineEdit::IsReadOnly() const +{ + return readonly; +} + +LineEdit::Alignment LineEdit::GetAlignment() const +{ + return align_left; +} + +bool LineEdit::IsLowercase() const +{ + return lowercase; +} + +bool LineEdit::IsUppercase() const +{ + return uppercase; +} + +bool LineEdit::IsPasswordMode() const +{ + return password_mode; +} + +int LineEdit::GetMaxLength() const +{ + return max_length; +} + +std::string LineEdit::GetText() const +{ + return text; +} + +int LineEdit::GetTextInt() const +{ + return std::atoi(text.c_str()); +} + +float LineEdit::GetTextFloat() const +{ + return (float)std::atof(text.c_str()); +} + +std::string LineEdit::GetSelection() const +{ + int start = std::min(selection_start, selection_start + selection_length); + return text.substr(start, std::abs(selection_length)); +} + +int LineEdit::GetSelectionStart() const +{ + return selection_start; +} + +int LineEdit::GetSelectionLength() const +{ + return selection_length; +} + +int LineEdit::GetCursorPos() const +{ + return cursor_pos; +} + +Size LineEdit::GetTextSize() +{ + Canvas* canvas = GetCanvas(); + return GetVisualTextSize(canvas); +} + +Size LineEdit::GetTextSize(const std::string& str) +{ + Canvas* canvas = GetCanvas(); + return canvas->measureText(str).size(); +} + +double LineEdit::GetPreferredContentWidth() +{ + return GetTextSize().width; +} + +double LineEdit::GetPreferredContentHeight(double width) +{ + return GetTextSize().height; +} + +void LineEdit::SelectAll() +{ + SetTextSelection(0, (int)text.size()); + Update(); +} + +void LineEdit::SetReadOnly(bool enable) +{ + if (readonly != enable) + { + readonly = enable; + Update(); + } +} + +void LineEdit::SetAlignment(Alignment newalignment) +{ + if (alignment != newalignment) + { + alignment = newalignment; + Update(); + } +} + +void LineEdit::SetLowercase(bool enable) +{ + if (lowercase != enable) + { + lowercase = enable; + text = ToLower(text); + Update(); + } +} + +void LineEdit::SetUppercase(bool enable) +{ + if (uppercase != enable) + { + uppercase = enable; + text = ToUpper(text); + Update(); + } +} + +void LineEdit::SetPasswordMode(bool enable) +{ + if (password_mode != enable) + { + password_mode = enable; + Update(); + } +} + +void LineEdit::SetMaxLength(int length) +{ + if (max_length != length) + { + max_length = length; + if ((int)text.length() > length) + { + if (FuncBeforeEditChanged) + FuncBeforeEditChanged(); + text = text.substr(0, length); + if (FuncAfterEditChanged) + FuncAfterEditChanged(); + } + Update(); + } +} + +void LineEdit::SetText(const std::string& newtext) +{ + if (lowercase) + text = ToLower(newtext); + else if (uppercase) + text = ToUpper(newtext); + else + text = newtext; + + clip_start_offset = 0; + UpdateTextClipping(); + SetCursorPos((int)text.size()); + SetTextSelection(0, 0); + Update(); +} + +void LineEdit::SetTextInt(int number) +{ + text = std::to_string(number); + clip_start_offset = 0; + UpdateTextClipping(); + SetCursorPos((int)text.size()); + SetTextSelection(0, 0); + Update(); +} + +void LineEdit::SetTextFloat(float number, int num_decimal_places) +{ + text = ToFixed(number, num_decimal_places); + clip_start_offset = 0; + UpdateTextClipping(); + SetCursorPos((int)text.size()); + SetTextSelection(0, 0); + Update(); +} + +void LineEdit::SetSelection(int pos, int length) +{ + //don't call FuncSelectionChanged() here, because this + //member is for public usage + selection_start = pos; + selection_length = length; + Update(); +} + +void LineEdit::ClearSelection() +{ + //don't call FuncSelectionChanged() here, because this + //member is for public usage + SetSelection(0, 0); + Update(); +} + +void LineEdit::DeleteSelectedText() +{ + if (GetSelectionLength() == 0) + return; + + int sel_start = selection_start; + int sel_end = selection_start + selection_length; + if (sel_start > sel_end) + std::swap(sel_start, sel_end); + + text = text.substr(0, sel_start) + text.substr(sel_end, text.size()); + cursor_pos = sel_start; + SetTextSelection(0, 0); + int old_pos = GetCursorPos(); + SetCursorPos(0); + SetCursorPos(old_pos); +} + +void LineEdit::SetCursorPos(int pos) +{ + cursor_pos = pos; + UpdateTextClipping(); + Update(); +} + +void LineEdit::SetInputMask(const std::string& mask) +{ + input_mask = mask; +} + +void LineEdit::SetNumericMode(bool enable, bool decimals) +{ + numeric_mode = enable; + numeric_mode_decimals = decimals; +} + +void LineEdit::SetDecimalCharacter(const std::string& new_decimal_char) +{ + decimal_char = new_decimal_char; +} + +void LineEdit::SetSelectAllOnFocusGain(bool enable) +{ + select_all_on_focus_gain = enable; +} + +void LineEdit::OnMouseMove(const Point& pos) +{ + if (mouse_selecting && !ignore_mouse_events) + { + if (pos.x < 0.0 || pos.x >= GetWidth()) + { + if (pos.x < 0.0) + mouse_moves_left = true; + else + mouse_moves_left = false; + + if (!readonly) + scroll_timer->Start(50, true); + } + else + { + scroll_timer->Stop(); + cursor_pos = GetCharacterIndex(pos.x); + SetSelectionLength(cursor_pos - selection_start); + Update(); + } + } +} + +bool LineEdit::OnMouseDown(const Point& pos, int key) +{ + if (key == IK_LeftMouse) + { + if (HasFocus()) + { + CaptureMouse(); + mouse_selecting = true; + cursor_pos = GetCharacterIndex(pos.x); + SetTextSelection(cursor_pos, 0); + } + else + { + SetFocus(); + } + Update(); + } + return true; +} + +bool LineEdit::OnMouseDoubleclick(const Point& pos, int key) +{ + return true; +} + +bool LineEdit::OnMouseUp(const Point& pos, int key) +{ + if (mouse_selecting && key == IK_LeftMouse) + { + if (ignore_mouse_events) // This prevents text selection from changing from what was set when focus was gained. + { + ReleaseMouseCapture(); + ignore_mouse_events = false; + mouse_selecting = false; + } + else + { + scroll_timer->Stop(); + ReleaseMouseCapture(); + mouse_selecting = false; + int sel_end = GetCharacterIndex(pos.x); + SetSelectionLength(sel_end - selection_start); + cursor_pos = sel_end; + SetFocus(); + Update(); + } + } + return true; +} + +void LineEdit::OnKeyChar(std::string chars) +{ + if (FuncFilterKeyChar) + { + chars = FuncFilterKeyChar(chars); + if (chars.empty()) + return; + } + + if (!chars.empty() && !(chars[0] >= 0 && chars[0] < 32)) + { + if (FuncBeforeEditChanged) + FuncBeforeEditChanged(); + + DeleteSelectedText(); + if (input_mask.empty()) + { + if (numeric_mode) + { + // '-' can only be added once, and only as the first character. + if (chars == "-" && cursor_pos == 0 && text.find("-") == std::string::npos) + { + if (InsertText(cursor_pos, chars)) + cursor_pos += (int)chars.size(); + } + else if (numeric_mode_decimals && chars == decimal_char && cursor_pos > 0) // add decimal char + { + if (text.find(decimal_char) == std::string::npos) // allow only one decimal char. + { + if (InsertText(cursor_pos, chars)) + cursor_pos += (int)chars.size(); + } + } + else if (numeric_mode_characters.find(chars) != std::string::npos) // 0-9 + { + if (InsertText(cursor_pos, chars)) + cursor_pos += (int)chars.size(); + } + } + else + { + // not in any special mode, just insert the string. + if (InsertText(cursor_pos, chars)) + cursor_pos += (int)chars.size(); + } + } + else + { + if (InputMaskAcceptsInput(cursor_pos, chars)) + { + if (InsertText(cursor_pos, chars)) + cursor_pos += (int)chars.size(); + } + } + UpdateTextClipping(); + + if (FuncAfterEditChanged) + FuncAfterEditChanged(); + } +} + +void LineEdit::OnKeyDown(EInputKey key) +{ + if (FuncIgnoreKeyDown && FuncIgnoreKeyDown(key)) + return; + + if (key == IK_Enter) + { + if (FuncEnterPressed) + FuncEnterPressed(); + return; + } + + if (!readonly) // Do not flash cursor when readonly + { + cursor_blink_visible = true; + timer->Start(500); // don't blink cursor when moving or typing. + } + + if (key == IK_Enter || key == IK_Escape || key == IK_Tab) + { + // Do not consume these. + return; + } + else if (key == IK_A && GetKeyState(IK_Ctrl)) + { + // select all + SetTextSelection(0, (int)text.size()); + cursor_pos = selection_length; + UpdateTextClipping(); + Update(); + } + else if (key == IK_C && GetKeyState(IK_Ctrl)) + { + if (!password_mode) // Do not allow copying the password to clipboard + { + std::string str = GetSelection(); + SetClipboardText(str); + } + } + else if (readonly) + { + // Do not consume messages on read only component (only allow CTRL-A and CTRL-C) + return; + } + else if (key == IK_Left) + { + Move(-1, GetKeyState(IK_Ctrl), GetKeyState(IK_Shift)); + } + else if (key == IK_Right) + { + Move(1, GetKeyState(IK_Ctrl), GetKeyState(IK_Shift)); + } + else if (key == IK_Backspace) + { + Backspace(); + UpdateTextClipping(); + } + else if (key == IK_Delete) + { + Del(); + UpdateTextClipping(); + } + else if (key == IK_Home) + { + SetSelectionStart(cursor_pos); + cursor_pos = 0; + if (GetKeyState(IK_Shift)) + SetSelectionLength(-selection_start); + else + SetTextSelection(0, 0); + UpdateTextClipping(); + Update(); + } + else if (key == IK_End) + { + SetSelectionStart(cursor_pos); + cursor_pos = (int)text.size(); + if (GetKeyState(IK_Shift)) + SetSelectionLength((int)text.size() - selection_start); + else + SetTextSelection(0, 0); + UpdateTextClipping(); + Update(); + } + else if (key == IK_X && GetKeyState(IK_Ctrl)) + { + std::string str = GetSelection(); + DeleteSelectedText(); + SetClipboardText(str); + UpdateTextClipping(); + } + else if (key == IK_V && GetKeyState(IK_Ctrl)) + { + std::string str = GetClipboardText(); + std::string::const_iterator end_str = std::remove(str.begin(), str.end(), '\n'); + str.resize(end_str - str.begin()); + end_str = std::remove(str.begin(), str.end(), '\r'); + str.resize(end_str - str.begin()); + DeleteSelectedText(); + + if (input_mask.empty()) + { + if (numeric_mode) + { + std::string present_text = GetText(); + + bool present_minus = present_text.find('-') != std::string::npos; + bool str_minus = str.find('-') != std::string::npos; + + if (!present_minus || !str_minus) + { + if ((!present_minus && !str_minus) || //if no minus found + (str_minus && cursor_pos == 0 && str[0] == '-') || //if there's minus in text to paste + (present_minus && cursor_pos > 0)) //if there's minus in the beginning of control's text + { + if (numeric_mode_decimals) + { + std::string::size_type decimal_point_pos; + if ((decimal_point_pos = str.find_first_not_of(numeric_mode_characters, str[0] == '-' ? 1 : 0)) == std::string::npos) //no decimal char inside string to paste + { //we don't look at the position of decimal char inside of text in the textbox, if it's present + if (InsertText(cursor_pos, str)) + SetCursorPos(cursor_pos + (int)str.length()); + } + else + { + if (present_text.find(decimal_char) == std::string::npos && + str[decimal_point_pos] == decimal_char[0] && + str.find_first_not_of(numeric_mode_characters, decimal_point_pos + 1) == std::string::npos) //allow only one decimal char in the string to paste + { + if (InsertText(cursor_pos, str)) + SetCursorPos(cursor_pos + (int)str.length()); + } + } + } + else + { + if (str.find_first_not_of(numeric_mode_characters, str[0] == '-' ? 1 : 0) == std::string::npos) + { + if (InsertText(cursor_pos, str)) + SetCursorPos(cursor_pos + (int)str.length()); + } + } + } + } + } + else + { + if (InsertText(cursor_pos, str)) + SetCursorPos(cursor_pos + (int)str.length()); + } + } + else + { + if (InputMaskAcceptsInput(cursor_pos, str)) + { + if (InsertText(cursor_pos, str)) + SetCursorPos(cursor_pos + (int)str.length()); + } + } + + UpdateTextClipping(); + } + else if (GetKeyState(IK_Ctrl) && key == IK_Z) + { + if (!readonly) + { + std::string tmp = undo_info.undo_text; + undo_info.undo_text = GetText(); + SetText(tmp); + } + } + else if (key == IK_Shift) + { + if (selection_start == -1) + SetTextSelection(cursor_pos, 0); + } + + if (FuncAfterEditChanged) + FuncAfterEditChanged(); +} + +void LineEdit::OnKeyUp(EInputKey key) +{ +} + +void LineEdit::OnSetFocus() +{ + if (!readonly) + timer->Start(500); + if (select_all_on_focus_gain) + SelectAll(); + ignore_mouse_events = true; + cursor_pos = (int)text.length(); + + Update(); + + if (FuncFocusGained) + FuncFocusGained(); +} + +void LineEdit::OnLostFocus() +{ + timer->Stop(); + SetTextSelection(0, 0); + + Update(); + + if (FuncFocusLost) + FuncFocusLost(); +} + +void LineEdit::Move(int steps, bool ctrl, bool shift) +{ + if (shift && selection_length == 0) + SetSelectionStart(cursor_pos); + + // Jump over words if control is pressed. + if (ctrl) + { + if (steps < 0) + steps = FindPreviousBreakCharacter(cursor_pos - 1) - cursor_pos; + else + steps = FindNextBreakCharacter(cursor_pos + 1) - cursor_pos; + + cursor_pos += steps; + if (cursor_pos < 0) + cursor_pos = 0; + if (cursor_pos > (int)text.size()) + cursor_pos = (int)text.size(); + } + else + { + UTF8Reader utf8_reader(text.data(), text.length()); + utf8_reader.set_position(cursor_pos); + if (steps > 0) + { + for (int i = 0; i < steps; i++) + utf8_reader.next(); + } + else if (steps < 0) + { + for (int i = 0; i < -steps; i++) + utf8_reader.prev(); + } + + cursor_pos = (int)utf8_reader.position(); + } + + + // Clear the selection if a cursor key is pressed but shift isn't down. + if (shift) + SetSelectionLength(cursor_pos - selection_start); + else + SetTextSelection(-1, 0); + + UpdateTextClipping(); + + Update(); + + undo_info.first_text_insert = true; +} + +bool LineEdit::InsertText(int pos, const std::string& str) +{ + undo_info.first_erase = false; + if (undo_info.first_text_insert) + { + undo_info.undo_text = GetText(); + undo_info.first_text_insert = false; + } + + // checking if insert exceeds max length + if (UTF8Reader::utf8_length(text) + UTF8Reader::utf8_length(str) > max_length) + { + return false; + } + + if (lowercase) + text.insert(pos, ToLower(str)); + else if (uppercase) + text.insert(pos, ToUpper(str)); + else + text.insert(pos, str); + + UpdateTextClipping(); + Update(); + return true; +} + +void LineEdit::Backspace() +{ + if (undo_info.first_erase) + { + undo_info.first_erase = false; + undo_info.undo_text = GetText(); + } + + if (GetSelectionLength() != 0) + { + DeleteSelectedText(); + Update(); + } + else + { + if (cursor_pos > 0) + { + UTF8Reader utf8_reader(text.data(), text.length()); + utf8_reader.set_position(cursor_pos); + utf8_reader.prev(); + size_t length = utf8_reader.char_length(); + text.erase(cursor_pos - length, length); + cursor_pos -= (int)length; + Update(); + } + } + + int old_pos = GetCursorPos(); + SetCursorPos(0); + SetCursorPos(old_pos); +} + +void LineEdit::Del() +{ + if (undo_info.first_erase) + { + undo_info.first_erase = false; + undo_info.undo_text = GetText(); + } + + if (GetSelectionLength() != 0) + { + DeleteSelectedText(); + Update(); + } + else + { + if (cursor_pos < (int)text.size()) + { + UTF8Reader utf8_reader(text.data(), text.length()); + utf8_reader.set_position(cursor_pos); + size_t length = utf8_reader.char_length(); + text.erase(cursor_pos, length); + Update(); + } + } +} + +int LineEdit::GetCharacterIndex(double mouse_x) +{ + if (text.size() <= 1) + { + return (int)text.size(); + } + + Canvas* canvas = GetCanvas(); + UTF8Reader utf8_reader(text.data(), text.length()); + + int seek_start = clip_start_offset; + int seek_end = (int)text.size(); + int seek_center = (seek_start + seek_end) / 2; + + //fast search + while (true) + { + utf8_reader.set_position(seek_center); + utf8_reader.move_to_leadbyte(); + + seek_center = (int)utf8_reader.position(); + + Size text_size = GetVisualTextSize(canvas, clip_start_offset, seek_center - clip_start_offset); + + if (text_size.width > mouse_x) + seek_end = seek_center; + else + seek_start = seek_center; + + if (seek_end - seek_start < 7) + break; //go to accurate search + + seek_center = (seek_start + seek_end) / 2; + } + + utf8_reader.set_position(seek_start); + utf8_reader.move_to_leadbyte(); + + //accurate search + while (true) + { + seek_center = (int)utf8_reader.position(); + + Size text_size = GetVisualTextSize(canvas, clip_start_offset, seek_center - clip_start_offset); + if (text_size.width > mouse_x || utf8_reader.is_end()) + break; + + utf8_reader.next(); + } + + return seek_center; +} + +void LineEdit::UpdateTextClipping() +{ + Canvas* canvas = GetCanvas(); + + Size text_size = GetVisualTextSize(canvas, clip_start_offset, (int)text.size() - clip_start_offset); + + if (cursor_pos < clip_start_offset) + clip_start_offset = cursor_pos; + + Rect cursor_rect = GetCursorRect(); + + UTF8Reader utf8_reader(text.data(), text.length()); + double width = GetWidth(); + while (cursor_rect.x + cursor_rect.width > width) + { + utf8_reader.set_position(clip_start_offset); + utf8_reader.next(); + clip_start_offset = (int)utf8_reader.position(); + if (clip_start_offset == text.size()) + break; + cursor_rect = GetCursorRect(); + } + + // Get number of chars of current text fitting in the lineedit. + int search_upper = (int)text.size(); + int search_lower = clip_start_offset; + + while (true) + { + int midpoint = (search_lower + search_upper) / 2; + + utf8_reader.set_position(midpoint); + utf8_reader.move_to_leadbyte(); + if (midpoint != utf8_reader.position()) + utf8_reader.next(); + midpoint = (int)utf8_reader.position(); + + if (midpoint == search_lower || midpoint == search_upper) + break; + + Size midpoint_size = GetVisualTextSize(canvas, clip_start_offset, midpoint - clip_start_offset); + + if (width < midpoint_size.width) + search_upper = midpoint; + else + search_lower = midpoint; + } + clip_end_offset = search_upper; + + if (cursor_rect.x < 0.0) + { + clip_start_offset = cursor_pos; + } +} + +Rect LineEdit::GetCursorRect() +{ + Canvas* canvas = GetCanvas(); + + int substr_end = cursor_pos - clip_start_offset; + if (substr_end < 0) + substr_end = 0; + + std::string clipped_text = text.substr(clip_start_offset, substr_end); + + if (password_mode) + { + // If we are in password mode, we gonna return the right characters + clipped_text = CreatePassword(UTF8Reader::utf8_length(clipped_text)); + } + + Size text_size_before_cursor = canvas->measureText(clipped_text).size(); + + Rect cursor_rect; + cursor_rect.x = text_size_before_cursor.width; + cursor_rect.width = 1.0f; + + cursor_rect.y = vertical_text_align.top; + cursor_rect.height = vertical_text_align.bottom - vertical_text_align.top; + + return cursor_rect; +} + +Rect LineEdit::GetSelectionRect() +{ + Canvas* canvas = GetCanvas(); + + // text before selection: + + std::string txt_before = GetVisibleTextBeforeSelection(); + Size text_size_before_selection = canvas->measureText(txt_before).size(); + + // selection text: + std::string txt_selected = GetVisibleSelectedText(); + Size text_size_selection = canvas->measureText(txt_selected).size(); + + Rect selection_rect; + selection_rect.x = text_size_before_selection.width; + selection_rect.width = text_size_selection.width; + selection_rect.y = vertical_text_align.top; + selection_rect.height = vertical_text_align.bottom - vertical_text_align.top; + return selection_rect; +} + +int LineEdit::FindNextBreakCharacter(int search_start) +{ + if (search_start >= int(text.size()) - 1) + return (int)text.size(); + + size_t pos = text.find_first_of(break_characters, search_start); + if (pos == std::string::npos) + return (int)text.size(); + return (int)pos; +} + +int LineEdit::FindPreviousBreakCharacter(int search_start) +{ + if (search_start <= 0) + return 0; + size_t pos = text.find_last_of(break_characters, search_start); + if (pos == std::string::npos) + return 0; + return (int)pos; +} + +void LineEdit::OnTimerExpired() +{ + if (!IsVisible()) + { + timer->Stop(); + return; + } + + if (cursor_blink_visible) + timer->Start(500); + else + timer->Start(500); + + cursor_blink_visible = !cursor_blink_visible; + Update(); +} + +void LineEdit::OnGeometryChanged() +{ + Canvas* canvas = GetCanvas(); + + vertical_text_align = canvas->verticalTextAlign(); + + clip_start_offset = 0; + cursor_pos = 0; + UpdateTextClipping(); +} + +std::string LineEdit::GetVisibleTextBeforeSelection() +{ + std::string ret; + int sel_start = std::min(selection_start, selection_start + selection_length); + int start = std::min(sel_start, clip_start_offset); + + if (start < clip_start_offset) + return ret; + + int end = std::min(sel_start, clip_end_offset); + + ret = text.substr(start, end - start); + + // If we are in password mode, we gonna return the right characters + if (password_mode) + ret = CreatePassword(UTF8Reader::utf8_length(ret)); + + return ret; +} + +std::string LineEdit::GetVisibleSelectedText() +{ + std::string ret; + + if (selection_length == 0) + return ret; + + int sel_start = std::min(selection_start, selection_start + selection_length); + int sel_end = std::max(selection_start, selection_start + selection_length); + int end = std::min(clip_end_offset, sel_end); + int start = std::max(clip_start_offset, sel_start); + + if (start > end) + return ret; + + if (start == end) + return ret; + + ret = text.substr(start, end - start); + + // If we are in password mode, we gonna return the right characters + if (password_mode) + ret = CreatePassword(UTF8Reader::utf8_length(ret)); + + return ret; +} + +void LineEdit::SetSelectionStart(int start) +{ + if (FuncSelectionChanged && selection_length && selection_start != start) + FuncSelectionChanged(); + + selection_start = start; +} + +void LineEdit::SetSelectionLength(int length) +{ + if (FuncSelectionChanged && selection_length != length) + FuncSelectionChanged(); + + selection_length = length; +} + +void LineEdit::SetTextSelection(int start, int length) +{ + if (FuncSelectionChanged && (selection_length != length || (selection_length && selection_start != start))) + FuncSelectionChanged(); + + selection_start = start; + selection_length = length; +} + +std::string LineEdit::GetVisibleTextAfterSelection() +{ + // returns the whole visible string if there is no selection. + std::string ret; + + int sel_end = std::max(selection_start, selection_start + selection_length); + int start = std::max(clip_start_offset, sel_end); + + int end = clip_end_offset; + if (start > end) + return ret; + + if (clip_end_offset == sel_end) + return ret; + + if (sel_end <= 0) + return ret; + else + { + ret = text.substr(start, end - start); + // If we are in password mode, we gonna return the right characters + if (password_mode) + ret = CreatePassword(UTF8Reader::utf8_length(ret)); + + return ret; + } +} + +void LineEdit::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + Colorf bordercolor = Colorf::fromRgba8(100, 100, 100); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, 1.0), bordercolor); + canvas->fillRect(Rect::xywh(0.0, h - 1.0, w, 1.0), bordercolor); + canvas->fillRect(Rect::xywh(0.0, 0.0, 1.0, h - 0.0), bordercolor); + canvas->fillRect(Rect::xywh(w - 1.0, 0.0, 1.0, h - 0.0), bordercolor); +} + +void LineEdit::OnPaint(Canvas* canvas) +{ + std::string txt_before = GetVisibleTextBeforeSelection(); + std::string txt_selected = GetVisibleSelectedText(); + std::string txt_after = GetVisibleTextAfterSelection(); + + if (txt_before.empty() && txt_selected.empty() && txt_after.empty()) + { + txt_after = text.substr(clip_start_offset, clip_end_offset - clip_start_offset); + + // If we are in password mode, we gonna return the right characters + if (password_mode) + txt_after = CreatePassword(UTF8Reader::utf8_length(txt_after)); + } + + Size size_before = canvas->measureText(txt_before).size(); + Size size_selected = canvas->measureText(txt_selected).size(); + + if (!txt_selected.empty()) + { + // Draw selection box. + Rect selection_rect = GetSelectionRect(); + canvas->fillRect(selection_rect, HasFocus() ? Colorf::fromRgba8(100, 100, 100) : Colorf::fromRgba8(68, 68, 68)); + } + + // Draw text before selection + if (!txt_before.empty()) + { + canvas->drawText(Point(0.0, canvas->verticalTextAlign().baseline), Colorf::fromRgba8(255, 255, 255), txt_before); + } + if (!txt_selected.empty()) + { + canvas->drawText(Point(size_before.width, canvas->verticalTextAlign().baseline), Colorf::fromRgba8(255, 255, 255), txt_selected); + } + if (!txt_after.empty()) + { + canvas->drawText(Point(size_before.width + size_selected.width, canvas->verticalTextAlign().baseline), Colorf::fromRgba8(255, 255, 255), txt_after); + } + + // draw cursor + if (HasFocus()) + { + if (cursor_blink_visible) + { + Rect cursor_rect = GetCursorRect(); + canvas->fillRect(cursor_rect, Colorf::fromRgba8(255, 255, 255)); + } + } +} + +void LineEdit::OnScrollTimerExpired() +{ + if (mouse_moves_left) + Move(-1, false, false); + else + Move(1, false, false); +} + +void LineEdit::OnEnableChanged() +{ + bool enabled = IsEnabled(); + + if (!enabled) + { + cursor_blink_visible = false; + timer->Stop(); + } + Update(); +} + +bool LineEdit::InputMaskAcceptsInput(int cursor_pos, const std::string& str) +{ + return str.find_first_not_of(input_mask) == std::string::npos; +} + +std::string LineEdit::CreatePassword(std::string::size_type num_letters) const +{ + return std::string(num_letters, '*'); +} + +Size LineEdit::GetVisualTextSize(Canvas* canvas, int pos, int npos) const +{ + return canvas->measureText(password_mode ? CreatePassword(UTF8Reader::utf8_length(text.substr(pos, npos))) : text.substr(pos, npos)).size(); +} + +Size LineEdit::GetVisualTextSize(Canvas* canvas) const +{ + return canvas->measureText(password_mode ? CreatePassword(UTF8Reader::utf8_length(text)) : text).size(); +} + +std::string LineEdit::ToFixed(float number, int num_decimal_places) +{ + for (int i = 0; i < num_decimal_places; i++) + number *= 10.0f; + std::string val = std::to_string((int)std::round(number)); + if ((int)val.size() < num_decimal_places) + val.resize(num_decimal_places + 1, 0); + return val.substr(0, val.size() - num_decimal_places) + "." + val.substr(val.size() - num_decimal_places); +} + +std::string LineEdit::ToLower(const std::string& text) +{ + return text; +} + +std::string LineEdit::ToUpper(const std::string& text) +{ + return text; +} + +const std::string LineEdit::break_characters = " ::;,.-"; +const std::string LineEdit::numeric_mode_characters = "0123456789"; diff --git a/libraries/ZWidget/src/widgets/listview/listview.cpp b/libraries/ZWidget/src/widgets/listview/listview.cpp new file mode 100644 index 00000000000..717f9582729 --- /dev/null +++ b/libraries/ZWidget/src/widgets/listview/listview.cpp @@ -0,0 +1,159 @@ + +#include "widgets/listview/listview.h" +#include "widgets/scrollbar/scrollbar.h" + +ListView::ListView(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(10.0, 10.0, 3.0, 10.0); + + scrollbar = new Scrollbar(this); + scrollbar->FuncScroll = [=]() { OnScrollbarScroll(); }; +} + +void ListView::AddItem(const std::string& text) +{ + items.push_back(text); + Update(); +} + +void ListView::Activate() +{ + if (OnActivated) + OnActivated(); +} + +void ListView::SetSelectedItem(int index) +{ + if (selectedItem != index && index >= 0 && index < items.size()) + { + selectedItem = index; + if (OnChanged) OnChanged(selectedItem); + Update(); + } +} + +void ListView::ScrollToItem(int index) +{ + double itemHeight = 20.0; + double y = itemHeight * index; + if (y < scrollbar->GetPosition()) + { + scrollbar->SetPosition(y); + } + else if (y + itemHeight > scrollbar->GetPosition() + GetHeight()) + { + scrollbar->SetPosition(std::max(y + itemHeight - GetHeight(), 0.0)); + } +} + +void ListView::OnScrollbarScroll() +{ + Update(); +} + +void ListView::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + double sw = scrollbar->GetPreferredWidth(); + scrollbar->SetFrameGeometry(Rect::xywh(w - sw, 0.0, sw, h)); + scrollbar->SetRanges(h, items.size() * 20.0); +} + +void ListView::OnPaint(Canvas* canvas) +{ + double y = -scrollbar->GetPosition(); + double x = 2.0; + double w = GetWidth() - scrollbar->GetPreferredWidth() - 2.0; + double h = 20.0; + + int index = 0; + for (const std::string& item : items) + { + double itemY = y; + if (itemY + h >= 0.0 && itemY < GetHeight()) + { + if (index == selectedItem) + { + canvas->fillRect(Rect::xywh(x - 2.0, itemY, w, h), Colorf::fromRgba8(100, 100, 100)); + } + canvas->drawText(Point(x, y + 15.0), Colorf::fromRgba8(255, 255, 255), item); + } + y += h; + index++; + } +} + +void ListView::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + Colorf bordercolor = Colorf::fromRgba8(100, 100, 100); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, 1.0), bordercolor); + canvas->fillRect(Rect::xywh(0.0, h - 1.0, w, 1.0), bordercolor); + canvas->fillRect(Rect::xywh(0.0, 0.0, 1.0, h - 0.0), bordercolor); + canvas->fillRect(Rect::xywh(w - 1.0, 0.0, 1.0, h - 0.0), bordercolor); +} + +bool ListView::OnMouseDown(const Point& pos, int key) +{ + SetFocus(); + + if (key == IK_LeftMouse) + { + int index = (int)((pos.y - 5.0 + scrollbar->GetPosition()) / 20.0); + if (index >= 0 && (size_t)index < items.size()) + { + SetSelectedItem(index); + ScrollToItem(selectedItem); + } + } + return true; +} + +bool ListView::OnMouseDoubleclick(const Point& pos, int key) +{ + if (key == IK_LeftMouse) + { + Activate(); + } + return true; +} + +bool ListView::OnMouseWheel(const Point& pos, EInputKey key) +{ + if (key == IK_MouseWheelUp) + { + scrollbar->SetPosition(std::max(scrollbar->GetPosition() - 20.0, 0.0)); + } + else if (key == IK_MouseWheelDown) + { + scrollbar->SetPosition(std::min(scrollbar->GetPosition() + 20.0, scrollbar->GetMax())); + } + return true; +} + +void ListView::OnKeyDown(EInputKey key) +{ + if (key == IK_Down) + { + if (selectedItem + 1 < (int)items.size()) + { + SetSelectedItem(selectedItem + 1); + } + ScrollToItem(selectedItem); + } + else if (key == IK_Up) + { + if (selectedItem > 0) + { + SetSelectedItem(selectedItem - 1); + } + ScrollToItem(selectedItem); + } + else if (key == IK_Enter) + { + Activate(); + } +} diff --git a/libraries/ZWidget/src/widgets/mainwindow/mainwindow.cpp b/libraries/ZWidget/src/widgets/mainwindow/mainwindow.cpp new file mode 100644 index 00000000000..7a98a2ce598 --- /dev/null +++ b/libraries/ZWidget/src/widgets/mainwindow/mainwindow.cpp @@ -0,0 +1,40 @@ + +#include "widgets/mainwindow/mainwindow.h" +#include "widgets/menubar/menubar.h" +#include "widgets/toolbar/toolbar.h" +#include "widgets/statusbar/statusbar.h" + +MainWindow::MainWindow() : Widget(nullptr, WidgetType::Window) +{ + MenubarWidget = new Menubar(this); + // ToolbarWidget = new Toolbar(this); + StatusbarWidget = new Statusbar(this); +} + +MainWindow::~MainWindow() +{ +} + +void MainWindow::SetCentralWidget(Widget* widget) +{ + if (CentralWidget != widget) + { + delete CentralWidget; + CentralWidget = widget; + if (CentralWidget) + CentralWidget->SetParent(this); + OnGeometryChanged(); + } +} + +void MainWindow::OnGeometryChanged() +{ + Size s = GetSize(); + + MenubarWidget->SetFrameGeometry(0.0, 0.0, s.width, 32.0); + // ToolbarWidget->SetFrameGeometry(0.0, 32.0, s.width, 36.0); + StatusbarWidget->SetFrameGeometry(0.0, s.height - 32.0, s.width, 32.0); + + if (CentralWidget) + CentralWidget->SetFrameGeometry(0.0, 32.0, s.width, s.height - 32.0 - 32.0); +} diff --git a/libraries/ZWidget/src/widgets/menubar/menubar.cpp b/libraries/ZWidget/src/widgets/menubar/menubar.cpp new file mode 100644 index 00000000000..8a66ce8f31c --- /dev/null +++ b/libraries/ZWidget/src/widgets/menubar/menubar.cpp @@ -0,0 +1,16 @@ + +#include "widgets/menubar/menubar.h" +#include "core/colorf.h" + +Menubar::Menubar(Widget* parent) : Widget(parent) +{ +} + +Menubar::~Menubar() +{ +} + +void Menubar::OnPaint(Canvas* canvas) +{ + canvas->drawText(Point(16.0, 21.0), Colorf::fromRgba8(0, 0, 0), "File Edit View Tools Window Help"); +} diff --git a/libraries/ZWidget/src/widgets/pushbutton/pushbutton.cpp b/libraries/ZWidget/src/widgets/pushbutton/pushbutton.cpp new file mode 100644 index 00000000000..d838fe4249a --- /dev/null +++ b/libraries/ZWidget/src/widgets/pushbutton/pushbutton.cpp @@ -0,0 +1,111 @@ + +#include "widgets/pushbutton/pushbutton.h" + +PushButton::PushButton(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(10.0, 5.0, 10.0, 5.0); +} + +void PushButton::SetText(const std::string& value) +{ + if (text != value) + { + text = value; + Update(); + } +} + +const std::string& PushButton::GetText() const +{ + return text; +} + +double PushButton::GetPreferredHeight() const +{ + return 30.0; +} + +void PushButton::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + Colorf bordercolor = Colorf::fromRgba8(100, 100, 100); + Colorf buttoncolor = Colorf::fromRgba8(68, 68, 68); + if (buttonDown) + buttoncolor = Colorf::fromRgba8(88, 88, 88); + else if (hot) + buttoncolor = Colorf::fromRgba8(78, 78, 78); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), buttoncolor); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, 1.0), bordercolor); + canvas->fillRect(Rect::xywh(0.0, h - 1.0, w, 1.0), bordercolor); + canvas->fillRect(Rect::xywh(0.0, 0.0, 1.0, h - 0.0), bordercolor); + canvas->fillRect(Rect::xywh(w - 1.0, 0.0, 1.0, h - 0.0), bordercolor); +} + +void PushButton::OnPaint(Canvas* canvas) +{ + Rect box = canvas->measureText(text); + canvas->drawText(Point((GetWidth() - box.width) * 0.5, GetHeight() - 5.0), Colorf::fromRgba8(255, 255, 255), text); +} + +void PushButton::OnMouseMove(const Point& pos) +{ + if (!hot) + { + hot = true; + Update(); + } +} + +bool PushButton::OnMouseDown(const Point& pos, int key) +{ + SetFocus(); + buttonDown = true; + Update(); + return true; +} + +bool PushButton::OnMouseUp(const Point& pos, int key) +{ + if (buttonDown) + { + buttonDown = false; + hot = false; + Repaint(); + Click(); + } + return true; +} + +void PushButton::OnMouseLeave() +{ + hot = false; + buttonDown = false; + Update(); +} + +void PushButton::OnKeyDown(EInputKey key) +{ + if (key == IK_Space || key == IK_Enter) + { + buttonDown = true; + Update(); + } +} + +void PushButton::OnKeyUp(EInputKey key) +{ + if (key == IK_Space || key == IK_Enter) + { + buttonDown = false; + hot = false; + Repaint(); + Click(); + } +} + +void PushButton::Click() +{ + if (OnClick) + OnClick(); +} diff --git a/libraries/ZWidget/src/widgets/scrollbar/scrollbar.cpp b/libraries/ZWidget/src/widgets/scrollbar/scrollbar.cpp new file mode 100644 index 00000000000..489a663438b --- /dev/null +++ b/libraries/ZWidget/src/widgets/scrollbar/scrollbar.cpp @@ -0,0 +1,408 @@ + +#include "widgets/scrollbar/scrollbar.h" +#include "core/colorf.h" +#include + +Scrollbar::Scrollbar(Widget* parent) : Widget(parent) +{ + UpdatePartPositions(); + + mouse_down_timer = new Timer(this); + mouse_down_timer->FuncExpired = [=]() { OnTimerExpired(); }; +} + +Scrollbar::~Scrollbar() +{ +} + +bool Scrollbar::IsVertical() const +{ + return vertical; +} + +bool Scrollbar::IsHorizontal() const +{ + return !vertical; +} + +double Scrollbar::GetMin() const +{ + return scroll_min; +} + +double Scrollbar::GetMax() const +{ + return scroll_max; +} + +double Scrollbar::GetLineStep() const +{ + return line_step; +} + +double Scrollbar::GetPageStep() const +{ + return page_step; +} + +double Scrollbar::GetPosition() const +{ + return position; +} + +void Scrollbar::SetVertical() +{ + vertical = true; + if (UpdatePartPositions()) + Update(); +} + +void Scrollbar::SetHorizontal() +{ + vertical = false; + if (UpdatePartPositions()) + Update(); +} + +void Scrollbar::SetMin(double new_scroll_min) +{ + SetRanges(new_scroll_min, scroll_max, line_step, page_step); +} + +void Scrollbar::SetMax(double new_scroll_max) +{ + SetRanges(scroll_min, new_scroll_max, line_step, page_step); +} + +void Scrollbar::SetLineStep(double step) +{ + SetRanges(scroll_min, scroll_max, step, page_step); +} + +void Scrollbar::SetPageStep(double step) +{ + SetRanges(scroll_min, scroll_max, line_step, step); +} + +void Scrollbar::SetRanges(double new_scroll_min, double new_scroll_max, double new_line_step, double new_page_step) +{ + if (new_scroll_min >= new_scroll_max || new_line_step <= 0.0 || new_page_step <= 0.0) + throw std::runtime_error("Scrollbar ranges out of bounds!"); + scroll_min = new_scroll_min; + scroll_max = new_scroll_max; + line_step = new_line_step; + page_step = new_page_step; + if (position >= scroll_max) + position = scroll_max - 1.0; + if (position < scroll_min) + position = scroll_min; + if (UpdatePartPositions()) + Update(); +} + +void Scrollbar::SetRanges(double view_size, double total_size) +{ + if (view_size <= 0.0 || total_size <= 0.0) + { + SetRanges(0.0, 1.0, 1.0, 1.0); + } + else + { + double scroll_max = std::max(1.0, total_size - view_size + 1.0); + double page_step = std::max(1.0, view_size); + SetRanges(0.0, scroll_max, 10, page_step); + } +} + +void Scrollbar::SetPosition(double pos) +{ + position = pos; + if (pos >= scroll_max) + position = scroll_max - 1.0; + if (pos < scroll_min) + position = scroll_min; + + if (UpdatePartPositions()) + Update(); +} + +void Scrollbar::OnMouseMove(const Point& pos) +{ + if (mouse_down_mode == mouse_down_thumb_drag) + { + double last_position = position; + + if (pos.x < -100.0 || pos.x > GetWidth() + 100.0 || pos.y < -100.0 || pos.y > GetHeight() + 100.0) + { + position = thumb_start_position; + } + else + { + double delta = vertical ? (pos.y - mouse_drag_start_pos.y) : (pos.x - mouse_drag_start_pos.x); + double position_pixels = thumb_start_pixel_position + delta; + + double track_height = 0; + if (vertical) + track_height = rect_track_decrement.height + rect_track_increment.height; + else + track_height = rect_track_decrement.width + rect_track_increment.width; + + if (track_height != 0.0) + position = scroll_min + position_pixels * (scroll_max - scroll_min) / track_height; + else + position = 0; + + if (position >= scroll_max) + position = scroll_max - 1; + if (position < scroll_min) + position = scroll_min; + + } + + if (position != last_position) + { + InvokeScrollEvent(&FuncScrollThumbTrack); + UpdatePartPositions(); + } + } + + Update(); +} + +bool Scrollbar::OnMouseDown(const Point& pos, int key) +{ + mouse_drag_start_pos = pos; + + if (rect_button_decrement.contains(pos)) + { + mouse_down_mode = mouse_down_button_decr; + FuncScrollOnMouseDown = &FuncScrollLineDecrement; + + double last_position = position; + + position -= line_step; + last_step_size = -line_step; + if (position >= scroll_max) + position = scroll_max - 1.0; + if (position < scroll_min) + position = scroll_min; + + if (last_position != position) + InvokeScrollEvent(&FuncScrollLineDecrement); + } + else if (rect_button_increment.contains(pos)) + { + mouse_down_mode = mouse_down_button_incr; + FuncScrollOnMouseDown = &FuncScrollLineIncrement; + + double last_position = position; + + position += line_step; + last_step_size = line_step; + if (position >= scroll_max) + position = scroll_max - 1.0; + if (position < scroll_min) + position = scroll_min; + + if (last_position != position) + InvokeScrollEvent(&FuncScrollLineIncrement); + } + else if (rect_thumb.contains(pos)) + { + mouse_down_mode = mouse_down_thumb_drag; + thumb_start_position = position; + thumb_start_pixel_position = vertical ? (rect_thumb.y - rect_track_decrement.y) : (rect_thumb.x - rect_track_decrement.x); + } + else if (rect_track_decrement.contains(pos)) + { + mouse_down_mode = mouse_down_track_decr; + FuncScrollOnMouseDown = &FuncScrollPageDecrement; + + double last_position = position; + + position -= page_step; + last_step_size = -page_step; + if (position >= scroll_max) + position = scroll_max - 1.0; + if (position < scroll_min) + position = scroll_min; + + if (last_position != position) + InvokeScrollEvent(&FuncScrollPageDecrement); + } + else if (rect_track_increment.contains(pos)) + { + mouse_down_mode = mouse_down_track_incr; + FuncScrollOnMouseDown = &FuncScrollPageIncrement; + + double last_position = position; + + position += page_step; + last_step_size = page_step; + if (position >= scroll_max) + position = scroll_max - 1.0; + if (position < scroll_min) + position = scroll_min; + + if (last_position != position) + InvokeScrollEvent(&FuncScrollPageIncrement); + } + + mouse_down_timer->Start(100, false); + + UpdatePartPositions(); + + Update(); + CaptureMouse(); + return true; +} + +bool Scrollbar::OnMouseUp(const Point& pos, int key) +{ + if (mouse_down_mode == mouse_down_thumb_drag) + { + if (FuncScrollThumbRelease) + FuncScrollThumbRelease(); + } + + mouse_down_mode = mouse_down_none; + mouse_down_timer->Stop(); + + Update(); + ReleaseMouseCapture(); + return true; +} + +void Scrollbar::OnMouseLeave() +{ + Update(); +} + +void Scrollbar::OnGeometryChanged() +{ + UpdatePartPositions(); +} + +void Scrollbar::OnPaint(Canvas* canvas) +{ + /* + part_button_decrement.render_box(canvas, rect_button_decrement); + part_track_decrement.render_box(canvas, rect_track_decrement); + part_thumb.render_box(canvas, rect_thumb); + part_thumb_gripper.render_box(canvas, rect_thumb); + part_track_increment.render_box(canvas, rect_track_increment); + part_button_increment.render_box(canvas, rect_button_increment); + */ + + canvas->fillRect(Rect::shrink(Rect::xywh(0.0, 0.0, GetWidth(), GetHeight()), 4.0, 0.0, 4.0, 0.0), Colorf::fromRgba8(33, 33, 33)); + canvas->fillRect(Rect::shrink(rect_thumb, 4.0, 0.0, 4.0, 0.0), Colorf::fromRgba8(58, 58, 58)); +} + +// Calculates positions of all parts. Returns true if thumb position was changed compared to previously, false otherwise. +bool Scrollbar::UpdatePartPositions() +{ + double decr_height = showbuttons ? 16.0 : 0.0; + double incr_height = showbuttons ? 16.0 : 0.0; + + double total_height = vertical ? GetHeight() : GetWidth(); + double track_height = std::max(0.0, total_height - decr_height - incr_height); + double thumb_height = CalculateThumbSize(track_height); + + double thumb_offset = decr_height + CalculateThumbPosition(thumb_height, track_height); + + Rect previous_rect_thumb = rect_thumb; + + rect_button_decrement = CreateRect(0.0, decr_height); + rect_track_decrement = CreateRect(decr_height, thumb_offset); + rect_thumb = CreateRect(thumb_offset, thumb_offset + thumb_height); + rect_track_increment = CreateRect(thumb_offset + thumb_height, decr_height + track_height); + rect_button_increment = CreateRect(decr_height + track_height, decr_height + track_height + incr_height); + + return (previous_rect_thumb != rect_thumb); +} + +double Scrollbar::CalculateThumbSize(double track_size) +{ + double minimum_thumb_size = 20.0; + double range = scroll_max - scroll_min; + double length = range + page_step - 1; + double thumb_size = page_step * track_size / length; + if (thumb_size < minimum_thumb_size) + thumb_size = minimum_thumb_size; + if (thumb_size > track_size) + thumb_size = track_size; + return thumb_size; +} + +double Scrollbar::CalculateThumbPosition(double thumb_size, double track_size) +{ + double relative_pos = position - scroll_min; + double range = scroll_max - scroll_min - 1; + if (range != 0) + { + double available_area = std::max(0.0, track_size - thumb_size); + return relative_pos * available_area / range; + } + else + { + return 0; + } +} + +Rect Scrollbar::CreateRect(double start, double end) +{ + if (vertical) + return Rect(0.0, start, GetWidth(), end - start); + else + return Rect(start, 0.0, end - start, GetHeight()); +} + +void Scrollbar::OnTimerExpired() +{ + if (mouse_down_mode == mouse_down_thumb_drag) + return; + + mouse_down_timer->Start(100, false); + + double last_position = position; + position += last_step_size; + if (position >= scroll_max) + position = scroll_max - 1; + + if (position < scroll_min) + position = scroll_min; + + if (position != last_position) + { + InvokeScrollEvent(FuncScrollOnMouseDown); + + if (UpdatePartPositions()) + Update(); + } +} + +void Scrollbar::OnEnableChanged() +{ + Update(); +} + +void Scrollbar::InvokeScrollEvent(std::function* event_ptr) +{ + if (position == scroll_max - 1) + { + if (FuncScrollMax) + FuncScrollMax(); + } + + if (position == scroll_min) + { + if (FuncScrollMin) + FuncScrollMin(); + } + + if (FuncScroll) + FuncScroll(); + + if (event_ptr && *event_ptr) + (*event_ptr)(); +} diff --git a/libraries/ZWidget/src/widgets/statusbar/statusbar.cpp b/libraries/ZWidget/src/widgets/statusbar/statusbar.cpp new file mode 100644 index 00000000000..fd914298c72 --- /dev/null +++ b/libraries/ZWidget/src/widgets/statusbar/statusbar.cpp @@ -0,0 +1,19 @@ + +#include "widgets/statusbar/statusbar.h" +#include "widgets/lineedit/lineedit.h" +#include "core/colorf.h" + +Statusbar::Statusbar(Widget* parent) : Widget(parent) +{ + CommandEdit = new LineEdit(this); + CommandEdit->SetFrameGeometry(Rect::xywh(90.0, 4.0, 400.0, 23.0)); +} + +Statusbar::~Statusbar() +{ +} + +void Statusbar::OnPaint(Canvas* canvas) +{ + canvas->drawText(Point(16.0, 21.0), Colorf::fromRgba8(0, 0, 0), "Command:"); +} diff --git a/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp new file mode 100644 index 00000000000..cbac877aafe --- /dev/null +++ b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp @@ -0,0 +1,358 @@ + +#include "widgets/tabwidget/tabwidget.h" +#include "widgets/textlabel/textlabel.h" +#include "widgets/imagebox/imagebox.h" +#include + +TabWidget::TabWidget(Widget* parent) : Widget(parent) +{ + Bar = new TabBar(this); + PageStack = new TabWidgetStack(this); + + Bar->OnCurrentChanged = [=]() { OnBarCurrentChanged(); }; +} + +int TabWidget::AddTab(Widget* page, const std::string& label) +{ + return AddTab(page, nullptr, label); +} + +int TabWidget::AddTab(Widget* page, const std::shared_ptr& icon, const std::string& label) +{ + int pageIndex = Bar->AddTab(label); + page->SetParent(PageStack); + page->SetVisible(false); + Pages.push_back(page); + if (Pages.size() == 1) + { + PageStack->SetCurrentWidget(page); + } + return pageIndex; +} + +void TabWidget::SetTabText(int index, const std::string& text) +{ + Bar->SetTabText(index, text); +} + +void TabWidget::SetTabText(Widget* page, const std::string& text) +{ + int index = GetPageIndex(page); + if (index != -1) + SetTabText(index, text); +} + +void TabWidget::SetTabIcon(int index, const std::shared_ptr& icon) +{ + Bar->SetTabIcon(index, icon); +} + +void TabWidget::SetTabIcon(Widget* page, const std::shared_ptr& icon) +{ + int index = GetPageIndex(page); + if (index != -1) + SetTabIcon(index, icon); +} + +int TabWidget::GetCurrentIndex() const +{ + return Bar->GetCurrentIndex(); +} + +Widget* TabWidget::GetCurrentWidget() const +{ + return Pages[Bar->GetCurrentIndex()]; +} + +void TabWidget::SetCurrentIndex(int pageIndex) +{ + if (Bar->GetCurrentIndex() != pageIndex) + { + Bar->SetCurrentIndex(pageIndex); + PageStack->SetCurrentWidget(Pages[pageIndex]); + } +} + +void TabWidget::SetCurrentWidget(Widget* pageWidget) +{ + int pageIndex = GetPageIndex(pageWidget); + if (pageIndex != -1) + SetCurrentIndex(pageIndex); +} + +int TabWidget::GetPageIndex(Widget* pageWidget) const +{ + for (size_t i = 0; i < Pages.size(); i++) + { + if (Pages[i] == pageWidget) + return i; + } + return -1; +} + +void TabWidget::OnBarCurrentChanged() +{ + int pageIndex = Bar->GetCurrentIndex(); + PageStack->SetCurrentWidget(Pages[pageIndex]); + if (OnCurrentChanged) + OnCurrentChanged(); +} + +void TabWidget::OnPaintFrame(Canvas* canvas) +{ +} + +void TabWidget::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + double barHeight = Bar->GetPreferredHeight(); + Bar->SetFrameGeometry(Rect::xywh(0.0, 0.0, w, barHeight)); + PageStack->SetFrameGeometry(Rect::xywh(0.0, barHeight, w, std::max(h - barHeight, 0.0))); +} + +///////////////////////////////////////////////////////////////////////////// + +TabBar::TabBar(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(20.0, 0.0, 20.0, 0.0); +} + +int TabBar::AddTab(const std::string& label) +{ + return AddTab(nullptr, label); +} + +int TabBar::AddTab(const std::shared_ptr& icon, const std::string& label) +{ + TabBarTab* tab = new TabBarTab(this); + tab->SetIcon(icon); + tab->SetText(label); + tab->OnClick = [=]() { OnTabClicked(tab); }; + int pageIndex = Tabs.size(); + Tabs.push_back(tab); + if (CurrentIndex == -1) + SetCurrentIndex(pageIndex); + OnGeometryChanged(); + return pageIndex; +} + +void TabBar::SetTabText(int index, const std::string& text) +{ + Tabs[index]->SetText(text); + OnGeometryChanged(); +} + +void TabBar::SetTabIcon(int index, const std::shared_ptr& icon) +{ + Tabs[index]->SetIcon(icon); + OnGeometryChanged(); +} + +int TabBar::GetCurrentIndex() const +{ + return CurrentIndex; +} + +void TabBar::SetCurrentIndex(int pageIndex) +{ + if (CurrentIndex != pageIndex) + { + if (CurrentIndex != -1) + Tabs[CurrentIndex]->SetCurrent(false); + CurrentIndex = pageIndex; + if (CurrentIndex != -1) + Tabs[CurrentIndex]->SetCurrent(true); + } +} + +void TabBar::OnTabClicked(TabBarTab* tab) +{ + int pageIndex = GetTabIndex(tab); + if (CurrentIndex != pageIndex) + { + SetCurrentIndex(pageIndex); + if (OnCurrentChanged) + OnCurrentChanged(); + } +} + +int TabBar::GetTabIndex(TabBarTab* tab) +{ + for (size_t i = 0; i < Tabs.size(); i++) + { + if (Tabs[i] == tab) + return i; + } + return -1; +} + +void TabBar::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); +} + +void TabBar::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + double x = 0.0; + for (TabBarTab* tab : Tabs) + { + double tabWidth = tab->GetNoncontentLeft() + tab->GetPreferredWidth() + tab->GetNoncontentRight(); + tab->SetFrameGeometry(Rect::xywh(x, 0.0, tabWidth, h)); + x += tabWidth; + } +} + +///////////////////////////////////////////////////////////////////////////// + +TabBarTab::TabBarTab(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(15.0, 0.0, 15.0, 0.0); +} + +void TabBarTab::SetText(const std::string& text) +{ + if (!text.empty()) + { + if (!Label) + { + Label = new TextLabel(this); + OnGeometryChanged(); + } + Label->SetText(text); + } + else + { + delete Label; + Label = nullptr; + OnGeometryChanged(); + } +} + +void TabBarTab::SetIcon(const std::shared_ptr& image) +{ + if (image) + { + if (!Icon) + { + Icon = new ImageBox(this); + OnGeometryChanged(); + } + Icon->SetImage(image); + } + else + { + delete Icon; + Icon = nullptr; + OnGeometryChanged(); + } +} + +void TabBarTab::SetCurrent(bool value) +{ + if (IsCurrent != value) + { + IsCurrent = value; + Update(); + } +} + +double TabBarTab::GetPreferredWidth() const +{ + double x = Icon ? 32.0 + 5.0 : 0.0; + if (Label) x += Label->GetPreferredWidth(); + return x; +} + +void TabBarTab::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + if (IsCurrent) + { + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(51, 51, 51)); + } + else if (hot) + { + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(45, 45, 45)); + } +} + +void TabBarTab::OnGeometryChanged() +{ + double x = 0.0; + double w = GetWidth(); + double h = GetHeight(); + if (Icon) + { + Icon->SetFrameGeometry(Rect::xywh(x, (h - 32.0) * 0.5, 32.0, 32.0)); + x = 32.0 + 5.0; + } + if (Label) + { + Label->SetFrameGeometry(Rect::xywh(x, (h - Label->GetPreferredHeight()) * 0.5, std::max(w - x, 0.0), Label->GetPreferredHeight())); + } +} + +void TabBarTab::OnMouseMove(const Point& pos) +{ + if (!hot) + { + hot = true; + Update(); + } +} + +bool TabBarTab::OnMouseDown(const Point& pos, int key) +{ + if (OnClick) + OnClick(); + return true; +} + +bool TabBarTab::OnMouseUp(const Point& pos, int key) +{ + return true; +} + +void TabBarTab::OnMouseLeave() +{ + hot = false; + Update(); +} + +///////////////////////////////////////////////////////////////////////////// + +TabWidgetStack::TabWidgetStack(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(20.0, 5.0, 20.0, 5.0); +} + +void TabWidgetStack::SetCurrentWidget(Widget* widget) +{ + if (widget != CurrentWidget) + { + if (CurrentWidget) + CurrentWidget->SetVisible(false); + CurrentWidget = widget; + if (CurrentWidget) + { + CurrentWidget->SetVisible(true); + OnGeometryChanged(); + } + } +} + +void TabWidgetStack::OnPaintFrame(Canvas* canvas) +{ +} + +void TabWidgetStack::OnGeometryChanged() +{ + if (CurrentWidget) + CurrentWidget->SetFrameGeometry(Rect::xywh(0.0, 0.0, GetWidth(), GetHeight())); +} diff --git a/libraries/ZWidget/src/widgets/textedit/textedit.cpp b/libraries/ZWidget/src/widgets/textedit/textedit.cpp new file mode 100644 index 00000000000..dca840a1bfe --- /dev/null +++ b/libraries/ZWidget/src/widgets/textedit/textedit.cpp @@ -0,0 +1,1050 @@ + +#include "widgets/textedit/textedit.h" +#include "widgets/scrollbar/scrollbar.h" +#include "core/utf8reader.h" +#include "core/colorf.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4267) // warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data +#endif + +TextEdit::TextEdit(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(8.0, 8.0, 8.0, 8.0); + + timer = new Timer(this); + timer->FuncExpired = [=]() { OnTimerExpired(); }; + + scroll_timer = new Timer(this); + scroll_timer->FuncExpired = [=]() { OnScrollTimerExpired(); }; + + SetCursor(StandardCursor::ibeam); + + CreateComponents(); +} + +TextEdit::~TextEdit() +{ +} + +bool TextEdit::IsReadOnly() const +{ + return readonly; +} + +bool TextEdit::IsLowercase() const +{ + return lowercase; +} + +bool TextEdit::IsUppercase() const +{ + return uppercase; +} + +int TextEdit::GetMaxLength() const +{ + return max_length; +} + +std::string TextEdit::GetLineText(int line) const +{ + if (line >= 0 && line < (int)lines.size()) + return lines[line].text; + else + return std::string(); +} + +std::string TextEdit::GetText() const +{ + std::string::size_type size = 0; + for (size_t i = 0; i < lines.size(); i++) + size += lines[i].text.size(); + size += lines.size() - 1; + + std::string text; + text.reserve(size); + + for (size_t i = 0; i < lines.size(); i++) + { + if (i > 0) + text.push_back('\n'); + text += lines[i].text; + } + + return text; +} + +int TextEdit::GetLineCount() const +{ + return (int)lines.size(); +} + +std::string TextEdit::GetSelection() const +{ + std::string::size_type offset = ToOffset(selection_start); + int start = (int)std::min(offset, offset + selection_length); + return GetText().substr(start, abs(selection_length)); +} + +int TextEdit::GetSelectionStart() const +{ + return (int)ToOffset(selection_start); +} + +int TextEdit::GetSelectionLength() const +{ + return selection_length; +} + +int TextEdit::GetCursorPos() const +{ + return (int)ToOffset(cursor_pos); +} + +int TextEdit::GetCursorLineNumber() const +{ + return cursor_pos.y; +} + +void TextEdit::SelectAll() +{ + std::string::size_type size = 0; + for (size_t i = 0; i < lines.size(); i++) + size += lines[i].text.size(); + size += lines.size() - 1; + SetSelection(0, (int)size); +} + +void TextEdit::SetReadOnly(bool enable) +{ + if (readonly != enable) + { + readonly = enable; + Update(); + } +} + +void TextEdit::SetLowercase(bool enable) +{ + if (lowercase != enable) + { + lowercase = enable; + Update(); + } +} + +void TextEdit::SetUppercase(bool enable) +{ + if (uppercase != enable) + { + uppercase = enable; + Update(); + } +} + +void TextEdit::SetMaxLength(int length) +{ + if (max_length != length) + { + max_length = length; + + std::string::size_type size = 0; + for (size_t i = 0; i < lines.size(); i++) + size += lines[i].text.size(); + size += lines.size() - 1; + + if ((int)size > length) + { + if (FuncBeforeEditChanged) + FuncBeforeEditChanged(); + SetSelection(length, (int)size - length); + DeleteSelectedText(); + if (FuncAfterEditChanged) + FuncAfterEditChanged(); + } + Update(); + } +} + +void TextEdit::SetText(const std::string& text) +{ + lines.clear(); + std::string::size_type start = 0; + std::string::size_type end = text.find('\n'); + while (end != std::string::npos) + { + TextEdit::Line line; + line.text = text.substr(start, end - start); + lines.push_back(line); + start = end + 1; + end = text.find('\n', start); + } + TextEdit::Line line; + line.text = text.substr(start); + lines.push_back(line); + + clip_start_offset = 0; + SetCursorPos(0); + ClearSelection(); + Update(); +} + +void TextEdit::AddText(const std::string& text) +{ + std::string::size_type start = 0; + std::string::size_type end = text.find('\n'); + while (end != std::string::npos) + { + TextEdit::Line line; + line.text = text.substr(start, end - start); + lines.push_back(line); + start = end + 1; + end = text.find('\n', start); + } + TextEdit::Line line; + line.text = text.substr(start); + lines.push_back(line); + + // clip_start_offset = 0; + // SetCursorPos(0); + ClearSelection(); + Update(); +} + +void TextEdit::SetSelection(int pos, int length) +{ + selection_start = ivec2(pos, 0); + selection_length = length; + Update(); +} + +void TextEdit::ClearSelection() +{ + SetSelection(0, 0); + Update(); +} + +void TextEdit::DeleteSelectedText() +{ + if (GetSelectionLength() == 0) + return; + + std::string::size_type offset = ToOffset(selection_start); + int start = (int)std::min(offset, offset + selection_length); + int length = std::abs(selection_length); + + ClearSelection(); + std::string text = GetText(); + SetText(text.substr(0, start) + text.substr(start + length)); + SetCursorPos(start); +} + +void TextEdit::SetCursorPos(int pos) +{ + cursor_pos = FromOffset(pos); + Update(); +} + +void TextEdit::SetInputMask(const std::string& mask) +{ + input_mask = mask; +} + +void TextEdit::SetCursorDrawingEnabled(bool enable) +{ + if (!readonly) + timer->Start(500); +} + +void TextEdit::SetSelectAllOnFocusGain(bool enable) +{ + select_all_on_focus_gain = enable; +} + +void TextEdit::OnMouseMove(const Point& pos) +{ + if (mouse_selecting && !ignore_mouse_events) + { + if (pos.x < 0.0 || pos.x > GetWidth()) + { + if (pos.x < 0.0) + mouse_moves_left = true; + else + mouse_moves_left = false; + + if (!readonly) + scroll_timer->Start(50, true); + } + else + { + scroll_timer->Stop(); + cursor_pos = GetCharacterIndex(pos); + selection_length = ToOffset(cursor_pos) - ToOffset(selection_start); + Update(); + } + } +} + +bool TextEdit::OnMouseDown(const Point& pos, int key) +{ + if (key == IK_LeftMouse) + { + CaptureMouse(); + mouse_selecting = true; + cursor_pos = GetCharacterIndex(pos); + selection_start = cursor_pos; + selection_length = 0; + + Update(); + } + return true; +} + +bool TextEdit::OnMouseDoubleclick(const Point& pos, int key) +{ + return true; +} + +bool TextEdit::OnMouseUp(const Point& pos, int key) +{ + if (mouse_selecting && key == IK_LeftMouse) + { + if (ignore_mouse_events) // This prevents text selection from changing from what was set when focus was gained. + { + ReleaseMouseCapture(); + ignore_mouse_events = false; + mouse_selecting = false; + } + else + { + scroll_timer->Stop(); + ReleaseMouseCapture(); + mouse_selecting = false; + ivec2 sel_end = GetCharacterIndex(pos); + selection_length = ToOffset(sel_end) - ToOffset(selection_start); + cursor_pos = sel_end; + SetFocus(); + Update(); + } + } + return true; +} + +void TextEdit::OnKeyChar(std::string chars) +{ + if (!chars.empty() && !(chars[0] >= 0 && chars[0] < 32)) + { + if (FuncBeforeEditChanged) + FuncBeforeEditChanged(); + + DeleteSelectedText(); + ClearSelection(); + if (input_mask.empty()) + { + // not in any special mode, just insert the string. + InsertText(cursor_pos, chars); + cursor_pos.x += chars.size(); + } + else + { + if (InputMaskAcceptsInput(cursor_pos, chars)) + { + InsertText(cursor_pos, chars); + cursor_pos.x += chars.size(); + } + } + + if (FuncAfterEditChanged) + FuncAfterEditChanged(); + } +} + +void TextEdit::OnKeyDown(EInputKey key) +{ + if (!readonly && key == IK_Enter) + { + if (FuncEnterPressed) + { + FuncEnterPressed(); + } + else + { + ClearSelection(); + InsertText(cursor_pos, "\n"); + SetCursorPos(GetCursorPos() + 1); + } + return; + } + + if (!readonly) // Do not flash cursor when readonly + { + cursor_blink_visible = true; + timer->Start(500); // don't blink cursor when moving or typing. + } + + if (key == IK_Enter || key == IK_Escape || key == IK_Tab) + { + // Do not consume these. + return; + } + else if (key == IK_A && GetKeyState(IK_Ctrl)) + { + // select all + SelectAll(); + } + else if (key == IK_C && GetKeyState(IK_Ctrl)) + { + std::string str = GetSelection(); + SetClipboardText(str); + } + else if (readonly) + { + // Do not consume messages on read only component (only allow CTRL-A and CTRL-C) + return; + } + else if (key == IK_Up) + { + if (GetKeyState(IK_Shift) && selection_length == 0) + selection_start = cursor_pos; + + if (cursor_pos.y > 0) + { + cursor_pos.y--; + cursor_pos.x = std::min(lines[cursor_pos.y].text.size(), (size_t)cursor_pos.x); + } + + if (GetKeyState(IK_Shift)) + { + selection_length = ToOffset(cursor_pos) - ToOffset(selection_start); + } + else + { + // Clear the selection if a cursor key is pressed but shift isn't down. + selection_start = ivec2(0, 0); + selection_length = 0; + } + MoveVerticalScroll(); + Update(); + undo_info.first_text_insert = true; + } + else if (key == IK_Down) + { + if (GetKeyState(IK_Shift) && selection_length == 0) + selection_start = cursor_pos; + + if (cursor_pos.y < lines.size() - 1) + { + cursor_pos.y++; + cursor_pos.x = std::min(lines[cursor_pos.y].text.size(), (size_t)cursor_pos.x); + } + + if (GetKeyState(IK_Shift)) + { + selection_length = ToOffset(cursor_pos) - ToOffset(selection_start); + } + else + { + // Clear the selection if a cursor key is pressed but shift isn't down. + selection_start = ivec2(0, 0); + selection_length = 0; + } + MoveVerticalScroll(); + + Update(); + undo_info.first_text_insert = true; + } + else if (key == IK_Left) + { + Move(-1, GetKeyState(IK_Shift), GetKeyState(IK_Ctrl)); + } + else if (key == IK_Right) + { + Move(1, GetKeyState(IK_Shift), GetKeyState(IK_Ctrl)); + } + else if (key == IK_Backspace) + { + Backspace(); + } + else if (key == IK_Delete) + { + Del(); + } + else if (key == IK_Home) + { + if (GetKeyState(IK_Ctrl)) + cursor_pos = ivec2(0, 0); + else + cursor_pos.x = 0; + if (GetKeyState(IK_Shift)) + selection_length = ToOffset(cursor_pos) - ToOffset(selection_start); + else + ClearSelection(); + Update(); + MoveVerticalScroll(); + } + else if (key == IK_End) + { + if (GetKeyState(IK_Ctrl)) + cursor_pos = ivec2(lines.back().text.length(), lines.size() - 1); + else + cursor_pos.x = lines[cursor_pos.y].text.size(); + + if (GetKeyState(IK_Shift)) + selection_length = ToOffset(cursor_pos) - ToOffset(selection_start); + else + ClearSelection(); + Update(); + } + else if (key == IK_X && GetKeyState(IK_Ctrl)) + { + std::string str = GetSelection(); + DeleteSelectedText(); + SetClipboardText(str); + } + else if (key == IK_V && GetKeyState(IK_Ctrl)) + { + std::string str = GetClipboardText(); + std::string::const_iterator end_str = std::remove(str.begin(), str.end(), '\r'); + str.resize(end_str - str.begin()); + DeleteSelectedText(); + + if (input_mask.empty()) + { + InsertText(cursor_pos, str); + SetCursorPos(GetCursorPos() + str.length()); + } + else + { + if (InputMaskAcceptsInput(cursor_pos, str)) + { + InsertText(cursor_pos, str); + SetCursorPos(GetCursorPos() + str.length()); + } + } + MoveVerticalScroll(); + } + else if (GetKeyState(IK_Ctrl) && key == IK_Z) + { + if (!readonly) + { + std::string tmp = undo_info.undo_text; + undo_info.undo_text = GetText(); + SetText(tmp); + } + } + else if (key == IK_Shift) + { + if (selection_length == 0) + selection_start = cursor_pos; + } + + if (FuncAfterEditChanged) + FuncAfterEditChanged(); +} + +void TextEdit::OnKeyUp(EInputKey key) +{ +} + +void TextEdit::OnSetFocus() +{ + if (!readonly) + timer->Start(500); + if (select_all_on_focus_gain) + SelectAll(); + ignore_mouse_events = true; + cursor_pos.y = lines.size() - 1; + cursor_pos.x = lines[cursor_pos.y].text.length(); + + Update(); + + if (FuncFocusGained) + FuncFocusGained(); +} + +void TextEdit::OnLostFocus() +{ + timer->Stop(); + ClearSelection(); + + Update(); + + if (FuncFocusLost) + FuncFocusLost(); +} + +void TextEdit::CreateComponents() +{ + vert_scrollbar = new Scrollbar(this); + vert_scrollbar->FuncScroll = [=]() { OnVerticalScroll(); }; + vert_scrollbar->SetVisible(false); + vert_scrollbar->SetVertical(); +} + +void TextEdit::OnVerticalScroll() +{ +} + +void TextEdit::UpdateVerticalScroll() +{ + Rect rect( + GetWidth() - 16.0/*vert_scrollbar->GetWidth()*/, + 0.0, + 16.0/*vert_scrollbar->GetWidth()*/, + GetHeight()); + + vert_scrollbar->SetFrameGeometry(rect); + + double total_height = GetTotalLineHeight(); + double height_per_line = std::max(1.0, total_height / std::max(1.0, (double)lines.size())); + bool visible = total_height > GetHeight(); + vert_scrollbar->SetRanges((int)std::round(GetHeight() / height_per_line), (int)std::round(total_height / height_per_line)); + vert_scrollbar->SetLineStep(1); + vert_scrollbar->SetVisible(visible); + + if (visible == false) + vert_scrollbar->SetPosition(0); +} + +void TextEdit::MoveVerticalScroll() +{ + double total_height = GetTotalLineHeight(); + double height_per_line = std::max(1.0, total_height / std::max((size_t)1, lines.size())); + int lines_fit = (int)(GetHeight() / height_per_line); + if (cursor_pos.y >= vert_scrollbar->GetPosition() + lines_fit) + { + vert_scrollbar->SetPosition(cursor_pos.y - lines_fit + 1); + } + else if (cursor_pos.y < vert_scrollbar->GetPosition()) + { + vert_scrollbar->SetPosition(cursor_pos.y); + } +} + +double TextEdit::GetTotalLineHeight() +{ + double total = 0; + for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); iter++) + { + total += iter->layout.GetSize().height; + } + return total; +} + +void TextEdit::Move(int steps, bool shift, bool ctrl) +{ + if (shift && selection_length == 0) + selection_start = cursor_pos; + + // Jump over words if control is pressed. + if (ctrl) + { + if (steps < 0 && cursor_pos.x == 0 && cursor_pos.y > 0) + { + cursor_pos.x = (int)lines[cursor_pos.y - 1].text.size(); + cursor_pos.y--; + } + else if (steps > 0 && cursor_pos.x == (int)lines[cursor_pos.y].text.size() && cursor_pos.y + 1 < (int)lines.size()) + { + cursor_pos.x = 0; + cursor_pos.y++; + } + + ivec2 new_pos; + if (steps < 0) + new_pos = FindPreviousBreakCharacter(cursor_pos); + else + new_pos = FindNextBreakCharacter(cursor_pos); + + cursor_pos = new_pos; + } + else if (steps < 0 && cursor_pos.x == 0 && cursor_pos.y > 0) + { + cursor_pos.x = (int)lines[cursor_pos.y - 1].text.size(); + cursor_pos.y--; + } + else if (steps > 0 && cursor_pos.x == (int)lines[cursor_pos.y].text.size() && cursor_pos.y + 1 < (int)lines.size()) + { + cursor_pos.x = 0; + cursor_pos.y++; + } + else + { + UTF8Reader utf8_reader(lines[cursor_pos.y].text.data(), lines[cursor_pos.y].text.length()); + utf8_reader.set_position(cursor_pos.x); + if (steps > 0) + { + for (int i = 0; i < steps; i++) + utf8_reader.next(); + } + else if (steps < 0) + { + for (int i = 0; i < -steps; i++) + utf8_reader.prev(); + } + + cursor_pos.x = (int)utf8_reader.position(); + } + + if (shift) + { + selection_length = (int)ToOffset(cursor_pos) - (int)ToOffset(selection_start); + } + else + { + // Clear the selection if a cursor key is pressed but shift isn't down. + selection_start = ivec2(0, 0); + selection_length = 0; + } + + + MoveVerticalScroll(); + Update(); + + undo_info.first_text_insert = true; +} + +std::string TextEdit::break_characters = " ::;,.-"; + +TextEdit::ivec2 TextEdit::FindNextBreakCharacter(ivec2 search_start) +{ + search_start.x++; + if (search_start.x >= int(lines[search_start.y].text.size()) - 1) + return ivec2(lines[search_start.y].text.size(), search_start.y); + + int pos = lines[search_start.y].text.find_first_of(break_characters, search_start.x); + if (pos == std::string::npos) + return ivec2(lines[search_start.y].text.size(), search_start.y); + return ivec2(pos, search_start.y); +} + +TextEdit::ivec2 TextEdit::FindPreviousBreakCharacter(ivec2 search_start) +{ + search_start.x--; + if (search_start.x <= 0) + return ivec2(0, search_start.y); + int pos = lines[search_start.y].text.find_last_of(break_characters, search_start.x); + if (pos == std::string::npos) + return ivec2(0, search_start.y); + return ivec2(pos, search_start.y); +} + +void TextEdit::InsertText(ivec2 pos, const std::string& str) +{ + undo_info.first_erase = false; + if (undo_info.first_text_insert) + { + undo_info.undo_text = GetText(); + undo_info.first_text_insert = false; + } + + // checking if insert exceeds max length + if (ToOffset(ivec2(lines[lines.size() - 1].text.size(), lines.size() - 1)) + str.length() > max_length) + { + return; + } + + std::string::size_type start = 0; + while (true) + { + std::string::size_type next_newline = str.find('\n', start); + + lines[pos.y].text.insert(pos.x, str.substr(start, next_newline - start)); + lines[pos.y].invalidated = true; + + if (next_newline == std::string::npos) + break; + + pos.x += next_newline - start; + + Line line; + line.text = lines[pos.y].text.substr(pos.x); + lines.insert(lines.begin() + pos.y + 1, line); + lines[pos.y].text = lines[pos.y].text.substr(0, pos.x); + lines[pos.y].invalidated = true; + pos = ivec2(0, pos.y + 1); + + start = next_newline + 1; + } + + MoveVerticalScroll(); + + Update(); +} + +void TextEdit::Backspace() +{ + if (undo_info.first_erase) + { + undo_info.first_erase = false; + undo_info.undo_text = GetText(); + } + + if (GetSelectionLength() != 0) + { + DeleteSelectedText(); + ClearSelection(); + Update(); + } + else + { + if (cursor_pos.x > 0) + { + UTF8Reader utf8_reader(lines[cursor_pos.y].text.data(), lines[cursor_pos.y].text.length()); + utf8_reader.set_position(cursor_pos.x); + utf8_reader.prev(); + int length = utf8_reader.char_length(); + lines[cursor_pos.y].text.erase(cursor_pos.x - length, length); + lines[cursor_pos.y].invalidated = true; + cursor_pos.x -= length; + Update(); + } + else if (cursor_pos.y > 0) + { + selection_start = ivec2(lines[cursor_pos.y - 1].text.length(), cursor_pos.y - 1); + selection_length = 1; + DeleteSelectedText(); + } + } + MoveVerticalScroll(); +} + +void TextEdit::Del() +{ + if (undo_info.first_erase) + { + undo_info.first_erase = false; + undo_info.undo_text = GetText(); + } + + if (GetSelectionLength() != 0) + { + DeleteSelectedText(); + ClearSelection(); + Update(); + } + else + { + if (cursor_pos.x < (int)lines[cursor_pos.y].text.size()) + { + UTF8Reader utf8_reader(lines[cursor_pos.y].text.data(), lines[cursor_pos.y].text.length()); + utf8_reader.set_position(cursor_pos.x); + int length = utf8_reader.char_length(); + lines[cursor_pos.y].text.erase(cursor_pos.x, length); + lines[cursor_pos.y].invalidated = true; + Update(); + } + else if (cursor_pos.y + 1 < lines.size()) + { + selection_start = ivec2(lines[cursor_pos.y].text.length(), cursor_pos.y); + selection_length = 1; + DeleteSelectedText(); + } + } + MoveVerticalScroll(); +} + +void TextEdit::OnTimerExpired() +{ + if (IsVisible() == false) + { + timer->Stop(); + return; + } + + if (cursor_blink_visible) + timer->Start(500); + else + timer->Start(500); + + cursor_blink_visible = !cursor_blink_visible; + Update(); +} + +void TextEdit::OnGeometryChanged() +{ + Canvas* canvas = GetCanvas(); + + vertical_text_align = canvas->verticalTextAlign(); + + clip_start_offset = 0; + UpdateVerticalScroll(); +} + +void TextEdit::OnScrollTimerExpired() +{ + if (mouse_moves_left) + Move(-1, false, false); + else + Move(1, false, false); +} + +void TextEdit::OnEnableChanged() +{ + bool enabled = IsEnabled(); + if (!enabled) + { + cursor_blink_visible = false; + timer->Stop(); + } + Update(); +} + +bool TextEdit::InputMaskAcceptsInput(ivec2 cursor_pos, const std::string& str) +{ + return str.find_first_not_of(input_mask) == std::string::npos; +} + +std::string::size_type TextEdit::ToOffset(ivec2 pos) const +{ + if (pos.y < lines.size()) + { + std::string::size_type offset = 0; + for (int line = 0; line < pos.y; line++) + { + offset += lines[line].text.size() + 1; + } + return offset + std::min((size_t)pos.x, lines[pos.y].text.size()); + } + else + { + std::string::size_type offset = 0; + for (size_t line = 0; line < lines.size(); line++) + { + offset += lines[line].text.size() + 1; + } + return offset - 1; + } +} + +TextEdit::ivec2 TextEdit::FromOffset(std::string::size_type offset) const +{ + int line_offset = 0; + for (int line = 0; line < lines.size(); line++) + { + if (offset <= line_offset + lines[line].text.size()) + { + return ivec2(offset - line_offset, line); + } + line_offset += lines[line].text.size() + 1; + } + return ivec2(lines.back().text.size(), lines.size() - 1); +} + +double TextEdit::GetTotalHeight() +{ + Canvas* canvas = GetCanvas(); + LayoutLines(canvas); + if (!lines.empty()) + { + return lines.back().box.bottom(); + } + else + { + return GetHeight(); + } +} + +void TextEdit::LayoutLines(Canvas* canvas) +{ + ivec2 sel_start; + ivec2 sel_end; + if (selection_length > 0) + { + sel_start = selection_start; + sel_end = FromOffset(ToOffset(selection_start) + selection_length); + } + else if (selection_length < 0) + { + sel_start = FromOffset(ToOffset(selection_start) + selection_length); + sel_end = selection_start; + } + + Point draw_pos; + for (size_t i = vert_scrollbar->GetPosition(); i < lines.size(); i++) + { + Line& line = lines[i]; + if (line.invalidated) + { + line.layout.Clear(); + if (!line.text.empty()) + line.layout.AddText(line.text, font, Colorf::fromRgba8(255, 255, 255)); + else + line.layout.AddText(" ", font, Colorf::fromRgba8(255, 255, 255)); // Draw one space character to get the correct height + line.layout.Layout(canvas, GetWidth()); + line.box = Rect(draw_pos, line.layout.GetSize()); + line.invalidated = false; + } + + if (sel_start != sel_end && sel_start.y <= i && sel_end.y >= i) + { + line.layout.SetSelectionRange(sel_start.y < i ? 0 : sel_start.x, sel_end.y > i ? line.text.size() : sel_end.x); + } + else + { + line.layout.SetSelectionRange(0, 0); + } + + line.layout.HideCursor(); + if (HasFocus()) + { + if (cursor_blink_visible && cursor_pos.y == i) + { + line.layout.SetCursorPos(cursor_pos.x); + line.layout.SetCursorColor(Colorf::fromRgba8(255, 255, 255)); + line.layout.ShowCursor(); + } + } + + line.box.x = draw_pos.x; + line.box.y = draw_pos.y; + line.layout.SetPosition(line.box.topLeft()); + + draw_pos = line.box.bottomLeft(); + } + UpdateVerticalScroll(); +} + +void TextEdit::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + Colorf bordercolor = Colorf::fromRgba8(100, 100, 100); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, 1.0), bordercolor); + canvas->fillRect(Rect::xywh(0.0, h - 1.0, w, 1.0), bordercolor); + canvas->fillRect(Rect::xywh(0.0, 0.0, 1.0, h - 0.0), bordercolor); + canvas->fillRect(Rect::xywh(w - 1.0, 0.0, 1.0, h - 0.0), bordercolor); +} + +void TextEdit::OnPaint(Canvas* canvas) +{ + LayoutLines(canvas); + for (size_t i = vert_scrollbar->GetPosition(); i < lines.size(); i++) + lines[i].layout.DrawLayout(canvas); +} + +TextEdit::ivec2 TextEdit::GetCharacterIndex(Point mouse_wincoords) +{ + Canvas* canvas = GetCanvas(); + for (size_t i = 0; i < lines.size(); i++) + { + Line& line = lines[i]; + if (line.box.top() <= mouse_wincoords.y && line.box.bottom() > mouse_wincoords.y) + { + SpanLayout::HitTestResult result = line.layout.HitTest(canvas, mouse_wincoords); + switch (result.type) + { + case SpanLayout::HitTestResult::inside: + return ivec2(clamp(result.offset, (size_t)0, line.text.size()), i); + case SpanLayout::HitTestResult::outside_left: + return ivec2(0, i); + case SpanLayout::HitTestResult::outside_right: + return ivec2(line.text.size(), i); + } + } + } + + return ivec2(lines.back().text.size(), lines.size() - 1); +} diff --git a/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp b/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp new file mode 100644 index 00000000000..55518f0a44f --- /dev/null +++ b/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp @@ -0,0 +1,60 @@ + +#include "widgets/textlabel/textlabel.h" + +TextLabel::TextLabel(Widget* parent) : Widget(parent) +{ +} + +void TextLabel::SetText(const std::string& value) +{ + if (text != value) + { + text = value; + Update(); + } +} + +const std::string& TextLabel::GetText() const +{ + return text; +} + +void TextLabel::SetTextAlignment(TextLabelAlignment alignment) +{ + if (textAlignment != alignment) + { + textAlignment = alignment; + Update(); + } +} + +TextLabelAlignment TextLabel::GetTextAlignment() const +{ + return textAlignment; +} + +double TextLabel::GetPreferredWidth() const +{ + Canvas* canvas = GetCanvas(); + return canvas->measureText(text).width; +} + +double TextLabel::GetPreferredHeight() const +{ + return 20.0; +} + +void TextLabel::OnPaint(Canvas* canvas) +{ + double x = 0.0; + if (textAlignment == TextLabelAlignment::Center) + { + x = (GetWidth() - canvas->measureText(text).width) * 0.5; + } + else if (textAlignment == TextLabelAlignment::Right) + { + x = GetWidth() - canvas->measureText(text).width; + } + + canvas->drawText(Point(x, GetHeight() - 5.0), Colorf::fromRgba8(255, 255, 255), text); +} diff --git a/libraries/ZWidget/src/widgets/toolbar/toolbar.cpp b/libraries/ZWidget/src/widgets/toolbar/toolbar.cpp new file mode 100644 index 00000000000..d028dd2d215 --- /dev/null +++ b/libraries/ZWidget/src/widgets/toolbar/toolbar.cpp @@ -0,0 +1,10 @@ + +#include "widgets/toolbar/toolbar.h" + +Toolbar::Toolbar(Widget* parent) : Widget(parent) +{ +} + +Toolbar::~Toolbar() +{ +} diff --git a/libraries/ZWidget/src/widgets/toolbar/toolbarbutton.cpp b/libraries/ZWidget/src/widgets/toolbar/toolbarbutton.cpp new file mode 100644 index 00000000000..adb6d08bf80 --- /dev/null +++ b/libraries/ZWidget/src/widgets/toolbar/toolbarbutton.cpp @@ -0,0 +1,14 @@ + +#include "widgets/toolbar/toolbarbutton.h" + +ToolbarButton::ToolbarButton(Widget* parent) : Widget(parent) +{ +} + +ToolbarButton::~ToolbarButton() +{ +} + +void ToolbarButton::OnPaint(Canvas* canvas) +{ +} diff --git a/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.cpp b/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.cpp new file mode 100644 index 00000000000..17db8a863f2 --- /dev/null +++ b/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.cpp @@ -0,0 +1,675 @@ + +#include "sdl2displaywindow.h" +#include + +Uint32 SDL2DisplayWindow::PaintEventNumber = 0xffffffff; +bool SDL2DisplayWindow::ExitRunLoop; +std::unordered_map SDL2DisplayWindow::WindowList; + +class InitSDL +{ +public: + InitSDL() + { + int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); + if (result != 0) + throw std::runtime_error(std::string("Unable to initialize SDL:") + SDL_GetError()); + + SDL2DisplayWindow::PaintEventNumber = SDL_RegisterEvents(1); + } +}; + +static void CheckInitSDL() +{ + static InitSDL initsdl; +} + +SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost) : WindowHost(windowHost) +{ + CheckInitSDL(); + + int result = SDL_CreateWindowAndRenderer(320, 200, SDL_WINDOW_HIDDEN /*| SDL_WINDOW_ALLOW_HIGHDPI*/, &WindowHandle, &RendererHandle); + if (result != 0) + throw std::runtime_error(std::string("Unable to create SDL window:") + SDL_GetError()); + + WindowList[SDL_GetWindowID(WindowHandle)] = this; +} + +SDL2DisplayWindow::~SDL2DisplayWindow() +{ + WindowList.erase(WindowList.find(SDL_GetWindowID(WindowHandle))); + + if (BackBufferTexture) + { + SDL_DestroyTexture(BackBufferTexture); + BackBufferTexture = nullptr; + } + + SDL_DestroyRenderer(RendererHandle); + SDL_DestroyWindow(WindowHandle); + RendererHandle = nullptr; + WindowHandle = nullptr; +} + +void SDL2DisplayWindow::SetWindowTitle(const std::string& text) +{ + SDL_SetWindowTitle(WindowHandle, text.c_str()); +} + +void SDL2DisplayWindow::SetWindowFrame(const Rect& box) +{ + // SDL2 doesn't really seem to have an API for this. + // The docs aren't clear what you're setting when calling SDL_SetWindowSize. + SetClientFrame(box); +} + +void SDL2DisplayWindow::SetClientFrame(const Rect& box) +{ + // Is there a way to set both in one call? + + double uiscale = GetDpiScale(); + int x = (int)std::round(box.x * uiscale); + int y = (int)std::round(box.y * uiscale); + int w = (int)std::round(box.width * uiscale); + int h = (int)std::round(box.height * uiscale); + + SDL_SetWindowPosition(WindowHandle, x, y); + SDL_SetWindowSize(WindowHandle, w, h); +} + +void SDL2DisplayWindow::Show() +{ + SDL_ShowWindow(WindowHandle); +} + +void SDL2DisplayWindow::ShowFullscreen() +{ + SDL_SetWindowFullscreen(WindowHandle, SDL_WINDOW_FULLSCREEN_DESKTOP); +} + +void SDL2DisplayWindow::ShowMaximized() +{ + SDL_ShowWindow(WindowHandle); + SDL_MaximizeWindow(WindowHandle); +} + +void SDL2DisplayWindow::ShowMinimized() +{ + SDL_ShowWindow(WindowHandle); + SDL_MinimizeWindow(WindowHandle); +} + +void SDL2DisplayWindow::ShowNormal() +{ + SDL_ShowWindow(WindowHandle); + SDL_SetWindowFullscreen(WindowHandle, 0); +} + +void SDL2DisplayWindow::Hide() +{ + SDL_HideWindow(WindowHandle); +} + +void SDL2DisplayWindow::Activate() +{ + SDL_RaiseWindow(WindowHandle); +} + +void SDL2DisplayWindow::ShowCursor(bool enable) +{ + SDL_ShowCursor(enable); +} + +void SDL2DisplayWindow::LockCursor() +{ + SDL_SetWindowGrab(WindowHandle, SDL_TRUE); + SDL_ShowCursor(0); +} + +void SDL2DisplayWindow::UnlockCursor() +{ + SDL_SetWindowGrab(WindowHandle, SDL_FALSE); + SDL_ShowCursor(1); +} + +void SDL2DisplayWindow::CaptureMouse() +{ +} + +void SDL2DisplayWindow::ReleaseMouseCapture() +{ +} + +void SDL2DisplayWindow::SetCursor(StandardCursor cursor) +{ +} + +void SDL2DisplayWindow::Update() +{ + SDL_Event event = {}; + event.type = PaintEventNumber; + event.user.windowID = SDL_GetWindowID(WindowHandle); + SDL_PushEvent(&event); +} + +bool SDL2DisplayWindow::GetKeyState(EInputKey key) +{ + int numkeys = 0; + const Uint8* state = SDL_GetKeyboardState(&numkeys); + if (!state) return false; + + SDL_Scancode index = InputKeyToScancode(key); + return (index < numkeys) ? state[index] != 0 : false; +} + +Rect SDL2DisplayWindow::GetWindowFrame() const +{ + int x = 0; + int y = 0; + int w = 0; + int h = 0; + double uiscale = GetDpiScale(); + SDL_GetWindowPosition(WindowHandle, &x, &y); + SDL_GetWindowSize(WindowHandle, &w, &h); + return Rect::xywh(x / uiscale, y / uiscale, w / uiscale, h / uiscale); +} + +Size SDL2DisplayWindow::GetClientSize() const +{ + int w = 0; + int h = 0; + double uiscale = GetDpiScale(); + SDL_GetWindowSize(WindowHandle, &w, &h); + return Size(w / uiscale, h / uiscale); +} + +int SDL2DisplayWindow::GetPixelWidth() const +{ + int w = 0; + int h = 0; + int result = SDL_GetRendererOutputSize(RendererHandle, &w, &h); + return w; +} + +int SDL2DisplayWindow::GetPixelHeight() const +{ + int w = 0; + int h = 0; + int result = SDL_GetRendererOutputSize(RendererHandle, &w, &h); + return h; +} + +double SDL2DisplayWindow::GetDpiScale() const +{ + // SDL2 doesn't really support this properly. SDL_GetDisplayDPI returns the wrong information according to the docs. + return 1.0; +} + +void SDL2DisplayWindow::PresentBitmap(int width, int height, const uint32_t* pixels) +{ + if (!BackBufferTexture || BackBufferWidth != width || BackBufferHeight != height) + { + if (BackBufferTexture) + { + SDL_DestroyTexture(BackBufferTexture); + BackBufferTexture = nullptr; + } + + BackBufferTexture = SDL_CreateTexture(RendererHandle, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); + if (!BackBufferTexture) + return; + + BackBufferWidth = width; + BackBufferHeight = height; + } + + int destpitch = 0; + void* dest = nullptr; + int result = SDL_LockTexture(BackBufferTexture, nullptr, &dest, &destpitch); + if (result != 0) return; + for (int y = 0; y < height; y++) + { + const void* sline = pixels + y * width; + void* dline = (uint8_t*)dest + y * destpitch; + memcpy(dline, sline, width << 2); + } + SDL_UnlockTexture(BackBufferTexture); + + SDL_RenderCopy(RendererHandle, BackBufferTexture, nullptr, nullptr); + SDL_RenderPresent(RendererHandle); +} + +void SDL2DisplayWindow::SetBorderColor(uint32_t bgra8) +{ + // SDL doesn't have this +} + +void SDL2DisplayWindow::SetCaptionColor(uint32_t bgra8) +{ + // SDL doesn't have this +} + +void SDL2DisplayWindow::SetCaptionTextColor(uint32_t bgra8) +{ + // SDL doesn't have this +} + +std::string SDL2DisplayWindow::GetClipboardText() +{ + char* buffer = SDL_GetClipboardText(); + if (!buffer) + return {}; + std::string text = buffer; + SDL_free(buffer); + return text; +} + +void SDL2DisplayWindow::SetClipboardText(const std::string& text) +{ + SDL_SetClipboardText(text.c_str()); +} + +void SDL2DisplayWindow::ProcessEvents() +{ + CheckInitSDL(); + + SDL_Event event; + while (SDL_PollEvent(&event) != 0) + { + DispatchEvent(event); + } +} + +void SDL2DisplayWindow::RunLoop() +{ + CheckInitSDL(); + + while (!ExitRunLoop) + { + SDL_Event event; + int result = SDL_WaitEvent(&event); + if (result == 1) + DispatchEvent(event); + } +} + +void SDL2DisplayWindow::ExitLoop() +{ + CheckInitSDL(); + + ExitRunLoop = true; +} + +Size SDL2DisplayWindow::GetScreenSize() +{ + CheckInitSDL(); + + SDL_Rect rect = {}; + int result = SDL_GetDisplayBounds(0, &rect); + if (result != 0) + throw std::runtime_error(std::string("Unable to get screen size:") + SDL_GetError()); + + double uiscale = 1.0; // SDL2 doesn't really support this properly. SDL_GetDisplayDPI returns the wrong information according to the docs. + return Size(rect.w / uiscale, rect.h / uiscale); +} + +void* SDL2DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + CheckInitSDL(); + + // To do: implement timers + + return nullptr; +} + +void SDL2DisplayWindow::StopTimer(void* timerID) +{ + CheckInitSDL(); + + // To do: implement timers +} + +SDL2DisplayWindow* SDL2DisplayWindow::FindEventWindow(const SDL_Event& event) +{ + int windowID; + switch (event.type) + { + case SDL_WINDOWEVENT: windowID = event.window.windowID; break; + case SDL_TEXTINPUT: windowID = event.text.windowID; break; + case SDL_KEYUP: windowID = event.key.windowID; break; + case SDL_KEYDOWN: windowID = event.key.windowID; break; + case SDL_MOUSEBUTTONUP: windowID = event.button.windowID; break; + case SDL_MOUSEBUTTONDOWN: windowID = event.button.windowID; break; + case SDL_MOUSEWHEEL: windowID = event.wheel.windowID; break; + case SDL_MOUSEMOTION: windowID = event.motion.windowID; break; + default: + if (event.type == PaintEventNumber) windowID = event.user.windowID; + else return nullptr; + } + + auto it = WindowList.find(windowID); + return it != WindowList.end() ? it->second : nullptr; +} + +void SDL2DisplayWindow::DispatchEvent(const SDL_Event& event) +{ + SDL2DisplayWindow* window = FindEventWindow(event); + if (!window) return; + + switch (event.type) + { + case SDL_WINDOWEVENT: window->OnWindowEvent(event.window); break; + case SDL_TEXTINPUT: window->OnTextInput(event.text); break; + case SDL_KEYUP: window->OnKeyUp(event.key); break; + case SDL_KEYDOWN: window->OnKeyDown(event.key); break; + case SDL_MOUSEBUTTONUP: window->OnMouseButtonUp(event.button); break; + case SDL_MOUSEBUTTONDOWN: window->OnMouseButtonDown(event.button); break; + case SDL_MOUSEWHEEL: window->OnMouseWheel(event.wheel); break; + case SDL_MOUSEMOTION: window->OnMouseMotion(event.motion); break; + default: + if (event.type == PaintEventNumber) window->OnPaintEvent(); + } +} + +void SDL2DisplayWindow::OnWindowEvent(const SDL_WindowEvent& event) +{ + switch (event.event) + { + case SDL_WINDOWEVENT_CLOSE: WindowHost->OnWindowClose(); break; + case SDL_WINDOWEVENT_MOVED: WindowHost->OnWindowGeometryChanged(); break; + case SDL_WINDOWEVENT_RESIZED: WindowHost->OnWindowGeometryChanged(); break; + case SDL_WINDOWEVENT_SHOWN: WindowHost->OnWindowPaint(); break; + case SDL_WINDOWEVENT_EXPOSED: WindowHost->OnWindowPaint(); break; + case SDL_WINDOWEVENT_FOCUS_GAINED: WindowHost->OnWindowActivated(); break; + case SDL_WINDOWEVENT_FOCUS_LOST: WindowHost->OnWindowDeactivated(); break; + } +} + +void SDL2DisplayWindow::OnTextInput(const SDL_TextInputEvent& event) +{ + WindowHost->OnWindowKeyChar(event.text); +} + +void SDL2DisplayWindow::OnKeyUp(const SDL_KeyboardEvent& event) +{ + WindowHost->OnWindowKeyUp(ScancodeToInputKey(event.keysym.scancode)); +} + +void SDL2DisplayWindow::OnKeyDown(const SDL_KeyboardEvent& event) +{ + WindowHost->OnWindowKeyDown(ScancodeToInputKey(event.keysym.scancode)); +} + +EInputKey SDL2DisplayWindow::GetMouseButtonKey(const SDL_MouseButtonEvent& event) +{ + switch (event.button) + { + case SDL_BUTTON_LEFT: return IK_LeftMouse; + case SDL_BUTTON_MIDDLE: return IK_MiddleMouse; + case SDL_BUTTON_RIGHT: return IK_RightMouse; + // case SDL_BUTTON_X1: return IK_XButton1; + // case SDL_BUTTON_X2: return IK_XButton2; + default: return IK_None; + } +} + +void SDL2DisplayWindow::OnMouseButtonUp(const SDL_MouseButtonEvent& event) +{ + EInputKey key = GetMouseButtonKey(event); + if (key != IK_None) + { + WindowHost->OnWindowMouseUp(GetMousePos(event), key); + } +} + +void SDL2DisplayWindow::OnMouseButtonDown(const SDL_MouseButtonEvent& event) +{ + EInputKey key = GetMouseButtonKey(event); + if (key != IK_None) + { + WindowHost->OnWindowMouseDown(GetMousePos(event), key); + } +} + +void SDL2DisplayWindow::OnMouseWheel(const SDL_MouseWheelEvent& event) +{ + EInputKey key = (event.y > 0) ? IK_MouseWheelUp : (event.y < 0) ? IK_MouseWheelDown : IK_None; + if (key != IK_None) + { + WindowHost->OnWindowMouseWheel(GetMousePos(event), key); + } +} + +void SDL2DisplayWindow::OnMouseMotion(const SDL_MouseMotionEvent& event) +{ + WindowHost->OnWindowMouseMove(GetMousePos(event)); +} + +void SDL2DisplayWindow::OnPaintEvent() +{ + WindowHost->OnWindowPaint(); +} + +EInputKey SDL2DisplayWindow::ScancodeToInputKey(SDL_Scancode keycode) +{ + switch (keycode) + { + case SDL_SCANCODE_BACKSPACE: return IK_Backspace; + case SDL_SCANCODE_TAB: return IK_Tab; + case SDL_SCANCODE_CLEAR: return IK_OEMClear; + case SDL_SCANCODE_RETURN: return IK_Enter; + case SDL_SCANCODE_MENU: return IK_Alt; + case SDL_SCANCODE_PAUSE: return IK_Pause; + case SDL_SCANCODE_ESCAPE: return IK_Escape; + case SDL_SCANCODE_SPACE: return IK_Space; + case SDL_SCANCODE_END: return IK_End; + case SDL_SCANCODE_HOME: return IK_Home; + case SDL_SCANCODE_LEFT: return IK_Left; + case SDL_SCANCODE_UP: return IK_Up; + case SDL_SCANCODE_RIGHT: return IK_Right; + case SDL_SCANCODE_DOWN: return IK_Down; + case SDL_SCANCODE_SELECT: return IK_Select; + case SDL_SCANCODE_PRINTSCREEN: return IK_Print; + case SDL_SCANCODE_EXECUTE: return IK_Execute; + case SDL_SCANCODE_INSERT: return IK_Insert; + case SDL_SCANCODE_DELETE: return IK_Delete; + case SDL_SCANCODE_HELP: return IK_Help; + case SDL_SCANCODE_0: return IK_0; + case SDL_SCANCODE_1: return IK_1; + case SDL_SCANCODE_2: return IK_2; + case SDL_SCANCODE_3: return IK_3; + case SDL_SCANCODE_4: return IK_4; + case SDL_SCANCODE_5: return IK_5; + case SDL_SCANCODE_6: return IK_6; + case SDL_SCANCODE_7: return IK_7; + case SDL_SCANCODE_8: return IK_8; + case SDL_SCANCODE_9: return IK_9; + case SDL_SCANCODE_A: return IK_A; + case SDL_SCANCODE_B: return IK_B; + case SDL_SCANCODE_C: return IK_C; + case SDL_SCANCODE_D: return IK_D; + case SDL_SCANCODE_E: return IK_E; + case SDL_SCANCODE_F: return IK_F; + case SDL_SCANCODE_G: return IK_G; + case SDL_SCANCODE_H: return IK_H; + case SDL_SCANCODE_I: return IK_I; + case SDL_SCANCODE_J: return IK_J; + case SDL_SCANCODE_K: return IK_K; + case SDL_SCANCODE_L: return IK_L; + case SDL_SCANCODE_M: return IK_M; + case SDL_SCANCODE_N: return IK_N; + case SDL_SCANCODE_O: return IK_O; + case SDL_SCANCODE_P: return IK_P; + case SDL_SCANCODE_Q: return IK_Q; + case SDL_SCANCODE_R: return IK_R; + case SDL_SCANCODE_S: return IK_S; + case SDL_SCANCODE_T: return IK_T; + case SDL_SCANCODE_U: return IK_U; + case SDL_SCANCODE_V: return IK_V; + case SDL_SCANCODE_W: return IK_W; + case SDL_SCANCODE_X: return IK_X; + case SDL_SCANCODE_Y: return IK_Y; + case SDL_SCANCODE_Z: return IK_Z; + case SDL_SCANCODE_KP_0: return IK_NumPad0; + case SDL_SCANCODE_KP_1: return IK_NumPad1; + case SDL_SCANCODE_KP_2: return IK_NumPad2; + case SDL_SCANCODE_KP_3: return IK_NumPad3; + case SDL_SCANCODE_KP_4: return IK_NumPad4; + case SDL_SCANCODE_KP_5: return IK_NumPad5; + case SDL_SCANCODE_KP_6: return IK_NumPad6; + case SDL_SCANCODE_KP_7: return IK_NumPad7; + case SDL_SCANCODE_KP_8: return IK_NumPad8; + case SDL_SCANCODE_KP_9: return IK_NumPad9; + // case SDL_SCANCODE_KP_ENTER: return IK_NumPadEnter; + // case SDL_SCANCODE_KP_MULTIPLY: return IK_Multiply; + // case SDL_SCANCODE_KP_PLUS: return IK_Add; + case SDL_SCANCODE_SEPARATOR: return IK_Separator; + // case SDL_SCANCODE_KP_MINUS: return IK_Subtract; + case SDL_SCANCODE_KP_PERIOD: return IK_NumPadPeriod; + // case SDL_SCANCODE_KP_DIVIDE: return IK_Divide; + case SDL_SCANCODE_F1: return IK_F1; + case SDL_SCANCODE_F2: return IK_F2; + case SDL_SCANCODE_F3: return IK_F3; + case SDL_SCANCODE_F4: return IK_F4; + case SDL_SCANCODE_F5: return IK_F5; + case SDL_SCANCODE_F6: return IK_F6; + case SDL_SCANCODE_F7: return IK_F7; + case SDL_SCANCODE_F8: return IK_F8; + case SDL_SCANCODE_F9: return IK_F9; + case SDL_SCANCODE_F10: return IK_F10; + case SDL_SCANCODE_F11: return IK_F11; + case SDL_SCANCODE_F12: return IK_F12; + case SDL_SCANCODE_F13: return IK_F13; + case SDL_SCANCODE_F14: return IK_F14; + case SDL_SCANCODE_F15: return IK_F15; + case SDL_SCANCODE_F16: return IK_F16; + case SDL_SCANCODE_F17: return IK_F17; + case SDL_SCANCODE_F18: return IK_F18; + case SDL_SCANCODE_F19: return IK_F19; + case SDL_SCANCODE_F20: return IK_F20; + case SDL_SCANCODE_F21: return IK_F21; + case SDL_SCANCODE_F22: return IK_F22; + case SDL_SCANCODE_F23: return IK_F23; + case SDL_SCANCODE_F24: return IK_F24; + case SDL_SCANCODE_NUMLOCKCLEAR: return IK_NumLock; + case SDL_SCANCODE_SCROLLLOCK: return IK_ScrollLock; + case SDL_SCANCODE_LSHIFT: return IK_LShift; + case SDL_SCANCODE_RSHIFT: return IK_RShift; + case SDL_SCANCODE_LCTRL: return IK_LControl; + case SDL_SCANCODE_RCTRL: return IK_RControl; + case SDL_SCANCODE_GRAVE: return IK_Tilde; + default: return IK_None; + } +} + +SDL_Scancode SDL2DisplayWindow::InputKeyToScancode(EInputKey inputkey) +{ + switch (inputkey) + { + case IK_Backspace: return SDL_SCANCODE_BACKSPACE; + case IK_Tab: return SDL_SCANCODE_TAB; + case IK_OEMClear: return SDL_SCANCODE_CLEAR; + case IK_Enter: return SDL_SCANCODE_RETURN; + case IK_Alt: return SDL_SCANCODE_MENU; + case IK_Pause: return SDL_SCANCODE_PAUSE; + case IK_Escape: return SDL_SCANCODE_ESCAPE; + case IK_Space: return SDL_SCANCODE_SPACE; + case IK_End: return SDL_SCANCODE_END; + case IK_Home: return SDL_SCANCODE_HOME; + case IK_Left: return SDL_SCANCODE_LEFT; + case IK_Up: return SDL_SCANCODE_UP; + case IK_Right: return SDL_SCANCODE_RIGHT; + case IK_Down: return SDL_SCANCODE_DOWN; + case IK_Select: return SDL_SCANCODE_SELECT; + case IK_Print: return SDL_SCANCODE_PRINTSCREEN; + case IK_Execute: return SDL_SCANCODE_EXECUTE; + case IK_Insert: return SDL_SCANCODE_INSERT; + case IK_Delete: return SDL_SCANCODE_DELETE; + case IK_Help: return SDL_SCANCODE_HELP; + case IK_0: return SDL_SCANCODE_0; + case IK_1: return SDL_SCANCODE_1; + case IK_2: return SDL_SCANCODE_2; + case IK_3: return SDL_SCANCODE_3; + case IK_4: return SDL_SCANCODE_4; + case IK_5: return SDL_SCANCODE_5; + case IK_6: return SDL_SCANCODE_6; + case IK_7: return SDL_SCANCODE_7; + case IK_8: return SDL_SCANCODE_8; + case IK_9: return SDL_SCANCODE_9; + case IK_A: return SDL_SCANCODE_A; + case IK_B: return SDL_SCANCODE_B; + case IK_C: return SDL_SCANCODE_C; + case IK_D: return SDL_SCANCODE_D; + case IK_E: return SDL_SCANCODE_E; + case IK_F: return SDL_SCANCODE_F; + case IK_G: return SDL_SCANCODE_G; + case IK_H: return SDL_SCANCODE_H; + case IK_I: return SDL_SCANCODE_I; + case IK_J: return SDL_SCANCODE_J; + case IK_K: return SDL_SCANCODE_K; + case IK_L: return SDL_SCANCODE_L; + case IK_M: return SDL_SCANCODE_M; + case IK_N: return SDL_SCANCODE_N; + case IK_O: return SDL_SCANCODE_O; + case IK_P: return SDL_SCANCODE_P; + case IK_Q: return SDL_SCANCODE_Q; + case IK_R: return SDL_SCANCODE_R; + case IK_S: return SDL_SCANCODE_S; + case IK_T: return SDL_SCANCODE_T; + case IK_U: return SDL_SCANCODE_U; + case IK_V: return SDL_SCANCODE_V; + case IK_W: return SDL_SCANCODE_W; + case IK_X: return SDL_SCANCODE_X; + case IK_Y: return SDL_SCANCODE_Y; + case IK_Z: return SDL_SCANCODE_Z; + case IK_NumPad0: return SDL_SCANCODE_KP_0; + case IK_NumPad1: return SDL_SCANCODE_KP_1; + case IK_NumPad2: return SDL_SCANCODE_KP_2; + case IK_NumPad3: return SDL_SCANCODE_KP_3; + case IK_NumPad4: return SDL_SCANCODE_KP_4; + case IK_NumPad5: return SDL_SCANCODE_KP_5; + case IK_NumPad6: return SDL_SCANCODE_KP_6; + case IK_NumPad7: return SDL_SCANCODE_KP_7; + case IK_NumPad8: return SDL_SCANCODE_KP_8; + case IK_NumPad9: return SDL_SCANCODE_KP_9; + // case IK_NumPadEnter: return SDL_SCANCODE_KP_ENTER; + // case IK_Multiply return SDL_SCANCODE_KP_MULTIPLY:; + // case IK_Add: return SDL_SCANCODE_KP_PLUS; + case IK_Separator: return SDL_SCANCODE_SEPARATOR; + // case IK_Subtract: return SDL_SCANCODE_KP_MINUS; + case IK_NumPadPeriod: return SDL_SCANCODE_KP_PERIOD; + // case IK_Divide: return SDL_SCANCODE_KP_DIVIDE; + case IK_F1: return SDL_SCANCODE_F1; + case IK_F2: return SDL_SCANCODE_F2; + case IK_F3: return SDL_SCANCODE_F3; + case IK_F4: return SDL_SCANCODE_F4; + case IK_F5: return SDL_SCANCODE_F5; + case IK_F6: return SDL_SCANCODE_F6; + case IK_F7: return SDL_SCANCODE_F7; + case IK_F8: return SDL_SCANCODE_F8; + case IK_F9: return SDL_SCANCODE_F9; + case IK_F10: return SDL_SCANCODE_F10; + case IK_F11: return SDL_SCANCODE_F11; + case IK_F12: return SDL_SCANCODE_F12; + case IK_F13: return SDL_SCANCODE_F13; + case IK_F14: return SDL_SCANCODE_F14; + case IK_F15: return SDL_SCANCODE_F15; + case IK_F16: return SDL_SCANCODE_F16; + case IK_F17: return SDL_SCANCODE_F17; + case IK_F18: return SDL_SCANCODE_F18; + case IK_F19: return SDL_SCANCODE_F19; + case IK_F20: return SDL_SCANCODE_F20; + case IK_F21: return SDL_SCANCODE_F21; + case IK_F22: return SDL_SCANCODE_F22; + case IK_F23: return SDL_SCANCODE_F23; + case IK_F24: return SDL_SCANCODE_F24; + case IK_NumLock: return SDL_SCANCODE_NUMLOCKCLEAR; + case IK_ScrollLock: return SDL_SCANCODE_SCROLLLOCK; + case IK_LShift: return SDL_SCANCODE_LSHIFT; + case IK_RShift: return SDL_SCANCODE_RSHIFT; + case IK_LControl: return SDL_SCANCODE_LCTRL; + case IK_RControl: return SDL_SCANCODE_RCTRL; + case IK_Tilde: return SDL_SCANCODE_GRAVE; + default: return (SDL_Scancode)0; + } +} diff --git a/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.h b/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.h new file mode 100644 index 00000000000..fa0e8253cce --- /dev/null +++ b/libraries/ZWidget/src/window/sdl2/sdl2displaywindow.h @@ -0,0 +1,91 @@ +#pragma once + +#include +#include +#include +#include + +class SDL2DisplayWindow : public DisplayWindow +{ +public: + SDL2DisplayWindow(DisplayWindowHost* windowHost); + ~SDL2DisplayWindow(); + + void SetWindowTitle(const std::string& text) override; + void SetWindowFrame(const Rect& box) override; + void SetClientFrame(const Rect& box) override; + void Show() override; + void ShowFullscreen() override; + void ShowMaximized() override; + void ShowMinimized() override; + void ShowNormal() override; + void Hide() override; + void Activate() override; + void ShowCursor(bool enable) override; + void LockCursor() override; + void UnlockCursor() override; + void CaptureMouse() override; + void ReleaseMouseCapture() override; + void Update() override; + bool GetKeyState(EInputKey key) override; + void SetCursor(StandardCursor cursor) override; + + Rect GetWindowFrame() const override; + Size GetClientSize() const override; + int GetPixelWidth() const override; + int GetPixelHeight() const override; + double GetDpiScale() const override; + + void PresentBitmap(int width, int height, const uint32_t* pixels) override; + + void SetBorderColor(uint32_t bgra8) override; + void SetCaptionColor(uint32_t bgra8) override; + void SetCaptionTextColor(uint32_t bgra8) override; + + std::string GetClipboardText() override; + void SetClipboardText(const std::string& text) override; + + static void DispatchEvent(const SDL_Event& event); + static SDL2DisplayWindow* FindEventWindow(const SDL_Event& event); + + void OnWindowEvent(const SDL_WindowEvent& event); + void OnTextInput(const SDL_TextInputEvent& event); + void OnKeyUp(const SDL_KeyboardEvent& event); + void OnKeyDown(const SDL_KeyboardEvent& event); + void OnMouseButtonUp(const SDL_MouseButtonEvent& event); + void OnMouseButtonDown(const SDL_MouseButtonEvent& event); + void OnMouseWheel(const SDL_MouseWheelEvent& event); + void OnMouseMotion(const SDL_MouseMotionEvent& event); + void OnPaintEvent(); + + EInputKey GetMouseButtonKey(const SDL_MouseButtonEvent& event); + + static EInputKey ScancodeToInputKey(SDL_Scancode keycode); + static SDL_Scancode InputKeyToScancode(EInputKey inputkey); + + template + Point GetMousePos(const T& event) + { + double uiscale = GetDpiScale(); + return Point(event.x / uiscale, event.y / uiscale); + } + + static void ProcessEvents(); + static void RunLoop(); + static void ExitLoop(); + static Size GetScreenSize(); + + static void* StartTimer(int timeoutMilliseconds, std::function onTimer); + static void StopTimer(void* timerID); + + DisplayWindowHost* WindowHost = nullptr; + SDL_Window* WindowHandle = nullptr; + SDL_Renderer* RendererHandle = nullptr; + SDL_Texture* BackBufferTexture = nullptr; + int BackBufferWidth = 0; + int BackBufferHeight = 0; + + static bool ExitRunLoop; + static Uint32 PaintEventNumber; + static std::unordered_map WindowList; +}; diff --git a/libraries/ZWidget/src/window/win32/win32window.cpp b/libraries/ZWidget/src/window/win32/win32window.cpp new file mode 100644 index 00000000000..6ad09ef6041 --- /dev/null +++ b/libraries/ZWidget/src/window/win32/win32window.cpp @@ -0,0 +1,702 @@ + +#include "win32window.h" +#include +#include +#include +#include +#include + +#pragma comment(lib, "dwmapi.lib") + +#ifndef HID_USAGE_PAGE_GENERIC +#define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01) +#endif + +#ifndef HID_USAGE_GENERIC_MOUSE +#define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02) +#endif + +#ifndef HID_USAGE_GENERIC_JOYSTICK +#define HID_USAGE_GENERIC_JOYSTICK ((USHORT) 0x04) +#endif + +#ifndef HID_USAGE_GENERIC_GAMEPAD +#define HID_USAGE_GENERIC_GAMEPAD ((USHORT) 0x05) +#endif + +#ifndef RIDEV_INPUTSINK +#define RIDEV_INPUTSINK (0x100) +#endif + +#ifdef MINGW +// MinGW's library doesn't contain a thunk for DwmDefWindowProc, so we need to create our own + +BOOL DwmDefWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult ) +{ + typedef BOOL(* dwmdwp)(HWND, UINT, WPARAM, LPARAM, LRESULT* ); + BOOL result(FALSE); + HMODULE module = LoadLibrary( _T( "dwmapi.dll" ) ); + if( module ) { + dwmdwp proc = reinterpret_cast( GetProcAddress( module, "DwmDefWindowProc" ) ); + if( proc ) { + result = proc( hWnd, msg, wParam, lParam, plResult ); + } + FreeLibrary(module); + } + return result; +} + +#endif + +static std::string from_utf16(const std::wstring& str) +{ + if (str.empty()) return {}; + int needed = WideCharToMultiByte(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0, nullptr, nullptr); + if (needed == 0) + throw std::runtime_error("WideCharToMultiByte failed"); + std::string result; + result.resize(needed); + needed = WideCharToMultiByte(CP_UTF8, 0, str.data(), (int)str.size(), &result[0], (int)result.size(), nullptr, nullptr); + if (needed == 0) + throw std::runtime_error("WideCharToMultiByte failed"); + return result; +} + +static std::wstring to_utf16(const std::string& str) +{ + if (str.empty()) return {}; + int needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0); + if (needed == 0) + throw std::runtime_error("MultiByteToWideChar failed"); + std::wstring result; + result.resize(needed); + needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &result[0], (int)result.size()); + if (needed == 0) + throw std::runtime_error("MultiByteToWideChar failed"); + return result; +} + +Win32Window::Win32Window(DisplayWindowHost* windowHost) : WindowHost(windowHost) +{ + Windows.push_front(this); + WindowsIterator = Windows.begin(); + + WNDCLASSEXW classdesc = {}; + classdesc.cbSize = sizeof(WNDCLASSEX); + classdesc.hInstance = GetModuleHandle(0); + classdesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS; + classdesc.lpszClassName = L"ZWidgetWindow"; + classdesc.lpfnWndProc = &Win32Window::WndProc; + RegisterClassEx(&classdesc); + + // Microsoft logic at its finest: + // WS_EX_DLGMODALFRAME hides the sysmenu icon + // WS_CAPTION shows the caption (yay! actually a flag that does what it says it does!) + // WS_SYSMENU shows the min/max/close buttons + // WS_THICKFRAME makes the window resizable + CreateWindowExW(WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME, L"ZWidgetWindow", L"", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, 100, 100, 0, 0, GetModuleHandle(0), this); + + /* + RAWINPUTDEVICE rid; + rid.usUsagePage = HID_USAGE_PAGE_GENERIC; + rid.usUsage = HID_USAGE_GENERIC_MOUSE; + rid.dwFlags = RIDEV_INPUTSINK; + rid.hwndTarget = WindowHandle; + BOOL result = RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE)); + */ +} + +Win32Window::~Win32Window() +{ + if (WindowHandle) + { + DestroyWindow(WindowHandle); + WindowHandle = 0; + } + + Windows.erase(WindowsIterator); +} + +void Win32Window::SetWindowTitle(const std::string& text) +{ + SetWindowText(WindowHandle, to_utf16(text).c_str()); +} + +void Win32Window::SetBorderColor(uint32_t bgra8) +{ + bgra8 = bgra8 & 0x00ffffff; + DwmSetWindowAttribute(WindowHandle, 34/*DWMWA_BORDER_COLOR*/, &bgra8, sizeof(uint32_t)); +} + +void Win32Window::SetCaptionColor(uint32_t bgra8) +{ + bgra8 = bgra8 & 0x00ffffff; + DwmSetWindowAttribute(WindowHandle, 35/*DWMWA_CAPTION_COLOR*/, &bgra8, sizeof(uint32_t)); +} + +void Win32Window::SetCaptionTextColor(uint32_t bgra8) +{ + bgra8 = bgra8 & 0x00ffffff; + DwmSetWindowAttribute(WindowHandle, 36/*DWMWA_TEXT_COLOR*/, &bgra8, sizeof(uint32_t)); +} + +void Win32Window::SetWindowFrame(const Rect& box) +{ + double dpiscale = GetDpiScale(); + SetWindowPos(WindowHandle, nullptr, (int)std::round(box.x * dpiscale), (int)std::round(box.y * dpiscale), (int)std::round(box.width * dpiscale), (int)std::round(box.height * dpiscale), SWP_NOACTIVATE | SWP_NOZORDER); +} + +void Win32Window::SetClientFrame(const Rect& box) +{ + // This function is currently unused but needs to be disabled because it contains Windows API calls that were only added in Windows 10. +#if 0 + double dpiscale = GetDpiScale(); + + RECT rect = {}; + rect.left = (int)std::round(box.x * dpiscale); + rect.top = (int)std::round(box.y * dpiscale); + rect.right = rect.left + (int)std::round(box.width * dpiscale); + rect.bottom = rect.top + (int)std::round(box.height * dpiscale); + + DWORD style = (DWORD)GetWindowLongPtr(WindowHandle, GWL_STYLE); + DWORD exstyle = (DWORD)GetWindowLongPtr(WindowHandle, GWL_EXSTYLE); + AdjustWindowRectExForDpi(&rect, style, FALSE, exstyle, GetDpiForWindow(WindowHandle)); + + SetWindowPos(WindowHandle, nullptr, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOZORDER); +#endif +} + +void Win32Window::Show() +{ + ShowWindow(WindowHandle, SW_SHOW); +} + +void Win32Window::ShowFullscreen() +{ + HDC screenDC = GetDC(0); + int width = GetDeviceCaps(screenDC, HORZRES); + int height = GetDeviceCaps(screenDC, VERTRES); + ReleaseDC(0, screenDC); + SetWindowLongPtr(WindowHandle, GWL_EXSTYLE, WS_EX_APPWINDOW); + SetWindowLongPtr(WindowHandle, GWL_STYLE, WS_OVERLAPPED); + SetWindowPos(WindowHandle, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED | SWP_SHOWWINDOW); + Fullscreen = true; +} + +void Win32Window::ShowMaximized() +{ + ShowWindow(WindowHandle, SW_SHOWMAXIMIZED); +} + +void Win32Window::ShowMinimized() +{ + ShowWindow(WindowHandle, SW_SHOWMINIMIZED); +} + +void Win32Window::ShowNormal() +{ + ShowWindow(WindowHandle, SW_NORMAL); +} + +void Win32Window::Hide() +{ + ShowWindow(WindowHandle, SW_HIDE); +} + +void Win32Window::Activate() +{ + SetFocus(WindowHandle); +} + +void Win32Window::ShowCursor(bool enable) +{ +} + +void Win32Window::LockCursor() +{ + if (!MouseLocked) + { + MouseLocked = true; + GetCursorPos(&MouseLockPos); + ::ShowCursor(FALSE); + } +} + +void Win32Window::UnlockCursor() +{ + if (MouseLocked) + { + MouseLocked = false; + SetCursorPos(MouseLockPos.x, MouseLockPos.y); + ::ShowCursor(TRUE); + } +} + +void Win32Window::CaptureMouse() +{ + SetCapture(WindowHandle); +} + +void Win32Window::ReleaseMouseCapture() +{ + ReleaseCapture(); +} + +void Win32Window::Update() +{ + InvalidateRect(WindowHandle, nullptr, FALSE); +} + +bool Win32Window::GetKeyState(EInputKey key) +{ + return ::GetKeyState((int)key) & 0x8000; // High bit (0x8000) means key is down, Low bit (0x0001) means key is sticky on (like Caps Lock, Num Lock, etc.) +} + +void Win32Window::SetCursor(StandardCursor cursor) +{ + if (cursor != CurrentCursor) + { + CurrentCursor = cursor; + UpdateCursor(); + } +} + +Rect Win32Window::GetWindowFrame() const +{ + RECT box = {}; + GetWindowRect(WindowHandle, &box); + double dpiscale = GetDpiScale(); + return Rect(box.left / dpiscale, box.top / dpiscale, box.right / dpiscale, box.bottom / dpiscale); +} + +Size Win32Window::GetClientSize() const +{ + RECT box = {}; + GetClientRect(WindowHandle, &box); + double dpiscale = GetDpiScale(); + return Size(box.right / dpiscale, box.bottom / dpiscale); +} + +int Win32Window::GetPixelWidth() const +{ + RECT box = {}; + GetClientRect(WindowHandle, &box); + return box.right; +} + +int Win32Window::GetPixelHeight() const +{ + RECT box = {}; + GetClientRect(WindowHandle, &box); + return box.bottom; +} + +typedef UINT(WINAPI* GetDpiForWindow_t)(HWND); +double Win32Window::GetDpiScale() const +{ + static GetDpiForWindow_t pGetDpiForWindow = nullptr; + static bool done = false; + if (!done) + { + HMODULE hMod = GetModuleHandleA("User32.dll"); + if (hMod != nullptr) pGetDpiForWindow = reinterpret_cast(GetProcAddress(hMod, "GetDpiForWindow")); + done = true; + } + + if (pGetDpiForWindow) + return pGetDpiForWindow(WindowHandle) / 96.0; + else + return 1.0; +} + +std::string Win32Window::GetClipboardText() +{ + BOOL result = OpenClipboard(WindowHandle); + if (result == FALSE) + throw std::runtime_error("Unable to open clipboard"); + + HANDLE handle = GetClipboardData(CF_UNICODETEXT); + if (handle == 0) + { + CloseClipboard(); + return std::string(); + } + + std::wstring::value_type* data = (std::wstring::value_type*)GlobalLock(handle); + if (data == 0) + { + CloseClipboard(); + return std::string(); + } + std::string str = from_utf16(data); + GlobalUnlock(handle); + + CloseClipboard(); + return str; +} + +void Win32Window::SetClipboardText(const std::string& text) +{ + std::wstring text16 = to_utf16(text); + + BOOL result = OpenClipboard(WindowHandle); + if (result == FALSE) + throw std::runtime_error("Unable to open clipboard"); + + result = EmptyClipboard(); + if (result == FALSE) + { + CloseClipboard(); + throw std::runtime_error("Unable to empty clipboard"); + } + + unsigned int length = (text16.length() + 1) * sizeof(std::wstring::value_type); + HANDLE handle = GlobalAlloc(GMEM_MOVEABLE, length); + if (handle == 0) + { + CloseClipboard(); + throw std::runtime_error("Unable to allocate clipboard memory"); + } + + void* data = GlobalLock(handle); + if (data == 0) + { + GlobalFree(handle); + CloseClipboard(); + throw std::runtime_error("Unable to lock clipboard memory"); + } + memcpy(data, text16.c_str(), length); + GlobalUnlock(handle); + + HANDLE data_result = SetClipboardData(CF_UNICODETEXT, handle); + + if (data_result == 0) + { + GlobalFree(handle); + CloseClipboard(); + throw std::runtime_error("Unable to set clipboard data"); + } + + CloseClipboard(); +} + +void Win32Window::PresentBitmap(int width, int height, const uint32_t* pixels) +{ + BITMAPV5HEADER header = {}; + header.bV5Size = sizeof(BITMAPV5HEADER); + header.bV5Width = width; + header.bV5Height = -height; + header.bV5Planes = 1; + header.bV5BitCount = 32; + header.bV5Compression = BI_BITFIELDS; + header.bV5AlphaMask = 0xff000000; + header.bV5RedMask = 0x00ff0000; + header.bV5GreenMask = 0x0000ff00; + header.bV5BlueMask = 0x000000ff; + header.bV5SizeImage = width * height * sizeof(uint32_t); + header.bV5CSType = LCS_sRGB; + + HDC dc = PaintDC; + if (dc != 0) + { + int result = SetDIBitsToDevice(dc, 0, 0, width, height, 0, 0, 0, height, pixels, (const BITMAPINFO*)&header, BI_RGB); + ReleaseDC(WindowHandle, dc); + } +} + +LRESULT Win32Window::OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam) +{ + LPARAM result = 0; + + if (DwmDefWindowProc(WindowHandle, msg, wparam, lparam, &result)) + return result; + + if (msg == WM_INPUT) + { + bool hasFocus = GetFocus() != 0; + + HRAWINPUT handle = (HRAWINPUT)lparam; + UINT size = 0; + UINT result = GetRawInputData(handle, RID_INPUT, 0, &size, sizeof(RAWINPUTHEADER)); + if (result == 0 && size > 0) + { + size *= 2; + std::vector buffer(size); + result = GetRawInputData(handle, RID_INPUT, buffer.data(), &size, sizeof(RAWINPUTHEADER)); + if (result >= 0) + { + RAWINPUT* rawinput = (RAWINPUT*)buffer.data(); + if (rawinput->header.dwType == RIM_TYPEMOUSE) + { + if (hasFocus) + WindowHost->OnWindowRawMouseMove(rawinput->data.mouse.lLastX, rawinput->data.mouse.lLastY); + } + } + } + return DefWindowProc(WindowHandle, msg, wparam, lparam); + } + else if (msg == WM_PAINT) + { + PAINTSTRUCT paintStruct = {}; + PaintDC = BeginPaint(WindowHandle, &paintStruct); + if (PaintDC) + { + WindowHost->OnWindowPaint(); + EndPaint(WindowHandle, &paintStruct); + PaintDC = 0; + } + return 0; + } + else if (msg == WM_ACTIVATE) + { + WindowHost->OnWindowActivated(); + } + else if (msg == WM_MOUSEMOVE) + { + if (MouseLocked && GetFocus() != 0) + { + RECT box = {}; + GetClientRect(WindowHandle, &box); + + POINT center = {}; + center.x = box.right / 2; + center.y = box.bottom / 2; + ClientToScreen(WindowHandle, ¢er); + + SetCursorPos(center.x, center.y); + } + else + { + UpdateCursor(); + } + + WindowHost->OnWindowMouseMove(GetLParamPos(lparam)); + } + else if (msg == WM_LBUTTONDOWN) + { + WindowHost->OnWindowMouseDown(GetLParamPos(lparam), IK_LeftMouse); + } + else if (msg == WM_LBUTTONDBLCLK) + { + WindowHost->OnWindowMouseDoubleclick(GetLParamPos(lparam), IK_LeftMouse); + } + else if (msg == WM_LBUTTONUP) + { + WindowHost->OnWindowMouseUp(GetLParamPos(lparam), IK_LeftMouse); + } + else if (msg == WM_MBUTTONDOWN) + { + WindowHost->OnWindowMouseDown(GetLParamPos(lparam), IK_MiddleMouse); + } + else if (msg == WM_MBUTTONDBLCLK) + { + WindowHost->OnWindowMouseDoubleclick(GetLParamPos(lparam), IK_MiddleMouse); + } + else if (msg == WM_MBUTTONUP) + { + WindowHost->OnWindowMouseUp(GetLParamPos(lparam), IK_MiddleMouse); + } + else if (msg == WM_RBUTTONDOWN) + { + WindowHost->OnWindowMouseDown(GetLParamPos(lparam), IK_RightMouse); + } + else if (msg == WM_RBUTTONDBLCLK) + { + WindowHost->OnWindowMouseDoubleclick(GetLParamPos(lparam), IK_RightMouse); + } + else if (msg == WM_RBUTTONUP) + { + WindowHost->OnWindowMouseUp(GetLParamPos(lparam), IK_RightMouse); + } + else if (msg == WM_MOUSEWHEEL) + { + double delta = GET_WHEEL_DELTA_WPARAM(wparam) / (double)WHEEL_DELTA; + + // Note: WM_MOUSEWHEEL uses screen coordinates. GetLParamPos assumes client coordinates. + double dpiscale = GetDpiScale(); + POINT pos; + pos.x = GET_X_LPARAM(lparam); + pos.y = GET_Y_LPARAM(lparam); + ScreenToClient(WindowHandle, &pos); + + WindowHost->OnWindowMouseWheel(Point(pos.x / dpiscale, pos.y / dpiscale), delta < 0.0 ? IK_MouseWheelDown : IK_MouseWheelUp); + } + else if (msg == WM_CHAR) + { + wchar_t buf[2] = { (wchar_t)wparam, 0 }; + WindowHost->OnWindowKeyChar(from_utf16(buf)); + } + else if (msg == WM_KEYDOWN) + { + WindowHost->OnWindowKeyDown((EInputKey)wparam); + } + else if (msg == WM_KEYUP) + { + WindowHost->OnWindowKeyUp((EInputKey)wparam); + } + else if (msg == WM_SETFOCUS) + { + if (MouseLocked) + { + ::ShowCursor(FALSE); + } + } + else if (msg == WM_KILLFOCUS) + { + if (MouseLocked) + { + ::ShowCursor(TRUE); + } + } + else if (msg == WM_CLOSE) + { + WindowHost->OnWindowClose(); + return 0; + } + else if (msg == WM_SIZE) + { + WindowHost->OnWindowGeometryChanged(); + return 0; + } + /*else if (msg == WM_NCCALCSIZE && wparam == TRUE) // calculate client area for the window + { + NCCALCSIZE_PARAMS* calcsize = (NCCALCSIZE_PARAMS*)lparam; + return WVR_REDRAW; + }*/ + + return DefWindowProc(WindowHandle, msg, wparam, lparam); +} + +void Win32Window::UpdateCursor() +{ + LPCWSTR cursor = IDC_ARROW; + switch (CurrentCursor) + { + case StandardCursor::arrow: cursor = IDC_ARROW; break; + case StandardCursor::appstarting: cursor = IDC_APPSTARTING; break; + case StandardCursor::cross: cursor = IDC_CROSS; break; + case StandardCursor::hand: cursor = IDC_HAND; break; + case StandardCursor::ibeam: cursor = IDC_IBEAM; break; + case StandardCursor::no: cursor = IDC_NO; break; + case StandardCursor::size_all: cursor = IDC_SIZEALL; break; + case StandardCursor::size_nesw: cursor = IDC_SIZENESW; break; + case StandardCursor::size_ns: cursor = IDC_SIZENS; break; + case StandardCursor::size_nwse: cursor = IDC_SIZENWSE; break; + case StandardCursor::size_we: cursor = IDC_SIZEWE; break; + case StandardCursor::uparrow: cursor = IDC_UPARROW; break; + case StandardCursor::wait: cursor = IDC_WAIT; break; + default: break; + } + + ::SetCursor((HCURSOR)LoadImage(0, cursor, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_SHARED)); +} + +Point Win32Window::GetLParamPos(LPARAM lparam) const +{ + double dpiscale = GetDpiScale(); + return Point(GET_X_LPARAM(lparam) / dpiscale, GET_Y_LPARAM(lparam) / dpiscale); +} + +LRESULT Win32Window::WndProc(HWND windowhandle, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_CREATE) + { + CREATESTRUCT* createstruct = (CREATESTRUCT*)lparam; + Win32Window* viewport = (Win32Window*)createstruct->lpCreateParams; + viewport->WindowHandle = windowhandle; + SetWindowLongPtr(windowhandle, GWLP_USERDATA, (LONG_PTR)viewport); + return viewport->OnWindowMessage(msg, wparam, lparam); + } + else + { + Win32Window* viewport = (Win32Window*)GetWindowLongPtr(windowhandle, GWLP_USERDATA); + if (viewport) + { + LRESULT result = viewport->OnWindowMessage(msg, wparam, lparam); + if (msg == WM_DESTROY) + { + SetWindowLongPtr(windowhandle, GWLP_USERDATA, 0); + viewport->WindowHandle = 0; + } + return result; + } + else + { + return DefWindowProc(windowhandle, msg, wparam, lparam); + } + } +} + +void Win32Window::ProcessEvents() +{ + while (true) + { + MSG msg = {}; + if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) <= 0) + break; + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void Win32Window::RunLoop() +{ + while (!ExitRunLoop && !Windows.empty()) + { + MSG msg = {}; + if (GetMessage(&msg, 0, 0, 0) <= 0) + break; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + ExitRunLoop = false; +} + +void Win32Window::ExitLoop() +{ + ExitRunLoop = true; +} + +Size Win32Window::GetScreenSize() +{ + HDC screenDC = GetDC(0); + int screenWidth = GetDeviceCaps(screenDC, HORZRES); + int screenHeight = GetDeviceCaps(screenDC, VERTRES); + double dpiScale = GetDeviceCaps(screenDC, LOGPIXELSX) / 96.0; + ReleaseDC(0, screenDC); + + return Size(screenWidth / dpiScale, screenHeight / dpiScale); +} + +static void CALLBACK Win32TimerCallback(HWND handle, UINT message, UINT_PTR timerID, DWORD timestamp) +{ + auto it = Win32Window::Timers.find(timerID); + if (it != Win32Window::Timers.end()) + { + it->second(); + } +} + +void* Win32Window::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + UINT_PTR result = SetTimer(0, 0, timeoutMilliseconds, Win32TimerCallback); + if (result == 0) + throw std::runtime_error("Could not create timer"); + Timers[result] = std::move(onTimer); + return (void*)result; +} + +void Win32Window::StopTimer(void* timerID) +{ + auto it = Timers.find((UINT_PTR)timerID); + if (it != Timers.end()) + { + Timers.erase(it); + KillTimer(0, (UINT_PTR)timerID); + } +} + +std::list Win32Window::Windows; +bool Win32Window::ExitRunLoop; + +std::unordered_map> Win32Window::Timers; diff --git a/libraries/ZWidget/src/window/win32/win32window.h b/libraries/ZWidget/src/window/win32/win32window.h new file mode 100644 index 00000000000..a0f493c8b2a --- /dev/null +++ b/libraries/ZWidget/src/window/win32/win32window.h @@ -0,0 +1,86 @@ +#pragma once + +#define NOMINMAX +#define WIN32_MEAN_AND_LEAN +#ifndef WINVER +#define WINVER 0x0605 +#endif +#include + +#include +#include +#include + +class Win32Window : public DisplayWindow +{ +public: + Win32Window(DisplayWindowHost* windowHost); + ~Win32Window(); + + void SetWindowTitle(const std::string& text) override; + void SetWindowFrame(const Rect& box) override; + void SetClientFrame(const Rect& box) override; + void Show() override; + void ShowFullscreen() override; + void ShowMaximized() override; + void ShowMinimized() override; + void ShowNormal() override; + void Hide() override; + void Activate() override; + void ShowCursor(bool enable) override; + void LockCursor() override; + void UnlockCursor() override; + void CaptureMouse() override; + void ReleaseMouseCapture() override; + void Update() override; + bool GetKeyState(EInputKey key) override; + + void SetCursor(StandardCursor cursor) override; + void UpdateCursor(); + + Rect GetWindowFrame() const override; + Size GetClientSize() const override; + int GetPixelWidth() const override; + int GetPixelHeight() const override; + double GetDpiScale() const override; + + void PresentBitmap(int width, int height, const uint32_t* pixels) override; + + void SetBorderColor(uint32_t bgra8) override; + void SetCaptionColor(uint32_t bgra8) override; + void SetCaptionTextColor(uint32_t bgra8) override; + + std::string GetClipboardText() override; + void SetClipboardText(const std::string& text) override; + + Point GetLParamPos(LPARAM lparam) const; + + static void ProcessEvents(); + static void RunLoop(); + static void ExitLoop(); + static Size GetScreenSize(); + + static void* StartTimer(int timeoutMilliseconds, std::function onTimer); + static void StopTimer(void* timerID); + + static bool ExitRunLoop; + static std::list Windows; + std::list::iterator WindowsIterator; + + static std::unordered_map> Timers; + + LRESULT OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam); + static LRESULT CALLBACK WndProc(HWND windowhandle, UINT msg, WPARAM wparam, LPARAM lparam); + + DisplayWindowHost* WindowHost = nullptr; + + HWND WindowHandle = 0; + bool Fullscreen = false; + + bool MouseLocked = false; + POINT MouseLockPos = {}; + + HDC PaintDC = 0; + + StandardCursor CurrentCursor = StandardCursor::arrow; +}; diff --git a/libraries/ZWidget/src/window/window.cpp b/libraries/ZWidget/src/window/window.cpp new file mode 100644 index 00000000000..b67b1a29677 --- /dev/null +++ b/libraries/ZWidget/src/window/window.cpp @@ -0,0 +1,120 @@ + +#include "window/window.h" +#include + +#ifdef _WIN32 + +#include "win32/win32window.h" + +std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost) +{ + return std::make_unique(windowHost); +} + +void DisplayWindow::ProcessEvents() +{ + Win32Window::ProcessEvents(); +} + +void DisplayWindow::RunLoop() +{ + Win32Window::RunLoop(); +} + +void DisplayWindow::ExitLoop() +{ + Win32Window::ExitLoop(); +} + +Size DisplayWindow::GetScreenSize() +{ + return Win32Window::GetScreenSize(); +} + +void* DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + return Win32Window::StartTimer(timeoutMilliseconds, std::move(onTimer)); +} + +void DisplayWindow::StopTimer(void* timerID) +{ + Win32Window::StopTimer(timerID); +} + +#elif defined(__APPLE__) + +std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost) +{ + throw std::runtime_error("DisplayWindow::Create not implemented"); +} + +void DisplayWindow::ProcessEvents() +{ + throw std::runtime_error("DisplayWindow::ProcessEvents not implemented"); +} + +void DisplayWindow::RunLoop() +{ + throw std::runtime_error("DisplayWindow::RunLoop not implemented"); +} + +void DisplayWindow::ExitLoop() +{ + throw std::runtime_error("DisplayWindow::ExitLoop not implemented"); +} + +Size DisplayWindow::GetScreenSize() +{ + throw std::runtime_error("DisplayWindow::GetScreenSize not implemented"); +} + +void* DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + throw std::runtime_error("DisplayWindow::StartTimer not implemented"); +} + +void DisplayWindow::StopTimer(void* timerID) +{ + throw std::runtime_error("DisplayWindow::StopTimer not implemented"); +} + +#else + +#include "sdl2/sdl2displaywindow.h" + +std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost) +{ + return std::make_unique(windowHost); +} + +void DisplayWindow::ProcessEvents() +{ + SDL2DisplayWindow::ProcessEvents(); +} + +void DisplayWindow::RunLoop() +{ + SDL2DisplayWindow::RunLoop(); +} + +void DisplayWindow::ExitLoop() +{ + SDL2DisplayWindow::ExitLoop(); +} + +Size DisplayWindow::GetScreenSize() +{ + return SDL2DisplayWindow::GetScreenSize(); +} + +void* DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + return SDL2DisplayWindow::StartTimer(timeoutMilliseconds, std::move(onTimer)); +} + +void DisplayWindow::StopTimer(void* timerID) +{ + SDL2DisplayWindow::StopTimer(timerID); +} + +#endif diff --git a/libraries/asmjit/CMakeLists.txt b/libraries/asmjit/CMakeLists.txt index 6b7636ebe98..4167e4c3372 100644 --- a/libraries/asmjit/CMakeLists.txt +++ b/libraries/asmjit/CMakeLists.txt @@ -1,5 +1,3 @@ -cmake_minimum_required(VERSION 2.8.7) - #make_release_only() project(asmjit C) diff --git a/libraries/asmjit/asmjit/asmjit_build.h b/libraries/asmjit/asmjit/asmjit_build.h index 77b151ac3a1..7a41a9e1cd3 100644 --- a/libraries/asmjit/asmjit/asmjit_build.h +++ b/libraries/asmjit/asmjit/asmjit_build.h @@ -819,11 +819,7 @@ // [@CC_FALLTHROUGH{@] // \def ASMJIT_FALLTHROUGH // The code falls through annotation (switch / case). -#if ASMJIT_CC_CLANG && __cplusplus >= 201103L -# define ASMJIT_FALLTHROUGH [[clang::fallthrough]] -#else -# define ASMJIT_FALLTHROUGH (void)0 -#endif +# define ASMJIT_FALLTHROUGH [[fallthrough]] // [@CC_FALLTHROUGH}@] // [@CC_UNUSED{@] diff --git a/libraries/bzip2/CMakeLists.txt b/libraries/bzip2/CMakeLists.txt index e01d5c09e3f..c42b46592c9 100644 --- a/libraries/bzip2/CMakeLists.txt +++ b/libraries/bzip2/CMakeLists.txt @@ -1,7 +1,9 @@ -cmake_minimum_required( VERSION 2.8.7 ) - make_release_only() +if (MSVC) + set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4244" ) +endif() + add_definitions( -DBZ_NO_STDIO ) add_library( bz2 STATIC blocksort.c @@ -11,4 +13,5 @@ add_library( bz2 STATIC decompress.c huffman.c randtable.c ) +link_libraries("-static") target_link_libraries( bz2 ) diff --git a/libraries/discordrpc/.clang-format b/libraries/discordrpc/.clang-format new file mode 100644 index 00000000000..1be83906c78 --- /dev/null +++ b/libraries/discordrpc/.clang-format @@ -0,0 +1,92 @@ +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: true +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Stroustrup +BreakBeforeInheritanceComma: true +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +FixNamespaceComments: true +ForEachMacros: [] +IndentCaseLabels: false +IncludeCategories: + - Regex: '^("|<)stdafx\.h(pp)?("|>)' + Priority: -1 + - Regex: '^<(W|w)indows.h>' + Priority: 1 + - Regex: '^<' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '(_test|_win|_linux|_mac|_ios|_osx|_null)?$' +IndentCaseLabels: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakAssignment: 0 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 9999999 +PointerAlignment: Left +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +--- +Language: Cpp +--- +Language: ObjC +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: false +--- +Language: Java +BasedOnStyle: Google +BreakAfterJavaFieldAnnotations: true +... diff --git a/libraries/discordrpc/.gitignore b/libraries/discordrpc/.gitignore new file mode 100644 index 00000000000..223c07d7068 --- /dev/null +++ b/libraries/discordrpc/.gitignore @@ -0,0 +1,5 @@ +/build*/ +/.vscode/ +/thirdparty/ +.vs/ +.DS_Store \ No newline at end of file diff --git a/libraries/discordrpc/.travis.yml b/libraries/discordrpc/.travis.yml new file mode 100644 index 00000000000..42cc09d5ba5 --- /dev/null +++ b/libraries/discordrpc/.travis.yml @@ -0,0 +1,47 @@ +language: cpp + +env: + global: + - CLANG_FORMAT_SUFFIX="-dummy" # don't use formatting on Travis, this is + # needed not to use default 3.5 version + # which is too old. + +matrix: + include: + - os: linux + env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + - os: linux + env: MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0" + addons: + apt: + sources: + - llvm-toolchain-trusty-4.0 + packages: + - clang-4.0 + - os: linux + env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" + addons: + apt: + sources: + - llvm-toolchain-trusty-5.0 + packages: + - clang-5.0 + - os: osx + osx_image: xcode9 + +# prevent Travis from overwriting our CXX variables +before_install: + - eval "${MATRIX_EVAL}" + - echo $CXX + +script: + - mkdir build + - cd build + - cmake -DCLANG_FORMAT_SUFFIX=$CLANG_FORMAT_SUFFIX -DWARNINGS_AS_ERRORS=On --config Release .. + - cmake --build . -- -j2 diff --git a/libraries/discordrpc/CMakeLists.txt b/libraries/discordrpc/CMakeLists.txt new file mode 100644 index 00000000000..2c417721a32 --- /dev/null +++ b/libraries/discordrpc/CMakeLists.txt @@ -0,0 +1,15 @@ +project (DiscordRPC) + +include(GNUInstallDirs) + +# format +file(GLOB_RECURSE ALL_SOURCE_FILES + include/*.h + src/*.cpp src/*.h src/*.c +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../src/common/thirdparty) + +# add subdirs + +add_subdirectory(src) diff --git a/libraries/discordrpc/LICENSE b/libraries/discordrpc/LICENSE new file mode 100644 index 00000000000..17fca3d50f9 --- /dev/null +++ b/libraries/discordrpc/LICENSE @@ -0,0 +1,19 @@ +Copyright 2017 Discord, Inc. + +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/libraries/discordrpc/README.md b/libraries/discordrpc/README.md new file mode 100644 index 00000000000..1285fb844dc --- /dev/null +++ b/libraries/discordrpc/README.md @@ -0,0 +1,158 @@ +# Discord RPC + +## Deprecation Notice + +This library has been deprecated in favor of Discord's GameSDK. [Learn more here](https://discordapp.com/developers/docs/game-sdk/sdk-starter-guide) + +--- + +This is a library for interfacing your game with a locally running Discord desktop client. It's known to work on Windows, macOS, and Linux. You can use the lib directly if you like, or use it as a guide to writing your own if it doesn't suit your game as is. PRs/feedback welcome if you have an improvement everyone might want, or can describe how this doesn't meet your needs. + +Included here are some quick demos that implement the very minimal subset to show current status, and +have callbacks for where a more complete game would do more things (joining, spectating, etc). + +## Documentation + +The most up to date documentation for Rich Presence can always be found on our [developer site](https://discordapp.com/developers/docs/rich-presence/how-to)! If you're interested in rolling your own native implementation of Rich Presence via IPC sockets instead of using our SDK—hey, you've got free time, right?—check out the ["Hard Mode" documentation](https://github.com/discordapp/discord-rpc/blob/master/documentation/hard-mode.md). + +## Basic Usage + +Zeroith, you should be set up to build things because you are a game developer, right? + +First, head on over to the [Discord developers site](https://discordapp.com/developers/applications/me) and make yourself an app. Keep track of `Client ID` -- you'll need it here to pass to the init function. + +### Unreal Engine 4 Setup + +To use the Rich Presense plugin with Unreal Engine Projects: + +1. Download the latest [release](https://github.com/discordapp/discord-rpc/releases) for each operating system you are targeting and the zipped source code +2. In the source code zip, copy the UE plugin—`examples/unrealstatus/Plugins/discordrpc`—to your project's plugin directory +3. At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create an `Include` folder and copy `discord_rpc.h` and `discord_register.h` to it from the zip +4. Follow the steps below for each OS +5. Build your UE4 project +6. Launch the editor, and enable the Discord plugin. + +#### Windows + +- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Win64` folder +- Copy `lib/discord-rpc.lib` and `bin/discord-rpc.dll` from `[RELEASE_ZIP]/win64-dynamic` to the `Win64` folder + +#### Mac + +- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Mac` folder +- Copy `libdiscord-rpc.dylib` from `[RELEASE_ZIP]/osx-dynamic/lib` to the `Mac` folder + +#### Linux + +- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Linux` folder +- Inside, create another folder `x86_64-unknown-linux-gnu` +- Copy `libdiscord-rpc.so` from `[RELEASE_ZIP]/linux-dynamic/lib` to `Linux/x86_64-unknown-linux-gnu` + +### Unity Setup + +If you're a Unity developer looking to integrate Rich Presence into your game, follow this simple guide to get started towards success: + +1. Download the DLLs for any platform that you need from [our releases](https://github.com/discordapp/discord-rpc/releases) +2. In your Unity project, create a `Plugins` folder inside your `Assets` folder if you don't already have one +3. Copy the file `DiscordRpc.cs` from [here](https://github.com/discordapp/discord-rpc/blob/master/examples/button-clicker/Assets/DiscordRpc.cs) into your `Assets` folder. This is basically your header file for the SDK + +We've got our `Plugins` folder ready, so let's get platform-specific! + +#### Windows + +4. Create `x86` and `x86_64` folders inside `Assets/Plugins/` +5. Copy `discord-rpc-win/win64-dynamic/bin/discord-rpc.dll` to `Assets/Plugins/x86_64/` +6. Copy `discord-rpc-win/win32-dynamic/bin/discord-rpc.dll` to `Assets/Plugins/x86/` +7. Click on both DLLs and make sure they are targetting the correct architectures in the Unity editor properties pane +8. Done! + +#### MacOS + +4. Copy `discord-rpc-osx/osx-dynamic/lib/libdiscord-rpc.dylib` to `Assets/Plugins/` +5. Rename `libdiscord-rpc.dylib` to `discord-rpc.bundle` +6. Done! + +#### Linux + +4. Copy `discord-rpc-linux/linux-dynamic-lib/libdiscord-rpc.so` to `Assets/Plugins/` +5. Done! + +You're ready to roll! For code examples on how to interact with the SDK using the `DiscordRpc.cs` header file, check out [our example](https://github.com/discordapp/discord-rpc/blob/master/examples/button-clicker/Assets/DiscordController.cs) + +### From package + +Download a release package for your platform(s) -- they have subdirs with various prebuilt options, select the one you need add `/include` to your compile includes, `/lib` to your linker paths, and link with `discord-rpc`. For the dynamically linked builds, you'll need to ship the associated file along with your game. + +### From repo + +First-eth, you'll want `CMake`. There's a few different ways to install it on your system, and you should refer to [their website](https://cmake.org/install/). Many package managers provide ways of installing CMake as well. + +To make sure it's installed correctly, type `cmake --version` into your flavor of terminal/cmd. If you get a response with a version number, you're good to go! + +There's a [CMake](https://cmake.org/download/) file that should be able to generate the lib for you; Sometimes I use it like this: + +```sh + cd + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX= + cmake --build . --config Release --target install +``` + +There is a wrapper build script `build.py` that runs `cmake` with a few different options. + +Usually, I run `build.py` to get things started, then use the generated project files as I work on things. It does depend on `click` library, so do a quick `pip install click` to make sure you have it if you want to run `build.py`. + +There are some CMake options you might care about: + +| flag | default | does | +| ---------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ENABLE_IO_THREAD` | `ON` | When enabled, we start up a thread to do io processing, if disabled you should call `Discord_UpdateConnection` yourself. | +| `USE_STATIC_CRT` | `OFF` | (Windows) Enable to statically link the CRT, avoiding requiring users install the redistributable package. (The prebuilt binaries enable this option) | +| [`BUILD_SHARED_LIBS`](https://cmake.org/cmake/help/v3.7/variable/BUILD_SHARED_LIBS.html) | `OFF` | Build library as a DLL | +| `WARNINGS_AS_ERRORS` | `OFF` | When enabled, compiles with `-Werror` (on \*nix platforms). | + +## Continuous Builds + +Why do we have three of these? Three times the fun! + +| CI | badge | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| TravisCI | [![Build status](https://travis-ci.org/discordapp/discord-rpc.svg?branch=master)](https://travis-ci.org/discordapp/discord-rpc) | +| AppVeyor | [![Build status](https://ci.appveyor.com/api/projects/status/qvkoc0w1c4f4b8tj?svg=true)](https://ci.appveyor.com/project/crmarsh/discord-rpc) | +| Buildkite (internal) | [![Build status](https://badge.buildkite.com/e103d79d247f6776605a15246352a04b8fd83d69211b836111.svg)](https://buildkite.com/discord/discord-rpc) | + +## Sample: send-presence + +This is a text adventure "game" that inits/deinits the connection to Discord, and sends a presence update on each command. + +## Sample: button-clicker + +This is a sample [Unity](https://unity3d.com/) project that wraps a DLL version of the library, and sends presence updates when you click on a button. Run `python build.py unity` in the root directory to build the correct library files and place them in their respective folders. + +## Sample: unrealstatus + +This is a sample [Unreal](https://www.unrealengine.com) project that wraps the DLL version of the library with an Unreal plugin, exposes a blueprint class for interacting with it, and uses that to make a very simple UI. Run `python build.py unreal` in the root directory to build the correct library files and place them in their respective folders. + +## Wrappers and Implementations + +Below is a table of unofficial, community-developed wrappers for and implementations of Rich Presence in various languages. If you would like to have yours added, please make a pull request adding your repository to the table. The repository should include: + +- The code +- A brief ReadMe of how to use it +- A working example + +###### Rich Presence Wrappers and Implementations + +| Name | Language | +| ------------------------------------------------------------------------- | --------------------------------- | +| [Discord RPC C#](https://github.com/Lachee/discord-rpc-csharp) | C# | +| [Discord RPC D](https://github.com/voidblaster/discord-rpc-d) | [D](https://dlang.org/) | +| [discord-rpc.jar](https://github.com/Vatuu/discord-rpc 'Discord-RPC.jar') | Java | +| [java-discord-rpc](https://github.com/MinnDevelopment/java-discord-rpc) | Java | +| [Discord-IPC](https://github.com/jagrosh/DiscordIPC) | Java | +| [Discord Rich Presence](https://npmjs.org/discord-rich-presence) | JavaScript | +| [drpc4k](https://github.com/Bluexin/drpc4k) | [Kotlin](https://kotlinlang.org/) | +| [lua-discordRPC](https://github.com/pfirsich/lua-discordRPC) | LuaJIT (FFI) | +| [pypresence](https://github.com/qwertyquerty/pypresence) | [Python](https://python.org/) | +| [SwordRPC](https://github.com/Azoy/SwordRPC) | [Swift](https://swift.org) | diff --git a/libraries/discordrpc/appveyor.yml b/libraries/discordrpc/appveyor.yml new file mode 100644 index 00000000000..1c328b87875 --- /dev/null +++ b/libraries/discordrpc/appveyor.yml @@ -0,0 +1,17 @@ +version: '{build}' +install: + - python -m pip install click + +build_script: + - mkdir examples\unrealstatus\Plugins\discordrpc\Binaries\ThirdParty\discordrpcLibrary\Win64 + - python build.py + +artifacts: +- path: builds\install\win32-dynamic + name: win32-dynamic +- path: builds\install\win32-static + name: win32-static +- path: builds\install\win64-dynamic + name: win64-dynamic +- path: builds\install\win64-static + name: win64-static diff --git a/libraries/discordrpc/build.py b/libraries/discordrpc/build.py new file mode 100644 index 00000000000..215d3586b31 --- /dev/null +++ b/libraries/discordrpc/build.py @@ -0,0 +1,304 @@ +#!/usr/bin/env python + +import os +import subprocess +import sys +import shutil +import zipfile +from contextlib import contextmanager +import click + + +def get_platform(): + """ a name for the platform """ + if sys.platform.startswith('win'): + return 'win' + elif sys.platform == 'darwin': + return 'osx' + elif sys.platform.startswith('linux'): + return 'linux' + raise Exception('Unsupported platform ' + sys.platform) + + +SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__)) +# we use Buildkite which sets this env variable by default +IS_BUILD_MACHINE = os.environ.get('CI', '') == 'true' +PLATFORM = get_platform() +INSTALL_ROOT = os.path.join(SCRIPT_PATH, 'builds', 'install') + + +def get_signtool(): + """ get path to code signing tool """ + if PLATFORM == 'win': + sdk_dir = 'c:\\Program Files (x86)\\Windows Kits\\10' # os.environ['WindowsSdkDir'] + return os.path.join(sdk_dir, 'bin', 'x86', 'signtool.exe') + elif PLATFORM == 'osx': + return '/usr/bin/codesign' + + +@contextmanager +def cd(new_dir): + """ Temporarily change current directory """ + if new_dir: + old_dir = os.getcwd() + os.chdir(new_dir) + yield + if new_dir: + os.chdir(old_dir) + + +def mkdir_p(path): + """ mkdir -p """ + if not os.path.isdir(path): + click.secho('Making ' + path, fg='yellow') + os.makedirs(path) + + +@click.group(invoke_without_command=True) +@click.pass_context +@click.option('--clean', is_flag=True) +def cli(ctx, clean): + """ click wrapper for command line stuff """ + if ctx.invoked_subcommand is None: + ctx.invoke(libs, clean=clean) + if IS_BUILD_MACHINE: + ctx.invoke(sign) + ctx.invoke(archive) + + +@cli.command() +@click.pass_context +def unity(ctx): + """ build just dynamic libs for use in unity project """ + ctx.invoke(libs, clean=False, static=False, shared=True, skip_formatter=True, just_release=True) + BUILDS = [] + + click.echo('--- Copying libs and header into unity example') + UNITY_PROJECT_PATH = os.path.join(SCRIPT_PATH, 'examples', 'button-clicker', 'Assets', 'Plugins') + + if sys.platform.startswith('win'): + LIBRARY_NAME = 'discord-rpc.dll' + BUILD_64_BASE_PATH = os.path.join(SCRIPT_PATH, 'builds', 'win64-dynamic', 'src', 'Release') + UNITY_64_DLL_PATH = os.path.join(UNITY_PROJECT_PATH, 'x86_64') + BUILDS.append({BUILD_64_BASE_PATH: UNITY_64_DLL_PATH}) + + BUILD_32_BASE_PATH = os.path.join(SCRIPT_PATH, 'builds', 'win32-dynamic', 'src', 'Release') + UNITY_32_DLL_PATH = os.path.join(UNITY_PROJECT_PATH, 'x86') + BUILDS.append({BUILD_32_BASE_PATH: UNITY_32_DLL_PATH}) + + elif sys.platform == 'darwin': + LIBRARY_NAME = 'discord-rpc.bundle' + BUILD_BASE_PATH = os.path.join(SCRIPT_PATH, 'builds', 'osx-dynamic', 'src') + UNITY_DLL_PATH = UNITY_PROJECT_PATH + os.rename( + os.path.join(BUILD_BASE_PATH, 'libdiscord-rpc.dylib'), os.path.join(BUILD_BASE_PATH, 'discord-rpc.bundle')) + + BUILDS.append({BUILD_BASE_PATH: UNITY_DLL_PATH}) + + elif sys.platform.startswith('linux'): + LIBRARY_NAME = 'discord-rpc.so' + BUILD_BASE_PATH = os.path.join(SCRIPT_PATH, 'builds', 'linux-dynamic', 'src') + UNITY_DLL_PATH = os.path.join(UNITY_PROJECT_PATH, 'x86') + os.rename(os.path.join(BUILD_BASE_PATH, 'libdiscord-rpc.so'), os.path.join(BUILD_BASE_PATH, 'discord-rpc.so')) + + BUILDS.append({BUILD_BASE_PATH: UNITY_DLL_PATH}) + + else: + raise Exception('Unsupported platform ' + sys.platform) + + for build in BUILDS: + for i in build: + mkdir_p(build[i]) + shutil.copy(os.path.join(i, LIBRARY_NAME), build[i]) + + +@cli.command() +@click.pass_context +def unreal(ctx): + """ build libs and copy them into the unreal project """ + ctx.invoke(libs, clean=False, static=False, shared=True, skip_formatter=True, just_release=True) + BUILDS = [] + + click.echo('--- Copying libs and header into unreal example') + UNREAL_PROJECT_PATH = os.path.join(SCRIPT_PATH, 'examples', 'unrealstatus', 'Plugins', 'discordrpc') + UNREAL_INCLUDE_PATH = os.path.join(UNREAL_PROJECT_PATH, 'Source', 'ThirdParty', 'DiscordRpcLibrary', 'Include') + mkdir_p(UNREAL_INCLUDE_PATH) + shutil.copy(os.path.join(SCRIPT_PATH, 'include', 'discord_rpc.h'), UNREAL_INCLUDE_PATH) + + if sys.platform.startswith('win'): + LIBRARY_NAME = 'discord-rpc.lib' + BUILD_64_BASE_PATH = os.path.join(SCRIPT_PATH, 'builds', 'win64-dynamic', 'src', 'Release') + UNREAL_64_DLL_PATH = os.path.join(UNREAL_PROJECT_PATH, 'Source', 'ThirdParty', 'DiscordRpcLibrary', 'Win64') + BUILDS.append({BUILD_64_BASE_PATH: UNREAL_64_DLL_PATH}) + + BUILD_32_BASE_PATH = os.path.join(SCRIPT_PATH, 'builds', 'win32-dynamic', 'src', 'Release') + UNREAL_32_DLL_PATH = os.path.join(UNREAL_PROJECT_PATH, 'Source', 'ThirdParty', 'DiscordRpcLibrary', 'Win32') + BUILDS.append({BUILD_32_BASE_PATH: UNREAL_32_DLL_PATH}) + + elif sys.platform == 'darwin': + LIBRARY_NAME = 'libdiscord-rpc.dylib' + BUILD_BASE_PATH = os.path.join(SCRIPT_PATH, 'builds', 'osx-dynamic', 'src') + UNREAL_DLL_PATH = os.path.join(UNREAL_PROJECT_PATH, 'Source', 'ThirdParty', 'DiscordRpcLibrary', 'Mac') + + BUILDS.append({BUILD_BASE_PATH: UNREAL_DLL_PATH}) + + elif sys.platform.startswith('linux'): + LIBRARY_NAME = 'libdiscord-rpc.so' + BUILD_BASE_PATH = os.path.join(SCRIPT_PATH, 'builds', 'linux-dynamic', 'src') + UNREAL_DLL_PATH = os.path.join(UNREAL_PROJECT_PATH, 'Source', 'ThirdParty', 'DiscordRpcLibrary', 'Linux') + + BUILDS.append({BUILD_BASE_PATH: UNREAL_DLL_PATH}) + + else: + raise Exception('Unsupported platform ' + sys.platform) + + for build in BUILDS: + for i in build: + mkdir_p(build[i]) + shutil.copy(os.path.join(i, LIBRARY_NAME), build[i]) + + +def build_lib(build_name, generator, options, just_release): + """ Create a dir under builds, run build and install in it """ + build_path = os.path.join(SCRIPT_PATH, 'builds', build_name) + install_path = os.path.join(INSTALL_ROOT, build_name) + mkdir_p(build_path) + mkdir_p(install_path) + with cd(build_path): + initial_cmake = ['cmake', SCRIPT_PATH, '-DCMAKE_INSTALL_PREFIX=%s' % os.path.join('..', 'install', build_name)] + if generator: + initial_cmake.extend(['-G', generator]) + for key in options: + val = options[key] + if type(val) is bool: + val = 'ON' if val else 'OFF' + initial_cmake.append('-D%s=%s' % (key, val)) + click.echo('--- Building ' + build_name) + subprocess.check_call(initial_cmake) + if not just_release: + subprocess.check_call(['cmake', '--build', '.', '--config', 'Debug']) + subprocess.check_call(['cmake', '--build', '.', '--config', 'Release', '--target', 'install']) + + +@cli.command() +def archive(): + """ create zip of install dir """ + click.echo('--- Archiving') + archive_file_path = os.path.join(SCRIPT_PATH, 'builds', 'discord-rpc-%s.zip' % get_platform()) + archive_file = zipfile.ZipFile(archive_file_path, 'w', zipfile.ZIP_DEFLATED) + archive_src_base_path = INSTALL_ROOT + archive_dst_base_path = 'discord-rpc' + with cd(archive_src_base_path): + for path, _, filenames in os.walk('.'): + for fname in filenames: + fpath = os.path.join(path, fname) + dst_path = os.path.normpath(os.path.join(archive_dst_base_path, fpath)) + click.echo('Adding ' + dst_path) + archive_file.write(fpath, dst_path) + + +@cli.command() +def sign(): + """ Do code signing within install directory using our cert """ + tool = get_signtool() + signable_extensions = set() + if PLATFORM == 'win': + signable_extensions.add('.dll') + sign_command_base = [ + tool, + 'sign', + '/n', + 'Discord Inc.', + '/a', + '/tr', + 'http://timestamp.digicert.com/rfc3161', + '/as', + '/td', + 'sha256', + '/fd', + 'sha256', + ] + elif PLATFORM == 'osx': + signable_extensions.add('.dylib') + sign_command_base = [ + tool, + '--keychain', + os.path.expanduser('~/Library/Keychains/login.keychain'), + '-vvvv', + '--deep', + '--force', + '--sign', + 'Developer ID Application: Hammer & Chisel Inc. (53Q6R32WPB)', + ] + else: + click.secho('Not signing things on this platform yet', fg='red') + return + + click.echo('--- Signing') + for path, _, filenames in os.walk(INSTALL_ROOT): + for fname in filenames: + ext = os.path.splitext(fname)[1] + if ext not in signable_extensions: + continue + fpath = os.path.join(path, fname) + click.echo('Sign ' + fpath) + sign_command = sign_command_base + [fpath] + subprocess.check_call(sign_command) + + +@cli.command() +@click.option('--clean', is_flag=True) +@click.option('--static', is_flag=True) +@click.option('--shared', is_flag=True) +@click.option('--skip_formatter', is_flag=True) +@click.option('--just_release', is_flag=True) +def libs(clean, static, shared, skip_formatter, just_release): + """ Do all the builds for this platform """ + if clean: + shutil.rmtree('builds', ignore_errors=True) + + mkdir_p('builds') + + if not (static or shared): + static = True + shared = True + + static_options = {} + dynamic_options = { + 'BUILD_SHARED_LIBS': True, + 'USE_STATIC_CRT': True, + } + + if skip_formatter or IS_BUILD_MACHINE: + static_options['CLANG_FORMAT_SUFFIX'] = 'none' + dynamic_options['CLANG_FORMAT_SUFFIX'] = 'none' + + if IS_BUILD_MACHINE: + just_release = True + static_options['WARNINGS_AS_ERRORS'] = True + dynamic_options['WARNINGS_AS_ERRORS'] = True + + if PLATFORM == 'win': + generator32 = 'Visual Studio 14 2015' + generator64 = 'Visual Studio 14 2015 Win64' + if static: + build_lib('win32-static', generator32, static_options, just_release) + build_lib('win64-static', generator64, static_options, just_release) + if shared: + build_lib('win32-dynamic', generator32, dynamic_options, just_release) + build_lib('win64-dynamic', generator64, dynamic_options, just_release) + elif PLATFORM == 'osx': + if static: + build_lib('osx-static', None, static_options, just_release) + if shared: + build_lib('osx-dynamic', None, dynamic_options, just_release) + elif PLATFORM == 'linux': + if static: + build_lib('linux-static', None, static_options, just_release) + if shared: + build_lib('linux-dynamic', None, dynamic_options, just_release) + + +if __name__ == '__main__': + os.chdir(SCRIPT_PATH) + sys.exit(cli()) diff --git a/libraries/discordrpc/documentation/hard-mode.md b/libraries/discordrpc/documentation/hard-mode.md new file mode 100644 index 00000000000..35042cbcbed --- /dev/null +++ b/libraries/discordrpc/documentation/hard-mode.md @@ -0,0 +1,164 @@ +# Hard Mode: Roll Your Own Client + +Discord's Rich Presence feature is designed as an obfuscated addition to our existing [RPC infrastructure](https://discordapp.com/developers/docs/topics/rpc). The standalone library and header files make it easy for any dev to drop it into their game. + +Our library communicates with Discord over the local Discord RPC socket. We've already done the work in connecting properly, handling disconnects and reconnects, and other RPC intracacies, but those who have done this implementation for our private alpha Voice and Chat SDK can simply make use of the new RPC commands and events to implement Rich Presence. + +## Hark! A warning! + +By committing to an RPC-only integration, you decide to forego the work our library and header file have done for you in the way of error handling, state storage, disconnecting and reconnecting, and other quality of life abstractions. While simply implementing the new RPC command and events will enable Rich Presence for your game, we highly suggest that you do your best to mimic the functionality of the SDK the most that you can. It ensure not only code quality on your part, but also an excellent experience on the part of your players. + +## Application Protocol Registration + +One thing that cannot be explicitly done over RPC is registering an application protocol for your game. If you choose to do an RPC-only implementation, you will have to register your application protocol yourself in the format of `discord-[your_app_id]://`. You can use `Discord_Register()` as a good(?) example of how to properly register an application protocol for use with Discord. For OSX and Linux it is probably simpler to handle the protocol registration as part of your install/packaging. + +## New RPC Command + +The new RPC command for Rich Presence is `SET_ACTIVITY`. The fields are similar to what is outlined in the SDK; we've combined similar fields into objects for the sake of less data on the wire. + +The one major difference is the `party.size` field. It is an array with a size of two. The first element is the current party size, `partySize` from the main documentation. The second element is the maximum party size, `partyMax` from the main documentation. + +Below is a full example of a `SET_ACTIVITY` command. Field restrictions like size are the same as outlined in the main documentation. + +``` +{ + "cmd": "SET_ACTIVITY", + "args": { + "pid": 9999, // Your application's process id - required field + "activity": { + "state": "In a Group", + "details": "Competitive | In a Match", + "timestamps": { + "start": time(nullptr), + "end": time(nullptr) + ((60 * 5) + 23) + }, + "assets": { + "large_image": "numbani_map", + "large_text": "Numbani", + "small_image": "pharah_profile", + "small_text": "Pharah" + }, + "party": { + "id": GameEngine.GetPartyId(), + "size": [3, 6] + }, + "secrets": { + "join": "025ed05c71f639de8bfaa0d679d7c94b2fdce12f", + "spectate": "e7eb30d2ee025ed05c71ea495f770b76454ee4e0", + "match": "4b2fdce12f639de8bfa7e3591b71a0d679d7c93f" + }, + "instance": true + } + }, + "nonce": "647d814a-4cf8-4fbb-948f-898abd24f55b" +} +``` + +## New RPC Events + +The three new RPC events for Rich Presence power the ability to join and spectate your friends' games. + +First is the `ACTIVITY_JOIN` event: + +```json +{ + "cmd": "DISPATCH", + "data": { + "secret": "025ed05c71f639de8bfaa0d679d7c94b2fdce12f" + }, + "evt": "ACTIVITY_JOIN" +} +``` + +Second is the `ACTIVITY_SPECTATE` event: + +```json +{ + "cmd": "DISPATCH", + "data": { + "secret": "e7eb30d2ee025ed05c71ea495f770b76454ee4e0" + }, + "evt": "ACTIVITY_SPECTATE" +} +``` + +And third is the `ACTIVITY_JOIN_REQUEST` event: + +```json +{ + "cmd": "DISPATCH", + "data": { + "user": { + "id": "53908232506183680", + "username": "Mason", + "discriminator": "1337", + "avatar": "a_bab14f271d565501444b2ca3be944b25" + } + }, + "evt": "ACTIVITY_JOIN_REQUEST" +} +``` + +In order to receive these events, you need to [subscribe](https://discordapp.com/developers/docs/topics/rpc#subscribe) to them like so: + +```json +{ + "nonce": "be9a6de3-31d0-4767-a8e9-4818c5690015", + "evt": "ACTIVITY_JOIN", + "cmd": "SUBSCRIBE" +} +``` + +```json +{ + "nonce": "ae9qdde3-31d0-8989-a8e9-dnakwy174he", + "evt": "ACTIVITY_SPECTATE", + "cmd": "SUBSCRIBE" +} +``` + +```json +{ + "nonce": "5dc0c062-98c6-47a0-8922-bbb52e9d6afa", + "evt": "ACTIVITY_JOIN_REQUEST", + "cmd": "SUBSCRIBE" +} +``` + +To unsubscribe from these events, resend with the command `UNSUBSCRIBE` + +## Responding +A discord user will request access to the game. If the ACTIVITY_JOIN_REQUEST has been subscribed too, the ACTIVITY_JOIN_REQUEST event will be sent to the host's game. Accept it with following model: +```json +{ + "nonce": "5dc0c062-98c6-47a0-8922-15aerg126", + "cmd": "SEND_ACTIVITY_JOIN_INVITE", + "args": + { + "user_id": "53908232506183680" + } +} +``` + +To reject the request, use `CLOSE_ACTIVITY_REQUEST`: +```json +{ + "nonce": "5dc0c062-98c6-47a0-8922-dasg256eafg", + "cmd": "CLOSE_ACTIVITY_REQUEST", + "args": + { + "user_id": "53908232506183680" + } +} +``` + +## Notes +Here are just some quick notes to help with some common troubleshooting problems. +* IPC will echo back every command you send as a response. Use this as a lock-step feature to avoid flooding messages. Can be used to validate messages such as the Presence or Subscribes. +* The pipe expects for frames to be written in a single byte array. You cannot do multiple `stream.Write(opcode);` `stream.Write(length);` as it will break the pipe. Instead create a buffer, write the data to the buffer, then send the entire buffer to the stream. +* Discord can be on any pipe ranging from `discord-ipc-0` to `discord-ipc-9`. It is a good idea to try and connect to each one and keeping the first one you connect too. For multiple clients (eg Discord and Canary), you might want to add a feature to manually select the pipe so you can more easily debug the application. +* All enums are `lower_snake_case`. +* The opcode and length in the header are `Little Endian Unsigned Integers (32bits)`. In some languages, you must convert them as they can be architecture specific. +* [Discord Rich Presence How-To](https://discordapp.com/developers/docs/rich-presence/how-to) contains a lot of the information this document doesn't. For example, it will tell you about the response payload. +* In the documentation, DISCORD_REPLY_IGNORE is just implemented the same as DISCORD_REPLY_NO. +* You can test the Join / Spectate feature by enabling them in your profile and whitelisting a test account. Use Canary to run 2 accounts on the same machine. diff --git a/libraries/discordrpc/documentation/images/rp-dev-dashboard.png b/libraries/discordrpc/documentation/images/rp-dev-dashboard.png new file mode 100644 index 00000000000..f246cfb2dda Binary files /dev/null and b/libraries/discordrpc/documentation/images/rp-dev-dashboard.png differ diff --git a/libraries/discordrpc/documentation/images/rp-profile-view.png b/libraries/discordrpc/documentation/images/rp-profile-view.png new file mode 100644 index 00000000000..f9ddc31304c Binary files /dev/null and b/libraries/discordrpc/documentation/images/rp-profile-view.png differ diff --git a/libraries/discordrpc/documentation/images/rp-secret-example.png b/libraries/discordrpc/documentation/images/rp-secret-example.png new file mode 100644 index 00000000000..4ff21b093fc Binary files /dev/null and b/libraries/discordrpc/documentation/images/rp-secret-example.png differ diff --git a/libraries/discordrpc/include/discord_register.h b/libraries/discordrpc/include/discord_register.h new file mode 100644 index 00000000000..16fb42f3289 --- /dev/null +++ b/libraries/discordrpc/include/discord_register.h @@ -0,0 +1,26 @@ +#pragma once + +#if defined(DISCORD_DYNAMIC_LIB) +#if defined(_WIN32) +#if defined(DISCORD_BUILDING_SDK) +#define DISCORD_EXPORT __declspec(dllexport) +#else +#define DISCORD_EXPORT __declspec(dllimport) +#endif +#else +#define DISCORD_EXPORT __attribute__((visibility("default"))) +#endif +#else +#define DISCORD_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command); +DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId); + +#ifdef __cplusplus +} +#endif diff --git a/libraries/discordrpc/include/discord_rpc.h b/libraries/discordrpc/include/discord_rpc.h new file mode 100644 index 00000000000..9470434a849 --- /dev/null +++ b/libraries/discordrpc/include/discord_rpc.h @@ -0,0 +1,90 @@ +#pragma once +#include + +// clang-format off + +#if defined(DISCORD_DYNAMIC_LIB) +# if defined(_WIN32) +# if defined(DISCORD_BUILDING_SDK) +# define DISCORD_EXPORT __declspec(dllexport) +# else +# define DISCORD_EXPORT __declspec(dllimport) +# endif +# else +# define DISCORD_EXPORT __attribute__((visibility("default"))) +# endif +#else +# define DISCORD_EXPORT +#endif + +// clang-format on + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DiscordRichPresence { + const char* state; /* max 128 bytes */ + const char* details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char* largeImageKey; /* max 32 bytes */ + const char* largeImageText; /* max 128 bytes */ + const char* smallImageKey; /* max 32 bytes */ + const char* smallImageText; /* max 128 bytes */ + const char* partyId; /* max 128 bytes */ + int partySize; + int partyMax; + int partyPrivacy; + const char* matchSecret; /* max 128 bytes */ + const char* joinSecret; /* max 128 bytes */ + const char* spectateSecret; /* max 128 bytes */ + int8_t instance; +} DiscordRichPresence; + +typedef struct DiscordUser { + const char* userId; + const char* username; + const char* discriminator; + const char* avatar; +} DiscordUser; + +typedef struct DiscordEventHandlers { + void (*ready)(const DiscordUser* request); + void (*disconnected)(int errorCode, const char* message); + void (*errored)(int errorCode, const char* message); + void (*joinGame)(const char* joinSecret); + void (*spectateGame)(const char* spectateSecret); + void (*joinRequest)(const DiscordUser* request); +} DiscordEventHandlers; + +#define DISCORD_REPLY_NO 0 +#define DISCORD_REPLY_YES 1 +#define DISCORD_REPLY_IGNORE 2 +#define DISCORD_PARTY_PRIVATE 0 +#define DISCORD_PARTY_PUBLIC 1 + +DISCORD_EXPORT void Discord_Initialize(const char* applicationId, + DiscordEventHandlers* handlers, + int autoRegister, + const char* optionalSteamId); +DISCORD_EXPORT void Discord_Shutdown(void); + +/* checks for incoming messages, dispatches callbacks */ +DISCORD_EXPORT void Discord_RunCallbacks(void); + +/* If you disable the lib starting its own io thread, you'll need to call this from your own */ +#ifdef DISCORD_DISABLE_IO_THREAD +DISCORD_EXPORT void Discord_UpdateConnection(void); +#endif + +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); +DISCORD_EXPORT void Discord_ClearPresence(void); + +DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); + +DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers); + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/libraries/discordrpc/src/CMakeLists.txt b/libraries/discordrpc/src/CMakeLists.txt new file mode 100644 index 00000000000..34aca1e4b1d --- /dev/null +++ b/libraries/discordrpc/src/CMakeLists.txt @@ -0,0 +1,141 @@ +include_directories(${PROJECT_SOURCE_DIR}/include) + +option(ENABLE_IO_THREAD "Start up a separate I/O thread, otherwise I'd need to call an update function" ON) +option(USE_STATIC_CRT "Use /MT[d] for dynamic library" OFF) +option(WARNINGS_AS_ERRORS "When enabled, compiles with `-Werror` (on *nix platforms)." OFF) + +set(CMAKE_CXX_STANDARD 14) + +set(BASE_RPC_SRC + ${PROJECT_SOURCE_DIR}/include/discord_rpc.h + discord_rpc.cpp + ${PROJECT_SOURCE_DIR}/include/discord_register.h + rpc_connection.h + rpc_connection.cpp + serialization.h + serialization.cpp + connection.h + backoff.h + msg_queue.h +) + +if (${BUILD_SHARED_LIBS}) + if(WIN32) + set(BASE_RPC_SRC ${BASE_RPC_SRC} dllmain.cpp) + endif(WIN32) +endif(${BUILD_SHARED_LIBS}) + +if(WIN32) + add_definitions(-DDISCORD_WINDOWS) + set(BASE_RPC_SRC ${BASE_RPC_SRC} connection_win.cpp discord_register_win.cpp) + add_library(discord-rpc ${BASE_RPC_SRC}) + if (MSVC) + if(USE_STATIC_CRT) + foreach(CompilerFlag + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE) + string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") + endforeach() + endif(USE_STATIC_CRT) + target_compile_options(discord-rpc PRIVATE /EHsc + /wd4100 # unreferenced formal parameter + /wd4514 # unreferenced inline + /wd4625 # copy constructor deleted + /wd5026 # move constructor deleted + /wd4626 # move assignment operator deleted + /wd4668 # not defined preprocessor macro + /wd4710 # function not inlined + /wd4711 # function was inlined + /wd4820 # structure padding + /wd4946 # reinterpret_cast used between related classes + /wd5027 # move assignment operator was implicitly defined as deleted + ) + endif(MSVC) + target_link_libraries(discord-rpc PRIVATE psapi advapi32) +endif(WIN32) + +if(UNIX) + set(BASE_RPC_SRC ${BASE_RPC_SRC} connection_unix.cpp) + + if (APPLE) + add_definitions(-DDISCORD_OSX) + set(BASE_RPC_SRC ${BASE_RPC_SRC} discord_register_osx.m) + else (APPLE) + add_definitions(-DDISCORD_LINUX) + set(BASE_RPC_SRC ${BASE_RPC_SRC} discord_register_linux.cpp) + endif(APPLE) + + add_library(discord-rpc ${BASE_RPC_SRC}) + target_link_libraries(discord-rpc PUBLIC pthread) + + target_compile_options(discord-rpc PRIVATE + -Wall + -Wextra + -Wpedantic + ) + + if (${CMAKE_BUILD_TYPE} STREQUAL Debug OR ${CMAKE_BUILD_TYPE} STREQUAL RelWithDebInfo) + target_compile_options(discord-rpc PRIVATE -g) + endif () + + if (${WARNINGS_AS_ERRORS}) + target_compile_options(discord-rpc PRIVATE -Werror) + endif (${WARNINGS_AS_ERRORS}) + + target_compile_options(discord-rpc PRIVATE + -Wno-unknown-pragmas # pragma push thing doesn't work on clang + -Wno-old-style-cast # it's fine + -Wno-c++98-compat # that was almost 2 decades ago + -Wno-c++98-compat-pedantic + -Wno-missing-noreturn + -Wno-padded # structure padding + -Wno-covered-switch-default + -Wno-exit-time-destructors # not sure about these + -Wno-global-constructors + ) + + if (${BUILD_SHARED_LIBS}) + target_compile_options(discord-rpc PRIVATE -fPIC) + endif (${BUILD_SHARED_LIBS}) + + if (APPLE) + target_link_libraries(discord-rpc PRIVATE "-framework AppKit") + endif (APPLE) +endif(UNIX) + +target_include_directories(discord-rpc PRIVATE ${RAPIDJSON}/include) + +if (NOT ${ENABLE_IO_THREAD}) + target_compile_definitions(discord-rpc PUBLIC -DDISCORD_DISABLE_IO_THREAD) +endif (NOT ${ENABLE_IO_THREAD}) + +if (${BUILD_SHARED_LIBS}) + target_compile_definitions(discord-rpc PUBLIC -DDISCORD_DYNAMIC_LIB) + target_compile_definitions(discord-rpc PRIVATE -DDISCORD_BUILDING_SDK) +endif(${BUILD_SHARED_LIBS}) + +# install + +install( + TARGETS discord-rpc + EXPORT "discord-rpc" + RUNTIME + DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY + DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE + DESTINATION "${CMAKE_INSTALL_LIBDIR}" + INCLUDES + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + +install( + FILES + "../include/discord_rpc.h" + "../include/discord_register.h" + DESTINATION "include" +) diff --git a/libraries/discordrpc/src/backoff.h b/libraries/discordrpc/src/backoff.h new file mode 100644 index 00000000000..a3e736fb7b3 --- /dev/null +++ b/libraries/discordrpc/src/backoff.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include + +struct Backoff { + int64_t minAmount; + int64_t maxAmount; + int64_t current; + int fails; + std::mt19937_64 randGenerator; + std::uniform_real_distribution<> randDistribution; + + double rand01() { return randDistribution(randGenerator); } + + Backoff(int64_t min, int64_t max) + : minAmount(min) + , maxAmount(max) + , current(min) + , fails(0) + , randGenerator((uint64_t)time(0)) + { + } + + void reset() + { + fails = 0; + current = minAmount; + } + + int64_t nextDelay() + { + ++fails; + int64_t delay = (int64_t)((double)current * 2.0 * rand01()); + current = std::min(current + delay, maxAmount); + return current; + } +}; diff --git a/libraries/discordrpc/src/connection.h b/libraries/discordrpc/src/connection.h new file mode 100644 index 00000000000..a8f99b9f10d --- /dev/null +++ b/libraries/discordrpc/src/connection.h @@ -0,0 +1,19 @@ +#pragma once + +// This is to wrap the platform specific kinds of connect/read/write. + +#include +#include + +// not really connectiony, but need per-platform +int GetProcessId(); + +struct BaseConnection { + static BaseConnection* Create(); + static void Destroy(BaseConnection*&); + bool isOpen{false}; + bool Open(); + bool Close(); + bool Write(const void* data, size_t length); + bool Read(void* data, size_t length); +}; diff --git a/libraries/discordrpc/src/connection_unix.cpp b/libraries/discordrpc/src/connection_unix.cpp new file mode 100644 index 00000000000..85dace3ccc2 --- /dev/null +++ b/libraries/discordrpc/src/connection_unix.cpp @@ -0,0 +1,125 @@ +#include "connection.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +int GetProcessId() +{ + return ::getpid(); +} + +struct BaseConnectionUnix : public BaseConnection { + int sock{-1}; +}; + +static BaseConnectionUnix Connection; +static sockaddr_un PipeAddr{}; +#ifdef MSG_NOSIGNAL +static int MsgFlags = MSG_NOSIGNAL; +#else +static int MsgFlags = 0; +#endif + +static const char* GetTempPath() +{ + const char* temp = getenv("XDG_RUNTIME_DIR"); + temp = temp ? temp : getenv("TMPDIR"); + temp = temp ? temp : getenv("TMP"); + temp = temp ? temp : getenv("TEMP"); + temp = temp ? temp : "/tmp"; + return temp; +} + +/*static*/ BaseConnection* BaseConnection::Create() +{ + PipeAddr.sun_family = AF_UNIX; + return &Connection; +} + +/*static*/ void BaseConnection::Destroy(BaseConnection*& c) +{ + auto self = reinterpret_cast(c); + self->Close(); + c = nullptr; +} + +bool BaseConnection::Open() +{ + const char* tempPath = GetTempPath(); + auto self = reinterpret_cast(this); + self->sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (self->sock == -1) { + return false; + } + fcntl(self->sock, F_SETFL, O_NONBLOCK); +#ifdef SO_NOSIGPIPE + int optval = 1; + setsockopt(self->sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)); +#endif + + for (int pipeNum = 0; pipeNum < 10; ++pipeNum) { + snprintf( + PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum); + int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr)); + if (err == 0) { + self->isOpen = true; + return true; + } + } + self->Close(); + return false; +} + +bool BaseConnection::Close() +{ + auto self = reinterpret_cast(this); + if (self->sock == -1) { + return false; + } + close(self->sock); + self->sock = -1; + self->isOpen = false; + return true; +} + +bool BaseConnection::Write(const void* data, size_t length) +{ + auto self = reinterpret_cast(this); + + if (self->sock == -1) { + return false; + } + + ssize_t sentBytes = send(self->sock, data, length, MsgFlags); + if (sentBytes < 0) { + Close(); + } + return sentBytes == (ssize_t)length; +} + +bool BaseConnection::Read(void* data, size_t length) +{ + auto self = reinterpret_cast(this); + + if (self->sock == -1) { + return false; + } + + int res = (int)recv(self->sock, data, length, MsgFlags); + if (res < 0) { + if (errno == EAGAIN) { + return false; + } + Close(); + } + else if (res == 0) { + Close(); + } + return res == (int)length; +} diff --git a/libraries/discordrpc/src/connection_win.cpp b/libraries/discordrpc/src/connection_win.cpp new file mode 100644 index 00000000000..2dd2750c06b --- /dev/null +++ b/libraries/discordrpc/src/connection_win.cpp @@ -0,0 +1,128 @@ +#include "connection.h" + +#define WIN32_LEAN_AND_MEAN +#define NOMCX +#define NOSERVICE +#define NOIME +#include +#include + +int GetProcessId() +{ + return (int)::GetCurrentProcessId(); +} + +struct BaseConnectionWin : public BaseConnection { + HANDLE pipe{INVALID_HANDLE_VALUE}; +}; + +static BaseConnectionWin Connection; + +/*static*/ BaseConnection* BaseConnection::Create() +{ + return &Connection; +} + +/*static*/ void BaseConnection::Destroy(BaseConnection*& c) +{ + auto self = reinterpret_cast(c); + self->Close(); + c = nullptr; +} + +bool BaseConnection::Open() +{ + wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"}; + const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2; + pipeName[pipeDigit] = L'0'; + auto self = reinterpret_cast(this); + for (;;) { + self->pipe = ::CreateFileW( + pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); + if (self->pipe != INVALID_HANDLE_VALUE) { + self->isOpen = true; + return true; + } + + auto lastError = GetLastError(); + if (lastError == ERROR_FILE_NOT_FOUND) { + if (pipeName[pipeDigit] < L'9') { + pipeName[pipeDigit]++; + continue; + } + } + else if (lastError == ERROR_PIPE_BUSY) { + if (!WaitNamedPipeW(pipeName, 10000)) { + return false; + } + continue; + } + return false; + } +} + +bool BaseConnection::Close() +{ + auto self = reinterpret_cast(this); + ::CloseHandle(self->pipe); + self->pipe = INVALID_HANDLE_VALUE; + self->isOpen = false; + return true; +} + +bool BaseConnection::Write(const void* data, size_t length) +{ + if (length == 0) { + return true; + } + auto self = reinterpret_cast(this); + assert(self); + if (!self) { + return false; + } + if (self->pipe == INVALID_HANDLE_VALUE) { + return false; + } + assert(data); + if (!data) { + return false; + } + const DWORD bytesLength = (DWORD)length; + DWORD bytesWritten = 0; + return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE && + bytesWritten == bytesLength; +} + +bool BaseConnection::Read(void* data, size_t length) +{ + assert(data); + if (!data) { + return false; + } + auto self = reinterpret_cast(this); + assert(self); + if (!self) { + return false; + } + if (self->pipe == INVALID_HANDLE_VALUE) { + return false; + } + DWORD bytesAvailable = 0; + if (::PeekNamedPipe(self->pipe, nullptr, 0, nullptr, &bytesAvailable, nullptr)) { + if (bytesAvailable >= length) { + DWORD bytesToRead = (DWORD)length; + DWORD bytesRead = 0; + if (::ReadFile(self->pipe, data, bytesToRead, &bytesRead, nullptr) == TRUE) { + assert(bytesToRead == bytesRead); + return true; + } + else { + Close(); + } + } + } + else { + Close(); + } + return false; +} diff --git a/libraries/discordrpc/src/discord_register_linux.cpp b/libraries/discordrpc/src/discord_register_linux.cpp new file mode 100644 index 00000000000..dd92eea0d4a --- /dev/null +++ b/libraries/discordrpc/src/discord_register_linux.cpp @@ -0,0 +1,102 @@ +#include "discord_rpc.h" +#include "discord_register.h" +#include + +#include +#include +#include +#include +#include +#include + +static bool Mkdir(const char* path) +{ + int result = mkdir(path, 0755); + if (result == 0) { + return true; + } + if (errno == EEXIST) { + return true; + } + return false; +} + +// we want to register games so we can run them from Discord client as discord-:// +extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) +{ + // Add a desktop file and update some mime handlers so that xdg-open does the right thing. + + const char* home = getenv("HOME"); + if (!home) { + return; + } + + char exePath[1024]; + if (!command || !command[0]) { + ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath)); + if (size <= 0 || size >= (ssize_t)sizeof(exePath)) { + return; + } + exePath[size] = '\0'; + command = exePath; + } + + const char* desktopFileFormat = "[Desktop Entry]\n" + "Name=Game %s\n" + "Exec=%s %%u\n" // note: it really wants that %u in there + "Type=Application\n" + "NoDisplay=true\n" + "Categories=Discord;Games;\n" + "MimeType=x-scheme-handler/discord-%s;\n"; + char desktopFile[2048]; + int fileLen = snprintf( + desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId); + if (fileLen <= 0) { + return; + } + + char desktopFilename[256]; + snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId); + + char desktopFilePath[1024]; + snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home); + if (!Mkdir(desktopFilePath)) { + return; + } + strcat(desktopFilePath, "/share"); + if (!Mkdir(desktopFilePath)) { + return; + } + strcat(desktopFilePath, "/applications"); + if (!Mkdir(desktopFilePath)) { + return; + } + strcat(desktopFilePath, desktopFilename); + + FILE* fp = fopen(desktopFilePath, "w"); + if (fp) { + fwrite(desktopFile, 1, fileLen, fp); + fclose(fp); + } + else { + return; + } + + char xdgMimeCommand[1024]; + snprintf(xdgMimeCommand, + sizeof(xdgMimeCommand), + "xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s", + applicationId, + applicationId); + if (system(xdgMimeCommand) < 0) { + fprintf(stderr, "Failed to register mime handler\n"); + } +} + +extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, + const char* steamId) +{ + char command[256]; + sprintf(command, "xdg-open steam://rungameid/%s", steamId); + Discord_Register(applicationId, command); +} diff --git a/libraries/discordrpc/src/discord_register_osx.m b/libraries/discordrpc/src/discord_register_osx.m new file mode 100644 index 00000000000..d710102865b --- /dev/null +++ b/libraries/discordrpc/src/discord_register_osx.m @@ -0,0 +1,80 @@ +#include +#include + +#import + +#include "discord_register.h" + +static void RegisterCommand(const char* applicationId, const char* command) +{ + // There does not appear to be a way to register arbitrary commands on OSX, so instead we'll save the command + // to a file in the Discord config path, and when it is needed, Discord can try to load the file there, open + // the command therein (will pass to js's window.open, so requires a url-like thing) + + // Note: will not work for sandboxed apps + NSString *home = NSHomeDirectory(); + if (!home) { + return; + } + + NSString *path = [[[[[[home stringByAppendingPathComponent:@"Library"] + stringByAppendingPathComponent:@"Application Support"] + stringByAppendingPathComponent:@"discord"] + stringByAppendingPathComponent:@"games"] + stringByAppendingPathComponent:[NSString stringWithUTF8String:applicationId]] + stringByAppendingPathExtension:@"json"]; + [[NSFileManager defaultManager] createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil]; + + NSString *jsonBuffer = [NSString stringWithFormat:@"{\"command\": \"%s\"}", command]; + [jsonBuffer writeToFile:path atomically:NO encoding:NSUTF8StringEncoding error:nil]; +} + +static void RegisterURL(const char* applicationId) +{ + char url[256]; + snprintf(url, sizeof(url), "discord-%s", applicationId); + CFStringRef cfURL = CFStringCreateWithCString(NULL, url, kCFStringEncodingUTF8); + + NSString* myBundleId = [[NSBundle mainBundle] bundleIdentifier]; + if (!myBundleId) { + fprintf(stderr, "No bundle id found\n"); + return; + } + + NSURL* myURL = [[NSBundle mainBundle] bundleURL]; + if (!myURL) { + fprintf(stderr, "No bundle url found\n"); + return; + } + + OSStatus status = LSSetDefaultHandlerForURLScheme(cfURL, (__bridge CFStringRef)myBundleId); + if (status != noErr) { + fprintf(stderr, "Error in LSSetDefaultHandlerForURLScheme: %d\n", (int)status); + return; + } + + status = LSRegisterURL((__bridge CFURLRef)myURL, true); + if (status != noErr) { + fprintf(stderr, "Error in LSRegisterURL: %d\n", (int)status); + } +} + +void Discord_Register(const char* applicationId, const char* command) +{ + if (command) { + RegisterCommand(applicationId, command); + } + else { + // raii lite + @autoreleasepool { + RegisterURL(applicationId); + } + } +} + +void Discord_RegisterSteamGame(const char* applicationId, const char* steamId) +{ + char command[256]; + snprintf(command, 256, "steam://rungameid/%s", steamId); + Discord_Register(applicationId, command); +} diff --git a/libraries/discordrpc/src/discord_register_win.cpp b/libraries/discordrpc/src/discord_register_win.cpp new file mode 100644 index 00000000000..0b1c4a13dae --- /dev/null +++ b/libraries/discordrpc/src/discord_register_win.cpp @@ -0,0 +1,186 @@ +#include "discord_rpc.h" +#include "discord_register.h" + +#define WIN32_LEAN_AND_MEAN +#define NOMCX +#define NOSERVICE +#define NOIME +#include +#include +#include + +/** + * Updated fixes for MinGW and WinXP + * This block is written the way it does not involve changing the rest of the code + * Checked to be compiling + * 1) strsafe.h belongs to Windows SDK and cannot be added to MinGW + * #include guarded, functions redirected to substitutes + * 2) RegSetKeyValueW and LSTATUS are not declared in + * The entire function is rewritten + */ +#ifdef __MINGW32__ +#include +/// strsafe.h fixes +static HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat, ...) +{ + HRESULT ret; + va_list va; + va_start(va, pszFormat); + cbDest /= 2; // Size is divided by 2 to convert from bytes to wide characters - causes segfault + // othervise + ret = vsnwprintf(pszDest, cbDest, pszFormat, va); + pszDest[cbDest - 1] = 0; // Terminate the string in case a buffer overflow; -1 will be returned + va_end(va); + return ret; +} +#else +#include +#include +#endif // __MINGW32__ + +/// winreg.h fixes +#ifndef LSTATUS +#define LSTATUS LONG +#endif +#ifdef RegSetKeyValueW +#undefine RegSetKeyValueW +#endif +#define RegSetKeyValueW regset +static LSTATUS regset(HKEY hkey, + LPCWSTR subkey, + LPCWSTR name, + DWORD type, + const void* data, + DWORD len) +{ + HKEY htkey = hkey, hsubkey = nullptr; + LSTATUS ret; + if (subkey && subkey[0]) { + if ((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) != + ERROR_SUCCESS) + return ret; + htkey = hsubkey; + } + ret = RegSetValueExW(htkey, name, 0, type, (const BYTE*)data, len); + if (hsubkey && hsubkey != hkey) + RegCloseKey(hsubkey); + return ret; +} + +static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command) +{ + // https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx + // we want to register games so we can run them as discord-:// + // Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions. + + wchar_t exeFilePath[MAX_PATH]; + DWORD exeLen = GetModuleFileNameW(nullptr, exeFilePath, MAX_PATH); + wchar_t openCommand[1024]; + + if (command && command[0]) { + StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command); + } + else { + // StringCbCopyW(openCommand, sizeof(openCommand), exeFilePath); + StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath); + } + + wchar_t protocolName[64]; + StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId); + wchar_t protocolDescription[128]; + StringCbPrintfW( + protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId); + wchar_t urlProtocol = 0; + + wchar_t keyName[256]; + StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName); + HKEY key; + auto status = + RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr); + if (status != ERROR_SUCCESS) { + fprintf(stderr, "Error creating key\n"); + return; + } + DWORD len; + LSTATUS result; + len = (DWORD)lstrlenW(protocolDescription) + 1; + result = + RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t)); + if (FAILED(result)) { + fprintf(stderr, "Error writing description\n"); + } + + len = (DWORD)lstrlenW(protocolDescription) + 1; + result = RegSetKeyValueW(key, nullptr, L"URL Protocol", REG_SZ, &urlProtocol, sizeof(wchar_t)); + if (FAILED(result)) { + fprintf(stderr, "Error writing description\n"); + } + + result = RegSetKeyValueW( + key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t)); + if (FAILED(result)) { + fprintf(stderr, "Error writing icon\n"); + } + + len = (DWORD)lstrlenW(openCommand) + 1; + result = RegSetKeyValueW( + key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t)); + if (FAILED(result)) { + fprintf(stderr, "Error writing command\n"); + } + RegCloseKey(key); +} + +extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) +{ + wchar_t appId[32]; + MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); + + wchar_t openCommand[1024]; + const wchar_t* wcommand = nullptr; + if (command && command[0]) { + const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand); + MultiByteToWideChar(CP_UTF8, 0, command, -1, openCommand, commandBufferLen); + wcommand = openCommand; + } + + Discord_RegisterW(appId, wcommand); +} + +extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, + const char* steamId) +{ + wchar_t appId[32]; + MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); + + wchar_t wSteamId[32]; + MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32); + + HKEY key; + auto status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_READ, &key); + if (status != ERROR_SUCCESS) { + fprintf(stderr, "Error opening Steam key\n"); + return; + } + + wchar_t steamPath[MAX_PATH]; + DWORD pathBytes = sizeof(steamPath); + status = RegQueryValueExW(key, L"SteamExe", nullptr, nullptr, (BYTE*)steamPath, &pathBytes); + RegCloseKey(key); + if (status != ERROR_SUCCESS || pathBytes < 1) { + fprintf(stderr, "Error reading SteamExe key\n"); + return; + } + + DWORD pathChars = pathBytes / sizeof(wchar_t); + for (DWORD i = 0; i < pathChars; ++i) { + if (steamPath[i] == L'/') { + steamPath[i] = L'\\'; + } + } + + wchar_t command[1024]; + StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://rungameid/%s", steamPath, wSteamId); + + Discord_RegisterW(appId, command); +} diff --git a/libraries/discordrpc/src/discord_rpc.cpp b/libraries/discordrpc/src/discord_rpc.cpp new file mode 100644 index 00000000000..03924538c30 --- /dev/null +++ b/libraries/discordrpc/src/discord_rpc.cpp @@ -0,0 +1,504 @@ +#include "discord_rpc.h" + +#include "backoff.h" +#include "discord_register.h" +#include "msg_queue.h" +#include "rpc_connection.h" +#include "serialization.h" + +#include +#include +#include + +#ifndef DISCORD_DISABLE_IO_THREAD +#include +#include +#endif + +constexpr size_t MaxMessageSize{16 * 1024}; +constexpr size_t MessageQueueSize{8}; +constexpr size_t JoinQueueSize{8}; + +struct QueuedMessage { + size_t length; + char buffer[MaxMessageSize]; + + void Copy(const QueuedMessage& other) + { + length = other.length; + if (length) { + memcpy(buffer, other.buffer, length); + } + } +}; + +struct User { + // snowflake (64bit int), turned into a ascii decimal string, at most 20 chars +1 null + // terminator = 21 + char userId[32]; + // 32 unicode glyphs is max name size => 4 bytes per glyph in the worst case, +1 for null + // terminator = 129 + char username[344]; + // 4 decimal digits + 1 null terminator = 5 + char discriminator[8]; + // optional 'a_' + md5 hex digest (32 bytes) + null terminator = 35 + char avatar[128]; + // Rounded way up because I'm paranoid about games breaking from future changes in these sizes +}; + +static RpcConnection* Connection{nullptr}; +static DiscordEventHandlers QueuedHandlers{}; +static DiscordEventHandlers Handlers{}; +static std::atomic_bool WasJustConnected{false}; +static std::atomic_bool WasJustDisconnected{false}; +static std::atomic_bool GotErrorMessage{false}; +static std::atomic_bool WasJoinGame{false}; +static std::atomic_bool WasSpectateGame{false}; +static std::atomic_bool UpdatePresence{false}; +static char JoinGameSecret[256]; +static char SpectateGameSecret[256]; +static int LastErrorCode{0}; +static char LastErrorMessage[256]; +static int LastDisconnectErrorCode{0}; +static char LastDisconnectErrorMessage[256]; +static std::mutex PresenceMutex; +static std::mutex HandlerMutex; +static QueuedMessage QueuedPresence{}; +static MsgQueue SendQueue; +static MsgQueue JoinAskQueue; +static User connectedUser; + +// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential +// backoff from 0.5 seconds to 1 minute +static Backoff ReconnectTimeMs(500, 60 * 1000); +static auto NextConnect = std::chrono::system_clock::now(); +static int Pid{0}; +static int Nonce{1}; + +#ifndef DISCORD_DISABLE_IO_THREAD +static void Discord_UpdateConnection(void); +class IoThreadHolder { +private: + std::atomic_bool keepRunning{true}; + std::mutex waitForIOMutex; + std::condition_variable waitForIOActivity; + std::thread ioThread; + +public: + void Start() + { + keepRunning.store(true); + ioThread = std::thread([&]() { + const std::chrono::duration maxWait{500LL}; + Discord_UpdateConnection(); + while (keepRunning.load()) { + std::unique_lock lock(waitForIOMutex); + waitForIOActivity.wait_for(lock, maxWait); + Discord_UpdateConnection(); + } + }); + } + + void Notify() { waitForIOActivity.notify_all(); } + + void Stop() + { + keepRunning.exchange(false); + Notify(); + if (ioThread.joinable()) { + ioThread.join(); + } + } + + ~IoThreadHolder() { Stop(); } +}; +#else +class IoThreadHolder { +public: + void Start() {} + void Stop() {} + void Notify() {} +}; +#endif // DISCORD_DISABLE_IO_THREAD +static IoThreadHolder* IoThread{nullptr}; + +static void UpdateReconnectTime() +{ + NextConnect = std::chrono::system_clock::now() + + std::chrono::duration{ReconnectTimeMs.nextDelay()}; +} + +#ifdef DISCORD_DISABLE_IO_THREAD +extern "C" DISCORD_EXPORT void Discord_UpdateConnection(void) +#else +static void Discord_UpdateConnection(void) +#endif +{ + if (!Connection) { + return; + } + + if (!Connection->IsOpen()) { + if (std::chrono::system_clock::now() >= NextConnect) { + UpdateReconnectTime(); + Connection->Open(); + } + } + else { + // reads + + for (;;) { + JsonDocument message; + + if (!Connection->Read(message)) { + break; + } + + const char* evtName = GetStrMember(&message, "evt"); + const char* nonce = GetStrMember(&message, "nonce"); + + if (nonce) { + // in responses only -- should use to match up response when needed. + + if (evtName && strcmp(evtName, "ERROR") == 0) { + auto data = GetObjMember(&message, "data"); + LastErrorCode = GetIntMember(data, "code"); + StringCopy(LastErrorMessage, GetStrMember(data, "message", "")); + GotErrorMessage.store(true); + } + } + else { + // should have evt == name of event, optional data + if (evtName == nullptr) { + continue; + } + + auto data = GetObjMember(&message, "data"); + + if (strcmp(evtName, "ACTIVITY_JOIN") == 0) { + auto secret = GetStrMember(data, "secret"); + if (secret) { + StringCopy(JoinGameSecret, secret); + WasJoinGame.store(true); + } + } + else if (strcmp(evtName, "ACTIVITY_SPECTATE") == 0) { + auto secret = GetStrMember(data, "secret"); + if (secret) { + StringCopy(SpectateGameSecret, secret); + WasSpectateGame.store(true); + } + } + else if (strcmp(evtName, "ACTIVITY_JOIN_REQUEST") == 0) { + auto user = GetObjMember(data, "user"); + auto userId = GetStrMember(user, "id"); + auto username = GetStrMember(user, "username"); + auto avatar = GetStrMember(user, "avatar"); + auto joinReq = JoinAskQueue.GetNextAddMessage(); + if (userId && username && joinReq) { + StringCopy(joinReq->userId, userId); + StringCopy(joinReq->username, username); + auto discriminator = GetStrMember(user, "discriminator"); + if (discriminator) { + StringCopy(joinReq->discriminator, discriminator); + } + if (avatar) { + StringCopy(joinReq->avatar, avatar); + } + else { + joinReq->avatar[0] = 0; + } + JoinAskQueue.CommitAdd(); + } + } + } + } + + // writes + if (UpdatePresence.exchange(false) && QueuedPresence.length) { + QueuedMessage local; + { + std::lock_guard guard(PresenceMutex); + local.Copy(QueuedPresence); + } + if (!Connection->Write(local.buffer, local.length)) { + // if we fail to send, requeue + std::lock_guard guard(PresenceMutex); + QueuedPresence.Copy(local); + UpdatePresence.exchange(true); + } + } + + while (SendQueue.HavePendingSends()) { + auto qmessage = SendQueue.GetNextSendMessage(); + Connection->Write(qmessage->buffer, qmessage->length); + SendQueue.CommitSend(); + } + } +} + +static void SignalIOActivity() +{ + if (IoThread != nullptr) { + IoThread->Notify(); + } +} + +static bool RegisterForEvent(const char* evtName) +{ + auto qmessage = SendQueue.GetNextAddMessage(); + if (qmessage) { + qmessage->length = + JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); + SendQueue.CommitAdd(); + SignalIOActivity(); + return true; + } + return false; +} + +static bool DeregisterForEvent(const char* evtName) +{ + auto qmessage = SendQueue.GetNextAddMessage(); + if (qmessage) { + qmessage->length = + JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); + SendQueue.CommitAdd(); + SignalIOActivity(); + return true; + } + return false; +} + +extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId, + DiscordEventHandlers* handlers, + int autoRegister, + const char* optionalSteamId) +{ + IoThread = new (std::nothrow) IoThreadHolder(); + if (IoThread == nullptr) { + return; + } + + if (autoRegister) { + if (optionalSteamId && optionalSteamId[0]) { + Discord_RegisterSteamGame(applicationId, optionalSteamId); + } + else { + Discord_Register(applicationId, nullptr); + } + } + + Pid = GetProcessId(); + + { + std::lock_guard guard(HandlerMutex); + + if (handlers) { + QueuedHandlers = *handlers; + } + else { + QueuedHandlers = {}; + } + + Handlers = {}; + } + + if (Connection) { + return; + } + + Connection = RpcConnection::Create(applicationId); + Connection->onConnect = [](JsonDocument& readyMessage) { + Discord_UpdateHandlers(&QueuedHandlers); + if (QueuedPresence.length > 0) { + UpdatePresence.exchange(true); + SignalIOActivity(); + } + auto data = GetObjMember(&readyMessage, "data"); + auto user = GetObjMember(data, "user"); + auto userId = GetStrMember(user, "id"); + auto username = GetStrMember(user, "username"); + auto avatar = GetStrMember(user, "avatar"); + if (userId && username) { + StringCopy(connectedUser.userId, userId); + StringCopy(connectedUser.username, username); + auto discriminator = GetStrMember(user, "discriminator"); + if (discriminator) { + StringCopy(connectedUser.discriminator, discriminator); + } + if (avatar) { + StringCopy(connectedUser.avatar, avatar); + } + else { + connectedUser.avatar[0] = 0; + } + } + WasJustConnected.exchange(true); + ReconnectTimeMs.reset(); + }; + Connection->onDisconnect = [](int err, const char* message) { + LastDisconnectErrorCode = err; + StringCopy(LastDisconnectErrorMessage, message); + WasJustDisconnected.exchange(true); + UpdateReconnectTime(); + }; + + IoThread->Start(); +} + +extern "C" DISCORD_EXPORT void Discord_Shutdown(void) +{ + if (!Connection) { + return; + } + Connection->onConnect = nullptr; + Connection->onDisconnect = nullptr; + Handlers = {}; + QueuedPresence.length = 0; + UpdatePresence.exchange(false); + if (IoThread != nullptr) { + IoThread->Stop(); + delete IoThread; + IoThread = nullptr; + } + + RpcConnection::Destroy(Connection); +} + +extern "C" DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence) +{ + { + std::lock_guard guard(PresenceMutex); + QueuedPresence.length = JsonWriteRichPresenceObj( + QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence); + UpdatePresence.exchange(true); + } + SignalIOActivity(); +} + +extern "C" DISCORD_EXPORT void Discord_ClearPresence(void) +{ + Discord_UpdatePresence(nullptr); +} + +extern "C" DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply) +{ + // if we are not connected, let's not batch up stale messages for later + if (!Connection || !Connection->IsOpen()) { + return; + } + auto qmessage = SendQueue.GetNextAddMessage(); + if (qmessage) { + qmessage->length = + JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++); + SendQueue.CommitAdd(); + SignalIOActivity(); + } +} + +extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void) +{ + // Note on some weirdness: internally we might connect, get other signals, disconnect any number + // of times inbetween calls here. Externally, we want the sequence to seem sane, so any other + // signals are book-ended by calls to ready and disconnect. + + if (!Connection) { + return; + } + + bool wasDisconnected = WasJustDisconnected.exchange(false); + bool isConnected = Connection->IsOpen(); + + if (isConnected) { + // if we are connected, disconnect cb first + std::lock_guard guard(HandlerMutex); + if (wasDisconnected && Handlers.disconnected) { + Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage); + } + } + + if (WasJustConnected.exchange(false)) { + std::lock_guard guard(HandlerMutex); + if (Handlers.ready) { + DiscordUser du{connectedUser.userId, + connectedUser.username, + connectedUser.discriminator, + connectedUser.avatar}; + Handlers.ready(&du); + } + } + + if (GotErrorMessage.exchange(false)) { + std::lock_guard guard(HandlerMutex); + if (Handlers.errored) { + Handlers.errored(LastErrorCode, LastErrorMessage); + } + } + + if (WasJoinGame.exchange(false)) { + std::lock_guard guard(HandlerMutex); + if (Handlers.joinGame) { + Handlers.joinGame(JoinGameSecret); + } + } + + if (WasSpectateGame.exchange(false)) { + std::lock_guard guard(HandlerMutex); + if (Handlers.spectateGame) { + Handlers.spectateGame(SpectateGameSecret); + } + } + + // Right now this batches up any requests and sends them all in a burst; I could imagine a world + // where the implementer would rather sequentially accept/reject each one before the next invite + // is sent. I left it this way because I could also imagine wanting to process these all and + // maybe show them in one common dialog and/or start fetching the avatars in parallel, and if + // not it should be trivial for the implementer to make a queue themselves. + while (JoinAskQueue.HavePendingSends()) { + auto req = JoinAskQueue.GetNextSendMessage(); + { + std::lock_guard guard(HandlerMutex); + if (Handlers.joinRequest) { + DiscordUser du{req->userId, req->username, req->discriminator, req->avatar}; + Handlers.joinRequest(&du); + } + } + JoinAskQueue.CommitSend(); + } + + if (!isConnected) { + // if we are not connected, disconnect message last + std::lock_guard guard(HandlerMutex); + if (wasDisconnected && Handlers.disconnected) { + Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage); + } + } +} + +extern "C" DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* newHandlers) +{ + if (newHandlers) { +#define HANDLE_EVENT_REGISTRATION(handler_name, event) \ + if (!Handlers.handler_name && newHandlers->handler_name) { \ + RegisterForEvent(event); \ + } \ + else if (Handlers.handler_name && !newHandlers->handler_name) { \ + DeregisterForEvent(event); \ + } + + std::lock_guard guard(HandlerMutex); + HANDLE_EVENT_REGISTRATION(joinGame, "ACTIVITY_JOIN") + HANDLE_EVENT_REGISTRATION(spectateGame, "ACTIVITY_SPECTATE") + HANDLE_EVENT_REGISTRATION(joinRequest, "ACTIVITY_JOIN_REQUEST") + +#undef HANDLE_EVENT_REGISTRATION + + Handlers = *newHandlers; + } + else { + std::lock_guard guard(HandlerMutex); + Handlers = {}; + } + return; +} diff --git a/libraries/discordrpc/src/dllmain.cpp b/libraries/discordrpc/src/dllmain.cpp new file mode 100644 index 00000000000..fbfc2950d7f --- /dev/null +++ b/libraries/discordrpc/src/dllmain.cpp @@ -0,0 +1,8 @@ +#include + +// outsmart GCC's missing-declarations warning +BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID); +BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID) +{ + return TRUE; +} diff --git a/libraries/discordrpc/src/msg_queue.h b/libraries/discordrpc/src/msg_queue.h new file mode 100644 index 00000000000..77f380e7053 --- /dev/null +++ b/libraries/discordrpc/src/msg_queue.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +// A simple queue. No locks, but only works with a single thread as producer and a single thread as +// a consumer. Mutex up as needed. + +template +class MsgQueue { + ElementType queue_[QueueSize]; + std::atomic_uint nextAdd_{0}; + std::atomic_uint nextSend_{0}; + std::atomic_uint pendingSends_{0}; + +public: + MsgQueue() {} + + ElementType* GetNextAddMessage() + { + // if we are falling behind, bail + if (pendingSends_.load() >= QueueSize) { + return nullptr; + } + auto index = (nextAdd_++) % QueueSize; + return &queue_[index]; + } + void CommitAdd() { ++pendingSends_; } + + bool HavePendingSends() const { return pendingSends_.load() != 0; } + ElementType* GetNextSendMessage() + { + auto index = (nextSend_++) % QueueSize; + return &queue_[index]; + } + void CommitSend() { --pendingSends_; } +}; diff --git a/libraries/discordrpc/src/rpc_connection.cpp b/libraries/discordrpc/src/rpc_connection.cpp new file mode 100644 index 00000000000..0933162169b --- /dev/null +++ b/libraries/discordrpc/src/rpc_connection.cpp @@ -0,0 +1,137 @@ +#include "rpc_connection.h" +#include "serialization.h" + +#include + +static const int RpcVersion = 1; +static RpcConnection Instance; + +/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId) +{ + Instance.connection = BaseConnection::Create(); + StringCopy(Instance.appId, applicationId); + return &Instance; +} + +/*static*/ void RpcConnection::Destroy(RpcConnection*& c) +{ + c->Close(); + BaseConnection::Destroy(c->connection); + c = nullptr; +} + +void RpcConnection::Open() +{ + if (state == State::Connected) { + return; + } + + if (state == State::Disconnected && !connection->Open()) { + return; + } + + if (state == State::SentHandshake) { + JsonDocument message; + if (Read(message)) { + auto cmd = GetStrMember(&message, "cmd"); + auto evt = GetStrMember(&message, "evt"); + if (cmd && evt && !strcmp(cmd, "DISPATCH") && !strcmp(evt, "READY")) { + state = State::Connected; + if (onConnect) { + onConnect(message); + } + } + } + } + else { + sendFrame.opcode = Opcode::Handshake; + sendFrame.length = (uint32_t)JsonWriteHandshakeObj( + sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId); + + if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) { + state = State::SentHandshake; + } + else { + Close(); + } + } +} + +void RpcConnection::Close() +{ + if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) { + onDisconnect(lastErrorCode, lastErrorMessage); + } + connection->Close(); + state = State::Disconnected; +} + +bool RpcConnection::Write(const void* data, size_t length) +{ + sendFrame.opcode = Opcode::Frame; + memcpy(sendFrame.message, data, length); + sendFrame.length = (uint32_t)length; + if (!connection->Write(&sendFrame, sizeof(MessageFrameHeader) + length)) { + Close(); + return false; + } + return true; +} + +bool RpcConnection::Read(JsonDocument& message) +{ + if (state != State::Connected && state != State::SentHandshake) { + return false; + } + MessageFrame readFrame; + for (;;) { + bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader)); + if (!didRead) { + if (!connection->isOpen) { + lastErrorCode = (int)ErrorCode::PipeClosed; + StringCopy(lastErrorMessage, "Pipe closed"); + Close(); + } + return false; + } + + if (readFrame.length > 0) { + didRead = connection->Read(readFrame.message, readFrame.length); + if (!didRead) { + lastErrorCode = (int)ErrorCode::ReadCorrupt; + StringCopy(lastErrorMessage, "Partial data in frame"); + Close(); + return false; + } + readFrame.message[readFrame.length] = 0; + } + + switch (readFrame.opcode) { + case Opcode::Close: { + message.ParseInsitu(readFrame.message); + lastErrorCode = GetIntMember(&message, "code"); + StringCopy(lastErrorMessage, GetStrMember(&message, "message", "")); + Close(); + return false; + } + case Opcode::Frame: + message.ParseInsitu(readFrame.message); + return true; + case Opcode::Ping: + readFrame.opcode = Opcode::Pong; + if (!connection->Write(&readFrame, sizeof(MessageFrameHeader) + readFrame.length)) { + Close(); + } + break; + case Opcode::Pong: + break; + case Opcode::Handshake: + default: + // something bad happened + lastErrorCode = (int)ErrorCode::ReadCorrupt; + StringCopy(lastErrorMessage, "Bad ipc frame"); + Close(); + return false; + } + } +} diff --git a/libraries/discordrpc/src/rpc_connection.h b/libraries/discordrpc/src/rpc_connection.h new file mode 100644 index 00000000000..bbdd05c7925 --- /dev/null +++ b/libraries/discordrpc/src/rpc_connection.h @@ -0,0 +1,59 @@ +#pragma once + +#include "connection.h" +#include "serialization.h" + +// I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much +// smaller. +constexpr size_t MaxRpcFrameSize = 64 * 1024; + +struct RpcConnection { + enum class ErrorCode : int { + Success = 0, + PipeClosed = 1, + ReadCorrupt = 2, + }; + + enum class Opcode : uint32_t { + Handshake = 0, + Frame = 1, + Close = 2, + Ping = 3, + Pong = 4, + }; + + struct MessageFrameHeader { + Opcode opcode; + uint32_t length; + }; + + struct MessageFrame : public MessageFrameHeader { + char message[MaxRpcFrameSize - sizeof(MessageFrameHeader)]; + }; + + enum class State : uint32_t { + Disconnected, + SentHandshake, + AwaitingResponse, + Connected, + }; + + BaseConnection* connection{nullptr}; + State state{State::Disconnected}; + void (*onConnect)(JsonDocument& message){nullptr}; + void (*onDisconnect)(int errorCode, const char* message){nullptr}; + char appId[64]{}; + int lastErrorCode{0}; + char lastErrorMessage[256]{}; + RpcConnection::MessageFrame sendFrame; + + static RpcConnection* Create(const char* applicationId); + static void Destroy(RpcConnection*&); + + inline bool IsOpen() const { return state == State::Connected; } + + void Open(); + void Close(); + bool Write(const void* data, size_t length); + bool Read(JsonDocument& message); +}; diff --git a/libraries/discordrpc/src/serialization.cpp b/libraries/discordrpc/src/serialization.cpp new file mode 100644 index 00000000000..70efa637f35 --- /dev/null +++ b/libraries/discordrpc/src/serialization.cpp @@ -0,0 +1,250 @@ +#include "serialization.h" +#include "connection.h" +#include "discord_rpc.h" + +template +void NumberToString(char* dest, T number) +{ + if (!number) { + *dest++ = '0'; + *dest++ = 0; + return; + } + if (number < 0) { + *dest++ = '-'; + number = -number; + } + char temp[32]; + int place = 0; + while (number) { + auto digit = number % 10; + number = number / 10; + temp[place++] = '0' + (char)digit; + } + for (--place; place >= 0; --place) { + *dest++ = temp[place]; + } + *dest = 0; +} + +// it's ever so slightly faster to not have to strlen the key +template +void WriteKey(JsonWriter& w, T& k) +{ + w.Key(k, sizeof(T) - 1); +} + +struct WriteObject { + JsonWriter& writer; + WriteObject(JsonWriter& w) + : writer(w) + { + writer.StartObject(); + } + template + WriteObject(JsonWriter& w, T& name) + : writer(w) + { + WriteKey(writer, name); + writer.StartObject(); + } + ~WriteObject() { writer.EndObject(); } +}; + +struct WriteArray { + JsonWriter& writer; + template + WriteArray(JsonWriter& w, T& name) + : writer(w) + { + WriteKey(writer, name); + writer.StartArray(); + } + ~WriteArray() { writer.EndArray(); } +}; + +template +void WriteOptionalString(JsonWriter& w, T& k, const char* value) +{ + if (value && value[0]) { + w.Key(k, sizeof(T) - 1); + w.String(value); + } +} + +static void JsonWriteNonce(JsonWriter& writer, int nonce) +{ + WriteKey(writer, "nonce"); + char nonceBuffer[32]; + NumberToString(nonceBuffer, nonce); + writer.String(nonceBuffer); +} + +size_t JsonWriteRichPresenceObj(char* dest, + size_t maxLen, + int nonce, + int pid, + const DiscordRichPresence* presence) +{ + JsonWriter writer(dest, maxLen); + + { + WriteObject top(writer); + + JsonWriteNonce(writer, nonce); + + WriteKey(writer, "cmd"); + writer.String("SET_ACTIVITY"); + + { + WriteObject args(writer, "args"); + + WriteKey(writer, "pid"); + writer.Int(pid); + + if (presence != nullptr) { + WriteObject activity(writer, "activity"); + + WriteOptionalString(writer, "state", presence->state); + WriteOptionalString(writer, "details", presence->details); + + if (presence->startTimestamp || presence->endTimestamp) { + WriteObject timestamps(writer, "timestamps"); + + if (presence->startTimestamp) { + WriteKey(writer, "start"); + writer.Int64(presence->startTimestamp); + } + + if (presence->endTimestamp) { + WriteKey(writer, "end"); + writer.Int64(presence->endTimestamp); + } + } + + if ((presence->largeImageKey && presence->largeImageKey[0]) || + (presence->largeImageText && presence->largeImageText[0]) || + (presence->smallImageKey && presence->smallImageKey[0]) || + (presence->smallImageText && presence->smallImageText[0])) { + WriteObject assets(writer, "assets"); + WriteOptionalString(writer, "large_image", presence->largeImageKey); + WriteOptionalString(writer, "large_text", presence->largeImageText); + WriteOptionalString(writer, "small_image", presence->smallImageKey); + WriteOptionalString(writer, "small_text", presence->smallImageText); + } + + if ((presence->partyId && presence->partyId[0]) || presence->partySize || + presence->partyMax || presence->partyPrivacy) { + WriteObject party(writer, "party"); + WriteOptionalString(writer, "id", presence->partyId); + if (presence->partySize && presence->partyMax) { + WriteArray size(writer, "size"); + writer.Int(presence->partySize); + writer.Int(presence->partyMax); + } + + if (presence->partyPrivacy) { + WriteKey(writer, "privacy"); + writer.Int(presence->partyPrivacy); + } + } + + if ((presence->matchSecret && presence->matchSecret[0]) || + (presence->joinSecret && presence->joinSecret[0]) || + (presence->spectateSecret && presence->spectateSecret[0])) { + WriteObject secrets(writer, "secrets"); + WriteOptionalString(writer, "match", presence->matchSecret); + WriteOptionalString(writer, "join", presence->joinSecret); + WriteOptionalString(writer, "spectate", presence->spectateSecret); + } + + writer.Key("instance"); + writer.Bool(presence->instance != 0); + } + } + } + + return writer.Size(); +} + +size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId) +{ + JsonWriter writer(dest, maxLen); + + { + WriteObject obj(writer); + WriteKey(writer, "v"); + writer.Int(version); + WriteKey(writer, "client_id"); + writer.String(applicationId); + } + + return writer.Size(); +} + +size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) +{ + JsonWriter writer(dest, maxLen); + + { + WriteObject obj(writer); + + JsonWriteNonce(writer, nonce); + + WriteKey(writer, "cmd"); + writer.String("SUBSCRIBE"); + + WriteKey(writer, "evt"); + writer.String(evtName); + } + + return writer.Size(); +} + +size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) +{ + JsonWriter writer(dest, maxLen); + + { + WriteObject obj(writer); + + JsonWriteNonce(writer, nonce); + + WriteKey(writer, "cmd"); + writer.String("UNSUBSCRIBE"); + + WriteKey(writer, "evt"); + writer.String(evtName); + } + + return writer.Size(); +} + +size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce) +{ + JsonWriter writer(dest, maxLen); + + { + WriteObject obj(writer); + + WriteKey(writer, "cmd"); + if (reply == DISCORD_REPLY_YES) { + writer.String("SEND_ACTIVITY_JOIN_INVITE"); + } + else { + writer.String("CLOSE_ACTIVITY_JOIN_REQUEST"); + } + + WriteKey(writer, "args"); + { + WriteObject args(writer); + + WriteKey(writer, "user_id"); + writer.String(userId); + } + + JsonWriteNonce(writer, nonce); + } + + return writer.Size(); +} diff --git a/libraries/discordrpc/src/serialization.h b/libraries/discordrpc/src/serialization.h new file mode 100644 index 00000000000..ddea73b2529 --- /dev/null +++ b/libraries/discordrpc/src/serialization.h @@ -0,0 +1,216 @@ +#pragma once + +#include + +#ifndef __MINGW32__ +#pragma warning(push) + +#pragma warning(disable : 4061) // enum is not explicitly handled by a case label +#pragma warning(disable : 4365) // signed/unsigned mismatch +#pragma warning(disable : 4464) // relative include path contains +#pragma warning(disable : 4668) // is not defined as a preprocessor macro +#pragma warning(disable : 6313) // Incorrect operator +#pragma warning(disable : 5045) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#endif // __MINGW32__ + +#include "rapidjson/document.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" + +#ifndef __MINGW32__ +#pragma warning(pop) +#endif // __MINGW32__ + +// if only there was a standard library function for this +template +inline size_t StringCopy(char (&dest)[Len], const char* src) +{ + if (!src || !Len) { + return 0; + } + size_t copied; + char* out = dest; + for (copied = 1; *src && copied < Len; ++copied) { + *out++ = *src++; + } + *out = 0; + return copied - 1; +} + +size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId); + +// Commands +struct DiscordRichPresence; +size_t JsonWriteRichPresenceObj(char* dest, + size_t maxLen, + int nonce, + int pid, + const DiscordRichPresence* presence); +size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName); + +size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName); + +size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce); + +// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need +// to supply some of your own allocators for stuff rather than use the defaults + +class LinearAllocator { +public: + char* buffer_; + char* end_; + LinearAllocator() + { + assert(0); // needed for some default case in rapidjson, should not use + } + LinearAllocator(char* buffer, size_t size) + : buffer_(buffer) + , end_(buffer + size) + { + } + static const bool kNeedFree = false; + void* Malloc(size_t size) + { + char* res = buffer_; + buffer_ += size; + if (buffer_ > end_) { + buffer_ = res; + return nullptr; + } + return res; + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) + { + if (newSize == 0) { + return nullptr; + } + // allocate how much you need in the first place + assert(!originalPtr && !originalSize); + // unused parameter warning + (void)(originalPtr); + (void)(originalSize); + return Malloc(newSize); + } + static void Free(void* ptr) + { + /* shrug */ + (void)ptr; + } +}; + +template +class FixedLinearAllocator : public LinearAllocator { +public: + char fixedBuffer_[Size]; + FixedLinearAllocator() + : LinearAllocator(fixedBuffer_, Size) + { + } + static const bool kNeedFree = false; +}; + +// wonder why this isn't a thing already, maybe I missed it +class DirectStringBuffer { +public: + using Ch = char; + char* buffer_; + char* end_; + char* current_; + + DirectStringBuffer(char* buffer, size_t maxLen) + : buffer_(buffer) + , end_(buffer + maxLen) + , current_(buffer) + { + } + + void Put(char c) + { + if (current_ < end_) { + *current_++ = c; + } + } + void Flush() {} + size_t GetSize() const { return (size_t)(current_ - buffer_); } +}; + +using MallocAllocator = rapidjson::CrtAllocator; +using PoolAllocator = rapidjson::MemoryPoolAllocator; +using UTF8 = rapidjson::UTF8; +// Writer appears to need about 16 bytes per nested object level (with 64bit size_t) +using StackAllocator = FixedLinearAllocator<2048>; +constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t)); +using JsonWriterBase = + rapidjson::Writer; +class JsonWriter : public JsonWriterBase { +public: + DirectStringBuffer stringBuffer_; + StackAllocator stackAlloc_; + + JsonWriter(char* dest, size_t maxLen) + : JsonWriterBase(stringBuffer_, &stackAlloc_, WriterNestingLevels) + , stringBuffer_(dest, maxLen) + , stackAlloc_() + { + } + + size_t Size() const { return stringBuffer_.GetSize(); } +}; + +using JsonDocumentBase = rapidjson::GenericDocument; +class JsonDocument : public JsonDocumentBase { +public: + static const int kDefaultChunkCapacity = 32 * 1024; + // json parser will use this buffer first, then allocate more if needed; I seriously doubt we + // send any messages that would use all of this, though. + char parseBuffer_[32 * 1024]; + MallocAllocator mallocAllocator_; + PoolAllocator poolAllocator_; + StackAllocator stackAllocator_; + JsonDocument() + : JsonDocumentBase(rapidjson::kObjectType, + &poolAllocator_, + sizeof(stackAllocator_.fixedBuffer_), + &stackAllocator_) + , poolAllocator_(parseBuffer_, sizeof(parseBuffer_), kDefaultChunkCapacity, &mallocAllocator_) + , stackAllocator_() + { + } +}; + +using JsonValue = rapidjson::GenericValue; + +inline JsonValue* GetObjMember(JsonValue* obj, const char* name) +{ + if (obj) { + auto member = obj->FindMember(name); + if (member != obj->MemberEnd() && member->value.IsObject()) { + return &member->value; + } + } + return nullptr; +} + +inline int GetIntMember(JsonValue* obj, const char* name, int notFoundDefault = 0) +{ + if (obj) { + auto member = obj->FindMember(name); + if (member != obj->MemberEnd() && member->value.IsInt()) { + return member->value.GetInt(); + } + } + return notFoundDefault; +} + +inline const char* GetStrMember(JsonValue* obj, + const char* name, + const char* notFoundDefault = nullptr) +{ + if (obj) { + auto member = obj->FindMember(name); + if (member != obj->MemberEnd() && member->value.IsString()) { + return member->value.GetString(); + } + } + return notFoundDefault; +} diff --git a/libraries/gdtoa/CMakeLists.txt b/libraries/gdtoa/CMakeLists.txt deleted file mode 100644 index 485f3778bf7..00000000000 --- a/libraries/gdtoa/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG" ) - -# Disable warnings for << operator precedence (4554) and -# unreferenced labels (4102) from VC -if( MSVC ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4554 /wd4102" ) -endif() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra" ) -endif() - -include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) -add_definitions( -DINFNAN_CHECK -DMULTIPLE_THREADS ) - -if( NOT MSVC AND NOT APPLE ) - if( NOT CMAKE_CROSSCOMPILING ) - add_executable( arithchk arithchk.c ) - endif() - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/arith.h - COMMAND arithchk >${CMAKE_CURRENT_BINARY_DIR}/arith.h - DEPENDS arithchk ) - - if( NOT CMAKE_CROSSCOMPILING ) - add_executable( qnan qnan.c arith.h ) - set( CROSS_EXPORTS ${CROSS_EXPORTS} arithchk qnan PARENT_SCOPE ) - endif() - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h - COMMAND qnan >${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h - DEPENDS qnan ) - - set( GEN_FP_FILES arith.h gd_qnan.h ) - set( GEN_FP_DEPS ${CMAKE_CURRENT_BINARY_DIR}/arith.h ${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h ) -endif() - -add_library( gdtoa STATIC - ${GEN_FP_FILES} - dmisc.c - dtoa.c - misc.c - ) -target_link_libraries( gdtoa ) - diff --git a/libraries/gdtoa/README b/libraries/gdtoa/README deleted file mode 100644 index 1bf7d91e43e..00000000000 --- a/libraries/gdtoa/README +++ /dev/null @@ -1,400 +0,0 @@ -This directory contains source for a library of binary -> decimal -and decimal -> binary conversion routines, for single-, double-, -and extended-precision IEEE binary floating-point arithmetic, and -other IEEE-like binary floating-point, including "double double", -as in - - T. J. Dekker, "A Floating-Point Technique for Extending the - Available Precision", Numer. Math. 18 (1971), pp. 224-242 - -and - - "Inside Macintosh: PowerPC Numerics", Addison-Wesley, 1994 - -The conversion routines use double-precision floating-point arithmetic -and, where necessary, high precision integer arithmetic. The routines -are generalizations of the strtod and dtoa routines described in - - David M. Gay, "Correctly Rounded Binary-Decimal and - Decimal-Binary Conversions", Numerical Analysis Manuscript - No. 90-10, Bell Labs, Murray Hill, 1990; - http://cm.bell-labs.com/cm/cs/what/ampl/REFS/rounding.ps.gz - -(based in part on papers by Clinger and Steele & White: see the -references in the above paper). - -The present conversion routines should be able to use any of IEEE binary, -VAX, or IBM-mainframe double-precision arithmetic internally, but I (dmg) -have so far only had a chance to test them with IEEE double precision -arithmetic. - -The core conversion routines are strtodg for decimal -> binary conversions -and gdtoa for binary -> decimal conversions. These routines operate -on arrays of unsigned 32-bit integers of type ULong, a signed 32-bit -exponent of type Long, and arithmetic characteristics described in -struct FPI; FPI, Long, and ULong are defined in gdtoa.h. File arith.h -is supposed to provide #defines that cause gdtoa.h to define its -types correctly. File arithchk.c is source for a program that -generates a suitable arith.h on all systems where I've been able to -test it. - -The core conversion routines are meant to be called by helper routines -that know details of the particular binary arithmetic of interest and -convert. The present directory provides helper routines for 5 variants -of IEEE binary floating-point arithmetic, each indicated by one or -two letters: - - f IEEE single precision - d IEEE double precision - x IEEE extended precision, as on Intel 80x87 - and software emulations of Motorola 68xxx chips - that do not pad the way the 68xxx does, but - only store 80 bits - xL IEEE extended precision, as on Motorola 68xxx chips - Q quad precision, as on Sun Sparc chips - dd double double, pairs of IEEE double numbers - whose sum is the desired value - -For decimal -> binary conversions, there are three families of -helper routines: one for round-nearest (or the current rounding -mode on IEEE-arithmetic systems that provide the C99 fegetround() -function, if compiled with -DHonor_FLT_ROUNDS): - - strtof - strtod - strtodd - strtopd - strtopf - strtopx - strtopxL - strtopQ - -one with rounding direction specified: - - strtorf - strtord - strtordd - strtorx - strtorxL - strtorQ - -and one for computing an interval (at most one bit wide) that contains -the decimal number: - - strtoIf - strtoId - strtoIdd - strtoIx - strtoIxL - strtoIQ - -The latter call strtoIg, which makes one call on strtodg and adjusts -the result to provide the desired interval. On systems where native -arithmetic can easily make one-ulp adjustments on values in the -desired floating-point format, it might be more efficient to use the -native arithmetic. Routine strtodI is a variant of strtoId that -illustrates one way to do this for IEEE binary double-precision -arithmetic -- but whether this is more efficient remains to be seen. - -Functions strtod and strtof have "natural" return types, float and -double -- strtod is specified by the C standard, and strtof appears -in the stdlib.h of some systems, such as (at least some) Linux systems. -The other functions write their results to their final argument(s): -to the final two argument for the strtoI... (interval) functions, -and to the final argument for the others (strtop... and strtor...). -Where possible, these arguments have "natural" return types (double* -or float*), to permit at least some type checking. In reality, they -are viewed as arrays of ULong (or, for the "x" functions, UShort) -values. On systems where long double is the appropriate type, one can -pass long double* final argument(s) to these routines. The int value -that these routines return is the return value from the call they make -on strtodg; see the enum of possible return values in gdtoa.h. - -Source files g_ddfmt.c, misc.c, smisc.c, strtod.c, strtodg.c, and ulp.c -should use true IEEE double arithmetic (not, e.g., double extended), -at least for storing (and viewing the bits of) the variables declared -"double" within them. - -One detail indicated in struct FPI is whether the target binary -arithmetic departs from the IEEE standard by flushing denormalized -numbers to 0. On systems that do this, the helper routines for -conversion to double-double format (when compiled with -Sudden_Underflow #defined) penalize the bottom of the exponent -range so that they return a nonzero result only when the least -significant bit of the less significant member of the pair of -double values returned can be expressed as a normalized double -value. An alternative would be to drop to 53-bit precision near -the bottom of the exponent range. To get correct rounding, this -would (in general) require two calls on strtodg (one specifying -126-bit arithmetic, then, if necessary, one specifying 53-bit -arithmetic). - -By default, the core routine strtodg and strtod set errno to ERANGE -if the result overflows to +Infinity or underflows to 0. Compile -these routines with NO_ERRNO #defined to inhibit errno assignments. - -Routine strtod is based on netlib's "dtoa.c from fp", and -(f = strtod(s,se)) is more efficient for some conversions than, say, -strtord(s,se,1,&f). Parts of strtod require true IEEE double -arithmetic with the default rounding mode (round-to-nearest) and, on -systems with IEEE extended-precision registers, double-precision -(53-bit) rounding precision. If the machine uses (the equivalent of) -Intel 80x87 arithmetic, the call - _control87(PC_53, MCW_PC); -does this with many compilers. Whether this or another call is -appropriate depends on the compiler; for this to work, it may be -necessary to #include "float.h" or another system-dependent header -file. - -Source file strtodnrp.c gives a strtod that does not require 53-bit -rounding precision on systems (such as Intel IA32 systems) that may -suffer double rounding due to use of extended-precision registers. -For some conversions this variant of strtod is less efficient than the -one in strtod.c when the latter is run with 53-bit rounding precision. - -When float or double are involved, the values that the strto* routines -return for NaNs are determined by gd_qnan.h, which the makefile -generates by running the program whose source is qnan.c. For other -types, default NaN values are specified in g__fmt.c and may need -adjusting. Note that the rules for distinguishing signaling from -quiet NaNs are system-dependent. For cross-compilation, you need to -determine arith.h and gd_qnan.h suitably, e.g., using the arithmetic -of the target machine. - -C99's hexadecimal floating-point constants are recognized by the -strto* routines (but this feature has not yet been heavily tested). -Compiling with NO_HEX_FP #defined disables this feature. - -When compiled with -DINFNAN_CHECK, the strto* routines recognize C99's -NaN and Infinity syntax. Moreover, unless No_Hex_NaN is #defined, the -strto* routines also recognize C99's NaN(...) syntax: they accept -(case insensitively) strings of the form NaN(x), where x is a string -of hexadecimal digits and spaces; if there is only one string of -hexadecimal digits, it is taken for the fraction bits of the resulting -NaN; if there are two or more strings of hexadecimal digits, each -string is assigned to the next available sequence of 32-bit words of -fractions bits (starting with the most significant), right-aligned in -each sequence. Strings of hexadecimal digits may be preceded by "0x" -or "0X". - -For binary -> decimal conversions, I've provided a family of helper -routines: - - g_ffmt - g_dfmt - g_ddfmt - g_xfmt - g_xLfmt - g_Qfmt - g_ffmt_p - g_dfmt_p - g_ddfmt_p - g_xfmt_p - g_xLfmt_p - g_Qfmt_p - -which do a "%g" style conversion either to a specified number of decimal -places (if their ndig argument is positive), or to the shortest -decimal string that rounds to the given binary floating-point value -(if ndig <= 0). They write into a buffer supplied as an argument -and return either a pointer to the end of the string (a null character) -in the buffer, if the buffer was long enough, or 0. Other forms of -conversion are easily done with the help of gdtoa(), such as %e or %f -style and conversions with direction of rounding specified (so that, if -desired, the decimal value is either >= or <= the binary value). -On IEEE-arithmetic systems that provide the C99 fegetround() function, -if compiled with -DHonor_FLT_ROUNDS, these routines honor the current -rounding mode. For pedants, the ...fmt_p() routines are similar to the -...fmt() routines, but have an additional final int argument, nik, -that for conversions of Infinity or NaN, determines whether upper, -lower, or mixed case is used, whether (...) is added to NaN values, -and whether the sign of a NaN is reported or suppressed: - - nik = ic + 6*(nb + 3*ns), - -where ic with 0 <= ic < 6 controls the rendering of Infinity and NaN: - - 0 ==> Infinity or NaN - 1 ==> infinity or nan - 2 ==> INFINITY or NAN - 3 ==> Inf or NaN - 4 ==> inf or nan - 5 ==> INF or NAN - -nb with 0 <= nb < 3 determines whether NaN values are rendered -as NaN(...): - - 0 ==> no - 1 ==> yes - 2 ==> no for default NaN values; yes otherwise - -ns = 0 or 1 determines whether the sign of NaN values reported: - - 0 ==> distinguish NaN and -NaN - 1 ==> report both as NaN - -For an example of more general conversions based on dtoa(), see -netlib's "printf.c from ampl/solvers". - -For double-double -> decimal, g_ddfmt() assumes IEEE-like arithmetic -of precision max(126, #bits(input)) bits, where #bits(input) is the -number of mantissa bits needed to represent the sum of the two double -values in the input. - -The makefile creates a library, gdtoa.a. To use the helper -routines, a program only needs to include gdtoa.h. All the -source files for gdtoa.a include a more extensive gdtoaimp.h; -among other things, gdtoaimp.h has #defines that make "internal" -names end in _D2A. To make a "system" library, one could modify -these #defines to make the names start with __. - -Various comments about possible #defines appear in gdtoaimp.h, -but for most purposes, arith.h should set suitable #defines. - -Systems with preemptive scheduling of multiple threads require some -manual intervention. On such systems, it's necessary to compile -dmisc.c, dtoa.c gdota.c, and misc.c with MULTIPLE_THREADS #defined, -and to provide (or suitably #define) two locks, acquired by -ACQUIRE_DTOA_LOCK(n) and freed by FREE_DTOA_LOCK(n) for n = 0 or 1. -(The second lock, accessed in pow5mult, ensures lazy evaluation of -only one copy of high powers of 5; omitting this lock would introduce -a small probability of wasting memory, but would otherwise be harmless.) -Routines that call dtoa or gdtoa directly must also invoke freedtoa(s) -to free the value s returned by dtoa or gdtoa. It's OK to do so whether -or not MULTIPLE_THREADS is #defined, and the helper g_*fmt routines -listed above all do this indirectly (in gfmt_D2A(), which they all call). - -By default, there is a private pool of memory of length 2000 bytes -for intermediate quantities, and MALLOC (see gdtoaimp.h) is called only -if the private pool does not suffice. 2000 is large enough that MALLOC -is called only under very unusual circumstances (decimal -> binary -conversion of very long strings) for conversions to and from double -precision. For systems with preemptively scheduled multiple threads -or for conversions to extended or quad, it may be appropriate to -#define PRIVATE_MEM nnnn, where nnnn is a suitable value > 2000. -For extended and quad precisions, -DPRIVATE_MEM=20000 is probably -plenty even for many digits at the ends of the exponent range. -Use of the private pool avoids some overhead. - -Directory test provides some test routines. See its README. -I've also tested this stuff (except double double conversions) -with Vern Paxson's testbase program: see - - V. Paxson and W. Kahan, "A Program for Testing IEEE Binary-Decimal - Conversion", manuscript, May 1991, - ftp://ftp.ee.lbl.gov/testbase-report.ps.Z . - -(The same ftp directory has source for testbase.) - -Some system-dependent additions to CFLAGS in the makefile: - - HU-UX: -Aa -Ae - OSF (DEC Unix): -ieee_with_no_inexact - SunOS 4.1x: -DKR_headers -DBad_float_h - -If you want to put this stuff into a shared library and your -operating system requires export lists for shared libraries, -the following would be an appropriate export list: - - dtoa - freedtoa - g_Qfmt - g_ddfmt - g_dfmt - g_ffmt - g_xLfmt - g_xfmt - gdtoa - strtoIQ - strtoId - strtoIdd - strtoIf - strtoIx - strtoIxL - strtod - strtodI - strtodg - strtof - strtopQ - strtopd - strtopdd - strtopf - strtopx - strtopxL - strtorQ - strtord - strtordd - strtorf - strtorx - strtorxL - -When time permits, I (dmg) hope to write in more detail about the -present conversion routines; for now, this README file must suffice. -Meanwhile, if you wish to write helper functions for other kinds of -IEEE-like arithmetic, some explanation of struct FPI and the bits -array may be helpful. Both gdtoa and strtodg operate on a bits array -described by FPI *fpi. The bits array is of type ULong, a 32-bit -unsigned integer type. Floating-point numbers have fpi->nbits bits, -with the least significant 32 bits in bits[0], the next 32 bits in -bits[1], etc. These numbers are regarded as integers multiplied by -2^e (i.e., 2 to the power of the exponent e), where e is the second -argument (be) to gdtoa and is stored in *exp by strtodg. The minimum -and maximum exponent values fpi->emin and fpi->emax for normalized -floating-point numbers reflect this arrangement. For example, the -P754 standard for binary IEEE arithmetic specifies doubles as having -53 bits, with normalized values of the form 1.xxxxx... times 2^(b-1023), -with 52 bits (the x's) and the biased exponent b represented explicitly; -b is an unsigned integer in the range 1 <= b <= 2046 for normalized -finite doubles, b = 0 for denormals, and b = 2047 for Infinities and NaNs. -To turn an IEEE double into the representation used by strtodg and gdtoa, -we multiply 1.xxxx... by 2^52 (to make it an integer) and reduce the -exponent e = (b-1023) by 52: - - fpi->emin = 1 - 1023 - 52 - fpi->emax = 1046 - 1023 - 52 - -In various wrappers for IEEE double, we actually write -53 + 1 rather -than -52, to emphasize that there are 53 bits including one implicit bit. -Field fpi->rounding indicates the desired rounding direction, with -possible values - FPI_Round_zero = toward 0, - FPI_Round_near = unbiased rounding -- the IEEE default, - FPI_Round_up = toward +Infinity, and - FPI_Round_down = toward -Infinity -given in gdtoa.h. - -Field fpi->sudden_underflow indicates whether strtodg should return -denormals or flush them to zero. Normal floating-point numbers have -bit fpi->nbits in the bits array on. Denormals have it off, with -exponent = fpi->emin. Strtodg provides distinct return values for normals -and denormals; see gdtoa.h. - -Compiling g__fmt.c, strtod.c, and strtodg.c with -DUSE_LOCALE causes -the decimal-point character to be taken from the current locale; otherwise -it is '.'. - -Source files dtoa.c and strtod.c in this directory are derived from -netlib's "dtoa.c from fp" and are meant to function equivalently. -When compiled with Honor_FLT_ROUNDS #defined (on systems that provide -FLT_ROUNDS and fegetround() as specified in the C99 standard), they -honor the current rounding mode. Because FLT_ROUNDS is buggy on some -(Linux) systems -- not reflecting calls on fesetround(), as the C99 -standard says it should -- when Honor_FLT_ROUNDS is #defined, the -current rounding mode is obtained from fegetround() rather than from -FLT_ROUNDS, unless Trust_FLT_ROUNDS is also #defined. - -Compile with -DUSE_LOCALE to use the current locale; otherwise -decimal points are assumed to be '.'. With -DUSE_LOCALE, unless -you also compile with -DNO_LOCALE_CACHE, the details about the -current "decimal point" character string are cached and assumed not -to change during the program's execution. - -On machines with a 64-bit long double and perhaps a 113-bit "quad" -type, you can invoke "make Printf" to add Printf (and variants, such -as Fprintf) to gdtoa.a. These are analogs, declared in stdio1.h, of -printf and fprintf, etc. in which %La, %Le, %Lf, and %Lg are for long -double and (if appropriate) %Lqa, %Lqe, %Lqf, and %Lqg are for quad -precision printing. - -Please send comments to David M. Gay (dmg at acm dot org, with " at " -changed at "@" and " dot " changed to "."). diff --git a/libraries/gdtoa/arithchk.c b/libraries/gdtoa/arithchk.c deleted file mode 100644 index ef6cda3db4e..00000000000 --- a/libraries/gdtoa/arithchk.c +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************** -Copyright (C) 1997, 1998 Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. -****************************************************************/ - -/* Try to deduce arith.h from arithmetic properties. */ - -#include - - static int dalign; - typedef struct -Akind { - char *name; - int kind; - } Akind; - - static Akind -IEEE_8087 = { "IEEE_8087", 1 }, -IEEE_MC68k = { "IEEE_MC68k", 2 }, -IBM = { "IBM", 3 }, -VAX = { "VAX", 4 }, -CRAY = { "CRAY", 5}; - - static Akind * -Lcheck() -{ - union { - double d; - long L[2]; - } u; - struct { - double d; - long L; - } x[2]; - - if (sizeof(x) > 2*(sizeof(double) + sizeof(long))) - dalign = 1; - u.L[0] = u.L[1] = 0; - u.d = 1e13; - if (u.L[0] == 1117925532 && u.L[1] == -448790528) - return &IEEE_MC68k; - if (u.L[1] == 1117925532 && u.L[0] == -448790528) - return &IEEE_8087; - if (u.L[0] == -2065213935 && u.L[1] == 10752) - return &VAX; - if (u.L[0] == 1267827943 && u.L[1] == 704643072) - return &IBM; - return 0; - } - - static Akind * -icheck() -{ - union { - double d; - int L[2]; - } u; - struct { - double d; - int L; - } x[2]; - - if (sizeof(x) > 2*(sizeof(double) + sizeof(int))) - dalign = 1; - u.L[0] = u.L[1] = 0; - u.d = 1e13; - if (u.L[0] == 1117925532 && u.L[1] == -448790528) - return &IEEE_MC68k; - if (u.L[1] == 1117925532 && u.L[0] == -448790528) - return &IEEE_8087; - if (u.L[0] == -2065213935 && u.L[1] == 10752) - return &VAX; - if (u.L[0] == 1267827943 && u.L[1] == 704643072) - return &IBM; - return 0; - } - -char *emptyfmt = ""; /* avoid possible warning message with printf("") */ - - static Akind * -ccheck() -{ - union { - double d; - long L; - } u; - long Cray1; - - /* Cray1 = 4617762693716115456 -- without overflow on non-Crays */ - Cray1 = printf("%s", emptyfmt) < 0 ? 0 : 4617762; - if (printf(emptyfmt, Cray1) >= 0) - Cray1 = 1000000*Cray1 + 693716; - if (printf(emptyfmt, Cray1) >= 0) - Cray1 = 1000000*Cray1 + 115456; - u.d = 1e13; - if (u.L == Cray1) - return &CRAY; - return 0; - } - - static int -fzcheck() -{ - double a, b; - int i; - - a = 1.; - b = .1; - for(i = 155;; b *= b, i >>= 1) { - if (i & 1) { - a *= b; - if (i == 1) - break; - } - } - b = a * a; - return b == 0.; - } - - int -main() -{ - Akind *a = 0; - int Ldef = 0; - FILE *f; - -#ifdef WRITE_ARITH_H /* for Symantec's buggy "make" */ - f = fopen("arith.h", "w"); - if (!f) { - printf("Cannot open arith.h\n"); - return 1; - } -#else - f = stdout; -#endif - - if (sizeof(double) == 2*sizeof(long)) - a = Lcheck(); - else if (sizeof(double) == 2*sizeof(int)) { - Ldef = 1; - a = icheck(); - } - else if (sizeof(double) == sizeof(long)) - a = ccheck(); - if (a) { - fprintf(f, "#define %s\n#define Arith_Kind_ASL %d\n", - a->name, a->kind); - if (Ldef) - fprintf(f, "#define Long int\n#define Intcast (int)(long)\n"); - if (dalign) - fprintf(f, "#define Double_Align\n"); - if (sizeof(char*) == 8) - fprintf(f, "#define X64_bit_pointers\n"); -#ifndef NO_LONG_LONG - if (sizeof(long long) < 8) -#endif - fprintf(f, "#define NO_LONG_LONG\n"); - if (a->kind <= 2 && fzcheck()) - fprintf(f, "#define Sudden_Underflow\n"); - return 0; - } - fprintf(f, "/* Unknown arithmetic */\n"); - return 1; - } diff --git a/libraries/gdtoa/dmisc.c b/libraries/gdtoa/dmisc.c deleted file mode 100644 index 3e712511bb5..00000000000 --- a/libraries/gdtoa/dmisc.c +++ /dev/null @@ -1,216 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#ifndef MULTIPLE_THREADS - char *dtoa_result; -#endif - - char * -#ifdef KR_headers -rv_alloc(i) int i; -#else -rv_alloc(int i) -#endif -{ - int j, k, *r; - - j = sizeof(ULong); - for(k = 0; - sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)(i); - j <<= 1) - k++; - r = (int*)Balloc(k); - *r = k; - return -#ifndef MULTIPLE_THREADS - dtoa_result = -#endif - (char *)(r+1); - } - - char * -#ifdef KR_headers -nrv_alloc(s, rve, n) char *s, **rve; int n; -#else -nrv_alloc(char *s, char **rve, int n) -#endif -{ - char *rv, *t; - - t = rv = rv_alloc(n); - while((*t = *s++) !=0) - t++; - if (rve) - *rve = t; - return rv; - } - -/* freedtoa(s) must be used to free values s returned by dtoa - * when MULTIPLE_THREADS is #defined. It should be used in all cases, - * but for consistency with earlier versions of dtoa, it is optional - * when MULTIPLE_THREADS is not defined. - */ - - void -#ifdef KR_headers -freedtoa(s) char *s; -#else -freedtoa(char *s) -#endif -{ - Bigint *b = (Bigint *)((int *)s - 1); - b->maxwds = 1 << (b->k = *(int*)b); - Bfree(b); -#ifndef MULTIPLE_THREADS - if (s == dtoa_result) - dtoa_result = 0; -#endif - } - - int -quorem -#ifdef KR_headers - (b, S) Bigint *b, *S; -#else - (Bigint *b, Bigint *S) -#endif -{ - int n; - ULong *bx, *bxe, q, *sx, *sxe; -#ifdef ULLong - ULLong borrow, carry, y, ys; -#else - ULong borrow, carry, y, ys; -#ifdef Pack_32 - ULong si, z, zs; -#endif -#endif - - n = S->wds; -#ifdef DEBUG - /*debug*/ if (b->wds > n) - /*debug*/ Bug("oversize b in quorem"); -#endif - if (b->wds < n) - return 0; - sx = S->x; - sxe = sx + --n; - bx = b->x; - bxe = bx + n; - q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ -#ifdef DEBUG - /*debug*/ if (q > 9) - /*debug*/ Bug("oversized quotient in quorem"); -#endif - if (q) { - borrow = 0; - carry = 0; - do { -#ifdef ULLong - ys = *sx++ * (ULLong)q + carry; - carry = ys >> 32; - y = *bx - (ys & 0xffffffffUL) - borrow; - borrow = y >> 32 & 1UL; - *bx++ = (ULong)(y & 0xffffffffUL); -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) * q + carry; - zs = (si >> 16) * q + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } - while(sx <= sxe); - if (!*bxe) { - bx = b->x; - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - if (cmp(b, S) >= 0) { - q++; - borrow = 0; - carry = 0; - bx = b->x; - sx = S->x; - do { -#ifdef ULLong - ys = *sx++ + carry; - carry = ys >> 32; - y = *bx - (ys & 0xffffffffUL) - borrow; - borrow = y >> 32 & 1UL; - *bx++ = (ULong)(y & 0xffffffffUL); -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) + carry; - zs = (si >> 16) + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } - while(sx <= sxe); - bx = b->x; - bxe = bx + n; - if (!*bxe) { - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - return q; - } diff --git a/libraries/gdtoa/dtoa.c b/libraries/gdtoa/dtoa.c deleted file mode 100644 index c96e6a5452b..00000000000 --- a/libraries/gdtoa/dtoa.c +++ /dev/null @@ -1,780 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the Long - * calculation. - */ - -#ifdef Honor_FLT_ROUNDS -#undef Check_FLT_ROUNDS -#define Check_FLT_ROUNDS -#else -#define Rounding Flt_Rounds -#endif - - char * -dtoa -#ifdef KR_headers - (d0, mode, ndigits, decpt, sign, rve) - double d0; int mode, ndigits, *decpt, *sign; char **rve; -#else - (double d0, int mode, int ndigits, int *decpt, int *sign, char **rve) -#endif -{ - /* Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4,5 ==> similar to 2 and 3, respectively, but (in - round-nearest mode) with the tests of mode 0 to - possibly return a shorter string that rounds to d. - With IEEE arithmetic and compilation with - -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same - as modes 2 and 3 when FLT_ROUNDS != 1. - 6-9 ==> Debugging modes similar to mode - 4: don't try - fast floating-point estimate (if applicable). - - Values of mode other than 0-9 are treated as mode 0. - - Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. - */ - - int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - spec_case, try_quick; - Long L; -#ifndef Sudden_Underflow - int denorm; - ULong x; -#endif - Bigint *b, *b1, *delta, *mlo, *mhi, *S; - U d, d2, eps; - double ds; - char *s, *s0; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif -#ifdef Honor_FLT_ROUNDS /*{*/ - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ -#endif /*}*/ - -#ifndef MULTIPLE_THREADS - if (dtoa_result) { - freedtoa(dtoa_result); - dtoa_result = 0; - } -#endif - d.d = d0; - if (word0(&d) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - word0(&d) &= ~Sign_bit; /* clear sign bit */ - } - else - *sign = 0; - -#if defined(IEEE_Arith) + defined(VAX) -#ifdef IEEE_Arith - if ((word0(&d) & Exp_mask) == Exp_mask) -#else - if (word0(&d) == 0x8000) -#endif - { - /* Infinity or NaN */ - *decpt = 9999; -#ifdef IEEE_Arith - if (!word1(&d) && !(word0(&d) & 0xfffff)) - return nrv_alloc("Infinity", rve, 8); -#endif - return nrv_alloc("NaN", rve, 3); - } -#endif -#ifdef IBM - dval(&d) += 0; /* normalize */ -#endif - if (!dval(&d)) { - *decpt = 1; - return nrv_alloc("0", rve, 1); - } - -#ifdef SET_INEXACT - try_quick = oldinexact = get_inexact(); - inexact = 1; -#endif -#ifdef Honor_FLT_ROUNDS - if (Rounding >= 2) { - if (*sign) - Rounding = Rounding == 2 ? 0 : 2; - else - if (Rounding != 2) - Rounding = 0; - } -#endif - - b = d2b(dval(&d), &be, &bbits); -#ifdef Sudden_Underflow - i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); -#else - if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) { -#endif - dval(&d2) = dval(&d); - word0(&d2) &= Frac_mask1; - word0(&d2) |= Exp_11; -#ifdef IBM - if (( j = 11 - hi0bits(word0(&d2) & Frac_mask) )!=0) - dval(&d2) /= 1 << j; -#endif - - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2) - * - * This suggests computing an approximation k to log10(&d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ - - i -= Bias; -#ifdef IBM - i <<= 2; - i += j; -#endif -#ifndef Sudden_Underflow - denorm = 0; - } - else { - /* d is denormalized */ - - i = bbits + be + (Bias + (P-1) - 1); - x = i > 32 ? word0(&d) << (64 - i) | word1(&d) >> (i - 32) - : word1(&d) << (32 - i); - dval(&d2) = x; - word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ - i -= (Bias + (P-1) - 1) + 1; - denorm = 1; - } -#endif - ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; - k = (int)ds; - if (ds < 0. && ds != k) - k--; /* want k = floor(ds) */ - k_check = 1; - if (k >= 0 && k <= Ten_pmax) { - if (dval(&d) < tens[k]) - k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } - else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } - else { - b2 -= k; - b5 = -k; - s5 = 0; - } - if (mode < 0 || mode > 9) - mode = 0; - -#ifndef SET_INEXACT -#ifdef Check_FLT_ROUNDS - try_quick = Rounding == 1; -#else - try_quick = 1; -#endif -#endif /*SET_INEXACT*/ - - if (mode > 5) { - mode -= 4; - try_quick = 0; - } - leftright = 1; - ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ - /* silence erroneous "gcc -Wall" warning. */ - switch(mode) { - case 0: - case 1: - i = 18; - ndigits = 0; - break; - case 2: - leftright = 0; - /* no break */ - case 4: - if (ndigits <= 0) - ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - /* no break */ - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) - i = 1; - } - s = s0 = rv_alloc(i); - -#ifdef Honor_FLT_ROUNDS - if (mode > 1 && Rounding != 1) - leftright = 0; -#endif - - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - dval(&d2) = dval(&d); - k0 = k; - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = tens[k&0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - dval(&d) /= bigtens[n_bigtens-1]; - ieps++; - } - for(; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - dval(&d) /= ds; - } - else if (( j1 = -k )!=0) { - dval(&d) *= tens[j1 & 0xf]; - for(j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - dval(&d) *= bigtens[i]; - } - } - if (k_check && dval(&d) < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - dval(&d) *= 10.; - ieps++; - } - dval(&eps) = ieps*dval(&d) + 7.; - word0(&eps) -= (P-1)*Exp_msk1; - if (ilim == 0) { - S = mhi = 0; - dval(&d) -= 5.; - if (dval(&d) > dval(&eps)) - goto one_digit; - if (dval(&d) < -dval(&eps)) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); - for(i = 0;;) { - L = (Long)dval(&d); - dval(&d) -= L; - *s++ = '0' + (int)L; - if (dval(&d) < dval(&eps)) - goto ret1; - if (1. - dval(&d) < dval(&eps)) - goto bump_up; - if (++i >= ilim) - break; - dval(&eps) *= 10.; - dval(&d) *= 10.; - } - } - else { -#endif - /* Generate ilim digits, then fix them up. */ - dval(&eps) *= tens[ilim-1]; - for(i = 1;; i++, dval(&d) *= 10.) { - L = (Long)(dval(&d)); - if (!(dval(&d) -= L)) - ilim = i; - *s++ = '0' + (int)L; - if (i == ilim) { - if (dval(&d) > 0.5 + dval(&eps)) - goto bump_up; - else if (dval(&d) < 0.5 - dval(&eps)) { - while(*--s == '0'); - s++; - goto ret1; - } - break; - } - } -#ifndef No_leftright - } -#endif - fast_failed: - s = s0; - dval(&d) = dval(&d2); - k = k0; - ilim = ilim0; - } - - /* Do we have a "small" integer? */ - - if (be >= 0 && k <= Int_max) { - /* Yes. */ - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || dval(&d) <= 5*ds) - goto no_digits; - goto one_digit; - } - for(i = 1;; i++, dval(&d) *= 10.) { - L = (Long)(dval(&d) / ds); - dval(&d) -= L*ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&d) < 0) { - L--; - dval(&d) += ds; - } -#endif - *s++ = '0' + (int)L; - if (!dval(&d)) { -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - if (i == ilim) { -#ifdef Honor_FLT_ROUNDS - if (mode > 1) - switch(Rounding) { - case 0: goto ret1; - case 2: goto bump_up; - } -#endif - dval(&d) += dval(&d); -#ifdef ROUND_BIASED - if (dval(&d) >= ds) -#else - if (dval(&d) > ds || (dval(&d) == ds && L & 1)) -#endif - { - bump_up: - while(*--s == '9') - if (s == s0) { - k++; - *s = '0'; - break; - } - ++*s++; - } - break; - } - } - goto ret1; - } - - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P-1) - 1 + 1) : -#endif -#ifdef IBM - 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); -#else - 1 + P - bbits; -#endif - b2 += i; - s2 += i; - mhi = i2b(1); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); - b = b1; - } - if (( j = b5 - m5 )!=0) - b = pow5mult(b, j); - } - else - b = pow5mult(b, b5); - } - S = i2b(1); - if (s5 > 0) - S = pow5mult(S, s5); - - /* Check for special case that d is a normalized power of 2. */ - - spec_case = 0; - if ((mode < 2 || leftright) -#ifdef Honor_FLT_ROUNDS - && Rounding == 1 -#endif - ) { - if (!word1(&d) && !(word0(&d) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(&d) & (Exp_mask & ~Exp_msk1) -#endif - ) { - /* The special case */ - b2 += Log2P; - s2 += Log2P; - spec_case = 1; - } - } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to quorem, so it - * can do shifts and ors to compute the numerator for q. - */ -#ifdef Pack_32 - if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f )!=0) - i = 32 - i; -#else - if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf )!=0) - i = 16 - i; -#endif - if (i > 4) { - i -= 4; - b2 += i; - m2 += i; - s2 += i; - } - else if (i < 4) { - i += 28; - b2 += i; - m2 += i; - s2 += i; - } - if (b2 > 0) - b = lshift(b, b2); - if (s2 > 0) - S = lshift(S, s2); - if (k_check) { - if (cmp(b,S) < 0) { - k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) - mhi = multadd(mhi, 10, 0); - ilim = ilim1; - } - } - if (ilim <= 0 && (mode == 3 || mode == 5)) { - if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { - /* no digits, fcvt style */ - no_digits: - k = -1 - ndigits; - goto ret; - } - one_digit: - *s++ = '1'; - k++; - goto ret; - } - if (leftright) { - if (m2 > 0) - mhi = lshift(mhi, m2); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = Balloc(mhi->k); - Bcopy(mhi, mlo); - mhi = lshift(mhi, Log2P); - } - - for(i = 1;;i++) { - dig = quorem(b,S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = cmp(b, mlo); - delta = diff(S, mhi); - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); -#ifndef ROUND_BIASED - if (j1 == 0 && mode != 1 && !(word1(&d) & 1) -#ifdef Honor_FLT_ROUNDS - && Rounding >= 1 -#endif - ) { - if (dig == '9') - goto round_9_up; - if (j > 0) - dig++; -#ifdef SET_INEXACT - else if (!b->x[0] && b->wds <= 1) - inexact = 0; -#endif - *s++ = dig; - goto ret; - } -#endif - if (j < 0 || (j == 0 && mode != 1 -#ifndef ROUND_BIASED - && !(word1(&d) & 1) -#endif - )) { - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto accept_dig; - } -#ifdef Honor_FLT_ROUNDS - if (mode > 1) - switch(Rounding) { - case 0: goto accept_dig; - case 2: goto keep_dig; - } -#endif /*Honor_FLT_ROUNDS*/ - if (j1 > 0) { - b = lshift(b, 1); - j1 = cmp(b, S); -#ifdef ROUND_BIASED - if (j1 >= 0 /*)*/ -#else - if ((j1 > 0 || (j1 == 0 && dig & 1)) -#endif - && dig++ == '9') - goto round_9_up; - } - accept_dig: - *s++ = dig; - goto ret; - } - if (j1 > 0) { -#ifdef Honor_FLT_ROUNDS - if (!Rounding) - goto accept_dig; -#endif - if (dig == '9') { /* possible if i == 1 */ - round_9_up: - *s++ = '9'; - goto roundoff; - } - *s++ = dig + 1; - goto ret; - } -#ifdef Honor_FLT_ROUNDS - keep_dig: -#endif - *s++ = dig; - if (i == ilim) - break; - b = multadd(b, 10, 0); - if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); - else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); - } - } - } - else - for(i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto ret; - } - if (i >= ilim) - break; - b = multadd(b, 10, 0); - } - - /* Round off last digit */ - -#ifdef Honor_FLT_ROUNDS - switch(Rounding) { - case 0: goto trimzeros; - case 2: goto roundoff; - } -#endif - b = lshift(b, 1); - j = cmp(b, S); -#ifdef ROUND_BIASED - if (j >= 0) -#else - if (j > 0 || (j == 0 && dig & 1)) -#endif - { - roundoff: - while(*--s == '9') - if (s == s0) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } - else { -#ifdef Honor_FLT_ROUNDS - trimzeros: -#endif - while(*--s == '0'); - s++; - } - ret: - Bfree(S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); - } - ret1: -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&d) = Exp_1 + (70 << Exp_shift); - word1(&d) = 0; - dval(&d) += 1.; - } - } - else if (!oldinexact) - clear_inexact(); -#endif - Bfree(b); - *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; - return s0; - } diff --git a/libraries/gdtoa/g_Qfmt.c b/libraries/gdtoa/g_Qfmt.c deleted file mode 100644 index 0f06970055c..00000000000 --- a/libraries/gdtoa/g_Qfmt.c +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#endif -#ifdef IEEE_8087 -#define _0 3 -#define _1 2 -#define _2 1 -#define _3 0 -#endif - - char* -#ifdef KR_headers -g_Qfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize; -#else -g_Qfmt(char *buf, void *V, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, 0, Int_max }; - char *b, *s, *se; - ULong bits[4], *L, sign; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (ULong*)V; - sign = L[_0] & 0x80000000L; - bits[3] = L[_0] & 0xffff; - bits[2] = L[_1]; - bits[1] = L[_2]; - bits[0] = L[_3]; - b = buf; - if ( (ex = (L[_0] & 0x7fff0000L) >> 16) !=0) { - if (ex == 0x7fff) { - /* Infinity or NaN */ - if (bits[0] | bits[1] | bits[2] | bits[3]) - b = strcp(b, "NaN"); - else { - b = buf; - if (sign) - *b++ = '-'; - b = strcp(b, "Infinity"); - } - return b; - } - i = STRTOG_Normal; - bits[3] |= 0x10000; - } - else if (bits[0] | bits[1] | bits[2] | bits[3]) { - i = STRTOG_Denormal; - ex = 1; - } - else { -#ifndef IGNORE_ZERO_SIGN - if (sign) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - ex -= 0x3fff + 112; - mode = 2; - if (ndig <= 0) { - if (bufsize < 48) - return 0; - mode = 0; - } - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/g__fmt.c b/libraries/gdtoa/g__fmt.c deleted file mode 100644 index 652c82b68e8..00000000000 --- a/libraries/gdtoa/g__fmt.c +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#ifdef USE_LOCALE -#include "locale.h" -#endif - -#ifndef ldus_QNAN0 -#define ldus_QNAN0 0x7fff -#endif -#ifndef ldus_QNAN1 -#define ldus_QNAN1 0xc000 -#endif -#ifndef ldus_QNAN2 -#define ldus_QNAN2 0 -#endif -#ifndef ldus_QNAN3 -#define ldus_QNAN3 0 -#endif -#ifndef ldus_QNAN4 -#define ldus_QNAN4 0 -#endif - - const char *InfName[6] = { "Infinity", "infinity", "INFINITY", "Inf", "inf", "INF" }; - const char *NanName[3] = { "NaN", "nan", "NAN" }; - ULong NanDflt_Q_D2A[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff }; - ULong NanDflt_d_D2A[2] = { d_QNAN1, d_QNAN0 }; - ULong NanDflt_f_D2A[1] = { f_QNAN }; - ULong NanDflt_xL_D2A[3] = { 1, 0x80000000, 0x7fff0000 }; - UShort NanDflt_ldus_D2A[5] = { ldus_QNAN4, ldus_QNAN3, ldus_QNAN2, ldus_QNAN1, ldus_QNAN0 }; - - char * -#ifdef KR_headers -g__fmt(b, s, se, decpt, sign, blen) char *b; char *s; char *se; int decpt; ULong sign; size_t blen; -#else -g__fmt(char *b, char *s, char *se, int decpt, ULong sign, size_t blen) -#endif -{ - int i, j, k; - char *be, *s0; - size_t len; -#ifdef USE_LOCALE -#ifdef NO_LOCALE_CACHE - char *decimalpoint = localeconv()->decimal_point; - size_t dlen = strlen(decimalpoint); -#else - char *decimalpoint; - static char *decimalpoint_cache; - static size_t dlen; - if (!(s0 = decimalpoint_cache)) { - s0 = localeconv()->decimal_point; - dlen = strlen(s0); - if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { - strcpy(decimalpoint_cache, s0); - s0 = decimalpoint_cache; - } - } - decimalpoint = s0; -#endif -#else -#define dlen 0 -#endif - s0 = s; - len = (se-s) + dlen + 6; /* 6 = sign + e+dd + trailing null */ - if (blen < len) - goto ret0; - be = b + blen - 1; - if (sign) - *b++ = '-'; - if (decpt <= -4 || decpt > se - s + 5) { - *b++ = *s++; - if (*s) { -#ifdef USE_LOCALE - while((*b = *decimalpoint++)) - ++b; -#else - *b++ = '.'; -#endif - while((*b = *s++) !=0) - b++; - } - *b++ = 'e'; - /* sprintf(b, "%+.2d", decpt - 1); */ - if (--decpt < 0) { - *b++ = '-'; - decpt = -decpt; - } - else - *b++ = '+'; - for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10){} - for(;;) { - i = decpt / k; - if (b >= be) - goto ret0; - *b++ = i + '0'; - if (--j <= 0) - break; - decpt -= i*k; - decpt *= 10; - } - *b = 0; - } - else if (decpt <= 0) { -#ifdef USE_LOCALE - while((*b = *decimalpoint++)) - ++b; -#else - *b++ = '.'; -#endif - if (be < b - decpt + (se - s)) - goto ret0; - for(; decpt < 0; decpt++) - *b++ = '0'; - while((*b = *s++) != 0) - b++; - } - else { - while((*b = *s++) != 0) { - b++; - if (--decpt == 0 && *s) { -#ifdef USE_LOCALE - while(*b = *decimalpoint++) - ++b; -#else - *b++ = '.'; -#endif - } - } - if (b + decpt > be) { - ret0: - b = 0; - goto ret; - } - for(; decpt > 0; decpt--) - *b++ = '0'; - *b = 0; - } - ret: - freedtoa(s0); - return b; - } - - char * -add_nanbits_D2A(char *b, size_t blen, ULong *bits, int nb) -{ - ULong t; - char *rv; - int i, j; - size_t L; - static char Hexdig[16] = "0123456789abcdef"; - - while(!bits[--nb]) - if (!nb) - return b; - L = 8*nb + 3; - t = bits[nb]; - do ++L; while((t >>= 4)); - if (L > blen) - return b; - b += L; - *--b = 0; - rv = b; - *--b = /*(*/ ')'; - for(i = 0; i < nb; ++i) { - t = bits[i]; - for(j = 0; j < 8; ++j, t >>= 4) - *--b = Hexdig[t & 0xf]; - } - t = bits[nb]; - do *--b = Hexdig[t & 0xf]; while(t >>= 4); - *--b = '('; /*)*/ - return rv; - } diff --git a/libraries/gdtoa/g_ddfmt.c b/libraries/gdtoa/g_ddfmt.c deleted file mode 100644 index 5ce4a076bb3..00000000000 --- a/libraries/gdtoa/g_ddfmt.c +++ /dev/null @@ -1,171 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg@acm.org). */ - -#include "gdtoaimp.h" -#include - - char * -#ifdef KR_headers -g_ddfmt(buf, dd0, ndig, bufsize) char *buf; double *dd0; int ndig; size_t bufsize; -#else -g_ddfmt(char *buf, double *dd0, int ndig, size_t bufsize) -#endif -{ - FPI fpi; - char *b, *s, *se; - ULong *L, bits0[4], *bits, *zx; - int bx, by, decpt, ex, ey, i, j, mode; - Bigint *x, *y, *z; - U *dd, ddx[2]; -#ifdef Honor_FLT_ROUNDS /*{{*/ - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ -#else /*}{*/ -#define Rounding FPI_Round_near -#endif /*}}*/ - - if (bufsize < 10 || bufsize < (size_t)(ndig + 8)) - return 0; - - dd = (U*)dd0; - L = dd->L; - if ((L[_0] & 0x7ff00000L) == 0x7ff00000L) { - /* Infinity or NaN */ - if (L[_0] & 0xfffff || L[_1]) { - nanret: - return strcp(buf, "NaN"); - } - if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) { - if (L[2+_0] & 0xfffff || L[2+_1]) - goto nanret; - if ((L[_0] ^ L[2+_0]) & 0x80000000L) - goto nanret; /* Infinity - Infinity */ - } - infret: - b = buf; - if (L[_0] & 0x80000000L) - *b++ = '-'; - return strcp(b, "Infinity"); - } - if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) { - L += 2; - if (L[_0] & 0xfffff || L[_1]) - goto nanret; - goto infret; - } - if (dval(&dd[0]) + dval(&dd[1]) == 0.) { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (L[_0] & L[2+_0] & 0x80000000L) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - if ((L[_0] & 0x7ff00000L) < (L[2+_0] & 0x7ff00000L)) { - dval(&ddx[1]) = dval(&dd[0]); - dval(&ddx[0]) = dval(&dd[1]); - dd = ddx; - L = dd->L; - } - z = d2b(dval(&dd[0]), &ex, &bx); - if (dval(&dd[1]) == 0.) - goto no_y; - x = z; - y = d2b(dval(&dd[1]), &ey, &by); - if ( (i = ex - ey) !=0) { - if (i > 0) { - x = lshift(x, i); - ex = ey; - } - else - y = lshift(y, -i); - } - if ((L[_0] ^ L[2+_0]) & 0x80000000L) { - z = diff(x, y); - if (L[_0] & 0x80000000L) - z->sign = 1 - z->sign; - } - else { - z = sum(x, y); - if (L[_0] & 0x80000000L) - z->sign = 1; - } - Bfree(x); - Bfree(y); - no_y: - bits = zx = z->x; - for(i = 0; !*zx; zx++) - i += 32; - i += lo0bits(zx); - if (i) { - rshift(z, i); - ex += i; - } - fpi.nbits = z->wds * 32 - hi0bits(z->x[j = z->wds-1]); - if (fpi.nbits < 106) { - fpi.nbits = 106; - if (j < 3) { - for(i = 0; i <= j; i++) - bits0[i] = bits[i]; - while(i < 4) - bits0[i++] = 0; - bits = bits0; - } - } - mode = 2; - if (ndig <= 0) { - if (bufsize < (size_t)((int)(fpi.nbits * .301029995664) + 10)) { - Bfree(z); - return 0; - } - mode = 0; - } - fpi.emin = 1-1023-53+1; - fpi.emax = 2046-1023-106+1; - fpi.rounding = Rounding; - fpi.sudden_underflow = 0; - fpi.int_max = Int_max; - i = STRTOG_Normal; - s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se); - b = g__fmt(buf, s, se, decpt, z->sign, bufsize); - Bfree(z); - return b; - } diff --git a/libraries/gdtoa/g_dfmt.c b/libraries/gdtoa/g_dfmt.c deleted file mode 100644 index d8e1438c4f4..00000000000 --- a/libraries/gdtoa/g_dfmt.c +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - char* -#ifdef KR_headers -g_dfmt(buf, d, ndig, bufsize) char *buf; double *d; int ndig; size_t bufsize; -#else -g_dfmt(char *buf, double *d, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, 0, Int_max }; - char *b, *s, *se; - ULong bits[2], *L, sign; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (ULong*)d; - sign = L[_0] & 0x80000000L; - if ((L[_0] & 0x7ff00000) == 0x7ff00000) { - /* Infinity or NaN */ - if (bufsize < 10) - return 0; - if (L[_0] & 0xfffff || L[_1]) { - return strcp(buf, "NaN"); - } - b = buf; - if (sign) - *b++ = '-'; - return strcp(b, "Infinity"); - } - if (L[_1] == 0 && (L[_0] ^ sign) == 0 /*d == 0.*/) { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (L[_0] & 0x80000000L) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - bits[0] = L[_1]; - bits[1] = L[_0] & 0xfffff; - if ( (ex = (L[_0] >> 20) & 0x7ff) !=0) - bits[1] |= 0x100000; - else - ex = 1; - ex -= 0x3ff + 52; - mode = 2; - if (ndig <= 0) - mode = 0; - i = STRTOG_Normal; - if (sign) - i = STRTOG_Normal | STRTOG_Neg; - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/g_ffmt.c b/libraries/gdtoa/g_ffmt.c deleted file mode 100644 index 30b53ae7ec0..00000000000 --- a/libraries/gdtoa/g_ffmt.c +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - char* -#ifdef KR_headers -g_ffmt(buf, f, ndig, bufsize) char *buf; float *f; int ndig; size_t bufsize; -#else -g_ffmt(char *buf, float *f, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, 0, 6 }; - char *b, *s, *se; - ULong bits[1], *L, sign; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (ULong*)f; - sign = L[0] & 0x80000000L; - if ((L[0] & 0x7f800000) == 0x7f800000) { - /* Infinity or NaN */ - if (L[0] & 0x7fffff) { - return strcp(buf, "NaN"); - } - b = buf; - if (sign) - *b++ = '-'; - return strcp(b, "Infinity"); - } - if (*f == 0.) { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (L[0] & 0x80000000L) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - bits[0] = L[0] & 0x7fffff; - if ( (ex = (L[0] >> 23) & 0xff) !=0) - bits[0] |= 0x800000; - else - ex = 1; - ex -= 0x7f + 23; - mode = 2; - if (ndig <= 0) { - if (bufsize < 16) - return 0; - mode = 0; - } - i = STRTOG_Normal; - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/g_xLfmt.c b/libraries/gdtoa/g_xLfmt.c deleted file mode 100644 index 5cda8d59e73..00000000000 --- a/libraries/gdtoa/g_xLfmt.c +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#endif -#ifdef IEEE_8087 -#define _0 2 -#define _1 1 -#define _2 0 -#endif - - char* -#ifdef KR_headers -g_xLfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize; -#else -g_xLfmt(char *buf, void *V, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max }; - char *b, *s, *se; - ULong bits[2], *L, sign; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (ULong*)V; - sign = L[_0] & 0x80000000L; - bits[1] = L[_1]; - bits[0] = L[_2]; - if ( (ex = (L[_0] >> 16) & 0x7fff) !=0) { - if (ex == 0x7fff) { - /* Infinity or NaN */ - if (bits[0] | bits[1]) - b = strcp(buf, "NaN"); - else { - b = buf; - if (sign) - *b++ = '-'; - b = strcp(b, "Infinity"); - } - return b; - } - i = STRTOG_Normal; - } - else if (bits[0] | bits[1]) { - i = STRTOG_Denormal; - } - else { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (sign) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - ex -= 0x3fff + 63; - mode = 2; - if (ndig <= 0) { - if (bufsize < 32) - return 0; - mode = 0; - } - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/g_xfmt.c b/libraries/gdtoa/g_xfmt.c deleted file mode 100644 index a0baa518ca3..00000000000 --- a/libraries/gdtoa/g_xfmt.c +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#define _4 4 -#endif -#ifdef IEEE_8087 -#define _0 4 -#define _1 3 -#define _2 2 -#define _3 1 -#define _4 0 -#endif - - char* -#ifdef KR_headers -g_xfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize; -#else -g_xfmt(char *buf, void *V, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max }; - char *b, *s, *se; - ULong bits[2], sign; - UShort *L; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (UShort *)V; - sign = L[_0] & 0x8000; - bits[1] = (L[_1] << 16) | L[_2]; - bits[0] = (L[_3] << 16) | L[_4]; - if ( (ex = L[_0] & 0x7fff) !=0) { - if (ex == 0x7fff) { - /* Infinity or NaN */ - if (!bits[0] && bits[1]== 0x80000000) { - b = buf; - if (sign) - *b++ = '-'; - b = strcp(b, "Infinity"); - } - else - b = strcp(buf, "NaN"); - return b; - } - i = STRTOG_Normal; - } - else if (bits[0] | bits[1]) { - i = STRTOG_Denormal; - ex = 1; - } - else { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (sign) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - ex -= 0x3fff + 63; - mode = 2; - if (ndig <= 0) { - if (bufsize < 32) - return 0; - mode = 0; - } - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/gdtoa.c b/libraries/gdtoa/gdtoa.c deleted file mode 100644 index a4759968a52..00000000000 --- a/libraries/gdtoa/gdtoa.c +++ /dev/null @@ -1,764 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - static Bigint * -#ifdef KR_headers -bitstob(bits, nbits, bbits) ULong *bits; int nbits; int *bbits; -#else -bitstob(ULong *bits, int nbits, int *bbits) -#endif -{ - int i, k; - Bigint *b; - ULong *be, *x, *x0; - - i = ULbits; - k = 0; - while(i < nbits) { - i <<= 1; - k++; - } -#ifndef Pack_32 - if (!k) - k = 1; -#endif - b = Balloc(k); - be = bits + ((nbits - 1) >> kshift); - x = x0 = b->x; - do { - *x++ = *bits & ALL_ON; -#ifdef Pack_16 - *x++ = (*bits >> 16) & ALL_ON; -#endif - } while(++bits <= be); - i = x - x0; - while(!x0[--i]) - if (!i) { - b->wds = 0; - *bbits = 0; - goto ret; - } - b->wds = i + 1; - *bbits = i*ULbits + 32 - hi0bits(b->x[i]); - ret: - return b; - } - -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the Long - * calculation. - */ - - char * -gdtoa -#ifdef KR_headers - (fpi, be, bits, kindp, mode, ndigits, decpt, rve) - FPI *fpi; int be; ULong *bits; - int *kindp, mode, ndigits, *decpt; char **rve; -#else - (FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, int *decpt, char **rve) -#endif -{ - /* Arguments ndigits and decpt are similar to the second and third - arguments of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - be = exponent: value = (integer represented by bits) * (2 to the power of be). - - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4-9 should give the same return values as 2-3, i.e., - 4 <= mode <= 9 ==> same return as mode - 2 + (mode & 1). These modes are mainly for - debugging; often they run slower but sometimes - faster than modes 2-3. - 4,5,8,9 ==> left-to-right digit generation. - 6-9 ==> don't try fast floating-point estimate - (if applicable). - - Values of mode other than 0-9 are treated as mode 0. - - Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. - */ - - int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex; - int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits; - int rdir, s2, s5, spec_case, try_quick; - Long L; - Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S; - double d2, ds; - char *s, *s0; - U d, eps; - -#ifndef MULTIPLE_THREADS - if (dtoa_result) { - freedtoa(dtoa_result); - dtoa_result = 0; - } -#endif - inex = 0; - kind = *kindp &= ~STRTOG_Inexact; - switch(kind & STRTOG_Retmask) { - case STRTOG_Zero: - goto ret_zero; - case STRTOG_Normal: - case STRTOG_Denormal: - break; - case STRTOG_Infinite: - *decpt = -32768; - return nrv_alloc("Infinity", rve, 8); - case STRTOG_NaN: - *decpt = -32768; - return nrv_alloc("NaN", rve, 3); - default: - return 0; - } - b = bitstob(bits, nbits = fpi->nbits, &bbits); - be0 = be; - if ( (i = trailz(b)) !=0) { - rshift(b, i); - be += i; - bbits -= i; - } - if (!b->wds) { - Bfree(b); - ret_zero: - *decpt = 1; - return nrv_alloc("0", rve, 1); - } - - dval(&d) = b2d(b, &i); - i = be + bbits - 1; - word0(&d) &= Frac_mask1; - word0(&d) |= Exp_11; -#ifdef IBM - if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0) - dval(&d) /= 1 << j; -#endif - - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2) - * - * This suggests computing an approximation k to log10(&d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ -#ifdef IBM - i <<= 2; - i += j; -#endif - ds = (dval(&d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; - - /* correct assumption about exponent range */ - if ((j = i) < 0) - j = -j; - if ((j -= 1077) > 0) - ds += j * 7e-17; - - k = (int)ds; - if (ds < 0. && ds != k) - k--; /* want k = floor(ds) */ - k_check = 1; -#ifdef IBM - j = be + bbits - 1; - if ( (j1 = j & 3) !=0) - dval(&d) *= 1 << j1; - word0(&d) += j << Exp_shift - 2 & Exp_mask; -#else - word0(&d) += (be + bbits - 1) << Exp_shift; -#endif - if (k >= 0 && k <= Ten_pmax) { - if (dval(&d) < tens[k]) - k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } - else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } - else { - b2 -= k; - b5 = -k; - s5 = 0; - } - if (mode < 0 || mode > 9) - mode = 0; - try_quick = 1; - if (mode > 5) { - mode -= 4; - try_quick = 0; - } - else if (i >= -4 - Emin || i < Emin) - try_quick = 0; - leftright = 1; - ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ - /* silence erroneous "gcc -Wall" warning. */ - switch(mode) { - case 0: - case 1: - i = (int)(nbits * .30103) + 3; - ndigits = 0; - break; - case 2: - leftright = 0; - /* no break */ - case 4: - if (ndigits <= 0) - ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - /* no break */ - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) - i = 1; - } - s = s0 = rv_alloc(i); - - if ( (rdir = fpi->rounding - 1) !=0) { - if (rdir < 0) - rdir = 2; - if (kind & STRTOG_Neg) - rdir = 3 - rdir; - } - - /* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */ - - if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir -#ifndef IMPRECISE_INEXACT - && k == 0 -#endif - ) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - d2 = dval(&d); -#ifdef IBM - if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0) - dval(&d) /= 1 << j; -#endif - k0 = k; - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = tens[k&0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - dval(&d) /= bigtens[n_bigtens-1]; - ieps++; - } - for(; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - } - else { - ds = 1.; - if ( (j1 = -k) !=0) { - dval(&d) *= tens[j1 & 0xf]; - for(j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - dval(&d) *= bigtens[i]; - } - } - } - if (k_check && dval(&d) < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - dval(&d) *= 10.; - ieps++; - } - dval(&eps) = ieps*dval(&d) + 7.; - word0(&eps) -= (P-1)*Exp_msk1; - if (ilim == 0) { - S = mhi = 0; - dval(&d) -= 5.; - if (dval(&d) > dval(&eps)) - goto one_digit; - if (dval(&d) < -dval(&eps)) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - dval(&eps) = ds*0.5/tens[ilim-1] - dval(&eps); - for(i = 0;;) { - L = (Long)(dval(&d)/ds); - dval(&d) -= L*ds; - *s++ = '0' + (int)L; - if (dval(&d) < dval(&eps)) { - if (dval(&d)) - inex = STRTOG_Inexlo; - goto ret1; - } - if (ds - dval(&d) < dval(&eps)) - goto bump_up; - if (++i >= ilim) - break; - dval(&eps) *= 10.; - dval(&d) *= 10.; - } - } - else { -#endif - /* Generate ilim digits, then fix them up. */ - dval(&eps) *= tens[ilim-1]; - for(i = 1;; i++, dval(&d) *= 10.) { - if ( (L = (Long)(dval(&d)/ds)) !=0) - dval(&d) -= L*ds; - *s++ = '0' + (int)L; - if (i == ilim) { - ds *= 0.5; - if (dval(&d) > ds + dval(&eps)) - goto bump_up; - else if (dval(&d) < ds - dval(&eps)) { - if (dval(&d)) - inex = STRTOG_Inexlo; - goto clear_trailing0; - } - break; - } - } -#ifndef No_leftright - } -#endif - fast_failed: - s = s0; - dval(&d) = d2; - k = k0; - ilim = ilim0; - } - - /* Do we have a "small" integer? */ - - if (be >= 0 && k <= fpi->int_max) { - /* Yes. */ - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || dval(&d) <= 5*ds) - goto no_digits; - goto one_digit; - } - for(i = 1;; i++, dval(&d) *= 10.) { - L = (Long)(dval(&d) / ds); - dval(&d) -= L*ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&d) < 0) { - L--; - dval(&d) += ds; - } -#endif - *s++ = '0' + (int)L; - if (dval(&d) == 0.) - break; - if (i == ilim) { - if (rdir) { - if (rdir == 1) - goto bump_up; - inex = STRTOG_Inexlo; - goto ret1; - } - dval(&d) += dval(&d); -#ifdef ROUND_BIASED - if (dval(&d) >= ds) -#else - if (dval(&d) > ds || (dval(&d) == ds && L & 1)) -#endif - { - bump_up: - inex = STRTOG_Inexhi; - while(*--s == '9') - if (s == s0) { - k++; - *s = '0'; - break; - } - ++*s++; - } - else { - inex = STRTOG_Inexlo; - clear_trailing0: - while(*--s == '0'){} - ++s; - } - break; - } - } - goto ret1; - } - - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - i = nbits - bbits; - if (be - i++ < fpi->emin && mode != 3 && mode != 5) { - /* denormal */ - i = be - fpi->emin + 1; - if (mode >= 2 && ilim > 0 && ilim < i) - goto small_ilim; - } - else if (mode >= 2) { - small_ilim: - j = ilim - 1; - if (m5 >= j) - m5 -= j; - else { - s5 += j -= m5; - b5 += j; - m5 = 0; - } - if ((i = ilim) < 0) { - m2 -= i; - i = 0; - } - } - b2 += i; - s2 += i; - mhi = i2b(1); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); - b = b1; - } - if ( (j = b5 - m5) !=0) - b = pow5mult(b, j); - } - else - b = pow5mult(b, b5); - } - S = i2b(1); - if (s5 > 0) - S = pow5mult(S, s5); - - /* Check for special case that d is a normalized power of 2. */ - - spec_case = 0; - if (mode < 2) { - if (bbits == 1 && be0 > fpi->emin + 1) { - /* The special case */ - b2++; - s2++; - spec_case = 1; - } - } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to quorem, so it - * can do shifts and ors to compute the numerator for q. - */ - i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask; - m2 += i; - if ((b2 += i) > 0) - b = lshift(b, b2); - if ((s2 += i) > 0) - S = lshift(S, s2); - if (k_check) { - if (cmp(b,S) < 0) { - k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) - mhi = multadd(mhi, 10, 0); - ilim = ilim1; - } - } - if (ilim <= 0 && mode > 2) { - if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { - /* no digits, fcvt style */ - no_digits: - k = -1 - ndigits; - inex = STRTOG_Inexlo; - goto ret; - } - one_digit: - inex = STRTOG_Inexhi; - *s++ = '1'; - k++; - goto ret; - } - if (leftright) { - if (m2 > 0) - mhi = lshift(mhi, m2); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = Balloc(mhi->k); - Bcopy(mhi, mlo); - mhi = lshift(mhi, 1); - } - - for(i = 1;;i++) { - dig = quorem(b,S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = cmp(b, mlo); - delta = diff(S, mhi); - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); -#ifndef ROUND_BIASED - if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) { - if (dig == '9') - goto round_9_up; - if (j <= 0) { - if (b->wds > 1 || b->x[0]) - inex = STRTOG_Inexlo; - } - else { - dig++; - inex = STRTOG_Inexhi; - } - *s++ = dig; - goto ret; - } -#endif - if (j < 0 || (j == 0 && !mode -#ifndef ROUND_BIASED - && !(bits[0] & 1) -#endif - )) { - if (rdir && (b->wds > 1 || b->x[0])) { - if (rdir == 2) { - inex = STRTOG_Inexlo; - goto accept; - } - while (cmp(S,mhi) > 0) { - *s++ = dig; - mhi1 = multadd(mhi, 10, 0); - if (mlo == mhi) - mlo = mhi1; - mhi = mhi1; - b = multadd(b, 10, 0); - dig = quorem(b,S) + '0'; - } - if (dig++ == '9') - goto round_9_up; - inex = STRTOG_Inexhi; - goto accept; - } - if (j1 > 0) { - b = lshift(b, 1); - j1 = cmp(b, S); -#ifdef ROUND_BIASED - if (j1 >= 0 /*)*/ -#else - if ((j1 > 0 || (j1 == 0 && dig & 1)) -#endif - && dig++ == '9') - goto round_9_up; - inex = STRTOG_Inexhi; - } - if (b->wds > 1 || b->x[0]) - inex = STRTOG_Inexlo; - accept: - *s++ = dig; - goto ret; - } - if (j1 > 0 && rdir != 2) { - if (dig == '9') { /* possible if i == 1 */ - round_9_up: - *s++ = '9'; - inex = STRTOG_Inexhi; - goto roundoff; - } - inex = STRTOG_Inexhi; - *s++ = dig + 1; - goto ret; - } - *s++ = dig; - if (i == ilim) - break; - b = multadd(b, 10, 0); - if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); - else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); - } - } - } - else - for(i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (i >= ilim) - break; - b = multadd(b, 10, 0); - } - - /* Round off last digit */ - - if (rdir) { - if (rdir == 2 || (b->wds <= 1 && !b->x[0])) - goto chopzeros; - goto roundoff; - } - b = lshift(b, 1); - j = cmp(b, S); -#ifdef ROUND_BIASED - if (j >= 0) -#else - if (j > 0 || (j == 0 && dig & 1)) -#endif - { - roundoff: - inex = STRTOG_Inexhi; - while(*--s == '9') - if (s == s0) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } - else { - chopzeros: - if (b->wds > 1 || b->x[0]) - inex = STRTOG_Inexlo; - while(*--s == '0'){} - ++s; - } - ret: - Bfree(S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); - } - ret1: - Bfree(b); - *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; - *kindp |= inex; - return s0; - } diff --git a/libraries/gdtoa/gdtoa.h b/libraries/gdtoa/gdtoa.h deleted file mode 100644 index 8b7390a288f..00000000000 --- a/libraries/gdtoa/gdtoa.h +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#ifndef GDTOA_H_INCLUDED -#define GDTOA_H_INCLUDED - -#if defined(_MSC_VER) -/* [RH] Generating arith.h strikes me as too cumbersome under Visual - * Studio, so here's the equivalent, given the limited number of - * architectures that MSC can target. (Itanium? Who cares about that?) - */ -#define IEEE_8087 -#define Arith_Kind_ASL 1 -#define Double_Align -#ifdef _M_X64 -#define X64_bit_pointers -#endif -#elif defined(__APPLE__) -/* [BL] While generating the files may be easy, on OS X we have cross - * compiling to deal with, which means we can't run the generation - * program on the target. - */ -#if defined(__x86_64__) -#define IEEE_8087 -#define Arith_Kind_ASL 1 -#define Long int -#define Intcast (int)(long) -#define Double_Align -#define X64_bit_pointers -#elif defined(__i386__) -#define IEEE_8087 -#define Arith_Kind_ASL 1 -#else -#define IEEE_MC68k -#define Arith_Kind_ASL 2 -#define Double_Align -#endif -#else -#include "arith.h" -#endif -#include /* for size_t */ - -#ifndef Long -#define Long int -#endif -#ifndef ULong -typedef unsigned Long ULong; -#endif -#ifndef UShort -typedef unsigned short UShort; -#endif - -#ifndef ANSI -#ifdef KR_headers -#define ANSI(x) () -#define Void /*nothing*/ -#else -#define ANSI(x) x -#define Void void -#endif -#endif /* ANSI */ - -#ifndef CONST -#ifdef KR_headers -#define CONST /* blank */ -#else -#define CONST const -#endif -#endif /* CONST */ - - enum { /* return values from strtodg */ - STRTOG_Zero = 0, - STRTOG_Normal = 1, - STRTOG_Denormal = 2, - STRTOG_Infinite = 3, - STRTOG_NaN = 4, - STRTOG_NaNbits = 5, - STRTOG_NoNumber = 6, - STRTOG_Retmask = 7, - - /* The following may be or-ed into one of the above values. */ - - STRTOG_Neg = 0x08, /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */ - STRTOG_Inexlo = 0x10, /* returned result rounded toward zero */ - STRTOG_Inexhi = 0x20, /* returned result rounded away from zero */ - STRTOG_Inexact = 0x30, - STRTOG_Underflow= 0x40, - STRTOG_Overflow = 0x80 - }; - - typedef struct -FPI { - int nbits; - int emin; - int emax; - int rounding; - int sudden_underflow; - int int_max; - } FPI; - -enum { /* FPI.rounding values: same as FLT_ROUNDS */ - FPI_Round_zero = 0, - FPI_Round_near = 1, - FPI_Round_up = 2, - FPI_Round_down = 3 - }; - -#ifdef __cplusplus -extern "C" { -#endif - -extern char* dtoa ANSI((double d, int mode, int ndigits, int *decpt, - int *sign, char **rve)); -extern char* gdtoa ANSI((FPI *fpi, int be, ULong *bits, int *kindp, - int mode, int ndigits, int *decpt, char **rve)); -extern void freedtoa ANSI((char*)); -//extern float strtof ANSI((CONST char *, char **)); -//extern double strtod ANSI((CONST char *, char **)); -extern int strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*)); - -extern char* g_ddfmt ANSI((char*, double*, int, size_t)); -extern char* g_ddfmt_p ANSI((char*, double*, int, size_t, int)); -extern char* g_dfmt ANSI((char*, double*, int, size_t)); -extern char* g_dfmt_p ANSI((char*, double*, int, size_t, int)); -extern char* g_ffmt ANSI((char*, float*, int, size_t)); -extern char* g_ffmt_p ANSI((char*, float*, int, size_t, int)); -extern char* g_Qfmt ANSI((char*, void*, int, size_t)); -extern char* g_Qfmt_p ANSI((char*, void*, int, size_t, int)); -extern char* g_xfmt ANSI((char*, void*, int, size_t)); -extern char* g_xfmt_p ANSI((char*, void*, int, size_t, int)); -extern char* g_xLfmt ANSI((char*, void*, int, size_t)); -extern char* g_xLfmt_p ANSI((char*, void*, int, size_t, int)); - -extern int strtoId ANSI((CONST char*, char**, double*, double*)); -extern int strtoIdd ANSI((CONST char*, char**, double*, double*)); -extern int strtoIf ANSI((CONST char*, char**, float*, float*)); -extern int strtoIQ ANSI((CONST char*, char**, void*, void*)); -extern int strtoIx ANSI((CONST char*, char**, void*, void*)); -extern int strtoIxL ANSI((CONST char*, char**, void*, void*)); -extern int strtord ANSI((CONST char*, char**, int, double*)); -extern int strtordd ANSI((CONST char*, char**, int, double*)); -extern int strtorf ANSI((CONST char*, char**, int, float*)); -extern int strtorQ ANSI((CONST char*, char**, int, void*)); -extern int strtorx ANSI((CONST char*, char**, int, void*)); -extern int strtorxL ANSI((CONST char*, char**, int, void*)); -#if 1 -extern int strtodI ANSI((CONST char*, char**, double*)); -extern int strtopd ANSI((CONST char*, char**, double*)); -extern int strtopdd ANSI((CONST char*, char**, double*)); -extern int strtopf ANSI((CONST char*, char**, float*)); -extern int strtopQ ANSI((CONST char*, char**, void*)); -extern int strtopx ANSI((CONST char*, char**, void*)); -extern int strtopxL ANSI((CONST char*, char**, void*)); -#else -#define strtopd(s,se,x) strtord(s,se,1,x) -#define strtopdd(s,se,x) strtordd(s,se,1,x) -#define strtopf(s,se,x) strtorf(s,se,1,x) -#define strtopQ(s,se,x) strtorQ(s,se,1,x) -#define strtopx(s,se,x) strtorx(s,se,1,x) -#define strtopxL(s,se,x) strtorxL(s,se,1,x) -#endif - -#ifdef __cplusplus -} -#endif -#endif /* GDTOA_H_INCLUDED */ diff --git a/libraries/gdtoa/gdtoa_fltrnds.h b/libraries/gdtoa/gdtoa_fltrnds.h deleted file mode 100644 index 33e5f9e5342..00000000000 --- a/libraries/gdtoa/gdtoa_fltrnds.h +++ /dev/null @@ -1,18 +0,0 @@ - FPI *fpi, fpi1; - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ - fpi = &fpi0; - if (Rounding != 1) { - fpi1 = fpi0; - fpi = &fpi1; - fpi1.rounding = Rounding; - } diff --git a/libraries/gdtoa/gdtoaimp.h b/libraries/gdtoa/gdtoaimp.h deleted file mode 100644 index c63bf31353c..00000000000 --- a/libraries/gdtoa/gdtoaimp.h +++ /dev/null @@ -1,685 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998-2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* This is a variation on dtoa.c that converts arbitary binary - floating-point formats to and from decimal notation. It uses - double-precision arithmetic internally, so there are still - various #ifdefs that adapt the calculations to the native - double-precision arithmetic (any of IEEE, VAX D_floating, - or IBM mainframe arithmetic). - - Please send bug reports to David M. Gay (dmg at acm dot org, - with " at " changed at "@" and " dot " changed to "."). - */ - -/* On a machine with IEEE extended-precision registers, it is - * necessary to specify double-precision (53-bit) rounding precision - * before invoking strtod or dtoa. If the machine uses (the equivalent - * of) Intel 80x87 arithmetic, the call - * _control87(PC_53, MCW_PC); - * does this with many compilers. Whether this or another call is - * appropriate depends on the compiler; for this to work, it may be - * necessary to #include "float.h" or another system-dependent header - * file. - */ - -/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. - * - * This strtod returns a nearest machine number to the input decimal - * string (or sets errno to ERANGE). With IEEE arithmetic, ties are - * broken by the IEEE round-even rule. Otherwise ties are broken by - * biased rounding (add half and chop). - * - * Inspired loosely by William D. Clinger's paper "How to Read Floating - * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126]. - * - * Modifications: - * - * 1. We only require IEEE, IBM, or VAX double-precision - * arithmetic (not IEEE double-extended). - * 2. We get by with floating-point arithmetic in a case that - * Clinger missed -- when we're computing d * 10^n - * for a small integer d and the integer n is not too - * much larger than 22 (the maximum integer k for which - * we can represent 10^k exactly), we may be able to - * compute (d*10^k) * 10^(e-k) with just one roundoff. - * 3. Rather than a bit-at-a-time adjustment of the binary - * result in the hard case, we use floating-point - * arithmetic to determine the adjustment to within - * one bit; only in really hard cases do we need to - * compute a second residual. - * 4. Because of 3., we don't need a large table of powers of 10 - * for ten-to-e (just some small tables, e.g. of 10^k - * for 0 <= k <= 22). - */ - -/* - * #define IEEE_8087 for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_MC68k for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define Long int on machines with 32-bit ints and 64-bit longs. - * #define Sudden_Underflow for IEEE-format machines without gradual - * underflow (i.e., that flush to zero on underflow). - * #define IBM for IBM mainframe-style floating-point arithmetic. - * #define VAX for VAX-style floating-point arithmetic (D_floating). - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa and gdtoa. This will cause modes 4 and 5 to be - * treated the same as modes 2 and 3 for some inputs. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. - * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines - * that use extended-precision instructions to compute rounded - * products and quotients) with IBM. - * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic - * that rounds toward +Infinity. - * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased - * rounding when the underlying floating-point arithmetic uses - * unbiased rounding. This prevent using ordinary floating-point - * arithmetic when the result could be computed with one rounding error. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define NO_LONG_LONG on machines that do not have a "long long" - * integer type (of >= 64 bits). On such machines, you can - * #define Just_16 to store 16 bits per 32-bit Long when doing - * high-precision integer arithmetic. Whether this speeds things - * up or slows things down depends on the machine and the number - * being converted. If long long is available and the name is - * something other than "long long", #define Llong to be the name, - * and if "unsigned Llong" does not work as an unsigned version of - * Llong, #define #ULLong to be the corresponding unsigned type. - * #define KR_headers for old-style C function headers. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) - * if memory is available and otherwise does something you deem - * appropriate. If MALLOC is undefined, malloc will be invoked - * directly -- and assumed always to succeed. Similarly, if you - * want something other than the system's free() to be called to - * recycle memory acquired from MALLOC, #define FREE to be the - * name of the alternate routine. (FREE or free is only called in - * pathological cases, e.g., in a gdtoa call after a gdtoa return in - * mode 3 with thousands of digits requested.) - * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making - * memory allocations from a private pool of memory when possible. - * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, - * unless #defined to be a different length. This default length - * suffices to get rid of MALLOC calls except for unusual cases, - * such as decimal-to-binary conversion of a very long string of - * digits. When converting IEEE double precision values, the - * longest string gdtoa can return is about 751 bytes long. For - * conversions by strtod of strings of 800 digits and all gdtoa - * conversions of IEEE doubles in single-threaded executions with - * 8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with - * 4-byte pointers, PRIVATE_MEM >= 7112 appears adequate. - * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK - * #defined automatically on IEEE systems. On such systems, - * when INFNAN_CHECK is #defined, strtod checks - * for Infinity and NaN (case insensitively). - * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, - * strtodg also accepts (case insensitively) strings of the form - * NaN(x), where x is a string of hexadecimal digits (optionally - * preceded by 0x or 0X) and spaces; if there is only one string - * of hexadecimal digits, it is taken for the fraction bits of the - * resulting NaN; if there are two or more strings of hexadecimal - * digits, each string is assigned to the next available sequence - * of 32-bit words of fractions bits (starting with the most - * significant), right-aligned in each sequence. - * Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)" - * is consumed even when ... has the wrong form (in which case the - * "(...)" is consumed but ignored). - * #define MULTIPLE_THREADS if the system offers preemptively scheduled - * multiple threads. In this case, you must provide (or suitably - * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed - * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed - * in pow5mult, ensures lazy evaluation of only one copy of high - * powers of 5; omitting this lock would introduce a small - * probability of wasting memory, but would otherwise be harmless.) - * You must also invoke freedtoa(s) to free the value s returned by - * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. - * #define IMPRECISE_INEXACT if you do not care about the setting of - * the STRTOG_Inexact bits in the special case of doing IEEE double - * precision conversions (which could also be done by the strtod in - * dtoa.c). - * #define NO_HEX_FP to disable recognition of C9x's hexadecimal - * floating-point constants. - * #define -DNO_ERRNO to suppress setting errno (in strtod.c and - * strtodg.c). - * #define NO_STRING_H to use private versions of memcpy. - * On some K&R systems, it may also be necessary to - * #define DECLARE_SIZE_T in this case. - * #define USE_LOCALE to use the current locale's decimal_point value. - */ - -#ifndef GDTOAIMP_H_INCLUDED -#define GDTOAIMP_H_INCLUDED -#include "gdtoa.h" - -#if defined(_MSC_VER) -/* [RH] Generating gd_qnan.h strikes me as too cumbersome under Visual - * Studio, so here's the equivalent, given the limited number of - * architectures that MSC can target. (Itanium? Who cares about that?) - */ -#define f_QNAN 0xffc00000 -#define d_QNAN0 0x0 -#define d_QNAN1 0xfff80000 -#define ld_QNAN0 0x0 -#define ld_QNAN1 0xfff80000 -#define ld_QNAN2 0x0 -#define ld_QNAN3 0x0 -#define ldus_QNAN0 0x0 -#define ldus_QNAN1 0x0 -#define ldus_QNAN2 0x0 -#define ldus_QNAN3 0xfff8 -#define ldus_QNAN4 0x0 -/* [RH] Interestingly, MinGW produces something different because - * it turns out that it has a true long double type. I thought that - * all ia32 compilers had phased out extended precision. - */ -#elif defined(__APPLE__) -#if defined(__x86_64__) || defined(__i386__) -#define f_QNAN 0xffc00000 -#define d_QNAN0 0x0 -#define d_QNAN1 0xfff80000 -#define ld_QNAN0 0x0 -#define ld_QNAN1 0xc0000000 -#define ld_QNAN2 0xffff -#define ld_QNAN3 0x0 -#define ldus_QNAN0 0x0 -#define ldus_QNAN1 0x0 -#define ldus_QNAN2 0x0 -#define ldus_QNAN3 0xc000 -#define ldus_QNAN4 0xffff -#else -#define f_QNAN 0xffc00000 -#define d_QNAN0 0xfff80000 -#define d_QNAN1 0x0 -#define ld_QNAN0 0xfff80000 -#define ld_QNAN1 0x0 -#define ld_QNAN2 0x0 -#define ld_QNAN3 0x0 -#define ldus_QNAN0 0xfff8 -#define ldus_QNAN1 0x0 -#define ldus_QNAN2 0x0 -#define ldus_QNAN3 0x0 -#define ldus_QNAN4 0x0 -#endif -#else -#include "gd_qnan.h" -#endif - -#ifdef Honor_FLT_ROUNDS -#include -#endif - -#ifdef DEBUG -#include "stdio.h" -#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} -#endif - -#include "stdlib.h" -#include "string.h" - -#ifdef KR_headers -#define Char char -#else -#define Char void -#endif - -#ifdef MALLOC -extern Char *MALLOC ANSI((size_t)); -#else -#define MALLOC malloc -#endif - -#undef IEEE_Arith -#undef Avoid_Underflow -#ifdef IEEE_MC68k -#define IEEE_Arith -#endif -#ifdef IEEE_8087 -#define IEEE_Arith -#endif - -#include "errno.h" -#ifdef Bad_float_h - -#ifdef IEEE_Arith -#define DBL_DIG 15 -#define DBL_MAX_10_EXP 308 -#define DBL_MAX_EXP 1024 -#define FLT_RADIX 2 -#define DBL_MAX 1.7976931348623157e+308 -#endif - -#ifdef IBM -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 75 -#define DBL_MAX_EXP 63 -#define FLT_RADIX 16 -#define DBL_MAX 7.2370055773322621e+75 -#endif - -#ifdef VAX -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 38 -#define DBL_MAX_EXP 127 -#define FLT_RADIX 2 -#define DBL_MAX 1.7014118346046923e+38 -#define n_bigtens 2 -#endif - -#ifndef LONG_MAX -#define LONG_MAX 2147483647 -#endif - -#else /* ifndef Bad_float_h */ -#include "float.h" -#endif /* Bad_float_h */ - -#ifdef IEEE_Arith -#define Scale_Bit 0x10 -#define n_bigtens 5 -#endif - -#ifdef IBM -#define n_bigtens 3 -#endif - -#ifdef VAX -#define n_bigtens 2 -#endif - -#ifndef __MATH_H__ -#include "math.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 -Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. -#endif - -typedef union { double d; ULong L[2]; } U; - -#ifdef IEEE_8087 -#define word0(x) (x)->L[1] -#define word1(x) (x)->L[0] -#else -#define word0(x) (x)->L[0] -#define word1(x) (x)->L[1] -#endif -#define dval(x) (x)->d - -/* The following definition of Storeinc is appropriate for MIPS processors. - * An alternative that might be better on some machines is - * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) - */ -#if defined(IEEE_8087) + defined(VAX) -#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ -((unsigned short *)a)[0] = (unsigned short)c, a++) -#else -#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ -((unsigned short *)a)[1] = (unsigned short)c, a++) -#endif - -/* #define P DBL_MANT_DIG */ -/* Ten_pmax = floor(P*log(2)/log(5)) */ -/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ -/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ -/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ - -#ifdef IEEE_Arith -#define Exp_shift 20 -#define Exp_shift1 20 -#define Exp_msk1 0x100000 -#define Exp_msk11 0x100000 -#define Exp_mask 0x7ff00000 -#define P 53 -#define Bias 1023 -#define Emin (-1022) -#define Exp_1 0x3ff00000 -#define Exp_11 0x3ff00000 -#define Ebits 11 -#define Frac_mask 0xfffff -#define Frac_mask1 0xfffff -#define Ten_pmax 22 -#define Bletch 0x10 -#define Bndry_mask 0xfffff -#define Bndry_mask1 0xfffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 1 -#define Tiny0 0 -#define Tiny1 1 -#define Quick_max 14 -#define Int_max 14 - -#ifndef Flt_Rounds -#ifdef FLT_ROUNDS -#define Flt_Rounds FLT_ROUNDS -#else -#define Flt_Rounds 1 -#endif -#endif /*Flt_Rounds*/ - -#else /* ifndef IEEE_Arith */ -#undef Sudden_Underflow -#define Sudden_Underflow -#ifdef IBM -#undef Flt_Rounds -#define Flt_Rounds 0 -#define Exp_shift 24 -#define Exp_shift1 24 -#define Exp_msk1 0x1000000 -#define Exp_msk11 0x1000000 -#define Exp_mask 0x7f000000 -#define P 14 -#define Bias 65 -#define Exp_1 0x41000000 -#define Exp_11 0x41000000 -#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ -#define Frac_mask 0xffffff -#define Frac_mask1 0xffffff -#define Bletch 4 -#define Ten_pmax 22 -#define Bndry_mask 0xefffff -#define Bndry_mask1 0xffffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 4 -#define Tiny0 0x100000 -#define Tiny1 0 -#define Quick_max 14 -#define Int_max 15 -#else /* VAX */ -#undef Flt_Rounds -#define Flt_Rounds 1 -#define Exp_shift 23 -#define Exp_shift1 7 -#define Exp_msk1 0x80 -#define Exp_msk11 0x800000 -#define Exp_mask 0x7f80 -#define P 56 -#define Bias 129 -#define Exp_1 0x40800000 -#define Exp_11 0x4080 -#define Ebits 8 -#define Frac_mask 0x7fffff -#define Frac_mask1 0xffff007f -#define Ten_pmax 24 -#define Bletch 2 -#define Bndry_mask 0xffff007f -#define Bndry_mask1 0xffff007f -#define LSB 0x10000 -#define Sign_bit 0x8000 -#define Log2P 1 -#define Tiny0 0x80 -#define Tiny1 0 -#define Quick_max 15 -#define Int_max 15 -#endif /* IBM, VAX */ -#endif /* IEEE_Arith */ - -#ifndef IEEE_Arith -#define ROUND_BIASED -#else -#ifdef ROUND_BIASED_without_Round_Up -#undef ROUND_BIASED -#define ROUND_BIASED -#endif -#endif - -#ifdef RND_PRODQUOT -#define rounded_product(a,b) a = rnd_prod(a, b) -#define rounded_quotient(a,b) a = rnd_quot(a, b) -#ifdef KR_headers -extern double rnd_prod(), rnd_quot(); -#else -extern double rnd_prod(double, double), rnd_quot(double, double); -#endif -#else -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b -#endif - -#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) -#define Big1 0xffffffff - -#undef Pack_16 -#ifndef Pack_32 -#define Pack_32 -#endif - -#ifdef NO_LONG_LONG -#undef ULLong -#ifdef Just_16 -#undef Pack_32 -#define Pack_16 -/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per Long. - */ -#endif -#else /* long long available */ -#ifndef Llong -#define Llong long long -#endif -#ifndef ULLong -#define ULLong unsigned Llong -#endif -#endif /* NO_LONG_LONG */ - -#ifdef Pack_32 -#define ULbits 32 -#define kshift 5 -#define kmask 31 -#define ALL_ON 0xffffffff -#else -#define ULbits 16 -#define kshift 4 -#define kmask 15 -#define ALL_ON 0xffff -#endif - -//#ifndef MULTIPLE_THREADS -#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ -#define FREE_DTOA_LOCK(n) /*nothing*/ -//#endif - -#define Kmax 9 - - struct -Bigint { - struct Bigint *next; - int k, maxwds, sign, wds; - ULong x[1]; - }; - - typedef struct Bigint Bigint; - -#ifdef NO_STRING_H -#ifdef DECLARE_SIZE_T -typedef unsigned int size_t; -#endif -extern void memcpy_D2A ANSI((void*, const void*, size_t)); -#define Bcopy(x,y) memcpy_D2A(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int)) -#else /* !NO_STRING_H */ -#define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int)) -#endif /* NO_STRING_H */ - -#define Balloc Balloc_D2A -#define Bfree Bfree_D2A -#define InfName InfName_D2A -#define NanName NanName_D2A -#define ULtoQ ULtoQ_D2A -#define ULtof ULtof_D2A -#define ULtod ULtod_D2A -#define ULtodd ULtodd_D2A -#define ULtox ULtox_D2A -#define ULtoxL ULtoxL_D2A -#define add_nanbits add_nanbits_D2A -#define any_on any_on_D2A -#define b2d b2d_D2A -#define bigtens bigtens_D2A -#define cmp cmp_D2A -#define copybits copybits_D2A -#define d2b d2b_D2A -#define decrement decrement_D2A -#define diff diff_D2A -#define dtoa_result dtoa_result_D2A -#define g__fmt g__fmt_D2A -#define gethex gethex_D2A -#define hexdig hexdig_D2A -#define hexnan hexnan_D2A -#define hi0bits(x) hi0bits_D2A((ULong)(x)) -#define i2b i2b_D2A -#define increment increment_D2A -#define lo0bits lo0bits_D2A -#define lshift lshift_D2A -#define match match_D2A -#define mult mult_D2A -#define multadd multadd_D2A -#define nrv_alloc nrv_alloc_D2A -#define pow5mult pow5mult_D2A -#define quorem quorem_D2A -#define ratio ratio_D2A -#define rshift rshift_D2A -#define rv_alloc rv_alloc_D2A -#define s2b s2b_D2A -#define set_ones set_ones_D2A -#define strcp strcp_D2A -#define strtoIg strtoIg_D2A -#define sum sum_D2A -#define tens tens_D2A -#define tinytens tinytens_D2A -#define tinytens tinytens_D2A -#define trailz trailz_D2A -#define ulp ulp_D2A - - extern char *add_nanbits ANSI((char*, size_t, ULong*, int)); - extern char *dtoa_result; - extern CONST double bigtens[], tens[], tinytens[]; - extern unsigned char hexdig[]; - extern const char *InfName[6], *NanName[3]; - - extern Bigint *Balloc ANSI((int)); - extern void Bfree ANSI((Bigint*)); - extern void ULtof ANSI((ULong*, ULong*, Long, int)); - extern void ULtod ANSI((ULong*, ULong*, Long, int)); - extern void ULtodd ANSI((ULong*, ULong*, Long, int)); - extern void ULtoQ ANSI((ULong*, ULong*, Long, int)); - extern void ULtox ANSI((UShort*, ULong*, Long, int)); - extern void ULtoxL ANSI((ULong*, ULong*, Long, int)); - extern ULong any_on ANSI((Bigint*, int)); - extern double b2d ANSI((Bigint*, int*)); - extern int cmp ANSI((Bigint*, Bigint*)); - extern void copybits ANSI((ULong*, int, Bigint*)); - extern Bigint *d2b ANSI((double, int*, int*)); - extern void decrement ANSI((Bigint*)); - extern Bigint *diff ANSI((Bigint*, Bigint*)); - extern char *dtoa ANSI((double d, int mode, int ndigits, - int *decpt, int *sign, char **rve)); - extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t)); - extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int)); - extern void hexdig_init_D2A(Void); - extern int hexnan ANSI((CONST char**, FPI*, ULong*)); - extern int hi0bits_D2A ANSI((ULong)); - extern Bigint *i2b ANSI((int)); - extern Bigint *increment ANSI((Bigint*)); - extern int lo0bits ANSI((ULong*)); - extern Bigint *lshift ANSI((Bigint*, int)); - extern int match ANSI((CONST char**, char*)); - extern Bigint *mult ANSI((Bigint*, Bigint*)); - extern Bigint *multadd ANSI((Bigint*, int, int)); - extern char *nrv_alloc ANSI((char*, char **, int)); - extern Bigint *pow5mult ANSI((Bigint*, int)); - extern int quorem ANSI((Bigint*, Bigint*)); - extern double ratio ANSI((Bigint*, Bigint*)); - extern void rshift ANSI((Bigint*, int)); - extern char *rv_alloc ANSI((int)); - extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int)); - extern Bigint *set_ones ANSI((Bigint*, int)); - extern char *strcp ANSI((char*, const char*)); - extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*)); -// extern double strtod ANSI((const char *s00, char **se)); - extern Bigint *sum ANSI((Bigint*, Bigint*)); - extern int trailz ANSI((Bigint*)); - extern double ulp ANSI((U*)); - -#ifdef __cplusplus -} -#endif -/* - * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c. Prior to - * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0, - * respectively), but now are determined by compiling and running - * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1. - * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=... - * and -DNAN_WORD1=... values if necessary. This should still work. - * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) - */ -#ifdef IEEE_Arith -#ifndef NO_INFNAN_CHECK -#undef INFNAN_CHECK -#define INFNAN_CHECK -#endif -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#ifndef NAN_WORD0 -#define NAN_WORD0 d_QNAN0 -#endif -#ifndef NAN_WORD1 -#define NAN_WORD1 d_QNAN1 -#endif -#else -#define _0 1 -#define _1 0 -#ifndef NAN_WORD0 -#define NAN_WORD0 d_QNAN1 -#endif -#ifndef NAN_WORD1 -#define NAN_WORD1 d_QNAN0 -#endif -#endif -#else -#undef INFNAN_CHECK -#endif - -#undef SI -#ifdef Sudden_Underflow -#define SI 1 -#else -#define SI 0 -#endif - -#endif /* GDTOAIMP_H_INCLUDED */ diff --git a/libraries/gdtoa/gethex.c b/libraries/gdtoa/gethex.c deleted file mode 100644 index 72da9d32610..00000000000 --- a/libraries/gdtoa/gethex.c +++ /dev/null @@ -1,349 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#ifdef USE_LOCALE -#include "locale.h" -#endif - - int -#ifdef KR_headers -gethex(sp, fpi, exp, bp, sign) - CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; -#else -gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) -#endif -{ - Bigint *b; - CONST unsigned char *decpt, *s0, *s, *s1; - int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; - ULong L, lostbits, *x; - Long e, e1; -#ifdef USE_LOCALE - int i; -#ifdef NO_LOCALE_CACHE - const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point; -#else - const unsigned char *decimalpoint; - static unsigned char *decimalpoint_cache; - if (!(s0 = decimalpoint_cache)) { - s0 = (unsigned char*)localeconv()->decimal_point; - if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { - strcpy(decimalpoint_cache, s0); - s0 = decimalpoint_cache; - } - } - decimalpoint = s0; -#endif -#endif - - /**** if (!hexdig['0']) hexdig_init_D2A(); ****/ - *bp = 0; - havedig = 0; - s0 = *(CONST unsigned char **)sp + 2; - while(s0[havedig] == '0') - havedig++; - s0 += havedig; - s = s0; - decpt = 0; - zret = 0; - e = 0; - if (hexdig[*s]) - havedig++; - else { - zret = 1; -#ifdef USE_LOCALE - for(i = 0; decimalpoint[i]; ++i) { - if (s[i] != decimalpoint[i]) - goto pcheck; - } - decpt = s += i; -#else - if (*s != '.') - goto pcheck; - decpt = ++s; -#endif - if (!hexdig[*s]) - goto pcheck; - while(*s == '0') - s++; - if (hexdig[*s]) - zret = 0; - havedig = 1; - s0 = s; - } - while(hexdig[*s]) - s++; -#ifdef USE_LOCALE - if (*s == *decimalpoint && !decpt) { - for(i = 1; decimalpoint[i]; ++i) { - if (s[i] != decimalpoint[i]) - goto pcheck; - } - decpt = s += i; -#else - if (*s == '.' && !decpt) { - decpt = ++s; -#endif - while(hexdig[*s]) - s++; - }/*}*/ - if (decpt) - e = -(((Long)(s-decpt)) << 2); - pcheck: - s1 = s; - big = esign = 0; - switch(*s) { - case 'p': - case 'P': - switch(*++s) { - case '-': - esign = 1; - /* no break */ - case '+': - s++; - } - if ((n = hexdig[*s]) == 0 || n > 0x19) { - s = s1; - break; - } - e1 = n - 0x10; - while((n = hexdig[*++s]) !=0 && n <= 0x19) { - if (e1 & 0xf8000000) - big = 1; - e1 = 10*e1 + n - 0x10; - } - if (esign) - e1 = -e1; - e += e1; - } - *sp = (char*)s; - if (!havedig) - *sp = (char*)s0 - 1; - if (zret) - return STRTOG_Zero; - if (big) { - if (esign) { - switch(fpi->rounding) { - case FPI_Round_up: - if (sign) - break; - goto ret_tiny; - case FPI_Round_down: - if (!sign) - break; - goto ret_tiny; - } - goto retz; - ret_tiny: - b = Balloc(0); - b->wds = 1; - b->x[0] = 1; - goto dret; - } - switch(fpi->rounding) { - case FPI_Round_near: - goto ovfl1; - case FPI_Round_up: - if (!sign) - goto ovfl1; - goto ret_big; - case FPI_Round_down: - if (sign) - goto ovfl1; - goto ret_big; - } - ret_big: - nbits = fpi->nbits; - n0 = n = nbits >> kshift; - if (nbits & kmask) - ++n; - for(j = n, k = 0; j >>= 1; ++k); - *bp = b = Balloc(k); - b->wds = n; - for(j = 0; j < n0; ++j) - b->x[j] = ALL_ON; - if (n > n0) - b->x[j] = ULbits >> (ULbits - (nbits & kmask)); - *exp = fpi->emin; - return STRTOG_Normal | STRTOG_Inexlo; - } - n = s1 - s0 - 1; - for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) - k++; - b = Balloc(k); - x = b->x; - n = 0; - L = 0; -#ifdef USE_LOCALE - for(i = 0; decimalpoint[i+1]; ++i); -#endif - while(s1 > s0) { -#ifdef USE_LOCALE - if (*--s1 == decimalpoint[i]) { - s1 -= i; - continue; - } -#else - if (*--s1 == '.') - continue; -#endif - if (n == ULbits) { - *x++ = L; - L = 0; - n = 0; - } - L |= (hexdig[*s1] & 0x0f) << n; - n += 4; - } - *x++ = L; - b->wds = n = x - b->x; - n = ULbits*n - hi0bits(L); - nbits = fpi->nbits; - lostbits = 0; - x = b->x; - if (n > nbits) { - n -= nbits; - if (any_on(b,n)) { - lostbits = 1; - k = n - 1; - if (x[k>>kshift] & 1 << (k & kmask)) { - lostbits = 2; - if (k > 0 && any_on(b,k)) - lostbits = 3; - } - } - rshift(b, n); - e += n; - } - else if (n < nbits) { - n = nbits - n; - b = lshift(b, n); - e -= n; - x = b->x; - } - if (e > fpi->emax) { - ovfl: - Bfree(b); - ovfl1: -#ifndef NO_ERRNO - errno = ERANGE; -#endif - return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; - } - irv = STRTOG_Normal; - if (e < fpi->emin) { - irv = STRTOG_Denormal; - n = fpi->emin - e; - if (n >= nbits) { - switch (fpi->rounding) { - case FPI_Round_near: - if (n == nbits && (n < 2 || any_on(b,n-1))) - goto one_bit; - break; - case FPI_Round_up: - if (!sign) - goto one_bit; - break; - case FPI_Round_down: - if (sign) { - one_bit: - x[0] = b->wds = 1; - dret: - *bp = b; - *exp = fpi->emin; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - return STRTOG_Denormal | STRTOG_Inexhi - | STRTOG_Underflow; - } - } - Bfree(b); - retz: -#ifndef NO_ERRNO - errno = ERANGE; -#endif - return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; - } - k = n - 1; - if (lostbits) - lostbits = 1; - else if (k > 0) - lostbits = any_on(b,k); - if (x[k>>kshift] & 1 << (k & kmask)) - lostbits |= 2; - nbits -= n; - rshift(b,n); - e = fpi->emin; - } - if (lostbits) { - up = 0; - switch(fpi->rounding) { - case FPI_Round_zero: - break; - case FPI_Round_near: - if (lostbits & 2 - && (lostbits | x[0]) & 1) - up = 1; - break; - case FPI_Round_up: - up = 1 - sign; - break; - case FPI_Round_down: - up = sign; - } - if (up) { - k = b->wds; - b = increment(b); - x = b->x; - if (irv == STRTOG_Denormal) { - if (nbits == fpi->nbits - 1 - && x[nbits >> kshift] & 1 << (nbits & kmask)) - irv = STRTOG_Normal; - } - else if (b->wds > k - || ((n = nbits & kmask) !=0 - && hi0bits(x[k-1]) < 32-n)) { - rshift(b,1); - if (++e > fpi->emax) - goto ovfl; - } - irv |= STRTOG_Inexhi; - } - else - irv |= STRTOG_Inexlo; - } - *bp = b; - *exp = e; - return irv; - } diff --git a/libraries/gdtoa/gmisc.c b/libraries/gdtoa/gmisc.c deleted file mode 100644 index 8270ef94479..00000000000 --- a/libraries/gdtoa/gmisc.c +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - void -#ifdef KR_headers -rshift(b, k) Bigint *b; int k; -#else -rshift(Bigint *b, int k) -#endif -{ - ULong *x, *x1, *xe, y; - int n; - - x = x1 = b->x; - n = k >> kshift; - if (n < b->wds) { - xe = x + b->wds; - x += n; - if (k &= kmask) { - n = ULbits - k; - y = *x++ >> k; - while(x < xe) { - *x1++ = (y | (*x << n)) & ALL_ON; - y = *x++ >> k; - } - if ((*x1 = y) !=0) - x1++; - } - else - while(x < xe) - *x1++ = *x++; - } - if ((b->wds = x1 - b->x) == 0) - b->x[0] = 0; - } - - int -#ifdef KR_headers -trailz(b) Bigint *b; -#else -trailz(Bigint *b) -#endif -{ - ULong L, *x, *xe; - int n = 0; - - x = b->x; - xe = x + b->wds; - for(n = 0; x < xe && !*x; x++) - n += ULbits; - if (x < xe) { - L = *x; - n += lo0bits(&L); - } - return n; - } diff --git a/libraries/gdtoa/hd_init.c b/libraries/gdtoa/hd_init.c deleted file mode 100644 index d79ae2ec8af..00000000000 --- a/libraries/gdtoa/hd_init.c +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#if 0 - unsigned char hexdig[256]; - - static void -#ifdef KR_headers -htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc; -#else -htinit(unsigned char *h, unsigned char *s, int inc) -#endif -{ - int i, j; - for(i = 0; (j = s[i]) !=0; i++) - h[j] = i + inc; - } - - void -hexdig_init_D2A(Void) /* Use of hexdig_init omitted 20121220 to avoid a */ - /* race condition when multiple threads are used. */ -{ -#define USC (unsigned char *) - htinit(hexdig, USC "0123456789", 0x10); - htinit(hexdig, USC "abcdef", 0x10 + 10); - htinit(hexdig, USC "ABCDEF", 0x10 + 10); - } -#else - unsigned char hexdig[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0, - 0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - }; -#endif diff --git a/libraries/gdtoa/hexnan.c b/libraries/gdtoa/hexnan.c deleted file mode 100644 index 80721e97af0..00000000000 --- a/libraries/gdtoa/hexnan.c +++ /dev/null @@ -1,159 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - static void -#ifdef KR_headers -L_shift(x, x1, i) ULong *x; ULong *x1; int i; -#else -L_shift(ULong *x, ULong *x1, int i) -#endif -{ - int j; - - i = 8 - i; - i <<= 2; - j = ULbits - i; - do { - *x |= x[1] << j; - x[1] >>= i; - } while(++x < x1); - } - - int -#ifdef KR_headers -hexnan(sp, fpi, x0) - CONST char **sp; FPI *fpi; ULong *x0; -#else -hexnan( CONST char **sp, FPI *fpi, ULong *x0) -#endif -{ - ULong c, h, *x, *x1, *xe; - CONST char *s; - int havedig, hd0, i, nbits; - - /**** if (!hexdig['0']) hexdig_init_D2A(); ****/ - nbits = fpi->nbits; - x = x0 + (nbits >> kshift); - if (nbits & kmask) - x++; - *--x = 0; - x1 = xe = x; - havedig = hd0 = i = 0; - s = *sp; - /* allow optional initial 0x or 0X */ - while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') { - if (!c) - goto retnan; - ++s; - } - if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X') - && *(CONST unsigned char*)(s+3) > ' ') - s += 2; - while((c = *(CONST unsigned char*)++s)) { - if (!(h = hexdig[c])) { - if (c <= ' ') { - if (hd0 < havedig) { - if (x < x1 && i < 8) - L_shift(x, x1, i); - if (x <= x0) { - i = 8; - continue; - } - hd0 = havedig; - *--x = 0; - x1 = x; - i = 0; - } - while((c = *(CONST unsigned char*)(s+1)) <= ' ') { - if (!c) - goto retnan; - ++s; - } - if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X') - && *(CONST unsigned char*)(s+3) > ' ') - s += 2; - continue; - } - if (/*(*/ c == ')' && havedig) { - *sp = s + 1; - break; - } -#ifndef GDTOA_NON_PEDANTIC_NANCHECK - do { - if (/*(*/ c == ')') { - *sp = s + 1; - goto break2; - } - } while((c = *++s)); -#endif - retnan: - return STRTOG_NaN; - } - havedig++; - if (++i > 8) { - if (x <= x0) - continue; - i = 1; - *--x = 0; - } - *x = (*x << 4) | (h & 0xf); - } -#ifndef GDTOA_NON_PEDANTIC_NANCHECK - break2: -#endif - if (!havedig) - return STRTOG_NaN; - if (x < x1 && i < 8) - L_shift(x, x1, i); - if (x > x0) { - x1 = x0; - do *x1++ = *x++; - while(x <= xe); - do *x1++ = 0; - while(x1 <= xe); - } - else { - /* truncate high-order word if necessary */ - if ( (i = nbits & (ULbits-1)) !=0) - *xe &= ((ULong)0xffffffff) >> (ULbits - i); - } - for(x1 = xe;; --x1) { - if (*x1 != 0) - break; - if (x1 == x0) { - *x1 = 1; - break; - } - } - return STRTOG_NaNbits; - } diff --git a/libraries/gdtoa/misc.c b/libraries/gdtoa/misc.c deleted file mode 100644 index d13046732a6..00000000000 --- a/libraries/gdtoa/misc.c +++ /dev/null @@ -1,875 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - static Bigint *freelist[Kmax+1]; -#ifndef Omit_Private_Memory -#ifndef PRIVATE_MEM -#define PRIVATE_MEM 2304 -#endif -#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) -static double private_mem[PRIVATE_mem], *pmem_next = private_mem; -#endif - - Bigint * -Balloc -#ifdef KR_headers - (k) int k; -#else - (int k) -#endif -{ - int x; - Bigint *rv; -#ifndef Omit_Private_Memory - unsigned int len; -#endif - - ACQUIRE_DTOA_LOCK(0); - /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ - /* but this case seems very unlikely. */ - if (k <= Kmax && (rv = freelist[k]) !=0) { - freelist[k] = rv->next; - } - else { - x = 1 << k; -#ifdef Omit_Private_Memory - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); -#else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) - /sizeof(double); - if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { - rv = (Bigint*)pmem_next; - pmem_next += len; - } - else - rv = (Bigint*)MALLOC(len*sizeof(double)); -#endif - rv->k = k; - rv->maxwds = x; - } - FREE_DTOA_LOCK(0); - rv->sign = rv->wds = 0; - return rv; - } - - void -Bfree -#ifdef KR_headers - (v) Bigint *v; -#else - (Bigint *v) -#endif -{ - if (v) { - if (v->k > Kmax) -#ifdef FREE - FREE((void*)v); -#else - free((void*)v); -#endif - else { - ACQUIRE_DTOA_LOCK(0); - v->next = freelist[v->k]; - freelist[v->k] = v; - FREE_DTOA_LOCK(0); - } - } - } - - int -lo0bits -#ifdef KR_headers - (y) ULong *y; -#else - (ULong *y) -#endif -{ - int k; - ULong x = *y; - - if (x & 7) { - if (x & 1) - return 0; - if (x & 2) { - *y = x >> 1; - return 1; - } - *y = x >> 2; - return 2; - } - k = 0; - if (!(x & 0xffff)) { - k = 16; - x >>= 16; - } - if (!(x & 0xff)) { - k += 8; - x >>= 8; - } - if (!(x & 0xf)) { - k += 4; - x >>= 4; - } - if (!(x & 0x3)) { - k += 2; - x >>= 2; - } - if (!(x & 1)) { - k++; - x >>= 1; - if (!x) - return 32; - } - *y = x; - return k; - } - - Bigint * -multadd -#ifdef KR_headers - (b, m, a) Bigint *b; int m, a; -#else - (Bigint *b, int m, int a) /* multiply by m and add a */ -#endif -{ - int i, wds; -#ifdef ULLong - ULong *x; - ULLong carry, y; -#else - ULong carry, *x, y; -#ifdef Pack_32 - ULong xi, z; -#endif -#endif - Bigint *b1; - - wds = b->wds; - x = b->x; - i = 0; - carry = a; - do { -#ifdef ULLong - y = *x * (ULLong)m + carry; - carry = y >> 32; - *x++ = (ULong)(y & 0xffffffffUL); -#else -#ifdef Pack_32 - xi = *x; - y = (xi & 0xffff) * m + carry; - z = (xi >> 16) * m + (y >> 16); - carry = z >> 16; - *x++ = (z << 16) + (y & 0xffff); -#else - y = *x * m + carry; - carry = y >> 16; - *x++ = y & 0xffff; -#endif -#endif - } - while(++i < wds); - if (carry) { - if (wds >= b->maxwds) { - b1 = Balloc(b->k+1); - Bcopy(b1, b); - Bfree(b); - b = b1; - } - b->x[wds++] = (ULong)carry; - b->wds = wds; - } - return b; - } - - int -hi0bits_D2A -#ifdef KR_headers - (x) ULong x; -#else - (ULong x) -#endif -{ - int k = 0; - - if (!(x & 0xffff0000)) { - k = 16; - x <<= 16; - } - if (!(x & 0xff000000)) { - k += 8; - x <<= 8; - } - if (!(x & 0xf0000000)) { - k += 4; - x <<= 4; - } - if (!(x & 0xc0000000)) { - k += 2; - x <<= 2; - } - if (!(x & 0x80000000)) { - k++; - if (!(x & 0x40000000)) - return 32; - } - return k; - } - - Bigint * -i2b -#ifdef KR_headers - (i) int i; -#else - (int i) -#endif -{ - Bigint *b; - - b = Balloc(1); - b->x[0] = i; - b->wds = 1; - return b; - } - - Bigint * -mult -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif -{ - Bigint *c; - int k, wa, wb, wc; - ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; - ULong y; -#ifdef ULLong - ULLong carry, z; -#else - ULong carry, z; -#ifdef Pack_32 - ULong z2; -#endif -#endif - - if (a->wds < b->wds) { - c = a; - a = b; - b = c; - } - k = a->k; - wa = a->wds; - wb = b->wds; - wc = wa + wb; - if (wc > a->maxwds) - k++; - c = Balloc(k); - for(x = c->x, xa = x + wc; x < xa; x++) - *x = 0; - xa = a->x; - xae = xa + wa; - xb = b->x; - xbe = xb + wb; - xc0 = c->x; -#ifdef ULLong - for(; xb < xbe; xc0++) { - if ( (y = *xb++) !=0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * (ULLong)y + *xc + carry; - carry = z >> 32; - *xc++ = (ULong)(z & 0xffffffffUL); - } - while(x < xae); - *xc = (ULong)carry; - } - } -#else -#ifdef Pack_32 - for(; xb < xbe; xb++, xc0++) { - if ( (y = *xb & 0xffff) !=0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; - carry = z >> 16; - z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; - carry = z2 >> 16; - Storeinc(xc, z2, z); - } - while(x < xae); - *xc = carry; - } - if ( (y = *xb >> 16) !=0) { - x = xa; - xc = xc0; - carry = 0; - z2 = *xc; - do { - z = (*x & 0xffff) * y + (*xc >> 16) + carry; - carry = z >> 16; - Storeinc(xc, z, z2); - z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; - carry = z2 >> 16; - } - while(x < xae); - *xc = z2; - } - } -#else - for(; xb < xbe; xc0++) { - if ( (y = *xb++) !=0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } - while(x < xae); - *xc = carry; - } - } -#endif -#endif - for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; - c->wds = wc; - return c; - } - - static Bigint *p5s; - - Bigint * -pow5mult -#ifdef KR_headers - (b, k) Bigint *b; int k; -#else - (Bigint *b, int k) -#endif -{ - Bigint *b1, *p5, *p51; - int i; - static int p05[3] = { 5, 25, 125 }; - - if ( (i = k & 3) !=0) - b = multadd(b, p05[i-1], 0); - - if (!(k >>= 2)) - return b; - if ((p5 = p5s) == 0) { - /* first time */ -#ifdef MULTIPLE_THREADS - ACQUIRE_DTOA_LOCK(1); - if (!(p5 = p5s)) { - p5 = p5s = i2b(625); - p5->next = 0; - } - FREE_DTOA_LOCK(1); -#else - p5 = p5s = i2b(625); - p5->next = 0; -#endif - } - for(;;) { - if (k & 1) { - b1 = mult(b, p5); - Bfree(b); - b = b1; - } - if (!(k >>= 1)) - break; - if ((p51 = p5->next) == 0) { -#ifdef MULTIPLE_THREADS - ACQUIRE_DTOA_LOCK(1); - if (!(p51 = p5->next)) { - p51 = p5->next = mult(p5,p5); - p51->next = 0; - } - FREE_DTOA_LOCK(1); -#else - p51 = p5->next = mult(p5,p5); - p51->next = 0; -#endif - } - p5 = p51; - } - return b; - } - - Bigint * -lshift -#ifdef KR_headers - (b, k) Bigint *b; int k; -#else - (Bigint *b, int k) -#endif -{ - int i, k1, n, n1; - Bigint *b1; - ULong *x, *x1, *xe, z; - - n = k >> kshift; - k1 = b->k; - n1 = n + b->wds + 1; - for(i = b->maxwds; n1 > i; i <<= 1) - k1++; - b1 = Balloc(k1); - x1 = b1->x; - for(i = 0; i < n; i++) - *x1++ = 0; - x = b->x; - xe = x + b->wds; - if (k &= kmask) { -#ifdef Pack_32 - k1 = 32 - k; - z = 0; - do { - *x1++ = *x << k | z; - z = *x++ >> k1; - } - while(x < xe); - if ((*x1 = z) !=0) - ++n1; -#else - k1 = 16 - k; - z = 0; - do { - *x1++ = *x << k & 0xffff | z; - z = *x++ >> k1; - } - while(x < xe); - if (*x1 = z) - ++n1; -#endif - } - else do - *x1++ = *x++; - while(x < xe); - b1->wds = n1 - 1; - Bfree(b); - return b1; - } - - int -cmp -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif -{ - ULong *xa, *xa0, *xb, *xb0; - int i, j; - - i = a->wds; - j = b->wds; -#ifdef DEBUG - if (i > 1 && !a->x[i-1]) - Bug("cmp called with a->x[a->wds-1] == 0"); - if (j > 1 && !b->x[j-1]) - Bug("cmp called with b->x[b->wds-1] == 0"); -#endif - if (i -= j) - return i; - xa0 = a->x; - xa = xa0 + j; - xb0 = b->x; - xb = xb0 + j; - for(;;) { - if (*--xa != *--xb) - return *xa < *xb ? -1 : 1; - if (xa <= xa0) - break; - } - return 0; - } - - Bigint * -diff -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif -{ - Bigint *c; - int i, wa, wb; - ULong *xa, *xae, *xb, *xbe, *xc; -#ifdef ULLong - ULLong borrow, y; -#else - ULong borrow, y; -#ifdef Pack_32 - ULong z; -#endif -#endif - - i = cmp(a,b); - if (!i) { - c = Balloc(0); - c->wds = 1; - c->x[0] = 0; - return c; - } - if (i < 0) { - c = a; - a = b; - b = c; - i = 1; - } - else - i = 0; - c = Balloc(a->k); - c->sign = i; - wa = a->wds; - xa = a->x; - xae = xa + wa; - wb = b->wds; - xb = b->x; - xbe = xb + wb; - xc = c->x; - borrow = 0; -#ifdef ULLong - do { - y = (ULLong)*xa++ - *xb++ - borrow; - borrow = y >> 32 & 1UL; - *xc++ = (ULong)(y & 0xffffffffUL); - } - while(xb < xbe); - while(xa < xae) { - y = *xa++ - borrow; - borrow = y >> 32 & 1UL; - *xc++ = (ULong)(y & 0xffffffffUL); - } -#else -#ifdef Pack_32 - do { - y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } - while(xb < xbe); - while(xa < xae) { - y = (*xa & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } -#else - do { - y = *xa++ - *xb++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } - while(xb < xbe); - while(xa < xae) { - y = *xa++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif -#endif - while(!*--xc) - wa--; - c->wds = wa; - return c; - } - - double -b2d -#ifdef KR_headers - (a, e) Bigint *a; int *e; -#else - (Bigint *a, int *e) -#endif -{ - ULong *xa, *xa0, w, y, z; - int k; - U d; -#ifdef VAX - ULong d0, d1; -#else -#define d0 word0(&d) -#define d1 word1(&d) -#endif - - xa0 = a->x; - xa = xa0 + a->wds; - y = *--xa; -#ifdef DEBUG - if (!y) Bug("zero y in b2d"); -#endif - k = hi0bits(y); - *e = 32 - k; -#ifdef Pack_32 - if (k < Ebits) { - d0 = Exp_1 | y >> (Ebits - k); - w = xa > xa0 ? *--xa : 0; - d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - if (k -= Ebits) { - d0 = Exp_1 | y << k | z >> (32 - k); - y = xa > xa0 ? *--xa : 0; - d1 = z << k | y >> (32 - k); - } - else { - d0 = Exp_1 | y; - d1 = z; - } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; - y = xa > xa0 ? *--xa : 0; - d1 = w << k + 16 | y << k; -#endif - ret_d: -#ifdef VAX - word0(&d) = d0 >> 16 | d0 << 16; - word1(&d) = d1 >> 16 | d1 << 16; -#endif - return dval(&d); - } -#undef d0 -#undef d1 - - Bigint * -d2b -#ifdef KR_headers - (dd, e, bits) double dd; int *e, *bits; -#else - (double dd, int *e, int *bits) -#endif -{ - Bigint *b; - U d; -#ifndef Sudden_Underflow - int i; -#endif - int de, k; - ULong *x, y, z; -#ifdef VAX - ULong d0, d1; -#else -#define d0 word0(&d) -#define d1 word1(&d) -#endif - d.d = dd; -#ifdef VAX - d0 = word0(&d) >> 16 | word0(&d) << 16; - d1 = word1(&d) >> 16 | word1(&d) << 16; -#endif - -#ifdef Pack_32 - b = Balloc(1); -#else - b = Balloc(2); -#endif - x = b->x; - - z = d0 & Frac_mask; - d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(d0 >> Exp_shift); -#ifndef IBM - z |= Exp_msk11; -#endif -#else - if ( (de = (int)(d0 >> Exp_shift)) !=0) - z |= Exp_msk1; -#endif -#ifdef Pack_32 - if ( (y = d1) !=0) { - if ( (k = lo0bits(&y)) !=0) { - x[0] = y | z << (32 - k); - z >>= k; - } - else - x[0] = y; -#ifndef Sudden_Underflow - i = -#endif - b->wds = (x[1] = z) !=0 ? 2 : 1; - } - else { - k = lo0bits(&z); - x[0] = z; -#ifndef Sudden_Underflow - i = -#endif - b->wds = 1; - k += 32; - } -#else - if ( (y = d1) !=0) { - if ( (k = lo0bits(&y)) !=0) - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k+16; - i = 3; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } - else { -#ifdef DEBUG - if (!z) - Bug("Zero passed to d2b"); -#endif - k = lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } - else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } - while(!x[i]) - --i; - b->wds = i + 1; -#endif -#ifndef Sudden_Underflow - if (de) { -#endif -#ifdef IBM - *e = (de - Bias - (P-1) << 2) + k; - *bits = 4*P + 8 - k - hi0bits(word0(&d) & Frac_mask); -#else - *e = de - Bias - (P-1) + k; - *bits = P - k; -#endif -#ifndef Sudden_Underflow - } - else { - *e = de - Bias - (P-1) + 1 + k; -#ifdef Pack_32 - *bits = 32*i - hi0bits(x[i-1]); -#else - *bits = (i+2)*16 - hi0bits(x[i]); -#endif - } -#endif - return b; - } -#undef d0 -#undef d1 - - CONST double -#ifdef IEEE_Arith -bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; -CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 - }; -#else -#ifdef IBM -bigtens[] = { 1e16, 1e32, 1e64 }; -CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; -#else -bigtens[] = { 1e16, 1e32 }; -CONST double tinytens[] = { 1e-16, 1e-32 }; -#endif -#endif - - CONST double -tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 -#ifdef VAX - , 1e23, 1e24 -#endif - }; - - char * -#ifdef KR_headers -strcp_D2A(a, b) char *a; char *b; -#else -strcp_D2A(char *a, CONST char *b) -#endif -{ - while((*a = *b++)) - a++; - return a; - } - -#ifdef NO_STRING_H - - Char * -#ifdef KR_headers -memcpy_D2A(a, b, len) Char *a; Char *b; size_t len; -#else -memcpy_D2A(void *a1, void *b1, size_t len) -#endif -{ - char *a = (char*)a1, *ae = a + len; - char *b = (char*)b1, *a0 = a; - while(a < ae) - *a++ = *b++; - return a0; - } - -#endif /* NO_STRING_H */ diff --git a/libraries/gdtoa/qnan.c b/libraries/gdtoa/qnan.c deleted file mode 100644 index ea7e8745ba8..00000000000 --- a/libraries/gdtoa/qnan.c +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 2005 by David M. Gay -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that the copyright notice and this permission notice and warranty -disclaimer appear in supporting documentation, and that the name of -the author or any of his current or former employers not be used in -advertising or publicity pertaining to distribution of the software -without specific, written prior permission. - -THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN -NO EVENT SHALL THE AUTHOR OR ANY OF HIS CURRENT OR FORMER EMPLOYERS BE -LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY -DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -/* Program to compute quiet NaNs of various precisions (float, */ -/* double, and perhaps long double) on the current system, */ -/* provided the system uses binary IEEE (P754) arithmetic. */ -/* Note that one system's quiet NaN may be a signaling NaN on */ -/* another system. The IEEE arithmetic standards (P754, P854) */ -/* do not specify how to distinguish signaling NaNs from quiet */ -/* ones, and this detail varies across systems. The computed */ -/* NaN values are encoded in #defines for values for an */ -/* unsigned 32-bit integer type, called Ulong below, and */ -/* (for long double) perhaps as unsigned short values. Once */ -/* upon a time, there were PC compilers for Intel CPUs that */ -/* had sizeof(long double) = 10. Are such compilers still */ -/* distributed? */ - -#include -#include "arith.h" - -#ifndef Long -#define Long long -#endif - -typedef unsigned Long Ulong; - -#undef HAVE_IEEE -#ifdef IEEE_8087 -#define _0 1 -#define _1 0 -#define _3 3 -#if defined(Gen_ld_QNAN) && !defined(NO_LONG_LONG) -static int perm[4] = { 0, 1, 2, 3 }; -#endif -#define HAVE_IEEE -#endif -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _3 0 -#if defined(Gen_ld_QNAN) && !defined(NO_LONG_LONG) -static int perm[4] = { 3, 2, 1, 0 }; -#endif -#define HAVE_IEEE -#endif - -#define UL (unsigned long) - - int -main(void) -{ -#ifdef HAVE_IEEE - typedef union { - float f; - double d; - Ulong L[4]; -#ifndef NO_LONG_LONG - unsigned short u[5]; - long double D; -#endif - } U; - U a, b, c; -#if defined(Gen_ld_QNAN) && !defined(NO_LONG_LONG) - int i; -#endif - - a.L[0] = b.L[0] = 0x7f800000; - c.f = a.f - b.f; - printf("#define f_QNAN 0x%lx\n", UL (c.L[0] & 0x7fffffff)); - a.L[_0] = b.L[_0] = 0x7ff00000; - a.L[_1] = b.L[_1] = 0; - c.d = a.d - b.d; /* quiet NaN */ - c.L[_0] &= 0x7fffffff; - printf("#define d_QNAN0 0x%lx\n", UL c.L[_0]); - printf("#define d_QNAN1 0x%lx\n", UL c.L[_1]); -#ifndef NO_LONG_LONG -#ifdef Gen_ld_QNAN - if (sizeof(a.D) >= 16) { - b.D = c.D = a.d; - if (printf("") < 0) - c.D = 37; /* never executed; just defeat optimization */ - a.L[0] = a.L[1] = a.L[2] = a.L[3] = 0; - a.D = b.D - c.D; - a.L[_3] &= 0x7fffffff; - for(i = 0; i < 4; i++) - printf("#define ld_QNAN%d 0x%lx\n", i, UL a.L[perm[i]]); - } -#endif -#endif -#endif /* HAVE_IEEE */ - return 0; - } diff --git a/libraries/gdtoa/qnan.obj b/libraries/gdtoa/qnan.obj deleted file mode 100644 index 994af47d98c..00000000000 Binary files a/libraries/gdtoa/qnan.obj and /dev/null differ diff --git a/libraries/gdtoa/smisc.c b/libraries/gdtoa/smisc.c deleted file mode 100644 index f4dbafb21c5..00000000000 --- a/libraries/gdtoa/smisc.c +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - Bigint * -s2b -#ifdef KR_headers - (s, nd0, nd, y9, dplen) CONST char *s; int dplen, nd0, nd; ULong y9; -#else - (CONST char *s, int nd0, int nd, ULong y9, int dplen) -#endif -{ - Bigint *b; - int i, k; - Long x, y; - - x = (nd + 8) / 9; - for(k = 0, y = 1; x > y; y <<= 1, k++) ; -#ifdef Pack_32 - b = Balloc(k); - b->x[0] = y9; - b->wds = 1; -#else - b = Balloc(k+1); - b->x[0] = y9 & 0xffff; - b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; -#endif - - i = 9; - if (9 < nd0) { - s += 9; - do b = multadd(b, 10, *s++ - '0'); - while(++i < nd0); - s += dplen; - } - else - s += dplen + 9; - for(; i < nd; i++) - b = multadd(b, 10, *s++ - '0'); - return b; - } - - double -ratio -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif -{ - U da, db; - int k, ka, kb; - - dval(&da) = b2d(a, &ka); - dval(&db) = b2d(b, &kb); - k = ka - kb + ULbits*(a->wds - b->wds); -#ifdef IBM - if (k > 0) { - word0(&da) += (k >> 2)*Exp_msk1; - if (k &= 3) - dval(&da) *= 1 << k; - } - else { - k = -k; - word0(&db) += (k >> 2)*Exp_msk1; - if (k &= 3) - dval(&db) *= 1 << k; - } -#else - if (k > 0) - word0(&da) += k*Exp_msk1; - else { - k = -k; - word0(&db) += k*Exp_msk1; - } -#endif - return dval(&da) / dval(&db); - } - -#ifdef INFNAN_CHECK - - int -match -#ifdef KR_headers - (sp, t) char **sp, *t; -#else - (CONST char **sp, char *t) -#endif -{ - int c, d; - CONST char *s = *sp; - - while( (d = *t++) !=0) { - if ((c = *++s) >= 'A' && c <= 'Z') - c += 'a' - 'A'; - if (c != d) - return 0; - } - *sp = s + 1; - return 1; - } -#endif /* INFNAN_CHECK */ - - void -#ifdef KR_headers -copybits(c, n, b) ULong *c; int n; Bigint *b; -#else -copybits(ULong *c, int n, Bigint *b) -#endif -{ - ULong *ce, *x, *xe; -#ifdef Pack_16 - int nw, nw1; -#endif - - ce = c + ((n-1) >> kshift) + 1; - x = b->x; -#ifdef Pack_32 - xe = x + b->wds; - while(x < xe) - *c++ = *x++; -#else - nw = b->wds; - nw1 = nw & 1; - for(xe = x + (nw - nw1); x < xe; x += 2) - Storeinc(c, x[1], x[0]); - if (nw1) - *c++ = *x; -#endif - while(c < ce) - *c++ = 0; - } - - ULong -#ifdef KR_headers -any_on(b, k) Bigint *b; int k; -#else -any_on(Bigint *b, int k) -#endif -{ - int n, nwds; - ULong *x, *x0, x1, x2; - - x = b->x; - nwds = b->wds; - n = k >> kshift; - if (n > nwds) - n = nwds; - else if (n < nwds && (k &= kmask)) { - x1 = x2 = x[n]; - x1 >>= k; - x1 <<= k; - if (x1 != x2) - return 1; - } - x0 = x; - x += n; - while(x > x0) - if (*--x) - return 1; - return 0; - } diff --git a/libraries/gdtoa/strtoIQ.c b/libraries/gdtoa/strtoIQ.c deleted file mode 100644 index 9ce5120e6b7..00000000000 --- a/libraries/gdtoa/strtoIQ.c +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIQ(s, sp, a, b) CONST char *s; char **sp; void *a; void *b; -#else -strtoIQ(CONST char *s, char **sp, void *a, void *b) -#endif -{ - static FPI fpi = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - ULong *L = (ULong *)a, *M = (ULong *)b; - - B[0] = Balloc(2); - B[0]->wds = 4; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtoQ(L, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtoQ(M, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - M[0] = L[0]; - M[1] = L[1]; - M[2] = L[2]; - M[3] = L[3]; - } - return k; - } diff --git a/libraries/gdtoa/strtoId.c b/libraries/gdtoa/strtoId.c deleted file mode 100644 index 1c97d382dea..00000000000 --- a/libraries/gdtoa/strtoId.c +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoId(s, sp, f0, f1) CONST char *s; char **sp; double *f0, *f1; -#else -strtoId(CONST char *s, char **sp, double *f0, double *f1) -#endif -{ - static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - - B[0] = Balloc(1); - B[0]->wds = 2; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtod((ULong*)f0, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtod((ULong*)f1, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - ((ULong*)f1)[0] = ((ULong*)f0)[0]; - ((ULong*)f1)[1] = ((ULong*)f0)[1]; - } - return k; - } diff --git a/libraries/gdtoa/strtoIdd.c b/libraries/gdtoa/strtoIdd.c deleted file mode 100644 index 40b7936bc00..00000000000 --- a/libraries/gdtoa/strtoIdd.c +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIdd(s, sp, f0, f1) CONST char *s; char **sp; double *f0, *f1; -#else -strtoIdd(CONST char *s, char **sp, double *f0, double *f1) -#endif -{ -#ifdef Sudden_Underflow - static FPI fpi = { 106, 1-1023, 2046-1023-106+1, 1, 1 }; -#else - static FPI fpi = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0 }; -#endif - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - - B[0] = Balloc(2); - B[0]->wds = 4; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtodd((ULong*)f0, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtodd((ULong*)f1, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - ((ULong*)f1)[0] = ((ULong*)f0)[0]; - ((ULong*)f1)[1] = ((ULong*)f0)[1]; - ((ULong*)f1)[2] = ((ULong*)f0)[2]; - ((ULong*)f1)[3] = ((ULong*)f0)[3]; - } - return k; - } diff --git a/libraries/gdtoa/strtoIf.c b/libraries/gdtoa/strtoIf.c deleted file mode 100644 index 65ecab2e0b8..00000000000 --- a/libraries/gdtoa/strtoIf.c +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIf(s, sp, f0, f1) CONST char *s; char **sp; float *f0, *f1; -#else -strtoIf(CONST char *s, char **sp, float *f0, float *f1) -#endif -{ - static FPI fpi = { 24, 1-127-24+1, 254-127-24+1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - - B[0] = Balloc(0); - B[0]->wds = 1; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtof((ULong*)f0, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtof((ULong*)f1, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else - *(ULong*)f1 = *(ULong*)f0; - return k; - } diff --git a/libraries/gdtoa/strtoIg.c b/libraries/gdtoa/strtoIg.c deleted file mode 100644 index 6a17760cf5c..00000000000 --- a/libraries/gdtoa/strtoIg.c +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIg(s00, se, fpi, exp, B, rvp) CONST char *s00; char **se; FPI *fpi; Long *exp; Bigint **B; int *rvp; -#else -strtoIg(CONST char *s00, char **se, FPI *fpi, Long *exp, Bigint **B, int *rvp) -#endif -{ - Bigint *b, *b1; - int i, nb, nw, nw1, rv, rv1, swap; - unsigned int nb1, nb11; - Long e1; - - b = *B; - rv = strtodg(s00, se, fpi, exp, b->x); - if (!(rv & STRTOG_Inexact)) { - B[1] = 0; - return *rvp = rv; - } - e1 = exp[0]; - rv1 = rv ^ STRTOG_Inexact; - b1 = Balloc(b->k); - Bcopy(b1, b); - nb = fpi->nbits; - nb1 = nb & 31; - nb11 = (nb1 - 1) & 31; - nw = b->wds; - nw1 = nw - 1; - if (rv & STRTOG_Inexlo) { - swap = 0; - b1 = increment(b1); - if ((rv & STRTOG_Retmask) == STRTOG_Zero) { - if (fpi->sudden_underflow) { - b1->x[0] = 0; - b1->x[nw1] = 1L << nb11; - rv1 += STRTOG_Normal - STRTOG_Zero; - rv1 &= ~STRTOG_Underflow; - goto swapcheck; - } - rv1 &= STRTOG_Inexlo | STRTOG_Underflow | STRTOG_Zero; - rv1 |= STRTOG_Inexhi | STRTOG_Denormal; - goto swapcheck; - } - if (b1->wds > nw - || (nb1 && b1->x[nw1] & 1L << nb1)) { - if (++e1 > fpi->emax) - rv1 = STRTOG_Infinite | STRTOG_Inexhi; - rshift(b1, 1); - } - else if ((rv & STRTOG_Retmask) == STRTOG_Denormal) { - if (b1->x[nw1] & 1L << nb11) { - rv1 += STRTOG_Normal - STRTOG_Denormal; - rv1 &= ~STRTOG_Underflow; - } - } - } - else { - swap = STRTOG_Neg; - if ((rv & STRTOG_Retmask) == STRTOG_Infinite) { - b1 = set_ones(b1, nb); - e1 = fpi->emax; - rv1 = STRTOG_Normal | STRTOG_Inexlo; - goto swapcheck; - } - decrement(b1); - if ((rv & STRTOG_Retmask) == STRTOG_Denormal) { - for(i = nw1; !b1->x[i]; --i) - if (!i) { - rv1 = STRTOG_Zero | STRTOG_Inexlo; - break; - } - goto swapcheck; - } - if (!(b1->x[nw1] & 1L << nb11)) { - if (e1 == fpi->emin) { - if (fpi->sudden_underflow) - rv1 += STRTOG_Zero - STRTOG_Normal; - else - rv1 += STRTOG_Denormal - STRTOG_Normal; - rv1 |= STRTOG_Underflow; - } - else { - b1 = lshift(b1, 1); - b1->x[0] |= 1; - --e1; - } - } - } - swapcheck: - if (swap ^ (rv & STRTOG_Neg)) { - rvp[0] = rv1; - rvp[1] = rv; - B[0] = b1; - B[1] = b; - exp[1] = exp[0]; - exp[0] = e1; - } - else { - rvp[0] = rv; - rvp[1] = rv1; - B[1] = b1; - exp[1] = e1; - } - return rv; - } diff --git a/libraries/gdtoa/strtoIx.c b/libraries/gdtoa/strtoIx.c deleted file mode 100644 index 783a631f066..00000000000 --- a/libraries/gdtoa/strtoIx.c +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIx(s, sp, a, b) CONST char *s; char **sp; void *a; void *b; -#else -strtoIx(CONST char *s, char **sp, void *a, void *b) -#endif -{ - static FPI fpi = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - UShort *L = (UShort *)a, *M = (UShort *)b; - - B[0] = Balloc(1); - B[0]->wds = 2; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtox(L, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtox(M, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - M[0] = L[0]; - M[1] = L[1]; - M[2] = L[2]; - M[3] = L[3]; - M[4] = L[4]; - } - return k; - } diff --git a/libraries/gdtoa/strtoIxL.c b/libraries/gdtoa/strtoIxL.c deleted file mode 100644 index 869bfd16fb8..00000000000 --- a/libraries/gdtoa/strtoIxL.c +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIxL(s, sp, a, b) CONST char *s; char **sp; void *a; void *b; -#else -strtoIxL(CONST char *s, char **sp, void *a, void *b) -#endif -{ - static FPI fpi = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - ULong *L = (ULong *)a, *M = (ULong *)b; - - B[0] = Balloc(1); - B[0]->wds = 2; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtoxL(L, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtoxL(M, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - M[0] = L[0]; - M[1] = L[1]; - M[2] = L[2]; - } - return k; - } diff --git a/libraries/gdtoa/strtod.c b/libraries/gdtoa/strtod.c deleted file mode 100644 index 3c22300537b..00000000000 --- a/libraries/gdtoa/strtod.c +++ /dev/null @@ -1,1074 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998-2001 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" -#if !defined(NO_FENV_H) && !defined(_MSC_VER) -#include -#endif - -#ifdef USE_LOCALE -#include "locale.h" -#endif - -#ifdef IEEE_Arith -#ifndef NO_IEEE_Scale -#define Avoid_Underflow -#undef tinytens -/* The factor of 2^106 in tinytens[4] helps us avoid setting the underflow */ -/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ -static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, - 9007199254740992.*9007199254740992.e-256 - }; -#endif -#endif - -#ifdef Honor_FLT_ROUNDS -#undef Check_FLT_ROUNDS -#define Check_FLT_ROUNDS -#else -#define Rounding Flt_Rounds -#endif - -#ifdef Avoid_Underflow /*{*/ - static double -sulp -#ifdef KR_headers - (x, scale) U *x; int scale; -#else - (U *x, int scale) -#endif -{ - U u; - double rv; - int i; - - rv = ulp(x); - if (!scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) - return rv; /* Is there an example where i <= 0 ? */ - word0(&u) = Exp_1 + (i << Exp_shift); - word1(&u) = 0; - return rv * u.d; - } -#endif /*}*/ - - double -strtod -#ifdef KR_headers - (s00, se) CONST char *s00; char **se; -#else - (CONST char *s00, char **se) -#endif -{ -#ifdef Avoid_Underflow - int scale; -#endif - int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; - CONST char *s, *s0, *s1; - double aadj; - Long L; - U adj, aadj1, rv, rv0; - ULong y, z; - Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; -#ifdef Avoid_Underflow - ULong Lsb, Lsb1; -#endif -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif -#ifdef USE_LOCALE /*{{*/ -#ifdef NO_LOCALE_CACHE - char *decimalpoint = localeconv()->decimal_point; - int dplen = strlen(decimalpoint); -#else - char *decimalpoint; - static char *decimalpoint_cache; - static int dplen; - if (!(s0 = decimalpoint_cache)) { - s0 = localeconv()->decimal_point; - if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { - strcpy(decimalpoint_cache, s0); - s0 = decimalpoint_cache; - } - dplen = strlen(s0); - } - decimalpoint = (char*)s0; -#endif /*NO_LOCALE_CACHE*/ -#else /*USE_LOCALE}{*/ -#define dplen 1 -#endif /*USE_LOCALE}}*/ - -#ifdef Honor_FLT_ROUNDS /*{*/ - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ -#endif /*}*/ - - sign = nz0 = nz = decpt = 0; - dval(&rv) = 0.; - for(s = s00;;s++) switch(*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) - goto break2; - /* no break */ - case 0: - goto ret0; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: - goto break2; - } - break2: - if (*s == '0') { -#ifndef NO_HEX_FP /*{*/ - { - static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - Long exp; - ULong bits[2]; - switch(s[1]) { - case 'x': - case 'X': - { -#ifdef Honor_FLT_ROUNDS - FPI fpi1 = fpi; - fpi1.rounding = Rounding; -#else -#define fpi1 fpi -#endif - switch((i = gethex(&s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) { - case STRTOG_NoNumber: - s = s00; - sign = 0; - case STRTOG_Zero: - break; - default: - if (bb) { - copybits(bits, fpi.nbits, bb); - Bfree(bb); - } - ULtod(((U*)&rv)->L, bits, exp, i); - }} - goto ret; - } - } -#endif /*}*/ - nz0 = 1; - while(*++s == '0') ; - if (!*s) - goto ret; - } - s0 = s; - y = z = 0; - for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10*y + c - '0'; - else if (nd < 16) - z = 10*z + c - '0'; - nd0 = nd; -#ifdef USE_LOCALE - if (c == *decimalpoint) { - for(i = 1; decimalpoint[i]; ++i) - if (s[i] != decimalpoint[i]) - goto dig_done; - s += i; - c = *s; -#else - if (c == '.') { - c = *++s; -#endif - decpt = 1; - if (!nd) { - for(; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for(; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - for(i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = 10*y + c; - else if (nd <= DBL_DIG + 1) - z = 10*z + c; - nz = 0; - } - } - }/*}*/ - dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - goto ret0; - } - s00 = s; - esign = 0; - switch(c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while(c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while((c = *++s) >= '0' && c <= '9') - L = 10*L + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = (int)L; - if (esign) - e = -e; - } - else - e = 0; - } - else - s = s00; - } - if (!nd) { - if (!nz && !nz0) { -#ifdef INFNAN_CHECK - /* Check for Nan and Infinity */ - ULong bits[2]; - static FPI fpinan = /* only 52 explicit bits */ - { 52, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - if (!decpt) - switch(c) { - case 'i': - case 'I': - if (match(&s,"nf")) { - --s; - if (!match(&s,"inity")) - ++s; - word0(&rv) = 0x7ff00000; - word1(&rv) = 0; - goto ret; - } - break; - case 'n': - case 'N': - if (match(&s, "an")) { -#ifndef No_Hex_NaN - if (*s == '(' /*)*/ - && hexnan(&s, &fpinan, bits) - == STRTOG_NaNbits) { - word0(&rv) = 0x7ff00000 | bits[1]; - word1(&rv) = bits[0]; - } - else { -#endif - word0(&rv) = NAN_WORD0; - word1(&rv) = NAN_WORD1; -#ifndef No_Hex_NaN - } -#endif - goto ret; - } - } -#endif /* INFNAN_CHECK */ - ret0: - s = s00; - sign = 0; - } - goto ret; - } - e1 = e -= nf; - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - dval(&rv) = y; - if (k > 9) { -#ifdef SET_INEXACT - if (k > DBL_DIG) - oldinexact = get_inexact(); -#endif - dval(&rv) = tens[k - 9] * dval(&rv) + z; - } - bd0 = 0; - if (nd <= DBL_DIG -#ifndef RND_PRODQUOT -#ifndef Honor_FLT_ROUNDS - && Flt_Rounds == 1 -#endif -#endif - ) { - if (!e) - goto ret; -#ifndef ROUND_BIASED_without_Round_Up - if (e > 0) { - if (e <= Ten_pmax) { -#ifdef VAX - goto vax_ovfl_check; -#else -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - /* rv = */ rounded_product(dval(&rv), tens[e]); - goto ret; -#endif - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - e -= i; - dval(&rv) *= tens[i]; -#ifdef VAX - /* VAX exponent range is so narrow we must - * worry about overflow here... - */ - vax_ovfl_check: - word0(&rv) -= P*Exp_msk1; - /* rv = */ rounded_product(dval(&rv), tens[e]); - if ((word0(&rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) - goto ovfl; - word0(&rv) += P*Exp_msk1; -#else - /* rv = */ rounded_product(dval(&rv), tens[e]); -#endif - goto ret; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - /* rv = */ rounded_quotient(dval(&rv), tens[-e]); - goto ret; - } -#endif -#endif /* ROUND_BIASED_without_Round_Up */ - } - e1 += nd - k; - -#ifdef IEEE_Arith -#ifdef SET_INEXACT - inexact = 1; - if (k <= DBL_DIG) - oldinexact = get_inexact(); -#endif -#ifdef Avoid_Underflow - scale = 0; -#endif -#ifdef Honor_FLT_ROUNDS - if (Rounding >= 2) { - if (sign) - Rounding = Rounding == 2 ? 0 : 2; - else - if (Rounding != 2) - Rounding = 0; - } -#endif -#endif /*IEEE_Arith*/ - - /* Get starting approximation = rv * 10**e1 */ - - if (e1 > 0) { - if ( (i = e1 & 15) !=0) - dval(&rv) *= tens[i]; - if (e1 &= ~15) { - if (e1 > DBL_MAX_10_EXP) { - ovfl: - /* Can't trust HUGE_VAL */ -#ifdef IEEE_Arith -#ifdef Honor_FLT_ROUNDS - switch(Rounding) { - case 0: /* toward 0 */ - case 3: /* toward -infinity */ - word0(&rv) = Big0; - word1(&rv) = Big1; - break; - default: - word0(&rv) = Exp_mask; - word1(&rv) = 0; - } -#else /*Honor_FLT_ROUNDS*/ - word0(&rv) = Exp_mask; - word1(&rv) = 0; -#endif /*Honor_FLT_ROUNDS*/ -#ifdef SET_INEXACT - /* set overflow bit */ - dval(&rv0) = 1e300; - dval(&rv0) *= dval(&rv0); -#endif -#else /*IEEE_Arith*/ - word0(&rv) = Big0; - word1(&rv) = Big1; -#endif /*IEEE_Arith*/ - range_err: - if (bd0) { - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); - } -#ifndef NO_ERRNO - errno = ERANGE; -#endif - goto ret; - } - e1 >>= 4; - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= bigtens[j]; - /* The last multiplication could overflow. */ - word0(&rv) -= P*Exp_msk1; - dval(&rv) *= bigtens[j]; - if ((z = word0(&rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-P)) - goto ovfl; - if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { - /* set to largest number */ - /* (Can't trust DBL_MAX) */ - word0(&rv) = Big0; - word1(&rv) = Big1; - } - else - word0(&rv) += P*Exp_msk1; - } - } - else if (e1 < 0) { - e1 = -e1; - if ( (i = e1 & 15) !=0) - dval(&rv) /= tens[i]; - if (e1 >>= 4) { - if (e1 >= 1 << n_bigtens) - goto undfl; -#ifdef Avoid_Underflow - if (e1 & Scale_Bit) - scale = 2*P; - for(j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - if (scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) - >> Exp_shift)) > 0) { - /* scaled rv is denormal; zap j low bits */ - if (j >= 32) { - word1(&rv) = 0; - if (j >= 53) - word0(&rv) = (P+2)*Exp_msk1; - else - word0(&rv) &= 0xffffffff << (j-32); - } - else - word1(&rv) &= 0xffffffff << j; - } -#else - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - /* The last multiplication could underflow. */ - dval(&rv0) = dval(&rv); - dval(&rv) *= tinytens[j]; - if (!dval(&rv)) { - dval(&rv) = 2.*dval(&rv0); - dval(&rv) *= tinytens[j]; -#endif - if (!dval(&rv)) { - undfl: - dval(&rv) = 0.; - goto range_err; - } -#ifndef Avoid_Underflow - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - /* The refinement below will clean - * this approximation up. - */ - } -#endif - } - } - - /* Now the hard part -- adjusting rv to the correct value.*/ - - /* Put digits into bd: true value = bd * 10^e */ - - bd0 = s2b(s0, nd0, nd, y, dplen); - - for(;;) { - bd = Balloc(bd0->k); - Bcopy(bd, bd0); - bb = d2b(dval(&rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ - bs = i2b(1); - - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } - else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; -#ifdef Honor_FLT_ROUNDS - if (Rounding != 1) - bs2++; -#endif -#ifdef Avoid_Underflow - Lsb = LSB; - Lsb1 = 0; - j = bbe - scale; - i = j + bbbits - 1; /* logb(rv) */ - j = P + 1 - bbbits; - if (i < Emin) { /* denormal */ - i = Emin - i; - j -= i; - if (i < 32) - Lsb <<= i; - else - Lsb1 = Lsb << (i-32); - } -#else /*Avoid_Underflow*/ -#ifdef Sudden_Underflow -#ifdef IBM - j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); -#else - j = P + 1 - bbbits; -#endif -#else /*Sudden_Underflow*/ - j = bbe; - i = j + bbbits - 1; /* logb(&rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - bb2 += j; - bd2 += j; -#ifdef Avoid_Underflow - bd2 += scale; -#endif - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); - bb = bb1; - } - if (bb2 > 0) - bb = lshift(bb, bb2); - if (bd5 > 0) - bd = pow5mult(bd, bd5); - if (bd2 > 0) - bd = lshift(bd, bd2); - if (bs2 > 0) - bs = lshift(bs, bs2); - delta = diff(bb, bd); - dsign = delta->sign; - delta->sign = 0; - i = cmp(delta, bs); -#ifdef Honor_FLT_ROUNDS - if (Rounding != 1) { - if (i < 0) { - /* Error is less than an ulp */ - if (!delta->x[0] && delta->wds <= 1) { - /* exact */ -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - if (Rounding) { - if (dsign) { - dval(&adj) = 1.; - goto apply_adj; - } - } - else if (!dsign) { - dval(&adj) = -1.; - if (!word1(&rv) - && !(word0(&rv) & Frac_mask)) { - y = word0(&rv) & Exp_mask; -#ifdef Avoid_Underflow - if (!scale || y > 2*P*Exp_msk1) -#else - if (y) -#endif - { - delta = lshift(delta,Log2P); - if (cmp(delta, bs) <= 0) - dval(&adj) = -0.5; - } - } - apply_adj: -#ifdef Avoid_Underflow - if (scale && (y = word0(&rv) & Exp_mask) - <= 2*P*Exp_msk1) - word0(&adj) += (2*P+1)*Exp_msk1 - y; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= - P*Exp_msk1) { - word0(&rv) += P*Exp_msk1; - dval(&rv) += adj*ulp(&rv); - word0(&rv) -= P*Exp_msk1; - } - else -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - dval(&rv) += adj.d*ulp(&rv); - } - break; - } - dval(&adj) = ratio(delta, bs); - if (adj.d < 1.) - dval(&adj) = 1.; - if (adj.d <= 0x7ffffffe) { - /* dval(&adj) = Rounding ? ceil(&adj) : floor(&adj); */ - y = adj.d; - if (y != adj.d) { - if (!((Rounding>>1) ^ dsign)) - y++; - dval(&adj) = y; - } - } -#ifdef Avoid_Underflow - if (scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) - word0(&adj) += (2*P+1)*Exp_msk1 - y; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { - word0(&rv) += P*Exp_msk1; - dval(&adj) *= ulp(&rv); - if (dsign) - dval(&rv) += adj; - else - dval(&rv) -= adj; - word0(&rv) -= P*Exp_msk1; - goto cont; - } -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - dval(&adj) *= ulp(&rv); - if (dsign) { - if (word0(&rv) == Big0 && word1(&rv) == Big1) - goto ovfl; - dval(&rv) += adj.d; - } - else - dval(&rv) -= adj.d; - goto cont; - } -#endif /*Honor_FLT_ROUNDS*/ - - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - if (dsign || word1(&rv) || word0(&rv) & Bndry_mask -#ifdef IEEE_Arith -#ifdef Avoid_Underflow - || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 -#else - || (word0(&rv) & Exp_mask) <= Exp_msk1 -#endif -#endif - ) { -#ifdef SET_INEXACT - if (!delta->x[0] && delta->wds <= 1) - inexact = 0; -#endif - break; - } - if (!delta->x[0] && delta->wds <= 1) { - /* exact result */ -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - delta = lshift(delta,Log2P); - if (cmp(delta, bs) > 0) - goto drop_down; - break; - } - if (i == 0) { - /* exactly half-way between */ - if (dsign) { - if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 - && word1(&rv) == ( -#ifdef Avoid_Underflow - (scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) - ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : -#endif - 0xffffffff)) { - /*boundary case -- increment exponent*/ - if (word0(&rv) == Big0 && word1(&rv) == Big1) - goto ovfl; - word0(&rv) = (word0(&rv) & Exp_mask) - + Exp_msk1 -#ifdef IBM - | Exp_msk1 >> 4 -#endif - ; - word1(&rv) = 0; -#ifdef Avoid_Underflow - dsign = 0; -#endif - break; - } - } - else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { - drop_down: - /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow /*{{*/ - L = word0(&rv) & Exp_mask; -#ifdef IBM - if (L < Exp_msk1) -#else -#ifdef Avoid_Underflow - if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) -#else - if (L <= Exp_msk1) -#endif /*Avoid_Underflow*/ -#endif /*IBM*/ - goto undfl; - L -= Exp_msk1; -#else /*Sudden_Underflow}{*/ -#ifdef Avoid_Underflow - if (scale) { - L = word0(&rv) & Exp_mask; - if (L <= (2*P+1)*Exp_msk1) { - if (L > (P+2)*Exp_msk1) - /* round even ==> */ - /* accept rv */ - break; - /* rv = smallest denormal */ - goto undfl; - } - } -#endif /*Avoid_Underflow*/ - L = (word0(&rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}}*/ - word0(&rv) = L | Bndry_mask1; - word1(&rv) = 0xffffffff; -#ifdef IBM - goto cont; -#else - break; -#endif - } -#ifndef ROUND_BIASED -#ifdef Avoid_Underflow - if (Lsb1) { - if (!(word0(&rv) & Lsb1)) - break; - } - else if (!(word1(&rv) & Lsb)) - break; -#else - if (!(word1(&rv) & LSB)) - break; -#endif -#endif - if (dsign) -#ifdef Avoid_Underflow - dval(&rv) += sulp(&rv, scale); -#else - dval(&rv) += ulp(&rv); -#endif -#ifndef ROUND_BIASED - else { -#ifdef Avoid_Underflow - dval(&rv) -= sulp(&rv, scale); -#else - dval(&rv) -= ulp(&rv); -#endif -#ifndef Sudden_Underflow - if (!dval(&rv)) - goto undfl; -#endif - } -#ifdef Avoid_Underflow - dsign = 1 - dsign; -#endif -#endif - break; - } - if ((aadj = ratio(delta, bs)) <= 2.) { - if (dsign) - aadj = dval(&aadj1) = 1.; - else if (word1(&rv) || word0(&rv) & Bndry_mask) { -#ifndef Sudden_Underflow - if (word1(&rv) == Tiny1 && !word0(&rv)) - goto undfl; -#endif - aadj = 1.; - dval(&aadj1) = -1.; - } - else { - /* special case -- power of FLT_RADIX to be */ - /* rounded down... */ - - if (aadj < 2./FLT_RADIX) - aadj = 1./FLT_RADIX; - else - aadj *= 0.5; - dval(&aadj1) = -aadj; - } - } - else { - aadj *= 0.5; - dval(&aadj1) = dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch(Rounding) { - case 2: /* towards +infinity */ - dval(&aadj1) -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - dval(&aadj1) += 0.5; - } -#else - if (Flt_Rounds == 0) - dval(&aadj1) += 0.5; -#endif /*Check_FLT_ROUNDS*/ - } - y = word0(&rv) & Exp_mask; - - /* Check for overflow */ - - if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { - dval(&rv0) = dval(&rv); - word0(&rv) -= P*Exp_msk1; - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += dval(&adj); - if ((word0(&rv) & Exp_mask) >= - Exp_msk1*(DBL_MAX_EXP+Bias-P)) { - if (word0(&rv0) == Big0 && word1(&rv0) == Big1) - goto ovfl; - word0(&rv) = Big0; - word1(&rv) = Big1; - goto cont; - } - else - word0(&rv) += P*Exp_msk1; - } - else { -#ifdef Avoid_Underflow - if (scale && y <= 2*P*Exp_msk1) { - if (aadj <= 0x7fffffff) { - if ((z = (ULong)aadj) <= 0) - z = 1; - aadj = z; - dval(&aadj1) = dsign ? aadj : -aadj; - } - word0(&aadj1) += (2*P+1)*Exp_msk1 - y; - } - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += dval(&adj); -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { - dval(&rv0) = dval(&rv); - word0(&rv) += P*Exp_msk1; - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += adj; -#ifdef IBM - if ((word0(&rv) & Exp_mask) < P*Exp_msk1) -#else - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) -#endif - { - if (word0(&rv0) == Tiny0 - && word1(&rv0) == Tiny1) - goto undfl; - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - goto cont; - } - else - word0(&rv) -= P*Exp_msk1; - } - else { - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += adj; - } -#else /*Sudden_Underflow*/ - /* Compute dval(&adj) so that the IEEE rounding rules will - * correctly round rv + dval(&adj) in some half-way cases. - * If rv * ulp(&rv) is denormalized (i.e., - * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P-1)*Exp_msk1 && aadj > 1.) { - dval(&aadj1) = (double)(int)(aadj + 0.5); - if (!dsign) - dval(&aadj1) = -dval(&aadj1); - } - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += adj; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - } - z = word0(&rv) & Exp_mask; -#ifndef SET_INEXACT -#ifdef Avoid_Underflow - if (!scale) -#endif - if (y == z) { - /* Can we stop now? */ - L = (Long)aadj; - aadj -= L; - /* The tolerances below are conservative. */ - if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) { - if (aadj < .4999999 || aadj > .5000001) - break; - } - else if (aadj < .4999999/FLT_RADIX) - break; - } -#endif - cont: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); - } - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&rv0) = Exp_1 + (70 << Exp_shift); - word1(&rv0) = 0; - dval(&rv0) += 1.; - } - } - else if (!oldinexact) - clear_inexact(); -#endif -#ifdef Avoid_Underflow - if (scale) { - word0(&rv0) = Exp_1 - 2*P*Exp_msk1; - word1(&rv0) = 0; - dval(&rv) *= dval(&rv0); -#ifndef NO_ERRNO - /* try to avoid the bug of testing an 8087 register value */ -#ifdef IEEE_Arith - if (!(word0(&rv) & Exp_mask)) -#else - if (word0(&rv) == 0 && word1(&rv) == 0) -#endif - errno = ERANGE; -#endif - } -#endif /* Avoid_Underflow */ -#ifdef SET_INEXACT - if (inexact && !(word0(&rv) & Exp_mask)) { - /* set underflow bit */ - dval(&rv0) = 1e-300; - dval(&rv0) *= dval(&rv0); - } -#endif - ret: - if (se) - *se = (char *)s; - return sign ? -dval(&rv) : dval(&rv); - } - diff --git a/libraries/gdtoa/strtodI.c b/libraries/gdtoa/strtodI.c deleted file mode 100644 index 0b7b8a45c09..00000000000 --- a/libraries/gdtoa/strtodI.c +++ /dev/null @@ -1,163 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - static double -#ifdef KR_headers -ulpdown(d) U *d; -#else -ulpdown(U *d) -#endif -{ - double u; - ULong *L = d->L; - - u = ulp(d); - if (!(L[_1] | (L[_0] & 0xfffff)) - && (L[_0] & 0x7ff00000) > 0x00100000) - u *= 0.5; - return u; - } - - int -#ifdef KR_headers -strtodI(s, sp, dd) CONST char *s; char **sp; double *dd; -#else -strtodI(CONST char *s, char **sp, double *dd) -#endif -{ - static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - ULong bits[2], sign; - Long exp; - int j, k; - U *u; - - k = strtodg(s, sp, &fpi, &exp, bits); - u = (U*)dd; - sign = k & STRTOG_Neg ? 0x80000000L : 0; - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - dval(&u[0]) = dval(&u[1]) = 0.; - break; - - case STRTOG_Zero: - dval(&u[0]) = dval(&u[1]) = 0.; -#ifdef Sudden_Underflow - if (k & STRTOG_Inexact) { - if (sign) - word0(&u[0]) = 0x80100000L; - else - word0(&u[1]) = 0x100000L; - } - break; -#else - goto contain; -#endif - - case STRTOG_Denormal: - word1(&u[0]) = bits[0]; - word0(&u[0]) = bits[1]; - goto contain; - - case STRTOG_Normal: - word1(&u[0]) = bits[0]; - word0(&u[0]) = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20); - contain: - j = k & STRTOG_Inexact; - if (sign) { - word0(&u[0]) |= sign; - j = STRTOG_Inexact - j; - } - switch(j) { - case STRTOG_Inexlo: -#ifdef Sudden_Underflow - if ((u->L[_0] & 0x7ff00000) < 0x3500000) { - word0(&u[1]) = word0(&u[0]) + 0x3500000; - word1(&u[1]) = word1(&u[0]); - dval(&u[1]) += ulp(&u[1]); - word0(&u[1]) -= 0x3500000; - if (!(word0(&u[1]) & 0x7ff00000)) { - word0(&u[1]) = sign; - word1(&u[1]) = 0; - } - } - else -#endif - dval(&u[1]) = dval(&u[0]) + ulp(&u[0]); - break; - case STRTOG_Inexhi: - dval(&u[1]) = dval(&u[0]); -#ifdef Sudden_Underflow - if ((word0(&u[0]) & 0x7ff00000) < 0x3500000) { - word0(&u[0]) += 0x3500000; - dval(&u[0]) -= ulpdown(u); - word0(&u[0]) -= 0x3500000; - if (!(word0(&u[0]) & 0x7ff00000)) { - word0(&u[0]) = sign; - word1(&u[0]) = 0; - } - } - else -#endif - dval(&u[0]) -= ulpdown(u); - break; - default: - dval(&u[1]) = dval(&u[0]); - } - break; - - case STRTOG_Infinite: - word0(&u[0]) = word0(&u[1]) = sign | 0x7ff00000; - word1(&u[0]) = word1(&u[1]) = 0; - if (k & STRTOG_Inexact) { - if (sign) { - word0(&u[1]) = 0xffefffffL; - word1(&u[1]) = 0xffffffffL; - } - else { - word0(&u[0]) = 0x7fefffffL; - word1(&u[0]) = 0xffffffffL; - } - } - break; - - case STRTOG_NaN: - u->L[0] = (u+1)->L[0] = d_QNAN0; - u->L[1] = (u+1)->L[1] = d_QNAN1; - break; - - case STRTOG_NaNbits: - word0(&u[0]) = word0(&u[1]) = 0x7ff00000 | sign | bits[1]; - word1(&u[0]) = word1(&u[1]) = bits[0]; - } - return k; - } diff --git a/libraries/gdtoa/strtodg.c b/libraries/gdtoa/strtodg.c deleted file mode 100644 index c2e3365c785..00000000000 --- a/libraries/gdtoa/strtodg.c +++ /dev/null @@ -1,1065 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998-2001 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#ifdef USE_LOCALE -#include "locale.h" -#endif - - static CONST int -fivesbits[] = { 0, 3, 5, 7, 10, 12, 14, 17, 19, 21, - 24, 26, 28, 31, 33, 35, 38, 40, 42, 45, - 47, 49, 52 -#ifdef VAX - , 54, 56 -#endif - }; - - Bigint * -#ifdef KR_headers -increment(b) Bigint *b; -#else -increment(Bigint *b) -#endif -{ - ULong *x, *xe; - Bigint *b1; -#ifdef Pack_16 - ULong carry = 1, y; -#endif - - x = b->x; - xe = x + b->wds; -#ifdef Pack_32 - do { - if (*x < (ULong)0xffffffffL) { - ++*x; - return b; - } - *x++ = 0; - } while(x < xe); -#else - do { - y = *x + carry; - carry = y >> 16; - *x++ = y & 0xffff; - if (!carry) - return b; - } while(x < xe); - if (carry) -#endif - { - if (b->wds >= b->maxwds) { - b1 = Balloc(b->k+1); - Bcopy(b1,b); - Bfree(b); - b = b1; - } - b->x[b->wds++] = 1; - } - return b; - } - - void -#ifdef KR_headers -decrement(b) Bigint *b; -#else -decrement(Bigint *b) -#endif -{ - ULong *x, *xe; -#ifdef Pack_16 - ULong borrow = 1, y; -#endif - - x = b->x; - xe = x + b->wds; -#ifdef Pack_32 - do { - if (*x) { - --*x; - break; - } - *x++ = 0xffffffffL; - } - while(x < xe); -#else - do { - y = *x - borrow; - borrow = (y & 0x10000) >> 16; - *x++ = y & 0xffff; - } while(borrow && x < xe); -#endif - } - - static int -#ifdef KR_headers -all_on(b, n) Bigint *b; int n; -#else -all_on(Bigint *b, int n) -#endif -{ - ULong *x, *xe; - - x = b->x; - xe = x + (n >> kshift); - while(x < xe) - if ((*x++ & ALL_ON) != ALL_ON) - return 0; - if (n &= kmask) - return ((*x | (ALL_ON << n)) & ALL_ON) == ALL_ON; - return 1; - } - - Bigint * -#ifdef KR_headers -set_ones(b, n) Bigint *b; int n; -#else -set_ones(Bigint *b, int n) -#endif -{ - int k; - ULong *x, *xe; - - k = (n + ((1 << kshift) - 1)) >> kshift; - if (b->k < k) { - Bfree(b); - b = Balloc(k); - } - k = n >> kshift; - if (n &= kmask) - k++; - b->wds = k; - x = b->x; - xe = x + k; - while(x < xe) - *x++ = ALL_ON; - if (n) - x[-1] >>= ULbits - n; - return b; - } - - static int -rvOK -#ifdef KR_headers - (d, fpi, exp, bits, exact, rd, irv) - U *d; FPI *fpi; Long *exp; ULong *bits; int exact, rd, *irv; -#else - (U *d, FPI *fpi, Long *exp, ULong *bits, int exact, int rd, int *irv) -#endif -{ - Bigint *b; - ULong carry, inex, lostbits; - int bdif, e, j, k, k1, nb, rv; - - carry = rv = 0; - b = d2b(dval(d), &e, &bdif); - bdif -= nb = fpi->nbits; - e += bdif; - if (bdif <= 0) { - if (exact) - goto trunc; - goto ret; - } - if (P == nb) { - if ( -#ifndef IMPRECISE_INEXACT - exact && -#endif - fpi->rounding == -#ifdef RND_PRODQUOT - FPI_Round_near -#else - Flt_Rounds -#endif - ) goto trunc; - goto ret; - } - switch(rd) { - case 1: /* round down (toward -Infinity) */ - goto trunc; - case 2: /* round up (toward +Infinity) */ - break; - default: /* round near */ - k = bdif - 1; - if (k < 0) - goto trunc; - if (!k) { - if (!exact) - goto ret; - if (b->x[0] & 2) - break; - goto trunc; - } - if (b->x[k>>kshift] & ((ULong)1 << (k & kmask))) - break; - goto trunc; - } - /* "break" cases: round up 1 bit, then truncate; bdif > 0 */ - carry = 1; - trunc: - inex = lostbits = 0; - if (bdif > 0) { - if ( (lostbits = any_on(b, bdif)) !=0) - inex = STRTOG_Inexlo; - rshift(b, bdif); - if (carry) { - inex = STRTOG_Inexhi; - b = increment(b); - if ( (j = nb & kmask) !=0) - j = ULbits - j; - if (hi0bits(b->x[b->wds - 1]) != j) { - if (!lostbits) - lostbits = b->x[0] & 1; - rshift(b, 1); - e++; - } - } - } - else if (bdif < 0) - b = lshift(b, -bdif); - if (e < fpi->emin) { - k = fpi->emin - e; - e = fpi->emin; - if (k > nb || fpi->sudden_underflow) { - b->wds = inex = 0; - *irv = STRTOG_Underflow | STRTOG_Inexlo; - } - else { - k1 = k - 1; - if (k1 > 0 && !lostbits) - lostbits = any_on(b, k1); - if (!lostbits && !exact) - goto ret; - lostbits |= - carry = b->x[k1>>kshift] & (1 << (k1 & kmask)); - rshift(b, k); - *irv = STRTOG_Denormal; - if (carry) { - b = increment(b); - inex = STRTOG_Inexhi | STRTOG_Underflow; - } - else if (lostbits) - inex = STRTOG_Inexlo | STRTOG_Underflow; - } - } - else if (e > fpi->emax) { - e = fpi->emax + 1; - *irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - b->wds = inex = 0; - } - *exp = e; - copybits(bits, nb, b); - *irv |= inex; - rv = 1; - ret: - Bfree(b); - return rv; - } - - static int -#ifdef KR_headers -mantbits(d) U *d; -#else -mantbits(U *d) -#endif -{ - ULong L; -#ifdef VAX - L = word1(d) << 16 | word1(d) >> 16; - if (L) -#else - if ( (L = word1(d)) !=0) -#endif - return P - lo0bits(&L); -#ifdef VAX - L = word0(d) << 16 | word0(d) >> 16 | Exp_msk11; -#else - L = word0(d) | Exp_msk1; -#endif - return P - 32 - lo0bits(&L); - } - - int -strtodg -#ifdef KR_headers - (s00, se, fpi, exp, bits) - CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits; -#else - (CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits) -#endif -{ - int abe, abits, asub; - int bb0, bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, denorm; - int dsign, e, e1, e2, emin, esign, finished, i, inex, irv; - int j, k, nbits, nd, nd0, nf, nz, nz0, rd, rvbits, rve, rve1, sign; - int sudden_underflow; - CONST char *s, *s0, *s1; - double adj0, tol; - Long L; - U adj, rv; - ULong *b, *be, y, z; - Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0; -#ifdef USE_LOCALE /*{{*/ -#ifdef NO_LOCALE_CACHE - char *decimalpoint = localeconv()->decimal_point; - int dplen = strlen(decimalpoint); -#else - char *decimalpoint; - static char *decimalpoint_cache; - static int dplen; - if (!(s0 = decimalpoint_cache)) { - s0 = localeconv()->decimal_point; - if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { - strcpy(decimalpoint_cache, s0); - s0 = decimalpoint_cache; - } - dplen = strlen(s0); - } - decimalpoint = (char*)s0; -#endif /*NO_LOCALE_CACHE*/ -#else /*USE_LOCALE}{*/ -#define dplen 1 -#endif /*USE_LOCALE}}*/ - - irv = STRTOG_Zero; - denorm = sign = nz0 = nz = 0; - dval(&rv) = 0.; - rvb = 0; - nbits = fpi->nbits; - for(s = s00;;s++) switch(*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) - goto break2; - /* no break */ - case 0: - sign = 0; - irv = STRTOG_NoNumber; - s = s00; - goto ret; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: - goto break2; - } - break2: - if (*s == '0') { -#ifndef NO_HEX_FP - switch(s[1]) { - case 'x': - case 'X': - irv = gethex(&s, fpi, exp, &rvb, sign); - if (irv == STRTOG_NoNumber) { - s = s00; - sign = 0; - } - goto ret; - } -#endif - nz0 = 1; - while(*++s == '0') ; - if (!*s) - goto ret; - } - sudden_underflow = fpi->sudden_underflow; - s0 = s; - y = z = 0; - for(decpt = nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10*y + c - '0'; - else if (nd < 16) - z = 10*z + c - '0'; - nd0 = nd; -#ifdef USE_LOCALE - if (c == *decimalpoint) { - for(i = 1; decimalpoint[i]; ++i) - if (s[i] != decimalpoint[i]) - goto dig_done; - s += i; - c = *s; -#else - if (c == '.') { - c = *++s; -#endif - decpt = 1; - if (!nd) { - for(; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for(; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - for(i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = 10*y + c; - else if (nd <= DBL_DIG + 1) - z = 10*z + c; - nz = 0; - } - } - }/*}*/ - dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - irv = STRTOG_NoNumber; - s = s00; - goto ret; - } - s00 = s; - esign = 0; - switch(c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while(c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while((c = *++s) >= '0' && c <= '9') - L = 10*L + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = (int)L; - if (esign) - e = -e; - } - else - e = 0; - } - else - s = s00; - } - if (!nd) { - if (!nz && !nz0) { -#ifdef INFNAN_CHECK - /* Check for Nan and Infinity */ - if (!decpt) - switch(c) { - case 'i': - case 'I': - if (match(&s,"nf")) { - --s; - if (!match(&s,"inity")) - ++s; - irv = STRTOG_Infinite; - goto infnanexp; - } - break; - case 'n': - case 'N': - if (match(&s, "an")) { - irv = STRTOG_NaN; - *exp = fpi->emax + 1; -#ifndef No_Hex_NaN - if (*s == '(') /*)*/ - irv = hexnan(&s, fpi, bits); -#endif - goto infnanexp; - } - } -#endif /* INFNAN_CHECK */ - irv = STRTOG_NoNumber; - s = s00; - } - goto ret; - } - - irv = STRTOG_Normal; - e1 = e -= nf; - rd = 0; - switch(fpi->rounding & 3) { - case FPI_Round_up: - rd = 2 - sign; - break; - case FPI_Round_zero: - rd = 1; - break; - case FPI_Round_down: - rd = 1 + sign; - } - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - dval(&rv) = y; - if (k > 9) - dval(&rv) = tens[k - 9] * dval(&rv) + z; - bd0 = 0; - if (nbits <= P && nd <= DBL_DIG) { - if (!e) { - if (rvOK(&rv, fpi, exp, bits, 1, rd, &irv)) - goto ret; - } - else if (e > 0) { - if (e <= Ten_pmax) { -#ifdef VAX - goto vax_ovfl_check; -#else - i = fivesbits[e] + mantbits(&rv) <= P; - /* rv = */ rounded_product(dval(&rv), tens[e]); - if (rvOK(&rv, fpi, exp, bits, i, rd, &irv)) - goto ret; - e1 -= e; - goto rv_notOK; -#endif - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ - e2 = e - i; - e1 -= i; - dval(&rv) *= tens[i]; -#ifdef VAX - /* VAX exponent range is so narrow we must - * worry about overflow here... - */ - vax_ovfl_check: - dval(&adj) = dval(&rv); - word0(&adj) -= P*Exp_msk1; - /* adj = */ rounded_product(dval(&adj), tens[e2]); - if ((word0(&adj) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) - goto rv_notOK; - word0(&adj) += P*Exp_msk1; - dval(&rv) = dval(&adj); -#else - /* rv = */ rounded_product(dval(&rv), tens[e2]); -#endif - if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv)) - goto ret; - e1 -= e2; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { - /* rv = */ rounded_quotient(dval(&rv), tens[-e]); - if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv)) - goto ret; - e1 -= e; - } -#endif - } - rv_notOK: - e1 += nd - k; - - /* Get starting approximation = rv * 10**e1 */ - - e2 = 0; - if (e1 > 0) { - if ( (i = e1 & 15) !=0) - dval(&rv) *= tens[i]; - if (e1 &= ~15) { - e1 >>= 4; - while(e1 >= (1 << (n_bigtens-1))) { - e2 += ((word0(&rv) & Exp_mask) - >> Exp_shift1) - Bias; - word0(&rv) &= ~Exp_mask; - word0(&rv) |= Bias << Exp_shift1; - dval(&rv) *= bigtens[n_bigtens-1]; - e1 -= 1 << (n_bigtens-1); - } - e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias; - word0(&rv) &= ~Exp_mask; - word0(&rv) |= Bias << Exp_shift1; - for(j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= bigtens[j]; - } - } - else if (e1 < 0) { - e1 = -e1; - if ( (i = e1 & 15) !=0) - dval(&rv) /= tens[i]; - if (e1 &= ~15) { - e1 >>= 4; - while(e1 >= (1 << (n_bigtens-1))) { - e2 += ((word0(&rv) & Exp_mask) - >> Exp_shift1) - Bias; - word0(&rv) &= ~Exp_mask; - word0(&rv) |= Bias << Exp_shift1; - dval(&rv) *= tinytens[n_bigtens-1]; - e1 -= 1 << (n_bigtens-1); - } - e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias; - word0(&rv) &= ~Exp_mask; - word0(&rv) |= Bias << Exp_shift1; - for(j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - } - } -#ifdef IBM - /* e2 is a correction to the (base 2) exponent of the return - * value, reflecting adjustments above to avoid overflow in the - * native arithmetic. For native IBM (base 16) arithmetic, we - * must multiply e2 by 4 to change from base 16 to 2. - */ - e2 <<= 2; -#endif - rvb = d2b(dval(&rv), &rve, &rvbits); /* rv = rvb * 2^rve */ - rve += e2; - if ((j = rvbits - nbits) > 0) { - rshift(rvb, j); - rvbits = nbits; - rve += j; - } - bb0 = 0; /* trailing zero bits in rvb */ - e2 = rve + rvbits - nbits; - if (e2 > fpi->emax + 1) - goto huge; - rve1 = rve + rvbits - nbits; - if (e2 < (emin = fpi->emin)) { - denorm = 1; - j = rve - emin; - if (j > 0) { - rvb = lshift(rvb, j); - rvbits += j; - } - else if (j < 0) { - rvbits += j; - if (rvbits <= 0) { - if (rvbits < -1) { - ufl: - rvb->wds = 0; - rvb->x[0] = 0; - *exp = emin; - irv = STRTOG_Underflow | STRTOG_Inexlo; - goto ret; - } - rvb->x[0] = rvb->wds = rvbits = 1; - } - else - rshift(rvb, -j); - } - rve = rve1 = emin; - if (sudden_underflow && e2 + 1 < emin) - goto ufl; - } - - /* Now the hard part -- adjusting rv to the correct value.*/ - - /* Put digits into bd: true value = bd * 10^e */ - - bd0 = s2b(s0, nd0, nd, y, dplen); - - for(;;) { - bd = Balloc(bd0->k); - Bcopy(bd, bd0); - bb = Balloc(rvb->k); - Bcopy(bb, rvb); - bbbits = rvbits - bb0; - bbe = rve + bb0; - bs = i2b(1); - - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } - else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; - j = nbits + 1 - bbbits; - i = bbe + bbbits - nbits; - if (i < emin) /* denormal */ - j += i - emin; - bb2 += j; - bd2 += j; - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); - bb = bb1; - } - bb2 -= bb0; - if (bb2 > 0) - bb = lshift(bb, bb2); - else if (bb2 < 0) - rshift(bb, -bb2); - if (bd5 > 0) - bd = pow5mult(bd, bd5); - if (bd2 > 0) - bd = lshift(bd, bd2); - if (bs2 > 0) - bs = lshift(bs, bs2); - asub = 1; - inex = STRTOG_Inexhi; - delta = diff(bb, bd); - if (delta->wds <= 1 && !delta->x[0]) - break; - dsign = delta->sign; - delta->sign = finished = 0; - L = 0; - i = cmp(delta, bs); - if (rd && i <= 0) { - irv = STRTOG_Normal; - if ( (finished = dsign ^ (rd&1)) !=0) { - if (dsign != 0) { - irv |= STRTOG_Inexhi; - goto adj1; - } - irv |= STRTOG_Inexlo; - if (rve1 == emin) - goto adj1; - for(i = 0, j = nbits; j >= ULbits; - i++, j -= ULbits) { - if (rvb->x[i] & ALL_ON) - goto adj1; - } - if (j > 1 && lo0bits(rvb->x + i) < j - 1) - goto adj1; - rve = rve1 - 1; - rvb = set_ones(rvb, rvbits = nbits); - break; - } - irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi; - break; - } - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - irv = dsign - ? STRTOG_Normal | STRTOG_Inexlo - : STRTOG_Normal | STRTOG_Inexhi; - if (dsign || bbbits > 1 || denorm || rve1 == emin) - break; - delta = lshift(delta,1); - if (cmp(delta, bs) > 0) { - irv = STRTOG_Normal | STRTOG_Inexlo; - goto drop_down; - } - break; - } - if (i == 0) { - /* exactly half-way between */ - if (dsign) { - if (denorm && all_on(rvb, rvbits)) { - /*boundary case -- increment exponent*/ - rvb->wds = 1; - rvb->x[0] = 1; - rve = emin + nbits - (rvbits = 1); - irv = STRTOG_Normal | STRTOG_Inexhi; - denorm = 0; - break; - } - irv = STRTOG_Normal | STRTOG_Inexlo; - } - else if (bbbits == 1) { - irv = STRTOG_Normal; - drop_down: - /* boundary case -- decrement exponent */ - if (rve1 == emin) { - irv = STRTOG_Normal | STRTOG_Inexhi; - if (rvb->wds == 1 && rvb->x[0] == 1) - sudden_underflow = 1; - break; - } - rve -= nbits; - rvb = set_ones(rvb, rvbits = nbits); - break; - } - else - irv = STRTOG_Normal | STRTOG_Inexhi; - if ((bbbits < nbits && !denorm) || !(rvb->x[0] & 1)) - break; - if (dsign) { - rvb = increment(rvb); - j = kmask & (ULbits - (rvbits & kmask)); - if (hi0bits(rvb->x[rvb->wds - 1]) != j) - rvbits++; - irv = STRTOG_Normal | STRTOG_Inexhi; - } - else { - if (bbbits == 1) - goto undfl; - decrement(rvb); - irv = STRTOG_Normal | STRTOG_Inexlo; - } - break; - } - if ((dval(&adj) = ratio(delta, bs)) <= 2.) { - adj1: - inex = STRTOG_Inexlo; - if (dsign) { - asub = 0; - inex = STRTOG_Inexhi; - } - else if (denorm && bbbits <= 1) { - undfl: - rvb->wds = 0; - rve = emin; - irv = STRTOG_Underflow | STRTOG_Inexlo; - break; - } - adj0 = dval(&adj) = 1.; - } - else { - adj0 = dval(&adj) *= 0.5; - if (dsign) { - asub = 0; - inex = STRTOG_Inexlo; - } - if (dval(&adj) < 2147483647.) { - L = (Long)adj0; - adj0 -= L; - switch(rd) { - case 0: - if (adj0 >= .5) - goto inc_L; - break; - case 1: - if (asub && adj0 > 0.) - goto inc_L; - break; - case 2: - if (!asub && adj0 > 0.) { - inc_L: - L++; - inex = STRTOG_Inexact - inex; - } - } - dval(&adj) = L; - } - } - y = rve + rvbits; - - /* adj *= ulp(dval(&rv)); */ - /* if (asub) rv -= adj; else rv += adj; */ - - if (!denorm && rvbits < nbits) { - rvb = lshift(rvb, j = nbits - rvbits); - rve -= j; - rvbits = nbits; - } - ab = d2b(dval(&adj), &abe, &abits); - if (abe < 0) - rshift(ab, -abe); - else if (abe > 0) - ab = lshift(ab, abe); - rvb0 = rvb; - if (asub) { - /* rv -= adj; */ - j = hi0bits(rvb->x[rvb->wds-1]); - rvb = diff(rvb, ab); - k = rvb0->wds - 1; - if (denorm) - /* do nothing */; - else if (rvb->wds <= k - || hi0bits( rvb->x[k]) > - hi0bits(rvb0->x[k])) { - /* unlikely; can only have lost 1 high bit */ - if (rve1 == emin) { - --rvbits; - denorm = 1; - } - else { - rvb = lshift(rvb, 1); - --rve; - --rve1; - L = finished = 0; - } - } - } - else { - rvb = sum(rvb, ab); - k = rvb->wds - 1; - if (k >= rvb0->wds - || hi0bits(rvb->x[k]) < hi0bits(rvb0->x[k])) { - if (denorm) { - if (++rvbits == nbits) - denorm = 0; - } - else { - rshift(rvb, 1); - rve++; - rve1++; - L = 0; - } - } - } - Bfree(ab); - Bfree(rvb0); - if (finished) - break; - - z = rve + rvbits; - if (y == z && L) { - /* Can we stop now? */ - tol = dval(&adj) * 5e-16; /* > max rel error */ - dval(&adj) = adj0 - .5; - if (dval(&adj) < -tol) { - if (adj0 > tol) { - irv |= inex; - break; - } - } - else if (dval(&adj) > tol && adj0 < 1. - tol) { - irv |= inex; - break; - } - } - bb0 = denorm ? 0 : trailz(rvb); - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); - } - if (!denorm && (j = nbits - rvbits)) { - if (j > 0) - rvb = lshift(rvb, j); - else - rshift(rvb, -j); - rve -= j; - } - *exp = rve; - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); - if (rve > fpi->emax) { - switch(fpi->rounding & 3) { - case FPI_Round_near: - goto huge; - case FPI_Round_up: - if (!sign) - goto huge; - break; - case FPI_Round_down: - if (sign) - goto huge; - } - /* Round to largest representable magnitude */ - Bfree(rvb); - rvb = 0; - irv = STRTOG_Normal | STRTOG_Inexlo; - *exp = fpi->emax; - b = bits; - be = b + ((fpi->nbits + 31) >> 5); - while(b < be) - *b++ = -1; - if ((j = fpi->nbits & 0x1f)) - *--be >>= (32 - j); - goto ret; - huge: - rvb->wds = 0; - irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - infnanexp: - *exp = fpi->emax + 1; - } - ret: - if (denorm) { - if (sudden_underflow) { - rvb->wds = 0; - irv = STRTOG_Underflow | STRTOG_Inexlo; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - } - else { - irv = (irv & ~STRTOG_Retmask) | - (rvb->wds > 0 ? STRTOG_Denormal : STRTOG_Zero); - if (irv & STRTOG_Inexact) { - irv |= STRTOG_Underflow; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - } - } - } - if (se) - *se = (char *)s; - if (sign) - irv |= STRTOG_Neg; - if (rvb) { - copybits(bits, nbits, rvb); - Bfree(rvb); - } - return irv; - } diff --git a/libraries/gdtoa/strtodnrp.c b/libraries/gdtoa/strtodnrp.c deleted file mode 100644 index 19a769f0b43..00000000000 --- a/libraries/gdtoa/strtodnrp.c +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 2004 by David M. Gay. -All Rights Reserved -Based on material in the rest of /netlib/fp/gdota.tar.gz, -which is copyright (C) 1998, 2000 by Lucent Technologies. - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* This is a variant of strtod that works on Intel ia32 systems */ -/* with the default extended-precision arithmetic -- it does not */ -/* require setting the precision control to 53 bits. */ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - double -#ifdef KR_headers -strtod(s, sp) CONST char *s; char **sp; -#else -strtod(CONST char *s, char **sp) -#endif -{ - static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - ULong bits[2]; - Long exp; - int k; - union { ULong L[2]; double d; } u; - - k = strtodg(s, sp, &fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - u.L[0] = u.L[1] = 0; - break; - - case STRTOG_Normal: - u.L[_1] = bits[0]; - u.L[_0] = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20); - break; - - case STRTOG_Denormal: - u.L[_1] = bits[0]; - u.L[_0] = bits[1]; - break; - - case STRTOG_Infinite: - u.L[_0] = 0x7ff00000; - u.L[_1] = 0; - break; - - case STRTOG_NaN: - u.L[0] = d_QNAN0; - u.L[1] = d_QNAN1; - break; - - case STRTOG_NaNbits: - u.L[_0] = 0x7ff00000 | bits[1]; - u.L[_1] = bits[0]; - } - if (k & STRTOG_Neg) - u.L[_0] |= 0x80000000L; - return u.d; - } diff --git a/libraries/gdtoa/strtof.c b/libraries/gdtoa/strtof.c deleted file mode 100644 index a8beb3520a0..00000000000 --- a/libraries/gdtoa/strtof.c +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - float -#ifdef KR_headers -strtof(s, sp) CONST char *s; char **sp; -#else -strtof(CONST char *s, char **sp) -#endif -{ - static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI }; - ULong bits[1]; - Long exp; - int k; - union { ULong L[1]; float f; } u; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - u.L[0] = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - u.L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23); - break; - - case STRTOG_Denormal: - u.L[0] = bits[0]; - break; - - case STRTOG_Infinite: - u.L[0] = 0x7f800000; - break; - - case STRTOG_NaN: - u.L[0] = f_QNAN; - } - if (k & STRTOG_Neg) - u.L[0] |= 0x80000000L; - return u.f; - } diff --git a/libraries/gdtoa/strtopQ.c b/libraries/gdtoa/strtopQ.c deleted file mode 100644 index 2acf7e91073..00000000000 --- a/libraries/gdtoa/strtopQ.c +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#endif -#ifdef IEEE_8087 -#define _0 3 -#define _1 2 -#define _2 1 -#define _3 0 -#endif - - extern ULong NanDflt_Q_D2A[4]; - - - int -#ifdef KR_headers -strtopQ(s, sp, V) CONST char *s; char **sp; void *V; -#else -strtopQ(CONST char *s, char **sp, void *V) -#endif -{ - static FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, SI }; - ULong bits[4]; - Long exp; - int k; - ULong *L = (ULong*)V; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_3] = bits[0]; - L[_2] = bits[1]; - L[_1] = bits[2]; - L[_0] = (bits[3] & ~0x10000) | ((exp + 0x3fff + 112) << 16); - break; - - case STRTOG_Denormal: - L[_3] = bits[0]; - L[_2] = bits[1]; - L[_1] = bits[2]; - L[_0] = bits[3]; - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff0000; - L[_1] = L[_2] = L[_3] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_Q_D2A[3]; - L[_1] = NanDflt_Q_D2A[2]; - L[_2] = NanDflt_Q_D2A[1]; - L[_3] = NanDflt_Q_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - return k; - } diff --git a/libraries/gdtoa/strtopd.c b/libraries/gdtoa/strtopd.c deleted file mode 100644 index 0fb35daeaa5..00000000000 --- a/libraries/gdtoa/strtopd.c +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtopd(s, sp, d) char *s; char **sp; double *d; -#else -strtopd(CONST char *s, char **sp, double *d) -#endif -{ - static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - ULong bits[2]; - Long exp; - int k; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - ULtod((ULong*)d, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtopdd.c b/libraries/gdtoa/strtopdd.c deleted file mode 100644 index 738372d8829..00000000000 --- a/libraries/gdtoa/strtopdd.c +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtopdd(s, sp, dd) CONST char *s; char **sp; double *dd; -#else -strtopdd(CONST char *s, char **sp, double *dd) -#endif -{ -#ifdef Sudden_Underflow - static FPI fpi0 = { 106, 1-1023, 2046-1023-106+1, 1, 1 }; -#else - static FPI fpi0 = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0 }; -#endif - ULong bits[4]; - Long exp; - int i, j, rv; - typedef union { - double d[2]; - ULong L[4]; - } U; - U *u; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - rv = strtodg(s, sp, fpi, &exp, bits); - u = (U*)dd; - switch(rv & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - u->d[0] = u->d[1] = 0.; - break; - - case STRTOG_Normal: - u->L[_1] = (bits[1] >> 21 | bits[2] << 11) & 0xffffffffL; - u->L[_0] = (bits[2] >> 21) | ((bits[3] << 11) & 0xfffff) - | ((exp + 0x3ff + 105) << 20); - exp += 0x3ff + 52; - if (bits[1] &= 0x1fffff) { - i = hi0bits(bits[1]) - 11; - if (i >= exp) { - i = exp - 1; - exp = 0; - } - else - exp -= i; - if (i > 0) { - bits[1] = bits[1] << i | bits[0] >> (32-i); - bits[0] = bits[0] << i & 0xffffffffL; - } - } - else if (bits[0]) { - i = hi0bits(bits[0]) + 21; - if (i >= exp) { - i = exp - 1; - exp = 0; - } - else - exp -= i; - if (i < 32) { - bits[1] = bits[0] >> (32 - i); - bits[0] = bits[0] << i & 0xffffffffL; - } - else { - bits[1] = bits[0] << (i - 32); - bits[0] = 0; - } - } - else { - u->L[2] = u->L[3] = 0; - break; - } - u->L[2+_1] = bits[0]; - u->L[2+_0] = (bits[1] & 0xfffff) | (exp << 20); - break; - - case STRTOG_Denormal: - if (bits[3]) - goto nearly_normal; - if (bits[2]) - goto partly_normal; - if (bits[1] & 0xffe00000) - goto hardly_normal; - /* completely denormal */ - u->L[2] = u->L[3] = 0; - u->L[_1] = bits[0]; - u->L[_0] = bits[1]; - break; - - nearly_normal: - i = hi0bits(bits[3]) - 11; /* i >= 12 */ - j = 32 - i; - u->L[_0] = ((bits[3] << i | bits[2] >> j) & 0xfffff) - | ((65 - i) << 20); - u->L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL; - u->L[2+_0] = bits[1] & ((1L << j) - 1); - u->L[2+_1] = bits[0]; - break; - - partly_normal: - i = hi0bits(bits[2]) - 11; - if (i < 0) { - j = -i; - i += 32; - u->L[_0] = (bits[2] >> j & 0xfffff) | (33 + j) << 20; - u->L[_1] = ((bits[2] << i) | (bits[1] >> j)) & 0xffffffffL; - u->L[2+_0] = bits[1] & ((1L << j) - 1); - u->L[2+_1] = bits[0]; - break; - } - if (i == 0) { - u->L[_0] = (bits[2] & 0xfffff) | (33 << 20); - u->L[_1] = bits[1]; - u->L[2+_0] = 0; - u->L[2+_1] = bits[0]; - break; - } - j = 32 - i; - u->L[_0] = (((bits[2] << i) | (bits[1] >> j)) & 0xfffff) - | ((j + 1) << 20); - u->L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL; - u->L[2+_0] = 0; - u->L[2+_1] = bits[0] & ((1L << j) - 1); - break; - - hardly_normal: - j = 11 - hi0bits(bits[1]); - i = 32 - j; - u->L[_0] = (bits[1] >> j & 0xfffff) | ((j + 1) << 20); - u->L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL; - u->L[2+_0] = 0; - u->L[2+_1] = bits[0] & ((1L << j) - 1); - break; - - case STRTOG_Infinite: - u->L[_0] = u->L[2+_0] = 0x7ff00000; - u->L[_1] = u->L[2+_1] = 0; - break; - - case STRTOG_NaN: - u->L[0] = u->L[2] = d_QNAN0; - u->L[1] = u->L[3] = d_QNAN1; - } - if (rv & STRTOG_Neg) { - u->L[ _0] |= 0x80000000L; - u->L[2+_0] |= 0x80000000L; - } - return rv; - } diff --git a/libraries/gdtoa/strtopf.c b/libraries/gdtoa/strtopf.c deleted file mode 100644 index 23ca5cbe582..00000000000 --- a/libraries/gdtoa/strtopf.c +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtopf(s, sp, f) CONST char *s; char **sp; float *f; -#else -strtopf(CONST char *s, char **sp, float *f) -#endif -{ - static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI }; - ULong bits[1], *L; - Long exp; - int k; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - L = (ULong*)f; - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23); - break; - - case STRTOG_Denormal: - L[0] = bits[0]; - break; - - case STRTOG_Infinite: - L[0] = 0x7f800000; - break; - - case STRTOG_NaN: - L[0] = f_QNAN; - } - if (k & STRTOG_Neg) - L[0] |= 0x80000000L; - return k; - } diff --git a/libraries/gdtoa/strtopx.c b/libraries/gdtoa/strtopx.c deleted file mode 100644 index 32192c57260..00000000000 --- a/libraries/gdtoa/strtopx.c +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern UShort NanDflt_ldus_D2A[5]; - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#define _4 4 -#endif -#ifdef IEEE_8087 -#define _0 4 -#define _1 3 -#define _2 2 -#define _3 1 -#define _4 0 -#endif - - int -#ifdef KR_headers -strtopx(s, sp, V) CONST char *s; char **sp; void *V; -#else -strtopx(CONST char *s, char **sp, void *V) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - ULong bits[2]; - Long exp; - int k; - UShort *L = (UShort*)V; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = L[4] = 0; - break; - - case STRTOG_Denormal: - L[_0] = 0; - goto normal_bits; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_0] = exp + 0x3fff + 63; - normal_bits: - L[_4] = (UShort)bits[0]; - L[_3] = (UShort)(bits[0] >> 16); - L[_2] = (UShort)bits[1]; - L[_1] = (UShort)(bits[1] >> 16); - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff; - L[_1] = 0x8000; - L[_2] = L[_3] = L[_4] = 0; - break; - - case STRTOG_NaN: - L[_4] = NanDflt_ldus_D2A[0]; - L[_3] = NanDflt_ldus_D2A[1]; - L[_2] = NanDflt_ldus_D2A[2]; - L[_1] = NanDflt_ldus_D2A[3]; - L[_0] = NanDflt_ldus_D2A[4]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x8000; - return k; - } diff --git a/libraries/gdtoa/strtopxL.c b/libraries/gdtoa/strtopxL.c deleted file mode 100644 index 6166c1e6260..00000000000 --- a/libraries/gdtoa/strtopxL.c +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern ULong NanDflt_xL_D2A[3]; - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#endif -#ifdef IEEE_8087 -#define _0 2 -#define _1 1 -#define _2 0 -#endif - - int -#ifdef KR_headers -strtopxL(s, sp, V) CONST char *s; char **sp; void *V; -#else -strtopxL(CONST char *s, char **sp, void *V) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - ULong bits[2]; - Long exp; - int k; - ULong *L = (ULong*)V; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = 0; - break; - - case STRTOG_Normal: - case STRTOG_Denormal: - case STRTOG_NaNbits: - L[_2] = bits[0]; - L[_1] = bits[1]; - L[_0] = (exp + 0x3fff + 63) << 16; - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff << 16; - L[_1] = 0x80000000; - L[_2] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_xL_D2A[2]; - L[_1] = NanDflt_xL_D2A[1]; - L[_2] = NanDflt_xL_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - return k; - } diff --git a/libraries/gdtoa/strtorQ.c b/libraries/gdtoa/strtorQ.c deleted file mode 100644 index f5fd7bba946..00000000000 --- a/libraries/gdtoa/strtorQ.c +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#endif -#ifdef IEEE_8087 -#define _0 3 -#define _1 2 -#define _2 1 -#define _3 0 -#endif - - extern ULong NanDflt_Q_D2A[4]; - - void -#ifdef KR_headers -ULtoQ(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtoQ(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_3] = bits[0]; - L[_2] = bits[1]; - L[_1] = bits[2]; - L[_0] = (bits[3] & ~0x10000) | ((exp + 0x3fff + 112) << 16); - break; - - case STRTOG_Denormal: - L[_3] = bits[0]; - L[_2] = bits[1]; - L[_1] = bits[2]; - L[_0] = bits[3]; - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff0000; - L[_1] = L[_2] = L[_3] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_Q_D2A[3]; - L[_1] = NanDflt_Q_D2A[2]; - L[_2] = NanDflt_Q_D2A[1]; - L[_3] = NanDflt_Q_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - } - - int -#ifdef KR_headers -strtorQ(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L; -#else -strtorQ(CONST char *s, char **sp, int rounding, void *L) -#endif -{ - static FPI fpi0 = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[4]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtoQ((ULong*)L, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtord.c b/libraries/gdtoa/strtord.c deleted file mode 100644 index dd0769698c9..00000000000 --- a/libraries/gdtoa/strtord.c +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern ULong NanDflt_d_D2A[2]; - - void -#ifdef KR_headers -ULtod(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtod(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = 0; - break; - - case STRTOG_Denormal: - L[_1] = bits[0]; - L[_0] = bits[1]; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_1] = bits[0]; - L[_0] = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20); - break; - - case STRTOG_Infinite: - L[_0] = 0x7ff00000; - L[_1] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_d_D2A[1]; - L[_1] = NanDflt_d_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - } - - int -#ifdef KR_headers -strtord(s, sp, rounding, d) CONST char *s; char **sp; int rounding; double *d; -#else -strtord(CONST char *s, char **sp, int rounding, double *d) -#endif -{ - static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[2]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtod((ULong*)d, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtordd.c b/libraries/gdtoa/strtordd.c deleted file mode 100644 index 62152dbd43e..00000000000 --- a/libraries/gdtoa/strtordd.c +++ /dev/null @@ -1,202 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern ULong NanDflt_d_D2A[2]; - - void -#ifdef KR_headers -ULtodd(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtodd(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - int i, j; - - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = 0; - break; - - case STRTOG_Normal: - L[_1] = (bits[1] >> 21 | bits[2] << 11) & (ULong)0xffffffffL; - L[_0] = (bits[2] >> 21) | (bits[3] << 11 & 0xfffff) - | ((exp + 0x3ff + 105) << 20); - exp += 0x3ff + 52; - if (bits[1] &= 0x1fffff) { - i = hi0bits(bits[1]) - 11; - if (i >= exp) { - i = exp - 1; - exp = 0; - } - else - exp -= i; - if (i > 0) { - bits[1] = bits[1] << i | bits[0] >> (32-i); - bits[0] = bits[0] << i & (ULong)0xffffffffL; - } - } - else if (bits[0]) { - i = hi0bits(bits[0]) + 21; - if (i >= exp) { - i = exp - 1; - exp = 0; - } - else - exp -= i; - if (i < 32) { - bits[1] = bits[0] >> (32 - i); - bits[0] = bits[0] << i & (ULong)0xffffffffL; - } - else { - bits[1] = bits[0] << (i - 32); - bits[0] = 0; - } - } - else { - L[2] = L[3] = 0; - break; - } - L[2+_1] = bits[0]; - L[2+_0] = (bits[1] & 0xfffff) | (exp << 20); - break; - - case STRTOG_Denormal: - if (bits[3]) - goto nearly_normal; - if (bits[2]) - goto partly_normal; - if (bits[1] & 0xffe00000) - goto hardly_normal; - /* completely denormal */ - L[2] = L[3] = 0; - L[_1] = bits[0]; - L[_0] = bits[1]; - break; - - nearly_normal: - i = hi0bits(bits[3]) - 11; /* i >= 12 */ - j = 32 - i; - L[_0] = ((bits[3] << i | bits[2] >> j) & 0xfffff) - | ((65 - i) << 20); - L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL; - L[2+_0] = bits[1] & (((ULong)1L << j) - 1); - L[2+_1] = bits[0]; - break; - - partly_normal: - i = hi0bits(bits[2]) - 11; - if (i < 0) { - j = -i; - i += 32; - L[_0] = (bits[2] >> j & 0xfffff) | ((33 + j) << 20); - L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL; - L[2+_0] = bits[1] & (((ULong)1L << j) - 1); - L[2+_1] = bits[0]; - break; - } - if (i == 0) { - L[_0] = (bits[2] & 0xfffff) | (33 << 20); - L[_1] = bits[1]; - L[2+_0] = 0; - L[2+_1] = bits[0]; - break; - } - j = 32 - i; - L[_0] = (((bits[2] << i) | (bits[1] >> j)) & 0xfffff) - | ((j + 1) << 20); - L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL; - L[2+_0] = 0; - L[2+_1] = bits[0] & ((1L << j) - 1); - break; - - hardly_normal: - j = 11 - hi0bits(bits[1]); - i = 32 - j; - L[_0] = (bits[1] >> j & 0xfffff) | ((j + 1) << 20); - L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL; - L[2+_0] = 0; - L[2+_1] = bits[0] & (((ULong)1L << j) - 1); - break; - - case STRTOG_Infinite: - L[_0] = L[2+_0] = 0x7ff00000; - L[_1] = L[2+_1] = 0; - break; - - case STRTOG_NaN: - L[_0] = L[_0+2] = NanDflt_d_D2A[1]; - L[_1] = L[_1+2] = NanDflt_d_D2A[0]; - break; - - case STRTOG_NaNbits: - L[_1] = (bits[1] >> 20 | bits[2] << 12) & (ULong)0xffffffffL; - L[_0] = bits[2] >> 20 | bits[3] << 12; - L[_0] |= (L[_1] | L[_0]) ? (ULong)0x7ff00000L : (ULong)0x7ff80000L; - L[2+_1] = bits[0] & (ULong)0xffffffffL; - L[2+_0] = bits[1] & 0xfffffL; - L[2+_0] |= (L[2+_1] | L[2+_0]) ? (ULong)0x7ff00000L : (ULong)0x7ff80000L; - } - if (k & STRTOG_Neg) { - L[_0] |= 0x80000000L; - L[2+_0] |= 0x80000000L; - } - } - - int -#ifdef KR_headers -strtordd(s, sp, rounding, dd) CONST char *s; char **sp; int rounding; double *dd; -#else -strtordd(CONST char *s, char **sp, int rounding, double *dd) -#endif -{ -#ifdef Sudden_Underflow - static FPI fpi0 = { 106, 1-1023, 2046-1023-106+1, 1, 1 }; -#else - static FPI fpi0 = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0 }; -#endif - FPI *fpi, fpi1; - ULong bits[4]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtodd((ULong*)dd, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtorf.c b/libraries/gdtoa/strtorf.c deleted file mode 100644 index 99b4ab7107b..00000000000 --- a/libraries/gdtoa/strtorf.c +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern ULong NanDflt_f_D2A[1]; - - void -#ifdef KR_headers -ULtof(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtof(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - *L = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23); - break; - - case STRTOG_Denormal: - L[0] = bits[0]; - break; - - case STRTOG_Infinite: - L[0] = 0x7f800000; - break; - - case STRTOG_NaN: - L[0] = NanDflt_f_D2A[0]; - } - if (k & STRTOG_Neg) - L[0] |= 0x80000000L; - } - - int -#ifdef KR_headers -strtorf(s, sp, rounding, f) CONST char *s; char **sp; int rounding; float *f; -#else -strtorf(CONST char *s, char **sp, int rounding, float *f) -#endif -{ - static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[1]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtof((ULong*)f, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtorx.c b/libraries/gdtoa/strtorx.c deleted file mode 100644 index 994ce8e63f5..00000000000 --- a/libraries/gdtoa/strtorx.c +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#define _4 4 -#endif -#ifdef IEEE_8087 -#define _0 4 -#define _1 3 -#define _2 2 -#define _3 1 -#define _4 0 -#endif - - extern UShort NanDflt_ldus_D2A[5]; - - void -#ifdef KR_headers -ULtox(L, bits, exp, k) UShort *L; ULong *bits; Long exp; int k; -#else -ULtox(UShort *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = L[4] = 0; - break; - - case STRTOG_Denormal: - L[_0] = 0; - goto normal_bits; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_0] = exp + 0x3fff + 63; - normal_bits: - L[_4] = (UShort)bits[0]; - L[_3] = (UShort)(bits[0] >> 16); - L[_2] = (UShort)bits[1]; - L[_1] = (UShort)(bits[1] >> 16); - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff; - L[_1] = 0x8000; - L[_2] = L[_3] = L[_4] = 0; - break; - - case STRTOG_NaN: - L[_4] = NanDflt_ldus_D2A[0]; - L[_3] = NanDflt_ldus_D2A[1]; - L[_2] = NanDflt_ldus_D2A[2]; - L[_1] = NanDflt_ldus_D2A[3]; - L[_0] = NanDflt_ldus_D2A[4]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x8000; - } - - int -#ifdef KR_headers -strtorx(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L; -#else -strtorx(CONST char *s, char **sp, int rounding, void *L) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[2]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtox((UShort*)L, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtorxL.c b/libraries/gdtoa/strtorxL.c deleted file mode 100644 index bac4a0bb150..00000000000 --- a/libraries/gdtoa/strtorxL.c +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#endif -#ifdef IEEE_8087 -#define _0 2 -#define _1 1 -#define _2 0 -#endif - - extern ULong NanDflt_xL_D2A[3]; - - void -#ifdef KR_headers -ULtoxL(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtoxL(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = 0; - break; - - case STRTOG_Normal: - case STRTOG_Denormal: - case STRTOG_NaNbits: - L[_0] = (exp + 0x3fff + 63) << 16; - L[_1] = bits[1]; - L[_2] = bits[0]; - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff0000; - L[_1] = 0x80000000; - L[_2] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_xL_D2A[2]; - L[_1] = NanDflt_xL_D2A[1]; - L[_2] = NanDflt_xL_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - } - - int -#ifdef KR_headers -strtorxL(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L; -#else -strtorxL(CONST char *s, char **sp, int rounding, void *L) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[2]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtoxL((ULong*)L, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/sum.c b/libraries/gdtoa/sum.c deleted file mode 100644 index dc0c88bcfab..00000000000 --- a/libraries/gdtoa/sum.c +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - Bigint * -#ifdef KR_headers -sum(a, b) Bigint *a; Bigint *b; -#else -sum(Bigint *a, Bigint *b) -#endif -{ - Bigint *c; - ULong carry, *xc, *xa, *xb, *xe, y; -#ifdef Pack_32 - ULong z; -#endif - - if (a->wds < b->wds) { - c = b; b = a; a = c; - } - c = Balloc(a->k); - c->wds = a->wds; - carry = 0; - xa = a->x; - xb = b->x; - xc = c->x; - xe = xc + b->wds; -#ifdef Pack_32 - do { - y = (*xa & 0xffff) + (*xb & 0xffff) + carry; - carry = (y & 0x10000) >> 16; - z = (*xa++ >> 16) + (*xb++ >> 16) + carry; - carry = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } - while(xc < xe); - xe += a->wds - b->wds; - while(xc < xe) { - y = (*xa & 0xffff) + carry; - carry = (y & 0x10000) >> 16; - z = (*xa++ >> 16) + carry; - carry = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } -#else - do { - y = *xa++ + *xb++ + carry; - carry = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } - while(xc < xe); - xe += a->wds - b->wds; - while(xc < xe) { - y = *xa++ + carry; - carry = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif - if (carry) { - if (c->wds == c->maxwds) { - b = Balloc(c->k + 1); - Bcopy(b, c); - Bfree(c); - c = b; - } - c->x[c->wds++] = 1; - } - return c; - } diff --git a/libraries/gdtoa/ulp.c b/libraries/gdtoa/ulp.c deleted file mode 100644 index 17e9f862c44..00000000000 --- a/libraries/gdtoa/ulp.c +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - double -ulp -#ifdef KR_headers - (x) U *x; -#else - (U *x) -#endif -{ - Long L; - U a; - - L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#ifdef IBM - L |= Exp_msk1 >> 4; -#endif - word0(&a) = L; - word1(&a) = 0; -#ifndef Sudden_Underflow - } - else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(&a) = 0x80000 >> L; - word1(&a) = 0; - } - else { - word0(&a) = 0; - L -= Exp_shift; - word1(&a) = L >= 31 ? 1 : 1 << (31 - L); - } - } -#endif - return dval(&a); - } diff --git a/libraries/glslang/OGLCompilersDLL/CMakeLists.txt b/libraries/glslang/OGLCompilersDLL/CMakeLists.txt deleted file mode 100644 index c6e6c8fc260..00000000000 --- a/libraries/glslang/OGLCompilersDLL/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -cmake_minimum_required(VERSION 2.8.12) - -make_release_only() -use_fast_math() - -# Request C++11 -if(${CMAKE_VERSION} VERSION_LESS 3.1) - # CMake versions before 3.1 do not understand CMAKE_CXX_STANDARD - # remove this block once CMake >=3.1 has fixated in the ecosystem - add_compile_options(-std=c++11) -else() - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) -endif() - -set(SOURCES InitializeDll.cpp InitializeDll.h) - -add_library(OGLCompiler STATIC ${SOURCES}) -set_property(TARGET OGLCompiler PROPERTY FOLDER glslang) -set_property(TARGET OGLCompiler PROPERTY POSITION_INDEPENDENT_CODE ON) - -if(WIN32) - source_group("Source" FILES ${SOURCES}) -endif(WIN32) - -if(ENABLE_GLSLANG_INSTALL) - install(TARGETS OGLCompiler - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -endif(ENABLE_GLSLANG_INSTALL) - diff --git a/libraries/glslang/glslang/CMakeLists.txt b/libraries/glslang/glslang/CMakeLists.txt deleted file mode 100644 index 3cd287b39ff..00000000000 --- a/libraries/glslang/glslang/CMakeLists.txt +++ /dev/null @@ -1,161 +0,0 @@ -cmake_minimum_required(VERSION 2.8.12) - -make_release_only() -use_fast_math() - -if(WIN32) - add_subdirectory(OSDependent/Windows) -elseif(UNIX) - add_subdirectory(OSDependent/Unix) -else(WIN32) - message("unknown platform") -endif(WIN32) - -if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") - add_compile_options(-Wall -Wmaybe-uninitialized -Wuninitialized -Wunused -Wunused-local-typedefs - -Wunused-parameter -Wunused-value -Wunused-variable -Wunused-but-set-parameter -Wunused-but-set-variable -fno-exceptions) - add_compile_options(-Wno-reorder) # disable this from -Wall, since it happens all over. -elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") - add_compile_options(-Wall -Wuninitialized -Wunused -Wunused-local-typedefs - -Wunused-parameter -Wunused-value -Wunused-variable) - add_compile_options(-Wno-reorder) # disable this from -Wall, since it happens all over. -endif() - -# Request C++11 -if(${CMAKE_VERSION} VERSION_LESS 3.1) - # CMake versions before 3.1 do not understand CMAKE_CXX_STANDARD - # remove this block once CMake >=3.1 has fixated in the ecosystem - add_compile_options(-std=c++11) -else() - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) -endif() - -set(SOURCES - MachineIndependent/glslang.y - MachineIndependent/glslang_tab.cpp - MachineIndependent/attribute.cpp - MachineIndependent/Constant.cpp - MachineIndependent/iomapper.cpp - MachineIndependent/InfoSink.cpp - MachineIndependent/Initialize.cpp - MachineIndependent/IntermTraverse.cpp - MachineIndependent/Intermediate.cpp - MachineIndependent/ParseContextBase.cpp - MachineIndependent/ParseHelper.cpp - MachineIndependent/PoolAlloc.cpp - MachineIndependent/RemoveTree.cpp - MachineIndependent/Scan.cpp - MachineIndependent/ShaderLang.cpp - MachineIndependent/SymbolTable.cpp - MachineIndependent/Versions.cpp - MachineIndependent/intermOut.cpp - MachineIndependent/limits.cpp - MachineIndependent/linkValidate.cpp - MachineIndependent/parseConst.cpp - MachineIndependent/reflection.cpp - MachineIndependent/preprocessor/Pp.cpp - MachineIndependent/preprocessor/PpAtom.cpp - MachineIndependent/preprocessor/PpContext.cpp - MachineIndependent/preprocessor/PpScanner.cpp - MachineIndependent/preprocessor/PpTokens.cpp - MachineIndependent/propagateNoContraction.cpp - GenericCodeGen/CodeGen.cpp - GenericCodeGen/Link.cpp) - -set(HEADERS - Public/ShaderLang.h - Include/arrays.h - Include/BaseTypes.h - Include/Common.h - Include/ConstantUnion.h - Include/InfoSink.h - Include/InitializeGlobals.h - Include/intermediate.h - Include/PoolAlloc.h - Include/ResourceLimits.h - Include/revision.h - Include/ShHandle.h - Include/Types.h - MachineIndependent/attribute.h - MachineIndependent/glslang_tab.cpp.h - MachineIndependent/gl_types.h - MachineIndependent/Initialize.h - MachineIndependent/iomapper.h - MachineIndependent/LiveTraverser.h - MachineIndependent/localintermediate.h - MachineIndependent/ParseHelper.h - MachineIndependent/reflection.h - MachineIndependent/RemoveTree.h - MachineIndependent/Scan.h - MachineIndependent/ScanContext.h - MachineIndependent/SymbolTable.h - MachineIndependent/Versions.h - MachineIndependent/parseVersions.h - MachineIndependent/propagateNoContraction.h - MachineIndependent/preprocessor/PpContext.h - MachineIndependent/preprocessor/PpTokens.h) - -# This might be useful for making grammar changes: -# -# find_package(BISON) -# add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp.h -# COMMAND ${BISON_EXECUTABLE} --defines=${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp.h -t ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang.y -o ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp -# MAIN_DEPENDENCY MachineIndependent/glslang.y -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -# set(BISON_GLSLParser_OUTPUT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp) - -# Precompiled header macro. Parameters are source file list and filename for pch cpp file. -macro(glslang_pch SRCS PCHCPP) - if(MSVC AND CMAKE_GENERATOR MATCHES "^Visual Studio") - set(PCH_NAME "$(IntDir)\\pch.pch") - # make source files use/depend on PCH_NAME - set_source_files_properties(${${SRCS}} PROPERTIES COMPILE_FLAGS "/Yupch.h /FIpch.h /Fp${PCH_NAME} /Zm300" OBJECT_DEPENDS "${PCH_NAME}") - # make PCHCPP file compile and generate PCH_NAME - set_source_files_properties(${PCHCPP} PROPERTIES COMPILE_FLAGS "/Ycpch.h /Fp${PCH_NAME} /Zm300" OBJECT_OUTPUTS "${PCH_NAME}") - list(APPEND ${SRCS} "${PCHCPP}") - endif() -endmacro(glslang_pch) - -glslang_pch(SOURCES MachineIndependent/pch.cpp) - -add_library(glslang STATIC ${LIB_TYPE} ${BISON_GLSLParser_OUTPUT_SOURCE} ${SOURCES} ${HEADERS}) -set_property(TARGET glslang PROPERTY FOLDER glslang) -set_property(TARGET glslang PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_libraries(glslang OGLCompiler OSDependent) -target_include_directories(glslang PUBLIC ..) - -if(WIN32 AND BUILD_SHARED_LIBS) - set_target_properties(glslang PROPERTIES PREFIX "") -endif() - -if(ENABLE_HLSL) - target_link_libraries(glslang HLSL) -endif() - -if(WIN32) - source_group("Public" REGULAR_EXPRESSION "Public/*") - source_group("MachineIndependent" REGULAR_EXPRESSION "MachineIndependent/[^/]*") - source_group("Include" REGULAR_EXPRESSION "Include/[^/]*") - source_group("GenericCodeGen" REGULAR_EXPRESSION "GenericCodeGen/*") - source_group("MachineIndependent\\Preprocessor" REGULAR_EXPRESSION "MachineIndependent/preprocessor/*") -endif(WIN32) - -if(ENABLE_GLSLANG_INSTALL) - if(BUILD_SHARED_LIBS) - install(TARGETS glslang - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) - else() - install(TARGETS glslang - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() -endif(ENABLE_GLSLANG_INSTALL) - -if(ENABLE_GLSLANG_INSTALL) - foreach(file ${HEADERS}) - get_filename_component(dir ${file} DIRECTORY) - install(FILES ${file} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/glslang/${dir}) - endforeach() -endif(ENABLE_GLSLANG_INSTALL) diff --git a/libraries/glslang/glslang/Include/revision.h b/libraries/glslang/glslang/Include/revision.h deleted file mode 100644 index a0e4b2066cb..00000000000 --- a/libraries/glslang/glslang/Include/revision.h +++ /dev/null @@ -1,3 +0,0 @@ -// This header is generated by the make-revision script. - -#define GLSLANG_PATCH_LEVEL 3559 diff --git a/libraries/glslang/glslang/Include/revision.template b/libraries/glslang/glslang/Include/revision.template deleted file mode 100644 index 4a16beeb0f8..00000000000 --- a/libraries/glslang/glslang/Include/revision.template +++ /dev/null @@ -1,13 +0,0 @@ -// The file revision.h should be updated to the latest version, somehow, on -// check-in, if glslang has changed. -// -// revision.template is the source for revision.h when using SubWCRev as the -// method of updating revision.h. You don't have to do it this way, the -// requirement is only that revision.h gets updated. -// -// revision.h is under source control so that not all consumers of glslang -// source have to figure out how to create revision.h just to get a build -// going. However, if it is not updated, it can be a version behind. - -#define GLSLANG_REVISION "$WCREV$" -#define GLSLANG_DATE "$WCDATE$" diff --git a/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp b/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp deleted file mode 100644 index d2967973d38..00000000000 --- a/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp +++ /dev/null @@ -1,10405 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ - -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "3.0.4" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 1 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - - - - -/* Copy the first part of user declarations. */ -#line 68 "MachineIndependent/glslang.y" /* yacc.c:339 */ - - -/* Based on: -ANSI C Yacc grammar - -In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a -matching Lex specification) for the April 30, 1985 draft version of the -ANSI C standard. Tom Stockfisch reposted it to net.sources in 1987; that -original, as mentioned in the answer to question 17.25 of the comp.lang.c -FAQ, can be ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z. - -I intend to keep this version as close to the current C Standard grammar as -possible; please let me know if you discover discrepancies. - -Jutta Degener, 1995 -*/ - -#include "SymbolTable.h" -#include "ParseHelper.h" -#include "../Public/ShaderLang.h" -#include "attribute.h" - -using namespace glslang; - - -#line 92 "MachineIndependent/glslang_tab.cpp" /* yacc.c:339 */ - -# ifndef YY_NULLPTR -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULLPTR nullptr -# else -# define YY_NULLPTR 0 -# endif -# endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 1 -#endif - -/* In a future release of Bison, this section will be replaced - by #include "glslang_tab.cpp.h". */ -#ifndef YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED -# define YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 1 -#endif -#if YYDEBUG -extern int yydebug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - CONST = 258, - BOOL = 259, - INT = 260, - UINT = 261, - FLOAT = 262, - BVEC2 = 263, - BVEC3 = 264, - BVEC4 = 265, - IVEC2 = 266, - IVEC3 = 267, - IVEC4 = 268, - UVEC2 = 269, - UVEC3 = 270, - UVEC4 = 271, - VEC2 = 272, - VEC3 = 273, - VEC4 = 274, - MAT2 = 275, - MAT3 = 276, - MAT4 = 277, - MAT2X2 = 278, - MAT2X3 = 279, - MAT2X4 = 280, - MAT3X2 = 281, - MAT3X3 = 282, - MAT3X4 = 283, - MAT4X2 = 284, - MAT4X3 = 285, - MAT4X4 = 286, - SAMPLER2D = 287, - SAMPLER3D = 288, - SAMPLERCUBE = 289, - SAMPLER2DSHADOW = 290, - SAMPLERCUBESHADOW = 291, - SAMPLER2DARRAY = 292, - SAMPLER2DARRAYSHADOW = 293, - ISAMPLER2D = 294, - ISAMPLER3D = 295, - ISAMPLERCUBE = 296, - ISAMPLER2DARRAY = 297, - USAMPLER2D = 298, - USAMPLER3D = 299, - USAMPLERCUBE = 300, - USAMPLER2DARRAY = 301, - SAMPLER = 302, - SAMPLERSHADOW = 303, - TEXTURE2D = 304, - TEXTURE3D = 305, - TEXTURECUBE = 306, - TEXTURE2DARRAY = 307, - ITEXTURE2D = 308, - ITEXTURE3D = 309, - ITEXTURECUBE = 310, - ITEXTURE2DARRAY = 311, - UTEXTURE2D = 312, - UTEXTURE3D = 313, - UTEXTURECUBE = 314, - UTEXTURE2DARRAY = 315, - ATTRIBUTE = 316, - VARYING = 317, - FLOAT16_T = 318, - FLOAT32_T = 319, - DOUBLE = 320, - FLOAT64_T = 321, - INT64_T = 322, - UINT64_T = 323, - INT32_T = 324, - UINT32_T = 325, - INT16_T = 326, - UINT16_T = 327, - INT8_T = 328, - UINT8_T = 329, - I64VEC2 = 330, - I64VEC3 = 331, - I64VEC4 = 332, - U64VEC2 = 333, - U64VEC3 = 334, - U64VEC4 = 335, - I32VEC2 = 336, - I32VEC3 = 337, - I32VEC4 = 338, - U32VEC2 = 339, - U32VEC3 = 340, - U32VEC4 = 341, - I16VEC2 = 342, - I16VEC3 = 343, - I16VEC4 = 344, - U16VEC2 = 345, - U16VEC3 = 346, - U16VEC4 = 347, - I8VEC2 = 348, - I8VEC3 = 349, - I8VEC4 = 350, - U8VEC2 = 351, - U8VEC3 = 352, - U8VEC4 = 353, - DVEC2 = 354, - DVEC3 = 355, - DVEC4 = 356, - DMAT2 = 357, - DMAT3 = 358, - DMAT4 = 359, - F16VEC2 = 360, - F16VEC3 = 361, - F16VEC4 = 362, - F16MAT2 = 363, - F16MAT3 = 364, - F16MAT4 = 365, - F32VEC2 = 366, - F32VEC3 = 367, - F32VEC4 = 368, - F32MAT2 = 369, - F32MAT3 = 370, - F32MAT4 = 371, - F64VEC2 = 372, - F64VEC3 = 373, - F64VEC4 = 374, - F64MAT2 = 375, - F64MAT3 = 376, - F64MAT4 = 377, - DMAT2X2 = 378, - DMAT2X3 = 379, - DMAT2X4 = 380, - DMAT3X2 = 381, - DMAT3X3 = 382, - DMAT3X4 = 383, - DMAT4X2 = 384, - DMAT4X3 = 385, - DMAT4X4 = 386, - F16MAT2X2 = 387, - F16MAT2X3 = 388, - F16MAT2X4 = 389, - F16MAT3X2 = 390, - F16MAT3X3 = 391, - F16MAT3X4 = 392, - F16MAT4X2 = 393, - F16MAT4X3 = 394, - F16MAT4X4 = 395, - F32MAT2X2 = 396, - F32MAT2X3 = 397, - F32MAT2X4 = 398, - F32MAT3X2 = 399, - F32MAT3X3 = 400, - F32MAT3X4 = 401, - F32MAT4X2 = 402, - F32MAT4X3 = 403, - F32MAT4X4 = 404, - F64MAT2X2 = 405, - F64MAT2X3 = 406, - F64MAT2X4 = 407, - F64MAT3X2 = 408, - F64MAT3X3 = 409, - F64MAT3X4 = 410, - F64MAT4X2 = 411, - F64MAT4X3 = 412, - F64MAT4X4 = 413, - ATOMIC_UINT = 414, - ACCSTRUCTNV = 415, - FCOOPMATNV = 416, - ICOOPMATNV = 417, - UCOOPMATNV = 418, - SAMPLERCUBEARRAY = 419, - SAMPLERCUBEARRAYSHADOW = 420, - ISAMPLERCUBEARRAY = 421, - USAMPLERCUBEARRAY = 422, - SAMPLER1D = 423, - SAMPLER1DARRAY = 424, - SAMPLER1DARRAYSHADOW = 425, - ISAMPLER1D = 426, - SAMPLER1DSHADOW = 427, - SAMPLER2DRECT = 428, - SAMPLER2DRECTSHADOW = 429, - ISAMPLER2DRECT = 430, - USAMPLER2DRECT = 431, - SAMPLERBUFFER = 432, - ISAMPLERBUFFER = 433, - USAMPLERBUFFER = 434, - SAMPLER2DMS = 435, - ISAMPLER2DMS = 436, - USAMPLER2DMS = 437, - SAMPLER2DMSARRAY = 438, - ISAMPLER2DMSARRAY = 439, - USAMPLER2DMSARRAY = 440, - SAMPLEREXTERNALOES = 441, - SAMPLEREXTERNAL2DY2YEXT = 442, - ISAMPLER1DARRAY = 443, - USAMPLER1D = 444, - USAMPLER1DARRAY = 445, - F16SAMPLER1D = 446, - F16SAMPLER2D = 447, - F16SAMPLER3D = 448, - F16SAMPLER2DRECT = 449, - F16SAMPLERCUBE = 450, - F16SAMPLER1DARRAY = 451, - F16SAMPLER2DARRAY = 452, - F16SAMPLERCUBEARRAY = 453, - F16SAMPLERBUFFER = 454, - F16SAMPLER2DMS = 455, - F16SAMPLER2DMSARRAY = 456, - F16SAMPLER1DSHADOW = 457, - F16SAMPLER2DSHADOW = 458, - F16SAMPLER1DARRAYSHADOW = 459, - F16SAMPLER2DARRAYSHADOW = 460, - F16SAMPLER2DRECTSHADOW = 461, - F16SAMPLERCUBESHADOW = 462, - F16SAMPLERCUBEARRAYSHADOW = 463, - IMAGE1D = 464, - IIMAGE1D = 465, - UIMAGE1D = 466, - IMAGE2D = 467, - IIMAGE2D = 468, - UIMAGE2D = 469, - IMAGE3D = 470, - IIMAGE3D = 471, - UIMAGE3D = 472, - IMAGE2DRECT = 473, - IIMAGE2DRECT = 474, - UIMAGE2DRECT = 475, - IMAGECUBE = 476, - IIMAGECUBE = 477, - UIMAGECUBE = 478, - IMAGEBUFFER = 479, - IIMAGEBUFFER = 480, - UIMAGEBUFFER = 481, - IMAGE1DARRAY = 482, - IIMAGE1DARRAY = 483, - UIMAGE1DARRAY = 484, - IMAGE2DARRAY = 485, - IIMAGE2DARRAY = 486, - UIMAGE2DARRAY = 487, - IMAGECUBEARRAY = 488, - IIMAGECUBEARRAY = 489, - UIMAGECUBEARRAY = 490, - IMAGE2DMS = 491, - IIMAGE2DMS = 492, - UIMAGE2DMS = 493, - IMAGE2DMSARRAY = 494, - IIMAGE2DMSARRAY = 495, - UIMAGE2DMSARRAY = 496, - F16IMAGE1D = 497, - F16IMAGE2D = 498, - F16IMAGE3D = 499, - F16IMAGE2DRECT = 500, - F16IMAGECUBE = 501, - F16IMAGE1DARRAY = 502, - F16IMAGE2DARRAY = 503, - F16IMAGECUBEARRAY = 504, - F16IMAGEBUFFER = 505, - F16IMAGE2DMS = 506, - F16IMAGE2DMSARRAY = 507, - TEXTURECUBEARRAY = 508, - ITEXTURECUBEARRAY = 509, - UTEXTURECUBEARRAY = 510, - TEXTURE1D = 511, - ITEXTURE1D = 512, - UTEXTURE1D = 513, - TEXTURE1DARRAY = 514, - ITEXTURE1DARRAY = 515, - UTEXTURE1DARRAY = 516, - TEXTURE2DRECT = 517, - ITEXTURE2DRECT = 518, - UTEXTURE2DRECT = 519, - TEXTUREBUFFER = 520, - ITEXTUREBUFFER = 521, - UTEXTUREBUFFER = 522, - TEXTURE2DMS = 523, - ITEXTURE2DMS = 524, - UTEXTURE2DMS = 525, - TEXTURE2DMSARRAY = 526, - ITEXTURE2DMSARRAY = 527, - UTEXTURE2DMSARRAY = 528, - F16TEXTURE1D = 529, - F16TEXTURE2D = 530, - F16TEXTURE3D = 531, - F16TEXTURE2DRECT = 532, - F16TEXTURECUBE = 533, - F16TEXTURE1DARRAY = 534, - F16TEXTURE2DARRAY = 535, - F16TEXTURECUBEARRAY = 536, - F16TEXTUREBUFFER = 537, - F16TEXTURE2DMS = 538, - F16TEXTURE2DMSARRAY = 539, - SUBPASSINPUT = 540, - SUBPASSINPUTMS = 541, - ISUBPASSINPUT = 542, - ISUBPASSINPUTMS = 543, - USUBPASSINPUT = 544, - USUBPASSINPUTMS = 545, - F16SUBPASSINPUT = 546, - F16SUBPASSINPUTMS = 547, - LEFT_OP = 548, - RIGHT_OP = 549, - INC_OP = 550, - DEC_OP = 551, - LE_OP = 552, - GE_OP = 553, - EQ_OP = 554, - NE_OP = 555, - AND_OP = 556, - OR_OP = 557, - XOR_OP = 558, - MUL_ASSIGN = 559, - DIV_ASSIGN = 560, - ADD_ASSIGN = 561, - MOD_ASSIGN = 562, - LEFT_ASSIGN = 563, - RIGHT_ASSIGN = 564, - AND_ASSIGN = 565, - XOR_ASSIGN = 566, - OR_ASSIGN = 567, - SUB_ASSIGN = 568, - LEFT_PAREN = 569, - RIGHT_PAREN = 570, - LEFT_BRACKET = 571, - RIGHT_BRACKET = 572, - LEFT_BRACE = 573, - RIGHT_BRACE = 574, - DOT = 575, - COMMA = 576, - COLON = 577, - EQUAL = 578, - SEMICOLON = 579, - BANG = 580, - DASH = 581, - TILDE = 582, - PLUS = 583, - STAR = 584, - SLASH = 585, - PERCENT = 586, - LEFT_ANGLE = 587, - RIGHT_ANGLE = 588, - VERTICAL_BAR = 589, - CARET = 590, - AMPERSAND = 591, - QUESTION = 592, - INVARIANT = 593, - HIGH_PRECISION = 594, - MEDIUM_PRECISION = 595, - LOW_PRECISION = 596, - PRECISION = 597, - PACKED = 598, - RESOURCE = 599, - SUPERP = 600, - FLOATCONSTANT = 601, - INTCONSTANT = 602, - UINTCONSTANT = 603, - BOOLCONSTANT = 604, - IDENTIFIER = 605, - TYPE_NAME = 606, - CENTROID = 607, - IN = 608, - OUT = 609, - INOUT = 610, - STRUCT = 611, - VOID = 612, - WHILE = 613, - BREAK = 614, - CONTINUE = 615, - DO = 616, - ELSE = 617, - FOR = 618, - IF = 619, - DISCARD = 620, - RETURN = 621, - SWITCH = 622, - CASE = 623, - DEFAULT = 624, - UNIFORM = 625, - SHARED = 626, - BUFFER = 627, - FLAT = 628, - SMOOTH = 629, - LAYOUT = 630, - DOUBLECONSTANT = 631, - INT16CONSTANT = 632, - UINT16CONSTANT = 633, - FLOAT16CONSTANT = 634, - INT32CONSTANT = 635, - UINT32CONSTANT = 636, - INT64CONSTANT = 637, - UINT64CONSTANT = 638, - SUBROUTINE = 639, - DEMOTE = 640, - PAYLOADNV = 641, - PAYLOADINNV = 642, - HITATTRNV = 643, - CALLDATANV = 644, - CALLDATAINNV = 645, - PATCH = 646, - SAMPLE = 647, - NONUNIFORM = 648, - COHERENT = 649, - VOLATILE = 650, - RESTRICT = 651, - READONLY = 652, - WRITEONLY = 653, - DEVICECOHERENT = 654, - QUEUEFAMILYCOHERENT = 655, - WORKGROUPCOHERENT = 656, - SUBGROUPCOHERENT = 657, - NONPRIVATE = 658, - NOPERSPECTIVE = 659, - EXPLICITINTERPAMD = 660, - PERVERTEXNV = 661, - PERPRIMITIVENV = 662, - PERVIEWNV = 663, - PERTASKNV = 664, - PRECISE = 665 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - -union YYSTYPE -{ -#line 96 "MachineIndependent/glslang.y" /* yacc.c:355 */ - - struct { - glslang::TSourceLoc loc; - union { - glslang::TString *string; - int i; - unsigned int u; - long long i64; - unsigned long long u64; - bool b; - double d; - }; - glslang::TSymbol* symbol; - } lex; - struct { - glslang::TSourceLoc loc; - glslang::TOperator op; - union { - TIntermNode* intermNode; - glslang::TIntermNodePair nodePair; - glslang::TIntermTyped* intermTypedNode; - glslang::TAttributes* attributes; - }; - union { - glslang::TPublicType type; - glslang::TFunction* function; - glslang::TParameter param; - glslang::TTypeLoc typeLine; - glslang::TTypeList* typeList; - glslang::TArraySizes* arraySizes; - glslang::TIdentifierList* identifierList; - }; - glslang::TArraySizes* typeParameters; - } interm; - -#line 579 "MachineIndependent/glslang_tab.cpp" /* yacc.c:355 */ -}; - -typedef union YYSTYPE YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - - -int yyparse (glslang::TParseContext* pParseContext); - -#endif /* !YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED */ - -/* Copy the second part of user declarations. */ -#line 132 "MachineIndependent/glslang.y" /* yacc.c:358 */ - - -/* windows only pragma */ -#ifdef _MSC_VER - #pragma warning(disable : 4065) - #pragma warning(disable : 4127) - #pragma warning(disable : 4244) -#endif - -#define parseContext (*pParseContext) -#define yyerror(context, msg) context->parserError(msg) - -extern int yylex(YYSTYPE*, TParseContext&); - - -#line 610 "MachineIndependent/glslang_tab.cpp" /* yacc.c:358 */ - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#else -typedef signed char yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) -# endif -# endif -# ifndef YY_ -# define YY_(Msgid) Msgid -# endif -#endif - -#ifndef YY_ATTRIBUTE -# if (defined __GNUC__ \ - && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ - || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C -# define YY_ATTRIBUTE(Spec) __attribute__(Spec) -# else -# define YY_ATTRIBUTE(Spec) /* empty */ -# endif -#endif - -#ifndef YY_ATTRIBUTE_PURE -# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) -#endif - -#ifndef YY_ATTRIBUTE_UNUSED -# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) -#endif - -#if !defined _Noreturn \ - && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) -# if defined _MSC_VER && 1200 <= _MSC_VER -# define _Noreturn __declspec (noreturn) -# else -# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) -#else -# define YYUSE(E) /* empty */ -#endif - -#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ -/* Suppress an incorrect diagnostic about yylval being uninitialized. */ -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ - _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ - _Pragma ("GCC diagnostic pop") -#else -# define YY_INITIAL_VALUE(Value) Value -#endif -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS -# include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's 'empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (0) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 386 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 9369 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 411 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 111 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 582 -/* YYNSTATES -- Number of states. */ -#define YYNSTATES 727 - -/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned - by yylex, with out-of-bounds checking. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 665 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM - as returned by yylex, without out-of-bounds checking. */ -static const yytype_uint16 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, - 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, - 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, - 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, - 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, - 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410 -}; - -#if YYDEBUG - /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 352, 352, 358, 361, 366, 369, 372, 376, 380, - 384, 388, 392, 396, 400, 404, 408, 416, 419, 422, - 425, 428, 433, 441, 448, 455, 461, 465, 472, 475, - 481, 488, 498, 506, 511, 539, 548, 554, 558, 562, - 582, 583, 584, 585, 591, 592, 597, 602, 611, 612, - 617, 625, 626, 632, 641, 642, 647, 652, 657, 665, - 666, 675, 687, 688, 697, 698, 707, 708, 717, 718, - 726, 727, 735, 736, 744, 745, 745, 763, 764, 780, - 784, 788, 792, 797, 801, 805, 809, 813, 817, 821, - 828, 831, 842, 849, 854, 859, 866, 870, 874, 878, - 883, 888, 897, 897, 908, 912, 919, 926, 929, 936, - 944, 964, 987, 1002, 1027, 1038, 1048, 1058, 1068, 1077, - 1080, 1084, 1088, 1093, 1101, 1108, 1113, 1118, 1123, 1132, - 1142, 1169, 1178, 1185, 1193, 1200, 1207, 1215, 1225, 1232, - 1243, 1249, 1252, 1259, 1263, 1267, 1276, 1286, 1289, 1300, - 1303, 1306, 1310, 1314, 1319, 1323, 1330, 1334, 1339, 1345, - 1351, 1358, 1363, 1371, 1377, 1389, 1403, 1409, 1414, 1422, - 1430, 1438, 1446, 1453, 1457, 1462, 1467, 1472, 1477, 1482, - 1486, 1490, 1494, 1498, 1504, 1515, 1522, 1525, 1534, 1539, - 1549, 1554, 1562, 1566, 1576, 1579, 1585, 1591, 1598, 1608, - 1612, 1616, 1620, 1625, 1629, 1634, 1639, 1644, 1649, 1654, - 1659, 1664, 1669, 1674, 1680, 1686, 1692, 1697, 1702, 1707, - 1712, 1717, 1722, 1727, 1732, 1737, 1742, 1747, 1753, 1758, - 1763, 1768, 1773, 1778, 1783, 1788, 1793, 1798, 1803, 1808, - 1813, 1819, 1825, 1831, 1837, 1843, 1849, 1855, 1861, 1867, - 1873, 1879, 1885, 1891, 1897, 1903, 1909, 1915, 1921, 1927, - 1933, 1939, 1945, 1951, 1957, 1963, 1969, 1975, 1981, 1987, - 1993, 1999, 2005, 2011, 2017, 2023, 2029, 2035, 2041, 2047, - 2053, 2059, 2065, 2071, 2077, 2083, 2089, 2095, 2101, 2107, - 2113, 2119, 2125, 2131, 2137, 2143, 2149, 2155, 2161, 2167, - 2173, 2179, 2185, 2191, 2197, 2203, 2209, 2215, 2221, 2227, - 2233, 2239, 2245, 2251, 2257, 2263, 2269, 2275, 2281, 2287, - 2293, 2299, 2305, 2311, 2317, 2321, 2326, 2332, 2337, 2342, - 2347, 2352, 2357, 2362, 2368, 2373, 2378, 2383, 2388, 2393, - 2399, 2405, 2411, 2417, 2423, 2429, 2435, 2441, 2447, 2453, - 2459, 2465, 2471, 2477, 2482, 2487, 2492, 2497, 2502, 2507, - 2513, 2518, 2523, 2528, 2533, 2538, 2543, 2548, 2554, 2559, - 2564, 2569, 2574, 2579, 2584, 2589, 2594, 2599, 2604, 2609, - 2614, 2619, 2624, 2630, 2635, 2640, 2646, 2652, 2657, 2662, - 2667, 2673, 2678, 2683, 2688, 2694, 2699, 2704, 2709, 2715, - 2720, 2725, 2730, 2736, 2742, 2748, 2754, 2759, 2765, 2771, - 2777, 2782, 2787, 2792, 2797, 2802, 2808, 2813, 2818, 2823, - 2829, 2834, 2839, 2844, 2850, 2855, 2860, 2865, 2871, 2876, - 2881, 2886, 2892, 2897, 2902, 2907, 2913, 2918, 2923, 2928, - 2934, 2939, 2944, 2949, 2955, 2960, 2965, 2970, 2976, 2981, - 2986, 2991, 2997, 3002, 3007, 3012, 3018, 3023, 3028, 3033, - 3039, 3044, 3049, 3054, 3060, 3065, 3070, 3075, 3081, 3086, - 3091, 3096, 3102, 3107, 3112, 3118, 3124, 3130, 3136, 3143, - 3150, 3156, 3162, 3168, 3174, 3180, 3186, 3193, 3198, 3214, - 3219, 3224, 3232, 3232, 3243, 3243, 3253, 3256, 3269, 3291, - 3318, 3322, 3328, 3333, 3344, 3348, 3354, 3365, 3368, 3375, - 3379, 3380, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3394, - 3400, 3409, 3410, 3414, 3410, 3426, 3427, 3431, 3431, 3438, - 3438, 3452, 3455, 3463, 3471, 3482, 3483, 3487, 3491, 3498, - 3505, 3509, 3517, 3521, 3534, 3538, 3545, 3545, 3565, 3568, - 3574, 3586, 3598, 3602, 3609, 3609, 3624, 3624, 3640, 3640, - 3661, 3664, 3670, 3673, 3679, 3683, 3690, 3695, 3700, 3707, - 3710, 3719, 3723, 3732, 3735, 3739, 3748, 3748, 3771, 3777, - 3780, 3785, 3788 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || 1 -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "CONST", "BOOL", "INT", "UINT", "FLOAT", - "BVEC2", "BVEC3", "BVEC4", "IVEC2", "IVEC3", "IVEC4", "UVEC2", "UVEC3", - "UVEC4", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", "MAT4", "MAT2X2", - "MAT2X3", "MAT2X4", "MAT3X2", "MAT3X3", "MAT3X4", "MAT4X2", "MAT4X3", - "MAT4X4", "SAMPLER2D", "SAMPLER3D", "SAMPLERCUBE", "SAMPLER2DSHADOW", - "SAMPLERCUBESHADOW", "SAMPLER2DARRAY", "SAMPLER2DARRAYSHADOW", - "ISAMPLER2D", "ISAMPLER3D", "ISAMPLERCUBE", "ISAMPLER2DARRAY", - "USAMPLER2D", "USAMPLER3D", "USAMPLERCUBE", "USAMPLER2DARRAY", "SAMPLER", - "SAMPLERSHADOW", "TEXTURE2D", "TEXTURE3D", "TEXTURECUBE", - "TEXTURE2DARRAY", "ITEXTURE2D", "ITEXTURE3D", "ITEXTURECUBE", - "ITEXTURE2DARRAY", "UTEXTURE2D", "UTEXTURE3D", "UTEXTURECUBE", - "UTEXTURE2DARRAY", "ATTRIBUTE", "VARYING", "FLOAT16_T", "FLOAT32_T", - "DOUBLE", "FLOAT64_T", "INT64_T", "UINT64_T", "INT32_T", "UINT32_T", - "INT16_T", "UINT16_T", "INT8_T", "UINT8_T", "I64VEC2", "I64VEC3", - "I64VEC4", "U64VEC2", "U64VEC3", "U64VEC4", "I32VEC2", "I32VEC3", - "I32VEC4", "U32VEC2", "U32VEC3", "U32VEC4", "I16VEC2", "I16VEC3", - "I16VEC4", "U16VEC2", "U16VEC3", "U16VEC4", "I8VEC2", "I8VEC3", "I8VEC4", - "U8VEC2", "U8VEC3", "U8VEC4", "DVEC2", "DVEC3", "DVEC4", "DMAT2", - "DMAT3", "DMAT4", "F16VEC2", "F16VEC3", "F16VEC4", "F16MAT2", "F16MAT3", - "F16MAT4", "F32VEC2", "F32VEC3", "F32VEC4", "F32MAT2", "F32MAT3", - "F32MAT4", "F64VEC2", "F64VEC3", "F64VEC4", "F64MAT2", "F64MAT3", - "F64MAT4", "DMAT2X2", "DMAT2X3", "DMAT2X4", "DMAT3X2", "DMAT3X3", - "DMAT3X4", "DMAT4X2", "DMAT4X3", "DMAT4X4", "F16MAT2X2", "F16MAT2X3", - "F16MAT2X4", "F16MAT3X2", "F16MAT3X3", "F16MAT3X4", "F16MAT4X2", - "F16MAT4X3", "F16MAT4X4", "F32MAT2X2", "F32MAT2X3", "F32MAT2X4", - "F32MAT3X2", "F32MAT3X3", "F32MAT3X4", "F32MAT4X2", "F32MAT4X3", - "F32MAT4X4", "F64MAT2X2", "F64MAT2X3", "F64MAT2X4", "F64MAT3X2", - "F64MAT3X3", "F64MAT3X4", "F64MAT4X2", "F64MAT4X3", "F64MAT4X4", - "ATOMIC_UINT", "ACCSTRUCTNV", "FCOOPMATNV", "ICOOPMATNV", "UCOOPMATNV", - "SAMPLERCUBEARRAY", "SAMPLERCUBEARRAYSHADOW", "ISAMPLERCUBEARRAY", - "USAMPLERCUBEARRAY", "SAMPLER1D", "SAMPLER1DARRAY", - "SAMPLER1DARRAYSHADOW", "ISAMPLER1D", "SAMPLER1DSHADOW", "SAMPLER2DRECT", - "SAMPLER2DRECTSHADOW", "ISAMPLER2DRECT", "USAMPLER2DRECT", - "SAMPLERBUFFER", "ISAMPLERBUFFER", "USAMPLERBUFFER", "SAMPLER2DMS", - "ISAMPLER2DMS", "USAMPLER2DMS", "SAMPLER2DMSARRAY", "ISAMPLER2DMSARRAY", - "USAMPLER2DMSARRAY", "SAMPLEREXTERNALOES", "SAMPLEREXTERNAL2DY2YEXT", - "ISAMPLER1DARRAY", "USAMPLER1D", "USAMPLER1DARRAY", "F16SAMPLER1D", - "F16SAMPLER2D", "F16SAMPLER3D", "F16SAMPLER2DRECT", "F16SAMPLERCUBE", - "F16SAMPLER1DARRAY", "F16SAMPLER2DARRAY", "F16SAMPLERCUBEARRAY", - "F16SAMPLERBUFFER", "F16SAMPLER2DMS", "F16SAMPLER2DMSARRAY", - "F16SAMPLER1DSHADOW", "F16SAMPLER2DSHADOW", "F16SAMPLER1DARRAYSHADOW", - "F16SAMPLER2DARRAYSHADOW", "F16SAMPLER2DRECTSHADOW", - "F16SAMPLERCUBESHADOW", "F16SAMPLERCUBEARRAYSHADOW", "IMAGE1D", - "IIMAGE1D", "UIMAGE1D", "IMAGE2D", "IIMAGE2D", "UIMAGE2D", "IMAGE3D", - "IIMAGE3D", "UIMAGE3D", "IMAGE2DRECT", "IIMAGE2DRECT", "UIMAGE2DRECT", - "IMAGECUBE", "IIMAGECUBE", "UIMAGECUBE", "IMAGEBUFFER", "IIMAGEBUFFER", - "UIMAGEBUFFER", "IMAGE1DARRAY", "IIMAGE1DARRAY", "UIMAGE1DARRAY", - "IMAGE2DARRAY", "IIMAGE2DARRAY", "UIMAGE2DARRAY", "IMAGECUBEARRAY", - "IIMAGECUBEARRAY", "UIMAGECUBEARRAY", "IMAGE2DMS", "IIMAGE2DMS", - "UIMAGE2DMS", "IMAGE2DMSARRAY", "IIMAGE2DMSARRAY", "UIMAGE2DMSARRAY", - "F16IMAGE1D", "F16IMAGE2D", "F16IMAGE3D", "F16IMAGE2DRECT", - "F16IMAGECUBE", "F16IMAGE1DARRAY", "F16IMAGE2DARRAY", - "F16IMAGECUBEARRAY", "F16IMAGEBUFFER", "F16IMAGE2DMS", - "F16IMAGE2DMSARRAY", "TEXTURECUBEARRAY", "ITEXTURECUBEARRAY", - "UTEXTURECUBEARRAY", "TEXTURE1D", "ITEXTURE1D", "UTEXTURE1D", - "TEXTURE1DARRAY", "ITEXTURE1DARRAY", "UTEXTURE1DARRAY", "TEXTURE2DRECT", - "ITEXTURE2DRECT", "UTEXTURE2DRECT", "TEXTUREBUFFER", "ITEXTUREBUFFER", - "UTEXTUREBUFFER", "TEXTURE2DMS", "ITEXTURE2DMS", "UTEXTURE2DMS", - "TEXTURE2DMSARRAY", "ITEXTURE2DMSARRAY", "UTEXTURE2DMSARRAY", - "F16TEXTURE1D", "F16TEXTURE2D", "F16TEXTURE3D", "F16TEXTURE2DRECT", - "F16TEXTURECUBE", "F16TEXTURE1DARRAY", "F16TEXTURE2DARRAY", - "F16TEXTURECUBEARRAY", "F16TEXTUREBUFFER", "F16TEXTURE2DMS", - "F16TEXTURE2DMSARRAY", "SUBPASSINPUT", "SUBPASSINPUTMS", "ISUBPASSINPUT", - "ISUBPASSINPUTMS", "USUBPASSINPUT", "USUBPASSINPUTMS", "F16SUBPASSINPUT", - "F16SUBPASSINPUTMS", "LEFT_OP", "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", - "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", "XOR_OP", "MUL_ASSIGN", - "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", - "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", "SUB_ASSIGN", "LEFT_PAREN", - "RIGHT_PAREN", "LEFT_BRACKET", "RIGHT_BRACKET", "LEFT_BRACE", - "RIGHT_BRACE", "DOT", "COMMA", "COLON", "EQUAL", "SEMICOLON", "BANG", - "DASH", "TILDE", "PLUS", "STAR", "SLASH", "PERCENT", "LEFT_ANGLE", - "RIGHT_ANGLE", "VERTICAL_BAR", "CARET", "AMPERSAND", "QUESTION", - "INVARIANT", "HIGH_PRECISION", "MEDIUM_PRECISION", "LOW_PRECISION", - "PRECISION", "PACKED", "RESOURCE", "SUPERP", "FLOATCONSTANT", - "INTCONSTANT", "UINTCONSTANT", "BOOLCONSTANT", "IDENTIFIER", "TYPE_NAME", - "CENTROID", "IN", "OUT", "INOUT", "STRUCT", "VOID", "WHILE", "BREAK", - "CONTINUE", "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN", "SWITCH", - "CASE", "DEFAULT", "UNIFORM", "SHARED", "BUFFER", "FLAT", "SMOOTH", - "LAYOUT", "DOUBLECONSTANT", "INT16CONSTANT", "UINT16CONSTANT", - "FLOAT16CONSTANT", "INT32CONSTANT", "UINT32CONSTANT", "INT64CONSTANT", - "UINT64CONSTANT", "SUBROUTINE", "DEMOTE", "PAYLOADNV", "PAYLOADINNV", - "HITATTRNV", "CALLDATANV", "CALLDATAINNV", "PATCH", "SAMPLE", - "NONUNIFORM", "COHERENT", "VOLATILE", "RESTRICT", "READONLY", - "WRITEONLY", "DEVICECOHERENT", "QUEUEFAMILYCOHERENT", - "WORKGROUPCOHERENT", "SUBGROUPCOHERENT", "NONPRIVATE", "NOPERSPECTIVE", - "EXPLICITINTERPAMD", "PERVERTEXNV", "PERPRIMITIVENV", "PERVIEWNV", - "PERTASKNV", "PRECISE", "$accept", "variable_identifier", - "primary_expression", "postfix_expression", "integer_expression", - "function_call", "function_call_or_method", "function_call_generic", - "function_call_header_no_parameters", - "function_call_header_with_parameters", "function_call_header", - "function_identifier", "unary_expression", "unary_operator", - "multiplicative_expression", "additive_expression", "shift_expression", - "relational_expression", "equality_expression", "and_expression", - "exclusive_or_expression", "inclusive_or_expression", - "logical_and_expression", "logical_xor_expression", - "logical_or_expression", "conditional_expression", "$@1", - "assignment_expression", "assignment_operator", "expression", - "constant_expression", "declaration", "block_structure", "$@2", - "identifier_list", "function_prototype", "function_declarator", - "function_header_with_parameters", "function_header", - "parameter_declarator", "parameter_declaration", - "parameter_type_specifier", "init_declarator_list", "single_declaration", - "fully_specified_type", "invariant_qualifier", "interpolation_qualifier", - "layout_qualifier", "layout_qualifier_id_list", "layout_qualifier_id", - "precise_qualifier", "type_qualifier", "single_type_qualifier", - "storage_qualifier", "non_uniform_qualifier", "type_name_list", - "type_specifier", "array_specifier", "type_parameter_specifier_opt", - "type_parameter_specifier", "type_parameter_specifier_list", - "type_specifier_nonarray", "precision_qualifier", "struct_specifier", - "$@3", "$@4", "struct_declaration_list", "struct_declaration", - "struct_declarator_list", "struct_declarator", "initializer", - "initializer_list", "declaration_statement", "statement", - "simple_statement", "demote_statement", "compound_statement", "$@5", - "$@6", "statement_no_new_scope", "statement_scoped", "$@7", "$@8", - "compound_statement_no_new_scope", "statement_list", - "expression_statement", "selection_statement", - "selection_statement_nonattributed", "selection_rest_statement", - "condition", "switch_statement", "switch_statement_nonattributed", "$@9", - "switch_statement_list", "case_label", "iteration_statement", - "iteration_statement_nonattributed", "$@10", "$@11", "$@12", - "for_init_statement", "conditionopt", "for_rest_statement", - "jump_statement", "translation_unit", "external_declaration", - "function_definition", "$@13", "attribute", "attribute_list", - "single_attribute", YY_NULLPTR -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[NUM] -- (External) token number corresponding to the - (internal) symbol number NUM (which must be that of a token). */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, - 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, - 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, - 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, - 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, - 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, - 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, - 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, - 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, - 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, - 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, - 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, - 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, - 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, - 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, - 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, - 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, - 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, - 665 -}; -# endif - -#define YYPACT_NINF -453 - -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-453))) - -#define YYTABLE_NINF -528 - -#define yytable_value_is_error(Yytable_value) \ - 0 - - /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -static const yytype_int16 yypact[] = -{ - 3994, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, 97, -453, -453, -453, - -453, -453, 6, -453, -453, -453, -453, -453, -453, -307, - -241, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -3, 95, 36, - 125, 6034, 82, -453, -22, -453, -453, -453, -453, 4402, - -453, -453, -453, -453, 131, -453, -453, 730, -453, -453, - 11, -453, 153, -28, 127, -453, 7, -453, 157, -453, - 6034, -453, -453, -453, 6034, 129, 134, -453, 13, -453, - 73, -453, -453, 8391, 162, -453, -453, -453, 161, 6034, - -453, 163, -453, -309, -453, -453, 27, 6831, -453, 16, - 1138, -453, -453, -453, -453, 162, 23, -453, 7221, 49, - -453, 138, -453, 87, 8391, 8391, 8391, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, -453, 68, -453, -453, -453, - 174, 60, 8781, 176, -453, 8391, -453, -453, -320, 175, - -453, 6034, 142, 4810, -453, 6034, 8391, -453, -28, -453, - 143, -453, -453, 119, 128, 32, 21, 38, 158, 160, - 165, 195, 194, 18, 183, 7611, -453, 185, 184, -453, - -453, 188, 180, 181, -453, 196, 197, 190, 8001, 198, - 8391, 187, 193, 122, -453, -453, 91, -453, 95, 204, - 205, -453, -453, -453, -453, -453, 1546, -453, -453, -453, - -453, -453, -453, -453, -453, -453, -353, 175, 7221, 69, - 7221, -453, -453, 7221, 6034, -453, 170, -453, -453, -453, - 78, -453, -453, 8391, 171, -453, -453, 8391, 207, -453, - -453, -453, 8391, -453, 142, 162, 93, -453, -453, -453, - 5218, -453, -453, -453, -453, 8391, 8391, 8391, 8391, 8391, - 8391, 8391, 8391, 8391, 8391, 8391, 8391, 8391, 8391, 8391, - 8391, 8391, 8391, 8391, -453, -453, -453, 206, 177, -453, - 1954, -453, -453, -453, 1954, -453, 8391, -453, -453, 100, - 8391, 144, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, -453, -453, -453, 8391, 8391, -453, -453, -453, - -453, -453, -453, -453, 7221, -453, 140, -453, 5626, -453, - -453, 209, 208, -453, -453, -453, 123, 175, 142, -453, - -453, -453, -453, -453, 119, 119, 128, 128, 32, 32, - 32, 32, 21, 21, 38, 158, 160, 165, 195, 194, - 8391, -453, 214, 56, -453, 1954, 3586, 172, 3178, 80, - -453, 81, -453, -453, -453, -453, -453, 6441, -453, -453, - -453, -453, 146, 8391, 215, 177, 212, 208, 186, 6034, - 219, 221, -453, -453, 3586, 220, -453, -453, -453, 8391, - 222, -453, -453, -453, 216, 2362, 8391, -453, 217, 227, - 182, 225, 2770, -453, 229, -453, -453, 7221, -453, -453, - -453, 89, 8391, 2362, 220, -453, -453, 1954, -453, 224, - 208, -453, -453, 1954, 226, -453, -453 -}; - - /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE does not specify something else to do. Zero - means the default is an error. */ -static const yytype_uint16 yydefact[] = -{ - 0, 156, 203, 201, 202, 200, 207, 208, 209, 210, - 211, 212, 213, 214, 215, 204, 205, 206, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 327, 328, 329, 330, 331, 332, 333, 353, 354, 355, - 356, 357, 358, 359, 368, 381, 382, 369, 370, 372, - 371, 373, 374, 375, 376, 377, 378, 379, 380, 164, - 165, 229, 230, 228, 231, 238, 239, 236, 237, 234, - 235, 232, 233, 261, 262, 263, 273, 274, 275, 258, - 259, 260, 270, 271, 272, 255, 256, 257, 267, 268, - 269, 252, 253, 254, 264, 265, 266, 240, 241, 242, - 276, 277, 278, 243, 244, 245, 288, 289, 290, 246, - 247, 248, 300, 301, 302, 249, 250, 251, 312, 313, - 314, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 291, 292, 293, 294, 295, 296, 297, 298, 299, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 325, 324, 484, - 485, 486, 337, 338, 361, 364, 326, 335, 336, 352, - 334, 383, 384, 387, 388, 389, 391, 392, 393, 395, - 396, 397, 399, 400, 474, 475, 360, 362, 363, 339, - 340, 341, 385, 342, 346, 347, 350, 390, 394, 398, - 343, 344, 348, 349, 386, 345, 351, 430, 432, 433, - 434, 436, 437, 438, 440, 441, 442, 444, 445, 446, - 448, 449, 450, 452, 453, 454, 456, 457, 458, 460, - 461, 462, 464, 465, 466, 468, 469, 470, 472, 473, - 431, 435, 439, 443, 447, 455, 459, 463, 451, 467, - 471, 365, 366, 367, 401, 410, 412, 406, 411, 413, - 414, 416, 417, 418, 420, 421, 422, 424, 425, 426, - 428, 429, 402, 403, 404, 415, 405, 407, 408, 409, - 419, 423, 427, 476, 477, 480, 481, 482, 483, 478, - 479, 575, 131, 489, 490, 491, 0, 488, 160, 158, - 159, 157, 0, 199, 161, 162, 163, 133, 132, 0, - 183, 169, 170, 168, 171, 172, 166, 167, 185, 173, - 179, 180, 181, 182, 174, 175, 176, 177, 178, 134, - 135, 136, 137, 138, 139, 146, 574, 0, 576, 0, - 108, 107, 0, 119, 124, 153, 152, 150, 154, 0, - 147, 149, 155, 129, 195, 151, 487, 0, 571, 573, - 0, 494, 0, 0, 0, 96, 0, 93, 0, 106, - 0, 115, 109, 117, 0, 118, 0, 94, 125, 99, - 0, 148, 130, 0, 188, 194, 1, 572, 0, 0, - 492, 143, 145, 0, 141, 186, 0, 0, 97, 0, - 0, 577, 110, 114, 116, 112, 120, 111, 0, 126, - 102, 0, 100, 0, 0, 0, 0, 42, 41, 43, - 40, 5, 6, 7, 8, 2, 15, 13, 14, 16, - 9, 10, 11, 12, 3, 17, 36, 19, 24, 25, - 0, 0, 29, 0, 197, 0, 35, 33, 0, 189, - 95, 0, 0, 0, 496, 0, 0, 140, 0, 184, - 0, 190, 44, 48, 51, 54, 59, 62, 64, 66, - 68, 70, 72, 74, 0, 0, 98, 0, 522, 531, - 535, 0, 0, 0, 556, 0, 0, 0, 0, 0, - 0, 0, 0, 44, 77, 90, 0, 509, 0, 155, - 129, 512, 533, 511, 519, 510, 0, 513, 514, 537, - 515, 544, 516, 517, 552, 518, 0, 113, 0, 121, - 0, 504, 128, 0, 0, 104, 0, 101, 37, 38, - 0, 21, 22, 0, 0, 27, 26, 0, 199, 30, - 32, 39, 0, 196, 0, 502, 0, 500, 495, 497, - 0, 92, 144, 142, 187, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 75, 191, 192, 0, 0, 521, - 0, 554, 567, 566, 0, 558, 0, 570, 568, 0, - 0, 0, 551, 520, 80, 81, 83, 82, 85, 86, - 87, 88, 89, 84, 79, 0, 0, 536, 532, 534, - 538, 545, 553, 123, 0, 507, 0, 127, 0, 105, - 4, 0, 23, 20, 31, 198, 0, 503, 0, 498, - 493, 45, 46, 47, 50, 49, 52, 53, 57, 58, - 55, 56, 60, 61, 63, 65, 67, 69, 71, 73, - 0, 193, 581, 0, 579, 523, 0, 0, 0, 0, - 569, 0, 550, 78, 91, 122, 505, 0, 103, 18, - 499, 501, 0, 0, 0, 0, 0, 542, 0, 0, - 0, 0, 561, 560, 563, 529, 546, 506, 508, 0, - 0, 578, 580, 524, 0, 0, 0, 562, 0, 0, - 541, 0, 0, 539, 0, 76, 582, 0, 526, 555, - 525, 0, 564, 0, 529, 528, 530, 548, 543, 0, - 565, 559, 540, 549, 0, 557, 547 -}; - - /* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -453, -453, -453, -453, -453, -453, -453, -453, -453, -453, - -453, -453, 8696, -453, -89, -88, -122, -84, -19, -18, - -17, -16, -20, -15, -453, -85, -453, -98, -453, -110, - -119, 2, -453, -453, -453, 4, -453, -453, -453, 189, - 191, 192, -453, -453, -339, -453, -453, -453, -453, 98, - -453, -37, -44, -453, 9, -453, 0, -71, -453, -453, - -453, -453, 261, -453, -453, -453, -452, -137, 20, -68, - -209, -453, -96, -198, -326, -453, -136, -453, -453, -146, - -144, -453, -453, 200, -265, -87, -453, 57, -453, -112, - -453, 59, -453, -453, -453, -453, 61, -453, -453, -453, - -453, -453, -453, -453, -453, 228, -453, -453, -453, -453, - -99 -}; - - /* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 434, 435, 436, 621, 437, 438, 439, 440, 441, - 442, 443, 493, 445, 463, 464, 465, 466, 467, 468, - 469, 470, 471, 472, 473, 494, 650, 495, 605, 496, - 552, 497, 337, 524, 413, 498, 339, 340, 341, 371, - 372, 373, 342, 343, 344, 345, 346, 347, 393, 394, - 348, 349, 350, 351, 446, 396, 447, 399, 384, 385, - 448, 354, 355, 356, 455, 389, 453, 454, 546, 547, - 522, 616, 501, 502, 503, 504, 505, 580, 676, 709, - 700, 701, 702, 710, 506, 507, 508, 509, 703, 680, - 510, 511, 704, 724, 512, 513, 514, 656, 584, 658, - 684, 698, 699, 515, 357, 358, 359, 368, 516, 653, - 654 -}; - - /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule whose - number is the opposite. If YYTABLE_NINF, syntax error. */ -static const yytype_int16 yytable[] = -{ - 353, 542, 336, 550, 338, 481, 457, 363, 484, 352, - 485, 486, 458, 543, 489, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 618, 364, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 374, 381, 530, 409, 609, 613, - 521, 615, 474, 449, 617, 655, 549, 678, 562, 563, - 573, 365, 391, 397, 361, 560, 561, 407, 378, 397, - 381, 398, 475, 374, 517, 519, 408, 566, 567, 397, - 476, 375, 459, 392, 539, 678, 518, 366, 460, 382, - 352, 369, 451, 564, 565, 574, 362, 353, 352, 336, - 388, 338, 297, 531, 532, 475, 352, 302, 303, 708, - 375, 551, 523, 674, 375, 536, 716, 675, 589, 352, - 591, 537, -34, 352, 533, 475, 657, 708, 534, 452, - 577, 410, 614, 620, 411, 685, 686, 412, 352, 606, - 500, 606, 606, 376, 719, 665, 377, 381, 526, 499, - 606, 527, 606, 549, 628, 607, 451, 629, 451, 367, - 521, 606, 521, 622, 660, 521, 594, 595, 596, 597, - 598, 599, 600, 601, 602, 603, 293, 294, 295, 624, - 638, 639, 640, 641, 628, 604, 370, 670, 555, 556, - 557, 544, 723, 452, 558, 452, 559, 609, 688, 666, - 352, 667, 352, 383, 352, 606, 662, 606, 689, 634, - 635, 390, 636, 637, 627, 400, 659, 395, 397, 405, - 661, 549, 642, 643, 406, 450, 456, 451, 525, 535, - 540, 475, 545, 554, 568, 569, 571, 572, 718, 570, - 575, 578, 581, 579, 582, 583, 500, 663, 664, 592, - 585, 586, 590, 451, 587, 499, 521, 593, -35, -33, - 619, 623, -28, 651, 452, 609, 669, 652, 673, 606, - 681, 693, 691, 352, 695, 696, 694, 706, -527, 707, - 672, 712, 713, 478, 714, 726, 677, 717, 725, 644, - 452, 645, 648, 646, 690, 647, 553, 360, 649, 352, - 671, 402, 682, 403, 626, 715, 404, 721, 401, 521, - 722, 683, 697, 610, 677, 611, 692, 612, 0, 0, - 500, 451, 0, 0, 500, 387, 711, 0, 551, 499, - 0, 705, 0, 499, 0, 0, 0, 0, 0, 0, - 0, 0, 720, 0, 0, 0, 0, 0, 0, 521, - 0, 0, 0, 0, 0, 0, 0, 0, 452, 679, - 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, - 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 679, 0, 0, - 0, 0, 0, 0, 0, 500, 500, 0, 500, 0, - 0, 0, 0, 0, 499, 499, 0, 499, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 382, - 0, 0, 0, 0, 500, 0, 0, 0, 352, 0, - 0, 0, 0, 499, 0, 500, 0, 0, 0, 0, - 0, 0, 500, 0, 499, 0, 0, 0, 0, 0, - 0, 499, 0, 500, 0, 0, 0, 500, 0, 0, - 0, 0, 499, 500, 0, 0, 499, 0, 0, 0, - 386, 0, 499, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 289, 290, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 292, 293, - 294, 295, 296, 0, 0, 0, 0, 0, 0, 0, - 0, 297, 298, 299, 300, 301, 302, 303, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 304, 305, 306, 307, 308, 309, 0, 0, 0, 0, - 0, 0, 0, 0, 310, 0, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 0, 0, 414, 415, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 416, 0, 477, 0, 478, 479, 0, 0, - 0, 0, 480, 417, 418, 419, 420, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 292, 293, 294, 295, - 296, 0, 0, 0, 421, 422, 423, 424, 425, 297, - 298, 299, 300, 301, 302, 303, 481, 482, 483, 484, - 0, 485, 486, 487, 488, 489, 490, 491, 304, 305, - 306, 307, 308, 309, 426, 427, 428, 429, 430, 431, - 432, 433, 310, 492, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 330, 331, 332, 333, 334, 335, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 0, - 0, 414, 415, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 416, 0, 477, 0, 478, 608, 0, 0, 0, 0, - 480, 417, 418, 419, 420, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 292, 293, 294, 295, 296, 0, - 0, 0, 421, 422, 423, 424, 425, 297, 298, 299, - 300, 301, 302, 303, 481, 482, 483, 484, 0, 485, - 486, 487, 488, 489, 490, 491, 304, 305, 306, 307, - 308, 309, 426, 427, 428, 429, 430, 431, 432, 433, - 310, 492, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - 329, 330, 331, 332, 333, 334, 335, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 289, 290, 0, 0, 414, - 415, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 416, 0, - 477, 0, 478, 0, 0, 0, 0, 0, 480, 417, - 418, 419, 420, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 292, 293, 294, 295, 296, 0, 0, 0, - 421, 422, 423, 424, 425, 297, 298, 299, 300, 301, - 302, 303, 481, 482, 483, 484, 0, 485, 486, 487, - 488, 489, 490, 491, 304, 305, 306, 307, 308, 309, - 426, 427, 428, 429, 430, 431, 432, 433, 310, 492, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 0, 0, 414, 415, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 416, 0, 477, 0, - 400, 0, 0, 0, 0, 0, 480, 417, 418, 419, - 420, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 292, 293, 294, 295, 296, 0, 0, 0, 421, 422, - 423, 424, 425, 297, 298, 299, 300, 301, 302, 303, - 481, 482, 483, 484, 0, 485, 486, 487, 488, 489, - 490, 491, 304, 305, 306, 307, 308, 309, 426, 427, - 428, 429, 430, 431, 432, 433, 310, 492, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, - 333, 334, 335, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 289, 290, 0, 0, 414, 415, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 416, 0, 477, 0, 0, 0, - 0, 0, 0, 0, 480, 417, 418, 419, 420, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 292, 293, - 294, 295, 296, 0, 0, 0, 421, 422, 423, 424, - 425, 297, 298, 299, 300, 301, 302, 303, 481, 482, - 483, 484, 0, 485, 486, 487, 488, 489, 490, 491, - 304, 305, 306, 307, 308, 309, 426, 427, 428, 429, - 430, 431, 432, 433, 310, 492, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 0, 0, 414, 415, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 416, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 480, 417, 418, 419, 420, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 292, 293, 294, 295, - 296, 0, 0, 0, 421, 422, 423, 424, 425, 297, - 298, 299, 300, 301, 302, 303, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 304, 305, - 306, 307, 308, 309, 426, 427, 428, 429, 430, 431, - 432, 433, 310, 0, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 330, 331, 332, 333, 334, 335, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 0, - 0, 414, 415, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 416, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 417, 418, 419, 420, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 292, 293, 294, 295, 0, 0, - 0, 0, 421, 422, 423, 424, 425, 297, 298, 299, - 300, 301, 302, 303, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 304, 305, 306, 307, - 308, 309, 426, 427, 428, 429, 430, 431, 432, 433, - 310, 0, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - 329, 330, 331, 332, 333, 334, 335, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 289, 290, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 291, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 292, 293, 294, 295, 296, 0, 0, 0, - 0, 0, 0, 0, 0, 297, 298, 299, 300, 301, - 302, 303, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 304, 305, 306, 307, 308, 309, - 0, 0, 0, 0, 0, 0, 0, 0, 310, 0, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 379, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 292, 293, 294, 295, 0, 0, 0, 0, 0, 0, - 0, 0, 380, 297, 298, 299, 300, 301, 302, 303, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 304, 305, 306, 307, 308, 309, 0, 0, - 0, 0, 0, 0, 0, 0, 310, 0, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, - 333, 334, 335, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 289, 290, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 548, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 292, 293, - 294, 295, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 297, 298, 299, 300, 301, 302, 303, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 304, 305, 306, 307, 308, 309, 0, 0, 0, 0, - 0, 0, 0, 0, 310, 0, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 630, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 292, 293, 294, 295, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 297, - 298, 299, 300, 301, 302, 303, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 304, 305, - 306, 307, 308, 309, 0, 0, 0, 0, 0, 0, - 0, 0, 310, 0, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 330, 331, 332, 333, 334, 335, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 668, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 292, 293, 294, 295, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 297, 298, 299, - 300, 301, 302, 303, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 304, 305, 306, 307, - 308, 309, 0, 0, 0, 0, 0, 0, 0, 0, - 310, 0, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - 329, 330, 331, 332, 333, 334, 335, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 289, 290, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 292, 293, 294, 295, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 297, 298, 299, 300, 301, - 302, 303, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 304, 305, 306, 307, 308, 309, - 0, 0, 0, 0, 0, 0, 0, 0, 310, 0, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 0, 0, 414, 415, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 416, 0, 0, 0, 520, - 687, 0, 0, 0, 0, 0, 417, 418, 419, 420, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 421, 422, 423, - 424, 425, 297, 0, 0, 0, 0, 302, 303, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 426, 427, 428, - 429, 430, 431, 432, 433, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 318, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 0, 0, 414, 415, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 416, 0, 0, 461, 0, - 0, 0, 0, 0, 0, 0, 417, 418, 419, 420, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 421, 422, 423, - 424, 425, 297, 0, 0, 0, 0, 302, 303, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 426, 427, 428, - 429, 430, 431, 432, 433, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 318, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 0, 0, 414, 415, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 416, 0, 0, 0, 520, - 0, 0, 0, 0, 0, 0, 417, 418, 419, 420, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 421, 422, 423, - 424, 425, 297, 0, 0, 0, 0, 302, 303, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 426, 427, 428, - 429, 430, 431, 432, 433, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 318, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 0, 0, 414, 415, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 416, 0, 0, 576, 0, - 0, 0, 0, 0, 0, 0, 417, 418, 419, 420, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 421, 422, 423, - 424, 425, 297, 0, 0, 0, 0, 302, 303, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 426, 427, 428, - 429, 430, 431, 432, 433, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 318, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 0, 0, 414, 415, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 416, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 588, 417, 418, 419, 420, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 421, 422, 423, - 424, 425, 297, 0, 0, 0, 0, 302, 303, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 426, 427, 428, - 429, 430, 431, 432, 433, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 318, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 0, 0, 414, 415, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 416, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 417, 418, 419, 420, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 421, 422, 423, - 424, 425, 297, 0, 0, 0, 0, 302, 303, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 426, 427, 428, - 429, 430, 431, 432, 433, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 318, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 0, 0, 414, 415, 0, 444, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 462, 0, 416, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 417, 418, 419, 420, - 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 421, 422, 423, - 424, 425, 297, 0, 0, 0, 0, 302, 538, 0, - 0, 541, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 462, 0, 0, 0, 0, 426, 427, 428, - 429, 430, 431, 432, 433, 0, 0, 0, 0, 0, - 0, 462, 0, 0, 318, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 625, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 631, 632, 633, 462, 462, 462, 462, 462, 462, - 462, 462, 462, 462, 462, 462, 462, 462, 462, 462, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 462 -}; - -static const yytype_int16 yycheck[] = -{ - 0, 321, 0, 455, 0, 358, 315, 314, 361, 0, - 363, 364, 321, 333, 367, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 524, 314, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, 341, 349, 416, 378, 506, 518, - 408, 520, 397, 384, 523, 580, 453, 656, 297, 298, - 302, 324, 350, 316, 318, 293, 294, 314, 350, 316, - 374, 324, 316, 370, 405, 406, 323, 299, 300, 316, - 324, 341, 315, 371, 442, 684, 323, 350, 321, 349, - 341, 315, 389, 332, 333, 337, 350, 357, 349, 357, - 360, 357, 351, 295, 296, 316, 357, 356, 357, 695, - 370, 456, 323, 317, 374, 315, 702, 321, 488, 370, - 490, 321, 314, 374, 316, 316, 584, 713, 320, 389, - 475, 318, 323, 315, 321, 315, 315, 324, 389, 321, - 400, 321, 321, 321, 315, 614, 324, 451, 321, 400, - 321, 324, 321, 550, 321, 324, 453, 324, 455, 324, - 518, 321, 520, 533, 324, 523, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 339, 340, 341, 537, - 562, 563, 564, 565, 321, 323, 321, 324, 329, 330, - 331, 451, 717, 453, 326, 455, 328, 655, 667, 319, - 451, 321, 453, 332, 455, 321, 322, 321, 322, 558, - 559, 318, 560, 561, 545, 318, 586, 350, 316, 350, - 590, 618, 566, 567, 350, 324, 323, 524, 350, 315, - 314, 316, 350, 350, 336, 335, 301, 303, 707, 334, - 317, 316, 314, 319, 324, 324, 506, 605, 606, 322, - 314, 314, 314, 550, 324, 506, 614, 324, 314, 314, - 350, 350, 315, 317, 524, 723, 317, 350, 314, 321, - 358, 319, 317, 524, 315, 314, 350, 315, 318, 323, - 650, 324, 315, 318, 362, 319, 656, 318, 324, 568, - 550, 569, 572, 570, 673, 571, 458, 296, 573, 550, - 628, 370, 658, 374, 544, 701, 374, 713, 368, 667, - 714, 658, 684, 516, 684, 516, 675, 516, -1, -1, - 580, 618, -1, -1, 584, 357, 696, -1, 673, 580, - -1, 689, -1, 584, -1, -1, -1, -1, -1, -1, - -1, -1, 712, -1, -1, -1, -1, -1, -1, 707, - -1, -1, -1, -1, -1, -1, -1, -1, 618, 656, - -1, -1, -1, -1, -1, -1, -1, 618, -1, -1, - -1, -1, -1, -1, -1, 679, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 684, -1, -1, - -1, -1, -1, -1, -1, 655, 656, -1, 658, -1, - -1, -1, -1, -1, 655, 656, -1, 658, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 679, - -1, -1, -1, -1, 684, -1, -1, -1, 679, -1, - -1, -1, -1, 684, -1, 695, -1, -1, -1, -1, - -1, -1, 702, -1, 695, -1, -1, -1, -1, -1, - -1, 702, -1, 713, -1, -1, -1, 717, -1, -1, - -1, -1, 713, 723, -1, -1, 717, -1, -1, -1, - 0, -1, 723, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 291, 292, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 324, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 338, 339, - 340, 341, 342, -1, -1, -1, -1, -1, -1, -1, - -1, 351, 352, 353, 354, 355, 356, 357, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 370, 371, 372, 373, 374, 375, -1, -1, -1, -1, - -1, -1, -1, -1, 384, -1, 386, 387, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, - 292, -1, -1, 295, 296, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 314, -1, 316, -1, 318, 319, -1, -1, - -1, -1, 324, 325, 326, 327, 328, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 338, 339, 340, 341, - 342, -1, -1, -1, 346, 347, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - -1, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 289, 290, 291, 292, -1, - -1, 295, 296, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 314, -1, 316, -1, 318, 319, -1, -1, -1, -1, - 324, 325, 326, 327, 328, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 338, 339, 340, 341, 342, -1, - -1, -1, 346, 347, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, 361, -1, 363, - 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, - 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 291, 292, -1, -1, 295, - 296, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 314, -1, - 316, -1, 318, -1, -1, -1, -1, -1, 324, 325, - 326, 327, 328, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 338, 339, 340, 341, 342, -1, -1, -1, - 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, 361, -1, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 289, 290, 291, 292, -1, -1, 295, 296, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 314, -1, 316, -1, - 318, -1, -1, -1, -1, -1, 324, 325, 326, 327, - 328, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 338, 339, 340, 341, 342, -1, -1, -1, 346, 347, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, -1, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 291, 292, -1, -1, 295, 296, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 314, -1, 316, -1, -1, -1, - -1, -1, -1, -1, 324, 325, 326, 327, 328, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 338, 339, - 340, 341, 342, -1, -1, -1, 346, 347, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, -1, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, - 292, -1, -1, 295, 296, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 314, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 324, 325, 326, 327, 328, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 338, 339, 340, 341, - 342, -1, -1, -1, 346, 347, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - 382, 383, 384, -1, 386, 387, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 289, 290, 291, 292, -1, - -1, 295, 296, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 314, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 325, 326, 327, 328, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 338, 339, 340, 341, -1, -1, - -1, -1, 346, 347, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, - 384, -1, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 291, 292, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 324, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 338, 339, 340, 341, 342, -1, -1, -1, - -1, -1, -1, -1, -1, 351, 352, 353, 354, 355, - 356, 357, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 370, 371, 372, 373, 374, 375, - -1, -1, -1, -1, -1, -1, -1, -1, 384, -1, - 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 289, 290, 291, 292, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 324, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 338, 339, 340, 341, -1, -1, -1, -1, -1, -1, - -1, -1, 350, 351, 352, 353, 354, 355, 356, 357, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 370, 371, 372, 373, 374, 375, -1, -1, - -1, -1, -1, -1, -1, -1, 384, -1, 386, 387, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 291, 292, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 319, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 338, 339, - 340, 341, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 351, 352, 353, 354, 355, 356, 357, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 370, 371, 372, 373, 374, 375, -1, -1, -1, -1, - -1, -1, -1, -1, 384, -1, 386, 387, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, - 292, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 319, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 338, 339, 340, 341, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 351, - 352, 353, 354, 355, 356, 357, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 370, 371, - 372, 373, 374, 375, -1, -1, -1, -1, -1, -1, - -1, -1, 384, -1, 386, 387, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 289, 290, 291, 292, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 319, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 338, 339, 340, 341, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 351, 352, 353, - 354, 355, 356, 357, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 370, 371, 372, 373, - 374, 375, -1, -1, -1, -1, -1, -1, -1, -1, - 384, -1, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 291, 292, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 338, 339, 340, 341, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 351, 352, 353, 354, 355, - 356, 357, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 370, 371, 372, 373, 374, 375, - -1, -1, -1, -1, -1, -1, -1, -1, 384, -1, - 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, -1, -1, 295, 296, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 314, -1, -1, -1, 318, - 319, -1, -1, -1, -1, -1, 325, 326, 327, 328, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 346, 347, 348, - 349, 350, 351, -1, -1, -1, -1, 356, 357, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 376, 377, 378, - 379, 380, 381, 382, 383, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 393, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, -1, -1, 295, 296, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 314, -1, -1, 317, -1, - -1, -1, -1, -1, -1, -1, 325, 326, 327, 328, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 346, 347, 348, - 349, 350, 351, -1, -1, -1, -1, 356, 357, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 376, 377, 378, - 379, 380, 381, 382, 383, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 393, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, -1, -1, 295, 296, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 314, -1, -1, -1, 318, - -1, -1, -1, -1, -1, -1, 325, 326, 327, 328, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 346, 347, 348, - 349, 350, 351, -1, -1, -1, -1, 356, 357, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 376, 377, 378, - 379, 380, 381, 382, 383, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 393, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, -1, -1, 295, 296, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 314, -1, -1, 317, -1, - -1, -1, -1, -1, -1, -1, 325, 326, 327, 328, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 346, 347, 348, - 349, 350, 351, -1, -1, -1, -1, 356, 357, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 376, 377, 378, - 379, 380, 381, 382, 383, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 393, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, -1, -1, 295, 296, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 314, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 324, 325, 326, 327, 328, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 346, 347, 348, - 349, 350, 351, -1, -1, -1, -1, 356, 357, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 376, 377, 378, - 379, 380, 381, 382, 383, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 393, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, -1, -1, 295, 296, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 314, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 325, 326, 327, 328, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 346, 347, 348, - 349, 350, 351, -1, -1, -1, -1, 356, 357, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 376, 377, 378, - 379, 380, 381, 382, 383, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 393, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, -1, -1, 295, 296, -1, 383, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 397, -1, 314, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 325, 326, 327, 328, - 414, 415, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 346, 347, 348, - 349, 350, 351, -1, -1, -1, -1, 356, 357, -1, - -1, 445, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 456, -1, -1, -1, -1, 376, 377, 378, - 379, 380, 381, 382, 383, -1, -1, -1, -1, -1, - -1, 475, -1, -1, 393, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 542, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 555, 556, 557, 558, 559, 560, 561, 562, 563, - 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 673 -}; - - /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint16 yystos[] = -{ - 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, - 292, 324, 338, 339, 340, 341, 342, 351, 352, 353, - 354, 355, 356, 357, 370, 371, 372, 373, 374, 375, - 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 442, 443, 446, 447, - 448, 449, 453, 454, 455, 456, 457, 458, 461, 462, - 463, 464, 465, 467, 472, 473, 474, 515, 516, 517, - 473, 318, 350, 314, 314, 324, 350, 324, 518, 315, - 321, 450, 451, 452, 462, 467, 321, 324, 350, 324, - 350, 463, 467, 332, 469, 470, 0, 516, 467, 476, - 318, 350, 371, 459, 460, 350, 466, 316, 324, 468, - 318, 494, 451, 450, 452, 350, 350, 314, 323, 468, - 318, 321, 324, 445, 295, 296, 314, 325, 326, 327, - 328, 346, 347, 348, 349, 350, 376, 377, 378, 379, - 380, 381, 382, 383, 412, 413, 414, 416, 417, 418, - 419, 420, 421, 422, 423, 424, 465, 467, 471, 468, - 324, 462, 467, 477, 478, 475, 323, 315, 321, 315, - 321, 317, 423, 425, 426, 427, 428, 429, 430, 431, - 432, 433, 434, 435, 436, 316, 324, 316, 318, 319, - 324, 358, 359, 360, 361, 363, 364, 365, 366, 367, - 368, 369, 385, 423, 436, 438, 440, 442, 446, 465, - 467, 483, 484, 485, 486, 487, 495, 496, 497, 498, - 501, 502, 505, 506, 507, 514, 519, 468, 323, 468, - 318, 438, 481, 323, 444, 350, 321, 324, 423, 423, - 440, 295, 296, 316, 320, 315, 315, 321, 357, 438, - 314, 423, 321, 333, 467, 350, 479, 480, 319, 478, - 477, 436, 441, 460, 350, 329, 330, 331, 326, 328, - 293, 294, 297, 298, 332, 333, 299, 300, 336, 335, - 334, 301, 303, 302, 337, 317, 317, 436, 316, 319, - 488, 314, 324, 324, 509, 314, 314, 324, 324, 440, - 314, 440, 322, 324, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 323, 439, 321, 324, 319, 484, - 498, 502, 507, 481, 323, 481, 482, 481, 477, 350, - 315, 415, 440, 350, 438, 423, 479, 468, 321, 324, - 319, 423, 423, 423, 425, 425, 426, 426, 427, 427, - 427, 427, 428, 428, 429, 430, 431, 432, 433, 434, - 437, 317, 350, 520, 521, 495, 508, 484, 510, 440, - 324, 440, 322, 438, 438, 481, 319, 321, 319, 317, - 324, 480, 440, 314, 317, 321, 489, 440, 455, 462, - 500, 358, 483, 496, 511, 315, 315, 319, 481, 322, - 441, 317, 521, 319, 350, 315, 314, 500, 512, 513, - 491, 492, 493, 499, 503, 438, 315, 323, 485, 490, - 494, 440, 324, 315, 362, 487, 485, 318, 481, 315, - 440, 490, 491, 495, 504, 324, 319 -}; - - /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint16 yyr1[] = -{ - 0, 411, 412, 413, 413, 413, 413, 413, 413, 413, - 413, 413, 413, 413, 413, 413, 413, 414, 414, 414, - 414, 414, 414, 415, 416, 417, 418, 418, 419, 419, - 420, 420, 421, 422, 422, 422, 423, 423, 423, 423, - 424, 424, 424, 424, 425, 425, 425, 425, 426, 426, - 426, 427, 427, 427, 428, 428, 428, 428, 428, 429, - 429, 429, 430, 430, 431, 431, 432, 432, 433, 433, - 434, 434, 435, 435, 436, 437, 436, 438, 438, 439, - 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, - 440, 440, 441, 442, 442, 442, 442, 442, 442, 442, - 442, 442, 444, 443, 445, 445, 446, 447, 447, 448, - 448, 449, 450, 450, 451, 451, 451, 451, 452, 453, - 453, 453, 453, 453, 454, 454, 454, 454, 454, 455, - 455, 456, 457, 457, 457, 457, 457, 457, 457, 457, - 458, 459, 459, 460, 460, 460, 461, 462, 462, 463, - 463, 463, 463, 463, 463, 463, 464, 464, 464, 464, - 464, 464, 464, 464, 464, 464, 464, 464, 464, 464, - 464, 464, 464, 464, 464, 464, 464, 464, 464, 464, - 464, 464, 464, 464, 464, 465, 466, 466, 467, 467, - 468, 468, 468, 468, 469, 469, 470, 471, 471, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, - 472, 472, 472, 472, 472, 472, 472, 472, 472, 473, - 473, 473, 475, 474, 476, 474, 477, 477, 478, 478, - 479, 479, 480, 480, 481, 481, 481, 482, 482, 483, - 484, 484, 485, 485, 485, 485, 485, 485, 485, 485, - 486, 487, 488, 489, 487, 490, 490, 492, 491, 493, - 491, 494, 494, 495, 495, 496, 496, 497, 497, 498, - 499, 499, 500, 500, 501, 501, 503, 502, 504, 504, - 505, 505, 506, 506, 508, 507, 509, 507, 510, 507, - 511, 511, 512, 512, 513, 513, 514, 514, 514, 514, - 514, 515, 515, 516, 516, 516, 518, 517, 519, 520, - 520, 521, 521 -}; - - /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 1, 1, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, - 3, 2, 2, 1, 1, 1, 2, 2, 2, 1, - 2, 3, 2, 1, 1, 1, 1, 2, 2, 2, - 1, 1, 1, 1, 1, 3, 3, 3, 1, 3, - 3, 1, 3, 3, 1, 3, 3, 3, 3, 1, - 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 0, 6, 1, 3, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 3, 1, 2, 2, 4, 2, 3, 4, 2, - 3, 4, 0, 6, 2, 3, 2, 1, 1, 2, - 3, 3, 2, 3, 2, 1, 2, 1, 1, 1, - 3, 4, 6, 5, 1, 2, 3, 5, 4, 1, - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 4, 1, 3, 1, 3, 1, 1, 1, 2, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 4, 1, 1, 3, 2, 3, - 2, 3, 3, 4, 1, 0, 3, 1, 3, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 6, 0, 5, 1, 2, 3, 4, - 1, 3, 1, 2, 1, 3, 4, 1, 3, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 0, 0, 5, 1, 1, 0, 2, 0, - 2, 2, 3, 1, 2, 1, 2, 1, 2, 5, - 3, 1, 1, 4, 1, 2, 0, 8, 0, 1, - 3, 2, 1, 2, 0, 6, 0, 8, 0, 7, - 1, 1, 1, 0, 2, 3, 2, 2, 2, 3, - 2, 1, 2, 1, 1, 1, 0, 3, 5, 1, - 3, 1, 4 -}; - - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (pParseContext, YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (0) - -/* Error token number */ -#define YYTERROR 1 -#define YYERRCODE 256 - - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - -/* This macro is provided for backward compatibility. */ -#ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -#endif - - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value, pParseContext); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - - -/*----------------------------------------. -| Print this symbol's value on YYOUTPUT. | -`----------------------------------------*/ - -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext) -{ - FILE *yyo = yyoutput; - YYUSE (yyo); - YYUSE (pParseContext); - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - YYUSE (yytype); -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext) -{ - YYFPRINTF (yyoutput, "%s %s (", - yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep, pParseContext); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -static void -yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, glslang::TParseContext* pParseContext) -{ - unsigned long int yylno = yyrline[yyrule]; - int yynrhs = yyr2[yyrule]; - int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, - yystos[yyssp[yyi + 1 - yynrhs]], - &(yyvsp[(yyi + 1) - (yynrhs)]) - , pParseContext); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyssp, yyvsp, Rule, pParseContext); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -yystrlen (const char *yystr) -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -yystpcpy (char *yydest, const char *yysrc) -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) -{ - YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = YY_NULLPTR; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } - } - - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } - - { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } - - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; -} -#endif /* YYERROR_VERBOSE */ - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, glslang::TParseContext* pParseContext) -{ - YYUSE (yyvaluep); - YYUSE (pParseContext); - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yytype); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - - - -/*----------. -| yyparse. | -`----------*/ - -int -yyparse (glslang::TParseContext* pParseContext) -{ -/* The lookahead symbol. */ -int yychar; - - -/* The semantic value of the lookahead symbol. */ -/* Default value used for initialization, for pacifying older GCCs - or non-GCC compilers. */ -YY_INITIAL_VALUE (static YYSTYPE yyval_default;) -YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); - - /* Number of syntax errors so far. */ - int yynerrs; - - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - 'yyss': related to states. - 'yyvs': related to semantic values. - - Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - - int yyn; - int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; - yystacksize = YYINITDEPTH; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = yylex (&yylval, parseContext); - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yytable_value_is_error (yyn)) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the lookahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token. */ - yychar = YYEMPTY; - - yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - '$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 2: -#line 352 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleVariable((yyvsp[0].lex).loc, (yyvsp[0].lex).symbol, (yyvsp[0].lex).string); - } -#line 4172 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 3: -#line 358 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } -#line 4180 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 4: -#line 361 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); - if ((yyval.interm.intermTypedNode)->getAsConstantUnion()) - (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); - } -#line 4190 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 5: -#line 366 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); - } -#line 4198 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 6: -#line 369 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); - } -#line 4206 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 7: -#line 372 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); - } -#line 4215 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 8: -#line 376 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); - } -#line 4223 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 9: -#line 380 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); - } -#line 4232 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 10: -#line 384 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); - } -#line 4241 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 11: -#line 388 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i64, (yyvsp[0].lex).loc, true); - } -#line 4250 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 12: -#line 392 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u64, (yyvsp[0].lex).loc, true); - } -#line 4259 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 13: -#line 396 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit integer literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((short)(yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); - } -#line 4268 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 14: -#line 400 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit unsigned integer literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((unsigned short)(yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); - } -#line 4277 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 15: -#line 404 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtDouble, (yyvsp[0].lex).loc, true); - } -#line 4286 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 16: -#line 408 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float literal"); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat16, (yyvsp[0].lex).loc, true); - } -#line 4295 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 17: -#line 416 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } -#line 4303 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 18: -#line 419 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBracketDereference((yyvsp[-2].lex).loc, (yyvsp[-3].interm.intermTypedNode), (yyvsp[-1].interm.intermTypedNode)); - } -#line 4311 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 19: -#line 422 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } -#line 4319 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 20: -#line 425 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleDotDereference((yyvsp[0].lex).loc, (yyvsp[-2].interm.intermTypedNode), *(yyvsp[0].lex).string); - } -#line 4327 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 21: -#line 428 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); - parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "++", (yyvsp[-1].interm.intermTypedNode)); - (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "++", EOpPostIncrement, (yyvsp[-1].interm.intermTypedNode)); - } -#line 4337 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 22: -#line 433 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); - parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "--", (yyvsp[-1].interm.intermTypedNode)); - (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "--", EOpPostDecrement, (yyvsp[-1].interm.intermTypedNode)); - } -#line 4347 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 23: -#line 441 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.integerCheck((yyvsp[0].interm.intermTypedNode), "[]"); - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } -#line 4356 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 24: -#line 448 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleFunctionCall((yyvsp[0].interm).loc, (yyvsp[0].interm).function, (yyvsp[0].interm).intermNode); - delete (yyvsp[0].interm).function; - } -#line 4365 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 25: -#line 455 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - } -#line 4373 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 26: -#line 461 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-1].interm); - (yyval.interm).loc = (yyvsp[0].lex).loc; - } -#line 4382 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 27: -#line 465 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-1].interm); - (yyval.interm).loc = (yyvsp[0].lex).loc; - } -#line 4391 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 28: -#line 472 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-1].interm); - } -#line 4399 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 29: -#line 475 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - } -#line 4407 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 30: -#line 481 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - TParameter param = { 0, new TType }; - param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); - (yyvsp[-1].interm).function->addParameter(param); - (yyval.interm).function = (yyvsp[-1].interm).function; - (yyval.interm).intermNode = (yyvsp[0].interm.intermTypedNode); - } -#line 4419 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 31: -#line 488 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - TParameter param = { 0, new TType }; - param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); - (yyvsp[-2].interm).function->addParameter(param); - (yyval.interm).function = (yyvsp[-2].interm).function; - (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); - } -#line 4431 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 32: -#line 498 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-1].interm); - } -#line 4439 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 33: -#line 506 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // Constructor - (yyval.interm).intermNode = 0; - (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); - } -#line 4449 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 34: -#line 511 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // - // Should be a method or subroutine call, but we haven't recognized the arguments yet. - // - (yyval.interm).function = 0; - (yyval.interm).intermNode = 0; - - TIntermMethod* method = (yyvsp[0].interm.intermTypedNode)->getAsMethodNode(); - if (method) { - (yyval.interm).function = new TFunction(&method->getMethodName(), TType(EbtInt), EOpArrayLength); - (yyval.interm).intermNode = method->getObject(); - } else { - TIntermSymbol* symbol = (yyvsp[0].interm.intermTypedNode)->getAsSymbolNode(); - if (symbol) { - parseContext.reservedErrorCheck(symbol->getLoc(), symbol->getName()); - TFunction *function = new TFunction(&symbol->getName(), TType(EbtVoid)); - (yyval.interm).function = function; - } else - parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "function call, method, or subroutine call expected", "", ""); - } - - if ((yyval.interm).function == 0) { - // error recover - TString* empty = NewPoolTString(""); - (yyval.interm).function = new TFunction(empty, TType(EbtVoid), EOpNull); - } - } -#line 4481 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 35: -#line 539 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // Constructor - (yyval.interm).intermNode = 0; - (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); - } -#line 4491 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 36: -#line 548 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.variableCheck((yyvsp[0].interm.intermTypedNode)); - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - if (TIntermMethod* method = (yyvsp[0].interm.intermTypedNode)->getAsMethodNode()) - parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "incomplete method syntax", method->getMethodName().c_str(), ""); - } -#line 4502 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 37: -#line 554 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "++", (yyvsp[0].interm.intermTypedNode)); - (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "++", EOpPreIncrement, (yyvsp[0].interm.intermTypedNode)); - } -#line 4511 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 38: -#line 558 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "--", (yyvsp[0].interm.intermTypedNode)); - (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "--", EOpPreDecrement, (yyvsp[0].interm.intermTypedNode)); - } -#line 4520 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 39: -#line 562 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-1].interm).op != EOpNull) { - char errorOp[2] = {0, 0}; - switch((yyvsp[-1].interm).op) { - case EOpNegative: errorOp[0] = '-'; break; - case EOpLogicalNot: errorOp[0] = '!'; break; - case EOpBitwiseNot: errorOp[0] = '~'; break; - default: break; // some compilers want this - } - (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].interm).loc, errorOp, (yyvsp[-1].interm).op, (yyvsp[0].interm.intermTypedNode)); - } else { - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - if ((yyval.interm.intermTypedNode)->getAsConstantUnion()) - (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); - } - } -#line 4541 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 40: -#line 582 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNull; } -#line 4547 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 41: -#line 583 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNegative; } -#line 4553 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 42: -#line 584 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLogicalNot; } -#line 4559 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 43: -#line 585 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpBitwiseNot; - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise not"); } -#line 4566 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 44: -#line 591 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4572 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 45: -#line 592 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "*", EOpMul, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4582 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 46: -#line 597 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "/", EOpDiv, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4592 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 47: -#line 602 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "%"); - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "%", EOpMod, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4603 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 48: -#line 611 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4609 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 49: -#line 612 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "+", EOpAdd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4619 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 50: -#line 617 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "-", EOpSub, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4629 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 51: -#line 625 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4635 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 52: -#line 626 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift left"); - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<<", EOpLeftShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4646 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 53: -#line 632 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift right"); - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">>", EOpRightShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4657 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 54: -#line 641 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4663 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 55: -#line 642 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<", EOpLessThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4673 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 56: -#line 647 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">", EOpGreaterThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4683 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 57: -#line 652 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<=", EOpLessThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4693 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 58: -#line 657 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">=", EOpGreaterThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4703 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 59: -#line 665 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4709 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 60: -#line 666 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); - parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); - parseContext.specializationCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); - parseContext.referenceCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "==", EOpEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4723 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 61: -#line 675 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); - parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); - parseContext.specializationCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); - parseContext.referenceCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "!=", EOpNotEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4737 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 62: -#line 687 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4743 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 63: -#line 688 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise and"); - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&", EOpAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4754 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 64: -#line 697 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4760 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 65: -#line 698 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise exclusive or"); - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^", EOpExclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4771 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 66: -#line 707 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4777 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 67: -#line 708 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise inclusive or"); - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "|", EOpInclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 4788 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 68: -#line 717 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4794 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 69: -#line 718 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&&", EOpLogicalAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4804 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 70: -#line 726 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4810 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 71: -#line 727 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^^", EOpLogicalXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4820 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 72: -#line 735 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4826 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 73: -#line 736 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "||", EOpLogicalOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - if ((yyval.interm.intermTypedNode) == 0) - (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); - } -#line 4836 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 74: -#line 744 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4842 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 75: -#line 745 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - ++parseContext.controlFlowNestingLevel; - } -#line 4850 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 76: -#line 748 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - --parseContext.controlFlowNestingLevel; - parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-5].interm.intermTypedNode)); - parseContext.rValueErrorCheck((yyvsp[-4].lex).loc, "?", (yyvsp[-5].interm.intermTypedNode)); - parseContext.rValueErrorCheck((yyvsp[-1].lex).loc, ":", (yyvsp[-2].interm.intermTypedNode)); - parseContext.rValueErrorCheck((yyvsp[-1].lex).loc, ":", (yyvsp[0].interm.intermTypedNode)); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addSelection((yyvsp[-5].interm.intermTypedNode), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-4].lex).loc); - if ((yyval.interm.intermTypedNode) == 0) { - parseContext.binaryOpError((yyvsp[-4].lex).loc, ":", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } - } -#line 4867 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 77: -#line 763 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 4873 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 78: -#line 764 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.arrayObjectCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array assignment"); - parseContext.opaqueCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); - parseContext.storage16BitAssignmentCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); - parseContext.specializationCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); - parseContext.lValueErrorCheck((yyvsp[-1].interm).loc, "assign", (yyvsp[-2].interm.intermTypedNode)); - parseContext.rValueErrorCheck((yyvsp[-1].interm).loc, "assign", (yyvsp[0].interm.intermTypedNode)); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addAssign((yyvsp[-1].interm).op, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].interm).loc); - if ((yyval.interm.intermTypedNode) == 0) { - parseContext.assignError((yyvsp[-1].interm).loc, "assign", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } - } -#line 4891 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 79: -#line 780 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).loc = (yyvsp[0].lex).loc; - (yyval.interm).op = EOpAssign; - } -#line 4900 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 80: -#line 784 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).loc = (yyvsp[0].lex).loc; - (yyval.interm).op = EOpMulAssign; - } -#line 4909 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 81: -#line 788 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).loc = (yyvsp[0].lex).loc; - (yyval.interm).op = EOpDivAssign; - } -#line 4918 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 82: -#line 792 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "%="); - (yyval.interm).loc = (yyvsp[0].lex).loc; - (yyval.interm).op = EOpModAssign; - } -#line 4928 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 83: -#line 797 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).loc = (yyvsp[0].lex).loc; - (yyval.interm).op = EOpAddAssign; - } -#line 4937 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 84: -#line 801 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).loc = (yyvsp[0].lex).loc; - (yyval.interm).op = EOpSubAssign; - } -#line 4946 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 85: -#line 805 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift left assign"); - (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLeftShiftAssign; - } -#line 4955 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 86: -#line 809 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift right assign"); - (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpRightShiftAssign; - } -#line 4964 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 87: -#line 813 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-and assign"); - (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAndAssign; - } -#line 4973 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 88: -#line 817 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-xor assign"); - (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpExclusiveOrAssign; - } -#line 4982 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 89: -#line 821 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-or assign"); - (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpInclusiveOrAssign; - } -#line 4991 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 90: -#line 828 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } -#line 4999 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 91: -#line 831 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.samplerConstructorLocationCheck((yyvsp[-1].lex).loc, ",", (yyvsp[0].interm.intermTypedNode)); - (yyval.interm.intermTypedNode) = parseContext.intermediate.addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); - if ((yyval.interm.intermTypedNode) == 0) { - parseContext.binaryOpError((yyvsp[-1].lex).loc, ",", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } - } -#line 5012 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 92: -#line 842 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.constantValueCheck((yyvsp[0].interm.intermTypedNode), ""); - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } -#line 5021 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 93: -#line 849 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.handleFunctionDeclarator((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).function, true /* prototype */); - (yyval.interm.intermNode) = 0; - // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature - } -#line 5031 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 94: -#line 854 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-1].interm).intermNode && (yyvsp[-1].interm).intermNode->getAsAggregate()) - (yyvsp[-1].interm).intermNode->getAsAggregate()->setOperator(EOpSequence); - (yyval.interm.intermNode) = (yyvsp[-1].interm).intermNode; - } -#line 5041 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 95: -#line 859 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.profileRequires((yyvsp[-3].lex).loc, ENoProfile, 130, 0, "precision statement"); - // lazy setting of the previous scope's defaults, has effect only the first time it is called in a particular scope - parseContext.symbolTable.setPreviousDefaultPrecisions(&parseContext.defaultPrecision[0]); - parseContext.setDefaultPrecision((yyvsp[-3].lex).loc, (yyvsp[-1].interm.type), (yyvsp[-2].interm.type).qualifier.precision); - (yyval.interm.intermNode) = 0; - } -#line 5053 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 96: -#line 866 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.declareBlock((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).typeList); - (yyval.interm.intermNode) = 0; - } -#line 5062 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 97: -#line 870 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.declareBlock((yyvsp[-2].interm).loc, *(yyvsp[-2].interm).typeList, (yyvsp[-1].lex).string); - (yyval.interm.intermNode) = 0; - } -#line 5071 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 98: -#line 874 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.declareBlock((yyvsp[-3].interm).loc, *(yyvsp[-3].interm).typeList, (yyvsp[-2].lex).string, (yyvsp[-1].interm).arraySizes); - (yyval.interm.intermNode) = 0; - } -#line 5080 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 99: -#line 878 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); - parseContext.updateStandaloneQualifierDefaults((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type)); - (yyval.interm.intermNode) = 0; - } -#line 5090 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 100: -#line 883 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.checkNoShaderLayouts((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).shaderQualifiers); - parseContext.addQualifierToExisting((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, *(yyvsp[-1].lex).string); - (yyval.interm.intermNode) = 0; - } -#line 5100 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 101: -#line 888 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.checkNoShaderLayouts((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).shaderQualifiers); - (yyvsp[-1].interm.identifierList)->push_back((yyvsp[-2].lex).string); - parseContext.addQualifierToExisting((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).qualifier, *(yyvsp[-1].interm.identifierList)); - (yyval.interm.intermNode) = 0; - } -#line 5111 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 102: -#line 897 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { parseContext.nestedBlockCheck((yyvsp[-2].interm.type).loc); } -#line 5117 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 103: -#line 897 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - --parseContext.structNestingLevel; - parseContext.blockName = (yyvsp[-4].lex).string; - parseContext.globalQualifierFixCheck((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).qualifier); - parseContext.checkNoShaderLayouts((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).shaderQualifiers); - parseContext.currentBlockQualifier = (yyvsp[-5].interm.type).qualifier; - (yyval.interm).loc = (yyvsp[-5].interm.type).loc; - (yyval.interm).typeList = (yyvsp[-1].interm.typeList); - } -#line 5131 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 104: -#line 908 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.identifierList) = new TIdentifierList; - (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); - } -#line 5140 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 105: -#line 912 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.identifierList) = (yyvsp[-2].interm.identifierList); - (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); - } -#line 5149 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 106: -#line 919 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).function = (yyvsp[-1].interm.function); - (yyval.interm).loc = (yyvsp[0].lex).loc; - } -#line 5158 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 107: -#line 926 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.function) = (yyvsp[0].interm.function); - } -#line 5166 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 108: -#line 929 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.function) = (yyvsp[0].interm.function); - } -#line 5174 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 109: -#line 936 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // Add the parameter - (yyval.interm.function) = (yyvsp[-1].interm.function); - if ((yyvsp[0].interm).param.type->getBasicType() != EbtVoid) - (yyvsp[-1].interm.function)->addParameter((yyvsp[0].interm).param); - else - delete (yyvsp[0].interm).param.type; - } -#line 5187 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 110: -#line 944 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // - // Only first parameter of one-parameter functions can be void - // The check for named parameters not being void is done in parameter_declarator - // - if ((yyvsp[0].interm).param.type->getBasicType() == EbtVoid) { - // - // This parameter > first is void - // - parseContext.error((yyvsp[-1].lex).loc, "cannot be an argument type except for '(void)'", "void", ""); - delete (yyvsp[0].interm).param.type; - } else { - // Add the parameter - (yyval.interm.function) = (yyvsp[-2].interm.function); - (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm).param); - } - } -#line 5209 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 111: -#line 964 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-2].interm.type).qualifier.storage != EvqGlobal && (yyvsp[-2].interm.type).qualifier.storage != EvqTemporary) { - parseContext.error((yyvsp[-1].lex).loc, "no qualifiers allowed for function return", - GetStorageQualifierString((yyvsp[-2].interm.type).qualifier.storage), ""); - } - if ((yyvsp[-2].interm.type).arraySizes) - parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); - - // Add the function as a prototype after parsing it (we do not support recursion) - TFunction *function; - TType type((yyvsp[-2].interm.type)); - - // Potentially rename shader entry point function. No-op most of the time. - parseContext.renameShaderFunction((yyvsp[-1].lex).string); - - // Make the function - function = new TFunction((yyvsp[-1].lex).string, type); - (yyval.interm.function) = function; - } -#line 5233 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 112: -#line 987 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-1].interm.type).arraySizes) { - parseContext.profileRequires((yyvsp[-1].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); - parseContext.profileRequires((yyvsp[-1].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); - parseContext.arraySizeRequiredCheck((yyvsp[-1].interm.type).loc, *(yyvsp[-1].interm.type).arraySizes); - } - if ((yyvsp[-1].interm.type).basicType == EbtVoid) { - parseContext.error((yyvsp[0].lex).loc, "illegal use of type 'void'", (yyvsp[0].lex).string->c_str(), ""); - } - parseContext.reservedErrorCheck((yyvsp[0].lex).loc, *(yyvsp[0].lex).string); - - TParameter param = {(yyvsp[0].lex).string, new TType((yyvsp[-1].interm.type))}; - (yyval.interm).loc = (yyvsp[0].lex).loc; - (yyval.interm).param = param; - } -#line 5253 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 113: -#line 1002 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-2].interm.type).arraySizes) { - parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); - parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); - parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); - } - TType* type = new TType((yyvsp[-2].interm.type)); - type->transferArraySizes((yyvsp[0].interm).arraySizes); - type->copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); - - parseContext.arrayOfArrayVersionCheck((yyvsp[-1].lex).loc, type->getArraySizes()); - parseContext.arraySizeRequiredCheck((yyvsp[0].interm).loc, *(yyvsp[0].interm).arraySizes); - parseContext.reservedErrorCheck((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string); - - TParameter param = { (yyvsp[-1].lex).string, type }; - - (yyval.interm).loc = (yyvsp[-1].lex).loc; - (yyval.interm).param = param; - } -#line 5277 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 114: -#line 1027 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) - (yyval.interm).param.type->getQualifier().precision = (yyvsp[-1].interm.type).qualifier.precision; - parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); - - parseContext.checkNoShaderLayouts((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); - parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); - parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); - - } -#line 5293 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 115: -#line 1038 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - - parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); - parseContext.paramCheckFixStorage((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); - parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); - } -#line 5305 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 116: -#line 1048 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) - (yyval.interm).param.type->getQualifier().precision = (yyvsp[-1].interm.type).qualifier.precision; - parseContext.precisionQualifierCheck((yyvsp[-1].interm.type).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); - - parseContext.checkNoShaderLayouts((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); - parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); - parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); - } -#line 5320 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 117: -#line 1058 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - - parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); - parseContext.paramCheckFixStorage((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); - parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); - } -#line 5332 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 118: -#line 1068 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - TParameter param = { 0, new TType((yyvsp[0].interm.type)) }; - (yyval.interm).param = param; - if ((yyvsp[0].interm.type).arraySizes) - parseContext.arraySizeRequiredCheck((yyvsp[0].interm.type).loc, *(yyvsp[0].interm.type).arraySizes); - } -#line 5343 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 119: -#line 1077 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[0].interm); - } -#line 5351 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 120: -#line 1080 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-2].interm); - parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-2].interm).type); - } -#line 5360 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 121: -#line 1084 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-3].interm); - parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-3].interm).type, (yyvsp[0].interm).arraySizes); - } -#line 5369 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 122: -#line 1088 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).type = (yyvsp[-5].interm).type; - TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-5].interm).type, (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); - (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-5].interm).intermNode, initNode, (yyvsp[-1].lex).loc); - } -#line 5379 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 123: -#line 1093 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).type = (yyvsp[-4].interm).type; - TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-4].interm).type, 0, (yyvsp[0].interm.intermTypedNode)); - (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-4].interm).intermNode, initNode, (yyvsp[-1].lex).loc); - } -#line 5389 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 124: -#line 1101 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).type = (yyvsp[0].interm.type); - (yyval.interm).intermNode = 0; - - parseContext.declareTypeDefaults((yyval.interm).loc, (yyval.interm).type); - - } -#line 5401 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 125: -#line 1108 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).type = (yyvsp[-1].interm.type); - (yyval.interm).intermNode = 0; - parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-1].interm.type)); - } -#line 5411 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 126: -#line 1113 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).type = (yyvsp[-2].interm.type); - (yyval.interm).intermNode = 0; - parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-2].interm.type), (yyvsp[0].interm).arraySizes); - } -#line 5421 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 127: -#line 1118 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).type = (yyvsp[-4].interm.type); - TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-4].interm.type), (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); - (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); - } -#line 5431 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 128: -#line 1123 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).type = (yyvsp[-3].interm.type); - TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), 0, (yyvsp[0].interm.intermTypedNode)); - (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); - } -#line 5441 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 129: -#line 1132 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[0].interm.type); - - parseContext.globalQualifierTypeCheck((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier, (yyval.interm.type)); - if ((yyvsp[0].interm.type).arraySizes) { - parseContext.profileRequires((yyvsp[0].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); - parseContext.profileRequires((yyvsp[0].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); - } - parseContext.precisionQualifierCheck((yyval.interm.type).loc, (yyval.interm.type).basicType, (yyval.interm.type).qualifier); - } -#line 5456 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 130: -#line 1142 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); - parseContext.globalQualifierTypeCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, (yyvsp[0].interm.type)); - - if ((yyvsp[0].interm.type).arraySizes) { - parseContext.profileRequires((yyvsp[0].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); - parseContext.profileRequires((yyvsp[0].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); - } - - if ((yyvsp[0].interm.type).arraySizes && parseContext.arrayQualifierError((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).qualifier)) - (yyvsp[0].interm.type).arraySizes = nullptr; - - parseContext.checkNoShaderLayouts((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); - (yyvsp[0].interm.type).shaderQualifiers.merge((yyvsp[-1].interm.type).shaderQualifiers); - parseContext.mergeQualifiers((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier, (yyvsp[-1].interm.type).qualifier, true); - parseContext.precisionQualifierCheck((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).basicType, (yyvsp[0].interm.type).qualifier); - - (yyval.interm.type) = (yyvsp[0].interm.type); - - if (! (yyval.interm.type).qualifier.isInterpolation() && - ((parseContext.language == EShLangVertex && (yyval.interm.type).qualifier.storage == EvqVaryingOut) || - (parseContext.language == EShLangFragment && (yyval.interm.type).qualifier.storage == EvqVaryingIn))) - (yyval.interm.type).qualifier.smooth = true; - } -#line 5485 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 131: -#line 1169 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "invariant"); - parseContext.profileRequires((yyval.interm.type).loc, ENoProfile, 120, 0, "invariant"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.invariant = true; - } -#line 5496 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 132: -#line 1178 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "smooth"); - parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "smooth"); - parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "smooth"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.smooth = true; - } -#line 5508 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 133: -#line 1185 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "flat"); - parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "flat"); - parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "flat"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.flat = true; - } -#line 5520 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 134: -#line 1193 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "noperspective"); - parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 0, E_GL_NV_shader_noperspective_interpolation, "noperspective"); - parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "noperspective"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.nopersp = true; - } -#line 5532 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 135: -#line 1200 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "__explicitInterpAMD"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECompatibilityProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.explicitInterp = true; - } -#line 5544 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 136: -#line 1207 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "pervertexNV"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 0, E_GL_NV_fragment_shader_barycentric, "fragment shader barycentric"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECompatibilityProfile, 0, E_GL_NV_fragment_shader_barycentric, "fragment shader barycentric"); - parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 0, E_GL_NV_fragment_shader_barycentric, "fragment shader barycentric"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.pervertexNV = true; - } -#line 5557 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 137: -#line 1215 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // No need for profile version or extension check. Shader stage already checks both. - parseContext.globalCheck((yyvsp[0].lex).loc, "perprimitiveNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangFragmentMask | EShLangMeshNVMask), "perprimitiveNV"); - // Fragment shader stage doesn't check for extension. So we explicitly add below extension check. - if (parseContext.language == EShLangFragment) - parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_NV_mesh_shader, "perprimitiveNV"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.perPrimitiveNV = true; - } -#line 5572 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 138: -#line 1225 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // No need for profile version or extension check. Shader stage already checks both. - parseContext.globalCheck((yyvsp[0].lex).loc, "perviewNV"); - parseContext.requireStage((yyvsp[0].lex).loc, EShLangMeshNV, "perviewNV"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.perViewNV = true; - } -#line 5584 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 139: -#line 1232 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // No need for profile version or extension check. Shader stage already checks both. - parseContext.globalCheck((yyvsp[0].lex).loc, "taskNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTaskNVMask | EShLangMeshNVMask), "taskNV"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.perTaskNV = true; - } -#line 5596 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 140: -#line 1243 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[-1].interm.type); - } -#line 5604 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 141: -#line 1249 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5612 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 142: -#line 1252 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[-2].interm.type); - (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); - parseContext.mergeObjectLayoutQualifiers((yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); - } -#line 5622 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 143: -#line 1259 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), *(yyvsp[0].lex).string); - } -#line 5631 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 144: -#line 1263 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[-2].lex).loc); - parseContext.setLayoutQualifier((yyvsp[-2].lex).loc, (yyval.interm.type), *(yyvsp[-2].lex).string, (yyvsp[0].interm.intermTypedNode)); - } -#line 5640 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 145: -#line 1267 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { // because "shared" is both an identifier and a keyword - (yyval.interm.type).init((yyvsp[0].lex).loc); - TString strShared("shared"); - parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), strShared); - } -#line 5650 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 146: -#line 1276 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.profileRequires((yyval.interm.type).loc, ECoreProfile | ECompatibilityProfile, 400, E_GL_ARB_gpu_shader5, "precise"); - parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, "precise"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.noContraction = true; - } -#line 5661 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 147: -#line 1286 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5669 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 148: -#line 1289 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[-1].interm.type); - if ((yyval.interm.type).basicType == EbtVoid) - (yyval.interm.type).basicType = (yyvsp[0].interm.type).basicType; - - (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); - parseContext.mergeQualifiers((yyval.interm.type).loc, (yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); - } -#line 5682 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 149: -#line 1300 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5690 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 150: -#line 1303 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5698 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 151: -#line 1306 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.checkPrecisionQualifier((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier.precision); - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5707 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 152: -#line 1310 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // allow inheritance of storage qualifier from block declaration - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5716 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 153: -#line 1314 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // allow inheritance of storage qualifier from block declaration - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5725 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 154: -#line 1319 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // allow inheritance of storage qualifier from block declaration - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5734 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 155: -#line 1323 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[0].interm.type); - } -#line 5742 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 156: -#line 1330 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqConst; // will later turn into EvqConstReadOnly, if the initializer is not constant - } -#line 5751 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 157: -#line 1334 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "inout"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqInOut; - } -#line 5761 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 158: -#line 1339 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "in"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - // whether this is a parameter "in" or a pipeline "in" will get sorted out a bit later - (yyval.interm.type).qualifier.storage = EvqIn; - } -#line 5772 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 159: -#line 1345 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "out"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - // whether this is a parameter "out" or a pipeline "out" will get sorted out a bit later - (yyval.interm.type).qualifier.storage = EvqOut; - } -#line 5783 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 160: -#line 1351 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 120, 0, "centroid"); - parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "centroid"); - parseContext.globalCheck((yyvsp[0].lex).loc, "centroid"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.centroid = true; - } -#line 5795 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 161: -#line 1358 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "uniform"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqUniform; - } -#line 5805 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 162: -#line 1363 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "shared"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_compute_shader, "shared"); - parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 310, 0, "shared"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangComputeMask | EShLangMeshNVMask | EShLangTaskNVMask), "shared"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqShared; - } -#line 5818 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 163: -#line 1371 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "buffer"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqBuffer; - } -#line 5828 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 164: -#line 1377 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[0].lex).loc, EShLangVertex, "attribute"); - parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "attribute"); - parseContext.checkDeprecated((yyvsp[0].lex).loc, ENoProfile, 130, "attribute"); - parseContext.requireNotRemoved((yyvsp[0].lex).loc, ECoreProfile, 420, "attribute"); - parseContext.requireNotRemoved((yyvsp[0].lex).loc, EEsProfile, 300, "attribute"); - - parseContext.globalCheck((yyvsp[0].lex).loc, "attribute"); - - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqVaryingIn; - } -#line 5845 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 165: -#line 1389 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.checkDeprecated((yyvsp[0].lex).loc, ENoProfile, 130, "varying"); - parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "varying"); - parseContext.requireNotRemoved((yyvsp[0].lex).loc, ECoreProfile, 420, "varying"); - parseContext.requireNotRemoved((yyvsp[0].lex).loc, EEsProfile, 300, "varying"); - - parseContext.globalCheck((yyvsp[0].lex).loc, "varying"); - - (yyval.interm.type).init((yyvsp[0].lex).loc); - if (parseContext.language == EShLangVertex) - (yyval.interm.type).qualifier.storage = EvqVaryingOut; - else - (yyval.interm.type).qualifier.storage = EvqVaryingIn; - } -#line 5864 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 166: -#line 1403 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "patch"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTessControlMask | EShLangTessEvaluationMask), "patch"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.patch = true; - } -#line 5875 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 167: -#line 1409 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "sample"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.sample = true; - } -#line 5885 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 168: -#line 1414 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "hitAttributeNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangIntersectNVMask | EShLangClosestHitNVMask - | EShLangAnyHitNVMask), "hitAttributeNV"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "hitAttributeNV"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqHitAttrNV; - } -#line 5898 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 169: -#line 1422 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenNVMask | EShLangClosestHitNVMask | - EShLangAnyHitNVMask | EShLangMissNVMask), "rayPayloadNV"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "rayPayloadNV"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqPayloadNV; - } -#line 5911 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 170: -#line 1430 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadInNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangClosestHitNVMask | - EShLangAnyHitNVMask | EShLangMissNVMask), "rayPayloadInNV"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "rayPayloadInNV"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqPayloadInNV; - } -#line 5924 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 171: -#line 1438 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenNVMask | - EShLangClosestHitNVMask | EShLangMissNVMask | EShLangCallableNVMask), "callableDataNV"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "callableDataNV"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqCallableDataNV; - } -#line 5937 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 172: -#line 1446 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataInNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangCallableNVMask), "callableDataInNV"); - parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_ray_tracing, "callableDataInNV"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.storage = EvqCallableDataInNV; - } -#line 5949 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 173: -#line 1453 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.coherent = true; - } -#line 5958 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 174: -#line 1457 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "devicecoherent"); - (yyval.interm.type).qualifier.devicecoherent = true; - } -#line 5968 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 175: -#line 1462 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "queuefamilycoherent"); - (yyval.interm.type).qualifier.queuefamilycoherent = true; - } -#line 5978 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 176: -#line 1467 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "workgroupcoherent"); - (yyval.interm.type).qualifier.workgroupcoherent = true; - } -#line 5988 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 177: -#line 1472 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "subgroupcoherent"); - (yyval.interm.type).qualifier.subgroupcoherent = true; - } -#line 5998 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 178: -#line 1477 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "nonprivate"); - (yyval.interm.type).qualifier.nonprivate = true; - } -#line 6008 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 179: -#line 1482 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.volatil = true; - } -#line 6017 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 180: -#line 1486 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.restrict = true; - } -#line 6026 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 181: -#line 1490 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.readonly = true; - } -#line 6035 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 182: -#line 1494 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.writeonly = true; - } -#line 6044 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 183: -#line 1498 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.spvRemoved((yyvsp[0].lex).loc, "subroutine"); - parseContext.globalCheck((yyvsp[0].lex).loc, "subroutine"); - parseContext.unimplemented((yyvsp[0].lex).loc, "subroutine"); - (yyval.interm.type).init((yyvsp[0].lex).loc); - } -#line 6055 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 184: -#line 1504 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.spvRemoved((yyvsp[-3].lex).loc, "subroutine"); - parseContext.globalCheck((yyvsp[-3].lex).loc, "subroutine"); - parseContext.unimplemented((yyvsp[-3].lex).loc, "subroutine"); - (yyval.interm.type).init((yyvsp[-3].lex).loc); - } -#line 6066 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 185: -#line 1515 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc); - (yyval.interm.type).qualifier.nonUniform = true; - } -#line 6075 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 186: -#line 1522 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // TODO - } -#line 6083 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 187: -#line 1525 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // TODO: 4.0 semantics: subroutines - // 1) make sure each identifier is a type declared earlier with SUBROUTINE - // 2) save all of the identifiers for future comparison with the declared function - } -#line 6093 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 188: -#line 1534 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[-1].interm.type); - (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); - (yyval.interm.type).typeParameters = (yyvsp[0].interm.typeParameters); - } -#line 6103 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 189: -#line 1539 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.arrayOfArrayVersionCheck((yyvsp[0].interm).loc, (yyvsp[0].interm).arraySizes); - (yyval.interm.type) = (yyvsp[-2].interm.type); - (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); - (yyval.interm.type).typeParameters = (yyvsp[-1].interm.typeParameters); - (yyval.interm.type).arraySizes = (yyvsp[0].interm).arraySizes; - } -#line 6115 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 190: -#line 1549 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).loc = (yyvsp[-1].lex).loc; - (yyval.interm).arraySizes = new TArraySizes; - (yyval.interm).arraySizes->addInnerSize(); - } -#line 6125 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 191: -#line 1554 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm).loc = (yyvsp[-2].lex).loc; - (yyval.interm).arraySizes = new TArraySizes; - - TArraySize size; - parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size, "array size"); - (yyval.interm).arraySizes->addInnerSize(size); - } -#line 6138 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 192: -#line 1562 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-2].interm); - (yyval.interm).arraySizes->addInnerSize(); - } -#line 6147 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 193: -#line 1566 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm) = (yyvsp[-3].interm); - - TArraySize size; - parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size, "array size"); - (yyval.interm).arraySizes->addInnerSize(size); - } -#line 6159 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 194: -#line 1576 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeParameters) = (yyvsp[0].interm.typeParameters); - } -#line 6167 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 195: -#line 1579 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeParameters) = 0; - } -#line 6175 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 196: -#line 1585 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeParameters) = (yyvsp[-1].interm.typeParameters); - } -#line 6183 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 197: -#line 1591 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeParameters) = new TArraySizes; - - TArraySize size; - parseContext.arraySizeCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode), size, "type parameter"); - (yyval.interm.typeParameters)->addInnerSize(size); - } -#line 6195 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 198: -#line 1598 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeParameters) = (yyvsp[-2].interm.typeParameters); - - TArraySize size; - parseContext.arraySizeCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode), size, "type parameter"); - (yyval.interm.typeParameters)->addInnerSize(size); - } -#line 6207 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 199: -#line 1608 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtVoid; - } -#line 6216 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 200: -#line 1612 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - } -#line 6225 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 201: -#line 1616 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - } -#line 6234 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 202: -#line 1620 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - } -#line 6244 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 203: -#line 1625 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - } -#line 6253 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 204: -#line 1629 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(2); - } -#line 6263 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 205: -#line 1634 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(3); - } -#line 6273 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 206: -#line 1639 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(4); - } -#line 6283 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 207: -#line 1644 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(2); - } -#line 6293 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 208: -#line 1649 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(3); - } -#line 6303 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 209: -#line 1654 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(4); - } -#line 6313 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 210: -#line 1659 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(2); - } -#line 6323 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 211: -#line 1664 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(3); - } -#line 6333 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 212: -#line 1669 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(4); - } -#line 6343 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 213: -#line 1674 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(2); - } -#line 6354 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 214: -#line 1680 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(3); - } -#line 6365 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 215: -#line 1686 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(4); - } -#line 6376 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 216: -#line 1692 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(2, 2); - } -#line 6386 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 217: -#line 1697 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(3, 3); - } -#line 6396 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 218: -#line 1702 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(4, 4); - } -#line 6406 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 219: -#line 1707 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(2, 2); - } -#line 6416 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 220: -#line 1712 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(2, 3); - } -#line 6426 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 221: -#line 1717 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(2, 4); - } -#line 6436 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 222: -#line 1722 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(3, 2); - } -#line 6446 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 223: -#line 1727 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(3, 3); - } -#line 6456 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 224: -#line 1732 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(3, 4); - } -#line 6466 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 225: -#line 1737 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(4, 2); - } -#line 6476 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 226: -#line 1742 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(4, 3); - } -#line 6486 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 227: -#line 1747 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(4, 4); - } -#line 6496 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 228: -#line 1753 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - } -#line 6506 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 229: -#line 1758 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "float16_t", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - } -#line 6516 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 230: -#line 1763 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - } -#line 6526 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 231: -#line 1768 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - } -#line 6536 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 232: -#line 1773 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt8; - } -#line 6546 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 233: -#line 1778 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint8; - } -#line 6556 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 234: -#line 1783 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt16; - } -#line 6566 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 235: -#line 1788 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint16; - } -#line 6576 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 236: -#line 1793 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - } -#line 6586 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 237: -#line 1798 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - } -#line 6596 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 238: -#line 1803 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt64; - } -#line 6606 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 239: -#line 1808 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint64; - } -#line 6616 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 240: -#line 1813 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(2); - } -#line 6627 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 241: -#line 1819 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(3); - } -#line 6638 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 242: -#line 1825 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(4); - } -#line 6649 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 243: -#line 1831 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setVector(2); - } -#line 6660 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 244: -#line 1837 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setVector(3); - } -#line 6671 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 245: -#line 1843 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setVector(4); - } -#line 6682 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 246: -#line 1849 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(2); - } -#line 6693 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 247: -#line 1855 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(3); - } -#line 6704 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 248: -#line 1861 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(4); - } -#line 6715 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 249: -#line 1867 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(2); - } -#line 6726 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 250: -#line 1873 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(3); - } -#line 6737 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 251: -#line 1879 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(4); - } -#line 6748 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 252: -#line 1885 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt8; - (yyval.interm.type).setVector(2); - } -#line 6759 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 253: -#line 1891 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt8; - (yyval.interm.type).setVector(3); - } -#line 6770 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 254: -#line 1897 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt8; - (yyval.interm.type).setVector(4); - } -#line 6781 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 255: -#line 1903 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt16; - (yyval.interm.type).setVector(2); - } -#line 6792 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 256: -#line 1909 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt16; - (yyval.interm.type).setVector(3); - } -#line 6803 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 257: -#line 1915 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt16; - (yyval.interm.type).setVector(4); - } -#line 6814 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 258: -#line 1921 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(2); - } -#line 6825 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 259: -#line 1927 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(3); - } -#line 6836 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 260: -#line 1933 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).setVector(4); - } -#line 6847 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 261: -#line 1939 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt64; - (yyval.interm.type).setVector(2); - } -#line 6858 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 262: -#line 1945 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt64; - (yyval.interm.type).setVector(3); - } -#line 6869 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 263: -#line 1951 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt64; - (yyval.interm.type).setVector(4); - } -#line 6880 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 264: -#line 1957 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint8; - (yyval.interm.type).setVector(2); - } -#line 6891 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 265: -#line 1963 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint8; - (yyval.interm.type).setVector(3); - } -#line 6902 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 266: -#line 1969 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint8; - (yyval.interm.type).setVector(4); - } -#line 6913 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 267: -#line 1975 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint16; - (yyval.interm.type).setVector(2); - } -#line 6924 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 268: -#line 1981 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint16; - (yyval.interm.type).setVector(3); - } -#line 6935 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 269: -#line 1987 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint16; - (yyval.interm.type).setVector(4); - } -#line 6946 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 270: -#line 1993 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(2); - } -#line 6957 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 271: -#line 1999 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(3); - } -#line 6968 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 272: -#line 2005 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(4); - } -#line 6979 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 273: -#line 2011 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint64; - (yyval.interm.type).setVector(2); - } -#line 6990 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 274: -#line 2017 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint64; - (yyval.interm.type).setVector(3); - } -#line 7001 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 275: -#line 2023 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint64; - (yyval.interm.type).setVector(4); - } -#line 7012 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 276: -#line 2029 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 2); - } -#line 7023 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 277: -#line 2035 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 3); - } -#line 7034 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 278: -#line 2041 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 4); - } -#line 7045 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 279: -#line 2047 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 2); - } -#line 7056 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 280: -#line 2053 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 3); - } -#line 7067 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 281: -#line 2059 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 4); - } -#line 7078 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 282: -#line 2065 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 2); - } -#line 7089 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 283: -#line 2071 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 3); - } -#line 7100 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 284: -#line 2077 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 4); - } -#line 7111 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 285: -#line 2083 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 2); - } -#line 7122 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 286: -#line 2089 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 3); - } -#line 7133 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 287: -#line 2095 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 4); - } -#line 7144 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 288: -#line 2101 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(2, 2); - } -#line 7155 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 289: -#line 2107 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(3, 3); - } -#line 7166 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 290: -#line 2113 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(4, 4); - } -#line 7177 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 291: -#line 2119 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(2, 2); - } -#line 7188 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 292: -#line 2125 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(2, 3); - } -#line 7199 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 293: -#line 2131 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(2, 4); - } -#line 7210 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 294: -#line 2137 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(3, 2); - } -#line 7221 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 295: -#line 2143 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(3, 3); - } -#line 7232 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 296: -#line 2149 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(3, 4); - } -#line 7243 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 297: -#line 2155 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(4, 2); - } -#line 7254 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 298: -#line 2161 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(4, 3); - } -#line 7265 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 299: -#line 2167 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(4, 4); - } -#line 7276 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 300: -#line 2173 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(2, 2); - } -#line 7287 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 301: -#line 2179 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(3, 3); - } -#line 7298 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 302: -#line 2185 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(4, 4); - } -#line 7309 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 303: -#line 2191 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(2, 2); - } -#line 7320 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 304: -#line 2197 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(2, 3); - } -#line 7331 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 305: -#line 2203 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(2, 4); - } -#line 7342 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 306: -#line 2209 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(3, 2); - } -#line 7353 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 307: -#line 2215 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(3, 3); - } -#line 7364 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 308: -#line 2221 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(3, 4); - } -#line 7375 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 309: -#line 2227 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(4, 2); - } -#line 7386 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 310: -#line 2233 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(4, 3); - } -#line 7397 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 311: -#line 2239 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setMatrix(4, 4); - } -#line 7408 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 312: -#line 2245 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 2); - } -#line 7419 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 313: -#line 2251 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 3); - } -#line 7430 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 314: -#line 2257 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 4); - } -#line 7441 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 315: -#line 2263 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 2); - } -#line 7452 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 316: -#line 2269 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 3); - } -#line 7463 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 317: -#line 2275 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 4); - } -#line 7474 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 318: -#line 2281 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 2); - } -#line 7485 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 319: -#line 2287 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 3); - } -#line 7496 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 320: -#line 2293 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 4); - } -#line 7507 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 321: -#line 2299 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 2); - } -#line 7518 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 322: -#line 2305 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 3); - } -#line 7529 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 323: -#line 2311 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 4); - } -#line 7540 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 324: -#line 2317 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtAccStructNV; - } -#line 7549 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 325: -#line 2321 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.vulkanRemoved((yyvsp[0].lex).loc, "atomic counter types"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtAtomicUint; - } -#line 7559 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 326: -#line 2326 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd1D); - } -#line 7569 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 327: -#line 2332 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd2D); - } -#line 7579 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 328: -#line 2337 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd3D); - } -#line 7589 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 329: -#line 2342 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, EsdCube); - } -#line 7599 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 330: -#line 2347 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, true); - } -#line 7609 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 331: -#line 2352 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, EsdCube, false, true); - } -#line 7619 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 332: -#line 2357 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true); - } -#line 7629 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 333: -#line 2362 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, true); - } -#line 7639 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 334: -#line 2368 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd1D, false, true); - } -#line 7649 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 335: -#line 2373 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true); - } -#line 7659 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 336: -#line 2378 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true, true); - } -#line 7669 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 337: -#line 2383 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true); - } -#line 7679 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 338: -#line 2388 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true, true); - } -#line 7689 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 339: -#line 2393 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd1D); - } -#line 7700 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 340: -#line 2399 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd2D); - } -#line 7711 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 341: -#line 2405 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd3D); - } -#line 7722 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 342: -#line 2411 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, EsdCube); - } -#line 7733 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 343: -#line 2417 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, false, true); - } -#line 7744 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 344: -#line 2423 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, false, true); - } -#line 7755 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 345: -#line 2429 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, false, true); - } -#line 7766 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 346: -#line 2435 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, true); - } -#line 7777 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 347: -#line 2441 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true); - } -#line 7788 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 348: -#line 2447 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, true, true); - } -#line 7799 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 349: -#line 2453 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true, true); - } -#line 7810 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 350: -#line 2459 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, true); - } -#line 7821 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 351: -#line 2465 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, true, true); - } -#line 7832 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 352: -#line 2471 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, Esd1D); - } -#line 7842 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 353: -#line 2477 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, Esd2D); - } -#line 7852 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 354: -#line 2482 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, Esd3D); - } -#line 7862 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 355: -#line 2487 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, EsdCube); - } -#line 7872 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 356: -#line 2492 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, Esd2D, true); - } -#line 7882 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 357: -#line 2497 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, Esd2D); - } -#line 7892 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 358: -#line 2502 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, Esd3D); - } -#line 7902 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 359: -#line 2507 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, EsdCube); - } -#line 7912 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 360: -#line 2513 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, Esd1D, true); - } -#line 7922 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 361: -#line 2518 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, EsdCube, true); - } -#line 7932 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 362: -#line 2523 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, Esd1D); - } -#line 7942 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 363: -#line 2528 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, Esd1D, true); - } -#line 7952 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 364: -#line 2533 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, EsdCube, true); - } -#line 7962 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 365: -#line 2538 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube, true); - } -#line 7972 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 366: -#line 2543 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube, true); - } -#line 7982 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 367: -#line 2548 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube, true); - } -#line 7992 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 368: -#line 2554 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, Esd2D, true); - } -#line 8002 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 369: -#line 2559 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D); - } -#line 8012 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 370: -#line 2564 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, Esd3D); - } -#line 8022 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 371: -#line 2569 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true); - } -#line 8032 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 372: -#line 2574 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube); - } -#line 8042 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 373: -#line 2579 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D); - } -#line 8052 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 374: -#line 2584 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, Esd3D); - } -#line 8062 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 375: -#line 2589 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube); - } -#line 8072 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 376: -#line 2594 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true); - } -#line 8082 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 377: -#line 2599 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D); - } -#line 8092 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 378: -#line 2604 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, Esd3D); - } -#line 8102 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 379: -#line 2609 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube); - } -#line 8112 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 380: -#line 2614 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true); - } -#line 8122 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 381: -#line 2619 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setPureSampler(false); - } -#line 8132 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 382: -#line 2624 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setPureSampler(true); - } -#line 8142 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 383: -#line 2630 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, EsdRect); - } -#line 8152 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 384: -#line 2635 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, EsdRect, false, true); - } -#line 8162 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 385: -#line 2640 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, EsdRect); - } -#line 8173 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 386: -#line 2646 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, EsdRect, false, true); - } -#line 8184 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 387: -#line 2652 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, EsdRect); - } -#line 8194 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 388: -#line 2657 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, EsdRect); - } -#line 8204 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 389: -#line 2662 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, EsdBuffer); - } -#line 8214 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 390: -#line 2667 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, EsdBuffer); - } -#line 8225 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 391: -#line 2673 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, EsdBuffer); - } -#line 8235 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 392: -#line 2678 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, EsdBuffer); - } -#line 8245 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 393: -#line 2683 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, false, true); - } -#line 8255 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 394: -#line 2688 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, false, false, true); - } -#line 8266 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 395: -#line 2694 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, Esd2D, false, false, true); - } -#line 8276 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 396: -#line 2699 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, Esd2D, false, false, true); - } -#line 8286 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 397: -#line 2704 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, false, true); - } -#line 8296 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 398: -#line 2709 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true, false, true); - } -#line 8307 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 399: -#line 2715 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtInt, Esd2D, true, false, true); - } -#line 8317 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 400: -#line 2720 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtUint, Esd2D, true, false, true); - } -#line 8327 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 401: -#line 2725 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D); - } -#line 8337 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 402: -#line 2730 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd1D); - } -#line 8348 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 403: -#line 2736 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D); - } -#line 8359 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 404: -#line 2742 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd3D); - } -#line 8370 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 405: -#line 2748 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdCube); - } -#line 8381 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 406: -#line 2754 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D, true); - } -#line 8391 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 407: -#line 2759 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd1D, true); - } -#line 8402 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 408: -#line 2765 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, true); - } -#line 8413 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 409: -#line 2771 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdCube, true); - } -#line 8424 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 410: -#line 2777 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D); - } -#line 8434 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 411: -#line 2782 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D, true); - } -#line 8444 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 412: -#line 2787 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D); - } -#line 8454 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 413: -#line 2792 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D, true); - } -#line 8464 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 414: -#line 2797 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, EsdRect); - } -#line 8474 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 415: -#line 2802 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdRect); - } -#line 8485 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 416: -#line 2808 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, EsdRect); - } -#line 8495 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 417: -#line 2813 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, EsdRect); - } -#line 8505 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 418: -#line 2818 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, EsdBuffer); - } -#line 8515 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 419: -#line 2823 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdBuffer); - } -#line 8526 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 420: -#line 2829 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, EsdBuffer); - } -#line 8536 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 421: -#line 2834 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, EsdBuffer); - } -#line 8546 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 422: -#line 2839 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, false, false, true); - } -#line 8556 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 423: -#line 2844 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, false, false, true); - } -#line 8567 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 424: -#line 2850 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, false, false, true); - } -#line 8577 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 425: -#line 2855 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, false, false, true); - } -#line 8587 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 426: -#line 2860 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true, false, true); - } -#line 8597 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 427: -#line 2865 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, true, false, true); - } -#line 8608 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 428: -#line 2871 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true, false, true); - } -#line 8618 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 429: -#line 2876 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true, false, true); - } -#line 8628 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 430: -#line 2881 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D); - } -#line 8638 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 431: -#line 2886 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, Esd1D); - } -#line 8649 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 432: -#line 2892 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, Esd1D); - } -#line 8659 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 433: -#line 2897 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, Esd1D); - } -#line 8669 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 434: -#line 2902 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D); - } -#line 8679 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 435: -#line 2907 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D); - } -#line 8690 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 436: -#line 2913 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, Esd2D); - } -#line 8700 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 437: -#line 2918 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, Esd2D); - } -#line 8710 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 438: -#line 2923 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, Esd3D); - } -#line 8720 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 439: -#line 2928 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, Esd3D); - } -#line 8731 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 440: -#line 2934 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, Esd3D); - } -#line 8741 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 441: -#line 2939 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, Esd3D); - } -#line 8751 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 442: -#line 2944 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, EsdRect); - } -#line 8761 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 443: -#line 2949 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, EsdRect); - } -#line 8772 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 444: -#line 2955 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, EsdRect); - } -#line 8782 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 445: -#line 2960 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, EsdRect); - } -#line 8792 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 446: -#line 2965 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube); - } -#line 8802 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 447: -#line 2970 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, EsdCube); - } -#line 8813 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 448: -#line 2976 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, EsdCube); - } -#line 8823 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 449: -#line 2981 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, EsdCube); - } -#line 8833 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 450: -#line 2986 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, EsdBuffer); - } -#line 8843 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 451: -#line 2991 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, EsdBuffer); - } -#line 8854 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 452: -#line 2997 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, EsdBuffer); - } -#line 8864 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 453: -#line 3002 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, EsdBuffer); - } -#line 8874 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 454: -#line 3007 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D, true); - } -#line 8884 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 455: -#line 3012 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, Esd1D, true); - } -#line 8895 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 456: -#line 3018 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, Esd1D, true); - } -#line 8905 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 457: -#line 3023 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, Esd1D, true); - } -#line 8915 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 458: -#line 3028 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true); - } -#line 8925 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 459: -#line 3033 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, true); - } -#line 8936 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 460: -#line 3039 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true); - } -#line 8946 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 461: -#line 3044 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true); - } -#line 8956 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 462: -#line 3049 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube, true); - } -#line 8966 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 463: -#line 3054 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, EsdCube, true); - } -#line 8977 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 464: -#line 3060 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, EsdCube, true); - } -#line 8987 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 465: -#line 3065 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, EsdCube, true); - } -#line 8997 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 466: -#line 3070 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, false, false, true); - } -#line 9007 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 467: -#line 3075 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, false, false, true); - } -#line 9018 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 468: -#line 3081 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, false, false, true); - } -#line 9028 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 469: -#line 3086 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, false, false, true); - } -#line 9038 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 470: -#line 3091 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true, false, true); - } -#line 9048 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 471: -#line 3096 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, true, false, true); - } -#line 9059 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 472: -#line 3102 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true, false, true); - } -#line 9069 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 473: -#line 3107 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true, false, true); - } -#line 9079 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 474: -#line 3112 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { // GL_OES_EGL_image_external - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd2D); - (yyval.interm.type).sampler.external = true; - } -#line 9090 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 475: -#line 3118 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { // GL_EXT_YUV_target - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.set(EbtFloat, Esd2D); - (yyval.interm.type).sampler.yuv = true; - } -#line 9101 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 476: -#line 3124 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setSubpass(EbtFloat); - } -#line 9112 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 477: -#line 3130 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setSubpass(EbtFloat, true); - } -#line 9123 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 478: -#line 3136 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); - parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setSubpass(EbtFloat16); - } -#line 9135 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 479: -#line 3143 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); - parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setSubpass(EbtFloat16, true); - } -#line 9147 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 480: -#line 3150 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setSubpass(EbtInt); - } -#line 9158 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 481: -#line 3156 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setSubpass(EbtInt, true); - } -#line 9169 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 482: -#line 3162 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setSubpass(EbtUint); - } -#line 9180 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 483: -#line 3168 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtSampler; - (yyval.interm.type).sampler.setSubpass(EbtUint, true); - } -#line 9191 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 484: -#line 3174 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.fcoopmatCheck((yyvsp[0].lex).loc, "fcoopmatNV", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).coopmat = true; - } -#line 9202 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 485: -#line 3180 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.intcoopmatCheck((yyvsp[0].lex).loc, "icoopmatNV", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).coopmat = true; - } -#line 9213 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 486: -#line 3186 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.intcoopmatCheck((yyvsp[0].lex).loc, "ucoopmatNV", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).coopmat = true; - } -#line 9224 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 487: -#line 3193 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.type) = (yyvsp[0].interm.type); - (yyval.interm.type).qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - parseContext.structTypeCheck((yyval.interm.type).loc, (yyval.interm.type)); - } -#line 9234 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 488: -#line 3198 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // - // This is for user defined type names. The lexical phase looked up the - // type. - // - if (const TVariable* variable = ((yyvsp[0].lex).symbol)->getAsVariable()) { - const TType& structure = variable->getType(); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtStruct; - (yyval.interm.type).userDef = &structure; - } else - parseContext.error((yyvsp[0].lex).loc, "expected type name", (yyvsp[0].lex).string->c_str(), ""); - } -#line 9252 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 489: -#line 3214 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "highp precision qualifier"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqHigh); - } -#line 9262 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 490: -#line 3219 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "mediump precision qualifier"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqMedium); - } -#line 9272 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 491: -#line 3224 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "lowp precision qualifier"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqLow); - } -#line 9282 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 492: -#line 3232 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { parseContext.nestedStructCheck((yyvsp[-2].lex).loc); } -#line 9288 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 493: -#line 3232 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - TType* structure = new TType((yyvsp[-1].interm.typeList), *(yyvsp[-4].lex).string); - parseContext.structArrayCheck((yyvsp[-4].lex).loc, *structure); - TVariable* userTypeDef = new TVariable((yyvsp[-4].lex).string, *structure, true); - if (! parseContext.symbolTable.insert(*userTypeDef)) - parseContext.error((yyvsp[-4].lex).loc, "redefinition", (yyvsp[-4].lex).string->c_str(), "struct"); - (yyval.interm.type).init((yyvsp[-5].lex).loc); - (yyval.interm.type).basicType = EbtStruct; - (yyval.interm.type).userDef = structure; - --parseContext.structNestingLevel; - } -#line 9304 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 494: -#line 3243 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { parseContext.nestedStructCheck((yyvsp[-1].lex).loc); } -#line 9310 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 495: -#line 3243 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - TType* structure = new TType((yyvsp[-1].interm.typeList), TString("")); - (yyval.interm.type).init((yyvsp[-4].lex).loc); - (yyval.interm.type).basicType = EbtStruct; - (yyval.interm.type).userDef = structure; - --parseContext.structNestingLevel; - } -#line 9322 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 496: -#line 3253 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeList) = (yyvsp[0].interm.typeList); - } -#line 9330 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 497: -#line 3256 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); - for (unsigned int i = 0; i < (yyvsp[0].interm.typeList)->size(); ++i) { - for (unsigned int j = 0; j < (yyval.interm.typeList)->size(); ++j) { - if ((*(yyval.interm.typeList))[j].type->getFieldName() == (*(yyvsp[0].interm.typeList))[i].type->getFieldName()) - parseContext.error((*(yyvsp[0].interm.typeList))[i].loc, "duplicate member name:", "", (*(yyvsp[0].interm.typeList))[i].type->getFieldName().c_str()); - } - (yyval.interm.typeList)->push_back((*(yyvsp[0].interm.typeList))[i]); - } - } -#line 9345 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 498: -#line 3269 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-2].interm.type).arraySizes) { - parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); - parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); - if (parseContext.isEsProfile()) - parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); - } - - (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); - - parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); - parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); - - for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { - TType type((yyvsp[-2].interm.type)); - type.setFieldName((*(yyval.interm.typeList))[i].type->getFieldName()); - type.transferArraySizes((*(yyval.interm.typeList))[i].type->getArraySizes()); - type.copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); - parseContext.arrayOfArrayVersionCheck((*(yyval.interm.typeList))[i].loc, type.getArraySizes()); - (*(yyval.interm.typeList))[i].type->shallowCopy(type); - } - } -#line 9372 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 499: -#line 3291 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-2].interm.type).arraySizes) { - parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); - parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); - if (parseContext.isEsProfile()) - parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); - } - - (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); - - parseContext.memberQualifierCheck((yyvsp[-3].interm.type)); - parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); - parseContext.mergeQualifiers((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, (yyvsp[-3].interm.type).qualifier, true); - parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); - - for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { - TType type((yyvsp[-2].interm.type)); - type.setFieldName((*(yyval.interm.typeList))[i].type->getFieldName()); - type.transferArraySizes((*(yyval.interm.typeList))[i].type->getArraySizes()); - type.copyArrayInnerSizes((yyvsp[-2].interm.type).arraySizes); - parseContext.arrayOfArrayVersionCheck((*(yyval.interm.typeList))[i].loc, type.getArraySizes()); - (*(yyval.interm.typeList))[i].type->shallowCopy(type); - } - } -#line 9401 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 500: -#line 3318 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeList) = new TTypeList; - (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); - } -#line 9410 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 501: -#line 3322 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); - } -#line 9418 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 502: -#line 3328 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.typeLine).type = new TType(EbtVoid); - (yyval.interm.typeLine).loc = (yyvsp[0].lex).loc; - (yyval.interm.typeLine).type->setFieldName(*(yyvsp[0].lex).string); - } -#line 9428 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 503: -#line 3333 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.arrayOfArrayVersionCheck((yyvsp[-1].lex).loc, (yyvsp[0].interm).arraySizes); - - (yyval.interm.typeLine).type = new TType(EbtVoid); - (yyval.interm.typeLine).loc = (yyvsp[-1].lex).loc; - (yyval.interm.typeLine).type->setFieldName(*(yyvsp[-1].lex).string); - (yyval.interm.typeLine).type->transferArraySizes((yyvsp[0].interm).arraySizes); - } -#line 9441 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 504: -#line 3344 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } -#line 9449 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 505: -#line 3348 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - const char* initFeature = "{ } style initializers"; - parseContext.requireProfile((yyvsp[-2].lex).loc, ~EEsProfile, initFeature); - parseContext.profileRequires((yyvsp[-2].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); - (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); - } -#line 9460 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 506: -#line 3354 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - const char* initFeature = "{ } style initializers"; - parseContext.requireProfile((yyvsp[-3].lex).loc, ~EEsProfile, initFeature); - parseContext.profileRequires((yyvsp[-3].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); - (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); - } -#line 9471 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 507: -#line 3365 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate(0, (yyvsp[0].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)->getLoc()); - } -#line 9479 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 508: -#line 3368 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); - } -#line 9487 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 509: -#line 3375 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9493 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 510: -#line 3379 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9499 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 511: -#line 3380 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9505 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 512: -#line 3386 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9511 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 513: -#line 3387 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9517 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 514: -#line 3388 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9523 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 515: -#line 3389 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9529 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 516: -#line 3390 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9535 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 517: -#line 3391 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9541 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 518: -#line 3392 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9547 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 519: -#line 3394 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9553 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 520: -#line 3400 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "demote"); - parseContext.requireExtensions((yyvsp[-1].lex).loc, 1, &E_GL_EXT_demote_to_helper_invocation, "demote"); - (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDemote, (yyvsp[-1].lex).loc); - } -#line 9563 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 521: -#line 3409 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = 0; } -#line 9569 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 522: -#line 3410 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.symbolTable.push(); - ++parseContext.statementNestingLevel; - } -#line 9578 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 523: -#line 3414 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); - --parseContext.statementNestingLevel; - } -#line 9587 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 524: -#line 3418 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-2].interm.intermNode) && (yyvsp[-2].interm.intermNode)->getAsAggregate()) - (yyvsp[-2].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); - (yyval.interm.intermNode) = (yyvsp[-2].interm.intermNode); - } -#line 9597 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 525: -#line 3426 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9603 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 526: -#line 3427 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 9609 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 527: -#line 3431 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - ++parseContext.controlFlowNestingLevel; - } -#line 9617 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 528: -#line 3434 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - --parseContext.controlFlowNestingLevel; - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9626 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 529: -#line 3438 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.symbolTable.push(); - ++parseContext.statementNestingLevel; - ++parseContext.controlFlowNestingLevel; - } -#line 9636 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 530: -#line 3443 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); - --parseContext.statementNestingLevel; - --parseContext.controlFlowNestingLevel; - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9647 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 531: -#line 3452 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = 0; - } -#line 9655 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 532: -#line 3455 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[-1].interm.intermNode) && (yyvsp[-1].interm.intermNode)->getAsAggregate()) - (yyvsp[-1].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); - (yyval.interm.intermNode) = (yyvsp[-1].interm.intermNode); - } -#line 9665 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 533: -#line 3463 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); - if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || - (yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) { - parseContext.wrapupSwitchSubsequence(0, (yyvsp[0].interm.intermNode)); - (yyval.interm.intermNode) = 0; // start a fresh subsequence for what's after this case - } - } -#line 9678 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 534: -#line 3471 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || - (yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) { - parseContext.wrapupSwitchSubsequence((yyvsp[-1].interm.intermNode) ? (yyvsp[-1].interm.intermNode)->getAsAggregate() : 0, (yyvsp[0].interm.intermNode)); - (yyval.interm.intermNode) = 0; // start a fresh subsequence for what's after this case - } else - (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); - } -#line 9691 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 535: -#line 3482 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = 0; } -#line 9697 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 536: -#line 3483 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { (yyval.interm.intermNode) = static_cast((yyvsp[-1].interm.intermTypedNode)); } -#line 9703 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 537: -#line 3487 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9711 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 538: -#line 3491 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.handleSelectionAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9720 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 539: -#line 3498 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-2].interm.intermTypedNode)); - (yyval.interm.intermNode) = parseContext.intermediate.addSelection((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yyvsp[-4].lex).loc); - } -#line 9729 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 540: -#line 3505 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode); - (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermNode); - } -#line 9738 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 541: -#line 3509 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode); - (yyval.interm.nodePair).node2 = 0; - } -#line 9747 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 542: -#line 3517 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - parseContext.boolCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode)); - } -#line 9756 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 543: -#line 3521 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.boolCheck((yyvsp[-2].lex).loc, (yyvsp[-3].interm.type)); - - TType type((yyvsp[-3].interm.type)); - TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), 0, (yyvsp[0].interm.intermTypedNode)); - if (initNode) - (yyval.interm.intermTypedNode) = initNode->getAsTyped(); - else - (yyval.interm.intermTypedNode) = 0; - } -#line 9771 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 544: -#line 3534 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9779 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 545: -#line 3538 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.handleSwitchAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9788 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 546: -#line 3545 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // start new switch sequence on the switch stack - ++parseContext.controlFlowNestingLevel; - ++parseContext.statementNestingLevel; - parseContext.switchSequenceStack.push_back(new TIntermSequence); - parseContext.switchLevel.push_back(parseContext.statementNestingLevel); - parseContext.symbolTable.push(); - } -#line 9801 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 547: -#line 3553 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = parseContext.addSwitch((yyvsp[-7].lex).loc, (yyvsp[-5].interm.intermTypedNode), (yyvsp[-1].interm.intermNode) ? (yyvsp[-1].interm.intermNode)->getAsAggregate() : 0); - delete parseContext.switchSequenceStack.back(); - parseContext.switchSequenceStack.pop_back(); - parseContext.switchLevel.pop_back(); - parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); - --parseContext.statementNestingLevel; - --parseContext.controlFlowNestingLevel; - } -#line 9815 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 548: -#line 3565 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = 0; - } -#line 9823 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 549: -#line 3568 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9831 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 550: -#line 3574 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = 0; - if (parseContext.switchLevel.size() == 0) - parseContext.error((yyvsp[-2].lex).loc, "cannot appear outside switch statement", "case", ""); - else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel) - parseContext.error((yyvsp[-2].lex).loc, "cannot be nested inside control flow", "case", ""); - else { - parseContext.constantValueCheck((yyvsp[-1].interm.intermTypedNode), "case"); - parseContext.integerCheck((yyvsp[-1].interm.intermTypedNode), "case"); - (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpCase, (yyvsp[-1].interm.intermTypedNode), (yyvsp[-2].lex).loc); - } - } -#line 9848 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 551: -#line 3586 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = 0; - if (parseContext.switchLevel.size() == 0) - parseContext.error((yyvsp[-1].lex).loc, "cannot appear outside switch statement", "default", ""); - else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel) - parseContext.error((yyvsp[-1].lex).loc, "cannot be nested inside control flow", "default", ""); - else - (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDefault, (yyvsp[-1].lex).loc); - } -#line 9862 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 552: -#line 3598 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9870 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 553: -#line 3602 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.handleLoopAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9879 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 554: -#line 3609 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if (! parseContext.limits.whileLoops) - parseContext.error((yyvsp[-1].lex).loc, "while loops not available", "limitation", ""); - parseContext.symbolTable.push(); - ++parseContext.loopNestingLevel; - ++parseContext.statementNestingLevel; - ++parseContext.controlFlowNestingLevel; - } -#line 9892 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 555: -#line 3617 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); - (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[0].interm.intermNode), (yyvsp[-2].interm.intermTypedNode), 0, true, (yyvsp[-5].lex).loc); - --parseContext.loopNestingLevel; - --parseContext.statementNestingLevel; - --parseContext.controlFlowNestingLevel; - } -#line 9904 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 556: -#line 3624 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - ++parseContext.loopNestingLevel; - ++parseContext.statementNestingLevel; - ++parseContext.controlFlowNestingLevel; - } -#line 9914 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 557: -#line 3629 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if (! parseContext.limits.whileLoops) - parseContext.error((yyvsp[-7].lex).loc, "do-while loops not available", "limitation", ""); - - parseContext.boolCheck((yyvsp[0].lex).loc, (yyvsp[-2].interm.intermTypedNode)); - - (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[-5].interm.intermNode), (yyvsp[-2].interm.intermTypedNode), 0, false, (yyvsp[-4].lex).loc); - --parseContext.loopNestingLevel; - --parseContext.statementNestingLevel; - --parseContext.controlFlowNestingLevel; - } -#line 9930 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 558: -#line 3640 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.symbolTable.push(); - ++parseContext.loopNestingLevel; - ++parseContext.statementNestingLevel; - ++parseContext.controlFlowNestingLevel; - } -#line 9941 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 559: -#line 3646 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); - (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[-3].interm.intermNode), (yyvsp[-5].lex).loc); - TIntermLoop* forLoop = parseContext.intermediate.addLoop((yyvsp[0].interm.intermNode), reinterpret_cast((yyvsp[-2].interm.nodePair).node1), reinterpret_cast((yyvsp[-2].interm.nodePair).node2), true, (yyvsp[-6].lex).loc); - if (! parseContext.limits.nonInductiveForLoops) - parseContext.inductiveLoopCheck((yyvsp[-6].lex).loc, (yyvsp[-3].interm.intermNode), forLoop); - (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyval.interm.intermNode), forLoop, (yyvsp[-6].lex).loc); - (yyval.interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); - --parseContext.loopNestingLevel; - --parseContext.statementNestingLevel; - --parseContext.controlFlowNestingLevel; - } -#line 9958 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 560: -#line 3661 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9966 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 561: -#line 3664 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 9974 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 562: -#line 3670 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - } -#line 9982 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 563: -#line 3673 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermTypedNode) = 0; - } -#line 9990 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 564: -#line 3679 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode); - (yyval.interm.nodePair).node2 = 0; - } -#line 9999 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 565: -#line 3683 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode); - (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode); - } -#line 10008 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 566: -#line 3690 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if (parseContext.loopNestingLevel <= 0) - parseContext.error((yyvsp[-1].lex).loc, "continue statement only allowed in loops", "", ""); - (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpContinue, (yyvsp[-1].lex).loc); - } -#line 10018 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 567: -#line 3695 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if (parseContext.loopNestingLevel + parseContext.switchSequenceStack.size() <= 0) - parseContext.error((yyvsp[-1].lex).loc, "break statement only allowed in switch and loops", "", ""); - (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpBreak, (yyvsp[-1].lex).loc); - } -#line 10028 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 568: -#line 3700 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[-1].lex).loc); - if (parseContext.currentFunctionType->getBasicType() != EbtVoid) - parseContext.error((yyvsp[-1].lex).loc, "non-void function must return a value", "return", ""); - if (parseContext.inMain) - parseContext.postEntryPointReturn = true; - } -#line 10040 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 569: -#line 3707 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = parseContext.handleReturnValue((yyvsp[-2].lex).loc, (yyvsp[-1].interm.intermTypedNode)); - } -#line 10048 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 570: -#line 3710 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "discard"); - (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpKill, (yyvsp[-1].lex).loc); - } -#line 10057 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 571: -#line 3719 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); - } -#line 10066 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 572: -#line 3723 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - if ((yyvsp[0].interm.intermNode) != nullptr) { - (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); - parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); - } - } -#line 10077 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 573: -#line 3732 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 10085 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 574: -#line 3735 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); - } -#line 10093 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 575: -#line 3739 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - parseContext.requireProfile((yyvsp[0].lex).loc, ~EEsProfile, "extraneous semicolon"); - parseContext.profileRequires((yyvsp[0].lex).loc, ~EEsProfile, 460, nullptr, "extraneous semicolon"); - (yyval.interm.intermNode) = nullptr; - } -#line 10103 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 576: -#line 3748 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyvsp[0].interm).function = parseContext.handleFunctionDeclarator((yyvsp[0].interm).loc, *(yyvsp[0].interm).function, false /* not prototype */); - (yyvsp[0].interm).intermNode = parseContext.handleFunctionDefinition((yyvsp[0].interm).loc, *(yyvsp[0].interm).function); - } -#line 10112 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 577: -#line 3752 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - // May be best done as post process phase on intermediate code - if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) - parseContext.error((yyvsp[-2].interm).loc, "function does not return a value:", "", (yyvsp[-2].interm).function->getName().c_str()); - parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); - (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermNode)); - parseContext.intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yyvsp[-2].interm).function->getType(), (yyvsp[-2].interm).loc); - (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[-2].interm).function->getMangledName().c_str()); - - // store the pragma information for debug and optimize and other vendor specific - // information. This information can be queried from the parse tree - (yyval.interm.intermNode)->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize); - (yyval.interm.intermNode)->getAsAggregate()->setDebug(parseContext.contextPragma.debug); - (yyval.interm.intermNode)->getAsAggregate()->setPragmaTable(parseContext.contextPragma.pragmaTable); - } -#line 10132 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 578: -#line 3771 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.attributes) = (yyvsp[-2].interm.attributes); - parseContext.requireExtensions((yyvsp[-4].lex).loc, 1, &E_GL_EXT_control_flow_attributes, "attribute"); - } -#line 10141 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 579: -#line 3777 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.attributes) = (yyvsp[0].interm.attributes); - } -#line 10149 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 580: -#line 3780 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.attributes) = parseContext.mergeAttributes((yyvsp[-2].interm.attributes), (yyvsp[0].interm.attributes)); - } -#line 10157 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 581: -#line 3785 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.attributes) = parseContext.makeAttributes(*(yyvsp[0].lex).string); - } -#line 10165 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - case 582: -#line 3788 "MachineIndependent/glslang.y" /* yacc.c:1646 */ - { - (yyval.interm.attributes) = parseContext.makeAttributes(*(yyvsp[-3].lex).string, (yyvsp[-1].interm.intermTypedNode)); - } -#line 10173 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - break; - - -#line 10177 "MachineIndependent/glslang_tab.cpp" /* yacc.c:1646 */ - default: break; - } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - /* Now 'shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*--------------------------------------. -| yyerrlab -- here on detecting error. | -`--------------------------------------*/ -yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (pParseContext, YY_("syntax error")); -#else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) - { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (pParseContext, yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; - } -# undef YYSYNTAX_ERROR -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval, pParseContext); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule whose action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp, pParseContext); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#if !defined yyoverflow || YYERROR_VERBOSE -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (pParseContext, YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, pParseContext); - } - /* Do not reclaim the symbols of the rule whose action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, pParseContext); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - return yyresult; -} -#line 3793 "MachineIndependent/glslang.y" /* yacc.c:1906 */ - diff --git a/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h b/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h deleted file mode 100644 index f4f41147305..00000000000 --- a/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h +++ /dev/null @@ -1,512 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -#ifndef YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED -# define YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 1 -#endif -#if YYDEBUG -extern int yydebug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - CONST = 258, - BOOL = 259, - INT = 260, - UINT = 261, - FLOAT = 262, - BVEC2 = 263, - BVEC3 = 264, - BVEC4 = 265, - IVEC2 = 266, - IVEC3 = 267, - IVEC4 = 268, - UVEC2 = 269, - UVEC3 = 270, - UVEC4 = 271, - VEC2 = 272, - VEC3 = 273, - VEC4 = 274, - MAT2 = 275, - MAT3 = 276, - MAT4 = 277, - MAT2X2 = 278, - MAT2X3 = 279, - MAT2X4 = 280, - MAT3X2 = 281, - MAT3X3 = 282, - MAT3X4 = 283, - MAT4X2 = 284, - MAT4X3 = 285, - MAT4X4 = 286, - SAMPLER2D = 287, - SAMPLER3D = 288, - SAMPLERCUBE = 289, - SAMPLER2DSHADOW = 290, - SAMPLERCUBESHADOW = 291, - SAMPLER2DARRAY = 292, - SAMPLER2DARRAYSHADOW = 293, - ISAMPLER2D = 294, - ISAMPLER3D = 295, - ISAMPLERCUBE = 296, - ISAMPLER2DARRAY = 297, - USAMPLER2D = 298, - USAMPLER3D = 299, - USAMPLERCUBE = 300, - USAMPLER2DARRAY = 301, - SAMPLER = 302, - SAMPLERSHADOW = 303, - TEXTURE2D = 304, - TEXTURE3D = 305, - TEXTURECUBE = 306, - TEXTURE2DARRAY = 307, - ITEXTURE2D = 308, - ITEXTURE3D = 309, - ITEXTURECUBE = 310, - ITEXTURE2DARRAY = 311, - UTEXTURE2D = 312, - UTEXTURE3D = 313, - UTEXTURECUBE = 314, - UTEXTURE2DARRAY = 315, - ATTRIBUTE = 316, - VARYING = 317, - FLOAT16_T = 318, - FLOAT32_T = 319, - DOUBLE = 320, - FLOAT64_T = 321, - INT64_T = 322, - UINT64_T = 323, - INT32_T = 324, - UINT32_T = 325, - INT16_T = 326, - UINT16_T = 327, - INT8_T = 328, - UINT8_T = 329, - I64VEC2 = 330, - I64VEC3 = 331, - I64VEC4 = 332, - U64VEC2 = 333, - U64VEC3 = 334, - U64VEC4 = 335, - I32VEC2 = 336, - I32VEC3 = 337, - I32VEC4 = 338, - U32VEC2 = 339, - U32VEC3 = 340, - U32VEC4 = 341, - I16VEC2 = 342, - I16VEC3 = 343, - I16VEC4 = 344, - U16VEC2 = 345, - U16VEC3 = 346, - U16VEC4 = 347, - I8VEC2 = 348, - I8VEC3 = 349, - I8VEC4 = 350, - U8VEC2 = 351, - U8VEC3 = 352, - U8VEC4 = 353, - DVEC2 = 354, - DVEC3 = 355, - DVEC4 = 356, - DMAT2 = 357, - DMAT3 = 358, - DMAT4 = 359, - F16VEC2 = 360, - F16VEC3 = 361, - F16VEC4 = 362, - F16MAT2 = 363, - F16MAT3 = 364, - F16MAT4 = 365, - F32VEC2 = 366, - F32VEC3 = 367, - F32VEC4 = 368, - F32MAT2 = 369, - F32MAT3 = 370, - F32MAT4 = 371, - F64VEC2 = 372, - F64VEC3 = 373, - F64VEC4 = 374, - F64MAT2 = 375, - F64MAT3 = 376, - F64MAT4 = 377, - DMAT2X2 = 378, - DMAT2X3 = 379, - DMAT2X4 = 380, - DMAT3X2 = 381, - DMAT3X3 = 382, - DMAT3X4 = 383, - DMAT4X2 = 384, - DMAT4X3 = 385, - DMAT4X4 = 386, - F16MAT2X2 = 387, - F16MAT2X3 = 388, - F16MAT2X4 = 389, - F16MAT3X2 = 390, - F16MAT3X3 = 391, - F16MAT3X4 = 392, - F16MAT4X2 = 393, - F16MAT4X3 = 394, - F16MAT4X4 = 395, - F32MAT2X2 = 396, - F32MAT2X3 = 397, - F32MAT2X4 = 398, - F32MAT3X2 = 399, - F32MAT3X3 = 400, - F32MAT3X4 = 401, - F32MAT4X2 = 402, - F32MAT4X3 = 403, - F32MAT4X4 = 404, - F64MAT2X2 = 405, - F64MAT2X3 = 406, - F64MAT2X4 = 407, - F64MAT3X2 = 408, - F64MAT3X3 = 409, - F64MAT3X4 = 410, - F64MAT4X2 = 411, - F64MAT4X3 = 412, - F64MAT4X4 = 413, - ATOMIC_UINT = 414, - ACCSTRUCTNV = 415, - FCOOPMATNV = 416, - ICOOPMATNV = 417, - UCOOPMATNV = 418, - SAMPLERCUBEARRAY = 419, - SAMPLERCUBEARRAYSHADOW = 420, - ISAMPLERCUBEARRAY = 421, - USAMPLERCUBEARRAY = 422, - SAMPLER1D = 423, - SAMPLER1DARRAY = 424, - SAMPLER1DARRAYSHADOW = 425, - ISAMPLER1D = 426, - SAMPLER1DSHADOW = 427, - SAMPLER2DRECT = 428, - SAMPLER2DRECTSHADOW = 429, - ISAMPLER2DRECT = 430, - USAMPLER2DRECT = 431, - SAMPLERBUFFER = 432, - ISAMPLERBUFFER = 433, - USAMPLERBUFFER = 434, - SAMPLER2DMS = 435, - ISAMPLER2DMS = 436, - USAMPLER2DMS = 437, - SAMPLER2DMSARRAY = 438, - ISAMPLER2DMSARRAY = 439, - USAMPLER2DMSARRAY = 440, - SAMPLEREXTERNALOES = 441, - SAMPLEREXTERNAL2DY2YEXT = 442, - ISAMPLER1DARRAY = 443, - USAMPLER1D = 444, - USAMPLER1DARRAY = 445, - F16SAMPLER1D = 446, - F16SAMPLER2D = 447, - F16SAMPLER3D = 448, - F16SAMPLER2DRECT = 449, - F16SAMPLERCUBE = 450, - F16SAMPLER1DARRAY = 451, - F16SAMPLER2DARRAY = 452, - F16SAMPLERCUBEARRAY = 453, - F16SAMPLERBUFFER = 454, - F16SAMPLER2DMS = 455, - F16SAMPLER2DMSARRAY = 456, - F16SAMPLER1DSHADOW = 457, - F16SAMPLER2DSHADOW = 458, - F16SAMPLER1DARRAYSHADOW = 459, - F16SAMPLER2DARRAYSHADOW = 460, - F16SAMPLER2DRECTSHADOW = 461, - F16SAMPLERCUBESHADOW = 462, - F16SAMPLERCUBEARRAYSHADOW = 463, - IMAGE1D = 464, - IIMAGE1D = 465, - UIMAGE1D = 466, - IMAGE2D = 467, - IIMAGE2D = 468, - UIMAGE2D = 469, - IMAGE3D = 470, - IIMAGE3D = 471, - UIMAGE3D = 472, - IMAGE2DRECT = 473, - IIMAGE2DRECT = 474, - UIMAGE2DRECT = 475, - IMAGECUBE = 476, - IIMAGECUBE = 477, - UIMAGECUBE = 478, - IMAGEBUFFER = 479, - IIMAGEBUFFER = 480, - UIMAGEBUFFER = 481, - IMAGE1DARRAY = 482, - IIMAGE1DARRAY = 483, - UIMAGE1DARRAY = 484, - IMAGE2DARRAY = 485, - IIMAGE2DARRAY = 486, - UIMAGE2DARRAY = 487, - IMAGECUBEARRAY = 488, - IIMAGECUBEARRAY = 489, - UIMAGECUBEARRAY = 490, - IMAGE2DMS = 491, - IIMAGE2DMS = 492, - UIMAGE2DMS = 493, - IMAGE2DMSARRAY = 494, - IIMAGE2DMSARRAY = 495, - UIMAGE2DMSARRAY = 496, - F16IMAGE1D = 497, - F16IMAGE2D = 498, - F16IMAGE3D = 499, - F16IMAGE2DRECT = 500, - F16IMAGECUBE = 501, - F16IMAGE1DARRAY = 502, - F16IMAGE2DARRAY = 503, - F16IMAGECUBEARRAY = 504, - F16IMAGEBUFFER = 505, - F16IMAGE2DMS = 506, - F16IMAGE2DMSARRAY = 507, - TEXTURECUBEARRAY = 508, - ITEXTURECUBEARRAY = 509, - UTEXTURECUBEARRAY = 510, - TEXTURE1D = 511, - ITEXTURE1D = 512, - UTEXTURE1D = 513, - TEXTURE1DARRAY = 514, - ITEXTURE1DARRAY = 515, - UTEXTURE1DARRAY = 516, - TEXTURE2DRECT = 517, - ITEXTURE2DRECT = 518, - UTEXTURE2DRECT = 519, - TEXTUREBUFFER = 520, - ITEXTUREBUFFER = 521, - UTEXTUREBUFFER = 522, - TEXTURE2DMS = 523, - ITEXTURE2DMS = 524, - UTEXTURE2DMS = 525, - TEXTURE2DMSARRAY = 526, - ITEXTURE2DMSARRAY = 527, - UTEXTURE2DMSARRAY = 528, - F16TEXTURE1D = 529, - F16TEXTURE2D = 530, - F16TEXTURE3D = 531, - F16TEXTURE2DRECT = 532, - F16TEXTURECUBE = 533, - F16TEXTURE1DARRAY = 534, - F16TEXTURE2DARRAY = 535, - F16TEXTURECUBEARRAY = 536, - F16TEXTUREBUFFER = 537, - F16TEXTURE2DMS = 538, - F16TEXTURE2DMSARRAY = 539, - SUBPASSINPUT = 540, - SUBPASSINPUTMS = 541, - ISUBPASSINPUT = 542, - ISUBPASSINPUTMS = 543, - USUBPASSINPUT = 544, - USUBPASSINPUTMS = 545, - F16SUBPASSINPUT = 546, - F16SUBPASSINPUTMS = 547, - LEFT_OP = 548, - RIGHT_OP = 549, - INC_OP = 550, - DEC_OP = 551, - LE_OP = 552, - GE_OP = 553, - EQ_OP = 554, - NE_OP = 555, - AND_OP = 556, - OR_OP = 557, - XOR_OP = 558, - MUL_ASSIGN = 559, - DIV_ASSIGN = 560, - ADD_ASSIGN = 561, - MOD_ASSIGN = 562, - LEFT_ASSIGN = 563, - RIGHT_ASSIGN = 564, - AND_ASSIGN = 565, - XOR_ASSIGN = 566, - OR_ASSIGN = 567, - SUB_ASSIGN = 568, - LEFT_PAREN = 569, - RIGHT_PAREN = 570, - LEFT_BRACKET = 571, - RIGHT_BRACKET = 572, - LEFT_BRACE = 573, - RIGHT_BRACE = 574, - DOT = 575, - COMMA = 576, - COLON = 577, - EQUAL = 578, - SEMICOLON = 579, - BANG = 580, - DASH = 581, - TILDE = 582, - PLUS = 583, - STAR = 584, - SLASH = 585, - PERCENT = 586, - LEFT_ANGLE = 587, - RIGHT_ANGLE = 588, - VERTICAL_BAR = 589, - CARET = 590, - AMPERSAND = 591, - QUESTION = 592, - INVARIANT = 593, - HIGH_PRECISION = 594, - MEDIUM_PRECISION = 595, - LOW_PRECISION = 596, - PRECISION = 597, - PACKED = 598, - RESOURCE = 599, - SUPERP = 600, - FLOATCONSTANT = 601, - INTCONSTANT = 602, - UINTCONSTANT = 603, - BOOLCONSTANT = 604, - IDENTIFIER = 605, - TYPE_NAME = 606, - CENTROID = 607, - IN = 608, - OUT = 609, - INOUT = 610, - STRUCT = 611, - VOID = 612, - WHILE = 613, - BREAK = 614, - CONTINUE = 615, - DO = 616, - ELSE = 617, - FOR = 618, - IF = 619, - DISCARD = 620, - RETURN = 621, - SWITCH = 622, - CASE = 623, - DEFAULT = 624, - UNIFORM = 625, - SHARED = 626, - BUFFER = 627, - FLAT = 628, - SMOOTH = 629, - LAYOUT = 630, - DOUBLECONSTANT = 631, - INT16CONSTANT = 632, - UINT16CONSTANT = 633, - FLOAT16CONSTANT = 634, - INT32CONSTANT = 635, - UINT32CONSTANT = 636, - INT64CONSTANT = 637, - UINT64CONSTANT = 638, - SUBROUTINE = 639, - DEMOTE = 640, - PAYLOADNV = 641, - PAYLOADINNV = 642, - HITATTRNV = 643, - CALLDATANV = 644, - CALLDATAINNV = 645, - PATCH = 646, - SAMPLE = 647, - NONUNIFORM = 648, - COHERENT = 649, - VOLATILE = 650, - RESTRICT = 651, - READONLY = 652, - WRITEONLY = 653, - DEVICECOHERENT = 654, - QUEUEFAMILYCOHERENT = 655, - WORKGROUPCOHERENT = 656, - SUBGROUPCOHERENT = 657, - NONPRIVATE = 658, - NOPERSPECTIVE = 659, - EXPLICITINTERPAMD = 660, - PERVERTEXNV = 661, - PERPRIMITIVENV = 662, - PERVIEWNV = 663, - PERTASKNV = 664, - PRECISE = 665 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - -union YYSTYPE -{ -#line 96 "MachineIndependent/glslang.y" /* yacc.c:1909 */ - - struct { - glslang::TSourceLoc loc; - union { - glslang::TString *string; - int i; - unsigned int u; - long long i64; - unsigned long long u64; - bool b; - double d; - }; - glslang::TSymbol* symbol; - } lex; - struct { - glslang::TSourceLoc loc; - glslang::TOperator op; - union { - TIntermNode* intermNode; - glslang::TIntermNodePair nodePair; - glslang::TIntermTyped* intermTypedNode; - glslang::TAttributes* attributes; - }; - union { - glslang::TPublicType type; - glslang::TFunction* function; - glslang::TParameter param; - glslang::TTypeLoc typeLine; - glslang::TTypeList* typeList; - glslang::TArraySizes* arraySizes; - glslang::TIdentifierList* identifierList; - }; - glslang::TArraySizes* typeParameters; - } interm; - -#line 501 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */ -}; - -typedef union YYSTYPE YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - - -int yyparse (glslang::TParseContext* pParseContext); - -#endif /* !YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED */ diff --git a/libraries/glslang/glslang/MachineIndependent/iomapper.cpp b/libraries/glslang/glslang/MachineIndependent/iomapper.cpp deleted file mode 100644 index 3262c0a2030..00000000000 --- a/libraries/glslang/glslang/MachineIndependent/iomapper.cpp +++ /dev/null @@ -1,1249 +0,0 @@ -// -// Copyright (C) 2016-2017 LunarG, Inc. -// -// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. -// - -#ifndef GLSLANG_WEB - -#include "../Include/Common.h" -#include "../Include/InfoSink.h" - -#include "gl_types.h" -#include "iomapper.h" - -// -// Map IO bindings. -// -// High-level algorithm for one stage: -// -// 1. Traverse all code (live+dead) to find the explicitly provided bindings. -// -// 2. Traverse (just) the live code to determine which non-provided bindings -// require auto-numbering. We do not auto-number dead ones. -// -// 3. Traverse all the code to apply the bindings: -// a. explicitly given bindings are offset according to their type -// b. implicit live bindings are auto-numbered into the holes, using -// any open binding slot. -// c. implicit dead bindings are left un-bound. -// - -namespace glslang { - -class TVarGatherTraverser : public TLiveTraverser { -public: - TVarGatherTraverser(const TIntermediate& i, bool traverseDeadCode, TVarLiveMap& inList, TVarLiveMap& outList, TVarLiveMap& uniformList) - : TLiveTraverser(i, traverseDeadCode, true, true, false) - , inputList(inList) - , outputList(outList) - , uniformList(uniformList) - { - } - - virtual void visitSymbol(TIntermSymbol* base) - { - TVarLiveMap* target = nullptr; - if (base->getQualifier().storage == EvqVaryingIn) - target = &inputList; - else if (base->getQualifier().storage == EvqVaryingOut) - target = &outputList; - else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().isPushConstant()) - target = &uniformList; - if (target) { - TVarEntryInfo ent = {base->getId(), base, ! traverseAll}; - ent.stage = intermediate.getStage(); - TVarLiveMap::iterator at = target->find( - ent.symbol->getName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById()); - if (at != target->end() && at->second.id == ent.id) - at->second.live = at->second.live || ! traverseAll; // update live state - else - (*target)[ent.symbol->getName()] = ent; - } - } - -private: - TVarLiveMap& inputList; - TVarLiveMap& outputList; - TVarLiveMap& uniformList; -}; - -class TVarSetTraverser : public TLiveTraverser -{ -public: - TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& inList, const TVarLiveMap& outList, const TVarLiveMap& uniformList) - : TLiveTraverser(i, true, true, true, false) - , inputList(inList) - , outputList(outList) - , uniformList(uniformList) - { - } - - virtual void visitSymbol(TIntermSymbol* base) { - const TVarLiveMap* source; - if (base->getQualifier().storage == EvqVaryingIn) - source = &inputList; - else if (base->getQualifier().storage == EvqVaryingOut) - source = &outputList; - else if (base->getQualifier().isUniformOrBuffer()) - source = &uniformList; - else - return; - - TVarEntryInfo ent = { base->getId() }; - TVarLiveMap::const_iterator at = source->find(base->getName()); - if (at == source->end()) - return; - - if (at->second.id != ent.id) - return; - - if (at->second.newBinding != -1) - base->getWritableType().getQualifier().layoutBinding = at->second.newBinding; - if (at->second.newSet != -1) - base->getWritableType().getQualifier().layoutSet = at->second.newSet; - if (at->second.newLocation != -1) - base->getWritableType().getQualifier().layoutLocation = at->second.newLocation; - if (at->second.newComponent != -1) - base->getWritableType().getQualifier().layoutComponent = at->second.newComponent; - if (at->second.newIndex != -1) - base->getWritableType().getQualifier().layoutIndex = at->second.newIndex; - } - - private: - const TVarLiveMap& inputList; - const TVarLiveMap& outputList; - const TVarLiveMap& uniformList; -}; - -struct TNotifyUniformAdaptor -{ - EShLanguage stage; - TIoMapResolver& resolver; - inline TNotifyUniformAdaptor(EShLanguage s, TIoMapResolver& r) - : stage(s) - , resolver(r) - { - } - - inline void operator()(std::pair& entKey) - { - resolver.notifyBinding(stage, entKey.second); - } - -private: - TNotifyUniformAdaptor& operator=(TNotifyUniformAdaptor&); -}; - -struct TNotifyInOutAdaptor -{ - EShLanguage stage; - TIoMapResolver& resolver; - inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r) - : stage(s) - , resolver(r) - { - } - - inline void operator()(std::pair& entKey) - { - resolver.notifyInOut(stage, entKey.second); - } - -private: - TNotifyInOutAdaptor& operator=(TNotifyInOutAdaptor&); -}; - -struct TResolverUniformAdaptor { - TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e) - : stage(s) - , resolver(r) - , infoSink(i) - , error(e) - { - } - - inline void operator()(std::pair& entKey) { - TVarEntryInfo& ent = entKey.second; - ent.newLocation = -1; - ent.newComponent = -1; - ent.newBinding = -1; - ent.newSet = -1; - ent.newIndex = -1; - const bool isValid = resolver.validateBinding(stage, ent); - if (isValid) { - resolver.resolveBinding(stage, ent); - resolver.resolveSet(stage, ent); - resolver.resolveUniformLocation(stage, ent); - - if (ent.newBinding != -1) { - if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) { - TString err = "mapped binding out of range: " + entKey.first; - - infoSink.info.message(EPrefixInternalError, err.c_str()); - error = true; - } - } - if (ent.newSet != -1) { - if (ent.newSet >= int(TQualifier::layoutSetEnd)) { - TString err = "mapped set out of range: " + entKey.first; - - infoSink.info.message(EPrefixInternalError, err.c_str()); - error = true; - } - } - } else { - TString errorMsg = "Invalid binding: " + entKey.first; - infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); - error = true; - } - } - - inline void setStage(EShLanguage s) { stage = s; } - - EShLanguage stage; - TIoMapResolver& resolver; - TInfoSink& infoSink; - bool& error; - -private: - TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&); -}; - -struct TResolverInOutAdaptor { - TResolverInOutAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e) - : stage(s) - , resolver(r) - , infoSink(i) - , error(e) - { - } - - inline void operator()(std::pair& entKey) - { - TVarEntryInfo& ent = entKey.second; - ent.newLocation = -1; - ent.newComponent = -1; - ent.newBinding = -1; - ent.newSet = -1; - ent.newIndex = -1; - const bool isValid = resolver.validateInOut(stage, ent); - if (isValid) { - resolver.resolveInOutLocation(stage, ent); - resolver.resolveInOutComponent(stage, ent); - resolver.resolveInOutIndex(stage, ent); - } else { - TString errorMsg; - if (ent.symbol->getType().getQualifier().semanticName != nullptr) { - errorMsg = "Invalid shader In/Out variable semantic: "; - errorMsg += ent.symbol->getType().getQualifier().semanticName; - } else { - errorMsg = "Invalid shader In/Out variable: "; - errorMsg += ent.symbol->getName(); - } - infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); - error = true; - } - } - - inline void setStage(EShLanguage s) { stage = s; } - - EShLanguage stage; - TIoMapResolver& resolver; - TInfoSink& infoSink; - bool& error; - -private: - TResolverInOutAdaptor& operator=(TResolverInOutAdaptor&); -}; - -// The class is used for reserving explicit uniform locations and ubo/ssbo/opaque bindings - -struct TSymbolValidater -{ - TSymbolValidater(TIoMapResolver& r, TInfoSink& i, TVarLiveMap* in[EShLangCount], TVarLiveMap* out[EShLangCount], - TVarLiveMap* uniform[EShLangCount], bool& hadError) - : preStage(EShLangCount) - , currentStage(EShLangCount) - , nextStage(EShLangCount) - , resolver(r) - , infoSink(i) - , hadError(hadError) - { - memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*))); - memcpy(outVarMaps, out, EShLangCount * (sizeof(TVarLiveMap*))); - memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*))); - } - - inline void operator()(std::pair& entKey) { - TVarEntryInfo& ent1 = entKey.second; - TIntermSymbol* base = ent1.symbol; - const TType& type = ent1.symbol->getType(); - const TString& name = entKey.first; - TString mangleName1, mangleName2; - type.appendMangledName(mangleName1); - EShLanguage stage = ent1.stage; - if (currentStage != stage) { - preStage = currentStage; - currentStage = stage; - nextStage = EShLangCount; - for (int i = currentStage + 1; i < EShLangCount; i++) { - if (inVarMaps[i] != nullptr) - nextStage = static_cast(i); - } - } - if (base->getQualifier().storage == EvqVaryingIn) { - // validate stage in; - if (preStage == EShLangCount) - return; - if (outVarMaps[preStage] != nullptr) { - auto ent2 = outVarMaps[preStage]->find(name); - if (ent2 != outVarMaps[preStage]->end()) { - ent2->second.symbol->getType().appendMangledName(mangleName2); - if (mangleName1 == mangleName2) - return; - else { - TString err = "Invalid In/Out variable type : " + entKey.first; - infoSink.info.message(EPrefixInternalError, err.c_str()); - hadError = true; - } - } - return; - } - } else if (base->getQualifier().storage == EvqVaryingOut) { - // validate stage out; - if (nextStage == EShLangCount) - return; - if (outVarMaps[nextStage] != nullptr) { - auto ent2 = inVarMaps[nextStage]->find(name); - if (ent2 != inVarMaps[nextStage]->end()) { - ent2->second.symbol->getType().appendMangledName(mangleName2); - if (mangleName1 == mangleName2) - return; - else { - TString err = "Invalid In/Out variable type : " + entKey.first; - infoSink.info.message(EPrefixInternalError, err.c_str()); - hadError = true; - } - } - return; - } - } else if (base->getQualifier().isUniformOrBuffer() && ! base->getQualifier().isPushConstant()) { - // validate uniform type; - for (int i = 0; i < EShLangCount; i++) { - if (i != currentStage && outVarMaps[i] != nullptr) { - auto ent2 = uniformVarMap[i]->find(name); - if (ent2 != uniformVarMap[i]->end()) { - ent2->second.symbol->getType().appendMangledName(mangleName2); - if (mangleName1 != mangleName2) { - TString err = "Invalid Uniform variable type : " + entKey.first; - infoSink.info.message(EPrefixInternalError, err.c_str()); - hadError = true; - } - mangleName2.clear(); - } - } - } - } - } - TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], *uniformVarMap[EShLangCount]; - // Use for mark pre stage, to get more interface symbol information. - EShLanguage preStage, currentStage, nextStage; - // Use for mark current shader stage for resolver - TIoMapResolver& resolver; - TInfoSink& infoSink; - bool& hadError; - -private: - TSymbolValidater& operator=(TSymbolValidater&); -}; - -struct TSlotCollector { - TSlotCollector(TIoMapResolver& r, TInfoSink& i) : resolver(r), infoSink(i) { } - - inline void operator()(std::pair& entKey) { - resolver.reserverStorageSlot(entKey.second, infoSink); - resolver.reserverResourceSlot(entKey.second, infoSink); - } - TIoMapResolver& resolver; - TInfoSink& infoSink; - -private: - TSlotCollector& operator=(TSlotCollector&); -}; - -TDefaultIoResolverBase::TDefaultIoResolverBase(const TIntermediate& intermediate) - : intermediate(intermediate) - , nextUniformLocation(intermediate.getUniformLocationBase()) - , nextInputLocation(0) - , nextOutputLocation(0) -{ - memset(stageMask, false, sizeof(bool) * (EShLangCount + 1)); -} - -int TDefaultIoResolverBase::getBaseBinding(TResourceType res, unsigned int set) const { - return selectBaseBinding(intermediate.getShiftBinding(res), intermediate.getShiftBindingForSet(res, set)); -} - -const std::vector& TDefaultIoResolverBase::getResourceSetBinding() const { - return intermediate.getResourceSetBinding(); -} - -bool TDefaultIoResolverBase::doAutoBindingMapping() const { return intermediate.getAutoMapBindings(); } - -bool TDefaultIoResolverBase::doAutoLocationMapping() const { return intermediate.getAutoMapLocations(); } - -TDefaultIoResolverBase::TSlotSet::iterator TDefaultIoResolverBase::findSlot(int set, int slot) { - return std::lower_bound(slots[set].begin(), slots[set].end(), slot); -} - -bool TDefaultIoResolverBase::checkEmpty(int set, int slot) { - TSlotSet::iterator at = findSlot(set, slot); - return ! (at != slots[set].end() && *at == slot); -} - -int TDefaultIoResolverBase::reserveSlot(int set, int slot, int size) { - TSlotSet::iterator at = findSlot(set, slot); - // tolerate aliasing, by not double-recording aliases - // (policy about appropriateness of the alias is higher up) - for (int i = 0; i < size; i++) { - if (at == slots[set].end() || *at != slot + i) - at = slots[set].insert(at, slot + i); - ++at; - } - return slot; -} - -int TDefaultIoResolverBase::getFreeSlot(int set, int base, int size) { - TSlotSet::iterator at = findSlot(set, base); - if (at == slots[set].end()) - return reserveSlot(set, base, size); - // look for a big enough gap - for (; at != slots[set].end(); ++at) { - if (*at - base >= size) - break; - base = *at + 1; - } - return reserveSlot(set, base, size); -} - -int TDefaultIoResolverBase::resolveSet(EShLanguage /*stage*/, TVarEntryInfo& ent) { - const TType& type = ent.symbol->getType(); - if (type.getQualifier().hasSet()) { - return ent.newSet = type.getQualifier().layoutSet; - } - // If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN) - if (getResourceSetBinding().size() == 1) { - return ent.newSet = atoi(getResourceSetBinding()[0].c_str()); - } - return ent.newSet = 0; -} - -int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) { - const TType& type = ent.symbol->getType(); - const char* name = ent.symbol->getName().c_str(); - // kick out of not doing this - if (! doAutoLocationMapping()) { - return ent.newLocation = -1; - } - // no locations added if already present, a built-in variable, a block, or an opaque - if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock || - type.isAtomic() || (type.containsOpaque() && intermediate.getSpv().openGl == 0)) { - return ent.newLocation = -1; - } - // no locations on blocks of built-in variables - if (type.isStruct()) { - if (type.getStruct()->size() < 1) { - return ent.newLocation = -1; - } - if ((*type.getStruct())[0].type->isBuiltIn()) { - return ent.newLocation = -1; - } - } - int location = intermediate.getUniformLocationOverride(name); - if (location != -1) { - return ent.newLocation = location; - } - location = nextUniformLocation; - nextUniformLocation += TIntermediate::computeTypeUniformLocationSize(type); - return ent.newLocation = location; -} - -int TDefaultIoResolverBase::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) { - const TType& type = ent.symbol->getType(); - // kick out of not doing this - if (! doAutoLocationMapping()) { - return ent.newLocation = -1; - } - - // no locations added if already present, or a built-in variable - if (type.getQualifier().hasLocation() || type.isBuiltIn()) { - return ent.newLocation = -1; - } - - // no locations on blocks of built-in variables - if (type.isStruct()) { - if (type.getStruct()->size() < 1) { - return ent.newLocation = -1; - } - if ((*type.getStruct())[0].type->isBuiltIn()) { - return ent.newLocation = -1; - } - } - // point to the right input or output location counter - int& nextLocation = type.getQualifier().isPipeInput() ? nextInputLocation : nextOutputLocation; - // Placeholder. This does not do proper cross-stage lining up, nor - // work with mixed location/no-location declarations. - int location = nextLocation; - int typeLocationSize; - // Don’t take into account the outer-most array if the stage’s - // interface is automatically an array. - typeLocationSize = computeTypeLocationSize(type, stage); - nextLocation += typeLocationSize; - return ent.newLocation = location; -} - -int TDefaultIoResolverBase::resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) { - return ent.newComponent = -1; -} - -int TDefaultIoResolverBase::resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) { return ent.newIndex = -1; } - -uint32_t TDefaultIoResolverBase::computeTypeLocationSize(const TType& type, EShLanguage stage) { - int typeLocationSize; - // Don’t take into account the outer-most array if the stage’s - // interface is automatically an array. - if (type.getQualifier().isArrayedIo(stage)) { - TType elementType(type, 0); - typeLocationSize = TIntermediate::computeTypeLocationSize(elementType, stage); - } else { - typeLocationSize = TIntermediate::computeTypeLocationSize(type, stage); - } - return typeLocationSize; -} - -//TDefaultGlslIoResolver -TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type) { - if (isImageType(type)) { - return EResImage; - } - if (isTextureType(type)) { - return EResTexture; - } - if (isSsboType(type)) { - return EResSsbo; - } - if (isSamplerType(type)) { - return EResSampler; - } - if (isUboType(type)) { - return EResUbo; - } - return EResCount; -} - -TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate) - : TDefaultIoResolverBase(intermediate) - , preStage(EShLangCount) - , currentStage(EShLangCount) -{ } - -int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) { - const TType& type = ent.symbol->getType(); - const TString& name = ent.symbol->getName(); - if (currentStage != stage) { - preStage = currentStage; - currentStage = stage; - } - // kick out of not doing this - if (! doAutoLocationMapping()) { - return ent.newLocation = -1; - } - // expand the location to each element if the symbol is a struct or array - if (type.getQualifier().hasLocation()) { - return ent.newLocation = type.getQualifier().layoutLocation; - } - // no locations added if already present, or a built-in variable - if (type.isBuiltIn()) { - return ent.newLocation = -1; - } - // no locations on blocks of built-in variables - if (type.isStruct()) { - if (type.getStruct()->size() < 1) { - return ent.newLocation = -1; - } - if ((*type.getStruct())[0].type->isBuiltIn()) { - return ent.newLocation = -1; - } - } - int typeLocationSize = computeTypeLocationSize(type, stage); - int location = type.getQualifier().layoutLocation; - bool hasLocation = false; - EShLanguage keyStage(EShLangCount); - TStorageQualifier storage; - storage = EvqInOut; - if (type.getQualifier().isPipeInput()) { - // If this symbol is a input, search pre stage's out - keyStage = preStage; - } - if (type.getQualifier().isPipeOutput()) { - // If this symbol is a output, search next stage's in - keyStage = currentStage; - } - // The in/out in current stage is not declared with location, but it is possible declared - // with explicit location in other stages, find the storageSlotMap firstly to check whether - // the in/out has location - int resourceKey = buildStorageKey(keyStage, storage); - if (! storageSlotMap[resourceKey].empty()) { - TVarSlotMap::iterator iter = storageSlotMap[resourceKey].find(name); - if (iter != storageSlotMap[resourceKey].end()) { - // If interface resource be found, set it has location and this symbol's new location - // equal the symbol's explicit location declarated in pre or next stage. - // - // vs: out vec4 a; - // fs: layout(..., location = 3,...) in vec4 a; - hasLocation = true; - location = iter->second; - // if we want deal like that: - // vs: layout(location=4) out vec4 a; - // out vec4 b; - // - // fs: in vec4 a; - // layout(location = 4) in vec4 b; - // we need retraverse the map. - } - if (! hasLocation) { - // If interface resource note found, It's mean the location in two stage are both implicit declarat. - // So we should find a new slot for this interface. - // - // vs: out vec4 a; - // fs: in vec4 a; - location = getFreeSlot(resourceKey, 0, typeLocationSize); - storageSlotMap[resourceKey][name] = location; - } - } else { - // the first interface declarated in a program. - TVarSlotMap varSlotMap; - location = getFreeSlot(resourceKey, 0, typeLocationSize); - varSlotMap[name] = location; - storageSlotMap[resourceKey] = varSlotMap; - } - //Update location - return ent.newLocation = location; -} - -int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) { - const TType& type = ent.symbol->getType(); - const TString& name = ent.symbol->getName(); - // kick out of not doing this - if (! doAutoLocationMapping()) { - return ent.newLocation = -1; - } - // expand the location to each element if the symbol is a struct or array - if (type.getQualifier().hasLocation() && (type.isStruct() || type.isArray())) { - return ent.newLocation = type.getQualifier().layoutLocation; - } else { - // no locations added if already present, a built-in variable, a block, or an opaque - if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock || - type.isAtomic() || (type.containsOpaque() && intermediate.getSpv().openGl == 0)) { - return ent.newLocation = -1; - } - // no locations on blocks of built-in variables - if (type.isStruct()) { - if (type.getStruct()->size() < 1) { - return ent.newLocation = -1; - } - if ((*type.getStruct())[0].type->isBuiltIn()) { - return ent.newLocation = -1; - } - } - } - int location = intermediate.getUniformLocationOverride(name.c_str()); - if (location != -1) { - return ent.newLocation = location; - } - - int size = TIntermediate::computeTypeUniformLocationSize(type); - - // The uniform in current stage is not declared with location, but it is possible declared - // with explicit location in other stages, find the storageSlotMap firstly to check whether - // the uniform has location - bool hasLocation = false; - int resourceKey = buildStorageKey(EShLangCount, EvqUniform); - TVarSlotMap& slotMap = storageSlotMap[resourceKey]; - // Check dose shader program has uniform resource - if (! slotMap.empty()) { - // If uniform resource not empty, try find a same name uniform - TVarSlotMap::iterator iter = slotMap.find(name); - if (iter != slotMap.end()) { - // If uniform resource be found, set it has location and this symbol's new location - // equal the uniform's explicit location declarated in other stage. - // - // vs: uniform vec4 a; - // fs: layout(..., location = 3,...) uniform vec4 a; - hasLocation = true; - location = iter->second; - } - if (! hasLocation) { - // No explicit location declaraten in other stage. - // So we should find a new slot for this uniform. - // - // vs: uniform vec4 a; - // fs: uniform vec4 a; - location = getFreeSlot(resourceKey, 0, computeTypeLocationSize(type, currentStage)); - storageSlotMap[resourceKey][name] = location; - } - } else { - // the first uniform declarated in a program. - TVarSlotMap varSlotMap; - location = getFreeSlot(resourceKey, 0, size); - varSlotMap[name] = location; - storageSlotMap[resourceKey] = varSlotMap; - } - return ent.newLocation = location; -} - -int TDefaultGlslIoResolver::resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) { - const TType& type = ent.symbol->getType(); - const TString& name = ent.symbol->getName(); - // On OpenGL arrays of opaque types take a seperate binding for each element - int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1; - TResourceType resource = getResourceType(type); - // don't need to handle uniform symbol, it will be handled in resolveUniformLocation - if (resource == EResUbo && type.getBasicType() != EbtBlock) { - return ent.newBinding = -1; - } - // There is no 'set' qualifier in OpenGL shading language, each resource has its own - // binding name space, so remap the 'set' to resource type which make each resource - // binding is valid from 0 to MAX_XXRESOURCE_BINDINGS - int set = resource; - if (resource < EResCount) { - if (type.getQualifier().hasBinding()) { - ent.newBinding = reserveSlot(set, getBaseBinding(resource, set) + type.getQualifier().layoutBinding, numBindings); - return ent.newBinding; - } else if (ent.live && doAutoBindingMapping()) { - // The resource in current stage is not declared with binding, but it is possible declared - // with explicit binding in other stages, find the resourceSlotMap firstly to check whether - // the resource has binding, don't need to allocate if it already has a binding - bool hasBinding = false; - if (! resourceSlotMap[resource].empty()) { - TVarSlotMap::iterator iter = resourceSlotMap[resource].find(name); - if (iter != resourceSlotMap[resource].end()) { - hasBinding = true; - ent.newBinding = iter->second; - } - } - if (! hasBinding) { - TVarSlotMap varSlotMap; - // find free slot, the caller did make sure it passes all vars with binding - // first and now all are passed that do not have a binding and needs one - int binding = getFreeSlot(resource, getBaseBinding(resource, set), numBindings); - varSlotMap[name] = binding; - resourceSlotMap[resource] = varSlotMap; - ent.newBinding = binding; - } - return ent.newBinding; - } - } - return ent.newBinding = -1; -} - -void TDefaultGlslIoResolver::beginResolve(EShLanguage stage) { - // reset stage state - if (stage == EShLangCount) - preStage = currentStage = stage; - // update stage state - else if (currentStage != stage) { - preStage = currentStage; - currentStage = stage; - } -} - -void TDefaultGlslIoResolver::endResolve(EShLanguage /*stage*/) { - // TODO nothing -} - -void TDefaultGlslIoResolver::beginCollect(EShLanguage stage) { - // reset stage state - if (stage == EShLangCount) - preStage = currentStage = stage; - // update stage state - else if (currentStage != stage) { - preStage = currentStage; - currentStage = stage; - } -} - -void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) { - // TODO nothing -} - -void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) { - const TType& type = ent.symbol->getType(); - const TString& name = ent.symbol->getName(); - TStorageQualifier storage = type.getQualifier().storage; - EShLanguage stage(EShLangCount); - switch (storage) { - case EvqUniform: - if (type.getBasicType() != EbtBlock && type.getQualifier().hasLocation()) { - // - // Reserve the slots for the uniforms who has explicit location - int storageKey = buildStorageKey(EShLangCount, EvqUniform); - int location = type.getQualifier().layoutLocation; - TVarSlotMap& varSlotMap = storageSlotMap[storageKey]; - TVarSlotMap::iterator iter = varSlotMap.find(name); - if (iter == varSlotMap.end()) { - int numLocations = TIntermediate::computeTypeUniformLocationSize(type); - reserveSlot(storageKey, location, numLocations); - varSlotMap[name] = location; - } else { - // Allocate location by name for OpenGL driver, so the uniform in different - // stages should be declared with the same location - if (iter->second != location) { - TString errorMsg = "Invalid location: " + name; - infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); - } - } - } - break; - case EvqVaryingIn: - case EvqVaryingOut: - // - // Reserve the slots for the inout who has explicit location - if (type.getQualifier().hasLocation()) { - stage = storage == EvqVaryingIn ? preStage : stage; - stage = storage == EvqVaryingOut ? currentStage : stage; - int storageKey = buildStorageKey(stage, EvqInOut); - int location = type.getQualifier().layoutLocation; - TVarSlotMap& varSlotMap = storageSlotMap[storageKey]; - TVarSlotMap::iterator iter = varSlotMap.find(name); - if (iter == varSlotMap.end()) { - int numLocations = TIntermediate::computeTypeUniformLocationSize(type); - reserveSlot(storageKey, location, numLocations); - varSlotMap[name] = location; - } else { - // Allocate location by name for OpenGL driver, so the uniform in different - // stages should be declared with the same location - if (iter->second != location) { - TString errorMsg = "Invalid location: " + name; - infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); - } - } - } - break; - default: - break; - } -} - -void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) { - const TType& type = ent.symbol->getType(); - const TString& name = ent.symbol->getName(); - int resource = getResourceType(type); - if (type.getQualifier().hasBinding()) { - TVarSlotMap& varSlotMap = resourceSlotMap[resource]; - TVarSlotMap::iterator iter = varSlotMap.find(name); - int binding = type.getQualifier().layoutBinding; - if (iter == varSlotMap.end()) { - // Reserve the slots for the ubo, ssbo and opaques who has explicit binding - int numBindings = type.isSizedArray() ? type.getCumulativeArraySize() : 1; - varSlotMap[name] = binding; - reserveSlot(resource, binding, numBindings); - } else { - // Allocate binding by name for OpenGL driver, so the resource in different - // stages should be declared with the same binding - if (iter->second != binding) { - TString errorMsg = "Invalid binding: " + name; - infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); - } - } - } -} - -//TDefaultGlslIoResolver end - -/* - * Basic implementation of glslang::TIoMapResolver that replaces the - * previous offset behavior. - * It does the same, uses the offsets for the corresponding uniform - * types. Also respects the EOptionAutoMapBindings flag and binds - * them if needed. - */ -/* - * Default resolver - */ -struct TDefaultIoResolver : public TDefaultIoResolverBase { - TDefaultIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { } - - bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; } - - TResourceType getResourceType(const glslang::TType& type) override { - if (isImageType(type)) { - return EResImage; - } - if (isTextureType(type)) { - return EResTexture; - } - if (isSsboType(type)) { - return EResSsbo; - } - if (isSamplerType(type)) { - return EResSampler; - } - if (isUboType(type)) { - return EResUbo; - } - return EResCount; - } - - int resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) override { - const TType& type = ent.symbol->getType(); - const int set = getLayoutSet(type); - // On OpenGL arrays of opaque types take a seperate binding for each element - int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1; - TResourceType resource = getResourceType(type); - if (resource < EResCount) { - if (type.getQualifier().hasBinding()) { - return ent.newBinding = reserveSlot( - set, getBaseBinding(resource, set) + type.getQualifier().layoutBinding, numBindings); - } else if (ent.live && doAutoBindingMapping()) { - // find free slot, the caller did make sure it passes all vars with binding - // first and now all are passed that do not have a binding and needs one - return ent.newBinding = getFreeSlot(set, getBaseBinding(resource, set), numBindings); - } - } - return ent.newBinding = -1; - } -}; - -#ifdef ENABLE_HLSL -/******************************************************************************** -The following IO resolver maps types in HLSL register space, as follows: - -t - for shader resource views (SRV) - TEXTURE1D - TEXTURE1DARRAY - TEXTURE2D - TEXTURE2DARRAY - TEXTURE3D - TEXTURECUBE - TEXTURECUBEARRAY - TEXTURE2DMS - TEXTURE2DMSARRAY - STRUCTUREDBUFFER - BYTEADDRESSBUFFER - BUFFER - TBUFFER - -s - for samplers - SAMPLER - SAMPLER1D - SAMPLER2D - SAMPLER3D - SAMPLERCUBE - SAMPLERSTATE - SAMPLERCOMPARISONSTATE - -u - for unordered access views (UAV) - RWBYTEADDRESSBUFFER - RWSTRUCTUREDBUFFER - APPENDSTRUCTUREDBUFFER - CONSUMESTRUCTUREDBUFFER - RWBUFFER - RWTEXTURE1D - RWTEXTURE1DARRAY - RWTEXTURE2D - RWTEXTURE2DARRAY - RWTEXTURE3D - -b - for constant buffer views (CBV) - CBUFFER - CONSTANTBUFFER - ********************************************************************************/ -struct TDefaultHlslIoResolver : public TDefaultIoResolverBase { - TDefaultHlslIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { } - - bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; } - - TResourceType getResourceType(const glslang::TType& type) override { - if (isUavType(type)) { - return EResUav; - } - if (isSrvType(type)) { - return EResTexture; - } - if (isSamplerType(type)) { - return EResSampler; - } - if (isUboType(type)) { - return EResUbo; - } - return EResCount; - } - - int resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) override { - const TType& type = ent.symbol->getType(); - const int set = getLayoutSet(type); - TResourceType resource = getResourceType(type); - if (resource < EResCount) { - if (type.getQualifier().hasBinding()) { - return ent.newBinding = reserveSlot(set, getBaseBinding(resource, set) + type.getQualifier().layoutBinding); - } else if (ent.live && doAutoBindingMapping()) { - // find free slot, the caller did make sure it passes all vars with binding - // first and now all are passed that do not have a binding and needs one - return ent.newBinding = getFreeSlot(set, getBaseBinding(resource, set)); - } - } - return ent.newBinding = -1; - } -}; -#endif - -// Map I/O variables to provided offsets, and make bindings for -// unbound but live variables. -// -// Returns false if the input is too malformed to do this. -bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) { - bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() || - intermediate.getAutoMapLocations(); - // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce - // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true. - for (int res = 0; (res < EResCount && !somethingToDo); ++res) { - somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) || - intermediate.hasShiftBindingForSet(TResourceType(res)); - } - if (! somethingToDo && resolver == nullptr) - return true; - if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) - return false; - TIntermNode* root = intermediate.getTreeRoot(); - if (root == nullptr) - return false; - // if no resolver is provided, use the default resolver with the given shifts and auto map settings - TDefaultIoResolver defaultResolver(intermediate); -#ifdef ENABLE_HLSL - TDefaultHlslIoResolver defaultHlslResolver(intermediate); - if (resolver == nullptr) { - // TODO: use a passed in IO mapper for this - if (intermediate.usingHlslIoMapping()) - resolver = &defaultHlslResolver; - else - resolver = &defaultResolver; - } - resolver->addStage(stage); -#else - resolver = &defaultResolver; -#endif - - TVarLiveMap inVarMap, outVarMap, uniformVarMap; - TVarLiveVector inVector, outVector, uniformVector; - TVarGatherTraverser iter_binding_all(intermediate, true, inVarMap, outVarMap, uniformVarMap); - TVarGatherTraverser iter_binding_live(intermediate, false, inVarMap, outVarMap, uniformVarMap); - root->traverse(&iter_binding_all); - iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str()); - while (! iter_binding_live.functions.empty()) { - TIntermNode* function = iter_binding_live.functions.back(); - iter_binding_live.functions.pop_back(); - function->traverse(&iter_binding_live); - } - // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info. - std::for_each(inVarMap.begin(), inVarMap.end(), - [&inVector](TVarLivePair p) { inVector.push_back(p); }); - std::sort(inVector.begin(), inVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { - return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); - }); - std::for_each(outVarMap.begin(), outVarMap.end(), - [&outVector](TVarLivePair p) { outVector.push_back(p); }); - std::sort(outVector.begin(), outVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { - return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); - }); - std::for_each(uniformVarMap.begin(), uniformVarMap.end(), - [&uniformVector](TVarLivePair p) { uniformVector.push_back(p); }); - std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { - return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); - }); - bool hadError = false; - TNotifyInOutAdaptor inOutNotify(stage, *resolver); - TNotifyUniformAdaptor uniformNotify(stage, *resolver); - TResolverUniformAdaptor uniformResolve(stage, *resolver, infoSink, hadError); - TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError); - resolver->beginNotifications(stage); - std::for_each(inVector.begin(), inVector.end(), inOutNotify); - std::for_each(outVector.begin(), outVector.end(), inOutNotify); - std::for_each(uniformVector.begin(), uniformVector.end(), uniformNotify); - resolver->endNotifications(stage); - resolver->beginResolve(stage); - std::for_each(inVector.begin(), inVector.end(), inOutResolve); - std::for_each(inVector.begin(), inVector.end(), [&inVarMap](TVarLivePair p) { - auto at = inVarMap.find(p.second.symbol->getName()); - if (at != inVarMap.end()) - at->second = p.second; - }); - std::for_each(outVector.begin(), outVector.end(), inOutResolve); - std::for_each(outVector.begin(), outVector.end(), [&outVarMap](TVarLivePair p) { - auto at = outVarMap.find(p.second.symbol->getName()); - if (at != outVarMap.end()) - at->second = p.second; - }); - std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve); - std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) { - auto at = uniformVarMap.find(p.second.symbol->getName()); - if (at != uniformVarMap.end()) - at->second = p.second; - }); - resolver->endResolve(stage); - if (!hadError) { - TVarSetTraverser iter_iomap(intermediate, inVarMap, outVarMap, uniformVarMap); - root->traverse(&iter_iomap); - } - return !hadError; -} - -// Map I/O variables to provided offsets, and make bindings for -// unbound but live variables. -// -// Returns false if the input is too malformed to do this. -bool TGlslIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) { - - bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() || - intermediate.getAutoMapLocations(); - // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce - // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true. - for (int res = 0; (res < EResCount && !somethingToDo); ++res) { - somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) || - intermediate.hasShiftBindingForSet(TResourceType(res)); - } - if (! somethingToDo && resolver == nullptr) { - return true; - } - if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) { - return false; - } - TIntermNode* root = intermediate.getTreeRoot(); - if (root == nullptr) { - return false; - } - // if no resolver is provided, use the default resolver with the given shifts and auto map settings - TDefaultGlslIoResolver defaultResolver(intermediate); - if (resolver == nullptr) { - resolver = &defaultResolver; - } - resolver->addStage(stage); - inVarMaps[stage] = new TVarLiveMap, outVarMaps[stage] = new TVarLiveMap(), uniformVarMap[stage] = new TVarLiveMap(); - TVarGatherTraverser iter_binding_all(intermediate, true, *inVarMaps[stage], *outVarMaps[stage], - *uniformVarMap[stage]); - TVarGatherTraverser iter_binding_live(intermediate, false, *inVarMaps[stage], *outVarMaps[stage], - *uniformVarMap[stage]); - root->traverse(&iter_binding_all); - iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str()); - while (! iter_binding_live.functions.empty()) { - TIntermNode* function = iter_binding_live.functions.back(); - iter_binding_live.functions.pop_back(); - function->traverse(&iter_binding_live); - } - TNotifyInOutAdaptor inOutNotify(stage, *resolver); - TNotifyUniformAdaptor uniformNotify(stage, *resolver); - // Resolve current stage input symbol location with previous stage output here, - // uniform symbol, ubo, ssbo and opaque symbols are per-program resource, - // will resolve uniform symbol location and ubo/ssbo/opaque binding in doMap() - resolver->beginNotifications(stage); - std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutNotify); - std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutNotify); - std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), uniformNotify); - resolver->endNotifications(stage); - TSlotCollector slotCollector(*resolver, infoSink); - resolver->beginCollect(stage); - std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), slotCollector); - std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), slotCollector); - std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), slotCollector); - resolver->endCollect(stage); - intermediates[stage] = &intermediate; - return !hadError; -} - -bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) { - resolver->endResolve(EShLangCount); - if (!hadError) { - //Resolve uniform location, ubo/ssbo/opaque bindings across stages - TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, infoSink, hadError); - TResolverInOutAdaptor inOutResolve(EShLangCount, *resolver, infoSink, hadError); - TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps, outVarMaps, uniformVarMap, hadError); - TVarLiveVector uniformVector; - resolver->beginResolve(EShLangCount); - for (int stage = EShLangVertex; stage < EShLangCount; stage++) { - if (inVarMaps[stage] != nullptr) { - inOutResolve.setStage(EShLanguage(stage)); - std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), symbolValidater); - std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutResolve); - std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), symbolValidater); - std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutResolve); - } - if (uniformVarMap[stage] != nullptr) { - uniformResolve.setStage(EShLanguage(stage)); - // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info. - std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), - [&uniformVector](TVarLivePair p) { uniformVector.push_back(p); }); - } - } - std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { - return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); - }); - std::for_each(uniformVector.begin(), uniformVector.end(), symbolValidater); - std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve); - std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool { - return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second); - }); - resolver->endResolve(EShLangCount); - for (size_t stage = 0; stage < EShLangCount; stage++) { - if (intermediates[stage] != nullptr) { - // traverse each stage, set new location to each input/output and unifom symbol, set new binding to - // ubo, ssbo and opaque symbols - TVarLiveMap** pUniformVarMap = uniformVarMap; - std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) { - auto at = pUniformVarMap[stage]->find(p.second.symbol->getName()); - if (at != pUniformVarMap[stage]->end()) - at->second = p.second; - }); - TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage], - *uniformVarMap[stage]); - intermediates[stage]->getTreeRoot()->traverse(&iter_iomap); - } - } - return !hadError; - } else { - return false; - } -} - -} // end namespace glslang - -#endif // GLSLANG_WEB diff --git a/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp b/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp deleted file mode 100644 index fe51ec93ff1..00000000000 --- a/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp +++ /dev/null @@ -1,1723 +0,0 @@ -// -// Copyright (C) 2013 LunarG, Inc. -// Copyright (C) 2017 ARM Limited. -// Copyright (C) 2015-2018 Google, Inc. -// -// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. -// - -// -// Do link-time merging and validation of intermediate representations. -// -// Basic model is that during compilation, each compilation unit (shader) is -// compiled into one TIntermediate instance. Then, at link time, multiple -// units for the same stage can be merged together, which can generate errors. -// Then, after all merging, a single instance of TIntermediate represents -// the whole stage. A final error check can be done on the resulting stage, -// even if no merging was done (i.e., the stage was only one compilation unit). -// - -#include "localintermediate.h" -#include "../Include/InfoSink.h" - -namespace glslang { - -// -// Link-time error emitter. -// -void TIntermediate::error(TInfoSink& infoSink, const char* message) -{ -#ifndef GLSLANG_WEB - infoSink.info.prefix(EPrefixError); - infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; -#endif - - ++numErrors; -} - -// Link-time warning. -void TIntermediate::warn(TInfoSink& infoSink, const char* message) -{ -#ifndef GLSLANG_WEB - infoSink.info.prefix(EPrefixWarning); - infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; -#endif -} - -// TODO: 4.4 offset/align: "Two blocks linked together in the same program with the same block -// name must have the exact same set of members qualified with offset and their integral-constant -// expression values must be the same, or a link-time error results." - -// -// Merge the information from 'unit' into 'this' -// -void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit) -{ -#ifndef GLSLANG_WEB - mergeCallGraphs(infoSink, unit); - mergeModes(infoSink, unit); - mergeTrees(infoSink, unit); -#endif -} - -void TIntermediate::mergeCallGraphs(TInfoSink& infoSink, TIntermediate& unit) -{ - if (unit.getNumEntryPoints() > 0) { - if (getNumEntryPoints() > 0) - error(infoSink, "can't handle multiple entry points per stage"); - else { - entryPointName = unit.getEntryPointName(); - entryPointMangledName = unit.getEntryPointMangledName(); - } - } - numEntryPoints += unit.getNumEntryPoints(); - - callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end()); -} - -#ifndef GLSLANG_WEB - -#define MERGE_MAX(member) member = std::max(member, unit.member) -#define MERGE_TRUE(member) if (unit.member) member = unit.member; - -void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) -{ - if (language != unit.language) - error(infoSink, "stages must match when linking into a single stage"); - - if (getSource() == EShSourceNone) - setSource(unit.getSource()); - if (getSource() != unit.getSource()) - error(infoSink, "can't link compilation units from different source languages"); - - if (treeRoot == nullptr) { - profile = unit.profile; - version = unit.version; - requestedExtensions = unit.requestedExtensions; - } else { - if ((isEsProfile()) != (unit.isEsProfile())) - error(infoSink, "Cannot cross link ES and desktop profiles"); - else if (unit.profile == ECompatibilityProfile) - profile = ECompatibilityProfile; - version = std::max(version, unit.version); - requestedExtensions.insert(unit.requestedExtensions.begin(), unit.requestedExtensions.end()); - } - - MERGE_MAX(spvVersion.spv); - MERGE_MAX(spvVersion.vulkanGlsl); - MERGE_MAX(spvVersion.vulkan); - MERGE_MAX(spvVersion.openGl); - - numErrors += unit.getNumErrors(); - numPushConstants += unit.numPushConstants; - - if (unit.invocations != TQualifier::layoutNotSet) { - if (invocations == TQualifier::layoutNotSet) - invocations = unit.invocations; - else if (invocations != unit.invocations) - error(infoSink, "number of invocations must match between compilation units"); - } - - if (vertices == TQualifier::layoutNotSet) - vertices = unit.vertices; - else if (vertices != unit.vertices) { - if (language == EShLangGeometry || language == EShLangMeshNV) - error(infoSink, "Contradictory layout max_vertices values"); - else if (language == EShLangTessControl) - error(infoSink, "Contradictory layout vertices values"); - else - assert(0); - } - if (primitives == TQualifier::layoutNotSet) - primitives = unit.primitives; - else if (primitives != unit.primitives) { - if (language == EShLangMeshNV) - error(infoSink, "Contradictory layout max_primitives values"); - else - assert(0); - } - - if (inputPrimitive == ElgNone) - inputPrimitive = unit.inputPrimitive; - else if (inputPrimitive != unit.inputPrimitive) - error(infoSink, "Contradictory input layout primitives"); - - if (outputPrimitive == ElgNone) - outputPrimitive = unit.outputPrimitive; - else if (outputPrimitive != unit.outputPrimitive) - error(infoSink, "Contradictory output layout primitives"); - - if (originUpperLeft != unit.originUpperLeft || pixelCenterInteger != unit.pixelCenterInteger) - error(infoSink, "gl_FragCoord redeclarations must match across shaders"); - - if (vertexSpacing == EvsNone) - vertexSpacing = unit.vertexSpacing; - else if (vertexSpacing != unit.vertexSpacing) - error(infoSink, "Contradictory input vertex spacing"); - - if (vertexOrder == EvoNone) - vertexOrder = unit.vertexOrder; - else if (vertexOrder != unit.vertexOrder) - error(infoSink, "Contradictory triangle ordering"); - - MERGE_TRUE(pointMode); - - for (int i = 0; i < 3; ++i) { - if (!localSizeNotDefault[i] && unit.localSizeNotDefault[i]) { - localSize[i] = unit.localSize[i]; - localSizeNotDefault[i] = true; - } - else if (localSize[i] != unit.localSize[i]) - error(infoSink, "Contradictory local size"); - - if (localSizeSpecId[i] == TQualifier::layoutNotSet) - localSizeSpecId[i] = unit.localSizeSpecId[i]; - else if (localSizeSpecId[i] != unit.localSizeSpecId[i]) - error(infoSink, "Contradictory local size specialization ids"); - } - - MERGE_TRUE(earlyFragmentTests); - MERGE_TRUE(postDepthCoverage); - - if (depthLayout == EldNone) - depthLayout = unit.depthLayout; - else if (depthLayout != unit.depthLayout) - error(infoSink, "Contradictory depth layouts"); - - MERGE_TRUE(depthReplacing); - MERGE_TRUE(hlslFunctionality1); - - blendEquations |= unit.blendEquations; - - MERGE_TRUE(xfbMode); - - for (size_t b = 0; b < xfbBuffers.size(); ++b) { - if (xfbBuffers[b].stride == TQualifier::layoutXfbStrideEnd) - xfbBuffers[b].stride = unit.xfbBuffers[b].stride; - else if (xfbBuffers[b].stride != unit.xfbBuffers[b].stride) - error(infoSink, "Contradictory xfb_stride"); - xfbBuffers[b].implicitStride = std::max(xfbBuffers[b].implicitStride, unit.xfbBuffers[b].implicitStride); - if (unit.xfbBuffers[b].contains64BitType) - xfbBuffers[b].contains64BitType = true; - if (unit.xfbBuffers[b].contains32BitType) - xfbBuffers[b].contains32BitType = true; - if (unit.xfbBuffers[b].contains16BitType) - xfbBuffers[b].contains16BitType = true; - // TODO: 4.4 link: enhanced layouts: compare ranges - } - - MERGE_TRUE(multiStream); - MERGE_TRUE(layoutOverrideCoverage); - MERGE_TRUE(geoPassthroughEXT); - - for (unsigned int i = 0; i < unit.shiftBinding.size(); ++i) { - if (unit.shiftBinding[i] > 0) - setShiftBinding((TResourceType)i, unit.shiftBinding[i]); - } - - for (unsigned int i = 0; i < unit.shiftBindingForSet.size(); ++i) { - for (auto it = unit.shiftBindingForSet[i].begin(); it != unit.shiftBindingForSet[i].end(); ++it) - setShiftBindingForSet((TResourceType)i, it->second, it->first); - } - - resourceSetBinding.insert(resourceSetBinding.end(), unit.resourceSetBinding.begin(), unit.resourceSetBinding.end()); - - MERGE_TRUE(autoMapBindings); - MERGE_TRUE(autoMapLocations); - MERGE_TRUE(invertY); - MERGE_TRUE(flattenUniformArrays); - MERGE_TRUE(useUnknownFormat); - MERGE_TRUE(hlslOffsets); - MERGE_TRUE(useStorageBuffer); - MERGE_TRUE(hlslIoMapping); - - // TODO: sourceFile - // TODO: sourceText - // TODO: processes - - MERGE_TRUE(needToLegalize); - MERGE_TRUE(binaryDoubleOutput); - MERGE_TRUE(usePhysicalStorageBuffer); -} - -// -// Merge the 'unit' AST into 'this' AST. -// That includes rationalizing the unique IDs, which were set up independently, -// and might have overlaps that are not the same symbol, or might have different -// IDs for what should be the same shared symbol. -// -void TIntermediate::mergeTrees(TInfoSink& infoSink, TIntermediate& unit) -{ - if (unit.treeRoot == nullptr) - return; - - if (treeRoot == nullptr) { - treeRoot = unit.treeRoot; - return; - } - - // Getting this far means we have two existing trees to merge... - numShaderRecordNVBlocks += unit.numShaderRecordNVBlocks; - numTaskNVBlocks += unit.numTaskNVBlocks; - - // Get the top-level globals of each unit - TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence(); - TIntermSequence& unitGlobals = unit.treeRoot->getAsAggregate()->getSequence(); - - // Get the linker-object lists - TIntermSequence& linkerObjects = findLinkerObjects()->getSequence(); - const TIntermSequence& unitLinkerObjects = unit.findLinkerObjects()->getSequence(); - - // Map by global name to unique ID to rationalize the same object having - // differing IDs in different trees. - TMap idMap; - int maxId; - seedIdMap(idMap, maxId); - remapIds(idMap, maxId + 1, unit); - - mergeBodies(infoSink, globals, unitGlobals); - mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects); - ioAccessed.insert(unit.ioAccessed.begin(), unit.ioAccessed.end()); -} - -#endif - -// Traverser that seeds an ID map with all built-ins, and tracks the -// maximum ID used. -// (It would be nice to put this in a function, but that causes warnings -// on having no bodies for the copy-constructor/operator=.) -class TBuiltInIdTraverser : public TIntermTraverser { -public: - TBuiltInIdTraverser(TMap& idMap) : idMap(idMap), maxId(0) { } - // If it's a built in, add it to the map. - // Track the max ID. - virtual void visitSymbol(TIntermSymbol* symbol) - { - const TQualifier& qualifier = symbol->getType().getQualifier(); - if (qualifier.builtIn != EbvNone) - idMap[symbol->getName()] = symbol->getId(); - maxId = std::max(maxId, symbol->getId()); - } - int getMaxId() const { return maxId; } -protected: - TBuiltInIdTraverser(TBuiltInIdTraverser&); - TBuiltInIdTraverser& operator=(TBuiltInIdTraverser&); - TMap& idMap; - int maxId; -}; - -// Traverser that seeds an ID map with non-builtins. -// (It would be nice to put this in a function, but that causes warnings -// on having no bodies for the copy-constructor/operator=.) -class TUserIdTraverser : public TIntermTraverser { -public: - TUserIdTraverser(TMap& idMap) : idMap(idMap) { } - // If its a non-built-in global, add it to the map. - virtual void visitSymbol(TIntermSymbol* symbol) - { - const TQualifier& qualifier = symbol->getType().getQualifier(); - if (qualifier.builtIn == EbvNone) - idMap[symbol->getName()] = symbol->getId(); - } - -protected: - TUserIdTraverser(TUserIdTraverser&); - TUserIdTraverser& operator=(TUserIdTraverser&); - TMap& idMap; // over biggest id -}; - -// Initialize the the ID map with what we know of 'this' AST. -void TIntermediate::seedIdMap(TMap& idMap, int& maxId) -{ - // all built-ins everywhere need to align on IDs and contribute to the max ID - TBuiltInIdTraverser builtInIdTraverser(idMap); - treeRoot->traverse(&builtInIdTraverser); - maxId = builtInIdTraverser.getMaxId(); - - // user variables in the linker object list need to align on ids - TUserIdTraverser userIdTraverser(idMap); - findLinkerObjects()->traverse(&userIdTraverser); -} - -// Traverser to map an AST ID to what was known from the seeding AST. -// (It would be nice to put this in a function, but that causes warnings -// on having no bodies for the copy-constructor/operator=.) -class TRemapIdTraverser : public TIntermTraverser { -public: - TRemapIdTraverser(const TMap& idMap, int idShift) : idMap(idMap), idShift(idShift) { } - // Do the mapping: - // - if the same symbol, adopt the 'this' ID - // - otherwise, ensure a unique ID by shifting to a new space - virtual void visitSymbol(TIntermSymbol* symbol) - { - const TQualifier& qualifier = symbol->getType().getQualifier(); - bool remapped = false; - if (qualifier.isLinkable() || qualifier.builtIn != EbvNone) { - auto it = idMap.find(symbol->getName()); - if (it != idMap.end()) { - symbol->changeId(it->second); - remapped = true; - } - } - if (!remapped) - symbol->changeId(symbol->getId() + idShift); - } -protected: - TRemapIdTraverser(TRemapIdTraverser&); - TRemapIdTraverser& operator=(TRemapIdTraverser&); - const TMap& idMap; - int idShift; -}; - -void TIntermediate::remapIds(const TMap& idMap, int idShift, TIntermediate& unit) -{ - // Remap all IDs to either share or be unique, as dictated by the idMap and idShift. - TRemapIdTraverser idTraverser(idMap, idShift); - unit.getTreeRoot()->traverse(&idTraverser); -} - -// -// Merge the function bodies and global-level initializers from unitGlobals into globals. -// Will error check duplication of function bodies for the same signature. -// -void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals) -{ - // TODO: link-time performance: Processing in alphabetical order will be faster - - // Error check the global objects, not including the linker objects - for (unsigned int child = 0; child < globals.size() - 1; ++child) { - for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) { - TIntermAggregate* body = globals[child]->getAsAggregate(); - TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate(); - if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) { - error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:"); - infoSink.info << " " << globals[child]->getAsAggregate()->getName() << "\n"; - } - } - } - - // Merge the global objects, just in front of the linker objects - globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1); -} - -// -// Merge the linker objects from unitLinkerObjects into linkerObjects. -// Duplication is expected and filtered out, but contradictions are an error. -// -void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects) -{ - // Error check and merge the linker objects (duplicates should not be created) - std::size_t initialNumLinkerObjects = linkerObjects.size(); - for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) { - bool merge = true; - for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) { - TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode(); - TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); - assert(symbol && unitSymbol); - if (symbol->getName() == unitSymbol->getName()) { - // filter out copy - merge = false; - - // but if one has an initializer and the other does not, update - // the initializer - if (symbol->getConstArray().empty() && ! unitSymbol->getConstArray().empty()) - symbol->setConstArray(unitSymbol->getConstArray()); - - // Similarly for binding - if (! symbol->getQualifier().hasBinding() && unitSymbol->getQualifier().hasBinding()) - symbol->getQualifier().layoutBinding = unitSymbol->getQualifier().layoutBinding; - - // Update implicit array sizes - mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType()); - - // Check for consistent types/qualification/initializers etc. - mergeErrorCheck(infoSink, *symbol, *unitSymbol, false); - } - } - if (merge) - linkerObjects.push_back(unitLinkerObjects[unitLinkObj]); - } -} - -// TODO 4.5 link functionality: cull distance array size checking - -// Recursively merge the implicit array sizes through the objects' respective type trees. -void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType) -{ - if (type.isUnsizedArray()) { - if (unitType.isUnsizedArray()) { - type.updateImplicitArraySize(unitType.getImplicitArraySize()); - if (unitType.isArrayVariablyIndexed()) - type.setArrayVariablyIndexed(); - } else if (unitType.isSizedArray()) - type.changeOuterArraySize(unitType.getOuterArraySize()); - } - - // Type mismatches are caught and reported after this, just be careful for now. - if (! type.isStruct() || ! unitType.isStruct() || type.getStruct()->size() != unitType.getStruct()->size()) - return; - - for (int i = 0; i < (int)type.getStruct()->size(); ++i) - mergeImplicitArraySizes(*(*type.getStruct())[i].type, *(*unitType.getStruct())[i].type); -} - -// -// Compare two global objects from two compilation units and see if they match -// well enough. Rules can be different for intra- vs. cross-stage matching. -// -// This function only does one of intra- or cross-stage matching per call. -// -void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, bool crossStage) -{ -#ifndef GLSLANG_WEB - bool writeTypeComparison = false; - - // Types have to match - if (symbol.getType() != unitSymbol.getType()) { - // but, we make an exception if one is an implicit array and the other is sized - if (! (symbol.getType().isArray() && unitSymbol.getType().isArray() && - symbol.getType().sameElementType(unitSymbol.getType()) && - (symbol.getType().isUnsizedArray() || unitSymbol.getType().isUnsizedArray()))) { - error(infoSink, "Types must match:"); - writeTypeComparison = true; - } - } - - // Qualifiers have to (almost) match - - // Storage... - if (symbol.getQualifier().storage != unitSymbol.getQualifier().storage) { - error(infoSink, "Storage qualifiers must match:"); - writeTypeComparison = true; - } - - // Precision... - if (symbol.getQualifier().precision != unitSymbol.getQualifier().precision) { - error(infoSink, "Precision qualifiers must match:"); - writeTypeComparison = true; - } - - // Invariance... - if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) { - error(infoSink, "Presence of invariant qualifier must match:"); - writeTypeComparison = true; - } - - // Precise... - if (! crossStage && symbol.getQualifier().isNoContraction() != unitSymbol.getQualifier().isNoContraction()) { - error(infoSink, "Presence of precise qualifier must match:"); - writeTypeComparison = true; - } - - // Auxiliary and interpolation... - if (symbol.getQualifier().centroid != unitSymbol.getQualifier().centroid || - symbol.getQualifier().smooth != unitSymbol.getQualifier().smooth || - symbol.getQualifier().flat != unitSymbol.getQualifier().flat || - symbol.getQualifier().isSample()!= unitSymbol.getQualifier().isSample() || - symbol.getQualifier().isPatch() != unitSymbol.getQualifier().isPatch() || - symbol.getQualifier().isNonPerspective() != unitSymbol.getQualifier().isNonPerspective()) { - error(infoSink, "Interpolation and auxiliary storage qualifiers must match:"); - writeTypeComparison = true; - } - - // Memory... - if (symbol.getQualifier().coherent != unitSymbol.getQualifier().coherent || - symbol.getQualifier().devicecoherent != unitSymbol.getQualifier().devicecoherent || - symbol.getQualifier().queuefamilycoherent != unitSymbol.getQualifier().queuefamilycoherent || - symbol.getQualifier().workgroupcoherent != unitSymbol.getQualifier().workgroupcoherent || - symbol.getQualifier().subgroupcoherent != unitSymbol.getQualifier().subgroupcoherent || - symbol.getQualifier().nonprivate != unitSymbol.getQualifier().nonprivate || - symbol.getQualifier().volatil != unitSymbol.getQualifier().volatil || - symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict || - symbol.getQualifier().readonly != unitSymbol.getQualifier().readonly || - symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) { - error(infoSink, "Memory qualifiers must match:"); - writeTypeComparison = true; - } - - // Layouts... - // TODO: 4.4 enhanced layouts: Generalize to include offset/align: current spec - // requires separate user-supplied offset from actual computed offset, but - // current implementation only has one offset. - if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix || - symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking || - symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation || - symbol.getQualifier().layoutComponent != unitSymbol.getQualifier().layoutComponent || - symbol.getQualifier().layoutIndex != unitSymbol.getQualifier().layoutIndex || - symbol.getQualifier().layoutBinding != unitSymbol.getQualifier().layoutBinding || - (symbol.getQualifier().hasBinding() && (symbol.getQualifier().layoutOffset != unitSymbol.getQualifier().layoutOffset))) { - error(infoSink, "Layout qualification must match:"); - writeTypeComparison = true; - } - - // Initializers have to match, if both are present, and if we don't already know the types don't match - if (! writeTypeComparison) { - if (! symbol.getConstArray().empty() && ! unitSymbol.getConstArray().empty()) { - if (symbol.getConstArray() != unitSymbol.getConstArray()) { - error(infoSink, "Initializers must match:"); - infoSink.info << " " << symbol.getName() << "\n"; - } - } - } - - if (writeTypeComparison) - infoSink.info << " " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus \"" << - unitSymbol.getType().getCompleteString() << "\"\n"; -#endif -} - -// -// Do final link-time error checking of a complete (merged) intermediate representation. -// (Much error checking was done during merging). -// -// Also, lock in defaults of things not set, including array sizes. -// -void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled) -{ - if (getTreeRoot() == nullptr) - return; - - if (numEntryPoints < 1) { - if (getSource() == EShSourceGlsl) - error(infoSink, "Missing entry point: Each stage requires one entry point"); - else - warn(infoSink, "Entry point not found"); - } - - // recursion and missing body checking - checkCallGraphCycles(infoSink); - checkCallGraphBodies(infoSink, keepUncalled); - - // overlap/alias/missing I/O, etc. - inOutLocationCheck(infoSink); - -#ifndef GLSLANG_WEB - if (getNumPushConstants() > 1) - error(infoSink, "Only one push_constant block is allowed per stage"); - - // invocations - if (invocations == TQualifier::layoutNotSet) - invocations = 1; - - if (inIoAccessed("gl_ClipDistance") && inIoAccessed("gl_ClipVertex")) - error(infoSink, "Can only use one of gl_ClipDistance or gl_ClipVertex (gl_ClipDistance is preferred)"); - if (inIoAccessed("gl_CullDistance") && inIoAccessed("gl_ClipVertex")) - error(infoSink, "Can only use one of gl_CullDistance or gl_ClipVertex (gl_ClipDistance is preferred)"); - - if (userOutputUsed() && (inIoAccessed("gl_FragColor") || inIoAccessed("gl_FragData"))) - error(infoSink, "Cannot use gl_FragColor or gl_FragData when using user-defined outputs"); - if (inIoAccessed("gl_FragColor") && inIoAccessed("gl_FragData")) - error(infoSink, "Cannot use both gl_FragColor and gl_FragData"); - - for (size_t b = 0; b < xfbBuffers.size(); ++b) { - if (xfbBuffers[b].contains64BitType) - RoundToPow2(xfbBuffers[b].implicitStride, 8); - else if (xfbBuffers[b].contains32BitType) - RoundToPow2(xfbBuffers[b].implicitStride, 4); - else if (xfbBuffers[b].contains16BitType) - RoundToPow2(xfbBuffers[b].implicitStride, 2); - - // "It is a compile-time or link-time error to have - // any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or - // in different compilation units. While xfb_stride can be declared multiple times for the same buffer, it is a - // compile-time or link-time error to have different values specified for the stride for the same buffer." - if (xfbBuffers[b].stride != TQualifier::layoutXfbStrideEnd && xfbBuffers[b].implicitStride > xfbBuffers[b].stride) { - error(infoSink, "xfb_stride is too small to hold all buffer entries:"); - infoSink.info.prefix(EPrefixError); - infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << ", minimum stride needed: " << xfbBuffers[b].implicitStride << "\n"; - } - if (xfbBuffers[b].stride == TQualifier::layoutXfbStrideEnd) - xfbBuffers[b].stride = xfbBuffers[b].implicitStride; - - // "If the buffer is capturing any - // outputs with double-precision or 64-bit integer components, the stride must be a multiple of 8, otherwise it must be a - // multiple of 4, or a compile-time or link-time error results." - if (xfbBuffers[b].contains64BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 8)) { - error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double or 64-bit integer:"); - infoSink.info.prefix(EPrefixError); - infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n"; - } else if (xfbBuffers[b].contains32BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) { - error(infoSink, "xfb_stride must be multiple of 4:"); - infoSink.info.prefix(EPrefixError); - infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n"; - } - // "If the buffer is capturing any - // outputs with half-precision or 16-bit integer components, the stride must be a multiple of 2" - else if (xfbBuffers[b].contains16BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 2)) { - error(infoSink, "xfb_stride must be multiple of 2 for buffer holding a half float or 16-bit integer:"); - infoSink.info.prefix(EPrefixError); - infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n"; - } - - // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the - // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents." - if (xfbBuffers[b].stride > (unsigned int)(4 * resources.maxTransformFeedbackInterleavedComponents)) { - error(infoSink, "xfb_stride is too large:"); - infoSink.info.prefix(EPrefixError); - infoSink.info << " xfb_buffer " << (unsigned int)b << ", components (1/4 stride) needed are " << xfbBuffers[b].stride/4 << ", gl_MaxTransformFeedbackInterleavedComponents is " << resources.maxTransformFeedbackInterleavedComponents << "\n"; - } - } - - switch (language) { - case EShLangVertex: - break; - case EShLangTessControl: - if (vertices == TQualifier::layoutNotSet) - error(infoSink, "At least one shader must specify an output layout(vertices=...)"); - break; - case EShLangTessEvaluation: - if (getSource() == EShSourceGlsl) { - if (inputPrimitive == ElgNone) - error(infoSink, "At least one shader must specify an input layout primitive"); - if (vertexSpacing == EvsNone) - vertexSpacing = EvsEqual; - if (vertexOrder == EvoNone) - vertexOrder = EvoCcw; - } - break; - case EShLangGeometry: - if (inputPrimitive == ElgNone) - error(infoSink, "At least one shader must specify an input layout primitive"); - if (outputPrimitive == ElgNone) - error(infoSink, "At least one shader must specify an output layout primitive"); - if (vertices == TQualifier::layoutNotSet) - error(infoSink, "At least one shader must specify a layout(max_vertices = value)"); - break; - case EShLangFragment: - // for GL_ARB_post_depth_coverage, EarlyFragmentTest is set automatically in - // ParseHelper.cpp. So if we reach here, this must be GL_EXT_post_depth_coverage - // requiring explicit early_fragment_tests - if (getPostDepthCoverage() && !getEarlyFragmentTests()) - error(infoSink, "post_depth_coverage requires early_fragment_tests"); - break; - case EShLangCompute: - break; - case EShLangRayGenNV: - case EShLangIntersectNV: - case EShLangAnyHitNV: - case EShLangClosestHitNV: - case EShLangMissNV: - case EShLangCallableNV: - if (numShaderRecordNVBlocks > 1) - error(infoSink, "Only one shaderRecordNV buffer block is allowed per stage"); - break; - case EShLangMeshNV: - // NV_mesh_shader doesn't allow use of both single-view and per-view builtins. - if (inIoAccessed("gl_Position") && inIoAccessed("gl_PositionPerViewNV")) - error(infoSink, "Can only use one of gl_Position or gl_PositionPerViewNV"); - if (inIoAccessed("gl_ClipDistance") && inIoAccessed("gl_ClipDistancePerViewNV")) - error(infoSink, "Can only use one of gl_ClipDistance or gl_ClipDistancePerViewNV"); - if (inIoAccessed("gl_CullDistance") && inIoAccessed("gl_CullDistancePerViewNV")) - error(infoSink, "Can only use one of gl_CullDistance or gl_CullDistancePerViewNV"); - if (inIoAccessed("gl_Layer") && inIoAccessed("gl_LayerPerViewNV")) - error(infoSink, "Can only use one of gl_Layer or gl_LayerPerViewNV"); - if (inIoAccessed("gl_ViewportMask") && inIoAccessed("gl_ViewportMaskPerViewNV")) - error(infoSink, "Can only use one of gl_ViewportMask or gl_ViewportMaskPerViewNV"); - if (outputPrimitive == ElgNone) - error(infoSink, "At least one shader must specify an output layout primitive"); - if (vertices == TQualifier::layoutNotSet) - error(infoSink, "At least one shader must specify a layout(max_vertices = value)"); - if (primitives == TQualifier::layoutNotSet) - error(infoSink, "At least one shader must specify a layout(max_primitives = value)"); - // fall through - case EShLangTaskNV: - if (numTaskNVBlocks > 1) - error(infoSink, "Only one taskNV interface block is allowed per shader"); - break; - default: - error(infoSink, "Unknown Stage."); - break; - } - - // Process the tree for any node-specific work. - class TFinalLinkTraverser : public TIntermTraverser { - public: - TFinalLinkTraverser() { } - virtual ~TFinalLinkTraverser() { } - - virtual void visitSymbol(TIntermSymbol* symbol) - { - // Implicitly size arrays. - // If an unsized array is left as unsized, it effectively - // becomes run-time sized. - symbol->getWritableType().adoptImplicitArraySizes(false); - } - } finalLinkTraverser; - - treeRoot->traverse(&finalLinkTraverser); -#endif -} - -// -// See if the call graph contains any static recursion, which is disallowed -// by the specification. -// -void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink) -{ - // Clear fields we'll use for this. - for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { - call->visited = false; - call->currentPath = false; - call->errorGiven = false; - } - - // - // Loop, looking for a new connected subgraph. One subgraph is handled per loop iteration. - // - - TCall* newRoot; - do { - // See if we have unvisited parts of the graph. - newRoot = 0; - for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { - if (! call->visited) { - newRoot = &(*call); - break; - } - } - - // If not, we are done. - if (! newRoot) - break; - - // Otherwise, we found a new subgraph, process it: - // See what all can be reached by this new root, and if any of - // that is recursive. This is done by depth-first traversals, seeing - // if a new call is found that was already in the currentPath (a back edge), - // thereby detecting recursion. - std::list stack; - newRoot->currentPath = true; // currentPath will be true iff it is on the stack - stack.push_back(newRoot); - while (! stack.empty()) { - // get a caller - TCall* call = stack.back(); - - // Add to the stack just one callee. - // This algorithm always terminates, because only !visited and !currentPath causes a push - // and all pushes change currentPath to true, and all pops change visited to true. - TGraph::iterator child = callGraph.begin(); - for (; child != callGraph.end(); ++child) { - - // If we already visited this node, its whole subgraph has already been processed, so skip it. - if (child->visited) - continue; - - if (call->callee == child->caller) { - if (child->currentPath) { - // Then, we found a back edge - if (! child->errorGiven) { - error(infoSink, "Recursion detected:"); - infoSink.info << " " << call->callee << " calling " << child->callee << "\n"; - child->errorGiven = true; - recursive = true; - } - } else { - child->currentPath = true; - stack.push_back(&(*child)); - break; - } - } - } - if (child == callGraph.end()) { - // no more callees, we bottomed out, never look at this node again - stack.back()->currentPath = false; - stack.back()->visited = true; - stack.pop_back(); - } - } // end while, meaning nothing left to process in this subtree - - } while (newRoot); // redundant loop check; should always exit via the 'break' above -} - -// -// See which functions are reachable from the entry point and which have bodies. -// Reachable ones with missing bodies are errors. -// Unreachable bodies are dead code. -// -void TIntermediate::checkCallGraphBodies(TInfoSink& infoSink, bool keepUncalled) -{ - // Clear fields we'll use for this. - for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { - call->visited = false; - call->calleeBodyPosition = -1; - } - - // The top level of the AST includes function definitions (bodies). - // Compare these to function calls in the call graph. - // We'll end up knowing which have bodies, and if so, - // how to map the call-graph node to the location in the AST. - TIntermSequence &functionSequence = getTreeRoot()->getAsAggregate()->getSequence(); - std::vector reachable(functionSequence.size(), true); // so that non-functions are reachable - for (int f = 0; f < (int)functionSequence.size(); ++f) { - glslang::TIntermAggregate* node = functionSequence[f]->getAsAggregate(); - if (node && (node->getOp() == glslang::EOpFunction)) { - if (node->getName().compare(getEntryPointMangledName().c_str()) != 0) - reachable[f] = false; // so that function bodies are unreachable, until proven otherwise - for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { - if (call->callee == node->getName()) - call->calleeBodyPosition = f; - } - } - } - - // Start call-graph traversal by visiting the entry point nodes. - for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { - if (call->caller.compare(getEntryPointMangledName().c_str()) == 0) - call->visited = true; - } - - // Propagate 'visited' through the call-graph to every part of the graph it - // can reach (seeded with the entry-point setting above). - bool changed; - do { - changed = false; - for (auto call1 = callGraph.begin(); call1 != callGraph.end(); ++call1) { - if (call1->visited) { - for (TGraph::iterator call2 = callGraph.begin(); call2 != callGraph.end(); ++call2) { - if (! call2->visited) { - if (call1->callee == call2->caller) { - changed = true; - call2->visited = true; - } - } - } - } - } - } while (changed); - - // Any call-graph node set to visited but without a callee body is an error. - for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { - if (call->visited) { - if (call->calleeBodyPosition == -1) { - error(infoSink, "No function definition (body) found: "); - infoSink.info << " " << call->callee << "\n"; - } else - reachable[call->calleeBodyPosition] = true; - } - } - - // Bodies in the AST not reached by the call graph are dead; - // clear them out, since they can't be reached and also can't - // be translated further due to possibility of being ill defined. - if (! keepUncalled) { - for (int f = 0; f < (int)functionSequence.size(); ++f) { - if (! reachable[f]) - functionSequence[f] = nullptr; - } - functionSequence.erase(std::remove(functionSequence.begin(), functionSequence.end(), nullptr), functionSequence.end()); - } -} - -// -// Satisfy rules for location qualifiers on inputs and outputs -// -void TIntermediate::inOutLocationCheck(TInfoSink& infoSink) -{ - // ES 3.0 requires all outputs to have location qualifiers if there is more than one output - bool fragOutWithNoLocation = false; - int numFragOut = 0; - - // TODO: linker functionality: location collision checking - - TIntermSequence& linkObjects = findLinkerObjects()->getSequence(); - for (size_t i = 0; i < linkObjects.size(); ++i) { - const TType& type = linkObjects[i]->getAsTyped()->getType(); - const TQualifier& qualifier = type.getQualifier(); - if (language == EShLangFragment) { - if (qualifier.storage == EvqVaryingOut && qualifier.builtIn == EbvNone) { - ++numFragOut; - if (!qualifier.hasAnyLocation()) - fragOutWithNoLocation = true; - } - } - } - - if (isEsProfile()) { - if (numFragOut > 1 && fragOutWithNoLocation) - error(infoSink, "when more than one fragment shader output, all must have location qualifiers"); - } -} - -TIntermAggregate* TIntermediate::findLinkerObjects() const -{ - // Get the top-level globals - TIntermSequence& globals = treeRoot->getAsAggregate()->getSequence(); - - // Get the last member of the sequences, expected to be the linker-object lists - assert(globals.back()->getAsAggregate()->getOp() == EOpLinkerObjects); - - return globals.back()->getAsAggregate(); -} - -// See if a variable was both a user-declared output and used. -// Note: the spec discusses writing to one, but this looks at read or write, which -// is more useful, and perhaps the spec should be changed to reflect that. -bool TIntermediate::userOutputUsed() const -{ - const TIntermSequence& linkerObjects = findLinkerObjects()->getSequence(); - - bool found = false; - for (size_t i = 0; i < linkerObjects.size(); ++i) { - const TIntermSymbol& symbolNode = *linkerObjects[i]->getAsSymbolNode(); - if (symbolNode.getQualifier().storage == EvqVaryingOut && - symbolNode.getName().compare(0, 3, "gl_") != 0 && - inIoAccessed(symbolNode.getName())) { - found = true; - break; - } - } - - return found; -} - -// Accumulate locations used for inputs, outputs, and uniforms, and check for collisions -// as the accumulation is done. -// -// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. -// -// typeCollision is set to true if there is no direct collision, but the types in the same location -// are different. -// -int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& type, bool& typeCollision) -{ - typeCollision = false; - - int set; - if (qualifier.isPipeInput()) - set = 0; - else if (qualifier.isPipeOutput()) - set = 1; - else if (qualifier.storage == EvqUniform) - set = 2; - else if (qualifier.storage == EvqBuffer) - set = 3; - else - return -1; - - int size; - if (qualifier.isUniformOrBuffer() || qualifier.isTaskMemory()) { - if (type.isSizedArray()) - size = type.getCumulativeArraySize(); - else - size = 1; - } else { - // Strip off the outer array dimension for those having an extra one. - if (type.isArray() && qualifier.isArrayedIo(language)) { - TType elementType(type, 0); - size = computeTypeLocationSize(elementType, language); - } else - size = computeTypeLocationSize(type, language); - } - - // Locations, and components within locations. - // - // Almost always, dealing with components means a single location is involved. - // The exception is a dvec3. From the spec: - // - // "A dvec3 will consume all four components of the first location and components 0 and 1 of - // the second location. This leaves components 2 and 3 available for other component-qualified - // declarations." - // - // That means, without ever mentioning a component, a component range - // for a different location gets specified, if it's not a vertex shader input. (!) - // (A vertex shader input will show using only one location, even for a dvec3/4.) - // - // So, for the case of dvec3, we need two independent ioRanges. - - int collision = -1; // no collision -#ifndef GLSLANG_WEB - if (size == 2 && type.getBasicType() == EbtDouble && type.getVectorSize() == 3 && - (qualifier.isPipeInput() || qualifier.isPipeOutput())) { - // Dealing with dvec3 in/out split across two locations. - // Need two io-ranges. - // The case where the dvec3 doesn't start at component 0 was previously caught as overflow. - - // First range: - TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation); - TRange componentRange(0, 3); - TIoRange range(locationRange, componentRange, type.getBasicType(), 0); - - // check for collisions - collision = checkLocationRange(set, range, type, typeCollision); - if (collision < 0) { - usedIo[set].push_back(range); - - // Second range: - TRange locationRange2(qualifier.layoutLocation + 1, qualifier.layoutLocation + 1); - TRange componentRange2(0, 1); - TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0); - - // check for collisions - collision = checkLocationRange(set, range2, type, typeCollision); - if (collision < 0) - usedIo[set].push_back(range2); - } - } else -#endif - { - // Not a dvec3 in/out split across two locations, generic path. - // Need a single IO-range block. - - TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1); - TRange componentRange(0, 3); - if (qualifier.hasComponent() || type.getVectorSize() > 0) { - int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1); - if (qualifier.hasComponent()) - componentRange.start = qualifier.layoutComponent; - componentRange.last = componentRange.start + consumedComponents - 1; - } - - // combine location and component ranges - TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.getIndex() : 0); - - // check for collisions, except for vertex inputs on desktop targeting OpenGL - if (! (!isEsProfile() && language == EShLangVertex && qualifier.isPipeInput()) || spvVersion.vulkan > 0) - collision = checkLocationRange(set, range, type, typeCollision); - - if (collision < 0) - usedIo[set].push_back(range); - } - - return collision; -} - -// Compare a new (the passed in) 'range' against the existing set, and see -// if there are any collisions. -// -// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. -// -int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TType& type, bool& typeCollision) -{ - for (size_t r = 0; r < usedIo[set].size(); ++r) { - if (range.overlap(usedIo[set][r])) { - // there is a collision; pick one - return std::max(range.location.start, usedIo[set][r].location.start); - } else if (range.location.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) { - // aliased-type mismatch - typeCollision = true; - return std::max(range.location.start, usedIo[set][r].location.start); - } - } - - return -1; // no collision -} - -// Accumulate bindings and offsets, and check for collisions -// as the accumulation is done. -// -// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. -// -int TIntermediate::addUsedOffsets(int binding, int offset, int numOffsets) -{ - TRange bindingRange(binding, binding); - TRange offsetRange(offset, offset + numOffsets - 1); - TOffsetRange range(bindingRange, offsetRange); - - // check for collisions, except for vertex inputs on desktop - for (size_t r = 0; r < usedAtomics.size(); ++r) { - if (range.overlap(usedAtomics[r])) { - // there is a collision; pick one - return std::max(offset, usedAtomics[r].offset.start); - } - } - - usedAtomics.push_back(range); - - return -1; // no collision -} - -// Accumulate used constant_id values. -// -// Return false is one was already used. -bool TIntermediate::addUsedConstantId(int id) -{ - if (usedConstantId.find(id) != usedConstantId.end()) - return false; - - usedConstantId.insert(id); - - return true; -} - -// Recursively figure out how many locations are used up by an input or output type. -// Return the size of type, as measured by "locations". -int TIntermediate::computeTypeLocationSize(const TType& type, EShLanguage stage) -{ - // "If the declared input is an array of size n and each element takes m locations, it will be assigned m * n - // consecutive locations..." - if (type.isArray()) { - // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness - // TODO: are there valid cases of having an unsized array with a location? If so, running this code too early. - TType elementType(type, 0); - if (type.isSizedArray() && !type.getQualifier().isPerView()) - return type.getOuterArraySize() * computeTypeLocationSize(elementType, stage); - else { -#ifndef GLSLANG_WEB - // unset perViewNV attributes for arrayed per-view outputs: "perviewNV vec4 v[MAX_VIEWS][3];" - elementType.getQualifier().perViewNV = false; -#endif - return computeTypeLocationSize(elementType, stage); - } - } - - // "The locations consumed by block and structure members are determined by applying the rules above - // recursively..." - if (type.isStruct()) { - int size = 0; - for (int member = 0; member < (int)type.getStruct()->size(); ++member) { - TType memberType(type, member); - size += computeTypeLocationSize(memberType, stage); - } - return size; - } - - // ES: "If a shader input is any scalar or vector type, it will consume a single location." - - // Desktop: "If a vertex shader input is any scalar or vector type, it will consume a single location. If a non-vertex - // shader input is a scalar or vector type other than dvec3 or dvec4, it will consume a single location, while - // types dvec3 or dvec4 will consume two consecutive locations. Inputs of type double and dvec2 will - // consume only a single location, in all stages." - if (type.isScalar()) - return 1; - if (type.isVector()) { - if (stage == EShLangVertex && type.getQualifier().isPipeInput()) - return 1; - if (type.getBasicType() == EbtDouble && type.getVectorSize() > 2) - return 2; - else - return 1; - } - - // "If the declared input is an n x m single- or double-precision matrix, ... - // The number of locations assigned for each matrix will be the same as - // for an n-element array of m-component vectors..." - if (type.isMatrix()) { - TType columnType(type, 0); - return type.getMatrixCols() * computeTypeLocationSize(columnType, stage); - } - - assert(0); - return 1; -} - -// Same as computeTypeLocationSize but for uniforms -int TIntermediate::computeTypeUniformLocationSize(const TType& type) -{ - // "Individual elements of a uniform array are assigned - // consecutive locations with the first element taking location - // location." - if (type.isArray()) { - // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness - TType elementType(type, 0); - if (type.isSizedArray()) { - return type.getOuterArraySize() * computeTypeUniformLocationSize(elementType); - } else { - // TODO: are there valid cases of having an implicitly-sized array with a location? If so, running this code too early. - return computeTypeUniformLocationSize(elementType); - } - } - - // "Each subsequent inner-most member or element gets incremental - // locations for the entire structure or array." - if (type.isStruct()) { - int size = 0; - for (int member = 0; member < (int)type.getStruct()->size(); ++member) { - TType memberType(type, member); - size += computeTypeUniformLocationSize(memberType); - } - return size; - } - - return 1; -} - -#ifndef GLSLANG_WEB - -// Accumulate xfb buffer ranges and check for collisions as the accumulation is done. -// -// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. -// -int TIntermediate::addXfbBufferOffset(const TType& type) -{ - const TQualifier& qualifier = type.getQualifier(); - - assert(qualifier.hasXfbOffset() && qualifier.hasXfbBuffer()); - TXfbBuffer& buffer = xfbBuffers[qualifier.layoutXfbBuffer]; - - // compute the range - unsigned int size = computeTypeXfbSize(type, buffer.contains64BitType, buffer.contains32BitType, buffer.contains16BitType); - buffer.implicitStride = std::max(buffer.implicitStride, qualifier.layoutXfbOffset + size); - TRange range(qualifier.layoutXfbOffset, qualifier.layoutXfbOffset + size - 1); - - // check for collisions - for (size_t r = 0; r < buffer.ranges.size(); ++r) { - if (range.overlap(buffer.ranges[r])) { - // there is a collision; pick an example to return - return std::max(range.start, buffer.ranges[r].start); - } - } - - buffer.ranges.push_back(range); - - return -1; // no collision -} - -// Recursively figure out how many bytes of xfb buffer are used by the given type. -// Return the size of type, in bytes. -// Sets contains64BitType to true if the type contains a 64-bit data type. -// Sets contains32BitType to true if the type contains a 32-bit data type. -// Sets contains16BitType to true if the type contains a 16-bit data type. -// N.B. Caller must set contains64BitType, contains32BitType, and contains16BitType to false before calling. -unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const -{ - // "...if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8, - // and the space taken in the buffer will be a multiple of 8. - // ...within the qualified entity, subsequent components are each - // assigned, in order, to the next available offset aligned to a multiple of - // that component's size. Aggregate types are flattened down to the component - // level to get this sequence of components." - - if (type.isArray()) { - // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness - assert(type.isSizedArray()); - TType elementType(type, 0); - return type.getOuterArraySize() * computeTypeXfbSize(elementType, contains64BitType, contains16BitType, contains16BitType); - } - - if (type.isStruct()) { - unsigned int size = 0; - bool structContains64BitType = false; - bool structContains32BitType = false; - bool structContains16BitType = false; - for (int member = 0; member < (int)type.getStruct()->size(); ++member) { - TType memberType(type, member); - // "... if applied to - // an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8, - // and the space taken in the buffer will be a multiple of 8." - bool memberContains64BitType = false; - bool memberContains32BitType = false; - bool memberContains16BitType = false; - int memberSize = computeTypeXfbSize(memberType, memberContains64BitType, memberContains32BitType, memberContains16BitType); - if (memberContains64BitType) { - structContains64BitType = true; - RoundToPow2(size, 8); - } else if (memberContains32BitType) { - structContains32BitType = true; - RoundToPow2(size, 4); - } else if (memberContains16BitType) { - structContains16BitType = true; - RoundToPow2(size, 2); - } - size += memberSize; - } - - if (structContains64BitType) { - contains64BitType = true; - RoundToPow2(size, 8); - } else if (structContains32BitType) { - contains32BitType = true; - RoundToPow2(size, 4); - } else if (structContains16BitType) { - contains16BitType = true; - RoundToPow2(size, 2); - } - return size; - } - - int numComponents; - if (type.isScalar()) - numComponents = 1; - else if (type.isVector()) - numComponents = type.getVectorSize(); - else if (type.isMatrix()) - numComponents = type.getMatrixCols() * type.getMatrixRows(); - else { - assert(0); - numComponents = 1; - } - - if (type.getBasicType() == EbtDouble || type.getBasicType() == EbtInt64 || type.getBasicType() == EbtUint64) { - contains64BitType = true; - return 8 * numComponents; - } else if (type.getBasicType() == EbtFloat16 || type.getBasicType() == EbtInt16 || type.getBasicType() == EbtUint16) { - contains16BitType = true; - return 2 * numComponents; - } else if (type.getBasicType() == EbtInt8 || type.getBasicType() == EbtUint8) - return numComponents; - else { - contains32BitType = true; - return 4 * numComponents; - } -} - -#endif - -const int baseAlignmentVec4Std140 = 16; - -// Return the size and alignment of a component of the given type. -// The size is returned in the 'size' parameter -// Return value is the alignment.. -int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size) -{ -#ifdef GLSLANG_WEB - size = 4; return 4; -#endif - - switch (type.getBasicType()) { - case EbtInt64: - case EbtUint64: - case EbtDouble: size = 8; return 8; - case EbtFloat16: size = 2; return 2; - case EbtInt8: - case EbtUint8: size = 1; return 1; - case EbtInt16: - case EbtUint16: size = 2; return 2; - case EbtReference: size = 8; return 8; - default: size = 4; return 4; - } -} - -// Implement base-alignment and size rules from section 7.6.2.2 Standard Uniform Block Layout -// Operates recursively. -// -// If std140 is true, it does the rounding up to vec4 size required by std140, -// otherwise it does not, yielding std430 rules. -// -// The size is returned in the 'size' parameter -// -// The stride is only non-0 for arrays or matrices, and is the stride of the -// top-level object nested within the type. E.g., for an array of matrices, -// it is the distances needed between matrices, despite the rules saying the -// stride comes from the flattening down to vectors. -// -// Return value is the alignment of the type. -int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor) -{ - int alignment; - - bool std140 = layoutPacking == glslang::ElpStd140; - // When using the std140 storage layout, structures will be laid out in buffer - // storage with its members stored in monotonically increasing order based on their - // location in the declaration. A structure and each structure member have a base - // offset and a base alignment, from which an aligned offset is computed by rounding - // the base offset up to a multiple of the base alignment. The base offset of the first - // member of a structure is taken from the aligned offset of the structure itself. The - // base offset of all other structure members is derived by taking the offset of the - // last basic machine unit consumed by the previous member and adding one. Each - // structure member is stored in memory at its aligned offset. The members of a top- - // level uniform block are laid out in buffer storage by treating the uniform block as - // a structure with a base offset of zero. - // - // 1. If the member is a scalar consuming N basic machine units, the base alignment is N. - // - // 2. If the member is a two- or four-component vector with components consuming N basic - // machine units, the base alignment is 2N or 4N, respectively. - // - // 3. If the member is a three-component vector with components consuming N - // basic machine units, the base alignment is 4N. - // - // 4. If the member is an array of scalars or vectors, the base alignment and array - // stride are set to match the base alignment of a single array element, according - // to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The - // array may have padding at the end; the base offset of the member following - // the array is rounded up to the next multiple of the base alignment. - // - // 5. If the member is a column-major matrix with C columns and R rows, the - // matrix is stored identically to an array of C column vectors with R - // components each, according to rule (4). - // - // 6. If the member is an array of S column-major matrices with C columns and - // R rows, the matrix is stored identically to a row of S X C column vectors - // with R components each, according to rule (4). - // - // 7. If the member is a row-major matrix with C columns and R rows, the matrix - // is stored identically to an array of R row vectors with C components each, - // according to rule (4). - // - // 8. If the member is an array of S row-major matrices with C columns and R - // rows, the matrix is stored identically to a row of S X R row vectors with C - // components each, according to rule (4). - // - // 9. If the member is a structure, the base alignment of the structure is N , where - // N is the largest base alignment value of any of its members, and rounded - // up to the base alignment of a vec4. The individual members of this substructure - // are then assigned offsets by applying this set of rules recursively, - // where the base offset of the first member of the sub-structure is equal to the - // aligned offset of the structure. The structure may have padding at the end; - // the base offset of the member following the sub-structure is rounded up to - // the next multiple of the base alignment of the structure. - // - // 10. If the member is an array of S structures, the S elements of the array are laid - // out in order, according to rule (9). - // - // Assuming, for rule 10: The stride is the same as the size of an element. - - stride = 0; - int dummyStride; - - // rules 4, 6, 8, and 10 - if (type.isArray()) { - // TODO: perf: this might be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness - TType derefType(type, 0); - alignment = getBaseAlignment(derefType, size, dummyStride, layoutPacking, rowMajor); - if (std140) - alignment = std::max(baseAlignmentVec4Std140, alignment); - RoundToPow2(size, alignment); - stride = size; // uses full matrix size for stride of an array of matrices (not quite what rule 6/8, but what's expected) - // uses the assumption for rule 10 in the comment above - size = stride * type.getOuterArraySize(); - return alignment; - } - - // rule 9 - if (type.getBasicType() == EbtStruct) { - const TTypeList& memberList = *type.getStruct(); - - size = 0; - int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0; - for (size_t m = 0; m < memberList.size(); ++m) { - int memberSize; - // modify just the children's view of matrix layout, if there is one for this member - TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix; - int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, dummyStride, layoutPacking, - (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor); - maxAlignment = std::max(maxAlignment, memberAlignment); - RoundToPow2(size, memberAlignment); - size += memberSize; - } - - // The structure may have padding at the end; the base offset of - // the member following the sub-structure is rounded up to the next - // multiple of the base alignment of the structure. - RoundToPow2(size, maxAlignment); - - return maxAlignment; - } - - // rule 1 - if (type.isScalar()) - return getBaseAlignmentScalar(type, size); - - // rules 2 and 3 - if (type.isVector()) { - int scalarAlign = getBaseAlignmentScalar(type, size); - switch (type.getVectorSize()) { - case 1: // HLSL has this, GLSL does not - return scalarAlign; - case 2: - size *= 2; - return 2 * scalarAlign; - default: - size *= type.getVectorSize(); - return 4 * scalarAlign; - } - } - - // rules 5 and 7 - if (type.isMatrix()) { - // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows - TType derefType(type, 0, rowMajor); - - alignment = getBaseAlignment(derefType, size, dummyStride, layoutPacking, rowMajor); - if (std140) - alignment = std::max(baseAlignmentVec4Std140, alignment); - RoundToPow2(size, alignment); - stride = size; // use intra-matrix stride for stride of a just a matrix - if (rowMajor) - size = stride * type.getMatrixRows(); - else - size = stride * type.getMatrixCols(); - - return alignment; - } - - assert(0); // all cases should be covered above - size = baseAlignmentVec4Std140; - return baseAlignmentVec4Std140; -} - -// To aid the basic HLSL rule about crossing vec4 boundaries. -bool TIntermediate::improperStraddle(const TType& type, int size, int offset) -{ - if (! type.isVector() || type.isArray()) - return false; - - return size <= 16 ? offset / 16 != (offset + size - 1) / 16 - : offset % 16 != 0; -} - -int TIntermediate::getScalarAlignment(const TType& type, int& size, int& stride, bool rowMajor) -{ - int alignment; - - stride = 0; - int dummyStride; - - if (type.isArray()) { - TType derefType(type, 0); - alignment = getScalarAlignment(derefType, size, dummyStride, rowMajor); - - stride = size; - RoundToPow2(stride, alignment); - - size = stride * (type.getOuterArraySize() - 1) + size; - return alignment; - } - - if (type.getBasicType() == EbtStruct) { - const TTypeList& memberList = *type.getStruct(); - - size = 0; - int maxAlignment = 0; - for (size_t m = 0; m < memberList.size(); ++m) { - int memberSize; - // modify just the children's view of matrix layout, if there is one for this member - TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix; - int memberAlignment = getScalarAlignment(*memberList[m].type, memberSize, dummyStride, - (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor); - maxAlignment = std::max(maxAlignment, memberAlignment); - RoundToPow2(size, memberAlignment); - size += memberSize; - } - - return maxAlignment; - } - - if (type.isScalar()) - return getBaseAlignmentScalar(type, size); - - if (type.isVector()) { - int scalarAlign = getBaseAlignmentScalar(type, size); - - size *= type.getVectorSize(); - return scalarAlign; - } - - if (type.isMatrix()) { - TType derefType(type, 0, rowMajor); - - alignment = getScalarAlignment(derefType, size, dummyStride, rowMajor); - - stride = size; // use intra-matrix stride for stride of a just a matrix - if (rowMajor) - size = stride * type.getMatrixRows(); - else - size = stride * type.getMatrixCols(); - - return alignment; - } - - assert(0); // all cases should be covered above - size = 1; - return 1; -} - -int TIntermediate::getMemberAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor) -{ - if (layoutPacking == glslang::ElpScalar) { - return getScalarAlignment(type, size, stride, rowMajor); - } else { - return getBaseAlignment(type, size, stride, layoutPacking, rowMajor); - } -} - -// shared calculation by getOffset and getOffsets -void TIntermediate::updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize) -{ - int dummyStride; - - // modify just the children's view of matrix layout, if there is one for this member - TLayoutMatrix subMatrixLayout = memberType.getQualifier().layoutMatrix; - int memberAlignment = getMemberAlignment(memberType, memberSize, dummyStride, - parentType.getQualifier().layoutPacking, - subMatrixLayout != ElmNone - ? subMatrixLayout == ElmRowMajor - : parentType.getQualifier().layoutMatrix == ElmRowMajor); - RoundToPow2(offset, memberAlignment); -} - -// Lookup or calculate the offset of a block member, using the recursively -// defined block offset rules. -int TIntermediate::getOffset(const TType& type, int index) -{ - const TTypeList& memberList = *type.getStruct(); - - // Don't calculate offset if one is present, it could be user supplied - // and different than what would be calculated. That is, this is faster, - // but not just an optimization. - if (memberList[index].type->getQualifier().hasOffset()) - return memberList[index].type->getQualifier().layoutOffset; - - int memberSize = 0; - int offset = 0; - for (int m = 0; m <= index; ++m) { - updateOffset(type, *memberList[m].type, offset, memberSize); - - if (m < index) - offset += memberSize; - } - - return offset; -} - -// Calculate the block data size. -// Block arrayness is not taken into account, each element is backed by a separate buffer. -int TIntermediate::getBlockSize(const TType& blockType) -{ - const TTypeList& memberList = *blockType.getStruct(); - int lastIndex = (int)memberList.size() - 1; - int lastOffset = getOffset(blockType, lastIndex); - - int lastMemberSize; - int dummyStride; - getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, - blockType.getQualifier().layoutPacking, - blockType.getQualifier().layoutMatrix == ElmRowMajor); - - return lastOffset + lastMemberSize; -} - -int TIntermediate::computeBufferReferenceTypeSize(const TType& type) -{ - assert(type.isReference()); - int size = getBlockSize(*type.getReferentType()); - - int align = type.getBufferReferenceAlignment(); - - if (align) { - size = (size + align - 1) & ~(align-1); - } - - return size; -} - -} // end namespace glslang diff --git a/libraries/glslang/glslang/MachineIndependent/pch.cpp b/libraries/glslang/glslang/MachineIndependent/pch.cpp deleted file mode 100644 index b7a08654a54..00000000000 --- a/libraries/glslang/glslang/MachineIndependent/pch.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (C) 2018 The Khronos Group Inc. -// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. -// - -#include "pch.h" diff --git a/libraries/glslang/glslang/OSDependent/Unix/CMakeLists.txt b/libraries/glslang/glslang/OSDependent/Unix/CMakeLists.txt deleted file mode 100644 index 9994314fd5a..00000000000 --- a/libraries/glslang/glslang/OSDependent/Unix/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -add_library(OSDependent STATIC ossource.cpp ../osinclude.h) -set_property(TARGET OSDependent PROPERTY FOLDER glslang) -set_property(TARGET OSDependent PROPERTY POSITION_INDEPENDENT_CODE ON) - -# Link pthread -set(CMAKE_THREAD_PREFER_PTHREAD ON) -if(${CMAKE_VERSION} VERSION_LESS "3.1.0" OR CMAKE_CROSSCOMPILING) - # Needed as long as we support CMake 2.8 for Ubuntu 14.04, - # which does not support the recommended Threads::Threads target. - # https://cmake.org/cmake/help/v2.8.12/cmake.html#module:FindThreads - # Also needed when cross-compiling to work around - # https://gitlab.kitware.com/cmake/cmake/issues/16920 - find_package(Threads) - target_link_libraries(OSDependent ${CMAKE_THREAD_LIBS_INIT}) -else() - # This is the recommended way, so we use it for 3.1+. - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads) - target_link_libraries(OSDependent Threads::Threads) -endif() - -if(ENABLE_GLSLANG_INSTALL) - install(TARGETS OSDependent EXPORT OSDependentTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(EXPORT OSDependentTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake) -endif(ENABLE_GLSLANG_INSTALL) diff --git a/libraries/glslang/glslang/OSDependent/Web/CMakeLists.txt b/libraries/glslang/glslang/OSDependent/Web/CMakeLists.txt deleted file mode 100644 index e8238c35049..00000000000 --- a/libraries/glslang/glslang/OSDependent/Web/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -add_executable(glslang.js "glslang.js.cpp") -glslang_set_link_args(glslang.js) -target_link_libraries(glslang.js glslang SPIRV) -if(EMSCRIPTEN) - set_target_properties(glslang.js PROPERTIES - OUTPUT_NAME "glslang" - SUFFIX ".js") - em_link_pre_js(glslang.js "${CMAKE_CURRENT_SOURCE_DIR}/glslang.pre.js") - - target_link_options(glslang.js PRIVATE - "SHELL:--bind -s MODULARIZE=1") - if(ENABLE_EMSCRIPTEN_ENVIRONMENT_NODE) - target_link_options(glslang.js PRIVATE - "SHELL:-s ENVIRONMENT=node -s BINARYEN_ASYNC_COMPILATION=0") - else() - target_link_options(glslang.js PRIVATE - "SHELL:-s ENVIRONMENT=web,worker") - endif() - - if(NOT ENABLE_EMSCRIPTEN_ENVIRONMENT_NODE) - add_custom_command(TARGET glslang.js POST_BUILD - COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/glslang.after.js >> ${CMAKE_CURRENT_BINARY_DIR}/glslang.js) - endif() -endif(EMSCRIPTEN) diff --git a/libraries/glslang/glslang/OSDependent/Web/glslang.pre.js b/libraries/glslang/glslang/OSDependent/Web/glslang.pre.js deleted file mode 100644 index 7d3fd0234c3..00000000000 --- a/libraries/glslang/glslang/OSDependent/Web/glslang.pre.js +++ /dev/null @@ -1,45 +0,0 @@ -Module['compileGLSLZeroCopy'] = function(glsl, shader_stage, gen_debug) { - gen_debug = !!gen_debug; - - var shader_stage_int; - if (shader_stage === 'vertex') { - shader_stage_int = 0; - } else if (shader_stage === 'fragment') { - shader_stage_int = 4; - } else if (shader_stage === 'compute') { - shader_stage_int = 5; - } else { - throw new Error("shader_stage must be 'vertex', 'fragment', or 'compute'"); - } - - var p_output = Module['_malloc'](4); - var p_output_len = Module['_malloc'](4); - var id = ccall('convert_glsl_to_spirv', - 'number', - ['string', 'number', 'boolean', 'number', 'number'], - [glsl, shader_stage_int, gen_debug, p_output, p_output_len]); - var output = getValue(p_output, 'i32'); - var output_len = getValue(p_output_len, 'i32'); - Module['_free'](p_output); - Module['_free'](p_output_len); - - if (id === 0) { - throw new Error('GLSL compilation failed'); - } - - var ret = {}; - var outputIndexU32 = output / 4; - ret['data'] = Module['HEAPU32'].subarray(outputIndexU32, outputIndexU32 + output_len); - ret['free'] = function() { - Module['_destroy_output_buffer'](id); - }; - - return ret; -}; - -Module['compileGLSL'] = function(glsl, shader_stage, gen_debug) { - var compiled = Module['compileGLSLZeroCopy'](glsl, shader_stage, gen_debug); - var ret = compiled['data'].slice() - compiled['free'](); - return ret; -}; diff --git a/libraries/glslang/glslang/OSDependent/Windows/CMakeLists.txt b/libraries/glslang/glslang/OSDependent/Windows/CMakeLists.txt deleted file mode 100644 index c050ef61de7..00000000000 --- a/libraries/glslang/glslang/OSDependent/Windows/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -set(SOURCES ossource.cpp ../osinclude.h) - -add_library(OSDependent STATIC ${SOURCES}) -set_property(TARGET OSDependent PROPERTY FOLDER glslang) -set_property(TARGET OSDependent PROPERTY POSITION_INDEPENDENT_CODE ON) - -# MinGW GCC complains about function pointer casts to void*. -# Turn that off with -fpermissive. -if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") - target_compile_options(OSDependent PRIVATE -fpermissive) -endif() - -if(WIN32) - source_group("Source" FILES ${SOURCES}) -endif(WIN32) - -if(ENABLE_GLSLANG_INSTALL) - install(TARGETS OSDependent EXPORT OSDependentTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(EXPORT OSDependentTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake) -endif(ENABLE_GLSLANG_INSTALL) diff --git a/libraries/glslang/glslang/Public/ShaderLang.h b/libraries/glslang/glslang/Public/ShaderLang.h deleted file mode 100644 index 4cc6c2f4889..00000000000 --- a/libraries/glslang/glslang/Public/ShaderLang.h +++ /dev/null @@ -1,902 +0,0 @@ -// -// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. -// Copyright (C) 2013-2016 LunarG, Inc. -// Copyright (C) 2015-2018 Google, Inc. -// -// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. -// -#ifndef _COMPILER_INTERFACE_INCLUDED_ -#define _COMPILER_INTERFACE_INCLUDED_ - -#include "../Include/ResourceLimits.h" -#include "../MachineIndependent/Versions.h" - -#include -#include - -#ifdef _WIN32 -#define C_DECL __cdecl -//#ifdef SH_EXPORTING -// #define SH_IMPORT_EXPORT __declspec(dllexport) -//#else -// #define SH_IMPORT_EXPORT __declspec(dllimport) -//#endif -#define SH_IMPORT_EXPORT -#else -#define SH_IMPORT_EXPORT -#define C_DECL -#endif - -// -// This is the platform independent interface between an OGL driver -// and the shading language compiler/linker. -// - -#ifdef __cplusplus - extern "C" { -#endif - -// This should always increase, as some paths to do not consume -// a more major number. -// It should increment by one when new functionality is added. -#define GLSLANG_MINOR_VERSION 13 - -// -// Call before doing any other compiler/linker operations. -// -// (Call once per process, not once per thread.) -// -SH_IMPORT_EXPORT int ShInitialize(); - -// -// Call this at process shutdown to clean up memory. -// -SH_IMPORT_EXPORT int ShFinalize(); - -// -// Types of languages the compiler can consume. -// -typedef enum { - EShLangVertex, - EShLangTessControl, - EShLangTessEvaluation, - EShLangGeometry, - EShLangFragment, - EShLangCompute, - EShLangRayGenNV, - EShLangIntersectNV, - EShLangAnyHitNV, - EShLangClosestHitNV, - EShLangMissNV, - EShLangCallableNV, - EShLangTaskNV, - EShLangMeshNV, - EShLangCount, -} EShLanguage; // would be better as stage, but this is ancient now - -typedef enum { - EShLangVertexMask = (1 << EShLangVertex), - EShLangTessControlMask = (1 << EShLangTessControl), - EShLangTessEvaluationMask = (1 << EShLangTessEvaluation), - EShLangGeometryMask = (1 << EShLangGeometry), - EShLangFragmentMask = (1 << EShLangFragment), - EShLangComputeMask = (1 << EShLangCompute), - EShLangRayGenNVMask = (1 << EShLangRayGenNV), - EShLangIntersectNVMask = (1 << EShLangIntersectNV), - EShLangAnyHitNVMask = (1 << EShLangAnyHitNV), - EShLangClosestHitNVMask = (1 << EShLangClosestHitNV), - EShLangMissNVMask = (1 << EShLangMissNV), - EShLangCallableNVMask = (1 << EShLangCallableNV), - EShLangTaskNVMask = (1 << EShLangTaskNV), - EShLangMeshNVMask = (1 << EShLangMeshNV), -} EShLanguageMask; - -namespace glslang { - -class TType; - -typedef enum { - EShSourceNone, - EShSourceGlsl, // GLSL, includes ESSL (OpenGL ES GLSL) - EShSourceHlsl, // HLSL -} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead - -typedef enum { - EShClientNone, // use when there is no client, e.g. for validation - EShClientVulkan, - EShClientOpenGL, -} EShClient; - -typedef enum { - EShTargetNone, - EShTargetSpv, // SPIR-V (preferred spelling) - EshTargetSpv = EShTargetSpv, // legacy spelling -} EShTargetLanguage; - -typedef enum { - EShTargetVulkan_1_0 = (1 << 22), // Vulkan 1.0 - EShTargetVulkan_1_1 = (1 << 22) | (1 << 12), // Vulkan 1.1 - EShTargetOpenGL_450 = 450, // OpenGL -} EShTargetClientVersion; - -typedef EShTargetClientVersion EshTargetClientVersion; - -typedef enum { - EShTargetSpv_1_0 = (1 << 16), // SPIR-V 1.0 - EShTargetSpv_1_1 = (1 << 16) | (1 << 8), // SPIR-V 1.1 - EShTargetSpv_1_2 = (1 << 16) | (2 << 8), // SPIR-V 1.2 - EShTargetSpv_1_3 = (1 << 16) | (3 << 8), // SPIR-V 1.3 - EShTargetSpv_1_4 = (1 << 16) | (4 << 8), // SPIR-V 1.4 - EShTargetSpv_1_5 = (1 << 16) | (5 << 8), // SPIR-V 1.5 -} EShTargetLanguageVersion; - -struct TInputLanguage { - EShSource languageFamily; // redundant information with other input, this one overrides when not EShSourceNone - EShLanguage stage; // redundant information with other input, this one overrides when not EShSourceNone - EShClient dialect; - int dialectVersion; // version of client's language definition, not the client (when not EShClientNone) -}; - -struct TClient { - EShClient client; - EShTargetClientVersion version; // version of client itself (not the client's input dialect) -}; - -struct TTarget { - EShTargetLanguage language; - EShTargetLanguageVersion version; // version to target, if SPIR-V, defined by "word 1" of the SPIR-V header - bool hlslFunctionality1; // can target hlsl_functionality1 extension(s) -}; - -// All source/client/target versions and settings. -// Can override previous methods of setting, when items are set here. -// Expected to grow, as more are added, rather than growing parameter lists. -struct TEnvironment { - TInputLanguage input; // definition of the input language - TClient client; // what client is the overall compilation being done for? - TTarget target; // what to generate -}; - -const char* StageName(EShLanguage); - -} // end namespace glslang - -// -// Types of output the linker will create. -// -typedef enum { - EShExVertexFragment, - EShExFragment -} EShExecutable; - -// -// Optimization level for the compiler. -// -typedef enum { - EShOptNoGeneration, - EShOptNone, - EShOptSimple, // Optimizations that can be done quickly - EShOptFull, // Optimizations that will take more time -} EShOptimizationLevel; - -// -// Texture and Sampler transformation mode. -// -typedef enum { - EShTexSampTransKeep, // keep textures and samplers as is (default) - EShTexSampTransUpgradeTextureRemoveSampler, // change texture w/o embeded sampler into sampled texture and throw away all samplers -} EShTextureSamplerTransformMode; - -// -// Message choices for what errors and warnings are given. -// -enum EShMessages { - EShMsgDefault = 0, // default is to give all required errors and extra warnings - EShMsgRelaxedErrors = (1 << 0), // be liberal in accepting input - EShMsgSuppressWarnings = (1 << 1), // suppress all warnings, except those required by the specification - EShMsgAST = (1 << 2), // print the AST intermediate representation - EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation - EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V - EShMsgOnlyPreprocessor = (1 << 5), // only print out errors produced by the preprocessor - EShMsgReadHlsl = (1 << 6), // use HLSL parsing rules and semantics - EShMsgCascadingErrors = (1 << 7), // get cascading errors; risks error-recovery issues, instead of an early exit - EShMsgKeepUncalled = (1 << 8), // for testing, don't eliminate uncalled functions - EShMsgHlslOffsets = (1 << 9), // allow block offsets to follow HLSL rules instead of GLSL rules - EShMsgDebugInfo = (1 << 10), // save debug information - EShMsgHlslEnable16BitTypes = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL - EShMsgHlslLegalization = (1 << 12), // enable HLSL Legalization messages - EShMsgHlslDX9Compatible = (1 << 13), // enable HLSL DX9 compatible mode (right now only for samplers) - EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table -}; - -// -// Options for building reflection -// -typedef enum { - EShReflectionDefault = 0, // default is original behaviour before options were added - EShReflectionStrictArraySuffix = (1 << 0), // reflection will follow stricter rules for array-of-structs suffixes - EShReflectionBasicArraySuffix = (1 << 1), // arrays of basic types will be appended with [0] as in GL reflection - EShReflectionIntermediateIO = (1 << 2), // reflect inputs and outputs to program, even with no vertex shader - EShReflectionSeparateBuffers = (1 << 3), // buffer variables and buffer blocks are reflected separately - EShReflectionAllBlockVariables = (1 << 4), // reflect all variables in blocks, even if they are inactive - EShReflectionUnwrapIOBlocks = (1 << 5), // unwrap input/output blocks the same as with uniform blocks -} EShReflectionOptions; - -// -// Build a table for bindings. This can be used for locating -// attributes, uniforms, globals, etc., as needed. -// -typedef struct { - const char* name; - int binding; -} ShBinding; - -typedef struct { - int numBindings; - ShBinding* bindings; // array of bindings -} ShBindingTable; - -// -// ShHandle held by but opaque to the driver. It is allocated, -// managed, and de-allocated by the compiler/linker. It's contents -// are defined by and used by the compiler and linker. For example, -// symbol table information and object code passed from the compiler -// to the linker can be stored where ShHandle points. -// -// If handle creation fails, 0 will be returned. -// -typedef void* ShHandle; - -// -// Driver calls these to create and destroy compiler/linker -// objects. -// -SH_IMPORT_EXPORT ShHandle ShConstructCompiler(const EShLanguage, int debugOptions); // one per shader -SH_IMPORT_EXPORT ShHandle ShConstructLinker(const EShExecutable, int debugOptions); // one per shader pair -SH_IMPORT_EXPORT ShHandle ShConstructUniformMap(); // one per uniform namespace (currently entire program object) -SH_IMPORT_EXPORT void ShDestruct(ShHandle); - -// -// The return value of ShCompile is boolean, non-zero indicating -// success. -// -// The info-log should be written by ShCompile into -// ShHandle, so it can answer future queries. -// -SH_IMPORT_EXPORT int ShCompile( - const ShHandle, - const char* const shaderStrings[], - const int numStrings, - const int* lengths, - const EShOptimizationLevel, - const TBuiltInResource *resources, - int debugOptions, - int defaultVersion = 110, // use 100 for ES environment, overridden by #version in shader - bool forwardCompatible = false, // give errors for use of deprecated features - EShMessages messages = EShMsgDefault // warnings and errors - ); - -SH_IMPORT_EXPORT int ShLinkExt( - const ShHandle, // linker object - const ShHandle h[], // compiler objects to link together - const int numHandles); - -// -// ShSetEncrpytionMethod is a place-holder for specifying -// how source code is encrypted. -// -SH_IMPORT_EXPORT void ShSetEncryptionMethod(ShHandle); - -// -// All the following return 0 if the information is not -// available in the object passed down, or the object is bad. -// -SH_IMPORT_EXPORT const char* ShGetInfoLog(const ShHandle); -SH_IMPORT_EXPORT const void* ShGetExecutable(const ShHandle); -SH_IMPORT_EXPORT int ShSetVirtualAttributeBindings(const ShHandle, const ShBindingTable*); // to detect user aliasing -SH_IMPORT_EXPORT int ShSetFixedAttributeBindings(const ShHandle, const ShBindingTable*); // to force any physical mappings -// -// Tell the linker to never assign a vertex attribute to this list of physical attributes -// -SH_IMPORT_EXPORT int ShExcludeAttributes(const ShHandle, int *attributes, int count); - -// -// Returns the location ID of the named uniform. -// Returns -1 if error. -// -SH_IMPORT_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char* name); - -#ifdef __cplusplus - } // end extern "C" -#endif - -//////////////////////////////////////////////////////////////////////////////////////////// -// -// Deferred-Lowering C++ Interface -// ----------------------------------- -// -// Below is a new alternate C++ interface, which deprecates the above -// opaque handle-based interface. -// -// The below is further designed to handle multiple compilation units per stage, where -// the intermediate results, including the parse tree, are preserved until link time, -// rather than the above interface which is designed to have each compilation unit -// lowered at compile time. In the above model, linking occurs on the lowered results, -// whereas in this model intra-stage linking can occur at the parse tree -// (treeRoot in TIntermediate) level, and then a full stage can be lowered. -// - -#include -#include -#include - -class TCompiler; -class TInfoSink; - -namespace glslang { - -const char* GetEsslVersionString(); -const char* GetGlslVersionString(); -int GetKhronosToolId(); - -class TIntermediate; -class TProgram; -class TPoolAllocator; - -// Call this exactly once per process before using anything else -bool InitializeProcess(); - -// Call once per process to tear down everything -void FinalizeProcess(); - -// Resource type for IO resolver -enum TResourceType { - EResSampler, - EResTexture, - EResImage, - EResUbo, - EResSsbo, - EResUav, - EResCount -}; - -// Make one TShader per shader that you will link into a program. Then -// - provide the shader through setStrings() or setStringsWithLengths() -// - optionally call setEnv*(), see below for more detail -// - optionally use setPreamble() to set a special shader string that will be -// processed before all others but won't affect the validity of #version -// - call parse(): source language and target environment must be selected -// either by correct setting of EShMessages sent to parse(), or by -// explicitly calling setEnv*() -// - query the info logs -// -// N.B.: Does not yet support having the same TShader instance being linked into -// multiple programs. -// -// N.B.: Destruct a linked program *before* destructing the shaders linked into it. -// -class TShader { -public: - explicit TShader(EShLanguage); - virtual ~TShader(); - void setStrings(const char* const* s, int n); - void setStringsWithLengths(const char* const* s, const int* l, int n); - void setStringsWithLengthsAndNames( - const char* const* s, const int* l, const char* const* names, int n); - void setPreamble(const char* s) { preamble = s; } - void setEntryPoint(const char* entryPoint); - void setSourceEntryPoint(const char* sourceEntryPointName); - void addProcesses(const std::vector&); - - // IO resolver binding data: see comments in ShaderLang.cpp - void setShiftBinding(TResourceType res, unsigned int base); - void setShiftSamplerBinding(unsigned int base); // DEPRECATED: use setShiftBinding - void setShiftTextureBinding(unsigned int base); // DEPRECATED: use setShiftBinding - void setShiftImageBinding(unsigned int base); // DEPRECATED: use setShiftBinding - void setShiftUboBinding(unsigned int base); // DEPRECATED: use setShiftBinding - void setShiftUavBinding(unsigned int base); // DEPRECATED: use setShiftBinding - void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding - void setShiftSsboBinding(unsigned int base); // DEPRECATED: use setShiftBinding - void setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set); - void setResourceSetBinding(const std::vector& base); - void setAutoMapBindings(bool map); - void setAutoMapLocations(bool map); - void addUniformLocationOverride(const char* name, int loc); - void setUniformLocationBase(int base); - void setInvertY(bool invert); -#ifdef ENABLE_HLSL - void setHlslIoMapping(bool hlslIoMap); - void setFlattenUniformArrays(bool flatten); -#endif - void setNoStorageFormat(bool useUnknownFormat); - void setNanMinMaxClamp(bool nanMinMaxClamp); - void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode); - - // For setting up the environment (cleared to nothingness in the constructor). - // These must be called so that parsing is done for the right source language and - // target environment, either indirectly through TranslateEnvironment() based on - // EShMessages et. al., or directly by the user. - // - // setEnvInput: The input source language and stage. If generating code for a - // specific client, the input client semantics to use and the - // version of the that client's input semantics to use, otherwise - // use EShClientNone and version of 0, e.g. for validation mode. - // Note 'version' does not describe the target environment, - // just the version of the source dialect to compile under. - // - // See the definitions of TEnvironment, EShSource, EShLanguage, - // and EShClient for choices and more detail. - // - // setEnvClient: The client that will be hosting the execution, and it's version. - // Note 'version' is not the version of the languages involved, but - // the version of the client environment. - // Use EShClientNone and version of 0 if there is no client, e.g. - // for validation mode. - // - // See EShTargetClientVersion for choices. - // - // setEnvTarget: The language to translate to when generating code, and that - // language's version. - // Use EShTargetNone and version of 0 if there is no client, e.g. - // for validation mode. - // - void setEnvInput(EShSource lang, EShLanguage envStage, EShClient client, int version) - { - environment.input.languageFamily = lang; - environment.input.stage = envStage; - environment.input.dialect = client; - environment.input.dialectVersion = version; - } - void setEnvClient(EShClient client, EShTargetClientVersion version) - { - environment.client.client = client; - environment.client.version = version; - } - void setEnvTarget(EShTargetLanguage lang, EShTargetLanguageVersion version) - { - environment.target.language = lang; - environment.target.version = version; - } - - void getStrings(const char* const* &s, int& n) { s = strings; n = numStrings; } - -#ifdef ENABLE_HLSL - void setEnvTargetHlslFunctionality1() { environment.target.hlslFunctionality1 = true; } - bool getEnvTargetHlslFunctionality1() const { return environment.target.hlslFunctionality1; } -#else - bool getEnvTargetHlslFunctionality1() const { return false; } -#endif - - // Interface to #include handlers. - // - // To support #include, a client of Glslang does the following: - // 1. Call setStringsWithNames to set the source strings and associated - // names. For example, the names could be the names of the files - // containing the shader sources. - // 2. Call parse with an Includer. - // - // When the Glslang parser encounters an #include directive, it calls - // the Includer's include method with the requested include name - // together with the current string name. The returned IncludeResult - // contains the fully resolved name of the included source, together - // with the source text that should replace the #include directive - // in the source stream. After parsing that source, Glslang will - // release the IncludeResult object. - class Includer { - public: - // An IncludeResult contains the resolved name and content of a source - // inclusion. - struct IncludeResult { - IncludeResult(const std::string& headerName, const char* const headerData, const size_t headerLength, void* userData) : - headerName(headerName), headerData(headerData), headerLength(headerLength), userData(userData) { } - // For a successful inclusion, the fully resolved name of the requested - // include. For example, in a file system-based includer, full resolution - // should convert a relative path name into an absolute path name. - // For a failed inclusion, this is an empty string. - const std::string headerName; - // The content and byte length of the requested inclusion. The - // Includer producing this IncludeResult retains ownership of the - // storage. - // For a failed inclusion, the header - // field points to a string containing error details. - const char* const headerData; - const size_t headerLength; - // Include resolver's context. - void* userData; - protected: - IncludeResult& operator=(const IncludeResult&); - IncludeResult(); - }; - - // For both include methods below: - // - // Resolves an inclusion request by name, current source name, - // and include depth. - // On success, returns an IncludeResult containing the resolved name - // and content of the include. - // On failure, returns a nullptr, or an IncludeResult - // with an empty string for the headerName and error details in the - // header field. - // The Includer retains ownership of the contents - // of the returned IncludeResult value, and those contents must - // remain valid until the releaseInclude method is called on that - // IncludeResult object. - // - // Note "local" vs. "system" is not an "either/or": "local" is an - // extra thing to do over "system". Both might get called, as per - // the C++ specification. - - // For the "system" or <>-style includes; search the "system" paths. - virtual IncludeResult* includeSystem(const char* /*headerName*/, - const char* /*includerName*/, - size_t /*inclusionDepth*/) { return nullptr; } - - // For the "local"-only aspect of a "" include. Should not search in the - // "system" paths, because on returning a failure, the parser will - // call includeSystem() to look in the "system" locations. - virtual IncludeResult* includeLocal(const char* /*headerName*/, - const char* /*includerName*/, - size_t /*inclusionDepth*/) { return nullptr; } - - // Signals that the parser will no longer use the contents of the - // specified IncludeResult. - virtual void releaseInclude(IncludeResult*) = 0; - virtual ~Includer() {} - }; - - // Fail all Includer searches - class ForbidIncluder : public Includer { - public: - virtual void releaseInclude(IncludeResult*) override { } - }; - - bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, - bool forwardCompatible, EShMessages, Includer&); - - bool parse(const TBuiltInResource* res, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, - bool forwardCompatible, EShMessages messages) - { - TShader::ForbidIncluder includer; - return parse(res, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, includer); - } - - // Equivalent to parse() without a default profile and without forcing defaults. - bool parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages) - { - return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages); - } - - bool parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages, - Includer& includer) - { - return parse(builtInResources, defaultVersion, ENoProfile, false, forwardCompatible, messages, includer); - } - - // NOTE: Doing just preprocessing to obtain a correct preprocessed shader string - // is not an officially supported or fully working path. - bool preprocess(const TBuiltInResource* builtInResources, - int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, - bool forwardCompatible, EShMessages message, std::string* outputString, - Includer& includer); - - const char* getInfoLog(); - const char* getInfoDebugLog(); - EShLanguage getStage() const { return stage; } - TIntermediate* getIntermediate() const { return intermediate; } - -protected: - TPoolAllocator* pool; - EShLanguage stage; - TCompiler* compiler; - TIntermediate* intermediate; - TInfoSink* infoSink; - // strings and lengths follow the standard for glShaderSource: - // strings is an array of numStrings pointers to string data. - // lengths can be null, but if not it is an array of numStrings - // integers containing the length of the associated strings. - // if lengths is null or lengths[n] < 0 the associated strings[n] is - // assumed to be null-terminated. - // stringNames is the optional names for all the strings. If stringNames - // is null, then none of the strings has name. If a certain element in - // stringNames is null, then the corresponding string does not have name. - const char* const* strings; - const int* lengths; - const char* const* stringNames; - const char* preamble; - int numStrings; - - // a function in the source string can be renamed FROM this TO the name given in setEntryPoint. - std::string sourceEntryPointName; - - TEnvironment environment; - - friend class TProgram; - -private: - TShader& operator=(TShader&); -}; - -#ifndef GLSLANG_WEB - -// -// A reflection database and its interface, consistent with the OpenGL API reflection queries. -// - -// Data needed for just a single object at the granularity exchanged by the reflection API -class TObjectReflection { -public: - TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex); - - const TType* getType() const { return type; } - int getBinding() const; - void dump() const; - static TObjectReflection badReflection() { return TObjectReflection(); } - - std::string name; - int offset; - int glDefineType; - int size; // data size in bytes for a block, array size for a (non-block) object that's an array - int index; - int counterIndex; - int numMembers; - int arrayStride; // stride of an array variable - int topLevelArrayStride; // stride of the top-level variable in a storage buffer member - EShLanguageMask stages; - -protected: - TObjectReflection() - : offset(-1), glDefineType(-1), size(-1), index(-1), counterIndex(-1), numMembers(-1), arrayStride(0), - topLevelArrayStride(0), stages(EShLanguageMask(0)), type(nullptr) - { - } - - const TType* type; -}; - -class TReflection; -class TIoMapper; -struct TVarEntryInfo; - -// Allows to customize the binding layout after linking. -// All used uniform variables will invoke at least validateBinding. -// If validateBinding returned true then the other resolveBinding, -// resolveSet, and resolveLocation are invoked to resolve the binding -// and descriptor set index respectively. -// -// Invocations happen in a particular order: -// 1) all shader inputs -// 2) all shader outputs -// 3) all uniforms with binding and set already defined -// 4) all uniforms with binding but no set defined -// 5) all uniforms with set but no binding defined -// 6) all uniforms with no binding and no set defined -// -// mapIO will use this resolver in two phases. The first -// phase is a notification phase, calling the corresponging -// notifiy callbacks, this phase ends with a call to endNotifications. -// Phase two starts directly after the call to endNotifications -// and calls all other callbacks to validate and to get the -// bindings, sets, locations, component and color indices. -// -// NOTE: that still limit checks are applied to bindings and sets -// and may result in an error. -class TIoMapResolver -{ -public: - virtual ~TIoMapResolver() {} - - // Should return true if the resulting/current binding would be okay. - // Basic idea is to do aliasing binding checks with this. - virtual bool validateBinding(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Should return a value >= 0 if the current binding should be overridden. - // Return -1 if the current binding (including no binding) should be kept. - virtual int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Should return a value >= 0 if the current set should be overridden. - // Return -1 if the current set (including no set) should be kept. - virtual int resolveSet(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Should return a value >= 0 if the current location should be overridden. - // Return -1 if the current location (including no location) should be kept. - virtual int resolveUniformLocation(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Should return true if the resulting/current setup would be okay. - // Basic idea is to do aliasing checks and reject invalid semantic names. - virtual bool validateInOut(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Should return a value >= 0 if the current location should be overridden. - // Return -1 if the current location (including no location) should be kept. - virtual int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Should return a value >= 0 if the current component index should be overridden. - // Return -1 if the current component index (including no index) should be kept. - virtual int resolveInOutComponent(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Should return a value >= 0 if the current color index should be overridden. - // Return -1 if the current color index (including no index) should be kept. - virtual int resolveInOutIndex(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Notification of a uniform variable - virtual void notifyBinding(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Notification of a in or out variable - virtual void notifyInOut(EShLanguage stage, TVarEntryInfo& ent) = 0; - // Called by mapIO when it starts its notify pass for the given stage - virtual void beginNotifications(EShLanguage stage) = 0; - // Called by mapIO when it has finished the notify pass - virtual void endNotifications(EShLanguage stage) = 0; - // Called by mipIO when it starts its resolve pass for the given stage - virtual void beginResolve(EShLanguage stage) = 0; - // Called by mapIO when it has finished the resolve pass - virtual void endResolve(EShLanguage stage) = 0; - // Called by mapIO when it starts its symbol collect for teh given stage - virtual void beginCollect(EShLanguage stage) = 0; - // Called by mapIO when it has finished the symbol collect - virtual void endCollect(EShLanguage stage) = 0; - // Called by TSlotCollector to resolve storage locations or bindings - virtual void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) = 0; - // Called by TSlotCollector to resolve resource locations or bindings - virtual void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) = 0; - // Called by mapIO.addStage to set shader stage mask to mark a stage be added to this pipeline - virtual void addStage(EShLanguage stage) = 0; -}; - -#endif // GLSLANG_WEB - -// Make one TProgram per set of shaders that will get linked together. Add all -// the shaders that are to be linked together. After calling shader.parse() -// for all shaders, call link(). -// -// N.B.: Destruct a linked program *before* destructing the shaders linked into it. -// -class TProgram { -public: - TProgram(); - virtual ~TProgram(); - void addShader(TShader* shader) { stages[shader->stage].push_back(shader); } - std::list& getShaders(EShLanguage stage) { return stages[stage]; } - // Link Validation interface - bool link(EShMessages); - const char* getInfoLog(); - const char* getInfoDebugLog(); - - TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; } - -#ifndef GLSLANG_WEB - - // Reflection Interface - - // call first, to do liveness analysis, index mapping, etc.; returns false on failure - bool buildReflection(int opts = EShReflectionDefault); - unsigned getLocalSize(int dim) const; // return dim'th local size - int getReflectionIndex(const char *name) const; - int getReflectionPipeIOIndex(const char* name, const bool inOrOut) const; - int getNumUniformVariables() const; - const TObjectReflection& getUniform(int index) const; - int getNumUniformBlocks() const; - const TObjectReflection& getUniformBlock(int index) const; - int getNumPipeInputs() const; - const TObjectReflection& getPipeInput(int index) const; - int getNumPipeOutputs() const; - const TObjectReflection& getPipeOutput(int index) const; - int getNumBufferVariables() const; - const TObjectReflection& getBufferVariable(int index) const; - int getNumBufferBlocks() const; - const TObjectReflection& getBufferBlock(int index) const; - int getNumAtomicCounters() const; - const TObjectReflection& getAtomicCounter(int index) const; - - // Legacy Reflection Interface - expressed in terms of above interface - - // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS) - int getNumLiveUniformVariables() const { return getNumUniformVariables(); } - - // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS) - int getNumLiveUniformBlocks() const { return getNumUniformBlocks(); } - - // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES) - int getNumLiveAttributes() const { return getNumPipeInputs(); } - - // can be used for glGetUniformIndices() - int getUniformIndex(const char *name) const { return getReflectionIndex(name); } - - int getPipeIOIndex(const char *name, const bool inOrOut) const - { return getReflectionPipeIOIndex(name, inOrOut); } - - // can be used for "name" part of glGetActiveUniform() - const char *getUniformName(int index) const { return getUniform(index).name.c_str(); } - - // returns the binding number - int getUniformBinding(int index) const { return getUniform(index).getBinding(); } - - // returns Shaders Stages where a Uniform is present - EShLanguageMask getUniformStages(int index) const { return getUniform(index).stages; } - - // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX) - int getUniformBlockIndex(int index) const { return getUniform(index).index; } - - // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE) - int getUniformType(int index) const { return getUniform(index).glDefineType; } - - // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET) - int getUniformBufferOffset(int index) const { return getUniform(index).offset; } - - // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE) - int getUniformArraySize(int index) const { return getUniform(index).size; } - - // returns a TType* - const TType *getUniformTType(int index) const { return getUniform(index).getType(); } - - // can be used for glGetActiveUniformBlockName() - const char *getUniformBlockName(int index) const { return getUniformBlock(index).name.c_str(); } - - // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE) - int getUniformBlockSize(int index) const { return getUniformBlock(index).size; } - - // returns the block binding number - int getUniformBlockBinding(int index) const { return getUniformBlock(index).getBinding(); } - - // returns block index of associated counter. - int getUniformBlockCounterIndex(int index) const { return getUniformBlock(index).counterIndex; } - - // returns a TType* - const TType *getUniformBlockTType(int index) const { return getUniformBlock(index).getType(); } - - // can be used for glGetActiveAttrib() - const char *getAttributeName(int index) const { return getPipeInput(index).name.c_str(); } - - // can be used for glGetActiveAttrib() - int getAttributeType(int index) const { return getPipeInput(index).glDefineType; } - - // returns a TType* - const TType *getAttributeTType(int index) const { return getPipeInput(index).getType(); } - - void dumpReflection(); - // I/O mapping: apply base offsets and map live unbound variables - // If resolver is not provided it uses the previous approach - // and respects auto assignment and offsets. - bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr); -#endif - -protected: - bool linkStage(EShLanguage, EShMessages); - - TPoolAllocator* pool; - std::list stages[EShLangCount]; - TIntermediate* intermediate[EShLangCount]; - bool newedIntermediate[EShLangCount]; // track which intermediate were "new" versus reusing a singleton unit in a stage - TInfoSink* infoSink; -#ifndef GLSLANG_WEB - TReflection* reflection; -#endif - bool linked; - -private: - TProgram(TProgram&); - TProgram& operator=(TProgram&); -}; - -} // end namespace glslang - -#endif // _COMPILER_INTERFACE_INCLUDED_ diff --git a/libraries/glslang/glslang/updateGrammar b/libraries/glslang/glslang/updateGrammar deleted file mode 100644 index 9384db94886..00000000000 --- a/libraries/glslang/glslang/updateGrammar +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -if [ "$1" = 'web' ] -then - m4 -P -DGLSLANG_WEB MachineIndependent/glslang.m4 > MachineIndependent/glslang.y -elif [ "$#" -eq 0 ] -then - m4 -P MachineIndependent/glslang.m4 > MachineIndependent/glslang.y -else - echo usage: - echo $0 web - echo $0 - exit -fi - -bison --defines=MachineIndependent/glslang_tab.cpp.h -t MachineIndependent/glslang.y -o MachineIndependent/glslang_tab.cpp diff --git a/libraries/glslang/spirv/CMakeLists.txt b/libraries/glslang/spirv/CMakeLists.txt deleted file mode 100644 index 453ac16b5d2..00000000000 --- a/libraries/glslang/spirv/CMakeLists.txt +++ /dev/null @@ -1,118 +0,0 @@ -cmake_minimum_required(VERSION 2.8.12) - -make_release_only() -use_fast_math() - -# Request C++11 -if(${CMAKE_VERSION} VERSION_LESS 3.1) - # CMake versions before 3.1 do not understand CMAKE_CXX_STANDARD - # remove this block once CMake >=3.1 has fixated in the ecosystem - add_compile_options(-std=c++11) -else() - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) -endif() - -set(SOURCES - GlslangToSpv.cpp - InReadableOrder.cpp - Logger.cpp - SpvBuilder.cpp - SpvPostProcess.cpp - doc.cpp - SpvTools.cpp - disassemble.cpp) - -set(SPVREMAP_SOURCES - SPVRemapper.cpp - doc.cpp) - -set(HEADERS - bitutils.h - spirv.hpp - GLSL.std.450.h - GLSL.ext.EXT.h - GLSL.ext.KHR.h - GlslangToSpv.h - hex_float.h - Logger.h - SpvBuilder.h - spvIR.h - doc.h - SpvTools.h - disassemble.h - GLSL.ext.AMD.h - GLSL.ext.NV.h) - -set(SPVREMAP_HEADERS - SPVRemapper.h - doc.h) - -add_library(SPIRV ${LIB_TYPE} ${SOURCES} ${HEADERS}) -set_property(TARGET SPIRV PROPERTY FOLDER glslang) -set_property(TARGET SPIRV PROPERTY POSITION_INDEPENDENT_CODE ON) -target_include_directories(SPIRV PUBLIC - $ - $) - -if (ENABLE_SPVREMAPPER) - add_library(SPVRemapper ${LIB_TYPE} ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS}) - set_property(TARGET SPVRemapper PROPERTY FOLDER glslang) - set_property(TARGET SPVRemapper PROPERTY POSITION_INDEPENDENT_CODE ON) -endif() - -if(WIN32 AND BUILD_SHARED_LIBS) - set_target_properties(SPIRV PROPERTIES PREFIX "") - if (ENABLE_SPVREMAPPER) - set_target_properties(SPVRemapper PROPERTIES PREFIX "") - endif() -endif() - -if(ENABLE_OPT) - target_include_directories(SPIRV - PRIVATE ${spirv-tools_SOURCE_DIR}/include - PRIVATE ${spirv-tools_SOURCE_DIR}/source - ) - target_link_libraries(SPIRV glslang SPIRV-Tools-opt) - target_include_directories(SPIRV PUBLIC - $ - $) -else() - target_link_libraries(SPIRV glslang) -endif(ENABLE_OPT) - -if(WIN32) - source_group("Source" FILES ${SOURCES} ${HEADERS}) - source_group("Source" FILES ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS}) -endif(WIN32) - -if(ENABLE_GLSLANG_INSTALL) - if(BUILD_SHARED_LIBS) - if (ENABLE_SPVREMAPPER) - install(TARGETS SPVRemapper EXPORT SPVRemapperTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() - install(TARGETS SPIRV EXPORT SPIRVTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - else() - if (ENABLE_SPVREMAPPER) - install(TARGETS SPVRemapper EXPORT SPVRemapperTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() - install(TARGETS SPIRV EXPORT SPIRVTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() - - if (ENABLE_SPVREMAPPER) - install(EXPORT SPVRemapperTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake) - endif() - - install(EXPORT SPIRVTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake) - - install(FILES ${HEADERS} ${SPVREMAP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SPIRV/) - install(FILES ${HEADERS} ${SPVREMAP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/glslang/SPIRV/) -endif(ENABLE_GLSLANG_INSTALL) diff --git a/libraries/glslang/spirv/SpvTools.cpp b/libraries/glslang/spirv/SpvTools.cpp deleted file mode 100644 index 7c3b0391927..00000000000 --- a/libraries/glslang/spirv/SpvTools.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// -// Copyright (C) 2014-2016 LunarG, Inc. -// Copyright (C) 2018 Google, Inc. -// -// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. - -// -// Call into SPIRV-Tools to disassemble, validate, and optimize. -// - -#if ENABLE_OPT - -#include -#include - -#include "SpvTools.h" -#include "spirv-tools/optimizer.hpp" -#include "spirv-tools/libspirv.h" - -namespace glslang { - -// Translate glslang's view of target versioning to what SPIRV-Tools uses. -spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger) -{ - switch (spvVersion.vulkan) { - case glslang::EShTargetVulkan_1_0: - return spv_target_env::SPV_ENV_VULKAN_1_0; - case glslang::EShTargetVulkan_1_1: - switch (spvVersion.spv) { - case EShTargetSpv_1_0: - case EShTargetSpv_1_1: - case EShTargetSpv_1_2: - case EShTargetSpv_1_3: - return spv_target_env::SPV_ENV_VULKAN_1_1; - case EShTargetSpv_1_4: - return spv_target_env::SPV_ENV_VULKAN_1_1_SPIRV_1_4; - default: - logger->missingFunctionality("Target version for SPIRV-Tools validator"); - return spv_target_env::SPV_ENV_VULKAN_1_1; - } - default: - break; - } - - if (spvVersion.openGl > 0) - return spv_target_env::SPV_ENV_OPENGL_4_5; - - logger->missingFunctionality("Target version for SPIRV-Tools validator"); - return spv_target_env::SPV_ENV_UNIVERSAL_1_0; -} - - -// Use the SPIRV-Tools disassembler to print SPIR-V. -void SpirvToolsDisassemble(std::ostream& out, const std::vector& spirv) -{ - // disassemble - spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3); - spv_text text; - spv_diagnostic diagnostic = nullptr; - spvBinaryToText(context, spirv.data(), spirv.size(), - SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT, - &text, &diagnostic); - - // dump - if (diagnostic == nullptr) - out << text->str; - else - spvDiagnosticPrint(diagnostic); - - // teardown - spvDiagnosticDestroy(diagnostic); - spvContextDestroy(context); -} - -// Apply the SPIRV-Tools validator to generated SPIR-V. -void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector& spirv, - spv::SpvBuildLogger* logger, bool prelegalization) -{ - // validate - spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger)); - spv_const_binary_t binary = { spirv.data(), spirv.size() }; - spv_diagnostic diagnostic = nullptr; - spv_validator_options options = spvValidatorOptionsCreate(); - spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets()); - spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization); - spvValidateWithOptions(context, options, &binary, &diagnostic); - - // report - if (diagnostic != nullptr) { - logger->error("SPIRV-Tools Validation Errors"); - logger->error(diagnostic->error); - } - - // tear down - spvValidatorOptionsDestroy(options); - spvDiagnosticDestroy(diagnostic); - spvContextDestroy(context); -} - -// Apply the SPIRV-Tools optimizer to generated SPIR-V, for the purpose of -// legalizing HLSL SPIR-V. -void SpirvToolsLegalize(const glslang::TIntermediate&, std::vector& spirv, - spv::SpvBuildLogger*, const SpvOptions* options) -{ - spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2; - - spvtools::Optimizer optimizer(target_env); - optimizer.SetMessageConsumer( - [](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) { - auto &out = std::cerr; - switch (level) - { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - out << "error: "; - break; - case SPV_MSG_WARNING: - out << "warning: "; - break; - case SPV_MSG_INFO: - case SPV_MSG_DEBUG: - out << "info: "; - break; - default: - break; - } - if (source) - { - out << source << ":"; - } - out << position.line << ":" << position.column << ":" << position.index << ":"; - if (message) - { - out << " " << message; - } - out << std::endl; - }); - - // If debug (specifically source line info) is being generated, propagate - // line information into all SPIR-V instructions. This avoids loss of - // information when instructions are deleted or moved. Later, remove - // redundant information to minimize final SPRIR-V size. - if (options->generateDebugInfo) { - optimizer.RegisterPass(spvtools::CreatePropagateLineInfoPass()); - } - optimizer.RegisterPass(spvtools::CreateWrapOpKillPass()); - optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass()); - optimizer.RegisterPass(spvtools::CreateMergeReturnPass()); - optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass()); - optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass()); - optimizer.RegisterPass(spvtools::CreateScalarReplacementPass()); - optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass()); - optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass()); - optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass()); - optimizer.RegisterPass(spvtools::CreateSimplificationPass()); - optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); - optimizer.RegisterPass(spvtools::CreateVectorDCEPass()); - optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass()); - optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); - optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass()); - optimizer.RegisterPass(spvtools::CreateBlockMergePass()); - optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass()); - optimizer.RegisterPass(spvtools::CreateIfConversionPass()); - optimizer.RegisterPass(spvtools::CreateSimplificationPass()); - optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); - optimizer.RegisterPass(spvtools::CreateVectorDCEPass()); - optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass()); - if (options->optimizeSize) { - optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass()); - } - optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); - optimizer.RegisterPass(spvtools::CreateCFGCleanupPass()); - if (options->generateDebugInfo) { - optimizer.RegisterPass(spvtools::CreateRedundantLineInfoElimPass()); - } - - spvtools::OptimizerOptions spvOptOptions; - spvOptOptions.set_run_validator(false); // The validator may run as a seperate step later on - optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); -} - -}; // end namespace glslang - -#endif diff --git a/libraries/glslang/spirv/SpvTools.h b/libraries/glslang/spirv/SpvTools.h deleted file mode 100644 index 59c914da0b7..00000000000 --- a/libraries/glslang/spirv/SpvTools.h +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright (C) 2014-2016 LunarG, Inc. -// Copyright (C) 2018 Google, Inc. -// -// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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. - -// -// Call into SPIRV-Tools to disassemble, validate, and optimize. -// - -#pragma once -#ifndef GLSLANG_SPV_TOOLS_H -#define GLSLANG_SPV_TOOLS_H - -#ifdef ENABLE_OPT -#include -#include -#endif - -#include "glslang/MachineIndependent/localintermediate.h" -#include "Logger.h" - -namespace glslang { - -struct SpvOptions { - SpvOptions() : generateDebugInfo(false), disableOptimizer(true), - optimizeSize(false), disassemble(false), validate(false) { } - bool generateDebugInfo; - bool disableOptimizer; - bool optimizeSize; - bool disassemble; - bool validate; -}; - -#ifdef ENABLE_OPT - -// Use the SPIRV-Tools disassembler to print SPIR-V. -void SpirvToolsDisassemble(std::ostream& out, const std::vector& spirv); - -// Apply the SPIRV-Tools validator to generated SPIR-V. -void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector& spirv, - spv::SpvBuildLogger*, bool prelegalization); - -// Apply the SPIRV-Tools optimizer to generated SPIR-V, for the purpose of -// legalizing HLSL SPIR-V. -void SpirvToolsLegalize(const glslang::TIntermediate& intermediate, std::vector& spirv, - spv::SpvBuildLogger*, const SpvOptions*); - -#endif - -} // end namespace glslang - -#endif // GLSLANG_SPV_TOOLS_H diff --git a/libraries/jpeg/CMakeLists.txt b/libraries/jpeg/CMakeLists.txt deleted file mode 100644 index 33a3938cf07..00000000000 --- a/libraries/jpeg/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -make_release_only() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" ) -endif() - -add_library( jpeg STATIC - jaricom.c - jcomapi.c - jdapimin.c - jdapistd.c - jdarith.c - jdatasrc.c - jdcoefct.c - jdcolor.c - jddctmgr.c - jdhuff.c - jdinput.c - jdmainct.c - jdmarker.c - jdmaster.c - jdmerge.c - jdpostct.c - jdsample.c - jerror.c - jidctflt.c - jidctfst.c - jidctint.c - jmemansi.c - jmemmgr.c - jquant1.c - jquant2.c - jutils.c ) -target_link_libraries( jpeg ) diff --git a/libraries/jpeg/README b/libraries/jpeg/README deleted file mode 100644 index 56cdb600386..00000000000 --- a/libraries/jpeg/README +++ /dev/null @@ -1,378 +0,0 @@ -The Independent JPEG Group's JPEG software -========================================== - -README for release 9c of 14-Jan-2018 -==================================== - -This distribution contains the ninth public release of the Independent JPEG -Group's free JPEG software. You are welcome to redistribute this software and -to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. - -This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone, -Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson, -Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers, -and other members of the Independent JPEG Group. - -IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee -(previously known as JPEG, together with ITU-T SG16). - - -DOCUMENTATION ROADMAP -===================== - -This file contains the following sections: - -OVERVIEW General description of JPEG and the IJG software. -LEGAL ISSUES Copyright, lack of warranty, terms of distribution. -REFERENCES Where to learn more about JPEG. -ARCHIVE LOCATIONS Where to find newer versions of this software. -ACKNOWLEDGMENTS Special thanks. -FILE FORMAT WARS Software *not* to get. -TO DO Plans for future IJG releases. - -Other documentation files in the distribution are: - -User documentation: - install.txt How to configure and install the IJG software. - usage.txt Usage instructions for cjpeg, djpeg, jpegtran, - rdjpgcom, and wrjpgcom. - *.1 Unix-style man pages for programs (same info as usage.txt). - wizard.txt Advanced usage instructions for JPEG wizards only. - change.log Version-to-version change highlights. -Programmer and internal documentation: - libjpeg.txt How to use the JPEG library in your own programs. - example.c Sample code for calling the JPEG library. - structure.txt Overview of the JPEG library's internal structure. - filelist.txt Road map of IJG files. - coderules.txt Coding style rules --- please read if you contribute code. - -Please read at least the files install.txt and usage.txt. Some information -can also be found in the JPEG FAQ (Frequently Asked Questions) article. See -ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. - -If you want to understand how the JPEG code works, we suggest reading one or -more of the REFERENCES, then looking at the documentation files (in roughly -the order listed) before diving into the code. - - -OVERVIEW -======== - -This package contains C software to implement JPEG image encoding, decoding, -and transcoding. JPEG (pronounced "jay-peg") is a standardized compression -method for full-color and grayscale images. - -This software implements JPEG baseline, extended-sequential, and progressive -compression processes. Provision is made for supporting all variants of these -processes, although some uncommon parameter settings aren't implemented yet. -We have made no provision for supporting the hierarchical or lossless -processes defined in the standard. - -We provide a set of library routines for reading and writing JPEG image files, -plus two sample applications "cjpeg" and "djpeg", which use the library to -perform conversion between JPEG and some other popular image file formats. -The library is intended to be reused in other applications. - -In order to support file conversion and viewing software, we have included -considerable functionality beyond the bare JPEG coding/decoding capability; -for example, the color quantization modules are not strictly part of JPEG -decoding, but they are essential for output to colormapped file formats or -colormapped displays. These extra functions can be compiled out of the -library if not required for a particular application. - -We have also included "jpegtran", a utility for lossless transcoding between -different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple -applications for inserting and extracting textual comments in JFIF files. - -The emphasis in designing this software has been on achieving portability and -flexibility, while also making it fast enough to be useful. In particular, -the software is not intended to be read as a tutorial on JPEG. (See the -REFERENCES section for introductory material.) Rather, it is intended to -be reliable, portable, industrial-strength code. We do not claim to have -achieved that goal in every aspect of the software, but we strive for it. - -We welcome the use of this software as a component of commercial products. -No royalty is required, but we do ask for an acknowledgement in product -documentation, as described under LEGAL ISSUES. - - -LEGAL ISSUES -============ - -In plain English: - -1. We don't promise that this software works. (But if you find any bugs, - please let us know!) -2. You can use this software for whatever you want. You don't have to pay us. -3. You may not pretend that you wrote this software. If you use it in a - program, you must acknowledge somewhere in your documentation that - you've used the IJG code. - -In legalese: - -The authors make NO WARRANTY or representation, either express or implied, -with respect to this software, its quality, accuracy, merchantability, or -fitness for a particular purpose. This software is provided "AS IS", and you, -its user, assume the entire risk as to its quality and accuracy. - -This software is copyright (C) 1991-2018, Thomas G. Lane, Guido Vollbeding. -All Rights Reserved except as specified below. - -Permission is hereby granted to use, copy, modify, and distribute this -software (or portions thereof) for any purpose, without fee, subject to these -conditions: -(1) If any part of the source code for this software is distributed, then this -README file must be included, with this copyright and no-warranty notice -unaltered; and any additions, deletions, or changes to the original files -must be clearly indicated in accompanying documentation. -(2) If only executable code is distributed, then the accompanying -documentation must state that "this software is based in part on the work of -the Independent JPEG Group". -(3) Permission for use of this software is granted only if the user accepts -full responsibility for any undesirable consequences; the authors accept -NO LIABILITY for damages of any kind. - -These conditions apply to any software derived from or based on the IJG code, -not just to the unmodified library. If you use our work, you ought to -acknowledge us. - -Permission is NOT granted for the use of any IJG author's name or company name -in advertising or publicity relating to this software or products derived from -it. This software may be referred to only as "the Independent JPEG Group's -software". - -We specifically permit and encourage the use of this software as the basis of -commercial products, provided that all warranty or liability claims are -assumed by the product vendor. - - -The Unix configuration script "configure" was produced with GNU Autoconf. -It is copyright by the Free Software Foundation but is freely distributable. -The same holds for its supporting scripts (config.guess, config.sub, -ltmain.sh). Another support script, install-sh, is copyright by X Consortium -but is also freely distributable. - -The IJG distribution formerly included code to read and write GIF files. -To avoid entanglement with the Unisys LZW patent (now expired), GIF reading -support has been removed altogether, and the GIF writer has been simplified -to produce "uncompressed GIFs". This technique does not use the LZW -algorithm; the resulting GIF files are larger than usual, but are readable -by all standard GIF decoders. - - -REFERENCES -========== - -We recommend reading one or more of these references before trying to -understand the innards of the JPEG software. - -The best short technical introduction to the JPEG compression algorithm is - Wallace, Gregory K. "The JPEG Still Picture Compression Standard", - Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. -(Adjacent articles in that issue discuss MPEG motion picture compression, -applications of JPEG, and related topics.) If you don't have the CACM issue -handy, a PDF file containing a revised version of Wallace's article is -available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually -a preprint for an article that appeared in IEEE Trans. Consumer Electronics) -omits the sample images that appeared in CACM, but it includes corrections -and some added material. Note: the Wallace article is copyright ACM and IEEE, -and it may not be used for commercial purposes. - -A somewhat less technical, more leisurely introduction to JPEG can be found in -"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by -M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides -good explanations and example C code for a multitude of compression methods -including JPEG. It is an excellent source if you are comfortable reading C -code but don't know much about data compression in general. The book's JPEG -sample code is far from industrial-strength, but when you are ready to look -at a full implementation, you've got one here... - -The best currently available description of JPEG is the textbook "JPEG Still -Image Data Compression Standard" by William B. Pennebaker and Joan L. -Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. -Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG -standards (DIS 10918-1 and draft DIS 10918-2). -Although this is by far the most detailed and comprehensive exposition of -JPEG publicly available, we point out that it is still missing an explanation -of the most essential properties and algorithms of the underlying DCT -technology. -If you think that you know about DCT-based JPEG after reading this book, -then you are in delusion. The real fundamentals and corresponding potential -of DCT-based JPEG are not publicly known so far, and that is the reason for -all the mistaken developments taking place in the image coding domain. - -The original JPEG standard is divided into two parts, Part 1 being the actual -specification, while Part 2 covers compliance testing methods. Part 1 is -titled "Digital Compression and Coding of Continuous-tone Still Images, -Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS -10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of -Continuous-tone Still Images, Part 2: Compliance testing" and has document -numbers ISO/IEC IS 10918-2, ITU-T T.83. -IJG JPEG 8 introduced an implementation of the JPEG SmartScale extension -which is specified in two documents: A contributed document at ITU and ISO -with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced -Image Coding", April 2006, Geneva, Switzerland. The latest version of this -document is Revision 3. And a contributed document ISO/IEC JTC1/SC29/WG1 N -5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany. -IJG JPEG 9 introduces a reversible color transform for improved lossless -compression which is described in a contributed document ISO/IEC JTC1/SC29/ -WG1 N 6080 with title "JPEG 9 Lossless Coding", June/July 2012, Paris, -France. - -The JPEG standard does not specify all details of an interchangeable file -format. For the omitted details we follow the "JFIF" conventions, version 2. -JFIF version 1 has been adopted as Recommendation ITU-T T.871 (05/2011) : -Information technology - Digital compression and coding of continuous-tone -still images: JPEG File Interchange Format (JFIF). It is available as a -free download in PDF file format from http://www.itu.int/rec/T-REC-T.871. -A PDF file of the older JFIF document is available at -http://www.w3.org/Graphics/JPEG/jfif3.pdf. - -The TIFF 6.0 file format specification can be obtained by FTP from -ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme -found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. -IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). -Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 -(Compression tag 7). Copies of this Note can be obtained from -http://www.ijg.org/files/. It is expected that the next revision -of the TIFF spec will replace the 6.0 JPEG design with the Note's design. -Although IJG's own code does not support TIFF/JPEG, the free libtiff library -uses our library to implement TIFF/JPEG per the Note. - - -ARCHIVE LOCATIONS -================= - -The "official" archive site for this software is www.ijg.org. -The most recent released version can always be found there in -directory "files". This particular version will be archived as -http://www.ijg.org/files/jpegsrc.v9c.tar.gz, and in Windows-compatible -"zip" archive format as http://www.ijg.org/files/jpegsr9c.zip. - -The JPEG FAQ (Frequently Asked Questions) article is a source of some -general information about JPEG. -It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ -and other news.answers archive sites, including the official news.answers -archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. -If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu -with body - send usenet/news.answers/jpeg-faq/part1 - send usenet/news.answers/jpeg-faq/part2 - - -ACKNOWLEDGMENTS -=============== - -Thank to Juergen Bruder for providing me with a copy of the common DCT -algorithm article, only to find out that I had come to the same result -in a more direct and comprehensible way with a more generative approach. - -Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the -ITU JPEG (Study Group 16) meeting in Geneva, Switzerland. - -Thank to Thomas Wiegand and Gary Sullivan for inviting me to the -Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland. - -Thank to Thomas Richter and Daniel Lee for inviting me to the -ISO/IEC JTC1/SC29/WG1 (previously known as JPEG, together with ITU-T SG16) -meeting in Berlin, Germany. - -Thank to John Korejwa and Massimo Ballerini for inviting me to -fruitful consultations in Boston, MA and Milan, Italy. - -Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther -Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel -for corresponding business development. - -Thank to Nico Zschach and Dirk Stelling of the technical support team -at the Digital Images company in Halle for providing me with extra -equipment for configuration tests. - -Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful -communication about JPEG configuration in Sigma Photo Pro software. - -Thank to Andrew Finkenstadt for hosting the ijg.org site. - -Thank to Thomas G. Lane for the original design and development of -this singular software package. - -Thank to Lars Goehler, Andreas Heinecke, Sebastian Fuss, Yvonne Roebert, -Andrej Werner, and Ulf-Dietrich Braumann for support and public relations. - - -FILE FORMAT WARS -================ - -The ISO/IEC JTC1/SC29/WG1 standards committee (previously known as JPEG, -together with ITU-T SG16) currently promotes different formats containing -the name "JPEG" which is misleading because these formats are incompatible -with original DCT-based JPEG and are based on faulty technologies. -IJG therefore does not and will not support such momentary mistakes -(see REFERENCES). -There exist also distributions under the name "OpenJPEG" promoting such -kind of formats which is misleading because they don't support original -JPEG images. -We have no sympathy for the promotion of inferior formats. Indeed, one of -the original reasons for developing this free software was to help force -convergence on common, interoperable format standards for JPEG files. -Don't use an incompatible file format! -(In any case, our decoder will remain capable of reading existing JPEG -image files indefinitely.) - -The ISO committee pretends to be "responsible for the popular JPEG" in their -public reports which is not true because they don't respond to actual -requirements for the maintenance of the original JPEG specification. -Furthermore, the ISO committee pretends to "ensure interoperability" with -their standards which is not true because their "standards" support only -application-specific and proprietary use cases and contain mathematically -incorrect code. - -There are currently different distributions in circulation containing the -name "libjpeg" which is misleading because they don't have the features and -are incompatible with formats supported by actual IJG libjpeg distributions. -One of those fakes is released by members of the ISO committee and just uses -the name of libjpeg for misdirection of people, similar to the abuse of the -name JPEG as described above, while having nothing in common with actual IJG -libjpeg distributions and containing mathematically incorrect code. -The other one claims to be a "derivative" or "fork" of the original libjpeg, -but violates the license conditions as described under LEGAL ISSUES above -and violates basic C programming properties. -We have no sympathy for the release of misleading, incorrect and illegal -distributions derived from obsolete code bases. -Don't use an obsolete code base! - -According to the UCC (Uniform Commercial Code) law, IJG has the lawful and -legal right to foreclose on certain standardization bodies and other -institutions or corporations that knowingly perform substantial and -systematic deceptive acts and practices, fraud, theft, and damaging of the -value of the people of this planet without their knowing, willing and -intentional consent. -The titles, ownership, and rights of these institutions and all their assets -are now duly secured and held in trust for the free people of this planet. -People of the planet, on every country, may have a financial interest in -the assets of these former principals, agents, and beneficiaries of the -foreclosed institutions and corporations. -IJG asserts what is: that each man, woman, and child has unalienable value -and rights granted and deposited in them by the Creator and not any one of -the people is subordinate to any artificial principality, corporate fiction -or the special interest of another without their appropriate knowing, -willing and intentional consent made by contract or accommodation agreement. -IJG expresses that which already was. -The people have already determined and demanded that public administration -entities, national governments, and their supporting judicial systems must -be fully transparent, accountable, and liable. -IJG has secured the value for all concerned free people of the planet. - -A partial list of foreclosed institutions and corporations ("Hall of Shame") -is currently prepared and will be published later. - - -TO DO -===== - -Version 9 is the second release of a new generation JPEG standard -to overcome the limitations of the original JPEG specification, -and is the first true source reference JPEG codec. -More features are being prepared for coming releases... - -Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org. diff --git a/libraries/jpeg/jaricom.c b/libraries/jpeg/jaricom.c deleted file mode 100644 index 690068861fa..00000000000 --- a/libraries/jpeg/jaricom.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * jaricom.c - * - * Developed 1997-2011 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains probability estimation tables for common use in - * arithmetic entropy encoding and decoding routines. - * - * This data represents Table D.3 in the JPEG spec (D.2 in the draft), - * ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81, and Table 24 - * in the JBIG spec, ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -/* The following #define specifies the packing of the four components - * into the compact INT32 representation. - * Note that this formula must match the actual arithmetic encoder - * and decoder implementation. The implementation has to be changed - * if this formula is changed. - * The current organization is leaned on Markus Kuhn's JBIG - * implementation (jbig_tab.c). - */ - -#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b) - -const INT32 jpeg_aritab[113+1] = { -/* - * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS - */ - V( 0, 0x5a1d, 1, 1, 1 ), - V( 1, 0x2586, 14, 2, 0 ), - V( 2, 0x1114, 16, 3, 0 ), - V( 3, 0x080b, 18, 4, 0 ), - V( 4, 0x03d8, 20, 5, 0 ), - V( 5, 0x01da, 23, 6, 0 ), - V( 6, 0x00e5, 25, 7, 0 ), - V( 7, 0x006f, 28, 8, 0 ), - V( 8, 0x0036, 30, 9, 0 ), - V( 9, 0x001a, 33, 10, 0 ), - V( 10, 0x000d, 35, 11, 0 ), - V( 11, 0x0006, 9, 12, 0 ), - V( 12, 0x0003, 10, 13, 0 ), - V( 13, 0x0001, 12, 13, 0 ), - V( 14, 0x5a7f, 15, 15, 1 ), - V( 15, 0x3f25, 36, 16, 0 ), - V( 16, 0x2cf2, 38, 17, 0 ), - V( 17, 0x207c, 39, 18, 0 ), - V( 18, 0x17b9, 40, 19, 0 ), - V( 19, 0x1182, 42, 20, 0 ), - V( 20, 0x0cef, 43, 21, 0 ), - V( 21, 0x09a1, 45, 22, 0 ), - V( 22, 0x072f, 46, 23, 0 ), - V( 23, 0x055c, 48, 24, 0 ), - V( 24, 0x0406, 49, 25, 0 ), - V( 25, 0x0303, 51, 26, 0 ), - V( 26, 0x0240, 52, 27, 0 ), - V( 27, 0x01b1, 54, 28, 0 ), - V( 28, 0x0144, 56, 29, 0 ), - V( 29, 0x00f5, 57, 30, 0 ), - V( 30, 0x00b7, 59, 31, 0 ), - V( 31, 0x008a, 60, 32, 0 ), - V( 32, 0x0068, 62, 33, 0 ), - V( 33, 0x004e, 63, 34, 0 ), - V( 34, 0x003b, 32, 35, 0 ), - V( 35, 0x002c, 33, 9, 0 ), - V( 36, 0x5ae1, 37, 37, 1 ), - V( 37, 0x484c, 64, 38, 0 ), - V( 38, 0x3a0d, 65, 39, 0 ), - V( 39, 0x2ef1, 67, 40, 0 ), - V( 40, 0x261f, 68, 41, 0 ), - V( 41, 0x1f33, 69, 42, 0 ), - V( 42, 0x19a8, 70, 43, 0 ), - V( 43, 0x1518, 72, 44, 0 ), - V( 44, 0x1177, 73, 45, 0 ), - V( 45, 0x0e74, 74, 46, 0 ), - V( 46, 0x0bfb, 75, 47, 0 ), - V( 47, 0x09f8, 77, 48, 0 ), - V( 48, 0x0861, 78, 49, 0 ), - V( 49, 0x0706, 79, 50, 0 ), - V( 50, 0x05cd, 48, 51, 0 ), - V( 51, 0x04de, 50, 52, 0 ), - V( 52, 0x040f, 50, 53, 0 ), - V( 53, 0x0363, 51, 54, 0 ), - V( 54, 0x02d4, 52, 55, 0 ), - V( 55, 0x025c, 53, 56, 0 ), - V( 56, 0x01f8, 54, 57, 0 ), - V( 57, 0x01a4, 55, 58, 0 ), - V( 58, 0x0160, 56, 59, 0 ), - V( 59, 0x0125, 57, 60, 0 ), - V( 60, 0x00f6, 58, 61, 0 ), - V( 61, 0x00cb, 59, 62, 0 ), - V( 62, 0x00ab, 61, 63, 0 ), - V( 63, 0x008f, 61, 32, 0 ), - V( 64, 0x5b12, 65, 65, 1 ), - V( 65, 0x4d04, 80, 66, 0 ), - V( 66, 0x412c, 81, 67, 0 ), - V( 67, 0x37d8, 82, 68, 0 ), - V( 68, 0x2fe8, 83, 69, 0 ), - V( 69, 0x293c, 84, 70, 0 ), - V( 70, 0x2379, 86, 71, 0 ), - V( 71, 0x1edf, 87, 72, 0 ), - V( 72, 0x1aa9, 87, 73, 0 ), - V( 73, 0x174e, 72, 74, 0 ), - V( 74, 0x1424, 72, 75, 0 ), - V( 75, 0x119c, 74, 76, 0 ), - V( 76, 0x0f6b, 74, 77, 0 ), - V( 77, 0x0d51, 75, 78, 0 ), - V( 78, 0x0bb6, 77, 79, 0 ), - V( 79, 0x0a40, 77, 48, 0 ), - V( 80, 0x5832, 80, 81, 1 ), - V( 81, 0x4d1c, 88, 82, 0 ), - V( 82, 0x438e, 89, 83, 0 ), - V( 83, 0x3bdd, 90, 84, 0 ), - V( 84, 0x34ee, 91, 85, 0 ), - V( 85, 0x2eae, 92, 86, 0 ), - V( 86, 0x299a, 93, 87, 0 ), - V( 87, 0x2516, 86, 71, 0 ), - V( 88, 0x5570, 88, 89, 1 ), - V( 89, 0x4ca9, 95, 90, 0 ), - V( 90, 0x44d9, 96, 91, 0 ), - V( 91, 0x3e22, 97, 92, 0 ), - V( 92, 0x3824, 99, 93, 0 ), - V( 93, 0x32b4, 99, 94, 0 ), - V( 94, 0x2e17, 93, 86, 0 ), - V( 95, 0x56a8, 95, 96, 1 ), - V( 96, 0x4f46, 101, 97, 0 ), - V( 97, 0x47e5, 102, 98, 0 ), - V( 98, 0x41cf, 103, 99, 0 ), - V( 99, 0x3c3d, 104, 100, 0 ), - V( 100, 0x375e, 99, 93, 0 ), - V( 101, 0x5231, 105, 102, 0 ), - V( 102, 0x4c0f, 106, 103, 0 ), - V( 103, 0x4639, 107, 104, 0 ), - V( 104, 0x415e, 103, 99, 0 ), - V( 105, 0x5627, 105, 106, 1 ), - V( 106, 0x50e7, 108, 107, 0 ), - V( 107, 0x4b85, 109, 103, 0 ), - V( 108, 0x5597, 110, 109, 0 ), - V( 109, 0x504f, 111, 107, 0 ), - V( 110, 0x5a10, 110, 111, 1 ), - V( 111, 0x5522, 112, 109, 0 ), - V( 112, 0x59eb, 112, 111, 1 ), -/* - * This last entry is used for fixed probability estimate of 0.5 - * as suggested in Section 10.3 Table 5 of ITU-T Rec. T.851. - */ - V( 113, 0x5a1d, 113, 113, 0 ) -}; diff --git a/libraries/jpeg/jcomapi.c b/libraries/jpeg/jcomapi.c deleted file mode 100644 index 9b1fa7568a6..00000000000 --- a/libraries/jpeg/jcomapi.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * jcomapi.c - * - * Copyright (C) 1994-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains application interface routines that are used for both - * compression and decompression. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * Abort processing of a JPEG compression or decompression operation, - * but don't destroy the object itself. - * - * For this, we merely clean up all the nonpermanent memory pools. - * Note that temp files (virtual arrays) are not allowed to belong to - * the permanent pool, so we will be able to close all temp files here. - * Closing a data source or destination, if necessary, is the application's - * responsibility. - */ - -GLOBAL(void) -jpeg_abort (j_common_ptr cinfo) -{ - int pool; - - /* Do nothing if called on a not-initialized or destroyed JPEG object. */ - if (cinfo->mem == NULL) - return; - - /* Releasing pools in reverse order might help avoid fragmentation - * with some (brain-damaged) malloc libraries. - */ - for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { - (*cinfo->mem->free_pool) (cinfo, pool); - } - - /* Reset overall state for possible reuse of object */ - if (cinfo->is_decompressor) { - cinfo->global_state = DSTATE_START; - /* Try to keep application from accessing now-deleted marker list. - * A bit kludgy to do it here, but this is the most central place. - */ - ((j_decompress_ptr) cinfo)->marker_list = NULL; - } else { - cinfo->global_state = CSTATE_START; - } -} - - -/* - * Destruction of a JPEG object. - * - * Everything gets deallocated except the master jpeg_compress_struct itself - * and the error manager struct. Both of these are supplied by the application - * and must be freed, if necessary, by the application. (Often they are on - * the stack and so don't need to be freed anyway.) - * Closing a data source or destination, if necessary, is the application's - * responsibility. - */ - -GLOBAL(void) -jpeg_destroy (j_common_ptr cinfo) -{ - /* We need only tell the memory manager to release everything. */ - /* NB: mem pointer is NULL if memory mgr failed to initialize. */ - if (cinfo->mem != NULL) - (*cinfo->mem->self_destruct) (cinfo); - cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ - cinfo->global_state = 0; /* mark it destroyed */ -} - - -/* - * Convenience routines for allocating quantization and Huffman tables. - * (Would jutils.c be a more reasonable place to put these?) - */ - -GLOBAL(JQUANT_TBL *) -jpeg_alloc_quant_table (j_common_ptr cinfo) -{ - JQUANT_TBL *tbl; - - tbl = (JQUANT_TBL *) - (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); - tbl->sent_table = FALSE; /* make sure this is false in any new table */ - return tbl; -} - - -GLOBAL(JHUFF_TBL *) -jpeg_alloc_huff_table (j_common_ptr cinfo) -{ - JHUFF_TBL *tbl; - - tbl = (JHUFF_TBL *) - (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); - tbl->sent_table = FALSE; /* make sure this is false in any new table */ - return tbl; -} diff --git a/libraries/jpeg/jconfig.h b/libraries/jpeg/jconfig.h deleted file mode 100644 index 347e6cb0faf..00000000000 --- a/libraries/jpeg/jconfig.h +++ /dev/null @@ -1,32 +0,0 @@ -/* jconfig.vc --- jconfig.h for Microsoft Visual C++ on Windows 95 or NT. */ -/* see jconfig.doc for explanations */ - -#define HAVE_PROTOTYPES -#define HAVE_UNSIGNED_CHAR -#define HAVE_UNSIGNED_SHORT -/* #define void char */ -/* #define const */ -#undef CHAR_IS_UNSIGNED -#define HAVE_STDDEF_H -#define HAVE_STDLIB_H -#undef NEED_BSD_STRINGS -#undef NEED_SYS_TYPES_H - -/* Define "boolean" as unsigned char, not int, per Windows custom */ -#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ -typedef unsigned char boolean; -#endif -#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - -#ifdef JPEG_INTERNALS - -#undef RIGHT_SHIFT_IS_UNSIGNED - -#endif /* JPEG_INTERNALS */ diff --git a/libraries/jpeg/jdapimin.c b/libraries/jpeg/jdapimin.c deleted file mode 100644 index a6e0dd9fb82..00000000000 --- a/libraries/jpeg/jdapimin.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * jdapimin.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * Modified 2009-2013 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains application interface code for the decompression half - * of the JPEG library. These are the "minimum" API routines that may be - * needed in either the normal full-decompression case or the - * transcoding-only case. - * - * Most of the routines intended to be called directly by an application - * are in this file or in jdapistd.c. But also see jcomapi.c for routines - * shared by compression and decompression, and jdtrans.c for the transcoding - * case. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * Initialization of a JPEG decompression object. - * The error manager must already be set up (in case memory manager fails). - */ - -GLOBAL(void) -jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) -{ - int i; - - /* Guard against version mismatches between library and caller. */ - cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ - if (version != JPEG_LIB_VERSION) - ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); - if (structsize != SIZEOF(struct jpeg_decompress_struct)) - ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, - (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize); - - /* For debugging purposes, we zero the whole master structure. - * But the application has already set the err pointer, and may have set - * client_data, so we have to save and restore those fields. - * Note: if application hasn't set client_data, tools like Purify may - * complain here. - */ - { - struct jpeg_error_mgr * err = cinfo->err; - void * client_data = cinfo->client_data; /* ignore Purify complaint here */ - MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); - cinfo->err = err; - cinfo->client_data = client_data; - } - cinfo->is_decompressor = TRUE; - - /* Initialize a memory manager instance for this object */ - jinit_memory_mgr((j_common_ptr) cinfo); - - /* Zero out pointers to permanent structures. */ - cinfo->progress = NULL; - cinfo->src = NULL; - - for (i = 0; i < NUM_QUANT_TBLS; i++) - cinfo->quant_tbl_ptrs[i] = NULL; - - for (i = 0; i < NUM_HUFF_TBLS; i++) { - cinfo->dc_huff_tbl_ptrs[i] = NULL; - cinfo->ac_huff_tbl_ptrs[i] = NULL; - } - - /* Initialize marker processor so application can override methods - * for COM, APPn markers before calling jpeg_read_header. - */ - cinfo->marker_list = NULL; - jinit_marker_reader(cinfo); - - /* And initialize the overall input controller. */ - jinit_input_controller(cinfo); - - /* OK, I'm ready */ - cinfo->global_state = DSTATE_START; -} - - -/* - * Destruction of a JPEG decompression object - */ - -GLOBAL(void) -jpeg_destroy_decompress (j_decompress_ptr cinfo) -{ - jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ -} - - -/* - * Abort processing of a JPEG decompression operation, - * but don't destroy the object itself. - */ - -GLOBAL(void) -jpeg_abort_decompress (j_decompress_ptr cinfo) -{ - jpeg_abort((j_common_ptr) cinfo); /* use common routine */ -} - - -/* - * Set default decompression parameters. - */ - -LOCAL(void) -default_decompress_parms (j_decompress_ptr cinfo) -{ - int cid0, cid1, cid2; - - /* Guess the input colorspace, and set output colorspace accordingly. */ - /* Note application may override our guesses. */ - switch (cinfo->num_components) { - case 1: - cinfo->jpeg_color_space = JCS_GRAYSCALE; - cinfo->out_color_space = JCS_GRAYSCALE; - break; - - case 3: - cid0 = cinfo->comp_info[0].component_id; - cid1 = cinfo->comp_info[1].component_id; - cid2 = cinfo->comp_info[2].component_id; - - /* First try to guess from the component IDs */ - if (cid0 == 0x01 && cid1 == 0x02 && cid2 == 0x03) - cinfo->jpeg_color_space = JCS_YCbCr; - else if (cid0 == 0x01 && cid1 == 0x22 && cid2 == 0x23) - cinfo->jpeg_color_space = JCS_BG_YCC; - else if (cid0 == 0x52 && cid1 == 0x47 && cid2 == 0x42) - cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ - else if (cid0 == 0x72 && cid1 == 0x67 && cid2 == 0x62) - cinfo->jpeg_color_space = JCS_BG_RGB; /* ASCII 'r', 'g', 'b' */ - else if (cinfo->saw_JFIF_marker) - cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ - else if (cinfo->saw_Adobe_marker) { - switch (cinfo->Adobe_transform) { - case 0: - cinfo->jpeg_color_space = JCS_RGB; - break; - case 1: - cinfo->jpeg_color_space = JCS_YCbCr; - break; - default: - WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); - cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ - break; - } - } else { - TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); - cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ - } - /* Always guess RGB is proper output colorspace. */ - cinfo->out_color_space = JCS_RGB; - break; - - case 4: - if (cinfo->saw_Adobe_marker) { - switch (cinfo->Adobe_transform) { - case 0: - cinfo->jpeg_color_space = JCS_CMYK; - break; - case 2: - cinfo->jpeg_color_space = JCS_YCCK; - break; - default: - WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); - cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ - break; - } - } else { - /* No special markers, assume straight CMYK. */ - cinfo->jpeg_color_space = JCS_CMYK; - } - cinfo->out_color_space = JCS_CMYK; - break; - - default: - cinfo->jpeg_color_space = JCS_UNKNOWN; - cinfo->out_color_space = JCS_UNKNOWN; - break; - } - - /* Set defaults for other decompression parameters. */ - cinfo->scale_num = cinfo->block_size; /* 1:1 scaling */ - cinfo->scale_denom = cinfo->block_size; - cinfo->output_gamma = 1.0; - cinfo->buffered_image = FALSE; - cinfo->raw_data_out = FALSE; - cinfo->dct_method = JDCT_DEFAULT; - cinfo->do_fancy_upsampling = TRUE; - cinfo->do_block_smoothing = TRUE; - cinfo->quantize_colors = FALSE; - /* We set these in case application only sets quantize_colors. */ - cinfo->dither_mode = JDITHER_FS; -#ifdef QUANT_2PASS_SUPPORTED - cinfo->two_pass_quantize = TRUE; -#else - cinfo->two_pass_quantize = FALSE; -#endif - cinfo->desired_number_of_colors = 256; - cinfo->colormap = NULL; - /* Initialize for no mode change in buffered-image mode. */ - cinfo->enable_1pass_quant = FALSE; - cinfo->enable_external_quant = FALSE; - cinfo->enable_2pass_quant = FALSE; -} - - -/* - * Decompression startup: read start of JPEG datastream to see what's there. - * Need only initialize JPEG object and supply a data source before calling. - * - * This routine will read as far as the first SOS marker (ie, actual start of - * compressed data), and will save all tables and parameters in the JPEG - * object. It will also initialize the decompression parameters to default - * values, and finally return JPEG_HEADER_OK. On return, the application may - * adjust the decompression parameters and then call jpeg_start_decompress. - * (Or, if the application only wanted to determine the image parameters, - * the data need not be decompressed. In that case, call jpeg_abort or - * jpeg_destroy to release any temporary space.) - * If an abbreviated (tables only) datastream is presented, the routine will - * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then - * re-use the JPEG object to read the abbreviated image datastream(s). - * It is unnecessary (but OK) to call jpeg_abort in this case. - * The JPEG_SUSPENDED return code only occurs if the data source module - * requests suspension of the decompressor. In this case the application - * should load more source data and then re-call jpeg_read_header to resume - * processing. - * If a non-suspending data source is used and require_image is TRUE, then the - * return code need not be inspected since only JPEG_HEADER_OK is possible. - * - * This routine is now just a front end to jpeg_consume_input, with some - * extra error checking. - */ - -GLOBAL(int) -jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) -{ - int retcode; - - if (cinfo->global_state != DSTATE_START && - cinfo->global_state != DSTATE_INHEADER) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - retcode = jpeg_consume_input(cinfo); - - switch (retcode) { - case JPEG_REACHED_SOS: - retcode = JPEG_HEADER_OK; - break; - case JPEG_REACHED_EOI: - if (require_image) /* Complain if application wanted an image */ - ERREXIT(cinfo, JERR_NO_IMAGE); - /* Reset to start state; it would be safer to require the application to - * call jpeg_abort, but we can't change it now for compatibility reasons. - * A side effect is to free any temporary memory (there shouldn't be any). - */ - jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ - retcode = JPEG_HEADER_TABLES_ONLY; - break; - case JPEG_SUSPENDED: - /* no work */ - break; - } - - return retcode; -} - - -/* - * Consume data in advance of what the decompressor requires. - * This can be called at any time once the decompressor object has - * been created and a data source has been set up. - * - * This routine is essentially a state machine that handles a couple - * of critical state-transition actions, namely initial setup and - * transition from header scanning to ready-for-start_decompress. - * All the actual input is done via the input controller's consume_input - * method. - */ - -GLOBAL(int) -jpeg_consume_input (j_decompress_ptr cinfo) -{ - int retcode = JPEG_SUSPENDED; - - /* NB: every possible DSTATE value should be listed in this switch */ - switch (cinfo->global_state) { - case DSTATE_START: - /* Start-of-datastream actions: reset appropriate modules */ - (*cinfo->inputctl->reset_input_controller) (cinfo); - /* Initialize application's data source module */ - (*cinfo->src->init_source) (cinfo); - cinfo->global_state = DSTATE_INHEADER; - /*FALLTHROUGH*/ - case DSTATE_INHEADER: - retcode = (*cinfo->inputctl->consume_input) (cinfo); - if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ - /* Set up default parameters based on header data */ - default_decompress_parms(cinfo); - /* Set global state: ready for start_decompress */ - cinfo->global_state = DSTATE_READY; - } - break; - case DSTATE_READY: - /* Can't advance past first SOS until start_decompress is called */ - retcode = JPEG_REACHED_SOS; - break; - case DSTATE_PRELOAD: - case DSTATE_PRESCAN: - case DSTATE_SCANNING: - case DSTATE_RAW_OK: - case DSTATE_BUFIMAGE: - case DSTATE_BUFPOST: - case DSTATE_STOPPING: - retcode = (*cinfo->inputctl->consume_input) (cinfo); - break; - default: - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - } - return retcode; -} - - -/* - * Have we finished reading the input file? - */ - -GLOBAL(boolean) -jpeg_input_complete (j_decompress_ptr cinfo) -{ - /* Check for valid jpeg object */ - if (cinfo->global_state < DSTATE_START || - cinfo->global_state > DSTATE_STOPPING) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - return cinfo->inputctl->eoi_reached; -} - - -/* - * Is there more than one scan? - */ - -GLOBAL(boolean) -jpeg_has_multiple_scans (j_decompress_ptr cinfo) -{ - /* Only valid after jpeg_read_header completes */ - if (cinfo->global_state < DSTATE_READY || - cinfo->global_state > DSTATE_STOPPING) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - return cinfo->inputctl->has_multiple_scans; -} - - -/* - * Finish JPEG decompression. - * - * This will normally just verify the file trailer and release temp storage. - * - * Returns FALSE if suspended. The return value need be inspected only if - * a suspending data source is used. - */ - -GLOBAL(boolean) -jpeg_finish_decompress (j_decompress_ptr cinfo) -{ - if ((cinfo->global_state == DSTATE_SCANNING || - cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { - /* Terminate final pass of non-buffered mode */ - if (cinfo->output_scanline < cinfo->output_height) - ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); - (*cinfo->master->finish_output_pass) (cinfo); - cinfo->global_state = DSTATE_STOPPING; - } else if (cinfo->global_state == DSTATE_BUFIMAGE) { - /* Finishing after a buffered-image operation */ - cinfo->global_state = DSTATE_STOPPING; - } else if (cinfo->global_state != DSTATE_STOPPING) { - /* STOPPING = repeat call after a suspension, anything else is error */ - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - } - /* Read until EOI */ - while (! cinfo->inputctl->eoi_reached) { - if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) - return FALSE; /* Suspend, come back later */ - } - /* Do final cleanup */ - (*cinfo->src->term_source) (cinfo); - /* We can use jpeg_abort to release memory and reset global_state */ - jpeg_abort((j_common_ptr) cinfo); - return TRUE; -} diff --git a/libraries/jpeg/jdapistd.c b/libraries/jpeg/jdapistd.c deleted file mode 100644 index 7f3a78b25af..00000000000 --- a/libraries/jpeg/jdapistd.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * jdapistd.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2002-2013 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains application interface code for the decompression half - * of the JPEG library. These are the "standard" API routines that are - * used in the normal full-decompression case. They are not used by a - * transcoding-only application. Note that if an application links in - * jpeg_start_decompress, it will end up linking in the entire decompressor. - * We thus must separate this file from jdapimin.c to avoid linking the - * whole decompression library into a transcoder. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Forward declarations */ -LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); - - -/* - * Decompression initialization. - * jpeg_read_header must be completed before calling this. - * - * If a multipass operating mode was selected, this will do all but the - * last pass, and thus may take a great deal of time. - * - * Returns FALSE if suspended. The return value need be inspected only if - * a suspending data source is used. - */ - -GLOBAL(boolean) -jpeg_start_decompress (j_decompress_ptr cinfo) -{ - if (cinfo->global_state == DSTATE_READY) { - /* First call: initialize master control, select active modules */ - jinit_master_decompress(cinfo); - if (cinfo->buffered_image) { - /* No more work here; expecting jpeg_start_output next */ - cinfo->global_state = DSTATE_BUFIMAGE; - return TRUE; - } - cinfo->global_state = DSTATE_PRELOAD; - } - if (cinfo->global_state == DSTATE_PRELOAD) { - /* If file has multiple scans, absorb them all into the coef buffer */ - if (cinfo->inputctl->has_multiple_scans) { -#ifdef D_MULTISCAN_FILES_SUPPORTED - for (;;) { - int retcode; - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - /* Absorb some more input */ - retcode = (*cinfo->inputctl->consume_input) (cinfo); - if (retcode == JPEG_SUSPENDED) - return FALSE; - if (retcode == JPEG_REACHED_EOI) - break; - /* Advance progress counter if appropriate */ - if (cinfo->progress != NULL && - (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { - if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { - /* jdmaster underestimated number of scans; ratchet up one scan */ - cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; - } - } - } -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif /* D_MULTISCAN_FILES_SUPPORTED */ - } - cinfo->output_scan_number = cinfo->input_scan_number; - } else if (cinfo->global_state != DSTATE_PRESCAN) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - /* Perform any dummy output passes, and set up for the final pass */ - return output_pass_setup(cinfo); -} - - -/* - * Set up for an output pass, and perform any dummy pass(es) needed. - * Common subroutine for jpeg_start_decompress and jpeg_start_output. - * Entry: global_state = DSTATE_PRESCAN only if previously suspended. - * Exit: If done, returns TRUE and sets global_state for proper output mode. - * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. - */ - -LOCAL(boolean) -output_pass_setup (j_decompress_ptr cinfo) -{ - if (cinfo->global_state != DSTATE_PRESCAN) { - /* First call: do pass setup */ - (*cinfo->master->prepare_for_output_pass) (cinfo); - cinfo->output_scanline = 0; - cinfo->global_state = DSTATE_PRESCAN; - } - /* Loop over any required dummy passes */ - while (cinfo->master->is_dummy_pass) { -#ifdef QUANT_2PASS_SUPPORTED - /* Crank through the dummy pass */ - while (cinfo->output_scanline < cinfo->output_height) { - JDIMENSION last_scanline; - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) cinfo->output_scanline; - cinfo->progress->pass_limit = (long) cinfo->output_height; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - /* Process some data */ - last_scanline = cinfo->output_scanline; - (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, - &cinfo->output_scanline, (JDIMENSION) 0); - if (cinfo->output_scanline == last_scanline) - return FALSE; /* No progress made, must suspend */ - } - /* Finish up dummy pass, and set up for another one */ - (*cinfo->master->finish_output_pass) (cinfo); - (*cinfo->master->prepare_for_output_pass) (cinfo); - cinfo->output_scanline = 0; -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif /* QUANT_2PASS_SUPPORTED */ - } - /* Ready for application to drive output pass through - * jpeg_read_scanlines or jpeg_read_raw_data. - */ - cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; - return TRUE; -} - - -/* - * Read some scanlines of data from the JPEG decompressor. - * - * The return value will be the number of lines actually read. - * This may be less than the number requested in several cases, - * including bottom of image, data source suspension, and operating - * modes that emit multiple scanlines at a time. - * - * Note: we warn about excess calls to jpeg_read_scanlines() since - * this likely signals an application programmer error. However, - * an oversize buffer (max_lines > scanlines remaining) is not an error. - */ - -GLOBAL(JDIMENSION) -jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, - JDIMENSION max_lines) -{ - JDIMENSION row_ctr; - - if (cinfo->global_state != DSTATE_SCANNING) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - if (cinfo->output_scanline >= cinfo->output_height) { - WARNMS(cinfo, JWRN_TOO_MUCH_DATA); - return 0; - } - - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) cinfo->output_scanline; - cinfo->progress->pass_limit = (long) cinfo->output_height; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - - /* Process some data */ - row_ctr = 0; - (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); - cinfo->output_scanline += row_ctr; - return row_ctr; -} - - -/* - * Alternate entry point to read raw data. - * Processes exactly one iMCU row per call, unless suspended. - */ - -GLOBAL(JDIMENSION) -jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, - JDIMENSION max_lines) -{ - JDIMENSION lines_per_iMCU_row; - - if (cinfo->global_state != DSTATE_RAW_OK) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - if (cinfo->output_scanline >= cinfo->output_height) { - WARNMS(cinfo, JWRN_TOO_MUCH_DATA); - return 0; - } - - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) cinfo->output_scanline; - cinfo->progress->pass_limit = (long) cinfo->output_height; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - - /* Verify that at least one iMCU row can be returned. */ - lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size; - if (max_lines < lines_per_iMCU_row) - ERREXIT(cinfo, JERR_BUFFER_SIZE); - - /* Decompress directly into user's buffer. */ - if (! (*cinfo->coef->decompress_data) (cinfo, data)) - return 0; /* suspension forced, can do nothing more */ - - /* OK, we processed one iMCU row. */ - cinfo->output_scanline += lines_per_iMCU_row; - return lines_per_iMCU_row; -} - - -/* Additional entry points for buffered-image mode. */ - -#ifdef D_MULTISCAN_FILES_SUPPORTED - -/* - * Initialize for an output pass in buffered-image mode. - */ - -GLOBAL(boolean) -jpeg_start_output (j_decompress_ptr cinfo, int scan_number) -{ - if (cinfo->global_state != DSTATE_BUFIMAGE && - cinfo->global_state != DSTATE_PRESCAN) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - /* Limit scan number to valid range */ - if (scan_number <= 0) - scan_number = 1; - if (cinfo->inputctl->eoi_reached && - scan_number > cinfo->input_scan_number) - scan_number = cinfo->input_scan_number; - cinfo->output_scan_number = scan_number; - /* Perform any dummy output passes, and set up for the real pass */ - return output_pass_setup(cinfo); -} - - -/* - * Finish up after an output pass in buffered-image mode. - * - * Returns FALSE if suspended. The return value need be inspected only if - * a suspending data source is used. - */ - -GLOBAL(boolean) -jpeg_finish_output (j_decompress_ptr cinfo) -{ - if ((cinfo->global_state == DSTATE_SCANNING || - cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { - /* Terminate this pass. */ - /* We do not require the whole pass to have been completed. */ - (*cinfo->master->finish_output_pass) (cinfo); - cinfo->global_state = DSTATE_BUFPOST; - } else if (cinfo->global_state != DSTATE_BUFPOST) { - /* BUFPOST = repeat call after a suspension, anything else is error */ - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - } - /* Read markers looking for SOS or EOI */ - while (cinfo->input_scan_number <= cinfo->output_scan_number && - ! cinfo->inputctl->eoi_reached) { - if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) - return FALSE; /* Suspend, come back later */ - } - cinfo->global_state = DSTATE_BUFIMAGE; - return TRUE; -} - -#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/libraries/jpeg/jdarith.c b/libraries/jpeg/jdarith.c deleted file mode 100644 index 5533c07397f..00000000000 --- a/libraries/jpeg/jdarith.c +++ /dev/null @@ -1,796 +0,0 @@ -/* - * jdarith.c - * - * Developed 1997-2015 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains portable arithmetic entropy decoding routines for JPEG - * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81). - * - * Both sequential and progressive modes are supported in this single module. - * - * Suspension is not currently supported in this module. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Expanded entropy decoder object for arithmetic decoding. */ - -typedef struct { - struct jpeg_entropy_decoder pub; /* public fields */ - - INT32 c; /* C register, base of coding interval + input bit buffer */ - INT32 a; /* A register, normalized size of coding interval */ - int ct; /* bit shift counter, # of bits left in bit buffer part of C */ - /* init: ct = -16 */ - /* run: ct = 0..7 */ - /* error: ct = -1 */ - int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ - int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */ - - unsigned int restarts_to_go; /* MCUs left in this restart interval */ - - /* Pointers to statistics areas (these workspaces have image lifespan) */ - unsigned char * dc_stats[NUM_ARITH_TBLS]; - unsigned char * ac_stats[NUM_ARITH_TBLS]; - - /* Statistics bin for coding with fixed probability 0.5 */ - unsigned char fixed_bin[4]; -} arith_entropy_decoder; - -typedef arith_entropy_decoder * arith_entropy_ptr; - -/* The following two definitions specify the allocation chunk size - * for the statistics area. - * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least - * 49 statistics bins for DC, and 245 statistics bins for AC coding. - * - * We use a compact representation with 1 byte per statistics bin, - * thus the numbers directly represent byte sizes. - * This 1 byte per statistics bin contains the meaning of the MPS - * (more probable symbol) in the highest bit (mask 0x80), and the - * index into the probability estimation state machine table - * in the lower bits (mask 0x7F). - */ - -#define DC_STAT_BINS 64 -#define AC_STAT_BINS 256 - - -LOCAL(int) -get_byte (j_decompress_ptr cinfo) -/* Read next input byte; we do not support suspension in this module. */ -{ - struct jpeg_source_mgr * src = cinfo->src; - - if (src->bytes_in_buffer == 0) - if (! (*src->fill_input_buffer) (cinfo)) - ERREXIT(cinfo, JERR_CANT_SUSPEND); - src->bytes_in_buffer--; - return GETJOCTET(*src->next_input_byte++); -} - - -/* - * The core arithmetic decoding routine (common in JPEG and JBIG). - * This needs to go as fast as possible. - * Machine-dependent optimization facilities - * are not utilized in this portable implementation. - * However, this code should be fairly efficient and - * may be a good base for further optimizations anyway. - * - * Return value is 0 or 1 (binary decision). - * - * Note: I've changed the handling of the code base & bit - * buffer register C compared to other implementations - * based on the standards layout & procedures. - * While it also contains both the actual base of the - * coding interval (16 bits) and the next-bits buffer, - * the cut-point between these two parts is floating - * (instead of fixed) with the bit shift counter CT. - * Thus, we also need only one (variable instead of - * fixed size) shift for the LPS/MPS decision, and - * we can do away with any renormalization update - * of C (except for new data insertion, of course). - * - * I've also introduced a new scheme for accessing - * the probability estimation state machine table, - * derived from Markus Kuhn's JBIG implementation. - */ - -LOCAL(int) -arith_decode (j_decompress_ptr cinfo, unsigned char *st) -{ - register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy; - register unsigned char nl, nm; - register INT32 qe, temp; - register int sv, data; - - /* Renormalization & data input per section D.2.6 */ - while (e->a < 0x8000L) { - if (--e->ct < 0) { - /* Need to fetch next data byte */ - if (cinfo->unread_marker) - data = 0; /* stuff zero data */ - else { - data = get_byte(cinfo); /* read next input byte */ - if (data == 0xFF) { /* zero stuff or marker code */ - do data = get_byte(cinfo); - while (data == 0xFF); /* swallow extra 0xFF bytes */ - if (data == 0) - data = 0xFF; /* discard stuffed zero byte */ - else { - /* Note: Different from the Huffman decoder, hitting - * a marker while processing the compressed data - * segment is legal in arithmetic coding. - * The convention is to supply zero data - * then until decoding is complete. - */ - cinfo->unread_marker = data; - data = 0; - } - } - } - e->c = (e->c << 8) | data; /* insert data into C register */ - if ((e->ct += 8) < 0) /* update bit shift counter */ - /* Need more initial bytes */ - if (++e->ct == 0) - /* Got 2 initial bytes -> re-init A and exit loop */ - e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */ - } - e->a <<= 1; - } - - /* Fetch values from our compact representation of Table D.3(D.2): - * Qe values and probability estimation state machine - */ - sv = *st; - qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */ - nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */ - nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */ - - /* Decode & estimation procedures per sections D.2.4 & D.2.5 */ - temp = e->a - qe; - e->a = temp; - temp <<= e->ct; - if (e->c >= temp) { - e->c -= temp; - /* Conditional LPS (less probable symbol) exchange */ - if (e->a < qe) { - e->a = qe; - *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ - } else { - e->a = qe; - *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ - sv ^= 0x80; /* Exchange LPS/MPS */ - } - } else if (e->a < 0x8000L) { - /* Conditional MPS (more probable symbol) exchange */ - if (e->a < qe) { - *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ - sv ^= 0x80; /* Exchange LPS/MPS */ - } else { - *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ - } - } - - return sv >> 7; -} - - -/* - * Check for a restart marker & resynchronize decoder. - */ - -LOCAL(void) -process_restart (j_decompress_ptr cinfo) -{ - arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; - int ci; - jpeg_component_info * compptr; - - /* Advance past the RSTn marker */ - if (! (*cinfo->marker->read_restart_marker) (cinfo)) - ERREXIT(cinfo, JERR_CANT_SUSPEND); - - /* Re-initialize statistics areas */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) { - MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS); - /* Reset DC predictions to 0 */ - entropy->last_dc_val[ci] = 0; - entropy->dc_context[ci] = 0; - } - if ((! cinfo->progressive_mode && cinfo->lim_Se) || - (cinfo->progressive_mode && cinfo->Ss)) { - MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS); - } - } - - /* Reset arithmetic decoding variables */ - entropy->c = 0; - entropy->a = 0; - entropy->ct = -16; /* force reading 2 initial bytes to fill C */ - - /* Reset restart counter */ - entropy->restarts_to_go = cinfo->restart_interval; -} - - -/* - * Arithmetic MCU decoding. - * Each of these routines decodes and returns one MCU's worth of - * arithmetic-compressed coefficients. - * The coefficients are reordered from zigzag order into natural array order, - * but are not dequantized. - * - * The i'th block of the MCU is stored into the block pointed to by - * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. - */ - -/* - * MCU decoding for DC initial scan (either spectral selection, - * or first pass of successive approximation). - */ - -METHODDEF(boolean) -decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; - JBLOCKROW block; - unsigned char *st; - int blkn, ci, tbl, sign; - int v, m; - - /* Process restart marker if needed */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - process_restart(cinfo); - entropy->restarts_to_go--; - } - - if (entropy->ct == -1) return TRUE; /* if error do nothing */ - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - block = MCU_data[blkn]; - ci = cinfo->MCU_membership[blkn]; - tbl = cinfo->cur_comp_info[ci]->dc_tbl_no; - - /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */ - - /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ - st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; - - /* Figure F.19: Decode_DC_DIFF */ - if (arith_decode(cinfo, st) == 0) - entropy->dc_context[ci] = 0; - else { - /* Figure F.21: Decoding nonzero value v */ - /* Figure F.22: Decoding the sign of v */ - sign = arith_decode(cinfo, st + 1); - st += 2; st += sign; - /* Figure F.23: Decoding the magnitude category of v */ - if ((m = arith_decode(cinfo, st)) != 0) { - st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ - while (arith_decode(cinfo, st)) { - if ((m <<= 1) == 0x8000) { - WARNMS(cinfo, JWRN_ARITH_BAD_CODE); - entropy->ct = -1; /* magnitude overflow */ - return TRUE; - } - st += 1; - } - } - /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ - if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) - entropy->dc_context[ci] = 0; /* zero diff category */ - else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) - entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */ - else - entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */ - v = m; - /* Figure F.24: Decoding the magnitude bit pattern of v */ - st += 14; - while (m >>= 1) - if (arith_decode(cinfo, st)) v |= m; - v += 1; if (sign) v = -v; - entropy->last_dc_val[ci] += v; - } - - /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */ - (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al); - } - - return TRUE; -} - - -/* - * MCU decoding for AC initial scan (either spectral selection, - * or first pass of successive approximation). - */ - -METHODDEF(boolean) -decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; - JBLOCKROW block; - unsigned char *st; - int tbl, sign, k; - int v, m; - const int * natural_order; - - /* Process restart marker if needed */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - process_restart(cinfo); - entropy->restarts_to_go--; - } - - if (entropy->ct == -1) return TRUE; /* if error do nothing */ - - natural_order = cinfo->natural_order; - - /* There is always only one block per MCU */ - block = MCU_data[0]; - tbl = cinfo->cur_comp_info[0]->ac_tbl_no; - - /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ - - /* Figure F.20: Decode_AC_coefficients */ - k = cinfo->Ss - 1; - do { - st = entropy->ac_stats[tbl] + 3 * k; - if (arith_decode(cinfo, st)) break; /* EOB flag */ - for (;;) { - k++; - if (arith_decode(cinfo, st + 1)) break; - st += 3; - if (k >= cinfo->Se) { - WARNMS(cinfo, JWRN_ARITH_BAD_CODE); - entropy->ct = -1; /* spectral overflow */ - return TRUE; - } - } - /* Figure F.21: Decoding nonzero value v */ - /* Figure F.22: Decoding the sign of v */ - sign = arith_decode(cinfo, entropy->fixed_bin); - st += 2; - /* Figure F.23: Decoding the magnitude category of v */ - if ((m = arith_decode(cinfo, st)) != 0) { - if (arith_decode(cinfo, st)) { - m <<= 1; - st = entropy->ac_stats[tbl] + - (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); - while (arith_decode(cinfo, st)) { - if ((m <<= 1) == 0x8000) { - WARNMS(cinfo, JWRN_ARITH_BAD_CODE); - entropy->ct = -1; /* magnitude overflow */ - return TRUE; - } - st += 1; - } - } - } - v = m; - /* Figure F.24: Decoding the magnitude bit pattern of v */ - st += 14; - while (m >>= 1) - if (arith_decode(cinfo, st)) v |= m; - v += 1; if (sign) v = -v; - /* Scale and output coefficient in natural (dezigzagged) order */ - (*block)[natural_order[k]] = (JCOEF) (v << cinfo->Al); - } while (k < cinfo->Se); - - return TRUE; -} - - -/* - * MCU decoding for DC successive approximation refinement scan. - * Note: we assume such scans can be multi-component, - * although the spec is not very clear on the point. - */ - -METHODDEF(boolean) -decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; - unsigned char *st; - int p1, blkn; - - /* Process restart marker if needed */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - process_restart(cinfo); - entropy->restarts_to_go--; - } - - st = entropy->fixed_bin; /* use fixed probability estimation */ - p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - /* Encoded data is simply the next bit of the two's-complement DC value */ - if (arith_decode(cinfo, st)) - MCU_data[blkn][0][0] |= p1; - } - - return TRUE; -} - - -/* - * MCU decoding for AC successive approximation refinement scan. - */ - -METHODDEF(boolean) -decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; - JBLOCKROW block; - JCOEFPTR thiscoef; - unsigned char *st; - int tbl, k, kex; - int p1, m1; - const int * natural_order; - - /* Process restart marker if needed */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - process_restart(cinfo); - entropy->restarts_to_go--; - } - - if (entropy->ct == -1) return TRUE; /* if error do nothing */ - - natural_order = cinfo->natural_order; - - /* There is always only one block per MCU */ - block = MCU_data[0]; - tbl = cinfo->cur_comp_info[0]->ac_tbl_no; - - p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ - m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ - - /* Establish EOBx (previous stage end-of-block) index */ - kex = cinfo->Se; - do { - if ((*block)[natural_order[kex]]) break; - } while (--kex); - - k = cinfo->Ss - 1; - do { - st = entropy->ac_stats[tbl] + 3 * k; - if (k >= kex) - if (arith_decode(cinfo, st)) break; /* EOB flag */ - for (;;) { - thiscoef = *block + natural_order[++k]; - if (*thiscoef) { /* previously nonzero coef */ - if (arith_decode(cinfo, st + 2)) { - if (*thiscoef < 0) - *thiscoef += m1; - else - *thiscoef += p1; - } - break; - } - if (arith_decode(cinfo, st + 1)) { /* newly nonzero coef */ - if (arith_decode(cinfo, entropy->fixed_bin)) - *thiscoef = m1; - else - *thiscoef = p1; - break; - } - st += 3; - if (k >= cinfo->Se) { - WARNMS(cinfo, JWRN_ARITH_BAD_CODE); - entropy->ct = -1; /* spectral overflow */ - return TRUE; - } - } - } while (k < cinfo->Se); - - return TRUE; -} - - -/* - * Decode one MCU's worth of arithmetic-compressed coefficients. - */ - -METHODDEF(boolean) -decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; - jpeg_component_info * compptr; - JBLOCKROW block; - unsigned char *st; - int blkn, ci, tbl, sign, k; - int v, m; - const int * natural_order; - - /* Process restart marker if needed */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - process_restart(cinfo); - entropy->restarts_to_go--; - } - - if (entropy->ct == -1) return TRUE; /* if error do nothing */ - - natural_order = cinfo->natural_order; - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - block = MCU_data[blkn]; - ci = cinfo->MCU_membership[blkn]; - compptr = cinfo->cur_comp_info[ci]; - - /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */ - - tbl = compptr->dc_tbl_no; - - /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ - st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; - - /* Figure F.19: Decode_DC_DIFF */ - if (arith_decode(cinfo, st) == 0) - entropy->dc_context[ci] = 0; - else { - /* Figure F.21: Decoding nonzero value v */ - /* Figure F.22: Decoding the sign of v */ - sign = arith_decode(cinfo, st + 1); - st += 2; st += sign; - /* Figure F.23: Decoding the magnitude category of v */ - if ((m = arith_decode(cinfo, st)) != 0) { - st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ - while (arith_decode(cinfo, st)) { - if ((m <<= 1) == 0x8000) { - WARNMS(cinfo, JWRN_ARITH_BAD_CODE); - entropy->ct = -1; /* magnitude overflow */ - return TRUE; - } - st += 1; - } - } - /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ - if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) - entropy->dc_context[ci] = 0; /* zero diff category */ - else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) - entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */ - else - entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */ - v = m; - /* Figure F.24: Decoding the magnitude bit pattern of v */ - st += 14; - while (m >>= 1) - if (arith_decode(cinfo, st)) v |= m; - v += 1; if (sign) v = -v; - entropy->last_dc_val[ci] += v; - } - - (*block)[0] = (JCOEF) entropy->last_dc_val[ci]; - - /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ - - if (cinfo->lim_Se == 0) continue; - tbl = compptr->ac_tbl_no; - k = 0; - - /* Figure F.20: Decode_AC_coefficients */ - do { - st = entropy->ac_stats[tbl] + 3 * k; - if (arith_decode(cinfo, st)) break; /* EOB flag */ - for (;;) { - k++; - if (arith_decode(cinfo, st + 1)) break; - st += 3; - if (k >= cinfo->lim_Se) { - WARNMS(cinfo, JWRN_ARITH_BAD_CODE); - entropy->ct = -1; /* spectral overflow */ - return TRUE; - } - } - /* Figure F.21: Decoding nonzero value v */ - /* Figure F.22: Decoding the sign of v */ - sign = arith_decode(cinfo, entropy->fixed_bin); - st += 2; - /* Figure F.23: Decoding the magnitude category of v */ - if ((m = arith_decode(cinfo, st)) != 0) { - if (arith_decode(cinfo, st)) { - m <<= 1; - st = entropy->ac_stats[tbl] + - (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); - while (arith_decode(cinfo, st)) { - if ((m <<= 1) == 0x8000) { - WARNMS(cinfo, JWRN_ARITH_BAD_CODE); - entropy->ct = -1; /* magnitude overflow */ - return TRUE; - } - st += 1; - } - } - } - v = m; - /* Figure F.24: Decoding the magnitude bit pattern of v */ - st += 14; - while (m >>= 1) - if (arith_decode(cinfo, st)) v |= m; - v += 1; if (sign) v = -v; - (*block)[natural_order[k]] = (JCOEF) v; - } while (k < cinfo->lim_Se); - } - - return TRUE; -} - - -/* - * Initialize for an arithmetic-compressed scan. - */ - -METHODDEF(void) -start_pass (j_decompress_ptr cinfo) -{ - arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; - int ci, tbl; - jpeg_component_info * compptr; - - if (cinfo->progressive_mode) { - /* Validate progressive scan parameters */ - if (cinfo->Ss == 0) { - if (cinfo->Se != 0) - goto bad; - } else { - /* need not check Ss/Se < 0 since they came from unsigned bytes */ - if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se) - goto bad; - /* AC scans may have only one component */ - if (cinfo->comps_in_scan != 1) - goto bad; - } - if (cinfo->Ah != 0) { - /* Successive approximation refinement scan: must have Al = Ah-1. */ - if (cinfo->Ah-1 != cinfo->Al) - goto bad; - } - if (cinfo->Al > 13) { /* need not check for < 0 */ - bad: - ERREXIT4(cinfo, JERR_BAD_PROGRESSION, - cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); - } - /* Update progression status, and verify that scan order is legal. - * Note that inter-scan inconsistencies are treated as warnings - * not fatal errors ... not clear if this is right way to behave. - */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - int coefi, cindex = cinfo->cur_comp_info[ci]->component_index; - int *coef_bit_ptr = & cinfo->coef_bits[cindex][0]; - if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ - WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); - for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { - int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; - if (cinfo->Ah != expected) - WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); - coef_bit_ptr[coefi] = cinfo->Al; - } - } - /* Select MCU decoding routine */ - if (cinfo->Ah == 0) { - if (cinfo->Ss == 0) - entropy->pub.decode_mcu = decode_mcu_DC_first; - else - entropy->pub.decode_mcu = decode_mcu_AC_first; - } else { - if (cinfo->Ss == 0) - entropy->pub.decode_mcu = decode_mcu_DC_refine; - else - entropy->pub.decode_mcu = decode_mcu_AC_refine; - } - } else { - /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. - * This ought to be an error condition, but we make it a warning. - */ - if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 || - (cinfo->Se < DCTSIZE2 && cinfo->Se != cinfo->lim_Se)) - WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); - /* Select MCU decoding routine */ - entropy->pub.decode_mcu = decode_mcu; - } - - /* Allocate & initialize requested statistics areas */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) { - tbl = compptr->dc_tbl_no; - if (tbl < 0 || tbl >= NUM_ARITH_TBLS) - ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); - if (entropy->dc_stats[tbl] == NULL) - entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS); - MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS); - /* Initialize DC predictions to 0 */ - entropy->last_dc_val[ci] = 0; - entropy->dc_context[ci] = 0; - } - if ((! cinfo->progressive_mode && cinfo->lim_Se) || - (cinfo->progressive_mode && cinfo->Ss)) { - tbl = compptr->ac_tbl_no; - if (tbl < 0 || tbl >= NUM_ARITH_TBLS) - ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); - if (entropy->ac_stats[tbl] == NULL) - entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS); - MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS); - } - } - - /* Initialize arithmetic decoding variables */ - entropy->c = 0; - entropy->a = 0; - entropy->ct = -16; /* force reading 2 initial bytes to fill C */ - - /* Initialize restart counter */ - entropy->restarts_to_go = cinfo->restart_interval; -} - - -/* - * Finish up at the end of an arithmetic-compressed scan. - */ - -METHODDEF(void) -finish_pass (j_decompress_ptr cinfo) -{ - /* no work necessary here */ -} - - -/* - * Module initialization routine for arithmetic entropy decoding. - */ - -GLOBAL(void) -jinit_arith_decoder (j_decompress_ptr cinfo) -{ - arith_entropy_ptr entropy; - int i; - - entropy = (arith_entropy_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(arith_entropy_decoder)); - cinfo->entropy = &entropy->pub; - entropy->pub.start_pass = start_pass; - entropy->pub.finish_pass = finish_pass; - - /* Mark tables unallocated */ - for (i = 0; i < NUM_ARITH_TBLS; i++) { - entropy->dc_stats[i] = NULL; - entropy->ac_stats[i] = NULL; - } - - /* Initialize index for fixed probability estimation */ - entropy->fixed_bin[0] = 113; - - if (cinfo->progressive_mode) { - /* Create progression status table */ - int *coef_bit_ptr, ci; - cinfo->coef_bits = (int (*)[DCTSIZE2]) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components*DCTSIZE2*SIZEOF(int)); - coef_bit_ptr = & cinfo->coef_bits[0][0]; - for (ci = 0; ci < cinfo->num_components; ci++) - for (i = 0; i < DCTSIZE2; i++) - *coef_bit_ptr++ = -1; - } -} diff --git a/libraries/jpeg/jdatasrc.c b/libraries/jpeg/jdatasrc.c deleted file mode 100644 index 2a27cfed809..00000000000 --- a/libraries/jpeg/jdatasrc.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * jdatasrc.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2009-2015 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains decompression data source routines for the case of - * reading JPEG data from memory or from a file (or any stdio stream). - * While these routines are sufficient for most applications, - * some will want to use a different source manager. - * IMPORTANT: we assume that fread() will correctly transcribe an array of - * JOCTETs from 8-bit-wide elements on external storage. If char is wider - * than 8 bits on your machine, you may need to do some tweaking. - */ - -/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ -#include "jinclude.h" -#include "jpeglib.h" -#include "jerror.h" - - -/* Expanded data source object for stdio input */ - -typedef struct { - struct jpeg_source_mgr pub; /* public fields */ - - FILE * infile; /* source stream */ - JOCTET * buffer; /* start of buffer */ - boolean start_of_file; /* have we gotten any data yet? */ -} my_source_mgr; - -typedef my_source_mgr * my_src_ptr; - -#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ - - -/* - * Initialize source --- called by jpeg_read_header - * before any data is actually read. - */ - -METHODDEF(void) -init_source (j_decompress_ptr cinfo) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - - /* We reset the empty-input-file flag for each image, - * but we don't clear the input buffer. - * This is correct behavior for reading a series of images from one source. - */ - src->start_of_file = TRUE; -} - -METHODDEF(void) -init_mem_source (j_decompress_ptr cinfo) -{ - /* no work necessary here */ -} - - -/* - * Fill the input buffer --- called whenever buffer is emptied. - * - * In typical applications, this should read fresh data into the buffer - * (ignoring the current state of next_input_byte & bytes_in_buffer), - * reset the pointer & count to the start of the buffer, and return TRUE - * indicating that the buffer has been reloaded. It is not necessary to - * fill the buffer entirely, only to obtain at least one more byte. - * - * There is no such thing as an EOF return. If the end of the file has been - * reached, the routine has a choice of ERREXIT() or inserting fake data into - * the buffer. In most cases, generating a warning message and inserting a - * fake EOI marker is the best course of action --- this will allow the - * decompressor to output however much of the image is there. However, - * the resulting error message is misleading if the real problem is an empty - * input file, so we handle that case specially. - * - * In applications that need to be able to suspend compression due to input - * not being available yet, a FALSE return indicates that no more data can be - * obtained right now, but more may be forthcoming later. In this situation, - * the decompressor will return to its caller (with an indication of the - * number of scanlines it has read, if any). The application should resume - * decompression after it has loaded more data into the input buffer. Note - * that there are substantial restrictions on the use of suspension --- see - * the documentation. - * - * When suspending, the decompressor will back up to a convenient restart point - * (typically the start of the current MCU). next_input_byte & bytes_in_buffer - * indicate where the restart point will be if the current call returns FALSE. - * Data beyond this point must be rescanned after resumption, so move it to - * the front of the buffer rather than discarding it. - */ - -METHODDEF(boolean) -fill_input_buffer (j_decompress_ptr cinfo) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - size_t nbytes; - - nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); - - if (nbytes <= 0) { - if (src->start_of_file) /* Treat empty input file as fatal error */ - ERREXIT(cinfo, JERR_INPUT_EMPTY); - WARNMS(cinfo, JWRN_JPEG_EOF); - /* Insert a fake EOI marker */ - src->buffer[0] = (JOCTET) 0xFF; - src->buffer[1] = (JOCTET) JPEG_EOI; - nbytes = 2; - } - - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = nbytes; - src->start_of_file = FALSE; - - return TRUE; -} - -METHODDEF(boolean) -fill_mem_input_buffer (j_decompress_ptr cinfo) -{ - static const JOCTET mybuffer[4] = { - (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0 - }; - - /* The whole JPEG data is expected to reside in the supplied memory - * buffer, so any request for more data beyond the given buffer size - * is treated as an error. - */ - WARNMS(cinfo, JWRN_JPEG_EOF); - - /* Insert a fake EOI marker */ - - cinfo->src->next_input_byte = mybuffer; - cinfo->src->bytes_in_buffer = 2; - - return TRUE; -} - - -/* - * Skip data --- used to skip over a potentially large amount of - * uninteresting data (such as an APPn marker). - * - * Writers of suspendable-input applications must note that skip_input_data - * is not granted the right to give a suspension return. If the skip extends - * beyond the data currently in the buffer, the buffer can be marked empty so - * that the next read will cause a fill_input_buffer call that can suspend. - * Arranging for additional bytes to be discarded before reloading the input - * buffer is the application writer's problem. - */ - -METHODDEF(void) -skip_input_data (j_decompress_ptr cinfo, long num_bytes) -{ - struct jpeg_source_mgr * src = cinfo->src; - - /* Just a dumb implementation for now. Could use fseek() except - * it doesn't work on pipes. Not clear that being smart is worth - * any trouble anyway --- large skips are infrequent. - */ - if (num_bytes > 0) { - while (num_bytes > (long) src->bytes_in_buffer) { - num_bytes -= (long) src->bytes_in_buffer; - (void) (*src->fill_input_buffer) (cinfo); - /* note we assume that fill_input_buffer will never return FALSE, - * so suspension need not be handled. - */ - } - src->next_input_byte += (size_t) num_bytes; - src->bytes_in_buffer -= (size_t) num_bytes; - } -} - - -/* - * An additional method that can be provided by data source modules is the - * resync_to_restart method for error recovery in the presence of RST markers. - * For the moment, this source module just uses the default resync method - * provided by the JPEG library. That method assumes that no backtracking - * is possible. - */ - - -/* - * Terminate source --- called by jpeg_finish_decompress - * after all data has been read. Often a no-op. - * - * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding - * application must deal with any cleanup that should happen even - * for error exit. - */ - -METHODDEF(void) -term_source (j_decompress_ptr cinfo) -{ - /* no work necessary here */ -} - - -/* - * Prepare for input from a stdio stream. - * The caller must have already opened the stream, and is responsible - * for closing it after finishing decompression. - */ - -GLOBAL(void) -jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) -{ - my_src_ptr src; - - /* The source object and input buffer are made permanent so that a series - * of JPEG images can be read from the same file by calling jpeg_stdio_src - * only before the first one. (If we discarded the buffer at the end of - * one image, we'd likely lose the start of the next one.) - * This makes it unsafe to use this manager and a different source - * manager serially with the same JPEG object. Caveat programmer. - */ - if (cinfo->src == NULL) { /* first time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - SIZEOF(my_source_mgr)); - src = (my_src_ptr) cinfo->src; - src->buffer = (JOCTET *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - INPUT_BUF_SIZE * SIZEOF(JOCTET)); - } - - src = (my_src_ptr) cinfo->src; - src->pub.init_source = init_source; - src->pub.fill_input_buffer = fill_input_buffer; - src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->pub.term_source = term_source; - src->infile = infile; - src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->pub.next_input_byte = NULL; /* until buffer loaded */ -} - - -/* - * Prepare for input from a supplied memory buffer. - * The buffer must contain the whole JPEG data. - */ - -GLOBAL(void) -jpeg_mem_src (j_decompress_ptr cinfo, - const unsigned char * inbuffer, unsigned long insize) -{ - struct jpeg_source_mgr * src; - - if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */ - ERREXIT(cinfo, JERR_INPUT_EMPTY); - - /* The source object is made permanent so that a series of JPEG images - * can be read from the same buffer by calling jpeg_mem_src only before - * the first one. - */ - if (cinfo->src == NULL) { /* first time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - SIZEOF(struct jpeg_source_mgr)); - } - - src = cinfo->src; - src->init_source = init_mem_source; - src->fill_input_buffer = fill_mem_input_buffer; - src->skip_input_data = skip_input_data; - src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->term_source = term_source; - src->bytes_in_buffer = (size_t) insize; - src->next_input_byte = (const JOCTET *) inbuffer; -} diff --git a/libraries/jpeg/jdcoefct.c b/libraries/jpeg/jdcoefct.c deleted file mode 100644 index ed02fc378f5..00000000000 --- a/libraries/jpeg/jdcoefct.c +++ /dev/null @@ -1,741 +0,0 @@ -/* - * jdcoefct.c - * - * Copyright (C) 1994-1997, Thomas G. Lane. - * Modified 2002-2011 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the coefficient buffer controller for decompression. - * This controller is the top level of the JPEG decompressor proper. - * The coefficient buffer lies between entropy decoding and inverse-DCT steps. - * - * In buffered-image mode, this controller is the interface between - * input-oriented processing and output-oriented processing. - * Also, the input side (only) is used when reading a file for transcoding. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -/* Block smoothing is only applicable for progressive JPEG, so: */ -#ifndef D_PROGRESSIVE_SUPPORTED -#undef BLOCK_SMOOTHING_SUPPORTED -#endif - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_d_coef_controller pub; /* public fields */ - - /* These variables keep track of the current location of the input side. */ - /* cinfo->input_iMCU_row is also used for this. */ - JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ - int MCU_vert_offset; /* counts MCU rows within iMCU row */ - int MCU_rows_per_iMCU_row; /* number of such rows needed */ - - /* The output side's location is represented by cinfo->output_iMCU_row. */ - - /* In single-pass modes, it's sufficient to buffer just one MCU. - * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, - * and let the entropy decoder write into that workspace each time. - * (On 80x86, the workspace is FAR even though it's not really very big; - * this is to keep the module interfaces unchanged when a large coefficient - * buffer is necessary.) - * In multi-pass modes, this array points to the current MCU's blocks - * within the virtual arrays; it is used only by the input side. - */ - JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; - -#ifdef D_MULTISCAN_FILES_SUPPORTED - /* In multi-pass modes, we need a virtual block array for each component. */ - jvirt_barray_ptr whole_image[MAX_COMPONENTS]; -#endif - -#ifdef BLOCK_SMOOTHING_SUPPORTED - /* When doing block smoothing, we latch coefficient Al values here */ - int * coef_bits_latch; -#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ -#endif -} my_coef_controller; - -typedef my_coef_controller * my_coef_ptr; - -/* Forward declarations */ -METHODDEF(int) decompress_onepass - JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); -#ifdef D_MULTISCAN_FILES_SUPPORTED -METHODDEF(int) decompress_data - JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); -#endif -#ifdef BLOCK_SMOOTHING_SUPPORTED -LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo)); -METHODDEF(int) decompress_smooth_data - JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); -#endif - - -LOCAL(void) -start_iMCU_row (j_decompress_ptr cinfo) -/* Reset within-iMCU-row counters for a new row (input side) */ -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - - /* In an interleaved scan, an MCU row is the same as an iMCU row. - * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. - * But at the bottom of the image, process only what's left. - */ - if (cinfo->comps_in_scan > 1) { - coef->MCU_rows_per_iMCU_row = 1; - } else { - if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; - else - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; - } - - coef->MCU_ctr = 0; - coef->MCU_vert_offset = 0; -} - - -/* - * Initialize for an input processing pass. - */ - -METHODDEF(void) -start_input_pass (j_decompress_ptr cinfo) -{ - cinfo->input_iMCU_row = 0; - start_iMCU_row(cinfo); -} - - -/* - * Initialize for an output processing pass. - */ - -METHODDEF(void) -start_output_pass (j_decompress_ptr cinfo) -{ -#ifdef BLOCK_SMOOTHING_SUPPORTED - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - - /* If multipass, check to see whether to use block smoothing on this pass */ - if (coef->pub.coef_arrays != NULL) { - if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) - coef->pub.decompress_data = decompress_smooth_data; - else - coef->pub.decompress_data = decompress_data; - } -#endif - cinfo->output_iMCU_row = 0; -} - - -/* - * Decompress and return some data in the single-pass case. - * Always attempts to emit one fully interleaved MCU row ("iMCU" row). - * Input and output must run in lockstep since we have only a one-MCU buffer. - * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. - * - * NB: output_buf contains a plane for each component in image, - * which we index according to the component's SOF position. - */ - -METHODDEF(int) -decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - JDIMENSION MCU_col_num; /* index of current MCU within row */ - JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - int blkn, ci, xindex, yindex, yoffset, useful_width; - JSAMPARRAY output_ptr; - JDIMENSION start_col, output_col; - jpeg_component_info *compptr; - inverse_DCT_method_ptr inverse_DCT; - - /* Loop to process as much as one whole iMCU row */ - for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; - yoffset++) { - for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; - MCU_col_num++) { - /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ - if (cinfo->lim_Se) /* can bypass in DC only case */ - FMEMZERO((void FAR *) coef->MCU_buffer[0], - (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK))); - if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { - /* Suspension forced; update state counters and exit */ - coef->MCU_vert_offset = yoffset; - coef->MCU_ctr = MCU_col_num; - return JPEG_SUSPENDED; - } - /* Determine where data should go in output_buf and do the IDCT thing. - * We skip dummy blocks at the right and bottom edges (but blkn gets - * incremented past them!). Note the inner loop relies on having - * allocated the MCU_buffer[] blocks sequentially. - */ - blkn = 0; /* index of current DCT block within MCU */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Don't bother to IDCT an uninteresting component. */ - if (! compptr->component_needed) { - blkn += compptr->MCU_blocks; - continue; - } - inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index]; - useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width - : compptr->last_col_width; - output_ptr = output_buf[compptr->component_index] + - yoffset * compptr->DCT_v_scaled_size; - start_col = MCU_col_num * compptr->MCU_sample_width; - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - if (cinfo->input_iMCU_row < last_iMCU_row || - yoffset+yindex < compptr->last_row_height) { - output_col = start_col; - for (xindex = 0; xindex < useful_width; xindex++) { - (*inverse_DCT) (cinfo, compptr, - (JCOEFPTR) coef->MCU_buffer[blkn+xindex], - output_ptr, output_col); - output_col += compptr->DCT_h_scaled_size; - } - } - blkn += compptr->MCU_width; - output_ptr += compptr->DCT_v_scaled_size; - } - } - } - /* Completed an MCU row, but perhaps not an iMCU row */ - coef->MCU_ctr = 0; - } - /* Completed the iMCU row, advance counters for next one */ - cinfo->output_iMCU_row++; - if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { - start_iMCU_row(cinfo); - return JPEG_ROW_COMPLETED; - } - /* Completed the scan */ - (*cinfo->inputctl->finish_input_pass) (cinfo); - return JPEG_SCAN_COMPLETED; -} - - -/* - * Dummy consume-input routine for single-pass operation. - */ - -METHODDEF(int) -dummy_consume_data (j_decompress_ptr cinfo) -{ - return JPEG_SUSPENDED; /* Always indicate nothing was done */ -} - - -#ifdef D_MULTISCAN_FILES_SUPPORTED - -/* - * Consume input data and store it in the full-image coefficient buffer. - * We read as much as one fully interleaved MCU row ("iMCU" row) per call, - * ie, v_samp_factor block rows for each component in the scan. - * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. - */ - -METHODDEF(int) -consume_data (j_decompress_ptr cinfo) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - JDIMENSION MCU_col_num; /* index of current MCU within row */ - int blkn, ci, xindex, yindex, yoffset; - JDIMENSION start_col; - JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; - JBLOCKROW buffer_ptr; - jpeg_component_info *compptr; - - /* Align the virtual buffers for the components used in this scan. */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - buffer[ci] = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], - cinfo->input_iMCU_row * compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, TRUE); - /* Note: entropy decoder expects buffer to be zeroed, - * but this is handled automatically by the memory manager - * because we requested a pre-zeroed array. - */ - } - - /* Loop to process one whole iMCU row */ - for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; - yoffset++) { - for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; - MCU_col_num++) { - /* Construct list of pointers to DCT blocks belonging to this MCU */ - blkn = 0; /* index of current DCT block within MCU */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - start_col = MCU_col_num * compptr->MCU_width; - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - buffer_ptr = buffer[ci][yindex+yoffset] + start_col; - for (xindex = 0; xindex < compptr->MCU_width; xindex++) { - coef->MCU_buffer[blkn++] = buffer_ptr++; - } - } - } - /* Try to fetch the MCU. */ - if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { - /* Suspension forced; update state counters and exit */ - coef->MCU_vert_offset = yoffset; - coef->MCU_ctr = MCU_col_num; - return JPEG_SUSPENDED; - } - } - /* Completed an MCU row, but perhaps not an iMCU row */ - coef->MCU_ctr = 0; - } - /* Completed the iMCU row, advance counters for next one */ - if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { - start_iMCU_row(cinfo); - return JPEG_ROW_COMPLETED; - } - /* Completed the scan */ - (*cinfo->inputctl->finish_input_pass) (cinfo); - return JPEG_SCAN_COMPLETED; -} - - -/* - * Decompress and return some data in the multi-pass case. - * Always attempts to emit one fully interleaved MCU row ("iMCU" row). - * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. - * - * NB: output_buf contains a plane for each component in image. - */ - -METHODDEF(int) -decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - JDIMENSION block_num; - int ci, block_row, block_rows; - JBLOCKARRAY buffer; - JBLOCKROW buffer_ptr; - JSAMPARRAY output_ptr; - JDIMENSION output_col; - jpeg_component_info *compptr; - inverse_DCT_method_ptr inverse_DCT; - - /* Force some input to be done if we are getting ahead of the input. */ - while (cinfo->input_scan_number < cinfo->output_scan_number || - (cinfo->input_scan_number == cinfo->output_scan_number && - cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { - if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) - return JPEG_SUSPENDED; - } - - /* OK, output from the virtual arrays. */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Don't bother to IDCT an uninteresting component. */ - if (! compptr->component_needed) - continue; - /* Align the virtual buffer for this component. */ - buffer = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[ci], - cinfo->output_iMCU_row * compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, FALSE); - /* Count non-dummy DCT block rows in this iMCU row. */ - if (cinfo->output_iMCU_row < last_iMCU_row) - block_rows = compptr->v_samp_factor; - else { - /* NB: can't use last_row_height here; it is input-side-dependent! */ - block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); - if (block_rows == 0) block_rows = compptr->v_samp_factor; - } - inverse_DCT = cinfo->idct->inverse_DCT[ci]; - output_ptr = output_buf[ci]; - /* Loop over all DCT blocks to be processed. */ - for (block_row = 0; block_row < block_rows; block_row++) { - buffer_ptr = buffer[block_row]; - output_col = 0; - for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { - (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, - output_ptr, output_col); - buffer_ptr++; - output_col += compptr->DCT_h_scaled_size; - } - output_ptr += compptr->DCT_v_scaled_size; - } - } - - if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) - return JPEG_ROW_COMPLETED; - return JPEG_SCAN_COMPLETED; -} - -#endif /* D_MULTISCAN_FILES_SUPPORTED */ - - -#ifdef BLOCK_SMOOTHING_SUPPORTED - -/* - * This code applies interblock smoothing as described by section K.8 - * of the JPEG standard: the first 5 AC coefficients are estimated from - * the DC values of a DCT block and its 8 neighboring blocks. - * We apply smoothing only for progressive JPEG decoding, and only if - * the coefficients it can estimate are not yet known to full precision. - */ - -/* Natural-order array positions of the first 5 zigzag-order coefficients */ -#define Q01_POS 1 -#define Q10_POS 8 -#define Q20_POS 16 -#define Q11_POS 9 -#define Q02_POS 2 - -/* - * Determine whether block smoothing is applicable and safe. - * We also latch the current states of the coef_bits[] entries for the - * AC coefficients; otherwise, if the input side of the decompressor - * advances into a new scan, we might think the coefficients are known - * more accurately than they really are. - */ - -LOCAL(boolean) -smoothing_ok (j_decompress_ptr cinfo) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - boolean smoothing_useful = FALSE; - int ci, coefi; - jpeg_component_info *compptr; - JQUANT_TBL * qtable; - int * coef_bits; - int * coef_bits_latch; - - if (! cinfo->progressive_mode || cinfo->coef_bits == NULL) - return FALSE; - - /* Allocate latch area if not already done */ - if (coef->coef_bits_latch == NULL) - coef->coef_bits_latch = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components * - (SAVED_COEFS * SIZEOF(int))); - coef_bits_latch = coef->coef_bits_latch; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* All components' quantization values must already be latched. */ - if ((qtable = compptr->quant_table) == NULL) - return FALSE; - /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ - if (qtable->quantval[0] == 0 || - qtable->quantval[Q01_POS] == 0 || - qtable->quantval[Q10_POS] == 0 || - qtable->quantval[Q20_POS] == 0 || - qtable->quantval[Q11_POS] == 0 || - qtable->quantval[Q02_POS] == 0) - return FALSE; - /* DC values must be at least partly known for all components. */ - coef_bits = cinfo->coef_bits[ci]; - if (coef_bits[0] < 0) - return FALSE; - /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ - for (coefi = 1; coefi <= 5; coefi++) { - coef_bits_latch[coefi] = coef_bits[coefi]; - if (coef_bits[coefi] != 0) - smoothing_useful = TRUE; - } - coef_bits_latch += SAVED_COEFS; - } - - return smoothing_useful; -} - - -/* - * Variant of decompress_data for use when doing block smoothing. - */ - -METHODDEF(int) -decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - JDIMENSION block_num, last_block_column; - int ci, block_row, block_rows, access_rows; - JBLOCKARRAY buffer; - JBLOCKROW buffer_ptr, prev_block_row, next_block_row; - JSAMPARRAY output_ptr; - JDIMENSION output_col; - jpeg_component_info *compptr; - inverse_DCT_method_ptr inverse_DCT; - boolean first_row, last_row; - JBLOCK workspace; - int *coef_bits; - JQUANT_TBL *quanttbl; - INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; - int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; - int Al, pred; - - /* Force some input to be done if we are getting ahead of the input. */ - while (cinfo->input_scan_number <= cinfo->output_scan_number && - ! cinfo->inputctl->eoi_reached) { - if (cinfo->input_scan_number == cinfo->output_scan_number) { - /* If input is working on current scan, we ordinarily want it to - * have completed the current row. But if input scan is DC, - * we want it to keep one row ahead so that next block row's DC - * values are up to date. - */ - JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; - if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) - break; - } - if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) - return JPEG_SUSPENDED; - } - - /* OK, output from the virtual arrays. */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Don't bother to IDCT an uninteresting component. */ - if (! compptr->component_needed) - continue; - /* Count non-dummy DCT block rows in this iMCU row. */ - if (cinfo->output_iMCU_row < last_iMCU_row) { - block_rows = compptr->v_samp_factor; - access_rows = block_rows * 2; /* this and next iMCU row */ - last_row = FALSE; - } else { - /* NB: can't use last_row_height here; it is input-side-dependent! */ - block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); - if (block_rows == 0) block_rows = compptr->v_samp_factor; - access_rows = block_rows; /* this iMCU row only */ - last_row = TRUE; - } - /* Align the virtual buffer for this component. */ - if (cinfo->output_iMCU_row > 0) { - access_rows += compptr->v_samp_factor; /* prior iMCU row too */ - buffer = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[ci], - (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, - (JDIMENSION) access_rows, FALSE); - buffer += compptr->v_samp_factor; /* point to current iMCU row */ - first_row = FALSE; - } else { - buffer = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[ci], - (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); - first_row = TRUE; - } - /* Fetch component-dependent info */ - coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); - quanttbl = compptr->quant_table; - Q00 = quanttbl->quantval[0]; - Q01 = quanttbl->quantval[Q01_POS]; - Q10 = quanttbl->quantval[Q10_POS]; - Q20 = quanttbl->quantval[Q20_POS]; - Q11 = quanttbl->quantval[Q11_POS]; - Q02 = quanttbl->quantval[Q02_POS]; - inverse_DCT = cinfo->idct->inverse_DCT[ci]; - output_ptr = output_buf[ci]; - /* Loop over all DCT blocks to be processed. */ - for (block_row = 0; block_row < block_rows; block_row++) { - buffer_ptr = buffer[block_row]; - if (first_row && block_row == 0) - prev_block_row = buffer_ptr; - else - prev_block_row = buffer[block_row-1]; - if (last_row && block_row == block_rows-1) - next_block_row = buffer_ptr; - else - next_block_row = buffer[block_row+1]; - /* We fetch the surrounding DC values using a sliding-register approach. - * Initialize all nine here so as to do the right thing on narrow pics. - */ - DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; - DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; - DC7 = DC8 = DC9 = (int) next_block_row[0][0]; - output_col = 0; - last_block_column = compptr->width_in_blocks - 1; - for (block_num = 0; block_num <= last_block_column; block_num++) { - /* Fetch current DCT block into workspace so we can modify it. */ - jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); - /* Update DC values */ - if (block_num < last_block_column) { - DC3 = (int) prev_block_row[1][0]; - DC6 = (int) buffer_ptr[1][0]; - DC9 = (int) next_block_row[1][0]; - } - /* Compute coefficient estimates per K.8. - * An estimate is applied only if coefficient is still zero, - * and is not known to be fully accurate. - */ - /* AC01 */ - if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { - num = 36 * Q00 * (DC4 - DC6); - if (num >= 0) { - pred = (int) (((Q01<<7) + num) / (Q01<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { - pred = (int) (((Q10<<7) + num) / (Q10<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { - pred = (int) (((Q20<<7) + num) / (Q20<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { - pred = (int) (((Q11<<7) + num) / (Q11<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { - pred = (int) (((Q02<<7) + num) / (Q02<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_h_scaled_size; - } - output_ptr += compptr->DCT_v_scaled_size; - } - } - - if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) - return JPEG_ROW_COMPLETED; - return JPEG_SCAN_COMPLETED; -} - -#endif /* BLOCK_SMOOTHING_SUPPORTED */ - - -/* - * Initialize coefficient buffer controller. - */ - -GLOBAL(void) -jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) -{ - my_coef_ptr coef; - - coef = (my_coef_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_coef_controller)); - cinfo->coef = (struct jpeg_d_coef_controller *) coef; - coef->pub.start_input_pass = start_input_pass; - coef->pub.start_output_pass = start_output_pass; -#ifdef BLOCK_SMOOTHING_SUPPORTED - coef->coef_bits_latch = NULL; -#endif - - /* Create the coefficient buffer. */ - if (need_full_buffer) { -#ifdef D_MULTISCAN_FILES_SUPPORTED - /* Allocate a full-image virtual array for each component, */ - /* padded to a multiple of samp_factor DCT blocks in each direction. */ - /* Note we ask for a pre-zeroed array. */ - int ci, access_rows; - jpeg_component_info *compptr; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - access_rows = compptr->v_samp_factor; -#ifdef BLOCK_SMOOTHING_SUPPORTED - /* If block smoothing could be used, need a bigger window */ - if (cinfo->progressive_mode) - access_rows *= 3; -#endif - coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, - (JDIMENSION) jround_up((long) compptr->width_in_blocks, - (long) compptr->h_samp_factor), - (JDIMENSION) jround_up((long) compptr->height_in_blocks, - (long) compptr->v_samp_factor), - (JDIMENSION) access_rows); - } - coef->pub.consume_data = consume_data; - coef->pub.decompress_data = decompress_data; - coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else { - /* We only need a single-MCU buffer. */ - JBLOCKROW buffer; - int i; - - buffer = (JBLOCKROW) - (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); - for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { - coef->MCU_buffer[i] = buffer + i; - } - if (cinfo->lim_Se == 0) /* DC only case: want to bypass later */ - FMEMZERO((void FAR *) buffer, - (size_t) (D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK))); - coef->pub.consume_data = dummy_consume_data; - coef->pub.decompress_data = decompress_onepass; - coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ - } -} diff --git a/libraries/jpeg/jdcolor.c b/libraries/jpeg/jdcolor.c deleted file mode 100644 index 0316354dace..00000000000 --- a/libraries/jpeg/jdcolor.c +++ /dev/null @@ -1,731 +0,0 @@ -/* - * jdcolor.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 2011-2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains output colorspace conversion routines. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -#if RANGE_BITS < 2 - /* Deliberate syntax err */ - Sorry, this code requires 2 or more range extension bits. -#endif - - -/* Private subobject */ - -typedef struct { - struct jpeg_color_deconverter pub; /* public fields */ - - /* Private state for YCbCr->RGB and BG_YCC->RGB conversion */ - int * Cr_r_tab; /* => table for Cr to R conversion */ - int * Cb_b_tab; /* => table for Cb to B conversion */ - INT32 * Cr_g_tab; /* => table for Cr to G conversion */ - INT32 * Cb_g_tab; /* => table for Cb to G conversion */ - - /* Private state for RGB->Y conversion */ - INT32 * rgb_y_tab; /* => table for RGB to Y conversion */ -} my_color_deconverter; - -typedef my_color_deconverter * my_cconvert_ptr; - - -/*************** YCbCr -> RGB conversion: most common case **************/ -/*************** BG_YCC -> RGB conversion: less common case **************/ -/*************** RGB -> Y conversion: less common case **************/ - -/* - * YCbCr is defined per Recommendation ITU-R BT.601-7 (03/2011), - * previously known as Recommendation CCIR 601-1, except that Cb and Cr - * are normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. - * sRGB (standard RGB color space) is defined per IEC 61966-2-1:1999. - * sYCC (standard luma-chroma-chroma color space with extended gamut) - * is defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex F. - * bg-sRGB and bg-sYCC (big gamut standard color spaces) - * are defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex G. - * Note that the derived conversion coefficients given in some of these - * documents are imprecise. The general conversion equations are - * - * R = Y + K * (1 - Kr) * Cr - * G = Y - K * (Kb * (1 - Kb) * Cb + Kr * (1 - Kr) * Cr) / (1 - Kr - Kb) - * B = Y + K * (1 - Kb) * Cb - * - * Y = Kr * R + (1 - Kr - Kb) * G + Kb * B - * - * With Kr = 0.299 and Kb = 0.114 (derived according to SMPTE RP 177-1993 - * from the 1953 FCC NTSC primaries and CIE Illuminant C), K = 2 for sYCC, - * the conversion equations to be implemented are therefore - * - * R = Y + 1.402 * Cr - * G = Y - 0.344136286 * Cb - 0.714136286 * Cr - * B = Y + 1.772 * Cb - * - * Y = 0.299 * R + 0.587 * G + 0.114 * B - * - * where Cb and Cr represent the incoming values less CENTERJSAMPLE. - * For bg-sYCC, with K = 4, the equations are - * - * R = Y + 2.804 * Cr - * G = Y - 0.688272572 * Cb - 1.428272572 * Cr - * B = Y + 3.544 * Cb - * - * To avoid floating-point arithmetic, we represent the fractional constants - * as integers scaled up by 2^16 (about 4 digits precision); we have to divide - * the products by 2^16, with appropriate rounding, to get the correct answer. - * Notice that Y, being an integral input, does not contribute any fraction - * so it need not participate in the rounding. - * - * For even more speed, we avoid doing any multiplications in the inner loop - * by precalculating the constants times Cb and Cr for all possible values. - * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); - * for 9-bit to 12-bit samples it is still acceptable. It's not very - * reasonable for 16-bit samples, but if you want lossless storage you - * shouldn't be changing colorspace anyway. - * The Cr=>R and Cb=>B values can be rounded to integers in advance; the - * values for the G calculation are left scaled up, since we must add them - * together before rounding. - */ - -#define SCALEBITS 16 /* speediest right-shift on some machines */ -#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) -#define FIX(x) ((INT32) ((x) * (1L<Y conversion and divide it up into - * three parts, instead of doing three alloc_small requests. This lets us - * use a single table base address, which can be held in a register in the - * inner loops on many machines (more than can hold all three addresses, - * anyway). - */ - -#define R_Y_OFF 0 /* offset to R => Y section */ -#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ -#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ -#define TABLE_SIZE (3*(MAXJSAMPLE+1)) - - -/* - * Initialize tables for YCbCr->RGB and BG_YCC->RGB colorspace conversion. - */ - -LOCAL(void) -build_ycc_rgb_table (j_decompress_ptr cinfo) -/* Normal case, sYCC */ -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - int i; - INT32 x; - SHIFT_TEMPS - - cconvert->Cr_r_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - cconvert->Cb_b_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - cconvert->Cr_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - cconvert->Cb_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - - for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { - /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ - /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ - /* Cr=>R value is nearest int to 1.402 * x */ - cconvert->Cr_r_tab[i] = (int) - RIGHT_SHIFT(FIX(1.402) * x + ONE_HALF, SCALEBITS); - /* Cb=>B value is nearest int to 1.772 * x */ - cconvert->Cb_b_tab[i] = (int) - RIGHT_SHIFT(FIX(1.772) * x + ONE_HALF, SCALEBITS); - /* Cr=>G value is scaled-up -0.714136286 * x */ - cconvert->Cr_g_tab[i] = (- FIX(0.714136286)) * x; - /* Cb=>G value is scaled-up -0.344136286 * x */ - /* We also add in ONE_HALF so that need not do it in inner loop */ - cconvert->Cb_g_tab[i] = (- FIX(0.344136286)) * x + ONE_HALF; - } -} - - -LOCAL(void) -build_bg_ycc_rgb_table (j_decompress_ptr cinfo) -/* Wide gamut case, bg-sYCC */ -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - int i; - INT32 x; - SHIFT_TEMPS - - cconvert->Cr_r_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - cconvert->Cb_b_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - cconvert->Cr_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - cconvert->Cb_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - - for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { - /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ - /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ - /* Cr=>R value is nearest int to 2.804 * x */ - cconvert->Cr_r_tab[i] = (int) - RIGHT_SHIFT(FIX(2.804) * x + ONE_HALF, SCALEBITS); - /* Cb=>B value is nearest int to 3.544 * x */ - cconvert->Cb_b_tab[i] = (int) - RIGHT_SHIFT(FIX(3.544) * x + ONE_HALF, SCALEBITS); - /* Cr=>G value is scaled-up -1.428272572 * x */ - cconvert->Cr_g_tab[i] = (- FIX(1.428272572)) * x; - /* Cb=>G value is scaled-up -0.688272572 * x */ - /* We also add in ONE_HALF so that need not do it in inner loop */ - cconvert->Cb_g_tab[i] = (- FIX(0.688272572)) * x + ONE_HALF; - } -} - - -/* - * Convert some rows of samples to the output colorspace. - * - * Note that we change from noninterleaved, one-plane-per-component format - * to interleaved-pixel format. The output buffer is therefore three times - * as wide as the input buffer. - * A starting row offset is provided only for the input buffer. The caller - * can easily adjust the passed output_buf value to accommodate any row - * offset required on that side. - */ - -METHODDEF(void) -ycc_rgb_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - register int y, cb, cr; - register JSAMPROW outptr; - register JSAMPROW inptr0, inptr1, inptr2; - register JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - /* copy these pointers into registers if possible */ - register JSAMPLE * range_limit = cinfo->sample_range_limit; - register int * Crrtab = cconvert->Cr_r_tab; - register int * Cbbtab = cconvert->Cb_b_tab; - register INT32 * Crgtab = cconvert->Cr_g_tab; - register INT32 * Cbgtab = cconvert->Cb_g_tab; - SHIFT_TEMPS - - while (--num_rows >= 0) { - inptr0 = input_buf[0][input_row]; - inptr1 = input_buf[1][input_row]; - inptr2 = input_buf[2][input_row]; - input_row++; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - y = GETJSAMPLE(inptr0[col]); - cb = GETJSAMPLE(inptr1[col]); - cr = GETJSAMPLE(inptr2[col]); - /* Range-limiting is essential due to noise introduced by DCT losses, - * for extended gamut (sYCC) and wide gamut (bg-sYCC) encodings. - */ - outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; - outptr[RGB_GREEN] = range_limit[y + - ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], - SCALEBITS))]; - outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; - outptr += RGB_PIXELSIZE; - } - } -} - - -/**************** Cases other than YCC -> RGB ****************/ - - -/* - * Initialize for RGB->grayscale colorspace conversion. - */ - -LOCAL(void) -build_rgb_y_table (j_decompress_ptr cinfo) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - INT32 * rgb_y_tab; - INT32 i; - - /* Allocate and fill in the conversion tables. */ - cconvert->rgb_y_tab = rgb_y_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (TABLE_SIZE * SIZEOF(INT32))); - - for (i = 0; i <= MAXJSAMPLE; i++) { - rgb_y_tab[i+R_Y_OFF] = FIX(0.299) * i; - rgb_y_tab[i+G_Y_OFF] = FIX(0.587) * i; - rgb_y_tab[i+B_Y_OFF] = FIX(0.114) * i + ONE_HALF; - } -} - - -/* - * Convert RGB to grayscale. - */ - -METHODDEF(void) -rgb_gray_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - register INT32 * ctab = cconvert->rgb_y_tab; - register int r, g, b; - register JSAMPROW outptr; - register JSAMPROW inptr0, inptr1, inptr2; - register JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - - while (--num_rows >= 0) { - inptr0 = input_buf[0][input_row]; - inptr1 = input_buf[1][input_row]; - inptr2 = input_buf[2][input_row]; - input_row++; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - r = GETJSAMPLE(inptr0[col]); - g = GETJSAMPLE(inptr1[col]); - b = GETJSAMPLE(inptr2[col]); - /* Y */ - outptr[col] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); - } - } -} - - -/* - * [R-G,G,B-G] to [R,G,B] conversion with modulo calculation - * (inverse color transform). - * This can be seen as an adaption of the general YCbCr->RGB - * conversion equation with Kr = Kb = 0, while replacing the - * normalization by modulo calculation. - */ - -METHODDEF(void) -rgb1_rgb_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - register int r, g, b; - register JSAMPROW outptr; - register JSAMPROW inptr0, inptr1, inptr2; - register JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - - while (--num_rows >= 0) { - inptr0 = input_buf[0][input_row]; - inptr1 = input_buf[1][input_row]; - inptr2 = input_buf[2][input_row]; - input_row++; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - r = GETJSAMPLE(inptr0[col]); - g = GETJSAMPLE(inptr1[col]); - b = GETJSAMPLE(inptr2[col]); - /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD - * (modulo) operator is equivalent to the bitmask operator AND. - */ - outptr[RGB_RED] = (JSAMPLE) ((r + g - CENTERJSAMPLE) & MAXJSAMPLE); - outptr[RGB_GREEN] = (JSAMPLE) g; - outptr[RGB_BLUE] = (JSAMPLE) ((b + g - CENTERJSAMPLE) & MAXJSAMPLE); - outptr += RGB_PIXELSIZE; - } - } -} - - -/* - * [R-G,G,B-G] to grayscale conversion with modulo calculation - * (inverse color transform). - */ - -METHODDEF(void) -rgb1_gray_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - register INT32 * ctab = cconvert->rgb_y_tab; - register int r, g, b; - register JSAMPROW outptr; - register JSAMPROW inptr0, inptr1, inptr2; - register JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - - while (--num_rows >= 0) { - inptr0 = input_buf[0][input_row]; - inptr1 = input_buf[1][input_row]; - inptr2 = input_buf[2][input_row]; - input_row++; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - r = GETJSAMPLE(inptr0[col]); - g = GETJSAMPLE(inptr1[col]); - b = GETJSAMPLE(inptr2[col]); - /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD - * (modulo) operator is equivalent to the bitmask operator AND. - */ - r = (r + g - CENTERJSAMPLE) & MAXJSAMPLE; - b = (b + g - CENTERJSAMPLE) & MAXJSAMPLE; - /* Y */ - outptr[col] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); - } - } -} - - -/* - * No colorspace change, but conversion from separate-planes - * to interleaved representation. - */ - -METHODDEF(void) -rgb_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - register JSAMPROW outptr; - register JSAMPROW inptr0, inptr1, inptr2; - register JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - - while (--num_rows >= 0) { - inptr0 = input_buf[0][input_row]; - inptr1 = input_buf[1][input_row]; - inptr2 = input_buf[2][input_row]; - input_row++; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - /* We can dispense with GETJSAMPLE() here */ - outptr[RGB_RED] = inptr0[col]; - outptr[RGB_GREEN] = inptr1[col]; - outptr[RGB_BLUE] = inptr2[col]; - outptr += RGB_PIXELSIZE; - } - } -} - - -/* - * Color conversion for no colorspace change: just copy the data, - * converting from separate-planes to interleaved representation. - */ - -METHODDEF(void) -null_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - int ci; - register int nc = cinfo->num_components; - register JSAMPROW outptr; - register JSAMPROW inptr; - register JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - - while (--num_rows >= 0) { - for (ci = 0; ci < nc; ci++) { - inptr = input_buf[ci][input_row]; - outptr = output_buf[0] + ci; - for (col = 0; col < num_cols; col++) { - *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ - outptr += nc; - } - } - input_row++; - output_buf++; - } -} - - -/* - * Color conversion for grayscale: just copy the data. - * This also works for YCC -> grayscale conversion, in which - * we just copy the Y (luminance) component and ignore chrominance. - */ - -METHODDEF(void) -grayscale_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, - num_rows, cinfo->output_width); -} - - -/* - * Convert grayscale to RGB: just duplicate the graylevel three times. - * This is provided to support applications that don't want to cope - * with grayscale as a separate case. - */ - -METHODDEF(void) -gray_rgb_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - register JSAMPROW outptr; - register JSAMPROW inptr; - register JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - - while (--num_rows >= 0) { - inptr = input_buf[0][input_row++]; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - /* We can dispense with GETJSAMPLE() here */ - outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col]; - outptr += RGB_PIXELSIZE; - } - } -} - - -/* - * Adobe-style YCCK->CMYK conversion. - * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same - * conversion as above, while passing K (black) unchanged. - * We assume build_ycc_rgb_table has been called. - */ - -METHODDEF(void) -ycck_cmyk_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - register int y, cb, cr; - register JSAMPROW outptr; - register JSAMPROW inptr0, inptr1, inptr2, inptr3; - register JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - /* copy these pointers into registers if possible */ - register JSAMPLE * range_limit = cinfo->sample_range_limit; - register int * Crrtab = cconvert->Cr_r_tab; - register int * Cbbtab = cconvert->Cb_b_tab; - register INT32 * Crgtab = cconvert->Cr_g_tab; - register INT32 * Cbgtab = cconvert->Cb_g_tab; - SHIFT_TEMPS - - while (--num_rows >= 0) { - inptr0 = input_buf[0][input_row]; - inptr1 = input_buf[1][input_row]; - inptr2 = input_buf[2][input_row]; - inptr3 = input_buf[3][input_row]; - input_row++; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - y = GETJSAMPLE(inptr0[col]); - cb = GETJSAMPLE(inptr1[col]); - cr = GETJSAMPLE(inptr2[col]); - /* Range-limiting is essential due to noise introduced by DCT losses, - * and for extended gamut encodings (sYCC). - */ - outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ - outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ - ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], - SCALEBITS)))]; - outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ - /* K passes through unchanged */ - outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ - outptr += 4; - } - } -} - - -/* - * Empty method for start_pass. - */ - -METHODDEF(void) -start_pass_dcolor (j_decompress_ptr cinfo) -{ - /* no work needed */ -} - - -/* - * Module initialization routine for output colorspace conversion. - */ - -GLOBAL(void) -jinit_color_deconverter (j_decompress_ptr cinfo) -{ - my_cconvert_ptr cconvert; - int ci; - - cconvert = (my_cconvert_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_color_deconverter)); - cinfo->cconvert = &cconvert->pub; - cconvert->pub.start_pass = start_pass_dcolor; - - /* Make sure num_components agrees with jpeg_color_space */ - switch (cinfo->jpeg_color_space) { - case JCS_GRAYSCALE: - if (cinfo->num_components != 1) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - break; - - case JCS_RGB: - case JCS_YCbCr: - case JCS_BG_RGB: - case JCS_BG_YCC: - if (cinfo->num_components != 3) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - break; - - case JCS_CMYK: - case JCS_YCCK: - if (cinfo->num_components != 4) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - break; - - default: /* JCS_UNKNOWN can be anything */ - if (cinfo->num_components < 1) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - break; - } - - /* Support color transform only for RGB colorspaces */ - if (cinfo->color_transform && - cinfo->jpeg_color_space != JCS_RGB && - cinfo->jpeg_color_space != JCS_BG_RGB) - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - - /* Set out_color_components and conversion method based on requested space. - * Also clear the component_needed flags for any unused components, - * so that earlier pipeline stages can avoid useless computation. - */ - - switch (cinfo->out_color_space) { - case JCS_GRAYSCALE: - cinfo->out_color_components = 1; - switch (cinfo->jpeg_color_space) { - case JCS_GRAYSCALE: - case JCS_YCbCr: - case JCS_BG_YCC: - cconvert->pub.color_convert = grayscale_convert; - /* For color->grayscale conversion, only the Y (0) component is needed */ - for (ci = 1; ci < cinfo->num_components; ci++) - cinfo->comp_info[ci].component_needed = FALSE; - break; - case JCS_RGB: - switch (cinfo->color_transform) { - case JCT_NONE: - cconvert->pub.color_convert = rgb_gray_convert; - break; - case JCT_SUBTRACT_GREEN: - cconvert->pub.color_convert = rgb1_gray_convert; - break; - default: - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - } - build_rgb_y_table(cinfo); - break; - default: - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - } - break; - - case JCS_RGB: - cinfo->out_color_components = RGB_PIXELSIZE; - switch (cinfo->jpeg_color_space) { - case JCS_GRAYSCALE: - cconvert->pub.color_convert = gray_rgb_convert; - break; - case JCS_YCbCr: - cconvert->pub.color_convert = ycc_rgb_convert; - build_ycc_rgb_table(cinfo); - break; - case JCS_BG_YCC: - cconvert->pub.color_convert = ycc_rgb_convert; - build_bg_ycc_rgb_table(cinfo); - break; - case JCS_RGB: - switch (cinfo->color_transform) { - case JCT_NONE: - cconvert->pub.color_convert = rgb_convert; - break; - case JCT_SUBTRACT_GREEN: - cconvert->pub.color_convert = rgb1_rgb_convert; - break; - default: - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - } - break; - default: - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - } - break; - - case JCS_BG_RGB: - cinfo->out_color_components = RGB_PIXELSIZE; - if (cinfo->jpeg_color_space == JCS_BG_RGB) { - switch (cinfo->color_transform) { - case JCT_NONE: - cconvert->pub.color_convert = rgb_convert; - break; - case JCT_SUBTRACT_GREEN: - cconvert->pub.color_convert = rgb1_rgb_convert; - break; - default: - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - } - } else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - case JCS_CMYK: - cinfo->out_color_components = 4; - switch (cinfo->jpeg_color_space) { - case JCS_YCCK: - cconvert->pub.color_convert = ycck_cmyk_convert; - build_ycc_rgb_table(cinfo); - break; - case JCS_CMYK: - cconvert->pub.color_convert = null_convert; - break; - default: - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - } - break; - - default: - /* Permit null conversion to same output space */ - if (cinfo->out_color_space == cinfo->jpeg_color_space) { - cinfo->out_color_components = cinfo->num_components; - cconvert->pub.color_convert = null_convert; - } else /* unsupported non-null conversion */ - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - } - - if (cinfo->quantize_colors) - cinfo->output_components = 1; /* single colormapped output component */ - else - cinfo->output_components = cinfo->out_color_components; -} diff --git a/libraries/jpeg/jdct.h b/libraries/jpeg/jdct.h deleted file mode 100644 index bcfedfcfd29..00000000000 --- a/libraries/jpeg/jdct.h +++ /dev/null @@ -1,416 +0,0 @@ -/* - * jdct.h - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2002-2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This include file contains common declarations for the forward and - * inverse DCT modules. These declarations are private to the DCT managers - * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. - * The individual DCT algorithms are kept in separate files to ease - * machine-dependent tuning (e.g., assembly coding). - */ - - -/* - * A forward DCT routine is given a pointer to an input sample array and - * a pointer to a work area of type DCTELEM[]; the DCT is to be performed - * in-place in that buffer. Type DCTELEM is int for 8-bit samples, INT32 - * for 12-bit samples. (NOTE: Floating-point DCT implementations use an - * array of type FAST_FLOAT, instead.) - * The input data is to be fetched from the sample array starting at a - * specified column. (Any row offset needed will be applied to the array - * pointer before it is passed to the FDCT code.) - * Note that the number of samples fetched by the FDCT routine is - * DCT_h_scaled_size * DCT_v_scaled_size. - * The DCT outputs are returned scaled up by a factor of 8; they therefore - * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This - * convention improves accuracy in integer implementations and saves some - * work in floating-point ones. - * Quantization of the output coefficients is done by jcdctmgr.c. - */ - -#if BITS_IN_JSAMPLE == 8 -typedef int DCTELEM; /* 16 or 32 bits is fine */ -#else -typedef INT32 DCTELEM; /* must have 32 bits */ -#endif - -typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data, - JSAMPARRAY sample_data, - JDIMENSION start_col)); -typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data, - JSAMPARRAY sample_data, - JDIMENSION start_col)); - - -/* - * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer - * to an output sample array. The routine must dequantize the input data as - * well as perform the IDCT; for dequantization, it uses the multiplier table - * pointed to by compptr->dct_table. The output data is to be placed into the - * sample array starting at a specified column. (Any row offset needed will - * be applied to the array pointer before it is passed to the IDCT code.) - * Note that the number of samples emitted by the IDCT routine is - * DCT_h_scaled_size * DCT_v_scaled_size. - */ - -/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ - -/* - * Each IDCT routine has its own ideas about the best dct_table element type. - */ - -typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ -#if BITS_IN_JSAMPLE == 8 -typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ -#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ -#else -typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ -#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ -#endif -typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ - - -/* - * Each IDCT routine is responsible for range-limiting its results and - * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - * be quite far out of range if the input data is corrupt, so a bulletproof - * range-limiting step is required. We use a mask-and-table-lookup method - * to do the combined operations quickly, assuming that RANGE_CENTER - * (defined in jpegint.h) is a power of 2. See the comments with - * prepare_range_limit_table (in jdmaster.c) for more info. - */ - -#define RANGE_MASK (RANGE_CENTER * 2 - 1) -#define RANGE_SUBSET (RANGE_CENTER - CENTERJSAMPLE) - -#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit - RANGE_SUBSET) - - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_fdct_islow jFDislow -#define jpeg_fdct_ifast jFDifast -#define jpeg_fdct_float jFDfloat -#define jpeg_fdct_7x7 jFD7x7 -#define jpeg_fdct_6x6 jFD6x6 -#define jpeg_fdct_5x5 jFD5x5 -#define jpeg_fdct_4x4 jFD4x4 -#define jpeg_fdct_3x3 jFD3x3 -#define jpeg_fdct_2x2 jFD2x2 -#define jpeg_fdct_1x1 jFD1x1 -#define jpeg_fdct_9x9 jFD9x9 -#define jpeg_fdct_10x10 jFD10x10 -#define jpeg_fdct_11x11 jFD11x11 -#define jpeg_fdct_12x12 jFD12x12 -#define jpeg_fdct_13x13 jFD13x13 -#define jpeg_fdct_14x14 jFD14x14 -#define jpeg_fdct_15x15 jFD15x15 -#define jpeg_fdct_16x16 jFD16x16 -#define jpeg_fdct_16x8 jFD16x8 -#define jpeg_fdct_14x7 jFD14x7 -#define jpeg_fdct_12x6 jFD12x6 -#define jpeg_fdct_10x5 jFD10x5 -#define jpeg_fdct_8x4 jFD8x4 -#define jpeg_fdct_6x3 jFD6x3 -#define jpeg_fdct_4x2 jFD4x2 -#define jpeg_fdct_2x1 jFD2x1 -#define jpeg_fdct_8x16 jFD8x16 -#define jpeg_fdct_7x14 jFD7x14 -#define jpeg_fdct_6x12 jFD6x12 -#define jpeg_fdct_5x10 jFD5x10 -#define jpeg_fdct_4x8 jFD4x8 -#define jpeg_fdct_3x6 jFD3x6 -#define jpeg_fdct_2x4 jFD2x4 -#define jpeg_fdct_1x2 jFD1x2 -#define jpeg_idct_islow jRDislow -#define jpeg_idct_ifast jRDifast -#define jpeg_idct_float jRDfloat -#define jpeg_idct_7x7 jRD7x7 -#define jpeg_idct_6x6 jRD6x6 -#define jpeg_idct_5x5 jRD5x5 -#define jpeg_idct_4x4 jRD4x4 -#define jpeg_idct_3x3 jRD3x3 -#define jpeg_idct_2x2 jRD2x2 -#define jpeg_idct_1x1 jRD1x1 -#define jpeg_idct_9x9 jRD9x9 -#define jpeg_idct_10x10 jRD10x10 -#define jpeg_idct_11x11 jRD11x11 -#define jpeg_idct_12x12 jRD12x12 -#define jpeg_idct_13x13 jRD13x13 -#define jpeg_idct_14x14 jRD14x14 -#define jpeg_idct_15x15 jRD15x15 -#define jpeg_idct_16x16 jRD16x16 -#define jpeg_idct_16x8 jRD16x8 -#define jpeg_idct_14x7 jRD14x7 -#define jpeg_idct_12x6 jRD12x6 -#define jpeg_idct_10x5 jRD10x5 -#define jpeg_idct_8x4 jRD8x4 -#define jpeg_idct_6x3 jRD6x3 -#define jpeg_idct_4x2 jRD4x2 -#define jpeg_idct_2x1 jRD2x1 -#define jpeg_idct_8x16 jRD8x16 -#define jpeg_idct_7x14 jRD7x14 -#define jpeg_idct_6x12 jRD6x12 -#define jpeg_idct_5x10 jRD5x10 -#define jpeg_idct_4x8 jRD4x8 -#define jpeg_idct_3x6 jRD3x8 -#define jpeg_idct_2x4 jRD2x4 -#define jpeg_idct_1x2 jRD1x2 -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - -/* Extern declarations for the forward and inverse DCT routines. */ - -EXTERN(void) jpeg_fdct_islow - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_ifast - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_float - JPP((FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_7x7 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_6x6 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_5x5 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_4x4 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_3x3 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_2x2 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_1x1 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_9x9 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_10x10 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_11x11 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_12x12 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_13x13 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_14x14 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_15x15 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_16x16 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_16x8 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_14x7 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_12x6 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_10x5 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_8x4 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_6x3 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_4x2 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_2x1 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_8x16 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_7x14 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_6x12 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_5x10 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_4x8 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_3x6 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_2x4 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); -EXTERN(void) jpeg_fdct_1x2 - JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); - -EXTERN(void) jpeg_idct_islow - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_ifast - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_float - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_7x7 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_6x6 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_5x5 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_4x4 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_3x3 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_2x2 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_1x1 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_9x9 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_10x10 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_11x11 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_12x12 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_13x13 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_14x14 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_15x15 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_16x16 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_16x8 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_14x7 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_12x6 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_10x5 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_8x4 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_6x3 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_4x2 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_2x1 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_8x16 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_7x14 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_6x12 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_5x10 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_4x8 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_3x6 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_2x4 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_1x2 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); - - -/* - * Macros for handling fixed-point arithmetic; these are used by many - * but not all of the DCT/IDCT modules. - * - * All values are expected to be of type INT32. - * Fractional constants are scaled left by CONST_BITS bits. - * CONST_BITS is defined within each module using these macros, - * and may differ from one module to the next. - */ - -#define ONE ((INT32) 1) -#define CONST_SCALE (ONE << CONST_BITS) - -/* Convert a positive real constant to an integer scaled by CONST_SCALE. - * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, - * thus causing a lot of useless floating-point operations at run time. - */ - -#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) - -/* Descale and correctly round an INT32 value that's scaled by N bits. - * We assume RIGHT_SHIFT rounds towards minus infinity, so adding - * the fudge factor is correct for either sign of X. - */ - -#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) - -/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - * This macro is used only when the two inputs will actually be no more than - * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a - * full 32x32 multiply. This provides a useful speedup on many machines. - * Unfortunately there is no way to specify a 16x16->32 multiply portably - * in C, but some C compilers will do the right thing if you provide the - * correct combination of casts. - */ - -#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ -#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) -#endif -#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ -#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) -#endif - -#ifndef MULTIPLY16C16 /* default definition */ -#define MULTIPLY16C16(var,const) ((var) * (const)) -#endif - -/* Same except both inputs are variables. */ - -#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ -#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) -#endif - -#ifndef MULTIPLY16V16 /* default definition */ -#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) -#endif - -/* Like RIGHT_SHIFT, but applies to a DCTELEM. - * We assume that int right shift is unsigned if INT32 right shift is. - */ - -#ifdef RIGHT_SHIFT_IS_UNSIGNED -#define ISHIFT_TEMPS DCTELEM ishift_temp; -#if BITS_IN_JSAMPLE == 8 -#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ -#else -#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ -#endif -#define IRIGHT_SHIFT(x,shft) \ - ((ishift_temp = (x)) < 0 ? \ - (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ - (ishift_temp >> (shft))) -#else -#define ISHIFT_TEMPS -#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) -#endif diff --git a/libraries/jpeg/jddctmgr.c b/libraries/jpeg/jddctmgr.c deleted file mode 100644 index 9ecfbb5107e..00000000000 --- a/libraries/jpeg/jddctmgr.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * jddctmgr.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2002-2013 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the inverse-DCT management logic. - * This code selects a particular IDCT implementation to be used, - * and it performs related housekeeping chores. No code in this file - * is executed per IDCT step, only during output pass setup. - * - * Note that the IDCT routines are responsible for performing coefficient - * dequantization as well as the IDCT proper. This module sets up the - * dequantization multiplier table needed by the IDCT routine. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - - -/* - * The decompressor input side (jdinput.c) saves away the appropriate - * quantization table for each component at the start of the first scan - * involving that component. (This is necessary in order to correctly - * decode files that reuse Q-table slots.) - * When we are ready to make an output pass, the saved Q-table is converted - * to a multiplier table that will actually be used by the IDCT routine. - * The multiplier table contents are IDCT-method-dependent. To support - * application changes in IDCT method between scans, we can remake the - * multiplier tables if necessary. - * In buffered-image mode, the first output pass may occur before any data - * has been seen for some components, and thus before their Q-tables have - * been saved away. To handle this case, multiplier tables are preset - * to zeroes; the result of the IDCT will be a neutral gray level. - */ - - -/* Private subobject for this module */ - -typedef struct { - struct jpeg_inverse_dct pub; /* public fields */ - - /* This array contains the IDCT method code that each multiplier table - * is currently set up for, or -1 if it's not yet set up. - * The actual multiplier tables are pointed to by dct_table in the - * per-component comp_info structures. - */ - int cur_method[MAX_COMPONENTS]; -} my_idct_controller; - -typedef my_idct_controller * my_idct_ptr; - - -/* Allocated multiplier tables: big enough for any supported variant */ - -typedef union { - ISLOW_MULT_TYPE islow_array[DCTSIZE2]; -#ifdef DCT_IFAST_SUPPORTED - IFAST_MULT_TYPE ifast_array[DCTSIZE2]; -#endif -#ifdef DCT_FLOAT_SUPPORTED - FLOAT_MULT_TYPE float_array[DCTSIZE2]; -#endif -} multiplier_table; - - -/* The current scaled-IDCT routines require ISLOW-style multiplier tables, - * so be sure to compile that code if either ISLOW or SCALING is requested. - */ -#ifdef DCT_ISLOW_SUPPORTED -#define PROVIDE_ISLOW_TABLES -#else -#ifdef IDCT_SCALING_SUPPORTED -#define PROVIDE_ISLOW_TABLES -#endif -#endif - - -/* - * Prepare for an output pass. - * Here we select the proper IDCT routine for each component and build - * a matching multiplier table. - */ - -METHODDEF(void) -start_pass (j_decompress_ptr cinfo) -{ - my_idct_ptr idct = (my_idct_ptr) cinfo->idct; - int ci, i; - jpeg_component_info *compptr; - int method = 0; - inverse_DCT_method_ptr method_ptr = NULL; - JQUANT_TBL * qtbl; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Select the proper IDCT routine for this component's scaling */ - switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) { -#ifdef IDCT_SCALING_SUPPORTED - case ((1 << 8) + 1): - method_ptr = jpeg_idct_1x1; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((2 << 8) + 2): - method_ptr = jpeg_idct_2x2; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((3 << 8) + 3): - method_ptr = jpeg_idct_3x3; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((4 << 8) + 4): - method_ptr = jpeg_idct_4x4; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((5 << 8) + 5): - method_ptr = jpeg_idct_5x5; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((6 << 8) + 6): - method_ptr = jpeg_idct_6x6; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((7 << 8) + 7): - method_ptr = jpeg_idct_7x7; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((9 << 8) + 9): - method_ptr = jpeg_idct_9x9; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((10 << 8) + 10): - method_ptr = jpeg_idct_10x10; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((11 << 8) + 11): - method_ptr = jpeg_idct_11x11; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((12 << 8) + 12): - method_ptr = jpeg_idct_12x12; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((13 << 8) + 13): - method_ptr = jpeg_idct_13x13; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((14 << 8) + 14): - method_ptr = jpeg_idct_14x14; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((15 << 8) + 15): - method_ptr = jpeg_idct_15x15; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((16 << 8) + 16): - method_ptr = jpeg_idct_16x16; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((16 << 8) + 8): - method_ptr = jpeg_idct_16x8; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((14 << 8) + 7): - method_ptr = jpeg_idct_14x7; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((12 << 8) + 6): - method_ptr = jpeg_idct_12x6; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((10 << 8) + 5): - method_ptr = jpeg_idct_10x5; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((8 << 8) + 4): - method_ptr = jpeg_idct_8x4; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((6 << 8) + 3): - method_ptr = jpeg_idct_6x3; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((4 << 8) + 2): - method_ptr = jpeg_idct_4x2; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((2 << 8) + 1): - method_ptr = jpeg_idct_2x1; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((8 << 8) + 16): - method_ptr = jpeg_idct_8x16; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((7 << 8) + 14): - method_ptr = jpeg_idct_7x14; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((6 << 8) + 12): - method_ptr = jpeg_idct_6x12; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((5 << 8) + 10): - method_ptr = jpeg_idct_5x10; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((4 << 8) + 8): - method_ptr = jpeg_idct_4x8; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((3 << 8) + 6): - method_ptr = jpeg_idct_3x6; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((2 << 8) + 4): - method_ptr = jpeg_idct_2x4; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; - case ((1 << 8) + 2): - method_ptr = jpeg_idct_1x2; - method = JDCT_ISLOW; /* jidctint uses islow-style table */ - break; -#endif - case ((DCTSIZE << 8) + DCTSIZE): - switch (cinfo->dct_method) { -#ifdef DCT_ISLOW_SUPPORTED - case JDCT_ISLOW: - method_ptr = jpeg_idct_islow; - method = JDCT_ISLOW; - break; -#endif -#ifdef DCT_IFAST_SUPPORTED - case JDCT_IFAST: - method_ptr = jpeg_idct_ifast; - method = JDCT_IFAST; - break; -#endif -#ifdef DCT_FLOAT_SUPPORTED - case JDCT_FLOAT: - method_ptr = jpeg_idct_float; - method = JDCT_FLOAT; - break; -#endif - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - break; - } - break; - default: - ERREXIT2(cinfo, JERR_BAD_DCTSIZE, - compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size); - break; - } - idct->pub.inverse_DCT[ci] = method_ptr; - /* Create multiplier table from quant table. - * However, we can skip this if the component is uninteresting - * or if we already built the table. Also, if no quant table - * has yet been saved for the component, we leave the - * multiplier table all-zero; we'll be reading zeroes from the - * coefficient controller's buffer anyway. - */ - if (! compptr->component_needed || idct->cur_method[ci] == method) - continue; - qtbl = compptr->quant_table; - if (qtbl == NULL) /* happens if no data yet for component */ - continue; - idct->cur_method[ci] = method; - switch (method) { -#ifdef PROVIDE_ISLOW_TABLES - case JDCT_ISLOW: - { - /* For LL&M IDCT method, multipliers are equal to raw quantization - * coefficients, but are stored as ints to ensure access efficiency. - */ - ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; - for (i = 0; i < DCTSIZE2; i++) { - ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i]; - } - } - break; -#endif -#ifdef DCT_IFAST_SUPPORTED - case JDCT_IFAST: - { - /* For AA&N IDCT method, multipliers are equal to quantization - * coefficients scaled by scalefactor[row]*scalefactor[col], where - * scalefactor[0] = 1 - * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 - * For integer operation, the multiplier table is to be scaled by - * IFAST_SCALE_BITS. - */ - IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; -#define CONST_BITS 14 - static const INT16 aanscales[DCTSIZE2] = { - /* precomputed values scaled up by 14 bits */ - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, - 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, - 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, - 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, - 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 - }; - SHIFT_TEMPS - - for (i = 0; i < DCTSIZE2; i++) { - ifmtbl[i] = (IFAST_MULT_TYPE) - DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], - (INT32) aanscales[i]), - CONST_BITS-IFAST_SCALE_BITS); - } - } - break; -#endif -#ifdef DCT_FLOAT_SUPPORTED - case JDCT_FLOAT: - { - /* For float AA&N IDCT method, multipliers are equal to quantization - * coefficients scaled by scalefactor[row]*scalefactor[col], where - * scalefactor[0] = 1 - * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 - * We apply a further scale factor of 1/8. - */ - FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; - int row, col; - static const double aanscalefactor[DCTSIZE] = { - 1.0, 1.387039845, 1.306562965, 1.175875602, - 1.0, 0.785694958, 0.541196100, 0.275899379 - }; - - i = 0; - for (row = 0; row < DCTSIZE; row++) { - for (col = 0; col < DCTSIZE; col++) { - fmtbl[i] = (FLOAT_MULT_TYPE) - ((double) qtbl->quantval[i] * - aanscalefactor[row] * aanscalefactor[col] * 0.125); - i++; - } - } - } - break; -#endif - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - break; - } - } -} - - -/* - * Initialize IDCT manager. - */ - -GLOBAL(void) -jinit_inverse_dct (j_decompress_ptr cinfo) -{ - my_idct_ptr idct; - int ci; - jpeg_component_info *compptr; - - idct = (my_idct_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_idct_controller)); - cinfo->idct = &idct->pub; - idct->pub.start_pass = start_pass; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Allocate and pre-zero a multiplier table for each component */ - compptr->dct_table = - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(multiplier_table)); - MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); - /* Mark multiplier table not yet set up for any method */ - idct->cur_method[ci] = -1; - } -} diff --git a/libraries/jpeg/jdhuff.c b/libraries/jpeg/jdhuff.c deleted file mode 100644 index 835d06ecb6a..00000000000 --- a/libraries/jpeg/jdhuff.c +++ /dev/null @@ -1,1553 +0,0 @@ -/* - * jdhuff.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 2006-2016 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains Huffman entropy decoding routines. - * Both sequential and progressive modes are supported in this single module. - * - * Much of the complexity here has to do with supporting input suspension. - * If the data source module demands suspension, we want to be able to back - * up to the start of the current MCU. To do this, we copy state variables - * into local working storage, and update them back to the permanent - * storage only upon successful completion of an MCU. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Derived data constructed for each Huffman table */ - -#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ - -typedef struct { - /* Basic tables: (element [0] of each array is unused) */ - INT32 maxcode[18]; /* largest code of length k (-1 if none) */ - /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ - INT32 valoffset[17]; /* huffval[] offset for codes of length k */ - /* valoffset[k] = huffval[] index of 1st symbol of code length k, less - * the smallest code of length k; so given a code of length k, the - * corresponding symbol is huffval[code + valoffset[k]] - */ - - /* Link to public Huffman table (needed only in jpeg_huff_decode) */ - JHUFF_TBL *pub; - - /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of - * the input data stream. If the next Huffman code is no more - * than HUFF_LOOKAHEAD bits long, we can obtain its length and - * the corresponding symbol directly from these tables. - */ - int look_nbits[1< 32 bits on your machine, and shifting/masking longs is - * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE - * appropriately should be a win. Unfortunately we can't define the size - * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) - * because not all machines measure sizeof in 8-bit bytes. - */ - -typedef struct { /* Bitreading state saved across MCUs */ - bit_buf_type get_buffer; /* current bit-extraction buffer */ - int bits_left; /* # of unused bits in it */ -} bitread_perm_state; - -typedef struct { /* Bitreading working state within an MCU */ - /* Current data source location */ - /* We need a copy, rather than munging the original, in case of suspension */ - const JOCTET * next_input_byte; /* => next byte to read from source */ - size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ - /* Bit input buffer --- note these values are kept in register variables, - * not in this struct, inside the inner loops. - */ - bit_buf_type get_buffer; /* current bit-extraction buffer */ - int bits_left; /* # of unused bits in it */ - /* Pointer needed by jpeg_fill_bit_buffer. */ - j_decompress_ptr cinfo; /* back link to decompress master record */ -} bitread_working_state; - -/* Macros to declare and load/save bitread local variables. */ -#define BITREAD_STATE_VARS \ - register bit_buf_type get_buffer; \ - register int bits_left; \ - bitread_working_state br_state - -#define BITREAD_LOAD_STATE(cinfop,permstate) \ - br_state.cinfo = cinfop; \ - br_state.next_input_byte = cinfop->src->next_input_byte; \ - br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ - get_buffer = permstate.get_buffer; \ - bits_left = permstate.bits_left; - -#define BITREAD_SAVE_STATE(cinfop,permstate) \ - cinfop->src->next_input_byte = br_state.next_input_byte; \ - cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ - permstate.get_buffer = get_buffer; \ - permstate.bits_left = bits_left - -/* - * These macros provide the in-line portion of bit fetching. - * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer - * before using GET_BITS, PEEK_BITS, or DROP_BITS. - * The variables get_buffer and bits_left are assumed to be locals, - * but the state struct might not be (jpeg_huff_decode needs this). - * CHECK_BIT_BUFFER(state,n,action); - * Ensure there are N bits in get_buffer; if suspend, take action. - * val = GET_BITS(n); - * Fetch next N bits. - * val = PEEK_BITS(n); - * Fetch next N bits without removing them from the buffer. - * DROP_BITS(n); - * Discard next N bits. - * The value N should be a simple variable, not an expression, because it - * is evaluated multiple times. - */ - -#define CHECK_BIT_BUFFER(state,nbits,action) \ - { if (bits_left < (nbits)) { \ - if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ - { action; } \ - get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } - -#define GET_BITS(nbits) \ - (((int) (get_buffer >> (bits_left -= (nbits)))) & BIT_MASK(nbits)) - -#define PEEK_BITS(nbits) \ - (((int) (get_buffer >> (bits_left - (nbits)))) & BIT_MASK(nbits)) - -#define DROP_BITS(nbits) \ - (bits_left -= (nbits)) - - -/* - * Code for extracting next Huffman-coded symbol from input bit stream. - * Again, this is time-critical and we make the main paths be macros. - * - * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits - * without looping. Usually, more than 95% of the Huffman codes will be 8 - * or fewer bits long. The few overlength codes are handled with a loop, - * which need not be inline code. - * - * Notes about the HUFF_DECODE macro: - * 1. Near the end of the data segment, we may fail to get enough bits - * for a lookahead. In that case, we do it the hard way. - * 2. If the lookahead table contains no entry, the next code must be - * more than HUFF_LOOKAHEAD bits long. - * 3. jpeg_huff_decode returns -1 if forced to suspend. - */ - -#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ -{ register int nb, look; \ - if (bits_left < HUFF_LOOKAHEAD) { \ - if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ - get_buffer = state.get_buffer; bits_left = state.bits_left; \ - if (bits_left < HUFF_LOOKAHEAD) { \ - nb = 1; goto slowlabel; \ - } \ - } \ - look = PEEK_BITS(HUFF_LOOKAHEAD); \ - if ((nb = htbl->look_nbits[look]) != 0) { \ - DROP_BITS(nb); \ - result = htbl->look_sym[look]; \ - } else { \ - nb = HUFF_LOOKAHEAD+1; \ -slowlabel: \ - if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ - { failaction; } \ - get_buffer = state.get_buffer; bits_left = state.bits_left; \ - } \ -} - - -/* - * Expanded entropy decoder object for Huffman decoding. - * - * The savable_state subrecord contains fields that change within an MCU, - * but must not be updated permanently until we complete the MCU. - */ - -typedef struct { - unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ - int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ -} savable_state; - -/* This macro is to work around compilers with missing or broken - * structure assignment. You'll need to fix this code if you have - * such a compiler and you change MAX_COMPS_IN_SCAN. - */ - -#ifndef NO_STRUCT_ASSIGN -#define ASSIGN_STATE(dest,src) ((dest) = (src)) -#else -#if MAX_COMPS_IN_SCAN == 4 -#define ASSIGN_STATE(dest,src) \ - ((dest).EOBRUN = (src).EOBRUN, \ - (dest).last_dc_val[0] = (src).last_dc_val[0], \ - (dest).last_dc_val[1] = (src).last_dc_val[1], \ - (dest).last_dc_val[2] = (src).last_dc_val[2], \ - (dest).last_dc_val[3] = (src).last_dc_val[3]) -#endif -#endif - - -typedef struct { - struct jpeg_entropy_decoder pub; /* public fields */ - - /* These fields are loaded into local variables at start of each MCU. - * In case of suspension, we exit WITHOUT updating them. - */ - bitread_perm_state bitstate; /* Bit buffer at start of MCU */ - savable_state saved; /* Other state at start of MCU */ - - /* These fields are NOT loaded into local working state. */ - boolean insufficient_data; /* set TRUE after emitting warning */ - unsigned int restarts_to_go; /* MCUs left in this restart interval */ - - /* Following two fields used only in progressive mode */ - - /* Pointers to derived tables (these workspaces have image lifespan) */ - d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; - - d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ - - /* Following fields used only in sequential mode */ - - /* Pointers to derived tables (these workspaces have image lifespan) */ - d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; - d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; - - /* Precalculated info set up by start_pass for use in decode_mcu: */ - - /* Pointers to derived tables to be used for each block within an MCU */ - d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU]; - d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU]; - /* Whether we care about the DC and AC coefficient values for each block */ - int coef_limit[D_MAX_BLOCKS_IN_MCU]; -} huff_entropy_decoder; - -typedef huff_entropy_decoder * huff_entropy_ptr; - - -static const int jpeg_zigzag_order[8][8] = { - { 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 } -}; - -static const int jpeg_zigzag_order7[7][7] = { - { 0, 1, 5, 6, 14, 15, 27 }, - { 2, 4, 7, 13, 16, 26, 28 }, - { 3, 8, 12, 17, 25, 29, 38 }, - { 9, 11, 18, 24, 30, 37, 39 }, - { 10, 19, 23, 31, 36, 40, 45 }, - { 20, 22, 32, 35, 41, 44, 46 }, - { 21, 33, 34, 42, 43, 47, 48 } -}; - -static const int jpeg_zigzag_order6[6][6] = { - { 0, 1, 5, 6, 14, 15 }, - { 2, 4, 7, 13, 16, 25 }, - { 3, 8, 12, 17, 24, 26 }, - { 9, 11, 18, 23, 27, 32 }, - { 10, 19, 22, 28, 31, 33 }, - { 20, 21, 29, 30, 34, 35 } -}; - -static const int jpeg_zigzag_order5[5][5] = { - { 0, 1, 5, 6, 14 }, - { 2, 4, 7, 13, 15 }, - { 3, 8, 12, 16, 21 }, - { 9, 11, 17, 20, 22 }, - { 10, 18, 19, 23, 24 } -}; - -static const int jpeg_zigzag_order4[4][4] = { - { 0, 1, 5, 6 }, - { 2, 4, 7, 12 }, - { 3, 8, 11, 13 }, - { 9, 10, 14, 15 } -}; - -static const int jpeg_zigzag_order3[3][3] = { - { 0, 1, 5 }, - { 2, 4, 6 }, - { 3, 7, 8 } -}; - -static const int jpeg_zigzag_order2[2][2] = { - { 0, 1 }, - { 2, 3 } -}; - - -/* - * Compute the derived values for a Huffman table. - * This routine also performs some validation checks on the table. - */ - -LOCAL(void) -jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno, - d_derived_tbl ** pdtbl) -{ - JHUFF_TBL *htbl; - d_derived_tbl *dtbl; - int p, i, l, si, numsymbols; - int lookbits, ctr; - char huffsize[257]; - unsigned int huffcode[257]; - unsigned int code; - - /* Note that huffsize[] and huffcode[] are filled in code-length order, - * paralleling the order of the symbols themselves in htbl->huffval[]. - */ - - /* Find the input Huffman table */ - if (tblno < 0 || tblno >= NUM_HUFF_TBLS) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); - htbl = - isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; - if (htbl == NULL) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); - - /* Allocate a workspace if we haven't already done so. */ - if (*pdtbl == NULL) - *pdtbl = (d_derived_tbl *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(d_derived_tbl)); - dtbl = *pdtbl; - dtbl->pub = htbl; /* fill in back link */ - - /* Figure C.1: make table of Huffman code length for each symbol */ - - p = 0; - for (l = 1; l <= 16; l++) { - i = (int) htbl->bits[l]; - if (i < 0 || p + i > 256) /* protect against table overrun */ - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - while (i--) - huffsize[p++] = (char) l; - } - huffsize[p] = 0; - numsymbols = p; - - /* Figure C.2: generate the codes themselves */ - /* We also validate that the counts represent a legal Huffman code tree. */ - - code = 0; - si = huffsize[0]; - p = 0; - while (huffsize[p]) { - while (((int) huffsize[p]) == si) { - huffcode[p++] = code; - code++; - } - /* code is now 1 more than the last code used for codelength si; but - * it must still fit in si bits, since no code is allowed to be all ones. - */ - if (((INT32) code) >= (((INT32) 1) << si)) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - code <<= 1; - si++; - } - - /* Figure F.15: generate decoding tables for bit-sequential decoding */ - - p = 0; - for (l = 1; l <= 16; l++) { - if (htbl->bits[l]) { - /* valoffset[l] = huffval[] index of 1st symbol of code length l, - * minus the minimum code of length l - */ - dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p]; - p += htbl->bits[l]; - dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ - } else { - dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ - } - } - dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ - - /* Compute lookahead tables to speed up decoding. - * First we set all the table entries to 0, indicating "too long"; - * then we iterate through the Huffman codes that are short enough and - * fill in all the entries that correspond to bit sequences starting - * with that code. - */ - - MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); - - p = 0; - for (l = 1; l <= HUFF_LOOKAHEAD; l++) { - for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { - /* l = current code's length, p = its index in huffcode[] & huffval[]. */ - /* Generate left-justified code followed by all possible bit sequences */ - lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); - for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { - dtbl->look_nbits[lookbits] = l; - dtbl->look_sym[lookbits] = htbl->huffval[p]; - lookbits++; - } - } - } - - /* Validate symbols as being reasonable. - * For AC tables, we make no check, but accept all byte values 0..255. - * For DC tables, we require the symbols to be in range 0..15. - * (Tighter bounds could be applied depending on the data depth and mode, - * but this is sufficient to ensure safe decoding.) - */ - if (isDC) { - for (i = 0; i < numsymbols; i++) { - int sym = htbl->huffval[i]; - if (sym < 0 || sym > 15) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - } - } -} - - -/* - * Out-of-line code for bit fetching. - * Note: current values of get_buffer and bits_left are passed as parameters, - * but are returned in the corresponding fields of the state struct. - * - * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width - * of get_buffer to be used. (On machines with wider words, an even larger - * buffer could be used.) However, on some machines 32-bit shifts are - * quite slow and take time proportional to the number of places shifted. - * (This is true with most PC compilers, for instance.) In this case it may - * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the - * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. - */ - -#ifdef SLOW_SHIFT_32 -#define MIN_GET_BITS 15 /* minimum allowable value */ -#else -#define MIN_GET_BITS (BIT_BUF_SIZE-7) -#endif - - -LOCAL(boolean) -jpeg_fill_bit_buffer (bitread_working_state * state, - register bit_buf_type get_buffer, register int bits_left, - int nbits) -/* Load up the bit buffer to a depth of at least nbits */ -{ - /* Copy heavily used state fields into locals (hopefully registers) */ - register const JOCTET * next_input_byte = state->next_input_byte; - register size_t bytes_in_buffer = state->bytes_in_buffer; - j_decompress_ptr cinfo = state->cinfo; - - /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ - /* (It is assumed that no request will be for more than that many bits.) */ - /* We fail to do so only if we hit a marker or are forced to suspend. */ - - if (cinfo->unread_marker == 0) { /* cannot advance past a marker */ - while (bits_left < MIN_GET_BITS) { - register int c; - - /* Attempt to read a byte */ - if (bytes_in_buffer == 0) { - if (! (*cinfo->src->fill_input_buffer) (cinfo)) - return FALSE; - next_input_byte = cinfo->src->next_input_byte; - bytes_in_buffer = cinfo->src->bytes_in_buffer; - } - bytes_in_buffer--; - c = GETJOCTET(*next_input_byte++); - - /* If it's 0xFF, check and discard stuffed zero byte */ - if (c == 0xFF) { - /* Loop here to discard any padding FF's on terminating marker, - * so that we can save a valid unread_marker value. NOTE: we will - * accept multiple FF's followed by a 0 as meaning a single FF data - * byte. This data pattern is not valid according to the standard. - */ - do { - if (bytes_in_buffer == 0) { - if (! (*cinfo->src->fill_input_buffer) (cinfo)) - return FALSE; - next_input_byte = cinfo->src->next_input_byte; - bytes_in_buffer = cinfo->src->bytes_in_buffer; - } - bytes_in_buffer--; - c = GETJOCTET(*next_input_byte++); - } while (c == 0xFF); - - if (c == 0) { - /* Found FF/00, which represents an FF data byte */ - c = 0xFF; - } else { - /* Oops, it's actually a marker indicating end of compressed data. - * Save the marker code for later use. - * Fine point: it might appear that we should save the marker into - * bitread working state, not straight into permanent state. But - * once we have hit a marker, we cannot need to suspend within the - * current MCU, because we will read no more bytes from the data - * source. So it is OK to update permanent state right away. - */ - cinfo->unread_marker = c; - /* See if we need to insert some fake zero bits. */ - goto no_more_bytes; - } - } - - /* OK, load c into get_buffer */ - get_buffer = (get_buffer << 8) | c; - bits_left += 8; - } /* end while */ - } else { - no_more_bytes: - /* We get here if we've read the marker that terminates the compressed - * data segment. There should be enough bits in the buffer register - * to satisfy the request; if so, no problem. - */ - if (nbits > bits_left) { - /* Uh-oh. Report corrupted data to user and stuff zeroes into - * the data stream, so that we can produce some kind of image. - * We use a nonvolatile flag to ensure that only one warning message - * appears per data segment. - */ - if (! ((huff_entropy_ptr) cinfo->entropy)->insufficient_data) { - WARNMS(cinfo, JWRN_HIT_MARKER); - ((huff_entropy_ptr) cinfo->entropy)->insufficient_data = TRUE; - } - /* Fill the buffer with zero bits */ - get_buffer <<= MIN_GET_BITS - bits_left; - bits_left = MIN_GET_BITS; - } - } - - /* Unload the local registers */ - state->next_input_byte = next_input_byte; - state->bytes_in_buffer = bytes_in_buffer; - state->get_buffer = get_buffer; - state->bits_left = bits_left; - - return TRUE; -} - - -/* - * Figure F.12: extend sign bit. - * On some machines, a shift and sub will be faster than a table lookup. - */ - -#ifdef AVOID_TABLES - -#define BIT_MASK(nbits) ((1<<(nbits))-1) -#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) - ((1<<(s))-1) : (x)) - -#else - -#define BIT_MASK(nbits) bmask[nbits] -#define HUFF_EXTEND(x,s) ((x) <= bmask[(s) - 1] ? (x) - bmask[s] : (x)) - -static const int bmask[16] = /* bmask[n] is mask for n rightmost bits */ - { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF }; - -#endif /* AVOID_TABLES */ - - -/* - * Out-of-line code for Huffman code decoding. - */ - -LOCAL(int) -jpeg_huff_decode (bitread_working_state * state, - register bit_buf_type get_buffer, register int bits_left, - d_derived_tbl * htbl, int min_bits) -{ - register int l = min_bits; - register INT32 code; - - /* HUFF_DECODE has determined that the code is at least min_bits */ - /* bits long, so fetch that many bits in one swoop. */ - - CHECK_BIT_BUFFER(*state, l, return -1); - code = GET_BITS(l); - - /* Collect the rest of the Huffman code one bit at a time. */ - /* This is per Figure F.16 in the JPEG spec. */ - - while (code > htbl->maxcode[l]) { - code <<= 1; - CHECK_BIT_BUFFER(*state, 1, return -1); - code |= GET_BITS(1); - l++; - } - - /* Unload the local registers */ - state->get_buffer = get_buffer; - state->bits_left = bits_left; - - /* With garbage input we may reach the sentinel value l = 17. */ - - if (l > 16) { - WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); - return 0; /* fake a zero as the safest result */ - } - - return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; -} - - -/* - * Finish up at the end of a Huffman-compressed scan. - */ - -METHODDEF(void) -finish_pass_huff (j_decompress_ptr cinfo) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - - /* Throw away any unused bits remaining in bit buffer; */ - /* include any full bytes in next_marker's count of discarded bytes */ - cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; - entropy->bitstate.bits_left = 0; -} - - -/* - * Check for a restart marker & resynchronize decoder. - * Returns FALSE if must suspend. - */ - -LOCAL(boolean) -process_restart (j_decompress_ptr cinfo) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - int ci; - - finish_pass_huff(cinfo); - - /* Advance past the RSTn marker */ - if (! (*cinfo->marker->read_restart_marker) (cinfo)) - return FALSE; - - /* Re-initialize DC predictions to 0 */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) - entropy->saved.last_dc_val[ci] = 0; - /* Re-init EOB run count, too */ - entropy->saved.EOBRUN = 0; - - /* Reset restart counter */ - entropy->restarts_to_go = cinfo->restart_interval; - - /* Reset out-of-data flag, unless read_restart_marker left us smack up - * against a marker. In that case we will end up treating the next data - * segment as empty, and we can avoid producing bogus output pixels by - * leaving the flag set. - */ - if (cinfo->unread_marker == 0) - entropy->insufficient_data = FALSE; - - return TRUE; -} - - -/* - * Huffman MCU decoding. - * Each of these routines decodes and returns one MCU's worth of - * Huffman-compressed coefficients. - * The coefficients are reordered from zigzag order into natural array order, - * but are not dequantized. - * - * The i'th block of the MCU is stored into the block pointed to by - * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. - * (Wholesale zeroing is usually a little faster than retail...) - * - * We return FALSE if data source requested suspension. In that case no - * changes have been made to permanent state. (Exception: some output - * coefficients may already have been assigned. This is harmless for - * spectral selection, since we'll just re-assign them on the next call. - * Successive approximation AC refinement has to be more careful, however.) - */ - -/* - * MCU decoding for DC initial scan (either spectral selection, - * or first pass of successive approximation). - */ - -METHODDEF(boolean) -decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - int Al = cinfo->Al; - register int s, r; - int blkn, ci; - JBLOCKROW block; - BITREAD_STATE_VARS; - savable_state state; - d_derived_tbl * tbl; - jpeg_component_info * compptr; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restart(cinfo)) - return FALSE; - } - - /* If we've run out of data, just leave the MCU set to zeroes. - * This way, we return uniform gray for the remainder of the segment. - */ - if (! entropy->insufficient_data) { - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(state, entropy->saved); - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - block = MCU_data[blkn]; - ci = cinfo->MCU_membership[blkn]; - compptr = cinfo->cur_comp_info[ci]; - tbl = entropy->derived_tbls[compptr->dc_tbl_no]; - - /* Decode a single block's worth of coefficients */ - - /* Section F.2.2.1: decode the DC coefficient difference */ - HUFF_DECODE(s, br_state, tbl, return FALSE, label1); - if (s) { - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - } - - /* Convert DC difference to actual value, update last_dc_val */ - s += state.last_dc_val[ci]; - state.last_dc_val[ci] = s; - /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ - (*block)[0] = (JCOEF) (s << Al); - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(entropy->saved, state); - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * MCU decoding for AC initial scan (either spectral selection, - * or first pass of successive approximation). - */ - -METHODDEF(boolean) -decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - register int s, k, r; - unsigned int EOBRUN; - int Se, Al; - const int * natural_order; - JBLOCKROW block; - BITREAD_STATE_VARS; - d_derived_tbl * tbl; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restart(cinfo)) - return FALSE; - } - - /* If we've run out of data, just leave the MCU set to zeroes. - * This way, we return uniform gray for the remainder of the segment. - */ - if (! entropy->insufficient_data) { - - /* Load up working state. - * We can avoid loading/saving bitread state if in an EOB run. - */ - EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ - - /* There is always only one block per MCU */ - - if (EOBRUN) /* if it's a band of zeroes... */ - EOBRUN--; /* ...process it now (we do nothing) */ - else { - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - Se = cinfo->Se; - Al = cinfo->Al; - natural_order = cinfo->natural_order; - block = MCU_data[0]; - tbl = entropy->ac_derived_tbl; - - for (k = cinfo->Ss; k <= Se; k++) { - HUFF_DECODE(s, br_state, tbl, return FALSE, label2); - r = s >> 4; - s &= 15; - if (s) { - k += r; - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - /* Scale and output coefficient in natural (dezigzagged) order */ - (*block)[natural_order[k]] = (JCOEF) (s << Al); - } else { - if (r != 15) { /* EOBr, run length is 2^r + appended bits */ - if (r) { /* EOBr, r > 0 */ - EOBRUN = 1 << r; - CHECK_BIT_BUFFER(br_state, r, return FALSE); - r = GET_BITS(r); - EOBRUN += r; - EOBRUN--; /* this band is processed at this moment */ - } - break; /* force end-of-band */ - } - k += 15; /* ZRL: skip 15 zeroes in band */ - } - } - - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - } - - /* Completed MCU, so update state */ - entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * MCU decoding for DC successive approximation refinement scan. - * Note: we assume such scans can be multi-component, - * although the spec is not very clear on the point. - */ - -METHODDEF(boolean) -decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - int p1, blkn; - BITREAD_STATE_VARS; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restart(cinfo)) - return FALSE; - } - - /* Not worth the cycles to check insufficient_data here, - * since we will not change the data anyway if we read zeroes. - */ - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - - p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - /* Encoded data is simply the next bit of the two's-complement DC value */ - CHECK_BIT_BUFFER(br_state, 1, return FALSE); - if (GET_BITS(1)) - MCU_data[blkn][0][0] |= p1; - /* Note: since we use |=, repeating the assignment later is safe */ - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * MCU decoding for AC successive approximation refinement scan. - */ - -METHODDEF(boolean) -decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - register int s, k, r; - unsigned int EOBRUN; - int Se, p1, m1; - const int * natural_order; - JBLOCKROW block; - JCOEFPTR thiscoef; - BITREAD_STATE_VARS; - d_derived_tbl * tbl; - int num_newnz; - int newnz_pos[DCTSIZE2]; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restart(cinfo)) - return FALSE; - } - - /* If we've run out of data, don't modify the MCU. - */ - if (! entropy->insufficient_data) { - - Se = cinfo->Se; - p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ - m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ - natural_order = cinfo->natural_order; - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ - - /* There is always only one block per MCU */ - block = MCU_data[0]; - tbl = entropy->ac_derived_tbl; - - /* If we are forced to suspend, we must undo the assignments to any newly - * nonzero coefficients in the block, because otherwise we'd get confused - * next time about which coefficients were already nonzero. - * But we need not undo addition of bits to already-nonzero coefficients; - * instead, we can test the current bit to see if we already did it. - */ - num_newnz = 0; - - /* initialize coefficient loop counter to start of band */ - k = cinfo->Ss; - - if (EOBRUN == 0) { - do { - HUFF_DECODE(s, br_state, tbl, goto undoit, label3); - r = s >> 4; - s &= 15; - if (s) { - if (s != 1) /* size of new coef should always be 1 */ - WARNMS(cinfo, JWRN_HUFF_BAD_CODE); - CHECK_BIT_BUFFER(br_state, 1, goto undoit); - if (GET_BITS(1)) - s = p1; /* newly nonzero coef is positive */ - else - s = m1; /* newly nonzero coef is negative */ - } else { - if (r != 15) { - EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ - if (r) { - CHECK_BIT_BUFFER(br_state, r, goto undoit); - r = GET_BITS(r); - EOBRUN += r; - } - break; /* rest of block is handled by EOB logic */ - } - /* note s = 0 for processing ZRL */ - } - /* Advance over already-nonzero coefs and r still-zero coefs, - * appending correction bits to the nonzeroes. A correction bit is 1 - * if the absolute value of the coefficient must be increased. - */ - do { - thiscoef = *block + natural_order[k]; - if (*thiscoef) { - CHECK_BIT_BUFFER(br_state, 1, goto undoit); - if (GET_BITS(1)) { - if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ - if (*thiscoef >= 0) - *thiscoef += p1; - else - *thiscoef += m1; - } - } - } else { - if (--r < 0) - break; /* reached target zero coefficient */ - } - k++; - } while (k <= Se); - if (s) { - int pos = natural_order[k]; - /* Output newly nonzero coefficient */ - (*block)[pos] = (JCOEF) s; - /* Remember its position in case we have to suspend */ - newnz_pos[num_newnz++] = pos; - } - k++; - } while (k <= Se); - } - - if (EOBRUN) { - /* Scan any remaining coefficient positions after the end-of-band - * (the last newly nonzero coefficient, if any). Append a correction - * bit to each already-nonzero coefficient. A correction bit is 1 - * if the absolute value of the coefficient must be increased. - */ - do { - thiscoef = *block + natural_order[k]; - if (*thiscoef) { - CHECK_BIT_BUFFER(br_state, 1, goto undoit); - if (GET_BITS(1)) { - if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ - if (*thiscoef >= 0) - *thiscoef += p1; - else - *thiscoef += m1; - } - } - } - k++; - } while (k <= Se); - /* Count one block completed in EOB run */ - EOBRUN--; - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; - -undoit: - /* Re-zero any output coefficients that we made newly nonzero */ - while (num_newnz) - (*block)[newnz_pos[--num_newnz]] = 0; - - return FALSE; -} - - -/* - * Decode one MCU's worth of Huffman-compressed coefficients, - * partial blocks. - */ - -METHODDEF(boolean) -decode_mcu_sub (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - const int * natural_order; - int Se, blkn; - BITREAD_STATE_VARS; - savable_state state; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restart(cinfo)) - return FALSE; - } - - /* If we've run out of data, just leave the MCU set to zeroes. - * This way, we return uniform gray for the remainder of the segment. - */ - if (! entropy->insufficient_data) { - - natural_order = cinfo->natural_order; - Se = cinfo->lim_Se; - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(state, entropy->saved); - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - JBLOCKROW block = MCU_data[blkn]; - d_derived_tbl * htbl; - register int s, k, r; - int coef_limit, ci; - - /* Decode a single block's worth of coefficients */ - - /* Section F.2.2.1: decode the DC coefficient difference */ - htbl = entropy->dc_cur_tbls[blkn]; - HUFF_DECODE(s, br_state, htbl, return FALSE, label1); - - htbl = entropy->ac_cur_tbls[blkn]; - k = 1; - coef_limit = entropy->coef_limit[blkn]; - if (coef_limit) { - /* Convert DC difference to actual value, update last_dc_val */ - if (s) { - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - } - ci = cinfo->MCU_membership[blkn]; - s += state.last_dc_val[ci]; - state.last_dc_val[ci] = s; - /* Output the DC coefficient */ - (*block)[0] = (JCOEF) s; - - /* Section F.2.2.2: decode the AC coefficients */ - /* Since zeroes are skipped, output area must be cleared beforehand */ - for (; k < coef_limit; k++) { - HUFF_DECODE(s, br_state, htbl, return FALSE, label2); - - r = s >> 4; - s &= 15; - - if (s) { - k += r; - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - /* Output coefficient in natural (dezigzagged) order. - * Note: the extra entries in natural_order[] will save us - * if k > Se, which could happen if the data is corrupted. - */ - (*block)[natural_order[k]] = (JCOEF) s; - } else { - if (r != 15) - goto EndOfBlock; - k += 15; - } - } - } else { - if (s) { - CHECK_BIT_BUFFER(br_state, s, return FALSE); - DROP_BITS(s); - } - } - - /* Section F.2.2.2: decode the AC coefficients */ - /* In this path we just discard the values */ - for (; k <= Se; k++) { - HUFF_DECODE(s, br_state, htbl, return FALSE, label3); - - r = s >> 4; - s &= 15; - - if (s) { - k += r; - CHECK_BIT_BUFFER(br_state, s, return FALSE); - DROP_BITS(s); - } else { - if (r != 15) - break; - k += 15; - } - } - - EndOfBlock: ; - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(entropy->saved, state); - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * Decode one MCU's worth of Huffman-compressed coefficients, - * full-size blocks. - */ - -METHODDEF(boolean) -decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - int blkn; - BITREAD_STATE_VARS; - savable_state state; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restart(cinfo)) - return FALSE; - } - - /* If we've run out of data, just leave the MCU set to zeroes. - * This way, we return uniform gray for the remainder of the segment. - */ - if (! entropy->insufficient_data) { - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(state, entropy->saved); - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - JBLOCKROW block = MCU_data[blkn]; - d_derived_tbl * htbl; - register int s, k, r; - int coef_limit, ci; - - /* Decode a single block's worth of coefficients */ - - /* Section F.2.2.1: decode the DC coefficient difference */ - htbl = entropy->dc_cur_tbls[blkn]; - HUFF_DECODE(s, br_state, htbl, return FALSE, label1); - - htbl = entropy->ac_cur_tbls[blkn]; - k = 1; - coef_limit = entropy->coef_limit[blkn]; - if (coef_limit) { - /* Convert DC difference to actual value, update last_dc_val */ - if (s) { - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - } - ci = cinfo->MCU_membership[blkn]; - s += state.last_dc_val[ci]; - state.last_dc_val[ci] = s; - /* Output the DC coefficient */ - (*block)[0] = (JCOEF) s; - - /* Section F.2.2.2: decode the AC coefficients */ - /* Since zeroes are skipped, output area must be cleared beforehand */ - for (; k < coef_limit; k++) { - HUFF_DECODE(s, br_state, htbl, return FALSE, label2); - - r = s >> 4; - s &= 15; - - if (s) { - k += r; - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - /* Output coefficient in natural (dezigzagged) order. - * Note: the extra entries in jpeg_natural_order[] will save us - * if k >= DCTSIZE2, which could happen if the data is corrupted. - */ - (*block)[jpeg_natural_order[k]] = (JCOEF) s; - } else { - if (r != 15) - goto EndOfBlock; - k += 15; - } - } - } else { - if (s) { - CHECK_BIT_BUFFER(br_state, s, return FALSE); - DROP_BITS(s); - } - } - - /* Section F.2.2.2: decode the AC coefficients */ - /* In this path we just discard the values */ - for (; k < DCTSIZE2; k++) { - HUFF_DECODE(s, br_state, htbl, return FALSE, label3); - - r = s >> 4; - s &= 15; - - if (s) { - k += r; - CHECK_BIT_BUFFER(br_state, s, return FALSE); - DROP_BITS(s); - } else { - if (r != 15) - break; - k += 15; - } - } - - EndOfBlock: ; - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(entropy->saved, state); - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * Initialize for a Huffman-compressed scan. - */ - -METHODDEF(void) -start_pass_huff_decoder (j_decompress_ptr cinfo) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - int ci, blkn, tbl, i; - jpeg_component_info * compptr; - - if (cinfo->progressive_mode) { - /* Validate progressive scan parameters */ - if (cinfo->Ss == 0) { - if (cinfo->Se != 0) - goto bad; - } else { - /* need not check Ss/Se < 0 since they came from unsigned bytes */ - if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se) - goto bad; - /* AC scans may have only one component */ - if (cinfo->comps_in_scan != 1) - goto bad; - } - if (cinfo->Ah != 0) { - /* Successive approximation refinement scan: must have Al = Ah-1. */ - if (cinfo->Ah-1 != cinfo->Al) - goto bad; - } - if (cinfo->Al > 13) { /* need not check for < 0 */ - /* Arguably the maximum Al value should be less than 13 for 8-bit precision, - * but the spec doesn't say so, and we try to be liberal about what we - * accept. Note: large Al values could result in out-of-range DC - * coefficients during early scans, leading to bizarre displays due to - * overflows in the IDCT math. But we won't crash. - */ - bad: - ERREXIT4(cinfo, JERR_BAD_PROGRESSION, - cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); - } - /* Update progression status, and verify that scan order is legal. - * Note that inter-scan inconsistencies are treated as warnings - * not fatal errors ... not clear if this is right way to behave. - */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - int coefi, cindex = cinfo->cur_comp_info[ci]->component_index; - int *coef_bit_ptr = & cinfo->coef_bits[cindex][0]; - if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ - WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); - for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { - int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; - if (cinfo->Ah != expected) - WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); - coef_bit_ptr[coefi] = cinfo->Al; - } - } - - /* Select MCU decoding routine */ - if (cinfo->Ah == 0) { - if (cinfo->Ss == 0) - entropy->pub.decode_mcu = decode_mcu_DC_first; - else - entropy->pub.decode_mcu = decode_mcu_AC_first; - } else { - if (cinfo->Ss == 0) - entropy->pub.decode_mcu = decode_mcu_DC_refine; - else - entropy->pub.decode_mcu = decode_mcu_AC_refine; - } - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Make sure requested tables are present, and compute derived tables. - * We may build same derived table more than once, but it's not expensive. - */ - if (cinfo->Ss == 0) { - if (cinfo->Ah == 0) { /* DC refinement needs no table */ - tbl = compptr->dc_tbl_no; - jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, - & entropy->derived_tbls[tbl]); - } - } else { - tbl = compptr->ac_tbl_no; - jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, - & entropy->derived_tbls[tbl]); - /* remember the single active table */ - entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; - } - /* Initialize DC predictions to 0 */ - entropy->saved.last_dc_val[ci] = 0; - } - - /* Initialize private state variables */ - entropy->saved.EOBRUN = 0; - } else { - /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. - * This ought to be an error condition, but we make it a warning because - * there are some baseline files out there with all zeroes in these bytes. - */ - if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 || - ((cinfo->is_baseline || cinfo->Se < DCTSIZE2) && - cinfo->Se != cinfo->lim_Se)) - WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); - - /* Select MCU decoding routine */ - /* We retain the hard-coded case for full-size blocks. - * This is not necessary, but it appears that this version is slightly - * more performant in the given implementation. - * With an improved implementation we would prefer a single optimized - * function. - */ - if (cinfo->lim_Se != DCTSIZE2-1) - entropy->pub.decode_mcu = decode_mcu_sub; - else - entropy->pub.decode_mcu = decode_mcu; - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Compute derived values for Huffman tables */ - /* We may do this more than once for a table, but it's not expensive */ - tbl = compptr->dc_tbl_no; - jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, - & entropy->dc_derived_tbls[tbl]); - if (cinfo->lim_Se) { /* AC needs no table when not present */ - tbl = compptr->ac_tbl_no; - jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, - & entropy->ac_derived_tbls[tbl]); - } - /* Initialize DC predictions to 0 */ - entropy->saved.last_dc_val[ci] = 0; - } - - /* Precalculate decoding info for each block in an MCU of this scan */ - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - ci = cinfo->MCU_membership[blkn]; - compptr = cinfo->cur_comp_info[ci]; - /* Precalculate which table to use for each block */ - entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no]; - entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no]; - /* Decide whether we really care about the coefficient values */ - if (compptr->component_needed) { - ci = compptr->DCT_v_scaled_size; - i = compptr->DCT_h_scaled_size; - switch (cinfo->lim_Se) { - case (1*1-1): - entropy->coef_limit[blkn] = 1; - break; - case (2*2-1): - if (ci <= 0 || ci > 2) ci = 2; - if (i <= 0 || i > 2) i = 2; - entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order2[ci - 1][i - 1]; - break; - case (3*3-1): - if (ci <= 0 || ci > 3) ci = 3; - if (i <= 0 || i > 3) i = 3; - entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order3[ci - 1][i - 1]; - break; - case (4*4-1): - if (ci <= 0 || ci > 4) ci = 4; - if (i <= 0 || i > 4) i = 4; - entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order4[ci - 1][i - 1]; - break; - case (5*5-1): - if (ci <= 0 || ci > 5) ci = 5; - if (i <= 0 || i > 5) i = 5; - entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order5[ci - 1][i - 1]; - break; - case (6*6-1): - if (ci <= 0 || ci > 6) ci = 6; - if (i <= 0 || i > 6) i = 6; - entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order6[ci - 1][i - 1]; - break; - case (7*7-1): - if (ci <= 0 || ci > 7) ci = 7; - if (i <= 0 || i > 7) i = 7; - entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order7[ci - 1][i - 1]; - break; - default: - if (ci <= 0 || ci > 8) ci = 8; - if (i <= 0 || i > 8) i = 8; - entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order[ci - 1][i - 1]; - break; - } - } else { - entropy->coef_limit[blkn] = 0; - } - } - } - - /* Initialize bitread state variables */ - entropy->bitstate.bits_left = 0; - entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ - entropy->insufficient_data = FALSE; - - /* Initialize restart counter */ - entropy->restarts_to_go = cinfo->restart_interval; -} - - -/* - * Module initialization routine for Huffman entropy decoding. - */ - -GLOBAL(void) -jinit_huff_decoder (j_decompress_ptr cinfo) -{ - huff_entropy_ptr entropy; - int i; - - entropy = (huff_entropy_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(huff_entropy_decoder)); - cinfo->entropy = &entropy->pub; - entropy->pub.start_pass = start_pass_huff_decoder; - entropy->pub.finish_pass = finish_pass_huff; - - if (cinfo->progressive_mode) { - /* Create progression status table */ - int *coef_bit_ptr, ci; - cinfo->coef_bits = (int (*)[DCTSIZE2]) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components*DCTSIZE2*SIZEOF(int)); - coef_bit_ptr = & cinfo->coef_bits[0][0]; - for (ci = 0; ci < cinfo->num_components; ci++) - for (i = 0; i < DCTSIZE2; i++) - *coef_bit_ptr++ = -1; - - /* Mark derived tables unallocated */ - for (i = 0; i < NUM_HUFF_TBLS; i++) { - entropy->derived_tbls[i] = NULL; - } - } else { - /* Mark tables unallocated */ - for (i = 0; i < NUM_HUFF_TBLS; i++) { - entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; - } - } -} diff --git a/libraries/jpeg/jdinput.c b/libraries/jpeg/jdinput.c deleted file mode 100644 index 0199553e896..00000000000 --- a/libraries/jpeg/jdinput.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * jdinput.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 2002-2013 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains input control logic for the JPEG decompressor. - * These routines are concerned with controlling the decompressor's input - * processing (marker reading and coefficient decoding). The actual input - * reading is done in jdmarker.c, jdhuff.c, and jdarith.c. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private state */ - -typedef struct { - struct jpeg_input_controller pub; /* public fields */ - - int inheaders; /* Nonzero until first SOS is reached */ -} my_input_controller; - -typedef my_input_controller * my_inputctl_ptr; - - -/* Forward declarations */ -METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); - - -/* - * Routines to calculate various quantities related to the size of the image. - */ - - -/* - * Compute output image dimensions and related values. - * NOTE: this is exported for possible use by application. - * Hence it mustn't do anything that can't be done twice. - */ - -GLOBAL(void) -jpeg_core_output_dimensions (j_decompress_ptr cinfo) -/* Do computations that are needed before master selection phase. - * This function is used for transcoding and full decompression. - */ -{ -#ifdef IDCT_SCALING_SUPPORTED - int ci; - jpeg_component_info *compptr; - - /* Compute actual output image dimensions and DCT scaling choices. */ - if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom) { - /* Provide 1/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 1; - cinfo->min_DCT_v_scaled_size = 1; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 2) { - /* Provide 2/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 2L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 2L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 2; - cinfo->min_DCT_v_scaled_size = 2; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 3) { - /* Provide 3/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 3L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 3L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 3; - cinfo->min_DCT_v_scaled_size = 3; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 4) { - /* Provide 4/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 4L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 4L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 4; - cinfo->min_DCT_v_scaled_size = 4; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 5) { - /* Provide 5/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 5L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 5L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 5; - cinfo->min_DCT_v_scaled_size = 5; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 6) { - /* Provide 6/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 6L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 6L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 6; - cinfo->min_DCT_v_scaled_size = 6; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 7) { - /* Provide 7/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 7L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 7L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 7; - cinfo->min_DCT_v_scaled_size = 7; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 8) { - /* Provide 8/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 8L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 8L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 8; - cinfo->min_DCT_v_scaled_size = 8; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 9) { - /* Provide 9/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 9L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 9L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 9; - cinfo->min_DCT_v_scaled_size = 9; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 10) { - /* Provide 10/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 10L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 10L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 10; - cinfo->min_DCT_v_scaled_size = 10; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 11) { - /* Provide 11/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 11L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 11L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 11; - cinfo->min_DCT_v_scaled_size = 11; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 12) { - /* Provide 12/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 12L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 12L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 12; - cinfo->min_DCT_v_scaled_size = 12; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 13) { - /* Provide 13/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 13L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 13L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 13; - cinfo->min_DCT_v_scaled_size = 13; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 14) { - /* Provide 14/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 14L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 14L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 14; - cinfo->min_DCT_v_scaled_size = 14; - } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 15) { - /* Provide 15/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 15L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 15L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 15; - cinfo->min_DCT_v_scaled_size = 15; - } else { - /* Provide 16/block_size scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * 16L, (long) cinfo->block_size); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * 16L, (long) cinfo->block_size); - cinfo->min_DCT_h_scaled_size = 16; - cinfo->min_DCT_v_scaled_size = 16; - } - - /* Recompute dimensions of components */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size; - compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size; - } - -#else /* !IDCT_SCALING_SUPPORTED */ - - /* Hardwire it to "no scaling" */ - cinfo->output_width = cinfo->image_width; - cinfo->output_height = cinfo->image_height; - /* initial_setup has already initialized DCT_scaled_size, - * and has computed unscaled downsampled_width and downsampled_height. - */ - -#endif /* IDCT_SCALING_SUPPORTED */ -} - - -LOCAL(void) -initial_setup (j_decompress_ptr cinfo) -/* Called once, when first SOS marker is reached */ -{ - int ci; - jpeg_component_info *compptr; - - /* Make sure image isn't bigger than I can handle */ - if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || - (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) - ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); - - /* Only 8 to 12 bits data precision are supported for DCT based JPEG */ - if (cinfo->data_precision < 8 || cinfo->data_precision > 12) - ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); - - /* Check that number of components won't exceed internal array sizes */ - if (cinfo->num_components > MAX_COMPONENTS) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, - MAX_COMPONENTS); - - /* Compute maximum sampling factors; check factor validity */ - cinfo->max_h_samp_factor = 1; - cinfo->max_v_samp_factor = 1; - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || - compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) - ERREXIT(cinfo, JERR_BAD_SAMPLING); - cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, - compptr->h_samp_factor); - cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, - compptr->v_samp_factor); - } - - /* Derive block_size, natural_order, and lim_Se */ - if (cinfo->is_baseline || (cinfo->progressive_mode && - cinfo->comps_in_scan)) { /* no pseudo SOS marker */ - cinfo->block_size = DCTSIZE; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - } else - switch (cinfo->Se) { - case (1*1-1): - cinfo->block_size = 1; - cinfo->natural_order = jpeg_natural_order; /* not needed */ - cinfo->lim_Se = cinfo->Se; - break; - case (2*2-1): - cinfo->block_size = 2; - cinfo->natural_order = jpeg_natural_order2; - cinfo->lim_Se = cinfo->Se; - break; - case (3*3-1): - cinfo->block_size = 3; - cinfo->natural_order = jpeg_natural_order3; - cinfo->lim_Se = cinfo->Se; - break; - case (4*4-1): - cinfo->block_size = 4; - cinfo->natural_order = jpeg_natural_order4; - cinfo->lim_Se = cinfo->Se; - break; - case (5*5-1): - cinfo->block_size = 5; - cinfo->natural_order = jpeg_natural_order5; - cinfo->lim_Se = cinfo->Se; - break; - case (6*6-1): - cinfo->block_size = 6; - cinfo->natural_order = jpeg_natural_order6; - cinfo->lim_Se = cinfo->Se; - break; - case (7*7-1): - cinfo->block_size = 7; - cinfo->natural_order = jpeg_natural_order7; - cinfo->lim_Se = cinfo->Se; - break; - case (8*8-1): - cinfo->block_size = 8; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - case (9*9-1): - cinfo->block_size = 9; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - case (10*10-1): - cinfo->block_size = 10; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - case (11*11-1): - cinfo->block_size = 11; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - case (12*12-1): - cinfo->block_size = 12; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - case (13*13-1): - cinfo->block_size = 13; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - case (14*14-1): - cinfo->block_size = 14; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - case (15*15-1): - cinfo->block_size = 15; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - case (16*16-1): - cinfo->block_size = 16; - cinfo->natural_order = jpeg_natural_order; - cinfo->lim_Se = DCTSIZE2-1; - break; - default: - ERREXIT4(cinfo, JERR_BAD_PROGRESSION, - cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); - break; - } - - /* We initialize DCT_scaled_size and min_DCT_scaled_size to block_size. - * In the full decompressor, - * this will be overridden by jpeg_calc_output_dimensions in jdmaster.c; - * but in the transcoder, - * jpeg_calc_output_dimensions is not used, so we must do it here. - */ - cinfo->min_DCT_h_scaled_size = cinfo->block_size; - cinfo->min_DCT_v_scaled_size = cinfo->block_size; - - /* Compute dimensions of components */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - compptr->DCT_h_scaled_size = cinfo->block_size; - compptr->DCT_v_scaled_size = cinfo->block_size; - /* Size in DCT blocks */ - compptr->width_in_blocks = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, - (long) (cinfo->max_h_samp_factor * cinfo->block_size)); - compptr->height_in_blocks = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, - (long) (cinfo->max_v_samp_factor * cinfo->block_size)); - /* downsampled_width and downsampled_height will also be overridden by - * jdmaster.c if we are doing full decompression. The transcoder library - * doesn't use these values, but the calling application might. - */ - /* Size in samples */ - compptr->downsampled_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, - (long) cinfo->max_h_samp_factor); - compptr->downsampled_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, - (long) cinfo->max_v_samp_factor); - /* Mark component needed, until color conversion says otherwise */ - compptr->component_needed = TRUE; - /* Mark no quantization table yet saved for component */ - compptr->quant_table = NULL; - } - - /* Compute number of fully interleaved MCU rows. */ - cinfo->total_iMCU_rows = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, - (long) (cinfo->max_v_samp_factor * cinfo->block_size)); - - /* Decide whether file contains multiple scans */ - if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode) - cinfo->inputctl->has_multiple_scans = TRUE; - else - cinfo->inputctl->has_multiple_scans = FALSE; -} - - -LOCAL(void) -per_scan_setup (j_decompress_ptr cinfo) -/* Do computations that are needed before processing a JPEG scan */ -/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ -{ - int ci, mcublks, tmp; - jpeg_component_info *compptr; - - if (cinfo->comps_in_scan == 1) { - - /* Noninterleaved (single-component) scan */ - compptr = cinfo->cur_comp_info[0]; - - /* Overall image size in MCUs */ - cinfo->MCUs_per_row = compptr->width_in_blocks; - cinfo->MCU_rows_in_scan = compptr->height_in_blocks; - - /* For noninterleaved scan, always one block per MCU */ - compptr->MCU_width = 1; - compptr->MCU_height = 1; - compptr->MCU_blocks = 1; - compptr->MCU_sample_width = compptr->DCT_h_scaled_size; - compptr->last_col_width = 1; - /* For noninterleaved scans, it is convenient to define last_row_height - * as the number of block rows present in the last iMCU row. - */ - tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); - if (tmp == 0) tmp = compptr->v_samp_factor; - compptr->last_row_height = tmp; - - /* Prepare array describing MCU composition */ - cinfo->blocks_in_MCU = 1; - cinfo->MCU_membership[0] = 0; - - } else { - - /* Interleaved (multi-component) scan */ - if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, - MAX_COMPS_IN_SCAN); - - /* Overall image size in MCUs */ - cinfo->MCUs_per_row = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width, - (long) (cinfo->max_h_samp_factor * cinfo->block_size)); - cinfo->MCU_rows_in_scan = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, - (long) (cinfo->max_v_samp_factor * cinfo->block_size)); - - cinfo->blocks_in_MCU = 0; - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Sampling factors give # of blocks of component in each MCU */ - compptr->MCU_width = compptr->h_samp_factor; - compptr->MCU_height = compptr->v_samp_factor; - compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; - compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size; - /* Figure number of non-dummy blocks in last MCU column & row */ - tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); - if (tmp == 0) tmp = compptr->MCU_width; - compptr->last_col_width = tmp; - tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); - if (tmp == 0) tmp = compptr->MCU_height; - compptr->last_row_height = tmp; - /* Prepare array describing MCU composition */ - mcublks = compptr->MCU_blocks; - if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU) - ERREXIT(cinfo, JERR_BAD_MCU_SIZE); - while (mcublks-- > 0) { - cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; - } - } - - } -} - - -/* - * Save away a copy of the Q-table referenced by each component present - * in the current scan, unless already saved during a prior scan. - * - * In a multiple-scan JPEG file, the encoder could assign different components - * the same Q-table slot number, but change table definitions between scans - * so that each component uses a different Q-table. (The IJG encoder is not - * currently capable of doing this, but other encoders might.) Since we want - * to be able to dequantize all the components at the end of the file, this - * means that we have to save away the table actually used for each component. - * We do this by copying the table at the start of the first scan containing - * the component. - * The JPEG spec prohibits the encoder from changing the contents of a Q-table - * slot between scans of a component using that slot. If the encoder does so - * anyway, this decoder will simply use the Q-table values that were current - * at the start of the first scan for the component. - * - * The decompressor output side looks only at the saved quant tables, - * not at the current Q-table slots. - */ - -LOCAL(void) -latch_quant_tables (j_decompress_ptr cinfo) -{ - int ci, qtblno; - jpeg_component_info *compptr; - JQUANT_TBL * qtbl; - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* No work if we already saved Q-table for this component */ - if (compptr->quant_table != NULL) - continue; - /* Make sure specified quantization table is present */ - qtblno = compptr->quant_tbl_no; - if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || - cinfo->quant_tbl_ptrs[qtblno] == NULL) - ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); - /* OK, save away the quantization table */ - qtbl = (JQUANT_TBL *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(JQUANT_TBL)); - MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); - compptr->quant_table = qtbl; - } -} - - -/* - * Initialize the input modules to read a scan of compressed data. - * The first call to this is done by jdmaster.c after initializing - * the entire decompressor (during jpeg_start_decompress). - * Subsequent calls come from consume_markers, below. - */ - -METHODDEF(void) -start_input_pass (j_decompress_ptr cinfo) -{ - per_scan_setup(cinfo); - latch_quant_tables(cinfo); - (*cinfo->entropy->start_pass) (cinfo); - (*cinfo->coef->start_input_pass) (cinfo); - cinfo->inputctl->consume_input = cinfo->coef->consume_data; -} - - -/* - * Finish up after inputting a compressed-data scan. - * This is called by the coefficient controller after it's read all - * the expected data of the scan. - */ - -METHODDEF(void) -finish_input_pass (j_decompress_ptr cinfo) -{ - (*cinfo->entropy->finish_pass) (cinfo); - cinfo->inputctl->consume_input = consume_markers; -} - - -/* - * Read JPEG markers before, between, or after compressed-data scans. - * Change state as necessary when a new scan is reached. - * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. - * - * The consume_input method pointer points either here or to the - * coefficient controller's consume_data routine, depending on whether - * we are reading a compressed data segment or inter-segment markers. - * - * Note: This function should NOT return a pseudo SOS marker (with zero - * component number) to the caller. A pseudo marker received by - * read_markers is processed and then skipped for other markers. - */ - -METHODDEF(int) -consume_markers (j_decompress_ptr cinfo) -{ - my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; - int val; - - if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ - return JPEG_REACHED_EOI; - - for (;;) { /* Loop to pass pseudo SOS marker */ - val = (*cinfo->marker->read_markers) (cinfo); - - switch (val) { - case JPEG_REACHED_SOS: /* Found SOS */ - if (inputctl->inheaders) { /* 1st SOS */ - if (inputctl->inheaders == 1) - initial_setup(cinfo); - if (cinfo->comps_in_scan == 0) { /* pseudo SOS marker */ - inputctl->inheaders = 2; - break; - } - inputctl->inheaders = 0; - /* Note: start_input_pass must be called by jdmaster.c - * before any more input can be consumed. jdapimin.c is - * responsible for enforcing this sequencing. - */ - } else { /* 2nd or later SOS marker */ - if (! inputctl->pub.has_multiple_scans) - ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ - if (cinfo->comps_in_scan == 0) /* unexpected pseudo SOS marker */ - break; - start_input_pass(cinfo); - } - return val; - case JPEG_REACHED_EOI: /* Found EOI */ - inputctl->pub.eoi_reached = TRUE; - if (inputctl->inheaders) { /* Tables-only datastream, apparently */ - if (cinfo->marker->saw_SOF) - ERREXIT(cinfo, JERR_SOF_NO_SOS); - } else { - /* Prevent infinite loop in coef ctlr's decompress_data routine - * if user set output_scan_number larger than number of scans. - */ - if (cinfo->output_scan_number > cinfo->input_scan_number) - cinfo->output_scan_number = cinfo->input_scan_number; - } - return val; - case JPEG_SUSPENDED: - return val; - default: - return val; - } - } -} - - -/* - * Reset state to begin a fresh datastream. - */ - -METHODDEF(void) -reset_input_controller (j_decompress_ptr cinfo) -{ - my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; - - inputctl->pub.consume_input = consume_markers; - inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ - inputctl->pub.eoi_reached = FALSE; - inputctl->inheaders = 1; - /* Reset other modules */ - (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); - (*cinfo->marker->reset_marker_reader) (cinfo); - /* Reset progression state -- would be cleaner if entropy decoder did this */ - cinfo->coef_bits = NULL; -} - - -/* - * Initialize the input controller module. - * This is called only once, when the decompression object is created. - */ - -GLOBAL(void) -jinit_input_controller (j_decompress_ptr cinfo) -{ - my_inputctl_ptr inputctl; - - /* Create subobject in permanent pool */ - inputctl = (my_inputctl_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - SIZEOF(my_input_controller)); - cinfo->inputctl = &inputctl->pub; - /* Initialize method pointers */ - inputctl->pub.consume_input = consume_markers; - inputctl->pub.reset_input_controller = reset_input_controller; - inputctl->pub.start_input_pass = start_input_pass; - inputctl->pub.finish_input_pass = finish_input_pass; - /* Initialize state: can't use reset_input_controller since we don't - * want to try to reset other modules yet. - */ - inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ - inputctl->pub.eoi_reached = FALSE; - inputctl->inheaders = 1; -} diff --git a/libraries/jpeg/jdmainct.c b/libraries/jpeg/jdmainct.c deleted file mode 100644 index 4d738fbaed6..00000000000 --- a/libraries/jpeg/jdmainct.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * jdmainct.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2002-2016 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the main buffer controller for decompression. - * The main buffer lies between the JPEG decompressor proper and the - * post-processor; it holds downsampled data in the JPEG colorspace. - * - * Note that this code is bypassed in raw-data mode, since the application - * supplies the equivalent of the main buffer in that case. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * In the current system design, the main buffer need never be a full-image - * buffer; any full-height buffers will be found inside the coefficient or - * postprocessing controllers. Nonetheless, the main controller is not - * trivial. Its responsibility is to provide context rows for upsampling/ - * rescaling, and doing this in an efficient fashion is a bit tricky. - * - * Postprocessor input data is counted in "row groups". A row group is - * defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size) - * sample rows of each component. (We require DCT_scaled_size values to be - * chosen such that these numbers are integers. In practice DCT_scaled_size - * values will likely be powers of two, so we actually have the stronger - * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) - * Upsampling will typically produce max_v_samp_factor pixel rows from each - * row group (times any additional scale factor that the upsampler is - * applying). - * - * The coefficient controller will deliver data to us one iMCU row at a time; - * each iMCU row contains v_samp_factor * DCT_v_scaled_size sample rows, or - * exactly min_DCT_v_scaled_size row groups. (This amount of data corresponds - * to one row of MCUs when the image is fully interleaved.) Note that the - * number of sample rows varies across components, but the number of row - * groups does not. Some garbage sample rows may be included in the last iMCU - * row at the bottom of the image. - * - * Depending on the vertical scaling algorithm used, the upsampler may need - * access to the sample row(s) above and below its current input row group. - * The upsampler is required to set need_context_rows TRUE at global selection - * time if so. When need_context_rows is FALSE, this controller can simply - * obtain one iMCU row at a time from the coefficient controller and dole it - * out as row groups to the postprocessor. - * - * When need_context_rows is TRUE, this controller guarantees that the buffer - * passed to postprocessing contains at least one row group's worth of samples - * above and below the row group(s) being processed. Note that the context - * rows "above" the first passed row group appear at negative row offsets in - * the passed buffer. At the top and bottom of the image, the required - * context rows are manufactured by duplicating the first or last real sample - * row; this avoids having special cases in the upsampling inner loops. - * - * The amount of context is fixed at one row group just because that's a - * convenient number for this controller to work with. The existing - * upsamplers really only need one sample row of context. An upsampler - * supporting arbitrary output rescaling might wish for more than one row - * group of context when shrinking the image; tough, we don't handle that. - * (This is justified by the assumption that downsizing will be handled mostly - * by adjusting the DCT_scaled_size values, so that the actual scale factor at - * the upsample step needn't be much less than one.) - * - * To provide the desired context, we have to retain the last two row groups - * of one iMCU row while reading in the next iMCU row. (The last row group - * can't be processed until we have another row group for its below-context, - * and so we have to save the next-to-last group too for its above-context.) - * We could do this most simply by copying data around in our buffer, but - * that'd be very slow. We can avoid copying any data by creating a rather - * strange pointer structure. Here's how it works. We allocate a workspace - * consisting of M+2 row groups (where M = min_DCT_v_scaled_size is the number - * of row groups per iMCU row). We create two sets of redundant pointers to - * the workspace. Labeling the physical row groups 0 to M+1, the synthesized - * pointer lists look like this: - * M+1 M-1 - * master pointer --> 0 master pointer --> 0 - * 1 1 - * ... ... - * M-3 M-3 - * M-2 M - * M-1 M+1 - * M M-2 - * M+1 M-1 - * 0 0 - * We read alternate iMCU rows using each master pointer; thus the last two - * row groups of the previous iMCU row remain un-overwritten in the workspace. - * The pointer lists are set up so that the required context rows appear to - * be adjacent to the proper places when we pass the pointer lists to the - * upsampler. - * - * The above pictures describe the normal state of the pointer lists. - * At top and bottom of the image, we diddle the pointer lists to duplicate - * the first or last sample row as necessary (this is cheaper than copying - * sample rows around). - * - * This scheme breaks down if M < 2, ie, min_DCT_v_scaled_size is 1. In that - * situation each iMCU row provides only one row group so the buffering logic - * must be different (eg, we must read two iMCU rows before we can emit the - * first row group). For now, we simply do not support providing context - * rows when min_DCT_v_scaled_size is 1. That combination seems unlikely to - * be worth providing --- if someone wants a 1/8th-size preview, they probably - * want it quick and dirty, so a context-free upsampler is sufficient. - */ - - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_d_main_controller pub; /* public fields */ - - /* Pointer to allocated workspace (M or M+2 row groups). */ - JSAMPARRAY buffer[MAX_COMPONENTS]; - - JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ - JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ - - /* Remaining fields are only used in the context case. */ - - boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ - - /* These are the master pointers to the funny-order pointer lists. */ - JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ - - int whichptr; /* indicates which pointer set is now in use */ - int context_state; /* process_data state machine status */ - JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ -} my_main_controller; - -typedef my_main_controller * my_main_ptr; - -/* context_state values: */ -#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ -#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ -#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ - - -/* Forward declarations */ -METHODDEF(void) process_data_simple_main - JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); -METHODDEF(void) process_data_context_main - JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); -#ifdef QUANT_2PASS_SUPPORTED -METHODDEF(void) process_data_crank_post - JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); -#endif - - -LOCAL(void) -alloc_funny_pointers (j_decompress_ptr cinfo) -/* Allocate space for the funny pointer lists. - * This is done only once, not once per pass. - */ -{ - my_main_ptr mainp = (my_main_ptr) cinfo->main; - int ci, rgroup; - int M = cinfo->min_DCT_v_scaled_size; - jpeg_component_info *compptr; - JSAMPARRAY xbuf; - - /* Get top-level space for component array pointers. - * We alloc both arrays with one call to save a few cycles. - */ - mainp->xbuffer[0] = (JSAMPIMAGE) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); - mainp->xbuffer[1] = mainp->xbuffer[0] + cinfo->num_components; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / - cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ - /* Get space for pointer lists --- M+4 row groups in each list. - * We alloc both pointer lists with one call to save a few cycles. - */ - xbuf = (JSAMPARRAY) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); - xbuf += rgroup; /* want one row group at negative offsets */ - mainp->xbuffer[0][ci] = xbuf; - xbuf += rgroup * (M + 4); - mainp->xbuffer[1][ci] = xbuf; - } -} - - -LOCAL(void) -make_funny_pointers (j_decompress_ptr cinfo) -/* Create the funny pointer lists discussed in the comments above. - * The actual workspace is already allocated (in mainp->buffer), - * and the space for the pointer lists is allocated too. - * This routine just fills in the curiously ordered lists. - * This will be repeated at the beginning of each pass. - */ -{ - my_main_ptr mainp = (my_main_ptr) cinfo->main; - int ci, i, rgroup; - int M = cinfo->min_DCT_v_scaled_size; - jpeg_component_info *compptr; - JSAMPARRAY buf, xbuf0, xbuf1; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / - cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ - xbuf0 = mainp->xbuffer[0][ci]; - xbuf1 = mainp->xbuffer[1][ci]; - /* First copy the workspace pointers as-is */ - buf = mainp->buffer[ci]; - for (i = 0; i < rgroup * (M + 2); i++) { - xbuf0[i] = xbuf1[i] = buf[i]; - } - /* In the second list, put the last four row groups in swapped order */ - for (i = 0; i < rgroup * 2; i++) { - xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; - xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; - } - /* The wraparound pointers at top and bottom will be filled later - * (see set_wraparound_pointers, below). Initially we want the "above" - * pointers to duplicate the first actual data line. This only needs - * to happen in xbuffer[0]. - */ - for (i = 0; i < rgroup; i++) { - xbuf0[i - rgroup] = xbuf0[0]; - } - } -} - - -LOCAL(void) -set_wraparound_pointers (j_decompress_ptr cinfo) -/* Set up the "wraparound" pointers at top and bottom of the pointer lists. - * This changes the pointer list state from top-of-image to the normal state. - */ -{ - my_main_ptr mainp = (my_main_ptr) cinfo->main; - int ci, i, rgroup; - int M = cinfo->min_DCT_v_scaled_size; - jpeg_component_info *compptr; - JSAMPARRAY xbuf0, xbuf1; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / - cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ - xbuf0 = mainp->xbuffer[0][ci]; - xbuf1 = mainp->xbuffer[1][ci]; - for (i = 0; i < rgroup; i++) { - xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; - xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; - xbuf0[rgroup*(M+2) + i] = xbuf0[i]; - xbuf1[rgroup*(M+2) + i] = xbuf1[i]; - } - } -} - - -LOCAL(void) -set_bottom_pointers (j_decompress_ptr cinfo) -/* Change the pointer lists to duplicate the last sample row at the bottom - * of the image. whichptr indicates which xbuffer holds the final iMCU row. - * Also sets rowgroups_avail to indicate number of nondummy row groups in row. - */ -{ - my_main_ptr mainp = (my_main_ptr) cinfo->main; - int ci, i, rgroup, iMCUheight, rows_left; - jpeg_component_info *compptr; - JSAMPARRAY xbuf; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Count sample rows in one iMCU row and in one row group */ - iMCUheight = compptr->v_samp_factor * compptr->DCT_v_scaled_size; - rgroup = iMCUheight / cinfo->min_DCT_v_scaled_size; - /* Count nondummy sample rows remaining for this component */ - rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); - if (rows_left == 0) rows_left = iMCUheight; - /* Count nondummy row groups. Should get same answer for each component, - * so we need only do it once. - */ - if (ci == 0) { - mainp->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); - } - /* Duplicate the last real sample row rgroup*2 times; this pads out the - * last partial rowgroup and ensures at least one full rowgroup of context. - */ - xbuf = mainp->xbuffer[mainp->whichptr][ci]; - for (i = 0; i < rgroup * 2; i++) { - xbuf[rows_left + i] = xbuf[rows_left-1]; - } - } -} - - -/* - * Initialize for a processing pass. - */ - -METHODDEF(void) -start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) -{ - my_main_ptr mainp = (my_main_ptr) cinfo->main; - - switch (pass_mode) { - case JBUF_PASS_THRU: - if (cinfo->upsample->need_context_rows) { - mainp->pub.process_data = process_data_context_main; - make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ - mainp->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ - mainp->context_state = CTX_PREPARE_FOR_IMCU; - mainp->iMCU_row_ctr = 0; - mainp->buffer_full = FALSE; /* Mark buffer empty */ - } else { - /* Simple case with no context needed */ - mainp->pub.process_data = process_data_simple_main; - mainp->rowgroup_ctr = mainp->rowgroups_avail; /* Mark buffer empty */ - } - break; -#ifdef QUANT_2PASS_SUPPORTED - case JBUF_CRANK_DEST: - /* For last pass of 2-pass quantization, just crank the postprocessor */ - mainp->pub.process_data = process_data_crank_post; - break; -#endif - default: - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - break; - } -} - - -/* - * Process some data. - * This handles the simple case where no context is required. - */ - -METHODDEF(void) -process_data_simple_main (j_decompress_ptr cinfo, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_main_ptr mainp = (my_main_ptr) cinfo->main; - - /* Read input data if we haven't filled the main buffer yet */ - if (mainp->rowgroup_ctr >= mainp->rowgroups_avail) { - if (! (*cinfo->coef->decompress_data) (cinfo, mainp->buffer)) - return; /* suspension forced, can do nothing more */ - mainp->rowgroup_ctr = 0; /* OK, we have an iMCU row to work with */ - } - - /* Note: at the bottom of the image, we may pass extra garbage row groups - * to the postprocessor. The postprocessor has to check for bottom - * of image anyway (at row resolution), so no point in us doing it too. - */ - - /* Feed the postprocessor */ - (*cinfo->post->post_process_data) (cinfo, mainp->buffer, - &mainp->rowgroup_ctr, mainp->rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); -} - - -/* - * Process some data. - * This handles the case where context rows must be provided. - */ - -METHODDEF(void) -process_data_context_main (j_decompress_ptr cinfo, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_main_ptr mainp = (my_main_ptr) cinfo->main; - - /* Read input data if we haven't filled the main buffer yet */ - if (! mainp->buffer_full) { - if (! (*cinfo->coef->decompress_data) (cinfo, - mainp->xbuffer[mainp->whichptr])) - return; /* suspension forced, can do nothing more */ - mainp->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ - mainp->iMCU_row_ctr++; /* count rows received */ - } - - /* Postprocessor typically will not swallow all the input data it is handed - * in one call (due to filling the output buffer first). Must be prepared - * to exit and restart. This switch lets us keep track of how far we got. - * Note that each case falls through to the next on successful completion. - */ - switch (mainp->context_state) { - case CTX_POSTPONED_ROW: - /* Call postprocessor using previously set pointers for postponed row */ - (*cinfo->post->post_process_data) (cinfo, mainp->xbuffer[mainp->whichptr], - &mainp->rowgroup_ctr, mainp->rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); - if (mainp->rowgroup_ctr < mainp->rowgroups_avail) - return; /* Need to suspend */ - mainp->context_state = CTX_PREPARE_FOR_IMCU; - if (*out_row_ctr >= out_rows_avail) - return; /* Postprocessor exactly filled output buf */ - /*FALLTHROUGH*/ - case CTX_PREPARE_FOR_IMCU: - /* Prepare to process first M-1 row groups of this iMCU row */ - mainp->rowgroup_ctr = 0; - mainp->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1); - /* Check for bottom of image: if so, tweak pointers to "duplicate" - * the last sample row, and adjust rowgroups_avail to ignore padding rows. - */ - if (mainp->iMCU_row_ctr == cinfo->total_iMCU_rows) - set_bottom_pointers(cinfo); - mainp->context_state = CTX_PROCESS_IMCU; - /*FALLTHROUGH*/ - case CTX_PROCESS_IMCU: - /* Call postprocessor using previously set pointers */ - (*cinfo->post->post_process_data) (cinfo, mainp->xbuffer[mainp->whichptr], - &mainp->rowgroup_ctr, mainp->rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); - if (mainp->rowgroup_ctr < mainp->rowgroups_avail) - return; /* Need to suspend */ - /* After the first iMCU, change wraparound pointers to normal state */ - if (mainp->iMCU_row_ctr == 1) - set_wraparound_pointers(cinfo); - /* Prepare to load new iMCU row using other xbuffer list */ - mainp->whichptr ^= 1; /* 0=>1 or 1=>0 */ - mainp->buffer_full = FALSE; - /* Still need to process last row group of this iMCU row, */ - /* which is saved at index M+1 of the other xbuffer */ - mainp->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1); - mainp->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2); - mainp->context_state = CTX_POSTPONED_ROW; - } -} - - -/* - * Process some data. - * Final pass of two-pass quantization: just call the postprocessor. - * Source data will be the postprocessor controller's internal buffer. - */ - -#ifdef QUANT_2PASS_SUPPORTED - -METHODDEF(void) -process_data_crank_post (j_decompress_ptr cinfo, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, - (JDIMENSION *) NULL, (JDIMENSION) 0, - output_buf, out_row_ctr, out_rows_avail); -} - -#endif /* QUANT_2PASS_SUPPORTED */ - - -/* - * Initialize main buffer controller. - */ - -GLOBAL(void) -jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) -{ - my_main_ptr mainp; - int ci, rgroup, ngroups; - jpeg_component_info *compptr; - - mainp = (my_main_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_main_controller)); - cinfo->main = &mainp->pub; - mainp->pub.start_pass = start_pass_main; - - if (need_full_buffer) /* shouldn't happen */ - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - - /* Allocate the workspace. - * ngroups is the number of row groups we need. - */ - if (cinfo->upsample->need_context_rows) { - if (cinfo->min_DCT_v_scaled_size < 2) /* unsupported, see comments above */ - ERREXIT(cinfo, JERR_NOTIMPL); - alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ - ngroups = cinfo->min_DCT_v_scaled_size + 2; - } else { - /* There are always min_DCT_v_scaled_size row groups in an iMCU row. */ - ngroups = cinfo->min_DCT_v_scaled_size; - mainp->rowgroups_avail = (JDIMENSION) ngroups; - } - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / - cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ - mainp->buffer[ci] = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size), - (JDIMENSION) (rgroup * ngroups)); - } -} diff --git a/libraries/jpeg/jdmarker.c b/libraries/jpeg/jdmarker.c deleted file mode 100644 index 3fbe5c16578..00000000000 --- a/libraries/jpeg/jdmarker.c +++ /dev/null @@ -1,1511 +0,0 @@ -/* - * jdmarker.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * Modified 2009-2013 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains routines to decode JPEG datastream markers. - * Most of the complexity arises from our desire to support input - * suspension: if not all of the data for a marker is available, - * we must exit back to the application. On resumption, we reprocess - * the marker. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -typedef enum { /* JPEG marker codes */ - M_SOF0 = 0xc0, - M_SOF1 = 0xc1, - M_SOF2 = 0xc2, - M_SOF3 = 0xc3, - - M_SOF5 = 0xc5, - M_SOF6 = 0xc6, - M_SOF7 = 0xc7, - - M_JPG = 0xc8, - M_SOF9 = 0xc9, - M_SOF10 = 0xca, - M_SOF11 = 0xcb, - - M_SOF13 = 0xcd, - M_SOF14 = 0xce, - M_SOF15 = 0xcf, - - M_DHT = 0xc4, - - M_DAC = 0xcc, - - M_RST0 = 0xd0, - M_RST1 = 0xd1, - M_RST2 = 0xd2, - M_RST3 = 0xd3, - M_RST4 = 0xd4, - M_RST5 = 0xd5, - M_RST6 = 0xd6, - M_RST7 = 0xd7, - - M_SOI = 0xd8, - M_EOI = 0xd9, - M_SOS = 0xda, - M_DQT = 0xdb, - M_DNL = 0xdc, - M_DRI = 0xdd, - M_DHP = 0xde, - M_EXP = 0xdf, - - M_APP0 = 0xe0, - M_APP1 = 0xe1, - M_APP2 = 0xe2, - M_APP3 = 0xe3, - M_APP4 = 0xe4, - M_APP5 = 0xe5, - M_APP6 = 0xe6, - M_APP7 = 0xe7, - M_APP8 = 0xe8, - M_APP9 = 0xe9, - M_APP10 = 0xea, - M_APP11 = 0xeb, - M_APP12 = 0xec, - M_APP13 = 0xed, - M_APP14 = 0xee, - M_APP15 = 0xef, - - M_JPG0 = 0xf0, - M_JPG8 = 0xf8, - M_JPG13 = 0xfd, - M_COM = 0xfe, - - M_TEM = 0x01, - - M_ERROR = 0x100 -} JPEG_MARKER; - - -/* Private state */ - -typedef struct { - struct jpeg_marker_reader pub; /* public fields */ - - /* Application-overridable marker processing methods */ - jpeg_marker_parser_method process_COM; - jpeg_marker_parser_method process_APPn[16]; - - /* Limit on marker data length to save for each marker type */ - unsigned int length_limit_COM; - unsigned int length_limit_APPn[16]; - - /* Status of COM/APPn marker saving */ - jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ - unsigned int bytes_read; /* data bytes read so far in marker */ - /* Note: cur_marker is not linked into marker_list until it's all read. */ -} my_marker_reader; - -typedef my_marker_reader * my_marker_ptr; - - -/* - * Macros for fetching data from the data source module. - * - * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect - * the current restart point; we update them only when we have reached a - * suitable place to restart if a suspension occurs. - */ - -/* Declare and initialize local copies of input pointer/count */ -#define INPUT_VARS(cinfo) \ - struct jpeg_source_mgr * datasrc = (cinfo)->src; \ - const JOCTET * next_input_byte = datasrc->next_input_byte; \ - size_t bytes_in_buffer = datasrc->bytes_in_buffer - -/* Unload the local copies --- do this only at a restart boundary */ -#define INPUT_SYNC(cinfo) \ - ( datasrc->next_input_byte = next_input_byte, \ - datasrc->bytes_in_buffer = bytes_in_buffer ) - -/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ -#define INPUT_RELOAD(cinfo) \ - ( next_input_byte = datasrc->next_input_byte, \ - bytes_in_buffer = datasrc->bytes_in_buffer ) - -/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. - * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - * but we must reload the local copies after a successful fill. - */ -#define MAKE_BYTE_AVAIL(cinfo,action) \ - if (bytes_in_buffer == 0) { \ - if (! (*datasrc->fill_input_buffer) (cinfo)) \ - { action; } \ - INPUT_RELOAD(cinfo); \ - } - -/* Read a byte into variable V. - * If must suspend, take the specified action (typically "return FALSE"). - */ -#define INPUT_BYTE(cinfo,V,action) \ - MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ - bytes_in_buffer--; \ - V = GETJOCTET(*next_input_byte++); ) - -/* As above, but read two bytes interpreted as an unsigned 16-bit integer. - * V should be declared unsigned int or perhaps INT32. - */ -#define INPUT_2BYTES(cinfo,V,action) \ - MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ - bytes_in_buffer--; \ - V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ - MAKE_BYTE_AVAIL(cinfo,action); \ - bytes_in_buffer--; \ - V += GETJOCTET(*next_input_byte++); ) - - -/* - * Routines to process JPEG markers. - * - * Entry condition: JPEG marker itself has been read and its code saved - * in cinfo->unread_marker; input restart point is just after the marker. - * - * Exit: if return TRUE, have read and processed any parameters, and have - * updated the restart point to point after the parameters. - * If return FALSE, was forced to suspend before reaching end of - * marker parameters; restart point has not been moved. Same routine - * will be called again after application supplies more input data. - * - * This approach to suspension assumes that all of a marker's parameters - * can fit into a single input bufferload. This should hold for "normal" - * markers. Some COM/APPn markers might have large parameter segments - * that might not fit. If we are simply dropping such a marker, we use - * skip_input_data to get past it, and thereby put the problem on the - * source manager's shoulders. If we are saving the marker's contents - * into memory, we use a slightly different convention: when forced to - * suspend, the marker processor updates the restart point to the end of - * what it's consumed (ie, the end of the buffer) before returning FALSE. - * On resumption, cinfo->unread_marker still contains the marker code, - * but the data source will point to the next chunk of marker data. - * The marker processor must retain internal state to deal with this. - * - * Note that we don't bother to avoid duplicate trace messages if a - * suspension occurs within marker parameters. Other side effects - * require more care. - */ - - -LOCAL(boolean) -get_soi (j_decompress_ptr cinfo) -/* Process an SOI marker */ -{ - int i; - - TRACEMS(cinfo, 1, JTRC_SOI); - - if (cinfo->marker->saw_SOI) - ERREXIT(cinfo, JERR_SOI_DUPLICATE); - - /* Reset all parameters that are defined to be reset by SOI */ - - for (i = 0; i < NUM_ARITH_TBLS; i++) { - cinfo->arith_dc_L[i] = 0; - cinfo->arith_dc_U[i] = 1; - cinfo->arith_ac_K[i] = 5; - } - cinfo->restart_interval = 0; - - /* Set initial assumptions for colorspace etc */ - - cinfo->jpeg_color_space = JCS_UNKNOWN; - cinfo->color_transform = JCT_NONE; - cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ - - cinfo->saw_JFIF_marker = FALSE; - cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */ - cinfo->JFIF_minor_version = 1; - cinfo->density_unit = 0; - cinfo->X_density = 1; - cinfo->Y_density = 1; - cinfo->saw_Adobe_marker = FALSE; - cinfo->Adobe_transform = 0; - - cinfo->marker->saw_SOI = TRUE; - - return TRUE; -} - - -LOCAL(boolean) -get_sof (j_decompress_ptr cinfo, boolean is_baseline, boolean is_prog, - boolean is_arith) -/* Process a SOFn marker */ -{ - INT32 length; - int c, ci, i; - jpeg_component_info * compptr; - INPUT_VARS(cinfo); - - cinfo->is_baseline = is_baseline; - cinfo->progressive_mode = is_prog; - cinfo->arith_code = is_arith; - - INPUT_2BYTES(cinfo, length, return FALSE); - - INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); - INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); - INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); - INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); - - length -= 8; - - TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, - (int) cinfo->image_width, (int) cinfo->image_height, - cinfo->num_components); - - if (cinfo->marker->saw_SOF) - ERREXIT(cinfo, JERR_SOF_DUPLICATE); - - /* We don't support files in which the image height is initially specified */ - /* as 0 and is later redefined by DNL. As long as we have to check that, */ - /* might as well have a general sanity check. */ - if (cinfo->image_height <= 0 || cinfo->image_width <= 0 || - cinfo->num_components <= 0) - ERREXIT(cinfo, JERR_EMPTY_IMAGE); - - if (length != (cinfo->num_components * 3)) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - if (cinfo->comp_info == NULL) /* do only once, even if suspend */ - cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components * SIZEOF(jpeg_component_info)); - - for (ci = 0; ci < cinfo->num_components; ci++) { - INPUT_BYTE(cinfo, c, return FALSE); - /* Check to see whether component id has already been seen */ - /* (in violation of the spec, but unfortunately seen in some */ - /* files). If so, create "fake" component id equal to the */ - /* max id seen so far + 1. */ - for (i = 0, compptr = cinfo->comp_info; i < ci; i++, compptr++) { - if (c == compptr->component_id) { - compptr = cinfo->comp_info; - c = compptr->component_id; - compptr++; - for (i = 1; i < ci; i++, compptr++) { - if (compptr->component_id > c) c = compptr->component_id; - } - c++; - break; - } - } - compptr->component_id = c; - compptr->component_index = ci; - INPUT_BYTE(cinfo, c, return FALSE); - compptr->h_samp_factor = (c >> 4) & 15; - compptr->v_samp_factor = (c ) & 15; - INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); - - TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, - compptr->component_id, compptr->h_samp_factor, - compptr->v_samp_factor, compptr->quant_tbl_no); - } - - cinfo->marker->saw_SOF = TRUE; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -get_sos (j_decompress_ptr cinfo) -/* Process a SOS marker */ -{ - INT32 length; - int c, ci, i, n; - jpeg_component_info * compptr; - INPUT_VARS(cinfo); - - if (! cinfo->marker->saw_SOF) - ERREXITS(cinfo, JERR_SOF_BEFORE, "SOS"); - - INPUT_2BYTES(cinfo, length, return FALSE); - - INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ - - TRACEMS1(cinfo, 1, JTRC_SOS, n); - - if (length != (n * 2 + 6) || n > MAX_COMPS_IN_SCAN || - (n == 0 && !cinfo->progressive_mode)) - /* pseudo SOS marker only allowed in progressive mode */ - ERREXIT(cinfo, JERR_BAD_LENGTH); - - cinfo->comps_in_scan = n; - - /* Collect the component-spec parameters */ - - for (i = 0; i < n; i++) { - INPUT_BYTE(cinfo, c, return FALSE); - - /* Detect the case where component id's are not unique, and, if so, */ - /* create a fake component id using the same logic as in get_sof. */ - /* Note: This also ensures that all of the SOF components are */ - /* referenced in the single scan case, which prevents access to */ - /* uninitialized memory in later decoding stages. */ - for (ci = 0; ci < i; ci++) { - if (c == cinfo->cur_comp_info[ci]->component_id) { - c = cinfo->cur_comp_info[0]->component_id; - for (ci = 1; ci < i; ci++) { - compptr = cinfo->cur_comp_info[ci]; - if (compptr->component_id > c) c = compptr->component_id; - } - c++; - break; - } - } - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - if (c == compptr->component_id) - goto id_found; - } - - ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, c); - - id_found: - - cinfo->cur_comp_info[i] = compptr; - INPUT_BYTE(cinfo, c, return FALSE); - compptr->dc_tbl_no = (c >> 4) & 15; - compptr->ac_tbl_no = (c ) & 15; - - TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, compptr->component_id, - compptr->dc_tbl_no, compptr->ac_tbl_no); - } - - /* Collect the additional scan parameters Ss, Se, Ah/Al. */ - INPUT_BYTE(cinfo, c, return FALSE); - cinfo->Ss = c; - INPUT_BYTE(cinfo, c, return FALSE); - cinfo->Se = c; - INPUT_BYTE(cinfo, c, return FALSE); - cinfo->Ah = (c >> 4) & 15; - cinfo->Al = (c ) & 15; - - TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, - cinfo->Ah, cinfo->Al); - - /* Prepare to scan data & restart markers */ - cinfo->marker->next_restart_num = 0; - - /* Count another (non-pseudo) SOS marker */ - if (n) cinfo->input_scan_number++; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -#ifdef D_ARITH_CODING_SUPPORTED - -LOCAL(boolean) -get_dac (j_decompress_ptr cinfo) -/* Process a DAC marker */ -{ - INT32 length; - int index, val; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - while (length > 0) { - INPUT_BYTE(cinfo, index, return FALSE); - INPUT_BYTE(cinfo, val, return FALSE); - - length -= 2; - - TRACEMS2(cinfo, 1, JTRC_DAC, index, val); - - if (index < 0 || index >= (2*NUM_ARITH_TBLS)) - ERREXIT1(cinfo, JERR_DAC_INDEX, index); - - if (index >= NUM_ARITH_TBLS) { /* define AC table */ - cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; - } else { /* define DC table */ - cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); - cinfo->arith_dc_U[index] = (UINT8) (val >> 4); - if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) - ERREXIT1(cinfo, JERR_DAC_VALUE, val); - } - } - - if (length != 0) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_SYNC(cinfo); - return TRUE; -} - -#else /* ! D_ARITH_CODING_SUPPORTED */ - -#define get_dac(cinfo) skip_variable(cinfo) - -#endif /* D_ARITH_CODING_SUPPORTED */ - - -LOCAL(boolean) -get_dht (j_decompress_ptr cinfo) -/* Process a DHT marker */ -{ - INT32 length; - UINT8 bits[17]; - UINT8 huffval[256]; - int i, index, count; - JHUFF_TBL **htblptr; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - while (length > 16) { - INPUT_BYTE(cinfo, index, return FALSE); - - TRACEMS1(cinfo, 1, JTRC_DHT, index); - - bits[0] = 0; - count = 0; - for (i = 1; i <= 16; i++) { - INPUT_BYTE(cinfo, bits[i], return FALSE); - count += bits[i]; - } - - length -= 1 + 16; - - TRACEMS8(cinfo, 2, JTRC_HUFFBITS, - bits[1], bits[2], bits[3], bits[4], - bits[5], bits[6], bits[7], bits[8]); - TRACEMS8(cinfo, 2, JTRC_HUFFBITS, - bits[9], bits[10], bits[11], bits[12], - bits[13], bits[14], bits[15], bits[16]); - - /* Here we just do minimal validation of the counts to avoid walking - * off the end of our table space. jdhuff.c will check more carefully. - */ - if (count > 256 || ((INT32) count) > length) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - - MEMZERO(huffval, SIZEOF(huffval)); /* pre-zero array for later copy */ - - for (i = 0; i < count; i++) - INPUT_BYTE(cinfo, huffval[i], return FALSE); - - length -= count; - - if (index & 0x10) { /* AC table definition */ - index -= 0x10; - htblptr = &cinfo->ac_huff_tbl_ptrs[index]; - } else { /* DC table definition */ - htblptr = &cinfo->dc_huff_tbl_ptrs[index]; - } - - if (index < 0 || index >= NUM_HUFF_TBLS) - ERREXIT1(cinfo, JERR_DHT_INDEX, index); - - if (*htblptr == NULL) - *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); - - MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); - MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); - } - - if (length != 0) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -get_dqt (j_decompress_ptr cinfo) -/* Process a DQT marker */ -{ - INT32 length, count, i; - int n, prec; - unsigned int tmp; - JQUANT_TBL *quant_ptr; - const int *natural_order; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - while (length > 0) { - length--; - INPUT_BYTE(cinfo, n, return FALSE); - prec = n >> 4; - n &= 0x0F; - - TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); - - if (n >= NUM_QUANT_TBLS) - ERREXIT1(cinfo, JERR_DQT_INDEX, n); - - if (cinfo->quant_tbl_ptrs[n] == NULL) - cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); - quant_ptr = cinfo->quant_tbl_ptrs[n]; - - if (prec) { - if (length < DCTSIZE2 * 2) { - /* Initialize full table for safety. */ - for (i = 0; i < DCTSIZE2; i++) { - quant_ptr->quantval[i] = 1; - } - count = length >> 1; - } else - count = DCTSIZE2; - } else { - if (length < DCTSIZE2) { - /* Initialize full table for safety. */ - for (i = 0; i < DCTSIZE2; i++) { - quant_ptr->quantval[i] = 1; - } - count = length; - } else - count = DCTSIZE2; - } - - switch (count) { - case (2*2): natural_order = jpeg_natural_order2; break; - case (3*3): natural_order = jpeg_natural_order3; break; - case (4*4): natural_order = jpeg_natural_order4; break; - case (5*5): natural_order = jpeg_natural_order5; break; - case (6*6): natural_order = jpeg_natural_order6; break; - case (7*7): natural_order = jpeg_natural_order7; break; - default: natural_order = jpeg_natural_order; break; - } - - for (i = 0; i < count; i++) { - if (prec) - INPUT_2BYTES(cinfo, tmp, return FALSE); - else - INPUT_BYTE(cinfo, tmp, return FALSE); - /* We convert the zigzag-order table to natural array order. */ - quant_ptr->quantval[natural_order[i]] = (UINT16) tmp; - } - - if (cinfo->err->trace_level >= 2) { - for (i = 0; i < DCTSIZE2; i += 8) { - TRACEMS8(cinfo, 2, JTRC_QUANTVALS, - quant_ptr->quantval[i], quant_ptr->quantval[i+1], - quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], - quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], - quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); - } - } - - length -= count; - if (prec) length -= count; - } - - if (length != 0) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -get_dri (j_decompress_ptr cinfo) -/* Process a DRI marker */ -{ - INT32 length; - unsigned int tmp; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - - if (length != 4) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_2BYTES(cinfo, tmp, return FALSE); - - TRACEMS1(cinfo, 1, JTRC_DRI, tmp); - - cinfo->restart_interval = tmp; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -get_lse (j_decompress_ptr cinfo) -/* Process an LSE marker */ -{ - INT32 length; - unsigned int tmp; - int cid; - INPUT_VARS(cinfo); - - if (! cinfo->marker->saw_SOF) - ERREXITS(cinfo, JERR_SOF_BEFORE, "LSE"); - - if (cinfo->num_components < 3) goto bad; - - INPUT_2BYTES(cinfo, length, return FALSE); - - if (length != 24) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_BYTE(cinfo, tmp, return FALSE); - if (tmp != 0x0D) /* ID inverse transform specification */ - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); - INPUT_2BYTES(cinfo, tmp, return FALSE); - if (tmp != MAXJSAMPLE) goto bad; /* MAXTRANS */ - INPUT_BYTE(cinfo, tmp, return FALSE); - if (tmp != 3) goto bad; /* Nt=3 */ - INPUT_BYTE(cinfo, cid, return FALSE); - if (cid != cinfo->comp_info[1].component_id) goto bad; - INPUT_BYTE(cinfo, cid, return FALSE); - if (cid != cinfo->comp_info[0].component_id) goto bad; - INPUT_BYTE(cinfo, cid, return FALSE); - if (cid != cinfo->comp_info[2].component_id) goto bad; - INPUT_BYTE(cinfo, tmp, return FALSE); - if (tmp != 0x80) goto bad; /* F1: CENTER1=1, NORM1=0 */ - INPUT_2BYTES(cinfo, tmp, return FALSE); - if (tmp != 0) goto bad; /* A(1,1)=0 */ - INPUT_2BYTES(cinfo, tmp, return FALSE); - if (tmp != 0) goto bad; /* A(1,2)=0 */ - INPUT_BYTE(cinfo, tmp, return FALSE); - if (tmp != 0) goto bad; /* F2: CENTER2=0, NORM2=0 */ - INPUT_2BYTES(cinfo, tmp, return FALSE); - if (tmp != 1) goto bad; /* A(2,1)=1 */ - INPUT_2BYTES(cinfo, tmp, return FALSE); - if (tmp != 0) goto bad; /* A(2,2)=0 */ - INPUT_BYTE(cinfo, tmp, return FALSE); - if (tmp != 0) goto bad; /* F3: CENTER3=0, NORM3=0 */ - INPUT_2BYTES(cinfo, tmp, return FALSE); - if (tmp != 1) goto bad; /* A(3,1)=1 */ - INPUT_2BYTES(cinfo, tmp, return FALSE); - if (tmp != 0) { /* A(3,2)=0 */ - bad: - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - } - - /* OK, valid transform that we can handle. */ - cinfo->color_transform = JCT_SUBTRACT_GREEN; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -/* - * Routines for processing APPn and COM markers. - * These are either saved in memory or discarded, per application request. - * APP0 and APP14 are specially checked to see if they are - * JFIF and Adobe markers, respectively. - */ - -#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */ -#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */ -#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */ - - -LOCAL(void) -examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data, - unsigned int datalen, INT32 remaining) -/* Examine first few bytes from an APP0. - * Take appropriate action if it is a JFIF marker. - * datalen is # of bytes at data[], remaining is length of rest of marker data. - */ -{ - INT32 totallen = (INT32) datalen + remaining; - - if (datalen >= APP0_DATA_LEN && - GETJOCTET(data[0]) == 0x4A && - GETJOCTET(data[1]) == 0x46 && - GETJOCTET(data[2]) == 0x49 && - GETJOCTET(data[3]) == 0x46 && - GETJOCTET(data[4]) == 0) { - /* Found JFIF APP0 marker: save info */ - cinfo->saw_JFIF_marker = TRUE; - cinfo->JFIF_major_version = GETJOCTET(data[5]); - cinfo->JFIF_minor_version = GETJOCTET(data[6]); - cinfo->density_unit = GETJOCTET(data[7]); - cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]); - cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]); - /* Check version. - * Major version must be 1 or 2, anything else signals an incompatible - * change. - * (We used to treat this as an error, but now it's a nonfatal warning, - * because some bozo at Hijaak couldn't read the spec.) - * Minor version should be 0..2, but process anyway if newer. - */ - if (cinfo->JFIF_major_version != 1 && cinfo->JFIF_major_version != 2) - WARNMS2(cinfo, JWRN_JFIF_MAJOR, - cinfo->JFIF_major_version, cinfo->JFIF_minor_version); - /* Generate trace messages */ - TRACEMS5(cinfo, 1, JTRC_JFIF, - cinfo->JFIF_major_version, cinfo->JFIF_minor_version, - cinfo->X_density, cinfo->Y_density, cinfo->density_unit); - /* Validate thumbnail dimensions and issue appropriate messages */ - if (GETJOCTET(data[12]) | GETJOCTET(data[13])) - TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, - GETJOCTET(data[12]), GETJOCTET(data[13])); - totallen -= APP0_DATA_LEN; - if (totallen != - ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3)) - TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen); - } else if (datalen >= 6 && - GETJOCTET(data[0]) == 0x4A && - GETJOCTET(data[1]) == 0x46 && - GETJOCTET(data[2]) == 0x58 && - GETJOCTET(data[3]) == 0x58 && - GETJOCTET(data[4]) == 0) { - /* Found JFIF "JFXX" extension APP0 marker */ - /* The library doesn't actually do anything with these, - * but we try to produce a helpful trace message. - */ - switch (GETJOCTET(data[5])) { - case 0x10: - TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen); - break; - case 0x11: - TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen); - break; - case 0x13: - TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen); - break; - default: - TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, - GETJOCTET(data[5]), (int) totallen); - break; - } - } else { - /* Start of APP0 does not match "JFIF" or "JFXX", or too short */ - TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen); - } -} - - -LOCAL(void) -examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data, - unsigned int datalen, INT32 remaining) -/* Examine first few bytes from an APP14. - * Take appropriate action if it is an Adobe marker. - * datalen is # of bytes at data[], remaining is length of rest of marker data. - */ -{ - unsigned int version, flags0, flags1, transform; - - if (datalen >= APP14_DATA_LEN && - GETJOCTET(data[0]) == 0x41 && - GETJOCTET(data[1]) == 0x64 && - GETJOCTET(data[2]) == 0x6F && - GETJOCTET(data[3]) == 0x62 && - GETJOCTET(data[4]) == 0x65) { - /* Found Adobe APP14 marker */ - version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]); - flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]); - flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]); - transform = GETJOCTET(data[11]); - TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); - cinfo->saw_Adobe_marker = TRUE; - cinfo->Adobe_transform = (UINT8) transform; - } else { - /* Start of APP14 does not match "Adobe", or too short */ - TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining)); - } -} - - -METHODDEF(boolean) -get_interesting_appn (j_decompress_ptr cinfo) -/* Process an APP0 or APP14 marker without saving it */ -{ - INT32 length; - JOCTET b[APPN_DATA_LEN]; - unsigned int i, numtoread; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - /* get the interesting part of the marker data */ - if (length >= APPN_DATA_LEN) - numtoread = APPN_DATA_LEN; - else if (length > 0) - numtoread = (unsigned int) length; - else - numtoread = 0; - for (i = 0; i < numtoread; i++) - INPUT_BYTE(cinfo, b[i], return FALSE); - length -= numtoread; - - /* process it */ - switch (cinfo->unread_marker) { - case M_APP0: - examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length); - break; - case M_APP14: - examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length); - break; - default: - /* can't get here unless jpeg_save_markers chooses wrong processor */ - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); - break; - } - - /* skip any remaining data -- could be lots */ - INPUT_SYNC(cinfo); - if (length > 0) - (*cinfo->src->skip_input_data) (cinfo, (long) length); - - return TRUE; -} - - -#ifdef SAVE_MARKERS_SUPPORTED - -METHODDEF(boolean) -save_marker (j_decompress_ptr cinfo) -/* Save an APPn or COM marker into the marker list */ -{ - my_marker_ptr marker = (my_marker_ptr) cinfo->marker; - jpeg_saved_marker_ptr cur_marker = marker->cur_marker; - unsigned int bytes_read, data_length; - JOCTET FAR * data; - INT32 length = 0; - INPUT_VARS(cinfo); - - if (cur_marker == NULL) { - /* begin reading a marker */ - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - if (length >= 0) { /* watch out for bogus length word */ - /* figure out how much we want to save */ - unsigned int limit; - if (cinfo->unread_marker == (int) M_COM) - limit = marker->length_limit_COM; - else - limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0]; - if ((unsigned int) length < limit) - limit = (unsigned int) length; - /* allocate and initialize the marker item */ - cur_marker = (jpeg_saved_marker_ptr) - (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(struct jpeg_marker_struct) + limit); - cur_marker->next = NULL; - cur_marker->marker = (UINT8) cinfo->unread_marker; - cur_marker->original_length = (unsigned int) length; - cur_marker->data_length = limit; - /* data area is just beyond the jpeg_marker_struct */ - data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1); - marker->cur_marker = cur_marker; - marker->bytes_read = 0; - bytes_read = 0; - data_length = limit; - } else { - /* deal with bogus length word */ - bytes_read = data_length = 0; - data = NULL; - } - } else { - /* resume reading a marker */ - bytes_read = marker->bytes_read; - data_length = cur_marker->data_length; - data = cur_marker->data + bytes_read; - } - - while (bytes_read < data_length) { - INPUT_SYNC(cinfo); /* move the restart point to here */ - marker->bytes_read = bytes_read; - /* If there's not at least one byte in buffer, suspend */ - MAKE_BYTE_AVAIL(cinfo, return FALSE); - /* Copy bytes with reasonable rapidity */ - while (bytes_read < data_length && bytes_in_buffer > 0) { - *data++ = *next_input_byte++; - bytes_in_buffer--; - bytes_read++; - } - } - - /* Done reading what we want to read */ - if (cur_marker != NULL) { /* will be NULL if bogus length word */ - /* Add new marker to end of list */ - if (cinfo->marker_list == NULL) { - cinfo->marker_list = cur_marker; - } else { - jpeg_saved_marker_ptr prev = cinfo->marker_list; - while (prev->next != NULL) - prev = prev->next; - prev->next = cur_marker; - } - /* Reset pointer & calc remaining data length */ - data = cur_marker->data; - length = cur_marker->original_length - data_length; - } - /* Reset to initial state for next marker */ - marker->cur_marker = NULL; - - /* Process the marker if interesting; else just make a generic trace msg */ - switch (cinfo->unread_marker) { - case M_APP0: - examine_app0(cinfo, data, data_length, length); - break; - case M_APP14: - examine_app14(cinfo, data, data_length, length); - break; - default: - TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, - (int) (data_length + length)); - break; - } - - /* skip any remaining data -- could be lots */ - INPUT_SYNC(cinfo); /* do before skip_input_data */ - if (length > 0) - (*cinfo->src->skip_input_data) (cinfo, (long) length); - - return TRUE; -} - -#endif /* SAVE_MARKERS_SUPPORTED */ - - -METHODDEF(boolean) -skip_variable (j_decompress_ptr cinfo) -/* Skip over an unknown or uninteresting variable-length marker */ -{ - INT32 length; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); - - INPUT_SYNC(cinfo); /* do before skip_input_data */ - if (length > 0) - (*cinfo->src->skip_input_data) (cinfo, (long) length); - - return TRUE; -} - - -/* - * Find the next JPEG marker, save it in cinfo->unread_marker. - * Returns FALSE if had to suspend before reaching a marker; - * in that case cinfo->unread_marker is unchanged. - * - * Note that the result might not be a valid marker code, - * but it will never be 0 or FF. - */ - -LOCAL(boolean) -next_marker (j_decompress_ptr cinfo) -{ - int c; - INPUT_VARS(cinfo); - - for (;;) { - INPUT_BYTE(cinfo, c, return FALSE); - /* Skip any non-FF bytes. - * This may look a bit inefficient, but it will not occur in a valid file. - * We sync after each discarded byte so that a suspending data source - * can discard the byte from its buffer. - */ - while (c != 0xFF) { - cinfo->marker->discarded_bytes++; - INPUT_SYNC(cinfo); - INPUT_BYTE(cinfo, c, return FALSE); - } - /* This loop swallows any duplicate FF bytes. Extra FFs are legal as - * pad bytes, so don't count them in discarded_bytes. We assume there - * will not be so many consecutive FF bytes as to overflow a suspending - * data source's input buffer. - */ - do { - INPUT_BYTE(cinfo, c, return FALSE); - } while (c == 0xFF); - if (c != 0) - break; /* found a valid marker, exit loop */ - /* Reach here if we found a stuffed-zero data sequence (FF/00). - * Discard it and loop back to try again. - */ - cinfo->marker->discarded_bytes += 2; - INPUT_SYNC(cinfo); - } - - if (cinfo->marker->discarded_bytes != 0) { - WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); - cinfo->marker->discarded_bytes = 0; - } - - cinfo->unread_marker = c; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -first_marker (j_decompress_ptr cinfo) -/* Like next_marker, but used to obtain the initial SOI marker. */ -/* For this marker, we do not allow preceding garbage or fill; otherwise, - * we might well scan an entire input file before realizing it ain't JPEG. - * If an application wants to process non-JFIF files, it must seek to the - * SOI before calling the JPEG library. - */ -{ - int c, c2; - INPUT_VARS(cinfo); - - INPUT_BYTE(cinfo, c, return FALSE); - INPUT_BYTE(cinfo, c2, return FALSE); - if (c != 0xFF || c2 != (int) M_SOI) - ERREXIT2(cinfo, JERR_NO_SOI, c, c2); - - cinfo->unread_marker = c2; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -/* - * Read markers until SOS or EOI. - * - * Returns same codes as are defined for jpeg_consume_input: - * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. - * - * Note: This function may return a pseudo SOS marker (with zero - * component number) for treat by input controller's consume_input. - * consume_input itself should filter out (skip) the pseudo marker - * after processing for the caller. - */ - -METHODDEF(int) -read_markers (j_decompress_ptr cinfo) -{ - /* Outer loop repeats once for each marker. */ - for (;;) { - /* Collect the marker proper, unless we already did. */ - /* NB: first_marker() enforces the requirement that SOI appear first. */ - if (cinfo->unread_marker == 0) { - if (! cinfo->marker->saw_SOI) { - if (! first_marker(cinfo)) - return JPEG_SUSPENDED; - } else { - if (! next_marker(cinfo)) - return JPEG_SUSPENDED; - } - } - /* At this point cinfo->unread_marker contains the marker code and the - * input point is just past the marker proper, but before any parameters. - * A suspension will cause us to return with this state still true. - */ - switch (cinfo->unread_marker) { - case M_SOI: - if (! get_soi(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_SOF0: /* Baseline */ - if (! get_sof(cinfo, TRUE, FALSE, FALSE)) - return JPEG_SUSPENDED; - break; - - case M_SOF1: /* Extended sequential, Huffman */ - if (! get_sof(cinfo, FALSE, FALSE, FALSE)) - return JPEG_SUSPENDED; - break; - - case M_SOF2: /* Progressive, Huffman */ - if (! get_sof(cinfo, FALSE, TRUE, FALSE)) - return JPEG_SUSPENDED; - break; - - case M_SOF9: /* Extended sequential, arithmetic */ - if (! get_sof(cinfo, FALSE, FALSE, TRUE)) - return JPEG_SUSPENDED; - break; - - case M_SOF10: /* Progressive, arithmetic */ - if (! get_sof(cinfo, FALSE, TRUE, TRUE)) - return JPEG_SUSPENDED; - break; - - /* Currently unsupported SOFn types */ - case M_SOF3: /* Lossless, Huffman */ - case M_SOF5: /* Differential sequential, Huffman */ - case M_SOF6: /* Differential progressive, Huffman */ - case M_SOF7: /* Differential lossless, Huffman */ - case M_JPG: /* Reserved for JPEG extensions */ - case M_SOF11: /* Lossless, arithmetic */ - case M_SOF13: /* Differential sequential, arithmetic */ - case M_SOF14: /* Differential progressive, arithmetic */ - case M_SOF15: /* Differential lossless, arithmetic */ - ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); - break; - - case M_SOS: - if (! get_sos(cinfo)) - return JPEG_SUSPENDED; - cinfo->unread_marker = 0; /* processed the marker */ - return JPEG_REACHED_SOS; - - case M_EOI: - TRACEMS(cinfo, 1, JTRC_EOI); - cinfo->unread_marker = 0; /* processed the marker */ - return JPEG_REACHED_EOI; - - case M_DAC: - if (! get_dac(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_DHT: - if (! get_dht(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_DQT: - if (! get_dqt(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_DRI: - if (! get_dri(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_JPG8: - if (! get_lse(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_APP0: - case M_APP1: - case M_APP2: - case M_APP3: - case M_APP4: - case M_APP5: - case M_APP6: - case M_APP7: - case M_APP8: - case M_APP9: - case M_APP10: - case M_APP11: - case M_APP12: - case M_APP13: - case M_APP14: - case M_APP15: - if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[ - cinfo->unread_marker - (int) M_APP0]) (cinfo)) - return JPEG_SUSPENDED; - break; - - case M_COM: - if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo)) - return JPEG_SUSPENDED; - break; - - case M_RST0: /* these are all parameterless */ - case M_RST1: - case M_RST2: - case M_RST3: - case M_RST4: - case M_RST5: - case M_RST6: - case M_RST7: - case M_TEM: - TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); - break; - - case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ - if (! skip_variable(cinfo)) - return JPEG_SUSPENDED; - break; - - default: /* must be DHP, EXP, JPGn, or RESn */ - /* For now, we treat the reserved markers as fatal errors since they are - * likely to be used to signal incompatible JPEG Part 3 extensions. - * Once the JPEG 3 version-number marker is well defined, this code - * ought to change! - */ - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); - break; - } - /* Successfully processed marker, so reset state variable */ - cinfo->unread_marker = 0; - } /* end loop */ -} - - -/* - * Read a restart marker, which is expected to appear next in the datastream; - * if the marker is not there, take appropriate recovery action. - * Returns FALSE if suspension is required. - * - * This is called by the entropy decoder after it has read an appropriate - * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder - * has already read a marker from the data source. Under normal conditions - * cinfo->unread_marker will be reset to 0 before returning; if not reset, - * it holds a marker which the decoder will be unable to read past. - */ - -METHODDEF(boolean) -read_restart_marker (j_decompress_ptr cinfo) -{ - /* Obtain a marker unless we already did. */ - /* Note that next_marker will complain if it skips any data. */ - if (cinfo->unread_marker == 0) { - if (! next_marker(cinfo)) - return FALSE; - } - - if (cinfo->unread_marker == - ((int) M_RST0 + cinfo->marker->next_restart_num)) { - /* Normal case --- swallow the marker and let entropy decoder continue */ - TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num); - cinfo->unread_marker = 0; - } else { - /* Uh-oh, the restart markers have been messed up. */ - /* Let the data source manager determine how to resync. */ - if (! (*cinfo->src->resync_to_restart) (cinfo, - cinfo->marker->next_restart_num)) - return FALSE; - } - - /* Update next-restart state */ - cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; - - return TRUE; -} - - -/* - * This is the default resync_to_restart method for data source managers - * to use if they don't have any better approach. Some data source managers - * may be able to back up, or may have additional knowledge about the data - * which permits a more intelligent recovery strategy; such managers would - * presumably supply their own resync method. - * - * read_restart_marker calls resync_to_restart if it finds a marker other than - * the restart marker it was expecting. (This code is *not* used unless - * a nonzero restart interval has been declared.) cinfo->unread_marker is - * the marker code actually found (might be anything, except 0 or FF). - * The desired restart marker number (0..7) is passed as a parameter. - * This routine is supposed to apply whatever error recovery strategy seems - * appropriate in order to position the input stream to the next data segment. - * Note that cinfo->unread_marker is treated as a marker appearing before - * the current data-source input point; usually it should be reset to zero - * before returning. - * Returns FALSE if suspension is required. - * - * This implementation is substantially constrained by wanting to treat the - * input as a data stream; this means we can't back up. Therefore, we have - * only the following actions to work with: - * 1. Simply discard the marker and let the entropy decoder resume at next - * byte of file. - * 2. Read forward until we find another marker, discarding intervening - * data. (In theory we could look ahead within the current bufferload, - * without having to discard data if we don't find the desired marker. - * This idea is not implemented here, in part because it makes behavior - * dependent on buffer size and chance buffer-boundary positions.) - * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). - * This will cause the entropy decoder to process an empty data segment, - * inserting dummy zeroes, and then we will reprocess the marker. - * - * #2 is appropriate if we think the desired marker lies ahead, while #3 is - * appropriate if the found marker is a future restart marker (indicating - * that we have missed the desired restart marker, probably because it got - * corrupted). - * We apply #2 or #3 if the found marker is a restart marker no more than - * two counts behind or ahead of the expected one. We also apply #2 if the - * found marker is not a legal JPEG marker code (it's certainly bogus data). - * If the found marker is a restart marker more than 2 counts away, we do #1 - * (too much risk that the marker is erroneous; with luck we will be able to - * resync at some future point). - * For any valid non-restart JPEG marker, we apply #3. This keeps us from - * overrunning the end of a scan. An implementation limited to single-scan - * files might find it better to apply #2 for markers other than EOI, since - * any other marker would have to be bogus data in that case. - */ - -GLOBAL(boolean) -jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) -{ - int marker = cinfo->unread_marker; - int action = 1; - - /* Always put up a warning. */ - WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); - - /* Outer loop handles repeated decision after scanning forward. */ - for (;;) { - if (marker < (int) M_SOF0) - action = 2; /* invalid marker */ - else if (marker < (int) M_RST0 || marker > (int) M_RST7) - action = 3; /* valid non-restart marker */ - else { - if (marker == ((int) M_RST0 + ((desired+1) & 7)) || - marker == ((int) M_RST0 + ((desired+2) & 7))) - action = 3; /* one of the next two expected restarts */ - else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || - marker == ((int) M_RST0 + ((desired-2) & 7))) - action = 2; /* a prior restart, so advance */ - else - action = 1; /* desired restart or too far away */ - } - TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); - switch (action) { - case 1: - /* Discard marker and let entropy decoder resume processing. */ - cinfo->unread_marker = 0; - return TRUE; - case 2: - /* Scan to the next marker, and repeat the decision loop. */ - if (! next_marker(cinfo)) - return FALSE; - marker = cinfo->unread_marker; - break; - case 3: - /* Return without advancing past this marker. */ - /* Entropy decoder will be forced to process an empty segment. */ - return TRUE; - } - } /* end loop */ -} - - -/* - * Reset marker processing state to begin a fresh datastream. - */ - -METHODDEF(void) -reset_marker_reader (j_decompress_ptr cinfo) -{ - my_marker_ptr marker = (my_marker_ptr) cinfo->marker; - - cinfo->comp_info = NULL; /* until allocated by get_sof */ - cinfo->input_scan_number = 0; /* no SOS seen yet */ - cinfo->unread_marker = 0; /* no pending marker */ - marker->pub.saw_SOI = FALSE; /* set internal state too */ - marker->pub.saw_SOF = FALSE; - marker->pub.discarded_bytes = 0; - marker->cur_marker = NULL; -} - - -/* - * Initialize the marker reader module. - * This is called only once, when the decompression object is created. - */ - -GLOBAL(void) -jinit_marker_reader (j_decompress_ptr cinfo) -{ - my_marker_ptr marker; - int i; - - /* Create subobject in permanent pool */ - marker = (my_marker_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - SIZEOF(my_marker_reader)); - cinfo->marker = &marker->pub; - /* Initialize public method pointers */ - marker->pub.reset_marker_reader = reset_marker_reader; - marker->pub.read_markers = read_markers; - marker->pub.read_restart_marker = read_restart_marker; - /* Initialize COM/APPn processing. - * By default, we examine and then discard APP0 and APP14, - * but simply discard COM and all other APPn. - */ - marker->process_COM = skip_variable; - marker->length_limit_COM = 0; - for (i = 0; i < 16; i++) { - marker->process_APPn[i] = skip_variable; - marker->length_limit_APPn[i] = 0; - } - marker->process_APPn[0] = get_interesting_appn; - marker->process_APPn[14] = get_interesting_appn; - /* Reset marker processing state */ - reset_marker_reader(cinfo); -} - - -/* - * Control saving of COM and APPn markers into marker_list. - */ - -#ifdef SAVE_MARKERS_SUPPORTED - -GLOBAL(void) -jpeg_save_markers (j_decompress_ptr cinfo, int marker_code, - unsigned int length_limit) -{ - my_marker_ptr marker = (my_marker_ptr) cinfo->marker; - long maxlength; - jpeg_marker_parser_method processor; - - /* Length limit mustn't be larger than what we can allocate - * (should only be a concern in a 16-bit environment). - */ - maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct); - if (((long) length_limit) > maxlength) - length_limit = (unsigned int) maxlength; - - /* Choose processor routine to use. - * APP0/APP14 have special requirements. - */ - if (length_limit) { - processor = save_marker; - /* If saving APP0/APP14, save at least enough for our internal use. */ - if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN) - length_limit = APP0_DATA_LEN; - else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN) - length_limit = APP14_DATA_LEN; - } else { - processor = skip_variable; - /* If discarding APP0/APP14, use our regular on-the-fly processor. */ - if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14) - processor = get_interesting_appn; - } - - if (marker_code == (int) M_COM) { - marker->process_COM = processor; - marker->length_limit_COM = length_limit; - } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) { - marker->process_APPn[marker_code - (int) M_APP0] = processor; - marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit; - } else - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); -} - -#endif /* SAVE_MARKERS_SUPPORTED */ - - -/* - * Install a special processing method for COM or APPn markers. - */ - -GLOBAL(void) -jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, - jpeg_marker_parser_method routine) -{ - my_marker_ptr marker = (my_marker_ptr) cinfo->marker; - - if (marker_code == (int) M_COM) - marker->process_COM = routine; - else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) - marker->process_APPn[marker_code - (int) M_APP0] = routine; - else - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); -} diff --git a/libraries/jpeg/jdmaster.c b/libraries/jpeg/jdmaster.c deleted file mode 100644 index 62c07671f77..00000000000 --- a/libraries/jpeg/jdmaster.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * jdmaster.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 2002-2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains master control logic for the JPEG decompressor. - * These routines are concerned with selecting the modules to be executed - * and with determining the number of passes and the work to be done in each - * pass. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private state */ - -typedef struct { - struct jpeg_decomp_master pub; /* public fields */ - - int pass_number; /* # of passes completed */ - - boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ - - /* Saved references to initialized quantizer modules, - * in case we need to switch modes. - */ - struct jpeg_color_quantizer * quantizer_1pass; - struct jpeg_color_quantizer * quantizer_2pass; -} my_decomp_master; - -typedef my_decomp_master * my_master_ptr; - - -/* - * Determine whether merged upsample/color conversion should be used. - * CRUCIAL: this must match the actual capabilities of jdmerge.c! - */ - -LOCAL(boolean) -use_merged_upsample (j_decompress_ptr cinfo) -{ -#ifdef UPSAMPLE_MERGING_SUPPORTED - /* Merging is the equivalent of plain box-filter upsampling. */ - /* The following condition is only needed if fancy shall select - * a different upsampling method. In our current implementation - * fancy only affects the DCT scaling, thus we can use fancy - * upsampling and merged upsample simultaneously, in particular - * with scaled DCT sizes larger than the default DCTSIZE. - */ -#if 0 - if (cinfo->do_fancy_upsampling) - return FALSE; -#endif - if (cinfo->CCIR601_sampling) - return FALSE; - /* jdmerge.c only supports YCC=>RGB color conversion */ - if ((cinfo->jpeg_color_space != JCS_YCbCr && - cinfo->jpeg_color_space != JCS_BG_YCC) || - cinfo->num_components != 3 || - cinfo->out_color_space != JCS_RGB || - cinfo->out_color_components != RGB_PIXELSIZE || - cinfo->color_transform) - return FALSE; - /* and it only handles 2h1v or 2h2v sampling ratios */ - if (cinfo->comp_info[0].h_samp_factor != 2 || - cinfo->comp_info[1].h_samp_factor != 1 || - cinfo->comp_info[2].h_samp_factor != 1 || - cinfo->comp_info[0].v_samp_factor > 2 || - cinfo->comp_info[1].v_samp_factor != 1 || - cinfo->comp_info[2].v_samp_factor != 1) - return FALSE; - /* furthermore, it doesn't work if we've scaled the IDCTs differently */ - if (cinfo->comp_info[0].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || - cinfo->comp_info[1].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || - cinfo->comp_info[2].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || - cinfo->comp_info[0].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size || - cinfo->comp_info[1].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size || - cinfo->comp_info[2].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size) - return FALSE; - /* ??? also need to test for upsample-time rescaling, when & if supported */ - return TRUE; /* by golly, it'll work... */ -#else - return FALSE; -#endif -} - - -/* - * Compute output image dimensions and related values. - * NOTE: this is exported for possible use by application. - * Hence it mustn't do anything that can't be done twice. - * Also note that it may be called before the master module is initialized! - */ - -GLOBAL(void) -jpeg_calc_output_dimensions (j_decompress_ptr cinfo) -/* Do computations that are needed before master selection phase. - * This function is used for full decompression. - */ -{ -#ifdef IDCT_SCALING_SUPPORTED - int ci; - jpeg_component_info *compptr; -#endif - - /* Prevent application from calling me at wrong times */ - if (cinfo->global_state != DSTATE_READY) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - /* Compute core output image dimensions and DCT scaling choices. */ - jpeg_core_output_dimensions(cinfo); - -#ifdef IDCT_SCALING_SUPPORTED - - /* In selecting the actual DCT scaling for each component, we try to - * scale up the chroma components via IDCT scaling rather than upsampling. - * This saves time if the upsampler gets to use 1:1 scaling. - * Note this code adapts subsampling ratios which are powers of 2. - */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - int ssize = 1; - while (cinfo->min_DCT_h_scaled_size * ssize <= - (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) && - (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) { - ssize = ssize * 2; - } - compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize; - ssize = 1; - while (cinfo->min_DCT_v_scaled_size * ssize <= - (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) && - (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) { - ssize = ssize * 2; - } - compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize; - - /* We don't support IDCT ratios larger than 2. */ - if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2) - compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2; - else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2) - compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2; - } - - /* Recompute downsampled dimensions of components; - * application needs to know these if using raw downsampled data. - */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Size in samples, after IDCT scaling */ - compptr->downsampled_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * - (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size), - (long) (cinfo->max_h_samp_factor * cinfo->block_size)); - compptr->downsampled_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * - (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size), - (long) (cinfo->max_v_samp_factor * cinfo->block_size)); - } - -#endif /* IDCT_SCALING_SUPPORTED */ - - /* Report number of components in selected colorspace. */ - /* Probably this should be in the color conversion module... */ - switch (cinfo->out_color_space) { - case JCS_GRAYSCALE: - cinfo->out_color_components = 1; - break; - case JCS_RGB: - case JCS_BG_RGB: - cinfo->out_color_components = RGB_PIXELSIZE; - break; - case JCS_YCbCr: - case JCS_BG_YCC: - cinfo->out_color_components = 3; - break; - case JCS_CMYK: - case JCS_YCCK: - cinfo->out_color_components = 4; - break; - default: /* else must be same colorspace as in file */ - cinfo->out_color_components = cinfo->num_components; - break; - } - cinfo->output_components = (cinfo->quantize_colors ? 1 : - cinfo->out_color_components); - - /* See if upsampler will want to emit more than one row at a time */ - if (use_merged_upsample(cinfo)) - cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; - else - cinfo->rec_outbuf_height = 1; -} - - -/* - * Several decompression processes need to range-limit values to the range - * 0..MAXJSAMPLE; the input value may fall somewhat outside this range - * due to noise introduced by quantization, roundoff error, etc. These - * processes are inner loops and need to be as fast as possible. On most - * machines, particularly CPUs with pipelines or instruction prefetch, - * a (subscript-check-less) C table lookup - * x = sample_range_limit[x]; - * is faster than explicit tests - * if (x < 0) x = 0; - * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; - * These processes all use a common table prepared by the routine below. - * - * For most steps we can mathematically guarantee that the initial value - * of x is within 2*(MAXJSAMPLE+1) of the legal range, so a table running - * from -2*(MAXJSAMPLE+1) to 3*MAXJSAMPLE+2 is sufficient. But for the - * initial limiting step (just after the IDCT), a wildly out-of-range value - * is possible if the input data is corrupt. To avoid any chance of indexing - * off the end of memory and getting a bad-pointer trap, we perform the - * post-IDCT limiting thus: - * x = (sample_range_limit - SUBSET)[(x + CENTER) & MASK]; - * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit - * samples. Under normal circumstances this is more than enough range and - * a correct output will be generated; with bogus input data the mask will - * cause wraparound, and we will safely generate a bogus-but-in-range output. - * For the post-IDCT step, we want to convert the data from signed to unsigned - * representation by adding CENTERJSAMPLE at the same time that we limit it. - * This is accomplished with SUBSET = CENTER - CENTERJSAMPLE. - * - * Note that the table is allocated in near data space on PCs; it's small - * enough and used often enough to justify this. - */ - -LOCAL(void) -prepare_range_limit_table (j_decompress_ptr cinfo) -/* Allocate and fill in the sample_range_limit table */ -{ - JSAMPLE * table; - int i; - - table = (JSAMPLE *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, - JPOOL_IMAGE, (RANGE_CENTER * 2 + MAXJSAMPLE + 1) * SIZEOF(JSAMPLE)); - /* First segment of range limit table: limit[x] = 0 for x < 0 */ - MEMZERO(table, RANGE_CENTER * SIZEOF(JSAMPLE)); - table += RANGE_CENTER; /* allow negative subscripts of table */ - cinfo->sample_range_limit = table; - /* Main part of range limit table: limit[x] = x */ - for (i = 0; i <= MAXJSAMPLE; i++) - table[i] = (JSAMPLE) i; - /* End of range limit table: limit[x] = MAXJSAMPLE for x > MAXJSAMPLE */ - for (; i <= MAXJSAMPLE + RANGE_CENTER; i++) - table[i] = MAXJSAMPLE; -} - - -/* - * Master selection of decompression modules. - * This is done once at jpeg_start_decompress time. We determine - * which modules will be used and give them appropriate initialization calls. - * We also initialize the decompressor input side to begin consuming data. - * - * Since jpeg_read_header has finished, we know what is in the SOF - * and (first) SOS markers. We also have all the application parameter - * settings. - */ - -LOCAL(void) -master_selection (j_decompress_ptr cinfo) -{ - my_master_ptr master = (my_master_ptr) cinfo->master; - boolean use_c_buffer; - long samplesperrow; - JDIMENSION jd_samplesperrow; - - /* For now, precision must match compiled-in value... */ - if (cinfo->data_precision != BITS_IN_JSAMPLE) - ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); - - /* Initialize dimensions and other stuff */ - jpeg_calc_output_dimensions(cinfo); - prepare_range_limit_table(cinfo); - - /* Sanity check on image dimensions */ - if (cinfo->output_height <= 0 || cinfo->output_width <= 0 || - cinfo->out_color_components <= 0) - ERREXIT(cinfo, JERR_EMPTY_IMAGE); - - /* Width of an output scanline must be representable as JDIMENSION. */ - samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; - jd_samplesperrow = (JDIMENSION) samplesperrow; - if ((long) jd_samplesperrow != samplesperrow) - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - - /* Initialize my private state */ - master->pass_number = 0; - master->using_merged_upsample = use_merged_upsample(cinfo); - - /* Color quantizer selection */ - master->quantizer_1pass = NULL; - master->quantizer_2pass = NULL; - /* No mode changes if not using buffered-image mode. */ - if (! cinfo->quantize_colors || ! cinfo->buffered_image) { - cinfo->enable_1pass_quant = FALSE; - cinfo->enable_external_quant = FALSE; - cinfo->enable_2pass_quant = FALSE; - } - if (cinfo->quantize_colors) { - if (cinfo->raw_data_out) - ERREXIT(cinfo, JERR_NOTIMPL); - /* 2-pass quantizer only works in 3-component color space. */ - if (cinfo->out_color_components != 3) { - cinfo->enable_1pass_quant = TRUE; - cinfo->enable_external_quant = FALSE; - cinfo->enable_2pass_quant = FALSE; - cinfo->colormap = NULL; - } else if (cinfo->colormap != NULL) { - cinfo->enable_external_quant = TRUE; - } else if (cinfo->two_pass_quantize) { - cinfo->enable_2pass_quant = TRUE; - } else { - cinfo->enable_1pass_quant = TRUE; - } - - if (cinfo->enable_1pass_quant) { -#ifdef QUANT_1PASS_SUPPORTED - jinit_1pass_quantizer(cinfo); - master->quantizer_1pass = cinfo->cquantize; -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } - - /* We use the 2-pass code to map to external colormaps. */ - if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { -#ifdef QUANT_2PASS_SUPPORTED - jinit_2pass_quantizer(cinfo); - master->quantizer_2pass = cinfo->cquantize; -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } - /* If both quantizers are initialized, the 2-pass one is left active; - * this is necessary for starting with quantization to an external map. - */ - } - - /* Post-processing: in particular, color conversion first */ - if (! cinfo->raw_data_out) { - if (master->using_merged_upsample) { -#ifdef UPSAMPLE_MERGING_SUPPORTED - jinit_merged_upsampler(cinfo); /* does color conversion too */ -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else { - jinit_color_deconverter(cinfo); - jinit_upsampler(cinfo); - } - jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); - } - /* Inverse DCT */ - jinit_inverse_dct(cinfo); - /* Entropy decoding: either Huffman or arithmetic coding. */ - if (cinfo->arith_code) - jinit_arith_decoder(cinfo); - else { - jinit_huff_decoder(cinfo); - } - - /* Initialize principal buffer controllers. */ - use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; - jinit_d_coef_controller(cinfo, use_c_buffer); - - if (! cinfo->raw_data_out) - jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); - - /* We can now tell the memory manager to allocate virtual arrays. */ - (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); - - /* Initialize input side of decompressor to consume first scan. */ - (*cinfo->inputctl->start_input_pass) (cinfo); - -#ifdef D_MULTISCAN_FILES_SUPPORTED - /* If jpeg_start_decompress will read the whole file, initialize - * progress monitoring appropriately. The input step is counted - * as one pass. - */ - if (cinfo->progress != NULL && ! cinfo->buffered_image && - cinfo->inputctl->has_multiple_scans) { - int nscans; - /* Estimate number of scans to set pass_limit. */ - if (cinfo->progressive_mode) { - /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ - nscans = 2 + 3 * cinfo->num_components; - } else { - /* For a nonprogressive multiscan file, estimate 1 scan per component. */ - nscans = cinfo->num_components; - } - cinfo->progress->pass_counter = 0L; - cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; - cinfo->progress->completed_passes = 0; - cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); - /* Count the input pass as done */ - master->pass_number++; - } -#endif /* D_MULTISCAN_FILES_SUPPORTED */ -} - - -/* - * Per-pass setup. - * This is called at the beginning of each output pass. We determine which - * modules will be active during this pass and give them appropriate - * start_pass calls. We also set is_dummy_pass to indicate whether this - * is a "real" output pass or a dummy pass for color quantization. - * (In the latter case, jdapistd.c will crank the pass to completion.) - */ - -METHODDEF(void) -prepare_for_output_pass (j_decompress_ptr cinfo) -{ - my_master_ptr master = (my_master_ptr) cinfo->master; - - if (master->pub.is_dummy_pass) { -#ifdef QUANT_2PASS_SUPPORTED - /* Final pass of 2-pass quantization */ - master->pub.is_dummy_pass = FALSE; - (*cinfo->cquantize->start_pass) (cinfo, FALSE); - (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); - (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif /* QUANT_2PASS_SUPPORTED */ - } else { - if (cinfo->quantize_colors && cinfo->colormap == NULL) { - /* Select new quantization method */ - if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { - cinfo->cquantize = master->quantizer_2pass; - master->pub.is_dummy_pass = TRUE; - } else if (cinfo->enable_1pass_quant) { - cinfo->cquantize = master->quantizer_1pass; - } else { - ERREXIT(cinfo, JERR_MODE_CHANGE); - } - } - (*cinfo->idct->start_pass) (cinfo); - (*cinfo->coef->start_output_pass) (cinfo); - if (! cinfo->raw_data_out) { - if (! master->using_merged_upsample) - (*cinfo->cconvert->start_pass) (cinfo); - (*cinfo->upsample->start_pass) (cinfo); - if (cinfo->quantize_colors) - (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); - (*cinfo->post->start_pass) (cinfo, - (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); - (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); - } - } - - /* Set up progress monitor's pass info if present */ - if (cinfo->progress != NULL) { - cinfo->progress->completed_passes = master->pass_number; - cinfo->progress->total_passes = master->pass_number + - (master->pub.is_dummy_pass ? 2 : 1); - /* In buffered-image mode, we assume one more output pass if EOI not - * yet reached, but no more passes if EOI has been reached. - */ - if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { - cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); - } - } -} - - -/* - * Finish up at end of an output pass. - */ - -METHODDEF(void) -finish_output_pass (j_decompress_ptr cinfo) -{ - my_master_ptr master = (my_master_ptr) cinfo->master; - - if (cinfo->quantize_colors) - (*cinfo->cquantize->finish_pass) (cinfo); - master->pass_number++; -} - - -#ifdef D_MULTISCAN_FILES_SUPPORTED - -/* - * Switch to a new external colormap between output passes. - */ - -GLOBAL(void) -jpeg_new_colormap (j_decompress_ptr cinfo) -{ - my_master_ptr master = (my_master_ptr) cinfo->master; - - /* Prevent application from calling me at wrong times */ - if (cinfo->global_state != DSTATE_BUFIMAGE) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - if (cinfo->quantize_colors && cinfo->enable_external_quant && - cinfo->colormap != NULL) { - /* Select 2-pass quantizer for external colormap use */ - cinfo->cquantize = master->quantizer_2pass; - /* Notify quantizer of colormap change */ - (*cinfo->cquantize->new_color_map) (cinfo); - master->pub.is_dummy_pass = FALSE; /* just in case */ - } else - ERREXIT(cinfo, JERR_MODE_CHANGE); -} - -#endif /* D_MULTISCAN_FILES_SUPPORTED */ - - -/* - * Initialize master decompression control and select active modules. - * This is performed at the start of jpeg_start_decompress. - */ - -GLOBAL(void) -jinit_master_decompress (j_decompress_ptr cinfo) -{ - my_master_ptr master; - - master = (my_master_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_decomp_master)); - cinfo->master = &master->pub; - master->pub.prepare_for_output_pass = prepare_for_output_pass; - master->pub.finish_output_pass = finish_output_pass; - - master->pub.is_dummy_pass = FALSE; - - master_selection(cinfo); -} diff --git a/libraries/jpeg/jdmerge.c b/libraries/jpeg/jdmerge.c deleted file mode 100644 index 866693f5294..00000000000 --- a/libraries/jpeg/jdmerge.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * jdmerge.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2013-2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains code for merged upsampling/color conversion. - * - * This file combines functions from jdsample.c and jdcolor.c; - * read those files first to understand what's going on. - * - * When the chroma components are to be upsampled by simple replication - * (ie, box filtering), we can save some work in color conversion by - * calculating all the output pixels corresponding to a pair of chroma - * samples at one time. In the conversion equations - * R = Y + K1 * Cr - * G = Y + K2 * Cb + K3 * Cr - * B = Y + K4 * Cb - * only the Y term varies among the group of pixels corresponding to a pair - * of chroma samples, so the rest of the terms can be calculated just once. - * At typical sampling ratios, this eliminates half or three-quarters of the - * multiplications needed for color conversion. - * - * This file currently provides implementations for the following cases: - * YCC => RGB color conversion only (YCbCr or BG_YCC). - * Sampling ratios of 2h1v or 2h2v. - * No scaling needed at upsample time. - * Corner-aligned (non-CCIR601) sampling alignment. - * Other special cases could be added, but in most applications these are - * the only common cases. (For uncommon cases we fall back on the more - * general code in jdsample.c and jdcolor.c.) - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -#ifdef UPSAMPLE_MERGING_SUPPORTED - - -#if RANGE_BITS < 2 - /* Deliberate syntax err */ - Sorry, this code requires 2 or more range extension bits. -#endif - - -/* Private subobject */ - -typedef struct { - struct jpeg_upsampler pub; /* public fields */ - - /* Pointer to routine to do actual upsampling/conversion of one row group */ - JMETHOD(void, upmethod, (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, - JSAMPARRAY output_buf)); - - /* Private state for YCC->RGB conversion */ - int * Cr_r_tab; /* => table for Cr to R conversion */ - int * Cb_b_tab; /* => table for Cb to B conversion */ - INT32 * Cr_g_tab; /* => table for Cr to G conversion */ - INT32 * Cb_g_tab; /* => table for Cb to G conversion */ - - /* For 2:1 vertical sampling, we produce two output rows at a time. - * We need a "spare" row buffer to hold the second output row if the - * application provides just a one-row buffer; we also use the spare - * to discard the dummy last row if the image height is odd. - */ - JSAMPROW spare_row; - boolean spare_full; /* T if spare buffer is occupied */ - - JDIMENSION out_row_width; /* samples per output row */ - JDIMENSION rows_to_go; /* counts rows remaining in image */ -} my_upsampler; - -typedef my_upsampler * my_upsample_ptr; - -#define SCALEBITS 16 /* speediest right-shift on some machines */ -#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) -#define FIX(x) ((INT32) ((x) * (1L<RGB and BG_YCC->RGB colorspace conversion. - * This is taken directly from jdcolor.c; see that file for more info. - */ - -LOCAL(void) -build_ycc_rgb_table (j_decompress_ptr cinfo) -/* Normal case, sYCC */ -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - int i; - INT32 x; - SHIFT_TEMPS - - upsample->Cr_r_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - upsample->Cb_b_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - upsample->Cr_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - upsample->Cb_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - - for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { - /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ - /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ - /* Cr=>R value is nearest int to 1.402 * x */ - upsample->Cr_r_tab[i] = (int) - RIGHT_SHIFT(FIX(1.402) * x + ONE_HALF, SCALEBITS); - /* Cb=>B value is nearest int to 1.772 * x */ - upsample->Cb_b_tab[i] = (int) - RIGHT_SHIFT(FIX(1.772) * x + ONE_HALF, SCALEBITS); - /* Cr=>G value is scaled-up -0.714136286 * x */ - upsample->Cr_g_tab[i] = (- FIX(0.714136286)) * x; - /* Cb=>G value is scaled-up -0.344136286 * x */ - /* We also add in ONE_HALF so that need not do it in inner loop */ - upsample->Cb_g_tab[i] = (- FIX(0.344136286)) * x + ONE_HALF; - } -} - - -LOCAL(void) -build_bg_ycc_rgb_table (j_decompress_ptr cinfo) -/* Wide gamut case, bg-sYCC */ -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - int i; - INT32 x; - SHIFT_TEMPS - - upsample->Cr_r_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - upsample->Cb_b_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - upsample->Cr_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - upsample->Cb_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - - for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { - /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ - /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ - /* Cr=>R value is nearest int to 2.804 * x */ - upsample->Cr_r_tab[i] = (int) - RIGHT_SHIFT(FIX(2.804) * x + ONE_HALF, SCALEBITS); - /* Cb=>B value is nearest int to 3.544 * x */ - upsample->Cb_b_tab[i] = (int) - RIGHT_SHIFT(FIX(3.544) * x + ONE_HALF, SCALEBITS); - /* Cr=>G value is scaled-up -1.428272572 * x */ - upsample->Cr_g_tab[i] = (- FIX(1.428272572)) * x; - /* Cb=>G value is scaled-up -0.688272572 * x */ - /* We also add in ONE_HALF so that need not do it in inner loop */ - upsample->Cb_g_tab[i] = (- FIX(0.688272572)) * x + ONE_HALF; - } -} - - -/* - * Initialize for an upsampling pass. - */ - -METHODDEF(void) -start_pass_merged_upsample (j_decompress_ptr cinfo) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - - /* Mark the spare buffer empty */ - upsample->spare_full = FALSE; - /* Initialize total-height counter for detecting bottom of image */ - upsample->rows_to_go = cinfo->output_height; -} - - -/* - * Control routine to do upsampling (and color conversion). - * - * The control routine just handles the row buffering considerations. - */ - -METHODDEF(void) -merged_2v_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -/* 2:1 vertical sampling case: may need a spare row. */ -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - JSAMPROW work_ptrs[2]; - JDIMENSION num_rows; /* number of rows returned to caller */ - - if (upsample->spare_full) { - /* If we have a spare row saved from a previous cycle, just return it. */ - jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, - 1, upsample->out_row_width); - num_rows = 1; - upsample->spare_full = FALSE; - } else { - /* Figure number of rows to return to caller. */ - num_rows = 2; - /* Not more than the distance to the end of the image. */ - if (num_rows > upsample->rows_to_go) - num_rows = upsample->rows_to_go; - /* And not more than what the client can accept: */ - out_rows_avail -= *out_row_ctr; - if (num_rows > out_rows_avail) - num_rows = out_rows_avail; - /* Create output pointer array for upsampler. */ - work_ptrs[0] = output_buf[*out_row_ctr]; - if (num_rows > 1) { - work_ptrs[1] = output_buf[*out_row_ctr + 1]; - } else { - work_ptrs[1] = upsample->spare_row; - upsample->spare_full = TRUE; - } - /* Now do the upsampling. */ - (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); - } - - /* Adjust counts */ - *out_row_ctr += num_rows; - upsample->rows_to_go -= num_rows; - /* When the buffer is emptied, declare this input row group consumed */ - if (! upsample->spare_full) - (*in_row_group_ctr)++; -} - - -METHODDEF(void) -merged_1v_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -/* 1:1 vertical sampling case: much easier, never need a spare row. */ -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - - /* Just do the upsampling. */ - (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, - output_buf + *out_row_ctr); - /* Adjust counts */ - (*out_row_ctr)++; - (*in_row_group_ctr)++; -} - - -/* - * These are the routines invoked by the control routines to do - * the actual upsampling/conversion. One row group is processed per call. - * - * Note: since we may be writing directly into application-supplied buffers, - * we have to be honest about the output width; we can't assume the buffer - * has been rounded up to an even width. - */ - - -/* - * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. - */ - -METHODDEF(void) -h2v1_merged_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, - JSAMPARRAY output_buf) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - register int y, cred, cgreen, cblue; - int cb, cr; - register JSAMPROW outptr; - JSAMPROW inptr0, inptr1, inptr2; - JDIMENSION col; - /* copy these pointers into registers if possible */ - register JSAMPLE * range_limit = cinfo->sample_range_limit; - int * Crrtab = upsample->Cr_r_tab; - int * Cbbtab = upsample->Cb_b_tab; - INT32 * Crgtab = upsample->Cr_g_tab; - INT32 * Cbgtab = upsample->Cb_g_tab; - SHIFT_TEMPS - - inptr0 = input_buf[0][in_row_group_ctr]; - inptr1 = input_buf[1][in_row_group_ctr]; - inptr2 = input_buf[2][in_row_group_ctr]; - outptr = output_buf[0]; - /* Loop for each pair of output pixels */ - for (col = cinfo->output_width >> 1; col > 0; col--) { - /* Do the chroma part of the calculation */ - cb = GETJSAMPLE(*inptr1++); - cr = GETJSAMPLE(*inptr2++); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - /* Fetch 2 Y values and emit 2 pixels */ - y = GETJSAMPLE(*inptr0++); - outptr[RGB_RED] = range_limit[y + cred]; - outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; - outptr += RGB_PIXELSIZE; - y = GETJSAMPLE(*inptr0++); - outptr[RGB_RED] = range_limit[y + cred]; - outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; - outptr += RGB_PIXELSIZE; - } - /* If image width is odd, do the last output column separately */ - if (cinfo->output_width & 1) { - cb = GETJSAMPLE(*inptr1); - cr = GETJSAMPLE(*inptr2); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - y = GETJSAMPLE(*inptr0); - outptr[RGB_RED] = range_limit[y + cred]; - outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; - } -} - - -/* - * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. - */ - -METHODDEF(void) -h2v2_merged_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, - JSAMPARRAY output_buf) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - register int y, cred, cgreen, cblue; - int cb, cr; - register JSAMPROW outptr0, outptr1; - JSAMPROW inptr00, inptr01, inptr1, inptr2; - JDIMENSION col; - /* copy these pointers into registers if possible */ - register JSAMPLE * range_limit = cinfo->sample_range_limit; - int * Crrtab = upsample->Cr_r_tab; - int * Cbbtab = upsample->Cb_b_tab; - INT32 * Crgtab = upsample->Cr_g_tab; - INT32 * Cbgtab = upsample->Cb_g_tab; - SHIFT_TEMPS - - inptr00 = input_buf[0][in_row_group_ctr*2]; - inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; - inptr1 = input_buf[1][in_row_group_ctr]; - inptr2 = input_buf[2][in_row_group_ctr]; - outptr0 = output_buf[0]; - outptr1 = output_buf[1]; - /* Loop for each group of output pixels */ - for (col = cinfo->output_width >> 1; col > 0; col--) { - /* Do the chroma part of the calculation */ - cb = GETJSAMPLE(*inptr1++); - cr = GETJSAMPLE(*inptr2++); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - /* Fetch 4 Y values and emit 4 pixels */ - y = GETJSAMPLE(*inptr00++); - outptr0[RGB_RED] = range_limit[y + cred]; - outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; - outptr0 += RGB_PIXELSIZE; - y = GETJSAMPLE(*inptr00++); - outptr0[RGB_RED] = range_limit[y + cred]; - outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; - outptr0 += RGB_PIXELSIZE; - y = GETJSAMPLE(*inptr01++); - outptr1[RGB_RED] = range_limit[y + cred]; - outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; - outptr1 += RGB_PIXELSIZE; - y = GETJSAMPLE(*inptr01++); - outptr1[RGB_RED] = range_limit[y + cred]; - outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; - outptr1 += RGB_PIXELSIZE; - } - /* If image width is odd, do the last output column separately */ - if (cinfo->output_width & 1) { - cb = GETJSAMPLE(*inptr1); - cr = GETJSAMPLE(*inptr2); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - y = GETJSAMPLE(*inptr00); - outptr0[RGB_RED] = range_limit[y + cred]; - outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; - y = GETJSAMPLE(*inptr01); - outptr1[RGB_RED] = range_limit[y + cred]; - outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; - } -} - - -/* - * Module initialization routine for merged upsampling/color conversion. - * - * NB: this is called under the conditions determined by use_merged_upsample() - * in jdmaster.c. That routine MUST correspond to the actual capabilities - * of this module; no safety checks are made here. - */ - -GLOBAL(void) -jinit_merged_upsampler (j_decompress_ptr cinfo) -{ - my_upsample_ptr upsample; - - upsample = (my_upsample_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_upsampler)); - cinfo->upsample = &upsample->pub; - upsample->pub.start_pass = start_pass_merged_upsample; - upsample->pub.need_context_rows = FALSE; - - upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; - - if (cinfo->max_v_samp_factor == 2) { - upsample->pub.upsample = merged_2v_upsample; - upsample->upmethod = h2v2_merged_upsample; - /* Allocate a spare row buffer */ - upsample->spare_row = (JSAMPROW) - (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE))); - } else { - upsample->pub.upsample = merged_1v_upsample; - upsample->upmethod = h2v1_merged_upsample; - /* No spare row needed */ - upsample->spare_row = NULL; - } - - if (cinfo->jpeg_color_space == JCS_BG_YCC) - build_bg_ycc_rgb_table(cinfo); - else - build_ycc_rgb_table(cinfo); -} - -#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/libraries/jpeg/jdpostct.c b/libraries/jpeg/jdpostct.c deleted file mode 100644 index 571563d728e..00000000000 --- a/libraries/jpeg/jdpostct.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * jdpostct.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the decompression postprocessing controller. - * This controller manages the upsampling, color conversion, and color - * quantization/reduction steps; specifically, it controls the buffering - * between upsample/color conversion and color quantization/reduction. - * - * If no color quantization/reduction is required, then this module has no - * work to do, and it just hands off to the upsample/color conversion code. - * An integrated upsample/convert/quantize process would replace this module - * entirely. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_d_post_controller pub; /* public fields */ - - /* Color quantization source buffer: this holds output data from - * the upsample/color conversion step to be passed to the quantizer. - * For two-pass color quantization, we need a full-image buffer; - * for one-pass operation, a strip buffer is sufficient. - */ - jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ - JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ - JDIMENSION strip_height; /* buffer size in rows */ - /* for two-pass mode only: */ - JDIMENSION starting_row; /* row # of first row in current strip */ - JDIMENSION next_row; /* index of next row to fill/empty in strip */ -} my_post_controller; - -typedef my_post_controller * my_post_ptr; - - -/* Forward declarations */ -METHODDEF(void) post_process_1pass - JPP((j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -#ifdef QUANT_2PASS_SUPPORTED -METHODDEF(void) post_process_prepass - JPP((j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -METHODDEF(void) post_process_2pass - JPP((j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -#endif - - -/* - * Initialize for a processing pass. - */ - -METHODDEF(void) -start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) -{ - my_post_ptr post = (my_post_ptr) cinfo->post; - - switch (pass_mode) { - case JBUF_PASS_THRU: - if (cinfo->quantize_colors) { - /* Single-pass processing with color quantization. */ - post->pub.post_process_data = post_process_1pass; - /* We could be doing buffered-image output before starting a 2-pass - * color quantization; in that case, jinit_d_post_controller did not - * allocate a strip buffer. Use the virtual-array buffer as workspace. - */ - if (post->buffer == NULL) { - post->buffer = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, post->whole_image, - (JDIMENSION) 0, post->strip_height, TRUE); - } - } else { - /* For single-pass processing without color quantization, - * I have no work to do; just call the upsampler directly. - */ - post->pub.post_process_data = cinfo->upsample->upsample; - } - break; -#ifdef QUANT_2PASS_SUPPORTED - case JBUF_SAVE_AND_PASS: - /* First pass of 2-pass quantization */ - if (post->whole_image == NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - post->pub.post_process_data = post_process_prepass; - break; - case JBUF_CRANK_DEST: - /* Second pass of 2-pass quantization */ - if (post->whole_image == NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - post->pub.post_process_data = post_process_2pass; - break; -#endif /* QUANT_2PASS_SUPPORTED */ - default: - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - break; - } - post->starting_row = post->next_row = 0; -} - - -/* - * Process some data in the one-pass (strip buffer) case. - * This is used for color precision reduction as well as one-pass quantization. - */ - -METHODDEF(void) -post_process_1pass (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_post_ptr post = (my_post_ptr) cinfo->post; - JDIMENSION num_rows, max_rows; - - /* Fill the buffer, but not more than what we can dump out in one go. */ - /* Note we rely on the upsampler to detect bottom of image. */ - max_rows = out_rows_avail - *out_row_ctr; - if (max_rows > post->strip_height) - max_rows = post->strip_height; - num_rows = 0; - (*cinfo->upsample->upsample) (cinfo, - input_buf, in_row_group_ctr, in_row_groups_avail, - post->buffer, &num_rows, max_rows); - /* Quantize and emit data. */ - (*cinfo->cquantize->color_quantize) (cinfo, - post->buffer, output_buf + *out_row_ctr, (int) num_rows); - *out_row_ctr += num_rows; -} - - -#ifdef QUANT_2PASS_SUPPORTED - -/* - * Process some data in the first pass of 2-pass quantization. - */ - -METHODDEF(void) -post_process_prepass (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_post_ptr post = (my_post_ptr) cinfo->post; - JDIMENSION old_next_row, num_rows; - - /* Reposition virtual buffer if at start of strip. */ - if (post->next_row == 0) { - post->buffer = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, post->whole_image, - post->starting_row, post->strip_height, TRUE); - } - - /* Upsample some data (up to a strip height's worth). */ - old_next_row = post->next_row; - (*cinfo->upsample->upsample) (cinfo, - input_buf, in_row_group_ctr, in_row_groups_avail, - post->buffer, &post->next_row, post->strip_height); - - /* Allow quantizer to scan new data. No data is emitted, */ - /* but we advance out_row_ctr so outer loop can tell when we're done. */ - if (post->next_row > old_next_row) { - num_rows = post->next_row - old_next_row; - (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, - (JSAMPARRAY) NULL, (int) num_rows); - *out_row_ctr += num_rows; - } - - /* Advance if we filled the strip. */ - if (post->next_row >= post->strip_height) { - post->starting_row += post->strip_height; - post->next_row = 0; - } -} - - -/* - * Process some data in the second pass of 2-pass quantization. - */ - -METHODDEF(void) -post_process_2pass (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_post_ptr post = (my_post_ptr) cinfo->post; - JDIMENSION num_rows, max_rows; - - /* Reposition virtual buffer if at start of strip. */ - if (post->next_row == 0) { - post->buffer = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, post->whole_image, - post->starting_row, post->strip_height, FALSE); - } - - /* Determine number of rows to emit. */ - num_rows = post->strip_height - post->next_row; /* available in strip */ - max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ - if (num_rows > max_rows) - num_rows = max_rows; - /* We have to check bottom of image here, can't depend on upsampler. */ - max_rows = cinfo->output_height - post->starting_row; - if (num_rows > max_rows) - num_rows = max_rows; - - /* Quantize and emit data. */ - (*cinfo->cquantize->color_quantize) (cinfo, - post->buffer + post->next_row, output_buf + *out_row_ctr, - (int) num_rows); - *out_row_ctr += num_rows; - - /* Advance if we filled the strip. */ - post->next_row += num_rows; - if (post->next_row >= post->strip_height) { - post->starting_row += post->strip_height; - post->next_row = 0; - } -} - -#endif /* QUANT_2PASS_SUPPORTED */ - - -/* - * Initialize postprocessing controller. - */ - -GLOBAL(void) -jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) -{ - my_post_ptr post; - - post = (my_post_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_post_controller)); - cinfo->post = (struct jpeg_d_post_controller *) post; - post->pub.start_pass = start_pass_dpost; - post->whole_image = NULL; /* flag for no virtual arrays */ - post->buffer = NULL; /* flag for no strip buffer */ - - /* Create the quantization buffer, if needed */ - if (cinfo->quantize_colors) { - /* The buffer strip height is max_v_samp_factor, which is typically - * an efficient number of rows for upsampling to return. - * (In the presence of output rescaling, we might want to be smarter?) - */ - post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; - if (need_full_buffer) { - /* Two-pass color quantization: need full-image storage. */ - /* We round up the number of rows to a multiple of the strip height. */ -#ifdef QUANT_2PASS_SUPPORTED - post->whole_image = (*cinfo->mem->request_virt_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, - cinfo->output_width * cinfo->out_color_components, - (JDIMENSION) jround_up((long) cinfo->output_height, - (long) post->strip_height), - post->strip_height); -#else - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); -#endif /* QUANT_2PASS_SUPPORTED */ - } else { - /* One-pass color quantization: just make a strip buffer. */ - post->buffer = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->output_width * cinfo->out_color_components, - post->strip_height); - } - } -} diff --git a/libraries/jpeg/jdsample.c b/libraries/jpeg/jdsample.c deleted file mode 100644 index fd9907e20cd..00000000000 --- a/libraries/jpeg/jdsample.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * jdsample.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * Modified 2002-2015 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains upsampling routines. - * - * Upsampling input data is counted in "row groups". A row group - * is defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size) - * sample rows of each component. Upsampling will normally produce - * max_v_samp_factor pixel rows from each row group (but this could vary - * if the upsampler is applying a scale factor of its own). - * - * An excellent reference for image resampling is - * Digital Image Warping, George Wolberg, 1990. - * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Pointer to routine to upsample a single component */ -typedef JMETHOD(void, upsample1_ptr, - (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); - -/* Private subobject */ - -typedef struct { - struct jpeg_upsampler pub; /* public fields */ - - /* Color conversion buffer. When using separate upsampling and color - * conversion steps, this buffer holds one upsampled row group until it - * has been color converted and output. - * Note: we do not allocate any storage for component(s) which are full-size, - * ie do not need rescaling. The corresponding entry of color_buf[] is - * simply set to point to the input data array, thereby avoiding copying. - */ - JSAMPARRAY color_buf[MAX_COMPONENTS]; - - /* Per-component upsampling method pointers */ - upsample1_ptr methods[MAX_COMPONENTS]; - - int next_row_out; /* counts rows emitted from color_buf */ - JDIMENSION rows_to_go; /* counts rows remaining in image */ - - /* Height of an input row group for each component. */ - int rowgroup_height[MAX_COMPONENTS]; - - /* These arrays save pixel expansion factors so that int_expand need not - * recompute them each time. They are unused for other upsampling methods. - */ - UINT8 h_expand[MAX_COMPONENTS]; - UINT8 v_expand[MAX_COMPONENTS]; -} my_upsampler; - -typedef my_upsampler * my_upsample_ptr; - - -/* - * Initialize for an upsampling pass. - */ - -METHODDEF(void) -start_pass_upsample (j_decompress_ptr cinfo) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - - /* Mark the conversion buffer empty */ - upsample->next_row_out = cinfo->max_v_samp_factor; - /* Initialize total-height counter for detecting bottom of image */ - upsample->rows_to_go = cinfo->output_height; -} - - -/* - * Control routine to do upsampling (and color conversion). - * - * In this version we upsample each component independently. - * We upsample one row group into the conversion buffer, then apply - * color conversion a row at a time. - */ - -METHODDEF(void) -sep_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - int ci; - jpeg_component_info * compptr; - JDIMENSION num_rows; - - /* Fill the conversion buffer, if it's empty */ - if (upsample->next_row_out >= cinfo->max_v_samp_factor) { - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Invoke per-component upsample method. Notice we pass a POINTER - * to color_buf[ci], so that fullsize_upsample can change it. - */ - (*upsample->methods[ci]) (cinfo, compptr, - input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), - upsample->color_buf + ci); - } - upsample->next_row_out = 0; - } - - /* Color-convert and emit rows */ - - /* How many we have in the buffer: */ - num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); - /* Not more than the distance to the end of the image. Need this test - * in case the image height is not a multiple of max_v_samp_factor: - */ - if (num_rows > upsample->rows_to_go) - num_rows = upsample->rows_to_go; - /* And not more than what the client can accept: */ - out_rows_avail -= *out_row_ctr; - if (num_rows > out_rows_avail) - num_rows = out_rows_avail; - - (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, - (JDIMENSION) upsample->next_row_out, - output_buf + *out_row_ctr, - (int) num_rows); - - /* Adjust counts */ - *out_row_ctr += num_rows; - upsample->rows_to_go -= num_rows; - upsample->next_row_out += num_rows; - /* When the buffer is emptied, declare this input row group consumed */ - if (upsample->next_row_out >= cinfo->max_v_samp_factor) - (*in_row_group_ctr)++; -} - - -/* - * These are the routines invoked by sep_upsample to upsample pixel values - * of a single component. One row group is processed per call. - */ - - -/* - * For full-size components, we just make color_buf[ci] point at the - * input buffer, and thus avoid copying any data. Note that this is - * safe only because sep_upsample doesn't declare the input row group - * "consumed" until we are done color converting and emitting it. - */ - -METHODDEF(void) -fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - *output_data_ptr = input_data; -} - - -/* - * This is a no-op version used for "uninteresting" components. - * These components will not be referenced by color conversion. - */ - -METHODDEF(void) -noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - *output_data_ptr = NULL; /* safety check */ -} - - -/* - * This version handles any integral sampling ratios. - * This is not used for typical JPEG files, so it need not be fast. - * Nor, for that matter, is it particularly accurate: the algorithm is - * simple replication of the input pixel onto the corresponding output - * pixels. The hi-falutin sampling literature refers to this as a - * "box filter". A box filter tends to introduce visible artifacts, - * so if you are actually going to use 3:1 or 4:1 sampling ratios - * you would be well advised to improve this code. - */ - -METHODDEF(void) -int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - JSAMPARRAY output_data = *output_data_ptr; - register JSAMPROW inptr, outptr; - register JSAMPLE invalue; - register int h; - JSAMPROW outend; - int h_expand, v_expand; - int inrow, outrow; - - h_expand = upsample->h_expand[compptr->component_index]; - v_expand = upsample->v_expand[compptr->component_index]; - - inrow = outrow = 0; - while (outrow < cinfo->max_v_samp_factor) { - /* Generate one output row with proper horizontal expansion */ - inptr = input_data[inrow]; - outptr = output_data[outrow]; - outend = outptr + cinfo->output_width; - while (outptr < outend) { - invalue = *inptr++; /* don't need GETJSAMPLE() here */ - for (h = h_expand; h > 0; h--) { - *outptr++ = invalue; - } - } - /* Generate any additional output rows by duplicating the first one */ - if (v_expand > 1) { - jcopy_sample_rows(output_data, outrow, output_data, outrow+1, - v_expand-1, cinfo->output_width); - } - inrow++; - outrow += v_expand; - } -} - - -/* - * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. - * It's still a box filter. - */ - -METHODDEF(void) -h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - JSAMPARRAY output_data = *output_data_ptr; - register JSAMPROW inptr, outptr; - register JSAMPLE invalue; - JSAMPROW outend; - int outrow; - - for (outrow = 0; outrow < cinfo->max_v_samp_factor; outrow++) { - inptr = input_data[outrow]; - outptr = output_data[outrow]; - outend = outptr + cinfo->output_width; - while (outptr < outend) { - invalue = *inptr++; /* don't need GETJSAMPLE() here */ - *outptr++ = invalue; - *outptr++ = invalue; - } - } -} - - -/* - * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. - * It's still a box filter. - */ - -METHODDEF(void) -h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - JSAMPARRAY output_data = *output_data_ptr; - register JSAMPROW inptr, outptr; - register JSAMPLE invalue; - JSAMPROW outend; - int inrow, outrow; - - inrow = outrow = 0; - while (outrow < cinfo->max_v_samp_factor) { - inptr = input_data[inrow]; - outptr = output_data[outrow]; - outend = outptr + cinfo->output_width; - while (outptr < outend) { - invalue = *inptr++; /* don't need GETJSAMPLE() here */ - *outptr++ = invalue; - *outptr++ = invalue; - } - jcopy_sample_rows(output_data, outrow, output_data, outrow+1, - 1, cinfo->output_width); - inrow++; - outrow += 2; - } -} - - -/* - * Module initialization routine for upsampling. - */ - -GLOBAL(void) -jinit_upsampler (j_decompress_ptr cinfo) -{ - my_upsample_ptr upsample; - int ci; - jpeg_component_info * compptr; - int h_in_group, v_in_group, h_out_group, v_out_group; - - upsample = (my_upsample_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_upsampler)); - cinfo->upsample = &upsample->pub; - upsample->pub.start_pass = start_pass_upsample; - upsample->pub.upsample = sep_upsample; - upsample->pub.need_context_rows = FALSE; /* until we find out differently */ - - if (cinfo->CCIR601_sampling) /* this isn't supported */ - ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); - - /* Verify we can handle the sampling factors, select per-component methods, - * and create storage as needed. - */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Compute size of an "input group" after IDCT scaling. This many samples - * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. - */ - h_in_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) / - cinfo->min_DCT_h_scaled_size; - v_in_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / - cinfo->min_DCT_v_scaled_size; - h_out_group = cinfo->max_h_samp_factor; - v_out_group = cinfo->max_v_samp_factor; - upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ - if (! compptr->component_needed) { - /* Don't bother to upsample an uninteresting component. */ - upsample->methods[ci] = noop_upsample; - continue; /* don't need to allocate buffer */ - } - if (h_in_group == h_out_group && v_in_group == v_out_group) { - /* Fullsize components can be processed without any work. */ - upsample->methods[ci] = fullsize_upsample; - continue; /* don't need to allocate buffer */ - } - if (h_in_group * 2 == h_out_group && v_in_group == v_out_group) { - /* Special case for 2h1v upsampling */ - upsample->methods[ci] = h2v1_upsample; - } else if (h_in_group * 2 == h_out_group && - v_in_group * 2 == v_out_group) { - /* Special case for 2h2v upsampling */ - upsample->methods[ci] = h2v2_upsample; - } else if ((h_out_group % h_in_group) == 0 && - (v_out_group % v_in_group) == 0) { - /* Generic integral-factors upsampling method */ - upsample->methods[ci] = int_upsample; - upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); - upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); - } else - ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); - upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (JDIMENSION) jround_up((long) cinfo->output_width, - (long) cinfo->max_h_samp_factor), - (JDIMENSION) cinfo->max_v_samp_factor); - } -} diff --git a/libraries/jpeg/jerror.c b/libraries/jpeg/jerror.c deleted file mode 100644 index 7163af699c3..00000000000 --- a/libraries/jpeg/jerror.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * jerror.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * Modified 2012-2015 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains simple error-reporting and trace-message routines. - * These are suitable for Unix-like systems and others where writing to - * stderr is the right thing to do. Many applications will want to replace - * some or all of these routines. - * - * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile, - * you get a Windows-specific hack to display error messages in a dialog box. - * It ain't much, but it beats dropping error messages into the bit bucket, - * which is what happens to output to stderr under most Windows C compilers. - * - * These routines are used by both the compression and decompression code. - */ - -#ifdef USE_WINDOWS_MESSAGEBOX -#include -#endif - -/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ -#include "jinclude.h" -#include "jpeglib.h" -#include "jversion.h" -#include "jerror.h" - -#ifndef EXIT_FAILURE /* define exit() codes if not provided */ -#define EXIT_FAILURE 1 -#endif - - -/* - * Create the message string table. - * We do this from the master message list in jerror.h by re-reading - * jerror.h with a suitable definition for macro JMESSAGE. - * The message table is made an external symbol just in case any applications - * want to refer to it directly. - */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_std_message_table jMsgTable -#endif - -#define JMESSAGE(code,string) string , - -const char * const jpeg_std_message_table[] = { -#include "jerror.h" - NULL -}; - - -/* - * Error exit handler: must not return to caller. - * - * Applications may override this if they want to get control back after - * an error. Typically one would longjmp somewhere instead of exiting. - * The setjmp buffer can be made a private field within an expanded error - * handler object. Note that the info needed to generate an error message - * is stored in the error object, so you can generate the message now or - * later, at your convenience. - * You should make sure that the JPEG object is cleaned up (with jpeg_abort - * or jpeg_destroy) at some point. - */ - -METHODDEF(noreturn_t) -error_exit (j_common_ptr cinfo) -{ - /* Always display the message */ - (*cinfo->err->output_message) (cinfo); - - /* Let the memory manager delete any temp files before we die */ - jpeg_destroy(cinfo); - - exit(EXIT_FAILURE); -} - - -/* - * Actual output of an error or trace message. - * Applications may override this method to send JPEG messages somewhere - * other than stderr. - * - * On Windows, printing to stderr is generally completely useless, - * so we provide optional code to produce an error-dialog popup. - * Most Windows applications will still prefer to override this routine, - * but if they don't, it'll do something at least marginally useful. - * - * NOTE: to use the library in an environment that doesn't support the - * C stdio library, you may have to delete the call to fprintf() entirely, - * not just not use this routine. - */ - -METHODDEF(void) -output_message (j_common_ptr cinfo) -{ - char buffer[JMSG_LENGTH_MAX]; - - /* Create the message */ - (*cinfo->err->format_message) (cinfo, buffer); - -#ifdef USE_WINDOWS_MESSAGEBOX - /* Display it in a message dialog box */ - MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", - MB_OK | MB_ICONERROR); -#else - /* Send it to stderr, adding a newline */ - fprintf(stderr, "%s\n", buffer); -#endif -} - - -/* - * Decide whether to emit a trace or warning message. - * msg_level is one of: - * -1: recoverable corrupt-data warning, may want to abort. - * 0: important advisory messages (always display to user). - * 1: first level of tracing detail. - * 2,3,...: successively more detailed tracing messages. - * An application might override this method if it wanted to abort on warnings - * or change the policy about which messages to display. - */ - -METHODDEF(void) -emit_message (j_common_ptr cinfo, int msg_level) -{ - struct jpeg_error_mgr * err = cinfo->err; - - if (msg_level < 0) { - /* It's a warning message. Since corrupt files may generate many warnings, - * the policy implemented here is to show only the first warning, - * unless trace_level >= 3. - */ - if (err->num_warnings == 0 || err->trace_level >= 3) - (*err->output_message) (cinfo); - /* Always count warnings in num_warnings. */ - err->num_warnings++; - } else { - /* It's a trace message. Show it if trace_level >= msg_level. */ - if (err->trace_level >= msg_level) - (*err->output_message) (cinfo); - } -} - - -/* - * Format a message string for the most recent JPEG error or message. - * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX - * characters. Note that no '\n' character is added to the string. - * Few applications should need to override this method. - */ - -METHODDEF(void) -format_message (j_common_ptr cinfo, char * buffer) -{ - struct jpeg_error_mgr * err = cinfo->err; - int msg_code = err->msg_code; - const char * msgtext = NULL; - const char * msgptr; - char ch; - boolean isstring; - - /* Look up message string in proper table */ - if (msg_code > 0 && msg_code <= err->last_jpeg_message) { - msgtext = err->jpeg_message_table[msg_code]; - } else if (err->addon_message_table != NULL && - msg_code >= err->first_addon_message && - msg_code <= err->last_addon_message) { - msgtext = err->addon_message_table[msg_code - err->first_addon_message]; - } - - /* Defend against bogus message number */ - if (msgtext == NULL) { - err->msg_parm.i[0] = msg_code; - msgtext = err->jpeg_message_table[0]; - } - - /* Check for string parameter, as indicated by %s in the message text */ - isstring = FALSE; - msgptr = msgtext; - while ((ch = *msgptr++) != '\0') { - if (ch == '%') { - if (*msgptr == 's') isstring = TRUE; - break; - } - } - - /* Format the message into the passed buffer */ - if (isstring) - sprintf(buffer, msgtext, err->msg_parm.s); - else - sprintf(buffer, msgtext, - err->msg_parm.i[0], err->msg_parm.i[1], - err->msg_parm.i[2], err->msg_parm.i[3], - err->msg_parm.i[4], err->msg_parm.i[5], - err->msg_parm.i[6], err->msg_parm.i[7]); -} - - -/* - * Reset error state variables at start of a new image. - * This is called during compression startup to reset trace/error - * processing to default state, without losing any application-specific - * method pointers. An application might possibly want to override - * this method if it has additional error processing state. - */ - -METHODDEF(void) -reset_error_mgr (j_common_ptr cinfo) -{ - cinfo->err->num_warnings = 0; - /* trace_level is not reset since it is an application-supplied parameter */ - cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ -} - - -/* - * Fill in the standard error-handling methods in a jpeg_error_mgr object. - * Typical call is: - * struct jpeg_compress_struct cinfo; - * struct jpeg_error_mgr err; - * - * cinfo.err = jpeg_std_error(&err); - * after which the application may override some of the methods. - */ - -GLOBAL(struct jpeg_error_mgr *) -jpeg_std_error (struct jpeg_error_mgr * err) -{ - err->error_exit = error_exit; - err->emit_message = emit_message; - err->output_message = output_message; - err->format_message = format_message; - err->reset_error_mgr = reset_error_mgr; - - err->trace_level = 0; /* default = no tracing */ - err->num_warnings = 0; /* no warnings emitted yet */ - err->msg_code = 0; /* may be useful as a flag for "no error" */ - - /* Initialize message table pointers */ - err->jpeg_message_table = jpeg_std_message_table; - err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; - - err->addon_message_table = NULL; - err->first_addon_message = 0; /* for safety */ - err->last_addon_message = 0; - - return err; -} diff --git a/libraries/jpeg/jerror.h b/libraries/jpeg/jerror.h deleted file mode 100644 index a4b661f716d..00000000000 --- a/libraries/jpeg/jerror.h +++ /dev/null @@ -1,304 +0,0 @@ -/* - * jerror.h - * - * Copyright (C) 1994-1997, Thomas G. Lane. - * Modified 1997-2012 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file defines the error and message codes for the JPEG library. - * Edit this file to add new codes, or to translate the message strings to - * some other language. - * A set of error-reporting macros are defined too. Some applications using - * the JPEG library may wish to include this file to get the error codes - * and/or the macros. - */ - -/* - * To define the enum list of message codes, include this file without - * defining macro JMESSAGE. To create a message string table, include it - * again with a suitable JMESSAGE definition (see jerror.c for an example). - */ -#ifndef JMESSAGE -#ifndef JERROR_H -/* First time through, define the enum list */ -#define JMAKE_ENUM_LIST -#else -/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ -#define JMESSAGE(code,string) -#endif /* JERROR_H */ -#endif /* JMESSAGE */ - -#ifdef JMAKE_ENUM_LIST - -typedef enum { - -#define JMESSAGE(code,string) code , - -#endif /* JMAKE_ENUM_LIST */ - -JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ - -/* For maintenance convenience, list is alphabetical by message code name */ -JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") -JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") -JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") -JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") -JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") -JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") -JMESSAGE(JERR_BAD_DCTSIZE, "DCT scaled block size %dx%d not supported") -JMESSAGE(JERR_BAD_DROP_SAMPLING, - "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c") -JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") -JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") -JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") -JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") -JMESSAGE(JERR_BAD_LIB_VERSION, - "Wrong JPEG library version: library is %d, caller expects %d") -JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") -JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") -JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") -JMESSAGE(JERR_BAD_PROGRESSION, - "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") -JMESSAGE(JERR_BAD_PROG_SCRIPT, - "Invalid progressive parameters at scan script entry %d") -JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") -JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") -JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") -JMESSAGE(JERR_BAD_STRUCT_SIZE, - "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") -JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") -JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") -JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") -JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") -JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") -JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") -JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") -JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") -JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") -JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") -JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") -JMESSAGE(JERR_EMS_READ, "Read from EMS failed") -JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") -JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") -JMESSAGE(JERR_FILE_READ, "Input file read error") -JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") -JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") -JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") -JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") -JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") -JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") -JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") -JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, - "Cannot transcode due to multiple use of quantization table %d") -JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") -JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") -JMESSAGE(JERR_NOTIMPL, "Not implemented yet") -JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") -JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") -JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") -JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") -JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") -JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") -JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") -JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") -JMESSAGE(JERR_QUANT_COMPONENTS, - "Cannot quantize more than %d color components") -JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") -JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") -JMESSAGE(JERR_SOF_BEFORE, "Invalid JPEG file structure: %s before SOF") -JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") -JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") -JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") -JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") -JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") -JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") -JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") -JMESSAGE(JERR_TFILE_WRITE, - "Write failed on temporary file --- out of disk space?") -JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") -JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") -JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") -JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") -JMESSAGE(JERR_XMS_READ, "Read from XMS failed") -JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") -JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) -JMESSAGE(JMSG_VERSION, JVERSION) -JMESSAGE(JTRC_16BIT_TABLES, - "Caution: quantization tables are too coarse for baseline JPEG") -JMESSAGE(JTRC_ADOBE, - "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") -JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") -JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") -JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") -JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") -JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") -JMESSAGE(JTRC_DRI, "Define Restart Interval %u") -JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") -JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") -JMESSAGE(JTRC_EOI, "End Of Image") -JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") -JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") -JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, - "Warning: thumbnail image size does not match data length %u") -JMESSAGE(JTRC_JFIF_EXTENSION, - "JFIF extension marker: type 0x%02x, length %u") -JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") -JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") -JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") -JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") -JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") -JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") -JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") -JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") -JMESSAGE(JTRC_RST, "RST%d") -JMESSAGE(JTRC_SMOOTH_NOTIMPL, - "Smoothing not supported with nonstandard sampling ratios") -JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") -JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") -JMESSAGE(JTRC_SOI, "Start of Image") -JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") -JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") -JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") -JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") -JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") -JMESSAGE(JTRC_THUMB_JPEG, - "JFIF extension marker: JPEG-compressed thumbnail image, length %u") -JMESSAGE(JTRC_THUMB_PALETTE, - "JFIF extension marker: palette thumbnail image, length %u") -JMESSAGE(JTRC_THUMB_RGB, - "JFIF extension marker: RGB thumbnail image, length %u") -JMESSAGE(JTRC_UNKNOWN_IDS, - "Unrecognized component IDs %d %d %d, assuming YCbCr") -JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") -JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") -JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") -JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") -JMESSAGE(JWRN_BOGUS_PROGRESSION, - "Inconsistent progression sequence for component %d coefficient %d") -JMESSAGE(JWRN_EXTRANEOUS_DATA, - "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") -JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") -JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") -JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") -JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") -JMESSAGE(JWRN_MUST_RESYNC, - "Corrupt JPEG data: found marker 0x%02x instead of RST%d") -JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") -JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") - -#ifdef JMAKE_ENUM_LIST - - JMSG_LASTMSGCODE -} J_MESSAGE_CODE; - -#undef JMAKE_ENUM_LIST -#endif /* JMAKE_ENUM_LIST */ - -/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ -#undef JMESSAGE - - -#ifndef JERROR_H -#define JERROR_H - -/* Macros to simplify using the error and trace message stuff */ -/* The first parameter is either type of cinfo pointer */ - -/* Fatal errors (print message and exit) */ -#define ERREXIT(cinfo,code) \ - ((cinfo)->err->msg_code = (code), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT1(cinfo,code,p1) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT2(cinfo,code,p1,p2) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT3(cinfo,code,p1,p2,p3) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (cinfo)->err->msg_parm.i[2] = (p3), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (cinfo)->err->msg_parm.i[2] = (p3), \ - (cinfo)->err->msg_parm.i[3] = (p4), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT6(cinfo,code,p1,p2,p3,p4,p5,p6) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (cinfo)->err->msg_parm.i[2] = (p3), \ - (cinfo)->err->msg_parm.i[3] = (p4), \ - (cinfo)->err->msg_parm.i[4] = (p5), \ - (cinfo)->err->msg_parm.i[5] = (p6), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXITS(cinfo,code,str) \ - ((cinfo)->err->msg_code = (code), \ - strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) - -#define MAKESTMT(stuff) do { stuff } while (0) - -/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ -#define WARNMS(cinfo,code) \ - ((cinfo)->err->msg_code = (code), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) -#define WARNMS1(cinfo,code,p1) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) -#define WARNMS2(cinfo,code,p1,p2) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) - -/* Informational/debugging messages */ -#define TRACEMS(cinfo,lvl,code) \ - ((cinfo)->err->msg_code = (code), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) -#define TRACEMS1(cinfo,lvl,code,p1) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) -#define TRACEMS2(cinfo,lvl,code,p1,p2) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) -#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ - MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ - _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ - (cinfo)->err->msg_code = (code); \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) -#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ - MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ - _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ - (cinfo)->err->msg_code = (code); \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) -#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ - MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ - _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ - _mp[4] = (p5); \ - (cinfo)->err->msg_code = (code); \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) -#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ - MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ - _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ - _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ - (cinfo)->err->msg_code = (code); \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) -#define TRACEMSS(cinfo,lvl,code,str) \ - ((cinfo)->err->msg_code = (code), \ - strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) - -#endif /* JERROR_H */ diff --git a/libraries/jpeg/jidctflt.c b/libraries/jpeg/jidctflt.c deleted file mode 100644 index e33a2b5e42c..00000000000 --- a/libraries/jpeg/jidctflt.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * jidctflt.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * Modified 2010-2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a floating-point implementation of the - * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - * must also perform dequantization of the input coefficients. - * - * This implementation should be more accurate than either of the integer - * IDCT implementations. However, it may not give the same results on all - * machines because of differences in roundoff behavior. Speed will depend - * on the hardware's floating point capacity. - * - * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - * on each row (or vice versa, but it's more convenient to emit a row at - * a time). Direct algorithms are also available, but they are much more - * complex and seem not to be any faster when reduced to code. - * - * This implementation is based on Arai, Agui, and Nakajima's algorithm for - * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - * Japanese, but the algorithm is described in the Pennebaker & Mitchell - * JPEG textbook (see REFERENCES section in file README). The following code - * is based directly on figure 4-8 in P&M. - * While an 8-point DCT cannot be done in less than 11 multiplies, it is - * possible to arrange the computation so that many of the multiplies are - * simple scalings of the final outputs. These multiplies can then be - * folded into the multiplications or divisions by the JPEG quantization - * table entries. The AA&N method leaves only 5 multiplies and 29 adds - * to be done in the DCT itself. - * The primary disadvantage of this method is that with a fixed-point - * implementation, accuracy is lost due to imprecise representation of the - * scaled quantization values. However, that problem does not arise if - * we use floating point arithmetic. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_FLOAT_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ -#endif - - -/* Dequantize a coefficient by multiplying it by the multiplier-table - * entry; produce a float result. - */ - -#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) - - -/* - * Perform dequantization and inverse DCT on one block of coefficients. - * - * cK represents cos(K*pi/16). - */ - -GLOBAL(void) -jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - FAST_FLOAT tmp10, tmp11, tmp12, tmp13; - FAST_FLOAT z5, z10, z11, z12, z13; - JCOEFPTR inptr; - FLOAT_MULT_TYPE * quantptr; - FAST_FLOAT * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - wsptr[DCTSIZE*4] = dcval; - wsptr[DCTSIZE*5] = dcval; - wsptr[DCTSIZE*6] = dcval; - wsptr[DCTSIZE*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp10 = tmp0 + tmp2; /* phase 3 */ - tmp11 = tmp0 - tmp2; - - tmp13 = tmp1 + tmp3; /* phases 5-3 */ - tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ - - tmp0 = tmp10 + tmp13; /* phase 2 */ - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - z13 = tmp6 + tmp5; /* phase 6 */ - z10 = tmp6 - tmp5; - z11 = tmp4 + tmp7; - z12 = tmp4 - tmp7; - - tmp7 = z11 + z13; /* phase 5 */ - tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ - - z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ - tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */ - tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; /* phase 2 */ - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 - tmp5; - - wsptr[DCTSIZE*0] = tmp0 + tmp7; - wsptr[DCTSIZE*7] = tmp0 - tmp7; - wsptr[DCTSIZE*1] = tmp1 + tmp6; - wsptr[DCTSIZE*6] = tmp1 - tmp6; - wsptr[DCTSIZE*2] = tmp2 + tmp5; - wsptr[DCTSIZE*5] = tmp2 - tmp5; - wsptr[DCTSIZE*3] = tmp3 + tmp4; - wsptr[DCTSIZE*4] = tmp3 - tmp4; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < DCTSIZE; ctr++) { - outptr = output_buf[ctr] + output_col; - /* Rows of zeroes can be exploited in the same way as we did with columns. - * However, the column calculation has created many nonzero AC terms, so - * the simplification applies less often (typically 5% to 10% of the time). - * And testing floats for zero is relatively expensive, so we don't bother. - */ - - /* Even part */ - - /* Prepare range-limit and float->int conversion */ - z5 = wsptr[0] + (((FAST_FLOAT) RANGE_CENTER) + ((FAST_FLOAT) 0.5)); - tmp10 = z5 + wsptr[4]; - tmp11 = z5 - wsptr[4]; - - tmp13 = wsptr[2] + wsptr[6]; - tmp12 = (wsptr[2] - wsptr[6]) * - ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ - - tmp0 = tmp10 + tmp13; - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - z13 = wsptr[5] + wsptr[3]; - z10 = wsptr[5] - wsptr[3]; - z11 = wsptr[1] + wsptr[7]; - z12 = wsptr[1] - wsptr[7]; - - tmp7 = z11 + z13; /* phase 5 */ - tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ - - z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ - tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */ - tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; /* phase 2 */ - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 - tmp5; - - /* Final output stage: float->int conversion and range-limit */ - - outptr[0] = range_limit[(int) (tmp0 + tmp7) & RANGE_MASK]; - outptr[7] = range_limit[(int) (tmp0 - tmp7) & RANGE_MASK]; - outptr[1] = range_limit[(int) (tmp1 + tmp6) & RANGE_MASK]; - outptr[6] = range_limit[(int) (tmp1 - tmp6) & RANGE_MASK]; - outptr[2] = range_limit[(int) (tmp2 + tmp5) & RANGE_MASK]; - outptr[5] = range_limit[(int) (tmp2 - tmp5) & RANGE_MASK]; - outptr[3] = range_limit[(int) (tmp3 + tmp4) & RANGE_MASK]; - outptr[4] = range_limit[(int) (tmp3 - tmp4) & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - -#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/libraries/jpeg/jidctfst.c b/libraries/jpeg/jidctfst.c deleted file mode 100644 index 1ac3e39cb7a..00000000000 --- a/libraries/jpeg/jidctfst.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * jidctfst.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * Modified 2015-2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a fast, not so accurate integer implementation of the - * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - * must also perform dequantization of the input coefficients. - * - * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - * on each row (or vice versa, but it's more convenient to emit a row at - * a time). Direct algorithms are also available, but they are much more - * complex and seem not to be any faster when reduced to code. - * - * This implementation is based on Arai, Agui, and Nakajima's algorithm for - * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - * Japanese, but the algorithm is described in the Pennebaker & Mitchell - * JPEG textbook (see REFERENCES section in file README). The following code - * is based directly on figure 4-8 in P&M. - * While an 8-point DCT cannot be done in less than 11 multiplies, it is - * possible to arrange the computation so that many of the multiplies are - * simple scalings of the final outputs. These multiplies can then be - * folded into the multiplications or divisions by the JPEG quantization - * table entries. The AA&N method leaves only 5 multiplies and 29 adds - * to be done in the DCT itself. - * The primary disadvantage of this method is that with fixed-point math, - * accuracy is lost due to imprecise representation of the scaled - * quantization values. The smaller the quantization table entry, the less - * precise the scaled value, so this implementation does worse with high- - * quality-setting files than with low-quality ones. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_IFAST_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ -#endif - - -/* Scaling decisions are generally the same as in the LL&M algorithm; - * see jidctint.c for more details. However, we choose to descale - * (right shift) multiplication products as soon as they are formed, - * rather than carrying additional fractional bits into subsequent additions. - * This compromises accuracy slightly, but it lets us save a few shifts. - * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) - * everywhere except in the multiplications proper; this saves a good deal - * of work on 16-bit-int machines. - * - * The dequantized coefficients are not integers because the AA&N scaling - * factors have been incorporated. We represent them scaled up by PASS1_BITS, - * so that the first and second IDCT rounds have the same input scaling. - * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to - * avoid a descaling shift; this compromises accuracy rather drastically - * for small quantization table entries, but it saves a lot of shifts. - * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, - * so we use a much larger scaling factor to preserve accuracy. - * - * A final compromise is to represent the multiplicative constants to only - * 8 fractional bits, rather than 13. This saves some shifting work on some - * machines, and may also reduce the cost of multiplication (since there - * are fewer one-bits in the constants). - */ - -#if BITS_IN_JSAMPLE == 8 -#define CONST_BITS 8 -#define PASS1_BITS 2 -#else -#define CONST_BITS 8 -#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ -#endif - -/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus - * causing a lot of useless floating-point operations at run time. - * To get around this we use the following pre-calculated constants. - * If you change CONST_BITS you may want to add appropriate values. - * (With a reasonable C compiler, you can just rely on the FIX() macro...) - */ - -#if CONST_BITS == 8 -#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ -#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ -#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ -#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ -#else -#define FIX_1_082392200 FIX(1.082392200) -#define FIX_1_414213562 FIX(1.414213562) -#define FIX_1_847759065 FIX(1.847759065) -#define FIX_2_613125930 FIX(2.613125930) -#endif - - -/* We can gain a little more speed, with a further compromise in accuracy, - * by omitting the addition in a descaling shift. This yields an incorrectly - * rounded result half the time... - */ - -#ifndef USE_ACCURATE_ROUNDING -#undef DESCALE -#define DESCALE(x,n) RIGHT_SHIFT(x, n) -#endif - - -/* Multiply a DCTELEM variable by an INT32 constant, and immediately - * descale to yield a DCTELEM result. - */ - -#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) - - -/* Dequantize a coefficient by multiplying it by the multiplier-table - * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 - * multiplication will do. For 12-bit data, the multiplier table is - * declared INT32, so a 32-bit multiply will be used. - */ - -#if BITS_IN_JSAMPLE == 8 -#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) -#else -#define DEQUANTIZE(coef,quantval) \ - DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) -#endif - - -/* - * Perform dequantization and inverse DCT on one block of coefficients. - * - * cK represents cos(K*pi/16). - */ - -GLOBAL(void) -jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - DCTELEM tmp10, tmp11, tmp12, tmp13; - DCTELEM z5, z10, z11, z12, z13; - JCOEFPTR inptr; - IFAST_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[DCTSIZE2]; /* buffers data between passes */ - SHIFT_TEMPS /* for DESCALE */ - ISHIFT_TEMPS /* for IRIGHT_SHIFT */ - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - wsptr[DCTSIZE*4] = dcval; - wsptr[DCTSIZE*5] = dcval; - wsptr[DCTSIZE*6] = dcval; - wsptr[DCTSIZE*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp10 = tmp0 + tmp2; /* phase 3 */ - tmp11 = tmp0 - tmp2; - - tmp13 = tmp1 + tmp3; /* phases 5-3 */ - tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ - - tmp0 = tmp10 + tmp13; /* phase 2 */ - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - z13 = tmp6 + tmp5; /* phase 6 */ - z10 = tmp6 - tmp5; - z11 = tmp4 + tmp7; - z12 = tmp4 - tmp7; - - tmp7 = z11 + z13; /* phase 5 */ - tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ - - z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ - tmp10 = z5 - MULTIPLY(z12, FIX_1_082392200); /* 2*(c2-c6) */ - tmp12 = z5 - MULTIPLY(z10, FIX_2_613125930); /* 2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; /* phase 2 */ - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 - tmp5; - - wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); - wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); - wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); - wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); - wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); - wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); - wsptr[DCTSIZE*3] = (int) (tmp3 + tmp4); - wsptr[DCTSIZE*4] = (int) (tmp3 - tmp4); - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process rows from work array, store into output array. - * Note that we must descale the results by a factor of 8 == 2**3, - * and also undo the PASS1_BITS scaling. - */ - - wsptr = workspace; - for (ctr = 0; ctr < DCTSIZE; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Add range center and fudge factor for final descale and range-limit. */ - z5 = (DCTELEM) wsptr[0] + - ((((DCTELEM) RANGE_CENTER) << (PASS1_BITS+3)) + - (1 << (PASS1_BITS+2))); - - /* Rows of zeroes can be exploited in the same way as we did with columns. - * However, the column calculation has created many nonzero AC terms, so - * the simplification applies less often (typically 5% to 10% of the time). - * On machines with very fast multiplication, it's possible that the - * test takes more time than it's worth. In that case this section - * may be commented out. - */ - -#ifndef NO_ZERO_ROW_TEST - if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && - wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { - /* AC terms all zero */ - JSAMPLE dcval = range_limit[(int) IRIGHT_SHIFT(z5, PASS1_BITS+3) - & RANGE_MASK]; - - outptr[0] = dcval; - outptr[1] = dcval; - outptr[2] = dcval; - outptr[3] = dcval; - outptr[4] = dcval; - outptr[5] = dcval; - outptr[6] = dcval; - outptr[7] = dcval; - - wsptr += DCTSIZE; /* advance pointer to next row */ - continue; - } -#endif - - /* Even part */ - - tmp10 = z5 + (DCTELEM) wsptr[4]; - tmp11 = z5 - (DCTELEM) wsptr[4]; - - tmp13 = (DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]; - tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], - FIX_1_414213562) - tmp13; /* 2*c4 */ - - tmp0 = tmp10 + tmp13; - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; - z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; - z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; - z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; - - tmp7 = z11 + z13; /* phase 5 */ - tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ - - z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ - tmp10 = z5 - MULTIPLY(z12, FIX_1_082392200); /* 2*(c2-c6) */ - tmp12 = z5 - MULTIPLY(z10, FIX_2_613125930); /* 2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; /* phase 2 */ - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 - tmp5; - - /* Final output stage: scale down by a factor of 8 and range-limit */ - - outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp7, PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp7, PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp1 + tmp6, PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) IRIGHT_SHIFT(tmp1 - tmp6, PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) IRIGHT_SHIFT(tmp2 + tmp5, PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) IRIGHT_SHIFT(tmp2 - tmp5, PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) IRIGHT_SHIFT(tmp3 + tmp4, PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) IRIGHT_SHIFT(tmp3 - tmp4, PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - -#endif /* DCT_IFAST_SUPPORTED */ diff --git a/libraries/jpeg/jidctint.c b/libraries/jpeg/jidctint.c deleted file mode 100644 index 6437079a31c..00000000000 --- a/libraries/jpeg/jidctint.c +++ /dev/null @@ -1,5240 +0,0 @@ -/* - * jidctint.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * Modification developed 2002-2016 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a slow-but-accurate integer implementation of the - * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - * must also perform dequantization of the input coefficients. - * - * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - * on each row (or vice versa, but it's more convenient to emit a row at - * a time). Direct algorithms are also available, but they are much more - * complex and seem not to be any faster when reduced to code. - * - * This implementation is based on an algorithm described in - * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT - * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, - * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. - * The primary algorithm described there uses 11 multiplies and 29 adds. - * We use their alternate method with 12 multiplies and 32 adds. - * The advantage of this method is that no data path contains more than one - * multiplication; this allows a very simple and accurate implementation in - * scaled fixed-point arithmetic, with a minimal number of shifts. - * - * We also provide IDCT routines with various output sample block sizes for - * direct resolution reduction or enlargement and for direct resolving the - * common 2x1 and 1x2 subsampling cases without additional resampling: NxN - * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 input DCT block. - * - * For N<8 we simply take the corresponding low-frequency coefficients of - * the 8x8 input DCT block and apply an NxN point IDCT on the sub-block - * to yield the downscaled outputs. - * This can be seen as direct low-pass downsampling from the DCT domain - * point of view rather than the usual spatial domain point of view, - * yielding significant computational savings and results at least - * as good as common bilinear (averaging) spatial downsampling. - * - * For N>8 we apply a partial NxN IDCT on the 8 input coefficients as - * lower frequencies and higher frequencies assumed to be zero. - * It turns out that the computational effort is similar to the 8x8 IDCT - * regarding the output size. - * Furthermore, the scaling and descaling is the same for all IDCT sizes. - * - * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases - * since there would be too many additional constants to pre-calculate. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_ISLOW_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ -#endif - - -/* - * The poop on this scaling stuff is as follows: - * - * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) - * larger than the true IDCT outputs. The final outputs are therefore - * a factor of N larger than desired; since N=8 this can be cured by - * a simple right shift at the end of the algorithm. The advantage of - * this arrangement is that we save two multiplications per 1-D IDCT, - * because the y0 and y4 inputs need not be divided by sqrt(N). - * - * We have to do addition and subtraction of the integer inputs, which - * is no problem, and multiplication by fractional constants, which is - * a problem to do in integer arithmetic. We multiply all the constants - * by CONST_SCALE and convert them to integer constants (thus retaining - * CONST_BITS bits of precision in the constants). After doing a - * multiplication we have to divide the product by CONST_SCALE, with proper - * rounding, to produce the correct output. This division can be done - * cheaply as a right shift of CONST_BITS bits. We postpone shifting - * as long as possible so that partial sums can be added together with - * full fractional precision. - * - * The outputs of the first pass are scaled up by PASS1_BITS bits so that - * they are represented to better-than-integral precision. These outputs - * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word - * with the recommended scaling. (To scale up 12-bit sample data further, an - * intermediate INT32 array would be needed.) - * - * To avoid overflow of the 32-bit intermediate results in pass 2, we must - * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis - * shows that the values given below are the most effective. - */ - -#if BITS_IN_JSAMPLE == 8 -#define CONST_BITS 13 -#define PASS1_BITS 2 -#else -#define CONST_BITS 13 -#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ -#endif - -/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus - * causing a lot of useless floating-point operations at run time. - * To get around this we use the following pre-calculated constants. - * If you change CONST_BITS you may want to add appropriate values. - * (With a reasonable C compiler, you can just rely on the FIX() macro...) - */ - -#if CONST_BITS == 13 -#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ -#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ -#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ -#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ -#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ -#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ -#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ -#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ -#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ -#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ -#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ -#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ -#else -#define FIX_0_298631336 FIX(0.298631336) -#define FIX_0_390180644 FIX(0.390180644) -#define FIX_0_541196100 FIX(0.541196100) -#define FIX_0_765366865 FIX(0.765366865) -#define FIX_0_899976223 FIX(0.899976223) -#define FIX_1_175875602 FIX(1.175875602) -#define FIX_1_501321110 FIX(1.501321110) -#define FIX_1_847759065 FIX(1.847759065) -#define FIX_1_961570560 FIX(1.961570560) -#define FIX_2_053119869 FIX(2.053119869) -#define FIX_2_562915447 FIX(2.562915447) -#define FIX_3_072711026 FIX(3.072711026) -#endif - - -/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - * For 8-bit samples with the recommended scaling, all the variable - * and constant values involved are no more than 16 bits wide, so a - * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. - * For 12-bit samples, a full 32-bit multiplication will be needed. - */ - -#if BITS_IN_JSAMPLE == 8 -#define MULTIPLY(var,const) MULTIPLY16C16(var,const) -#else -#define MULTIPLY(var,const) ((var) * (const)) -#endif - - -/* Dequantize a coefficient by multiplying it by the multiplier-table - * entry; produce an int result. In this module, both inputs and result - * are 16 bits or less, so either int or short multiply will work. - */ - -#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) - - -/* - * Perform dequantization and inverse DCT on one block of coefficients. - * - * Optimized algorithm with 12 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/16). - */ - -GLOBAL(void) -jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp3; - INT32 tmp10, tmp11, tmp12, tmp13; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[DCTSIZE2]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * Note results are scaled up by sqrt(8) compared to a true IDCT; - * furthermore, we scale the results by 2**PASS1_BITS. - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - wsptr[DCTSIZE*4] = dcval; - wsptr[DCTSIZE*5] = dcval; - wsptr[DCTSIZE*6] = dcval; - wsptr[DCTSIZE*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part: reverse the even part of the forward DCT. - * The rotator is c(-6). - */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z2 <<= CONST_BITS; - z3 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z2 += ONE << (CONST_BITS-PASS1_BITS-1); - - tmp0 = z2 + z3; - tmp1 = z2 - z3; - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - tmp10 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - tmp11 = tmp1 + tmp3; - tmp12 = tmp1 - tmp3; - - /* Odd part per figure 8; the matrix is unitary and hence its - * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. - */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - - z2 = tmp0 + tmp2; - z3 = tmp1 + tmp3; - - z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ - z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ - z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ - z2 += z1; - z3 += z1; - - z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ - tmp0 += z1 + z2; - tmp3 += z1 + z3; - - z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ - tmp1 += z1 + z3; - tmp2 += z1 + z2; - - /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ - - wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process rows from work array, store into output array. - * Note that we must descale the results by a factor of 8 == 2**3, - * and also undo the PASS1_BITS scaling. - */ - - wsptr = workspace; - for (ctr = 0; ctr < DCTSIZE; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Add range center and fudge factor for final descale and range-limit. */ - z2 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - - /* Rows of zeroes can be exploited in the same way as we did with columns. - * However, the column calculation has created many nonzero AC terms, so - * the simplification applies less often (typically 5% to 10% of the time). - * On machines with very fast multiplication, it's possible that the - * test takes more time than it's worth. In that case this section - * may be commented out. - */ - -#ifndef NO_ZERO_ROW_TEST - if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && - wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { - /* AC terms all zero */ - JSAMPLE dcval = range_limit[(int) RIGHT_SHIFT(z2, PASS1_BITS+3) - & RANGE_MASK]; - - outptr[0] = dcval; - outptr[1] = dcval; - outptr[2] = dcval; - outptr[3] = dcval; - outptr[4] = dcval; - outptr[5] = dcval; - outptr[6] = dcval; - outptr[7] = dcval; - - wsptr += DCTSIZE; /* advance pointer to next row */ - continue; - } -#endif - - /* Even part: reverse the even part of the forward DCT. - * The rotator is c(-6). - */ - - z3 = (INT32) wsptr[4]; - - tmp0 = (z2 + z3) << CONST_BITS; - tmp1 = (z2 - z3) << CONST_BITS; - - z2 = (INT32) wsptr[2]; - z3 = (INT32) wsptr[6]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - tmp10 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - tmp11 = tmp1 + tmp3; - tmp12 = tmp1 - tmp3; - - /* Odd part per figure 8; the matrix is unitary and hence its - * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. - */ - - tmp0 = (INT32) wsptr[7]; - tmp1 = (INT32) wsptr[5]; - tmp2 = (INT32) wsptr[3]; - tmp3 = (INT32) wsptr[1]; - - z2 = tmp0 + tmp2; - z3 = tmp1 + tmp3; - - z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ - z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ - z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ - z2 += z1; - z3 += z1; - - z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ - tmp0 += z1 + z2; - tmp3 += z1 + z3; - - z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ - tmp1 += z1 + z3; - tmp2 += z1 + z2; - - /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - -#ifdef IDCT_SCALING_SUPPORTED - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 7x7 output block. - * - * Optimized algorithm with 12 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/14). - */ - -GLOBAL(void) -jpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[7*7]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp13 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp13 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp13 += ONE << (CONST_BITS-PASS1_BITS-1); - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ - tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ - tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ - tmp0 = z1 + z3; - z2 -= tmp0; - tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */ - tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ - tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ - tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - - tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ - tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ - tmp0 = tmp1 - tmp2; - tmp1 += tmp2; - tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ - tmp1 += tmp2; - z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ - tmp0 += z2; - tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ - - /* Final output stage */ - - wsptr[7*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[7*6] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[7*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[7*5] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[7*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[7*4] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); - wsptr[7*3] = (int) RIGHT_SHIFT(tmp13, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 7 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 7; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp13 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp13 <<= CONST_BITS; - - z1 = (INT32) wsptr[2]; - z2 = (INT32) wsptr[4]; - z3 = (INT32) wsptr[6]; - - tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ - tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ - tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ - tmp0 = z1 + z3; - z2 -= tmp0; - tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */ - tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ - tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ - tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - - tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ - tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ - tmp0 = tmp1 - tmp2; - tmp1 += tmp2; - tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ - tmp1 += tmp2; - z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ - tmp0 += z2; - tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 7; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 6x6 output block. - * - * Optimized algorithm with 3 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/12). - */ - -GLOBAL(void) -jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[6*6]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ - tmp1 = tmp0 + tmp10; - tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS); - tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ - tmp10 = tmp1 + tmp0; - tmp12 = tmp1 - tmp0; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ - tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); - tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); - tmp1 = (z1 - z2 - z3) << PASS1_BITS; - - /* Final output stage */ - - wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[6*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[6*1] = (int) (tmp11 + tmp1); - wsptr[6*4] = (int) (tmp11 - tmp1); - wsptr[6*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[6*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 6 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 6; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp0 <<= CONST_BITS; - tmp2 = (INT32) wsptr[4]; - tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ - tmp1 = tmp0 + tmp10; - tmp11 = tmp0 - tmp10 - tmp10; - tmp10 = (INT32) wsptr[2]; - tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ - tmp10 = tmp1 + tmp0; - tmp12 = tmp1 - tmp0; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ - tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); - tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); - tmp1 = (z1 - z2 - z3) << CONST_BITS; - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 6; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 5x5 output block. - * - * Optimized algorithm with 5 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/10). - */ - -GLOBAL(void) -jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp10, tmp11, tmp12; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[5*5]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp12 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp12 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp0 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */ - z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */ - z3 = tmp12 + z2; - tmp10 = z3 + z1; - tmp11 = z3 - z1; - tmp12 -= z2 << 2; - - /* Odd part */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - - z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ - tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ - tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ - - /* Final output stage */ - - wsptr[5*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[5*4] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[5*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[5*3] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[5*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 5 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 5; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp12 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp12 <<= CONST_BITS; - tmp0 = (INT32) wsptr[2]; - tmp1 = (INT32) wsptr[4]; - z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */ - z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */ - z3 = tmp12 + z2; - tmp10 = z3 + z1; - tmp11 = z3 - z1; - tmp12 -= z2 << 2; - - /* Odd part */ - - z2 = (INT32) wsptr[1]; - z3 = (INT32) wsptr[3]; - - z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ - tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ - tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 5; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 4x4 output block. - * - * Optimized algorithm with 3 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. - */ - -GLOBAL(void) -jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp2, tmp10, tmp12; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[4*4]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - - tmp10 = (tmp0 + tmp2) << PASS1_BITS; - tmp12 = (tmp0 - tmp2) << PASS1_BITS; - - /* Odd part */ - /* Same rotation as in the even part of the 8x8 LL&M IDCT */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - /* Add fudge factor here for final descale. */ - z1 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */ - CONST_BITS-PASS1_BITS); - tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */ - CONST_BITS-PASS1_BITS); - - /* Final output stage */ - - wsptr[4*0] = (int) (tmp10 + tmp0); - wsptr[4*3] = (int) (tmp10 - tmp0); - wsptr[4*1] = (int) (tmp12 + tmp2); - wsptr[4*2] = (int) (tmp12 - tmp2); - } - - /* Pass 2: process 4 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 4; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp2 = (INT32) wsptr[2]; - - tmp10 = (tmp0 + tmp2) << CONST_BITS; - tmp12 = (tmp0 - tmp2) << CONST_BITS; - - /* Odd part */ - /* Same rotation as in the even part of the 8x8 LL&M IDCT */ - - z2 = (INT32) wsptr[1]; - z3 = (INT32) wsptr[3]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 4; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 3x3 output block. - * - * Optimized algorithm with 2 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/6). - */ - -GLOBAL(void) -jpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp2, tmp10, tmp12; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[3*3]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ - tmp10 = tmp0 + tmp12; - tmp2 = tmp0 - tmp12 - tmp12; - - /* Odd part */ - - tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ - - /* Final output stage */ - - wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[3*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[3*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 3 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 3; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp0 <<= CONST_BITS; - tmp2 = (INT32) wsptr[2]; - tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ - tmp10 = tmp0 + tmp12; - tmp2 = tmp0 - tmp12 - tmp12; - - /* Odd part */ - - tmp12 = (INT32) wsptr[1]; - tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 3; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 2x2 output block. - * - * Multiplication-less algorithm. - */ - -GLOBAL(void) -jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - ISLOW_MULT_TYPE * quantptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - ISHIFT_TEMPS - - /* Pass 1: process columns from input. */ - - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - - /* Column 0 */ - tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]); - /* Add range center and fudge factor for final descale and range-limit. */ - tmp4 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2); - - tmp0 = tmp4 + tmp5; - tmp2 = tmp4 - tmp5; - - /* Column 1 */ - tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0+1], quantptr[DCTSIZE*0+1]); - tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1+1], quantptr[DCTSIZE*1+1]); - - tmp1 = tmp4 + tmp5; - tmp3 = tmp4 - tmp5; - - /* Pass 2: process 2 rows, store into output array. */ - - /* Row 0 */ - outptr = output_buf[0] + output_col; - - outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK]; - outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK]; - - /* Row 1 */ - outptr = output_buf[1] + output_col; - - outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp2 + tmp3, 3) & RANGE_MASK]; - outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp2 - tmp3, 3) & RANGE_MASK]; -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 1x1 output block. - * - * We hardly need an inverse DCT routine for this: just take the - * average pixel value, which is one-eighth of the DC coefficient. - */ - -GLOBAL(void) -jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - DCTELEM dcval; - ISLOW_MULT_TYPE * quantptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - ISHIFT_TEMPS - - /* 1x1 is trivial: just take the DC coefficient divided by 8. */ - - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - - dcval = DEQUANTIZE(coef_block[0], quantptr[0]); - /* Add range center and fudge factor for descale and range-limit. */ - dcval += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2); - - output_buf[0][output_col] = - range_limit[(int) IRIGHT_SHIFT(dcval, 3) & RANGE_MASK]; -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 9x9 output block. - * - * Optimized algorithm with 10 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/18). - */ - -GLOBAL(void) -jpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*9]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */ - tmp1 = tmp0 + tmp3; - tmp2 = tmp0 - tmp3 - tmp3; - - tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */ - tmp11 = tmp2 + tmp0; - tmp14 = tmp2 - tmp0 - tmp0; - - tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */ - tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */ - tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */ - - tmp10 = tmp1 + tmp0 - tmp3; - tmp12 = tmp1 - tmp0 + tmp2; - tmp13 = tmp1 - tmp2 + tmp3; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */ - - tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */ - tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */ - tmp0 = tmp2 + tmp3 - z2; - tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */ - tmp2 += z2 - tmp1; - tmp3 += z2 + tmp1; - tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */ - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[8*7] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp13 + tmp3, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp13 - tmp3, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp14, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 9 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 9; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp0 <<= CONST_BITS; - - z1 = (INT32) wsptr[2]; - z2 = (INT32) wsptr[4]; - z3 = (INT32) wsptr[6]; - - tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */ - tmp1 = tmp0 + tmp3; - tmp2 = tmp0 - tmp3 - tmp3; - - tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */ - tmp11 = tmp2 + tmp0; - tmp14 = tmp2 - tmp0 - tmp0; - - tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */ - tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */ - tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */ - - tmp10 = tmp1 + tmp0 - tmp3; - tmp12 = tmp1 - tmp0 + tmp2; - tmp13 = tmp1 - tmp2 + tmp3; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - - z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */ - - tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */ - tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */ - tmp0 = tmp2 + tmp3 - z2; - tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */ - tmp2 += z2 - tmp1; - tmp3 += z2 + tmp1; - tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 10x10 output block. - * - * Optimized algorithm with 12 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/20). - */ - -GLOBAL(void) -jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24; - INT32 z1, z2, z3, z4, z5; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*10]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z3 += ONE << (CONST_BITS-PASS1_BITS-1); - z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ - z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ - tmp10 = z3 + z1; - tmp11 = z3 - z2; - - tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */ - CONST_BITS-PASS1_BITS); - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ - tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ - tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ - - tmp20 = tmp10 + tmp12; - tmp24 = tmp10 - tmp12; - tmp21 = tmp11 + tmp13; - tmp23 = tmp11 - tmp13; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp11 = z2 + z4; - tmp13 = z2 - z4; - - tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ - z5 = z3 << CONST_BITS; - - z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ - z4 = z5 + tmp12; - - tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ - tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ - - z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ - z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1)); - - tmp12 = (z1 - tmp13 - z3) << PASS1_BITS; - - tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ - tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) (tmp22 + tmp12); - wsptr[8*7] = (int) (tmp22 - tmp12); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 10 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 10; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z3 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z3 <<= CONST_BITS; - z4 = (INT32) wsptr[4]; - z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ - z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ - tmp10 = z3 + z1; - tmp11 = z3 - z2; - - tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */ - - z2 = (INT32) wsptr[2]; - z3 = (INT32) wsptr[6]; - - z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ - tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ - tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ - - tmp20 = tmp10 + tmp12; - tmp24 = tmp10 - tmp12; - tmp21 = tmp11 + tmp13; - tmp23 = tmp11 - tmp13; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z3 <<= CONST_BITS; - z4 = (INT32) wsptr[7]; - - tmp11 = z2 + z4; - tmp13 = z2 - z4; - - tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ - - z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ - z4 = z3 + tmp12; - - tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ - tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ - - z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ - z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1)); - - tmp12 = ((z1 - tmp13) << CONST_BITS) - z3; - - tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ - tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 11x11 output block. - * - * Optimized algorithm with 24 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/22). - */ - -GLOBAL(void) -jpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*11]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp10 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp10 += ONE << (CONST_BITS-PASS1_BITS-1); - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */ - tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */ - z4 = z1 + z3; - tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */ - z4 -= z2; - tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */ - tmp21 = tmp20 + tmp23 + tmp25 - - MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */ - tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */ - tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */ - tmp24 += tmp25; - tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */ - tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */ - MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */ - tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */ - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp11 = z1 + z2; - tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */ - tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */ - tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */ - tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */ - tmp10 = tmp11 + tmp12 + tmp13 - - MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */ - z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */ - tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */ - tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */ - z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */ - tmp11 += z1; - tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */ - tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */ - MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */ - MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */ - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*10] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*9] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*7] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp25, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 11 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 11; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp10 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp10 <<= CONST_BITS; - - z1 = (INT32) wsptr[2]; - z2 = (INT32) wsptr[4]; - z3 = (INT32) wsptr[6]; - - tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */ - tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */ - z4 = z1 + z3; - tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */ - z4 -= z2; - tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */ - tmp21 = tmp20 + tmp23 + tmp25 - - MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */ - tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */ - tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */ - tmp24 += tmp25; - tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */ - tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */ - MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */ - tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */ - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - - tmp11 = z1 + z2; - tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */ - tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */ - tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */ - tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */ - tmp10 = tmp11 + tmp12 + tmp13 - - MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */ - z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */ - tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */ - tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */ - z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */ - tmp11 += z1; - tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */ - tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */ - MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */ - MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 12x12 output block. - * - * Optimized algorithm with 15 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/24). - */ - -GLOBAL(void) -jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*12]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z3 += ONE << (CONST_BITS-PASS1_BITS-1); - - z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ - - tmp10 = z3 + z4; - tmp11 = z3 - z4; - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ - z1 <<= CONST_BITS; - z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - z2 <<= CONST_BITS; - - tmp12 = z1 - z2; - - tmp21 = z3 + tmp12; - tmp24 = z3 - tmp12; - - tmp12 = z4 + z2; - - tmp20 = tmp10 + tmp12; - tmp25 = tmp10 - tmp12; - - tmp12 = z4 - z1 - z2; - - tmp22 = tmp11 + tmp12; - tmp23 = tmp11 - tmp12; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ - tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ - - tmp10 = z1 + z3; - tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ - tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ - tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ - tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ - tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ - tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ - tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ - MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ - - z1 -= z4; - z2 -= z3; - z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ - tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ - tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 12 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 12; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z3 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z3 <<= CONST_BITS; - - z4 = (INT32) wsptr[4]; - z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ - - tmp10 = z3 + z4; - tmp11 = z3 - z4; - - z1 = (INT32) wsptr[2]; - z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ - z1 <<= CONST_BITS; - z2 = (INT32) wsptr[6]; - z2 <<= CONST_BITS; - - tmp12 = z1 - z2; - - tmp21 = z3 + tmp12; - tmp24 = z3 - tmp12; - - tmp12 = z4 + z2; - - tmp20 = tmp10 + tmp12; - tmp25 = tmp10 - tmp12; - - tmp12 = z4 - z1 - z2; - - tmp22 = tmp11 + tmp12; - tmp23 = tmp11 - tmp12; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - - tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ - tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ - - tmp10 = z1 + z3; - tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ - tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ - tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ - tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ - tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ - tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ - tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ - MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ - - z1 -= z4; - z2 -= z3; - z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ - tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ - tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 13x13 output block. - * - * Optimized algorithm with 29 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/26). - */ - -GLOBAL(void) -jpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*13]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z1 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z1 += ONE << (CONST_BITS-PASS1_BITS-1); - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp10 = z3 + z4; - tmp11 = z3 - z4; - - tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */ - tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */ - - tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */ - tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */ - - tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */ - tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */ - - tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */ - tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */ - - tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */ - tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */ - - tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */ - tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */ - - tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */ - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */ - tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */ - tmp15 = z1 + z4; - tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */ - tmp10 = tmp11 + tmp12 + tmp13 - - MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */ - tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */ - tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */ - tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */ - tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */ - tmp11 += tmp14; - tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */ - tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */ - tmp12 += tmp14; - tmp13 += tmp14; - tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */ - tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */ - MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */ - z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */ - tmp14 += z1; - tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */ - MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */ - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*12] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*11] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*10] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*9] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); - wsptr[8*7] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp26, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 13 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 13; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z1 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z1 <<= CONST_BITS; - - z2 = (INT32) wsptr[2]; - z3 = (INT32) wsptr[4]; - z4 = (INT32) wsptr[6]; - - tmp10 = z3 + z4; - tmp11 = z3 - z4; - - tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */ - tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */ - - tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */ - tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */ - - tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */ - tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */ - - tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */ - tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */ - - tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */ - tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */ - - tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */ - tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */ - - tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */ - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - - tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */ - tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */ - tmp15 = z1 + z4; - tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */ - tmp10 = tmp11 + tmp12 + tmp13 - - MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */ - tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */ - tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */ - tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */ - tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */ - tmp11 += tmp14; - tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */ - tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */ - tmp12 += tmp14; - tmp13 += tmp14; - tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */ - tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */ - MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */ - z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */ - tmp14 += z1; - tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */ - MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 14x14 output block. - * - * Optimized algorithm with 20 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/28). - */ - -GLOBAL(void) -jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*14]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z1 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z1 += ONE << (CONST_BITS-PASS1_BITS-1); - z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ - z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ - z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ - - tmp10 = z1 + z2; - tmp11 = z1 + z3; - tmp12 = z1 - z4; - - tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */ - CONST_BITS-PASS1_BITS); - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ - - tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ - tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ - tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ - MULTIPLY(z2, FIX(1.378756276)); /* c2 */ - - tmp20 = tmp10 + tmp13; - tmp26 = tmp10 - tmp13; - tmp21 = tmp11 + tmp14; - tmp25 = tmp11 - tmp14; - tmp22 = tmp12 + tmp15; - tmp24 = tmp12 - tmp15; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - tmp13 = z4 << CONST_BITS; - - tmp14 = z1 + z3; - tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ - tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ - tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ - tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ - tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ - z1 -= z2; - tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */ - tmp16 += tmp15; - z1 += z4; - z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */ - tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ - tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ - z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ - tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ - tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ - - tmp13 = (z1 - z3) << PASS1_BITS; - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) (tmp23 + tmp13); - wsptr[8*10] = (int) (tmp23 - tmp13); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); - wsptr[8*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 14 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 14; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z1 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z1 <<= CONST_BITS; - z4 = (INT32) wsptr[4]; - z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ - z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ - z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ - - tmp10 = z1 + z2; - tmp11 = z1 + z3; - tmp12 = z1 - z4; - - tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */ - - z1 = (INT32) wsptr[2]; - z2 = (INT32) wsptr[6]; - - z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ - - tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ - tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ - tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ - MULTIPLY(z2, FIX(1.378756276)); /* c2 */ - - tmp20 = tmp10 + tmp13; - tmp26 = tmp10 - tmp13; - tmp21 = tmp11 + tmp14; - tmp25 = tmp11 - tmp14; - tmp22 = tmp12 + tmp15; - tmp24 = tmp12 - tmp15; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - z4 <<= CONST_BITS; - - tmp14 = z1 + z3; - tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ - tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ - tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ - tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ - tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ - z1 -= z2; - tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */ - tmp16 += tmp15; - tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */ - tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ - tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ - tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ - tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ - tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ - - tmp13 = ((z1 - z3) << CONST_BITS) + z4; - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 15x15 output block. - * - * Optimized algorithm with 22 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/30). - */ - -GLOBAL(void) -jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*15]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z1 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z1 += ONE << (CONST_BITS-PASS1_BITS-1); - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */ - tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */ - - tmp12 = z1 - tmp10; - tmp13 = z1 + tmp11; - z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */ - - z4 = z2 - z3; - z3 += z2; - tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */ - tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */ - z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */ - - tmp20 = tmp13 + tmp10 + tmp11; - tmp23 = tmp12 - tmp10 + tmp11 + z2; - - tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */ - tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */ - - tmp25 = tmp13 - tmp10 - tmp11; - tmp26 = tmp12 + tmp10 - tmp11 - z2; - - tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */ - tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */ - - tmp21 = tmp12 + tmp10 + tmp11; - tmp24 = tmp13 - tmp10 + tmp11; - tmp11 += tmp11; - tmp22 = z1 + tmp11; /* c10 = c6-c12 */ - tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */ - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z4 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */ - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp13 = z2 - z4; - tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */ - tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */ - tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */ - - tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */ - tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */ - z2 = z1 - z4; - tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */ - - tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */ - tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */ - tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */ - z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */ - tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */ - tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */ - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*14] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*13] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*12] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*11] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*10] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); - wsptr[8*9] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); - wsptr[8*7] = (int) RIGHT_SHIFT(tmp27, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 15 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 15; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z1 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z1 <<= CONST_BITS; - - z2 = (INT32) wsptr[2]; - z3 = (INT32) wsptr[4]; - z4 = (INT32) wsptr[6]; - - tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */ - tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */ - - tmp12 = z1 - tmp10; - tmp13 = z1 + tmp11; - z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */ - - z4 = z2 - z3; - z3 += z2; - tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */ - tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */ - z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */ - - tmp20 = tmp13 + tmp10 + tmp11; - tmp23 = tmp12 - tmp10 + tmp11 + z2; - - tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */ - tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */ - - tmp25 = tmp13 - tmp10 - tmp11; - tmp26 = tmp12 + tmp10 - tmp11 - z2; - - tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */ - tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */ - - tmp21 = tmp12 + tmp10 + tmp11; - tmp24 = tmp13 - tmp10 + tmp11; - tmp11 += tmp11; - tmp22 = z1 + tmp11; /* c10 = c6-c12 */ - tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */ - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z4 = (INT32) wsptr[5]; - z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */ - z4 = (INT32) wsptr[7]; - - tmp13 = z2 - z4; - tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */ - tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */ - tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */ - - tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */ - tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */ - z2 = z1 - z4; - tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */ - - tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */ - tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */ - tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */ - z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */ - tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */ - tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 16x16 output block. - * - * Optimized algorithm with 28 multiplications in the 1-D kernel. - * cK represents sqrt(2) * cos(K*pi/32). - */ - -GLOBAL(void) -jpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*16]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); - - z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ - tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ - - tmp10 = tmp0 + tmp1; - tmp11 = tmp0 - tmp1; - tmp12 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - z3 = z1 - z2; - z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ - z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ - - tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ - tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ - tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ - tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ - - tmp20 = tmp10 + tmp0; - tmp27 = tmp10 - tmp0; - tmp21 = tmp12 + tmp1; - tmp26 = tmp12 - tmp1; - tmp22 = tmp13 + tmp2; - tmp25 = tmp13 - tmp2; - tmp23 = tmp11 + tmp3; - tmp24 = tmp11 - tmp3; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp11 = z1 + z3; - - tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ - tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ - tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ - tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ - tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ - tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ - tmp0 = tmp1 + tmp2 + tmp3 - - MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ - tmp13 = tmp10 + tmp11 + tmp12 - - MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ - z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ - tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ - tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ - z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ - tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ - tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ - z2 += z4; - z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ - tmp1 += z1; - tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ - z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ - tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ - tmp12 += z2; - z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ - tmp2 += z2; - tmp3 += z2; - z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ - tmp10 += z2; - tmp11 += z2; - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS); - wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 16 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 16; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp0 <<= CONST_BITS; - - z1 = (INT32) wsptr[4]; - tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ - tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ - - tmp10 = tmp0 + tmp1; - tmp11 = tmp0 - tmp1; - tmp12 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - - z1 = (INT32) wsptr[2]; - z2 = (INT32) wsptr[6]; - z3 = z1 - z2; - z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ - z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ - - tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ - tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ - tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ - tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ - - tmp20 = tmp10 + tmp0; - tmp27 = tmp10 - tmp0; - tmp21 = tmp12 + tmp1; - tmp26 = tmp12 - tmp1; - tmp22 = tmp13 + tmp2; - tmp25 = tmp13 - tmp2; - tmp23 = tmp11 + tmp3; - tmp24 = tmp11 - tmp3; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - - tmp11 = z1 + z3; - - tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ - tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ - tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ - tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ - tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ - tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ - tmp0 = tmp1 + tmp2 + tmp3 - - MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ - tmp13 = tmp10 + tmp11 + tmp12 - - MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ - z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ - tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ - tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ - z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ - tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ - tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ - z2 += z4; - z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ - tmp1 += z1; - tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ - z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ - tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ - tmp12 += z2; - z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ - tmp2 += z2; - tmp3 += z2; - z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ - tmp10 += z2; - tmp11 += z2; - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 16x8 output block. - * - * 8-point IDCT in pass 1 (columns), 16-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_16x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*8]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * Note results are scaled up by sqrt(8) compared to a true IDCT; - * furthermore, we scale the results by 2**PASS1_BITS. - * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - wsptr[DCTSIZE*4] = dcval; - wsptr[DCTSIZE*5] = dcval; - wsptr[DCTSIZE*6] = dcval; - wsptr[DCTSIZE*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part: reverse the even part of the forward DCT. - * The rotator is c(-6). - */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z2 <<= CONST_BITS; - z3 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z2 += ONE << (CONST_BITS-PASS1_BITS-1); - - tmp0 = z2 + z3; - tmp1 = z2 - z3; - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - tmp10 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - tmp11 = tmp1 + tmp3; - tmp12 = tmp1 - tmp3; - - /* Odd part per figure 8; the matrix is unitary and hence its - * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. - */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - - z2 = tmp0 + tmp2; - z3 = tmp1 + tmp3; - - z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ - z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ - z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ - z2 += z1; - z3 += z1; - - z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ - tmp0 += z1 + z2; - tmp3 += z1 + z3; - - z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ - tmp1 += z1 + z3; - tmp2 += z1 + z2; - - /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ - - wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process 8 rows from work array, store into output array. - * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp0 <<= CONST_BITS; - - z1 = (INT32) wsptr[4]; - tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ - tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ - - tmp10 = tmp0 + tmp1; - tmp11 = tmp0 - tmp1; - tmp12 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - - z1 = (INT32) wsptr[2]; - z2 = (INT32) wsptr[6]; - z3 = z1 - z2; - z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ - z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ - - tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ - tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ - tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ - tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ - - tmp20 = tmp10 + tmp0; - tmp27 = tmp10 - tmp0; - tmp21 = tmp12 + tmp1; - tmp26 = tmp12 - tmp1; - tmp22 = tmp13 + tmp2; - tmp25 = tmp13 - tmp2; - tmp23 = tmp11 + tmp3; - tmp24 = tmp11 - tmp3; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - - tmp11 = z1 + z3; - - tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ - tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ - tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ - tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ - tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ - tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ - tmp0 = tmp1 + tmp2 + tmp3 - - MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ - tmp13 = tmp10 + tmp11 + tmp12 - - MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ - z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ - tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ - tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ - z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ - tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ - tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ - z2 += z4; - z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ - tmp1 += z1; - tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ - z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ - tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ - tmp12 += z2; - z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ - tmp2 += z2; - tmp3 += z2; - z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ - tmp10 += z2; - tmp11 += z2; - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 14x7 output block. - * - * 7-point IDCT in pass 1 (columns), 14-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_14x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*7]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp23 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp23 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp23 += ONE << (CONST_BITS-PASS1_BITS-1); - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ - tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ - tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ - tmp10 = z1 + z3; - z2 -= tmp10; - tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */ - tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ - tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ - tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - - tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ - tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ - tmp10 = tmp11 - tmp12; - tmp11 += tmp12; - tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ - tmp11 += tmp12; - z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ - tmp10 += z2; - tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp23, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 7 rows from work array, store into output array. - * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 7; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z1 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z1 <<= CONST_BITS; - z4 = (INT32) wsptr[4]; - z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ - z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ - z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ - - tmp10 = z1 + z2; - tmp11 = z1 + z3; - tmp12 = z1 - z4; - - tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */ - - z1 = (INT32) wsptr[2]; - z2 = (INT32) wsptr[6]; - - z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ - - tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ - tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ - tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ - MULTIPLY(z2, FIX(1.378756276)); /* c2 */ - - tmp20 = tmp10 + tmp13; - tmp26 = tmp10 - tmp13; - tmp21 = tmp11 + tmp14; - tmp25 = tmp11 - tmp14; - tmp22 = tmp12 + tmp15; - tmp24 = tmp12 - tmp15; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - z4 <<= CONST_BITS; - - tmp14 = z1 + z3; - tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ - tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ - tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ - tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ - tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ - z1 -= z2; - tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */ - tmp16 += tmp15; - tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */ - tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ - tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ - tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ - tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ - tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ - - tmp13 = ((z1 - z3) << CONST_BITS) + z4; - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 12x6 output block. - * - * 6-point IDCT in pass 1 (columns), 12-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_12x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*6]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp10 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp10 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp12 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */ - tmp11 = tmp10 + tmp20; - tmp21 = RIGHT_SHIFT(tmp10 - tmp20 - tmp20, CONST_BITS-PASS1_BITS); - tmp20 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */ - tmp20 = tmp11 + tmp10; - tmp22 = tmp11 - tmp10; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ - tmp10 = tmp11 + ((z1 + z2) << CONST_BITS); - tmp12 = tmp11 + ((z3 - z2) << CONST_BITS); - tmp11 = (z1 - z2 - z3) << PASS1_BITS; - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) (tmp21 + tmp11); - wsptr[8*4] = (int) (tmp21 - tmp11); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 6 rows from work array, store into output array. - * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 6; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z3 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z3 <<= CONST_BITS; - - z4 = (INT32) wsptr[4]; - z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ - - tmp10 = z3 + z4; - tmp11 = z3 - z4; - - z1 = (INT32) wsptr[2]; - z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ - z1 <<= CONST_BITS; - z2 = (INT32) wsptr[6]; - z2 <<= CONST_BITS; - - tmp12 = z1 - z2; - - tmp21 = z3 + tmp12; - tmp24 = z3 - tmp12; - - tmp12 = z4 + z2; - - tmp20 = tmp10 + tmp12; - tmp25 = tmp10 - tmp12; - - tmp12 = z4 - z1 - z2; - - tmp22 = tmp11 + tmp12; - tmp23 = tmp11 - tmp12; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z4 = (INT32) wsptr[7]; - - tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ - tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ - - tmp10 = z1 + z3; - tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ - tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ - tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ - tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ - tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ - tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ - tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ - MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ - - z1 -= z4; - z2 -= z3; - z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ - tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ - tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 10x5 output block. - * - * 5-point IDCT in pass 1 (columns), 10-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_10x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*5]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp12 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp12 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp13 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp14 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */ - z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */ - z3 = tmp12 + z2; - tmp10 = z3 + z1; - tmp11 = z3 - z1; - tmp12 -= z2 << 2; - - /* Odd part */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - - z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ - tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ - tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp10 - tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp11 - tmp14, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 5 rows from work array, store into output array. - * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 5; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z3 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z3 <<= CONST_BITS; - z4 = (INT32) wsptr[4]; - z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ - z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ - tmp10 = z3 + z1; - tmp11 = z3 - z2; - - tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */ - - z2 = (INT32) wsptr[2]; - z3 = (INT32) wsptr[6]; - - z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ - tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ - tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ - - tmp20 = tmp10 + tmp12; - tmp24 = tmp10 - tmp12; - tmp21 = tmp11 + tmp13; - tmp23 = tmp11 - tmp13; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - z3 <<= CONST_BITS; - z4 = (INT32) wsptr[7]; - - tmp11 = z2 + z4; - tmp13 = z2 - z4; - - tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ - - z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ - z4 = z3 + tmp12; - - tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ - tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ - - z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ - z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1)); - - tmp12 = ((z1 - tmp13) << CONST_BITS) - z3; - - tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ - tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 8; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 8x4 output block. - * - * 4-point IDCT in pass 1 (columns), 8-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_8x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp3; - INT32 tmp10, tmp11, tmp12, tmp13; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*4]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 4-point IDCT kernel, - * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - - tmp10 = (tmp0 + tmp2) << PASS1_BITS; - tmp12 = (tmp0 - tmp2) << PASS1_BITS; - - /* Odd part */ - /* Same rotation as in the even part of the 8x8 LL&M IDCT */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - /* Add fudge factor here for final descale. */ - z1 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */ - CONST_BITS-PASS1_BITS); - tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */ - CONST_BITS-PASS1_BITS); - - /* Final output stage */ - - wsptr[8*0] = (int) (tmp10 + tmp0); - wsptr[8*3] = (int) (tmp10 - tmp0); - wsptr[8*1] = (int) (tmp12 + tmp2); - wsptr[8*2] = (int) (tmp12 - tmp2); - } - - /* Pass 2: process rows from work array, store into output array. - * Note that we must descale the results by a factor of 8 == 2**3, - * and also undo the PASS1_BITS scaling. - * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 4; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part: reverse the even part of the forward DCT. - * The rotator is c(-6). - */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z2 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z3 = (INT32) wsptr[4]; - - tmp0 = (z2 + z3) << CONST_BITS; - tmp1 = (z2 - z3) << CONST_BITS; - - z2 = (INT32) wsptr[2]; - z3 = (INT32) wsptr[6]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - tmp10 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - tmp11 = tmp1 + tmp3; - tmp12 = tmp1 - tmp3; - - /* Odd part per figure 8; the matrix is unitary and hence its - * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. - */ - - tmp0 = (INT32) wsptr[7]; - tmp1 = (INT32) wsptr[5]; - tmp2 = (INT32) wsptr[3]; - tmp3 = (INT32) wsptr[1]; - - z2 = tmp0 + tmp2; - z3 = tmp1 + tmp3; - - z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ - z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ - z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ - z2 += z1; - z3 += z1; - - z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ - tmp0 += z1 + z2; - tmp3 += z1 + z3; - - z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ - tmp1 += z1 + z3; - tmp2 += z1 + z2; - - /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 6x3 output block. - * - * 3-point IDCT in pass 1 (columns), 6-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_6x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[6*3]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ - tmp10 = tmp0 + tmp12; - tmp2 = tmp0 - tmp12 - tmp12; - - /* Odd part */ - - tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ - - /* Final output stage */ - - wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[6*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[6*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 3 rows from work array, store into output array. - * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 3; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp0 <<= CONST_BITS; - tmp2 = (INT32) wsptr[4]; - tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ - tmp1 = tmp0 + tmp10; - tmp11 = tmp0 - tmp10 - tmp10; - tmp10 = (INT32) wsptr[2]; - tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ - tmp10 = tmp1 + tmp0; - tmp12 = tmp1 - tmp0; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ - tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); - tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); - tmp1 = (z1 - z2 - z3) << CONST_BITS; - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 6; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 4x2 output block. - * - * 2-point IDCT in pass 1 (columns), 4-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_4x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp2, tmp10, tmp12; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - INT32 * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - INT32 workspace[4*2]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - - /* Odd part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - - /* Final output stage */ - - wsptr[4*0] = tmp10 + tmp0; - wsptr[4*1] = tmp10 - tmp0; - } - - /* Pass 2: process 2 rows from work array, store into output array. - * 4-point IDCT kernel, - * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. - */ - - wsptr = workspace; - for (ctr = 0; ctr < 2; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = wsptr[0] + ((((INT32) RANGE_CENTER) << 3) + (ONE << 2)); - tmp2 = wsptr[2]; - - tmp10 = (tmp0 + tmp2) << CONST_BITS; - tmp12 = (tmp0 - tmp2) << CONST_BITS; - - /* Odd part */ - /* Same rotation as in the even part of the 8x8 LL&M IDCT */ - - z2 = wsptr[1]; - z3 = wsptr[3]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, - CONST_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, - CONST_BITS+3) - & RANGE_MASK]; - - wsptr += 4; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 2x1 output block. - * - * 1-point IDCT in pass 1 (columns), 2-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_2x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - DCTELEM tmp0, tmp1; - ISLOW_MULT_TYPE * quantptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - ISHIFT_TEMPS - - /* Pass 1: empty. */ - - /* Pass 2: process 1 row from input, store into output array. */ - - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - outptr = output_buf[0] + output_col; - - /* Even part */ - - tmp0 = DEQUANTIZE(coef_block[0], quantptr[0]); - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2); - - /* Odd part */ - - tmp1 = DEQUANTIZE(coef_block[1], quantptr[1]); - - /* Final output stage */ - - outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK]; - outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK]; -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 8x16 output block. - * - * 16-point IDCT in pass 1 (columns), 8-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_8x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[8*16]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); - - z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ - tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ - - tmp10 = tmp0 + tmp1; - tmp11 = tmp0 - tmp1; - tmp12 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - z3 = z1 - z2; - z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ - z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ - - tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ - tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ - tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ - tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ - - tmp20 = tmp10 + tmp0; - tmp27 = tmp10 - tmp0; - tmp21 = tmp12 + tmp1; - tmp26 = tmp12 - tmp1; - tmp22 = tmp13 + tmp2; - tmp25 = tmp13 - tmp2; - tmp23 = tmp11 + tmp3; - tmp24 = tmp11 - tmp3; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp11 = z1 + z3; - - tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ - tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ - tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ - tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ - tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ - tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ - tmp0 = tmp1 + tmp2 + tmp3 - - MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ - tmp13 = tmp10 + tmp11 + tmp12 - - MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ - z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ - tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ - tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ - z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ - tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ - tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ - z2 += z4; - z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ - tmp1 += z1; - tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ - z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ - tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ - tmp12 += z2; - z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ - tmp2 += z2; - tmp3 += z2; - z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ - tmp10 += z2; - tmp11 += z2; - - /* Final output stage */ - - wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS); - wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS); - wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS); - wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process rows from work array, store into output array. - * Note that we must descale the results by a factor of 8 == 2**3, - * and also undo the PASS1_BITS scaling. - * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 16; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part: reverse the even part of the forward DCT. - * The rotator is c(-6). - */ - - /* Add range center and fudge factor for final descale and range-limit. */ - z2 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - z3 = (INT32) wsptr[4]; - - tmp0 = (z2 + z3) << CONST_BITS; - tmp1 = (z2 - z3) << CONST_BITS; - - z2 = (INT32) wsptr[2]; - z3 = (INT32) wsptr[6]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - tmp10 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - tmp11 = tmp1 + tmp3; - tmp12 = tmp1 - tmp3; - - /* Odd part per figure 8; the matrix is unitary and hence its - * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. - */ - - tmp0 = (INT32) wsptr[7]; - tmp1 = (INT32) wsptr[5]; - tmp2 = (INT32) wsptr[3]; - tmp3 = (INT32) wsptr[1]; - - z2 = tmp0 + tmp2; - z3 = tmp1 + tmp3; - - z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ - z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ - z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ - z2 += z1; - z3 += z1; - - z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ - tmp0 += z1 + z2; - tmp3 += z1 + z3; - - z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ - tmp1 += z1 + z3; - tmp2 += z1 + z2; - - /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 7x14 output block. - * - * 14-point IDCT in pass 1 (columns), 7-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_7x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[7*14]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z1 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z1 += ONE << (CONST_BITS-PASS1_BITS-1); - z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ - z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ - z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ - - tmp10 = z1 + z2; - tmp11 = z1 + z3; - tmp12 = z1 - z4; - - tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */ - CONST_BITS-PASS1_BITS); - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ - - tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ - tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ - tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ - MULTIPLY(z2, FIX(1.378756276)); /* c2 */ - - tmp20 = tmp10 + tmp13; - tmp26 = tmp10 - tmp13; - tmp21 = tmp11 + tmp14; - tmp25 = tmp11 - tmp14; - tmp22 = tmp12 + tmp15; - tmp24 = tmp12 - tmp15; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - tmp13 = z4 << CONST_BITS; - - tmp14 = z1 + z3; - tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ - tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ - tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ - tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ - tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ - z1 -= z2; - tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */ - tmp16 += tmp15; - z1 += z4; - z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */ - tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ - tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ - z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ - tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ - tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ - - tmp13 = (z1 - z3) << PASS1_BITS; - - /* Final output stage */ - - wsptr[7*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[7*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[7*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[7*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[7*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[7*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[7*3] = (int) (tmp23 + tmp13); - wsptr[7*10] = (int) (tmp23 - tmp13); - wsptr[7*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[7*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - wsptr[7*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); - wsptr[7*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); - wsptr[7*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); - wsptr[7*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 14 rows from work array, store into output array. - * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 14; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp23 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp23 <<= CONST_BITS; - - z1 = (INT32) wsptr[2]; - z2 = (INT32) wsptr[4]; - z3 = (INT32) wsptr[6]; - - tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ - tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ - tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ - tmp10 = z1 + z3; - z2 -= tmp10; - tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */ - tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ - tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ - tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - - tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ - tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ - tmp10 = tmp11 - tmp12; - tmp11 += tmp12; - tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ - tmp11 += tmp12; - z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ - tmp10 += z2; - tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 7; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 6x12 output block. - * - * 12-point IDCT in pass 1 (columns), 6-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_6x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[6*12]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z3 += ONE << (CONST_BITS-PASS1_BITS-1); - - z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ - - tmp10 = z3 + z4; - tmp11 = z3 - z4; - - z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ - z1 <<= CONST_BITS; - z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - z2 <<= CONST_BITS; - - tmp12 = z1 - z2; - - tmp21 = z3 + tmp12; - tmp24 = z3 - tmp12; - - tmp12 = z4 + z2; - - tmp20 = tmp10 + tmp12; - tmp25 = tmp10 - tmp12; - - tmp12 = z4 - z1 - z2; - - tmp22 = tmp11 + tmp12; - tmp23 = tmp11 - tmp12; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ - tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ - - tmp10 = z1 + z3; - tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ - tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ - tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ - tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ - tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ - tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ - tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ - MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ - - z1 -= z4; - z2 -= z3; - z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ - tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ - tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ - - /* Final output stage */ - - wsptr[6*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[6*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[6*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[6*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[6*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); - wsptr[6*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); - wsptr[6*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[6*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); - wsptr[6*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[6*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - wsptr[6*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); - wsptr[6*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 12 rows from work array, store into output array. - * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 12; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp10 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp10 <<= CONST_BITS; - tmp12 = (INT32) wsptr[4]; - tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */ - tmp11 = tmp10 + tmp20; - tmp21 = tmp10 - tmp20 - tmp20; - tmp20 = (INT32) wsptr[2]; - tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */ - tmp20 = tmp11 + tmp10; - tmp22 = tmp11 - tmp10; - - /* Odd part */ - - z1 = (INT32) wsptr[1]; - z2 = (INT32) wsptr[3]; - z3 = (INT32) wsptr[5]; - tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ - tmp10 = tmp11 + ((z1 + z2) << CONST_BITS); - tmp12 = tmp11 + ((z3 - z2) << CONST_BITS); - tmp11 = (z1 - z2 - z3) << CONST_BITS; - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 6; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 5x10 output block. - * - * 10-point IDCT in pass 1 (columns), 5-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_5x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp10, tmp11, tmp12, tmp13, tmp14; - INT32 tmp20, tmp21, tmp22, tmp23, tmp24; - INT32 z1, z2, z3, z4, z5; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[5*10]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z3 += ONE << (CONST_BITS-PASS1_BITS-1); - z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ - z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ - tmp10 = z3 + z1; - tmp11 = z3 - z2; - - tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */ - CONST_BITS-PASS1_BITS); - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ - tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ - tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ - - tmp20 = tmp10 + tmp12; - tmp24 = tmp10 - tmp12; - tmp21 = tmp11 + tmp13; - tmp23 = tmp11 - tmp13; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - tmp11 = z2 + z4; - tmp13 = z2 - z4; - - tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ - z5 = z3 << CONST_BITS; - - z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ - z4 = z5 + tmp12; - - tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ - tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ - - z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ - z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1)); - - tmp12 = (z1 - tmp13 - z3) << PASS1_BITS; - - tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ - tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ - - /* Final output stage */ - - wsptr[5*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); - wsptr[5*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); - wsptr[5*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); - wsptr[5*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); - wsptr[5*2] = (int) (tmp22 + tmp12); - wsptr[5*7] = (int) (tmp22 - tmp12); - wsptr[5*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); - wsptr[5*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); - wsptr[5*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); - wsptr[5*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 10 rows from work array, store into output array. - * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 10; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp12 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp12 <<= CONST_BITS; - tmp13 = (INT32) wsptr[2]; - tmp14 = (INT32) wsptr[4]; - z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */ - z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */ - z3 = tmp12 + z2; - tmp10 = z3 + z1; - tmp11 = z3 - z1; - tmp12 -= z2 << 2; - - /* Odd part */ - - z2 = (INT32) wsptr[1]; - z3 = (INT32) wsptr[3]; - - z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ - tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ - tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp13, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp14, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 5; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 4x8 output block. - * - * 8-point IDCT in pass 1 (columns), 4-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_4x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp3; - INT32 tmp10, tmp11, tmp12, tmp13; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[4*8]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * Note results are scaled up by sqrt(8) compared to a true IDCT; - * furthermore, we scale the results by 2**PASS1_BITS. - * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 4; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; - - wsptr[4*0] = dcval; - wsptr[4*1] = dcval; - wsptr[4*2] = dcval; - wsptr[4*3] = dcval; - wsptr[4*4] = dcval; - wsptr[4*5] = dcval; - wsptr[4*6] = dcval; - wsptr[4*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part: reverse the even part of the forward DCT. - * The rotator is c(-6). - */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - z2 <<= CONST_BITS; - z3 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - z2 += ONE << (CONST_BITS-PASS1_BITS-1); - - tmp0 = z2 + z3; - tmp1 = z2 - z3; - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - tmp10 = tmp0 + tmp2; - tmp13 = tmp0 - tmp2; - tmp11 = tmp1 + tmp3; - tmp12 = tmp1 - tmp3; - - /* Odd part per figure 8; the matrix is unitary and hence its - * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. - */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - - z2 = tmp0 + tmp2; - z3 = tmp1 + tmp3; - - z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* c3 */ - z2 = MULTIPLY(z2, - FIX_1_961570560); /* -c3-c5 */ - z3 = MULTIPLY(z3, - FIX_0_390180644); /* -c3+c5 */ - z2 += z1; - z3 += z1; - - z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */ - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* -c1+c3+c5-c7 */ - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* c1+c3-c5-c7 */ - tmp0 += z1 + z2; - tmp3 += z1 + z3; - - z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */ - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* c1+c3-c5+c7 */ - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* c1+c3+c5-c7 */ - tmp1 += z1 + z3; - tmp2 += z1 + z2; - - /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ - - wsptr[4*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); - wsptr[4*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); - wsptr[4*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[4*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); - wsptr[4*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[4*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[4*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[4*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process 8 rows from work array, store into output array. - * 4-point IDCT kernel, - * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. - */ - - wsptr = workspace; - for (ctr = 0; ctr < 8; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp2 = (INT32) wsptr[2]; - - tmp10 = (tmp0 + tmp2) << CONST_BITS; - tmp12 = (tmp0 - tmp2) << CONST_BITS; - - /* Odd part */ - /* Same rotation as in the even part of the 8x8 LL&M IDCT */ - - z2 = (INT32) wsptr[1]; - z3 = (INT32) wsptr[3]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 4; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 3x6 output block. - * - * 6-point IDCT in pass 1 (columns), 3-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_3x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[3*6]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; - /* Add fudge factor here for final descale. */ - tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ - tmp1 = tmp0 + tmp10; - tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS); - tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ - tmp10 = tmp1 + tmp0; - tmp12 = tmp1 - tmp0; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ - tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); - tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); - tmp1 = (z1 - z2 - z3) << PASS1_BITS; - - /* Final output stage */ - - wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[3*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); - wsptr[3*1] = (int) (tmp11 + tmp1); - wsptr[3*4] = (int) (tmp11 - tmp1); - wsptr[3*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[3*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); - } - - /* Pass 2: process 6 rows from work array, store into output array. - * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6). - */ - - wsptr = workspace; - for (ctr = 0; ctr < 6; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 = (INT32) wsptr[0] + - ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) + - (ONE << (PASS1_BITS+2))); - tmp0 <<= CONST_BITS; - tmp2 = (INT32) wsptr[2]; - tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ - tmp10 = tmp0 + tmp12; - tmp2 = tmp0 - tmp12 - tmp12; - - /* Odd part */ - - tmp12 = (INT32) wsptr[1]; - tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += 3; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 2x4 output block. - * - * 4-point IDCT in pass 1 (columns), 2-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_2x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp2, tmp10, tmp12; - INT32 z1, z2, z3; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - INT32 * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - INT32 workspace[2*4]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. - * 4-point IDCT kernel, - * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. - */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = 0; ctr < 2; ctr++, inptr++, quantptr++, wsptr++) { - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - - tmp10 = (tmp0 + tmp2) << CONST_BITS; - tmp12 = (tmp0 - tmp2) << CONST_BITS; - - /* Odd part */ - /* Same rotation as in the even part of the 8x8 LL&M IDCT */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ - tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ - tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ - - /* Final output stage */ - - wsptr[2*0] = tmp10 + tmp0; - wsptr[2*3] = tmp10 - tmp0; - wsptr[2*1] = tmp12 + tmp2; - wsptr[2*2] = tmp12 - tmp2; - } - - /* Pass 2: process 4 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 4; ctr++) { - outptr = output_buf[ctr] + output_col; - - /* Even part */ - - /* Add range center and fudge factor for final descale and range-limit. */ - tmp10 = wsptr[0] + - ((((INT32) RANGE_CENTER) << (CONST_BITS+3)) + - (ONE << (CONST_BITS+2))); - - /* Odd part */ - - tmp0 = wsptr[1]; - - /* Final output stage */ - - outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS+3) - & RANGE_MASK]; - - wsptr += 2; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a 1x2 output block. - * - * 2-point IDCT in pass 1 (columns), 1-point in pass 2 (rows). - */ - -GLOBAL(void) -jpeg_idct_1x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - DCTELEM tmp0, tmp1; - ISLOW_MULT_TYPE * quantptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - ISHIFT_TEMPS - - /* Process 1 column from input, store into output array. */ - - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - - /* Even part */ - - tmp0 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]); - /* Add range center and fudge factor for final descale and range-limit. */ - tmp0 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2); - - /* Odd part */ - - tmp1 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]); - - /* Final output stage */ - - output_buf[0][output_col] = - range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK]; - output_buf[1][output_col] = - range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK]; -} - -#endif /* IDCT_SCALING_SUPPORTED */ -#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/libraries/jpeg/jinclude.h b/libraries/jpeg/jinclude.h deleted file mode 100644 index 20ed4ef11f8..00000000000 --- a/libraries/jpeg/jinclude.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * jinclude.h - * - * Copyright (C) 1991-1994, Thomas G. Lane. - * Modified 2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file exists to provide a single place to fix any problems with - * including the wrong system include files. (Common problems are taken - * care of by the standard jconfig symbols, but on really weird systems - * you may have to edit this file.) - * - * NOTE: this file is NOT intended to be included by applications using the - * JPEG library. Most applications need only include jpeglib.h. - */ - - -/* Include auto-config file to find out which system include files we need. */ - -#include "jconfig.h" /* auto configuration options */ -#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ - -/* - * We need the NULL macro and size_t typedef. - * On an ANSI-conforming system it is sufficient to include . - * Otherwise, we get them from or ; we may have to - * pull in as well. - * Note that the core JPEG library does not require ; - * only the default error handler and data source/destination modules do. - * But we must pull it in because of the references to FILE in jpeglib.h. - * You can remove those references if you want to compile without . - */ - -#ifdef HAVE_STDDEF_H -#include -#endif - -#ifdef HAVE_STDLIB_H -#include -#endif - -#ifdef NEED_SYS_TYPES_H -#include -#endif - -#include - -/* - * We need memory copying and zeroing functions, plus strncpy(). - * ANSI and System V implementations declare these in . - * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). - * Some systems may declare memset and memcpy in . - * - * NOTE: we assume the size parameters to these functions are of type size_t. - * Change the casts in these macros if not! - */ - -#ifdef NEED_BSD_STRINGS - -#include -#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) -#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) - -#else /* not BSD, assume ANSI/SysV string lib */ - -#include -#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) -#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) - -#endif - -/* - * In ANSI C, and indeed any rational implementation, size_t is also the - * type returned by sizeof(). However, it seems there are some irrational - * implementations out there, in which sizeof() returns an int even though - * size_t is defined as long or unsigned long. To ensure consistent results - * we always use this SIZEOF() macro in place of using sizeof() directly. - */ - -#define SIZEOF(object) ((size_t) sizeof(object)) - -/* - * The modules that use fread() and fwrite() always invoke them through - * these macros. On some systems you may need to twiddle the argument casts. - * CAUTION: argument order is different from underlying functions! - * - * Furthermore, macros are provided for fflush() and ferror() in order - * to facilitate adaption by applications using an own FILE class. - */ - -#define JFREAD(file,buf,sizeofbuf) \ - ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) -#define JFWRITE(file,buf,sizeofbuf) \ - ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) -#define JFFLUSH(file) fflush(file) -#define JFERROR(file) ferror(file) diff --git a/libraries/jpeg/jmemansi.c b/libraries/jpeg/jmemansi.c deleted file mode 100644 index 2d93e496251..00000000000 --- a/libraries/jpeg/jmemansi.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * jmemansi.c - * - * Copyright (C) 1992-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file provides a simple generic implementation of the system- - * dependent portion of the JPEG memory manager. This implementation - * assumes that you have the ANSI-standard library routine tmpfile(). - * Also, the problem of determining the amount of memory available - * is shoved onto the user. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jmemsys.h" /* import the system-dependent declarations */ - -#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ -extern void * malloc JPP((size_t size)); -extern void free JPP((void *ptr)); -#endif - -#ifndef SEEK_SET /* pre-ANSI systems may not define this; */ -#define SEEK_SET 0 /* if not, assume 0 is correct */ -#endif - - -/* - * Memory allocation and freeing are controlled by the regular library - * routines malloc() and free(). - */ - -GLOBAL(void *) -jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) -{ - return (void *) malloc(sizeofobject); -} - -GLOBAL(void) -jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) -{ - free(object); -} - - -/* - * "Large" objects are treated the same as "small" ones. - * NB: although we include FAR keywords in the routine declarations, - * this file won't actually work in 80x86 small/medium model; at least, - * you probably won't be able to process useful-size images in only 64KB. - */ - -GLOBAL(void FAR *) -jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) -{ - return (void FAR *) malloc(sizeofobject); -} - -GLOBAL(void) -jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) -{ - free(object); -} - - -/* - * This routine computes the total memory space available for allocation. - * It's impossible to do this in a portable way; our current solution is - * to make the user tell us (with a default value set at compile time). - * If you can actually get the available space, it's a good idea to subtract - * a slop factor of 5% or so. - */ - -#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ -#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */ -#endif - -GLOBAL(long) -jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, - long max_bytes_needed, long already_allocated) -{ - return cinfo->mem->max_memory_to_use - already_allocated; -} - - -/* - * Backing store (temporary file) management. - * Backing store objects are only used when the value returned by - * jpeg_mem_available is less than the total space needed. You can dispense - * with these routines if you have plenty of virtual memory; see jmemnobs.c. - */ - - -METHODDEF(void) -read_backing_store (j_common_ptr cinfo, backing_store_ptr info, - void FAR * buffer_address, - long file_offset, long byte_count) -{ - if (fseek(info->temp_file, file_offset, SEEK_SET)) - ERREXIT(cinfo, JERR_TFILE_SEEK); - if (JFREAD(info->temp_file, buffer_address, byte_count) - != (size_t) byte_count) - ERREXIT(cinfo, JERR_TFILE_READ); -} - - -METHODDEF(void) -write_backing_store (j_common_ptr cinfo, backing_store_ptr info, - void FAR * buffer_address, - long file_offset, long byte_count) -{ - if (fseek(info->temp_file, file_offset, SEEK_SET)) - ERREXIT(cinfo, JERR_TFILE_SEEK); - if (JFWRITE(info->temp_file, buffer_address, byte_count) - != (size_t) byte_count) - ERREXIT(cinfo, JERR_TFILE_WRITE); -} - - -METHODDEF(void) -close_backing_store (j_common_ptr cinfo, backing_store_ptr info) -{ - fclose(info->temp_file); - /* Since this implementation uses tmpfile() to create the file, - * no explicit file deletion is needed. - */ -} - - -/* - * Initial opening of a backing-store object. - * - * This version uses tmpfile(), which constructs a suitable file name - * behind the scenes. We don't have to use info->temp_name[] at all; - * indeed, we can't even find out the actual name of the temp file. - */ - -GLOBAL(void) -jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, - long total_bytes_needed) -{ - if ((info->temp_file = tmpfile()) == NULL) - ERREXITS(cinfo, JERR_TFILE_CREATE, ""); - info->read_backing_store = read_backing_store; - info->write_backing_store = write_backing_store; - info->close_backing_store = close_backing_store; -} - - -/* - * These routines take care of any system-dependent initialization and - * cleanup required. - */ - -GLOBAL(long) -jpeg_mem_init (j_common_ptr cinfo) -{ - return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ -} - -GLOBAL(void) -jpeg_mem_term (j_common_ptr cinfo) -{ - /* no work */ -} diff --git a/libraries/jpeg/jmemmgr.c b/libraries/jpeg/jmemmgr.c deleted file mode 100644 index 0a137cdde43..00000000000 --- a/libraries/jpeg/jmemmgr.c +++ /dev/null @@ -1,1119 +0,0 @@ -/* - * jmemmgr.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 2011-2012 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the JPEG system-independent memory management - * routines. This code is usable across a wide variety of machines; most - * of the system dependencies have been isolated in a separate file. - * The major functions provided here are: - * * pool-based allocation and freeing of memory; - * * policy decisions about how to divide available memory among the - * virtual arrays; - * * control logic for swapping virtual arrays between main memory and - * backing storage. - * The separate system-dependent file provides the actual backing-storage - * access code, and it contains the policy decision about how much total - * main memory to use. - * This file is system-dependent in the sense that some of its functions - * are unnecessary in some systems. For example, if there is enough virtual - * memory so that backing storage will never be used, much of the virtual - * array control logic could be removed. (Of course, if you have that much - * memory then you shouldn't care about a little bit of unused code...) - */ - -#define JPEG_INTERNALS -#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ -#include "jinclude.h" -#include "jpeglib.h" -#include "jmemsys.h" /* import the system-dependent declarations */ - -#ifndef NO_GETENV -#ifndef HAVE_STDLIB_H /* should declare getenv() */ -extern char * getenv JPP((const char * name)); -#endif -#endif - - -/* - * Some important notes: - * The allocation routines provided here must never return NULL. - * They should exit to error_exit if unsuccessful. - * - * It's not a good idea to try to merge the sarray and barray routines, - * even though they are textually almost the same, because samples are - * usually stored as bytes while coefficients are shorts or ints. Thus, - * in machines where byte pointers have a different representation from - * word pointers, the resulting machine code could not be the same. - */ - - -/* - * Many machines require storage alignment: longs must start on 4-byte - * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() - * always returns pointers that are multiples of the worst-case alignment - * requirement, and we had better do so too. - * There isn't any really portable way to determine the worst-case alignment - * requirement. This module assumes that the alignment requirement is - * multiples of sizeof(ALIGN_TYPE). - * By default, we define ALIGN_TYPE as double. This is necessary on some - * workstations (where doubles really do need 8-byte alignment) and will work - * fine on nearly everything. If your machine has lesser alignment needs, - * you can save a few bytes by making ALIGN_TYPE smaller. - * The only place I know of where this will NOT work is certain Macintosh - * 680x0 compilers that define double as a 10-byte IEEE extended float. - * Doing 10-byte alignment is counterproductive because longwords won't be - * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have - * such a compiler. - */ - -#ifndef ALIGN_TYPE /* so can override from jconfig.h */ -#define ALIGN_TYPE double -#endif - - -/* - * We allocate objects from "pools", where each pool is gotten with a single - * request to jpeg_get_small() or jpeg_get_large(). There is no per-object - * overhead within a pool, except for alignment padding. Each pool has a - * header with a link to the next pool of the same class. - * Small and large pool headers are identical except that the latter's - * link pointer must be FAR on 80x86 machines. - * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE - * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple - * of the alignment requirement of ALIGN_TYPE. - */ - -typedef union small_pool_struct * small_pool_ptr; - -typedef union small_pool_struct { - struct { - small_pool_ptr next; /* next in list of pools */ - size_t bytes_used; /* how many bytes already used within pool */ - size_t bytes_left; /* bytes still available in this pool */ - } hdr; - ALIGN_TYPE dummy; /* included in union to ensure alignment */ -} small_pool_hdr; - -typedef union large_pool_struct FAR * large_pool_ptr; - -typedef union large_pool_struct { - struct { - large_pool_ptr next; /* next in list of pools */ - size_t bytes_used; /* how many bytes already used within pool */ - size_t bytes_left; /* bytes still available in this pool */ - } hdr; - ALIGN_TYPE dummy; /* included in union to ensure alignment */ -} large_pool_hdr; - - -/* - * Here is the full definition of a memory manager object. - */ - -typedef struct { - struct jpeg_memory_mgr pub; /* public fields */ - - /* Each pool identifier (lifetime class) names a linked list of pools. */ - small_pool_ptr small_list[JPOOL_NUMPOOLS]; - large_pool_ptr large_list[JPOOL_NUMPOOLS]; - - /* Since we only have one lifetime class of virtual arrays, only one - * linked list is necessary (for each datatype). Note that the virtual - * array control blocks being linked together are actually stored somewhere - * in the small-pool list. - */ - jvirt_sarray_ptr virt_sarray_list; - jvirt_barray_ptr virt_barray_list; - - /* This counts total space obtained from jpeg_get_small/large */ - long total_space_allocated; - - /* alloc_sarray and alloc_barray set this value for use by virtual - * array routines. - */ - JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ -} my_memory_mgr; - -typedef my_memory_mgr * my_mem_ptr; - - -/* - * The control blocks for virtual arrays. - * Note that these blocks are allocated in the "small" pool area. - * System-dependent info for the associated backing store (if any) is hidden - * inside the backing_store_info struct. - */ - -struct jvirt_sarray_control { - JSAMPARRAY mem_buffer; /* => the in-memory buffer */ - JDIMENSION rows_in_array; /* total virtual array height */ - JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ - JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ - JDIMENSION rows_in_mem; /* height of memory buffer */ - JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ - JDIMENSION cur_start_row; /* first logical row # in the buffer */ - JDIMENSION first_undef_row; /* row # of first uninitialized row */ - boolean pre_zero; /* pre-zero mode requested? */ - boolean dirty; /* do current buffer contents need written? */ - boolean b_s_open; /* is backing-store data valid? */ - jvirt_sarray_ptr next; /* link to next virtual sarray control block */ - backing_store_info b_s_info; /* System-dependent control info */ -}; - -struct jvirt_barray_control { - JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ - JDIMENSION rows_in_array; /* total virtual array height */ - JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ - JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ - JDIMENSION rows_in_mem; /* height of memory buffer */ - JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ - JDIMENSION cur_start_row; /* first logical row # in the buffer */ - JDIMENSION first_undef_row; /* row # of first uninitialized row */ - boolean pre_zero; /* pre-zero mode requested? */ - boolean dirty; /* do current buffer contents need written? */ - boolean b_s_open; /* is backing-store data valid? */ - jvirt_barray_ptr next; /* link to next virtual barray control block */ - backing_store_info b_s_info; /* System-dependent control info */ -}; - - -#ifdef MEM_STATS /* optional extra stuff for statistics */ - -LOCAL(void) -print_mem_stats (j_common_ptr cinfo, int pool_id) -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - small_pool_ptr shdr_ptr; - large_pool_ptr lhdr_ptr; - - /* Since this is only a debugging stub, we can cheat a little by using - * fprintf directly rather than going through the trace message code. - * This is helpful because message parm array can't handle longs. - */ - fprintf(stderr, "Freeing pool %d, total space = %ld\n", - pool_id, mem->total_space_allocated); - - for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; - lhdr_ptr = lhdr_ptr->hdr.next) { - fprintf(stderr, " Large chunk used %ld\n", - (long) lhdr_ptr->hdr.bytes_used); - } - - for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; - shdr_ptr = shdr_ptr->hdr.next) { - fprintf(stderr, " Small chunk used %ld free %ld\n", - (long) shdr_ptr->hdr.bytes_used, - (long) shdr_ptr->hdr.bytes_left); - } -} - -#endif /* MEM_STATS */ - - -LOCAL(noreturn_t) -out_of_memory (j_common_ptr cinfo, int which) -/* Report an out-of-memory error and stop execution */ -/* If we compiled MEM_STATS support, report alloc requests before dying */ -{ -#ifdef MEM_STATS - cinfo->err->trace_level = 2; /* force self_destruct to report stats */ -#endif - ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); -} - - -/* - * Allocation of "small" objects. - * - * For these, we use pooled storage. When a new pool must be created, - * we try to get enough space for the current request plus a "slop" factor, - * where the slop will be the amount of leftover space in the new pool. - * The speed vs. space tradeoff is largely determined by the slop values. - * A different slop value is provided for each pool class (lifetime), - * and we also distinguish the first pool of a class from later ones. - * NOTE: the values given work fairly well on both 16- and 32-bit-int - * machines, but may be too small if longs are 64 bits or more. - */ - -static const size_t first_pool_slop[JPOOL_NUMPOOLS] = -{ - 1600, /* first PERMANENT pool */ - 16000 /* first IMAGE pool */ -}; - -static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = -{ - 0, /* additional PERMANENT pools */ - 5000 /* additional IMAGE pools */ -}; - -#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ - - -METHODDEF(void *) -alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) -/* Allocate a "small" object */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - small_pool_ptr hdr_ptr, prev_hdr_ptr; - char * data_ptr; - size_t odd_bytes, min_request, slop; - - /* Check for unsatisfiable request (do now to ensure no overflow below) */ - if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) - out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ - - /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ - odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); - if (odd_bytes > 0) - sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; - - /* See if space is available in any existing pool */ - if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - prev_hdr_ptr = NULL; - hdr_ptr = mem->small_list[pool_id]; - while (hdr_ptr != NULL) { - if (hdr_ptr->hdr.bytes_left >= sizeofobject) - break; /* found pool with enough space */ - prev_hdr_ptr = hdr_ptr; - hdr_ptr = hdr_ptr->hdr.next; - } - - /* Time to make a new pool? */ - if (hdr_ptr == NULL) { - /* min_request is what we need now, slop is what will be leftover */ - min_request = sizeofobject + SIZEOF(small_pool_hdr); - if (prev_hdr_ptr == NULL) /* first pool in class? */ - slop = first_pool_slop[pool_id]; - else - slop = extra_pool_slop[pool_id]; - /* Don't ask for more than MAX_ALLOC_CHUNK */ - if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) - slop = (size_t) (MAX_ALLOC_CHUNK-min_request); - /* Try to get space, if fail reduce slop and try again */ - for (;;) { - hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); - if (hdr_ptr != NULL) - break; - slop /= 2; - if (slop < MIN_SLOP) /* give up when it gets real small */ - out_of_memory(cinfo, 2); /* jpeg_get_small failed */ - } - mem->total_space_allocated += min_request + slop; - /* Success, initialize the new pool header and add to end of list */ - hdr_ptr->hdr.next = NULL; - hdr_ptr->hdr.bytes_used = 0; - hdr_ptr->hdr.bytes_left = sizeofobject + slop; - if (prev_hdr_ptr == NULL) /* first pool in class? */ - mem->small_list[pool_id] = hdr_ptr; - else - prev_hdr_ptr->hdr.next = hdr_ptr; - } - - /* OK, allocate the object from the current pool */ - data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ - data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ - hdr_ptr->hdr.bytes_used += sizeofobject; - hdr_ptr->hdr.bytes_left -= sizeofobject; - - return (void *) data_ptr; -} - - -/* - * Allocation of "large" objects. - * - * The external semantics of these are the same as "small" objects, - * except that FAR pointers are used on 80x86. However the pool - * management heuristics are quite different. We assume that each - * request is large enough that it may as well be passed directly to - * jpeg_get_large; the pool management just links everything together - * so that we can free it all on demand. - * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY - * structures. The routines that create these structures (see below) - * deliberately bunch rows together to ensure a large request size. - */ - -METHODDEF(void FAR *) -alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) -/* Allocate a "large" object */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - large_pool_ptr hdr_ptr; - size_t odd_bytes; - - /* Check for unsatisfiable request (do now to ensure no overflow below) */ - if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) - out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ - - /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ - odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); - if (odd_bytes > 0) - sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; - - /* Always make a new pool */ - if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - - hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + - SIZEOF(large_pool_hdr)); - if (hdr_ptr == NULL) - out_of_memory(cinfo, 4); /* jpeg_get_large failed */ - mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); - - /* Success, initialize the new pool header and add to list */ - hdr_ptr->hdr.next = mem->large_list[pool_id]; - /* We maintain space counts in each pool header for statistical purposes, - * even though they are not needed for allocation. - */ - hdr_ptr->hdr.bytes_used = sizeofobject; - hdr_ptr->hdr.bytes_left = 0; - mem->large_list[pool_id] = hdr_ptr; - - return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ -} - - -/* - * Creation of 2-D sample arrays. - * The pointers are in near heap, the samples themselves in FAR heap. - * - * To minimize allocation overhead and to allow I/O of large contiguous - * blocks, we allocate the sample rows in groups of as many rows as possible - * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. - * NB: the virtual array control routines, later in this file, know about - * this chunking of rows. The rowsperchunk value is left in the mem manager - * object so that it can be saved away if this sarray is the workspace for - * a virtual array. - */ - -METHODDEF(JSAMPARRAY) -alloc_sarray (j_common_ptr cinfo, int pool_id, - JDIMENSION samplesperrow, JDIMENSION numrows) -/* Allocate a 2-D sample array */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - JSAMPARRAY result; - JSAMPROW workspace; - JDIMENSION rowsperchunk, currow, i; - long ltemp; - - /* Calculate max # of rows allowed in one allocation chunk */ - ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / - ((long) samplesperrow * SIZEOF(JSAMPLE)); - if (ltemp <= 0) - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - if (ltemp < (long) numrows) - rowsperchunk = (JDIMENSION) ltemp; - else - rowsperchunk = numrows; - mem->last_rowsperchunk = rowsperchunk; - - /* Get space for row pointers (small object) */ - result = (JSAMPARRAY) alloc_small(cinfo, pool_id, - (size_t) (numrows * SIZEOF(JSAMPROW))); - - /* Get the rows themselves (large objects) */ - currow = 0; - while (currow < numrows) { - rowsperchunk = MIN(rowsperchunk, numrows - currow); - workspace = (JSAMPROW) alloc_large(cinfo, pool_id, - (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow - * SIZEOF(JSAMPLE))); - for (i = rowsperchunk; i > 0; i--) { - result[currow++] = workspace; - workspace += samplesperrow; - } - } - - return result; -} - - -/* - * Creation of 2-D coefficient-block arrays. - * This is essentially the same as the code for sample arrays, above. - */ - -METHODDEF(JBLOCKARRAY) -alloc_barray (j_common_ptr cinfo, int pool_id, - JDIMENSION blocksperrow, JDIMENSION numrows) -/* Allocate a 2-D coefficient-block array */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - JBLOCKARRAY result; - JBLOCKROW workspace; - JDIMENSION rowsperchunk, currow, i; - long ltemp; - - /* Calculate max # of rows allowed in one allocation chunk */ - ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / - ((long) blocksperrow * SIZEOF(JBLOCK)); - if (ltemp <= 0) - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - if (ltemp < (long) numrows) - rowsperchunk = (JDIMENSION) ltemp; - else - rowsperchunk = numrows; - mem->last_rowsperchunk = rowsperchunk; - - /* Get space for row pointers (small object) */ - result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, - (size_t) (numrows * SIZEOF(JBLOCKROW))); - - /* Get the rows themselves (large objects) */ - currow = 0; - while (currow < numrows) { - rowsperchunk = MIN(rowsperchunk, numrows - currow); - workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, - (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow - * SIZEOF(JBLOCK))); - for (i = rowsperchunk; i > 0; i--) { - result[currow++] = workspace; - workspace += blocksperrow; - } - } - - return result; -} - - -/* - * About virtual array management: - * - * The above "normal" array routines are only used to allocate strip buffers - * (as wide as the image, but just a few rows high). Full-image-sized buffers - * are handled as "virtual" arrays. The array is still accessed a strip at a - * time, but the memory manager must save the whole array for repeated - * accesses. The intended implementation is that there is a strip buffer in - * memory (as high as is possible given the desired memory limit), plus a - * backing file that holds the rest of the array. - * - * The request_virt_array routines are told the total size of the image and - * the maximum number of rows that will be accessed at once. The in-memory - * buffer must be at least as large as the maxaccess value. - * - * The request routines create control blocks but not the in-memory buffers. - * That is postponed until realize_virt_arrays is called. At that time the - * total amount of space needed is known (approximately, anyway), so free - * memory can be divided up fairly. - * - * The access_virt_array routines are responsible for making a specific strip - * area accessible (after reading or writing the backing file, if necessary). - * Note that the access routines are told whether the caller intends to modify - * the accessed strip; during a read-only pass this saves having to rewrite - * data to disk. The access routines are also responsible for pre-zeroing - * any newly accessed rows, if pre-zeroing was requested. - * - * In current usage, the access requests are usually for nonoverlapping - * strips; that is, successive access start_row numbers differ by exactly - * num_rows = maxaccess. This means we can get good performance with simple - * buffer dump/reload logic, by making the in-memory buffer be a multiple - * of the access height; then there will never be accesses across bufferload - * boundaries. The code will still work with overlapping access requests, - * but it doesn't handle bufferload overlaps very efficiently. - */ - - -METHODDEF(jvirt_sarray_ptr) -request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, - JDIMENSION samplesperrow, JDIMENSION numrows, - JDIMENSION maxaccess) -/* Request a virtual 2-D sample array */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - jvirt_sarray_ptr result; - - /* Only IMAGE-lifetime virtual arrays are currently supported */ - if (pool_id != JPOOL_IMAGE) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - - /* get control block */ - result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, - SIZEOF(struct jvirt_sarray_control)); - - result->mem_buffer = NULL; /* marks array not yet realized */ - result->rows_in_array = numrows; - result->samplesperrow = samplesperrow; - result->maxaccess = maxaccess; - result->pre_zero = pre_zero; - result->b_s_open = FALSE; /* no associated backing-store object */ - result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ - mem->virt_sarray_list = result; - - return result; -} - - -METHODDEF(jvirt_barray_ptr) -request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, - JDIMENSION blocksperrow, JDIMENSION numrows, - JDIMENSION maxaccess) -/* Request a virtual 2-D coefficient-block array */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - jvirt_barray_ptr result; - - /* Only IMAGE-lifetime virtual arrays are currently supported */ - if (pool_id != JPOOL_IMAGE) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - - /* get control block */ - result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, - SIZEOF(struct jvirt_barray_control)); - - result->mem_buffer = NULL; /* marks array not yet realized */ - result->rows_in_array = numrows; - result->blocksperrow = blocksperrow; - result->maxaccess = maxaccess; - result->pre_zero = pre_zero; - result->b_s_open = FALSE; /* no associated backing-store object */ - result->next = mem->virt_barray_list; /* add to list of virtual arrays */ - mem->virt_barray_list = result; - - return result; -} - - -METHODDEF(void) -realize_virt_arrays (j_common_ptr cinfo) -/* Allocate the in-memory buffers for any unrealized virtual arrays */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - long space_per_minheight, maximum_space, avail_mem; - long minheights, max_minheights; - jvirt_sarray_ptr sptr; - jvirt_barray_ptr bptr; - - /* Compute the minimum space needed (maxaccess rows in each buffer) - * and the maximum space needed (full image height in each buffer). - * These may be of use to the system-dependent jpeg_mem_available routine. - */ - space_per_minheight = 0; - maximum_space = 0; - for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { - if (sptr->mem_buffer == NULL) { /* if not realized yet */ - space_per_minheight += (long) sptr->maxaccess * - (long) sptr->samplesperrow * SIZEOF(JSAMPLE); - maximum_space += (long) sptr->rows_in_array * - (long) sptr->samplesperrow * SIZEOF(JSAMPLE); - } - } - for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { - if (bptr->mem_buffer == NULL) { /* if not realized yet */ - space_per_minheight += (long) bptr->maxaccess * - (long) bptr->blocksperrow * SIZEOF(JBLOCK); - maximum_space += (long) bptr->rows_in_array * - (long) bptr->blocksperrow * SIZEOF(JBLOCK); - } - } - - if (space_per_minheight <= 0) - return; /* no unrealized arrays, no work */ - - /* Determine amount of memory to actually use; this is system-dependent. */ - avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, - mem->total_space_allocated); - - /* If the maximum space needed is available, make all the buffers full - * height; otherwise parcel it out with the same number of minheights - * in each buffer. - */ - if (avail_mem >= maximum_space) - max_minheights = 1000000000L; - else { - max_minheights = avail_mem / space_per_minheight; - /* If there doesn't seem to be enough space, try to get the minimum - * anyway. This allows a "stub" implementation of jpeg_mem_available(). - */ - if (max_minheights <= 0) - max_minheights = 1; - } - - /* Allocate the in-memory buffers and initialize backing store as needed. */ - - for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { - if (sptr->mem_buffer == NULL) { /* if not realized yet */ - minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; - if (minheights <= max_minheights) { - /* This buffer fits in memory */ - sptr->rows_in_mem = sptr->rows_in_array; - } else { - /* It doesn't fit in memory, create backing store. */ - sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); - jpeg_open_backing_store(cinfo, & sptr->b_s_info, - (long) sptr->rows_in_array * - (long) sptr->samplesperrow * - (long) SIZEOF(JSAMPLE)); - sptr->b_s_open = TRUE; - } - sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, - sptr->samplesperrow, sptr->rows_in_mem); - sptr->rowsperchunk = mem->last_rowsperchunk; - sptr->cur_start_row = 0; - sptr->first_undef_row = 0; - sptr->dirty = FALSE; - } - } - - for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { - if (bptr->mem_buffer == NULL) { /* if not realized yet */ - minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; - if (minheights <= max_minheights) { - /* This buffer fits in memory */ - bptr->rows_in_mem = bptr->rows_in_array; - } else { - /* It doesn't fit in memory, create backing store. */ - bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); - jpeg_open_backing_store(cinfo, & bptr->b_s_info, - (long) bptr->rows_in_array * - (long) bptr->blocksperrow * - (long) SIZEOF(JBLOCK)); - bptr->b_s_open = TRUE; - } - bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, - bptr->blocksperrow, bptr->rows_in_mem); - bptr->rowsperchunk = mem->last_rowsperchunk; - bptr->cur_start_row = 0; - bptr->first_undef_row = 0; - bptr->dirty = FALSE; - } - } -} - - -LOCAL(void) -do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) -/* Do backing store read or write of a virtual sample array */ -{ - long bytesperrow, file_offset, byte_count, rows, thisrow, i; - - bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); - file_offset = ptr->cur_start_row * bytesperrow; - /* Loop to read or write each allocation chunk in mem_buffer */ - for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { - /* One chunk, but check for short chunk at end of buffer */ - rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); - /* Transfer no more than is currently defined */ - thisrow = (long) ptr->cur_start_row + i; - rows = MIN(rows, (long) ptr->first_undef_row - thisrow); - /* Transfer no more than fits in file */ - rows = MIN(rows, (long) ptr->rows_in_array - thisrow); - if (rows <= 0) /* this chunk might be past end of file! */ - break; - byte_count = rows * bytesperrow; - if (writing) - (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, - (void FAR *) ptr->mem_buffer[i], - file_offset, byte_count); - else - (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, - (void FAR *) ptr->mem_buffer[i], - file_offset, byte_count); - file_offset += byte_count; - } -} - - -LOCAL(void) -do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) -/* Do backing store read or write of a virtual coefficient-block array */ -{ - long bytesperrow, file_offset, byte_count, rows, thisrow, i; - - bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); - file_offset = ptr->cur_start_row * bytesperrow; - /* Loop to read or write each allocation chunk in mem_buffer */ - for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { - /* One chunk, but check for short chunk at end of buffer */ - rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); - /* Transfer no more than is currently defined */ - thisrow = (long) ptr->cur_start_row + i; - rows = MIN(rows, (long) ptr->first_undef_row - thisrow); - /* Transfer no more than fits in file */ - rows = MIN(rows, (long) ptr->rows_in_array - thisrow); - if (rows <= 0) /* this chunk might be past end of file! */ - break; - byte_count = rows * bytesperrow; - if (writing) - (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, - (void FAR *) ptr->mem_buffer[i], - file_offset, byte_count); - else - (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, - (void FAR *) ptr->mem_buffer[i], - file_offset, byte_count); - file_offset += byte_count; - } -} - - -METHODDEF(JSAMPARRAY) -access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, - JDIMENSION start_row, JDIMENSION num_rows, - boolean writable) -/* Access the part of a virtual sample array starting at start_row */ -/* and extending for num_rows rows. writable is true if */ -/* caller intends to modify the accessed area. */ -{ - JDIMENSION end_row = start_row + num_rows; - JDIMENSION undef_row; - - /* debugging check */ - if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || - ptr->mem_buffer == NULL) - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - - /* Make the desired part of the virtual array accessible */ - if (start_row < ptr->cur_start_row || - end_row > ptr->cur_start_row+ptr->rows_in_mem) { - if (! ptr->b_s_open) - ERREXIT(cinfo, JERR_VIRTUAL_BUG); - /* Flush old buffer contents if necessary */ - if (ptr->dirty) { - do_sarray_io(cinfo, ptr, TRUE); - ptr->dirty = FALSE; - } - /* Decide what part of virtual array to access. - * Algorithm: if target address > current window, assume forward scan, - * load starting at target address. If target address < current window, - * assume backward scan, load so that target area is top of window. - * Note that when switching from forward write to forward read, will have - * start_row = 0, so the limiting case applies and we load from 0 anyway. - */ - if (start_row > ptr->cur_start_row) { - ptr->cur_start_row = start_row; - } else { - /* use long arithmetic here to avoid overflow & unsigned problems */ - long ltemp; - - ltemp = (long) end_row - (long) ptr->rows_in_mem; - if (ltemp < 0) - ltemp = 0; /* don't fall off front end of file */ - ptr->cur_start_row = (JDIMENSION) ltemp; - } - /* Read in the selected part of the array. - * During the initial write pass, we will do no actual read - * because the selected part is all undefined. - */ - do_sarray_io(cinfo, ptr, FALSE); - } - /* Ensure the accessed part of the array is defined; prezero if needed. - * To improve locality of access, we only prezero the part of the array - * that the caller is about to access, not the entire in-memory array. - */ - if (ptr->first_undef_row < end_row) { - if (ptr->first_undef_row < start_row) { - if (writable) /* writer skipped over a section of array */ - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - undef_row = start_row; /* but reader is allowed to read ahead */ - } else { - undef_row = ptr->first_undef_row; - } - if (writable) - ptr->first_undef_row = end_row; - if (ptr->pre_zero) { - size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); - undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ - end_row -= ptr->cur_start_row; - while (undef_row < end_row) { - FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); - undef_row++; - } - } else { - if (! writable) /* reader looking at undefined data */ - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - } - } - /* Flag the buffer dirty if caller will write in it */ - if (writable) - ptr->dirty = TRUE; - /* Return address of proper part of the buffer */ - return ptr->mem_buffer + (start_row - ptr->cur_start_row); -} - - -METHODDEF(JBLOCKARRAY) -access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, - JDIMENSION start_row, JDIMENSION num_rows, - boolean writable) -/* Access the part of a virtual block array starting at start_row */ -/* and extending for num_rows rows. writable is true if */ -/* caller intends to modify the accessed area. */ -{ - JDIMENSION end_row = start_row + num_rows; - JDIMENSION undef_row; - - /* debugging check */ - if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || - ptr->mem_buffer == NULL) - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - - /* Make the desired part of the virtual array accessible */ - if (start_row < ptr->cur_start_row || - end_row > ptr->cur_start_row+ptr->rows_in_mem) { - if (! ptr->b_s_open) - ERREXIT(cinfo, JERR_VIRTUAL_BUG); - /* Flush old buffer contents if necessary */ - if (ptr->dirty) { - do_barray_io(cinfo, ptr, TRUE); - ptr->dirty = FALSE; - } - /* Decide what part of virtual array to access. - * Algorithm: if target address > current window, assume forward scan, - * load starting at target address. If target address < current window, - * assume backward scan, load so that target area is top of window. - * Note that when switching from forward write to forward read, will have - * start_row = 0, so the limiting case applies and we load from 0 anyway. - */ - if (start_row > ptr->cur_start_row) { - ptr->cur_start_row = start_row; - } else { - /* use long arithmetic here to avoid overflow & unsigned problems */ - long ltemp; - - ltemp = (long) end_row - (long) ptr->rows_in_mem; - if (ltemp < 0) - ltemp = 0; /* don't fall off front end of file */ - ptr->cur_start_row = (JDIMENSION) ltemp; - } - /* Read in the selected part of the array. - * During the initial write pass, we will do no actual read - * because the selected part is all undefined. - */ - do_barray_io(cinfo, ptr, FALSE); - } - /* Ensure the accessed part of the array is defined; prezero if needed. - * To improve locality of access, we only prezero the part of the array - * that the caller is about to access, not the entire in-memory array. - */ - if (ptr->first_undef_row < end_row) { - if (ptr->first_undef_row < start_row) { - if (writable) /* writer skipped over a section of array */ - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - undef_row = start_row; /* but reader is allowed to read ahead */ - } else { - undef_row = ptr->first_undef_row; - } - if (writable) - ptr->first_undef_row = end_row; - if (ptr->pre_zero) { - size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); - undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ - end_row -= ptr->cur_start_row; - while (undef_row < end_row) { - FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); - undef_row++; - } - } else { - if (! writable) /* reader looking at undefined data */ - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - } - } - /* Flag the buffer dirty if caller will write in it */ - if (writable) - ptr->dirty = TRUE; - /* Return address of proper part of the buffer */ - return ptr->mem_buffer + (start_row - ptr->cur_start_row); -} - - -/* - * Release all objects belonging to a specified pool. - */ - -METHODDEF(void) -free_pool (j_common_ptr cinfo, int pool_id) -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - small_pool_ptr shdr_ptr; - large_pool_ptr lhdr_ptr; - size_t space_freed; - - if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - -#ifdef MEM_STATS - if (cinfo->err->trace_level > 1) - print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ -#endif - - /* If freeing IMAGE pool, close any virtual arrays first */ - if (pool_id == JPOOL_IMAGE) { - jvirt_sarray_ptr sptr; - jvirt_barray_ptr bptr; - - for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { - if (sptr->b_s_open) { /* there may be no backing store */ - sptr->b_s_open = FALSE; /* prevent recursive close if error */ - (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); - } - } - mem->virt_sarray_list = NULL; - for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { - if (bptr->b_s_open) { /* there may be no backing store */ - bptr->b_s_open = FALSE; /* prevent recursive close if error */ - (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); - } - } - mem->virt_barray_list = NULL; - } - - /* Release large objects */ - lhdr_ptr = mem->large_list[pool_id]; - mem->large_list[pool_id] = NULL; - - while (lhdr_ptr != NULL) { - large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; - space_freed = lhdr_ptr->hdr.bytes_used + - lhdr_ptr->hdr.bytes_left + - SIZEOF(large_pool_hdr); - jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); - mem->total_space_allocated -= space_freed; - lhdr_ptr = next_lhdr_ptr; - } - - /* Release small objects */ - shdr_ptr = mem->small_list[pool_id]; - mem->small_list[pool_id] = NULL; - - while (shdr_ptr != NULL) { - small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; - space_freed = shdr_ptr->hdr.bytes_used + - shdr_ptr->hdr.bytes_left + - SIZEOF(small_pool_hdr); - jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); - mem->total_space_allocated -= space_freed; - shdr_ptr = next_shdr_ptr; - } -} - - -/* - * Close up shop entirely. - * Note that this cannot be called unless cinfo->mem is non-NULL. - */ - -METHODDEF(void) -self_destruct (j_common_ptr cinfo) -{ - int pool; - - /* Close all backing store, release all memory. - * Releasing pools in reverse order might help avoid fragmentation - * with some (brain-damaged) malloc libraries. - */ - for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { - free_pool(cinfo, pool); - } - - /* Release the memory manager control block too. */ - jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); - cinfo->mem = NULL; /* ensures I will be called only once */ - - jpeg_mem_term(cinfo); /* system-dependent cleanup */ -} - - -/* - * Memory manager initialization. - * When this is called, only the error manager pointer is valid in cinfo! - */ - -GLOBAL(void) -jinit_memory_mgr (j_common_ptr cinfo) -{ - my_mem_ptr mem; - long max_to_use; - int pool; - size_t test_mac; - - cinfo->mem = NULL; /* for safety if init fails */ - - /* Check for configuration errors. - * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably - * doesn't reflect any real hardware alignment requirement. - * The test is a little tricky: for X>0, X and X-1 have no one-bits - * in common if and only if X is a power of 2, ie has only one one-bit. - * Some compilers may give an "unreachable code" warning here; ignore it. - */ - if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) - ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); - /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be - * a multiple of SIZEOF(ALIGN_TYPE). - * Again, an "unreachable code" warning may be ignored here. - * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. - */ - test_mac = (size_t) MAX_ALLOC_CHUNK; - if ((long) test_mac != MAX_ALLOC_CHUNK || - (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) - ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); - - max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ - - /* Attempt to allocate memory manager's control block */ - mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); - - if (mem == NULL) { - jpeg_mem_term(cinfo); /* system-dependent cleanup */ - ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); - } - - /* OK, fill in the method pointers */ - mem->pub.alloc_small = alloc_small; - mem->pub.alloc_large = alloc_large; - mem->pub.alloc_sarray = alloc_sarray; - mem->pub.alloc_barray = alloc_barray; - mem->pub.request_virt_sarray = request_virt_sarray; - mem->pub.request_virt_barray = request_virt_barray; - mem->pub.realize_virt_arrays = realize_virt_arrays; - mem->pub.access_virt_sarray = access_virt_sarray; - mem->pub.access_virt_barray = access_virt_barray; - mem->pub.free_pool = free_pool; - mem->pub.self_destruct = self_destruct; - - /* Make MAX_ALLOC_CHUNK accessible to other modules */ - mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK; - - /* Initialize working state */ - mem->pub.max_memory_to_use = max_to_use; - - for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { - mem->small_list[pool] = NULL; - mem->large_list[pool] = NULL; - } - mem->virt_sarray_list = NULL; - mem->virt_barray_list = NULL; - - mem->total_space_allocated = SIZEOF(my_memory_mgr); - - /* Declare ourselves open for business */ - cinfo->mem = & mem->pub; - - /* Check for an environment variable JPEGMEM; if found, override the - * default max_memory setting from jpeg_mem_init. Note that the - * surrounding application may again override this value. - * If your system doesn't support getenv(), define NO_GETENV to disable - * this feature. - */ -#ifndef NO_GETENV - { char * memenv; - - if ((memenv = getenv("JPEGMEM")) != NULL) { - char ch = 'x'; - - if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { - if (ch == 'm' || ch == 'M') - max_to_use *= 1000L; - mem->pub.max_memory_to_use = max_to_use * 1000L; - } - } - } -#endif - -} diff --git a/libraries/jpeg/jmemsys.h b/libraries/jpeg/jmemsys.h deleted file mode 100644 index 6c3c6d348f2..00000000000 --- a/libraries/jpeg/jmemsys.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * jmemsys.h - * - * Copyright (C) 1992-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This include file defines the interface between the system-independent - * and system-dependent portions of the JPEG memory manager. No other - * modules need include it. (The system-independent portion is jmemmgr.c; - * there are several different versions of the system-dependent portion.) - * - * This file works as-is for the system-dependent memory managers supplied - * in the IJG distribution. You may need to modify it if you write a - * custom memory manager. If system-dependent changes are needed in - * this file, the best method is to #ifdef them based on a configuration - * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR - * and USE_MAC_MEMMGR. - */ - - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_get_small jGetSmall -#define jpeg_free_small jFreeSmall -#define jpeg_get_large jGetLarge -#define jpeg_free_large jFreeLarge -#define jpeg_mem_available jMemAvail -#define jpeg_open_backing_store jOpenBackStore -#define jpeg_mem_init jMemInit -#define jpeg_mem_term jMemTerm -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* - * These two functions are used to allocate and release small chunks of - * memory. (Typically the total amount requested through jpeg_get_small is - * no more than 20K or so; this will be requested in chunks of a few K each.) - * Behavior should be the same as for the standard library functions malloc - * and free; in particular, jpeg_get_small must return NULL on failure. - * On most systems, these ARE malloc and free. jpeg_free_small is passed the - * size of the object being freed, just in case it's needed. - * On an 80x86 machine using small-data memory model, these manage near heap. - */ - -EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); -EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, - size_t sizeofobject)); - -/* - * These two functions are used to allocate and release large chunks of - * memory (up to the total free space designated by jpeg_mem_available). - * The interface is the same as above, except that on an 80x86 machine, - * far pointers are used. On most other machines these are identical to - * the jpeg_get/free_small routines; but we keep them separate anyway, - * in case a different allocation strategy is desirable for large chunks. - */ - -EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, - size_t sizeofobject)); -EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, - size_t sizeofobject)); - -/* - * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may - * be requested in a single call to jpeg_get_large (and jpeg_get_small for that - * matter, but that case should never come into play). This macro is needed - * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. - * On those machines, we expect that jconfig.h will provide a proper value. - * On machines with 32-bit flat address spaces, any large constant may be used. - * - * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type - * size_t and will be a multiple of sizeof(align_type). - */ - -#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ -#define MAX_ALLOC_CHUNK 1000000000L -#endif - -/* - * This routine computes the total space still available for allocation by - * jpeg_get_large. If more space than this is needed, backing store will be - * used. NOTE: any memory already allocated must not be counted. - * - * There is a minimum space requirement, corresponding to the minimum - * feasible buffer sizes; jmemmgr.c will request that much space even if - * jpeg_mem_available returns zero. The maximum space needed, enough to hold - * all working storage in memory, is also passed in case it is useful. - * Finally, the total space already allocated is passed. If no better - * method is available, cinfo->mem->max_memory_to_use - already_allocated - * is often a suitable calculation. - * - * It is OK for jpeg_mem_available to underestimate the space available - * (that'll just lead to more backing-store access than is really necessary). - * However, an overestimate will lead to failure. Hence it's wise to subtract - * a slop factor from the true available space. 5% should be enough. - * - * On machines with lots of virtual memory, any large constant may be returned. - * Conversely, zero may be returned to always use the minimum amount of memory. - */ - -EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, - long min_bytes_needed, - long max_bytes_needed, - long already_allocated)); - - -/* - * This structure holds whatever state is needed to access a single - * backing-store object. The read/write/close method pointers are called - * by jmemmgr.c to manipulate the backing-store object; all other fields - * are private to the system-dependent backing store routines. - */ - -#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ - - -#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ - -typedef unsigned short XMSH; /* type of extended-memory handles */ -typedef unsigned short EMSH; /* type of expanded-memory handles */ - -typedef union { - short file_handle; /* DOS file handle if it's a temp file */ - XMSH xms_handle; /* handle if it's a chunk of XMS */ - EMSH ems_handle; /* handle if it's a chunk of EMS */ -} handle_union; - -#endif /* USE_MSDOS_MEMMGR */ - -#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ -#include -#endif /* USE_MAC_MEMMGR */ - - -typedef struct backing_store_struct * backing_store_ptr; - -typedef struct backing_store_struct { - /* Methods for reading/writing/closing this backing-store object */ - JMETHOD(void, read_backing_store, (j_common_ptr cinfo, - backing_store_ptr info, - void FAR * buffer_address, - long file_offset, long byte_count)); - JMETHOD(void, write_backing_store, (j_common_ptr cinfo, - backing_store_ptr info, - void FAR * buffer_address, - long file_offset, long byte_count)); - JMETHOD(void, close_backing_store, (j_common_ptr cinfo, - backing_store_ptr info)); - - /* Private fields for system-dependent backing-store management */ -#ifdef USE_MSDOS_MEMMGR - /* For the MS-DOS manager (jmemdos.c), we need: */ - handle_union handle; /* reference to backing-store storage object */ - char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ -#else -#ifdef USE_MAC_MEMMGR - /* For the Mac manager (jmemmac.c), we need: */ - short temp_file; /* file reference number to temp file */ - FSSpec tempSpec; /* the FSSpec for the temp file */ - char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ -#else - /* For a typical implementation with temp files, we need: */ - FILE * temp_file; /* stdio reference to temp file */ - char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ -#endif -#endif -} backing_store_info; - - -/* - * Initial opening of a backing-store object. This must fill in the - * read/write/close pointers in the object. The read/write routines - * may take an error exit if the specified maximum file size is exceeded. - * (If jpeg_mem_available always returns a large value, this routine can - * just take an error exit.) - */ - -EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, - backing_store_ptr info, - long total_bytes_needed)); - - -/* - * These routines take care of any system-dependent initialization and - * cleanup required. jpeg_mem_init will be called before anything is - * allocated (and, therefore, nothing in cinfo is of use except the error - * manager pointer). It should return a suitable default value for - * max_memory_to_use; this may subsequently be overridden by the surrounding - * application. (Note that max_memory_to_use is only important if - * jpeg_mem_available chooses to consult it ... no one else will.) - * jpeg_mem_term may assume that all requested memory has been freed and that - * all opened backing-store objects have been closed. - */ - -EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); -EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/libraries/jpeg/jmorecfg.h b/libraries/jpeg/jmorecfg.h deleted file mode 100644 index 679d68bdc54..00000000000 --- a/libraries/jpeg/jmorecfg.h +++ /dev/null @@ -1,446 +0,0 @@ -/* - * jmorecfg.h - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 1997-2013 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains additional configuration options that customize the - * JPEG software for special applications or support machine-dependent - * optimizations. Most users will not need to touch this file. - */ - - -/* - * Define BITS_IN_JSAMPLE as either - * 8 for 8-bit sample values (the usual setting) - * 9 for 9-bit sample values - * 10 for 10-bit sample values - * 11 for 11-bit sample values - * 12 for 12-bit sample values - * Only 8, 9, 10, 11, and 12 bits sample data precision are supported for - * full-feature DCT processing. Further depths up to 16-bit may be added - * later for the lossless modes of operation. - * Run-time selection and conversion of data precision will be added later - * and are currently not supported, sorry. - * Exception: The transcoding part (jpegtran) supports all settings in a - * single instance, since it operates on the level of DCT coefficients and - * not sample values. The DCT coefficients are of the same type (16 bits) - * in all cases (see below). - */ - -#define BITS_IN_JSAMPLE 8 /* use 8, 9, 10, 11, or 12 */ - - -/* - * Maximum number of components (color channels) allowed in JPEG image. - * To meet the letter of the JPEG spec, set this to 255. However, darn - * few applications need more than 4 channels (maybe 5 for CMYK + alpha - * mask). We recommend 10 as a reasonable compromise; use 4 if you are - * really short on memory. (Each allowed component costs a hundred or so - * bytes of storage, whether actually used in an image or not.) - */ - -#define MAX_COMPONENTS 10 /* maximum number of image components */ - - -/* - * Basic data types. - * You may need to change these if you have a machine with unusual data - * type sizes; for example, "char" not 8 bits, "short" not 16 bits, - * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, - * but it had better be at least 16. - */ - -/* Representation of a single sample (pixel element value). - * We frequently allocate large arrays of these, so it's important to keep - * them small. But if you have memory to burn and access to char or short - * arrays is very slow on your hardware, you might want to change these. - */ - -#if BITS_IN_JSAMPLE == 8 -/* JSAMPLE should be the smallest type that will hold the values 0..255. - * You can use a signed char by having GETJSAMPLE mask it with 0xFF. - */ - -#ifdef HAVE_UNSIGNED_CHAR - -typedef unsigned char JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#else /* not HAVE_UNSIGNED_CHAR */ - -typedef char JSAMPLE; -#ifdef CHAR_IS_UNSIGNED -#define GETJSAMPLE(value) ((int) (value)) -#else -#define GETJSAMPLE(value) ((int) (value) & 0xFF) -#endif /* CHAR_IS_UNSIGNED */ - -#endif /* HAVE_UNSIGNED_CHAR */ - -#define MAXJSAMPLE 255 -#define CENTERJSAMPLE 128 - -#endif /* BITS_IN_JSAMPLE == 8 */ - - -#if BITS_IN_JSAMPLE == 9 -/* JSAMPLE should be the smallest type that will hold the values 0..511. - * On nearly all machines "short" will do nicely. - */ - -typedef short JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#define MAXJSAMPLE 511 -#define CENTERJSAMPLE 256 - -#endif /* BITS_IN_JSAMPLE == 9 */ - - -#if BITS_IN_JSAMPLE == 10 -/* JSAMPLE should be the smallest type that will hold the values 0..1023. - * On nearly all machines "short" will do nicely. - */ - -typedef short JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#define MAXJSAMPLE 1023 -#define CENTERJSAMPLE 512 - -#endif /* BITS_IN_JSAMPLE == 10 */ - - -#if BITS_IN_JSAMPLE == 11 -/* JSAMPLE should be the smallest type that will hold the values 0..2047. - * On nearly all machines "short" will do nicely. - */ - -typedef short JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#define MAXJSAMPLE 2047 -#define CENTERJSAMPLE 1024 - -#endif /* BITS_IN_JSAMPLE == 11 */ - - -#if BITS_IN_JSAMPLE == 12 -/* JSAMPLE should be the smallest type that will hold the values 0..4095. - * On nearly all machines "short" will do nicely. - */ - -typedef short JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#define MAXJSAMPLE 4095 -#define CENTERJSAMPLE 2048 - -#endif /* BITS_IN_JSAMPLE == 12 */ - - -/* Representation of a DCT frequency coefficient. - * This should be a signed value of at least 16 bits; "short" is usually OK. - * Again, we allocate large arrays of these, but you can change to int - * if you have memory to burn and "short" is really slow. - */ - -typedef short JCOEF; - - -/* Compressed datastreams are represented as arrays of JOCTET. - * These must be EXACTLY 8 bits wide, at least once they are written to - * external storage. Note that when using the stdio data source/destination - * managers, this is also the data type passed to fread/fwrite. - */ - -#ifdef HAVE_UNSIGNED_CHAR - -typedef unsigned char JOCTET; -#define GETJOCTET(value) (value) - -#else /* not HAVE_UNSIGNED_CHAR */ - -typedef char JOCTET; -#ifdef CHAR_IS_UNSIGNED -#define GETJOCTET(value) (value) -#else -#define GETJOCTET(value) ((value) & 0xFF) -#endif /* CHAR_IS_UNSIGNED */ - -#endif /* HAVE_UNSIGNED_CHAR */ - - -/* These typedefs are used for various table entries and so forth. - * They must be at least as wide as specified; but making them too big - * won't cost a huge amount of memory, so we don't provide special - * extraction code like we did for JSAMPLE. (In other words, these - * typedefs live at a different point on the speed/space tradeoff curve.) - */ - -/* UINT8 must hold at least the values 0..255. */ - -#ifdef HAVE_UNSIGNED_CHAR -typedef unsigned char UINT8; -#else /* not HAVE_UNSIGNED_CHAR */ -#ifdef CHAR_IS_UNSIGNED -typedef char UINT8; -#else /* not CHAR_IS_UNSIGNED */ -typedef short UINT8; -#endif /* CHAR_IS_UNSIGNED */ -#endif /* HAVE_UNSIGNED_CHAR */ - -/* UINT16 must hold at least the values 0..65535. */ - -#ifdef HAVE_UNSIGNED_SHORT -typedef unsigned short UINT16; -#else /* not HAVE_UNSIGNED_SHORT */ -typedef unsigned int UINT16; -#endif /* HAVE_UNSIGNED_SHORT */ - -/* INT16 must hold at least the values -32768..32767. */ - -#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ -typedef short INT16; -#endif - -/* INT32 must hold at least signed 32-bit values. */ - -#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ -#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */ -#ifndef _BASETSD_H /* MinGW is slightly different */ -#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */ -typedef long INT32; -#endif -#endif -#endif -#endif - -/* Datatype used for image dimensions. The JPEG standard only supports - * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore - * "unsigned int" is sufficient on all machines. However, if you need to - * handle larger images and you don't mind deviating from the spec, you - * can change this datatype. - */ - -typedef unsigned int JDIMENSION; - -#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ - - -/* These macros are used in all function definitions and extern declarations. - * You could modify them if you need to change function linkage conventions; - * in particular, you'll need to do that to make the library a Windows DLL. - * Another application is to make all functions global for use with debuggers - * or code profilers that require it. - */ - -/* a function called through method pointers: */ -#define METHODDEF(type) static type -/* a function used only in its module: */ -#define LOCAL(type) static type -/* a function referenced thru EXTERNs: */ -#define GLOBAL(type) type -/* a reference to a GLOBAL function: */ -#define EXTERN(type) extern type - - -/* This macro is used to declare a "method", that is, a function pointer. - * We want to supply prototype parameters if the compiler can cope. - * Note that the arglist parameter must be parenthesized! - * Again, you can customize this if you need special linkage keywords. - */ - -#ifdef HAVE_PROTOTYPES -#define JMETHOD(type,methodname,arglist) type (*methodname) arglist -#else -#define JMETHOD(type,methodname,arglist) type (*methodname) () -#endif - - -/* The noreturn type identifier is used to declare functions - * which cannot return. - * Compilers can thus create more optimized code and perform - * better checks for warnings and errors. - * Static analyzer tools can make improved inferences about - * execution paths and are prevented from giving false alerts. - * - * Unfortunately, the proposed specifications of corresponding - * extensions in the Dec 2011 ISO C standard revision (C11), - * GCC, MSVC, etc. are not viable. - * Thus we introduce a user defined type to declare noreturn - * functions at least for clarity. A proper compiler would - * have a suitable noreturn type to match in place of void. - */ - -#ifndef HAVE_NORETURN_T -typedef void noreturn_t; -#endif - - -/* Here is the pseudo-keyword for declaring pointers that must be "far" - * on 80x86 machines. Most of the specialized coding for 80x86 is handled - * by just saying "FAR *" where such a pointer is needed. In a few places - * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. - */ - -#ifndef FAR -#ifdef NEED_FAR_POINTERS -#define FAR far -#else -#define FAR -#endif -#endif - - -/* - * On a few systems, type boolean and/or its values FALSE, TRUE may appear - * in standard header files. Or you may have conflicts with application- - * specific header files that you want to include together with these files. - * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. - */ - -#ifndef HAVE_BOOLEAN -#if defined FALSE || defined TRUE || defined QGLOBAL_H -/* Qt3 defines FALSE and TRUE as "const" variables in qglobal.h */ -typedef int boolean; -#ifndef FALSE /* in case these macros already exist */ -#define FALSE 0 /* values of boolean */ -#endif -#ifndef TRUE -#define TRUE 1 -#endif -#else -typedef enum { FALSE = 0, TRUE = 1 } boolean; -#endif -#endif - - -/* - * The remaining options affect code selection within the JPEG library, - * but they don't need to be visible to most applications using the library. - * To minimize application namespace pollution, the symbols won't be - * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. - */ - -#ifdef JPEG_INTERNALS -#define JPEG_INTERNAL_OPTIONS -#endif - -#ifdef JPEG_INTERNAL_OPTIONS - - -/* - * These defines indicate whether to include various optional functions. - * Undefining some of these symbols will produce a smaller but less capable - * library. Note that you can leave certain source files out of the - * compilation/linking process if you've #undef'd the corresponding symbols. - * (You may HAVE to do that if your compiler doesn't like null source files.) - */ - -/* Capability options common to encoder and decoder: */ - -#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ -#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ -#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ - -/* Encoder capability options: */ - -#define C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ -#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW)*/ -#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ -/* Note: if you selected more than 8-bit data precision, it is dangerous to - * turn off ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only - * good for 8-bit precision, so arithmetic coding is recommended for higher - * precision. The Huffman encoder normally uses entropy optimization to - * compute usable tables for higher precision. Otherwise, you'll have to - * supply different default Huffman tables. - * The exact same statements apply for progressive JPEG: the default tables - * don't work for progressive mode. (This may get fixed, however.) - */ -#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ - -/* Decoder capability options: */ - -#define D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ -#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? (Requires DCT_ISLOW)*/ -#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ -#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ -#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ -#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ -#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ -#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ - -/* more capability options later, no doubt */ - - -/* - * Ordering of RGB data in scanlines passed to or from the application. - * If your application wants to deal with data in the order B,G,R, just - * change these macros. You can also deal with formats such as R,G,B,X - * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing - * the offsets will also change the order in which colormap data is organized. - * RESTRICTIONS: - * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. - * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE - * is not 3 (they don't understand about dummy color components!). So you - * can't use color quantization if you change that value. - */ - -#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ -#define RGB_GREEN 1 /* Offset of Green */ -#define RGB_BLUE 2 /* Offset of Blue */ -#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ - - -/* Definitions for speed-related optimizations. */ - - -/* If your compiler supports inline functions, define INLINE - * as the inline keyword; otherwise define it as empty. - */ - -#ifndef INLINE -#ifdef __GNUC__ /* for instance, GNU C knows about inline */ -#define INLINE __inline__ -#endif -#ifndef INLINE -#define INLINE /* default is to define it as empty */ -#endif -#endif - - -/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying - * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER - * as short on such a machine. MULTIPLIER must be at least 16 bits wide. - */ - -#ifndef MULTIPLIER -#define MULTIPLIER int /* type for fastest integer multiply */ -#endif - - -/* FAST_FLOAT should be either float or double, whichever is done faster - * by your compiler. (Note that this type is only used in the floating point - * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) - * Typically, float is faster in ANSI C compilers, while double is faster in - * pre-ANSI compilers (because they insist on converting to double anyway). - * The code below therefore chooses float if we have ANSI-style prototypes. - */ - -#ifndef FAST_FLOAT -#ifdef HAVE_PROTOTYPES -#define FAST_FLOAT float -#else -#define FAST_FLOAT double -#endif -#endif - -#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/libraries/jpeg/jpegint.h b/libraries/jpeg/jpegint.h deleted file mode 100644 index e312e1af974..00000000000 --- a/libraries/jpeg/jpegint.h +++ /dev/null @@ -1,439 +0,0 @@ -/* - * jpegint.h - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 1997-2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file provides common declarations for the various JPEG modules. - * These declarations are considered internal to the JPEG library; most - * applications using the library shouldn't need to include this file. - */ - - -/* Declarations for both compression & decompression */ - -typedef enum { /* Operating modes for buffer controllers */ - JBUF_PASS_THRU, /* Plain stripwise operation */ - /* Remaining modes require a full-image buffer to have been created */ - JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ - JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ - JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ -} J_BUF_MODE; - -/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ -#define CSTATE_START 100 /* after create_compress */ -#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ -#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ -#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ -#define DSTATE_START 200 /* after create_decompress */ -#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ -#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ -#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ -#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ -#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ -#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ -#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ -#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ -#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ -#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ - - -/* Declarations for compression modules */ - -/* Master control module */ -struct jpeg_comp_master { - JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); - JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); - JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); - - /* State variables made visible to other modules */ - boolean call_pass_startup; /* True if pass_startup must be called */ - boolean is_last_pass; /* True during last pass */ -}; - -/* Main buffer control (downsampled-data buffer) */ -struct jpeg_c_main_controller { - JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(void, process_data, (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, - JDIMENSION in_rows_avail)); -}; - -/* Compression preprocessing (downsampling input buffer control) */ -struct jpeg_c_prep_controller { - JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, - JSAMPARRAY input_buf, - JDIMENSION *in_row_ctr, - JDIMENSION in_rows_avail, - JSAMPIMAGE output_buf, - JDIMENSION *out_row_group_ctr, - JDIMENSION out_row_groups_avail)); -}; - -/* Coefficient buffer control */ -struct jpeg_c_coef_controller { - JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, - JSAMPIMAGE input_buf)); -}; - -/* Colorspace conversion */ -struct jpeg_color_converter { - JMETHOD(void, start_pass, (j_compress_ptr cinfo)); - JMETHOD(void, color_convert, (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPIMAGE output_buf, - JDIMENSION output_row, int num_rows)); -}; - -/* Downsampling */ -struct jpeg_downsampler { - JMETHOD(void, start_pass, (j_compress_ptr cinfo)); - JMETHOD(void, downsample, (j_compress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_index, - JSAMPIMAGE output_buf, - JDIMENSION out_row_group_index)); - - boolean need_context_rows; /* TRUE if need rows above & below */ -}; - -/* Forward DCT (also controls coefficient quantization) */ -typedef JMETHOD(void, forward_DCT_ptr, - (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY sample_data, JBLOCKROW coef_blocks, - JDIMENSION start_row, JDIMENSION start_col, - JDIMENSION num_blocks)); - -struct jpeg_forward_dct { - JMETHOD(void, start_pass, (j_compress_ptr cinfo)); - /* It is useful to allow each component to have a separate FDCT method. */ - forward_DCT_ptr forward_DCT[MAX_COMPONENTS]; -}; - -/* Entropy encoding */ -struct jpeg_entropy_encoder { - JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); - JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); - JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); -}; - -/* Marker writing */ -struct jpeg_marker_writer { - JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); - JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); - JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); - JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); - JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); - /* These routines are exported to allow insertion of extra markers */ - /* Probably only COM and APPn markers should be written this way */ - JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, - unsigned int datalen)); - JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); -}; - - -/* Declarations for decompression modules */ - -/* Master control module */ -struct jpeg_decomp_master { - JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); - - /* State variables made visible to other modules */ - boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ -}; - -/* Input control module */ -struct jpeg_input_controller { - JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); - JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); - JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); - - /* State variables made visible to other modules */ - boolean has_multiple_scans; /* True if file has multiple scans */ - boolean eoi_reached; /* True when EOI has been consumed */ -}; - -/* Main buffer control (downsampled-data buffer) */ -struct jpeg_d_main_controller { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(void, process_data, (j_decompress_ptr cinfo, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -}; - -/* Coefficient buffer control */ -struct jpeg_d_coef_controller { - JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); - JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); - JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); - JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, - JSAMPIMAGE output_buf)); - /* Pointer to array of coefficient virtual arrays, or NULL if none */ - jvirt_barray_ptr *coef_arrays; -}; - -/* Decompression postprocessing (color quantization buffer control) */ -struct jpeg_d_post_controller { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, - JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -}; - -/* Marker reading & parsing */ -struct jpeg_marker_reader { - JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); - /* Read markers until SOS or EOI. - * Returns same codes as are defined for jpeg_consume_input: - * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. - */ - JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); - /* Read a restart marker --- exported for use by entropy decoder only */ - jpeg_marker_parser_method read_restart_marker; - - /* State of marker reader --- nominally internal, but applications - * supplying COM or APPn handlers might like to know the state. - */ - boolean saw_SOI; /* found SOI? */ - boolean saw_SOF; /* found SOF? */ - int next_restart_num; /* next restart number expected (0-7) */ - unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ -}; - -/* Entropy decoding */ -struct jpeg_entropy_decoder { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); - JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)); - JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); -}; - -/* Inverse DCT (also performs dequantization) */ -typedef JMETHOD(void, inverse_DCT_method_ptr, - (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col)); - -struct jpeg_inverse_dct { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); - /* It is useful to allow each component to have a separate IDCT method. */ - inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; -}; - -/* Upsampling (note that upsampler must also call color converter) */ -struct jpeg_upsampler { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, upsample, (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, - JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); - - boolean need_context_rows; /* TRUE if need rows above & below */ -}; - -/* Colorspace conversion */ -struct jpeg_color_deconverter { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, color_convert, (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows)); -}; - -/* Color quantization or color precision reduction */ -struct jpeg_color_quantizer { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); - JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, - int num_rows)); - JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); -}; - - -/* Definition of range extension bits for decompression processes. - * See the comments with prepare_range_limit_table (in jdmaster.c) - * for more info. - * The recommended default value for normal applications is 2. - * Applications with special requirements may use a different value. - * For example, Ghostscript wants to use 3 for proper handling of - * wacky images with oversize coefficient values. - */ - -#define RANGE_BITS 2 -#define RANGE_CENTER (CENTERJSAMPLE << RANGE_BITS) - - -/* Miscellaneous useful macros */ - -#undef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#undef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - - -/* We assume that right shift corresponds to signed division by 2 with - * rounding towards minus infinity. This is correct for typical "arithmetic - * shift" instructions that shift in copies of the sign bit. But some - * C compilers implement >> with an unsigned shift. For these machines you - * must define RIGHT_SHIFT_IS_UNSIGNED. - * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. - * It is only applied with constant shift counts. SHIFT_TEMPS must be - * included in the variables of any routine using RIGHT_SHIFT. - */ - -#ifdef RIGHT_SHIFT_IS_UNSIGNED -#define SHIFT_TEMPS INT32 shift_temp; -#define RIGHT_SHIFT(x,shft) \ - ((shift_temp = (x)) < 0 ? \ - (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ - (shift_temp >> (shft))) -#else -#define SHIFT_TEMPS -#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) -#endif - - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jinit_compress_master jICompress -#define jinit_c_master_control jICMaster -#define jinit_c_main_controller jICMainC -#define jinit_c_prep_controller jICPrepC -#define jinit_c_coef_controller jICCoefC -#define jinit_color_converter jICColor -#define jinit_downsampler jIDownsampler -#define jinit_forward_dct jIFDCT -#define jinit_huff_encoder jIHEncoder -#define jinit_arith_encoder jIAEncoder -#define jinit_marker_writer jIMWriter -#define jinit_master_decompress jIDMaster -#define jinit_d_main_controller jIDMainC -#define jinit_d_coef_controller jIDCoefC -#define jinit_d_post_controller jIDPostC -#define jinit_input_controller jIInCtlr -#define jinit_marker_reader jIMReader -#define jinit_huff_decoder jIHDecoder -#define jinit_arith_decoder jIADecoder -#define jinit_inverse_dct jIIDCT -#define jinit_upsampler jIUpsampler -#define jinit_color_deconverter jIDColor -#define jinit_1pass_quantizer jI1Quant -#define jinit_2pass_quantizer jI2Quant -#define jinit_merged_upsampler jIMUpsampler -#define jinit_memory_mgr jIMemMgr -#define jdiv_round_up jDivRound -#define jround_up jRound -#define jzero_far jZeroFar -#define jcopy_sample_rows jCopySamples -#define jcopy_block_row jCopyBlocks -#define jpeg_zigzag_order jZIGTable -#define jpeg_natural_order jZAGTable -#define jpeg_natural_order7 jZAG7Table -#define jpeg_natural_order6 jZAG6Table -#define jpeg_natural_order5 jZAG5Table -#define jpeg_natural_order4 jZAG4Table -#define jpeg_natural_order3 jZAG3Table -#define jpeg_natural_order2 jZAG2Table -#define jpeg_aritab jAriTab -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays - * and coefficient-block arrays. This won't work on 80x86 because the arrays - * are FAR and we're assuming a small-pointer memory model. However, some - * DOS compilers provide far-pointer versions of memcpy() and memset() even - * in the small-model libraries. These will be used if USE_FMEM is defined. - * Otherwise, the routines in jutils.c do it the hard way. - */ - -#ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */ -#define FMEMZERO(target,size) MEMZERO(target,size) -#else /* 80x86 case */ -#ifdef USE_FMEM -#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) -#else -EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); -#define FMEMZERO(target,size) jzero_far(target, size) -#endif -#endif - - -/* Compression module initialization routines */ -EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, - boolean transcode_only)); -EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); -/* Decompression module initialization routines */ -EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); -/* Memory manager initialization */ -EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); - -/* Utility routines in jutils.c */ -EXTERN(long) jdiv_round_up JPP((long a, long b)); -EXTERN(long) jround_up JPP((long a, long b)); -EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, - JSAMPARRAY output_array, int dest_row, - int num_rows, JDIMENSION num_cols)); -EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, - JDIMENSION num_blocks)); -/* Constant tables in jutils.c */ -#if 0 /* This table is not actually needed in v6a */ -extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ -#endif -extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ -extern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */ -extern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */ -extern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */ -extern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */ -extern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */ -extern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */ - -/* Arithmetic coding probability estimation tables in jaricom.c */ -extern const INT32 jpeg_aritab[]; - -/* Suppress undefined-structure complaints if necessary. */ - -#ifdef INCOMPLETE_TYPES_BROKEN -#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ -struct jvirt_sarray_control { long dummy; }; -struct jvirt_barray_control { long dummy; }; -#endif -#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/libraries/jpeg/jpeglib.h b/libraries/jpeg/jpeglib.h deleted file mode 100644 index 4bd985316ec..00000000000 --- a/libraries/jpeg/jpeglib.h +++ /dev/null @@ -1,1180 +0,0 @@ -/* - * jpeglib.h - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * Modified 2002-2017 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file defines the application interface for the JPEG library. - * Most applications using the library need only include this file, - * and perhaps jerror.h if they want to know the exact error codes. - */ - -#ifndef JPEGLIB_H -#define JPEGLIB_H - -/* - * First we include the configuration files that record how this - * installation of the JPEG library is set up. jconfig.h can be - * generated automatically for many systems. jmorecfg.h contains - * manual configuration options that most people need not worry about. - */ - -#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ -#include "jconfig.h" /* widely used configuration options */ -#endif -#include "jmorecfg.h" /* seldom changed options */ - - -#ifdef __cplusplus -#ifndef DONT_USE_EXTERN_C -extern "C" { -#endif -#endif - -/* Version IDs for the JPEG library. - * Might be useful for tests like "#if JPEG_LIB_VERSION >= 90". - */ - -#define JPEG_LIB_VERSION 90 /* Compatibility version 9.0 */ -#define JPEG_LIB_VERSION_MAJOR 9 -#define JPEG_LIB_VERSION_MINOR 3 - - -/* Various constants determining the sizes of things. - * All of these are specified by the JPEG standard, - * so don't change them if you want to be compatible. - */ - -#define DCTSIZE 8 /* The basic DCT block is 8x8 coefficients */ -#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ -#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ -#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ -#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ -#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ -#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ -/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; - * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. - * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU - * to handle it. We even let you do this from the jconfig.h file. However, - * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe - * sometimes emits noncompliant files doesn't mean you should too. - */ -#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ -#ifndef D_MAX_BLOCKS_IN_MCU -#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ -#endif - - -/* Data structures for images (arrays of samples and of DCT coefficients). - * On 80x86 machines, the image arrays are too big for near pointers, - * but the pointer arrays can fit in near memory. - */ - -typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ -typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ -typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ - -typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ -typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ -typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ -typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ - -typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ - - -/* Types for JPEG compression parameters and working tables. */ - - -/* DCT coefficient quantization tables. */ - -typedef struct { - /* This array gives the coefficient quantizers in natural array order - * (not the zigzag order in which they are stored in a JPEG DQT marker). - * CAUTION: IJG versions prior to v6a kept this array in zigzag order. - */ - UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ - /* This field is used only during compression. It's initialized FALSE when - * the table is created, and set TRUE when it's been output to the file. - * You could suppress output of a table by setting this to TRUE. - * (See jpeg_suppress_tables for an example.) - */ - boolean sent_table; /* TRUE when table has been output */ -} JQUANT_TBL; - - -/* Huffman coding tables. */ - -typedef struct { - /* These two fields directly represent the contents of a JPEG DHT marker */ - UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ - /* length k bits; bits[0] is unused */ - UINT8 huffval[256]; /* The symbols, in order of incr code length */ - /* This field is used only during compression. It's initialized FALSE when - * the table is created, and set TRUE when it's been output to the file. - * You could suppress output of a table by setting this to TRUE. - * (See jpeg_suppress_tables for an example.) - */ - boolean sent_table; /* TRUE when table has been output */ -} JHUFF_TBL; - - -/* Basic info about one component (color channel). */ - -typedef struct { - /* These values are fixed over the whole image. */ - /* For compression, they must be supplied by parameter setup; */ - /* for decompression, they are read from the SOF marker. */ - int component_id; /* identifier for this component (0..255) */ - int component_index; /* its index in SOF or cinfo->comp_info[] */ - int h_samp_factor; /* horizontal sampling factor (1..4) */ - int v_samp_factor; /* vertical sampling factor (1..4) */ - int quant_tbl_no; /* quantization table selector (0..3) */ - /* These values may vary between scans. */ - /* For compression, they must be supplied by parameter setup; */ - /* for decompression, they are read from the SOS marker. */ - /* The decompressor output side may not use these variables. */ - int dc_tbl_no; /* DC entropy table selector (0..3) */ - int ac_tbl_no; /* AC entropy table selector (0..3) */ - - /* Remaining fields should be treated as private by applications. */ - - /* These values are computed during compression or decompression startup: */ - /* Component's size in DCT blocks. - * Any dummy blocks added to complete an MCU are not counted; therefore - * these values do not depend on whether a scan is interleaved or not. - */ - JDIMENSION width_in_blocks; - JDIMENSION height_in_blocks; - /* Size of a DCT block in samples, - * reflecting any scaling we choose to apply during the DCT step. - * Values from 1 to 16 are supported. - * Note that different components may receive different DCT scalings. - */ - int DCT_h_scaled_size; - int DCT_v_scaled_size; - /* The downsampled dimensions are the component's actual, unpadded number - * of samples at the main buffer (preprocessing/compression interface); - * DCT scaling is included, so - * downsampled_width = - * ceil(image_width * Hi/Hmax * DCT_h_scaled_size/block_size) - * and similarly for height. - */ - JDIMENSION downsampled_width; /* actual width in samples */ - JDIMENSION downsampled_height; /* actual height in samples */ - /* For decompression, in cases where some of the components will be - * ignored (eg grayscale output from YCbCr image), we can skip most - * computations for the unused components. - * For compression, some of the components will need further quantization - * scale by factor of 2 after DCT (eg BG_YCC output from normal RGB input). - * The field is first set TRUE for decompression, FALSE for compression - * in initial_setup, and then adapted in color conversion setup. - */ - boolean component_needed; - - /* These values are computed before starting a scan of the component. */ - /* The decompressor output side may not use these variables. */ - int MCU_width; /* number of blocks per MCU, horizontally */ - int MCU_height; /* number of blocks per MCU, vertically */ - int MCU_blocks; /* MCU_width * MCU_height */ - int MCU_sample_width; /* MCU width in samples: MCU_width * DCT_h_scaled_size */ - int last_col_width; /* # of non-dummy blocks across in last MCU */ - int last_row_height; /* # of non-dummy blocks down in last MCU */ - - /* Saved quantization table for component; NULL if none yet saved. - * See jdinput.c comments about the need for this information. - * This field is currently used only for decompression. - */ - JQUANT_TBL * quant_table; - - /* Private per-component storage for DCT or IDCT subsystem. */ - void * dct_table; -} jpeg_component_info; - - -/* The script for encoding a multiple-scan file is an array of these: */ - -typedef struct { - int comps_in_scan; /* number of components encoded in this scan */ - int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ - int Ss, Se; /* progressive JPEG spectral selection parms */ - int Ah, Al; /* progressive JPEG successive approx. parms */ -} jpeg_scan_info; - -/* The decompressor can save APPn and COM markers in a list of these: */ - -typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; - -struct jpeg_marker_struct { - jpeg_saved_marker_ptr next; /* next in list, or NULL */ - UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ - unsigned int original_length; /* # bytes of data in the file */ - unsigned int data_length; /* # bytes of data saved at data[] */ - JOCTET FAR * data; /* the data contained in the marker */ - /* the marker length word is not counted in data_length or original_length */ -}; - -/* Known color spaces. */ - -typedef enum { - JCS_UNKNOWN, /* error/unspecified */ - JCS_GRAYSCALE, /* monochrome */ - JCS_RGB, /* red/green/blue, standard RGB (sRGB) */ - JCS_YCbCr, /* Y/Cb/Cr (also known as YUV), standard YCC */ - JCS_CMYK, /* C/M/Y/K */ - JCS_YCCK, /* Y/Cb/Cr/K */ - JCS_BG_RGB, /* big gamut red/green/blue, bg-sRGB */ - JCS_BG_YCC /* big gamut Y/Cb/Cr, bg-sYCC */ -} J_COLOR_SPACE; - -/* Supported color transforms. */ - -typedef enum { - JCT_NONE = 0, - JCT_SUBTRACT_GREEN = 1 -} J_COLOR_TRANSFORM; - -/* DCT/IDCT algorithm options. */ - -typedef enum { - JDCT_ISLOW, /* slow but accurate integer algorithm */ - JDCT_IFAST, /* faster, less accurate integer method */ - JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ -} J_DCT_METHOD; - -#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ -#define JDCT_DEFAULT JDCT_ISLOW -#endif -#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ -#define JDCT_FASTEST JDCT_IFAST -#endif - -/* Dithering options for decompression. */ - -typedef enum { - JDITHER_NONE, /* no dithering */ - JDITHER_ORDERED, /* simple ordered dither */ - JDITHER_FS /* Floyd-Steinberg error diffusion dither */ -} J_DITHER_MODE; - - -/* Common fields between JPEG compression and decompression master structs. */ - -#define jpeg_common_fields \ - struct jpeg_error_mgr * err; /* Error handler module */\ - struct jpeg_memory_mgr * mem; /* Memory manager module */\ - struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ - void * client_data; /* Available for use by application */\ - boolean is_decompressor; /* So common code can tell which is which */\ - int global_state /* For checking call sequence validity */ - -/* Routines that are to be used by both halves of the library are declared - * to receive a pointer to this structure. There are no actual instances of - * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. - */ -struct jpeg_common_struct { - jpeg_common_fields; /* Fields common to both master struct types */ - /* Additional fields follow in an actual jpeg_compress_struct or - * jpeg_decompress_struct. All three structs must agree on these - * initial fields! (This would be a lot cleaner in C++.) - */ -}; - -typedef struct jpeg_common_struct * j_common_ptr; -typedef struct jpeg_compress_struct * j_compress_ptr; -typedef struct jpeg_decompress_struct * j_decompress_ptr; - - -/* Master record for a compression instance */ - -struct jpeg_compress_struct { - jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ - - /* Destination for compressed data */ - struct jpeg_destination_mgr * dest; - - /* Description of source image --- these fields must be filled in by - * outer application before starting compression. in_color_space must - * be correct before you can even call jpeg_set_defaults(). - */ - - JDIMENSION image_width; /* input image width */ - JDIMENSION image_height; /* input image height */ - int input_components; /* # of color components in input image */ - J_COLOR_SPACE in_color_space; /* colorspace of input image */ - - double input_gamma; /* image gamma of input image */ - - /* Compression parameters --- these fields must be set before calling - * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to - * initialize everything to reasonable defaults, then changing anything - * the application specifically wants to change. That way you won't get - * burnt when new parameters are added. Also note that there are several - * helper routines to simplify changing parameters. - */ - - unsigned int scale_num, scale_denom; /* fraction by which to scale image */ - - JDIMENSION jpeg_width; /* scaled JPEG image width */ - JDIMENSION jpeg_height; /* scaled JPEG image height */ - /* Dimensions of actual JPEG image that will be written to file, - * derived from input dimensions by scaling factors above. - * These fields are computed by jpeg_start_compress(). - * You can also use jpeg_calc_jpeg_dimensions() to determine these values - * in advance of calling jpeg_start_compress(). - */ - - int data_precision; /* bits of precision in image data */ - - int num_components; /* # of color components in JPEG image */ - J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ - - jpeg_component_info * comp_info; - /* comp_info[i] describes component that appears i'th in SOF */ - - JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; - int q_scale_factor[NUM_QUANT_TBLS]; - /* ptrs to coefficient quantization tables, or NULL if not defined, - * and corresponding scale factors (percentage, initialized 100). - */ - - JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; - JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; - /* ptrs to Huffman coding tables, or NULL if not defined */ - - UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ - UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ - UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ - - int num_scans; /* # of entries in scan_info array */ - const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ - /* The default value of scan_info is NULL, which causes a single-scan - * sequential JPEG file to be emitted. To create a multi-scan file, - * set num_scans and scan_info to point to an array of scan definitions. - */ - - boolean raw_data_in; /* TRUE=caller supplies downsampled data */ - boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ - boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ - boolean CCIR601_sampling; /* TRUE=first samples are cosited */ - boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ - int smoothing_factor; /* 1..100, or 0 for no input smoothing */ - J_DCT_METHOD dct_method; /* DCT algorithm selector */ - - /* The restart interval can be specified in absolute MCUs by setting - * restart_interval, or in MCU rows by setting restart_in_rows - * (in which case the correct restart_interval will be figured - * for each scan). - */ - unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ - int restart_in_rows; /* if > 0, MCU rows per restart interval */ - - /* Parameters controlling emission of special markers. */ - - boolean write_JFIF_header; /* should a JFIF marker be written? */ - UINT8 JFIF_major_version; /* What to write for the JFIF version number */ - UINT8 JFIF_minor_version; - /* These three values are not used by the JPEG code, merely copied */ - /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ - /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ - /* ratio is defined by X_density/Y_density even when density_unit=0. */ - UINT8 density_unit; /* JFIF code for pixel size units */ - UINT16 X_density; /* Horizontal pixel density */ - UINT16 Y_density; /* Vertical pixel density */ - boolean write_Adobe_marker; /* should an Adobe marker be written? */ - - J_COLOR_TRANSFORM color_transform; - /* Color transform identifier, writes LSE marker if nonzero */ - - /* State variable: index of next scanline to be written to - * jpeg_write_scanlines(). Application may use this to control its - * processing loop, e.g., "while (next_scanline < image_height)". - */ - - JDIMENSION next_scanline; /* 0 .. image_height-1 */ - - /* Remaining fields are known throughout compressor, but generally - * should not be touched by a surrounding application. - */ - - /* - * These fields are computed during compression startup - */ - boolean progressive_mode; /* TRUE if scan script uses progressive mode */ - int max_h_samp_factor; /* largest h_samp_factor */ - int max_v_samp_factor; /* largest v_samp_factor */ - - int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ - int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ - - JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ - /* The coefficient controller receives data in units of MCU rows as defined - * for fully interleaved scans (whether the JPEG file is interleaved or not). - * There are v_samp_factor * DCT_v_scaled_size sample rows of each component - * in an "iMCU" (interleaved MCU) row. - */ - - /* - * These fields are valid during any one scan. - * They describe the components and MCUs actually appearing in the scan. - */ - int comps_in_scan; /* # of JPEG components in this scan */ - jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; - /* *cur_comp_info[i] describes component that appears i'th in SOS */ - - JDIMENSION MCUs_per_row; /* # of MCUs across the image */ - JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ - - int blocks_in_MCU; /* # of DCT blocks per MCU */ - int MCU_membership[C_MAX_BLOCKS_IN_MCU]; - /* MCU_membership[i] is index in cur_comp_info of component owning */ - /* i'th block in an MCU */ - - int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ - - int block_size; /* the basic DCT block size: 1..16 */ - const int * natural_order; /* natural-order position array */ - int lim_Se; /* min( Se, DCTSIZE2-1 ) */ - - /* - * Links to compression subobjects (methods and private variables of modules) - */ - struct jpeg_comp_master * master; - struct jpeg_c_main_controller * main; - struct jpeg_c_prep_controller * prep; - struct jpeg_c_coef_controller * coef; - struct jpeg_marker_writer * marker; - struct jpeg_color_converter * cconvert; - struct jpeg_downsampler * downsample; - struct jpeg_forward_dct * fdct; - struct jpeg_entropy_encoder * entropy; - jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ - int script_space_size; -}; - - -/* Master record for a decompression instance */ - -struct jpeg_decompress_struct { - jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ - - /* Source of compressed data */ - struct jpeg_source_mgr * src; - - /* Basic description of image --- filled in by jpeg_read_header(). */ - /* Application may inspect these values to decide how to process image. */ - - JDIMENSION image_width; /* nominal image width (from SOF marker) */ - JDIMENSION image_height; /* nominal image height */ - int num_components; /* # of color components in JPEG image */ - J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ - - /* Decompression processing parameters --- these fields must be set before - * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes - * them to default values. - */ - - J_COLOR_SPACE out_color_space; /* colorspace for output */ - - unsigned int scale_num, scale_denom; /* fraction by which to scale image */ - - double output_gamma; /* image gamma wanted in output */ - - boolean buffered_image; /* TRUE=multiple output passes */ - boolean raw_data_out; /* TRUE=downsampled data wanted */ - - J_DCT_METHOD dct_method; /* IDCT algorithm selector */ - boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ - boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ - - boolean quantize_colors; /* TRUE=colormapped output wanted */ - /* the following are ignored if not quantize_colors: */ - J_DITHER_MODE dither_mode; /* type of color dithering to use */ - boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ - int desired_number_of_colors; /* max # colors to use in created colormap */ - /* these are significant only in buffered-image mode: */ - boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ - boolean enable_external_quant;/* enable future use of external colormap */ - boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ - - /* Description of actual output image that will be returned to application. - * These fields are computed by jpeg_start_decompress(). - * You can also use jpeg_calc_output_dimensions() to determine these values - * in advance of calling jpeg_start_decompress(). - */ - - JDIMENSION output_width; /* scaled image width */ - JDIMENSION output_height; /* scaled image height */ - int out_color_components; /* # of color components in out_color_space */ - int output_components; /* # of color components returned */ - /* output_components is 1 (a colormap index) when quantizing colors; - * otherwise it equals out_color_components. - */ - int rec_outbuf_height; /* min recommended height of scanline buffer */ - /* If the buffer passed to jpeg_read_scanlines() is less than this many rows - * high, space and time will be wasted due to unnecessary data copying. - * Usually rec_outbuf_height will be 1 or 2, at most 4. - */ - - /* When quantizing colors, the output colormap is described by these fields. - * The application can supply a colormap by setting colormap non-NULL before - * calling jpeg_start_decompress; otherwise a colormap is created during - * jpeg_start_decompress or jpeg_start_output. - * The map has out_color_components rows and actual_number_of_colors columns. - */ - int actual_number_of_colors; /* number of entries in use */ - JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ - - /* State variables: these variables indicate the progress of decompression. - * The application may examine these but must not modify them. - */ - - /* Row index of next scanline to be read from jpeg_read_scanlines(). - * Application may use this to control its processing loop, e.g., - * "while (output_scanline < output_height)". - */ - JDIMENSION output_scanline; /* 0 .. output_height-1 */ - - /* Current input scan number and number of iMCU rows completed in scan. - * These indicate the progress of the decompressor input side. - */ - int input_scan_number; /* Number of SOS markers seen so far */ - JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ - - /* The "output scan number" is the notional scan being displayed by the - * output side. The decompressor will not allow output scan/row number - * to get ahead of input scan/row, but it can fall arbitrarily far behind. - */ - int output_scan_number; /* Nominal scan number being displayed */ - JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ - - /* Current progression status. coef_bits[c][i] indicates the precision - * with which component c's DCT coefficient i (in zigzag order) is known. - * It is -1 when no data has yet been received, otherwise it is the point - * transform (shift) value for the most recent scan of the coefficient - * (thus, 0 at completion of the progression). - * This pointer is NULL when reading a non-progressive file. - */ - int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ - - /* Internal JPEG parameters --- the application usually need not look at - * these fields. Note that the decompressor output side may not use - * any parameters that can change between scans. - */ - - /* Quantization and Huffman tables are carried forward across input - * datastreams when processing abbreviated JPEG datastreams. - */ - - JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; - /* ptrs to coefficient quantization tables, or NULL if not defined */ - - JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; - JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; - /* ptrs to Huffman coding tables, or NULL if not defined */ - - /* These parameters are never carried across datastreams, since they - * are given in SOF/SOS markers or defined to be reset by SOI. - */ - - int data_precision; /* bits of precision in image data */ - - jpeg_component_info * comp_info; - /* comp_info[i] describes component that appears i'th in SOF */ - - boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ - boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ - boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ - - UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ - UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ - UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ - - unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ - - /* These fields record data obtained from optional markers recognized by - * the JPEG library. - */ - boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ - /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ - UINT8 JFIF_major_version; /* JFIF version number */ - UINT8 JFIF_minor_version; - UINT8 density_unit; /* JFIF code for pixel size units */ - UINT16 X_density; /* Horizontal pixel density */ - UINT16 Y_density; /* Vertical pixel density */ - boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ - UINT8 Adobe_transform; /* Color transform code from Adobe marker */ - - J_COLOR_TRANSFORM color_transform; - /* Color transform identifier derived from LSE marker, otherwise zero */ - - boolean CCIR601_sampling; /* TRUE=first samples are cosited */ - - /* Aside from the specific data retained from APPn markers known to the - * library, the uninterpreted contents of any or all APPn and COM markers - * can be saved in a list for examination by the application. - */ - jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ - - /* Remaining fields are known throughout decompressor, but generally - * should not be touched by a surrounding application. - */ - - /* - * These fields are computed during decompression startup - */ - int max_h_samp_factor; /* largest h_samp_factor */ - int max_v_samp_factor; /* largest v_samp_factor */ - - int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ - int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ - - JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ - /* The coefficient controller's input and output progress is measured in - * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows - * in fully interleaved JPEG scans, but are used whether the scan is - * interleaved or not. We define an iMCU row as v_samp_factor DCT block - * rows of each component. Therefore, the IDCT output contains - * v_samp_factor * DCT_v_scaled_size sample rows of a component per iMCU row. - */ - - JSAMPLE * sample_range_limit; /* table for fast range-limiting */ - - /* - * These fields are valid during any one scan. - * They describe the components and MCUs actually appearing in the scan. - * Note that the decompressor output side must not use these fields. - */ - int comps_in_scan; /* # of JPEG components in this scan */ - jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; - /* *cur_comp_info[i] describes component that appears i'th in SOS */ - - JDIMENSION MCUs_per_row; /* # of MCUs across the image */ - JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ - - int blocks_in_MCU; /* # of DCT blocks per MCU */ - int MCU_membership[D_MAX_BLOCKS_IN_MCU]; - /* MCU_membership[i] is index in cur_comp_info of component owning */ - /* i'th block in an MCU */ - - int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ - - /* These fields are derived from Se of first SOS marker. - */ - int block_size; /* the basic DCT block size: 1..16 */ - const int * natural_order; /* natural-order position array for entropy decode */ - int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ - - /* This field is shared between entropy decoder and marker parser. - * It is either zero or the code of a JPEG marker that has been - * read from the data source, but has not yet been processed. - */ - int unread_marker; - - /* - * Links to decompression subobjects (methods, private variables of modules) - */ - struct jpeg_decomp_master * master; - struct jpeg_d_main_controller * main; - struct jpeg_d_coef_controller * coef; - struct jpeg_d_post_controller * post; - struct jpeg_input_controller * inputctl; - struct jpeg_marker_reader * marker; - struct jpeg_entropy_decoder * entropy; - struct jpeg_inverse_dct * idct; - struct jpeg_upsampler * upsample; - struct jpeg_color_deconverter * cconvert; - struct jpeg_color_quantizer * cquantize; -}; - - -/* "Object" declarations for JPEG modules that may be supplied or called - * directly by the surrounding application. - * As with all objects in the JPEG library, these structs only define the - * publicly visible methods and state variables of a module. Additional - * private fields may exist after the public ones. - */ - - -/* Error handler object */ - -struct jpeg_error_mgr { - /* Error exit handler: does not return to caller */ - JMETHOD(noreturn_t, error_exit, (j_common_ptr cinfo)); - /* Conditionally emit a trace or warning message */ - JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); - /* Routine that actually outputs a trace or error message */ - JMETHOD(void, output_message, (j_common_ptr cinfo)); - /* Format a message string for the most recent JPEG error or message */ - JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); -#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ - /* Reset error state variables at start of a new image */ - JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); - - /* The message ID code and any parameters are saved here. - * A message can have one string parameter or up to 8 int parameters. - */ - int msg_code; -#define JMSG_STR_PARM_MAX 80 - union { - int i[8]; - char s[JMSG_STR_PARM_MAX]; - } msg_parm; - - /* Standard state variables for error facility */ - - int trace_level; /* max msg_level that will be displayed */ - - /* For recoverable corrupt-data errors, we emit a warning message, - * but keep going unless emit_message chooses to abort. emit_message - * should count warnings in num_warnings. The surrounding application - * can check for bad data by seeing if num_warnings is nonzero at the - * end of processing. - */ - long num_warnings; /* number of corrupt-data warnings */ - - /* These fields point to the table(s) of error message strings. - * An application can change the table pointer to switch to a different - * message list (typically, to change the language in which errors are - * reported). Some applications may wish to add additional error codes - * that will be handled by the JPEG library error mechanism; the second - * table pointer is used for this purpose. - * - * First table includes all errors generated by JPEG library itself. - * Error code 0 is reserved for a "no such error string" message. - */ - const char * const * jpeg_message_table; /* Library errors */ - int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ - /* Second table can be added by application (see cjpeg/djpeg for example). - * It contains strings numbered first_addon_message..last_addon_message. - */ - const char * const * addon_message_table; /* Non-library errors */ - int first_addon_message; /* code for first string in addon table */ - int last_addon_message; /* code for last string in addon table */ -}; - - -/* Progress monitor object */ - -struct jpeg_progress_mgr { - JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); - - long pass_counter; /* work units completed in this pass */ - long pass_limit; /* total number of work units in this pass */ - int completed_passes; /* passes completed so far */ - int total_passes; /* total number of passes expected */ -}; - - -/* Data destination object for compression */ - -struct jpeg_destination_mgr { - JOCTET * next_output_byte; /* => next byte to write in buffer */ - size_t free_in_buffer; /* # of byte spaces remaining in buffer */ - - JMETHOD(void, init_destination, (j_compress_ptr cinfo)); - JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); - JMETHOD(void, term_destination, (j_compress_ptr cinfo)); -}; - - -/* Data source object for decompression */ - -struct jpeg_source_mgr { - const JOCTET * next_input_byte; /* => next byte to read from buffer */ - size_t bytes_in_buffer; /* # of bytes remaining in buffer */ - - JMETHOD(void, init_source, (j_decompress_ptr cinfo)); - JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); - JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); - JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); - JMETHOD(void, term_source, (j_decompress_ptr cinfo)); -}; - - -/* Memory manager object. - * Allocates "small" objects (a few K total), "large" objects (tens of K), - * and "really big" objects (virtual arrays with backing store if needed). - * The memory manager does not allow individual objects to be freed; rather, - * each created object is assigned to a pool, and whole pools can be freed - * at once. This is faster and more convenient than remembering exactly what - * to free, especially where malloc()/free() are not too speedy. - * NB: alloc routines never return NULL. They exit to error_exit if not - * successful. - */ - -#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ -#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ -#define JPOOL_NUMPOOLS 2 - -typedef struct jvirt_sarray_control * jvirt_sarray_ptr; -typedef struct jvirt_barray_control * jvirt_barray_ptr; - - -struct jpeg_memory_mgr { - /* Method pointers */ - JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, - size_t sizeofobject)); - JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, - size_t sizeofobject)); - JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, - JDIMENSION samplesperrow, - JDIMENSION numrows)); - JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, - JDIMENSION blocksperrow, - JDIMENSION numrows)); - JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, - int pool_id, - boolean pre_zero, - JDIMENSION samplesperrow, - JDIMENSION numrows, - JDIMENSION maxaccess)); - JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, - int pool_id, - boolean pre_zero, - JDIMENSION blocksperrow, - JDIMENSION numrows, - JDIMENSION maxaccess)); - JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); - JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, - jvirt_sarray_ptr ptr, - JDIMENSION start_row, - JDIMENSION num_rows, - boolean writable)); - JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, - jvirt_barray_ptr ptr, - JDIMENSION start_row, - JDIMENSION num_rows, - boolean writable)); - JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); - JMETHOD(void, self_destruct, (j_common_ptr cinfo)); - - /* Limit on memory allocation for this JPEG object. (Note that this is - * merely advisory, not a guaranteed maximum; it only affects the space - * used for virtual-array buffers.) May be changed by outer application - * after creating the JPEG object. - */ - long max_memory_to_use; - - /* Maximum allocation request accepted by alloc_large. */ - long max_alloc_chunk; -}; - - -/* Routine signature for application-supplied marker processing methods. - * Need not pass marker code since it is stored in cinfo->unread_marker. - */ -typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); - - -/* Declarations for routines called by application. - * The JPP macro hides prototype parameters from compilers that can't cope. - * Note JPP requires double parentheses. - */ - -#ifdef HAVE_PROTOTYPES -#define JPP(arglist) arglist -#else -#define JPP(arglist) () -#endif - - -/* Short forms of external names for systems with brain-damaged linkers. - * We shorten external names to be unique in the first six letters, which - * is good enough for all known systems. - * (If your compiler itself needs names to be unique in less than 15 - * characters, you are out of luck. Get a better compiler.) - */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_std_error jStdError -#define jpeg_CreateCompress jCreaCompress -#define jpeg_CreateDecompress jCreaDecompress -#define jpeg_destroy_compress jDestCompress -#define jpeg_destroy_decompress jDestDecompress -#define jpeg_stdio_dest jStdDest -#define jpeg_stdio_src jStdSrc -#define jpeg_mem_dest jMemDest -#define jpeg_mem_src jMemSrc -#define jpeg_set_defaults jSetDefaults -#define jpeg_set_colorspace jSetColorspace -#define jpeg_default_colorspace jDefColorspace -#define jpeg_set_quality jSetQuality -#define jpeg_set_linear_quality jSetLQuality -#define jpeg_default_qtables jDefQTables -#define jpeg_add_quant_table jAddQuantTable -#define jpeg_quality_scaling jQualityScaling -#define jpeg_simple_progression jSimProgress -#define jpeg_suppress_tables jSuppressTables -#define jpeg_alloc_quant_table jAlcQTable -#define jpeg_alloc_huff_table jAlcHTable -#define jpeg_start_compress jStrtCompress -#define jpeg_write_scanlines jWrtScanlines -#define jpeg_finish_compress jFinCompress -#define jpeg_calc_jpeg_dimensions jCjpegDimensions -#define jpeg_write_raw_data jWrtRawData -#define jpeg_write_marker jWrtMarker -#define jpeg_write_m_header jWrtMHeader -#define jpeg_write_m_byte jWrtMByte -#define jpeg_write_tables jWrtTables -#define jpeg_read_header jReadHeader -#define jpeg_start_decompress jStrtDecompress -#define jpeg_read_scanlines jReadScanlines -#define jpeg_finish_decompress jFinDecompress -#define jpeg_read_raw_data jReadRawData -#define jpeg_has_multiple_scans jHasMultScn -#define jpeg_start_output jStrtOutput -#define jpeg_finish_output jFinOutput -#define jpeg_input_complete jInComplete -#define jpeg_new_colormap jNewCMap -#define jpeg_consume_input jConsumeInput -#define jpeg_core_output_dimensions jCoreDimensions -#define jpeg_calc_output_dimensions jCalcDimensions -#define jpeg_save_markers jSaveMarkers -#define jpeg_set_marker_processor jSetMarker -#define jpeg_read_coefficients jReadCoefs -#define jpeg_write_coefficients jWrtCoefs -#define jpeg_copy_critical_parameters jCopyCrit -#define jpeg_abort_compress jAbrtCompress -#define jpeg_abort_decompress jAbrtDecompress -#define jpeg_abort jAbort -#define jpeg_destroy jDestroy -#define jpeg_resync_to_restart jResyncRestart -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* Default error-management setup */ -EXTERN(struct jpeg_error_mgr *) jpeg_std_error - JPP((struct jpeg_error_mgr * err)); - -/* Initialization of JPEG compression objects. - * jpeg_create_compress() and jpeg_create_decompress() are the exported - * names that applications should call. These expand to calls on - * jpeg_CreateCompress and jpeg_CreateDecompress with additional information - * passed for version mismatch checking. - * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. - */ -#define jpeg_create_compress(cinfo) \ - jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ - (size_t) sizeof(struct jpeg_compress_struct)) -#define jpeg_create_decompress(cinfo) \ - jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ - (size_t) sizeof(struct jpeg_decompress_struct)) -EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, - int version, size_t structsize)); -EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, - int version, size_t structsize)); -/* Destruction of JPEG compression objects */ -EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); - -/* Standard data source and destination managers: stdio streams. */ -/* Caller is responsible for opening the file before and closing after. */ -EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); -EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); - -/* Data source and destination managers: memory buffers. */ -EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo, - unsigned char ** outbuffer, - unsigned long * outsize)); -EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, - const unsigned char * inbuffer, - unsigned long insize)); - -/* Default parameter setup for compression */ -EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); -/* Compression parameter setup aids */ -EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, - J_COLOR_SPACE colorspace)); -EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, - boolean force_baseline)); -EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, - int scale_factor, - boolean force_baseline)); -EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo, - boolean force_baseline)); -EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, - const unsigned int *basic_table, - int scale_factor, - boolean force_baseline)); -EXTERN(int) jpeg_quality_scaling JPP((int quality)); -EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, - boolean suppress)); -EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); -EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); - -/* Main entry points for compression */ -EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, - boolean write_all_tables)); -EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, - JSAMPARRAY scanlines, - JDIMENSION num_lines)); -EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); - -/* Precalculate JPEG dimensions for current compression parameters. */ -EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo)); - -/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ -EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, - JSAMPIMAGE data, - JDIMENSION num_lines)); - -/* Write a special marker. See libjpeg.txt concerning safe usage. */ -EXTERN(void) jpeg_write_marker - JPP((j_compress_ptr cinfo, int marker, - const JOCTET * dataptr, unsigned int datalen)); -/* Same, but piecemeal. */ -EXTERN(void) jpeg_write_m_header - JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); -EXTERN(void) jpeg_write_m_byte - JPP((j_compress_ptr cinfo, int val)); - -/* Alternate compression function: just write an abbreviated table file */ -EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); - -/* Decompression startup: read start of JPEG datastream to see what's there */ -EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, - boolean require_image)); -/* Return value is one of: */ -#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ -#define JPEG_HEADER_OK 1 /* Found valid image datastream */ -#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ -/* If you pass require_image = TRUE (normal case), you need not check for - * a TABLES_ONLY return code; an abbreviated file will cause an error exit. - * JPEG_SUSPENDED is only possible if you use a data source module that can - * give a suspension return (the stdio source module doesn't). - */ - -/* Main entry points for decompression */ -EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); -EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, - JSAMPARRAY scanlines, - JDIMENSION max_lines)); -EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); - -/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ -EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, - JSAMPIMAGE data, - JDIMENSION max_lines)); - -/* Additional entry points for buffered-image mode. */ -EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); -EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, - int scan_number)); -EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); -EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); -EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); -EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); -/* Return value is one of: */ -/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ -#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ -#define JPEG_REACHED_EOI 2 /* Reached end of image */ -#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ -#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ - -/* Precalculate output dimensions for current decompression parameters. */ -EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo)); -EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); - -/* Control saving of COM and APPn markers into marker_list. */ -EXTERN(void) jpeg_save_markers - JPP((j_decompress_ptr cinfo, int marker_code, - unsigned int length_limit)); - -/* Install a special processing method for COM or APPn markers. */ -EXTERN(void) jpeg_set_marker_processor - JPP((j_decompress_ptr cinfo, int marker_code, - jpeg_marker_parser_method routine)); - -/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ -EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); -EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, - jvirt_barray_ptr * coef_arrays)); -EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, - j_compress_ptr dstinfo)); - -/* If you choose to abort compression or decompression before completing - * jpeg_finish_(de)compress, then you need to clean up to release memory, - * temporary files, etc. You can just call jpeg_destroy_(de)compress - * if you're done with the JPEG object, but if you want to clean it up and - * reuse it, call this: - */ -EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); - -/* Generic versions of jpeg_abort and jpeg_destroy that work on either - * flavor of JPEG object. These may be more convenient in some places. - */ -EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); -EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); - -/* Default restart-marker-resync procedure for use by data source modules */ -EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, - int desired)); - - -/* These marker codes are exported since applications and data source modules - * are likely to want to use them. - */ - -#define JPEG_RST0 0xD0 /* RST0 marker code */ -#define JPEG_EOI 0xD9 /* EOI marker code */ -#define JPEG_APP0 0xE0 /* APP0 marker code */ -#define JPEG_COM 0xFE /* COM marker code */ - - -/* If we have a brain-damaged compiler that emits warnings (or worse, errors) - * for structure definitions that are never filled in, keep it quiet by - * supplying dummy definitions for the various substructures. - */ - -#ifdef INCOMPLETE_TYPES_BROKEN -#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ -struct jvirt_sarray_control { long dummy; }; -struct jvirt_barray_control { long dummy; }; -struct jpeg_comp_master { long dummy; }; -struct jpeg_c_main_controller { long dummy; }; -struct jpeg_c_prep_controller { long dummy; }; -struct jpeg_c_coef_controller { long dummy; }; -struct jpeg_marker_writer { long dummy; }; -struct jpeg_color_converter { long dummy; }; -struct jpeg_downsampler { long dummy; }; -struct jpeg_forward_dct { long dummy; }; -struct jpeg_entropy_encoder { long dummy; }; -struct jpeg_decomp_master { long dummy; }; -struct jpeg_d_main_controller { long dummy; }; -struct jpeg_d_coef_controller { long dummy; }; -struct jpeg_d_post_controller { long dummy; }; -struct jpeg_input_controller { long dummy; }; -struct jpeg_marker_reader { long dummy; }; -struct jpeg_entropy_decoder { long dummy; }; -struct jpeg_inverse_dct { long dummy; }; -struct jpeg_upsampler { long dummy; }; -struct jpeg_color_deconverter { long dummy; }; -struct jpeg_color_quantizer { long dummy; }; -#endif /* JPEG_INTERNALS */ -#endif /* INCOMPLETE_TYPES_BROKEN */ - - -/* - * The JPEG library modules define JPEG_INTERNALS before including this file. - * The internal structure declarations are read only when that is true. - * Applications using the library should not include jpegint.h, but may wish - * to include jerror.h. - */ - -#ifdef JPEG_INTERNALS -#include "jpegint.h" /* fetch private declarations */ -#include "jerror.h" /* fetch error codes too */ -#endif - -#ifdef __cplusplus -#ifndef DONT_USE_EXTERN_C -} -#endif -#endif - -#endif /* JPEGLIB_H */ diff --git a/libraries/jpeg/jquant1.c b/libraries/jpeg/jquant1.c deleted file mode 100644 index 9d11f70669b..00000000000 --- a/libraries/jpeg/jquant1.c +++ /dev/null @@ -1,857 +0,0 @@ -/* - * jquant1.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * Modified 2011 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains 1-pass color quantization (color mapping) routines. - * These routines provide mapping to a fixed color map using equally spaced - * color values. Optional Floyd-Steinberg or ordered dithering is available. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -#ifdef QUANT_1PASS_SUPPORTED - - -/* - * The main purpose of 1-pass quantization is to provide a fast, if not very - * high quality, colormapped output capability. A 2-pass quantizer usually - * gives better visual quality; however, for quantized grayscale output this - * quantizer is perfectly adequate. Dithering is highly recommended with this - * quantizer, though you can turn it off if you really want to. - * - * In 1-pass quantization the colormap must be chosen in advance of seeing the - * image. We use a map consisting of all combinations of Ncolors[i] color - * values for the i'th component. The Ncolors[] values are chosen so that - * their product, the total number of colors, is no more than that requested. - * (In most cases, the product will be somewhat less.) - * - * Since the colormap is orthogonal, the representative value for each color - * component can be determined without considering the other components; - * then these indexes can be combined into a colormap index by a standard - * N-dimensional-array-subscript calculation. Most of the arithmetic involved - * can be precalculated and stored in the lookup table colorindex[]. - * colorindex[i][j] maps pixel value j in component i to the nearest - * representative value (grid plane) for that component; this index is - * multiplied by the array stride for component i, so that the - * index of the colormap entry closest to a given pixel value is just - * sum( colorindex[component-number][pixel-component-value] ) - * Aside from being fast, this scheme allows for variable spacing between - * representative values with no additional lookup cost. - * - * If gamma correction has been applied in color conversion, it might be wise - * to adjust the color grid spacing so that the representative colors are - * equidistant in linear space. At this writing, gamma correction is not - * implemented by jdcolor, so nothing is done here. - */ - - -/* Declarations for ordered dithering. - * - * We use a standard 16x16 ordered dither array. The basic concept of ordered - * dithering is described in many references, for instance Dale Schumacher's - * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). - * In place of Schumacher's comparisons against a "threshold" value, we add a - * "dither" value to the input pixel and then round the result to the nearest - * output value. The dither value is equivalent to (0.5 - threshold) times - * the distance between output values. For ordered dithering, we assume that - * the output colors are equally spaced; if not, results will probably be - * worse, since the dither may be too much or too little at a given point. - * - * The normal calculation would be to form pixel value + dither, range-limit - * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. - * We can skip the separate range-limiting step by extending the colorindex - * table in both directions. - */ - -#define ODITHER_SIZE 16 /* dimension of dither matrix */ -/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ -#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ -#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ - -typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; -typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; - -static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { - /* Bayer's order-4 dither array. Generated by the code given in - * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. - * The values in this array must range from 0 to ODITHER_CELLS-1. - */ - { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, - { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, - { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, - { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, - { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, - { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, - { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, - { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, - { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, - { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, - { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, - { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, - { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, - { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, - { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, - { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } -}; - - -/* Declarations for Floyd-Steinberg dithering. - * - * Errors are accumulated into the array fserrors[], at a resolution of - * 1/16th of a pixel count. The error at a given pixel is propagated - * to its not-yet-processed neighbors using the standard F-S fractions, - * ... (here) 7/16 - * 3/16 5/16 1/16 - * We work left-to-right on even rows, right-to-left on odd rows. - * - * We can get away with a single array (holding one row's worth of errors) - * by using it to store the current row's errors at pixel columns not yet - * processed, but the next row's errors at columns already processed. We - * need only a few extra variables to hold the errors immediately around the - * current column. (If we are lucky, those variables are in registers, but - * even if not, they're probably cheaper to access than array elements are.) - * - * The fserrors[] array is indexed [component#][position]. - * We provide (#columns + 2) entries per component; the extra entry at each - * end saves us from special-casing the first and last pixels. - * - * Note: on a wide image, we might not have enough room in a PC's near data - * segment to hold the error array; so it is allocated with alloc_large. - */ - -#if BITS_IN_JSAMPLE == 8 -typedef INT16 FSERROR; /* 16 bits should be enough */ -typedef int LOCFSERROR; /* use 'int' for calculation temps */ -#else -typedef INT32 FSERROR; /* may need more than 16 bits */ -typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ -#endif - -typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ - - -/* Private subobject */ - -#define MAX_Q_COMPS 4 /* max components I can handle */ - -typedef struct { - struct jpeg_color_quantizer pub; /* public fields */ - - /* Initially allocated colormap is saved here */ - JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ - int sv_actual; /* number of entries in use */ - - JSAMPARRAY colorindex; /* Precomputed mapping for speed */ - /* colorindex[i][j] = index of color closest to pixel value j in component i, - * premultiplied as described above. Since colormap indexes must fit into - * JSAMPLEs, the entries of this array will too. - */ - boolean is_padded; /* is the colorindex padded for odither? */ - - int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ - - /* Variables for ordered dithering */ - int row_index; /* cur row's vertical index in dither matrix */ - ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ - - /* Variables for Floyd-Steinberg dithering */ - FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ - boolean on_odd_row; /* flag to remember which row we are on */ -} my_cquantizer; - -typedef my_cquantizer * my_cquantize_ptr; - - -/* - * Policy-making subroutines for create_colormap and create_colorindex. - * These routines determine the colormap to be used. The rest of the module - * only assumes that the colormap is orthogonal. - * - * * select_ncolors decides how to divvy up the available colors - * among the components. - * * output_value defines the set of representative values for a component. - * * largest_input_value defines the mapping from input values to - * representative values for a component. - * Note that the latter two routines may impose different policies for - * different components, though this is not currently done. - */ - - -LOCAL(int) -select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) -/* Determine allocation of desired colors to components, */ -/* and fill in Ncolors[] array to indicate choice. */ -/* Return value is total number of colors (product of Ncolors[] values). */ -{ - int nc = cinfo->out_color_components; /* number of color components */ - int max_colors = cinfo->desired_number_of_colors; - int total_colors, iroot, i, j; - boolean changed; - long temp; - static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; - - /* We can allocate at least the nc'th root of max_colors per component. */ - /* Compute floor(nc'th root of max_colors). */ - iroot = 1; - do { - iroot++; - temp = iroot; /* set temp = iroot ** nc */ - for (i = 1; i < nc; i++) - temp *= iroot; - } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ - iroot--; /* now iroot = floor(root) */ - - /* Must have at least 2 color values per component */ - if (iroot < 2) - ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); - - /* Initialize to iroot color values for each component */ - total_colors = 1; - for (i = 0; i < nc; i++) { - Ncolors[i] = iroot; - total_colors *= iroot; - } - /* We may be able to increment the count for one or more components without - * exceeding max_colors, though we know not all can be incremented. - * Sometimes, the first component can be incremented more than once! - * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) - * In RGB colorspace, try to increment G first, then R, then B. - */ - do { - changed = FALSE; - for (i = 0; i < nc; i++) { - j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); - /* calculate new total_colors if Ncolors[j] is incremented */ - temp = total_colors / Ncolors[j]; - temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ - if (temp > (long) max_colors) - break; /* won't fit, done with this pass */ - Ncolors[j]++; /* OK, apply the increment */ - total_colors = (int) temp; - changed = TRUE; - } - } while (changed); - - return total_colors; -} - - -LOCAL(int) -output_value (j_decompress_ptr cinfo, int ci, int j, int maxj) -/* Return j'th output value, where j will range from 0 to maxj */ -/* The output values must fall in 0..MAXJSAMPLE in increasing order */ -{ - /* We always provide values 0 and MAXJSAMPLE for each component; - * any additional values are equally spaced between these limits. - * (Forcing the upper and lower values to the limits ensures that - * dithering can't produce a color outside the selected gamut.) - */ - return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); -} - - -LOCAL(int) -largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj) -/* Return largest input value that should map to j'th output value */ -/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ -{ - /* Breakpoints are halfway between values returned by output_value */ - return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); -} - - -/* - * Create the colormap. - */ - -LOCAL(void) -create_colormap (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - JSAMPARRAY colormap; /* Created colormap */ - int total_colors; /* Number of distinct output colors */ - int i,j,k, nci, blksize, blkdist, ptr, val; - - /* Select number of colors for each component */ - total_colors = select_ncolors(cinfo, cquantize->Ncolors); - - /* Report selected color counts */ - if (cinfo->out_color_components == 3) - TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, - total_colors, cquantize->Ncolors[0], - cquantize->Ncolors[1], cquantize->Ncolors[2]); - else - TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); - - /* Allocate and fill in the colormap. */ - /* The colors are ordered in the map in standard row-major order, */ - /* i.e. rightmost (highest-indexed) color changes most rapidly. */ - - colormap = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); - - /* blksize is number of adjacent repeated entries for a component */ - /* blkdist is distance between groups of identical entries for a component */ - blkdist = total_colors; - - for (i = 0; i < cinfo->out_color_components; i++) { - /* fill in colormap entries for i'th color component */ - nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ - blksize = blkdist / nci; - for (j = 0; j < nci; j++) { - /* Compute j'th output value (out of nci) for component */ - val = output_value(cinfo, i, j, nci-1); - /* Fill in all colormap entries that have this value of this component */ - for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { - /* fill in blksize entries beginning at ptr */ - for (k = 0; k < blksize; k++) - colormap[i][ptr+k] = (JSAMPLE) val; - } - } - blkdist = blksize; /* blksize of this color is blkdist of next */ - } - - /* Save the colormap in private storage, - * where it will survive color quantization mode changes. - */ - cquantize->sv_colormap = colormap; - cquantize->sv_actual = total_colors; -} - - -/* - * Create the color index table. - */ - -LOCAL(void) -create_colorindex (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - JSAMPROW indexptr; - int i,j,k, nci, blksize, val, pad; - - /* For ordered dither, we pad the color index tables by MAXJSAMPLE in - * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). - * This is not necessary in the other dithering modes. However, we - * flag whether it was done in case user changes dithering mode. - */ - if (cinfo->dither_mode == JDITHER_ORDERED) { - pad = MAXJSAMPLE*2; - cquantize->is_padded = TRUE; - } else { - pad = 0; - cquantize->is_padded = FALSE; - } - - cquantize->colorindex = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (JDIMENSION) (MAXJSAMPLE+1 + pad), - (JDIMENSION) cinfo->out_color_components); - - /* blksize is number of adjacent repeated entries for a component */ - blksize = cquantize->sv_actual; - - for (i = 0; i < cinfo->out_color_components; i++) { - /* fill in colorindex entries for i'th color component */ - nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ - blksize = blksize / nci; - - /* adjust colorindex pointers to provide padding at negative indexes. */ - if (pad) - cquantize->colorindex[i] += MAXJSAMPLE; - - /* in loop, val = index of current output value, */ - /* and k = largest j that maps to current val */ - indexptr = cquantize->colorindex[i]; - val = 0; - k = largest_input_value(cinfo, i, 0, nci-1); - for (j = 0; j <= MAXJSAMPLE; j++) { - while (j > k) /* advance val if past boundary */ - k = largest_input_value(cinfo, i, ++val, nci-1); - /* premultiply so that no multiplication needed in main processing */ - indexptr[j] = (JSAMPLE) (val * blksize); - } - /* Pad at both ends if necessary */ - if (pad) - for (j = 1; j <= MAXJSAMPLE; j++) { - indexptr[-j] = indexptr[0]; - indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; - } - } -} - - -/* - * Create an ordered-dither array for a component having ncolors - * distinct output values. - */ - -LOCAL(ODITHER_MATRIX_PTR) -make_odither_array (j_decompress_ptr cinfo, int ncolors) -{ - ODITHER_MATRIX_PTR odither; - int j,k; - INT32 num,den; - - odither = (ODITHER_MATRIX_PTR) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(ODITHER_MATRIX)); - /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). - * Hence the dither value for the matrix cell with fill order f - * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). - * On 16-bit-int machine, be careful to avoid overflow. - */ - den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); - for (j = 0; j < ODITHER_SIZE; j++) { - for (k = 0; k < ODITHER_SIZE; k++) { - num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) - * MAXJSAMPLE; - /* Ensure round towards zero despite C's lack of consistency - * about rounding negative values in integer division... - */ - odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); - } - } - return odither; -} - - -/* - * Create the ordered-dither tables. - * Components having the same number of representative colors may - * share a dither table. - */ - -LOCAL(void) -create_odither_tables (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - ODITHER_MATRIX_PTR odither; - int i, j, nci; - - for (i = 0; i < cinfo->out_color_components; i++) { - nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ - odither = NULL; /* search for matching prior component */ - for (j = 0; j < i; j++) { - if (nci == cquantize->Ncolors[j]) { - odither = cquantize->odither[j]; - break; - } - } - if (odither == NULL) /* need a new table? */ - odither = make_odither_array(cinfo, nci); - cquantize->odither[i] = odither; - } -} - - -/* - * Map some rows of pixels to the output colormapped representation. - */ - -METHODDEF(void) -color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* General case, no dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - JSAMPARRAY colorindex = cquantize->colorindex; - register int pixcode, ci; - register JSAMPROW ptrin, ptrout; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - register int nc = cinfo->out_color_components; - - for (row = 0; row < num_rows; row++) { - ptrin = input_buf[row]; - ptrout = output_buf[row]; - for (col = width; col > 0; col--) { - pixcode = 0; - for (ci = 0; ci < nc; ci++) { - pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); - } - *ptrout++ = (JSAMPLE) pixcode; - } - } -} - - -METHODDEF(void) -color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* Fast path for out_color_components==3, no dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - register int pixcode; - register JSAMPROW ptrin, ptrout; - JSAMPROW colorindex0 = cquantize->colorindex[0]; - JSAMPROW colorindex1 = cquantize->colorindex[1]; - JSAMPROW colorindex2 = cquantize->colorindex[2]; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - ptrin = input_buf[row]; - ptrout = output_buf[row]; - for (col = width; col > 0; col--) { - pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); - pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); - pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); - *ptrout++ = (JSAMPLE) pixcode; - } - } -} - - -METHODDEF(void) -quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* General case, with ordered dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - register JSAMPROW input_ptr; - register JSAMPROW output_ptr; - JSAMPROW colorindex_ci; - int * dither; /* points to active row of dither matrix */ - int row_index, col_index; /* current indexes into dither matrix */ - int nc = cinfo->out_color_components; - int ci; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - /* Initialize output values to 0 so can process components separately */ - FMEMZERO((void FAR *) output_buf[row], - (size_t) (width * SIZEOF(JSAMPLE))); - row_index = cquantize->row_index; - for (ci = 0; ci < nc; ci++) { - input_ptr = input_buf[row] + ci; - output_ptr = output_buf[row]; - colorindex_ci = cquantize->colorindex[ci]; - dither = cquantize->odither[ci][row_index]; - col_index = 0; - - for (col = width; col > 0; col--) { - /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, - * select output value, accumulate into output code for this pixel. - * Range-limiting need not be done explicitly, as we have extended - * the colorindex table to produce the right answers for out-of-range - * inputs. The maximum dither is +- MAXJSAMPLE; this sets the - * required amount of padding. - */ - *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; - input_ptr += nc; - output_ptr++; - col_index = (col_index + 1) & ODITHER_MASK; - } - } - /* Advance row index for next row */ - row_index = (row_index + 1) & ODITHER_MASK; - cquantize->row_index = row_index; - } -} - - -METHODDEF(void) -quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* Fast path for out_color_components==3, with ordered dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - register int pixcode; - register JSAMPROW input_ptr; - register JSAMPROW output_ptr; - JSAMPROW colorindex0 = cquantize->colorindex[0]; - JSAMPROW colorindex1 = cquantize->colorindex[1]; - JSAMPROW colorindex2 = cquantize->colorindex[2]; - int * dither0; /* points to active row of dither matrix */ - int * dither1; - int * dither2; - int row_index, col_index; /* current indexes into dither matrix */ - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - row_index = cquantize->row_index; - input_ptr = input_buf[row]; - output_ptr = output_buf[row]; - dither0 = cquantize->odither[0][row_index]; - dither1 = cquantize->odither[1][row_index]; - dither2 = cquantize->odither[2][row_index]; - col_index = 0; - - for (col = width; col > 0; col--) { - pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + - dither0[col_index]]); - pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + - dither1[col_index]]); - pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + - dither2[col_index]]); - *output_ptr++ = (JSAMPLE) pixcode; - col_index = (col_index + 1) & ODITHER_MASK; - } - row_index = (row_index + 1) & ODITHER_MASK; - cquantize->row_index = row_index; - } -} - - -METHODDEF(void) -quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* General case, with Floyd-Steinberg dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - register LOCFSERROR cur; /* current error or pixel value */ - LOCFSERROR belowerr; /* error for pixel below cur */ - LOCFSERROR bpreverr; /* error for below/prev col */ - LOCFSERROR bnexterr; /* error for below/next col */ - LOCFSERROR delta; - register FSERRPTR errorptr; /* => fserrors[] at column before current */ - register JSAMPROW input_ptr; - register JSAMPROW output_ptr; - JSAMPROW colorindex_ci; - JSAMPROW colormap_ci; - int pixcode; - int nc = cinfo->out_color_components; - int dir; /* 1 for left-to-right, -1 for right-to-left */ - int dirnc; /* dir * nc */ - int ci; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - JSAMPLE *range_limit = cinfo->sample_range_limit; - SHIFT_TEMPS - - for (row = 0; row < num_rows; row++) { - /* Initialize output values to 0 so can process components separately */ - FMEMZERO((void FAR *) output_buf[row], - (size_t) (width * SIZEOF(JSAMPLE))); - for (ci = 0; ci < nc; ci++) { - input_ptr = input_buf[row] + ci; - output_ptr = output_buf[row]; - if (cquantize->on_odd_row) { - /* work right to left in this row */ - input_ptr += (width-1) * nc; /* so point to rightmost pixel */ - output_ptr += width-1; - dir = -1; - dirnc = -nc; - errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ - } else { - /* work left to right in this row */ - dir = 1; - dirnc = nc; - errorptr = cquantize->fserrors[ci]; /* => entry before first column */ - } - colorindex_ci = cquantize->colorindex[ci]; - colormap_ci = cquantize->sv_colormap[ci]; - /* Preset error values: no error propagated to first pixel from left */ - cur = 0; - /* and no error propagated to row below yet */ - belowerr = bpreverr = 0; - - for (col = width; col > 0; col--) { - /* cur holds the error propagated from the previous pixel on the - * current line. Add the error propagated from the previous line - * to form the complete error correction term for this pixel, and - * round the error term (which is expressed * 16) to an integer. - * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct - * for either sign of the error value. - * Note: errorptr points to *previous* column's array entry. - */ - cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); - /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. - * The maximum error is +- MAXJSAMPLE; this sets the required size - * of the range_limit array. - */ - cur += GETJSAMPLE(*input_ptr); - cur = GETJSAMPLE(range_limit[cur]); - /* Select output value, accumulate into output code for this pixel */ - pixcode = GETJSAMPLE(colorindex_ci[cur]); - *output_ptr += (JSAMPLE) pixcode; - /* Compute actual representation error at this pixel */ - /* Note: we can do this even though we don't have the final */ - /* pixel code, because the colormap is orthogonal. */ - cur -= GETJSAMPLE(colormap_ci[pixcode]); - /* Compute error fractions to be propagated to adjacent pixels. - * Add these into the running sums, and simultaneously shift the - * next-line error sums left by 1 column. - */ - bnexterr = cur; - delta = cur * 2; - cur += delta; /* form error * 3 */ - errorptr[0] = (FSERROR) (bpreverr + cur); - cur += delta; /* form error * 5 */ - bpreverr = belowerr + cur; - belowerr = bnexterr; - cur += delta; /* form error * 7 */ - /* At this point cur contains the 7/16 error value to be propagated - * to the next pixel on the current line, and all the errors for the - * next line have been shifted over. We are therefore ready to move on. - */ - input_ptr += dirnc; /* advance input ptr to next column */ - output_ptr += dir; /* advance output ptr to next column */ - errorptr += dir; /* advance errorptr to current column */ - } - /* Post-loop cleanup: we must unload the final error value into the - * final fserrors[] entry. Note we need not unload belowerr because - * it is for the dummy column before or after the actual array. - */ - errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ - } - cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); - } -} - - -/* - * Allocate workspace for Floyd-Steinberg errors. - */ - -LOCAL(void) -alloc_fs_workspace (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - size_t arraysize; - int i; - - arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); - for (i = 0; i < cinfo->out_color_components; i++) { - cquantize->fserrors[i] = (FSERRPTR) - (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); - } -} - - -/* - * Initialize for one-pass color quantization. - */ - -METHODDEF(void) -start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - size_t arraysize; - int i; - - /* Install my colormap. */ - cinfo->colormap = cquantize->sv_colormap; - cinfo->actual_number_of_colors = cquantize->sv_actual; - - /* Initialize for desired dithering mode. */ - switch (cinfo->dither_mode) { - case JDITHER_NONE: - if (cinfo->out_color_components == 3) - cquantize->pub.color_quantize = color_quantize3; - else - cquantize->pub.color_quantize = color_quantize; - break; - case JDITHER_ORDERED: - if (cinfo->out_color_components == 3) - cquantize->pub.color_quantize = quantize3_ord_dither; - else - cquantize->pub.color_quantize = quantize_ord_dither; - cquantize->row_index = 0; /* initialize state for ordered dither */ - /* If user changed to ordered dither from another mode, - * we must recreate the color index table with padding. - * This will cost extra space, but probably isn't very likely. - */ - if (! cquantize->is_padded) - create_colorindex(cinfo); - /* Create ordered-dither tables if we didn't already. */ - if (cquantize->odither[0] == NULL) - create_odither_tables(cinfo); - break; - case JDITHER_FS: - cquantize->pub.color_quantize = quantize_fs_dither; - cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ - /* Allocate Floyd-Steinberg workspace if didn't already. */ - if (cquantize->fserrors[0] == NULL) - alloc_fs_workspace(cinfo); - /* Initialize the propagated errors to zero. */ - arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); - for (i = 0; i < cinfo->out_color_components; i++) - FMEMZERO((void FAR *) cquantize->fserrors[i], arraysize); - break; - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - break; - } -} - - -/* - * Finish up at the end of the pass. - */ - -METHODDEF(void) -finish_pass_1_quant (j_decompress_ptr cinfo) -{ - /* no work in 1-pass case */ -} - - -/* - * Switch to a new external colormap between output passes. - * Shouldn't get to this module! - */ - -METHODDEF(void) -new_color_map_1_quant (j_decompress_ptr cinfo) -{ - ERREXIT(cinfo, JERR_MODE_CHANGE); -} - - -/* - * Module initialization routine for 1-pass color quantization. - */ - -GLOBAL(void) -jinit_1pass_quantizer (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize; - - cquantize = (my_cquantize_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_cquantizer)); - cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; - cquantize->pub.start_pass = start_pass_1_quant; - cquantize->pub.finish_pass = finish_pass_1_quant; - cquantize->pub.new_color_map = new_color_map_1_quant; - cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ - cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ - - /* Make sure my internal arrays won't overflow */ - if (cinfo->out_color_components > MAX_Q_COMPS) - ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); - /* Make sure colormap indexes can be represented by JSAMPLEs */ - if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) - ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); - - /* Create the colormap and color index table. */ - create_colormap(cinfo); - create_colorindex(cinfo); - - /* Allocate Floyd-Steinberg workspace now if requested. - * We do this now since it is FAR storage and may affect the memory - * manager's space calculations. If the user changes to FS dither - * mode in a later pass, we will allocate the space then, and will - * possibly overrun the max_memory_to_use setting. - */ - if (cinfo->dither_mode == JDITHER_FS) - alloc_fs_workspace(cinfo); -} - -#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/libraries/jpeg/jquant2.c b/libraries/jpeg/jquant2.c deleted file mode 100644 index 38fc2af7a55..00000000000 --- a/libraries/jpeg/jquant2.c +++ /dev/null @@ -1,1311 +0,0 @@ -/* - * jquant2.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * Modified 2011 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains 2-pass color quantization (color mapping) routines. - * These routines provide selection of a custom color map for an image, - * followed by mapping of the image to that color map, with optional - * Floyd-Steinberg dithering. - * It is also possible to use just the second pass to map to an arbitrary - * externally-given color map. - * - * Note: ordered dithering is not supported, since there isn't any fast - * way to compute intercolor distances; it's unclear that ordered dither's - * fundamental assumptions even hold with an irregularly spaced color map. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -#ifdef QUANT_2PASS_SUPPORTED - - -/* - * This module implements the well-known Heckbert paradigm for color - * quantization. Most of the ideas used here can be traced back to - * Heckbert's seminal paper - * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", - * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. - * - * In the first pass over the image, we accumulate a histogram showing the - * usage count of each possible color. To keep the histogram to a reasonable - * size, we reduce the precision of the input; typical practice is to retain - * 5 or 6 bits per color, so that 8 or 4 different input values are counted - * in the same histogram cell. - * - * Next, the color-selection step begins with a box representing the whole - * color space, and repeatedly splits the "largest" remaining box until we - * have as many boxes as desired colors. Then the mean color in each - * remaining box becomes one of the possible output colors. - * - * The second pass over the image maps each input pixel to the closest output - * color (optionally after applying a Floyd-Steinberg dithering correction). - * This mapping is logically trivial, but making it go fast enough requires - * considerable care. - * - * Heckbert-style quantizers vary a good deal in their policies for choosing - * the "largest" box and deciding where to cut it. The particular policies - * used here have proved out well in experimental comparisons, but better ones - * may yet be found. - * - * In earlier versions of the IJG code, this module quantized in YCbCr color - * space, processing the raw upsampled data without a color conversion step. - * This allowed the color conversion math to be done only once per colormap - * entry, not once per pixel. However, that optimization precluded other - * useful optimizations (such as merging color conversion with upsampling) - * and it also interfered with desired capabilities such as quantizing to an - * externally-supplied colormap. We have therefore abandoned that approach. - * The present code works in the post-conversion color space, typically RGB. - * - * To improve the visual quality of the results, we actually work in scaled - * RGB space, giving G distances more weight than R, and R in turn more than - * B. To do everything in integer math, we must use integer scale factors. - * The 2/3/1 scale factors used here correspond loosely to the relative - * weights of the colors in the NTSC grayscale equation. - * If you want to use this code to quantize a non-RGB color space, you'll - * probably need to change these scale factors. - */ - -#define R_SCALE 2 /* scale R distances by this much */ -#define G_SCALE 3 /* scale G distances by this much */ -#define B_SCALE 1 /* and B by this much */ - -/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined - * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B - * and B,G,R orders. If you define some other weird order in jmorecfg.h, - * you'll get compile errors until you extend this logic. In that case - * you'll probably want to tweak the histogram sizes too. - */ - -#if RGB_RED == 0 -#define C0_SCALE R_SCALE -#endif -#if RGB_BLUE == 0 -#define C0_SCALE B_SCALE -#endif -#if RGB_GREEN == 1 -#define C1_SCALE G_SCALE -#endif -#if RGB_RED == 2 -#define C2_SCALE R_SCALE -#endif -#if RGB_BLUE == 2 -#define C2_SCALE B_SCALE -#endif - - -/* - * First we have the histogram data structure and routines for creating it. - * - * The number of bits of precision can be adjusted by changing these symbols. - * We recommend keeping 6 bits for G and 5 each for R and B. - * If you have plenty of memory and cycles, 6 bits all around gives marginally - * better results; if you are short of memory, 5 bits all around will save - * some space but degrade the results. - * To maintain a fully accurate histogram, we'd need to allocate a "long" - * (preferably unsigned long) for each cell. In practice this is overkill; - * we can get by with 16 bits per cell. Few of the cell counts will overflow, - * and clamping those that do overflow to the maximum value will give close- - * enough results. This reduces the recommended histogram size from 256Kb - * to 128Kb, which is a useful savings on PC-class machines. - * (In the second pass the histogram space is re-used for pixel mapping data; - * in that capacity, each cell must be able to store zero to the number of - * desired colors. 16 bits/cell is plenty for that too.) - * Since the JPEG code is intended to run in small memory model on 80x86 - * machines, we can't just allocate the histogram in one chunk. Instead - * of a true 3-D array, we use a row of pointers to 2-D arrays. Each - * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and - * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that - * on 80x86 machines, the pointer row is in near memory but the actual - * arrays are in far memory (same arrangement as we use for image arrays). - */ - -#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ - -/* These will do the right thing for either R,G,B or B,G,R color order, - * but you may not like the results for other color orders. - */ -#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ -#define HIST_C1_BITS 6 /* bits of precision in G histogram */ -#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ - -/* Number of elements along histogram axes. */ -#define HIST_C0_ELEMS (1<cquantize; - register JSAMPROW ptr; - register histptr histp; - register hist3d histogram = cquantize->histogram; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - ptr = input_buf[row]; - for (col = width; col > 0; col--) { - /* get pixel value and index into the histogram */ - histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] - [GETJSAMPLE(ptr[1]) >> C1_SHIFT] - [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; - /* increment, check for overflow and undo increment if so. */ - if (++(*histp) <= 0) - (*histp)--; - ptr += 3; - } - } -} - - -/* - * Next we have the really interesting routines: selection of a colormap - * given the completed histogram. - * These routines work with a list of "boxes", each representing a rectangular - * subset of the input color space (to histogram precision). - */ - -typedef struct { - /* The bounds of the box (inclusive); expressed as histogram indexes */ - int c0min, c0max; - int c1min, c1max; - int c2min, c2max; - /* The volume (actually 2-norm) of the box */ - INT32 volume; - /* The number of nonzero histogram cells within this box */ - long colorcount; -} box; - -typedef box * boxptr; - - -LOCAL(boxptr) -find_biggest_color_pop (boxptr boxlist, int numboxes) -/* Find the splittable box with the largest color population */ -/* Returns NULL if no splittable boxes remain */ -{ - register boxptr boxp; - register int i; - register long maxc = 0; - boxptr which = NULL; - - for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { - if (boxp->colorcount > maxc && boxp->volume > 0) { - which = boxp; - maxc = boxp->colorcount; - } - } - return which; -} - - -LOCAL(boxptr) -find_biggest_volume (boxptr boxlist, int numboxes) -/* Find the splittable box with the largest (scaled) volume */ -/* Returns NULL if no splittable boxes remain */ -{ - register boxptr boxp; - register int i; - register INT32 maxv = 0; - boxptr which = NULL; - - for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { - if (boxp->volume > maxv) { - which = boxp; - maxv = boxp->volume; - } - } - return which; -} - - -LOCAL(void) -update_box (j_decompress_ptr cinfo, boxptr boxp) -/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ -/* and recompute its volume and population */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - histptr histp; - int c0,c1,c2; - int c0min,c0max,c1min,c1max,c2min,c2max; - INT32 dist0,dist1,dist2; - long ccount; - - c0min = boxp->c0min; c0max = boxp->c0max; - c1min = boxp->c1min; c1max = boxp->c1max; - c2min = boxp->c2min; c2max = boxp->c2max; - - if (c0max > c0min) - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c0min = c0min = c0; - goto have_c0min; - } - } - have_c0min: - if (c0max > c0min) - for (c0 = c0max; c0 >= c0min; c0--) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c0max = c0max = c0; - goto have_c0max; - } - } - have_c0max: - if (c1max > c1min) - for (c1 = c1min; c1 <= c1max; c1++) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c1min = c1min = c1; - goto have_c1min; - } - } - have_c1min: - if (c1max > c1min) - for (c1 = c1max; c1 >= c1min; c1--) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c1max = c1max = c1; - goto have_c1max; - } - } - have_c1max: - if (c2max > c2min) - for (c2 = c2min; c2 <= c2max; c2++) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1min][c2]; - for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) - if (*histp != 0) { - boxp->c2min = c2min = c2; - goto have_c2min; - } - } - have_c2min: - if (c2max > c2min) - for (c2 = c2max; c2 >= c2min; c2--) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1min][c2]; - for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) - if (*histp != 0) { - boxp->c2max = c2max = c2; - goto have_c2max; - } - } - have_c2max: - - /* Update box volume. - * We use 2-norm rather than real volume here; this biases the method - * against making long narrow boxes, and it has the side benefit that - * a box is splittable iff norm > 0. - * Since the differences are expressed in histogram-cell units, - * we have to shift back to JSAMPLE units to get consistent distances; - * after which, we scale according to the selected distance scale factors. - */ - dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; - dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; - dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; - boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; - - /* Now scan remaining volume of box and compute population */ - ccount = 0; - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++, histp++) - if (*histp != 0) { - ccount++; - } - } - boxp->colorcount = ccount; -} - - -LOCAL(int) -median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, - int desired_colors) -/* Repeatedly select and split the largest box until we have enough boxes */ -{ - int n,lb; - int c0,c1,c2,cmax; - register boxptr b1,b2; - - while (numboxes < desired_colors) { - /* Select box to split. - * Current algorithm: by population for first half, then by volume. - */ - if (numboxes*2 <= desired_colors) { - b1 = find_biggest_color_pop(boxlist, numboxes); - } else { - b1 = find_biggest_volume(boxlist, numboxes); - } - if (b1 == NULL) /* no splittable boxes left! */ - break; - b2 = &boxlist[numboxes]; /* where new box will go */ - /* Copy the color bounds to the new box. */ - b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; - b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; - /* Choose which axis to split the box on. - * Current algorithm: longest scaled axis. - * See notes in update_box about scaling distances. - */ - c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; - c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; - c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; - /* We want to break any ties in favor of green, then red, blue last. - * This code does the right thing for R,G,B or B,G,R color orders only. - */ -#if RGB_RED == 0 - cmax = c1; n = 1; - if (c0 > cmax) { cmax = c0; n = 0; } - if (c2 > cmax) { n = 2; } -#else - cmax = c1; n = 1; - if (c2 > cmax) { cmax = c2; n = 2; } - if (c0 > cmax) { n = 0; } -#endif - /* Choose split point along selected axis, and update box bounds. - * Current algorithm: split at halfway point. - * (Since the box has been shrunk to minimum volume, - * any split will produce two nonempty subboxes.) - * Note that lb value is max for lower box, so must be < old max. - */ - switch (n) { - case 0: - lb = (b1->c0max + b1->c0min) / 2; - b1->c0max = lb; - b2->c0min = lb+1; - break; - case 1: - lb = (b1->c1max + b1->c1min) / 2; - b1->c1max = lb; - b2->c1min = lb+1; - break; - case 2: - lb = (b1->c2max + b1->c2min) / 2; - b1->c2max = lb; - b2->c2min = lb+1; - break; - } - /* Update stats for boxes */ - update_box(cinfo, b1); - update_box(cinfo, b2); - numboxes++; - } - return numboxes; -} - - -LOCAL(void) -compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) -/* Compute representative color for a box, put it in colormap[icolor] */ -{ - /* Current algorithm: mean weighted by pixels (not colors) */ - /* Note it is important to get the rounding correct! */ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - histptr histp; - int c0,c1,c2; - int c0min,c0max,c1min,c1max,c2min,c2max; - long count; - long total = 0; - long c0total = 0; - long c1total = 0; - long c2total = 0; - - c0min = boxp->c0min; c0max = boxp->c0max; - c1min = boxp->c1min; c1max = boxp->c1max; - c2min = boxp->c2min; c2max = boxp->c2max; - - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) { - if ((count = *histp++) != 0) { - total += count; - c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; - c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; - c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; - } - } - } - - cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); - cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); - cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); -} - - -LOCAL(void) -select_colors (j_decompress_ptr cinfo, int desired_colors) -/* Master routine for color selection */ -{ - boxptr boxlist; - int numboxes; - int i; - - /* Allocate workspace for box list */ - boxlist = (boxptr) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); - /* Initialize one box containing whole space */ - numboxes = 1; - boxlist[0].c0min = 0; - boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; - boxlist[0].c1min = 0; - boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; - boxlist[0].c2min = 0; - boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; - /* Shrink it to actually-used volume and set its statistics */ - update_box(cinfo, & boxlist[0]); - /* Perform median-cut to produce final box list */ - numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); - /* Compute the representative color for each box, fill colormap */ - for (i = 0; i < numboxes; i++) - compute_color(cinfo, & boxlist[i], i); - cinfo->actual_number_of_colors = numboxes; - TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); -} - - -/* - * These routines are concerned with the time-critical task of mapping input - * colors to the nearest color in the selected colormap. - * - * We re-use the histogram space as an "inverse color map", essentially a - * cache for the results of nearest-color searches. All colors within a - * histogram cell will be mapped to the same colormap entry, namely the one - * closest to the cell's center. This may not be quite the closest entry to - * the actual input color, but it's almost as good. A zero in the cache - * indicates we haven't found the nearest color for that cell yet; the array - * is cleared to zeroes before starting the mapping pass. When we find the - * nearest color for a cell, its colormap index plus one is recorded in the - * cache for future use. The pass2 scanning routines call fill_inverse_cmap - * when they need to use an unfilled entry in the cache. - * - * Our method of efficiently finding nearest colors is based on the "locally - * sorted search" idea described by Heckbert and on the incremental distance - * calculation described by Spencer W. Thomas in chapter III.1 of Graphics - * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that - * the distances from a given colormap entry to each cell of the histogram can - * be computed quickly using an incremental method: the differences between - * distances to adjacent cells themselves differ by a constant. This allows a - * fairly fast implementation of the "brute force" approach of computing the - * distance from every colormap entry to every histogram cell. Unfortunately, - * it needs a work array to hold the best-distance-so-far for each histogram - * cell (because the inner loop has to be over cells, not colormap entries). - * The work array elements have to be INT32s, so the work array would need - * 256Kb at our recommended precision. This is not feasible in DOS machines. - * - * To get around these problems, we apply Thomas' method to compute the - * nearest colors for only the cells within a small subbox of the histogram. - * The work array need be only as big as the subbox, so the memory usage - * problem is solved. Furthermore, we need not fill subboxes that are never - * referenced in pass2; many images use only part of the color gamut, so a - * fair amount of work is saved. An additional advantage of this - * approach is that we can apply Heckbert's locality criterion to quickly - * eliminate colormap entries that are far away from the subbox; typically - * three-fourths of the colormap entries are rejected by Heckbert's criterion, - * and we need not compute their distances to individual cells in the subbox. - * The speed of this approach is heavily influenced by the subbox size: too - * small means too much overhead, too big loses because Heckbert's criterion - * can't eliminate as many colormap entries. Empirically the best subbox - * size seems to be about 1/512th of the histogram (1/8th in each direction). - * - * Thomas' article also describes a refined method which is asymptotically - * faster than the brute-force method, but it is also far more complex and - * cannot efficiently be applied to small subboxes. It is therefore not - * useful for programs intended to be portable to DOS machines. On machines - * with plenty of memory, filling the whole histogram in one shot with Thomas' - * refined method might be faster than the present code --- but then again, - * it might not be any faster, and it's certainly more complicated. - */ - - -/* log2(histogram cells in update box) for each axis; this can be adjusted */ -#define BOX_C0_LOG (HIST_C0_BITS-3) -#define BOX_C1_LOG (HIST_C1_BITS-3) -#define BOX_C2_LOG (HIST_C2_BITS-3) - -#define BOX_C0_ELEMS (1<actual_number_of_colors; - int maxc0, maxc1, maxc2; - int centerc0, centerc1, centerc2; - int i, x, ncolors; - INT32 minmaxdist, min_dist, max_dist, tdist; - INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ - - /* Compute true coordinates of update box's upper corner and center. - * Actually we compute the coordinates of the center of the upper-corner - * histogram cell, which are the upper bounds of the volume we care about. - * Note that since ">>" rounds down, the "center" values may be closer to - * min than to max; hence comparisons to them must be "<=", not "<". - */ - maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); - centerc0 = (minc0 + maxc0) >> 1; - maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); - centerc1 = (minc1 + maxc1) >> 1; - maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); - centerc2 = (minc2 + maxc2) >> 1; - - /* For each color in colormap, find: - * 1. its minimum squared-distance to any point in the update box - * (zero if color is within update box); - * 2. its maximum squared-distance to any point in the update box. - * Both of these can be found by considering only the corners of the box. - * We save the minimum distance for each color in mindist[]; - * only the smallest maximum distance is of interest. - */ - minmaxdist = 0x7FFFFFFFL; - - for (i = 0; i < numcolors; i++) { - /* We compute the squared-c0-distance term, then add in the other two. */ - x = GETJSAMPLE(cinfo->colormap[0][i]); - if (x < minc0) { - tdist = (x - minc0) * C0_SCALE; - min_dist = tdist*tdist; - tdist = (x - maxc0) * C0_SCALE; - max_dist = tdist*tdist; - } else if (x > maxc0) { - tdist = (x - maxc0) * C0_SCALE; - min_dist = tdist*tdist; - tdist = (x - minc0) * C0_SCALE; - max_dist = tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - min_dist = 0; - if (x <= centerc0) { - tdist = (x - maxc0) * C0_SCALE; - max_dist = tdist*tdist; - } else { - tdist = (x - minc0) * C0_SCALE; - max_dist = tdist*tdist; - } - } - - x = GETJSAMPLE(cinfo->colormap[1][i]); - if (x < minc1) { - tdist = (x - minc1) * C1_SCALE; - min_dist += tdist*tdist; - tdist = (x - maxc1) * C1_SCALE; - max_dist += tdist*tdist; - } else if (x > maxc1) { - tdist = (x - maxc1) * C1_SCALE; - min_dist += tdist*tdist; - tdist = (x - minc1) * C1_SCALE; - max_dist += tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - if (x <= centerc1) { - tdist = (x - maxc1) * C1_SCALE; - max_dist += tdist*tdist; - } else { - tdist = (x - minc1) * C1_SCALE; - max_dist += tdist*tdist; - } - } - - x = GETJSAMPLE(cinfo->colormap[2][i]); - if (x < minc2) { - tdist = (x - minc2) * C2_SCALE; - min_dist += tdist*tdist; - tdist = (x - maxc2) * C2_SCALE; - max_dist += tdist*tdist; - } else if (x > maxc2) { - tdist = (x - maxc2) * C2_SCALE; - min_dist += tdist*tdist; - tdist = (x - minc2) * C2_SCALE; - max_dist += tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - if (x <= centerc2) { - tdist = (x - maxc2) * C2_SCALE; - max_dist += tdist*tdist; - } else { - tdist = (x - minc2) * C2_SCALE; - max_dist += tdist*tdist; - } - } - - mindist[i] = min_dist; /* save away the results */ - if (max_dist < minmaxdist) - minmaxdist = max_dist; - } - - /* Now we know that no cell in the update box is more than minmaxdist - * away from some colormap entry. Therefore, only colors that are - * within minmaxdist of some part of the box need be considered. - */ - ncolors = 0; - for (i = 0; i < numcolors; i++) { - if (mindist[i] <= minmaxdist) - colorlist[ncolors++] = (JSAMPLE) i; - } - return ncolors; -} - - -LOCAL(void) -find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, - int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) -/* Find the closest colormap entry for each cell in the update box, - * given the list of candidate colors prepared by find_nearby_colors. - * Return the indexes of the closest entries in the bestcolor[] array. - * This routine uses Thomas' incremental distance calculation method to - * find the distance from a colormap entry to successive cells in the box. - */ -{ - int ic0, ic1, ic2; - int i, icolor; - register INT32 * bptr; /* pointer into bestdist[] array */ - JSAMPLE * cptr; /* pointer into bestcolor[] array */ - INT32 dist0, dist1; /* initial distance values */ - register INT32 dist2; /* current distance in inner loop */ - INT32 xx0, xx1; /* distance increments */ - register INT32 xx2; - INT32 inc0, inc1, inc2; /* initial values for increments */ - /* This array holds the distance to the nearest-so-far color for each cell */ - INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; - - /* Initialize best-distance for each cell of the update box */ - bptr = bestdist; - for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) - *bptr++ = 0x7FFFFFFFL; - - /* For each color selected by find_nearby_colors, - * compute its distance to the center of each cell in the box. - * If that's less than best-so-far, update best distance and color number. - */ - - /* Nominal steps between cell centers ("x" in Thomas article) */ -#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) -#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) -#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) - - for (i = 0; i < numcolors; i++) { - icolor = GETJSAMPLE(colorlist[i]); - /* Compute (square of) distance from minc0/c1/c2 to this color */ - inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; - dist0 = inc0*inc0; - inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; - dist0 += inc1*inc1; - inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; - dist0 += inc2*inc2; - /* Form the initial difference increments */ - inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; - inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; - inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; - /* Now loop over all cells in box, updating distance per Thomas method */ - bptr = bestdist; - cptr = bestcolor; - xx0 = inc0; - for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { - dist1 = dist0; - xx1 = inc1; - for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { - dist2 = dist1; - xx2 = inc2; - for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { - if (dist2 < *bptr) { - *bptr = dist2; - *cptr = (JSAMPLE) icolor; - } - dist2 += xx2; - xx2 += 2 * STEP_C2 * STEP_C2; - bptr++; - cptr++; - } - dist1 += xx1; - xx1 += 2 * STEP_C1 * STEP_C1; - } - dist0 += xx0; - xx0 += 2 * STEP_C0 * STEP_C0; - } - } -} - - -LOCAL(void) -fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) -/* Fill the inverse-colormap entries in the update box that contains */ -/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ -/* we can fill as many others as we wish.) */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - int minc0, minc1, minc2; /* lower left corner of update box */ - int ic0, ic1, ic2; - register JSAMPLE * cptr; /* pointer into bestcolor[] array */ - register histptr cachep; /* pointer into main cache array */ - /* This array lists the candidate colormap indexes. */ - JSAMPLE colorlist[MAXNUMCOLORS]; - int numcolors; /* number of candidate colors */ - /* This array holds the actually closest colormap index for each cell. */ - JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; - - /* Convert cell coordinates to update box ID */ - c0 >>= BOX_C0_LOG; - c1 >>= BOX_C1_LOG; - c2 >>= BOX_C2_LOG; - - /* Compute true coordinates of update box's origin corner. - * Actually we compute the coordinates of the center of the corner - * histogram cell, which are the lower bounds of the volume we care about. - */ - minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); - minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); - minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); - - /* Determine which colormap entries are close enough to be candidates - * for the nearest entry to some cell in the update box. - */ - numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); - - /* Determine the actually nearest colors. */ - find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, - bestcolor); - - /* Save the best color numbers (plus 1) in the main cache array */ - c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ - c1 <<= BOX_C1_LOG; - c2 <<= BOX_C2_LOG; - cptr = bestcolor; - for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { - for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { - cachep = & histogram[c0+ic0][c1+ic1][c2]; - for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { - *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); - } - } - } -} - - -/* - * Map some rows of pixels to the output colormapped representation. - */ - -METHODDEF(void) -pass2_no_dither (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) -/* This version performs no dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - register JSAMPROW inptr, outptr; - register histptr cachep; - register int c0, c1, c2; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - inptr = input_buf[row]; - outptr = output_buf[row]; - for (col = width; col > 0; col--) { - /* get pixel value and index into the cache */ - c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; - c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; - c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; - cachep = & histogram[c0][c1][c2]; - /* If we have not seen this color before, find nearest colormap entry */ - /* and update the cache */ - if (*cachep == 0) - fill_inverse_cmap(cinfo, c0,c1,c2); - /* Now emit the colormap index for this cell */ - *outptr++ = (JSAMPLE) (*cachep - 1); - } - } -} - - -METHODDEF(void) -pass2_fs_dither (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) -/* This version performs Floyd-Steinberg dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ - LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ - LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ - register FSERRPTR errorptr; /* => fserrors[] at column before current */ - JSAMPROW inptr; /* => current input pixel */ - JSAMPROW outptr; /* => current output pixel */ - histptr cachep; - int dir; /* +1 or -1 depending on direction */ - int dir3; /* 3*dir, for advancing inptr & errorptr */ - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - JSAMPLE *range_limit = cinfo->sample_range_limit; - int *error_limit = cquantize->error_limiter; - JSAMPROW colormap0 = cinfo->colormap[0]; - JSAMPROW colormap1 = cinfo->colormap[1]; - JSAMPROW colormap2 = cinfo->colormap[2]; - SHIFT_TEMPS - - for (row = 0; row < num_rows; row++) { - inptr = input_buf[row]; - outptr = output_buf[row]; - if (cquantize->on_odd_row) { - /* work right to left in this row */ - inptr += (width-1) * 3; /* so point to rightmost pixel */ - outptr += width-1; - dir = -1; - dir3 = -3; - errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ - cquantize->on_odd_row = FALSE; /* flip for next time */ - } else { - /* work left to right in this row */ - dir = 1; - dir3 = 3; - errorptr = cquantize->fserrors; /* => entry before first real column */ - cquantize->on_odd_row = TRUE; /* flip for next time */ - } - /* Preset error values: no error propagated to first pixel from left */ - cur0 = cur1 = cur2 = 0; - /* and no error propagated to row below yet */ - belowerr0 = belowerr1 = belowerr2 = 0; - bpreverr0 = bpreverr1 = bpreverr2 = 0; - - for (col = width; col > 0; col--) { - /* curN holds the error propagated from the previous pixel on the - * current line. Add the error propagated from the previous line - * to form the complete error correction term for this pixel, and - * round the error term (which is expressed * 16) to an integer. - * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct - * for either sign of the error value. - * Note: errorptr points to *previous* column's array entry. - */ - cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); - cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); - cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); - /* Limit the error using transfer function set by init_error_limit. - * See comments with init_error_limit for rationale. - */ - cur0 = error_limit[cur0]; - cur1 = error_limit[cur1]; - cur2 = error_limit[cur2]; - /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. - * The maximum error is +- MAXJSAMPLE (or less with error limiting); - * this sets the required size of the range_limit array. - */ - cur0 += GETJSAMPLE(inptr[0]); - cur1 += GETJSAMPLE(inptr[1]); - cur2 += GETJSAMPLE(inptr[2]); - cur0 = GETJSAMPLE(range_limit[cur0]); - cur1 = GETJSAMPLE(range_limit[cur1]); - cur2 = GETJSAMPLE(range_limit[cur2]); - /* Index into the cache with adjusted pixel value */ - cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; - /* If we have not seen this color before, find nearest colormap */ - /* entry and update the cache */ - if (*cachep == 0) - fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); - /* Now emit the colormap index for this cell */ - { register int pixcode = *cachep - 1; - *outptr = (JSAMPLE) pixcode; - /* Compute representation error for this pixel */ - cur0 -= GETJSAMPLE(colormap0[pixcode]); - cur1 -= GETJSAMPLE(colormap1[pixcode]); - cur2 -= GETJSAMPLE(colormap2[pixcode]); - } - /* Compute error fractions to be propagated to adjacent pixels. - * Add these into the running sums, and simultaneously shift the - * next-line error sums left by 1 column. - */ - { register LOCFSERROR bnexterr, delta; - - bnexterr = cur0; /* Process component 0 */ - delta = cur0 * 2; - cur0 += delta; /* form error * 3 */ - errorptr[0] = (FSERROR) (bpreverr0 + cur0); - cur0 += delta; /* form error * 5 */ - bpreverr0 = belowerr0 + cur0; - belowerr0 = bnexterr; - cur0 += delta; /* form error * 7 */ - bnexterr = cur1; /* Process component 1 */ - delta = cur1 * 2; - cur1 += delta; /* form error * 3 */ - errorptr[1] = (FSERROR) (bpreverr1 + cur1); - cur1 += delta; /* form error * 5 */ - bpreverr1 = belowerr1 + cur1; - belowerr1 = bnexterr; - cur1 += delta; /* form error * 7 */ - bnexterr = cur2; /* Process component 2 */ - delta = cur2 * 2; - cur2 += delta; /* form error * 3 */ - errorptr[2] = (FSERROR) (bpreverr2 + cur2); - cur2 += delta; /* form error * 5 */ - bpreverr2 = belowerr2 + cur2; - belowerr2 = bnexterr; - cur2 += delta; /* form error * 7 */ - } - /* At this point curN contains the 7/16 error value to be propagated - * to the next pixel on the current line, and all the errors for the - * next line have been shifted over. We are therefore ready to move on. - */ - inptr += dir3; /* Advance pixel pointers to next column */ - outptr += dir; - errorptr += dir3; /* advance errorptr to current column */ - } - /* Post-loop cleanup: we must unload the final error values into the - * final fserrors[] entry. Note we need not unload belowerrN because - * it is for the dummy column before or after the actual array. - */ - errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ - errorptr[1] = (FSERROR) bpreverr1; - errorptr[2] = (FSERROR) bpreverr2; - } -} - - -/* - * Initialize the error-limiting transfer function (lookup table). - * The raw F-S error computation can potentially compute error values of up to - * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be - * much less, otherwise obviously wrong pixels will be created. (Typical - * effects include weird fringes at color-area boundaries, isolated bright - * pixels in a dark area, etc.) The standard advice for avoiding this problem - * is to ensure that the "corners" of the color cube are allocated as output - * colors; then repeated errors in the same direction cannot cause cascading - * error buildup. However, that only prevents the error from getting - * completely out of hand; Aaron Giles reports that error limiting improves - * the results even with corner colors allocated. - * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty - * well, but the smoother transfer function used below is even better. Thanks - * to Aaron Giles for this idea. - */ - -LOCAL(void) -init_error_limit (j_decompress_ptr cinfo) -/* Allocate and fill in the error_limiter table */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - int * table; - int in, out; - - table = (int *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); - table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ - cquantize->error_limiter = table; - -#define STEPSIZE ((MAXJSAMPLE+1)/16) - /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ - out = 0; - for (in = 0; in < STEPSIZE; in++, out++) { - table[in] = out; table[-in] = -out; - } - /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ - for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { - table[in] = out; table[-in] = -out; - } - /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ - for (; in <= MAXJSAMPLE; in++) { - table[in] = out; table[-in] = -out; - } -#undef STEPSIZE -} - - -/* - * Finish up at the end of each pass. - */ - -METHODDEF(void) -finish_pass1 (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - - /* Select the representative colors and fill in cinfo->colormap */ - cinfo->colormap = cquantize->sv_colormap; - select_colors(cinfo, cquantize->desired); - /* Force next pass to zero the color index table */ - cquantize->needs_zeroed = TRUE; -} - - -METHODDEF(void) -finish_pass2 (j_decompress_ptr cinfo) -{ - /* no work */ -} - - -/* - * Initialize for each processing pass. - */ - -METHODDEF(void) -start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - int i; - - /* Only F-S dithering or no dithering is supported. */ - /* If user asks for ordered dither, give him F-S. */ - if (cinfo->dither_mode != JDITHER_NONE) - cinfo->dither_mode = JDITHER_FS; - - if (is_pre_scan) { - /* Set up method pointers */ - cquantize->pub.color_quantize = prescan_quantize; - cquantize->pub.finish_pass = finish_pass1; - cquantize->needs_zeroed = TRUE; /* Always zero histogram */ - } else { - /* Set up method pointers */ - if (cinfo->dither_mode == JDITHER_FS) - cquantize->pub.color_quantize = pass2_fs_dither; - else - cquantize->pub.color_quantize = pass2_no_dither; - cquantize->pub.finish_pass = finish_pass2; - - /* Make sure color count is acceptable */ - i = cinfo->actual_number_of_colors; - if (i < 1) - ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); - if (i > MAXNUMCOLORS) - ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); - - if (cinfo->dither_mode == JDITHER_FS) { - size_t arraysize = (size_t) ((cinfo->output_width + 2) * - (3 * SIZEOF(FSERROR))); - /* Allocate Floyd-Steinberg workspace if we didn't already. */ - if (cquantize->fserrors == NULL) - cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) - ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); - /* Initialize the propagated errors to zero. */ - FMEMZERO((void FAR *) cquantize->fserrors, arraysize); - /* Make the error-limit table if we didn't already. */ - if (cquantize->error_limiter == NULL) - init_error_limit(cinfo); - cquantize->on_odd_row = FALSE; - } - - } - /* Zero the histogram or inverse color map, if necessary */ - if (cquantize->needs_zeroed) { - for (i = 0; i < HIST_C0_ELEMS; i++) { - FMEMZERO((void FAR *) histogram[i], - HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); - } - cquantize->needs_zeroed = FALSE; - } -} - - -/* - * Switch to a new external colormap between output passes. - */ - -METHODDEF(void) -new_color_map_2_quant (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - - /* Reset the inverse color map */ - cquantize->needs_zeroed = TRUE; -} - - -/* - * Module initialization routine for 2-pass color quantization. - */ - -GLOBAL(void) -jinit_2pass_quantizer (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize; - int i; - - cquantize = (my_cquantize_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_cquantizer)); - cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; - cquantize->pub.start_pass = start_pass_2_quant; - cquantize->pub.new_color_map = new_color_map_2_quant; - cquantize->fserrors = NULL; /* flag optional arrays not allocated */ - cquantize->error_limiter = NULL; - - /* Make sure jdmaster didn't give me a case I can't handle */ - if (cinfo->out_color_components != 3) - ERREXIT(cinfo, JERR_NOTIMPL); - - /* Allocate the histogram/inverse colormap storage */ - cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); - for (i = 0; i < HIST_C0_ELEMS; i++) { - cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); - } - cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ - - /* Allocate storage for the completed colormap, if required. - * We do this now since it is FAR storage and may affect - * the memory manager's space calculations. - */ - if (cinfo->enable_2pass_quant) { - /* Make sure color count is acceptable */ - int desired = cinfo->desired_number_of_colors; - /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ - if (desired < 8) - ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); - /* Make sure colormap indexes can be represented by JSAMPLEs */ - if (desired > MAXNUMCOLORS) - ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); - cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3); - cquantize->desired = desired; - } else - cquantize->sv_colormap = NULL; - - /* Only F-S dithering or no dithering is supported. */ - /* If user asks for ordered dither, give him F-S. */ - if (cinfo->dither_mode != JDITHER_NONE) - cinfo->dither_mode = JDITHER_FS; - - /* Allocate Floyd-Steinberg workspace if necessary. - * This isn't really needed until pass 2, but again it is FAR storage. - * Although we will cope with a later change in dither_mode, - * we do not promise to honor max_memory_to_use if dither_mode changes. - */ - if (cinfo->dither_mode == JDITHER_FS) { - cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR)))); - /* Might as well create the error-limiting table too. */ - init_error_limit(cinfo); - } -} - -#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/libraries/jpeg/jutils.c b/libraries/jpeg/jutils.c deleted file mode 100644 index 5b16b6d03c0..00000000000 --- a/libraries/jpeg/jutils.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * jutils.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * Modified 2009-2011 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains tables and miscellaneous utility routines needed - * for both compression and decompression. - * Note we prefix all global names with "j" to minimize conflicts with - * a surrounding application. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element - * of a DCT block read in natural order (left to right, top to bottom). - */ - -#if 0 /* This table is not actually needed in v6a */ - -const int jpeg_zigzag_order[DCTSIZE2] = { - 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 -}; - -#endif - -/* - * jpeg_natural_order[i] is the natural-order position of the i'th element - * of zigzag order. - * - * When reading corrupted data, the Huffman decoders could attempt - * to reference an entry beyond the end of this array (if the decoded - * zero run length reaches past the end of the block). To prevent - * wild stores without adding an inner-loop test, we put some extra - * "63"s after the real entries. This will cause the extra coefficient - * to be stored in location 63 of the block, not somewhere random. - * The worst case would be a run-length of 15, which means we need 16 - * fake entries. - */ - -const int jpeg_natural_order[DCTSIZE2+16] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ - 63, 63, 63, 63, 63, 63, 63, 63 -}; - -const int jpeg_natural_order7[7*7+16] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 14, 21, 28, 35, - 42, 49, 50, 43, 36, 29, 22, 30, - 37, 44, 51, 52, 45, 38, 46, 53, - 54, - 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ - 63, 63, 63, 63, 63, 63, 63, 63 -}; - -const int jpeg_natural_order6[6*6+16] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 41, 34, 27, - 20, 13, 21, 28, 35, 42, 43, 36, - 29, 37, 44, 45, - 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ - 63, 63, 63, 63, 63, 63, 63, 63 -}; - -const int jpeg_natural_order5[5*5+16] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 12, - 19, 26, 33, 34, 27, 20, 28, 35, - 36, - 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ - 63, 63, 63, 63, 63, 63, 63, 63 -}; - -const int jpeg_natural_order4[4*4+16] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 25, 18, 11, 19, 26, 27, - 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ - 63, 63, 63, 63, 63, 63, 63, 63 -}; - -const int jpeg_natural_order3[3*3+16] = { - 0, 1, 8, 16, 9, 2, 10, 17, - 18, - 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ - 63, 63, 63, 63, 63, 63, 63, 63 -}; - -const int jpeg_natural_order2[2*2+16] = { - 0, 1, 8, 9, - 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ - 63, 63, 63, 63, 63, 63, 63, 63 -}; - - -/* - * Arithmetic utilities - */ - -GLOBAL(long) -jdiv_round_up (long a, long b) -/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ -/* Assumes a >= 0, b > 0 */ -{ - return (a + b - 1L) / b; -} - - -GLOBAL(long) -jround_up (long a, long b) -/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ -/* Assumes a >= 0, b > 0 */ -{ - a += b - 1L; - return a - (a % b); -} - - -/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays - * and coefficient-block arrays. This won't work on 80x86 because the arrays - * are FAR and we're assuming a small-pointer memory model. However, some - * DOS compilers provide far-pointer versions of memcpy() and memset() even - * in the small-model libraries. These will be used if USE_FMEM is defined. - * Otherwise, the routines below do it the hard way. (The performance cost - * is not all that great, because these routines aren't very heavily used.) - */ - -#ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */ -#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) -#else /* 80x86 case, define if we can */ -#ifdef USE_FMEM -#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) -#else -/* This function is for use by the FMEMZERO macro defined in jpegint.h. - * Do not call this function directly, use the FMEMZERO macro instead. - */ -GLOBAL(void) -jzero_far (void FAR * target, size_t bytestozero) -/* Zero out a chunk of FAR memory. */ -/* This might be sample-array data, block-array data, or alloc_large data. */ -{ - register char FAR * ptr = (char FAR *) target; - register size_t count; - - for (count = bytestozero; count > 0; count--) { - *ptr++ = 0; - } -} -#endif -#endif - - -GLOBAL(void) -jcopy_sample_rows (JSAMPARRAY input_array, int source_row, - JSAMPARRAY output_array, int dest_row, - int num_rows, JDIMENSION num_cols) -/* Copy some rows of samples from one place to another. - * num_rows rows are copied from input_array[source_row++] - * to output_array[dest_row++]; these areas may overlap for duplication. - * The source and destination arrays must be at least as wide as num_cols. - */ -{ - register JSAMPROW inptr, outptr; -#ifdef FMEMCOPY - register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); -#else - register JDIMENSION count; -#endif - register int row; - - input_array += source_row; - output_array += dest_row; - - for (row = num_rows; row > 0; row--) { - inptr = *input_array++; - outptr = *output_array++; -#ifdef FMEMCOPY - FMEMCOPY(outptr, inptr, count); -#else - for (count = num_cols; count > 0; count--) - *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ -#endif - } -} - - -GLOBAL(void) -jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, - JDIMENSION num_blocks) -/* Copy a row of coefficient blocks from one place to another. */ -{ -#ifdef FMEMCOPY - FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); -#else - register JCOEFPTR inptr, outptr; - register long count; - - inptr = (JCOEFPTR) input_row; - outptr = (JCOEFPTR) output_row; - for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { - *outptr++ = *inptr++; - } -#endif -} diff --git a/libraries/jpeg/jversion.h b/libraries/jpeg/jversion.h deleted file mode 100644 index d096384f7e3..00000000000 --- a/libraries/jpeg/jversion.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * jversion.h - * - * Copyright (C) 1991-2018, Thomas G. Lane, Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains software version identification. - */ - - -#define JVERSION "9c 14-Jan-2018" - -#define JCOPYRIGHT "Copyright (C) 2018, Thomas G. Lane, Guido Vollbeding" diff --git a/libraries/lzma/C/7z.h b/libraries/lzma/C/7z.h index 6c7886e38b1..9e27c015218 100644 --- a/libraries/lzma/C/7z.h +++ b/libraries/lzma/C/7z.h @@ -1,8 +1,8 @@ /* 7z.h -- 7z interface -2017-04-03 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ -#ifndef __7Z_H -#define __7Z_H +#ifndef ZIP7_INC_7Z_H +#define ZIP7_INC_7Z_H #include "7zTypes.h" @@ -91,12 +91,14 @@ typedef struct UInt64 *CoderUnpackSizes; // for all coders in all folders Byte *CodersData; + + UInt64 RangeLimit; } CSzAr; UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, - ILookInStream *stream, UInt64 startPos, + ILookInStreamPtr stream, UInt64 startPos, Byte *outBuffer, size_t outSize, ISzAllocPtr allocMain); @@ -172,7 +174,7 @@ UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 SRes SzArEx_Extract( const CSzArEx *db, - ILookInStream *inStream, + ILookInStreamPtr inStream, UInt32 fileIndex, /* index of file */ UInt32 *blockIndex, /* index of solid block */ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ @@ -194,7 +196,7 @@ SZ_ERROR_INPUT_EOF SZ_ERROR_FAIL */ -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, +SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream, ISzAllocPtr allocMain, ISzAllocPtr allocTemp); EXTERN_C_END diff --git a/libraries/lzma/C/7zAlloc.c b/libraries/lzma/C/7zAlloc.c new file mode 100644 index 00000000000..2f0659af6f7 --- /dev/null +++ b/libraries/lzma/C/7zAlloc.c @@ -0,0 +1,89 @@ +/* 7zAlloc.c -- Allocation functions for 7z processing +2023-03-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zAlloc.h" + +/* #define SZ_ALLOC_DEBUG */ +/* use SZ_ALLOC_DEBUG to debug alloc/free operations */ + +#ifdef SZ_ALLOC_DEBUG + +/* +#ifdef _WIN32 +#include "7zWindows.h" +#endif +*/ + +#include +static int g_allocCount = 0; +static int g_allocCountTemp = 0; + +static void Print_Alloc(const char *s, size_t size, int *counter) +{ + const unsigned size2 = (unsigned)size; + fprintf(stderr, "\n%s count = %10d : %10u bytes; ", s, *counter, size2); + (*counter)++; +} +static void Print_Free(const char *s, int *counter) +{ + (*counter)--; + fprintf(stderr, "\n%s count = %10d", s, *counter); +} +#endif + +void *SzAlloc(ISzAllocPtr p, size_t size) +{ + UNUSED_VAR(p) + if (size == 0) + return 0; + #ifdef SZ_ALLOC_DEBUG + Print_Alloc("Alloc", size, &g_allocCount); + #endif + return malloc(size); +} + +void SzFree(ISzAllocPtr p, void *address) +{ + UNUSED_VAR(p) + #ifdef SZ_ALLOC_DEBUG + if (address) + Print_Free("Free ", &g_allocCount); + #endif + free(address); +} + +void *SzAllocTemp(ISzAllocPtr p, size_t size) +{ + UNUSED_VAR(p) + if (size == 0) + return 0; + #ifdef SZ_ALLOC_DEBUG + Print_Alloc("Alloc_temp", size, &g_allocCountTemp); + /* + #ifdef _WIN32 + return HeapAlloc(GetProcessHeap(), 0, size); + #endif + */ + #endif + return malloc(size); +} + +void SzFreeTemp(ISzAllocPtr p, void *address) +{ + UNUSED_VAR(p) + #ifdef SZ_ALLOC_DEBUG + if (address) + Print_Free("Free_temp ", &g_allocCountTemp); + /* + #ifdef _WIN32 + HeapFree(GetProcessHeap(), 0, address); + return; + #endif + */ + #endif + free(address); +} diff --git a/libraries/lzma/C/7zAlloc.h b/libraries/lzma/C/7zAlloc.h new file mode 100644 index 00000000000..b2b8b0cdd93 --- /dev/null +++ b/libraries/lzma/C/7zAlloc.h @@ -0,0 +1,19 @@ +/* 7zAlloc.h -- Allocation functions +2023-03-04 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_7Z_ALLOC_H +#define ZIP7_INC_7Z_ALLOC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void *SzAlloc(ISzAllocPtr p, size_t size); +void SzFree(ISzAllocPtr p, void *address); + +void *SzAllocTemp(ISzAllocPtr p, size_t size); +void SzFreeTemp(ISzAllocPtr p, void *address); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/7zArcIn.c b/libraries/lzma/C/7zArcIn.c index f74d0fad510..43fa7c21454 100644 --- a/libraries/lzma/C/7zArcIn.c +++ b/libraries/lzma/C/7zArcIn.c @@ -1,5 +1,5 @@ /* 7zArcIn.c -- 7z Input functions -2018-12-31 : Igor Pavlov : Public domain */ +2023-05-11 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -10,10 +10,11 @@ #include "7zCrc.h" #include "CpuArch.h" -#define MY_ALLOC(T, p, size, alloc) { \ - if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } +#define MY_ALLOC(T, p, size, alloc) \ + { if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } -#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } +#define MY_ALLOC_ZE(T, p, size, alloc) \ + { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } #define MY_ALLOC_AND_CPY(to, size, from, alloc) \ { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } @@ -58,7 +59,7 @@ enum EIdEnum const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; -#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } +#define SzBitUi32s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; } static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc) { @@ -69,21 +70,21 @@ static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc) } else { - MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); - MY_ALLOC(UInt32, p->Vals, num, alloc); + MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc) + MY_ALLOC(UInt32, p->Vals, num, alloc) } return SZ_OK; } -void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc) +static void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc) { ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; } -#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } +#define SzBitUi64s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; } -void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc) +static void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc) { ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; @@ -96,7 +97,7 @@ static void SzAr_Init(CSzAr *p) p->NumFolders = 0; p->PackPositions = NULL; - SzBitUi32s_Init(&p->FolderCRCs); + SzBitUi32s_INIT(&p->FolderCRCs) p->FoCodersOffsets = NULL; p->FoStartPackStreamIndex = NULL; @@ -105,6 +106,8 @@ static void SzAr_Init(CSzAr *p) p->CoderUnpackSizes = NULL; p->CodersData = NULL; + + p->RangeLimit = 0; } static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc) @@ -140,11 +143,11 @@ void SzArEx_Init(CSzArEx *p) p->FileNameOffsets = NULL; p->FileNames = NULL; - SzBitUi32s_Init(&p->CRCs); - SzBitUi32s_Init(&p->Attribs); - // SzBitUi32s_Init(&p->Parents); - SzBitUi64s_Init(&p->MTime); - SzBitUi64s_Init(&p->CTime); + SzBitUi32s_INIT(&p->CRCs) + SzBitUi32s_INIT(&p->Attribs) + // SzBitUi32s_INIT(&p->Parents) + SzBitUi64s_INIT(&p->MTime) + SzBitUi64s_INIT(&p->CTime) } void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc) @@ -178,11 +181,20 @@ static int TestSignatureCandidate(const Byte *testBytes) return 1; } -#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; } +#define SzData_CLEAR(p) { (p)->Data = NULL; (p)->Size = 0; } + +#define SZ_READ_BYTE_SD_NOCHECK(_sd_, dest) \ + (_sd_)->Size--; dest = *(_sd_)->Data++; + +#define SZ_READ_BYTE_SD(_sd_, dest) \ + if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; \ + SZ_READ_BYTE_SD_NOCHECK(_sd_, dest) -#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++; #define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest) -#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++; + +#define SZ_READ_BYTE_2(dest) \ + if (sd.Size == 0) return SZ_ERROR_ARCHIVE; \ + sd.Size--; dest = *sd.Data++; #define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); } #define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); } @@ -190,25 +202,25 @@ static int TestSignatureCandidate(const Byte *testBytes) #define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); -static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) +static Z7_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) { Byte firstByte, mask; unsigned i; UInt32 v; - SZ_READ_BYTE(firstByte); + SZ_READ_BYTE(firstByte) if ((firstByte & 0x80) == 0) { *value = firstByte; return SZ_OK; } - SZ_READ_BYTE(v); + SZ_READ_BYTE(v) if ((firstByte & 0x40) == 0) { *value = (((UInt32)firstByte & 0x3F) << 8) | v; return SZ_OK; } - SZ_READ_BYTE(mask); + SZ_READ_BYTE(mask) *value = v | ((UInt32)mask << 8); mask = 0x20; for (i = 2; i < 8; i++) @@ -216,11 +228,11 @@ static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) Byte b; if ((firstByte & mask) == 0) { - UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); + const UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); *value |= (highPart << (8 * i)); return SZ_OK; } - SZ_READ_BYTE(b); + SZ_READ_BYTE(b) *value |= ((UInt64)b << (8 * i)); mask >>= 1; } @@ -228,7 +240,7 @@ static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) } -static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) +static Z7_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) { Byte firstByte; UInt64 value64; @@ -242,7 +254,7 @@ static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) sd->Size--; return SZ_OK; } - RINOK(ReadNumber(sd, &value64)); + RINOK(ReadNumber(sd, &value64)) if (value64 >= (UInt32)0x80000000 - 1) return SZ_ERROR_UNSUPPORTED; if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) @@ -256,10 +268,10 @@ static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) static SRes SkipData(CSzData *sd) { UInt64 size; - RINOK(ReadNumber(sd, &size)); + RINOK(ReadNumber(sd, &size)) if (size > sd->Size) return SZ_ERROR_ARCHIVE; - SKIP_DATA(sd, size); + SKIP_DATA(sd, size) return SZ_OK; } @@ -268,22 +280,22 @@ static SRes WaitId(CSzData *sd, UInt32 id) for (;;) { UInt64 type; - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) if (type == id) return SZ_OK; if (type == k7zIdEnd) return SZ_ERROR_ARCHIVE; - RINOK(SkipData(sd)); + RINOK(SkipData(sd)) } } static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) { - UInt32 numBytes = (numItems + 7) >> 3; + const UInt32 numBytes = (numItems + 7) >> 3; if (numBytes > sd->Size) return SZ_ERROR_ARCHIVE; *v = sd->Data; - SKIP_DATA(sd, numBytes); + SKIP_DATA(sd, numBytes) return SZ_OK; } @@ -305,48 +317,48 @@ static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) return sum; } -static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc) +static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc) { Byte allAreDefined; Byte *v2; - UInt32 numBytes = (numItems + 7) >> 3; + const UInt32 numBytes = (numItems + 7) >> 3; *v = NULL; - SZ_READ_BYTE(allAreDefined); + SZ_READ_BYTE(allAreDefined) if (numBytes == 0) return SZ_OK; if (allAreDefined == 0) { if (numBytes > sd->Size) return SZ_ERROR_ARCHIVE; - MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); - SKIP_DATA(sd, numBytes); + MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc) + SKIP_DATA(sd, numBytes) return SZ_OK; } - MY_ALLOC(Byte, *v, numBytes, alloc); + MY_ALLOC(Byte, *v, numBytes, alloc) v2 = *v; memset(v2, 0xFF, (size_t)numBytes); { - unsigned numBits = (unsigned)numItems & 7; + const unsigned numBits = (unsigned)numItems & 7; if (numBits != 0) v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); } return SZ_OK; } -static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) +static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) { UInt32 i; CSzData sd; UInt32 *vals; const Byte *defs; - MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); + MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc) sd = *sd2; defs = crcs->Defs; vals = crcs->Vals; for (i = 0; i < numItems; i++) if (SzBitArray_Check(defs, i)) { - SZ_READ_32(vals[i]); + SZ_READ_32(vals[i]) } else vals[i] = 0; @@ -357,7 +369,7 @@ static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *c static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) { SzBitUi32s_Free(crcs, alloc); - RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)); + RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)) return ReadUi32s(sd, numItems, crcs, alloc); } @@ -365,36 +377,36 @@ static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) { Byte allAreDefined; UInt32 numDefined = numItems; - SZ_READ_BYTE(allAreDefined); + SZ_READ_BYTE(allAreDefined) if (!allAreDefined) { - size_t numBytes = (numItems + 7) >> 3; + const size_t numBytes = (numItems + 7) >> 3; if (numBytes > sd->Size) return SZ_ERROR_ARCHIVE; numDefined = CountDefinedBits(sd->Data, numItems); - SKIP_DATA(sd, numBytes); + SKIP_DATA(sd, numBytes) } if (numDefined > (sd->Size >> 2)) return SZ_ERROR_ARCHIVE; - SKIP_DATA(sd, (size_t)numDefined * 4); + SKIP_DATA(sd, (size_t)numDefined * 4) return SZ_OK; } static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc) { - RINOK(SzReadNumber32(sd, &p->NumPackStreams)); + RINOK(SzReadNumber32(sd, &p->NumPackStreams)) - RINOK(WaitId(sd, k7zIdSize)); - MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc); + RINOK(WaitId(sd, k7zIdSize)) + MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc) { UInt64 sum = 0; UInt32 i; - UInt32 numPackStreams = p->NumPackStreams; + const UInt32 numPackStreams = p->NumPackStreams; for (i = 0; i < numPackStreams; i++) { UInt64 packSize; p->PackPositions[i] = sum; - RINOK(ReadNumber(sd, &packSize)); + RINOK(ReadNumber(sd, &packSize)) sum += packSize; if (sum < packSize) return SZ_ERROR_ARCHIVE; @@ -405,16 +417,16 @@ static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc) for (;;) { UInt64 type; - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) if (type == k7zIdEnd) return SZ_OK; if (type == k7zIdCRC) { /* CRC of packed streams is unused now */ - RINOK(SkipBitUi32s(sd, p->NumPackStreams)); + RINOK(SkipBitUi32s(sd, p->NumPackStreams)) continue; } - RINOK(SkipData(sd)); + RINOK(SkipData(sd)) } } @@ -440,7 +452,7 @@ SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) f->NumPackStreams = 0; f->UnpackStream = 0; - RINOK(SzReadNumber32(sd, &numCoders)); + RINOK(SzReadNumber32(sd, &numCoders)) if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) return SZ_ERROR_UNSUPPORTED; @@ -451,7 +463,7 @@ SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) unsigned idSize, j; UInt64 id; - SZ_READ_BYTE(mainByte); + SZ_READ_BYTE(mainByte) if ((mainByte & 0xC0) != 0) return SZ_ERROR_UNSUPPORTED; @@ -479,12 +491,12 @@ SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) { UInt32 numStreams; - RINOK(SzReadNumber32(sd, &numStreams)); + RINOK(SzReadNumber32(sd, &numStreams)) if (numStreams > k_NumCodersStreams_in_Folder_MAX) return SZ_ERROR_UNSUPPORTED; coder->NumStreams = (Byte)numStreams; - RINOK(SzReadNumber32(sd, &numStreams)); + RINOK(SzReadNumber32(sd, &numStreams)) if (numStreams != 1) return SZ_ERROR_UNSUPPORTED; } @@ -497,12 +509,12 @@ SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) if ((mainByte & 0x20) != 0) { UInt32 propsSize = 0; - RINOK(SzReadNumber32(sd, &propsSize)); + RINOK(SzReadNumber32(sd, &propsSize)) if (propsSize > sd->Size) return SZ_ERROR_ARCHIVE; if (propsSize >= 0x80) return SZ_ERROR_UNSUPPORTED; - coder->PropsOffset = sd->Data - dataStart; + coder->PropsOffset = (size_t)(sd->Data - dataStart); coder->PropsSize = (Byte)propsSize; sd->Data += (size_t)propsSize; sd->Size -= (size_t)propsSize; @@ -547,12 +559,12 @@ SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) { CSzBond *bp = f->Bonds + i; - RINOK(SzReadNumber32(sd, &bp->InIndex)); + RINOK(SzReadNumber32(sd, &bp->InIndex)) if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) return SZ_ERROR_ARCHIVE; streamUsed[bp->InIndex] = True; - RINOK(SzReadNumber32(sd, &bp->OutIndex)); + RINOK(SzReadNumber32(sd, &bp->OutIndex)) if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) return SZ_ERROR_ARCHIVE; coderUsed[bp->OutIndex] = True; @@ -582,7 +594,7 @@ SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) for (i = 0; i < numPackStreams; i++) { UInt32 index; - RINOK(SzReadNumber32(sd, &index)); + RINOK(SzReadNumber32(sd, &index)) if (index >= numInStreams || streamUsed[index]) return SZ_ERROR_ARCHIVE; streamUsed[index] = True; @@ -596,7 +608,7 @@ SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) } -static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) +static Z7_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) { CSzData sd; sd = *sd2; @@ -604,7 +616,7 @@ static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) { Byte firstByte, mask; unsigned i; - SZ_READ_BYTE_2(firstByte); + SZ_READ_BYTE_2(firstByte) if ((firstByte & 0x80) == 0) continue; if ((firstByte & 0x40) == 0) @@ -620,7 +632,7 @@ static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) mask >>= 1; if (i > sd.Size) return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, i); + SKIP_DATA2(sd, i) } *sd2 = sd; return SZ_OK; @@ -643,30 +655,30 @@ static SRes ReadUnpackInfo(CSzAr *p, const Byte *startBufPtr; Byte external; - RINOK(WaitId(sd2, k7zIdFolder)); + RINOK(WaitId(sd2, k7zIdFolder)) - RINOK(SzReadNumber32(sd2, &numFolders)); + RINOK(SzReadNumber32(sd2, &numFolders)) if (numFolders > numFoldersMax) return SZ_ERROR_UNSUPPORTED; p->NumFolders = numFolders; - SZ_READ_BYTE_SD(sd2, external); + SZ_READ_BYTE_SD(sd2, external) if (external == 0) sd = *sd2; else { UInt32 index; - RINOK(SzReadNumber32(sd2, &index)); + RINOK(SzReadNumber32(sd2, &index)) if (index >= numTempBufs) return SZ_ERROR_ARCHIVE; sd.Data = tempBufs[index].data; sd.Size = tempBufs[index].size; } - MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); - MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); - MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); - MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); + MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc) + MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc) + MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc) + MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc) startBufPtr = sd.Data; @@ -677,9 +689,9 @@ static SRes ReadUnpackInfo(CSzAr *p, { UInt32 numCoders, ci, numInStreams = 0; - p->FoCodersOffsets[fo] = sd.Data - startBufPtr; + p->FoCodersOffsets[fo] = (size_t)(sd.Data - startBufPtr); - RINOK(SzReadNumber32(&sd, &numCoders)); + RINOK(SzReadNumber32(&sd, &numCoders)) if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) return SZ_ERROR_UNSUPPORTED; @@ -689,7 +701,7 @@ static SRes ReadUnpackInfo(CSzAr *p, unsigned idSize; UInt32 coderInStreams; - SZ_READ_BYTE_2(mainByte); + SZ_READ_BYTE_2(mainByte) if ((mainByte & 0xC0) != 0) return SZ_ERROR_UNSUPPORTED; idSize = (mainByte & 0xF); @@ -697,15 +709,15 @@ static SRes ReadUnpackInfo(CSzAr *p, return SZ_ERROR_UNSUPPORTED; if (idSize > sd.Size) return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, idSize); + SKIP_DATA2(sd, idSize) coderInStreams = 1; if ((mainByte & 0x10) != 0) { UInt32 coderOutStreams; - RINOK(SzReadNumber32(&sd, &coderInStreams)); - RINOK(SzReadNumber32(&sd, &coderOutStreams)); + RINOK(SzReadNumber32(&sd, &coderInStreams)) + RINOK(SzReadNumber32(&sd, &coderOutStreams)) if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) return SZ_ERROR_UNSUPPORTED; } @@ -715,10 +727,10 @@ static SRes ReadUnpackInfo(CSzAr *p, if ((mainByte & 0x20) != 0) { UInt32 propsSize; - RINOK(SzReadNumber32(&sd, &propsSize)); + RINOK(SzReadNumber32(&sd, &propsSize)) if (propsSize > sd.Size) return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, propsSize); + SKIP_DATA2(sd, propsSize) } } @@ -732,7 +744,7 @@ static SRes ReadUnpackInfo(CSzAr *p, Byte coderUsed[k_Scan_NumCoders_MAX]; UInt32 i; - UInt32 numBonds = numCoders - 1; + const UInt32 numBonds = numCoders - 1; if (numInStreams < numBonds) return SZ_ERROR_ARCHIVE; @@ -748,12 +760,12 @@ static SRes ReadUnpackInfo(CSzAr *p, { UInt32 index; - RINOK(SzReadNumber32(&sd, &index)); + RINOK(SzReadNumber32(&sd, &index)) if (index >= numInStreams || streamUsed[index]) return SZ_ERROR_ARCHIVE; streamUsed[index] = True; - RINOK(SzReadNumber32(&sd, &index)); + RINOK(SzReadNumber32(&sd, &index)) if (index >= numCoders || coderUsed[index]) return SZ_ERROR_ARCHIVE; coderUsed[index] = True; @@ -765,7 +777,7 @@ static SRes ReadUnpackInfo(CSzAr *p, for (i = 0; i < numPackStreams; i++) { UInt32 index; - RINOK(SzReadNumber32(&sd, &index)); + RINOK(SzReadNumber32(&sd, &index)) if (index >= numInStreams || streamUsed[index]) return SZ_ERROR_ARCHIVE; streamUsed[index] = True; @@ -797,10 +809,10 @@ static SRes ReadUnpackInfo(CSzAr *p, p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; { - size_t dataSize = sd.Data - startBufPtr; + const size_t dataSize = (size_t)(sd.Data - startBufPtr); p->FoStartPackStreamIndex[fo] = packStreamIndex; p->FoCodersOffsets[fo] = dataSize; - MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); + MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc) } if (external != 0) @@ -810,21 +822,21 @@ static SRes ReadUnpackInfo(CSzAr *p, sd = *sd2; } - RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); + RINOK(WaitId(&sd, k7zIdCodersUnpackSize)) - MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); + MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc) { UInt32 i; for (i = 0; i < numCodersOutStreams; i++) { - RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); + RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)) } } for (;;) { UInt64 type; - RINOK(ReadID(&sd, &type)); + RINOK(ReadID(&sd, &type)) if (type == k7zIdEnd) { *sd2 = sd; @@ -832,10 +844,10 @@ static SRes ReadUnpackInfo(CSzAr *p, } if (type == k7zIdCRC) { - RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)); + RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)) continue; } - RINOK(SkipData(&sd)); + RINOK(SkipData(&sd)) } } @@ -860,13 +872,13 @@ static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) { UInt64 type = 0; UInt32 numSubDigests = 0; - UInt32 numFolders = p->NumFolders; + const UInt32 numFolders = p->NumFolders; UInt32 numUnpackStreams = numFolders; UInt32 numUnpackSizesInData = 0; for (;;) { - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) if (type == k7zIdNumUnpackStream) { UInt32 i; @@ -876,7 +888,7 @@ static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) for (i = 0; i < numFolders; i++) { UInt32 numStreams; - RINOK(SzReadNumber32(sd, &numStreams)); + RINOK(SzReadNumber32(sd, &numStreams)) if (numUnpackStreams > numUnpackStreams + numStreams) return SZ_ERROR_UNSUPPORTED; numUnpackStreams += numStreams; @@ -885,12 +897,12 @@ static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) numSubDigests += numStreams; } - ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data; + ssi->sdNumSubStreams.Size = (size_t)(sd->Data - ssi->sdNumSubStreams.Data); continue; } if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) break; - RINOK(SkipData(sd)); + RINOK(SkipData(sd)) } if (!ssi->sdNumSubStreams.Data) @@ -906,9 +918,9 @@ static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) if (type == k7zIdSize) { ssi->sdSizes.Data = sd->Data; - RINOK(SkipNumbers(sd, numUnpackSizesInData)); - ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data; - RINOK(ReadID(sd, &type)); + RINOK(SkipNumbers(sd, numUnpackSizesInData)) + ssi->sdSizes.Size = (size_t)(sd->Data - ssi->sdSizes.Data); + RINOK(ReadID(sd, &type)) } for (;;) @@ -918,14 +930,14 @@ static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) if (type == k7zIdCRC) { ssi->sdCRCs.Data = sd->Data; - RINOK(SkipBitUi32s(sd, numSubDigests)); - ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data; + RINOK(SkipBitUi32s(sd, numSubDigests)) + ssi->sdCRCs.Size = (size_t)(sd->Data - ssi->sdCRCs.Data); } else { - RINOK(SkipData(sd)); + RINOK(SkipData(sd)) } - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) } } @@ -938,27 +950,31 @@ static SRes SzReadStreamsInfo(CSzAr *p, { UInt64 type; - SzData_Clear(&ssi->sdSizes); - SzData_Clear(&ssi->sdCRCs); - SzData_Clear(&ssi->sdNumSubStreams); + SzData_CLEAR(&ssi->sdSizes) + SzData_CLEAR(&ssi->sdCRCs) + SzData_CLEAR(&ssi->sdNumSubStreams) *dataOffset = 0; - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) if (type == k7zIdPackInfo) { - RINOK(ReadNumber(sd, dataOffset)); - RINOK(ReadPackInfo(p, sd, alloc)); - RINOK(ReadID(sd, &type)); + RINOK(ReadNumber(sd, dataOffset)) + if (*dataOffset > p->RangeLimit) + return SZ_ERROR_ARCHIVE; + RINOK(ReadPackInfo(p, sd, alloc)) + if (p->PackPositions[p->NumPackStreams] > p->RangeLimit - *dataOffset) + return SZ_ERROR_ARCHIVE; + RINOK(ReadID(sd, &type)) } if (type == k7zIdUnpackInfo) { - RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)); - RINOK(ReadID(sd, &type)); + RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)) + RINOK(ReadID(sd, &type)) } if (type == k7zIdSubStreamsInfo) { - RINOK(ReadSubStreamsInfo(p, sd, ssi)); - RINOK(ReadID(sd, &type)); + RINOK(ReadSubStreamsInfo(p, sd, ssi)) + RINOK(ReadID(sd, &type)) } else { @@ -970,7 +986,7 @@ static SRes SzReadStreamsInfo(CSzAr *p, } static SRes SzReadAndDecodePackedStreams( - ILookInStream *inStream, + ILookInStreamPtr inStream, CSzData *sd, CBuf *tempBufs, UInt32 numFoldersMax, @@ -982,7 +998,7 @@ static SRes SzReadAndDecodePackedStreams( UInt32 fo; CSubStreamInfo ssi; - RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)); + RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)) dataStartPos += baseOffset; if (p->NumFolders == 0) @@ -994,7 +1010,7 @@ static SRes SzReadAndDecodePackedStreams( for (fo = 0; fo < p->NumFolders; fo++) { CBuf *tempBuf = tempBufs + fo; - UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); + const UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); if ((size_t)unpackSize != unpackSize) return SZ_ERROR_MEM; if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) @@ -1004,8 +1020,8 @@ static SRes SzReadAndDecodePackedStreams( for (fo = 0; fo < p->NumFolders; fo++) { const CBuf *tempBuf = tempBufs + fo; - RINOK(LookInStream_SeekTo(inStream, dataStartPos)); - RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); + RINOK(LookInStream_SeekTo(inStream, dataStartPos)) + RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)) } return SZ_OK; @@ -1028,19 +1044,19 @@ static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size return SZ_ERROR_ARCHIVE; for (p = data + pos; #ifdef _WIN32 - *(const UInt16 *)p != 0 + *(const UInt16 *)(const void *)p != 0 #else p[0] != 0 || p[1] != 0 #endif ; p += 2); - pos = p - data + 2; + pos = (size_t)(p - data) + 2; *offsets++ = (pos >> 1); } while (--numFiles); return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; } -static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, +static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, CSzData *sd2, const CBuf *tempBufs, UInt32 numTempBufs, ISzAllocPtr alloc) @@ -1051,22 +1067,22 @@ static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, Byte *defs; Byte external; - RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); + RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)) - SZ_READ_BYTE_SD(sd2, external); + SZ_READ_BYTE_SD(sd2, external) if (external == 0) sd = *sd2; else { UInt32 index; - RINOK(SzReadNumber32(sd2, &index)); + RINOK(SzReadNumber32(sd2, &index)) if (index >= numTempBufs) return SZ_ERROR_ARCHIVE; sd.Data = tempBufs[index].data; sd.Size = tempBufs[index].size; } - MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); + MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc) vals = p->Vals; defs = p->Defs; for (i = 0; i < num; i++) @@ -1076,7 +1092,7 @@ static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, return SZ_ERROR_ARCHIVE; vals[i].Low = GetUi32(sd.Data); vals[i].High = GetUi32(sd.Data + 4); - SKIP_DATA2(sd, 8); + SKIP_DATA2(sd, 8) } else vals[i].High = vals[i].Low = 0; @@ -1094,7 +1110,7 @@ static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, static SRes SzReadHeader2( CSzArEx *p, /* allocMain */ CSzData *sd, - ILookInStream *inStream, + ILookInStreamPtr inStream, CBuf *tempBufs, UInt32 *numTempBufs, ISzAllocPtr allocMain, ISzAllocPtr allocTemp @@ -1105,26 +1121,26 @@ static SRes SzReadHeader2( { UInt64 type; - SzData_Clear(&ssi.sdSizes); - SzData_Clear(&ssi.sdCRCs); - SzData_Clear(&ssi.sdNumSubStreams); + SzData_CLEAR(&ssi.sdSizes) + SzData_CLEAR(&ssi.sdCRCs) + SzData_CLEAR(&ssi.sdNumSubStreams) ssi.NumSubDigests = 0; ssi.NumTotalSubStreams = 0; - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) if (type == k7zIdArchiveProperties) { for (;;) { UInt64 type2; - RINOK(ReadID(sd, &type2)); + RINOK(ReadID(sd, &type2)) if (type2 == k7zIdEnd) break; - RINOK(SkipData(sd)); + RINOK(SkipData(sd)) } - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) } if (type == k7zIdAdditionalStreamsInfo) @@ -1133,6 +1149,8 @@ static SRes SzReadHeader2( SRes res; SzAr_Init(&tempAr); + tempAr.RangeLimit = p->db.RangeLimit; + res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, p->startPosAfterHeader, &tempAr, allocTemp); *numTempBufs = tempAr.NumFolders; @@ -1140,15 +1158,15 @@ static SRes SzReadHeader2( if (res != SZ_OK) return res; - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) } if (type == k7zIdMainStreamsInfo) { RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, - &p->dataPos, &ssi, allocMain)); + &p->dataPos, &ssi, allocMain)) p->dataPos += p->startPosAfterHeader; - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) } if (type == k7zIdEnd) @@ -1166,23 +1184,23 @@ static SRes SzReadHeader2( const Byte *emptyStreams = NULL; const Byte *emptyFiles = NULL; - RINOK(SzReadNumber32(sd, &numFiles)); + RINOK(SzReadNumber32(sd, &numFiles)) p->NumFiles = numFiles; for (;;) { UInt64 type; UInt64 size; - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) if (type == k7zIdEnd) break; - RINOK(ReadNumber(sd, &size)); + RINOK(ReadNumber(sd, &size)) if (size > sd->Size) return SZ_ERROR_ARCHIVE; if (type >= ((UInt32)1 << 8)) { - SKIP_DATA(sd, size); + SKIP_DATA(sd, size) } else switch ((unsigned)type) { @@ -1192,7 +1210,7 @@ static SRes SzReadHeader2( const Byte *namesData; Byte external; - SZ_READ_BYTE(external); + SZ_READ_BYTE(external) if (external == 0) { namesSize = (size_t)size - 1; @@ -1201,7 +1219,7 @@ static SRes SzReadHeader2( else { UInt32 index; - RINOK(SzReadNumber32(sd, &index)); + RINOK(SzReadNumber32(sd, &index)) if (index >= *numTempBufs) return SZ_ERROR_ARCHIVE; namesData = (tempBufs)[index].data; @@ -1210,25 +1228,25 @@ static SRes SzReadHeader2( if ((namesSize & 1) != 0) return SZ_ERROR_ARCHIVE; - MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); - MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain) + MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain) RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) if (external == 0) { - SKIP_DATA(sd, namesSize); + SKIP_DATA(sd, namesSize) } break; } case k7zIdEmptyStream: { - RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); + RINOK(RememberBitVector(sd, numFiles, &emptyStreams)) numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); emptyFiles = NULL; break; } case k7zIdEmptyFile: { - RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)); + RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)) break; } case k7zIdWinAttrib: @@ -1237,22 +1255,22 @@ static SRes SzReadHeader2( CSzData sdSwitch; CSzData *sdPtr; SzBitUi32s_Free(&p->Attribs, allocMain); - RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)); + RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)) - SZ_READ_BYTE(external); + SZ_READ_BYTE(external) if (external == 0) sdPtr = sd; else { UInt32 index; - RINOK(SzReadNumber32(sd, &index)); + RINOK(SzReadNumber32(sd, &index)) if (index >= *numTempBufs) return SZ_ERROR_ARCHIVE; sdSwitch.Data = (tempBufs)[index].data; sdSwitch.Size = (tempBufs)[index].size; sdPtr = &sdSwitch; } - RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)); + RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)) break; } /* @@ -1265,11 +1283,11 @@ static SRes SzReadHeader2( break; } */ - case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; - case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break; + case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break; default: { - SKIP_DATA(sd, size); + SKIP_DATA(sd, size) } } } @@ -1280,10 +1298,10 @@ static SRes SzReadHeader2( for (;;) { UInt64 type; - RINOK(ReadID(sd, &type)); + RINOK(ReadID(sd, &type)) if (type == k7zIdEnd) break; - RINOK(SkipData(sd)); + RINOK(SkipData(sd)) } { @@ -1295,40 +1313,37 @@ static SRes SzReadHeader2( UInt64 unpackPos = 0; const Byte *digestsDefs = NULL; const Byte *digestsVals = NULL; - UInt32 digestsValsIndex = 0; - UInt32 digestIndex; - Byte allDigestsDefined = 0; + UInt32 digestIndex = 0; Byte isDirMask = 0; Byte crcMask = 0; Byte mask = 0x80; - MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); - MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); - MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); - MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); + MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain) + MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain) + MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain) + MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain) - RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); + RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)) if (ssi.sdCRCs.Size != 0) { - SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); + Byte allDigestsDefined = 0; + SZ_READ_BYTE_SD_NOCHECK(&ssi.sdCRCs, allDigestsDefined) if (allDigestsDefined) digestsVals = ssi.sdCRCs.Data; else { - size_t numBytes = (ssi.NumSubDigests + 7) >> 3; + const size_t numBytes = (ssi.NumSubDigests + 7) >> 3; digestsDefs = ssi.sdCRCs.Data; digestsVals = digestsDefs + numBytes; } } - digestIndex = 0; - for (i = 0; i < numFiles; i++, mask >>= 1) { if (mask == 0) { - UInt32 byteIndex = (i - 1) >> 3; + const UInt32 byteIndex = (i - 1) >> 3; p->IsDirs[byteIndex] = isDirMask; p->CRCs.Defs[byteIndex] = crcMask; isDirMask = 0; @@ -1366,18 +1381,17 @@ static SRes SzReadHeader2( numSubStreams = 1; if (ssi.sdNumSubStreams.Data) { - RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)) } remSubStreams = numSubStreams; if (numSubStreams != 0) break; { - UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); unpackPos += folderUnpackSize; if (unpackPos < folderUnpackSize) return SZ_ERROR_ARCHIVE; } - folderIndex++; } } @@ -1389,47 +1403,44 @@ static SRes SzReadHeader2( if (--remSubStreams == 0) { - UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; + const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + const UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; if (folderUnpackSize < unpackPos - startFolderUnpackPos) return SZ_ERROR_ARCHIVE; unpackPos = startFolderUnpackPos + folderUnpackSize; if (unpackPos < folderUnpackSize) return SZ_ERROR_ARCHIVE; - if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) + if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, folderIndex)) { p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; crcMask |= mask; } - else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) - { - p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); - digestsValsIndex++; - crcMask |= mask; - } - folderIndex++; } else { UInt64 v; - RINOK(ReadNumber(&ssi.sdSizes, &v)); + RINOK(ReadNumber(&ssi.sdSizes, &v)) unpackPos += v; if (unpackPos < v) return SZ_ERROR_ARCHIVE; - if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + } + if ((crcMask & mask) == 0 && digestsVals) + { + if (!digestsDefs || SzBitArray_Check(digestsDefs, digestIndex)) { - p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); - digestsValsIndex++; + p->CRCs.Vals[i] = GetUi32(digestsVals); + digestsVals += 4; crcMask |= mask; } + digestIndex++; } } if (mask != 0x80) { - UInt32 byteIndex = (i - 1) >> 3; + const UInt32 byteIndex = (i - 1) >> 3; p->IsDirs[byteIndex] = isDirMask; p->CRCs.Defs[byteIndex] = crcMask; } @@ -1446,7 +1457,7 @@ static SRes SzReadHeader2( break; if (!ssi.sdNumSubStreams.Data) return SZ_ERROR_ARCHIVE; - RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)) if (numSubStreams != 0) return SZ_ERROR_ARCHIVE; /* @@ -1471,7 +1482,7 @@ static SRes SzReadHeader2( static SRes SzReadHeader( CSzArEx *p, CSzData *sd, - ILookInStream *inStream, + ILookInStreamPtr inStream, ISzAllocPtr allocMain, ISzAllocPtr allocTemp) { @@ -1490,7 +1501,7 @@ static SRes SzReadHeader( for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) Buf_Free(tempBufs + i, allocTemp); - RINOK(res); + RINOK(res) if (sd->Size != 0) return SZ_ERROR_FAIL; @@ -1500,7 +1511,7 @@ static SRes SzReadHeader( static SRes SzArEx_Open2( CSzArEx *p, - ILookInStream *inStream, + ILookInStreamPtr inStream, ISzAllocPtr allocMain, ISzAllocPtr allocTemp) { @@ -1513,9 +1524,9 @@ static SRes SzArEx_Open2( SRes res; startArcPos = 0; - RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR)); + RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR)) - RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)) if (!TestSignatureCandidate(header)) return SZ_ERROR_NO_ARCHIVE; @@ -1526,11 +1537,13 @@ static SRes SzArEx_Open2( nextHeaderSize = GetUi64(header + 20); nextHeaderCRC = GetUi32(header + 28); - p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; + p->startPosAfterHeader = (UInt64)startArcPos + k7zStartHeaderSize; if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) return SZ_ERROR_CRC; + p->db.RangeLimit = nextHeaderOffset; + nextHeaderSizeT = (size_t)nextHeaderSize; if (nextHeaderSizeT != nextHeaderSize) return SZ_ERROR_MEM; @@ -1542,14 +1555,14 @@ static SRes SzArEx_Open2( { Int64 pos = 0; - RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END)); - if ((UInt64)pos < startArcPos + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END)) + if ((UInt64)pos < (UInt64)startArcPos + nextHeaderOffset || + (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) return SZ_ERROR_INPUT_EOF; } - RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); + RINOK(LookInStream_SeekTo(inStream, (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset)) if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) return SZ_ERROR_MEM; @@ -1575,6 +1588,8 @@ static SRes SzArEx_Open2( Buf_Init(&tempBuf); SzAr_Init(&tempAr); + tempAr.RangeLimit = p->db.RangeLimit; + res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); SzAr_Free(&tempAr, allocTemp); @@ -1622,10 +1637,10 @@ static SRes SzArEx_Open2( } -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, +SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream, ISzAllocPtr allocMain, ISzAllocPtr allocTemp) { - SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + const SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); if (res != SZ_OK) SzArEx_Free(p, allocMain); return res; @@ -1634,7 +1649,7 @@ SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, SRes SzArEx_Extract( const CSzArEx *p, - ILookInStream *inStream, + ILookInStreamPtr inStream, UInt32 fileIndex, UInt32 *blockIndex, Byte **tempBuf, @@ -1644,7 +1659,7 @@ SRes SzArEx_Extract( ISzAllocPtr allocMain, ISzAllocPtr allocTemp) { - UInt32 folderIndex = p->FileToFolder[fileIndex]; + const UInt32 folderIndex = p->FileToFolder[fileIndex]; SRes res = SZ_OK; *offset = 0; @@ -1661,13 +1676,13 @@ SRes SzArEx_Extract( if (*tempBuf == NULL || *blockIndex != folderIndex) { - UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + const UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); /* UInt64 unpackSizeSpec = p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] - p->UnpackPositions[p->FolderToFile[folderIndex]]; */ - size_t unpackSize = (size_t)unpackSizeSpec; + const size_t unpackSize = (size_t)unpackSizeSpec; if (unpackSize != unpackSizeSpec) return SZ_ERROR_MEM; @@ -1695,7 +1710,7 @@ SRes SzArEx_Extract( if (res == SZ_OK) { - UInt64 unpackPos = p->UnpackPositions[fileIndex]; + const UInt64 unpackPos = p->UnpackPositions[fileIndex]; *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos); if (*offset + *outSizeProcessed > *outBufferSize) @@ -1711,8 +1726,8 @@ SRes SzArEx_Extract( size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) { - size_t offs = p->FileNameOffsets[fileIndex]; - size_t len = p->FileNameOffsets[fileIndex + 1] - offs; + const size_t offs = p->FileNameOffsets[fileIndex]; + const size_t len = p->FileNameOffsets[fileIndex + 1] - offs; if (dest != 0) { size_t i; diff --git a/libraries/lzma/C/7zBuf.h b/libraries/lzma/C/7zBuf.h index 81d1b5b646c..c0ba8a7b607 100644 --- a/libraries/lzma/C/7zBuf.h +++ b/libraries/lzma/C/7zBuf.h @@ -1,8 +1,8 @@ /* 7zBuf.h -- Byte Buffer -2017-04-03 : Igor Pavlov : Public domain */ +2023-03-04 : Igor Pavlov : Public domain */ -#ifndef __7Z_BUF_H -#define __7Z_BUF_H +#ifndef ZIP7_INC_7Z_BUF_H +#define ZIP7_INC_7Z_BUF_H #include "7zTypes.h" diff --git a/libraries/lzma/C/7zBuf2.c b/libraries/lzma/C/7zBuf2.c new file mode 100644 index 00000000000..20834741654 --- /dev/null +++ b/libraries/lzma/C/7zBuf2.c @@ -0,0 +1,52 @@ +/* 7zBuf2.c -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zBuf.h" + +void DynBuf_Construct(CDynBuf *p) +{ + p->data = 0; + p->size = 0; + p->pos = 0; +} + +void DynBuf_SeekToBeg(CDynBuf *p) +{ + p->pos = 0; +} + +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc) +{ + if (size > p->size - p->pos) + { + size_t newSize = p->pos + size; + Byte *data; + newSize += newSize / 4; + data = (Byte *)ISzAlloc_Alloc(alloc, newSize); + if (!data) + return 0; + p->size = newSize; + if (p->pos != 0) + memcpy(data, p->data, p->pos); + ISzAlloc_Free(alloc, p->data); + p->data = data; + } + if (size != 0) + { + memcpy(p->data + p->pos, buf, size); + p->pos += size; + } + return 1; +} + +void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->data); + p->data = 0; + p->size = 0; + p->pos = 0; +} diff --git a/libraries/lzma/C/7zCrc.c b/libraries/lzma/C/7zCrc.c index b4d84f0233a..c995a8be40c 100644 --- a/libraries/lzma/C/7zCrc.c +++ b/libraries/lzma/C/7zCrc.c @@ -1,5 +1,5 @@ -/* 7zCrc.c -- CRC32 init -2017-06-06 : Igor Pavlov : Public domain */ +/* 7zCrc.c -- CRC32 calculation and init +2023-04-02 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -13,38 +13,51 @@ #else #define CRC_NUM_TABLES 9 - #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) - - UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); - UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif #ifndef MY_CPU_BE - UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); - UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif -typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); - +/* +extern CRC_FUNC g_CrcUpdateT4; +CRC_FUNC g_CrcUpdateT4; +*/ +extern +CRC_FUNC g_CrcUpdateT8; CRC_FUNC g_CrcUpdateT8; +extern +CRC_FUNC g_CrcUpdateT0_32; +CRC_FUNC g_CrcUpdateT0_32; +extern +CRC_FUNC g_CrcUpdateT0_64; +CRC_FUNC g_CrcUpdateT0_64; +extern +CRC_FUNC g_CrcUpdate; CRC_FUNC g_CrcUpdate; UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; -UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) +UInt32 Z7_FASTCALL CrcUpdate(UInt32 v, const void *data, size_t size) { return g_CrcUpdate(v, data, size, g_CrcTable); } -UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) +UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size) { return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; } +#if CRC_NUM_TABLES < 4 \ + || (CRC_NUM_TABLES == 4 && defined(MY_CPU_BE)) \ + || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table); +UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; const Byte *pEnd = p + size; @@ -52,8 +65,184 @@ UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const U v = CRC_UPDATE_BYTE_2(v, *p); return v; } +#endif + +/* ---------- hardware CRC ---------- */ + +#ifdef MY_CPU_LE + +#if defined(MY_CPU_ARM_OR_ARM64) + +// #pragma message("ARM*") + + #if defined(_MSC_VER) + #if defined(MY_CPU_ARM64) + #if (_MSC_VER >= 1910) + #ifndef __clang__ + #define USE_ARM64_CRC + #include + #endif + #endif + #endif + #elif (defined(__clang__) && (__clang_major__ >= 3)) \ + || (defined(__GNUC__) && (__GNUC__ > 4)) + #if !defined(__ARM_FEATURE_CRC32) + #define __ARM_FEATURE_CRC32 1 + #if defined(__clang__) + #if defined(MY_CPU_ARM64) + #define ATTRIB_CRC __attribute__((__target__("crc"))) + #else + #define ATTRIB_CRC __attribute__((__target__("armv8-a,crc"))) + #endif + #else + #if defined(MY_CPU_ARM64) + #define ATTRIB_CRC __attribute__((__target__("+crc"))) + #else + #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc"))) + #endif + #endif + #endif + #if defined(__ARM_FEATURE_CRC32) + #define USE_ARM64_CRC + #include + #endif + #endif + +#else + +// no hardware CRC + +// #define USE_CRC_EMU + +#ifdef USE_CRC_EMU + +#pragma message("ARM64 CRC emulation") + +Z7_FORCE_INLINE +UInt32 __crc32b(UInt32 v, UInt32 data) +{ + const UInt32 *table = g_CrcTable; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); + return v; +} + +Z7_FORCE_INLINE +UInt32 __crc32w(UInt32 v, UInt32 data) +{ + const UInt32 *table = g_CrcTable; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + return v; +} + +Z7_FORCE_INLINE +UInt32 __crc32d(UInt32 v, UInt64 data) +{ + const UInt32 *table = g_CrcTable; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; + return v; +} + +#endif // USE_CRC_EMU + +#endif // defined(MY_CPU_ARM64) && defined(MY_CPU_LE) + + + +#if defined(USE_ARM64_CRC) || defined(USE_CRC_EMU) + +#define T0_32_UNROLL_BYTES (4 * 4) +#define T0_64_UNROLL_BYTES (4 * 8) + +#ifndef ATTRIB_CRC +#define ATTRIB_CRC +#endif +// #pragma message("USE ARM HW CRC") + +ATTRIB_CRC +UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table); +ATTRIB_CRC +UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + UNUSED_VAR(table); + + for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_32_UNROLL_BYTES - 1)) != 0; size--) + v = __crc32b(v, *p++); + + if (size >= T0_32_UNROLL_BYTES) + { + const Byte *lim = p + size; + size &= (T0_32_UNROLL_BYTES - 1); + lim -= size; + do + { + v = __crc32w(v, *(const UInt32 *)(const void *)(p)); + v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4; + v = __crc32w(v, *(const UInt32 *)(const void *)(p)); + v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4; + } + while (p != lim); + } + + for (; size != 0; size--) + v = __crc32b(v, *p++); + + return v; +} -void MY_FAST_CALL CrcGenerateTable() +ATTRIB_CRC +UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table); +ATTRIB_CRC +UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + UNUSED_VAR(table); + + for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_64_UNROLL_BYTES - 1)) != 0; size--) + v = __crc32b(v, *p++); + + if (size >= T0_64_UNROLL_BYTES) + { + const Byte *lim = p + size; + size &= (T0_64_UNROLL_BYTES - 1); + lim -= size; + do + { + v = __crc32d(v, *(const UInt64 *)(const void *)(p)); + v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8; + v = __crc32d(v, *(const UInt64 *)(const void *)(p)); + v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8; + } + while (p != lim); + } + + for (; size != 0; size--) + v = __crc32b(v, *p++); + + return v; +} + +#undef T0_32_UNROLL_BYTES +#undef T0_64_UNROLL_BYTES + +#endif // defined(USE_ARM64_CRC) || defined(USE_CRC_EMU) + +#endif // MY_CPU_LE + + + + +void Z7_FASTCALL CrcGenerateTable(void) { UInt32 i; for (i = 0; i < 256; i++) @@ -66,63 +255,86 @@ void MY_FAST_CALL CrcGenerateTable() } for (i = 256; i < 256 * CRC_NUM_TABLES; i++) { - UInt32 r = g_CrcTable[(size_t)i - 256]; + const UInt32 r = g_CrcTable[(size_t)i - 256]; g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); } #if CRC_NUM_TABLES < 4 - - g_CrcUpdate = CrcUpdateT1; - - #else - - #ifdef MY_CPU_LE - - g_CrcUpdateT4 = CrcUpdateT4; - g_CrcUpdate = CrcUpdateT4; - - #if CRC_NUM_TABLES >= 8 + g_CrcUpdate = CrcUpdateT1; + #elif defined(MY_CPU_LE) + // g_CrcUpdateT4 = CrcUpdateT4; + #if CRC_NUM_TABLES < 8 + g_CrcUpdate = CrcUpdateT4; + #else // CRC_NUM_TABLES >= 8 g_CrcUpdateT8 = CrcUpdateT8; - + /* #ifdef MY_CPU_X86_OR_AMD64 if (!CPU_Is_InOrder()) #endif - g_CrcUpdate = CrcUpdateT8; + */ + g_CrcUpdate = CrcUpdateT8; #endif - #else { - #ifndef MY_CPU_BE + #ifndef MY_CPU_BE UInt32 k = 0x01020304; const Byte *p = (const Byte *)&k; if (p[0] == 4 && p[1] == 3) { - g_CrcUpdateT4 = CrcUpdateT4; - g_CrcUpdate = CrcUpdateT4; - #if CRC_NUM_TABLES >= 8 - g_CrcUpdateT8 = CrcUpdateT8; - g_CrcUpdate = CrcUpdateT8; + #if CRC_NUM_TABLES < 8 + // g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; + #else // CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + g_CrcUpdate = CrcUpdateT8; #endif } else if (p[0] != 1 || p[1] != 2) g_CrcUpdate = CrcUpdateT1; else - #endif + #endif // MY_CPU_BE { for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) { - UInt32 x = g_CrcTable[(size_t)i - 256]; - g_CrcTable[i] = CRC_UINT32_SWAP(x); + const UInt32 x = g_CrcTable[(size_t)i - 256]; + g_CrcTable[i] = Z7_BSWAP32(x); } - g_CrcUpdateT4 = CrcUpdateT1_BeT4; - g_CrcUpdate = CrcUpdateT1_BeT4; - #if CRC_NUM_TABLES >= 8 - g_CrcUpdateT8 = CrcUpdateT1_BeT8; - g_CrcUpdate = CrcUpdateT1_BeT8; + #if CRC_NUM_TABLES <= 4 + g_CrcUpdate = CrcUpdateT1; + #elif CRC_NUM_TABLES <= 8 + // g_CrcUpdateT4 = CrcUpdateT1_BeT4; + g_CrcUpdate = CrcUpdateT1_BeT4; + #else // CRC_NUM_TABLES > 8 + g_CrcUpdateT8 = CrcUpdateT1_BeT8; + g_CrcUpdate = CrcUpdateT1_BeT8; #endif } } - #endif + #endif // CRC_NUM_TABLES < 4 + #ifdef MY_CPU_LE + #ifdef USE_ARM64_CRC + if (CPU_IsSupported_CRC32()) + { + g_CrcUpdateT0_32 = CrcUpdateT0_32; + g_CrcUpdateT0_64 = CrcUpdateT0_64; + g_CrcUpdate = + #if defined(MY_CPU_ARM) + CrcUpdateT0_32; + #else + CrcUpdateT0_64; + #endif + } + #endif + + #ifdef USE_CRC_EMU + g_CrcUpdateT0_32 = CrcUpdateT0_32; + g_CrcUpdateT0_64 = CrcUpdateT0_64; + g_CrcUpdate = CrcUpdateT0_64; + #endif #endif } + +#undef kCrcPoly +#undef CRC64_NUM_TABLES +#undef CRC_UPDATE_BYTE_2 diff --git a/libraries/lzma/C/7zCrc.h b/libraries/lzma/C/7zCrc.h index 8fd57958715..4afaeae4a84 100644 --- a/libraries/lzma/C/7zCrc.h +++ b/libraries/lzma/C/7zCrc.h @@ -1,8 +1,8 @@ /* 7zCrc.h -- CRC32 calculation -2013-01-18 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ -#ifndef __7Z_CRC_H -#define __7Z_CRC_H +#ifndef ZIP7_INC_7Z_CRC_H +#define ZIP7_INC_7Z_CRC_H #include "7zTypes.h" @@ -11,14 +11,16 @@ EXTERN_C_BEGIN extern UInt32 g_CrcTable[]; /* Call CrcGenerateTable one time before other CRC functions */ -void MY_FAST_CALL CrcGenerateTable(void); +void Z7_FASTCALL CrcGenerateTable(void); #define CRC_INIT_VAL 0xFFFFFFFF #define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) #define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) -UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); -UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); +UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size); +UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size); + +typedef UInt32 (Z7_FASTCALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); EXTERN_C_END diff --git a/libraries/lzma/C/7zCrcOpt.c b/libraries/lzma/C/7zCrcOpt.c index 73beba298dc..9c649290df7 100644 --- a/libraries/lzma/C/7zCrcOpt.c +++ b/libraries/lzma/C/7zCrcOpt.c @@ -1,5 +1,5 @@ /* 7zCrcOpt.c -- CRC32 calculation -2017-04-03 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -9,14 +9,15 @@ #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) -UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); +UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); for (; size >= 4; size -= 4, p += 4) { - v ^= *(const UInt32 *)p; + v ^= *(const UInt32 *)(const void *)p; v = (table + 0x300)[((v ) & 0xFF)] ^ (table + 0x200)[((v >> 8) & 0xFF)] @@ -28,7 +29,8 @@ UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const U return v; } -UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); +UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) @@ -36,13 +38,13 @@ UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const U for (; size >= 8; size -= 8, p += 8) { UInt32 d; - v ^= *(const UInt32 *)p; + v ^= *(const UInt32 *)(const void *)p; v = (table + 0x700)[((v ) & 0xFF)] ^ (table + 0x600)[((v >> 8) & 0xFF)] ^ (table + 0x500)[((v >> 16) & 0xFF)] ^ (table + 0x400)[((v >> 24))]; - d = *((const UInt32 *)p + 1); + d = *((const UInt32 *)(const void *)p + 1); v ^= (table + 0x300)[((d ) & 0xFF)] ^ (table + 0x200)[((d >> 8) & 0xFF)] @@ -59,11 +61,11 @@ UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const U #ifndef MY_CPU_LE -#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) +#define CRC_UINT32_SWAP(v) Z7_BSWAP32(v) #define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8)) -UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; table += 0x100; @@ -72,7 +74,7 @@ UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, co v = CRC_UPDATE_BYTE_2_BE(v, *p); for (; size >= 4; size -= 4, p += 4) { - v ^= *(const UInt32 *)p; + v ^= *(const UInt32 *)(const void *)p; v = (table + 0x000)[((v ) & 0xFF)] ^ (table + 0x100)[((v >> 8) & 0xFF)] @@ -84,7 +86,7 @@ UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, co return CRC_UINT32_SWAP(v); } -UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; table += 0x100; @@ -94,13 +96,13 @@ UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, co for (; size >= 8; size -= 8, p += 8) { UInt32 d; - v ^= *(const UInt32 *)p; + v ^= *(const UInt32 *)(const void *)p; v = (table + 0x400)[((v ) & 0xFF)] ^ (table + 0x500)[((v >> 8) & 0xFF)] ^ (table + 0x600)[((v >> 16) & 0xFF)] ^ (table + 0x700)[((v >> 24))]; - d = *((const UInt32 *)p + 1); + d = *((const UInt32 *)(const void *)p + 1); v ^= (table + 0x000)[((d ) & 0xFF)] ^ (table + 0x100)[((d >> 8) & 0xFF)] diff --git a/libraries/lzma/C/7zDec.c b/libraries/lzma/C/7zDec.c index 7c463521112..96c60359a47 100644 --- a/libraries/lzma/C/7zDec.c +++ b/libraries/lzma/C/7zDec.c @@ -1,11 +1,11 @@ /* 7zDec.c -- Decoding from 7z folder -2019-02-02 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ #include "Precomp.h" #include -/* #define _7ZIP_PPMD_SUPPPORT */ +/* #define Z7_PPMD_SUPPORT */ #include "7z.h" #include "7zCrc.h" @@ -16,24 +16,49 @@ #include "Delta.h" #include "LzmaDec.h" #include "Lzma2Dec.h" -#ifdef _7ZIP_PPMD_SUPPPORT +#ifdef Z7_PPMD_SUPPORT #include "Ppmd7.h" #endif #define k_Copy 0 -#define k_Delta 3 +#ifndef Z7_NO_METHOD_LZMA2 #define k_LZMA2 0x21 +#endif #define k_LZMA 0x30101 -#define k_BCJ 0x3030103 #define k_BCJ2 0x303011B + +#if !defined(Z7_NO_METHODS_FILTERS) +#define Z7_USE_BRANCH_FILTER +#endif + +#if !defined(Z7_NO_METHODS_FILTERS) || \ + defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARM64) +#define Z7_USE_FILTER_ARM64 +#ifndef Z7_USE_BRANCH_FILTER +#define Z7_USE_BRANCH_FILTER +#endif +#define k_ARM64 0xa +#endif + +#if !defined(Z7_NO_METHODS_FILTERS) || \ + defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARMT) +#define Z7_USE_FILTER_ARMT +#ifndef Z7_USE_BRANCH_FILTER +#define Z7_USE_BRANCH_FILTER +#endif +#define k_ARMT 0x3030701 +#endif + +#ifndef Z7_NO_METHODS_FILTERS +#define k_Delta 3 +#define k_BCJ 0x3030103 #define k_PPC 0x3030205 #define k_IA64 0x3030401 #define k_ARM 0x3030501 -#define k_ARMT 0x3030701 #define k_SPARC 0x3030805 +#endif - -#ifdef _7ZIP_PPMD_SUPPPORT +#ifdef Z7_PPMD_SUPPORT #define k_PPMD 0x30401 @@ -46,17 +71,17 @@ typedef struct UInt64 processed; BoolInt extra; SRes res; - const ILookInStream *inStream; + ILookInStreamPtr inStream; } CByteInToLook; -static Byte ReadByte(const IByteIn *pp) +static Byte ReadByte(IByteInPtr pp) { - CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt); + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInToLook) if (p->cur != p->end) return *p->cur++; if (p->res == SZ_OK) { - size_t size = p->cur - p->begin; + size_t size = (size_t)(p->cur - p->begin); p->processed += size; p->res = ILookInStream_Skip(p->inStream, size); size = (1 << 25); @@ -64,13 +89,13 @@ static Byte ReadByte(const IByteIn *pp) p->cur = p->begin; p->end = p->begin + size; if (size != 0) - return *p->cur++;; + return *p->cur++; } p->extra = True; return 0; } -static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream, +static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) { CPpmd7 ppmd; @@ -101,28 +126,32 @@ static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, c Ppmd7_Init(&ppmd, order); } { - CPpmd7z_RangeDec rc; - Ppmd7z_RangeDec_CreateVTable(&rc); - rc.Stream = &s.vt; - if (!Ppmd7z_RangeDec_Init(&rc)) + ppmd.rc.dec.Stream = &s.vt; + if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec)) res = SZ_ERROR_DATA; - else if (s.extra) - res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); - else + else if (!s.extra) { - SizeT i; - for (i = 0; i < outSize; i++) + Byte *buf = outBuffer; + const Byte *lim = buf + outSize; + for (; buf != lim; buf++) { - int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.vt); + int sym = Ppmd7z_DecodeSymbol(&ppmd); if (s.extra || sym < 0) break; - outBuffer[i] = (Byte)sym; + *buf = (Byte)sym; } - if (i != outSize) - res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); - else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc)) + if (buf != lim) + res = SZ_ERROR_DATA; + else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) + { + /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */ res = SZ_ERROR_DATA; + } } + if (s.extra) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else if (s.processed + (size_t)(s.cur - s.begin) != inSize) + res = SZ_ERROR_DATA; } Ppmd7_Free(&ppmd, allocMain); return res; @@ -131,14 +160,14 @@ static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, c #endif -static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, +static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) { CLzmaDec state; SRes res = SZ_OK; - LzmaDec_Construct(&state); - RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); + LzmaDec_CONSTRUCT(&state) + RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)) state.dic = outBuffer; state.dicBufSize = outSize; LzmaDec_Init(&state); @@ -189,18 +218,18 @@ static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, I } -#ifndef _7Z_NO_METHOD_LZMA2 +#ifndef Z7_NO_METHOD_LZMA2 -static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, +static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) { CLzma2Dec state; SRes res = SZ_OK; - Lzma2Dec_Construct(&state); + Lzma2Dec_CONSTRUCT(&state) if (propsSize != 1) return SZ_ERROR_DATA; - RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); + RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)) state.decoder.dic = outBuffer; state.decoder.dicBufSize = outSize; Lzma2Dec_Init(&state); @@ -250,7 +279,7 @@ static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, #endif -static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) +static SRes SzDecodeCopy(UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer) { while (inSize > 0) { @@ -258,13 +287,13 @@ static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer size_t curSize = (1 << 18); if (curSize > inSize) curSize = (size_t)inSize; - RINOK(ILookInStream_Look(inStream, &inBuf, &curSize)); + RINOK(ILookInStream_Look(inStream, &inBuf, &curSize)) if (curSize == 0) return SZ_ERROR_INPUT_EOF; memcpy(outBuffer, inBuf, curSize); outBuffer += curSize; inSize -= curSize; - RINOK(ILookInStream_Skip(inStream, curSize)); + RINOK(ILookInStream_Skip(inStream, curSize)) } return SZ_OK; } @@ -275,12 +304,12 @@ static BoolInt IS_MAIN_METHOD(UInt32 m) { case k_Copy: case k_LZMA: - #ifndef _7Z_NO_METHOD_LZMA2 + #ifndef Z7_NO_METHOD_LZMA2 case k_LZMA2: - #endif - #ifdef _7ZIP_PPMD_SUPPPORT + #endif + #ifdef Z7_PPMD_SUPPORT case k_PPMD: - #endif + #endif return True; } return False; @@ -310,7 +339,7 @@ static SRes CheckSupportedFolder(const CSzFolder *f) } - #ifndef _7Z_NO_METHODS_FILTERS + #if defined(Z7_USE_BRANCH_FILTER) if (f->NumCoders == 2) { @@ -326,13 +355,20 @@ static SRes CheckSupportedFolder(const CSzFolder *f) return SZ_ERROR_UNSUPPORTED; switch ((UInt32)c->MethodID) { + #if !defined(Z7_NO_METHODS_FILTERS) case k_Delta: case k_BCJ: case k_PPC: case k_IA64: case k_SPARC: case k_ARM: + #endif + #ifdef Z7_USE_FILTER_ARM64 + case k_ARM64: + #endif + #ifdef Z7_USE_FILTER_ARMT case k_ARMT: + #endif break; default: return SZ_ERROR_UNSUPPORTED; @@ -365,13 +401,16 @@ static SRes CheckSupportedFolder(const CSzFolder *f) return SZ_ERROR_UNSUPPORTED; } -#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; + + + + static SRes SzFolder_Decode2(const CSzFolder *folder, const Byte *propsData, const UInt64 *unpackSizes, const UInt64 *packPositions, - ILookInStream *inStream, UInt64 startPos, + ILookInStreamPtr inStream, UInt64 startPos, Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain, Byte *tempBuf[]) { @@ -380,7 +419,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, SizeT tempSize3 = 0; Byte *tempBuf3 = 0; - RINOK(CheckSupportedFolder(folder)); + RINOK(CheckSupportedFolder(folder)) for (ci = 0; ci < folder->NumCoders; ci++) { @@ -395,8 +434,8 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, SizeT outSizeCur = outSize; if (folder->NumCoders == 4) { - UInt32 indices[] = { 3, 2, 0 }; - UInt64 unpackSize = unpackSizes[ci]; + const UInt32 indices[] = { 3, 2, 0 }; + const UInt64 unpackSize = unpackSizes[ci]; si = indices[ci]; if (ci < 2) { @@ -422,37 +461,37 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, } offset = packPositions[si]; inSize = packPositions[(size_t)si + 1] - offset; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + RINOK(LookInStream_SeekTo(inStream, startPos + offset)) if (coder->MethodID == k_Copy) { if (inSize != outSizeCur) /* check it */ return SZ_ERROR_DATA; - RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); + RINOK(SzDecodeCopy(inSize, inStream, outBufCur)) } else if (coder->MethodID == k_LZMA) { - RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) } - #ifndef _7Z_NO_METHOD_LZMA2 + #ifndef Z7_NO_METHOD_LZMA2 else if (coder->MethodID == k_LZMA2) { - RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) } - #endif - #ifdef _7ZIP_PPMD_SUPPPORT + #endif + #ifdef Z7_PPMD_SUPPORT else if (coder->MethodID == k_PPMD) { - RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) } - #endif + #endif else return SZ_ERROR_UNSUPPORTED; } else if (coder->MethodID == k_BCJ2) { - UInt64 offset = packPositions[1]; - UInt64 s3Size = packPositions[2] - offset; + const UInt64 offset = packPositions[1]; + const UInt64 s3Size = packPositions[2] - offset; if (ci != 3) return SZ_ERROR_UNSUPPORTED; @@ -464,8 +503,8 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, if (!tempBuf[2] && tempSizes[2] != 0) return SZ_ERROR_MEM; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); - RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); + RINOK(LookInStream_SeekTo(inStream, startPos + offset)) + RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])) if ((tempSizes[0] & 3) != 0 || (tempSizes[1] & 3) != 0 || @@ -484,26 +523,22 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, p.destLim = outBuffer + outSize; Bcj2Dec_Init(&p); - RINOK(Bcj2Dec_Decode(&p)); + RINOK(Bcj2Dec_Decode(&p)) { unsigned i; for (i = 0; i < 4; i++) if (p.bufs[i] != p.lims[i]) return SZ_ERROR_DATA; - - if (!Bcj2Dec_IsFinished(&p)) - return SZ_ERROR_DATA; - - if (p.dest != p.destLim - || p.state != BCJ2_STREAM_MAIN) + if (p.dest != p.destLim || !Bcj2Dec_IsMaybeFinished(&p)) return SZ_ERROR_DATA; } } } - #ifndef _7Z_NO_METHODS_FILTERS + #if defined(Z7_USE_BRANCH_FILTER) else if (ci == 1) { + #if !defined(Z7_NO_METHODS_FILTERS) if (coder->MethodID == k_Delta) { if (coder->PropsSize != 1) @@ -513,31 +548,53 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, Delta_Init(state); Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); } + continue; } - else + #endif + + #ifdef Z7_USE_FILTER_ARM64 + if (coder->MethodID == k_ARM64) + { + UInt32 pc = 0; + if (coder->PropsSize == 4) + pc = GetUi32(propsData + coder->PropsOffset); + else if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc); + continue; + } + #endif + + #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT) { if (coder->PropsSize != 0) return SZ_ERROR_UNSUPPORTED; + #define CASE_BRA_CONV(isa) case k_ ## isa: Z7_BRANCH_CONV_DEC(isa)(outBuffer, outSize, 0); break; // pc = 0; switch (coder->MethodID) { + #if !defined(Z7_NO_METHODS_FILTERS) case k_BCJ: { - UInt32 state; - x86_Convert_Init(state); - x86_Convert(outBuffer, outSize, 0, &state, 0); + UInt32 state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; + z7_BranchConvSt_X86_Dec(outBuffer, outSize, 0, &state); // pc = 0 break; } CASE_BRA_CONV(PPC) CASE_BRA_CONV(IA64) CASE_BRA_CONV(SPARC) CASE_BRA_CONV(ARM) + #endif + #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT) CASE_BRA_CONV(ARMT) + #endif default: return SZ_ERROR_UNSUPPORTED; } + continue; } - } - #endif + #endif + } // (c == 1) + #endif else return SZ_ERROR_UNSUPPORTED; } @@ -547,7 +604,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, - ILookInStream *inStream, UInt64 startPos, + ILookInStreamPtr inStream, UInt64 startPos, Byte *outBuffer, size_t outSize, ISzAllocPtr allocMain) { diff --git a/libraries/lzma/C/7zFile.c b/libraries/lzma/C/7zFile.c new file mode 100644 index 00000000000..ba5daa133b9 --- /dev/null +++ b/libraries/lzma/C/7zFile.c @@ -0,0 +1,443 @@ +/* 7zFile.c -- File IO +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zFile.h" + +#ifndef USE_WINDOWS_FILE + + #include + + #ifndef USE_FOPEN + #include + #include + #ifdef _WIN32 + #include + typedef int ssize_t; + typedef int off_t; + #else + #include + #endif + #endif + +#else + +/* + ReadFile and WriteFile functions in Windows have BUG: + If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) + from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES + (Insufficient system resources exist to complete the requested service). + Probably in some version of Windows there are problems with other sizes: + for 32 MB (maybe also for 16 MB). + And message can be "Network connection was lost" +*/ + +#endif + +#define kChunkSizeMax (1 << 22) + +void File_Construct(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + p->handle = INVALID_HANDLE_VALUE; + #elif defined(USE_FOPEN) + p->file = NULL; + #else + p->fd = -1; + #endif +} + +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) + +static WRes File_Open(CSzFile *p, const char *name, int writeMode) +{ + #ifdef USE_WINDOWS_FILE + + p->handle = CreateFileA(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); + + #elif defined(USE_FOPEN) + + p->file = fopen(name, writeMode ? "wb+" : "rb"); + return (p->file != 0) ? 0 : + #ifdef UNDER_CE + 2; /* ENOENT */ + #else + errno; + #endif + + #else + + int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY); + #ifdef O_BINARY + flags |= O_BINARY; + #endif + p->fd = open(name, flags, 0666); + return (p->fd != -1) ? 0 : errno; + + #endif +} + +WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } + +WRes OutFile_Open(CSzFile *p, const char *name) +{ + #if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN) + return File_Open(p, name, 1); + #else + p->fd = creat(name, 0666); + return (p->fd != -1) ? 0 : errno; + #endif +} + +#endif + + +#ifdef USE_WINDOWS_FILE +static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) +{ + p->handle = CreateFileW(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); +} +WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } +#endif + +WRes File_Close(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + + if (p->handle != INVALID_HANDLE_VALUE) + { + if (!CloseHandle(p->handle)) + return GetLastError(); + p->handle = INVALID_HANDLE_VALUE; + } + + #elif defined(USE_FOPEN) + + if (p->file != NULL) + { + int res = fclose(p->file); + if (res != 0) + { + if (res == EOF) + return errno; + return res; + } + p->file = NULL; + } + + #else + + if (p->fd != -1) + { + if (close(p->fd) != 0) + return errno; + p->fd = -1; + } + + #endif + + return 0; +} + + +WRes File_Read(CSzFile *p, void *data, size_t *size) +{ + size_t originalSize = *size; + *size = 0; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + do + { + const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); + data = (void *)((Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + // debug : we can break here for partial reading mode + if (processed == 0) + break; + } + while (originalSize > 0); + + #elif defined(USE_FOPEN) + + do + { + const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; + const size_t processed = fread(data, 1, curSize, p->file); + data = (void *)((Byte *)data + (size_t)processed); + originalSize -= processed; + *size += processed; + if (processed != curSize) + return ferror(p->file); + // debug : we can break here for partial reading mode + if (processed == 0) + break; + } + while (originalSize > 0); + + #else + + do + { + const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; + const ssize_t processed = read(p->fd, data, curSize); + if (processed == -1) + return errno; + if (processed == 0) + break; + data = (void *)((Byte *)data + (size_t)processed); + originalSize -= (size_t)processed; + *size += (size_t)processed; + // debug : we can break here for partial reading mode + // break; + } + while (originalSize > 0); + + #endif + + return 0; +} + + +WRes File_Write(CSzFile *p, const void *data, size_t *size) +{ + size_t originalSize = *size; + *size = 0; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + do + { + const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); + data = (const void *)((const Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + + #elif defined(USE_FOPEN) + + do + { + const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; + const size_t processed = fwrite(data, 1, curSize, p->file); + data = (void *)((Byte *)data + (size_t)processed); + originalSize -= processed; + *size += processed; + if (processed != curSize) + return ferror(p->file); + if (processed == 0) + break; + } + while (originalSize > 0); + + #else + + do + { + const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; + const ssize_t processed = write(p->fd, data, curSize); + if (processed == -1) + return errno; + if (processed == 0) + break; + data = (const void *)((const Byte *)data + (size_t)processed); + originalSize -= (size_t)processed; + *size += (size_t)processed; + } + while (originalSize > 0); + + #endif + + return 0; +} + + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) +{ + #ifdef USE_WINDOWS_FILE + + DWORD moveMethod; + UInt32 low = (UInt32)*pos; + LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ + // (int) to eliminate clang warning + switch ((int)origin) + { + case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; + case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; + case SZ_SEEK_END: moveMethod = FILE_END; break; + default: return ERROR_INVALID_PARAMETER; + } + low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod); + if (low == (UInt32)0xFFFFFFFF) + { + WRes res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *pos = ((Int64)high << 32) | low; + return 0; + + #else + + int moveMethod; // = origin; + + switch ((int)origin) + { + case SZ_SEEK_SET: moveMethod = SEEK_SET; break; + case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; + case SZ_SEEK_END: moveMethod = SEEK_END; break; + default: return EINVAL; + } + + #if defined(USE_FOPEN) + { + int res = fseek(p->file, (long)*pos, moveMethod); + if (res == -1) + return errno; + *pos = ftell(p->file); + if (*pos == -1) + return errno; + return 0; + } + #else + { + off_t res = lseek(p->fd, (off_t)*pos, moveMethod); + if (res == -1) + return errno; + *pos = res; + return 0; + } + + #endif // USE_FOPEN + #endif // USE_WINDOWS_FILE +} + + +WRes File_GetLength(CSzFile *p, UInt64 *length) +{ + #ifdef USE_WINDOWS_FILE + + DWORD sizeHigh; + DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); + if (sizeLow == 0xFFFFFFFF) + { + DWORD res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *length = (((UInt64)sizeHigh) << 32) + sizeLow; + return 0; + + #elif defined(USE_FOPEN) + + long pos = ftell(p->file); + int res = fseek(p->file, 0, SEEK_END); + *length = ftell(p->file); + fseek(p->file, pos, SEEK_SET); + return res; + + #else + + off_t pos; + *length = 0; + pos = lseek(p->fd, 0, SEEK_CUR); + if (pos != -1) + { + const off_t len2 = lseek(p->fd, 0, SEEK_END); + const off_t res2 = lseek(p->fd, pos, SEEK_SET); + if (len2 != -1) + { + *length = (UInt64)len2; + if (res2 != -1) + return 0; + } + } + return errno; + + #endif +} + + +/* ---------- FileSeqInStream ---------- */ + +static SRes FileSeqInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileSeqInStream) + const WRes wres = File_Read(&p->file, buf, size); + p->wres = wres; + return (wres == 0) ? SZ_OK : SZ_ERROR_READ; +} + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p) +{ + p->vt.Read = FileSeqInStream_Read; +} + + +/* ---------- FileInStream ---------- */ + +static SRes FileInStream_Read(ISeekInStreamPtr pp, void *buf, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream) + const WRes wres = File_Read(&p->file, buf, size); + p->wres = wres; + return (wres == 0) ? SZ_OK : SZ_ERROR_READ; +} + +static SRes FileInStream_Seek(ISeekInStreamPtr pp, Int64 *pos, ESzSeek origin) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream) + const WRes wres = File_Seek(&p->file, pos, origin); + p->wres = wres; + return (wres == 0) ? SZ_OK : SZ_ERROR_READ; +} + +void FileInStream_CreateVTable(CFileInStream *p) +{ + p->vt.Read = FileInStream_Read; + p->vt.Seek = FileInStream_Seek; +} + + +/* ---------- FileOutStream ---------- */ + +static size_t FileOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileOutStream) + const WRes wres = File_Write(&p->file, data, &size); + p->wres = wres; + return size; +} + +void FileOutStream_CreateVTable(CFileOutStream *p) +{ + p->vt.Write = FileOutStream_Write; +} diff --git a/libraries/lzma/C/7zFile.h b/libraries/lzma/C/7zFile.h new file mode 100644 index 00000000000..f5069cd9ee2 --- /dev/null +++ b/libraries/lzma/C/7zFile.h @@ -0,0 +1,92 @@ +/* 7zFile.h -- File IO +2023-03-05 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_FILE_H +#define ZIP7_INC_FILE_H + +#ifdef _WIN32 +#define USE_WINDOWS_FILE +// #include +#endif + +#ifdef USE_WINDOWS_FILE +#include "7zWindows.h" + +#else +// note: USE_FOPEN mode is limited to 32-bit file size +// #define USE_FOPEN +// #include +#endif + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* ---------- File ---------- */ + +typedef struct +{ + #ifdef USE_WINDOWS_FILE + HANDLE handle; + #elif defined(USE_FOPEN) + FILE *file; + #else + int fd; + #endif +} CSzFile; + +void File_Construct(CSzFile *p); +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) +WRes InFile_Open(CSzFile *p, const char *name); +WRes OutFile_Open(CSzFile *p, const char *name); +#endif +#ifdef USE_WINDOWS_FILE +WRes InFile_OpenW(CSzFile *p, const WCHAR *name); +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); +#endif +WRes File_Close(CSzFile *p); + +/* reads max(*size, remain file's size) bytes */ +WRes File_Read(CSzFile *p, void *data, size_t *size); + +/* writes *size bytes */ +WRes File_Write(CSzFile *p, const void *data, size_t *size); + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); +WRes File_GetLength(CSzFile *p, UInt64 *length); + + +/* ---------- FileInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + CSzFile file; + WRes wres; +} CFileSeqInStream; + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p); + + +typedef struct +{ + ISeekInStream vt; + CSzFile file; + WRes wres; +} CFileInStream; + +void FileInStream_CreateVTable(CFileInStream *p); + + +typedef struct +{ + ISeqOutStream vt; + CSzFile file; + WRes wres; +} CFileOutStream; + +void FileOutStream_CreateVTable(CFileOutStream *p); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/7zStream.c b/libraries/lzma/C/7zStream.c index 6b5aa1621dd..74e75b65aa2 100644 --- a/libraries/lzma/C/7zStream.c +++ b/libraries/lzma/C/7zStream.c @@ -1,5 +1,5 @@ /* 7zStream.c -- 7z Stream functions -2017-04-03 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -7,12 +7,33 @@ #include "7zTypes.h" -SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType) + +SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize) +{ + size_t size = *processedSize; + *processedSize = 0; + while (size != 0) + { + size_t cur = size; + const SRes res = ISeqInStream_Read(stream, buf, &cur); + *processedSize += cur; + buf = (void *)((Byte *)buf + cur); + size -= cur; + if (res != SZ_OK) + return res; + if (cur == 0) + return SZ_OK; + } + return SZ_OK; +} + +/* +SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType) { while (size != 0) { size_t processed = size; - RINOK(ISeqInStream_Read(stream, buf, &processed)); + RINOK(ISeqInStream_Read(stream, buf, &processed)) if (processed == 0) return errorType; buf = (void *)((Byte *)buf + processed); @@ -21,42 +42,44 @@ SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes return SZ_OK; } -SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size) +SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size) { return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); } +*/ + -SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf) +SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf) { size_t processed = 1; - RINOK(ISeqInStream_Read(stream, buf, &processed)); + RINOK(ISeqInStream_Read(stream, buf, &processed)) return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; } -SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset) +SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset) { - Int64 t = offset; + Int64 t = (Int64)offset; return ILookInStream_Seek(stream, &t, SZ_SEEK_SET); } -SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size) +SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size) { const void *lookBuf; if (*size == 0) return SZ_OK; - RINOK(ILookInStream_Look(stream, &lookBuf, size)); + RINOK(ILookInStream_Look(stream, &lookBuf, size)) memcpy(buf, lookBuf, *size); return ILookInStream_Skip(stream, *size); } -SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType) +SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType) { while (size != 0) { size_t processed = size; - RINOK(ILookInStream_Read(stream, buf, &processed)); + RINOK(ILookInStream_Read(stream, buf, &processed)) if (processed == 0) return errorType; buf = (void *)((Byte *)buf + processed); @@ -65,16 +88,16 @@ SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRe return SZ_OK; } -SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size) +SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size) { return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); } -#define GET_LookToRead2 CLookToRead2 *p = CONTAINER_FROM_VTBL(pp, CLookToRead2, vt); +#define GET_LookToRead2 Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLookToRead2) -static SRes LookToRead2_Look_Lookahead(const ILookInStream *pp, const void **buf, size_t *size) +static SRes LookToRead2_Look_Lookahead(ILookInStreamPtr pp, const void **buf, size_t *size) { SRes res = SZ_OK; GET_LookToRead2 @@ -93,7 +116,7 @@ static SRes LookToRead2_Look_Lookahead(const ILookInStream *pp, const void **buf return res; } -static SRes LookToRead2_Look_Exact(const ILookInStream *pp, const void **buf, size_t *size) +static SRes LookToRead2_Look_Exact(ILookInStreamPtr pp, const void **buf, size_t *size) { SRes res = SZ_OK; GET_LookToRead2 @@ -113,14 +136,14 @@ static SRes LookToRead2_Look_Exact(const ILookInStream *pp, const void **buf, si return res; } -static SRes LookToRead2_Skip(const ILookInStream *pp, size_t offset) +static SRes LookToRead2_Skip(ILookInStreamPtr pp, size_t offset) { GET_LookToRead2 p->pos += offset; return SZ_OK; } -static SRes LookToRead2_Read(const ILookInStream *pp, void *buf, size_t *size) +static SRes LookToRead2_Read(ILookInStreamPtr pp, void *buf, size_t *size) { GET_LookToRead2 size_t rem = p->size - p->pos; @@ -134,7 +157,7 @@ static SRes LookToRead2_Read(const ILookInStream *pp, void *buf, size_t *size) return SZ_OK; } -static SRes LookToRead2_Seek(const ILookInStream *pp, Int64 *pos, ESzSeek origin) +static SRes LookToRead2_Seek(ILookInStreamPtr pp, Int64 *pos, ESzSeek origin) { GET_LookToRead2 p->pos = p->size = 0; @@ -153,9 +176,9 @@ void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead) -static SRes SecToLook_Read(const ISeqInStream *pp, void *buf, size_t *size) +static SRes SecToLook_Read(ISeqInStreamPtr pp, void *buf, size_t *size) { - CSecToLook *p = CONTAINER_FROM_VTBL(pp, CSecToLook, vt); + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToLook) return LookInStream_LookRead(p->realStream, buf, size); } @@ -164,9 +187,9 @@ void SecToLook_CreateVTable(CSecToLook *p) p->vt.Read = SecToLook_Read; } -static SRes SecToRead_Read(const ISeqInStream *pp, void *buf, size_t *size) +static SRes SecToRead_Read(ISeqInStreamPtr pp, void *buf, size_t *size) { - CSecToRead *p = CONTAINER_FROM_VTBL(pp, CSecToRead, vt); + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToRead) return ILookInStream_Read(p->realStream, buf, size); } diff --git a/libraries/lzma/C/7zTypes.h b/libraries/lzma/C/7zTypes.h index 65b3af63c75..1fcb2473e18 100644 --- a/libraries/lzma/C/7zTypes.h +++ b/libraries/lzma/C/7zTypes.h @@ -1,11 +1,13 @@ /* 7zTypes.h -- Basic types -2018-08-04 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ -#ifndef __7Z_TYPES_H -#define __7Z_TYPES_H +#ifndef ZIP7_7Z_TYPES_H +#define ZIP7_7Z_TYPES_H #ifdef _WIN32 /* #include */ +#else +#include #endif #include @@ -43,31 +45,134 @@ EXTERN_C_BEGIN typedef int SRes; +#ifdef _MSC_VER + #if _MSC_VER > 1200 + #define MY_ALIGN(n) __declspec(align(n)) + #else + #define MY_ALIGN(n) + #endif +#else + /* + // C11/C++11: + #include + #define MY_ALIGN(n) alignas(n) + */ + #define MY_ALIGN(n) __attribute__ ((aligned(n))) +#endif + + #ifdef _WIN32 /* typedef DWORD WRes; */ typedef unsigned WRes; #define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x) -#else +// #define MY_HRES_ERROR_INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR) +#else // _WIN32 + +// #define ENV_HAVE_LSTAT typedef int WRes; -#define MY__FACILITY_WIN32 7 -#define MY__FACILITY__WRes MY__FACILITY_WIN32 -#define MY_SRes_HRESULT_FROM_WRes(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (MY__FACILITY__WRes << 16) | 0x80000000))) + +// (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT +#define MY_FACILITY_ERRNO 0x800 +#define MY_FACILITY_WIN32 7 +#define MY_FACILITY_WRes MY_FACILITY_ERRNO + +#define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \ + ( (HRESULT)(x) & 0x0000FFFF) \ + | (MY_FACILITY_WRes << 16) \ + | (HRESULT)0x80000000 )) + +#define MY_SRes_HRESULT_FROM_WRes(x) \ + ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x)) + +// we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno) +#define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x) + +/* +#define ERROR_FILE_NOT_FOUND 2L +#define ERROR_ACCESS_DENIED 5L +#define ERROR_NO_MORE_FILES 18L +#define ERROR_LOCK_VIOLATION 33L +#define ERROR_FILE_EXISTS 80L +#define ERROR_DISK_FULL 112L +#define ERROR_NEGATIVE_SEEK 131L +#define ERROR_ALREADY_EXISTS 183L +#define ERROR_DIRECTORY 267L +#define ERROR_TOO_MANY_POSTS 298L + +#define ERROR_INTERNAL_ERROR 1359L +#define ERROR_INVALID_REPARSE_DATA 4392L +#define ERROR_REPARSE_TAG_INVALID 4393L +#define ERROR_REPARSE_TAG_MISMATCH 4394L +*/ + +// we use errno equivalents for some WIN32 errors: + +#define ERROR_INVALID_PARAMETER EINVAL +#define ERROR_INVALID_FUNCTION EINVAL +#define ERROR_ALREADY_EXISTS EEXIST +#define ERROR_FILE_EXISTS EEXIST +#define ERROR_PATH_NOT_FOUND ENOENT +#define ERROR_FILE_NOT_FOUND ENOENT +#define ERROR_DISK_FULL ENOSPC +// #define ERROR_INVALID_HANDLE EBADF + +// we use FACILITY_WIN32 for errors that has no errno equivalent +// Too many posts were made to a semaphore. +#define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL) +#define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L) +#define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L) + +// if (MY_FACILITY_WRes != FACILITY_WIN32), +// we use FACILITY_WIN32 for COM errors: +#define E_OUTOFMEMORY ((HRESULT)0x8007000EL) +#define E_INVALIDARG ((HRESULT)0x80070057L) +#define MY_E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L) + +/* +// we can use FACILITY_ERRNO for some COM errors, that have errno equivalents: +#define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM) +#define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) +#define MY_E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) +*/ + +#define TEXT(quote) quote + +#define FILE_ATTRIBUTE_READONLY 0x0001 +#define FILE_ATTRIBUTE_HIDDEN 0x0002 +#define FILE_ATTRIBUTE_SYSTEM 0x0004 +#define FILE_ATTRIBUTE_DIRECTORY 0x0010 +#define FILE_ATTRIBUTE_ARCHIVE 0x0020 +#define FILE_ATTRIBUTE_DEVICE 0x0040 +#define FILE_ATTRIBUTE_NORMAL 0x0080 +#define FILE_ATTRIBUTE_TEMPORARY 0x0100 +#define FILE_ATTRIBUTE_SPARSE_FILE 0x0200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400 +#define FILE_ATTRIBUTE_COMPRESSED 0x0800 +#define FILE_ATTRIBUTE_OFFLINE 0x1000 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000 +#define FILE_ATTRIBUTE_ENCRYPTED 0x4000 + +#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */ #endif #ifndef RINOK -#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#define RINOK(x) { const int _result_ = (x); if (_result_ != 0) return _result_; } +#endif + +#ifndef RINOK_WRes +#define RINOK_WRes(x) { const WRes _result_ = (x); if (_result_ != 0) return _result_; } #endif typedef unsigned char Byte; typedef short Int16; typedef unsigned short UInt16; -#ifdef _LZMA_UINT32_IS_ULONG +#ifdef Z7_DECL_Int32_AS_long typedef long Int32; typedef unsigned long UInt32; #else @@ -75,34 +180,82 @@ typedef int Int32; typedef unsigned int UInt32; #endif -#ifdef _SZ_NO_INT_64 -/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. - NOTES: Some code will work incorrectly in that case! */ +#ifndef _WIN32 + +typedef int INT; +typedef Int32 INT32; +typedef unsigned int UINT; +typedef UInt32 UINT32; +typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility +typedef UINT32 ULONG; + +#undef DWORD +typedef UINT32 DWORD; + +#define VOID void + +#define HRESULT LONG + +typedef void *LPVOID; +// typedef void VOID; +// typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; +// gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits) +typedef long INT_PTR; +typedef unsigned long UINT_PTR; +typedef long LONG_PTR; +typedef unsigned long DWORD_PTR; + +typedef size_t SIZE_T; + +#endif // _WIN32 + + +#define MY_HRES_ERROR_INTERNAL_ERROR ((HRESULT)0x8007054FL) + + +#ifdef Z7_DECL_Int64_AS_long typedef long Int64; typedef unsigned long UInt64; #else -#if defined(_MSC_VER) || defined(__BORLANDC__) +#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__clang__) typedef __int64 Int64; typedef unsigned __int64 UInt64; -#define UINT64_CONST(n) n +#else +#if defined(__clang__) || defined(__GNUC__) +#include +typedef int64_t Int64; +typedef uint64_t UInt64; #else typedef long long int Int64; typedef unsigned long long int UInt64; -#define UINT64_CONST(n) n ## ULL +// #define UINT64_CONST(n) n ## ULL +#endif #endif #endif -#ifdef _LZMA_NO_SYSTEM_SIZE_T -typedef UInt32 SizeT; +#define UINT64_CONST(n) n + + +#ifdef Z7_DECL_SizeT_AS_unsigned_int +typedef unsigned int SizeT; #else typedef size_t SizeT; #endif +/* +#if (defined(_MSC_VER) && _MSC_VER <= 1200) +typedef size_t MY_uintptr_t; +#else +#include +typedef uintptr_t MY_uintptr_t; +#endif +*/ + typedef int BoolInt; /* typedef BoolInt Bool; */ #define True 1 @@ -110,81 +263,99 @@ typedef int BoolInt; #ifdef _WIN32 -#define MY_STD_CALL __stdcall +#define Z7_STDCALL __stdcall #else -#define MY_STD_CALL +#define Z7_STDCALL #endif #ifdef _MSC_VER #if _MSC_VER >= 1300 -#define MY_NO_INLINE __declspec(noinline) +#define Z7_NO_INLINE __declspec(noinline) #else -#define MY_NO_INLINE +#define Z7_NO_INLINE #endif -#define MY_FORCE_INLINE __forceinline +#define Z7_FORCE_INLINE __forceinline -#define MY_CDECL __cdecl -#define MY_FAST_CALL __fastcall +#define Z7_CDECL __cdecl +#define Z7_FASTCALL __fastcall -#else +#else // _MSC_VER -#define MY_NO_INLINE -#define MY_FORCE_INLINE -#define MY_CDECL -#define MY_FAST_CALL +#if (defined(__GNUC__) && (__GNUC__ >= 4)) \ + || (defined(__clang__) && (__clang_major__ >= 4)) \ + || defined(__INTEL_COMPILER) \ + || defined(__xlC__) +#define Z7_NO_INLINE __attribute__((noinline)) +#define Z7_FORCE_INLINE __attribute__((always_inline)) inline +#else +#define Z7_NO_INLINE +#define Z7_FORCE_INLINE +#endif -/* inline keyword : for C++ / C99 */ +#define Z7_CDECL -/* GCC, clang: */ -/* -#if defined (__GNUC__) && (__GNUC__ >= 4) -#define MY_FORCE_INLINE __attribute__((always_inline)) -#define MY_NO_INLINE __attribute__((noinline)) +#if defined(_M_IX86) \ + || defined(__i386__) +// #define Z7_FASTCALL __attribute__((fastcall)) +// #define Z7_FASTCALL __attribute__((cdecl)) +#define Z7_FASTCALL +#elif defined(MY_CPU_AMD64) +// #define Z7_FASTCALL __attribute__((ms_abi)) +#define Z7_FASTCALL +#else +#define Z7_FASTCALL #endif -*/ -#endif +#endif // _MSC_VER /* The following interfaces use first parameter as pointer to structure */ -typedef struct IByteIn IByteIn; -struct IByteIn +// #define Z7_C_IFACE_CONST_QUAL +#define Z7_C_IFACE_CONST_QUAL const + +#define Z7_C_IFACE_DECL(a) \ + struct a ## _; \ + typedef Z7_C_IFACE_CONST_QUAL struct a ## _ * a ## Ptr; \ + typedef struct a ## _ a; \ + struct a ## _ + + +Z7_C_IFACE_DECL (IByteIn) { - Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */ + Byte (*Read)(IByteInPtr p); /* reads one byte, returns 0 in case of EOF or error */ }; #define IByteIn_Read(p) (p)->Read(p) -typedef struct IByteOut IByteOut; -struct IByteOut +Z7_C_IFACE_DECL (IByteOut) { - void (*Write)(const IByteOut *p, Byte b); + void (*Write)(IByteOutPtr p, Byte b); }; #define IByteOut_Write(p, b) (p)->Write(p, b) -typedef struct ISeqInStream ISeqInStream; -struct ISeqInStream +Z7_C_IFACE_DECL (ISeqInStream) { - SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size); + SRes (*Read)(ISeqInStreamPtr p, void *buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) < input(*size)) is allowed */ }; #define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size) +/* try to read as much as avail in stream and limited by (*processedSize) */ +SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize); /* it can return SZ_ERROR_INPUT_EOF */ -SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size); -SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType); -SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf); +// SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size); +// SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf); -typedef struct ISeqOutStream ISeqOutStream; -struct ISeqOutStream +Z7_C_IFACE_DECL (ISeqOutStream) { - size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size); + size_t (*Write)(ISeqOutStreamPtr p, const void *buf, size_t size); /* Returns: result - the number of actually written bytes. (result < size) means error */ }; @@ -198,29 +369,26 @@ typedef enum } ESzSeek; -typedef struct ISeekInStream ISeekInStream; -struct ISeekInStream +Z7_C_IFACE_DECL (ISeekInStream) { - SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ - SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin); + SRes (*Read)(ISeekInStreamPtr p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(ISeekInStreamPtr p, Int64 *pos, ESzSeek origin); }; #define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size) #define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) -typedef struct ILookInStream ILookInStream; -struct ILookInStream +Z7_C_IFACE_DECL (ILookInStream) { - SRes (*Look)(const ILookInStream *p, const void **buf, size_t *size); + SRes (*Look)(ILookInStreamPtr p, const void **buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) > input(*size)) is not allowed (output(*size) < input(*size)) is allowed */ - SRes (*Skip)(const ILookInStream *p, size_t offset); + SRes (*Skip)(ILookInStreamPtr p, size_t offset); /* offset must be <= output(*size) of Look */ - - SRes (*Read)(const ILookInStream *p, void *buf, size_t *size); + SRes (*Read)(ILookInStreamPtr p, void *buf, size_t *size); /* reads directly (without buffer). It's same as ISeqInStream::Read */ - SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin); + SRes (*Seek)(ILookInStreamPtr p, Int64 *pos, ESzSeek origin); }; #define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size) @@ -229,19 +397,18 @@ struct ILookInStream #define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) -SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size); -SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset); +SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset); /* reads via ILookInStream::Read */ -SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType); -SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size); - +SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size); typedef struct { ILookInStream vt; - const ISeekInStream *realStream; + ISeekInStreamPtr realStream; size_t pos; size_t size; /* it's data size */ @@ -253,13 +420,13 @@ typedef struct void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead); -#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; } +#define LookToRead2_INIT(p) { (p)->pos = (p)->size = 0; } typedef struct { ISeqInStream vt; - const ILookInStream *realStream; + ILookInStreamPtr realStream; } CSecToLook; void SecToLook_CreateVTable(CSecToLook *p); @@ -269,20 +436,19 @@ void SecToLook_CreateVTable(CSecToLook *p); typedef struct { ISeqInStream vt; - const ILookInStream *realStream; + ILookInStreamPtr realStream; } CSecToRead; void SecToRead_CreateVTable(CSecToRead *p); -typedef struct ICompressProgress ICompressProgress; - -struct ICompressProgress +Z7_C_IFACE_DECL (ICompressProgress) { - SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize); + SRes (*Progress)(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize); /* Returns: result. (result != SZ_OK) means break. Value (UInt64)(Int64)-1 for size means unknown value. */ }; + #define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize) @@ -320,13 +486,13 @@ struct ISzAlloc -#ifndef MY_container_of +#ifndef Z7_container_of /* -#define MY_container_of(ptr, type, m) container_of(ptr, type, m) -#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) -#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) -#define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) +#define Z7_container_of(ptr, type, m) container_of(ptr, type, m) +#define Z7_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) +#define Z7_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) +#define Z7_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) */ /* @@ -335,23 +501,63 @@ struct ISzAlloc GCC 4.8.1 : classes with non-public variable members" */ -#define MY_container_of(ptr, type, m) ((type *)((char *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m))) +#define Z7_container_of(ptr, type, m) \ + ((type *)(void *)((char *)(void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) + +#define Z7_container_of_CONST(ptr, type, m) \ + ((const type *)(const void *)((const char *)(const void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) +/* +#define Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) \ + ((type *)(void *)(const void *)((const char *)(const void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) +*/ #endif -#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(ptr)) +#define Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr)) -/* -#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) -*/ -#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m) +// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +#define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of(ptr, type, m) +// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) + +#define Z7_CONTAINER_FROM_VTBL_CONST(ptr, type, m) Z7_container_of_CONST(ptr, type, m) -#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) /* -#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m) +#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL(ptr, type, m) */ +#if defined (__clang__) || defined(__GNUC__) +#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#define Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL \ + _Pragma("GCC diagnostic pop") +#else +#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL +#define Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL +#endif + +#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(ptr, type, m, p) \ + Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL \ + type *p = Z7_CONTAINER_FROM_VTBL(ptr, type, m); \ + Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL + +#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(type) \ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(pp, type, vt, p) + +// #define ZIP7_DECLARE_HANDLE(name) typedef void *name; +#define Z7_DECLARE_HANDLE(name) struct name##_dummy{int unused;}; typedef struct name##_dummy *name; + + +#define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a)) + +#ifndef Z7_ARRAY_SIZE +#define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif #ifdef _WIN32 @@ -370,6 +576,22 @@ struct ISzAlloc #endif +#define k_PropVar_TimePrec_0 0 +#define k_PropVar_TimePrec_Unix 1 +#define k_PropVar_TimePrec_DOS 2 +#define k_PropVar_TimePrec_HighPrec 3 +#define k_PropVar_TimePrec_Base 16 +#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7) +#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9) + EXTERN_C_END #endif + +/* +#ifndef Z7_ST +#ifdef _7ZIP_ST +#define Z7_ST +#endif +#endif +*/ diff --git a/libraries/lzma/C/7zVersion.h b/libraries/lzma/C/7zVersion.h index c176823a4dd..7549239614e 100644 --- a/libraries/lzma/C/7zVersion.h +++ b/libraries/lzma/C/7zVersion.h @@ -1,7 +1,7 @@ -#define MY_VER_MAJOR 19 -#define MY_VER_MINOR 00 +#define MY_VER_MAJOR 23 +#define MY_VER_MINOR 01 #define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "19.00" +#define MY_VERSION_NUMBERS "23.01" #define MY_VERSION MY_VERSION_NUMBERS #ifdef MY_CPU_NAME @@ -10,12 +10,12 @@ #define MY_VERSION_CPU MY_VERSION #endif -#define MY_DATE "2019-02-21" +#define MY_DATE "2023-06-20" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_AUTHOR_NAME "Igor Pavlov" #define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" -#define MY_COPYRIGHT_CR "Copyright (c) 1999-2018 Igor Pavlov" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2023 Igor Pavlov" #ifdef USE_COPYRIGHT_CR #define MY_COPYRIGHT MY_COPYRIGHT_CR diff --git a/libraries/lzma/C/7zWindows.h b/libraries/lzma/C/7zWindows.h new file mode 100644 index 00000000000..42c6db8bfc2 --- /dev/null +++ b/libraries/lzma/C/7zWindows.h @@ -0,0 +1,101 @@ +/* 7zWindows.h -- StdAfx +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_7Z_WINDOWS_H +#define ZIP7_INC_7Z_WINDOWS_H + +#ifdef _WIN32 + +#if defined(__clang__) +# pragma clang diagnostic push +#endif + +#if defined(_MSC_VER) + +#pragma warning(push) +#pragma warning(disable : 4668) // '_WIN32_WINNT' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + +#if _MSC_VER == 1900 +// for old kit10 versions +// #pragma warning(disable : 4255) // winuser.h(13979): warning C4255: 'GetThreadDpiAwarenessContext': +#endif +// win10 Windows Kit: +#endif // _MSC_VER + +#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64) +// for msvc6 without sdk2003 +#define RPC_NO_WINDOWS_H +#endif + +#if defined(__MINGW32__) || defined(__MINGW64__) +// #if defined(__GNUC__) && !defined(__clang__) +#include +#else +#include +#endif +// #include +// #include + +// but if precompiled with clang-cl then we need +// #include +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64) +#ifndef _W64 + +typedef long LONG_PTR, *PLONG_PTR; +typedef unsigned long ULONG_PTR, *PULONG_PTR; +typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; + +#define Z7_OLD_WIN_SDK +#endif // _W64 +#endif // _MSC_VER == 1200 + +#ifdef Z7_OLD_WIN_SDK + +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif +#ifndef FILE_SPECIAL_ACCESS +#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#endif + +// ShlObj.h: +// #define BIF_NEWDIALOGSTYLE 0x0040 + +#pragma warning(disable : 4201) +// #pragma warning(disable : 4115) + +#undef VARIANT_TRUE +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#endif + +#endif // Z7_OLD_WIN_SDK + +#ifdef UNDER_CE +#undef VARIANT_TRUE +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#endif + + +#if defined(_MSC_VER) +#if _MSC_VER >= 1400 && _MSC_VER <= 1600 + // BaseTsd.h(148) : 'HandleToULong' : unreferenced inline function has been removed + // string.h + // #pragma warning(disable : 4514) +#endif +#endif + + +/* #include "7zTypes.h" */ + +#endif diff --git a/libraries/lzma/C/Alloc.c b/libraries/lzma/C/Alloc.c new file mode 100644 index 00000000000..d841bf20a35 --- /dev/null +++ b/libraries/lzma/C/Alloc.c @@ -0,0 +1,535 @@ +/* Alloc.c -- Memory allocation functions +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifdef _WIN32 +#include "7zWindows.h" +#endif +#include + +#include "Alloc.h" + +#ifdef _WIN32 +#ifdef Z7_LARGE_PAGES +#if defined(__clang__) || defined(__GNUC__) +typedef void (*Z7_voidFunction)(void); +#define MY_CAST_FUNC (Z7_voidFunction) +#elif defined(_MSC_VER) && _MSC_VER > 1920 +#define MY_CAST_FUNC (void *) +// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()' +#else +#define MY_CAST_FUNC +#endif +#endif // Z7_LARGE_PAGES +#endif // _WIN32 + +// #define SZ_ALLOC_DEBUG +/* #define SZ_ALLOC_DEBUG */ + +/* use SZ_ALLOC_DEBUG to debug alloc/free operations */ +#ifdef SZ_ALLOC_DEBUG + +#include +#include +static int g_allocCount = 0; +#ifdef _WIN32 +static int g_allocCountMid = 0; +static int g_allocCountBig = 0; +#endif + + +#define CONVERT_INT_TO_STR(charType, tempSize) \ + char temp[tempSize]; unsigned i = 0; \ + while (val >= 10) { temp[i++] = (char)('0' + (unsigned)(val % 10)); val /= 10; } \ + *s++ = (charType)('0' + (unsigned)val); \ + while (i != 0) { i--; *s++ = temp[i]; } \ + *s = 0; + +static void ConvertUInt64ToString(UInt64 val, char *s) +{ + CONVERT_INT_TO_STR(char, 24) +} + +#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) + +static void ConvertUInt64ToHex(UInt64 val, char *s) +{ + UInt64 v = val; + unsigned i; + for (i = 1;; i++) + { + v >>= 4; + if (v == 0) + break; + } + s[i] = 0; + do + { + unsigned t = (unsigned)(val & 0xF); + val >>= 4; + s[--i] = GET_HEX_CHAR(t); + } + while (i); +} + +#define DEBUG_OUT_STREAM stderr + +static void Print(const char *s) +{ + fputs(s, DEBUG_OUT_STREAM); +} + +static void PrintAligned(const char *s, size_t align) +{ + size_t len = strlen(s); + for(;;) + { + fputc(' ', DEBUG_OUT_STREAM); + if (len >= align) + break; + ++len; + } + Print(s); +} + +static void PrintLn(void) +{ + Print("\n"); +} + +static void PrintHex(UInt64 v, size_t align) +{ + char s[32]; + ConvertUInt64ToHex(v, s); + PrintAligned(s, align); +} + +static void PrintDec(int v, size_t align) +{ + char s[32]; + ConvertUInt64ToString((unsigned)v, s); + PrintAligned(s, align); +} + +static void PrintAddr(void *p) +{ + PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12); +} + + +#define PRINT_REALLOC(name, cnt, size, ptr) { \ + Print(name " "); \ + if (!ptr) PrintDec(cnt++, 10); \ + PrintHex(size, 10); \ + PrintAddr(ptr); \ + PrintLn(); } + +#define PRINT_ALLOC(name, cnt, size, ptr) { \ + Print(name " "); \ + PrintDec(cnt++, 10); \ + PrintHex(size, 10); \ + PrintAddr(ptr); \ + PrintLn(); } + +#define PRINT_FREE(name, cnt, ptr) if (ptr) { \ + Print(name " "); \ + PrintDec(--cnt, 10); \ + PrintAddr(ptr); \ + PrintLn(); } + +#else + +#ifdef _WIN32 +#define PRINT_ALLOC(name, cnt, size, ptr) +#endif +#define PRINT_FREE(name, cnt, ptr) +#define Print(s) +#define PrintLn() +#define PrintHex(v, align) +#define PrintAddr(p) + +#endif + + +/* +by specification: + malloc(non_NULL, 0) : returns NULL or a unique pointer value that can later be successfully passed to free() + realloc(NULL, size) : the call is equivalent to malloc(size) + realloc(non_NULL, 0) : the call is equivalent to free(ptr) + +in main compilers: + malloc(0) : returns non_NULL + realloc(NULL, 0) : returns non_NULL + realloc(non_NULL, 0) : returns NULL +*/ + + +void *MyAlloc(size_t size) +{ + if (size == 0) + return NULL; + // PRINT_ALLOC("Alloc ", g_allocCount, size, NULL) + #ifdef SZ_ALLOC_DEBUG + { + void *p = malloc(size); + if (p) + { + PRINT_ALLOC("Alloc ", g_allocCount, size, p) + } + return p; + } + #else + return malloc(size); + #endif +} + +void MyFree(void *address) +{ + PRINT_FREE("Free ", g_allocCount, address) + + free(address); +} + +void *MyRealloc(void *address, size_t size) +{ + if (size == 0) + { + MyFree(address); + return NULL; + } + // PRINT_REALLOC("Realloc ", g_allocCount, size, address) + #ifdef SZ_ALLOC_DEBUG + { + void *p = realloc(address, size); + if (p) + { + PRINT_REALLOC("Realloc ", g_allocCount, size, address) + } + return p; + } + #else + return realloc(address, size); + #endif +} + + +#ifdef _WIN32 + +void *MidAlloc(size_t size) +{ + if (size == 0) + return NULL; + #ifdef SZ_ALLOC_DEBUG + { + void *p = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); + if (p) + { + PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, p) + } + return p; + } + #else + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); + #endif +} + +void MidFree(void *address) +{ + PRINT_FREE("Free-Mid", g_allocCountMid, address) + + if (!address) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#ifdef Z7_LARGE_PAGES + +#ifdef MEM_LARGE_PAGES + #define MY__MEM_LARGE_PAGES MEM_LARGE_PAGES +#else + #define MY__MEM_LARGE_PAGES 0x20000000 +#endif + +extern +SIZE_T g_LargePageSize; +SIZE_T g_LargePageSize = 0; +typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID); + +void SetLargePageSize(void) +{ + #ifdef Z7_LARGE_PAGES + SIZE_T size; + const + Func_GetLargePageMinimum fn = + (Func_GetLargePageMinimum) MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), + "GetLargePageMinimum"); + if (!fn) + return; + size = fn(); + if (size == 0 || (size & (size - 1)) != 0) + return; + g_LargePageSize = size; + #endif +} + +#endif // Z7_LARGE_PAGES + +void *BigAlloc(size_t size) +{ + if (size == 0) + return NULL; + + PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL) + + #ifdef Z7_LARGE_PAGES + { + SIZE_T ps = g_LargePageSize; + if (ps != 0 && ps <= (1 << 30) && size > (ps / 2)) + { + size_t size2; + ps--; + size2 = (size + ps) & ~ps; + if (size2 >= size) + { + void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY__MEM_LARGE_PAGES, PAGE_READWRITE); + if (p) + { + PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p) + return p; + } + } + } + } + #endif + + return MidAlloc(size); +} + +void BigFree(void *address) +{ + PRINT_FREE("Free-Big", g_allocCountBig, address) + MidFree(address); +} + +#endif // _WIN32 + + +static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MyAlloc(size); } +static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MyFree(address); } +const ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +#ifdef _WIN32 +static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); } +static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); } +static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); } +static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); } +const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree }; +const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; +#endif + +/* + uintptr_t : C99 (optional) + : unsupported in VS6 +*/ + +#ifdef _WIN32 + typedef UINT_PTR UIntPtr; +#else + /* + typedef uintptr_t UIntPtr; + */ + typedef ptrdiff_t UIntPtr; +#endif + + +#define ADJUST_ALLOC_SIZE 0 +/* +#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1) +*/ +/* + Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if + MyAlloc() can return address that is NOT multiple of sizeof(void *). +*/ + + +/* +#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1)))) +*/ +#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1)))) + + +#if !defined(_WIN32) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) + #define USE_posix_memalign +#endif + +#ifndef USE_posix_memalign +#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align) +#endif + +/* + This posix_memalign() is for test purposes only. + We also need special Free() function instead of free(), + if this posix_memalign() is used. +*/ + +/* +static int posix_memalign(void **ptr, size_t align, size_t size) +{ + size_t newSize = size + align; + void *p; + void *pAligned; + *ptr = NULL; + if (newSize < size) + return 12; // ENOMEM + p = MyAlloc(newSize); + if (!p) + return 12; // ENOMEM + pAligned = MY_ALIGN_PTR_UP_PLUS(p, align); + ((void **)pAligned)[-1] = p; + *ptr = pAligned; + return 0; +} +*/ + +/* + ALLOC_ALIGN_SIZE >= sizeof(void *) + ALLOC_ALIGN_SIZE >= cache_line_size +*/ + +#define ALLOC_ALIGN_SIZE ((size_t)1 << 7) + +static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size) +{ + #ifndef USE_posix_memalign + + void *p; + void *pAligned; + size_t newSize; + UNUSED_VAR(pp) + + /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned + block to prevent cache line sharing with another allocated blocks */ + + newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE; + if (newSize < size) + return NULL; + + p = MyAlloc(newSize); + + if (!p) + return NULL; + pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE); + + Print(" size="); PrintHex(size, 8); + Print(" a_size="); PrintHex(newSize, 8); + Print(" ptr="); PrintAddr(p); + Print(" a_ptr="); PrintAddr(pAligned); + PrintLn(); + + ((void **)pAligned)[-1] = p; + + return pAligned; + + #else + + void *p; + UNUSED_VAR(pp) + if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size)) + return NULL; + + Print(" posix_memalign="); PrintAddr(p); + PrintLn(); + + return p; + + #endif +} + + +static void SzAlignedFree(ISzAllocPtr pp, void *address) +{ + UNUSED_VAR(pp) + #ifndef USE_posix_memalign + if (address) + MyFree(((void **)address)[-1]); + #else + free(address); + #endif +} + + +const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree }; + + + +#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *)) + +/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */ +#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1] +/* +#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1] +*/ + +static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size) +{ + const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt); + void *adr; + void *pAligned; + size_t newSize; + size_t extra; + size_t alignSize = (size_t)1 << p->numAlignBits; + + if (alignSize < sizeof(void *)) + alignSize = sizeof(void *); + + if (p->offset >= alignSize) + return NULL; + + /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned + block to prevent cache line sharing with another allocated blocks */ + extra = p->offset & (sizeof(void *) - 1); + newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE; + if (newSize < size) + return NULL; + + adr = ISzAlloc_Alloc(p->baseAlloc, newSize); + + if (!adr) + return NULL; + + pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr + + alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset; + + PrintLn(); + Print("- Aligned: "); + Print(" size="); PrintHex(size, 8); + Print(" a_size="); PrintHex(newSize, 8); + Print(" ptr="); PrintAddr(adr); + Print(" a_ptr="); PrintAddr(pAligned); + PrintLn(); + + REAL_BLOCK_PTR_VAR(pAligned) = adr; + + return pAligned; +} + + +static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address) +{ + if (address) + { + const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt); + PrintLn(); + Print("- Aligned Free: "); + PrintLn(); + ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address)); + } +} + + +void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p) +{ + p->vt.Alloc = AlignOffsetAlloc_Alloc; + p->vt.Free = AlignOffsetAlloc_Free; +} diff --git a/libraries/lzma/C/Alloc.h b/libraries/lzma/C/Alloc.h new file mode 100644 index 00000000000..fac5b62fb9f --- /dev/null +++ b/libraries/lzma/C/Alloc.h @@ -0,0 +1,71 @@ +/* Alloc.h -- Memory allocation functions +2023-03-04 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_ALLOC_H +#define ZIP7_INC_ALLOC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* + MyFree(NULL) : is allowed, as free(NULL) + MyAlloc(0) : returns NULL : but malloc(0) is allowed to return NULL or non_NULL + MyRealloc(NULL, 0) : returns NULL : but realloc(NULL, 0) is allowed to return NULL or non_NULL +MyRealloc() is similar to realloc() for the following cases: + MyRealloc(non_NULL, 0) : returns NULL and always calls MyFree(ptr) + MyRealloc(NULL, non_ZERO) : returns NULL, if allocation failed + MyRealloc(non_NULL, non_ZERO) : returns NULL, if reallocation failed +*/ + +void *MyAlloc(size_t size); +void MyFree(void *address); +void *MyRealloc(void *address, size_t size); + +#ifdef _WIN32 + +#ifdef Z7_LARGE_PAGES +void SetLargePageSize(void); +#endif + +void *MidAlloc(size_t size); +void MidFree(void *address); +void *BigAlloc(size_t size); +void BigFree(void *address); + +#else + +#define MidAlloc(size) MyAlloc(size) +#define MidFree(address) MyFree(address) +#define BigAlloc(size) MyAlloc(size) +#define BigFree(address) MyFree(address) + +#endif + +extern const ISzAlloc g_Alloc; + +#ifdef _WIN32 +extern const ISzAlloc g_BigAlloc; +extern const ISzAlloc g_MidAlloc; +#else +#define g_BigAlloc g_AlignedAlloc +#define g_MidAlloc g_AlignedAlloc +#endif + +extern const ISzAlloc g_AlignedAlloc; + + +typedef struct +{ + ISzAlloc vt; + ISzAllocPtr baseAlloc; + unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */ + size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */ +} CAlignOffsetAlloc; + +void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p); + + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/Bcj2.c b/libraries/lzma/C/Bcj2.c index 9a0046a6508..7cb57ad62dc 100644 --- a/libraries/lzma/C/Bcj2.c +++ b/libraries/lzma/C/Bcj2.c @@ -1,29 +1,24 @@ /* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) -2018-04-28 : Igor Pavlov : Public domain */ +2023-03-01 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bcj2.h" #include "CpuArch.h" -#define CProb UInt16 - #define kTopValue ((UInt32)1 << 24) -#define kNumModelBits 11 -#define kBitModelTotal (1 << kNumModelBits) +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) #define kNumMoveBits 5 -#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound) -#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); -#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); +// UInt32 bcj2_stats[256 + 2][2]; void Bcj2Dec_Init(CBcj2Dec *p) { unsigned i; - - p->state = BCJ2_DEC_STATE_OK; + p->state = BCJ2_STREAM_RC; // BCJ2_DEC_STATE_OK; p->ip = 0; - p->temp[3] = 0; + p->temp = 0; p->range = 0; p->code = 0; for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) @@ -32,217 +27,248 @@ void Bcj2Dec_Init(CBcj2Dec *p) SRes Bcj2Dec_Decode(CBcj2Dec *p) { + UInt32 v = p->temp; + // const Byte *src; if (p->range <= 5) { - p->state = BCJ2_DEC_STATE_OK; + UInt32 code = p->code; + p->state = BCJ2_DEC_STATE_ERROR; /* for case if we return SZ_ERROR_DATA; */ for (; p->range != 5; p->range++) { - if (p->range == 1 && p->code != 0) + if (p->range == 1 && code != 0) return SZ_ERROR_DATA; - if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) { p->state = BCJ2_STREAM_RC; return SZ_OK; } - - p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + code = (code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + p->code = code; } - - if (p->code == 0xFFFFFFFF) + if (code == 0xffffffff) return SZ_ERROR_DATA; - - p->range = 0xFFFFFFFF; + p->range = 0xffffffff; } - else if (p->state >= BCJ2_DEC_STATE_ORIG_0) + // else { - while (p->state <= BCJ2_DEC_STATE_ORIG_3) + unsigned state = p->state; + // we check BCJ2_IS_32BIT_STREAM() here instead of check in the main loop + if (BCJ2_IS_32BIT_STREAM(state)) { - Byte *dest = p->dest; - if (dest == p->destLim) + const Byte *cur = p->bufs[state]; + if (cur == p->lims[state]) return SZ_OK; - *dest = p->temp[(size_t)p->state - BCJ2_DEC_STATE_ORIG_0]; - p->state++; - p->dest = dest + 1; + p->bufs[state] = cur + 4; + { + const UInt32 ip = p->ip + 4; + v = GetBe32a(cur) - ip; + p->ip = ip; + } + state = BCJ2_DEC_STATE_ORIG_0; } - } - - /* - if (BCJ2_IS_32BIT_STREAM(p->state)) - { - const Byte *cur = p->bufs[p->state]; - if (cur == p->lims[p->state]) - return SZ_OK; - p->bufs[p->state] = cur + 4; - + if ((unsigned)(state - BCJ2_DEC_STATE_ORIG_0) < 4) { - UInt32 val; - Byte *dest; - SizeT rem; - - p->ip += 4; - val = GetBe32(cur) - p->ip; - dest = p->dest; - rem = p->destLim - dest; - if (rem < 4) + Byte *dest = p->dest; + for (;;) { - SizeT i; - SetUi32(p->temp, val); - for (i = 0; i < rem; i++) - dest[i] = p->temp[i]; - p->dest = dest + rem; - p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; - return SZ_OK; + if (dest == p->destLim) + { + p->state = state; + p->temp = v; + return SZ_OK; + } + *dest++ = (Byte)v; + p->dest = dest; + if (++state == BCJ2_DEC_STATE_ORIG_3 + 1) + break; + v >>= 8; } - SetUi32(dest, val); - p->temp[3] = (Byte)(val >> 24); - p->dest = dest + 4; - p->state = BCJ2_DEC_STATE_OK; } } - */ + // src = p->bufs[BCJ2_STREAM_MAIN]; for (;;) { + /* if (BCJ2_IS_32BIT_STREAM(p->state)) p->state = BCJ2_DEC_STATE_OK; else + */ { if (p->range < kTopValue) { if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) { p->state = BCJ2_STREAM_RC; + p->temp = v; return SZ_OK; } p->range <<= 8; p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; } - { const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; const Byte *srcLim; - Byte *dest; - SizeT num = p->lims[BCJ2_STREAM_MAIN] - src; - - if (num == 0) + Byte *dest = p->dest; { - p->state = BCJ2_STREAM_MAIN; - return SZ_OK; + const SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - src); + SizeT num = (SizeT)(p->destLim - dest); + if (num >= rem) + num = rem; + #define NUM_ITERS 4 + #if (NUM_ITERS & (NUM_ITERS - 1)) == 0 + num &= ~((SizeT)NUM_ITERS - 1); // if (NUM_ITERS == (1 << x)) + #else + num -= num % NUM_ITERS; // if (NUM_ITERS != (1 << x)) + #endif + srcLim = src + num; } - - dest = p->dest; - if (num > (SizeT)(p->destLim - dest)) + + #define NUM_SHIFT_BITS 24 + #define ONE_ITER(indx) { \ + const unsigned b = src[indx]; \ + *dest++ = (Byte)b; \ + v = (v << NUM_SHIFT_BITS) | b; \ + if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \ + if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \ + ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \ + /* ++dest */; /* v = b; */ } + + if (src != srcLim) + for (;;) { - num = p->destLim - dest; - if (num == 0) - { - p->state = BCJ2_DEC_STATE_ORIG; - return SZ_OK; - } + /* The dependency chain of 2-cycle for (v) calculation is not big problem here. + But we can remove dependency chain with v = b in the end of loop. */ + ONE_ITER(0) + #if (NUM_ITERS > 1) + ONE_ITER(1) + #if (NUM_ITERS > 2) + ONE_ITER(2) + #if (NUM_ITERS > 3) + ONE_ITER(3) + #if (NUM_ITERS > 4) + ONE_ITER(4) + #if (NUM_ITERS > 5) + ONE_ITER(5) + #if (NUM_ITERS > 6) + ONE_ITER(6) + #if (NUM_ITERS > 7) + ONE_ITER(7) + #endif + #endif + #endif + #endif + #endif + #endif + #endif + + src += NUM_ITERS; + if (src == srcLim) + break; } - - srcLim = src + num; - if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) - *dest = src[0]; - else for (;;) + if (src == srcLim) + #if (NUM_ITERS > 1) + for (;;) + #endif { - Byte b = *src; - *dest = b; - if (b != 0x0F) + #if (NUM_ITERS > 1) + if (src == p->lims[BCJ2_STREAM_MAIN] || dest == p->destLim) + #endif { - if ((b & 0xFE) == 0xE8) - break; - dest++; - if (++src != srcLim) - continue; - break; + const SizeT num = (SizeT)(src - p->bufs[BCJ2_STREAM_MAIN]); + p->bufs[BCJ2_STREAM_MAIN] = src; + p->dest = dest; + p->ip += (UInt32)num; + /* state BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + p->state = + src == p->lims[BCJ2_STREAM_MAIN] ? + (unsigned)BCJ2_STREAM_MAIN : + (unsigned)BCJ2_DEC_STATE_ORIG; + p->temp = v; + return SZ_OK; } - dest++; - if (++src == srcLim) - break; - if ((*src & 0xF0) != 0x80) - continue; - *dest = *src; - break; + #if (NUM_ITERS > 1) + ONE_ITER(0) + src++; + #endif } - - num = src - p->bufs[BCJ2_STREAM_MAIN]; - - if (src == srcLim) + { - p->temp[3] = src[-1]; - p->bufs[BCJ2_STREAM_MAIN] = src; + const SizeT num = (SizeT)(dest - p->dest); + p->dest = dest; // p->dest += num; + p->bufs[BCJ2_STREAM_MAIN] += num; // = src; p->ip += (UInt32)num; - p->dest += num; - p->state = - p->bufs[BCJ2_STREAM_MAIN] == - p->lims[BCJ2_STREAM_MAIN] ? - (unsigned)BCJ2_STREAM_MAIN : - (unsigned)BCJ2_DEC_STATE_ORIG; - return SZ_OK; } - { UInt32 bound, ttt; - CProb *prob; - Byte b = src[0]; - Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); - - p->temp[3] = b; - p->bufs[BCJ2_STREAM_MAIN] = src + 1; - num++; - p->ip += (UInt32)num; - p->dest += num; - - prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); - - _IF_BIT_0 + CBcj2Prob *prob; // unsigned index; + /* + prob = p->probs + (unsigned)((Byte)v == 0xe8 ? + 2 + (Byte)(v >> 8) : + ((v >> 5) & 1)); // ((Byte)v < 0xe8 ? 0 : 1)); + */ { - _UPDATE_0 + const unsigned c = ((v + 0x17) >> 6) & 1; + prob = p->probs + (unsigned) + (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1)); + // (Byte) + // 8x->0 : e9->1 : xxe8->xx+2 + // 8x->0x100 : e9->0x101 : xxe8->xx + // (((0x100 - (e & ~v)) & (0x100 | (v >> 8))) + (e & v)); + // (((0x101 + (~e | v)) & (0x100 | (v >> 8))) + (e & v)); + } + ttt = *prob; + bound = (p->range >> kNumBitModelTotalBits) * ttt; + if (p->code < bound) + { + // bcj2_stats[prob - p->probs][0]++; + p->range = bound; + *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); continue; } - _UPDATE_1 - + { + // bcj2_stats[prob - p->probs][1]++; + p->range -= bound; + p->code -= bound; + *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits)); + } } } } - { - UInt32 val; - unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + /* (v == 0xe8 ? 0 : 1) uses setcc instruction with additional zero register usage in x64 MSVC. */ + // const unsigned cj = ((Byte)v == 0xe8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL; const Byte *cur = p->bufs[cj]; Byte *dest; SizeT rem; - if (cur == p->lims[cj]) { p->state = cj; break; } - - val = GetBe32(cur); + v = GetBe32a(cur); p->bufs[cj] = cur + 4; - - p->ip += 4; - val -= p->ip; + { + const UInt32 ip = p->ip + 4; + v -= ip; + p->ip = ip; + } dest = p->dest; - rem = p->destLim - dest; - + rem = (SizeT)(p->destLim - dest); if (rem < 4) { - p->temp[0] = (Byte)val; if (rem > 0) dest[0] = (Byte)val; val >>= 8; - p->temp[1] = (Byte)val; if (rem > 1) dest[1] = (Byte)val; val >>= 8; - p->temp[2] = (Byte)val; if (rem > 2) dest[2] = (Byte)val; val >>= 8; - p->temp[3] = (Byte)val; + if ((unsigned)rem > 0) { dest[0] = (Byte)v; v >>= 8; + if ((unsigned)rem > 1) { dest[1] = (Byte)v; v >>= 8; + if ((unsigned)rem > 2) { dest[2] = (Byte)v; v >>= 8; }}} + p->temp = v; p->dest = dest + rem; p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; break; } - - SetUi32(dest, val); - p->temp[3] = (Byte)(val >> 24); + SetUi32(dest, v) + v >>= 24; p->dest = dest + 4; } } @@ -252,6 +278,13 @@ SRes Bcj2Dec_Decode(CBcj2Dec *p) p->range <<= 8; p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; } - return SZ_OK; } + +#undef NUM_ITERS +#undef ONE_ITER +#undef NUM_SHIFT_BITS +#undef kTopValue +#undef kNumBitModelTotalBits +#undef kBitModelTotal +#undef kNumMoveBits diff --git a/libraries/lzma/C/Bcj2.h b/libraries/lzma/C/Bcj2.h index 8824080acfb..4575545b62c 100644 --- a/libraries/lzma/C/Bcj2.h +++ b/libraries/lzma/C/Bcj2.h @@ -1,8 +1,8 @@ -/* Bcj2.h -- BCJ2 Converter for x86 code -2014-11-10 : Igor Pavlov : Public domain */ +/* Bcj2.h -- BCJ2 converter for x86 code (Branch CALL/JUMP variant2) +2023-03-02 : Igor Pavlov : Public domain */ -#ifndef __BCJ2_H -#define __BCJ2_H +#ifndef ZIP7_INC_BCJ2_H +#define ZIP7_INC_BCJ2_H #include "7zTypes.h" @@ -26,37 +26,68 @@ enum BCJ2_DEC_STATE_ORIG_3, BCJ2_DEC_STATE_ORIG, - BCJ2_DEC_STATE_OK + BCJ2_DEC_STATE_ERROR /* after detected data error */ }; enum { BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, - BCJ2_ENC_STATE_OK + BCJ2_ENC_STATE_FINISHED /* it's state after fully encoded stream */ }; -#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) +/* #define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) */ +#define BCJ2_IS_32BIT_STREAM(s) ((unsigned)((unsigned)(s) - (unsigned)BCJ2_STREAM_CALL) < 2) /* CBcj2Dec / CBcj2Enc bufs sizes: BUF_SIZE(n) = lims[n] - bufs[n] -bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4: +bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be multiply of 4: (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 */ +// typedef UInt32 CBcj2Prob; +typedef UInt16 CBcj2Prob; + +/* +BCJ2 encoder / decoder internal requirements: + - If last bytes of stream contain marker (e8/e8/0f8x), then + there is also encoded symbol (0 : no conversion) in RC stream. + - One case of overlapped instructions is supported, + if last byte of converted instruction is (0f) and next byte is (8x): + marker [xx xx xx 0f] 8x + then the pair (0f 8x) is treated as marker. +*/ + +/* ---------- BCJ2 Decoder ---------- */ + /* CBcj2Dec: -dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: +(dest) is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: bufs[BCJ2_STREAM_MAIN] >= dest && - bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv + + bufs[BCJ2_STREAM_MAIN] - dest >= BUF_SIZE(BCJ2_STREAM_CALL) + BUF_SIZE(BCJ2_STREAM_JUMP) - tempReserv = 0 : for first call of Bcj2Dec_Decode - tempReserv = 4 : for any other calls of Bcj2Dec_Decode - overlap with offset = 1 is not allowed + reserve = bufs[BCJ2_STREAM_MAIN] - dest - + ( BUF_SIZE(BCJ2_STREAM_CALL) + + BUF_SIZE(BCJ2_STREAM_JUMP) ) + and additional conditions: + if (it's first call of Bcj2Dec_Decode() after Bcj2Dec_Init()) + { + (reserve != 1) : if (ver < v23.00) + } + else // if there are more than one calls of Bcj2Dec_Decode() after Bcj2Dec_Init()) + { + (reserve >= 6) : if (ver < v23.00) + (reserve >= 4) : if (ver >= v23.00) + We need that (reserve) because after first call of Bcj2Dec_Decode(), + CBcj2Dec::temp can contain up to 4 bytes for writing to (dest). + } + (reserve == 0) is allowed, if we decode full stream via single call of Bcj2Dec_Decode(). + (reserve == 0) also is allowed in case of multi-call, if we use fixed buffers, + and (reserve) is calculated from full (final) sizes of all streams before first call. */ typedef struct @@ -68,21 +99,65 @@ typedef struct unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ - UInt32 ip; - Byte temp[4]; + UInt32 ip; /* property of starting base for decoding */ + UInt32 temp; /* Byte temp[4]; */ UInt32 range; UInt32 code; - UInt16 probs[2 + 256]; + CBcj2Prob probs[2 + 256]; } CBcj2Dec; + +/* Note: + Bcj2Dec_Init() sets (CBcj2Dec::ip = 0) + if (ip != 0) property is required, the caller must set CBcj2Dec::ip after Bcj2Dec_Init() +*/ void Bcj2Dec_Init(CBcj2Dec *p); -/* Returns: SZ_OK or SZ_ERROR_DATA */ + +/* Bcj2Dec_Decode(): + returns: + SZ_OK + SZ_ERROR_DATA : if data in 5 starting bytes of BCJ2_STREAM_RC stream are not correct +*/ SRes Bcj2Dec_Decode(CBcj2Dec *p); -#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0) +/* To check that decoding was finished you can compare + sizes of processed streams with sizes known from another sources. + You must do at least one mandatory check from the two following options: + - the check for size of processed output (ORIG) stream. + - the check for size of processed input (MAIN) stream. + additional optional checks: + - the checks for processed sizes of all input streams (MAIN, CALL, JUMP, RC) + - the checks Bcj2Dec_IsMaybeFinished*() + also before actual decoding you can check that the + following condition is met for stream sizes: + ( size(ORIG) == size(MAIN) + size(CALL) + size(JUMP) ) +*/ +/* (state == BCJ2_STREAM_MAIN) means that decoder is ready for + additional input data in BCJ2_STREAM_MAIN stream. + Note that (state == BCJ2_STREAM_MAIN) is allowed for non-finished decoding. +*/ +#define Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) ((_p_)->state == BCJ2_STREAM_MAIN) +/* if the stream decoding was finished correctly, then range decoder + part of CBcj2Dec also was finished, and then (CBcj2Dec::code == 0). + Note that (CBcj2Dec::code == 0) is allowed for non-finished decoding. +*/ +#define Bcj2Dec_IsMaybeFinished_code(_p_) ((_p_)->code == 0) + +/* use Bcj2Dec_IsMaybeFinished() only as additional check + after at least one mandatory check from the two following options: + - the check for size of processed output (ORIG) stream. + - the check for size of processed input (MAIN) stream. +*/ +#define Bcj2Dec_IsMaybeFinished(_p_) ( \ + Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) && \ + Bcj2Dec_IsMaybeFinished_code(_p_)) + + + +/* ---------- BCJ2 Encoder ---------- */ typedef enum { @@ -91,6 +166,91 @@ typedef enum BCJ2_ENC_FINISH_MODE_END_STREAM } EBcj2Enc_FinishMode; +/* + BCJ2_ENC_FINISH_MODE_CONTINUE: + process non finished encoding. + It notifies the encoder that additional further calls + can provide more input data (src) than provided by current call. + In that case the CBcj2Enc encoder still can move (src) pointer + up to (srcLim), but CBcj2Enc encoder can store some of the last + processed bytes (up to 4 bytes) from src to internal CBcj2Enc::temp[] buffer. + at return: + (CBcj2Enc::src will point to position that includes + processed data and data copied to (temp[]) buffer) + That data from (temp[]) buffer will be used in further calls. + + BCJ2_ENC_FINISH_MODE_END_BLOCK: + finish encoding of current block (ended at srcLim) without RC flushing. + at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_ORIG) && + CBcj2Enc::src == CBcj2Enc::srcLim) + : it shows that block encoding was finished. And the encoder is + ready for new (src) data or for stream finish operation. + finished block means + { + CBcj2Enc has completed block encoding up to (srcLim). + (1 + 4 bytes) or (2 + 4 bytes) CALL/JUMP cortages will + not cross block boundary at (srcLim). + temporary CBcj2Enc buffer for (ORIG) src data is empty. + 3 output uncompressed streams (MAIN, CALL, JUMP) were flushed. + RC stream was not flushed. And RC stream will cross block boundary. + } + Note: some possible implementation of BCJ2 encoder could + write branch marker (e8/e8/0f8x) in one call of Bcj2Enc_Encode(), + and it could calculate symbol for RC in another call of Bcj2Enc_Encode(). + BCJ2 encoder uses ip/fileIp/fileSize/relatLimit values to calculate RC symbol. + And these CBcj2Enc variables can have different values in different Bcj2Enc_Encode() calls. + So caller must finish each block with BCJ2_ENC_FINISH_MODE_END_BLOCK + to ensure that RC symbol is calculated and written in proper block. + + BCJ2_ENC_FINISH_MODE_END_STREAM + finish encoding of stream (ended at srcLim) fully including RC flushing. + at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_FINISHED) + : it shows that stream encoding was finished fully, + and all output streams were flushed fully. + also Bcj2Enc_IsFinished() can be called. +*/ + + +/* + 32-bit relative offset in JUMP/CALL commands is + - (mod 4 GiB) for 32-bit x86 code + - signed Int32 for 64-bit x86-64 code + BCJ2 encoder also does internal relative to absolute address conversions. + And there are 2 possible ways to do it: + before v23: we used 32-bit variables and (mod 4 GiB) conversion + since v23: we use 64-bit variables and (signed Int32 offset) conversion. + The absolute address condition for conversion in v23: + ((UInt64)((Int64)ip64 - (Int64)fileIp64 + 5 + (Int32)offset) < (UInt64)fileSize64) + note that if (fileSize64 > 2 GiB). there is difference between + old (mod 4 GiB) way (v22) and new (signed Int32 offset) way (v23). + And new (v23) way is more suitable to encode 64-bit x86-64 code for (fileSize64 > 2 GiB) cases. +*/ + +/* +// for old (v22) way for conversion: +typedef UInt32 CBcj2Enc_ip_unsigned; +typedef Int32 CBcj2Enc_ip_signed; +#define BCJ2_ENC_FileSize_MAX ((UInt32)1 << 31) +*/ +typedef UInt64 CBcj2Enc_ip_unsigned; +typedef Int64 CBcj2Enc_ip_signed; + +/* maximum size of file that can be used for conversion condition */ +#define BCJ2_ENC_FileSize_MAX ((CBcj2Enc_ip_unsigned)0 - 2) + +/* default value of fileSize64_minus1 variable that means + that absolute address limitation will not be used */ +#define BCJ2_ENC_FileSizeField_UNLIMITED ((CBcj2Enc_ip_unsigned)0 - 1) + +/* calculate value that later can be set to CBcj2Enc::fileSize64_minus1 */ +#define BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize) \ + ((CBcj2Enc_ip_unsigned)(fileSize) - 1) + +/* set CBcj2Enc::fileSize64_minus1 variable from size of file */ +#define Bcj2Enc_SET_FileSize(p, fileSize) \ + (p)->fileSize64_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize); + + typedef struct { Byte *bufs[BCJ2_NUM_STREAMS]; @@ -101,45 +261,71 @@ typedef struct unsigned state; EBcj2Enc_FinishMode finishMode; - Byte prevByte; + Byte context; + Byte flushRem; + Byte isFlushState; Byte cache; UInt32 range; UInt64 low; UInt64 cacheSize; + + // UInt32 context; // for marker version, it can include marker flag. - UInt32 ip; - - /* 32-bit ralative offset in JUMP/CALL commands is - - (mod 4 GB) in 32-bit mode - - signed Int32 in 64-bit mode - We use (mod 4 GB) check for fileSize. - Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ - UInt32 fileIp; - UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ - UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ + /* (ip64) and (fileIp64) correspond to virtual source stream position + that doesn't include data in temp[] */ + CBcj2Enc_ip_unsigned ip64; /* current (ip) position */ + CBcj2Enc_ip_unsigned fileIp64; /* start (ip) position of current file */ + CBcj2Enc_ip_unsigned fileSize64_minus1; /* size of current file (for conversion limitation) */ + UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)) : 0 means disable_conversion */ + // UInt32 relatExcludeBits; UInt32 tempTarget; - unsigned tempPos; - Byte temp[4 * 2]; - - unsigned flushPos; - - UInt16 probs[2 + 256]; + unsigned tempPos; /* the number of bytes that were copied to temp[] buffer + (tempPos <= 4) outside of Bcj2Enc_Encode() */ + // Byte temp[4]; // for marker version + Byte temp[8]; + CBcj2Prob probs[2 + 256]; } CBcj2Enc; void Bcj2Enc_Init(CBcj2Enc *p); -void Bcj2Enc_Encode(CBcj2Enc *p); -#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos) -#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5) +/* +Bcj2Enc_Encode(): at exit: + p->State < BCJ2_NUM_STREAMS : we need more buffer space for output stream + (bufs[p->State] == lims[p->State]) + p->State == BCJ2_ENC_STATE_ORIG : we need more data in input src stream + (src == srcLim) + p->State == BCJ2_ENC_STATE_FINISHED : after fully encoded stream +*/ +void Bcj2Enc_Encode(CBcj2Enc *p); -#define BCJ2_RELAT_LIMIT_NUM_BITS 26 -#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS) +/* Bcj2Enc encoder can look ahead for up 4 bytes of source stream. + CBcj2Enc::tempPos : is the number of bytes that were copied from input stream to temp[] buffer. + (CBcj2Enc::src) after Bcj2Enc_Encode() is starting position after + fully processed data and after data copied to temp buffer. + So if the caller needs to get real number of fully processed input + bytes (without look ahead data in temp buffer), + the caller must subtruct (CBcj2Enc::tempPos) value from processed size + value that is calculated based on current (CBcj2Enc::src): + cur_processed_pos = Calc_Big_Processed_Pos(enc.src)) - + Bcj2Enc_Get_AvailInputSize_in_Temp(&enc); +*/ +/* get the size of input data that was stored in temp[] buffer: */ +#define Bcj2Enc_Get_AvailInputSize_in_Temp(p) ((p)->tempPos) -/* limit for CBcj2Enc::fileSize variable */ -#define BCJ2_FileSize_MAX ((UInt32)1 << 31) +#define Bcj2Enc_IsFinished(p) ((p)->flushRem == 0) + +/* Note : the decoder supports overlapping of marker (0f 80). + But we can eliminate such overlapping cases by setting + the limit for relative offset conversion as + CBcj2Enc::relatLimit <= (0x0f << 24) == (240 MiB) +*/ +/* default value for CBcj2Enc::relatLimit */ +#define BCJ2_ENC_RELAT_LIMIT_DEFAULT ((UInt32)0x0f << 24) +#define BCJ2_ENC_RELAT_LIMIT_MAX ((UInt32)1 << 31) +// #define BCJ2_RELAT_EXCLUDE_NUM_BITS 5 EXTERN_C_END diff --git a/libraries/lzma/C/Bcj2Enc.c b/libraries/lzma/C/Bcj2Enc.c new file mode 100644 index 00000000000..79460bb150a --- /dev/null +++ b/libraries/lzma/C/Bcj2Enc.c @@ -0,0 +1,506 @@ +/* Bcj2Enc.c -- BCJ2 Encoder converter for x86 code (Branch CALL/JUMP variant2) +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +/* #define SHOW_STAT */ +#ifdef SHOW_STAT +#include +#define PRF2(s) printf("%s ip=%8x tempPos=%d src= %8x\n", s, (unsigned)p->ip64, p->tempPos, (unsigned)(p->srcLim - p->src)); +#else +#define PRF2(s) +#endif + +#include "Bcj2.h" +#include "CpuArch.h" + +#define kTopValue ((UInt32)1 << 24) +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +void Bcj2Enc_Init(CBcj2Enc *p) +{ + unsigned i; + p->state = BCJ2_ENC_STATE_ORIG; + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + p->context = 0; + p->flushRem = 5; + p->isFlushState = 0; + p->cache = 0; + p->range = 0xffffffff; + p->low = 0; + p->cacheSize = 1; + p->ip64 = 0; + p->fileIp64 = 0; + p->fileSize64_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED; + p->relatLimit = BCJ2_ENC_RELAT_LIMIT_DEFAULT; + // p->relatExcludeBits = 0; + p->tempPos = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} + +// Z7_NO_INLINE +Z7_FORCE_INLINE +static BoolInt Bcj2_RangeEnc_ShiftLow(CBcj2Enc *p) +{ + const UInt32 low = (UInt32)p->low; + const unsigned high = (unsigned) + #if defined(Z7_MSC_VER_ORIGINAL) \ + && defined(MY_CPU_X86) \ + && defined(MY_CPU_LE) \ + && !defined(MY_CPU_64BIT) + // we try to rid of __aullshr() call in MSVS-x86 + (((const UInt32 *)&p->low)[1]); // [1] : for little-endian only + #else + (p->low >> 32); + #endif + if (low < (UInt32)0xff000000 || high != 0) + { + Byte *buf = p->bufs[BCJ2_STREAM_RC]; + do + { + if (buf == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + p->bufs[BCJ2_STREAM_RC] = buf; + return True; + } + *buf++ = (Byte)(p->cache + high); + p->cache = 0xff; + } + while (--p->cacheSize); + p->bufs[BCJ2_STREAM_RC] = buf; + p->cache = (Byte)(low >> 24); + } + p->cacheSize++; + p->low = low << 8; + return False; +} + + +/* +We can use 2 alternative versions of code: +1) non-marker version: + Byte CBcj2Enc::context + Byte temp[8]; + Last byte of marker (e8/e9/[0f]8x) can be written to temp[] buffer. + Encoder writes last byte of marker (e8/e9/[0f]8x) to dest, only in conjunction + with writing branch symbol to range coder in same Bcj2Enc_Encode_2() call. + +2) marker version: + UInt32 CBcj2Enc::context + Byte CBcj2Enc::temp[4]; + MARKER_FLAG in CBcj2Enc::context shows that CBcj2Enc::context contains finded marker. + it's allowed that + one call of Bcj2Enc_Encode_2() writes last byte of marker (e8/e9/[0f]8x) to dest, + and another call of Bcj2Enc_Encode_2() does offset conversion. + So different values of (fileIp) and (fileSize) are possible + in these different Bcj2Enc_Encode_2() calls. + +Also marker version requires additional if((v & MARKER_FLAG) == 0) check in main loop. +So we use non-marker version. +*/ + +/* + Corner cases with overlap in multi-block. + before v23: there was one corner case, where converted instruction + could start in one sub-stream and finish in next sub-stream. + If multi-block (solid) encoding is used, + and BCJ2_ENC_FINISH_MODE_END_BLOCK is used for each sub-stream. + and (0f) is last byte of previous sub-stream + and (8x) is first byte of current sub-stream + then (0f 8x) pair is treated as marker by BCJ2 encoder and decoder. + BCJ2 encoder can converts 32-bit offset for that (0f 8x) cortage, + if that offset meets limit requirements. + If encoder allows 32-bit offset conversion for such overlap case, + then the data in 3 uncompressed BCJ2 streams for some sub-stream + can depend from data of previous sub-stream. + That corner case is not big problem, and it's rare case. + Since v23.00 we do additional check to prevent conversions in such overlap cases. +*/ + +/* + Bcj2Enc_Encode_2() output variables at exit: + { + if (Bcj2Enc_Encode_2() exits with (p->state == BCJ2_ENC_STATE_ORIG)) + { + it means that encoder needs more input data. + if (p->srcLim == p->src) at exit, then + { + (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) + all input data were read and processed, and we are ready for + new input data. + } + else + { + (p->srcLim != p->src) + (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) + The encoder have found e8/e9/0f_8x marker, + and p->src points to last byte of that marker, + Bcj2Enc_Encode_2() needs more input data to get totally + 5 bytes (last byte of marker and 32-bit branch offset) + as continuous array starting from p->src. + (p->srcLim - p->src < 5) requirement is met after exit. + So non-processed resedue from p->src to p->srcLim is always less than 5 bytes. + } + } + } +*/ + +Z7_NO_INLINE +static void Bcj2Enc_Encode_2(CBcj2Enc *p) +{ + if (!p->isFlushState) + { + const Byte *src; + UInt32 v; + { + const unsigned state = p->state; + if (BCJ2_IS_32BIT_STREAM(state)) + { + Byte *cur = p->bufs[state]; + if (cur == p->lims[state]) + return; + SetBe32a(cur, p->tempTarget) + p->bufs[state] = cur + 4; + } + } + p->state = BCJ2_ENC_STATE_ORIG; // for main reason of exit + src = p->src; + v = p->context; + + // #define WRITE_CONTEXT p->context = v; // for marker version + #define WRITE_CONTEXT p->context = (Byte)v; + #define WRITE_CONTEXT_AND_SRC p->src = src; WRITE_CONTEXT + + for (;;) + { + // const Byte *src; + // UInt32 v; + CBcj2Enc_ip_unsigned ip; + if (p->range < kTopValue) + { + // to reduce register pressure and code size: we save and restore local variables. + WRITE_CONTEXT_AND_SRC + if (Bcj2_RangeEnc_ShiftLow(p)) + return; + p->range <<= 8; + src = p->src; + v = p->context; + } + // src = p->src; + // #define MARKER_FLAG ((UInt32)1 << 17) + // if ((v & MARKER_FLAG) == 0) // for marker version + { + const Byte *srcLim; + Byte *dest = p->bufs[BCJ2_STREAM_MAIN]; + { + const SizeT remSrc = (SizeT)(p->srcLim - src); + SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest); + if (rem >= remSrc) + rem = remSrc; + srcLim = src + rem; + } + /* p->context contains context of previous byte: + bits [0 : 7] : src[-1], if (src) was changed in this call + bits [8 : 31] : are undefined for non-marker version + */ + // v = p->context; + #define NUM_SHIFT_BITS 24 + #define CONV_FLAG ((UInt32)1 << 16) + #define ONE_ITER { \ + b = src[0]; \ + *dest++ = (Byte)b; \ + v = (v << NUM_SHIFT_BITS) | b; \ + if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \ + if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \ + ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \ + src++; if (src == srcLim) { break; } } + + if (src != srcLim) + for (;;) + { + /* clang can generate ineffective code with setne instead of two jcc instructions. + we can use 2 iterations and external (unsigned b) to avoid that ineffective code genaration. */ + unsigned b; + ONE_ITER + ONE_ITER + } + + ip = p->ip64 + (CBcj2Enc_ip_unsigned)(SizeT)(dest - p->bufs[BCJ2_STREAM_MAIN]); + p->bufs[BCJ2_STREAM_MAIN] = dest; + p->ip64 = ip; + + if (src == srcLim) + { + WRITE_CONTEXT_AND_SRC + if (src != p->srcLim) + { + p->state = BCJ2_STREAM_MAIN; + return; + } + /* (p->src == p->srcLim) + (p->state == BCJ2_ENC_STATE_ORIG) */ + if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) + return; + /* (p->finishMode == BCJ2_ENC_FINISH_MODE_END_STREAM */ + // (p->flushRem == 5); + p->isFlushState = 1; + break; + } + src++; + // p->src = src; + } + // ip = p->ip; // for marker version + /* marker was found */ + /* (v) contains marker that was found: + bits [NUM_SHIFT_BITS : NUM_SHIFT_BITS + 7] + : value of src[-2] : xx/xx/0f + bits [0 : 7] : value of src[-1] : e8/e9/8x + */ + { + { + #if NUM_SHIFT_BITS != 24 + v &= ~(UInt32)CONV_FLAG; + #endif + // UInt32 relat = 0; + if ((SizeT)(p->srcLim - src) >= 4) + { + /* + if (relat != 0 || (Byte)v != 0xe8) + BoolInt isBigOffset = True; + */ + const UInt32 relat = GetUi32(src); + /* + #define EXCLUDE_FLAG ((UInt32)1 << 4) + #define NEED_CONVERT(rel) ((((rel) + EXCLUDE_FLAG) & (0 - EXCLUDE_FLAG * 2)) != 0) + if (p->relatExcludeBits != 0) + { + const UInt32 flag = (UInt32)1 << (p->relatExcludeBits - 1); + isBigOffset = (((relat + flag) & (0 - flag * 2)) != 0); + } + // isBigOffset = False; // for debug + */ + ip -= p->fileIp64; + // Use the following if check, if (ip) is 64-bit: + if (ip > (((v + 0x20) >> 5) & 1)) // 23.00 : we eliminate milti-block overlap for (Of 80) and (e8/e9) + if ((CBcj2Enc_ip_unsigned)((CBcj2Enc_ip_signed)ip + 4 + (Int32)relat) <= p->fileSize64_minus1) + if (((UInt32)(relat + p->relatLimit) >> 1) < p->relatLimit) + v |= CONV_FLAG; + } + else if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) + { + // (p->srcLim - src < 4) + // /* + // for non-marker version + p->ip64--; // p->ip = ip - 1; + p->bufs[BCJ2_STREAM_MAIN]--; + src--; + v >>= NUM_SHIFT_BITS; + // (0 < p->srcLim - p->src <= 4) + // */ + // v |= MARKER_FLAG; // for marker version + /* (p->state == BCJ2_ENC_STATE_ORIG) */ + WRITE_CONTEXT_AND_SRC + return; + } + { + const unsigned c = ((v + 0x17) >> 6) & 1; + CBcj2Prob *prob = p->probs + (unsigned) + (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1)); + /* + ((Byte)v == 0xe8 ? 2 + ((Byte)(v >> 8)) : + ((Byte)v < 0xe8 ? 0 : 1)); // ((v >> 5) & 1)); + */ + const unsigned ttt = *prob; + const UInt32 bound = (p->range >> kNumBitModelTotalBits) * ttt; + if ((v & CONV_FLAG) == 0) + { + // static int yyy = 0; yyy++; printf("\n!needConvert = %d\n", yyy); + // v = (Byte)v; // for marker version + p->range = bound; + *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + // WRITE_CONTEXT_AND_SRC + continue; + } + p->low += bound; + p->range -= bound; + *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits)); + } + // p->context = src[3]; + { + // const unsigned cj = ((Byte)v == 0xe8 ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP); + const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL; + ip = p->ip64; + v = GetUi32(src); // relat + ip += 4; + p->ip64 = ip; + src += 4; + // p->src = src; + { + const UInt32 absol = (UInt32)ip + v; + Byte *cur = p->bufs[cj]; + v >>= 24; + // WRITE_CONTEXT + if (cur == p->lims[cj]) + { + p->state = cj; + p->tempTarget = absol; + WRITE_CONTEXT_AND_SRC + return; + } + SetBe32a(cur, absol) + p->bufs[cj] = cur + 4; + } + } + } + } + } // end of loop + } + + for (; p->flushRem != 0; p->flushRem--) + if (Bcj2_RangeEnc_ShiftLow(p)) + return; + p->state = BCJ2_ENC_STATE_FINISHED; +} + + +/* +BCJ2 encoder needs look ahead for up to 4 bytes in (src) buffer. +So base function Bcj2Enc_Encode_2() + in BCJ2_ENC_FINISH_MODE_CONTINUE mode can return with + (p->state == BCJ2_ENC_STATE_ORIG && p->src < p->srcLim) +Bcj2Enc_Encode() solves that look ahead problem by using p->temp[] buffer. + so if (p->state == BCJ2_ENC_STATE_ORIG) after Bcj2Enc_Encode(), + then (p->src == p->srcLim). + And the caller's code is simpler with Bcj2Enc_Encode(). +*/ + +Z7_NO_INLINE +void Bcj2Enc_Encode(CBcj2Enc *p) +{ + PRF2("\n----") + if (p->tempPos != 0) + { + /* extra: number of bytes that were copied from (src) to (temp) buffer in this call */ + unsigned extra = 0; + /* We will touch only minimal required number of bytes in input (src) stream. + So we will add input bytes from (src) stream to temp[] with step of 1 byte. + We don't add new bytes to temp[] before Bcj2Enc_Encode_2() call + in first loop iteration because + - previous call of Bcj2Enc_Encode() could use another (finishMode), + - previous call could finish with (p->state != BCJ2_ENC_STATE_ORIG). + the case with full temp[] buffer (p->tempPos == 4) is possible here. + */ + for (;;) + { + // (0 < p->tempPos <= 5) // in non-marker version + /* p->src : the current src data position including extra bytes + that were copied to temp[] buffer in this call */ + const Byte *src = p->src; + const Byte *srcLim = p->srcLim; + const EBcj2Enc_FinishMode finishMode = p->finishMode; + if (src != srcLim) + { + /* if there are some src data after the data copied to temp[], + then we use MODE_CONTINUE for temp data */ + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + } + p->src = p->temp; + p->srcLim = p->temp + p->tempPos; + PRF2(" ") + Bcj2Enc_Encode_2(p); + { + const unsigned num = (unsigned)(p->src - p->temp); + const unsigned tempPos = p->tempPos - num; + unsigned i; + p->tempPos = tempPos; + for (i = 0; i < tempPos; i++) + p->temp[i] = p->temp[(SizeT)i + num]; + // tempPos : number of bytes in temp buffer + p->src = src; + p->srcLim = srcLim; + p->finishMode = finishMode; + if (p->state != BCJ2_ENC_STATE_ORIG) + { + // (p->tempPos <= 4) // in non-marker version + /* if (the reason of exit from Bcj2Enc_Encode_2() + is not BCJ2_ENC_STATE_ORIG), + then we exit from Bcj2Enc_Encode() with same reason */ + // optional code begin : we rollback (src) and tempPos, if it's possible: + if (extra >= tempPos) + extra = tempPos; + p->src = src - extra; + p->tempPos = tempPos - extra; + // optional code end : rollback of (src) and tempPos + return; + } + /* (p->tempPos <= 4) + (p->state == BCJ2_ENC_STATE_ORIG) + so encoder needs more data than in temp[] */ + if (src == srcLim) + return; // src buffer has no more input data. + /* (src != srcLim) + so we can provide more input data from src for Bcj2Enc_Encode_2() */ + if (extra >= tempPos) + { + /* (extra >= tempPos) means that temp buffer contains + only data from src buffer of this call. + So now we can encode without temp buffer */ + p->src = src - tempPos; // rollback (src) + p->tempPos = 0; + break; + } + // we append one additional extra byte from (src) to temp[] buffer: + p->temp[tempPos] = *src; + p->tempPos = tempPos + 1; + // (0 < p->tempPos <= 5) // in non-marker version + p->src = src + 1; + extra++; + } + } + } + + PRF2("++++") + // (p->tempPos == 0) + Bcj2Enc_Encode_2(p); + PRF2("====") + + if (p->state == BCJ2_ENC_STATE_ORIG) + { + const Byte *src = p->src; + const Byte *srcLim = p->srcLim; + const unsigned rem = (unsigned)(srcLim - src); + /* (rem <= 4) here. + if (p->src != p->srcLim), then + - we copy non-processed bytes from (p->src) to temp[] buffer, + - we set p->src equal to p->srcLim. + */ + if (rem) + { + unsigned i = 0; + p->src = srcLim; + p->tempPos = rem; + // (0 < p->tempPos <= 4) + do + p->temp[i] = src[i]; + while (++i != rem); + } + // (p->tempPos <= 4) + // (p->src == p->srcLim) + } +} + +#undef PRF2 +#undef CONV_FLAG +#undef MARKER_FLAG +#undef WRITE_CONTEXT +#undef WRITE_CONTEXT_AND_SRC +#undef ONE_ITER +#undef NUM_SHIFT_BITS +#undef kTopValue +#undef kNumBitModelTotalBits +#undef kBitModelTotal +#undef kNumMoveBits diff --git a/libraries/lzma/C/Bra.c b/libraries/lzma/C/Bra.c index aed17e330db..22e0e478eca 100644 --- a/libraries/lzma/C/Bra.c +++ b/libraries/lzma/C/Bra.c @@ -1,230 +1,420 @@ -/* Bra.c -- Converters for RISC code -2017-04-04 : Igor Pavlov : Public domain */ +/* Bra.c -- Branch converters for RISC code +2023-04-02 : Igor Pavlov : Public domain */ #include "Precomp.h" -#include "CpuArch.h" #include "Bra.h" +#include "CpuArch.h" +#include "RotateDefs.h" + +#if defined(MY_CPU_SIZEOF_POINTER) \ + && ( MY_CPU_SIZEOF_POINTER == 4 \ + || MY_CPU_SIZEOF_POINTER == 8) + #define BR_CONV_USE_OPT_PC_PTR +#endif + +#ifdef BR_CONV_USE_OPT_PC_PTR +#define BR_PC_INIT pc -= (UInt32)(SizeT)p; +#define BR_PC_GET (pc + (UInt32)(SizeT)p) +#else +#define BR_PC_INIT pc += (UInt32)size; +#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p)) +// #define BR_PC_INIT +// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data)) +#endif + +#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c; +// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c; + +#define Z7_BRANCH_CONV(name) z7_BranchConv_ ## name + +#define Z7_BRANCH_FUNC_MAIN(name) \ +static \ +Z7_FORCE_INLINE \ +Z7_ATTRIB_NO_VECTOR \ +Byte *Z7_BRANCH_CONV(name)(Byte *p, SizeT size, UInt32 pc, int encoding) -SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +#define Z7_BRANCH_FUNC_IMP(name, m, encoding) \ +Z7_NO_INLINE \ +Z7_ATTRIB_NO_VECTOR \ +Byte *m(name)(Byte *data, SizeT size, UInt32 pc) \ + { return Z7_BRANCH_CONV(name)(data, size, pc, encoding); } \ + +#ifdef Z7_EXTRACT_ONLY +#define Z7_BRANCH_FUNCS_IMP(name) \ + Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC, 0) +#else +#define Z7_BRANCH_FUNCS_IMP(name) \ + Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC, 0) \ + Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_ENC, 1) +#endif + +#if defined(__clang__) +#define BR_EXTERNAL_FOR +#define BR_NEXT_ITERATION continue; +#else +#define BR_EXTERNAL_FOR for (;;) +#define BR_NEXT_ITERATION break; +#endif + +#if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 1000) \ + // GCC is not good for __builtin_expect() here + /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */ + // #define Z7_unlikely [[unlikely]] + // #define Z7_LIKELY(x) (__builtin_expect((x), 1)) + #define Z7_UNLIKELY(x) (__builtin_expect((x), 0)) + // #define Z7_likely [[likely]] +#else + // #define Z7_LIKELY(x) (x) + #define Z7_UNLIKELY(x) (x) + // #define Z7_likely +#endif + + +Z7_BRANCH_FUNC_MAIN(ARM64) { - Byte *p; + // Byte *p = data; const Byte *lim; - size &= ~(size_t)3; - ip += 4; - p = data; - lim = data + size; + const UInt32 flag = (UInt32)1 << (24 - 4); + const UInt32 mask = ((UInt32)1 << 24) - (flag << 1); + size &= ~(SizeT)3; + // if (size == 0) return p; + lim = p + size; + BR_PC_INIT + pc -= 4; // because (p) will point to next instruction + + BR_EXTERNAL_FOR + { + // Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (;;) + { + UInt32 v; + if Z7_UNLIKELY(p == lim) + return p; + v = GetUi32a(p); + p += 4; + if Z7_UNLIKELY(((v - 0x94000000) & 0xfc000000) == 0) + { + UInt32 c = BR_PC_GET >> 2; + BR_CONVERT_VAL(v, c) + v &= 0x03ffffff; + v |= 0x94000000; + SetUi32a(p - 4, v) + BR_NEXT_ITERATION + } + // v = rotlFixed(v, 8); v += (flag << 8) - 0x90; if Z7_UNLIKELY((v & ((mask << 8) + 0x9f)) == 0) + v -= 0x90000000; if Z7_UNLIKELY((v & 0x9f000000) == 0) + { + UInt32 z, c; + // v = rotrFixed(v, 8); + v += flag; if Z7_UNLIKELY(v & mask) continue; + z = (v & 0xffffffe0) | (v >> 26); + c = (BR_PC_GET >> (12 - 3)) & ~(UInt32)7; + BR_CONVERT_VAL(z, c) + v &= 0x1f; + v |= 0x90000000; + v |= z << 26; + v |= 0x00ffffe0 & ((z & (((flag << 1) - 1))) - flag); + SetUi32a(p - 4, v) + } + } + } +} +Z7_BRANCH_FUNCS_IMP(ARM64) - if (encoding) +Z7_BRANCH_FUNC_MAIN(ARM) +{ + // Byte *p = data; + const Byte *lim; + size &= ~(SizeT)3; + lim = p + size; + BR_PC_INIT + /* in ARM: branch offset is relative to the +2 instructions from current instruction. + (p) will point to next instruction */ + pc += 8 - 4; + for (;;) { for (;;) { - if (p >= lim) - return p - data; - p += 4; - if (p[-1] == 0xEB) - break; + if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break; + if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break; } { - UInt32 v = GetUi32(p - 4); - v <<= 2; - v += ip + (UInt32)(p - data); - v >>= 2; - v &= 0x00FFFFFF; - v |= 0xEB000000; - SetUi32(p - 4, v); + UInt32 v = GetUi32a(p - 4); + UInt32 c = BR_PC_GET >> 2; + BR_CONVERT_VAL(v, c) + v &= 0x00ffffff; + v |= 0xeb000000; + SetUi32a(p - 4, v) } } +} +Z7_BRANCH_FUNCS_IMP(ARM) + +Z7_BRANCH_FUNC_MAIN(PPC) +{ + // Byte *p = data; + const Byte *lim; + size &= ~(SizeT)3; + lim = p + size; + BR_PC_INIT + pc -= 4; // because (p) will point to next instruction + for (;;) { + UInt32 v; for (;;) { - if (p >= lim) - return p - data; + if Z7_UNLIKELY(p == lim) + return p; + // v = GetBe32a(p); + v = *(UInt32 *)(void *)p; p += 4; - if (p[-1] == 0xEB) - break; + // if ((v & 0xfc000003) == 0x48000001) break; + // if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) break; + if Z7_UNLIKELY( + ((v - Z7_CONV_BE_TO_NATIVE_CONST32(0x48000001)) + & Z7_CONV_BE_TO_NATIVE_CONST32(0xfc000003)) == 0) break; } { - UInt32 v = GetUi32(p - 4); - v <<= 2; - v -= ip + (UInt32)(p - data); - v >>= 2; - v &= 0x00FFFFFF; - v |= 0xEB000000; - SetUi32(p - 4, v); + v = Z7_CONV_NATIVE_TO_BE_32(v); + { + UInt32 c = BR_PC_GET; + BR_CONVERT_VAL(v, c) + } + v &= 0x03ffffff; + v |= 0x48000000; + SetBe32a(p - 4, v) } } } +Z7_BRANCH_FUNCS_IMP(PPC) -SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +#ifdef Z7_CPU_FAST_ROTATE_SUPPORTED +#define BR_SPARC_USE_ROTATE +#endif + +Z7_BRANCH_FUNC_MAIN(SPARC) { - Byte *p; + // Byte *p = data; const Byte *lim; - size &= ~(size_t)1; - p = data; - lim = data + size - 4; - - if (encoding) - + const UInt32 flag = (UInt32)1 << 22; + size &= ~(SizeT)3; + lim = p + size; + BR_PC_INIT + pc -= 4; // because (p) will point to next instruction for (;;) { - UInt32 b1; + UInt32 v; for (;;) { - UInt32 b3; - if (p > lim) - return p - data; - b1 = p[1]; - b3 = p[3]; - p += 2; - b1 ^= 8; - if ((b3 & b1) >= 0xF8) + if Z7_UNLIKELY(p == lim) + return p; + /* // the code without GetBe32a(): + { const UInt32 v = GetUi16a(p) & 0xc0ff; p += 4; if (v == 0x40 || v == 0xc07f) break; } + */ + v = GetBe32a(p); + p += 4; + #ifdef BR_SPARC_USE_ROTATE + v = rotlFixed(v, 2); + v += (flag << 2) - 1; + if Z7_UNLIKELY((v & (3 - (flag << 3))) == 0) + #else + v += (UInt32)5 << 29; + v ^= (UInt32)7 << 29; + v += flag; + if Z7_UNLIKELY((v & (0 - (flag << 1))) == 0) + #endif break; } { - UInt32 v = - ((UInt32)b1 << 19) - + (((UInt32)p[1] & 0x7) << 8) - + (((UInt32)p[-2] << 11)) - + (p[0]); - - p += 2; + // UInt32 v = GetBe32a(p - 4); + #ifndef BR_SPARC_USE_ROTATE + v <<= 2; + #endif { - UInt32 cur = (ip + (UInt32)(p - data)) >> 1; - v += cur; + UInt32 c = BR_PC_GET; + BR_CONVERT_VAL(v, c) } - - p[-4] = (Byte)(v >> 11); - p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7)); - p[-2] = (Byte)v; - p[-1] = (Byte)(0xF8 | (v >> 8)); + v &= (flag << 3) - 1; + #ifdef BR_SPARC_USE_ROTATE + v -= (flag << 2) - 1; + v = rotrFixed(v, 2); + #else + v -= (flag << 2); + v >>= 2; + v |= (UInt32)1 << 30; + #endif + SetBe32a(p - 4, v) } } +} +Z7_BRANCH_FUNCS_IMP(SPARC) + + +Z7_BRANCH_FUNC_MAIN(ARMT) +{ + // Byte *p = data; + Byte *lim; + size &= ~(SizeT)1; + // if (size == 0) return p; + if (size <= 2) return p; + size -= 2; + lim = p + size; + BR_PC_INIT + /* in ARM: branch offset is relative to the +2 instructions from current instruction. + (p) will point to the +2 instructions from current instruction */ + // pc += 4 - 4; + // if (encoding) pc -= 0xf800 << 1; else pc += 0xf800 << 1; + // #define ARMT_TAIL_PROC { goto armt_tail; } + #define ARMT_TAIL_PROC { return p; } - for (;;) + do { - UInt32 b1; + /* in MSVC 32-bit x86 compilers: + UInt32 version : it loads value from memory with movzx + Byte version : it loads value to 8-bit register (AL/CL) + movzx version is slightly faster in some cpus + */ + unsigned b1; + // Byte / unsigned + b1 = p[1]; + // optimized version to reduce one (p >= lim) check: + // unsigned a1 = p[1]; b1 = p[3]; p += 2; if Z7_LIKELY((b1 & (a1 ^ 8)) < 0xf8) for (;;) { - UInt32 b3; - if (p > lim) - return p - data; - b1 = p[1]; - b3 = p[3]; - p += 2; - b1 ^= 8; - if ((b3 & b1) >= 0xF8) - break; + unsigned b3; // Byte / UInt32 + /* (Byte)(b3) normalization can use low byte computations in MSVC. + It gives smaller code, and no loss of speed in some compilers/cpus. + But new MSVC 32-bit x86 compilers use more slow load + from memory to low byte register in that case. + So we try to use full 32-bit computations for faster code. + */ + // if (p >= lim) { ARMT_TAIL_PROC } b3 = b1 + 8; b1 = p[3]; p += 2; if ((b3 & b1) >= 0xf8) break; + if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b3 = p[3]; p += 2; if Z7_UNLIKELY((b3 & (b1 ^ 8)) >= 0xf8) break; + if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b1 = p[3]; p += 2; if Z7_UNLIKELY((b1 & (b3 ^ 8)) >= 0xf8) break; } { + /* we can adjust pc for (0xf800) to rid of (& 0x7FF) operation. + But gcc/clang for arm64 can use bfi instruction for full code here */ UInt32 v = - ((UInt32)b1 << 19) + ((UInt32)GetUi16a(p - 2) << 11) | + ((UInt32)GetUi16a(p) & 0x7FF); + /* + UInt32 v = + ((UInt32)p[1 - 2] << 19) + (((UInt32)p[1] & 0x7) << 8) + (((UInt32)p[-2] << 11)) + (p[0]); - + */ p += 2; { - UInt32 cur = (ip + (UInt32)(p - data)) >> 1; - v -= cur; + UInt32 c = BR_PC_GET >> 1; + BR_CONVERT_VAL(v, c) } - + SetUi16a(p - 4, (UInt16)(((v >> 11) & 0x7ff) | 0xf000)) + SetUi16a(p - 2, (UInt16)(v | 0xf800)) /* - SetUi16(p - 4, (UInt16)(((v >> 11) & 0x7FF) | 0xF000)); - SetUi16(p - 2, (UInt16)(v | 0xF800)); - */ - p[-4] = (Byte)(v >> 11); - p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7)); + p[-3] = (Byte)(0xf0 | ((v >> 19) & 0x7)); p[-2] = (Byte)v; - p[-1] = (Byte)(0xF8 | (v >> 8)); + p[-1] = (Byte)(0xf8 | (v >> 8)); + */ } } + while (p < lim); + return p; + // armt_tail: + // if ((Byte)((lim[1] & 0xf8)) != 0xf0) { lim += 2; } return lim; + // return (Byte *)(lim + ((Byte)((lim[1] ^ 0xf0) & 0xf8) == 0 ? 0 : 2)); + // return (Byte *)(lim + (((lim[1] ^ ~0xfu) & ~7u) == 0 ? 0 : 2)); + // return (Byte *)(lim + 2 - (((((unsigned)lim[1] ^ 8) + 8) >> 7) & 2)); } +Z7_BRANCH_FUNCS_IMP(ARMT) -SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) -{ - Byte *p; - const Byte *lim; - size &= ~(size_t)3; - ip -= 4; - p = data; - lim = data + size; - - for (;;) - { - for (;;) - { - if (p >= lim) - return p - data; - p += 4; - /* if ((v & 0xFC000003) == 0x48000001) */ - if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) - break; - } - { - UInt32 v = GetBe32(p - 4); - if (encoding) - v += ip + (UInt32)(p - data); - else - v -= ip + (UInt32)(p - data); - v &= 0x03FFFFFF; - v |= 0x48000000; - SetBe32(p - 4, v); - } - } -} - +// #define BR_IA64_NO_INLINE -SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +Z7_BRANCH_FUNC_MAIN(IA64) { - Byte *p; + // Byte *p = data; const Byte *lim; - size &= ~(size_t)3; - ip -= 4; - p = data; - lim = data + size; - + size &= ~(SizeT)15; + lim = p + size; + pc -= 1 << 4; + pc >>= 4 - 1; + // pc -= 1 << 1; + for (;;) { + unsigned m; for (;;) { - if (p >= lim) - return p - data; - /* - v = GetBe32(p); - p += 4; - m = v + ((UInt32)5 << 29); - m ^= (UInt32)7 << 29; - m += (UInt32)1 << 22; - if ((m & ((UInt32)0x1FF << 23)) == 0) - break; - */ - p += 4; - if ((p[-4] == 0x40 && (p[-3] & 0xC0) == 0) || - (p[-4] == 0x7F && (p[-3] >= 0xC0))) + if Z7_UNLIKELY(p == lim) + return p; + m = (unsigned)((UInt32)0x334b0000 >> (*p & 0x1e)); + p += 16; + pc += 1 << 1; + if (m &= 3) break; } { - UInt32 v = GetBe32(p - 4); - v <<= 2; - if (encoding) - v += ip + (UInt32)(p - data); - else - v -= ip + (UInt32)(p - data); - - v &= 0x01FFFFFF; - v -= (UInt32)1 << 24; - v ^= 0xFF000000; - v >>= 2; - v |= 0x40000000; - SetBe32(p - 4, v); + p += (ptrdiff_t)m * 5 - 20; // negative value is expected here. + do + { + const UInt32 t = + #if defined(MY_CPU_X86_OR_AMD64) + // we use 32-bit load here to reduce code size on x86: + GetUi32(p); + #else + GetUi16(p); + #endif + UInt32 z = GetUi32(p + 1) >> m; + p += 5; + if (((t >> m) & (0x70 << 1)) == 0 + && ((z - (0x5000000 << 1)) & (0xf000000 << 1)) == 0) + { + UInt32 v = (UInt32)((0x8fffff << 1) | 1) & z; + z ^= v; + #ifdef BR_IA64_NO_INLINE + v |= (v & ((UInt32)1 << (23 + 1))) >> 3; + { + UInt32 c = pc; + BR_CONVERT_VAL(v, c) + } + v &= (0x1fffff << 1) | 1; + #else + { + if (encoding) + { + // pc &= ~(0xc00000 << 1); // we just need to clear at least 2 bits + pc &= (0x1fffff << 1) | 1; + v += pc; + } + else + { + // pc |= 0xc00000 << 1; // we need to set at least 2 bits + pc |= ~(UInt32)((0x1fffff << 1) | 1); + v -= pc; + } + } + v &= ~(UInt32)(0x600000 << 1); + #endif + v += (0x700000 << 1); + v &= (0x8fffff << 1) | 1; + z |= v; + z <<= m; + SetUi32(p + 1 - 5, z) + } + m++; + } + while (m &= 3); // while (m < 4); } } } +Z7_BRANCH_FUNCS_IMP(IA64) diff --git a/libraries/lzma/C/Bra.h b/libraries/lzma/C/Bra.h index 855e37a6b50..a4ee568e215 100644 --- a/libraries/lzma/C/Bra.h +++ b/libraries/lzma/C/Bra.h @@ -1,64 +1,99 @@ /* Bra.h -- Branch converters for executables -2013-01-18 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ -#ifndef __BRA_H -#define __BRA_H +#ifndef ZIP7_INC_BRA_H +#define ZIP7_INC_BRA_H #include "7zTypes.h" EXTERN_C_BEGIN +#define Z7_BRANCH_CONV_DEC(name) z7_BranchConv_ ## name ## _Dec +#define Z7_BRANCH_CONV_ENC(name) z7_BranchConv_ ## name ## _Enc +#define Z7_BRANCH_CONV_ST_DEC(name) z7_BranchConvSt_ ## name ## _Dec +#define Z7_BRANCH_CONV_ST_ENC(name) z7_BranchConvSt_ ## name ## _Enc + +#define Z7_BRANCH_CONV_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc) +#define Z7_BRANCH_CONV_ST_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc, UInt32 *state) + +typedef Z7_BRANCH_CONV_DECL( (*z7_Func_BranchConv)); +typedef Z7_BRANCH_CONV_ST_DECL((*z7_Func_BranchConvSt)); + +#define Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL 0 +Z7_BRANCH_CONV_ST_DECL(Z7_BRANCH_CONV_ST_DEC(X86)); +Z7_BRANCH_CONV_ST_DECL(Z7_BRANCH_CONV_ST_ENC(X86)); + +#define Z7_BRANCH_FUNCS_DECL(name) \ +Z7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_DEC(name)); \ +Z7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_ENC(name)); + +Z7_BRANCH_FUNCS_DECL(ARM64) +Z7_BRANCH_FUNCS_DECL(ARM) +Z7_BRANCH_FUNCS_DECL(ARMT) +Z7_BRANCH_FUNCS_DECL(PPC) +Z7_BRANCH_FUNCS_DECL(SPARC) +Z7_BRANCH_FUNCS_DECL(IA64) + /* -These functions convert relative addresses to absolute addresses -in CALL instructions to increase the compression ratio. - - In: - data - data buffer - size - size of data - ip - current virtual Instruction Pinter (IP) value - state - state variable for x86 converter - encoding - 0 (for decoding), 1 (for encoding) - - Out: - state - state variable for x86 converter +These functions convert data that contain CPU instructions. +Each such function converts relative addresses to absolute addresses in some +branch instructions: CALL (in all converters) and JUMP (X86 converter only). +Such conversion allows to increase compression ratio, if we compress that data. + +There are 2 types of converters: + Byte * Conv_RISC (Byte *data, SizeT size, UInt32 pc); + Byte * ConvSt_X86(Byte *data, SizeT size, UInt32 pc, UInt32 *state); +Each Converter supports 2 versions: one for encoding +and one for decoding (_Enc/_Dec postfixes in function name). - Returns: - The number of processed bytes. If you call these functions with multiple calls, - you must start next call with first byte after block of processed bytes. +In params: + data : data buffer + size : size of data + pc : current virtual Program Counter (Instruction Pinter) value +In/Out param: + state : pointer to state variable (for X86 converter only) + +Return: + The pointer to position in (data) buffer after last byte that was processed. + If the caller calls converter again, it must call it starting with that position. + But the caller is allowed to move data in buffer. so pointer to + current processed position also will be changed for next call. + Also the caller must increase internal (pc) value for next call. +Each converter has some characteristics: Endian, Alignment, LookAhead. Type Endian Alignment LookAhead - x86 little 1 4 + X86 little 1 4 ARMT little 2 2 ARM little 4 0 + ARM64 little 4 0 PPC big 4 0 SPARC big 4 0 IA64 little 16 0 - size must be >= Alignment + LookAhead, if it's not last block. - If (size < Alignment + LookAhead), converter returns 0. - - Example: + (data) must be aligned for (Alignment). + processed size can be calculated as: + SizeT processed = Conv(data, size, pc) - data; + if (processed == 0) + it means that converter needs more data for processing. + If (size < Alignment + LookAhead) + then (processed == 0) is allowed. - UInt32 ip = 0; - for () - { - ; size must be >= Alignment + LookAhead, if it's not last block - SizeT processed = Convert(data, size, ip, 1); - data += processed; - size -= processed; - ip += processed; - } +Example code for conversion in loop: + UInt32 pc = 0; + size = 0; + for (;;) + { + size += Load_more_input_data(data + size); + SizeT processed = Conv(data, size, pc) - data; + if (processed == 0 && no_more_input_data_after_size) + break; // we stop convert loop + data += processed; + size -= processed; + pc += processed; + } */ -#define x86_Convert_Init(state) { state = 0; } -SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); -SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); - EXTERN_C_END #endif diff --git a/libraries/lzma/C/Bra86.c b/libraries/lzma/C/Bra86.c index 93ed4d762b3..d81f392ae04 100644 --- a/libraries/lzma/C/Bra86.c +++ b/libraries/lzma/C/Bra86.c @@ -1,82 +1,187 @@ -/* Bra86.c -- Converter for x86 code (BCJ) -2017-04-03 : Igor Pavlov : Public domain */ +/* Bra86.c -- Branch converter for X86 code (BCJ) +2023-04-02 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bra.h" +#include "CpuArch.h" -#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) -SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) +#if defined(MY_CPU_SIZEOF_POINTER) \ + && ( MY_CPU_SIZEOF_POINTER == 4 \ + || MY_CPU_SIZEOF_POINTER == 8) + #define BR_CONV_USE_OPT_PC_PTR +#endif + +#ifdef BR_CONV_USE_OPT_PC_PTR +#define BR_PC_INIT pc -= (UInt32)(SizeT)p; // (MY_uintptr_t) +#define BR_PC_GET (pc + (UInt32)(SizeT)p) +#else +#define BR_PC_INIT pc += (UInt32)size; +#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p)) +// #define BR_PC_INIT +// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data)) +#endif + +#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c; +// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c; + +#define Z7_BRANCH_CONV_ST(name) z7_BranchConvSt_ ## name + +#define BR86_NEED_CONV_FOR_MS_BYTE(b) ((((b) + 1) & 0xfe) == 0) + +#ifdef MY_CPU_LE_UNALIGN + #define BR86_PREPARE_BCJ_SCAN const UInt32 v = GetUi32(p) ^ 0xe8e8e8e8; + #define BR86_IS_BCJ_BYTE(n) ((v & ((UInt32)0xfe << (n) * 8)) == 0) +#else + #define BR86_PREPARE_BCJ_SCAN + // bad for MSVC X86 (partial write to byte reg): + #define BR86_IS_BCJ_BYTE(n) ((p[n - 4] & 0xfe) == 0xe8) + // bad for old MSVC (partial write to byte reg): + // #define BR86_IS_BCJ_BYTE(n) (((*p ^ 0xe8) & 0xfe) == 0) +#endif + +static +Z7_FORCE_INLINE +Z7_ATTRIB_NO_VECTOR +Byte *Z7_BRANCH_CONV_ST(X86)(Byte *p, SizeT size, UInt32 pc, UInt32 *state, int encoding) { - SizeT pos = 0; - UInt32 mask = *state & 7; if (size < 5) - return 0; - size -= 4; - ip += 5; + return p; + { + // Byte *p = data; + const Byte *lim = p + size - 4; + unsigned mask = (unsigned)*state; // & 7; +#ifdef BR_CONV_USE_OPT_PC_PTR + /* if BR_CONV_USE_OPT_PC_PTR is defined: we need to adjust (pc) for (+4), + because call/jump offset is relative to the next instruction. + if BR_CONV_USE_OPT_PC_PTR is not defined : we don't need to adjust (pc) for (+4), + because BR_PC_GET uses (pc - (lim - p)), and lim was adjusted for (-4) before. + */ + pc += 4; +#endif + BR_PC_INIT + goto start; - for (;;) + for (;; mask |= 4) { - Byte *p = data + pos; - const Byte *limit = data + size; - for (; p < limit; p++) - if ((*p & 0xFE) == 0xE8) - break; - + // cont: mask |= 4; + start: + if (p >= lim) + goto fin; { - SizeT d = (SizeT)(p - data - pos); - pos = (SizeT)(p - data); - if (p >= limit) - { - *state = (d > 2 ? 0 : mask >> (unsigned)d); - return pos; - } - if (d > 2) - mask = 0; - else - { - mask >>= (unsigned)d; - if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(size_t)(mask >> 1) + 1]))) - { - mask = (mask >> 1) | 4; - pos++; - continue; - } - } + BR86_PREPARE_BCJ_SCAN + p += 4; + if (BR86_IS_BCJ_BYTE(0)) { goto m0; } mask >>= 1; + if (BR86_IS_BCJ_BYTE(1)) { goto m1; } mask >>= 1; + if (BR86_IS_BCJ_BYTE(2)) { goto m2; } mask = 0; + if (BR86_IS_BCJ_BYTE(3)) { goto a3; } } + goto main_loop; - if (Test86MSByte(p[4])) + m0: p--; + m1: p--; + m2: p--; + if (mask == 0) + goto a3; + if (p > lim) + goto fin_p; + + // if (((0x17u >> mask) & 1) == 0) + if (mask > 4 || mask == 3) + { + mask >>= 1; + continue; // goto cont; + } + mask >>= 1; + if (BR86_NEED_CONV_FOR_MS_BYTE(p[mask])) + continue; // goto cont; + // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont; { - UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); - UInt32 cur = ip + (UInt32)pos; - pos += 5; - if (encoding) - v += cur; - else - v -= cur; - if (mask != 0) + UInt32 v = GetUi32(p); + UInt32 c; + v += (1 << 24); if (v & 0xfe000000) continue; // goto cont; + c = BR_PC_GET; + BR_CONVERT_VAL(v, c) { - unsigned sh = (mask & 6) << 2; - if (Test86MSByte((Byte)(v >> sh))) + mask <<= 3; + if (BR86_NEED_CONV_FOR_MS_BYTE(v >> mask)) { - v ^= (((UInt32)0x100 << sh) - 1); - if (encoding) - v += cur; - else - v -= cur; + v ^= (((UInt32)0x100 << mask) - 1); + #ifdef MY_CPU_X86 + // for X86 : we can recalculate (c) to reduce register pressure + c = BR_PC_GET; + #endif + BR_CONVERT_VAL(v, c) } mask = 0; } - p[1] = (Byte)v; - p[2] = (Byte)(v >> 8); - p[3] = (Byte)(v >> 16); - p[4] = (Byte)(0 - ((v >> 24) & 1)); + // v = (v & ((1 << 24) - 1)) - (v & (1 << 24)); + v &= (1 << 25) - 1; v -= (1 << 24); + SetUi32(p, v) + p += 4; + goto main_loop; } - else + + main_loop: + if (p >= lim) + goto fin; + for (;;) { - mask = (mask >> 1) | 4; - pos++; + BR86_PREPARE_BCJ_SCAN + p += 4; + if (BR86_IS_BCJ_BYTE(0)) { goto a0; } + if (BR86_IS_BCJ_BYTE(1)) { goto a1; } + if (BR86_IS_BCJ_BYTE(2)) { goto a2; } + if (BR86_IS_BCJ_BYTE(3)) { goto a3; } + if (p >= lim) + goto fin; + } + + a0: p--; + a1: p--; + a2: p--; + a3: + if (p > lim) + goto fin_p; + // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont; + { + UInt32 v = GetUi32(p); + UInt32 c; + v += (1 << 24); if (v & 0xfe000000) continue; // goto cont; + c = BR_PC_GET; + BR_CONVERT_VAL(v, c) + // v = (v & ((1 << 24) - 1)) - (v & (1 << 24)); + v &= (1 << 25) - 1; v -= (1 << 24); + SetUi32(p, v) + p += 4; + goto main_loop; } } + +fin_p: + p--; +fin: + // the following processing for tail is optional and can be commented + /* + lim += 4; + for (; p < lim; p++, mask >>= 1) + if ((*p & 0xfe) == 0xe8) + break; + */ + *state = (UInt32)mask; + return p; + } } + + +#define Z7_BRANCH_CONV_ST_FUNC_IMP(name, m, encoding) \ +Z7_NO_INLINE \ +Z7_ATTRIB_NO_VECTOR \ +Byte *m(name)(Byte *data, SizeT size, UInt32 pc, UInt32 *state) \ + { return Z7_BRANCH_CONV_ST(name)(data, size, pc, state, encoding); } + +Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_DEC, 0) +#ifndef Z7_EXTRACT_ONLY +Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_ENC, 1) +#endif diff --git a/libraries/lzma/C/BraIA64.c b/libraries/lzma/C/BraIA64.c deleted file mode 100644 index d1dbc62c55b..00000000000 --- a/libraries/lzma/C/BraIA64.c +++ /dev/null @@ -1,53 +0,0 @@ -/* BraIA64.c -- Converter for IA-64 code -2017-01-26 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "CpuArch.h" -#include "Bra.h" - -SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) -{ - SizeT i; - if (size < 16) - return 0; - size -= 16; - i = 0; - do - { - unsigned m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3; - if (m) - { - m++; - do - { - Byte *p = data + (i + (size_t)m * 5 - 8); - if (((p[3] >> m) & 15) == 5 - && (((p[-1] | ((UInt32)p[0] << 8)) >> m) & 0x70) == 0) - { - unsigned raw = GetUi32(p); - unsigned v = raw >> m; - v = (v & 0xFFFFF) | ((v & (1 << 23)) >> 3); - - v <<= 4; - if (encoding) - v += ip + (UInt32)i; - else - v -= ip + (UInt32)i; - v >>= 4; - - v &= 0x1FFFFF; - v += 0x700000; - v &= 0x8FFFFF; - raw &= ~((UInt32)0x8FFFFF << m); - raw |= (v << m); - SetUi32(p, raw); - } - } - while (++m <= 4); - } - i += 16; - } - while (i <= size); - return i; -} diff --git a/libraries/lzma/C/Compiler.h b/libraries/lzma/C/Compiler.h index 0cc409d8a86..185a52deb50 100644 --- a/libraries/lzma/C/Compiler.h +++ b/libraries/lzma/C/Compiler.h @@ -1,8 +1,37 @@ -/* Compiler.h -2017-04-03 : Igor Pavlov : Public domain */ +/* Compiler.h : Compiler specific defines and pragmas +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_COMPILER_H +#define ZIP7_INC_COMPILER_H + +#if defined(__clang__) +# define Z7_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#endif +#if defined(__clang__) && defined(__apple_build_version__) +# define Z7_APPLE_CLANG_VERSION Z7_CLANG_VERSION +#elif defined(__clang__) +# define Z7_LLVM_CLANG_VERSION Z7_CLANG_VERSION +#elif defined(__GNUC__) +# define Z7_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#ifdef _MSC_VER +#if !defined(__clang__) && !defined(__GNUC__) +#define Z7_MSC_VER_ORIGINAL _MSC_VER +#endif +#endif + +#if defined(__MINGW32__) || defined(__MINGW64__) +#define Z7_MINGW +#endif + +// #pragma GCC diagnostic ignored "-Wunknown-pragmas" + +#ifdef __clang__ +// padding size of '' with 4 bytes to alignment boundary +#pragma GCC diagnostic ignored "-Wpadded" +#endif -#ifndef __7Z_COMPILER_H -#define __7Z_COMPILER_H #ifdef _MSC_VER @@ -13,18 +42,115 @@ #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int #endif - #if _MSC_VER >= 1300 - #pragma warning(disable : 4996) // This function or variable may be unsafe - #else - #pragma warning(disable : 4511) // copy constructor could not be generated - #pragma warning(disable : 4512) // assignment operator could not be generated - #pragma warning(disable : 4514) // unreferenced inline function has been removed - #pragma warning(disable : 4702) // unreachable code - #pragma warning(disable : 4710) // not inlined - #pragma warning(disable : 4714) // function marked as __forceinline not inlined - #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information - #endif +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +// == 1200 : -O1 : for __forceinline +// >= 1900 : -O1 : for printf +#pragma warning(disable : 4710) // function not inlined + +#if _MSC_VER < 1900 +// winnt.h: 'Int64ShllMod32' +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#endif + +#if _MSC_VER < 1300 +// #pragma warning(disable : 4702) // unreachable code +// Bra.c : -O1: +#pragma warning(disable : 4714) // function marked as __forceinline not inlined +#endif + +/* +#if _MSC_VER > 1400 && _MSC_VER <= 1900 +// strcat: This function or variable may be unsafe +// sysinfoapi.h: kit10: GetVersion was declared deprecated +#pragma warning(disable : 4996) +#endif +*/ + +#if _MSC_VER > 1200 +// -Wall warnings + +#pragma warning(disable : 4711) // function selected for automatic inline expansion +#pragma warning(disable : 4820) // '2' bytes padding added after data member + +#if _MSC_VER >= 1400 && _MSC_VER < 1920 +// 1400: string.h: _DBG_MEMCPY_INLINE_ +// 1600 - 191x : smmintrin.h __cplusplus' +// is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' +#pragma warning(disable : 4668) + +// 1400 - 1600 : WinDef.h : 'FARPROC' : +// 1900 - 191x : immintrin.h: _readfsbase_u32 +// no function prototype given : converting '()' to '(void)' +#pragma warning(disable : 4255) +#endif + +#if _MSC_VER >= 1914 +// Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#pragma warning(disable : 5045) +#endif + +#endif // _MSC_VER > 1200 +#endif // _MSC_VER + + +#if defined(__clang__) && (__clang_major__ >= 4) + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + _Pragma("clang loop unroll(disable)") \ + _Pragma("clang loop vectorize(disable)") + #define Z7_ATTRIB_NO_VECTORIZE +#elif defined(__GNUC__) && (__GNUC__ >= 5) + #define Z7_ATTRIB_NO_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) + // __attribute__((optimize("no-unroll-loops"))); + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE +#elif defined(_MSC_VER) && (_MSC_VER >= 1920) + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + _Pragma("loop( no_vector )") + #define Z7_ATTRIB_NO_VECTORIZE +#else + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + #define Z7_ATTRIB_NO_VECTORIZE +#endif + +#if defined(MY_CPU_X86_OR_AMD64) && ( \ + defined(__clang__) && (__clang_major__ >= 4) \ + || defined(__GNUC__) && (__GNUC__ >= 5)) + #define Z7_ATTRIB_NO_SSE __attribute__((__target__("no-sse"))) +#else + #define Z7_ATTRIB_NO_SSE +#endif + +#define Z7_ATTRIB_NO_VECTOR \ + Z7_ATTRIB_NO_VECTORIZE \ + Z7_ATTRIB_NO_SSE + + +#if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 1000) \ + /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */ + // GCC is not good for __builtin_expect() + #define Z7_LIKELY(x) (__builtin_expect((x), 1)) + #define Z7_UNLIKELY(x) (__builtin_expect((x), 0)) + // #define Z7_unlikely [[unlikely]] + // #define Z7_likely [[likely]] +#else + #define Z7_LIKELY(x) (x) + #define Z7_UNLIKELY(x) (x) + // #define Z7_likely +#endif + +#if (defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 36000)) +#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wreserved-macro-identifier\"") +#define Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER \ + _Pragma("GCC diagnostic pop") +#else +#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +#define Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER #endif #define UNUSED_VAR(x) (void)x; diff --git a/libraries/lzma/C/CpuArch.c b/libraries/lzma/C/CpuArch.c index 02e482e088a..33f8a3ab4c1 100644 --- a/libraries/lzma/C/CpuArch.c +++ b/libraries/lzma/C/CpuArch.c @@ -1,144 +1,318 @@ /* CpuArch.c -- CPU specific code -2018-02-18: Igor Pavlov : Public domain */ +2023-05-18 : Igor Pavlov : Public domain */ #include "Precomp.h" +// #include + #include "CpuArch.h" #ifdef MY_CPU_X86_OR_AMD64 -#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) -#define USE_ASM +#undef NEED_CHECK_FOR_CPUID +#if !defined(MY_CPU_AMD64) +#define NEED_CHECK_FOR_CPUID #endif -#if !defined(USE_ASM) && _MSC_VER >= 1500 -#include +/* + cpuid instruction supports (subFunction) parameter in ECX, + that is used only with some specific (function) parameter values. + But we always use only (subFunction==0). +*/ +/* + __cpuid(): MSVC and GCC/CLANG use same function/macro name + but parameters are different. + We use MSVC __cpuid() parameters style for our z7_x86_cpuid() function. +*/ + +#if defined(__GNUC__) /* && (__GNUC__ >= 10) */ \ + || defined(__clang__) /* && (__clang_major__ >= 10) */ + +/* there was some CLANG/GCC compilers that have issues with + rbx(ebx) handling in asm blocks in -fPIC mode (__PIC__ is defined). + compiler's contains the macro __cpuid() that is similar to our code. + The history of __cpuid() changes in CLANG/GCC: + GCC: + 2007: it preserved ebx for (__PIC__ && __i386__) + 2013: it preserved rbx and ebx for __PIC__ + 2014: it doesn't preserves rbx and ebx anymore + we suppose that (__GNUC__ >= 5) fixed that __PIC__ ebx/rbx problem. + CLANG: + 2014+: it preserves rbx, but only for 64-bit code. No __PIC__ check. + Why CLANG cares about 64-bit mode only, and doesn't care about ebx (in 32-bit)? + Do we need __PIC__ test for CLANG or we must care about rbx even if + __PIC__ is not defined? +*/ + +#define ASM_LN "\n" + +#if defined(MY_CPU_AMD64) && defined(__PIC__) \ + && ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__)) + +#define x86_cpuid_MACRO(p, func) { \ + __asm__ __volatile__ ( \ + ASM_LN "mov %%rbx, %q1" \ + ASM_LN "cpuid" \ + ASM_LN "xchg %%rbx, %q1" \ + : "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); } + + /* "=&r" selects free register. It can select even rbx, if that register is free. + "=&D" for (RDI) also works, but the code can be larger with "=&D" + "2"(0) means (subFunction = 0), + 2 is (zero-based) index in the output constraint list "=c" (ECX). */ + +#elif defined(MY_CPU_X86) && defined(__PIC__) \ + && ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__)) + +#define x86_cpuid_MACRO(p, func) { \ + __asm__ __volatile__ ( \ + ASM_LN "mov %%ebx, %k1" \ + ASM_LN "cpuid" \ + ASM_LN "xchg %%ebx, %k1" \ + : "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); } + +#else + +#define x86_cpuid_MACRO(p, func) { \ + __asm__ __volatile__ ( \ + ASM_LN "cpuid" \ + : "=a" ((p)[0]), "=b" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); } + #endif -#if defined(USE_ASM) && !defined(MY_CPU_AMD64) -static UInt32 CheckFlag(UInt32 flag) + +void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) { - #ifdef _MSC_VER - __asm pushfd; - __asm pop EAX; - __asm mov EDX, EAX; - __asm xor EAX, flag; - __asm push EAX; - __asm popfd; - __asm pushfd; - __asm pop EAX; - __asm xor EAX, EDX; - __asm push EDX; - __asm popfd; - __asm and flag, EAX; - #else - __asm__ __volatile__ ( - "pushf\n\t" - "pop %%EAX\n\t" - "movl %%EAX,%%EDX\n\t" - "xorl %0,%%EAX\n\t" - "push %%EAX\n\t" - "popf\n\t" - "pushf\n\t" - "pop %%EAX\n\t" - "xorl %%EDX,%%EAX\n\t" - "push %%EDX\n\t" - "popf\n\t" - "andl %%EAX, %0\n\t": - "=c" (flag) : "c" (flag) : - "%eax", "%edx"); - #endif - return flag; + x86_cpuid_MACRO(p, func) } -#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; -#else -#define CHECK_CPUID_IS_SUPPORTED -#endif -void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) + +Z7_NO_INLINE +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) { - #ifdef USE_ASM + #if defined(NEED_CHECK_FOR_CPUID) + #define EFALGS_CPUID_BIT 21 + UInt32 a; + __asm__ __volatile__ ( + ASM_LN "pushf" + ASM_LN "pushf" + ASM_LN "pop %0" + // ASM_LN "movl %0, %1" + // ASM_LN "xorl $0x200000, %0" + ASM_LN "btc %1, %0" + ASM_LN "push %0" + ASM_LN "popf" + ASM_LN "pushf" + ASM_LN "pop %0" + ASM_LN "xorl (%%esp), %0" - #ifdef _MSC_VER + ASM_LN "popf" + ASM_LN + : "=&r" (a) // "=a" + : "i" (EFALGS_CPUID_BIT) + ); + if ((a & (1 << EFALGS_CPUID_BIT)) == 0) + return 0; + #endif + { + UInt32 p[4]; + x86_cpuid_MACRO(p, 0) + return p[0]; + } +} + +#undef ASM_LN - UInt32 a2, b2, c2, d2; - __asm xor EBX, EBX; - __asm xor ECX, ECX; - __asm xor EDX, EDX; - __asm mov EAX, function; - __asm cpuid; - __asm mov a2, EAX; - __asm mov b2, EBX; - __asm mov c2, ECX; - __asm mov d2, EDX; +#elif !defined(_MSC_VER) + +/* +// for gcc/clang and other: we can try to use __cpuid macro: +#include +void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + __cpuid(func, p[0], p[1], p[2], p[3]); +} +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + return (UInt32)__get_cpuid_max(0, NULL); +} +*/ +// for unsupported cpuid: +void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + UNUSED_VAR(func) + p[0] = p[1] = p[2] = p[3] = 0; +} +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + return 0; +} - *a = a2; - *b = b2; - *c = c2; - *d = d2; +#else // _MSC_VER - #else +#if !defined(MY_CPU_AMD64) - __asm__ __volatile__ ( - #if defined(MY_CPU_AMD64) && defined(__PIC__) - "mov %%rbx, %%rdi;" - "cpuid;" - "xchg %%rbx, %%rdi;" - : "=a" (*a) , - "=D" (*b) , - #elif defined(MY_CPU_X86) && defined(__PIC__) - "mov %%ebx, %%edi;" - "cpuid;" - "xchgl %%ebx, %%edi;" - : "=a" (*a) , - "=D" (*b) , - #else - "cpuid" - : "=a" (*a) , - "=b" (*b) , +UInt32 __declspec(naked) Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + #if defined(NEED_CHECK_FOR_CPUID) + #define EFALGS_CPUID_BIT 21 + __asm pushfd + __asm pushfd + /* + __asm pop eax + // __asm mov edx, eax + __asm btc eax, EFALGS_CPUID_BIT + __asm push eax + */ + __asm btc dword ptr [esp], EFALGS_CPUID_BIT + __asm popfd + __asm pushfd + __asm pop eax + // __asm xor eax, edx + __asm xor eax, [esp] + // __asm push edx + __asm popfd + __asm and eax, (1 shl EFALGS_CPUID_BIT) + __asm jz end_func #endif - "=c" (*c) , - "=d" (*d) - : "0" (function)) ; - + __asm push ebx + __asm xor eax, eax // func + __asm xor ecx, ecx // subFunction (optional) for (func == 0) + __asm cpuid + __asm pop ebx + #if defined(NEED_CHECK_FOR_CPUID) + end_func: #endif - - #else + __asm ret 0 +} - int CPUInfo[4]; - __cpuid(CPUInfo, function); - *a = CPUInfo[0]; - *b = CPUInfo[1]; - *c = CPUInfo[2]; - *d = CPUInfo[3]; +void __declspec(naked) Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + UNUSED_VAR(p) + UNUSED_VAR(func) + __asm push ebx + __asm push edi + __asm mov edi, ecx // p + __asm mov eax, edx // func + __asm xor ecx, ecx // subfunction (optional) for (func == 0) + __asm cpuid + __asm mov [edi ], eax + __asm mov [edi + 4], ebx + __asm mov [edi + 8], ecx + __asm mov [edi + 12], edx + __asm pop edi + __asm pop ebx + __asm ret 0 +} - #endif +#else // MY_CPU_AMD64 + + #if _MSC_VER >= 1600 + #include + #define MY_cpuidex __cpuidex + #else +/* + __cpuid (func == (0 or 7)) requires subfunction number in ECX. + MSDN: The __cpuid intrinsic clears the ECX register before calling the cpuid instruction. + __cpuid() in new MSVC clears ECX. + __cpuid() in old MSVC (14.00) x64 doesn't clear ECX + We still can use __cpuid for low (func) values that don't require ECX, + but __cpuid() in old MSVC will be incorrect for some func values: (func == 7). + So here we use the hack for old MSVC to send (subFunction) in ECX register to cpuid instruction, + where ECX value is first parameter for FASTCALL / NO_INLINE func, + So the caller of MY_cpuidex_HACK() sets ECX as subFunction, and + old MSVC for __cpuid() doesn't change ECX and cpuid instruction gets (subFunction) value. + +DON'T remove Z7_NO_INLINE and Z7_FASTCALL for MY_cpuidex_HACK(): !!! +*/ +static +Z7_NO_INLINE void Z7_FASTCALL MY_cpuidex_HACK(UInt32 subFunction, UInt32 func, int *CPUInfo) +{ + UNUSED_VAR(subFunction) + __cpuid(CPUInfo, func); } + #define MY_cpuidex(info, func, func2) MY_cpuidex_HACK(func2, func, info) + #pragma message("======== MY_cpuidex_HACK WAS USED ========") + #endif // _MSC_VER >= 1600 -BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p) +#if !defined(MY_CPU_AMD64) +/* inlining for __cpuid() in MSVC x86 (32-bit) produces big ineffective code, + so we disable inlining here */ +Z7_NO_INLINE +#endif +void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + MY_cpuidex((int *)p, (int)func, 0); +} + +Z7_NO_INLINE +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + int a[4]; + MY_cpuidex(a, 0, 0); + return a[0]; +} + +#endif // MY_CPU_AMD64 +#endif // _MSC_VER + +#if defined(NEED_CHECK_FOR_CPUID) +#define CHECK_CPUID_IS_SUPPORTED { if (z7_x86_cpuid_GetMaxFunc() == 0) return 0; } +#else +#define CHECK_CPUID_IS_SUPPORTED +#endif +#undef NEED_CHECK_FOR_CPUID + + +static +BoolInt x86cpuid_Func_1(UInt32 *p) { CHECK_CPUID_IS_SUPPORTED - MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); - MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); + z7_x86_cpuid(p, 1); return True; } -static const UInt32 kVendors[][3] = +/* +static const UInt32 kVendors[][1] = +{ + { 0x756E6547 }, // , 0x49656E69, 0x6C65746E }, + { 0x68747541 }, // , 0x69746E65, 0x444D4163 }, + { 0x746E6543 } // , 0x48727561, 0x736C7561 } +}; +*/ + +/* +typedef struct +{ + UInt32 maxFunc; + UInt32 vendor[3]; + UInt32 ver; + UInt32 b; + UInt32 c; + UInt32 d; +} Cx86cpuid; + +enum { - { 0x756E6547, 0x49656E69, 0x6C65746E}, - { 0x68747541, 0x69746E65, 0x444D4163}, - { 0x746E6543, 0x48727561, 0x736C7561} + CPU_FIRM_INTEL, + CPU_FIRM_AMD, + CPU_FIRM_VIA }; +int x86cpuid_GetFirm(const Cx86cpuid *p); +#define x86cpuid_ver_GetFamily(ver) (((ver >> 16) & 0xff0) | ((ver >> 8) & 0xf)) +#define x86cpuid_ver_GetModel(ver) (((ver >> 12) & 0xf0) | ((ver >> 4) & 0xf)) +#define x86cpuid_ver_GetStepping(ver) (ver & 0xf) int x86cpuid_GetFirm(const Cx86cpuid *p) { unsigned i; - for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) + for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[0]); i++) { const UInt32 *v = kVendors[i]; - if (v[0] == p->vendor[0] && - v[1] == p->vendor[1] && - v[2] == p->vendor[2]) + if (v[0] == p->vendor[0] + // && v[1] == p->vendor[1] + // && v[2] == p->vendor[2] + ) return (int)i; } return -1; @@ -147,72 +321,503 @@ int x86cpuid_GetFirm(const Cx86cpuid *p) BoolInt CPU_Is_InOrder() { Cx86cpuid p; - int firm; UInt32 family, model; if (!x86cpuid_CheckAndRead(&p)) return True; - family = x86cpuid_GetFamily(p.ver); - model = x86cpuid_GetModel(p.ver); - - firm = x86cpuid_GetFirm(&p); + family = x86cpuid_ver_GetFamily(p.ver); + model = x86cpuid_ver_GetModel(p.ver); - switch (firm) + switch (x86cpuid_GetFirm(&p)) { case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( - /* In-Order Atom CPU */ - model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ - || model == 0x26 /* 45 nm, Z6xx */ - || model == 0x27 /* 32 nm, Z2460 */ - || model == 0x35 /* 32 nm, Z2760 */ - || model == 0x36 /* 32 nm, N2xxx, D2xxx */ + // In-Order Atom CPU + model == 0x1C // 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 + || model == 0x26 // 45 nm, Z6xx + || model == 0x27 // 32 nm, Z2460 + || model == 0x35 // 32 nm, Z2760 + || model == 0x36 // 32 nm, N2xxx, D2xxx ))); case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); } - return True; + return False; // v23 : unknown processors are not In-Order } +*/ + +#ifdef _WIN32 +#include "7zWindows.h" +#endif #if !defined(MY_CPU_AMD64) && defined(_WIN32) -#include -static BoolInt CPU_Sys_Is_SSE_Supported() + +/* for legacy SSE ia32: there is no user-space cpu instruction to check + that OS supports SSE register storing/restoring on context switches. + So we need some OS-specific function to check that it's safe to use SSE registers. +*/ + +Z7_FORCE_INLINE +static BoolInt CPU_Sys_Is_SSE_Supported(void) { - OSVERSIONINFO vi; - vi.dwOSVersionInfoSize = sizeof(vi); - if (!GetVersionEx(&vi)) - return False; - return (vi.dwMajorVersion >= 5); +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4996) // `GetVersion': was declared deprecated +#endif + /* low byte is major version of Windows + We suppose that any Windows version since + Windows2000 (major == 5) supports SSE registers */ + return (Byte)GetVersion() >= 5; +#if defined(_MSC_VER) + #pragma warning(pop) +#endif } #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; #else #define CHECK_SYS_SSE_SUPPORT #endif -BoolInt CPU_Is_Aes_Supported() + +#if !defined(MY_CPU_AMD64) + +BoolInt CPU_IsSupported_CMOV(void) { - Cx86cpuid p; + UInt32 a[4]; + if (!x86cpuid_Func_1(&a[0])) + return 0; + return (a[3] >> 15) & 1; +} + +BoolInt CPU_IsSupported_SSE(void) +{ + UInt32 a[4]; CHECK_SYS_SSE_SUPPORT - if (!x86cpuid_CheckAndRead(&p)) + if (!x86cpuid_Func_1(&a[0])) + return 0; + return (a[3] >> 25) & 1; +} + +BoolInt CPU_IsSupported_SSE2(void) +{ + UInt32 a[4]; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_Func_1(&a[0])) + return 0; + return (a[3] >> 26) & 1; +} + +#endif + + +static UInt32 x86cpuid_Func_1_ECX(void) +{ + UInt32 a[4]; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_Func_1(&a[0])) + return 0; + return a[2]; +} + +BoolInt CPU_IsSupported_AES(void) +{ + return (x86cpuid_Func_1_ECX() >> 25) & 1; +} + +BoolInt CPU_IsSupported_SSSE3(void) +{ + return (x86cpuid_Func_1_ECX() >> 9) & 1; +} + +BoolInt CPU_IsSupported_SSE41(void) +{ + return (x86cpuid_Func_1_ECX() >> 19) & 1; +} + +BoolInt CPU_IsSupported_SHA(void) +{ + CHECK_SYS_SSE_SUPPORT + + if (z7_x86_cpuid_GetMaxFunc() < 7) return False; - return (p.c >> 25) & 1; + { + UInt32 d[4]; + z7_x86_cpuid(d, 7); + return (d[1] >> 29) & 1; + } } -BoolInt CPU_IsSupported_PageGB() +/* +MSVC: _xgetbv() intrinsic is available since VS2010SP1. + MSVC also defines (_XCR_XFEATURE_ENABLED_MASK) macro in + that we can use or check. + For any 32-bit x86 we can use asm code in MSVC, + but MSVC asm code is huge after compilation. + So _xgetbv() is better + +ICC: _xgetbv() intrinsic is available (in what version of ICC?) + ICC defines (__GNUC___) and it supports gnu assembler + also ICC supports MASM style code with -use-msasm switch. + but ICC doesn't support __attribute__((__target__)) + +GCC/CLANG 9: + _xgetbv() is macro that works via __builtin_ia32_xgetbv() + and we need __attribute__((__target__("xsave")). + But with __target__("xsave") the function will be not + inlined to function that has no __target__("xsave") attribute. + If we want _xgetbv() call inlining, then we should use asm version + instead of calling _xgetbv(). + Note:intrinsic is broke before GCC 8.2: + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684 +*/ + +#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) \ + || defined(_MSC_VER) && (_MSC_VER >= 1600) && (_MSC_FULL_VER >= 160040219) \ + || defined(__GNUC__) && (__GNUC__ >= 9) \ + || defined(__clang__) && (__clang_major__ >= 9) +// we define ATTRIB_XGETBV, if we want to use predefined _xgetbv() from compiler +#if defined(__INTEL_COMPILER) +#define ATTRIB_XGETBV +#elif defined(__GNUC__) || defined(__clang__) +// we don't define ATTRIB_XGETBV here, because asm version is better for inlining. +// #define ATTRIB_XGETBV __attribute__((__target__("xsave"))) +#else +#define ATTRIB_XGETBV +#endif +#endif + +#if defined(ATTRIB_XGETBV) +#include +#endif + + +// XFEATURE_ENABLED_MASK/XCR0 +#define MY_XCR_XFEATURE_ENABLED_MASK 0 + +#if defined(ATTRIB_XGETBV) +ATTRIB_XGETBV +#endif +static UInt64 x86_xgetbv_0(UInt32 num) { - Cx86cpuid cpuid; - if (!x86cpuid_CheckAndRead(&cpuid)) +#if defined(ATTRIB_XGETBV) + { + return + #if (defined(_MSC_VER)) + _xgetbv(num); + #else + __builtin_ia32_xgetbv( + #if !defined(__clang__) + (int) + #endif + num); + #endif + } + +#elif defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_CC) + + UInt32 a, d; + #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) + __asm__ + ( + "xgetbv" + : "=a"(a), "=d"(d) : "c"(num) : "cc" + ); + #else // is old gcc + __asm__ + ( + ".byte 0x0f, 0x01, 0xd0" "\n\t" + : "=a"(a), "=d"(d) : "c"(num) : "cc" + ); + #endif + return ((UInt64)d << 32) | a; + // return a; + +#elif defined(_MSC_VER) && !defined(MY_CPU_AMD64) + + UInt32 a, d; + __asm { + push eax + push edx + push ecx + mov ecx, num; + // xor ecx, ecx // = MY_XCR_XFEATURE_ENABLED_MASK + _emit 0x0f + _emit 0x01 + _emit 0xd0 + mov a, eax + mov d, edx + pop ecx + pop edx + pop eax + } + return ((UInt64)d << 32) | a; + // return a; + +#else // it's unknown compiler + // #error "Need xgetbv function" + UNUSED_VAR(num) + // for MSVC-X64 we could call external function from external file. + /* Actually we had checked OSXSAVE/AVX in cpuid before. + So it's expected that OS supports at least AVX and below. */ + // if (num != MY_XCR_XFEATURE_ENABLED_MASK) return 0; // if not XCR0 + return + // (1 << 0) | // x87 + (1 << 1) // SSE + | (1 << 2); // AVX + +#endif +} + +#ifdef _WIN32 +/* + Windows versions do not know about new ISA extensions that + can be introduced. But we still can use new extensions, + even if Windows doesn't report about supporting them, + But we can use new extensions, only if Windows knows about new ISA extension + that changes the number or size of registers: SSE, AVX/XSAVE, AVX512 + So it's enough to check + MY_PF_AVX_INSTRUCTIONS_AVAILABLE + instead of + MY_PF_AVX2_INSTRUCTIONS_AVAILABLE +*/ +#define MY_PF_XSAVE_ENABLED 17 +// #define MY_PF_SSSE3_INSTRUCTIONS_AVAILABLE 36 +// #define MY_PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37 +// #define MY_PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38 +// #define MY_PF_AVX_INSTRUCTIONS_AVAILABLE 39 +// #define MY_PF_AVX2_INSTRUCTIONS_AVAILABLE 40 +// #define MY_PF_AVX512F_INSTRUCTIONS_AVAILABLE 41 +#endif + +BoolInt CPU_IsSupported_AVX(void) +{ + #ifdef _WIN32 + if (!IsProcessorFeaturePresent(MY_PF_XSAVE_ENABLED)) return False; + /* PF_AVX_INSTRUCTIONS_AVAILABLE probably is supported starting from + some latest Win10 revisions. But we need AVX in older Windows also. + So we don't use the following check: */ + /* + if (!IsProcessorFeaturePresent(MY_PF_AVX_INSTRUCTIONS_AVAILABLE)) + return False; + */ + #endif + + /* + OS must use new special XSAVE/XRSTOR instructions to save + AVX registers when it required for context switching. + At OS statring: + OS sets CR4.OSXSAVE flag to signal the processor that OS supports the XSAVE extensions. + Also OS sets bitmask in XCR0 register that defines what + registers will be processed by XSAVE instruction: + XCR0.SSE[bit 0] - x87 registers and state + XCR0.SSE[bit 1] - SSE registers and state + XCR0.AVX[bit 2] - AVX registers and state + CR4.OSXSAVE is reflected to CPUID.1:ECX.OSXSAVE[bit 27]. + So we can read that bit in user-space. + XCR0 is available for reading in user-space by new XGETBV instruction. + */ { - UInt32 d[4] = { 0 }; - MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]); - if (d[0] < 0x80000001) + const UInt32 c = x86cpuid_Func_1_ECX(); + if (0 == (1 + & (c >> 28) // AVX instructions are supported by hardware + & (c >> 27))) // OSXSAVE bit: XSAVE and related instructions are enabled by OS. return False; } + + /* also we can check + CPUID.1:ECX.XSAVE [bit 26] : that shows that + XSAVE, XRESTOR, XSETBV, XGETBV instructions are supported by hardware. + But that check is redundant, because if OSXSAVE bit is set, then XSAVE is also set */ + + /* If OS have enabled XSAVE extension instructions (OSXSAVE == 1), + in most cases we expect that OS also will support storing/restoring + for AVX and SSE states at least. + But to be ensure for that we call user-space instruction + XGETBV(0) to get XCR0 value that contains bitmask that defines + what exact states(registers) OS have enabled for storing/restoring. + */ + + { + const UInt32 bm = (UInt32)x86_xgetbv_0(MY_XCR_XFEATURE_ENABLED_MASK); + // printf("\n=== XGetBV=%d\n", bm); + return 1 + & (bm >> 1) // SSE state is supported (set by OS) for storing/restoring + & (bm >> 2); // AVX state is supported (set by OS) for storing/restoring + } + // since Win7SP1: we can use GetEnabledXStateFeatures(); +} + + +BoolInt CPU_IsSupported_AVX2(void) +{ + if (!CPU_IsSupported_AVX()) + return False; + if (z7_x86_cpuid_GetMaxFunc() < 7) + return False; + { + UInt32 d[4]; + z7_x86_cpuid(d, 7); + // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); + return 1 + & (d[1] >> 5); // avx2 + } +} + +BoolInt CPU_IsSupported_VAES_AVX2(void) +{ + if (!CPU_IsSupported_AVX()) + return False; + if (z7_x86_cpuid_GetMaxFunc() < 7) + return False; { - UInt32 d[4] = { 0 }; - MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]); + UInt32 d[4]; + z7_x86_cpuid(d, 7); + // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); + return 1 + & (d[1] >> 5) // avx2 + // & (d[1] >> 31) // avx512vl + & (d[2] >> 9); // vaes // VEX-256/EVEX + } +} + +BoolInt CPU_IsSupported_PageGB(void) +{ + CHECK_CPUID_IS_SUPPORTED + { + UInt32 d[4]; + z7_x86_cpuid(d, 0x80000000); + if (d[0] < 0x80000001) + return False; + z7_x86_cpuid(d, 0x80000001); return (d[3] >> 26) & 1; } } + +#elif defined(MY_CPU_ARM_OR_ARM64) + +#ifdef _WIN32 + +#include "7zWindows.h" + +BoolInt CPU_IsSupported_CRC32(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } +BoolInt CPU_IsSupported_CRYPTO(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } +BoolInt CPU_IsSupported_NEON(void) { return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } + +#else + +#if defined(__APPLE__) + +/* +#include +#include +static void Print_sysctlbyname(const char *name) +{ + size_t bufSize = 256; + char buf[256]; + int res = sysctlbyname(name, &buf, &bufSize, NULL, 0); + { + int i; + printf("\nres = %d : %s : '%s' : bufSize = %d, numeric", res, name, buf, (unsigned)bufSize); + for (i = 0; i < 20; i++) + printf(" %2x", (unsigned)(Byte)buf[i]); + + } +} +*/ +/* + Print_sysctlbyname("hw.pagesize"); + Print_sysctlbyname("machdep.cpu.brand_string"); +*/ + +static BoolInt z7_sysctlbyname_Get_BoolInt(const char *name) +{ + UInt32 val = 0; + if (z7_sysctlbyname_Get_UInt32(name, &val) == 0 && val == 1) + return 1; + return 0; +} + +BoolInt CPU_IsSupported_CRC32(void) +{ + return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32"); +} + +BoolInt CPU_IsSupported_NEON(void) +{ + return z7_sysctlbyname_Get_BoolInt("hw.optional.neon"); +} + +#ifdef MY_CPU_ARM64 +#define APPLE_CRYPTO_SUPPORT_VAL 1 +#else +#define APPLE_CRYPTO_SUPPORT_VAL 0 +#endif + +BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; } +BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; } +BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; } + + +#else // __APPLE__ + +#include + +#define USE_HWCAP + +#ifdef USE_HWCAP + +#include + + #define MY_HWCAP_CHECK_FUNC_2(name1, name2) \ + BoolInt CPU_IsSupported_ ## name1() { return (getauxval(AT_HWCAP) & (HWCAP_ ## name2)) ? 1 : 0; } + +#ifdef MY_CPU_ARM64 + #define MY_HWCAP_CHECK_FUNC(name) \ + MY_HWCAP_CHECK_FUNC_2(name, name) + MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD) +// MY_HWCAP_CHECK_FUNC (ASIMD) +#elif defined(MY_CPU_ARM) + #define MY_HWCAP_CHECK_FUNC(name) \ + BoolInt CPU_IsSupported_ ## name() { return (getauxval(AT_HWCAP2) & (HWCAP2_ ## name)) ? 1 : 0; } + MY_HWCAP_CHECK_FUNC_2(NEON, NEON) +#endif + +#else // USE_HWCAP + + #define MY_HWCAP_CHECK_FUNC(name) \ + BoolInt CPU_IsSupported_ ## name() { return 0; } + MY_HWCAP_CHECK_FUNC(NEON) + +#endif // USE_HWCAP + +MY_HWCAP_CHECK_FUNC (CRC32) +MY_HWCAP_CHECK_FUNC (SHA1) +MY_HWCAP_CHECK_FUNC (SHA2) +MY_HWCAP_CHECK_FUNC (AES) + +#endif // __APPLE__ +#endif // _WIN32 + +#endif // MY_CPU_ARM_OR_ARM64 + + + +#ifdef __APPLE__ + +#include + +int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize) +{ + return sysctlbyname(name, buf, bufSize, NULL, 0); +} + +int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val) +{ + size_t bufSize = sizeof(*val); + const int res = z7_sysctlbyname_Get(name, val, &bufSize); + if (res == 0 && bufSize != sizeof(*val)) + return EFAULT; + return res; +} + #endif diff --git a/libraries/lzma/C/CpuArch.h b/libraries/lzma/C/CpuArch.h index bd429388024..8e5d8a543f8 100644 --- a/libraries/lzma/C/CpuArch.h +++ b/libraries/lzma/C/CpuArch.h @@ -1,8 +1,8 @@ /* CpuArch.h -- CPU specific code -2018-02-18 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ -#ifndef __CPU_ARCH_H -#define __CPU_ARCH_H +#ifndef ZIP7_INC_CPU_ARCH_H +#define ZIP7_INC_CPU_ARCH_H #include "7zTypes.h" @@ -14,6 +14,10 @@ MY_CPU_BE means that CPU is BIG ENDIAN. If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. + +MY_CPU_64BIT means that processor can work with 64-bit registers. + MY_CPU_64BIT can be used to select fast code branch + MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8) */ #if defined(_M_X64) \ @@ -24,8 +28,10 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem #define MY_CPU_AMD64 #ifdef __ILP32__ #define MY_CPU_NAME "x32" + #define MY_CPU_SIZEOF_POINTER 4 #else #define MY_CPU_NAME "x64" + #define MY_CPU_SIZEOF_POINTER 8 #endif #define MY_CPU_64BIT #endif @@ -35,7 +41,8 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem || defined(__i386__) #define MY_CPU_X86 #define MY_CPU_NAME "x86" - #define MY_CPU_32BIT + /* #define MY_CPU_32BIT */ + #define MY_CPU_SIZEOF_POINTER 4 #endif @@ -44,7 +51,13 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem || defined(__AARCH64EB__) \ || defined(__aarch64__) #define MY_CPU_ARM64 - #define MY_CPU_NAME "arm64" + #ifdef __ILP32__ + #define MY_CPU_NAME "arm64-32" + #define MY_CPU_SIZEOF_POINTER 4 + #else + #define MY_CPU_NAME "arm64" + #define MY_CPU_SIZEOF_POINTER 8 + #endif #define MY_CPU_64BIT #endif @@ -59,8 +72,16 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem || defined(__THUMBEL__) \ || defined(__THUMBEB__) #define MY_CPU_ARM - #define MY_CPU_NAME "arm" - #define MY_CPU_32BIT + + #if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT) + #define MY_CPU_ARMT + #define MY_CPU_NAME "armt" + #else + #define MY_CPU_ARM32 + #define MY_CPU_NAME "arm" + #endif + /* #define MY_CPU_32BIT */ + #define MY_CPU_SIZEOF_POINTER 4 #endif @@ -84,26 +105,43 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem #if defined(__ppc64__) \ - || defined(__powerpc64__) + || defined(__powerpc64__) \ + || defined(__ppc__) \ + || defined(__powerpc__) \ + || defined(__PPC__) \ + || defined(_POWER) + +#define MY_CPU_PPC_OR_PPC64 + +#if defined(__ppc64__) \ + || defined(__powerpc64__) \ + || defined(_LP64) \ + || defined(__64BIT__) #ifdef __ILP32__ #define MY_CPU_NAME "ppc64-32" + #define MY_CPU_SIZEOF_POINTER 4 #else #define MY_CPU_NAME "ppc64" + #define MY_CPU_SIZEOF_POINTER 8 #endif #define MY_CPU_64BIT -#elif defined(__ppc__) \ - || defined(__powerpc__) +#else #define MY_CPU_NAME "ppc" - #define MY_CPU_32BIT + #define MY_CPU_SIZEOF_POINTER 4 + /* #define MY_CPU_32BIT */ +#endif #endif -#if defined(__sparc64__) - #define MY_CPU_NAME "sparc64" - #define MY_CPU_64BIT -#elif defined(__sparc__) - #define MY_CPU_NAME "sparc" - /* #define MY_CPU_32BIT */ +#if defined(__riscv) \ + || defined(__riscv__) + #if __riscv_xlen == 32 + #define MY_CPU_NAME "riscv32" + #elif __riscv_xlen == 64 + #define MY_CPU_NAME "riscv64" + #else + #define MY_CPU_NAME "riscv" + #endif #endif @@ -111,6 +149,10 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem #define MY_CPU_X86_OR_AMD64 #endif +#if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64) +#define MY_CPU_ARM_OR_ARM64 +#endif + #ifdef _WIN32 @@ -165,11 +207,48 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem #error Stop_Compiling_Bad_Endian #endif +#if !defined(MY_CPU_LE) && !defined(MY_CPU_BE) + #error Stop_Compiling_CPU_ENDIAN_must_be_detected_at_compile_time +#endif #if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT) #error Stop_Compiling_Bad_32_64_BIT #endif +#ifdef __SIZEOF_POINTER__ + #ifdef MY_CPU_SIZEOF_POINTER + #if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__ + #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE + #endif + #else + #define MY_CPU_SIZEOF_POINTER __SIZEOF_POINTER__ + #endif +#endif + +#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) +#if defined (_LP64) + #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE +#endif +#endif + +#ifdef _MSC_VER + #if _MSC_VER >= 1300 + #define MY_CPU_pragma_pack_push_1 __pragma(pack(push, 1)) + #define MY_CPU_pragma_pop __pragma(pack(pop)) + #else + #define MY_CPU_pragma_pack_push_1 + #define MY_CPU_pragma_pop + #endif +#else + #ifdef __xlC__ + #define MY_CPU_pragma_pack_push_1 _Pragma("pack(1)") + #define MY_CPU_pragma_pop _Pragma("pack()") + #else + #define MY_CPU_pragma_pack_push_1 _Pragma("pack(push, 1)") + #define MY_CPU_pragma_pop _Pragma("pack(pop)") + #endif +#endif + #ifndef MY_CPU_NAME #ifdef MY_CPU_LE @@ -187,10 +266,75 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem +#ifdef __has_builtin + #define Z7_has_builtin(x) __has_builtin(x) +#else + #define Z7_has_builtin(x) 0 +#endif + + +#define Z7_BSWAP32_CONST(v) \ + ( (((UInt32)(v) << 24) ) \ + | (((UInt32)(v) << 8) & (UInt32)0xff0000) \ + | (((UInt32)(v) >> 8) & (UInt32)0xff00 ) \ + | (((UInt32)(v) >> 24) )) + + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) + +#include + +/* Note: these macros will use bswap instruction (486), that is unsupported in 386 cpu */ + +#pragma intrinsic(_byteswap_ushort) +#pragma intrinsic(_byteswap_ulong) +#pragma intrinsic(_byteswap_uint64) + +#define Z7_BSWAP16(v) _byteswap_ushort(v) +#define Z7_BSWAP32(v) _byteswap_ulong (v) +#define Z7_BSWAP64(v) _byteswap_uint64(v) +#define Z7_CPU_FAST_BSWAP_SUPPORTED + +#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ + || (defined(__clang__) && Z7_has_builtin(__builtin_bswap16)) + +#define Z7_BSWAP16(v) __builtin_bswap16(v) +#define Z7_BSWAP32(v) __builtin_bswap32(v) +#define Z7_BSWAP64(v) __builtin_bswap64(v) +#define Z7_CPU_FAST_BSWAP_SUPPORTED + +#else + +#define Z7_BSWAP16(v) ((UInt16) \ + ( ((UInt32)(v) << 8) \ + | ((UInt32)(v) >> 8) \ + )) + +#define Z7_BSWAP32(v) Z7_BSWAP32_CONST(v) + +#define Z7_BSWAP64(v) \ + ( ( ( (UInt64)(v) ) << 8 * 7 ) \ + | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 1) ) << 8 * 5 ) \ + | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 2) ) << 8 * 3 ) \ + | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 3) ) << 8 * 1 ) \ + | ( ( (UInt64)(v) >> 8 * 1 ) & ((UInt32)0xff << 8 * 3) ) \ + | ( ( (UInt64)(v) >> 8 * 3 ) & ((UInt32)0xff << 8 * 2) ) \ + | ( ( (UInt64)(v) >> 8 * 5 ) & ((UInt32)0xff << 8 * 1) ) \ + | ( ( (UInt64)(v) >> 8 * 7 ) ) \ + ) + +#endif + + + #ifdef MY_CPU_LE #if defined(MY_CPU_X86_OR_AMD64) \ - || defined(MY_CPU_ARM64) \ - || defined(__ARM_FEATURE_UNALIGNED) + || defined(MY_CPU_ARM64) + #define MY_CPU_LE_UNALIGN + #define MY_CPU_LE_UNALIGN_64 + #elif defined(__ARM_FEATURE_UNALIGNED) + /* gcc9 for 32-bit arm can use LDRD instruction that requires 32-bit alignment. + So we can't use unaligned 64-bit operations. */ #define MY_CPU_LE_UNALIGN #endif #endif @@ -200,11 +344,13 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem #define GetUi16(p) (*(const UInt16 *)(const void *)(p)) #define GetUi32(p) (*(const UInt32 *)(const void *)(p)) +#ifdef MY_CPU_LE_UNALIGN_64 #define GetUi64(p) (*(const UInt64 *)(const void *)(p)) +#define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); } +#endif -#define SetUi16(p, v) { *(UInt16 *)(p) = (v); } -#define SetUi32(p, v) { *(UInt32 *)(p) = (v); } -#define SetUi64(p, v) { *(UInt64 *)(p) = (v); } +#define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); } +#define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); } #else @@ -218,8 +364,6 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem ((UInt32)((const Byte *)(p))[2] << 16) | \ ((UInt32)((const Byte *)(p))[3] << 24)) -#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) - #define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ _ppp_[0] = (Byte)_vvv_; \ _ppp_[1] = (Byte)(_vvv_ >> 8); } @@ -230,43 +374,28 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem _ppp_[2] = (Byte)(_vvv_ >> 16); \ _ppp_[3] = (Byte)(_vvv_ >> 24); } -#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ - SetUi32(_ppp2_ , (UInt32)_vvv2_); \ - SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); } - #endif -#ifdef __has_builtin - #define MY__has_builtin(x) __has_builtin(x) -#else - #define MY__has_builtin(x) 0 -#endif - -#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300) - -/* Note: we use bswap instruction, that is unsupported in 386 cpu */ - -#include -#pragma intrinsic(_byteswap_ushort) -#pragma intrinsic(_byteswap_ulong) -#pragma intrinsic(_byteswap_uint64) +#ifndef GetUi64 +#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) +#endif -/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */ -#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) -#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) +#ifndef SetUi64 +#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ + SetUi32(_ppp2_ , (UInt32)_vvv2_) \ + SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)) } +#endif -#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v) -#elif defined(MY_CPU_LE_UNALIGN) && ( \ - (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ - || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) ) +#if defined(MY_CPU_LE_UNALIGN) && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) -/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const Byte *)(p)) */ -#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p)) -#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p)) +#define GetBe32(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p)) +#define SetBe32(p, v) { (*(UInt32 *)(void *)(p)) = Z7_BSWAP32(v); } -#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v) +#if defined(MY_CPU_LE_UNALIGN_64) +#define GetBe64(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p)) +#endif #else @@ -276,8 +405,6 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem ((UInt32)((const Byte *)(p))[2] << 8) | \ ((const Byte *)(p))[3] ) -#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) - #define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ _ppp_[0] = (Byte)(_vvv_ >> 24); \ _ppp_[1] = (Byte)(_vvv_ >> 16); \ @@ -286,49 +413,109 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem #endif +#ifndef GetBe64 +#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) +#endif #ifndef GetBe16 - #define GetBe16(p) ( (UInt16) ( \ ((UInt16)((const Byte *)(p))[0] << 8) | \ ((const Byte *)(p))[1] )) +#endif + +#if defined(MY_CPU_BE) +#define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v) +#define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) +#define Z7_CONV_NATIVE_TO_BE_32(v) (v) +#elif defined(MY_CPU_LE) +#define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) +#define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v) +#define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v) +#else +#error Stop_Compiling_Unknown_Endian_CONV #endif +#if defined(MY_CPU_BE) -#ifdef MY_CPU_X86_OR_AMD64 +#define GetBe32a(p) (*(const UInt32 *)(const void *)(p)) +#define GetBe16a(p) (*(const UInt16 *)(const void *)(p)) +#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); } +#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); } -typedef struct -{ - UInt32 maxFunc; - UInt32 vendor[3]; - UInt32 ver; - UInt32 b; - UInt32 c; - UInt32 d; -} Cx86cpuid; +#define GetUi32a(p) GetUi32(p) +#define GetUi16a(p) GetUi16(p) +#define SetUi32a(p, v) SetUi32(p, v) +#define SetUi16a(p, v) SetUi16(p, v) -enum -{ - CPU_FIRM_INTEL, - CPU_FIRM_AMD, - CPU_FIRM_VIA -}; +#elif defined(MY_CPU_LE) -void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d); +#define GetUi32a(p) (*(const UInt32 *)(const void *)(p)) +#define GetUi16a(p) (*(const UInt16 *)(const void *)(p)) +#define SetUi32a(p, v) { *(UInt32 *)(void *)(p) = (v); } +#define SetUi16a(p, v) { *(UInt16 *)(void *)(p) = (v); } -BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p); -int x86cpuid_GetFirm(const Cx86cpuid *p); +#define GetBe32a(p) GetBe32(p) +#define GetBe16a(p) GetBe16(p) +#define SetBe32a(p, v) SetBe32(p, v) +#define SetBe16a(p, v) SetBe16(p, v) + +#else +#error Stop_Compiling_Unknown_Endian_CPU_a +#endif -#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF)) -#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF)) -#define x86cpuid_GetStepping(ver) (ver & 0xF) -BoolInt CPU_Is_InOrder(); -BoolInt CPU_Is_Aes_Supported(); -BoolInt CPU_IsSupported_PageGB(); +#if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM_OR_ARM64) \ + || defined(MY_CPU_PPC_OR_PPC64) + #define Z7_CPU_FAST_ROTATE_SUPPORTED +#endif + + +#ifdef MY_CPU_X86_OR_AMD64 + +void Z7_FASTCALL z7_x86_cpuid(UInt32 a[4], UInt32 function); +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void); +#if defined(MY_CPU_AMD64) +#define Z7_IF_X86_CPUID_SUPPORTED +#else +#define Z7_IF_X86_CPUID_SUPPORTED if (z7_x86_cpuid_GetMaxFunc()) +#endif + +BoolInt CPU_IsSupported_AES(void); +BoolInt CPU_IsSupported_AVX(void); +BoolInt CPU_IsSupported_AVX2(void); +BoolInt CPU_IsSupported_VAES_AVX2(void); +BoolInt CPU_IsSupported_CMOV(void); +BoolInt CPU_IsSupported_SSE(void); +BoolInt CPU_IsSupported_SSE2(void); +BoolInt CPU_IsSupported_SSSE3(void); +BoolInt CPU_IsSupported_SSE41(void); +BoolInt CPU_IsSupported_SHA(void); +BoolInt CPU_IsSupported_PageGB(void); + +#elif defined(MY_CPU_ARM_OR_ARM64) + +BoolInt CPU_IsSupported_CRC32(void); +BoolInt CPU_IsSupported_NEON(void); + +#if defined(_WIN32) +BoolInt CPU_IsSupported_CRYPTO(void); +#define CPU_IsSupported_SHA1 CPU_IsSupported_CRYPTO +#define CPU_IsSupported_SHA2 CPU_IsSupported_CRYPTO +#define CPU_IsSupported_AES CPU_IsSupported_CRYPTO +#else +BoolInt CPU_IsSupported_SHA1(void); +BoolInt CPU_IsSupported_SHA2(void); +BoolInt CPU_IsSupported_AES(void); +#endif + +#endif +#if defined(__APPLE__) +int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize); +int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val); #endif EXTERN_C_END diff --git a/libraries/lzma/C/Delta.c b/libraries/lzma/C/Delta.c index e3edd21edbb..c4a4499fe2a 100644 --- a/libraries/lzma/C/Delta.c +++ b/libraries/lzma/C/Delta.c @@ -1,5 +1,5 @@ /* Delta.c -- Delta converter -2009-05-26 : Igor Pavlov : Public domain */ +2021-02-09 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -12,53 +12,158 @@ void Delta_Init(Byte *state) state[i] = 0; } -static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) -{ - unsigned i; - for (i = 0; i < size; i++) - dest[i] = src[i]; -} void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) { - Byte buf[DELTA_STATE_SIZE]; - unsigned j = 0; - MyMemCpy(buf, state, delta); + Byte temp[DELTA_STATE_SIZE]; + + if (size == 0) + return; + + { + unsigned i = 0; + do + temp[i] = state[i]; + while (++i != delta); + } + + if (size <= delta) + { + unsigned i = 0, k; + do + { + Byte b = *data; + *data++ = (Byte)(b - temp[i]); + temp[i] = b; + } + while (++i != size); + + k = 0; + + do + { + if (i == delta) + i = 0; + state[k] = temp[i++]; + } + while (++k != delta); + + return; + } + { - SizeT i; - for (i = 0; i < size;) + Byte *p = data + size - delta; + { + unsigned i = 0; + do + state[i] = *p++; + while (++i != delta); + } { - for (j = 0; j < delta && i < size; i++, j++) + const Byte *lim = data + delta; + ptrdiff_t dif = -(ptrdiff_t)delta; + + if (((ptrdiff_t)size + dif) & 1) { - Byte b = data[i]; - data[i] = (Byte)(b - buf[j]); - buf[j] = b; + --p; *p = (Byte)(*p - p[dif]); } + + while (p != lim) + { + --p; *p = (Byte)(*p - p[dif]); + --p; *p = (Byte)(*p - p[dif]); + } + + dif = -dif; + + do + { + --p; *p = (Byte)(*p - temp[--dif]); + } + while (dif != 0); } } - if (j == delta) - j = 0; - MyMemCpy(state, buf + j, delta - j); - MyMemCpy(state + delta - j, buf, j); } + void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) { - Byte buf[DELTA_STATE_SIZE]; - unsigned j = 0; - MyMemCpy(buf, state, delta); + unsigned i; + const Byte *lim; + + if (size == 0) + return; + + i = 0; + lim = data + size; + + if (size <= delta) + { + do + *data = (Byte)(*data + state[i++]); + while (++data != lim); + + for (; delta != i; state++, delta--) + *state = state[i]; + data -= i; + } + else { - SizeT i; - for (i = 0; i < size;) + /* + #define B(n) b ## n + #define I(n) Byte B(n) = state[n]; + #define U(n) { B(n) = (Byte)((B(n)) + *data++); data[-1] = (B(n)); } + #define F(n) if (data != lim) { U(n) } + + if (delta == 1) + { + I(0) + if ((lim - data) & 1) { U(0) } + while (data != lim) { U(0) U(0) } + data -= 1; + } + else if (delta == 2) { - for (j = 0; j < delta && i < size; i++, j++) + I(0) I(1) + lim -= 1; while (data < lim) { U(0) U(1) } + lim += 1; F(0) + data -= 2; + } + else if (delta == 3) + { + I(0) I(1) I(2) + lim -= 2; while (data < lim) { U(0) U(1) U(2) } + lim += 2; F(0) F(1) + data -= 3; + } + else if (delta == 4) + { + I(0) I(1) I(2) I(3) + lim -= 3; while (data < lim) { U(0) U(1) U(2) U(3) } + lim += 3; F(0) F(1) F(2) + data -= 4; + } + else + */ + { + do + { + *data = (Byte)(*data + state[i++]); + data++; + } + while (i != delta); + { - buf[j] = data[i] = (Byte)(buf[j] + data[i]); + ptrdiff_t dif = -(ptrdiff_t)delta; + do + *data = (Byte)(*data + data[dif]); + while (++data != lim); + data += dif; } } } - if (j == delta) - j = 0; - MyMemCpy(state, buf + j, delta - j); - MyMemCpy(state + delta - j, buf, j); + + do + *state++ = *data; + while (++data != lim); } diff --git a/libraries/lzma/C/Delta.h b/libraries/lzma/C/Delta.h index 2fa54ad67b3..706095417aa 100644 --- a/libraries/lzma/C/Delta.h +++ b/libraries/lzma/C/Delta.h @@ -1,8 +1,8 @@ /* Delta.h -- Delta converter -2013-01-18 : Igor Pavlov : Public domain */ +2023-03-03 : Igor Pavlov : Public domain */ -#ifndef __DELTA_H -#define __DELTA_H +#ifndef ZIP7_INC_DELTA_H +#define ZIP7_INC_DELTA_H #include "7zTypes.h" diff --git a/libraries/lzma/C/DllSecur.c b/libraries/lzma/C/DllSecur.c new file mode 100644 index 00000000000..02a0f977ead --- /dev/null +++ b/libraries/lzma/C/DllSecur.c @@ -0,0 +1,111 @@ +/* DllSecur.c -- DLL loading security +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifdef _WIN32 + +#include "7zWindows.h" + +#include "DllSecur.h" + +#ifndef UNDER_CE + +#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__) + // #pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + +#if defined(__clang__) || defined(__GNUC__) +typedef void (*Z7_voidFunction)(void); +#define MY_CAST_FUNC (Z7_voidFunction) +#elif defined(_MSC_VER) && _MSC_VER > 1920 +#define MY_CAST_FUNC (void *) +// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()' +#else +#define MY_CAST_FUNC +#endif + +typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags); + +#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400 +#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800 + +#define DELIM "\0" + +static const char * const g_Dlls = + "userenv" + DELIM "setupapi" + DELIM "apphelp" + DELIM "propsys" + DELIM "dwmapi" + DELIM "cryptbase" + DELIM "oleacc" + DELIM "clbcatq" + DELIM "version" + #ifndef _CONSOLE + DELIM "uxtheme" + #endif + DELIM; + +#endif + +#ifdef __clang__ + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +#if defined (_MSC_VER) && _MSC_VER >= 1900 +// sysinfoapi.h: kit10: GetVersion was declared deprecated +#pragma warning(disable : 4996) +#endif + +#define IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN \ + if ((UInt16)GetVersion() != 6) { \ + const \ + Func_SetDefaultDllDirectories setDllDirs = \ + (Func_SetDefaultDllDirectories) MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), \ + "SetDefaultDllDirectories"); \ + if (setDllDirs) if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) return; } + +void My_SetDefaultDllDirectories(void) +{ + #ifndef UNDER_CE + IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN + #endif +} + + +void LoadSecurityDlls(void) +{ + #ifndef UNDER_CE + // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ??? + IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN + { + wchar_t buf[MAX_PATH + 100]; + const char *dll; + unsigned pos = GetSystemDirectoryW(buf, MAX_PATH + 2); + if (pos == 0 || pos > MAX_PATH) + return; + if (buf[pos - 1] != '\\') + buf[pos++] = '\\'; + for (dll = g_Dlls; *dll != 0;) + { + wchar_t *dest = &buf[pos]; + for (;;) + { + const char c = *dll++; + if (c == 0) + break; + *dest++ = (Byte)c; + } + dest[0] = '.'; + dest[1] = 'd'; + dest[2] = 'l'; + dest[3] = 'l'; + dest[4] = 0; + // lstrcatW(buf, L".dll"); + LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + } + } + #endif +} + +#endif // _WIN32 diff --git a/libraries/lzma/C/DllSecur.h b/libraries/lzma/C/DllSecur.h new file mode 100644 index 00000000000..9fa41538265 --- /dev/null +++ b/libraries/lzma/C/DllSecur.h @@ -0,0 +1,20 @@ +/* DllSecur.h -- DLL loading for security +2023-03-03 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_DLL_SECUR_H +#define ZIP7_INC_DLL_SECUR_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#ifdef _WIN32 + +void My_SetDefaultDllDirectories(void); +void LoadSecurityDlls(void); + +#endif + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/LzFind.c b/libraries/lzma/C/LzFind.c index df55e86c146..0fbd5aae563 100644 --- a/libraries/lzma/C/LzFind.c +++ b/libraries/lzma/C/LzFind.c @@ -1,74 +1,134 @@ /* LzFind.c -- Match finder for LZ algorithms -2018-07-08 : Igor Pavlov : Public domain */ +2023-03-14 : Igor Pavlov : Public domain */ #include "Precomp.h" #include +// #include +#include "CpuArch.h" #include "LzFind.h" #include "LzHash.h" +#define kBlockMoveAlign (1 << 7) // alignment for memmove() +#define kBlockSizeAlign (1 << 16) // alignment for block allocation +#define kBlockSizeReserveMin (1 << 24) // it's 1/256 from 4 GB dictinary + #define kEmptyHashValue 0 -#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) -#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ -#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1)) -#define kMaxHistorySize ((UInt32)7 << 29) -#define kStartMaxLen 3 +#define kMaxValForNormalize ((UInt32)0) +// #define kMaxValForNormalize ((UInt32)(1 << 20) + 0xfff) // for debug + +// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses + +#define GET_AVAIL_BYTES(p) \ + Inline_MatchFinder_GetNumAvailableBytes(p) + + +// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) +#define kFix5HashSize kFix4HashSize + +/* + HASH2_CALC: + if (hv) match, then cur[0] and cur[1] also match +*/ +#define HASH2_CALC hv = GetUi16(cur); + +// (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255] + +/* + HASH3_CALC: + if (cur[0]) and (h2) match, then cur[1] also match + if (cur[0]) and (hv) match, then cur[1] and cur[2] also match +*/ +#define HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + +#define HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + hv = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hashMask; } + +#define HASH5_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + temp ^= (p->crc[cur[3]] << kLzHash_CrcShift_1); \ + /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */ \ + hv = (temp ^ (p->crc[cur[4]] << kLzHash_CrcShift_2)) & p->hashMask; } + +#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; + static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc) { - if (!p->directInput) + // if (!p->directInput) { - ISzAlloc_Free(alloc, p->bufferBase); - p->bufferBase = NULL; + ISzAlloc_Free(alloc, p->bufBase); + p->bufBase = NULL; } } -/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ -static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc) +static int LzInWindow_Create2(CMatchFinder *p, UInt32 blockSize, ISzAllocPtr alloc) { - UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; - if (p->directInput) - { - p->blockSize = blockSize; - return 1; - } - if (!p->bufferBase || p->blockSize != blockSize) + if (blockSize == 0) + return 0; + if (!p->bufBase || p->blockSize != blockSize) { + // size_t blockSizeT; LzInWindow_Free(p, alloc); p->blockSize = blockSize; - p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize); + // blockSizeT = blockSize; + + // printf("\nblockSize = 0x%x\n", blockSize); + /* + #if defined _WIN64 + // we can allocate 4GiB, but still use UInt32 for (p->blockSize) + // we use UInt32 type for (p->blockSize), because + // we don't want to wrap over 4 GiB, + // when we use (p->streamPos - p->pos) that is UInt32. + if (blockSize >= (UInt32)0 - (UInt32)kBlockSizeAlign) + { + blockSizeT = ((size_t)1 << 32); + printf("\nchanged to blockSizeT = 4GiB\n"); + } + #endif + */ + + p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, blockSize); + // printf("\nbufferBase = %p\n", p->bufBase); + // return 0; // for debug } - return (p->bufferBase != NULL); + return (p->bufBase != NULL); } -Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +static const Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } -UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } +static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return GET_AVAIL_BYTES(p); } -void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) -{ - p->posLimit -= subValue; - p->pos -= subValue; - p->streamPos -= subValue; -} +Z7_NO_INLINE static void MatchFinder_ReadBlock(CMatchFinder *p) { if (p->streamEndWasReached || p->result != SZ_OK) return; - /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */ + /* We use (p->streamPos - p->pos) value. + (p->streamPos < p->pos) is allowed. */ if (p->directInput) { - UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos); + UInt32 curSize = 0xFFFFFFFF - GET_AVAIL_BYTES(p); if (curSize > p->directInputRem) curSize = (UInt32)p->directInputRem; - p->directInputRem -= curSize; p->streamPos += curSize; + p->directInputRem -= curSize; if (p->directInputRem == 0) p->streamEndWasReached = 1; return; @@ -76,12 +136,31 @@ static void MatchFinder_ReadBlock(CMatchFinder *p) for (;;) { - Byte *dest = p->buffer + (p->streamPos - p->pos); - size_t size = (p->bufferBase + p->blockSize - dest); + const Byte *dest = p->buffer + GET_AVAIL_BYTES(p); + size_t size = (size_t)(p->bufBase + p->blockSize - dest); if (size == 0) + { + /* we call ReadBlock() after NeedMove() and MoveBlock(). + NeedMove() and MoveBlock() povide more than (keepSizeAfter) + to the end of (blockSize). + So we don't execute this branch in normal code flow. + We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock(). + */ + // p->result = SZ_ERROR_FAIL; // we can show error here return; + } + + // #define kRead 3 + // if (size > kRead) size = kRead; // for debug - p->result = ISeqInStream_Read(p->stream, dest, &size); + /* + // we need cast (Byte *)dest. + #ifdef __clang__ + #pragma GCC diagnostic ignored "-Wcast-qual" + #endif + */ + p->result = ISeqInStream_Read(p->stream, + p->bufBase + (dest - p->bufBase), &size); if (p->result != SZ_OK) return; if (size == 0) @@ -90,47 +169,60 @@ static void MatchFinder_ReadBlock(CMatchFinder *p) return; } p->streamPos += (UInt32)size; - if (p->streamPos - p->pos > p->keepSizeAfter) + if (GET_AVAIL_BYTES(p) > p->keepSizeAfter) return; + /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function + (GET_AVAIL_BYTES(p) >= p->keepSizeAfter) - minimal required size */ } + + // on exit: (p->result != SZ_OK || p->streamEndWasReached || GET_AVAIL_BYTES(p) > p->keepSizeAfter) } + + +Z7_NO_INLINE void MatchFinder_MoveBlock(CMatchFinder *p) { - memmove(p->bufferBase, - p->buffer - p->keepSizeBefore, - (size_t)(p->streamPos - p->pos) + p->keepSizeBefore); - p->buffer = p->bufferBase + p->keepSizeBefore; + const size_t offset = (size_t)(p->buffer - p->bufBase) - p->keepSizeBefore; + const size_t keepBefore = (offset & (kBlockMoveAlign - 1)) + p->keepSizeBefore; + p->buffer = p->bufBase + keepBefore; + memmove(p->bufBase, + p->bufBase + (offset & ~((size_t)kBlockMoveAlign - 1)), + keepBefore + (size_t)GET_AVAIL_BYTES(p)); } +/* We call MoveBlock() before ReadBlock(). + So MoveBlock() can be wasteful operation, if the whole input data + can fit in current block even without calling MoveBlock(). + in important case where (dataSize <= historySize) + condition (p->blockSize > dataSize + p->keepSizeAfter) is met + So there is no MoveBlock() in that case case. +*/ + int MatchFinder_NeedMove(CMatchFinder *p) { if (p->directInput) return 0; - /* if (p->streamEndWasReached) return 0; */ - return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); + if (p->streamEndWasReached || p->result != SZ_OK) + return 0; + return ((size_t)(p->bufBase + p->blockSize - p->buffer) <= p->keepSizeAfter); } void MatchFinder_ReadIfRequired(CMatchFinder *p) { - if (p->streamEndWasReached) - return; - if (p->keepSizeAfter >= p->streamPos - p->pos) + if (p->keepSizeAfter >= GET_AVAIL_BYTES(p)) MatchFinder_ReadBlock(p); } -static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) -{ - if (MatchFinder_NeedMove(p)) - MatchFinder_MoveBlock(p); - MatchFinder_ReadBlock(p); -} + static void MatchFinder_SetDefaultSettings(CMatchFinder *p) { p->cutValue = 32; p->btMode = 1; p->numHashBytes = 4; + p->numHashBytes_Min = 2; + p->numHashOutBits = 0; p->bigHash = 0; } @@ -139,8 +231,10 @@ static void MatchFinder_SetDefaultSettings(CMatchFinder *p) void MatchFinder_Construct(CMatchFinder *p) { unsigned i; - p->bufferBase = NULL; + p->buffer = NULL; + p->bufBase = NULL; p->directInput = 0; + p->stream = NULL; p->hash = NULL; p->expectedDataSize = (UInt64)(Int64)-1; MatchFinder_SetDefaultSettings(p); @@ -155,6 +249,8 @@ void MatchFinder_Construct(CMatchFinder *p) } } +#undef kCrcPoly + static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc) { ISzAlloc_Free(alloc, p->hash); @@ -169,87 +265,213 @@ void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc) static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc) { - size_t sizeInBytes = (size_t)num * sizeof(CLzRef); + const size_t sizeInBytes = (size_t)num * sizeof(CLzRef); if (sizeInBytes / sizeof(CLzRef) != num) return NULL; return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes); } -int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, - UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, - ISzAllocPtr alloc) +#if (kBlockSizeReserveMin < kBlockSizeAlign * 2) + #error Stop_Compiling_Bad_Reserve +#endif + + + +static UInt32 GetBlockSize(CMatchFinder *p, UInt32 historySize) { - UInt32 sizeReserv; - + UInt32 blockSize = (p->keepSizeBefore + p->keepSizeAfter); + /* if (historySize > kMaxHistorySize) - { - MatchFinder_Free(p, alloc); return 0; - } + */ + // printf("\nhistorySize == 0x%x\n", historySize); - sizeReserv = historySize >> 1; - if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3; - else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2; + if (p->keepSizeBefore < historySize || blockSize < p->keepSizeBefore) // if 32-bit overflow + return 0; - sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); + { + const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)kBlockSizeAlign; + const UInt32 rem = kBlockSizeMax - blockSize; + const UInt32 reserve = (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)) + + (1 << 12) + kBlockMoveAlign + kBlockSizeAlign; // do not overflow 32-bit here + if (blockSize >= kBlockSizeMax + || rem < kBlockSizeReserveMin) // we reject settings that will be slow + return 0; + if (reserve >= rem) + blockSize = kBlockSizeMax; + else + { + blockSize += reserve; + blockSize &= ~(UInt32)(kBlockSizeAlign - 1); + } + } + // printf("\n LzFind_blockSize = %x\n", blockSize); + // printf("\n LzFind_blockSize = %d\n", blockSize >> 20); + return blockSize; +} + + +// input is historySize +static UInt32 MatchFinder_GetHashMask2(CMatchFinder *p, UInt32 hs) +{ + if (p->numHashBytes == 2) + return (1 << 16) - 1; + if (hs != 0) + hs--; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + // we propagated 16 bits in (hs). Low 16 bits must be set later + if (hs >= (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ + } + // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) + hs |= (1 << 16) - 1; /* don't change it! */ + // bt5: we adjust the size with recommended minimum size + if (p->numHashBytes >= 5) + hs |= (256 << kLzHash_CrcShift_2) - 1; + return hs; +} + +// input is historySize +static UInt32 MatchFinder_GetHashMask(CMatchFinder *p, UInt32 hs) +{ + if (p->numHashBytes == 2) + return (1 << 16) - 1; + if (hs != 0) + hs--; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + // we propagated 16 bits in (hs). Low 16 bits must be set later + hs >>= 1; + if (hs >= (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + else + hs >>= 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ + } + // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) + hs |= (1 << 16) - 1; /* don't change it! */ + // bt5: we adjust the size with recommended minimum size + if (p->numHashBytes >= 5) + hs |= (256 << kLzHash_CrcShift_2) - 1; + return hs; +} + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAllocPtr alloc) +{ + /* we need one additional byte in (p->keepSizeBefore), + since we use MoveBlock() after (p->pos++) and before dictionary using */ + // keepAddBufferBefore = (UInt32)0xFFFFFFFF - (1 << 22); // for debug p->keepSizeBefore = historySize + keepAddBufferBefore + 1; - p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; - - /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ - - if (LzInWindow_Create(p, sizeReserv, alloc)) + + keepAddBufferAfter += matchMaxLen; + /* we need (p->keepSizeAfter >= p->numHashBytes) */ + if (keepAddBufferAfter < p->numHashBytes) + keepAddBufferAfter = p->numHashBytes; + // keepAddBufferAfter -= 2; // for debug + p->keepSizeAfter = keepAddBufferAfter; + + if (p->directInput) + p->blockSize = 0; + if (p->directInput || LzInWindow_Create2(p, GetBlockSize(p, historySize), alloc)) { - UInt32 newCyclicBufferSize = historySize + 1; - UInt32 hs; - p->matchMaxLen = matchMaxLen; + size_t hashSizeSum; { - p->fixedHashSize = 0; - if (p->numHashBytes == 2) - hs = (1 << 16) - 1; + UInt32 hs; + UInt32 hsCur; + + if (p->numHashOutBits != 0) + { + unsigned numBits = p->numHashOutBits; + const unsigned nbMax = + (p->numHashBytes == 2 ? 16 : + (p->numHashBytes == 3 ? 24 : 32)); + if (numBits > nbMax) + numBits = nbMax; + if (numBits >= 32) + hs = (UInt32)0 - 1; + else + hs = ((UInt32)1 << numBits) - 1; + // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) + hs |= (1 << 16) - 1; /* don't change it! */ + if (p->numHashBytes >= 5) + hs |= (256 << kLzHash_CrcShift_2) - 1; + { + const UInt32 hs2 = MatchFinder_GetHashMask2(p, historySize); + if (hs > hs2) + hs = hs2; + } + hsCur = hs; + if (p->expectedDataSize < historySize) + { + const UInt32 hs2 = MatchFinder_GetHashMask2(p, (UInt32)p->expectedDataSize); + if (hsCur > hs2) + hsCur = hs2; + } + } else { - hs = historySize; - if (hs > p->expectedDataSize) - hs = (UInt32)p->expectedDataSize; - if (hs != 0) - hs--; - hs |= (hs >> 1); - hs |= (hs >> 2); - hs |= (hs >> 4); - hs |= (hs >> 8); - hs >>= 1; - hs |= 0xFFFF; /* don't change it! It's required for Deflate */ - if (hs > (1 << 24)) + hs = MatchFinder_GetHashMask(p, historySize); + hsCur = hs; + if (p->expectedDataSize < historySize) { - if (p->numHashBytes == 3) - hs = (1 << 24) - 1; - else - hs >>= 1; - /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ + hsCur = MatchFinder_GetHashMask(p, (UInt32)p->expectedDataSize); + if (hsCur > hs) // is it possible? + hsCur = hs; } } - p->hashMask = hs; - hs++; - if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; - if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; - if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; - hs += p->fixedHashSize; + + p->hashMask = hsCur; + + hashSizeSum = hs; + hashSizeSum++; + if (hashSizeSum < hs) + return 0; + { + UInt32 fixedHashSize = 0; + if (p->numHashBytes > 2 && p->numHashBytes_Min <= 2) fixedHashSize += kHash2Size; + if (p->numHashBytes > 3 && p->numHashBytes_Min <= 3) fixedHashSize += kHash3Size; + // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size; + hashSizeSum += fixedHashSize; + p->fixedHashSize = fixedHashSize; + } } + p->matchMaxLen = matchMaxLen; + { size_t newSize; size_t numSons; + const UInt32 newCyclicBufferSize = historySize + 1; // do not change it p->historySize = historySize; - p->hashSizeSum = hs; - p->cyclicBufferSize = newCyclicBufferSize; + p->cyclicBufferSize = newCyclicBufferSize; // it must be = (historySize + 1) numSons = newCyclicBufferSize; if (p->btMode) numSons <<= 1; - newSize = hs + numSons; + newSize = hashSizeSum + numSons; + + if (numSons < newCyclicBufferSize || newSize < numSons) + return 0; + + // aligned size is not required here, but it can be better for some loops + #define NUM_REFS_ALIGN_MASK 0xF + newSize = (newSize + NUM_REFS_ALIGN_MASK) & ~(size_t)NUM_REFS_ALIGN_MASK; - if (p->hash && p->numRefs == newSize) + // 22.02: we don't reallocate buffer, if old size is enough + if (p->hash && p->numRefs >= newSize) return 1; MatchFinder_FreeThisClassMemory(p, alloc); @@ -258,7 +480,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, if (p->hash) { - p->son = p->hash + p->hashSizeSum; + p->son = p->hash + hashSizeSum; return 1; } } @@ -268,33 +490,43 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, return 0; } + static void MatchFinder_SetLimits(CMatchFinder *p) { - UInt32 limit = kMaxValForNormalize - p->pos; - UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; - - if (limit2 < limit) - limit = limit2; - limit2 = p->streamPos - p->pos; + UInt32 k; + UInt32 n = kMaxValForNormalize - p->pos; + if (n == 0) + n = (UInt32)(Int32)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0) - if (limit2 <= p->keepSizeAfter) + k = p->cyclicBufferSize - p->cyclicBufferPos; + if (k < n) + n = k; + + k = GET_AVAIL_BYTES(p); { - if (limit2 > 0) - limit2 = 1; + const UInt32 ksa = p->keepSizeAfter; + UInt32 mm = p->matchMaxLen; + if (k > ksa) + k -= ksa; // we must limit exactly to keepSizeAfter for ReadBlock + else if (k >= mm) + { + // the limitation for (p->lenLimit) update + k -= mm; // optimization : to reduce the number of checks + k++; + // k = 1; // non-optimized version : for debug + } + else + { + mm = k; + if (k != 0) + k = 1; + } + p->lenLimit = mm; } - else - limit2 -= p->keepSizeAfter; - - if (limit2 < limit) - limit = limit2; + if (k < n) + n = k; - { - UInt32 lenLimit = p->streamPos - p->pos; - if (lenLimit > p->matchMaxLen) - lenLimit = p->matchMaxLen; - p->lenLimit = lenLimit; - } - p->posLimit = p->pos + limit; + p->posLimit = p->pos + n; } @@ -302,7 +534,7 @@ void MatchFinder_Init_LowHash(CMatchFinder *p) { size_t i; CLzRef *items = p->hash; - size_t numItems = p->fixedHashSize; + const size_t numItems = p->fixedHashSize; for (i = 0; i < numItems; i++) items[i] = kEmptyHashValue; } @@ -312,72 +544,324 @@ void MatchFinder_Init_HighHash(CMatchFinder *p) { size_t i; CLzRef *items = p->hash + p->fixedHashSize; - size_t numItems = (size_t)p->hashMask + 1; + const size_t numItems = (size_t)p->hashMask + 1; for (i = 0; i < numItems; i++) items[i] = kEmptyHashValue; } -void MatchFinder_Init_3(CMatchFinder *p, int readData) +void MatchFinder_Init_4(CMatchFinder *p) { - p->cyclicBufferPos = 0; - p->buffer = p->bufferBase; - p->pos = - p->streamPos = p->cyclicBufferSize; + if (!p->directInput) + p->buffer = p->bufBase; + { + /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker. + the code in CMatchFinderMt expects (pos = 1) */ + p->pos = + p->streamPos = + 1; // it's smallest optimal value. do not change it + // 0; // for debug + } p->result = SZ_OK; p->streamEndWasReached = 0; - - if (readData) - MatchFinder_ReadBlock(p); - - MatchFinder_SetLimits(p); } +// (CYC_TO_POS_OFFSET == 0) is expected by some optimized code +#define CYC_TO_POS_OFFSET 0 +// #define CYC_TO_POS_OFFSET 1 // for debug + void MatchFinder_Init(CMatchFinder *p) { MatchFinder_Init_HighHash(p); MatchFinder_Init_LowHash(p); - MatchFinder_Init_3(p, True); + MatchFinder_Init_4(p); + // if (readData) + MatchFinder_ReadBlock(p); + + /* if we init (cyclicBufferPos = pos), then we can use one variable + instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */ + p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); // init with relation to (pos) + // p->cyclicBufferPos = 0; // smallest value + // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses. + MatchFinder_SetLimits(p); } - -static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) + + +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(__clang__) && (__clang_major__ >= 4) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701) + // || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) + + #define USE_LZFIND_SATUR_SUB_128 + #define USE_LZFIND_SATUR_SUB_256 + #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("sse4.1"))) + #define LZFIND_ATTRIB_AVX2 __attribute__((__target__("avx2"))) + #elif defined(_MSC_VER) + #if (_MSC_VER >= 1600) + #define USE_LZFIND_SATUR_SUB_128 + #endif + #if (_MSC_VER >= 1900) + #define USE_LZFIND_SATUR_SUB_256 + #endif + #endif + +// #elif defined(MY_CPU_ARM_OR_ARM64) +#elif defined(MY_CPU_ARM64) + + #if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 8) + #define USE_LZFIND_SATUR_SUB_128 + #ifdef MY_CPU_ARM64 + // #define LZFIND_ATTRIB_SSE41 __attribute__((__target__(""))) + #else + // #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) + #endif + + #elif defined(_MSC_VER) + #if (_MSC_VER >= 1910) + #define USE_LZFIND_SATUR_SUB_128 + #endif + #endif + + #if defined(_MSC_VER) && defined(MY_CPU_ARM64) + #include + #else + #include + #endif + +#endif + + +#ifdef USE_LZFIND_SATUR_SUB_128 + +// #define Z7_SHOW_HW_STATUS + +#ifdef Z7_SHOW_HW_STATUS +#include +#define PRF(x) x +PRF(;) +#else +#define PRF(x) +#endif + + +#ifdef MY_CPU_ARM_OR_ARM64 + +#ifdef MY_CPU_ARM64 +// #define FORCE_LZFIND_SATUR_SUB_128 +#endif +typedef uint32x4_t LzFind_v128; +#define SASUB_128_V(v, s) \ + vsubq_u32(vmaxq_u32(v, s), s) + +#else // MY_CPU_ARM_OR_ARM64 + +#include // sse4.1 + +typedef __m128i LzFind_v128; +// SSE 4.1 +#define SASUB_128_V(v, s) \ + _mm_sub_epi32(_mm_max_epu32(v, s), s) + +#endif // MY_CPU_ARM_OR_ARM64 + + +#define SASUB_128(i) \ + *( LzFind_v128 *)( void *)(items + (i) * 4) = SASUB_128_V( \ + *(const LzFind_v128 *)(const void *)(items + (i) * 4), sub2); + + +Z7_NO_INLINE +static +#ifdef LZFIND_ATTRIB_SSE41 +LZFIND_ATTRIB_SSE41 +#endif +void +Z7_FASTCALL +LzFind_SaturSub_128(UInt32 subValue, CLzRef *items, const CLzRef *lim) { - return (p->pos - p->historySize - 1) & kNormalizeMask; + const LzFind_v128 sub2 = + #ifdef MY_CPU_ARM_OR_ARM64 + vdupq_n_u32(subValue); + #else + _mm_set_epi32((Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue); + #endif + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SASUB_128(0) SASUB_128(1) items += 2 * 4; + SASUB_128(0) SASUB_128(1) items += 2 * 4; + } + while (items != lim); } -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) + + +#ifdef USE_LZFIND_SATUR_SUB_256 + +#include // avx +/* +clang :immintrin.h uses +#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \ + defined(__AVX2__) +#include +#endif +so we need for clang-cl */ + +#if defined(__clang__) +#include +#include +#endif + +// AVX2: +#define SASUB_256(i) \ + *( __m256i *)( void *)(items + (i) * 8) = \ + _mm256_sub_epi32(_mm256_max_epu32( \ + *(const __m256i *)(const void *)(items + (i) * 8), sub2), sub2); + +Z7_NO_INLINE +static +#ifdef LZFIND_ATTRIB_AVX2 +LZFIND_ATTRIB_AVX2 +#endif +void +Z7_FASTCALL +LzFind_SaturSub_256(UInt32 subValue, CLzRef *items, const CLzRef *lim) { - size_t i; - for (i = 0; i < numItems; i++) + const __m256i sub2 = _mm256_set_epi32( + (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue, + (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue); + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do { - UInt32 value = items[i]; - if (value <= subValue) - value = kEmptyHashValue; - else - value -= subValue; - items[i] = value; + SASUB_256(0) SASUB_256(1) items += 2 * 8; + SASUB_256(0) SASUB_256(1) items += 2 * 8; } + while (items != lim); } +#endif // USE_LZFIND_SATUR_SUB_256 + +#ifndef FORCE_LZFIND_SATUR_SUB_128 +typedef void (Z7_FASTCALL *LZFIND_SATUR_SUB_CODE_FUNC)( + UInt32 subValue, CLzRef *items, const CLzRef *lim); +static LZFIND_SATUR_SUB_CODE_FUNC g_LzFind_SaturSub; +#endif // FORCE_LZFIND_SATUR_SUB_128 + +#endif // USE_LZFIND_SATUR_SUB_128 + + +// kEmptyHashValue must be zero +// #define SASUB_32(i) { UInt32 v = items[i]; UInt32 m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m; } +#define SASUB_32(i) { UInt32 v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue; } + +#ifdef FORCE_LZFIND_SATUR_SUB_128 -static void MatchFinder_Normalize(CMatchFinder *p) +#define DEFAULT_SaturSub LzFind_SaturSub_128 + +#else + +#define DEFAULT_SaturSub LzFind_SaturSub_32 + +Z7_NO_INLINE +static +void +Z7_FASTCALL +LzFind_SaturSub_32(UInt32 subValue, CLzRef *items, const CLzRef *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SASUB_32(0) SASUB_32(1) items += 2; + SASUB_32(0) SASUB_32(1) items += 2; + SASUB_32(0) SASUB_32(1) items += 2; + SASUB_32(0) SASUB_32(1) items += 2; + } + while (items != lim); +} + +#endif + + +Z7_NO_INLINE +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) { - UInt32 subValue = MatchFinder_GetSubValue(p); - MatchFinder_Normalize3(subValue, p->hash, p->numRefs); - MatchFinder_ReduceOffsets(p, subValue); + #define LZFIND_NORM_ALIGN_BLOCK_SIZE (1 << 7) + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (LZFIND_NORM_ALIGN_BLOCK_SIZE - 1)) != 0; numItems--) + { + SASUB_32(0) + items++; + } + { + const size_t k_Align_Mask = (LZFIND_NORM_ALIGN_BLOCK_SIZE / 4 - 1); + CLzRef *lim = items + (numItems & ~(size_t)k_Align_Mask); + numItems &= k_Align_Mask; + if (items != lim) + { + #if defined(USE_LZFIND_SATUR_SUB_128) && !defined(FORCE_LZFIND_SATUR_SUB_128) + if (g_LzFind_SaturSub) + g_LzFind_SaturSub(subValue, items, lim); + else + #endif + DEFAULT_SaturSub(subValue, items, lim); + } + items = lim; + } + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0; numItems--) + { + SASUB_32(0) + items++; + } } -MY_NO_INLINE + +// call MatchFinder_CheckLimits() only after (p->pos++) update + +Z7_NO_INLINE static void MatchFinder_CheckLimits(CMatchFinder *p) { + if (// !p->streamEndWasReached && p->result == SZ_OK && + p->keepSizeAfter == GET_AVAIL_BYTES(p)) + { + // we try to read only in exact state (p->keepSizeAfter == GET_AVAIL_BYTES(p)) + if (MatchFinder_NeedMove(p)) + MatchFinder_MoveBlock(p); + MatchFinder_ReadBlock(p); + } + if (p->pos == kMaxValForNormalize) - MatchFinder_Normalize(p); - if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) - MatchFinder_CheckAndMoveAndRead(p); + if (GET_AVAIL_BYTES(p) >= p->numHashBytes) // optional optimization for last bytes of data. + /* + if we disable normalization for last bytes of data, and + if (data_size == 4 GiB), we don't call wastfull normalization, + but (pos) will be wrapped over Zero (0) in that case. + And we cannot resume later to normal operation + */ + { + // MatchFinder_Normalize(p); + /* after normalization we need (p->pos >= p->historySize + 1); */ + /* we can reduce subValue to aligned value, if want to keep alignment + of (p->pos) and (p->buffer) for speculated accesses. */ + const UInt32 subValue = (p->pos - p->historySize - 1) /* & ~(UInt32)(kNormalizeAlign - 1) */; + // const UInt32 subValue = (1 << 15); // for debug + // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue); + MatchFinder_REDUCE_OFFSETS(p, subValue) + MatchFinder_Normalize3(subValue, p->hash, (size_t)p->hashMask + 1 + p->fixedHashSize); + { + size_t numSonRefs = p->cyclicBufferSize; + if (p->btMode) + numSonRefs <<= 1; + MatchFinder_Normalize3(subValue, p->son, numSonRefs); + } + } + if (p->cyclicBufferPos == p->cyclicBufferSize) p->cyclicBufferPos = 0; + MatchFinder_SetLimits(p); } @@ -385,10 +869,10 @@ static void MatchFinder_CheckLimits(CMatchFinder *p) /* (lenLimit > maxLen) */ -MY_FORCE_INLINE -static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, - UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, - UInt32 *distances, unsigned maxLen) +Z7_FORCE_INLINE +static UInt32 * Hc_GetMatchesSpec(size_t lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *d, unsigned maxLen) { /* son[_cyclicBufferPos] = curMatch; @@ -396,7 +880,7 @@ static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) - return distances; + return d; { const Byte *pb = cur - delta; curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; @@ -409,10 +893,10 @@ static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos if (maxLen < len) { maxLen = len; - *distances++ = len; - *distances++ = delta - 1; + *d++ = len; + *d++ = delta - 1; if (len == lenLimit) - return distances; + return d; } } } @@ -421,35 +905,41 @@ static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos const Byte *lim = cur + lenLimit; son[_cyclicBufferPos] = curMatch; + do { - UInt32 delta = pos - curMatch; + UInt32 delta; + + if (curMatch == 0) + break; + // if (curMatch2 >= curMatch) return NULL; + delta = pos - curMatch; if (delta >= _cyclicBufferSize) break; { ptrdiff_t diff; curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; - diff = (ptrdiff_t)0 - delta; - if (cur[maxLen] == cur[maxLen + diff]) + diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff]) { const Byte *c = cur; while (*c == c[diff]) { if (++c == lim) { - distances[0] = (UInt32)(lim - cur); - distances[1] = delta - 1; - return distances + 2; + d[0] = (UInt32)(lim - cur); + d[1] = delta - 1; + return d + 2; } } { - unsigned len = (unsigned)(c - cur); + const unsigned len = (unsigned)(c - cur); if (maxLen < len) { maxLen = len; - distances[0] = (UInt32)len; - distances[1] = delta - 1; - distances += 2; + d[0] = (UInt32)len; + d[1] = delta - 1; + d += 2; } } } @@ -457,31 +947,36 @@ static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos } while (--cutValue); - return distances; + return d; } -MY_FORCE_INLINE +Z7_FORCE_INLINE UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, - UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, - UInt32 *distances, UInt32 maxLen) + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *d, UInt32 maxLen) { CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); unsigned len0 = 0, len1 = 0; - for (;;) + + UInt32 cmCheck; + + // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } + + cmCheck = (UInt32)(pos - _cyclicBufferSize); + if ((UInt32)pos <= _cyclicBufferSize) + cmCheck = 0; + + if (cmCheck < curMatch) + do { - UInt32 delta = pos - curMatch; - if (cutValue-- == 0 || delta >= _cyclicBufferSize) - { - *ptr0 = *ptr1 = kEmptyHashValue; - return distances; - } + const UInt32 delta = pos - curMatch; { CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; unsigned len = (len0 < len1 ? len0 : len1); - UInt32 pair0 = pair[0]; + const UInt32 pair0 = pair[0]; if (pb[len] == cur[len]) { if (++len != lenLimit && pb[len] == cur[len]) @@ -491,48 +986,60 @@ UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byt if (maxLen < len) { maxLen = (UInt32)len; - *distances++ = (UInt32)len; - *distances++ = delta - 1; + *d++ = (UInt32)len; + *d++ = delta - 1; if (len == lenLimit) { *ptr1 = pair0; *ptr0 = pair[1]; - return distances; + return d; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; + // const UInt32 curMatch2 = pair[1]; + // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } + // curMatch = curMatch2; + curMatch = pair[1]; ptr1 = pair + 1; - curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; + curMatch = pair[0]; ptr0 = pair; - curMatch = *ptr0; len0 = len; } } } + while(--cutValue && cmCheck < curMatch); + + *ptr0 = *ptr1 = kEmptyHashValue; + return d; } + static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, - UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) { CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); unsigned len0 = 0, len1 = 0; - for (;;) + + UInt32 cmCheck; + + cmCheck = (UInt32)(pos - _cyclicBufferSize); + if ((UInt32)pos <= _cyclicBufferSize) + cmCheck = 0; + + if (// curMatch >= pos || // failure + cmCheck < curMatch) + do { - UInt32 delta = pos - curMatch; - if (cutValue-- == 0 || delta >= _cyclicBufferSize) - { - *ptr0 = *ptr1 = kEmptyHashValue; - return; - } + const UInt32 delta = pos - curMatch; { CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; @@ -554,84 +1061,112 @@ static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const if (pb[len] < cur[len]) { *ptr1 = curMatch; + curMatch = pair[1]; ptr1 = pair + 1; - curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; + curMatch = pair[0]; ptr0 = pair; - curMatch = *ptr0; len0 = len; } } } + while(--cutValue && cmCheck < curMatch); + + *ptr0 = *ptr1 = kEmptyHashValue; + return; } + #define MOVE_POS \ ++p->cyclicBufferPos; \ p->buffer++; \ - if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + { const UInt32 pos1 = p->pos + 1; p->pos = pos1; if (pos1 == p->posLimit) MatchFinder_CheckLimits(p); } -#define MOVE_POS_RET MOVE_POS return (UInt32)offset; +#define MOVE_POS_RET MOVE_POS return distances; -static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } +Z7_NO_INLINE +static void MatchFinder_MovePos(CMatchFinder *p) +{ + /* we go here at the end of stream data, when (avail < num_hash_bytes) + We don't update sons[cyclicBufferPos << btMode]. + So (sons) record will contain junk. And we cannot resume match searching + to normal operation, even if we will provide more input data in buffer. + p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue + if (p->btMode) + p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue + */ + MOVE_POS +} #define GET_MATCHES_HEADER2(minLen, ret_op) \ unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \ lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ cur = p->buffer; -#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) -#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) +#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return distances) +#define SKIP_HEADER(minLen) do { GET_MATCHES_HEADER2(minLen, continue) + +#define MF_PARAMS(p) lenLimit, curMatch, p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue + +#define SKIP_FOOTER SkipMatchesSpec(MF_PARAMS(p)); MOVE_POS } while (--num); + +#define GET_MATCHES_FOOTER_BASE(_maxLen_, func) \ + distances = func(MF_PARAMS(p), \ + distances, (UInt32)_maxLen_); MOVE_POS_RET + +#define GET_MATCHES_FOOTER_BT(_maxLen_) \ + GET_MATCHES_FOOTER_BASE(_maxLen_, GetMatchesSpec1) -#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue +#define GET_MATCHES_FOOTER_HC(_maxLen_) \ + GET_MATCHES_FOOTER_BASE(_maxLen_, Hc_GetMatchesSpec) -#define GET_MATCHES_FOOTER(offset, maxLen) \ - offset = (unsigned)(GetMatchesSpec1((UInt32)lenLimit, curMatch, MF_PARAMS(p), \ - distances + offset, (UInt32)maxLen) - distances); MOVE_POS_RET; -#define SKIP_FOOTER \ - SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; #define UPDATE_maxLen { \ - ptrdiff_t diff = (ptrdiff_t)0 - d2; \ + const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)d2; \ const Byte *c = cur + maxLen; \ const Byte *lim = cur + lenLimit; \ for (; c != lim; c++) if (*(c + diff) != *c) break; \ maxLen = (unsigned)(c - cur); } -static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +static UInt32* Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - unsigned offset; GET_MATCHES_HEADER(2) - HASH2_CALC; + HASH2_CALC curMatch = p->hash[hv]; p->hash[hv] = p->pos; - offset = 0; - GET_MATCHES_FOOTER(offset, 1) + GET_MATCHES_FOOTER_BT(1) } -UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - unsigned offset; GET_MATCHES_HEADER(3) - HASH_ZIP_CALC; + HASH_ZIP_CALC curMatch = p->hash[hv]; p->hash[hv] = p->pos; - offset = 0; - GET_MATCHES_FOOTER(offset, 2) + GET_MATCHES_FOOTER_BT(2) } -static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + +#define SET_mmm \ + mmm = p->cyclicBufferSize; \ + if (pos < mmm) \ + mmm = pos; + + +static UInt32* Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { + UInt32 mmm; UInt32 h2, d2, pos; - unsigned maxLen, offset; + unsigned maxLen; UInt32 *hash; GET_MATCHES_HEADER(3) - HASH3_CALC; + HASH3_CALC hash = p->hash; pos = p->pos; @@ -643,167 +1178,176 @@ static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) hash[h2] = pos; (hash + kFix3HashSize)[hv] = pos; + SET_mmm + maxLen = 2; - offset = 0; - if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + if (d2 < mmm && *(cur - d2) == *cur) { UPDATE_maxLen distances[0] = (UInt32)maxLen; distances[1] = d2 - 1; - offset = 2; + distances += 2; if (maxLen == lenLimit) { - SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); - MOVE_POS_RET; + SkipMatchesSpec(MF_PARAMS(p)); + MOVE_POS_RET } } - GET_MATCHES_FOOTER(offset, maxLen) + GET_MATCHES_FOOTER_BT(maxLen) } -static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + +static UInt32* Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { + UInt32 mmm; UInt32 h2, h3, d2, d3, pos; - unsigned maxLen, offset; + unsigned maxLen; UInt32 *hash; GET_MATCHES_HEADER(4) - HASH4_CALC; + HASH4_CALC hash = p->hash; pos = p->pos; d2 = pos - hash [h2]; d3 = pos - (hash + kFix3HashSize)[h3]; - curMatch = (hash + kFix4HashSize)[hv]; hash [h2] = pos; (hash + kFix3HashSize)[h3] = pos; (hash + kFix4HashSize)[hv] = pos; - maxLen = 0; - offset = 0; - - if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) - { - maxLen = 2; - distances[0] = 2; - distances[1] = d2 - 1; - offset = 2; - } + SET_mmm + + maxLen = 3; - if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + for (;;) { - maxLen = 3; - distances[(size_t)offset + 1] = d3 - 1; - offset += 2; - d2 = d3; - } + if (d2 < mmm && *(cur - d2) == *cur) + { + distances[0] = 2; + distances[1] = d2 - 1; + distances += 2; + if (*(cur - d2 + 2) == cur[2]) + { + // distances[-2] = 3; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + d2 = d3; + distances[1] = d3 - 1; + distances += 2; + } + else + break; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + d2 = d3; + distances[1] = d3 - 1; + distances += 2; + } + else + break; - if (offset != 0) - { UPDATE_maxLen - distances[(size_t)offset - 2] = (UInt32)maxLen; + distances[-2] = (UInt32)maxLen; if (maxLen == lenLimit) { - SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); - MOVE_POS_RET; + SkipMatchesSpec(MF_PARAMS(p)); + MOVE_POS_RET } + break; } - if (maxLen < 3) - maxLen = 3; - - GET_MATCHES_FOOTER(offset, maxLen) + GET_MATCHES_FOOTER_BT(maxLen) } -/* -static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + +static UInt32* Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos; + UInt32 mmm; + UInt32 h2, h3, d2, d3, maxLen, pos; UInt32 *hash; GET_MATCHES_HEADER(5) - HASH5_CALC; + HASH5_CALC hash = p->hash; pos = p->pos; d2 = pos - hash [h2]; d3 = pos - (hash + kFix3HashSize)[h3]; - d4 = pos - (hash + kFix4HashSize)[h4]; + // d4 = pos - (hash + kFix4HashSize)[h4]; curMatch = (hash + kFix5HashSize)[hv]; hash [h2] = pos; (hash + kFix3HashSize)[h3] = pos; - (hash + kFix4HashSize)[h4] = pos; + // (hash + kFix4HashSize)[h4] = pos; (hash + kFix5HashSize)[hv] = pos; - maxLen = 0; - offset = 0; + SET_mmm + + maxLen = 4; - if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + for (;;) { - distances[0] = maxLen = 2; - distances[1] = d2 - 1; - offset = 2; - if (*(cur - d2 + 2) == cur[2]) - distances[0] = maxLen = 3; - else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + if (d2 < mmm && *(cur - d2) == *cur) + { + distances[0] = 2; + distances[1] = d2 - 1; + distances += 2; + if (*(cur - d2 + 2) == cur[2]) + { + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + distances[1] = d3 - 1; + distances += 2; + d2 = d3; + } + else + break; + } + else if (d3 < mmm && *(cur - d3) == *cur) { - distances[2] = maxLen = 3; - distances[3] = d3 - 1; - offset = 4; + distances[1] = d3 - 1; + distances += 2; d2 = d3; } - } - else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) - { - distances[0] = maxLen = 3; - distances[1] = d3 - 1; - offset = 2; - d2 = d3; - } - - if (d2 != d4 && d4 < p->cyclicBufferSize - && *(cur - d4) == *cur - && *(cur - d4 + 3) == *(cur + 3)) - { - maxLen = 4; - distances[(size_t)offset + 1] = d4 - 1; - offset += 2; - d2 = d4; - } - - if (offset != 0) - { + else + break; + + distances[-2] = 3; + if (*(cur - d2 + 3) != cur[3]) + break; UPDATE_maxLen - distances[(size_t)offset - 2] = maxLen; + distances[-2] = (UInt32)maxLen; if (maxLen == lenLimit) { - SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); - MOVE_POS_RET; + SkipMatchesSpec(MF_PARAMS(p)); + MOVE_POS_RET } + break; } - - if (maxLen < 4) - maxLen = 4; - GET_MATCHES_FOOTER(offset, maxLen) + GET_MATCHES_FOOTER_BT(maxLen) } -*/ -static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + +static UInt32* Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { + UInt32 mmm; UInt32 h2, h3, d2, d3, pos; - unsigned maxLen, offset; + unsigned maxLen; UInt32 *hash; GET_MATCHES_HEADER(4) - HASH4_CALC; + HASH4_CALC hash = p->hash; pos = p->pos; @@ -816,291 +1360,295 @@ static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) (hash + kFix3HashSize)[h3] = pos; (hash + kFix4HashSize)[hv] = pos; - maxLen = 0; - offset = 0; + SET_mmm - if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) - { - maxLen = 2; - distances[0] = 2; - distances[1] = d2 - 1; - offset = 2; - } - - if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) - { - maxLen = 3; - distances[(size_t)offset + 1] = d3 - 1; - offset += 2; - d2 = d3; - } - - if (offset != 0) + maxLen = 3; + + for (;;) { + if (d2 < mmm && *(cur - d2) == *cur) + { + distances[0] = 2; + distances[1] = d2 - 1; + distances += 2; + if (*(cur - d2 + 2) == cur[2]) + { + // distances[-2] = 3; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + d2 = d3; + distances[1] = d3 - 1; + distances += 2; + } + else + break; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + d2 = d3; + distances[1] = d3 - 1; + distances += 2; + } + else + break; + UPDATE_maxLen - distances[(size_t)offset - 2] = (UInt32)maxLen; + distances[-2] = (UInt32)maxLen; if (maxLen == lenLimit) { p->son[p->cyclicBufferPos] = curMatch; - MOVE_POS_RET; + MOVE_POS_RET } + break; } - if (maxLen < 3) - maxLen = 3; - - offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances + offset, maxLen) - (distances)); - MOVE_POS_RET + GET_MATCHES_FOOTER_HC(maxLen) } -/* -static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + +static UInt32 * Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos + UInt32 mmm; + UInt32 h2, h3, d2, d3, maxLen, pos; UInt32 *hash; GET_MATCHES_HEADER(5) - HASH5_CALC; + HASH5_CALC hash = p->hash; pos = p->pos; - + d2 = pos - hash [h2]; d3 = pos - (hash + kFix3HashSize)[h3]; - d4 = pos - (hash + kFix4HashSize)[h4]; + // d4 = pos - (hash + kFix4HashSize)[h4]; curMatch = (hash + kFix5HashSize)[hv]; hash [h2] = pos; (hash + kFix3HashSize)[h3] = pos; - (hash + kFix4HashSize)[h4] = pos; + // (hash + kFix4HashSize)[h4] = pos; (hash + kFix5HashSize)[hv] = pos; - maxLen = 0; - offset = 0; + SET_mmm + + maxLen = 4; - if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + for (;;) { - distances[0] = maxLen = 2; - distances[1] = d2 - 1; - offset = 2; - if (*(cur - d2 + 2) == cur[2]) - distances[0] = maxLen = 3; - else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + if (d2 < mmm && *(cur - d2) == *cur) + { + distances[0] = 2; + distances[1] = d2 - 1; + distances += 2; + if (*(cur - d2 + 2) == cur[2]) + { + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + distances[1] = d3 - 1; + distances += 2; + d2 = d3; + } + else + break; + } + else if (d3 < mmm && *(cur - d3) == *cur) { - distances[2] = maxLen = 3; - distances[3] = d3 - 1; - offset = 4; + distances[1] = d3 - 1; + distances += 2; d2 = d3; } - } - else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) - { - distances[0] = maxLen = 3; - distances[1] = d3 - 1; - offset = 2; - d2 = d3; - } - - if (d2 != d4 && d4 < p->cyclicBufferSize - && *(cur - d4) == *cur - && *(cur - d4 + 3) == *(cur + 3)) - { - maxLen = 4; - distances[(size_t)offset + 1] = d4 - 1; - offset += 2; - d2 = d4; - } - - if (offset != 0) - { + else + break; + + distances[-2] = 3; + if (*(cur - d2 + 3) != cur[3]) + break; UPDATE_maxLen - distances[(size_t)offset - 2] = maxLen; + distances[-2] = maxLen; if (maxLen == lenLimit) { p->son[p->cyclicBufferPos] = curMatch; - MOVE_POS_RET; + MOVE_POS_RET } + break; } - if (maxLen < 4) - maxLen = 4; - - offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances + offset, maxLen) - (distances)); - MOVE_POS_RET + GET_MATCHES_FOOTER_HC(maxLen) } -*/ -UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + +UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - unsigned offset; GET_MATCHES_HEADER(3) - HASH_ZIP_CALC; + HASH_ZIP_CALC curMatch = p->hash[hv]; p->hash[hv] = p->pos; - offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances, 2) - (distances)); - MOVE_POS_RET + GET_MATCHES_FOOTER_HC(2) } + static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { - do + SKIP_HEADER(2) { - SKIP_HEADER(2) - HASH2_CALC; + HASH2_CALC curMatch = p->hash[hv]; p->hash[hv] = p->pos; - SKIP_FOOTER } - while (--num != 0); + SKIP_FOOTER } void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { - do + SKIP_HEADER(3) { - SKIP_HEADER(3) - HASH_ZIP_CALC; + HASH_ZIP_CALC curMatch = p->hash[hv]; p->hash[hv] = p->pos; - SKIP_FOOTER } - while (--num != 0); + SKIP_FOOTER } static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { - do + SKIP_HEADER(3) { UInt32 h2; UInt32 *hash; - SKIP_HEADER(3) - HASH3_CALC; + HASH3_CALC hash = p->hash; curMatch = (hash + kFix3HashSize)[hv]; hash[h2] = (hash + kFix3HashSize)[hv] = p->pos; - SKIP_FOOTER } - while (--num != 0); + SKIP_FOOTER } static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { - do + SKIP_HEADER(4) { UInt32 h2, h3; UInt32 *hash; - SKIP_HEADER(4) - HASH4_CALC; + HASH4_CALC hash = p->hash; curMatch = (hash + kFix4HashSize)[hv]; hash [h2] = (hash + kFix3HashSize)[h3] = (hash + kFix4HashSize)[hv] = p->pos; - SKIP_FOOTER } - while (--num != 0); + SKIP_FOOTER } -/* static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { - do + SKIP_HEADER(5) { - UInt32 h2, h3, h4; + UInt32 h2, h3; UInt32 *hash; - SKIP_HEADER(5) - HASH5_CALC; + HASH5_CALC hash = p->hash; curMatch = (hash + kFix5HashSize)[hv]; hash [h2] = (hash + kFix3HashSize)[h3] = - (hash + kFix4HashSize)[h4] = + // (hash + kFix4HashSize)[h4] = (hash + kFix5HashSize)[hv] = p->pos; - SKIP_FOOTER } - while (--num != 0); + SKIP_FOOTER } -*/ + + +#define HC_SKIP_HEADER(minLen) \ + do { if (p->lenLimit < minLen) { MatchFinder_MovePos(p); num--; continue; } { \ + const Byte *cur; \ + UInt32 *hash; \ + UInt32 *son; \ + UInt32 pos = p->pos; \ + UInt32 num2 = num; \ + /* (p->pos == p->posLimit) is not allowed here !!! */ \ + { const UInt32 rem = p->posLimit - pos; if (num2 > rem) num2 = rem; } \ + num -= num2; \ + { const UInt32 cycPos = p->cyclicBufferPos; \ + son = p->son + cycPos; \ + p->cyclicBufferPos = cycPos + num2; } \ + cur = p->buffer; \ + hash = p->hash; \ + do { \ + UInt32 curMatch; \ + UInt32 hv; + + +#define HC_SKIP_FOOTER \ + cur++; pos++; *son++ = curMatch; \ + } while (--num2); \ + p->buffer = cur; \ + p->pos = pos; \ + if (pos == p->posLimit) MatchFinder_CheckLimits(p); \ + }} while(num); \ + static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { - do - { + HC_SKIP_HEADER(4) + UInt32 h2, h3; - UInt32 *hash; - SKIP_HEADER(4) - HASH4_CALC; - hash = p->hash; + HASH4_CALC curMatch = (hash + kFix4HashSize)[hv]; hash [h2] = (hash + kFix3HashSize)[h3] = - (hash + kFix4HashSize)[hv] = p->pos; - p->son[p->cyclicBufferPos] = curMatch; - MOVE_POS - } - while (--num != 0); + (hash + kFix4HashSize)[hv] = pos; + + HC_SKIP_FOOTER } -/* + static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { - do - { - UInt32 h2, h3, h4; - UInt32 *hash; - SKIP_HEADER(5) - HASH5_CALC; - hash = p->hash; - curMatch = hash + kFix5HashSize)[hv]; + HC_SKIP_HEADER(5) + + UInt32 h2, h3; + HASH5_CALC + curMatch = (hash + kFix5HashSize)[hv]; hash [h2] = (hash + kFix3HashSize)[h3] = - (hash + kFix4HashSize)[h4] = - (hash + kFix5HashSize)[hv] = p->pos; - p->son[p->cyclicBufferPos] = curMatch; - MOVE_POS - } - while (--num != 0); + // (hash + kFix4HashSize)[h4] = + (hash + kFix5HashSize)[hv] = pos; + + HC_SKIP_FOOTER } -*/ + void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { - do - { - SKIP_HEADER(3) - HASH_ZIP_CALC; - curMatch = p->hash[hv]; - p->hash[hv] = p->pos; - p->son[p->cyclicBufferPos] = curMatch; - MOVE_POS - } - while (--num != 0); + HC_SKIP_HEADER(3) + + HASH_ZIP_CALC + curMatch = hash[hv]; + hash[hv] = pos; + + HC_SKIP_FOOTER } -void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable) { vTable->Init = (Mf_Init_Func)MatchFinder_Init; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; if (!p->btMode) { - /* if (p->numHashBytes <= 4) */ + if (p->numHashBytes <= 4) { vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; } - /* else { vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip; } - */ } else if (p->numHashBytes == 2) { @@ -1112,16 +1660,58 @@ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; } - else /* if (p->numHashBytes == 4) */ + else if (p->numHashBytes == 4) { vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; } - /* else { vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip; } - */ } + + + +void LzFindPrepare(void) +{ + #ifndef FORCE_LZFIND_SATUR_SUB_128 + #ifdef USE_LZFIND_SATUR_SUB_128 + LZFIND_SATUR_SUB_CODE_FUNC f = NULL; + #ifdef MY_CPU_ARM_OR_ARM64 + { + if (CPU_IsSupported_NEON()) + { + // #pragma message ("=== LzFind NEON") + PRF(printf("\n=== LzFind NEON\n")); + f = LzFind_SaturSub_128; + } + // f = 0; // for debug + } + #else // MY_CPU_ARM_OR_ARM64 + if (CPU_IsSupported_SSE41()) + { + // #pragma message ("=== LzFind SSE41") + PRF(printf("\n=== LzFind SSE41\n")); + f = LzFind_SaturSub_128; + + #ifdef USE_LZFIND_SATUR_SUB_256 + if (CPU_IsSupported_AVX2()) + { + // #pragma message ("=== LzFind AVX2") + PRF(printf("\n=== LzFind AVX2\n")); + f = LzFind_SaturSub_256; + } + #endif + } + #endif // MY_CPU_ARM_OR_ARM64 + g_LzFind_SaturSub = f; + #endif // USE_LZFIND_SATUR_SUB_128 + #endif // FORCE_LZFIND_SATUR_SUB_128 +} + + +#undef MOVE_POS +#undef MOVE_POS_RET +#undef PRF diff --git a/libraries/lzma/C/LzFind.h b/libraries/lzma/C/LzFind.h index 42c13be157c..a3f72c98700 100644 --- a/libraries/lzma/C/LzFind.h +++ b/libraries/lzma/C/LzFind.h @@ -1,8 +1,8 @@ /* LzFind.h -- Match finder for LZ algorithms -2017-06-10 : Igor Pavlov : Public domain */ +2023-03-04 : Igor Pavlov : Public domain */ -#ifndef __LZ_FIND_H -#define __LZ_FIND_H +#ifndef ZIP7_INC_LZ_FIND_H +#define ZIP7_INC_LZ_FIND_H #include "7zTypes.h" @@ -10,12 +10,12 @@ EXTERN_C_BEGIN typedef UInt32 CLzRef; -typedef struct _CMatchFinder +typedef struct { - Byte *buffer; + const Byte *buffer; UInt32 pos; UInt32 posLimit; - UInt32 streamPos; + UInt32 streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (UInt32)(streamPos - pos) */ UInt32 lenLimit; UInt32 cyclicBufferPos; @@ -32,8 +32,8 @@ typedef struct _CMatchFinder UInt32 hashMask; UInt32 cutValue; - Byte *bufferBase; - ISeqInStream *stream; + Byte *bufBase; + ISeqInStreamPtr stream; UInt32 blockSize; UInt32 keepSizeBefore; @@ -43,7 +43,9 @@ typedef struct _CMatchFinder size_t directInputRem; UInt32 historySize; UInt32 fixedHashSize; - UInt32 hashSizeSum; + Byte numHashBytes_Min; + Byte numHashOutBits; + Byte _pad2_[2]; SRes result; UInt32 crc[256]; size_t numRefs; @@ -51,35 +53,69 @@ typedef struct _CMatchFinder UInt64 expectedDataSize; } CMatchFinder; -#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) +#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const Byte *)(p)->buffer) -#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((UInt32)((p)->streamPos - (p)->pos)) +/* #define Inline_MatchFinder_IsFinishedOK(p) \ ((p)->streamEndWasReached \ && (p)->streamPos == (p)->pos \ && (!(p)->directInput || (p)->directInputRem == 0)) +*/ int MatchFinder_NeedMove(CMatchFinder *p); -Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +/* Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */ void MatchFinder_MoveBlock(CMatchFinder *p); void MatchFinder_ReadIfRequired(CMatchFinder *p); void MatchFinder_Construct(CMatchFinder *p); -/* Conditions: - historySize <= 3 GB - keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB +/* (directInput = 0) is default value. + It's required to provide correct (directInput) value + before calling MatchFinder_Create(). + You can set (directInput) by any of the following calls: + - MatchFinder_SET_DIRECT_INPUT_BUF() + - MatchFinder_SET_STREAM() + - MatchFinder_SET_STREAM_MODE() +*/ + +#define MatchFinder_SET_DIRECT_INPUT_BUF(p, _src_, _srcLen_) { \ + (p)->stream = NULL; \ + (p)->directInput = 1; \ + (p)->buffer = (_src_); \ + (p)->directInputRem = (_srcLen_); } + +/* +#define MatchFinder_SET_STREAM_MODE(p) { \ + (p)->directInput = 0; } */ + +#define MatchFinder_SET_STREAM(p, _stream_) { \ + (p)->stream = _stream_; \ + (p)->directInput = 0; } + + int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc); void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc); void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); -void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); + +/* +#define MatchFinder_INIT_POS(p, val) \ + (p)->pos = (val); \ + (p)->streamPos = (val); +*/ + +// void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); +#define MatchFinder_REDUCE_OFFSETS(p, subValue) \ + (p)->pos -= (subValue); \ + (p)->streamPos -= (subValue); + UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, - UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *distances, UInt32 maxLen); /* @@ -91,31 +127,33 @@ UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byt typedef void (*Mf_Init_Func)(void *object); typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); -typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); +typedef UInt32 * (*Mf_GetMatches_Func)(void *object, UInt32 *distances); typedef void (*Mf_Skip_Func)(void *object, UInt32); -typedef struct _IMatchFinder +typedef struct { Mf_Init_Func Init; Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; Mf_GetMatches_Func GetMatches; Mf_Skip_Func Skip; -} IMatchFinder; +} IMatchFinder2; -void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable); void MatchFinder_Init_LowHash(CMatchFinder *p); void MatchFinder_Init_HighHash(CMatchFinder *p); -void MatchFinder_Init_3(CMatchFinder *p, int readData); +void MatchFinder_Init_4(CMatchFinder *p); void MatchFinder_Init(CMatchFinder *p); -UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); -UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +void LzFindPrepare(void); + EXTERN_C_END #endif diff --git a/libraries/lzma/C/LzFindMt.c b/libraries/lzma/C/LzFindMt.c index bb0f42c302c..5253e6ebb35 100644 --- a/libraries/lzma/C/LzFindMt.c +++ b/libraries/lzma/C/LzFindMt.c @@ -1,97 +1,215 @@ /* LzFindMt.c -- multithreaded Match finder for LZ algorithms -2018-12-29 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ #include "Precomp.h" -#include "LzHash.h" +// #include + +#include "CpuArch.h" +#include "LzHash.h" #include "LzFindMt.h" +// #define LOG_ITERS + +// #define LOG_THREAD + +#ifdef LOG_THREAD +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#ifdef LOG_ITERS +#include +extern UInt64 g_NumIters_Tree; +extern UInt64 g_NumIters_Loop; +extern UInt64 g_NumIters_Bytes; +#define LOG_ITER(x) x +#else +#define LOG_ITER(x) +#endif + +#define kMtHashBlockSize ((UInt32)1 << 17) +#define kMtHashNumBlocks (1 << 1) + +#define GET_HASH_BLOCK_OFFSET(i) (((i) & (kMtHashNumBlocks - 1)) * kMtHashBlockSize) + +#define kMtBtBlockSize ((UInt32)1 << 16) +#define kMtBtNumBlocks (1 << 4) + +#define GET_BT_BLOCK_OFFSET(i) (((i) & (kMtBtNumBlocks - 1)) * (size_t)kMtBtBlockSize) + +/* + HASH functions: + We use raw 8/16 bits from a[1] and a[2], + xored with crc(a[0]) and crc(a[3]). + We check a[0], a[3] only. We don't need to compare a[1] and a[2] in matches. + our crc() function provides one-to-one correspondence for low 8-bit values: + (crc[0...0xFF] & 0xFF) <-> [0...0xFF] +*/ + +#define MF(mt) ((mt)->MatchFinder) +#define MF_CRC (p->crc) + +// #define MF(mt) (&(mt)->MatchFinder) +// #define MF_CRC (p->MatchFinder.crc) + +#define MT_HASH2_CALC \ + h2 = (MF_CRC[cur[0]] ^ cur[1]) & (kHash2Size - 1); + +#define MT_HASH3_CALC { \ + UInt32 temp = MF_CRC[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +/* +#define MT_HASH3_CALC__NO_2 { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +#define MT_HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + h4 = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hash4Mask; } + // (kHash4Size - 1); +*/ + + +Z7_NO_INLINE static void MtSync_Construct(CMtSync *p) { + p->affinity = 0; p->wasCreated = False; p->csWasInitialized = False; p->csWasEntered = False; - Thread_Construct(&p->thread); + Thread_CONSTRUCT(&p->thread) Event_Construct(&p->canStart); - Event_Construct(&p->wasStarted); Event_Construct(&p->wasStopped); Semaphore_Construct(&p->freeSemaphore); Semaphore_Construct(&p->filledSemaphore); } -static void MtSync_GetNextBlock(CMtSync *p) + +#define DEBUG_BUFFER_LOCK // define it to debug lock state + +#ifdef DEBUG_BUFFER_LOCK +#include +#define BUFFER_MUST_BE_LOCKED(p) if (!(p)->csWasEntered) exit(1); +#define BUFFER_MUST_BE_UNLOCKED(p) if ( (p)->csWasEntered) exit(1); +#else +#define BUFFER_MUST_BE_LOCKED(p) +#define BUFFER_MUST_BE_UNLOCKED(p) +#endif + +#define LOCK_BUFFER(p) { \ + BUFFER_MUST_BE_UNLOCKED(p); \ + CriticalSection_Enter(&(p)->cs); \ + (p)->csWasEntered = True; } + +#define UNLOCK_BUFFER(p) { \ + BUFFER_MUST_BE_LOCKED(p); \ + CriticalSection_Leave(&(p)->cs); \ + (p)->csWasEntered = False; } + + +Z7_NO_INLINE +static UInt32 MtSync_GetNextBlock(CMtSync *p) { + UInt32 numBlocks = 0; if (p->needStart) { + BUFFER_MUST_BE_UNLOCKED(p) p->numProcessedBlocks = 1; p->needStart = False; p->stopWriting = False; p->exit = False; - Event_Reset(&p->wasStarted); Event_Reset(&p->wasStopped); - Event_Set(&p->canStart); - Event_Wait(&p->wasStarted); - - // if (mt) MatchFinder_Init_LowHash(mt->MatchFinder); } else { - CriticalSection_Leave(&p->cs); - p->csWasEntered = False; - p->numProcessedBlocks++; + UNLOCK_BUFFER(p) + // we free current block + numBlocks = p->numProcessedBlocks++; Semaphore_Release1(&p->freeSemaphore); } + + // buffer is UNLOCKED here Semaphore_Wait(&p->filledSemaphore); - CriticalSection_Enter(&p->cs); - p->csWasEntered = True; + LOCK_BUFFER(p) + return numBlocks; } -/* MtSync_StopWriting must be called if Writing was started */ +/* if Writing (Processing) thread was started, we must call MtSync_StopWriting() */ + +Z7_NO_INLINE static void MtSync_StopWriting(CMtSync *p) { - UInt32 myNumBlocks = p->numProcessedBlocks; if (!Thread_WasCreated(&p->thread) || p->needStart) return; - p->stopWriting = True; + + PRF(printf("\nMtSync_StopWriting %p\n", p)); + if (p->csWasEntered) { - CriticalSection_Leave(&p->cs); - p->csWasEntered = False; + /* we don't use buffer in this thread after StopWriting(). + So we UNLOCK buffer. + And we restore default UNLOCKED state for stopped thread */ + UNLOCK_BUFFER(p) } - Semaphore_Release1(&p->freeSemaphore); - + + /* We send (p->stopWriting) message and release freeSemaphore + to free current block. + So the thread will see (p->stopWriting) at some + iteration after Wait(freeSemaphore). + The thread doesn't need to fill all avail free blocks, + so we can get fast thread stop. + */ + + p->stopWriting = True; + Semaphore_Release1(&p->freeSemaphore); // check semaphore count !!! + + PRF(printf("\nMtSync_StopWriting %p : Event_Wait(&p->wasStopped)\n", p)); Event_Wait(&p->wasStopped); + PRF(printf("\nMtSync_StopWriting %p : Event_Wait() finsihed\n", p)); + + /* 21.03 : we don't restore samaphore counters here. + We will recreate and reinit samaphores in next start */ - while (myNumBlocks++ != p->numProcessedBlocks) - { - Semaphore_Wait(&p->filledSemaphore); - Semaphore_Release1(&p->freeSemaphore); - } p->needStart = True; } + +Z7_NO_INLINE static void MtSync_Destruct(CMtSync *p) { + PRF(printf("\nMtSync_Destruct %p\n", p)); + if (Thread_WasCreated(&p->thread)) { + /* we want thread to be in Stopped state before sending EXIT command. + note: stop(btSync) will stop (htSync) also */ MtSync_StopWriting(p); + /* thread in Stopped state here : (p->needStart == true) */ p->exit = True; - if (p->needStart) - Event_Set(&p->canStart); - Thread_Wait(&p->thread); - Thread_Close(&p->thread); + // if (p->needStart) // it's (true) + Event_Set(&p->canStart); // we send EXIT command to thread + Thread_Wait_Close(&p->thread); // we wait thread finishing } + if (p->csWasInitialized) { CriticalSection_Delete(&p->cs); p->csWasInitialized = False; } + p->csWasEntered = False; Event_Close(&p->canStart); - Event_Close(&p->wasStarted); Event_Close(&p->wasStopped); Semaphore_Close(&p->freeSemaphore); Semaphore_Close(&p->filledSemaphore); @@ -99,80 +217,251 @@ static void MtSync_Destruct(CMtSync *p) p->wasCreated = False; } -#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } -static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) +// #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } +// we want to get real system error codes here instead of SZ_ERROR_THREAD +#define RINOK_THREAD(x) RINOK_WRes(x) + + +// call it before each new file (when new starting is required): +Z7_NO_INLINE +static SRes MtSync_Init(CMtSync *p, UInt32 numBlocks) +{ + WRes wres; + // BUFFER_MUST_BE_UNLOCKED(p) + if (!p->needStart || p->csWasEntered) + return SZ_ERROR_FAIL; + wres = Semaphore_OptCreateInit(&p->freeSemaphore, numBlocks, numBlocks); + if (wres == 0) + wres = Semaphore_OptCreateInit(&p->filledSemaphore, 0, numBlocks); + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +static WRes MtSync_Create_WRes(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj) { + WRes wres; + if (p->wasCreated) return SZ_OK; - RINOK_THREAD(CriticalSection_Init(&p->cs)); + RINOK_THREAD(CriticalSection_Init(&p->cs)) p->csWasInitialized = True; + p->csWasEntered = False; - RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)); - RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted)); - RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)); - - RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks)); - RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)) + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)) p->needStart = True; - - RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj)); + p->exit = True; /* p->exit is unused before (canStart) Event. + But in case of some unexpected code failure we will get fast exit from thread */ + + // return ERROR_TOO_MANY_POSTS; // for debug + // return EINVAL; // for debug + + if (p->affinity != 0) + wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity); + else + wres = Thread_Create(&p->thread, startAddress, obj); + + RINOK_THREAD(wres) p->wasCreated = True; return SZ_OK; } -static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) + +Z7_NO_INLINE +static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj) { - SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); - if (res != SZ_OK) - MtSync_Destruct(p); - return res; + const WRes wres = MtSync_Create_WRes(p, startAddress, obj); + if (wres == 0) + return 0; + MtSync_Destruct(p); + return MY_SRes_HRESULT_FROM_WRes(wres); } -void MtSync_Init(CMtSync *p) { p->needStart = True; } + +// ---------- HASH THREAD ---------- #define kMtMaxValForNormalize 0xFFFFFFFF +// #define kMtMaxValForNormalize ((1 << 21)) // for debug +// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses -#define DEF_GetHeads2(name, v, action) \ - static void GetHeads ## name(const Byte *p, UInt32 pos, \ - UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ - { action; for (; numHeads != 0; numHeads--) { \ - const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } +#ifdef MY_CPU_LE_UNALIGN + #define GetUi24hi_from32(p) ((UInt32)GetUi32(p) >> 8) +#else + #define GetUi24hi_from32(p) ((p)[1] ^ ((UInt32)(p)[2] << 8) ^ ((UInt32)(p)[3] << 16)) +#endif + +#define GetHeads_DECL(name) \ + static void GetHeads ## name(const Byte *p, UInt32 pos, \ + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) + +#define GetHeads_LOOP(v) \ + for (; numHeads != 0; numHeads--) { \ + const UInt32 value = (v); \ + p++; \ + *heads++ = pos - hash[value]; \ + hash[value] = pos++; } +#define DEF_GetHeads2(name, v, action) \ + GetHeads_DECL(name) { action \ + GetHeads_LOOP(v) } + #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) -DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) -DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) -DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) -DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) -/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ +DEF_GetHeads2(2, GetUi16(p), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) +DEF_GetHeads(3, (crc[p[0]] ^ GetUi16(p + 1)) & hashMask) +DEF_GetHeads2(3b, GetUi16(p) ^ ((UInt32)(p)[2] << 16), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) +// BT3 is not good for crc collisions for big hashMask values. + +/* +GetHeads_DECL(3b) +{ + UNUSED_VAR(hashMask); + UNUSED_VAR(crc); + { + const Byte *pLim = p + numHeads; + if (numHeads == 0) + return; + pLim--; + while (p < pLim) + { + UInt32 v1 = GetUi32(p); + UInt32 v0 = v1 & 0xFFFFFF; + UInt32 h0, h1; + p += 2; + v1 >>= 8; + h0 = hash[v0]; hash[v0] = pos; heads[0] = pos - h0; pos++; + h1 = hash[v1]; hash[v1] = pos; heads[1] = pos - h1; pos++; + heads += 2; + } + if (p == pLim) + { + UInt32 v0 = GetUi16(p) ^ ((UInt32)(p)[2] << 16); + *heads = pos - hash[v0]; + hash[v0] = pos; + } + } +} +*/ + +/* +GetHeads_DECL(4) +{ + unsigned sh = 0; + UNUSED_VAR(crc) + while ((hashMask & 0x80000000) == 0) + { + hashMask <<= 1; + sh++; + } + GetHeads_LOOP((GetUi32(p) * 0xa54a1) >> sh) +} +#define GetHeads4b GetHeads4 +*/ + +#define USE_GetHeads_LOCAL_CRC + +#ifdef USE_GetHeads_LOCAL_CRC + +GetHeads_DECL(4) +{ + UInt32 crc0[256]; + UInt32 crc1[256]; + { + unsigned i; + for (i = 0; i < 256; i++) + { + UInt32 v = crc[i]; + crc0[i] = v & hashMask; + crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; + // crc1[i] = rotlFixed(v, 8) & hashMask; + } + } + GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ (UInt32)GetUi16(p+1)) +} + +GetHeads_DECL(4b) +{ + UInt32 crc0[256]; + { + unsigned i; + for (i = 0; i < 256; i++) + crc0[i] = crc[i] & hashMask; + } + GetHeads_LOOP(crc0[p[0]] ^ GetUi24hi_from32(p)) +} + +GetHeads_DECL(5) +{ + UInt32 crc0[256]; + UInt32 crc1[256]; + UInt32 crc2[256]; + { + unsigned i; + for (i = 0; i < 256; i++) + { + UInt32 v = crc[i]; + crc0[i] = v & hashMask; + crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; + crc2[i] = (v << kLzHash_CrcShift_2) & hashMask; + } + } + GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ crc2[p[4]] ^ (UInt32)GetUi16(p+1)) +} + +GetHeads_DECL(5b) +{ + UInt32 crc0[256]; + UInt32 crc1[256]; + { + unsigned i; + for (i = 0; i < 256; i++) + { + UInt32 v = crc[i]; + crc0[i] = v & hashMask; + crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; + } + } + GetHeads_LOOP(crc0[p[0]] ^ crc1[p[4]] ^ GetUi24hi_from32(p)) +} + +#else + +DEF_GetHeads(4, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (UInt32)GetUi16(p+1)) & hashMask) +DEF_GetHeads(4b, (crc[p[0]] ^ GetUi24hi_from32(p)) & hashMask) +DEF_GetHeads(5, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (crc[p[4]] << kLzHash_CrcShift_2) ^ (UInt32)GetUi16(p + 1)) & hashMask) +DEF_GetHeads(5b, (crc[p[0]] ^ (crc[p[4]] << kLzHash_CrcShift_1) ^ GetUi24hi_from32(p)) & hashMask) + +#endif + static void HashThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->hashSync; + PRF(printf("\nHashThreadFunc\n")); + for (;;) { - UInt32 numProcessedBlocks = 0; + UInt32 blockIndex = 0; + PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart)\n")); Event_Wait(&p->canStart); - Event_Set(&p->wasStarted); + PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart) : after \n")); + if (p->exit) + { + PRF(printf("\nHashThreadFunc : exit \n")); + return; + } - MatchFinder_Init_HighHash(mt->MatchFinder); + MatchFinder_Init_HighHash(MF(mt)); for (;;) { - if (p->exit) - return; - if (p->stopWriting) - { - p->numProcessedBlocks = numProcessedBlocks; - Event_Set(&p->wasStopped); - break; - } + PRF(printf("Hash thread block = %d pos = %d\n", (unsigned)blockIndex, mt->MatchFinder->pos)); { - CMatchFinder *mf = mt->MatchFinder; + CMatchFinder *mf = MF(mt); if (MatchFinder_NeedMove(mf)) { CriticalSection_Enter(&mt->btSync.cs); @@ -185,194 +474,178 @@ static void HashThreadFunc(CMatchFinderMt *mt) mt->pointerToCurPos -= offset; mt->buffer -= offset; } - CriticalSection_Leave(&mt->btSync.cs); CriticalSection_Leave(&mt->hashSync.cs); + CriticalSection_Leave(&mt->btSync.cs); continue; } Semaphore_Wait(&p->freeSemaphore); + if (p->exit) // exit is unexpected here. But we check it here for some failure case + return; + + // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore) + if (p->stopWriting) + break; + MatchFinder_ReadIfRequired(mf); - if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize)) { - UInt32 subValue = (mf->pos - mf->historySize - 1); - MatchFinder_ReduceOffsets(mf, subValue); - MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); - } - { - UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; - UInt32 num = mf->streamPos - mf->pos; + UInt32 *heads = mt->hashBuf + GET_HASH_BLOCK_OFFSET(blockIndex++); + UInt32 num = Inline_MatchFinder_GetNumAvailableBytes(mf); heads[0] = 2; heads[1] = num; + + /* heads[1] contains the number of avail bytes: + if (avail < mf->numHashBytes) : + { + it means that stream was finished + HASH_THREAD and BT_TREAD must move position for heads[1] (avail) bytes. + HASH_THREAD doesn't stop, + HASH_THREAD fills only the header (2 numbers) for all next blocks: + {2, NumHashBytes - 1}, {2,0}, {2,0}, ... , {2,0} + } + else + { + HASH_THREAD and BT_TREAD must move position for (heads[0] - 2) bytes; + } + */ + if (num >= mf->numHashBytes) { num = num - mf->numHashBytes + 1; if (num > kMtHashBlockSize - 2) num = kMtHashBlockSize - 2; - mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); + + if (mf->pos > (UInt32)kMtMaxValForNormalize - num) + { + const UInt32 subValue = (mf->pos - mf->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1); + MatchFinder_REDUCE_OFFSETS(mf, subValue) + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); + } + heads[0] = 2 + num; + mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); } - mf->pos += num; + + mf->pos += num; // wrap over zero is allowed at the end of stream mf->buffer += num; } } Semaphore_Release1(&p->filledSemaphore); - } - } -} + } // for() processing end -static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) -{ - MtSync_GetNextBlock(&p->hashSync); - p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; - p->hashBufPosLimit += p->hashBuf[p->hashBufPos++]; - p->hashNumAvail = p->hashBuf[p->hashBufPos++]; + // p->numBlocks_Sent = blockIndex; + Event_Set(&p->wasStopped); + } // for() thread end } -#define kEmptyHashValue 0 + + + +// ---------- BT THREAD ---------- + +/* we use one variable instead of two (cyclicBufferPos == pos) before CyclicBuf wrap. + here we define fixed offset of (p->pos) from (p->cyclicBufferPos) */ +#define CYC_TO_POS_OFFSET 0 +// #define CYC_TO_POS_OFFSET 1 // for debug #define MFMT_GM_INLINE #ifdef MFMT_GM_INLINE /* - we use size_t for _cyclicBufferPos instead of UInt32 + we use size_t for (pos) instead of UInt32 to eliminate "movsx" BUG in old MSVC x64 compiler. */ -MY_NO_INLINE -static UInt32 *GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, - UInt32 *distances, UInt32 _maxLen, const UInt32 *hash, const UInt32 *limit, UInt32 size, UInt32 *posRes) -{ - do - { - UInt32 *_distances = ++distances; - UInt32 delta = *hash++; - - CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; - CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); - unsigned len0 = 0, len1 = 0; - UInt32 cutValue = _cutValue; - unsigned maxLen = (unsigned)_maxLen; - /* - if (size > 1) - { - UInt32 delta = *hash; - if (delta < _cyclicBufferSize) - { - UInt32 cyc1 = _cyclicBufferPos + 1; - CLzRef *pair = son + ((size_t)(cyc1 - delta + ((delta > cyc1) ? _cyclicBufferSize : 0)) << 1); - Byte b = *(cur + 1 - delta); - _distances[0] = pair[0]; - _distances[1] = b; - } - } - */ - if (cutValue == 0 || delta >= _cyclicBufferSize) - { - *ptr0 = *ptr1 = kEmptyHashValue; - } - else - for(;;) - { - { - CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((_cyclicBufferPos < delta) ? _cyclicBufferSize : 0)) << 1); - const Byte *pb = cur - delta; - unsigned len = (len0 < len1 ? len0 : len1); - UInt32 pair0 = *pair; - if (pb[len] == cur[len]) - { - if (++len != lenLimit && pb[len] == cur[len]) - while (++len != lenLimit) - if (pb[len] != cur[len]) - break; - if (maxLen < len) - { - maxLen = len; - *distances++ = (UInt32)len; - *distances++ = delta - 1; - if (len == lenLimit) - { - UInt32 pair1 = pair[1]; - *ptr1 = pair0; - *ptr0 = pair1; - break; - } - } - } - { - UInt32 curMatch = pos - delta; - // delta = pos - *pair; - // delta = pos - pair[((UInt32)pb[len] - (UInt32)cur[len]) >> 31]; - if (pb[len] < cur[len]) - { - delta = pos - pair[1]; - *ptr1 = curMatch; - ptr1 = pair + 1; - len1 = len; - } - else - { - delta = pos - *pair; - *ptr0 = curMatch; - ptr0 = pair; - len0 = len; - } - } - } - if (--cutValue == 0 || delta >= _cyclicBufferSize) - { - *ptr0 = *ptr1 = kEmptyHashValue; - break; - } - } - pos++; - _cyclicBufferPos++; - cur++; - { - UInt32 num = (UInt32)(distances - _distances); - _distances[-1] = num; - } - } - while (distances < limit && --size != 0); - *posRes = pos; - return distances; -} +UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, + UInt32 *posRes); #endif - -static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) +static void BtGetMatches(CMatchFinderMt *p, UInt32 *d) { UInt32 numProcessed = 0; UInt32 curPos = 2; - UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); // * 2 - distances[1] = p->hashNumAvail; + /* GetMatchesSpec() functions don't create (len = 1) + in [len, dist] match pairs, if (p->numHashBytes >= 2) + Also we suppose here that (matchMaxLen >= 2). + So the following code for (reserve) is not required + UInt32 reserve = (p->matchMaxLen * 2); + const UInt32 kNumHashBytes_Max = 5; // BT_HASH_BYTES_MAX + if (reserve < kNumHashBytes_Max - 1) + reserve = kNumHashBytes_Max - 1; + const UInt32 limit = kMtBtBlockSize - (reserve); + */ + + const UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); + + d[1] = p->hashNumAvail; + + if (p->failure_BT) + { + // printf("\n == 1 BtGetMatches() p->failure_BT\n"); + d[0] = 0; + // d[1] = 0; + return; + } while (curPos < limit) { if (p->hashBufPos == p->hashBufPosLimit) { - MatchFinderMt_GetNextBlock_Hash(p); - distances[1] = numProcessed + p->hashNumAvail; - if (p->hashNumAvail >= p->numHashBytes) + // MatchFinderMt_GetNextBlock_Hash(p); + UInt32 avail; + { + const UInt32 bi = MtSync_GetNextBlock(&p->hashSync); + const UInt32 k = GET_HASH_BLOCK_OFFSET(bi); + const UInt32 *h = p->hashBuf + k; + avail = h[1]; + p->hashBufPosLimit = k + h[0]; + p->hashNumAvail = avail; + p->hashBufPos = k + 2; + } + + { + /* we must prevent UInt32 overflow for avail total value, + if avail was increased with new hash block */ + UInt32 availSum = numProcessed + avail; + if (availSum < numProcessed) + availSum = (UInt32)(Int32)-1; + d[1] = availSum; + } + + if (avail >= p->numHashBytes) continue; - distances[0] = curPos + p->hashNumAvail; - distances += curPos; - for (; p->hashNumAvail != 0; p->hashNumAvail--) - *distances++ = 0; + + // if (p->hashBufPos != p->hashBufPosLimit) exit(1); + + /* (avail < p->numHashBytes) + It means that stream was finished. + And (avail) - is a number of remaining bytes, + we fill (d) for (avail) bytes for LZ_THREAD (receiver). + but we don't update (p->pos) and (p->cyclicBufferPos) here in BT_THREAD */ + + /* here we suppose that we have space enough: + (kMtBtBlockSize - curPos >= p->hashNumAvail) */ + p->hashNumAvail = 0; + d[0] = curPos + avail; + d += curPos; + for (; avail != 0; avail--) + *d++ = 0; return; } { UInt32 size = p->hashBufPosLimit - p->hashBufPos; - UInt32 lenLimit = p->matchMaxLen; UInt32 pos = p->pos; UInt32 cyclicBufferPos = p->cyclicBufferPos; + UInt32 lenLimit = p->matchMaxLen; if (lenLimit >= p->hashNumAvail) lenLimit = p->hashNumAvail; { @@ -384,10 +657,18 @@ static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) size = size2; } + if (pos > (UInt32)kMtMaxValForNormalize - size) + { + const UInt32 subValue = (pos - p->cyclicBufferSize); // & ~(UInt32)(kNormalizeAlign - 1); + pos -= subValue; + p->pos = pos; + MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); + } + #ifndef MFMT_GM_INLINE while (curPos < limit && size-- != 0) { - UInt32 *startDistances = distances + curPos; + UInt32 *startDistances = d + curPos; UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, startDistances + 1, p->numHashBytes - 1) - startDistances); @@ -399,81 +680,112 @@ static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) } #else { - UInt32 posRes; - curPos = (UInt32)(GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, - distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, - distances + limit, - size, &posRes) - distances); - p->hashBufPos += posRes - pos; - cyclicBufferPos += posRes - pos; - p->buffer += posRes - pos; - pos = posRes; + UInt32 posRes = pos; + const UInt32 *d_end; + { + d_end = GetMatchesSpecN_2( + p->buffer + lenLimit - 1, + pos, p->buffer, p->son, p->cutValue, d + curPos, + p->numHashBytes - 1, p->hashBuf + p->hashBufPos, + d + limit, p->hashBuf + p->hashBufPos + size, + cyclicBufferPos, p->cyclicBufferSize, + &posRes); + } + { + if (!d_end) + { + // printf("\n == 2 BtGetMatches() p->failure_BT\n"); + // internal data failure + p->failure_BT = True; + d[0] = 0; + // d[1] = 0; + return; + } + } + curPos = (UInt32)(d_end - d); + { + const UInt32 processed = posRes - pos; + pos = posRes; + p->hashBufPos += processed; + cyclicBufferPos += processed; + p->buffer += processed; + } } #endif - numProcessed += pos - p->pos; - p->hashNumAvail -= pos - p->pos; - p->pos = pos; + { + const UInt32 processed = pos - p->pos; + numProcessed += processed; + p->hashNumAvail -= processed; + p->pos = pos; + } if (cyclicBufferPos == p->cyclicBufferSize) cyclicBufferPos = 0; p->cyclicBufferPos = cyclicBufferPos; } } - distances[0] = curPos; + d[0] = curPos; } + static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) { CMtSync *sync = &p->hashSync; + + BUFFER_MUST_BE_UNLOCKED(sync) + if (!sync->needStart) { - CriticalSection_Enter(&sync->cs); - sync->csWasEntered = True; + LOCK_BUFFER(sync) } - BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize); - - if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) - { - UInt32 subValue = p->pos - p->cyclicBufferSize; - MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); - p->pos -= subValue; - } + BtGetMatches(p, p->btBuf + GET_BT_BLOCK_OFFSET(globalBlockIndex)); + + /* We suppose that we have called GetNextBlock() from start. + So buffer is LOCKED */ - if (!sync->needStart) - { - CriticalSection_Leave(&sync->cs); - sync->csWasEntered = False; - } + UNLOCK_BUFFER(sync) } -void BtThreadFunc(CMatchFinderMt *mt) + +Z7_NO_INLINE +static void BtThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->btSync; for (;;) { UInt32 blockIndex = 0; Event_Wait(&p->canStart); - Event_Set(&p->wasStarted); + for (;;) { + PRF(printf(" BT thread block = %d pos = %d\n", (unsigned)blockIndex, mt->pos)); + /* (p->exit == true) is possible after (p->canStart) at first loop iteration + and is unexpected after more Wait(freeSemaphore) iterations */ if (p->exit) return; + + Semaphore_Wait(&p->freeSemaphore); + + // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore) if (p->stopWriting) - { - p->numProcessedBlocks = blockIndex; - MtSync_StopWriting(&mt->hashSync); - Event_Set(&p->wasStopped); break; - } - Semaphore_Wait(&p->freeSemaphore); + BtFillBlock(mt, blockIndex++); + Semaphore_Release1(&p->filledSemaphore); } + + // we stop HASH_THREAD here + MtSync_StopWriting(&mt->hashSync); + + // p->numBlocks_Sent = blockIndex; + Event_Set(&p->wasStopped); } } + void MatchFinderMt_Construct(CMatchFinderMt *p) { p->hashBuf = NULL; @@ -489,16 +801,39 @@ static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc) void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc) { - MtSync_Destruct(&p->hashSync); + /* + HASH_THREAD can use CriticalSection(s) btSync.cs and hashSync.cs. + So we must be sure that HASH_THREAD will not use CriticalSection(s) + after deleting CriticalSection here. + + we call ReleaseStream(p) + that calls StopWriting(btSync) + that calls StopWriting(hashSync), if it's required to stop HASH_THREAD. + after StopWriting() it's safe to destruct MtSync(s) in any order */ + + MatchFinderMt_ReleaseStream(p); + MtSync_Destruct(&p->btSync); + MtSync_Destruct(&p->hashSync); + + LOG_ITER( + printf("\nTree %9d * %7d iter = %9d = sum : bytes = %9d\n", + (UInt32)(g_NumIters_Tree / 1000), + (UInt32)(((UInt64)g_NumIters_Loop * 1000) / (g_NumIters_Tree + 1)), + (UInt32)(g_NumIters_Loop / 1000), + (UInt32)(g_NumIters_Bytes / 1000) + )); + MatchFinderMt_FreeMem(p, alloc); } + #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) -static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } -static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) + +static THREAD_FUNC_DECL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static THREAD_FUNC_DECL BtThreadFunc2(void *p) { Byte allocaDummy[0x180]; unsigned i = 0; @@ -509,16 +844,17 @@ static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) return 0; } + SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc) { - CMatchFinder *mf = p->MatchFinder; + CMatchFinder *mf = MF(p); p->historySize = historySize; if (kMtBtBlockSize <= matchMaxLen * 4) return SZ_ERROR_PARAM; if (!p->hashBuf) { - p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); + p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, ((size_t)kHashBufferSize + (size_t)kBtBufferSize) * sizeof(UInt32)); if (!p->hashBuf) return SZ_ERROR_MEM; p->btBuf = p->hashBuf + kHashBufferSize; @@ -528,253 +864,456 @@ SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddB if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) return SZ_ERROR_MEM; - RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks)); - RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks)); + RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p)) + RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p)) return SZ_OK; } -/* Call it after ReleaseStream / SetStream */ + +SRes MatchFinderMt_InitMt(CMatchFinderMt *p) +{ + RINOK(MtSync_Init(&p->hashSync, kMtHashNumBlocks)) + return MtSync_Init(&p->btSync, kMtBtNumBlocks); +} + + static void MatchFinderMt_Init(CMatchFinderMt *p) { - CMatchFinder *mf = p->MatchFinder; + CMatchFinder *mf = MF(p); p->btBufPos = - p->btBufPosLimit = 0; + p->btBufPosLimit = NULL; p->hashBufPos = p->hashBufPosLimit = 0; + p->hashNumAvail = 0; // 21.03 + + p->failure_BT = False; /* Init without data reading. We don't want to read data in this thread */ - MatchFinder_Init_3(mf, False); + MatchFinder_Init_4(mf); + MatchFinder_Init_LowHash(mf); p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); p->btNumAvailBytes = 0; - p->lzPos = p->historySize + 1; + p->failure_LZ_BT = False; + // p->failure_LZ_LZ = False; + + p->lzPos = + 1; // optimal smallest value + // 0; // for debug: ignores match to start + // kNormalizeAlign; // for debug p->hash = mf->hash; p->fixedHashSize = mf->fixedHashSize; + // p->hash4Mask = mf->hash4Mask; p->crc = mf->crc; + // memcpy(p->crc, mf->crc, sizeof(mf->crc)); p->son = mf->son; p->matchMaxLen = mf->matchMaxLen; p->numHashBytes = mf->numHashBytes; - p->pos = mf->pos; - p->buffer = mf->buffer; - p->cyclicBufferPos = mf->cyclicBufferPos; + + /* (mf->pos) and (mf->streamPos) were already initialized to 1 in MatchFinder_Init_4() */ + // mf->streamPos = mf->pos = 1; // optimal smallest value + // 0; // for debug: ignores match to start + // kNormalizeAlign; // for debug + + /* we must init (p->pos = mf->pos) for BT, because + BT code needs (p->pos == delta_value_for_empty_hash_record == mf->pos) */ + p->pos = mf->pos; // do not change it + + p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); p->cyclicBufferSize = mf->cyclicBufferSize; + p->buffer = mf->buffer; p->cutValue = mf->cutValue; + // p->son[0] = p->son[1] = 0; // unused: to init skipped record for speculated accesses. } + /* ReleaseStream is required to finish multithreading */ void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) { + // Sleep(1); // for debug MtSync_StopWriting(&p->btSync); + // Sleep(200); // for debug /* p->MatchFinder->ReleaseStream(); */ } -static void MatchFinderMt_Normalize(CMatchFinderMt *p) -{ - MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); - p->lzPos = p->historySize + 1; -} -static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +Z7_NO_INLINE +static UInt32 MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) { - UInt32 blockIndex; - MtSync_GetNextBlock(&p->btSync); - blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask); - p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize; - p->btBufPosLimit += p->btBuf[p->btBufPos++]; - p->btNumAvailBytes = p->btBuf[p->btBufPos++]; - if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) - MatchFinderMt_Normalize(p); + if (p->failure_LZ_BT) + p->btBufPos = p->failureBuf; + else + { + const UInt32 bi = MtSync_GetNextBlock(&p->btSync); + const UInt32 *bt = p->btBuf + GET_BT_BLOCK_OFFSET(bi); + { + const UInt32 numItems = bt[0]; + p->btBufPosLimit = bt + numItems; + p->btNumAvailBytes = bt[1]; + p->btBufPos = bt + 2; + if (numItems < 2 || numItems > kMtBtBlockSize) + { + p->failureBuf[0] = 0; + p->btBufPos = p->failureBuf; + p->btBufPosLimit = p->failureBuf + 1; + p->failure_LZ_BT = True; + // p->btNumAvailBytes = 0; + /* we don't want to decrease AvailBytes, that was load before. + that can be unxepected for the code that have loaded anopther value before */ + } + } + + if (p->lzPos >= (UInt32)kMtMaxValForNormalize - (UInt32)kMtBtBlockSize) + { + /* we don't check (lzPos) over exact avail bytes in (btBuf). + (fixedHashSize) is small, so normalization is fast */ + const UInt32 subValue = (p->lzPos - p->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1); + p->lzPos -= subValue; + MatchFinder_Normalize3(subValue, p->hash, p->fixedHashSize); + } + } + return p->btNumAvailBytes; } + + static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) { return p->pointerToCurPos; } + #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); + static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) { - GET_NEXT_BLOCK_IF_REQUIRED; - return p->btNumAvailBytes; + if (p->btBufPos != p->btBufPosLimit) + return p->btNumAvailBytes; + return MatchFinderMt_GetNextBlock_Bt(p); } -static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) + +// #define CHECK_FAILURE_LZ(_match_, _pos_) if (_match_ >= _pos_) { p->failure_LZ_LZ = True; return d; } +#define CHECK_FAILURE_LZ(_match_, _pos_) + +static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) { - UInt32 h2, curMatch2; + UInt32 h2, c2; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; - UInt32 lzPos = p->lzPos; + const UInt32 m = p->lzPos; MT_HASH2_CALC - curMatch2 = hash[h2]; - hash[h2] = lzPos; + c2 = hash[h2]; + hash[h2] = m; - if (curMatch2 >= matchMinPos) - if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + if (c2 >= matchMinPos) + { + CHECK_FAILURE_LZ(c2, m) + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) { - *distances++ = 2; - *distances++ = lzPos - curMatch2 - 1; + *d++ = 2; + *d++ = m - c2 - 1; } + } - return distances; + return d; } -static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) { - UInt32 h2, h3, curMatch2, curMatch3; + UInt32 h2, h3, c2, c3; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; - UInt32 lzPos = p->lzPos; + const UInt32 m = p->lzPos; MT_HASH3_CALC - curMatch2 = hash[ h2]; - curMatch3 = (hash + kFix3HashSize)[h3]; + c2 = hash[h2]; + c3 = (hash + kFix3HashSize)[h3]; - hash[ h2] = lzPos; - (hash + kFix3HashSize)[h3] = lzPos; + hash[h2] = m; + (hash + kFix3HashSize)[h3] = m; - if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + if (c2 >= matchMinPos) { - distances[1] = lzPos - curMatch2 - 1; - if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + CHECK_FAILURE_LZ(c2, m) + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) { - distances[0] = 3; - return distances + 2; + d[1] = m - c2 - 1; + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) + { + d[0] = 3; + return d + 2; + } + d[0] = 2; + d += 2; } - distances[0] = 2; - distances += 2; } - if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + if (c3 >= matchMinPos) { - *distances++ = 3; - *distances++ = lzPos - curMatch3 - 1; + CHECK_FAILURE_LZ(c3, m) + if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) + { + *d++ = 3; + *d++ = m - c3 - 1; + } } - return distances; + return d; } + +#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; + /* -static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static +UInt32* MatchFinderMt_GetMatches_Bt4(CMatchFinderMt *p, UInt32 *d) { - UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4; + const UInt32 *bt = p->btBufPos; + const UInt32 len = *bt++; + const UInt32 *btLim = bt + len; + UInt32 matchMinPos; + UInt32 avail = p->btNumAvailBytes - 1; + p->btBufPos = btLim; + + { + p->btNumAvailBytes = avail; + + #define BT_HASH_BYTES_MAX 5 + + matchMinPos = p->lzPos; + + if (len != 0) + matchMinPos -= bt[1]; + else if (avail < (BT_HASH_BYTES_MAX - 1) - 1) + { + INCREASE_LZ_POS + return d; + } + else + { + const UInt32 hs = p->historySize; + if (matchMinPos > hs) + matchMinPos -= hs; + else + matchMinPos = 1; + } + } + + for (;;) + { + + UInt32 h2, h3, c2, c3; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; - UInt32 lzPos = p->lzPos; - MT_HASH4_CALC - - curMatch2 = hash[ h2]; - curMatch3 = (hash + kFix3HashSize)[h3]; - curMatch4 = (hash + kFix4HashSize)[h4]; + UInt32 m = p->lzPos; + MT_HASH3_CALC + + c2 = hash[h2]; + c3 = (hash + kFix3HashSize)[h3]; + + hash[h2] = m; + (hash + kFix3HashSize)[h3] = m; + + if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) + { + d[1] = m - c2 - 1; + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) + { + d[0] = 3; + d += 2; + break; + } + // else + { + d[0] = 2; + d += 2; + } + } + if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) + { + *d++ = 3; + *d++ = m - c3 - 1; + } + break; + } + + if (len != 0) + { + do + { + const UInt32 v0 = bt[0]; + const UInt32 v1 = bt[1]; + bt += 2; + d[0] = v0; + d[1] = v1; + d += 2; + } + while (bt != btLim); + } + INCREASE_LZ_POS + return d; +} +*/ + + +static UInt32 * MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) +{ + UInt32 h2, h3, /* h4, */ c2, c3 /* , c4 */; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + const UInt32 m = p->lzPos; + MT_HASH3_CALC + // MT_HASH4_CALC + c2 = hash[h2]; + c3 = (hash + kFix3HashSize)[h3]; + // c4 = (hash + kFix4HashSize)[h4]; - hash[ h2] = lzPos; - (hash + kFix3HashSize)[h3] = lzPos; - (hash + kFix4HashSize)[h4] = lzPos; + hash[h2] = m; + (hash + kFix3HashSize)[h3] = m; + // (hash + kFix4HashSize)[h4] = m; - if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + // #define BT5_USE_H2 + // #ifdef BT5_USE_H2 + if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) { - distances[1] = lzPos - curMatch2 - 1; - if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + d[1] = m - c2 - 1; + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) { - distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; - return distances + 2; + // d[0] = (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) ? 4 : 3; + // return d + 2; + + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) + { + d[0] = 4; + return d + 2; + } + d[0] = 3; + d += 2; + + #ifdef BT5_USE_H4 + if (c4 >= matchMinPos) + if ( + cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] && + cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3] + ) + { + *d++ = 4; + *d++ = m - c4 - 1; + } + #endif + return d; } - distances[0] = 2; - distances += 2; + d[0] = 2; + d += 2; } + // #endif - if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) { - distances[1] = lzPos - curMatch3 - 1; - if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3]) + d[1] = m - c3 - 1; + if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m + 3] == cur[3]) { - distances[0] = 4; - return distances + 2; + d[0] = 4; + return d + 2; } - distances[0] = 3; - distances += 2; + d[0] = 3; + d += 2; } - if (curMatch4 >= matchMinPos) + #ifdef BT5_USE_H4 + if (c4 >= matchMinPos) if ( - cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] && - cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3] + cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] && + cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3] ) { - *distances++ = 4; - *distances++ = lzPos - curMatch4 - 1; + *d++ = 4; + *d++ = m - c4 - 1; } + #endif - return distances; + return d; } -*/ -#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; -static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) +static UInt32 * MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *d) { - const UInt32 *btBuf = p->btBuf + p->btBufPos; - UInt32 len = *btBuf++; - p->btBufPos += 1 + len; + const UInt32 *bt = p->btBufPos; + const UInt32 len = *bt++; + const UInt32 *btLim = bt + len; + p->btBufPos = btLim; p->btNumAvailBytes--; + INCREASE_LZ_POS { - UInt32 i; - for (i = 0; i < len; i += 2) + while (bt != btLim) { - UInt32 v0 = btBuf[0]; - UInt32 v1 = btBuf[1]; - btBuf += 2; - distances[0] = v0; - distances[1] = v1; - distances += 2; + const UInt32 v0 = bt[0]; + const UInt32 v1 = bt[1]; + bt += 2; + d[0] = v0; + d[1] = v1; + d += 2; } } - INCREASE_LZ_POS - return len; + return d; } -static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) -{ - const UInt32 *btBuf = p->btBuf + p->btBufPos; - UInt32 len = *btBuf++; - p->btBufPos += 1 + len; + +static UInt32 * MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *d) +{ + const UInt32 *bt = p->btBufPos; + UInt32 len = *bt++; + const UInt32 avail = p->btNumAvailBytes - 1; + p->btNumAvailBytes = avail; + p->btBufPos = bt + len; if (len == 0) { - /* change for bt5 ! */ - if (p->btNumAvailBytes-- >= 4) - len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); + #define BT_HASH_BYTES_MAX 5 + if (avail >= (BT_HASH_BYTES_MAX - 1) - 1) + { + UInt32 m = p->lzPos; + if (m > p->historySize) + m -= p->historySize; + else + m = 1; + d = p->MixMatchesFunc(p, m, d); + } } else { - /* Condition: there are matches in btBuf with length < p->numHashBytes */ - UInt32 *distances2; - p->btNumAvailBytes--; - distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances); + /* + first match pair from BinTree: (match_len, match_dist), + (match_len >= numHashBytes). + MixMatchesFunc() inserts only hash matches that are nearer than (match_dist) + */ + d = p->MixMatchesFunc(p, p->lzPos - bt[1], d); + // if (d) // check for failure do { - UInt32 v0 = btBuf[0]; - UInt32 v1 = btBuf[1]; - btBuf += 2; - distances2[0] = v0; - distances2[1] = v1; - distances2 += 2; + const UInt32 v0 = bt[0]; + const UInt32 v1 = bt[1]; + bt += 2; + d[0] = v0; + d[1] = v1; + d += 2; } - while ((len -= 2) != 0); - len = (UInt32)(distances2 - (distances)); + while (len -= 2); } INCREASE_LZ_POS - return len; + return d; } #define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED #define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; -#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); +#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += (size_t)*p->btBufPos + 1; } while (--num != 0); static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) { @@ -803,12 +1342,16 @@ static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) } /* +// MatchFinderMt4_Skip() is similar to MatchFinderMt3_Skip(). +// The difference is that MatchFinderMt3_Skip() updates hash for last 3 bytes of stream. + static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(4) - UInt32 h2, h3, h4; - MT_HASH4_CALC - (hash + kFix4HashSize)[h4] = + UInt32 h2, h3; // h4 + MT_HASH3_CALC + // MT_HASH4_CALC + // (hash + kFix4HashSize)[h4] = (hash + kFix3HashSize)[h3] = hash[ h2] = p->lzPos; @@ -816,14 +1359,14 @@ static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) } */ -void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable) { vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; - switch (p->MatchFinder->numHashBytes) + switch (MF(p)->numHashBytes) { case 2: p->GetHeadsFunc = GetHeads2; @@ -832,22 +1375,32 @@ void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches; break; case 3: - p->GetHeadsFunc = GetHeads3; + p->GetHeadsFunc = MF(p)->bigHash ? GetHeads3b : GetHeads3; p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2; vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip; break; - default: - /* case 4: */ - p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; + case 4: + p->GetHeadsFunc = MF(p)->bigHash ? GetHeads4b : GetHeads4; + + // it's fast inline version of GetMatches() + // vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches_Bt4; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; break; - /* default: - p->GetHeadsFunc = GetHeads5; + p->GetHeadsFunc = MF(p)->bigHash ? GetHeads5b : GetHeads5; p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4; - vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip; + vTable->Skip = + (Mf_Skip_Func)MatchFinderMt3_Skip; + // (Mf_Skip_Func)MatchFinderMt4_Skip; break; - */ } } + +#undef RINOK_THREAD +#undef PRF +#undef MF +#undef GetUi24hi_from32 +#undef LOCK_BUFFER +#undef UNLOCK_BUFFER diff --git a/libraries/lzma/C/LzFindMt.h b/libraries/lzma/C/LzFindMt.h index ef431e3f552..db5923ea05b 100644 --- a/libraries/lzma/C/LzFindMt.h +++ b/libraries/lzma/C/LzFindMt.h @@ -1,39 +1,34 @@ /* LzFindMt.h -- multithreaded Match finder for LZ algorithms -2018-07-04 : Igor Pavlov : Public domain */ +2023-03-05 : Igor Pavlov : Public domain */ -#ifndef __LZ_FIND_MT_H -#define __LZ_FIND_MT_H +#ifndef ZIP7_INC_LZ_FIND_MT_H +#define ZIP7_INC_LZ_FIND_MT_H #include "LzFind.h" #include "Threads.h" EXTERN_C_BEGIN -#define kMtHashBlockSize (1 << 13) -#define kMtHashNumBlocks (1 << 3) -#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1) - -#define kMtBtBlockSize (1 << 14) -#define kMtBtNumBlocks (1 << 6) -#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1) - -typedef struct _CMtSync +typedef struct { + UInt32 numProcessedBlocks; + CThread thread; + UInt64 affinity; + BoolInt wasCreated; BoolInt needStart; + BoolInt csWasInitialized; + BoolInt csWasEntered; + BoolInt exit; BoolInt stopWriting; - CThread thread; CAutoResetEvent canStart; - CAutoResetEvent wasStarted; CAutoResetEvent wasStopped; CSemaphore freeSemaphore; CSemaphore filledSemaphore; - BoolInt csWasInitialized; - BoolInt csWasEntered; CCriticalSection cs; - UInt32 numProcessedBlocks; + // UInt32 numBlocks_Sent; } CMtSync; typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances); @@ -44,23 +39,28 @@ typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distance typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); -typedef struct _CMatchFinderMt +typedef struct { /* LZ */ const Byte *pointerToCurPos; UInt32 *btBuf; - UInt32 btBufPos; - UInt32 btBufPosLimit; + const UInt32 *btBufPos; + const UInt32 *btBufPosLimit; UInt32 lzPos; UInt32 btNumAvailBytes; UInt32 *hash; UInt32 fixedHashSize; + // UInt32 hash4Mask; UInt32 historySize; const UInt32 *crc; Mf_Mix_Matches MixMatchesFunc; - + UInt32 failure_LZ_BT; // failure in BT transfered to LZ + // UInt32 failure_LZ_LZ; // failure in LZ tables + UInt32 failureBuf[1]; + // UInt32 crc[256]; + /* LZ + BT */ CMtSync btSync; Byte btDummy[kMtCacheLineDummy]; @@ -70,6 +70,8 @@ typedef struct _CMatchFinderMt UInt32 hashBufPos; UInt32 hashBufPosLimit; UInt32 hashNumAvail; + UInt32 failure_BT; + CLzRef *son; UInt32 matchMaxLen; @@ -77,7 +79,7 @@ typedef struct _CMatchFinderMt UInt32 pos; const Byte *buffer; UInt32 cyclicBufferPos; - UInt32 cyclicBufferSize; /* it must be historySize + 1 */ + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ UInt32 cutValue; /* BT + Hash */ @@ -87,13 +89,19 @@ typedef struct _CMatchFinderMt /* Hash */ Mf_GetHeads GetHeadsFunc; CMatchFinder *MatchFinder; + // CMatchFinder MatchFinder; } CMatchFinderMt; +// only for Mt part void MatchFinderMt_Construct(CMatchFinderMt *p); void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc); + SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc); -void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable); + +/* call MatchFinderMt_InitMt() before IMatchFinder::Init() */ +SRes MatchFinderMt_InitMt(CMatchFinderMt *p); void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); EXTERN_C_END diff --git a/libraries/lzma/C/LzFindOpt.c b/libraries/lzma/C/LzFindOpt.c new file mode 100644 index 00000000000..85bdc136d67 --- /dev/null +++ b/libraries/lzma/C/LzFindOpt.c @@ -0,0 +1,578 @@ +/* LzFindOpt.c -- multithreaded Match finder for LZ algorithms +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" +#include "LzFind.h" + +// #include "LzFindMt.h" + +// #define LOG_ITERS + +// #define LOG_THREAD + +#ifdef LOG_THREAD +#include +#define PRF(x) x +#else +// #define PRF(x) +#endif + +#ifdef LOG_ITERS +#include +UInt64 g_NumIters_Tree; +UInt64 g_NumIters_Loop; +UInt64 g_NumIters_Bytes; +#define LOG_ITER(x) x +#else +#define LOG_ITER(x) +#endif + +// ---------- BT THREAD ---------- + +#define USE_SON_PREFETCH +#define USE_LONG_MATCH_OPT + +#define kEmptyHashValue 0 + +// #define CYC_TO_POS_OFFSET 0 + +// #define CYC_TO_POS_OFFSET 1 // for debug + +/* +Z7_NO_INLINE +UInt32 * Z7_FASTCALL GetMatchesSpecN_1(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, UInt32 *posRes) +{ + do + { + UInt32 delta; + if (hash == size) + break; + delta = *hash++; + + if (delta == 0 || delta > (UInt32)pos) + return NULL; + + lenLimit++; + + if (delta == (UInt32)pos) + { + CLzRef *ptr1 = son + ((size_t)pos << 1) - CYC_TO_POS_OFFSET * 2; + *d++ = 0; + ptr1[0] = kEmptyHashValue; + ptr1[1] = kEmptyHashValue; + } +else +{ + UInt32 *_distances = ++d; + + CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1; + CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; + + const Byte *len0 = cur, *len1 = cur; + UInt32 cutValue = _cutValue; + const Byte *maxLen = cur + _maxLen; + + for (LOG_ITER(g_NumIters_Tree++);;) + { + LOG_ITER(g_NumIters_Loop++); + { + const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + CLzRef *pair = son + ((size_t)(((ptrdiff_t)pos - CYC_TO_POS_OFFSET) + diff) << 1); + const Byte *len = (len0 < len1 ? len0 : len1); + + #ifdef USE_SON_PREFETCH + const UInt32 pair0 = *pair; + #endif + + if (len[diff] == len[0]) + { + if (++len != lenLimit && len[diff] == len[0]) + while (++len != lenLimit) + { + LOG_ITER(g_NumIters_Bytes++); + if (len[diff] != len[0]) + break; + } + if (maxLen < len) + { + maxLen = len; + *d++ = (UInt32)(len - cur); + *d++ = delta - 1; + + if (len == lenLimit) + { + const UInt32 pair1 = pair[1]; + *ptr1 = + #ifdef USE_SON_PREFETCH + pair0; + #else + pair[0]; + #endif + *ptr0 = pair1; + + _distances[-1] = (UInt32)(d - _distances); + + #ifdef USE_LONG_MATCH_OPT + + if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + break; + + { + for (;;) + { + hash++; + pos++; + cur++; + lenLimit++; + { + CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; + #if 0 + *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff]; + #else + const UInt32 p0 = ptr[0 + (diff * 2)]; + const UInt32 p1 = ptr[1 + (diff * 2)]; + ptr[0] = p0; + ptr[1] = p1; + // ptr[0] = ptr[0 + (diff * 2)]; + // ptr[1] = ptr[1 + (diff * 2)]; + #endif + } + // PrintSon(son + 2, pos - 1); + // printf("\npos = %x delta = %x\n", pos, delta); + len++; + *d++ = 2; + *d++ = (UInt32)(len - cur); + *d++ = delta - 1; + if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + break; + } + } + #endif + + break; + } + } + } + + { + const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff); + if (len[diff] < len[0]) + { + delta = pair[1]; + if (delta >= curMatch) + return NULL; + *ptr1 = curMatch; + ptr1 = pair + 1; + len1 = len; + } + else + { + delta = *pair; + if (delta >= curMatch) + return NULL; + *ptr0 = curMatch; + ptr0 = pair; + len0 = len; + } + + delta = (UInt32)pos - delta; + + if (--cutValue == 0 || delta >= pos) + { + *ptr0 = *ptr1 = kEmptyHashValue; + _distances[-1] = (UInt32)(d - _distances); + break; + } + } + } + } // for (tree iterations) +} + pos++; + cur++; + } + while (d < limit); + *posRes = (UInt32)pos; + return d; +} +*/ + +/* define cbs if you use 2 functions. + GetMatchesSpecN_1() : (pos < _cyclicBufferSize) + GetMatchesSpecN_2() : (pos >= _cyclicBufferSize) + + do not define cbs if you use 1 function: + GetMatchesSpecN_2() +*/ + +// #define cbs _cyclicBufferSize + +/* + we use size_t for (pos) and (_cyclicBufferPos_ instead of UInt32 + to eliminate "movsx" BUG in old MSVC x64 compiler. +*/ + +UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, + UInt32 *posRes); + +Z7_NO_INLINE +UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, + UInt32 *posRes) +{ + do // while (hash != size) + { + UInt32 delta; + + #ifndef cbs + UInt32 cbs; + #endif + + if (hash == size) + break; + + delta = *hash++; + + if (delta == 0) + return NULL; + + lenLimit++; + + #ifndef cbs + cbs = _cyclicBufferSize; + if ((UInt32)pos < cbs) + { + if (delta > (UInt32)pos) + return NULL; + cbs = (UInt32)pos; + } + #endif + + if (delta >= cbs) + { + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + *d++ = 0; + ptr1[0] = kEmptyHashValue; + ptr1[1] = kEmptyHashValue; + } +else +{ + UInt32 *_distances = ++d; + + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + + UInt32 cutValue = _cutValue; + const Byte *len0 = cur, *len1 = cur; + const Byte *maxLen = cur + _maxLen; + + // if (cutValue == 0) { *ptr0 = *ptr1 = kEmptyHashValue; } else + for (LOG_ITER(g_NumIters_Tree++);;) + { + LOG_ITER(g_NumIters_Loop++); + { + // SPEC code + CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - (ptrdiff_t)delta + + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0) + ) << 1); + + const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + const Byte *len = (len0 < len1 ? len0 : len1); + + #ifdef USE_SON_PREFETCH + const UInt32 pair0 = *pair; + #endif + + if (len[diff] == len[0]) + { + if (++len != lenLimit && len[diff] == len[0]) + while (++len != lenLimit) + { + LOG_ITER(g_NumIters_Bytes++); + if (len[diff] != len[0]) + break; + } + if (maxLen < len) + { + maxLen = len; + *d++ = (UInt32)(len - cur); + *d++ = delta - 1; + + if (len == lenLimit) + { + const UInt32 pair1 = pair[1]; + *ptr1 = + #ifdef USE_SON_PREFETCH + pair0; + #else + pair[0]; + #endif + *ptr0 = pair1; + + _distances[-1] = (UInt32)(d - _distances); + + #ifdef USE_LONG_MATCH_OPT + + if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + break; + + { + for (;;) + { + *d++ = 2; + *d++ = (UInt32)(lenLimit - cur); + *d++ = delta - 1; + cur++; + lenLimit++; + // SPEC + _cyclicBufferPos++; + { + // SPEC code + CLzRef *dest = son + ((size_t)(_cyclicBufferPos) << 1); + const CLzRef *src = dest + ((diff + + (ptrdiff_t)(UInt32)((_cyclicBufferPos < delta) ? cbs : 0)) << 1); + // CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; + #if 0 + *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src); + #else + const UInt32 p0 = src[0]; + const UInt32 p1 = src[1]; + dest[0] = p0; + dest[1] = p1; + #endif + } + pos++; + hash++; + if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + break; + } // for() end for long matches + } + #endif + + break; // break from TREE iterations + } + } + } + { + const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff); + if (len[diff] < len[0]) + { + delta = pair[1]; + *ptr1 = curMatch; + ptr1 = pair + 1; + len1 = len; + if (delta >= curMatch) + return NULL; + } + else + { + delta = *pair; + *ptr0 = curMatch; + ptr0 = pair; + len0 = len; + if (delta >= curMatch) + return NULL; + } + delta = (UInt32)pos - delta; + + if (--cutValue == 0 || delta >= cbs) + { + *ptr0 = *ptr1 = kEmptyHashValue; + _distances[-1] = (UInt32)(d - _distances); + break; + } + } + } + } // for (tree iterations) +} + pos++; + _cyclicBufferPos++; + cur++; + } + while (d < limit); + *posRes = (UInt32)pos; + return d; +} + + + +/* +typedef UInt32 uint32plus; // size_t + +UInt32 * Z7_FASTCALL GetMatchesSpecN_3(uint32plus lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, uint32plus _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, + UInt32 *posRes) +{ + do // while (hash != size) + { + UInt32 delta; + + #ifndef cbs + UInt32 cbs; + #endif + + if (hash == size) + break; + + delta = *hash++; + + if (delta == 0) + return NULL; + + #ifndef cbs + cbs = _cyclicBufferSize; + if ((UInt32)pos < cbs) + { + if (delta > (UInt32)pos) + return NULL; + cbs = (UInt32)pos; + } + #endif + + if (delta >= cbs) + { + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + *d++ = 0; + ptr1[0] = kEmptyHashValue; + ptr1[1] = kEmptyHashValue; + } +else +{ + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + UInt32 *_distances = ++d; + uint32plus len0 = 0, len1 = 0; + UInt32 cutValue = _cutValue; + uint32plus maxLen = _maxLen; + // lenLimit++; // const Byte *lenLimit = cur + _lenLimit; + + for (LOG_ITER(g_NumIters_Tree++);;) + { + LOG_ITER(g_NumIters_Loop++); + { + // const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - delta + + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0) + ) << 1); + const Byte *pb = cur - delta; + uint32plus len = (len0 < len1 ? len0 : len1); + + #ifdef USE_SON_PREFETCH + const UInt32 pair0 = *pair; + #endif + + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = len; + *d++ = (UInt32)len; + *d++ = delta - 1; + if (len == lenLimit) + { + { + const UInt32 pair1 = pair[1]; + *ptr0 = pair1; + *ptr1 = + #ifdef USE_SON_PREFETCH + pair0; + #else + pair[0]; + #endif + } + + _distances[-1] = (UInt32)(d - _distances); + + #ifdef USE_LONG_MATCH_OPT + + if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit) + break; + + { + const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + for (;;) + { + *d++ = 2; + *d++ = (UInt32)lenLimit; + *d++ = delta - 1; + _cyclicBufferPos++; + { + CLzRef *dest = son + ((size_t)_cyclicBufferPos << 1); + const CLzRef *src = dest + ((diff + + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)) << 1); + #if 0 + *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src); + #else + const UInt32 p0 = src[0]; + const UInt32 p1 = src[1]; + dest[0] = p0; + dest[1] = p1; + #endif + } + hash++; + pos++; + cur++; + pb++; + if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit) + break; + } + } + #endif + + break; + } + } + } + { + const UInt32 curMatch = (UInt32)pos - delta; + if (pb[len] < cur[len]) + { + delta = pair[1]; + *ptr1 = curMatch; + ptr1 = pair + 1; + len1 = len; + } + else + { + delta = *pair; + *ptr0 = curMatch; + ptr0 = pair; + len0 = len; + } + + { + if (delta >= curMatch) + return NULL; + delta = (UInt32)pos - delta; + if (delta >= cbs + // delta >= _cyclicBufferSize || delta >= pos + || --cutValue == 0) + { + *ptr0 = *ptr1 = kEmptyHashValue; + _distances[-1] = (UInt32)(d - _distances); + break; + } + } + } + } + } // for (tree iterations) +} + pos++; + _cyclicBufferPos++; + cur++; + } + while (d < limit); + *posRes = (UInt32)pos; + return d; +} +*/ diff --git a/libraries/lzma/C/LzHash.h b/libraries/lzma/C/LzHash.h index e7c942303dd..2b6290b64c0 100644 --- a/libraries/lzma/C/LzHash.h +++ b/libraries/lzma/C/LzHash.h @@ -1,57 +1,34 @@ -/* LzHash.h -- HASH functions for LZ algorithms -2015-04-12 : Igor Pavlov : Public domain */ +/* LzHash.h -- HASH constants for LZ algorithms +2023-03-05 : Igor Pavlov : Public domain */ -#ifndef __LZ_HASH_H -#define __LZ_HASH_H +#ifndef ZIP7_INC_LZ_HASH_H +#define ZIP7_INC_LZ_HASH_H + +/* + (kHash2Size >= (1 << 8)) : Required + (kHash3Size >= (1 << 16)) : Required +*/ #define kHash2Size (1 << 10) #define kHash3Size (1 << 16) -#define kHash4Size (1 << 20) +// #define kHash4Size (1 << 20) #define kFix3HashSize (kHash2Size) #define kFix4HashSize (kHash2Size + kHash3Size) -#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) - -#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8); - -#define HASH3_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } - -#define HASH4_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - temp ^= ((UInt32)cur[2] << 8); \ - h3 = temp & (kHash3Size - 1); \ - hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; } - -#define HASH5_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - temp ^= ((UInt32)cur[2] << 8); \ - h3 = temp & (kHash3Size - 1); \ - temp ^= (p->crc[cur[3]] << 5); \ - h4 = temp & (kHash4Size - 1); \ - hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; } - -/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ -#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; - - -#define MT_HASH2_CALC \ - h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); - -#define MT_HASH3_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } - -#define MT_HASH4_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - temp ^= ((UInt32)cur[2] << 8); \ - h3 = temp & (kHash3Size - 1); \ - h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } +// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) + +/* + We use up to 3 crc values for hash: + crc0 + crc1 << Shift_1 + crc2 << Shift_2 + (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff. + Small values for Shift are not good for collision rate. + Big value for Shift_2 increases the minimum size + of hash table, that will be slow for small files. +*/ + +#define kLzHash_CrcShift_1 5 +#define kLzHash_CrcShift_2 10 #endif diff --git a/libraries/lzma/C/Lzma2Dec.c b/libraries/lzma/C/Lzma2Dec.c index 4e138a4aef5..388cbc71732 100644 --- a/libraries/lzma/C/Lzma2Dec.c +++ b/libraries/lzma/C/Lzma2Dec.c @@ -1,5 +1,5 @@ /* Lzma2Dec.c -- LZMA2 Decoder -2019-02-02 : Igor Pavlov : Public domain */ +2023-03-03 : Igor Pavlov : Public domain */ /* #define SHOW_DEBUG_INFO */ @@ -71,14 +71,14 @@ static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) { Byte props[LZMA_PROPS_SIZE]; - RINOK(Lzma2Dec_GetOldProps(prop, props)); + RINOK(Lzma2Dec_GetOldProps(prop, props)) return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); } SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) { Byte props[LZMA_PROPS_SIZE]; - RINOK(Lzma2Dec_GetOldProps(prop, props)); + RINOK(Lzma2Dec_GetOldProps(prop, props)) return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); } @@ -93,7 +93,8 @@ void Lzma2Dec_Init(CLzma2Dec *p) LzmaDec_Init(&p->decoder); } -static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) +// ELzma2State +static unsigned Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) { switch (p->state) { @@ -473,8 +474,8 @@ SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, SizeT outSize = *destLen, inSize = *srcLen; *destLen = *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; - Lzma2Dec_Construct(&p); - RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); + Lzma2Dec_CONSTRUCT(&p) + RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)) p.decoder.dic = dest; p.decoder.dicBufSize = outSize; Lzma2Dec_Init(&p); @@ -486,3 +487,5 @@ SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, Lzma2Dec_FreeProbs(&p, alloc); return res; } + +#undef PRF diff --git a/libraries/lzma/C/Lzma2Dec.h b/libraries/lzma/C/Lzma2Dec.h index b8ddeac890b..1f5233a728a 100644 --- a/libraries/lzma/C/Lzma2Dec.h +++ b/libraries/lzma/C/Lzma2Dec.h @@ -1,8 +1,8 @@ /* Lzma2Dec.h -- LZMA2 Decoder -2018-02-19 : Igor Pavlov : Public domain */ +2023-03-03 : Igor Pavlov : Public domain */ -#ifndef __LZMA2_DEC_H -#define __LZMA2_DEC_H +#ifndef ZIP7_INC_LZMA2_DEC_H +#define ZIP7_INC_LZMA2_DEC_H #include "LzmaDec.h" @@ -22,9 +22,10 @@ typedef struct CLzmaDec decoder; } CLzma2Dec; -#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) -#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc) -#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc) +#define Lzma2Dec_CONSTRUCT(p) LzmaDec_CONSTRUCT(&(p)->decoder) +#define Lzma2Dec_Construct(p) Lzma2Dec_CONSTRUCT(p) +#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc) +#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc) SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); @@ -90,7 +91,7 @@ Lzma2Dec_GetUnpackExtra() returns the value that shows at current input positon. */ -#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0); +#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0) /* ---------- One Call Interface ---------- */ diff --git a/libraries/lzma/C/Lzma2DecMt.c b/libraries/lzma/C/Lzma2DecMt.c new file mode 100644 index 00000000000..4bc4ddeb5c4 --- /dev/null +++ b/libraries/lzma/C/Lzma2DecMt.c @@ -0,0 +1,1095 @@ +/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread +2023-04-13 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO +// #define Z7_ST + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "Alloc.h" + +#include "Lzma2Dec.h" +#include "Lzma2DecMt.h" + +#ifndef Z7_ST +#include "MtDec.h" + +#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28) +#endif + + +#ifndef Z7_ST +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif +#define PRF_STR(s) PRF(printf("\n" s "\n");) +#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2);) +#endif + + +void Lzma2DecMtProps_Init(CLzma2DecMtProps *p) +{ + p->inBufSize_ST = 1 << 20; + p->outStep_ST = 1 << 20; + + #ifndef Z7_ST + p->numThreads = 1; + p->inBufSize_MT = 1 << 18; + p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT; + p->inBlockMax = p->outBlockMax + p->outBlockMax / 16; + #endif +} + + + +#ifndef Z7_ST + +/* ---------- CLzma2DecMtThread ---------- */ + +typedef struct +{ + CLzma2Dec dec; + Byte dec_created; + Byte needInit; + + Byte *outBuf; + size_t outBufSize; + + EMtDecParseState state; + ELzma2ParseStatus parseStatus; + + size_t inPreSize; + size_t outPreSize; + + size_t inCodeSize; + size_t outCodeSize; + SRes codeRes; + + CAlignOffsetAlloc alloc; + + Byte mtPad[1 << 7]; +} CLzma2DecMtThread; + +#endif + + +/* ---------- CLzma2DecMt ---------- */ + +struct CLzma2DecMt +{ + // ISzAllocPtr alloc; + ISzAllocPtr allocMid; + + CAlignOffsetAlloc alignOffsetAlloc; + CLzma2DecMtProps props; + Byte prop; + + ISeqInStreamPtr inStream; + ISeqOutStreamPtr outStream; + ICompressProgressPtr progress; + + BoolInt finishMode; + BoolInt outSize_Defined; + UInt64 outSize; + + UInt64 outProcessed; + UInt64 inProcessed; + BoolInt readWasFinished; + SRes readRes; + + Byte *inBuf; + size_t inBufSize; + Byte dec_created; + CLzma2Dec dec; + + size_t inPos; + size_t inLim; + + #ifndef Z7_ST + UInt64 outProcessed_Parse; + BoolInt mtc_WasConstructed; + CMtDec mtc; + CLzma2DecMtThread coders[MTDEC_THREADS_MAX]; + #endif +}; + + + +CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) +{ + CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt)); + if (!p) + return NULL; + + // p->alloc = alloc; + p->allocMid = allocMid; + + AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); + p->alignOffsetAlloc.numAlignBits = 7; + p->alignOffsetAlloc.offset = 0; + p->alignOffsetAlloc.baseAlloc = alloc; + + p->inBuf = NULL; + p->inBufSize = 0; + p->dec_created = False; + + // Lzma2DecMtProps_Init(&p->props); + + #ifndef Z7_ST + p->mtc_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + t->dec_created = False; + t->outBuf = NULL; + t->outBufSize = 0; + } + } + #endif + + return (CLzma2DecMtHandle)(void *)p; +} + + +#ifndef Z7_ST + +static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p) +{ + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + if (t->outBuf) + { + ISzAlloc_Free(p->allocMid, t->outBuf); + t->outBuf = NULL; + t->outBufSize = 0; + } + } +} + +#endif + + +static void Lzma2DecMt_FreeSt(CLzma2DecMt *p) +{ + if (p->dec_created) + { + Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt); + p->dec_created = False; + } + if (p->inBuf) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBuf = NULL; + } + p->inBufSize = 0; +} + + +// #define GET_CLzma2DecMt_p CLzma2DecMt *p = (CLzma2DecMt *)(void *)pp; + +void Lzma2DecMt_Destroy(CLzma2DecMtHandle p) +{ + // GET_CLzma2DecMt_p + + Lzma2DecMt_FreeSt(p); + + #ifndef Z7_ST + + if (p->mtc_WasConstructed) + { + MtDec_Destruct(&p->mtc); + p->mtc_WasConstructed = False; + } + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + if (t->dec_created) + { + // we don't need to free dict here + Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!! + t->dec_created = False; + } + } + } + Lzma2DecMt_FreeOutBufs(p); + + #endif + + ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, p); +} + + + +#ifndef Z7_ST + +static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) +{ + CLzma2DecMt *me = (CLzma2DecMt *)obj; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + + PRF_STR_INT_2("Parse", coderIndex, cc->srcSize) + + cc->state = MTDEC_PARSE_CONTINUE; + + if (cc->startCall) + { + if (!t->dec_created) + { + Lzma2Dec_CONSTRUCT(&t->dec) + t->dec_created = True; + AlignOffsetAlloc_CreateVTable(&t->alloc); + { + /* (1 << 12) is expected size of one way in data cache. + We optimize alignment for cache line size of 128 bytes and smaller */ + const unsigned kNumAlignBits = 12; + const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */ + t->alloc.numAlignBits = kNumAlignBits; + t->alloc.offset = ((UInt32)coderIndex * (((unsigned)1 << 11) + (1 << 8) + (1 << 6))) & (((unsigned)1 << kNumAlignBits) - ((unsigned)1 << kNumCacheLineBits)); + t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc; + } + } + Lzma2Dec_Init(&t->dec); + + t->inPreSize = 0; + t->outPreSize = 0; + // t->blockWasFinished = False; + // t->finishedWithMark = False; + t->parseStatus = (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; + t->state = MTDEC_PARSE_CONTINUE; + + t->inCodeSize = 0; + t->outCodeSize = 0; + t->codeRes = SZ_OK; + + // (cc->srcSize == 0) is allowed + } + + { + ELzma2ParseStatus status; + BoolInt overflow; + UInt32 unpackRem = 0; + + int checkFinishBlock = True; + size_t limit = me->props.outBlockMax; + if (me->outSize_Defined) + { + UInt64 rem = me->outSize - me->outProcessed_Parse; + if (limit >= rem) + { + limit = (size_t)rem; + if (!me->finishMode) + checkFinishBlock = False; + } + } + + // checkFinishBlock = False, if we want to decode partial data + // that must be finished at position <= outBlockMax. + + { + const size_t srcOrig = cc->srcSize; + SizeT srcSize_Point = 0; + SizeT dicPos_Point = 0; + + cc->srcSize = 0; + overflow = False; + + for (;;) + { + SizeT srcCur = (SizeT)(srcOrig - cc->srcSize); + + status = Lzma2Dec_Parse(&t->dec, + (SizeT)limit - t->dec.decoder.dicPos, + cc->src + cc->srcSize, &srcCur, + checkFinishBlock); + + cc->srcSize += srcCur; + + if (status == LZMA2_PARSE_STATUS_NEW_CHUNK) + { + if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos) + { + overflow = True; + break; + } + continue; + } + + if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) + { + if (t->dec.decoder.dicPos == 0) + continue; + // we decode small blocks in one thread + if (t->dec.decoder.dicPos >= (1 << 14)) + break; + dicPos_Point = t->dec.decoder.dicPos; + srcSize_Point = (SizeT)cc->srcSize; + continue; + } + + if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock + // && limit == t->dec.decoder.dicPos + // && limit == me->props.outBlockMax + ) + { + overflow = True; + break; + } + + unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec); + break; + } + + if (dicPos_Point != 0 + && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK + && (int)status != LZMA_STATUS_FINISHED_WITH_MARK + && (int)status != LZMA_STATUS_NOT_SPECIFIED) + { + // we revert to latest newBlock state + status = LZMA2_PARSE_STATUS_NEW_BLOCK; + unpackRem = 0; + t->dec.decoder.dicPos = dicPos_Point; + cc->srcSize = srcSize_Point; + overflow = False; + } + } + + t->inPreSize += cc->srcSize; + t->parseStatus = status; + + if (overflow) + cc->state = MTDEC_PARSE_OVERFLOW; + else + { + size_t dicPos = t->dec.decoder.dicPos; + + if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) + { + cc->state = MTDEC_PARSE_NEW; + cc->srcSize--; // we don't need control byte of next block + t->inPreSize--; + } + else + { + cc->state = MTDEC_PARSE_END; + if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK) + { + // (status == LZMA_STATUS_NOT_SPECIFIED) + // (status == LZMA_STATUS_NOT_FINISHED) + if (unpackRem != 0) + { + /* we also reserve space for max possible number of output bytes of current LZMA chunk */ + size_t rem = limit - dicPos; + if (rem > unpackRem) + rem = unpackRem; + dicPos += rem; + } + } + } + + me->outProcessed_Parse += dicPos; + } + + cc->outPos = dicPos; + t->outPreSize = (size_t)dicPos; + } + + t->state = cc->state; + return; + } +} + + +static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + Byte *dest = t->outBuf; + + if (t->inPreSize == 0) + { + t->codeRes = SZ_ERROR_DATA; + return t->codeRes; + } + + if (!dest || t->outBufSize < t->outPreSize) + { + if (dest) + { + ISzAlloc_Free(me->allocMid, dest); + t->outBuf = NULL; + t->outBufSize = 0; + } + + dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize + // + (1 << 28) + ); + // Sleep(200); + if (!dest) + return SZ_ERROR_MEM; + t->outBuf = dest; + t->outBufSize = t->outPreSize; + } + + t->dec.decoder.dic = dest; + t->dec.decoder.dicBufSize = (SizeT)t->outPreSize; + + t->needInit = True; + + return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt +} + + +static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + // int finished, int blockFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + + UNUSED_VAR(srcFinished) + + PRF_STR_INT_2("Code", coderIndex, srcSize) + + *inCodePos = t->inCodeSize; + *outCodePos = 0; + *stop = True; + + if (t->needInit) + { + Lzma2Dec_Init(&t->dec); + t->needInit = False; + } + + { + ELzmaStatus status; + SizeT srcProcessed = (SizeT)srcSize; + BoolInt blockWasFinished = + ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK); + + SRes res = Lzma2Dec_DecodeToDic(&t->dec, + (SizeT)t->outPreSize, + src, &srcProcessed, + blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY, + &status); + + t->codeRes = res; + + t->inCodeSize += srcProcessed; + *inCodePos = t->inCodeSize; + t->outCodeSize = t->dec.decoder.dicPos; + *outCodePos = t->dec.decoder.dicPos; + + if (res != SZ_OK) + return res; + + if (srcProcessed == srcSize) + *stop = False; + + if (blockWasFinished) + { + if (srcSize != srcProcessed) + return SZ_ERROR_FAIL; + + if (t->inPreSize == t->inCodeSize) + { + if (t->outPreSize != t->outCodeSize) + return SZ_ERROR_FAIL; + *stop = True; + } + } + else + { + if (t->outPreSize == t->outCodeSize) + *stop = True; + } + + return SZ_OK; + } +} + + +#define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24) + +static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, BoolInt isCross, + BoolInt *needContinue, BoolInt *canRecode) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + const CLzma2DecMtThread *t = &me->coders[coderIndex]; + size_t size = t->outCodeSize; + const Byte *data = t->outBuf; + BoolInt needContinue2 = True; + + UNUSED_VAR(src) + UNUSED_VAR(srcSize) + UNUSED_VAR(isCross) + + PRF_STR_INT_2("Write", coderIndex, srcSize) + + *needContinue = False; + *canRecode = True; + + if ( + // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + t->state == MTDEC_PARSE_OVERFLOW + || t->state == MTDEC_PARSE_END) + needContinue2 = False; + + + if (!needWriteToStream) + return SZ_OK; + + me->mtc.inProcessed += t->inCodeSize; + + if (t->codeRes == SZ_OK) + if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK) + if (t->outPreSize != t->outCodeSize + || t->inPreSize != t->inCodeSize) + return SZ_ERROR_FAIL; + + *canRecode = False; + + if (me->outStream) + { + for (;;) + { + size_t cur = size; + size_t written; + if (cur > LZMA2DECMT_STREAM_WRITE_STEP) + cur = LZMA2DECMT_STREAM_WRITE_STEP; + + written = ISeqOutStream_Write(me->outStream, data, cur); + + me->outProcessed += written; + // me->mtc.writtenTotal += written; + if (written != cur) + return SZ_ERROR_WRITE; + data += cur; + size -= cur; + if (size == 0) + { + *needContinue = needContinue2; + return SZ_OK; + } + RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0)) + } + } + + return SZ_ERROR_FAIL; + /* + if (size > me->outBufSize) + return SZ_ERROR_OUTPUT_EOF; + memcpy(me->outBuf, data, size); + me->outBufSize -= size; + me->outBuf += size; + *needContinue = needContinue2; + return SZ_OK; + */ +} + +#endif + + +static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p) +{ + if (!p->dec_created) + { + Lzma2Dec_CONSTRUCT(&p->dec) + p->dec_created = True; + } + + RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt)) + + if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBufSize = 0; + p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); + if (!p->inBuf) + return SZ_ERROR_MEM; + p->inBufSize = p->props.inBufSize_ST; + } + + Lzma2Dec_Init(&p->dec); + + return SZ_OK; +} + + +static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p + #ifndef Z7_ST + , BoolInt tMode + #endif + ) +{ + SizeT wrPos; + size_t inPos, inLim; + const Byte *inData; + UInt64 inPrev, outPrev; + + CLzma2Dec *dec; + + #ifndef Z7_ST + if (tMode) + { + Lzma2DecMt_FreeOutBufs(p); + tMode = MtDec_PrepareRead(&p->mtc); + } + #endif + + RINOK(Lzma2Dec_Prepare_ST(p)) + + dec = &p->dec; + + inPrev = p->inProcessed; + outPrev = p->outProcessed; + + inPos = 0; + inLim = 0; + inData = NULL; + wrPos = dec->decoder.dicPos; + + for (;;) + { + SizeT dicPos; + SizeT size; + ELzmaFinishMode finishMode; + SizeT inProcessed; + ELzmaStatus status; + SRes res; + + SizeT outProcessed; + BoolInt outFinished; + BoolInt needStop; + + if (inPos == inLim) + { + #ifndef Z7_ST + if (tMode) + { + inData = MtDec_Read(&p->mtc, &inLim); + inPos = 0; + if (inData) + continue; + tMode = False; + inLim = 0; + } + #endif + + if (!p->readWasFinished) + { + inPos = 0; + inLim = p->inBufSize; + inData = p->inBuf; + p->readRes = ISeqInStream_Read(p->inStream, (void *)(p->inBuf), &inLim); + // p->readProcessed += inLim; + // inLim -= 5; p->readWasFinished = True; // for test + if (inLim == 0 || p->readRes != SZ_OK) + p->readWasFinished = True; + } + } + + dicPos = dec->decoder.dicPos; + { + SizeT next = dec->decoder.dicBufSize; + if (next - wrPos > p->props.outStep_ST) + next = wrPos + (SizeT)p->props.outStep_ST; + size = next - dicPos; + } + + finishMode = LZMA_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (size >= rem) + { + size = (SizeT)rem; + if (p->finishMode) + finishMode = LZMA_FINISH_END; + } + } + + inProcessed = (SizeT)(inLim - inPos); + + res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status); + + inPos += inProcessed; + p->inProcessed += inProcessed; + outProcessed = dec->decoder.dicPos - dicPos; + p->outProcessed += outProcessed; + + outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed); + + needStop = (res != SZ_OK + || (inProcessed == 0 && outProcessed == 0) + || status == LZMA_STATUS_FINISHED_WITH_MARK + || (!p->finishMode && outFinished)); + + if (needStop || outProcessed >= size) + { + SRes res2; + { + size_t writeSize = dec->decoder.dicPos - wrPos; + size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize); + res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE; + } + + if (dec->decoder.dicPos == dec->decoder.dicBufSize) + dec->decoder.dicPos = 0; + wrPos = dec->decoder.dicPos; + + RINOK(res2) + + if (needStop) + { + if (res != SZ_OK) + return res; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (p->finishMode) + { + if (p->outSize_Defined && p->outSize != p->outProcessed) + return SZ_ERROR_DATA; + } + return SZ_OK; + } + + if (!p->finishMode && outFinished) + return SZ_OK; + + if (status == LZMA_STATUS_NEEDS_MORE_INPUT) + return SZ_ERROR_INPUT_EOF; + + return SZ_ERROR_DATA; + } + } + + if (p->progress) + { + UInt64 inDelta = p->inProcessed - inPrev; + UInt64 outDelta = p->outProcessed - outPrev; + if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) + { + RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed)) + inPrev = p->inProcessed; + outPrev = p->outProcessed; + } + } + } +} + + + +SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, + Byte prop, + const CLzma2DecMtProps *props, + ISeqOutStreamPtr outStream, const UInt64 *outDataSize, int finishMode, + // Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + // const Byte *inData, size_t inDataSize, + UInt64 *inProcessed, + // UInt64 *outProcessed, + int *isMT, + ICompressProgressPtr progress) +{ + // GET_CLzma2DecMt_p + #ifndef Z7_ST + BoolInt tMode; + #endif + + *inProcessed = 0; + + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + + p->prop = prop; + p->props = *props; + + p->inStream = inStream; + p->outStream = outStream; + p->progress = progress; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + p->finishMode = finishMode; + + p->outProcessed = 0; + p->inProcessed = 0; + + p->readWasFinished = False; + p->readRes = SZ_OK; + + *isMT = False; + + + #ifndef Z7_ST + + tMode = False; + + // p->mtc.parseRes = SZ_OK; + + // p->mtc.numFilledThreads = 0; + // p->mtc.crossStart = 0; + // p->mtc.crossEnd = 0; + // p->mtc.allocError_for_Read_BlockIndex = 0; + // p->mtc.isAllocError = False; + + if (p->props.numThreads > 1) + { + IMtDecCallback2 vt; + + Lzma2DecMt_FreeSt(p); + + p->outProcessed_Parse = 0; + + if (!p->mtc_WasConstructed) + { + p->mtc_WasConstructed = True; + MtDec_Construct(&p->mtc); + } + + p->mtc.progress = progress; + p->mtc.inStream = inStream; + + // p->outBuf = NULL; + // p->outBufSize = 0; + /* + if (!outStream) + { + // p->outBuf = outBuf; + // p->outBufSize = *outBufSize; + // *outBufSize = 0; + return SZ_ERROR_PARAM; + } + */ + + // p->mtc.inBlockMax = p->props.inBlockMax; + p->mtc.alloc = &p->alignOffsetAlloc.vt; + // p->alignOffsetAlloc.baseAlloc; + // p->mtc.inData = inData; + // p->mtc.inDataSize = inDataSize; + p->mtc.mtCallback = &vt; + p->mtc.mtCallbackObject = p; + + p->mtc.inBufSize = p->props.inBufSize_MT; + + p->mtc.numThreadsMax = p->props.numThreads; + + *isMT = True; + + vt.Parse = Lzma2DecMt_MtCallback_Parse; + vt.PreCode = Lzma2DecMt_MtCallback_PreCode; + vt.Code = Lzma2DecMt_MtCallback_Code; + vt.Write = Lzma2DecMt_MtCallback_Write; + + { + BoolInt needContinue = False; + + SRes res = MtDec_Code(&p->mtc); + + /* + if (!outStream) + *outBufSize = p->outBuf - outBuf; + */ + + *inProcessed = p->mtc.inProcessed; + + needContinue = False; + + if (res == SZ_OK) + { + if (p->mtc.mtProgress.res != SZ_OK) + res = p->mtc.mtProgress.res; + else + needContinue = p->mtc.needContinue; + } + + if (!needContinue) + { + if (res == SZ_OK) + return p->mtc.readRes; + return res; + } + + tMode = True; + p->readRes = p->mtc.readRes; + p->readWasFinished = p->mtc.readWasFinished; + p->inProcessed = p->mtc.inProcessed; + + PRF_STR("----- decoding ST -----") + } + } + + #endif + + + *isMT = False; + + { + SRes res = Lzma2Dec_Decode_ST(p + #ifndef Z7_ST + , tMode + #endif + ); + + *inProcessed = p->inProcessed; + + // res = SZ_OK; // for test + if (res == SZ_ERROR_INPUT_EOF) + { + if (p->readRes != SZ_OK) + res = p->readRes; + } + else if (res == SZ_OK && p->readRes != SZ_OK) + res = p->readRes; + + /* + #ifndef Z7_ST + if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK) + res = p->mtc.parseRes; + #endif + */ + + return res; + } +} + + +/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ + +SRes Lzma2DecMt_Init(CLzma2DecMtHandle p, + Byte prop, + const CLzma2DecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqInStreamPtr inStream) +{ + // GET_CLzma2DecMt_p + + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + + p->prop = prop; + p->props = *props; + + p->inStream = inStream; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + p->finishMode = finishMode; + + p->outProcessed = 0; + p->inProcessed = 0; + + p->inPos = 0; + p->inLim = 0; + + return Lzma2Dec_Prepare_ST(p); +} + + +SRes Lzma2DecMt_Read(CLzma2DecMtHandle p, + Byte *data, size_t *outSize, + UInt64 *inStreamProcessed) +{ + // GET_CLzma2DecMt_p + ELzmaFinishMode finishMode; + SRes readRes; + size_t size = *outSize; + + *outSize = 0; + *inStreamProcessed = 0; + + finishMode = LZMA_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (size >= rem) + { + size = (size_t)rem; + if (p->finishMode) + finishMode = LZMA_FINISH_END; + } + } + + readRes = SZ_OK; + + for (;;) + { + SizeT inCur; + SizeT outCur; + ELzmaStatus status; + SRes res; + + if (p->inPos == p->inLim && readRes == SZ_OK) + { + p->inPos = 0; + p->inLim = p->props.inBufSize_ST; + readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim); + } + + inCur = (SizeT)(p->inLim - p->inPos); + outCur = (SizeT)size; + + res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur, + p->inBuf + p->inPos, &inCur, finishMode, &status); + + p->inPos += inCur; + p->inProcessed += inCur; + *inStreamProcessed += inCur; + p->outProcessed += outCur; + *outSize += outCur; + size -= outCur; + data += outCur; + + if (res != 0) + return res; + + /* + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + return readRes; + + if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize) + return SZ_ERROR_DATA; + return readRes; + } + */ + + if (inCur == 0 && outCur == 0) + return readRes; + } +} + +#undef PRF +#undef PRF_STR +#undef PRF_STR_INT_2 diff --git a/libraries/lzma/C/Lzma2DecMt.h b/libraries/lzma/C/Lzma2DecMt.h new file mode 100644 index 00000000000..93a5cd59e63 --- /dev/null +++ b/libraries/lzma/C/Lzma2DecMt.h @@ -0,0 +1,81 @@ +/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA2_DEC_MT_H +#define ZIP7_INC_LZMA2_DEC_MT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef struct +{ + size_t inBufSize_ST; + size_t outStep_ST; + + #ifndef Z7_ST + unsigned numThreads; + size_t inBufSize_MT; + size_t outBlockMax; + size_t inBlockMax; + #endif +} CLzma2DecMtProps; + +/* init to single-thread mode */ +void Lzma2DecMtProps_Init(CLzma2DecMtProps *p); + + +/* ---------- CLzma2DecMtHandle Interface ---------- */ + +/* Lzma2DecMt_ * functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + // SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef struct CLzma2DecMt CLzma2DecMt; +typedef CLzma2DecMt * CLzma2DecMtHandle; +// Z7_DECLARE_HANDLE(CLzma2DecMtHandle) + +CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); +void Lzma2DecMt_Destroy(CLzma2DecMtHandle p); + +SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, + Byte prop, + const CLzma2DecMtProps *props, + ISeqOutStreamPtr outStream, + const UInt64 *outDataSize, // NULL means undefined + int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished + // Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + // const Byte *inData, size_t inDataSize, + + // out variables: + UInt64 *inProcessed, + int *isMT, /* out: (*isMT == 0), if single thread decoding was used */ + + // UInt64 *outProcessed, + ICompressProgressPtr progress); + + +/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ + +SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, + Byte prop, + const CLzma2DecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqInStreamPtr inStream); + +SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, + Byte *data, size_t *outSize, + UInt64 *inStreamProcessed); + + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/Lzma2Enc.c b/libraries/lzma/C/Lzma2Enc.c new file mode 100644 index 00000000000..703e146b57e --- /dev/null +++ b/libraries/lzma/C/Lzma2Enc.c @@ -0,0 +1,805 @@ +/* Lzma2Enc.c -- LZMA2 Encoder +2023-04-13 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define Z7_ST */ + +#include "Lzma2Enc.h" + +#ifndef Z7_ST +#include "MtCoder.h" +#else +#define MTCODER_THREADS_MAX 1 +#endif + +#define LZMA2_CONTROL_LZMA (1 << 7) +#define LZMA2_CONTROL_COPY_NO_RESET 2 +#define LZMA2_CONTROL_COPY_RESET_DIC 1 +#define LZMA2_CONTROL_EOF 0 + +#define LZMA2_LCLP_MAX 4 + +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#define LZMA2_PACK_SIZE_MAX (1 << 16) +#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX +#define LZMA2_UNPACK_SIZE_MAX (1 << 21) +#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX + +#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) + + +#define PRF(x) /* x */ + + +/* ---------- CLimitedSeqInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + ISeqInStreamPtr realStream; + UInt64 limit; + UInt64 processed; + int finished; +} CLimitedSeqInStream; + +static void LimitedSeqInStream_Init(CLimitedSeqInStream *p) +{ + p->limit = (UInt64)(Int64)-1; + p->processed = 0; + p->finished = 0; +} + +static SRes LimitedSeqInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLimitedSeqInStream) + size_t size2 = *size; + SRes res = SZ_OK; + + if (p->limit != (UInt64)(Int64)-1) + { + const UInt64 rem = p->limit - p->processed; + if (size2 > rem) + size2 = (size_t)rem; + } + if (size2 != 0) + { + res = ISeqInStream_Read(p->realStream, data, &size2); + p->finished = (size2 == 0 ? 1 : 0); + p->processed += size2; + } + *size = size2; + return res; +} + + +/* ---------- CLzma2EncInt ---------- */ + +typedef struct +{ + CLzmaEncHandle enc; + Byte propsAreSet; + Byte propsByte; + Byte needInitState; + Byte needInitProp; + UInt64 srcPos; +} CLzma2EncInt; + + +static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props) +{ + if (!p->propsAreSet) + { + SizeT propsSize = LZMA_PROPS_SIZE; + Byte propsEncoded[LZMA_PROPS_SIZE]; + RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)) + RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)) + p->propsByte = propsEncoded[0]; + p->propsAreSet = True; + } + return SZ_OK; +} + +static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) +{ + p->srcPos = 0; + p->needInitState = True; + p->needInitProp = True; +} + + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, ISeqInStreamPtr inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p); +void LzmaEnc_Finish(CLzmaEncHandle p); +void LzmaEnc_SaveState(CLzmaEncHandle p); +void LzmaEnc_RestoreState(CLzmaEncHandle p); + +/* +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p); +*/ + +static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, + size_t *packSizeRes, ISeqOutStreamPtr outStream) +{ + size_t packSizeLimit = *packSizeRes; + size_t packSize = packSizeLimit; + UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; + unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); + BoolInt useCopyBlock; + SRes res; + + *packSizeRes = 0; + if (packSize < lzHeaderSize) + return SZ_ERROR_OUTPUT_EOF; + packSize -= lzHeaderSize; + + LzmaEnc_SaveState(p->enc); + res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, + outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); + + PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); + + if (unpackSize == 0) + return res; + + if (res == SZ_OK) + useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); + else + { + if (res != SZ_ERROR_OUTPUT_EOF) + return res; + res = SZ_OK; + useCopyBlock = True; + } + + if (useCopyBlock) + { + size_t destPos = 0; + PRF(printf("################# COPY ")); + + while (unpackSize > 0) + { + const UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; + if (packSizeLimit - destPos < u + 3) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); + outBuf[destPos++] = (Byte)((u - 1) >> 8); + outBuf[destPos++] = (Byte)(u - 1); + memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); + unpackSize -= u; + destPos += u; + p->srcPos += u; + + if (outStream) + { + *packSizeRes += destPos; + if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + destPos = 0; + } + else + *packSizeRes = destPos; + /* needInitState = True; */ + } + + LzmaEnc_RestoreState(p->enc); + return SZ_OK; + } + + { + size_t destPos = 0; + const UInt32 u = unpackSize - 1; + const UInt32 pm = (UInt32)(packSize - 1); + const unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); + + PRF(printf(" ")); + + outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); + outBuf[destPos++] = (Byte)(u >> 8); + outBuf[destPos++] = (Byte)u; + outBuf[destPos++] = (Byte)(pm >> 8); + outBuf[destPos++] = (Byte)pm; + + if (p->needInitProp) + outBuf[destPos++] = p->propsByte; + + p->needInitProp = False; + p->needInitState = False; + destPos += packSize; + p->srcPos += unpackSize; + + if (outStream) + if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + + *packSizeRes = destPos; + return SZ_OK; + } +} + + +/* ---------- Lzma2 Props ---------- */ + +void Lzma2EncProps_Init(CLzma2EncProps *p) +{ + LzmaEncProps_Init(&p->lzmaProps); + p->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO; + p->numBlockThreads_Reduced = -1; + p->numBlockThreads_Max = -1; + p->numTotalThreads = -1; +} + +void Lzma2EncProps_Normalize(CLzma2EncProps *p) +{ + UInt64 fileSize; + int t1, t1n, t2, t2r, t3; + { + CLzmaEncProps lzmaProps = p->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + t1n = lzmaProps.numThreads; + } + + t1 = p->lzmaProps.numThreads; + t2 = p->numBlockThreads_Max; + t3 = p->numTotalThreads; + + if (t2 > MTCODER_THREADS_MAX) + t2 = MTCODER_THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > MTCODER_THREADS_MAX) + t2 = MTCODER_THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzmaProps.numThreads = t1; + + t2r = t2; + + fileSize = p->lzmaProps.reduceSize; + + if ( p->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + && p->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO + && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) + p->lzmaProps.reduceSize = p->blockSize; + + LzmaEncProps_Normalize(&p->lzmaProps); + + p->lzmaProps.reduceSize = fileSize; + + t1 = p->lzmaProps.numThreads; + + if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) + { + t2r = t2 = 1; + t3 = t1; + } + else if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO && t2 <= 1) + { + /* if there is no block multi-threading, we use SOLID block */ + p->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID; + } + else + { + if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) + { + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + const UInt32 dictSize = p->lzmaProps.dictSize; + UInt64 blockSize = (UInt64)dictSize << 2; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + if (blockSize < dictSize) blockSize = dictSize; + blockSize += (kMinSize - 1); + blockSize &= ~(UInt64)(kMinSize - 1); + p->blockSize = blockSize; + } + + if (t2 > 1 && fileSize != (UInt64)(Int64)-1) + { + UInt64 numBlocks = fileSize / p->blockSize; + if (numBlocks * p->blockSize != fileSize) + numBlocks++; + if (numBlocks < (unsigned)t2) + { + t2r = (int)numBlocks; + if (t2r == 0) + t2r = 1; + t3 = t1 * t2r; + } + } + } + + p->numBlockThreads_Max = t2; + p->numBlockThreads_Reduced = t2r; + p->numTotalThreads = t3; +} + + +static SRes Progress(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize) +{ + return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; +} + + +/* ---------- Lzma2 ---------- */ + +struct CLzma2Enc +{ + Byte propEncoded; + CLzma2EncProps props; + UInt64 expectedDataSize; + + Byte *tempBufLzma; + + ISzAllocPtr alloc; + ISzAllocPtr allocBig; + + CLzma2EncInt coders[MTCODER_THREADS_MAX]; + + #ifndef Z7_ST + + ISeqOutStreamPtr outStream; + Byte *outBuf; + size_t outBuf_Rem; /* remainder in outBuf */ + + size_t outBufSize; /* size of allocated outBufs[i] */ + size_t outBufsDataSizes[MTCODER_BLOCKS_MAX]; + BoolInt mtCoder_WasConstructed; + CMtCoder mtCoder; + Byte *outBufs[MTCODER_BLOCKS_MAX]; + + #endif +}; + + + +CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); + if (!p) + return NULL; + Lzma2EncProps_Init(&p->props); + Lzma2EncProps_Normalize(&p->props); + p->expectedDataSize = (UInt64)(Int64)-1; + p->tempBufLzma = NULL; + p->alloc = alloc; + p->allocBig = allocBig; + { + unsigned i; + for (i = 0; i < MTCODER_THREADS_MAX; i++) + p->coders[i].enc = NULL; + } + + #ifndef Z7_ST + p->mtCoder_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + p->outBufs[i] = NULL; + p->outBufSize = 0; + } + #endif + + return (CLzma2EncHandle)p; +} + + +#ifndef Z7_ST + +static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p) +{ + unsigned i; + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + if (p->outBufs[i]) + { + ISzAlloc_Free(p->alloc, p->outBufs[i]); + p->outBufs[i] = NULL; + } + p->outBufSize = 0; +} + +#endif + +// #define GET_CLzma2Enc_p CLzma2Enc *p = (CLzma2Enc *)(void *)p; + +void Lzma2Enc_Destroy(CLzma2EncHandle p) +{ + // GET_CLzma2Enc_p + unsigned i; + for (i = 0; i < MTCODER_THREADS_MAX; i++) + { + CLzma2EncInt *t = &p->coders[i]; + if (t->enc) + { + LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); + t->enc = NULL; + } + } + + + #ifndef Z7_ST + if (p->mtCoder_WasConstructed) + { + MtCoder_Destruct(&p->mtCoder); + p->mtCoder_WasConstructed = False; + } + Lzma2Enc_FreeOutBufs(p); + #endif + + ISzAlloc_Free(p->alloc, p->tempBufLzma); + p->tempBufLzma = NULL; + + ISzAlloc_Free(p->alloc, p); +} + + +SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props) +{ + // GET_CLzma2Enc_p + CLzmaEncProps lzmaProps = props->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) + return SZ_ERROR_PARAM; + p->props = *props; + Lzma2EncProps_Normalize(&p->props); + return SZ_OK; +} + + +void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize) +{ + // GET_CLzma2Enc_p + p->expectedDataSize = expectedDataSiize; +} + + +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p) +{ + // GET_CLzma2Enc_p + unsigned i; + UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); + for (i = 0; i < 40; i++) + if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) + break; + return (Byte)i; +} + + +static SRes Lzma2Enc_EncodeMt1( + CLzma2Enc *me, + CLzma2EncInt *p, + ISeqOutStreamPtr outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + const Byte *inData, size_t inDataSize, + int finished, + ICompressProgressPtr progress) +{ + UInt64 unpackTotal = 0; + UInt64 packTotal = 0; + size_t outLim = 0; + CLimitedSeqInStream limitedInStream; + + if (outBuf) + { + outLim = *outBufSize; + *outBufSize = 0; + } + + if (!p->enc) + { + p->propsAreSet = False; + p->enc = LzmaEnc_Create(me->alloc); + if (!p->enc) + return SZ_ERROR_MEM; + } + + limitedInStream.realStream = inStream; + if (inStream) + { + limitedInStream.vt.Read = LimitedSeqInStream_Read; + } + + if (!outBuf) + { + // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma + if (!me->tempBufLzma) + { + me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); + if (!me->tempBufLzma) + return SZ_ERROR_MEM; + } + } + + RINOK(Lzma2EncInt_InitStream(p, &me->props)) + + for (;;) + { + SRes res = SZ_OK; + SizeT inSizeCur = 0; + + Lzma2EncInt_InitBlock(p); + + LimitedSeqInStream_Init(&limitedInStream); + limitedInStream.limit = me->props.blockSize; + + if (inStream) + { + UInt64 expected = (UInt64)(Int64)-1; + // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize + if (me->expectedDataSize != (UInt64)(Int64)-1 + && me->expectedDataSize >= unpackTotal) + expected = me->expectedDataSize - unpackTotal; + if (me->props.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + && expected > me->props.blockSize) + expected = (size_t)me->props.blockSize; + + LzmaEnc_SetDataSize(p->enc, expected); + + RINOK(LzmaEnc_PrepareForLzma2(p->enc, + &limitedInStream.vt, + LZMA2_KEEP_WINDOW_SIZE, + me->alloc, + me->allocBig)) + } + else + { + inSizeCur = (SizeT)(inDataSize - (size_t)unpackTotal); + if (me->props.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + && inSizeCur > me->props.blockSize) + inSizeCur = (SizeT)(size_t)me->props.blockSize; + + // LzmaEnc_SetDataSize(p->enc, inSizeCur); + + RINOK(LzmaEnc_MemPrepare(p->enc, + inData + (size_t)unpackTotal, inSizeCur, + LZMA2_KEEP_WINDOW_SIZE, + me->alloc, + me->allocBig)) + } + + for (;;) + { + size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; + if (outBuf) + packSize = outLim - (size_t)packTotal; + + res = Lzma2EncInt_EncodeSubblock(p, + outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, + outBuf ? NULL : outStream); + + if (res != SZ_OK) + break; + + packTotal += packSize; + if (outBuf) + *outBufSize = (size_t)packTotal; + + res = Progress(progress, unpackTotal + p->srcPos, packTotal); + if (res != SZ_OK) + break; + + /* + if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) + break; + */ + + if (packSize == 0) + break; + } + + LzmaEnc_Finish(p->enc); + + unpackTotal += p->srcPos; + + RINOK(res) + + if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) + return SZ_ERROR_FAIL; + + if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) + { + if (finished) + { + if (outBuf) + { + const size_t destPos = *outBufSize; + if (destPos >= outLim) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos] = LZMA2_CONTROL_EOF; // 0 + *outBufSize = destPos + 1; + } + else + { + const Byte b = LZMA2_CONTROL_EOF; // 0; + if (ISeqOutStream_Write(outStream, &b, 1) != 1) + return SZ_ERROR_WRITE; + } + } + return SZ_OK; + } + } +} + + + +#ifndef Z7_ST + +static SRes Lzma2Enc_MtCallback_Code(void *p, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished) +{ + CLzma2Enc *me = (CLzma2Enc *)p; + size_t destSize = me->outBufSize; + SRes res; + CMtProgressThunk progressThunk; + + Byte *dest = me->outBufs[outBufIndex]; + + me->outBufsDataSizes[outBufIndex] = 0; + + if (!dest) + { + dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); + if (!dest) + return SZ_ERROR_MEM; + me->outBufs[outBufIndex] = dest; + } + + MtProgressThunk_CreateVTable(&progressThunk); + progressThunk.mtProgress = &me->mtCoder.mtProgress; + progressThunk.inSize = 0; + progressThunk.outSize = 0; + + res = Lzma2Enc_EncodeMt1(me, + &me->coders[coderIndex], + NULL, dest, &destSize, + NULL, src, srcSize, + finished, + &progressThunk.vt); + + me->outBufsDataSizes[outBufIndex] = destSize; + + return res; +} + + +static SRes Lzma2Enc_MtCallback_Write(void *p, unsigned outBufIndex) +{ + CLzma2Enc *me = (CLzma2Enc *)p; + size_t size = me->outBufsDataSizes[outBufIndex]; + const Byte *data = me->outBufs[outBufIndex]; + + if (me->outStream) + return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE; + + if (size > me->outBuf_Rem) + return SZ_ERROR_OUTPUT_EOF; + memcpy(me->outBuf, data, size); + me->outBuf_Rem -= size; + me->outBuf += size; + return SZ_OK; +} + +#endif + + + +SRes Lzma2Enc_Encode2(CLzma2EncHandle p, + ISeqOutStreamPtr outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + const Byte *inData, size_t inDataSize, + ICompressProgressPtr progress) +{ + // GET_CLzma2Enc_p + + if (inStream && inData) + return SZ_ERROR_PARAM; + + if (outStream && outBuf) + return SZ_ERROR_PARAM; + + { + unsigned i; + for (i = 0; i < MTCODER_THREADS_MAX; i++) + p->coders[i].propsAreSet = False; + } + + #ifndef Z7_ST + + if (p->props.numBlockThreads_Reduced > 1) + { + IMtCoderCallback2 vt; + + if (!p->mtCoder_WasConstructed) + { + p->mtCoder_WasConstructed = True; + MtCoder_Construct(&p->mtCoder); + } + + vt.Code = Lzma2Enc_MtCallback_Code; + vt.Write = Lzma2Enc_MtCallback_Write; + + p->outStream = outStream; + p->outBuf = NULL; + p->outBuf_Rem = 0; + if (!outStream) + { + p->outBuf = outBuf; + p->outBuf_Rem = *outBufSize; + *outBufSize = 0; + } + + p->mtCoder.allocBig = p->allocBig; + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.inData = inData; + p->mtCoder.inDataSize = inDataSize; + p->mtCoder.mtCallback = &vt; + p->mtCoder.mtCallbackObject = p; + + p->mtCoder.blockSize = (size_t)p->props.blockSize; + if (p->mtCoder.blockSize != p->props.blockSize) + return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ + + { + const size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16; + if (destBlockSize < p->mtCoder.blockSize) + return SZ_ERROR_PARAM; + if (p->outBufSize != destBlockSize) + Lzma2Enc_FreeOutBufs(p); + p->outBufSize = destBlockSize; + } + + p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max; + p->mtCoder.expectedDataSize = p->expectedDataSize; + + { + const SRes res = MtCoder_Code(&p->mtCoder); + if (!outStream) + *outBufSize = (size_t)(p->outBuf - outBuf); + return res; + } + } + + #endif + + + return Lzma2Enc_EncodeMt1(p, + &p->coders[0], + outStream, outBuf, outBufSize, + inStream, inData, inDataSize, + True, /* finished */ + progress); +} + +#undef PRF diff --git a/libraries/lzma/C/Lzma2Enc.h b/libraries/lzma/C/Lzma2Enc.h new file mode 100644 index 00000000000..cb25275c6b8 --- /dev/null +++ b/libraries/lzma/C/Lzma2Enc.h @@ -0,0 +1,57 @@ +/* Lzma2Enc.h -- LZMA2 Encoder +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA2_ENC_H +#define ZIP7_INC_LZMA2_ENC_H + +#include "LzmaEnc.h" + +EXTERN_C_BEGIN + +#define LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO 0 +#define LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID ((UInt64)(Int64)-1) + +typedef struct +{ + CLzmaEncProps lzmaProps; + UInt64 blockSize; + int numBlockThreads_Reduced; + int numBlockThreads_Max; + int numTotalThreads; +} CLzma2EncProps; + +void Lzma2EncProps_Init(CLzma2EncProps *p); +void Lzma2EncProps_Normalize(CLzma2EncProps *p); + +/* ---------- CLzmaEnc2Handle Interface ---------- */ + +/* Lzma2Enc_* functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef struct CLzma2Enc CLzma2Enc; +typedef CLzma2Enc * CLzma2EncHandle; +// Z7_DECLARE_HANDLE(CLzma2EncHandle) + +CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); +void Lzma2Enc_Destroy(CLzma2EncHandle p); +SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); +void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize); +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); +SRes Lzma2Enc_Encode2(CLzma2EncHandle p, + ISeqOutStreamPtr outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + const Byte *inData, size_t inDataSize, + ICompressProgressPtr progress); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/LzmaDec.c b/libraries/lzma/C/LzmaDec.c index ba3e1dd50ef..69bb8bba9d4 100644 --- a/libraries/lzma/C/LzmaDec.c +++ b/libraries/lzma/C/LzmaDec.c @@ -1,5 +1,5 @@ /* LzmaDec.c -- LZMA Decoder -2018-07-04 : Igor Pavlov : Public domain */ +2023-04-07 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -8,29 +8,31 @@ /* #include "CpuArch.h" */ #include "LzmaDec.h" -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) +// #define kNumTopBits 24 +#define kTopValue ((UInt32)1 << 24) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) -#define kNumMoveBits 5 #define RC_INIT_SIZE 5 +#ifndef Z7_LZMA_DEC_OPT + +#define kNumMoveBits 5 #define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) #define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); #define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); #define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ - { UPDATE_0(p); i = (i + i); A0; } else \ - { UPDATE_1(p); i = (i + i) + 1; A1; } + { UPDATE_0(p) i = (i + i); A0; } else \ + { UPDATE_1(p) i = (i + i) + 1; A1; } #define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); } #define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \ - { UPDATE_0(p + i); A0; } else \ - { UPDATE_1(p + i); A1; } + { UPDATE_0(p + i) A0; } else \ + { UPDATE_1(p + i) A1; } #define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; ) #define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; ) #define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; ) @@ -38,19 +40,19 @@ #define TREE_DECODE(probs, limit, i) \ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } -/* #define _LZMA_SIZE_OPT */ +/* #define Z7_LZMA_SIZE_OPT */ -#ifdef _LZMA_SIZE_OPT +#ifdef Z7_LZMA_SIZE_OPT #define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) #else #define TREE_6_DECODE(probs, i) \ { i = 1; \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ - TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ i -= 0x40; } #endif @@ -62,24 +64,25 @@ probLit = prob + (offs + bit + symbol); \ GET_BIT2(probLit, symbol, offs ^= bit; , ;) +#endif // Z7_LZMA_DEC_OPT -#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_INPUT_EOF; range <<= 8; code = (code << 8) | (*buf++); } -#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) #define UPDATE_0_CHECK range = bound; #define UPDATE_1_CHECK range -= bound; code -= bound; #define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ - { UPDATE_0_CHECK; i = (i + i); A0; } else \ - { UPDATE_1_CHECK; i = (i + i) + 1; A1; } + { UPDATE_0_CHECK i = (i + i); A0; } else \ + { UPDATE_1_CHECK i = (i + i) + 1; A1; } #define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) #define TREE_DECODE_CHECK(probs, limit, i) \ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } #define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \ - { UPDATE_0_CHECK; i += m; m += m; } else \ - { UPDATE_1_CHECK; m += m; i += m; } + { UPDATE_0_CHECK i += m; m += m; } else \ + { UPDATE_1_CHECK m += m; i += m; } #define kNumPosBitsMax 4 @@ -114,6 +117,9 @@ #define kMatchMinLen 2 #define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) +#define kMatchSpecLen_Error_Data (1 << 9) +#define kMatchSpecLen_Error_Fail (kMatchSpecLen_Error_Data - 1) + /* External ASM code needs same CLzmaProb array layout. So don't change it. */ /* (probs_1664) is faster and better for code size at some platforms */ @@ -166,10 +172,12 @@ /* p->remainLen : shows status of LZMA decoder: - < kMatchSpecLenStart : normal remain - = kMatchSpecLenStart : finished - = kMatchSpecLenStart + 1 : need init range coder - = kMatchSpecLenStart + 2 : need init range coder and state + < kMatchSpecLenStart : the number of bytes to be copied with (p->rep0) offset + = kMatchSpecLenStart : the LZMA stream was finished with end mark + = kMatchSpecLenStart + 1 : need init range coder + = kMatchSpecLenStart + 2 : need init range coder and state + = kMatchSpecLen_Error_Fail : Internal Code Failure + = kMatchSpecLen_Error_Data + [0 ... 273] : LZMA Data Error */ /* ---------- LZMA_DECODE_REAL ---------- */ @@ -188,34 +196,42 @@ LZMA_DECODE_REAL() { LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases. So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol - is not END_OF_PAYALOAD_MARKER, then function returns error code. + is not END_OF_PAYALOAD_MARKER, then the function doesn't write any byte to dictionary, + the function returns SZ_OK, and the caller can use (p->remainLen) and (p->reps[0]) later. } Processing: - first LZMA symbol will be decoded in any case - All checks for limits are at the end of main loop, - It will decode new LZMA-symbols while (p->buf < bufLimit && dicPos < limit), + The first LZMA symbol will be decoded in any case. + All main checks for limits are at the end of main loop, + It decodes additional LZMA-symbols while (p->buf < bufLimit && dicPos < limit), RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked. + But if (p->buf < bufLimit), the caller provided at least (LZMA_REQUIRED_INPUT_MAX + 1) bytes for + next iteration before limit (bufLimit + LZMA_REQUIRED_INPUT_MAX), + that is enough for worst case LZMA symbol with one additional RangeCoder normalization for one bit. + So that function never reads bufLimit [LZMA_REQUIRED_INPUT_MAX] byte. Out: RangeCoder is normalized Result: SZ_OK - OK - SZ_ERROR_DATA - Error - p->remainLen: - < kMatchSpecLenStart : normal remain - = kMatchSpecLenStart : finished + p->remainLen: + < kMatchSpecLenStart : the number of bytes to be copied with (p->reps[0]) offset + = kMatchSpecLenStart : the LZMA stream was finished with end mark + + SZ_ERROR_DATA - error, when the MATCH-Symbol refers out of dictionary + p->remainLen : undefined + p->reps[*] : undefined */ -#ifdef _LZMA_DEC_OPT +#ifdef Z7_LZMA_DEC_OPT -int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit); +int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit); #else static -int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { CLzmaProb *probs = GET_PROBS; unsigned state = (unsigned)p->state; @@ -247,7 +263,7 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit IF_BIT_0(prob) { unsigned symbol; - UPDATE_0(prob); + UPDATE_0(prob) prob = probs + Literal; if (processedPos != 0 || checkDicSize != 0) prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); @@ -257,7 +273,7 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit { state -= (state < 4) ? state : 3; symbol = 1; - #ifdef _LZMA_SIZE_OPT + #ifdef Z7_LZMA_SIZE_OPT do { NORMAL_LITER_DEC } while (symbol < 0x100); #else NORMAL_LITER_DEC @@ -276,7 +292,7 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit unsigned offs = 0x100; state -= (state < 10) ? 3 : 6; symbol = 1; - #ifdef _LZMA_SIZE_OPT + #ifdef Z7_LZMA_SIZE_OPT do { unsigned bit; @@ -305,60 +321,62 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit } { - UPDATE_1(prob); + UPDATE_1(prob) prob = probs + IsRep + state; IF_BIT_0(prob) { - UPDATE_0(prob); + UPDATE_0(prob) state += kNumStates; prob = probs + LenCoder; } else { - UPDATE_1(prob); - /* - // that case was checked before with kBadRepCode - if (checkDicSize == 0 && processedPos == 0) - return SZ_ERROR_DATA; - */ + UPDATE_1(prob) prob = probs + IsRepG0 + state; IF_BIT_0(prob) { - UPDATE_0(prob); + UPDATE_0(prob) prob = probs + IsRep0Long + COMBINED_PS_STATE; IF_BIT_0(prob) { - UPDATE_0(prob); + UPDATE_0(prob) + + // that case was checked before with kBadRepCode + // if (checkDicSize == 0 && processedPos == 0) { len = kMatchSpecLen_Error_Data + 1; break; } + // The caller doesn't allow (dicPos == limit) case here + // so we don't need the following check: + // if (dicPos == limit) { state = state < kNumLitStates ? 9 : 11; len = 1; break; } + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; processedPos++; state = state < kNumLitStates ? 9 : 11; continue; } - UPDATE_1(prob); + UPDATE_1(prob) } else { UInt32 distance; - UPDATE_1(prob); + UPDATE_1(prob) prob = probs + IsRepG1 + state; IF_BIT_0(prob) { - UPDATE_0(prob); + UPDATE_0(prob) distance = rep1; } else { - UPDATE_1(prob); + UPDATE_1(prob) prob = probs + IsRepG2 + state; IF_BIT_0(prob) { - UPDATE_0(prob); + UPDATE_0(prob) distance = rep2; } else { - UPDATE_1(prob); + UPDATE_1(prob) distance = rep3; rep3 = rep2; } @@ -371,37 +389,37 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit prob = probs + RepLenCoder; } - #ifdef _LZMA_SIZE_OPT + #ifdef Z7_LZMA_SIZE_OPT { unsigned lim, offset; CLzmaProb *probLen = prob + LenChoice; IF_BIT_0(probLen) { - UPDATE_0(probLen); + UPDATE_0(probLen) probLen = prob + LenLow + GET_LEN_STATE; offset = 0; lim = (1 << kLenNumLowBits); } else { - UPDATE_1(probLen); + UPDATE_1(probLen) probLen = prob + LenChoice2; IF_BIT_0(probLen) { - UPDATE_0(probLen); + UPDATE_0(probLen) probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); offset = kLenNumLowSymbols; lim = (1 << kLenNumLowBits); } else { - UPDATE_1(probLen); + UPDATE_1(probLen) probLen = prob + LenHigh; offset = kLenNumLowSymbols * 2; lim = (1 << kLenNumHighBits); } } - TREE_DECODE(probLen, lim, len); + TREE_DECODE(probLen, lim, len) len += offset; } #else @@ -409,32 +427,32 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit CLzmaProb *probLen = prob + LenChoice; IF_BIT_0(probLen) { - UPDATE_0(probLen); + UPDATE_0(probLen) probLen = prob + LenLow + GET_LEN_STATE; len = 1; - TREE_GET_BIT(probLen, len); - TREE_GET_BIT(probLen, len); - TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len) + TREE_GET_BIT(probLen, len) + TREE_GET_BIT(probLen, len) len -= 8; } else { - UPDATE_1(probLen); + UPDATE_1(probLen) probLen = prob + LenChoice2; IF_BIT_0(probLen) { - UPDATE_0(probLen); + UPDATE_0(probLen) probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); len = 1; - TREE_GET_BIT(probLen, len); - TREE_GET_BIT(probLen, len); - TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len) + TREE_GET_BIT(probLen, len) + TREE_GET_BIT(probLen, len) } else { - UPDATE_1(probLen); + UPDATE_1(probLen) probLen = prob + LenHigh; - TREE_DECODE(probLen, (1 << kLenNumHighBits), len); + TREE_DECODE(probLen, (1 << kLenNumHighBits), len) len += kLenNumLowSymbols * 2; } } @@ -446,7 +464,7 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit UInt32 distance; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); - TREE_6_DECODE(prob, distance); + TREE_6_DECODE(prob, distance) if (distance >= kStartPosModelIndex) { unsigned posSlot = (unsigned)distance; @@ -461,7 +479,7 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit distance++; do { - REV_BIT_VAR(prob, distance, m); + REV_BIT_VAR(prob, distance, m) } while (--numDirectBits); distance -= m; @@ -496,10 +514,10 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit distance <<= kNumAlignBits; { unsigned i = 1; - REV_BIT_CONST(prob, i, 1); - REV_BIT_CONST(prob, i, 2); - REV_BIT_CONST(prob, i, 4); - REV_BIT_LAST (prob, i, 8); + REV_BIT_CONST(prob, i, 1) + REV_BIT_CONST(prob, i, 2) + REV_BIT_CONST(prob, i, 4) + REV_BIT_LAST (prob, i, 8) distance |= i; } if (distance == (UInt32)0xFFFFFFFF) @@ -518,8 +536,10 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize)) { - p->dicPos = dicPos; - return SZ_ERROR_DATA; + len += kMatchSpecLen_Error_Data + kMatchMinLen; + // len = kMatchSpecLen_Error_Data; + // len += kMatchMinLen; + break; } } @@ -532,8 +552,13 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit if ((rem = limit - dicPos) == 0) { - p->dicPos = dicPos; - return SZ_ERROR_DATA; + /* + We stop decoding and return SZ_OK, and we can resume decoding later. + Any error conditions can be tested later in caller code. + For more strict mode we can stop decoding with error + // len += kMatchSpecLen_Error_Data; + */ + break; } curLen = ((rem < len) ? (unsigned)rem : len); @@ -567,12 +592,12 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit } while (dicPos < limit && buf < bufLimit); - NORMALIZE; + NORMALIZE p->buf = buf; p->range = range; p->code = code; - p->remainLen = (UInt32)len; + p->remainLen = (UInt32)len; // & (kMatchSpecLen_Error_Data - 1); // we can write real length for error matches too. p->dicPos = dicPos; p->processedPos = processedPos; p->reps[0] = rep0; @@ -580,40 +605,61 @@ int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit p->reps[2] = rep2; p->reps[3] = rep3; p->state = (UInt32)state; - + if (len >= kMatchSpecLen_Error_Data) + return SZ_ERROR_DATA; return SZ_OK; } #endif -static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) + + +static void Z7_FASTCALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) { - if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + unsigned len = (unsigned)p->remainLen; + if (len == 0 /* || len >= kMatchSpecLenStart */) + return; { - Byte *dic = p->dic; SizeT dicPos = p->dicPos; - SizeT dicBufSize = p->dicBufSize; - unsigned len = (unsigned)p->remainLen; - SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ - SizeT rem = limit - dicPos; - if (rem < len) - len = (unsigned)(rem); + Byte *dic; + SizeT dicBufSize; + SizeT rep0; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ + { + SizeT rem = limit - dicPos; + if (rem < len) + { + len = (unsigned)(rem); + if (len == 0) + return; + } + } if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) p->checkDicSize = p->prop.dicSize; p->processedPos += (UInt32)len; p->remainLen -= (UInt32)len; - while (len != 0) + dic = p->dic; + rep0 = p->reps[0]; + dicBufSize = p->dicBufSize; + do { - len--; dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; } + while (--len); p->dicPos = dicPos; } } +/* +At staring of new stream we have one of the following symbols: + - Literal - is allowed + - Non-Rep-Match - is allowed only if it's end marker symbol + - Rep-Match - is not allowed +We use early check of (RangeCoder:Code) over kBadRepCode to simplify main decoding code +*/ + #define kRange0 0xFFFFFFFF #define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)) #define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))) @@ -621,69 +667,77 @@ static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) #error Stop_Compiling_Bad_LZMA_Check #endif -static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -{ - do - { - SizeT limit2 = limit; - if (p->checkDicSize == 0) - { - UInt32 rem = p->prop.dicSize - p->processedPos; - if (limit - p->dicPos > rem) - limit2 = p->dicPos + rem; - if (p->processedPos == 0) - if (p->code >= kBadRepCode) - return SZ_ERROR_DATA; - } +/* +LzmaDec_DecodeReal2(): + It calls LZMA_DECODE_REAL() and it adjusts limit according (p->checkDicSize). - RINOK(LZMA_DECODE_REAL(p, limit2, bufLimit)); - +We correct (p->checkDicSize) after LZMA_DECODE_REAL() and in LzmaDec_WriteRem(), +and we support the following state of (p->checkDicSize): + if (total_processed < p->prop.dicSize) then + { + (total_processed == p->processedPos) + (p->checkDicSize == 0) + } + else + (p->checkDicSize == p->prop.dicSize) +*/ + +static int Z7_FASTCALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit = p->dicPos + rem; + } + { + int res = LZMA_DECODE_REAL(p, limit, bufLimit); if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) p->checkDicSize = p->prop.dicSize; - - LzmaDec_WriteRem(p, limit); + return res; } - while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); - - return 0; } + + typedef enum { - DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_INPUT_EOF, /* need more input data */ DUMMY_LIT, DUMMY_MATCH, DUMMY_REP } ELzmaDummy; -static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) + +#define IS_DUMMY_END_MARKER_POSSIBLE(dummyRes) ((dummyRes) == DUMMY_MATCH) + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byte **bufOut) { UInt32 range = p->range; UInt32 code = p->code; - const Byte *bufLimit = buf + inSize; + const Byte *bufLimit = *bufOut; const CLzmaProb *probs = GET_PROBS; unsigned state = (unsigned)p->state; ELzmaDummy res; + for (;;) { const CLzmaProb *prob; UInt32 bound; unsigned ttt; - unsigned posState = CALC_POS_STATE(p->processedPos, (1 << p->prop.pb) - 1); + unsigned posState = CALC_POS_STATE(p->processedPos, ((unsigned)1 << p->prop.pb) - 1); prob = probs + IsMatch + COMBINED_PS_STATE; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK - /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ - prob = probs + Literal; if (p->checkDicSize != 0 || p->processedPos != 0) prob += ((UInt32)LZMA_LIT_SIZE * - ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + - (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + ((((p->processedPos) & (((unsigned)1 << (p->prop.lp)) - 1)) << p->prop.lc) + + ((unsigned)p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); if (state < kNumLitStates) { @@ -713,55 +767,54 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS else { unsigned len; - UPDATE_1_CHECK; + UPDATE_1_CHECK prob = probs + IsRep + state; IF_BIT_0_CHECK(prob) { - UPDATE_0_CHECK; + UPDATE_0_CHECK state = 0; prob = probs + LenCoder; res = DUMMY_MATCH; } else { - UPDATE_1_CHECK; + UPDATE_1_CHECK res = DUMMY_REP; prob = probs + IsRepG0 + state; IF_BIT_0_CHECK(prob) { - UPDATE_0_CHECK; + UPDATE_0_CHECK prob = probs + IsRep0Long + COMBINED_PS_STATE; IF_BIT_0_CHECK(prob) { - UPDATE_0_CHECK; - NORMALIZE_CHECK; - return DUMMY_REP; + UPDATE_0_CHECK + break; } else { - UPDATE_1_CHECK; + UPDATE_1_CHECK } } else { - UPDATE_1_CHECK; + UPDATE_1_CHECK prob = probs + IsRepG1 + state; IF_BIT_0_CHECK(prob) { - UPDATE_0_CHECK; + UPDATE_0_CHECK } else { - UPDATE_1_CHECK; + UPDATE_1_CHECK prob = probs + IsRepG2 + state; IF_BIT_0_CHECK(prob) { - UPDATE_0_CHECK; + UPDATE_0_CHECK } else { - UPDATE_1_CHECK; + UPDATE_1_CHECK } } } @@ -773,31 +826,31 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS const CLzmaProb *probLen = prob + LenChoice; IF_BIT_0_CHECK(probLen) { - UPDATE_0_CHECK; + UPDATE_0_CHECK probLen = prob + LenLow + GET_LEN_STATE; offset = 0; limit = 1 << kLenNumLowBits; } else { - UPDATE_1_CHECK; + UPDATE_1_CHECK probLen = prob + LenChoice2; IF_BIT_0_CHECK(probLen) { - UPDATE_0_CHECK; + UPDATE_0_CHECK probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); offset = kLenNumLowSymbols; limit = 1 << kLenNumLowBits; } else { - UPDATE_1_CHECK; + UPDATE_1_CHECK probLen = prob + LenHigh; offset = kLenNumLowSymbols * 2; limit = 1 << kLenNumHighBits; } } - TREE_DECODE_CHECK(probLen, limit, len); + TREE_DECODE_CHECK(probLen, limit, len) len += offset; } @@ -807,13 +860,11 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS prob = probs + PosSlot + ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); - TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot) if (posSlot >= kStartPosModelIndex) { unsigned numDirectBits = ((posSlot >> 1) - 1); - /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ - if (posSlot < kEndPosModelIndex) { prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); @@ -837,19 +888,22 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS unsigned m = 1; do { - REV_BIT_CHECK(prob, i, m); + REV_BIT_CHECK(prob, i, m) } while (--numDirectBits); } } } } + break; } - NORMALIZE_CHECK; + NORMALIZE_CHECK + + *bufOut = buf; return res; } - +void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState) { p->remainLen = kMatchSpecLenStart + 1; @@ -872,16 +926,41 @@ void LzmaDec_Init(CLzmaDec *p) } +/* +LZMA supports optional end_marker. +So the decoder can lookahead for one additional LZMA-Symbol to check end_marker. +That additional LZMA-Symbol can require up to LZMA_REQUIRED_INPUT_MAX bytes in input stream. +When the decoder reaches dicLimit, it looks (finishMode) parameter: + if (finishMode == LZMA_FINISH_ANY), the decoder doesn't lookahead + if (finishMode != LZMA_FINISH_ANY), the decoder lookahead, if end_marker is possible for current position + +When the decoder lookahead, and the lookahead symbol is not end_marker, we have two ways: + 1) Strict mode (default) : the decoder returns SZ_ERROR_DATA. + 2) The relaxed mode (alternative mode) : we could return SZ_OK, and the caller + must check (status) value. The caller can show the error, + if the end of stream is expected, and the (status) is noit + LZMA_STATUS_FINISHED_WITH_MARK or LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK. +*/ + + +#define RETURN_NOT_FINISHED_FOR_FINISH \ + *status = LZMA_STATUS_NOT_FINISHED; \ + return SZ_ERROR_DATA; // for strict mode + // return SZ_OK; // for relaxed mode + + SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; (*srcLen) = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; if (p->remainLen > kMatchSpecLenStart) { + if (p->remainLen > kMatchSpecLenStart + 2) + return p->remainLen == kMatchSpecLen_Error_Fail ? SZ_ERROR_FAIL : SZ_ERROR_DATA; + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) p->tempBuf[p->tempBufSize++] = *src++; if (p->tempBufSize != 0 && p->tempBuf[0] != 0) @@ -896,6 +975,12 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr | ((UInt32)p->tempBuf[2] << 16) | ((UInt32)p->tempBuf[3] << 8) | ((UInt32)p->tempBuf[4]); + + if (p->checkDicSize == 0 + && p->processedPos == 0 + && p->code >= kBadRepCode) + return SZ_ERROR_DATA; + p->range = 0xFFFFFFFF; p->tempBufSize = 0; @@ -913,10 +998,21 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr p->remainLen = 0; } - LzmaDec_WriteRem(p, dicLimit); - - while (p->remainLen != kMatchSpecLenStart) + for (;;) { + if (p->remainLen == kMatchSpecLenStart) + { + if (p->code != 0) + return SZ_ERROR_DATA; + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + + LzmaDec_WriteRem(p, dicLimit); + + { + // (p->remainLen == 0 || p->dicPos == dicLimit) + int checkEndMarkNow = 0; if (p->dicPos >= dicLimit) @@ -933,92 +1029,174 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr } if (p->remainLen != 0) { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; + RETURN_NOT_FINISHED_FOR_FINISH } checkEndMarkNow = 1; } + // (p->remainLen == 0) + if (p->tempBufSize == 0) { - SizeT processed; const Byte *bufLimit; + int dummyProcessed = -1; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { - int dummyRes = LzmaDec_TryDummy(p, src, inSize); - if (dummyRes == DUMMY_ERROR) + const Byte *bufOut = src + inSize; + + ELzmaDummy dummyRes = LzmaDec_TryDummy(p, src, &bufOut); + + if (dummyRes == DUMMY_INPUT_EOF) { - memcpy(p->tempBuf, src, inSize); - p->tempBufSize = (unsigned)inSize; + size_t i; + if (inSize >= LZMA_REQUIRED_INPUT_MAX) + break; (*srcLen) += inSize; + p->tempBufSize = (unsigned)inSize; + for (i = 0; i < inSize; i++) + p->tempBuf[i] = src[i]; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } - if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + + dummyProcessed = (int)(bufOut - src); + if ((unsigned)dummyProcessed > LZMA_REQUIRED_INPUT_MAX) + break; + + if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes)) { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; + unsigned i; + (*srcLen) += (unsigned)dummyProcessed; + p->tempBufSize = (unsigned)dummyProcessed; + for (i = 0; i < (unsigned)dummyProcessed; i++) + p->tempBuf[i] = src[i]; + // p->remainLen = kMatchSpecLen_Error_Data; + RETURN_NOT_FINISHED_FOR_FINISH } + bufLimit = src; + // we will decode only one iteration } else bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; - if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) - return SZ_ERROR_DATA; - processed = (SizeT)(p->buf - src); - (*srcLen) += processed; - src += processed; - inSize -= processed; + + { + int res = LzmaDec_DecodeReal2(p, dicLimit, bufLimit); + + SizeT processed = (SizeT)(p->buf - src); + + if (dummyProcessed < 0) + { + if (processed > inSize) + break; + } + else if ((unsigned)dummyProcessed != processed) + break; + + src += processed; + inSize -= processed; + (*srcLen) += processed; + + if (res != SZ_OK) + { + p->remainLen = kMatchSpecLen_Error_Data; + return SZ_ERROR_DATA; + } + } + continue; } - else + { - unsigned rem = p->tempBufSize, lookAhead = 0; - while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) - p->tempBuf[rem++] = src[lookAhead++]; - p->tempBufSize = rem; + // we have some data in (p->tempBuf) + // in strict mode: tempBufSize is not enough for one Symbol decoding. + // in relaxed mode: tempBufSize not larger than required for one Symbol decoding. + + unsigned rem = p->tempBufSize; + unsigned ahead = 0; + int dummyProcessed = -1; + + while (rem < LZMA_REQUIRED_INPUT_MAX && ahead < inSize) + p->tempBuf[rem++] = src[ahead++]; + + // ahead - the size of new data copied from (src) to (p->tempBuf) + // rem - the size of temp buffer including new data from (src) + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { - int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, (SizeT)rem); - if (dummyRes == DUMMY_ERROR) + const Byte *bufOut = p->tempBuf + rem; + + ELzmaDummy dummyRes = LzmaDec_TryDummy(p, p->tempBuf, &bufOut); + + if (dummyRes == DUMMY_INPUT_EOF) { - (*srcLen) += (SizeT)lookAhead; + if (rem >= LZMA_REQUIRED_INPUT_MAX) + break; + p->tempBufSize = rem; + (*srcLen) += (SizeT)ahead; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } - if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + + dummyProcessed = (int)(bufOut - p->tempBuf); + + if ((unsigned)dummyProcessed < p->tempBufSize) + break; + + if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes)) { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; + (*srcLen) += (unsigned)dummyProcessed - p->tempBufSize; + p->tempBufSize = (unsigned)dummyProcessed; + // p->remainLen = kMatchSpecLen_Error_Data; + RETURN_NOT_FINISHED_FOR_FINISH } } + p->buf = p->tempBuf; - if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) - return SZ_ERROR_DATA; { - unsigned kkk = (unsigned)(p->buf - p->tempBuf); - if (rem < kkk) - return SZ_ERROR_FAIL; /* some internal error */ - rem -= kkk; - if (lookAhead < rem) - return SZ_ERROR_FAIL; /* some internal error */ - lookAhead -= rem; + // we decode one symbol from (p->tempBuf) here, so the (bufLimit) is equal to (p->buf) + int res = LzmaDec_DecodeReal2(p, dicLimit, p->buf); + + SizeT processed = (SizeT)(p->buf - p->tempBuf); + rem = p->tempBufSize; + + if (dummyProcessed < 0) + { + if (processed > LZMA_REQUIRED_INPUT_MAX) + break; + if (processed < rem) + break; + } + else if ((unsigned)dummyProcessed != processed) + break; + + processed -= rem; + + src += processed; + inSize -= processed; + (*srcLen) += processed; + p->tempBufSize = 0; + + if (res != SZ_OK) + { + p->remainLen = kMatchSpecLen_Error_Data; + return SZ_ERROR_DATA; + } } - (*srcLen) += (SizeT)lookAhead; - src += lookAhead; - inSize -= (SizeT)lookAhead; - p->tempBufSize = 0; } + } } - - if (p->code != 0) - return SZ_ERROR_DATA; - *status = LZMA_STATUS_FINISHED_WITH_MARK; - return SZ_OK; + + /* Some unexpected error: internal error of code, memory corruption or hardware failure */ + p->remainLen = kMatchSpecLen_Error_Fail; + return SZ_ERROR_FAIL; } + SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT outSize = *destLen; @@ -1121,8 +1299,8 @@ static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAl SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) { CLzmaProps propNew; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + RINOK(LzmaProps_Decode(&propNew, props, propsSize)) + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)) p->prop = propNew; return SZ_OK; } @@ -1131,14 +1309,14 @@ SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAll { CLzmaProps propNew; SizeT dicBufSize; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + RINOK(LzmaProps_Decode(&propNew, props, propsSize)) + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)) { UInt32 dictSize = propNew.dicSize; SizeT mask = ((UInt32)1 << 12) - 1; if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; - else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; + else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1; dicBufSize = ((SizeT)dictSize + mask) & ~mask; if (dicBufSize < dictSize) dicBufSize = dictSize; @@ -1170,8 +1348,8 @@ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, *status = LZMA_STATUS_NOT_SPECIFIED; if (inSize < RC_INIT_SIZE) return SZ_ERROR_INPUT_EOF; - LzmaDec_Construct(&p); - RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); + LzmaDec_CONSTRUCT(&p) + RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)) p.dic = dest; p.dicBufSize = outSize; LzmaDec_Init(&p); diff --git a/libraries/lzma/C/LzmaDec.h b/libraries/lzma/C/LzmaDec.h index 1f0927ab132..b0ce28fa02a 100644 --- a/libraries/lzma/C/LzmaDec.h +++ b/libraries/lzma/C/LzmaDec.h @@ -1,19 +1,19 @@ /* LzmaDec.h -- LZMA Decoder -2018-04-21 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ -#ifndef __LZMA_DEC_H -#define __LZMA_DEC_H +#ifndef ZIP7_INC_LZMA_DEC_H +#define ZIP7_INC_LZMA_DEC_H #include "7zTypes.h" EXTERN_C_BEGIN -/* #define _LZMA_PROB32 */ -/* _LZMA_PROB32 can increase the speed on some CPUs, +/* #define Z7_LZMA_PROB32 */ +/* Z7_LZMA_PROB32 can increase the speed on some CPUs, but memory usage for CLzmaDec::probs will be doubled in that case */ typedef -#ifdef _LZMA_PROB32 +#ifdef Z7_LZMA_PROB32 UInt32 #else UInt16 @@ -25,7 +25,7 @@ typedef #define LZMA_PROPS_SIZE 5 -typedef struct _CLzmaProps +typedef struct { Byte lc; Byte lp; @@ -73,7 +73,8 @@ typedef struct Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; } CLzmaDec; -#define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; } +#define LzmaDec_CONSTRUCT(p) { (p)->dic = NULL; (p)->probs = NULL; } +#define LzmaDec_Construct(p) LzmaDec_CONSTRUCT(p) void LzmaDec_Init(CLzmaDec *p); @@ -181,6 +182,7 @@ void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc); LZMA_STATUS_NEEDS_MORE_INPUT LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error + SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure */ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, @@ -223,6 +225,7 @@ SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure */ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, diff --git a/libraries/lzma/C/LzmaEnc.c b/libraries/lzma/C/LzmaEnc.c index 46a0db000f9..6d13cac8ce2 100644 --- a/libraries/lzma/C/LzmaEnc.c +++ b/libraries/lzma/C/LzmaEnc.c @@ -1,5 +1,5 @@ /* LzmaEnc.c -- LZMA Encoder -2019-01-10: Igor Pavlov : Public domain */ +2023-04-13: Igor Pavlov : Public domain */ #include "Precomp.h" @@ -12,22 +12,36 @@ #include #endif +#include "CpuArch.h" #include "LzmaEnc.h" #include "LzFind.h" -#ifndef _7ZIP_ST +#ifndef Z7_ST #include "LzFindMt.h" #endif +/* the following LzmaEnc_* declarations is internal LZMA interface for LZMA2 encoder */ + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, ISeqInStreamPtr inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p); +void LzmaEnc_Finish(CLzmaEncHandle p); +void LzmaEnc_SaveState(CLzmaEncHandle p); +void LzmaEnc_RestoreState(CLzmaEncHandle p); + #ifdef SHOW_STAT static unsigned g_STAT_OFFSET = 0; #endif -#define kLzmaMaxHistorySize ((UInt32)3 << 29) -/* #define kLzmaMaxHistorySize ((UInt32)7 << 29) */ +/* for good normalization speed we still reserve 256 MB before 4 GB range */ +#define kLzmaMaxHistorySize ((UInt32)15 << 28) -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) +// #define kNumTopBits 24 +#define kTopValue ((UInt32)1 << 24) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) @@ -36,7 +50,7 @@ static unsigned g_STAT_OFFSET = 0; #define kNumMoveReducingBits 4 #define kNumBitPriceShiftBits 4 -#define kBitPrice (1 << kNumBitPriceShiftBits) +// #define kBitPrice (1 << kNumBitPriceShiftBits) #define REP_LEN_COUNT 64 @@ -46,7 +60,9 @@ void LzmaEncProps_Init(CLzmaEncProps *p) p->dictSize = p->mc = 0; p->reduceSize = (UInt64)(Int64)-1; p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; + p->numHashOutBits = 0; p->writeEndMark = 0; + p->affinity = 0; } void LzmaEncProps_Normalize(CLzmaEncProps *p) @@ -55,16 +71,21 @@ void LzmaEncProps_Normalize(CLzmaEncProps *p) if (level < 0) level = 5; p->level = level; - if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level <= 7 ? (1 << 25) : (1 << 26))); + if (p->dictSize == 0) + p->dictSize = + ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) : + ( level <= 6 ? ((UInt32)1 << (level + 19)) : + ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26) + ))); + if (p->dictSize > p->reduceSize) { - unsigned i; - UInt32 reduceSize = (UInt32)p->reduceSize; - for (i = 11; i <= 30; i++) - { - if (reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } - if (reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } - } + UInt32 v = (UInt32)p->reduceSize; + const UInt32 kReduceMin = ((UInt32)1 << 12); + if (v < kReduceMin) + v = kReduceMin; + if (p->dictSize > v) + p->dictSize = v; } if (p->lc < 0) p->lc = 3; @@ -74,12 +95,12 @@ void LzmaEncProps_Normalize(CLzmaEncProps *p) if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); - if (p->numHashBytes < 0) p->numHashBytes = 4; - if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->numHashBytes < 0) p->numHashBytes = (p->btMode ? 4 : 5); + if (p->mc == 0) p->mc = (16 + ((unsigned)p->fb >> 1)) >> (p->btMode ? 0 : 1); if (p->numThreads < 0) p->numThreads = - #ifndef _7ZIP_ST + #ifndef Z7_ST ((p->btMode && p->algo) ? 2 : 1); #else 1; @@ -93,18 +114,85 @@ UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) return props.dictSize; } -#if (_MSC_VER >= 1400) -/* BSR code is fast for some new CPUs */ -/* #define LZMA_LOG_BSR */ + +/* +x86/x64: + +BSR: + IF (SRC == 0) ZF = 1, DEST is undefined; + AMD : DEST is unchanged; + IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit + BSR is slow in some processors + +LZCNT: + IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64) + IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits + IF (DEST == 0) ZF = 1; + +LZCNT works only in new processors starting from Haswell. +if LZCNT is not supported by processor, then it's executed as BSR. +LZCNT can be faster than BSR, if supported. +*/ + +// #define LZMA_LOG_BSR + +#if defined(MY_CPU_ARM_OR_ARM64) /* || defined(MY_CPU_X86_OR_AMD64) */ + + #if (defined(__clang__) && (__clang_major__ >= 6)) \ + || (defined(__GNUC__) && (__GNUC__ >= 6)) + #define LZMA_LOG_BSR + #elif defined(_MSC_VER) && (_MSC_VER >= 1300) + // #if defined(MY_CPU_ARM_OR_ARM64) + #define LZMA_LOG_BSR + // #endif + #endif #endif +// #include + #ifdef LZMA_LOG_BSR -#define kDicLogSizeMaxCompress 32 +#if defined(__clang__) \ + || defined(__GNUC__) + +/* + C code: : (30 - __builtin_clz(x)) + gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31) + clang10 for x64 : 31 + (bsr(x) xor -32) +*/ -#define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); res = (zz + zz) + ((pos >> (zz - 1)) & 1); } + #define MY_clz(x) ((unsigned)__builtin_clz(x)) + // __lzcnt32 + // __builtin_ia32_lzcnt_u32 -static unsigned GetPosSlot1(UInt32 pos) +#else // #if defined(_MSC_VER) + + #ifdef MY_CPU_ARM_OR_ARM64 + + #define MY_clz _CountLeadingZeros + + #else // if defined(MY_CPU_X86_OR_AMD64) + + // #define MY_clz __lzcnt // we can use lzcnt (unsupported by old CPU) + // _BitScanReverse code is not optimal for some MSVC compilers + #define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); zz--; \ + res = (zz + zz) + (pos >> zz); } + + #endif // MY_CPU_X86_OR_AMD64 + +#endif // _MSC_VER + + +#ifndef BSR2_RET + + #define BSR2_RET(pos, res) { unsigned zz = 30 - MY_clz(pos); \ + res = (zz + zz) + (pos >> zz); } + +#endif + + +unsigned GetPosSlot1(UInt32 pos); +unsigned GetPosSlot1(UInt32 pos) { unsigned res; BSR2_RET(pos, res); @@ -113,10 +201,10 @@ static unsigned GetPosSlot1(UInt32 pos) #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } -#else -#define kNumLogBits (9 + sizeof(size_t) / 2) -/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */ +#else // ! LZMA_LOG_BSR + +#define kNumLogBits (11 + sizeof(size_t) / 8 * 3) #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) @@ -163,7 +251,7 @@ static void LzmaEnc_FastPosInit(Byte *g_FastPos) #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } #define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); } -#endif +#endif // LZMA_LOG_BSR #define LZMA_NUM_REPS 4 @@ -193,7 +281,7 @@ typedef struct #define kNumLenToPosStates 4 #define kNumPosSlotBits 6 -#define kDicLogSizeMin 0 +// #define kDicLogSizeMin 0 #define kDicLogSizeMax 32 #define kDistTableSizeMax (kDicLogSizeMax * 2) @@ -206,7 +294,7 @@ typedef struct #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) typedef -#ifdef _LZMA_PROB32 +#ifdef Z7_LZMA_PROB32 UInt32 #else UInt16 @@ -263,7 +351,7 @@ typedef struct Byte *buf; Byte *bufLim; Byte *bufBase; - ISeqOutStream *outStream; + ISeqOutStreamPtr outStream; UInt64 processed; SRes res; } CRangeEnc; @@ -296,10 +384,10 @@ typedef struct typedef UInt32 CProbPrice; -typedef struct +struct CLzmaEnc { void *matchFinderObj; - IMatchFinder matchFinder; + IMatchFinder2 matchFinder; unsigned optCur; unsigned optEnd; @@ -339,24 +427,30 @@ typedef struct UInt32 dictSize; SRes result; - #ifndef _7ZIP_ST + #ifndef Z7_ST BoolInt mtMode; // begin of CMatchFinderMt is used in LZ thread CMatchFinderMt matchFinderMt; // end of CMatchFinderMt is used in BT and HASH threads + // #else + // CMatchFinder matchFinderBase; #endif - CMatchFinder matchFinderBase; - #ifndef _7ZIP_ST + + // we suppose that we have 8-bytes alignment after CMatchFinder + + #ifndef Z7_ST Byte pad[128]; #endif // LZ thread CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; - UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; + // we want {len , dist} pairs to be 8-bytes aligned in matches array + UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2]; + // we want 8-bytes alignment here UInt32 alignPrices[kAlignTableSize]; UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; @@ -385,113 +479,115 @@ typedef struct CSaveState saveState; - #ifndef _7ZIP_ST + // BoolInt mf_Failure; + #ifndef Z7_ST Byte pad2[128]; #endif -} CLzmaEnc; - +}; -#define COPY_ARR(dest, src, arr) memcpy(dest->arr, src->arr, sizeof(src->arr)); +#define MFB (p->matchFinderBase) +/* +#ifndef Z7_ST +#define MFB (p->matchFinderMt.MatchFinder) +#endif +*/ -void LzmaEnc_SaveState(CLzmaEncHandle pp) -{ - CLzmaEnc *p = (CLzmaEnc *)pp; - CSaveState *dest = &p->saveState; - - dest->state = p->state; - - dest->lenProbs = p->lenProbs; - dest->repLenProbs = p->repLenProbs; - - COPY_ARR(dest, p, reps); - - COPY_ARR(dest, p, posAlignEncoder); - COPY_ARR(dest, p, isRep); - COPY_ARR(dest, p, isRepG0); - COPY_ARR(dest, p, isRepG1); - COPY_ARR(dest, p, isRepG2); - COPY_ARR(dest, p, isMatch); - COPY_ARR(dest, p, isRep0Long); - COPY_ARR(dest, p, posSlotEncoder); - COPY_ARR(dest, p, posEncoders); - - memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb)); +// #define GET_CLzmaEnc_p CLzmaEnc *p = (CLzmaEnc*)(void *)p; +// #define GET_const_CLzmaEnc_p const CLzmaEnc *p = (const CLzmaEnc*)(const void *)p; + +#define COPY_ARR(dest, src, arr) memcpy((dest)->arr, (src)->arr, sizeof((src)->arr)); + +#define COPY_LZMA_ENC_STATE(d, s, p) \ + (d)->state = (s)->state; \ + COPY_ARR(d, s, reps) \ + COPY_ARR(d, s, posAlignEncoder) \ + COPY_ARR(d, s, isRep) \ + COPY_ARR(d, s, isRepG0) \ + COPY_ARR(d, s, isRepG1) \ + COPY_ARR(d, s, isRepG2) \ + COPY_ARR(d, s, isMatch) \ + COPY_ARR(d, s, isRep0Long) \ + COPY_ARR(d, s, posSlotEncoder) \ + COPY_ARR(d, s, posEncoders) \ + (d)->lenProbs = (s)->lenProbs; \ + (d)->repLenProbs = (s)->repLenProbs; \ + memcpy((d)->litProbs, (s)->litProbs, ((UInt32)0x300 << (p)->lclp) * sizeof(CLzmaProb)); + +void LzmaEnc_SaveState(CLzmaEncHandle p) +{ + // GET_CLzmaEnc_p + CSaveState *v = &p->saveState; + COPY_LZMA_ENC_STATE(v, p, p) } - -void LzmaEnc_RestoreState(CLzmaEncHandle pp) +void LzmaEnc_RestoreState(CLzmaEncHandle p) { - CLzmaEnc *dest = (CLzmaEnc *)pp; - const CSaveState *p = &dest->saveState; - - dest->state = p->state; - - dest->lenProbs = p->lenProbs; - dest->repLenProbs = p->repLenProbs; - - COPY_ARR(dest, p, reps); - - COPY_ARR(dest, p, posAlignEncoder); - COPY_ARR(dest, p, isRep); - COPY_ARR(dest, p, isRepG0); - COPY_ARR(dest, p, isRepG1); - COPY_ARR(dest, p, isRepG2); - COPY_ARR(dest, p, isMatch); - COPY_ARR(dest, p, isRep0Long); - COPY_ARR(dest, p, posSlotEncoder); - COPY_ARR(dest, p, posEncoders); - - memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb)); + // GET_CLzmaEnc_p + const CSaveState *v = &p->saveState; + COPY_LZMA_ENC_STATE(p, v, p) } - -SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) +Z7_NO_INLINE +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props2) { - CLzmaEnc *p = (CLzmaEnc *)pp; + // GET_CLzmaEnc_p CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX - || props.pb > LZMA_PB_MAX - || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress) - || props.dictSize > kLzmaMaxHistorySize) + || props.pb > LZMA_PB_MAX) return SZ_ERROR_PARAM; + + if (props.dictSize > kLzmaMaxHistorySize) + props.dictSize = kLzmaMaxHistorySize; + + #ifndef LZMA_LOG_BSR + { + const UInt64 dict64 = props.dictSize; + if (dict64 > ((UInt64)1 << kDicLogSizeMaxCompress)) + return SZ_ERROR_PARAM; + } + #endif + p->dictSize = props.dictSize; { - unsigned fb = props.fb; + unsigned fb = (unsigned)props.fb; if (fb < 5) fb = 5; if (fb > LZMA_MATCH_LEN_MAX) fb = LZMA_MATCH_LEN_MAX; p->numFastBytes = fb; } - p->lc = props.lc; - p->lp = props.lp; - p->pb = props.pb; + p->lc = (unsigned)props.lc; + p->lp = (unsigned)props.lp; + p->pb = (unsigned)props.pb; p->fastMode = (props.algo == 0); // p->_maxMode = True; - p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0); + MFB.btMode = (Byte)(props.btMode ? 1 : 0); + // MFB.btMode = (Byte)(props.btMode); { unsigned numHashBytes = 4; if (props.btMode) { - if (props.numHashBytes < 2) - numHashBytes = 2; - else if (props.numHashBytes < 4) - numHashBytes = props.numHashBytes; + if (props.numHashBytes < 2) numHashBytes = 2; + else if (props.numHashBytes < 4) numHashBytes = (unsigned)props.numHashBytes; } - p->matchFinderBase.numHashBytes = numHashBytes; + if (props.numHashBytes >= 5) numHashBytes = 5; + + MFB.numHashBytes = numHashBytes; + // MFB.numHashBytes_Min = 2; + MFB.numHashOutBits = (Byte)props.numHashOutBits; } - p->matchFinderBase.cutValue = props.mc; + MFB.cutValue = props.mc; - p->writeEndMark = props.writeEndMark; + p->writeEndMark = (BoolInt)props.writeEndMark; - #ifndef _7ZIP_ST + #ifndef Z7_ST /* if (newMultiThread != _multiThread) { @@ -500,16 +596,18 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) } */ p->multiThread = (props.numThreads > 1); + p->matchFinderMt.btSync.affinity = + p->matchFinderMt.hashSync.affinity = props.affinity; #endif return SZ_OK; } -void LzmaEnc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) +void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize) { - CLzmaEnc *p = (CLzmaEnc *)pp; - p->matchFinderBase.expectedDataSize = expectedDataSiize; + // GET_CLzmaEnc_p + MFB.expectedDataSize = expectedDataSiize; } @@ -536,8 +634,8 @@ static void RangeEnc_Construct(CRangeEnc *p) p->bufBase = NULL; } -#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) -#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + ((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize) +#define RangeEnc_GetProcessed(p) ( (p)->processed + (size_t)((p)->buf - (p)->bufBase) + (p)->cacheSize) +#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + (size_t)((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize) #define RC_BUF_SIZE (1 << 16) @@ -556,12 +654,11 @@ static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc) static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc) { ISzAlloc_Free(alloc, p->bufBase); - p->bufBase = 0; + p->bufBase = NULL; } static void RangeEnc_Init(CRangeEnc *p) { - /* Stream.Init(); */ p->range = 0xFFFFFFFF; p->cache = 0; p->low = 0; @@ -573,19 +670,19 @@ static void RangeEnc_Init(CRangeEnc *p) p->res = SZ_OK; } -MY_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p) +Z7_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p) { - size_t num; - if (p->res != SZ_OK) - return; - num = p->buf - p->bufBase; - if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num)) - p->res = SZ_ERROR_WRITE; + const size_t num = (size_t)(p->buf - p->bufBase); + if (p->res == SZ_OK) + { + if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num)) + p->res = SZ_ERROR_WRITE; + } p->processed += num; p->buf = p->bufBase; } -MY_NO_INLINE static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) +Z7_NO_INLINE static void Z7_FASTCALL RangeEnc_ShiftLow(CRangeEnc *p) { UInt32 low = (UInt32)p->low; unsigned high = (unsigned)(p->low >> 32); @@ -630,9 +727,9 @@ static void RangeEnc_FlushData(CRangeEnc *p) ttt = *(prob); \ newBound = (range >> kNumBitModelTotalBits) * ttt; -// #define _LZMA_ENC_USE_BRANCH +// #define Z7_LZMA_ENC_USE_BRANCH -#ifdef _LZMA_ENC_USE_BRANCH +#ifdef Z7_LZMA_ENC_USE_BRANCH #define RC_BIT(p, prob, bit) { \ RC_BIT_PRE(p, prob) \ @@ -656,7 +753,7 @@ static void RangeEnc_FlushData(CRangeEnc *p) range += newBound & mask; \ mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \ mask += ((1 << kNumMoveBits) - 1); \ - ttt += (Int32)(mask - ttt) >> kNumMoveBits; \ + ttt += (UInt32)((Int32)(mask - ttt) >> kNumMoveBits); \ *(prob) = (CLzmaProb)ttt; \ RC_NORM(p) \ } @@ -700,7 +797,7 @@ static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym) CLzmaProb *prob = probs + (sym >> 8); UInt32 bit = (sym >> 7) & 1; sym <<= 1; - RC_BIT(p, prob, bit); + RC_BIT(p, prob, bit) } while (sym < 0x10000); p->range = range; @@ -722,7 +819,7 @@ static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UIn bit = (sym >> 7) & 1; sym <<= 1; offs &= ~(matchByte ^ sym); - RC_BIT(p, prob, bit); + RC_BIT(p, prob, bit) } while (sym < 0x10000); p->range = range; @@ -749,17 +846,17 @@ static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices) bitCount++; } } - ProbPrices[i] = (CProbPrice)((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); + ProbPrices[i] = (CProbPrice)(((unsigned)kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); // printf("\n%3d: %5d", i, ProbPrices[i]); } } #define GET_PRICE(prob, bit) \ - p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits] #define GET_PRICEa(prob, bit) \ - ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits] #define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] @@ -810,7 +907,7 @@ static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBi unsigned bit = sym & 1; // RangeEnc_EncodeBit(rc, probs + m, bit); sym >>= 1; - RC_BIT(rc, probs + m, bit); + RC_BIT(rc, probs + m, bit) m = (m << 1) | bit; } while (--numBits); @@ -833,15 +930,15 @@ static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posS UInt32 range, ttt, newBound; CLzmaProb *probs = p->low; range = rc->range; - RC_BIT_PRE(rc, probs); + RC_BIT_PRE(rc, probs) if (sym >= kLenNumLowSymbols) { - RC_BIT_1(rc, probs); + RC_BIT_1(rc, probs) probs += kLenNumLowSymbols; - RC_BIT_PRE(rc, probs); + RC_BIT_PRE(rc, probs) if (sym >= kLenNumLowSymbols * 2) { - RC_BIT_1(rc, probs); + RC_BIT_1(rc, probs) rc->range = range; // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2); LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2); @@ -854,11 +951,11 @@ static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posS { unsigned m; unsigned bit; - RC_BIT_0(rc, probs); + RC_BIT_0(rc, probs) probs += (posState << (1 + kLenNumLowBits)); - bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit); m = (1 << 1) + bit; - bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit); m = (m << 1) + bit; - bit = sym & 1; RC_BIT(rc, probs + m, bit); + bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit) m = (1 << 1) + bit; + bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit) m = (m << 1) + bit; + bit = sym & 1; RC_BIT(rc, probs + m, bit) rc->range = range; } } @@ -879,7 +976,7 @@ static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *price } -MY_NO_INLINE static void MY_FAST_CALL LenPriceEnc_UpdateTables( +Z7_NO_INLINE static void Z7_FASTCALL LenPriceEnc_UpdateTables( CLenPriceEnc *p, unsigned numPosStates, const CLenEnc *enc, @@ -985,7 +1082,11 @@ static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) p->additionalOffset++; p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); - numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + { + const UInt32 *d = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; } + numPairs = (unsigned)(d - p->matches); + } *numPairsRes = numPairs; #ifdef SHOW_STAT @@ -1001,7 +1102,7 @@ static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) if (numPairs == 0) return 0; { - unsigned len = p->matches[(size_t)numPairs - 2]; + const unsigned len = p->matches[(size_t)numPairs - 2]; if (len != p->numFastBytes) return len; { @@ -1011,7 +1112,7 @@ static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) { const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; const Byte *p2 = p1 + len; - ptrdiff_t dif = (ptrdiff_t)-1 - p->matches[(size_t)numPairs - 1]; + const ptrdiff_t dif = (ptrdiff_t)-1 - (ptrdiff_t)p->matches[(size_t)numPairs - 1]; const Byte *lim = p1 + numAvail; for (; p2 != lim && *p2 == p2[dif]; p2++) {} @@ -1037,7 +1138,7 @@ static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) + GET_PRICE_1(p->isRep[state]) \ + GET_PRICE_0(p->isRepG0[state]) -MY_FORCE_INLINE +Z7_FORCE_INLINE static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState) { UInt32 price; @@ -1167,6 +1268,8 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) repLens[i] = len; if (len > repLens[repMaxIndex]) repMaxIndex = i; + if (len == LZMA_MATCH_LEN_MAX) // 21.03 : optimization + break; } if (repLens[repMaxIndex] >= p->numFastBytes) @@ -1179,10 +1282,12 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) } matches = p->matches; + #define MATCHES matches + // #define MATCHES p->matches if (mainLen >= p->numFastBytes) { - p->backRes = matches[(size_t)numPairs - 1] + LZMA_NUM_REPS; + p->backRes = MATCHES[(size_t)numPairs - 1] + LZMA_NUM_REPS; MOVE_POS(p, mainLen - 1) return mainLen; } @@ -1212,7 +1317,7 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) LitEnc_GetPrice(probs, curByte, p->ProbPrices)); } - MakeAs_Lit(&p->opt[1]); + MakeAs_Lit(&p->opt[1]) matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); @@ -1224,7 +1329,7 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) if (shortRepPrice < p->opt[1].price) { p->opt[1].price = shortRepPrice; - MakeAs_ShortRep(&p->opt[1]); + MakeAs_ShortRep(&p->opt[1]) } if (last < 2) { @@ -1276,13 +1381,13 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) if (len < 2) len = 2; else - while (len > matches[offs]) + while (len > MATCHES[offs]) offs += 2; for (; ; len++) { COptimal *opt; - UInt32 dist = matches[(size_t)offs + 1]; + UInt32 dist = MATCHES[(size_t)offs + 1]; UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); unsigned lenToPosState = GetLenToPosState(len); @@ -1291,7 +1396,7 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) else { unsigned slot; - GetPosSlot2(dist, slot); + GetPosSlot2(dist, slot) price += p->alignPrices[dist & kAlignMask]; price += p->posSlotPrices[lenToPosState][slot]; } @@ -1306,7 +1411,7 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) opt->extra = 0; } - if (len == matches[offs]) + if (len == MATCHES[offs]) { offs += 2; if (offs == numPairs) @@ -1367,7 +1472,7 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) unsigned delta = best - cur; if (delta != 0) { - MOVE_POS(p, delta); + MOVE_POS(p, delta) } } cur = best; @@ -1514,7 +1619,7 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) { nextOpt->price = litPrice; nextOpt->len = 1; - MakeAs_Lit(nextOpt); + MakeAs_Lit(nextOpt) nextIsLit = True; } } @@ -1548,7 +1653,7 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) { nextOpt->price = shortRepPrice; nextOpt->len = 1; - MakeAs_ShortRep(nextOpt); + MakeAs_ShortRep(nextOpt) nextIsLit = False; } } @@ -1727,8 +1832,8 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) if (newLen > numAvail) { newLen = numAvail; - for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); - matches[numPairs] = (UInt32)newLen; + for (numPairs = 0; newLen > MATCHES[numPairs]; numPairs += 2); + MATCHES[numPairs] = (UInt32)newLen; numPairs += 2; } @@ -1747,12 +1852,12 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) } offs = 0; - while (startLen > matches[offs]) + while (startLen > MATCHES[offs]) offs += 2; - dist = matches[(size_t)offs + 1]; + dist = MATCHES[(size_t)offs + 1]; // if (dist >= kNumFullDistances) - GetPosSlot2(dist, posSlot); + GetPosSlot2(dist, posSlot) for (len = /*2*/ startLen; ; len++) { @@ -1776,7 +1881,7 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) } } - if (len == matches[offs]) + if (len == MATCHES[offs]) { // if (p->_maxMode) { // MATCH : LIT : REP_0 @@ -1841,9 +1946,9 @@ static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) offs += 2; if (offs == numPairs) break; - dist = matches[(size_t)offs + 1]; + dist = MATCHES[(size_t)offs + 1]; // if (dist >= kNumFullDistances) - GetPosSlot2(dist, posSlot); + GetPosSlot2(dist, posSlot) } } } @@ -2019,7 +2124,7 @@ static void WriteEndMarker(CLzmaEnc *p, unsigned posState) { UInt32 ttt, newBound; RC_BIT_PRE(p, probs + m) - RC_BIT_1(&p->rc, probs + m); + RC_BIT_1(&p->rc, probs + m) m = (m << 1) + 1; } while (m < (1 << kNumPosSlotBits)); @@ -2044,7 +2149,7 @@ static void WriteEndMarker(CLzmaEnc *p, unsigned posState) { UInt32 ttt, newBound; RC_BIT_PRE(p, probs + m) - RC_BIT_1(&p->rc, probs + m); + RC_BIT_1(&p->rc, probs + m) m = (m << 1) + 1; } while (m < kAlignTableSize); @@ -2059,15 +2164,30 @@ static SRes CheckErrors(CLzmaEnc *p) return p->result; if (p->rc.res != SZ_OK) p->result = SZ_ERROR_WRITE; - if (p->matchFinderBase.result != SZ_OK) + + #ifndef Z7_ST + if ( + // p->mf_Failure || + (p->mtMode && + ( // p->matchFinderMt.failure_LZ_LZ || + p->matchFinderMt.failure_LZ_BT)) + ) + { + p->result = MY_HRES_ERROR_INTERNAL_ERROR; + // printf("\nCheckErrors p->matchFinderMt.failureLZ\n"); + } + #endif + + if (MFB.result != SZ_OK) p->result = SZ_ERROR_READ; + if (p->result != SZ_OK) p->finished = True; return p->result; } -MY_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos) +Z7_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos) { /* ReleaseMFStream(); */ p->finished = True; @@ -2079,7 +2199,7 @@ MY_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos) } -MY_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) +Z7_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) { unsigned i; const CProbPrice *ProbPrices = p->ProbPrices; @@ -2103,7 +2223,7 @@ MY_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) } -MY_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p) +Z7_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p) { // int y; for (y = 0; y < 100; y++) { @@ -2198,20 +2318,20 @@ MY_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p) -void LzmaEnc_Construct(CLzmaEnc *p) +static void LzmaEnc_Construct(CLzmaEnc *p) { RangeEnc_Construct(&p->rc); - MatchFinder_Construct(&p->matchFinderBase); + MatchFinder_Construct(&MFB); - #ifndef _7ZIP_ST + #ifndef Z7_ST + p->matchFinderMt.MatchFinder = &MFB; MatchFinderMt_Construct(&p->matchFinderMt); - p->matchFinderMt.MatchFinder = &p->matchFinderBase; #endif { CLzmaEncProps props; LzmaEncProps_Init(&props); - LzmaEnc_SetProps(p, &props); + LzmaEnc_SetProps((CLzmaEncHandle)(void *)p, &props); } #ifndef LZMA_LOG_BSR @@ -2221,7 +2341,6 @@ void LzmaEnc_Construct(CLzmaEnc *p) LzmaEnc_InitPriceTables(p->ProbPrices); p->litProbs = NULL; p->saveState.litProbs = NULL; - } CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc) @@ -2233,7 +2352,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc) return p; } -void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc) +static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc) { ISzAlloc_Free(alloc, p->litProbs); ISzAlloc_Free(alloc, p->saveState.litProbs); @@ -2241,36 +2360,44 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc) p->saveState.litProbs = NULL; } -void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig) +static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig) { - #ifndef _7ZIP_ST + #ifndef Z7_ST MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); #endif - MatchFinder_Free(&p->matchFinderBase, allocBig); + MatchFinder_Free(&MFB, allocBig); LzmaEnc_FreeLits(p, alloc); RangeEnc_Free(&p->rc, alloc); } void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig) { - LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); + // GET_CLzmaEnc_p + LzmaEnc_Destruct(p, alloc, allocBig); ISzAlloc_Free(alloc, p); } +Z7_NO_INLINE static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize) { UInt32 nowPos32, startPos32; if (p->needInit) { + #ifndef Z7_ST + if (p->mtMode) + { + RINOK(MatchFinderMt_InitMt(&p->matchFinderMt)) + } + #endif p->matchFinder.Init(p->matchFinderObj); p->needInit = 0; } if (p->finished) return p->result; - RINOK(CheckErrors(p)); + RINOK(CheckErrors(p)) nowPos32 = (UInt32)p->nowPos64; startPos32 = nowPos32; @@ -2333,7 +2460,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpa const Byte *data; unsigned state; - RC_BIT_0(&p->rc, probs); + RC_BIT_0(&p->rc, probs) p->rc.range = range; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; probs = LIT_PROBS(nowPos32, *(data - 1)); @@ -2347,53 +2474,53 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpa } else { - RC_BIT_1(&p->rc, probs); + RC_BIT_1(&p->rc, probs) probs = &p->isRep[p->state]; RC_BIT_PRE(&p->rc, probs) if (dist < LZMA_NUM_REPS) { - RC_BIT_1(&p->rc, probs); + RC_BIT_1(&p->rc, probs) probs = &p->isRepG0[p->state]; RC_BIT_PRE(&p->rc, probs) if (dist == 0) { - RC_BIT_0(&p->rc, probs); + RC_BIT_0(&p->rc, probs) probs = &p->isRep0Long[p->state][posState]; RC_BIT_PRE(&p->rc, probs) if (len != 1) { - RC_BIT_1_BASE(&p->rc, probs); + RC_BIT_1_BASE(&p->rc, probs) } else { - RC_BIT_0_BASE(&p->rc, probs); + RC_BIT_0_BASE(&p->rc, probs) p->state = kShortRepNextStates[p->state]; } } else { - RC_BIT_1(&p->rc, probs); + RC_BIT_1(&p->rc, probs) probs = &p->isRepG1[p->state]; RC_BIT_PRE(&p->rc, probs) if (dist == 1) { - RC_BIT_0_BASE(&p->rc, probs); + RC_BIT_0_BASE(&p->rc, probs) dist = p->reps[1]; } else { - RC_BIT_1(&p->rc, probs); + RC_BIT_1(&p->rc, probs) probs = &p->isRepG2[p->state]; RC_BIT_PRE(&p->rc, probs) if (dist == 2) { - RC_BIT_0_BASE(&p->rc, probs); + RC_BIT_0_BASE(&p->rc, probs) dist = p->reps[2]; } else { - RC_BIT_1_BASE(&p->rc, probs); + RC_BIT_1_BASE(&p->rc, probs) dist = p->reps[3]; p->reps[3] = p->reps[2]; } @@ -2417,7 +2544,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpa else { unsigned posSlot; - RC_BIT_0(&p->rc, probs); + RC_BIT_0(&p->rc, probs) p->rc.range = range; p->state = kMatchNextStates[p->state]; @@ -2431,7 +2558,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpa p->reps[0] = dist + 1; p->matchPriceCount++; - GetPosSlot(dist, posSlot); + GetPosSlot(dist, posSlot) // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot); { UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits); @@ -2442,7 +2569,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpa CLzmaProb *prob = probs + (sym >> kNumPosSlotBits); UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1; sym <<= 1; - RC_BIT(&p->rc, prob, bit); + RC_BIT(&p->rc, prob, bit) } while (sym < (1 << kNumPosSlotBits * 2)); p->rc.range = range; @@ -2486,10 +2613,10 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpa { unsigned m = 1; unsigned bit; - bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; - bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; - bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; - bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; + bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) p->rc.range = range; // p->alignPriceCount++; } @@ -2521,12 +2648,12 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpa // { int y; for (y = 0; y < 100; y++) { FillDistancesPrices(p); // }} - LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices); } if (p->repLenEncCounter <= 0) { p->repLenEncCounter = REP_LEN_COUNT; - LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices); } } @@ -2559,11 +2686,13 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpa static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) { UInt32 beforeSize = kNumOpts; + UInt32 dictSize; + if (!RangeEnc_Alloc(&p->rc, alloc)) return SZ_ERROR_MEM; - #ifndef _7ZIP_ST - p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0)); + #ifndef Z7_ST + p->mtMode = (p->multiThread && !p->fastMode && (MFB.btMode != 0)); #endif { @@ -2582,36 +2711,55 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, } } - p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); + MFB.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); + + + dictSize = p->dictSize; + if (dictSize == ((UInt32)2 << 30) || + dictSize == ((UInt32)3 << 30)) + { + /* 21.03 : here we reduce the dictionary for 2 reasons: + 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary. + 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases, + where data size is aligned for 1 GB: 5/6/8 GB. + That reducing must be >= 1 for such corner cases. */ + dictSize -= 1; + } + + if (beforeSize + dictSize < keepWindowSize) + beforeSize = keepWindowSize - dictSize; - if (beforeSize + p->dictSize < keepWindowSize) - beforeSize = keepWindowSize - p->dictSize; + /* in worst case we can look ahead for + max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes. + we send larger value for (keepAfter) to MantchFinder_Create(): + (numFastBytes + LZMA_MATCH_LEN_MAX + 1) + */ - #ifndef _7ZIP_ST + #ifndef Z7_ST if (p->mtMode) { - RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, - LZMA_MATCH_LEN_MAX - + 1 /* 18.04 */ - , allocBig)); + RINOK(MatchFinderMt_Create(&p->matchFinderMt, dictSize, beforeSize, + p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 18.04 */ + , allocBig)) p->matchFinderObj = &p->matchFinderMt; - p->matchFinderBase.bigHash = (Byte)( - (p->dictSize > kBigHashDicLimit && p->matchFinderBase.hashMask >= 0xFFFFFF) ? 1 : 0); + MFB.bigHash = (Byte)(MFB.hashMask >= 0xFFFFFF ? 1 : 0); MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); } else #endif { - if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) + if (!MatchFinder_Create(&MFB, dictSize, beforeSize, + p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 21.03 */ + , allocBig)) return SZ_ERROR_MEM; - p->matchFinderObj = &p->matchFinderBase; - MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); + p->matchFinderObj = &MFB; + MatchFinder_CreateVTable(&MFB, &p->matchFinder); } return SZ_OK; } -void LzmaEnc_Init(CLzmaEnc *p) +static void LzmaEnc_Init(CLzmaEnc *p) { unsigned i; p->state = 0; @@ -2675,12 +2823,14 @@ void LzmaEnc_Init(CLzmaEnc *p) p->additionalOffset = 0; - p->pbMask = (1 << p->pb) - 1; + p->pbMask = ((unsigned)1 << p->pb) - 1; p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc); + + // p->mf_Failure = False; } -void LzmaEnc_InitPrices(CLzmaEnc *p) +static void LzmaEnc_InitPrices(CLzmaEnc *p) { if (!p->fastMode) { @@ -2694,8 +2844,8 @@ void LzmaEnc_InitPrices(CLzmaEnc *p) p->repLenEncCounter = REP_LEN_COUNT; - LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); - LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices); } static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) @@ -2708,59 +2858,53 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr p->finished = False; p->result = SZ_OK; - RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); + p->nowPos64 = 0; + p->needInit = 1; + RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)) LzmaEnc_Init(p); LzmaEnc_InitPrices(p); - p->nowPos64 = 0; return SZ_OK; } -static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, +static SRes LzmaEnc_Prepare(CLzmaEncHandle p, + ISeqOutStreamPtr outStream, + ISeqInStreamPtr inStream, ISzAllocPtr alloc, ISzAllocPtr allocBig) { - CLzmaEnc *p = (CLzmaEnc *)pp; - p->matchFinderBase.stream = inStream; - p->needInit = 1; + // GET_CLzmaEnc_p + MatchFinder_SET_STREAM(&MFB, inStream) p->rc.outStream = outStream; return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); } -SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, - ISeqInStream *inStream, UInt32 keepWindowSize, +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, + ISeqInStreamPtr inStream, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) { - CLzmaEnc *p = (CLzmaEnc *)pp; - p->matchFinderBase.stream = inStream; - p->needInit = 1; + // GET_CLzmaEnc_p + MatchFinder_SET_STREAM(&MFB, inStream) return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); } -static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) -{ - p->matchFinderBase.directInput = 1; - p->matchFinderBase.bufferBase = (Byte *)src; - p->matchFinderBase.directInputRem = srcLen; -} - -SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, - UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, + const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig) { - CLzmaEnc *p = (CLzmaEnc *)pp; - LzmaEnc_SetInputBuf(p, src, srcLen); - p->needInit = 1; - - LzmaEnc_SetDataSize(pp, srcLen); + // GET_CLzmaEnc_p + MatchFinder_SET_DIRECT_INPUT_BUF(&MFB, src, srcLen) + LzmaEnc_SetDataSize(p, srcLen); return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); } -void LzmaEnc_Finish(CLzmaEncHandle pp) +void LzmaEnc_Finish(CLzmaEncHandle p) { - #ifndef _7ZIP_ST - CLzmaEnc *p = (CLzmaEnc *)pp; + #ifndef Z7_ST + // GET_CLzmaEnc_p if (p->mtMode) MatchFinderMt_ReleaseStream(&p->matchFinderMt); #else - UNUSED_VAR(pp); + UNUSED_VAR(p) #endif } @@ -2769,43 +2913,48 @@ typedef struct { ISeqOutStream vt; Byte *data; - SizeT rem; + size_t rem; BoolInt overflow; } CLzmaEnc_SeqOutStreamBuf; -static size_t SeqOutStreamBuf_Write(const ISeqOutStream *pp, const void *data, size_t size) +static size_t SeqOutStreamBuf_Write(ISeqOutStreamPtr pp, const void *data, size_t size) { - CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt); + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLzmaEnc_SeqOutStreamBuf) if (p->rem < size) { size = p->rem; p->overflow = True; } - memcpy(p->data, data, size); - p->rem -= size; - p->data += size; + if (size != 0) + { + memcpy(p->data, data, size); + p->rem -= size; + p->data += size; + } return size; } -UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +/* +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p) { - const CLzmaEnc *p = (CLzmaEnc *)pp; + GET_const_CLzmaEnc_p return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); } +*/ - -const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p) { - const CLzmaEnc *p = (CLzmaEnc *)pp; + // GET_const_CLzmaEnc_p return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; } -SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, +// (desiredPackSize == 0) is not allowed +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) { - CLzmaEnc *p = (CLzmaEnc *)pp; + // GET_CLzmaEnc_p UInt64 nowPos64; SRes res; CLzmaEnc_SeqOutStreamBuf outStream; @@ -2822,14 +2971,10 @@ SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, if (reInit) LzmaEnc_Init(p); LzmaEnc_InitPrices(p); - - nowPos64 = p->nowPos64; RangeEnc_Init(&p->rc); p->rc.outStream = &outStream.vt; - - if (desiredPackSize == 0) - return SZ_ERROR_OUTPUT_EOF; - + nowPos64 = p->nowPos64; + res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); *unpackSize = (UInt32)(p->nowPos64 - nowPos64); @@ -2841,11 +2986,12 @@ SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, } -static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) +Z7_NO_INLINE +static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgressPtr progress) { SRes res = SZ_OK; - #ifndef _7ZIP_ST + #ifndef Z7_ST Byte allocaDummy[0x300]; allocaDummy[0] = 0; allocaDummy[1] = allocaDummy[0]; @@ -2867,10 +3013,10 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) } } - LzmaEnc_Finish(p); + LzmaEnc_Finish((CLzmaEncHandle)(void *)p); /* - if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase)) + if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&MFB)) res = SZ_ERROR_FAIL; } */ @@ -2879,53 +3025,63 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) } -SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) { - RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); - return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); + // GET_CLzmaEnc_p + RINOK(LzmaEnc_Prepare(p, outStream, inStream, alloc, allocBig)) + return LzmaEnc_Encode2(p, progress); } -SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *props, SizeT *size) { - CLzmaEnc *p = (CLzmaEnc *)pp; - unsigned i; - UInt32 dictSize = p->dictSize; if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM; *size = LZMA_PROPS_SIZE; - props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); - - if (dictSize >= ((UInt32)1 << 22)) - { - UInt32 kDictMask = ((UInt32)1 << 20) - 1; - if (dictSize < (UInt32)0xFFFFFFFF - kDictMask) - dictSize = (dictSize + kDictMask) & ~kDictMask; - } - else for (i = 11; i <= 30; i++) { - if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } - if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } - } + // GET_CLzmaEnc_p + const UInt32 dictSize = p->dictSize; + UInt32 v; + props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); + + // we write aligned dictionary value to properties for lzma decoder + if (dictSize >= ((UInt32)1 << 21)) + { + const UInt32 kDictMask = ((UInt32)1 << 20) - 1; + v = (dictSize + kDictMask) & ~kDictMask; + if (v < dictSize) + v = dictSize; + } + else + { + unsigned i = 11 * 2; + do + { + v = (UInt32)(2 + (i & 1)) << (i >> 1); + i++; + } + while (v < dictSize); + } - for (i = 0; i < 4; i++) - props[1 + i] = (Byte)(dictSize >> (8 * i)); - return SZ_OK; + SetUi32(props + 1, v) + return SZ_OK; + } } -unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle pp) +unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p) { - return ((CLzmaEnc *)pp)->writeEndMark; + // GET_CLzmaEnc_p + return (unsigned)p->writeEndMark; } -SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) { SRes res; - CLzmaEnc *p = (CLzmaEnc *)pp; + // GET_CLzmaEnc_p CLzmaEnc_SeqOutStreamBuf outStream; @@ -2937,7 +3093,7 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte p->writeEndMark = writeEndMark; p->rc.outStream = &outStream.vt; - res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + res = LzmaEnc_MemPrepare(p, src, srcLen, 0, alloc, allocBig); if (res == SZ_OK) { @@ -2946,7 +3102,7 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte res = SZ_ERROR_FAIL; } - *destLen -= outStream.rem; + *destLen -= (SizeT)outStream.rem; if (outStream.overflow) return SZ_ERROR_OUTPUT_EOF; return res; @@ -2955,9 +3111,9 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, - ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) + ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) { - CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); + CLzmaEncHandle p = LzmaEnc_Create(alloc); SRes res; if (!p) return SZ_ERROR_MEM; @@ -2974,3 +3130,15 @@ SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, LzmaEnc_Destroy(p, alloc, allocBig); return res; } + + +/* +#ifndef Z7_ST +void LzmaEnc_GetLzThreads(CLzmaEncHandle p, HANDLE lz_threads[2]) +{ + GET_const_CLzmaEnc_p + lz_threads[0] = p->matchFinderMt.hashSync.thread; + lz_threads[1] = p->matchFinderMt.btSync.thread; +} +#endif +*/ diff --git a/libraries/lzma/C/LzmaEnc.h b/libraries/lzma/C/LzmaEnc.h index 9194ee576d5..9f8039a1032 100644 --- a/libraries/lzma/C/LzmaEnc.h +++ b/libraries/lzma/C/LzmaEnc.h @@ -1,8 +1,8 @@ /* LzmaEnc.h -- LZMA Encoder -2017-07-27 : Igor Pavlov : Public domain */ +2023-04-13 : Igor Pavlov : Public domain */ -#ifndef __LZMA_ENC_H -#define __LZMA_ENC_H +#ifndef ZIP7_INC_LZMA_ENC_H +#define ZIP7_INC_LZMA_ENC_H #include "7zTypes.h" @@ -10,7 +10,7 @@ EXTERN_C_BEGIN #define LZMA_PROPS_SIZE 5 -typedef struct _CLzmaEncProps +typedef struct { int level; /* 0 <= level <= 9 */ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version @@ -23,12 +23,17 @@ typedef struct _CLzmaEncProps int fb; /* 5 <= fb <= 273, default = 32 */ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ int numHashBytes; /* 2, 3 or 4, default = 4 */ + unsigned numHashOutBits; /* default = ? */ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ int numThreads; /* 1 or 2, default = 2 */ + // int _pad; + UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. Encoder uses this value to reduce dictionary size */ + + UInt64 affinity; } CLzmaEncProps; void LzmaEncProps_Init(CLzmaEncProps *p); @@ -49,7 +54,9 @@ UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) */ -typedef void * CLzmaEncHandle; +typedef struct CLzmaEnc CLzmaEnc; +typedef CLzmaEnc * CLzmaEncHandle; +// Z7_DECLARE_HANDLE(CLzmaEncHandle) CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc); void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig); @@ -59,17 +66,17 @@ void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize); SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p); -SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, - ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, + ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); + int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); /* ---------- One Call Interface ---------- */ SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, - ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); + ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); EXTERN_C_END diff --git a/libraries/lzma/C/LzmaLib.c b/libraries/lzma/C/LzmaLib.c new file mode 100644 index 00000000000..785e8848744 --- /dev/null +++ b/libraries/lzma/C/LzmaLib.c @@ -0,0 +1,42 @@ +/* LzmaLib.c -- LZMA library wrapper +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Alloc.h" +#include "LzmaDec.h" +#include "LzmaEnc.h" +#include "LzmaLib.h" + +Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ +) +{ + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + props.lc = lc; + props.lp = lp; + props.pb = pb; + props.fb = fb; + props.numThreads = numThreads; + + return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); +} + + +Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, + const unsigned char *props, size_t propsSize) +{ + ELzmaStatus status; + return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc); +} diff --git a/libraries/lzma/C/LzmaLib.h b/libraries/lzma/C/LzmaLib.h new file mode 100644 index 00000000000..d7c0724de5e --- /dev/null +++ b/libraries/lzma/C/LzmaLib.h @@ -0,0 +1,138 @@ +/* LzmaLib.h -- LZMA library interface +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA_LIB_H +#define ZIP7_INC_LZMA_LIB_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define Z7_STDAPI int Z7_STDCALL + +#define LZMA_PROPS_SIZE 5 + +/* +RAM requirements for LZMA: + for compression: (dictSize * 11.5 + 6 MB) + state_size + for decompression: dictSize + state_size + state_size = (4 + (1.5 << (lc + lp))) KB + by default (lc=3, lp=0), state_size = 16 KB. + +LZMA properties (5 bytes) format + Offset Size Description + 0 1 lc, lp and pb in encoded form. + 1 4 dictSize (little endian). +*/ + +/* +LzmaCompress +------------ + +outPropsSize - + In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + + LZMA Encoder will use defult values for any parameter, if it is + -1 for any from: level, loc, lp, pb, fb, numThreads + 0 for dictSize + +level - compression level: 0 <= level <= 9; + + level dictSize algo fb + 0: 64 KB 0 32 + 1: 256 KB 0 32 + 2: 1 MB 0 32 + 3: 4 MB 0 32 + 4: 16 MB 0 32 + 5: 16 MB 1 32 + 6: 32 MB 1 32 + 7: 32 MB 1 64 + 8: 64 MB 1 64 + 9: 64 MB 1 64 + + The default value for "level" is 5. + + algo = 0 means fast method + algo = 1 means normal method + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + +lc - The number of literal context bits (high bits of previous literal). + It can be in the range from 0 to 8. The default value is 3. + Sometimes lc=4 gives the gain for big files. + +lp - The number of literal pos bits (low bits of current position for literals). + It can be in the range from 0 to 4. The default value is 0. + The lp switch is intended for periodical data when the period is equal to 2^lp. + For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's + better to set lc=0, if you change lp switch. + +pb - The number of pos bits (low bits of current position). + It can be in the range from 0 to 4. The default value is 2. + The pb switch is intended for periodical data when the period is equal 2^pb. + +fb - Word size (the number of fast bytes). + It can be in the range from 5 to 273. The default value is 32. + Usually, a big number gives a little bit better compression ratio and + slower compression process. + +numThreads - The number of thereads. 1 or 2. The default value is 2. + Fast mode (algo = 0) can use only 1 thread. + +In: + dest - output data buffer + destLen - output data buffer size + src - input data + srcLen - input data size +Out: + destLen - processed output size +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* default = (1 << 24) */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ + ); + +/* +LzmaUncompress +-------------- +In: + dest - output data buffer + destLen - output data buffer size + src - input data + srcLen - input data size +Out: + destLen - processed output size + srcLen - processed input size +Returns: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation arror + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src) +*/ + +Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, + const unsigned char *props, size_t propsSize); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/MtCoder.c b/libraries/lzma/C/MtCoder.c new file mode 100644 index 00000000000..6f58abb2a39 --- /dev/null +++ b/libraries/lzma/C/MtCoder.c @@ -0,0 +1,571 @@ +/* MtCoder.c -- Multi-thread Coder +2023-04-13 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "MtCoder.h" + +#ifndef Z7_ST + +static SRes MtProgressThunk_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CMtProgressThunk) + UInt64 inSize2 = 0; + UInt64 outSize2 = 0; + if (inSize != (UInt64)(Int64)-1) + { + inSize2 = inSize - p->inSize; + p->inSize = inSize; + } + if (outSize != (UInt64)(Int64)-1) + { + outSize2 = outSize - p->outSize; + p->outSize = outSize; + } + return MtProgress_ProgressAdd(p->mtProgress, inSize2, outSize2); +} + + +void MtProgressThunk_CreateVTable(CMtProgressThunk *p) +{ + p->vt.Progress = MtProgressThunk_Progress; +} + + + +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } + + +static THREAD_FUNC_DECL ThreadFunc(void *pp); + + +static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) +{ + WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->startEvent); + if (wres == 0) + { + t->stop = False; + if (!Thread_WasCreated(&t->thread)) + wres = Thread_Create(&t->thread, ThreadFunc, t); + if (wres == 0) + wres = Event_Set(&t->startEvent); + } + if (wres == 0) + return SZ_OK; + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +static void MtCoderThread_Destruct(CMtCoderThread *t) +{ + if (Thread_WasCreated(&t->thread)) + { + t->stop = 1; + Event_Set(&t->startEvent); + Thread_Wait_Close(&t->thread); + } + + Event_Close(&t->startEvent); + + if (t->inBuf) + { + ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf); + t->inBuf = NULL; + } +} + + + + +/* + ThreadFunc2() returns: + SZ_OK - in all normal cases (even for stream error or memory allocation error) + SZ_ERROR_THREAD - in case of failure in system synch function +*/ + +static SRes ThreadFunc2(CMtCoderThread *t) +{ + CMtCoder *mtc = t->mtCoder; + + for (;;) + { + unsigned bi; + SRes res; + SRes res2; + BoolInt finished; + unsigned bufIndex; + size_t size; + const Byte *inData; + UInt64 readProcessed = 0; + + RINOK_THREAD(Event_Wait(&mtc->readEvent)) + + /* after Event_Wait(&mtc->readEvent) we must call Event_Set(&mtc->readEvent) in any case to unlock another threads */ + + if (mtc->stopReading) + { + return Event_Set(&mtc->readEvent) == 0 ? SZ_OK : SZ_ERROR_THREAD; + } + + res = MtProgress_GetError(&mtc->mtProgress); + + size = 0; + inData = NULL; + finished = True; + + if (res == SZ_OK) + { + size = mtc->blockSize; + if (mtc->inStream) + { + if (!t->inBuf) + { + t->inBuf = (Byte *)ISzAlloc_Alloc(mtc->allocBig, mtc->blockSize); + if (!t->inBuf) + res = SZ_ERROR_MEM; + } + if (res == SZ_OK) + { + res = SeqInStream_ReadMax(mtc->inStream, t->inBuf, &size); + readProcessed = mtc->readProcessed + size; + mtc->readProcessed = readProcessed; + } + if (res != SZ_OK) + { + mtc->readRes = res; + /* after reading error - we can stop encoding of previous blocks */ + MtProgress_SetError(&mtc->mtProgress, res); + } + else + finished = (size != mtc->blockSize); + } + else + { + size_t rem; + readProcessed = mtc->readProcessed; + rem = mtc->inDataSize - (size_t)readProcessed; + if (size > rem) + size = rem; + inData = mtc->inData + (size_t)readProcessed; + readProcessed += size; + mtc->readProcessed = readProcessed; + finished = (mtc->inDataSize == (size_t)readProcessed); + } + } + + /* we must get some block from blocksSemaphore before Event_Set(&mtc->readEvent) */ + + res2 = SZ_OK; + + if (Semaphore_Wait(&mtc->blocksSemaphore) != 0) + { + res2 = SZ_ERROR_THREAD; + if (res == SZ_OK) + { + res = res2; + // MtProgress_SetError(&mtc->mtProgress, res); + } + } + + bi = mtc->blockIndex; + + if (++mtc->blockIndex >= mtc->numBlocksMax) + mtc->blockIndex = 0; + + bufIndex = (unsigned)(int)-1; + + if (res == SZ_OK) + res = MtProgress_GetError(&mtc->mtProgress); + + if (res != SZ_OK) + finished = True; + + if (!finished) + { + if (mtc->numStartedThreads < mtc->numStartedThreadsLimit + && mtc->expectedDataSize != readProcessed) + { + res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]); + if (res == SZ_OK) + mtc->numStartedThreads++; + else + { + MtProgress_SetError(&mtc->mtProgress, res); + finished = True; + } + } + } + + if (finished) + mtc->stopReading = True; + + RINOK_THREAD(Event_Set(&mtc->readEvent)) + + if (res2 != SZ_OK) + return res2; + + if (res == SZ_OK) + { + CriticalSection_Enter(&mtc->cs); + bufIndex = mtc->freeBlockHead; + mtc->freeBlockHead = mtc->freeBlockList[bufIndex]; + CriticalSection_Leave(&mtc->cs); + + res = mtc->mtCallback->Code(mtc->mtCallbackObject, t->index, bufIndex, + mtc->inStream ? t->inBuf : inData, size, finished); + + // MtProgress_Reinit(&mtc->mtProgress, t->index); + + if (res != SZ_OK) + MtProgress_SetError(&mtc->mtProgress, res); + } + + { + CMtCoderBlock *block = &mtc->blocks[bi]; + block->res = res; + block->bufIndex = bufIndex; + block->finished = finished; + } + + #ifdef MTCODER_USE_WRITE_THREAD + RINOK_THREAD(Event_Set(&mtc->writeEvents[bi])) + #else + { + unsigned wi; + { + CriticalSection_Enter(&mtc->cs); + wi = mtc->writeIndex; + if (wi == bi) + mtc->writeIndex = (unsigned)(int)-1; + else + mtc->ReadyBlocks[bi] = True; + CriticalSection_Leave(&mtc->cs); + } + + if (wi != bi) + { + if (res != SZ_OK || finished) + return 0; + continue; + } + + if (mtc->writeRes != SZ_OK) + res = mtc->writeRes; + + for (;;) + { + if (res == SZ_OK && bufIndex != (unsigned)(int)-1) + { + res = mtc->mtCallback->Write(mtc->mtCallbackObject, bufIndex); + if (res != SZ_OK) + { + mtc->writeRes = res; + MtProgress_SetError(&mtc->mtProgress, res); + } + } + + if (++wi >= mtc->numBlocksMax) + wi = 0; + { + BoolInt isReady; + + CriticalSection_Enter(&mtc->cs); + + if (bufIndex != (unsigned)(int)-1) + { + mtc->freeBlockList[bufIndex] = mtc->freeBlockHead; + mtc->freeBlockHead = bufIndex; + } + + isReady = mtc->ReadyBlocks[wi]; + + if (isReady) + mtc->ReadyBlocks[wi] = False; + else + mtc->writeIndex = wi; + + CriticalSection_Leave(&mtc->cs); + + RINOK_THREAD(Semaphore_Release1(&mtc->blocksSemaphore)) + + if (!isReady) + break; + } + + { + CMtCoderBlock *block = &mtc->blocks[wi]; + if (res == SZ_OK && block->res != SZ_OK) + res = block->res; + bufIndex = block->bufIndex; + finished = block->finished; + } + } + } + #endif + + if (finished || res != SZ_OK) + return 0; + } +} + + +static THREAD_FUNC_DECL ThreadFunc(void *pp) +{ + CMtCoderThread *t = (CMtCoderThread *)pp; + for (;;) + { + if (Event_Wait(&t->startEvent) != 0) + return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; + if (t->stop) + return 0; + { + SRes res = ThreadFunc2(t); + CMtCoder *mtc = t->mtCoder; + if (res != SZ_OK) + { + MtProgress_SetError(&mtc->mtProgress, res); + } + + #ifndef MTCODER_USE_WRITE_THREAD + { + unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads); + if (numFinished == mtc->numStartedThreads) + if (Event_Set(&mtc->finishedEvent) != 0) + return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; + } + #endif + } + } +} + + + +void MtCoder_Construct(CMtCoder *p) +{ + unsigned i; + + p->blockSize = 0; + p->numThreadsMax = 0; + p->expectedDataSize = (UInt64)(Int64)-1; + + p->inStream = NULL; + p->inData = NULL; + p->inDataSize = 0; + + p->progress = NULL; + p->allocBig = NULL; + + p->mtCallback = NULL; + p->mtCallbackObject = NULL; + + p->allocatedBufsSize = 0; + + Event_Construct(&p->readEvent); + Semaphore_Construct(&p->blocksSemaphore); + + for (i = 0; i < MTCODER_THREADS_MAX; i++) + { + CMtCoderThread *t = &p->threads[i]; + t->mtCoder = p; + t->index = i; + t->inBuf = NULL; + t->stop = False; + Event_Construct(&t->startEvent); + Thread_CONSTRUCT(&t->thread) + } + + #ifdef MTCODER_USE_WRITE_THREAD + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + Event_Construct(&p->writeEvents[i]); + #else + Event_Construct(&p->finishedEvent); + #endif + + CriticalSection_Init(&p->cs); + CriticalSection_Init(&p->mtProgress.cs); +} + + + + +static void MtCoder_Free(CMtCoder *p) +{ + unsigned i; + + /* + p->stopReading = True; + if (Event_IsCreated(&p->readEvent)) + Event_Set(&p->readEvent); + */ + + for (i = 0; i < MTCODER_THREADS_MAX; i++) + MtCoderThread_Destruct(&p->threads[i]); + + Event_Close(&p->readEvent); + Semaphore_Close(&p->blocksSemaphore); + + #ifdef MTCODER_USE_WRITE_THREAD + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + Event_Close(&p->writeEvents[i]); + #else + Event_Close(&p->finishedEvent); + #endif +} + + +void MtCoder_Destruct(CMtCoder *p) +{ + MtCoder_Free(p); + + CriticalSection_Delete(&p->cs); + CriticalSection_Delete(&p->mtProgress.cs); +} + + +SRes MtCoder_Code(CMtCoder *p) +{ + unsigned numThreads = p->numThreadsMax; + unsigned numBlocksMax; + unsigned i; + SRes res = SZ_OK; + + if (numThreads > MTCODER_THREADS_MAX) + numThreads = MTCODER_THREADS_MAX; + numBlocksMax = MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads); + + if (p->blockSize < ((UInt32)1 << 26)) numBlocksMax++; + if (p->blockSize < ((UInt32)1 << 24)) numBlocksMax++; + if (p->blockSize < ((UInt32)1 << 22)) numBlocksMax++; + + if (numBlocksMax > MTCODER_BLOCKS_MAX) + numBlocksMax = MTCODER_BLOCKS_MAX; + + if (p->blockSize != p->allocatedBufsSize) + { + for (i = 0; i < MTCODER_THREADS_MAX; i++) + { + CMtCoderThread *t = &p->threads[i]; + if (t->inBuf) + { + ISzAlloc_Free(p->allocBig, t->inBuf); + t->inBuf = NULL; + } + } + p->allocatedBufsSize = p->blockSize; + } + + p->readRes = SZ_OK; + + MtProgress_Init(&p->mtProgress, p->progress); + + #ifdef MTCODER_USE_WRITE_THREAD + for (i = 0; i < numBlocksMax; i++) + { + RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->writeEvents[i])) + } + #else + RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent)) + #endif + + { + RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->readEvent)) + RINOK_THREAD(Semaphore_OptCreateInit(&p->blocksSemaphore, numBlocksMax, numBlocksMax)) + } + + for (i = 0; i < MTCODER_BLOCKS_MAX - 1; i++) + p->freeBlockList[i] = i + 1; + p->freeBlockList[MTCODER_BLOCKS_MAX - 1] = (unsigned)(int)-1; + p->freeBlockHead = 0; + + p->readProcessed = 0; + p->blockIndex = 0; + p->numBlocksMax = numBlocksMax; + p->stopReading = False; + + #ifndef MTCODER_USE_WRITE_THREAD + p->writeIndex = 0; + p->writeRes = SZ_OK; + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + p->ReadyBlocks[i] = False; + p->numFinishedThreads = 0; + #endif + + p->numStartedThreadsLimit = numThreads; + p->numStartedThreads = 0; + + // for (i = 0; i < numThreads; i++) + { + CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++]; + RINOK(MtCoderThread_CreateAndStart(nextThread)) + } + + RINOK_THREAD(Event_Set(&p->readEvent)) + + #ifdef MTCODER_USE_WRITE_THREAD + { + unsigned bi = 0; + + for (;; bi++) + { + if (bi >= numBlocksMax) + bi = 0; + + RINOK_THREAD(Event_Wait(&p->writeEvents[bi])) + + { + const CMtCoderBlock *block = &p->blocks[bi]; + unsigned bufIndex = block->bufIndex; + BoolInt finished = block->finished; + if (res == SZ_OK && block->res != SZ_OK) + res = block->res; + + if (bufIndex != (unsigned)(int)-1) + { + if (res == SZ_OK) + { + res = p->mtCallback->Write(p->mtCallbackObject, bufIndex); + if (res != SZ_OK) + MtProgress_SetError(&p->mtProgress, res); + } + + CriticalSection_Enter(&p->cs); + { + p->freeBlockList[bufIndex] = p->freeBlockHead; + p->freeBlockHead = bufIndex; + } + CriticalSection_Leave(&p->cs); + } + + RINOK_THREAD(Semaphore_Release1(&p->blocksSemaphore)) + + if (finished) + break; + } + } + } + #else + { + WRes wres = Event_Wait(&p->finishedEvent); + res = MY_SRes_HRESULT_FROM_WRes(wres); + } + #endif + + if (res == SZ_OK) + res = p->readRes; + + if (res == SZ_OK) + res = p->mtProgress.res; + + #ifndef MTCODER_USE_WRITE_THREAD + if (res == SZ_OK) + res = p->writeRes; + #endif + + if (res != SZ_OK) + MtCoder_Free(p); + return res; +} + +#endif + +#undef RINOK_THREAD diff --git a/libraries/lzma/C/MtCoder.h b/libraries/lzma/C/MtCoder.h new file mode 100644 index 00000000000..1231d3c2a54 --- /dev/null +++ b/libraries/lzma/C/MtCoder.h @@ -0,0 +1,141 @@ +/* MtCoder.h -- Multi-thread Coder +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_MT_CODER_H +#define ZIP7_INC_MT_CODER_H + +#include "MtDec.h" + +EXTERN_C_BEGIN + +/* + if ( defined MTCODER_USE_WRITE_THREAD) : main thread writes all data blocks to output stream + if (not defined MTCODER_USE_WRITE_THREAD) : any coder thread can write data blocks to output stream +*/ +/* #define MTCODER_USE_WRITE_THREAD */ + +#ifndef Z7_ST + #define MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1) + #define MTCODER_THREADS_MAX 64 + #define MTCODER_BLOCKS_MAX (MTCODER_GET_NUM_BLOCKS_FROM_THREADS(MTCODER_THREADS_MAX) + 3) +#else + #define MTCODER_THREADS_MAX 1 + #define MTCODER_BLOCKS_MAX 1 +#endif + + +#ifndef Z7_ST + + +typedef struct +{ + ICompressProgress vt; + CMtProgress *mtProgress; + UInt64 inSize; + UInt64 outSize; +} CMtProgressThunk; + +void MtProgressThunk_CreateVTable(CMtProgressThunk *p); + +#define MtProgressThunk_INIT(p) { (p)->inSize = 0; (p)->outSize = 0; } + + +struct CMtCoder_; + + +typedef struct +{ + struct CMtCoder_ *mtCoder; + unsigned index; + int stop; + Byte *inBuf; + + CAutoResetEvent startEvent; + CThread thread; +} CMtCoderThread; + + +typedef struct +{ + SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished); + SRes (*Write)(void *p, unsigned outBufIndex); +} IMtCoderCallback2; + + +typedef struct +{ + SRes res; + unsigned bufIndex; + BoolInt finished; +} CMtCoderBlock; + + +typedef struct CMtCoder_ +{ + /* input variables */ + + size_t blockSize; /* size of input block */ + unsigned numThreadsMax; + UInt64 expectedDataSize; + + ISeqInStreamPtr inStream; + const Byte *inData; + size_t inDataSize; + + ICompressProgressPtr progress; + ISzAllocPtr allocBig; + + IMtCoderCallback2 *mtCallback; + void *mtCallbackObject; + + + /* internal variables */ + + size_t allocatedBufsSize; + + CAutoResetEvent readEvent; + CSemaphore blocksSemaphore; + + BoolInt stopReading; + SRes readRes; + + #ifdef MTCODER_USE_WRITE_THREAD + CAutoResetEvent writeEvents[MTCODER_BLOCKS_MAX]; + #else + CAutoResetEvent finishedEvent; + SRes writeRes; + unsigned writeIndex; + Byte ReadyBlocks[MTCODER_BLOCKS_MAX]; + LONG numFinishedThreads; + #endif + + unsigned numStartedThreadsLimit; + unsigned numStartedThreads; + + unsigned numBlocksMax; + unsigned blockIndex; + UInt64 readProcessed; + + CCriticalSection cs; + + unsigned freeBlockHead; + unsigned freeBlockList[MTCODER_BLOCKS_MAX]; + + CMtProgress mtProgress; + CMtCoderBlock blocks[MTCODER_BLOCKS_MAX]; + CMtCoderThread threads[MTCODER_THREADS_MAX]; +} CMtCoder; + + +void MtCoder_Construct(CMtCoder *p); +void MtCoder_Destruct(CMtCoder *p); +SRes MtCoder_Code(CMtCoder *p); + + +#endif + + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/MtDec.c b/libraries/lzma/C/MtDec.c new file mode 100644 index 00000000000..782069926d5 --- /dev/null +++ b/libraries/lzma/C/MtDec.c @@ -0,0 +1,1114 @@ +/* MtDec.c -- Multi-thread Decoder +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO + +// #include +#include + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "MtDec.h" + +#ifndef Z7_ST + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) + +void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress) +{ + p->progress = progress; + p->res = SZ_OK; + p->totalInSize = 0; + p->totalOutSize = 0; +} + + +SRes MtProgress_Progress_ST(CMtProgress *p) +{ + if (p->res == SZ_OK && p->progress) + if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) + p->res = SZ_ERROR_PROGRESS; + return p->res; +} + + +SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize) +{ + SRes res; + CriticalSection_Enter(&p->cs); + + p->totalInSize += inSize; + p->totalOutSize += outSize; + if (p->res == SZ_OK && p->progress) + if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) + p->res = SZ_ERROR_PROGRESS; + res = p->res; + + CriticalSection_Leave(&p->cs); + return res; +} + + +SRes MtProgress_GetError(CMtProgress *p) +{ + SRes res; + CriticalSection_Enter(&p->cs); + res = p->res; + CriticalSection_Leave(&p->cs); + return res; +} + + +void MtProgress_SetError(CMtProgress *p, SRes res) +{ + CriticalSection_Enter(&p->cs); + if (p->res == SZ_OK) + p->res = res; + CriticalSection_Leave(&p->cs); +} + + +#define RINOK_THREAD(x) RINOK_WRes(x) + + +struct CMtDecBufLink_ +{ + struct CMtDecBufLink_ *next; + void *pad[3]; +}; + +typedef struct CMtDecBufLink_ CMtDecBufLink; + +#define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink) +#define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET) + + + +static THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp); + + +static WRes MtDecThread_CreateEvents(CMtDecThread *t) +{ + WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->canWrite); + if (wres == 0) + { + wres = AutoResetEvent_OptCreate_And_Reset(&t->canRead); + if (wres == 0) + return SZ_OK; + } + return wres; +} + + +static SRes MtDecThread_CreateAndStart(CMtDecThread *t) +{ + WRes wres = MtDecThread_CreateEvents(t); + // wres = 17; // for test + if (wres == 0) + { + if (Thread_WasCreated(&t->thread)) + return SZ_OK; + wres = Thread_Create(&t->thread, MtDec_ThreadFunc, t); + if (wres == 0) + return SZ_OK; + } + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +void MtDecThread_FreeInBufs(CMtDecThread *t) +{ + if (t->inBuf) + { + void *link = t->inBuf; + t->inBuf = NULL; + do + { + void *next = ((CMtDecBufLink *)link)->next; + ISzAlloc_Free(t->mtDec->alloc, link); + link = next; + } + while (link); + } +} + + +static void MtDecThread_CloseThread(CMtDecThread *t) +{ + if (Thread_WasCreated(&t->thread)) + { + Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */ + Event_Set(&t->canRead); + Thread_Wait_Close(&t->thread); + } + + Event_Close(&t->canRead); + Event_Close(&t->canWrite); +} + +static void MtDec_CloseThreads(CMtDec *p) +{ + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + MtDecThread_CloseThread(&p->threads[i]); +} + +static void MtDecThread_Destruct(CMtDecThread *t) +{ + MtDecThread_CloseThread(t); + MtDecThread_FreeInBufs(t); +} + + + +static SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted) +{ + SRes res; + CriticalSection_Enter(&p->mtProgress.cs); + *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); + res = p->mtProgress.res; + CriticalSection_Leave(&p->mtProgress.cs); + return res; +} + +static SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted) +{ + SRes res; + CriticalSection_Enter(&p->mtProgress.cs); + + p->mtProgress.totalInSize += inSize; + p->mtProgress.totalOutSize += outSize; + if (p->mtProgress.res == SZ_OK && p->mtProgress.progress) + if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK) + p->mtProgress.res = SZ_ERROR_PROGRESS; + + *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); + res = p->mtProgress.res; + + CriticalSection_Leave(&p->mtProgress.cs); + + return res; +} + +static void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex) +{ + CriticalSection_Enter(&p->mtProgress.cs); + if (!p->needInterrupt || interruptIndex < p->interruptIndex) + { + p->interruptIndex = interruptIndex; + p->needInterrupt = True; + } + CriticalSection_Leave(&p->mtProgress.cs); +} + +Byte *MtDec_GetCrossBuff(CMtDec *p) +{ + Byte *cr = p->crossBlock; + if (!cr) + { + cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); + if (!cr) + return NULL; + p->crossBlock = cr; + } + return MTDEC__DATA_PTR_FROM_LINK(cr); +} + + +/* + MtDec_ThreadFunc2() returns: + 0 - in all normal cases (even for stream error or memory allocation error) + (!= 0) - WRes error return by system threading function +*/ + +// #define MTDEC_ProgessStep (1 << 22) +#define MTDEC_ProgessStep (1 << 0) + +static WRes MtDec_ThreadFunc2(CMtDecThread *t) +{ + CMtDec *p = t->mtDec; + + PRF_STR_INT("MtDec_ThreadFunc2", t->index) + + // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index); + + for (;;) + { + SRes res, codeRes; + BoolInt wasInterrupted, isAllocError, overflow, finish; + SRes threadingErrorSRes; + BoolInt needCode, needWrite, needContinue; + + size_t inDataSize_Start; + UInt64 inDataSize; + // UInt64 inDataSize_Full; + + UInt64 blockIndex; + + UInt64 inPrev = 0; + UInt64 outPrev = 0; + UInt64 inCodePos; + UInt64 outCodePos; + + Byte *afterEndData = NULL; + size_t afterEndData_Size = 0; + BoolInt afterEndData_IsCross = False; + + BoolInt canCreateNewThread = False; + // CMtDecCallbackInfo parse; + CMtDecThread *nextThread; + + PRF_STR_INT("=============== Event_Wait(&t->canRead)", t->index) + + RINOK_THREAD(Event_Wait(&t->canRead)) + if (p->exitThread) + return 0; + + PRF_STR_INT("after Event_Wait(&t->canRead)", t->index) + + // if (t->index == 3) return 19; // for test + + blockIndex = p->blockIndex++; + + // PRF(printf("\ncanRead\n")) + + res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); + + finish = p->readWasFinished; + needCode = False; + needWrite = False; + isAllocError = False; + overflow = False; + + inDataSize_Start = 0; + inDataSize = 0; + // inDataSize_Full = 0; + + if (res == SZ_OK && !wasInterrupted) + { + // if (p->inStream) + { + CMtDecBufLink *prev = NULL; + CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; + size_t crossSize = p->crossEnd - p->crossStart; + + PRF(printf("\ncrossSize = %d\n", crossSize)); + + for (;;) + { + if (!link) + { + link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); + if (!link) + { + finish = True; + // p->allocError_for_Read_BlockIndex = blockIndex; + isAllocError = True; + break; + } + link->next = NULL; + if (prev) + { + // static unsigned g_num = 0; + // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev)); + prev->next = link; + } + else + t->inBuf = (void *)link; + } + + { + Byte *data = MTDEC__DATA_PTR_FROM_LINK(link); + Byte *parseData = data; + size_t size; + + if (crossSize != 0) + { + inDataSize = crossSize; + // inDataSize_Full = inDataSize; + inDataSize_Start = crossSize; + size = crossSize; + parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; + PRF(printf("\ncross : crossStart = %7d crossEnd = %7d finish = %1d", + (int)p->crossStart, (int)p->crossEnd, (int)finish)); + } + else + { + size = p->inBufSize; + + res = SeqInStream_ReadMax(p->inStream, data, &size); + + // size = 10; // test + + inDataSize += size; + // inDataSize_Full = inDataSize; + if (!prev) + inDataSize_Start = size; + + p->readProcessed += size; + finish = (size != p->inBufSize); + if (finish) + p->readWasFinished = True; + + // res = E_INVALIDARG; // test + + if (res != SZ_OK) + { + // PRF(printf("\nRead error = %d\n", res)) + // we want to decode all data before error + p->readRes = res; + // p->readError_BlockIndex = blockIndex; + p->readWasFinished = True; + finish = True; + res = SZ_OK; + // break; + } + + if (inDataSize - inPrev >= MTDEC_ProgessStep) + { + res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); + if (res != SZ_OK || wasInterrupted) + break; + inPrev = inDataSize; + } + } + + { + CMtDecCallbackInfo parse; + + parse.startCall = (prev == NULL); + parse.src = parseData; + parse.srcSize = size; + parse.srcFinished = finish; + parse.canCreateNewThread = True; + + PRF(printf("\nParse size = %d\n", (unsigned)size)); + + p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse); + + PRF(printf(" Parse processed = %d, state = %d \n", (unsigned)parse.srcSize, (unsigned)parse.state)); + + needWrite = True; + canCreateNewThread = parse.canCreateNewThread; + + // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize); + + if ( + // parseRes != SZ_OK || + // inDataSize - (size - parse.srcSize) > p->inBlockMax + // || + parse.state == MTDEC_PARSE_OVERFLOW + // || wasInterrupted + ) + { + // Overflow or Parse error - switch from MT decoding to ST decoding + finish = True; + overflow = True; + + { + PRF(printf("\n Overflow")); + // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished)); + PRF(printf("\n inDataSize = %d", (unsigned)inDataSize)); + } + + if (crossSize != 0) + memcpy(data, parseData, size); + p->crossStart = 0; + p->crossEnd = 0; + break; + } + + if (crossSize != 0) + { + memcpy(data, parseData, parse.srcSize); + p->crossStart += parse.srcSize; + } + + if (parse.state != MTDEC_PARSE_CONTINUE || finish) + { + // we don't need to parse in current thread anymore + + if (parse.state == MTDEC_PARSE_END) + finish = True; + + needCode = True; + // p->crossFinished = finish; + + if (parse.srcSize == size) + { + // full parsed - no cross transfer + p->crossStart = 0; + p->crossEnd = 0; + break; + } + + if (parse.state == MTDEC_PARSE_END) + { + afterEndData = parseData + parse.srcSize; + afterEndData_Size = size - parse.srcSize; + if (crossSize != 0) + afterEndData_IsCross = True; + // we reduce data size to required bytes (parsed only) + inDataSize -= afterEndData_Size; + if (!prev) + inDataSize_Start = parse.srcSize; + break; + } + + { + // partial parsed - need cross transfer + if (crossSize != 0) + inDataSize = parse.srcSize; // it's only parsed now + else + { + // partial parsed - is not in initial cross block - we need to copy new data to cross block + Byte *cr = MtDec_GetCrossBuff(p); + if (!cr) + { + { + PRF(printf("\ncross alloc error error\n")); + // res = SZ_ERROR_MEM; + finish = True; + // p->allocError_for_Read_BlockIndex = blockIndex; + isAllocError = True; + break; + } + } + + { + size_t crSize = size - parse.srcSize; + inDataSize -= crSize; + p->crossEnd = crSize; + p->crossStart = 0; + memcpy(cr, parseData + parse.srcSize, crSize); + } + } + + // inDataSize_Full = inDataSize; + if (!prev) + inDataSize_Start = parse.srcSize; // it's partial size (parsed only) + + finish = False; + break; + } + } + + if (parse.srcSize != size) + { + res = SZ_ERROR_FAIL; + PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res)); + break; + } + } + } + + prev = link; + link = link->next; + + if (crossSize != 0) + { + crossSize = 0; + p->crossStart = 0; + p->crossEnd = 0; + } + } + } + + if (res == SZ_OK) + res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted); + } + + codeRes = SZ_OK; + + if (res == SZ_OK && needCode && !wasInterrupted) + { + codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index); + if (codeRes != SZ_OK) + { + needCode = False; + finish = True; + // SZ_ERROR_MEM is expected error here. + // if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later. + // if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding. + } + } + + if (res != SZ_OK || wasInterrupted) + finish = True; + + nextThread = NULL; + threadingErrorSRes = SZ_OK; + + if (!finish) + { + if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread) + { + SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]); + if (res2 == SZ_OK) + { + // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads)); + p->numStartedThreads++; + } + else + { + PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads)); + if (p->numStartedThreads == 1) + { + // if only one thread is possible, we leave muti-threading code + finish = True; + needCode = False; + threadingErrorSRes = res2; + } + else + p->numStartedThreads_Limit = p->numStartedThreads; + } + } + + if (!finish) + { + unsigned nextIndex = t->index + 1; + nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex]; + RINOK_THREAD(Event_Set(&nextThread->canRead)) + // We have started executing for new iteration (with next thread) + // And that next thread now is responsible for possible exit from decoding (threading_code) + } + } + + // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite) + // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case + // if ( finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block): + // - if (needContinue) after Write(&needContinue), we restore decoding with new iteration + // - otherwise we stop decoding and exit from MtDec_ThreadFunc2() + + // Don't change (finish) variable in the further code + + + // ---------- CODE ---------- + + inPrev = 0; + outPrev = 0; + inCodePos = 0; + outCodePos = 0; + + if (res == SZ_OK && needCode && codeRes == SZ_OK) + { + BoolInt isStartBlock = True; + CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; + + for (;;) + { + size_t inSize; + int stop; + + if (isStartBlock) + inSize = inDataSize_Start; + else + { + UInt64 rem = inDataSize - inCodePos; + inSize = p->inBufSize; + if (inSize > rem) + inSize = (size_t)rem; + } + + inCodePos += inSize; + stop = True; + + codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index, + (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize, + (inCodePos == inDataSize), // srcFinished + &inCodePos, &outCodePos, &stop); + + if (codeRes != SZ_OK) + { + PRF(printf("\nCode Interrupt error = %x\n", codeRes)); + // we interrupt only later blocks + MtDec_Interrupt(p, blockIndex); + break; + } + + if (stop || inCodePos == inDataSize) + break; + + { + const UInt64 inDelta = inCodePos - inPrev; + const UInt64 outDelta = outCodePos - outPrev; + if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep) + { + // Sleep(1); + res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted); + if (res != SZ_OK || wasInterrupted) + break; + inPrev = inCodePos; + outPrev = outCodePos; + } + } + + link = link->next; + isStartBlock = False; + } + } + + + // ---------- WRITE ---------- + + RINOK_THREAD(Event_Wait(&t->canWrite)) + + { + BoolInt isErrorMode = False; + BoolInt canRecode = True; + BoolInt needWriteToStream = needWrite; + + if (p->exitThread) return 0; // it's never executed in normal cases + + if (p->wasInterrupted) + wasInterrupted = True; + else + { + if (codeRes != SZ_OK) // || !needCode // check it !!! + { + p->wasInterrupted = True; + p->codeRes = codeRes; + if (codeRes == SZ_ERROR_MEM) + isAllocError = True; + } + + if (threadingErrorSRes) + { + p->wasInterrupted = True; + p->threadingErrorSRes = threadingErrorSRes; + needWriteToStream = False; + } + if (isAllocError) + { + p->wasInterrupted = True; + p->isAllocError = True; + needWriteToStream = False; + } + if (overflow) + { + p->wasInterrupted = True; + p->overflow = True; + needWriteToStream = False; + } + } + + if (needCode) + { + if (wasInterrupted) + { + inCodePos = 0; + outCodePos = 0; + } + { + const UInt64 inDelta = inCodePos - inPrev; + const UInt64 outDelta = outCodePos - outPrev; + // if (inDelta != 0 || outDelta != 0) + res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta); + } + } + + needContinue = (!finish); + + // if (res == SZ_OK && needWrite && !wasInterrupted) + if (needWrite) + { + // p->inProcessed += inCodePos; + + PRF(printf("\n--Write afterSize = %d\n", (unsigned)afterEndData_Size)); + + res = p->mtCallback->Write(p->mtCallbackObject, t->index, + res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite + afterEndData, afterEndData_Size, afterEndData_IsCross, + &needContinue, + &canRecode); + + // res = SZ_ERROR_FAIL; // for test + + PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue)); + PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed)); + + if (res != SZ_OK) + { + PRF(printf("\nWrite error = %d\n", res)); + isErrorMode = True; + p->wasInterrupted = True; + } + if (res != SZ_OK + || (!needContinue && !finish)) + { + PRF(printf("\nWrite Interrupt error = %x\n", res)); + MtDec_Interrupt(p, blockIndex); + } + } + + if (canRecode) + if (!needCode + || res != SZ_OK + || p->wasInterrupted + || codeRes != SZ_OK + || wasInterrupted + || p->numFilledThreads != 0 + || isErrorMode) + { + if (p->numFilledThreads == 0) + p->filledThreadStart = t->index; + if (inDataSize != 0 || !finish) + { + t->inDataSize_Start = inDataSize_Start; + t->inDataSize = inDataSize; + p->numFilledThreads++; + } + PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads)); + PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart)); + } + + if (!finish) + { + RINOK_THREAD(Event_Set(&nextThread->canWrite)) + } + else + { + if (needContinue) + { + // we restore decoding with new iteration + RINOK_THREAD(Event_Set(&p->threads[0].canWrite)) + } + else + { + // we exit from decoding + if (t->index == 0) + return SZ_OK; + p->exitThread = True; + } + RINOK_THREAD(Event_Set(&p->threads[0].canRead)) + } + } + } +} + +#ifdef _WIN32 +#define USE_ALLOCA +#endif + +#ifdef USE_ALLOCA +#ifdef _WIN32 +#include +#else +#include +#endif +#endif + + +static THREAD_FUNC_DECL MtDec_ThreadFunc1(void *pp) +{ + WRes res; + + CMtDecThread *t = (CMtDecThread *)pp; + CMtDec *p; + + // fprintf(stdout, "\n%d = %p\n", t->index, &t); + + res = MtDec_ThreadFunc2(t); + p = t->mtDec; + if (res == 0) + return (THREAD_FUNC_RET_TYPE)(UINT_PTR)p->exitThreadWRes; + { + // it's unexpected situation for some threading function error + if (p->exitThreadWRes == 0) + p->exitThreadWRes = res; + PRF(printf("\nthread exit error = %d\n", res)); + p->exitThread = True; + Event_Set(&p->threads[0].canRead); + Event_Set(&p->threads[0].canWrite); + MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res)); + } + return (THREAD_FUNC_RET_TYPE)(UINT_PTR)res; +} + +static Z7_NO_INLINE THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp) +{ + #ifdef USE_ALLOCA + CMtDecThread *t = (CMtDecThread *)pp; + // fprintf(stderr, "\n%d = %p - before", t->index, &t); + t->allocaPtr = alloca(t->index * 128); + #endif + return MtDec_ThreadFunc1(pp); +} + + +int MtDec_PrepareRead(CMtDec *p) +{ + if (p->crossBlock && p->crossStart == p->crossEnd) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + if (i > p->numStartedThreads + || p->numFilledThreads <= + (i >= p->filledThreadStart ? + i - p->filledThreadStart : + i + p->numStartedThreads - p->filledThreadStart)) + MtDecThread_FreeInBufs(&p->threads[i]); + } + + return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd); +} + + +const Byte *MtDec_Read(CMtDec *p, size_t *inLim) +{ + while (p->numFilledThreads != 0) + { + CMtDecThread *t = &p->threads[p->filledThreadStart]; + + if (*inLim != 0) + { + { + void *link = t->inBuf; + void *next = ((CMtDecBufLink *)link)->next; + ISzAlloc_Free(p->alloc, link); + t->inBuf = next; + } + + if (t->inDataSize == 0) + { + MtDecThread_FreeInBufs(t); + if (--p->numFilledThreads == 0) + break; + if (++p->filledThreadStart == p->numStartedThreads) + p->filledThreadStart = 0; + t = &p->threads[p->filledThreadStart]; + } + } + + { + size_t lim = t->inDataSize_Start; + if (lim != 0) + t->inDataSize_Start = 0; + else + { + UInt64 rem = t->inDataSize; + lim = p->inBufSize; + if (lim > rem) + lim = (size_t)rem; + } + t->inDataSize -= lim; + *inLim = lim; + return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf); + } + } + + { + size_t crossSize = p->crossEnd - p->crossStart; + if (crossSize != 0) + { + const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; + *inLim = crossSize; + p->crossStart = 0; + p->crossEnd = 0; + return data; + } + *inLim = 0; + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + return NULL; + } +} + + +void MtDec_Construct(CMtDec *p) +{ + unsigned i; + + p->inBufSize = (size_t)1 << 18; + + p->numThreadsMax = 0; + + p->inStream = NULL; + + // p->inData = NULL; + // p->inDataSize = 0; + + p->crossBlock = NULL; + p->crossStart = 0; + p->crossEnd = 0; + + p->numFilledThreads = 0; + + p->progress = NULL; + p->alloc = NULL; + + p->mtCallback = NULL; + p->mtCallbackObject = NULL; + + p->allocatedBufsSize = 0; + + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CMtDecThread *t = &p->threads[i]; + t->mtDec = p; + t->index = i; + t->inBuf = NULL; + Event_Construct(&t->canRead); + Event_Construct(&t->canWrite); + Thread_CONSTRUCT(&t->thread) + } + + // Event_Construct(&p->finishedEvent); + + CriticalSection_Init(&p->mtProgress.cs); +} + + +static void MtDec_Free(CMtDec *p) +{ + unsigned i; + + p->exitThread = True; + + for (i = 0; i < MTDEC_THREADS_MAX; i++) + MtDecThread_Destruct(&p->threads[i]); + + // Event_Close(&p->finishedEvent); + + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } +} + + +void MtDec_Destruct(CMtDec *p) +{ + MtDec_Free(p); + + CriticalSection_Delete(&p->mtProgress.cs); +} + + +SRes MtDec_Code(CMtDec *p) +{ + unsigned i; + + p->inProcessed = 0; + + p->blockIndex = 1; // it must be larger than not_defined index (0) + p->isAllocError = False; + p->overflow = False; + p->threadingErrorSRes = SZ_OK; + + p->needContinue = True; + + p->readWasFinished = False; + p->needInterrupt = False; + p->interruptIndex = (UInt64)(Int64)-1; + + p->readProcessed = 0; + p->readRes = SZ_OK; + p->codeRes = SZ_OK; + p->wasInterrupted = False; + + p->crossStart = 0; + p->crossEnd = 0; + + p->filledThreadStart = 0; + p->numFilledThreads = 0; + + { + unsigned numThreads = p->numThreadsMax; + if (numThreads > MTDEC_THREADS_MAX) + numThreads = MTDEC_THREADS_MAX; + p->numStartedThreads_Limit = numThreads; + p->numStartedThreads = 0; + } + + if (p->inBufSize != p->allocatedBufsSize) + { + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CMtDecThread *t = &p->threads[i]; + if (t->inBuf) + MtDecThread_FreeInBufs(t); + } + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + + p->allocatedBufsSize = p->inBufSize; + } + + MtProgress_Init(&p->mtProgress, p->progress); + + // RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent)) + p->exitThread = False; + p->exitThreadWRes = 0; + + { + WRes wres; + SRes sres; + CMtDecThread *nextThread = &p->threads[p->numStartedThreads++]; + // wres = MtDecThread_CreateAndStart(nextThread); + wres = MtDecThread_CreateEvents(nextThread); + if (wres == 0) { wres = Event_Set(&nextThread->canWrite); + if (wres == 0) { wres = Event_Set(&nextThread->canRead); + if (wres == 0) { THREAD_FUNC_RET_TYPE res = MtDec_ThreadFunc(nextThread); + wres = (WRes)(UINT_PTR)res; + if (wres != 0) + { + p->needContinue = False; + MtDec_CloseThreads(p); + }}}} + + // wres = 17; // for test + // wres = Event_Wait(&p->finishedEvent); + + sres = MY_SRes_HRESULT_FROM_WRes(wres); + + if (sres != 0) + p->threadingErrorSRes = sres; + + if ( + // wres == 0 + // wres != 0 + // || p->mtc.codeRes == SZ_ERROR_MEM + p->isAllocError + || p->threadingErrorSRes != SZ_OK + || p->overflow) + { + // p->needContinue = True; + } + else + p->needContinue = False; + + if (p->needContinue) + return SZ_OK; + + // if (sres != SZ_OK) + return sres; + // return SZ_ERROR_FAIL; + } +} + +#endif + +#undef PRF diff --git a/libraries/lzma/C/MtDec.h b/libraries/lzma/C/MtDec.h new file mode 100644 index 00000000000..c28e8d9acfa --- /dev/null +++ b/libraries/lzma/C/MtDec.h @@ -0,0 +1,202 @@ +/* MtDec.h -- Multi-thread Decoder +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_MT_DEC_H +#define ZIP7_INC_MT_DEC_H + +#include "7zTypes.h" + +#ifndef Z7_ST +#include "Threads.h" +#endif + +EXTERN_C_BEGIN + +#ifndef Z7_ST + +#ifndef Z7_ST + #define MTDEC_THREADS_MAX 32 +#else + #define MTDEC_THREADS_MAX 1 +#endif + + +typedef struct +{ + ICompressProgressPtr progress; + SRes res; + UInt64 totalInSize; + UInt64 totalOutSize; + CCriticalSection cs; +} CMtProgress; + +void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress); +SRes MtProgress_Progress_ST(CMtProgress *p); +SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize); +SRes MtProgress_GetError(CMtProgress *p); +void MtProgress_SetError(CMtProgress *p, SRes res); + +struct CMtDec; + +typedef struct +{ + struct CMtDec_ *mtDec; + unsigned index; + void *inBuf; + + size_t inDataSize_Start; // size of input data in start block + UInt64 inDataSize; // total size of input data in all blocks + + CThread thread; + CAutoResetEvent canRead; + CAutoResetEvent canWrite; + void *allocaPtr; +} CMtDecThread; + +void MtDecThread_FreeInBufs(CMtDecThread *t); + + +typedef enum +{ + MTDEC_PARSE_CONTINUE, // continue this block with more input data + MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread + MTDEC_PARSE_NEW, // new block + MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue) +} EMtDecParseState; + +typedef struct +{ + // in + int startCall; + const Byte *src; + size_t srcSize; + // in : (srcSize == 0) is allowed + // out : it's allowed to return less that actually was used ? + int srcFinished; + + // out + EMtDecParseState state; + BoolInt canCreateNewThread; + UInt64 outPos; // check it (size_t) +} CMtDecCallbackInfo; + + +typedef struct +{ + void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci); + + // PreCode() and Code(): + // (SRes_return_result != SZ_OK) means stop decoding, no need another blocks + SRes (*PreCode)(void *p, unsigned coderIndex); + SRes (*Code)(void *p, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop); + // stop - means stop another Code calls + + + /* Write() must be called, if Parse() was called + set (needWrite) if + { + && (was not interrupted by progress) + && (was not interrupted in previous block) + } + + out: + if (*needContinue), decoder still need to continue decoding with new iteration, + even after MTDEC_PARSE_END + if (*canRecode), we didn't flush current block data, so we still can decode current block later. + */ + SRes (*Write)(void *p, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, BoolInt isCross, + // int srcFinished, + BoolInt *needContinue, + BoolInt *canRecode); + +} IMtDecCallback2; + + + +typedef struct CMtDec_ +{ + /* input variables */ + + size_t inBufSize; /* size of input block */ + unsigned numThreadsMax; + // size_t inBlockMax; + unsigned numThreadsMax_2; + + ISeqInStreamPtr inStream; + // const Byte *inData; + // size_t inDataSize; + + ICompressProgressPtr progress; + ISzAllocPtr alloc; + + IMtDecCallback2 *mtCallback; + void *mtCallbackObject; + + + /* internal variables */ + + size_t allocatedBufsSize; + + BoolInt exitThread; + WRes exitThreadWRes; + + UInt64 blockIndex; + BoolInt isAllocError; + BoolInt overflow; + SRes threadingErrorSRes; + + BoolInt needContinue; + + // CAutoResetEvent finishedEvent; + + SRes readRes; + SRes codeRes; + + BoolInt wasInterrupted; + + unsigned numStartedThreads_Limit; + unsigned numStartedThreads; + + Byte *crossBlock; + size_t crossStart; + size_t crossEnd; + UInt64 readProcessed; + BoolInt readWasFinished; + UInt64 inProcessed; + + unsigned filledThreadStart; + unsigned numFilledThreads; + + #ifndef Z7_ST + BoolInt needInterrupt; + UInt64 interruptIndex; + CMtProgress mtProgress; + CMtDecThread threads[MTDEC_THREADS_MAX]; + #endif +} CMtDec; + + +void MtDec_Construct(CMtDec *p); +void MtDec_Destruct(CMtDec *p); + +/* +MtDec_Code() returns: + SZ_OK - in most cases + MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function +*/ + +SRes MtDec_Code(CMtDec *p); +Byte *MtDec_GetCrossBuff(CMtDec *p); + +int MtDec_PrepareRead(CMtDec *p); +const Byte *MtDec_Read(CMtDec *p, size_t *inLim); + +#endif + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/Ppmd.h b/libraries/lzma/C/Ppmd.h index a5c1e3ef254..66b26266ffd 100644 --- a/libraries/lzma/C/Ppmd.h +++ b/libraries/lzma/C/Ppmd.h @@ -1,15 +1,24 @@ /* Ppmd.h -- PPMD codec common code -2017-04-03 : Igor Pavlov : Public domain +2023-03-05 : Igor Pavlov : Public domain This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ -#ifndef __PPMD_H -#define __PPMD_H +#ifndef ZIP7_INC_PPMD_H +#define ZIP7_INC_PPMD_H #include "CpuArch.h" EXTERN_C_BEGIN -#ifdef MY_CPU_32BIT +#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) +/* + PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block. + if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields. + if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields. + if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed, + if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional, + and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit. + PPMD code works slightly faster in (PPMD_32BIT) mode. +*/ #define PPMD_32BIT #endif @@ -28,7 +37,7 @@ EXTERN_C_BEGIN #define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) #define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) -#pragma pack(push, 1) +MY_CPU_pragma_pack_push_1 /* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ /* SEE-contexts for PPM-contexts with masked symbols */ @@ -39,42 +48,117 @@ typedef struct Byte Count; /* Count to next change of Shift */ } CPpmd_See; -#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ - { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } +#define Ppmd_See_UPDATE(p) \ + { if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ = (UInt16)((p)->Summ << 1); \ + (p)->Count = (Byte)(3 << (p)->Shift++); }} + typedef struct { Byte Symbol; Byte Freq; - UInt16 SuccessorLow; - UInt16 SuccessorHigh; + UInt16 Successor_0; + UInt16 Successor_1; } CPpmd_State; -#pragma pack(pop) - -typedef - #ifdef PPMD_32BIT - CPpmd_State * - #else - UInt32 - #endif - CPpmd_State_Ref; - -typedef - #ifdef PPMD_32BIT - void * - #else - UInt32 - #endif - CPpmd_Void_Ref; - -typedef - #ifdef PPMD_32BIT - Byte * - #else - UInt32 - #endif - CPpmd_Byte_Ref; +typedef struct CPpmd_State2_ +{ + Byte Symbol; + Byte Freq; +} CPpmd_State2; + +typedef struct CPpmd_State4_ +{ + UInt16 Successor_0; + UInt16 Successor_1; +} CPpmd_State4; + +MY_CPU_pragma_pop + +/* + PPMD code can write full CPpmd_State structure data to CPpmd*_Context + at (byte offset = 2) instead of some fields of original CPpmd*_Context structure. + + If we use pointers to different types, but that point to shared + memory space, we can have aliasing problem (strict aliasing). + + XLC compiler in -O2 mode can change the order of memory write instructions + in relation to read instructions, if we have use pointers to different types. + + To solve that aliasing problem we use combined CPpmd*_Context structure + with unions that contain the fields from both structures: + the original CPpmd*_Context and CPpmd_State. + So we can access the fields from both structures via one pointer, + and the compiler doesn't change the order of write instructions + in relation to read instructions. + + If we don't use memory write instructions to shared memory in + some local code, and we use only reading instructions (read only), + then probably it's safe to use pointers to different types for reading. +*/ + + + +#ifdef PPMD_32BIT + + #define Ppmd_Ref_Type(type) type * + #define Ppmd_GetRef(p, ptr) (ptr) + #define Ppmd_GetPtr(p, ptr) (ptr) + #define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr) + +#else + + #define Ppmd_Ref_Type(type) UInt32 + #define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) + #define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs)) + +#endif // PPMD_32BIT + + +typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref; +typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref; +typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref; + + +/* +#ifdef MY_CPU_LE_UNALIGN +// the unaligned 32-bit access latency can be too large, if the data is not in L1 cache. +#define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0) +#define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v) + +#else +*/ + +/* + We can write 16-bit halves to 32-bit (Successor) field in any selected order. + But the native order is more consistent way. + So we use the native order, if LE/BE order can be detected here at compile time. +*/ + +#ifdef MY_CPU_BE + + #define Ppmd_GET_SUCCESSOR(p) \ + ( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) ) + + #define Ppmd_SET_SUCCESSOR(p, v) { \ + (p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \ + (p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); } + +#else + + #define Ppmd_GET_SUCCESSOR(p) \ + ( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) ) + + #define Ppmd_SET_SUCCESSOR(p, v) { \ + (p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \ + (p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); } + +#endif + +// #endif + #define PPMD_SetAllBitsIn256Bytes(p) \ { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \ diff --git a/libraries/lzma/C/Ppmd7.c b/libraries/lzma/C/Ppmd7.c index 470aadccf1d..6e1307e2d39 100644 --- a/libraries/lzma/C/Ppmd7.c +++ b/libraries/lzma/C/Ppmd7.c @@ -1,5 +1,5 @@ /* Ppmd7.c -- PPMdH codec -2018-07-04 : Igor Pavlov : Public domain +2023-04-02 : Igor Pavlov : Public domain This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ #include "Precomp.h" @@ -8,21 +8,23 @@ This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ #include "Ppmd7.h" -const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; -static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; +/* define PPMD7_ORDER_0_SUPPPORT to suport order-0 mode, unsupported by orignal PPMd var.H. code */ +// #define PPMD7_ORDER_0_SUPPPORT + +MY_ALIGN(16) +static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +MY_ALIGN(16) +static const UInt16 PPMD7_kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; #define MAX_FREQ 124 #define UNIT_SIZE 12 #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) #define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) -#define I2U(indx) (p->Indx2Units[indx]) +#define I2U(indx) ((unsigned)p->Indx2Units[indx]) +#define I2U_UInt16(indx) ((UInt16)p->Indx2Units[indx]) -#ifdef PPMD_32BIT - #define REF(ptr) (ptr) -#else - #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) -#endif +#define REF(ptr) Ppmd_GetRef(p, ptr) #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) @@ -31,17 +33,11 @@ static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x #define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) #define SUFFIX(ctx) CTX((ctx)->Suffix) -typedef CPpmd7_Context * CTX_PTR; +typedef CPpmd7_Context * PPMD7_CTX_PTR; struct CPpmd7_Node_; -typedef - #ifdef PPMD_32BIT - struct CPpmd7_Node_ * - #else - UInt32 - #endif - CPpmd7_Node_Ref; +typedef Ppmd_Ref_Type(struct CPpmd7_Node_) CPpmd7_Node_Ref; typedef struct CPpmd7_Node_ { @@ -51,17 +47,13 @@ typedef struct CPpmd7_Node_ CPpmd7_Node_Ref Prev; } CPpmd7_Node; -#ifdef PPMD_32BIT - #define NODE(ptr) (ptr) -#else - #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) -#endif +#define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd7_Node) void Ppmd7_Construct(CPpmd7 *p) { unsigned i, k, m; - p->Base = 0; + p->Base = NULL; for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) { @@ -77,6 +69,7 @@ void Ppmd7_Construct(CPpmd7 *p) for (i = 0; i < 3; i++) p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) { p->NS2Indx[i] = (Byte)m; @@ -84,183 +77,236 @@ void Ppmd7_Construct(CPpmd7 *p) k = (++m) - 2; } - memset(p->HB2Flag, 0, 0x40); - memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); + memcpy(p->ExpEscape, PPMD7_kExpEscape, 16); } + void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc) { ISzAlloc_Free(alloc, p->Base); p->Size = 0; - p->Base = 0; + p->Base = NULL; } + BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc) { if (!p->Base || p->Size != size) { - size_t size2; Ppmd7_Free(p, alloc); - size2 = 0 - #ifndef PPMD_32BIT - + UNIT_SIZE - #endif - ; - p->AlignOffset = - #ifdef PPMD_32BIT - (4 - size) & 3; - #else - 4 - (size & 3); - #endif - if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size + size2)) == 0) + p->AlignOffset = (4 - size) & 3; + if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL) return False; p->Size = size; } return True; } -static void InsertNode(CPpmd7 *p, void *node, unsigned indx) + + +// ---------- Internal Memory Allocator ---------- + +/* We can use CPpmd7_Node in list of free units (as in Ppmd8) + But we still need one additional list walk pass in Ppmd7_GlueFreeBlocks(). + So we use simple CPpmd_Void_Ref instead of CPpmd7_Node in Ppmd7_InsertNode() / Ppmd7_RemoveNode() +*/ + +#define EMPTY_NODE 0 + + +static void Ppmd7_InsertNode(CPpmd7 *p, void *node, unsigned indx) { *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + // ((CPpmd7_Node *)node)->Next = (CPpmd7_Node_Ref)p->FreeList[indx]; + p->FreeList[indx] = REF(node); + } -static void *RemoveNode(CPpmd7 *p, unsigned indx) + +static void *Ppmd7_RemoveNode(CPpmd7 *p, unsigned indx) { CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); p->FreeList[indx] = *node; + // CPpmd7_Node *node = NODE((CPpmd7_Node_Ref)p->FreeList[indx]); + // p->FreeList[indx] = node->Next; return node; } -static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) + +static void Ppmd7_SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) { unsigned i, nu = I2U(oldIndx) - I2U(newIndx); ptr = (Byte *)ptr + U2B(I2U(newIndx)); if (I2U(i = U2I(nu)) != nu) { unsigned k = I2U(--i); - InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + Ppmd7_InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); } - InsertNode(p, ptr, i); + Ppmd7_InsertNode(p, ptr, i); } -static void GlueFreeBlocks(CPpmd7 *p) + +/* we use CPpmd7_Node_Union union to solve XLC -O2 strict pointer aliasing problem */ + +typedef union { - #ifdef PPMD_32BIT - CPpmd7_Node headItem; - CPpmd7_Node_Ref head = &headItem; - #else - CPpmd7_Node_Ref head = p->AlignOffset + p->Size; - #endif - - CPpmd7_Node_Ref n = head; - unsigned i; + CPpmd7_Node Node; + CPpmd7_Node_Ref NextRef; +} CPpmd7_Node_Union; + +/* Original PPmdH (Ppmd7) code uses doubly linked list in Ppmd7_GlueFreeBlocks() + we use single linked list similar to Ppmd8 code */ + +static void Ppmd7_GlueFreeBlocks(CPpmd7 *p) +{ + /* + we use first UInt16 field of 12-bytes UNITs as record type stamp + CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0 + CPpmd7_Context { UInt16 NumStats; : NumStats != 0 + CPpmd7_Node { UInt16 Stamp : Stamp == 0 for free record + : Stamp == 1 for head record and guard + Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd7_Context record. + */ + CPpmd7_Node_Ref head, n = 0; + p->GlueCount = 255; - /* create doubly-linked list of free blocks */ - for (i = 0; i < PPMD_NUM_INDEXES; i++) + + /* we set guard NODE at LoUnit */ + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)(void *)p->LoUnit)->Stamp = 1; + { - UInt16 nu = I2U(i); - CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; - p->FreeList[i] = 0; - while (next != 0) + /* Create list of free blocks. + We still need one additional list walk pass before Glue. */ + unsigned i; + for (i = 0; i < PPMD_NUM_INDEXES; i++) { - CPpmd7_Node *node = NODE(next); - node->Next = n; - n = NODE(n)->Prev = next; - next = *(const CPpmd7_Node_Ref *)node; - node->Stamp = 0; - node->NU = (UInt16)nu; + const UInt16 nu = I2U_UInt16(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + /* Don't change the order of the following commands: */ + CPpmd7_Node_Union *un = (CPpmd7_Node_Union *)NODE(next); + const CPpmd7_Node_Ref tmp = next; + next = un->NextRef; + un->Node.Stamp = EMPTY_NODE; + un->Node.NU = nu; + un->Node.Next = n; + n = tmp; + } } } - NODE(head)->Stamp = 1; - NODE(head)->Next = n; - NODE(n)->Prev = head; - if (p->LoUnit != p->HiUnit) - ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; - - /* Glue free blocks */ - while (n != head) + + head = n; + /* Glue and Fill must walk the list in same direction */ { - CPpmd7_Node *node = NODE(n); - UInt32 nu = (UInt32)node->NU; - for (;;) + /* Glue free blocks */ + CPpmd7_Node_Ref *prev = &head; + while (n) { - CPpmd7_Node *node2 = NODE(n) + nu; - nu += node2->NU; - if (node2->Stamp != 0 || nu >= 0x10000) - break; - NODE(node2->Prev)->Next = node2->Next; - NODE(node2->Next)->Prev = node2->Prev; - node->NU = (UInt16)nu; + CPpmd7_Node *node = NODE(n); + UInt32 nu = node->NU; + n = node->Next; + if (nu == 0) + { + *prev = n; + continue; + } + prev = &node->Next; + for (;;) + { + CPpmd7_Node *node2 = node + nu; + nu += node2->NU; + if (node2->Stamp != EMPTY_NODE || nu >= 0x10000) + break; + node->NU = (UInt16)nu; + node2->NU = 0; + } } - n = node->Next; } - + /* Fill lists of free blocks */ - for (n = NODE(head)->Next; n != head;) + for (n = head; n != 0;) { CPpmd7_Node *node = NODE(n); - unsigned nu; - CPpmd7_Node_Ref next = node->Next; - for (nu = node->NU; nu > 128; nu -= 128, node += 128) - InsertNode(p, node, PPMD_NUM_INDEXES - 1); + UInt32 nu = node->NU; + unsigned i; + n = node->Next; + if (nu == 0) + continue; + for (; nu > 128; nu -= 128, node += 128) + Ppmd7_InsertNode(p, node, PPMD_NUM_INDEXES - 1); if (I2U(i = U2I(nu)) != nu) { unsigned k = I2U(--i); - InsertNode(p, node + k, nu - k - 1); + Ppmd7_InsertNode(p, node + k, (unsigned)nu - k - 1); } - InsertNode(p, node, i); - n = next; + Ppmd7_InsertNode(p, node, i); } } -static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) + +Z7_NO_INLINE +static void *Ppmd7_AllocUnitsRare(CPpmd7 *p, unsigned indx) { unsigned i; - void *retVal; + if (p->GlueCount == 0) { - GlueFreeBlocks(p); + Ppmd7_GlueFreeBlocks(p); if (p->FreeList[indx] != 0) - return RemoveNode(p, indx); + return Ppmd7_RemoveNode(p, indx); } + i = indx; + do { if (++i == PPMD_NUM_INDEXES) { UInt32 numBytes = U2B(I2U(indx)); + Byte *us = p->UnitsStart; p->GlueCount--; - return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : NULL; } } while (p->FreeList[i] == 0); - retVal = RemoveNode(p, i); - SplitBlock(p, retVal, i, indx); - return retVal; + + { + void *block = Ppmd7_RemoveNode(p, i); + Ppmd7_SplitBlock(p, block, i, indx); + return block; + } } -static void *AllocUnits(CPpmd7 *p, unsigned indx) + +static void *Ppmd7_AllocUnits(CPpmd7 *p, unsigned indx) { - UInt32 numBytes; if (p->FreeList[indx] != 0) - return RemoveNode(p, indx); - numBytes = U2B(I2U(indx)); - if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + return Ppmd7_RemoveNode(p, indx); { - void *retVal = p->LoUnit; - p->LoUnit += numBytes; - return retVal; + UInt32 numBytes = U2B(I2U(indx)); + Byte *lo = p->LoUnit; + if ((UInt32)(p->HiUnit - lo) >= numBytes) + { + p->LoUnit = lo + numBytes; + return lo; + } } - return AllocUnitsRare(p, indx); + return Ppmd7_AllocUnitsRare(p, indx); } -#define MyMem12Cpy(dest, src, num) \ - { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ - do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); } +#define MEM_12_CPY(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *z = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; } while (--n); } + + +/* static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) { unsigned i0 = U2I(oldNU); @@ -269,28 +315,33 @@ static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU return oldPtr; if (p->FreeList[i1] != 0) { - void *ptr = RemoveNode(p, i1); - MyMem12Cpy(ptr, oldPtr, newNU); - InsertNode(p, oldPtr, i0); + void *ptr = Ppmd7_RemoveNode(p, i1); + MEM_12_CPY(ptr, oldPtr, newNU) + Ppmd7_InsertNode(p, oldPtr, i0); return ptr; } - SplitBlock(p, oldPtr, i0, i1); + Ppmd7_SplitBlock(p, oldPtr, i0, i1); return oldPtr; } +*/ -#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) { - (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); - (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); + Ppmd_SET_SUCCESSOR(p, v) } -static void RestartModel(CPpmd7 *p) + + +Z7_NO_INLINE +static +void Ppmd7_RestartModel(CPpmd7 *p) { - unsigned i, k, m; + unsigned i, k; memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; p->HiUnit = p->Text + p->Size; p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; @@ -300,57 +351,110 @@ static void RestartModel(CPpmd7 *p) p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; p->PrevSuccess = 0; - p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ - p->MinContext->Suffix = 0; - p->MinContext->NumStats = 256; - p->MinContext->SummFreq = 256 + 1; - p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ - p->LoUnit += U2B(256 / 2); - p->MinContext->Stats = REF(p->FoundState); - for (i = 0; i < 256; i++) { - CPpmd_State *s = &p->FoundState[i]; - s->Symbol = (Byte)i; - s->Freq = 1; - SetSuccessor(s, 0); + CPpmd7_Context *mc = (PPMD7_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* Ppmd7_AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + + p->LoUnit += U2B(256 / 2); + p->MaxContext = p->MinContext = mc; + p->FoundState = s; + + mc->NumStats = 256; + mc->Union2.SummFreq = 256 + 1; + mc->Union4.Stats = REF(s); + mc->Suffix = 0; + + for (i = 0; i < 256; i++, s++) + { + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + #ifdef PPMD7_ORDER_0_SUPPPORT + if (p->MaxOrder == 0) + { + CPpmd_Void_Ref r = REF(mc); + s = p->FoundState; + for (i = 0; i < 256; i++, s++) + SetSuccessor(s, r); + return; + } + #endif } for (i = 0; i < 128; i++) + + + for (k = 0; k < 8; k++) { + unsigned m; UInt16 *dest = p->BinSumm[i] + k; - UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + const UInt16 val = (UInt16)(PPMD_BIN_SCALE - PPMD7_kInitBinEsc[k] / (i + 2)); for (m = 0; m < 64; m += 8) dest[m] = val; } - + + for (i = 0; i < 25; i++) - for (k = 0; k < 16; k++) + { + + CPpmd_See *s = p->See[i]; + + + + unsigned summ = ((5 * i + 10) << (PPMD_PERIOD_BITS - 4)); + for (k = 0; k < 16; k++, s++) { - CPpmd_See *s = &p->See[i][k]; - s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Summ = (UInt16)summ; + s->Shift = (PPMD_PERIOD_BITS - 4); s->Count = 4; } + } + + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Count = 64; /* unused */ } + void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) { p->MaxOrder = maxOrder; - RestartModel(p); - p->DummySee.Shift = PPMD_PERIOD_BITS; - p->DummySee.Summ = 0; /* unused */ - p->DummySee.Count = 64; /* unused */ + + Ppmd7_RestartModel(p); } -static CTX_PTR CreateSuccessors(CPpmd7 *p, BoolInt skip) + + +/* + Ppmd7_CreateSuccessors() + It's called when (FoundState->Successor) is RAW-Successor, + that is the link to position in Raw text. + So we create Context records and write the links to + FoundState->Successor and to identical RAW-Successors in suffix + contexts of MinContex. + + The function returns: + if (OrderFall == 0) then MinContext is already at MAX order, + { return pointer to new or existing context of same MAX order } + else + { return pointer to new real context that will be (Order+1) in comparison with MinContext + + also it can return pointer to real context of same order, +*/ + +Z7_NO_INLINE +static PPMD7_CTX_PTR Ppmd7_CreateSuccessors(CPpmd7 *p) { - CPpmd_State upState; - CTX_PTR c = p->MinContext; + PPMD7_CTX_PTR c = p->MinContext; CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); - CPpmd_State *ps[PPMD7_MAX_ORDER]; + Byte newSym, newFreq; unsigned numPs = 0; - - if (!skip) + CPpmd_State *ps[PPMD7_MAX_ORDER]; + + if (p->OrderFall != 0) ps[numPs++] = p->FoundState; while (c->Suffix) @@ -358,54 +462,83 @@ static CTX_PTR CreateSuccessors(CPpmd7 *p, BoolInt skip) CPpmd_Void_Ref successor; CPpmd_State *s; c = SUFFIX(c); + + if (c->NumStats != 1) { - for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + Byte sym = p->FoundState->Symbol; + for (s = STATS(c); s->Symbol != sym; s++); + } else + { s = ONE_STATE(c); + + } successor = SUCCESSOR(s); if (successor != upBranch) { + // (c) is real record Context here, c = CTX(successor); if (numPs == 0) + { + // (c) is real record MAX Order Context here, + // So we don't need to create any new contexts. return c; + } break; } ps[numPs++] = s; } - upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); - SetSuccessor(&upState, upBranch + 1); + // All created contexts will have single-symbol with new RAW-Successor + // All new RAW-Successors will point to next position in RAW text + // after FoundState->Successor + + newSym = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + upBranch++; + if (c->NumStats == 1) - upState.Freq = ONE_STATE(c)->Freq; + newFreq = ONE_STATE(c)->Freq; else { UInt32 cf, s0; CPpmd_State *s; - for (s = STATS(c); s->Symbol != upState.Symbol; s++); - cf = s->Freq - 1; - s0 = c->SummFreq - c->NumStats - cf; - upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + for (s = STATS(c); s->Symbol != newSym; s++); + cf = (UInt32)s->Freq - 1; + s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf; + /* + cf - is frequency of symbol that will be Successor in new context records. + s0 - is commulative frequency sum of another symbols from parent context. + max(newFreq)= (s->Freq + 1), when (s0 == 1) + we have requirement (Ppmd7Context_OneState()->Freq <= 128) in BinSumm[] + so (s->Freq < 128) - is requirement for multi-symbol contexts + */ + newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : (2 * cf + s0 - 1) / (2 * s0) + 1)); } + // Create new single-symbol contexts from low order to high order in loop + do { - /* Create Child */ - CTX_PTR c1; /* = AllocContext(p); */ + PPMD7_CTX_PTR c1; + /* = AllocContext(p); */ if (p->HiUnit != p->LoUnit) - c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + c1 = (PPMD7_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); else if (p->FreeList[0] != 0) - c1 = (CTX_PTR)RemoveNode(p, 0); + c1 = (PPMD7_CTX_PTR)Ppmd7_RemoveNode(p, 0); else { - c1 = (CTX_PTR)AllocUnitsRare(p, 0); + c1 = (PPMD7_CTX_PTR)Ppmd7_AllocUnitsRare(p, 0); if (!c1) return NULL; } + c1->NumStats = 1; - *ONE_STATE(c1) = upState; + ONE_STATE(c1)->Symbol = newSym; + ONE_STATE(c1)->Freq = newFreq; + SetSuccessor(ONE_STATE(c1), upBranch); c1->Suffix = REF(c); SetSuccessor(ps[--numPs], REF(c1)); c = c1; @@ -415,21 +548,26 @@ static CTX_PTR CreateSuccessors(CPpmd7 *p, BoolInt skip) return c; } -static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) -{ - CPpmd_State tmp = *t1; - *t1 = *t2; - *t2 = tmp; -} -static void UpdateModel(CPpmd7 *p) + +#define SWAP_STATES(s) \ + { CPpmd_State tmp = s[0]; s[0] = s[-1]; s[-1] = tmp; } + + +void Ppmd7_UpdateModel(CPpmd7 *p); +Z7_NO_INLINE +void Ppmd7_UpdateModel(CPpmd7 *p) { - CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); - CTX_PTR c; + CPpmd_Void_Ref maxSuccessor, minSuccessor; + PPMD7_CTX_PTR c, mc; unsigned s0, ns; - + + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) { + /* Update Freqs in Suffix Context */ + c = SUFFIX(p->MinContext); if (c->NumStats == 1) @@ -441,73 +579,133 @@ static void UpdateModel(CPpmd7 *p) else { CPpmd_State *s = STATS(c); - if (s->Symbol != p->FoundState->Symbol) + Byte sym = p->FoundState->Symbol; + + if (s->Symbol != sym) { - do { s++; } while (s->Symbol != p->FoundState->Symbol); + do + { + // s++; if (s->Symbol == sym) break; + s++; + } + while (s->Symbol != sym); + if (s[0].Freq >= s[-1].Freq) { - SwapStates(&s[0], &s[-1]); + SWAP_STATES(s) s--; } } + if (s->Freq < MAX_FREQ - 9) { - s->Freq += 2; - c->SummFreq += 2; + s->Freq = (Byte)(s->Freq + 2); + c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); } } } + if (p->OrderFall == 0) { - p->MinContext = p->MaxContext = CreateSuccessors(p, True); - if (p->MinContext == 0) + /* MAX ORDER context */ + /* (FoundState->Successor) is RAW-Successor. */ + p->MaxContext = p->MinContext = Ppmd7_CreateSuccessors(p); + if (!p->MinContext) { - RestartModel(p); + Ppmd7_RestartModel(p); return; } SetSuccessor(p->FoundState, REF(p->MinContext)); return; } + + + /* NON-MAX ORDER context */ - *p->Text++ = p->FoundState->Symbol; - successor = REF(p->Text); - if (p->Text >= p->UnitsStart) { - RestartModel(p); - return; + Byte *text = p->Text; + *text++ = p->FoundState->Symbol; + p->Text = text; + if (text >= p->UnitsStart) + { + Ppmd7_RestartModel(p); + return; + } + maxSuccessor = REF(text); } - if (fSuccessor) + minSuccessor = SUCCESSOR(p->FoundState); + + if (minSuccessor) { - if (fSuccessor <= successor) + // there is Successor for FoundState in MinContext. + // So the next context will be one order higher than MinContext. + + if (minSuccessor <= maxSuccessor) { - CTX_PTR cs = CreateSuccessors(p, False); - if (cs == NULL) + // minSuccessor is RAW-Successor. So we will create real contexts records: + PPMD7_CTX_PTR cs = Ppmd7_CreateSuccessors(p); + if (!cs) { - RestartModel(p); + Ppmd7_RestartModel(p); return; } - fSuccessor = REF(cs); + minSuccessor = REF(cs); } + + // minSuccessor now is real Context pointer that points to existing (Order+1) context + if (--p->OrderFall == 0) { - successor = fSuccessor; + /* + if we move to MaxOrder context, then minSuccessor will be common Succesor for both: + MinContext that is (MaxOrder - 1) + MaxContext that is (MaxOrder) + so we don't need new RAW-Successor, and we can use real minSuccessor + as succssors for both MinContext and MaxContext. + */ + maxSuccessor = minSuccessor; + + /* + if (MaxContext != MinContext) + { + there was order fall from MaxOrder and we don't need current symbol + to transfer some RAW-Succesors to real contexts. + So we roll back pointer in raw data for one position. + } + */ p->Text -= (p->MaxContext != p->MinContext); } } else { - SetSuccessor(p->FoundState, successor); - fSuccessor = REF(p->MinContext); + /* + FoundState has NULL-Successor here. + And only root 0-order context can contain NULL-Successors. + We change Successor in FoundState to RAW-Successor, + And next context will be same 0-order root Context. + */ + SetSuccessor(p->FoundState, maxSuccessor); + minSuccessor = REF(p->MinContext); } - - s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); - - for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + + mc = p->MinContext; + c = p->MaxContext; + + p->MaxContext = p->MinContext = CTX(minSuccessor); + + if (c == mc) + return; + + // s0 : is pure Escape Freq + s0 = mc->Union2.SummFreq - (ns = mc->NumStats) - ((unsigned)p->FoundState->Freq - 1); + + do { unsigned ns1; - UInt32 cf, sf; + UInt32 sum; + if ((ns1 = c->NumStats) != 1) { if ((ns1 & 1) == 0) @@ -517,90 +715,137 @@ static void UpdateModel(CPpmd7 *p) unsigned i = U2I(oldNU); if (i != U2I((size_t)oldNU + 1)) { - void *ptr = AllocUnits(p, i + 1); + void *ptr = Ppmd7_AllocUnits(p, i + 1); void *oldPtr; if (!ptr) { - RestartModel(p); + Ppmd7_RestartModel(p); return; } oldPtr = STATS(c); - MyMem12Cpy(ptr, oldPtr, oldNU); - InsertNode(p, oldPtr, i); - c->Stats = STATS_REF(ptr); + MEM_12_CPY(ptr, oldPtr, oldNU) + Ppmd7_InsertNode(p, oldPtr, i); + c->Union4.Stats = STATS_REF(ptr); } } - c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + sum = c->Union2.SummFreq; + /* max increase of Escape_Freq is 3 here. + total increase of Union2.SummFreq for all symbols is less than 256 here */ + sum += (UInt32)(2 * ns1 < ns) + 2 * ((unsigned)(4 * ns1 <= ns) & (sum <= 8 * ns1)); + /* original PPMdH uses 16-bit variable for (sum) here. + But (sum < 0x9000). So we don't truncate (sum) to 16-bit */ + // sum = (UInt16)sum; } else { - CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + // instead of One-symbol context we create 2-symbol context + CPpmd_State *s = (CPpmd_State*)Ppmd7_AllocUnits(p, 0); if (!s) { - RestartModel(p); + Ppmd7_RestartModel(p); return; } - *s = *ONE_STATE(c); - c->Stats = REF(s); - if (s->Freq < MAX_FREQ / 4 - 1) - s->Freq <<= 1; - else - s->Freq = MAX_FREQ - 4; - c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); - } - cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); - sf = (UInt32)s0 + c->SummFreq; - if (cf < 6 * sf) - { - cf = 1 + (cf > sf) + (cf >= 4 * sf); - c->SummFreq += 3; - } - else - { - cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); - c->SummFreq = (UInt16)(c->SummFreq + cf); + { + unsigned freq = c->Union2.State2.Freq; + // s = *ONE_STATE(c); + s->Symbol = c->Union2.State2.Symbol; + s->Successor_0 = c->Union4.State4.Successor_0; + s->Successor_1 = c->Union4.State4.Successor_1; + // SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of + // (Successor_0 and Successor_1) in LE/BE. + c->Union4.Stats = REF(s); + if (freq < MAX_FREQ / 4 - 1) + freq <<= 1; + else + freq = MAX_FREQ - 4; + // (max(s->freq) == 120), when we convert from 1-symbol into 2-symbol context + s->Freq = (Byte)freq; + // max(InitEsc = PPMD7_kExpEscape[*]) is 25. So the max(escapeFreq) is 26 here + sum = freq + p->InitEsc + (ns > 3); + } } + { CPpmd_State *s = STATS(c) + ns1; - SetSuccessor(s, successor); + UInt32 cf = 2 * (sum + 6) * (UInt32)p->FoundState->Freq; + UInt32 sf = (UInt32)s0 + sum; s->Symbol = p->FoundState->Symbol; - s->Freq = (Byte)cf; c->NumStats = (UInt16)(ns1 + 1); + SetSuccessor(s, maxSuccessor); + + if (cf < 6 * sf) + { + cf = (UInt32)1 + (cf > sf) + (cf >= 4 * sf); + sum += 3; + /* It can add (0, 1, 2) to Escape_Freq */ + } + else + { + cf = (UInt32)4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + sum += cf; + } + + c->Union2.SummFreq = (UInt16)sum; + s->Freq = (Byte)cf; } + c = SUFFIX(c); } - p->MaxContext = p->MinContext = CTX(fSuccessor); + while (c != mc); } -static void Rescale(CPpmd7 *p) + + +Z7_NO_INLINE +static void Ppmd7_Rescale(CPpmd7 *p) { unsigned i, adder, sumFreq, escFreq; CPpmd_State *stats = STATS(p->MinContext); CPpmd_State *s = p->FoundState; + + /* Sort the list by Freq */ + if (s != stats) { CPpmd_State tmp = *s; - for (; s != stats; s--) + do s[0] = s[-1]; + while (--s != stats); *s = tmp; } - escFreq = p->MinContext->SummFreq - s->Freq; - s->Freq += 4; - adder = (p->OrderFall != 0); - s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + escFreq = p->MinContext->Union2.SummFreq - sumFreq; + + /* + if (p->OrderFall == 0), adder = 0 : it's allowed to remove symbol from MAX Order context + if (p->OrderFall != 0), adder = 1 : it's NOT allowed to remove symbol from NON-MAX Order context + */ + + adder = (p->OrderFall != 0); + + #ifdef PPMD7_ORDER_0_SUPPPORT + adder |= (p->MaxOrder == 0); // we don't remove symbols from order-0 context + #endif + + sumFreq = (sumFreq + 4 + adder) >> 1; + i = (unsigned)p->MinContext->NumStats - 1; + s->Freq = (Byte)sumFreq; - i = p->MinContext->NumStats - 1; do { - escFreq -= (++s)->Freq; - s->Freq = (Byte)((s->Freq + adder) >> 1); - sumFreq += s->Freq; - if (s[0].Freq > s[-1].Freq) + unsigned freq = (++s)->Freq; + escFreq -= freq; + freq = (freq + adder) >> 1; + sumFreq += freq; + s->Freq = (Byte)freq; + if (freq > s[-1].Freq) { + CPpmd_State tmp = *s; CPpmd_State *s1 = s; - CPpmd_State tmp = *s1; do + { s1[0] = s1[-1]; - while (--s1 != stats && tmp.Freq > s1[-1].Freq); + } + while (--s1 != stats && freq > s1[-1].Freq); *s1 = tmp; } } @@ -608,47 +853,89 @@ static void Rescale(CPpmd7 *p) if (s->Freq == 0) { - unsigned numStats = p->MinContext->NumStats; - unsigned n0, n1; - do { i++; } while ((--s)->Freq == 0); + /* Remove all items with Freq == 0 */ + CPpmd7_Context *mc; + unsigned numStats, numStatsNew, n0, n1; + + i = 0; do { i++; } while ((--s)->Freq == 0); + + /* We increase (escFreq) for the number of removed symbols. + So we will have (0.5) increase for Escape_Freq in avarage per + removed symbol after Escape_Freq halving */ escFreq += i; - p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); - if (p->MinContext->NumStats == 1) + mc = p->MinContext; + numStats = mc->NumStats; + numStatsNew = numStats - i; + mc->NumStats = (UInt16)(numStatsNew); + n0 = (numStats + 1) >> 1; + + if (numStatsNew == 1) { - CPpmd_State tmp = *stats; + /* Create Single-Symbol context */ + unsigned freq = stats->Freq; + do { - tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); escFreq >>= 1; + freq = (freq + 1) >> 1; } while (escFreq > 1); - InsertNode(p, stats, U2I(((numStats + 1) >> 1))); - *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + + s = ONE_STATE(mc); + *s = *stats; + s->Freq = (Byte)freq; // (freq <= 260 / 4) + p->FoundState = s; + Ppmd7_InsertNode(p, stats, U2I(n0)); return; } - n0 = (numStats + 1) >> 1; - n1 = (p->MinContext->NumStats + 1) >> 1; + + n1 = (numStatsNew + 1) >> 1; if (n0 != n1) - p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + { + // p->MinContext->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + unsigned i0 = U2I(n0); + unsigned i1 = U2I(n1); + if (i0 != i1) + { + if (p->FreeList[i1] != 0) + { + void *ptr = Ppmd7_RemoveNode(p, i1); + p->MinContext->Union4.Stats = STATS_REF(ptr); + MEM_12_CPY(ptr, (const void *)stats, n1) + Ppmd7_InsertNode(p, stats, i0); + } + else + Ppmd7_SplitBlock(p, stats, i0, i1); + } + } + } + { + CPpmd7_Context *mc = p->MinContext; + mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + // Escape_Freq halving here + p->FoundState = STATS(mc); } - p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); - p->FoundState = STATS(p->MinContext); } + CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) { CPpmd_See *see; - unsigned nonMasked = p->MinContext->NumStats - numMasked; - if (p->MinContext->NumStats != 256) + const CPpmd7_Context *mc = p->MinContext; + unsigned numStats = mc->NumStats; + if (numStats != 256) { - see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] + - (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + - 2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + - 4 * (unsigned)(numMasked > nonMasked) + + unsigned nonMasked = numStats - numMasked; + see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - numStats) + + 2 * (unsigned)(mc->Union2.SummFreq < 11 * numStats) + + 4 * (unsigned)(numMasked > nonMasked) + p->HiBitsFlag; { - unsigned r = (see->Summ >> see->Shift); - see->Summ = (UInt16)(see->Summ - r); + // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ + unsigned summ = (UInt16)see->Summ; // & 0xFFFF + unsigned r = (summ >> see->Shift); + see->Summ = (UInt16)(summ - r); *escFreq = r + (r == 0); } } @@ -660,53 +947,176 @@ CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) return see; } -static void NextContext(CPpmd7 *p) + +static void Ppmd7_NextContext(CPpmd7 *p) { - CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); - if (p->OrderFall == 0 && (Byte *)c > p->Text) - p->MinContext = p->MaxContext = c; + PPMD7_CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (const Byte *)c > p->Text) + p->MaxContext = p->MinContext = c; else - UpdateModel(p); + Ppmd7_UpdateModel(p); } + void Ppmd7_Update1(CPpmd7 *p) { CPpmd_State *s = p->FoundState; - s->Freq += 4; - p->MinContext->SummFreq += 4; - if (s[0].Freq > s[-1].Freq) + unsigned freq = s->Freq; + freq += 4; + p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); + s->Freq = (Byte)freq; + if (freq > s[-1].Freq) { - SwapStates(&s[0], &s[-1]); + SWAP_STATES(s) p->FoundState = --s; - if (s->Freq > MAX_FREQ) - Rescale(p); + if (freq > MAX_FREQ) + Ppmd7_Rescale(p); } - NextContext(p); + Ppmd7_NextContext(p); } + void Ppmd7_Update1_0(CPpmd7 *p) { - p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); - p->RunLength += p->PrevSuccess; - p->MinContext->SummFreq += 4; - if ((p->FoundState->Freq += 4) > MAX_FREQ) - Rescale(p); - NextContext(p); + CPpmd_State *s = p->FoundState; + CPpmd7_Context *mc = p->MinContext; + unsigned freq = s->Freq; + unsigned summFreq = mc->Union2.SummFreq; + p->PrevSuccess = (2 * freq > summFreq); + p->RunLength += (int)p->PrevSuccess; + mc->Union2.SummFreq = (UInt16)(summFreq + 4); + freq += 4; + s->Freq = (Byte)freq; + if (freq > MAX_FREQ) + Ppmd7_Rescale(p); + Ppmd7_NextContext(p); } + +/* void Ppmd7_UpdateBin(CPpmd7 *p) { - p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); + unsigned freq = p->FoundState->Freq; + p->FoundState->Freq = (Byte)(freq + (freq < 128)); p->PrevSuccess = 1; p->RunLength++; - NextContext(p); + Ppmd7_NextContext(p); } +*/ void Ppmd7_Update2(CPpmd7 *p) { - p->MinContext->SummFreq += 4; - if ((p->FoundState->Freq += 4) > MAX_FREQ) - Rescale(p); + CPpmd_State *s = p->FoundState; + unsigned freq = s->Freq; + freq += 4; p->RunLength = p->InitRL; - UpdateModel(p); + p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); + s->Freq = (Byte)freq; + if (freq > MAX_FREQ) + Ppmd7_Rescale(p); + Ppmd7_UpdateModel(p); +} + + + +/* +PPMd Memory Map: +{ + [ 0 ] contains subset of original raw text, that is required to create context + records, Some symbols are not written, when max order context was reached + [ Text ] free area + [ UnitsStart ] CPpmd_State vectors and CPpmd7_Context records + [ LoUnit ] free area for CPpmd_State and CPpmd7_Context items +[ HiUnit ] CPpmd7_Context records + [ Size ] end of array } + +These addresses don't cross at any time. +And the following condtions is true for addresses: + (0 <= Text < UnitsStart <= LoUnit <= HiUnit <= Size) + +Raw text is BYTE--aligned. +the data in block [ UnitsStart ... Size ] contains 12-bytes aligned UNITs. + +Last UNIT of array at offset (Size - 12) is root order-0 CPpmd7_Context record. +The code can free UNITs memory blocks that were allocated to store CPpmd_State vectors. +The code doesn't free UNITs allocated for CPpmd7_Context records. + +The code calls Ppmd7_RestartModel(), when there is no free memory for allocation. +And Ppmd7_RestartModel() changes the state to orignal start state, with full free block. + + +The code allocates UNITs with the following order: + +Allocation of 1 UNIT for Context record + - from free space (HiUnit) down to (LoUnit) + - from FreeList[0] + - Ppmd7_AllocUnitsRare() + +Ppmd7_AllocUnits() for CPpmd_State vectors: + - from FreeList[i] + - from free space (LoUnit) up to (HiUnit) + - Ppmd7_AllocUnitsRare() + +Ppmd7_AllocUnitsRare() + - if (GlueCount == 0) + { Glue lists, GlueCount = 255, allocate from FreeList[i]] } + - loop for all higher sized FreeList[...] lists + - from (UnitsStart - Text), GlueCount-- + - ERROR + + +Each Record with Context contains the CPpmd_State vector, where each +CPpmd_State contains the link to Successor. +There are 3 types of Successor: + 1) NULL-Successor - NULL pointer. NULL-Successor links can be stored + only in 0-order Root Context Record. + We use 0 value as NULL-Successor + 2) RAW-Successor - the link to position in raw text, + that "RAW-Successor" is being created after first + occurrence of new symbol for some existing context record. + (RAW-Successor > 0). + 3) RECORD-Successor - the link to CPpmd7_Context record of (Order+1), + that record is being created when we go via RAW-Successor again. + +For any successors at any time: the following condtions are true for Successor links: +(NULL-Successor < RAW-Successor < UnitsStart <= RECORD-Successor) + + +---------- Symbol Frequency, SummFreq and Range in Range_Coder ---------- + +CPpmd7_Context::SummFreq = Sum(Stats[].Freq) + Escape_Freq + +The PPMd code tries to fulfill the condition: + (SummFreq <= (256 * 128 = RC::kBot)) + +We have (Sum(Stats[].Freq) <= 256 * 124), because of (MAX_FREQ = 124) +So (4 = 128 - 124) is average reserve for Escape_Freq for each symbol. +If (CPpmd_State::Freq) is not aligned for 4, the reserve can be 5, 6 or 7. +SummFreq and Escape_Freq can be changed in Ppmd7_Rescale() and *Update*() functions. +Ppmd7_Rescale() can remove symbols only from max-order contexts. So Escape_Freq can increase after multiple calls of Ppmd7_Rescale() for +max-order context. + +When the PPMd code still break (Total <= RC::Range) condition in range coder, +we have two ways to resolve that problem: + 1) we can report error, if we want to keep compatibility with original PPMd code that has no fix for such cases. + 2) we can reduce (Total) value to (RC::Range) by reducing (Escape_Freq) part of (Total) value. +*/ + +#undef MAX_FREQ +#undef UNIT_SIZE +#undef U2B +#undef U2I +#undef I2U +#undef I2U_UInt16 +#undef REF +#undef STATS_REF +#undef CTX +#undef STATS +#undef ONE_STATE +#undef SUFFIX +#undef NODE +#undef EMPTY_NODE +#undef MEM_12_CPY +#undef SUCCESSOR +#undef SWAP_STATES diff --git a/libraries/lzma/C/Ppmd7.h b/libraries/lzma/C/Ppmd7.h index 610539a047f..d9eb326d60b 100644 --- a/libraries/lzma/C/Ppmd7.h +++ b/libraries/lzma/C/Ppmd7.h @@ -1,13 +1,11 @@ -/* Ppmd7.h -- PPMdH compression codec -2018-07-04 : Igor Pavlov : Public domain -This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ - -/* This code supports virtual RangeDecoder and includes the implementation -of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. -If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ +/* Ppmd7.h -- Ppmd7 (PPMdH) compression codec +2023-04-02 : Igor Pavlov : Public domain +This code is based on: + PPMd var.H (2001): Dmitry Shkarin : Public domain */ + -#ifndef __PPMD7_H -#define __PPMD7_H +#ifndef ZIP7_INC_PPMD7_H +#define ZIP7_INC_PPMD7_H #include "Ppmd.h" @@ -21,23 +19,56 @@ EXTERN_C_BEGIN struct CPpmd7_Context_; -typedef - #ifdef PPMD_32BIT - struct CPpmd7_Context_ * - #else - UInt32 - #endif - CPpmd7_Context_Ref; +typedef Ppmd_Ref_Type(struct CPpmd7_Context_) CPpmd7_Context_Ref; + +// MY_CPU_pragma_pack_push_1 typedef struct CPpmd7_Context_ { UInt16 NumStats; - UInt16 SummFreq; - CPpmd_State_Ref Stats; + + + union + { + UInt16 SummFreq; + CPpmd_State2 State2; + } Union2; + + union + { + CPpmd_State_Ref Stats; + CPpmd_State4 State4; + } Union4; + CPpmd7_Context_Ref Suffix; } CPpmd7_Context; -#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) +// MY_CPU_pragma_pop + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->Union2) + + + + +typedef struct +{ + UInt32 Range; + UInt32 Code; + UInt32 Low; + IByteInPtr Stream; +} CPpmd7_RangeDec; + + +typedef struct +{ + UInt32 Range; + Byte Cache; + // Byte _dummy_[3]; + UInt64 Low; + UInt64 CacheSize; + IByteOutPtr Stream; +} CPpmd7z_RangeEnc; + typedef struct { @@ -48,17 +79,30 @@ typedef struct UInt32 Size; UInt32 GlueCount; - Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; UInt32 AlignOffset; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; - Byte Indx2Units[PPMD_NUM_INDEXES]; + + + + union + { + CPpmd7_RangeDec dec; + CPpmd7z_RangeEnc enc; + } rc; + + Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment Byte Units2Indx[128]; CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; - Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + + Byte NS2BSIndx[256], NS2Indx[256]; + Byte ExpEscape[16]; CPpmd_See DummySee, See[25][16]; UInt16 BinSumm[128][64]; + // int LastSymbol; } CPpmd7; + void Ppmd7_Construct(CPpmd7 *p); BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc); void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc); @@ -68,74 +112,69 @@ void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); /* ---------- Internal Functions ---------- */ -extern const Byte PPMD7_kExpEscape[16]; - -#ifdef PPMD_32BIT - #define Ppmd7_GetPtr(p, ptr) (ptr) - #define Ppmd7_GetContext(p, ptr) (ptr) - #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) -#else - #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) - #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) - #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) -#endif +#define Ppmd7_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr) +#define Ppmd7_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd7_Context) +#define Ppmd7_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State) void Ppmd7_Update1(CPpmd7 *p); void Ppmd7_Update1_0(CPpmd7 *p); void Ppmd7_Update2(CPpmd7 *p); -void Ppmd7_UpdateBin(CPpmd7 *p); + +#define PPMD7_HiBitsFlag_3(sym) ((((unsigned)sym + 0xC0) >> (8 - 3)) & (1 << 3)) +#define PPMD7_HiBitsFlag_4(sym) ((((unsigned)sym + 0xC0) >> (8 - 4)) & (1 << 4)) +// #define PPMD7_HiBitsFlag_3(sym) ((sym) < 0x40 ? 0 : (1 << 3)) +// #define PPMD7_HiBitsFlag_4(sym) ((sym) < 0x40 ? 0 : (1 << 4)) #define Ppmd7_GetBinSumm(p) \ - &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ - p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ - (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ - 2 * p->HB2Flag[(unsigned)Ppmd7Context_OneState(p->MinContext)->Symbol] + \ - ((p->RunLength >> 26) & 0x20)] + &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1] \ + [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \ + + p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] \ + + PPMD7_HiBitsFlag_4(Ppmd7Context_OneState(p->MinContext)->Symbol) \ + + (p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol)) ] CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); +/* +We support two versions of Ppmd7 (PPMdH) methods that use same CPpmd7 structure: + 1) Ppmd7a_*: original PPMdH + 2) Ppmd7z_*: modified PPMdH with 7z Range Coder +Ppmd7_*: the structures and functions that are common for both versions of PPMd7 (PPMdH) +*/ + /* ---------- Decode ---------- */ -typedef struct IPpmd7_RangeDec IPpmd7_RangeDec; +#define PPMD7_SYM_END (-1) +#define PPMD7_SYM_ERROR (-2) -struct IPpmd7_RangeDec -{ - UInt32 (*GetThreshold)(const IPpmd7_RangeDec *p, UInt32 total); - void (*Decode)(const IPpmd7_RangeDec *p, UInt32 start, UInt32 size); - UInt32 (*DecodeBit)(const IPpmd7_RangeDec *p, UInt32 size0); -}; +/* +You must set (CPpmd7::rc.dec.Stream) before Ppmd7*_RangeDec_Init() -typedef struct -{ - IPpmd7_RangeDec vt; - UInt32 Range; - UInt32 Code; - IByteIn *Stream; -} CPpmd7z_RangeDec; +Ppmd7*_DecodeSymbol() +out: + >= 0 : decoded byte + -1 : PPMD7_SYM_END : End of payload marker + -2 : PPMD7_SYM_ERROR : Data error +*/ -void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); -BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); -#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +/* Ppmd7a_* : original PPMdH */ +BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p); +#define Ppmd7a_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +int Ppmd7a_DecodeSymbol(CPpmd7 *p); -int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc); +/* Ppmd7z_* : modified PPMdH with 7z Range Coder */ +BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p); +#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +int Ppmd7z_DecodeSymbol(CPpmd7 *p); +// Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim); /* ---------- Encode ---------- */ -typedef struct -{ - UInt64 Low; - UInt32 Range; - Byte Cache; - UInt64 CacheSize; - IByteOut *Stream; -} CPpmd7z_RangeEnc; - -void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); -void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); - -void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); +void Ppmd7z_Init_RangeEnc(CPpmd7 *p); +void Ppmd7z_Flush_RangeEnc(CPpmd7 *p); +// void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol); +void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim); EXTERN_C_END diff --git a/libraries/lzma/C/Ppmd7Dec.c b/libraries/lzma/C/Ppmd7Dec.c index 311e9f9ddb0..832382828d1 100644 --- a/libraries/lzma/C/Ppmd7Dec.c +++ b/libraries/lzma/C/Ppmd7Dec.c @@ -1,191 +1,312 @@ -/* Ppmd7Dec.c -- PPMdH Decoder -2018-07-04 : Igor Pavlov : Public domain -This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ +/* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder +2023-04-02 : Igor Pavlov : Public domain +This code is based on: + PPMd var.H (2001): Dmitry Shkarin : Public domain */ + #include "Precomp.h" #include "Ppmd7.h" -#define kTopValue (1 << 24) +#define kTopValue ((UInt32)1 << 24) + + +#define READ_BYTE(p) IByteIn_Read((p)->Stream) -BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p) { unsigned i; p->Code = 0; p->Range = 0xFFFFFFFF; - if (IByteIn_Read(p->Stream) != 0) + if (READ_BYTE(p) != 0) return False; for (i = 0; i < 4; i++) - p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); + p->Code = (p->Code << 8) | READ_BYTE(p); return (p->Code < 0xFFFFFFFF); } -#define GET_Ppmd7z_RangeDec CPpmd7z_RangeDec *p = CONTAINER_FROM_VTBL(pp, CPpmd7z_RangeDec, vt); - -static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total) -{ - GET_Ppmd7z_RangeDec - return p->Code / (p->Range /= total); -} +#define RC_NORM_BASE(p) if ((p)->Range < kTopValue) \ + { (p)->Code = ((p)->Code << 8) | READ_BYTE(p); (p)->Range <<= 8; -static void Range_Normalize(CPpmd7z_RangeDec *p) -{ - if (p->Range < kTopValue) - { - p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); - p->Range <<= 8; - if (p->Range < kTopValue) - { - p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); - p->Range <<= 8; - } - } -} +#define RC_NORM_1(p) RC_NORM_BASE(p) } +#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }} -static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) -{ - GET_Ppmd7z_RangeDec - p->Code -= start * p->Range; - p->Range *= size; - Range_Normalize(p); -} +// we must use only one type of Normalization from two: LOCAL or REMOTE +#define RC_NORM_LOCAL(p) // RC_NORM(p) +#define RC_NORM_REMOTE(p) RC_NORM(p) -static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0) -{ - GET_Ppmd7z_RangeDec - UInt32 newBound = (p->Range >> 14) * size0; - UInt32 symbol; - if (p->Code < newBound) - { - symbol = 0; - p->Range = newBound; - } - else - { - symbol = 1; - p->Code -= newBound; - p->Range -= newBound; - } - Range_Normalize(p); - return symbol; -} +#define R (&p->rc.dec) -void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +Z7_FORCE_INLINE +// Z7_NO_INLINE +static void Ppmd7z_RD_Decode(CPpmd7 *p, UInt32 start, UInt32 size) { - p->vt.GetThreshold = Range_GetThreshold; - p->vt.Decode = Range_Decode; - p->vt.DecodeBit = Range_DecodeBit; + + + R->Code -= start * R->Range; + R->Range *= size; + RC_NORM_LOCAL(R) } +#define RC_Decode(start, size) Ppmd7z_RD_Decode(p, start, size); +#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) +#define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) + -#define MASK(sym) ((signed char *)charMask)[sym] +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +// typedef CPpmd7_Context * CTX_PTR; +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) +void Ppmd7_UpdateModel(CPpmd7 *p); -int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc) +#define MASK(sym) ((unsigned char *)charMask)[sym] +// Z7_FORCE_INLINE +// static +int Ppmd7z_DecodeSymbol(CPpmd7 *p) { size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) { CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); unsigned i; UInt32 count, hiCnt; - if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + const UInt32 summFreq = p->MinContext->Union2.SummFreq; + + + + + count = RC_GetThreshold(summFreq); + hiCnt = count; + + if ((Int32)(count -= s->Freq) < 0) { - Byte symbol; - rc->Decode(rc, 0, s->Freq); + Byte sym; + RC_DecodeFinal(0, s->Freq) p->FoundState = s; - symbol = s->Symbol; + sym = s->Symbol; Ppmd7_Update1_0(p); - return symbol; + return sym; } + p->PrevSuccess = 0; - i = p->MinContext->NumStats - 1; + i = (unsigned)p->MinContext->NumStats - 1; + do { - if ((hiCnt += (++s)->Freq) > count) + if ((Int32)(count -= (++s)->Freq) < 0) { - Byte symbol; - rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Byte sym; + RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) p->FoundState = s; - symbol = s->Symbol; + sym = s->Symbol; Ppmd7_Update1(p); - return symbol; + return sym; } } while (--i); - if (count >= p->MinContext->SummFreq) - return -2; - p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; - rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(s->Symbol) = 0; - i = p->MinContext->NumStats - 1; - do { MASK((--s)->Symbol) = 0; } while (--i); + + if (hiCnt >= summFreq) + return PPMD7_SYM_ERROR; + + hiCnt -= count; + RC_Decode(hiCnt, summFreq - hiCnt) + + p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); + PPMD_SetAllBitsIn256Bytes(charMask) + // i = p->MinContext->NumStats - 1; + // do { MASK((--s)->Symbol) = 0; } while (--i); + { + CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); + MASK(s->Symbol) = 0; + do + { + unsigned sym0 = s2[0].Symbol; + unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } } else { + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); UInt16 *prob = Ppmd7_GetBinSumm(p); - if (rc->DecodeBit(rc, *prob) == 0) + UInt32 pr = *prob; + UInt32 size0 = (R->Range >> 14) * pr; + pr = PPMD_UPDATE_PROB_1(pr); + + if (R->Code < size0) { - Byte symbol; - *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); - symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; - Ppmd7_UpdateBin(p); - return symbol; + Byte sym; + *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); + + // RangeDec_DecodeBit0(size0); + R->Range = size0; + RC_NORM_1(R) + /* we can use single byte normalization here because of + (min(BinSumm[][]) = 95) > (1 << (14 - 8)) */ + + // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + // Ppmd7_UpdateBin(p); + { + unsigned freq = s->Freq; + CPpmd7_Context *c = CTX(SUCCESSOR(s)); + sym = s->Symbol; + p->FoundState = s; + p->PrevSuccess = 1; + p->RunLength++; + s->Freq = (Byte)(freq + (freq < 128)); + // NextContext(p); + if (p->OrderFall == 0 && (const Byte *)c > p->Text) + p->MaxContext = p->MinContext = c; + else + Ppmd7_UpdateModel(p); + } + return sym; } - *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); - p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; - PPMD_SetAllBitsIn256Bytes(charMask); + + *prob = (UInt16)pr; + p->InitEsc = p->ExpEscape[pr >> 10]; + + // RangeDec_DecodeBit1(size0); + + R->Code -= size0; + R->Range -= size0; + RC_NORM_LOCAL(R) + + PPMD_SetAllBitsIn256Bytes(charMask) MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; p->PrevSuccess = 0; } + for (;;) { - CPpmd_State *ps[256], *s; + CPpmd_State *s, *s2; UInt32 freqSum, count, hiCnt; + CPpmd_See *see; - unsigned i, num, numMasked = p->MinContext->NumStats; + CPpmd7_Context *mc; + unsigned numMasked; + RC_NORM_REMOTE(R) + mc = p->MinContext; + numMasked = mc->NumStats; + do { p->OrderFall++; - if (!p->MinContext->Suffix) - return -1; - p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + if (!mc->Suffix) + return PPMD7_SYM_END; + mc = Ppmd7_GetContext(p, mc->Suffix); } - while (p->MinContext->NumStats == numMasked); - hiCnt = 0; - s = Ppmd7_GetStats(p, p->MinContext); - i = 0; - num = p->MinContext->NumStats - numMasked; - do + while (mc->NumStats == numMasked); + + s = Ppmd7_GetStats(p, mc); + { - int k = (int)(MASK(s->Symbol)); - hiCnt += (s->Freq & k); - ps[i] = s++; - i -= k; + unsigned num = mc->NumStats; + unsigned num2 = num / 2; + + num &= 1; + hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num); + s += num; + p->MinContext = mc; + + do + { + unsigned sym0 = s[0].Symbol; + unsigned sym1 = s[1].Symbol; + s += 2; + hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0))); + hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1))); + } + while (--num2); } - while (i != num); - + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); freqSum += hiCnt; - count = rc->GetThreshold(rc, freqSum); + + + + + count = RC_GetThreshold(freqSum); if (count < hiCnt) { - Byte symbol; - CPpmd_State **pps = ps; - for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); - s = *pps; - rc->Decode(rc, hiCnt - s->Freq, s->Freq); - Ppmd_See_Update(see); + Byte sym; + + s = Ppmd7_GetStats(p, p->MinContext); + hiCnt = count; + // count -= s->Freq & (unsigned)(MASK(s->Symbol)); + // if ((Int32)count >= 0) + { + for (;;) + { + count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; + // count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; + } + } + s--; + RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) + + // new (see->Summ) value can overflow over 16-bits in some rare cases + Ppmd_See_UPDATE(see) p->FoundState = s; - symbol = s->Symbol; + sym = s->Symbol; Ppmd7_Update2(p); - return symbol; + return sym; } + if (count >= freqSum) - return -2; - rc->Decode(rc, hiCnt, freqSum - hiCnt); + return PPMD7_SYM_ERROR; + + RC_Decode(hiCnt, freqSum - hiCnt) + + // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. + // new (see->Summ) value can overflow over 16-bits in some rare cases see->Summ = (UInt16)(see->Summ + freqSum); - do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + + s = Ppmd7_GetStats(p, p->MinContext); + s2 = s + p->MinContext->NumStats; + do + { + MASK(s->Symbol) = 0; + s++; + } + while (s != s2); } } + +/* +Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim) +{ + int sym = 0; + if (buf != lim) + do + { + sym = Ppmd7z_DecodeSymbol(p); + if (sym < 0) + break; + *buf = (Byte)sym; + } + while (++buf < lim); + p->LastSymbol = sym; + return buf; +} +*/ + +#undef kTopValue +#undef READ_BYTE +#undef RC_NORM_BASE +#undef RC_NORM_1 +#undef RC_NORM +#undef RC_NORM_LOCAL +#undef RC_NORM_REMOTE +#undef R +#undef RC_Decode +#undef RC_DecodeFinal +#undef RC_GetThreshold +#undef CTX +#undef SUCCESSOR +#undef MASK diff --git a/libraries/lzma/C/Ppmd7Enc.c b/libraries/lzma/C/Ppmd7Enc.c new file mode 100644 index 00000000000..41106bab459 --- /dev/null +++ b/libraries/lzma/C/Ppmd7Enc.c @@ -0,0 +1,338 @@ +/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder +2023-04-02 : Igor Pavlov : Public domain +This code is based on: + PPMd var.H (2001): Dmitry Shkarin : Public domain */ + + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue ((UInt32)1 << 24) + +#define R (&p->rc.enc) + +void Ppmd7z_Init_RangeEnc(CPpmd7 *p) +{ + R->Low = 0; + R->Range = 0xFFFFFFFF; + R->Cache = 0; + R->CacheSize = 1; +} + +Z7_NO_INLINE +static void Ppmd7z_RangeEnc_ShiftLow(CPpmd7 *p) +{ + if ((UInt32)R->Low < (UInt32)0xFF000000 || (unsigned)(R->Low >> 32) != 0) + { + Byte temp = R->Cache; + do + { + IByteOut_Write(R->Stream, (Byte)(temp + (Byte)(R->Low >> 32))); + temp = 0xFF; + } + while (--R->CacheSize != 0); + R->Cache = (Byte)((UInt32)R->Low >> 24); + } + R->CacheSize++; + R->Low = (UInt32)((UInt32)R->Low << 8); +} + +#define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8; Ppmd7z_RangeEnc_ShiftLow(p); +#define RC_NORM_1(p) RC_NORM_BASE(p) } +#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }} + +// we must use only one type of Normalization from two: LOCAL or REMOTE +#define RC_NORM_LOCAL(p) // RC_NORM(p) +#define RC_NORM_REMOTE(p) RC_NORM(p) + +/* +#define Ppmd7z_RangeEnc_Encode(p, start, _size_) \ + { UInt32 size = _size_; \ + R->Low += start * R->Range; \ + R->Range *= size; \ + RC_NORM_LOCAL(p); } +*/ + +Z7_FORCE_INLINE +// Z7_NO_INLINE +static void Ppmd7z_RangeEnc_Encode(CPpmd7 *p, UInt32 start, UInt32 size) +{ + R->Low += start * R->Range; + R->Range *= size; + RC_NORM_LOCAL(p) +} + +void Ppmd7z_Flush_RangeEnc(CPpmd7 *p) +{ + unsigned i; + for (i = 0; i < 5; i++) + Ppmd7z_RangeEnc_ShiftLow(p); +} + + + +#define RC_Encode(start, size) Ppmd7z_RangeEnc_Encode(p, start, size); +#define RC_EncodeFinal(start, size) RC_Encode(start, size) RC_NORM_REMOTE(p) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define SUFFIX(ctx) CTX((ctx)->Suffix) +// typedef CPpmd7_Context * CTX_PTR; +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) + +void Ppmd7_UpdateModel(CPpmd7 *p); + +#define MASK(sym) ((unsigned char *)charMask)[sym] + +Z7_FORCE_INLINE +static +void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + + + + + R->Range /= p->MinContext->Union2.SummFreq; + + if (s->Symbol == symbol) + { + // R->Range /= p->MinContext->Union2.SummFreq; + RC_EncodeFinal(0, s->Freq) + p->FoundState = s; + Ppmd7_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = (unsigned)p->MinContext->NumStats - 1; + do + { + if ((++s)->Symbol == symbol) + { + // R->Range /= p->MinContext->Union2.SummFreq; + RC_EncodeFinal(sum, s->Freq) + p->FoundState = s; + Ppmd7_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + // R->Range /= p->MinContext->Union2.SummFreq; + RC_Encode(sum, p->MinContext->Union2.SummFreq - sum) + + p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); + PPMD_SetAllBitsIn256Bytes(charMask) + // MASK(s->Symbol) = 0; + // i = p->MinContext->NumStats - 1; + // do { MASK((--s)->Symbol) = 0; } while (--i); + { + CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); + MASK(s->Symbol) = 0; + do + { + unsigned sym0 = s2[0].Symbol; + unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); + UInt32 pr = *prob; + const UInt32 bound = (R->Range >> 14) * pr; + pr = PPMD_UPDATE_PROB_1(pr); + if (s->Symbol == symbol) + { + *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); + // RangeEnc_EncodeBit_0(p, bound); + R->Range = bound; + RC_NORM_1(p) + + // p->FoundState = s; + // Ppmd7_UpdateBin(p); + { + const unsigned freq = s->Freq; + CPpmd7_Context *c = CTX(SUCCESSOR(s)); + p->FoundState = s; + p->PrevSuccess = 1; + p->RunLength++; + s->Freq = (Byte)(freq + (freq < 128)); + // NextContext(p); + if (p->OrderFall == 0 && (const Byte *)c > p->Text) + p->MaxContext = p->MinContext = c; + else + Ppmd7_UpdateModel(p); + } + return; + } + + *prob = (UInt16)pr; + p->InitEsc = p->ExpEscape[pr >> 10]; + // RangeEnc_EncodeBit_1(p, bound); + R->Low += bound; + R->Range -= bound; + RC_NORM_LOCAL(p) + + PPMD_SetAllBitsIn256Bytes(charMask) + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + + for (;;) + { + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum, escFreq; + CPpmd7_Context *mc; + unsigned i, numMasked; + + RC_NORM_REMOTE(p) + + mc = p->MinContext; + numMasked = mc->NumStats; + + do + { + p->OrderFall++; + if (!mc->Suffix) + return; /* EndMarker (symbol = -1) */ + mc = Ppmd7_GetContext(p, mc->Suffix); + i = mc->NumStats; + } + while (i == numMasked); + + p->MinContext = mc; + + // see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); + { + if (i != 256) + { + unsigned nonMasked = i - numMasked; + see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] + + p->HiBitsFlag + + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - i) + + 2 * (unsigned)(mc->Union2.SummFreq < 11 * i) + + 4 * (unsigned)(numMasked > nonMasked); + { + // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ + unsigned summ = (UInt16)see->Summ; // & 0xFFFF + unsigned r = (summ >> see->Shift); + see->Summ = (UInt16)(summ - r); + escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + escFreq = 1; + } + } + + s = Ppmd7_GetStats(p, mc); + sum = 0; + // i = mc->NumStats; + + do + { + const unsigned cur = s->Symbol; + if ((int)cur == symbol) + { + const UInt32 low = sum; + const UInt32 freq = s->Freq; + unsigned num2; + + Ppmd_See_UPDATE(see) + p->FoundState = s; + sum += escFreq; + + num2 = i / 2; + i &= 1; + sum += freq & (0 - (UInt32)i); + if (num2 != 0) + { + s += i; + for (;;) + { + unsigned sym0 = s[0].Symbol; + unsigned sym1 = s[1].Symbol; + s += 2; + sum += (s[-2].Freq & (unsigned)(MASK(sym0))); + sum += (s[-1].Freq & (unsigned)(MASK(sym1))); + if (--num2 == 0) + break; + } + } + + + R->Range /= sum; + RC_EncodeFinal(low, freq) + Ppmd7_Update2(p); + return; + } + sum += (s->Freq & (unsigned)(MASK(cur))); + s++; + } + while (--i); + + { + const UInt32 total = sum + escFreq; + see->Summ = (UInt16)(see->Summ + total); + + R->Range /= total; + RC_Encode(sum, escFreq) + } + + { + const CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); + s--; + MASK(s->Symbol) = 0; + do + { + const unsigned sym0 = s2[0].Symbol; + const unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } +} + + +void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim) +{ + for (; buf < lim; buf++) + { + Ppmd7z_EncodeSymbol(p, *buf); + } +} + +#undef kTopValue +#undef WRITE_BYTE +#undef RC_NORM_BASE +#undef RC_NORM_1 +#undef RC_NORM +#undef RC_NORM_LOCAL +#undef RC_NORM_REMOTE +#undef R +#undef RC_Encode +#undef RC_EncodeFinal +#undef SUFFIX +#undef CTX +#undef SUCCESSOR +#undef MASK diff --git a/libraries/lzma/C/Precomp.h b/libraries/lzma/C/Precomp.h index e8ff8b40e81..69afb2ffd10 100644 --- a/libraries/lzma/C/Precomp.h +++ b/libraries/lzma/C/Precomp.h @@ -1,8 +1,8 @@ /* Precomp.h -- StdAfx -2013-11-12 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ -#ifndef __7Z_PRECOMP_H -#define __7Z_PRECOMP_H +#ifndef ZIP7_INC_PRECOMP_H +#define ZIP7_INC_PRECOMP_H #include "Compiler.h" /* #include "7zTypes.h" */ diff --git a/libraries/lzma/C/RotateDefs.h b/libraries/lzma/C/RotateDefs.h new file mode 100644 index 00000000000..c16b4f8e6a1 --- /dev/null +++ b/libraries/lzma/C/RotateDefs.h @@ -0,0 +1,50 @@ +/* RotateDefs.h -- Rotate functions +2023-06-18 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_ROTATE_DEFS_H +#define ZIP7_INC_ROTATE_DEFS_H + +#ifdef _MSC_VER + +#include + +/* don't use _rotl with old MINGW. It can insert slow call to function. */ + +/* #if (_MSC_VER >= 1200) */ +#pragma intrinsic(_rotl) +#pragma intrinsic(_rotr) +/* #endif */ + +#define rotlFixed(x, n) _rotl((x), (n)) +#define rotrFixed(x, n) _rotr((x), (n)) + +#if (_MSC_VER >= 1300) +#define Z7_ROTL64(x, n) _rotl64((x), (n)) +#define Z7_ROTR64(x, n) _rotr64((x), (n)) +#else +#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) +#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) +#endif + +#else + +/* new compilers can translate these macros to fast commands. */ + +#if defined(__clang__) && (__clang_major__ >= 4) \ + || defined(__GNUC__) && (__GNUC__ >= 5) +/* GCC 4.9.0 and clang 3.5 can recognize more correct version: */ +#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (-(n) & 31))) +#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (-(n) & 31))) +#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (-(n) & 63))) +#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (-(n) & 63))) +#else +/* for old GCC / clang: */ +#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) +#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) +#endif + +#endif + +#endif diff --git a/libraries/lzma/C/Sha256.c b/libraries/lzma/C/Sha256.c new file mode 100644 index 00000000000..018cf6f4b4b --- /dev/null +++ b/libraries/lzma/C/Sha256.c @@ -0,0 +1,516 @@ +/* Sha256.c -- SHA-256 Hash +2023-04-02 : Igor Pavlov : Public domain +This code is based on public domain code from Wei Dai's Crypto++ library. */ + +#include "Precomp.h" + +#include + +#include "CpuArch.h" +#include "RotateDefs.h" +#include "Sha256.h" + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +// #define USE_MY_MM +#endif + +#ifdef MY_CPU_X86_OR_AMD64 + #ifdef _MSC_VER + #if _MSC_VER >= 1200 + #define Z7_COMPILER_SHA256_SUPPORTED + #endif + #elif defined(__clang__) + #if (__clang_major__ >= 8) // fix that check + #define Z7_COMPILER_SHA256_SUPPORTED + #endif + #elif defined(__GNUC__) + #if (__GNUC__ >= 8) // fix that check + #define Z7_COMPILER_SHA256_SUPPORTED + #endif + #elif defined(__INTEL_COMPILER) + #if (__INTEL_COMPILER >= 1800) // fix that check + #define Z7_COMPILER_SHA256_SUPPORTED + #endif + #endif +#elif defined(MY_CPU_ARM_OR_ARM64) + #ifdef _MSC_VER + #if _MSC_VER >= 1910 + #define Z7_COMPILER_SHA256_SUPPORTED + #endif + #elif defined(__clang__) + #if (__clang_major__ >= 8) // fix that check + #define Z7_COMPILER_SHA256_SUPPORTED + #endif + #elif defined(__GNUC__) + #if (__GNUC__ >= 6) // fix that check + #define Z7_COMPILER_SHA256_SUPPORTED + #endif + #endif +#endif + +void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); + +#ifdef Z7_COMPILER_SHA256_SUPPORTED + void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); + + static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS = Sha256_UpdateBlocks; + static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS_HW; + + #define SHA256_UPDATE_BLOCKS(p) p->func_UpdateBlocks +#else + #define SHA256_UPDATE_BLOCKS(p) Sha256_UpdateBlocks +#endif + + +BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo) +{ + SHA256_FUNC_UPDATE_BLOCKS func = Sha256_UpdateBlocks; + + #ifdef Z7_COMPILER_SHA256_SUPPORTED + if (algo != SHA256_ALGO_SW) + { + if (algo == SHA256_ALGO_DEFAULT) + func = g_SHA256_FUNC_UPDATE_BLOCKS; + else + { + if (algo != SHA256_ALGO_HW) + return False; + func = g_SHA256_FUNC_UPDATE_BLOCKS_HW; + if (!func) + return False; + } + } + #else + if (algo > 1) + return False; + #endif + + p->func_UpdateBlocks = func; + return True; +} + + +/* define it for speed optimization */ + +#ifdef Z7_SFX + #define STEP_PRE 1 + #define STEP_MAIN 1 +#else + #define STEP_PRE 2 + #define STEP_MAIN 4 + // #define Z7_SHA256_UNROLL +#endif + +#undef Z7_SHA256_BIG_W +#if STEP_MAIN != 16 + #define Z7_SHA256_BIG_W +#endif + + + + +void Sha256_InitState(CSha256 *p) +{ + p->count = 0; + p->state[0] = 0x6a09e667; + p->state[1] = 0xbb67ae85; + p->state[2] = 0x3c6ef372; + p->state[3] = 0xa54ff53a; + p->state[4] = 0x510e527f; + p->state[5] = 0x9b05688c; + p->state[6] = 0x1f83d9ab; + p->state[7] = 0x5be0cd19; +} + +void Sha256_Init(CSha256 *p) +{ + p->func_UpdateBlocks = + #ifdef Z7_COMPILER_SHA256_SUPPORTED + g_SHA256_FUNC_UPDATE_BLOCKS; + #else + NULL; + #endif + Sha256_InitState(p); +} + +#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) +#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) +#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) +#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + + +#define W_PRE(i) (W[(i) + (size_t)(j)] = GetBe32(data + ((size_t)(j) + i) * 4)) + +#define blk2_main(j, i) s1(w(j, (i)-2)) + w(j, (i)-7) + s0(w(j, (i)-15)) + +#ifdef Z7_SHA256_BIG_W + // we use +i instead of +(i) to change the order to solve CLANG compiler warning for signed/unsigned. + #define w(j, i) W[(size_t)(j) + i] + #define blk2(j, i) (w(j, i) = w(j, (i)-16) + blk2_main(j, i)) +#else + #if STEP_MAIN == 16 + #define w(j, i) W[(i) & 15] + #else + #define w(j, i) W[((size_t)(j) + (i)) & 15] + #endif + #define blk2(j, i) (w(j, i) += blk2_main(j, i)) +#endif + +#define W_MAIN(i) blk2(j, i) + + +#define T1(wx, i) \ + tmp = h + S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + h = g; \ + g = f; \ + f = e; \ + e = d + tmp; \ + tmp += S0(a) + Maj(a, b, c); \ + d = c; \ + c = b; \ + b = a; \ + a = tmp; \ + +#define R1_PRE(i) T1( W_PRE, i) +#define R1_MAIN(i) T1( W_MAIN, i) + +#if (!defined(Z7_SHA256_UNROLL) || STEP_MAIN < 8) && (STEP_MAIN >= 4) +#define R2_MAIN(i) \ + R1_MAIN(i) \ + R1_MAIN(i + 1) \ + +#endif + + + +#if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8 + +#define T4( a,b,c,d,e,f,g,h, wx, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + tmp = h; \ + h += d; \ + d = tmp + S0(a) + Maj(a, b, c); \ + +#define R4( wx, i) \ + T4 ( a,b,c,d,e,f,g,h, wx, (i )); \ + T4 ( d,a,b,c,h,e,f,g, wx, (i+1)); \ + T4 ( c,d,a,b,g,h,e,f, wx, (i+2)); \ + T4 ( b,c,d,a,f,g,h,e, wx, (i+3)); \ + +#define R4_PRE(i) R4( W_PRE, i) +#define R4_MAIN(i) R4( W_MAIN, i) + + +#define T8( a,b,c,d,e,f,g,h, wx, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + d += h; \ + h += S0(a) + Maj(a, b, c); \ + +#define R8( wx, i) \ + T8 ( a,b,c,d,e,f,g,h, wx, i ); \ + T8 ( h,a,b,c,d,e,f,g, wx, i+1); \ + T8 ( g,h,a,b,c,d,e,f, wx, i+2); \ + T8 ( f,g,h,a,b,c,d,e, wx, i+3); \ + T8 ( e,f,g,h,a,b,c,d, wx, i+4); \ + T8 ( d,e,f,g,h,a,b,c, wx, i+5); \ + T8 ( c,d,e,f,g,h,a,b, wx, i+6); \ + T8 ( b,c,d,e,f,g,h,a, wx, i+7); \ + +#define R8_PRE(i) R8( W_PRE, i) +#define R8_MAIN(i) R8( W_MAIN, i) + +#endif + +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); + +// static +extern MY_ALIGN(64) +const UInt32 SHA256_K_ARRAY[64]; + +MY_ALIGN(64) +const UInt32 SHA256_K_ARRAY[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +#define K SHA256_K_ARRAY + + +Z7_NO_INLINE +void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + UInt32 W + #ifdef Z7_SHA256_BIG_W + [64]; + #else + [16]; + #endif + + unsigned j; + + UInt32 a,b,c,d,e,f,g,h; + + #if !defined(Z7_SHA256_UNROLL) || (STEP_MAIN <= 4) || (STEP_PRE <= 4) + UInt32 tmp; + #endif + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; + + while (numBlocks) + { + + for (j = 0; j < 16; j += STEP_PRE) + { + #if STEP_PRE > 4 + + #if STEP_PRE < 8 + R4_PRE(0); + #else + R8_PRE(0); + #if STEP_PRE == 16 + R8_PRE(8); + #endif + #endif + + #else + + R1_PRE(0) + #if STEP_PRE >= 2 + R1_PRE(1) + #if STEP_PRE >= 4 + R1_PRE(2) + R1_PRE(3) + #endif + #endif + + #endif + } + + for (j = 16; j < 64; j += STEP_MAIN) + { + #if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8 + + #if STEP_MAIN < 8 + R4_MAIN(0) + #else + R8_MAIN(0) + #if STEP_MAIN == 16 + R8_MAIN(8) + #endif + #endif + + #else + + R1_MAIN(0) + #if STEP_MAIN >= 2 + R1_MAIN(1) + #if STEP_MAIN >= 4 + R2_MAIN(2) + #if STEP_MAIN >= 8 + R2_MAIN(4) + R2_MAIN(6) + #if STEP_MAIN >= 16 + R2_MAIN(8) + R2_MAIN(10) + R2_MAIN(12) + R2_MAIN(14) + #endif + #endif + #endif + #endif + #endif + } + + a += state[0]; state[0] = a; + b += state[1]; state[1] = b; + c += state[2]; state[2] = c; + d += state[3]; state[3] = d; + e += state[4]; state[4] = e; + f += state[5]; state[5] = f; + g += state[6]; state[6] = g; + h += state[7]; state[7] = h; + + data += 64; + numBlocks--; + } + + /* Wipe variables */ + /* memset(W, 0, sizeof(W)); */ +} + +#undef S0 +#undef S1 +#undef s0 +#undef s1 +#undef K + +#define Sha256_UpdateBlock(p) SHA256_UPDATE_BLOCKS(p)(p->state, p->buffer, 1) + +void Sha256_Update(CSha256 *p, const Byte *data, size_t size) +{ + if (size == 0) + return; + + { + unsigned pos = (unsigned)p->count & 0x3F; + unsigned num; + + p->count += size; + + num = 64 - pos; + if (num > size) + { + memcpy(p->buffer + pos, data, size); + return; + } + + if (pos != 0) + { + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; + Sha256_UpdateBlock(p); + } + } + { + size_t numBlocks = size >> 6; + SHA256_UPDATE_BLOCKS(p)(p->state, data, numBlocks); + size &= 0x3F; + if (size == 0) + return; + data += (numBlocks << 6); + memcpy(p->buffer, data, size); + } +} + + +void Sha256_Final(CSha256 *p, Byte *digest) +{ + unsigned pos = (unsigned)p->count & 0x3F; + unsigned i; + + p->buffer[pos++] = 0x80; + + if (pos > (64 - 8)) + { + while (pos != 64) { p->buffer[pos++] = 0; } + // memset(&p->buf.buffer[pos], 0, 64 - pos); + Sha256_UpdateBlock(p); + pos = 0; + } + + /* + if (pos & 3) + { + p->buffer[pos] = 0; + p->buffer[pos + 1] = 0; + p->buffer[pos + 2] = 0; + pos += 3; + pos &= ~3; + } + { + for (; pos < 64 - 8; pos += 4) + *(UInt32 *)(&p->buffer[pos]) = 0; + } + */ + + memset(&p->buffer[pos], 0, (64 - 8) - pos); + + { + UInt64 numBits = (p->count << 3); + SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)) + SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)) + } + + Sha256_UpdateBlock(p); + + for (i = 0; i < 8; i += 2) + { + UInt32 v0 = p->state[i]; + UInt32 v1 = p->state[(size_t)i + 1]; + SetBe32(digest , v0) + SetBe32(digest + 4, v1) + digest += 8; + } + + Sha256_InitState(p); +} + + +void Sha256Prepare(void) +{ + #ifdef Z7_COMPILER_SHA256_SUPPORTED + SHA256_FUNC_UPDATE_BLOCKS f, f_hw; + f = Sha256_UpdateBlocks; + f_hw = NULL; + #ifdef MY_CPU_X86_OR_AMD64 + #ifndef USE_MY_MM + if (CPU_IsSupported_SHA() + && CPU_IsSupported_SSSE3() + // && CPU_IsSupported_SSE41() + ) + #endif + #else + if (CPU_IsSupported_SHA2()) + #endif + { + // printf("\n========== HW SHA256 ======== \n"); + f = f_hw = Sha256_UpdateBlocks_HW; + } + g_SHA256_FUNC_UPDATE_BLOCKS = f; + g_SHA256_FUNC_UPDATE_BLOCKS_HW = f_hw; + #endif +} + +#undef S0 +#undef S1 +#undef s0 +#undef s1 +#undef Ch +#undef Maj +#undef W_MAIN +#undef W_PRE +#undef w +#undef blk2_main +#undef blk2 +#undef T1 +#undef T4 +#undef T8 +#undef R1_PRE +#undef R1_MAIN +#undef R2_MAIN +#undef R4 +#undef R4_PRE +#undef R4_MAIN +#undef R8 +#undef R8_PRE +#undef R8_MAIN +#undef STEP_PRE +#undef STEP_MAIN +#undef Z7_SHA256_BIG_W +#undef Z7_SHA256_UNROLL +#undef Z7_COMPILER_SHA256_SUPPORTED diff --git a/libraries/lzma/C/Sha256.h b/libraries/lzma/C/Sha256.h new file mode 100644 index 00000000000..9e0422320c7 --- /dev/null +++ b/libraries/lzma/C/Sha256.h @@ -0,0 +1,76 @@ +/* Sha256.h -- SHA-256 Hash +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_SHA256_H +#define ZIP7_INC_SHA256_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define SHA256_NUM_BLOCK_WORDS 16 +#define SHA256_NUM_DIGEST_WORDS 8 + +#define SHA256_BLOCK_SIZE (SHA256_NUM_BLOCK_WORDS * 4) +#define SHA256_DIGEST_SIZE (SHA256_NUM_DIGEST_WORDS * 4) + +typedef void (Z7_FASTCALL *SHA256_FUNC_UPDATE_BLOCKS)(UInt32 state[8], const Byte *data, size_t numBlocks); + +/* + if (the system supports different SHA256 code implementations) + { + (CSha256::func_UpdateBlocks) will be used + (CSha256::func_UpdateBlocks) can be set by + Sha256_Init() - to default (fastest) + Sha256_SetFunction() - to any algo + } + else + { + (CSha256::func_UpdateBlocks) is ignored. + } +*/ + +typedef struct +{ + SHA256_FUNC_UPDATE_BLOCKS func_UpdateBlocks; + UInt64 count; + UInt64 _pad_2[2]; + UInt32 state[SHA256_NUM_DIGEST_WORDS]; + + Byte buffer[SHA256_BLOCK_SIZE]; +} CSha256; + + +#define SHA256_ALGO_DEFAULT 0 +#define SHA256_ALGO_SW 1 +#define SHA256_ALGO_HW 2 + +/* +Sha256_SetFunction() +return: + 0 - (algo) value is not supported, and func_UpdateBlocks was not changed + 1 - func_UpdateBlocks was set according (algo) value. +*/ + +BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo); + +void Sha256_InitState(CSha256 *p); +void Sha256_Init(CSha256 *p); +void Sha256_Update(CSha256 *p, const Byte *data, size_t size); +void Sha256_Final(CSha256 *p, Byte *digest); + + + + +// void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); + +/* +call Sha256Prepare() once at program start. +It prepares all supported implementations, and detects the fastest implementation. +*/ + +void Sha256Prepare(void); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/Sha256Opt.c b/libraries/lzma/C/Sha256Opt.c new file mode 100644 index 00000000000..e4465e3e7d7 --- /dev/null +++ b/libraries/lzma/C/Sha256Opt.c @@ -0,0 +1,386 @@ +/* Sha256Opt.c -- SHA-256 optimized code for SHA-256 hardware instructions +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" +#include "Compiler.h" +#include "CpuArch.h" + +#if defined(_MSC_VER) +#if (_MSC_VER < 1900) && (_MSC_VER >= 1200) +// #define USE_MY_MM +#endif +#endif + +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) // fix that check + #define USE_HW_SHA + #elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) + #define USE_HW_SHA + #if !defined(_INTEL_COMPILER) + // icc defines __GNUC__, but icc doesn't support __attribute__(__target__) + #if !defined(__SHA__) || !defined(__SSSE3__) + #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) + #endif + #endif + #elif defined(_MSC_VER) + #ifdef USE_MY_MM + #define USE_VER_MIN 1300 + #else + #define USE_VER_MIN 1900 + #endif + #if (_MSC_VER >= USE_VER_MIN) + #define USE_HW_SHA + #endif + #endif +// #endif // MY_CPU_X86_OR_AMD64 + +#ifdef USE_HW_SHA + +// #pragma message("Sha256 HW") + +// sse/sse2/ssse3: +#include +// sha*: +#include + +#if defined (__clang__) && defined(_MSC_VER) + // #if !defined(__SSSE3__) + // #endif + #if !defined(__SHA__) + #include + #endif +#else + +#ifdef USE_MY_MM +#include "My_mm.h" +#endif + +#endif + +/* +SHA256 uses: +SSE2: + _mm_loadu_si128 + _mm_storeu_si128 + _mm_set_epi32 + _mm_add_epi32 + _mm_shuffle_epi32 / pshufd + + + +SSSE3: + _mm_shuffle_epi8 / pshufb + _mm_alignr_epi8 +SHA: + _mm_sha256* +*/ + +// K array must be aligned for 16-bytes at least. +// The compiler can look align attribute and selects +// movdqu - for code without align attribute +// movdqa - for code with align attribute +extern +MY_ALIGN(64) +const UInt32 SHA256_K_ARRAY[64]; + +#define K SHA256_K_ARRAY + + +#define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src); +#define SHA256_MSG1(dest, src) dest = _mm_sha256msg1_epu32(dest, src); +#define SHA25G_MSG2(dest, src) dest = _mm_sha256msg2_epu32(dest, src); + + +#define LOAD_SHUFFLE(m, k) \ + m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \ + m = _mm_shuffle_epi8(m, mask); \ + +#define SM1(g0, g1, g2, g3) \ + SHA256_MSG1(g3, g0); \ + +#define SM2(g0, g1, g2, g3) \ + tmp = _mm_alignr_epi8(g1, g0, 4); \ + ADD_EPI32(g2, tmp) \ + SHA25G_MSG2(g2, g1); \ + +// #define LS0(k, g0, g1, g2, g3) LOAD_SHUFFLE(g0, k) +// #define LS1(k, g0, g1, g2, g3) LOAD_SHUFFLE(g1, k+1) + + +#define NNN(g0, g1, g2, g3) + + +#define RND2(t0, t1) \ + t0 = _mm_sha256rnds2_epu32(t0, t1, msg); + +#define RND2_0(m, k) \ + msg = _mm_add_epi32(m, *(const __m128i *) (const void *) &K[(k) * 4]); \ + RND2(state0, state1); \ + msg = _mm_shuffle_epi32(msg, 0x0E); \ + + +#define RND2_1 \ + RND2(state1, state0); \ + + +// We use scheme with 3 rounds ahead for SHA256_MSG1 / 2 rounds ahead for SHA256_MSG2 + +#define R4(k, g0, g1, g2, g3, OP0, OP1) \ + RND2_0(g0, k) \ + OP0(g0, g1, g2, g3) \ + RND2_1 \ + OP1(g0, g1, g2, g3) \ + +#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ + R4 ( (k)*4+0, m0,m1,m2,m3, OP0, OP1 ) \ + R4 ( (k)*4+1, m1,m2,m3,m0, OP2, OP3 ) \ + R4 ( (k)*4+2, m2,m3,m0,m1, OP4, OP5 ) \ + R4 ( (k)*4+3, m3,m0,m1,m2, OP6, OP7 ) \ + +#define PREPARE_STATE \ + tmp = _mm_shuffle_epi32(state0, 0x1B); /* abcd */ \ + state0 = _mm_shuffle_epi32(state1, 0x1B); /* efgh */ \ + state1 = state0; \ + state0 = _mm_unpacklo_epi64(state0, tmp); /* cdgh */ \ + state1 = _mm_unpackhi_epi64(state1, tmp); /* abef */ \ + + +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); +#ifdef ATTRIB_SHA +ATTRIB_SHA +#endif +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + const __m128i mask = _mm_set_epi32(0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203); + __m128i tmp; + __m128i state0, state1; + + if (numBlocks == 0) + return; + + state0 = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); + state1 = _mm_loadu_si128((const __m128i *) (const void *) &state[4]); + + PREPARE_STATE + + do + { + __m128i state0_save, state1_save; + __m128i m0, m1, m2, m3; + __m128i msg; + // #define msg tmp + + state0_save = state0; + state1_save = state1; + + LOAD_SHUFFLE (m0, 0) + LOAD_SHUFFLE (m1, 1) + LOAD_SHUFFLE (m2, 2) + LOAD_SHUFFLE (m3, 3) + + + + R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ) + R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ) + + ADD_EPI32(state0, state0_save) + ADD_EPI32(state1, state1_save) + + data += 64; + } + while (--numBlocks); + + PREPARE_STATE + + _mm_storeu_si128((__m128i *) (void *) &state[0], state0); + _mm_storeu_si128((__m128i *) (void *) &state[4], state1); +} + +#endif // USE_HW_SHA + +#elif defined(MY_CPU_ARM_OR_ARM64) + + #if defined(__clang__) + #if (__clang_major__ >= 8) // fix that check + #define USE_HW_SHA + #endif + #elif defined(__GNUC__) + #if (__GNUC__ >= 6) // fix that check + #define USE_HW_SHA + #endif + #elif defined(_MSC_VER) + #if _MSC_VER >= 1910 + #define USE_HW_SHA + #endif + #endif + +#ifdef USE_HW_SHA + +// #pragma message("=== Sha256 HW === ") + +#if defined(__clang__) || defined(__GNUC__) + #ifdef MY_CPU_ARM64 + #define ATTRIB_SHA __attribute__((__target__("+crypto"))) + #else + #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) + #endif +#else + // _MSC_VER + // for arm32 + #define _ARM_USE_NEW_NEON_INTRINSICS +#endif + +#if defined(_MSC_VER) && defined(MY_CPU_ARM64) +#include +#else +#include +#endif + +typedef uint32x4_t v128; +// typedef __n128 v128; // MSVC + +#ifdef MY_CPU_BE + #define MY_rev32_for_LE(x) +#else + #define MY_rev32_for_LE(x) x = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(x))) +#endif + +#define LOAD_128(_p) (*(const v128 *)(const void *)(_p)) +#define STORE_128(_p, _v) *(v128 *)(void *)(_p) = (_v) + +#define LOAD_SHUFFLE(m, k) \ + m = LOAD_128((data + (k) * 16)); \ + MY_rev32_for_LE(m); \ + +// K array must be aligned for 16-bytes at least. +extern +MY_ALIGN(64) +const UInt32 SHA256_K_ARRAY[64]; + +#define K SHA256_K_ARRAY + + +#define SHA256_SU0(dest, src) dest = vsha256su0q_u32(dest, src); +#define SHA25G_SU1(dest, src2, src3) dest = vsha256su1q_u32(dest, src2, src3); + +#define SM1(g0, g1, g2, g3) SHA256_SU0(g3, g0) +#define SM2(g0, g1, g2, g3) SHA25G_SU1(g2, g0, g1) +#define NNN(g0, g1, g2, g3) + + +#define R4(k, g0, g1, g2, g3, OP0, OP1) \ + msg = vaddq_u32(g0, *(const v128 *) (const void *) &K[(k) * 4]); \ + tmp = state0; \ + state0 = vsha256hq_u32( state0, state1, msg ); \ + state1 = vsha256h2q_u32( state1, tmp, msg ); \ + OP0(g0, g1, g2, g3); \ + OP1(g0, g1, g2, g3); \ + + +#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ + R4 ( (k)*4+0, m0, m1, m2, m3, OP0, OP1 ) \ + R4 ( (k)*4+1, m1, m2, m3, m0, OP2, OP3 ) \ + R4 ( (k)*4+2, m2, m3, m0, m1, OP4, OP5 ) \ + R4 ( (k)*4+3, m3, m0, m1, m2, OP6, OP7 ) \ + + +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); +#ifdef ATTRIB_SHA +ATTRIB_SHA +#endif +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + v128 state0, state1; + + if (numBlocks == 0) + return; + + state0 = LOAD_128(&state[0]); + state1 = LOAD_128(&state[4]); + + do + { + v128 state0_save, state1_save; + v128 m0, m1, m2, m3; + v128 msg, tmp; + + state0_save = state0; + state1_save = state1; + + LOAD_SHUFFLE (m0, 0) + LOAD_SHUFFLE (m1, 1) + LOAD_SHUFFLE (m2, 2) + LOAD_SHUFFLE (m3, 3) + + R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ); + R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ); + R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ); + R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ); + + state0 = vaddq_u32(state0, state0_save); + state1 = vaddq_u32(state1, state1_save); + + data += 64; + } + while (--numBlocks); + + STORE_128(&state[0], state0); + STORE_128(&state[4], state1); +} + +#endif // USE_HW_SHA + +#endif // MY_CPU_ARM_OR_ARM64 + + +#ifndef USE_HW_SHA + +// #error Stop_Compiling_UNSUPPORTED_SHA +// #include + +// #include "Sha256.h" +void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); + +#pragma message("Sha256 HW-SW stub was used") + +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + Sha256_UpdateBlocks(state, data, numBlocks); + /* + UNUSED_VAR(state); + UNUSED_VAR(data); + UNUSED_VAR(numBlocks); + exit(1); + return; + */ +} + +#endif + + + +#undef K +#undef RND2 +#undef RND2_0 +#undef RND2_1 + +#undef MY_rev32_for_LE +#undef NNN +#undef LOAD_128 +#undef STORE_128 +#undef LOAD_SHUFFLE +#undef SM1 +#undef SM2 + +#undef NNN +#undef R4 +#undef R16 +#undef PREPARE_STATE +#undef USE_HW_SHA +#undef ATTRIB_SHA +#undef USE_VER_MIN diff --git a/libraries/lzma/C/Sort.c b/libraries/lzma/C/Sort.c new file mode 100644 index 00000000000..e1097e38068 --- /dev/null +++ b/libraries/lzma/C/Sort.c @@ -0,0 +1,141 @@ +/* Sort.c -- Sort functions +2014-04-05 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Sort.h" + +#define HeapSortDown(p, k, size, temp) \ + { for (;;) { \ + size_t s = (k << 1); \ + if (s > size) break; \ + if (s < size && p[s + 1] > p[s]) s++; \ + if (temp >= p[s]) break; \ + p[k] = p[s]; k = s; \ + } p[k] = temp; } + +void HeapSort(UInt32 *p, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt32 temp = p[i]; + size_t k = i; + HeapSortDown(p, k, size, temp) + } + while (--i != 0); + } + /* + do + { + size_t k = 1; + UInt32 temp = p[size]; + p[size--] = p[1]; + HeapSortDown(p, k, size, temp) + } + while (size > 1); + */ + while (size > 3) + { + UInt32 temp = p[size]; + size_t k = (p[3] > p[2]) ? 3 : 2; + p[size--] = p[1]; + p[1] = p[k]; + HeapSortDown(p, k, size, temp) + } + { + UInt32 temp = p[size]; + p[size] = p[1]; + if (size > 2 && p[2] < temp) + { + p[1] = p[2]; + p[2] = temp; + } + else + p[1] = temp; + } +} + +void HeapSort64(UInt64 *p, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt64 temp = p[i]; + size_t k = i; + HeapSortDown(p, k, size, temp) + } + while (--i != 0); + } + /* + do + { + size_t k = 1; + UInt64 temp = p[size]; + p[size--] = p[1]; + HeapSortDown(p, k, size, temp) + } + while (size > 1); + */ + while (size > 3) + { + UInt64 temp = p[size]; + size_t k = (p[3] > p[2]) ? 3 : 2; + p[size--] = p[1]; + p[1] = p[k]; + HeapSortDown(p, k, size, temp) + } + { + UInt64 temp = p[size]; + p[size] = p[1]; + if (size > 2 && p[2] < temp) + { + p[1] = p[2]; + p[2] = temp; + } + else + p[1] = temp; + } +} + +/* +#define HeapSortRefDown(p, vals, n, size, temp) \ + { size_t k = n; UInt32 val = vals[temp]; for (;;) { \ + size_t s = (k << 1); \ + if (s > size) break; \ + if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \ + if (val >= vals[p[s]]) break; \ + p[k] = p[s]; k = s; \ + } p[k] = temp; } + +void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt32 temp = p[i]; + HeapSortRefDown(p, vals, i, size, temp); + } + while (--i != 0); + } + do + { + UInt32 temp = p[size]; + p[size--] = p[1]; + HeapSortRefDown(p, vals, 1, size, temp); + } + while (size > 1); +} +*/ diff --git a/libraries/lzma/C/Sort.h b/libraries/lzma/C/Sort.h new file mode 100644 index 00000000000..1817b652f55 --- /dev/null +++ b/libraries/lzma/C/Sort.h @@ -0,0 +1,18 @@ +/* Sort.h -- Sort functions +2023-03-05 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_SORT_H +#define ZIP7_INC_SORT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void HeapSort(UInt32 *p, size_t size); +void HeapSort64(UInt64 *p, size_t size); + +/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */ + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/SwapBytes.c b/libraries/lzma/C/SwapBytes.c new file mode 100644 index 00000000000..7901bbaa87e --- /dev/null +++ b/libraries/lzma/C/SwapBytes.c @@ -0,0 +1,800 @@ +/* SwapBytes.c -- Byte Swap conversion filter +2023-04-07 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Compiler.h" +#include "CpuArch.h" +#include "RotateDefs.h" +#include "SwapBytes.h" + +typedef UInt16 CSwapUInt16; +typedef UInt32 CSwapUInt32; + +// #define k_SwapBytes_Mode_BASE 0 + +#ifdef MY_CPU_X86_OR_AMD64 + +#define k_SwapBytes_Mode_SSE2 1 +#define k_SwapBytes_Mode_SSSE3 2 +#define k_SwapBytes_Mode_AVX2 3 + + // #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) + #if defined(__clang__) && (__clang_major__ >= 4) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701) + #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2 + #define SWAP_ATTRIB_SSE2 __attribute__((__target__("sse2"))) + #define SWAP_ATTRIB_SSSE3 __attribute__((__target__("ssse3"))) + #define SWAP_ATTRIB_AVX2 __attribute__((__target__("avx2"))) + #elif defined(_MSC_VER) + #if (_MSC_VER == 1900) + #pragma warning(disable : 4752) // found Intel(R) Advanced Vector Extensions; consider using /arch:AVX + #endif + #if (_MSC_VER >= 1900) + #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2 + #elif (_MSC_VER >= 1500) // (VS2008) + #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSSE3 + #elif (_MSC_VER >= 1310) // (VS2003) + #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSE2 + #endif + #endif // _MSC_VER + +/* +// for debug +#ifdef k_SwapBytes_Mode_MAX +#undef k_SwapBytes_Mode_MAX +#endif +*/ + +#ifndef k_SwapBytes_Mode_MAX +#define k_SwapBytes_Mode_MAX 0 +#endif + +#if (k_SwapBytes_Mode_MAX != 0) && defined(MY_CPU_AMD64) + #define k_SwapBytes_Mode_MIN k_SwapBytes_Mode_SSE2 +#else + #define k_SwapBytes_Mode_MIN 0 +#endif + +#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_AVX2) + #define USE_SWAP_AVX2 +#endif +#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSSE3) + #define USE_SWAP_SSSE3 +#endif +#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSE2) + #define USE_SWAP_128 +#endif + +#if k_SwapBytes_Mode_MAX <= k_SwapBytes_Mode_MIN || !defined(USE_SWAP_128) +#define FORCE_SWAP_MODE +#endif + + +#ifdef USE_SWAP_128 +/* + MMX + SSE + SSE2 + SSE3 + SSSE3 + SSE4.1 + SSE4.2 + SSE4A + AES + AVX, AVX2, FMA +*/ + +#include // sse2 +// typedef __m128i v128; + +#define SWAP2_128(i) { \ + const __m128i v = *(const __m128i *)(const void *)(items + (i) * 8); \ + *( __m128i *)( void *)(items + (i) * 8) = \ + _mm_or_si128( \ + _mm_slli_epi16(v, 8), \ + _mm_srli_epi16(v, 8)); } +// _mm_or_si128() has more ports to execute than _mm_add_epi16(). + +static +#ifdef SWAP_ATTRIB_SSE2 +SWAP_ATTRIB_SSE2 +#endif +void +Z7_FASTCALL +SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP2_128(0) SWAP2_128(1) items += 2 * 8; + SWAP2_128(0) SWAP2_128(1) items += 2 * 8; + } + while (items != lim); +} + +/* +// sse2 +#define SWAP4_128_pack(i) { \ + __m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \ + __m128i v0 = _mm_unpacklo_epi8(v, mask); \ + __m128i v1 = _mm_unpackhi_epi8(v, mask); \ + v0 = _mm_shufflelo_epi16(v0, 0x1b); \ + v1 = _mm_shufflelo_epi16(v1, 0x1b); \ + v0 = _mm_shufflehi_epi16(v0, 0x1b); \ + v1 = _mm_shufflehi_epi16(v1, 0x1b); \ + *(__m128i *)(void *)(items + (i) * 4) = _mm_packus_epi16(v0, v1); } + +static +#ifdef SWAP_ATTRIB_SSE2 +SWAP_ATTRIB_SSE2 +#endif +void +Z7_FASTCALL +SwapBytes4_128_pack(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + const __m128i mask = _mm_setzero_si128(); + // const __m128i mask = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP4_128_pack(0); items += 1 * 4; + // SWAP4_128_pack(0); SWAP4_128_pack(1); items += 2 * 4; + } + while (items != lim); +} + +// sse2 +#define SWAP4_128_shift(i) { \ + __m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \ + __m128i v2; \ + v2 = _mm_or_si128( \ + _mm_slli_si128(_mm_and_si128(v, mask), 1), \ + _mm_and_si128(_mm_srli_si128(v, 1), mask)); \ + v = _mm_or_si128( \ + _mm_slli_epi32(v, 24), \ + _mm_srli_epi32(v, 24)); \ + *(__m128i *)(void *)(items + (i) * 4) = _mm_or_si128(v2, v); } + +static +#ifdef SWAP_ATTRIB_SSE2 +SWAP_ATTRIB_SSE2 +#endif +void +Z7_FASTCALL +SwapBytes4_128_shift(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + #define M1 0xff00 + const __m128i mask = _mm_set_epi32(M1, M1, M1, M1); + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + // SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4; + // SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4; + SWAP4_128_shift(0); items += 1 * 4; + } + while (items != lim); +} +*/ + + +#if defined(USE_SWAP_SSSE3) || defined(USE_SWAP_AVX2) + +#define SWAP_SHUF_REV_SEQ_2_VALS(v) (v)+1, (v) +#define SWAP_SHUF_REV_SEQ_4_VALS(v) (v)+3, (v)+2, (v)+1, (v) + +#define SWAP2_SHUF_MASK_16_BYTES \ + SWAP_SHUF_REV_SEQ_2_VALS (0 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (1 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (2 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (3 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (4 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (5 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (6 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (7 * 2) + +#define SWAP4_SHUF_MASK_16_BYTES \ + SWAP_SHUF_REV_SEQ_4_VALS (0 * 4), \ + SWAP_SHUF_REV_SEQ_4_VALS (1 * 4), \ + SWAP_SHUF_REV_SEQ_4_VALS (2 * 4), \ + SWAP_SHUF_REV_SEQ_4_VALS (3 * 4) + +#if defined(USE_SWAP_AVX2) +/* if we use 256_BIT_INIT_MASK, each static array mask will be larger for 16 bytes */ +// #define SWAP_USE_256_BIT_INIT_MASK +#endif + +#if defined(SWAP_USE_256_BIT_INIT_MASK) && defined(USE_SWAP_AVX2) +#define SWAP_MASK_INIT_SIZE 32 +#else +#define SWAP_MASK_INIT_SIZE 16 +#endif + +MY_ALIGN(SWAP_MASK_INIT_SIZE) +static const Byte k_ShufMask_Swap2[] = +{ + SWAP2_SHUF_MASK_16_BYTES + #if SWAP_MASK_INIT_SIZE > 16 + , SWAP2_SHUF_MASK_16_BYTES + #endif +}; + +MY_ALIGN(SWAP_MASK_INIT_SIZE) +static const Byte k_ShufMask_Swap4[] = +{ + SWAP4_SHUF_MASK_16_BYTES + #if SWAP_MASK_INIT_SIZE > 16 + , SWAP4_SHUF_MASK_16_BYTES + #endif +}; + + +#ifdef USE_SWAP_SSSE3 + +#include // ssse3 + +#define SHUF_128(i) *(items + (i)) = \ + _mm_shuffle_epi8(*(items + (i)), mask); // SSSE3 + +// Z7_NO_INLINE +static +#ifdef SWAP_ATTRIB_SSSE3 +SWAP_ATTRIB_SSSE3 +#endif +Z7_ATTRIB_NO_VECTORIZE +void +Z7_FASTCALL +ShufBytes_128(void *items8, const void *lim8, const void *mask128_ptr) +{ + __m128i *items = (__m128i *)items8; + const __m128i *lim = (const __m128i *)lim8; + // const __m128i mask = _mm_set_epi8(SHUF_SWAP2_MASK_16_VALS); + // const __m128i mask = _mm_set_epi8(SHUF_SWAP4_MASK_16_VALS); + // const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); + // const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); + // const __m128i mask = *(const __m128i *)(const void *)&(k_ShufMask_Swap4[0]); + const __m128i mask = *(const __m128i *)mask128_ptr; + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SHUF_128(0) SHUF_128(1) items += 2; + SHUF_128(0) SHUF_128(1) items += 2; + } + while (items != lim); +} + +#endif // USE_SWAP_SSSE3 + + + +#ifdef USE_SWAP_AVX2 + +#include // avx, avx2 +#if defined(__clang__) +#include +#include +#endif + +#define SHUF_256(i) *(items + (i)) = \ + _mm256_shuffle_epi8(*(items + (i)), mask); // AVX2 + +// Z7_NO_INLINE +static +#ifdef SWAP_ATTRIB_AVX2 +SWAP_ATTRIB_AVX2 +#endif +Z7_ATTRIB_NO_VECTORIZE +void +Z7_FASTCALL +ShufBytes_256(void *items8, const void *lim8, const void *mask128_ptr) +{ + __m256i *items = (__m256i *)items8; + const __m256i *lim = (const __m256i *)lim8; + /* + UNUSED_VAR(mask128_ptr) + __m256i mask = + for Swap4: _mm256_setr_epi8(SWAP4_SHUF_MASK_16_BYTES, SWAP4_SHUF_MASK_16_BYTES); + for Swap2: _mm256_setr_epi8(SWAP2_SHUF_MASK_16_BYTES, SWAP2_SHUF_MASK_16_BYTES); + */ + const __m256i mask = + #if SWAP_MASK_INIT_SIZE > 16 + *(const __m256i *)(const void *)mask128_ptr; + #else + /* msvc: broadcastsi128() version reserves the stack for no reason + msvc 19.29-: _mm256_insertf128_si256() / _mm256_set_m128i)) versions use non-avx movdqu xmm0,XMMWORD PTR [r8] + msvc 19.30+ (VS2022): replaces _mm256_set_m128i(m,m) to vbroadcastf128(m) as we want + */ + // _mm256_broadcastsi128_si256(*mask128_ptr); + /* + #define MY_mm256_set_m128i(hi, lo) _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1) + MY_mm256_set_m128i + */ + _mm256_set_m128i( + *(const __m128i *)mask128_ptr, + *(const __m128i *)mask128_ptr); + #endif + + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SHUF_256(0) SHUF_256(1) items += 2; + SHUF_256(0) SHUF_256(1) items += 2; + } + while (items != lim); +} + +#endif // USE_SWAP_AVX2 +#endif // USE_SWAP_SSSE3 || USE_SWAP_AVX2 +#endif // USE_SWAP_128 + + + +// compile message "NEON intrinsics not available with the soft-float ABI" +#elif defined(MY_CPU_ARM_OR_ARM64) || \ + (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) +// #elif defined(MY_CPU_ARM64) + + #if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 8) + #if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) \ + || defined(MY_CPU_ARM64) + #define USE_SWAP_128 + #endif + #ifdef MY_CPU_ARM64 + // #define SWAP_ATTRIB_NEON __attribute__((__target__(""))) + #else + // #define SWAP_ATTRIB_NEON __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) + #endif + #elif defined(_MSC_VER) + #if (_MSC_VER >= 1910) + #define USE_SWAP_128 + #endif + #endif + + #if defined(_MSC_VER) && defined(MY_CPU_ARM64) + #include + #else + #include + #endif + +#ifndef USE_SWAP_128 + #define FORCE_SWAP_MODE +#else + +#ifdef MY_CPU_ARM64 + // for debug : comment it + #define FORCE_SWAP_MODE +#else + #define k_SwapBytes_Mode_NEON 1 +#endif +// typedef uint8x16_t v128; +#define SWAP2_128(i) *(uint8x16_t *) (void *)(items + (i) * 8) = \ + vrev16q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 8)); +#define SWAP4_128(i) *(uint8x16_t *) (void *)(items + (i) * 4) = \ + vrev32q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 4)); + +// Z7_NO_INLINE +static +#ifdef SWAP_ATTRIB_NEON +SWAP_ATTRIB_NEON +#endif +Z7_ATTRIB_NO_VECTORIZE +void +Z7_FASTCALL +SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP2_128(0) SWAP2_128(1) items += 2 * 8; + SWAP2_128(0) SWAP2_128(1) items += 2 * 8; + } + while (items != lim); +} + +// Z7_NO_INLINE +static +#ifdef SWAP_ATTRIB_NEON +SWAP_ATTRIB_NEON +#endif +Z7_ATTRIB_NO_VECTORIZE +void +Z7_FASTCALL +SwapBytes4_128(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP4_128(0) SWAP4_128(1) items += 2 * 4; + SWAP4_128(0) SWAP4_128(1) items += 2 * 4; + } + while (items != lim); +} + +#endif // USE_SWAP_128 + +#else // MY_CPU_ARM_OR_ARM64 +#define FORCE_SWAP_MODE +#endif // MY_CPU_ARM_OR_ARM64 + + + + + + +#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_X86) + /* _byteswap_ushort() in MSVC x86 32-bit works via slow { mov dh, al; mov dl, ah } + So we use own versions of byteswap function */ + #if (_MSC_VER < 1400 ) // old MSVC-X86 without _rotr16() support + #define SWAP2_16(i) { UInt32 v = items[i]; v += (v << 16); v >>= 8; items[i] = (CSwapUInt16)v; } + #else // is new MSVC-X86 with fast _rotr16() + #include + #define SWAP2_16(i) { items[i] = _rotr16(items[i], 8); } + #endif +#else // is not MSVC-X86 + #define SWAP2_16(i) { CSwapUInt16 v = items[i]; items[i] = Z7_BSWAP16(v); } +#endif // MSVC-X86 + +#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) + #define SWAP4_32(i) { CSwapUInt32 v = items[i]; items[i] = Z7_BSWAP32(v); } +#else + #define SWAP4_32(i) \ + { UInt32 v = items[i]; \ + v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff); \ + v = rotlFixed(v, 16); \ + items[i] = v; } +#endif + + + + +#if defined(FORCE_SWAP_MODE) && defined(USE_SWAP_128) + #define DEFAULT_Swap2 SwapBytes2_128 + #if !defined(MY_CPU_X86_OR_AMD64) + #define DEFAULT_Swap4 SwapBytes4_128 + #endif +#endif + +#if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4) + +#define SWAP_BASE_FUNCS_PREFIXES \ +Z7_FORCE_INLINE \ +static \ +Z7_ATTRIB_NO_VECTOR \ +void Z7_FASTCALL + + +#ifdef MY_CPU_64BIT + +#if defined(MY_CPU_ARM64) \ + && defined(__ARM_ARCH) && (__ARM_ARCH >= 8) \ + && ( (defined(__GNUC__) && (__GNUC__ >= 4)) \ + || (defined(__clang__) && (__clang_major__ >= 4))) + + #define SWAP2_64_VAR(v) asm ("rev16 %x0,%x0" : "+r" (v)); + #define SWAP4_64_VAR(v) asm ("rev32 %x0,%x0" : "+r" (v)); + +#else // is not ARM64-GNU + +#if !defined(MY_CPU_X86_OR_AMD64) || (k_SwapBytes_Mode_MIN == 0) || !defined(USE_SWAP_128) + #define SWAP2_64_VAR(v) \ + v = ( 0x00ff00ff00ff00ff & (v >> 8)) \ + + ((0x00ff00ff00ff00ff & v) << 8); + /* plus gives faster code in MSVC */ +#endif + +#ifdef Z7_CPU_FAST_BSWAP_SUPPORTED + #define SWAP4_64_VAR(v) \ + v = Z7_BSWAP64(v); \ + v = Z7_ROTL64(v, 32); +#else + #define SWAP4_64_VAR(v) \ + v = ( 0x000000ff000000ff & (v >> 24)) \ + + ((0x000000ff000000ff & v) << 24 ) \ + + ( 0x0000ff000000ff00 & (v >> 8)) \ + + ((0x0000ff000000ff00 & v) << 8 ) \ + ; +#endif + +#endif // ARM64-GNU + + +#ifdef SWAP2_64_VAR + +#define SWAP2_64(i) { \ + UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 4); \ + SWAP2_64_VAR(v) \ + *(UInt64 *)(void *)(items + (i) * 4) = v; } + +SWAP_BASE_FUNCS_PREFIXES +SwapBytes2_64(CSwapUInt16 *items, const CSwapUInt16 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP2_64(0) SWAP2_64(1) items += 2 * 4; + SWAP2_64(0) SWAP2_64(1) items += 2 * 4; + } + while (items != lim); +} + + #define DEFAULT_Swap2 SwapBytes2_64 + #if !defined(FORCE_SWAP_MODE) + #define SWAP2_DEFAULT_MODE 0 + #endif +#else // !defined(SWAP2_64_VAR) + #define DEFAULT_Swap2 SwapBytes2_128 + #if !defined(FORCE_SWAP_MODE) + #define SWAP2_DEFAULT_MODE 1 + #endif +#endif // SWAP2_64_VAR + + +#define SWAP4_64(i) { \ + UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 2); \ + SWAP4_64_VAR(v) \ + *(UInt64 *)(void *)(items + (i) * 2) = v; } + +SWAP_BASE_FUNCS_PREFIXES +SwapBytes4_64(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP4_64(0) SWAP4_64(1) items += 2 * 2; + SWAP4_64(0) SWAP4_64(1) items += 2 * 2; + } + while (items != lim); +} + +#define DEFAULT_Swap4 SwapBytes4_64 + +#else // is not 64BIT + + +#if defined(MY_CPU_ARM_OR_ARM64) \ + && defined(__ARM_ARCH) && (__ARM_ARCH >= 6) \ + && ( (defined(__GNUC__) && (__GNUC__ >= 4)) \ + || (defined(__clang__) && (__clang_major__ >= 4))) + +#ifdef MY_CPU_64BIT + #define SWAP2_32_VAR(v) asm ("rev16 %w0,%w0" : "+r" (v)); +#else + #define SWAP2_32_VAR(v) asm ("rev16 %0,%0" : "+r" (v)); // for clang/gcc + // asm ("rev16 %r0,%r0" : "+r" (a)); // for gcc +#endif + +#elif defined(_MSC_VER) && (_MSC_VER < 1300) && defined(MY_CPU_X86) \ + || !defined(Z7_CPU_FAST_BSWAP_SUPPORTED) \ + || !defined(Z7_CPU_FAST_ROTATE_SUPPORTED) + // old msvc doesn't support _byteswap_ulong() + #define SWAP2_32_VAR(v) \ + v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff); + +#else // is not ARM and is not old-MSVC-X86 and fast BSWAP/ROTATE are supported + #define SWAP2_32_VAR(v) \ + v = Z7_BSWAP32(v); \ + v = rotlFixed(v, 16); + +#endif // GNU-ARM* + +#define SWAP2_32(i) { \ + UInt32 v = *(const UInt32 *)(const void *)(items + (i) * 2); \ + SWAP2_32_VAR(v); \ + *(UInt32 *)(void *)(items + (i) * 2) = v; } + + +SWAP_BASE_FUNCS_PREFIXES +SwapBytes2_32(CSwapUInt16 *items, const CSwapUInt16 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP2_32(0) SWAP2_32(1) items += 2 * 2; + SWAP2_32(0) SWAP2_32(1) items += 2 * 2; + } + while (items != lim); +} + + +SWAP_BASE_FUNCS_PREFIXES +SwapBytes4_32(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP4_32(0) SWAP4_32(1) items += 2; + SWAP4_32(0) SWAP4_32(1) items += 2; + } + while (items != lim); +} + +#define DEFAULT_Swap2 SwapBytes2_32 +#define DEFAULT_Swap4 SwapBytes4_32 +#if !defined(FORCE_SWAP_MODE) + #define SWAP2_DEFAULT_MODE 0 +#endif + +#endif // MY_CPU_64BIT +#endif // if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4) + + + +#if !defined(FORCE_SWAP_MODE) +static unsigned g_SwapBytes_Mode; +#endif + +/* size of largest unrolled loop iteration: 128 bytes = 4 * 32 bytes (AVX). */ +#define SWAP_ITERATION_BLOCK_SIZE_MAX (1 << 7) + +// 32 bytes for (AVX) or 2 * 16-bytes for NEON. +#define SWAP_VECTOR_ALIGN_SIZE (1 << 5) + +Z7_NO_INLINE +void z7_SwapBytes2(CSwapUInt16 *items, size_t numItems) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--) + { + SWAP2_16(0) + items++; + } + { + const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt16) - 1; + size_t numItems2 = numItems; + CSwapUInt16 *lim; + numItems &= k_Align_Mask; + numItems2 &= ~(size_t)k_Align_Mask; + lim = items + numItems2; + if (numItems2 != 0) + { + #if !defined(FORCE_SWAP_MODE) + #ifdef MY_CPU_X86_OR_AMD64 + #ifdef USE_SWAP_AVX2 + if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3) + ShufBytes_256((__m256i *)(void *)items, + (const __m256i *)(const void *)lim, + (const __m128i *)(const void *)&(k_ShufMask_Swap2[0])); + else + #endif + #ifdef USE_SWAP_SSSE3 + if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3) + ShufBytes_128((__m128i *)(void *)items, + (const __m128i *)(const void *)lim, + (const __m128i *)(const void *)&(k_ShufMask_Swap2[0])); + else + #endif + #endif // MY_CPU_X86_OR_AMD64 + #if SWAP2_DEFAULT_MODE == 0 + if (g_SwapBytes_Mode != 0) + SwapBytes2_128(items, lim); + else + #endif + #endif // FORCE_SWAP_MODE + DEFAULT_Swap2(items, lim); + } + items = lim; + } + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0; numItems--) + { + SWAP2_16(0) + items++; + } +} + + +Z7_NO_INLINE +void z7_SwapBytes4(CSwapUInt32 *items, size_t numItems) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--) + { + SWAP4_32(0) + items++; + } + { + const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt32) - 1; + size_t numItems2 = numItems; + CSwapUInt32 *lim; + numItems &= k_Align_Mask; + numItems2 &= ~(size_t)k_Align_Mask; + lim = items + numItems2; + if (numItems2 != 0) + { + #if !defined(FORCE_SWAP_MODE) + #ifdef MY_CPU_X86_OR_AMD64 + #ifdef USE_SWAP_AVX2 + if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3) + ShufBytes_256((__m256i *)(void *)items, + (const __m256i *)(const void *)lim, + (const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); + else + #endif + #ifdef USE_SWAP_SSSE3 + if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3) + ShufBytes_128((__m128i *)(void *)items, + (const __m128i *)(const void *)lim, + (const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); + else + #endif + #else // MY_CPU_X86_OR_AMD64 + + if (g_SwapBytes_Mode != 0) + SwapBytes4_128(items, lim); + else + #endif // MY_CPU_X86_OR_AMD64 + #endif // FORCE_SWAP_MODE + DEFAULT_Swap4(items, lim); + } + items = lim; + } + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0; numItems--) + { + SWAP4_32(0) + items++; + } +} + + +// #define SHOW_HW_STATUS + +#ifdef SHOW_HW_STATUS +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +void z7_SwapBytesPrepare(void) +{ +#ifndef FORCE_SWAP_MODE + unsigned mode = 0; // k_SwapBytes_Mode_BASE; + +#ifdef MY_CPU_ARM_OR_ARM64 + { + if (CPU_IsSupported_NEON()) + { + // #pragma message ("=== SwapBytes NEON") + PRF(printf("\n=== SwapBytes NEON\n");) + mode = k_SwapBytes_Mode_NEON; + } + } +#else // MY_CPU_ARM_OR_ARM64 + { + #ifdef USE_SWAP_AVX2 + if (CPU_IsSupported_AVX2()) + { + // #pragma message ("=== SwapBytes AVX2") + PRF(printf("\n=== SwapBytes AVX2\n");) + mode = k_SwapBytes_Mode_AVX2; + } + else + #endif + #ifdef USE_SWAP_SSSE3 + if (CPU_IsSupported_SSSE3()) + { + // #pragma message ("=== SwapBytes SSSE3") + PRF(printf("\n=== SwapBytes SSSE3\n");) + mode = k_SwapBytes_Mode_SSSE3; + } + else + #endif + #if !defined(MY_CPU_AMD64) + if (CPU_IsSupported_SSE2()) + #endif + { + // #pragma message ("=== SwapBytes SSE2") + PRF(printf("\n=== SwapBytes SSE2\n");) + mode = k_SwapBytes_Mode_SSE2; + } + } +#endif // MY_CPU_ARM_OR_ARM64 + g_SwapBytes_Mode = mode; + // g_SwapBytes_Mode = 0; // for debug +#endif // FORCE_SWAP_MODE + PRF(printf("\n=== SwapBytesPrepare\n");) +} + +#undef PRF diff --git a/libraries/lzma/C/SwapBytes.h b/libraries/lzma/C/SwapBytes.h new file mode 100644 index 00000000000..d442467386e --- /dev/null +++ b/libraries/lzma/C/SwapBytes.h @@ -0,0 +1,17 @@ +/* SwapBytes.h -- Byte Swap conversion filter +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_SWAP_BYTES_H +#define ZIP7_INC_SWAP_BYTES_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void z7_SwapBytes2(UInt16 *data, size_t numItems); +void z7_SwapBytes4(UInt32 *data, size_t numItems); +void z7_SwapBytesPrepare(void); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/Threads.c b/libraries/lzma/C/Threads.c index 930ad271b44..cf52bd30307 100644 --- a/libraries/lzma/C/Threads.c +++ b/libraries/lzma/C/Threads.c @@ -1,17 +1,19 @@ /* Threads.c -- multithreading library -2017-06-26 : Igor Pavlov : Public domain */ +2023-03-04 : Igor Pavlov : Public domain */ #include "Precomp.h" -#ifndef UNDER_CE +#ifdef _WIN32 + +#ifndef USE_THREADS_CreateThread #include #endif #include "Threads.h" -static WRes GetError() +static WRes GetError(void) { - DWORD res = GetLastError(); + const DWORD res = GetLastError(); return res ? (WRes)res : 1; } @@ -29,28 +31,103 @@ WRes HandlePtr_Close(HANDLE *p) return 0; } -WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); } +WRes Handle_WaitObject(HANDLE h) +{ + DWORD dw = WaitForSingleObject(h, INFINITE); + /* + (dw) result: + WAIT_OBJECT_0 // 0 + WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space + WAIT_TIMEOUT // 0x00000102 : is compatible with Win32 Error space + WAIT_FAILED // 0xFFFFFFFF + */ + if (dw == WAIT_FAILED) + { + dw = GetLastError(); + if (dw == 0) + return WAIT_FAILED; + } + return (WRes)dw; +} + +#define Thread_Wait(p) Handle_WaitObject(*(p)) + +WRes Thread_Wait_Close(CThread *p) +{ + WRes res = Thread_Wait(p); + WRes res2 = Thread_Close(p); + return (res != 0 ? res : res2); +} WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) { /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ - - #ifdef UNDER_CE - - DWORD threadId; - *p = CreateThread(0, 0, func, param, 0, &threadId); - #else + #ifdef USE_THREADS_CreateThread + DWORD threadId; + *p = CreateThread(NULL, 0, func, param, 0, &threadId); + + #else + unsigned threadId; - *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); - + *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId)); + #endif /* maybe we must use errno here, but probably GetLastError() is also OK. */ return HandleToWRes(*p); } + +WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) +{ + #ifdef USE_THREADS_CreateThread + + UNUSED_VAR(affinity) + return Thread_Create(p, func, param); + + #else + + /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + HANDLE h; + WRes wres; + unsigned threadId; + h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId)); + *p = h; + wres = HandleToWRes(h); + if (h) + { + { + // DWORD_PTR prevMask = + SetThreadAffinityMask(h, (DWORD_PTR)affinity); + /* + if (prevMask == 0) + { + // affinity change is non-critical error, so we can ignore it + // wres = GetError(); + } + */ + } + { + DWORD prevSuspendCount = ResumeThread(h); + /* ResumeThread() returns: + 0 : was_not_suspended + 1 : was_resumed + -1 : error + */ + if (prevSuspendCount == (DWORD)-1) + wres = GetError(); + } + } + + /* maybe we must use errno here, but probably GetLastError() is also OK. */ + return wres; + + #endif +} + + static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) { *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); @@ -68,10 +145,22 @@ WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEven WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) { + // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore() *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); return HandleToWRes(*p); } +WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + // if (Semaphore_IsCreated(p)) + { + WRes wres = Semaphore_Close(p); + if (wres != 0) + return wres; + } + return Semaphore_Create(p, initCount, maxCount); +} + static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) @@ -80,8 +169,13 @@ WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } WRes CriticalSection_Init(CCriticalSection *p) { - /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */ + /* InitializeCriticalSection() can raise exception: + Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception + Windows Vista+ : no exceptions */ #ifdef _MSC_VER + #ifdef __clang__ + #pragma GCC diagnostic ignored "-Wlanguage-extension-token" + #endif __try #endif { @@ -89,7 +183,380 @@ WRes CriticalSection_Init(CCriticalSection *p) /* InitializeCriticalSectionAndSpinCount(p, 0); */ } #ifdef _MSC_VER - __except (EXCEPTION_EXECUTE_HANDLER) { return 1; } + __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; } #endif return 0; } + + + + +#else // _WIN32 + +// ---------- POSIX ---------- + +#ifndef __APPLE__ +#ifndef Z7_AFFINITY_DISABLE +// _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET +// clang < 3.6 : unknown warning group '-Wreserved-id-macro' +// clang 3.6 - 12.01 : gives warning "macro name is a reserved identifier" +// clang >= 13 : do not give warning +#if !defined(_GNU_SOURCE) + #if defined(__clang__) && (__clang_major__ >= 4) && (__clang_major__ <= 12) + #pragma GCC diagnostic ignored "-Wreserved-id-macro" + #endif +#define _GNU_SOURCE +#endif // !defined(_GNU_SOURCE) +#endif // Z7_AFFINITY_DISABLE +#endif // __APPLE__ + +#include "Threads.h" + +#include +#include +#include +#ifdef Z7_AFFINITY_SUPPORTED +// #include +#endif + + +// #include +// #define PRF(p) p +#define PRF(p) +#define Print(s) PRF(printf("\n%s\n", s);) + +WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet) +{ + // new thread in Posix probably inherits affinity from parrent thread + Print("Thread_Create_With_CpuSet") + + pthread_attr_t attr; + int ret; + // int ret2; + + p->_created = 0; + + RINOK(pthread_attr_init(&attr)) + + ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + if (!ret) + { + if (cpuSet) + { + #ifdef Z7_AFFINITY_SUPPORTED + + /* + printf("\n affinity :"); + unsigned i; + for (i = 0; i < sizeof(*cpuSet) && i < 8; i++) + { + Byte b = *((const Byte *)cpuSet + i); + char temp[32]; + #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) + temp[0] = GET_HEX_CHAR((b & 0xF)); + temp[1] = GET_HEX_CHAR((b >> 4)); + // temp[0] = GET_HEX_CHAR((b >> 4)); // big-endian + // temp[1] = GET_HEX_CHAR((b & 0xF)); // big-endian + temp[2] = 0; + printf("%s", temp); + } + printf("\n"); + */ + + // ret2 = + pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet); + // if (ret2) ret = ret2; + #endif + } + + ret = pthread_create(&p->_tid, &attr, func, param); + + if (!ret) + { + p->_created = 1; + /* + if (cpuSet) + { + // ret2 = + pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet); + // if (ret2) ret = ret2; + } + */ + } + } + // ret2 = + pthread_attr_destroy(&attr); + // if (ret2 != 0) ret = ret2; + return ret; +} + + +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) +{ + return Thread_Create_With_CpuSet(p, func, param, NULL); +} + + +WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) +{ + Print("Thread_Create_WithAffinity") + CCpuSet cs; + unsigned i; + CpuSet_Zero(&cs); + for (i = 0; i < sizeof(affinity) * 8; i++) + { + if (affinity == 0) + break; + if (affinity & 1) + { + CpuSet_Set(&cs, i); + } + affinity >>= 1; + } + return Thread_Create_With_CpuSet(p, func, param, &cs); +} + + +WRes Thread_Close(CThread *p) +{ + // Print("Thread_Close") + int ret; + if (!p->_created) + return 0; + + ret = pthread_detach(p->_tid); + p->_tid = 0; + p->_created = 0; + return ret; +} + + +WRes Thread_Wait_Close(CThread *p) +{ + // Print("Thread_Wait_Close") + void *thread_return; + int ret; + if (!p->_created) + return EINVAL; + + ret = pthread_join(p->_tid, &thread_return); + // probably we can't use that (_tid) after pthread_join(), so we close thread here + p->_created = 0; + p->_tid = 0; + return ret; +} + + + +static WRes Event_Create(CEvent *p, int manualReset, int signaled) +{ + RINOK(pthread_mutex_init(&p->_mutex, NULL)) + RINOK(pthread_cond_init(&p->_cond, NULL)) + p->_manual_reset = manualReset; + p->_state = (signaled ? True : False); + p->_created = 1; + return 0; +} + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) + { return Event_Create(p, True, signaled); } +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) + { return ManualResetEvent_Create(p, 0); } +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) + { return Event_Create(p, False, signaled); } +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) + { return AutoResetEvent_Create(p, 0); } + + +WRes Event_Set(CEvent *p) +{ + RINOK(pthread_mutex_lock(&p->_mutex)) + p->_state = True; + int res1 = pthread_cond_broadcast(&p->_cond); + int res2 = pthread_mutex_unlock(&p->_mutex); + return (res2 ? res2 : res1); +} + +WRes Event_Reset(CEvent *p) +{ + RINOK(pthread_mutex_lock(&p->_mutex)) + p->_state = False; + return pthread_mutex_unlock(&p->_mutex); +} + +WRes Event_Wait(CEvent *p) +{ + RINOK(pthread_mutex_lock(&p->_mutex)) + while (p->_state == False) + { + // ETIMEDOUT + // ret = + pthread_cond_wait(&p->_cond, &p->_mutex); + // if (ret != 0) break; + } + if (p->_manual_reset == False) + { + p->_state = False; + } + return pthread_mutex_unlock(&p->_mutex); +} + +WRes Event_Close(CEvent *p) +{ + if (!p->_created) + return 0; + p->_created = 0; + { + int res1 = pthread_mutex_destroy(&p->_mutex); + int res2 = pthread_cond_destroy(&p->_cond); + return (res1 ? res1 : res2); + } +} + + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + if (initCount > maxCount || maxCount < 1) + return EINVAL; + RINOK(pthread_mutex_init(&p->_mutex, NULL)) + RINOK(pthread_cond_init(&p->_cond, NULL)) + p->_count = initCount; + p->_maxCount = maxCount; + p->_created = 1; + return 0; +} + + +WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + if (Semaphore_IsCreated(p)) + { + /* + WRes wres = Semaphore_Close(p); + if (wres != 0) + return wres; + */ + if (initCount > maxCount || maxCount < 1) + return EINVAL; + // return EINVAL; // for debug + p->_count = initCount; + p->_maxCount = maxCount; + return 0; + } + return Semaphore_Create(p, initCount, maxCount); +} + + +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount) +{ + UInt32 newCount; + int ret; + + if (releaseCount < 1) + return EINVAL; + + RINOK(pthread_mutex_lock(&p->_mutex)) + + newCount = p->_count + releaseCount; + if (newCount > p->_maxCount) + ret = ERROR_TOO_MANY_POSTS; // EINVAL; + else + { + p->_count = newCount; + ret = pthread_cond_broadcast(&p->_cond); + } + RINOK(pthread_mutex_unlock(&p->_mutex)) + return ret; +} + +WRes Semaphore_Wait(CSemaphore *p) +{ + RINOK(pthread_mutex_lock(&p->_mutex)) + while (p->_count < 1) + { + pthread_cond_wait(&p->_cond, &p->_mutex); + } + p->_count--; + return pthread_mutex_unlock(&p->_mutex); +} + +WRes Semaphore_Close(CSemaphore *p) +{ + if (!p->_created) + return 0; + p->_created = 0; + { + int res1 = pthread_mutex_destroy(&p->_mutex); + int res2 = pthread_cond_destroy(&p->_cond); + return (res1 ? res1 : res2); + } +} + + + +WRes CriticalSection_Init(CCriticalSection *p) +{ + // Print("CriticalSection_Init") + if (!p) + return EINTR; + return pthread_mutex_init(&p->_mutex, NULL); +} + +void CriticalSection_Enter(CCriticalSection *p) +{ + // Print("CriticalSection_Enter") + if (p) + { + // int ret = + pthread_mutex_lock(&p->_mutex); + } +} + +void CriticalSection_Leave(CCriticalSection *p) +{ + // Print("CriticalSection_Leave") + if (p) + { + // int ret = + pthread_mutex_unlock(&p->_mutex); + } +} + +void CriticalSection_Delete(CCriticalSection *p) +{ + // Print("CriticalSection_Delete") + if (p) + { + // int ret = + pthread_mutex_destroy(&p->_mutex); + } +} + +LONG InterlockedIncrement(LONG volatile *addend) +{ + // Print("InterlockedIncrement") + #ifdef USE_HACK_UNSAFE_ATOMIC + LONG val = *addend + 1; + *addend = val; + return val; + #else + + #if defined(__clang__) && (__clang_major__ >= 8) + #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst" + #endif + return __sync_add_and_fetch(addend, 1); + #endif +} + +#endif // _WIN32 + +WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p) +{ + if (Event_IsCreated(p)) + return Event_Reset(p); + return AutoResetEvent_CreateNotSignaled(p); +} + +#undef PRF +#undef Print diff --git a/libraries/lzma/C/Threads.h b/libraries/lzma/C/Threads.h index e53ace4356c..4028464a337 100644 --- a/libraries/lzma/C/Threads.h +++ b/libraries/lzma/C/Threads.h @@ -1,38 +1,144 @@ /* Threads.h -- multithreading library -2017-06-18 : Igor Pavlov : Public domain */ +2023-04-02 : Igor Pavlov : Public domain */ -#ifndef __7Z_THREADS_H -#define __7Z_THREADS_H +#ifndef ZIP7_INC_THREADS_H +#define ZIP7_INC_THREADS_H #ifdef _WIN32 -#include +#include "7zWindows.h" + +#else + +#if defined(__linux__) +#if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__) +#ifndef Z7_AFFINITY_DISABLE +#define Z7_AFFINITY_SUPPORTED +// #pragma message(" ==== Z7_AFFINITY_SUPPORTED") +// #define _GNU_SOURCE +#endif +#endif +#endif + +#include + #endif #include "7zTypes.h" EXTERN_C_BEGIN +#ifdef _WIN32 + WRes HandlePtr_Close(HANDLE *h); WRes Handle_WaitObject(HANDLE h); typedef HANDLE CThread; -#define Thread_Construct(p) *(p) = NULL + +#define Thread_CONSTRUCT(p) { *(p) = NULL; } #define Thread_WasCreated(p) (*(p) != NULL) #define Thread_Close(p) HandlePtr_Close(p) -#define Thread_Wait(p) Handle_WaitObject(*(p)) +// #define Thread_Wait(p) Handle_WaitObject(*(p)) -typedef #ifdef UNDER_CE - DWORD + // if (USE_THREADS_CreateThread is defined), we use _beginthreadex() + // if (USE_THREADS_CreateThread is not definned), we use CreateThread() + #define USE_THREADS_CreateThread +#endif + +typedef + #ifdef USE_THREADS_CreateThread + DWORD + #else + unsigned + #endif + THREAD_FUNC_RET_TYPE; + +#define THREAD_FUNC_RET_ZERO 0 + +typedef DWORD_PTR CAffinityMask; +typedef DWORD_PTR CCpuSet; + +#define CpuSet_Zero(p) *(p) = (0) +#define CpuSet_Set(p, cpu) *(p) |= ((DWORD_PTR)1 << (cpu)) + +#else // _WIN32 + +typedef struct +{ + pthread_t _tid; + int _created; +} CThread; + +#define Thread_CONSTRUCT(p) { (p)->_tid = 0; (p)->_created = 0; } +#define Thread_WasCreated(p) ((p)->_created != 0) +WRes Thread_Close(CThread *p); +// #define Thread_Wait Thread_Wait_Close + +typedef void * THREAD_FUNC_RET_TYPE; +#define THREAD_FUNC_RET_ZERO NULL + + +typedef UInt64 CAffinityMask; + +#ifdef Z7_AFFINITY_SUPPORTED + +typedef cpu_set_t CCpuSet; +#define CpuSet_Zero(p) CPU_ZERO(p) +#define CpuSet_Set(p, cpu) CPU_SET(cpu, p) +#define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p) + +#else + +typedef UInt64 CCpuSet; +#define CpuSet_Zero(p) *(p) = (0) +#define CpuSet_Set(p, cpu) *(p) |= ((UInt64)1 << (cpu)) +#define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0) + +#endif + + +#endif // _WIN32 + + +#define THREAD_FUNC_CALL_TYPE Z7_STDCALL + +#if defined(_WIN32) && defined(__GNUC__) +/* GCC compiler for x86 32-bit uses the rule: + the stack is 16-byte aligned before CALL instruction for function calling. + But only root function main() contains instructions that + set 16-byte alignment for stack pointer. And another functions + just keep alignment, if it was set in some parent function. + + The problem: + if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(), + the root function of thread doesn't set 16-byte alignment. + And stack frames in all child functions also will be unaligned in that case. + + Here we set (force_align_arg_pointer) attribute for root function of new thread. + Do we need (force_align_arg_pointer) also for another systems? */ + + #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer)) + // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions #else - unsigned + #define THREAD_FUNC_ATTRIB_ALIGN_ARG #endif - THREAD_FUNC_RET_TYPE; -#define THREAD_FUNC_CALL_TYPE MY_STD_CALL -#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE +#define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE + typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); +WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity); +WRes Thread_Wait_Close(CThread *p); + +#ifdef _WIN32 +#define Thread_Create_With_CpuSet(p, func, param, cs) \ + Thread_Create_With_Affinity(p, func, param, *cs) +#else +WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet); +#endif + + +#ifdef _WIN32 typedef HANDLE CEvent; typedef CEvent CAutoResetEvent; @@ -54,6 +160,7 @@ typedef HANDLE CSemaphore; #define Semaphore_Close(p) HandlePtr_Close(p) #define Semaphore_Wait(p) Handle_WaitObject(*(p)) WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); WRes Semaphore_Release1(CSemaphore *p); @@ -63,6 +170,71 @@ WRes CriticalSection_Init(CCriticalSection *p); #define CriticalSection_Enter(p) EnterCriticalSection(p) #define CriticalSection_Leave(p) LeaveCriticalSection(p) + +#else // _WIN32 + +typedef struct _CEvent +{ + int _created; + int _manual_reset; + int _state; + pthread_mutex_t _mutex; + pthread_cond_t _cond; +} CEvent; + +typedef CEvent CAutoResetEvent; +typedef CEvent CManualResetEvent; + +#define Event_Construct(p) (p)->_created = 0 +#define Event_IsCreated(p) ((p)->_created) + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); + +WRes Event_Set(CEvent *p); +WRes Event_Reset(CEvent *p); +WRes Event_Wait(CEvent *p); +WRes Event_Close(CEvent *p); + + +typedef struct _CSemaphore +{ + int _created; + UInt32 _count; + UInt32 _maxCount; + pthread_mutex_t _mutex; + pthread_cond_t _cond; +} CSemaphore; + +#define Semaphore_Construct(p) (p)->_created = 0 +#define Semaphore_IsCreated(p) ((p)->_created) + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); +#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1) +WRes Semaphore_Wait(CSemaphore *p); +WRes Semaphore_Close(CSemaphore *p); + + +typedef struct _CCriticalSection +{ + pthread_mutex_t _mutex; +} CCriticalSection; + +WRes CriticalSection_Init(CCriticalSection *p); +void CriticalSection_Delete(CCriticalSection *cs); +void CriticalSection_Enter(CCriticalSection *cs); +void CriticalSection_Leave(CCriticalSection *cs); + +LONG InterlockedIncrement(LONG volatile *addend); + +#endif // _WIN32 + +WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p); + EXTERN_C_END #endif diff --git a/libraries/lzma/C/Xz.c b/libraries/lzma/C/Xz.c new file mode 100644 index 00000000000..4ad071060a7 --- /dev/null +++ b/libraries/lzma/C/Xz.c @@ -0,0 +1,90 @@ +/* Xz.c - Xz +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" +#include "XzCrc64.h" + +const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; +/* const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; */ + +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) +{ + unsigned i = 0; + do + { + buf[i++] = (Byte)((v & 0x7F) | 0x80); + v >>= 7; + } + while (v != 0); + buf[(size_t)i - 1] &= 0x7F; + return i; +} + +void Xz_Construct(CXzStream *p) +{ + p->numBlocks = 0; + p->blocks = NULL; + p->flags = 0; +} + +void Xz_Free(CXzStream *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->blocks); + p->numBlocks = 0; + p->blocks = NULL; +} + +unsigned XzFlags_GetCheckSize(CXzStreamFlags f) +{ + unsigned t = XzFlags_GetCheckType(f); + return (t == 0) ? 0 : ((unsigned)4 << ((t - 1) / 3)); +} + +void XzCheck_Init(CXzCheck *p, unsigned mode) +{ + p->mode = mode; + switch (mode) + { + case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; + case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; + case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; + } +} + +void XzCheck_Update(CXzCheck *p, const void *data, size_t size) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; + case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; + case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; + } +} + +int XzCheck_Final(CXzCheck *p, Byte *digest) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: + SetUi32(digest, CRC_GET_DIGEST(p->crc)) + break; + case XZ_CHECK_CRC64: + { + int i; + UInt64 v = CRC64_GET_DIGEST(p->crc64); + for (i = 0; i < 8; i++, v >>= 8) + digest[i] = (Byte)(v & 0xFF); + break; + } + case XZ_CHECK_SHA256: + Sha256_Final(&p->sha, digest); + break; + default: + return 0; + } + return 1; +} diff --git a/libraries/lzma/C/Xz.h b/libraries/lzma/C/Xz.h new file mode 100644 index 00000000000..d5001f6cace --- /dev/null +++ b/libraries/lzma/C/Xz.h @@ -0,0 +1,535 @@ +/* Xz.h - Xz interface +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_XZ_H +#define ZIP7_INC_XZ_H + +#include "Sha256.h" +#include "Delta.h" + +EXTERN_C_BEGIN + +#define XZ_ID_Subblock 1 +#define XZ_ID_Delta 3 +#define XZ_ID_X86 4 +#define XZ_ID_PPC 5 +#define XZ_ID_IA64 6 +#define XZ_ID_ARM 7 +#define XZ_ID_ARMT 8 +#define XZ_ID_SPARC 9 +#define XZ_ID_ARM64 0xa +#define XZ_ID_LZMA2 0x21 + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); + +/* ---------- xz block ---------- */ + +#define XZ_BLOCK_HEADER_SIZE_MAX 1024 + +#define XZ_NUM_FILTERS_MAX 4 +#define XZ_BF_NUM_FILTERS_MASK 3 +#define XZ_BF_PACK_SIZE (1 << 6) +#define XZ_BF_UNPACK_SIZE (1 << 7) + +#define XZ_FILTER_PROPS_SIZE_MAX 20 + +typedef struct +{ + UInt64 id; + UInt32 propsSize; + Byte props[XZ_FILTER_PROPS_SIZE_MAX]; +} CXzFilter; + +typedef struct +{ + UInt64 packSize; + UInt64 unpackSize; + Byte flags; + CXzFilter filters[XZ_NUM_FILTERS_MAX]; +} CXzBlock; + +#define XzBlock_GetNumFilters(p) (((unsigned)(p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) +#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) +#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) +#define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0) + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header); +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes); + +/* ---------- xz stream ---------- */ + +#define XZ_SIG_SIZE 6 +#define XZ_FOOTER_SIG_SIZE 2 + +extern const Byte XZ_SIG[XZ_SIG_SIZE]; + +/* +extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; +*/ + +#define XZ_FOOTER_SIG_0 'Y' +#define XZ_FOOTER_SIG_1 'Z' + +#define XZ_STREAM_FLAGS_SIZE 2 +#define XZ_STREAM_CRC_SIZE 4 + +#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) +#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) + +#define XZ_CHECK_MASK 0xF +#define XZ_CHECK_NO 0 +#define XZ_CHECK_CRC32 1 +#define XZ_CHECK_CRC64 4 +#define XZ_CHECK_SHA256 10 + +typedef struct +{ + unsigned mode; + UInt32 crc; + UInt64 crc64; + CSha256 sha; +} CXzCheck; + +void XzCheck_Init(CXzCheck *p, unsigned mode); +void XzCheck_Update(CXzCheck *p, const void *data, size_t size); +int XzCheck_Final(CXzCheck *p, Byte *digest); + +typedef UInt16 CXzStreamFlags; + +#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) +#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) +#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) +unsigned XzFlags_GetCheckSize(CXzStreamFlags f); + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream); + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; +} CXzBlockSizes; + +typedef struct +{ + CXzStreamFlags flags; + // Byte _pad[6]; + size_t numBlocks; + CXzBlockSizes *blocks; + UInt64 startOffset; +} CXzStream; + +void Xz_Construct(CXzStream *p); +void Xz_Free(CXzStream *p, ISzAllocPtr alloc); + +#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) + +UInt64 Xz_GetUnpackSize(const CXzStream *p); +UInt64 Xz_GetPackSize(const CXzStream *p); + +typedef struct +{ + size_t num; + size_t numAllocated; + CXzStream *streams; +} CXzs; + +void Xzs_Construct(CXzs *p); +void Xzs_Free(CXzs *p, ISzAllocPtr alloc); +SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr inStream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc); + +UInt64 Xzs_GetNumBlocks(const CXzs *p); +UInt64 Xzs_GetUnpackSize(const CXzs *p); + + +// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder + +typedef enum +{ + CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ + CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + CODER_STATUS_NOT_FINISHED, /* stream was not finished */ + CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ +} ECoderStatus; + + +// ECoderFinishMode values are identical to ELzmaFinishMode + +typedef enum +{ + CODER_FINISH_ANY, /* finish at any point */ + CODER_FINISH_END /* block must be finished at the end */ +} ECoderFinishMode; + + +typedef struct +{ + void *p; // state object; + void (*Free)(void *p, ISzAllocPtr alloc); + SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc); + void (*Init)(void *p); + SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished, + ECoderStatus *status); + SizeT (*Filter)(void *p, Byte *data, SizeT size); +} IStateCoder; + + +typedef struct +{ + UInt32 methodId; + UInt32 delta; + UInt32 ip; + UInt32 X86_State; + Byte delta_State[DELTA_STATE_SIZE]; +} CXzBcFilterStateBase; + +typedef SizeT (*Xz_Func_BcFilterStateBase_Filter)(CXzBcFilterStateBase *p, Byte *data, SizeT size); + +SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id, + Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc); + + +#define MIXCODER_NUM_FILTERS_MAX 4 + +typedef struct +{ + ISzAllocPtr alloc; + Byte *buf; + unsigned numCoders; + + Byte *outBuf; + size_t outBufSize; + size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode) + BoolInt wasFinished; + SRes res; + ECoderStatus status; + // BoolInt SingleBufMode; + + int finished[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; + UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; + SRes results[MIXCODER_NUM_FILTERS_MAX]; + IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; +} CMixCoder; + + +typedef enum +{ + XZ_STATE_STREAM_HEADER, + XZ_STATE_STREAM_INDEX, + XZ_STATE_STREAM_INDEX_CRC, + XZ_STATE_STREAM_FOOTER, + XZ_STATE_STREAM_PADDING, + XZ_STATE_BLOCK_HEADER, + XZ_STATE_BLOCK, + XZ_STATE_BLOCK_FOOTER +} EXzState; + + +typedef struct +{ + EXzState state; + UInt32 pos; + unsigned alignPos; + unsigned indexPreSize; + + CXzStreamFlags streamFlags; + + UInt32 blockHeaderSize; + UInt64 packSize; + UInt64 unpackSize; + + UInt64 numBlocks; // number of finished blocks in current stream + UInt64 indexSize; + UInt64 indexPos; + UInt64 padSize; + + UInt64 numStartedStreams; + UInt64 numFinishedStreams; + UInt64 numTotalBlocks; + + UInt32 crc; + CMixCoder decoder; + CXzBlock block; + CXzCheck check; + CSha256 sha; + + BoolInt parseMode; + BoolInt headerParsedOk; + BoolInt decodeToStreamSignature; + unsigned decodeOnlyOneBlock; + + Byte *outBuf; + size_t outBufSize; + size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked + + Byte shaDigest[SHA256_DIGEST_SIZE]; + Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; +} CXzUnpacker; + +/* alloc : aligned for cache line allocation is better */ +void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc); +void XzUnpacker_Init(CXzUnpacker *p); +void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize); +void XzUnpacker_Free(CXzUnpacker *p); + +/* + XzUnpacker + The sequence for decoding functions: + { + XzUnpacker_Construct() + [Decoding_Calls] + XzUnpacker_Free() + } + + [Decoding_Calls] + + There are 3 types of interfaces for [Decoding_Calls] calls: + + Interface-1 : Partial output buffers: + { + XzUnpacker_Init() + for() + { + XzUnpacker_Code(); + } + XzUnpacker_IsStreamWasFinished() + } + + Interface-2 : Direct output buffer: + Use it, if you know exact size of decoded data, and you need + whole xz unpacked data in one output buffer. + xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode. + { + XzUnpacker_Init() + XzUnpacker_SetOutBufMode(); // to set output buffer and size + for() + { + XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code() + } + XzUnpacker_IsStreamWasFinished() + } + + Interface-3 : Direct output buffer : One call full decoding + It unpacks whole input buffer to output buffer in one call. + It uses Interface-2 internally. + { + XzUnpacker_CodeFull() + XzUnpacker_IsStreamWasFinished() + } +*/ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + CODER_FINISH_ANY - use smallest number of input bytes + CODER_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + CODER_STATUS_NOT_FINISHED, + CODER_STATUS_NEEDS_MORE_INPUT - the decoder can return it in two cases: + 1) it needs more input data to finish current xz stream + 2) xz stream was finished successfully. But the decoder supports multiple + concatented xz streams. So it expects more input data for new xz streams. + Call XzUnpacker_IsStreamWasFinished() to check that latest xz stream was finished successfully. + + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_DATA - Data error + SZ_ERROR_UNSUPPORTED - Unsupported method or method properties + SZ_ERROR_CRC - CRC error + // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + + SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: + - xz Stream Signature failure + - CRC32 of xz Stream Header is failed + - The size of Stream padding is not multiple of four bytes. + It's possible to get that error, if xz stream was finished and the stream + contains some another data. In that case you can call XzUnpacker_GetExtraSize() + function to get real size of xz stream. +*/ + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcFinished, + ECoderFinishMode finishMode, ECoderStatus *status); + +SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, + ECoderFinishMode finishMode, ECoderStatus *status); + +/* +If you decode full xz stream(s), then you can call XzUnpacker_IsStreamWasFinished() +after successful XzUnpacker_CodeFull() or after last call of XzUnpacker_Code(). +*/ + +BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p); + +/* +XzUnpacker_GetExtraSize() returns then number of unconfirmed bytes, + if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state. +These bytes can be some data after xz archive, or +it can be start of new xz stream. + +Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of +xz stream in two cases, if XzUnpacker_Code() returns: + res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT + res == SZ_ERROR_NO_ARCHIVE +*/ + +UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p); + + +/* + for random block decoding: + XzUnpacker_Init(); + set CXzUnpacker::streamFlags + XzUnpacker_PrepareToRandomBlockDecoding() + loop + { + XzUnpacker_Code() + XzUnpacker_IsBlockFinished() + } +*/ + +void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p); +BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p); + +#define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags)) + + + + + + +/* ---- Single-Thread and Multi-Thread xz Decoding with Input/Output Streams ---- */ + +/* + if (CXzDecMtProps::numThreads > 1), the decoder can try to use + Multi-Threading. The decoder analyses xz block header, and if + there are pack size and unpack size values stored in xz block header, + the decoder reads compressed data of block to internal buffers, + and then it can start parallel decoding, if there are another blocks. + The decoder can switch back to Single-Thread decoding after some conditions. + + The sequence of calls for xz decoding with in/out Streams: + { + XzDecMt_Create() + XzDecMtProps_Init(XzDecMtProps) to set default values of properties + // then you can change some XzDecMtProps parameters with required values + // here you can set the number of threads and (memUseMax) - the maximum + Memory usage for multithreading decoding. + for() + { + XzDecMt_Decode() // one call per one file + } + XzDecMt_Destroy() + } +*/ + + +typedef struct +{ + size_t inBufSize_ST; // size of input buffer for Single-Thread decoding + size_t outStep_ST; // size of output buffer for Single-Thread decoding + BoolInt ignoreErrors; // if set to 1, the decoder can ignore some errors and it skips broken parts of data. + + #ifndef Z7_ST + unsigned numThreads; // the number of threads for Multi-Thread decoding. if (umThreads == 1) it will use Single-thread decoding + size_t inBufSize_MT; // size of small input data buffers for Multi-Thread decoding. Big number of such small buffers can be created + size_t memUseMax; // the limit of total memory usage for Multi-Thread decoding. + // it's recommended to set (memUseMax) manually to value that is smaller of total size of RAM in computer. + #endif +} CXzDecMtProps; + +void XzDecMtProps_Init(CXzDecMtProps *p); + +typedef struct CXzDecMt CXzDecMt; +typedef CXzDecMt * CXzDecMtHandle; +// Z7_DECLARE_HANDLE(CXzDecMtHandle) + +/* + alloc : XzDecMt uses CAlignOffsetAlloc internally for addresses allocated by (alloc). + allocMid : for big allocations, aligned allocation is better +*/ + +CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); +void XzDecMt_Destroy(CXzDecMtHandle p); + + +typedef struct +{ + Byte UnpackSize_Defined; + Byte NumStreams_Defined; + Byte NumBlocks_Defined; + + Byte DataAfterEnd; // there are some additional data after good xz streams, and that data is not new xz stream. + Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data + + UInt64 InSize; // pack size processed. That value doesn't include the data after + // end of xz stream, if that data was not correct + UInt64 OutSize; + + UInt64 NumStreams; + UInt64 NumBlocks; + + SRes DecodeRes; // the error code of xz streams data decoding + SRes ReadRes; // error code from ISeqInStream:Read() + SRes ProgressRes; // error code from ICompressProgress:Progress() + + SRes CombinedRes; // Combined result error code that shows main rusult + // = S_OK, if there is no error. + // but check also (DataAfterEnd) that can show additional minor errors. + + SRes CombinedRes_Type; // = SZ_ERROR_READ, if error from ISeqInStream + // = SZ_ERROR_PROGRESS, if error from ICompressProgress + // = SZ_ERROR_WRITE, if error from ISeqOutStream + // = SZ_ERROR_* codes for decoding +} CXzStatInfo; + +void XzStatInfo_Clear(CXzStatInfo *p); + +/* + +XzDecMt_Decode() +SRes: it's combined decoding result. It also is equal to stat->CombinedRes. + + SZ_OK - no error + check also output value in (stat->DataAfterEnd) + that can show additional possible error + + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_NO_ARCHIVE - is not xz archive + SZ_ERROR_ARCHIVE - Headers error + SZ_ERROR_DATA - Data Error + SZ_ERROR_UNSUPPORTED - Unsupported method or method properties + SZ_ERROR_CRC - CRC Error + SZ_ERROR_INPUT_EOF - it needs more input data + SZ_ERROR_WRITE - ISeqOutStream error + (SZ_ERROR_READ) - ISeqInStream errors + (SZ_ERROR_PROGRESS) - ICompressProgress errors + // SZ_ERROR_THREAD - error in multi-threading functions + MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function +*/ + +SRes XzDecMt_Decode(CXzDecMtHandle p, + const CXzDecMtProps *props, + const UInt64 *outDataSize, // NULL means undefined + int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished + ISeqOutStreamPtr outStream, + // Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + // const Byte *inData, size_t inDataSize, + CXzStatInfo *stat, // out: decoding results and statistics + int *isMT, // out: 0 means that ST (Single-Thread) version was used + // 1 means that MT (Multi-Thread) version was used + ICompressProgressPtr progress); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/XzCrc64.c b/libraries/lzma/C/XzCrc64.c new file mode 100644 index 00000000000..c2fad6cdaaa --- /dev/null +++ b/libraries/lzma/C/XzCrc64.c @@ -0,0 +1,80 @@ +/* XzCrc64.c -- CRC64 calculation +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "XzCrc64.h" +#include "CpuArch.h" + +#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42) + +#ifdef MY_CPU_LE + #define CRC64_NUM_TABLES 4 +#else + #define CRC64_NUM_TABLES 5 + + UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif + +#ifndef MY_CPU_BE + UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif + +typedef UInt64 (Z7_FASTCALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table); + +static CRC64_FUNC g_Crc64Update; +UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES]; + +UInt64 Z7_FASTCALL Crc64Update(UInt64 v, const void *data, size_t size) +{ + return g_Crc64Update(v, data, size, g_Crc64Table); +} + +UInt64 Z7_FASTCALL Crc64Calc(const void *data, size_t size) +{ + return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL; +} + +void Z7_FASTCALL Crc64GenerateTable(void) +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt64 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrc64Poly & ((UInt64)0 - (r & 1))); + g_Crc64Table[i] = r; + } + for (i = 256; i < 256 * CRC64_NUM_TABLES; i++) + { + const UInt64 r = g_Crc64Table[(size_t)i - 256]; + g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8); + } + + #ifdef MY_CPU_LE + + g_Crc64Update = XzCrc64UpdateT4; + + #else + { + #ifndef MY_CPU_BE + UInt32 k = 1; + if (*(const Byte *)&k == 1) + g_Crc64Update = XzCrc64UpdateT4; + else + #endif + { + for (i = 256 * CRC64_NUM_TABLES - 1; i >= 256; i--) + { + const UInt64 x = g_Crc64Table[(size_t)i - 256]; + g_Crc64Table[i] = Z7_BSWAP64(x); + } + g_Crc64Update = XzCrc64UpdateT1_BeT4; + } + } + #endif +} + +#undef kCrc64Poly +#undef CRC64_NUM_TABLES diff --git a/libraries/lzma/C/XzCrc64.h b/libraries/lzma/C/XzCrc64.h new file mode 100644 index 00000000000..ca46869a644 --- /dev/null +++ b/libraries/lzma/C/XzCrc64.h @@ -0,0 +1,26 @@ +/* XzCrc64.h -- CRC64 calculation +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_XZ_CRC64_H +#define ZIP7_INC_XZ_CRC64_H + +#include + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +extern UInt64 g_Crc64Table[]; + +void Z7_FASTCALL Crc64GenerateTable(void); + +#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF) +#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL) +#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt64 Z7_FASTCALL Crc64Update(UInt64 crc, const void *data, size_t size); +UInt64 Z7_FASTCALL Crc64Calc(const void *data, size_t size); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/XzCrc64Opt.c b/libraries/lzma/C/XzCrc64Opt.c new file mode 100644 index 00000000000..d03374c0063 --- /dev/null +++ b/libraries/lzma/C/XzCrc64Opt.c @@ -0,0 +1,61 @@ +/* XzCrc64Opt.c -- CRC64 calculation +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifndef MY_CPU_BE + +#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table); +UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + const UInt32 d = (UInt32)v ^ *(const UInt32 *)(const void *)p; + v = (v >> 32) + ^ (table + 0x300)[((d ) & 0xFF)] + ^ (table + 0x200)[((d >> 8) & 0xFF)] + ^ (table + 0x100)[((d >> 16) & 0xFF)] + ^ (table + 0x000)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + return v; +} + +#endif + + +#ifndef MY_CPU_LE + +#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8)) + +UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); +UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = Z7_BSWAP64(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC64_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + const UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)(const void *)p; + v = (v << 32) + ^ (table + 0x000)[((d ) & 0xFF)] + ^ (table + 0x100)[((d >> 8) & 0xFF)] + ^ (table + 0x200)[((d >> 16) & 0xFF)] + ^ (table + 0x300)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC64_UPDATE_BYTE_2_BE(v, *p); + return Z7_BSWAP64(v); +} + +#endif diff --git a/libraries/lzma/C/XzDec.c b/libraries/lzma/C/XzDec.c new file mode 100644 index 00000000000..a5f703966d6 --- /dev/null +++ b/libraries/lzma/C/XzDec.c @@ -0,0 +1,2875 @@ +/* XzDec.c -- Xz Decode +2023-04-13 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #include + +// #define XZ_DUMP + +/* #define XZ_DUMP */ + +#ifdef XZ_DUMP +#include +#endif + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR(s) PRF(printf("\n" s "\n")) +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) + +#include +#include + +#include "7zCrc.h" +#include "Alloc.h" +#include "Bra.h" +#include "CpuArch.h" +#include "Delta.h" +#include "Lzma2Dec.h" + +// #define USE_SUBBLOCK + +#ifdef USE_SUBBLOCK +#include "Bcj3Dec.c" +#include "SbDec.h" +#endif + +#include "Xz.h" + +#define XZ_CHECK_SIZE_MAX 64 + +#define CODER_BUF_SIZE ((size_t)1 << 17) + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) +{ + unsigned i, limit; + *value = 0; + limit = (maxSize > 9) ? 9 : (unsigned)maxSize; + + for (i = 0; i < limit;) + { + Byte b = p[i]; + *value |= (UInt64)(b & 0x7F) << (7 * i++); + if ((b & 0x80) == 0) + return (b == 0 && i != 1) ? 0 : i; + } + return 0; +} + + +/* ---------- XzBcFilterState ---------- */ + +#define BRA_BUF_SIZE (1 << 14) + +typedef struct +{ + size_t bufPos; + size_t bufConv; + size_t bufTotal; + Byte *buf; // must be aligned for 4 bytes + Xz_Func_BcFilterStateBase_Filter filter_func; + // int encodeMode; + CXzBcFilterStateBase base; + // Byte buf[BRA_BUF_SIZE]; +} CXzBcFilterState; + + +static void XzBcFilterState_Free(void *pp, ISzAllocPtr alloc) +{ + if (pp) + { + CXzBcFilterState *p = ((CXzBcFilterState *)pp); + ISzAlloc_Free(alloc, p->buf); + ISzAlloc_Free(alloc, pp); + } +} + + +static SRes XzBcFilterState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + CXzBcFilterStateBase *p = &((CXzBcFilterState *)pp)->base; + UNUSED_VAR(alloc) + p->ip = 0; + if (p->methodId == XZ_ID_Delta) + { + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + p->delta = (unsigned)props[0] + 1; + } + else + { + if (propSize == 4) + { + UInt32 v = GetUi32(props); + switch (p->methodId) + { + case XZ_ID_PPC: + case XZ_ID_ARM: + case XZ_ID_SPARC: + case XZ_ID_ARM64: + if ((v & 3) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_ARMT: + if ((v & 1) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_IA64: + if ((v & 0xF) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + } + p->ip = v; + } + else if (propSize != 0) + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; +} + + +static void XzBcFilterState_Init(void *pp) +{ + CXzBcFilterState *p = ((CXzBcFilterState *)pp); + p->bufPos = p->bufConv = p->bufTotal = 0; + p->base.X86_State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; + if (p->base.methodId == XZ_ID_Delta) + Delta_Init(p->base.delta_State); +} + + +static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Dec[] = +{ + Z7_BRANCH_CONV_DEC(PPC), + Z7_BRANCH_CONV_DEC(IA64), + Z7_BRANCH_CONV_DEC(ARM), + Z7_BRANCH_CONV_DEC(ARMT), + Z7_BRANCH_CONV_DEC(SPARC), + Z7_BRANCH_CONV_DEC(ARM64) +}; + +static SizeT XzBcFilterStateBase_Filter_Dec(CXzBcFilterStateBase *p, Byte *data, SizeT size) +{ + switch (p->methodId) + { + case XZ_ID_Delta: + Delta_Decode(p->delta_State, p->delta, data, size); + break; + case XZ_ID_X86: + size = (SizeT)(z7_BranchConvSt_X86_Dec(data, size, p->ip, &p->X86_State) - data); + break; + default: + if (p->methodId >= XZ_ID_PPC) + { + const UInt32 i = p->methodId - XZ_ID_PPC; + if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Dec)) + size = (SizeT)(g_Funcs_BranchConv_RISC_Dec[i](data, size, p->ip) - data); + } + break; + } + p->ip += (UInt32)size; + return size; +} + + +static SizeT XzBcFilterState_Filter(void *pp, Byte *data, SizeT size) +{ + CXzBcFilterState *p = ((CXzBcFilterState *)pp); + return p->filter_func(&p->base, data, size); +} + + +static SRes XzBcFilterState_Code2(void *pp, + Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode, + // int *wasFinished + ECoderStatus *status) +{ + CXzBcFilterState *p = ((CXzBcFilterState *)pp); + SizeT destRem = *destLen; + SizeT srcRem = *srcLen; + UNUSED_VAR(finishMode) + + *destLen = 0; + *srcLen = 0; + // *wasFinished = False; + *status = CODER_STATUS_NOT_FINISHED; + + while (destRem != 0) + { + { + size_t size = p->bufConv - p->bufPos; + if (size) + { + if (size > destRem) + size = destRem; + memcpy(dest, p->buf + p->bufPos, size); + p->bufPos += size; + *destLen += size; + dest += size; + destRem -= size; + continue; + } + } + + p->bufTotal -= p->bufPos; + memmove(p->buf, p->buf + p->bufPos, p->bufTotal); + p->bufPos = 0; + p->bufConv = 0; + { + size_t size = BRA_BUF_SIZE - p->bufTotal; + if (size > srcRem) + size = srcRem; + memcpy(p->buf + p->bufTotal, src, size); + *srcLen += size; + src += size; + srcRem -= size; + p->bufTotal += size; + } + if (p->bufTotal == 0) + break; + + p->bufConv = p->filter_func(&p->base, p->buf, p->bufTotal); + + if (p->bufConv == 0) + { + if (!srcWasFinished) + break; + p->bufConv = p->bufTotal; + } + } + + if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished) + { + *status = CODER_STATUS_FINISHED_WITH_MARK; + // *wasFinished = 1; + } + + return SZ_OK; +} + + +#define XZ_IS_SUPPORTED_FILTER_ID(id) \ + ((id) >= XZ_ID_Delta && (id) <= XZ_ID_ARM64) + +SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id, + Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc) +{ + CXzBcFilterState *decoder; + if (!XZ_IS_SUPPORTED_FILTER_ID(id)) + return SZ_ERROR_UNSUPPORTED; + decoder = (CXzBcFilterState *)p->p; + if (!decoder) + { + decoder = (CXzBcFilterState *)ISzAlloc_Alloc(alloc, sizeof(CXzBcFilterState)); + if (!decoder) + return SZ_ERROR_MEM; + decoder->buf = ISzAlloc_Alloc(alloc, BRA_BUF_SIZE); + if (!decoder->buf) + { + ISzAlloc_Free(alloc, decoder); + return SZ_ERROR_MEM; + } + p->p = decoder; + p->Free = XzBcFilterState_Free; + p->SetProps = XzBcFilterState_SetProps; + p->Init = XzBcFilterState_Init; + p->Code2 = XzBcFilterState_Code2; + p->Filter = XzBcFilterState_Filter; + decoder->filter_func = func; + } + decoder->base.methodId = (UInt32)id; + // decoder->encodeMode = encodeMode; + return SZ_OK; +} + + + +/* ---------- SbState ---------- */ + +#ifdef USE_SUBBLOCK + +static void SbState_Free(void *pp, ISzAllocPtr alloc) +{ + CSbDec *p = (CSbDec *)pp; + SbDec_Free(p); + ISzAlloc_Free(alloc, pp); +} + +static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + UNUSED_VAR(pp) + UNUSED_VAR(props) + UNUSED_VAR(alloc) + return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static void SbState_Init(void *pp) +{ + SbDec_Init((CSbDec *)pp); +} + +static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished + ECoderStatus *status) +{ + CSbDec *p = (CSbDec *)pp; + SRes res; + UNUSED_VAR(srcWasFinished) + p->dest = dest; + p->destLen = *destLen; + p->src = src; + p->srcLen = *srcLen; + p->finish = finishMode; /* change it */ + res = SbDec_Decode((CSbDec *)pp); + *destLen -= p->destLen; + *srcLen -= p->srcLen; + // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */ + *status = (*destLen == 0 && *srcLen == 0) ? + CODER_STATUS_FINISHED_WITH_MARK : + CODER_STATUS_NOT_FINISHED; + return res; +} + +static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc) +{ + CSbDec *decoder = (CSbDec *)p->p; + if (!decoder) + { + decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec)); + if (!decoder) + return SZ_ERROR_MEM; + p->p = decoder; + p->Free = SbState_Free; + p->SetProps = SbState_SetProps; + p->Init = SbState_Init; + p->Code2 = SbState_Code2; + p->Filter = NULL; + } + SbDec_Construct(decoder); + SbDec_SetAlloc(decoder, alloc); + return SZ_OK; +} + +#endif + + + +/* ---------- Lzma2 ---------- */ + +typedef struct +{ + CLzma2Dec decoder; + BoolInt outBufMode; +} CLzma2Dec_Spec; + + +static void Lzma2State_Free(void *pp, ISzAllocPtr alloc) +{ + CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; + if (p->outBufMode) + Lzma2Dec_FreeProbs(&p->decoder, alloc); + else + Lzma2Dec_Free(&p->decoder, alloc); + ISzAlloc_Free(alloc, pp); +} + +static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; + if (p->outBufMode) + return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc); + else + return Lzma2Dec_Allocate(&p->decoder, props[0], alloc); + } +} + +static void Lzma2State_Init(void *pp) +{ + Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder); +} + + +/* + if (outBufMode), then (dest) is not used. Use NULL. + Data is unpacked to (spec->decoder.decoder.dic) output buffer. +*/ + +static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished, + ECoderStatus *status) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp; + ELzmaStatus status2; + /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ + SRes res; + UNUSED_VAR(srcWasFinished) + if (spec->outBufMode) + { + SizeT dicPos = spec->decoder.decoder.dicPos; + SizeT dicLimit = dicPos + *destLen; + res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2); + *destLen = spec->decoder.decoder.dicPos - dicPos; + } + else + res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2); + // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK); + // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder + *status = (ECoderStatus)status2; + return res; +} + + +static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; + if (!spec) + { + spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec)); + if (!spec) + return SZ_ERROR_MEM; + p->p = spec; + p->Free = Lzma2State_Free; + p->SetProps = Lzma2State_SetProps; + p->Init = Lzma2State_Init; + p->Code2 = Lzma2State_Code2; + p->Filter = NULL; + Lzma2Dec_CONSTRUCT(&spec->decoder) + } + spec->outBufMode = False; + if (outBuf) + { + spec->outBufMode = True; + spec->decoder.decoder.dic = outBuf; + spec->decoder.decoder.dicBufSize = outBufSize; + } + return SZ_OK; +} + + +static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; + if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf)) + return SZ_ERROR_FAIL; + if (outBuf) + { + spec->decoder.decoder.dic = outBuf; + spec->decoder.decoder.dicBufSize = outBufSize; + } + return SZ_OK; +} + + + +static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc) +{ + unsigned i; + p->alloc = alloc; + p->buf = NULL; + p->numCoders = 0; + + p->outBufSize = 0; + p->outBuf = NULL; + // p->SingleBufMode = False; + + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + p->coders[i].p = NULL; +} + + +static void MixCoder_Free(CMixCoder *p) +{ + unsigned i; + p->numCoders = 0; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + { + IStateCoder *sc = &p->coders[i]; + if (sc->p) + { + sc->Free(sc->p, p->alloc); + sc->p = NULL; + } + } + if (p->buf) + { + ISzAlloc_Free(p->alloc, p->buf); + p->buf = NULL; /* 9.31: the BUG was fixed */ + } +} + +static void MixCoder_Init(CMixCoder *p) +{ + unsigned i; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++) + { + p->size[i] = 0; + p->pos[i] = 0; + p->finished[i] = 0; + } + for (i = 0; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + coder->Init(coder->p); + p->results[i] = SZ_OK; + } + p->outWritten = 0; + p->wasFinished = False; + p->res = SZ_OK; + p->status = CODER_STATUS_NOT_SPECIFIED; +} + + +static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) +{ + IStateCoder *sc = &p->coders[coderIndex]; + p->ids[coderIndex] = methodId; + switch (methodId) + { + case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc); + #ifdef USE_SUBBLOCK + case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc); + #endif + } + if (coderIndex == 0) + return SZ_ERROR_UNSUPPORTED; + return Xz_StateCoder_Bc_SetFromMethod_Func(sc, methodId, + XzBcFilterStateBase_Filter_Dec, p->alloc); +} + + +static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) +{ + IStateCoder *sc = &p->coders[coderIndex]; + switch (methodId) + { + case XZ_ID_LZMA2: return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize); + } + return SZ_ERROR_UNSUPPORTED; +} + + + +/* + if (destFinish) - then unpack data block is finished at (*destLen) position, + and we can return data that were not processed by filter + +output (status) can be : + CODER_STATUS_NOT_FINISHED + CODER_STATUS_FINISHED_WITH_MARK + CODER_STATUS_NEEDS_MORE_INPUT - not implemented still +*/ + +static SRes MixCoder_Code(CMixCoder *p, + Byte *dest, SizeT *destLen, int destFinish, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + + *destLen = 0; + *srcLen = 0; + + if (p->wasFinished) + return p->res; + + p->status = CODER_STATUS_NOT_FINISHED; + + // if (p->SingleBufMode) + if (p->outBuf) + { + SRes res; + SizeT destLen2, srcLen2; + int wasFinished; + + PRF_STR("------- MixCoder Single ----------") + + srcLen2 = srcLenOrig; + destLen2 = destLenOrig; + + { + IStateCoder *coder = &p->coders[0]; + res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode, + // &wasFinished, + &p->status); + wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK); + } + + p->res = res; + + /* + if (wasFinished) + p->status = CODER_STATUS_FINISHED_WITH_MARK; + else + { + if (res == SZ_OK) + if (destLen2 != destLenOrig) + p->status = CODER_STATUS_NEEDS_MORE_INPUT; + } + */ + + + *srcLen = srcLen2; + src += srcLen2; + p->outWritten += destLen2; + + if (res != SZ_OK || srcWasFinished || wasFinished) + p->wasFinished = True; + + if (p->numCoders == 1) + *destLen = destLen2; + else if (p->wasFinished) + { + unsigned i; + size_t processed = p->outWritten; + + for (i = 1; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + processed = coder->Filter(coder->p, p->outBuf, processed); + if (wasFinished || (destFinish && p->outWritten == destLenOrig)) + processed = p->outWritten; + PRF_STR_INT("filter", i) + } + *destLen = processed; + } + return res; + } + + PRF_STR("standard mix") + + if (p->numCoders != 1) + { + if (!p->buf) + { + p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); + if (!p->buf) + return SZ_ERROR_MEM; + } + + finishMode = CODER_FINISH_ANY; + } + + for (;;) + { + BoolInt processed = False; + BoolInt allFinished = True; + SRes resMain = SZ_OK; + unsigned i; + + p->status = CODER_STATUS_NOT_FINISHED; + /* + if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) + break; + */ + + for (i = 0; i < p->numCoders; i++) + { + SRes res; + IStateCoder *coder = &p->coders[i]; + Byte *dest2; + SizeT destLen2, srcLen2; // destLen2_Orig; + const Byte *src2; + int srcFinished2; + int encodingWasFinished; + ECoderStatus status2; + + if (i == 0) + { + src2 = src; + srcLen2 = srcLenOrig - *srcLen; + srcFinished2 = srcWasFinished; + } + else + { + size_t k = i - 1; + src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k]; + srcLen2 = p->size[k] - p->pos[k]; + srcFinished2 = p->finished[k]; + } + + if (i == p->numCoders - 1) + { + dest2 = dest; + destLen2 = destLenOrig - *destLen; + } + else + { + if (p->pos[i] != p->size[i]) + continue; + dest2 = p->buf + (CODER_BUF_SIZE * i); + destLen2 = CODER_BUF_SIZE; + } + + // destLen2_Orig = destLen2; + + if (p->results[i] != SZ_OK) + { + if (resMain == SZ_OK) + resMain = p->results[i]; + continue; + } + + res = coder->Code2(coder->p, + dest2, &destLen2, + src2, &srcLen2, srcFinished2, + finishMode, + // &encodingWasFinished, + &status2); + + if (res != SZ_OK) + { + p->results[i] = res; + if (resMain == SZ_OK) + resMain = res; + } + + encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK); + + if (!encodingWasFinished) + { + allFinished = False; + if (p->numCoders == 1 && res == SZ_OK) + p->status = status2; + } + + if (i == 0) + { + *srcLen += srcLen2; + src += srcLen2; + } + else + p->pos[(size_t)i - 1] += srcLen2; + + if (i == p->numCoders - 1) + { + *destLen += destLen2; + dest += destLen2; + } + else + { + p->size[i] = destLen2; + p->pos[i] = 0; + p->finished[i] = encodingWasFinished; + } + + if (destLen2 != 0 || srcLen2 != 0) + processed = True; + } + + if (!processed) + { + if (allFinished) + p->status = CODER_STATUS_FINISHED_WITH_MARK; + return resMain; + } + } +} + + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) +{ + *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); + if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != + GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) + return SZ_ERROR_NO_ARCHIVE; + return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) +{ + return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) + && GetUi32(buf) == CrcCalc(buf + 4, 6) + && flags == GetBe16(buf + 8) + && buf[10] == XZ_FOOTER_SIG_0 + && buf[11] == XZ_FOOTER_SIG_1; +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; \ + pos += s; } + + +static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p) +{ + const unsigned numFilters = XzBlock_GetNumFilters(p) - 1; + unsigned i; + { + const CXzFilter *f = &p->filters[numFilters]; + if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40) + return False; + } + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + if (f->id == XZ_ID_Delta) + { + if (f->propsSize != 1) + return False; + } + else if (!XZ_IS_SUPPORTED_FILTER_ID(f->id) + || (f->propsSize != 0 && f->propsSize != 4)) + return False; + } + return True; +} + + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header) +{ + unsigned pos; + unsigned numFilters, i; + unsigned headerSize = (unsigned)header[0] << 2; + + /* (headerSize != 0) : another code checks */ + + if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) + return SZ_ERROR_ARCHIVE; + + pos = 1; + p->flags = header[pos++]; + + p->packSize = (UInt64)(Int64)-1; + if (XzBlock_HasPackSize(p)) + { + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize) + if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) + return SZ_ERROR_ARCHIVE; + } + + p->unpackSize = (UInt64)(Int64)-1; + if (XzBlock_HasUnpackSize(p)) + { + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize) + } + + numFilters = XzBlock_GetNumFilters(p); + for (i = 0; i < numFilters; i++) + { + CXzFilter *filter = p->filters + i; + UInt64 size; + READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id) + READ_VARINT_AND_CHECK(header, pos, headerSize, &size) + if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) + return SZ_ERROR_ARCHIVE; + filter->propsSize = (UInt32)size; + memcpy(filter->props, header + pos, (size_t)size); + pos += (unsigned)size; + + #ifdef XZ_DUMP + printf("\nf[%u] = %2X: ", i, (unsigned)filter->id); + { + unsigned i; + for (i = 0; i < size; i++) + printf(" %2X", filter->props[i]); + } + #endif + } + + if (XzBlock_HasUnsupportedFlags(p)) + return SZ_ERROR_UNSUPPORTED; + + while (pos < headerSize) + if (header[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return SZ_OK; +} + + + + +static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize) +{ + unsigned i; + BoolInt needReInit = True; + unsigned numFilters = XzBlock_GetNumFilters(block); + + if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf))) + { + needReInit = False; + for (i = 0; i < numFilters; i++) + if (p->ids[i] != block->filters[numFilters - 1 - i].id) + { + needReInit = True; + break; + } + } + + // p->SingleBufMode = (outBuf != NULL); + p->outBuf = outBuf; + p->outBufSize = outBufSize; + + // p->SingleBufMode = False; + // outBuf = NULL; + + if (needReInit) + { + MixCoder_Free(p); + for (i = 0; i < numFilters; i++) + { + RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize)) + } + p->numCoders = numFilters; + } + else + { + RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize)) + } + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &block->filters[numFilters - 1 - i]; + IStateCoder *sc = &p->coders[i]; + RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)) + } + + MixCoder_Init(p); + return SZ_OK; +} + + + +void XzUnpacker_Init(CXzUnpacker *p) +{ + p->state = XZ_STATE_STREAM_HEADER; + p->pos = 0; + p->numStartedStreams = 0; + p->numFinishedStreams = 0; + p->numTotalBlocks = 0; + p->padSize = 0; + p->decodeOnlyOneBlock = 0; + + p->parseMode = False; + p->decodeToStreamSignature = False; + + // p->outBuf = NULL; + // p->outBufSize = 0; + p->outDataWritten = 0; +} + + +void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize) +{ + p->outBuf = outBuf; + p->outBufSize = outBufSize; +} + + +void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc) +{ + MixCoder_Construct(&p->decoder, alloc); + p->outBuf = NULL; + p->outBufSize = 0; + XzUnpacker_Init(p); +} + + +void XzUnpacker_Free(CXzUnpacker *p) +{ + MixCoder_Free(&p->decoder); +} + + +void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p) +{ + p->indexSize = 0; + p->numBlocks = 0; + Sha256_Init(&p->sha); + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + p->decodeOnlyOneBlock = 1; +} + + +static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize) +{ + Byte temp[32]; + unsigned num = Xz_WriteVarInt(temp, packSize); + num += Xz_WriteVarInt(temp + num, unpackSize); + Sha256_Update(&p->sha, temp, num); + p->indexSize += num; + p->numBlocks++; +} + + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcFinished, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + *destLen = 0; + *srcLen = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + + for (;;) + { + SizeT srcRem; + + if (p->state == XZ_STATE_BLOCK) + { + SizeT destLen2 = destLenOrig - *destLen; + SizeT srcLen2 = srcLenOrig - *srcLen; + SRes res; + + ECoderFinishMode finishMode2 = finishMode; + BoolInt srcFinished2 = srcFinished; + BoolInt destFinish = False; + + if (p->block.packSize != (UInt64)(Int64)-1) + { + UInt64 rem = p->block.packSize - p->packSize; + if (srcLen2 >= rem) + { + srcFinished2 = True; + srcLen2 = (SizeT)rem; + } + if (rem == 0 && p->block.unpackSize == p->unpackSize) + return SZ_ERROR_DATA; + } + + if (p->block.unpackSize != (UInt64)(Int64)-1) + { + UInt64 rem = p->block.unpackSize - p->unpackSize; + if (destLen2 >= rem) + { + destFinish = True; + finishMode2 = CODER_FINISH_END; + destLen2 = (SizeT)rem; + } + } + + /* + if (srcLen2 == 0 && destLen2 == 0) + { + *status = CODER_STATUS_NOT_FINISHED; + return SZ_OK; + } + */ + + { + res = MixCoder_Code(&p->decoder, + (p->outBuf ? NULL : dest), &destLen2, destFinish, + src, &srcLen2, srcFinished2, + finishMode2); + + *status = p->decoder.status; + XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2); + if (!p->outBuf) + dest += destLen2; + p->outDataWritten += destLen2; + } + + (*srcLen) += srcLen2; + src += srcLen2; + p->packSize += srcLen2; + (*destLen) += destLen2; + p->unpackSize += destLen2; + + RINOK(res) + + if (*status != CODER_STATUS_FINISHED_WITH_MARK) + { + if (p->block.packSize == p->packSize + && *status == CODER_STATUS_NEEDS_MORE_INPUT) + { + PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT") + *status = CODER_STATUS_NOT_SPECIFIED; + return SZ_ERROR_DATA; + } + + return SZ_OK; + } + { + XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize); + p->state = XZ_STATE_BLOCK_FOOTER; + p->pos = 0; + p->alignPos = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + + if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize) + || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize)) + { + PRF_STR("ERROR: block.size mismatch") + return SZ_ERROR_DATA; + } + } + // continue; + } + + srcRem = srcLenOrig - *srcLen; + + // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes + if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + switch (p->state) + { + case XZ_STATE_STREAM_HEADER: + { + if (p->pos < XZ_STREAM_HEADER_SIZE) + { + if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) + return SZ_ERROR_NO_ARCHIVE; + if (p->decodeToStreamSignature) + return SZ_OK; + p->buf[p->pos++] = *src++; + (*srcLen)++; + } + else + { + RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)) + p->numStartedStreams++; + p->indexSize = 0; + p->numBlocks = 0; + Sha256_Init(&p->sha); + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + } + break; + } + + case XZ_STATE_BLOCK_HEADER: + { + if (p->pos == 0) + { + p->buf[p->pos++] = *src++; + (*srcLen)++; + if (p->buf[0] == 0) + { + if (p->decodeOnlyOneBlock) + return SZ_ERROR_DATA; + p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); + p->indexPos = p->indexPreSize; + p->indexSize += p->indexPreSize; + Sha256_Final(&p->sha, p->shaDigest); + Sha256_Init(&p->sha); + p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); + p->state = XZ_STATE_STREAM_INDEX; + break; + } + p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4; + break; + } + + if (p->pos != p->blockHeaderSize) + { + UInt32 cur = p->blockHeaderSize - p->pos; + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + } + else + { + RINOK(XzBlock_Parse(&p->block, p->buf)) + if (!XzBlock_AreSupportedFilters(&p->block)) + return SZ_ERROR_UNSUPPORTED; + p->numTotalBlocks++; + p->state = XZ_STATE_BLOCK; + p->packSize = 0; + p->unpackSize = 0; + XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); + if (p->parseMode) + { + p->headerParsedOk = True; + return SZ_OK; + } + RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize)) + } + break; + } + + case XZ_STATE_BLOCK_FOOTER: + { + if ((((unsigned)p->packSize + p->alignPos) & 3) != 0) + { + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->alignPos++; + if (*src++ != 0) + return SZ_ERROR_CRC; + } + else + { + UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags); + UInt32 cur = checkSize - p->pos; + if (cur != 0) + { + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (checkSize != p->pos) + break; + } + { + Byte digest[XZ_CHECK_SIZE_MAX]; + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) + return SZ_ERROR_CRC; + if (p->decodeOnlyOneBlock) + { + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + } + } + break; + } + + case XZ_STATE_STREAM_INDEX: + { + if (p->pos < p->indexPreSize) + { + (*srcLen)++; + if (*src++ != p->buf[p->pos++]) + return SZ_ERROR_CRC; + } + else + { + if (p->indexPos < p->indexSize) + { + UInt64 cur = p->indexSize - p->indexPos; + if (srcRem > cur) + srcRem = (SizeT)cur; + p->crc = CrcUpdate(p->crc, src, srcRem); + Sha256_Update(&p->sha, src, srcRem); + (*srcLen) += srcRem; + src += srcRem; + p->indexPos += srcRem; + } + else if ((p->indexPos & 3) != 0) + { + Byte b = *src++; + p->crc = CRC_UPDATE_BYTE(p->crc, b); + (*srcLen)++; + p->indexPos++; + p->indexSize++; + if (b != 0) + return SZ_ERROR_CRC; + } + else + { + Byte digest[SHA256_DIGEST_SIZE]; + p->state = XZ_STATE_STREAM_INDEX_CRC; + p->indexSize += 4; + p->pos = 0; + Sha256_Final(&p->sha, digest); + if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) + return SZ_ERROR_CRC; + } + } + break; + } + + case XZ_STATE_STREAM_INDEX_CRC: + { + if (p->pos < 4) + { + (*srcLen)++; + p->buf[p->pos++] = *src++; + } + else + { + const Byte *ptr = p->buf; + p->state = XZ_STATE_STREAM_FOOTER; + p->pos = 0; + if (CRC_GET_DIGEST(p->crc) != GetUi32(ptr)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_FOOTER: + { + UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos; + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (p->pos == XZ_STREAM_FOOTER_SIZE) + { + p->state = XZ_STATE_STREAM_PADDING; + p->numFinishedStreams++; + p->padSize = 0; + if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_PADDING: + { + if (*src != 0) + { + if (((UInt32)p->padSize & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + p->pos = 0; + p->state = XZ_STATE_STREAM_HEADER; + } + else + { + (*srcLen)++; + src++; + p->padSize++; + } + break; + } + + case XZ_STATE_BLOCK: break; /* to disable GCC warning */ + } + } + /* + if (p->state == XZ_STATE_FINISHED) + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + */ +} + + +SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + XzUnpacker_Init(p); + XzUnpacker_SetOutBuf(p, dest, *destLen); + + return XzUnpacker_Code(p, + NULL, destLen, + src, srcLen, True, + finishMode, status); +} + + +BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p) +{ + return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0); +} + +BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p) +{ + return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); +} + +UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p) +{ + UInt64 num = 0; + if (p->state == XZ_STATE_STREAM_PADDING) + num = p->padSize; + else if (p->state == XZ_STATE_STREAM_HEADER) + num = p->padSize + p->pos; + return num; +} + + + + + + + + + + + + + + + + + + + + + +#ifndef Z7_ST +#include "MtDec.h" +#endif + + +void XzDecMtProps_Init(CXzDecMtProps *p) +{ + p->inBufSize_ST = 1 << 18; + p->outStep_ST = 1 << 20; + p->ignoreErrors = False; + + #ifndef Z7_ST + p->numThreads = 1; + p->inBufSize_MT = 1 << 18; + p->memUseMax = sizeof(size_t) << 28; + #endif +} + + + +#ifndef Z7_ST + +/* ---------- CXzDecMtThread ---------- */ + +typedef struct +{ + Byte *outBuf; + size_t outBufSize; + size_t outPreSize; + size_t inPreSize; + size_t inPreHeaderSize; + size_t blockPackSize_for_Index; // including block header and checksum. + size_t blockPackTotal; // including stream header, block header and checksum. + size_t inCodeSize; + size_t outCodeSize; + ECoderStatus status; + SRes codeRes; + BoolInt skipMode; + // BoolInt finishedWithMark; + EMtDecParseState parseState; + BoolInt parsing_Truncated; + BoolInt atBlockHeader; + CXzStreamFlags streamFlags; + // UInt64 numFinishedStreams + UInt64 numStreams; + UInt64 numTotalBlocks; + UInt64 numBlocks; + + BoolInt dec_created; + CXzUnpacker dec; + + Byte mtPad[1 << 7]; +} CXzDecMtThread; + +#endif + + +/* ---------- CXzDecMt ---------- */ + +struct CXzDecMt +{ + CAlignOffsetAlloc alignOffsetAlloc; + ISzAllocPtr allocMid; + + CXzDecMtProps props; + size_t unpackBlockMaxSize; + + ISeqInStreamPtr inStream; + ISeqOutStreamPtr outStream; + ICompressProgressPtr progress; + + BoolInt finishMode; + BoolInt outSize_Defined; + UInt64 outSize; + + UInt64 outProcessed; + UInt64 inProcessed; + UInt64 readProcessed; + BoolInt readWasFinished; + SRes readRes; + SRes writeRes; + + Byte *outBuf; + size_t outBufSize; + Byte *inBuf; + size_t inBufSize; + + CXzUnpacker dec; + + ECoderStatus status; + SRes codeRes; + + #ifndef Z7_ST + BoolInt mainDecoderWasCalled; + // int statErrorDefined; + int finishedDecoderIndex; + + // global values that are used in Parse stage + CXzStreamFlags streamFlags; + // UInt64 numFinishedStreams + UInt64 numStreams; + UInt64 numTotalBlocks; + UInt64 numBlocks; + + // UInt64 numBadBlocks; + SRes mainErrorCode; // it's set to error code, if the size Code() output doesn't patch the size from Parsing stage + // it can be = SZ_ERROR_INPUT_EOF + // it can be = SZ_ERROR_DATA, in some another cases + BoolInt isBlockHeaderState_Parse; + BoolInt isBlockHeaderState_Write; + UInt64 outProcessed_Parse; + BoolInt parsing_Truncated; + + BoolInt mtc_WasConstructed; + CMtDec mtc; + CXzDecMtThread coders[MTDEC_THREADS_MAX]; + #endif +}; + + + +CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) +{ + CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt)); + if (!p) + return NULL; + + AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); + p->alignOffsetAlloc.baseAlloc = alloc; + p->alignOffsetAlloc.numAlignBits = 7; + p->alignOffsetAlloc.offset = 0; + + p->allocMid = allocMid; + + p->outBuf = NULL; + p->outBufSize = 0; + p->inBuf = NULL; + p->inBufSize = 0; + + XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt); + + p->unpackBlockMaxSize = 0; + + XzDecMtProps_Init(&p->props); + + #ifndef Z7_ST + p->mtc_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CXzDecMtThread *coder = &p->coders[i]; + coder->dec_created = False; + coder->outBuf = NULL; + coder->outBufSize = 0; + } + } + #endif + + return (CXzDecMtHandle)p; +} + + +#ifndef Z7_ST + +static void XzDecMt_FreeOutBufs(CXzDecMt *p) +{ + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CXzDecMtThread *coder = &p->coders[i]; + if (coder->outBuf) + { + ISzAlloc_Free(p->allocMid, coder->outBuf); + coder->outBuf = NULL; + coder->outBufSize = 0; + } + } + p->unpackBlockMaxSize = 0; +} + +#endif + + + +static void XzDecMt_FreeSt(CXzDecMt *p) +{ + XzUnpacker_Free(&p->dec); + + if (p->outBuf) + { + ISzAlloc_Free(p->allocMid, p->outBuf); + p->outBuf = NULL; + } + p->outBufSize = 0; + + if (p->inBuf) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBuf = NULL; + } + p->inBufSize = 0; +} + + +// #define GET_CXzDecMt_p CXzDecMt *p = pp; + +void XzDecMt_Destroy(CXzDecMtHandle p) +{ + // GET_CXzDecMt_p + + XzDecMt_FreeSt(p); + + #ifndef Z7_ST + + if (p->mtc_WasConstructed) + { + MtDec_Destruct(&p->mtc); + p->mtc_WasConstructed = False; + } + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CXzDecMtThread *t = &p->coders[i]; + if (t->dec_created) + { + // we don't need to free dict here + XzUnpacker_Free(&t->dec); + t->dec_created = False; + } + } + } + XzDecMt_FreeOutBufs(p); + + #endif + + ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, p); +} + + + +#ifndef Z7_ST + +static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) +{ + CXzDecMt *me = (CXzDecMt *)obj; + CXzDecMtThread *coder = &me->coders[coderIndex]; + size_t srcSize = cc->srcSize; + + cc->srcSize = 0; + cc->outPos = 0; + cc->state = MTDEC_PARSE_CONTINUE; + + cc->canCreateNewThread = True; + + if (cc->startCall) + { + coder->outPreSize = 0; + coder->inPreSize = 0; + coder->inPreHeaderSize = 0; + coder->parseState = MTDEC_PARSE_CONTINUE; + coder->parsing_Truncated = False; + coder->skipMode = False; + coder->codeRes = SZ_OK; + coder->status = CODER_STATUS_NOT_SPECIFIED; + coder->inCodeSize = 0; + coder->outCodeSize = 0; + + coder->numStreams = me->numStreams; + coder->numTotalBlocks = me->numTotalBlocks; + coder->numBlocks = me->numBlocks; + + if (!coder->dec_created) + { + XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt); + coder->dec_created = True; + } + + XzUnpacker_Init(&coder->dec); + + if (me->isBlockHeaderState_Parse) + { + coder->dec.streamFlags = me->streamFlags; + coder->atBlockHeader = True; + XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec); + } + else + { + coder->atBlockHeader = False; + me->isBlockHeaderState_Parse = True; + } + + coder->dec.numStartedStreams = me->numStreams; + coder->dec.numTotalBlocks = me->numTotalBlocks; + coder->dec.numBlocks = me->numBlocks; + } + + while (!coder->skipMode) + { + ECoderStatus status; + SRes res; + size_t srcSize2 = srcSize; + size_t destSize = (size_t)0 - 1; + + coder->dec.parseMode = True; + coder->dec.headerParsedOk = False; + + PRF_STR_INT("Parse", srcSize2) + + res = XzUnpacker_Code(&coder->dec, + NULL, &destSize, + cc->src, &srcSize2, cc->srcFinished, + CODER_FINISH_END, &status); + + // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2)); + + coder->codeRes = res; + coder->status = status; + cc->srcSize += srcSize2; + srcSize -= srcSize2; + coder->inPreHeaderSize += srcSize2; + coder->inPreSize = coder->inPreHeaderSize; + + if (res != SZ_OK) + { + cc->state = + coder->parseState = MTDEC_PARSE_END; + /* + if (res == SZ_ERROR_MEM) + return res; + return SZ_OK; + */ + return; // res; + } + + if (coder->dec.headerParsedOk) + { + const CXzBlock *block = &coder->dec.block; + if (XzBlock_HasUnpackSize(block) + // && block->unpackSize <= me->props.outBlockMax + && XzBlock_HasPackSize(block)) + { + { + if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax) + { + cc->state = MTDEC_PARSE_OVERFLOW; + return; // SZ_OK; + } + } + { + UInt64 packSize = block->packSize; + UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3); + UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags); + UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize; + // if (blockPackSum <= me->props.inBlockMax) + // unpackBlockMaxSize + { + coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize); + coder->blockPackTotal = (size_t)blockPackSum; + coder->outPreSize = (size_t)block->unpackSize; + coder->streamFlags = coder->dec.streamFlags; + me->streamFlags = coder->dec.streamFlags; + coder->skipMode = True; + break; + } + } + } + } + else + // if (coder->inPreSize <= me->props.inBlockMax) + { + if (!cc->srcFinished) + return; // SZ_OK; + cc->state = + coder->parseState = MTDEC_PARSE_END; + return; // SZ_OK; + } + cc->state = MTDEC_PARSE_OVERFLOW; + return; // SZ_OK; + } + + // ---------- skipMode ---------- + { + UInt64 rem = coder->blockPackTotal - coder->inPreSize; + size_t cur = srcSize; + if (cur > rem) + cur = (size_t)rem; + cc->srcSize += cur; + coder->inPreSize += cur; + srcSize -= cur; + + if (coder->inPreSize == coder->blockPackTotal) + { + if (srcSize == 0) + { + if (!cc->srcFinished) + return; // SZ_OK; + cc->state = MTDEC_PARSE_END; + } + else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block + cc->state = MTDEC_PARSE_END; + else + { + cc->state = MTDEC_PARSE_NEW; + + { + size_t blockMax = me->unpackBlockMaxSize; + if (blockMax < coder->outPreSize) + blockMax = coder->outPreSize; + { + UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2; + if (me->props.memUseMax < required) + cc->canCreateNewThread = False; + } + } + + if (me->outSize_Defined) + { + // next block can be zero size + const UInt64 rem2 = me->outSize - me->outProcessed_Parse; + if (rem2 < coder->outPreSize) + { + coder->parsing_Truncated = True; + cc->state = MTDEC_PARSE_END; + } + me->outProcessed_Parse += coder->outPreSize; + } + } + } + else if (cc->srcFinished) + cc->state = MTDEC_PARSE_END; + else + return; // SZ_OK; + + coder->parseState = cc->state; + cc->outPos = coder->outPreSize; + + me->numStreams = coder->dec.numStartedStreams; + me->numTotalBlocks = coder->dec.numTotalBlocks; + me->numBlocks = coder->dec.numBlocks + 1; + return; // SZ_OK; + } +} + + +static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex) +{ + CXzDecMt *me = (CXzDecMt *)pp; + CXzDecMtThread *coder = &me->coders[coderIndex]; + Byte *dest; + + if (!coder->dec.headerParsedOk) + return SZ_OK; + + dest = coder->outBuf; + + if (!dest || coder->outBufSize < coder->outPreSize) + { + if (dest) + { + ISzAlloc_Free(me->allocMid, dest); + coder->outBuf = NULL; + coder->outBufSize = 0; + } + { + size_t outPreSize = coder->outPreSize; + if (outPreSize == 0) + outPreSize = 1; + dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize); + } + if (!dest) + return SZ_ERROR_MEM; + coder->outBuf = dest; + coder->outBufSize = coder->outPreSize; + + if (coder->outBufSize > me->unpackBlockMaxSize) + me->unpackBlockMaxSize = coder->outBufSize; + } + + // return SZ_ERROR_MEM; + + XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize); + + { + SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize); + // res = SZ_ERROR_UNSUPPORTED; // to test + coder->codeRes = res; + if (res != SZ_OK) + { + // if (res == SZ_ERROR_MEM) return res; + if (me->props.ignoreErrors && res != SZ_ERROR_MEM) + return SZ_OK; + return res; + } + } + + return SZ_OK; +} + + +static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + // int finished, int blockFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop) +{ + CXzDecMt *me = (CXzDecMt *)pp; + CXzDecMtThread *coder = &me->coders[coderIndex]; + + *inCodePos = coder->inCodeSize; + *outCodePos = coder->outCodeSize; + *stop = True; + + if (srcSize > coder->inPreSize - coder->inCodeSize) + return SZ_ERROR_FAIL; + + if (coder->inCodeSize < coder->inPreHeaderSize) + { + size_t step = coder->inPreHeaderSize - coder->inCodeSize; + if (step > srcSize) + step = srcSize; + src += step; + srcSize -= step; + coder->inCodeSize += step; + *inCodePos = coder->inCodeSize; + if (coder->inCodeSize < coder->inPreHeaderSize) + { + *stop = False; + return SZ_OK; + } + } + + if (!coder->dec.headerParsedOk) + return SZ_OK; + if (!coder->outBuf) + return SZ_OK; + + if (coder->codeRes == SZ_OK) + { + ECoderStatus status; + SRes res; + size_t srcProcessed = srcSize; + size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten; + + // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur)); + + res = XzUnpacker_Code(&coder->dec, + NULL, &outSizeCur, + src, &srcProcessed, srcFinished, + // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY, + CODER_FINISH_END, + &status); + + // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur)); + + coder->codeRes = res; + coder->status = status; + coder->inCodeSize += srcProcessed; + coder->outCodeSize = coder->dec.outDataWritten; + *inCodePos = coder->inCodeSize; + *outCodePos = coder->outCodeSize; + + if (res == SZ_OK) + { + if (srcProcessed == srcSize) + *stop = False; + return SZ_OK; + } + } + + if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM) + { + *inCodePos = coder->inPreSize; + *outCodePos = coder->outPreSize; + return SZ_OK; + } + return coder->codeRes; +} + + +#define XZDECMT_STREAM_WRITE_STEP (1 << 24) + +static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, BoolInt isCross, + // int srcFinished, + BoolInt *needContinue, + BoolInt *canRecode) +{ + CXzDecMt *me = (CXzDecMt *)pp; + const CXzDecMtThread *coder = &me->coders[coderIndex]; + + // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize)); + + *needContinue = False; + *canRecode = True; + + if (!needWriteToStream) + return SZ_OK; + + if (!coder->dec.headerParsedOk || !coder->outBuf) + { + if (me->finishedDecoderIndex < 0) + me->finishedDecoderIndex = (int)coderIndex; + return SZ_OK; + } + + if (me->finishedDecoderIndex >= 0) + return SZ_OK; + + me->mtc.inProcessed += coder->inCodeSize; + + *canRecode = False; + + { + SRes res; + size_t size = coder->outCodeSize; + Byte *data = coder->outBuf; + + // we use in me->dec: sha, numBlocks, indexSize + + if (!me->isBlockHeaderState_Write) + { + XzUnpacker_PrepareToRandomBlockDecoding(&me->dec); + me->dec.decodeOnlyOneBlock = False; + me->dec.numStartedStreams = coder->dec.numStartedStreams; + me->dec.streamFlags = coder->streamFlags; + + me->isBlockHeaderState_Write = True; + } + + me->dec.numTotalBlocks = coder->dec.numTotalBlocks; + XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize); + + if (coder->outPreSize != size) + { + if (me->props.ignoreErrors) + { + memset(data + size, 0, coder->outPreSize - size); + size = coder->outPreSize; + } + // me->numBadBlocks++; + if (me->mainErrorCode == SZ_OK) + { + if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT) + me->mainErrorCode = SZ_ERROR_INPUT_EOF; + else + me->mainErrorCode = SZ_ERROR_DATA; + } + } + + if (me->writeRes != SZ_OK) + return me->writeRes; + + res = SZ_OK; + { + if (me->outSize_Defined) + { + const UInt64 rem = me->outSize - me->outProcessed; + if (size > rem) + size = (SizeT)rem; + } + + for (;;) + { + size_t cur = size; + size_t written; + if (cur > XZDECMT_STREAM_WRITE_STEP) + cur = XZDECMT_STREAM_WRITE_STEP; + + written = ISeqOutStream_Write(me->outStream, data, cur); + + // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written)); + + me->outProcessed += written; + if (written != cur) + { + me->writeRes = SZ_ERROR_WRITE; + res = me->writeRes; + break; + } + data += cur; + size -= cur; + // PRF_STR_INT("Written size =", size) + if (size == 0) + break; + res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0); + if (res != SZ_OK) + break; + } + } + + if (coder->codeRes != SZ_OK) + if (!me->props.ignoreErrors) + { + me->finishedDecoderIndex = (int)coderIndex; + return res; + } + + RINOK(res) + + if (coder->inPreSize != coder->inCodeSize + || coder->blockPackTotal != coder->inCodeSize) + { + me->finishedDecoderIndex = (int)coderIndex; + return SZ_OK; + } + + if (coder->parseState != MTDEC_PARSE_END) + { + *needContinue = True; + return SZ_OK; + } + } + + // (coder->state == MTDEC_PARSE_END) means that there are no other working threads + // so we can use mtc variables without lock + + PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed) + + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + { + CXzUnpacker *dec = &me->dec; + + PRF_STR_INT("PostSingle", srcSize) + + { + size_t srcProcessed = srcSize; + ECoderStatus status; + size_t outSizeCur = 0; + SRes res; + + // dec->decodeOnlyOneBlock = False; + dec->decodeToStreamSignature = True; + + me->mainDecoderWasCalled = True; + + if (coder->parsing_Truncated) + { + me->parsing_Truncated = True; + return SZ_OK; + } + + /* + We have processed all xz-blocks of stream, + And xz unpacker is at XZ_STATE_BLOCK_HEADER state, where + (src) is a pointer to xz-Index structure. + We finish reading of current xz-Stream, including Zero padding after xz-Stream. + We exit, if we reach extra byte (first byte of new-Stream or another data). + But we don't update input stream pointer for that new extra byte. + If extra byte is not correct first byte of xz-signature, + we have SZ_ERROR_NO_ARCHIVE error here. + */ + + res = XzUnpacker_Code(dec, + NULL, &outSizeCur, + src, &srcProcessed, + me->mtc.readWasFinished, // srcFinished + CODER_FINISH_END, // CODER_FINISH_ANY, + &status); + + // res = SZ_ERROR_ARCHIVE; // for failure test + + me->status = status; + me->codeRes = res; + + if (isCross) + me->mtc.crossStart += srcProcessed; + + me->mtc.inProcessed += srcProcessed; + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + + srcSize -= srcProcessed; + src += srcProcessed; + + if (res != SZ_OK) + { + return SZ_OK; + // return res; + } + + if (dec->state == XZ_STATE_STREAM_HEADER) + { + *needContinue = True; + me->isBlockHeaderState_Parse = False; + me->isBlockHeaderState_Write = False; + + if (!isCross) + { + Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); + if (!crossBuf) + return SZ_ERROR_MEM; + if (srcSize != 0) + memcpy(crossBuf, src, srcSize); + me->mtc.crossStart = 0; + me->mtc.crossEnd = srcSize; + } + + PRF_STR_INT("XZ_STATE_STREAM_HEADER crossEnd = ", (unsigned)me->mtc.crossEnd) + + return SZ_OK; + } + + if (status != CODER_STATUS_NEEDS_MORE_INPUT || srcSize != 0) + { + return SZ_ERROR_FAIL; + } + + if (me->mtc.readWasFinished) + { + return SZ_OK; + } + } + + { + size_t inPos; + size_t inLim; + // const Byte *inData; + UInt64 inProgressPrev = me->mtc.inProcessed; + + // XzDecMt_Prepare_InBuf_ST(p); + Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); + if (!crossBuf) + return SZ_ERROR_MEM; + + inPos = 0; + inLim = 0; + + // inData = crossBuf; + + for (;;) + { + SizeT inProcessed; + SizeT outProcessed; + ECoderStatus status; + SRes res; + + if (inPos == inLim) + { + if (!me->mtc.readWasFinished) + { + inPos = 0; + inLim = me->mtc.inBufSize; + me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)crossBuf, &inLim); + me->mtc.readProcessed += inLim; + if (inLim == 0 || me->mtc.readRes != SZ_OK) + me->mtc.readWasFinished = True; + } + } + + inProcessed = inLim - inPos; + outProcessed = 0; + + res = XzUnpacker_Code(dec, + NULL, &outProcessed, + crossBuf + inPos, &inProcessed, + (inProcessed == 0), // srcFinished + CODER_FINISH_END, &status); + + me->codeRes = res; + me->status = status; + inPos += inProcessed; + me->mtc.inProcessed += inProcessed; + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + + if (res != SZ_OK) + { + return SZ_OK; + // return res; + } + + if (dec->state == XZ_STATE_STREAM_HEADER) + { + *needContinue = True; + me->mtc.crossStart = inPos; + me->mtc.crossEnd = inLim; + me->isBlockHeaderState_Parse = False; + me->isBlockHeaderState_Write = False; + return SZ_OK; + } + + if (status != CODER_STATUS_NEEDS_MORE_INPUT) + return SZ_ERROR_FAIL; + + if (me->mtc.progress) + { + UInt64 inDelta = me->mtc.inProcessed - inProgressPrev; + if (inDelta >= (1 << 22)) + { + RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress)) + inProgressPrev = me->mtc.inProcessed; + } + } + if (me->mtc.readWasFinished) + return SZ_OK; + } + } + } +} + + +#endif + + + +void XzStatInfo_Clear(CXzStatInfo *p) +{ + p->InSize = 0; + p->OutSize = 0; + + p->NumStreams = 0; + p->NumBlocks = 0; + + p->UnpackSize_Defined = False; + + p->NumStreams_Defined = False; + p->NumBlocks_Defined = False; + + p->DataAfterEnd = False; + p->DecodingTruncated = False; + + p->DecodeRes = SZ_OK; + p->ReadRes = SZ_OK; + p->ProgressRes = SZ_OK; + + p->CombinedRes = SZ_OK; + p->CombinedRes_Type = SZ_OK; +} + + + +/* + XzDecMt_Decode_ST() can return SZ_OK or the following errors + - SZ_ERROR_MEM for memory allocation error + - error from XzUnpacker_Code() function + - SZ_ERROR_WRITE for ISeqOutStream::Write(). stat->CombinedRes_Type = SZ_ERROR_WRITE in that case + - ICompressProgress::Progress() error, stat->CombinedRes_Type = SZ_ERROR_PROGRESS. + But XzDecMt_Decode_ST() doesn't return ISeqInStream::Read() errors. + ISeqInStream::Read() result is set to p->readRes. + also it can set stat->CombinedRes_Type to SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. +*/ + +static SRes XzDecMt_Decode_ST(CXzDecMt *p + #ifndef Z7_ST + , BoolInt tMode + #endif + , CXzStatInfo *stat) +{ + size_t outPos; + size_t inPos, inLim; + const Byte *inData; + UInt64 inPrev, outPrev; + + CXzUnpacker *dec; + + #ifndef Z7_ST + if (tMode) + { + XzDecMt_FreeOutBufs(p); + tMode = MtDec_PrepareRead(&p->mtc); + } + #endif + + if (!p->outBuf || p->outBufSize != p->props.outStep_ST) + { + ISzAlloc_Free(p->allocMid, p->outBuf); + p->outBufSize = 0; + p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST); + if (!p->outBuf) + return SZ_ERROR_MEM; + p->outBufSize = p->props.outStep_ST; + } + + if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBufSize = 0; + p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); + if (!p->inBuf) + return SZ_ERROR_MEM; + p->inBufSize = p->props.inBufSize_ST; + } + + dec = &p->dec; + dec->decodeToStreamSignature = False; + // dec->decodeOnlyOneBlock = False; + + XzUnpacker_SetOutBuf(dec, NULL, 0); + + inPrev = p->inProcessed; + outPrev = p->outProcessed; + + inPos = 0; + inLim = 0; + inData = NULL; + outPos = 0; + + for (;;) + { + SizeT outSize; + BoolInt finished; + ECoderFinishMode finishMode; + SizeT inProcessed; + ECoderStatus status; + SRes res; + + SizeT outProcessed; + + + + if (inPos == inLim) + { + #ifndef Z7_ST + if (tMode) + { + inData = MtDec_Read(&p->mtc, &inLim); + inPos = 0; + if (inData) + continue; + tMode = False; + inLim = 0; + } + #endif + + if (!p->readWasFinished) + { + inPos = 0; + inLim = p->inBufSize; + inData = p->inBuf; + p->readRes = ISeqInStream_Read(p->inStream, (void *)p->inBuf, &inLim); + p->readProcessed += inLim; + if (inLim == 0 || p->readRes != SZ_OK) + p->readWasFinished = True; + } + } + + outSize = p->props.outStep_ST - outPos; + + finishMode = CODER_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (outSize >= rem) + { + outSize = (SizeT)rem; + if (p->finishMode) + finishMode = CODER_FINISH_END; + } + } + + inProcessed = inLim - inPos; + outProcessed = outSize; + + res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed, + inData + inPos, &inProcessed, + (inPos == inLim), // srcFinished + finishMode, &status); + + p->codeRes = res; + p->status = status; + + inPos += inProcessed; + outPos += outProcessed; + p->inProcessed += inProcessed; + p->outProcessed += outProcessed; + + finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK); + + if (finished || outProcessed >= outSize) + if (outPos != 0) + { + const size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos); + // p->outProcessed += written; // 21.01: BUG fixed + if (written != outPos) + { + stat->CombinedRes_Type = SZ_ERROR_WRITE; + return SZ_ERROR_WRITE; + } + outPos = 0; + } + + if (p->progress && res == SZ_OK) + { + if (p->inProcessed - inPrev >= (1 << 22) || + p->outProcessed - outPrev >= (1 << 22)) + { + res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed); + if (res != SZ_OK) + { + stat->CombinedRes_Type = SZ_ERROR_PROGRESS; + stat->ProgressRes = res; + return res; + } + inPrev = p->inProcessed; + outPrev = p->outProcessed; + } + } + + if (finished) + { + // p->codeRes is preliminary error from XzUnpacker_Code. + // and it can be corrected later as final result + // so we return SZ_OK here instead of (res); + return SZ_OK; + // return res; + } + } +} + + + +/* +XzStatInfo_SetStat() transforms + CXzUnpacker return code and status to combined CXzStatInfo results. + it can convert SZ_OK to SZ_ERROR_INPUT_EOF + it can convert SZ_ERROR_NO_ARCHIVE to SZ_OK and (DataAfterEnd = 1) +*/ + +static void XzStatInfo_SetStat(const CXzUnpacker *dec, + int finishMode, + // UInt64 readProcessed, + UInt64 inProcessed, + SRes res, // it's result from CXzUnpacker unpacker + ECoderStatus status, + BoolInt decodingTruncated, + CXzStatInfo *stat) +{ + UInt64 extraSize; + + stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0); + stat->InSize = inProcessed; + stat->NumStreams = dec->numStartedStreams; + stat->NumBlocks = dec->numTotalBlocks; + + stat->UnpackSize_Defined = True; + stat->NumStreams_Defined = True; + stat->NumBlocks_Defined = True; + + extraSize = XzUnpacker_GetExtraSize(dec); + + if (res == SZ_OK) + { + if (status == CODER_STATUS_NEEDS_MORE_INPUT) + { + // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams + // any extra data is part of correct data + extraSize = 0; + // if xz stream was not finished, then we need more data + if (!XzUnpacker_IsStreamWasFinished(dec)) + res = SZ_ERROR_INPUT_EOF; + } + else + { + // CODER_STATUS_FINISHED_WITH_MARK is not possible for multi stream xz decoding + // so he we have (status == CODER_STATUS_NOT_FINISHED) + // if (status != CODER_STATUS_FINISHED_WITH_MARK) + if (!decodingTruncated || finishMode) + res = SZ_ERROR_DATA; + } + } + else if (res == SZ_ERROR_NO_ARCHIVE) + { + /* + SZ_ERROR_NO_ARCHIVE is possible for 2 states: + XZ_STATE_STREAM_HEADER - if bad signature or bad CRC + XZ_STATE_STREAM_PADDING - if non-zero padding data + extraSize and inProcessed don't include "bad" byte + */ + // if (inProcessed == extraSize), there was no any good xz stream header, and we keep error + if (inProcessed != extraSize) // if there were good xz streams before error + { + // if (extraSize != 0 || readProcessed != inProcessed) + { + // he we suppose that all xz streams were finsihed OK, and we have + // some extra data after all streams + stat->DataAfterEnd = True; + res = SZ_OK; + } + } + } + + if (stat->DecodeRes == SZ_OK) + stat->DecodeRes = res; + + stat->InSize -= extraSize; +} + + + +SRes XzDecMt_Decode(CXzDecMtHandle p, + const CXzDecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqOutStreamPtr outStream, + // Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + // const Byte *inData, size_t inDataSize, + CXzStatInfo *stat, + int *isMT, + ICompressProgressPtr progress) +{ + // GET_CXzDecMt_p + #ifndef Z7_ST + BoolInt tMode; + #endif + + XzStatInfo_Clear(stat); + + p->props = *props; + + p->inStream = inStream; + p->outStream = outStream; + p->progress = progress; + // p->stat = stat; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + + p->finishMode = finishMode; + + // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test + + p->writeRes = SZ_OK; + p->outProcessed = 0; + p->inProcessed = 0; + p->readProcessed = 0; + p->readWasFinished = False; + p->readRes = SZ_OK; + + p->codeRes = SZ_OK; + p->status = CODER_STATUS_NOT_SPECIFIED; + + XzUnpacker_Init(&p->dec); + + *isMT = False; + + /* + p->outBuf = NULL; + p->outBufSize = 0; + if (!outStream) + { + p->outBuf = outBuf; + p->outBufSize = *outBufSize; + *outBufSize = 0; + } + */ + + + #ifndef Z7_ST + + p->isBlockHeaderState_Parse = False; + p->isBlockHeaderState_Write = False; + // p->numBadBlocks = 0; + p->mainErrorCode = SZ_OK; + p->mainDecoderWasCalled = False; + + tMode = False; + + if (p->props.numThreads > 1) + { + IMtDecCallback2 vt; + BoolInt needContinue; + SRes res; + // we just free ST buffers here + // but we still keep state variables, that was set in XzUnpacker_Init() + XzDecMt_FreeSt(p); + + p->outProcessed_Parse = 0; + p->parsing_Truncated = False; + + p->numStreams = 0; + p->numTotalBlocks = 0; + p->numBlocks = 0; + p->finishedDecoderIndex = -1; + + if (!p->mtc_WasConstructed) + { + p->mtc_WasConstructed = True; + MtDec_Construct(&p->mtc); + } + + p->mtc.mtCallback = &vt; + p->mtc.mtCallbackObject = p; + + p->mtc.progress = progress; + p->mtc.inStream = inStream; + p->mtc.alloc = &p->alignOffsetAlloc.vt; + // p->mtc.inData = inData; + // p->mtc.inDataSize = inDataSize; + p->mtc.inBufSize = p->props.inBufSize_MT; + // p->mtc.inBlockMax = p->props.inBlockMax; + p->mtc.numThreadsMax = p->props.numThreads; + + *isMT = True; + + vt.Parse = XzDecMt_Callback_Parse; + vt.PreCode = XzDecMt_Callback_PreCode; + vt.Code = XzDecMt_Callback_Code; + vt.Write = XzDecMt_Callback_Write; + + + res = MtDec_Code(&p->mtc); + + + stat->InSize = p->mtc.inProcessed; + + p->inProcessed = p->mtc.inProcessed; + p->readRes = p->mtc.readRes; + p->readWasFinished = p->mtc.readWasFinished; + p->readProcessed = p->mtc.readProcessed; + + tMode = True; + needContinue = False; + + if (res == SZ_OK) + { + if (p->mtc.mtProgress.res != SZ_OK) + { + res = p->mtc.mtProgress.res; + stat->ProgressRes = res; + stat->CombinedRes_Type = SZ_ERROR_PROGRESS; + } + else + needContinue = p->mtc.needContinue; + } + + if (!needContinue) + { + { + SRes codeRes; + BoolInt truncated = False; + ECoderStatus status; + const CXzUnpacker *dec; + + stat->OutSize = p->outProcessed; + + if (p->finishedDecoderIndex >= 0) + { + const CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex]; + codeRes = coder->codeRes; + dec = &coder->dec; + status = coder->status; + } + else if (p->mainDecoderWasCalled) + { + codeRes = p->codeRes; + dec = &p->dec; + status = p->status; + truncated = p->parsing_Truncated; + } + else + return SZ_ERROR_FAIL; + + if (p->mainErrorCode != SZ_OK) + stat->DecodeRes = p->mainErrorCode; + + XzStatInfo_SetStat(dec, p->finishMode, + // p->mtc.readProcessed, + p->mtc.inProcessed, + codeRes, status, + truncated, + stat); + } + + if (res == SZ_OK) + { + stat->ReadRes = p->mtc.readRes; + + if (p->writeRes != SZ_OK) + { + res = p->writeRes; + stat->CombinedRes_Type = SZ_ERROR_WRITE; + } + else if (p->mtc.readRes != SZ_OK + // && p->mtc.inProcessed == p->mtc.readProcessed + && stat->DecodeRes == SZ_ERROR_INPUT_EOF) + { + res = p->mtc.readRes; + stat->CombinedRes_Type = SZ_ERROR_READ; + } + else if (stat->DecodeRes != SZ_OK) + res = stat->DecodeRes; + } + + stat->CombinedRes = res; + if (stat->CombinedRes_Type == SZ_OK) + stat->CombinedRes_Type = res; + return res; + } + + PRF_STR("----- decoding ST -----") + } + + #endif + + + *isMT = False; + + { + SRes res = XzDecMt_Decode_ST(p + #ifndef Z7_ST + , tMode + #endif + , stat + ); + + #ifndef Z7_ST + // we must set error code from MT decoding at first + if (p->mainErrorCode != SZ_OK) + stat->DecodeRes = p->mainErrorCode; + #endif + + XzStatInfo_SetStat(&p->dec, + p->finishMode, + // p->readProcessed, + p->inProcessed, + p->codeRes, p->status, + False, // truncated + stat); + + stat->ReadRes = p->readRes; + + if (res == SZ_OK) + { + if (p->readRes != SZ_OK + // && p->inProcessed == p->readProcessed + && stat->DecodeRes == SZ_ERROR_INPUT_EOF) + { + // we set read error as combined error, only if that error was the reason + // of decoding problem + res = p->readRes; + stat->CombinedRes_Type = SZ_ERROR_READ; + } + else if (stat->DecodeRes != SZ_OK) + res = stat->DecodeRes; + } + + stat->CombinedRes = res; + if (stat->CombinedRes_Type == SZ_OK) + stat->CombinedRes_Type = res; + return res; + } +} + +#undef PRF +#undef PRF_STR +#undef PRF_STR_INT_2 diff --git a/libraries/lzma/C/XzEnc.c b/libraries/lzma/C/XzEnc.c new file mode 100644 index 00000000000..22408e26189 --- /dev/null +++ b/libraries/lzma/C/XzEnc.c @@ -0,0 +1,1362 @@ +/* XzEnc.c -- Xz Encode +2023-04-13 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +#include + +#include "7zCrc.h" +#include "Bra.h" +#include "CpuArch.h" + +#ifdef USE_SUBBLOCK +#include "Bcj3Enc.c" +#include "SbFind.c" +#include "SbEnc.c" +#endif + +#include "XzEnc.h" + +// #define Z7_ST + +#ifndef Z7_ST +#include "MtCoder.h" +#else +#define MTCODER_THREADS_MAX 1 +#define MTCODER_BLOCKS_MAX 1 +#endif + +#define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3) + +/* max pack size for LZMA2 block + check-64bytrs: */ +#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64) + +#define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize)) + + +// #define XzBlock_ClearFlags(p) (p)->flags = 0; +#define XzBlock_ClearFlags_SetNumFilters(p, n) (p)->flags = (Byte)((n) - 1); +#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; +#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; + + +static SRes WriteBytes(ISeqOutStreamPtr s, const void *buf, size_t size) +{ + return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; +} + +static SRes WriteBytes_UpdateCrc(ISeqOutStreamPtr s, const void *buf, size_t size, UInt32 *crc) +{ + *crc = CrcUpdate(*crc, buf, size); + return WriteBytes(s, buf, size); +} + + +static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStreamPtr s) +{ + UInt32 crc; + Byte header[XZ_STREAM_HEADER_SIZE]; + memcpy(header, XZ_SIG, XZ_SIG_SIZE); + header[XZ_SIG_SIZE] = (Byte)(f >> 8); + header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); + crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); + SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc) + return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); +} + + +static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStreamPtr s) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + + unsigned pos = 1; + unsigned numFilters, i; + header[pos++] = p->flags; + + if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); + if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); + numFilters = XzBlock_GetNumFilters(p); + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + pos += Xz_WriteVarInt(header + pos, f->id); + pos += Xz_WriteVarInt(header + pos, f->propsSize); + memcpy(header + pos, f->props, f->propsSize); + pos += f->propsSize; + } + + while ((pos & 3) != 0) + header[pos++] = 0; + + header[0] = (Byte)(pos >> 2); + SetUi32(header + pos, CrcCalc(header, pos)) + return WriteBytes(s, header, pos + 4); +} + + + + +typedef struct +{ + size_t numBlocks; + size_t size; + size_t allocated; + Byte *blocks; +} CXzEncIndex; + + +static void XzEncIndex_Construct(CXzEncIndex *p) +{ + p->numBlocks = 0; + p->size = 0; + p->allocated = 0; + p->blocks = NULL; +} + +static void XzEncIndex_Init(CXzEncIndex *p) +{ + p->numBlocks = 0; + p->size = 0; +} + +static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc) +{ + if (p->blocks) + { + ISzAlloc_Free(alloc, p->blocks); + p->blocks = NULL; + } + p->numBlocks = 0; + p->size = 0; + p->allocated = 0; +} + + +static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc) +{ + Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize); + if (!blocks) + return SZ_ERROR_MEM; + if (p->size != 0) + memcpy(blocks, p->blocks, p->size); + if (p->blocks) + ISzAlloc_Free(alloc, p->blocks); + p->blocks = blocks; + p->allocated = newSize; + return SZ_OK; +} + + +static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) +{ + UInt64 pos; + { + Byte buf[32]; + unsigned pos2 = Xz_WriteVarInt(buf, totalSize); + pos2 += Xz_WriteVarInt(buf + pos2, unpackSize); + pos = numBlocks * pos2; + } + + if (pos <= p->allocated - p->size) + return SZ_OK; + { + UInt64 newSize64 = p->size + pos; + size_t newSize = (size_t)newSize64; + if (newSize != newSize64) + return SZ_ERROR_MEM; + return XzEncIndex_ReAlloc(p, newSize, alloc); + } +} + + +static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) +{ + Byte buf[32]; + unsigned pos = Xz_WriteVarInt(buf, totalSize); + pos += Xz_WriteVarInt(buf + pos, unpackSize); + + if (pos > p->allocated - p->size) + { + size_t newSize = p->allocated * 2 + 16 * 2; + if (newSize < p->size + pos) + return SZ_ERROR_MEM; + RINOK(XzEncIndex_ReAlloc(p, newSize, alloc)) + } + memcpy(p->blocks + p->size, buf, pos); + p->size += pos; + p->numBlocks++; + return SZ_OK; +} + + +static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStreamPtr s) +{ + Byte buf[32]; + UInt64 globalPos; + UInt32 crc = CRC_INIT_VAL; + unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); + + globalPos = pos; + buf[0] = 0; + RINOK(WriteBytes_UpdateCrc(s, buf, pos, &crc)) + RINOK(WriteBytes_UpdateCrc(s, p->blocks, p->size, &crc)) + globalPos += p->size; + + pos = XZ_GET_PAD_SIZE(globalPos); + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + globalPos += pos; + + crc = CrcUpdate(crc, buf + 4 - pos, pos); + SetUi32(buf + 4, CRC_GET_DIGEST(crc)) + + SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2)) + buf[8 + 8] = (Byte)(flags >> 8); + buf[8 + 9] = (Byte)(flags & 0xFF); + SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6)) + buf[8 + 10] = XZ_FOOTER_SIG_0; + buf[8 + 11] = XZ_FOOTER_SIG_1; + + return WriteBytes(s, buf + 4 - pos, pos + 4 + 12); +} + + + +/* ---------- CSeqCheckInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + ISeqInStreamPtr realStream; + const Byte *data; + UInt64 limit; + UInt64 processed; + int realStreamFinished; + CXzCheck check; +} CSeqCheckInStream; + +static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode) +{ + p->limit = (UInt64)(Int64)-1; + p->processed = 0; + p->realStreamFinished = 0; + XzCheck_Init(&p->check, checkMode); +} + +static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) +{ + XzCheck_Final(&p->check, digest); +} + +static SRes SeqCheckInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqCheckInStream) + size_t size2 = *size; + SRes res = SZ_OK; + + if (p->limit != (UInt64)(Int64)-1) + { + UInt64 rem = p->limit - p->processed; + if (size2 > rem) + size2 = (size_t)rem; + } + if (size2 != 0) + { + if (p->realStream) + { + res = ISeqInStream_Read(p->realStream, data, &size2); + p->realStreamFinished = (size2 == 0) ? 1 : 0; + } + else + memcpy(data, p->data + (size_t)p->processed, size2); + XzCheck_Update(&p->check, data, size2); + p->processed += size2; + } + *size = size2; + return res; +} + + +/* ---------- CSeqSizeOutStream ---------- */ + +typedef struct +{ + ISeqOutStream vt; + ISeqOutStreamPtr realStream; + Byte *outBuf; + size_t outBufLimit; + UInt64 processed; +} CSeqSizeOutStream; + +static size_t SeqSizeOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqSizeOutStream) + if (p->realStream) + size = ISeqOutStream_Write(p->realStream, data, size); + else + { + if (size > p->outBufLimit - (size_t)p->processed) + return 0; + memcpy(p->outBuf + (size_t)p->processed, data, size); + } + p->processed += size; + return size; +} + + +/* ---------- CSeqInFilter ---------- */ + +#define FILTER_BUF_SIZE (1 << 20) + +typedef struct +{ + ISeqInStream vt; + ISeqInStreamPtr realStream; + IStateCoder StateCoder; + Byte *buf; + size_t curPos; + size_t endPos; + int srcWasFinished; +} CSeqInFilter; + + +static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Enc[] = +{ + Z7_BRANCH_CONV_ENC(PPC), + Z7_BRANCH_CONV_ENC(IA64), + Z7_BRANCH_CONV_ENC(ARM), + Z7_BRANCH_CONV_ENC(ARMT), + Z7_BRANCH_CONV_ENC(SPARC), + Z7_BRANCH_CONV_ENC(ARM64) +}; + +static SizeT XzBcFilterStateBase_Filter_Enc(CXzBcFilterStateBase *p, Byte *data, SizeT size) +{ + switch (p->methodId) + { + case XZ_ID_Delta: + Delta_Encode(p->delta_State, p->delta, data, size); + break; + case XZ_ID_X86: + size = (SizeT)(z7_BranchConvSt_X86_Enc(data, size, p->ip, &p->X86_State) - data); + break; + default: + if (p->methodId >= XZ_ID_PPC) + { + const UInt32 i = p->methodId - XZ_ID_PPC; + if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Enc)) + size = (SizeT)(g_Funcs_BranchConv_RISC_Enc[i](data, size, p->ip) - data); + } + break; + } + p->ip += (UInt32)size; + return size; +} + + +static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc) +{ + if (!p->buf) + { + p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE); + if (!p->buf) + return SZ_ERROR_MEM; + } + p->curPos = p->endPos = 0; + p->srcWasFinished = 0; + RINOK(Xz_StateCoder_Bc_SetFromMethod_Func(&p->StateCoder, props->id, XzBcFilterStateBase_Filter_Enc, alloc)) + RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc)) + p->StateCoder.Init(p->StateCoder.p); + return SZ_OK; +} + + +static SRes SeqInFilter_Read(ISeqInStreamPtr pp, void *data, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInFilter) + const size_t sizeOriginal = *size; + if (sizeOriginal == 0) + return SZ_OK; + *size = 0; + + for (;;) + { + if (!p->srcWasFinished && p->curPos == p->endPos) + { + p->curPos = 0; + p->endPos = FILTER_BUF_SIZE; + RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos)) + if (p->endPos == 0) + p->srcWasFinished = 1; + } + { + SizeT srcLen = p->endPos - p->curPos; + ECoderStatus status; + SRes res; + *size = sizeOriginal; + res = p->StateCoder.Code2(p->StateCoder.p, + (Byte *)data, size, + p->buf + p->curPos, &srcLen, + p->srcWasFinished, CODER_FINISH_ANY, + &status); + p->curPos += srcLen; + if (*size != 0 || srcLen == 0 || res != SZ_OK) + return res; + } + } +} + +static void SeqInFilter_Construct(CSeqInFilter *p) +{ + p->buf = NULL; + p->StateCoder.p = NULL; + p->vt.Read = SeqInFilter_Read; +} + +static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) +{ + if (p->StateCoder.p) + { + p->StateCoder.Free(p->StateCoder.p, alloc); + p->StateCoder.p = NULL; + } + if (p->buf) + { + ISzAlloc_Free(alloc, p->buf); + p->buf = NULL; + } +} + + +/* ---------- CSbEncInStream ---------- */ + +#ifdef USE_SUBBLOCK + +typedef struct +{ + ISeqInStream vt; + ISeqInStreamPtr inStream; + CSbEnc enc; +} CSbEncInStream; + +static SRes SbEncInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) +{ + CSbEncInStream *p = Z7_CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt); + size_t sizeOriginal = *size; + if (sizeOriginal == 0) + return SZ_OK; + + for (;;) + { + if (p->enc.needRead && !p->enc.readWasFinished) + { + size_t processed = p->enc.needReadSizeMax; + RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)) + p->enc.readPos += processed; + if (processed == 0) + { + p->enc.readWasFinished = True; + p->enc.isFinalFinished = True; + } + p->enc.needRead = False; + } + + *size = sizeOriginal; + RINOK(SbEnc_Read(&p->enc, data, size)) + if (*size != 0 || !p->enc.needRead) + return SZ_OK; + } +} + +void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc) +{ + SbEnc_Construct(&p->enc, alloc); + p->vt.Read = SbEncInStream_Read; +} + +SRes SbEncInStream_Init(CSbEncInStream *p) +{ + return SbEnc_Init(&p->enc); +} + +void SbEncInStream_Free(CSbEncInStream *p) +{ + SbEnc_Free(&p->enc); +} + +#endif + + + +/* ---------- CXzProps ---------- */ + + +void XzFilterProps_Init(CXzFilterProps *p) +{ + p->id = 0; + p->delta = 0; + p->ip = 0; + p->ipDefined = False; +} + +void XzProps_Init(CXzProps *p) +{ + p->checkId = XZ_CHECK_CRC32; + p->blockSize = XZ_PROPS_BLOCK_SIZE_AUTO; + p->numBlockThreads_Reduced = -1; + p->numBlockThreads_Max = -1; + p->numTotalThreads = -1; + p->reduceSize = (UInt64)(Int64)-1; + p->forceWriteSizesInHeader = 0; + // p->forceWriteSizesInHeader = 1; + + XzFilterProps_Init(&p->filterProps); + Lzma2EncProps_Init(&p->lzma2Props); +} + + +static void XzEncProps_Normalize_Fixed(CXzProps *p) +{ + UInt64 fileSize; + int t1, t1n, t2, t2r, t3; + { + CLzma2EncProps tp = p->lzma2Props; + if (tp.numTotalThreads <= 0) + tp.numTotalThreads = p->numTotalThreads; + Lzma2EncProps_Normalize(&tp); + t1n = tp.numTotalThreads; + } + + t1 = p->lzma2Props.numTotalThreads; + t2 = p->numBlockThreads_Max; + t3 = p->numTotalThreads; + + if (t2 > MTCODER_THREADS_MAX) + t2 = MTCODER_THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > MTCODER_THREADS_MAX) + t2 = MTCODER_THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzma2Props.numTotalThreads = t1; + + t2r = t2; + + fileSize = p->reduceSize; + + if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) + p->lzma2Props.lzmaProps.reduceSize = p->blockSize; + + Lzma2EncProps_Normalize(&p->lzma2Props); + + t1 = p->lzma2Props.numTotalThreads; + + { + if (t2 > 1 && fileSize != (UInt64)(Int64)-1) + { + UInt64 numBlocks = fileSize / p->blockSize; + if (numBlocks * p->blockSize != fileSize) + numBlocks++; + if (numBlocks < (unsigned)t2) + { + t2r = (int)numBlocks; + if (t2r == 0) + t2r = 1; + t3 = t1 * t2r; + } + } + } + + p->numBlockThreads_Max = t2; + p->numBlockThreads_Reduced = t2r; + p->numTotalThreads = t3; +} + + +static void XzProps_Normalize(CXzProps *p) +{ + /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties. + Lzma2Enc_SetProps() will normalize lzma2Props later. */ + + if (p->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID) + { + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + p->numBlockThreads_Reduced = 1; + p->numBlockThreads_Max = 1; + if (p->lzma2Props.numTotalThreads <= 0) + p->lzma2Props.numTotalThreads = p->numTotalThreads; + return; + } + else + { + CLzma2EncProps *lzma2 = &p->lzma2Props; + if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) + { + // xz-auto + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + + if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) + { + // if (xz-auto && lzma2-solid) - we use solid for both + p->blockSize = XZ_PROPS_BLOCK_SIZE_SOLID; + p->numBlockThreads_Reduced = 1; + p->numBlockThreads_Max = 1; + if (p->lzma2Props.numTotalThreads <= 0) + p->lzma2Props.numTotalThreads = p->numTotalThreads; + } + else + { + // if (xz-auto && (lzma2-auto || lzma2-fixed_) + // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block + CLzma2EncProps tp = p->lzma2Props; + if (tp.numTotalThreads <= 0) + tp.numTotalThreads = p->numTotalThreads; + + Lzma2EncProps_Normalize(&tp); + + p->blockSize = tp.blockSize; // fixed or solid + p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced; + p->numBlockThreads_Max = tp.numBlockThreads_Max; + if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) + lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) + lzma2->lzmaProps.reduceSize = tp.blockSize; + lzma2->numBlockThreads_Reduced = 1; + lzma2->numBlockThreads_Max = 1; + return; + } + } + else + { + // xz-fixed + // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize + + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + { + UInt64 r = p->reduceSize; + if (r > p->blockSize || r == (UInt64)(Int64)-1) + r = p->blockSize; + lzma2->lzmaProps.reduceSize = r; + } + if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) + lzma2->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID; + else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) + lzma2->blockSize = p->blockSize; + + XzEncProps_Normalize_Fixed(p); + } + } +} + + +/* ---------- CLzma2WithFilters ---------- */ + +typedef struct +{ + CLzma2EncHandle lzma2; + CSeqInFilter filter; + + #ifdef USE_SUBBLOCK + CSbEncInStream sb; + #endif +} CLzma2WithFilters; + + +static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) +{ + p->lzma2 = NULL; + SeqInFilter_Construct(&p->filter); + + #ifdef USE_SUBBLOCK + SbEncInStream_Construct(&p->sb, alloc); + #endif +} + + +static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc) +{ + if (!p->lzma2) + { + p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc); + if (!p->lzma2) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + + +static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) +{ + #ifdef USE_SUBBLOCK + SbEncInStream_Free(&p->sb); + #endif + + SeqInFilter_Free(&p->filter, alloc); + if (p->lzma2) + { + Lzma2Enc_Destroy(p->lzma2); + p->lzma2 = NULL; + } +} + + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; + size_t headerSize; +} CXzEncBlockInfo; + + +static SRes Xz_CompressBlock( + CLzma2WithFilters *lzmaf, + + ISeqOutStreamPtr outStream, + Byte *outBufHeader, + Byte *outBufData, size_t outBufDataLimit, + + ISeqInStreamPtr inStream, + // UInt64 expectedSize, + const Byte *inBuf, // used if (!inStream) + size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored + + const CXzProps *props, + ICompressProgressPtr progress, + int *inStreamFinished, /* only for inStream version */ + CXzEncBlockInfo *blockSizes, + ISzAllocPtr alloc, + ISzAllocPtr allocBig) +{ + CSeqCheckInStream checkInStream; + CSeqSizeOutStream seqSizeOutStream; + CXzBlock block; + unsigned filterIndex = 0; + CXzFilter *filter = NULL; + const CXzFilterProps *fp = &props->filterProps; + if (fp->id == 0) + fp = NULL; + + *inStreamFinished = False; + + RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig)) + + RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props)) + + // XzBlock_ClearFlags(&block) + XzBlock_ClearFlags_SetNumFilters(&block, 1 + (fp ? 1 : 0)) + + if (fp) + { + filter = &block.filters[filterIndex++]; + filter->id = fp->id; + filter->propsSize = 0; + + if (fp->id == XZ_ID_Delta) + { + filter->props[0] = (Byte)(fp->delta - 1); + filter->propsSize = 1; + } + else if (fp->ipDefined) + { + Byte *ptr = filter->props; + SetUi32(ptr, fp->ip) + filter->propsSize = 4; + } + } + + { + CXzFilter *f = &block.filters[filterIndex++]; + f->id = XZ_ID_LZMA2; + f->propsSize = 1; + f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); + } + + seqSizeOutStream.vt.Write = SeqSizeOutStream_Write; + seqSizeOutStream.realStream = outStream; + seqSizeOutStream.outBuf = outBufData; + seqSizeOutStream.outBufLimit = outBufDataLimit; + seqSizeOutStream.processed = 0; + + /* + if (expectedSize != (UInt64)(Int64)-1) + { + block.unpackSize = expectedSize; + if (props->blockSize != (UInt64)(Int64)-1) + if (expectedSize > props->blockSize) + block.unpackSize = props->blockSize; + XzBlock_SetHasUnpackSize(&block) + } + */ + + if (outStream) + { + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)) + } + + checkInStream.vt.Read = SeqCheckInStream_Read; + SeqCheckInStream_Init(&checkInStream, props->checkId); + + checkInStream.realStream = inStream; + checkInStream.data = inBuf; + checkInStream.limit = props->blockSize; + if (!inStream) + checkInStream.limit = inBufSize; + + if (fp) + { + #ifdef USE_SUBBLOCK + if (fp->id == XZ_ID_Subblock) + { + lzmaf->sb.inStream = &checkInStream.vt; + RINOK(SbEncInStream_Init(&lzmaf->sb)) + } + else + #endif + { + lzmaf->filter.realStream = &checkInStream.vt; + RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc)) + } + } + + { + SRes res; + Byte *outBuf = NULL; + size_t outSize = 0; + BoolInt useStream = (fp || inStream); + // useStream = True; + + if (!useStream) + { + XzCheck_Update(&checkInStream.check, inBuf, inBufSize); + checkInStream.processed = inBufSize; + } + + if (!outStream) + { + outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed; + outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed; + } + + res = Lzma2Enc_Encode2(lzmaf->lzma2, + outBuf ? NULL : &seqSizeOutStream.vt, + outBuf, + outBuf ? &outSize : NULL, + + useStream ? + (fp ? + ( + #ifdef USE_SUBBLOCK + (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt: + #endif + &lzmaf->filter.vt) : + &checkInStream.vt) : NULL, + + useStream ? NULL : inBuf, + useStream ? 0 : inBufSize, + + progress); + + if (outBuf) + seqSizeOutStream.processed += outSize; + + RINOK(res) + blockSizes->unpackSize = checkInStream.processed; + } + { + Byte buf[4 + 64]; + unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed); + UInt64 packSize = seqSizeOutStream.processed; + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + SeqCheckInStream_GetDigest(&checkInStream, buf + 4); + RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId))) + + blockSizes->totalSize = seqSizeOutStream.processed - padSize; + + if (!outStream) + { + seqSizeOutStream.outBuf = outBufHeader; + seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX; + seqSizeOutStream.processed = 0; + + block.unpackSize = blockSizes->unpackSize; + XzBlock_SetHasUnpackSize(&block) + + block.packSize = packSize; + XzBlock_SetHasPackSize(&block) + + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)) + + blockSizes->headerSize = (size_t)seqSizeOutStream.processed; + blockSizes->totalSize += seqSizeOutStream.processed; + } + } + + if (inStream) + *inStreamFinished = checkInStream.realStreamFinished; + else + { + *inStreamFinished = False; + if (checkInStream.processed != inBufSize) + return SZ_ERROR_FAIL; + } + + return SZ_OK; +} + + + +typedef struct +{ + ICompressProgress vt; + ICompressProgressPtr progress; + UInt64 inOffset; + UInt64 outOffset; +} CCompressProgress_XzEncOffset; + + +static SRes CompressProgress_XzEncOffset_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) +{ + const CCompressProgress_XzEncOffset *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CCompressProgress_XzEncOffset, vt); + inSize += p->inOffset; + outSize += p->outOffset; + return ICompressProgress_Progress(p->progress, inSize, outSize); +} + + + + +struct CXzEnc +{ + ISzAllocPtr alloc; + ISzAllocPtr allocBig; + + CXzProps xzProps; + UInt64 expectedDataSize; + + CXzEncIndex xzIndex; + + CLzma2WithFilters lzmaf_Items[MTCODER_THREADS_MAX]; + + size_t outBufSize; /* size of allocated outBufs[i] */ + Byte *outBufs[MTCODER_BLOCKS_MAX]; + + #ifndef Z7_ST + unsigned checkType; + ISeqOutStreamPtr outStream; + BoolInt mtCoder_WasConstructed; + CMtCoder mtCoder; + CXzEncBlockInfo EncBlocks[MTCODER_BLOCKS_MAX]; + #endif +}; + + +static void XzEnc_Construct(CXzEnc *p) +{ + unsigned i; + + XzEncIndex_Construct(&p->xzIndex); + + for (i = 0; i < MTCODER_THREADS_MAX; i++) + Lzma2WithFilters_Construct(&p->lzmaf_Items[i]); + + #ifndef Z7_ST + p->mtCoder_WasConstructed = False; + { + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + p->outBufs[i] = NULL; + p->outBufSize = 0; + } + #endif +} + + +static void XzEnc_FreeOutBufs(CXzEnc *p) +{ + unsigned i; + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + if (p->outBufs[i]) + { + ISzAlloc_Free(p->alloc, p->outBufs[i]); + p->outBufs[i] = NULL; + } + p->outBufSize = 0; +} + + +static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc) +{ + unsigned i; + + XzEncIndex_Free(&p->xzIndex, alloc); + + for (i = 0; i < MTCODER_THREADS_MAX; i++) + Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc); + + #ifndef Z7_ST + if (p->mtCoder_WasConstructed) + { + MtCoder_Destruct(&p->mtCoder); + p->mtCoder_WasConstructed = False; + } + XzEnc_FreeOutBufs(p); + #endif +} + + +CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc)); + if (!p) + return NULL; + XzEnc_Construct(p); + XzProps_Init(&p->xzProps); + XzProps_Normalize(&p->xzProps); + p->expectedDataSize = (UInt64)(Int64)-1; + p->alloc = alloc; + p->allocBig = allocBig; + return (CXzEncHandle)p; +} + +// #define GET_CXzEnc_p CXzEnc *p = (CXzEnc *)(void *)pp; + +void XzEnc_Destroy(CXzEncHandle p) +{ + // GET_CXzEnc_p + XzEnc_Free(p, p->alloc); + ISzAlloc_Free(p->alloc, p); +} + + +SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props) +{ + // GET_CXzEnc_p + p->xzProps = *props; + XzProps_Normalize(&p->xzProps); + return SZ_OK; +} + + +void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize) +{ + // GET_CXzEnc_p + p->expectedDataSize = expectedDataSiize; +} + + + + +#ifndef Z7_ST + +static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished) +{ + CXzEnc *me = (CXzEnc *)pp; + SRes res; + CMtProgressThunk progressThunk; + + Byte *dest = me->outBufs[outBufIndex]; + + UNUSED_VAR(finished) + + { + CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; + bInfo->totalSize = 0; + bInfo->unpackSize = 0; + bInfo->headerSize = 0; + } + + if (!dest) + { + dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); + if (!dest) + return SZ_ERROR_MEM; + me->outBufs[outBufIndex] = dest; + } + + MtProgressThunk_CreateVTable(&progressThunk); + progressThunk.mtProgress = &me->mtCoder.mtProgress; + MtProgressThunk_INIT(&progressThunk) + + { + CXzEncBlockInfo blockSizes; + int inStreamFinished; + + res = Xz_CompressBlock( + &me->lzmaf_Items[coderIndex], + + NULL, + dest, + dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX, + + NULL, + // srcSize, // expectedSize + src, srcSize, + + &me->xzProps, + &progressThunk.vt, + &inStreamFinished, + &blockSizes, + me->alloc, + me->allocBig); + + if (res == SZ_OK) + me->EncBlocks[outBufIndex] = blockSizes; + + return res; + } +} + + +static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex) +{ + CXzEnc *me = (CXzEnc *)pp; + + const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; + const Byte *data = me->outBufs[outBufIndex]; + + RINOK(WriteBytes(me->outStream, data, bInfo->headerSize)) + + { + UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize); + RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize)) + } + + return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc); +} + +#endif + + + +SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress) +{ + // GET_CXzEnc_p + + const CXzProps *props = &p->xzProps; + + XzEncIndex_Init(&p->xzIndex); + { + UInt64 numBlocks = 1; + UInt64 blockSize = props->blockSize; + + if (blockSize != XZ_PROPS_BLOCK_SIZE_SOLID + && props->reduceSize != (UInt64)(Int64)-1) + { + numBlocks = props->reduceSize / blockSize; + if (numBlocks * blockSize != props->reduceSize) + numBlocks++; + } + else + blockSize = (UInt64)1 << 62; + + RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc)) + } + + RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream)) + + + #ifndef Z7_ST + if (props->numBlockThreads_Reduced > 1) + { + IMtCoderCallback2 vt; + + if (!p->mtCoder_WasConstructed) + { + p->mtCoder_WasConstructed = True; + MtCoder_Construct(&p->mtCoder); + } + + vt.Code = XzEnc_MtCallback_Code; + vt.Write = XzEnc_MtCallback_Write; + + p->checkType = props->checkId; + p->xzProps = *props; + + p->outStream = outStream; + + p->mtCoder.allocBig = p->allocBig; + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.inData = NULL; + p->mtCoder.inDataSize = 0; + p->mtCoder.mtCallback = &vt; + p->mtCoder.mtCallbackObject = p; + + if ( props->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID + || props->blockSize == XZ_PROPS_BLOCK_SIZE_AUTO) + return SZ_ERROR_FAIL; + + p->mtCoder.blockSize = (size_t)props->blockSize; + if (p->mtCoder.blockSize != props->blockSize) + return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ + + { + size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize); + if (destBlockSize < p->mtCoder.blockSize) + return SZ_ERROR_PARAM; + if (p->outBufSize != destBlockSize) + XzEnc_FreeOutBufs(p); + p->outBufSize = destBlockSize; + } + + p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max; + p->mtCoder.expectedDataSize = p->expectedDataSize; + + RINOK(MtCoder_Code(&p->mtCoder)) + } + else + #endif + { + int writeStartSizes; + CCompressProgress_XzEncOffset progress2; + Byte *bufData = NULL; + size_t bufSize = 0; + + progress2.vt.Progress = CompressProgress_XzEncOffset_Progress; + progress2.inOffset = 0; + progress2.outOffset = 0; + progress2.progress = progress; + + writeStartSizes = 0; + + if (props->blockSize != XZ_PROPS_BLOCK_SIZE_SOLID) + { + writeStartSizes = (props->forceWriteSizesInHeader > 0); + + if (writeStartSizes) + { + size_t t2; + size_t t = (size_t)props->blockSize; + if (t != props->blockSize) + return SZ_ERROR_PARAM; + t = XZ_GET_MAX_BLOCK_PACK_SIZE(t); + if (t < props->blockSize) + return SZ_ERROR_PARAM; + t2 = XZ_BLOCK_HEADER_SIZE_MAX + t; + if (!p->outBufs[0] || t2 != p->outBufSize) + { + XzEnc_FreeOutBufs(p); + p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2); + if (!p->outBufs[0]) + return SZ_ERROR_MEM; + p->outBufSize = t2; + } + bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX; + bufSize = t; + } + } + + for (;;) + { + CXzEncBlockInfo blockSizes; + int inStreamFinished; + + /* + UInt64 rem = (UInt64)(Int64)-1; + if (props->reduceSize != (UInt64)(Int64)-1 + && props->reduceSize >= progress2.inOffset) + rem = props->reduceSize - progress2.inOffset; + */ + + blockSizes.headerSize = 0; // for GCC + + RINOK(Xz_CompressBlock( + &p->lzmaf_Items[0], + + writeStartSizes ? NULL : outStream, + writeStartSizes ? p->outBufs[0] : NULL, + bufData, bufSize, + + inStream, + // rem, + NULL, 0, + + props, + progress ? &progress2.vt : NULL, + &inStreamFinished, + &blockSizes, + p->alloc, + p->allocBig)) + + { + UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize); + + if (writeStartSizes) + { + RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize)) + RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize)) + } + + RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc)) + + progress2.inOffset += blockSizes.unpackSize; + progress2.outOffset += totalPackFull; + } + + if (inStreamFinished) + break; + } + } + + return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream); +} + + +#include "Alloc.h" + +SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, + const CXzProps *props, ICompressProgressPtr progress) +{ + SRes res; + CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc); + if (!xz) + return SZ_ERROR_MEM; + res = XzEnc_SetProps(xz, props); + if (res == SZ_OK) + res = XzEnc_Encode(xz, outStream, inStream, progress); + XzEnc_Destroy(xz); + return res; +} + + +SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream) +{ + SRes res; + CXzEncIndex xzIndex; + XzEncIndex_Construct(&xzIndex); + res = Xz_WriteHeader((CXzStreamFlags)0, outStream); + if (res == SZ_OK) + res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream); + XzEncIndex_Free(&xzIndex, NULL); // g_Alloc + return res; +} diff --git a/libraries/lzma/C/XzEnc.h b/libraries/lzma/C/XzEnc.h new file mode 100644 index 00000000000..77b78c014be --- /dev/null +++ b/libraries/lzma/C/XzEnc.h @@ -0,0 +1,61 @@ +/* XzEnc.h -- Xz Encode +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_XZ_ENC_H +#define ZIP7_INC_XZ_ENC_H + +#include "Lzma2Enc.h" + +#include "Xz.h" + +EXTERN_C_BEGIN + + +#define XZ_PROPS_BLOCK_SIZE_AUTO LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO +#define XZ_PROPS_BLOCK_SIZE_SOLID LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + + +typedef struct +{ + UInt32 id; + UInt32 delta; + UInt32 ip; + int ipDefined; +} CXzFilterProps; + +void XzFilterProps_Init(CXzFilterProps *p); + + +typedef struct +{ + CLzma2EncProps lzma2Props; + CXzFilterProps filterProps; + unsigned checkId; + UInt64 blockSize; + int numBlockThreads_Reduced; + int numBlockThreads_Max; + int numTotalThreads; + int forceWriteSizesInHeader; + UInt64 reduceSize; +} CXzProps; + +void XzProps_Init(CXzProps *p); + +typedef struct CXzEnc CXzEnc; +typedef CXzEnc * CXzEncHandle; +// Z7_DECLARE_HANDLE(CXzEncHandle) + +CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); +void XzEnc_Destroy(CXzEncHandle p); +SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props); +void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize); +SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress); + +SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, + const CXzProps *props, ICompressProgressPtr progress); + +SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream); + +EXTERN_C_END + +#endif diff --git a/libraries/lzma/C/XzIn.c b/libraries/lzma/C/XzIn.c new file mode 100644 index 00000000000..d0fc763679e --- /dev/null +++ b/libraries/lzma/C/XzIn.c @@ -0,0 +1,340 @@ +/* XzIn.c - Xz input +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" + +/* +#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0) +*/ +#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1) + + +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream) +{ + Byte sig[XZ_STREAM_HEADER_SIZE]; + size_t processedSize = XZ_STREAM_HEADER_SIZE; + RINOK(SeqInStream_ReadMax(inStream, sig, &processedSize)) + if (processedSize != XZ_STREAM_HEADER_SIZE + || memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) + return SZ_ERROR_NO_ARCHIVE; + return Xz_ParseHeader(p, sig); +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; \ + pos += s; } + +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + unsigned headerSize; + *headerSizeRes = 0; + RINOK(SeqInStream_ReadByte(inStream, &header[0])) + headerSize = (unsigned)header[0]; + if (headerSize == 0) + { + *headerSizeRes = 1; + *isIndex = True; + return SZ_OK; + } + + *isIndex = False; + headerSize = (headerSize << 2) + 4; + *headerSizeRes = headerSize; + { + size_t processedSize = headerSize - 1; + RINOK(SeqInStream_ReadMax(inStream, header + 1, &processedSize)) + if (processedSize != headerSize - 1) + return SZ_ERROR_INPUT_EOF; + } + return XzBlock_Parse(p, header); +} + +#define ADD_SIZE_CHECK(size, val) \ + { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } + +UInt64 Xz_GetUnpackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + { + ADD_SIZE_CHECK(size, p->blocks[i].unpackSize) + } + return size; +} + +UInt64 Xz_GetPackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + { + ADD_SIZE_CHECK(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3) + } + return size; +} + +/* +SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStreamPtr inStream) +{ + return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); +} +*/ + +static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) +{ + size_t numBlocks, pos = 1; + UInt32 crc; + + if (size < 5 || buf[0] != 0) + return SZ_ERROR_ARCHIVE; + + size -= 4; + crc = CrcCalc(buf, size); + if (crc != GetUi32(buf + size)) + return SZ_ERROR_ARCHIVE; + + { + UInt64 numBlocks64; + READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64) + numBlocks = (size_t)numBlocks64; + if (numBlocks != numBlocks64 || numBlocks * 2 > size) + return SZ_ERROR_ARCHIVE; + } + + Xz_Free(p, alloc); + if (numBlocks != 0) + { + size_t i; + p->numBlocks = numBlocks; + p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); + if (!p->blocks) + return SZ_ERROR_MEM; + for (i = 0; i < numBlocks; i++) + { + CXzBlockSizes *block = &p->blocks[i]; + READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize) + READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize) + if (block->totalSize == 0) + return SZ_ERROR_ARCHIVE; + } + } + while ((pos & 3) != 0) + if (buf[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc) +{ + SRes res; + size_t size; + Byte *buf; + if (indexSize > ((UInt32)1 << 31)) + return SZ_ERROR_UNSUPPORTED; + size = (size_t)indexSize; + if (size != indexSize) + return SZ_ERROR_UNSUPPORTED; + buf = (Byte *)ISzAlloc_Alloc(alloc, size); + if (!buf) + return SZ_ERROR_MEM; + res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); + if (res == SZ_OK) + res = Xz_ReadIndex2(p, buf, size, alloc); + ISzAlloc_Free(alloc, buf); + return res; +} + +static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size) +{ + RINOK(LookInStream_SeekTo(stream, offset)) + return LookInStream_Read(stream, buf, size); + /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ +} + +static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc) +{ + UInt64 indexSize; + Byte buf[XZ_STREAM_FOOTER_SIZE]; + UInt64 pos = (UInt64)*startOffset; + + if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) + + if (!XZ_FOOTER_SIG_CHECK(buf + 10)) + { + UInt32 total = 0; + pos += XZ_STREAM_FOOTER_SIZE; + + for (;;) + { + size_t i; + #define TEMP_BUF_SIZE (1 << 10) + Byte temp[TEMP_BUF_SIZE]; + + i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos; + pos -= i; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)) + total += (UInt32)i; + for (; i != 0; i--) + if (temp[i - 1] != 0) + break; + if (i != 0) + { + if ((i & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + pos += i; + break; + } + if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) + return SZ_ERROR_NO_ARCHIVE; + } + + if (pos < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) + if (!XZ_FOOTER_SIG_CHECK(buf + 10)) + return SZ_ERROR_NO_ARCHIVE; + } + + p->flags = (CXzStreamFlags)GetBe16(buf + 8); + + if (!XzFlags_IsSupported(p->flags)) + return SZ_ERROR_UNSUPPORTED; + + { + /* to eliminate GCC 6.3 warning: + dereferencing type-punned pointer will break strict-aliasing rules */ + const Byte *buf_ptr = buf; + if (GetUi32(buf_ptr) != CrcCalc(buf + 4, 6)) + return SZ_ERROR_ARCHIVE; + } + + indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; + + if (pos < indexSize) + return SZ_ERROR_ARCHIVE; + + pos -= indexSize; + RINOK(LookInStream_SeekTo(stream, pos)) + RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)) + + { + UInt64 totalSize = Xz_GetPackSize(p); + if (totalSize == XZ_SIZE_OVERFLOW + || totalSize >= ((UInt64)1 << 63) + || pos < totalSize + XZ_STREAM_HEADER_SIZE) + return SZ_ERROR_ARCHIVE; + pos -= (totalSize + XZ_STREAM_HEADER_SIZE); + RINOK(LookInStream_SeekTo(stream, pos)) + *startOffset = (Int64)pos; + } + { + CXzStreamFlags headerFlags; + CSecToRead secToRead; + SecToRead_CreateVTable(&secToRead); + secToRead.realStream = stream; + + RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)) + return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; + } +} + + +/* ---------- Xz Streams ---------- */ + +void Xzs_Construct(CXzs *p) +{ + p->num = p->numAllocated = 0; + p->streams = 0; +} + +void Xzs_Free(CXzs *p, ISzAllocPtr alloc) +{ + size_t i; + for (i = 0; i < p->num; i++) + Xz_Free(&p->streams[i], alloc); + ISzAlloc_Free(alloc, p->streams); + p->num = p->numAllocated = 0; + p->streams = 0; +} + +UInt64 Xzs_GetNumBlocks(const CXzs *p) +{ + UInt64 num = 0; + size_t i; + for (i = 0; i < p->num; i++) + num += p->streams[i].numBlocks; + return num; +} + +UInt64 Xzs_GetUnpackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + { + ADD_SIZE_CHECK(size, Xz_GetUnpackSize(&p->streams[i])) + } + return size; +} + +/* +UInt64 Xzs_GetPackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + { + ADD_SIZE_CHECK(size, Xz_GetTotalSize(&p->streams[i])) + } + return size; +} +*/ + +SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc) +{ + Int64 endOffset = 0; + RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)) + *startOffset = endOffset; + for (;;) + { + CXzStream st; + SRes res; + Xz_Construct(&st); + res = Xz_ReadBackward(&st, stream, startOffset, alloc); + st.startOffset = (UInt64)*startOffset; + RINOK(res) + if (p->num == p->numAllocated) + { + const size_t newNum = p->num + p->num / 4 + 1; + void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); + if (!data) + return SZ_ERROR_MEM; + p->numAllocated = newNum; + if (p->num != 0) + memcpy(data, p->streams, p->num * sizeof(CXzStream)); + ISzAlloc_Free(alloc, p->streams); + p->streams = (CXzStream *)data; + } + p->streams[p->num++] = st; + if (*startOffset == 0) + break; + RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset)) + if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK) + return SZ_ERROR_PROGRESS; + } + return SZ_OK; +} diff --git a/libraries/lzma/CMakeLists.txt b/libraries/lzma/CMakeLists.txt index b0d7565cd15..e1c668b2969 100644 --- a/libraries/lzma/CMakeLists.txt +++ b/libraries/lzma/CMakeLists.txt @@ -1,34 +1,51 @@ -cmake_minimum_required( VERSION 2.8.7 ) - make_release_only() -set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_7ZIP_PPMD_SUPPPORT" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DZ7_PPMD_SUPPORT" ) + +find_package(Threads) -set( LZMA_FILES +add_library( lzma STATIC + C/7zAlloc.c C/7zArcIn.c C/7zBuf.c + C/7zBuf2.c C/7zCrc.c C/7zCrcOpt.c C/7zDec.c + C/7zFile.c C/7zStream.c + C/Alloc.c C/Bcj2.c + C/Bcj2Enc.c C/Bra.c C/Bra86.c - C/BraIA64.c C/CpuArch.c C/Delta.c + C/DllSecur.c C/LzFind.c + C/LzFindMt.c + C/LzFindOpt.c C/Lzma2Dec.c + C/Lzma2DecMt.c + C/Lzma2Enc.c C/LzmaDec.c C/LzmaEnc.c + C/LzmaLib.c + C/MtCoder.c + C/MtDec.c C/Ppmd7.c - C/Ppmd7Dec.c ) - -if( WIN32 ) - set( LZMA_FILES ${LZMA_FILES} C/LzFindMt.c C/Threads.c ) -else() - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_7ZIP_ST" ) -endif() - -add_library( lzma STATIC ${LZMA_FILES} ) -target_link_libraries( lzma ) + C/Ppmd7Dec.c + C/Ppmd7Enc.c + C/Sha256.c + C/Sha256Opt.c + C/Sort.c + C/SwapBytes.c + C/Threads.c + C/Xz.c + C/XzCrc64.c + C/XzCrc64Opt.c + C/XzDec.c + C/XzEnc.c + C/XzIn.c +) +target_link_libraries( lzma Threads::Threads ) diff --git a/libraries/lzma/DOC/lzma-history.txt b/libraries/lzma/DOC/lzma-history.txt index 48ee74813dd..0963c7bf799 100644 --- a/libraries/lzma/DOC/lzma-history.txt +++ b/libraries/lzma/DOC/lzma-history.txt @@ -1,6 +1,80 @@ HISTORY of the LZMA SDK ----------------------- +21.07 2021-12-26 +------------------------- +- New switches: -spm and -im!{file_path} to exclude directories from processing + for specified paths that don't contain path separator character at the end of path. +- The sorting order of files in archives was slightly changed to be more consistent + for cases where the name of some directory is the same as the prefix part of the name + of another directory or file. + + +21.06 2021-11-24 +------------------------- +- Bug in LZMA encoder in file LzmaEnc.c was fixed: + LzmaEnc_MemEncode(), LzmaEncode() and LzmaCompress() could work incorrectly, + if size value for output buffer is smaller than size required for all compressed data. + LzmaEnc_Encode() could work incorrectly, + if callback ISeqOutStream::Write() doesn't write all compressed data. + NCompress::NLzma::CEncoder::Code() could work incorrectly, + if callback ISequentialOutStream::Write() returns error code. +- Bug in versions 21.00-21.05 was fixed: + 7-Zip didn't set attributes of directories during archive extracting. + + +21.04 beta 2021-11-02 +------------------------- +- 7-Zip now reduces the number of working CPU threads for compression, + if RAM size is not enough for compression with big LZMA2 dictionary. +- 7-Zip now can create and check "file.sha256" text files that contain the list + of file names and SHA-256 checksums in format compatible with sha256sum program. + + +21.03 beta 2021-07-20 +------------------------- +- The maximum dictionary size for LZMA/LZMA2 compressing was increased to 4 GB (3840 MiB). +- Minor speed optimizations in LZMA/LZMA2 compressing. + + +21.02 alpha 2021-05-06 +------------------------- +- The command line version of 7-Zip for macOS was released. +- The speed for LZMA and LZMA2 decompression in arm64 versions for macOS and Linux + was increased by 20%-60%. + + +21.01 alpha 2021-03-09 +------------------------- +- The command line version of 7-Zip for Linux was released. +- The improvements for speed of ARM64 version using hardware CPU instructions + for AES, CRC-32, SHA-1 and SHA-256. +- Some bugs were fixed. + + +20.02 alpha 2020-08-08 +------------------------- +- The default number of LZMA2 chunks per solid block in 7z archive was increased to 64. + It allows to increase the compression speed for big 7z archives, if there is a big number + of CPU cores and threads. +- The speed of PPMd compressing/decompressing was increased for 7z archives. +- The new -ssp switch. If the switch -ssp is specified, 7-Zip doesn't allow the system + to modify "Last Access Time" property of source files for archiving and hashing operations. +- Some bugs were fixed. + + +20.00 alpha 2020-02-06 +------------------------- +- 7-Zip now supports new optional match finders for LZMA/LZMA2 compression: bt5 and hc5, + that can work faster than bt4 and hc4 match finders for the data with big redundancy. +- The compression ratio was improved for Fast and Fastest compression levels with the + following default settings: + - Fastest level (-mx1) : hc5 match finder with 256 KB dictionary. + - Fast level (-mx3) : hc5 match finder with 4 MB dictionary. +- Minor speed optimizations in multithreaded LZMA/LZMA2 compression for Normal/Maximum/Ultra + compression levels. + + 19.00 2019-02-21 ------------------------- - Encryption strength for 7z archives was increased: diff --git a/libraries/lzma/DOC/lzma-sdk.txt b/libraries/lzma/DOC/lzma-sdk.txt index b0e14a2e295..9621c8d5db0 100644 --- a/libraries/lzma/DOC/lzma-sdk.txt +++ b/libraries/lzma/DOC/lzma-sdk.txt @@ -1,4 +1,4 @@ -LZMA SDK 19.00 +LZMA SDK 21.07 -------------- LZMA SDK provides the documentation, samples, header files, @@ -62,14 +62,61 @@ LZMA SDK Contents UNIX/Linux version ------------------ -To compile C++ version of file->file LZMA encoding, go to directory -CPP/7zip/Bundles/LzmaCon -and call make to recompile it: - make -f makefile.gcc clean all - -In some UNIX/Linux versions you must compile LZMA with static libraries. -To compile with static libraries, you can use -LIB = -lm -static +There are several otpions to compile 7-Zip with different compilers: gcc and clang. +Also 7-Zip code contains two versions for some critical parts of code: in C and in Assembeler. +So if you compile the version with Assembeler code, you will get faster 7-Zip binary. + +7-Zip's assembler code uses the following syntax for different platforms: + +1) x86 and x86-64 (AMD64): MASM syntax. + There are 2 programs that supports MASM syntax in Linux. +' 'Asmc Macro Assembler and JWasm. But JWasm now doesn't support some + cpu instructions used in 7-Zip. + So you must install Asmc Macro Assembler in Linux, if you want to compile fastest version + of 7-Zip x86 and x86-64: + https://github.com/nidud/asmc + +2) arm64: GNU assembler for ARM64 with preprocessor. + That systax of that arm64 assembler code in 7-Zip is supported by GCC and CLANG for ARM64. + +There are different binaries that can be compiled from 7-Zip source. +There are 2 main files in folder for compiling: + makefile - that can be used for compiling Windows version of 7-Zip with nmake command + makefile.gcc - that can be used for compiling Linux/macOS versions of 7-Zip with make command + +At first you must change the current folder to folder that contains `makefile.gcc`: + + cd CPP/7zip/Bundles/Alone7z + +Then you can compile `makefile.gcc` with the command: + + make -j -f makefile.gcc + +Also there are additional "*.mak" files in folder "CPP/7zip/" that can be used to compile +7-Zip binaries with optimized code and optimzing options. + +To compile with GCC without assembler: + cd CPP/7zip/Bundles/Alone7z + make -j -f ../../cmpl_gcc.mak + +To compile with CLANG without assembler: + make -j -f ../../cmpl_clang.mak + +To compile 7-Zip for x86-64 with asmc assembler: + make -j -f ../../cmpl_gcc_x64.mak + +To compile 7-Zip for arm64 with assembler: + make -j -f ../../cmpl_gcc_arm64.mak + +To compile 7-Zip for arm64 for macOS: + make -j -f ../../cmpl_mac_arm64.mak + +Also you can change some compiler options in the mak files: + cmpl_gcc.mak + var_gcc.mak + warn_gcc.mak + + Also you can use p7zip (port of 7-Zip for POSIX systems like Unix or Linux): diff --git a/libraries/miniz/CMakeLists.txt b/libraries/miniz/CMakeLists.txt new file mode 100644 index 00000000000..b5a5529f24a --- /dev/null +++ b/libraries/miniz/CMakeLists.txt @@ -0,0 +1,9 @@ +make_release_only() + +if (MSVC) + set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4244" ) +endif() + +add_library( miniz miniz.c ) +target_compile_definitions( miniz PRIVATE -DMINIZ_NO_STDIO ) +target_include_directories( miniz INTERFACE "$" ) \ No newline at end of file diff --git a/libraries/miniz/miniz.c b/libraries/miniz/miniz.c new file mode 100644 index 00000000000..8d0032f9e4f --- /dev/null +++ b/libraries/miniz/miniz.c @@ -0,0 +1,7833 @@ +#include "miniz.h" +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * 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. + * + **************************************************************************/ + + + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API's */ + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) + return MZ_ADLER32_INIT; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ +#if 0 + mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) + { + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) + return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) + { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; + } +#elif defined(USE_EXTERNAL_MZCRC) +/* If USE_EXTERNAL_CRC is defined, an external module will export the + * mz_crc32() symbol for us to use, e.g. an SSE-accelerated version. + * Depending on the impl, it may be necessary to ~ the input/output crc values. + */ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len); +#else +/* Faster, but larger CPU cache footprint. + */ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +{ + static const mz_uint32 s_crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, + 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, + 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, + 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, + 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, + 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, + 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, + 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, + 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, + 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, + 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, + 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, + 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, + 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, + 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, + 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, + 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, + 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, + 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, + 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, + 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, + 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, + 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; + const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; + + while (buf_len >= 4) + { + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; + pByte_buf += 4; + buf_len -= 4; + } + + while (buf_len) + { + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; + ++pByte_buf; + --buf_len; + } + + return ~crc32; +} +#endif + +void mz_free(void *p) +{ + MZ_FREE(p); +} + +MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) +{ + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address) +{ + (void)opaque, (void)address; + MZ_FREE(address); +} +MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) +{ + (void)opaque, (void)address, (void)items, (void)size; + return MZ_REALLOC(address, items * size); +} + +const char *mz_version(void) +{ + return MZ_VERSION; +} + +#ifndef MINIZ_NO_ZLIB_APIS + +#ifndef MINIZ_NO_DEFLATE_APIS + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) + return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) + return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) + return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; /* Can't make forward progress without some input. + */ + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +{ + (void)pStream; + /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((mz_uint64)(source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) + return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) +{ + return mz_deflateBound(NULL, source_len); +} + +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + +#ifndef MINIZ_NO_INFLATE_APIS + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflateReset(mz_streamp pStream) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + + pDecomp = (inflate_state *)pStream->state; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + /* pDecomp->m_window_bits = window_bits */; + + return MZ_OK; +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) + return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) + decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) + return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + /* flush != MZ_FINISH then we must assume there's more input. */ + if (flush != MZ_FINISH) + decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for (;;) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ + else if (flush == MZ_FINISH) + { + /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} +int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong *pSource_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((mz_uint64)(*pSource_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)*pSource_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + *pSource_len = *pSource_len - stream.avail_in; + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_uncompress2(pDest, pDest_len, pSource, &source_len); +} + +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + +const char *mz_error(int err) +{ + static struct + { + int m_err; + const char *m_pDesc; + } s_error_descs[] = + { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) + if (s_error_descs[i].m_err == err) + return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif /*MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + 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 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. + + For more information, please refer to +*/ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * 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. + * + **************************************************************************/ + + + +#ifndef MINIZ_NO_DEFLATE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Compression (independent from all decompression API's) */ + +/* Purposely making these tables static for faster init and thread safety. */ +static const mz_uint16 s_tdefl_len_sym[256] = + { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 + }; + +static const mz_uint8 s_tdefl_len_extra[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 + }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = + { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 + }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = + { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = + { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 + }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = + { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 + }; + +/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ +typedef struct +{ + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_ARR(hist); + for (i = 0; i < num_syms; i++) + { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) + { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) + { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) + { + if (leaf >= n || A[root].m_key < A[leaf].m_key) + { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) + { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) + { + while (root >= 0 && (int)A[root].m_key == dpth) + { + used++; + root--; + } + while (avbl > used) + { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +/* Limits canonical Huffman code table's max code size. */ +enum +{ + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 +}; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) + return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) + { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_ARR(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) + { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_ARR(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_ARR(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) + continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do \ + { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) \ + { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) \ + { \ + if (rle_repeat_count < 3) \ + { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } \ + else \ + { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) \ + { \ + if (rle_z_count < 3) \ + { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) \ + packed_code_sizes[num_packed_code_sizes++] = 0; \ + } \ + else if (rle_z_count <= 10) \ + { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } \ + else \ + { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static const mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) + break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) + break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0]; + mz_uint match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + memcpy(pOutput_buf, &bit_buffer, sizeof(mz_uint64)); + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static const mz_uint s_tdefl_num_probes[11]; + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + const mz_uint8 cmf = 0x78; + mz_uint8 flg, flevel = 3; + mz_uint header, i, mz_un = sizeof(s_tdefl_num_probes) / sizeof(mz_uint); + + /* Determine compression level by reversing the process in tdefl_create_comp_flags_from_zip_params() */ + for (i = 0; i < mz_un; i++) + if (s_tdefl_num_probes[i] == (d->m_flags & 0xFFF)) break; + + if (i < 2) + flevel = 0; + else if (i < 6) + flevel = 1; + else if (i == 6) + flevel = 2; + + header = cmf << 8 | (flevel << 6); + header += 31 - (header % 31); + flg = header & 0xFF; + + TDEFL_PUT_BITS(cmf, 8); + TDEFL_PUT_BITS(flg, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ + if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) + { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) + { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) + { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } + else + { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) + { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) +#endif +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) + continue; + p = s; + probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + if (!probe_len) + { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); + break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) + break; + if (probe_len > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) + return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p) +{ + mz_uint32 ret; + memcpy(&ret, p, sizeof(mz_uint32)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p) +#endif +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) + break; + + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_WORD32(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); +#ifdef MINIZ_UNALIGNED_USE_MEMCPY + memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist)); +#else + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; +#endif + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc ? pSrc + num_bytes_to_process : NULL; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + /* Simple lazy/greedy parsing state machine. */ + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) + { + if (d->m_dict[cur_pos + cur_match_len] != c) + break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + /* Move the lookahead forward by len_to_move bytes. */ + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + /* Check if it's time to flush the current LZ codes to the internal output buffer. */ + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) + { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) + { + MZ_CLEAR_ARR(d->m_hash); + MZ_CLEAR_ARR(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +{ + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_ARR(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + *d->m_pLZ_flags = 0; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_ARR(d->m_dict); + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +{ + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) + return MZ_FALSE; + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) + return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +{ + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) + return MZ_FALSE; + do + { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) + return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) + return MZ_FALSE; + else + *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) + return 0; + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return 0; + return out_buf.m_size; +} + +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) + comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ +#endif + +/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +{ + /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ + static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) + return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) + { + MZ_FREE(pComp); + return NULL; + } + /* write dummy header */ + for (z = 41; z; --z) + tdefl_output_buffer_putter(&z, 1, &out_buf); + /* compress image data */ + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) + { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) + { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + /* write real header */ + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; + mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, + 0x0a, 0x1a, 0x0a, 0x00, 0x00, + 0x00, 0x0d, 0x49, 0x48, 0x44, + 0x52, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x44, 0x41, + 0x54 }; + pnghdr[18] = (mz_uint8)(w >> 8); + pnghdr[19] = (mz_uint8)w; + pnghdr[22] = (mz_uint8)(h >> 8); + pnghdr[23] = (mz_uint8)h; + pnghdr[25] = chans[num_chans]; + pnghdr[33] = (mz_uint8)(*pLen_out >> 24); + pnghdr[34] = (mz_uint8)(*pLen_out >> 16); + pnghdr[35] = (mz_uint8)(*pLen_out >> 8); + pnghdr[36] = (mz_uint8)*pLen_out; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + /* write footer (IDAT CRC-32, followed by IEND chunk) */ + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) + { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + /* compute final size of file, grab compressed data buffer and return */ + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; +} +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +{ + /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +} + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ +/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +tdefl_compressor *tdefl_compressor_alloc(void) +{ + return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +} + +void tdefl_compressor_free(tdefl_compressor *pComp) +{ + MZ_FREE(pComp); +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + /************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * 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. + * + **************************************************************************/ + + + +#ifndef MINIZ_NO_INFLATE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Decompression (completely independent from all compression API's) */ + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) \ + { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do \ + { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do \ + { \ + for (;;) \ + { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +#define TINFL_GET_BYTE(state_index, c) \ + do \ + { \ + while (pIn_buf_cur >= pIn_buf_end) \ + { \ + TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ + } \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do \ + { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ +/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ +/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ +/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ +#define TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree) \ + do \ + { \ + temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) \ + { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } \ + else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) \ + break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ +/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ +/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ +/* The slow path is only executed at the very end of the input buffer. */ +/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ +/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ +#define TINFL_HUFF_DECODE(state_index, sym, pLookUp, pTree) \ + do \ + { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) \ + { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) \ + { \ + TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree); \ + } \ + else \ + { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +static void tinfl_clear_tree(tinfl_decompressor *r) +{ + if (r->m_type == 0) + MZ_CLEAR_ARR(r->m_tree_0); + else if (r->m_type == 1) + MZ_CLEAR_ARR(r->m_tree_1); + else + MZ_CLEAR_ARR(r->m_tree_2); +} + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; + static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; + static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; + static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; + + mz_int16 *pTrees[3]; + mz_uint8 *pCode_sizes[3]; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next ? pOut_buf_next + *pOut_buf_size : NULL; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) + { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + pTrees[0] = r->m_tree_0; + pTrees[1] = r->m_tree_1; + pTrees[2] = r->m_tree_2; + pCode_sizes[0] = r->m_code_size_0; + pCode_sizes[1] = r->m_code_size_1; + pCode_sizes[2] = r->m_code_size_2; + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)((size_t)1 << (8U + (r->m_zhdr0 >> 4))))); + if (counter) + { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) + { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) + { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) + { + TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_code_size_0; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_code_size_1, 5, 32); + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) + { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_ARR(r->m_code_size_2); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) + { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_code_size_2[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; + mz_int16 *pLookUp; + mz_int16 *pTree; + mz_uint8 *pCode_size; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; + pLookUp = r->m_look_up[r->m_type]; + pTree = pTrees[r->m_type]; + pCode_size = pCode_sizes[r->m_type]; + MZ_CLEAR_ARR(total_syms); + TINFL_MEMSET(pLookUp, 0, sizeof(r->m_look_up[0])); + tinfl_clear_tree(r); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pCode_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) + { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pCode_size[sym_index]; + if (!code_size) + continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) + { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) + { + pLookUp[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == (tree_cur = pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) + { + pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTree[-tree_cur - 1]) + { + pTree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + else + tree_cur = pTree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) + { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, r->m_look_up[2], r->m_tree_2); + if (dist < 16) + { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_code_size_0, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_code_size_1, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for (;;) + { + mz_uint8 *pSrc; + for (;;) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, r->m_look_up[0], r->m_tree_0); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) + break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, r->m_look_up[1], r->m_tree_1); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist == 0 || dist > dist_from_out_buf_start || dist_from_out_buf_start == 0) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { +#ifdef MINIZ_UNALIGNED_USE_MEMCPY + memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2); +#else + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; +#endif + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + while(counter>2) + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + counter -= 3; + } + if (counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + + /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ + TINFL_SKIP_BITS(32, num_bits & 7); + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + bit_buf &= ~(~(tinfl_bit_buf_t)0 << num_bits); + MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ + + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + for (counter = 0; counter < 4; ++counter) + { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + + TINFL_CR_FINISH + +common_exit: + /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ + /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ + if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) + { + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + } + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf & ~(~(tinfl_bit_buf_t)0 << num_bits); + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +/* Higher level helper functions. */ +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for (;;) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) + break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) + new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + memset(pDict,0,TINFL_LZ_DICT_SIZE); + tinfl_init(&decomp); + for (;;) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +#ifndef MINIZ_NO_MALLOC +tinfl_decompressor *tinfl_decompressor_alloc(void) +{ + tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); + if (pDecomp) + tinfl_init(pDecomp); + return pDecomp; +} + +void tinfl_decompressor_free(tinfl_decompressor *pDecomp) +{ + MZ_FREE(pDecomp); +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + /************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * Copyright 2016 Martin Raiber + * All Rights Reserved. + * + * 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. + * + **************************************************************************/ + + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- .ZIP archive reading */ + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include + +#if defined(_MSC_VER) || defined(__MINGW64__) + +#define WIN32_LEAN_AND_MEAN +#include + +static WCHAR* mz_utf8z_to_widechar(const char* str) +{ + int reqChars = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + WCHAR* wStr = (WCHAR*)malloc(reqChars * sizeof(WCHAR)); + MultiByteToWideChar(CP_UTF8, 0, str, -1, wStr, reqChars); + return wStr; +} + +static FILE *mz_fopen(const char *pFilename, const char *pMode) +{ + WCHAR* wFilename = mz_utf8z_to_widechar(pFilename); + WCHAR* wMode = mz_utf8z_to_widechar(pMode); + FILE* pFile = NULL; + errno_t err = _wfopen_s(&pFile, wFilename, wMode); + free(wFilename); + free(wMode); + return err ? NULL : pFile; +} + +static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) +{ + WCHAR* wPath = mz_utf8z_to_widechar(pPath); + WCHAR* wMode = mz_utf8z_to_widechar(pMode); + FILE* pFile = NULL; + errno_t err = _wfreopen_s(&pFile, wPath, wMode, pStream); + free(wPath); + free(wMode); + return err ? NULL : pFile; +} + +static int mz_stat64(const char *path, struct __stat64 *buffer) +{ + WCHAR* wPath = mz_utf8z_to_widechar(path); + int res = _wstat64(wPath, buffer); + free(wPath); + return res; +} + +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat64 +#define MZ_FILE_STAT mz_stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove + +#elif defined(__MINGW32__) || defined(__WATCOMC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove + +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove + +#elif defined(__USE_LARGEFILE64) /* gcc, clang */ +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove + +#elif defined(__APPLE__) || defined(__FreeBSD__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen(p, m, s) +#define MZ_DELETE_FILE remove + +#else +#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#ifdef __STRICT_ANSI__ +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#else +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#endif +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif /* #ifdef _MSC_VER */ +#endif /* #ifdef MINIZ_NO_STDIO */ + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ +enum +{ + /* ZIP archive identifiers and record sizes */ + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + + /* ZIP64 archive identifier and record sizes */ + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, + MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, + MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, + MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, + MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, + + /* Central directory header record offsets */ + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + + /* Local directory header offsets */ + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, + + /* End of central directory offsets */ + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + + /* ZIP64 End of central directory locator offsets */ + MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ + MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ + + /* ZIP64 End of central directory header offsets */ + MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ + MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, + MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 +}; + +typedef struct +{ + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag +{ + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + + /* The flags passed in when the archive is initially opened. */ + mz_uint32 m_init_flags; + + /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ + mz_bool m_zip64; + + /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ + mz_bool m_zip64_has_extended_info_fields; + + /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ + MZ_FILE *m_pFile; + mz_uint64 m_file_archive_start_ofs; + + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size + +#if defined(DEBUG) || defined(_DEBUG) +static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) +{ + MZ_ASSERT(index < pArray->m_size); + return index; +} +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] +#else +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +#endif + +static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) +{ + memset(pArray, 0, sizeof(mz_zip_array)); + pArray->m_element_size = element_size; +} + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +{ + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +{ + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) + return MZ_TRUE; + if (growing) + { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) + new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +{ + if (new_capacity > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) + return MZ_FALSE; + } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +{ + if (new_size > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) + return MZ_FALSE; + } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +{ + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +{ + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) + return MZ_FALSE; + if (n > 0) + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) + { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif /* #ifdef _MSC_VER */ + + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ + +#ifndef MINIZ_NO_STDIO +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) +{ + struct MZ_FILE_STAT_STRUCT file_stat; + + /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) + return MZ_FALSE; + + *pTime = file_stat.st_mtime; + + return MZ_TRUE; +} +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) +{ + struct utimbuf t; + + memset(&t, 0, sizeof(t)); + t.actime = access_time; + t.modtime = modified_time; + + return !utime(pFilename, &t); +} +#endif /* #ifndef MINIZ_NO_STDIO */ +#endif /* #ifndef MINIZ_NO_TIME */ + +static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) +{ + if (pZip) + pZip->m_last_error = err_num; + return MZ_FALSE; +} + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) +{ + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!pZip->m_pAlloc) + pZip->m_pAlloc = miniz_def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = miniz_def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = miniz_def_realloc_func; + + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + pZip->m_last_error = MZ_ZIP_NO_ERROR; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + pZip->m_pState->m_init_flags = flags; + pZip->m_pState->m_zip64 = MZ_FALSE; + pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) \ + do \ + { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END + +/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ +static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices; + mz_uint32 start, end; + const mz_uint32 size = pZip->m_total_files; + + if (size <= 1U) + return; + + pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + + start = (size - 2U) >> 1U; + for (;;) + { + mz_uint64 child, root = start; + for (;;) + { + if ((child = (root << 1U) + 1U) >= size) + break; + child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + if (!start) + break; + start--; + } + + end = size - 1; + while (end > 0) + { + mz_uint64 child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for (;;) + { + if ((child = (root << 1U) + 1U) >= end) + break; + child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) +{ + mz_int64 cur_file_ofs; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + + /* Basic sanity checks - reject files which are too small */ + if (pZip->m_archive_size < record_size) + return MZ_FALSE; + + /* Find the record by scanning the file from the end towards the beginning. */ + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (;;) + { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + + for (i = n - 4; i >= 0; --i) + { + mz_uint s = MZ_READ_LE32(pBuf + i); + if (s == record_sig) + { + if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) + break; + } + } + + if (i >= 0) + { + cur_file_ofs += i; + break; + } + + /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) + return MZ_FALSE; + + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + + *pOfs = cur_file_ofs; + return MZ_TRUE; +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) +{ + mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; + mz_uint64 cdir_ofs = 0; + mz_int64 cur_file_ofs = 0; + const mz_uint8 *p; + + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; + + mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; + + mz_uint64 zip64_end_of_central_dir_ofs = 0; + + /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) + return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + + /* Read and verify the end of central directory record. */ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + { + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + { + if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) + { + zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); + if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + { + if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) + { + pZip->m_pState->m_zip64 = MZ_TRUE; + } + } + } + } + } + + pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); + cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + + if (pZip->m_pState->m_zip64) + { + mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); + mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); + mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); + mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); + mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); + + if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (zip64_total_num_of_disks != 1U) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + /* Check for miniz's practical limits */ + if (zip64_cdir_total_entries > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; + + if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; + + /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ + if (zip64_size_of_central_directory > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + cdir_size = (mz_uint32)zip64_size_of_central_directory; + + num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); + + cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); + + cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); + } + + if (pZip->m_total_files != cdir_entries_on_this_disk) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (cdir_size < (mz_uint64)pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) + { + mz_uint i, n; + /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (sort_central_dir) + { + if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + /* Now create an index into the central directory file records, do some basic sanity checking on each record */ + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) + { + mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; + mz_uint64 comp_size, decomp_size, local_header_ofs; + + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + + if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && + (ext_data_size) && + (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) + { + /* Attempt to find zip64 extended information field in the entry's extra data */ + mz_uint32 extra_size_remaining = ext_data_size; + + if (extra_size_remaining) + { + const mz_uint8 *pExtra_data; + void* buf = NULL; + + if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n) + { + buf = MZ_MALLOC(ext_data_size); + if(buf==NULL) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + pExtra_data = (mz_uint8*)buf; + } + else + { + pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; + } + + do + { + mz_uint32 field_id; + mz_uint32 field_data_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + + if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ + pZip->m_pState->m_zip64 = MZ_TRUE; + pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; + break; + } + + pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; + extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; + } while (extra_size_remaining); + + MZ_FREE(buf); + } + } + + /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ + if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) + { + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (comp_size != MZ_UINT32_MAX) + { + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + n -= total_header_size; + p += total_header_size; + } + } + + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +void mz_zip_zero_struct(mz_zip_archive *pZip) +{ + if (pZip) + MZ_CLEAR_PTR(pZip); +} + +static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +{ + mz_bool status = MZ_TRUE; + + if (!pZip) + return MZ_FALSE; + + if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + { + if (set_last_error) + pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; + + return MZ_FALSE; + } + + if (pZip->m_pState) + { + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (MZ_FCLOSE(pState->m_pFile) == EOF) + { + if (set_last_error) + pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; + status = MZ_FALSE; + } + } + pState->m_pFile = NULL; + } +#endif /* #ifndef MINIZ_NO_STDIO */ + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return status; +} + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +{ + return mz_zip_reader_end_internal(pZip, MZ_TRUE); +} +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) +{ + if ((!pZip) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_USER; + pZip->m_archive_size = size; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) +{ + if (!pMem) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pNeeds_keepalive = NULL; + +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + + pZip->m_pState->m_mem_size = size; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + + file_ofs += pZip->m_pState->m_file_archive_start_ofs; + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +{ + return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); +} + +mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) +{ + mz_uint64 file_size; + MZ_FILE *pFile; + + if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + file_size = archive_size; + if (!file_size) + { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + { + MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + } + + file_size = MZ_FTELL64(pFile); + } + + /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + + if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + { + MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } + + if (!mz_zip_reader_init_internal(pZip, flags)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + + pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) +{ + mz_uint64 cur_file_ofs; + + if ((!pZip) || (!pFile)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + cur_file_ofs = MZ_FTELL64(pFile); + + if (!archive_size) + { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + + archive_size = MZ_FTELL64(pFile) - cur_file_ofs; + + if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = archive_size; + pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +#endif /* #ifndef MINIZ_NO_STDIO */ + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +{ + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; +} + +mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint bit_flag; + mz_uint method; + + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); + bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + + if ((method != 0) && (method != MZ_DEFLATED)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + return MZ_FALSE; + } + + if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + return MZ_FALSE; + } + + if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint filename_len, attribute_mapping_id, external_attr; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) + { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ + /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ + /* FIXME: Remove this check? Is it necessary - we already check the filename. */ + attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; + (void)attribute_mapping_id; + + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) + { + return MZ_TRUE; + } + + return MZ_FALSE; +} + +static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) +{ + mz_uint n; + const mz_uint8 *p = pCentral_dir_header; + + if (pFound_zip64_extra_data) + *pFound_zip64_extra_data = MZ_FALSE; + + if ((!p) || (!pStat)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Extract fields from the central directory record. */ + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + /* Copy as much of the filename and comment as possible. */ + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); + pStat->m_comment[n] = '\0'; + + /* Set some flags for convienance */ + pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); + pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); + pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); + + /* See if we need to read any zip64 extended information fields. */ + /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ + if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) + { + /* Attempt to find zip64 extended information field in the entry's extra data */ + mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + + if (extra_size_remaining) + { + const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + + do + { + mz_uint32 field_id; + mz_uint32 field_data_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + + if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; + mz_uint32 field_data_remaining = field_data_size; + + if (pFound_zip64_extra_data) + *pFound_zip64_extra_data = MZ_TRUE; + + if (pStat->m_uncomp_size == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_uncomp_size = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + if (pStat->m_comp_size == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_comp_size = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + if (pStat->m_local_header_ofs == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + break; + } + + pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; + extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; + } while (extra_size_remaining); + } + } + + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +{ + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) + return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) + return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const mz_uint32 size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + + if (pIndex) + *pIndex = 0; + + if (size) + { + /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ + /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ + mz_int64 l = 0, h = (mz_int64)size - 1; + + while (l <= h) + { + mz_int64 m = l + ((h - l) >> 1); + mz_uint32 file_index = pIndices[(mz_uint32)m]; + + int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) + { + if (pIndex) + *pIndex = file_index; + return MZ_TRUE; + } + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + } + + return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +{ + mz_uint32 index; + if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) + return -1; + else + return (int)index; +} + +mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +{ + mz_uint file_index; + size_t name_len, comment_len; + + if (pIndex) + *pIndex = 0; + + if ((!pZip) || (!pZip->m_pState) || (!pName)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* See if we can use a binary search */ + if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && + (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && + ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + { + return mz_zip_locate_file_binary_search(pZip, pName, pIndex); + } + + /* Locate the entry by scanning the entire central directory */ + name_len = strlen(pName); + if (name_len > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + for (file_index = 0; file_index < pZip->m_total_files; file_index++) + { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) + continue; + if (comment_len) + { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) + { + int ofs = filename_len - 1; + do + { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) + { + if (pIndex) + *pIndex = file_index; + return MZ_TRUE; + } + } + + return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +} + +static +mz_bool mz_zip_reader_extract_to_mem_no_alloc1(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size, const mz_zip_archive_file_stat *st) +{ + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (st) { + file_stat = *st; + } else + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + /* Ensure supplied output buffer is large enough. */ + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) + return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); + + /* Read and parse the local directory entry. */ + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data. */ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) + { + if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) + return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); + } +#endif + + return MZ_TRUE; + } + + /* Decompress the file either directly from memory or from a file input buffer. */ + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) + { + /* Read directly from the archive in memory. */ + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else if (pUser_read_buf) + { + /* Use a user provided read buffer. */ + if (!user_read_buf_size) + return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + else + { + /* Temporarily allocate a read buffer. */ + read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do + { + /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (out_buf_ofs != file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); + status = TINFL_STATUS_FAILED; + } +#endif + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size, NULL); +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size, NULL); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, NULL, 0, NULL); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + mz_uint64 alloc_size; + void *pBuf; + + if (pSize) + *pSize = 0; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return NULL; + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) + { + mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + return NULL; + } + + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return NULL; + } + + if (!mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, (size_t)alloc_size, flags, NULL, 0, &file_stat)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) + *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + { + if (pSize) + *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int status = TINFL_STATUS_DONE; +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + mz_uint file_crc32 = MZ_CRC32_INIT; +#endif + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + /* Decompress the file either directly from memory or from a file input buffer. */ + if (pZip->m_pState->m_pMem) + { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data. */ + if (pZip->m_pState->m_pMem) + { + if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + } + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); +#endif + } + + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + while (comp_remaining) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + } +#endif + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } + else + { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + status = TINFL_STATUS_FAILED; + } + else + { + do + { + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) + { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); +#endif + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (out_buf_ofs != file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (file_crc32 != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + status = TINFL_STATUS_FAILED; + } +#endif + } + + if (!pZip->m_pState->m_pMem) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + if (pWrite_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +} + +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +{ + mz_zip_reader_extract_iter_state *pState; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + /* Argument sanity check */ + if ((!pZip) || (!pZip->m_pState)) + return NULL; + + /* Allocate an iterator status structure */ + pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); + if (!pState) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return NULL; + } + + /* Fetch file details */ + if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Encryption and patch files are not supported. */ + if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Init state - save args */ + pState->pZip = pZip; + pState->flags = flags; + + /* Init state - reset variables to defaults */ + pState->status = TINFL_STATUS_DONE; +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + pState->file_crc32 = MZ_CRC32_INIT; +#endif + pState->read_buf_ofs = 0; + pState->out_buf_ofs = 0; + pState->pRead_buf = NULL; + pState->pWrite_buf = NULL; + pState->out_blk_remain = 0; + + /* Read and parse the local directory entry. */ + pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Decompress the file either directly from memory or from a file input buffer. */ + if (pZip->m_pState->m_pMem) + { + pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; + pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; + pState->comp_remaining = pState->file_stat.m_comp_size; + } + else + { + if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) + { + /* Decompression required, therefore intermediate read buffer required */ + pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + } + else + { + /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ + pState->read_buf_size = 0; + } + pState->read_buf_avail = 0; + pState->comp_remaining = pState->file_stat.m_comp_size; + } + + if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) + { + /* Decompression required, init decompressor */ + tinfl_init( &pState->inflator ); + + /* Allocate write buffer */ + if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + if (pState->pRead_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + } + + return pState; +} + +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +{ + mz_uint32 file_index; + + /* Locate file index by name */ + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return NULL; + + /* Construct iterator */ + return mz_zip_reader_extract_iter_new(pZip, file_index, flags); +} + +size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) +{ + size_t copied_to_caller = 0; + + /* Argument sanity check */ + if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) + return 0; + + if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data, calc amount to return. */ + copied_to_caller = (size_t)MZ_MIN( buf_size, pState->comp_remaining ); + + /* Zip is in memory....or requires reading from a file? */ + if (pState->pZip->m_pState->m_pMem) + { + /* Copy data to caller's buffer */ + memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); + pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; + } + else + { + /* Read directly into caller's buffer */ + if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) + { + /* Failed to read all that was asked for, flag failure and alert user */ + mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); + pState->status = TINFL_STATUS_FAILED; + copied_to_caller = 0; + } + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + /* Compute CRC if not returning compressed data only */ + if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); +#endif + + /* Advance offsets, dec counters */ + pState->cur_file_ofs += copied_to_caller; + pState->out_buf_ofs += copied_to_caller; + pState->comp_remaining -= copied_to_caller; + } + else + { + do + { + /* Calc ptr to write buffer - given current output pos and block size */ + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + + /* Calc max output size - given current output pos and block size */ + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + + if (!pState->out_blk_remain) + { + /* Read more data from file if none available (and reading from file) */ + if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) + { + /* Calc read size */ + pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); + if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); + pState->status = TINFL_STATUS_FAILED; + break; + } + + /* Advance offsets, dec counters */ + pState->cur_file_ofs += pState->read_buf_avail; + pState->comp_remaining -= pState->read_buf_avail; + pState->read_buf_ofs = 0; + } + + /* Perform decompression */ + in_buf_size = (size_t)pState->read_buf_avail; + pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + pState->read_buf_avail -= in_buf_size; + pState->read_buf_ofs += in_buf_size; + + /* Update current output block size remaining */ + pState->out_blk_remain = out_buf_size; + } + + if (pState->out_blk_remain) + { + /* Calc amount to return. */ + size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); + + /* Copy data to caller's buffer */ + memcpy( (mz_uint8*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + /* Perform CRC */ + pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); +#endif + + /* Decrement data consumed from block */ + pState->out_blk_remain -= to_copy; + + /* Inc output offset, while performing sanity check */ + if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); + pState->status = TINFL_STATUS_FAILED; + break; + } + + /* Increment counter of data copied to caller */ + copied_to_caller += to_copy; + } + } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); + } + + /* Return how many bytes were copied into user buffer */ + return copied_to_caller; +} + +mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) +{ + int status; + + /* Argument sanity check */ + if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) + return MZ_FALSE; + + /* Was decompression completed and requested? */ + if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + pState->status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (pState->file_crc32 != pState->file_stat.m_crc32) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); + pState->status = TINFL_STATUS_FAILED; + } +#endif + } + + /* Free buffers */ + if (!pState->pZip->m_pState->m_pMem) + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); + if (pState->pWrite_buf) + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); + + /* Save status */ + status = pState->status; + + /* Free context */ + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); + + return status == TINFL_STATUS_DONE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +{ + (void)ofs; + + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +{ + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + + if (MZ_FCLOSE(pFile) == EOF) + { + if (status) + mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + + status = MZ_FALSE; + } + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + + return status; +} + +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} + +mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); +} + +mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_uint32 *p = (mz_uint32 *)pOpaque; + (void)file_ofs; + *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); + return n; +} + +mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + mz_zip_internal_state *pState; + const mz_uint8 *pCentral_dir_header; + mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; + mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint64 local_header_ofs = 0; + mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; + mz_uint64 local_header_comp_size, local_header_uncomp_size; + mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; + mz_bool has_data_descriptor; + mz_uint32 local_header_bit_flags; + + mz_zip_array file_data_array; + mz_zip_array_init(&file_data_array, 1); + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (file_index > pZip->m_total_files) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); + + if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_is_encrypted) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports stored and deflate. */ + if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + if (!file_stat.m_is_supported) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + /* Read and parse the local directory entry. */ + local_header_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); + local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); + local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); + local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); + local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + has_data_descriptor = (local_header_bit_flags & 8) != 0; + + if (local_header_filename_len != strlen(file_stat.m_filename)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + goto handle_failure; + } + + if (local_header_filename_len) + { + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ + if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + + if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) + { + mz_uint32 extra_size_remaining = local_header_extra_len; + const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; + + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + goto handle_failure; + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + goto handle_failure; + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + goto handle_failure; + } + + local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); + local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + } + + /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ + /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ + if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) + { + mz_uint8 descriptor_buf[32]; + mz_bool has_id; + const mz_uint8 *pSrc; + mz_uint32 file_crc32; + mz_uint64 comp_size = 0, uncomp_size = 0; + + mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; + + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; + + file_crc32 = MZ_READ_LE32(pSrc); + + if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) + { + comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); + uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); + } + else + { + comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); + uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); + } + + if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + else + { + if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + + mz_zip_array_clear(pZip, &file_data_array); + + if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) + { + if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) + return MZ_FALSE; + + /* 1 more check to be sure, although the extract checks too. */ + if (uncomp_crc32 != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + return MZ_FALSE; + } + } + + return MZ_TRUE; + +handle_failure: + mz_zip_array_clear(pZip, &file_data_array); + return MZ_FALSE; +} + +mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) +{ + mz_zip_internal_state *pState; + mz_uint32 i; + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + /* Basic sanity checks */ + if (!pState->m_zip64) + { + if (pZip->m_total_files > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (pZip->m_archive_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + else + { + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + + for (i = 0; i < pZip->m_total_files; i++) + { + if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) + { + mz_uint32 found_index; + mz_zip_archive_file_stat stat; + + if (!mz_zip_reader_file_stat(pZip, i, &stat)) + return MZ_FALSE; + + if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) + return MZ_FALSE; + + /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ + if (found_index != i) + return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + } + + if (!mz_zip_validate_file(pZip, i, flags)) + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) +{ + mz_bool success = MZ_TRUE; + mz_zip_archive zip; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + if ((!pMem) || (!size)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + mz_zip_zero_struct(&zip); + + if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) + { + if (pErr) + *pErr = zip.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_validate_archive(&zip, flags)) + { + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (!mz_zip_reader_end_internal(&zip, success)) + { + if (!actual_err) + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (pErr) + *pErr = actual_err; + + return success; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) +{ + mz_bool success = MZ_TRUE; + mz_zip_archive zip; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + if (!pFilename) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + mz_zip_zero_struct(&zip); + + if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) + { + if (pErr) + *pErr = zip.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_validate_archive(&zip, flags)) + { + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (!mz_zip_reader_end_internal(&zip, success)) + { + if (!actual_err) + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (pErr) + *pErr = actual_err; + + return success; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +/* ------------------- .ZIP archive writing */ + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} +static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} +static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) +{ + mz_write_le32(p, (mz_uint32)v); + mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); +} + +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) +#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + + if (!n) + return 0; + + /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ + if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + return 0; + } + + if (new_size > pState->m_mem_capacity) + { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + + while (new_capacity < new_size) + new_capacity *= 2; + + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return 0; + } + + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +{ + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + { + if (set_last_error) + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (MZ_FCLOSE(pState->m_pFile) == EOF) + { + if (set_last_error) + mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + status = MZ_FALSE; + } + } + + pState->m_pFile = NULL; + } +#endif /* #ifndef MINIZ_NO_STDIO */ + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) +{ + mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; + + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + { + if (!pZip->m_pRead) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + if (pZip->m_file_offset_alignment) + { + /* Ensure user specified file offset alignment is a power of 2. */ + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + if (!pZip->m_pAlloc) + pZip->m_pAlloc = miniz_def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = miniz_def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = miniz_def_realloc_func; + + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + + pZip->m_pState->m_zip64 = zip64; + pZip->m_pState->m_zip64_has_extended_info_fields = zip64; + + pZip->m_zip_type = MZ_ZIP_TYPE_USER; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +{ + return mz_zip_writer_init_v2(pZip, existing_size, 0); +} + +mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) +{ + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_mem_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; + + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) + { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + { + mz_zip_writer_end_internal(pZip, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +{ + return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + + file_ofs += pZip->m_pState->m_file_archive_start_ofs; + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + return 0; + } + + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +{ + return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); +} + +mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) +{ + MZ_FILE *pFile; + + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) + return MZ_FALSE; + + if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) + { + mz_zip_writer_end(pZip); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + } + + pZip->m_pState->m_pFile = pFile; + pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + + if (size_to_reserve_at_beginning) + { + mz_uint64 cur_ofs = 0; + char buf[4096]; + + MZ_CLEAR_ARR(buf); + + do + { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) + { + mz_zip_writer_end(pZip); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) +{ + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, 0, flags)) + return MZ_FALSE; + + pZip->m_pState->m_pFile = pFile; + pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + + return MZ_TRUE; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +{ + mz_zip_internal_state *pState; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) + { + /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ + if (!pZip->m_pState->m_zip64) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + /* No sense in trying to write to an archive that's already at the support max size */ + if (pZip->m_pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + } + + pState = pZip->m_pState; + + if (pState->m_pFile) + { +#ifdef MINIZ_NO_STDIO + (void)pFilename; + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +#else + if (pZip->m_pIO_opaque != pZip) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (!pFilename) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + { + /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + } + } + + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; +#endif /* #ifdef MINIZ_NO_STDIO */ + } + else if (pState->m_pMem) + { + /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ + if (pZip->m_pIO_opaque != pZip) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pNeeds_keepalive = NULL; + } + /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ + else if (!pZip->m_pWrite) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Start writing new files at the archive's current central directory location. */ + /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_central_directory_file_ofs = 0; + + /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ + /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ + /* TODO: We could easily maintain the sorted central directory offsets. */ + mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +{ + return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); +} + +/* TODO: pArchive_name is a terrible name here! */ +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +{ + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +} + +typedef struct +{ + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) +{ + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + return MZ_FALSE; + + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) +#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) +static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) +{ + mz_uint8 *pDst = pBuf; + mz_uint32 field_size = 0; + + MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); + MZ_WRITE_LE16(pDst + 2, 0); + pDst += sizeof(mz_uint16) * 2; + + if (pUncomp_size) + { + MZ_WRITE_LE64(pDst, *pUncomp_size); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + if (pComp_size) + { + MZ_WRITE_LE64(pDst, *pComp_size); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + if (pLocal_header_ofs) + { + MZ_WRITE_LE64(pDst, *pLocal_header_ofs); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + MZ_WRITE_LE16(pBuf + 2, field_size); + + return (mz_uint32)(pDst - pBuf); +} + +static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, + mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, + mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, + const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, + mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes, + const char *user_extra_data, mz_uint user_extra_data_len) +{ + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + if (!pZip->m_pState->m_zip64) + { + if (local_header_ofs > 0xFFFFFFFF) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + } + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, (mz_uint16)(extra_size + user_extra_data_len), comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) + { + /* Try to resize the central directory array back into its original state. */ + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +{ + /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ + if (*pArchive_name == '/') + return MZ_FALSE; + + /* Making sure the name does not contain drive letters or DOS style backward slashes is the responsibility of the program using miniz*/ + + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +{ + mz_uint32 n; + if (!pZip->m_file_offset_alignment) + return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +{ + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) + { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +{ + return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); +} + +mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + mz_uint8 *pExtra_data = NULL; + mz_uint32 extra_size = 0; + mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; + mz_uint16 bit_flags = 0; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + + if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) + bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if (pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ + } + if (((mz_uint64)buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +#ifndef MINIZ_NO_TIME + if (last_modified != NULL) + { + mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); + } + else + { + MZ_TIME_T cur_time; + time(&cur_time); + mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif /* #ifndef MINIZ_NO_TIME */ + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) + { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!pState->m_zip64) + { + /* Bail early if the archive would obviously become too large */ + if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len + + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) + { + /* Set DOS Subdirectory attribute bit. */ + ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; + + /* Subdirectories cannot contain data. */ + if ((buf_size) || (uncomp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if ((!store_data_uncompressed) && (buf_size)) + { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + cur_archive_file_ofs += num_alignment_padding_bytes; + + MZ_CLEAR_ARR(local_dir_header); + + if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + method = MZ_DEFLATED; + } + + if (pState->m_zip64) + { + if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + { + pExtra_data = extra_data; + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, bit_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_archive_file_ofs += archive_name_size; + + if (pExtra_data != NULL) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += extra_size; + } + } + else + { + if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_archive_file_ofs += archive_name_size; + } + + if (user_extra_data_len > 0) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += user_extra_data_len; + } + + if (store_data_uncompressed) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + } + else if (buf_size) + { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + if (uncomp_size) + { + mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; + mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + + MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); + + MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); + MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); + if (pExtra_data == NULL) + { + if (comp_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(local_dir_footer + 8, comp_size); + MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); + } + else + { + MZ_WRITE_LE64(local_dir_footer + 8, comp_size); + MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); + local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) + return MZ_FALSE; + + cur_archive_file_ofs += local_dir_footer_size; + } + + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, + user_extra_data_central, user_extra_data_central_len)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + mz_uint16 gen_flags; + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + mz_uint8 *pExtra_data = NULL; + mz_uint32 extra_size = 0; + mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; + mz_zip_internal_state *pState; + mz_uint64 file_ofs = 0, cur_archive_header_file_ofs; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + gen_flags = (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) ? 0 : MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) + gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + + /* Sanity checks */ + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if ((!pState->m_zip64) && (max_size > MZ_UINT32_MAX)) + { + /* Source file is too large for non-zip64 */ + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + pState->m_zip64 = MZ_TRUE; + } + + /* We could support this, but why? */ + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + if (pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ + } + } + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!pState->m_zip64) + { + /* Bail early if the archive would obviously become too large */ + if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 + + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + +#ifndef MINIZ_NO_TIME + if (pFile_time) + { + mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); + } +#endif + + if (max_size <= 3) + level = 0; + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_archive_file_ofs; + + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + + if (max_size && level) + { + method = MZ_DEFLATED; + } + + MZ_CLEAR_ARR(local_dir_header); + if (pState->m_zip64) + { + if (max_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + { + pExtra_data = extra_data; + if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL, + (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + else + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, NULL, + NULL, + (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += archive_name_size; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += extra_size; + } + else + { + if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += archive_name_size; + } + + if (user_extra_data_len > 0) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += user_extra_data_len; + } + + if (max_size) + { + void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) + { + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!level) + { + while (1) + { + size_t n = read_callback(callback_opaque, file_ofs, pRead_buf, MZ_ZIP_MAX_IO_BUF_SIZE); + if (n == 0) + break; + + if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + file_ofs += n; + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + cur_archive_file_ofs += n; + } + uncomp_size = file_ofs; + comp_size = uncomp_size; + } + else + { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + } + + for (;;) + { + tdefl_status status; + tdefl_flush flush = TDEFL_NO_FLUSH; + + size_t n = read_callback(callback_opaque, file_ofs, pRead_buf, MZ_ZIP_MAX_IO_BUF_SIZE); + if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + break; + } + + file_ofs += n; + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + + if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) + flush = TDEFL_FULL_FLUSH; + + if (n == 0) + flush = TDEFL_FINISH; + + status = tdefl_compress_buffer(pComp, pRead_buf, n, flush); + if (status == TDEFL_STATUS_DONE) + { + result = MZ_TRUE; + break; + } + else if (status != TDEFL_STATUS_OKAY) + { + mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); + break; + } + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return MZ_FALSE; + } + + uncomp_size = file_ofs; + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + if (!(level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)) + { + mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; + mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + + MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); + MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); + if (pExtra_data == NULL) + { + if (comp_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(local_dir_footer + 8, comp_size); + MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); + } + else + { + MZ_WRITE_LE64(local_dir_footer + 8, comp_size); + MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); + local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) + return MZ_FALSE; + + cur_archive_file_ofs += local_dir_footer_size; + } + + if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) + { + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, + (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), + (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size, + (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : comp_size, + uncomp_crc32, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + cur_archive_header_file_ofs = local_dir_header_ofs; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + if (pExtra_data != NULL) + { + cur_archive_header_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_header_file_ofs += archive_name_size; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_header_file_ofs += extra_size; + } + } + + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, + user_extra_data_central, user_extra_data_central_len)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO + +static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pSrc_file); + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + + return MZ_FREAD(pBuf, 1, n, pSrc_file); +} + +mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, pFile_time, pComment, comment_size, level_and_flags, + user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len); +} + +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + MZ_FILE *pSrc_file = NULL; + mz_uint64 uncomp_size = 0; + MZ_TIME_T file_modified_time; + MZ_TIME_T *pFile_time = NULL; + mz_bool status; + + memset(&file_modified_time, 0, sizeof(file_modified_time)); + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) + pFile_time = &file_modified_time; + if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); +#endif + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + + MZ_FCLOSE(pSrc_file); + + return status; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, mz_uint32 ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) +{ + /* + 64 should be enough for any new zip64 data */ + if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); + + if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) + { + mz_uint8 new_ext_block[64]; + mz_uint8 *pDst = new_ext_block; + mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); + mz_write_le16(pDst + sizeof(mz_uint16), 0); + pDst += sizeof(mz_uint16) * 2; + + if (pUncomp_size) + { + mz_write_le64(pDst, *pUncomp_size); + pDst += sizeof(mz_uint64); + } + + if (pComp_size) + { + mz_write_le64(pDst, *pComp_size); + pDst += sizeof(mz_uint64); + } + + if (pLocal_header_ofs) + { + mz_write_le64(pDst, *pLocal_header_ofs); + pDst += sizeof(mz_uint64); + } + + if (pDisk_start) + { + mz_write_le32(pDst, *pDisk_start); + pDst += sizeof(mz_uint32); + } + + mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); + + if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if ((pExt) && (ext_len)) + { + mz_uint32 extra_size_remaining = ext_len; + const mz_uint8 *pExtra_data = pExt; + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + } + + return MZ_TRUE; +} + +/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) +{ + mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; + mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; + const mz_uint8 *pSrc_central_header; + mz_zip_archive_file_stat src_file_stat; + mz_uint32 src_filename_len, src_comment_len, src_ext_len; + mz_uint32 local_header_filename_size, local_header_extra_len; + mz_uint64 local_header_comp_size, local_header_uncomp_size; + mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + + /* Sanity checks */ + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ + if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Get pointer to the source central dir header and crack it */ + if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); + src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); + src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; + + /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ + if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + if (!pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + + if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) + return MZ_FALSE; + + cur_src_file_ofs = src_file_stat.m_local_header_ofs; + cur_dst_file_ofs = pZip->m_archive_size; + + /* Read the source archive's local dir header */ + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + /* Compute the total size we need to copy (filename+extra data+compressed data) */ + local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); + local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); + local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); + src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; + + /* Try to find a zip64 extended information field */ + if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) + { + mz_zip_array file_data_array; + const mz_uint8 *pExtra_data; + mz_uint32 extra_size_remaining = local_header_extra_len; + + mz_zip_array_init(&file_data_array, 1); + if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) + { + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + pExtra_data = (const mz_uint8 *)file_data_array.m_p; + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); + local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + + mz_zip_array_clear(pZip, &file_data_array); + } + + if (!pState->m_zip64) + { + /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ + /* We also check when the archive is finalized so this doesn't need to be perfect. */ + mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + + pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; + + if (approx_new_archive_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + + /* Write dest archive padding */ + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + return MZ_FALSE; + + cur_dst_file_ofs += num_alignment_padding_bytes; + + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + + /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + while (src_archive_bytes_remaining) + { + n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_dst_file_ofs += n; + + src_archive_bytes_remaining -= n; + } + + /* Now deal with the optional data descriptor */ + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) + { + /* Copy data descriptor */ + if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) + { + /* src is zip64, dest must be zip64 */ + + /* name uint32_t's */ + /* id 1 (optional in zip64?) */ + /* crc 1 */ + /* comp_size 2 */ + /* uncomp_size 2 */ + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); + } + else + { + /* src is NOT zip64 */ + mz_bool has_id; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + + if (pZip->m_pState->m_zip64) + { + /* dest is zip64, so upgrade the data descriptor */ + const mz_uint8 *pSrc_descriptor = (const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0); + const mz_uint32 src_crc32 = MZ_READ_LE32(pSrc_descriptor); + const mz_uint64 src_comp_size = MZ_READ_LE32(pSrc_descriptor + sizeof(mz_uint32)); + const mz_uint64 src_uncomp_size = MZ_READ_LE32(pSrc_descriptor + 2*sizeof(mz_uint32)); + + mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); + mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); + mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); + mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); + + n = sizeof(mz_uint32) * 6; + } + else + { + /* dest is NOT zip64, just copy it as-is */ + n = sizeof(mz_uint32) * (has_id ? 4 : 3); + } + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + /* Finally, add the new central dir header */ + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + + if (pState->m_zip64) + { + /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ + const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; + mz_zip_array new_ext_block; + + mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); + + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); + + if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) + { + mz_zip_array_clear(pZip, &new_ext_block); + return MZ_FALSE; + } + + MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + { + mz_zip_array_clear(pZip, &new_ext_block); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + mz_zip_array_clear(pZip, &new_ext_block); + } + else + { + /* sanity checks */ + if (cur_dst_file_ofs > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (local_dir_header_ofs >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + } + + /* This shouldn't trigger unless we screwed up during the initial sanity checks */ + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) + { + /* TODO: Support central dirs >= 32-bits in size */ + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + } + + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[256]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if (pState->m_zip64) + { + if ((mz_uint64)pState->m_central_dir.m_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) + { + /* Write central directory */ + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += central_dir_size; + } + + if (pState->m_zip64) + { + /* Write zip64 end of central directory header */ + mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; + + MZ_CLEAR_ARR(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); + MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ + MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + + /* Write zip64 end of central directory locator */ + MZ_CLEAR_ARR(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; + } + + /* Write end of central directory record */ + MZ_CLEAR_ARR(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +#endif /* #ifndef MINIZ_NO_STDIO */ + + pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) +{ + if ((!ppBuf) || (!pSize)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + *ppBuf = NULL; + *pSize = 0; + + if ((!pZip) || (!pZip->m_pState)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (pZip->m_pWrite != mz_zip_heap_write_func) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_finalize_archive(pZip)) + return MZ_FALSE; + + *ppBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +{ + return mz_zip_writer_end_internal(pZip, MZ_TRUE); +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); +} + +mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) +{ + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + mz_zip_zero_struct(&zip_archive); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_FILENAME; + return MZ_FALSE; + } + + /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ + /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) + { + /* Create a new archive. */ + if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + return MZ_FALSE; + } + + created_new_archive = MZ_TRUE; + } + else + { + /* Append to an existing archive. */ + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + + mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); + + return MZ_FALSE; + } + } + + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); + actual_err = zip_archive.m_last_error; + + /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ + if (!mz_zip_writer_finalize_archive(&zip_archive)) + { + if (!actual_err) + actual_err = zip_archive.m_last_error; + + status = MZ_FALSE; + } + + if (!mz_zip_writer_end_internal(&zip_archive, status)) + { + if (!actual_err) + actual_err = zip_archive.m_last_error; + + status = MZ_FALSE; + } + + if ((!status) && (created_new_archive)) + { + /* It's a new archive and something went wrong, so just delete it. */ + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + + if (pErr) + *pErr = actual_err; + + return status; +} + +void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) +{ + mz_uint32 file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) + *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + + return NULL; + } + + mz_zip_zero_struct(&zip_archive); + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + + return NULL; + } + + if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) + { + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + } + + mz_zip_reader_end_internal(&zip_archive, p != NULL); + + if (pErr) + *pErr = zip_archive.m_last_error; + + return p; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +{ + return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); +} + +#endif /* #ifndef MINIZ_NO_STDIO */ + +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* ------------------- Misc utils */ + +mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; +} + +mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; +} + +mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) +{ + mz_zip_error prev_err; + + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + prev_err = pZip->m_last_error; + + pZip->m_last_error = err_num; + return prev_err; +} + +mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) +{ + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + return pZip->m_last_error; +} + +mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) +{ + return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); +} + +mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) +{ + mz_zip_error prev_err; + + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + prev_err = pZip->m_last_error; + + pZip->m_last_error = MZ_ZIP_NO_ERROR; + return prev_err; +} + +const char *mz_zip_get_error_string(mz_zip_error mz_err) +{ + switch (mz_err) + { + case MZ_ZIP_NO_ERROR: + return "no error"; + case MZ_ZIP_UNDEFINED_ERROR: + return "undefined error"; + case MZ_ZIP_TOO_MANY_FILES: + return "too many files"; + case MZ_ZIP_FILE_TOO_LARGE: + return "file too large"; + case MZ_ZIP_UNSUPPORTED_METHOD: + return "unsupported method"; + case MZ_ZIP_UNSUPPORTED_ENCRYPTION: + return "unsupported encryption"; + case MZ_ZIP_UNSUPPORTED_FEATURE: + return "unsupported feature"; + case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: + return "failed finding central directory"; + case MZ_ZIP_NOT_AN_ARCHIVE: + return "not a ZIP archive"; + case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: + return "invalid header or archive is corrupted"; + case MZ_ZIP_UNSUPPORTED_MULTIDISK: + return "unsupported multidisk archive"; + case MZ_ZIP_DECOMPRESSION_FAILED: + return "decompression failed or archive is corrupted"; + case MZ_ZIP_COMPRESSION_FAILED: + return "compression failed"; + case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: + return "unexpected decompressed size"; + case MZ_ZIP_CRC_CHECK_FAILED: + return "CRC-32 check failed"; + case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: + return "unsupported central directory size"; + case MZ_ZIP_ALLOC_FAILED: + return "allocation failed"; + case MZ_ZIP_FILE_OPEN_FAILED: + return "file open failed"; + case MZ_ZIP_FILE_CREATE_FAILED: + return "file create failed"; + case MZ_ZIP_FILE_WRITE_FAILED: + return "file write failed"; + case MZ_ZIP_FILE_READ_FAILED: + return "file read failed"; + case MZ_ZIP_FILE_CLOSE_FAILED: + return "file close failed"; + case MZ_ZIP_FILE_SEEK_FAILED: + return "file seek failed"; + case MZ_ZIP_FILE_STAT_FAILED: + return "file stat failed"; + case MZ_ZIP_INVALID_PARAMETER: + return "invalid parameter"; + case MZ_ZIP_INVALID_FILENAME: + return "invalid filename"; + case MZ_ZIP_BUF_TOO_SMALL: + return "buffer too small"; + case MZ_ZIP_INTERNAL_ERROR: + return "internal error"; + case MZ_ZIP_FILE_NOT_FOUND: + return "file not found"; + case MZ_ZIP_ARCHIVE_TOO_LARGE: + return "archive is too large"; + case MZ_ZIP_VALIDATION_FAILED: + return "validation failed"; + case MZ_ZIP_WRITE_CALLBACK_FAILED: + return "write callback failed"; + case MZ_ZIP_TOTAL_ERRORS: + return "total errors"; + default: + break; + } + + return "unknown error"; +} + +/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ +mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return MZ_FALSE; + + return pZip->m_pState->m_zip64; +} + +size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + + return pZip->m_pState->m_central_dir.m_size; +} + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_total_files : 0; +} + +mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) +{ + if (!pZip) + return 0; + return pZip->m_archive_size; +} + +mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + return pZip->m_pState->m_file_archive_start_ofs; +} + +MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + return pZip->m_pState->m_pFile; +} + +size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + if (filename_buf_size) + pFilename[0] = '\0'; + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) + { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +{ + return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); +} + +mz_bool mz_zip_end(mz_zip_archive *pZip) +{ + if (!pZip) + return MZ_FALSE; + + if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) + return mz_zip_reader_end(pZip); +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) + return mz_zip_writer_end(pZip); +#endif + + return MZ_FALSE; +} + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/libraries/miniz/miniz.h b/libraries/miniz/miniz.h new file mode 100644 index 00000000000..9fcfffcc8cd --- /dev/null +++ b/libraries/miniz/miniz.h @@ -0,0 +1,1422 @@ +#ifndef MINIZ_EXPORT +#define MINIZ_EXPORT +#endif +/* miniz.c 3.0.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateReset/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ +#pragma once + + + +/* Defines to completely disable specific portions of miniz.c: + If all macros here are defined the only functionality remaining will be CRC-32 and adler-32. */ + +/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ +/*#define MINIZ_NO_STDIO */ + +/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ +/* get/set file times, and the C run-time funcs that get/set times won't be called. */ +/* The current downside is the times written to your archives will be from 1979. */ +/*#define MINIZ_NO_TIME */ + +/* Define MINIZ_NO_DEFLATE_APIS to disable all compression API's. */ +/*#define MINIZ_NO_DEFLATE_APIS */ + +/* Define MINIZ_NO_INFLATE_APIS to disable all decompression API's. */ +/*#define MINIZ_NO_INFLATE_APIS */ + +/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_APIS */ + +/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ +/*#define MINIZ_NO_ZLIB_APIS */ + +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ +/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. + Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc + callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user + functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ +/*#define MINIZ_NO_MALLOC */ + +#ifdef MINIZ_NO_INFLATE_APIS +#define MINIZ_NO_ARCHIVE_APIS +#endif + +#ifdef MINIZ_NO_DEFLATE_APIS +#define MINIZ_NO_ARCHIVE_WRITING_APIS +#endif + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ +#define MINIZ_NO_TIME +#endif + +#include + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ +#define MINIZ_X86_OR_X64_CPU 1 +#else +#define MINIZ_X86_OR_X64_CPU 0 +#endif + +/* Set MINIZ_LITTLE_ENDIAN only if not set */ +#if !defined(MINIZ_LITTLE_ENDIAN) +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif + +#else + +#if MINIZ_X86_OR_X64_CPU +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif + +#endif +#endif + +/* Using unaligned loads and stores causes errors when using UBSan */ +#if defined(__has_feature) +#if __has_feature(undefined_behavior_sanitizer) +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#endif +#endif + +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ +#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) +#if MINIZ_X86_OR_X64_CPU +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#define MINIZ_UNALIGNED_USE_MEMCPY +#else +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#endif +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ +#define MINIZ_HAS_64BIT_REGISTERS 1 +#else +#define MINIZ_HAS_64BIT_REGISTERS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API Definitions. */ + +/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ +typedef unsigned long mz_ulong; + +/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ +MINIZ_EXPORT void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ +MINIZ_EXPORT mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ +MINIZ_EXPORT mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +/* Compression strategies. */ +enum +{ + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +/* Method */ +#define MZ_DEFLATED 8 + +/* Heap allocation callbacks. +Note that mz_alloc_func parameter types purposely differ from zlib's: items/size is size_t, not unsigned long. */ +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ +enum +{ + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +#define MZ_VERSION "11.0.2" +#define MZ_VERNUM 0xB002 +#define MZ_VER_MAJOR 11 +#define MZ_VER_MINOR 2 +#define MZ_VER_REVISION 0 +#define MZ_VER_SUBREVISION 0 + +#ifndef MINIZ_NO_ZLIB_APIS + +/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ +enum +{ + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +/* Return status codes. MZ_PARAM_ERROR is non-standard. */ +enum +{ + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +/* Window bits */ +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +/* Compression/decompression stream struct. */ +typedef struct mz_stream_s +{ + const unsigned char *next_in; /* pointer to next byte to read */ + unsigned int avail_in; /* number of bytes available at next_in */ + mz_ulong total_in; /* total number of bytes consumed so far */ + + unsigned char *next_out; /* pointer to next byte to write */ + unsigned int avail_out; /* number of bytes that can be written to next_out */ + mz_ulong total_out; /* total number of bytes produced so far */ + + char *msg; /* error msg (unused) */ + struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ + + mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ + mz_free_func zfree; /* optional heap free function (defaults to free) */ + void *opaque; /* heap alloc function user pointer */ + + int data_type; /* data_type (unused) */ + mz_ulong adler; /* adler32 of the source or uncompressed data */ + mz_ulong reserved; /* not used */ +} mz_stream; + +typedef mz_stream *mz_streamp; + +/* Returns the version string of miniz.c. */ +MINIZ_EXPORT const char *mz_version(void); + +#ifndef MINIZ_NO_DEFLATE_APIS + +/* mz_deflateInit() initializes a compressor with default options: */ +/* Parameters: */ +/* pStream must point to an initialized mz_stream struct. */ +/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ +/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ +/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if the input parameters are bogus. */ +/* MZ_MEM_ERROR on out of memory. */ +MINIZ_EXPORT int mz_deflateInit(mz_streamp pStream, int level); + +/* mz_deflateInit2() is like mz_deflate(), except with more control: */ +/* Additional parameters: */ +/* method must be MZ_DEFLATED */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ +/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ +MINIZ_EXPORT int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +MINIZ_EXPORT int mz_deflateReset(mz_streamp pStream); + +/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ +/* Return values: */ +/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ +/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ +MINIZ_EXPORT int mz_deflate(mz_streamp pStream, int flush); + +/* mz_deflateEnd() deinitializes a compressor: */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +MINIZ_EXPORT int mz_deflateEnd(mz_streamp pStream); + +/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ +MINIZ_EXPORT mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +/* Single-call compression functions mz_compress() and mz_compress2(): */ +/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ +MINIZ_EXPORT int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +MINIZ_EXPORT int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ +MINIZ_EXPORT mz_ulong mz_compressBound(mz_ulong source_len); + +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + +#ifndef MINIZ_NO_INFLATE_APIS + +/* Initializes a decompressor. */ +MINIZ_EXPORT int mz_inflateInit(mz_streamp pStream); + +/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ +MINIZ_EXPORT int mz_inflateInit2(mz_streamp pStream, int window_bits); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */ +MINIZ_EXPORT int mz_inflateReset(mz_streamp pStream); + +/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ +/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ +/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ +/* Return values: */ +/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ +/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_DATA_ERROR if the deflate stream is invalid. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ +/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ +MINIZ_EXPORT int mz_inflate(mz_streamp pStream, int flush); + +/* Deinitializes a decompressor. */ +MINIZ_EXPORT int mz_inflateEnd(mz_streamp pStream); + +/* Single-call decompression. */ +/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ +MINIZ_EXPORT int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +MINIZ_EXPORT int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong *pSource_len); +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + +/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ +MINIZ_EXPORT const char *mz_error(int err); + +/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream + +#ifndef MINIZ_NO_DEFLATE_APIS +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + +#ifndef MINIZ_NO_INFLATE_APIS +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflateReset mz_inflateReset +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define uncompress2 mz_uncompress2 +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() +#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +#endif /* MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif + + + + + +#pragma once +#include +#include +#include +#include + + + +/* ------------------- Types and macros */ +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef int64_t mz_int64; +typedef uint64_t mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#define MZ_FILE FILE +#endif /* #ifdef MINIZ_NO_STDIO */ + +#ifdef MINIZ_NO_TIME +typedef struct mz_dummy_time_t_tag +{ + mz_uint32 m_dummy1; + mz_uint32 m_dummy2; +} mz_dummy_time_t; +#define MZ_TIME_T mz_dummy_time_t +#else +#define MZ_TIME_T time_t +#endif + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) +#define MZ_CLEAR_ARR(obj) memset((obj), 0, sizeof(obj)) +#define MZ_CLEAR_PTR(obj) memset((obj), 0, sizeof(*obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); +extern MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address); +extern MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); + +#define MZ_UINT16_MAX (0xFFFFU) +#define MZ_UINT32_MAX (0xFFFFFFFFU) + +#ifdef __cplusplus +} +#endif + #pragma once + + +#ifndef MINIZ_NO_DEFLATE_APIS + +#ifdef __cplusplus +extern "C" { +#endif +/* ------------------- Low-level Compression API Definitions */ + +/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ +#define TDEFL_LESS_MEMORY 0 + +/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ +/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ +enum +{ + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ +/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ +/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ +/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ +/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ +/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ +/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ +/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ +/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +/* High level compression functions: */ +/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ +/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must free() the returned block when it's no longer needed. */ +MINIZ_EXPORT void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ +/* Returns 0 on failure. */ +MINIZ_EXPORT size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* Compresses an image to a compressed PNG file in memory. */ +/* On entry: */ +/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ +/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ +/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ +/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pLen_out will be set to the size of the PNG image file. */ +/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ +MINIZ_EXPORT void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +MINIZ_EXPORT void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + +/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ +MINIZ_EXPORT mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum +{ + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ +#if TDEFL_LESS_MEMORY +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +/* tdefl's compression state structure. */ +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +/* Initializes the compressor. */ +/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ +/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ +/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ +/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ +MINIZ_EXPORT tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ +MINIZ_EXPORT tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ +/* tdefl_compress_buffer() always consumes the entire input buffer. */ +MINIZ_EXPORT tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +MINIZ_EXPORT tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +MINIZ_EXPORT mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +/* Create tdefl_compress() flags given zlib-style compression parameters. */ +/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ +/* window_bits may be -15 (raw deflate) or 15 (zlib) */ +/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ +MINIZ_EXPORT mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tdefl_compressor structure in C so that */ +/* non-C language bindings to tdefl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +MINIZ_EXPORT tdefl_compressor *tdefl_compressor_alloc(void); +MINIZ_EXPORT void tdefl_compressor_free(tdefl_compressor *pComp); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ + #pragma once + +/* ------------------- Low-level Decompression API Definitions */ + +#ifndef MINIZ_NO_INFLATE_APIS + +#ifdef __cplusplus +extern "C" { +#endif +/* Decompression flags used by tinfl_decompress(). */ +/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ +/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ +/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ +/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +/* High level decompression functions: */ +/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ +/* On return: */ +/* Function returns a pointer to the decompressed data, or NULL on failure. */ +/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must call mz_free() on the returned block when it's no longer needed. */ +MINIZ_EXPORT void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ +/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +MINIZ_EXPORT size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ +/* Returns 1 on success or 0 on failure. */ +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +MINIZ_EXPORT int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tinfl_decompressor structure in C so that */ +/* non-C language bindings to tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +MINIZ_EXPORT tinfl_decompressor *tinfl_decompressor_alloc(void); +MINIZ_EXPORT void tinfl_decompressor_free(tinfl_decompressor *pDecomp); +#endif + +/* Max size of LZ dictionary. */ +#define TINFL_LZ_DICT_SIZE 32768 + +/* Return status. */ +typedef enum { + /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ + /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ + /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ + TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, + + /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ + TINFL_STATUS_BAD_PARAM = -3, + + /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ + TINFL_STATUS_ADLER32_MISMATCH = -2, + + /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ + TINFL_STATUS_FAILED = -1, + + /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ + + /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ + /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ + TINFL_STATUS_DONE = 0, + + /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ + /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ + /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + + /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ + /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ + /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ + /* so I may need to add some code to address this. */ + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +/* Initializes the decompressor to its initial state. */ +#define tinfl_init(r) \ + do \ + { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ +/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ +MINIZ_EXPORT tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +/* Internal/private bits follow. */ +enum +{ + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#else +#define TINFL_USE_64BIT_BITBUF 0 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + mz_int16 m_look_up[TINFL_MAX_HUFF_TABLES][TINFL_FAST_LOOKUP_SIZE]; + mz_int16 m_tree_0[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; + mz_int16 m_tree_1[TINFL_MAX_HUFF_SYMBOLS_1 * 2]; + mz_int16 m_tree_2[TINFL_MAX_HUFF_SYMBOLS_2 * 2]; + mz_uint8 m_code_size_0[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_uint8 m_code_size_1[TINFL_MAX_HUFF_SYMBOLS_1]; + mz_uint8 m_code_size_2[TINFL_MAX_HUFF_SYMBOLS_2]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ + +#pragma once + + +/* ------------------- ZIP archive reading/writing */ + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 +}; + +typedef struct +{ + /* Central directory file index. */ + mz_uint32 m_file_index; + + /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ + mz_uint64 m_central_dir_ofs; + + /* These fields are copied directly from the zip's central dir. */ + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; + + /* CRC-32 of uncompressed data. */ + mz_uint32 m_crc32; + + /* File's compressed size. */ + mz_uint64 m_comp_size; + + /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ + mz_uint64 m_uncomp_size; + + /* Zip internal and external file attributes. */ + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + + /* Entry's local header file offset in bytes. */ + mz_uint64 m_local_header_ofs; + + /* Size of comment in bytes. */ + mz_uint32 m_comment_size; + + /* MZ_TRUE if the entry appears to be a directory. */ + mz_bool m_is_directory; + + /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ + mz_bool m_is_encrypted; + + /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ + mz_bool m_is_supported; + + /* Filename. If string ends in '/' it's a subdirectory entry. */ + /* Guaranteed to be zero terminated, may be truncated to fit. */ + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + + /* Comment field. */ + /* Guaranteed to be zero terminated, may be truncated to fit. */ + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + +#ifdef MINIZ_NO_TIME + MZ_TIME_T m_padding; +#else + MZ_TIME_T m_time; +#endif +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum { + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, + MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ + MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ + MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ + MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, + MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000, + /*After adding a compressed file, seek back + to local file header and set the correct sizes*/ + MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE = 0x20000 +} mz_zip_flags; + +typedef enum { + MZ_ZIP_TYPE_INVALID = 0, + MZ_ZIP_TYPE_USER, + MZ_ZIP_TYPE_MEMORY, + MZ_ZIP_TYPE_HEAP, + MZ_ZIP_TYPE_FILE, + MZ_ZIP_TYPE_CFILE, + MZ_ZIP_TOTAL_TYPES +} mz_zip_type; + +/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ +typedef enum { + MZ_ZIP_NO_ERROR = 0, + MZ_ZIP_UNDEFINED_ERROR, + MZ_ZIP_TOO_MANY_FILES, + MZ_ZIP_FILE_TOO_LARGE, + MZ_ZIP_UNSUPPORTED_METHOD, + MZ_ZIP_UNSUPPORTED_ENCRYPTION, + MZ_ZIP_UNSUPPORTED_FEATURE, + MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, + MZ_ZIP_NOT_AN_ARCHIVE, + MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, + MZ_ZIP_UNSUPPORTED_MULTIDISK, + MZ_ZIP_DECOMPRESSION_FAILED, + MZ_ZIP_COMPRESSION_FAILED, + MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, + MZ_ZIP_CRC_CHECK_FAILED, + MZ_ZIP_UNSUPPORTED_CDIR_SIZE, + MZ_ZIP_ALLOC_FAILED, + MZ_ZIP_FILE_OPEN_FAILED, + MZ_ZIP_FILE_CREATE_FAILED, + MZ_ZIP_FILE_WRITE_FAILED, + MZ_ZIP_FILE_READ_FAILED, + MZ_ZIP_FILE_CLOSE_FAILED, + MZ_ZIP_FILE_SEEK_FAILED, + MZ_ZIP_FILE_STAT_FAILED, + MZ_ZIP_INVALID_PARAMETER, + MZ_ZIP_INVALID_FILENAME, + MZ_ZIP_BUF_TOO_SMALL, + MZ_ZIP_INTERNAL_ERROR, + MZ_ZIP_FILE_NOT_FOUND, + MZ_ZIP_ARCHIVE_TOO_LARGE, + MZ_ZIP_VALIDATION_FAILED, + MZ_ZIP_WRITE_CALLBACK_FAILED, + MZ_ZIP_TOTAL_ERRORS +} mz_zip_error; + +typedef struct +{ + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + + /* We only support up to UINT32_MAX files in zip64 mode. */ + mz_uint32 m_total_files; + mz_zip_mode m_zip_mode; + mz_zip_type m_zip_type; + mz_zip_error m_last_error; + + mz_uint64 m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + mz_file_needs_keepalive m_pNeeds_keepalive; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef struct +{ + mz_zip_archive *pZip; + mz_uint flags; + + int status; + + mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + void *pWrite_buf; + + size_t out_blk_remain; + + tinfl_decompressor inflator; + +#ifdef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + mz_uint padding; +#else + mz_uint file_crc32; +#endif + +} mz_zip_reader_extract_iter_state; + +/* -------- ZIP reading */ + +/* Inits a ZIP archive reader. */ +/* These functions read and validate the archive's central directory. */ +MINIZ_EXPORT mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); + +MINIZ_EXPORT mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +/* Read a archive from a disk file. */ +/* file_start_ofs is the file offset where the archive actually begins, or 0. */ +/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ +MINIZ_EXPORT mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); + +/* Read an archive from an already opened FILE, beginning at the current file position. */ +/* The archive is assumed to be archive_size bytes long. If archive_size is 0, then the entire rest of the file is assumed to contain the archive. */ +/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ +MINIZ_EXPORT mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); +#endif + +/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ +MINIZ_EXPORT mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +/* -------- ZIP reading or writing */ + +/* Clears a mz_zip_archive struct to all zeros. */ +/* Important: This must be done before passing the struct to any mz_zip functions. */ +MINIZ_EXPORT void mz_zip_zero_struct(mz_zip_archive *pZip); + +MINIZ_EXPORT mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); +MINIZ_EXPORT mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); + +/* Returns the total number of files in the archive. */ +MINIZ_EXPORT mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +MINIZ_EXPORT mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); +MINIZ_EXPORT mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); +MINIZ_EXPORT MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); + +/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ +MINIZ_EXPORT size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); + +/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ +/* Note that the m_last_error functionality is not thread safe. */ +MINIZ_EXPORT mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); +MINIZ_EXPORT mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); +MINIZ_EXPORT mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); +MINIZ_EXPORT mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); +MINIZ_EXPORT const char *mz_zip_get_error_string(mz_zip_error mz_err); + +/* MZ_TRUE if the archive file entry is a directory entry. */ +MINIZ_EXPORT mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the file is encrypted/strong encrypted. */ +MINIZ_EXPORT mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ +MINIZ_EXPORT mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); + +/* Retrieves the filename of an archive file entry. */ +/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ +MINIZ_EXPORT mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +MINIZ_EXPORT int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); + +/* Returns detailed information about an archive file entry. */ +MINIZ_EXPORT mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +/* MZ_TRUE if the file is in zip64 format. */ +/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ +MINIZ_EXPORT mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); + +/* Returns the total central directory size in bytes. */ +/* The current max supported size is <= MZ_UINT32_MAX. */ +MINIZ_EXPORT size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); + +/* Extracts a archive file to a memory buffer using no memory allocation. */ +/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +/* Extracts a archive file to a memory buffer. */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +/* Extracts a archive file to a dynamically allocated heap buffer. */ +/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ +/* Returns NULL and sets the last error on failure. */ +MINIZ_EXPORT void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +MINIZ_EXPORT void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +/* Extracts a archive file using a callback function to output the file's data. */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +/* Extract a file iteratively */ +MINIZ_EXPORT mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); +MINIZ_EXPORT mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); +MINIZ_EXPORT size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); + +#ifndef MINIZ_NO_STDIO +/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ +/* This function only extracts files, not archive directory records. */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); + +/* Extracts a archive file starting at the current position in the destination FILE stream. */ +MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); +#endif + +#if 0 +/* TODO */ + typedef void *mz_zip_streaming_extract_state_ptr; + mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + mz_uint64 mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_uint64 mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, mz_uint64 new_ofs); + size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); + mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); +#endif + +/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ +/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ +MINIZ_EXPORT mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + +/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ +MINIZ_EXPORT mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); + +/* Misc utils/helpers, valid for ZIP reading or writing */ +MINIZ_EXPORT mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); +#ifndef MINIZ_NO_STDIO +MINIZ_EXPORT mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); +#endif + +/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ +MINIZ_EXPORT mz_bool mz_zip_end(mz_zip_archive *pZip); + +/* -------- ZIP writing */ + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +/* Inits a ZIP archive writer. */ +/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ +/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ +MINIZ_EXPORT mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +MINIZ_EXPORT mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); + +MINIZ_EXPORT mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +MINIZ_EXPORT mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +MINIZ_EXPORT mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +MINIZ_EXPORT mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); +#endif + +/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ +/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ +/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ +/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ +/* the archive is finalized the file's central directory will be hosed. */ +MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); + +/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ +/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ +/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */ +/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/ +MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size, + const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); + + +#ifndef MINIZ_NO_STDIO +/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, + const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); +#endif + +/* Adds a file to an archive by fully cloning the data from another archive. */ +/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ +MINIZ_EXPORT mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); + +/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ +/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ +/* An archive must be manually finalized by calling this function for it to be valid. */ +MINIZ_EXPORT mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + +/* Finalizes a heap archive, returning a pointer to the heap block and its size. */ +/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ +MINIZ_EXPORT mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); + +/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ +/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ +MINIZ_EXPORT mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +/* -------- Misc. high-level helper functions: */ + +/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ +/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ +MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); + +#ifndef MINIZ_NO_STDIO +/* Reads a single file from an archive into a heap block. */ +/* If pComment is not NULL, only the file with the specified comment will be extracted. */ +/* Returns NULL on failure. */ +MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); +MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); +#endif + +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +#ifdef __cplusplus +} +#endif + +#endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/libraries/webp/AUTHORS b/libraries/webp/AUTHORS new file mode 100644 index 00000000000..8359b20da9d --- /dev/null +++ b/libraries/webp/AUTHORS @@ -0,0 +1,60 @@ +Contributors: +- Aidan O'Loan (aidanol at gmail dot com) +- Alan Browning (browning at google dot com) +- Alexandru Ardelean (ardeleanalex at gmail dot com) +- Brian Ledger (brianpl at google dot com) +- Charles Munger (clm at google dot com) +- Cheng Yi (cyi at google dot com) +- Christian Duvivier (cduvivier at google dot com) +- Christopher Degawa (ccom at randomderp dot com) +- Clement Courbet (courbet at google dot com) +- Djordje Pesut (djordje dot pesut at imgtec dot com) +- Frank Barchard (fbarchard at google dot com) +- Hui Su (huisu at google dot com) +- H. Vetinari (h dot vetinari at gmx dot com) +- Ilya Kurdyukov (jpegqs at gmail dot com) +- Ingvar Stepanyan (rreverser at google dot com) +- James Zern (jzern at google dot com) +- Jan Engelhardt (jengelh at medozas dot de) +- Jehan (jehan at girinstud dot io) +- Jeremy Maitin-Shepard (jbms at google dot com) +- Johann Koenig (johann dot koenig at duck dot com) +- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com) +- Jyrki Alakuijala (jyrki at google dot com) +- Konstantin Ivlev (tomskside at gmail dot com) +- Lode Vandevenne (lode at google dot com) +- Lou Quillio (louquillio at google dot com) +- Mans Rullgard (mans at mansr dot com) +- Marcin Kowalczyk (qrczak at google dot com) +- Martin Olsson (mnemo at minimum dot se) +- Maryla Ustarroz-Calonge (maryla at google dot com) +- Mikołaj Zalewski (mikolajz at google dot com) +- Mislav Bradac (mislavm at google dot com) +- Nico Weber (thakis at chromium dot org) +- Noel Chromium (noel at chromium dot org) +- Nozomi Isozaki (nontan at pixiv dot co dot jp) +- Oliver Wolff (oliver dot wolff at qt dot io) +- Owen Rodley (orodley at google dot com) +- Parag Salasakar (img dot mips1 at gmail dot com) +- Pascal Massimino (pascal dot massimino at gmail dot com) +- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org) +- Pierre Joye (pierre dot php at gmail dot com) +- Roberto Alanis (alanisbaez at google dot com) +- Sam Clegg (sbc at chromium dot org) +- Scott Hancher (seh at google dot com) +- Scott LaVarnway (slavarnway at google dot com) +- Scott Talbot (s at chikachow dot org) +- Slobodan Prijic (slobodan dot prijic at imgtec dot com) +- Somnath Banerjee (somnath dot banerjee at gmail dot com) +- Sriraman Tallam (tmsriram at google dot com) +- Tamar Levy (tamar dot levy at intel dot com) +- Thiago Perrotta (tperrotta at google dot com) +- Timothy Gu (timothygu99 at gmail dot com) +- Urvang Joshi (urvang at google dot com) +- Vikas Arora (vikasa at google dot com) +- Vincent Rabaud (vrabaud at google dot com) +- Vlad Tsyrklevich (vtsyrklevich at chromium dot org) +- Wan-Teh Chang (wtc at google dot com) +- Yang Zhang (yang dot zhang at arm dot com) +- Yannis Guyon (yguyon at google dot com) +- Zhi An Ng (zhin at chromium dot org) diff --git a/libraries/webp/CMakeLists.txt b/libraries/webp/CMakeLists.txt new file mode 100644 index 00000000000..9bd3fa9f70a --- /dev/null +++ b/libraries/webp/CMakeLists.txt @@ -0,0 +1,211 @@ +cmake_minimum_required(VERSION 3.11) +project(webp) + +set(WEBP_SOURCES + src/dec/alphai_dec.h + src/dec/alpha_dec.c + src/dec/buffer_dec.c + src/dec/common_dec.h + src/dec/frame_dec.c + src/dec/idec_dec.c + src/dec/io_dec.c + src/dec/quant_dec.c + src/dec/tree_dec.c + src/dec/vp8i_dec.h + src/dec/vp8li_dec.h + src/dec/vp8l_dec.c + src/dec/vp8_dec.c + src/dec/vp8_dec.h + src/dec/webpi_dec.h + src/dec/webp_dec.c + src/demux/anim_decode.c + src/demux/demux.c + src/dsp/alpha_processing.c + src/dsp/alpha_processing_mips_dsp_r2.c + src/dsp/alpha_processing_neon.c + src/dsp/alpha_processing_sse2.c + src/dsp/alpha_processing_sse41.c + src/dsp/common_sse2.h + src/dsp/common_sse41.h + src/dsp/cost.c + src/dsp/cost_mips32.c + src/dsp/cost_mips_dsp_r2.c + src/dsp/cost_neon.c + src/dsp/cost_sse2.c + src/dsp/cpu.c + src/dsp/cpu.h + src/dsp/dec.c + src/dsp/dec_clip_tables.c + src/dsp/dec_mips32.c + src/dsp/dec_mips_dsp_r2.c + src/dsp/dec_msa.c + src/dsp/dec_neon.c + src/dsp/dec_sse2.c + src/dsp/dec_sse41.c + src/dsp/dsp.h + src/dsp/enc.c + src/dsp/enc_mips32.c + src/dsp/enc_mips_dsp_r2.c + src/dsp/enc_msa.c + src/dsp/enc_neon.c + src/dsp/enc_sse2.c + src/dsp/enc_sse41.c + src/dsp/filters.c + src/dsp/filters_mips_dsp_r2.c + src/dsp/filters_msa.c + src/dsp/filters_neon.c + src/dsp/filters_sse2.c + src/dsp/lossless.c + src/dsp/lossless.h + src/dsp/lossless_common.h + src/dsp/lossless_enc.c + src/dsp/lossless_enc_mips32.c + src/dsp/lossless_enc_mips_dsp_r2.c + src/dsp/lossless_enc_msa.c + src/dsp/lossless_enc_neon.c + src/dsp/lossless_enc_sse2.c + src/dsp/lossless_enc_sse41.c + src/dsp/lossless_mips_dsp_r2.c + src/dsp/lossless_msa.c + src/dsp/lossless_neon.c + src/dsp/lossless_sse2.c + src/dsp/lossless_sse41.c + src/dsp/mips_macro.h + src/dsp/msa_macro.h + src/dsp/neon.h + src/dsp/quant.h + src/dsp/rescaler.c + src/dsp/rescaler_mips32.c + src/dsp/rescaler_mips_dsp_r2.c + src/dsp/rescaler_msa.c + src/dsp/rescaler_neon.c + src/dsp/rescaler_sse2.c + src/dsp/ssim.c + src/dsp/ssim_sse2.c + src/dsp/upsampling.c + src/dsp/upsampling_mips_dsp_r2.c + src/dsp/upsampling_msa.c + src/dsp/upsampling_neon.c + src/dsp/upsampling_sse2.c + src/dsp/upsampling_sse41.c + src/dsp/yuv.c + src/dsp/yuv.h + src/dsp/yuv_mips32.c + src/dsp/yuv_mips_dsp_r2.c + src/dsp/yuv_neon.c + src/dsp/yuv_sse2.c + src/dsp/yuv_sse41.c + src/enc/alpha_enc.c + src/enc/analysis_enc.c + src/enc/backward_references_cost_enc.c + src/enc/backward_references_enc.c + src/enc/backward_references_enc.h + src/enc/config_enc.c + src/enc/cost_enc.c + src/enc/cost_enc.h + src/enc/filter_enc.c + src/enc/frame_enc.c + src/enc/histogram_enc.c + src/enc/histogram_enc.h + src/enc/iterator_enc.c + src/enc/near_lossless_enc.c + src/enc/picture_csp_enc.c + src/enc/picture_enc.c + src/enc/picture_psnr_enc.c + src/enc/picture_rescale_enc.c + src/enc/picture_tools_enc.c + src/enc/predictor_enc.c + src/enc/quant_enc.c + src/enc/syntax_enc.c + src/enc/token_enc.c + src/enc/tree_enc.c + src/enc/vp8i_enc.h + src/enc/vp8li_enc.h + src/enc/vp8l_enc.c + src/enc/webp_enc.c + src/mux/animi.h + src/mux/anim_encode.c + src/mux/muxedit.c + src/mux/muxi.h + src/mux/muxinternal.c + src/mux/muxread.c + src/utils/bit_reader_inl_utils.h + src/utils/bit_reader_utils.c + src/utils/bit_reader_utils.h + src/utils/bit_writer_utils.c + src/utils/bit_writer_utils.h + src/utils/color_cache_utils.c + src/utils/color_cache_utils.h + src/utils/endian_inl_utils.h + src/utils/filters_utils.c + src/utils/filters_utils.h + src/utils/huffman_encode_utils.c + src/utils/huffman_encode_utils.h + src/utils/huffman_utils.c + src/utils/huffman_utils.h + src/utils/palette.c + src/utils/palette.h + src/utils/quant_levels_dec_utils.c + src/utils/quant_levels_dec_utils.h + src/utils/quant_levels_utils.c + src/utils/quant_levels_utils.h + src/utils/random_utils.c + src/utils/random_utils.h + src/utils/rescaler_utils.c + src/utils/rescaler_utils.h + src/utils/thread_utils.c + src/utils/thread_utils.h + src/utils/utils.c + src/utils/utils.h + sharpyuv/sharpyuv.c + sharpyuv/sharpyuv.h + sharpyuv/sharpyuv_cpu.c + sharpyuv/sharpyuv_cpu.h + sharpyuv/sharpyuv_csp.c + sharpyuv/sharpyuv_csp.h + sharpyuv/sharpyuv_dsp.c + sharpyuv/sharpyuv_dsp.h + sharpyuv/sharpyuv_gamma.c + sharpyuv/sharpyuv_gamma.h + sharpyuv/sharpyuv_neon.c + sharpyuv/sharpyuv_sse2.c +) + +set(WEBP_INCLUDES + include/webp/decode.h + include/webp/demux.h + include/webp/encode.h + include/webp/format_constants.h + include/webp/mux.h + include/webp/mux_types.h + include/webp/types.h +) + +source_group("src" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/.+") +source_group("src\\dec" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/dec/.+") +source_group("src\\demux" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/demux/.+") +source_group("src\\dsp" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/dsp/.+") +source_group("src\\enc" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/enc/.+") +source_group("src\\mux" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/mux/.+") +source_group("src\\utils" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/.+") +source_group("sharpyuv" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/.+") +source_group("include" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/webp/.+") +source_group("include\\webp" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/webp/core/.+") + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +if(MSVC) + # Use all cores for compilation + set(CMAKE_CXX_FLAGS "/MP ${CMAKE_CXX_FLAGS}") + + # Ignore warnings in third party code + #set_source_files_properties(${WEBP_SOURCES} PROPERTIES COMPILE_FLAGS "/wd4244 /wd4267 /wd4005 /wd4018 -D_CRT_SECURE_NO_WARNINGS") +endif() + +add_library(webp STATIC ${WEBP_SOURCES} ${WEBP_INCLUDES}) +target_link_libraries(webp ${WEBP_LIBS}) +set_target_properties(webp PROPERTIES CXX_STANDARD 17) + +if(MSVC) + set_property(TARGET webp PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +endif() diff --git a/libraries/webp/COPYING b/libraries/webp/COPYING new file mode 100644 index 00000000000..7a6f99547d4 --- /dev/null +++ b/libraries/webp/COPYING @@ -0,0 +1,30 @@ +Copyright (c) 2010, Google Inc. 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 Google 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 +HOLDER 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/libraries/webp/PATENTS b/libraries/webp/PATENTS new file mode 100644 index 00000000000..caedf607e95 --- /dev/null +++ b/libraries/webp/PATENTS @@ -0,0 +1,23 @@ +Additional IP Rights Grant (Patents) +------------------------------------ + +"These implementations" means the copyrightable works that implement the WebM +codecs distributed by Google as part of the WebM Project. + +Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable (except as stated in this section) patent license to +make, have made, use, offer to sell, sell, import, transfer, and otherwise +run, modify and propagate the contents of these implementations of WebM, where +such license applies only to those patent claims, both currently owned by +Google and acquired in the future, licensable by Google that are necessarily +infringed by these implementations of WebM. This grant does not include claims +that would be infringed only as a consequence of further modification of these +implementations. If you or your agent or exclusive licensee institute or order +or agree to the institution of patent litigation or any other patent +enforcement activity against any entity (including a cross-claim or +counterclaim in a lawsuit) alleging that any of these implementations of WebM +or any code incorporated within any of these implementations of WebM +constitute direct or contributory patent infringement, or inducement of +patent infringement, then any patent rights granted to you under this License +for these implementations of WebM shall terminate as of the date such +litigation is filed. diff --git a/libraries/webp/README.md b/libraries/webp/README.md new file mode 100644 index 00000000000..a9f2c0e12b7 --- /dev/null +++ b/libraries/webp/README.md @@ -0,0 +1,53 @@ +# WebP Codec + +``` + __ __ ____ ____ ____ + / \\/ \/ _ \/ _ )/ _ \ + \ / __/ _ \ __/ + \__\__/\____/\_____/__/ ____ ___ + / _/ / \ \ / _ \/ _/ + / \_/ / / \ \ __/ \__ + \____/____/\_____/_____/____/v1.3.2 +``` + +WebP codec is a library to encode and decode images in WebP format. This package +contains the library that can be used in other programs to add WebP support, as +well as the command line tools 'cwebp' and 'dwebp' to compress and decompress +images respectively. + +See https://developers.google.com/speed/webp for details on the image format. + +The latest source tree is available at +https://chromium.googlesource.com/webm/libwebp + +It is released under the same license as the WebM project. See +https://www.webmproject.org/license/software/ or the "COPYING" file for details. +An additional intellectual property rights grant can be found in the file +PATENTS. + +## Building + +See the [building documentation](doc/building.md). + +## Encoding and Decoding Tools + +The examples/ directory contains tools to encode and decode images and +animations, view information about WebP images, and more. See the +[tools documentation](doc/tools.md). + +## APIs + +See the [APIs documentation](doc/api.md), and API usage examples in the +`examples/` directory. + +## Bugs + +Please report all bugs to the issue tracker: https://bugs.chromium.org/p/webp + +Patches welcome! See [how to contribute](CONTRIBUTING.md). + +## Discuss + +Email: webp-discuss@webmproject.org + +Web: https://groups.google.com/a/webmproject.org/group/webp-discuss diff --git a/libraries/webp/include/webp/decode.h b/libraries/webp/include/webp/decode.h new file mode 100644 index 00000000000..d6895f5c555 --- /dev/null +++ b/libraries/webp/include/webp/decode.h @@ -0,0 +1,506 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Main decoding functions for WebP images. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_WEBP_DECODE_H_ +#define WEBP_WEBP_DECODE_H_ + +#include "./types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WEBP_DECODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b) + +// Note: forward declaring enumerations is not allowed in (strict) C and C++, +// the types are left here for reference. +// typedef enum VP8StatusCode VP8StatusCode; +// typedef enum WEBP_CSP_MODE WEBP_CSP_MODE; +typedef struct WebPRGBABuffer WebPRGBABuffer; +typedef struct WebPYUVABuffer WebPYUVABuffer; +typedef struct WebPDecBuffer WebPDecBuffer; +typedef struct WebPIDecoder WebPIDecoder; +typedef struct WebPBitstreamFeatures WebPBitstreamFeatures; +typedef struct WebPDecoderOptions WebPDecoderOptions; +typedef struct WebPDecoderConfig WebPDecoderConfig; + +// Return the decoder's version number, packed in hexadecimal using 8bits for +// each of major/minor/revision. E.g: v2.5.7 is 0x020507. +WEBP_EXTERN int WebPGetDecoderVersion(void); + +// Retrieve basic header information: width, height. +// This function will also validate the header, returning true on success, +// false otherwise. '*width' and '*height' are only valid on successful return. +// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant. +// Note: The following chunk sequences (before the raw VP8/VP8L data) are +// considered valid by this function: +// RIFF + VP8(L) +// RIFF + VP8X + (optional chunks) + VP8(L) +// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. +// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. +WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo( + const uint8_t* data, size_t data_size, int* width, int* height); + +// Decodes WebP images pointed to by 'data' and returns RGBA samples, along +// with the dimensions in *width and *height. The ordering of samples in +// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent). +// The returned pointer should be deleted calling WebPFree(). +// Returns NULL in case of error. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA( + const uint8_t* data, size_t data_size, int* width, int* height); + +// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB( + const uint8_t* data, size_t data_size, int* width, int* height); + +// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA( + const uint8_t* data, size_t data_size, int* width, int* height); + +// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data. +// If the bitstream contains transparency, it is ignored. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB( + const uint8_t* data, size_t data_size, int* width, int* height); + +// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR( + const uint8_t* data, size_t data_size, int* width, int* height); + +// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer +// returned is the Y samples buffer. Upon return, *u and *v will point to +// the U and V chroma data. These U and V buffers need NOT be passed to +// WebPFree(), unlike the returned Y luma one. The dimension of the U and V +// planes are both (*width + 1) / 2 and (*height + 1) / 2. +// Upon return, the Y buffer has a stride returned as '*stride', while U and V +// have a common stride returned as '*uv_stride'. +// 'width' and 'height' may be NULL, the other pointers must not be. +// Returns NULL in case of error. +// (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV( + const uint8_t* data, size_t data_size, int* width, int* height, + uint8_t** u, uint8_t** v, int* stride, int* uv_stride); + +// These five functions are variants of the above ones, that decode the image +// directly into a pre-allocated buffer 'output_buffer'. The maximum storage +// available in this buffer is indicated by 'output_buffer_size'. If this +// storage is not sufficient (or an error occurred), NULL is returned. +// Otherwise, output_buffer is returned, for convenience. +// The parameter 'output_stride' specifies the distance (in bytes) +// between scanlines. Hence, output_buffer_size is expected to be at least +// output_stride x picture-height. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBAInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGBInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRAInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); + +// RGB and BGR variants. Here too the transparency information, if present, +// will be dropped and ignored. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); + +// WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly +// into pre-allocated luma/chroma plane buffers. This function requires the +// strides to be passed: one for the luma plane and one for each of the +// chroma ones. The size of each plane buffer is passed as 'luma_size', +// 'u_size' and 'v_size' respectively. +// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred +// during decoding (or because some buffers were found to be too small). +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUVInto( + const uint8_t* data, size_t data_size, + uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride); + +//------------------------------------------------------------------------------ +// Output colorspaces and buffer + +// Colorspaces +// Note: the naming describes the byte-ordering of packed samples in memory. +// For instance, MODE_BGRA relates to samples ordered as B,G,R,A,B,G,R,A,... +// Non-capital names (e.g.:MODE_Argb) relates to pre-multiplied RGB channels. +// RGBA-4444 and RGB-565 colorspaces are represented by following byte-order: +// RGBA-4444: [r3 r2 r1 r0 g3 g2 g1 g0], [b3 b2 b1 b0 a3 a2 a1 a0], ... +// RGB-565: [r4 r3 r2 r1 r0 g5 g4 g3], [g2 g1 g0 b4 b3 b2 b1 b0], ... +// In the case WEBP_SWAP_16BITS_CSP is defined, the bytes are swapped for +// these two modes: +// RGBA-4444: [b3 b2 b1 b0 a3 a2 a1 a0], [r3 r2 r1 r0 g3 g2 g1 g0], ... +// RGB-565: [g2 g1 g0 b4 b3 b2 b1 b0], [r4 r3 r2 r1 r0 g5 g4 g3], ... + +typedef enum WEBP_CSP_MODE { + MODE_RGB = 0, MODE_RGBA = 1, + MODE_BGR = 2, MODE_BGRA = 3, + MODE_ARGB = 4, MODE_RGBA_4444 = 5, + MODE_RGB_565 = 6, + // RGB-premultiplied transparent modes (alpha value is preserved) + MODE_rgbA = 7, + MODE_bgrA = 8, + MODE_Argb = 9, + MODE_rgbA_4444 = 10, + // YUV modes must come after RGB ones. + MODE_YUV = 11, MODE_YUVA = 12, // yuv 4:2:0 + MODE_LAST = 13 +} WEBP_CSP_MODE; + +// Some useful macros: +static WEBP_INLINE int WebPIsPremultipliedMode(WEBP_CSP_MODE mode) { + return (mode == MODE_rgbA || mode == MODE_bgrA || mode == MODE_Argb || + mode == MODE_rgbA_4444); +} + +static WEBP_INLINE int WebPIsAlphaMode(WEBP_CSP_MODE mode) { + return (mode == MODE_RGBA || mode == MODE_BGRA || mode == MODE_ARGB || + mode == MODE_RGBA_4444 || mode == MODE_YUVA || + WebPIsPremultipliedMode(mode)); +} + +static WEBP_INLINE int WebPIsRGBMode(WEBP_CSP_MODE mode) { + return (mode < MODE_YUV); +} + +//------------------------------------------------------------------------------ +// WebPDecBuffer: Generic structure for describing the output sample buffer. + +struct WebPRGBABuffer { // view as RGBA + uint8_t* rgba; // pointer to RGBA samples + int stride; // stride in bytes from one scanline to the next. + size_t size; // total size of the *rgba buffer. +}; + +struct WebPYUVABuffer { // view as YUVA + uint8_t* y, *u, *v, *a; // pointer to luma, chroma U/V, alpha samples + int y_stride; // luma stride + int u_stride, v_stride; // chroma strides + int a_stride; // alpha stride + size_t y_size; // luma plane size + size_t u_size, v_size; // chroma planes size + size_t a_size; // alpha-plane size +}; + +// Output buffer +struct WebPDecBuffer { + WEBP_CSP_MODE colorspace; // Colorspace. + int width, height; // Dimensions. + int is_external_memory; // If non-zero, 'internal_memory' pointer is not + // used. If value is '2' or more, the external + // memory is considered 'slow' and multiple + // read/write will be avoided. + union { + WebPRGBABuffer RGBA; + WebPYUVABuffer YUVA; + } u; // Nameless union of buffer parameters. + uint32_t pad[4]; // padding for later use + + uint8_t* private_memory; // Internally allocated memory (only when + // is_external_memory is 0). Should not be used + // externally, but accessed via the buffer union. +}; + +// Internal, version-checked, entry point +WEBP_NODISCARD WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int); + +// Initialize the structure as empty. Must be called before any other use. +// Returns false in case of version mismatch +WEBP_NODISCARD static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) { + return WebPInitDecBufferInternal(buffer, WEBP_DECODER_ABI_VERSION); +} + +// Free any memory associated with the buffer. Must always be called last. +// Note: doesn't free the 'buffer' structure itself. +WEBP_EXTERN void WebPFreeDecBuffer(WebPDecBuffer* buffer); + +//------------------------------------------------------------------------------ +// Enumeration of the status codes + +typedef enum WEBP_NODISCARD VP8StatusCode { + VP8_STATUS_OK = 0, + VP8_STATUS_OUT_OF_MEMORY, + VP8_STATUS_INVALID_PARAM, + VP8_STATUS_BITSTREAM_ERROR, + VP8_STATUS_UNSUPPORTED_FEATURE, + VP8_STATUS_SUSPENDED, + VP8_STATUS_USER_ABORT, + VP8_STATUS_NOT_ENOUGH_DATA +} VP8StatusCode; + +//------------------------------------------------------------------------------ +// Incremental decoding +// +// This API allows streamlined decoding of partial data. +// Picture can be incrementally decoded as data become available thanks to the +// WebPIDecoder object. This object can be left in a SUSPENDED state if the +// picture is only partially decoded, pending additional input. +// Code example: +/* + WebPInitDecBuffer(&output_buffer); + output_buffer.colorspace = mode; + ... + WebPIDecoder* idec = WebPINewDecoder(&output_buffer); + while (additional_data_is_available) { + // ... (get additional data in some new_data[] buffer) + status = WebPIAppend(idec, new_data, new_data_size); + if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) { + break; // an error occurred. + } + + // The above call decodes the current available buffer. + // Part of the image can now be refreshed by calling + // WebPIDecGetRGB()/WebPIDecGetYUVA() etc. + } + WebPIDelete(idec); +*/ + +// Creates a new incremental decoder with the supplied buffer parameter. +// This output_buffer can be passed NULL, in which case a default output buffer +// is used (with MODE_RGB). Otherwise, an internal reference to 'output_buffer' +// is kept, which means that the lifespan of 'output_buffer' must be larger than +// that of the returned WebPIDecoder object. +// The supplied 'output_buffer' content MUST NOT be changed between calls to +// WebPIAppend() or WebPIUpdate() unless 'output_buffer.is_external_memory' is +// not set to 0. In such a case, it is allowed to modify the pointers, size and +// stride of output_buffer.u.RGBA or output_buffer.u.YUVA, provided they remain +// within valid bounds. +// All other fields of WebPDecBuffer MUST remain constant between calls. +// Returns NULL if the allocation failed. +WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewDecoder( + WebPDecBuffer* output_buffer); + +// This function allocates and initializes an incremental-decoder object, which +// will output the RGB/A samples specified by 'csp' into a preallocated +// buffer 'output_buffer'. The size of this buffer is at least +// 'output_buffer_size' and the stride (distance in bytes between two scanlines) +// is specified by 'output_stride'. +// Additionally, output_buffer can be passed NULL in which case the output +// buffer will be allocated automatically when the decoding starts. The +// colorspace 'csp' is taken into account for allocating this buffer. All other +// parameters are ignored. +// Returns NULL if the allocation failed, or if some parameters are invalid. +WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB( + WEBP_CSP_MODE csp, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); + +// This function allocates and initializes an incremental-decoder object, which +// will output the raw luma/chroma samples into a preallocated planes if +// supplied. The luma plane is specified by its pointer 'luma', its size +// 'luma_size' and its stride 'luma_stride'. Similarly, the chroma-u plane +// is specified by the 'u', 'u_size' and 'u_stride' parameters, and the chroma-v +// plane by 'v' and 'v_size'. And same for the alpha-plane. The 'a' pointer +// can be pass NULL in case one is not interested in the transparency plane. +// Conversely, 'luma' can be passed NULL if no preallocated planes are supplied. +// In this case, the output buffer will be automatically allocated (using +// MODE_YUVA) when decoding starts. All parameters are then ignored. +// Returns NULL if the allocation failed or if a parameter is invalid. +WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUVA( + uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride, + uint8_t* a, size_t a_size, int a_stride); + +// Deprecated version of the above, without the alpha plane. +// Kept for backward compatibility. +WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUV( + uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride); + +// Deletes the WebPIDecoder object and associated memory. Must always be called +// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded. +WEBP_EXTERN void WebPIDelete(WebPIDecoder* idec); + +// Copies and decodes the next available data. Returns VP8_STATUS_OK when +// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more +// data is expected. Returns error in other cases. +WEBP_EXTERN VP8StatusCode WebPIAppend( + WebPIDecoder* idec, const uint8_t* data, size_t data_size); + +// A variant of the above function to be used when data buffer contains +// partial data from the beginning. In this case data buffer is not copied +// to the internal memory. +// Note that the value of the 'data' pointer can change between calls to +// WebPIUpdate, for instance when the data buffer is resized to fit larger data. +WEBP_EXTERN VP8StatusCode WebPIUpdate( + WebPIDecoder* idec, const uint8_t* data, size_t data_size); + +// Returns the RGB/A image decoded so far. Returns NULL if output params +// are not initialized yet. The RGB/A output type corresponds to the colorspace +// specified during call to WebPINewDecoder() or WebPINewRGB(). +// *last_y is the index of last decoded row in raster scan order. Some pointers +// (*last_y, *width etc.) can be NULL if corresponding information is not +// needed. The values in these pointers are only valid on successful (non-NULL) +// return. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPIDecGetRGB( + const WebPIDecoder* idec, int* last_y, + int* width, int* height, int* stride); + +// Same as above function to get a YUVA image. Returns pointer to the luma +// plane or NULL in case of error. If there is no alpha information +// the alpha pointer '*a' will be returned NULL. +WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPIDecGetYUVA( + const WebPIDecoder* idec, int* last_y, + uint8_t** u, uint8_t** v, uint8_t** a, + int* width, int* height, int* stride, int* uv_stride, int* a_stride); + +// Deprecated alpha-less version of WebPIDecGetYUVA(): it will ignore the +// alpha information (if present). Kept for backward compatibility. +WEBP_NODISCARD static WEBP_INLINE uint8_t* WebPIDecGetYUV( + const WebPIDecoder* idec, int* last_y, uint8_t** u, uint8_t** v, + int* width, int* height, int* stride, int* uv_stride) { + return WebPIDecGetYUVA(idec, last_y, u, v, NULL, width, height, + stride, uv_stride, NULL); +} + +// Generic call to retrieve information about the displayable area. +// If non NULL, the left/right/width/height pointers are filled with the visible +// rectangular area so far. +// Returns NULL in case the incremental decoder object is in an invalid state. +// Otherwise returns the pointer to the internal representation. This structure +// is read-only, tied to WebPIDecoder's lifespan and should not be modified. +WEBP_NODISCARD WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea( + const WebPIDecoder* idec, int* left, int* top, int* width, int* height); + +//------------------------------------------------------------------------------ +// Advanced decoding parametrization +// +// Code sample for using the advanced decoding API +/* + // A) Init a configuration object + WebPDecoderConfig config; + CHECK(WebPInitDecoderConfig(&config)); + + // B) optional: retrieve the bitstream's features. + CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK); + + // C) Adjust 'config', if needed + config.options.no_fancy_upsampling = 1; + config.output.colorspace = MODE_BGRA; + // etc. + + // Note that you can also make config.output point to an externally + // supplied memory buffer, provided it's big enough to store the decoded + // picture. Otherwise, config.output will just be used to allocate memory + // and store the decoded picture. + + // D) Decode! + CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK); + + // E) Decoded image is now in config.output (and config.output.u.RGBA) + + // F) Reclaim memory allocated in config's object. It's safe to call + // this function even if the memory is external and wasn't allocated + // by WebPDecode(). + WebPFreeDecBuffer(&config.output); +*/ + +// Features gathered from the bitstream +struct WebPBitstreamFeatures { + int width; // Width in pixels, as read from the bitstream. + int height; // Height in pixels, as read from the bitstream. + int has_alpha; // True if the bitstream contains an alpha channel. + int has_animation; // True if the bitstream is an animation. + int format; // 0 = undefined (/mixed), 1 = lossy, 2 = lossless + + uint32_t pad[5]; // padding for later use +}; + +// Internal, version-checked, entry point +WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal( + const uint8_t*, size_t, WebPBitstreamFeatures*, int); + +// Retrieve features from the bitstream. The *features structure is filled +// with information gathered from the bitstream. +// Returns VP8_STATUS_OK when the features are successfully retrieved. Returns +// VP8_STATUS_NOT_ENOUGH_DATA when more data is needed to retrieve the +// features from headers. Returns error in other cases. +// Note: The following chunk sequences (before the raw VP8/VP8L data) are +// considered valid by this function: +// RIFF + VP8(L) +// RIFF + VP8X + (optional chunks) + VP8(L) +// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. +// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. +static WEBP_INLINE VP8StatusCode WebPGetFeatures( + const uint8_t* data, size_t data_size, + WebPBitstreamFeatures* features) { + return WebPGetFeaturesInternal(data, data_size, features, + WEBP_DECODER_ABI_VERSION); +} + +// Decoding options +struct WebPDecoderOptions { + int bypass_filtering; // if true, skip the in-loop filtering + int no_fancy_upsampling; // if true, use faster pointwise upsampler + int use_cropping; // if true, cropping is applied _first_ + int crop_left, crop_top; // top-left position for cropping. + // Will be snapped to even values. + int crop_width, crop_height; // dimension of the cropping area + int use_scaling; // if true, scaling is applied _afterward_ + int scaled_width, scaled_height; // final resolution + int use_threads; // if true, use multi-threaded decoding + int dithering_strength; // dithering strength (0=Off, 100=full) + int flip; // if true, flip output vertically + int alpha_dithering_strength; // alpha dithering strength in [0..100] + + uint32_t pad[5]; // padding for later use +}; + +// Main object storing the configuration for advanced decoding. +struct WebPDecoderConfig { + WebPBitstreamFeatures input; // Immutable bitstream features (optional) + WebPDecBuffer output; // Output buffer (can point to external mem) + WebPDecoderOptions options; // Decoding options +}; + +// Internal, version-checked, entry point +WEBP_NODISCARD WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*, + int); + +// Initialize the configuration as empty. This function must always be +// called first, unless WebPGetFeatures() is to be called. +// Returns false in case of mismatched version. +WEBP_NODISCARD static WEBP_INLINE int WebPInitDecoderConfig( + WebPDecoderConfig* config) { + return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION); +} + +// Instantiate a new incremental decoder object with the requested +// configuration. The bitstream can be passed using 'data' and 'data_size' +// parameter, in which case the features will be parsed and stored into +// config->input. Otherwise, 'data' can be NULL and no parsing will occur. +// Note that 'config' can be NULL too, in which case a default configuration +// is used. If 'config' is not NULL, it must outlive the WebPIDecoder object +// as some references to its fields will be used. No internal copy of 'config' +// is made. +// The return WebPIDecoder object must always be deleted calling WebPIDelete(). +// Returns NULL in case of error (and config->status will then reflect +// the error condition, if available). +WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode( + const uint8_t* data, size_t data_size, WebPDecoderConfig* config); + +// Non-incremental version. This version decodes the full data at once, taking +// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK +// if the decoding was successful). Note that 'config' cannot be NULL. +WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, + WebPDecoderConfig* config); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_WEBP_DECODE_H_ diff --git a/libraries/webp/include/webp/demux.h b/libraries/webp/include/webp/demux.h new file mode 100644 index 00000000000..8d246550ca6 --- /dev/null +++ b/libraries/webp/include/webp/demux.h @@ -0,0 +1,367 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Demux API. +// Enables extraction of image and extended format data from WebP files. + +// Code Example: Demuxing WebP data to extract all the frames, ICC profile +// and EXIF/XMP metadata. +/* + WebPDemuxer* demux = WebPDemux(&webp_data); + + uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH); + uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT); + // ... (Get information about the features present in the WebP file). + uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS); + + // ... (Iterate over all frames). + WebPIterator iter; + if (WebPDemuxGetFrame(demux, 1, &iter)) { + do { + // ... (Consume 'iter'; e.g. Decode 'iter.fragment' with WebPDecode(), + // ... and get other frame properties like width, height, offsets etc. + // ... see 'struct WebPIterator' below for more info). + } while (WebPDemuxNextFrame(&iter)); + WebPDemuxReleaseIterator(&iter); + } + + // ... (Extract metadata). + WebPChunkIterator chunk_iter; + if (flags & ICCP_FLAG) WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter); + // ... (Consume the ICC profile in 'chunk_iter.chunk'). + WebPDemuxReleaseChunkIterator(&chunk_iter); + if (flags & EXIF_FLAG) WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter); + // ... (Consume the EXIF metadata in 'chunk_iter.chunk'). + WebPDemuxReleaseChunkIterator(&chunk_iter); + if (flags & XMP_FLAG) WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter); + // ... (Consume the XMP metadata in 'chunk_iter.chunk'). + WebPDemuxReleaseChunkIterator(&chunk_iter); + WebPDemuxDelete(demux); +*/ + +#ifndef WEBP_WEBP_DEMUX_H_ +#define WEBP_WEBP_DEMUX_H_ + +#include "./decode.h" // for WEBP_CSP_MODE +#include "./mux_types.h" +#include "./types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WEBP_DEMUX_ABI_VERSION 0x0107 // MAJOR(8b) + MINOR(8b) + +// Note: forward declaring enumerations is not allowed in (strict) C and C++, +// the types are left here for reference. +// typedef enum WebPDemuxState WebPDemuxState; +// typedef enum WebPFormatFeature WebPFormatFeature; +typedef struct WebPDemuxer WebPDemuxer; +typedef struct WebPIterator WebPIterator; +typedef struct WebPChunkIterator WebPChunkIterator; +typedef struct WebPAnimInfo WebPAnimInfo; +typedef struct WebPAnimDecoderOptions WebPAnimDecoderOptions; + +//------------------------------------------------------------------------------ + +// Returns the version number of the demux library, packed in hexadecimal using +// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507. +WEBP_EXTERN int WebPGetDemuxVersion(void); + +//------------------------------------------------------------------------------ +// Life of a Demux object + +typedef enum WebPDemuxState { + WEBP_DEMUX_PARSE_ERROR = -1, // An error occurred while parsing. + WEBP_DEMUX_PARSING_HEADER = 0, // Not enough data to parse full header. + WEBP_DEMUX_PARSED_HEADER = 1, // Header parsing complete, + // data may be available. + WEBP_DEMUX_DONE = 2 // Entire file has been parsed. +} WebPDemuxState; + +// Internal, version-checked, entry point +WEBP_NODISCARD WEBP_EXTERN WebPDemuxer* WebPDemuxInternal( + const WebPData*, int, WebPDemuxState*, int); + +// Parses the full WebP file given by 'data'. For single images the WebP file +// header alone or the file header and the chunk header may be absent. +// Returns a WebPDemuxer object on successful parse, NULL otherwise. +WEBP_NODISCARD static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) { + return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION); +} + +// Parses the possibly incomplete WebP file given by 'data'. +// If 'state' is non-NULL it will be set to indicate the status of the demuxer. +// Returns NULL in case of error or if there isn't enough data to start parsing; +// and a WebPDemuxer object on successful parse. +// Note that WebPDemuxer keeps internal pointers to 'data' memory segment. +// If this data is volatile, the demuxer object should be deleted (by calling +// WebPDemuxDelete()) and WebPDemuxPartial() called again on the new data. +// This is usually an inexpensive operation. +WEBP_NODISCARD static WEBP_INLINE WebPDemuxer* WebPDemuxPartial( + const WebPData* data, WebPDemuxState* state) { + return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION); +} + +// Frees memory associated with 'dmux'. +WEBP_EXTERN void WebPDemuxDelete(WebPDemuxer* dmux); + +//------------------------------------------------------------------------------ +// Data/information extraction. + +typedef enum WebPFormatFeature { + WEBP_FF_FORMAT_FLAGS, // bit-wise combination of WebPFeatureFlags + // corresponding to the 'VP8X' chunk (if present). + WEBP_FF_CANVAS_WIDTH, + WEBP_FF_CANVAS_HEIGHT, + WEBP_FF_LOOP_COUNT, // only relevant for animated file + WEBP_FF_BACKGROUND_COLOR, // idem. + WEBP_FF_FRAME_COUNT // Number of frames present in the demux object. + // In case of a partial demux, this is the number + // of frames seen so far, with the last frame + // possibly being partial. +} WebPFormatFeature; + +// Get the 'feature' value from the 'dmux'. +// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial() +// returned a state > WEBP_DEMUX_PARSING_HEADER. +// If 'feature' is WEBP_FF_FORMAT_FLAGS, the returned value is a bit-wise +// combination of WebPFeatureFlags values. +// If 'feature' is WEBP_FF_LOOP_COUNT, WEBP_FF_BACKGROUND_COLOR, the returned +// value is only meaningful if the bitstream is animated. +WEBP_EXTERN uint32_t WebPDemuxGetI( + const WebPDemuxer* dmux, WebPFormatFeature feature); + +//------------------------------------------------------------------------------ +// Frame iteration. + +struct WebPIterator { + int frame_num; + int num_frames; // equivalent to WEBP_FF_FRAME_COUNT. + int x_offset, y_offset; // offset relative to the canvas. + int width, height; // dimensions of this frame. + int duration; // display duration in milliseconds. + WebPMuxAnimDispose dispose_method; // dispose method for the frame. + int complete; // true if 'fragment' contains a full frame. partial images + // may still be decoded with the WebP incremental decoder. + WebPData fragment; // The frame given by 'frame_num'. Note for historical + // reasons this is called a fragment. + int has_alpha; // True if the frame contains transparency. + WebPMuxAnimBlend blend_method; // Blend operation for the frame. + + uint32_t pad[2]; // padding for later use. + void* private_; // for internal use only. +}; + +// Retrieves frame 'frame_number' from 'dmux'. +// 'iter->fragment' points to the frame on return from this function. +// Setting 'frame_number' equal to 0 will return the last frame of the image. +// Returns false if 'dmux' is NULL or frame 'frame_number' is not present. +// Call WebPDemuxReleaseIterator() when use of the iterator is complete. +// NOTE: 'dmux' must persist for the lifetime of 'iter'. +WEBP_NODISCARD WEBP_EXTERN int WebPDemuxGetFrame( + const WebPDemuxer* dmux, int frame_number, WebPIterator* iter); + +// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or +// previous ('iter->frame_num' - 1) frame. These functions do not loop. +// Returns true on success, false otherwise. +WEBP_NODISCARD WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter); +WEBP_NODISCARD WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter); + +// Releases any memory associated with 'iter'. +// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same +// iter. Also, must be called before destroying the associated WebPDemuxer with +// WebPDemuxDelete(). +WEBP_EXTERN void WebPDemuxReleaseIterator(WebPIterator* iter); + +//------------------------------------------------------------------------------ +// Chunk iteration. + +struct WebPChunkIterator { + // The current and total number of chunks with the fourcc given to + // WebPDemuxGetChunk(). + int chunk_num; + int num_chunks; + WebPData chunk; // The payload of the chunk. + + uint32_t pad[6]; // padding for later use + void* private_; +}; + +// Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from +// 'dmux'. +// 'fourcc' is a character array containing the fourcc of the chunk to return, +// e.g., "ICCP", "XMP ", "EXIF", etc. +// Setting 'chunk_number' equal to 0 will return the last chunk in a set. +// Returns true if the chunk is found, false otherwise. Image related chunk +// payloads are accessed through WebPDemuxGetFrame() and related functions. +// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete. +// NOTE: 'dmux' must persist for the lifetime of the iterator. +WEBP_NODISCARD WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux, + const char fourcc[4], + int chunk_number, + WebPChunkIterator* iter); + +// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous +// ('iter->chunk_num' - 1) chunk. These functions do not loop. +// Returns true on success, false otherwise. +WEBP_NODISCARD WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter); +WEBP_NODISCARD WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter); + +// Releases any memory associated with 'iter'. +// Must be called before destroying the associated WebPDemuxer with +// WebPDemuxDelete(). +WEBP_EXTERN void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter); + +//------------------------------------------------------------------------------ +// WebPAnimDecoder API +// +// This API allows decoding (possibly) animated WebP images. +// +// Code Example: +/* + WebPAnimDecoderOptions dec_options; + WebPAnimDecoderOptionsInit(&dec_options); + // Tune 'dec_options' as needed. + WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options); + WebPAnimInfo anim_info; + WebPAnimDecoderGetInfo(dec, &anim_info); + for (uint32_t i = 0; i < anim_info.loop_count; ++i) { + while (WebPAnimDecoderHasMoreFrames(dec)) { + uint8_t* buf; + int timestamp; + WebPAnimDecoderGetNext(dec, &buf, ×tamp); + // ... (Render 'buf' based on 'timestamp'). + // ... (Do NOT free 'buf', as it is owned by 'dec'). + } + WebPAnimDecoderReset(dec); + } + const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec); + // ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data). + WebPAnimDecoderDelete(dec); +*/ + +typedef struct WebPAnimDecoder WebPAnimDecoder; // Main opaque object. + +// Global options. +struct WebPAnimDecoderOptions { + // Output colorspace. Only the following modes are supported: + // MODE_RGBA, MODE_BGRA, MODE_rgbA and MODE_bgrA. + WEBP_CSP_MODE color_mode; + int use_threads; // If true, use multi-threaded decoding. + uint32_t padding[7]; // Padding for later use. +}; + +// Internal, version-checked, entry point. +WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal( + WebPAnimDecoderOptions*, int); + +// Should always be called, to initialize a fresh WebPAnimDecoderOptions +// structure before modification. Returns false in case of version mismatch. +// WebPAnimDecoderOptionsInit() must have succeeded before using the +// 'dec_options' object. +WEBP_NODISCARD static WEBP_INLINE int WebPAnimDecoderOptionsInit( + WebPAnimDecoderOptions* dec_options) { + return WebPAnimDecoderOptionsInitInternal(dec_options, + WEBP_DEMUX_ABI_VERSION); +} + +// Internal, version-checked, entry point. +WEBP_NODISCARD WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal( + const WebPData*, const WebPAnimDecoderOptions*, int); + +// Creates and initializes a WebPAnimDecoder object. +// Parameters: +// webp_data - (in) WebP bitstream. This should remain unchanged during the +// lifetime of the output WebPAnimDecoder object. +// dec_options - (in) decoding options. Can be passed NULL to choose +// reasonable defaults (in particular, color mode MODE_RGBA +// will be picked). +// Returns: +// A pointer to the newly created WebPAnimDecoder object, or NULL in case of +// parsing error, invalid option or memory error. +WEBP_NODISCARD static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew( + const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options) { + return WebPAnimDecoderNewInternal(webp_data, dec_options, + WEBP_DEMUX_ABI_VERSION); +} + +// Global information about the animation.. +struct WebPAnimInfo { + uint32_t canvas_width; + uint32_t canvas_height; + uint32_t loop_count; + uint32_t bgcolor; + uint32_t frame_count; + uint32_t pad[4]; // padding for later use +}; + +// Get global information about the animation. +// Parameters: +// dec - (in) decoder instance to get information from. +// info - (out) global information fetched from the animation. +// Returns: +// True on success. +WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderGetInfo( + const WebPAnimDecoder* dec, WebPAnimInfo* info); + +// Fetch the next frame from 'dec' based on options supplied to +// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size +// 'canvas_width * 4 * canvas_height', and not just the frame sub-rectangle. The +// returned buffer 'buf' is valid only until the next call to +// WebPAnimDecoderGetNext(), WebPAnimDecoderReset() or WebPAnimDecoderDelete(). +// Parameters: +// dec - (in/out) decoder instance from which the next frame is to be fetched. +// buf - (out) decoded frame. +// timestamp - (out) timestamp of the frame in milliseconds. +// Returns: +// False if any of the arguments are NULL, or if there is a parsing or +// decoding error, or if there are no more frames. Otherwise, returns true. +WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, + uint8_t** buf, + int* timestamp); + +// Check if there are more frames left to decode. +// Parameters: +// dec - (in) decoder instance to be checked. +// Returns: +// True if 'dec' is not NULL and some frames are yet to be decoded. +// Otherwise, returns false. +WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderHasMoreFrames( + const WebPAnimDecoder* dec); + +// Resets the WebPAnimDecoder object, so that next call to +// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be +// helpful when all frames need to be decoded multiple times (e.g. +// info.loop_count times) without destroying and recreating the 'dec' object. +// Parameters: +// dec - (in/out) decoder instance to be reset +WEBP_EXTERN void WebPAnimDecoderReset(WebPAnimDecoder* dec); + +// Grab the internal demuxer object. +// Getting the demuxer object can be useful if one wants to use operations only +// available through demuxer; e.g. to get XMP/EXIF/ICC metadata. The returned +// demuxer object is owned by 'dec' and is valid only until the next call to +// WebPAnimDecoderDelete(). +// +// Parameters: +// dec - (in) decoder instance from which the demuxer object is to be fetched. +WEBP_NODISCARD WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer( + const WebPAnimDecoder* dec); + +// Deletes the WebPAnimDecoder object. +// Parameters: +// dec - (in/out) decoder instance to be deleted +WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_WEBP_DEMUX_H_ diff --git a/libraries/webp/include/webp/encode.h b/libraries/webp/include/webp/encode.h new file mode 100644 index 00000000000..f3d59297c8c --- /dev/null +++ b/libraries/webp/include/webp/encode.h @@ -0,0 +1,557 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebP encoder: main interface +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_WEBP_ENCODE_H_ +#define WEBP_WEBP_ENCODE_H_ + +#include "./types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WEBP_ENCODER_ABI_VERSION 0x020f // MAJOR(8b) + MINOR(8b) + +// Note: forward declaring enumerations is not allowed in (strict) C and C++, +// the types are left here for reference. +// typedef enum WebPImageHint WebPImageHint; +// typedef enum WebPEncCSP WebPEncCSP; +// typedef enum WebPPreset WebPPreset; +// typedef enum WebPEncodingError WebPEncodingError; +typedef struct WebPConfig WebPConfig; +typedef struct WebPPicture WebPPicture; // main structure for I/O +typedef struct WebPAuxStats WebPAuxStats; +typedef struct WebPMemoryWriter WebPMemoryWriter; + +// Return the encoder's version number, packed in hexadecimal using 8bits for +// each of major/minor/revision. E.g: v2.5.7 is 0x020507. +WEBP_EXTERN int WebPGetEncoderVersion(void); + +//------------------------------------------------------------------------------ +// One-stop-shop call! No questions asked: + +// Returns the size of the compressed data (pointed to by *output), or 0 if +// an error occurred. The compressed data must be released by the caller +// using the call 'WebPFree(*output)'. +// These functions compress using the lossy format, and the quality_factor +// can go from 0 (smaller output, lower quality) to 100 (best quality, +// larger output). +WEBP_EXTERN size_t WebPEncodeRGB(const uint8_t* rgb, + int width, int height, int stride, + float quality_factor, uint8_t** output); +WEBP_EXTERN size_t WebPEncodeBGR(const uint8_t* bgr, + int width, int height, int stride, + float quality_factor, uint8_t** output); +WEBP_EXTERN size_t WebPEncodeRGBA(const uint8_t* rgba, + int width, int height, int stride, + float quality_factor, uint8_t** output); +WEBP_EXTERN size_t WebPEncodeBGRA(const uint8_t* bgra, + int width, int height, int stride, + float quality_factor, uint8_t** output); + +// These functions are the equivalent of the above, but compressing in a +// lossless manner. Files are usually larger than lossy format, but will +// not suffer any compression loss. +// Note these functions, like the lossy versions, use the library's default +// settings. For lossless this means 'exact' is disabled. RGB values in +// transparent areas will be modified to improve compression. To avoid this, +// use WebPEncode() and set WebPConfig::exact to 1. +WEBP_EXTERN size_t WebPEncodeLosslessRGB(const uint8_t* rgb, + int width, int height, int stride, + uint8_t** output); +WEBP_EXTERN size_t WebPEncodeLosslessBGR(const uint8_t* bgr, + int width, int height, int stride, + uint8_t** output); +WEBP_EXTERN size_t WebPEncodeLosslessRGBA(const uint8_t* rgba, + int width, int height, int stride, + uint8_t** output); +WEBP_EXTERN size_t WebPEncodeLosslessBGRA(const uint8_t* bgra, + int width, int height, int stride, + uint8_t** output); + +//------------------------------------------------------------------------------ +// Coding parameters + +// Image characteristics hint for the underlying encoder. +typedef enum WebPImageHint { + WEBP_HINT_DEFAULT = 0, // default preset. + WEBP_HINT_PICTURE, // digital picture, like portrait, inner shot + WEBP_HINT_PHOTO, // outdoor photograph, with natural lighting + WEBP_HINT_GRAPH, // Discrete tone image (graph, map-tile etc). + WEBP_HINT_LAST +} WebPImageHint; + +// Compression parameters. +struct WebPConfig { + int lossless; // Lossless encoding (0=lossy(default), 1=lossless). + float quality; // between 0 and 100. For lossy, 0 gives the smallest + // size and 100 the largest. For lossless, this + // parameter is the amount of effort put into the + // compression: 0 is the fastest but gives larger + // files compared to the slowest, but best, 100. + int method; // quality/speed trade-off (0=fast, 6=slower-better) + + WebPImageHint image_hint; // Hint for image type (lossless only for now). + + int target_size; // if non-zero, set the desired target size in bytes. + // Takes precedence over the 'compression' parameter. + float target_PSNR; // if non-zero, specifies the minimal distortion to + // try to achieve. Takes precedence over target_size. + int segments; // maximum number of segments to use, in [1..4] + int sns_strength; // Spatial Noise Shaping. 0=off, 100=maximum. + int filter_strength; // range: [0 = off .. 100 = strongest] + int filter_sharpness; // range: [0 = off .. 7 = least sharp] + int filter_type; // filtering type: 0 = simple, 1 = strong (only used + // if filter_strength > 0 or autofilter > 0) + int autofilter; // Auto adjust filter's strength [0 = off, 1 = on] + int alpha_compression; // Algorithm for encoding the alpha plane (0 = none, + // 1 = compressed with WebP lossless). Default is 1. + int alpha_filtering; // Predictive filtering method for alpha plane. + // 0: none, 1: fast, 2: best. Default if 1. + int alpha_quality; // Between 0 (smallest size) and 100 (lossless). + // Default is 100. + int pass; // number of entropy-analysis passes (in [1..10]). + + int show_compressed; // if true, export the compressed picture back. + // In-loop filtering is not applied. + int preprocessing; // preprocessing filter: + // 0=none, 1=segment-smooth, 2=pseudo-random dithering + int partitions; // log2(number of token partitions) in [0..3]. Default + // is set to 0 for easier progressive decoding. + int partition_limit; // quality degradation allowed to fit the 512k limit + // on prediction modes coding (0: no degradation, + // 100: maximum possible degradation). + int emulate_jpeg_size; // If true, compression parameters will be remapped + // to better match the expected output size from + // JPEG compression. Generally, the output size will + // be similar but the degradation will be lower. + int thread_level; // If non-zero, try and use multi-threaded encoding. + int low_memory; // If set, reduce memory usage (but increase CPU use). + + int near_lossless; // Near lossless encoding [0 = max loss .. 100 = off + // (default)]. + int exact; // if non-zero, preserve the exact RGB values under + // transparent area. Otherwise, discard this invisible + // RGB information for better compression. The default + // value is 0. + + int use_delta_palette; // reserved for future lossless feature + int use_sharp_yuv; // if needed, use sharp (and slow) RGB->YUV conversion + + int qmin; // minimum permissible quality factor + int qmax; // maximum permissible quality factor +}; + +// Enumerate some predefined settings for WebPConfig, depending on the type +// of source picture. These presets are used when calling WebPConfigPreset(). +typedef enum WebPPreset { + WEBP_PRESET_DEFAULT = 0, // default preset. + WEBP_PRESET_PICTURE, // digital picture, like portrait, inner shot + WEBP_PRESET_PHOTO, // outdoor photograph, with natural lighting + WEBP_PRESET_DRAWING, // hand or line drawing, with high-contrast details + WEBP_PRESET_ICON, // small-sized colorful images + WEBP_PRESET_TEXT // text-like +} WebPPreset; + +// Internal, version-checked, entry point +WEBP_NODISCARD WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset, + float, int); + +// Should always be called, to initialize a fresh WebPConfig structure before +// modification. Returns false in case of version mismatch. WebPConfigInit() +// must have succeeded before using the 'config' object. +// Note that the default values are lossless=0 and quality=75. +WEBP_NODISCARD static WEBP_INLINE int WebPConfigInit(WebPConfig* config) { + return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f, + WEBP_ENCODER_ABI_VERSION); +} + +// This function will initialize the configuration according to a predefined +// set of parameters (referred to by 'preset') and a given quality factor. +// This function can be called as a replacement to WebPConfigInit(). Will +// return false in case of error. +WEBP_NODISCARD static WEBP_INLINE int WebPConfigPreset(WebPConfig* config, + WebPPreset preset, + float quality) { + return WebPConfigInitInternal(config, preset, quality, + WEBP_ENCODER_ABI_VERSION); +} + +// Activate the lossless compression mode with the desired efficiency level +// between 0 (fastest, lowest compression) and 9 (slower, best compression). +// A good default level is '6', providing a fair tradeoff between compression +// speed and final compressed size. +// This function will overwrite several fields from config: 'method', 'quality' +// and 'lossless'. Returns false in case of parameter error. +WEBP_NODISCARD WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config, + int level); + +// Returns true if 'config' is non-NULL and all configuration parameters are +// within their valid ranges. +WEBP_NODISCARD WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config); + +//------------------------------------------------------------------------------ +// Input / Output +// Structure for storing auxiliary statistics. + +struct WebPAuxStats { + int coded_size; // final size + + float PSNR[5]; // peak-signal-to-noise ratio for Y/U/V/All/Alpha + int block_count[3]; // number of intra4/intra16/skipped macroblocks + int header_bytes[2]; // approximate number of bytes spent for header + // and mode-partition #0 + int residual_bytes[3][4]; // approximate number of bytes spent for + // DC/AC/uv coefficients for each (0..3) segments. + int segment_size[4]; // number of macroblocks in each segments + int segment_quant[4]; // quantizer values for each segments + int segment_level[4]; // filtering strength for each segments [0..63] + + int alpha_data_size; // size of the transparency data + int layer_data_size; // size of the enhancement layer data + + // lossless encoder statistics + uint32_t lossless_features; // bit0:predictor bit1:cross-color transform + // bit2:subtract-green bit3:color indexing + int histogram_bits; // number of precision bits of histogram + int transform_bits; // precision bits for transform + int cache_bits; // number of bits for color cache lookup + int palette_size; // number of color in palette, if used + int lossless_size; // final lossless size + int lossless_hdr_size; // lossless header (transform, huffman etc) size + int lossless_data_size; // lossless image data size + + uint32_t pad[2]; // padding for later use +}; + +// Signature for output function. Should return true if writing was successful. +// data/data_size is the segment of data to write, and 'picture' is for +// reference (and so one can make use of picture->custom_ptr). +typedef int (*WebPWriterFunction)(const uint8_t* data, size_t data_size, + const WebPPicture* picture); + +// WebPMemoryWrite: a special WebPWriterFunction that writes to memory using +// the following WebPMemoryWriter object (to be set as a custom_ptr). +struct WebPMemoryWriter { + uint8_t* mem; // final buffer (of size 'max_size', larger than 'size'). + size_t size; // final size + size_t max_size; // total capacity + uint32_t pad[1]; // padding for later use +}; + +// The following must be called first before any use. +WEBP_EXTERN void WebPMemoryWriterInit(WebPMemoryWriter* writer); + +// The following must be called to deallocate writer->mem memory. The 'writer' +// object itself is not deallocated. +WEBP_EXTERN void WebPMemoryWriterClear(WebPMemoryWriter* writer); +// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon +// completion, writer.mem and writer.size will hold the coded data. +// writer.mem must be freed by calling WebPMemoryWriterClear. +WEBP_NODISCARD WEBP_EXTERN int WebPMemoryWrite( + const uint8_t* data, size_t data_size, const WebPPicture* picture); + +// Progress hook, called from time to time to report progress. It can return +// false to request an abort of the encoding process, or true otherwise if +// everything is OK. +typedef int (*WebPProgressHook)(int percent, const WebPPicture* picture); + +// Color spaces. +typedef enum WebPEncCSP { + // chroma sampling + WEBP_YUV420 = 0, // 4:2:0 + WEBP_YUV420A = 4, // alpha channel variant + WEBP_CSP_UV_MASK = 3, // bit-mask to get the UV sampling factors + WEBP_CSP_ALPHA_BIT = 4 // bit that is set if alpha is present +} WebPEncCSP; + +// Encoding error conditions. +typedef enum WebPEncodingError { + VP8_ENC_OK = 0, + VP8_ENC_ERROR_OUT_OF_MEMORY, // memory error allocating objects + VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY, // memory error while flushing bits + VP8_ENC_ERROR_NULL_PARAMETER, // a pointer parameter is NULL + VP8_ENC_ERROR_INVALID_CONFIGURATION, // configuration is invalid + VP8_ENC_ERROR_BAD_DIMENSION, // picture has invalid width/height + VP8_ENC_ERROR_PARTITION0_OVERFLOW, // partition is bigger than 512k + VP8_ENC_ERROR_PARTITION_OVERFLOW, // partition is bigger than 16M + VP8_ENC_ERROR_BAD_WRITE, // error while flushing bytes + VP8_ENC_ERROR_FILE_TOO_BIG, // file is bigger than 4G + VP8_ENC_ERROR_USER_ABORT, // abort request by user + VP8_ENC_ERROR_LAST // list terminator. always last. +} WebPEncodingError; + +// maximum width/height allowed (inclusive), in pixels +#define WEBP_MAX_DIMENSION 16383 + +// Main exchange structure (input samples, output bytes, statistics) +// +// Once WebPPictureInit() has been called, it's ok to make all the INPUT fields +// (use_argb, y/u/v, argb, ...) point to user-owned data, even if +// WebPPictureAlloc() has been called. Depending on the value use_argb, +// it's guaranteed that either *argb or *y/*u/*v content will be kept untouched. +struct WebPPicture { + // INPUT + ////////////// + // Main flag for encoder selecting between ARGB or YUV input. + // It is recommended to use ARGB input (*argb, argb_stride) for lossless + // compression, and YUV input (*y, *u, *v, etc.) for lossy compression + // since these are the respective native colorspace for these formats. + int use_argb; + + // YUV input (mostly used for input to lossy compression) + WebPEncCSP colorspace; // colorspace: should be YUV420 for now (=Y'CbCr). + int width, height; // dimensions (less or equal to WEBP_MAX_DIMENSION) + uint8_t* y, *u, *v; // pointers to luma/chroma planes. + int y_stride, uv_stride; // luma/chroma strides. + uint8_t* a; // pointer to the alpha plane + int a_stride; // stride of the alpha plane + uint32_t pad1[2]; // padding for later use + + // ARGB input (mostly used for input to lossless compression) + uint32_t* argb; // Pointer to argb (32 bit) plane. + int argb_stride; // This is stride in pixels units, not bytes. + uint32_t pad2[3]; // padding for later use + + // OUTPUT + /////////////// + // Byte-emission hook, to store compressed bytes as they are ready. + WebPWriterFunction writer; // can be NULL + void* custom_ptr; // can be used by the writer. + + // map for extra information (only for lossy compression mode) + int extra_info_type; // 1: intra type, 2: segment, 3: quant + // 4: intra-16 prediction mode, + // 5: chroma prediction mode, + // 6: bit cost, 7: distortion + uint8_t* extra_info; // if not NULL, points to an array of size + // ((width + 15) / 16) * ((height + 15) / 16) that + // will be filled with a macroblock map, depending + // on extra_info_type. + + // STATS AND REPORTS + /////////////////////////// + // Pointer to side statistics (updated only if not NULL) + WebPAuxStats* stats; + + // Error code for the latest error encountered during encoding + WebPEncodingError error_code; + + // If not NULL, report progress during encoding. + WebPProgressHook progress_hook; + + void* user_data; // this field is free to be set to any value and + // used during callbacks (like progress-report e.g.). + + uint32_t pad3[3]; // padding for later use + + // Unused for now + uint8_t* pad4, *pad5; + uint32_t pad6[8]; // padding for later use + + // PRIVATE FIELDS + //////////////////// + void* memory_; // row chunk of memory for yuva planes + void* memory_argb_; // and for argb too. + void* pad7[2]; // padding for later use +}; + +// Internal, version-checked, entry point +WEBP_NODISCARD WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int); + +// Should always be called, to initialize the structure. Returns false in case +// of version mismatch. WebPPictureInit() must have succeeded before using the +// 'picture' object. +// Note that, by default, use_argb is false and colorspace is WEBP_YUV420. +WEBP_NODISCARD static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) { + return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION); +} + +//------------------------------------------------------------------------------ +// WebPPicture utils + +// Convenience allocation / deallocation based on picture->width/height: +// Allocate y/u/v buffers as per colorspace/width/height specification. +// Note! This function will free the previous buffer if needed. +// Returns false in case of memory error. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture); + +// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*(). +// Note that this function does _not_ free the memory used by the 'picture' +// object itself. +// Besides memory (which is reclaimed) all other fields of 'picture' are +// preserved. +WEBP_EXTERN void WebPPictureFree(WebPPicture* picture); + +// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return, *dst +// will fully own the copied pixels (this is not a view). The 'dst' picture need +// not be initialized as its content is overwritten. +// Returns false in case of memory allocation error. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, + WebPPicture* dst); + +// Compute the single distortion for packed planes of samples. +// 'src' will be compared to 'ref', and the raw distortion stored into +// '*distortion'. The refined metric (log(MSE), log(1 - ssim),...' will be +// stored in '*result'. +// 'x_step' is the horizontal stride (in bytes) between samples. +// 'src/ref_stride' is the byte distance between rows. +// Returns false in case of error (bad parameter, memory allocation error, ...). +WEBP_NODISCARD WEBP_EXTERN int WebPPlaneDistortion( + const uint8_t* src, size_t src_stride, + const uint8_t* ref, size_t ref_stride, int width, int height, size_t x_step, + int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM + float* distortion, float* result); + +// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results +// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is +// always performed using ARGB samples. Hence if the input is YUV(A), the +// picture will be internally converted to ARGB (just for the measurement). +// Warning: this function is rather CPU-intensive. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureDistortion( + const WebPPicture* src, const WebPPicture* ref, + int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM + float result[5]); + +// self-crops a picture to the rectangle defined by top/left/width/height. +// Returns false in case of memory allocation error, or if the rectangle is +// outside of the source picture. +// The rectangle for the view is defined by the top-left corner pixel +// coordinates (left, top) as well as its width and height. This rectangle +// must be fully be comprised inside the 'src' source picture. If the source +// picture uses the YUV420 colorspace, the top and left coordinates will be +// snapped to even values. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureCrop( + WebPPicture* picture, int left, int top, int width, int height); + +// Extracts a view from 'src' picture into 'dst'. The rectangle for the view +// is defined by the top-left corner pixel coordinates (left, top) as well +// as its width and height. This rectangle must be fully be comprised inside +// the 'src' source picture. If the source picture uses the YUV420 colorspace, +// the top and left coordinates will be snapped to even values. +// Picture 'src' must out-live 'dst' picture. Self-extraction of view is allowed +// ('src' equal to 'dst') as a mean of fast-cropping (but note that doing so, +// the original dimension will be lost). Picture 'dst' need not be initialized +// with WebPPictureInit() if it is different from 'src', since its content will +// be overwritten. +// Returns false in case of invalid parameters. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureView( + const WebPPicture* src, int left, int top, int width, int height, + WebPPicture* dst); + +// Returns true if the 'picture' is actually a view and therefore does +// not own the memory for pixels. +WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture); + +// Rescale a picture to new dimension width x height. +// If either 'width' or 'height' (but not both) is 0 the corresponding +// dimension will be calculated preserving the aspect ratio. +// No gamma correction is applied. +// Returns false in case of error (invalid parameter or insufficient memory). +WEBP_NODISCARD WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture, + int width, int height); + +// Colorspace conversion function to import RGB samples. +// Previous buffer will be free'd, if any. +// *rgb buffer should have a size of at least height * rgb_stride. +// Returns false in case of memory error. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGB( + WebPPicture* picture, const uint8_t* rgb, int rgb_stride); +// Same, but for RGBA buffer. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGBA( + WebPPicture* picture, const uint8_t* rgba, int rgba_stride); +// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format +// input buffer ignoring the alpha channel. Avoids needing to copy the data +// to a temporary 24-bit RGB buffer to import the RGB only. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGBX( + WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride); + +// Variants of the above, but taking BGR(A|X) input. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGR( + WebPPicture* picture, const uint8_t* bgr, int bgr_stride); +WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGRA( + WebPPicture* picture, const uint8_t* bgra, int bgra_stride); +WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGRX( + WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride); + +// Converts picture->argb data to the YUV420A format. The 'colorspace' +// parameter is deprecated and should be equal to WEBP_YUV420. +// Upon return, picture->use_argb is set to false. The presence of real +// non-opaque transparent values is detected, and 'colorspace' will be +// adjusted accordingly. Note that this method is lossy. +// Returns false in case of error. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureARGBToYUVA( + WebPPicture* picture, WebPEncCSP /*colorspace = WEBP_YUV420*/); + +// Same as WebPPictureARGBToYUVA(), but the conversion is done using +// pseudo-random dithering with a strength 'dithering' between +// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful +// for photographic picture. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureARGBToYUVADithered( + WebPPicture* picture, WebPEncCSP colorspace, float dithering); + +// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion +// Downsampling is handled with extra care in case of color clipping. This +// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better +// and sharper YUV representation. +// Returns false in case of error. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture); +// kept for backward compatibility: +WEBP_NODISCARD WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture); + +// Converts picture->yuv to picture->argb and sets picture->use_argb to true. +// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to +// ARGB incurs a small loss too. +// Note that the use of this colorspace is discouraged if one has access to the +// raw ARGB samples, since using YUV420 is comparatively lossy. +// Returns false in case of error. +WEBP_NODISCARD WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture); + +// Helper function: given a width x height plane of RGBA or YUV(A) samples +// clean-up or smoothen the YUV or RGB samples under fully transparent area, +// to help compressibility (no guarantee, though). +WEBP_EXTERN void WebPCleanupTransparentArea(WebPPicture* picture); + +// Scan the picture 'picture' for the presence of non fully opaque alpha values. +// Returns true in such case. Otherwise returns false (indicating that the +// alpha plane can be ignored altogether e.g.). +WEBP_EXTERN int WebPPictureHasTransparency(const WebPPicture* picture); + +// Remove the transparency information (if present) by blending the color with +// the background color 'background_rgb' (specified as 24bit RGB triplet). +// After this call, all alpha values are reset to 0xff. +WEBP_EXTERN void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb); + +//------------------------------------------------------------------------------ +// Main call + +// Main encoding call, after config and picture have been initialized. +// 'picture' must be less than 16384x16384 in dimension (cf WEBP_MAX_DIMENSION), +// and the 'config' object must be a valid one. +// Returns false in case of error, true otherwise. +// In case of error, picture->error_code is updated accordingly. +// 'picture' can hold the source samples in both YUV(A) or ARGB input, depending +// on the value of 'picture->use_argb'. It is highly recommended to use +// the former for lossy encoding, and the latter for lossless encoding +// (when config.lossless is true). Automatic conversion from one format to +// another is provided but they both incur some loss. +WEBP_NODISCARD WEBP_EXTERN int WebPEncode(const WebPConfig* config, + WebPPicture* picture); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_WEBP_ENCODE_H_ diff --git a/libraries/webp/include/webp/format_constants.h b/libraries/webp/include/webp/format_constants.h new file mode 100644 index 00000000000..999035c5d26 --- /dev/null +++ b/libraries/webp/include/webp/format_constants.h @@ -0,0 +1,87 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Internal header for constants related to WebP file format. +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_WEBP_FORMAT_CONSTANTS_H_ +#define WEBP_WEBP_FORMAT_CONSTANTS_H_ + +// Create fourcc of the chunk from the chunk tag characters. +#define MKFOURCC(a, b, c, d) ((a) | (b) << 8 | (c) << 16 | (uint32_t)(d) << 24) + +// VP8 related constants. +#define VP8_SIGNATURE 0x9d012a // Signature in VP8 data. +#define VP8_MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition +#define VP8_MAX_PARTITION_SIZE (1 << 24) // max size for token partition +#define VP8_FRAME_HEADER_SIZE 10 // Size of the frame header within VP8 data. + +// VP8L related constants. +#define VP8L_SIGNATURE_SIZE 1 // VP8L signature size. +#define VP8L_MAGIC_BYTE 0x2f // VP8L signature byte. +#define VP8L_IMAGE_SIZE_BITS 14 // Number of bits used to store + // width and height. +#define VP8L_VERSION_BITS 3 // 3 bits reserved for version. +#define VP8L_VERSION 0 // version 0 +#define VP8L_FRAME_HEADER_SIZE 5 // Size of the VP8L frame header. + +#define MAX_PALETTE_SIZE 256 +#define MAX_CACHE_BITS 11 +#define HUFFMAN_CODES_PER_META_CODE 5 +#define ARGB_BLACK 0xff000000 + +#define DEFAULT_CODE_LENGTH 8 +#define MAX_ALLOWED_CODE_LENGTH 15 + +#define NUM_LITERAL_CODES 256 +#define NUM_LENGTH_CODES 24 +#define NUM_DISTANCE_CODES 40 +#define CODE_LENGTH_CODES 19 + +#define MIN_HUFFMAN_BITS 2 // min number of Huffman bits +#define MAX_HUFFMAN_BITS 9 // max number of Huffman bits + +#define TRANSFORM_PRESENT 1 // The bit to be written when next data + // to be read is a transform. +#define NUM_TRANSFORMS 4 // Maximum number of allowed transform + // in a bitstream. +typedef enum { + PREDICTOR_TRANSFORM = 0, + CROSS_COLOR_TRANSFORM = 1, + SUBTRACT_GREEN_TRANSFORM = 2, + COLOR_INDEXING_TRANSFORM = 3 +} VP8LImageTransformType; + +// Alpha related constants. +#define ALPHA_HEADER_LEN 1 +#define ALPHA_NO_COMPRESSION 0 +#define ALPHA_LOSSLESS_COMPRESSION 1 +#define ALPHA_PREPROCESSED_LEVELS 1 + +// Mux related constants. +#define TAG_SIZE 4 // Size of a chunk tag (e.g. "VP8L"). +#define CHUNK_SIZE_BYTES 4 // Size needed to store chunk's size. +#define CHUNK_HEADER_SIZE 8 // Size of a chunk header. +#define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP"). +#define ANMF_CHUNK_SIZE 16 // Size of an ANMF chunk. +#define ANIM_CHUNK_SIZE 6 // Size of an ANIM chunk. +#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk. + +#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height. +#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. +#define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count +#define MAX_DURATION (1 << 24) // maximum duration +#define MAX_POSITION_OFFSET (1 << 24) // maximum frame x/y offset + +// Maximum chunk payload is such that adding the header and padding won't +// overflow a uint32_t. +#define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1) + +#endif // WEBP_WEBP_FORMAT_CONSTANTS_H_ diff --git a/libraries/webp/include/webp/mux.h b/libraries/webp/include/webp/mux.h new file mode 100644 index 00000000000..8fb067e4354 --- /dev/null +++ b/libraries/webp/include/webp/mux.h @@ -0,0 +1,591 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// RIFF container manipulation and encoding for WebP images. +// +// Authors: Urvang (urvang@google.com) +// Vikas (vikasa@google.com) + +#ifndef WEBP_WEBP_MUX_H_ +#define WEBP_WEBP_MUX_H_ + +#include "./mux_types.h" +#include "./types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WEBP_MUX_ABI_VERSION 0x0109 // MAJOR(8b) + MINOR(8b) + +//------------------------------------------------------------------------------ +// Mux API +// +// This API allows manipulation of WebP container images containing features +// like color profile, metadata, animation. +// +// Code Example#1: Create a WebPMux object with image data, color profile and +// XMP metadata. +/* + int copy_data = 0; + WebPMux* mux = WebPMuxNew(); + // ... (Prepare image data). + WebPMuxSetImage(mux, &image, copy_data); + // ... (Prepare ICCP color profile data). + WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); + // ... (Prepare XMP metadata). + WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data); + // Get data from mux in WebP RIFF format. + WebPMuxAssemble(mux, &output_data); + WebPMuxDelete(mux); + // ... (Consume output_data; e.g. write output_data.bytes to file). + WebPDataClear(&output_data); +*/ + +// Code Example#2: Get image and color profile data from a WebP file. +/* + int copy_data = 0; + // ... (Read data from file). + WebPMux* mux = WebPMuxCreate(&data, copy_data); + WebPMuxGetFrame(mux, 1, &image); + // ... (Consume image; e.g. call WebPDecode() to decode the data). + WebPMuxGetChunk(mux, "ICCP", &icc_profile); + // ... (Consume icc_data). + WebPMuxDelete(mux); + WebPFree(data); +*/ + +// Note: forward declaring enumerations is not allowed in (strict) C and C++, +// the types are left here for reference. +// typedef enum WebPMuxError WebPMuxError; +// typedef enum WebPChunkId WebPChunkId; +typedef struct WebPMux WebPMux; // main opaque object. +typedef struct WebPMuxFrameInfo WebPMuxFrameInfo; +typedef struct WebPMuxAnimParams WebPMuxAnimParams; +typedef struct WebPAnimEncoderOptions WebPAnimEncoderOptions; + +// Error codes +typedef enum WEBP_NODISCARD WebPMuxError { + WEBP_MUX_OK = 1, + WEBP_MUX_NOT_FOUND = 0, + WEBP_MUX_INVALID_ARGUMENT = -1, + WEBP_MUX_BAD_DATA = -2, + WEBP_MUX_MEMORY_ERROR = -3, + WEBP_MUX_NOT_ENOUGH_DATA = -4 +} WebPMuxError; + +// IDs for different types of chunks. +typedef enum WebPChunkId { + WEBP_CHUNK_VP8X, // VP8X + WEBP_CHUNK_ICCP, // ICCP + WEBP_CHUNK_ANIM, // ANIM + WEBP_CHUNK_ANMF, // ANMF + WEBP_CHUNK_DEPRECATED, // (deprecated from FRGM) + WEBP_CHUNK_ALPHA, // ALPH + WEBP_CHUNK_IMAGE, // VP8/VP8L + WEBP_CHUNK_EXIF, // EXIF + WEBP_CHUNK_XMP, // XMP + WEBP_CHUNK_UNKNOWN, // Other chunks. + WEBP_CHUNK_NIL +} WebPChunkId; + +//------------------------------------------------------------------------------ + +// Returns the version number of the mux library, packed in hexadecimal using +// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507. +WEBP_EXTERN int WebPGetMuxVersion(void); + +//------------------------------------------------------------------------------ +// Life of a Mux object + +// Internal, version-checked, entry point +WEBP_NODISCARD WEBP_EXTERN WebPMux* WebPNewInternal(int); + +// Creates an empty mux object. +// Returns: +// A pointer to the newly created empty mux object. +// Or NULL in case of memory error. +WEBP_NODISCARD static WEBP_INLINE WebPMux* WebPMuxNew(void) { + return WebPNewInternal(WEBP_MUX_ABI_VERSION); +} + +// Deletes the mux object. +// Parameters: +// mux - (in/out) object to be deleted +WEBP_EXTERN void WebPMuxDelete(WebPMux* mux); + +//------------------------------------------------------------------------------ +// Mux creation. + +// Internal, version-checked, entry point +WEBP_NODISCARD WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int, + int); + +// Creates a mux object from raw data given in WebP RIFF format. +// Parameters: +// bitstream - (in) the bitstream data in WebP RIFF format +// copy_data - (in) value 1 indicates given data WILL be copied to the mux +// object and value 0 indicates data will NOT be copied. If the +// data is not copied, it must exist for the lifetime of the +// mux object. +// Returns: +// A pointer to the mux object created from given data - on success. +// NULL - In case of invalid data or memory error. +WEBP_NODISCARD static WEBP_INLINE WebPMux* WebPMuxCreate( + const WebPData* bitstream, int copy_data) { + return WebPMuxCreateInternal(bitstream, copy_data, WEBP_MUX_ABI_VERSION); +} + +//------------------------------------------------------------------------------ +// Non-image chunks. + +// Note: Only non-image related chunks should be managed through chunk APIs. +// (Image related chunks are: "ANMF", "VP8 ", "VP8L" and "ALPH"). +// To add, get and delete images, use WebPMuxSetImage(), WebPMuxPushFrame(), +// WebPMuxGetFrame() and WebPMuxDeleteFrame(). + +// Adds a chunk with id 'fourcc' and data 'chunk_data' in the mux object. +// Any existing chunk(s) with the same id will be removed. +// Parameters: +// mux - (in/out) object to which the chunk is to be added +// fourcc - (in) a character array containing the fourcc of the given chunk; +// e.g., "ICCP", "XMP ", "EXIF" etc. +// chunk_data - (in) the chunk data to be added +// copy_data - (in) value 1 indicates given data WILL be copied to the mux +// object and value 0 indicates data will NOT be copied. If the +// data is not copied, it must exist until a call to +// WebPMuxAssemble() is made. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL +// or if fourcc corresponds to an image chunk. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxSetChunk( + WebPMux* mux, const char fourcc[4], const WebPData* chunk_data, + int copy_data); + +// Gets a reference to the data of the chunk with id 'fourcc' in the mux object. +// The caller should NOT free the returned data. +// Parameters: +// mux - (in) object from which the chunk data is to be fetched +// fourcc - (in) a character array containing the fourcc of the chunk; +// e.g., "ICCP", "XMP ", "EXIF" etc. +// chunk_data - (out) returned chunk data +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL +// or if fourcc corresponds to an image chunk. +// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given id. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxGetChunk( + const WebPMux* mux, const char fourcc[4], WebPData* chunk_data); + +// Deletes the chunk with the given 'fourcc' from the mux object. +// Parameters: +// mux - (in/out) object from which the chunk is to be deleted +// fourcc - (in) a character array containing the fourcc of the chunk; +// e.g., "ICCP", "XMP ", "EXIF" etc. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or fourcc is NULL +// or if fourcc corresponds to an image chunk. +// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given fourcc. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxDeleteChunk( + WebPMux* mux, const char fourcc[4]); + +//------------------------------------------------------------------------------ +// Images. + +// Encapsulates data about a single frame. +struct WebPMuxFrameInfo { + WebPData bitstream; // image data: can be a raw VP8/VP8L bitstream + // or a single-image WebP file. + int x_offset; // x-offset of the frame. + int y_offset; // y-offset of the frame. + int duration; // duration of the frame (in milliseconds). + + WebPChunkId id; // frame type: should be one of WEBP_CHUNK_ANMF + // or WEBP_CHUNK_IMAGE + WebPMuxAnimDispose dispose_method; // Disposal method for the frame. + WebPMuxAnimBlend blend_method; // Blend operation for the frame. + uint32_t pad[1]; // padding for later use +}; + +// Sets the (non-animated) image in the mux object. +// Note: Any existing images (including frames) will be removed. +// Parameters: +// mux - (in/out) object in which the image is to be set +// bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image +// WebP file (non-animated) +// copy_data - (in) value 1 indicates given data WILL be copied to the mux +// object and value 0 indicates data will NOT be copied. If the +// data is not copied, it must exist until a call to +// WebPMuxAssemble() is made. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxSetImage( + WebPMux* mux, const WebPData* bitstream, int copy_data); + +// Adds a frame at the end of the mux object. +// Notes: (1) frame.id should be WEBP_CHUNK_ANMF +// (2) For setting a non-animated image, use WebPMuxSetImage() instead. +// (3) Type of frame being pushed must be same as the frames in mux. +// (4) As WebP only supports even offsets, any odd offset will be snapped +// to an even location using: offset &= ~1 +// Parameters: +// mux - (in/out) object to which the frame is to be added +// frame - (in) frame data. +// copy_data - (in) value 1 indicates given data WILL be copied to the mux +// object and value 0 indicates data will NOT be copied. If the +// data is not copied, it must exist until a call to +// WebPMuxAssemble() is made. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL +// or if content of 'frame' is invalid. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxPushFrame( + WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data); + +// Gets the nth frame from the mux object. +// The content of 'frame->bitstream' is allocated using WebPMalloc(), and NOT +// owned by the 'mux' object. It MUST be deallocated by the caller by calling +// WebPDataClear(). +// nth=0 has a special meaning - last position. +// Parameters: +// mux - (in) object from which the info is to be fetched +// nth - (in) index of the frame in the mux object +// frame - (out) data of the returned frame +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL. +// WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object. +// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxGetFrame( + const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame); + +// Deletes a frame from the mux object. +// nth=0 has a special meaning - last position. +// Parameters: +// mux - (in/out) object from which a frame is to be deleted +// nth - (in) The position from which the frame is to be deleted +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL. +// WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object +// before deletion. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth); + +//------------------------------------------------------------------------------ +// Animation. + +// Animation parameters. +struct WebPMuxAnimParams { + uint32_t bgcolor; // Background color of the canvas stored (in MSB order) as: + // Bits 00 to 07: Alpha. + // Bits 08 to 15: Red. + // Bits 16 to 23: Green. + // Bits 24 to 31: Blue. + int loop_count; // Number of times to repeat the animation [0 = infinite]. +}; + +// Sets the animation parameters in the mux object. Any existing ANIM chunks +// will be removed. +// Parameters: +// mux - (in/out) object in which ANIM chunk is to be set/added +// params - (in) animation parameters. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxSetAnimationParams( + WebPMux* mux, const WebPMuxAnimParams* params); + +// Gets the animation parameters from the mux object. +// Parameters: +// mux - (in) object from which the animation parameters to be fetched +// params - (out) animation parameters extracted from the ANIM chunk +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL. +// WEBP_MUX_NOT_FOUND - if ANIM chunk is not present in mux object. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxGetAnimationParams( + const WebPMux* mux, WebPMuxAnimParams* params); + +//------------------------------------------------------------------------------ +// Misc Utilities. + +// Sets the canvas size for the mux object. The width and height can be +// specified explicitly or left as zero (0, 0). +// * When width and height are specified explicitly, then this frame bound is +// enforced during subsequent calls to WebPMuxAssemble() and an error is +// reported if any animated frame does not completely fit within the canvas. +// * When unspecified (0, 0), the constructed canvas will get the frame bounds +// from the bounding-box over all frames after calling WebPMuxAssemble(). +// Parameters: +// mux - (in) object to which the canvas size is to be set +// width - (in) canvas width +// height - (in) canvas height +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL; or +// width or height are invalid or out of bounds +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux, + int width, int height); + +// Gets the canvas size from the mux object. +// Note: This method assumes that the VP8X chunk, if present, is up-to-date. +// That is, the mux object hasn't been modified since the last call to +// WebPMuxAssemble() or WebPMuxCreate(). +// Parameters: +// mux - (in) object from which the canvas size is to be fetched +// width - (out) canvas width +// height - (out) canvas height +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux, width or height is NULL. +// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux, + int* width, int* height); + +// Gets the feature flags from the mux object. +// Note: This method assumes that the VP8X chunk, if present, is up-to-date. +// That is, the mux object hasn't been modified since the last call to +// WebPMuxAssemble() or WebPMuxCreate(). +// Parameters: +// mux - (in) object from which the features are to be fetched +// flags - (out) the flags specifying which features are present in the +// mux object. This will be an OR of various flag values. +// Enum 'WebPFeatureFlags' can be used to test individual flag values. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL. +// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, + uint32_t* flags); + +// Gets number of chunks with the given 'id' in the mux object. +// Parameters: +// mux - (in) object from which the info is to be fetched +// id - (in) chunk id specifying the type of chunk +// num_elements - (out) number of chunks with the given chunk id +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux, or num_elements is NULL. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxNumChunks(const WebPMux* mux, + WebPChunkId id, int* num_elements); + +// Assembles all chunks in WebP RIFF format and returns in 'assembled_data'. +// This function also validates the mux object. +// Note: The content of 'assembled_data' will be ignored and overwritten. +// Also, the content of 'assembled_data' is allocated using WebPMalloc(), and +// NOT owned by the 'mux' object. It MUST be deallocated by the caller by +// calling WebPDataClear(). It's always safe to call WebPDataClear() upon +// return, even in case of error. +// Parameters: +// mux - (in/out) object whose chunks are to be assembled +// assembled_data - (out) assembled WebP data +// Returns: +// WEBP_MUX_BAD_DATA - if mux object is invalid. +// WEBP_MUX_INVALID_ARGUMENT - if mux or assembled_data is NULL. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPMuxAssemble(WebPMux* mux, + WebPData* assembled_data); + +//------------------------------------------------------------------------------ +// WebPAnimEncoder API +// +// This API allows encoding (possibly) animated WebP images. +// +// Code Example: +/* + WebPAnimEncoderOptions enc_options; + WebPAnimEncoderOptionsInit(&enc_options); + // Tune 'enc_options' as needed. + WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options); + while() { + WebPConfig config; + WebPConfigInit(&config); + // Tune 'config' as needed. + WebPAnimEncoderAdd(enc, frame, timestamp_ms, &config); + } + WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL); + WebPAnimEncoderAssemble(enc, webp_data); + WebPAnimEncoderDelete(enc); + // Write the 'webp_data' to a file, or re-mux it further. +*/ + +typedef struct WebPAnimEncoder WebPAnimEncoder; // Main opaque object. + +// Forward declarations. Defined in encode.h. +struct WebPPicture; +struct WebPConfig; + +// Global options. +struct WebPAnimEncoderOptions { + WebPMuxAnimParams anim_params; // Animation parameters. + int minimize_size; // If true, minimize the output size (slow). Implicitly + // disables key-frame insertion. + int kmin; + int kmax; // Minimum and maximum distance between consecutive key + // frames in the output. The library may insert some key + // frames as needed to satisfy this criteria. + // Note that these conditions should hold: kmax > kmin + // and kmin >= kmax / 2 + 1. Also, if kmax <= 0, then + // key-frame insertion is disabled; and if kmax == 1, + // then all frames will be key-frames (kmin value does + // not matter for these special cases). + int allow_mixed; // If true, use mixed compression mode; may choose + // either lossy and lossless for each frame. + int verbose; // If true, print info and warning messages to stderr. + + uint32_t padding[4]; // Padding for later use. +}; + +// Internal, version-checked, entry point. +WEBP_EXTERN int WebPAnimEncoderOptionsInitInternal( + WebPAnimEncoderOptions*, int); + +// Should always be called, to initialize a fresh WebPAnimEncoderOptions +// structure before modification. Returns false in case of version mismatch. +// WebPAnimEncoderOptionsInit() must have succeeded before using the +// 'enc_options' object. +WEBP_NODISCARD static WEBP_INLINE int WebPAnimEncoderOptionsInit( + WebPAnimEncoderOptions* enc_options) { + return WebPAnimEncoderOptionsInitInternal(enc_options, WEBP_MUX_ABI_VERSION); +} + +// Internal, version-checked, entry point. +WEBP_EXTERN WebPAnimEncoder* WebPAnimEncoderNewInternal( + int, int, const WebPAnimEncoderOptions*, int); + +// Creates and initializes a WebPAnimEncoder object. +// Parameters: +// width/height - (in) canvas width and height of the animation. +// enc_options - (in) encoding options; can be passed NULL to pick +// reasonable defaults. +// Returns: +// A pointer to the newly created WebPAnimEncoder object. +// Or NULL in case of memory error. +static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew( + int width, int height, const WebPAnimEncoderOptions* enc_options) { + return WebPAnimEncoderNewInternal(width, height, enc_options, + WEBP_MUX_ABI_VERSION); +} + +// Optimize the given frame for WebP, encode it and add it to the +// WebPAnimEncoder object. +// The last call to 'WebPAnimEncoderAdd' should be with frame = NULL, which +// indicates that no more frames are to be added. This call is also used to +// determine the duration of the last frame. +// Parameters: +// enc - (in/out) object to which the frame is to be added. +// frame - (in/out) frame data in ARGB or YUV(A) format. If it is in YUV(A) +// format, it will be converted to ARGB, which incurs a small loss. +// timestamp_ms - (in) timestamp of this frame in milliseconds. +// Duration of a frame would be calculated as +// "timestamp of next frame - timestamp of this frame". +// Hence, timestamps should be in non-decreasing order. +// config - (in) encoding options; can be passed NULL to pick +// reasonable defaults. +// Returns: +// On error, returns false and frame->error_code is set appropriately. +// Otherwise, returns true. +WEBP_NODISCARD WEBP_EXTERN int WebPAnimEncoderAdd( + WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms, + const struct WebPConfig* config); + +// Assemble all frames added so far into a WebP bitstream. +// This call should be preceded by a call to 'WebPAnimEncoderAdd' with +// frame = NULL; if not, the duration of the last frame will be internally +// estimated. +// Parameters: +// enc - (in/out) object from which the frames are to be assembled. +// webp_data - (out) generated WebP bitstream. +// Returns: +// True on success. +WEBP_NODISCARD WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc, + WebPData* webp_data); + +// Get error string corresponding to the most recent call using 'enc'. The +// returned string is owned by 'enc' and is valid only until the next call to +// WebPAnimEncoderAdd() or WebPAnimEncoderAssemble() or WebPAnimEncoderDelete(). +// Parameters: +// enc - (in/out) object from which the error string is to be fetched. +// Returns: +// NULL if 'enc' is NULL. Otherwise, returns the error string if the last call +// to 'enc' had an error, or an empty string if the last call was a success. +WEBP_EXTERN const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc); + +// Deletes the WebPAnimEncoder object. +// Parameters: +// enc - (in/out) object to be deleted +WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc); + +//------------------------------------------------------------------------------ +// Non-image chunks. + +// Note: Only non-image related chunks should be managed through chunk APIs. +// (Image related chunks are: "ANMF", "VP8 ", "VP8L" and "ALPH"). + +// Adds a chunk with id 'fourcc' and data 'chunk_data' in the enc object. +// Any existing chunk(s) with the same id will be removed. +// Parameters: +// enc - (in/out) object to which the chunk is to be added +// fourcc - (in) a character array containing the fourcc of the given chunk; +// e.g., "ICCP", "XMP ", "EXIF", etc. +// chunk_data - (in) the chunk data to be added +// copy_data - (in) value 1 indicates given data WILL be copied to the enc +// object and value 0 indicates data will NOT be copied. If the +// data is not copied, it must exist until a call to +// WebPAnimEncoderAssemble() is made. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if enc, fourcc or chunk_data is NULL. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPAnimEncoderSetChunk( + WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data, + int copy_data); + +// Gets a reference to the data of the chunk with id 'fourcc' in the enc object. +// The caller should NOT free the returned data. +// Parameters: +// enc - (in) object from which the chunk data is to be fetched +// fourcc - (in) a character array containing the fourcc of the chunk; +// e.g., "ICCP", "XMP ", "EXIF", etc. +// chunk_data - (out) returned chunk data +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if enc, fourcc or chunk_data is NULL. +// WEBP_MUX_NOT_FOUND - If enc does not contain a chunk with the given id. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPAnimEncoderGetChunk( + const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data); + +// Deletes the chunk with the given 'fourcc' from the enc object. +// Parameters: +// enc - (in/out) object from which the chunk is to be deleted +// fourcc - (in) a character array containing the fourcc of the chunk; +// e.g., "ICCP", "XMP ", "EXIF", etc. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if enc or fourcc is NULL. +// WEBP_MUX_NOT_FOUND - If enc does not contain a chunk with the given fourcc. +// WEBP_MUX_OK - on success. +WEBP_EXTERN WebPMuxError WebPAnimEncoderDeleteChunk( + WebPAnimEncoder* enc, const char fourcc[4]); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_WEBP_MUX_H_ diff --git a/libraries/webp/include/webp/mux_types.h b/libraries/webp/include/webp/mux_types.h new file mode 100644 index 00000000000..c585d2082f7 --- /dev/null +++ b/libraries/webp/include/webp/mux_types.h @@ -0,0 +1,99 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Data-types common to the mux and demux libraries. +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_WEBP_MUX_TYPES_H_ +#define WEBP_WEBP_MUX_TYPES_H_ + +#include // memset() +#include "./types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Note: forward declaring enumerations is not allowed in (strict) C and C++, +// the types are left here for reference. +// typedef enum WebPFeatureFlags WebPFeatureFlags; +// typedef enum WebPMuxAnimDispose WebPMuxAnimDispose; +// typedef enum WebPMuxAnimBlend WebPMuxAnimBlend; +typedef struct WebPData WebPData; + +// VP8X Feature Flags. +typedef enum WebPFeatureFlags { + ANIMATION_FLAG = 0x00000002, + XMP_FLAG = 0x00000004, + EXIF_FLAG = 0x00000008, + ALPHA_FLAG = 0x00000010, + ICCP_FLAG = 0x00000020, + + ALL_VALID_FLAGS = 0x0000003e +} WebPFeatureFlags; + +// Dispose method (animation only). Indicates how the area used by the current +// frame is to be treated before rendering the next frame on the canvas. +typedef enum WebPMuxAnimDispose { + WEBP_MUX_DISPOSE_NONE, // Do not dispose. + WEBP_MUX_DISPOSE_BACKGROUND // Dispose to background color. +} WebPMuxAnimDispose; + +// Blend operation (animation only). Indicates how transparent pixels of the +// current frame are blended with those of the previous canvas. +typedef enum WebPMuxAnimBlend { + WEBP_MUX_BLEND, // Blend. + WEBP_MUX_NO_BLEND // Do not blend. +} WebPMuxAnimBlend; + +// Data type used to describe 'raw' data, e.g., chunk data +// (ICC profile, metadata) and WebP compressed image data. +// 'bytes' memory must be allocated using WebPMalloc() and such. +struct WebPData { + const uint8_t* bytes; + size_t size; +}; + +// Initializes the contents of the 'webp_data' object with default values. +static WEBP_INLINE void WebPDataInit(WebPData* webp_data) { + if (webp_data != NULL) { + memset(webp_data, 0, sizeof(*webp_data)); + } +} + +// Clears the contents of the 'webp_data' object by calling WebPFree(). +// Does not deallocate the object itself. +static WEBP_INLINE void WebPDataClear(WebPData* webp_data) { + if (webp_data != NULL) { + WebPFree((void*)webp_data->bytes); + WebPDataInit(webp_data); + } +} + +// Allocates necessary storage for 'dst' and copies the contents of 'src'. +// Returns true on success. +WEBP_NODISCARD static WEBP_INLINE int WebPDataCopy(const WebPData* src, + WebPData* dst) { + if (src == NULL || dst == NULL) return 0; + WebPDataInit(dst); + if (src->bytes != NULL && src->size != 0) { + dst->bytes = (uint8_t*)WebPMalloc(src->size); + if (dst->bytes == NULL) return 0; + memcpy((void*)dst->bytes, src->bytes, src->size); + dst->size = src->size; + } + return 1; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_WEBP_MUX_TYPES_H_ diff --git a/libraries/webp/include/webp/types.h b/libraries/webp/include/webp/types.h new file mode 100644 index 00000000000..0e7ef1295b0 --- /dev/null +++ b/libraries/webp/include/webp/types.h @@ -0,0 +1,87 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Common types + memory wrappers +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_WEBP_TYPES_H_ +#define WEBP_WEBP_TYPES_H_ + +#include // for size_t + +#ifndef _MSC_VER +#include +#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define WEBP_INLINE inline +#else +#define WEBP_INLINE +#endif +#else +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; +typedef long long int int64_t; +#define WEBP_INLINE __forceinline +#endif /* _MSC_VER */ + +#if defined(WEBP_ENABLE_NODISCARD) || \ + (defined(__cplusplus) && __cplusplus >= 201700L) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) +#define WEBP_NODISCARD [[nodiscard]] +#else +// gcc's __has_attribute does not work for enums. +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(warn_unused_result) +#define WEBP_NODISCARD __attribute__((warn_unused_result)) +#else +#define WEBP_NODISCARD +#endif +#else +#define WEBP_NODISCARD +#endif +#endif + +#ifndef WEBP_EXTERN +// This explicitly marks library functions and allows for changing the +// signature for e.g., Windows DLL builds. +# if defined(_WIN32) && defined(WEBP_DLL) +# define WEBP_EXTERN __declspec(dllexport) +# elif defined(__GNUC__) && __GNUC__ >= 4 +# define WEBP_EXTERN extern __attribute__ ((visibility ("default"))) +# else +# define WEBP_EXTERN extern +# endif /* defined(_WIN32) && defined(WEBP_DLL) */ +#endif /* WEBP_EXTERN */ + +// Macro to check ABI compatibility (same major revision number) +#define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8)) + +#ifdef __cplusplus +extern "C" { +#endif + +// Allocates 'size' bytes of memory. Returns NULL upon error. Memory +// must be deallocated by calling WebPFree(). This function is made available +// by the core 'libwebp' library. +WEBP_NODISCARD WEBP_EXTERN void* WebPMalloc(size_t size); + +// Releases memory returned by the WebPDecode*() functions (from decode.h). +WEBP_EXTERN void WebPFree(void* ptr); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_WEBP_TYPES_H_ diff --git a/libraries/webp/sharpyuv/sharpyuv.c b/libraries/webp/sharpyuv/sharpyuv.c new file mode 100644 index 00000000000..c779e7383c9 --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv.c @@ -0,0 +1,574 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Sharp RGB to YUV conversion. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "sharpyuv/sharpyuv.h" + +#include +#include +#include +#include +#include + +#include "include/webp/types.h" +#include "sharpyuv/sharpyuv_cpu.h" +#include "sharpyuv/sharpyuv_dsp.h" +#include "sharpyuv/sharpyuv_gamma.h" + +//------------------------------------------------------------------------------ + +int SharpYuvGetVersion(void) { + return SHARPYUV_VERSION; +} + +//------------------------------------------------------------------------------ +// Sharp RGB->YUV conversion + +static const int kNumIterations = 4; + +#define YUV_FIX 16 // fixed-point precision for RGB->YUV +static const int kYuvHalf = 1 << (YUV_FIX - 1); + +// Max bit depth so that intermediate calculations fit in 16 bits. +static const int kMaxBitDepth = 14; + +// Returns the precision shift to use based on the input rgb_bit_depth. +static int GetPrecisionShift(int rgb_bit_depth) { + // Try to add 2 bits of precision if it fits in kMaxBitDepth. Otherwise remove + // bits if needed. + return ((rgb_bit_depth + 2) <= kMaxBitDepth) ? 2 + : (kMaxBitDepth - rgb_bit_depth); +} + +typedef int16_t fixed_t; // signed type with extra precision for UV +typedef uint16_t fixed_y_t; // unsigned type with extra precision for W + +//------------------------------------------------------------------------------ + +static uint8_t clip_8b(fixed_t v) { + return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u; +} + +static uint16_t clip(fixed_t v, int max) { + return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; +} + +static fixed_y_t clip_bit_depth(int y, int bit_depth) { + const int max = (1 << bit_depth) - 1; + return (!(y & ~max)) ? (fixed_y_t)y : (y < 0) ? 0 : max; +} + +//------------------------------------------------------------------------------ + +static int RGBToGray(int64_t r, int64_t g, int64_t b) { + const int64_t luma = 13933 * r + 46871 * g + 4732 * b + kYuvHalf; + return (int)(luma >> YUV_FIX); +} + +static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d, + int rgb_bit_depth, + SharpYuvTransferFunctionType transfer_type) { + const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); + const uint32_t A = SharpYuvGammaToLinear(a, bit_depth, transfer_type); + const uint32_t B = SharpYuvGammaToLinear(b, bit_depth, transfer_type); + const uint32_t C = SharpYuvGammaToLinear(c, bit_depth, transfer_type); + const uint32_t D = SharpYuvGammaToLinear(d, bit_depth, transfer_type); + return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth, + transfer_type); +} + +static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w, + int rgb_bit_depth, + SharpYuvTransferFunctionType transfer_type) { + const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); + int i = 0; + do { + const uint32_t R = + SharpYuvGammaToLinear(src[0 * w + i], bit_depth, transfer_type); + const uint32_t G = + SharpYuvGammaToLinear(src[1 * w + i], bit_depth, transfer_type); + const uint32_t B = + SharpYuvGammaToLinear(src[2 * w + i], bit_depth, transfer_type); + const uint32_t Y = RGBToGray(R, G, B); + dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth, transfer_type); + } while (++i < w); +} + +static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2, + fixed_t* dst, int uv_w, int rgb_bit_depth, + SharpYuvTransferFunctionType transfer_type) { + int i = 0; + do { + const int r = + ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0], + src2[0 * uv_w + 1], rgb_bit_depth, transfer_type); + const int g = + ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0], + src2[2 * uv_w + 1], rgb_bit_depth, transfer_type); + const int b = + ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0], + src2[4 * uv_w + 1], rgb_bit_depth, transfer_type); + const int W = RGBToGray(r, g, b); + dst[0 * uv_w] = (fixed_t)(r - W); + dst[1 * uv_w] = (fixed_t)(g - W); + dst[2 * uv_w] = (fixed_t)(b - W); + dst += 1; + src1 += 2; + src2 += 2; + } while (++i < uv_w); +} + +static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) { + int i = 0; + assert(w > 0); + do { + y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]); + } while (++i < w); +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0, int bit_depth) { + const int v0 = (A * 3 + B + 2) >> 2; + return clip_bit_depth(v0 + W0, bit_depth); +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE int Shift(int v, int shift) { + return (shift >= 0) ? (v << shift) : (v >> -shift); +} + +static void ImportOneRow(const uint8_t* const r_ptr, + const uint8_t* const g_ptr, + const uint8_t* const b_ptr, + int rgb_step, + int rgb_bit_depth, + int pic_width, + fixed_y_t* const dst) { + // Convert the rgb_step from a number of bytes to a number of uint8_t or + // uint16_t values depending the bit depth. + const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step; + int i = 0; + const int w = (pic_width + 1) & ~1; + do { + const int off = i * step; + const int shift = GetPrecisionShift(rgb_bit_depth); + if (rgb_bit_depth == 8) { + dst[i + 0 * w] = Shift(r_ptr[off], shift); + dst[i + 1 * w] = Shift(g_ptr[off], shift); + dst[i + 2 * w] = Shift(b_ptr[off], shift); + } else { + dst[i + 0 * w] = Shift(((uint16_t*)r_ptr)[off], shift); + dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift); + dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift); + } + } while (++i < pic_width); + if (pic_width & 1) { // replicate rightmost pixel + dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1]; + dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1]; + dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1]; + } +} + +static void InterpolateTwoRows(const fixed_y_t* const best_y, + const fixed_t* prev_uv, + const fixed_t* cur_uv, + const fixed_t* next_uv, + int w, + fixed_y_t* out1, + fixed_y_t* out2, + int rgb_bit_depth) { + const int uv_w = w >> 1; + const int len = (w - 1) >> 1; // length to filter + int k = 3; + const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); + while (k-- > 0) { // process each R/G/B segments in turn + // special boundary case for i==0 + out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0], bit_depth); + out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w], bit_depth); + + SharpYuvFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1, + bit_depth); + SharpYuvFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1, + bit_depth); + + // special boundary case for i == w - 1 when w is even + if (!(w & 1)) { + out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1], + best_y[w - 1 + 0], bit_depth); + out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1], + best_y[w - 1 + w], bit_depth); + } + out1 += w; + out2 += w; + prev_uv += uv_w; + cur_uv += uv_w; + next_uv += uv_w; + } +} + +static WEBP_INLINE int RGBToYUVComponent(int r, int g, int b, + const int coeffs[4], int sfix) { + const int srounder = 1 << (YUV_FIX + sfix - 1); + const int luma = coeffs[0] * r + coeffs[1] * g + coeffs[2] * b + + coeffs[3] + srounder; + return (luma >> (YUV_FIX + sfix)); +} + +static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv, + uint8_t* y_ptr, int y_stride, uint8_t* u_ptr, + int u_stride, uint8_t* v_ptr, int v_stride, + int rgb_bit_depth, + int yuv_bit_depth, int width, int height, + const SharpYuvConversionMatrix* yuv_matrix) { + int i, j; + const fixed_t* const best_uv_base = best_uv; + const int w = (width + 1) & ~1; + const int h = (height + 1) & ~1; + const int uv_w = w >> 1; + const int uv_h = h >> 1; + const int sfix = GetPrecisionShift(rgb_bit_depth); + const int yuv_max = (1 << yuv_bit_depth) - 1; + + best_uv = best_uv_base; + j = 0; + do { + i = 0; + do { + const int off = (i >> 1); + const int W = best_y[i]; + const int r = best_uv[off + 0 * uv_w] + W; + const int g = best_uv[off + 1 * uv_w] + W; + const int b = best_uv[off + 2 * uv_w] + W; + const int y = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_y, sfix); + if (yuv_bit_depth <= 8) { + y_ptr[i] = clip_8b(y); + } else { + ((uint16_t*)y_ptr)[i] = clip(y, yuv_max); + } + } while (++i < width); + best_y += w; + best_uv += (j & 1) * 3 * uv_w; + y_ptr += y_stride; + } while (++j < height); + + best_uv = best_uv_base; + j = 0; + do { + i = 0; + do { + // Note r, g and b values here are off by W, but a constant offset on all + // 3 components doesn't change the value of u and v with a YCbCr matrix. + const int r = best_uv[i + 0 * uv_w]; + const int g = best_uv[i + 1 * uv_w]; + const int b = best_uv[i + 2 * uv_w]; + const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix); + const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix); + if (yuv_bit_depth <= 8) { + u_ptr[i] = clip_8b(u); + v_ptr[i] = clip_8b(v); + } else { + ((uint16_t*)u_ptr)[i] = clip(u, yuv_max); + ((uint16_t*)v_ptr)[i] = clip(v, yuv_max); + } + } while (++i < uv_w); + best_uv += 3 * uv_w; + u_ptr += u_stride; + v_ptr += v_stride; + } while (++j < uv_h); + return 1; +} + +//------------------------------------------------------------------------------ +// Main function + +static void* SafeMalloc(uint64_t nmemb, size_t size) { + const uint64_t total_size = nmemb * (uint64_t)size; + if (total_size != (size_t)total_size) return NULL; + return malloc((size_t)total_size); +} + +#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((uint64_t)(W) * (H), sizeof(T))) + +static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr, + const uint8_t* b_ptr, int rgb_step, int rgb_stride, + int rgb_bit_depth, uint8_t* y_ptr, int y_stride, + uint8_t* u_ptr, int u_stride, uint8_t* v_ptr, + int v_stride, int yuv_bit_depth, int width, + int height, + const SharpYuvConversionMatrix* yuv_matrix, + SharpYuvTransferFunctionType transfer_type) { + // we expand the right/bottom border if needed + const int w = (width + 1) & ~1; + const int h = (height + 1) & ~1; + const int uv_w = w >> 1; + const int uv_h = h >> 1; + const int y_bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); + uint64_t prev_diff_y_sum = ~0; + int j, iter; + + // TODO(skal): allocate one big memory chunk. But for now, it's easier + // for valgrind debugging to have several chunks. + fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch + fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t); + fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t); + fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); + fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); + fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); + fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); + fixed_y_t* best_y = best_y_base; + fixed_y_t* target_y = target_y_base; + fixed_t* best_uv = best_uv_base; + fixed_t* target_uv = target_uv_base; + const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h); + int ok; + assert(w > 0); + assert(h > 0); + + if (best_y_base == NULL || best_uv_base == NULL || + target_y_base == NULL || target_uv_base == NULL || + best_rgb_y == NULL || best_rgb_uv == NULL || + tmp_buffer == NULL) { + ok = 0; + goto End; + } + + // Import RGB samples to W/RGB representation. + for (j = 0; j < height; j += 2) { + const int is_last_row = (j == height - 1); + fixed_y_t* const src1 = tmp_buffer + 0 * w; + fixed_y_t* const src2 = tmp_buffer + 3 * w; + + // prepare two rows of input + ImportOneRow(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, width, + src1); + if (!is_last_row) { + ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride, + rgb_step, rgb_bit_depth, width, src2); + } else { + memcpy(src2, src1, 3 * w * sizeof(*src2)); + } + StoreGray(src1, best_y + 0, w); + StoreGray(src2, best_y + w, w); + + UpdateW(src1, target_y, w, rgb_bit_depth, transfer_type); + UpdateW(src2, target_y + w, w, rgb_bit_depth, transfer_type); + UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth, transfer_type); + memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv)); + best_y += 2 * w; + best_uv += 3 * uv_w; + target_y += 2 * w; + target_uv += 3 * uv_w; + r_ptr += 2 * rgb_stride; + g_ptr += 2 * rgb_stride; + b_ptr += 2 * rgb_stride; + } + + // Iterate and resolve clipping conflicts. + for (iter = 0; iter < kNumIterations; ++iter) { + const fixed_t* cur_uv = best_uv_base; + const fixed_t* prev_uv = best_uv_base; + uint64_t diff_y_sum = 0; + + best_y = best_y_base; + best_uv = best_uv_base; + target_y = target_y_base; + target_uv = target_uv_base; + j = 0; + do { + fixed_y_t* const src1 = tmp_buffer + 0 * w; + fixed_y_t* const src2 = tmp_buffer + 3 * w; + { + const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); + InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, + src1, src2, rgb_bit_depth); + prev_uv = cur_uv; + cur_uv = next_uv; + } + + UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth, transfer_type); + UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth, transfer_type); + UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth, transfer_type); + + // update two rows of Y and one row of RGB + diff_y_sum += + SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w, y_bit_depth); + SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w); + + best_y += 2 * w; + best_uv += 3 * uv_w; + target_y += 2 * w; + target_uv += 3 * uv_w; + j += 2; + } while (j < h); + // test exit condition + if (iter > 0) { + if (diff_y_sum < diff_y_threshold) break; + if (diff_y_sum > prev_diff_y_sum) break; + } + prev_diff_y_sum = diff_y_sum; + } + + // final reconstruction + ok = ConvertWRGBToYUV(best_y_base, best_uv_base, y_ptr, y_stride, u_ptr, + u_stride, v_ptr, v_stride, rgb_bit_depth, yuv_bit_depth, + width, height, yuv_matrix); + + End: + free(best_y_base); + free(best_uv_base); + free(target_y_base); + free(target_uv_base); + free(best_rgb_y); + free(best_rgb_uv); + free(tmp_buffer); + return ok; +} + +#undef SAFE_ALLOC + +#if defined(WEBP_USE_THREAD) && !defined(_WIN32) +#include // NOLINT + +#define LOCK_ACCESS \ + static pthread_mutex_t sharpyuv_lock = PTHREAD_MUTEX_INITIALIZER; \ + if (pthread_mutex_lock(&sharpyuv_lock)) return +#define UNLOCK_ACCESS_AND_RETURN \ + do { \ + (void)pthread_mutex_unlock(&sharpyuv_lock); \ + return; \ + } while (0) +#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32)) +#define LOCK_ACCESS do {} while (0) +#define UNLOCK_ACCESS_AND_RETURN return +#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32) + +// Hidden exported init function. +// By default SharpYuvConvert calls it with SharpYuvGetCPUInfo. If needed, +// users can declare it as extern and call it with an alternate VP8CPUInfo +// function. +extern VP8CPUInfo SharpYuvGetCPUInfo; +SHARPYUV_EXTERN void SharpYuvInit(VP8CPUInfo cpu_info_func); +void SharpYuvInit(VP8CPUInfo cpu_info_func) { + static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used = + (VP8CPUInfo)&sharpyuv_last_cpuinfo_used; + LOCK_ACCESS; + // Only update SharpYuvGetCPUInfo when called from external code to avoid a + // race on reading the value in SharpYuvConvert(). + if (cpu_info_func != (VP8CPUInfo)&SharpYuvGetCPUInfo) { + SharpYuvGetCPUInfo = cpu_info_func; + } + if (sharpyuv_last_cpuinfo_used == SharpYuvGetCPUInfo) { + UNLOCK_ACCESS_AND_RETURN; + } + + SharpYuvInitDsp(); + SharpYuvInitGammaTables(); + + sharpyuv_last_cpuinfo_used = SharpYuvGetCPUInfo; + UNLOCK_ACCESS_AND_RETURN; +} + +int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr, + int rgb_step, int rgb_stride, int rgb_bit_depth, + void* y_ptr, int y_stride, void* u_ptr, int u_stride, + void* v_ptr, int v_stride, int yuv_bit_depth, int width, + int height, const SharpYuvConversionMatrix* yuv_matrix) { + SharpYuvOptions options; + options.yuv_matrix = yuv_matrix; + options.transfer_type = kSharpYuvTransferFunctionSrgb; + return SharpYuvConvertWithOptions( + r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride, rgb_bit_depth, y_ptr, y_stride, + u_ptr, u_stride, v_ptr, v_stride, yuv_bit_depth, width, height, &options); +} + +int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix* yuv_matrix, + SharpYuvOptions* options, int version) { + const int major = (version >> 24); + const int minor = (version >> 16) & 0xff; + if (options == NULL || yuv_matrix == NULL || + (major == SHARPYUV_VERSION_MAJOR && major == 0 && + minor != SHARPYUV_VERSION_MINOR) || + (major != SHARPYUV_VERSION_MAJOR)) { + return 0; + } + options->yuv_matrix = yuv_matrix; + options->transfer_type = kSharpYuvTransferFunctionSrgb; + return 1; +} + +int SharpYuvConvertWithOptions(const void* r_ptr, const void* g_ptr, + const void* b_ptr, int rgb_step, int rgb_stride, + int rgb_bit_depth, void* y_ptr, int y_stride, + void* u_ptr, int u_stride, void* v_ptr, + int v_stride, int yuv_bit_depth, int width, + int height, const SharpYuvOptions* options) { + const SharpYuvConversionMatrix* yuv_matrix = options->yuv_matrix; + SharpYuvTransferFunctionType transfer_type = options->transfer_type; + SharpYuvConversionMatrix scaled_matrix; + const int rgb_max = (1 << rgb_bit_depth) - 1; + const int rgb_round = 1 << (rgb_bit_depth - 1); + const int yuv_max = (1 << yuv_bit_depth) - 1; + const int sfix = GetPrecisionShift(rgb_bit_depth); + + if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX || + r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || y_ptr == NULL || + u_ptr == NULL || v_ptr == NULL) { + return 0; + } + if (rgb_bit_depth != 8 && rgb_bit_depth != 10 && rgb_bit_depth != 12 && + rgb_bit_depth != 16) { + return 0; + } + if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) { + return 0; + } + if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride % 2 != 0)) { + // Step/stride should be even for uint16_t buffers. + return 0; + } + if (yuv_bit_depth > 8 && + (y_stride % 2 != 0 || u_stride % 2 != 0 || v_stride % 2 != 0)) { + // Stride should be even for uint16_t buffers. + return 0; + } + // The address of the function pointer is used to avoid a read race. + SharpYuvInit((VP8CPUInfo)&SharpYuvGetCPUInfo); + + // Add scaling factor to go from rgb_bit_depth to yuv_bit_depth, to the + // rgb->yuv conversion matrix. + if (rgb_bit_depth == yuv_bit_depth) { + memcpy(&scaled_matrix, yuv_matrix, sizeof(scaled_matrix)); + } else { + int i; + for (i = 0; i < 3; ++i) { + scaled_matrix.rgb_to_y[i] = + (yuv_matrix->rgb_to_y[i] * yuv_max + rgb_round) / rgb_max; + scaled_matrix.rgb_to_u[i] = + (yuv_matrix->rgb_to_u[i] * yuv_max + rgb_round) / rgb_max; + scaled_matrix.rgb_to_v[i] = + (yuv_matrix->rgb_to_v[i] * yuv_max + rgb_round) / rgb_max; + } + } + // Also incorporate precision change scaling. + scaled_matrix.rgb_to_y[3] = Shift(yuv_matrix->rgb_to_y[3], sfix); + scaled_matrix.rgb_to_u[3] = Shift(yuv_matrix->rgb_to_u[3], sfix); + scaled_matrix.rgb_to_v[3] = Shift(yuv_matrix->rgb_to_v[3], sfix); + + return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride, + rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride, + v_ptr, v_stride, yuv_bit_depth, width, height, + &scaled_matrix, transfer_type); +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/sharpyuv/sharpyuv.h b/libraries/webp/sharpyuv/sharpyuv.h new file mode 100644 index 00000000000..fe95891599e --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv.h @@ -0,0 +1,172 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Sharp RGB to YUV conversion. + +#ifndef WEBP_SHARPYUV_SHARPYUV_H_ +#define WEBP_SHARPYUV_SHARPYUV_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SHARPYUV_EXTERN +#ifdef WEBP_EXTERN +#define SHARPYUV_EXTERN WEBP_EXTERN +#else +// This explicitly marks library functions and allows for changing the +// signature for e.g., Windows DLL builds. +#if defined(_WIN32) && defined(WEBP_DLL) +#define SHARPYUV_EXTERN __declspec(dllexport) +#elif defined(__GNUC__) && __GNUC__ >= 4 +#define SHARPYUV_EXTERN extern __attribute__((visibility("default"))) +#else +#define SHARPYUV_EXTERN extern +#endif /* defined(_WIN32) && defined(WEBP_DLL) */ +#endif /* WEBP_EXTERN */ +#endif /* SHARPYUV_EXTERN */ + +#ifndef SHARPYUV_INLINE +#ifdef WEBP_INLINE +#define SHARPYUV_INLINE WEBP_INLINE +#else +#ifndef _MSC_VER +#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#define SHARPYUV_INLINE inline +#else +#define SHARPYUV_INLINE +#endif +#else +#define SHARPYUV_INLINE __forceinline +#endif /* _MSC_VER */ +#endif /* WEBP_INLINE */ +#endif /* SHARPYUV_INLINE */ + +// SharpYUV API version following the convention from semver.org +#define SHARPYUV_VERSION_MAJOR 0 +#define SHARPYUV_VERSION_MINOR 4 +#define SHARPYUV_VERSION_PATCH 0 +// Version as a uint32_t. The major number is the high 8 bits. +// The minor number is the middle 8 bits. The patch number is the low 16 bits. +#define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \ + (((MAJOR) << 24) | ((MINOR) << 16) | (PATCH)) +#define SHARPYUV_VERSION \ + SHARPYUV_MAKE_VERSION(SHARPYUV_VERSION_MAJOR, SHARPYUV_VERSION_MINOR, \ + SHARPYUV_VERSION_PATCH) + +// Returns the library's version number, packed in hexadecimal. See +// SHARPYUV_VERSION. +SHARPYUV_EXTERN int SharpYuvGetVersion(void); + +// RGB to YUV conversion matrix, in 16 bit fixed point. +// y = rgb_to_y[0] * r + rgb_to_y[1] * g + rgb_to_y[2] * b + rgb_to_y[3] +// u = rgb_to_u[0] * r + rgb_to_u[1] * g + rgb_to_u[2] * b + rgb_to_u[3] +// v = rgb_to_v[0] * r + rgb_to_v[1] * g + rgb_to_v[2] * b + rgb_to_v[3] +// Then y, u and v values are divided by 1<<16 and rounded. +typedef struct { + int rgb_to_y[4]; + int rgb_to_u[4]; + int rgb_to_v[4]; +} SharpYuvConversionMatrix; + +typedef struct SharpYuvOptions SharpYuvOptions; + +// Enums for transfer functions, as defined in H.273, +// https://www.itu.int/rec/T-REC-H.273-202107-I/en +typedef enum SharpYuvTransferFunctionType { + // 0 is reserved + kSharpYuvTransferFunctionBt709 = 1, + // 2 is unspecified + // 3 is reserved + kSharpYuvTransferFunctionBt470M = 4, + kSharpYuvTransferFunctionBt470Bg = 5, + kSharpYuvTransferFunctionBt601 = 6, + kSharpYuvTransferFunctionSmpte240 = 7, + kSharpYuvTransferFunctionLinear = 8, + kSharpYuvTransferFunctionLog100 = 9, + kSharpYuvTransferFunctionLog100_Sqrt10 = 10, + kSharpYuvTransferFunctionIec61966 = 11, + kSharpYuvTransferFunctionBt1361 = 12, + kSharpYuvTransferFunctionSrgb = 13, + kSharpYuvTransferFunctionBt2020_10Bit = 14, + kSharpYuvTransferFunctionBt2020_12Bit = 15, + kSharpYuvTransferFunctionSmpte2084 = 16, // PQ + kSharpYuvTransferFunctionSmpte428 = 17, + kSharpYuvTransferFunctionHlg = 18, + kSharpYuvTransferFunctionNum +} SharpYuvTransferFunctionType; + +// Converts RGB to YUV420 using a downsampling algorithm that minimizes +// artefacts caused by chroma subsampling. +// This is slower than standard downsampling (averaging of 4 UV values). +// Assumes that the image will be upsampled using a bilinear filter. If nearest +// neighbor is used instead, the upsampled image might look worse than with +// standard downsampling. +// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point +// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise. +// rgb_step: distance in bytes between two horizontally adjacent pixels on the +// r, g and b channels. If rgb_bit_depth is > 8, it should be a +// multiple of 2. +// rgb_stride: distance in bytes between two vertically adjacent pixels on the +// r, g, and b channels. If rgb_bit_depth is > 8, it should be a +// multiple of 2. +// rgb_bit_depth: number of bits for each r/g/b value. One of: 8, 10, 12, 16. +// Note: 16 bit input is truncated to 14 bits before conversion to yuv. +// yuv_bit_depth: number of bits for each y/u/v value. One of: 8, 10, 12. +// y_ptr, u_ptr, v_ptr: pointers to the destination y, u and v channels. Should +// point to uint8_t buffers if yuv_bit_depth is 8, or uint16_t buffers +// otherwise. +// y_stride, u_stride, v_stride: distance in bytes between two vertically +// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they +// should be multiples of 2. +// width, height: width and height of the image in pixels +// This function calls SharpYuvConvertWithOptions with a default transfer +// function of kSharpYuvTransferFunctionSrgb. +SHARPYUV_EXTERN int SharpYuvConvert(const void* r_ptr, const void* g_ptr, + const void* b_ptr, int rgb_step, + int rgb_stride, int rgb_bit_depth, + void* y_ptr, int y_stride, void* u_ptr, + int u_stride, void* v_ptr, int v_stride, + int yuv_bit_depth, int width, int height, + const SharpYuvConversionMatrix* yuv_matrix); + +struct SharpYuvOptions { + // This matrix cannot be NULL and can be initialized by + // SharpYuvComputeConversionMatrix. + const SharpYuvConversionMatrix* yuv_matrix; + SharpYuvTransferFunctionType transfer_type; +}; + +// Internal, version-checked, entry point +SHARPYUV_EXTERN int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix*, + SharpYuvOptions*, int); + +// Should always be called, to initialize a fresh SharpYuvOptions +// structure before modification. SharpYuvOptionsInit() must have succeeded +// before using the 'options' object. +static SHARPYUV_INLINE int SharpYuvOptionsInit( + const SharpYuvConversionMatrix* yuv_matrix, SharpYuvOptions* options) { + return SharpYuvOptionsInitInternal(yuv_matrix, options, SHARPYUV_VERSION); +} + +SHARPYUV_EXTERN int SharpYuvConvertWithOptions( + const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step, + int rgb_stride, int rgb_bit_depth, void* y_ptr, int y_stride, void* u_ptr, + int u_stride, void* v_ptr, int v_stride, int yuv_bit_depth, int width, + int height, const SharpYuvOptions* options); + +// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422 +// support (it's rarely used in practice, especially for images). + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_SHARPYUV_SHARPYUV_H_ diff --git a/libraries/webp/sharpyuv/sharpyuv_cpu.c b/libraries/webp/sharpyuv/sharpyuv_cpu.c new file mode 100644 index 00000000000..29425a0c491 --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_cpu.c @@ -0,0 +1,14 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +#include "sharpyuv/sharpyuv_cpu.h" + +// Include src/dsp/cpu.c to create SharpYuvGetCPUInfo from VP8GetCPUInfo. The +// function pointer is renamed in sharpyuv_cpu.h. +#include "src/dsp/cpu.c" diff --git a/libraries/webp/sharpyuv/sharpyuv_cpu.h b/libraries/webp/sharpyuv/sharpyuv_cpu.h new file mode 100644 index 00000000000..176ca3eb168 --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_cpu.h @@ -0,0 +1,22 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +#ifndef WEBP_SHARPYUV_SHARPYUV_CPU_H_ +#define WEBP_SHARPYUV_SHARPYUV_CPU_H_ + +#include "sharpyuv/sharpyuv.h" + +// Avoid exporting SharpYuvGetCPUInfo in shared object / DLL builds. +// SharpYuvInit() replaces the use of the function pointer. +#undef WEBP_EXTERN +#define WEBP_EXTERN extern +#define VP8GetCPUInfo SharpYuvGetCPUInfo +#include "src/dsp/cpu.h" + +#endif // WEBP_SHARPYUV_SHARPYUV_CPU_H_ diff --git a/libraries/webp/sharpyuv/sharpyuv_csp.c b/libraries/webp/sharpyuv/sharpyuv_csp.c new file mode 100644 index 00000000000..0ad22be9458 --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_csp.c @@ -0,0 +1,110 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Colorspace utilities. + +#include "sharpyuv/sharpyuv_csp.h" + +#include +#include +#include + +static int ToFixed16(float f) { return (int)floor(f * (1 << 16) + 0.5f); } + +void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space, + SharpYuvConversionMatrix* matrix) { + const float kr = yuv_color_space->kr; + const float kb = yuv_color_space->kb; + const float kg = 1.0f - kr - kb; + const float cr = 0.5f / (1.0f - kb); + const float cb = 0.5f / (1.0f - kr); + + const int shift = yuv_color_space->bit_depth - 8; + + const float denom = (float)((1 << yuv_color_space->bit_depth) - 1); + float scale_y = 1.0f; + float add_y = 0.0f; + float scale_u = cr; + float scale_v = cb; + float add_uv = (float)(128 << shift); + assert(yuv_color_space->bit_depth >= 8); + + if (yuv_color_space->range == kSharpYuvRangeLimited) { + scale_y *= (219 << shift) / denom; + scale_u *= (224 << shift) / denom; + scale_v *= (224 << shift) / denom; + add_y = (float)(16 << shift); + } + + matrix->rgb_to_y[0] = ToFixed16(kr * scale_y); + matrix->rgb_to_y[1] = ToFixed16(kg * scale_y); + matrix->rgb_to_y[2] = ToFixed16(kb * scale_y); + matrix->rgb_to_y[3] = ToFixed16(add_y); + + matrix->rgb_to_u[0] = ToFixed16(-kr * scale_u); + matrix->rgb_to_u[1] = ToFixed16(-kg * scale_u); + matrix->rgb_to_u[2] = ToFixed16((1 - kb) * scale_u); + matrix->rgb_to_u[3] = ToFixed16(add_uv); + + matrix->rgb_to_v[0] = ToFixed16((1 - kr) * scale_v); + matrix->rgb_to_v[1] = ToFixed16(-kg * scale_v); + matrix->rgb_to_v[2] = ToFixed16(-kb * scale_v); + matrix->rgb_to_v[3] = ToFixed16(add_uv); +} + +// Matrices are in YUV_FIX fixed point precision. +// WebP's matrix, similar but not identical to kRec601LimitedMatrix. +static const SharpYuvConversionMatrix kWebpMatrix = { + {16839, 33059, 6420, 16 << 16}, + {-9719, -19081, 28800, 128 << 16}, + {28800, -24116, -4684, 128 << 16}, +}; +// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeLimited +static const SharpYuvConversionMatrix kRec601LimitedMatrix = { + {16829, 33039, 6416, 16 << 16}, + {-9714, -19071, 28784, 128 << 16}, + {28784, -24103, -4681, 128 << 16}, +}; +// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeFull +static const SharpYuvConversionMatrix kRec601FullMatrix = { + {19595, 38470, 7471, 0}, + {-11058, -21710, 32768, 128 << 16}, + {32768, -27439, -5329, 128 << 16}, +}; +// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeLimited +static const SharpYuvConversionMatrix kRec709LimitedMatrix = { + {11966, 40254, 4064, 16 << 16}, + {-6596, -22189, 28784, 128 << 16}, + {28784, -26145, -2639, 128 << 16}, +}; +// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeFull +static const SharpYuvConversionMatrix kRec709FullMatrix = { + {13933, 46871, 4732, 0}, + {-7509, -25259, 32768, 128 << 16}, + {32768, -29763, -3005, 128 << 16}, +}; + +const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( + SharpYuvMatrixType matrix_type) { + switch (matrix_type) { + case kSharpYuvMatrixWebp: + return &kWebpMatrix; + case kSharpYuvMatrixRec601Limited: + return &kRec601LimitedMatrix; + case kSharpYuvMatrixRec601Full: + return &kRec601FullMatrix; + case kSharpYuvMatrixRec709Limited: + return &kRec709LimitedMatrix; + case kSharpYuvMatrixRec709Full: + return &kRec709FullMatrix; + case kSharpYuvMatrixNum: + return NULL; + } + return NULL; +} diff --git a/libraries/webp/sharpyuv/sharpyuv_csp.h b/libraries/webp/sharpyuv/sharpyuv_csp.h new file mode 100644 index 00000000000..3214e3ac607 --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_csp.h @@ -0,0 +1,60 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Colorspace utilities. + +#ifndef WEBP_SHARPYUV_SHARPYUV_CSP_H_ +#define WEBP_SHARPYUV_SHARPYUV_CSP_H_ + +#include "sharpyuv/sharpyuv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Range of YUV values. +typedef enum { + kSharpYuvRangeFull, // YUV values between [0;255] (for 8 bit) + kSharpYuvRangeLimited // Y in [16;235], YUV in [16;240] (for 8 bit) +} SharpYuvRange; + +// Constants that define a YUV color space. +typedef struct { + // Kr and Kb are defined such that: + // Y = Kr * r + Kg * g + Kb * b where Kg = 1 - Kr - Kb. + float kr; + float kb; + int bit_depth; // 8, 10 or 12 + SharpYuvRange range; +} SharpYuvColorSpace; + +// Fills in 'matrix' for the given YUVColorSpace. +SHARPYUV_EXTERN void SharpYuvComputeConversionMatrix( + const SharpYuvColorSpace* yuv_color_space, + SharpYuvConversionMatrix* matrix); + +// Enums for precomputed conversion matrices. +typedef enum { + kSharpYuvMatrixWebp = 0, + kSharpYuvMatrixRec601Limited, + kSharpYuvMatrixRec601Full, + kSharpYuvMatrixRec709Limited, + kSharpYuvMatrixRec709Full, + kSharpYuvMatrixNum +} SharpYuvMatrixType; + +// Returns a pointer to a matrix for one of the predefined colorspaces. +SHARPYUV_EXTERN const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( + SharpYuvMatrixType matrix_type); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_SHARPYUV_SHARPYUV_CSP_H_ diff --git a/libraries/webp/sharpyuv/sharpyuv_dsp.c b/libraries/webp/sharpyuv/sharpyuv_dsp.c new file mode 100644 index 00000000000..b539d61e134 --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_dsp.c @@ -0,0 +1,104 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions for Sharp YUV. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "sharpyuv/sharpyuv_dsp.h" + +#include +#include + +#include "sharpyuv/sharpyuv_cpu.h" +#include "include/webp/types.h" + +//----------------------------------------------------------------------------- + +#if !WEBP_NEON_OMIT_C_CODE +static uint16_t clip(int v, int max) { + return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; +} + +static uint64_t SharpYuvUpdateY_C(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len, int bit_depth) { + uint64_t diff = 0; + int i; + const int max_y = (1 << bit_depth) - 1; + for (i = 0; i < len; ++i) { + const int diff_y = ref[i] - src[i]; + const int new_y = (int)dst[i] + diff_y; + dst[i] = clip(new_y, max_y); + diff += (uint64_t)abs(diff_y); + } + return diff; +} + +static void SharpYuvUpdateRGB_C(const int16_t* ref, const int16_t* src, + int16_t* dst, int len) { + int i; + for (i = 0; i < len; ++i) { + const int diff_uv = ref[i] - src[i]; + dst[i] += diff_uv; + } +} + +static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth) { + int i; + const int max_y = (1 << bit_depth) - 1; + for (i = 0; i < len; ++i, ++A, ++B) { + const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4; + const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4; + out[2 * i + 0] = clip(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip(best_y[2 * i + 1] + v1, max_y); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//----------------------------------------------------------------------------- + +uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref, + uint16_t* dst, int len, int bit_depth); +void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst, + int len); +void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, int bit_depth); + +extern VP8CPUInfo SharpYuvGetCPUInfo; +extern void InitSharpYuvSSE2(void); +extern void InitSharpYuvNEON(void); + +void SharpYuvInitDsp(void) { +#if !WEBP_NEON_OMIT_C_CODE + SharpYuvUpdateY = SharpYuvUpdateY_C; + SharpYuvUpdateRGB = SharpYuvUpdateRGB_C; + SharpYuvFilterRow = SharpYuvFilterRow_C; +#endif + + if (SharpYuvGetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (SharpYuvGetCPUInfo(kSSE2)) { + InitSharpYuvSSE2(); + } +#endif // WEBP_HAVE_SSE2 + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (SharpYuvGetCPUInfo != NULL && SharpYuvGetCPUInfo(kNEON))) { + InitSharpYuvNEON(); + } +#endif // WEBP_HAVE_NEON + + assert(SharpYuvUpdateY != NULL); + assert(SharpYuvUpdateRGB != NULL); + assert(SharpYuvFilterRow != NULL); +} diff --git a/libraries/webp/sharpyuv/sharpyuv_dsp.h b/libraries/webp/sharpyuv/sharpyuv_dsp.h new file mode 100644 index 00000000000..1822375015f --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_dsp.h @@ -0,0 +1,28 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions for Sharp YUV. + +#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_ +#define WEBP_SHARPYUV_SHARPYUV_DSP_H_ + +#include "sharpyuv/sharpyuv_cpu.h" +#include "include/webp/types.h" + +extern uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref, + uint16_t* dst, int len, int bit_depth); +extern void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, + int16_t* dst, int len); +extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth); + +void SharpYuvInitDsp(void); + +#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_ diff --git a/libraries/webp/sharpyuv/sharpyuv_gamma.c b/libraries/webp/sharpyuv/sharpyuv_gamma.c new file mode 100644 index 00000000000..4c79d634ff0 --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_gamma.c @@ -0,0 +1,419 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Gamma correction utilities. + +#include "sharpyuv/sharpyuv_gamma.h" + +#include +#include +#include + +#include "include/webp/types.h" + +// Gamma correction compensates loss of resolution during chroma subsampling. +// Size of pre-computed table for converting from gamma to linear. +#define GAMMA_TO_LINEAR_TAB_BITS 10 +#define GAMMA_TO_LINEAR_TAB_SIZE (1 << GAMMA_TO_LINEAR_TAB_BITS) +static uint32_t kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 2]; +#define LINEAR_TO_GAMMA_TAB_BITS 9 +#define LINEAR_TO_GAMMA_TAB_SIZE (1 << LINEAR_TO_GAMMA_TAB_BITS) +static uint32_t kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 2]; + +static const double kGammaF = 1. / 0.45; +#define GAMMA_TO_LINEAR_BITS 16 + +static volatile int kGammaTablesSOk = 0; +void SharpYuvInitGammaTables(void) { + assert(GAMMA_TO_LINEAR_BITS <= 16); + if (!kGammaTablesSOk) { + int v; + const double a = 0.09929682680944; + const double thresh = 0.018053968510807; + const double final_scale = 1 << GAMMA_TO_LINEAR_BITS; + // Precompute gamma to linear table. + { + const double norm = 1. / GAMMA_TO_LINEAR_TAB_SIZE; + const double a_rec = 1. / (1. + a); + for (v = 0; v <= GAMMA_TO_LINEAR_TAB_SIZE; ++v) { + const double g = norm * v; + double value; + if (g <= thresh * 4.5) { + value = g / 4.5; + } else { + value = pow(a_rec * (g + a), kGammaF); + } + kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5); + } + // to prevent small rounding errors to cause read-overflow: + kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 1] = + kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE]; + } + // Precompute linear to gamma table. + { + const double scale = 1. / LINEAR_TO_GAMMA_TAB_SIZE; + for (v = 0; v <= LINEAR_TO_GAMMA_TAB_SIZE; ++v) { + const double g = scale * v; + double value; + if (g <= thresh) { + value = 4.5 * g; + } else { + value = (1. + a) * pow(g, 1. / kGammaF) - a; + } + kLinearToGammaTabS[v] = + (uint32_t)(final_scale * value + 0.5); + } + // to prevent small rounding errors to cause read-overflow: + kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 1] = + kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE]; + } + kGammaTablesSOk = 1; + } +} + +static WEBP_INLINE int Shift(int v, int shift) { + return (shift >= 0) ? (v << shift) : (v >> -shift); +} + +static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab, + int tab_pos_shift_right, + int tab_value_shift) { + const uint32_t tab_pos = Shift(v, -tab_pos_shift_right); + // fractional part, in 'tab_pos_shift' fixed-point precision + const uint32_t x = v - (tab_pos << tab_pos_shift_right); // fractional part + // v0 / v1 are in kGammaToLinearBits fixed-point precision (range [0..1]) + const uint32_t v0 = Shift(tab[tab_pos + 0], tab_value_shift); + const uint32_t v1 = Shift(tab[tab_pos + 1], tab_value_shift); + // Final interpolation. + const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0. + const int half = + (tab_pos_shift_right > 0) ? 1 << (tab_pos_shift_right - 1) : 0; + const uint32_t result = v0 + ((v2 + half) >> tab_pos_shift_right); + return result; +} + +static uint32_t ToLinearSrgb(uint16_t v, int bit_depth) { + const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth; + if (shift > 0) { + return kGammaToLinearTabS[v << shift]; + } + return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0); +} + +static uint16_t FromLinearSrgb(uint32_t value, int bit_depth) { + return FixedPointInterpolation( + value, kLinearToGammaTabS, + (GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS), + bit_depth - GAMMA_TO_LINEAR_BITS); +} + +//////////////////////////////////////////////////////////////////////////////// + +#define CLAMP(x, low, high) \ + (((x) < (low)) ? (low) : (((high) < (x)) ? (high) : (x))) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +static WEBP_INLINE float Roundf(float x) { + if (x < 0) + return (float)ceil((double)(x - 0.5f)); + else + return (float)floor((double)(x + 0.5f)); +} + +static WEBP_INLINE float Powf(float base, float exp) { + return (float)pow((double)base, (double)exp); +} + +static WEBP_INLINE float Log10f(float x) { return (float)log10((double)x); } + +static float ToLinear709(float gamma) { + if (gamma < 0.f) { + return 0.f; + } else if (gamma < 4.5f * 0.018053968510807f) { + return gamma / 4.5f; + } else if (gamma < 1.f) { + return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f); + } + return 1.f; +} + +static float FromLinear709(float linear) { + if (linear < 0.f) { + return 0.f; + } else if (linear < 0.018053968510807f) { + return linear * 4.5f; + } else if (linear < 1.f) { + return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f; + } + return 1.f; +} + +static float ToLinear470M(float gamma) { + return Powf(CLAMP(gamma, 0.f, 1.f), 2.2f); +} + +static float FromLinear470M(float linear) { + return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.2f); +} + +static float ToLinear470Bg(float gamma) { + return Powf(CLAMP(gamma, 0.f, 1.f), 2.8f); +} + +static float FromLinear470Bg(float linear) { + return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.8f); +} + +static float ToLinearSmpte240(float gamma) { + if (gamma < 0.f) { + return 0.f; + } else if (gamma < 4.f * 0.022821585529445f) { + return gamma / 4.f; + } else if (gamma < 1.f) { + return Powf((gamma + 0.111572195921731f) / 1.111572195921731f, 1.f / 0.45f); + } + return 1.f; +} + +static float FromLinearSmpte240(float linear) { + if (linear < 0.f) { + return 0.f; + } else if (linear < 0.022821585529445f) { + return linear * 4.f; + } else if (linear < 1.f) { + return 1.111572195921731f * Powf(linear, 0.45f) - 0.111572195921731f; + } + return 1.f; +} + +static float ToLinearLog100(float gamma) { + // The function is non-bijective so choose the middle of [0, 0.01]. + const float mid_interval = 0.01f / 2.f; + return (gamma <= 0.0f) ? mid_interval + : Powf(10.0f, 2.f * (MIN(gamma, 1.f) - 1.0f)); +} + +static float FromLinearLog100(float linear) { + return (linear < 0.01f) ? 0.0f : 1.0f + Log10f(MIN(linear, 1.f)) / 2.0f; +} + +static float ToLinearLog100Sqrt10(float gamma) { + // The function is non-bijective so choose the middle of [0, 0.00316227766f[. + const float mid_interval = 0.00316227766f / 2.f; + return (gamma <= 0.0f) ? mid_interval + : Powf(10.0f, 2.5f * (MIN(gamma, 1.f) - 1.0f)); +} + +static float FromLinearLog100Sqrt10(float linear) { + return (linear < 0.00316227766f) ? 0.0f + : 1.0f + Log10f(MIN(linear, 1.f)) / 2.5f; +} + +static float ToLinearIec61966(float gamma) { + if (gamma <= -4.5f * 0.018053968510807f) { + return Powf((-gamma + 0.09929682680944f) / -1.09929682680944f, 1.f / 0.45f); + } else if (gamma < 4.5f * 0.018053968510807f) { + return gamma / 4.5f; + } + return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f); +} + +static float FromLinearIec61966(float linear) { + if (linear <= -0.018053968510807f) { + return -1.09929682680944f * Powf(-linear, 0.45f) + 0.09929682680944f; + } else if (linear < 0.018053968510807f) { + return linear * 4.5f; + } + return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f; +} + +static float ToLinearBt1361(float gamma) { + if (gamma < -0.25f) { + return -0.25f; + } else if (gamma < 0.f) { + return Powf((gamma - 0.02482420670236f) / -0.27482420670236f, 1.f / 0.45f) / + -4.f; + } else if (gamma < 4.5f * 0.018053968510807f) { + return gamma / 4.5f; + } else if (gamma < 1.f) { + return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f); + } + return 1.f; +} + +static float FromLinearBt1361(float linear) { + if (linear < -0.25f) { + return -0.25f; + } else if (linear < 0.f) { + return -0.27482420670236f * Powf(-4.f * linear, 0.45f) + 0.02482420670236f; + } else if (linear < 0.018053968510807f) { + return linear * 4.5f; + } else if (linear < 1.f) { + return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f; + } + return 1.f; +} + +static float ToLinearPq(float gamma) { + if (gamma > 0.f) { + const float pow_gamma = Powf(gamma, 32.f / 2523.f); + const float num = MAX(pow_gamma - 107.f / 128.f, 0.0f); + const float den = MAX(2413.f / 128.f - 2392.f / 128.f * pow_gamma, FLT_MIN); + return Powf(num / den, 4096.f / 653.f); + } + return 0.f; +} + +static float FromLinearPq(float linear) { + if (linear > 0.f) { + const float pow_linear = Powf(linear, 653.f / 4096.f); + const float num = 107.f / 128.f + 2413.f / 128.f * pow_linear; + const float den = 1.0f + 2392.f / 128.f * pow_linear; + return Powf(num / den, 2523.f / 32.f); + } + return 0.f; +} + +static float ToLinearSmpte428(float gamma) { + return Powf(MAX(gamma, 0.f), 2.6f) / 0.91655527974030934f; +} + +static float FromLinearSmpte428(float linear) { + return Powf(0.91655527974030934f * MAX(linear, 0.f), 1.f / 2.6f); +} + +// Conversion in BT.2100 requires RGB info. Simplify to gamma correction here. +static float ToLinearHlg(float gamma) { + if (gamma < 0.f) { + return 0.f; + } else if (gamma <= 0.5f) { + return Powf((gamma * gamma) * (1.f / 3.f), 1.2f); + } + return Powf((expf((gamma - 0.55991073f) / 0.17883277f) + 0.28466892f) / 12.0f, + 1.2f); +} + +static float FromLinearHlg(float linear) { + linear = Powf(linear, 1.f / 1.2f); + if (linear < 0.f) { + return 0.f; + } else if (linear <= (1.f / 12.f)) { + return sqrtf(3.f * linear); + } + return 0.17883277f * logf(12.f * linear - 0.28466892f) + 0.55991073f; +} + +uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth, + SharpYuvTransferFunctionType transfer_type) { + float v_float, linear; + if (transfer_type == kSharpYuvTransferFunctionSrgb) { + return ToLinearSrgb(v, bit_depth); + } + v_float = (float)v / ((1 << bit_depth) - 1); + switch (transfer_type) { + case kSharpYuvTransferFunctionBt709: + case kSharpYuvTransferFunctionBt601: + case kSharpYuvTransferFunctionBt2020_10Bit: + case kSharpYuvTransferFunctionBt2020_12Bit: + linear = ToLinear709(v_float); + break; + case kSharpYuvTransferFunctionBt470M: + linear = ToLinear470M(v_float); + break; + case kSharpYuvTransferFunctionBt470Bg: + linear = ToLinear470Bg(v_float); + break; + case kSharpYuvTransferFunctionSmpte240: + linear = ToLinearSmpte240(v_float); + break; + case kSharpYuvTransferFunctionLinear: + return v; + case kSharpYuvTransferFunctionLog100: + linear = ToLinearLog100(v_float); + break; + case kSharpYuvTransferFunctionLog100_Sqrt10: + linear = ToLinearLog100Sqrt10(v_float); + break; + case kSharpYuvTransferFunctionIec61966: + linear = ToLinearIec61966(v_float); + break; + case kSharpYuvTransferFunctionBt1361: + linear = ToLinearBt1361(v_float); + break; + case kSharpYuvTransferFunctionSmpte2084: + linear = ToLinearPq(v_float); + break; + case kSharpYuvTransferFunctionSmpte428: + linear = ToLinearSmpte428(v_float); + break; + case kSharpYuvTransferFunctionHlg: + linear = ToLinearHlg(v_float); + break; + default: + assert(0); + linear = 0; + break; + } + return (uint32_t)Roundf(linear * ((1 << 16) - 1)); +} + +uint16_t SharpYuvLinearToGamma(uint32_t v, int bit_depth, + SharpYuvTransferFunctionType transfer_type) { + float v_float, linear; + if (transfer_type == kSharpYuvTransferFunctionSrgb) { + return FromLinearSrgb(v, bit_depth); + } + v_float = (float)v / ((1 << 16) - 1); + switch (transfer_type) { + case kSharpYuvTransferFunctionBt709: + case kSharpYuvTransferFunctionBt601: + case kSharpYuvTransferFunctionBt2020_10Bit: + case kSharpYuvTransferFunctionBt2020_12Bit: + linear = FromLinear709(v_float); + break; + case kSharpYuvTransferFunctionBt470M: + linear = FromLinear470M(v_float); + break; + case kSharpYuvTransferFunctionBt470Bg: + linear = FromLinear470Bg(v_float); + break; + case kSharpYuvTransferFunctionSmpte240: + linear = FromLinearSmpte240(v_float); + break; + case kSharpYuvTransferFunctionLinear: + return v; + case kSharpYuvTransferFunctionLog100: + linear = FromLinearLog100(v_float); + break; + case kSharpYuvTransferFunctionLog100_Sqrt10: + linear = FromLinearLog100Sqrt10(v_float); + break; + case kSharpYuvTransferFunctionIec61966: + linear = FromLinearIec61966(v_float); + break; + case kSharpYuvTransferFunctionBt1361: + linear = FromLinearBt1361(v_float); + break; + case kSharpYuvTransferFunctionSmpte2084: + linear = FromLinearPq(v_float); + break; + case kSharpYuvTransferFunctionSmpte428: + linear = FromLinearSmpte428(v_float); + break; + case kSharpYuvTransferFunctionHlg: + linear = FromLinearHlg(v_float); + break; + default: + assert(0); + linear = 0; + break; + } + return (uint16_t)Roundf(linear * ((1 << bit_depth) - 1)); +} diff --git a/libraries/webp/sharpyuv/sharpyuv_gamma.h b/libraries/webp/sharpyuv/sharpyuv_gamma.h new file mode 100644 index 00000000000..d5215069edd --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_gamma.h @@ -0,0 +1,38 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Gamma correction utilities. + +#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ +#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ + +#include "sharpyuv/sharpyuv.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes precomputed tables. Must be called once before calling +// SharpYuvGammaToLinear or SharpYuvLinearToGamma. +void SharpYuvInitGammaTables(void); + +// Converts a 'bit_depth'-bit gamma color value to a 16-bit linear value. +uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth, + SharpYuvTransferFunctionType transfer_type); + +// Converts a 16-bit linear color value to a 'bit_depth'-bit gamma value. +uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth, + SharpYuvTransferFunctionType transfer_type); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ diff --git a/libraries/webp/sharpyuv/sharpyuv_neon.c b/libraries/webp/sharpyuv/sharpyuv_neon.c new file mode 100644 index 00000000000..5840914865e --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_neon.c @@ -0,0 +1,181 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions for Sharp YUV. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "sharpyuv/sharpyuv_dsp.h" + +#if defined(WEBP_USE_NEON) +#include +#include +#include + +static uint16_t clip_NEON(int v, int max) { + return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; +} + +static uint64_t SharpYuvUpdateY_NEON(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const int16x8_t zero = vdupq_n_s16(0); + const int16x8_t max = vdupq_n_s16(max_y); + uint64x2_t sum = vdupq_n_u64(0); + uint64_t diff; + + for (i = 0; i + 8 <= len; i += 8) { + const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i)); + const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i)); + const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i)); + const int16x8_t D = vsubq_s16(A, B); // diff_y + const int16x8_t F = vaddq_s16(C, D); // new_y + const uint16x8_t H = + vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero)); + const int16x8_t I = vabsq_s16(D); // abs(diff_y) + vst1q_u16(dst + i, H); + sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I))); + } + diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1); + for (; i < len; ++i) { + const int diff_y = ref[i] - src[i]; + const int new_y = (int)(dst[i]) + diff_y; + dst[i] = clip_NEON(new_y, max_y); + diff += (uint64_t)(abs(diff_y)); + } + return diff; +} + +static void SharpYuvUpdateRGB_NEON(const int16_t* ref, const int16_t* src, + int16_t* dst, int len) { + int i; + for (i = 0; i + 8 <= len; i += 8) { + const int16x8_t A = vld1q_s16(ref + i); + const int16x8_t B = vld1q_s16(src + i); + const int16x8_t C = vld1q_s16(dst + i); + const int16x8_t D = vsubq_s16(A, B); // diff_uv + const int16x8_t E = vaddq_s16(C, D); // new_uv + vst1q_s16(dst + i, E); + } + for (; i < len; ++i) { + const int diff_uv = ref[i] - src[i]; + dst[i] += diff_uv; + } +} + +static void SharpYuvFilterRow16_NEON(const int16_t* A, const int16_t* B, + int len, const uint16_t* best_y, + uint16_t* out, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const int16x8_t max = vdupq_n_s16(max_y); + const int16x8_t zero = vdupq_n_s16(0); + for (i = 0; i + 8 <= len; i += 8) { + const int16x8_t a0 = vld1q_s16(A + i + 0); + const int16x8_t a1 = vld1q_s16(A + i + 1); + const int16x8_t b0 = vld1q_s16(B + i + 0); + const int16x8_t b1 = vld1q_s16(B + i + 1); + const int16x8_t a0b1 = vaddq_s16(a0, b1); + const int16x8_t a1b0 = vaddq_s16(a1, b0); + const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1 + const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1) + const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0) + const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3); + const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3); + const int16x8_t e0 = vrhaddq_s16(c1, a0); + const int16x8_t e1 = vrhaddq_s16(c0, a1); + const int16x8x2_t f = vzipq_s16(e0, e1); + const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0)); + const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8)); + const int16x8_t h0 = vaddq_s16(g0, f.val[0]); + const int16x8_t h1 = vaddq_s16(g1, f.val[1]); + const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero); + const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero); + vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0)); + vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1)); + } + for (; i < len; ++i) { + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y); + } +} + +static void SharpYuvFilterRow32_NEON(const int16_t* A, const int16_t* B, + int len, const uint16_t* best_y, + uint16_t* out, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const uint16x8_t max = vdupq_n_u16(max_y); + for (i = 0; i + 4 <= len; i += 4) { + const int16x4_t a0 = vld1_s16(A + i + 0); + const int16x4_t a1 = vld1_s16(A + i + 1); + const int16x4_t b0 = vld1_s16(B + i + 0); + const int16x4_t b1 = vld1_s16(B + i + 1); + const int32x4_t a0b1 = vaddl_s16(a0, b1); + const int32x4_t a1b0 = vaddl_s16(a1, b0); + const int32x4_t a0a1b0b1 = vaddq_s32(a0b1, a1b0); // A0+A1+B0+B1 + const int32x4_t a0b1_2 = vaddq_s32(a0b1, a0b1); // 2*(A0+B1) + const int32x4_t a1b0_2 = vaddq_s32(a1b0, a1b0); // 2*(A1+B0) + const int32x4_t c0 = vshrq_n_s32(vaddq_s32(a0b1_2, a0a1b0b1), 3); + const int32x4_t c1 = vshrq_n_s32(vaddq_s32(a1b0_2, a0a1b0b1), 3); + const int32x4_t e0 = vrhaddq_s32(c1, vmovl_s16(a0)); + const int32x4_t e1 = vrhaddq_s32(c0, vmovl_s16(a1)); + const int32x4x2_t f = vzipq_s32(e0, e1); + + const int16x8_t g = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i)); + const int32x4_t h0 = vaddw_s16(f.val[0], vget_low_s16(g)); + const int32x4_t h1 = vaddw_s16(f.val[1], vget_high_s16(g)); + const uint16x8_t i_16 = vcombine_u16(vqmovun_s32(h0), vqmovun_s32(h1)); + const uint16x8_t i_clamped = vminq_u16(i_16, max); + vst1q_u16(out + 2 * i + 0, i_clamped); + } + for (; i < len; ++i) { + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y); + } +} + +static void SharpYuvFilterRow_NEON(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth) { + if (bit_depth <= 10) { + SharpYuvFilterRow16_NEON(A, B, len, best_y, out, bit_depth); + } else { + SharpYuvFilterRow32_NEON(A, B, len, best_y, out, bit_depth); + } +} + +//------------------------------------------------------------------------------ + +extern void InitSharpYuvNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) { + SharpYuvUpdateY = SharpYuvUpdateY_NEON; + SharpYuvUpdateRGB = SharpYuvUpdateRGB_NEON; + SharpYuvFilterRow = SharpYuvFilterRow_NEON; +} + +#else // !WEBP_USE_NEON + +extern void InitSharpYuvNEON(void); + +void InitSharpYuvNEON(void) {} + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/sharpyuv/sharpyuv_sse2.c b/libraries/webp/sharpyuv/sharpyuv_sse2.c new file mode 100644 index 00000000000..9744d1bb6cf --- /dev/null +++ b/libraries/webp/sharpyuv/sharpyuv_sse2.c @@ -0,0 +1,201 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions for Sharp YUV. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "sharpyuv/sharpyuv_dsp.h" + +#if defined(WEBP_USE_SSE2) +#include +#include + +static uint16_t clip_SSE2(int v, int max) { + return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; +} + +static uint64_t SharpYuvUpdateY_SSE2(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + uint64_t diff = 0; + uint32_t tmp[4]; + int i; + const __m128i zero = _mm_setzero_si128(); + const __m128i max = _mm_set1_epi16(max_y); + const __m128i one = _mm_set1_epi16(1); + __m128i sum = zero; + + for (i = 0; i + 8 <= len; i += 8) { + const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); + const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); + const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); + const __m128i D = _mm_sub_epi16(A, B); // diff_y + const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0) + const __m128i F = _mm_add_epi16(C, D); // new_y + const __m128i G = _mm_or_si128(E, one); // -1 or 1 + const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero); + const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...)) + _mm_storeu_si128((__m128i*)(dst + i), H); + sum = _mm_add_epi32(sum, I); + } + _mm_storeu_si128((__m128i*)tmp, sum); + diff = tmp[3] + tmp[2] + tmp[1] + tmp[0]; + for (; i < len; ++i) { + const int diff_y = ref[i] - src[i]; + const int new_y = (int)dst[i] + diff_y; + dst[i] = clip_SSE2(new_y, max_y); + diff += (uint64_t)abs(diff_y); + } + return diff; +} + +static void SharpYuvUpdateRGB_SSE2(const int16_t* ref, const int16_t* src, + int16_t* dst, int len) { + int i = 0; + for (i = 0; i + 8 <= len; i += 8) { + const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); + const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); + const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); + const __m128i D = _mm_sub_epi16(A, B); // diff_uv + const __m128i E = _mm_add_epi16(C, D); // new_uv + _mm_storeu_si128((__m128i*)(dst + i), E); + } + for (; i < len; ++i) { + const int diff_uv = ref[i] - src[i]; + dst[i] += diff_uv; + } +} + +static void SharpYuvFilterRow16_SSE2(const int16_t* A, const int16_t* B, + int len, const uint16_t* best_y, + uint16_t* out, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const __m128i kCst8 = _mm_set1_epi16(8); + const __m128i max = _mm_set1_epi16(max_y); + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 8 <= len; i += 8) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0)); + const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1)); + const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0)); + const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1)); + const __m128i a0b1 = _mm_add_epi16(a0, b1); + const __m128i a1b0 = _mm_add_epi16(a1, b0); + const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1 + const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8); + const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1) + const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0) + const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3); + const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3); + const __m128i d0 = _mm_add_epi16(c1, a0); + const __m128i d1 = _mm_add_epi16(c0, a1); + const __m128i e0 = _mm_srai_epi16(d0, 1); + const __m128i e1 = _mm_srai_epi16(d1, 1); + const __m128i f0 = _mm_unpacklo_epi16(e0, e1); + const __m128i f1 = _mm_unpackhi_epi16(e0, e1); + const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0)); + const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8)); + const __m128i h0 = _mm_add_epi16(g0, f0); + const __m128i h1 = _mm_add_epi16(g1, f1); + const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero); + const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero); + _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0); + _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1); + } + for (; i < len; ++i) { + // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 = + // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4 + // We reuse the common sub-expressions. + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y); + } +} + +static WEBP_INLINE __m128i s16_to_s32(__m128i in) { + return _mm_srai_epi32(_mm_unpacklo_epi16(in, in), 16); +} + +static void SharpYuvFilterRow32_SSE2(const int16_t* A, const int16_t* B, + int len, const uint16_t* best_y, + uint16_t* out, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const __m128i kCst8 = _mm_set1_epi32(8); + const __m128i max = _mm_set1_epi16(max_y); + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 4 <= len; i += 4) { + const __m128i a0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 0))); + const __m128i a1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 1))); + const __m128i b0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 0))); + const __m128i b1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 1))); + const __m128i a0b1 = _mm_add_epi32(a0, b1); + const __m128i a1b0 = _mm_add_epi32(a1, b0); + const __m128i a0a1b0b1 = _mm_add_epi32(a0b1, a1b0); // A0+A1+B0+B1 + const __m128i a0a1b0b1_8 = _mm_add_epi32(a0a1b0b1, kCst8); + const __m128i a0b1_2 = _mm_add_epi32(a0b1, a0b1); // 2*(A0+B1) + const __m128i a1b0_2 = _mm_add_epi32(a1b0, a1b0); // 2*(A1+B0) + const __m128i c0 = _mm_srai_epi32(_mm_add_epi32(a0b1_2, a0a1b0b1_8), 3); + const __m128i c1 = _mm_srai_epi32(_mm_add_epi32(a1b0_2, a0a1b0b1_8), 3); + const __m128i d0 = _mm_add_epi32(c1, a0); + const __m128i d1 = _mm_add_epi32(c0, a1); + const __m128i e0 = _mm_srai_epi32(d0, 1); + const __m128i e1 = _mm_srai_epi32(d1, 1); + const __m128i f0 = _mm_unpacklo_epi32(e0, e1); + const __m128i f1 = _mm_unpackhi_epi32(e0, e1); + const __m128i g = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0)); + const __m128i h_16 = _mm_add_epi16(g, _mm_packs_epi32(f0, f1)); + const __m128i final = _mm_max_epi16(_mm_min_epi16(h_16, max), zero); + _mm_storeu_si128((__m128i*)(out + 2 * i + 0), final); + } + for (; i < len; ++i) { + // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 = + // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4 + // We reuse the common sub-expressions. + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y); + } +} + +static void SharpYuvFilterRow_SSE2(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth) { + if (bit_depth <= 10) { + SharpYuvFilterRow16_SSE2(A, B, len, best_y, out, bit_depth); + } else { + SharpYuvFilterRow32_SSE2(A, B, len, best_y, out, bit_depth); + } +} + +//------------------------------------------------------------------------------ + +extern void InitSharpYuvSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvSSE2(void) { + SharpYuvUpdateY = SharpYuvUpdateY_SSE2; + SharpYuvUpdateRGB = SharpYuvUpdateRGB_SSE2; + SharpYuvFilterRow = SharpYuvFilterRow_SSE2; +} +#else // !WEBP_USE_SSE2 + +extern void InitSharpYuvSSE2(void); + +void InitSharpYuvSSE2(void) {} + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dec/alpha_dec.c b/libraries/webp/src/dec/alpha_dec.c new file mode 100644 index 00000000000..540646b8cb2 --- /dev/null +++ b/libraries/webp/src/dec/alpha_dec.c @@ -0,0 +1,239 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Alpha-plane decompression. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include "src/dec/alphai_dec.h" +#include "src/dec/vp8_dec.h" +#include "src/dec/vp8i_dec.h" +#include "src/dec/vp8li_dec.h" +#include "src/dsp/dsp.h" +#include "src/utils/quant_levels_dec_utils.h" +#include "src/utils/utils.h" +#include "include/webp/format_constants.h" +#include "include/webp/types.h" + +//------------------------------------------------------------------------------ +// ALPHDecoder object. + +// Allocates a new alpha decoder instance. +WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) { + ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); + return dec; +} + +// Clears and deallocates an alpha decoder instance. +static void ALPHDelete(ALPHDecoder* const dec) { + if (dec != NULL) { + VP8LDelete(dec->vp8l_dec_); + dec->vp8l_dec_ = NULL; + WebPSafeFree(dec); + } +} + +//------------------------------------------------------------------------------ +// Decoding. + +// Initialize alpha decoding by parsing the alpha header and decoding the image +// header for alpha data stored using lossless compression. +// Returns false in case of error in alpha header (data too short, invalid +// compression method or filter, error in lossless header data etc). +WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, + size_t data_size, const VP8Io* const src_io, + uint8_t* output) { + int ok = 0; + const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN; + const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN; + int rsrv; + VP8Io* const io = &dec->io_; + + assert(data != NULL && output != NULL && src_io != NULL); + + VP8FiltersInit(); + dec->output_ = output; + dec->width_ = src_io->width; + dec->height_ = src_io->height; + assert(dec->width_ > 0 && dec->height_ > 0); + + if (data_size <= ALPHA_HEADER_LEN) { + return 0; + } + + dec->method_ = (data[0] >> 0) & 0x03; + dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03); + dec->pre_processing_ = (data[0] >> 4) & 0x03; + rsrv = (data[0] >> 6) & 0x03; + if (dec->method_ < ALPHA_NO_COMPRESSION || + dec->method_ > ALPHA_LOSSLESS_COMPRESSION || + dec->filter_ >= WEBP_FILTER_LAST || + dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS || + rsrv != 0) { + return 0; + } + + // Copy the necessary parameters from src_io to io + if (!VP8InitIo(io)) { + return 0; + } + WebPInitCustomIo(NULL, io); + io->opaque = dec; + io->width = src_io->width; + io->height = src_io->height; + + io->use_cropping = src_io->use_cropping; + io->crop_left = src_io->crop_left; + io->crop_right = src_io->crop_right; + io->crop_top = src_io->crop_top; + io->crop_bottom = src_io->crop_bottom; + // No need to copy the scaling parameters. + + if (dec->method_ == ALPHA_NO_COMPRESSION) { + const size_t alpha_decoded_size = dec->width_ * dec->height_; + ok = (alpha_data_size >= alpha_decoded_size); + } else { + assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION); + ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size); + } + + return ok; +} + +// Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha +// starting from row number 'row'. It assumes that rows up to (row - 1) have +// already been decoded. +// Returns false in case of bitstream error. +WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row, + int num_rows) { + ALPHDecoder* const alph_dec = dec->alph_dec_; + const int width = alph_dec->width_; + const int height = alph_dec->io_.crop_bottom; + if (alph_dec->method_ == ALPHA_NO_COMPRESSION) { + int y; + const uint8_t* prev_line = dec->alpha_prev_line_; + const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width; + uint8_t* dst = dec->alpha_plane_ + row * width; + assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]); + assert(WebPUnfilters[alph_dec->filter_] != NULL); + for (y = 0; y < num_rows; ++y) { + WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width); + prev_line = dst; + dst += width; + deltas += width; + } + dec->alpha_prev_line_ = prev_line; + } else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION + assert(alph_dec->vp8l_dec_ != NULL); + if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) { + return 0; + } + } + + if (row + num_rows >= height) { + dec->is_alpha_decoded_ = 1; + } + return 1; +} + +WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec, + const VP8Io* const io) { + const int stride = io->width; + const int height = io->crop_bottom; + const uint64_t alpha_size = (uint64_t)stride * height; + assert(dec->alpha_plane_mem_ == NULL); + dec->alpha_plane_mem_ = + (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_)); + if (dec->alpha_plane_mem_ == NULL) { + return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, + "Alpha decoder initialization failed."); + } + dec->alpha_plane_ = dec->alpha_plane_mem_; + dec->alpha_prev_line_ = NULL; + return 1; +} + +void WebPDeallocateAlphaMemory(VP8Decoder* const dec) { + assert(dec != NULL); + WebPSafeFree(dec->alpha_plane_mem_); + dec->alpha_plane_mem_ = NULL; + dec->alpha_plane_ = NULL; + ALPHDelete(dec->alph_dec_); + dec->alph_dec_ = NULL; +} + +//------------------------------------------------------------------------------ +// Main entry point. + +WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, + const VP8Io* const io, + int row, int num_rows) { + const int width = io->width; + const int height = io->crop_bottom; + + assert(dec != NULL && io != NULL); + + if (row < 0 || num_rows <= 0 || row + num_rows > height) { + return NULL; + } + + if (!dec->is_alpha_decoded_) { + if (dec->alph_dec_ == NULL) { // Initialize decoder. + dec->alph_dec_ = ALPHNew(); + if (dec->alph_dec_ == NULL) { + VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, + "Alpha decoder initialization failed."); + return NULL; + } + if (!AllocateAlphaPlane(dec, io)) goto Error; + if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_, + io, dec->alpha_plane_)) { + VP8LDecoder* const vp8l_dec = dec->alph_dec_->vp8l_dec_; + VP8SetError(dec, + (vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY + : vp8l_dec->status_, + "Alpha decoder initialization failed."); + goto Error; + } + // if we allowed use of alpha dithering, check whether it's needed at all + if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) { + dec->alpha_dithering_ = 0; // disable dithering + } else { + num_rows = height - row; // decode everything in one pass + } + } + + assert(dec->alph_dec_ != NULL); + assert(row + num_rows <= height); + if (!ALPHDecode(dec, row, num_rows)) goto Error; + + if (dec->is_alpha_decoded_) { // finished? + ALPHDelete(dec->alph_dec_); + dec->alph_dec_ = NULL; + if (dec->alpha_dithering_ > 0) { + uint8_t* const alpha = dec->alpha_plane_ + io->crop_top * width + + io->crop_left; + if (!WebPDequantizeLevels(alpha, + io->crop_right - io->crop_left, + io->crop_bottom - io->crop_top, + width, dec->alpha_dithering_)) { + goto Error; + } + } + } + } + + // Return a pointer to the current decoded row. + return dec->alpha_plane_ + row * width; + + Error: + WebPDeallocateAlphaMemory(dec); + return NULL; +} diff --git a/libraries/webp/src/dec/alphai_dec.h b/libraries/webp/src/dec/alphai_dec.h new file mode 100644 index 00000000000..a64104abeb3 --- /dev/null +++ b/libraries/webp/src/dec/alphai_dec.h @@ -0,0 +1,54 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Alpha decoder: internal header. +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_DEC_ALPHAI_DEC_H_ +#define WEBP_DEC_ALPHAI_DEC_H_ + +#include "src/dec/webpi_dec.h" +#include "src/utils/filters_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct VP8LDecoder; // Defined in dec/vp8li.h. + +typedef struct ALPHDecoder ALPHDecoder; +struct ALPHDecoder { + int width_; + int height_; + int method_; + WEBP_FILTER_TYPE filter_; + int pre_processing_; + struct VP8LDecoder* vp8l_dec_; + VP8Io io_; + int use_8b_decode_; // Although alpha channel requires only 1 byte per + // pixel, sometimes VP8LDecoder may need to allocate + // 4 bytes per pixel internally during decode. + uint8_t* output_; + const uint8_t* prev_line_; // last output row (or NULL) +}; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + +// Deallocate memory associated to dec->alpha_plane_ decoding +void WebPDeallocateAlphaMemory(VP8Decoder* const dec); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DEC_ALPHAI_DEC_H_ diff --git a/libraries/webp/src/dec/buffer_dec.c b/libraries/webp/src/dec/buffer_dec.c new file mode 100644 index 00000000000..11ce76f19e2 --- /dev/null +++ b/libraries/webp/src/dec/buffer_dec.c @@ -0,0 +1,310 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Everything about WebPDecBuffer +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/dec/vp8i_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// WebPDecBuffer + +// Number of bytes per pixel for the different color-spaces. +static const uint8_t kModeBpp[MODE_LAST] = { + 3, 4, 3, 4, 4, 2, 2, + 4, 4, 4, 2, // pre-multiplied modes + 1, 1 }; + +// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE. +// Convert to an integer to handle both the unsigned/signed enum cases +// without the need for casting to remove type limit warnings. +static int IsValidColorspace(int webp_csp_mode) { + return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST); +} + +// strictly speaking, the very last (or first, if flipped) row +// doesn't require padding. +#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \ + ((uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH)) + +static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) { + int ok = 1; + const WEBP_CSP_MODE mode = buffer->colorspace; + const int width = buffer->width; + const int height = buffer->height; + if (!IsValidColorspace(mode)) { + ok = 0; + } else if (!WebPIsRGBMode(mode)) { // YUV checks + const WebPYUVABuffer* const buf = &buffer->u.YUVA; + const int uv_width = (width + 1) / 2; + const int uv_height = (height + 1) / 2; + const int y_stride = abs(buf->y_stride); + const int u_stride = abs(buf->u_stride); + const int v_stride = abs(buf->v_stride); + const int a_stride = abs(buf->a_stride); + const uint64_t y_size = MIN_BUFFER_SIZE(width, height, y_stride); + const uint64_t u_size = MIN_BUFFER_SIZE(uv_width, uv_height, u_stride); + const uint64_t v_size = MIN_BUFFER_SIZE(uv_width, uv_height, v_stride); + const uint64_t a_size = MIN_BUFFER_SIZE(width, height, a_stride); + ok &= (y_size <= buf->y_size); + ok &= (u_size <= buf->u_size); + ok &= (v_size <= buf->v_size); + ok &= (y_stride >= width); + ok &= (u_stride >= uv_width); + ok &= (v_stride >= uv_width); + ok &= (buf->y != NULL); + ok &= (buf->u != NULL); + ok &= (buf->v != NULL); + if (mode == MODE_YUVA) { + ok &= (a_stride >= width); + ok &= (a_size <= buf->a_size); + ok &= (buf->a != NULL); + } + } else { // RGB checks + const WebPRGBABuffer* const buf = &buffer->u.RGBA; + const int stride = abs(buf->stride); + const uint64_t size = + MIN_BUFFER_SIZE((uint64_t)width * kModeBpp[mode], height, stride); + ok &= (size <= buf->size); + ok &= (stride >= width * kModeBpp[mode]); + ok &= (buf->rgba != NULL); + } + return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM; +} +#undef MIN_BUFFER_SIZE + +static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) { + const int w = buffer->width; + const int h = buffer->height; + const WEBP_CSP_MODE mode = buffer->colorspace; + + if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) { + return VP8_STATUS_INVALID_PARAM; + } + + if (buffer->is_external_memory <= 0 && buffer->private_memory == NULL) { + uint8_t* output; + int uv_stride = 0, a_stride = 0; + uint64_t uv_size = 0, a_size = 0, total_size; + // We need memory and it hasn't been allocated yet. + // => initialize output buffer, now that dimensions are known. + int stride; + uint64_t size; + + if ((uint64_t)w * kModeBpp[mode] >= (1ull << 31)) { + return VP8_STATUS_INVALID_PARAM; + } + stride = w * kModeBpp[mode]; + size = (uint64_t)stride * h; + if (!WebPIsRGBMode(mode)) { + uv_stride = (w + 1) / 2; + uv_size = (uint64_t)uv_stride * ((h + 1) / 2); + if (mode == MODE_YUVA) { + a_stride = w; + a_size = (uint64_t)a_stride * h; + } + } + total_size = size + 2 * uv_size + a_size; + + output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output)); + if (output == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + buffer->private_memory = output; + + if (!WebPIsRGBMode(mode)) { // YUVA initialization + WebPYUVABuffer* const buf = &buffer->u.YUVA; + buf->y = output; + buf->y_stride = stride; + buf->y_size = (size_t)size; + buf->u = output + size; + buf->u_stride = uv_stride; + buf->u_size = (size_t)uv_size; + buf->v = output + size + uv_size; + buf->v_stride = uv_stride; + buf->v_size = (size_t)uv_size; + if (mode == MODE_YUVA) { + buf->a = output + size + 2 * uv_size; + } + buf->a_size = (size_t)a_size; + buf->a_stride = a_stride; + } else { // RGBA initialization + WebPRGBABuffer* const buf = &buffer->u.RGBA; + buf->rgba = output; + buf->stride = stride; + buf->size = (size_t)size; + } + } + return CheckDecBuffer(buffer); +} + +VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) { + if (buffer == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + if (WebPIsRGBMode(buffer->colorspace)) { + WebPRGBABuffer* const buf = &buffer->u.RGBA; + buf->rgba += (int64_t)(buffer->height - 1) * buf->stride; + buf->stride = -buf->stride; + } else { + WebPYUVABuffer* const buf = &buffer->u.YUVA; + const int64_t H = buffer->height; + buf->y += (H - 1) * buf->y_stride; + buf->y_stride = -buf->y_stride; + buf->u += ((H - 1) >> 1) * buf->u_stride; + buf->u_stride = -buf->u_stride; + buf->v += ((H - 1) >> 1) * buf->v_stride; + buf->v_stride = -buf->v_stride; + if (buf->a != NULL) { + buf->a += (H - 1) * buf->a_stride; + buf->a_stride = -buf->a_stride; + } + } + return VP8_STATUS_OK; +} + +VP8StatusCode WebPAllocateDecBuffer(int width, int height, + const WebPDecoderOptions* const options, + WebPDecBuffer* const buffer) { + VP8StatusCode status; + if (buffer == NULL || width <= 0 || height <= 0) { + return VP8_STATUS_INVALID_PARAM; + } + if (options != NULL) { // First, apply options if there is any. + if (options->use_cropping) { + const int cw = options->crop_width; + const int ch = options->crop_height; + const int x = options->crop_left & ~1; + const int y = options->crop_top & ~1; + if (!WebPCheckCropDimensions(width, height, x, y, cw, ch)) { + return VP8_STATUS_INVALID_PARAM; // out of frame boundary. + } + width = cw; + height = ch; + } + + if (options->use_scaling) { +#if !defined(WEBP_REDUCE_SIZE) + int scaled_width = options->scaled_width; + int scaled_height = options->scaled_height; + if (!WebPRescalerGetScaledDimensions( + width, height, &scaled_width, &scaled_height)) { + return VP8_STATUS_INVALID_PARAM; + } + width = scaled_width; + height = scaled_height; +#else + return VP8_STATUS_INVALID_PARAM; // rescaling not supported +#endif + } + } + buffer->width = width; + buffer->height = height; + + // Then, allocate buffer for real. + status = AllocateBuffer(buffer); + if (status != VP8_STATUS_OK) return status; + + // Use the stride trick if vertical flip is needed. + if (options != NULL && options->flip) { + status = WebPFlipBuffer(buffer); + } + return status; +} + +//------------------------------------------------------------------------------ +// constructors / destructors + +int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { + return 0; // version mismatch + } + if (buffer == NULL) return 0; + memset(buffer, 0, sizeof(*buffer)); + return 1; +} + +void WebPFreeDecBuffer(WebPDecBuffer* buffer) { + if (buffer != NULL) { + if (buffer->is_external_memory <= 0) { + WebPSafeFree(buffer->private_memory); + } + buffer->private_memory = NULL; + } +} + +void WebPCopyDecBuffer(const WebPDecBuffer* const src, + WebPDecBuffer* const dst) { + if (src != NULL && dst != NULL) { + *dst = *src; + if (src->private_memory != NULL) { + dst->is_external_memory = 1; // dst buffer doesn't own the memory. + dst->private_memory = NULL; + } + } +} + +// Copy and transfer ownership from src to dst (beware of parameter order!) +void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) { + if (src != NULL && dst != NULL) { + *dst = *src; + if (src->private_memory != NULL) { + src->is_external_memory = 1; // src relinquishes ownership + src->private_memory = NULL; + } + } +} + +VP8StatusCode WebPCopyDecBufferPixels(const WebPDecBuffer* const src_buf, + WebPDecBuffer* const dst_buf) { + assert(src_buf != NULL && dst_buf != NULL); + assert(src_buf->colorspace == dst_buf->colorspace); + + dst_buf->width = src_buf->width; + dst_buf->height = src_buf->height; + if (CheckDecBuffer(dst_buf) != VP8_STATUS_OK) { + return VP8_STATUS_INVALID_PARAM; + } + if (WebPIsRGBMode(src_buf->colorspace)) { + const WebPRGBABuffer* const src = &src_buf->u.RGBA; + const WebPRGBABuffer* const dst = &dst_buf->u.RGBA; + WebPCopyPlane(src->rgba, src->stride, dst->rgba, dst->stride, + src_buf->width * kModeBpp[src_buf->colorspace], + src_buf->height); + } else { + const WebPYUVABuffer* const src = &src_buf->u.YUVA; + const WebPYUVABuffer* const dst = &dst_buf->u.YUVA; + WebPCopyPlane(src->y, src->y_stride, dst->y, dst->y_stride, + src_buf->width, src_buf->height); + WebPCopyPlane(src->u, src->u_stride, dst->u, dst->u_stride, + (src_buf->width + 1) / 2, (src_buf->height + 1) / 2); + WebPCopyPlane(src->v, src->v_stride, dst->v, dst->v_stride, + (src_buf->width + 1) / 2, (src_buf->height + 1) / 2); + if (WebPIsAlphaMode(src_buf->colorspace)) { + WebPCopyPlane(src->a, src->a_stride, dst->a, dst->a_stride, + src_buf->width, src_buf->height); + } + } + return VP8_STATUS_OK; +} + +int WebPAvoidSlowMemory(const WebPDecBuffer* const output, + const WebPBitstreamFeatures* const features) { + assert(output != NULL); + return (output->is_external_memory >= 2) && + WebPIsPremultipliedMode(output->colorspace) && + (features != NULL && features->has_alpha); +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dec/common_dec.h b/libraries/webp/src/dec/common_dec.h new file mode 100644 index 00000000000..b158550a80b --- /dev/null +++ b/libraries/webp/src/dec/common_dec.h @@ -0,0 +1,54 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Definitions and macros common to encoding and decoding +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DEC_COMMON_DEC_H_ +#define WEBP_DEC_COMMON_DEC_H_ + +// intra prediction modes +enum { B_DC_PRED = 0, // 4x4 modes + B_TM_PRED = 1, + B_VE_PRED = 2, + B_HE_PRED = 3, + B_RD_PRED = 4, + B_VR_PRED = 5, + B_LD_PRED = 6, + B_VL_PRED = 7, + B_HD_PRED = 8, + B_HU_PRED = 9, + NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10 + + // Luma16 or UV modes + DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED, + H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED, + B_PRED = NUM_BMODES, // refined I4x4 mode + NUM_PRED_MODES = 4, + + // special modes + B_DC_PRED_NOTOP = 4, + B_DC_PRED_NOLEFT = 5, + B_DC_PRED_NOTOPLEFT = 6, + NUM_B_DC_MODES = 7 }; + +enum { MB_FEATURE_TREE_PROBS = 3, + NUM_MB_SEGMENTS = 4, + NUM_REF_LF_DELTAS = 4, + NUM_MODE_LF_DELTAS = 4, // I4x4, ZERO, *, SPLIT + MAX_NUM_PARTITIONS = 8, + // Probabilities + NUM_TYPES = 4, // 0: i16-AC, 1: i16-DC, 2:chroma-AC, 3:i4-AC + NUM_BANDS = 8, + NUM_CTX = 3, + NUM_PROBAS = 11 + }; + +#endif // WEBP_DEC_COMMON_DEC_H_ diff --git a/libraries/webp/src/dec/frame_dec.c b/libraries/webp/src/dec/frame_dec.c new file mode 100644 index 00000000000..91ca1f8609a --- /dev/null +++ b/libraries/webp/src/dec/frame_dec.c @@ -0,0 +1,803 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Frame-reconstruction function. Memory allocation. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include "src/dec/vp8i_dec.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// Main reconstruction function. + +static const uint16_t kScan[16] = { + 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, + 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, + 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, + 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS +}; + +static int CheckMode(int mb_x, int mb_y, int mode) { + if (mode == B_DC_PRED) { + if (mb_x == 0) { + return (mb_y == 0) ? B_DC_PRED_NOTOPLEFT : B_DC_PRED_NOLEFT; + } else { + return (mb_y == 0) ? B_DC_PRED_NOTOP : B_DC_PRED; + } + } + return mode; +} + +static void Copy32b(uint8_t* const dst, const uint8_t* const src) { + memcpy(dst, src, 4); +} + +static WEBP_INLINE void DoTransform(uint32_t bits, const int16_t* const src, + uint8_t* const dst) { + switch (bits >> 30) { + case 3: + VP8Transform(src, dst, 0); + break; + case 2: + VP8TransformAC3(src, dst); + break; + case 1: + VP8TransformDC(src, dst); + break; + default: + break; + } +} + +static void DoUVTransform(uint32_t bits, const int16_t* const src, + uint8_t* const dst) { + if (bits & 0xff) { // any non-zero coeff at all? + if (bits & 0xaa) { // any non-zero AC coefficient? + VP8TransformUV(src, dst); // note we don't use the AC3 variant for U/V + } else { + VP8TransformDCUV(src, dst); + } + } +} + +static void ReconstructRow(const VP8Decoder* const dec, + const VP8ThreadContext* ctx) { + int j; + int mb_x; + const int mb_y = ctx->mb_y_; + const int cache_id = ctx->id_; + uint8_t* const y_dst = dec->yuv_b_ + Y_OFF; + uint8_t* const u_dst = dec->yuv_b_ + U_OFF; + uint8_t* const v_dst = dec->yuv_b_ + V_OFF; + + // Initialize left-most block. + for (j = 0; j < 16; ++j) { + y_dst[j * BPS - 1] = 129; + } + for (j = 0; j < 8; ++j) { + u_dst[j * BPS - 1] = 129; + v_dst[j * BPS - 1] = 129; + } + + // Init top-left sample on left column too. + if (mb_y > 0) { + y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129; + } else { + // we only need to do this init once at block (0,0). + // Afterward, it remains valid for the whole topmost row. + memset(y_dst - BPS - 1, 127, 16 + 4 + 1); + memset(u_dst - BPS - 1, 127, 8 + 1); + memset(v_dst - BPS - 1, 127, 8 + 1); + } + + // Reconstruct one row. + for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) { + const VP8MBData* const block = ctx->mb_data_ + mb_x; + + // Rotate in the left samples from previously decoded block. We move four + // pixels at a time for alignment reason, and because of in-loop filter. + if (mb_x > 0) { + for (j = -1; j < 16; ++j) { + Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]); + } + for (j = -1; j < 8; ++j) { + Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]); + Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]); + } + } + { + // bring top samples into the cache + VP8TopSamples* const top_yuv = dec->yuv_t_ + mb_x; + const int16_t* const coeffs = block->coeffs_; + uint32_t bits = block->non_zero_y_; + int n; + + if (mb_y > 0) { + memcpy(y_dst - BPS, top_yuv[0].y, 16); + memcpy(u_dst - BPS, top_yuv[0].u, 8); + memcpy(v_dst - BPS, top_yuv[0].v, 8); + } + + // predict and add residuals + if (block->is_i4x4_) { // 4x4 + uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16); + + if (mb_y > 0) { + if (mb_x >= dec->mb_w_ - 1) { // on rightmost border + memset(top_right, top_yuv[0].y[15], sizeof(*top_right)); + } else { + memcpy(top_right, top_yuv[1].y, sizeof(*top_right)); + } + } + // replicate the top-right pixels below + top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0]; + + // predict and add residuals for all 4x4 blocks in turn. + for (n = 0; n < 16; ++n, bits <<= 2) { + uint8_t* const dst = y_dst + kScan[n]; + VP8PredLuma4[block->imodes_[n]](dst); + DoTransform(bits, coeffs + n * 16, dst); + } + } else { // 16x16 + const int pred_func = CheckMode(mb_x, mb_y, block->imodes_[0]); + VP8PredLuma16[pred_func](y_dst); + if (bits != 0) { + for (n = 0; n < 16; ++n, bits <<= 2) { + DoTransform(bits, coeffs + n * 16, y_dst + kScan[n]); + } + } + } + { + // Chroma + const uint32_t bits_uv = block->non_zero_uv_; + const int pred_func = CheckMode(mb_x, mb_y, block->uvmode_); + VP8PredChroma8[pred_func](u_dst); + VP8PredChroma8[pred_func](v_dst); + DoUVTransform(bits_uv >> 0, coeffs + 16 * 16, u_dst); + DoUVTransform(bits_uv >> 8, coeffs + 20 * 16, v_dst); + } + + // stash away top samples for next block + if (mb_y < dec->mb_h_ - 1) { + memcpy(top_yuv[0].y, y_dst + 15 * BPS, 16); + memcpy(top_yuv[0].u, u_dst + 7 * BPS, 8); + memcpy(top_yuv[0].v, v_dst + 7 * BPS, 8); + } + } + // Transfer reconstructed samples from yuv_b_ cache to final destination. + { + const int y_offset = cache_id * 16 * dec->cache_y_stride_; + const int uv_offset = cache_id * 8 * dec->cache_uv_stride_; + uint8_t* const y_out = dec->cache_y_ + mb_x * 16 + y_offset; + uint8_t* const u_out = dec->cache_u_ + mb_x * 8 + uv_offset; + uint8_t* const v_out = dec->cache_v_ + mb_x * 8 + uv_offset; + for (j = 0; j < 16; ++j) { + memcpy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16); + } + for (j = 0; j < 8; ++j) { + memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8); + memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8); + } + } + } +} + +//------------------------------------------------------------------------------ +// Filtering + +// kFilterExtraRows[] = How many extra lines are needed on the MB boundary +// for caching, given a filtering level. +// Simple filter: up to 2 luma samples are read and 1 is written. +// Complex filter: up to 4 luma samples are read and 3 are written. Same for +// U/V, so it's 8 samples total (because of the 2x upsampling). +static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 }; + +static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) { + const VP8ThreadContext* const ctx = &dec->thread_ctx_; + const int cache_id = ctx->id_; + const int y_bps = dec->cache_y_stride_; + const VP8FInfo* const f_info = ctx->f_info_ + mb_x; + uint8_t* const y_dst = dec->cache_y_ + cache_id * 16 * y_bps + mb_x * 16; + const int ilevel = f_info->f_ilevel_; + const int limit = f_info->f_limit_; + if (limit == 0) { + return; + } + assert(limit >= 3); + if (dec->filter_type_ == 1) { // simple + if (mb_x > 0) { + VP8SimpleHFilter16(y_dst, y_bps, limit + 4); + } + if (f_info->f_inner_) { + VP8SimpleHFilter16i(y_dst, y_bps, limit); + } + if (mb_y > 0) { + VP8SimpleVFilter16(y_dst, y_bps, limit + 4); + } + if (f_info->f_inner_) { + VP8SimpleVFilter16i(y_dst, y_bps, limit); + } + } else { // complex + const int uv_bps = dec->cache_uv_stride_; + uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8; + uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8; + const int hev_thresh = f_info->hev_thresh_; + if (mb_x > 0) { + VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh); + VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh); + } + if (f_info->f_inner_) { + VP8HFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh); + VP8HFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh); + } + if (mb_y > 0) { + VP8VFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh); + VP8VFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh); + } + if (f_info->f_inner_) { + VP8VFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh); + VP8VFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh); + } + } +} + +// Filter the decoded macroblock row (if needed) +static void FilterRow(const VP8Decoder* const dec) { + int mb_x; + const int mb_y = dec->thread_ctx_.mb_y_; + assert(dec->thread_ctx_.filter_row_); + for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { + DoFilter(dec, mb_x, mb_y); + } +} + +//------------------------------------------------------------------------------ +// Precompute the filtering strength for each segment and each i4x4/i16x16 mode. + +static void PrecomputeFilterStrengths(VP8Decoder* const dec) { + if (dec->filter_type_ > 0) { + int s; + const VP8FilterHeader* const hdr = &dec->filter_hdr_; + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + int i4x4; + // First, compute the initial level + int base_level; + if (dec->segment_hdr_.use_segment_) { + base_level = dec->segment_hdr_.filter_strength_[s]; + if (!dec->segment_hdr_.absolute_delta_) { + base_level += hdr->level_; + } + } else { + base_level = hdr->level_; + } + for (i4x4 = 0; i4x4 <= 1; ++i4x4) { + VP8FInfo* const info = &dec->fstrengths_[s][i4x4]; + int level = base_level; + if (hdr->use_lf_delta_) { + level += hdr->ref_lf_delta_[0]; + if (i4x4) { + level += hdr->mode_lf_delta_[0]; + } + } + level = (level < 0) ? 0 : (level > 63) ? 63 : level; + if (level > 0) { + int ilevel = level; + if (hdr->sharpness_ > 0) { + if (hdr->sharpness_ > 4) { + ilevel >>= 2; + } else { + ilevel >>= 1; + } + if (ilevel > 9 - hdr->sharpness_) { + ilevel = 9 - hdr->sharpness_; + } + } + if (ilevel < 1) ilevel = 1; + info->f_ilevel_ = ilevel; + info->f_limit_ = 2 * level + ilevel; + info->hev_thresh_ = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; + } else { + info->f_limit_ = 0; // no filtering + } + info->f_inner_ = i4x4; + } + } + } +} + +//------------------------------------------------------------------------------ +// Dithering + +// minimal amp that will provide a non-zero dithering effect +#define MIN_DITHER_AMP 4 + +#define DITHER_AMP_TAB_SIZE 12 +static const uint8_t kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = { + // roughly, it's dqm->uv_mat_[1] + 8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1 +}; + +void VP8InitDithering(const WebPDecoderOptions* const options, + VP8Decoder* const dec) { + assert(dec != NULL); + if (options != NULL) { + const int d = options->dithering_strength; + const int max_amp = (1 << VP8_RANDOM_DITHER_FIX) - 1; + const int f = (d < 0) ? 0 : (d > 100) ? max_amp : (d * max_amp / 100); + if (f > 0) { + int s; + int all_amp = 0; + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + VP8QuantMatrix* const dqm = &dec->dqm_[s]; + if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) { + const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_; + dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3; + } + all_amp |= dqm->dither_; + } + if (all_amp != 0) { + VP8InitRandom(&dec->dithering_rg_, 1.0f); + dec->dither_ = 1; + } + } + // potentially allow alpha dithering + dec->alpha_dithering_ = options->alpha_dithering_strength; + if (dec->alpha_dithering_ > 100) { + dec->alpha_dithering_ = 100; + } else if (dec->alpha_dithering_ < 0) { + dec->alpha_dithering_ = 0; + } + } +} + +// Convert to range: [-2,2] for dither=50, [-4,4] for dither=100 +static void Dither8x8(VP8Random* const rg, uint8_t* dst, int bps, int amp) { + uint8_t dither[64]; + int i; + for (i = 0; i < 8 * 8; ++i) { + dither[i] = VP8RandomBits2(rg, VP8_DITHER_AMP_BITS + 1, amp); + } + VP8DitherCombine8x8(dither, dst, bps); +} + +static void DitherRow(VP8Decoder* const dec) { + int mb_x; + assert(dec->dither_); + for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { + const VP8ThreadContext* const ctx = &dec->thread_ctx_; + const VP8MBData* const data = ctx->mb_data_ + mb_x; + const int cache_id = ctx->id_; + const int uv_bps = dec->cache_uv_stride_; + if (data->dither_ >= MIN_DITHER_AMP) { + uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8; + uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8; + Dither8x8(&dec->dithering_rg_, u_dst, uv_bps, data->dither_); + Dither8x8(&dec->dithering_rg_, v_dst, uv_bps, data->dither_); + } + } +} + +//------------------------------------------------------------------------------ +// This function is called after a row of macroblocks is finished decoding. +// It also takes into account the following restrictions: +// * In case of in-loop filtering, we must hold off sending some of the bottom +// pixels as they are yet unfiltered. They will be when the next macroblock +// row is decoded. Meanwhile, we must preserve them by rotating them in the +// cache area. This doesn't hold for the very bottom row of the uncropped +// picture of course. +// * we must clip the remaining pixels against the cropping area. The VP8Io +// struct must have the following fields set correctly before calling put(): + +#define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB + +// Finalize and transmit a complete row. Return false in case of user-abort. +static int FinishRow(void* arg1, void* arg2) { + VP8Decoder* const dec = (VP8Decoder*)arg1; + VP8Io* const io = (VP8Io*)arg2; + int ok = 1; + const VP8ThreadContext* const ctx = &dec->thread_ctx_; + const int cache_id = ctx->id_; + const int extra_y_rows = kFilterExtraRows[dec->filter_type_]; + const int ysize = extra_y_rows * dec->cache_y_stride_; + const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_; + const int y_offset = cache_id * 16 * dec->cache_y_stride_; + const int uv_offset = cache_id * 8 * dec->cache_uv_stride_; + uint8_t* const ydst = dec->cache_y_ - ysize + y_offset; + uint8_t* const udst = dec->cache_u_ - uvsize + uv_offset; + uint8_t* const vdst = dec->cache_v_ - uvsize + uv_offset; + const int mb_y = ctx->mb_y_; + const int is_first_row = (mb_y == 0); + const int is_last_row = (mb_y >= dec->br_mb_y_ - 1); + + if (dec->mt_method_ == 2) { + ReconstructRow(dec, ctx); + } + + if (ctx->filter_row_) { + FilterRow(dec); + } + + if (dec->dither_) { + DitherRow(dec); + } + + if (io->put != NULL) { + int y_start = MACROBLOCK_VPOS(mb_y); + int y_end = MACROBLOCK_VPOS(mb_y + 1); + if (!is_first_row) { + y_start -= extra_y_rows; + io->y = ydst; + io->u = udst; + io->v = vdst; + } else { + io->y = dec->cache_y_ + y_offset; + io->u = dec->cache_u_ + uv_offset; + io->v = dec->cache_v_ + uv_offset; + } + + if (!is_last_row) { + y_end -= extra_y_rows; + } + if (y_end > io->crop_bottom) { + y_end = io->crop_bottom; // make sure we don't overflow on last row. + } + // If dec->alpha_data_ is not NULL, we have some alpha plane present. + io->a = NULL; + if (dec->alpha_data_ != NULL && y_start < y_end) { + io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start); + if (io->a == NULL) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "Could not decode alpha data."); + } + } + if (y_start < io->crop_top) { + const int delta_y = io->crop_top - y_start; + y_start = io->crop_top; + assert(!(delta_y & 1)); + io->y += dec->cache_y_stride_ * delta_y; + io->u += dec->cache_uv_stride_ * (delta_y >> 1); + io->v += dec->cache_uv_stride_ * (delta_y >> 1); + if (io->a != NULL) { + io->a += io->width * delta_y; + } + } + if (y_start < y_end) { + io->y += io->crop_left; + io->u += io->crop_left >> 1; + io->v += io->crop_left >> 1; + if (io->a != NULL) { + io->a += io->crop_left; + } + io->mb_y = y_start - io->crop_top; + io->mb_w = io->crop_right - io->crop_left; + io->mb_h = y_end - y_start; + ok = io->put(io); + } + } + // rotate top samples if needed + if (cache_id + 1 == dec->num_caches_) { + if (!is_last_row) { + memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize); + memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize); + memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize); + } + } + + return ok; +} + +#undef MACROBLOCK_VPOS + +//------------------------------------------------------------------------------ + +int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) { + int ok = 1; + VP8ThreadContext* const ctx = &dec->thread_ctx_; + const int filter_row = + (dec->filter_type_ > 0) && + (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_); + if (dec->mt_method_ == 0) { + // ctx->id_ and ctx->f_info_ are already set + ctx->mb_y_ = dec->mb_y_; + ctx->filter_row_ = filter_row; + ReconstructRow(dec, ctx); + ok = FinishRow(dec, io); + } else { + WebPWorker* const worker = &dec->worker_; + // Finish previous job *before* updating context + ok &= WebPGetWorkerInterface()->Sync(worker); + assert(worker->status_ == OK); + if (ok) { // spawn a new deblocking/output job + ctx->io_ = *io; + ctx->id_ = dec->cache_id_; + ctx->mb_y_ = dec->mb_y_; + ctx->filter_row_ = filter_row; + if (dec->mt_method_ == 2) { // swap macroblock data + VP8MBData* const tmp = ctx->mb_data_; + ctx->mb_data_ = dec->mb_data_; + dec->mb_data_ = tmp; + } else { + // perform reconstruction directly in main thread + ReconstructRow(dec, ctx); + } + if (filter_row) { // swap filter info + VP8FInfo* const tmp = ctx->f_info_; + ctx->f_info_ = dec->f_info_; + dec->f_info_ = tmp; + } + // (reconstruct)+filter in parallel + WebPGetWorkerInterface()->Launch(worker); + if (++dec->cache_id_ == dec->num_caches_) { + dec->cache_id_ = 0; + } + } + } + return ok; +} + +//------------------------------------------------------------------------------ +// Finish setting up the decoding parameter once user's setup() is called. + +VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) { + // Call setup() first. This may trigger additional decoding features on 'io'. + // Note: Afterward, we must call teardown() no matter what. + if (io->setup != NULL && !io->setup(io)) { + VP8SetError(dec, VP8_STATUS_USER_ABORT, "Frame setup failed"); + return dec->status_; + } + + // Disable filtering per user request + if (io->bypass_filtering) { + dec->filter_type_ = 0; + } + + // Define the area where we can skip in-loop filtering, in case of cropping. + // + // 'Simple' filter reads two luma samples outside of the macroblock + // and filters one. It doesn't filter the chroma samples. Hence, we can + // avoid doing the in-loop filtering before crop_top/crop_left position. + // For the 'Complex' filter, 3 samples are read and up to 3 are filtered. + // Means: there's a dependency chain that goes all the way up to the + // top-left corner of the picture (MB #0). We must filter all the previous + // macroblocks. + { + const int extra_pixels = kFilterExtraRows[dec->filter_type_]; + if (dec->filter_type_ == 2) { + // For complex filter, we need to preserve the dependency chain. + dec->tl_mb_x_ = 0; + dec->tl_mb_y_ = 0; + } else { + // For simple filter, we can filter only the cropped region. + // We include 'extra_pixels' on the other side of the boundary, since + // vertical or horizontal filtering of the previous macroblock can + // modify some abutting pixels. + dec->tl_mb_x_ = (io->crop_left - extra_pixels) >> 4; + dec->tl_mb_y_ = (io->crop_top - extra_pixels) >> 4; + if (dec->tl_mb_x_ < 0) dec->tl_mb_x_ = 0; + if (dec->tl_mb_y_ < 0) dec->tl_mb_y_ = 0; + } + // We need some 'extra' pixels on the right/bottom. + dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4; + dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4; + if (dec->br_mb_x_ > dec->mb_w_) { + dec->br_mb_x_ = dec->mb_w_; + } + if (dec->br_mb_y_ > dec->mb_h_) { + dec->br_mb_y_ = dec->mb_h_; + } + } + PrecomputeFilterStrengths(dec); + return VP8_STATUS_OK; +} + +int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { + int ok = 1; + if (dec->mt_method_ > 0) { + ok = WebPGetWorkerInterface()->Sync(&dec->worker_); + } + + if (io->teardown != NULL) { + io->teardown(io); + } + return ok; +} + +//------------------------------------------------------------------------------ +// For multi-threaded decoding we need to use 3 rows of 16 pixels as delay line. +// +// Reason is: the deblocking filter cannot deblock the bottom horizontal edges +// immediately, and needs to wait for first few rows of the next macroblock to +// be decoded. Hence, deblocking is lagging behind by 4 or 8 pixels (depending +// on strength). +// With two threads, the vertical positions of the rows being decoded are: +// Decode: [ 0..15][16..31][32..47][48..63][64..79][... +// Deblock: [ 0..11][12..27][28..43][44..59][... +// If we use two threads and two caches of 16 pixels, the sequence would be: +// Decode: [ 0..15][16..31][ 0..15!!][16..31][ 0..15][... +// Deblock: [ 0..11][12..27!!][-4..11][12..27][... +// The problem occurs during row [12..15!!] that both the decoding and +// deblocking threads are writing simultaneously. +// With 3 cache lines, one get a safe write pattern: +// Decode: [ 0..15][16..31][32..47][ 0..15][16..31][32..47][0.. +// Deblock: [ 0..11][12..27][28..43][-4..11][12..27][28... +// Note that multi-threaded output _without_ deblocking can make use of two +// cache lines of 16 pixels only, since there's no lagging behind. The decoding +// and output process have non-concurrent writing: +// Decode: [ 0..15][16..31][ 0..15][16..31][... +// io->put: [ 0..15][16..31][ 0..15][... + +#define MT_CACHE_LINES 3 +#define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case + +// Initialize multi/single-thread worker +static int InitThreadContext(VP8Decoder* const dec) { + dec->cache_id_ = 0; + if (dec->mt_method_ > 0) { + WebPWorker* const worker = &dec->worker_; + if (!WebPGetWorkerInterface()->Reset(worker)) { + return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, + "thread initialization failed."); + } + worker->data1 = dec; + worker->data2 = (void*)&dec->thread_ctx_.io_; + worker->hook = FinishRow; + dec->num_caches_ = + (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; + } else { + dec->num_caches_ = ST_CACHE_LINES; + } + return 1; +} + +int VP8GetThreadMethod(const WebPDecoderOptions* const options, + const WebPHeaderStructure* const headers, + int width, int height) { + if (options == NULL || options->use_threads == 0) { + return 0; + } + (void)headers; + (void)width; + (void)height; + assert(headers == NULL || !headers->is_lossless); +#if defined(WEBP_USE_THREAD) + if (width >= MIN_WIDTH_FOR_THREADS) return 2; +#endif + return 0; +} + +#undef MT_CACHE_LINES +#undef ST_CACHE_LINES + +//------------------------------------------------------------------------------ +// Memory setup + +static int AllocateMemory(VP8Decoder* const dec) { + const int num_caches = dec->num_caches_; + const int mb_w = dec->mb_w_; + // Note: we use 'size_t' when there's no overflow risk, uint64_t otherwise. + const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t); + const size_t top_size = sizeof(VP8TopSamples) * mb_w; + const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB); + const size_t f_info_size = + (dec->filter_type_ > 0) ? + mb_w * (dec->mt_method_ > 0 ? 2 : 1) * sizeof(VP8FInfo) + : 0; + const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_); + const size_t mb_data_size = + (dec->mt_method_ == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data_); + const size_t cache_height = (16 * num_caches + + kFilterExtraRows[dec->filter_type_]) * 3 / 2; + const size_t cache_size = top_size * cache_height; + // alpha_size is the only one that scales as width x height. + const uint64_t alpha_size = (dec->alpha_data_ != NULL) ? + (uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL; + const uint64_t needed = (uint64_t)intra_pred_mode_size + + top_size + mb_info_size + f_info_size + + yuv_size + mb_data_size + + cache_size + alpha_size + WEBP_ALIGN_CST; + uint8_t* mem; + + if (!CheckSizeOverflow(needed)) return 0; // check for overflow + if (needed > dec->mem_size_) { + WebPSafeFree(dec->mem_); + dec->mem_size_ = 0; + dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t)); + if (dec->mem_ == NULL) { + return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, + "no memory during frame initialization."); + } + // down-cast is ok, thanks to WebPSafeMalloc() above. + dec->mem_size_ = (size_t)needed; + } + + mem = (uint8_t*)dec->mem_; + dec->intra_t_ = mem; + mem += intra_pred_mode_size; + + dec->yuv_t_ = (VP8TopSamples*)mem; + mem += top_size; + + dec->mb_info_ = ((VP8MB*)mem) + 1; + mem += mb_info_size; + + dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL; + mem += f_info_size; + dec->thread_ctx_.id_ = 0; + dec->thread_ctx_.f_info_ = dec->f_info_; + if (dec->filter_type_ > 0 && dec->mt_method_ > 0) { + // secondary cache line. The deblocking process need to make use of the + // filtering strength from previous macroblock row, while the new ones + // are being decoded in parallel. We'll just swap the pointers. + dec->thread_ctx_.f_info_ += mb_w; + } + + mem = (uint8_t*)WEBP_ALIGN(mem); + assert((yuv_size & WEBP_ALIGN_CST) == 0); + dec->yuv_b_ = mem; + mem += yuv_size; + + dec->mb_data_ = (VP8MBData*)mem; + dec->thread_ctx_.mb_data_ = (VP8MBData*)mem; + if (dec->mt_method_ == 2) { + dec->thread_ctx_.mb_data_ += mb_w; + } + mem += mb_data_size; + + dec->cache_y_stride_ = 16 * mb_w; + dec->cache_uv_stride_ = 8 * mb_w; + { + const int extra_rows = kFilterExtraRows[dec->filter_type_]; + const int extra_y = extra_rows * dec->cache_y_stride_; + const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_; + dec->cache_y_ = mem + extra_y; + dec->cache_u_ = dec->cache_y_ + + 16 * num_caches * dec->cache_y_stride_ + extra_uv; + dec->cache_v_ = dec->cache_u_ + + 8 * num_caches * dec->cache_uv_stride_ + extra_uv; + dec->cache_id_ = 0; + } + mem += cache_size; + + // alpha plane + dec->alpha_plane_ = alpha_size ? mem : NULL; + mem += alpha_size; + assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_); + + // note: left/top-info is initialized once for all. + memset(dec->mb_info_ - 1, 0, mb_info_size); + VP8InitScanline(dec); // initialize left too. + + // initialize top + memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size); + + return 1; +} + +static void InitIo(VP8Decoder* const dec, VP8Io* io) { + // prepare 'io' + io->mb_y = 0; + io->y = dec->cache_y_; + io->u = dec->cache_u_; + io->v = dec->cache_v_; + io->y_stride = dec->cache_y_stride_; + io->uv_stride = dec->cache_uv_stride_; + io->a = NULL; +} + +int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io) { + if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_. + if (!AllocateMemory(dec)) return 0; + InitIo(dec, io); + VP8DspInit(); // Init critical function pointers and look-up tables. + return 1; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dec/idec_dec.c b/libraries/webp/src/dec/idec_dec.c new file mode 100644 index 00000000000..78428d24b3f --- /dev/null +++ b/libraries/webp/src/dec/idec_dec.c @@ -0,0 +1,920 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Incremental decoding +// +// Author: somnath@google.com (Somnath Banerjee) + +#include +#include +#include + +#include "src/dec/alphai_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/dec/vp8_dec.h" +#include "src/dec/vp8i_dec.h" +#include "src/utils/utils.h" +#include "include/webp/decode.h" + +// In append mode, buffer allocations increase as multiples of this value. +// Needs to be a power of 2. +#define CHUNK_SIZE 4096 +#define MAX_MB_SIZE 4096 + +//------------------------------------------------------------------------------ +// Data structures for memory and states + +// Decoding states. State normally flows as: +// WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and +// WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image. +// If there is any error the decoder goes into state ERROR. +typedef enum { + STATE_WEBP_HEADER, // All the data before that of the VP8/VP8L chunk. + STATE_VP8_HEADER, // The VP8 Frame header (within the VP8 chunk). + STATE_VP8_PARTS0, + STATE_VP8_DATA, + STATE_VP8L_HEADER, + STATE_VP8L_DATA, + STATE_DONE, + STATE_ERROR +} DecState; + +// Operating state for the MemBuffer +typedef enum { + MEM_MODE_NONE = 0, + MEM_MODE_APPEND, + MEM_MODE_MAP +} MemBufferMode; + +// storage for partition #0 and partial data (in a rolling fashion) +typedef struct { + MemBufferMode mode_; // Operation mode + size_t start_; // start location of the data to be decoded + size_t end_; // end location + size_t buf_size_; // size of the allocated buffer + uint8_t* buf_; // We don't own this buffer in case WebPIUpdate() + + size_t part0_size_; // size of partition #0 + const uint8_t* part0_buf_; // buffer to store partition #0 +} MemBuffer; + +struct WebPIDecoder { + DecState state_; // current decoding state + WebPDecParams params_; // Params to store output info + int is_lossless_; // for down-casting 'dec_'. + void* dec_; // either a VP8Decoder or a VP8LDecoder instance + VP8Io io_; + + MemBuffer mem_; // input memory buffer. + WebPDecBuffer output_; // output buffer (when no external one is supplied, + // or if the external one has slow-memory) + WebPDecBuffer* final_output_; // Slow-memory output to copy to eventually. + size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header. + + int last_mb_y_; // last row reached for intra-mode decoding +}; + +// MB context to restore in case VP8DecodeMB() fails +typedef struct { + VP8MB left_; + VP8MB info_; + VP8BitReader token_br_; +} MBContext; + +//------------------------------------------------------------------------------ +// MemBuffer: incoming data handling + +static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { + return (mem->end_ - mem->start_); +} + +// Check if we need to preserve the compressed alpha data, as it may not have +// been decoded yet. +static int NeedCompressedAlpha(const WebPIDecoder* const idec) { + if (idec->state_ == STATE_WEBP_HEADER) { + // We haven't parsed the headers yet, so we don't know whether the image is + // lossy or lossless. This also means that we haven't parsed the ALPH chunk. + return 0; + } + if (idec->is_lossless_) { + return 0; // ALPH chunk is not present for lossless images. + } else { + const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + assert(dec != NULL); // Must be true as idec->state_ != STATE_WEBP_HEADER. + return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_; + } +} + +static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { + MemBuffer* const mem = &idec->mem_; + const uint8_t* const new_base = mem->buf_ + mem->start_; + // note: for VP8, setting up idec->io_ is only really needed at the beginning + // of the decoding, till partition #0 is complete. + idec->io_.data = new_base; + idec->io_.data_size = MemDataSize(mem); + + if (idec->dec_ != NULL) { + if (!idec->is_lossless_) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + const uint32_t last_part = dec->num_parts_minus_one_; + if (offset != 0) { + uint32_t p; + for (p = 0; p <= last_part; ++p) { + VP8RemapBitReader(dec->parts_ + p, offset); + } + // Remap partition #0 data pointer to new offset, but only in MAP + // mode (in APPEND mode, partition #0 is copied into a fixed memory). + if (mem->mode_ == MEM_MODE_MAP) { + VP8RemapBitReader(&dec->br_, offset); + } + } + { + const uint8_t* const last_start = dec->parts_[last_part].buf_; + VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start, + mem->buf_ + mem->end_ - last_start); + } + if (NeedCompressedAlpha(idec)) { + ALPHDecoder* const alph_dec = dec->alph_dec_; + dec->alpha_data_ += offset; + if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) { + if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { + VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; + assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN); + VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_, + dec->alpha_data_ + ALPHA_HEADER_LEN, + dec->alpha_data_size_ - ALPHA_HEADER_LEN); + } else { // alph_dec->method_ == ALPHA_NO_COMPRESSION + // Nothing special to do in this case. + } + } + } + } else { // Resize lossless bitreader + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; + VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem)); + } + } +} + +// Appends data to the end of MemBuffer->buf_. It expands the allocated memory +// size if required and also updates VP8BitReader's if new memory is allocated. +WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec, + const uint8_t* const data, + size_t data_size) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + MemBuffer* const mem = &idec->mem_; + const int need_compressed_alpha = NeedCompressedAlpha(idec); + const uint8_t* const old_start = + (mem->buf_ == NULL) ? NULL : mem->buf_ + mem->start_; + const uint8_t* const old_base = + need_compressed_alpha ? dec->alpha_data_ : old_start; + assert(mem->buf_ != NULL || mem->start_ == 0); + assert(mem->mode_ == MEM_MODE_APPEND); + if (data_size > MAX_CHUNK_PAYLOAD) { + // security safeguard: trying to allocate more than what the format + // allows for a chunk should be considered a smoke smell. + return 0; + } + + if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory + const size_t new_mem_start = old_start - old_base; + const size_t current_size = MemDataSize(mem) + new_mem_start; + const uint64_t new_size = (uint64_t)current_size + data_size; + const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1); + uint8_t* const new_buf = + (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); + if (new_buf == NULL) return 0; + if (old_base != NULL) memcpy(new_buf, old_base, current_size); + WebPSafeFree(mem->buf_); + mem->buf_ = new_buf; + mem->buf_size_ = (size_t)extra_size; + mem->start_ = new_mem_start; + mem->end_ = current_size; + } + + assert(mem->buf_ != NULL); + memcpy(mem->buf_ + mem->end_, data, data_size); + mem->end_ += data_size; + assert(mem->end_ <= mem->buf_size_); + + DoRemap(idec, mem->buf_ + mem->start_ - old_start); + return 1; +} + +WEBP_NODISCARD static int RemapMemBuffer(WebPIDecoder* const idec, + const uint8_t* const data, + size_t data_size) { + MemBuffer* const mem = &idec->mem_; + const uint8_t* const old_buf = mem->buf_; + const uint8_t* const old_start = + (old_buf == NULL) ? NULL : old_buf + mem->start_; + assert(old_buf != NULL || mem->start_ == 0); + assert(mem->mode_ == MEM_MODE_MAP); + + if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer! + + mem->buf_ = (uint8_t*)data; + mem->end_ = mem->buf_size_ = data_size; + + DoRemap(idec, mem->buf_ + mem->start_ - old_start); + return 1; +} + +static void InitMemBuffer(MemBuffer* const mem) { + mem->mode_ = MEM_MODE_NONE; + mem->buf_ = NULL; + mem->buf_size_ = 0; + mem->part0_buf_ = NULL; + mem->part0_size_ = 0; +} + +static void ClearMemBuffer(MemBuffer* const mem) { + assert(mem); + if (mem->mode_ == MEM_MODE_APPEND) { + WebPSafeFree(mem->buf_); + WebPSafeFree((void*)mem->part0_buf_); + } +} + +WEBP_NODISCARD static int CheckMemBufferMode(MemBuffer* const mem, + MemBufferMode expected) { + if (mem->mode_ == MEM_MODE_NONE) { + mem->mode_ = expected; // switch to the expected mode + } else if (mem->mode_ != expected) { + return 0; // we mixed the modes => error + } + assert(mem->mode_ == expected); // mode is ok + return 1; +} + +// To be called last. +WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { + const WebPDecoderOptions* const options = idec->params_.options; + WebPDecBuffer* const output = idec->params_.output; + + idec->state_ = STATE_DONE; + if (options != NULL && options->flip) { + const VP8StatusCode status = WebPFlipBuffer(output); + if (status != VP8_STATUS_OK) return status; + } + if (idec->final_output_ != NULL) { + const VP8StatusCode status = WebPCopyDecBufferPixels( + output, idec->final_output_); // do the slow-copy + WebPFreeDecBuffer(&idec->output_); + if (status != VP8_STATUS_OK) return status; + *output = *idec->final_output_; + idec->final_output_ = NULL; + } + return VP8_STATUS_OK; +} + +//------------------------------------------------------------------------------ +// Macroblock-decoding contexts + +static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, + MBContext* const context) { + context->left_ = dec->mb_info_[-1]; + context->info_ = dec->mb_info_[dec->mb_x_]; + context->token_br_ = *token_br; +} + +static void RestoreContext(const MBContext* context, VP8Decoder* const dec, + VP8BitReader* const token_br) { + dec->mb_info_[-1] = context->left_; + dec->mb_info_[dec->mb_x_] = context->info_; + *token_br = context->token_br_; +} + +//------------------------------------------------------------------------------ + +static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) { + if (idec->state_ == STATE_VP8_DATA) { + // Synchronize the thread, clean-up and check for errors. + (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); + } + idec->state_ = STATE_ERROR; + return error; +} + +static void ChangeState(WebPIDecoder* const idec, DecState new_state, + size_t consumed_bytes) { + MemBuffer* const mem = &idec->mem_; + idec->state_ = new_state; + mem->start_ += consumed_bytes; + assert(mem->start_ <= mem->end_); + idec->io_.data = mem->buf_ + mem->start_; + idec->io_.data_size = MemDataSize(mem); +} + +// Headers +static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) { + MemBuffer* const mem = &idec->mem_; + const uint8_t* data = mem->buf_ + mem->start_; + size_t curr_size = MemDataSize(mem); + VP8StatusCode status; + WebPHeaderStructure headers; + + headers.data = data; + headers.data_size = curr_size; + headers.have_all_data = 0; + status = WebPParseHeaders(&headers); + if (status == VP8_STATUS_NOT_ENOUGH_DATA) { + return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet. + } else if (status != VP8_STATUS_OK) { + return IDecError(idec, status); + } + + idec->chunk_size_ = headers.compressed_size; + idec->is_lossless_ = headers.is_lossless; + if (!idec->is_lossless_) { + VP8Decoder* const dec = VP8New(); + if (dec == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + dec->incremental_ = 1; + idec->dec_ = dec; + dec->alpha_data_ = headers.alpha_data; + dec->alpha_data_size_ = headers.alpha_data_size; + ChangeState(idec, STATE_VP8_HEADER, headers.offset); + } else { + VP8LDecoder* const dec = VP8LNew(); + if (dec == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + idec->dec_ = dec; + ChangeState(idec, STATE_VP8L_HEADER, headers.offset); + } + return VP8_STATUS_OK; +} + +static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { + const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; + const size_t curr_size = MemDataSize(&idec->mem_); + int width, height; + uint32_t bits; + + if (curr_size < VP8_FRAME_HEADER_SIZE) { + // Not enough data bytes to extract VP8 Frame Header. + return VP8_STATUS_SUSPENDED; + } + if (!VP8GetInfo(data, curr_size, idec->chunk_size_, &width, &height)) { + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + + bits = data[0] | (data[1] << 8) | (data[2] << 16); + idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE; + + idec->io_.data = data; + idec->io_.data_size = curr_size; + idec->state_ = STATE_VP8_PARTS0; + return VP8_STATUS_OK; +} + +// Partition #0 +static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + VP8BitReader* const br = &dec->br_; + const size_t part_size = br->buf_end_ - br->buf_; + MemBuffer* const mem = &idec->mem_; + assert(!idec->is_lossless_); + assert(mem->part0_buf_ == NULL); + // the following is a format limitation, no need for runtime check: + assert(part_size <= mem->part0_size_); + if (part_size == 0) { // can't have zero-size partition #0 + return VP8_STATUS_BITSTREAM_ERROR; + } + if (mem->mode_ == MEM_MODE_APPEND) { + // We copy and grab ownership of the partition #0 data. + uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size); + if (part0_buf == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + memcpy(part0_buf, br->buf_, part_size); + mem->part0_buf_ = part0_buf; + VP8BitReaderSetBuffer(br, part0_buf, part_size); + } else { + // Else: just keep pointers to the partition #0's data in dec_->br_. + } + mem->start_ += part_size; + return VP8_STATUS_OK; +} + +static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + VP8Io* const io = &idec->io_; + const WebPDecParams* const params = &idec->params_; + WebPDecBuffer* const output = params->output; + + // Wait till we have enough data for the whole partition #0 + if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) { + return VP8_STATUS_SUSPENDED; + } + + if (!VP8GetHeaders(dec, io)) { + const VP8StatusCode status = dec->status_; + if (status == VP8_STATUS_SUSPENDED || + status == VP8_STATUS_NOT_ENOUGH_DATA) { + // treating NOT_ENOUGH_DATA as SUSPENDED state + return VP8_STATUS_SUSPENDED; + } + return IDecError(idec, status); + } + + // Allocate/Verify output buffer now + dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, + output); + if (dec->status_ != VP8_STATUS_OK) { + return IDecError(idec, dec->status_); + } + // This change must be done before calling VP8InitFrame() + dec->mt_method_ = VP8GetThreadMethod(params->options, NULL, + io->width, io->height); + VP8InitDithering(params->options, dec); + + dec->status_ = CopyParts0Data(idec); + if (dec->status_ != VP8_STATUS_OK) { + return IDecError(idec, dec->status_); + } + + // Finish setting up the decoding parameters. Will call io->setup(). + if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) { + return IDecError(idec, dec->status_); + } + + // Note: past this point, teardown() must always be called + // in case of error. + idec->state_ = STATE_VP8_DATA; + // Allocate memory and prepare everything. + if (!VP8InitFrame(dec, io)) { + return IDecError(idec, dec->status_); + } + return VP8_STATUS_OK; +} + +// Remaining partitions +static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + VP8Io* const io = &idec->io_; + + // Make sure partition #0 has been read before, to set dec to ready_. + if (!dec->ready_) { + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { + if (idec->last_mb_y_ != dec->mb_y_) { + if (!VP8ParseIntraModeRow(&dec->br_, dec)) { + // note: normally, error shouldn't occur since we already have the whole + // partition0 available here in DecodeRemaining(). Reaching EOF while + // reading intra modes really means a BITSTREAM_ERROR. + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + idec->last_mb_y_ = dec->mb_y_; + } + for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { + VP8BitReader* const token_br = + &dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_]; + MBContext context; + SaveContext(dec, token_br, &context); + if (!VP8DecodeMB(dec, token_br)) { + // We shouldn't fail when MAX_MB data was available + if (dec->num_parts_minus_one_ == 0 && + MemDataSize(&idec->mem_) > MAX_MB_SIZE) { + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + // Synchronize the threads. + if (dec->mt_method_ > 0) { + if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) { + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + } + RestoreContext(&context, dec, token_br); + return VP8_STATUS_SUSPENDED; + } + // Release buffer only if there is only one partition + if (dec->num_parts_minus_one_ == 0) { + idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_; + assert(idec->mem_.start_ <= idec->mem_.end_); + } + } + VP8InitScanline(dec); // Prepare for next scanline + + // Reconstruct, filter and emit the row. + if (!VP8ProcessRow(dec, io)) { + return IDecError(idec, VP8_STATUS_USER_ABORT); + } + } + // Synchronize the thread and check for errors. + if (!VP8ExitCritical(dec, io)) { + idec->state_ = STATE_ERROR; // prevent re-entry in IDecError + return IDecError(idec, VP8_STATUS_USER_ABORT); + } + dec->ready_ = 0; + return FinishDecoding(idec); +} + +static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec, + VP8StatusCode status) { + if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) { + return VP8_STATUS_SUSPENDED; + } + return IDecError(idec, status); +} + +static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) { + VP8Io* const io = &idec->io_; + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; + const WebPDecParams* const params = &idec->params_; + WebPDecBuffer* const output = params->output; + size_t curr_size = MemDataSize(&idec->mem_); + assert(idec->is_lossless_); + + // Wait until there's enough data for decoding header. + if (curr_size < (idec->chunk_size_ >> 3)) { + dec->status_ = VP8_STATUS_SUSPENDED; + return ErrorStatusLossless(idec, dec->status_); + } + + if (!VP8LDecodeHeader(dec, io)) { + if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && + curr_size < idec->chunk_size_) { + dec->status_ = VP8_STATUS_SUSPENDED; + } + return ErrorStatusLossless(idec, dec->status_); + } + // Allocate/verify output buffer now. + dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, + output); + if (dec->status_ != VP8_STATUS_OK) { + return IDecError(idec, dec->status_); + } + + idec->state_ = STATE_VP8L_DATA; + return VP8_STATUS_OK; +} + +static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) { + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; + const size_t curr_size = MemDataSize(&idec->mem_); + assert(idec->is_lossless_); + + // Switch to incremental decoding if we don't have all the bytes available. + dec->incremental_ = (curr_size < idec->chunk_size_); + + if (!VP8LDecodeImage(dec)) { + return ErrorStatusLossless(idec, dec->status_); + } + assert(dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED); + return (dec->status_ == VP8_STATUS_SUSPENDED) ? dec->status_ + : FinishDecoding(idec); +} + + // Main decoding loop +static VP8StatusCode IDecode(WebPIDecoder* idec) { + VP8StatusCode status = VP8_STATUS_SUSPENDED; + + if (idec->state_ == STATE_WEBP_HEADER) { + status = DecodeWebPHeaders(idec); + } else { + if (idec->dec_ == NULL) { + return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. + } + } + if (idec->state_ == STATE_VP8_HEADER) { + status = DecodeVP8FrameHeader(idec); + } + if (idec->state_ == STATE_VP8_PARTS0) { + status = DecodePartition0(idec); + } + if (idec->state_ == STATE_VP8_DATA) { + const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + if (dec == NULL) { + return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. + } + status = DecodeRemaining(idec); + } + if (idec->state_ == STATE_VP8L_HEADER) { + status = DecodeVP8LHeader(idec); + } + if (idec->state_ == STATE_VP8L_DATA) { + status = DecodeVP8LData(idec); + } + return status; +} + +//------------------------------------------------------------------------------ +// Internal constructor + +WEBP_NODISCARD static WebPIDecoder* NewDecoder( + WebPDecBuffer* const output_buffer, + const WebPBitstreamFeatures* const features) { + WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec)); + if (idec == NULL) { + return NULL; + } + + idec->state_ = STATE_WEBP_HEADER; + idec->chunk_size_ = 0; + + idec->last_mb_y_ = -1; + + InitMemBuffer(&idec->mem_); + if (!WebPInitDecBuffer(&idec->output_) || !VP8InitIo(&idec->io_)) { + WebPSafeFree(idec); + return NULL; + } + + WebPResetDecParams(&idec->params_); + if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) { + idec->params_.output = &idec->output_; + idec->final_output_ = output_buffer; + if (output_buffer != NULL) { + idec->params_.output->colorspace = output_buffer->colorspace; + } + } else { + idec->params_.output = output_buffer; + idec->final_output_ = NULL; + } + WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. + + return idec; +} + +//------------------------------------------------------------------------------ +// Public functions + +WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { + return NewDecoder(output_buffer, NULL); +} + +WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, + WebPDecoderConfig* config) { + WebPIDecoder* idec; + WebPBitstreamFeatures tmp_features; + WebPBitstreamFeatures* const features = + (config == NULL) ? &tmp_features : &config->input; + memset(&tmp_features, 0, sizeof(tmp_features)); + + // Parse the bitstream's features, if requested: + if (data != NULL && data_size > 0) { + if (WebPGetFeatures(data, data_size, features) != VP8_STATUS_OK) { + return NULL; + } + } + + // Create an instance of the incremental decoder + idec = (config != NULL) ? NewDecoder(&config->output, features) + : NewDecoder(NULL, features); + if (idec == NULL) { + return NULL; + } + // Finish initialization + if (config != NULL) { + idec->params_.options = &config->options; + } + return idec; +} + +void WebPIDelete(WebPIDecoder* idec) { + if (idec == NULL) return; + if (idec->dec_ != NULL) { + if (!idec->is_lossless_) { + if (idec->state_ == STATE_VP8_DATA) { + // Synchronize the thread, clean-up and check for errors. + // TODO(vrabaud) do we care about the return result? + (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); + } + VP8Delete((VP8Decoder*)idec->dec_); + } else { + VP8LDelete((VP8LDecoder*)idec->dec_); + } + } + ClearMemBuffer(&idec->mem_); + WebPFreeDecBuffer(&idec->output_); + WebPSafeFree(idec); +} + +//------------------------------------------------------------------------------ +// Wrapper toward WebPINewDecoder + +WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer, + size_t output_buffer_size, int output_stride) { + const int is_external_memory = (output_buffer != NULL) ? 1 : 0; + WebPIDecoder* idec; + + if (csp >= MODE_YUV) return NULL; + if (is_external_memory == 0) { // Overwrite parameters to sane values. + output_buffer_size = 0; + output_stride = 0; + } else { // A buffer was passed. Validate the other params. + if (output_stride == 0 || output_buffer_size == 0) { + return NULL; // invalid parameter. + } + } + idec = WebPINewDecoder(NULL); + if (idec == NULL) return NULL; + idec->output_.colorspace = csp; + idec->output_.is_external_memory = is_external_memory; + idec->output_.u.RGBA.rgba = output_buffer; + idec->output_.u.RGBA.stride = output_stride; + idec->output_.u.RGBA.size = output_buffer_size; + return idec; +} + +WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride, + uint8_t* a, size_t a_size, int a_stride) { + const int is_external_memory = (luma != NULL) ? 1 : 0; + WebPIDecoder* idec; + WEBP_CSP_MODE colorspace; + + if (is_external_memory == 0) { // Overwrite parameters to sane values. + luma_size = u_size = v_size = a_size = 0; + luma_stride = u_stride = v_stride = a_stride = 0; + u = v = a = NULL; + colorspace = MODE_YUVA; + } else { // A luma buffer was passed. Validate the other parameters. + if (u == NULL || v == NULL) return NULL; + if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL; + if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL; + if (a != NULL) { + if (a_size == 0 || a_stride == 0) return NULL; + } + colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA; + } + + idec = WebPINewDecoder(NULL); + if (idec == NULL) return NULL; + + idec->output_.colorspace = colorspace; + idec->output_.is_external_memory = is_external_memory; + idec->output_.u.YUVA.y = luma; + idec->output_.u.YUVA.y_stride = luma_stride; + idec->output_.u.YUVA.y_size = luma_size; + idec->output_.u.YUVA.u = u; + idec->output_.u.YUVA.u_stride = u_stride; + idec->output_.u.YUVA.u_size = u_size; + idec->output_.u.YUVA.v = v; + idec->output_.u.YUVA.v_stride = v_stride; + idec->output_.u.YUVA.v_size = v_size; + idec->output_.u.YUVA.a = a; + idec->output_.u.YUVA.a_stride = a_stride; + idec->output_.u.YUVA.a_size = a_size; + return idec; +} + +WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride) { + return WebPINewYUVA(luma, luma_size, luma_stride, + u, u_size, u_stride, + v, v_size, v_stride, + NULL, 0, 0); +} + +//------------------------------------------------------------------------------ + +static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) { + assert(idec); + if (idec->state_ == STATE_ERROR) { + return VP8_STATUS_BITSTREAM_ERROR; + } + if (idec->state_ == STATE_DONE) { + return VP8_STATUS_OK; + } + return VP8_STATUS_SUSPENDED; +} + +VP8StatusCode WebPIAppend(WebPIDecoder* idec, + const uint8_t* data, size_t data_size) { + VP8StatusCode status; + if (idec == NULL || data == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + status = IDecCheckStatus(idec); + if (status != VP8_STATUS_SUSPENDED) { + return status; + } + // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. + if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) { + return VP8_STATUS_INVALID_PARAM; + } + // Append data to memory buffer + if (!AppendToMemBuffer(idec, data, data_size)) { + return VP8_STATUS_OUT_OF_MEMORY; + } + return IDecode(idec); +} + +VP8StatusCode WebPIUpdate(WebPIDecoder* idec, + const uint8_t* data, size_t data_size) { + VP8StatusCode status; + if (idec == NULL || data == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + status = IDecCheckStatus(idec); + if (status != VP8_STATUS_SUSPENDED) { + return status; + } + // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. + if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) { + return VP8_STATUS_INVALID_PARAM; + } + // Make the memory buffer point to the new buffer + if (!RemapMemBuffer(idec, data, data_size)) { + return VP8_STATUS_INVALID_PARAM; + } + return IDecode(idec); +} + +//------------------------------------------------------------------------------ + +static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) { + if (idec == NULL || idec->dec_ == NULL) { + return NULL; + } + if (idec->state_ <= STATE_VP8_PARTS0) { + return NULL; + } + if (idec->final_output_ != NULL) { + return NULL; // not yet slow-copied + } + return idec->params_.output; +} + +const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, + int* left, int* top, + int* width, int* height) { + const WebPDecBuffer* const src = GetOutputBuffer(idec); + if (left != NULL) *left = 0; + if (top != NULL) *top = 0; + if (src != NULL) { + if (width != NULL) *width = src->width; + if (height != NULL) *height = idec->params_.last_y; + } else { + if (width != NULL) *width = 0; + if (height != NULL) *height = 0; + } + return src; +} + +WEBP_NODISCARD uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y, + int* width, int* height, int* stride) { + const WebPDecBuffer* const src = GetOutputBuffer(idec); + if (src == NULL) return NULL; + if (src->colorspace >= MODE_YUV) { + return NULL; + } + + if (last_y != NULL) *last_y = idec->params_.last_y; + if (width != NULL) *width = src->width; + if (height != NULL) *height = src->height; + if (stride != NULL) *stride = src->u.RGBA.stride; + + return src->u.RGBA.rgba; +} + +WEBP_NODISCARD uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y, + uint8_t** u, uint8_t** v, uint8_t** a, + int* width, int* height, int* stride, + int* uv_stride, int* a_stride) { + const WebPDecBuffer* const src = GetOutputBuffer(idec); + if (src == NULL) return NULL; + if (src->colorspace < MODE_YUV) { + return NULL; + } + + if (last_y != NULL) *last_y = idec->params_.last_y; + if (u != NULL) *u = src->u.YUVA.u; + if (v != NULL) *v = src->u.YUVA.v; + if (a != NULL) *a = src->u.YUVA.a; + if (width != NULL) *width = src->width; + if (height != NULL) *height = src->height; + if (stride != NULL) *stride = src->u.YUVA.y_stride; + if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride; + if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride; + + return src->u.YUVA.y; +} + +int WebPISetIOHooks(WebPIDecoder* const idec, + VP8IoPutHook put, + VP8IoSetupHook setup, + VP8IoTeardownHook teardown, + void* user_data) { + if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) { + return 0; + } + + idec->io_.put = put; + idec->io_.setup = setup; + idec->io_.teardown = teardown; + idec->io_.opaque = user_data; + + return 1; +} diff --git a/libraries/webp/src/dec/io_dec.c b/libraries/webp/src/dec/io_dec.c new file mode 100644 index 00000000000..5ef6298886e --- /dev/null +++ b/libraries/webp/src/dec/io_dec.c @@ -0,0 +1,662 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// functions for sample output. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include "src/dec/vp8i_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/dsp/dsp.h" +#include "src/dsp/yuv.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// Main YUV<->RGB conversion functions + +static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { + WebPDecBuffer* output = p->output; + const WebPYUVABuffer* const buf = &output->u.YUVA; + uint8_t* const y_dst = buf->y + (size_t)io->mb_y * buf->y_stride; + uint8_t* const u_dst = buf->u + (size_t)(io->mb_y >> 1) * buf->u_stride; + uint8_t* const v_dst = buf->v + (size_t)(io->mb_y >> 1) * buf->v_stride; + const int mb_w = io->mb_w; + const int mb_h = io->mb_h; + const int uv_w = (mb_w + 1) / 2; + const int uv_h = (mb_h + 1) / 2; + WebPCopyPlane(io->y, io->y_stride, y_dst, buf->y_stride, mb_w, mb_h); + WebPCopyPlane(io->u, io->uv_stride, u_dst, buf->u_stride, uv_w, uv_h); + WebPCopyPlane(io->v, io->uv_stride, v_dst, buf->v_stride, uv_w, uv_h); + return io->mb_h; +} + +// Point-sampling U/V sampler. +static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) { + WebPDecBuffer* const output = p->output; + WebPRGBABuffer* const buf = &output->u.RGBA; + uint8_t* const dst = buf->rgba + (size_t)io->mb_y * buf->stride; + WebPSamplerProcessPlane(io->y, io->y_stride, + io->u, io->v, io->uv_stride, + dst, buf->stride, io->mb_w, io->mb_h, + WebPSamplers[output->colorspace]); + return io->mb_h; +} + +//------------------------------------------------------------------------------ +// Fancy upsampling + +#ifdef FANCY_UPSAMPLING +static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) { + int num_lines_out = io->mb_h; // a priori guess + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + uint8_t* dst = buf->rgba + (size_t)io->mb_y * buf->stride; + WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace]; + const uint8_t* cur_y = io->y; + const uint8_t* cur_u = io->u; + const uint8_t* cur_v = io->v; + const uint8_t* top_u = p->tmp_u; + const uint8_t* top_v = p->tmp_v; + int y = io->mb_y; + const int y_end = io->mb_y + io->mb_h; + const int mb_w = io->mb_w; + const int uv_w = (mb_w + 1) / 2; + + if (y == 0) { + // First line is special cased. We mirror the u/v samples at boundary. + upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, mb_w); + } else { + // We can finish the left-over line from previous call. + upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v, + dst - buf->stride, dst, mb_w); + ++num_lines_out; + } + // Loop over each output pairs of row. + for (; y + 2 < y_end; y += 2) { + top_u = cur_u; + top_v = cur_v; + cur_u += io->uv_stride; + cur_v += io->uv_stride; + dst += 2 * buf->stride; + cur_y += 2 * io->y_stride; + upsample(cur_y - io->y_stride, cur_y, + top_u, top_v, cur_u, cur_v, + dst - buf->stride, dst, mb_w); + } + // move to last row + cur_y += io->y_stride; + if (io->crop_top + y_end < io->crop_bottom) { + // Save the unfinished samples for next call (as we're not done yet). + memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y)); + memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u)); + memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v)); + // The fancy upsampler leaves a row unfinished behind + // (except for the very last row) + num_lines_out--; + } else { + // Process the very last row of even-sized picture + if (!(y_end & 1)) { + upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, + dst + buf->stride, NULL, mb_w); + } + } + return num_lines_out; +} + +#endif /* FANCY_UPSAMPLING */ + +//------------------------------------------------------------------------------ + +static void FillAlphaPlane(uint8_t* dst, int w, int h, int stride) { + int j; + for (j = 0; j < h; ++j) { + memset(dst, 0xff, w * sizeof(*dst)); + dst += stride; + } +} + +static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p, + int expected_num_lines_out) { + const uint8_t* alpha = io->a; + const WebPYUVABuffer* const buf = &p->output->u.YUVA; + const int mb_w = io->mb_w; + const int mb_h = io->mb_h; + uint8_t* dst = buf->a + (size_t)io->mb_y * buf->a_stride; + int j; + (void)expected_num_lines_out; + assert(expected_num_lines_out == mb_h); + if (alpha != NULL) { + for (j = 0; j < mb_h; ++j) { + memcpy(dst, alpha, mb_w * sizeof(*dst)); + alpha += io->width; + dst += buf->a_stride; + } + } else if (buf->a != NULL) { + // the user requested alpha, but there is none, set it to opaque. + FillAlphaPlane(dst, mb_w, mb_h, buf->a_stride); + } + return 0; +} + +static int GetAlphaSourceRow(const VP8Io* const io, + const uint8_t** alpha, int* const num_rows) { + int start_y = io->mb_y; + *num_rows = io->mb_h; + + // Compensate for the 1-line delay of the fancy upscaler. + // This is similar to EmitFancyRGB(). + if (io->fancy_upsampling) { + if (start_y == 0) { + // We don't process the last row yet. It'll be done during the next call. + --*num_rows; + } else { + --start_y; + // Fortunately, *alpha data is persistent, so we can go back + // one row and finish alpha blending, now that the fancy upscaler + // completed the YUV->RGB interpolation. + *alpha -= io->width; + } + if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) { + // If it's the very last call, we process all the remaining rows! + *num_rows = io->crop_bottom - io->crop_top - start_y; + } + } + return start_y; +} + +static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p, + int expected_num_lines_out) { + const uint8_t* alpha = io->a; + if (alpha != NULL) { + const int mb_w = io->mb_w; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const int alpha_first = + (colorspace == MODE_ARGB || colorspace == MODE_Argb); + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + int num_rows; + const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows); + uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; + uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3); + const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w, + num_rows, dst, buf->stride); + (void)expected_num_lines_out; + assert(expected_num_lines_out == num_rows); + // has_alpha is true if there's non-trivial alpha to premultiply with. + if (has_alpha && WebPIsPremultipliedMode(colorspace)) { + WebPApplyAlphaMultiply(base_rgba, alpha_first, + mb_w, num_rows, buf->stride); + } + } + return 0; +} + +static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p, + int expected_num_lines_out) { + const uint8_t* alpha = io->a; + if (alpha != NULL) { + const int mb_w = io->mb_w; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + int num_rows; + const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows); + uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; +#if (WEBP_SWAP_16BIT_CSP == 1) + uint8_t* alpha_dst = base_rgba; +#else + uint8_t* alpha_dst = base_rgba + 1; +#endif + uint32_t alpha_mask = 0x0f; + int i, j; + for (j = 0; j < num_rows; ++j) { + for (i = 0; i < mb_w; ++i) { + // Fill in the alpha value (converted to 4 bits). + const uint32_t alpha_value = alpha[i] >> 4; + alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; + alpha_mask &= alpha_value; + } + alpha += io->width; + alpha_dst += buf->stride; + } + (void)expected_num_lines_out; + assert(expected_num_lines_out == num_rows); + if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) { + WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride); + } + } + return 0; +} + +//------------------------------------------------------------------------------ +// YUV rescaling (no final RGB conversion needed) + +#if !defined(WEBP_REDUCE_SIZE) +static int Rescale(const uint8_t* src, int src_stride, + int new_lines, WebPRescaler* const wrk) { + int num_lines_out = 0; + while (new_lines > 0) { // import new contributions of source rows. + const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride); + src += lines_in * src_stride; + new_lines -= lines_in; + num_lines_out += WebPRescalerExport(wrk); // emit output row(s) + } + return num_lines_out; +} + +static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { + const int mb_h = io->mb_h; + const int uv_mb_h = (mb_h + 1) >> 1; + WebPRescaler* const scaler = p->scaler_y; + int num_lines_out = 0; + if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { + // Before rescaling, we premultiply the luma directly into the io->y + // internal buffer. This is OK since these samples are not used for + // intra-prediction (the top samples are saved in cache_y_/u_/v_). + // But we need to cast the const away, though. + WebPMultRows((uint8_t*)io->y, io->y_stride, + io->a, io->width, io->mb_w, mb_h, 0); + } + num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler); + Rescale(io->u, io->uv_stride, uv_mb_h, p->scaler_u); + Rescale(io->v, io->uv_stride, uv_mb_h, p->scaler_v); + return num_lines_out; +} + +static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, + int expected_num_lines_out) { + const WebPYUVABuffer* const buf = &p->output->u.YUVA; + uint8_t* const dst_a = buf->a + (size_t)p->last_y * buf->a_stride; + if (io->a != NULL) { + uint8_t* const dst_y = buf->y + (size_t)p->last_y * buf->y_stride; + const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a); + assert(expected_num_lines_out == num_lines_out); + if (num_lines_out > 0) { // unmultiply the Y + WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride, + p->scaler_a->dst_width, num_lines_out, 1); + } + } else if (buf->a != NULL) { + // the user requested alpha, but there is none, set it to opaque. + assert(p->last_y + expected_num_lines_out <= io->scaled_height); + FillAlphaPlane(dst_a, io->scaled_width, expected_num_lines_out, + buf->a_stride); + } + return 0; +} + +static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { + const int has_alpha = WebPIsAlphaMode(p->output->colorspace); + const WebPYUVABuffer* const buf = &p->output->u.YUVA; + const int out_width = io->scaled_width; + const int out_height = io->scaled_height; + const int uv_out_width = (out_width + 1) >> 1; + const int uv_out_height = (out_height + 1) >> 1; + const int uv_in_width = (io->mb_w + 1) >> 1; + const int uv_in_height = (io->mb_h + 1) >> 1; + // scratch memory for luma rescaler + const size_t work_size = 2 * (size_t)out_width; + const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones + uint64_t total_size; + size_t rescaler_size; + rescaler_t* work; + WebPRescaler* scalers; + const int num_rescalers = has_alpha ? 4 : 3; + + total_size = ((uint64_t)work_size + 2 * uv_work_size) * sizeof(*work); + if (has_alpha) { + total_size += (uint64_t)work_size * sizeof(*work); + } + rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST; + total_size += rescaler_size; + if (!CheckSizeOverflow(total_size)) { + return 0; + } + + p->memory = WebPSafeMalloc(1ULL, (size_t)total_size); + if (p->memory == NULL) { + return 0; // memory error + } + work = (rescaler_t*)p->memory; + + scalers = (WebPRescaler*)WEBP_ALIGN( + (const uint8_t*)work + total_size - rescaler_size); + p->scaler_y = &scalers[0]; + p->scaler_u = &scalers[1]; + p->scaler_v = &scalers[2]; + p->scaler_a = has_alpha ? &scalers[3] : NULL; + + if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h, + buf->y, out_width, out_height, buf->y_stride, 1, + work) || + !WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height, + buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, + work + work_size) || + !WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height, + buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, + work + work_size + uv_work_size)) { + return 0; + } + p->emit = EmitRescaledYUV; + + if (has_alpha) { + if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h, + buf->a, out_width, out_height, buf->a_stride, 1, + work + work_size + 2 * uv_work_size)) { + return 0; + } + p->emit_alpha = EmitRescaledAlphaYUV; + WebPInitAlphaProcessing(); + } + return 1; +} + +//------------------------------------------------------------------------------ +// RGBA rescaling + +static int ExportRGB(WebPDecParams* const p, int y_pos) { + const WebPYUV444Converter convert = + WebPYUV444Converters[p->output->colorspace]; + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + uint8_t* dst = buf->rgba + (size_t)y_pos * buf->stride; + int num_lines_out = 0; + // For RGB rescaling, because of the YUV420, current scan position + // U/V can be +1/-1 line from the Y one. Hence the double test. + while (WebPRescalerHasPendingOutput(p->scaler_y) && + WebPRescalerHasPendingOutput(p->scaler_u)) { + assert(y_pos + num_lines_out < p->output->height); + assert(p->scaler_u->y_accum == p->scaler_v->y_accum); + WebPRescalerExportRow(p->scaler_y); + WebPRescalerExportRow(p->scaler_u); + WebPRescalerExportRow(p->scaler_v); + convert(p->scaler_y->dst, p->scaler_u->dst, p->scaler_v->dst, + dst, p->scaler_y->dst_width); + dst += buf->stride; + ++num_lines_out; + } + return num_lines_out; +} + +static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { + const int mb_h = io->mb_h; + const int uv_mb_h = (mb_h + 1) >> 1; + int j = 0, uv_j = 0; + int num_lines_out = 0; + while (j < mb_h) { + const int y_lines_in = + WebPRescalerImport(p->scaler_y, mb_h - j, + io->y + (size_t)j * io->y_stride, io->y_stride); + j += y_lines_in; + if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) { + const int u_lines_in = WebPRescalerImport( + p->scaler_u, uv_mb_h - uv_j, io->u + (size_t)uv_j * io->uv_stride, + io->uv_stride); + const int v_lines_in = WebPRescalerImport( + p->scaler_v, uv_mb_h - uv_j, io->v + (size_t)uv_j * io->uv_stride, + io->uv_stride); + (void)v_lines_in; // remove a gcc warning + assert(u_lines_in == v_lines_in); + uv_j += u_lines_in; + } + num_lines_out += ExportRGB(p, p->last_y + num_lines_out); + } + return num_lines_out; +} + +static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const int alpha_first = + (colorspace == MODE_ARGB || colorspace == MODE_Argb); + uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); + int num_lines_out = 0; + const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); + uint32_t non_opaque = 0; + const int width = p->scaler_a->dst_width; + + while (WebPRescalerHasPendingOutput(p->scaler_a) && + num_lines_out < max_lines_out) { + assert(y_pos + num_lines_out < p->output->height); + WebPRescalerExportRow(p->scaler_a); + non_opaque |= WebPDispatchAlpha(p->scaler_a->dst, 0, width, 1, dst, 0); + dst += buf->stride; + ++num_lines_out; + } + if (is_premult_alpha && non_opaque) { + WebPApplyAlphaMultiply(base_rgba, alpha_first, + width, num_lines_out, buf->stride); + } + return num_lines_out; +} + +static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, + int max_lines_out) { + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride; +#if (WEBP_SWAP_16BIT_CSP == 1) + uint8_t* alpha_dst = base_rgba; +#else + uint8_t* alpha_dst = base_rgba + 1; +#endif + int num_lines_out = 0; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const int width = p->scaler_a->dst_width; + const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); + uint32_t alpha_mask = 0x0f; + + while (WebPRescalerHasPendingOutput(p->scaler_a) && + num_lines_out < max_lines_out) { + int i; + assert(y_pos + num_lines_out < p->output->height); + WebPRescalerExportRow(p->scaler_a); + for (i = 0; i < width; ++i) { + // Fill in the alpha value (converted to 4 bits). + const uint32_t alpha_value = p->scaler_a->dst[i] >> 4; + alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; + alpha_mask &= alpha_value; + } + alpha_dst += buf->stride; + ++num_lines_out; + } + if (is_premult_alpha && alpha_mask != 0x0f) { + WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride); + } + return num_lines_out; +} + +static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p, + int expected_num_out_lines) { + if (io->a != NULL) { + WebPRescaler* const scaler = p->scaler_a; + int lines_left = expected_num_out_lines; + const int y_end = p->last_y + lines_left; + while (lines_left > 0) { + const int64_t row_offset = (int64_t)scaler->src_y - io->mb_y; + WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y, + io->a + row_offset * io->width, io->width); + lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left); + } + } + return 0; +} + +static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { + const int has_alpha = WebPIsAlphaMode(p->output->colorspace); + const int out_width = io->scaled_width; + const int out_height = io->scaled_height; + const int uv_in_width = (io->mb_w + 1) >> 1; + const int uv_in_height = (io->mb_h + 1) >> 1; + // scratch memory for one rescaler + const size_t work_size = 2 * (size_t)out_width; + rescaler_t* work; // rescalers work area + uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion + uint64_t tmp_size1, tmp_size2, total_size; + size_t rescaler_size; + WebPRescaler* scalers; + const int num_rescalers = has_alpha ? 4 : 3; + + tmp_size1 = (uint64_t)num_rescalers * work_size; + tmp_size2 = (uint64_t)num_rescalers * out_width; + total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp); + rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST; + total_size += rescaler_size; + if (!CheckSizeOverflow(total_size)) { + return 0; + } + + p->memory = WebPSafeMalloc(1ULL, (size_t)total_size); + if (p->memory == NULL) { + return 0; // memory error + } + work = (rescaler_t*)p->memory; + tmp = (uint8_t*)(work + tmp_size1); + + scalers = (WebPRescaler*)WEBP_ALIGN( + (const uint8_t*)work + total_size - rescaler_size); + p->scaler_y = &scalers[0]; + p->scaler_u = &scalers[1]; + p->scaler_v = &scalers[2]; + p->scaler_a = has_alpha ? &scalers[3] : NULL; + + if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h, + tmp + 0 * out_width, out_width, out_height, 0, 1, + work + 0 * work_size) || + !WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height, + tmp + 1 * out_width, out_width, out_height, 0, 1, + work + 1 * work_size) || + !WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height, + tmp + 2 * out_width, out_width, out_height, 0, 1, + work + 2 * work_size)) { + return 0; + } + p->emit = EmitRescaledRGB; + WebPInitYUV444Converters(); + + if (has_alpha) { + if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h, + tmp + 3 * out_width, out_width, out_height, 0, 1, + work + 3 * work_size)) { + return 0; + } + p->emit_alpha = EmitRescaledAlphaRGB; + if (p->output->colorspace == MODE_RGBA_4444 || + p->output->colorspace == MODE_rgbA_4444) { + p->emit_alpha_row = ExportAlphaRGBA4444; + } else { + p->emit_alpha_row = ExportAlpha; + } + WebPInitAlphaProcessing(); + } + return 1; +} + +#endif // WEBP_REDUCE_SIZE + +//------------------------------------------------------------------------------ +// Default custom functions + +static int CustomSetup(VP8Io* io) { + WebPDecParams* const p = (WebPDecParams*)io->opaque; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const int is_rgb = WebPIsRGBMode(colorspace); + const int is_alpha = WebPIsAlphaMode(colorspace); + + p->memory = NULL; + p->emit = NULL; + p->emit_alpha = NULL; + p->emit_alpha_row = NULL; + if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) { + return 0; + } + if (is_alpha && WebPIsPremultipliedMode(colorspace)) { + WebPInitUpsamplers(); + } + if (io->use_scaling) { +#if !defined(WEBP_REDUCE_SIZE) + const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p); + if (!ok) { + return 0; // memory error + } +#else + return 0; // rescaling support not compiled +#endif + } else { + if (is_rgb) { + WebPInitSamplers(); + p->emit = EmitSampledRGB; // default + if (io->fancy_upsampling) { +#ifdef FANCY_UPSAMPLING + const int uv_width = (io->mb_w + 1) >> 1; + p->memory = WebPSafeMalloc(1ULL, (size_t)(io->mb_w + 2 * uv_width)); + if (p->memory == NULL) { + return 0; // memory error. + } + p->tmp_y = (uint8_t*)p->memory; + p->tmp_u = p->tmp_y + io->mb_w; + p->tmp_v = p->tmp_u + uv_width; + p->emit = EmitFancyRGB; + WebPInitUpsamplers(); +#endif + } + } else { + p->emit = EmitYUV; + } + if (is_alpha) { // need transparency output + p->emit_alpha = + (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ? + EmitAlphaRGBA4444 + : is_rgb ? EmitAlphaRGB + : EmitAlphaYUV; + if (is_rgb) { + WebPInitAlphaProcessing(); + } + } + } + + return 1; +} + +//------------------------------------------------------------------------------ + +static int CustomPut(const VP8Io* io) { + WebPDecParams* const p = (WebPDecParams*)io->opaque; + const int mb_w = io->mb_w; + const int mb_h = io->mb_h; + int num_lines_out; + assert(!(io->mb_y & 1)); + + if (mb_w <= 0 || mb_h <= 0) { + return 0; + } + num_lines_out = p->emit(io, p); + if (p->emit_alpha != NULL) { + p->emit_alpha(io, p, num_lines_out); + } + p->last_y += num_lines_out; + return 1; +} + +//------------------------------------------------------------------------------ + +static void CustomTeardown(const VP8Io* io) { + WebPDecParams* const p = (WebPDecParams*)io->opaque; + WebPSafeFree(p->memory); + p->memory = NULL; +} + +//------------------------------------------------------------------------------ +// Main entry point + +void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) { + io->put = CustomPut; + io->setup = CustomSetup; + io->teardown = CustomTeardown; + io->opaque = params; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dec/quant_dec.c b/libraries/webp/src/dec/quant_dec.c new file mode 100644 index 00000000000..a0ac018b0f5 --- /dev/null +++ b/libraries/webp/src/dec/quant_dec.c @@ -0,0 +1,115 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Quantizer initialization +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dec/vp8i_dec.h" + +static WEBP_INLINE int clip(int v, int M) { + return v < 0 ? 0 : v > M ? M : v; +} + +// Paragraph 14.1 +static const uint8_t kDcTable[128] = { + 4, 5, 6, 7, 8, 9, 10, 10, + 11, 12, 13, 14, 15, 16, 17, 17, + 18, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 25, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 37, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, + 91, 93, 95, 96, 98, 100, 101, 102, + 104, 106, 108, 110, 112, 114, 116, 118, + 122, 124, 126, 128, 130, 132, 134, 136, + 138, 140, 143, 145, 148, 151, 154, 157 +}; + +static const uint16_t kAcTable[128] = { + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 60, + 62, 64, 66, 68, 70, 72, 74, 76, + 78, 80, 82, 84, 86, 88, 90, 92, + 94, 96, 98, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 119, 122, 125, 128, + 131, 134, 137, 140, 143, 146, 149, 152, + 155, 158, 161, 164, 167, 170, 173, 177, + 181, 185, 189, 193, 197, 201, 205, 209, + 213, 217, 221, 225, 229, 234, 239, 245, + 249, 254, 259, 264, 269, 274, 279, 284 +}; + +//------------------------------------------------------------------------------ +// Paragraph 9.6 + +void VP8ParseQuant(VP8Decoder* const dec) { + VP8BitReader* const br = &dec->br_; + const int base_q0 = VP8GetValue(br, 7, "global-header"); + const int dqy1_dc = VP8Get(br, "global-header") ? + VP8GetSignedValue(br, 4, "global-header") : 0; + const int dqy2_dc = VP8Get(br, "global-header") ? + VP8GetSignedValue(br, 4, "global-header") : 0; + const int dqy2_ac = VP8Get(br, "global-header") ? + VP8GetSignedValue(br, 4, "global-header") : 0; + const int dquv_dc = VP8Get(br, "global-header") ? + VP8GetSignedValue(br, 4, "global-header") : 0; + const int dquv_ac = VP8Get(br, "global-header") ? + VP8GetSignedValue(br, 4, "global-header") : 0; + + const VP8SegmentHeader* const hdr = &dec->segment_hdr_; + int i; + + for (i = 0; i < NUM_MB_SEGMENTS; ++i) { + int q; + if (hdr->use_segment_) { + q = hdr->quantizer_[i]; + if (!hdr->absolute_delta_) { + q += base_q0; + } + } else { + if (i > 0) { + dec->dqm_[i] = dec->dqm_[0]; + continue; + } else { + q = base_q0; + } + } + { + VP8QuantMatrix* const m = &dec->dqm_[i]; + m->y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)]; + m->y1_mat_[1] = kAcTable[clip(q + 0, 127)]; + + m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2; + // For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16. + // The smallest precision for that is '(x*6349) >> 12' but 16 is a good + // word size. + m->y2_mat_[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16; + if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8; + + m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)]; + m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)]; + + m->uv_quant_ = q + dquv_ac; // for dithering strength evaluation + } + } +} + +//------------------------------------------------------------------------------ + diff --git a/libraries/webp/src/dec/tree_dec.c b/libraries/webp/src/dec/tree_dec.c new file mode 100644 index 00000000000..24346059532 --- /dev/null +++ b/libraries/webp/src/dec/tree_dec.c @@ -0,0 +1,538 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Coding trees and probas +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dec/vp8i_dec.h" +#include "src/dsp/cpu.h" +#include "src/utils/bit_reader_inl_utils.h" + +#if !defined(USE_GENERIC_TREE) +#if !defined(__arm__) && !defined(_M_ARM) && !WEBP_AARCH64 +// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then. +#define USE_GENERIC_TREE 1 // ALTERNATE_CODE +#else +#define USE_GENERIC_TREE 0 +#endif +#endif // USE_GENERIC_TREE + +#if (USE_GENERIC_TREE == 1) +static const int8_t kYModesIntra4[18] = { + -B_DC_PRED, 1, + -B_TM_PRED, 2, + -B_VE_PRED, 3, + 4, 6, + -B_HE_PRED, 5, + -B_RD_PRED, -B_VR_PRED, + -B_LD_PRED, 7, + -B_VL_PRED, 8, + -B_HD_PRED, -B_HU_PRED +}; +#endif + +//------------------------------------------------------------------------------ +// Default probabilities + +// Paragraph 13.5 +static const uint8_t + CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { + { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 }, + { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 }, + { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 } + }, + { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 }, + { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 }, + { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 }, + }, + { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 }, + { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 }, + { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 }, + }, + { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 }, + { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 }, + { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 } + }, + { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 }, + { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 }, + { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 } + }, + { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 }, + { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 }, + { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 } + }, + { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 }, + { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 }, + { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 } + }, + { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 }, + { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 }, + { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 } + }, + { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 }, + { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 }, + { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 } + }, + { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 }, + { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 }, + { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 } + }, + { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 }, + { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 }, + { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 } + }, + { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 }, + { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 }, + { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 } + }, + { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 }, + { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 }, + { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 } + }, + { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 } + } + }, + { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 }, + { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 }, + { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 } + }, + { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 }, + { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 }, + { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 } + }, + { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 }, + { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 }, + { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 } + }, + { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 }, + { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 }, + { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 }, + { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 } + }, + { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 }, + { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 }, + { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 } + }, + { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 }, + { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 }, + { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 } + }, + { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 }, + { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 }, + { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 } + }, + { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 }, + { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 }, + { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 } + }, + { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 }, + { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 }, + { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 } + }, + { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 }, + { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 }, + { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 } + }, + { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + } + } +}; + +// Paragraph 11.5 +static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = { + { { 231, 120, 48, 89, 115, 113, 120, 152, 112 }, + { 152, 179, 64, 126, 170, 118, 46, 70, 95 }, + { 175, 69, 143, 80, 85, 82, 72, 155, 103 }, + { 56, 58, 10, 171, 218, 189, 17, 13, 152 }, + { 114, 26, 17, 163, 44, 195, 21, 10, 173 }, + { 121, 24, 80, 195, 26, 62, 44, 64, 85 }, + { 144, 71, 10, 38, 171, 213, 144, 34, 26 }, + { 170, 46, 55, 19, 136, 160, 33, 206, 71 }, + { 63, 20, 8, 114, 114, 208, 12, 9, 226 }, + { 81, 40, 11, 96, 182, 84, 29, 16, 36 } }, + { { 134, 183, 89, 137, 98, 101, 106, 165, 148 }, + { 72, 187, 100, 130, 157, 111, 32, 75, 80 }, + { 66, 102, 167, 99, 74, 62, 40, 234, 128 }, + { 41, 53, 9, 178, 241, 141, 26, 8, 107 }, + { 74, 43, 26, 146, 73, 166, 49, 23, 157 }, + { 65, 38, 105, 160, 51, 52, 31, 115, 128 }, + { 104, 79, 12, 27, 217, 255, 87, 17, 7 }, + { 87, 68, 71, 44, 114, 51, 15, 186, 23 }, + { 47, 41, 14, 110, 182, 183, 21, 17, 194 }, + { 66, 45, 25, 102, 197, 189, 23, 18, 22 } }, + { { 88, 88, 147, 150, 42, 46, 45, 196, 205 }, + { 43, 97, 183, 117, 85, 38, 35, 179, 61 }, + { 39, 53, 200, 87, 26, 21, 43, 232, 171 }, + { 56, 34, 51, 104, 114, 102, 29, 93, 77 }, + { 39, 28, 85, 171, 58, 165, 90, 98, 64 }, + { 34, 22, 116, 206, 23, 34, 43, 166, 73 }, + { 107, 54, 32, 26, 51, 1, 81, 43, 31 }, + { 68, 25, 106, 22, 64, 171, 36, 225, 114 }, + { 34, 19, 21, 102, 132, 188, 16, 76, 124 }, + { 62, 18, 78, 95, 85, 57, 50, 48, 51 } }, + { { 193, 101, 35, 159, 215, 111, 89, 46, 111 }, + { 60, 148, 31, 172, 219, 228, 21, 18, 111 }, + { 112, 113, 77, 85, 179, 255, 38, 120, 114 }, + { 40, 42, 1, 196, 245, 209, 10, 25, 109 }, + { 88, 43, 29, 140, 166, 213, 37, 43, 154 }, + { 61, 63, 30, 155, 67, 45, 68, 1, 209 }, + { 100, 80, 8, 43, 154, 1, 51, 26, 71 }, + { 142, 78, 78, 16, 255, 128, 34, 197, 171 }, + { 41, 40, 5, 102, 211, 183, 4, 1, 221 }, + { 51, 50, 17, 168, 209, 192, 23, 25, 82 } }, + { { 138, 31, 36, 171, 27, 166, 38, 44, 229 }, + { 67, 87, 58, 169, 82, 115, 26, 59, 179 }, + { 63, 59, 90, 180, 59, 166, 93, 73, 154 }, + { 40, 40, 21, 116, 143, 209, 34, 39, 175 }, + { 47, 15, 16, 183, 34, 223, 49, 45, 183 }, + { 46, 17, 33, 183, 6, 98, 15, 32, 183 }, + { 57, 46, 22, 24, 128, 1, 54, 17, 37 }, + { 65, 32, 73, 115, 28, 128, 23, 128, 205 }, + { 40, 3, 9, 115, 51, 192, 18, 6, 223 }, + { 87, 37, 9, 115, 59, 77, 64, 21, 47 } }, + { { 104, 55, 44, 218, 9, 54, 53, 130, 226 }, + { 64, 90, 70, 205, 40, 41, 23, 26, 57 }, + { 54, 57, 112, 184, 5, 41, 38, 166, 213 }, + { 30, 34, 26, 133, 152, 116, 10, 32, 134 }, + { 39, 19, 53, 221, 26, 114, 32, 73, 255 }, + { 31, 9, 65, 234, 2, 15, 1, 118, 73 }, + { 75, 32, 12, 51, 192, 255, 160, 43, 51 }, + { 88, 31, 35, 67, 102, 85, 55, 186, 85 }, + { 56, 21, 23, 111, 59, 205, 45, 37, 192 }, + { 55, 38, 70, 124, 73, 102, 1, 34, 98 } }, + { { 125, 98, 42, 88, 104, 85, 117, 175, 82 }, + { 95, 84, 53, 89, 128, 100, 113, 101, 45 }, + { 75, 79, 123, 47, 51, 128, 81, 171, 1 }, + { 57, 17, 5, 71, 102, 57, 53, 41, 49 }, + { 38, 33, 13, 121, 57, 73, 26, 1, 85 }, + { 41, 10, 67, 138, 77, 110, 90, 47, 114 }, + { 115, 21, 2, 10, 102, 255, 166, 23, 6 }, + { 101, 29, 16, 10, 85, 128, 101, 196, 26 }, + { 57, 18, 10, 102, 102, 213, 34, 20, 43 }, + { 117, 20, 15, 36, 163, 128, 68, 1, 26 } }, + { { 102, 61, 71, 37, 34, 53, 31, 243, 192 }, + { 69, 60, 71, 38, 73, 119, 28, 222, 37 }, + { 68, 45, 128, 34, 1, 47, 11, 245, 171 }, + { 62, 17, 19, 70, 146, 85, 55, 62, 70 }, + { 37, 43, 37, 154, 100, 163, 85, 160, 1 }, + { 63, 9, 92, 136, 28, 64, 32, 201, 85 }, + { 75, 15, 9, 9, 64, 255, 184, 119, 16 }, + { 86, 6, 28, 5, 64, 255, 25, 248, 1 }, + { 56, 8, 17, 132, 137, 255, 55, 116, 128 }, + { 58, 15, 20, 82, 135, 57, 26, 121, 40 } }, + { { 164, 50, 31, 137, 154, 133, 25, 35, 218 }, + { 51, 103, 44, 131, 131, 123, 31, 6, 158 }, + { 86, 40, 64, 135, 148, 224, 45, 183, 128 }, + { 22, 26, 17, 131, 240, 154, 14, 1, 209 }, + { 45, 16, 21, 91, 64, 222, 7, 1, 197 }, + { 56, 21, 39, 155, 60, 138, 23, 102, 213 }, + { 83, 12, 13, 54, 192, 255, 68, 47, 28 }, + { 85, 26, 85, 85, 128, 128, 32, 146, 171 }, + { 18, 11, 7, 63, 144, 171, 4, 4, 246 }, + { 35, 27, 10, 146, 174, 171, 12, 26, 128 } }, + { { 190, 80, 35, 99, 180, 80, 126, 54, 45 }, + { 85, 126, 47, 87, 176, 51, 41, 20, 32 }, + { 101, 75, 128, 139, 118, 146, 116, 128, 85 }, + { 56, 41, 15, 176, 236, 85, 37, 9, 62 }, + { 71, 30, 17, 119, 118, 255, 17, 18, 138 }, + { 101, 38, 60, 138, 55, 70, 43, 26, 142 }, + { 146, 36, 19, 30, 171, 255, 97, 27, 20 }, + { 138, 45, 61, 62, 219, 1, 81, 188, 64 }, + { 32, 41, 20, 117, 151, 142, 20, 21, 163 }, + { 112, 19, 12, 61, 195, 128, 48, 4, 24 } } +}; + +void VP8ResetProba(VP8Proba* const proba) { + memset(proba->segments_, 255u, sizeof(proba->segments_)); + // proba->bands_[][] is initialized later +} + +static void ParseIntraMode(VP8BitReader* const br, + VP8Decoder* const dec, int mb_x) { + uint8_t* const top = dec->intra_t_ + 4 * mb_x; + uint8_t* const left = dec->intra_l_; + VP8MBData* const block = dec->mb_data_ + mb_x; + + // Note: we don't save segment map (yet), as we don't expect + // to decode more than 1 keyframe. + if (dec->segment_hdr_.update_map_) { + // Hardcoded tree parsing + block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0], "segments") + ? VP8GetBit(br, dec->proba_.segments_[1], "segments") + : VP8GetBit(br, dec->proba_.segments_[2], "segments") + 2; + } else { + block->segment_ = 0; // default for intra + } + if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_, "skip"); + + block->is_i4x4_ = !VP8GetBit(br, 145, "block-size"); + if (!block->is_i4x4_) { + // Hardcoded 16x16 intra-mode decision tree. + const int ymode = + VP8GetBit(br, 156, "pred-modes") ? + (VP8GetBit(br, 128, "pred-modes") ? TM_PRED : H_PRED) : + (VP8GetBit(br, 163, "pred-modes") ? V_PRED : DC_PRED); + block->imodes_[0] = ymode; + memset(top, ymode, 4 * sizeof(*top)); + memset(left, ymode, 4 * sizeof(*left)); + } else { + uint8_t* modes = block->imodes_; + int y; + for (y = 0; y < 4; ++y) { + int ymode = left[y]; + int x; + for (x = 0; x < 4; ++x) { + const uint8_t* const prob = kBModesProba[top[x]][ymode]; +#if (USE_GENERIC_TREE == 1) + // Generic tree-parsing + int i = kYModesIntra4[VP8GetBit(br, prob[0], "pred-modes")]; + while (i > 0) { + i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i], "pred-modes")]; + } + ymode = -i; +#else + // Hardcoded tree parsing + ymode = !VP8GetBit(br, prob[0], "pred-modes") ? B_DC_PRED : + !VP8GetBit(br, prob[1], "pred-modes") ? B_TM_PRED : + !VP8GetBit(br, prob[2], "pred-modes") ? B_VE_PRED : + !VP8GetBit(br, prob[3], "pred-modes") ? + (!VP8GetBit(br, prob[4], "pred-modes") ? B_HE_PRED : + (!VP8GetBit(br, prob[5], "pred-modes") ? B_RD_PRED + : B_VR_PRED)) : + (!VP8GetBit(br, prob[6], "pred-modes") ? B_LD_PRED : + (!VP8GetBit(br, prob[7], "pred-modes") ? B_VL_PRED : + (!VP8GetBit(br, prob[8], "pred-modes") ? B_HD_PRED + : B_HU_PRED)) + ); +#endif // USE_GENERIC_TREE + top[x] = ymode; + } + memcpy(modes, top, 4 * sizeof(*top)); + modes += 4; + left[y] = ymode; + } + } + // Hardcoded UVMode decision tree + block->uvmode_ = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED + : !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED + : VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED; +} + +int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) { + int mb_x; + for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) { + ParseIntraMode(br, dec, mb_x); + } + return !dec->br_.eof_; +} + +//------------------------------------------------------------------------------ +// Paragraph 13 + +static const uint8_t + CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { + { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 }, + { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 } + }, + { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 }, + { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + } +}; + +// Paragraph 9.9 + +static const uint8_t kBands[16 + 1] = { + 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, + 0 // extra entry as sentinel +}; + +void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) { + VP8Proba* const proba = &dec->proba_; + int t, b, c, p; + for (t = 0; t < NUM_TYPES; ++t) { + for (b = 0; b < NUM_BANDS; ++b) { + for (c = 0; c < NUM_CTX; ++c) { + for (p = 0; p < NUM_PROBAS; ++p) { + const int v = + VP8GetBit(br, CoeffsUpdateProba[t][b][c][p], "global-header") ? + VP8GetValue(br, 8, "global-header") : + CoeffsProba0[t][b][c][p]; + proba->bands_[t][b].probas_[c][p] = v; + } + } + } + for (b = 0; b < 16 + 1; ++b) { + proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]]; + } + } + dec->use_skip_proba_ = VP8Get(br, "global-header"); + if (dec->use_skip_proba_) { + dec->skip_p_ = VP8GetValue(br, 8, "global-header"); + } +} diff --git a/libraries/webp/src/dec/vp8_dec.c b/libraries/webp/src/dec/vp8_dec.c new file mode 100644 index 00000000000..2ee89006059 --- /dev/null +++ b/libraries/webp/src/dec/vp8_dec.c @@ -0,0 +1,728 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// main entry for the decoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/dec/alphai_dec.h" +#include "src/dec/vp8i_dec.h" +#include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/utils/bit_reader_inl_utils.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ + +int WebPGetDecoderVersion(void) { + return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION; +} + +//------------------------------------------------------------------------------ +// Signature and pointer-to-function for GetCoeffs() variants below. + +typedef int (*GetCoeffsFunc)(VP8BitReader* const br, + const VP8BandProbas* const prob[], + int ctx, const quant_t dq, int n, int16_t* out); +static volatile GetCoeffsFunc GetCoeffs = NULL; + +static void InitGetCoeffs(void); + +//------------------------------------------------------------------------------ +// VP8Decoder + +static void SetOk(VP8Decoder* const dec) { + dec->status_ = VP8_STATUS_OK; + dec->error_msg_ = "OK"; +} + +int VP8InitIoInternal(VP8Io* const io, int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { + return 0; // mismatch error + } + if (io != NULL) { + memset(io, 0, sizeof(*io)); + } + return 1; +} + +VP8Decoder* VP8New(void) { + VP8Decoder* const dec = (VP8Decoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); + if (dec != NULL) { + SetOk(dec); + WebPGetWorkerInterface()->Init(&dec->worker_); + dec->ready_ = 0; + dec->num_parts_minus_one_ = 0; + InitGetCoeffs(); + } + return dec; +} + +VP8StatusCode VP8Status(VP8Decoder* const dec) { + if (!dec) return VP8_STATUS_INVALID_PARAM; + return dec->status_; +} + +const char* VP8StatusMessage(VP8Decoder* const dec) { + if (dec == NULL) return "no object"; + if (!dec->error_msg_) return "OK"; + return dec->error_msg_; +} + +void VP8Delete(VP8Decoder* const dec) { + if (dec != NULL) { + VP8Clear(dec); + WebPSafeFree(dec); + } +} + +int VP8SetError(VP8Decoder* const dec, + VP8StatusCode error, const char* const msg) { + // VP8_STATUS_SUSPENDED is only meaningful in incremental decoding. + assert(dec->incremental_ || error != VP8_STATUS_SUSPENDED); + // The oldest error reported takes precedence over the new one. + if (dec->status_ == VP8_STATUS_OK) { + dec->status_ = error; + dec->error_msg_ = msg; + dec->ready_ = 0; + } + return 0; +} + +//------------------------------------------------------------------------------ + +int VP8CheckSignature(const uint8_t* const data, size_t data_size) { + return (data_size >= 3 && + data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a); +} + +int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size, + int* const width, int* const height) { + if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) { + return 0; // not enough data + } + // check signature + if (!VP8CheckSignature(data + 3, data_size - 3)) { + return 0; // Wrong signature. + } else { + const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16); + const int key_frame = !(bits & 1); + const int w = ((data[7] << 8) | data[6]) & 0x3fff; + const int h = ((data[9] << 8) | data[8]) & 0x3fff; + + if (!key_frame) { // Not a keyframe. + return 0; + } + + if (((bits >> 1) & 7) > 3) { + return 0; // unknown profile + } + if (!((bits >> 4) & 1)) { + return 0; // first frame is invisible! + } + if (((bits >> 5)) >= chunk_size) { // partition_length + return 0; // inconsistent size information. + } + if (w == 0 || h == 0) { + return 0; // We don't support both width and height to be zero. + } + + if (width) { + *width = w; + } + if (height) { + *height = h; + } + + return 1; + } +} + +//------------------------------------------------------------------------------ +// Header parsing + +static void ResetSegmentHeader(VP8SegmentHeader* const hdr) { + assert(hdr != NULL); + hdr->use_segment_ = 0; + hdr->update_map_ = 0; + hdr->absolute_delta_ = 1; + memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_)); + memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_)); +} + +// Paragraph 9.3 +static int ParseSegmentHeader(VP8BitReader* br, + VP8SegmentHeader* hdr, VP8Proba* proba) { + assert(br != NULL); + assert(hdr != NULL); + hdr->use_segment_ = VP8Get(br, "global-header"); + if (hdr->use_segment_) { + hdr->update_map_ = VP8Get(br, "global-header"); + if (VP8Get(br, "global-header")) { // update data + int s; + hdr->absolute_delta_ = VP8Get(br, "global-header"); + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + hdr->quantizer_[s] = VP8Get(br, "global-header") ? + VP8GetSignedValue(br, 7, "global-header") : 0; + } + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + hdr->filter_strength_[s] = VP8Get(br, "global-header") ? + VP8GetSignedValue(br, 6, "global-header") : 0; + } + } + if (hdr->update_map_) { + int s; + for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) { + proba->segments_[s] = VP8Get(br, "global-header") ? + VP8GetValue(br, 8, "global-header") : 255u; + } + } + } else { + hdr->update_map_ = 0; + } + return !br->eof_; +} + +// Paragraph 9.5 +// If we don't have all the necessary data in 'buf', this function returns +// VP8_STATUS_SUSPENDED in incremental decoding, VP8_STATUS_NOT_ENOUGH_DATA +// otherwise. +// In incremental decoding, this case is not necessarily an error. Still, no +// bitreader is ever initialized to make it possible to read unavailable memory. +// If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA +// is returned, and this is an unrecoverable error. +// If the partitions were positioned ok, VP8_STATUS_OK is returned. +static VP8StatusCode ParsePartitions(VP8Decoder* const dec, + const uint8_t* buf, size_t size) { + VP8BitReader* const br = &dec->br_; + const uint8_t* sz = buf; + const uint8_t* buf_end = buf + size; + const uint8_t* part_start; + size_t size_left = size; + size_t last_part; + size_t p; + + dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2, "global-header")) - 1; + last_part = dec->num_parts_minus_one_; + if (size < 3 * last_part) { + // we can't even read the sizes with sz[]! That's a failure. + return VP8_STATUS_NOT_ENOUGH_DATA; + } + part_start = buf + last_part * 3; + size_left -= last_part * 3; + for (p = 0; p < last_part; ++p) { + size_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16); + if (psize > size_left) psize = size_left; + VP8InitBitReader(dec->parts_ + p, part_start, psize); + part_start += psize; + size_left -= psize; + sz += 3; + } + VP8InitBitReader(dec->parts_ + last_part, part_start, size_left); + if (part_start < buf_end) return VP8_STATUS_OK; + return dec->incremental_ + ? VP8_STATUS_SUSPENDED // Init is ok, but there's not enough data + : VP8_STATUS_NOT_ENOUGH_DATA; +} + +// Paragraph 9.4 +static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) { + VP8FilterHeader* const hdr = &dec->filter_hdr_; + hdr->simple_ = VP8Get(br, "global-header"); + hdr->level_ = VP8GetValue(br, 6, "global-header"); + hdr->sharpness_ = VP8GetValue(br, 3, "global-header"); + hdr->use_lf_delta_ = VP8Get(br, "global-header"); + if (hdr->use_lf_delta_) { + if (VP8Get(br, "global-header")) { // update lf-delta? + int i; + for (i = 0; i < NUM_REF_LF_DELTAS; ++i) { + if (VP8Get(br, "global-header")) { + hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header"); + } + } + for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) { + if (VP8Get(br, "global-header")) { + hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header"); + } + } + } + } + dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2; + return !br->eof_; +} + +// Topmost call +int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { + const uint8_t* buf; + size_t buf_size; + VP8FrameHeader* frm_hdr; + VP8PictureHeader* pic_hdr; + VP8BitReader* br; + VP8StatusCode status; + + if (dec == NULL) { + return 0; + } + SetOk(dec); + if (io == NULL) { + return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, + "null VP8Io passed to VP8GetHeaders()"); + } + buf = io->data; + buf_size = io->data_size; + if (buf_size < 4) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "Truncated header."); + } + + // Paragraph 9.1 + { + const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16); + frm_hdr = &dec->frm_hdr_; + frm_hdr->key_frame_ = !(bits & 1); + frm_hdr->profile_ = (bits >> 1) & 7; + frm_hdr->show_ = (bits >> 4) & 1; + frm_hdr->partition_length_ = (bits >> 5); + if (frm_hdr->profile_ > 3) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "Incorrect keyframe parameters."); + } + if (!frm_hdr->show_) { + return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, + "Frame not displayable."); + } + buf += 3; + buf_size -= 3; + } + + pic_hdr = &dec->pic_hdr_; + if (frm_hdr->key_frame_) { + // Paragraph 9.2 + if (buf_size < 7) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "cannot parse picture header"); + } + if (!VP8CheckSignature(buf, buf_size)) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "Bad code word"); + } + pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff; + pic_hdr->xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2 + pic_hdr->height_ = ((buf[6] << 8) | buf[5]) & 0x3fff; + pic_hdr->yscale_ = buf[6] >> 6; + buf += 7; + buf_size -= 7; + + dec->mb_w_ = (pic_hdr->width_ + 15) >> 4; + dec->mb_h_ = (pic_hdr->height_ + 15) >> 4; + + // Setup default output area (can be later modified during io->setup()) + io->width = pic_hdr->width_; + io->height = pic_hdr->height_; + // IMPORTANT! use some sane dimensions in crop_* and scaled_* fields. + // So they can be used interchangeably without always testing for + // 'use_cropping'. + io->use_cropping = 0; + io->crop_top = 0; + io->crop_left = 0; + io->crop_right = io->width; + io->crop_bottom = io->height; + io->use_scaling = 0; + io->scaled_width = io->width; + io->scaled_height = io->height; + + io->mb_w = io->width; // for soundness + io->mb_h = io->height; // ditto + + VP8ResetProba(&dec->proba_); + ResetSegmentHeader(&dec->segment_hdr_); + } + + // Check if we have all the partition #0 available, and initialize dec->br_ + // to read this partition (and this partition only). + if (frm_hdr->partition_length_ > buf_size) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "bad partition length"); + } + + br = &dec->br_; + VP8InitBitReader(br, buf, frm_hdr->partition_length_); + buf += frm_hdr->partition_length_; + buf_size -= frm_hdr->partition_length_; + + if (frm_hdr->key_frame_) { + pic_hdr->colorspace_ = VP8Get(br, "global-header"); + pic_hdr->clamp_type_ = VP8Get(br, "global-header"); + } + if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "cannot parse segment header"); + } + // Filter specs + if (!ParseFilterHeader(br, dec)) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "cannot parse filter header"); + } + status = ParsePartitions(dec, buf, buf_size); + if (status != VP8_STATUS_OK) { + return VP8SetError(dec, status, "cannot parse partitions"); + } + + // quantizer change + VP8ParseQuant(dec); + + // Frame buffer marking + if (!frm_hdr->key_frame_) { + return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, + "Not a key frame."); + } + + VP8Get(br, "global-header"); // ignore the value of update_proba_ + + VP8ParseProba(br, dec); + + // sanitized state + dec->ready_ = 1; + return 1; +} + +//------------------------------------------------------------------------------ +// Residual decoding (Paragraph 13.2 / 13.3) + +static const uint8_t kCat3[] = { 173, 148, 140, 0 }; +static const uint8_t kCat4[] = { 176, 155, 140, 135, 0 }; +static const uint8_t kCat5[] = { 180, 157, 141, 134, 130, 0 }; +static const uint8_t kCat6[] = + { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0 }; +static const uint8_t* const kCat3456[] = { kCat3, kCat4, kCat5, kCat6 }; +static const uint8_t kZigzag[16] = { + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +// See section 13-2: https://datatracker.ietf.org/doc/html/rfc6386#section-13.2 +static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) { + int v; + if (!VP8GetBit(br, p[3], "coeffs")) { + if (!VP8GetBit(br, p[4], "coeffs")) { + v = 2; + } else { + v = 3 + VP8GetBit(br, p[5], "coeffs"); + } + } else { + if (!VP8GetBit(br, p[6], "coeffs")) { + if (!VP8GetBit(br, p[7], "coeffs")) { + v = 5 + VP8GetBit(br, 159, "coeffs"); + } else { + v = 7 + 2 * VP8GetBit(br, 165, "coeffs"); + v += VP8GetBit(br, 145, "coeffs"); + } + } else { + const uint8_t* tab; + const int bit1 = VP8GetBit(br, p[8], "coeffs"); + const int bit0 = VP8GetBit(br, p[9 + bit1], "coeffs"); + const int cat = 2 * bit1 + bit0; + v = 0; + for (tab = kCat3456[cat]; *tab; ++tab) { + v += v + VP8GetBit(br, *tab, "coeffs"); + } + v += 3 + (8 << cat); + } + } + return v; +} + +// Returns the position of the last non-zero coeff plus one +static int GetCoeffsFast(VP8BitReader* const br, + const VP8BandProbas* const prob[], + int ctx, const quant_t dq, int n, int16_t* out) { + const uint8_t* p = prob[n]->probas_[ctx]; + for (; n < 16; ++n) { + if (!VP8GetBit(br, p[0], "coeffs")) { + return n; // previous coeff was last non-zero coeff + } + while (!VP8GetBit(br, p[1], "coeffs")) { // sequence of zero coeffs + p = prob[++n]->probas_[0]; + if (n == 16) return 16; + } + { // non zero coeff + const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; + int v; + if (!VP8GetBit(br, p[2], "coeffs")) { + v = 1; + p = p_ctx[1]; + } else { + v = GetLargeValue(br, p); + p = p_ctx[2]; + } + out[kZigzag[n]] = VP8GetSigned(br, v, "coeffs") * dq[n > 0]; + } + } + return 16; +} + +// This version of GetCoeffs() uses VP8GetBitAlt() which is an alternate version +// of VP8GetBitAlt() targeting specific platforms. +static int GetCoeffsAlt(VP8BitReader* const br, + const VP8BandProbas* const prob[], + int ctx, const quant_t dq, int n, int16_t* out) { + const uint8_t* p = prob[n]->probas_[ctx]; + for (; n < 16; ++n) { + if (!VP8GetBitAlt(br, p[0], "coeffs")) { + return n; // previous coeff was last non-zero coeff + } + while (!VP8GetBitAlt(br, p[1], "coeffs")) { // sequence of zero coeffs + p = prob[++n]->probas_[0]; + if (n == 16) return 16; + } + { // non zero coeff + const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; + int v; + if (!VP8GetBitAlt(br, p[2], "coeffs")) { + v = 1; + p = p_ctx[1]; + } else { + v = GetLargeValue(br, p); + p = p_ctx[2]; + } + out[kZigzag[n]] = VP8GetSigned(br, v, "coeffs") * dq[n > 0]; + } + } + return 16; +} + +extern VP8CPUInfo VP8GetCPUInfo; + +WEBP_DSP_INIT_FUNC(InitGetCoeffs) { + if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) { + GetCoeffs = GetCoeffsAlt; + } else { + GetCoeffs = GetCoeffsFast; + } +} + +static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) { + nz_coeffs <<= 2; + nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz; + return nz_coeffs; +} + +static int ParseResiduals(VP8Decoder* const dec, + VP8MB* const mb, VP8BitReader* const token_br) { + const VP8BandProbas* (* const bands)[16 + 1] = dec->proba_.bands_ptr_; + const VP8BandProbas* const * ac_proba; + VP8MBData* const block = dec->mb_data_ + dec->mb_x_; + const VP8QuantMatrix* const q = &dec->dqm_[block->segment_]; + int16_t* dst = block->coeffs_; + VP8MB* const left_mb = dec->mb_info_ - 1; + uint8_t tnz, lnz; + uint32_t non_zero_y = 0; + uint32_t non_zero_uv = 0; + int x, y, ch; + uint32_t out_t_nz, out_l_nz; + int first; + + memset(dst, 0, 384 * sizeof(*dst)); + if (!block->is_i4x4_) { // parse DC + int16_t dc[16] = { 0 }; + const int ctx = mb->nz_dc_ + left_mb->nz_dc_; + const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat_, 0, dc); + mb->nz_dc_ = left_mb->nz_dc_ = (nz > 0); + if (nz > 1) { // more than just the DC -> perform the full transform + VP8TransformWHT(dc, dst); + } else { // only DC is non-zero -> inlined simplified transform + int i; + const int dc0 = (dc[0] + 3) >> 3; + for (i = 0; i < 16 * 16; i += 16) dst[i] = dc0; + } + first = 1; + ac_proba = bands[0]; + } else { + first = 0; + ac_proba = bands[3]; + } + + tnz = mb->nz_ & 0x0f; + lnz = left_mb->nz_ & 0x0f; + for (y = 0; y < 4; ++y) { + int l = lnz & 1; + uint32_t nz_coeffs = 0; + for (x = 0; x < 4; ++x) { + const int ctx = l + (tnz & 1); + const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat_, first, dst); + l = (nz > first); + tnz = (tnz >> 1) | (l << 7); + nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0); + dst += 16; + } + tnz >>= 4; + lnz = (lnz >> 1) | (l << 7); + non_zero_y = (non_zero_y << 8) | nz_coeffs; + } + out_t_nz = tnz; + out_l_nz = lnz >> 4; + + for (ch = 0; ch < 4; ch += 2) { + uint32_t nz_coeffs = 0; + tnz = mb->nz_ >> (4 + ch); + lnz = left_mb->nz_ >> (4 + ch); + for (y = 0; y < 2; ++y) { + int l = lnz & 1; + for (x = 0; x < 2; ++x) { + const int ctx = l + (tnz & 1); + const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat_, 0, dst); + l = (nz > 0); + tnz = (tnz >> 1) | (l << 3); + nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0); + dst += 16; + } + tnz >>= 2; + lnz = (lnz >> 1) | (l << 5); + } + // Note: we don't really need the per-4x4 details for U/V blocks. + non_zero_uv |= nz_coeffs << (4 * ch); + out_t_nz |= (tnz << 4) << ch; + out_l_nz |= (lnz & 0xf0) << ch; + } + mb->nz_ = out_t_nz; + left_mb->nz_ = out_l_nz; + + block->non_zero_y_ = non_zero_y; + block->non_zero_uv_ = non_zero_uv; + + // We look at the mode-code of each block and check if some blocks have less + // than three non-zero coeffs (code < 2). This is to avoid dithering flat and + // empty blocks. + block->dither_ = (non_zero_uv & 0xaaaa) ? 0 : q->dither_; + + return !(non_zero_y | non_zero_uv); // will be used for further optimization +} + +//------------------------------------------------------------------------------ +// Main loop + +int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) { + VP8MB* const left = dec->mb_info_ - 1; + VP8MB* const mb = dec->mb_info_ + dec->mb_x_; + VP8MBData* const block = dec->mb_data_ + dec->mb_x_; + int skip = dec->use_skip_proba_ ? block->skip_ : 0; + + if (!skip) { + skip = ParseResiduals(dec, mb, token_br); + } else { + left->nz_ = mb->nz_ = 0; + if (!block->is_i4x4_) { + left->nz_dc_ = mb->nz_dc_ = 0; + } + block->non_zero_y_ = 0; + block->non_zero_uv_ = 0; + block->dither_ = 0; + } + + if (dec->filter_type_ > 0) { // store filter info + VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_; + *finfo = dec->fstrengths_[block->segment_][block->is_i4x4_]; + finfo->f_inner_ |= !skip; + } + + return !token_br->eof_; +} + +void VP8InitScanline(VP8Decoder* const dec) { + VP8MB* const left = dec->mb_info_ - 1; + left->nz_ = 0; + left->nz_dc_ = 0; + memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_)); + dec->mb_x_ = 0; +} + +static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { + for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) { + // Parse bitstream for this row. + VP8BitReader* const token_br = + &dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_]; + if (!VP8ParseIntraModeRow(&dec->br_, dec)) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "Premature end-of-partition0 encountered."); + } + for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { + if (!VP8DecodeMB(dec, token_br)) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "Premature end-of-file encountered."); + } + } + VP8InitScanline(dec); // Prepare for next scanline + + // Reconstruct, filter and emit the row. + if (!VP8ProcessRow(dec, io)) { + return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted."); + } + } + if (dec->mt_method_ > 0) { + if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) return 0; + } + + return 1; +} + +// Main entry point +int VP8Decode(VP8Decoder* const dec, VP8Io* const io) { + int ok = 0; + if (dec == NULL) { + return 0; + } + if (io == NULL) { + return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, + "NULL VP8Io parameter in VP8Decode()."); + } + + if (!dec->ready_) { + if (!VP8GetHeaders(dec, io)) { + return 0; + } + } + assert(dec->ready_); + + // Finish setting up the decoding parameter. Will call io->setup(). + ok = (VP8EnterCritical(dec, io) == VP8_STATUS_OK); + if (ok) { // good to go. + // Will allocate memory and prepare everything. + if (ok) ok = VP8InitFrame(dec, io); + + // Main decoding loop + if (ok) ok = ParseFrame(dec, io); + + // Exit. + ok &= VP8ExitCritical(dec, io); + } + + if (!ok) { + VP8Clear(dec); + return 0; + } + + dec->ready_ = 0; + return ok; +} + +void VP8Clear(VP8Decoder* const dec) { + if (dec == NULL) { + return; + } + WebPGetWorkerInterface()->End(&dec->worker_); + WebPDeallocateAlphaMemory(dec); + WebPSafeFree(dec->mem_); + dec->mem_ = NULL; + dec->mem_size_ = 0; + memset(&dec->br_, 0, sizeof(dec->br_)); + dec->ready_ = 0; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dec/vp8_dec.h b/libraries/webp/src/dec/vp8_dec.h new file mode 100644 index 00000000000..c649539cf26 --- /dev/null +++ b/libraries/webp/src/dec/vp8_dec.h @@ -0,0 +1,184 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Low-level API for VP8 decoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DEC_VP8_DEC_H_ +#define WEBP_DEC_VP8_DEC_H_ + +#include "include/webp/decode.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Lower-level API +// +// These functions provide fine-grained control of the decoding process. +// The call flow should resemble: +// +// VP8Io io; +// VP8InitIo(&io); +// io.data = data; +// io.data_size = size; +// /* customize io's functions (setup()/put()/teardown()) if needed. */ +// +// VP8Decoder* dec = VP8New(); +// int ok = VP8Decode(dec, &io); +// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec)); +// VP8Delete(dec); +// return ok; + +// Input / Output +typedef struct VP8Io VP8Io; +typedef int (*VP8IoPutHook)(const VP8Io* io); +typedef int (*VP8IoSetupHook)(VP8Io* io); +typedef void (*VP8IoTeardownHook)(const VP8Io* io); + +struct VP8Io { + // set by VP8GetHeaders() + int width, height; // picture dimensions, in pixels (invariable). + // These are the original, uncropped dimensions. + // The actual area passed to put() is stored + // in mb_w / mb_h fields. + + // set before calling put() + int mb_y; // position of the current rows (in pixels) + int mb_w; // number of columns in the sample + int mb_h; // number of rows in the sample + const uint8_t* y, *u, *v; // rows to copy (in yuv420 format) + int y_stride; // row stride for luma + int uv_stride; // row stride for chroma + + void* opaque; // user data + + // called when fresh samples are available. Currently, samples are in + // YUV420 format, and can be up to width x 24 in size (depending on the + // in-loop filtering level, e.g.). Should return false in case of error + // or abort request. The actual size of the area to update is mb_w x mb_h + // in size, taking cropping into account. + VP8IoPutHook put; + + // called just before starting to decode the blocks. + // Must return false in case of setup error, true otherwise. If false is + // returned, teardown() will NOT be called. But if the setup succeeded + // and true is returned, then teardown() will always be called afterward. + VP8IoSetupHook setup; + + // Called just after block decoding is finished (or when an error occurred + // during put()). Is NOT called if setup() failed. + VP8IoTeardownHook teardown; + + // this is a recommendation for the user-side yuv->rgb converter. This flag + // is set when calling setup() hook and can be overwritten by it. It then + // can be taken into consideration during the put() method. + int fancy_upsampling; + + // Input buffer. + size_t data_size; + const uint8_t* data; + + // If true, in-loop filtering will not be performed even if present in the + // bitstream. Switching off filtering may speed up decoding at the expense + // of more visible blocking. Note that output will also be non-compliant + // with the VP8 specifications. + int bypass_filtering; + + // Cropping parameters. + int use_cropping; + int crop_left, crop_right, crop_top, crop_bottom; + + // Scaling parameters. + int use_scaling; + int scaled_width, scaled_height; + + // If non NULL, pointer to the alpha data (if present) corresponding to the + // start of the current row (That is: it is pre-offset by mb_y and takes + // cropping into account). + const uint8_t* a; +}; + +// Internal, version-checked, entry point +WEBP_NODISCARD int VP8InitIoInternal(VP8Io* const, int); + +// Set the custom IO function pointers and user-data. The setter for IO hooks +// should be called before initiating incremental decoding. Returns true if +// WebPIDecoder object is successfully modified, false otherwise. +WEBP_NODISCARD int WebPISetIOHooks(WebPIDecoder* const idec, VP8IoPutHook put, + VP8IoSetupHook setup, + VP8IoTeardownHook teardown, void* user_data); + +// Main decoding object. This is an opaque structure. +typedef struct VP8Decoder VP8Decoder; + +// Create a new decoder object. +VP8Decoder* VP8New(void); + +// Must be called to make sure 'io' is initialized properly. +// Returns false in case of version mismatch. Upon such failure, no other +// decoding function should be called (VP8Decode, VP8GetHeaders, ...) +WEBP_NODISCARD static WEBP_INLINE int VP8InitIo(VP8Io* const io) { + return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION); +} + +// Decode the VP8 frame header. Returns true if ok. +// Note: 'io->data' must be pointing to the start of the VP8 frame header. +WEBP_NODISCARD int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io); + +// Decode a picture. Will call VP8GetHeaders() if it wasn't done already. +// Returns false in case of error. +WEBP_NODISCARD int VP8Decode(VP8Decoder* const dec, VP8Io* const io); + +// Return current status of the decoder: +VP8StatusCode VP8Status(VP8Decoder* const dec); + +// return readable string corresponding to the last status. +const char* VP8StatusMessage(VP8Decoder* const dec); + +// Resets the decoder in its initial state, reclaiming memory. +// Not a mandatory call between calls to VP8Decode(). +void VP8Clear(VP8Decoder* const dec); + +// Destroy the decoder object. +void VP8Delete(VP8Decoder* const dec); + +//------------------------------------------------------------------------------ +// Miscellaneous VP8/VP8L bitstream probing functions. + +// Returns true if the next 3 bytes in data contain the VP8 signature. +WEBP_EXTERN int VP8CheckSignature(const uint8_t* const data, size_t data_size); + +// Validates the VP8 data-header and retrieves basic header information viz +// width and height. Returns 0 in case of formatting error. *width/*height +// can be passed NULL. +WEBP_EXTERN int VP8GetInfo( + const uint8_t* data, + size_t data_size, // data available so far + size_t chunk_size, // total data size expected in the chunk + int* const width, int* const height); + +// Returns true if the next byte(s) in data is a VP8L signature. +WEBP_EXTERN int VP8LCheckSignature(const uint8_t* const data, size_t size); + +// Validates the VP8L data-header and retrieves basic header information viz +// width, height and alpha. Returns 0 in case of formatting error. +// width/height/has_alpha can be passed NULL. +WEBP_EXTERN int VP8LGetInfo( + const uint8_t* data, size_t data_size, // data available so far + int* const width, int* const height, int* const has_alpha); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DEC_VP8_DEC_H_ diff --git a/libraries/webp/src/dec/vp8i_dec.h b/libraries/webp/src/dec/vp8i_dec.h new file mode 100644 index 00000000000..e46bf50f101 --- /dev/null +++ b/libraries/webp/src/dec/vp8i_dec.h @@ -0,0 +1,322 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// VP8 decoder: internal header. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DEC_VP8I_DEC_H_ +#define WEBP_DEC_VP8I_DEC_H_ + +#include // for memcpy() +#include "src/dec/common_dec.h" +#include "src/dec/vp8li_dec.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/random_utils.h" +#include "src/utils/thread_utils.h" +#include "src/dsp/dsp.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Various defines and enums + +// version numbers +#define DEC_MAJ_VERSION 1 +#define DEC_MIN_VERSION 3 +#define DEC_REV_VERSION 2 + +// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). +// Constraints are: We need to store one 16x16 block of luma samples (y), +// and two 8x8 chroma blocks (u/v). These are better be 16-bytes aligned, +// in order to be SIMD-friendly. We also need to store the top, left and +// top-left samples (from previously decoded blocks), along with four +// extra top-right samples for luma (intra4x4 prediction only). +// One possible layout is, using 32 * (17 + 9) bytes: +// +// .+------ <- only 1 pixel high +// .|yyyyt. +// .|yyyyt. +// .|yyyyt. +// .|yyyy.. +// .+--.+-- <- only 1 pixel high +// .|uu.|vv +// .|uu.|vv +// +// Every character is a 4x4 block, with legend: +// '.' = unused +// 'y' = y-samples 'u' = u-samples 'v' = u-samples +// '|' = left sample, '-' = top sample, '+' = top-left sample +// 't' = extra top-right sample for 4x4 modes +#define YUV_SIZE (BPS * 17 + BPS * 9) +#define Y_OFF (BPS * 1 + 8) +#define U_OFF (Y_OFF + BPS * 16 + BPS) +#define V_OFF (U_OFF + 16) + +// minimal width under which lossy multi-threading is always disabled +#define MIN_WIDTH_FOR_THREADS 512 + +//------------------------------------------------------------------------------ +// Headers + +typedef struct { + uint8_t key_frame_; + uint8_t profile_; + uint8_t show_; + uint32_t partition_length_; +} VP8FrameHeader; + +typedef struct { + uint16_t width_; + uint16_t height_; + uint8_t xscale_; + uint8_t yscale_; + uint8_t colorspace_; // 0 = YCbCr + uint8_t clamp_type_; +} VP8PictureHeader; + +// segment features +typedef struct { + int use_segment_; + int update_map_; // whether to update the segment map or not + int absolute_delta_; // absolute or delta values for quantizer and filter + int8_t quantizer_[NUM_MB_SEGMENTS]; // quantization changes + int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments +} VP8SegmentHeader; + +// probas associated to one of the contexts +typedef uint8_t VP8ProbaArray[NUM_PROBAS]; + +typedef struct { // all the probas associated to one band + VP8ProbaArray probas_[NUM_CTX]; +} VP8BandProbas; + +// Struct collecting all frame-persistent probabilities. +typedef struct { + uint8_t segments_[MB_FEATURE_TREE_PROBS]; + // Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4 + VP8BandProbas bands_[NUM_TYPES][NUM_BANDS]; + const VP8BandProbas* bands_ptr_[NUM_TYPES][16 + 1]; +} VP8Proba; + +// Filter parameters +typedef struct { + int simple_; // 0=complex, 1=simple + int level_; // [0..63] + int sharpness_; // [0..7] + int use_lf_delta_; + int ref_lf_delta_[NUM_REF_LF_DELTAS]; + int mode_lf_delta_[NUM_MODE_LF_DELTAS]; +} VP8FilterHeader; + +//------------------------------------------------------------------------------ +// Informations about the macroblocks. + +typedef struct { // filter specs + uint8_t f_limit_; // filter limit in [3..189], or 0 if no filtering + uint8_t f_ilevel_; // inner limit in [1..63] + uint8_t f_inner_; // do inner filtering? + uint8_t hev_thresh_; // high edge variance threshold in [0..2] +} VP8FInfo; + +typedef struct { // Top/Left Contexts used for syntax-parsing + uint8_t nz_; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma) + uint8_t nz_dc_; // non-zero DC coeff (1bit) +} VP8MB; + +// Dequantization matrices +typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower). +typedef struct { + quant_t y1_mat_, y2_mat_, uv_mat_; + + int uv_quant_; // U/V quantizer value + int dither_; // dithering amplitude (0 = off, max=255) +} VP8QuantMatrix; + +// Data needed to reconstruct a macroblock +typedef struct { + int16_t coeffs_[384]; // 384 coeffs = (16+4+4) * 4*4 + uint8_t is_i4x4_; // true if intra4x4 + uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes + uint8_t uvmode_; // chroma prediction mode + // bit-wise info about the content of each sub-4x4 blocks (in decoding order). + // Each of the 4x4 blocks for y/u/v is associated with a 2b code according to: + // code=0 -> no coefficient + // code=1 -> only DC + // code=2 -> first three coefficients are non-zero + // code=3 -> more than three coefficients are non-zero + // This allows to call specialized transform functions. + uint32_t non_zero_y_; + uint32_t non_zero_uv_; + uint8_t dither_; // local dithering strength (deduced from non_zero_*) + uint8_t skip_; + uint8_t segment_; +} VP8MBData; + +// Persistent information needed by the parallel processing +typedef struct { + int id_; // cache row to process (in [0..2]) + int mb_y_; // macroblock position of the row + int filter_row_; // true if row-filtering is needed + VP8FInfo* f_info_; // filter strengths (swapped with dec->f_info_) + VP8MBData* mb_data_; // reconstruction data (swapped with dec->mb_data_) + VP8Io io_; // copy of the VP8Io to pass to put() +} VP8ThreadContext; + +// Saved top samples, per macroblock. Fits into a cache-line. +typedef struct { + uint8_t y[16], u[8], v[8]; +} VP8TopSamples; + +//------------------------------------------------------------------------------ +// VP8Decoder: the main opaque structure handed over to user + +struct VP8Decoder { + VP8StatusCode status_; + int ready_; // true if ready to decode a picture with VP8Decode() + const char* error_msg_; // set when status_ is not OK. + + // Main data source + VP8BitReader br_; + int incremental_; // if true, incremental decoding is expected + + // headers + VP8FrameHeader frm_hdr_; + VP8PictureHeader pic_hdr_; + VP8FilterHeader filter_hdr_; + VP8SegmentHeader segment_hdr_; + + // Worker + WebPWorker worker_; + int mt_method_; // multi-thread method: 0=off, 1=[parse+recon][filter] + // 2=[parse][recon+filter] + int cache_id_; // current cache row + int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3) + VP8ThreadContext thread_ctx_; // Thread context + + // dimension, in macroblock units. + int mb_w_, mb_h_; + + // Macroblock to process/filter, depending on cropping and filter_type. + int tl_mb_x_, tl_mb_y_; // top-left MB that must be in-loop filtered + int br_mb_x_, br_mb_y_; // last bottom-right MB that must be decoded + + // number of partitions minus one. + uint32_t num_parts_minus_one_; + // per-partition boolean decoders. + VP8BitReader parts_[MAX_NUM_PARTITIONS]; + + // Dithering strength, deduced from decoding options + int dither_; // whether to use dithering or not + VP8Random dithering_rg_; // random generator for dithering + + // dequantization (one set of DC/AC dequant factor per segment) + VP8QuantMatrix dqm_[NUM_MB_SEGMENTS]; + + // probabilities + VP8Proba proba_; + int use_skip_proba_; + uint8_t skip_p_; + + // Boundary data cache and persistent buffers. + uint8_t* intra_t_; // top intra modes values: 4 * mb_w_ + uint8_t intra_l_[4]; // left intra modes values + + VP8TopSamples* yuv_t_; // top y/u/v samples + + VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1) + VP8FInfo* f_info_; // filter strength info + uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE) + + uint8_t* cache_y_; // macroblock row for storing unfiltered samples + uint8_t* cache_u_; + uint8_t* cache_v_; + int cache_y_stride_; + int cache_uv_stride_; + + // main memory chunk for the above data. Persistent. + void* mem_; + size_t mem_size_; + + // Per macroblock non-persistent infos. + int mb_x_, mb_y_; // current position, in macroblock units + VP8MBData* mb_data_; // parsed reconstruction data + + // Filtering side-info + int filter_type_; // 0=off, 1=simple, 2=complex + VP8FInfo fstrengths_[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type + + // Alpha + struct ALPHDecoder* alph_dec_; // alpha-plane decoder object + const uint8_t* alpha_data_; // compressed alpha data (if present) + size_t alpha_data_size_; + int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_ + uint8_t* alpha_plane_mem_; // memory allocated for alpha_plane_ + uint8_t* alpha_plane_; // output. Persistent, contains the whole data. + const uint8_t* alpha_prev_line_; // last decoded alpha row (or NULL) + int alpha_dithering_; // derived from decoding options (0=off, 100=full) +}; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + +// in vp8.c +int VP8SetError(VP8Decoder* const dec, + VP8StatusCode error, const char* const msg); + +// in tree.c +void VP8ResetProba(VP8Proba* const proba); +void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec); +// parses one row of intra mode data in partition 0, returns !eof +int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec); + +// in quant.c +void VP8ParseQuant(VP8Decoder* const dec); + +// in frame.c +WEBP_NODISCARD int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io); +// Call io->setup() and finish setting up scan parameters. +// After this call returns, one must always call VP8ExitCritical() with the +// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK +// if ok, otherwise sets and returns the error status on *dec. +VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io); +// Must always be called in pair with VP8EnterCritical(). +// Returns false in case of error. +WEBP_NODISCARD int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io); +// Return the multi-threading method to use (0=off), depending +// on options and bitstream size. Only for lossy decoding. +int VP8GetThreadMethod(const WebPDecoderOptions* const options, + const WebPHeaderStructure* const headers, + int width, int height); +// Initialize dithering post-process if needed. +void VP8InitDithering(const WebPDecoderOptions* const options, + VP8Decoder* const dec); +// Process the last decoded row (filtering + output). +WEBP_NODISCARD int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io); +// To be called at the start of a new scanline, to initialize predictors. +void VP8InitScanline(VP8Decoder* const dec); +// Decode one macroblock. Returns false if there is not enough data. +WEBP_NODISCARD int VP8DecodeMB(VP8Decoder* const dec, + VP8BitReader* const token_br); + +// in alpha.c +const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, + const VP8Io* const io, + int row, int num_rows); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DEC_VP8I_DEC_H_ diff --git a/libraries/webp/src/dec/vp8l_dec.c b/libraries/webp/src/dec/vp8l_dec.c new file mode 100644 index 00000000000..11c00ea964a --- /dev/null +++ b/libraries/webp/src/dec/vp8l_dec.c @@ -0,0 +1,1778 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// main entry for the decoder +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) + +#include +#include + +#include "src/dec/alphai_dec.h" +#include "src/dec/vp8li_dec.h" +#include "src/dsp/dsp.h" +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" +#include "src/dsp/yuv.h" +#include "src/utils/endian_inl_utils.h" +#include "src/utils/huffman_utils.h" +#include "src/utils/utils.h" + +#define NUM_ARGB_CACHE_ROWS 16 + +static const int kCodeLengthLiterals = 16; +static const int kCodeLengthRepeatCode = 16; +static const uint8_t kCodeLengthExtraBits[3] = { 2, 3, 7 }; +static const uint8_t kCodeLengthRepeatOffsets[3] = { 3, 3, 11 }; + +// ----------------------------------------------------------------------------- +// Five Huffman codes are used at each meta code: +// 1. green + length prefix codes + color cache codes, +// 2. alpha, +// 3. red, +// 4. blue, and, +// 5. distance prefix codes. +typedef enum { + GREEN = 0, + RED = 1, + BLUE = 2, + ALPHA = 3, + DIST = 4 +} HuffIndex; + +static const uint16_t kAlphabetSize[HUFFMAN_CODES_PER_META_CODE] = { + NUM_LITERAL_CODES + NUM_LENGTH_CODES, + NUM_LITERAL_CODES, NUM_LITERAL_CODES, NUM_LITERAL_CODES, + NUM_DISTANCE_CODES +}; + +static const uint8_t kLiteralMap[HUFFMAN_CODES_PER_META_CODE] = { + 0, 1, 1, 1, 0 +}; + +#define NUM_CODE_LENGTH_CODES 19 +static const uint8_t kCodeLengthCodeOrder[NUM_CODE_LENGTH_CODES] = { + 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +#define CODE_TO_PLANE_CODES 120 +static const uint8_t kCodeToPlane[CODE_TO_PLANE_CODES] = { + 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a, + 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a, + 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b, + 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03, + 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c, + 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e, + 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b, + 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f, + 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b, + 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41, + 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f, + 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70 +}; + +// Memory needed for lookup tables of one Huffman tree group. Red, blue, alpha +// and distance alphabets are constant (256 for red, blue and alpha, 40 for +// distance) and lookup table sizes for them in worst case are 630 and 410 +// respectively. Size of green alphabet depends on color cache size and is equal +// to 256 (green component values) + 24 (length prefix values) +// + color_cache_size (between 0 and 2048). +// All values computed for 8-bit first level lookup with Mark Adler's tool: +// https://github.com/madler/zlib/blob/v1.2.5/examples/enough.c +#define FIXED_TABLE_SIZE (630 * 3 + 410) +static const uint16_t kTableSize[12] = { + FIXED_TABLE_SIZE + 654, + FIXED_TABLE_SIZE + 656, + FIXED_TABLE_SIZE + 658, + FIXED_TABLE_SIZE + 662, + FIXED_TABLE_SIZE + 670, + FIXED_TABLE_SIZE + 686, + FIXED_TABLE_SIZE + 718, + FIXED_TABLE_SIZE + 782, + FIXED_TABLE_SIZE + 912, + FIXED_TABLE_SIZE + 1168, + FIXED_TABLE_SIZE + 1680, + FIXED_TABLE_SIZE + 2704 +}; + +static int VP8LSetError(VP8LDecoder* const dec, VP8StatusCode error) { + // The oldest error reported takes precedence over the new one. + if (dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED) { + dec->status_ = error; + } + return 0; +} + +static int DecodeImageStream(int xsize, int ysize, + int is_level0, + VP8LDecoder* const dec, + uint32_t** const decoded_data); + +//------------------------------------------------------------------------------ + +int VP8LCheckSignature(const uint8_t* const data, size_t size) { + return (size >= VP8L_FRAME_HEADER_SIZE && + data[0] == VP8L_MAGIC_BYTE && + (data[4] >> 5) == 0); // version +} + +static int ReadImageInfo(VP8LBitReader* const br, + int* const width, int* const height, + int* const has_alpha) { + if (VP8LReadBits(br, 8) != VP8L_MAGIC_BYTE) return 0; + *width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; + *height = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; + *has_alpha = VP8LReadBits(br, 1); + if (VP8LReadBits(br, VP8L_VERSION_BITS) != 0) return 0; + return !br->eos_; +} + +int VP8LGetInfo(const uint8_t* data, size_t data_size, + int* const width, int* const height, int* const has_alpha) { + if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) { + return 0; // not enough data + } else if (!VP8LCheckSignature(data, data_size)) { + return 0; // bad signature + } else { + int w, h, a; + VP8LBitReader br; + VP8LInitBitReader(&br, data, data_size); + if (!ReadImageInfo(&br, &w, &h, &a)) { + return 0; + } + if (width != NULL) *width = w; + if (height != NULL) *height = h; + if (has_alpha != NULL) *has_alpha = a; + return 1; + } +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE int GetCopyDistance(int distance_symbol, + VP8LBitReader* const br) { + int extra_bits, offset; + if (distance_symbol < 4) { + return distance_symbol + 1; + } + extra_bits = (distance_symbol - 2) >> 1; + offset = (2 + (distance_symbol & 1)) << extra_bits; + return offset + VP8LReadBits(br, extra_bits) + 1; +} + +static WEBP_INLINE int GetCopyLength(int length_symbol, + VP8LBitReader* const br) { + // Length and distance prefixes are encoded the same way. + return GetCopyDistance(length_symbol, br); +} + +static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) { + if (plane_code > CODE_TO_PLANE_CODES) { + return plane_code - CODE_TO_PLANE_CODES; + } else { + const int dist_code = kCodeToPlane[plane_code - 1]; + const int yoffset = dist_code >> 4; + const int xoffset = 8 - (dist_code & 0xf); + const int dist = yoffset * xsize + xoffset; + return (dist >= 1) ? dist : 1; // dist<1 can happen if xsize is very small + } +} + +//------------------------------------------------------------------------------ +// Decodes the next Huffman code from bit-stream. +// VP8LFillBitWindow(br) needs to be called at minimum every second call +// to ReadSymbol, in order to pre-fetch enough bits. +static WEBP_INLINE int ReadSymbol(const HuffmanCode* table, + VP8LBitReader* const br) { + int nbits; + uint32_t val = VP8LPrefetchBits(br); + table += val & HUFFMAN_TABLE_MASK; + nbits = table->bits - HUFFMAN_TABLE_BITS; + if (nbits > 0) { + VP8LSetBitPos(br, br->bit_pos_ + HUFFMAN_TABLE_BITS); + val = VP8LPrefetchBits(br); + table += table->value; + table += val & ((1 << nbits) - 1); + } + VP8LSetBitPos(br, br->bit_pos_ + table->bits); + return table->value; +} + +// Reads packed symbol depending on GREEN channel +#define BITS_SPECIAL_MARKER 0x100 // something large enough (and a bit-mask) +#define PACKED_NON_LITERAL_CODE 0 // must be < NUM_LITERAL_CODES +static WEBP_INLINE int ReadPackedSymbols(const HTreeGroup* group, + VP8LBitReader* const br, + uint32_t* const dst) { + const uint32_t val = VP8LPrefetchBits(br) & (HUFFMAN_PACKED_TABLE_SIZE - 1); + const HuffmanCode32 code = group->packed_table[val]; + assert(group->use_packed_table); + if (code.bits < BITS_SPECIAL_MARKER) { + VP8LSetBitPos(br, br->bit_pos_ + code.bits); + *dst = code.value; + return PACKED_NON_LITERAL_CODE; + } else { + VP8LSetBitPos(br, br->bit_pos_ + code.bits - BITS_SPECIAL_MARKER); + assert(code.value >= NUM_LITERAL_CODES); + return code.value; + } +} + +static int AccumulateHCode(HuffmanCode hcode, int shift, + HuffmanCode32* const huff) { + huff->bits += hcode.bits; + huff->value |= (uint32_t)hcode.value << shift; + assert(huff->bits <= HUFFMAN_TABLE_BITS); + return hcode.bits; +} + +static void BuildPackedTable(HTreeGroup* const htree_group) { + uint32_t code; + for (code = 0; code < HUFFMAN_PACKED_TABLE_SIZE; ++code) { + uint32_t bits = code; + HuffmanCode32* const huff = &htree_group->packed_table[bits]; + HuffmanCode hcode = htree_group->htrees[GREEN][bits]; + if (hcode.value >= NUM_LITERAL_CODES) { + huff->bits = hcode.bits + BITS_SPECIAL_MARKER; + huff->value = hcode.value; + } else { + huff->bits = 0; + huff->value = 0; + bits >>= AccumulateHCode(hcode, 8, huff); + bits >>= AccumulateHCode(htree_group->htrees[RED][bits], 16, huff); + bits >>= AccumulateHCode(htree_group->htrees[BLUE][bits], 0, huff); + bits >>= AccumulateHCode(htree_group->htrees[ALPHA][bits], 24, huff); + (void)bits; + } + } +} + +static int ReadHuffmanCodeLengths( + VP8LDecoder* const dec, const int* const code_length_code_lengths, + int num_symbols, int* const code_lengths) { + int ok = 0; + VP8LBitReader* const br = &dec->br_; + int symbol; + int max_symbol; + int prev_code_len = DEFAULT_CODE_LENGTH; + HuffmanTables tables; + + if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) || + !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS, + code_length_code_lengths, NUM_CODE_LENGTH_CODES)) { + goto End; + } + + if (VP8LReadBits(br, 1)) { // use length + const int length_nbits = 2 + 2 * VP8LReadBits(br, 3); + max_symbol = 2 + VP8LReadBits(br, length_nbits); + if (max_symbol > num_symbols) { + goto End; + } + } else { + max_symbol = num_symbols; + } + + symbol = 0; + while (symbol < num_symbols) { + const HuffmanCode* p; + int code_len; + if (max_symbol-- == 0) break; + VP8LFillBitWindow(br); + p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; + VP8LSetBitPos(br, br->bit_pos_ + p->bits); + code_len = p->value; + if (code_len < kCodeLengthLiterals) { + code_lengths[symbol++] = code_len; + if (code_len != 0) prev_code_len = code_len; + } else { + const int use_prev = (code_len == kCodeLengthRepeatCode); + const int slot = code_len - kCodeLengthLiterals; + const int extra_bits = kCodeLengthExtraBits[slot]; + const int repeat_offset = kCodeLengthRepeatOffsets[slot]; + int repeat = VP8LReadBits(br, extra_bits) + repeat_offset; + if (symbol + repeat > num_symbols) { + goto End; + } else { + const int length = use_prev ? prev_code_len : 0; + while (repeat-- > 0) code_lengths[symbol++] = length; + } + } + } + ok = 1; + + End: + VP8LHuffmanTablesDeallocate(&tables); + if (!ok) return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); + return ok; +} + +// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman +// tree. +static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, + int* const code_lengths, + HuffmanTables* const table) { + int ok = 0; + int size = 0; + VP8LBitReader* const br = &dec->br_; + const int simple_code = VP8LReadBits(br, 1); + + memset(code_lengths, 0, alphabet_size * sizeof(*code_lengths)); + + if (simple_code) { // Read symbols, codes & code lengths directly. + const int num_symbols = VP8LReadBits(br, 1) + 1; + const int first_symbol_len_code = VP8LReadBits(br, 1); + // The first code is either 1 bit or 8 bit code. + int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8); + code_lengths[symbol] = 1; + // The second code (if present), is always 8 bits long. + if (num_symbols == 2) { + symbol = VP8LReadBits(br, 8); + code_lengths[symbol] = 1; + } + ok = 1; + } else { // Decode Huffman-coded code lengths. + int i; + int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 }; + const int num_codes = VP8LReadBits(br, 4) + 4; + assert(num_codes <= NUM_CODE_LENGTH_CODES); + + for (i = 0; i < num_codes; ++i) { + code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3); + } + ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size, + code_lengths); + } + + ok = ok && !br->eos_; + if (ok) { + size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS, + code_lengths, alphabet_size); + } + if (!ok || size == 0) { + return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); + } + return size; +} + +static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, + int color_cache_bits, int allow_recursion) { + int i; + VP8LBitReader* const br = &dec->br_; + VP8LMetadata* const hdr = &dec->hdr_; + uint32_t* huffman_image = NULL; + HTreeGroup* htree_groups = NULL; + HuffmanTables* huffman_tables = &hdr->huffman_tables_; + int num_htree_groups = 1; + int num_htree_groups_max = 1; + int* mapping = NULL; + int ok = 0; + + // Check the table has been 0 initialized (through InitMetadata). + assert(huffman_tables->root.start == NULL); + assert(huffman_tables->curr_segment == NULL); + + if (allow_recursion && VP8LReadBits(br, 1)) { + // use meta Huffman codes. + const int huffman_precision = VP8LReadBits(br, 3) + 2; + const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision); + const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision); + const int huffman_pixs = huffman_xsize * huffman_ysize; + if (!DecodeImageStream(huffman_xsize, huffman_ysize, /*is_level0=*/0, dec, + &huffman_image)) { + goto Error; + } + hdr->huffman_subsample_bits_ = huffman_precision; + for (i = 0; i < huffman_pixs; ++i) { + // The huffman data is stored in red and green bytes. + const int group = (huffman_image[i] >> 8) & 0xffff; + huffman_image[i] = group; + if (group >= num_htree_groups_max) { + num_htree_groups_max = group + 1; + } + } + // Check the validity of num_htree_groups_max. If it seems too big, use a + // smaller value for later. This will prevent big memory allocations to end + // up with a bad bitstream anyway. + // The value of 1000 is totally arbitrary. We know that num_htree_groups_max + // is smaller than (1 << 16) and should be smaller than the number of pixels + // (though the format allows it to be bigger). + if (num_htree_groups_max > 1000 || num_htree_groups_max > xsize * ysize) { + // Create a mapping from the used indices to the minimal set of used + // values [0, num_htree_groups) + mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping)); + if (mapping == NULL) { + VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + goto Error; + } + // -1 means a value is unmapped, and therefore unused in the Huffman + // image. + memset(mapping, 0xff, num_htree_groups_max * sizeof(*mapping)); + for (num_htree_groups = 0, i = 0; i < huffman_pixs; ++i) { + // Get the current mapping for the group and remap the Huffman image. + int* const mapped_group = &mapping[huffman_image[i]]; + if (*mapped_group == -1) *mapped_group = num_htree_groups++; + huffman_image[i] = *mapped_group; + } + } else { + num_htree_groups = num_htree_groups_max; + } + } + + if (br->eos_) goto Error; + + if (!ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups, + num_htree_groups_max, mapping, dec, + huffman_tables, &htree_groups)) { + goto Error; + } + ok = 1; + + // All OK. Finalize pointers. + hdr->huffman_image_ = huffman_image; + hdr->num_htree_groups_ = num_htree_groups; + hdr->htree_groups_ = htree_groups; + + Error: + WebPSafeFree(mapping); + if (!ok) { + WebPSafeFree(huffman_image); + VP8LHuffmanTablesDeallocate(huffman_tables); + VP8LHtreeGroupsFree(htree_groups); + } + return ok; +} + +int ReadHuffmanCodesHelper(int color_cache_bits, int num_htree_groups, + int num_htree_groups_max, const int* const mapping, + VP8LDecoder* const dec, + HuffmanTables* const huffman_tables, + HTreeGroup** const htree_groups) { + int i, j, ok = 0; + const int max_alphabet_size = + kAlphabetSize[0] + ((color_cache_bits > 0) ? 1 << color_cache_bits : 0); + const int table_size = kTableSize[color_cache_bits]; + int* code_lengths = NULL; + + if ((mapping == NULL && num_htree_groups != num_htree_groups_max) || + num_htree_groups > num_htree_groups_max) { + goto Error; + } + + code_lengths = + (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, sizeof(*code_lengths)); + *htree_groups = VP8LHtreeGroupsNew(num_htree_groups); + + if (*htree_groups == NULL || code_lengths == NULL || + !VP8LHuffmanTablesAllocate(num_htree_groups * table_size, + huffman_tables)) { + VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + goto Error; + } + + for (i = 0; i < num_htree_groups_max; ++i) { + // If the index "i" is unused in the Huffman image, just make sure the + // coefficients are valid but do not store them. + if (mapping != NULL && mapping[i] == -1) { + for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { + int alphabet_size = kAlphabetSize[j]; + if (j == 0 && color_cache_bits > 0) { + alphabet_size += (1 << color_cache_bits); + } + // Passing in NULL so that nothing gets filled. + if (!ReadHuffmanCode(alphabet_size, dec, code_lengths, NULL)) { + goto Error; + } + } + } else { + HTreeGroup* const htree_group = + &(*htree_groups)[(mapping == NULL) ? i : mapping[i]]; + HuffmanCode** const htrees = htree_group->htrees; + int size; + int total_size = 0; + int is_trivial_literal = 1; + int max_bits = 0; + for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { + int alphabet_size = kAlphabetSize[j]; + if (j == 0 && color_cache_bits > 0) { + alphabet_size += (1 << color_cache_bits); + } + size = + ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables); + htrees[j] = huffman_tables->curr_segment->curr_table; + if (size == 0) { + goto Error; + } + if (is_trivial_literal && kLiteralMap[j] == 1) { + is_trivial_literal = (htrees[j]->bits == 0); + } + total_size += htrees[j]->bits; + huffman_tables->curr_segment->curr_table += size; + if (j <= ALPHA) { + int local_max_bits = code_lengths[0]; + int k; + for (k = 1; k < alphabet_size; ++k) { + if (code_lengths[k] > local_max_bits) { + local_max_bits = code_lengths[k]; + } + } + max_bits += local_max_bits; + } + } + htree_group->is_trivial_literal = is_trivial_literal; + htree_group->is_trivial_code = 0; + if (is_trivial_literal) { + const int red = htrees[RED][0].value; + const int blue = htrees[BLUE][0].value; + const int alpha = htrees[ALPHA][0].value; + htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue; + if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) { + htree_group->is_trivial_code = 1; + htree_group->literal_arb |= htrees[GREEN][0].value << 8; + } + } + htree_group->use_packed_table = + !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS); + if (htree_group->use_packed_table) BuildPackedTable(htree_group); + } + } + ok = 1; + + Error: + WebPSafeFree(code_lengths); + if (!ok) { + VP8LHuffmanTablesDeallocate(huffman_tables); + VP8LHtreeGroupsFree(*htree_groups); + *htree_groups = NULL; + } + return ok; +} + +//------------------------------------------------------------------------------ +// Scaling. + +#if !defined(WEBP_REDUCE_SIZE) +static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) { + const int num_channels = 4; + const int in_width = io->mb_w; + const int out_width = io->scaled_width; + const int in_height = io->mb_h; + const int out_height = io->scaled_height; + const uint64_t work_size = 2 * num_channels * (uint64_t)out_width; + rescaler_t* work; // Rescaler work area. + const uint64_t scaled_data_size = (uint64_t)out_width; + uint32_t* scaled_data; // Temporary storage for scaled BGRA data. + const uint64_t memory_size = sizeof(*dec->rescaler) + + work_size * sizeof(*work) + + scaled_data_size * sizeof(*scaled_data); + uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory)); + if (memory == NULL) { + return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + } + assert(dec->rescaler_memory == NULL); + dec->rescaler_memory = memory; + + dec->rescaler = (WebPRescaler*)memory; + memory += sizeof(*dec->rescaler); + work = (rescaler_t*)memory; + memory += work_size * sizeof(*work); + scaled_data = (uint32_t*)memory; + + if (!WebPRescalerInit(dec->rescaler, in_width, in_height, + (uint8_t*)scaled_data, out_width, out_height, + 0, num_channels, work)) { + return 0; + } + return 1; +} +#endif // WEBP_REDUCE_SIZE + +//------------------------------------------------------------------------------ +// Export to ARGB + +#if !defined(WEBP_REDUCE_SIZE) + +// We have special "export" function since we need to convert from BGRA +static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace, + int rgba_stride, uint8_t* const rgba) { + uint32_t* const src = (uint32_t*)rescaler->dst; + uint8_t* dst = rgba; + const int dst_width = rescaler->dst_width; + int num_lines_out = 0; + while (WebPRescalerHasPendingOutput(rescaler)) { + WebPRescalerExportRow(rescaler); + WebPMultARGBRow(src, dst_width, 1); + VP8LConvertFromBGRA(src, dst_width, colorspace, dst); + dst += rgba_stride; + ++num_lines_out; + } + return num_lines_out; +} + +// Emit scaled rows. +static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec, + uint8_t* in, int in_stride, int mb_h, + uint8_t* const out, int out_stride) { + const WEBP_CSP_MODE colorspace = dec->output_->colorspace; + int num_lines_in = 0; + int num_lines_out = 0; + while (num_lines_in < mb_h) { + uint8_t* const row_in = in + (uint64_t)num_lines_in * in_stride; + uint8_t* const row_out = out + (uint64_t)num_lines_out * out_stride; + const int lines_left = mb_h - num_lines_in; + const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); + int lines_imported; + assert(needed_lines > 0 && needed_lines <= lines_left); + WebPMultARGBRows(row_in, in_stride, + dec->rescaler->src_width, needed_lines, 0); + lines_imported = + WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride); + assert(lines_imported == needed_lines); + num_lines_in += lines_imported; + num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out); + } + return num_lines_out; +} + +#endif // WEBP_REDUCE_SIZE + +// Emit rows without any scaling. +static int EmitRows(WEBP_CSP_MODE colorspace, + const uint8_t* row_in, int in_stride, + int mb_w, int mb_h, + uint8_t* const out, int out_stride) { + int lines = mb_h; + uint8_t* row_out = out; + while (lines-- > 0) { + VP8LConvertFromBGRA((const uint32_t*)row_in, mb_w, colorspace, row_out); + row_in += in_stride; + row_out += out_stride; + } + return mb_h; // Num rows out == num rows in. +} + +//------------------------------------------------------------------------------ +// Export to YUVA + +static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos, + const WebPDecBuffer* const output) { + const WebPYUVABuffer* const buf = &output->u.YUVA; + + // first, the luma plane + WebPConvertARGBToY(src, buf->y + y_pos * buf->y_stride, width); + + // then U/V planes + { + uint8_t* const u = buf->u + (y_pos >> 1) * buf->u_stride; + uint8_t* const v = buf->v + (y_pos >> 1) * buf->v_stride; + // even lines: store values + // odd lines: average with previous values + WebPConvertARGBToUV(src, u, v, width, !(y_pos & 1)); + } + // Lastly, store alpha if needed. + if (buf->a != NULL) { + uint8_t* const a = buf->a + y_pos * buf->a_stride; +#if defined(WORDS_BIGENDIAN) + WebPExtractAlpha((uint8_t*)src + 0, 0, width, 1, a, 0); +#else + WebPExtractAlpha((uint8_t*)src + 3, 0, width, 1, a, 0); +#endif + } +} + +static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) { + WebPRescaler* const rescaler = dec->rescaler; + uint32_t* const src = (uint32_t*)rescaler->dst; + const int dst_width = rescaler->dst_width; + int num_lines_out = 0; + while (WebPRescalerHasPendingOutput(rescaler)) { + WebPRescalerExportRow(rescaler); + WebPMultARGBRow(src, dst_width, 1); + ConvertToYUVA(src, dst_width, y_pos, dec->output_); + ++y_pos; + ++num_lines_out; + } + return num_lines_out; +} + +static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec, + uint8_t* in, int in_stride, int mb_h) { + int num_lines_in = 0; + int y_pos = dec->last_out_row_; + while (num_lines_in < mb_h) { + const int lines_left = mb_h - num_lines_in; + const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); + int lines_imported; + WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0); + lines_imported = + WebPRescalerImport(dec->rescaler, lines_left, in, in_stride); + assert(lines_imported == needed_lines); + num_lines_in += lines_imported; + in += needed_lines * in_stride; + y_pos += ExportYUVA(dec, y_pos); + } + return y_pos; +} + +static int EmitRowsYUVA(const VP8LDecoder* const dec, + const uint8_t* in, int in_stride, + int mb_w, int num_rows) { + int y_pos = dec->last_out_row_; + while (num_rows-- > 0) { + ConvertToYUVA((const uint32_t*)in, mb_w, y_pos, dec->output_); + in += in_stride; + ++y_pos; + } + return y_pos; +} + +//------------------------------------------------------------------------------ +// Cropping. + +// Sets io->mb_y, io->mb_h & io->mb_w according to start row, end row and +// crop options. Also updates the input data pointer, so that it points to the +// start of the cropped window. Note that pixels are in ARGB format even if +// 'in_data' is uint8_t*. +// Returns true if the crop window is not empty. +static int SetCropWindow(VP8Io* const io, int y_start, int y_end, + uint8_t** const in_data, int pixel_stride) { + assert(y_start < y_end); + assert(io->crop_left < io->crop_right); + if (y_end > io->crop_bottom) { + y_end = io->crop_bottom; // make sure we don't overflow on last row. + } + if (y_start < io->crop_top) { + const int delta = io->crop_top - y_start; + y_start = io->crop_top; + *in_data += delta * pixel_stride; + } + if (y_start >= y_end) return 0; // Crop window is empty. + + *in_data += io->crop_left * sizeof(uint32_t); + + io->mb_y = y_start - io->crop_top; + io->mb_w = io->crop_right - io->crop_left; + io->mb_h = y_end - y_start; + return 1; // Non-empty crop window. +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE int GetMetaIndex( + const uint32_t* const image, int xsize, int bits, int x, int y) { + if (bits == 0) return 0; + return image[xsize * (y >> bits) + (x >> bits)]; +} + +static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr, + int x, int y) { + const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_, + hdr->huffman_subsample_bits_, x, y); + assert(meta_index < hdr->num_htree_groups_); + return hdr->htree_groups_ + meta_index; +} + +//------------------------------------------------------------------------------ +// Main loop, with custom row-processing function + +typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row); + +static void ApplyInverseTransforms(VP8LDecoder* const dec, + int start_row, int num_rows, + const uint32_t* const rows) { + int n = dec->next_transform_; + const int cache_pixs = dec->width_ * num_rows; + const int end_row = start_row + num_rows; + const uint32_t* rows_in = rows; + uint32_t* const rows_out = dec->argb_cache_; + + // Inverse transforms. + while (n-- > 0) { + VP8LTransform* const transform = &dec->transforms_[n]; + VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); + rows_in = rows_out; + } + if (rows_in != rows_out) { + // No transform called, hence just copy. + memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out)); + } +} + +// Processes (transforms, scales & color-converts) the rows decoded after the +// last call. +static void ProcessRows(VP8LDecoder* const dec, int row) { + const uint32_t* const rows = dec->pixels_ + dec->width_ * dec->last_row_; + const int num_rows = row - dec->last_row_; + + assert(row <= dec->io_->crop_bottom); + // We can't process more than NUM_ARGB_CACHE_ROWS at a time (that's the size + // of argb_cache_), but we currently don't need more than that. + assert(num_rows <= NUM_ARGB_CACHE_ROWS); + if (num_rows > 0) { // Emit output. + VP8Io* const io = dec->io_; + uint8_t* rows_data = (uint8_t*)dec->argb_cache_; + const int in_stride = io->width * sizeof(uint32_t); // in unit of RGBA + ApplyInverseTransforms(dec, dec->last_row_, num_rows, rows); + if (!SetCropWindow(io, dec->last_row_, row, &rows_data, in_stride)) { + // Nothing to output (this time). + } else { + const WebPDecBuffer* const output = dec->output_; + if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA + const WebPRGBABuffer* const buf = &output->u.RGBA; + uint8_t* const rgba = + buf->rgba + (int64_t)dec->last_out_row_ * buf->stride; + const int num_rows_out = +#if !defined(WEBP_REDUCE_SIZE) + io->use_scaling ? + EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h, + rgba, buf->stride) : +#endif // WEBP_REDUCE_SIZE + EmitRows(output->colorspace, rows_data, in_stride, + io->mb_w, io->mb_h, rgba, buf->stride); + // Update 'last_out_row_'. + dec->last_out_row_ += num_rows_out; + } else { // convert to YUVA + dec->last_out_row_ = io->use_scaling ? + EmitRescaledRowsYUVA(dec, rows_data, in_stride, io->mb_h) : + EmitRowsYUVA(dec, rows_data, in_stride, io->mb_w, io->mb_h); + } + assert(dec->last_out_row_ <= output->height); + } + } + + // Update 'last_row_'. + dec->last_row_ = row; + assert(dec->last_row_ <= dec->height_); +} + +// Row-processing for the special case when alpha data contains only one +// transform (color indexing), and trivial non-green literals. +static int Is8bOptimizable(const VP8LMetadata* const hdr) { + int i; + if (hdr->color_cache_size_ > 0) return 0; + // When the Huffman tree contains only one symbol, we can skip the + // call to ReadSymbol() for red/blue/alpha channels. + for (i = 0; i < hdr->num_htree_groups_; ++i) { + HuffmanCode** const htrees = hdr->htree_groups_[i].htrees; + if (htrees[RED][0].bits > 0) return 0; + if (htrees[BLUE][0].bits > 0) return 0; + if (htrees[ALPHA][0].bits > 0) return 0; + } + return 1; +} + +static void AlphaApplyFilter(ALPHDecoder* const alph_dec, + int first_row, int last_row, + uint8_t* out, int stride) { + if (alph_dec->filter_ != WEBP_FILTER_NONE) { + int y; + const uint8_t* prev_line = alph_dec->prev_line_; + assert(WebPUnfilters[alph_dec->filter_] != NULL); + for (y = first_row; y < last_row; ++y) { + WebPUnfilters[alph_dec->filter_](prev_line, out, out, stride); + prev_line = out; + out += stride; + } + alph_dec->prev_line_ = prev_line; + } +} + +static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int last_row) { + // For vertical and gradient filtering, we need to decode the part above the + // crop_top row, in order to have the correct spatial predictors. + ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque; + const int top_row = + (alph_dec->filter_ == WEBP_FILTER_NONE || + alph_dec->filter_ == WEBP_FILTER_HORIZONTAL) ? dec->io_->crop_top + : dec->last_row_; + const int first_row = (dec->last_row_ < top_row) ? top_row : dec->last_row_; + assert(last_row <= dec->io_->crop_bottom); + if (last_row > first_row) { + // Special method for paletted alpha data. We only process the cropped area. + const int width = dec->io_->width; + uint8_t* out = alph_dec->output_ + width * first_row; + const uint8_t* const in = + (uint8_t*)dec->pixels_ + dec->width_ * first_row; + VP8LTransform* const transform = &dec->transforms_[0]; + assert(dec->next_transform_ == 1); + assert(transform->type_ == COLOR_INDEXING_TRANSFORM); + VP8LColorIndexInverseTransformAlpha(transform, first_row, last_row, + in, out); + AlphaApplyFilter(alph_dec, first_row, last_row, out, width); + } + dec->last_row_ = dec->last_out_row_ = last_row; +} + +//------------------------------------------------------------------------------ +// Helper functions for fast pattern copy (8b and 32b) + +// cyclic rotation of pattern word +static WEBP_INLINE uint32_t Rotate8b(uint32_t V) { +#if defined(WORDS_BIGENDIAN) + return ((V & 0xff000000u) >> 24) | (V << 8); +#else + return ((V & 0xffu) << 24) | (V >> 8); +#endif +} + +// copy 1, 2 or 4-bytes pattern +static WEBP_INLINE void CopySmallPattern8b(const uint8_t* src, uint8_t* dst, + int length, uint32_t pattern) { + int i; + // align 'dst' to 4-bytes boundary. Adjust the pattern along the way. + while ((uintptr_t)dst & 3) { + *dst++ = *src++; + pattern = Rotate8b(pattern); + --length; + } + // Copy the pattern 4 bytes at a time. + for (i = 0; i < (length >> 2); ++i) { + ((uint32_t*)dst)[i] = pattern; + } + // Finish with left-overs. 'pattern' is still correctly positioned, + // so no Rotate8b() call is needed. + for (i <<= 2; i < length; ++i) { + dst[i] = src[i]; + } +} + +static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) { + const uint8_t* src = dst - dist; + if (length >= 8) { + uint32_t pattern = 0; + switch (dist) { + case 1: + pattern = src[0]; +#if defined(__arm__) || defined(_M_ARM) // arm doesn't like multiply that much + pattern |= pattern << 8; + pattern |= pattern << 16; +#elif defined(WEBP_USE_MIPS_DSP_R2) + __asm__ volatile ("replv.qb %0, %0" : "+r"(pattern)); +#else + pattern = 0x01010101u * pattern; +#endif + break; + case 2: +#if !defined(WORDS_BIGENDIAN) + memcpy(&pattern, src, sizeof(uint16_t)); +#else + pattern = ((uint32_t)src[0] << 8) | src[1]; +#endif +#if defined(__arm__) || defined(_M_ARM) + pattern |= pattern << 16; +#elif defined(WEBP_USE_MIPS_DSP_R2) + __asm__ volatile ("replv.ph %0, %0" : "+r"(pattern)); +#else + pattern = 0x00010001u * pattern; +#endif + break; + case 4: + memcpy(&pattern, src, sizeof(uint32_t)); + break; + default: + goto Copy; + } + CopySmallPattern8b(src, dst, length, pattern); + return; + } + Copy: + if (dist >= length) { // no overlap -> use memcpy() + memcpy(dst, src, length * sizeof(*dst)); + } else { + int i; + for (i = 0; i < length; ++i) dst[i] = src[i]; + } +} + +// copy pattern of 1 or 2 uint32_t's +static WEBP_INLINE void CopySmallPattern32b(const uint32_t* src, + uint32_t* dst, + int length, uint64_t pattern) { + int i; + if ((uintptr_t)dst & 4) { // Align 'dst' to 8-bytes boundary. + *dst++ = *src++; + pattern = (pattern >> 32) | (pattern << 32); + --length; + } + assert(0 == ((uintptr_t)dst & 7)); + for (i = 0; i < (length >> 1); ++i) { + ((uint64_t*)dst)[i] = pattern; // Copy the pattern 8 bytes at a time. + } + if (length & 1) { // Finish with left-over. + dst[i << 1] = src[i << 1]; + } +} + +static WEBP_INLINE void CopyBlock32b(uint32_t* const dst, + int dist, int length) { + const uint32_t* const src = dst - dist; + if (dist <= 2 && length >= 4 && ((uintptr_t)dst & 3) == 0) { + uint64_t pattern; + if (dist == 1) { + pattern = (uint64_t)src[0]; + pattern |= pattern << 32; + } else { + memcpy(&pattern, src, sizeof(pattern)); + } + CopySmallPattern32b(src, dst, length, pattern); + } else if (dist >= length) { // no overlap + memcpy(dst, src, length * sizeof(*dst)); + } else { + int i; + for (i = 0; i < length; ++i) dst[i] = src[i]; + } +} + +//------------------------------------------------------------------------------ + +static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data, + int width, int height, int last_row) { + int ok = 1; + int row = dec->last_pixel_ / width; + int col = dec->last_pixel_ % width; + VP8LBitReader* const br = &dec->br_; + VP8LMetadata* const hdr = &dec->hdr_; + int pos = dec->last_pixel_; // current position + const int end = width * height; // End of data + const int last = width * last_row; // Last pixel to decode + const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; + const int mask = hdr->huffman_mask_; + const HTreeGroup* htree_group = + (pos < last) ? GetHtreeGroupForPos(hdr, col, row) : NULL; + assert(pos <= end); + assert(last_row <= height); + assert(Is8bOptimizable(hdr)); + + while (!br->eos_ && pos < last) { + int code; + // Only update when changing tile. + if ((col & mask) == 0) { + htree_group = GetHtreeGroupForPos(hdr, col, row); + } + assert(htree_group != NULL); + VP8LFillBitWindow(br); + code = ReadSymbol(htree_group->htrees[GREEN], br); + if (code < NUM_LITERAL_CODES) { // Literal + data[pos] = code; + ++pos; + ++col; + if (col >= width) { + col = 0; + ++row; + if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) { + ExtractPalettedAlphaRows(dec, row); + } + } + } else if (code < len_code_limit) { // Backward reference + int dist_code, dist; + const int length_sym = code - NUM_LITERAL_CODES; + const int length = GetCopyLength(length_sym, br); + const int dist_symbol = ReadSymbol(htree_group->htrees[DIST], br); + VP8LFillBitWindow(br); + dist_code = GetCopyDistance(dist_symbol, br); + dist = PlaneCodeToDistance(width, dist_code); + if (pos >= dist && end - pos >= length) { + CopyBlock8b(data + pos, dist, length); + } else { + ok = 0; + goto End; + } + pos += length; + col += length; + while (col >= width) { + col -= width; + ++row; + if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) { + ExtractPalettedAlphaRows(dec, row); + } + } + if (pos < last && (col & mask)) { + htree_group = GetHtreeGroupForPos(hdr, col, row); + } + } else { // Not reached + ok = 0; + goto End; + } + br->eos_ = VP8LIsEndOfStream(br); + } + // Process the remaining rows corresponding to last row-block. + ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row); + + End: + br->eos_ = VP8LIsEndOfStream(br); + if (!ok || (br->eos_ && pos < end)) { + return VP8LSetError( + dec, br->eos_ ? VP8_STATUS_SUSPENDED : VP8_STATUS_BITSTREAM_ERROR); + } + dec->last_pixel_ = pos; + return ok; +} + +static void SaveState(VP8LDecoder* const dec, int last_pixel) { + assert(dec->incremental_); + dec->saved_br_ = dec->br_; + dec->saved_last_pixel_ = last_pixel; + if (dec->hdr_.color_cache_size_ > 0) { + VP8LColorCacheCopy(&dec->hdr_.color_cache_, &dec->hdr_.saved_color_cache_); + } +} + +static void RestoreState(VP8LDecoder* const dec) { + assert(dec->br_.eos_); + dec->status_ = VP8_STATUS_SUSPENDED; + dec->br_ = dec->saved_br_; + dec->last_pixel_ = dec->saved_last_pixel_; + if (dec->hdr_.color_cache_size_ > 0) { + VP8LColorCacheCopy(&dec->hdr_.saved_color_cache_, &dec->hdr_.color_cache_); + } +} + +#define SYNC_EVERY_N_ROWS 8 // minimum number of rows between check-points +static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data, + int width, int height, int last_row, + ProcessRowsFunc process_func) { + int row = dec->last_pixel_ / width; + int col = dec->last_pixel_ % width; + VP8LBitReader* const br = &dec->br_; + VP8LMetadata* const hdr = &dec->hdr_; + uint32_t* src = data + dec->last_pixel_; + uint32_t* last_cached = src; + uint32_t* const src_end = data + width * height; // End of data + uint32_t* const src_last = data + width * last_row; // Last pixel to decode + const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; + const int color_cache_limit = len_code_limit + hdr->color_cache_size_; + int next_sync_row = dec->incremental_ ? row : 1 << 24; + VP8LColorCache* const color_cache = + (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL; + const int mask = hdr->huffman_mask_; + const HTreeGroup* htree_group = + (src < src_last) ? GetHtreeGroupForPos(hdr, col, row) : NULL; + assert(dec->last_row_ < last_row); + assert(src_last <= src_end); + + while (src < src_last) { + int code; + if (row >= next_sync_row) { + SaveState(dec, (int)(src - data)); + next_sync_row = row + SYNC_EVERY_N_ROWS; + } + // Only update when changing tile. Note we could use this test: + // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed + // but that's actually slower and needs storing the previous col/row. + if ((col & mask) == 0) { + htree_group = GetHtreeGroupForPos(hdr, col, row); + } + assert(htree_group != NULL); + if (htree_group->is_trivial_code) { + *src = htree_group->literal_arb; + goto AdvanceByOne; + } + VP8LFillBitWindow(br); + if (htree_group->use_packed_table) { + code = ReadPackedSymbols(htree_group, br, src); + if (VP8LIsEndOfStream(br)) break; + if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne; + } else { + code = ReadSymbol(htree_group->htrees[GREEN], br); + } + if (VP8LIsEndOfStream(br)) break; + if (code < NUM_LITERAL_CODES) { // Literal + if (htree_group->is_trivial_literal) { + *src = htree_group->literal_arb | (code << 8); + } else { + int red, blue, alpha; + red = ReadSymbol(htree_group->htrees[RED], br); + VP8LFillBitWindow(br); + blue = ReadSymbol(htree_group->htrees[BLUE], br); + alpha = ReadSymbol(htree_group->htrees[ALPHA], br); + if (VP8LIsEndOfStream(br)) break; + *src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue; + } + AdvanceByOne: + ++src; + ++col; + if (col >= width) { + col = 0; + ++row; + if (process_func != NULL) { + if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) { + process_func(dec, row); + } + } + if (color_cache != NULL) { + while (last_cached < src) { + VP8LColorCacheInsert(color_cache, *last_cached++); + } + } + } + } else if (code < len_code_limit) { // Backward reference + int dist_code, dist; + const int length_sym = code - NUM_LITERAL_CODES; + const int length = GetCopyLength(length_sym, br); + const int dist_symbol = ReadSymbol(htree_group->htrees[DIST], br); + VP8LFillBitWindow(br); + dist_code = GetCopyDistance(dist_symbol, br); + dist = PlaneCodeToDistance(width, dist_code); + + if (VP8LIsEndOfStream(br)) break; + if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) { + goto Error; + } else { + CopyBlock32b(src, dist, length); + } + src += length; + col += length; + while (col >= width) { + col -= width; + ++row; + if (process_func != NULL) { + if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) { + process_func(dec, row); + } + } + } + // Because of the check done above (before 'src' was incremented by + // 'length'), the following holds true. + assert(src <= src_end); + if (col & mask) htree_group = GetHtreeGroupForPos(hdr, col, row); + if (color_cache != NULL) { + while (last_cached < src) { + VP8LColorCacheInsert(color_cache, *last_cached++); + } + } + } else if (code < color_cache_limit) { // Color cache + const int key = code - len_code_limit; + assert(color_cache != NULL); + while (last_cached < src) { + VP8LColorCacheInsert(color_cache, *last_cached++); + } + *src = VP8LColorCacheLookup(color_cache, key); + goto AdvanceByOne; + } else { // Not reached + goto Error; + } + } + + br->eos_ = VP8LIsEndOfStream(br); + // In incremental decoding: + // br->eos_ && src < src_last: if 'br' reached the end of the buffer and + // 'src_last' has not been reached yet, there is not enough data. 'dec' has to + // be reset until there is more data. + // !br->eos_ && src < src_last: this cannot happen as either the buffer is + // fully read, either enough has been read to reach 'src_last'. + // src >= src_last: 'src_last' is reached, all is fine. 'src' can actually go + // beyond 'src_last' in case the image is cropped and an LZ77 goes further. + // The buffer might have been enough or there is some left. 'br->eos_' does + // not matter. + assert(!dec->incremental_ || (br->eos_ && src < src_last) || src >= src_last); + if (dec->incremental_ && br->eos_ && src < src_last) { + RestoreState(dec); + } else if ((dec->incremental_ && src >= src_last) || !br->eos_) { + // Process the remaining rows corresponding to last row-block. + if (process_func != NULL) { + process_func(dec, row > last_row ? last_row : row); + } + dec->status_ = VP8_STATUS_OK; + dec->last_pixel_ = (int)(src - data); // end-of-scan marker + } else { + // if not incremental, and we are past the end of buffer (eos_=1), then this + // is a real bitstream error. + goto Error; + } + return 1; + + Error: + return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); +} + +// ----------------------------------------------------------------------------- +// VP8LTransform + +static void ClearTransform(VP8LTransform* const transform) { + WebPSafeFree(transform->data_); + transform->data_ = NULL; +} + +// For security reason, we need to remap the color map to span +// the total possible bundled values, and not just the num_colors. +static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { + int i; + const int final_num_colors = 1 << (8 >> transform->bits_); + uint32_t* const new_color_map = + (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors, + sizeof(*new_color_map)); + if (new_color_map == NULL) { + return 0; + } else { + uint8_t* const data = (uint8_t*)transform->data_; + uint8_t* const new_data = (uint8_t*)new_color_map; + new_color_map[0] = transform->data_[0]; + for (i = 4; i < 4 * num_colors; ++i) { + // Equivalent to VP8LAddPixels(), on a byte-basis. + new_data[i] = (data[i] + new_data[i - 4]) & 0xff; + } + for (; i < 4 * final_num_colors; ++i) { + new_data[i] = 0; // black tail. + } + WebPSafeFree(transform->data_); + transform->data_ = new_color_map; + } + return 1; +} + +static int ReadTransform(int* const xsize, int const* ysize, + VP8LDecoder* const dec) { + int ok = 1; + VP8LBitReader* const br = &dec->br_; + VP8LTransform* transform = &dec->transforms_[dec->next_transform_]; + const VP8LImageTransformType type = + (VP8LImageTransformType)VP8LReadBits(br, 2); + + // Each transform type can only be present once in the stream. + if (dec->transforms_seen_ & (1U << type)) { + return 0; // Already there, let's not accept the second same transform. + } + dec->transforms_seen_ |= (1U << type); + + transform->type_ = type; + transform->xsize_ = *xsize; + transform->ysize_ = *ysize; + transform->data_ = NULL; + ++dec->next_transform_; + assert(dec->next_transform_ <= NUM_TRANSFORMS); + + switch (type) { + case PREDICTOR_TRANSFORM: + case CROSS_COLOR_TRANSFORM: + transform->bits_ = VP8LReadBits(br, 3) + 2; + ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize_, + transform->bits_), + VP8LSubSampleSize(transform->ysize_, + transform->bits_), + /*is_level0=*/0, dec, &transform->data_); + break; + case COLOR_INDEXING_TRANSFORM: { + const int num_colors = VP8LReadBits(br, 8) + 1; + const int bits = (num_colors > 16) ? 0 + : (num_colors > 4) ? 1 + : (num_colors > 2) ? 2 + : 3; + *xsize = VP8LSubSampleSize(transform->xsize_, bits); + transform->bits_ = bits; + ok = DecodeImageStream(num_colors, /*ysize=*/1, /*is_level0=*/0, dec, + &transform->data_); + if (ok && !ExpandColorMap(num_colors, transform)) { + return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + } + break; + } + case SUBTRACT_GREEN_TRANSFORM: + break; + default: + assert(0); // can't happen + break; + } + + return ok; +} + +// ----------------------------------------------------------------------------- +// VP8LMetadata + +static void InitMetadata(VP8LMetadata* const hdr) { + assert(hdr != NULL); + memset(hdr, 0, sizeof(*hdr)); +} + +static void ClearMetadata(VP8LMetadata* const hdr) { + assert(hdr != NULL); + + WebPSafeFree(hdr->huffman_image_); + VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_); + VP8LHtreeGroupsFree(hdr->htree_groups_); + VP8LColorCacheClear(&hdr->color_cache_); + VP8LColorCacheClear(&hdr->saved_color_cache_); + InitMetadata(hdr); +} + +// ----------------------------------------------------------------------------- +// VP8LDecoder + +VP8LDecoder* VP8LNew(void) { + VP8LDecoder* const dec = (VP8LDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); + if (dec == NULL) return NULL; + dec->status_ = VP8_STATUS_OK; + dec->state_ = READ_DIM; + + VP8LDspInit(); // Init critical function pointers. + + return dec; +} + +void VP8LClear(VP8LDecoder* const dec) { + int i; + if (dec == NULL) return; + ClearMetadata(&dec->hdr_); + + WebPSafeFree(dec->pixels_); + dec->pixels_ = NULL; + for (i = 0; i < dec->next_transform_; ++i) { + ClearTransform(&dec->transforms_[i]); + } + dec->next_transform_ = 0; + dec->transforms_seen_ = 0; + + WebPSafeFree(dec->rescaler_memory); + dec->rescaler_memory = NULL; + + dec->output_ = NULL; // leave no trace behind +} + +void VP8LDelete(VP8LDecoder* const dec) { + if (dec != NULL) { + VP8LClear(dec); + WebPSafeFree(dec); + } +} + +static void UpdateDecoder(VP8LDecoder* const dec, int width, int height) { + VP8LMetadata* const hdr = &dec->hdr_; + const int num_bits = hdr->huffman_subsample_bits_; + dec->width_ = width; + dec->height_ = height; + + hdr->huffman_xsize_ = VP8LSubSampleSize(width, num_bits); + hdr->huffman_mask_ = (num_bits == 0) ? ~0 : (1 << num_bits) - 1; +} + +static int DecodeImageStream(int xsize, int ysize, + int is_level0, + VP8LDecoder* const dec, + uint32_t** const decoded_data) { + int ok = 1; + int transform_xsize = xsize; + int transform_ysize = ysize; + VP8LBitReader* const br = &dec->br_; + VP8LMetadata* const hdr = &dec->hdr_; + uint32_t* data = NULL; + int color_cache_bits = 0; + + // Read the transforms (may recurse). + if (is_level0) { + while (ok && VP8LReadBits(br, 1)) { + ok = ReadTransform(&transform_xsize, &transform_ysize, dec); + } + } + + // Color cache + if (ok && VP8LReadBits(br, 1)) { + color_cache_bits = VP8LReadBits(br, 4); + ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS); + if (!ok) { + VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); + goto End; + } + } + + // Read the Huffman codes (may recurse). + ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize, + color_cache_bits, is_level0); + if (!ok) { + VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); + goto End; + } + + // Finish setting up the color-cache + if (color_cache_bits > 0) { + hdr->color_cache_size_ = 1 << color_cache_bits; + if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) { + ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + goto End; + } + } else { + hdr->color_cache_size_ = 0; + } + UpdateDecoder(dec, transform_xsize, transform_ysize); + + if (is_level0) { // level 0 complete + dec->state_ = READ_HDR; + goto End; + } + + { + const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize; + data = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*data)); + if (data == NULL) { + ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + goto End; + } + } + + // Use the Huffman trees to decode the LZ77 encoded data. + ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, + transform_ysize, NULL); + ok = ok && !br->eos_; + + End: + if (!ok) { + WebPSafeFree(data); + ClearMetadata(hdr); + } else { + if (decoded_data != NULL) { + *decoded_data = data; + } else { + // We allocate image data in this function only for transforms. At level 0 + // (that is: not the transforms), we shouldn't have allocated anything. + assert(data == NULL); + assert(is_level0); + } + dec->last_pixel_ = 0; // Reset for future DECODE_DATA_FUNC() calls. + if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind. + } + return ok; +} + +//------------------------------------------------------------------------------ +// Allocate internal buffers dec->pixels_ and dec->argb_cache_. +static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) { + const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_; + // Scratch buffer corresponding to top-prediction row for transforming the + // first row in the row-blocks. Not needed for paletted alpha. + const uint64_t cache_top_pixels = (uint16_t)final_width; + // Scratch buffer for temporary BGRA storage. Not needed for paletted alpha. + const uint64_t cache_pixels = (uint64_t)final_width * NUM_ARGB_CACHE_ROWS; + const uint64_t total_num_pixels = + num_pixels + cache_top_pixels + cache_pixels; + + assert(dec->width_ <= final_width); + dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t)); + if (dec->pixels_ == NULL) { + dec->argb_cache_ = NULL; // for soundness + return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + } + dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels; + return 1; +} + +static int AllocateInternalBuffers8b(VP8LDecoder* const dec) { + const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_; + dec->argb_cache_ = NULL; // for soundness + dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t)); + if (dec->pixels_ == NULL) { + return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + } + return 1; +} + +//------------------------------------------------------------------------------ + +// Special row-processing that only stores the alpha data. +static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) { + int cur_row = dec->last_row_; + int num_rows = last_row - cur_row; + const uint32_t* in = dec->pixels_ + dec->width_ * cur_row; + + assert(last_row <= dec->io_->crop_bottom); + while (num_rows > 0) { + const int num_rows_to_process = + (num_rows > NUM_ARGB_CACHE_ROWS) ? NUM_ARGB_CACHE_ROWS : num_rows; + // Extract alpha (which is stored in the green plane). + ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque; + uint8_t* const output = alph_dec->output_; + const int width = dec->io_->width; // the final width (!= dec->width_) + const int cache_pixs = width * num_rows_to_process; + uint8_t* const dst = output + width * cur_row; + const uint32_t* const src = dec->argb_cache_; + ApplyInverseTransforms(dec, cur_row, num_rows_to_process, in); + WebPExtractGreen(src, dst, cache_pixs); + AlphaApplyFilter(alph_dec, + cur_row, cur_row + num_rows_to_process, dst, width); + num_rows -= num_rows_to_process; + in += num_rows_to_process * dec->width_; + cur_row += num_rows_to_process; + } + assert(cur_row == last_row); + dec->last_row_ = dec->last_out_row_ = last_row; +} + +int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, + const uint8_t* const data, size_t data_size) { + int ok = 0; + VP8LDecoder* dec = VP8LNew(); + + if (dec == NULL) return 0; + + assert(alph_dec != NULL); + + dec->width_ = alph_dec->width_; + dec->height_ = alph_dec->height_; + dec->io_ = &alph_dec->io_; + dec->io_->opaque = alph_dec; + dec->io_->width = alph_dec->width_; + dec->io_->height = alph_dec->height_; + + dec->status_ = VP8_STATUS_OK; + VP8LInitBitReader(&dec->br_, data, data_size); + + if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, /*is_level0=*/1, + dec, /*decoded_data=*/NULL)) { + goto Err; + } + + // Special case: if alpha data uses only the color indexing transform and + // doesn't use color cache (a frequent case), we will use DecodeAlphaData() + // method that only needs allocation of 1 byte per pixel (alpha channel). + if (dec->next_transform_ == 1 && + dec->transforms_[0].type_ == COLOR_INDEXING_TRANSFORM && + Is8bOptimizable(&dec->hdr_)) { + alph_dec->use_8b_decode_ = 1; + ok = AllocateInternalBuffers8b(dec); + } else { + // Allocate internal buffers (note that dec->width_ may have changed here). + alph_dec->use_8b_decode_ = 0; + ok = AllocateInternalBuffers32b(dec, alph_dec->width_); + } + + if (!ok) goto Err; + + // Only set here, once we are sure it is valid (to avoid thread races). + alph_dec->vp8l_dec_ = dec; + return 1; + + Err: + VP8LDelete(dec); + return 0; +} + +int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) { + VP8LDecoder* const dec = alph_dec->vp8l_dec_; + assert(dec != NULL); + assert(last_row <= dec->height_); + + if (dec->last_row_ >= last_row) { + return 1; // done + } + + if (!alph_dec->use_8b_decode_) WebPInitAlphaProcessing(); + + // Decode (with special row processing). + return alph_dec->use_8b_decode_ ? + DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_, + last_row) : + DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_, + last_row, ExtractAlphaRows); +} + +//------------------------------------------------------------------------------ + +int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) { + int width, height, has_alpha; + + if (dec == NULL) return 0; + if (io == NULL) { + return VP8LSetError(dec, VP8_STATUS_INVALID_PARAM); + } + + dec->io_ = io; + dec->status_ = VP8_STATUS_OK; + VP8LInitBitReader(&dec->br_, io->data, io->data_size); + if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) { + VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); + goto Error; + } + dec->state_ = READ_DIM; + io->width = width; + io->height = height; + + if (!DecodeImageStream(width, height, /*is_level0=*/1, dec, + /*decoded_data=*/NULL)) { + goto Error; + } + return 1; + + Error: + VP8LClear(dec); + assert(dec->status_ != VP8_STATUS_OK); + return 0; +} + +int VP8LDecodeImage(VP8LDecoder* const dec) { + VP8Io* io = NULL; + WebPDecParams* params = NULL; + + if (dec == NULL) return 0; + + assert(dec->hdr_.huffman_tables_.root.start != NULL); + assert(dec->hdr_.htree_groups_ != NULL); + assert(dec->hdr_.num_htree_groups_ > 0); + + io = dec->io_; + assert(io != NULL); + params = (WebPDecParams*)io->opaque; + assert(params != NULL); + + // Initialization. + if (dec->state_ != READ_DATA) { + dec->output_ = params->output; + assert(dec->output_ != NULL); + + if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) { + VP8LSetError(dec, VP8_STATUS_INVALID_PARAM); + goto Err; + } + + if (!AllocateInternalBuffers32b(dec, io->width)) goto Err; + +#if !defined(WEBP_REDUCE_SIZE) + if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err; +#else + if (io->use_scaling) { + VP8LSetError(dec, VP8_STATUS_INVALID_PARAM); + goto Err; + } +#endif + if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) { + // need the alpha-multiply functions for premultiplied output or rescaling + WebPInitAlphaProcessing(); + } + + if (!WebPIsRGBMode(dec->output_->colorspace)) { + WebPInitConvertARGBToYUV(); + if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing(); + } + if (dec->incremental_) { + if (dec->hdr_.color_cache_size_ > 0 && + dec->hdr_.saved_color_cache_.colors_ == NULL) { + if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_, + dec->hdr_.color_cache_.hash_bits_)) { + VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); + goto Err; + } + } + } + dec->state_ = READ_DATA; + } + + // Decode. + if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_, + io->crop_bottom, ProcessRows)) { + goto Err; + } + + params->last_y = dec->last_out_row_; + return 1; + + Err: + VP8LClear(dec); + assert(dec->status_ != VP8_STATUS_OK); + return 0; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dec/vp8li_dec.h b/libraries/webp/src/dec/vp8li_dec.h new file mode 100644 index 00000000000..e863b4b60dd --- /dev/null +++ b/libraries/webp/src/dec/vp8li_dec.h @@ -0,0 +1,149 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Lossless decoder: internal header. +// +// Author: Skal (pascal.massimino@gmail.com) +// Vikas Arora(vikaas.arora@gmail.com) + +#ifndef WEBP_DEC_VP8LI_DEC_H_ +#define WEBP_DEC_VP8LI_DEC_H_ + +#include // for memcpy() +#include "src/dec/webpi_dec.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/color_cache_utils.h" +#include "src/utils/huffman_utils.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + READ_DATA = 0, + READ_HDR = 1, + READ_DIM = 2 +} VP8LDecodeState; + +typedef struct VP8LTransform VP8LTransform; +struct VP8LTransform { + VP8LImageTransformType type_; // transform type. + int bits_; // subsampling bits defining transform window. + int xsize_; // transform window X index. + int ysize_; // transform window Y index. + uint32_t* data_; // transform data. +}; + +typedef struct { + int color_cache_size_; + VP8LColorCache color_cache_; + VP8LColorCache saved_color_cache_; // for incremental + + int huffman_mask_; + int huffman_subsample_bits_; + int huffman_xsize_; + uint32_t* huffman_image_; + int num_htree_groups_; + HTreeGroup* htree_groups_; + HuffmanTables huffman_tables_; +} VP8LMetadata; + +typedef struct VP8LDecoder VP8LDecoder; +struct VP8LDecoder { + VP8StatusCode status_; + VP8LDecodeState state_; + VP8Io* io_; + + const WebPDecBuffer* output_; // shortcut to io->opaque->output + + uint32_t* pixels_; // Internal data: either uint8_t* for alpha + // or uint32_t* for BGRA. + uint32_t* argb_cache_; // Scratch buffer for temporary BGRA storage. + + VP8LBitReader br_; + int incremental_; // if true, incremental decoding is expected + VP8LBitReader saved_br_; // note: could be local variables too + int saved_last_pixel_; + + int width_; + int height_; + int last_row_; // last input row decoded so far. + int last_pixel_; // last pixel decoded so far. However, it may + // not be transformed, scaled and + // color-converted yet. + int last_out_row_; // last row output so far. + + VP8LMetadata hdr_; + + int next_transform_; + VP8LTransform transforms_[NUM_TRANSFORMS]; + // or'd bitset storing the transforms types. + uint32_t transforms_seen_; + + uint8_t* rescaler_memory; // Working memory for rescaling work. + WebPRescaler* rescaler; // Common rescaler for all channels. +}; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + +struct ALPHDecoder; // Defined in dec/alphai.h. + +// in vp8l.c + +// Decodes image header for alpha data stored using lossless compression. +// Returns false in case of error. +WEBP_NODISCARD int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec, + const uint8_t* const data, + size_t data_size); + +// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are +// already decoded in previous call(s), it will resume decoding from where it +// was paused. +// Returns false in case of bitstream error. +WEBP_NODISCARD int VP8LDecodeAlphaImageStream( + struct ALPHDecoder* const alph_dec, int last_row); + +// Allocates and initialize a new lossless decoder instance. +WEBP_NODISCARD VP8LDecoder* VP8LNew(void); + +// Decodes the image header. Returns false in case of error. +WEBP_NODISCARD int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io); + +// Decodes an image. It's required to decode the lossless header before calling +// this function. Returns false in case of error, with updated dec->status_. +WEBP_NODISCARD int VP8LDecodeImage(VP8LDecoder* const dec); + +// Resets the decoder in its initial state, reclaiming memory. +// Preserves the dec->status_ value. +void VP8LClear(VP8LDecoder* const dec); + +// Clears and deallocate a lossless decoder instance. +void VP8LDelete(VP8LDecoder* const dec); + +// Helper function for reading the different Huffman codes and storing them in +// 'huffman_tables' and 'htree_groups'. +// If mapping is NULL 'num_htree_groups_max' must equal 'num_htree_groups'. +// If it is not NULL, it maps 'num_htree_groups_max' indices to the +// 'num_htree_groups' groups. If 'num_htree_groups_max' > 'num_htree_groups', +// some of those indices map to -1. This is used for non-balanced codes to +// limit memory usage. +WEBP_NODISCARD int ReadHuffmanCodesHelper( + int color_cache_bits, int num_htree_groups, int num_htree_groups_max, + const int* const mapping, VP8LDecoder* const dec, + HuffmanTables* const huffman_tables, HTreeGroup** const htree_groups); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DEC_VP8LI_DEC_H_ diff --git a/libraries/webp/src/dec/webp_dec.c b/libraries/webp/src/dec/webp_dec.c new file mode 100644 index 00000000000..3aa87dab057 --- /dev/null +++ b/libraries/webp/src/dec/webp_dec.c @@ -0,0 +1,871 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Main decoding functions for WEBP images. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/dec/vp8_dec.h" +#include "src/dec/vp8i_dec.h" +#include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/utils/utils.h" +#include "include/webp/mux_types.h" // ALPHA_FLAG +#include "include/webp/decode.h" +#include "include/webp/types.h" + +//------------------------------------------------------------------------------ +// RIFF layout is: +// Offset tag +// 0...3 "RIFF" 4-byte tag +// 4...7 size of image data (including metadata) starting at offset 8 +// 8...11 "WEBP" our form-type signature +// The RIFF container (12 bytes) is followed by appropriate chunks: +// 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format +// 16..19 size of the raw VP8 image data, starting at offset 20 +// 20.... the VP8 bytes +// Or, +// 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format +// 16..19 size of the raw VP8L image data, starting at offset 20 +// 20.... the VP8L bytes +// Or, +// 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. +// 16..19 size of the VP8X chunk starting at offset 20. +// 20..23 VP8X flags bit-map corresponding to the chunk-types present. +// 24..26 Width of the Canvas Image. +// 27..29 Height of the Canvas Image. +// There can be extra chunks after the "VP8X" chunk (ICCP, ANMF, VP8, VP8L, +// XMP, EXIF ...) +// All sizes are in little-endian order. +// Note: chunk data size must be padded to multiple of 2 when written. + +// Validates the RIFF container (if detected) and skips over it. +// If a RIFF container is detected, returns: +// VP8_STATUS_BITSTREAM_ERROR for invalid header, +// VP8_STATUS_NOT_ENOUGH_DATA for truncated data if have_all_data is true, +// and VP8_STATUS_OK otherwise. +// In case there are not enough bytes (partial RIFF container), return 0 for +// *riff_size. Else return the RIFF size extracted from the header. +static VP8StatusCode ParseRIFF(const uint8_t** const data, + size_t* const data_size, int have_all_data, + size_t* const riff_size) { + assert(data != NULL); + assert(data_size != NULL); + assert(riff_size != NULL); + + *riff_size = 0; // Default: no RIFF present. + if (*data_size >= RIFF_HEADER_SIZE && !memcmp(*data, "RIFF", TAG_SIZE)) { + if (memcmp(*data + 8, "WEBP", TAG_SIZE)) { + return VP8_STATUS_BITSTREAM_ERROR; // Wrong image file signature. + } else { + const uint32_t size = GetLE32(*data + TAG_SIZE); + // Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn"). + if (size < TAG_SIZE + CHUNK_HEADER_SIZE) { + return VP8_STATUS_BITSTREAM_ERROR; + } + if (size > MAX_CHUNK_PAYLOAD) { + return VP8_STATUS_BITSTREAM_ERROR; + } + if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) { + return VP8_STATUS_NOT_ENOUGH_DATA; // Truncated bitstream. + } + // We have a RIFF container. Skip it. + *riff_size = size; + *data += RIFF_HEADER_SIZE; + *data_size -= RIFF_HEADER_SIZE; + } + } + return VP8_STATUS_OK; +} + +// Validates the VP8X header and skips over it. +// Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header, +// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and +// VP8_STATUS_OK otherwise. +// If a VP8X chunk is found, found_vp8x is set to true and *width_ptr, +// *height_ptr and *flags_ptr are set to the corresponding values extracted +// from the VP8X chunk. +static VP8StatusCode ParseVP8X(const uint8_t** const data, + size_t* const data_size, + int* const found_vp8x, + int* const width_ptr, int* const height_ptr, + uint32_t* const flags_ptr) { + const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; + assert(data != NULL); + assert(data_size != NULL); + assert(found_vp8x != NULL); + + *found_vp8x = 0; + + if (*data_size < CHUNK_HEADER_SIZE) { + return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. + } + + if (!memcmp(*data, "VP8X", TAG_SIZE)) { + int width, height; + uint32_t flags; + const uint32_t chunk_size = GetLE32(*data + TAG_SIZE); + if (chunk_size != VP8X_CHUNK_SIZE) { + return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size. + } + + // Verify if enough data is available to validate the VP8X chunk. + if (*data_size < vp8x_size) { + return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. + } + flags = GetLE32(*data + 8); + width = 1 + GetLE24(*data + 12); + height = 1 + GetLE24(*data + 15); + if (width * (uint64_t)height >= MAX_IMAGE_AREA) { + return VP8_STATUS_BITSTREAM_ERROR; // image is too large + } + + if (flags_ptr != NULL) *flags_ptr = flags; + if (width_ptr != NULL) *width_ptr = width; + if (height_ptr != NULL) *height_ptr = height; + // Skip over VP8X header bytes. + *data += vp8x_size; + *data_size -= vp8x_size; + *found_vp8x = 1; + } + return VP8_STATUS_OK; +} + +// Skips to the next VP8/VP8L chunk header in the data given the size of the +// RIFF chunk 'riff_size'. +// Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered, +// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and +// VP8_STATUS_OK otherwise. +// If an alpha chunk is found, *alpha_data and *alpha_size are set +// appropriately. +static VP8StatusCode ParseOptionalChunks(const uint8_t** const data, + size_t* const data_size, + size_t const riff_size, + const uint8_t** const alpha_data, + size_t* const alpha_size) { + const uint8_t* buf; + size_t buf_size; + uint32_t total_size = TAG_SIZE + // "WEBP". + CHUNK_HEADER_SIZE + // "VP8Xnnnn". + VP8X_CHUNK_SIZE; // data. + assert(data != NULL); + assert(data_size != NULL); + buf = *data; + buf_size = *data_size; + + assert(alpha_data != NULL); + assert(alpha_size != NULL); + *alpha_data = NULL; + *alpha_size = 0; + + while (1) { + uint32_t chunk_size; + uint32_t disk_chunk_size; // chunk_size with padding + + *data = buf; + *data_size = buf_size; + + if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data. + return VP8_STATUS_NOT_ENOUGH_DATA; + } + + chunk_size = GetLE32(buf + TAG_SIZE); + if (chunk_size > MAX_CHUNK_PAYLOAD) { + return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size. + } + // For odd-sized chunk-payload, there's one byte padding at the end. + disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1u; + total_size += disk_chunk_size; + + // Check that total bytes skipped so far does not exceed riff_size. + if (riff_size > 0 && (total_size > riff_size)) { + return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size. + } + + // Start of a (possibly incomplete) VP8/VP8L chunk implies that we have + // parsed all the optional chunks. + // Note: This check must occur before the check 'buf_size < disk_chunk_size' + // below to allow incomplete VP8/VP8L chunks. + if (!memcmp(buf, "VP8 ", TAG_SIZE) || + !memcmp(buf, "VP8L", TAG_SIZE)) { + return VP8_STATUS_OK; + } + + if (buf_size < disk_chunk_size) { // Insufficient data. + return VP8_STATUS_NOT_ENOUGH_DATA; + } + + if (!memcmp(buf, "ALPH", TAG_SIZE)) { // A valid ALPH header. + *alpha_data = buf + CHUNK_HEADER_SIZE; + *alpha_size = chunk_size; + } + + // We have a full and valid chunk; skip it. + buf += disk_chunk_size; + buf_size -= disk_chunk_size; + } +} + +// Validates the VP8/VP8L Header ("VP8 nnnn" or "VP8L nnnn") and skips over it. +// Returns VP8_STATUS_BITSTREAM_ERROR for invalid (chunk larger than +// riff_size) VP8/VP8L header, +// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and +// VP8_STATUS_OK otherwise. +// If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes +// extracted from the VP8/VP8L chunk header. +// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data. +static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr, + size_t* const data_size, int have_all_data, + size_t riff_size, size_t* const chunk_size, + int* const is_lossless) { + const uint8_t* const data = *data_ptr; + const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE); + const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE); + const uint32_t minimal_size = + TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR + // "WEBP" + "VP8Lnnnn" + assert(data != NULL); + assert(data_size != NULL); + assert(chunk_size != NULL); + assert(is_lossless != NULL); + + if (*data_size < CHUNK_HEADER_SIZE) { + return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. + } + + if (is_vp8 || is_vp8l) { + // Bitstream contains VP8/VP8L header. + const uint32_t size = GetLE32(data + TAG_SIZE); + if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) { + return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information. + } + if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) { + return VP8_STATUS_NOT_ENOUGH_DATA; // Truncated bitstream. + } + // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header. + *chunk_size = size; + *data_ptr += CHUNK_HEADER_SIZE; + *data_size -= CHUNK_HEADER_SIZE; + *is_lossless = is_vp8l; + } else { + // Raw VP8/VP8L bitstream (no header). + *is_lossless = VP8LCheckSignature(data, *data_size); + *chunk_size = *data_size; + } + + return VP8_STATUS_OK; +} + +//------------------------------------------------------------------------------ + +// Fetch '*width', '*height', '*has_alpha' and fill out 'headers' based on +// 'data'. All the output parameters may be NULL. If 'headers' is NULL only the +// minimal amount will be read to fetch the remaining parameters. +// If 'headers' is non-NULL this function will attempt to locate both alpha +// data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L). +// Note: The following chunk sequences (before the raw VP8/VP8L data) are +// considered valid by this function: +// RIFF + VP8(L) +// RIFF + VP8X + (optional chunks) + VP8(L) +// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. +// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. +static VP8StatusCode ParseHeadersInternal(const uint8_t* data, + size_t data_size, + int* const width, + int* const height, + int* const has_alpha, + int* const has_animation, + int* const format, + WebPHeaderStructure* const headers) { + int canvas_width = 0; + int canvas_height = 0; + int image_width = 0; + int image_height = 0; + int found_riff = 0; + int found_vp8x = 0; + int animation_present = 0; + const int have_all_data = (headers != NULL) ? headers->have_all_data : 0; + + VP8StatusCode status; + WebPHeaderStructure hdrs; + + if (data == NULL || data_size < RIFF_HEADER_SIZE) { + return VP8_STATUS_NOT_ENOUGH_DATA; + } + memset(&hdrs, 0, sizeof(hdrs)); + hdrs.data = data; + hdrs.data_size = data_size; + + // Skip over RIFF header. + status = ParseRIFF(&data, &data_size, have_all_data, &hdrs.riff_size); + if (status != VP8_STATUS_OK) { + return status; // Wrong RIFF header / insufficient data. + } + found_riff = (hdrs.riff_size > 0); + + // Skip over VP8X. + { + uint32_t flags = 0; + status = ParseVP8X(&data, &data_size, &found_vp8x, + &canvas_width, &canvas_height, &flags); + if (status != VP8_STATUS_OK) { + return status; // Wrong VP8X / insufficient data. + } + animation_present = !!(flags & ANIMATION_FLAG); + if (!found_riff && found_vp8x) { + // Note: This restriction may be removed in the future, if it becomes + // necessary to send VP8X chunk to the decoder. + return VP8_STATUS_BITSTREAM_ERROR; + } + if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG); + if (has_animation != NULL) *has_animation = animation_present; + if (format != NULL) *format = 0; // default = undefined + + image_width = canvas_width; + image_height = canvas_height; + if (found_vp8x && animation_present && headers == NULL) { + status = VP8_STATUS_OK; + goto ReturnWidthHeight; // Just return features from VP8X header. + } + } + + if (data_size < TAG_SIZE) { + status = VP8_STATUS_NOT_ENOUGH_DATA; + goto ReturnWidthHeight; + } + + // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". + if ((found_riff && found_vp8x) || + (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { + status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, + &hdrs.alpha_data, &hdrs.alpha_data_size); + if (status != VP8_STATUS_OK) { + goto ReturnWidthHeight; // Invalid chunk size / insufficient data. + } + } + + // Skip over VP8/VP8L header. + status = ParseVP8Header(&data, &data_size, have_all_data, hdrs.riff_size, + &hdrs.compressed_size, &hdrs.is_lossless); + if (status != VP8_STATUS_OK) { + goto ReturnWidthHeight; // Wrong VP8/VP8L chunk-header / insufficient data. + } + if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) { + return VP8_STATUS_BITSTREAM_ERROR; + } + + if (format != NULL && !animation_present) { + *format = hdrs.is_lossless ? 2 : 1; + } + + if (!hdrs.is_lossless) { + if (data_size < VP8_FRAME_HEADER_SIZE) { + status = VP8_STATUS_NOT_ENOUGH_DATA; + goto ReturnWidthHeight; + } + // Validates raw VP8 data. + if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size, + &image_width, &image_height)) { + return VP8_STATUS_BITSTREAM_ERROR; + } + } else { + if (data_size < VP8L_FRAME_HEADER_SIZE) { + status = VP8_STATUS_NOT_ENOUGH_DATA; + goto ReturnWidthHeight; + } + // Validates raw VP8L data. + if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) { + return VP8_STATUS_BITSTREAM_ERROR; + } + } + // Validates image size coherency. + if (found_vp8x) { + if (canvas_width != image_width || canvas_height != image_height) { + return VP8_STATUS_BITSTREAM_ERROR; + } + } + if (headers != NULL) { + *headers = hdrs; + headers->offset = data - headers->data; + assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD); + assert(headers->offset == headers->data_size - data_size); + } + ReturnWidthHeight: + if (status == VP8_STATUS_OK || + (status == VP8_STATUS_NOT_ENOUGH_DATA && found_vp8x && headers == NULL)) { + if (has_alpha != NULL) { + // If the data did not contain a VP8X/VP8L chunk the only definitive way + // to set this is by looking for alpha data (from an ALPH chunk). + *has_alpha |= (hdrs.alpha_data != NULL); + } + if (width != NULL) *width = image_width; + if (height != NULL) *height = image_height; + return VP8_STATUS_OK; + } else { + return status; + } +} + +VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) { + // status is marked volatile as a workaround for a clang-3.8 (aarch64) bug + volatile VP8StatusCode status; + int has_animation = 0; + assert(headers != NULL); + // fill out headers, ignore width/height/has_alpha. + status = ParseHeadersInternal(headers->data, headers->data_size, + NULL, NULL, NULL, &has_animation, + NULL, headers); + if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) { + // The WebPDemux API + libwebp can be used to decode individual + // uncomposited frames or the WebPAnimDecoder can be used to fully + // reconstruct them (see webp/demux.h). + if (has_animation) { + status = VP8_STATUS_UNSUPPORTED_FEATURE; + } + } + return status; +} + +//------------------------------------------------------------------------------ +// WebPDecParams + +void WebPResetDecParams(WebPDecParams* const params) { + if (params != NULL) { + memset(params, 0, sizeof(*params)); + } +} + +//------------------------------------------------------------------------------ +// "Into" decoding variants + +// Main flow +WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data, + size_t data_size, + WebPDecParams* const params) { + VP8StatusCode status; + VP8Io io; + WebPHeaderStructure headers; + + headers.data = data; + headers.data_size = data_size; + headers.have_all_data = 1; + status = WebPParseHeaders(&headers); // Process Pre-VP8 chunks. + if (status != VP8_STATUS_OK) { + return status; + } + + assert(params != NULL); + if (!VP8InitIo(&io)) { + return VP8_STATUS_INVALID_PARAM; + } + io.data = headers.data + headers.offset; + io.data_size = headers.data_size - headers.offset; + WebPInitCustomIo(params, &io); // Plug the I/O functions. + + if (!headers.is_lossless) { + VP8Decoder* const dec = VP8New(); + if (dec == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + dec->alpha_data_ = headers.alpha_data; + dec->alpha_data_size_ = headers.alpha_data_size; + + // Decode bitstream header, update io->width/io->height. + if (!VP8GetHeaders(dec, &io)) { + status = dec->status_; // An error occurred. Grab error status. + } else { + // Allocate/check output buffers. + status = WebPAllocateDecBuffer(io.width, io.height, params->options, + params->output); + if (status == VP8_STATUS_OK) { // Decode + // This change must be done before calling VP8Decode() + dec->mt_method_ = VP8GetThreadMethod(params->options, &headers, + io.width, io.height); + VP8InitDithering(params->options, dec); + if (!VP8Decode(dec, &io)) { + status = dec->status_; + } + } + } + VP8Delete(dec); + } else { + VP8LDecoder* const dec = VP8LNew(); + if (dec == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + if (!VP8LDecodeHeader(dec, &io)) { + status = dec->status_; // An error occurred. Grab error status. + } else { + // Allocate/check output buffers. + status = WebPAllocateDecBuffer(io.width, io.height, params->options, + params->output); + if (status == VP8_STATUS_OK) { // Decode + if (!VP8LDecodeImage(dec)) { + status = dec->status_; + } + } + } + VP8LDelete(dec); + } + + if (status != VP8_STATUS_OK) { + WebPFreeDecBuffer(params->output); + } else { + if (params->options != NULL && params->options->flip) { + // This restores the original stride values if options->flip was used + // during the call to WebPAllocateDecBuffer above. + status = WebPFlipBuffer(params->output); + } + } + return status; +} + +// Helpers +WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace, + const uint8_t* const data, + size_t data_size, + uint8_t* const rgba, + int stride, size_t size) { + WebPDecParams params; + WebPDecBuffer buf; + if (rgba == NULL || !WebPInitDecBuffer(&buf)) { + return NULL; + } + WebPResetDecParams(¶ms); + params.output = &buf; + buf.colorspace = colorspace; + buf.u.RGBA.rgba = rgba; + buf.u.RGBA.stride = stride; + buf.u.RGBA.size = size; + buf.is_external_memory = 1; + if (DecodeInto(data, data_size, ¶ms) != VP8_STATUS_OK) { + return NULL; + } + return rgba; +} + +uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size, + uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride) { + WebPDecParams params; + WebPDecBuffer output; + if (luma == NULL || !WebPInitDecBuffer(&output)) return NULL; + WebPResetDecParams(¶ms); + params.output = &output; + output.colorspace = MODE_YUV; + output.u.YUVA.y = luma; + output.u.YUVA.y_stride = luma_stride; + output.u.YUVA.y_size = luma_size; + output.u.YUVA.u = u; + output.u.YUVA.u_stride = u_stride; + output.u.YUVA.u_size = u_size; + output.u.YUVA.v = v; + output.u.YUVA.v_stride = v_stride; + output.u.YUVA.v_size = v_size; + output.is_external_memory = 1; + if (DecodeInto(data, data_size, ¶ms) != VP8_STATUS_OK) { + return NULL; + } + return luma; +} + +//------------------------------------------------------------------------------ + +WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode, + const uint8_t* const data, + size_t data_size, int* const width, + int* const height, + WebPDecBuffer* const keep_info) { + WebPDecParams params; + WebPDecBuffer output; + + if (!WebPInitDecBuffer(&output)) { + return NULL; + } + WebPResetDecParams(¶ms); + params.output = &output; + output.colorspace = mode; + + // Retrieve (and report back) the required dimensions from bitstream. + if (!WebPGetInfo(data, data_size, &output.width, &output.height)) { + return NULL; + } + if (width != NULL) *width = output.width; + if (height != NULL) *height = output.height; + + // Decode + if (DecodeInto(data, data_size, ¶ms) != VP8_STATUS_OK) { + return NULL; + } + if (keep_info != NULL) { // keep track of the side-info + WebPCopyDecBuffer(&output, keep_info); + } + // return decoded samples (don't clear 'output'!) + return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y; +} + +uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_RGB, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_RGBA, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_ARGB, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_BGR, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_BGRA, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size, + int* width, int* height, uint8_t** u, uint8_t** v, + int* stride, int* uv_stride) { + // data, width and height are checked by Decode(). + if (u == NULL || v == NULL || stride == NULL || uv_stride == NULL) { + return NULL; + } + + { + WebPDecBuffer output; // only to preserve the side-infos + uint8_t* const out = Decode(MODE_YUV, data, data_size, + width, height, &output); + + if (out != NULL) { + const WebPYUVABuffer* const buf = &output.u.YUVA; + *u = buf->u; + *v = buf->v; + *stride = buf->y_stride; + *uv_stride = buf->u_stride; + assert(buf->u_stride == buf->v_stride); + } + return out; + } +} + +static void DefaultFeatures(WebPBitstreamFeatures* const features) { + assert(features != NULL); + memset(features, 0, sizeof(*features)); +} + +static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size, + WebPBitstreamFeatures* const features) { + if (features == NULL || data == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + DefaultFeatures(features); + + // Only parse enough of the data to retrieve the features. + return ParseHeadersInternal(data, data_size, + &features->width, &features->height, + &features->has_alpha, &features->has_animation, + &features->format, NULL); +} + +//------------------------------------------------------------------------------ +// WebPGetInfo() + +int WebPGetInfo(const uint8_t* data, size_t data_size, + int* width, int* height) { + WebPBitstreamFeatures features; + + if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) { + return 0; + } + + if (width != NULL) { + *width = features.width; + } + if (height != NULL) { + *height = features.height; + } + + return 1; +} + +//------------------------------------------------------------------------------ +// Advance decoding API + +int WebPInitDecoderConfigInternal(WebPDecoderConfig* config, + int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { + return 0; // version mismatch + } + if (config == NULL) { + return 0; + } + memset(config, 0, sizeof(*config)); + DefaultFeatures(&config->input); + if (!WebPInitDecBuffer(&config->output)) { + return 0; + } + return 1; +} + +VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, + WebPBitstreamFeatures* features, + int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { + return VP8_STATUS_INVALID_PARAM; // version mismatch + } + if (features == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + return GetFeatures(data, data_size, features); +} + +VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, + WebPDecoderConfig* config) { + WebPDecParams params; + VP8StatusCode status; + + if (config == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + + status = GetFeatures(data, data_size, &config->input); + if (status != VP8_STATUS_OK) { + if (status == VP8_STATUS_NOT_ENOUGH_DATA) { + return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error. + } + return status; + } + + WebPResetDecParams(¶ms); + params.options = &config->options; + params.output = &config->output; + if (WebPAvoidSlowMemory(params.output, &config->input)) { + // decoding to slow memory: use a temporary in-mem buffer to decode into. + WebPDecBuffer in_mem_buffer; + if (!WebPInitDecBuffer(&in_mem_buffer)) { + return VP8_STATUS_INVALID_PARAM; + } + in_mem_buffer.colorspace = config->output.colorspace; + in_mem_buffer.width = config->input.width; + in_mem_buffer.height = config->input.height; + params.output = &in_mem_buffer; + status = DecodeInto(data, data_size, ¶ms); + if (status == VP8_STATUS_OK) { // do the slow-copy + status = WebPCopyDecBufferPixels(&in_mem_buffer, &config->output); + } + WebPFreeDecBuffer(&in_mem_buffer); + } else { + status = DecodeInto(data, data_size, ¶ms); + } + + return status; +} + +//------------------------------------------------------------------------------ +// Cropping and rescaling. + +int WebPCheckCropDimensions(int image_width, int image_height, + int x, int y, int w, int h) { + return !(x < 0 || y < 0 || w <= 0 || h <= 0 || + x >= image_width || w > image_width || w > image_width - x || + y >= image_height || h > image_height || h > image_height - y); +} + +int WebPIoInitFromOptions(const WebPDecoderOptions* const options, + VP8Io* const io, WEBP_CSP_MODE src_colorspace) { + const int W = io->width; + const int H = io->height; + int x = 0, y = 0, w = W, h = H; + + // Cropping + io->use_cropping = (options != NULL) && options->use_cropping; + if (io->use_cropping) { + w = options->crop_width; + h = options->crop_height; + x = options->crop_left; + y = options->crop_top; + if (!WebPIsRGBMode(src_colorspace)) { // only snap for YUV420 + x &= ~1; + y &= ~1; + } + if (!WebPCheckCropDimensions(W, H, x, y, w, h)) { + return 0; // out of frame boundary error + } + } + io->crop_left = x; + io->crop_top = y; + io->crop_right = x + w; + io->crop_bottom = y + h; + io->mb_w = w; + io->mb_h = h; + + // Scaling + io->use_scaling = (options != NULL) && options->use_scaling; + if (io->use_scaling) { + int scaled_width = options->scaled_width; + int scaled_height = options->scaled_height; + if (!WebPRescalerGetScaledDimensions(w, h, &scaled_width, &scaled_height)) { + return 0; + } + io->scaled_width = scaled_width; + io->scaled_height = scaled_height; + } + + // Filter + io->bypass_filtering = (options != NULL) && options->bypass_filtering; + + // Fancy upsampler +#ifdef FANCY_UPSAMPLING + io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling); +#endif + + if (io->use_scaling) { + // disable filter (only for large downscaling ratio). + io->bypass_filtering |= (io->scaled_width < W * 3 / 4) && + (io->scaled_height < H * 3 / 4); + io->fancy_upsampling = 0; + } + return 1; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dec/webpi_dec.h b/libraries/webp/src/dec/webpi_dec.h new file mode 100644 index 00000000000..4ff1d141e4f --- /dev/null +++ b/libraries/webp/src/dec/webpi_dec.h @@ -0,0 +1,139 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Internal header: WebP decoding parameters and custom IO on buffer +// +// Author: somnath@google.com (Somnath Banerjee) + +#ifndef WEBP_DEC_WEBPI_DEC_H_ +#define WEBP_DEC_WEBPI_DEC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "src/utils/rescaler_utils.h" +#include "src/dec/vp8_dec.h" +#include "include/webp/decode.h" + +//------------------------------------------------------------------------------ +// WebPDecParams: Decoding output parameters. Transient internal object. + +typedef struct WebPDecParams WebPDecParams; +typedef int (*OutputFunc)(const VP8Io* const io, WebPDecParams* const p); +typedef int (*OutputAlphaFunc)(const VP8Io* const io, WebPDecParams* const p, + int expected_num_out_lines); +typedef int (*OutputRowFunc)(WebPDecParams* const p, int y_pos, + int max_out_lines); + +struct WebPDecParams { + WebPDecBuffer* output; // output buffer. + uint8_t* tmp_y, *tmp_u, *tmp_v; // cache for the fancy upsampler + // or used for tmp rescaling + + int last_y; // coordinate of the line that was last output + const WebPDecoderOptions* options; // if not NULL, use alt decoding features + + WebPRescaler* scaler_y, *scaler_u, *scaler_v, *scaler_a; // rescalers + void* memory; // overall scratch memory for the output work. + + OutputFunc emit; // output RGB or YUV samples + OutputAlphaFunc emit_alpha; // output alpha channel + OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values +}; + +// Should be called first, before any use of the WebPDecParams object. +void WebPResetDecParams(WebPDecParams* const params); + +//------------------------------------------------------------------------------ +// Header parsing helpers + +// Structure storing a description of the RIFF headers. +typedef struct { + const uint8_t* data; // input buffer + size_t data_size; // input buffer size + int have_all_data; // true if all data is known to be available + size_t offset; // offset to main data chunk (VP8 or VP8L) + const uint8_t* alpha_data; // points to alpha chunk (if present) + size_t alpha_data_size; // alpha chunk size + size_t compressed_size; // VP8/VP8L compressed data size + size_t riff_size; // size of the riff payload (or 0 if absent) + int is_lossless; // true if a VP8L chunk is present +} WebPHeaderStructure; + +// Skips over all valid chunks prior to the first VP8/VP8L frame header. +// Returns: VP8_STATUS_OK, VP8_STATUS_BITSTREAM_ERROR (invalid header/chunk), +// VP8_STATUS_NOT_ENOUGH_DATA (partial input) or VP8_STATUS_UNSUPPORTED_FEATURE +// in the case of non-decodable features (animation for instance). +// In 'headers', compressed_size, offset, alpha_data, alpha_size, and lossless +// fields are updated appropriately upon success. +VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers); + +//------------------------------------------------------------------------------ +// Misc utils + +// Returns true if crop dimensions are within image bounds. +int WebPCheckCropDimensions(int image_width, int image_height, + int x, int y, int w, int h); + +// Initializes VP8Io with custom setup, io and teardown functions. The default +// hooks will use the supplied 'params' as io->opaque handle. +void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io); + +// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers +// to the *compressed* format, not the output one. +WEBP_NODISCARD int WebPIoInitFromOptions( + const WebPDecoderOptions* const options, VP8Io* const io, + WEBP_CSP_MODE src_colorspace); + +//------------------------------------------------------------------------------ +// Internal functions regarding WebPDecBuffer memory (in buffer.c). +// Don't really need to be externally visible for now. + +// Prepare 'buffer' with the requested initial dimensions width/height. +// If no external storage is supplied, initializes buffer by allocating output +// memory and setting up the stride information. Validate the parameters. Return +// an error code in case of problem (no memory, or invalid stride / size / +// dimension / etc.). If *options is not NULL, also verify that the options' +// parameters are valid and apply them to the width/height dimensions of the +// output buffer. This takes cropping / scaling / rotation into account. +// Also incorporates the options->flip flag to flip the buffer parameters if +// needed. +VP8StatusCode WebPAllocateDecBuffer(int width, int height, + const WebPDecoderOptions* const options, + WebPDecBuffer* const buffer); + +// Flip buffer vertically by negating the various strides. +VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer); + +// Copy 'src' into 'dst' buffer, making sure 'dst' is not marked as owner of the +// memory (still held by 'src'). No pixels are copied. +void WebPCopyDecBuffer(const WebPDecBuffer* const src, + WebPDecBuffer* const dst); + +// Copy and transfer ownership from src to dst (beware of parameter order!) +void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst); + +// Copy pixels from 'src' into a *preallocated* 'dst' buffer. Returns +// VP8_STATUS_INVALID_PARAM if the 'dst' is not set up correctly for the copy. +VP8StatusCode WebPCopyDecBufferPixels(const WebPDecBuffer* const src, + WebPDecBuffer* const dst); + +// Returns true if decoding will be slow with the current configuration +// and bitstream features. +int WebPAvoidSlowMemory(const WebPDecBuffer* const output, + const WebPBitstreamFeatures* const features); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DEC_WEBPI_DEC_H_ diff --git a/libraries/webp/src/demux/anim_decode.c b/libraries/webp/src/demux/anim_decode.c new file mode 100644 index 00000000000..03b8dc62578 --- /dev/null +++ b/libraries/webp/src/demux/anim_decode.c @@ -0,0 +1,479 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// AnimDecoder implementation. +// + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include +#include + +#include "src/utils/utils.h" +#include "include/webp/decode.h" +#include "include/webp/demux.h" +#include "include/webp/types.h" + +#define NUM_CHANNELS 4 + +// Channel extraction from a uint32_t representation of a uint8_t RGBA/BGRA +// buffer. +#ifdef WORDS_BIGENDIAN +#define CHANNEL_SHIFT(i) (24 - (i) * 8) +#else +#define CHANNEL_SHIFT(i) ((i) * 8) +#endif + +typedef void (*BlendRowFunc)(uint32_t* const, const uint32_t* const, int); +static void BlendPixelRowNonPremult(uint32_t* const src, + const uint32_t* const dst, int num_pixels); +static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst, + int num_pixels); + +struct WebPAnimDecoder { + WebPDemuxer* demux_; // Demuxer created from given WebP bitstream. + WebPDecoderConfig config_; // Decoder config. + // Note: we use a pointer to a function blending multiple pixels at a time to + // allow possible inlining of per-pixel blending function. + BlendRowFunc blend_func_; // Pointer to the chose blend row function. + WebPAnimInfo info_; // Global info about the animation. + uint8_t* curr_frame_; // Current canvas (not disposed). + uint8_t* prev_frame_disposed_; // Previous canvas (properly disposed). + int prev_frame_timestamp_; // Previous frame timestamp (milliseconds). + WebPIterator prev_iter_; // Iterator object for previous frame. + int prev_frame_was_keyframe_; // True if previous frame was a keyframe. + int next_frame_; // Index of the next frame to be decoded + // (starting from 1). +}; + +static void DefaultDecoderOptions(WebPAnimDecoderOptions* const dec_options) { + dec_options->color_mode = MODE_RGBA; + dec_options->use_threads = 0; +} + +int WebPAnimDecoderOptionsInitInternal(WebPAnimDecoderOptions* dec_options, + int abi_version) { + if (dec_options == NULL || + WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) { + return 0; + } + DefaultDecoderOptions(dec_options); + return 1; +} + +WEBP_NODISCARD static int ApplyDecoderOptions( + const WebPAnimDecoderOptions* const dec_options, + WebPAnimDecoder* const dec) { + WEBP_CSP_MODE mode; + WebPDecoderConfig* config = &dec->config_; + assert(dec_options != NULL); + + mode = dec_options->color_mode; + if (mode != MODE_RGBA && mode != MODE_BGRA && + mode != MODE_rgbA && mode != MODE_bgrA) { + return 0; + } + dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA) + ? &BlendPixelRowNonPremult + : &BlendPixelRowPremult; + if (!WebPInitDecoderConfig(config)) { + return 0; + } + config->output.colorspace = mode; + config->output.is_external_memory = 1; + config->options.use_threads = dec_options->use_threads; + // Note: config->output.u.RGBA is set at the time of decoding each frame. + return 1; +} + +WebPAnimDecoder* WebPAnimDecoderNewInternal( + const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options, + int abi_version) { + WebPAnimDecoderOptions options; + WebPAnimDecoder* dec = NULL; + WebPBitstreamFeatures features; + if (webp_data == NULL || + WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) { + return NULL; + } + + // Validate the bitstream before doing expensive allocations. The demuxer may + // be more tolerant than the decoder. + if (WebPGetFeatures(webp_data->bytes, webp_data->size, &features) != + VP8_STATUS_OK) { + return NULL; + } + + // Note: calloc() so that the pointer members are initialized to NULL. + dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); + if (dec == NULL) goto Error; + + if (dec_options != NULL) { + options = *dec_options; + } else { + DefaultDecoderOptions(&options); + } + if (!ApplyDecoderOptions(&options, dec)) goto Error; + + dec->demux_ = WebPDemux(webp_data); + if (dec->demux_ == NULL) goto Error; + + dec->info_.canvas_width = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_WIDTH); + dec->info_.canvas_height = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_HEIGHT); + dec->info_.loop_count = WebPDemuxGetI(dec->demux_, WEBP_FF_LOOP_COUNT); + dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR); + dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT); + + // Note: calloc() because we fill frame with zeroes as well. + dec->curr_frame_ = (uint8_t*)WebPSafeCalloc( + dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height); + if (dec->curr_frame_ == NULL) goto Error; + dec->prev_frame_disposed_ = (uint8_t*)WebPSafeCalloc( + dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height); + if (dec->prev_frame_disposed_ == NULL) goto Error; + + WebPAnimDecoderReset(dec); + return dec; + + Error: + WebPAnimDecoderDelete(dec); + return NULL; +} + +int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) { + if (dec == NULL || info == NULL) return 0; + *info = dec->info_; + return 1; +} + +// Returns true if the frame covers the full canvas. +static int IsFullFrame(int width, int height, int canvas_width, + int canvas_height) { + return (width == canvas_width && height == canvas_height); +} + +// Clear the canvas to transparent. +WEBP_NODISCARD static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width, + uint32_t canvas_height) { + const uint64_t size = + (uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf); + if (!CheckSizeOverflow(size)) return 0; + memset(buf, 0, (size_t)size); + return 1; +} + +// Clear given frame rectangle to transparent. +static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset, + int y_offset, int width, int height) { + int j; + assert(width * NUM_CHANNELS <= buf_stride); + buf += y_offset * buf_stride + x_offset * NUM_CHANNELS; + for (j = 0; j < height; ++j) { + memset(buf, 0, width * NUM_CHANNELS); + buf += buf_stride; + } +} + +// Copy width * height pixels from 'src' to 'dst'. +WEBP_NODISCARD static int CopyCanvas(const uint8_t* src, uint8_t* dst, + uint32_t width, uint32_t height) { + const uint64_t size = (uint64_t)width * height * NUM_CHANNELS; + if (!CheckSizeOverflow(size)) return 0; + assert(src != NULL && dst != NULL); + memcpy(dst, src, (size_t)size); + return 1; +} + +// Returns true if the current frame is a key-frame. +static int IsKeyFrame(const WebPIterator* const curr, + const WebPIterator* const prev, + int prev_frame_was_key_frame, + int canvas_width, int canvas_height) { + if (curr->frame_num == 1) { + return 1; + } else if ((!curr->has_alpha || curr->blend_method == WEBP_MUX_NO_BLEND) && + IsFullFrame(curr->width, curr->height, + canvas_width, canvas_height)) { + return 1; + } else { + return (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) && + (IsFullFrame(prev->width, prev->height, canvas_width, + canvas_height) || + prev_frame_was_key_frame); + } +} + + +// Blend a single channel of 'src' over 'dst', given their alpha channel values. +// 'src' and 'dst' are assumed to be NOT pre-multiplied by alpha. +static uint8_t BlendChannelNonPremult(uint32_t src, uint8_t src_a, + uint32_t dst, uint8_t dst_a, + uint32_t scale, int shift) { + const uint8_t src_channel = (src >> shift) & 0xff; + const uint8_t dst_channel = (dst >> shift) & 0xff; + const uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a; + assert(blend_unscaled < (1ULL << 32) / scale); + return (blend_unscaled * scale) >> CHANNEL_SHIFT(3); +} + +// Blend 'src' over 'dst' assuming they are NOT pre-multiplied by alpha. +static uint32_t BlendPixelNonPremult(uint32_t src, uint32_t dst) { + const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff; + + if (src_a == 0) { + return dst; + } else { + const uint8_t dst_a = (dst >> CHANNEL_SHIFT(3)) & 0xff; + // This is the approximate integer arithmetic for the actual formula: + // dst_factor_a = (dst_a * (255 - src_a)) / 255. + const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8; + const uint8_t blend_a = src_a + dst_factor_a; + const uint32_t scale = (1UL << 24) / blend_a; + + const uint8_t blend_r = BlendChannelNonPremult( + src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(0)); + const uint8_t blend_g = BlendChannelNonPremult( + src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(1)); + const uint8_t blend_b = BlendChannelNonPremult( + src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(2)); + assert(src_a + dst_factor_a < 256); + + return ((uint32_t)blend_r << CHANNEL_SHIFT(0)) | + ((uint32_t)blend_g << CHANNEL_SHIFT(1)) | + ((uint32_t)blend_b << CHANNEL_SHIFT(2)) | + ((uint32_t)blend_a << CHANNEL_SHIFT(3)); + } +} + +// Blend 'num_pixels' in 'src' over 'dst' assuming they are NOT pre-multiplied +// by alpha. +static void BlendPixelRowNonPremult(uint32_t* const src, + const uint32_t* const dst, int num_pixels) { + int i; + for (i = 0; i < num_pixels; ++i) { + const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff; + if (src_alpha != 0xff) { + src[i] = BlendPixelNonPremult(src[i], dst[i]); + } + } +} + +// Individually multiply each channel in 'pix' by 'scale'. +static WEBP_INLINE uint32_t ChannelwiseMultiply(uint32_t pix, uint32_t scale) { + uint32_t mask = 0x00FF00FF; + uint32_t rb = ((pix & mask) * scale) >> 8; + uint32_t ag = ((pix >> 8) & mask) * scale; + return (rb & mask) | (ag & ~mask); +} + +// Blend 'src' over 'dst' assuming they are pre-multiplied by alpha. +static uint32_t BlendPixelPremult(uint32_t src, uint32_t dst) { + const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff; + return src + ChannelwiseMultiply(dst, 256 - src_a); +} + +// Blend 'num_pixels' in 'src' over 'dst' assuming they are pre-multiplied by +// alpha. +static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst, + int num_pixels) { + int i; + for (i = 0; i < num_pixels; ++i) { + const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff; + if (src_alpha != 0xff) { + src[i] = BlendPixelPremult(src[i], dst[i]); + } + } +} + +// Returns two ranges ( pairs) at row 'canvas_y', that belong to +// 'src' but not 'dst'. A point range is empty if the corresponding width is 0. +static void FindBlendRangeAtRow(const WebPIterator* const src, + const WebPIterator* const dst, int canvas_y, + int* const left1, int* const width1, + int* const left2, int* const width2) { + const int src_max_x = src->x_offset + src->width; + const int dst_max_x = dst->x_offset + dst->width; + const int dst_max_y = dst->y_offset + dst->height; + assert(canvas_y >= src->y_offset && canvas_y < (src->y_offset + src->height)); + *left1 = -1; + *width1 = 0; + *left2 = -1; + *width2 = 0; + + if (canvas_y < dst->y_offset || canvas_y >= dst_max_y || + src->x_offset >= dst_max_x || src_max_x <= dst->x_offset) { + *left1 = src->x_offset; + *width1 = src->width; + return; + } + + if (src->x_offset < dst->x_offset) { + *left1 = src->x_offset; + *width1 = dst->x_offset - src->x_offset; + } + + if (src_max_x > dst_max_x) { + *left2 = dst_max_x; + *width2 = src_max_x - dst_max_x; + } +} + +int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, + uint8_t** buf_ptr, int* timestamp_ptr) { + WebPIterator iter; + uint32_t width; + uint32_t height; + int is_key_frame; + int timestamp; + BlendRowFunc blend_row; + + if (dec == NULL || buf_ptr == NULL || timestamp_ptr == NULL) return 0; + if (!WebPAnimDecoderHasMoreFrames(dec)) return 0; + + width = dec->info_.canvas_width; + height = dec->info_.canvas_height; + blend_row = dec->blend_func_; + + // Get compressed frame. + if (!WebPDemuxGetFrame(dec->demux_, dec->next_frame_, &iter)) { + return 0; + } + timestamp = dec->prev_frame_timestamp_ + iter.duration; + + // Initialize. + is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_, + dec->prev_frame_was_keyframe_, width, height); + if (is_key_frame) { + if (!ZeroFillCanvas(dec->curr_frame_, width, height)) { + goto Error; + } + } else { + if (!CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_, + width, height)) { + goto Error; + } + } + + // Decode. + { + const uint8_t* in = iter.fragment.bytes; + const size_t in_size = iter.fragment.size; + const uint32_t stride = width * NUM_CHANNELS; // at most 25 + 2 bits + const uint64_t out_offset = (uint64_t)iter.y_offset * stride + + (uint64_t)iter.x_offset * NUM_CHANNELS; // 53b + const uint64_t size = (uint64_t)iter.height * stride; // at most 25 + 27b + WebPDecoderConfig* const config = &dec->config_; + WebPRGBABuffer* const buf = &config->output.u.RGBA; + if ((size_t)size != size) goto Error; + buf->stride = (int)stride; + buf->size = (size_t)size; + buf->rgba = dec->curr_frame_ + out_offset; + + if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) { + goto Error; + } + } + + // During the decoding of current frame, we may have set some pixels to be + // transparent (i.e. alpha < 255). However, the value of each of these + // pixels should have been determined by blending it against the value of + // that pixel in the previous frame if blending method of is WEBP_MUX_BLEND. + if (iter.frame_num > 1 && iter.blend_method == WEBP_MUX_BLEND && + !is_key_frame) { + if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_NONE) { + int y; + // Blend transparent pixels with pixels in previous canvas. + for (y = 0; y < iter.height; ++y) { + const size_t offset = + (iter.y_offset + y) * width + iter.x_offset; + blend_row((uint32_t*)dec->curr_frame_ + offset, + (uint32_t*)dec->prev_frame_disposed_ + offset, iter.width); + } + } else { + int y; + assert(dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND); + // We need to blend a transparent pixel with its value just after + // initialization. That is, blend it with: + // * Fully transparent pixel if it belongs to prevRect <-- No-op. + // * The pixel in the previous canvas otherwise <-- Need alpha-blending. + for (y = 0; y < iter.height; ++y) { + const int canvas_y = iter.y_offset + y; + int left1, width1, left2, width2; + FindBlendRangeAtRow(&iter, &dec->prev_iter_, canvas_y, &left1, &width1, + &left2, &width2); + if (width1 > 0) { + const size_t offset1 = canvas_y * width + left1; + blend_row((uint32_t*)dec->curr_frame_ + offset1, + (uint32_t*)dec->prev_frame_disposed_ + offset1, width1); + } + if (width2 > 0) { + const size_t offset2 = canvas_y * width + left2; + blend_row((uint32_t*)dec->curr_frame_ + offset2, + (uint32_t*)dec->prev_frame_disposed_ + offset2, width2); + } + } + } + } + + // Update info of the previous frame and dispose it for the next iteration. + dec->prev_frame_timestamp_ = timestamp; + WebPDemuxReleaseIterator(&dec->prev_iter_); + dec->prev_iter_ = iter; + dec->prev_frame_was_keyframe_ = is_key_frame; + if (!CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height)) { + goto Error; + } + if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { + ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS, + dec->prev_iter_.x_offset, dec->prev_iter_.y_offset, + dec->prev_iter_.width, dec->prev_iter_.height); + } + ++dec->next_frame_; + + // All OK, fill in the values. + *buf_ptr = dec->curr_frame_; + *timestamp_ptr = timestamp; + return 1; + + Error: + WebPDemuxReleaseIterator(&iter); + return 0; +} + +int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) { + if (dec == NULL) return 0; + return (dec->next_frame_ <= (int)dec->info_.frame_count); +} + +void WebPAnimDecoderReset(WebPAnimDecoder* dec) { + if (dec != NULL) { + dec->prev_frame_timestamp_ = 0; + WebPDemuxReleaseIterator(&dec->prev_iter_); + memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_)); + dec->prev_frame_was_keyframe_ = 0; + dec->next_frame_ = 1; + } +} + +const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) { + if (dec == NULL) return NULL; + return dec->demux_; +} + +void WebPAnimDecoderDelete(WebPAnimDecoder* dec) { + if (dec != NULL) { + WebPDemuxReleaseIterator(&dec->prev_iter_); + WebPDemuxDelete(dec->demux_); + WebPSafeFree(dec->curr_frame_); + WebPSafeFree(dec->prev_frame_disposed_); + WebPSafeFree(dec); + } +} diff --git a/libraries/webp/src/demux/demux.c b/libraries/webp/src/demux/demux.c new file mode 100644 index 00000000000..d1aa4753690 --- /dev/null +++ b/libraries/webp/src/demux/demux.c @@ -0,0 +1,975 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebP container demux. +// + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include +#include +#include + +#include "src/utils/utils.h" +#include "include/webp/decode.h" // WebPGetFeatures +#include "include/webp/demux.h" +#include "include/webp/format_constants.h" + +#define DMUX_MAJ_VERSION 1 +#define DMUX_MIN_VERSION 3 +#define DMUX_REV_VERSION 2 + +typedef struct { + size_t start_; // start location of the data + size_t end_; // end location + size_t riff_end_; // riff chunk end location, can be > end_. + size_t buf_size_; // size of the buffer + const uint8_t* buf_; +} MemBuffer; + +typedef struct { + size_t offset_; + size_t size_; +} ChunkData; + +typedef struct Frame { + int x_offset_, y_offset_; + int width_, height_; + int has_alpha_; + int duration_; + WebPMuxAnimDispose dispose_method_; + WebPMuxAnimBlend blend_method_; + int frame_num_; + int complete_; // img_components_ contains a full image. + ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH + struct Frame* next_; +} Frame; + +typedef struct Chunk { + ChunkData data_; + struct Chunk* next_; +} Chunk; + +struct WebPDemuxer { + MemBuffer mem_; + WebPDemuxState state_; + int is_ext_format_; + uint32_t feature_flags_; + int canvas_width_, canvas_height_; + int loop_count_; + uint32_t bgcolor_; + int num_frames_; + Frame* frames_; + Frame** frames_tail_; + Chunk* chunks_; // non-image chunks + Chunk** chunks_tail_; +}; + +typedef enum { + PARSE_OK, + PARSE_NEED_MORE_DATA, + PARSE_ERROR +} ParseStatus; + +typedef struct ChunkParser { + uint8_t id[4]; + ParseStatus (*parse)(WebPDemuxer* const dmux); + int (*valid)(const WebPDemuxer* const dmux); +} ChunkParser; + +static ParseStatus ParseSingleImage(WebPDemuxer* const dmux); +static ParseStatus ParseVP8X(WebPDemuxer* const dmux); +static int IsValidSimpleFormat(const WebPDemuxer* const dmux); +static int IsValidExtendedFormat(const WebPDemuxer* const dmux); + +static const ChunkParser kMasterChunks[] = { + { { 'V', 'P', '8', ' ' }, ParseSingleImage, IsValidSimpleFormat }, + { { 'V', 'P', '8', 'L' }, ParseSingleImage, IsValidSimpleFormat }, + { { 'V', 'P', '8', 'X' }, ParseVP8X, IsValidExtendedFormat }, + { { '0', '0', '0', '0' }, NULL, NULL }, +}; + +//------------------------------------------------------------------------------ + +int WebPGetDemuxVersion(void) { + return (DMUX_MAJ_VERSION << 16) | (DMUX_MIN_VERSION << 8) | DMUX_REV_VERSION; +} + +// ----------------------------------------------------------------------------- +// MemBuffer + +static int RemapMemBuffer(MemBuffer* const mem, + const uint8_t* data, size_t size) { + if (size < mem->buf_size_) return 0; // can't remap to a shorter buffer! + + mem->buf_ = data; + mem->end_ = mem->buf_size_ = size; + return 1; +} + +static int InitMemBuffer(MemBuffer* const mem, + const uint8_t* data, size_t size) { + memset(mem, 0, sizeof(*mem)); + return RemapMemBuffer(mem, data, size); +} + +// Return the remaining data size available in 'mem'. +static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) { + return (mem->end_ - mem->start_); +} + +// Return true if 'size' exceeds the end of the RIFF chunk. +static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) { + return (size > mem->riff_end_ - mem->start_); +} + +static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) { + mem->start_ += size; +} + +static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) { + mem->start_ -= size; +} + +static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) { + return mem->buf_ + mem->start_; +} + +// Read from 'mem' and skip the read bytes. +static WEBP_INLINE uint8_t ReadByte(MemBuffer* const mem) { + const uint8_t byte = mem->buf_[mem->start_]; + Skip(mem, 1); + return byte; +} + +static WEBP_INLINE int ReadLE16s(MemBuffer* const mem) { + const uint8_t* const data = mem->buf_ + mem->start_; + const int val = GetLE16(data); + Skip(mem, 2); + return val; +} + +static WEBP_INLINE int ReadLE24s(MemBuffer* const mem) { + const uint8_t* const data = mem->buf_ + mem->start_; + const int val = GetLE24(data); + Skip(mem, 3); + return val; +} + +static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) { + const uint8_t* const data = mem->buf_ + mem->start_; + const uint32_t val = GetLE32(data); + Skip(mem, 4); + return val; +} + +// ----------------------------------------------------------------------------- +// Secondary chunk parsing + +static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) { + *dmux->chunks_tail_ = chunk; + chunk->next_ = NULL; + dmux->chunks_tail_ = &chunk->next_; +} + +// Add a frame to the end of the list, ensuring the last frame is complete. +// Returns true on success, false otherwise. +static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { + const Frame* const last_frame = *dmux->frames_tail_; + if (last_frame != NULL && !last_frame->complete_) return 0; + + *dmux->frames_tail_ = frame; + frame->next_ = NULL; + dmux->frames_tail_ = &frame->next_; + return 1; +} + +static void SetFrameInfo(size_t start_offset, size_t size, + int frame_num, int complete, + const WebPBitstreamFeatures* const features, + Frame* const frame) { + frame->img_components_[0].offset_ = start_offset; + frame->img_components_[0].size_ = size; + frame->width_ = features->width; + frame->height_ = features->height; + frame->has_alpha_ |= features->has_alpha; + frame->frame_num_ = frame_num; + frame->complete_ = complete; +} + +// Store image bearing chunks to 'frame'. 'min_size' is an optional size +// requirement, it may be zero. +static ParseStatus StoreFrame(int frame_num, uint32_t min_size, + MemBuffer* const mem, Frame* const frame) { + int alpha_chunks = 0; + int image_chunks = 0; + int done = (MemDataSize(mem) < CHUNK_HEADER_SIZE || + MemDataSize(mem) < min_size); + ParseStatus status = PARSE_OK; + + if (done) return PARSE_NEED_MORE_DATA; + + do { + const size_t chunk_start_offset = mem->start_; + const uint32_t fourcc = ReadLE32(mem); + const uint32_t payload_size = ReadLE32(mem); + uint32_t payload_size_padded; + size_t payload_available; + size_t chunk_size; + + if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; + + payload_size_padded = payload_size + (payload_size & 1); + payload_available = (payload_size_padded > MemDataSize(mem)) + ? MemDataSize(mem) : payload_size_padded; + chunk_size = CHUNK_HEADER_SIZE + payload_available; + if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR; + if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA; + + switch (fourcc) { + case MKFOURCC('A', 'L', 'P', 'H'): + if (alpha_chunks == 0) { + ++alpha_chunks; + frame->img_components_[1].offset_ = chunk_start_offset; + frame->img_components_[1].size_ = chunk_size; + frame->has_alpha_ = 1; + frame->frame_num_ = frame_num; + Skip(mem, payload_available); + } else { + goto Done; + } + break; + case MKFOURCC('V', 'P', '8', 'L'): + if (alpha_chunks > 0) return PARSE_ERROR; // VP8L has its own alpha + // fall through + case MKFOURCC('V', 'P', '8', ' '): + if (image_chunks == 0) { + // Extract the bitstream features, tolerating failures when the data + // is incomplete. + WebPBitstreamFeatures features; + const VP8StatusCode vp8_status = + WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size, + &features); + if (status == PARSE_NEED_MORE_DATA && + vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) { + return PARSE_NEED_MORE_DATA; + } else if (vp8_status != VP8_STATUS_OK) { + // We have enough data, and yet WebPGetFeatures() failed. + return PARSE_ERROR; + } + ++image_chunks; + SetFrameInfo(chunk_start_offset, chunk_size, frame_num, + status == PARSE_OK, &features, frame); + Skip(mem, payload_available); + } else { + goto Done; + } + break; + Done: + default: + // Restore fourcc/size when moving up one level in parsing. + Rewind(mem, CHUNK_HEADER_SIZE); + done = 1; + break; + } + + if (mem->start_ == mem->riff_end_) { + done = 1; + } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { + status = PARSE_NEED_MORE_DATA; + } + } while (!done && status == PARSE_OK); + + return status; +} + +// Creates a new Frame if 'actual_size' is within bounds and 'mem' contains +// enough data ('min_size') to parse the payload. +// Returns PARSE_OK on success with *frame pointing to the new Frame. +// Returns PARSE_NEED_MORE_DATA with insufficient data, PARSE_ERROR otherwise. +static ParseStatus NewFrame(const MemBuffer* const mem, + uint32_t min_size, uint32_t actual_size, + Frame** frame) { + if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; + if (actual_size < min_size) return PARSE_ERROR; + if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; + + *frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(**frame)); + return (*frame == NULL) ? PARSE_ERROR : PARSE_OK; +} + +// Parse a 'ANMF' chunk and any image bearing chunks that immediately follow. +// 'frame_chunk_size' is the previously validated, padded chunk size. +static ParseStatus ParseAnimationFrame( + WebPDemuxer* const dmux, uint32_t frame_chunk_size) { + const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); + const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE; + int added_frame = 0; + int bits; + MemBuffer* const mem = &dmux->mem_; + Frame* frame; + size_t start_offset; + ParseStatus status = + NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame); + if (status != PARSE_OK) return status; + + frame->x_offset_ = 2 * ReadLE24s(mem); + frame->y_offset_ = 2 * ReadLE24s(mem); + frame->width_ = 1 + ReadLE24s(mem); + frame->height_ = 1 + ReadLE24s(mem); + frame->duration_ = ReadLE24s(mem); + bits = ReadByte(mem); + frame->dispose_method_ = + (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; + frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; + if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { + WebPSafeFree(frame); + return PARSE_ERROR; + } + + // Store a frame only if the animation flag is set there is some data for + // this frame is available. + start_offset = mem->start_; + status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame); + if (status != PARSE_ERROR && mem->start_ - start_offset > anmf_payload_size) { + status = PARSE_ERROR; + } + if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) { + added_frame = AddFrame(dmux, frame); + if (added_frame) { + ++dmux->num_frames_; + } else { + status = PARSE_ERROR; + } + } + + if (!added_frame) WebPSafeFree(frame); + return status; +} + +// General chunk storage, starting with the header at 'start_offset', allowing +// the user to request the payload via a fourcc string. 'size' includes the +// header and the unpadded payload size. +// Returns true on success, false otherwise. +static int StoreChunk(WebPDemuxer* const dmux, + size_t start_offset, uint32_t size) { + Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk)); + if (chunk == NULL) return 0; + + chunk->data_.offset_ = start_offset; + chunk->data_.size_ = size; + AddChunk(dmux, chunk); + return 1; +} + +// ----------------------------------------------------------------------------- +// Primary chunk parsing + +static ParseStatus ReadHeader(MemBuffer* const mem) { + const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE; + uint32_t riff_size; + + // Basic file level validation. + if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; + if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) || + memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) { + return PARSE_ERROR; + } + + riff_size = GetLE32(GetBuffer(mem) + TAG_SIZE); + if (riff_size < CHUNK_HEADER_SIZE) return PARSE_ERROR; + if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; + + // There's no point in reading past the end of the RIFF chunk + mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE; + if (mem->buf_size_ > mem->riff_end_) { + mem->buf_size_ = mem->end_ = mem->riff_end_; + } + + Skip(mem, RIFF_HEADER_SIZE); + return PARSE_OK; +} + +static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { + const size_t min_size = CHUNK_HEADER_SIZE; + MemBuffer* const mem = &dmux->mem_; + Frame* frame; + ParseStatus status; + int image_added = 0; + + if (dmux->frames_ != NULL) return PARSE_ERROR; + if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; + if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; + + frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame)); + if (frame == NULL) return PARSE_ERROR; + + // For the single image case we allow parsing of a partial frame, so no + // minimum size is imposed here. + status = StoreFrame(1, 0, &dmux->mem_, frame); + if (status != PARSE_ERROR) { + const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); + // Clear any alpha when the alpha flag is missing. + if (!has_alpha && frame->img_components_[1].size_ > 0) { + frame->img_components_[1].offset_ = 0; + frame->img_components_[1].size_ = 0; + frame->has_alpha_ = 0; + } + + // Use the frame width/height as the canvas values for non-vp8x files. + // Also, set ALPHA_FLAG if this is a lossless image with alpha. + if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { + dmux->state_ = WEBP_DEMUX_PARSED_HEADER; + dmux->canvas_width_ = frame->width_; + dmux->canvas_height_ = frame->height_; + dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0; + } + if (!AddFrame(dmux, frame)) { + status = PARSE_ERROR; // last frame was left incomplete + } else { + image_added = 1; + dmux->num_frames_ = 1; + } + } + + if (!image_added) WebPSafeFree(frame); + return status; +} + +static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { + const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); + MemBuffer* const mem = &dmux->mem_; + int anim_chunks = 0; + ParseStatus status = PARSE_OK; + + do { + int store_chunk = 1; + const size_t chunk_start_offset = mem->start_; + const uint32_t fourcc = ReadLE32(mem); + const uint32_t chunk_size = ReadLE32(mem); + uint32_t chunk_size_padded; + + if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; + + chunk_size_padded = chunk_size + (chunk_size & 1); + if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR; + + switch (fourcc) { + case MKFOURCC('V', 'P', '8', 'X'): { + return PARSE_ERROR; + } + case MKFOURCC('A', 'L', 'P', 'H'): + case MKFOURCC('V', 'P', '8', ' '): + case MKFOURCC('V', 'P', '8', 'L'): { + // check that this isn't an animation (all frames should be in an ANMF). + if (anim_chunks > 0 || is_animation) return PARSE_ERROR; + + Rewind(mem, CHUNK_HEADER_SIZE); + status = ParseSingleImage(dmux); + break; + } + case MKFOURCC('A', 'N', 'I', 'M'): { + if (chunk_size_padded < ANIM_CHUNK_SIZE) return PARSE_ERROR; + + if (MemDataSize(mem) < chunk_size_padded) { + status = PARSE_NEED_MORE_DATA; + } else if (anim_chunks == 0) { + ++anim_chunks; + dmux->bgcolor_ = ReadLE32(mem); + dmux->loop_count_ = ReadLE16s(mem); + Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE); + } else { + store_chunk = 0; + goto Skip; + } + break; + } + case MKFOURCC('A', 'N', 'M', 'F'): { + if (anim_chunks == 0) return PARSE_ERROR; // 'ANIM' precedes frames. + status = ParseAnimationFrame(dmux, chunk_size_padded); + break; + } + case MKFOURCC('I', 'C', 'C', 'P'): { + store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); + goto Skip; + } + case MKFOURCC('E', 'X', 'I', 'F'): { + store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG); + goto Skip; + } + case MKFOURCC('X', 'M', 'P', ' '): { + store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); + goto Skip; + } + Skip: + default: { + if (chunk_size_padded <= MemDataSize(mem)) { + if (store_chunk) { + // Store only the chunk header and unpadded size as only the payload + // will be returned to the user. + if (!StoreChunk(dmux, chunk_start_offset, + CHUNK_HEADER_SIZE + chunk_size)) { + return PARSE_ERROR; + } + } + Skip(mem, chunk_size_padded); + } else { + status = PARSE_NEED_MORE_DATA; + } + } + } + + if (mem->start_ == mem->riff_end_) { + break; + } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { + status = PARSE_NEED_MORE_DATA; + } + } while (status == PARSE_OK); + + return status; +} + +static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { + MemBuffer* const mem = &dmux->mem_; + uint32_t vp8x_size; + + if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; + + dmux->is_ext_format_ = 1; + Skip(mem, TAG_SIZE); // VP8X + vp8x_size = ReadLE32(mem); + if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; + if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR; + vp8x_size += vp8x_size & 1; + if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR; + if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA; + + dmux->feature_flags_ = ReadByte(mem); + Skip(mem, 3); // Reserved. + dmux->canvas_width_ = 1 + ReadLE24s(mem); + dmux->canvas_height_ = 1 + ReadLE24s(mem); + if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) { + return PARSE_ERROR; // image final dimension is too large + } + Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. + dmux->state_ = WEBP_DEMUX_PARSED_HEADER; + + if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR; + if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; + + return ParseVP8XChunks(dmux); +} + +// ----------------------------------------------------------------------------- +// Format validation + +static int IsValidSimpleFormat(const WebPDemuxer* const dmux) { + const Frame* const frame = dmux->frames_; + if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; + + if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; + if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0; + + if (frame->width_ <= 0 || frame->height_ <= 0) return 0; + return 1; +} + +// If 'exact' is true, check that the image resolution matches the canvas. +// If 'exact' is false, check that the x/y offsets do not exceed the canvas. +static int CheckFrameBounds(const Frame* const frame, int exact, + int canvas_width, int canvas_height) { + if (exact) { + if (frame->x_offset_ != 0 || frame->y_offset_ != 0) { + return 0; + } + if (frame->width_ != canvas_width || frame->height_ != canvas_height) { + return 0; + } + } else { + if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0; + if (frame->width_ + frame->x_offset_ > canvas_width) return 0; + if (frame->height_ + frame->y_offset_ > canvas_height) return 0; + } + return 1; +} + +static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { + const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); + const Frame* f = dmux->frames_; + + if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; + + if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; + if (dmux->loop_count_ < 0) return 0; + if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; + if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream + + while (f != NULL) { + const int cur_frame_set = f->frame_num_; + + // Check frame properties. + for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { + const ChunkData* const image = f->img_components_; + const ChunkData* const alpha = f->img_components_ + 1; + + if (!is_animation && f->frame_num_ > 1) return 0; + + if (f->complete_) { + if (alpha->size_ == 0 && image->size_ == 0) return 0; + // Ensure alpha precedes image bitstream. + if (alpha->size_ > 0 && alpha->offset_ > image->offset_) { + return 0; + } + + if (f->width_ <= 0 || f->height_ <= 0) return 0; + } else { + // There shouldn't be a partial frame in a complete file. + if (dmux->state_ == WEBP_DEMUX_DONE) return 0; + + // Ensure alpha precedes image bitstream. + if (alpha->size_ > 0 && image->size_ > 0 && + alpha->offset_ > image->offset_) { + return 0; + } + // There shouldn't be any frames after an incomplete one. + if (f->next_ != NULL) return 0; + } + + if (f->width_ > 0 && f->height_ > 0 && + !CheckFrameBounds(f, !is_animation, + dmux->canvas_width_, dmux->canvas_height_)) { + return 0; + } + } + } + return 1; +} + +// ----------------------------------------------------------------------------- +// WebPDemuxer object + +static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) { + dmux->state_ = WEBP_DEMUX_PARSING_HEADER; + dmux->loop_count_ = 1; + dmux->bgcolor_ = 0xFFFFFFFF; // White background by default. + dmux->canvas_width_ = -1; + dmux->canvas_height_ = -1; + dmux->frames_tail_ = &dmux->frames_; + dmux->chunks_tail_ = &dmux->chunks_; + dmux->mem_ = *mem; +} + +static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem, + WebPDemuxer** demuxer) { + WebPBitstreamFeatures features; + const VP8StatusCode status = + WebPGetFeatures(mem->buf_, mem->buf_size_, &features); + *demuxer = NULL; + if (status != VP8_STATUS_OK) { + return (status == VP8_STATUS_NOT_ENOUGH_DATA) ? PARSE_NEED_MORE_DATA + : PARSE_ERROR; + } + + { + WebPDemuxer* const dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux)); + Frame* const frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame)); + if (dmux == NULL || frame == NULL) goto Error; + InitDemux(dmux, mem); + SetFrameInfo(0, mem->buf_size_, 1 /*frame_num*/, 1 /*complete*/, &features, + frame); + if (!AddFrame(dmux, frame)) goto Error; + dmux->state_ = WEBP_DEMUX_DONE; + dmux->canvas_width_ = frame->width_; + dmux->canvas_height_ = frame->height_; + dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0; + dmux->num_frames_ = 1; + assert(IsValidSimpleFormat(dmux)); + *demuxer = dmux; + return PARSE_OK; + + Error: + WebPSafeFree(dmux); + WebPSafeFree(frame); + return PARSE_ERROR; + } +} + +WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial, + WebPDemuxState* state, int version) { + const ChunkParser* parser; + int partial; + ParseStatus status = PARSE_ERROR; + MemBuffer mem; + WebPDemuxer* dmux; + + if (state != NULL) *state = WEBP_DEMUX_PARSE_ERROR; + + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL; + if (data == NULL || data->bytes == NULL || data->size == 0) return NULL; + + if (!InitMemBuffer(&mem, data->bytes, data->size)) return NULL; + status = ReadHeader(&mem); + if (status != PARSE_OK) { + // If parsing of the webp file header fails attempt to handle a raw + // VP8/VP8L frame. Note 'allow_partial' is ignored in this case. + if (status == PARSE_ERROR) { + status = CreateRawImageDemuxer(&mem, &dmux); + if (status == PARSE_OK) { + if (state != NULL) *state = WEBP_DEMUX_DONE; + return dmux; + } + } + if (state != NULL) { + *state = (status == PARSE_NEED_MORE_DATA) ? WEBP_DEMUX_PARSING_HEADER + : WEBP_DEMUX_PARSE_ERROR; + } + return NULL; + } + + partial = (mem.buf_size_ < mem.riff_end_); + if (!allow_partial && partial) return NULL; + + dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux)); + if (dmux == NULL) return NULL; + InitDemux(dmux, &mem); + + status = PARSE_ERROR; + for (parser = kMasterChunks; parser->parse != NULL; ++parser) { + if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) { + status = parser->parse(dmux); + if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE; + if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR; + if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR; + if (status == PARSE_ERROR) dmux->state_ = WEBP_DEMUX_PARSE_ERROR; + break; + } + } + if (state != NULL) *state = dmux->state_; + + if (status == PARSE_ERROR) { + WebPDemuxDelete(dmux); + return NULL; + } + return dmux; +} + +void WebPDemuxDelete(WebPDemuxer* dmux) { + Chunk* c; + Frame* f; + if (dmux == NULL) return; + + for (f = dmux->frames_; f != NULL;) { + Frame* const cur_frame = f; + f = f->next_; + WebPSafeFree(cur_frame); + } + for (c = dmux->chunks_; c != NULL;) { + Chunk* const cur_chunk = c; + c = c->next_; + WebPSafeFree(cur_chunk); + } + WebPSafeFree(dmux); +} + +// ----------------------------------------------------------------------------- + +uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) { + if (dmux == NULL) return 0; + + switch (feature) { + case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags_; + case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width_; + case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height_; + case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_; + case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor_; + case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames_; + } + return 0; +} + +// ----------------------------------------------------------------------------- +// Frame iteration + +static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) { + const Frame* f; + for (f = dmux->frames_; f != NULL; f = f->next_) { + if (frame_num == f->frame_num_) break; + } + return f; +} + +static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, + const Frame* const frame, + size_t* const data_size) { + *data_size = 0; + if (frame != NULL) { + const ChunkData* const image = frame->img_components_; + const ChunkData* const alpha = frame->img_components_ + 1; + size_t start_offset = image->offset_; + *data_size = image->size_; + + // if alpha exists it precedes image, update the size allowing for + // intervening chunks. + if (alpha->size_ > 0) { + const size_t inter_size = (image->offset_ > 0) + ? image->offset_ - (alpha->offset_ + alpha->size_) + : 0; + start_offset = alpha->offset_; + *data_size += alpha->size_ + inter_size; + } + return mem_buf + start_offset; + } + return NULL; +} + +// Create a whole 'frame' from VP8 (+ alpha) or lossless. +static int SynthesizeFrame(const WebPDemuxer* const dmux, + const Frame* const frame, + WebPIterator* const iter) { + const uint8_t* const mem_buf = dmux->mem_.buf_; + size_t payload_size = 0; + const uint8_t* const payload = GetFramePayload(mem_buf, frame, &payload_size); + if (payload == NULL) return 0; + assert(frame != NULL); + + iter->frame_num = frame->frame_num_; + iter->num_frames = dmux->num_frames_; + iter->x_offset = frame->x_offset_; + iter->y_offset = frame->y_offset_; + iter->width = frame->width_; + iter->height = frame->height_; + iter->has_alpha = frame->has_alpha_; + iter->duration = frame->duration_; + iter->dispose_method = frame->dispose_method_; + iter->blend_method = frame->blend_method_; + iter->complete = frame->complete_; + iter->fragment.bytes = payload; + iter->fragment.size = payload_size; + return 1; +} + +static int SetFrame(int frame_num, WebPIterator* const iter) { + const Frame* frame; + const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; + if (dmux == NULL || frame_num < 0) return 0; + if (frame_num > dmux->num_frames_) return 0; + if (frame_num == 0) frame_num = dmux->num_frames_; + + frame = GetFrame(dmux, frame_num); + if (frame == NULL) return 0; + + return SynthesizeFrame(dmux, frame, iter); +} + +int WebPDemuxGetFrame(const WebPDemuxer* dmux, int frame, WebPIterator* iter) { + if (iter == NULL) return 0; + + memset(iter, 0, sizeof(*iter)); + iter->private_ = (void*)dmux; + return SetFrame(frame, iter); +} + +int WebPDemuxNextFrame(WebPIterator* iter) { + if (iter == NULL) return 0; + return SetFrame(iter->frame_num + 1, iter); +} + +int WebPDemuxPrevFrame(WebPIterator* iter) { + if (iter == NULL) return 0; + if (iter->frame_num <= 1) return 0; + return SetFrame(iter->frame_num - 1, iter); +} + +void WebPDemuxReleaseIterator(WebPIterator* iter) { + (void)iter; +} + +// ----------------------------------------------------------------------------- +// Chunk iteration + +static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) { + const uint8_t* const mem_buf = dmux->mem_.buf_; + const Chunk* c; + int count = 0; + for (c = dmux->chunks_; c != NULL; c = c->next_) { + const uint8_t* const header = mem_buf + c->data_.offset_; + if (!memcmp(header, fourcc, TAG_SIZE)) ++count; + } + return count; +} + +static const Chunk* GetChunk(const WebPDemuxer* const dmux, + const char fourcc[4], int chunk_num) { + const uint8_t* const mem_buf = dmux->mem_.buf_; + const Chunk* c; + int count = 0; + for (c = dmux->chunks_; c != NULL; c = c->next_) { + const uint8_t* const header = mem_buf + c->data_.offset_; + if (!memcmp(header, fourcc, TAG_SIZE)) ++count; + if (count == chunk_num) break; + } + return c; +} + +static int SetChunk(const char fourcc[4], int chunk_num, + WebPChunkIterator* const iter) { + const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; + int count; + + if (dmux == NULL || fourcc == NULL || chunk_num < 0) return 0; + count = ChunkCount(dmux, fourcc); + if (count == 0) return 0; + if (chunk_num == 0) chunk_num = count; + + if (chunk_num <= count) { + const uint8_t* const mem_buf = dmux->mem_.buf_; + const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num); + iter->chunk.bytes = mem_buf + chunk->data_.offset_ + CHUNK_HEADER_SIZE; + iter->chunk.size = chunk->data_.size_ - CHUNK_HEADER_SIZE; + iter->num_chunks = count; + iter->chunk_num = chunk_num; + return 1; + } + return 0; +} + +int WebPDemuxGetChunk(const WebPDemuxer* dmux, + const char fourcc[4], int chunk_num, + WebPChunkIterator* iter) { + if (iter == NULL) return 0; + + memset(iter, 0, sizeof(*iter)); + iter->private_ = (void*)dmux; + return SetChunk(fourcc, chunk_num, iter); +} + +int WebPDemuxNextChunk(WebPChunkIterator* iter) { + if (iter != NULL) { + const char* const fourcc = + (const char*)iter->chunk.bytes - CHUNK_HEADER_SIZE; + return SetChunk(fourcc, iter->chunk_num + 1, iter); + } + return 0; +} + +int WebPDemuxPrevChunk(WebPChunkIterator* iter) { + if (iter != NULL && iter->chunk_num > 1) { + const char* const fourcc = + (const char*)iter->chunk.bytes - CHUNK_HEADER_SIZE; + return SetChunk(fourcc, iter->chunk_num - 1, iter); + } + return 0; +} + +void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) { + (void)iter; +} + diff --git a/libraries/webp/src/dsp/alpha_processing.c b/libraries/webp/src/dsp/alpha_processing.c new file mode 100644 index 00000000000..1d152f24dad --- /dev/null +++ b/libraries/webp/src/dsp/alpha_processing.c @@ -0,0 +1,496 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for processing transparent channel. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include "src/dsp/dsp.h" + +// Tables can be faster on some platform but incur some extra binary size (~2k). +#if !defined(USE_TABLES_FOR_ALPHA_MULT) +#define USE_TABLES_FOR_ALPHA_MULT 0 // ALTERNATE_CODE +#endif + + +// ----------------------------------------------------------------------------- + +#define MFIX 24 // 24bit fixed-point arithmetic +#define HALF ((1u << MFIX) >> 1) +#define KINV_255 ((1u << MFIX) / 255u) + +static uint32_t Mult(uint8_t x, uint32_t mult) { + const uint32_t v = (x * mult + HALF) >> MFIX; + assert(v <= 255); // <- 24bit precision is enough to ensure that. + return v; +} + +#if (USE_TABLES_FOR_ALPHA_MULT == 1) + +static const uint32_t kMultTables[2][256] = { + { // (255u << MFIX) / alpha + 0x00000000, 0xff000000, 0x7f800000, 0x55000000, 0x3fc00000, 0x33000000, + 0x2a800000, 0x246db6db, 0x1fe00000, 0x1c555555, 0x19800000, 0x172e8ba2, + 0x15400000, 0x139d89d8, 0x1236db6d, 0x11000000, 0x0ff00000, 0x0f000000, + 0x0e2aaaaa, 0x0d6bca1a, 0x0cc00000, 0x0c249249, 0x0b9745d1, 0x0b1642c8, + 0x0aa00000, 0x0a333333, 0x09cec4ec, 0x0971c71c, 0x091b6db6, 0x08cb08d3, + 0x08800000, 0x0839ce73, 0x07f80000, 0x07ba2e8b, 0x07800000, 0x07492492, + 0x07155555, 0x06e45306, 0x06b5e50d, 0x0689d89d, 0x06600000, 0x063831f3, + 0x06124924, 0x05ee23b8, 0x05cba2e8, 0x05aaaaaa, 0x058b2164, 0x056cefa8, + 0x05500000, 0x05343eb1, 0x05199999, 0x05000000, 0x04e76276, 0x04cfb2b7, + 0x04b8e38e, 0x04a2e8ba, 0x048db6db, 0x0479435e, 0x04658469, 0x045270d0, + 0x04400000, 0x042e29f7, 0x041ce739, 0x040c30c3, 0x03fc0000, 0x03ec4ec4, + 0x03dd1745, 0x03ce540f, 0x03c00000, 0x03b21642, 0x03a49249, 0x03976fc6, + 0x038aaaaa, 0x037e3f1f, 0x03722983, 0x03666666, 0x035af286, 0x034fcace, + 0x0344ec4e, 0x033a5440, 0x03300000, 0x0325ed09, 0x031c18f9, 0x0312818a, + 0x03092492, 0x03000000, 0x02f711dc, 0x02ee5846, 0x02e5d174, 0x02dd7baf, + 0x02d55555, 0x02cd5cd5, 0x02c590b2, 0x02bdef7b, 0x02b677d4, 0x02af286b, + 0x02a80000, 0x02a0fd5c, 0x029a1f58, 0x029364d9, 0x028ccccc, 0x0286562d, + 0x02800000, 0x0279c952, 0x0273b13b, 0x026db6db, 0x0267d95b, 0x026217ec, + 0x025c71c7, 0x0256e62a, 0x0251745d, 0x024c1bac, 0x0246db6d, 0x0241b2f9, + 0x023ca1af, 0x0237a6f4, 0x0232c234, 0x022df2df, 0x02293868, 0x02249249, + 0x02200000, 0x021b810e, 0x021714fb, 0x0212bb51, 0x020e739c, 0x020a3d70, + 0x02061861, 0x02020408, 0x01fe0000, 0x01fa0be8, 0x01f62762, 0x01f25213, + 0x01ee8ba2, 0x01ead3ba, 0x01e72a07, 0x01e38e38, 0x01e00000, 0x01dc7f10, + 0x01d90b21, 0x01d5a3e9, 0x01d24924, 0x01cefa8d, 0x01cbb7e3, 0x01c880e5, + 0x01c55555, 0x01c234f7, 0x01bf1f8f, 0x01bc14e5, 0x01b914c1, 0x01b61eed, + 0x01b33333, 0x01b05160, 0x01ad7943, 0x01aaaaaa, 0x01a7e567, 0x01a5294a, + 0x01a27627, 0x019fcbd2, 0x019d2a20, 0x019a90e7, 0x01980000, 0x01957741, + 0x0192f684, 0x01907da4, 0x018e0c7c, 0x018ba2e8, 0x018940c5, 0x0186e5f0, + 0x01849249, 0x018245ae, 0x01800000, 0x017dc11f, 0x017b88ee, 0x0179574e, + 0x01772c23, 0x01750750, 0x0172e8ba, 0x0170d045, 0x016ebdd7, 0x016cb157, + 0x016aaaaa, 0x0168a9b9, 0x0166ae6a, 0x0164b8a7, 0x0162c859, 0x0160dd67, + 0x015ef7bd, 0x015d1745, 0x015b3bea, 0x01596596, 0x01579435, 0x0155c7b4, + 0x01540000, 0x01523d03, 0x01507eae, 0x014ec4ec, 0x014d0fac, 0x014b5edc, + 0x0149b26c, 0x01480a4a, 0x01466666, 0x0144c6af, 0x01432b16, 0x0141938b, + 0x01400000, 0x013e7063, 0x013ce4a9, 0x013b5cc0, 0x0139d89d, 0x01385830, + 0x0136db6d, 0x01356246, 0x0133ecad, 0x01327a97, 0x01310bf6, 0x012fa0be, + 0x012e38e3, 0x012cd459, 0x012b7315, 0x012a150a, 0x0128ba2e, 0x01276276, + 0x01260dd6, 0x0124bc44, 0x01236db6, 0x01222222, 0x0120d97c, 0x011f93bc, + 0x011e50d7, 0x011d10c4, 0x011bd37a, 0x011a98ef, 0x0119611a, 0x01182bf2, + 0x0116f96f, 0x0115c988, 0x01149c34, 0x0113716a, 0x01124924, 0x01112358, + 0x01100000, 0x010edf12, 0x010dc087, 0x010ca458, 0x010b8a7d, 0x010a72f0, + 0x01095da8, 0x01084a9f, 0x010739ce, 0x01062b2e, 0x01051eb8, 0x01041465, + 0x01030c30, 0x01020612, 0x01010204, 0x01000000 }, + { // alpha * KINV_255 + 0x00000000, 0x00010101, 0x00020202, 0x00030303, 0x00040404, 0x00050505, + 0x00060606, 0x00070707, 0x00080808, 0x00090909, 0x000a0a0a, 0x000b0b0b, + 0x000c0c0c, 0x000d0d0d, 0x000e0e0e, 0x000f0f0f, 0x00101010, 0x00111111, + 0x00121212, 0x00131313, 0x00141414, 0x00151515, 0x00161616, 0x00171717, + 0x00181818, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d, + 0x001e1e1e, 0x001f1f1f, 0x00202020, 0x00212121, 0x00222222, 0x00232323, + 0x00242424, 0x00252525, 0x00262626, 0x00272727, 0x00282828, 0x00292929, + 0x002a2a2a, 0x002b2b2b, 0x002c2c2c, 0x002d2d2d, 0x002e2e2e, 0x002f2f2f, + 0x00303030, 0x00313131, 0x00323232, 0x00333333, 0x00343434, 0x00353535, + 0x00363636, 0x00373737, 0x00383838, 0x00393939, 0x003a3a3a, 0x003b3b3b, + 0x003c3c3c, 0x003d3d3d, 0x003e3e3e, 0x003f3f3f, 0x00404040, 0x00414141, + 0x00424242, 0x00434343, 0x00444444, 0x00454545, 0x00464646, 0x00474747, + 0x00484848, 0x00494949, 0x004a4a4a, 0x004b4b4b, 0x004c4c4c, 0x004d4d4d, + 0x004e4e4e, 0x004f4f4f, 0x00505050, 0x00515151, 0x00525252, 0x00535353, + 0x00545454, 0x00555555, 0x00565656, 0x00575757, 0x00585858, 0x00595959, + 0x005a5a5a, 0x005b5b5b, 0x005c5c5c, 0x005d5d5d, 0x005e5e5e, 0x005f5f5f, + 0x00606060, 0x00616161, 0x00626262, 0x00636363, 0x00646464, 0x00656565, + 0x00666666, 0x00676767, 0x00686868, 0x00696969, 0x006a6a6a, 0x006b6b6b, + 0x006c6c6c, 0x006d6d6d, 0x006e6e6e, 0x006f6f6f, 0x00707070, 0x00717171, + 0x00727272, 0x00737373, 0x00747474, 0x00757575, 0x00767676, 0x00777777, + 0x00787878, 0x00797979, 0x007a7a7a, 0x007b7b7b, 0x007c7c7c, 0x007d7d7d, + 0x007e7e7e, 0x007f7f7f, 0x00808080, 0x00818181, 0x00828282, 0x00838383, + 0x00848484, 0x00858585, 0x00868686, 0x00878787, 0x00888888, 0x00898989, + 0x008a8a8a, 0x008b8b8b, 0x008c8c8c, 0x008d8d8d, 0x008e8e8e, 0x008f8f8f, + 0x00909090, 0x00919191, 0x00929292, 0x00939393, 0x00949494, 0x00959595, + 0x00969696, 0x00979797, 0x00989898, 0x00999999, 0x009a9a9a, 0x009b9b9b, + 0x009c9c9c, 0x009d9d9d, 0x009e9e9e, 0x009f9f9f, 0x00a0a0a0, 0x00a1a1a1, + 0x00a2a2a2, 0x00a3a3a3, 0x00a4a4a4, 0x00a5a5a5, 0x00a6a6a6, 0x00a7a7a7, + 0x00a8a8a8, 0x00a9a9a9, 0x00aaaaaa, 0x00ababab, 0x00acacac, 0x00adadad, + 0x00aeaeae, 0x00afafaf, 0x00b0b0b0, 0x00b1b1b1, 0x00b2b2b2, 0x00b3b3b3, + 0x00b4b4b4, 0x00b5b5b5, 0x00b6b6b6, 0x00b7b7b7, 0x00b8b8b8, 0x00b9b9b9, + 0x00bababa, 0x00bbbbbb, 0x00bcbcbc, 0x00bdbdbd, 0x00bebebe, 0x00bfbfbf, + 0x00c0c0c0, 0x00c1c1c1, 0x00c2c2c2, 0x00c3c3c3, 0x00c4c4c4, 0x00c5c5c5, + 0x00c6c6c6, 0x00c7c7c7, 0x00c8c8c8, 0x00c9c9c9, 0x00cacaca, 0x00cbcbcb, + 0x00cccccc, 0x00cdcdcd, 0x00cecece, 0x00cfcfcf, 0x00d0d0d0, 0x00d1d1d1, + 0x00d2d2d2, 0x00d3d3d3, 0x00d4d4d4, 0x00d5d5d5, 0x00d6d6d6, 0x00d7d7d7, + 0x00d8d8d8, 0x00d9d9d9, 0x00dadada, 0x00dbdbdb, 0x00dcdcdc, 0x00dddddd, + 0x00dedede, 0x00dfdfdf, 0x00e0e0e0, 0x00e1e1e1, 0x00e2e2e2, 0x00e3e3e3, + 0x00e4e4e4, 0x00e5e5e5, 0x00e6e6e6, 0x00e7e7e7, 0x00e8e8e8, 0x00e9e9e9, + 0x00eaeaea, 0x00ebebeb, 0x00ececec, 0x00ededed, 0x00eeeeee, 0x00efefef, + 0x00f0f0f0, 0x00f1f1f1, 0x00f2f2f2, 0x00f3f3f3, 0x00f4f4f4, 0x00f5f5f5, + 0x00f6f6f6, 0x00f7f7f7, 0x00f8f8f8, 0x00f9f9f9, 0x00fafafa, 0x00fbfbfb, + 0x00fcfcfc, 0x00fdfdfd, 0x00fefefe, 0x00ffffff } +}; + +static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) { + return kMultTables[!inverse][a]; +} + +#else + +static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) { + return inverse ? (255u << MFIX) / a : a * KINV_255; +} + +#endif // USE_TABLES_FOR_ALPHA_MULT + +void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) { + int x; + for (x = 0; x < width; ++x) { + const uint32_t argb = ptr[x]; + if (argb < 0xff000000u) { // alpha < 255 + if (argb <= 0x00ffffffu) { // alpha == 0 + ptr[x] = 0; + } else { + const uint32_t alpha = (argb >> 24) & 0xff; + const uint32_t scale = GetScale(alpha, inverse); + uint32_t out = argb & 0xff000000u; + out |= Mult(argb >> 0, scale) << 0; + out |= Mult(argb >> 8, scale) << 8; + out |= Mult(argb >> 16, scale) << 16; + ptr[x] = out; + } + } + } +} + +void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr, + const uint8_t* WEBP_RESTRICT const alpha, + int width, int inverse) { + int x; + for (x = 0; x < width; ++x) { + const uint32_t a = alpha[x]; + if (a != 255) { + if (a == 0) { + ptr[x] = 0; + } else { + const uint32_t scale = GetScale(a, inverse); + ptr[x] = Mult(ptr[x], scale); + } + } + } +} + +#undef KINV_255 +#undef HALF +#undef MFIX + +void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse); +void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr, + const uint8_t* WEBP_RESTRICT const alpha, + int width, int inverse); + +//------------------------------------------------------------------------------ +// Generic per-plane calls + +void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows, + int inverse) { + int n; + for (n = 0; n < num_rows; ++n) { + WebPMultARGBRow((uint32_t*)ptr, width, inverse); + ptr += stride; + } +} + +void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride, + const uint8_t* WEBP_RESTRICT alpha, int alpha_stride, + int width, int num_rows, int inverse) { + int n; + for (n = 0; n < num_rows; ++n) { + WebPMultRow(ptr, alpha, width, inverse); + ptr += stride; + alpha += alpha_stride; + } +} + +//------------------------------------------------------------------------------ +// Premultiplied modes + +// non dithered-modes + +// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.) +// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5), +// one can use instead: (x * a * 65793 + (1 << 23)) >> 24 +#if 1 // (int)(x * a / 255.) +#define MULTIPLIER(a) ((a) * 32897U) +#define PREMULTIPLY(x, m) (((x) * (m)) >> 23) +#else // (int)(x * a / 255. + .5) +#define MULTIPLIER(a) ((a) * 65793U) +#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24) +#endif + +#if !WEBP_NEON_OMIT_C_CODE +static void ApplyAlphaMultiply_C(uint8_t* rgba, int alpha_first, + int w, int h, int stride) { + while (h-- > 0) { + uint8_t* const rgb = rgba + (alpha_first ? 1 : 0); + const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3); + int i; + for (i = 0; i < w; ++i) { + const uint32_t a = alpha[4 * i]; + if (a != 0xff) { + const uint32_t mult = MULTIPLIER(a); + rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult); + rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult); + rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult); + } + } + rgba += stride; + } +} +#endif // !WEBP_NEON_OMIT_C_CODE +#undef MULTIPLIER +#undef PREMULTIPLY + +// rgbA4444 + +#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15 + +static WEBP_INLINE uint8_t dither_hi(uint8_t x) { + return (x & 0xf0) | (x >> 4); +} + +static WEBP_INLINE uint8_t dither_lo(uint8_t x) { + return (x & 0x0f) | (x << 4); +} + +static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) { + return (x * m) >> 16; +} + +static WEBP_INLINE void ApplyAlphaMultiply4444_C(uint8_t* rgba4444, + int w, int h, int stride, + int rg_byte_pos /* 0 or 1 */) { + while (h-- > 0) { + int i; + for (i = 0; i < w; ++i) { + const uint32_t rg = rgba4444[2 * i + rg_byte_pos]; + const uint32_t ba = rgba4444[2 * i + (rg_byte_pos ^ 1)]; + const uint8_t a = ba & 0x0f; + const uint32_t mult = MULTIPLIER(a); + const uint8_t r = multiply(dither_hi(rg), mult); + const uint8_t g = multiply(dither_lo(rg), mult); + const uint8_t b = multiply(dither_hi(ba), mult); + rgba4444[2 * i + rg_byte_pos] = (r & 0xf0) | ((g >> 4) & 0x0f); + rgba4444[2 * i + (rg_byte_pos ^ 1)] = (b & 0xf0) | a; + } + rgba4444 += stride; + } +} +#undef MULTIPLIER + +static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444, + int w, int h, int stride) { +#if (WEBP_SWAP_16BIT_CSP == 1) + ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 1); +#else + ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 0); +#endif +} + +#if !WEBP_NEON_OMIT_C_CODE +static int DispatchAlpha_C(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride, + int width, int height, + uint8_t* WEBP_RESTRICT dst, int dst_stride) { + uint32_t alpha_mask = 0xff; + int i, j; + + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + const uint32_t alpha_value = alpha[i]; + dst[4 * i] = alpha_value; + alpha_mask &= alpha_value; + } + alpha += alpha_stride; + dst += dst_stride; + } + + return (alpha_mask != 0xff); +} + +static void DispatchAlphaToGreen_C(const uint8_t* WEBP_RESTRICT alpha, + int alpha_stride, int width, int height, + uint32_t* WEBP_RESTRICT dst, + int dst_stride) { + int i, j; + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + dst[i] = alpha[i] << 8; // leave A/R/B channels zero'd. + } + alpha += alpha_stride; + dst += dst_stride; + } +} + +static int ExtractAlpha_C(const uint8_t* WEBP_RESTRICT argb, int argb_stride, + int width, int height, + uint8_t* WEBP_RESTRICT alpha, int alpha_stride) { + uint8_t alpha_mask = 0xff; + int i, j; + + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + const uint8_t alpha_value = argb[4 * i]; + alpha[i] = alpha_value; + alpha_mask &= alpha_value; + } + argb += argb_stride; + alpha += alpha_stride; + } + return (alpha_mask == 0xff); +} + +static void ExtractGreen_C(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT alpha, int size) { + int i; + for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8; +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//------------------------------------------------------------------------------ + +static int HasAlpha8b_C(const uint8_t* src, int length) { + while (length-- > 0) if (*src++ != 0xff) return 1; + return 0; +} + +static int HasAlpha32b_C(const uint8_t* src, int length) { + int x; + for (x = 0; length-- > 0; x += 4) if (src[x] != 0xff) return 1; + return 0; +} + +static void AlphaReplace_C(uint32_t* src, int length, uint32_t color) { + int x; + for (x = 0; x < length; ++x) if ((src[x] >> 24) == 0) src[x] = color; +} + +//------------------------------------------------------------------------------ +// Simple channel manipulations. + +static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) { + return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b); +} + +#ifdef WORDS_BIGENDIAN +static void PackARGB_C(const uint8_t* WEBP_RESTRICT a, + const uint8_t* WEBP_RESTRICT r, + const uint8_t* WEBP_RESTRICT g, + const uint8_t* WEBP_RESTRICT b, + int len, uint32_t* WEBP_RESTRICT out) { + int i; + for (i = 0; i < len; ++i) { + out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]); + } +} +#endif + +static void PackRGB_C(const uint8_t* WEBP_RESTRICT r, + const uint8_t* WEBP_RESTRICT g, + const uint8_t* WEBP_RESTRICT b, + int len, int step, uint32_t* WEBP_RESTRICT out) { + int i, offset = 0; + for (i = 0; i < len; ++i) { + out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]); + offset += step; + } +} + +void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int); +void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int); +int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int, + uint8_t* WEBP_RESTRICT, int); +void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT, int, int, int, + uint32_t* WEBP_RESTRICT, int); +int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int, + uint8_t* WEBP_RESTRICT, int); +void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT alpha, int size); +#ifdef WORDS_BIGENDIAN +void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g, + const uint8_t* b, int, uint32_t*); +#endif +void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r, + const uint8_t* WEBP_RESTRICT g, + const uint8_t* WEBP_RESTRICT b, + int len, int step, uint32_t* WEBP_RESTRICT out); + +int (*WebPHasAlpha8b)(const uint8_t* src, int length); +int (*WebPHasAlpha32b)(const uint8_t* src, int length); +void (*WebPAlphaReplace)(uint32_t* src, int length, uint32_t color); + +//------------------------------------------------------------------------------ +// Init function + +extern VP8CPUInfo VP8GetCPUInfo; +extern void WebPInitAlphaProcessingMIPSdspR2(void); +extern void WebPInitAlphaProcessingSSE2(void); +extern void WebPInitAlphaProcessingSSE41(void); +extern void WebPInitAlphaProcessingNEON(void); + +WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) { + WebPMultARGBRow = WebPMultARGBRow_C; + WebPMultRow = WebPMultRow_C; + WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b_C; + +#ifdef WORDS_BIGENDIAN + WebPPackARGB = PackARGB_C; +#endif + WebPPackRGB = PackRGB_C; +#if !WEBP_NEON_OMIT_C_CODE + WebPApplyAlphaMultiply = ApplyAlphaMultiply_C; + WebPDispatchAlpha = DispatchAlpha_C; + WebPDispatchAlphaToGreen = DispatchAlphaToGreen_C; + WebPExtractAlpha = ExtractAlpha_C; + WebPExtractGreen = ExtractGreen_C; +#endif + + WebPHasAlpha8b = HasAlpha8b_C; + WebPHasAlpha32b = HasAlpha32b_C; + WebPAlphaReplace = AlphaReplace_C; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + WebPInitAlphaProcessingSSE2(); +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitAlphaProcessingSSE41(); + } +#endif + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + WebPInitAlphaProcessingMIPSdspR2(); + } +#endif + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + WebPInitAlphaProcessingNEON(); + } +#endif + + assert(WebPMultARGBRow != NULL); + assert(WebPMultRow != NULL); + assert(WebPApplyAlphaMultiply != NULL); + assert(WebPApplyAlphaMultiply4444 != NULL); + assert(WebPDispatchAlpha != NULL); + assert(WebPDispatchAlphaToGreen != NULL); + assert(WebPExtractAlpha != NULL); + assert(WebPExtractGreen != NULL); +#ifdef WORDS_BIGENDIAN + assert(WebPPackARGB != NULL); +#endif + assert(WebPPackRGB != NULL); + assert(WebPHasAlpha8b != NULL); + assert(WebPHasAlpha32b != NULL); + assert(WebPAlphaReplace != NULL); +} diff --git a/libraries/webp/src/dsp/alpha_processing_mips_dsp_r2.c b/libraries/webp/src/dsp/alpha_processing_mips_dsp_r2.c new file mode 100644 index 00000000000..0090e87cd1f --- /dev/null +++ b/libraries/webp/src/dsp/alpha_processing_mips_dsp_r2.c @@ -0,0 +1,228 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for processing transparent channel. +// +// Author(s): Branimir Vasic (branimir.vasic@imgtec.com) +// Djordje Pesut (djordje.pesut@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +static int DispatchAlpha_MIPSdspR2(const uint8_t* alpha, int alpha_stride, + int width, int height, + uint8_t* dst, int dst_stride) { + uint32_t alpha_mask = 0xffffffff; + int i, j, temp0; + + for (j = 0; j < height; ++j) { + uint8_t* pdst = dst; + const uint8_t* palpha = alpha; + for (i = 0; i < (width >> 2); ++i) { + int temp1, temp2, temp3; + + __asm__ volatile ( + "ulw %[temp0], 0(%[palpha]) \n\t" + "addiu %[palpha], %[palpha], 4 \n\t" + "addiu %[pdst], %[pdst], 16 \n\t" + "srl %[temp1], %[temp0], 8 \n\t" + "srl %[temp2], %[temp0], 16 \n\t" + "srl %[temp3], %[temp0], 24 \n\t" + "and %[alpha_mask], %[alpha_mask], %[temp0] \n\t" + "sb %[temp0], -16(%[pdst]) \n\t" + "sb %[temp1], -12(%[pdst]) \n\t" + "sb %[temp2], -8(%[pdst]) \n\t" + "sb %[temp3], -4(%[pdst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [palpha]"+r"(palpha), [pdst]"+r"(pdst), + [alpha_mask]"+r"(alpha_mask) + : + : "memory" + ); + } + + for (i = 0; i < (width & 3); ++i) { + __asm__ volatile ( + "lbu %[temp0], 0(%[palpha]) \n\t" + "addiu %[palpha], %[palpha], 1 \n\t" + "sb %[temp0], 0(%[pdst]) \n\t" + "and %[alpha_mask], %[alpha_mask], %[temp0] \n\t" + "addiu %[pdst], %[pdst], 4 \n\t" + : [temp0]"=&r"(temp0), [palpha]"+r"(palpha), [pdst]"+r"(pdst), + [alpha_mask]"+r"(alpha_mask) + : + : "memory" + ); + } + alpha += alpha_stride; + dst += dst_stride; + } + + __asm__ volatile ( + "ext %[temp0], %[alpha_mask], 0, 16 \n\t" + "srl %[alpha_mask], %[alpha_mask], 16 \n\t" + "and %[alpha_mask], %[alpha_mask], %[temp0] \n\t" + "ext %[temp0], %[alpha_mask], 0, 8 \n\t" + "srl %[alpha_mask], %[alpha_mask], 8 \n\t" + "and %[alpha_mask], %[alpha_mask], %[temp0] \n\t" + : [temp0]"=&r"(temp0), [alpha_mask]"+r"(alpha_mask) + : + ); + + return (alpha_mask != 0xff); +} + +static void MultARGBRow_MIPSdspR2(uint32_t* const ptr, int width, + int inverse) { + int x; + const uint32_t c_00ffffff = 0x00ffffffu; + const uint32_t c_ff000000 = 0xff000000u; + const uint32_t c_8000000 = 0x00800000u; + const uint32_t c_8000080 = 0x00800080u; + for (x = 0; x < width; ++x) { + const uint32_t argb = ptr[x]; + if (argb < 0xff000000u) { // alpha < 255 + if (argb <= 0x00ffffffu) { // alpha == 0 + ptr[x] = 0; + } else { + int temp0, temp1, temp2, temp3, alpha; + __asm__ volatile ( + "srl %[alpha], %[argb], 24 \n\t" + "replv.qb %[temp0], %[alpha] \n\t" + "and %[temp0], %[temp0], %[c_00ffffff] \n\t" + "beqz %[inverse], 0f \n\t" + "divu $zero, %[c_ff000000], %[alpha] \n\t" + "mflo %[temp0] \n\t" + "0: \n\t" + "andi %[temp1], %[argb], 0xff \n\t" + "ext %[temp2], %[argb], 8, 8 \n\t" + "ext %[temp3], %[argb], 16, 8 \n\t" + "mul %[temp1], %[temp1], %[temp0] \n\t" + "mul %[temp2], %[temp2], %[temp0] \n\t" + "mul %[temp3], %[temp3], %[temp0] \n\t" + "precrq.ph.w %[temp1], %[temp2], %[temp1] \n\t" + "addu %[temp3], %[temp3], %[c_8000000] \n\t" + "addu %[temp1], %[temp1], %[c_8000080] \n\t" + "precrq.ph.w %[temp3], %[argb], %[temp3] \n\t" + "precrq.qb.ph %[temp1], %[temp3], %[temp1] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [alpha]"=&r"(alpha) + : [inverse]"r"(inverse), [c_00ffffff]"r"(c_00ffffff), + [c_8000000]"r"(c_8000000), [c_8000080]"r"(c_8000080), + [c_ff000000]"r"(c_ff000000), [argb]"r"(argb) + : "memory", "hi", "lo" + ); + ptr[x] = temp1; + } + } + } +} + +#ifdef WORDS_BIGENDIAN +static void PackARGB_MIPSdspR2(const uint8_t* a, const uint8_t* r, + const uint8_t* g, const uint8_t* b, int len, + uint32_t* out) { + int temp0, temp1, temp2, temp3, offset; + const int rest = len & 1; + const uint32_t* const loop_end = out + len - rest; + const int step = 4; + __asm__ volatile ( + "xor %[offset], %[offset], %[offset] \n\t" + "beq %[loop_end], %[out], 0f \n\t" + "2: \n\t" + "lbux %[temp0], %[offset](%[a]) \n\t" + "lbux %[temp1], %[offset](%[r]) \n\t" + "lbux %[temp2], %[offset](%[g]) \n\t" + "lbux %[temp3], %[offset](%[b]) \n\t" + "ins %[temp1], %[temp0], 16, 16 \n\t" + "ins %[temp3], %[temp2], 16, 16 \n\t" + "addiu %[out], %[out], 4 \n\t" + "precr.qb.ph %[temp0], %[temp1], %[temp3] \n\t" + "sw %[temp0], -4(%[out]) \n\t" + "addu %[offset], %[offset], %[step] \n\t" + "bne %[loop_end], %[out], 2b \n\t" + "0: \n\t" + "beq %[rest], $zero, 1f \n\t" + "lbux %[temp0], %[offset](%[a]) \n\t" + "lbux %[temp1], %[offset](%[r]) \n\t" + "lbux %[temp2], %[offset](%[g]) \n\t" + "lbux %[temp3], %[offset](%[b]) \n\t" + "ins %[temp1], %[temp0], 16, 16 \n\t" + "ins %[temp3], %[temp2], 16, 16 \n\t" + "precr.qb.ph %[temp0], %[temp1], %[temp3] \n\t" + "sw %[temp0], 0(%[out]) \n\t" + "1: \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [offset]"=&r"(offset), [out]"+&r"(out) + : [a]"r"(a), [r]"r"(r), [g]"r"(g), [b]"r"(b), [step]"r"(step), + [loop_end]"r"(loop_end), [rest]"r"(rest) + : "memory" + ); +} +#endif // WORDS_BIGENDIAN + +static void PackRGB_MIPSdspR2(const uint8_t* r, const uint8_t* g, + const uint8_t* b, int len, int step, + uint32_t* out) { + int temp0, temp1, temp2, offset; + const int rest = len & 1; + const int a = 0xff; + const uint32_t* const loop_end = out + len - rest; + __asm__ volatile ( + "xor %[offset], %[offset], %[offset] \n\t" + "beq %[loop_end], %[out], 0f \n\t" + "2: \n\t" + "lbux %[temp0], %[offset](%[r]) \n\t" + "lbux %[temp1], %[offset](%[g]) \n\t" + "lbux %[temp2], %[offset](%[b]) \n\t" + "ins %[temp0], %[a], 16, 16 \n\t" + "ins %[temp2], %[temp1], 16, 16 \n\t" + "addiu %[out], %[out], 4 \n\t" + "precr.qb.ph %[temp0], %[temp0], %[temp2] \n\t" + "sw %[temp0], -4(%[out]) \n\t" + "addu %[offset], %[offset], %[step] \n\t" + "bne %[loop_end], %[out], 2b \n\t" + "0: \n\t" + "beq %[rest], $zero, 1f \n\t" + "lbux %[temp0], %[offset](%[r]) \n\t" + "lbux %[temp1], %[offset](%[g]) \n\t" + "lbux %[temp2], %[offset](%[b]) \n\t" + "ins %[temp0], %[a], 16, 16 \n\t" + "ins %[temp2], %[temp1], 16, 16 \n\t" + "precr.qb.ph %[temp0], %[temp0], %[temp2] \n\t" + "sw %[temp0], 0(%[out]) \n\t" + "1: \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [offset]"=&r"(offset), [out]"+&r"(out) + : [a]"r"(a), [r]"r"(r), [g]"r"(g), [b]"r"(b), [step]"r"(step), + [loop_end]"r"(loop_end), [rest]"r"(rest) + : "memory" + ); +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitAlphaProcessingMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingMIPSdspR2(void) { + WebPDispatchAlpha = DispatchAlpha_MIPSdspR2; + WebPMultARGBRow = MultARGBRow_MIPSdspR2; +#ifdef WORDS_BIGENDIAN + WebPPackARGB = PackARGB_MIPSdspR2; +#endif + WebPPackRGB = PackRGB_MIPSdspR2; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/alpha_processing_neon.c b/libraries/webp/src/dsp/alpha_processing_neon.c new file mode 100644 index 00000000000..6716fb77f0d --- /dev/null +++ b/libraries/webp/src/dsp/alpha_processing_neon.c @@ -0,0 +1,194 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for processing transparent channel, NEON version. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include "src/dsp/neon.h" + +//------------------------------------------------------------------------------ + +#define MULTIPLIER(a) ((a) * 0x8081) +#define PREMULTIPLY(x, m) (((x) * (m)) >> 23) + +#define MULTIPLY_BY_ALPHA(V, ALPHA, OTHER) do { \ + const uint8x8_t alpha = (V).val[(ALPHA)]; \ + const uint16x8_t r1 = vmull_u8((V).val[1], alpha); \ + const uint16x8_t g1 = vmull_u8((V).val[2], alpha); \ + const uint16x8_t b1 = vmull_u8((V).val[(OTHER)], alpha); \ + /* we use: v / 255 = (v + 1 + (v >> 8)) >> 8 */ \ + const uint16x8_t r2 = vsraq_n_u16(r1, r1, 8); \ + const uint16x8_t g2 = vsraq_n_u16(g1, g1, 8); \ + const uint16x8_t b2 = vsraq_n_u16(b1, b1, 8); \ + const uint16x8_t r3 = vaddq_u16(r2, kOne); \ + const uint16x8_t g3 = vaddq_u16(g2, kOne); \ + const uint16x8_t b3 = vaddq_u16(b2, kOne); \ + (V).val[1] = vshrn_n_u16(r3, 8); \ + (V).val[2] = vshrn_n_u16(g3, 8); \ + (V).val[(OTHER)] = vshrn_n_u16(b3, 8); \ +} while (0) + +static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first, + int w, int h, int stride) { + const uint16x8_t kOne = vdupq_n_u16(1u); + while (h-- > 0) { + uint32_t* const rgbx = (uint32_t*)rgba; + int i = 0; + if (alpha_first) { + for (; i + 8 <= w; i += 8) { + // load aaaa...|rrrr...|gggg...|bbbb... + uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i)); + MULTIPLY_BY_ALPHA(RGBX, 0, 3); + vst4_u8((uint8_t*)(rgbx + i), RGBX); + } + } else { + for (; i + 8 <= w; i += 8) { + uint8x8x4_t RGBX = vld4_u8((const uint8_t*)(rgbx + i)); + MULTIPLY_BY_ALPHA(RGBX, 3, 0); + vst4_u8((uint8_t*)(rgbx + i), RGBX); + } + } + // Finish with left-overs. + for (; i < w; ++i) { + uint8_t* const rgb = rgba + (alpha_first ? 1 : 0); + const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3); + const uint32_t a = alpha[4 * i]; + if (a != 0xff) { + const uint32_t mult = MULTIPLIER(a); + rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult); + rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult); + rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult); + } + } + rgba += stride; + } +} +#undef MULTIPLY_BY_ALPHA +#undef MULTIPLIER +#undef PREMULTIPLY + +//------------------------------------------------------------------------------ + +static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha, + int alpha_stride, int width, int height, + uint8_t* WEBP_RESTRICT dst, int dst_stride) { + uint32_t alpha_mask = 0xffu; + uint8x8_t mask8 = vdup_n_u8(0xff); + uint32_t tmp[2]; + int i, j; + for (j = 0; j < height; ++j) { + // We don't know if alpha is first or last in dst[] (depending on rgbA/Argb + // mode). So we must be sure dst[4*i + 8 - 1] is writable for the store. + // Hence the test with 'width - 1' instead of just 'width'. + for (i = 0; i + 8 <= width - 1; i += 8) { + uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(dst + 4 * i)); + const uint8x8_t alphas = vld1_u8(alpha + i); + rgbX.val[0] = alphas; + vst4_u8((uint8_t*)(dst + 4 * i), rgbX); + mask8 = vand_u8(mask8, alphas); + } + for (; i < width; ++i) { + const uint32_t alpha_value = alpha[i]; + dst[4 * i] = alpha_value; + alpha_mask &= alpha_value; + } + alpha += alpha_stride; + dst += dst_stride; + } + vst1_u8((uint8_t*)tmp, mask8); + alpha_mask *= 0x01010101; + alpha_mask &= tmp[0]; + alpha_mask &= tmp[1]; + return (alpha_mask != 0xffffffffu); +} + +static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha, + int alpha_stride, int width, int height, + uint32_t* WEBP_RESTRICT dst, + int dst_stride) { + int i, j; + uint8x8x4_t greens; // leave A/R/B channels zero'd. + greens.val[0] = vdup_n_u8(0); + greens.val[2] = vdup_n_u8(0); + greens.val[3] = vdup_n_u8(0); + for (j = 0; j < height; ++j) { + for (i = 0; i + 8 <= width; i += 8) { + greens.val[1] = vld1_u8(alpha + i); + vst4_u8((uint8_t*)(dst + i), greens); + } + for (; i < width; ++i) dst[i] = alpha[i] << 8; + alpha += alpha_stride; + dst += dst_stride; + } +} + +static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride, + int width, int height, + uint8_t* WEBP_RESTRICT alpha, int alpha_stride) { + uint32_t alpha_mask = 0xffu; + uint8x8_t mask8 = vdup_n_u8(0xff); + uint32_t tmp[2]; + int i, j; + for (j = 0; j < height; ++j) { + // We don't know if alpha is first or last in dst[] (depending on rgbA/Argb + // mode). So we must be sure dst[4*i + 8 - 1] is writable for the store. + // Hence the test with 'width - 1' instead of just 'width'. + for (i = 0; i + 8 <= width - 1; i += 8) { + const uint8x8x4_t rgbX = vld4_u8((const uint8_t*)(argb + 4 * i)); + const uint8x8_t alphas = rgbX.val[0]; + vst1_u8((uint8_t*)(alpha + i), alphas); + mask8 = vand_u8(mask8, alphas); + } + for (; i < width; ++i) { + alpha[i] = argb[4 * i]; + alpha_mask &= alpha[i]; + } + argb += argb_stride; + alpha += alpha_stride; + } + vst1_u8((uint8_t*)tmp, mask8); + alpha_mask *= 0x01010101; + alpha_mask &= tmp[0]; + alpha_mask &= tmp[1]; + return (alpha_mask == 0xffffffffu); +} + +static void ExtractGreen_NEON(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT alpha, int size) { + int i; + for (i = 0; i + 16 <= size; i += 16) { + const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i)); + const uint8x16_t greens = rgbX.val[1]; + vst1q_u8(alpha + i, greens); + } + for (; i < size; ++i) alpha[i] = (argb[i] >> 8) & 0xff; +} + +//------------------------------------------------------------------------------ + +extern void WebPInitAlphaProcessingNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingNEON(void) { + WebPApplyAlphaMultiply = ApplyAlphaMultiply_NEON; + WebPDispatchAlpha = DispatchAlpha_NEON; + WebPDispatchAlphaToGreen = DispatchAlphaToGreen_NEON; + WebPExtractAlpha = ExtractAlpha_NEON; + WebPExtractGreen = ExtractGreen_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/alpha_processing_sse2.c b/libraries/webp/src/dsp/alpha_processing_sse2.c new file mode 100644 index 00000000000..aa0cc2848ae --- /dev/null +++ b/libraries/webp/src/dsp/alpha_processing_sse2.c @@ -0,0 +1,408 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for processing transparent channel. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) +#include + +//------------------------------------------------------------------------------ + +static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha, + int alpha_stride, int width, int height, + uint8_t* WEBP_RESTRICT dst, int dst_stride) { + // alpha_and stores an 'and' operation of all the alpha[] values. The final + // value is not 0xff if any of the alpha[] is not equal to 0xff. + uint32_t alpha_and = 0xff; + int i, j; + const __m128i zero = _mm_setzero_si128(); + const __m128i rgb_mask = _mm_set1_epi32((int)0xffffff00); // to preserve RGB + const __m128i all_0xff = _mm_set_epi32(0, 0, ~0, ~0); + __m128i all_alphas = all_0xff; + + // We must be able to access 3 extra bytes after the last written byte + // 'dst[4 * width - 4]', because we don't know if alpha is the first or the + // last byte of the quadruplet. + const int limit = (width - 1) & ~7; + + for (j = 0; j < height; ++j) { + __m128i* out = (__m128i*)dst; + for (i = 0; i < limit; i += 8) { + // load 8 alpha bytes + const __m128i a0 = _mm_loadl_epi64((const __m128i*)&alpha[i]); + const __m128i a1 = _mm_unpacklo_epi8(a0, zero); + const __m128i a2_lo = _mm_unpacklo_epi16(a1, zero); + const __m128i a2_hi = _mm_unpackhi_epi16(a1, zero); + // load 8 dst pixels (32 bytes) + const __m128i b0_lo = _mm_loadu_si128(out + 0); + const __m128i b0_hi = _mm_loadu_si128(out + 1); + // mask dst alpha values + const __m128i b1_lo = _mm_and_si128(b0_lo, rgb_mask); + const __m128i b1_hi = _mm_and_si128(b0_hi, rgb_mask); + // combine + const __m128i b2_lo = _mm_or_si128(b1_lo, a2_lo); + const __m128i b2_hi = _mm_or_si128(b1_hi, a2_hi); + // store + _mm_storeu_si128(out + 0, b2_lo); + _mm_storeu_si128(out + 1, b2_hi); + // accumulate eight alpha 'and' in parallel + all_alphas = _mm_and_si128(all_alphas, a0); + out += 2; + } + for (; i < width; ++i) { + const uint32_t alpha_value = alpha[i]; + dst[4 * i] = alpha_value; + alpha_and &= alpha_value; + } + alpha += alpha_stride; + dst += dst_stride; + } + // Combine the eight alpha 'and' into a 8-bit mask. + alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff)); + return (alpha_and != 0xff); +} + +static void DispatchAlphaToGreen_SSE2(const uint8_t* WEBP_RESTRICT alpha, + int alpha_stride, int width, int height, + uint32_t* WEBP_RESTRICT dst, + int dst_stride) { + int i, j; + const __m128i zero = _mm_setzero_si128(); + const int limit = width & ~15; + for (j = 0; j < height; ++j) { + for (i = 0; i < limit; i += 16) { // process 16 alpha bytes + const __m128i a0 = _mm_loadu_si128((const __m128i*)&alpha[i]); + const __m128i a1 = _mm_unpacklo_epi8(zero, a0); // note the 'zero' first! + const __m128i b1 = _mm_unpackhi_epi8(zero, a0); + const __m128i a2_lo = _mm_unpacklo_epi16(a1, zero); + const __m128i b2_lo = _mm_unpacklo_epi16(b1, zero); + const __m128i a2_hi = _mm_unpackhi_epi16(a1, zero); + const __m128i b2_hi = _mm_unpackhi_epi16(b1, zero); + _mm_storeu_si128((__m128i*)&dst[i + 0], a2_lo); + _mm_storeu_si128((__m128i*)&dst[i + 4], a2_hi); + _mm_storeu_si128((__m128i*)&dst[i + 8], b2_lo); + _mm_storeu_si128((__m128i*)&dst[i + 12], b2_hi); + } + for (; i < width; ++i) dst[i] = alpha[i] << 8; + alpha += alpha_stride; + dst += dst_stride; + } +} + +static int ExtractAlpha_SSE2(const uint8_t* WEBP_RESTRICT argb, int argb_stride, + int width, int height, + uint8_t* WEBP_RESTRICT alpha, int alpha_stride) { + // alpha_and stores an 'and' operation of all the alpha[] values. The final + // value is not 0xff if any of the alpha[] is not equal to 0xff. + uint32_t alpha_and = 0xff; + int i, j; + const __m128i a_mask = _mm_set1_epi32(0xff); // to preserve alpha + const __m128i all_0xff = _mm_set_epi32(0, 0, ~0, ~0); + __m128i all_alphas = all_0xff; + + // We must be able to access 3 extra bytes after the last written byte + // 'src[4 * width - 4]', because we don't know if alpha is the first or the + // last byte of the quadruplet. + const int limit = (width - 1) & ~7; + + for (j = 0; j < height; ++j) { + const __m128i* src = (const __m128i*)argb; + for (i = 0; i < limit; i += 8) { + // load 32 argb bytes + const __m128i a0 = _mm_loadu_si128(src + 0); + const __m128i a1 = _mm_loadu_si128(src + 1); + const __m128i b0 = _mm_and_si128(a0, a_mask); + const __m128i b1 = _mm_and_si128(a1, a_mask); + const __m128i c0 = _mm_packs_epi32(b0, b1); + const __m128i d0 = _mm_packus_epi16(c0, c0); + // store + _mm_storel_epi64((__m128i*)&alpha[i], d0); + // accumulate eight alpha 'and' in parallel + all_alphas = _mm_and_si128(all_alphas, d0); + src += 2; + } + for (; i < width; ++i) { + const uint32_t alpha_value = argb[4 * i]; + alpha[i] = alpha_value; + alpha_and &= alpha_value; + } + argb += argb_stride; + alpha += alpha_stride; + } + // Combine the eight alpha 'and' into a 8-bit mask. + alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff)); + return (alpha_and == 0xff); +} + +static void ExtractGreen_SSE2(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT alpha, int size) { + int i; + const __m128i mask = _mm_set1_epi32(0xff); + const __m128i* src = (const __m128i*)argb; + + for (i = 0; i + 16 <= size; i += 16, src += 4) { + const __m128i a0 = _mm_loadu_si128(src + 0); + const __m128i a1 = _mm_loadu_si128(src + 1); + const __m128i a2 = _mm_loadu_si128(src + 2); + const __m128i a3 = _mm_loadu_si128(src + 3); + const __m128i b0 = _mm_srli_epi32(a0, 8); + const __m128i b1 = _mm_srli_epi32(a1, 8); + const __m128i b2 = _mm_srli_epi32(a2, 8); + const __m128i b3 = _mm_srli_epi32(a3, 8); + const __m128i c0 = _mm_and_si128(b0, mask); + const __m128i c1 = _mm_and_si128(b1, mask); + const __m128i c2 = _mm_and_si128(b2, mask); + const __m128i c3 = _mm_and_si128(b3, mask); + const __m128i d0 = _mm_packs_epi32(c0, c1); + const __m128i d1 = _mm_packs_epi32(c2, c3); + const __m128i e = _mm_packus_epi16(d0, d1); + // store + _mm_storeu_si128((__m128i*)&alpha[i], e); + } + if (i + 8 <= size) { + const __m128i a0 = _mm_loadu_si128(src + 0); + const __m128i a1 = _mm_loadu_si128(src + 1); + const __m128i b0 = _mm_srli_epi32(a0, 8); + const __m128i b1 = _mm_srli_epi32(a1, 8); + const __m128i c0 = _mm_and_si128(b0, mask); + const __m128i c1 = _mm_and_si128(b1, mask); + const __m128i d = _mm_packs_epi32(c0, c1); + const __m128i e = _mm_packus_epi16(d, d); + _mm_storel_epi64((__m128i*)&alpha[i], e); + i += 8; + } + for (; i < size; ++i) alpha[i] = argb[i] >> 8; +} + +//------------------------------------------------------------------------------ +// Non-dither premultiplied modes + +#define MULTIPLIER(a) ((a) * 0x8081) +#define PREMULTIPLY(x, m) (((x) * (m)) >> 23) + +// We can't use a 'const int' for the SHUFFLE value, because it has to be an +// immediate in the _mm_shufflexx_epi16() instruction. We really need a macro. +// We use: v / 255 = (v * 0x8081) >> 23, where v = alpha * {r,g,b} is a 16bit +// value. +#define APPLY_ALPHA(RGBX, SHUFFLE) do { \ + const __m128i argb0 = _mm_loadu_si128((const __m128i*)&(RGBX)); \ + const __m128i argb1_lo = _mm_unpacklo_epi8(argb0, zero); \ + const __m128i argb1_hi = _mm_unpackhi_epi8(argb0, zero); \ + const __m128i alpha0_lo = _mm_or_si128(argb1_lo, kMask); \ + const __m128i alpha0_hi = _mm_or_si128(argb1_hi, kMask); \ + const __m128i alpha1_lo = _mm_shufflelo_epi16(alpha0_lo, SHUFFLE); \ + const __m128i alpha1_hi = _mm_shufflelo_epi16(alpha0_hi, SHUFFLE); \ + const __m128i alpha2_lo = _mm_shufflehi_epi16(alpha1_lo, SHUFFLE); \ + const __m128i alpha2_hi = _mm_shufflehi_epi16(alpha1_hi, SHUFFLE); \ + /* alpha2 = [ff a0 a0 a0][ff a1 a1 a1] */ \ + const __m128i A0_lo = _mm_mullo_epi16(alpha2_lo, argb1_lo); \ + const __m128i A0_hi = _mm_mullo_epi16(alpha2_hi, argb1_hi); \ + const __m128i A1_lo = _mm_mulhi_epu16(A0_lo, kMult); \ + const __m128i A1_hi = _mm_mulhi_epu16(A0_hi, kMult); \ + const __m128i A2_lo = _mm_srli_epi16(A1_lo, 7); \ + const __m128i A2_hi = _mm_srli_epi16(A1_hi, 7); \ + const __m128i A3 = _mm_packus_epi16(A2_lo, A2_hi); \ + _mm_storeu_si128((__m128i*)&(RGBX), A3); \ +} while (0) + +static void ApplyAlphaMultiply_SSE2(uint8_t* rgba, int alpha_first, + int w, int h, int stride) { + const __m128i zero = _mm_setzero_si128(); + const __m128i kMult = _mm_set1_epi16((short)0x8081); + const __m128i kMask = _mm_set_epi16(0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0); + const int kSpan = 4; + while (h-- > 0) { + uint32_t* const rgbx = (uint32_t*)rgba; + int i; + if (!alpha_first) { + for (i = 0; i + kSpan <= w; i += kSpan) { + APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(2, 3, 3, 3)); + } + } else { + for (i = 0; i + kSpan <= w; i += kSpan) { + APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 0, 0, 1)); + } + } + // Finish with left-overs. + for (; i < w; ++i) { + uint8_t* const rgb = rgba + (alpha_first ? 1 : 0); + const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3); + const uint32_t a = alpha[4 * i]; + if (a != 0xff) { + const uint32_t mult = MULTIPLIER(a); + rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult); + rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult); + rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult); + } + } + rgba += stride; + } +} +#undef MULTIPLIER +#undef PREMULTIPLY + +//------------------------------------------------------------------------------ +// Alpha detection + +static int HasAlpha8b_SSE2(const uint8_t* src, int length) { + const __m128i all_0xff = _mm_set1_epi8((char)0xff); + int i = 0; + for (; i + 16 <= length; i += 16) { + const __m128i v = _mm_loadu_si128((const __m128i*)(src + i)); + const __m128i bits = _mm_cmpeq_epi8(v, all_0xff); + const int mask = _mm_movemask_epi8(bits); + if (mask != 0xffff) return 1; + } + for (; i < length; ++i) if (src[i] != 0xff) return 1; + return 0; +} + +static int HasAlpha32b_SSE2(const uint8_t* src, int length) { + const __m128i alpha_mask = _mm_set1_epi32(0xff); + const __m128i all_0xff = _mm_set1_epi8((char)0xff); + int i = 0; + // We don't know if we can access the last 3 bytes after the last alpha + // value 'src[4 * length - 4]' (because we don't know if alpha is the first + // or the last byte of the quadruplet). Hence the '-3' protection below. + length = length * 4 - 3; // size in bytes + for (; i + 64 <= length; i += 64) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)(src + i + 0)); + const __m128i a1 = _mm_loadu_si128((const __m128i*)(src + i + 16)); + const __m128i a2 = _mm_loadu_si128((const __m128i*)(src + i + 32)); + const __m128i a3 = _mm_loadu_si128((const __m128i*)(src + i + 48)); + const __m128i b0 = _mm_and_si128(a0, alpha_mask); + const __m128i b1 = _mm_and_si128(a1, alpha_mask); + const __m128i b2 = _mm_and_si128(a2, alpha_mask); + const __m128i b3 = _mm_and_si128(a3, alpha_mask); + const __m128i c0 = _mm_packs_epi32(b0, b1); + const __m128i c1 = _mm_packs_epi32(b2, b3); + const __m128i d = _mm_packus_epi16(c0, c1); + const __m128i bits = _mm_cmpeq_epi8(d, all_0xff); + const int mask = _mm_movemask_epi8(bits); + if (mask != 0xffff) return 1; + } + for (; i + 32 <= length; i += 32) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)(src + i + 0)); + const __m128i a1 = _mm_loadu_si128((const __m128i*)(src + i + 16)); + const __m128i b0 = _mm_and_si128(a0, alpha_mask); + const __m128i b1 = _mm_and_si128(a1, alpha_mask); + const __m128i c = _mm_packs_epi32(b0, b1); + const __m128i d = _mm_packus_epi16(c, c); + const __m128i bits = _mm_cmpeq_epi8(d, all_0xff); + const int mask = _mm_movemask_epi8(bits); + if (mask != 0xffff) return 1; + } + for (; i <= length; i += 4) if (src[i] != 0xff) return 1; + return 0; +} + +static void AlphaReplace_SSE2(uint32_t* src, int length, uint32_t color) { + const __m128i m_color = _mm_set1_epi32((int)color); + const __m128i zero = _mm_setzero_si128(); + int i = 0; + for (; i + 8 <= length; i += 8) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)(src + i + 0)); + const __m128i a1 = _mm_loadu_si128((const __m128i*)(src + i + 4)); + const __m128i b0 = _mm_srai_epi32(a0, 24); + const __m128i b1 = _mm_srai_epi32(a1, 24); + const __m128i c0 = _mm_cmpeq_epi32(b0, zero); + const __m128i c1 = _mm_cmpeq_epi32(b1, zero); + const __m128i d0 = _mm_and_si128(c0, m_color); + const __m128i d1 = _mm_and_si128(c1, m_color); + const __m128i e0 = _mm_andnot_si128(c0, a0); + const __m128i e1 = _mm_andnot_si128(c1, a1); + _mm_storeu_si128((__m128i*)(src + i + 0), _mm_or_si128(d0, e0)); + _mm_storeu_si128((__m128i*)(src + i + 4), _mm_or_si128(d1, e1)); + } + for (; i < length; ++i) if ((src[i] >> 24) == 0) src[i] = color; +} + +// ----------------------------------------------------------------------------- +// Apply alpha value to rows + +static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) { + int x = 0; + if (!inverse) { + const int kSpan = 2; + const __m128i zero = _mm_setzero_si128(); + const __m128i k128 = _mm_set1_epi16(128); + const __m128i kMult = _mm_set1_epi16(0x0101); + const __m128i kMask = _mm_set_epi16(0, 0xff, 0, 0, 0, 0xff, 0, 0); + for (x = 0; x + kSpan <= width; x += kSpan) { + // To compute 'result = (int)(a * x / 255. + .5)', we use: + // tmp = a * v + 128, result = (tmp * 0x0101u) >> 16 + const __m128i A0 = _mm_loadl_epi64((const __m128i*)&ptr[x]); + const __m128i A1 = _mm_unpacklo_epi8(A0, zero); + const __m128i A2 = _mm_or_si128(A1, kMask); + const __m128i A3 = _mm_shufflelo_epi16(A2, _MM_SHUFFLE(2, 3, 3, 3)); + const __m128i A4 = _mm_shufflehi_epi16(A3, _MM_SHUFFLE(2, 3, 3, 3)); + // here, A4 = [ff a0 a0 a0][ff a1 a1 a1] + const __m128i A5 = _mm_mullo_epi16(A4, A1); + const __m128i A6 = _mm_add_epi16(A5, k128); + const __m128i A7 = _mm_mulhi_epu16(A6, kMult); + const __m128i A10 = _mm_packus_epi16(A7, zero); + _mm_storel_epi64((__m128i*)&ptr[x], A10); + } + } + width -= x; + if (width > 0) WebPMultARGBRow_C(ptr + x, width, inverse); +} + +static void MultRow_SSE2(uint8_t* WEBP_RESTRICT const ptr, + const uint8_t* WEBP_RESTRICT const alpha, + int width, int inverse) { + int x = 0; + if (!inverse) { + const __m128i zero = _mm_setzero_si128(); + const __m128i k128 = _mm_set1_epi16(128); + const __m128i kMult = _mm_set1_epi16(0x0101); + for (x = 0; x + 8 <= width; x += 8) { + const __m128i v0 = _mm_loadl_epi64((__m128i*)&ptr[x]); + const __m128i a0 = _mm_loadl_epi64((const __m128i*)&alpha[x]); + const __m128i v1 = _mm_unpacklo_epi8(v0, zero); + const __m128i a1 = _mm_unpacklo_epi8(a0, zero); + const __m128i v2 = _mm_mullo_epi16(v1, a1); + const __m128i v3 = _mm_add_epi16(v2, k128); + const __m128i v4 = _mm_mulhi_epu16(v3, kMult); + const __m128i v5 = _mm_packus_epi16(v4, zero); + _mm_storel_epi64((__m128i*)&ptr[x], v5); + } + } + width -= x; + if (width > 0) WebPMultRow_C(ptr + x, alpha + x, width, inverse); +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitAlphaProcessingSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) { + WebPMultARGBRow = MultARGBRow_SSE2; + WebPMultRow = MultRow_SSE2; + WebPApplyAlphaMultiply = ApplyAlphaMultiply_SSE2; + WebPDispatchAlpha = DispatchAlpha_SSE2; + WebPDispatchAlphaToGreen = DispatchAlphaToGreen_SSE2; + WebPExtractAlpha = ExtractAlpha_SSE2; + WebPExtractGreen = ExtractGreen_SSE2; + + WebPHasAlpha8b = HasAlpha8b_SSE2; + WebPHasAlpha32b = HasAlpha32b_SSE2; + WebPAlphaReplace = AlphaReplace_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/alpha_processing_sse41.c b/libraries/webp/src/dsp/alpha_processing_sse41.c new file mode 100644 index 00000000000..1156ac3417b --- /dev/null +++ b/libraries/webp/src/dsp/alpha_processing_sse41.c @@ -0,0 +1,92 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for processing transparent channel, SSE4.1 variant. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE41) + +#include + +//------------------------------------------------------------------------------ + +static int ExtractAlpha_SSE41(const uint8_t* WEBP_RESTRICT argb, + int argb_stride, int width, int height, + uint8_t* WEBP_RESTRICT alpha, int alpha_stride) { + // alpha_and stores an 'and' operation of all the alpha[] values. The final + // value is not 0xff if any of the alpha[] is not equal to 0xff. + uint32_t alpha_and = 0xff; + int i, j; + const __m128i all_0xff = _mm_set1_epi32(~0); + __m128i all_alphas = all_0xff; + + // We must be able to access 3 extra bytes after the last written byte + // 'src[4 * width - 4]', because we don't know if alpha is the first or the + // last byte of the quadruplet. + const int limit = (width - 1) & ~15; + const __m128i kCstAlpha0 = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 12, 8, 4, 0); + const __m128i kCstAlpha1 = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, + 12, 8, 4, 0, -1, -1, -1, -1); + const __m128i kCstAlpha2 = _mm_set_epi8(-1, -1, -1, -1, 12, 8, 4, 0, + -1, -1, -1, -1, -1, -1, -1, -1); + const __m128i kCstAlpha3 = _mm_set_epi8(12, 8, 4, 0, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1); + for (j = 0; j < height; ++j) { + const __m128i* src = (const __m128i*)argb; + for (i = 0; i < limit; i += 16) { + // load 64 argb bytes + const __m128i a0 = _mm_loadu_si128(src + 0); + const __m128i a1 = _mm_loadu_si128(src + 1); + const __m128i a2 = _mm_loadu_si128(src + 2); + const __m128i a3 = _mm_loadu_si128(src + 3); + const __m128i b0 = _mm_shuffle_epi8(a0, kCstAlpha0); + const __m128i b1 = _mm_shuffle_epi8(a1, kCstAlpha1); + const __m128i b2 = _mm_shuffle_epi8(a2, kCstAlpha2); + const __m128i b3 = _mm_shuffle_epi8(a3, kCstAlpha3); + const __m128i c0 = _mm_or_si128(b0, b1); + const __m128i c1 = _mm_or_si128(b2, b3); + const __m128i d0 = _mm_or_si128(c0, c1); + // store + _mm_storeu_si128((__m128i*)&alpha[i], d0); + // accumulate sixteen alpha 'and' in parallel + all_alphas = _mm_and_si128(all_alphas, d0); + src += 4; + } + for (; i < width; ++i) { + const uint32_t alpha_value = argb[4 * i]; + alpha[i] = alpha_value; + alpha_and &= alpha_value; + } + argb += argb_stride; + alpha += alpha_stride; + } + // Combine the sixteen alpha 'and' into an 8-bit mask. + alpha_and |= 0xff00u; // pretend the upper bits [8..15] were tested ok. + alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff)); + return (alpha_and == 0xffffu); +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitAlphaProcessingSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE41(void) { + WebPExtractAlpha = ExtractAlpha_SSE41; +} + +#else // !WEBP_USE_SSE41 + +WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingSSE41) + +#endif // WEBP_USE_SSE41 diff --git a/libraries/webp/src/dsp/common_sse2.h b/libraries/webp/src/dsp/common_sse2.h new file mode 100644 index 00000000000..e9f1ebff44f --- /dev/null +++ b/libraries/webp/src/dsp/common_sse2.h @@ -0,0 +1,194 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 code common to several files. +// +// Author: Vincent Rabaud (vrabaud@google.com) + +#ifndef WEBP_DSP_COMMON_SSE2_H_ +#define WEBP_DSP_COMMON_SSE2_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(WEBP_USE_SSE2) + +#include + +//------------------------------------------------------------------------------ +// Quite useful macro for debugging. Left here for convenience. + +#if 0 +#include +static WEBP_INLINE void PrintReg(const __m128i r, const char* const name, + int size) { + int n; + union { + __m128i r; + uint8_t i8[16]; + uint16_t i16[8]; + uint32_t i32[4]; + uint64_t i64[2]; + } tmp; + tmp.r = r; + fprintf(stderr, "%s\t: ", name); + if (size == 8) { + for (n = 0; n < 16; ++n) fprintf(stderr, "%.2x ", tmp.i8[n]); + } else if (size == 16) { + for (n = 0; n < 8; ++n) fprintf(stderr, "%.4x ", tmp.i16[n]); + } else if (size == 32) { + for (n = 0; n < 4; ++n) fprintf(stderr, "%.8x ", tmp.i32[n]); + } else { + for (n = 0; n < 2; ++n) fprintf(stderr, "%.16lx ", tmp.i64[n]); + } + fprintf(stderr, "\n"); +} +#endif + +//------------------------------------------------------------------------------ +// Math functions. + +// Return the sum of all the 8b in the register. +static WEBP_INLINE int VP8HorizontalAdd8b(const __m128i* const a) { + const __m128i zero = _mm_setzero_si128(); + const __m128i sad8x2 = _mm_sad_epu8(*a, zero); + // sum the two sads: sad8x2[0:1] + sad8x2[8:9] + const __m128i sum = _mm_add_epi32(sad8x2, _mm_shuffle_epi32(sad8x2, 2)); + return _mm_cvtsi128_si32(sum); +} + +// Transpose two 4x4 16b matrices horizontally stored in registers. +static WEBP_INLINE void VP8Transpose_2_4x4_16b( + const __m128i* const in0, const __m128i* const in1, + const __m128i* const in2, const __m128i* const in3, __m128i* const out0, + __m128i* const out1, __m128i* const out2, __m128i* const out3) { + // Transpose the two 4x4. + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + const __m128i transpose0_0 = _mm_unpacklo_epi16(*in0, *in1); + const __m128i transpose0_1 = _mm_unpacklo_epi16(*in2, *in3); + const __m128i transpose0_2 = _mm_unpackhi_epi16(*in0, *in1); + const __m128i transpose0_3 = _mm_unpackhi_epi16(*in2, *in3); + // a00 a10 a01 a11 a02 a12 a03 a13 + // a20 a30 a21 a31 a22 a32 a23 a33 + // b00 b10 b01 b11 b02 b12 b03 b13 + // b20 b30 b21 b31 b22 b32 b23 b33 + const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3); + const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3); + // a00 a10 a20 a30 a01 a11 a21 a31 + // b00 b10 b20 b30 b01 b11 b21 b31 + // a02 a12 a22 a32 a03 a13 a23 a33 + // b02 b12 a22 b32 b03 b13 b23 b33 + *out0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1); + *out1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1); + *out2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3); + *out3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 +} + +//------------------------------------------------------------------------------ +// Channel mixing. + +// Function used several times in VP8PlanarTo24b. +// It samples the in buffer as follows: one every two unsigned char is stored +// at the beginning of the buffer, while the other half is stored at the end. +#define VP8PlanarTo24bHelper(IN, OUT) \ + do { \ + const __m128i v_mask = _mm_set1_epi16(0x00ff); \ + /* Take one every two upper 8b values.*/ \ + (OUT##0) = _mm_packus_epi16(_mm_and_si128((IN##0), v_mask), \ + _mm_and_si128((IN##1), v_mask)); \ + (OUT##1) = _mm_packus_epi16(_mm_and_si128((IN##2), v_mask), \ + _mm_and_si128((IN##3), v_mask)); \ + (OUT##2) = _mm_packus_epi16(_mm_and_si128((IN##4), v_mask), \ + _mm_and_si128((IN##5), v_mask)); \ + /* Take one every two lower 8b values.*/ \ + (OUT##3) = _mm_packus_epi16(_mm_srli_epi16((IN##0), 8), \ + _mm_srli_epi16((IN##1), 8)); \ + (OUT##4) = _mm_packus_epi16(_mm_srli_epi16((IN##2), 8), \ + _mm_srli_epi16((IN##3), 8)); \ + (OUT##5) = _mm_packus_epi16(_mm_srli_epi16((IN##4), 8), \ + _mm_srli_epi16((IN##5), 8)); \ + } while (0) + +// Pack the planar buffers +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... +static WEBP_INLINE void VP8PlanarTo24b_SSE2( + __m128i* const in0, __m128i* const in1, __m128i* const in2, + __m128i* const in3, __m128i* const in4, __m128i* const in5) { + // The input is 6 registers of sixteen 8b but for the sake of explanation, + // let's take 6 registers of four 8b values. + // To pack, we will keep taking one every two 8b integer and move it + // around as follows: + // Input: + // r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7 + // Split the 6 registers in two sets of 3 registers: the first set as the even + // 8b bytes, the second the odd ones: + // r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7 + // Repeat the same permutations twice more: + // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7 + // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7 + __m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + VP8PlanarTo24bHelper(*in, tmp); + VP8PlanarTo24bHelper(tmp, *in); + VP8PlanarTo24bHelper(*in, tmp); + // We need to do it two more times than the example as we have sixteen bytes. + { + __m128i out0, out1, out2, out3, out4, out5; + VP8PlanarTo24bHelper(tmp, out); + VP8PlanarTo24bHelper(out, *in); + } +} + +#undef VP8PlanarTo24bHelper + +// Convert four packed four-channel buffers like argbargbargbargb... into the +// split channels aaaaa ... rrrr ... gggg .... bbbbb ...... +static WEBP_INLINE void VP8L32bToPlanar_SSE2(__m128i* const in0, + __m128i* const in1, + __m128i* const in2, + __m128i* const in3) { + // Column-wise transpose. + const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1); + const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1); + const __m128i A2 = _mm_unpacklo_epi8(*in2, *in3); + const __m128i A3 = _mm_unpackhi_epi8(*in2, *in3); + const __m128i B0 = _mm_unpacklo_epi8(A0, A1); + const __m128i B1 = _mm_unpackhi_epi8(A0, A1); + const __m128i B2 = _mm_unpacklo_epi8(A2, A3); + const __m128i B3 = _mm_unpackhi_epi8(A2, A3); + // C0 = g7 g6 ... g1 g0 | b7 b6 ... b1 b0 + // C1 = a7 a6 ... a1 a0 | r7 r6 ... r1 r0 + const __m128i C0 = _mm_unpacklo_epi8(B0, B1); + const __m128i C1 = _mm_unpackhi_epi8(B0, B1); + const __m128i C2 = _mm_unpacklo_epi8(B2, B3); + const __m128i C3 = _mm_unpackhi_epi8(B2, B3); + // Gather the channels. + *in0 = _mm_unpackhi_epi64(C1, C3); + *in1 = _mm_unpacklo_epi64(C1, C3); + *in2 = _mm_unpackhi_epi64(C0, C2); + *in3 = _mm_unpacklo_epi64(C0, C2); +} + +#endif // WEBP_USE_SSE2 + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_COMMON_SSE2_H_ diff --git a/libraries/webp/src/dsp/common_sse41.h b/libraries/webp/src/dsp/common_sse41.h new file mode 100644 index 00000000000..2f173c024a9 --- /dev/null +++ b/libraries/webp/src/dsp/common_sse41.h @@ -0,0 +1,132 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE4 code common to several files. +// +// Author: Vincent Rabaud (vrabaud@google.com) + +#ifndef WEBP_DSP_COMMON_SSE41_H_ +#define WEBP_DSP_COMMON_SSE41_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(WEBP_USE_SSE41) +#include + +//------------------------------------------------------------------------------ +// Channel mixing. +// Shuffles the input buffer as A0 0 0 A1 0 0 A2 ... +#define WEBP_SSE41_SHUFF(OUT, IN0, IN1) \ + OUT##0 = _mm_shuffle_epi8(*IN0, shuff0); \ + OUT##1 = _mm_shuffle_epi8(*IN0, shuff1); \ + OUT##2 = _mm_shuffle_epi8(*IN0, shuff2); \ + OUT##3 = _mm_shuffle_epi8(*IN1, shuff0); \ + OUT##4 = _mm_shuffle_epi8(*IN1, shuff1); \ + OUT##5 = _mm_shuffle_epi8(*IN1, shuff2); + +// Pack the planar buffers +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... +static WEBP_INLINE void VP8PlanarTo24b_SSE41( + __m128i* const in0, __m128i* const in1, __m128i* const in2, + __m128i* const in3, __m128i* const in4, __m128i* const in5) { + __m128i R0, R1, R2, R3, R4, R5; + __m128i G0, G1, G2, G3, G4, G5; + __m128i B0, B1, B2, B3, B4, B5; + + // Process R. + { + const __m128i shuff0 = _mm_set_epi8( + 5, -1, -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0); + const __m128i shuff1 = _mm_set_epi8( + -1, 10, -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1); + const __m128i shuff2 = _mm_set_epi8( + -1, -1, 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1); + WEBP_SSE41_SHUFF(R, in0, in1) + } + + // Process G. + { + // Same as before, just shifted to the left by one and including the right + // padding. + const __m128i shuff0 = _mm_set_epi8( + -1, -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1); + const __m128i shuff1 = _mm_set_epi8( + 10, -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1, 5); + const __m128i shuff2 = _mm_set_epi8( + -1, 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1, -1); + WEBP_SSE41_SHUFF(G, in2, in3) + } + + // Process B. + { + const __m128i shuff0 = _mm_set_epi8( + -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1, -1); + const __m128i shuff1 = _mm_set_epi8( + -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1, 5, -1); + const __m128i shuff2 = _mm_set_epi8( + 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1, -1, 10); + WEBP_SSE41_SHUFF(B, in4, in5) + } + + // OR the different channels. + { + const __m128i RG0 = _mm_or_si128(R0, G0); + const __m128i RG1 = _mm_or_si128(R1, G1); + const __m128i RG2 = _mm_or_si128(R2, G2); + const __m128i RG3 = _mm_or_si128(R3, G3); + const __m128i RG4 = _mm_or_si128(R4, G4); + const __m128i RG5 = _mm_or_si128(R5, G5); + *in0 = _mm_or_si128(RG0, B0); + *in1 = _mm_or_si128(RG1, B1); + *in2 = _mm_or_si128(RG2, B2); + *in3 = _mm_or_si128(RG3, B3); + *in4 = _mm_or_si128(RG4, B4); + *in5 = _mm_or_si128(RG5, B5); + } +} + +#undef WEBP_SSE41_SHUFF + +// Convert four packed four-channel buffers like argbargbargbargb... into the +// split channels aaaaa ... rrrr ... gggg .... bbbbb ...... +static WEBP_INLINE void VP8L32bToPlanar_SSE41(__m128i* const in0, + __m128i* const in1, + __m128i* const in2, + __m128i* const in3) { + // aaaarrrrggggbbbb + const __m128i shuff0 = + _mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0); + const __m128i A0 = _mm_shuffle_epi8(*in0, shuff0); + const __m128i A1 = _mm_shuffle_epi8(*in1, shuff0); + const __m128i A2 = _mm_shuffle_epi8(*in2, shuff0); + const __m128i A3 = _mm_shuffle_epi8(*in3, shuff0); + // A0A1R0R1 + // G0G1B0B1 + // A2A3R2R3 + // G0G1B0B1 + const __m128i B0 = _mm_unpacklo_epi32(A0, A1); + const __m128i B1 = _mm_unpackhi_epi32(A0, A1); + const __m128i B2 = _mm_unpacklo_epi32(A2, A3); + const __m128i B3 = _mm_unpackhi_epi32(A2, A3); + *in3 = _mm_unpacklo_epi64(B0, B2); + *in2 = _mm_unpackhi_epi64(B0, B2); + *in1 = _mm_unpacklo_epi64(B1, B3); + *in0 = _mm_unpackhi_epi64(B1, B3); +} + +#endif // WEBP_USE_SSE41 + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_COMMON_SSE41_H_ diff --git a/libraries/webp/src/dsp/cost.c b/libraries/webp/src/dsp/cost.c new file mode 100644 index 00000000000..73d2140177c --- /dev/null +++ b/libraries/webp/src/dsp/cost.c @@ -0,0 +1,412 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" +#include "src/enc/cost_enc.h" + +//------------------------------------------------------------------------------ +// Boolean-cost cost table + +const uint16_t VP8EntropyCost[256] = { + 1792, 1792, 1792, 1536, 1536, 1408, 1366, 1280, 1280, 1216, + 1178, 1152, 1110, 1076, 1061, 1024, 1024, 992, 968, 951, + 939, 911, 896, 878, 871, 854, 838, 820, 811, 794, + 786, 768, 768, 752, 740, 732, 720, 709, 704, 690, + 683, 672, 666, 655, 647, 640, 631, 622, 615, 607, + 598, 592, 586, 576, 572, 564, 559, 555, 547, 541, + 534, 528, 522, 512, 512, 504, 500, 494, 488, 483, + 477, 473, 467, 461, 458, 452, 448, 443, 438, 434, + 427, 424, 419, 415, 410, 406, 403, 399, 394, 390, + 384, 384, 377, 374, 370, 366, 362, 359, 355, 351, + 347, 342, 342, 336, 333, 330, 326, 323, 320, 316, + 312, 308, 305, 302, 299, 296, 293, 288, 287, 283, + 280, 277, 274, 272, 268, 266, 262, 256, 256, 256, + 251, 248, 245, 242, 240, 237, 234, 232, 228, 226, + 223, 221, 218, 216, 214, 211, 208, 205, 203, 201, + 198, 196, 192, 191, 188, 187, 183, 181, 179, 176, + 175, 171, 171, 168, 165, 163, 160, 159, 156, 154, + 152, 150, 148, 146, 144, 142, 139, 138, 135, 133, + 131, 128, 128, 125, 123, 121, 119, 117, 115, 113, + 111, 110, 107, 105, 103, 102, 100, 98, 96, 94, + 92, 91, 89, 86, 86, 83, 82, 80, 77, 76, + 74, 73, 71, 69, 67, 66, 64, 63, 61, 59, + 57, 55, 54, 52, 51, 49, 47, 46, 44, 43, + 41, 40, 38, 36, 35, 33, 32, 30, 29, 27, + 25, 24, 22, 21, 19, 18, 16, 15, 13, 12, + 10, 9, 7, 6, 4, 3 +}; + +//------------------------------------------------------------------------------ +// Level cost tables + +// fixed costs for coding levels, deduce from the coding tree. +// This is only the part that doesn't depend on the probability state. +const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1] = { + 0, 256, 256, 256, 256, 432, 618, 630, + 731, 640, 640, 828, 901, 948, 1021, 1101, + 1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202, + 1245, 1275, 1318, 1337, 1380, 1410, 1453, 1497, + 1540, 1570, 1613, 1280, 1295, 1317, 1332, 1358, + 1373, 1395, 1410, 1454, 1469, 1491, 1506, 1532, + 1547, 1569, 1584, 1601, 1616, 1638, 1653, 1679, + 1694, 1716, 1731, 1775, 1790, 1812, 1827, 1853, + 1868, 1890, 1905, 1727, 1733, 1742, 1748, 1759, + 1765, 1774, 1780, 1800, 1806, 1815, 1821, 1832, + 1838, 1847, 1853, 1878, 1884, 1893, 1899, 1910, + 1916, 1925, 1931, 1951, 1957, 1966, 1972, 1983, + 1989, 1998, 2004, 2027, 2033, 2042, 2048, 2059, + 2065, 2074, 2080, 2100, 2106, 2115, 2121, 2132, + 2138, 2147, 2153, 2178, 2184, 2193, 2199, 2210, + 2216, 2225, 2231, 2251, 2257, 2266, 2272, 2283, + 2289, 2298, 2304, 2168, 2174, 2183, 2189, 2200, + 2206, 2215, 2221, 2241, 2247, 2256, 2262, 2273, + 2279, 2288, 2294, 2319, 2325, 2334, 2340, 2351, + 2357, 2366, 2372, 2392, 2398, 2407, 2413, 2424, + 2430, 2439, 2445, 2468, 2474, 2483, 2489, 2500, + 2506, 2515, 2521, 2541, 2547, 2556, 2562, 2573, + 2579, 2588, 2594, 2619, 2625, 2634, 2640, 2651, + 2657, 2666, 2672, 2692, 2698, 2707, 2713, 2724, + 2730, 2739, 2745, 2540, 2546, 2555, 2561, 2572, + 2578, 2587, 2593, 2613, 2619, 2628, 2634, 2645, + 2651, 2660, 2666, 2691, 2697, 2706, 2712, 2723, + 2729, 2738, 2744, 2764, 2770, 2779, 2785, 2796, + 2802, 2811, 2817, 2840, 2846, 2855, 2861, 2872, + 2878, 2887, 2893, 2913, 2919, 2928, 2934, 2945, + 2951, 2960, 2966, 2991, 2997, 3006, 3012, 3023, + 3029, 3038, 3044, 3064, 3070, 3079, 3085, 3096, + 3102, 3111, 3117, 2981, 2987, 2996, 3002, 3013, + 3019, 3028, 3034, 3054, 3060, 3069, 3075, 3086, + 3092, 3101, 3107, 3132, 3138, 3147, 3153, 3164, + 3170, 3179, 3185, 3205, 3211, 3220, 3226, 3237, + 3243, 3252, 3258, 3281, 3287, 3296, 3302, 3313, + 3319, 3328, 3334, 3354, 3360, 3369, 3375, 3386, + 3392, 3401, 3407, 3432, 3438, 3447, 3453, 3464, + 3470, 3479, 3485, 3505, 3511, 3520, 3526, 3537, + 3543, 3552, 3558, 2816, 2822, 2831, 2837, 2848, + 2854, 2863, 2869, 2889, 2895, 2904, 2910, 2921, + 2927, 2936, 2942, 2967, 2973, 2982, 2988, 2999, + 3005, 3014, 3020, 3040, 3046, 3055, 3061, 3072, + 3078, 3087, 3093, 3116, 3122, 3131, 3137, 3148, + 3154, 3163, 3169, 3189, 3195, 3204, 3210, 3221, + 3227, 3236, 3242, 3267, 3273, 3282, 3288, 3299, + 3305, 3314, 3320, 3340, 3346, 3355, 3361, 3372, + 3378, 3387, 3393, 3257, 3263, 3272, 3278, 3289, + 3295, 3304, 3310, 3330, 3336, 3345, 3351, 3362, + 3368, 3377, 3383, 3408, 3414, 3423, 3429, 3440, + 3446, 3455, 3461, 3481, 3487, 3496, 3502, 3513, + 3519, 3528, 3534, 3557, 3563, 3572, 3578, 3589, + 3595, 3604, 3610, 3630, 3636, 3645, 3651, 3662, + 3668, 3677, 3683, 3708, 3714, 3723, 3729, 3740, + 3746, 3755, 3761, 3781, 3787, 3796, 3802, 3813, + 3819, 3828, 3834, 3629, 3635, 3644, 3650, 3661, + 3667, 3676, 3682, 3702, 3708, 3717, 3723, 3734, + 3740, 3749, 3755, 3780, 3786, 3795, 3801, 3812, + 3818, 3827, 3833, 3853, 3859, 3868, 3874, 3885, + 3891, 3900, 3906, 3929, 3935, 3944, 3950, 3961, + 3967, 3976, 3982, 4002, 4008, 4017, 4023, 4034, + 4040, 4049, 4055, 4080, 4086, 4095, 4101, 4112, + 4118, 4127, 4133, 4153, 4159, 4168, 4174, 4185, + 4191, 4200, 4206, 4070, 4076, 4085, 4091, 4102, + 4108, 4117, 4123, 4143, 4149, 4158, 4164, 4175, + 4181, 4190, 4196, 4221, 4227, 4236, 4242, 4253, + 4259, 4268, 4274, 4294, 4300, 4309, 4315, 4326, + 4332, 4341, 4347, 4370, 4376, 4385, 4391, 4402, + 4408, 4417, 4423, 4443, 4449, 4458, 4464, 4475, + 4481, 4490, 4496, 4521, 4527, 4536, 4542, 4553, + 4559, 4568, 4574, 4594, 4600, 4609, 4615, 4626, + 4632, 4641, 4647, 3515, 3521, 3530, 3536, 3547, + 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620, + 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698, + 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771, + 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847, + 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920, + 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998, + 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071, + 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988, + 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061, + 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139, + 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212, + 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288, + 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361, + 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439, + 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512, + 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360, + 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433, + 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511, + 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584, + 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660, + 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733, + 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811, + 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884, + 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801, + 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874, + 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952, + 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025, + 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101, + 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174, + 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252, + 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325, + 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636, + 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709, + 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787, + 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860, + 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936, + 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009, + 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087, + 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160, + 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077, + 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150, + 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228, + 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301, + 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377, + 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450, + 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528, + 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601, + 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449, + 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522, + 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600, + 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673, + 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749, + 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822, + 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900, + 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973, + 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890, + 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963, + 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041, + 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114, + 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190, + 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263, + 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341, + 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414, + 6420, 6429, 6435, 3515, 3521, 3530, 3536, 3547, + 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620, + 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698, + 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771, + 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847, + 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920, + 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998, + 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071, + 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988, + 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061, + 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139, + 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212, + 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288, + 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361, + 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439, + 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512, + 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360, + 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433, + 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511, + 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584, + 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660, + 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733, + 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811, + 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884, + 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801, + 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874, + 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952, + 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025, + 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101, + 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174, + 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252, + 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325, + 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636, + 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709, + 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787, + 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860, + 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936, + 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009, + 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087, + 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160, + 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077, + 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150, + 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228, + 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301, + 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377, + 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450, + 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528, + 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601, + 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449, + 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522, + 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600, + 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673, + 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749, + 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822, + 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900, + 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973, + 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890, + 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963, + 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041, + 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114, + 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190, + 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263, + 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341, + 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414, + 6420, 6429, 6435, 5303, 5309, 5318, 5324, 5335, + 5341, 5350, 5356, 5376, 5382, 5391, 5397, 5408, + 5414, 5423, 5429, 5454, 5460, 5469, 5475, 5486, + 5492, 5501, 5507, 5527, 5533, 5542, 5548, 5559, + 5565, 5574, 5580, 5603, 5609, 5618, 5624, 5635, + 5641, 5650, 5656, 5676, 5682, 5691, 5697, 5708, + 5714, 5723, 5729, 5754, 5760, 5769, 5775, 5786, + 5792, 5801, 5807, 5827, 5833, 5842, 5848, 5859, + 5865, 5874, 5880, 5744, 5750, 5759, 5765, 5776, + 5782, 5791, 5797, 5817, 5823, 5832, 5838, 5849, + 5855, 5864, 5870, 5895, 5901, 5910, 5916, 5927, + 5933, 5942, 5948, 5968, 5974, 5983, 5989, 6000, + 6006, 6015, 6021, 6044, 6050, 6059, 6065, 6076, + 6082, 6091, 6097, 6117, 6123, 6132, 6138, 6149, + 6155, 6164, 6170, 6195, 6201, 6210, 6216, 6227, + 6233, 6242, 6248, 6268, 6274, 6283, 6289, 6300, + 6306, 6315, 6321, 6116, 6122, 6131, 6137, 6148, + 6154, 6163, 6169, 6189, 6195, 6204, 6210, 6221, + 6227, 6236, 6242, 6267, 6273, 6282, 6288, 6299, + 6305, 6314, 6320, 6340, 6346, 6355, 6361, 6372, + 6378, 6387, 6393, 6416, 6422, 6431, 6437, 6448, + 6454, 6463, 6469, 6489, 6495, 6504, 6510, 6521, + 6527, 6536, 6542, 6567, 6573, 6582, 6588, 6599, + 6605, 6614, 6620, 6640, 6646, 6655, 6661, 6672, + 6678, 6687, 6693, 6557, 6563, 6572, 6578, 6589, + 6595, 6604, 6610, 6630, 6636, 6645, 6651, 6662, + 6668, 6677, 6683, 6708, 6714, 6723, 6729, 6740, + 6746, 6755, 6761, 6781, 6787, 6796, 6802, 6813, + 6819, 6828, 6834, 6857, 6863, 6872, 6878, 6889, + 6895, 6904, 6910, 6930, 6936, 6945, 6951, 6962, + 6968, 6977, 6983, 7008, 7014, 7023, 7029, 7040, + 7046, 7055, 7061, 7081, 7087, 7096, 7102, 7113, + 7119, 7128, 7134, 6392, 6398, 6407, 6413, 6424, + 6430, 6439, 6445, 6465, 6471, 6480, 6486, 6497, + 6503, 6512, 6518, 6543, 6549, 6558, 6564, 6575, + 6581, 6590, 6596, 6616, 6622, 6631, 6637, 6648, + 6654, 6663, 6669, 6692, 6698, 6707, 6713, 6724, + 6730, 6739, 6745, 6765, 6771, 6780, 6786, 6797, + 6803, 6812, 6818, 6843, 6849, 6858, 6864, 6875, + 6881, 6890, 6896, 6916, 6922, 6931, 6937, 6948, + 6954, 6963, 6969, 6833, 6839, 6848, 6854, 6865, + 6871, 6880, 6886, 6906, 6912, 6921, 6927, 6938, + 6944, 6953, 6959, 6984, 6990, 6999, 7005, 7016, + 7022, 7031, 7037, 7057, 7063, 7072, 7078, 7089, + 7095, 7104, 7110, 7133, 7139, 7148, 7154, 7165, + 7171, 7180, 7186, 7206, 7212, 7221, 7227, 7238, + 7244, 7253, 7259, 7284, 7290, 7299, 7305, 7316, + 7322, 7331, 7337, 7357, 7363, 7372, 7378, 7389, + 7395, 7404, 7410, 7205, 7211, 7220, 7226, 7237, + 7243, 7252, 7258, 7278, 7284, 7293, 7299, 7310, + 7316, 7325, 7331, 7356, 7362, 7371, 7377, 7388, + 7394, 7403, 7409, 7429, 7435, 7444, 7450, 7461, + 7467, 7476, 7482, 7505, 7511, 7520, 7526, 7537, + 7543, 7552, 7558, 7578, 7584, 7593, 7599, 7610, + 7616, 7625, 7631, 7656, 7662, 7671, 7677, 7688, + 7694, 7703, 7709, 7729, 7735, 7744, 7750, 7761 +}; + +//------------------------------------------------------------------------------ +// Tables for level coding + +const uint8_t VP8EncBands[16 + 1] = { + 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, + 0 // sentinel +}; + +//------------------------------------------------------------------------------ +// Mode costs + +static int GetResidualCost_C(int ctx0, const VP8Residual* const res) { + int n = res->first; + // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 + const int p0 = res->prob[n][ctx0][0]; + CostArrayPtr const costs = res->costs; + const uint16_t* t = costs[n][ctx0]; + // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 + // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll + // be missing during the loop. + int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; + + if (res->last < 0) { + return VP8BitCost(0, p0); + } + for (; n < res->last; ++n) { + const int v = abs(res->coeffs[n]); + const int ctx = (v >= 2) ? 2 : v; + cost += VP8LevelCost(t, v); + t = costs[n + 1][ctx]; + } + // Last coefficient is always non-zero + { + const int v = abs(res->coeffs[n]); + assert(v != 0); + cost += VP8LevelCost(t, v); + if (n < 15) { + const int b = VP8EncBands[n + 1]; + const int ctx = (v == 1) ? 1 : 2; + const int last_p0 = res->prob[b][ctx][0]; + cost += VP8BitCost(0, last_p0); + } + } + return cost; +} + +static void SetResidualCoeffs_C(const int16_t* const coeffs, + VP8Residual* const res) { + int n; + res->last = -1; + assert(res->first == 0 || coeffs[0] == 0); + for (n = 15; n >= 0; --n) { + if (coeffs[n]) { + res->last = n; + break; + } + } + res->coeffs = coeffs; +} + +//------------------------------------------------------------------------------ +// init function + +VP8GetResidualCostFunc VP8GetResidualCost; +VP8SetResidualCoeffsFunc VP8SetResidualCoeffs; + +extern VP8CPUInfo VP8GetCPUInfo; +extern void VP8EncDspCostInitMIPS32(void); +extern void VP8EncDspCostInitMIPSdspR2(void); +extern void VP8EncDspCostInitSSE2(void); +extern void VP8EncDspCostInitNEON(void); + +WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) { + VP8GetResidualCost = GetResidualCost_C; + VP8SetResidualCoeffs = SetResidualCoeffs_C; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_USE_MIPS32) + if (VP8GetCPUInfo(kMIPS32)) { + VP8EncDspCostInitMIPS32(); + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + VP8EncDspCostInitMIPSdspR2(); + } +#endif +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8EncDspCostInitSSE2(); + } +#endif +#if defined(WEBP_HAVE_NEON) + if (VP8GetCPUInfo(kNEON)) { + VP8EncDspCostInitNEON(); + } +#endif + } +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dsp/cost_mips32.c b/libraries/webp/src/dsp/cost_mips32.c new file mode 100644 index 00000000000..0500f88c132 --- /dev/null +++ b/libraries/webp/src/dsp/cost_mips32.c @@ -0,0 +1,154 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Djordje Pesut (djordje.pesut@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS32) + +#include "src/enc/cost_enc.h" + +static int GetResidualCost_MIPS32(int ctx0, const VP8Residual* const res) { + int temp0, temp1; + int v_reg, ctx_reg; + int n = res->first; + // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 + int p0 = res->prob[n][ctx0][0]; + CostArrayPtr const costs = res->costs; + const uint16_t* t = costs[n][ctx0]; + // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 + // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll + // be missing during the loop. + int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; + const int16_t* res_coeffs = res->coeffs; + const int res_last = res->last; + const int const_max_level = MAX_VARIABLE_LEVEL; + const int const_2 = 2; + const uint16_t** p_costs = &costs[n][0]; + const size_t inc_p_costs = NUM_CTX * sizeof(*p_costs); + + if (res->last < 0) { + return VP8BitCost(0, p0); + } + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "subu %[temp1], %[res_last], %[n] \n\t" + "sll %[temp0], %[n], 1 \n\t" + "blez %[temp1], 2f \n\t" + " addu %[res_coeffs], %[res_coeffs], %[temp0] \n\t" + "1: \n\t" + "lh %[v_reg], 0(%[res_coeffs]) \n\t" + "addiu %[n], %[n], 1 \n\t" + "negu %[temp0], %[v_reg] \n\t" + "slti %[temp1], %[v_reg], 0 \n\t" + "movn %[v_reg], %[temp0], %[temp1] \n\t" + "sltiu %[temp0], %[v_reg], 2 \n\t" + "move %[ctx_reg], %[v_reg] \n\t" + "movz %[ctx_reg], %[const_2], %[temp0] \n\t" + "sll %[temp1], %[v_reg], 1 \n\t" + "addu %[temp1], %[temp1], %[VP8LevelFixedCosts] \n\t" + "lhu %[temp1], 0(%[temp1]) \n\t" + "slt %[temp0], %[v_reg], %[const_max_level] \n\t" + "movz %[v_reg], %[const_max_level], %[temp0] \n\t" + "addu %[cost], %[cost], %[temp1] \n\t" + "sll %[v_reg], %[v_reg], 1 \n\t" + "sll %[ctx_reg], %[ctx_reg], 2 \n\t" + "addu %[v_reg], %[v_reg], %[t] \n\t" + "lhu %[temp0], 0(%[v_reg]) \n\t" + "addu %[p_costs], %[p_costs], %[inc_p_costs] \n\t" + "addu %[t], %[p_costs], %[ctx_reg] \n\t" + "addu %[cost], %[cost], %[temp0] \n\t" + "addiu %[res_coeffs], %[res_coeffs], 2 \n\t" + "bne %[n], %[res_last], 1b \n\t" + " lw %[t], 0(%[t]) \n\t" + "2: \n\t" + ".set pop \n\t" + : [cost]"+&r"(cost), [t]"+&r"(t), [n]"+&r"(n), [v_reg]"=&r"(v_reg), + [ctx_reg]"=&r"(ctx_reg), [p_costs]"+&r"(p_costs), [temp0]"=&r"(temp0), + [temp1]"=&r"(temp1), [res_coeffs]"+&r"(res_coeffs) + : [const_2]"r"(const_2), [const_max_level]"r"(const_max_level), + [VP8LevelFixedCosts]"r"(VP8LevelFixedCosts), [res_last]"r"(res_last), + [inc_p_costs]"r"(inc_p_costs) + : "memory" + ); + + // Last coefficient is always non-zero + { + const int v = abs(res->coeffs[n]); + assert(v != 0); + cost += VP8LevelCost(t, v); + if (n < 15) { + const int b = VP8EncBands[n + 1]; + const int ctx = (v == 1) ? 1 : 2; + const int last_p0 = res->prob[b][ctx][0]; + cost += VP8BitCost(0, last_p0); + } + } + return cost; +} + +static void SetResidualCoeffs_MIPS32(const int16_t* const coeffs, + VP8Residual* const res) { + const int16_t* p_coeffs = (int16_t*)coeffs; + int temp0, temp1, temp2, n, n1; + assert(res->first == 0 || coeffs[0] == 0); + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[p_coeffs], %[p_coeffs], 28 \n\t" + "li %[n], 15 \n\t" + "li %[temp2], -1 \n\t" + "0: \n\t" + "ulw %[temp0], 0(%[p_coeffs]) \n\t" + "beqz %[temp0], 1f \n\t" +#if defined(WORDS_BIGENDIAN) + " sll %[temp1], %[temp0], 16 \n\t" +#else + " srl %[temp1], %[temp0], 16 \n\t" +#endif + "addiu %[n1], %[n], -1 \n\t" + "movz %[temp0], %[n1], %[temp1] \n\t" + "movn %[temp0], %[n], %[temp1] \n\t" + "j 2f \n\t" + " addiu %[temp2], %[temp0], 0 \n\t" + "1: \n\t" + "addiu %[n], %[n], -2 \n\t" + "bgtz %[n], 0b \n\t" + " addiu %[p_coeffs], %[p_coeffs], -4 \n\t" + "2: \n\t" + ".set pop \n\t" + : [p_coeffs]"+&r"(p_coeffs), [temp0]"=&r"(temp0), + [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [n]"=&r"(n), [n1]"=&r"(n1) + : + : "memory" + ); + res->last = temp2; + res->coeffs = coeffs; +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspCostInitMIPS32(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitMIPS32(void) { + VP8GetResidualCost = GetResidualCost_MIPS32; + VP8SetResidualCoeffs = SetResidualCoeffs_MIPS32; +} + +#else // !WEBP_USE_MIPS32 + +WEBP_DSP_INIT_STUB(VP8EncDspCostInitMIPS32) + +#endif // WEBP_USE_MIPS32 diff --git a/libraries/webp/src/dsp/cost_mips_dsp_r2.c b/libraries/webp/src/dsp/cost_mips_dsp_r2.c new file mode 100644 index 00000000000..51248de7a13 --- /dev/null +++ b/libraries/webp/src/dsp/cost_mips_dsp_r2.c @@ -0,0 +1,107 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Djordje Pesut (djordje.pesut@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +#include "src/enc/cost_enc.h" + +static int GetResidualCost_MIPSdspR2(int ctx0, const VP8Residual* const res) { + int temp0, temp1; + int v_reg, ctx_reg; + int n = res->first; + // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 + int p0 = res->prob[n][ctx0][0]; + CostArrayPtr const costs = res->costs; + const uint16_t* t = costs[n][ctx0]; + // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 + // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll + // be missing during the loop. + int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; + const int16_t* res_coeffs = res->coeffs; + const int res_last = res->last; + const int const_max_level = MAX_VARIABLE_LEVEL; + const int const_2 = 2; + const uint16_t** p_costs = &costs[n][0]; + const size_t inc_p_costs = NUM_CTX * sizeof(*p_costs); + + if (res->last < 0) { + return VP8BitCost(0, p0); + } + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "subu %[temp1], %[res_last], %[n] \n\t" + "blez %[temp1], 2f \n\t" + " nop \n\t" + "1: \n\t" + "sll %[temp0], %[n], 1 \n\t" + "lhx %[v_reg], %[temp0](%[res_coeffs]) \n\t" + "addiu %[n], %[n], 1 \n\t" + "absq_s.w %[v_reg], %[v_reg] \n\t" + "sltiu %[temp0], %[v_reg], 2 \n\t" + "move %[ctx_reg], %[v_reg] \n\t" + "movz %[ctx_reg], %[const_2], %[temp0] \n\t" + "sll %[temp1], %[v_reg], 1 \n\t" + "lhx %[temp1], %[temp1](%[VP8LevelFixedCosts]) \n\t" + "slt %[temp0], %[v_reg], %[const_max_level] \n\t" + "movz %[v_reg], %[const_max_level], %[temp0] \n\t" + "addu %[cost], %[cost], %[temp1] \n\t" + "sll %[v_reg], %[v_reg], 1 \n\t" + "sll %[ctx_reg], %[ctx_reg], 2 \n\t" + "lhx %[temp0], %[v_reg](%[t]) \n\t" + "addu %[p_costs], %[p_costs], %[inc_p_costs] \n\t" + "addu %[t], %[p_costs], %[ctx_reg] \n\t" + "addu %[cost], %[cost], %[temp0] \n\t" + "bne %[n], %[res_last], 1b \n\t" + " lw %[t], 0(%[t]) \n\t" + "2: \n\t" + ".set pop \n\t" + : [cost]"+&r"(cost), [t]"+&r"(t), [n]"+&r"(n), [v_reg]"=&r"(v_reg), + [ctx_reg]"=&r"(ctx_reg), [p_costs]"+&r"(p_costs), [temp0]"=&r"(temp0), + [temp1]"=&r"(temp1) + : [const_2]"r"(const_2), [const_max_level]"r"(const_max_level), + [VP8LevelFixedCosts]"r"(VP8LevelFixedCosts), [res_last]"r"(res_last), + [res_coeffs]"r"(res_coeffs), [inc_p_costs]"r"(inc_p_costs) + : "memory" + ); + + // Last coefficient is always non-zero + { + const int v = abs(res->coeffs[n]); + assert(v != 0); + cost += VP8LevelCost(t, v); + if (n < 15) { + const int b = VP8EncBands[n + 1]; + const int ctx = (v == 1) ? 1 : 2; + const int last_p0 = res->prob[b][ctx][0]; + cost += VP8BitCost(0, last_p0); + } + } + return cost; +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspCostInitMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitMIPSdspR2(void) { + VP8GetResidualCost = GetResidualCost_MIPSdspR2; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(VP8EncDspCostInitMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/cost_neon.c b/libraries/webp/src/dsp/cost_neon.c new file mode 100644 index 00000000000..6582669cb3f --- /dev/null +++ b/libraries/webp/src/dsp/cost_neon.c @@ -0,0 +1,122 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// ARM NEON version of cost functions + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include "src/dsp/neon.h" +#include "src/enc/cost_enc.h" + +static const uint8_t position[16] = { 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16 }; + +static void SetResidualCoeffs_NEON(const int16_t* const coeffs, + VP8Residual* const res) { + const int16x8_t minus_one = vdupq_n_s16(-1); + const int16x8_t coeffs_0 = vld1q_s16(coeffs); + const int16x8_t coeffs_1 = vld1q_s16(coeffs + 8); + const uint16x8_t eob_0 = vtstq_s16(coeffs_0, minus_one); + const uint16x8_t eob_1 = vtstq_s16(coeffs_1, minus_one); + const uint8x16_t eob = vcombine_u8(vqmovn_u16(eob_0), vqmovn_u16(eob_1)); + const uint8x16_t masked = vandq_u8(eob, vld1q_u8(position)); + +#if WEBP_AARCH64 + res->last = vmaxvq_u8(masked) - 1; +#else + const uint8x8_t eob_8x8 = vmax_u8(vget_low_u8(masked), vget_high_u8(masked)); + const uint16x8_t eob_16x8 = vmovl_u8(eob_8x8); + const uint16x4_t eob_16x4 = + vmax_u16(vget_low_u16(eob_16x8), vget_high_u16(eob_16x8)); + const uint32x4_t eob_32x4 = vmovl_u16(eob_16x4); + uint32x2_t eob_32x2 = + vmax_u32(vget_low_u32(eob_32x4), vget_high_u32(eob_32x4)); + eob_32x2 = vpmax_u32(eob_32x2, eob_32x2); + + vst1_lane_s32(&res->last, vreinterpret_s32_u32(eob_32x2), 0); + --res->last; +#endif // WEBP_AARCH64 + + res->coeffs = coeffs; +} + +static int GetResidualCost_NEON(int ctx0, const VP8Residual* const res) { + uint8_t levels[16], ctxs[16]; + uint16_t abs_levels[16]; + int n = res->first; + // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 + const int p0 = res->prob[n][ctx0][0]; + CostArrayPtr const costs = res->costs; + const uint16_t* t = costs[n][ctx0]; + // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 + // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll + // be missing during the loop. + int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; + + if (res->last < 0) { + return VP8BitCost(0, p0); + } + + { // precompute clamped levels and contexts, packed to 8b. + const uint8x16_t kCst2 = vdupq_n_u8(2); + const uint8x16_t kCst67 = vdupq_n_u8(MAX_VARIABLE_LEVEL); + const int16x8_t c0 = vld1q_s16(res->coeffs); + const int16x8_t c1 = vld1q_s16(res->coeffs + 8); + const uint16x8_t E0 = vreinterpretq_u16_s16(vabsq_s16(c0)); + const uint16x8_t E1 = vreinterpretq_u16_s16(vabsq_s16(c1)); + const uint8x16_t F = vcombine_u8(vqmovn_u16(E0), vqmovn_u16(E1)); + const uint8x16_t G = vminq_u8(F, kCst2); // context = 0,1,2 + const uint8x16_t H = vminq_u8(F, kCst67); // clamp_level in [0..67] + + vst1q_u8(ctxs, G); + vst1q_u8(levels, H); + + vst1q_u16(abs_levels, E0); + vst1q_u16(abs_levels + 8, E1); + } + for (; n < res->last; ++n) { + const int ctx = ctxs[n]; + const int level = levels[n]; + const int flevel = abs_levels[n]; // full level + cost += VP8LevelFixedCosts[flevel] + t[level]; // simplified VP8LevelCost() + t = costs[n + 1][ctx]; + } + // Last coefficient is always non-zero + { + const int level = levels[n]; + const int flevel = abs_levels[n]; + assert(flevel != 0); + cost += VP8LevelFixedCosts[flevel] + t[level]; + if (n < 15) { + const int b = VP8EncBands[n + 1]; + const int ctx = ctxs[n]; + const int last_p0 = res->prob[b][ctx][0]; + cost += VP8BitCost(0, last_p0); + } + } + return cost; +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspCostInitNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitNEON(void) { + VP8SetResidualCoeffs = SetResidualCoeffs_NEON; + VP8GetResidualCost = GetResidualCost_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(VP8EncDspCostInitNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/cost_sse2.c b/libraries/webp/src/dsp/cost_sse2.c new file mode 100644 index 00000000000..487a079921c --- /dev/null +++ b/libraries/webp/src/dsp/cost_sse2.c @@ -0,0 +1,119 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 version of cost functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) +#include + +#include "src/enc/cost_enc.h" +#include "src/enc/vp8i_enc.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ + +static void SetResidualCoeffs_SSE2(const int16_t* const coeffs, + VP8Residual* const res) { + const __m128i c0 = _mm_loadu_si128((const __m128i*)(coeffs + 0)); + const __m128i c1 = _mm_loadu_si128((const __m128i*)(coeffs + 8)); + // Use SSE2 to compare 16 values with a single instruction. + const __m128i zero = _mm_setzero_si128(); + const __m128i m0 = _mm_packs_epi16(c0, c1); + const __m128i m1 = _mm_cmpeq_epi8(m0, zero); + // Get the comparison results as a bitmask into 16bits. Negate the mask to get + // the position of entries that are not equal to zero. We don't need to mask + // out least significant bits according to res->first, since coeffs[0] is 0 + // if res->first > 0. + const uint32_t mask = 0x0000ffffu ^ (uint32_t)_mm_movemask_epi8(m1); + // The position of the most significant non-zero bit indicates the position of + // the last non-zero value. + assert(res->first == 0 || coeffs[0] == 0); + res->last = mask ? BitsLog2Floor(mask) : -1; + res->coeffs = coeffs; +} + +static int GetResidualCost_SSE2(int ctx0, const VP8Residual* const res) { + uint8_t levels[16], ctxs[16]; + uint16_t abs_levels[16]; + int n = res->first; + // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 + const int p0 = res->prob[n][ctx0][0]; + CostArrayPtr const costs = res->costs; + const uint16_t* t = costs[n][ctx0]; + // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 + // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll + // be missing during the loop. + int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; + + if (res->last < 0) { + return VP8BitCost(0, p0); + } + + { // precompute clamped levels and contexts, packed to 8b. + const __m128i zero = _mm_setzero_si128(); + const __m128i kCst2 = _mm_set1_epi8(2); + const __m128i kCst67 = _mm_set1_epi8(MAX_VARIABLE_LEVEL); + const __m128i c0 = _mm_loadu_si128((const __m128i*)&res->coeffs[0]); + const __m128i c1 = _mm_loadu_si128((const __m128i*)&res->coeffs[8]); + const __m128i D0 = _mm_sub_epi16(zero, c0); + const __m128i D1 = _mm_sub_epi16(zero, c1); + const __m128i E0 = _mm_max_epi16(c0, D0); // abs(v), 16b + const __m128i E1 = _mm_max_epi16(c1, D1); + const __m128i F = _mm_packs_epi16(E0, E1); + const __m128i G = _mm_min_epu8(F, kCst2); // context = 0,1,2 + const __m128i H = _mm_min_epu8(F, kCst67); // clamp_level in [0..67] + + _mm_storeu_si128((__m128i*)&ctxs[0], G); + _mm_storeu_si128((__m128i*)&levels[0], H); + + _mm_storeu_si128((__m128i*)&abs_levels[0], E0); + _mm_storeu_si128((__m128i*)&abs_levels[8], E1); + } + for (; n < res->last; ++n) { + const int ctx = ctxs[n]; + const int level = levels[n]; + const int flevel = abs_levels[n]; // full level + cost += VP8LevelFixedCosts[flevel] + t[level]; // simplified VP8LevelCost() + t = costs[n + 1][ctx]; + } + // Last coefficient is always non-zero + { + const int level = levels[n]; + const int flevel = abs_levels[n]; + assert(flevel != 0); + cost += VP8LevelFixedCosts[flevel] + t[level]; + if (n < 15) { + const int b = VP8EncBands[n + 1]; + const int ctx = ctxs[n]; + const int last_p0 = res->prob[b][ctx][0]; + cost += VP8BitCost(0, last_p0); + } + } + return cost; +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspCostInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitSSE2(void) { + VP8SetResidualCoeffs = SetResidualCoeffs_SSE2; + VP8GetResidualCost = GetResidualCost_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(VP8EncDspCostInitSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/cpu.c b/libraries/webp/src/dsp/cpu.c new file mode 100644 index 00000000000..8ba8f683357 --- /dev/null +++ b/libraries/webp/src/dsp/cpu.c @@ -0,0 +1,247 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// CPU detection +// +// Author: Christian Duvivier (cduvivier@google.com) + +#include "src/dsp/cpu.h" + +#if defined(WEBP_HAVE_NEON_RTCD) +#include +#include +#endif + +#if defined(WEBP_ANDROID_NEON) +#include +#endif + +//------------------------------------------------------------------------------ +// SSE2 detection. +// + +// apple/darwin gcc-4.0.1 defines __PIC__, but not __pic__ with -fPIC. +#if (defined(__pic__) || defined(__PIC__)) && defined(__i386__) +static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) { + __asm__ volatile ( + "mov %%ebx, %%edi\n" + "cpuid\n" + "xchg %%edi, %%ebx\n" + : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type), "c"(0)); +} +#elif defined(__i386__) || defined(__x86_64__) +static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) { + __asm__ volatile ( + "cpuid\n" + : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type), "c"(0)); +} +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) + +#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 150030729 // >= VS2008 SP1 +#include +#define GetCPUInfo(info, type) __cpuidex(info, type, 0) // set ecx=0 +#define WEBP_HAVE_MSC_CPUID +#elif _MSC_VER > 1310 +#include +#define GetCPUInfo __cpuid +#define WEBP_HAVE_MSC_CPUID +#endif + +#endif + +// NaCl has no support for xgetbv or the raw opcode. +#if !defined(__native_client__) && (defined(__i386__) || defined(__x86_64__)) +static WEBP_INLINE uint64_t xgetbv(void) { + const uint32_t ecx = 0; + uint32_t eax, edx; + // Use the raw opcode for xgetbv for compatibility with older toolchains. + __asm__ volatile ( + ".byte 0x0f, 0x01, 0xd0\n" + : "=a"(eax), "=d"(edx) : "c" (ecx)); + return ((uint64_t)edx << 32) | eax; +} +#elif (defined(_M_X64) || defined(_M_IX86)) && \ + defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219 // >= VS2010 SP1 +#include +#define xgetbv() _xgetbv(0) +#elif defined(_MSC_VER) && defined(_M_IX86) +static WEBP_INLINE uint64_t xgetbv(void) { + uint32_t eax_, edx_; + __asm { + xor ecx, ecx // ecx = 0 + // Use the raw opcode for xgetbv for compatibility with older toolchains. + __asm _emit 0x0f __asm _emit 0x01 __asm _emit 0xd0 + mov eax_, eax + mov edx_, edx + } + return ((uint64_t)edx_ << 32) | eax_; +} +#else +#define xgetbv() 0U // no AVX for older x64 or unrecognized toolchains. +#endif + +#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_HAVE_MSC_CPUID) + +// helper function for run-time detection of slow SSSE3 platforms +static int CheckSlowModel(int info) { + // Table listing display models with longer latencies for the bsr instruction + // (ie 2 cycles vs 10/16 cycles) and some SSSE3 instructions like pshufb. + // Refer to Intel 64 and IA-32 Architectures Optimization Reference Manual. + static const uint8_t kSlowModels[] = { + 0x37, 0x4a, 0x4d, // Silvermont Microarchitecture + 0x1c, 0x26, 0x27 // Atom Microarchitecture + }; + const uint32_t model = ((info & 0xf0000) >> 12) | ((info >> 4) & 0xf); + const uint32_t family = (info >> 8) & 0xf; + if (family == 0x06) { + size_t i; + for (i = 0; i < sizeof(kSlowModels) / sizeof(kSlowModels[0]); ++i) { + if (model == kSlowModels[i]) return 1; + } + } + return 0; +} + +static int x86CPUInfo(CPUFeature feature) { + int max_cpuid_value; + int cpu_info[4]; + int is_intel = 0; + + // get the highest feature value cpuid supports + GetCPUInfo(cpu_info, 0); + max_cpuid_value = cpu_info[0]; + if (max_cpuid_value < 1) { + return 0; + } else { + const int VENDOR_ID_INTEL_EBX = 0x756e6547; // uneG + const int VENDOR_ID_INTEL_EDX = 0x49656e69; // Ieni + const int VENDOR_ID_INTEL_ECX = 0x6c65746e; // letn + is_intel = (cpu_info[1] == VENDOR_ID_INTEL_EBX && + cpu_info[2] == VENDOR_ID_INTEL_ECX && + cpu_info[3] == VENDOR_ID_INTEL_EDX); // genuine Intel? + } + + GetCPUInfo(cpu_info, 1); + if (feature == kSSE2) { + return !!(cpu_info[3] & (1 << 26)); + } + if (feature == kSSE3) { + return !!(cpu_info[2] & (1 << 0)); + } + if (feature == kSlowSSSE3) { + if (is_intel && (cpu_info[2] & (1 << 9))) { // SSSE3? + return CheckSlowModel(cpu_info[0]); + } + return 0; + } + + if (feature == kSSE4_1) { + return !!(cpu_info[2] & (1 << 19)); + } + if (feature == kAVX) { + // bits 27 (OSXSAVE) & 28 (256-bit AVX) + if ((cpu_info[2] & 0x18000000) == 0x18000000) { + // XMM state and YMM state enabled by the OS. + return (xgetbv() & 0x6) == 0x6; + } + } + if (feature == kAVX2) { + if (x86CPUInfo(kAVX) && max_cpuid_value >= 7) { + GetCPUInfo(cpu_info, 7); + return !!(cpu_info[1] & (1 << 5)); + } + } + return 0; +} +WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; +VP8CPUInfo VP8GetCPUInfo = x86CPUInfo; +#elif defined(WEBP_ANDROID_NEON) // NB: needs to be before generic NEON test. +static int AndroidCPUInfo(CPUFeature feature) { + const AndroidCpuFamily cpu_family = android_getCpuFamily(); + const uint64_t cpu_features = android_getCpuFeatures(); + if (feature == kNEON) { + return cpu_family == ANDROID_CPU_FAMILY_ARM && + (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) != 0; + } + return 0; +} +WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; +VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo; +#elif defined(EMSCRIPTEN) // also needs to be before generic NEON test +// Use compile flags as an indicator of SIMD support instead of a runtime check. +static int wasmCPUInfo(CPUFeature feature) { + switch (feature) { +#ifdef WEBP_HAVE_SSE2 + case kSSE2: + return 1; +#endif +#ifdef WEBP_HAVE_SSE41 + case kSSE3: + case kSlowSSSE3: + case kSSE4_1: + return 1; +#endif +#ifdef WEBP_HAVE_NEON + case kNEON: + return 1; +#endif + default: + break; + } + return 0; +} +WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; +VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo; +#elif defined(WEBP_HAVE_NEON) +// In most cases this function doesn't check for NEON support (it's assumed by +// the configuration), but enables turning off NEON at runtime, for testing +// purposes, by setting VP8GetCPUInfo = NULL. +static int armCPUInfo(CPUFeature feature) { + if (feature != kNEON) return 0; +#if defined(__linux__) && defined(WEBP_HAVE_NEON_RTCD) + { + int has_neon = 0; + char line[200]; + FILE* const cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo == NULL) return 0; + while (fgets(line, sizeof(line), cpuinfo)) { + if (!strncmp(line, "Features", 8)) { + if (strstr(line, " neon ") != NULL) { + has_neon = 1; + break; + } + } + } + fclose(cpuinfo); + return has_neon; + } +#else + return 1; +#endif +} +WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; +VP8CPUInfo VP8GetCPUInfo = armCPUInfo; +#elif defined(WEBP_USE_MIPS32) || defined(WEBP_USE_MIPS_DSP_R2) || \ + defined(WEBP_USE_MSA) +static int mipsCPUInfo(CPUFeature feature) { + if ((feature == kMIPS32) || (feature == kMIPSdspR2) || (feature == kMSA)) { + return 1; + } else { + return 0; + } + +} +WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; +VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo; +#else +WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; +VP8CPUInfo VP8GetCPUInfo = NULL; +#endif diff --git a/libraries/webp/src/dsp/cpu.h b/libraries/webp/src/dsp/cpu.h new file mode 100644 index 00000000000..9d4d19f32fe --- /dev/null +++ b/libraries/webp/src/dsp/cpu.h @@ -0,0 +1,266 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// CPU detection functions and macros. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DSP_CPU_H_ +#define WEBP_DSP_CPU_H_ + +#include + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include "include/webp/types.h" + +#if defined(__GNUC__) +#define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__) +#define LOCAL_GCC_PREREQ(maj, min) (LOCAL_GCC_VERSION >= (((maj) << 8) | (min))) +#else +#define LOCAL_GCC_VERSION 0 +#define LOCAL_GCC_PREREQ(maj, min) 0 +#endif + +#if defined(__clang__) +#define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__) +#define LOCAL_CLANG_PREREQ(maj, min) \ + (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min))) +#else +#define LOCAL_CLANG_VERSION 0 +#define LOCAL_CLANG_PREREQ(maj, min) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +//------------------------------------------------------------------------------ +// x86 defines. + +#if !defined(HAVE_CONFIG_H) +#if defined(_MSC_VER) && _MSC_VER > 1310 && \ + (defined(_M_X64) || defined(_M_IX86)) +#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1500 && \ + (defined(_M_X64) || defined(_M_IX86)) +#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets +#endif +#endif + +// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp +// files without intrinsics, allowing the corresponding Init() to be called. +// Files containing intrinsics will need to be built targeting the instruction +// set so should succeed on one of the earlier tests. +#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \ + (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2)) +#define WEBP_USE_SSE2 +#endif + +#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2) +#define WEBP_HAVE_SSE2 +#endif + +#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \ + (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41)) +#define WEBP_USE_SSE41 +#endif + +#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41) +#define WEBP_HAVE_SSE41 +#endif + +#undef WEBP_MSC_SSE41 +#undef WEBP_MSC_SSE2 + +//------------------------------------------------------------------------------ +// Arm defines. + +// The intrinsics currently cause compiler errors with arm-nacl-gcc and the +// inline assembly would need to be modified for use with Native Client. +#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \ + (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \ + !defined(__native_client__) +#define WEBP_USE_NEON +#endif + +#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \ + defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H) +#define WEBP_ANDROID_NEON // Android targets that may have NEON +#define WEBP_USE_NEON +#endif + +// Note: ARM64 is supported in Visual Studio 2017, but requires the direct +// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in +// arm_neon.h. Compile errors were seen with Visual Studio 2019 16.4 with +// vtbl4_u8(); a fix was made in 16.6. +#if defined(_MSC_VER) && \ + ((_MSC_VER >= 1700 && defined(_M_ARM)) || \ + (_MSC_VER >= 1926 && (defined(_M_ARM64) || defined(_M_ARM64EC)))) +#define WEBP_USE_NEON +#define WEBP_USE_INTRINSICS +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) +#define WEBP_AARCH64 1 +#else +#define WEBP_AARCH64 0 +#endif + +#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON) +#define WEBP_HAVE_NEON +#endif + +//------------------------------------------------------------------------------ +// MIPS defines. + +#if defined(__mips__) && !defined(__mips64) && defined(__mips_isa_rev) && \ + (__mips_isa_rev >= 1) && (__mips_isa_rev < 6) +#define WEBP_USE_MIPS32 +#if (__mips_isa_rev >= 2) +#define WEBP_USE_MIPS32_R2 +#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2) +#define WEBP_USE_MIPS_DSP_R2 +#endif +#endif +#endif + +#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5) +#define WEBP_USE_MSA +#endif + +//------------------------------------------------------------------------------ + +#ifndef WEBP_DSP_OMIT_C_CODE +#define WEBP_DSP_OMIT_C_CODE 1 +#endif + +#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE +#define WEBP_NEON_OMIT_C_CODE 1 +#else +#define WEBP_NEON_OMIT_C_CODE 0 +#endif + +#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || WEBP_AARCH64) +#define WEBP_NEON_WORK_AROUND_GCC 1 +#else +#define WEBP_NEON_WORK_AROUND_GCC 0 +#endif + +//------------------------------------------------------------------------------ + +// This macro prevents thread_sanitizer from reporting known concurrent writes. +#define WEBP_TSAN_IGNORE_FUNCTION +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#undef WEBP_TSAN_IGNORE_FUNCTION +#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread)) +#endif +#endif + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#define WEBP_MSAN +#endif +#endif + +#if defined(WEBP_USE_THREAD) && !defined(_WIN32) +#include // NOLINT + +#define WEBP_DSP_INIT(func) \ + do { \ + static volatile VP8CPUInfo func##_last_cpuinfo_used = \ + (VP8CPUInfo)&func##_last_cpuinfo_used; \ + static pthread_mutex_t func##_lock = PTHREAD_MUTEX_INITIALIZER; \ + if (pthread_mutex_lock(&func##_lock)) break; \ + if (func##_last_cpuinfo_used != VP8GetCPUInfo) func(); \ + func##_last_cpuinfo_used = VP8GetCPUInfo; \ + (void)pthread_mutex_unlock(&func##_lock); \ + } while (0) +#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32)) +#define WEBP_DSP_INIT(func) \ + do { \ + static volatile VP8CPUInfo func##_last_cpuinfo_used = \ + (VP8CPUInfo)&func##_last_cpuinfo_used; \ + if (func##_last_cpuinfo_used == VP8GetCPUInfo) break; \ + func(); \ + func##_last_cpuinfo_used = VP8GetCPUInfo; \ + } while (0) +#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32) + +// Defines an Init + helper function that control multiple initialization of +// function pointers / tables. +/* Usage: + WEBP_DSP_INIT_FUNC(InitFunc) { + ...function body + } +*/ +#define WEBP_DSP_INIT_FUNC(name) \ + static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void); \ + WEBP_TSAN_IGNORE_FUNCTION void name(void) { WEBP_DSP_INIT(name##_body); } \ + static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void) + +#define WEBP_UBSAN_IGNORE_UNDEF +#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(no_sanitize) +// This macro prevents the undefined behavior sanitizer from reporting +// failures. This is only meant to silence unaligned loads on platforms that +// are known to support them. +#undef WEBP_UBSAN_IGNORE_UNDEF +#define WEBP_UBSAN_IGNORE_UNDEF __attribute__((no_sanitize("undefined"))) + +// This macro prevents the undefined behavior sanitizer from reporting +// failures related to unsigned integer overflows. This is only meant to +// silence cases where this well defined behavior is expected. +#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW +#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \ + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif +#endif + +// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'. +// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning. +#if !defined(WEBP_OFFSET_PTR) +#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off))) +#endif + +// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility) +#if !defined(WEBP_SWAP_16BIT_CSP) +#define WEBP_SWAP_16BIT_CSP 0 +#endif + +// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__) +#if !defined(WORDS_BIGENDIAN) && \ + (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \ + (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) +#define WORDS_BIGENDIAN +#endif + +typedef enum { + kSSE2, + kSSE3, + kSlowSSSE3, // special feature for slow SSSE3 architectures + kSSE4_1, + kAVX, + kAVX2, + kNEON, + kMIPS32, + kMIPSdspR2, + kMSA +} CPUFeature; + +// returns true if the CPU supports the feature. +typedef int (*VP8CPUInfo)(CPUFeature feature); + +#endif // WEBP_DSP_CPU_H_ diff --git a/libraries/webp/src/dsp/dec.c b/libraries/webp/src/dsp/dec.c new file mode 100644 index 00000000000..451d649d58e --- /dev/null +++ b/libraries/webp/src/dsp/dec.c @@ -0,0 +1,887 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical decoding functions, default plain-C implementations. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/dsp/dsp.h" +#include "src/dec/vp8i_dec.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ + +static WEBP_INLINE uint8_t clip_8b(int v) { + return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; +} + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +#define STORE(x, y, v) \ + dst[(x) + (y) * BPS] = clip_8b(dst[(x) + (y) * BPS] + ((v) >> 3)) + +#define STORE2(y, dc, d, c) do { \ + const int DC = (dc); \ + STORE(0, y, DC + (d)); \ + STORE(1, y, DC + (c)); \ + STORE(2, y, DC - (c)); \ + STORE(3, y, DC - (d)); \ +} while (0) + +#if !WEBP_NEON_OMIT_C_CODE +static void TransformOne_C(const int16_t* in, uint8_t* dst) { + int C[4 * 4], *tmp; + int i; + tmp = C; + for (i = 0; i < 4; ++i) { // vertical pass + const int a = in[0] + in[8]; // [-4096, 4094] + const int b = in[0] - in[8]; // [-4095, 4095] + const int c = WEBP_TRANSFORM_AC3_MUL2(in[4]) - + WEBP_TRANSFORM_AC3_MUL1(in[12]); // [-3783, 3783] + const int d = WEBP_TRANSFORM_AC3_MUL1(in[4]) + + WEBP_TRANSFORM_AC3_MUL2(in[12]); // [-3785, 3781] + tmp[0] = a + d; // [-7881, 7875] + tmp[1] = b + c; // [-7878, 7878] + tmp[2] = b - c; // [-7878, 7878] + tmp[3] = a - d; // [-7877, 7879] + tmp += 4; + in++; + } + // Each pass is expanding the dynamic range by ~3.85 (upper bound). + // The exact value is (2. + (20091 + 35468) / 65536). + // After the second pass, maximum interval is [-3794, 3794], assuming + // an input in [-2048, 2047] interval. We then need to add a dst value + // in the [0, 255] range. + // In the worst case scenario, the input to clip_8b() can be as large as + // [-60713, 60968]. + tmp = C; + for (i = 0; i < 4; ++i) { // horizontal pass + const int dc = tmp[0] + 4; + const int a = dc + tmp[8]; + const int b = dc - tmp[8]; + const int c = + WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]); + const int d = + WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]); + STORE(0, 0, a + d); + STORE(1, 0, b + c); + STORE(2, 0, b - c); + STORE(3, 0, a - d); + tmp++; + dst += BPS; + } +} + +// Simplified transform when only in[0], in[1] and in[4] are non-zero +static void TransformAC3_C(const int16_t* in, uint8_t* dst) { + const int a = in[0] + 4; + const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]); + const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]); + const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]); + const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]); + STORE2(0, a + d4, d1, c1); + STORE2(1, a + c4, d1, c1); + STORE2(2, a - c4, d1, c1); + STORE2(3, a - d4, d1, c1); +} +#undef STORE2 + +static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) { + TransformOne_C(in, dst); + if (do_two) { + TransformOne_C(in + 16, dst + 4); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +static void TransformUV_C(const int16_t* in, uint8_t* dst) { + VP8Transform(in + 0 * 16, dst, 1); + VP8Transform(in + 2 * 16, dst + 4 * BPS, 1); +} + +#if !WEBP_NEON_OMIT_C_CODE +static void TransformDC_C(const int16_t* in, uint8_t* dst) { + const int DC = in[0] + 4; + int i, j; + for (j = 0; j < 4; ++j) { + for (i = 0; i < 4; ++i) { + STORE(i, j, DC); + } + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +static void TransformDCUV_C(const int16_t* in, uint8_t* dst) { + if (in[0 * 16]) VP8TransformDC(in + 0 * 16, dst); + if (in[1 * 16]) VP8TransformDC(in + 1 * 16, dst + 4); + if (in[2 * 16]) VP8TransformDC(in + 2 * 16, dst + 4 * BPS); + if (in[3 * 16]) VP8TransformDC(in + 3 * 16, dst + 4 * BPS + 4); +} + +#undef STORE + +//------------------------------------------------------------------------------ +// Paragraph 14.3 + +#if !WEBP_NEON_OMIT_C_CODE +static void TransformWHT_C(const int16_t* in, int16_t* out) { + int tmp[16]; + int i; + for (i = 0; i < 4; ++i) { + const int a0 = in[0 + i] + in[12 + i]; + const int a1 = in[4 + i] + in[ 8 + i]; + const int a2 = in[4 + i] - in[ 8 + i]; + const int a3 = in[0 + i] - in[12 + i]; + tmp[0 + i] = a0 + a1; + tmp[8 + i] = a0 - a1; + tmp[4 + i] = a3 + a2; + tmp[12 + i] = a3 - a2; + } + for (i = 0; i < 4; ++i) { + const int dc = tmp[0 + i * 4] + 3; // w/ rounder + const int a0 = dc + tmp[3 + i * 4]; + const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4]; + const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4]; + const int a3 = dc - tmp[3 + i * 4]; + out[ 0] = (a0 + a1) >> 3; + out[16] = (a3 + a2) >> 3; + out[32] = (a0 - a1) >> 3; + out[48] = (a3 - a2) >> 3; + out += 64; + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +void (*VP8TransformWHT)(const int16_t* in, int16_t* out); + +//------------------------------------------------------------------------------ +// Intra predictions + +#define DST(x, y) dst[(x) + (y) * BPS] + +#if !WEBP_NEON_OMIT_C_CODE +static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) { + const uint8_t* top = dst - BPS; + const uint8_t* const clip0 = VP8kclip1 - top[-1]; + int y; + for (y = 0; y < size; ++y) { + const uint8_t* const clip = clip0 + dst[-1]; + int x; + for (x = 0; x < size; ++x) { + dst[x] = clip[top[x]]; + } + dst += BPS; + } +} +static void TM4_C(uint8_t* dst) { TrueMotion(dst, 4); } +static void TM8uv_C(uint8_t* dst) { TrueMotion(dst, 8); } +static void TM16_C(uint8_t* dst) { TrueMotion(dst, 16); } + +//------------------------------------------------------------------------------ +// 16x16 + +static void VE16_C(uint8_t* dst) { // vertical + int j; + for (j = 0; j < 16; ++j) { + memcpy(dst + j * BPS, dst - BPS, 16); + } +} + +static void HE16_C(uint8_t* dst) { // horizontal + int j; + for (j = 16; j > 0; --j) { + memset(dst, dst[-1], 16); + dst += BPS; + } +} + +static WEBP_INLINE void Put16(int v, uint8_t* dst) { + int j; + for (j = 0; j < 16; ++j) { + memset(dst + j * BPS, v, 16); + } +} + +static void DC16_C(uint8_t* dst) { // DC + int DC = 16; + int j; + for (j = 0; j < 16; ++j) { + DC += dst[-1 + j * BPS] + dst[j - BPS]; + } + Put16(DC >> 5, dst); +} + +static void DC16NoTop_C(uint8_t* dst) { // DC with top samples not available + int DC = 8; + int j; + for (j = 0; j < 16; ++j) { + DC += dst[-1 + j * BPS]; + } + Put16(DC >> 4, dst); +} + +static void DC16NoLeft_C(uint8_t* dst) { // DC with left samples not available + int DC = 8; + int i; + for (i = 0; i < 16; ++i) { + DC += dst[i - BPS]; + } + Put16(DC >> 4, dst); +} + +static void DC16NoTopLeft_C(uint8_t* dst) { // DC with no top and left samples + Put16(0x80, dst); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES]; + +//------------------------------------------------------------------------------ +// 4x4 + +#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2)) +#define AVG2(a, b) (((a) + (b) + 1) >> 1) + +#if !WEBP_NEON_OMIT_C_CODE +static void VE4_C(uint8_t* dst) { // vertical + const uint8_t* top = dst - BPS; + const uint8_t vals[4] = { + AVG3(top[-1], top[0], top[1]), + AVG3(top[ 0], top[1], top[2]), + AVG3(top[ 1], top[2], top[3]), + AVG3(top[ 2], top[3], top[4]) + }; + int i; + for (i = 0; i < 4; ++i) { + memcpy(dst + i * BPS, vals, sizeof(vals)); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +static void HE4_C(uint8_t* dst) { // horizontal + const int A = dst[-1 - BPS]; + const int B = dst[-1]; + const int C = dst[-1 + BPS]; + const int D = dst[-1 + 2 * BPS]; + const int E = dst[-1 + 3 * BPS]; + WebPUint32ToMem(dst + 0 * BPS, 0x01010101U * AVG3(A, B, C)); + WebPUint32ToMem(dst + 1 * BPS, 0x01010101U * AVG3(B, C, D)); + WebPUint32ToMem(dst + 2 * BPS, 0x01010101U * AVG3(C, D, E)); + WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(D, E, E)); +} + +#if !WEBP_NEON_OMIT_C_CODE +static void DC4_C(uint8_t* dst) { // DC + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS]; + dc >>= 3; + for (i = 0; i < 4; ++i) memset(dst + i * BPS, dc, 4); +} + +static void RD4_C(uint8_t* dst) { // Down-right + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int L = dst[-1 + 3 * BPS]; + const int X = dst[-1 - BPS]; + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + const int D = dst[3 - BPS]; + DST(0, 3) = AVG3(J, K, L); + DST(1, 3) = DST(0, 2) = AVG3(I, J, K); + DST(2, 3) = DST(1, 2) = DST(0, 1) = AVG3(X, I, J); + DST(3, 3) = DST(2, 2) = DST(1, 1) = DST(0, 0) = AVG3(A, X, I); + DST(3, 2) = DST(2, 1) = DST(1, 0) = AVG3(B, A, X); + DST(3, 1) = DST(2, 0) = AVG3(C, B, A); + DST(3, 0) = AVG3(D, C, B); +} + +static void LD4_C(uint8_t* dst) { // Down-Left + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + const int D = dst[3 - BPS]; + const int E = dst[4 - BPS]; + const int F = dst[5 - BPS]; + const int G = dst[6 - BPS]; + const int H = dst[7 - BPS]; + DST(0, 0) = AVG3(A, B, C); + DST(1, 0) = DST(0, 1) = AVG3(B, C, D); + DST(2, 0) = DST(1, 1) = DST(0, 2) = AVG3(C, D, E); + DST(3, 0) = DST(2, 1) = DST(1, 2) = DST(0, 3) = AVG3(D, E, F); + DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G); + DST(3, 2) = DST(2, 3) = AVG3(F, G, H); + DST(3, 3) = AVG3(G, H, H); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +static void VR4_C(uint8_t* dst) { // Vertical-Right + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int X = dst[-1 - BPS]; + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + const int D = dst[3 - BPS]; + DST(0, 0) = DST(1, 2) = AVG2(X, A); + DST(1, 0) = DST(2, 2) = AVG2(A, B); + DST(2, 0) = DST(3, 2) = AVG2(B, C); + DST(3, 0) = AVG2(C, D); + + DST(0, 3) = AVG3(K, J, I); + DST(0, 2) = AVG3(J, I, X); + DST(0, 1) = DST(1, 3) = AVG3(I, X, A); + DST(1, 1) = DST(2, 3) = AVG3(X, A, B); + DST(2, 1) = DST(3, 3) = AVG3(A, B, C); + DST(3, 1) = AVG3(B, C, D); +} + +static void VL4_C(uint8_t* dst) { // Vertical-Left + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + const int D = dst[3 - BPS]; + const int E = dst[4 - BPS]; + const int F = dst[5 - BPS]; + const int G = dst[6 - BPS]; + const int H = dst[7 - BPS]; + DST(0, 0) = AVG2(A, B); + DST(1, 0) = DST(0, 2) = AVG2(B, C); + DST(2, 0) = DST(1, 2) = AVG2(C, D); + DST(3, 0) = DST(2, 2) = AVG2(D, E); + + DST(0, 1) = AVG3(A, B, C); + DST(1, 1) = DST(0, 3) = AVG3(B, C, D); + DST(2, 1) = DST(1, 3) = AVG3(C, D, E); + DST(3, 1) = DST(2, 3) = AVG3(D, E, F); + DST(3, 2) = AVG3(E, F, G); + DST(3, 3) = AVG3(F, G, H); +} + +static void HU4_C(uint8_t* dst) { // Horizontal-Up + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int L = dst[-1 + 3 * BPS]; + DST(0, 0) = AVG2(I, J); + DST(2, 0) = DST(0, 1) = AVG2(J, K); + DST(2, 1) = DST(0, 2) = AVG2(K, L); + DST(1, 0) = AVG3(I, J, K); + DST(3, 0) = DST(1, 1) = AVG3(J, K, L); + DST(3, 1) = DST(1, 2) = AVG3(K, L, L); + DST(3, 2) = DST(2, 2) = + DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; +} + +static void HD4_C(uint8_t* dst) { // Horizontal-Down + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int L = dst[-1 + 3 * BPS]; + const int X = dst[-1 - BPS]; + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + + DST(0, 0) = DST(2, 1) = AVG2(I, X); + DST(0, 1) = DST(2, 2) = AVG2(J, I); + DST(0, 2) = DST(2, 3) = AVG2(K, J); + DST(0, 3) = AVG2(L, K); + + DST(3, 0) = AVG3(A, B, C); + DST(2, 0) = AVG3(X, A, B); + DST(1, 0) = DST(3, 1) = AVG3(I, X, A); + DST(1, 1) = DST(3, 2) = AVG3(J, I, X); + DST(1, 2) = DST(3, 3) = AVG3(K, J, I); + DST(1, 3) = AVG3(L, K, J); +} + +#undef DST +#undef AVG3 +#undef AVG2 + +VP8PredFunc VP8PredLuma4[NUM_BMODES]; + +//------------------------------------------------------------------------------ +// Chroma + +#if !WEBP_NEON_OMIT_C_CODE +static void VE8uv_C(uint8_t* dst) { // vertical + int j; + for (j = 0; j < 8; ++j) { + memcpy(dst + j * BPS, dst - BPS, 8); + } +} + +static void HE8uv_C(uint8_t* dst) { // horizontal + int j; + for (j = 0; j < 8; ++j) { + memset(dst, dst[-1], 8); + dst += BPS; + } +} + +// helper for chroma-DC predictions +static WEBP_INLINE void Put8x8uv(uint8_t value, uint8_t* dst) { + int j; + for (j = 0; j < 8; ++j) { + memset(dst + j * BPS, value, 8); + } +} + +static void DC8uv_C(uint8_t* dst) { // DC + int dc0 = 8; + int i; + for (i = 0; i < 8; ++i) { + dc0 += dst[i - BPS] + dst[-1 + i * BPS]; + } + Put8x8uv(dc0 >> 4, dst); +} + +static void DC8uvNoLeft_C(uint8_t* dst) { // DC with no left samples + int dc0 = 4; + int i; + for (i = 0; i < 8; ++i) { + dc0 += dst[i - BPS]; + } + Put8x8uv(dc0 >> 3, dst); +} + +static void DC8uvNoTop_C(uint8_t* dst) { // DC with no top samples + int dc0 = 4; + int i; + for (i = 0; i < 8; ++i) { + dc0 += dst[-1 + i * BPS]; + } + Put8x8uv(dc0 >> 3, dst); +} + +static void DC8uvNoTopLeft_C(uint8_t* dst) { // DC with nothing + Put8x8uv(0x80, dst); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES]; + +//------------------------------------------------------------------------------ +// Edge filtering functions + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC +// 4 pixels in, 2 pixels out +static WEBP_INLINE void DoFilter2_C(uint8_t* p, int step) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1]; // in [-893,892] + const int a1 = VP8ksclip2[(a + 4) >> 3]; // in [-16,15] + const int a2 = VP8ksclip2[(a + 3) >> 3]; + p[-step] = VP8kclip1[p0 + a2]; + p[ 0] = VP8kclip1[q0 - a1]; +} + +// 4 pixels in, 4 pixels out +static WEBP_INLINE void DoFilter4_C(uint8_t* p, int step) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + const int a = 3 * (q0 - p0); + const int a1 = VP8ksclip2[(a + 4) >> 3]; + const int a2 = VP8ksclip2[(a + 3) >> 3]; + const int a3 = (a1 + 1) >> 1; + p[-2*step] = VP8kclip1[p1 + a3]; + p[- step] = VP8kclip1[p0 + a2]; + p[ 0] = VP8kclip1[q0 - a1]; + p[ step] = VP8kclip1[q1 - a3]; +} + +// 6 pixels in, 6 pixels out +static WEBP_INLINE void DoFilter6_C(uint8_t* p, int step) { + const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step]; + const int q0 = p[0], q1 = p[step], q2 = p[2*step]; + const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]]; + // a is in [-128,127], a1 in [-27,27], a2 in [-18,18] and a3 in [-9,9] + const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7 + const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7 + const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7 + p[-3*step] = VP8kclip1[p2 + a3]; + p[-2*step] = VP8kclip1[p1 + a2]; + p[- step] = VP8kclip1[p0 + a1]; + p[ 0] = VP8kclip1[q0 - a1]; + p[ step] = VP8kclip1[q1 - a2]; + p[ 2*step] = VP8kclip1[q2 - a3]; +} + +static WEBP_INLINE int Hev(const uint8_t* p, int step, int thresh) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + return (VP8kabs0[p1 - p0] > thresh) || (VP8kabs0[q1 - q0] > thresh); +} +#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + +#if !WEBP_NEON_OMIT_C_CODE +static WEBP_INLINE int NeedsFilter_C(const uint8_t* p, int step, int t) { + const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step]; + return ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) <= t); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC +static WEBP_INLINE int NeedsFilter2_C(const uint8_t* p, + int step, int t, int it) { + const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step]; + const int p0 = p[-step], q0 = p[0]; + const int q1 = p[step], q2 = p[2 * step], q3 = p[3 * step]; + if ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) > t) return 0; + return VP8kabs0[p3 - p2] <= it && VP8kabs0[p2 - p1] <= it && + VP8kabs0[p1 - p0] <= it && VP8kabs0[q3 - q2] <= it && + VP8kabs0[q2 - q1] <= it && VP8kabs0[q1 - q0] <= it; +} +#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + +//------------------------------------------------------------------------------ +// Simple In-loop filtering (Paragraph 15.2) + +#if !WEBP_NEON_OMIT_C_CODE +static void SimpleVFilter16_C(uint8_t* p, int stride, int thresh) { + int i; + const int thresh2 = 2 * thresh + 1; + for (i = 0; i < 16; ++i) { + if (NeedsFilter_C(p + i, stride, thresh2)) { + DoFilter2_C(p + i, stride); + } + } +} + +static void SimpleHFilter16_C(uint8_t* p, int stride, int thresh) { + int i; + const int thresh2 = 2 * thresh + 1; + for (i = 0; i < 16; ++i) { + if (NeedsFilter_C(p + i * stride, 1, thresh2)) { + DoFilter2_C(p + i * stride, 1); + } + } +} + +static void SimpleVFilter16i_C(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + SimpleVFilter16_C(p, stride, thresh); + } +} + +static void SimpleHFilter16i_C(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + SimpleHFilter16_C(p, stride, thresh); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//------------------------------------------------------------------------------ +// Complex In-loop filtering (Paragraph 15.3) + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC +static WEBP_INLINE void FilterLoop26_C(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, + int hev_thresh) { + const int thresh2 = 2 * thresh + 1; + while (size-- > 0) { + if (NeedsFilter2_C(p, hstride, thresh2, ithresh)) { + if (Hev(p, hstride, hev_thresh)) { + DoFilter2_C(p, hstride); + } else { + DoFilter6_C(p, hstride); + } + } + p += vstride; + } +} + +static WEBP_INLINE void FilterLoop24_C(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, + int hev_thresh) { + const int thresh2 = 2 * thresh + 1; + while (size-- > 0) { + if (NeedsFilter2_C(p, hstride, thresh2, ithresh)) { + if (Hev(p, hstride, hev_thresh)) { + DoFilter2_C(p, hstride); + } else { + DoFilter4_C(p, hstride); + } + } + p += vstride; + } +} +#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + +#if !WEBP_NEON_OMIT_C_CODE +// on macroblock edges +static void VFilter16_C(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26_C(p, stride, 1, 16, thresh, ithresh, hev_thresh); +} + +static void HFilter16_C(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26_C(p, 1, stride, 16, thresh, ithresh, hev_thresh); +} + +// on three inner edges +static void VFilter16i_C(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + FilterLoop24_C(p, stride, 1, 16, thresh, ithresh, hev_thresh); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC +static void HFilter16i_C(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + FilterLoop24_C(p, 1, stride, 16, thresh, ithresh, hev_thresh); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + +#if !WEBP_NEON_OMIT_C_CODE +// 8-pixels wide variant, for chroma filtering +static void VFilter8_C(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26_C(u, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop26_C(v, stride, 1, 8, thresh, ithresh, hev_thresh); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC +static void HFilter8_C(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26_C(u, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop26_C(v, 1, stride, 8, thresh, ithresh, hev_thresh); +} +#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + +#if !WEBP_NEON_OMIT_C_CODE +static void VFilter8i_C(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24_C(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop24_C(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC +static void HFilter8i_C(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24_C(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop24_C(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); +} +#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + +//------------------------------------------------------------------------------ + +static void DitherCombine8x8_C(const uint8_t* dither, uint8_t* dst, + int dst_stride) { + int i, j; + for (j = 0; j < 8; ++j) { + for (i = 0; i < 8; ++i) { + const int delta0 = dither[i] - VP8_DITHER_AMP_CENTER; + const int delta1 = + (delta0 + VP8_DITHER_DESCALE_ROUNDER) >> VP8_DITHER_DESCALE; + dst[i] = clip_8b((int)dst[i] + delta1); + } + dst += dst_stride; + dither += 8; + } +} + +//------------------------------------------------------------------------------ + +VP8DecIdct2 VP8Transform; +VP8DecIdct VP8TransformAC3; +VP8DecIdct VP8TransformUV; +VP8DecIdct VP8TransformDC; +VP8DecIdct VP8TransformDCUV; + +VP8LumaFilterFunc VP8VFilter16; +VP8LumaFilterFunc VP8HFilter16; +VP8ChromaFilterFunc VP8VFilter8; +VP8ChromaFilterFunc VP8HFilter8; +VP8LumaFilterFunc VP8VFilter16i; +VP8LumaFilterFunc VP8HFilter16i; +VP8ChromaFilterFunc VP8VFilter8i; +VP8ChromaFilterFunc VP8HFilter8i; +VP8SimpleFilterFunc VP8SimpleVFilter16; +VP8SimpleFilterFunc VP8SimpleHFilter16; +VP8SimpleFilterFunc VP8SimpleVFilter16i; +VP8SimpleFilterFunc VP8SimpleHFilter16i; + +void (*VP8DitherCombine8x8)(const uint8_t* dither, uint8_t* dst, + int dst_stride); + +extern VP8CPUInfo VP8GetCPUInfo; +extern void VP8DspInitSSE2(void); +extern void VP8DspInitSSE41(void); +extern void VP8DspInitNEON(void); +extern void VP8DspInitMIPS32(void); +extern void VP8DspInitMIPSdspR2(void); +extern void VP8DspInitMSA(void); + +WEBP_DSP_INIT_FUNC(VP8DspInit) { + VP8InitClipTables(); + +#if !WEBP_NEON_OMIT_C_CODE + VP8TransformWHT = TransformWHT_C; + VP8Transform = TransformTwo_C; + VP8TransformDC = TransformDC_C; + VP8TransformAC3 = TransformAC3_C; +#endif + VP8TransformUV = TransformUV_C; + VP8TransformDCUV = TransformDCUV_C; + +#if !WEBP_NEON_OMIT_C_CODE + VP8VFilter16 = VFilter16_C; + VP8VFilter16i = VFilter16i_C; + VP8HFilter16 = HFilter16_C; + VP8VFilter8 = VFilter8_C; + VP8VFilter8i = VFilter8i_C; + VP8SimpleVFilter16 = SimpleVFilter16_C; + VP8SimpleHFilter16 = SimpleHFilter16_C; + VP8SimpleVFilter16i = SimpleVFilter16i_C; + VP8SimpleHFilter16i = SimpleHFilter16i_C; +#endif + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + VP8HFilter16i = HFilter16i_C; + VP8HFilter8 = HFilter8_C; + VP8HFilter8i = HFilter8i_C; +#endif + +#if !WEBP_NEON_OMIT_C_CODE + VP8PredLuma4[0] = DC4_C; + VP8PredLuma4[1] = TM4_C; + VP8PredLuma4[2] = VE4_C; + VP8PredLuma4[4] = RD4_C; + VP8PredLuma4[6] = LD4_C; +#endif + + VP8PredLuma4[3] = HE4_C; + VP8PredLuma4[5] = VR4_C; + VP8PredLuma4[7] = VL4_C; + VP8PredLuma4[8] = HD4_C; + VP8PredLuma4[9] = HU4_C; + +#if !WEBP_NEON_OMIT_C_CODE + VP8PredLuma16[0] = DC16_C; + VP8PredLuma16[1] = TM16_C; + VP8PredLuma16[2] = VE16_C; + VP8PredLuma16[3] = HE16_C; + VP8PredLuma16[4] = DC16NoTop_C; + VP8PredLuma16[5] = DC16NoLeft_C; + VP8PredLuma16[6] = DC16NoTopLeft_C; + + VP8PredChroma8[0] = DC8uv_C; + VP8PredChroma8[1] = TM8uv_C; + VP8PredChroma8[2] = VE8uv_C; + VP8PredChroma8[3] = HE8uv_C; + VP8PredChroma8[4] = DC8uvNoTop_C; + VP8PredChroma8[5] = DC8uvNoLeft_C; + VP8PredChroma8[6] = DC8uvNoTopLeft_C; +#endif + + VP8DitherCombine8x8 = DitherCombine8x8_C; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8DspInitSSE2(); +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + VP8DspInitSSE41(); + } +#endif + } +#endif +#if defined(WEBP_USE_MIPS32) + if (VP8GetCPUInfo(kMIPS32)) { + VP8DspInitMIPS32(); + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + VP8DspInitMIPSdspR2(); + } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8DspInitMSA(); + } +#endif + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + VP8DspInitNEON(); + } +#endif + + assert(VP8TransformWHT != NULL); + assert(VP8Transform != NULL); + assert(VP8TransformDC != NULL); + assert(VP8TransformAC3 != NULL); + assert(VP8TransformUV != NULL); + assert(VP8TransformDCUV != NULL); + assert(VP8VFilter16 != NULL); + assert(VP8HFilter16 != NULL); + assert(VP8VFilter8 != NULL); + assert(VP8HFilter8 != NULL); + assert(VP8VFilter16i != NULL); + assert(VP8HFilter16i != NULL); + assert(VP8VFilter8i != NULL); + assert(VP8HFilter8i != NULL); + assert(VP8SimpleVFilter16 != NULL); + assert(VP8SimpleHFilter16 != NULL); + assert(VP8SimpleVFilter16i != NULL); + assert(VP8SimpleHFilter16i != NULL); + assert(VP8PredLuma4[0] != NULL); + assert(VP8PredLuma4[1] != NULL); + assert(VP8PredLuma4[2] != NULL); + assert(VP8PredLuma4[3] != NULL); + assert(VP8PredLuma4[4] != NULL); + assert(VP8PredLuma4[5] != NULL); + assert(VP8PredLuma4[6] != NULL); + assert(VP8PredLuma4[7] != NULL); + assert(VP8PredLuma4[8] != NULL); + assert(VP8PredLuma4[9] != NULL); + assert(VP8PredLuma16[0] != NULL); + assert(VP8PredLuma16[1] != NULL); + assert(VP8PredLuma16[2] != NULL); + assert(VP8PredLuma16[3] != NULL); + assert(VP8PredLuma16[4] != NULL); + assert(VP8PredLuma16[5] != NULL); + assert(VP8PredLuma16[6] != NULL); + assert(VP8PredChroma8[0] != NULL); + assert(VP8PredChroma8[1] != NULL); + assert(VP8PredChroma8[2] != NULL); + assert(VP8PredChroma8[3] != NULL); + assert(VP8PredChroma8[4] != NULL); + assert(VP8PredChroma8[5] != NULL); + assert(VP8PredChroma8[6] != NULL); + assert(VP8DitherCombine8x8 != NULL); +} diff --git a/libraries/webp/src/dsp/dec_clip_tables.c b/libraries/webp/src/dsp/dec_clip_tables.c new file mode 100644 index 00000000000..427b74f776c --- /dev/null +++ b/libraries/webp/src/dsp/dec_clip_tables.c @@ -0,0 +1,369 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Clipping tables for filtering +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +// define to 0 to have run-time table initialization +#if !defined(USE_STATIC_TABLES) +#define USE_STATIC_TABLES 1 // ALTERNATE_CODE +#endif + +#if (USE_STATIC_TABLES == 1) + +static const uint8_t abs0[255 + 255 + 1] = { + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, + 0xf3, 0xf2, 0xf1, 0xf0, 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8, + 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 0xdf, 0xde, 0xdd, 0xdc, + 0xdb, 0xda, 0xd9, 0xd8, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0, + 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8, 0xc7, 0xc6, 0xc5, 0xc4, + 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, + 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 0xaf, 0xae, 0xad, 0xac, + 0xab, 0xaa, 0xa9, 0xa8, 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0, + 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, + 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, + 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, + 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, + 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, + 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, + 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4c, + 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, + 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, + 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, + 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, + 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, + 0x03, 0x02, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, + 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, + 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, + 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, + 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, + 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, + 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const uint8_t sclip1[1020 + 1020 + 1] = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, + 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, + 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f +}; + +static const uint8_t sclip2[112 + 112 + 1] = { + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f +}; + +static const uint8_t clip1[255 + 511 + 1] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, + 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, + 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, + 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, + 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, + 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, + 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +#else + +// uninitialized tables +static uint8_t abs0[255 + 255 + 1]; +static int8_t sclip1[1020 + 1020 + 1]; +static int8_t sclip2[112 + 112 + 1]; +static uint8_t clip1[255 + 511 + 1]; + +// We declare this variable 'volatile' to prevent instruction reordering +// and make sure it's set to true _last_ (so as to be thread-safe) +static volatile int tables_ok = 0; + +#endif // USE_STATIC_TABLES + +const int8_t* const VP8ksclip1 = (const int8_t*)&sclip1[1020]; +const int8_t* const VP8ksclip2 = (const int8_t*)&sclip2[112]; +const uint8_t* const VP8kclip1 = &clip1[255]; +const uint8_t* const VP8kabs0 = &abs0[255]; + +WEBP_TSAN_IGNORE_FUNCTION void VP8InitClipTables(void) { +#if (USE_STATIC_TABLES == 0) + int i; + if (!tables_ok) { + for (i = -255; i <= 255; ++i) { + abs0[255 + i] = (i < 0) ? -i : i; + } + for (i = -1020; i <= 1020; ++i) { + sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i; + } + for (i = -112; i <= 112; ++i) { + sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i; + } + for (i = -255; i <= 255 + 255; ++i) { + clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i; + } + tables_ok = 1; + } +#endif // USE_STATIC_TABLES +} diff --git a/libraries/webp/src/dsp/dec_mips32.c b/libraries/webp/src/dsp/dec_mips32.c new file mode 100644 index 00000000000..f0e7de4ac4f --- /dev/null +++ b/libraries/webp/src/dsp/dec_mips32.c @@ -0,0 +1,571 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS version of dsp functions +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) +// Jovan Zelincevic (jovan.zelincevic@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS32) + +#include "src/dsp/mips_macro.h" + +static const int kC1 = WEBP_TRANSFORM_AC3_C1; +static const int kC2 = WEBP_TRANSFORM_AC3_C2; + +static WEBP_INLINE int abs_mips32(int x) { + const int sign = x >> 31; + return (x ^ sign) - sign; +} + +// 4 pixels in, 2 pixels out +static WEBP_INLINE void do_filter2(uint8_t* p, int step) { + const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step]; + const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1]; + const int a1 = VP8ksclip2[(a + 4) >> 3]; + const int a2 = VP8ksclip2[(a + 3) >> 3]; + p[-step] = VP8kclip1[p0 + a2]; + p[ 0] = VP8kclip1[q0 - a1]; +} + +// 4 pixels in, 4 pixels out +static WEBP_INLINE void do_filter4(uint8_t* p, int step) { + const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step]; + const int a = 3 * (q0 - p0); + const int a1 = VP8ksclip2[(a + 4) >> 3]; + const int a2 = VP8ksclip2[(a + 3) >> 3]; + const int a3 = (a1 + 1) >> 1; + p[-2 * step] = VP8kclip1[p1 + a3]; + p[- step] = VP8kclip1[p0 + a2]; + p[ 0] = VP8kclip1[q0 - a1]; + p[ step] = VP8kclip1[q1 - a3]; +} + +// 6 pixels in, 6 pixels out +static WEBP_INLINE void do_filter6(uint8_t* p, int step) { + const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step]; + const int q0 = p[0], q1 = p[step], q2 = p[2 * step]; + const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]]; + // a is in [-128,127], a1 in [-27,27], a2 in [-18,18] and a3 in [-9,9] + const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7 + const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7 + const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7 + p[-3 * step] = VP8kclip1[p2 + a3]; + p[-2 * step] = VP8kclip1[p1 + a2]; + p[- step] = VP8kclip1[p0 + a1]; + p[ 0] = VP8kclip1[q0 - a1]; + p[ step] = VP8kclip1[q1 - a2]; + p[ 2 * step] = VP8kclip1[q2 - a3]; +} + +static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) { + const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step]; + return (abs_mips32(p1 - p0) > thresh) || (abs_mips32(q1 - q0) > thresh); +} + +static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int t) { + const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step]; + return ((4 * abs_mips32(p0 - q0) + abs_mips32(p1 - q1)) <= t); +} + +static WEBP_INLINE int needs_filter2(const uint8_t* p, + int step, int t, int it) { + const int p3 = p[-4 * step], p2 = p[-3 * step]; + const int p1 = p[-2 * step], p0 = p[-step]; + const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step]; + if ((4 * abs_mips32(p0 - q0) + abs_mips32(p1 - q1)) > t) { + return 0; + } + return abs_mips32(p3 - p2) <= it && abs_mips32(p2 - p1) <= it && + abs_mips32(p1 - p0) <= it && abs_mips32(q3 - q2) <= it && + abs_mips32(q2 - q1) <= it && abs_mips32(q1 - q0) <= it; +} + +static WEBP_INLINE void FilterLoop26(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, int hev_thresh) { + const int thresh2 = 2 * thresh + 1; + while (size-- > 0) { + if (needs_filter2(p, hstride, thresh2, ithresh)) { + if (hev(p, hstride, hev_thresh)) { + do_filter2(p, hstride); + } else { + do_filter6(p, hstride); + } + } + p += vstride; + } +} + +static WEBP_INLINE void FilterLoop24(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, int hev_thresh) { + const int thresh2 = 2 * thresh + 1; + while (size-- > 0) { + if (needs_filter2(p, hstride, thresh2, ithresh)) { + if (hev(p, hstride, hev_thresh)) { + do_filter2(p, hstride); + } else { + do_filter4(p, hstride); + } + } + p += vstride; + } +} + +// on macroblock edges +static void VFilter16(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh); +} + +static void HFilter16(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh); +} + +// 8-pixels wide variant, for chroma filtering +static void VFilter8(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh); +} + +static void HFilter8(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh); +} + +static void VFilter8i(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); +} + +static void HFilter8i(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); +} + +// on three inner edges +static void VFilter16i(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh); + } +} + +static void HFilter16i(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh); + } +} + +//------------------------------------------------------------------------------ +// Simple In-loop filtering (Paragraph 15.2) + +static void SimpleVFilter16(uint8_t* p, int stride, int thresh) { + int i; + const int thresh2 = 2 * thresh + 1; + for (i = 0; i < 16; ++i) { + if (needs_filter(p + i, stride, thresh2)) { + do_filter2(p + i, stride); + } + } +} + +static void SimpleHFilter16(uint8_t* p, int stride, int thresh) { + int i; + const int thresh2 = 2 * thresh + 1; + for (i = 0; i < 16; ++i) { + if (needs_filter(p + i * stride, 1, thresh2)) { + do_filter2(p + i * stride, 1); + } + } +} + +static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + SimpleVFilter16(p, stride, thresh); + } +} + +static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + SimpleHFilter16(p, stride, thresh); + } +} + +static void TransformOne(const int16_t* in, uint8_t* dst) { + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8, temp9; + int temp10, temp11, temp12, temp13, temp14; + int temp15, temp16, temp17, temp18, temp19; + int16_t* p_in = (int16_t*)in; + + // loops unrolled and merged to avoid usage of tmp buffer + // and to reduce number of stalls. MUL macro is written + // in assembler and inlined + __asm__ volatile( + "lh %[temp0], 0(%[in]) \n\t" + "lh %[temp8], 16(%[in]) \n\t" + "lh %[temp4], 8(%[in]) \n\t" + "lh %[temp12], 24(%[in]) \n\t" + "addu %[temp16], %[temp0], %[temp8] \n\t" + "subu %[temp0], %[temp0], %[temp8] \n\t" + "mul %[temp8], %[temp4], %[kC2] \n\t" + MUL_SHIFT_C1(temp17, temp12) + MUL_SHIFT_C1_IO(temp4, temp19) + "mul %[temp12], %[temp12], %[kC2] \n\t" + "lh %[temp1], 2(%[in]) \n\t" + "lh %[temp5], 10(%[in]) \n\t" + "lh %[temp9], 18(%[in]) \n\t" + "lh %[temp13], 26(%[in]) \n\t" + "sra %[temp8], %[temp8], 16 \n\t" + "sra %[temp12], %[temp12], 16 \n\t" + "lh %[temp2], 4(%[in]) \n\t" + "lh %[temp6], 12(%[in]) \n\t" + "lh %[temp10], 20(%[in]) \n\t" + "lh %[temp14], 28(%[in]) \n\t" + "subu %[temp17], %[temp8], %[temp17] \n\t" + "addu %[temp4], %[temp4], %[temp12] \n\t" + "addu %[temp8], %[temp16], %[temp4] \n\t" + "subu %[temp4], %[temp16], %[temp4] \n\t" + "addu %[temp16], %[temp1], %[temp9] \n\t" + "subu %[temp1], %[temp1], %[temp9] \n\t" + "lh %[temp3], 6(%[in]) \n\t" + "lh %[temp7], 14(%[in]) \n\t" + "lh %[temp11], 22(%[in]) \n\t" + "lh %[temp15], 30(%[in]) \n\t" + "addu %[temp12], %[temp0], %[temp17] \n\t" + "subu %[temp0], %[temp0], %[temp17] \n\t" + "mul %[temp9], %[temp5], %[kC2] \n\t" + MUL_SHIFT_C1(temp17, temp13) + MUL_SHIFT_C1_IO(temp5, temp19) + "mul %[temp13], %[temp13], %[kC2] \n\t" + "sra %[temp9], %[temp9], 16 \n\t" + "subu %[temp17], %[temp9], %[temp17] \n\t" + "sra %[temp13], %[temp13], 16 \n\t" + "addu %[temp5], %[temp5], %[temp13] \n\t" + "addu %[temp13], %[temp1], %[temp17] \n\t" + "subu %[temp1], %[temp1], %[temp17] \n\t" + MUL_SHIFT_C1(temp17, temp14) + "mul %[temp14], %[temp14], %[kC2] \n\t" + "addu %[temp9], %[temp16], %[temp5] \n\t" + "subu %[temp5], %[temp16], %[temp5] \n\t" + "addu %[temp16], %[temp2], %[temp10] \n\t" + "subu %[temp2], %[temp2], %[temp10] \n\t" + "mul %[temp10], %[temp6], %[kC2] \n\t" + MUL_SHIFT_C1_IO(temp6, temp19) + "sra %[temp14], %[temp14], 16 \n\t" + "sra %[temp10], %[temp10], 16 \n\t" + "subu %[temp17], %[temp10], %[temp17] \n\t" + "addu %[temp6], %[temp6], %[temp14] \n\t" + "addu %[temp10], %[temp16], %[temp6] \n\t" + "subu %[temp6], %[temp16], %[temp6] \n\t" + "addu %[temp14], %[temp2], %[temp17] \n\t" + "subu %[temp2], %[temp2], %[temp17] \n\t" + MUL_SHIFT_C1(temp17, temp15) + "mul %[temp15], %[temp15], %[kC2] \n\t" + "addu %[temp16], %[temp3], %[temp11] \n\t" + "subu %[temp3], %[temp3], %[temp11] \n\t" + "mul %[temp11], %[temp7], %[kC2] \n\t" + MUL_SHIFT_C1_IO(temp7, temp19) + "addiu %[temp8], %[temp8], 4 \n\t" + "addiu %[temp12], %[temp12], 4 \n\t" + "addiu %[temp0], %[temp0], 4 \n\t" + "addiu %[temp4], %[temp4], 4 \n\t" + "sra %[temp15], %[temp15], 16 \n\t" + "sra %[temp11], %[temp11], 16 \n\t" + "subu %[temp17], %[temp11], %[temp17] \n\t" + "addu %[temp7], %[temp7], %[temp15] \n\t" + "addu %[temp15], %[temp3], %[temp17] \n\t" + "subu %[temp3], %[temp3], %[temp17] \n\t" + "addu %[temp11], %[temp16], %[temp7] \n\t" + "subu %[temp7], %[temp16], %[temp7] \n\t" + "addu %[temp16], %[temp8], %[temp10] \n\t" + "subu %[temp8], %[temp8], %[temp10] \n\t" + "mul %[temp10], %[temp9], %[kC2] \n\t" + MUL_SHIFT_C1(temp17, temp11) + MUL_SHIFT_C1_IO(temp9, temp19) + "mul %[temp11], %[temp11], %[kC2] \n\t" + "sra %[temp10], %[temp10], 16 \n\t" + "sra %[temp11], %[temp11], 16 \n\t" + "subu %[temp17], %[temp10], %[temp17] \n\t" + "addu %[temp11], %[temp9], %[temp11] \n\t" + "addu %[temp10], %[temp12], %[temp14] \n\t" + "subu %[temp12], %[temp12], %[temp14] \n\t" + "mul %[temp14], %[temp13], %[kC2] \n\t" + MUL_SHIFT_C1(temp9, temp15) + MUL_SHIFT_C1_IO(temp13, temp19) + "mul %[temp15], %[temp15], %[kC2] \n\t" + "sra %[temp14], %[temp14], 16 \n\t" + "sra %[temp15], %[temp15], 16 \n\t" + "subu %[temp9], %[temp14], %[temp9] \n\t" + "addu %[temp15], %[temp13], %[temp15] \n\t" + "addu %[temp14], %[temp0], %[temp2] \n\t" + "subu %[temp0], %[temp0], %[temp2] \n\t" + "mul %[temp2], %[temp1], %[kC2] \n\t" + MUL_SHIFT_C1(temp13, temp3) + MUL_SHIFT_C1_IO(temp1, temp19) + "mul %[temp3], %[temp3], %[kC2] \n\t" + "sra %[temp2], %[temp2], 16 \n\t" + "sra %[temp3], %[temp3], 16 \n\t" + "subu %[temp13], %[temp2], %[temp13] \n\t" + "addu %[temp3], %[temp1], %[temp3] \n\t" + "addu %[temp2], %[temp4], %[temp6] \n\t" + "subu %[temp4], %[temp4], %[temp6] \n\t" + "mul %[temp6], %[temp5], %[kC2] \n\t" + MUL_SHIFT_C1(temp1, temp7) + MUL_SHIFT_C1_IO(temp5, temp19) + "mul %[temp7], %[temp7], %[kC2] \n\t" + "sra %[temp6], %[temp6], 16 \n\t" + "sra %[temp7], %[temp7], 16 \n\t" + "subu %[temp1], %[temp6], %[temp1] \n\t" + "addu %[temp7], %[temp5], %[temp7] \n\t" + "addu %[temp5], %[temp16], %[temp11] \n\t" + "subu %[temp16], %[temp16], %[temp11] \n\t" + "addu %[temp11], %[temp8], %[temp17] \n\t" + "subu %[temp8], %[temp8], %[temp17] \n\t" + "sra %[temp5], %[temp5], 3 \n\t" + "sra %[temp16], %[temp16], 3 \n\t" + "sra %[temp11], %[temp11], 3 \n\t" + "sra %[temp8], %[temp8], 3 \n\t" + "addu %[temp17], %[temp10], %[temp15] \n\t" + "subu %[temp10], %[temp10], %[temp15] \n\t" + "addu %[temp15], %[temp12], %[temp9] \n\t" + "subu %[temp12], %[temp12], %[temp9] \n\t" + "sra %[temp17], %[temp17], 3 \n\t" + "sra %[temp10], %[temp10], 3 \n\t" + "sra %[temp15], %[temp15], 3 \n\t" + "sra %[temp12], %[temp12], 3 \n\t" + "addu %[temp9], %[temp14], %[temp3] \n\t" + "subu %[temp14], %[temp14], %[temp3] \n\t" + "addu %[temp3], %[temp0], %[temp13] \n\t" + "subu %[temp0], %[temp0], %[temp13] \n\t" + "sra %[temp9], %[temp9], 3 \n\t" + "sra %[temp14], %[temp14], 3 \n\t" + "sra %[temp3], %[temp3], 3 \n\t" + "sra %[temp0], %[temp0], 3 \n\t" + "addu %[temp13], %[temp2], %[temp7] \n\t" + "subu %[temp2], %[temp2], %[temp7] \n\t" + "addu %[temp7], %[temp4], %[temp1] \n\t" + "subu %[temp4], %[temp4], %[temp1] \n\t" + "sra %[temp13], %[temp13], 3 \n\t" + "sra %[temp2], %[temp2], 3 \n\t" + "sra %[temp7], %[temp7], 3 \n\t" + "sra %[temp4], %[temp4], 3 \n\t" + "addiu %[temp6], $zero, 255 \n\t" + "lbu %[temp1], 0+0*" XSTR(BPS) "(%[dst]) \n\t" + "addu %[temp1], %[temp1], %[temp5] \n\t" + "sra %[temp5], %[temp1], 8 \n\t" + "sra %[temp18], %[temp1], 31 \n\t" + "beqz %[temp5], 1f \n\t" + "xor %[temp1], %[temp1], %[temp1] \n\t" + "movz %[temp1], %[temp6], %[temp18] \n\t" + "1: \n\t" + "lbu %[temp18], 1+0*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp1], 0+0*" XSTR(BPS) "(%[dst]) \n\t" + "addu %[temp18], %[temp18], %[temp11] \n\t" + "sra %[temp11], %[temp18], 8 \n\t" + "sra %[temp1], %[temp18], 31 \n\t" + "beqz %[temp11], 2f \n\t" + "xor %[temp18], %[temp18], %[temp18] \n\t" + "movz %[temp18], %[temp6], %[temp1] \n\t" + "2: \n\t" + "lbu %[temp1], 2+0*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp18], 1+0*" XSTR(BPS) "(%[dst]) \n\t" + "addu %[temp1], %[temp1], %[temp8] \n\t" + "sra %[temp8], %[temp1], 8 \n\t" + "sra %[temp18], %[temp1], 31 \n\t" + "beqz %[temp8], 3f \n\t" + "xor %[temp1], %[temp1], %[temp1] \n\t" + "movz %[temp1], %[temp6], %[temp18] \n\t" + "3: \n\t" + "lbu %[temp18], 3+0*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp1], 2+0*" XSTR(BPS) "(%[dst]) \n\t" + "addu %[temp18], %[temp18], %[temp16] \n\t" + "sra %[temp16], %[temp18], 8 \n\t" + "sra %[temp1], %[temp18], 31 \n\t" + "beqz %[temp16], 4f \n\t" + "xor %[temp18], %[temp18], %[temp18] \n\t" + "movz %[temp18], %[temp6], %[temp1] \n\t" + "4: \n\t" + "sb %[temp18], 3+0*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp5], 0+1*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp8], 1+1*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp11], 2+1*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp16], 3+1*" XSTR(BPS) "(%[dst]) \n\t" + "addu %[temp5], %[temp5], %[temp17] \n\t" + "addu %[temp8], %[temp8], %[temp15] \n\t" + "addu %[temp11], %[temp11], %[temp12] \n\t" + "addu %[temp16], %[temp16], %[temp10] \n\t" + "sra %[temp18], %[temp5], 8 \n\t" + "sra %[temp1], %[temp5], 31 \n\t" + "beqz %[temp18], 5f \n\t" + "xor %[temp5], %[temp5], %[temp5] \n\t" + "movz %[temp5], %[temp6], %[temp1] \n\t" + "5: \n\t" + "sra %[temp18], %[temp8], 8 \n\t" + "sra %[temp1], %[temp8], 31 \n\t" + "beqz %[temp18], 6f \n\t" + "xor %[temp8], %[temp8], %[temp8] \n\t" + "movz %[temp8], %[temp6], %[temp1] \n\t" + "6: \n\t" + "sra %[temp18], %[temp11], 8 \n\t" + "sra %[temp1], %[temp11], 31 \n\t" + "sra %[temp17], %[temp16], 8 \n\t" + "sra %[temp15], %[temp16], 31 \n\t" + "beqz %[temp18], 7f \n\t" + "xor %[temp11], %[temp11], %[temp11] \n\t" + "movz %[temp11], %[temp6], %[temp1] \n\t" + "7: \n\t" + "beqz %[temp17], 8f \n\t" + "xor %[temp16], %[temp16], %[temp16] \n\t" + "movz %[temp16], %[temp6], %[temp15] \n\t" + "8: \n\t" + "sb %[temp5], 0+1*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp8], 1+1*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp11], 2+1*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp16], 3+1*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp5], 0+2*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp8], 1+2*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp11], 2+2*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp16], 3+2*" XSTR(BPS) "(%[dst]) \n\t" + "addu %[temp5], %[temp5], %[temp9] \n\t" + "addu %[temp8], %[temp8], %[temp3] \n\t" + "addu %[temp11], %[temp11], %[temp0] \n\t" + "addu %[temp16], %[temp16], %[temp14] \n\t" + "sra %[temp18], %[temp5], 8 \n\t" + "sra %[temp1], %[temp5], 31 \n\t" + "sra %[temp17], %[temp8], 8 \n\t" + "sra %[temp15], %[temp8], 31 \n\t" + "sra %[temp12], %[temp11], 8 \n\t" + "sra %[temp10], %[temp11], 31 \n\t" + "sra %[temp9], %[temp16], 8 \n\t" + "sra %[temp3], %[temp16], 31 \n\t" + "beqz %[temp18], 9f \n\t" + "xor %[temp5], %[temp5], %[temp5] \n\t" + "movz %[temp5], %[temp6], %[temp1] \n\t" + "9: \n\t" + "beqz %[temp17], 10f \n\t" + "xor %[temp8], %[temp8], %[temp8] \n\t" + "movz %[temp8], %[temp6], %[temp15] \n\t" + "10: \n\t" + "beqz %[temp12], 11f \n\t" + "xor %[temp11], %[temp11], %[temp11] \n\t" + "movz %[temp11], %[temp6], %[temp10] \n\t" + "11: \n\t" + "beqz %[temp9], 12f \n\t" + "xor %[temp16], %[temp16], %[temp16] \n\t" + "movz %[temp16], %[temp6], %[temp3] \n\t" + "12: \n\t" + "sb %[temp5], 0+2*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp8], 1+2*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp11], 2+2*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp16], 3+2*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp5], 0+3*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp8], 1+3*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp11], 2+3*" XSTR(BPS) "(%[dst]) \n\t" + "lbu %[temp16], 3+3*" XSTR(BPS) "(%[dst]) \n\t" + "addu %[temp5], %[temp5], %[temp13] \n\t" + "addu %[temp8], %[temp8], %[temp7] \n\t" + "addu %[temp11], %[temp11], %[temp4] \n\t" + "addu %[temp16], %[temp16], %[temp2] \n\t" + "sra %[temp18], %[temp5], 8 \n\t" + "sra %[temp1], %[temp5], 31 \n\t" + "sra %[temp17], %[temp8], 8 \n\t" + "sra %[temp15], %[temp8], 31 \n\t" + "sra %[temp12], %[temp11], 8 \n\t" + "sra %[temp10], %[temp11], 31 \n\t" + "sra %[temp9], %[temp16], 8 \n\t" + "sra %[temp3], %[temp16], 31 \n\t" + "beqz %[temp18], 13f \n\t" + "xor %[temp5], %[temp5], %[temp5] \n\t" + "movz %[temp5], %[temp6], %[temp1] \n\t" + "13: \n\t" + "beqz %[temp17], 14f \n\t" + "xor %[temp8], %[temp8], %[temp8] \n\t" + "movz %[temp8], %[temp6], %[temp15] \n\t" + "14: \n\t" + "beqz %[temp12], 15f \n\t" + "xor %[temp11], %[temp11], %[temp11] \n\t" + "movz %[temp11], %[temp6], %[temp10] \n\t" + "15: \n\t" + "beqz %[temp9], 16f \n\t" + "xor %[temp16], %[temp16], %[temp16] \n\t" + "movz %[temp16], %[temp6], %[temp3] \n\t" + "16: \n\t" + "sb %[temp5], 0+3*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp8], 1+3*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp11], 2+3*" XSTR(BPS) "(%[dst]) \n\t" + "sb %[temp16], 3+3*" XSTR(BPS) "(%[dst]) \n\t" + + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11), + [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14), + [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17), + [temp18]"=&r"(temp18), [temp19]"=&r"(temp19) + : [in]"r"(p_in), [kC1]"r"(kC1), [kC2]"r"(kC2), [dst]"r"(dst) + : "memory", "hi", "lo" + ); +} + +static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) { + TransformOne(in, dst); + if (do_two) { + TransformOne(in + 16, dst + 4); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitMIPS32(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitMIPS32(void) { + VP8InitClipTables(); + + VP8Transform = TransformTwo; + + VP8VFilter16 = VFilter16; + VP8HFilter16 = HFilter16; + VP8VFilter8 = VFilter8; + VP8HFilter8 = HFilter8; + VP8VFilter16i = VFilter16i; + VP8HFilter16i = HFilter16i; + VP8VFilter8i = VFilter8i; + VP8HFilter8i = HFilter8i; + + VP8SimpleVFilter16 = SimpleVFilter16; + VP8SimpleHFilter16 = SimpleHFilter16; + VP8SimpleVFilter16i = SimpleVFilter16i; + VP8SimpleHFilter16i = SimpleHFilter16i; +} + +#else // !WEBP_USE_MIPS32 + +WEBP_DSP_INIT_STUB(VP8DspInitMIPS32) + +#endif // WEBP_USE_MIPS32 diff --git a/libraries/webp/src/dsp/dec_mips_dsp_r2.c b/libraries/webp/src/dsp/dec_mips_dsp_r2.c new file mode 100644 index 00000000000..0ba706a2ef8 --- /dev/null +++ b/libraries/webp/src/dsp/dec_mips_dsp_r2.c @@ -0,0 +1,990 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS version of dsp functions +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) +// Jovan Zelincevic (jovan.zelincevic@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +#include "src/dsp/mips_macro.h" + +static const int kC1 = WEBP_TRANSFORM_AC3_C1; +static const int kC2 = WEBP_TRANSFORM_AC3_C2; + +static void TransformDC(const int16_t* in, uint8_t* dst) { + int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10; + + __asm__ volatile ( + LOAD_WITH_OFFSET_X4(temp1, temp2, temp3, temp4, dst, + 0, 0, 0, 0, + 0, 1, 2, 3, + BPS) + "lh %[temp5], 0(%[in]) \n\t" + "addiu %[temp5], %[temp5], 4 \n\t" + "ins %[temp5], %[temp5], 16, 16 \n\t" + "shra.ph %[temp5], %[temp5], 3 \n\t" + CONVERT_2_BYTES_TO_HALF(temp6, temp7, temp8, temp9, temp10, temp1, temp2, + temp3, temp1, temp2, temp3, temp4) + STORE_SAT_SUM_X2(temp6, temp7, temp8, temp9, temp10, temp1, temp2, temp3, + temp5, temp5, temp5, temp5, temp5, temp5, temp5, temp5, + dst, 0, 1, 2, 3, BPS) + + OUTPUT_EARLY_CLOBBER_REGS_10() + : [in]"r"(in), [dst]"r"(dst) + : "memory" + ); +} + +static void TransformAC3(const int16_t* in, uint8_t* dst) { + const int a = in[0] + 4; + int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]); + const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]); + const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]); + const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]); + int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; + int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18; + + __asm__ volatile ( + "ins %[c4], %[d4], 16, 16 \n\t" + "replv.ph %[temp1], %[a] \n\t" + "replv.ph %[temp4], %[d1] \n\t" + ADD_SUB_HALVES(temp2, temp3, temp1, c4) + "replv.ph %[temp5], %[c1] \n\t" + SHIFT_R_SUM_X2(temp1, temp6, temp7, temp8, temp2, temp9, temp10, temp4, + temp2, temp2, temp3, temp3, temp4, temp5, temp4, temp5) + LOAD_WITH_OFFSET_X4(temp3, temp5, temp11, temp12, dst, + 0, 0, 0, 0, + 0, 1, 2, 3, + BPS) + CONVERT_2_BYTES_TO_HALF(temp13, temp14, temp3, temp15, temp5, temp16, + temp11, temp17, temp3, temp5, temp11, temp12) + PACK_2_HALVES_TO_WORD(temp12, temp18, temp7, temp6, temp1, temp8, temp2, + temp4, temp7, temp6, temp10, temp9) + STORE_SAT_SUM_X2(temp13, temp14, temp3, temp15, temp5, temp16, temp11, + temp17, temp12, temp18, temp1, temp8, temp2, temp4, + temp7, temp6, dst, 0, 1, 2, 3, BPS) + + OUTPUT_EARLY_CLOBBER_REGS_18(), + [c4]"+&r"(c4) + : [dst]"r"(dst), [a]"r"(a), [d1]"r"(d1), [d4]"r"(d4), [c1]"r"(c1) + : "memory" + ); +} + +static void TransformOne(const int16_t* in, uint8_t* dst) { + int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; + int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18; + + __asm__ volatile ( + "ulw %[temp1], 0(%[in]) \n\t" + "ulw %[temp2], 16(%[in]) \n\t" + LOAD_IN_X2(temp5, temp6, 24, 26) + ADD_SUB_HALVES(temp3, temp4, temp1, temp2) + LOAD_IN_X2(temp1, temp2, 8, 10) + MUL_SHIFT_SUM(temp7, temp8, temp9, temp10, temp11, temp12, temp13, temp14, + temp10, temp8, temp9, temp7, temp1, temp2, temp5, temp6, + temp13, temp11, temp14, temp12) + INSERT_HALF_X2(temp8, temp7, temp10, temp9) + "ulw %[temp17], 4(%[in]) \n\t" + "ulw %[temp18], 20(%[in]) \n\t" + ADD_SUB_HALVES(temp1, temp2, temp3, temp8) + ADD_SUB_HALVES(temp5, temp6, temp4, temp7) + ADD_SUB_HALVES(temp7, temp8, temp17, temp18) + LOAD_IN_X2(temp17, temp18, 12, 14) + LOAD_IN_X2(temp9, temp10, 28, 30) + MUL_SHIFT_SUM(temp11, temp12, temp13, temp14, temp15, temp16, temp4, temp17, + temp12, temp14, temp11, temp13, temp17, temp18, temp9, temp10, + temp15, temp4, temp16, temp17) + INSERT_HALF_X2(temp11, temp12, temp13, temp14) + ADD_SUB_HALVES(temp17, temp8, temp8, temp11) + ADD_SUB_HALVES(temp3, temp4, temp7, temp12) + + // horizontal + SRA_16(temp9, temp10, temp11, temp12, temp1, temp2, temp5, temp6) + INSERT_HALF_X2(temp1, temp6, temp5, temp2) + SRA_16(temp13, temp14, temp15, temp16, temp3, temp4, temp17, temp8) + "repl.ph %[temp2], 0x4 \n\t" + INSERT_HALF_X2(temp3, temp8, temp17, temp4) + "addq.ph %[temp1], %[temp1], %[temp2] \n\t" + "addq.ph %[temp6], %[temp6], %[temp2] \n\t" + ADD_SUB_HALVES(temp2, temp4, temp1, temp3) + ADD_SUB_HALVES(temp5, temp7, temp6, temp8) + MUL_SHIFT_SUM(temp1, temp3, temp6, temp8, temp9, temp13, temp17, temp18, + temp3, temp13, temp1, temp9, temp9, temp13, temp11, temp15, + temp6, temp17, temp8, temp18) + MUL_SHIFT_SUM(temp6, temp8, temp18, temp17, temp11, temp15, temp12, temp16, + temp8, temp15, temp6, temp11, temp12, temp16, temp10, temp14, + temp18, temp12, temp17, temp16) + INSERT_HALF_X2(temp1, temp3, temp9, temp13) + INSERT_HALF_X2(temp6, temp8, temp11, temp15) + SHIFT_R_SUM_X2(temp9, temp10, temp11, temp12, temp13, temp14, temp15, + temp16, temp2, temp4, temp5, temp7, temp3, temp1, temp8, + temp6) + PACK_2_HALVES_TO_WORD(temp1, temp2, temp3, temp4, temp9, temp12, temp13, + temp16, temp11, temp10, temp15, temp14) + LOAD_WITH_OFFSET_X4(temp10, temp11, temp14, temp15, dst, + 0, 0, 0, 0, + 0, 1, 2, 3, + BPS) + CONVERT_2_BYTES_TO_HALF(temp5, temp6, temp7, temp8, temp17, temp18, temp10, + temp11, temp10, temp11, temp14, temp15) + STORE_SAT_SUM_X2(temp5, temp6, temp7, temp8, temp17, temp18, temp10, temp11, + temp9, temp12, temp1, temp2, temp13, temp16, temp3, temp4, + dst, 0, 1, 2, 3, BPS) + + OUTPUT_EARLY_CLOBBER_REGS_18() + : [dst]"r"(dst), [in]"r"(in), [kC1]"r"(kC1), [kC2]"r"(kC2) + : "memory", "hi", "lo" + ); +} + +static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) { + TransformOne(in, dst); + if (do_two) { + TransformOne(in + 16, dst + 4); + } +} + +static WEBP_INLINE void FilterLoop26(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, int hev_thresh) { + const int thresh2 = 2 * thresh + 1; + int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; + int temp10, temp11, temp12, temp13, temp14, temp15; + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "1: \n\t" + "negu %[temp1], %[hstride] \n\t" + "addiu %[size], %[size], -1 \n\t" + "sll %[temp2], %[hstride], 1 \n\t" + "sll %[temp3], %[temp1], 1 \n\t" + "addu %[temp4], %[temp2], %[hstride] \n\t" + "addu %[temp5], %[temp3], %[temp1] \n\t" + "lbu %[temp7], 0(%[p]) \n\t" + "sll %[temp6], %[temp3], 1 \n\t" + "lbux %[temp8], %[temp5](%[p]) \n\t" + "lbux %[temp9], %[temp3](%[p]) \n\t" + "lbux %[temp10], %[temp1](%[p]) \n\t" + "lbux %[temp11], %[temp6](%[p]) \n\t" + "lbux %[temp12], %[hstride](%[p]) \n\t" + "lbux %[temp13], %[temp2](%[p]) \n\t" + "lbux %[temp14], %[temp4](%[p]) \n\t" + "subu %[temp1], %[temp10], %[temp7] \n\t" + "subu %[temp2], %[temp9], %[temp12] \n\t" + "absq_s.w %[temp3], %[temp1] \n\t" + "absq_s.w %[temp4], %[temp2] \n\t" + "negu %[temp1], %[temp1] \n\t" + "sll %[temp3], %[temp3], 2 \n\t" + "addu %[temp15], %[temp3], %[temp4] \n\t" + "subu %[temp3], %[temp15], %[thresh2] \n\t" + "sll %[temp6], %[temp1], 1 \n\t" + "bgtz %[temp3], 3f \n\t" + " subu %[temp4], %[temp11], %[temp8] \n\t" + "absq_s.w %[temp4], %[temp4] \n\t" + "shll_s.w %[temp2], %[temp2], 24 \n\t" + "subu %[temp4], %[temp4], %[ithresh] \n\t" + "bgtz %[temp4], 3f \n\t" + " subu %[temp3], %[temp8], %[temp9] \n\t" + "absq_s.w %[temp3], %[temp3] \n\t" + "subu %[temp3], %[temp3], %[ithresh] \n\t" + "bgtz %[temp3], 3f \n\t" + " subu %[temp5], %[temp9], %[temp10] \n\t" + "absq_s.w %[temp3], %[temp5] \n\t" + "absq_s.w %[temp5], %[temp5] \n\t" + "subu %[temp3], %[temp3], %[ithresh] \n\t" + "bgtz %[temp3], 3f \n\t" + " subu %[temp3], %[temp14], %[temp13] \n\t" + "absq_s.w %[temp3], %[temp3] \n\t" + "slt %[temp5], %[hev_thresh], %[temp5] \n\t" + "subu %[temp3], %[temp3], %[ithresh] \n\t" + "bgtz %[temp3], 3f \n\t" + " subu %[temp3], %[temp13], %[temp12] \n\t" + "absq_s.w %[temp3], %[temp3] \n\t" + "sra %[temp4], %[temp2], 24 \n\t" + "subu %[temp3], %[temp3], %[ithresh] \n\t" + "bgtz %[temp3], 3f \n\t" + " subu %[temp15], %[temp12], %[temp7] \n\t" + "absq_s.w %[temp3], %[temp15] \n\t" + "absq_s.w %[temp15], %[temp15] \n\t" + "subu %[temp3], %[temp3], %[ithresh] \n\t" + "bgtz %[temp3], 3f \n\t" + " slt %[temp15], %[hev_thresh], %[temp15] \n\t" + "addu %[temp3], %[temp6], %[temp1] \n\t" + "or %[temp2], %[temp5], %[temp15] \n\t" + "addu %[temp5], %[temp4], %[temp3] \n\t" + "beqz %[temp2], 4f \n\t" + " shra_r.w %[temp1], %[temp5], 3 \n\t" + "addiu %[temp2], %[temp5], 3 \n\t" + "sra %[temp2], %[temp2], 3 \n\t" + "shll_s.w %[temp1], %[temp1], 27 \n\t" + "shll_s.w %[temp2], %[temp2], 27 \n\t" + "subu %[temp3], %[p], %[hstride] \n\t" + "sra %[temp1], %[temp1], 27 \n\t" + "sra %[temp2], %[temp2], 27 \n\t" + "subu %[temp1], %[temp7], %[temp1] \n\t" + "addu %[temp2], %[temp10], %[temp2] \n\t" + "lbux %[temp2], %[temp2](%[VP8kclip1]) \n\t" + "lbux %[temp1], %[temp1](%[VP8kclip1]) \n\t" + "sb %[temp2], 0(%[temp3]) \n\t" + "j 3f \n\t" + " sb %[temp1], 0(%[p]) \n\t" + "4: \n\t" + "shll_s.w %[temp5], %[temp5], 24 \n\t" + "subu %[temp14], %[p], %[hstride] \n\t" + "subu %[temp11], %[temp14], %[hstride] \n\t" + "sra %[temp6], %[temp5], 24 \n\t" + "sll %[temp1], %[temp6], 3 \n\t" + "subu %[temp15], %[temp11], %[hstride] \n\t" + "addu %[temp2], %[temp6], %[temp1] \n\t" + "sll %[temp3], %[temp2], 1 \n\t" + "addu %[temp4], %[temp3], %[temp2] \n\t" + "addiu %[temp2], %[temp2], 63 \n\t" + "addiu %[temp3], %[temp3], 63 \n\t" + "addiu %[temp4], %[temp4], 63 \n\t" + "sra %[temp2], %[temp2], 7 \n\t" + "sra %[temp3], %[temp3], 7 \n\t" + "sra %[temp4], %[temp4], 7 \n\t" + "addu %[temp1], %[temp8], %[temp2] \n\t" + "addu %[temp5], %[temp9], %[temp3] \n\t" + "addu %[temp6], %[temp10], %[temp4] \n\t" + "subu %[temp8], %[temp7], %[temp4] \n\t" + "subu %[temp7], %[temp12], %[temp3] \n\t" + "addu %[temp10], %[p], %[hstride] \n\t" + "subu %[temp9], %[temp13], %[temp2] \n\t" + "addu %[temp12], %[temp10], %[hstride] \n\t" + "lbux %[temp2], %[temp1](%[VP8kclip1]) \n\t" + "lbux %[temp3], %[temp5](%[VP8kclip1]) \n\t" + "lbux %[temp4], %[temp6](%[VP8kclip1]) \n\t" + "lbux %[temp5], %[temp8](%[VP8kclip1]) \n\t" + "lbux %[temp6], %[temp7](%[VP8kclip1]) \n\t" + "lbux %[temp8], %[temp9](%[VP8kclip1]) \n\t" + "sb %[temp2], 0(%[temp15]) \n\t" + "sb %[temp3], 0(%[temp11]) \n\t" + "sb %[temp4], 0(%[temp14]) \n\t" + "sb %[temp5], 0(%[p]) \n\t" + "sb %[temp6], 0(%[temp10]) \n\t" + "sb %[temp8], 0(%[temp12]) \n\t" + "3: \n\t" + "bgtz %[size], 1b \n\t" + " addu %[p], %[p], %[vstride] \n\t" + ".set pop \n\t" + : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),[temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), + [temp7]"=&r"(temp7),[temp8]"=&r"(temp8),[temp9]"=&r"(temp9), + [temp10]"=&r"(temp10),[temp11]"=&r"(temp11),[temp12]"=&r"(temp12), + [temp13]"=&r"(temp13),[temp14]"=&r"(temp14),[temp15]"=&r"(temp15), + [size]"+&r"(size), [p]"+&r"(p) + : [hstride]"r"(hstride), [thresh2]"r"(thresh2), + [ithresh]"r"(ithresh),[vstride]"r"(vstride), [hev_thresh]"r"(hev_thresh), + [VP8kclip1]"r"(VP8kclip1) + : "memory" + ); +} + +static WEBP_INLINE void FilterLoop24(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, int hev_thresh) { + int p0, q0, p1, q1, p2, q2, p3, q3; + int step1, step2, temp1, temp2, temp3, temp4; + uint8_t* pTemp0; + uint8_t* pTemp1; + const int thresh2 = 2 * thresh + 1; + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "bltz %[size], 3f \n\t" + " nop \n\t" + "2: \n\t" + "negu %[step1], %[hstride] \n\t" + "lbu %[q0], 0(%[p]) \n\t" + "lbux %[p0], %[step1](%[p]) \n\t" + "subu %[step1], %[step1], %[hstride] \n\t" + "lbux %[q1], %[hstride](%[p]) \n\t" + "subu %[temp1], %[p0], %[q0] \n\t" + "lbux %[p1], %[step1](%[p]) \n\t" + "addu %[step2], %[hstride], %[hstride] \n\t" + "absq_s.w %[temp2], %[temp1] \n\t" + "subu %[temp3], %[p1], %[q1] \n\t" + "absq_s.w %[temp4], %[temp3] \n\t" + "sll %[temp2], %[temp2], 2 \n\t" + "addu %[temp2], %[temp2], %[temp4] \n\t" + "subu %[temp4], %[temp2], %[thresh2] \n\t" + "subu %[step1], %[step1], %[hstride] \n\t" + "bgtz %[temp4], 0f \n\t" + " lbux %[p2], %[step1](%[p]) \n\t" + "subu %[step1], %[step1], %[hstride] \n\t" + "lbux %[q2], %[step2](%[p]) \n\t" + "lbux %[p3], %[step1](%[p]) \n\t" + "subu %[temp4], %[p2], %[p1] \n\t" + "addu %[step2], %[step2], %[hstride] \n\t" + "subu %[temp2], %[p3], %[p2] \n\t" + "absq_s.w %[temp4], %[temp4] \n\t" + "absq_s.w %[temp2], %[temp2] \n\t" + "lbux %[q3], %[step2](%[p]) \n\t" + "subu %[temp4], %[temp4], %[ithresh] \n\t" + "negu %[temp1], %[temp1] \n\t" + "bgtz %[temp4], 0f \n\t" + " subu %[temp2], %[temp2], %[ithresh] \n\t" + "subu %[p3], %[p1], %[p0] \n\t" + "bgtz %[temp2], 0f \n\t" + " absq_s.w %[p3], %[p3] \n\t" + "subu %[temp4], %[q3], %[q2] \n\t" + "subu %[pTemp0], %[p], %[hstride] \n\t" + "absq_s.w %[temp4], %[temp4] \n\t" + "subu %[temp2], %[p3], %[ithresh] \n\t" + "sll %[step1], %[temp1], 1 \n\t" + "bgtz %[temp2], 0f \n\t" + " subu %[temp4], %[temp4], %[ithresh] \n\t" + "subu %[temp2], %[q2], %[q1] \n\t" + "bgtz %[temp4], 0f \n\t" + " absq_s.w %[temp2], %[temp2] \n\t" + "subu %[q3], %[q1], %[q0] \n\t" + "absq_s.w %[q3], %[q3] \n\t" + "subu %[temp2], %[temp2], %[ithresh] \n\t" + "addu %[temp1], %[temp1], %[step1] \n\t" + "bgtz %[temp2], 0f \n\t" + " subu %[temp4], %[q3], %[ithresh] \n\t" + "slt %[p3], %[hev_thresh], %[p3] \n\t" + "bgtz %[temp4], 0f \n\t" + " slt %[q3], %[hev_thresh], %[q3] \n\t" + "or %[q3], %[q3], %[p3] \n\t" + "bgtz %[q3], 1f \n\t" + " shra_r.w %[temp2], %[temp1], 3 \n\t" + "addiu %[temp1], %[temp1], 3 \n\t" + "sra %[temp1], %[temp1], 3 \n\t" + "shll_s.w %[temp2], %[temp2], 27 \n\t" + "shll_s.w %[temp1], %[temp1], 27 \n\t" + "addu %[pTemp1], %[p], %[hstride] \n\t" + "sra %[temp2], %[temp2], 27 \n\t" + "sra %[temp1], %[temp1], 27 \n\t" + "addiu %[step1], %[temp2], 1 \n\t" + "sra %[step1], %[step1], 1 \n\t" + "addu %[p0], %[p0], %[temp1] \n\t" + "addu %[p1], %[p1], %[step1] \n\t" + "subu %[q0], %[q0], %[temp2] \n\t" + "subu %[q1], %[q1], %[step1] \n\t" + "lbux %[temp2], %[p0](%[VP8kclip1]) \n\t" + "lbux %[temp3], %[q0](%[VP8kclip1]) \n\t" + "lbux %[temp4], %[q1](%[VP8kclip1]) \n\t" + "sb %[temp2], 0(%[pTemp0]) \n\t" + "lbux %[temp1], %[p1](%[VP8kclip1]) \n\t" + "subu %[pTemp0], %[pTemp0], %[hstride] \n\t" + "sb %[temp3], 0(%[p]) \n\t" + "sb %[temp4], 0(%[pTemp1]) \n\t" + "j 0f \n\t" + " sb %[temp1], 0(%[pTemp0]) \n\t" + "1: \n\t" + "shll_s.w %[temp3], %[temp3], 24 \n\t" + "sra %[temp3], %[temp3], 24 \n\t" + "addu %[temp1], %[temp1], %[temp3] \n\t" + "shra_r.w %[temp2], %[temp1], 3 \n\t" + "addiu %[temp1], %[temp1], 3 \n\t" + "shll_s.w %[temp2], %[temp2], 27 \n\t" + "sra %[temp1], %[temp1], 3 \n\t" + "shll_s.w %[temp1], %[temp1], 27 \n\t" + "sra %[temp2], %[temp2], 27 \n\t" + "sra %[temp1], %[temp1], 27 \n\t" + "addu %[p0], %[p0], %[temp1] \n\t" + "subu %[q0], %[q0], %[temp2] \n\t" + "lbux %[temp1], %[p0](%[VP8kclip1]) \n\t" + "lbux %[temp2], %[q0](%[VP8kclip1]) \n\t" + "sb %[temp2], 0(%[p]) \n\t" + "sb %[temp1], 0(%[pTemp0]) \n\t" + "0: \n\t" + "subu %[size], %[size], 1 \n\t" + "bgtz %[size], 2b \n\t" + " addu %[p], %[p], %[vstride] \n\t" + "3: \n\t" + ".set pop \n\t" + : [p0]"=&r"(p0), [q0]"=&r"(q0), [p1]"=&r"(p1), [q1]"=&r"(q1), + [p2]"=&r"(p2), [q2]"=&r"(q2), [p3]"=&r"(p3), [q3]"=&r"(q3), + [step2]"=&r"(step2), [step1]"=&r"(step1), [temp1]"=&r"(temp1), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), + [pTemp0]"=&r"(pTemp0), [pTemp1]"=&r"(pTemp1), [p]"+&r"(p), + [size]"+&r"(size) + : [vstride]"r"(vstride), [ithresh]"r"(ithresh), + [hev_thresh]"r"(hev_thresh), [hstride]"r"(hstride), + [VP8kclip1]"r"(VP8kclip1), [thresh2]"r"(thresh2) + : "memory" + ); +} + +// on macroblock edges +static void VFilter16(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh); +} + +static void HFilter16(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh); +} + +// 8-pixels wide variant, for chroma filtering +static void VFilter8(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh); +} + +static void HFilter8(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh); +} + +// on three inner edges +static void VFilter16i(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh); + } +} + +static void HFilter16i(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh); + } +} + +static void VFilter8i(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); +} + +static void HFilter8i(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); +} + +//------------------------------------------------------------------------------ +// Simple In-loop filtering (Paragraph 15.2) + +static void SimpleVFilter16(uint8_t* p, int stride, int thresh) { + int i; + const int thresh2 = 2 * thresh + 1; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; + uint8_t* p1 = p - stride; + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "li %[i], 16 \n\t" + "0: \n\t" + "negu %[temp4], %[stride] \n\t" + "sll %[temp5], %[temp4], 1 \n\t" + "lbu %[temp2], 0(%[p]) \n\t" + "lbux %[temp3], %[stride](%[p]) \n\t" + "lbux %[temp1], %[temp4](%[p]) \n\t" + "lbux %[temp0], %[temp5](%[p]) \n\t" + "subu %[temp7], %[temp1], %[temp2] \n\t" + "subu %[temp6], %[temp0], %[temp3] \n\t" + "absq_s.w %[temp4], %[temp7] \n\t" + "absq_s.w %[temp5], %[temp6] \n\t" + "sll %[temp4], %[temp4], 2 \n\t" + "subu %[temp5], %[temp5], %[thresh2] \n\t" + "addu %[temp5], %[temp4], %[temp5] \n\t" + "negu %[temp8], %[temp7] \n\t" + "bgtz %[temp5], 1f \n\t" + " addiu %[i], %[i], -1 \n\t" + "sll %[temp4], %[temp8], 1 \n\t" + "shll_s.w %[temp5], %[temp6], 24 \n\t" + "addu %[temp3], %[temp4], %[temp8] \n\t" + "sra %[temp5], %[temp5], 24 \n\t" + "addu %[temp3], %[temp3], %[temp5] \n\t" + "addiu %[temp7], %[temp3], 3 \n\t" + "sra %[temp7], %[temp7], 3 \n\t" + "shra_r.w %[temp8], %[temp3], 3 \n\t" + "shll_s.w %[temp0], %[temp7], 27 \n\t" + "shll_s.w %[temp4], %[temp8], 27 \n\t" + "sra %[temp0], %[temp0], 27 \n\t" + "sra %[temp4], %[temp4], 27 \n\t" + "addu %[temp7], %[temp1], %[temp0] \n\t" + "subu %[temp2], %[temp2], %[temp4] \n\t" + "lbux %[temp3], %[temp7](%[VP8kclip1]) \n\t" + "lbux %[temp4], %[temp2](%[VP8kclip1]) \n\t" + "sb %[temp3], 0(%[p1]) \n\t" + "sb %[temp4], 0(%[p]) \n\t" + "1: \n\t" + "addiu %[p1], %[p1], 1 \n\t" + "bgtz %[i], 0b \n\t" + " addiu %[p], %[p], 1 \n\t" + " .set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [p]"+&r"(p), [i]"=&r"(i), [p1]"+&r"(p1) + : [stride]"r"(stride), [VP8kclip1]"r"(VP8kclip1), [thresh2]"r"(thresh2) + : "memory" + ); +} + +// TEMP0 = SRC[A + A1 * BPS] +// TEMP1 = SRC[B + B1 * BPS] +// TEMP2 = SRC[C + C1 * BPS] +// TEMP3 = SRC[D + D1 * BPS] +#define LOAD_4_BYTES(TEMP0, TEMP1, TEMP2, TEMP3, \ + A, A1, B, B1, C, C1, D, D1, SRC) \ + "lbu %[" #TEMP0 "], " #A "+" #A1 "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \ + "lbu %[" #TEMP1 "], " #B "+" #B1 "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \ + "lbu %[" #TEMP2 "], " #C "+" #C1 "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \ + "lbu %[" #TEMP3 "], " #D "+" #D1 "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \ + +static void SimpleHFilter16(uint8_t* p, int stride, int thresh) { + int i; + const int thresh2 = 2 * thresh + 1; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "li %[i], 16 \n\t" + "0: \n\t" + LOAD_4_BYTES(temp0, temp1, temp2, temp3, -2, 0, -1, 0, 0, 0, 1, 0, p) + "subu %[temp7], %[temp1], %[temp2] \n\t" + "subu %[temp6], %[temp0], %[temp3] \n\t" + "absq_s.w %[temp4], %[temp7] \n\t" + "absq_s.w %[temp5], %[temp6] \n\t" + "sll %[temp4], %[temp4], 2 \n\t" + "addu %[temp5], %[temp4], %[temp5] \n\t" + "subu %[temp5], %[temp5], %[thresh2] \n\t" + "negu %[temp8], %[temp7] \n\t" + "bgtz %[temp5], 1f \n\t" + " addiu %[i], %[i], -1 \n\t" + "sll %[temp4], %[temp8], 1 \n\t" + "shll_s.w %[temp5], %[temp6], 24 \n\t" + "addu %[temp3], %[temp4], %[temp8] \n\t" + "sra %[temp5], %[temp5], 24 \n\t" + "addu %[temp3], %[temp3], %[temp5] \n\t" + "addiu %[temp7], %[temp3], 3 \n\t" + "sra %[temp7], %[temp7], 3 \n\t" + "shra_r.w %[temp8], %[temp3], 3 \n\t" + "shll_s.w %[temp0], %[temp7], 27 \n\t" + "shll_s.w %[temp4], %[temp8], 27 \n\t" + "sra %[temp0], %[temp0], 27 \n\t" + "sra %[temp4], %[temp4], 27 \n\t" + "addu %[temp7], %[temp1], %[temp0] \n\t" + "subu %[temp2], %[temp2], %[temp4] \n\t" + "lbux %[temp3], %[temp7](%[VP8kclip1]) \n\t" + "lbux %[temp4], %[temp2](%[VP8kclip1]) \n\t" + "sb %[temp3], -1(%[p]) \n\t" + "sb %[temp4], 0(%[p]) \n\t" + "1: \n\t" + "bgtz %[i], 0b \n\t" + " addu %[p], %[p], %[stride] \n\t" + ".set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [p]"+&r"(p), [i]"=&r"(i) + : [stride]"r"(stride), [VP8kclip1]"r"(VP8kclip1), [thresh2]"r"(thresh2) + : "memory" + ); +} + +static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + SimpleVFilter16(p, stride, thresh); + } +} + +static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + SimpleHFilter16(p, stride, thresh); + } +} + +// DST[A * BPS] = TEMP0 +// DST[B + C * BPS] = TEMP1 +#define STORE_8_BYTES(TEMP0, TEMP1, A, B, C, DST) \ + "usw %[" #TEMP0 "], " #A "*" XSTR(BPS) "(%[" #DST "]) \n\t" \ + "usw %[" #TEMP1 "], " #B "+" #C "*" XSTR(BPS) "(%[" #DST "]) \n\t" + +static void VE4(uint8_t* dst) { // vertical + const uint8_t* top = dst - BPS; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6; + __asm__ volatile ( + "ulw %[temp0], -1(%[top]) \n\t" + "ulh %[temp1], 3(%[top]) \n\t" + "preceu.ph.qbr %[temp2], %[temp0] \n\t" + "preceu.ph.qbl %[temp3], %[temp0] \n\t" + "preceu.ph.qbr %[temp4], %[temp1] \n\t" + "packrl.ph %[temp5], %[temp3], %[temp2] \n\t" + "packrl.ph %[temp6], %[temp4], %[temp3] \n\t" + "shll.ph %[temp5], %[temp5], 1 \n\t" + "shll.ph %[temp6], %[temp6], 1 \n\t" + "addq.ph %[temp2], %[temp5], %[temp2] \n\t" + "addq.ph %[temp6], %[temp6], %[temp4] \n\t" + "addq.ph %[temp2], %[temp2], %[temp3] \n\t" + "addq.ph %[temp6], %[temp6], %[temp3] \n\t" + "shra_r.ph %[temp2], %[temp2], 2 \n\t" + "shra_r.ph %[temp6], %[temp6], 2 \n\t" + "precr.qb.ph %[temp4], %[temp6], %[temp2] \n\t" + STORE_8_BYTES(temp4, temp4, 0, 0, 1, dst) + STORE_8_BYTES(temp4, temp4, 2, 0, 3, dst) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void DC4(uint8_t* dst) { // DC + int temp0, temp1, temp2, temp3, temp4; + __asm__ volatile ( + "ulw %[temp0], -1*" XSTR(BPS) "(%[dst]) \n\t" + LOAD_4_BYTES(temp1, temp2, temp3, temp4, -1, 0, -1, 1, -1, 2, -1, 3, dst) + "ins %[temp1], %[temp2], 8, 8 \n\t" + "ins %[temp1], %[temp3], 16, 8 \n\t" + "ins %[temp1], %[temp4], 24, 8 \n\t" + "raddu.w.qb %[temp0], %[temp0] \n\t" + "raddu.w.qb %[temp1], %[temp1] \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "shra_r.w %[temp0], %[temp0], 3 \n\t" + "replv.qb %[temp0], %[temp0] \n\t" + STORE_8_BYTES(temp0, temp0, 0, 0, 1, dst) + STORE_8_BYTES(temp0, temp0, 2, 0, 3, dst) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4) + : [dst]"r"(dst) + : "memory" + ); +} + +static void RD4(uint8_t* dst) { // Down-right + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8; + __asm__ volatile ( + LOAD_4_BYTES(temp0, temp1, temp2, temp3, -1, 0, -1, 1, -1, 2, -1, 3, dst) + "ulw %[temp7], -1-" XSTR(BPS) "(%[dst]) \n\t" + "ins %[temp1], %[temp0], 16, 16 \n\t" + "preceu.ph.qbr %[temp5], %[temp7] \n\t" + "ins %[temp2], %[temp1], 16, 16 \n\t" + "preceu.ph.qbl %[temp4], %[temp7] \n\t" + "ins %[temp3], %[temp2], 16, 16 \n\t" + "shll.ph %[temp2], %[temp2], 1 \n\t" + "addq.ph %[temp3], %[temp3], %[temp1] \n\t" + "packrl.ph %[temp6], %[temp5], %[temp1] \n\t" + "addq.ph %[temp3], %[temp3], %[temp2] \n\t" + "addq.ph %[temp1], %[temp1], %[temp5] \n\t" + "shll.ph %[temp6], %[temp6], 1 \n\t" + "addq.ph %[temp1], %[temp1], %[temp6] \n\t" + "packrl.ph %[temp0], %[temp4], %[temp5] \n\t" + "addq.ph %[temp8], %[temp5], %[temp4] \n\t" + "shra_r.ph %[temp3], %[temp3], 2 \n\t" + "shll.ph %[temp0], %[temp0], 1 \n\t" + "shra_r.ph %[temp1], %[temp1], 2 \n\t" + "addq.ph %[temp8], %[temp0], %[temp8] \n\t" + "lbu %[temp5], 3-" XSTR(BPS) "(%[dst]) \n\t" + "precrq.ph.w %[temp7], %[temp7], %[temp7] \n\t" + "shra_r.ph %[temp8], %[temp8], 2 \n\t" + "ins %[temp7], %[temp5], 0, 8 \n\t" + "precr.qb.ph %[temp2], %[temp1], %[temp3] \n\t" + "raddu.w.qb %[temp4], %[temp7] \n\t" + "precr.qb.ph %[temp6], %[temp8], %[temp1] \n\t" + "shra_r.w %[temp4], %[temp4], 2 \n\t" + STORE_8_BYTES(temp2, temp6, 3, 0, 1, dst) + "prepend %[temp2], %[temp8], 8 \n\t" + "prepend %[temp6], %[temp4], 8 \n\t" + STORE_8_BYTES(temp2, temp6, 2, 0, 0, dst) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8) + : [dst]"r"(dst) + : "memory" + ); +} + +// TEMP0 = SRC[A * BPS] +// TEMP1 = SRC[B + C * BPS] +#define LOAD_8_BYTES(TEMP0, TEMP1, A, B, C, SRC) \ + "ulw %[" #TEMP0 "], " #A "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \ + "ulw %[" #TEMP1 "], " #B "+" #C "*" XSTR(BPS) "(%[" #SRC "]) \n\t" + +static void LD4(uint8_t* dst) { // Down-Left + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8, temp9; + __asm__ volatile ( + LOAD_8_BYTES(temp0, temp1, -1, 4, -1, dst) + "preceu.ph.qbl %[temp2], %[temp0] \n\t" + "preceu.ph.qbr %[temp3], %[temp0] \n\t" + "preceu.ph.qbr %[temp4], %[temp1] \n\t" + "preceu.ph.qbl %[temp5], %[temp1] \n\t" + "packrl.ph %[temp6], %[temp2], %[temp3] \n\t" + "packrl.ph %[temp7], %[temp4], %[temp2] \n\t" + "packrl.ph %[temp8], %[temp5], %[temp4] \n\t" + "shll.ph %[temp6], %[temp6], 1 \n\t" + "addq.ph %[temp9], %[temp2], %[temp6] \n\t" + "shll.ph %[temp7], %[temp7], 1 \n\t" + "addq.ph %[temp9], %[temp9], %[temp3] \n\t" + "shll.ph %[temp8], %[temp8], 1 \n\t" + "shra_r.ph %[temp9], %[temp9], 2 \n\t" + "addq.ph %[temp3], %[temp4], %[temp7] \n\t" + "addq.ph %[temp0], %[temp5], %[temp8] \n\t" + "addq.ph %[temp3], %[temp3], %[temp2] \n\t" + "addq.ph %[temp0], %[temp0], %[temp4] \n\t" + "shra_r.ph %[temp3], %[temp3], 2 \n\t" + "shra_r.ph %[temp0], %[temp0], 2 \n\t" + "srl %[temp1], %[temp1], 24 \n\t" + "sll %[temp1], %[temp1], 1 \n\t" + "raddu.w.qb %[temp5], %[temp5] \n\t" + "precr.qb.ph %[temp9], %[temp3], %[temp9] \n\t" + "precr.qb.ph %[temp3], %[temp0], %[temp3] \n\t" + "addu %[temp1], %[temp1], %[temp5] \n\t" + "shra_r.w %[temp1], %[temp1], 2 \n\t" + STORE_8_BYTES(temp9, temp3, 0, 0, 2, dst) + "prepend %[temp9], %[temp0], 8 \n\t" + "prepend %[temp3], %[temp1], 8 \n\t" + STORE_8_BYTES(temp9, temp3, 1, 0, 3, dst) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9) + : [dst]"r"(dst) + : "memory" + ); +} + +//------------------------------------------------------------------------------ +// Chroma + +static void DC8uv(uint8_t* dst) { // DC + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8, temp9; + __asm__ volatile ( + LOAD_8_BYTES(temp0, temp1, -1, 4, -1, dst) + LOAD_4_BYTES(temp2, temp3, temp4, temp5, -1, 0, -1, 1, -1, 2, -1, 3, dst) + LOAD_4_BYTES(temp6, temp7, temp8, temp9, -1, 4, -1, 5, -1, 6, -1, 7, dst) + "raddu.w.qb %[temp0], %[temp0] \n\t" + "raddu.w.qb %[temp1], %[temp1] \n\t" + "addu %[temp2], %[temp2], %[temp3] \n\t" + "addu %[temp4], %[temp4], %[temp5] \n\t" + "addu %[temp6], %[temp6], %[temp7] \n\t" + "addu %[temp8], %[temp8], %[temp9] \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "addu %[temp2], %[temp2], %[temp4] \n\t" + "addu %[temp6], %[temp6], %[temp8] \n\t" + "addu %[temp0], %[temp0], %[temp2] \n\t" + "addu %[temp0], %[temp0], %[temp6] \n\t" + "shra_r.w %[temp0], %[temp0], 4 \n\t" + "replv.qb %[temp0], %[temp0] \n\t" + STORE_8_BYTES(temp0, temp0, 0, 4, 0, dst) + STORE_8_BYTES(temp0, temp0, 1, 4, 1, dst) + STORE_8_BYTES(temp0, temp0, 2, 4, 2, dst) + STORE_8_BYTES(temp0, temp0, 3, 4, 3, dst) + STORE_8_BYTES(temp0, temp0, 4, 4, 4, dst) + STORE_8_BYTES(temp0, temp0, 5, 4, 5, dst) + STORE_8_BYTES(temp0, temp0, 6, 4, 6, dst) + STORE_8_BYTES(temp0, temp0, 7, 4, 7, dst) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9) + : [dst]"r"(dst) + : "memory" + ); +} + +static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples + int temp0, temp1; + __asm__ volatile ( + LOAD_8_BYTES(temp0, temp1, -1, 4, -1, dst) + "raddu.w.qb %[temp0], %[temp0] \n\t" + "raddu.w.qb %[temp1], %[temp1] \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "shra_r.w %[temp0], %[temp0], 3 \n\t" + "replv.qb %[temp0], %[temp0] \n\t" + STORE_8_BYTES(temp0, temp0, 0, 4, 0, dst) + STORE_8_BYTES(temp0, temp0, 1, 4, 1, dst) + STORE_8_BYTES(temp0, temp0, 2, 4, 2, dst) + STORE_8_BYTES(temp0, temp0, 3, 4, 3, dst) + STORE_8_BYTES(temp0, temp0, 4, 4, 4, dst) + STORE_8_BYTES(temp0, temp0, 5, 4, 5, dst) + STORE_8_BYTES(temp0, temp0, 6, 4, 6, dst) + STORE_8_BYTES(temp0, temp0, 7, 4, 7, dst) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1) + : [dst]"r"(dst) + : "memory" + ); +} + +static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8; + __asm__ volatile ( + LOAD_4_BYTES(temp2, temp3, temp4, temp5, -1, 0, -1, 1, -1, 2, -1, 3, dst) + LOAD_4_BYTES(temp6, temp7, temp8, temp1, -1, 4, -1, 5, -1, 6, -1, 7, dst) + "addu %[temp2], %[temp2], %[temp3] \n\t" + "addu %[temp4], %[temp4], %[temp5] \n\t" + "addu %[temp6], %[temp6], %[temp7] \n\t" + "addu %[temp8], %[temp8], %[temp1] \n\t" + "addu %[temp2], %[temp2], %[temp4] \n\t" + "addu %[temp6], %[temp6], %[temp8] \n\t" + "addu %[temp0], %[temp6], %[temp2] \n\t" + "shra_r.w %[temp0], %[temp0], 3 \n\t" + "replv.qb %[temp0], %[temp0] \n\t" + STORE_8_BYTES(temp0, temp0, 0, 4, 0, dst) + STORE_8_BYTES(temp0, temp0, 1, 4, 1, dst) + STORE_8_BYTES(temp0, temp0, 2, 4, 2, dst) + STORE_8_BYTES(temp0, temp0, 3, 4, 3, dst) + STORE_8_BYTES(temp0, temp0, 4, 4, 4, dst) + STORE_8_BYTES(temp0, temp0, 5, 4, 5, dst) + STORE_8_BYTES(temp0, temp0, 6, 4, 6, dst) + STORE_8_BYTES(temp0, temp0, 7, 4, 7, dst) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8) + : [dst]"r"(dst) + : "memory" + ); +} + +#undef LOAD_8_BYTES +#undef STORE_8_BYTES +#undef LOAD_4_BYTES + +#define CLIPPING(SIZE) \ + "preceu.ph.qbl %[temp2], %[temp0] \n\t" \ + "preceu.ph.qbr %[temp0], %[temp0] \n\t" \ +".if " #SIZE " == 8 \n\t" \ + "preceu.ph.qbl %[temp3], %[temp1] \n\t" \ + "preceu.ph.qbr %[temp1], %[temp1] \n\t" \ +".endif \n\t" \ + "addu.ph %[temp2], %[temp2], %[dst_1] \n\t" \ + "addu.ph %[temp0], %[temp0], %[dst_1] \n\t" \ +".if " #SIZE " == 8 \n\t" \ + "addu.ph %[temp3], %[temp3], %[dst_1] \n\t" \ + "addu.ph %[temp1], %[temp1], %[dst_1] \n\t" \ +".endif \n\t" \ + "shll_s.ph %[temp2], %[temp2], 7 \n\t" \ + "shll_s.ph %[temp0], %[temp0], 7 \n\t" \ +".if " #SIZE " == 8 \n\t" \ + "shll_s.ph %[temp3], %[temp3], 7 \n\t" \ + "shll_s.ph %[temp1], %[temp1], 7 \n\t" \ +".endif \n\t" \ + "precrqu_s.qb.ph %[temp0], %[temp2], %[temp0] \n\t" \ +".if " #SIZE " == 8 \n\t" \ + "precrqu_s.qb.ph %[temp1], %[temp3], %[temp1] \n\t" \ +".endif \n\t" + + +#define CLIP_8B_TO_DST(DST, TOP, SIZE) do { \ + int dst_1 = ((int)(DST)[-1] << 16) + (DST)[-1]; \ + int temp0, temp1, temp2, temp3; \ + __asm__ volatile ( \ + ".if " #SIZE " < 8 \n\t" \ + "ulw %[temp0], 0(%[top]) \n\t" \ + "subu.ph %[dst_1], %[dst_1], %[top_1] \n\t" \ + CLIPPING(4) \ + "usw %[temp0], 0(%[dst]) \n\t" \ + ".else \n\t" \ + "ulw %[temp0], 0(%[top]) \n\t" \ + "ulw %[temp1], 4(%[top]) \n\t" \ + "subu.ph %[dst_1], %[dst_1], %[top_1] \n\t" \ + CLIPPING(8) \ + "usw %[temp0], 0(%[dst]) \n\t" \ + "usw %[temp1], 4(%[dst]) \n\t" \ + ".if " #SIZE " == 16 \n\t" \ + "ulw %[temp0], 8(%[top]) \n\t" \ + "ulw %[temp1], 12(%[top]) \n\t" \ + CLIPPING(8) \ + "usw %[temp0], 8(%[dst]) \n\t" \ + "usw %[temp1], 12(%[dst]) \n\t" \ + ".endif \n\t" \ + ".endif \n\t" \ + : [dst_1]"+&r"(dst_1), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \ + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3) \ + : [top_1]"r"(top_1), [top]"r"((TOP)), [dst]"r"((DST)) \ + : "memory" \ + ); \ +} while (0) + +#define CLIP_TO_DST(DST, SIZE) do { \ + int y; \ + const uint8_t* top = (DST) - BPS; \ + const int top_1 = ((int)top[-1] << 16) + top[-1]; \ + for (y = 0; y < (SIZE); ++y) { \ + CLIP_8B_TO_DST((DST), top, (SIZE)); \ + (DST) += BPS; \ + } \ +} while (0) + +#define TRUE_MOTION(DST, SIZE) \ +static void TrueMotion##SIZE(uint8_t* (DST)) { \ + CLIP_TO_DST((DST), (SIZE)); \ +} + +TRUE_MOTION(dst, 4) +TRUE_MOTION(dst, 8) +TRUE_MOTION(dst, 16) + +#undef TRUE_MOTION +#undef CLIP_TO_DST +#undef CLIP_8B_TO_DST +#undef CLIPPING + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitMIPSdspR2(void) { + VP8TransformDC = TransformDC; + VP8TransformAC3 = TransformAC3; + VP8Transform = TransformTwo; + + VP8VFilter16 = VFilter16; + VP8HFilter16 = HFilter16; + VP8VFilter8 = VFilter8; + VP8HFilter8 = HFilter8; + VP8VFilter16i = VFilter16i; + VP8HFilter16i = HFilter16i; + VP8VFilter8i = VFilter8i; + VP8HFilter8i = HFilter8i; + VP8SimpleVFilter16 = SimpleVFilter16; + VP8SimpleHFilter16 = SimpleHFilter16; + VP8SimpleVFilter16i = SimpleVFilter16i; + VP8SimpleHFilter16i = SimpleHFilter16i; + + VP8PredLuma4[0] = DC4; + VP8PredLuma4[1] = TrueMotion4; + VP8PredLuma4[2] = VE4; + VP8PredLuma4[4] = RD4; + VP8PredLuma4[6] = LD4; + + VP8PredChroma8[0] = DC8uv; + VP8PredChroma8[1] = TrueMotion8; + VP8PredChroma8[4] = DC8uvNoTop; + VP8PredChroma8[5] = DC8uvNoLeft; + + VP8PredLuma16[1] = TrueMotion16; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(VP8DspInitMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/dec_msa.c b/libraries/webp/src/dsp/dec_msa.c new file mode 100644 index 00000000000..58d17301921 --- /dev/null +++ b/libraries/webp/src/dsp/dec_msa.c @@ -0,0 +1,1018 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MSA version of dsp functions +// +// Author(s): Prashant Patil (prashant.patil@imgtec.com) + + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "src/dsp/msa_macro.h" + +//------------------------------------------------------------------------------ +// Transforms + +#define IDCT_1D_W(in0, in1, in2, in3, out0, out1, out2, out3) { \ + v4i32 a1_m, b1_m, c1_m, d1_m; \ + v4i32 c_tmp1_m, c_tmp2_m, d_tmp1_m, d_tmp2_m; \ + const v4i32 cospi8sqrt2minus1 = __msa_fill_w(20091); \ + const v4i32 sinpi8sqrt2 = __msa_fill_w(35468); \ + \ + a1_m = in0 + in2; \ + b1_m = in0 - in2; \ + c_tmp1_m = (in1 * sinpi8sqrt2) >> 16; \ + c_tmp2_m = in3 + ((in3 * cospi8sqrt2minus1) >> 16); \ + c1_m = c_tmp1_m - c_tmp2_m; \ + d_tmp1_m = in1 + ((in1 * cospi8sqrt2minus1) >> 16); \ + d_tmp2_m = (in3 * sinpi8sqrt2) >> 16; \ + d1_m = d_tmp1_m + d_tmp2_m; \ + BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \ +} + +static void TransformOne(const int16_t* in, uint8_t* dst) { + v8i16 input0, input1; + v4i32 in0, in1, in2, in3, hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3; + v4i32 res0, res1, res2, res3; + const v16i8 zero = { 0 }; + v16i8 dest0, dest1, dest2, dest3; + + LD_SH2(in, 8, input0, input1); + UNPCK_SH_SW(input0, in0, in1); + UNPCK_SH_SW(input1, in2, in3); + IDCT_1D_W(in0, in1, in2, in3, hz0, hz1, hz2, hz3); + TRANSPOSE4x4_SW_SW(hz0, hz1, hz2, hz3, hz0, hz1, hz2, hz3); + IDCT_1D_W(hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3); + SRARI_W4_SW(vt0, vt1, vt2, vt3, 3); + TRANSPOSE4x4_SW_SW(vt0, vt1, vt2, vt3, vt0, vt1, vt2, vt3); + LD_SB4(dst, BPS, dest0, dest1, dest2, dest3); + ILVR_B4_SW(zero, dest0, zero, dest1, zero, dest2, zero, dest3, + res0, res1, res2, res3); + ILVR_H4_SW(zero, res0, zero, res1, zero, res2, zero, res3, + res0, res1, res2, res3); + ADD4(res0, vt0, res1, vt1, res2, vt2, res3, vt3, res0, res1, res2, res3); + CLIP_SW4_0_255(res0, res1, res2, res3); + PCKEV_B2_SW(res0, res1, res2, res3, vt0, vt1); + res0 = (v4i32)__msa_pckev_b((v16i8)vt0, (v16i8)vt1); + ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS); +} + +static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) { + TransformOne(in, dst); + if (do_two) { + TransformOne(in + 16, dst + 4); + } +} + +static void TransformWHT(const int16_t* in, int16_t* out) { + v8i16 input0, input1; + const v8i16 mask0 = { 0, 1, 2, 3, 8, 9, 10, 11 }; + const v8i16 mask1 = { 4, 5, 6, 7, 12, 13, 14, 15 }; + const v8i16 mask2 = { 0, 4, 8, 12, 1, 5, 9, 13 }; + const v8i16 mask3 = { 3, 7, 11, 15, 2, 6, 10, 14 }; + v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 out0, out1; + + LD_SH2(in, 8, input0, input1); + input1 = SLDI_SH(input1, input1, 8); + tmp0 = input0 + input1; + tmp1 = input0 - input1; + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + out0 = tmp2 + tmp3; + out1 = tmp2 - tmp3; + VSHF_H2_SH(out0, out1, out0, out1, mask2, mask3, input0, input1); + tmp0 = input0 + input1; + tmp1 = input0 - input1; + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + tmp0 = tmp2 + tmp3; + tmp1 = tmp2 - tmp3; + ADDVI_H2_SH(tmp0, 3, tmp1, 3, out0, out1); + SRAI_H2_SH(out0, out1, 3); + out[0] = __msa_copy_s_h(out0, 0); + out[16] = __msa_copy_s_h(out0, 4); + out[32] = __msa_copy_s_h(out1, 0); + out[48] = __msa_copy_s_h(out1, 4); + out[64] = __msa_copy_s_h(out0, 1); + out[80] = __msa_copy_s_h(out0, 5); + out[96] = __msa_copy_s_h(out1, 1); + out[112] = __msa_copy_s_h(out1, 5); + out[128] = __msa_copy_s_h(out0, 2); + out[144] = __msa_copy_s_h(out0, 6); + out[160] = __msa_copy_s_h(out1, 2); + out[176] = __msa_copy_s_h(out1, 6); + out[192] = __msa_copy_s_h(out0, 3); + out[208] = __msa_copy_s_h(out0, 7); + out[224] = __msa_copy_s_h(out1, 3); + out[240] = __msa_copy_s_h(out1, 7); +} + +static void TransformDC(const int16_t* in, uint8_t* dst) { + const int DC = (in[0] + 4) >> 3; + const v8i16 tmp0 = __msa_fill_h(DC); + ADDBLK_ST4x4_UB(tmp0, tmp0, tmp0, tmp0, dst, BPS); +} + +static void TransformAC3(const int16_t* in, uint8_t* dst) { + const int a = in[0] + 4; + const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]); + const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]); + const int in2 = WEBP_TRANSFORM_AC3_MUL2(in[1]); + const int in3 = WEBP_TRANSFORM_AC3_MUL1(in[1]); + v4i32 tmp0 = { 0 }; + v4i32 out0 = __msa_fill_w(a + d4); + v4i32 out1 = __msa_fill_w(a + c4); + v4i32 out2 = __msa_fill_w(a - c4); + v4i32 out3 = __msa_fill_w(a - d4); + v4i32 res0, res1, res2, res3; + const v4i32 zero = { 0 }; + v16u8 dest0, dest1, dest2, dest3; + + INSERT_W4_SW(in3, in2, -in2, -in3, tmp0); + ADD4(out0, tmp0, out1, tmp0, out2, tmp0, out3, tmp0, + out0, out1, out2, out3); + SRAI_W4_SW(out0, out1, out2, out3, 3); + LD_UB4(dst, BPS, dest0, dest1, dest2, dest3); + ILVR_B4_SW(zero, dest0, zero, dest1, zero, dest2, zero, dest3, + res0, res1, res2, res3); + ILVR_H4_SW(zero, res0, zero, res1, zero, res2, zero, res3, + res0, res1, res2, res3); + ADD4(res0, out0, res1, out1, res2, out2, res3, out3, res0, res1, res2, res3); + CLIP_SW4_0_255(res0, res1, res2, res3); + PCKEV_B2_SW(res0, res1, res2, res3, out0, out1); + res0 = (v4i32)__msa_pckev_b((v16i8)out0, (v16i8)out1); + ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS); +} + +//------------------------------------------------------------------------------ +// Edge filtering functions + +#define FLIP_SIGN2(in0, in1, out0, out1) { \ + out0 = (v16i8)__msa_xori_b(in0, 0x80); \ + out1 = (v16i8)__msa_xori_b(in1, 0x80); \ +} + +#define FLIP_SIGN4(in0, in1, in2, in3, out0, out1, out2, out3) { \ + FLIP_SIGN2(in0, in1, out0, out1); \ + FLIP_SIGN2(in2, in3, out2, out3); \ +} + +#define FILT_VAL(q0_m, p0_m, mask, filt) do { \ + v16i8 q0_sub_p0; \ + q0_sub_p0 = __msa_subs_s_b(q0_m, p0_m); \ + filt = __msa_adds_s_b(filt, q0_sub_p0); \ + filt = __msa_adds_s_b(filt, q0_sub_p0); \ + filt = __msa_adds_s_b(filt, q0_sub_p0); \ + filt = filt & mask; \ +} while (0) + +#define FILT2(q_m, p_m, q, p) do { \ + u_r = SRAI_H(temp1, 7); \ + u_r = __msa_sat_s_h(u_r, 7); \ + u_l = SRAI_H(temp3, 7); \ + u_l = __msa_sat_s_h(u_l, 7); \ + u = __msa_pckev_b((v16i8)u_l, (v16i8)u_r); \ + q_m = __msa_subs_s_b(q_m, u); \ + p_m = __msa_adds_s_b(p_m, u); \ + q = __msa_xori_b((v16u8)q_m, 0x80); \ + p = __msa_xori_b((v16u8)p_m, 0x80); \ +} while (0) + +#define LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev) do { \ + v16i8 p1_m, p0_m, q0_m, q1_m; \ + v16i8 filt, t1, t2; \ + const v16i8 cnst4b = __msa_ldi_b(4); \ + const v16i8 cnst3b = __msa_ldi_b(3); \ + \ + FLIP_SIGN4(p1, p0, q0, q1, p1_m, p0_m, q0_m, q1_m); \ + filt = __msa_subs_s_b(p1_m, q1_m); \ + filt = filt & hev; \ + FILT_VAL(q0_m, p0_m, mask, filt); \ + t1 = __msa_adds_s_b(filt, cnst4b); \ + t1 = SRAI_B(t1, 3); \ + t2 = __msa_adds_s_b(filt, cnst3b); \ + t2 = SRAI_B(t2, 3); \ + q0_m = __msa_subs_s_b(q0_m, t1); \ + q0 = __msa_xori_b((v16u8)q0_m, 0x80); \ + p0_m = __msa_adds_s_b(p0_m, t2); \ + p0 = __msa_xori_b((v16u8)p0_m, 0x80); \ + filt = __msa_srari_b(t1, 1); \ + hev = __msa_xori_b(hev, 0xff); \ + filt = filt & hev; \ + q1_m = __msa_subs_s_b(q1_m, filt); \ + q1 = __msa_xori_b((v16u8)q1_m, 0x80); \ + p1_m = __msa_adds_s_b(p1_m, filt); \ + p1 = __msa_xori_b((v16u8)p1_m, 0x80); \ +} while (0) + +#define LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev) do { \ + v16i8 p2_m, p1_m, p0_m, q2_m, q1_m, q0_m; \ + v16i8 u, filt, t1, t2, filt_sign; \ + v8i16 filt_r, filt_l, u_r, u_l; \ + v8i16 temp0, temp1, temp2, temp3; \ + const v16i8 cnst4b = __msa_ldi_b(4); \ + const v16i8 cnst3b = __msa_ldi_b(3); \ + const v8i16 cnst9h = __msa_ldi_h(9); \ + const v8i16 cnst63h = __msa_ldi_h(63); \ + \ + FLIP_SIGN4(p1, p0, q0, q1, p1_m, p0_m, q0_m, q1_m); \ + filt = __msa_subs_s_b(p1_m, q1_m); \ + FILT_VAL(q0_m, p0_m, mask, filt); \ + FLIP_SIGN2(p2, q2, p2_m, q2_m); \ + t2 = filt & hev; \ + /* filt_val &= ~hev */ \ + hev = __msa_xori_b(hev, 0xff); \ + filt = filt & hev; \ + t1 = __msa_adds_s_b(t2, cnst4b); \ + t1 = SRAI_B(t1, 3); \ + t2 = __msa_adds_s_b(t2, cnst3b); \ + t2 = SRAI_B(t2, 3); \ + q0_m = __msa_subs_s_b(q0_m, t1); \ + p0_m = __msa_adds_s_b(p0_m, t2); \ + filt_sign = __msa_clti_s_b(filt, 0); \ + ILVRL_B2_SH(filt_sign, filt, filt_r, filt_l); \ + /* update q2/p2 */ \ + temp0 = filt_r * cnst9h; \ + temp1 = temp0 + cnst63h; \ + temp2 = filt_l * cnst9h; \ + temp3 = temp2 + cnst63h; \ + FILT2(q2_m, p2_m, q2, p2); \ + /* update q1/p1 */ \ + temp1 = temp1 + temp0; \ + temp3 = temp3 + temp2; \ + FILT2(q1_m, p1_m, q1, p1); \ + /* update q0/p0 */ \ + temp1 = temp1 + temp0; \ + temp3 = temp3 + temp2; \ + FILT2(q0_m, p0_m, q0, p0); \ +} while (0) + +#define LPF_MASK_HEV(p3_in, p2_in, p1_in, p0_in, \ + q0_in, q1_in, q2_in, q3_in, \ + limit_in, b_limit_in, thresh_in, \ + hev_out, mask_out) do { \ + v16u8 p3_asub_p2_m, p2_asub_p1_m, p1_asub_p0_m, q1_asub_q0_m; \ + v16u8 p1_asub_q1_m, p0_asub_q0_m, q3_asub_q2_m, q2_asub_q1_m; \ + v16u8 flat_out; \ + \ + /* absolute subtraction of pixel values */ \ + p3_asub_p2_m = __msa_asub_u_b(p3_in, p2_in); \ + p2_asub_p1_m = __msa_asub_u_b(p2_in, p1_in); \ + p1_asub_p0_m = __msa_asub_u_b(p1_in, p0_in); \ + q1_asub_q0_m = __msa_asub_u_b(q1_in, q0_in); \ + q2_asub_q1_m = __msa_asub_u_b(q2_in, q1_in); \ + q3_asub_q2_m = __msa_asub_u_b(q3_in, q2_in); \ + p0_asub_q0_m = __msa_asub_u_b(p0_in, q0_in); \ + p1_asub_q1_m = __msa_asub_u_b(p1_in, q1_in); \ + /* calculation of hev */ \ + flat_out = __msa_max_u_b(p1_asub_p0_m, q1_asub_q0_m); \ + hev_out = (thresh_in < flat_out); \ + /* calculation of mask */ \ + p0_asub_q0_m = __msa_adds_u_b(p0_asub_q0_m, p0_asub_q0_m); \ + p1_asub_q1_m = SRAI_B(p1_asub_q1_m, 1); \ + p0_asub_q0_m = __msa_adds_u_b(p0_asub_q0_m, p1_asub_q1_m); \ + mask_out = (b_limit_in < p0_asub_q0_m); \ + mask_out = __msa_max_u_b(flat_out, mask_out); \ + p3_asub_p2_m = __msa_max_u_b(p3_asub_p2_m, p2_asub_p1_m); \ + mask_out = __msa_max_u_b(p3_asub_p2_m, mask_out); \ + q2_asub_q1_m = __msa_max_u_b(q2_asub_q1_m, q3_asub_q2_m); \ + mask_out = __msa_max_u_b(q2_asub_q1_m, mask_out); \ + mask_out = (limit_in < mask_out); \ + mask_out = __msa_xori_b(mask_out, 0xff); \ +} while (0) + +#define ST6x1_UB(in0, in0_idx, in1, in1_idx, pdst, stride) do { \ + const uint16_t tmp0_h = __msa_copy_s_h((v8i16)in1, in1_idx); \ + const uint32_t tmp0_w = __msa_copy_s_w((v4i32)in0, in0_idx); \ + SW(tmp0_w, pdst); \ + SH(tmp0_h, pdst + stride); \ +} while (0) + +#define ST6x4_UB(in0, start_in0_idx, in1, start_in1_idx, pdst, stride) do { \ + uint8_t* ptmp1 = (uint8_t*)pdst; \ + ST6x1_UB(in0, start_in0_idx, in1, start_in1_idx, ptmp1, 4); \ + ptmp1 += stride; \ + ST6x1_UB(in0, start_in0_idx + 1, in1, start_in1_idx + 1, ptmp1, 4); \ + ptmp1 += stride; \ + ST6x1_UB(in0, start_in0_idx + 2, in1, start_in1_idx + 2, ptmp1, 4); \ + ptmp1 += stride; \ + ST6x1_UB(in0, start_in0_idx + 3, in1, start_in1_idx + 3, ptmp1, 4); \ +} while (0) + +#define LPF_SIMPLE_FILT(p1_in, p0_in, q0_in, q1_in, mask) do { \ + v16i8 p1_m, p0_m, q0_m, q1_m, filt, filt1, filt2; \ + const v16i8 cnst4b = __msa_ldi_b(4); \ + const v16i8 cnst3b = __msa_ldi_b(3); \ + \ + FLIP_SIGN4(p1_in, p0_in, q0_in, q1_in, p1_m, p0_m, q0_m, q1_m); \ + filt = __msa_subs_s_b(p1_m, q1_m); \ + FILT_VAL(q0_m, p0_m, mask, filt); \ + filt1 = __msa_adds_s_b(filt, cnst4b); \ + filt1 = SRAI_B(filt1, 3); \ + filt2 = __msa_adds_s_b(filt, cnst3b); \ + filt2 = SRAI_B(filt2, 3); \ + q0_m = __msa_subs_s_b(q0_m, filt1); \ + p0_m = __msa_adds_s_b(p0_m, filt2); \ + q0_in = __msa_xori_b((v16u8)q0_m, 0x80); \ + p0_in = __msa_xori_b((v16u8)p0_m, 0x80); \ +} while (0) + +#define LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask) do { \ + v16u8 p1_a_sub_q1, p0_a_sub_q0; \ + \ + p0_a_sub_q0 = __msa_asub_u_b(p0, q0); \ + p1_a_sub_q1 = __msa_asub_u_b(p1, q1); \ + p1_a_sub_q1 = (v16u8)__msa_srli_b((v16i8)p1_a_sub_q1, 1); \ + p0_a_sub_q0 = __msa_adds_u_b(p0_a_sub_q0, p0_a_sub_q0); \ + mask = __msa_adds_u_b(p0_a_sub_q0, p1_a_sub_q1); \ + mask = (mask <= b_limit); \ +} while (0) + +static void VFilter16(uint8_t* src, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint8_t* ptemp = src - 4 * stride; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0; + v16u8 mask, hev; + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + + LD_UB8(ptemp, stride, p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev); + ptemp = src - 3 * stride; + ST_UB4(p2, p1, p0, q0, ptemp, stride); + ptemp += (4 * stride); + ST_UB2(q1, q2, ptemp, stride); +} + +static void HFilter16(uint8_t* src, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint8_t* ptmp = src - 4; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0; + v16u8 mask, hev; + v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8; + v16u8 row9, row10, row11, row12, row13, row14, row15; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + + LD_UB8(ptmp, stride, row0, row1, row2, row3, row4, row5, row6, row7); + ptmp += (8 * stride); + LD_UB8(ptmp, stride, row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev); + ILVR_B2_SH(p1, p2, q0, p0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp3, tmp4); + ILVL_B2_SH(p1, p2, q0, p0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp6, tmp7); + ILVRL_B2_SH(q2, q1, tmp2, tmp5); + ptmp = src - 3; + ST6x1_UB(tmp3, 0, tmp2, 0, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp3, 1, tmp2, 1, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp3, 2, tmp2, 2, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp3, 3, tmp2, 3, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp4, 0, tmp2, 4, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp4, 1, tmp2, 5, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp4, 2, tmp2, 6, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp4, 3, tmp2, 7, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp6, 0, tmp5, 0, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp6, 1, tmp5, 1, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp6, 2, tmp5, 2, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp6, 3, tmp5, 3, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp7, 0, tmp5, 4, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp7, 1, tmp5, 5, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp7, 2, tmp5, 6, ptmp, 4); + ptmp += stride; + ST6x1_UB(tmp7, 3, tmp5, 7, ptmp, 4); +} + +// on three inner edges +static void VFilterHorEdge16i(uint8_t* src, int stride, + int b_limit, int limit, int thresh) { + v16u8 mask, hev; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0; + const v16u8 thresh0 = (v16u8)__msa_fill_b(thresh); + const v16u8 b_limit0 = (v16u8)__msa_fill_b(b_limit); + const v16u8 limit0 = (v16u8)__msa_fill_b(limit); + + LD_UB8((src - 4 * stride), stride, p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit0, b_limit0, thresh0, + hev, mask); + LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev); + ST_UB4(p1, p0, q0, q1, (src - 2 * stride), stride); +} + +static void VFilter16i(uint8_t* src_y, int stride, + int b_limit, int limit, int thresh) { + VFilterHorEdge16i(src_y + 4 * stride, stride, b_limit, limit, thresh); + VFilterHorEdge16i(src_y + 8 * stride, stride, b_limit, limit, thresh); + VFilterHorEdge16i(src_y + 12 * stride, stride, b_limit, limit, thresh); +} + +static void HFilterVertEdge16i(uint8_t* src, int stride, + int b_limit, int limit, int thresh) { + v16u8 mask, hev; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0; + v16u8 row0, row1, row2, row3, row4, row5, row6, row7; + v16u8 row8, row9, row10, row11, row12, row13, row14, row15; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + const v16u8 thresh0 = (v16u8)__msa_fill_b(thresh); + const v16u8 b_limit0 = (v16u8)__msa_fill_b(b_limit); + const v16u8 limit0 = (v16u8)__msa_fill_b(limit); + + LD_UB8(src - 4, stride, row0, row1, row2, row3, row4, row5, row6, row7); + LD_UB8(src - 4 + (8 * stride), stride, + row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit0, b_limit0, thresh0, + hev, mask); + LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev); + ILVR_B2_SH(p0, p1, q1, q0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp2, tmp3); + ILVL_B2_SH(p0, p1, q1, q0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp4, tmp5); + src -= 2; + ST4x8_UB(tmp2, tmp3, src, stride); + src += (8 * stride); + ST4x8_UB(tmp4, tmp5, src, stride); +} + +static void HFilter16i(uint8_t* src_y, int stride, + int b_limit, int limit, int thresh) { + HFilterVertEdge16i(src_y + 4, stride, b_limit, limit, thresh); + HFilterVertEdge16i(src_y + 8, stride, b_limit, limit, thresh); + HFilterVertEdge16i(src_y + 12, stride, b_limit, limit, thresh); +} + +// 8-pixels wide variants, for chroma filtering +static void VFilter8(uint8_t* src_u, uint8_t* src_v, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint8_t* ptmp_src_u = src_u - 4 * stride; + uint8_t* ptmp_src_v = src_v - 4 * stride; + uint64_t p2_d, p1_d, p0_d, q0_d, q1_d, q2_d; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; + v16u8 p3_u, p2_u, p1_u, p0_u, q3_u, q2_u, q1_u, q0_u; + v16u8 p3_v, p2_v, p1_v, p0_v, q3_v, q2_v, q1_v, q0_v; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + + LD_UB8(ptmp_src_u, stride, p3_u, p2_u, p1_u, p0_u, q0_u, q1_u, q2_u, q3_u); + LD_UB8(ptmp_src_v, stride, p3_v, p2_v, p1_v, p0_v, q0_v, q1_v, q2_v, q3_v); + ILVR_D4_UB(p3_v, p3_u, p2_v, p2_u, p1_v, p1_u, p0_v, p0_u, p3, p2, p1, p0); + ILVR_D4_UB(q0_v, q0_u, q1_v, q1_u, q2_v, q2_u, q3_v, q3_u, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev); + p2_d = __msa_copy_s_d((v2i64)p2, 0); + p1_d = __msa_copy_s_d((v2i64)p1, 0); + p0_d = __msa_copy_s_d((v2i64)p0, 0); + q0_d = __msa_copy_s_d((v2i64)q0, 0); + q1_d = __msa_copy_s_d((v2i64)q1, 0); + q2_d = __msa_copy_s_d((v2i64)q2, 0); + ptmp_src_u += stride; + SD4(p2_d, p1_d, p0_d, q0_d, ptmp_src_u, stride); + ptmp_src_u += (4 * stride); + SD(q1_d, ptmp_src_u); + ptmp_src_u += stride; + SD(q2_d, ptmp_src_u); + p2_d = __msa_copy_s_d((v2i64)p2, 1); + p1_d = __msa_copy_s_d((v2i64)p1, 1); + p0_d = __msa_copy_s_d((v2i64)p0, 1); + q0_d = __msa_copy_s_d((v2i64)q0, 1); + q1_d = __msa_copy_s_d((v2i64)q1, 1); + q2_d = __msa_copy_s_d((v2i64)q2, 1); + ptmp_src_v += stride; + SD4(p2_d, p1_d, p0_d, q0_d, ptmp_src_v, stride); + ptmp_src_v += (4 * stride); + SD(q1_d, ptmp_src_v); + ptmp_src_v += stride; + SD(q2_d, ptmp_src_v); +} + +static void HFilter8(uint8_t* src_u, uint8_t* src_v, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint8_t* ptmp_src_u = src_u - 4; + uint8_t* ptmp_src_v = src_v - 4; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; + v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8; + v16u8 row9, row10, row11, row12, row13, row14, row15; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + + LD_UB8(ptmp_src_u, stride, row0, row1, row2, row3, row4, row5, row6, row7); + LD_UB8(ptmp_src_v, stride, + row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_MBFILTER(p2, p1, p0, q0, q1, q2, mask, hev); + ILVR_B2_SH(p1, p2, q0, p0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp3, tmp4); + ILVL_B2_SH(p1, p2, q0, p0, tmp0, tmp1); + ILVRL_H2_SH(tmp1, tmp0, tmp6, tmp7); + ILVRL_B2_SH(q2, q1, tmp2, tmp5); + ptmp_src_u += 1; + ST6x4_UB(tmp3, 0, tmp2, 0, ptmp_src_u, stride); + ptmp_src_u += 4 * stride; + ST6x4_UB(tmp4, 0, tmp2, 4, ptmp_src_u, stride); + ptmp_src_v += 1; + ST6x4_UB(tmp6, 0, tmp5, 0, ptmp_src_v, stride); + ptmp_src_v += 4 * stride; + ST6x4_UB(tmp7, 0, tmp5, 4, ptmp_src_v, stride); +} + +static void VFilter8i(uint8_t* src_u, uint8_t* src_v, int stride, + int b_limit_in, int limit_in, int thresh_in) { + uint64_t p1_d, p0_d, q0_d, q1_d; + v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; + v16u8 p3_u, p2_u, p1_u, p0_u, q3_u, q2_u, q1_u, q0_u; + v16u8 p3_v, p2_v, p1_v, p0_v, q3_v, q2_v, q1_v, q0_v; + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + + LD_UB8(src_u, stride, p3_u, p2_u, p1_u, p0_u, q0_u, q1_u, q2_u, q3_u); + src_u += (5 * stride); + LD_UB8(src_v, stride, p3_v, p2_v, p1_v, p0_v, q0_v, q1_v, q2_v, q3_v); + src_v += (5 * stride); + ILVR_D4_UB(p3_v, p3_u, p2_v, p2_u, p1_v, p1_u, p0_v, p0_u, p3, p2, p1, p0); + ILVR_D4_UB(q0_v, q0_u, q1_v, q1_u, q2_v, q2_u, q3_v, q3_u, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev); + p1_d = __msa_copy_s_d((v2i64)p1, 0); + p0_d = __msa_copy_s_d((v2i64)p0, 0); + q0_d = __msa_copy_s_d((v2i64)q0, 0); + q1_d = __msa_copy_s_d((v2i64)q1, 0); + SD4(q1_d, q0_d, p0_d, p1_d, src_u, -stride); + p1_d = __msa_copy_s_d((v2i64)p1, 1); + p0_d = __msa_copy_s_d((v2i64)p0, 1); + q0_d = __msa_copy_s_d((v2i64)q0, 1); + q1_d = __msa_copy_s_d((v2i64)q1, 1); + SD4(q1_d, q0_d, p0_d, p1_d, src_v, -stride); +} + +static void HFilter8i(uint8_t* src_u, uint8_t* src_v, int stride, + int b_limit_in, int limit_in, int thresh_in) { + v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; + v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8; + v16u8 row9, row10, row11, row12, row13, row14, row15; + v4i32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + const v16u8 thresh = (v16u8)__msa_fill_b(thresh_in); + const v16u8 limit = (v16u8)__msa_fill_b(limit_in); + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + + LD_UB8(src_u, stride, row0, row1, row2, row3, row4, row5, row6, row7); + LD_UB8(src_v, stride, + row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x8_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p3, p2, p1, p0, q0, q1, q2, q3); + LPF_MASK_HEV(p3, p2, p1, p0, q0, q1, q2, q3, limit, b_limit, thresh, + hev, mask); + LPF_FILTER4_4W(p1, p0, q0, q1, mask, hev); + ILVR_B2_SW(p0, p1, q1, q0, tmp0, tmp1); + ILVRL_H2_SW(tmp1, tmp0, tmp2, tmp3); + ILVL_B2_SW(p0, p1, q1, q0, tmp0, tmp1); + ILVRL_H2_SW(tmp1, tmp0, tmp4, tmp5); + src_u += 2; + ST4x4_UB(tmp2, tmp2, 0, 1, 2, 3, src_u, stride); + src_u += 4 * stride; + ST4x4_UB(tmp3, tmp3, 0, 1, 2, 3, src_u, stride); + src_v += 2; + ST4x4_UB(tmp4, tmp4, 0, 1, 2, 3, src_v, stride); + src_v += 4 * stride; + ST4x4_UB(tmp5, tmp5, 0, 1, 2, 3, src_v, stride); +} + +static void SimpleVFilter16(uint8_t* src, int stride, int b_limit_in) { + v16u8 p1, p0, q1, q0, mask; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + + LD_UB4(src - 2 * stride, stride, p1, p0, q0, q1); + LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask); + LPF_SIMPLE_FILT(p1, p0, q0, q1, mask); + ST_UB2(p0, q0, src - stride, stride); +} + +static void SimpleHFilter16(uint8_t* src, int stride, int b_limit_in) { + v16u8 p1, p0, q1, q0, mask, row0, row1, row2, row3, row4, row5, row6, row7; + v16u8 row8, row9, row10, row11, row12, row13, row14, row15; + v8i16 tmp0, tmp1; + const v16u8 b_limit = (v16u8)__msa_fill_b(b_limit_in); + uint8_t* ptemp_src = src - 2; + + LD_UB8(ptemp_src, stride, row0, row1, row2, row3, row4, row5, row6, row7); + LD_UB8(ptemp_src + 8 * stride, stride, + row8, row9, row10, row11, row12, row13, row14, row15); + TRANSPOSE16x4_UB_UB(row0, row1, row2, row3, row4, row5, row6, row7, + row8, row9, row10, row11, row12, row13, row14, row15, + p1, p0, q0, q1); + LPF_SIMPLE_MASK(p1, p0, q0, q1, b_limit, mask); + LPF_SIMPLE_FILT(p1, p0, q0, q1, mask); + ILVRL_B2_SH(q0, p0, tmp1, tmp0); + ptemp_src += 1; + ST2x4_UB(tmp1, 0, ptemp_src, stride); + ptemp_src += 4 * stride; + ST2x4_UB(tmp1, 4, ptemp_src, stride); + ptemp_src += 4 * stride; + ST2x4_UB(tmp0, 0, ptemp_src, stride); + ptemp_src += 4 * stride; + ST2x4_UB(tmp0, 4, ptemp_src, stride); + ptemp_src += 4 * stride; +} + +static void SimpleVFilter16i(uint8_t* src_y, int stride, int b_limit_in) { + SimpleVFilter16(src_y + 4 * stride, stride, b_limit_in); + SimpleVFilter16(src_y + 8 * stride, stride, b_limit_in); + SimpleVFilter16(src_y + 12 * stride, stride, b_limit_in); +} + +static void SimpleHFilter16i(uint8_t* src_y, int stride, int b_limit_in) { + SimpleHFilter16(src_y + 4, stride, b_limit_in); + SimpleHFilter16(src_y + 8, stride, b_limit_in); + SimpleHFilter16(src_y + 12, stride, b_limit_in); +} + +//------------------------------------------------------------------------------ +// Intra predictions +//------------------------------------------------------------------------------ + +// 4x4 + +static void DC4(uint8_t* dst) { // DC + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS]; + dc >>= 3; + dc = dc | (dc << 8) | (dc << 16) | (dc << 24); + SW4(dc, dc, dc, dc, dst, BPS); +} + +static void TM4(uint8_t* dst) { + const uint8_t* const ptemp = dst - BPS - 1; + v8i16 T, d, r0, r1, r2, r3; + const v16i8 zero = { 0 }; + const v8i16 TL = (v8i16)__msa_fill_h(ptemp[0 * BPS]); + const v8i16 L0 = (v8i16)__msa_fill_h(ptemp[1 * BPS]); + const v8i16 L1 = (v8i16)__msa_fill_h(ptemp[2 * BPS]); + const v8i16 L2 = (v8i16)__msa_fill_h(ptemp[3 * BPS]); + const v8i16 L3 = (v8i16)__msa_fill_h(ptemp[4 * BPS]); + const v16u8 T1 = LD_UB(ptemp + 1); + + T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1); + d = T - TL; + ADD4(d, L0, d, L1, d, L2, d, L3, r0, r1, r2, r3); + CLIP_SH4_0_255(r0, r1, r2, r3); + PCKEV_ST4x4_UB(r0, r1, r2, r3, dst, BPS); +} + +static void VE4(uint8_t* dst) { // vertical + const uint8_t* const ptop = dst - BPS - 1; + const uint32_t val0 = LW(ptop + 0); + const uint32_t val1 = LW(ptop + 4); + uint32_t out; + v16u8 A = { 0 }, B, C, AC, B2, R; + + INSERT_W2_UB(val0, val1, A); + B = SLDI_UB(A, A, 1); + C = SLDI_UB(A, A, 2); + AC = __msa_ave_u_b(A, C); + B2 = __msa_ave_u_b(B, B); + R = __msa_aver_u_b(AC, B2); + out = __msa_copy_s_w((v4i32)R, 0); + SW4(out, out, out, out, dst, BPS); +} + +static void RD4(uint8_t* dst) { // Down-right + const uint8_t* const ptop = dst - 1 - BPS; + uint32_t val0 = LW(ptop + 0); + uint32_t val1 = LW(ptop + 4); + uint32_t val2, val3; + v16u8 A, B, C, AC, B2, R, A1 = { 0 }; + + INSERT_W2_UB(val0, val1, A1); + A = SLDI_UB(A1, A1, 12); + A = (v16u8)__msa_insert_b((v16i8)A, 3, ptop[1 * BPS]); + A = (v16u8)__msa_insert_b((v16i8)A, 2, ptop[2 * BPS]); + A = (v16u8)__msa_insert_b((v16i8)A, 1, ptop[3 * BPS]); + A = (v16u8)__msa_insert_b((v16i8)A, 0, ptop[4 * BPS]); + B = SLDI_UB(A, A, 1); + C = SLDI_UB(A, A, 2); + AC = __msa_ave_u_b(A, C); + B2 = __msa_ave_u_b(B, B); + R = __msa_aver_u_b(AC, B2); + val3 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val2 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val1 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val0 = __msa_copy_s_w((v4i32)R, 0); + SW4(val0, val1, val2, val3, dst, BPS); +} + +static void LD4(uint8_t* dst) { // Down-Left + const uint8_t* const ptop = dst - BPS; + uint32_t val0 = LW(ptop + 0); + uint32_t val1 = LW(ptop + 4); + uint32_t val2, val3; + v16u8 A = { 0 }, B, C, AC, B2, R; + + INSERT_W2_UB(val0, val1, A); + B = SLDI_UB(A, A, 1); + C = SLDI_UB(A, A, 2); + C = (v16u8)__msa_insert_b((v16i8)C, 6, ptop[7]); + AC = __msa_ave_u_b(A, C); + B2 = __msa_ave_u_b(B, B); + R = __msa_aver_u_b(AC, B2); + val0 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val1 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val2 = __msa_copy_s_w((v4i32)R, 0); + R = SLDI_UB(R, R, 1); + val3 = __msa_copy_s_w((v4i32)R, 0); + SW4(val0, val1, val2, val3, dst, BPS); +} + +// 16x16 + +static void DC16(uint8_t* dst) { // DC + uint32_t dc = 16; + int i; + const v16u8 rtop = LD_UB(dst - BPS); + const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); + v16u8 out; + + for (i = 0; i < 16; ++i) { + dc += dst[-1 + i * BPS]; + } + dc += HADD_UH_U32(dctop); + out = (v16u8)__msa_fill_b(dc >> 5); + ST_UB8(out, out, out, out, out, out, out, out, dst, BPS); + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); +} + +static void TM16(uint8_t* dst) { + int j; + v8i16 d1, d2; + const v16i8 zero = { 0 }; + const v8i16 TL = (v8i16)__msa_fill_h(dst[-1 - BPS]); + const v16i8 T = LD_SB(dst - BPS); + + ILVRL_B2_SH(zero, T, d1, d2); + SUB2(d1, TL, d2, TL, d1, d2); + for (j = 0; j < 16; j += 4) { + v16i8 t0, t1, t2, t3; + v8i16 r0, r1, r2, r3, r4, r5, r6, r7; + const v8i16 L0 = (v8i16)__msa_fill_h(dst[-1 + 0 * BPS]); + const v8i16 L1 = (v8i16)__msa_fill_h(dst[-1 + 1 * BPS]); + const v8i16 L2 = (v8i16)__msa_fill_h(dst[-1 + 2 * BPS]); + const v8i16 L3 = (v8i16)__msa_fill_h(dst[-1 + 3 * BPS]); + ADD4(d1, L0, d1, L1, d1, L2, d1, L3, r0, r1, r2, r3); + ADD4(d2, L0, d2, L1, d2, L2, d2, L3, r4, r5, r6, r7); + CLIP_SH4_0_255(r0, r1, r2, r3); + CLIP_SH4_0_255(r4, r5, r6, r7); + PCKEV_B4_SB(r4, r0, r5, r1, r6, r2, r7, r3, t0, t1, t2, t3); + ST_SB4(t0, t1, t2, t3, dst, BPS); + dst += 4 * BPS; + } +} + +static void VE16(uint8_t* dst) { // vertical + const v16u8 rtop = LD_UB(dst - BPS); + ST_UB8(rtop, rtop, rtop, rtop, rtop, rtop, rtop, rtop, dst, BPS); + ST_UB8(rtop, rtop, rtop, rtop, rtop, rtop, rtop, rtop, dst + 8 * BPS, BPS); +} + +static void HE16(uint8_t* dst) { // horizontal + int j; + for (j = 16; j > 0; j -= 4) { + const v16u8 L0 = (v16u8)__msa_fill_b(dst[-1 + 0 * BPS]); + const v16u8 L1 = (v16u8)__msa_fill_b(dst[-1 + 1 * BPS]); + const v16u8 L2 = (v16u8)__msa_fill_b(dst[-1 + 2 * BPS]); + const v16u8 L3 = (v16u8)__msa_fill_b(dst[-1 + 3 * BPS]); + ST_UB4(L0, L1, L2, L3, dst, BPS); + dst += 4 * BPS; + } +} + +static void DC16NoTop(uint8_t* dst) { // DC with top samples not available + int j; + uint32_t dc = 8; + v16u8 out; + + for (j = 0; j < 16; ++j) { + dc += dst[-1 + j * BPS]; + } + out = (v16u8)__msa_fill_b(dc >> 4); + ST_UB8(out, out, out, out, out, out, out, out, dst, BPS); + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); +} + +static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available + uint32_t dc = 8; + const v16u8 rtop = LD_UB(dst - BPS); + const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); + v16u8 out; + + dc += HADD_UH_U32(dctop); + out = (v16u8)__msa_fill_b(dc >> 4); + ST_UB8(out, out, out, out, out, out, out, out, dst, BPS); + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); +} + +static void DC16NoTopLeft(uint8_t* dst) { // DC with nothing + const v16u8 out = (v16u8)__msa_fill_b(0x80); + ST_UB8(out, out, out, out, out, out, out, out, dst, BPS); + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); +} + +// Chroma + +#define STORE8x8(out, dst) do { \ + SD4(out, out, out, out, dst + 0 * BPS, BPS); \ + SD4(out, out, out, out, dst + 4 * BPS, BPS); \ +} while (0) + +static void DC8uv(uint8_t* dst) { // DC + uint32_t dc = 8; + int i; + uint64_t out; + const v16u8 rtop = LD_UB(dst - BPS); + const v8u16 temp0 = __msa_hadd_u_h(rtop, rtop); + const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0); + const v2u64 temp2 = __msa_hadd_u_d(temp1, temp1); + v16u8 dctemp; + + for (i = 0; i < 8; ++i) { + dc += dst[-1 + i * BPS]; + } + dc += __msa_copy_s_w((v4i32)temp2, 0); + dctemp = (v16u8)__msa_fill_b(dc >> 4); + out = __msa_copy_s_d((v2i64)dctemp, 0); + STORE8x8(out, dst); +} + +static void TM8uv(uint8_t* dst) { + int j; + const v16i8 T1 = LD_SB(dst - BPS); + const v16i8 zero = { 0 }; + const v8i16 T = (v8i16)__msa_ilvr_b(zero, T1); + const v8i16 TL = (v8i16)__msa_fill_h(dst[-1 - BPS]); + const v8i16 d = T - TL; + + for (j = 0; j < 8; j += 4) { + v16i8 t0, t1; + v8i16 r0 = (v8i16)__msa_fill_h(dst[-1 + 0 * BPS]); + v8i16 r1 = (v8i16)__msa_fill_h(dst[-1 + 1 * BPS]); + v8i16 r2 = (v8i16)__msa_fill_h(dst[-1 + 2 * BPS]); + v8i16 r3 = (v8i16)__msa_fill_h(dst[-1 + 3 * BPS]); + ADD4(d, r0, d, r1, d, r2, d, r3, r0, r1, r2, r3); + CLIP_SH4_0_255(r0, r1, r2, r3); + PCKEV_B2_SB(r1, r0, r3, r2, t0, t1); + ST4x4_UB(t0, t1, 0, 2, 0, 2, dst, BPS); + ST4x4_UB(t0, t1, 1, 3, 1, 3, dst + 4, BPS); + dst += 4 * BPS; + } +} + +static void VE8uv(uint8_t* dst) { // vertical + const v16u8 rtop = LD_UB(dst - BPS); + const uint64_t out = __msa_copy_s_d((v2i64)rtop, 0); + STORE8x8(out, dst); +} + +static void HE8uv(uint8_t* dst) { // horizontal + int j; + for (j = 0; j < 8; j += 4) { + const v16u8 L0 = (v16u8)__msa_fill_b(dst[-1 + 0 * BPS]); + const v16u8 L1 = (v16u8)__msa_fill_b(dst[-1 + 1 * BPS]); + const v16u8 L2 = (v16u8)__msa_fill_b(dst[-1 + 2 * BPS]); + const v16u8 L3 = (v16u8)__msa_fill_b(dst[-1 + 3 * BPS]); + const uint64_t out0 = __msa_copy_s_d((v2i64)L0, 0); + const uint64_t out1 = __msa_copy_s_d((v2i64)L1, 0); + const uint64_t out2 = __msa_copy_s_d((v2i64)L2, 0); + const uint64_t out3 = __msa_copy_s_d((v2i64)L3, 0); + SD4(out0, out1, out2, out3, dst, BPS); + dst += 4 * BPS; + } +} + +static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples + const uint32_t dc = 4; + const v16u8 rtop = LD_UB(dst - BPS); + const v8u16 temp0 = __msa_hadd_u_h(rtop, rtop); + const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0); + const v2u64 temp2 = __msa_hadd_u_d(temp1, temp1); + const uint32_t sum_m = __msa_copy_s_w((v4i32)temp2, 0); + const v16u8 dcval = (v16u8)__msa_fill_b((dc + sum_m) >> 3); + const uint64_t out = __msa_copy_s_d((v2i64)dcval, 0); + STORE8x8(out, dst); +} + +static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples + uint32_t dc = 4; + int i; + uint64_t out; + v16u8 dctemp; + + for (i = 0; i < 8; ++i) { + dc += dst[-1 + i * BPS]; + } + dctemp = (v16u8)__msa_fill_b(dc >> 3); + out = __msa_copy_s_d((v2i64)dctemp, 0); + STORE8x8(out, dst); +} + +static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing + const uint64_t out = 0x8080808080808080ULL; + STORE8x8(out, dst); +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitMSA(void) { + VP8TransformWHT = TransformWHT; + VP8Transform = TransformTwo; + VP8TransformDC = TransformDC; + VP8TransformAC3 = TransformAC3; + + VP8VFilter16 = VFilter16; + VP8HFilter16 = HFilter16; + VP8VFilter16i = VFilter16i; + VP8HFilter16i = HFilter16i; + VP8VFilter8 = VFilter8; + VP8HFilter8 = HFilter8; + VP8VFilter8i = VFilter8i; + VP8HFilter8i = HFilter8i; + VP8SimpleVFilter16 = SimpleVFilter16; + VP8SimpleHFilter16 = SimpleHFilter16; + VP8SimpleVFilter16i = SimpleVFilter16i; + VP8SimpleHFilter16i = SimpleHFilter16i; + + VP8PredLuma4[0] = DC4; + VP8PredLuma4[1] = TM4; + VP8PredLuma4[2] = VE4; + VP8PredLuma4[4] = RD4; + VP8PredLuma4[6] = LD4; + VP8PredLuma16[0] = DC16; + VP8PredLuma16[1] = TM16; + VP8PredLuma16[2] = VE16; + VP8PredLuma16[3] = HE16; + VP8PredLuma16[4] = DC16NoTop; + VP8PredLuma16[5] = DC16NoLeft; + VP8PredLuma16[6] = DC16NoTopLeft; + VP8PredChroma8[0] = DC8uv; + VP8PredChroma8[1] = TM8uv; + VP8PredChroma8[2] = VE8uv; + VP8PredChroma8[3] = HE8uv; + VP8PredChroma8[4] = DC8uvNoTop; + VP8PredChroma8[5] = DC8uvNoLeft; + VP8PredChroma8[6] = DC8uvNoTopLeft; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8DspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/libraries/webp/src/dsp/dec_neon.c b/libraries/webp/src/dsp/dec_neon.c new file mode 100644 index 00000000000..83b3a1f970a --- /dev/null +++ b/libraries/webp/src/dsp/dec_neon.c @@ -0,0 +1,1660 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// ARM NEON version of dsp functions and loop filtering. +// +// Authors: Somnath Banerjee (somnath@google.com) +// Johann Koenig (johannkoenig@google.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include "src/dsp/neon.h" +#include "src/dec/vp8i_dec.h" + +//------------------------------------------------------------------------------ +// NxM Loading functions + +#if !defined(WORK_AROUND_GCC) + +// This intrinsics version makes gcc-4.6.3 crash during Load4x??() compilation +// (register alloc, probably). The variants somewhat mitigate the problem, but +// not quite. HFilter16i() remains problematic. +static WEBP_INLINE uint8x8x4_t Load4x8_NEON(const uint8_t* const src, + int stride) { + const uint8x8_t zero = vdup_n_u8(0); + uint8x8x4_t out; + INIT_VECTOR4(out, zero, zero, zero, zero); + out = vld4_lane_u8(src + 0 * stride, out, 0); + out = vld4_lane_u8(src + 1 * stride, out, 1); + out = vld4_lane_u8(src + 2 * stride, out, 2); + out = vld4_lane_u8(src + 3 * stride, out, 3); + out = vld4_lane_u8(src + 4 * stride, out, 4); + out = vld4_lane_u8(src + 5 * stride, out, 5); + out = vld4_lane_u8(src + 6 * stride, out, 6); + out = vld4_lane_u8(src + 7 * stride, out, 7); + return out; +} + +static WEBP_INLINE void Load4x16_NEON(const uint8_t* const src, int stride, + uint8x16_t* const p1, + uint8x16_t* const p0, + uint8x16_t* const q0, + uint8x16_t* const q1) { + // row0 = p1[0..7]|p0[0..7]|q0[0..7]|q1[0..7] + // row8 = p1[8..15]|p0[8..15]|q0[8..15]|q1[8..15] + const uint8x8x4_t row0 = Load4x8_NEON(src - 2 + 0 * stride, stride); + const uint8x8x4_t row8 = Load4x8_NEON(src - 2 + 8 * stride, stride); + *p1 = vcombine_u8(row0.val[0], row8.val[0]); + *p0 = vcombine_u8(row0.val[1], row8.val[1]); + *q0 = vcombine_u8(row0.val[2], row8.val[2]); + *q1 = vcombine_u8(row0.val[3], row8.val[3]); +} + +#else // WORK_AROUND_GCC + +#define LOADQ_LANE_32b(VALUE, LANE) do { \ + (VALUE) = vld1q_lane_u32((const uint32_t*)src, (VALUE), (LANE)); \ + src += stride; \ +} while (0) + +static WEBP_INLINE void Load4x16_NEON(const uint8_t* src, int stride, + uint8x16_t* const p1, + uint8x16_t* const p0, + uint8x16_t* const q0, + uint8x16_t* const q1) { + const uint32x4_t zero = vdupq_n_u32(0); + uint32x4x4_t in; + INIT_VECTOR4(in, zero, zero, zero, zero); + src -= 2; + LOADQ_LANE_32b(in.val[0], 0); + LOADQ_LANE_32b(in.val[1], 0); + LOADQ_LANE_32b(in.val[2], 0); + LOADQ_LANE_32b(in.val[3], 0); + LOADQ_LANE_32b(in.val[0], 1); + LOADQ_LANE_32b(in.val[1], 1); + LOADQ_LANE_32b(in.val[2], 1); + LOADQ_LANE_32b(in.val[3], 1); + LOADQ_LANE_32b(in.val[0], 2); + LOADQ_LANE_32b(in.val[1], 2); + LOADQ_LANE_32b(in.val[2], 2); + LOADQ_LANE_32b(in.val[3], 2); + LOADQ_LANE_32b(in.val[0], 3); + LOADQ_LANE_32b(in.val[1], 3); + LOADQ_LANE_32b(in.val[2], 3); + LOADQ_LANE_32b(in.val[3], 3); + // Transpose four 4x4 parts: + { + const uint8x16x2_t row01 = vtrnq_u8(vreinterpretq_u8_u32(in.val[0]), + vreinterpretq_u8_u32(in.val[1])); + const uint8x16x2_t row23 = vtrnq_u8(vreinterpretq_u8_u32(in.val[2]), + vreinterpretq_u8_u32(in.val[3])); + const uint16x8x2_t row02 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[0]), + vreinterpretq_u16_u8(row23.val[0])); + const uint16x8x2_t row13 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[1]), + vreinterpretq_u16_u8(row23.val[1])); + *p1 = vreinterpretq_u8_u16(row02.val[0]); + *p0 = vreinterpretq_u8_u16(row13.val[0]); + *q0 = vreinterpretq_u8_u16(row02.val[1]); + *q1 = vreinterpretq_u8_u16(row13.val[1]); + } +} +#undef LOADQ_LANE_32b + +#endif // !WORK_AROUND_GCC + +static WEBP_INLINE void Load8x16_NEON( + const uint8_t* const src, int stride, + uint8x16_t* const p3, uint8x16_t* const p2, uint8x16_t* const p1, + uint8x16_t* const p0, uint8x16_t* const q0, uint8x16_t* const q1, + uint8x16_t* const q2, uint8x16_t* const q3) { + Load4x16_NEON(src - 2, stride, p3, p2, p1, p0); + Load4x16_NEON(src + 2, stride, q0, q1, q2, q3); +} + +static WEBP_INLINE void Load16x4_NEON(const uint8_t* const src, int stride, + uint8x16_t* const p1, + uint8x16_t* const p0, + uint8x16_t* const q0, + uint8x16_t* const q1) { + *p1 = vld1q_u8(src - 2 * stride); + *p0 = vld1q_u8(src - 1 * stride); + *q0 = vld1q_u8(src + 0 * stride); + *q1 = vld1q_u8(src + 1 * stride); +} + +static WEBP_INLINE void Load16x8_NEON( + const uint8_t* const src, int stride, + uint8x16_t* const p3, uint8x16_t* const p2, uint8x16_t* const p1, + uint8x16_t* const p0, uint8x16_t* const q0, uint8x16_t* const q1, + uint8x16_t* const q2, uint8x16_t* const q3) { + Load16x4_NEON(src - 2 * stride, stride, p3, p2, p1, p0); + Load16x4_NEON(src + 2 * stride, stride, q0, q1, q2, q3); +} + +static WEBP_INLINE void Load8x8x2_NEON( + const uint8_t* const u, const uint8_t* const v, int stride, + uint8x16_t* const p3, uint8x16_t* const p2, uint8x16_t* const p1, + uint8x16_t* const p0, uint8x16_t* const q0, uint8x16_t* const q1, + uint8x16_t* const q2, uint8x16_t* const q3) { + // We pack the 8x8 u-samples in the lower half of the uint8x16_t destination + // and the v-samples on the higher half. + *p3 = vcombine_u8(vld1_u8(u - 4 * stride), vld1_u8(v - 4 * stride)); + *p2 = vcombine_u8(vld1_u8(u - 3 * stride), vld1_u8(v - 3 * stride)); + *p1 = vcombine_u8(vld1_u8(u - 2 * stride), vld1_u8(v - 2 * stride)); + *p0 = vcombine_u8(vld1_u8(u - 1 * stride), vld1_u8(v - 1 * stride)); + *q0 = vcombine_u8(vld1_u8(u + 0 * stride), vld1_u8(v + 0 * stride)); + *q1 = vcombine_u8(vld1_u8(u + 1 * stride), vld1_u8(v + 1 * stride)); + *q2 = vcombine_u8(vld1_u8(u + 2 * stride), vld1_u8(v + 2 * stride)); + *q3 = vcombine_u8(vld1_u8(u + 3 * stride), vld1_u8(v + 3 * stride)); +} + +#if !defined(WORK_AROUND_GCC) + +#define LOAD_UV_8(ROW) \ + vcombine_u8(vld1_u8(u - 4 + (ROW) * stride), vld1_u8(v - 4 + (ROW) * stride)) + +static WEBP_INLINE void Load8x8x2T_NEON( + const uint8_t* const u, const uint8_t* const v, int stride, + uint8x16_t* const p3, uint8x16_t* const p2, uint8x16_t* const p1, + uint8x16_t* const p0, uint8x16_t* const q0, uint8x16_t* const q1, + uint8x16_t* const q2, uint8x16_t* const q3) { + // We pack the 8x8 u-samples in the lower half of the uint8x16_t destination + // and the v-samples on the higher half. + const uint8x16_t row0 = LOAD_UV_8(0); + const uint8x16_t row1 = LOAD_UV_8(1); + const uint8x16_t row2 = LOAD_UV_8(2); + const uint8x16_t row3 = LOAD_UV_8(3); + const uint8x16_t row4 = LOAD_UV_8(4); + const uint8x16_t row5 = LOAD_UV_8(5); + const uint8x16_t row6 = LOAD_UV_8(6); + const uint8x16_t row7 = LOAD_UV_8(7); + // Perform two side-by-side 8x8 transposes + // u00 u01 u02 u03 u04 u05 u06 u07 | v00 v01 v02 v03 v04 v05 v06 v07 + // u10 u11 u12 u13 u14 u15 u16 u17 | v10 v11 v12 ... + // u20 u21 u22 u23 u24 u25 u26 u27 | v20 v21 ... + // u30 u31 u32 u33 u34 u35 u36 u37 | ... + // u40 u41 u42 u43 u44 u45 u46 u47 | ... + // u50 u51 u52 u53 u54 u55 u56 u57 | ... + // u60 u61 u62 u63 u64 u65 u66 u67 | v60 ... + // u70 u71 u72 u73 u74 u75 u76 u77 | v70 v71 v72 ... + const uint8x16x2_t row01 = vtrnq_u8(row0, row1); // u00 u10 u02 u12 ... + // u01 u11 u03 u13 ... + const uint8x16x2_t row23 = vtrnq_u8(row2, row3); // u20 u30 u22 u32 ... + // u21 u31 u23 u33 ... + const uint8x16x2_t row45 = vtrnq_u8(row4, row5); // ... + const uint8x16x2_t row67 = vtrnq_u8(row6, row7); // ... + const uint16x8x2_t row02 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[0]), + vreinterpretq_u16_u8(row23.val[0])); + const uint16x8x2_t row13 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[1]), + vreinterpretq_u16_u8(row23.val[1])); + const uint16x8x2_t row46 = vtrnq_u16(vreinterpretq_u16_u8(row45.val[0]), + vreinterpretq_u16_u8(row67.val[0])); + const uint16x8x2_t row57 = vtrnq_u16(vreinterpretq_u16_u8(row45.val[1]), + vreinterpretq_u16_u8(row67.val[1])); + const uint32x4x2_t row04 = vtrnq_u32(vreinterpretq_u32_u16(row02.val[0]), + vreinterpretq_u32_u16(row46.val[0])); + const uint32x4x2_t row26 = vtrnq_u32(vreinterpretq_u32_u16(row02.val[1]), + vreinterpretq_u32_u16(row46.val[1])); + const uint32x4x2_t row15 = vtrnq_u32(vreinterpretq_u32_u16(row13.val[0]), + vreinterpretq_u32_u16(row57.val[0])); + const uint32x4x2_t row37 = vtrnq_u32(vreinterpretq_u32_u16(row13.val[1]), + vreinterpretq_u32_u16(row57.val[1])); + *p3 = vreinterpretq_u8_u32(row04.val[0]); + *p2 = vreinterpretq_u8_u32(row15.val[0]); + *p1 = vreinterpretq_u8_u32(row26.val[0]); + *p0 = vreinterpretq_u8_u32(row37.val[0]); + *q0 = vreinterpretq_u8_u32(row04.val[1]); + *q1 = vreinterpretq_u8_u32(row15.val[1]); + *q2 = vreinterpretq_u8_u32(row26.val[1]); + *q3 = vreinterpretq_u8_u32(row37.val[1]); +} +#undef LOAD_UV_8 + +#endif // !WORK_AROUND_GCC + +static WEBP_INLINE void Store2x8_NEON(const uint8x8x2_t v, + uint8_t* const dst, int stride) { + vst2_lane_u8(dst + 0 * stride, v, 0); + vst2_lane_u8(dst + 1 * stride, v, 1); + vst2_lane_u8(dst + 2 * stride, v, 2); + vst2_lane_u8(dst + 3 * stride, v, 3); + vst2_lane_u8(dst + 4 * stride, v, 4); + vst2_lane_u8(dst + 5 * stride, v, 5); + vst2_lane_u8(dst + 6 * stride, v, 6); + vst2_lane_u8(dst + 7 * stride, v, 7); +} + +static WEBP_INLINE void Store2x16_NEON(const uint8x16_t p0, const uint8x16_t q0, + uint8_t* const dst, int stride) { + uint8x8x2_t lo, hi; + lo.val[0] = vget_low_u8(p0); + lo.val[1] = vget_low_u8(q0); + hi.val[0] = vget_high_u8(p0); + hi.val[1] = vget_high_u8(q0); + Store2x8_NEON(lo, dst - 1 + 0 * stride, stride); + Store2x8_NEON(hi, dst - 1 + 8 * stride, stride); +} + +#if !defined(WORK_AROUND_GCC) +static WEBP_INLINE void Store4x8_NEON(const uint8x8x4_t v, + uint8_t* const dst, int stride) { + vst4_lane_u8(dst + 0 * stride, v, 0); + vst4_lane_u8(dst + 1 * stride, v, 1); + vst4_lane_u8(dst + 2 * stride, v, 2); + vst4_lane_u8(dst + 3 * stride, v, 3); + vst4_lane_u8(dst + 4 * stride, v, 4); + vst4_lane_u8(dst + 5 * stride, v, 5); + vst4_lane_u8(dst + 6 * stride, v, 6); + vst4_lane_u8(dst + 7 * stride, v, 7); +} + +static WEBP_INLINE void Store4x16_NEON(const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, + uint8_t* const dst, int stride) { + uint8x8x4_t lo, hi; + INIT_VECTOR4(lo, + vget_low_u8(p1), vget_low_u8(p0), + vget_low_u8(q0), vget_low_u8(q1)); + INIT_VECTOR4(hi, + vget_high_u8(p1), vget_high_u8(p0), + vget_high_u8(q0), vget_high_u8(q1)); + Store4x8_NEON(lo, dst - 2 + 0 * stride, stride); + Store4x8_NEON(hi, dst - 2 + 8 * stride, stride); +} +#endif // !WORK_AROUND_GCC + +static WEBP_INLINE void Store16x2_NEON(const uint8x16_t p0, const uint8x16_t q0, + uint8_t* const dst, int stride) { + vst1q_u8(dst - stride, p0); + vst1q_u8(dst, q0); +} + +static WEBP_INLINE void Store16x4_NEON(const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, + uint8_t* const dst, int stride) { + Store16x2_NEON(p1, p0, dst - stride, stride); + Store16x2_NEON(q0, q1, dst + stride, stride); +} + +static WEBP_INLINE void Store8x2x2_NEON(const uint8x16_t p0, + const uint8x16_t q0, + uint8_t* const u, uint8_t* const v, + int stride) { + // p0 and q0 contain the u+v samples packed in low/high halves. + vst1_u8(u - stride, vget_low_u8(p0)); + vst1_u8(u, vget_low_u8(q0)); + vst1_u8(v - stride, vget_high_u8(p0)); + vst1_u8(v, vget_high_u8(q0)); +} + +static WEBP_INLINE void Store8x4x2_NEON(const uint8x16_t p1, + const uint8x16_t p0, + const uint8x16_t q0, + const uint8x16_t q1, + uint8_t* const u, uint8_t* const v, + int stride) { + // The p1...q1 registers contain the u+v samples packed in low/high halves. + Store8x2x2_NEON(p1, p0, u - stride, v - stride, stride); + Store8x2x2_NEON(q0, q1, u + stride, v + stride, stride); +} + +#if !defined(WORK_AROUND_GCC) + +#define STORE6_LANE(DST, VAL0, VAL1, LANE) do { \ + vst3_lane_u8((DST) - 3, (VAL0), (LANE)); \ + vst3_lane_u8((DST) + 0, (VAL1), (LANE)); \ + (DST) += stride; \ +} while (0) + +static WEBP_INLINE void Store6x8x2_NEON( + const uint8x16_t p2, const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, const uint8x16_t q2, + uint8_t* u, uint8_t* v, int stride) { + uint8x8x3_t u0, u1, v0, v1; + INIT_VECTOR3(u0, vget_low_u8(p2), vget_low_u8(p1), vget_low_u8(p0)); + INIT_VECTOR3(u1, vget_low_u8(q0), vget_low_u8(q1), vget_low_u8(q2)); + INIT_VECTOR3(v0, vget_high_u8(p2), vget_high_u8(p1), vget_high_u8(p0)); + INIT_VECTOR3(v1, vget_high_u8(q0), vget_high_u8(q1), vget_high_u8(q2)); + STORE6_LANE(u, u0, u1, 0); + STORE6_LANE(u, u0, u1, 1); + STORE6_LANE(u, u0, u1, 2); + STORE6_LANE(u, u0, u1, 3); + STORE6_LANE(u, u0, u1, 4); + STORE6_LANE(u, u0, u1, 5); + STORE6_LANE(u, u0, u1, 6); + STORE6_LANE(u, u0, u1, 7); + STORE6_LANE(v, v0, v1, 0); + STORE6_LANE(v, v0, v1, 1); + STORE6_LANE(v, v0, v1, 2); + STORE6_LANE(v, v0, v1, 3); + STORE6_LANE(v, v0, v1, 4); + STORE6_LANE(v, v0, v1, 5); + STORE6_LANE(v, v0, v1, 6); + STORE6_LANE(v, v0, v1, 7); +} +#undef STORE6_LANE + +static WEBP_INLINE void Store4x8x2_NEON(const uint8x16_t p1, + const uint8x16_t p0, + const uint8x16_t q0, + const uint8x16_t q1, + uint8_t* const u, uint8_t* const v, + int stride) { + uint8x8x4_t u0, v0; + INIT_VECTOR4(u0, + vget_low_u8(p1), vget_low_u8(p0), + vget_low_u8(q0), vget_low_u8(q1)); + INIT_VECTOR4(v0, + vget_high_u8(p1), vget_high_u8(p0), + vget_high_u8(q0), vget_high_u8(q1)); + vst4_lane_u8(u - 2 + 0 * stride, u0, 0); + vst4_lane_u8(u - 2 + 1 * stride, u0, 1); + vst4_lane_u8(u - 2 + 2 * stride, u0, 2); + vst4_lane_u8(u - 2 + 3 * stride, u0, 3); + vst4_lane_u8(u - 2 + 4 * stride, u0, 4); + vst4_lane_u8(u - 2 + 5 * stride, u0, 5); + vst4_lane_u8(u - 2 + 6 * stride, u0, 6); + vst4_lane_u8(u - 2 + 7 * stride, u0, 7); + vst4_lane_u8(v - 2 + 0 * stride, v0, 0); + vst4_lane_u8(v - 2 + 1 * stride, v0, 1); + vst4_lane_u8(v - 2 + 2 * stride, v0, 2); + vst4_lane_u8(v - 2 + 3 * stride, v0, 3); + vst4_lane_u8(v - 2 + 4 * stride, v0, 4); + vst4_lane_u8(v - 2 + 5 * stride, v0, 5); + vst4_lane_u8(v - 2 + 6 * stride, v0, 6); + vst4_lane_u8(v - 2 + 7 * stride, v0, 7); +} + +#endif // !WORK_AROUND_GCC + +// Zero extend 'v' to an int16x8_t. +static WEBP_INLINE int16x8_t ConvertU8ToS16_NEON(uint8x8_t v) { + return vreinterpretq_s16_u16(vmovl_u8(v)); +} + +// Performs unsigned 8b saturation on 'dst01' and 'dst23' storing the result +// to the corresponding rows of 'dst'. +static WEBP_INLINE void SaturateAndStore4x4_NEON(uint8_t* const dst, + const int16x8_t dst01, + const int16x8_t dst23) { + // Unsigned saturate to 8b. + const uint8x8_t dst01_u8 = vqmovun_s16(dst01); + const uint8x8_t dst23_u8 = vqmovun_s16(dst23); + + // Store the results. + vst1_lane_u32((uint32_t*)(dst + 0 * BPS), vreinterpret_u32_u8(dst01_u8), 0); + vst1_lane_u32((uint32_t*)(dst + 1 * BPS), vreinterpret_u32_u8(dst01_u8), 1); + vst1_lane_u32((uint32_t*)(dst + 2 * BPS), vreinterpret_u32_u8(dst23_u8), 0); + vst1_lane_u32((uint32_t*)(dst + 3 * BPS), vreinterpret_u32_u8(dst23_u8), 1); +} + +static WEBP_INLINE void Add4x4_NEON(const int16x8_t row01, + const int16x8_t row23, + uint8_t* const dst) { + uint32x2_t dst01 = vdup_n_u32(0); + uint32x2_t dst23 = vdup_n_u32(0); + + // Load the source pixels. + dst01 = vld1_lane_u32((uint32_t*)(dst + 0 * BPS), dst01, 0); + dst23 = vld1_lane_u32((uint32_t*)(dst + 2 * BPS), dst23, 0); + dst01 = vld1_lane_u32((uint32_t*)(dst + 1 * BPS), dst01, 1); + dst23 = vld1_lane_u32((uint32_t*)(dst + 3 * BPS), dst23, 1); + + { + // Convert to 16b. + const int16x8_t dst01_s16 = ConvertU8ToS16_NEON(vreinterpret_u8_u32(dst01)); + const int16x8_t dst23_s16 = ConvertU8ToS16_NEON(vreinterpret_u8_u32(dst23)); + + // Descale with rounding. + const int16x8_t out01 = vrsraq_n_s16(dst01_s16, row01, 3); + const int16x8_t out23 = vrsraq_n_s16(dst23_s16, row23, 3); + // Add the inverse transform. + SaturateAndStore4x4_NEON(dst, out01, out23); + } +} + +//----------------------------------------------------------------------------- +// Simple In-loop filtering (Paragraph 15.2) + +static uint8x16_t NeedsFilter_NEON(const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, + int thresh) { + const uint8x16_t thresh_v = vdupq_n_u8((uint8_t)thresh); + const uint8x16_t a_p0_q0 = vabdq_u8(p0, q0); // abs(p0-q0) + const uint8x16_t a_p1_q1 = vabdq_u8(p1, q1); // abs(p1-q1) + const uint8x16_t a_p0_q0_2 = vqaddq_u8(a_p0_q0, a_p0_q0); // 2 * abs(p0-q0) + const uint8x16_t a_p1_q1_2 = vshrq_n_u8(a_p1_q1, 1); // abs(p1-q1) / 2 + const uint8x16_t sum = vqaddq_u8(a_p0_q0_2, a_p1_q1_2); + const uint8x16_t mask = vcgeq_u8(thresh_v, sum); + return mask; +} + +static int8x16_t FlipSign_NEON(const uint8x16_t v) { + const uint8x16_t sign_bit = vdupq_n_u8(0x80); + return vreinterpretq_s8_u8(veorq_u8(v, sign_bit)); +} + +static uint8x16_t FlipSignBack_NEON(const int8x16_t v) { + const int8x16_t sign_bit = vdupq_n_s8(0x80); + return vreinterpretq_u8_s8(veorq_s8(v, sign_bit)); +} + +static int8x16_t GetBaseDelta_NEON(const int8x16_t p1, const int8x16_t p0, + const int8x16_t q0, const int8x16_t q1) { + const int8x16_t q0_p0 = vqsubq_s8(q0, p0); // (q0-p0) + const int8x16_t p1_q1 = vqsubq_s8(p1, q1); // (p1-q1) + const int8x16_t s1 = vqaddq_s8(p1_q1, q0_p0); // (p1-q1) + 1 * (q0 - p0) + const int8x16_t s2 = vqaddq_s8(q0_p0, s1); // (p1-q1) + 2 * (q0 - p0) + const int8x16_t s3 = vqaddq_s8(q0_p0, s2); // (p1-q1) + 3 * (q0 - p0) + return s3; +} + +static int8x16_t GetBaseDelta0_NEON(const int8x16_t p0, const int8x16_t q0) { + const int8x16_t q0_p0 = vqsubq_s8(q0, p0); // (q0-p0) + const int8x16_t s1 = vqaddq_s8(q0_p0, q0_p0); // 2 * (q0 - p0) + const int8x16_t s2 = vqaddq_s8(q0_p0, s1); // 3 * (q0 - p0) + return s2; +} + +//------------------------------------------------------------------------------ + +static void ApplyFilter2NoFlip_NEON(const int8x16_t p0s, const int8x16_t q0s, + const int8x16_t delta, + int8x16_t* const op0, + int8x16_t* const oq0) { + const int8x16_t kCst3 = vdupq_n_s8(0x03); + const int8x16_t kCst4 = vdupq_n_s8(0x04); + const int8x16_t delta_p3 = vqaddq_s8(delta, kCst3); + const int8x16_t delta_p4 = vqaddq_s8(delta, kCst4); + const int8x16_t delta3 = vshrq_n_s8(delta_p3, 3); + const int8x16_t delta4 = vshrq_n_s8(delta_p4, 3); + *op0 = vqaddq_s8(p0s, delta3); + *oq0 = vqsubq_s8(q0s, delta4); +} + +#if defined(WEBP_USE_INTRINSICS) + +static void ApplyFilter2_NEON(const int8x16_t p0s, const int8x16_t q0s, + const int8x16_t delta, + uint8x16_t* const op0, uint8x16_t* const oq0) { + const int8x16_t kCst3 = vdupq_n_s8(0x03); + const int8x16_t kCst4 = vdupq_n_s8(0x04); + const int8x16_t delta_p3 = vqaddq_s8(delta, kCst3); + const int8x16_t delta_p4 = vqaddq_s8(delta, kCst4); + const int8x16_t delta3 = vshrq_n_s8(delta_p3, 3); + const int8x16_t delta4 = vshrq_n_s8(delta_p4, 3); + const int8x16_t sp0 = vqaddq_s8(p0s, delta3); + const int8x16_t sq0 = vqsubq_s8(q0s, delta4); + *op0 = FlipSignBack_NEON(sp0); + *oq0 = FlipSignBack_NEON(sq0); +} + +static void DoFilter2_NEON(const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, + const uint8x16_t mask, + uint8x16_t* const op0, uint8x16_t* const oq0) { + const int8x16_t p1s = FlipSign_NEON(p1); + const int8x16_t p0s = FlipSign_NEON(p0); + const int8x16_t q0s = FlipSign_NEON(q0); + const int8x16_t q1s = FlipSign_NEON(q1); + const int8x16_t delta0 = GetBaseDelta_NEON(p1s, p0s, q0s, q1s); + const int8x16_t delta1 = vandq_s8(delta0, vreinterpretq_s8_u8(mask)); + ApplyFilter2_NEON(p0s, q0s, delta1, op0, oq0); +} + +static void SimpleVFilter16_NEON(uint8_t* p, int stride, int thresh) { + uint8x16_t p1, p0, q0, q1, op0, oq0; + Load16x4_NEON(p, stride, &p1, &p0, &q0, &q1); + { + const uint8x16_t mask = NeedsFilter_NEON(p1, p0, q0, q1, thresh); + DoFilter2_NEON(p1, p0, q0, q1, mask, &op0, &oq0); + } + Store16x2_NEON(op0, oq0, p, stride); +} + +static void SimpleHFilter16_NEON(uint8_t* p, int stride, int thresh) { + uint8x16_t p1, p0, q0, q1, oq0, op0; + Load4x16_NEON(p, stride, &p1, &p0, &q0, &q1); + { + const uint8x16_t mask = NeedsFilter_NEON(p1, p0, q0, q1, thresh); + DoFilter2_NEON(p1, p0, q0, q1, mask, &op0, &oq0); + } + Store2x16_NEON(op0, oq0, p, stride); +} + +#else + +// Load/Store vertical edge +#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \ + "vld4.8 {" #c1 "[0]," #c2 "[0]," #c3 "[0]," #c4 "[0]}," #b1 "," #stride "\n" \ + "vld4.8 {" #c1 "[1]," #c2 "[1]," #c3 "[1]," #c4 "[1]}," #b2 "," #stride "\n" \ + "vld4.8 {" #c1 "[2]," #c2 "[2]," #c3 "[2]," #c4 "[2]}," #b1 "," #stride "\n" \ + "vld4.8 {" #c1 "[3]," #c2 "[3]," #c3 "[3]," #c4 "[3]}," #b2 "," #stride "\n" \ + "vld4.8 {" #c1 "[4]," #c2 "[4]," #c3 "[4]," #c4 "[4]}," #b1 "," #stride "\n" \ + "vld4.8 {" #c1 "[5]," #c2 "[5]," #c3 "[5]," #c4 "[5]}," #b2 "," #stride "\n" \ + "vld4.8 {" #c1 "[6]," #c2 "[6]," #c3 "[6]," #c4 "[6]}," #b1 "," #stride "\n" \ + "vld4.8 {" #c1 "[7]," #c2 "[7]," #c3 "[7]," #c4 "[7]}," #b2 "," #stride "\n" + +#define STORE8x2(c1, c2, p, stride) \ + "vst2.8 {" #c1 "[0], " #c2 "[0]}," #p "," #stride " \n" \ + "vst2.8 {" #c1 "[1], " #c2 "[1]}," #p "," #stride " \n" \ + "vst2.8 {" #c1 "[2], " #c2 "[2]}," #p "," #stride " \n" \ + "vst2.8 {" #c1 "[3], " #c2 "[3]}," #p "," #stride " \n" \ + "vst2.8 {" #c1 "[4], " #c2 "[4]}," #p "," #stride " \n" \ + "vst2.8 {" #c1 "[5], " #c2 "[5]}," #p "," #stride " \n" \ + "vst2.8 {" #c1 "[6], " #c2 "[6]}," #p "," #stride " \n" \ + "vst2.8 {" #c1 "[7], " #c2 "[7]}," #p "," #stride " \n" + +#define QRegs "q0", "q1", "q2", "q3", \ + "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" + +#define FLIP_SIGN_BIT2(a, b, s) \ + "veor " #a "," #a "," #s " \n" \ + "veor " #b "," #b "," #s " \n" \ + +#define FLIP_SIGN_BIT4(a, b, c, d, s) \ + FLIP_SIGN_BIT2(a, b, s) \ + FLIP_SIGN_BIT2(c, d, s) \ + +#define NEEDS_FILTER(p1, p0, q0, q1, thresh, mask) \ + "vabd.u8 q15," #p0 "," #q0 " \n" /* abs(p0 - q0) */ \ + "vabd.u8 q14," #p1 "," #q1 " \n" /* abs(p1 - q1) */ \ + "vqadd.u8 q15, q15, q15 \n" /* abs(p0 - q0) * 2 */ \ + "vshr.u8 q14, q14, #1 \n" /* abs(p1 - q1) / 2 */ \ + "vqadd.u8 q15, q15, q14 \n" /* abs(p0 - q0) * 2 + abs(p1 - q1) / 2 */ \ + "vdup.8 q14, " #thresh " \n" \ + "vcge.u8 " #mask ", q14, q15 \n" /* mask <= thresh */ + +#define GET_BASE_DELTA(p1, p0, q0, q1, o) \ + "vqsub.s8 q15," #q0 "," #p0 " \n" /* (q0 - p0) */ \ + "vqsub.s8 " #o "," #p1 "," #q1 " \n" /* (p1 - q1) */ \ + "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 1 * (p0 - q0) */ \ + "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 2 * (p0 - q0) */ \ + "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 3 * (p0 - q0) */ + +#define DO_SIMPLE_FILTER(p0, q0, fl) \ + "vmov.i8 q15, #0x03 \n" \ + "vqadd.s8 q15, q15, " #fl " \n" /* filter1 = filter + 3 */ \ + "vshr.s8 q15, q15, #3 \n" /* filter1 >> 3 */ \ + "vqadd.s8 " #p0 "," #p0 ", q15 \n" /* p0 += filter1 */ \ + \ + "vmov.i8 q15, #0x04 \n" \ + "vqadd.s8 q15, q15, " #fl " \n" /* filter1 = filter + 4 */ \ + "vshr.s8 q15, q15, #3 \n" /* filter2 >> 3 */ \ + "vqsub.s8 " #q0 "," #q0 ", q15 \n" /* q0 -= filter2 */ + +// Applies filter on 2 pixels (p0 and q0) +#define DO_FILTER2(p1, p0, q0, q1, thresh) \ + NEEDS_FILTER(p1, p0, q0, q1, thresh, q9) /* filter mask in q9 */ \ + "vmov.i8 q10, #0x80 \n" /* sign bit */ \ + FLIP_SIGN_BIT4(p1, p0, q0, q1, q10) /* convert to signed value */ \ + GET_BASE_DELTA(p1, p0, q0, q1, q11) /* get filter level */ \ + "vand q9, q9, q11 \n" /* apply filter mask */ \ + DO_SIMPLE_FILTER(p0, q0, q9) /* apply filter */ \ + FLIP_SIGN_BIT2(p0, q0, q10) + +static void SimpleVFilter16_NEON(uint8_t* p, int stride, int thresh) { + __asm__ volatile ( + "sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride + + "vld1.u8 {q1}, [%[p]], %[stride] \n" // p1 + "vld1.u8 {q2}, [%[p]], %[stride] \n" // p0 + "vld1.u8 {q3}, [%[p]], %[stride] \n" // q0 + "vld1.u8 {q12}, [%[p]] \n" // q1 + + DO_FILTER2(q1, q2, q3, q12, %[thresh]) + + "sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride + + "vst1.u8 {q2}, [%[p]], %[stride] \n" // store op0 + "vst1.u8 {q3}, [%[p]] \n" // store oq0 + : [p] "+r"(p) + : [stride] "r"(stride), [thresh] "r"(thresh) + : "memory", QRegs + ); +} + +static void SimpleHFilter16_NEON(uint8_t* p, int stride, int thresh) { + __asm__ volatile ( + "sub r4, %[p], #2 \n" // base1 = p - 2 + "lsl r6, %[stride], #1 \n" // r6 = 2 * stride + "add r5, r4, %[stride] \n" // base2 = base1 + stride + + LOAD8x4(d2, d3, d4, d5, [r4], [r5], r6) + LOAD8x4(d24, d25, d26, d27, [r4], [r5], r6) + "vswp d3, d24 \n" // p1:q1 p0:q3 + "vswp d5, d26 \n" // q0:q2 q1:q4 + "vswp q2, q12 \n" // p1:q1 p0:q2 q0:q3 q1:q4 + + DO_FILTER2(q1, q2, q12, q13, %[thresh]) + + "sub %[p], %[p], #1 \n" // p - 1 + + "vswp d5, d24 \n" + STORE8x2(d4, d5, [%[p]], %[stride]) + STORE8x2(d24, d25, [%[p]], %[stride]) + + : [p] "+r"(p) + : [stride] "r"(stride), [thresh] "r"(thresh) + : "memory", "r4", "r5", "r6", QRegs + ); +} + +#undef LOAD8x4 +#undef STORE8x2 + +#endif // WEBP_USE_INTRINSICS + +static void SimpleVFilter16i_NEON(uint8_t* p, int stride, int thresh) { + uint32_t k; + for (k = 3; k != 0; --k) { + p += 4 * stride; + SimpleVFilter16_NEON(p, stride, thresh); + } +} + +static void SimpleHFilter16i_NEON(uint8_t* p, int stride, int thresh) { + uint32_t k; + for (k = 3; k != 0; --k) { + p += 4; + SimpleHFilter16_NEON(p, stride, thresh); + } +} + +//------------------------------------------------------------------------------ +// Complex In-loop filtering (Paragraph 15.3) + +static uint8x16_t NeedsHev_NEON(const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, + int hev_thresh) { + const uint8x16_t hev_thresh_v = vdupq_n_u8((uint8_t)hev_thresh); + const uint8x16_t a_p1_p0 = vabdq_u8(p1, p0); // abs(p1 - p0) + const uint8x16_t a_q1_q0 = vabdq_u8(q1, q0); // abs(q1 - q0) + const uint8x16_t a_max = vmaxq_u8(a_p1_p0, a_q1_q0); + const uint8x16_t mask = vcgtq_u8(a_max, hev_thresh_v); + return mask; +} + +static uint8x16_t NeedsFilter2_NEON(const uint8x16_t p3, const uint8x16_t p2, + const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, + const uint8x16_t q2, const uint8x16_t q3, + int ithresh, int thresh) { + const uint8x16_t ithresh_v = vdupq_n_u8((uint8_t)ithresh); + const uint8x16_t a_p3_p2 = vabdq_u8(p3, p2); // abs(p3 - p2) + const uint8x16_t a_p2_p1 = vabdq_u8(p2, p1); // abs(p2 - p1) + const uint8x16_t a_p1_p0 = vabdq_u8(p1, p0); // abs(p1 - p0) + const uint8x16_t a_q3_q2 = vabdq_u8(q3, q2); // abs(q3 - q2) + const uint8x16_t a_q2_q1 = vabdq_u8(q2, q1); // abs(q2 - q1) + const uint8x16_t a_q1_q0 = vabdq_u8(q1, q0); // abs(q1 - q0) + const uint8x16_t max1 = vmaxq_u8(a_p3_p2, a_p2_p1); + const uint8x16_t max2 = vmaxq_u8(a_p1_p0, a_q3_q2); + const uint8x16_t max3 = vmaxq_u8(a_q2_q1, a_q1_q0); + const uint8x16_t max12 = vmaxq_u8(max1, max2); + const uint8x16_t max123 = vmaxq_u8(max12, max3); + const uint8x16_t mask2 = vcgeq_u8(ithresh_v, max123); + const uint8x16_t mask1 = NeedsFilter_NEON(p1, p0, q0, q1, thresh); + const uint8x16_t mask = vandq_u8(mask1, mask2); + return mask; +} + +// 4-points filter + +static void ApplyFilter4_NEON( + const int8x16_t p1, const int8x16_t p0, + const int8x16_t q0, const int8x16_t q1, + const int8x16_t delta0, + uint8x16_t* const op1, uint8x16_t* const op0, + uint8x16_t* const oq0, uint8x16_t* const oq1) { + const int8x16_t kCst3 = vdupq_n_s8(0x03); + const int8x16_t kCst4 = vdupq_n_s8(0x04); + const int8x16_t delta1 = vqaddq_s8(delta0, kCst4); + const int8x16_t delta2 = vqaddq_s8(delta0, kCst3); + const int8x16_t a1 = vshrq_n_s8(delta1, 3); + const int8x16_t a2 = vshrq_n_s8(delta2, 3); + const int8x16_t a3 = vrshrq_n_s8(a1, 1); // a3 = (a1 + 1) >> 1 + *op0 = FlipSignBack_NEON(vqaddq_s8(p0, a2)); // clip(p0 + a2) + *oq0 = FlipSignBack_NEON(vqsubq_s8(q0, a1)); // clip(q0 - a1) + *op1 = FlipSignBack_NEON(vqaddq_s8(p1, a3)); // clip(p1 + a3) + *oq1 = FlipSignBack_NEON(vqsubq_s8(q1, a3)); // clip(q1 - a3) +} + +static void DoFilter4_NEON( + const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, + const uint8x16_t mask, const uint8x16_t hev_mask, + uint8x16_t* const op1, uint8x16_t* const op0, + uint8x16_t* const oq0, uint8x16_t* const oq1) { + // This is a fused version of DoFilter2() calling ApplyFilter2 directly + const int8x16_t p1s = FlipSign_NEON(p1); + int8x16_t p0s = FlipSign_NEON(p0); + int8x16_t q0s = FlipSign_NEON(q0); + const int8x16_t q1s = FlipSign_NEON(q1); + const uint8x16_t simple_lf_mask = vandq_u8(mask, hev_mask); + + // do_filter2 part (simple loopfilter on pixels with hev) + { + const int8x16_t delta = GetBaseDelta_NEON(p1s, p0s, q0s, q1s); + const int8x16_t simple_lf_delta = + vandq_s8(delta, vreinterpretq_s8_u8(simple_lf_mask)); + ApplyFilter2NoFlip_NEON(p0s, q0s, simple_lf_delta, &p0s, &q0s); + } + + // do_filter4 part (complex loopfilter on pixels without hev) + { + const int8x16_t delta0 = GetBaseDelta0_NEON(p0s, q0s); + // we use: (mask & hev_mask) ^ mask = mask & !hev_mask + const uint8x16_t complex_lf_mask = veorq_u8(simple_lf_mask, mask); + const int8x16_t complex_lf_delta = + vandq_s8(delta0, vreinterpretq_s8_u8(complex_lf_mask)); + ApplyFilter4_NEON(p1s, p0s, q0s, q1s, complex_lf_delta, op1, op0, oq0, oq1); + } +} + +// 6-points filter + +static void ApplyFilter6_NEON( + const int8x16_t p2, const int8x16_t p1, const int8x16_t p0, + const int8x16_t q0, const int8x16_t q1, const int8x16_t q2, + const int8x16_t delta, + uint8x16_t* const op2, uint8x16_t* const op1, uint8x16_t* const op0, + uint8x16_t* const oq0, uint8x16_t* const oq1, uint8x16_t* const oq2) { + // We have to compute: X = (9*a+63) >> 7, Y = (18*a+63)>>7, Z = (27*a+63) >> 7 + // Turns out, there's a common sub-expression S=9 * a - 1 that can be used + // with the special vqrshrn_n_s16 rounding-shift-and-narrow instruction: + // X = (S + 64) >> 7, Y = (S + 32) >> 6, Z = (18 * a + S + 64) >> 7 + const int8x8_t delta_lo = vget_low_s8(delta); + const int8x8_t delta_hi = vget_high_s8(delta); + const int8x8_t kCst9 = vdup_n_s8(9); + const int16x8_t kCstm1 = vdupq_n_s16(-1); + const int8x8_t kCst18 = vdup_n_s8(18); + const int16x8_t S_lo = vmlal_s8(kCstm1, kCst9, delta_lo); // S = 9 * a - 1 + const int16x8_t S_hi = vmlal_s8(kCstm1, kCst9, delta_hi); + const int16x8_t Z_lo = vmlal_s8(S_lo, kCst18, delta_lo); // S + 18 * a + const int16x8_t Z_hi = vmlal_s8(S_hi, kCst18, delta_hi); + const int8x8_t a3_lo = vqrshrn_n_s16(S_lo, 7); // (9 * a + 63) >> 7 + const int8x8_t a3_hi = vqrshrn_n_s16(S_hi, 7); + const int8x8_t a2_lo = vqrshrn_n_s16(S_lo, 6); // (9 * a + 31) >> 6 + const int8x8_t a2_hi = vqrshrn_n_s16(S_hi, 6); + const int8x8_t a1_lo = vqrshrn_n_s16(Z_lo, 7); // (27 * a + 63) >> 7 + const int8x8_t a1_hi = vqrshrn_n_s16(Z_hi, 7); + const int8x16_t a1 = vcombine_s8(a1_lo, a1_hi); + const int8x16_t a2 = vcombine_s8(a2_lo, a2_hi); + const int8x16_t a3 = vcombine_s8(a3_lo, a3_hi); + + *op0 = FlipSignBack_NEON(vqaddq_s8(p0, a1)); // clip(p0 + a1) + *oq0 = FlipSignBack_NEON(vqsubq_s8(q0, a1)); // clip(q0 - q1) + *oq1 = FlipSignBack_NEON(vqsubq_s8(q1, a2)); // clip(q1 - a2) + *op1 = FlipSignBack_NEON(vqaddq_s8(p1, a2)); // clip(p1 + a2) + *oq2 = FlipSignBack_NEON(vqsubq_s8(q2, a3)); // clip(q2 - a3) + *op2 = FlipSignBack_NEON(vqaddq_s8(p2, a3)); // clip(p2 + a3) +} + +static void DoFilter6_NEON( + const uint8x16_t p2, const uint8x16_t p1, const uint8x16_t p0, + const uint8x16_t q0, const uint8x16_t q1, const uint8x16_t q2, + const uint8x16_t mask, const uint8x16_t hev_mask, + uint8x16_t* const op2, uint8x16_t* const op1, uint8x16_t* const op0, + uint8x16_t* const oq0, uint8x16_t* const oq1, uint8x16_t* const oq2) { + // This is a fused version of DoFilter2() calling ApplyFilter2 directly + const int8x16_t p2s = FlipSign_NEON(p2); + const int8x16_t p1s = FlipSign_NEON(p1); + int8x16_t p0s = FlipSign_NEON(p0); + int8x16_t q0s = FlipSign_NEON(q0); + const int8x16_t q1s = FlipSign_NEON(q1); + const int8x16_t q2s = FlipSign_NEON(q2); + const uint8x16_t simple_lf_mask = vandq_u8(mask, hev_mask); + const int8x16_t delta0 = GetBaseDelta_NEON(p1s, p0s, q0s, q1s); + + // do_filter2 part (simple loopfilter on pixels with hev) + { + const int8x16_t simple_lf_delta = + vandq_s8(delta0, vreinterpretq_s8_u8(simple_lf_mask)); + ApplyFilter2NoFlip_NEON(p0s, q0s, simple_lf_delta, &p0s, &q0s); + } + + // do_filter6 part (complex loopfilter on pixels without hev) + { + // we use: (mask & hev_mask) ^ mask = mask & !hev_mask + const uint8x16_t complex_lf_mask = veorq_u8(simple_lf_mask, mask); + const int8x16_t complex_lf_delta = + vandq_s8(delta0, vreinterpretq_s8_u8(complex_lf_mask)); + ApplyFilter6_NEON(p2s, p1s, p0s, q0s, q1s, q2s, complex_lf_delta, + op2, op1, op0, oq0, oq1, oq2); + } +} + +// on macroblock edges + +static void VFilter16_NEON(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; + Load16x8_NEON(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3); + { + const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, + ithresh, thresh); + const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh); + uint8x16_t op2, op1, op0, oq0, oq1, oq2; + DoFilter6_NEON(p2, p1, p0, q0, q1, q2, mask, hev_mask, + &op2, &op1, &op0, &oq0, &oq1, &oq2); + Store16x2_NEON(op2, op1, p - 2 * stride, stride); + Store16x2_NEON(op0, oq0, p + 0 * stride, stride); + Store16x2_NEON(oq1, oq2, p + 2 * stride, stride); + } +} + +static void HFilter16_NEON(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; + Load8x16_NEON(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3); + { + const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, + ithresh, thresh); + const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh); + uint8x16_t op2, op1, op0, oq0, oq1, oq2; + DoFilter6_NEON(p2, p1, p0, q0, q1, q2, mask, hev_mask, + &op2, &op1, &op0, &oq0, &oq1, &oq2); + Store2x16_NEON(op2, op1, p - 2, stride); + Store2x16_NEON(op0, oq0, p + 0, stride); + Store2x16_NEON(oq1, oq2, p + 2, stride); + } +} + +// on three inner edges +static void VFilter16i_NEON(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + uint32_t k; + uint8x16_t p3, p2, p1, p0; + Load16x4_NEON(p + 2 * stride, stride, &p3, &p2, &p1, &p0); + for (k = 3; k != 0; --k) { + uint8x16_t q0, q1, q2, q3; + p += 4 * stride; + Load16x4_NEON(p + 2 * stride, stride, &q0, &q1, &q2, &q3); + { + const uint8x16_t mask = + NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh); + const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh); + // p3 and p2 are not just temporary variables here: they will be + // re-used for next span. And q2/q3 will become p1/p0 accordingly. + DoFilter4_NEON(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2); + Store16x4_NEON(p1, p0, p3, p2, p, stride); + p1 = q2; + p0 = q3; + } + } +} + +#if !defined(WORK_AROUND_GCC) +static void HFilter16i_NEON(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + uint32_t k; + uint8x16_t p3, p2, p1, p0; + Load4x16_NEON(p + 2, stride, &p3, &p2, &p1, &p0); + for (k = 3; k != 0; --k) { + uint8x16_t q0, q1, q2, q3; + p += 4; + Load4x16_NEON(p + 2, stride, &q0, &q1, &q2, &q3); + { + const uint8x16_t mask = + NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh); + const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh); + DoFilter4_NEON(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2); + Store4x16_NEON(p1, p0, p3, p2, p, stride); + p1 = q2; + p0 = q3; + } + } +} +#endif // !WORK_AROUND_GCC + +// 8-pixels wide variant, for chroma filtering +static void VFilter8_NEON(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; + Load8x8x2_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3); + { + const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, + ithresh, thresh); + const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh); + uint8x16_t op2, op1, op0, oq0, oq1, oq2; + DoFilter6_NEON(p2, p1, p0, q0, q1, q2, mask, hev_mask, + &op2, &op1, &op0, &oq0, &oq1, &oq2); + Store8x2x2_NEON(op2, op1, u - 2 * stride, v - 2 * stride, stride); + Store8x2x2_NEON(op0, oq0, u + 0 * stride, v + 0 * stride, stride); + Store8x2x2_NEON(oq1, oq2, u + 2 * stride, v + 2 * stride, stride); + } +} +static void VFilter8i_NEON(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; + u += 4 * stride; + v += 4 * stride; + Load8x8x2_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3); + { + const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, + ithresh, thresh); + const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh); + uint8x16_t op1, op0, oq0, oq1; + DoFilter4_NEON(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1); + Store8x4x2_NEON(op1, op0, oq0, oq1, u, v, stride); + } +} + +#if !defined(WORK_AROUND_GCC) +static void HFilter8_NEON(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; + Load8x8x2T_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3); + { + const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, + ithresh, thresh); + const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh); + uint8x16_t op2, op1, op0, oq0, oq1, oq2; + DoFilter6_NEON(p2, p1, p0, q0, q1, q2, mask, hev_mask, + &op2, &op1, &op0, &oq0, &oq1, &oq2); + Store6x8x2_NEON(op2, op1, op0, oq0, oq1, oq2, u, v, stride); + } +} + +static void HFilter8i_NEON(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; + u += 4; + v += 4; + Load8x8x2T_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3); + { + const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, + ithresh, thresh); + const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh); + uint8x16_t op1, op0, oq0, oq1; + DoFilter4_NEON(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1); + Store4x8x2_NEON(op1, op0, oq0, oq1, u, v, stride); + } +} +#endif // !WORK_AROUND_GCC + +//----------------------------------------------------------------------------- +// Inverse transforms (Paragraph 14.4) + +// Technically these are unsigned but vqdmulh is only available in signed. +// vqdmulh returns high half (effectively >> 16) but also doubles the value, +// changing the >> 16 to >> 15 and requiring an additional >> 1. +// We use this to our advantage with kC2. The canonical value is 35468. +// However, the high bit is set so treating it as signed will give incorrect +// results. We avoid this by down shifting by 1 here to clear the highest bit. +// Combined with the doubling effect of vqdmulh we get >> 16. +// This can not be applied to kC1 because the lowest bit is set. Down shifting +// the constant would reduce precision. + +// libwebp uses a trick to avoid some extra addition that libvpx does. +// Instead of: +// temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16); +// libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the +// same issue with kC1 and vqdmulh that we work around by down shifting kC2 + +static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1; +static const int16_t kC2 = + WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above. + +#if defined(WEBP_USE_INTRINSICS) +static WEBP_INLINE void Transpose8x2_NEON(const int16x8_t in0, + const int16x8_t in1, + int16x8x2_t* const out) { + // a0 a1 a2 a3 | b0 b1 b2 b3 => a0 b0 c0 d0 | a1 b1 c1 d1 + // c0 c1 c2 c3 | d0 d1 d2 d3 a2 b2 c2 d2 | a3 b3 c3 d3 + const int16x8x2_t tmp0 = vzipq_s16(in0, in1); // a0 c0 a1 c1 a2 c2 ... + // b0 d0 b1 d1 b2 d2 ... + *out = vzipq_s16(tmp0.val[0], tmp0.val[1]); +} + +static WEBP_INLINE void TransformPass_NEON(int16x8x2_t* const rows) { + // {rows} = in0 | in4 + // in8 | in12 + // B1 = in4 | in12 + const int16x8_t B1 = + vcombine_s16(vget_high_s16(rows->val[0]), vget_high_s16(rows->val[1])); + // C0 = kC1 * in4 | kC1 * in12 + // C1 = kC2 * in4 | kC2 * in12 + const int16x8_t C0 = vsraq_n_s16(B1, vqdmulhq_n_s16(B1, kC1), 1); + const int16x8_t C1 = vqdmulhq_n_s16(B1, kC2); + const int16x4_t a = vqadd_s16(vget_low_s16(rows->val[0]), + vget_low_s16(rows->val[1])); // in0 + in8 + const int16x4_t b = vqsub_s16(vget_low_s16(rows->val[0]), + vget_low_s16(rows->val[1])); // in0 - in8 + // c = kC2 * in4 - kC1 * in12 + // d = kC1 * in4 + kC2 * in12 + const int16x4_t c = vqsub_s16(vget_low_s16(C1), vget_high_s16(C0)); + const int16x4_t d = vqadd_s16(vget_low_s16(C0), vget_high_s16(C1)); + const int16x8_t D0 = vcombine_s16(a, b); // D0 = a | b + const int16x8_t D1 = vcombine_s16(d, c); // D1 = d | c + const int16x8_t E0 = vqaddq_s16(D0, D1); // a+d | b+c + const int16x8_t E_tmp = vqsubq_s16(D0, D1); // a-d | b-c + const int16x8_t E1 = vcombine_s16(vget_high_s16(E_tmp), vget_low_s16(E_tmp)); + Transpose8x2_NEON(E0, E1, rows); +} + +static void TransformOne_NEON(const int16_t* in, uint8_t* dst) { + int16x8x2_t rows; + INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8)); + TransformPass_NEON(&rows); + TransformPass_NEON(&rows); + Add4x4_NEON(rows.val[0], rows.val[1], dst); +} + +#else + +static void TransformOne_NEON(const int16_t* in, uint8_t* dst) { + const int kBPS = BPS; + // kC1, kC2. Padded because vld1.16 loads 8 bytes + const int16_t constants[4] = { kC1, kC2, 0, 0 }; + /* Adapted from libvpx: vp8/common/arm/neon/shortidct4x4llm_neon.asm */ + __asm__ volatile ( + "vld1.16 {q1, q2}, [%[in]] \n" + "vld1.16 {d0}, [%[constants]] \n" + + /* d2: in[0] + * d3: in[8] + * d4: in[4] + * d5: in[12] + */ + "vswp d3, d4 \n" + + /* q8 = {in[4], in[12]} * kC1 * 2 >> 16 + * q9 = {in[4], in[12]} * kC2 >> 16 + */ + "vqdmulh.s16 q8, q2, d0[0] \n" + "vqdmulh.s16 q9, q2, d0[1] \n" + + /* d22 = a = in[0] + in[8] + * d23 = b = in[0] - in[8] + */ + "vqadd.s16 d22, d2, d3 \n" + "vqsub.s16 d23, d2, d3 \n" + + /* The multiplication should be x * kC1 >> 16 + * However, with vqdmulh we get x * kC1 * 2 >> 16 + * (multiply, double, return high half) + * We avoided this in kC2 by pre-shifting the constant. + * q8 = in[4]/[12] * kC1 >> 16 + */ + "vshr.s16 q8, q8, #1 \n" + + /* Add {in[4], in[12]} back after the multiplication. This is handled by + * adding 1 << 16 to kC1 in the libwebp C code. + */ + "vqadd.s16 q8, q2, q8 \n" + + /* d20 = c = in[4]*kC2 - in[12]*kC1 + * d21 = d = in[4]*kC1 + in[12]*kC2 + */ + "vqsub.s16 d20, d18, d17 \n" + "vqadd.s16 d21, d19, d16 \n" + + /* d2 = tmp[0] = a + d + * d3 = tmp[1] = b + c + * d4 = tmp[2] = b - c + * d5 = tmp[3] = a - d + */ + "vqadd.s16 d2, d22, d21 \n" + "vqadd.s16 d3, d23, d20 \n" + "vqsub.s16 d4, d23, d20 \n" + "vqsub.s16 d5, d22, d21 \n" + + "vzip.16 q1, q2 \n" + "vzip.16 q1, q2 \n" + + "vswp d3, d4 \n" + + /* q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16 + * q9 = {tmp[4], tmp[12]} * kC2 >> 16 + */ + "vqdmulh.s16 q8, q2, d0[0] \n" + "vqdmulh.s16 q9, q2, d0[1] \n" + + /* d22 = a = tmp[0] + tmp[8] + * d23 = b = tmp[0] - tmp[8] + */ + "vqadd.s16 d22, d2, d3 \n" + "vqsub.s16 d23, d2, d3 \n" + + /* See long winded explanations prior */ + "vshr.s16 q8, q8, #1 \n" + "vqadd.s16 q8, q2, q8 \n" + + /* d20 = c = in[4]*kC2 - in[12]*kC1 + * d21 = d = in[4]*kC1 + in[12]*kC2 + */ + "vqsub.s16 d20, d18, d17 \n" + "vqadd.s16 d21, d19, d16 \n" + + /* d2 = tmp[0] = a + d + * d3 = tmp[1] = b + c + * d4 = tmp[2] = b - c + * d5 = tmp[3] = a - d + */ + "vqadd.s16 d2, d22, d21 \n" + "vqadd.s16 d3, d23, d20 \n" + "vqsub.s16 d4, d23, d20 \n" + "vqsub.s16 d5, d22, d21 \n" + + "vld1.32 d6[0], [%[dst]], %[kBPS] \n" + "vld1.32 d6[1], [%[dst]], %[kBPS] \n" + "vld1.32 d7[0], [%[dst]], %[kBPS] \n" + "vld1.32 d7[1], [%[dst]], %[kBPS] \n" + + "sub %[dst], %[dst], %[kBPS], lsl #2 \n" + + /* (val) + 4 >> 3 */ + "vrshr.s16 d2, d2, #3 \n" + "vrshr.s16 d3, d3, #3 \n" + "vrshr.s16 d4, d4, #3 \n" + "vrshr.s16 d5, d5, #3 \n" + + "vzip.16 q1, q2 \n" + "vzip.16 q1, q2 \n" + + /* Must accumulate before saturating */ + "vmovl.u8 q8, d6 \n" + "vmovl.u8 q9, d7 \n" + + "vqadd.s16 q1, q1, q8 \n" + "vqadd.s16 q2, q2, q9 \n" + + "vqmovun.s16 d0, q1 \n" + "vqmovun.s16 d1, q2 \n" + + "vst1.32 d0[0], [%[dst]], %[kBPS] \n" + "vst1.32 d0[1], [%[dst]], %[kBPS] \n" + "vst1.32 d1[0], [%[dst]], %[kBPS] \n" + "vst1.32 d1[1], [%[dst]] \n" + + : [in] "+r"(in), [dst] "+r"(dst) /* modified registers */ + : [kBPS] "r"(kBPS), [constants] "r"(constants) /* constants */ + : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" /* clobbered */ + ); +} + +#endif // WEBP_USE_INTRINSICS + +static void TransformTwo_NEON(const int16_t* in, uint8_t* dst, int do_two) { + TransformOne_NEON(in, dst); + if (do_two) { + TransformOne_NEON(in + 16, dst + 4); + } +} + +static void TransformDC_NEON(const int16_t* in, uint8_t* dst) { + const int16x8_t DC = vdupq_n_s16(in[0]); + Add4x4_NEON(DC, DC, dst); +} + +//------------------------------------------------------------------------------ + +#define STORE_WHT(dst, col, rows) do { \ + *dst = vgetq_lane_s32(rows.val[0], col); (dst) += 16; \ + *dst = vgetq_lane_s32(rows.val[1], col); (dst) += 16; \ + *dst = vgetq_lane_s32(rows.val[2], col); (dst) += 16; \ + *dst = vgetq_lane_s32(rows.val[3], col); (dst) += 16; \ +} while (0) + +static void TransformWHT_NEON(const int16_t* in, int16_t* out) { + int32x4x4_t tmp; + + { + // Load the source. + const int16x4_t in00_03 = vld1_s16(in + 0); + const int16x4_t in04_07 = vld1_s16(in + 4); + const int16x4_t in08_11 = vld1_s16(in + 8); + const int16x4_t in12_15 = vld1_s16(in + 12); + const int32x4_t a0 = vaddl_s16(in00_03, in12_15); // in[0..3] + in[12..15] + const int32x4_t a1 = vaddl_s16(in04_07, in08_11); // in[4..7] + in[8..11] + const int32x4_t a2 = vsubl_s16(in04_07, in08_11); // in[4..7] - in[8..11] + const int32x4_t a3 = vsubl_s16(in00_03, in12_15); // in[0..3] - in[12..15] + tmp.val[0] = vaddq_s32(a0, a1); + tmp.val[1] = vaddq_s32(a3, a2); + tmp.val[2] = vsubq_s32(a0, a1); + tmp.val[3] = vsubq_s32(a3, a2); + // Arrange the temporary results column-wise. + tmp = Transpose4x4_NEON(tmp); + } + + { + const int32x4_t kCst3 = vdupq_n_s32(3); + const int32x4_t dc = vaddq_s32(tmp.val[0], kCst3); // add rounder + const int32x4_t a0 = vaddq_s32(dc, tmp.val[3]); + const int32x4_t a1 = vaddq_s32(tmp.val[1], tmp.val[2]); + const int32x4_t a2 = vsubq_s32(tmp.val[1], tmp.val[2]); + const int32x4_t a3 = vsubq_s32(dc, tmp.val[3]); + + tmp.val[0] = vaddq_s32(a0, a1); + tmp.val[1] = vaddq_s32(a3, a2); + tmp.val[2] = vsubq_s32(a0, a1); + tmp.val[3] = vsubq_s32(a3, a2); + + // right shift the results by 3. + tmp.val[0] = vshrq_n_s32(tmp.val[0], 3); + tmp.val[1] = vshrq_n_s32(tmp.val[1], 3); + tmp.val[2] = vshrq_n_s32(tmp.val[2], 3); + tmp.val[3] = vshrq_n_s32(tmp.val[3], 3); + + STORE_WHT(out, 0, tmp); + STORE_WHT(out, 1, tmp); + STORE_WHT(out, 2, tmp); + STORE_WHT(out, 3, tmp); + } +} + +#undef STORE_WHT + +//------------------------------------------------------------------------------ + +static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) { + const int16x4_t A = vld1_dup_s16(in); + const int16x4_t c4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL2(in[4])); + const int16x4_t d4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL1(in[4])); + const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]); + const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]); + const uint64_t cd = (uint64_t)( d1 & 0xffff) << 0 | + (uint64_t)( c1 & 0xffff) << 16 | + (uint64_t)(-c1 & 0xffff) << 32 | + (uint64_t)(-d1 & 0xffff) << 48; + const int16x4_t CD = vcreate_s16(cd); + const int16x4_t B = vqadd_s16(A, CD); + const int16x8_t m0_m1 = vcombine_s16(vqadd_s16(B, d4), vqadd_s16(B, c4)); + const int16x8_t m2_m3 = vcombine_s16(vqsub_s16(B, c4), vqsub_s16(B, d4)); + Add4x4_NEON(m0_m1, m2_m3, dst); +} + +//------------------------------------------------------------------------------ +// 4x4 + +static void DC4_NEON(uint8_t* dst) { // DC + const uint8x8_t A = vld1_u8(dst - BPS); // top row + const uint16x4_t p0 = vpaddl_u8(A); // cascading summation of the top + const uint16x4_t p1 = vpadd_u16(p0, p0); + const uint8x8_t L0 = vld1_u8(dst + 0 * BPS - 1); + const uint8x8_t L1 = vld1_u8(dst + 1 * BPS - 1); + const uint8x8_t L2 = vld1_u8(dst + 2 * BPS - 1); + const uint8x8_t L3 = vld1_u8(dst + 3 * BPS - 1); + const uint16x8_t s0 = vaddl_u8(L0, L1); + const uint16x8_t s1 = vaddl_u8(L2, L3); + const uint16x8_t s01 = vaddq_u16(s0, s1); + const uint16x8_t sum = vaddq_u16(s01, vcombine_u16(p1, p1)); + const uint8x8_t dc0 = vrshrn_n_u16(sum, 3); // (sum + 4) >> 3 + const uint8x8_t dc = vdup_lane_u8(dc0, 0); + int i; + for (i = 0; i < 4; ++i) { + vst1_lane_u32((uint32_t*)(dst + i * BPS), vreinterpret_u32_u8(dc), 0); + } +} + +// TrueMotion (4x4 + 8x8) +static WEBP_INLINE void TrueMotion_NEON(uint8_t* dst, int size) { + const uint8x8_t TL = vld1_dup_u8(dst - BPS - 1); // top-left pixel 'A[-1]' + const uint8x8_t T = vld1_u8(dst - BPS); // top row 'A[0..3]' + const int16x8_t d = vreinterpretq_s16_u16(vsubl_u8(T, TL)); // A[c] - A[-1] + int y; + for (y = 0; y < size; y += 4) { + // left edge + const int16x8_t L0 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 0 * BPS - 1)); + const int16x8_t L1 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 1 * BPS - 1)); + const int16x8_t L2 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 2 * BPS - 1)); + const int16x8_t L3 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 3 * BPS - 1)); + const int16x8_t r0 = vaddq_s16(L0, d); // L[r] + A[c] - A[-1] + const int16x8_t r1 = vaddq_s16(L1, d); + const int16x8_t r2 = vaddq_s16(L2, d); + const int16x8_t r3 = vaddq_s16(L3, d); + // Saturate and store the result. + const uint32x2_t r0_u32 = vreinterpret_u32_u8(vqmovun_s16(r0)); + const uint32x2_t r1_u32 = vreinterpret_u32_u8(vqmovun_s16(r1)); + const uint32x2_t r2_u32 = vreinterpret_u32_u8(vqmovun_s16(r2)); + const uint32x2_t r3_u32 = vreinterpret_u32_u8(vqmovun_s16(r3)); + if (size == 4) { + vst1_lane_u32((uint32_t*)(dst + 0 * BPS), r0_u32, 0); + vst1_lane_u32((uint32_t*)(dst + 1 * BPS), r1_u32, 0); + vst1_lane_u32((uint32_t*)(dst + 2 * BPS), r2_u32, 0); + vst1_lane_u32((uint32_t*)(dst + 3 * BPS), r3_u32, 0); + } else { + vst1_u32((uint32_t*)(dst + 0 * BPS), r0_u32); + vst1_u32((uint32_t*)(dst + 1 * BPS), r1_u32); + vst1_u32((uint32_t*)(dst + 2 * BPS), r2_u32); + vst1_u32((uint32_t*)(dst + 3 * BPS), r3_u32); + } + dst += 4 * BPS; + } +} + +static void TM4_NEON(uint8_t* dst) { TrueMotion_NEON(dst, 4); } + +static void VE4_NEON(uint8_t* dst) { // vertical + // NB: avoid vld1_u64 here as an alignment hint may be added -> SIGBUS. + const uint64x1_t A0 = vreinterpret_u64_u8(vld1_u8(dst - BPS - 1)); // top row + const uint64x1_t A1 = vshr_n_u64(A0, 8); + const uint64x1_t A2 = vshr_n_u64(A0, 16); + const uint8x8_t ABCDEFGH = vreinterpret_u8_u64(A0); + const uint8x8_t BCDEFGH0 = vreinterpret_u8_u64(A1); + const uint8x8_t CDEFGH00 = vreinterpret_u8_u64(A2); + const uint8x8_t b = vhadd_u8(ABCDEFGH, CDEFGH00); + const uint8x8_t avg = vrhadd_u8(b, BCDEFGH0); + int i; + for (i = 0; i < 4; ++i) { + vst1_lane_u32((uint32_t*)(dst + i * BPS), vreinterpret_u32_u8(avg), 0); + } +} + +static void RD4_NEON(uint8_t* dst) { // Down-right + const uint8x8_t XABCD_u8 = vld1_u8(dst - BPS - 1); + const uint64x1_t XABCD = vreinterpret_u64_u8(XABCD_u8); + const uint64x1_t ____XABC = vshl_n_u64(XABCD, 32); + const uint32_t I = dst[-1 + 0 * BPS]; + const uint32_t J = dst[-1 + 1 * BPS]; + const uint32_t K = dst[-1 + 2 * BPS]; + const uint32_t L = dst[-1 + 3 * BPS]; + const uint64x1_t LKJI____ = + vcreate_u64((uint64_t)L | (K << 8) | (J << 16) | (I << 24)); + const uint64x1_t LKJIXABC = vorr_u64(LKJI____, ____XABC); + const uint8x8_t KJIXABC_ = vreinterpret_u8_u64(vshr_n_u64(LKJIXABC, 8)); + const uint8x8_t JIXABC__ = vreinterpret_u8_u64(vshr_n_u64(LKJIXABC, 16)); + const uint8_t D = vget_lane_u8(XABCD_u8, 4); + const uint8x8_t JIXABCD_ = vset_lane_u8(D, JIXABC__, 6); + const uint8x8_t LKJIXABC_u8 = vreinterpret_u8_u64(LKJIXABC); + const uint8x8_t avg1 = vhadd_u8(JIXABCD_, LKJIXABC_u8); + const uint8x8_t avg2 = vrhadd_u8(avg1, KJIXABC_); + const uint64x1_t avg2_u64 = vreinterpret_u64_u8(avg2); + const uint32x2_t r3 = vreinterpret_u32_u8(avg2); + const uint32x2_t r2 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 8)); + const uint32x2_t r1 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 16)); + const uint32x2_t r0 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 24)); + vst1_lane_u32((uint32_t*)(dst + 0 * BPS), r0, 0); + vst1_lane_u32((uint32_t*)(dst + 1 * BPS), r1, 0); + vst1_lane_u32((uint32_t*)(dst + 2 * BPS), r2, 0); + vst1_lane_u32((uint32_t*)(dst + 3 * BPS), r3, 0); +} + +static void LD4_NEON(uint8_t* dst) { // Down-left + // Note using the same shift trick as VE4() is slower here. + const uint8x8_t ABCDEFGH = vld1_u8(dst - BPS + 0); + const uint8x8_t BCDEFGH0 = vld1_u8(dst - BPS + 1); + const uint8x8_t CDEFGH00 = vld1_u8(dst - BPS + 2); + const uint8x8_t CDEFGHH0 = vset_lane_u8(dst[-BPS + 7], CDEFGH00, 6); + const uint8x8_t avg1 = vhadd_u8(ABCDEFGH, CDEFGHH0); + const uint8x8_t avg2 = vrhadd_u8(avg1, BCDEFGH0); + const uint64x1_t avg2_u64 = vreinterpret_u64_u8(avg2); + const uint32x2_t r0 = vreinterpret_u32_u8(avg2); + const uint32x2_t r1 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 8)); + const uint32x2_t r2 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 16)); + const uint32x2_t r3 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 24)); + vst1_lane_u32((uint32_t*)(dst + 0 * BPS), r0, 0); + vst1_lane_u32((uint32_t*)(dst + 1 * BPS), r1, 0); + vst1_lane_u32((uint32_t*)(dst + 2 * BPS), r2, 0); + vst1_lane_u32((uint32_t*)(dst + 3 * BPS), r3, 0); +} + +//------------------------------------------------------------------------------ +// Chroma + +static void VE8uv_NEON(uint8_t* dst) { // vertical + const uint8x8_t top = vld1_u8(dst - BPS); + int j; + for (j = 0; j < 8; ++j) { + vst1_u8(dst + j * BPS, top); + } +} + +static void HE8uv_NEON(uint8_t* dst) { // horizontal + int j; + for (j = 0; j < 8; ++j) { + const uint8x8_t left = vld1_dup_u8(dst - 1); + vst1_u8(dst, left); + dst += BPS; + } +} + +static WEBP_INLINE void DC8_NEON(uint8_t* dst, int do_top, int do_left) { + uint16x8_t sum_top; + uint16x8_t sum_left; + uint8x8_t dc0; + + if (do_top) { + const uint8x8_t A = vld1_u8(dst - BPS); // top row +#if WEBP_AARCH64 + const uint16_t p2 = vaddlv_u8(A); + sum_top = vdupq_n_u16(p2); +#else + const uint16x4_t p0 = vpaddl_u8(A); // cascading summation of the top + const uint16x4_t p1 = vpadd_u16(p0, p0); + const uint16x4_t p2 = vpadd_u16(p1, p1); + sum_top = vcombine_u16(p2, p2); +#endif + } + + if (do_left) { + const uint8x8_t L0 = vld1_u8(dst + 0 * BPS - 1); + const uint8x8_t L1 = vld1_u8(dst + 1 * BPS - 1); + const uint8x8_t L2 = vld1_u8(dst + 2 * BPS - 1); + const uint8x8_t L3 = vld1_u8(dst + 3 * BPS - 1); + const uint8x8_t L4 = vld1_u8(dst + 4 * BPS - 1); + const uint8x8_t L5 = vld1_u8(dst + 5 * BPS - 1); + const uint8x8_t L6 = vld1_u8(dst + 6 * BPS - 1); + const uint8x8_t L7 = vld1_u8(dst + 7 * BPS - 1); + const uint16x8_t s0 = vaddl_u8(L0, L1); + const uint16x8_t s1 = vaddl_u8(L2, L3); + const uint16x8_t s2 = vaddl_u8(L4, L5); + const uint16x8_t s3 = vaddl_u8(L6, L7); + const uint16x8_t s01 = vaddq_u16(s0, s1); + const uint16x8_t s23 = vaddq_u16(s2, s3); + sum_left = vaddq_u16(s01, s23); + } + + if (do_top && do_left) { + const uint16x8_t sum = vaddq_u16(sum_left, sum_top); + dc0 = vrshrn_n_u16(sum, 4); + } else if (do_top) { + dc0 = vrshrn_n_u16(sum_top, 3); + } else if (do_left) { + dc0 = vrshrn_n_u16(sum_left, 3); + } else { + dc0 = vdup_n_u8(0x80); + } + + { + const uint8x8_t dc = vdup_lane_u8(dc0, 0); + int i; + for (i = 0; i < 8; ++i) { + vst1_u32((uint32_t*)(dst + i * BPS), vreinterpret_u32_u8(dc)); + } + } +} + +static void DC8uv_NEON(uint8_t* dst) { DC8_NEON(dst, 1, 1); } +static void DC8uvNoTop_NEON(uint8_t* dst) { DC8_NEON(dst, 0, 1); } +static void DC8uvNoLeft_NEON(uint8_t* dst) { DC8_NEON(dst, 1, 0); } +static void DC8uvNoTopLeft_NEON(uint8_t* dst) { DC8_NEON(dst, 0, 0); } + +static void TM8uv_NEON(uint8_t* dst) { TrueMotion_NEON(dst, 8); } + +//------------------------------------------------------------------------------ +// 16x16 + +static void VE16_NEON(uint8_t* dst) { // vertical + const uint8x16_t top = vld1q_u8(dst - BPS); + int j; + for (j = 0; j < 16; ++j) { + vst1q_u8(dst + j * BPS, top); + } +} + +static void HE16_NEON(uint8_t* dst) { // horizontal + int j; + for (j = 0; j < 16; ++j) { + const uint8x16_t left = vld1q_dup_u8(dst - 1); + vst1q_u8(dst, left); + dst += BPS; + } +} + +static WEBP_INLINE void DC16_NEON(uint8_t* dst, int do_top, int do_left) { + uint16x8_t sum_top; + uint16x8_t sum_left; + uint8x8_t dc0; + + if (do_top) { + const uint8x16_t A = vld1q_u8(dst - BPS); // top row +#if WEBP_AARCH64 + const uint16_t p3 = vaddlvq_u8(A); + sum_top = vdupq_n_u16(p3); +#else + const uint16x8_t p0 = vpaddlq_u8(A); // cascading summation of the top + const uint16x4_t p1 = vadd_u16(vget_low_u16(p0), vget_high_u16(p0)); + const uint16x4_t p2 = vpadd_u16(p1, p1); + const uint16x4_t p3 = vpadd_u16(p2, p2); + sum_top = vcombine_u16(p3, p3); +#endif + } + + if (do_left) { + int i; + sum_left = vdupq_n_u16(0); + for (i = 0; i < 16; i += 8) { + const uint8x8_t L0 = vld1_u8(dst + (i + 0) * BPS - 1); + const uint8x8_t L1 = vld1_u8(dst + (i + 1) * BPS - 1); + const uint8x8_t L2 = vld1_u8(dst + (i + 2) * BPS - 1); + const uint8x8_t L3 = vld1_u8(dst + (i + 3) * BPS - 1); + const uint8x8_t L4 = vld1_u8(dst + (i + 4) * BPS - 1); + const uint8x8_t L5 = vld1_u8(dst + (i + 5) * BPS - 1); + const uint8x8_t L6 = vld1_u8(dst + (i + 6) * BPS - 1); + const uint8x8_t L7 = vld1_u8(dst + (i + 7) * BPS - 1); + const uint16x8_t s0 = vaddl_u8(L0, L1); + const uint16x8_t s1 = vaddl_u8(L2, L3); + const uint16x8_t s2 = vaddl_u8(L4, L5); + const uint16x8_t s3 = vaddl_u8(L6, L7); + const uint16x8_t s01 = vaddq_u16(s0, s1); + const uint16x8_t s23 = vaddq_u16(s2, s3); + const uint16x8_t sum = vaddq_u16(s01, s23); + sum_left = vaddq_u16(sum_left, sum); + } + } + + if (do_top && do_left) { + const uint16x8_t sum = vaddq_u16(sum_left, sum_top); + dc0 = vrshrn_n_u16(sum, 5); + } else if (do_top) { + dc0 = vrshrn_n_u16(sum_top, 4); + } else if (do_left) { + dc0 = vrshrn_n_u16(sum_left, 4); + } else { + dc0 = vdup_n_u8(0x80); + } + + { + const uint8x16_t dc = vdupq_lane_u8(dc0, 0); + int i; + for (i = 0; i < 16; ++i) { + vst1q_u8(dst + i * BPS, dc); + } + } +} + +static void DC16TopLeft_NEON(uint8_t* dst) { DC16_NEON(dst, 1, 1); } +static void DC16NoTop_NEON(uint8_t* dst) { DC16_NEON(dst, 0, 1); } +static void DC16NoLeft_NEON(uint8_t* dst) { DC16_NEON(dst, 1, 0); } +static void DC16NoTopLeft_NEON(uint8_t* dst) { DC16_NEON(dst, 0, 0); } + +static void TM16_NEON(uint8_t* dst) { + const uint8x8_t TL = vld1_dup_u8(dst - BPS - 1); // top-left pixel 'A[-1]' + const uint8x16_t T = vld1q_u8(dst - BPS); // top row 'A[0..15]' + // A[c] - A[-1] + const int16x8_t d_lo = vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(T), TL)); + const int16x8_t d_hi = vreinterpretq_s16_u16(vsubl_u8(vget_high_u8(T), TL)); + int y; + for (y = 0; y < 16; y += 4) { + // left edge + const int16x8_t L0 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 0 * BPS - 1)); + const int16x8_t L1 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 1 * BPS - 1)); + const int16x8_t L2 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 2 * BPS - 1)); + const int16x8_t L3 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 3 * BPS - 1)); + const int16x8_t r0_lo = vaddq_s16(L0, d_lo); // L[r] + A[c] - A[-1] + const int16x8_t r1_lo = vaddq_s16(L1, d_lo); + const int16x8_t r2_lo = vaddq_s16(L2, d_lo); + const int16x8_t r3_lo = vaddq_s16(L3, d_lo); + const int16x8_t r0_hi = vaddq_s16(L0, d_hi); + const int16x8_t r1_hi = vaddq_s16(L1, d_hi); + const int16x8_t r2_hi = vaddq_s16(L2, d_hi); + const int16x8_t r3_hi = vaddq_s16(L3, d_hi); + // Saturate and store the result. + const uint8x16_t row0 = vcombine_u8(vqmovun_s16(r0_lo), vqmovun_s16(r0_hi)); + const uint8x16_t row1 = vcombine_u8(vqmovun_s16(r1_lo), vqmovun_s16(r1_hi)); + const uint8x16_t row2 = vcombine_u8(vqmovun_s16(r2_lo), vqmovun_s16(r2_hi)); + const uint8x16_t row3 = vcombine_u8(vqmovun_s16(r3_lo), vqmovun_s16(r3_hi)); + vst1q_u8(dst + 0 * BPS, row0); + vst1q_u8(dst + 1 * BPS, row1); + vst1q_u8(dst + 2 * BPS, row2); + vst1q_u8(dst + 3 * BPS, row3); + dst += 4 * BPS; + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitNEON(void) { + VP8Transform = TransformTwo_NEON; + VP8TransformAC3 = TransformAC3_NEON; + VP8TransformDC = TransformDC_NEON; + VP8TransformWHT = TransformWHT_NEON; + + VP8VFilter16 = VFilter16_NEON; + VP8VFilter16i = VFilter16i_NEON; + VP8HFilter16 = HFilter16_NEON; +#if !defined(WORK_AROUND_GCC) + VP8HFilter16i = HFilter16i_NEON; +#endif + VP8VFilter8 = VFilter8_NEON; + VP8VFilter8i = VFilter8i_NEON; +#if !defined(WORK_AROUND_GCC) + VP8HFilter8 = HFilter8_NEON; + VP8HFilter8i = HFilter8i_NEON; +#endif + VP8SimpleVFilter16 = SimpleVFilter16_NEON; + VP8SimpleHFilter16 = SimpleHFilter16_NEON; + VP8SimpleVFilter16i = SimpleVFilter16i_NEON; + VP8SimpleHFilter16i = SimpleHFilter16i_NEON; + + VP8PredLuma4[0] = DC4_NEON; + VP8PredLuma4[1] = TM4_NEON; + VP8PredLuma4[2] = VE4_NEON; + VP8PredLuma4[4] = RD4_NEON; + VP8PredLuma4[6] = LD4_NEON; + + VP8PredLuma16[0] = DC16TopLeft_NEON; + VP8PredLuma16[1] = TM16_NEON; + VP8PredLuma16[2] = VE16_NEON; + VP8PredLuma16[3] = HE16_NEON; + VP8PredLuma16[4] = DC16NoTop_NEON; + VP8PredLuma16[5] = DC16NoLeft_NEON; + VP8PredLuma16[6] = DC16NoTopLeft_NEON; + + VP8PredChroma8[0] = DC8uv_NEON; + VP8PredChroma8[1] = TM8uv_NEON; + VP8PredChroma8[2] = VE8uv_NEON; + VP8PredChroma8[3] = HE8uv_NEON; + VP8PredChroma8[4] = DC8uvNoTop_NEON; + VP8PredChroma8[5] = DC8uvNoLeft_NEON; + VP8PredChroma8[6] = DC8uvNoTopLeft_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(VP8DspInitNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/dec_sse2.c b/libraries/webp/src/dsp/dec_sse2.c new file mode 100644 index 00000000000..ff3a28555b4 --- /dev/null +++ b/libraries/webp/src/dsp/dec_sse2.c @@ -0,0 +1,1226 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 version of some decoding functions (idct, loop filtering). +// +// Author: somnath@google.com (Somnath Banerjee) +// cduvivier@google.com (Christian Duvivier) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) + +// The 3-coeff sparse transform in SSE2 is not really faster than the plain-C +// one it seems => disable it by default. Uncomment the following to enable: +#if !defined(USE_TRANSFORM_AC3) +#define USE_TRANSFORM_AC3 0 // ALTERNATE_CODE +#endif + +#include +#include "src/dsp/common_sse2.h" +#include "src/dec/vp8i_dec.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +static void Transform_SSE2(const int16_t* in, uint8_t* dst, int do_two) { + // This implementation makes use of 16-bit fixed point versions of two + // multiply constants: + // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16 + // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16 + // + // To be able to use signed 16-bit integers, we use the following trick to + // have constants within range: + // - Associated constants are obtained by subtracting the 16-bit fixed point + // version of one: + // k = K - (1 << 16) => K = k + (1 << 16) + // K1 = 85267 => k1 = 20091 + // K2 = 35468 => k2 = -30068 + // - The multiplication of a variable by a constant become the sum of the + // variable and the multiplication of that variable by the associated + // constant: + // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x + const __m128i k1 = _mm_set1_epi16(20091); + const __m128i k2 = _mm_set1_epi16(-30068); + __m128i T0, T1, T2, T3; + + // Load and concatenate the transform coefficients (we'll do two transforms + // in parallel). In the case of only one transform, the second half of the + // vectors will just contain random value we'll never use nor store. + __m128i in0, in1, in2, in3; + { + in0 = _mm_loadl_epi64((const __m128i*)&in[0]); + in1 = _mm_loadl_epi64((const __m128i*)&in[4]); + in2 = _mm_loadl_epi64((const __m128i*)&in[8]); + in3 = _mm_loadl_epi64((const __m128i*)&in[12]); + // a00 a10 a20 a30 x x x x + // a01 a11 a21 a31 x x x x + // a02 a12 a22 a32 x x x x + // a03 a13 a23 a33 x x x x + if (do_two) { + const __m128i inB0 = _mm_loadl_epi64((const __m128i*)&in[16]); + const __m128i inB1 = _mm_loadl_epi64((const __m128i*)&in[20]); + const __m128i inB2 = _mm_loadl_epi64((const __m128i*)&in[24]); + const __m128i inB3 = _mm_loadl_epi64((const __m128i*)&in[28]); + in0 = _mm_unpacklo_epi64(in0, inB0); + in1 = _mm_unpacklo_epi64(in1, inB1); + in2 = _mm_unpacklo_epi64(in2, inB2); + in3 = _mm_unpacklo_epi64(in3, inB3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + } + + // Vertical pass and subsequent transpose. + { + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i a = _mm_add_epi16(in0, in2); + const __m128i b = _mm_sub_epi16(in0, in2); + // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3 + const __m128i c1 = _mm_mulhi_epi16(in1, k2); + const __m128i c2 = _mm_mulhi_epi16(in3, k1); + const __m128i c3 = _mm_sub_epi16(in1, in3); + const __m128i c4 = _mm_sub_epi16(c1, c2); + const __m128i c = _mm_add_epi16(c3, c4); + // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3 + const __m128i d1 = _mm_mulhi_epi16(in1, k1); + const __m128i d2 = _mm_mulhi_epi16(in3, k2); + const __m128i d3 = _mm_add_epi16(in1, in3); + const __m128i d4 = _mm_add_epi16(d1, d2); + const __m128i d = _mm_add_epi16(d3, d4); + + // Second pass. + const __m128i tmp0 = _mm_add_epi16(a, d); + const __m128i tmp1 = _mm_add_epi16(b, c); + const __m128i tmp2 = _mm_sub_epi16(b, c); + const __m128i tmp3 = _mm_sub_epi16(a, d); + + // Transpose the two 4x4. + VP8Transpose_2_4x4_16b(&tmp0, &tmp1, &tmp2, &tmp3, &T0, &T1, &T2, &T3); + } + + // Horizontal pass and subsequent transpose. + { + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i four = _mm_set1_epi16(4); + const __m128i dc = _mm_add_epi16(T0, four); + const __m128i a = _mm_add_epi16(dc, T2); + const __m128i b = _mm_sub_epi16(dc, T2); + // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3 + const __m128i c1 = _mm_mulhi_epi16(T1, k2); + const __m128i c2 = _mm_mulhi_epi16(T3, k1); + const __m128i c3 = _mm_sub_epi16(T1, T3); + const __m128i c4 = _mm_sub_epi16(c1, c2); + const __m128i c = _mm_add_epi16(c3, c4); + // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3 + const __m128i d1 = _mm_mulhi_epi16(T1, k1); + const __m128i d2 = _mm_mulhi_epi16(T3, k2); + const __m128i d3 = _mm_add_epi16(T1, T3); + const __m128i d4 = _mm_add_epi16(d1, d2); + const __m128i d = _mm_add_epi16(d3, d4); + + // Second pass. + const __m128i tmp0 = _mm_add_epi16(a, d); + const __m128i tmp1 = _mm_add_epi16(b, c); + const __m128i tmp2 = _mm_sub_epi16(b, c); + const __m128i tmp3 = _mm_sub_epi16(a, d); + const __m128i shifted0 = _mm_srai_epi16(tmp0, 3); + const __m128i shifted1 = _mm_srai_epi16(tmp1, 3); + const __m128i shifted2 = _mm_srai_epi16(tmp2, 3); + const __m128i shifted3 = _mm_srai_epi16(tmp3, 3); + + // Transpose the two 4x4. + VP8Transpose_2_4x4_16b(&shifted0, &shifted1, &shifted2, &shifted3, &T0, &T1, + &T2, &T3); + } + + // Add inverse transform to 'dst' and store. + { + const __m128i zero = _mm_setzero_si128(); + // Load the reference(s). + __m128i dst0, dst1, dst2, dst3; + if (do_two) { + // Load eight bytes/pixels per line. + dst0 = _mm_loadl_epi64((__m128i*)(dst + 0 * BPS)); + dst1 = _mm_loadl_epi64((__m128i*)(dst + 1 * BPS)); + dst2 = _mm_loadl_epi64((__m128i*)(dst + 2 * BPS)); + dst3 = _mm_loadl_epi64((__m128i*)(dst + 3 * BPS)); + } else { + // Load four bytes/pixels per line. + dst0 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 0 * BPS)); + dst1 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 1 * BPS)); + dst2 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 2 * BPS)); + dst3 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 3 * BPS)); + } + // Convert to 16b. + dst0 = _mm_unpacklo_epi8(dst0, zero); + dst1 = _mm_unpacklo_epi8(dst1, zero); + dst2 = _mm_unpacklo_epi8(dst2, zero); + dst3 = _mm_unpacklo_epi8(dst3, zero); + // Add the inverse transform(s). + dst0 = _mm_add_epi16(dst0, T0); + dst1 = _mm_add_epi16(dst1, T1); + dst2 = _mm_add_epi16(dst2, T2); + dst3 = _mm_add_epi16(dst3, T3); + // Unsigned saturate to 8b. + dst0 = _mm_packus_epi16(dst0, dst0); + dst1 = _mm_packus_epi16(dst1, dst1); + dst2 = _mm_packus_epi16(dst2, dst2); + dst3 = _mm_packus_epi16(dst3, dst3); + // Store the results. + if (do_two) { + // Store eight bytes/pixels per line. + _mm_storel_epi64((__m128i*)(dst + 0 * BPS), dst0); + _mm_storel_epi64((__m128i*)(dst + 1 * BPS), dst1); + _mm_storel_epi64((__m128i*)(dst + 2 * BPS), dst2); + _mm_storel_epi64((__m128i*)(dst + 3 * BPS), dst3); + } else { + // Store four bytes/pixels per line. + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(dst0)); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(dst1)); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2)); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3)); + } + } +} + +#if (USE_TRANSFORM_AC3 == 1) + +static void TransformAC3(const int16_t* in, uint8_t* dst) { + const __m128i A = _mm_set1_epi16(in[0] + 4); + const __m128i c4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL2(in[4])); + const __m128i d4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL1(in[4])); + const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]); + const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]); + const __m128i CD = _mm_set_epi16(0, 0, 0, 0, -d1, -c1, c1, d1); + const __m128i B = _mm_adds_epi16(A, CD); + const __m128i m0 = _mm_adds_epi16(B, d4); + const __m128i m1 = _mm_adds_epi16(B, c4); + const __m128i m2 = _mm_subs_epi16(B, c4); + const __m128i m3 = _mm_subs_epi16(B, d4); + const __m128i zero = _mm_setzero_si128(); + // Load the source pixels. + __m128i dst0 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 0 * BPS)); + __m128i dst1 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 1 * BPS)); + __m128i dst2 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 2 * BPS)); + __m128i dst3 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 3 * BPS)); + // Convert to 16b. + dst0 = _mm_unpacklo_epi8(dst0, zero); + dst1 = _mm_unpacklo_epi8(dst1, zero); + dst2 = _mm_unpacklo_epi8(dst2, zero); + dst3 = _mm_unpacklo_epi8(dst3, zero); + // Add the inverse transform. + dst0 = _mm_adds_epi16(dst0, _mm_srai_epi16(m0, 3)); + dst1 = _mm_adds_epi16(dst1, _mm_srai_epi16(m1, 3)); + dst2 = _mm_adds_epi16(dst2, _mm_srai_epi16(m2, 3)); + dst3 = _mm_adds_epi16(dst3, _mm_srai_epi16(m3, 3)); + // Unsigned saturate to 8b. + dst0 = _mm_packus_epi16(dst0, dst0); + dst1 = _mm_packus_epi16(dst1, dst1); + dst2 = _mm_packus_epi16(dst2, dst2); + dst3 = _mm_packus_epi16(dst3, dst3); + // Store the results. + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(dst0)); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(dst1)); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2)); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3)); +} + +#endif // USE_TRANSFORM_AC3 + +//------------------------------------------------------------------------------ +// Loop Filter (Paragraph 15) + +// Compute abs(p - q) = subs(p - q) OR subs(q - p) +#define MM_ABS(p, q) _mm_or_si128( \ + _mm_subs_epu8((q), (p)), \ + _mm_subs_epu8((p), (q))) + +// Shift each byte of "x" by 3 bits while preserving by the sign bit. +static WEBP_INLINE void SignedShift8b_SSE2(__m128i* const x) { + const __m128i zero = _mm_setzero_si128(); + const __m128i lo_0 = _mm_unpacklo_epi8(zero, *x); + const __m128i hi_0 = _mm_unpackhi_epi8(zero, *x); + const __m128i lo_1 = _mm_srai_epi16(lo_0, 3 + 8); + const __m128i hi_1 = _mm_srai_epi16(hi_0, 3 + 8); + *x = _mm_packs_epi16(lo_1, hi_1); +} + +#define FLIP_SIGN_BIT2(a, b) do { \ + (a) = _mm_xor_si128(a, sign_bit); \ + (b) = _mm_xor_si128(b, sign_bit); \ +} while (0) + +#define FLIP_SIGN_BIT4(a, b, c, d) do { \ + FLIP_SIGN_BIT2(a, b); \ + FLIP_SIGN_BIT2(c, d); \ +} while (0) + +// input/output is uint8_t +static WEBP_INLINE void GetNotHEV_SSE2(const __m128i* const p1, + const __m128i* const p0, + const __m128i* const q0, + const __m128i* const q1, + int hev_thresh, __m128i* const not_hev) { + const __m128i zero = _mm_setzero_si128(); + const __m128i t_1 = MM_ABS(*p1, *p0); + const __m128i t_2 = MM_ABS(*q1, *q0); + + const __m128i h = _mm_set1_epi8(hev_thresh); + const __m128i t_max = _mm_max_epu8(t_1, t_2); + + const __m128i t_max_h = _mm_subs_epu8(t_max, h); + *not_hev = _mm_cmpeq_epi8(t_max_h, zero); // not_hev <= t1 && not_hev <= t2 +} + +// input pixels are int8_t +static WEBP_INLINE void GetBaseDelta_SSE2(const __m128i* const p1, + const __m128i* const p0, + const __m128i* const q0, + const __m128i* const q1, + __m128i* const delta) { + // beware of addition order, for saturation! + const __m128i p1_q1 = _mm_subs_epi8(*p1, *q1); // p1 - q1 + const __m128i q0_p0 = _mm_subs_epi8(*q0, *p0); // q0 - p0 + const __m128i s1 = _mm_adds_epi8(p1_q1, q0_p0); // p1 - q1 + 1 * (q0 - p0) + const __m128i s2 = _mm_adds_epi8(q0_p0, s1); // p1 - q1 + 2 * (q0 - p0) + const __m128i s3 = _mm_adds_epi8(q0_p0, s2); // p1 - q1 + 3 * (q0 - p0) + *delta = s3; +} + +// input and output are int8_t +static WEBP_INLINE void DoSimpleFilter_SSE2(__m128i* const p0, + __m128i* const q0, + const __m128i* const fl) { + const __m128i k3 = _mm_set1_epi8(3); + const __m128i k4 = _mm_set1_epi8(4); + __m128i v3 = _mm_adds_epi8(*fl, k3); + __m128i v4 = _mm_adds_epi8(*fl, k4); + + SignedShift8b_SSE2(&v4); // v4 >> 3 + SignedShift8b_SSE2(&v3); // v3 >> 3 + *q0 = _mm_subs_epi8(*q0, v4); // q0 -= v4 + *p0 = _mm_adds_epi8(*p0, v3); // p0 += v3 +} + +// Updates values of 2 pixels at MB edge during complex filtering. +// Update operations: +// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)] +// Pixels 'pi' and 'qi' are int8_t on input, uint8_t on output (sign flip). +static WEBP_INLINE void Update2Pixels_SSE2(__m128i* const pi, __m128i* const qi, + const __m128i* const a0_lo, + const __m128i* const a0_hi) { + const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7); + const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7); + const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi); + const __m128i sign_bit = _mm_set1_epi8((char)0x80); + *pi = _mm_adds_epi8(*pi, delta); + *qi = _mm_subs_epi8(*qi, delta); + FLIP_SIGN_BIT2(*pi, *qi); +} + +// input pixels are uint8_t +static WEBP_INLINE void NeedsFilter_SSE2(const __m128i* const p1, + const __m128i* const p0, + const __m128i* const q0, + const __m128i* const q1, + int thresh, __m128i* const mask) { + const __m128i m_thresh = _mm_set1_epi8((char)thresh); + const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1) + const __m128i kFE = _mm_set1_epi8((char)0xFE); + const __m128i t2 = _mm_and_si128(t1, kFE); // set lsb of each byte to zero + const __m128i t3 = _mm_srli_epi16(t2, 1); // abs(p1 - q1) / 2 + + const __m128i t4 = MM_ABS(*p0, *q0); // abs(p0 - q0) + const __m128i t5 = _mm_adds_epu8(t4, t4); // abs(p0 - q0) * 2 + const __m128i t6 = _mm_adds_epu8(t5, t3); // abs(p0-q0)*2 + abs(p1-q1)/2 + + const __m128i t7 = _mm_subs_epu8(t6, m_thresh); // mask <= m_thresh + *mask = _mm_cmpeq_epi8(t7, _mm_setzero_si128()); +} + +//------------------------------------------------------------------------------ +// Edge filtering functions + +// Applies filter on 2 pixels (p0 and q0) +static WEBP_INLINE void DoFilter2_SSE2(__m128i* const p1, __m128i* const p0, + __m128i* const q0, __m128i* const q1, + int thresh) { + __m128i a, mask; + const __m128i sign_bit = _mm_set1_epi8((char)0x80); + // convert p1/q1 to int8_t (for GetBaseDelta_SSE2) + const __m128i p1s = _mm_xor_si128(*p1, sign_bit); + const __m128i q1s = _mm_xor_si128(*q1, sign_bit); + + NeedsFilter_SSE2(p1, p0, q0, q1, thresh, &mask); + + FLIP_SIGN_BIT2(*p0, *q0); + GetBaseDelta_SSE2(&p1s, p0, q0, &q1s, &a); + a = _mm_and_si128(a, mask); // mask filter values we don't care about + DoSimpleFilter_SSE2(p0, q0, &a); + FLIP_SIGN_BIT2(*p0, *q0); +} + +// Applies filter on 4 pixels (p1, p0, q0 and q1) +static WEBP_INLINE void DoFilter4_SSE2(__m128i* const p1, __m128i* const p0, + __m128i* const q0, __m128i* const q1, + const __m128i* const mask, + int hev_thresh) { + const __m128i zero = _mm_setzero_si128(); + const __m128i sign_bit = _mm_set1_epi8((char)0x80); + const __m128i k64 = _mm_set1_epi8(64); + const __m128i k3 = _mm_set1_epi8(3); + const __m128i k4 = _mm_set1_epi8(4); + __m128i not_hev; + __m128i t1, t2, t3; + + // compute hev mask + GetNotHEV_SSE2(p1, p0, q0, q1, hev_thresh, ¬_hev); + + // convert to signed values + FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1); + + t1 = _mm_subs_epi8(*p1, *q1); // p1 - q1 + t1 = _mm_andnot_si128(not_hev, t1); // hev(p1 - q1) + t2 = _mm_subs_epi8(*q0, *p0); // q0 - p0 + t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 1 * (q0 - p0) + t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 2 * (q0 - p0) + t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 3 * (q0 - p0) + t1 = _mm_and_si128(t1, *mask); // mask filter values we don't care about + + t2 = _mm_adds_epi8(t1, k3); // 3 * (q0 - p0) + hev(p1 - q1) + 3 + t3 = _mm_adds_epi8(t1, k4); // 3 * (q0 - p0) + hev(p1 - q1) + 4 + SignedShift8b_SSE2(&t2); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3 + SignedShift8b_SSE2(&t3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3 + *p0 = _mm_adds_epi8(*p0, t2); // p0 += t2 + *q0 = _mm_subs_epi8(*q0, t3); // q0 -= t3 + FLIP_SIGN_BIT2(*p0, *q0); + + // this is equivalent to signed (a + 1) >> 1 calculation + t2 = _mm_add_epi8(t3, sign_bit); + t3 = _mm_avg_epu8(t2, zero); + t3 = _mm_sub_epi8(t3, k64); + + t3 = _mm_and_si128(not_hev, t3); // if !hev + *q1 = _mm_subs_epi8(*q1, t3); // q1 -= t3 + *p1 = _mm_adds_epi8(*p1, t3); // p1 += t3 + FLIP_SIGN_BIT2(*p1, *q1); +} + +// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2) +static WEBP_INLINE void DoFilter6_SSE2(__m128i* const p2, __m128i* const p1, + __m128i* const p0, __m128i* const q0, + __m128i* const q1, __m128i* const q2, + const __m128i* const mask, + int hev_thresh) { + const __m128i zero = _mm_setzero_si128(); + const __m128i sign_bit = _mm_set1_epi8((char)0x80); + __m128i a, not_hev; + + // compute hev mask + GetNotHEV_SSE2(p1, p0, q0, q1, hev_thresh, ¬_hev); + + FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1); + FLIP_SIGN_BIT2(*p2, *q2); + GetBaseDelta_SSE2(p1, p0, q0, q1, &a); + + { // do simple filter on pixels with hev + const __m128i m = _mm_andnot_si128(not_hev, *mask); + const __m128i f = _mm_and_si128(a, m); + DoSimpleFilter_SSE2(p0, q0, &f); + } + + { // do strong filter on pixels with not hev + const __m128i k9 = _mm_set1_epi16(0x0900); + const __m128i k63 = _mm_set1_epi16(63); + + const __m128i m = _mm_and_si128(not_hev, *mask); + const __m128i f = _mm_and_si128(a, m); + + const __m128i f_lo = _mm_unpacklo_epi8(zero, f); + const __m128i f_hi = _mm_unpackhi_epi8(zero, f); + + const __m128i f9_lo = _mm_mulhi_epi16(f_lo, k9); // Filter (lo) * 9 + const __m128i f9_hi = _mm_mulhi_epi16(f_hi, k9); // Filter (hi) * 9 + + const __m128i a2_lo = _mm_add_epi16(f9_lo, k63); // Filter * 9 + 63 + const __m128i a2_hi = _mm_add_epi16(f9_hi, k63); // Filter * 9 + 63 + + const __m128i a1_lo = _mm_add_epi16(a2_lo, f9_lo); // Filter * 18 + 63 + const __m128i a1_hi = _mm_add_epi16(a2_hi, f9_hi); // Filter * 18 + 63 + + const __m128i a0_lo = _mm_add_epi16(a1_lo, f9_lo); // Filter * 27 + 63 + const __m128i a0_hi = _mm_add_epi16(a1_hi, f9_hi); // Filter * 27 + 63 + + Update2Pixels_SSE2(p2, q2, &a2_lo, &a2_hi); + Update2Pixels_SSE2(p1, q1, &a1_lo, &a1_hi); + Update2Pixels_SSE2(p0, q0, &a0_lo, &a0_hi); + } +} + +// reads 8 rows across a vertical edge. +static WEBP_INLINE void Load8x4_SSE2(const uint8_t* const b, int stride, + __m128i* const p, __m128i* const q) { + // A0 = 63 62 61 60 23 22 21 20 43 42 41 40 03 02 01 00 + // A1 = 73 72 71 70 33 32 31 30 53 52 51 50 13 12 11 10 + const __m128i A0 = _mm_set_epi32( + WebPMemToInt32(&b[6 * stride]), WebPMemToInt32(&b[2 * stride]), + WebPMemToInt32(&b[4 * stride]), WebPMemToInt32(&b[0 * stride])); + const __m128i A1 = _mm_set_epi32( + WebPMemToInt32(&b[7 * stride]), WebPMemToInt32(&b[3 * stride]), + WebPMemToInt32(&b[5 * stride]), WebPMemToInt32(&b[1 * stride])); + + // B0 = 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00 + // B1 = 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20 + const __m128i B0 = _mm_unpacklo_epi8(A0, A1); + const __m128i B1 = _mm_unpackhi_epi8(A0, A1); + + // C0 = 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + // C1 = 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40 + const __m128i C0 = _mm_unpacklo_epi16(B0, B1); + const __m128i C1 = _mm_unpackhi_epi16(B0, B1); + + // *p = 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + // *q = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + *p = _mm_unpacklo_epi32(C0, C1); + *q = _mm_unpackhi_epi32(C0, C1); +} + +static WEBP_INLINE void Load16x4_SSE2(const uint8_t* const r0, + const uint8_t* const r8, + int stride, + __m128i* const p1, __m128i* const p0, + __m128i* const q0, __m128i* const q1) { + // Assume the pixels around the edge (|) are numbered as follows + // 00 01 | 02 03 + // 10 11 | 12 13 + // ... | ... + // e0 e1 | e2 e3 + // f0 f1 | f2 f3 + // + // r0 is pointing to the 0th row (00) + // r8 is pointing to the 8th row (80) + + // Load + // p1 = 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + // q0 = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + // p0 = f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80 + // q1 = f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82 + Load8x4_SSE2(r0, stride, p1, q0); + Load8x4_SSE2(r8, stride, p0, q1); + + { + // p1 = f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + // p0 = f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + // q0 = f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + // q1 = f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + const __m128i t1 = *p1; + const __m128i t2 = *q0; + *p1 = _mm_unpacklo_epi64(t1, *p0); + *p0 = _mm_unpackhi_epi64(t1, *p0); + *q0 = _mm_unpacklo_epi64(t2, *q1); + *q1 = _mm_unpackhi_epi64(t2, *q1); + } +} + +static WEBP_INLINE void Store4x4_SSE2(__m128i* const x, + uint8_t* dst, int stride) { + int i; + for (i = 0; i < 4; ++i, dst += stride) { + WebPInt32ToMem(dst, _mm_cvtsi128_si32(*x)); + *x = _mm_srli_si128(*x, 4); + } +} + +// Transpose back and store +static WEBP_INLINE void Store16x4_SSE2(const __m128i* const p1, + const __m128i* const p0, + const __m128i* const q0, + const __m128i* const q1, + uint8_t* r0, uint8_t* r8, + int stride) { + __m128i t1, p1_s, p0_s, q0_s, q1_s; + + // p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00 + // p1 = f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80 + t1 = *p0; + p0_s = _mm_unpacklo_epi8(*p1, t1); + p1_s = _mm_unpackhi_epi8(*p1, t1); + + // q0 = 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + // q1 = f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + t1 = *q0; + q0_s = _mm_unpacklo_epi8(t1, *q1); + q1_s = _mm_unpackhi_epi8(t1, *q1); + + // p0 = 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 + // q0 = 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40 + t1 = p0_s; + p0_s = _mm_unpacklo_epi16(t1, q0_s); + q0_s = _mm_unpackhi_epi16(t1, q0_s); + + // p1 = b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80 + // q1 = f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0 + t1 = p1_s; + p1_s = _mm_unpacklo_epi16(t1, q1_s); + q1_s = _mm_unpackhi_epi16(t1, q1_s); + + Store4x4_SSE2(&p0_s, r0, stride); + r0 += 4 * stride; + Store4x4_SSE2(&q0_s, r0, stride); + + Store4x4_SSE2(&p1_s, r8, stride); + r8 += 4 * stride; + Store4x4_SSE2(&q1_s, r8, stride); +} + +//------------------------------------------------------------------------------ +// Simple In-loop filtering (Paragraph 15.2) + +static void SimpleVFilter16_SSE2(uint8_t* p, int stride, int thresh) { + // Load + __m128i p1 = _mm_loadu_si128((__m128i*)&p[-2 * stride]); + __m128i p0 = _mm_loadu_si128((__m128i*)&p[-stride]); + __m128i q0 = _mm_loadu_si128((__m128i*)&p[0]); + __m128i q1 = _mm_loadu_si128((__m128i*)&p[stride]); + + DoFilter2_SSE2(&p1, &p0, &q0, &q1, thresh); + + // Store + _mm_storeu_si128((__m128i*)&p[-stride], p0); + _mm_storeu_si128((__m128i*)&p[0], q0); +} + +static void SimpleHFilter16_SSE2(uint8_t* p, int stride, int thresh) { + __m128i p1, p0, q0, q1; + + p -= 2; // beginning of p1 + + Load16x4_SSE2(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1); + DoFilter2_SSE2(&p1, &p0, &q0, &q1, thresh); + Store16x4_SSE2(&p1, &p0, &q0, &q1, p, p + 8 * stride, stride); +} + +static void SimpleVFilter16i_SSE2(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + SimpleVFilter16_SSE2(p, stride, thresh); + } +} + +static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + SimpleHFilter16_SSE2(p, stride, thresh); + } +} + +//------------------------------------------------------------------------------ +// Complex In-loop filtering (Paragraph 15.3) + +#define MAX_DIFF1(p3, p2, p1, p0, m) do { \ + (m) = MM_ABS(p1, p0); \ + (m) = _mm_max_epu8(m, MM_ABS(p3, p2)); \ + (m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \ +} while (0) + +#define MAX_DIFF2(p3, p2, p1, p0, m) do { \ + (m) = _mm_max_epu8(m, MM_ABS(p1, p0)); \ + (m) = _mm_max_epu8(m, MM_ABS(p3, p2)); \ + (m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \ +} while (0) + +#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) do { \ + (e1) = _mm_loadu_si128((__m128i*)&(p)[0 * (stride)]); \ + (e2) = _mm_loadu_si128((__m128i*)&(p)[1 * (stride)]); \ + (e3) = _mm_loadu_si128((__m128i*)&(p)[2 * (stride)]); \ + (e4) = _mm_loadu_si128((__m128i*)&(p)[3 * (stride)]); \ +} while (0) + +#define LOADUV_H_EDGE(p, u, v, stride) do { \ + const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \ + const __m128i V = _mm_loadl_epi64((__m128i*)&(v)[(stride)]); \ + (p) = _mm_unpacklo_epi64(U, V); \ +} while (0) + +#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) do { \ + LOADUV_H_EDGE(e1, u, v, 0 * (stride)); \ + LOADUV_H_EDGE(e2, u, v, 1 * (stride)); \ + LOADUV_H_EDGE(e3, u, v, 2 * (stride)); \ + LOADUV_H_EDGE(e4, u, v, 3 * (stride)); \ +} while (0) + +#define STOREUV(p, u, v, stride) do { \ + _mm_storel_epi64((__m128i*)&(u)[(stride)], p); \ + (p) = _mm_srli_si128(p, 8); \ + _mm_storel_epi64((__m128i*)&(v)[(stride)], p); \ +} while (0) + +static WEBP_INLINE void ComplexMask_SSE2(const __m128i* const p1, + const __m128i* const p0, + const __m128i* const q0, + const __m128i* const q1, + int thresh, int ithresh, + __m128i* const mask) { + const __m128i it = _mm_set1_epi8(ithresh); + const __m128i diff = _mm_subs_epu8(*mask, it); + const __m128i thresh_mask = _mm_cmpeq_epi8(diff, _mm_setzero_si128()); + __m128i filter_mask; + NeedsFilter_SSE2(p1, p0, q0, q1, thresh, &filter_mask); + *mask = _mm_and_si128(thresh_mask, filter_mask); +} + +// on macroblock edges +static void VFilter16_SSE2(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i t1; + __m128i mask; + __m128i p2, p1, p0, q0, q1, q2; + + // Load p3, p2, p1, p0 + LOAD_H_EDGES4(p - 4 * stride, stride, t1, p2, p1, p0); + MAX_DIFF1(t1, p2, p1, p0, mask); + + // Load q0, q1, q2, q3 + LOAD_H_EDGES4(p, stride, q0, q1, q2, t1); + MAX_DIFF2(t1, q2, q1, q0, mask); + + ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask); + DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh); + + // Store + _mm_storeu_si128((__m128i*)&p[-3 * stride], p2); + _mm_storeu_si128((__m128i*)&p[-2 * stride], p1); + _mm_storeu_si128((__m128i*)&p[-1 * stride], p0); + _mm_storeu_si128((__m128i*)&p[+0 * stride], q0); + _mm_storeu_si128((__m128i*)&p[+1 * stride], q1); + _mm_storeu_si128((__m128i*)&p[+2 * stride], q2); +} + +static void HFilter16_SSE2(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i p3, p2, p1, p0, q0, q1, q2, q3; + + uint8_t* const b = p - 4; + Load16x4_SSE2(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0); + MAX_DIFF1(p3, p2, p1, p0, mask); + + Load16x4_SSE2(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); + MAX_DIFF2(q3, q2, q1, q0, mask); + + ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask); + DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh); + + Store16x4_SSE2(&p3, &p2, &p1, &p0, b, b + 8 * stride, stride); + Store16x4_SSE2(&q0, &q1, &q2, &q3, p, p + 8 * stride, stride); +} + +// on three inner edges +static void VFilter16i_SSE2(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + __m128i p3, p2, p1, p0; // loop invariants + + LOAD_H_EDGES4(p, stride, p3, p2, p1, p0); // prologue + + for (k = 3; k > 0; --k) { + __m128i mask, tmp1, tmp2; + uint8_t* const b = p + 2 * stride; // beginning of p1 + p += 4 * stride; + + MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask + LOAD_H_EDGES4(p, stride, p3, p2, tmp1, tmp2); + MAX_DIFF2(p3, p2, tmp1, tmp2, mask); + + // p3 and p2 are not just temporary variables here: they will be + // re-used for next span. And q2/q3 will become p1/p0 accordingly. + ComplexMask_SSE2(&p1, &p0, &p3, &p2, thresh, ithresh, &mask); + DoFilter4_SSE2(&p1, &p0, &p3, &p2, &mask, hev_thresh); + + // Store + _mm_storeu_si128((__m128i*)&b[0 * stride], p1); + _mm_storeu_si128((__m128i*)&b[1 * stride], p0); + _mm_storeu_si128((__m128i*)&b[2 * stride], p3); + _mm_storeu_si128((__m128i*)&b[3 * stride], p2); + + // rotate samples + p1 = tmp1; + p0 = tmp2; + } +} + +static void HFilter16i_SSE2(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + __m128i p3, p2, p1, p0; // loop invariants + + Load16x4_SSE2(p, p + 8 * stride, stride, &p3, &p2, &p1, &p0); // prologue + + for (k = 3; k > 0; --k) { + __m128i mask, tmp1, tmp2; + uint8_t* const b = p + 2; // beginning of p1 + + p += 4; // beginning of q0 (and next span) + + MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask + Load16x4_SSE2(p, p + 8 * stride, stride, &p3, &p2, &tmp1, &tmp2); + MAX_DIFF2(p3, p2, tmp1, tmp2, mask); + + ComplexMask_SSE2(&p1, &p0, &p3, &p2, thresh, ithresh, &mask); + DoFilter4_SSE2(&p1, &p0, &p3, &p2, &mask, hev_thresh); + + Store16x4_SSE2(&p1, &p0, &p3, &p2, b, b + 8 * stride, stride); + + // rotate samples + p1 = tmp1; + p0 = tmp2; + } +} + +// 8-pixels wide variant, for chroma filtering +static void VFilter8_SSE2(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i t1, p2, p1, p0, q0, q1, q2; + + // Load p3, p2, p1, p0 + LOADUV_H_EDGES4(u - 4 * stride, v - 4 * stride, stride, t1, p2, p1, p0); + MAX_DIFF1(t1, p2, p1, p0, mask); + + // Load q0, q1, q2, q3 + LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1); + MAX_DIFF2(t1, q2, q1, q0, mask); + + ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask); + DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh); + + // Store + STOREUV(p2, u, v, -3 * stride); + STOREUV(p1, u, v, -2 * stride); + STOREUV(p0, u, v, -1 * stride); + STOREUV(q0, u, v, 0 * stride); + STOREUV(q1, u, v, 1 * stride); + STOREUV(q2, u, v, 2 * stride); +} + +static void HFilter8_SSE2(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i p3, p2, p1, p0, q0, q1, q2, q3; + + uint8_t* const tu = u - 4; + uint8_t* const tv = v - 4; + Load16x4_SSE2(tu, tv, stride, &p3, &p2, &p1, &p0); + MAX_DIFF1(p3, p2, p1, p0, mask); + + Load16x4_SSE2(u, v, stride, &q0, &q1, &q2, &q3); + MAX_DIFF2(q3, q2, q1, q0, mask); + + ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask); + DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh); + + Store16x4_SSE2(&p3, &p2, &p1, &p0, tu, tv, stride); + Store16x4_SSE2(&q0, &q1, &q2, &q3, u, v, stride); +} + +static void VFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i t1, t2, p1, p0, q0, q1; + + // Load p3, p2, p1, p0 + LOADUV_H_EDGES4(u, v, stride, t2, t1, p1, p0); + MAX_DIFF1(t2, t1, p1, p0, mask); + + u += 4 * stride; + v += 4 * stride; + + // Load q0, q1, q2, q3 + LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2); + MAX_DIFF2(t2, t1, q1, q0, mask); + + ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask); + DoFilter4_SSE2(&p1, &p0, &q0, &q1, &mask, hev_thresh); + + // Store + STOREUV(p1, u, v, -2 * stride); + STOREUV(p0, u, v, -1 * stride); + STOREUV(q0, u, v, 0 * stride); + STOREUV(q1, u, v, 1 * stride); +} + +static void HFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i t1, t2, p1, p0, q0, q1; + Load16x4_SSE2(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0 + MAX_DIFF1(t2, t1, p1, p0, mask); + + u += 4; // beginning of q0 + v += 4; + Load16x4_SSE2(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3 + MAX_DIFF2(t2, t1, q1, q0, mask); + + ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask); + DoFilter4_SSE2(&p1, &p0, &q0, &q1, &mask, hev_thresh); + + u -= 2; // beginning of p1 + v -= 2; + Store16x4_SSE2(&p1, &p0, &q0, &q1, u, v, stride); +} + +//------------------------------------------------------------------------------ +// 4x4 predictions + +#define DST(x, y) dst[(x) + (y) * BPS] +#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) + +// We use the following 8b-arithmetic tricks: +// (a + 2 * b + c + 2) >> 2 = (AC + b + 1) >> 1 +// where: AC = (a + c) >> 1 = [(a + c + 1) >> 1] - [(a^c) & 1] +// and: +// (a + 2 * b + c + 2) >> 2 = (AB + BC + 1) >> 1 - (ab|bc)&lsb +// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1 +// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1 + +static void VE4_SSE2(uint8_t* dst) { // vertical + const __m128i one = _mm_set1_epi8(1); + const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS - 1)); + const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1); + const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2); + const __m128i a = _mm_avg_epu8(ABCDEFGH, CDEFGH00); + const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGH00), one); + const __m128i b = _mm_subs_epu8(a, lsb); + const __m128i avg = _mm_avg_epu8(b, BCDEFGH0); + const int vals = _mm_cvtsi128_si32(avg); + int i; + for (i = 0; i < 4; ++i) { + WebPInt32ToMem(dst + i * BPS, vals); + } +} + +static void LD4_SSE2(uint8_t* dst) { // Down-Left + const __m128i one = _mm_set1_epi8(1); + const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS)); + const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1); + const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2); + const __m128i CDEFGHH0 = _mm_insert_epi16(CDEFGH00, dst[-BPS + 7], 3); + const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, CDEFGHH0); + const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGHH0), one); + const __m128i avg2 = _mm_subs_epu8(avg1, lsb); + const __m128i abcdefg = _mm_avg_epu8(avg2, BCDEFGH0); + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcdefg )); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1))); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2))); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3))); +} + +static void VR4_SSE2(uint8_t* dst) { // Vertical-Right + const __m128i one = _mm_set1_epi8(1); + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int X = dst[-1 - BPS]; + const __m128i XABCD = _mm_loadl_epi64((__m128i*)(dst - BPS - 1)); + const __m128i ABCD0 = _mm_srli_si128(XABCD, 1); + const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0); + const __m128i _XABCD = _mm_slli_si128(XABCD, 1); + const __m128i IXABCD = _mm_insert_epi16(_XABCD, (short)(I | (X << 8)), 0); + const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0); + const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one); + const __m128i avg2 = _mm_subs_epu8(avg1, lsb); + const __m128i efgh = _mm_avg_epu8(avg2, XABCD); + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcd )); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( efgh )); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1))); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1))); + + // these two are hard to implement in SSE2, so we keep the C-version: + DST(0, 2) = AVG3(J, I, X); + DST(0, 3) = AVG3(K, J, I); +} + +static void VL4_SSE2(uint8_t* dst) { // Vertical-Left + const __m128i one = _mm_set1_epi8(1); + const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS)); + const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1); + const __m128i CDEFGH__ = _mm_srli_si128(ABCDEFGH, 2); + const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, BCDEFGH_); + const __m128i avg2 = _mm_avg_epu8(CDEFGH__, BCDEFGH_); + const __m128i avg3 = _mm_avg_epu8(avg1, avg2); + const __m128i lsb1 = _mm_and_si128(_mm_xor_si128(avg1, avg2), one); + const __m128i ab = _mm_xor_si128(ABCDEFGH, BCDEFGH_); + const __m128i bc = _mm_xor_si128(CDEFGH__, BCDEFGH_); + const __m128i abbc = _mm_or_si128(ab, bc); + const __m128i lsb2 = _mm_and_si128(abbc, lsb1); + const __m128i avg4 = _mm_subs_epu8(avg3, lsb2); + const uint32_t extra_out = + (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(avg4, 4)); + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( avg1 )); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( avg4 )); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1))); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1))); + + // these two are hard to get and irregular + DST(3, 2) = (extra_out >> 0) & 0xff; + DST(3, 3) = (extra_out >> 8) & 0xff; +} + +static void RD4_SSE2(uint8_t* dst) { // Down-right + const __m128i one = _mm_set1_epi8(1); + const __m128i XABCD = _mm_loadl_epi64((__m128i*)(dst - BPS - 1)); + const __m128i ____XABCD = _mm_slli_si128(XABCD, 4); + const uint32_t I = dst[-1 + 0 * BPS]; + const uint32_t J = dst[-1 + 1 * BPS]; + const uint32_t K = dst[-1 + 2 * BPS]; + const uint32_t L = dst[-1 + 3 * BPS]; + const __m128i LKJI_____ = + _mm_cvtsi32_si128((int)(L | (K << 8) | (J << 16) | (I << 24))); + const __m128i LKJIXABCD = _mm_or_si128(LKJI_____, ____XABCD); + const __m128i KJIXABCD_ = _mm_srli_si128(LKJIXABCD, 1); + const __m128i JIXABCD__ = _mm_srli_si128(LKJIXABCD, 2); + const __m128i avg1 = _mm_avg_epu8(JIXABCD__, LKJIXABCD); + const __m128i lsb = _mm_and_si128(_mm_xor_si128(JIXABCD__, LKJIXABCD), one); + const __m128i avg2 = _mm_subs_epu8(avg1, lsb); + const __m128i abcdefg = _mm_avg_epu8(avg2, KJIXABCD_); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32( abcdefg )); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1))); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2))); + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3))); +} + +#undef DST +#undef AVG3 + +//------------------------------------------------------------------------------ +// Luma 16x16 + +static WEBP_INLINE void TrueMotion_SSE2(uint8_t* dst, int size) { + const uint8_t* top = dst - BPS; + const __m128i zero = _mm_setzero_si128(); + int y; + if (size == 4) { + const __m128i top_values = _mm_cvtsi32_si128(WebPMemToInt32(top)); + const __m128i top_base = _mm_unpacklo_epi8(top_values, zero); + for (y = 0; y < 4; ++y, dst += BPS) { + const int val = dst[-1] - top[-1]; + const __m128i base = _mm_set1_epi16(val); + const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero); + WebPInt32ToMem(dst, _mm_cvtsi128_si32(out)); + } + } else if (size == 8) { + const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); + const __m128i top_base = _mm_unpacklo_epi8(top_values, zero); + for (y = 0; y < 8; ++y, dst += BPS) { + const int val = dst[-1] - top[-1]; + const __m128i base = _mm_set1_epi16(val); + const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero); + _mm_storel_epi64((__m128i*)dst, out); + } + } else { + const __m128i top_values = _mm_loadu_si128((const __m128i*)top); + const __m128i top_base_0 = _mm_unpacklo_epi8(top_values, zero); + const __m128i top_base_1 = _mm_unpackhi_epi8(top_values, zero); + for (y = 0; y < 16; ++y, dst += BPS) { + const int val = dst[-1] - top[-1]; + const __m128i base = _mm_set1_epi16(val); + const __m128i out_0 = _mm_add_epi16(base, top_base_0); + const __m128i out_1 = _mm_add_epi16(base, top_base_1); + const __m128i out = _mm_packus_epi16(out_0, out_1); + _mm_storeu_si128((__m128i*)dst, out); + } + } +} + +static void TM4_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 4); } +static void TM8uv_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 8); } +static void TM16_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 16); } + +static void VE16_SSE2(uint8_t* dst) { + const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS)); + int j; + for (j = 0; j < 16; ++j) { + _mm_storeu_si128((__m128i*)(dst + j * BPS), top); + } +} + +static void HE16_SSE2(uint8_t* dst) { // horizontal + int j; + for (j = 16; j > 0; --j) { + const __m128i values = _mm_set1_epi8((char)dst[-1]); + _mm_storeu_si128((__m128i*)dst, values); + dst += BPS; + } +} + +static WEBP_INLINE void Put16_SSE2(uint8_t v, uint8_t* dst) { + int j; + const __m128i values = _mm_set1_epi8((char)v); + for (j = 0; j < 16; ++j) { + _mm_storeu_si128((__m128i*)(dst + j * BPS), values); + } +} + +static void DC16_SSE2(uint8_t* dst) { // DC + const __m128i zero = _mm_setzero_si128(); + const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS)); + const __m128i sad8x2 = _mm_sad_epu8(top, zero); + // sum the two sads: sad8x2[0:1] + sad8x2[8:9] + const __m128i sum = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2)); + int left = 0; + int j; + for (j = 0; j < 16; ++j) { + left += dst[-1 + j * BPS]; + } + { + const int DC = _mm_cvtsi128_si32(sum) + left + 16; + Put16_SSE2(DC >> 5, dst); + } +} + +static void DC16NoTop_SSE2(uint8_t* dst) { // DC with top samples unavailable + int DC = 8; + int j; + for (j = 0; j < 16; ++j) { + DC += dst[-1 + j * BPS]; + } + Put16_SSE2(DC >> 4, dst); +} + +static void DC16NoLeft_SSE2(uint8_t* dst) { // DC with left samples unavailable + const __m128i zero = _mm_setzero_si128(); + const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS)); + const __m128i sad8x2 = _mm_sad_epu8(top, zero); + // sum the two sads: sad8x2[0:1] + sad8x2[8:9] + const __m128i sum = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2)); + const int DC = _mm_cvtsi128_si32(sum) + 8; + Put16_SSE2(DC >> 4, dst); +} + +static void DC16NoTopLeft_SSE2(uint8_t* dst) { // DC with no top & left samples + Put16_SSE2(0x80, dst); +} + +//------------------------------------------------------------------------------ +// Chroma + +static void VE8uv_SSE2(uint8_t* dst) { // vertical + int j; + const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS)); + for (j = 0; j < 8; ++j) { + _mm_storel_epi64((__m128i*)(dst + j * BPS), top); + } +} + +// helper for chroma-DC predictions +static WEBP_INLINE void Put8x8uv_SSE2(uint8_t v, uint8_t* dst) { + int j; + const __m128i values = _mm_set1_epi8((char)v); + for (j = 0; j < 8; ++j) { + _mm_storel_epi64((__m128i*)(dst + j * BPS), values); + } +} + +static void DC8uv_SSE2(uint8_t* dst) { // DC + const __m128i zero = _mm_setzero_si128(); + const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS)); + const __m128i sum = _mm_sad_epu8(top, zero); + int left = 0; + int j; + for (j = 0; j < 8; ++j) { + left += dst[-1 + j * BPS]; + } + { + const int DC = _mm_cvtsi128_si32(sum) + left + 8; + Put8x8uv_SSE2(DC >> 4, dst); + } +} + +static void DC8uvNoLeft_SSE2(uint8_t* dst) { // DC with no left samples + const __m128i zero = _mm_setzero_si128(); + const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS)); + const __m128i sum = _mm_sad_epu8(top, zero); + const int DC = _mm_cvtsi128_si32(sum) + 4; + Put8x8uv_SSE2(DC >> 3, dst); +} + +static void DC8uvNoTop_SSE2(uint8_t* dst) { // DC with no top samples + int dc0 = 4; + int i; + for (i = 0; i < 8; ++i) { + dc0 += dst[-1 + i * BPS]; + } + Put8x8uv_SSE2(dc0 >> 3, dst); +} + +static void DC8uvNoTopLeft_SSE2(uint8_t* dst) { // DC with nothing + Put8x8uv_SSE2(0x80, dst); +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE2(void) { + VP8Transform = Transform_SSE2; +#if (USE_TRANSFORM_AC3 == 1) + VP8TransformAC3 = TransformAC3_SSE2; +#endif + + VP8VFilter16 = VFilter16_SSE2; + VP8HFilter16 = HFilter16_SSE2; + VP8VFilter8 = VFilter8_SSE2; + VP8HFilter8 = HFilter8_SSE2; + VP8VFilter16i = VFilter16i_SSE2; + VP8HFilter16i = HFilter16i_SSE2; + VP8VFilter8i = VFilter8i_SSE2; + VP8HFilter8i = HFilter8i_SSE2; + + VP8SimpleVFilter16 = SimpleVFilter16_SSE2; + VP8SimpleHFilter16 = SimpleHFilter16_SSE2; + VP8SimpleVFilter16i = SimpleVFilter16i_SSE2; + VP8SimpleHFilter16i = SimpleHFilter16i_SSE2; + + VP8PredLuma4[1] = TM4_SSE2; + VP8PredLuma4[2] = VE4_SSE2; + VP8PredLuma4[4] = RD4_SSE2; + VP8PredLuma4[5] = VR4_SSE2; + VP8PredLuma4[6] = LD4_SSE2; + VP8PredLuma4[7] = VL4_SSE2; + + VP8PredLuma16[0] = DC16_SSE2; + VP8PredLuma16[1] = TM16_SSE2; + VP8PredLuma16[2] = VE16_SSE2; + VP8PredLuma16[3] = HE16_SSE2; + VP8PredLuma16[4] = DC16NoTop_SSE2; + VP8PredLuma16[5] = DC16NoLeft_SSE2; + VP8PredLuma16[6] = DC16NoTopLeft_SSE2; + + VP8PredChroma8[0] = DC8uv_SSE2; + VP8PredChroma8[1] = TM8uv_SSE2; + VP8PredChroma8[2] = VE8uv_SSE2; + VP8PredChroma8[4] = DC8uvNoTop_SSE2; + VP8PredChroma8[5] = DC8uvNoLeft_SSE2; + VP8PredChroma8[6] = DC8uvNoTopLeft_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(VP8DspInitSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/dec_sse41.c b/libraries/webp/src/dsp/dec_sse41.c new file mode 100644 index 00000000000..08a36302722 --- /dev/null +++ b/libraries/webp/src/dsp/dec_sse41.c @@ -0,0 +1,46 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE4 version of some decoding functions. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE41) + +#include +#include "src/dec/vp8i_dec.h" +#include "src/utils/utils.h" + +static void HE16_SSE41(uint8_t* dst) { // horizontal + int j; + const __m128i kShuffle3 = _mm_set1_epi8(3); + for (j = 16; j > 0; --j) { + const __m128i in = _mm_cvtsi32_si128(WebPMemToInt32(dst - 4)); + const __m128i values = _mm_shuffle_epi8(in, kShuffle3); + _mm_storeu_si128((__m128i*)dst, values); + dst += BPS; + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE41(void) { + VP8PredLuma16[3] = HE16_SSE41; +} + +#else // !WEBP_USE_SSE41 + +WEBP_DSP_INIT_STUB(VP8DspInitSSE41) + +#endif // WEBP_USE_SSE41 diff --git a/libraries/webp/src/dsp/dsp.h b/libraries/webp/src/dsp/dsp.h new file mode 100644 index 00000000000..b22be1dc5a1 --- /dev/null +++ b/libraries/webp/src/dsp/dsp.h @@ -0,0 +1,509 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DSP_DSP_H_ +#define WEBP_DSP_DSP_H_ + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include "src/dsp/cpu.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BPS 32 // this is the common stride for enc/dec + +//------------------------------------------------------------------------------ +// WEBP_RESTRICT + +// Declares a pointer with the restrict type qualifier if available. +// This allows code to hint to the compiler that only this pointer references a +// particular object or memory region within the scope of the block in which it +// is declared. This may allow for improved optimizations due to the lack of +// pointer aliasing. See also: +// https://en.cppreference.com/w/c/language/restrict +#if defined(__GNUC__) +#define WEBP_RESTRICT __restrict__ +#elif defined(_MSC_VER) +#define WEBP_RESTRICT __restrict +#else +#define WEBP_RESTRICT +#endif + + +//------------------------------------------------------------------------------ +// Init stub generator + +// Defines an init function stub to ensure each module exposes a symbol, +// avoiding a compiler warning. +#define WEBP_DSP_INIT_STUB(func) \ + extern void func(void); \ + void func(void) {} + +//------------------------------------------------------------------------------ +// Encoding + +// Transforms +// VP8Idct: Does one of two inverse transforms. If do_two is set, the transforms +// will be done for (ref, in, dst) and (ref + 4, in + 16, dst + 4). +typedef void (*VP8Idct)(const uint8_t* ref, const int16_t* in, uint8_t* dst, + int do_two); +typedef void (*VP8Fdct)(const uint8_t* src, const uint8_t* ref, int16_t* out); +typedef void (*VP8WHT)(const int16_t* in, int16_t* out); +extern VP8Idct VP8ITransform; +extern VP8Fdct VP8FTransform; +extern VP8Fdct VP8FTransform2; // performs two transforms at a time +extern VP8WHT VP8FTransformWHT; +// Predictions +// *dst is the destination block. *top and *left can be NULL. +typedef void (*VP8IntraPreds)(uint8_t* dst, const uint8_t* left, + const uint8_t* top); +typedef void (*VP8Intra4Preds)(uint8_t* dst, const uint8_t* top); +extern VP8Intra4Preds VP8EncPredLuma4; +extern VP8IntraPreds VP8EncPredLuma16; +extern VP8IntraPreds VP8EncPredChroma8; + +typedef int (*VP8Metric)(const uint8_t* pix, const uint8_t* ref); +extern VP8Metric VP8SSE16x16, VP8SSE16x8, VP8SSE8x8, VP8SSE4x4; +typedef int (*VP8WMetric)(const uint8_t* pix, const uint8_t* ref, + const uint16_t* const weights); +// The weights for VP8TDisto4x4 and VP8TDisto16x16 contain a row-major +// 4 by 4 symmetric matrix. +extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16; + +// Compute the average (DC) of four 4x4 blocks. +// Each sub-4x4 block #i sum is stored in dc[i]. +typedef void (*VP8MeanMetric)(const uint8_t* ref, uint32_t dc[4]); +extern VP8MeanMetric VP8Mean16x4; + +typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst); +extern VP8BlockCopy VP8Copy4x4; +extern VP8BlockCopy VP8Copy16x8; +// Quantization +struct VP8Matrix; // forward declaration +typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16], + const struct VP8Matrix* const mtx); +// Same as VP8QuantizeBlock, but quantizes two consecutive blocks. +typedef int (*VP8Quantize2Blocks)(int16_t in[32], int16_t out[32], + const struct VP8Matrix* const mtx); + +extern VP8QuantizeBlock VP8EncQuantizeBlock; +extern VP8Quantize2Blocks VP8EncQuantize2Blocks; + +// specific to 2nd transform: +typedef int (*VP8QuantizeBlockWHT)(int16_t in[16], int16_t out[16], + const struct VP8Matrix* const mtx); +extern VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT; + +extern const int VP8DspScan[16 + 4 + 4]; + +// Collect histogram for susceptibility calculation. +#define MAX_COEFF_THRESH 31 // size of histogram used by CollectHistogram. +typedef struct { + // We only need to store max_value and last_non_zero, not the distribution. + int max_value; + int last_non_zero; +} VP8Histogram; +typedef void (*VP8CHisto)(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block, + VP8Histogram* const histo); +extern VP8CHisto VP8CollectHistogram; +// General-purpose util function to help VP8CollectHistogram(). +void VP8SetHistogramData(const int distribution[MAX_COEFF_THRESH + 1], + VP8Histogram* const histo); + +// must be called before using any of the above +void VP8EncDspInit(void); + +//------------------------------------------------------------------------------ +// cost functions (encoding) + +extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p) +// approximate cost per level: +extern const uint16_t VP8LevelFixedCosts[2047 /*MAX_LEVEL*/ + 1]; +extern const uint8_t VP8EncBands[16 + 1]; + +struct VP8Residual; +typedef void (*VP8SetResidualCoeffsFunc)(const int16_t* const coeffs, + struct VP8Residual* const res); +extern VP8SetResidualCoeffsFunc VP8SetResidualCoeffs; + +// Cost calculation function. +typedef int (*VP8GetResidualCostFunc)(int ctx0, + const struct VP8Residual* const res); +extern VP8GetResidualCostFunc VP8GetResidualCost; + +// must be called before anything using the above +void VP8EncDspCostInit(void); + +//------------------------------------------------------------------------------ +// SSIM / PSNR utils + +// struct for accumulating statistical moments +typedef struct { + uint32_t w; // sum(w_i) : sum of weights + uint32_t xm, ym; // sum(w_i * x_i), sum(w_i * y_i) + uint32_t xxm, xym, yym; // sum(w_i * x_i * x_i), etc. +} VP8DistoStats; + +// Compute the final SSIM value +// The non-clipped version assumes stats->w = (2 * VP8_SSIM_KERNEL + 1)^2. +double VP8SSIMFromStats(const VP8DistoStats* const stats); +double VP8SSIMFromStatsClipped(const VP8DistoStats* const stats); + +#define VP8_SSIM_KERNEL 3 // total size of the kernel: 2 * VP8_SSIM_KERNEL + 1 +typedef double (*VP8SSIMGetClippedFunc)(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2, + int xo, int yo, // center position + int W, int H); // plane dimension + +#if !defined(WEBP_REDUCE_SIZE) +// This version is called with the guarantee that you can load 8 bytes and +// 8 rows at offset src1 and src2 +typedef double (*VP8SSIMGetFunc)(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2); + +extern VP8SSIMGetFunc VP8SSIMGet; // unclipped / unchecked +extern VP8SSIMGetClippedFunc VP8SSIMGetClipped; // with clipping +#endif + +#if !defined(WEBP_DISABLE_STATS) +typedef uint32_t (*VP8AccumulateSSEFunc)(const uint8_t* src1, + const uint8_t* src2, int len); +extern VP8AccumulateSSEFunc VP8AccumulateSSE; +#endif + +// must be called before using any of the above directly +void VP8SSIMDspInit(void); + +//------------------------------------------------------------------------------ +// Decoding + +typedef void (*VP8DecIdct)(const int16_t* coeffs, uint8_t* dst); +// when doing two transforms, coeffs is actually int16_t[2][16]. +typedef void (*VP8DecIdct2)(const int16_t* coeffs, uint8_t* dst, int do_two); +extern VP8DecIdct2 VP8Transform; +extern VP8DecIdct VP8TransformAC3; +extern VP8DecIdct VP8TransformUV; +extern VP8DecIdct VP8TransformDC; +extern VP8DecIdct VP8TransformDCUV; +extern VP8WHT VP8TransformWHT; + +#define WEBP_TRANSFORM_AC3_C1 20091 +#define WEBP_TRANSFORM_AC3_C2 35468 +#define WEBP_TRANSFORM_AC3_MUL1(a) ((((a) * WEBP_TRANSFORM_AC3_C1) >> 16) + (a)) +#define WEBP_TRANSFORM_AC3_MUL2(a) (((a) * WEBP_TRANSFORM_AC3_C2) >> 16) + +// *dst is the destination block, with stride BPS. Boundary samples are +// assumed accessible when needed. +typedef void (*VP8PredFunc)(uint8_t* dst); +extern VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */]; +extern VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */]; +extern VP8PredFunc VP8PredLuma4[/* NUM_BMODES */]; + +// clipping tables (for filtering) +extern const int8_t* const VP8ksclip1; // clips [-1020, 1020] to [-128, 127] +extern const int8_t* const VP8ksclip2; // clips [-112, 112] to [-16, 15] +extern const uint8_t* const VP8kclip1; // clips [-255,511] to [0,255] +extern const uint8_t* const VP8kabs0; // abs(x) for x in [-255,255] +// must be called first +void VP8InitClipTables(void); + +// simple filter (only for luma) +typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh); +extern VP8SimpleFilterFunc VP8SimpleVFilter16; +extern VP8SimpleFilterFunc VP8SimpleHFilter16; +extern VP8SimpleFilterFunc VP8SimpleVFilter16i; // filter 3 inner edges +extern VP8SimpleFilterFunc VP8SimpleHFilter16i; + +// regular filter (on both macroblock edges and inner edges) +typedef void (*VP8LumaFilterFunc)(uint8_t* luma, int stride, + int thresh, int ithresh, int hev_t); +typedef void (*VP8ChromaFilterFunc)(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_t); +// on outer edge +extern VP8LumaFilterFunc VP8VFilter16; +extern VP8LumaFilterFunc VP8HFilter16; +extern VP8ChromaFilterFunc VP8VFilter8; +extern VP8ChromaFilterFunc VP8HFilter8; + +// on inner edge +extern VP8LumaFilterFunc VP8VFilter16i; // filtering 3 inner edges altogether +extern VP8LumaFilterFunc VP8HFilter16i; +extern VP8ChromaFilterFunc VP8VFilter8i; // filtering u and v altogether +extern VP8ChromaFilterFunc VP8HFilter8i; + +// Dithering. Combines dithering values (centered around 128) with dst[], +// according to: dst[] = clip(dst[] + (((dither[]-128) + 8) >> 4) +#define VP8_DITHER_DESCALE 4 +#define VP8_DITHER_DESCALE_ROUNDER (1 << (VP8_DITHER_DESCALE - 1)) +#define VP8_DITHER_AMP_BITS 7 +#define VP8_DITHER_AMP_CENTER (1 << VP8_DITHER_AMP_BITS) +extern void (*VP8DitherCombine8x8)(const uint8_t* dither, uint8_t* dst, + int dst_stride); + +// must be called before anything using the above +void VP8DspInit(void); + +//------------------------------------------------------------------------------ +// WebP I/O + +#define FANCY_UPSAMPLING // undefined to remove fancy upsampling support + +// Convert a pair of y/u/v lines together to the output rgb/a colorspace. +// bottom_y can be NULL if only one line of output is needed (at top/bottom). +typedef void (*WebPUpsampleLinePairFunc)( + const uint8_t* top_y, const uint8_t* bottom_y, + const uint8_t* top_u, const uint8_t* top_v, + const uint8_t* cur_u, const uint8_t* cur_v, + uint8_t* top_dst, uint8_t* bottom_dst, int len); + +#ifdef FANCY_UPSAMPLING + +// Fancy upsampling functions to convert YUV to RGB(A) modes +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +#endif // FANCY_UPSAMPLING + +// Per-row point-sampling methods. +typedef void (*WebPSamplerRowFunc)(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len); +// Generic function to apply 'WebPSamplerRowFunc' to the whole plane: +void WebPSamplerProcessPlane(const uint8_t* y, int y_stride, + const uint8_t* u, const uint8_t* v, int uv_stride, + uint8_t* dst, int dst_stride, + int width, int height, WebPSamplerRowFunc func); + +// Sampling functions to convert rows of YUV to RGB(A) +extern WebPSamplerRowFunc WebPSamplers[/* MODE_LAST */]; + +// General function for converting two lines of ARGB or RGBA. +// 'alpha_is_last' should be true if 0xff000000 is stored in memory as +// as 0x00, 0x00, 0x00, 0xff (little endian). +WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last); + +// YUV444->RGB converters +typedef void (*WebPYUV444Converter)(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len); + +extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; + +// Must be called before using the WebPUpsamplers[] (and for premultiplied +// colorspaces like rgbA, rgbA4444, etc) +void WebPInitUpsamplers(void); +// Must be called before using WebPSamplers[] +void WebPInitSamplers(void); +// Must be called before using WebPYUV444Converters[] +void WebPInitYUV444Converters(void); + +//------------------------------------------------------------------------------ +// ARGB -> YUV converters + +// Convert ARGB samples to luma Y. +extern void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width); +// Convert ARGB samples to U/V with downsampling. do_store should be '1' for +// even lines and '0' for odd ones. 'src_width' is the original width, not +// the U/V one. +extern void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v, + int src_width, int do_store); + +// Convert a row of accumulated (four-values) of rgba32 toward U/V +extern void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb, + uint8_t* u, uint8_t* v, int width); + +// Convert RGB or BGR to Y +extern void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width); +extern void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width); + +// used for plain-C fallback. +extern void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v, + int src_width, int do_store); +extern void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, + uint8_t* u, uint8_t* v, int width); + +// Must be called before using the above. +void WebPInitConvertARGBToYUV(void); + +//------------------------------------------------------------------------------ +// Rescaler + +struct WebPRescaler; + +// Import a row of data and save its contribution in the rescaler. +// 'channel' denotes the channel number to be imported. 'Expand' corresponds to +// the wrk->x_expand case. Otherwise, 'Shrink' is to be used. +typedef void (*WebPRescalerImportRowFunc)(struct WebPRescaler* const wrk, + const uint8_t* src); + +extern WebPRescalerImportRowFunc WebPRescalerImportRowExpand; +extern WebPRescalerImportRowFunc WebPRescalerImportRowShrink; + +// Export one row (starting at x_out position) from rescaler. +// 'Expand' corresponds to the wrk->y_expand case. +// Otherwise 'Shrink' is to be used +typedef void (*WebPRescalerExportRowFunc)(struct WebPRescaler* const wrk); +extern WebPRescalerExportRowFunc WebPRescalerExportRowExpand; +extern WebPRescalerExportRowFunc WebPRescalerExportRowShrink; + +// Plain-C implementation, as fall-back. +extern void WebPRescalerImportRowExpand_C(struct WebPRescaler* const wrk, + const uint8_t* src); +extern void WebPRescalerImportRowShrink_C(struct WebPRescaler* const wrk, + const uint8_t* src); +extern void WebPRescalerExportRowExpand_C(struct WebPRescaler* const wrk); +extern void WebPRescalerExportRowShrink_C(struct WebPRescaler* const wrk); + +// Main entry calls: +extern void WebPRescalerImportRow(struct WebPRescaler* const wrk, + const uint8_t* src); +// Export one row (starting at x_out position) from rescaler. +extern void WebPRescalerExportRow(struct WebPRescaler* const wrk); + +// Must be called first before using the above. +void WebPRescalerDspInit(void); + +//------------------------------------------------------------------------------ +// Utilities for processing transparent channel. + +// Apply alpha pre-multiply on an rgba, bgra or argb plane of size w * h. +// alpha_first should be 0 for argb, 1 for rgba or bgra (where alpha is last). +extern void (*WebPApplyAlphaMultiply)( + uint8_t* rgba, int alpha_first, int w, int h, int stride); + +// Same, buf specifically for RGBA4444 format +extern void (*WebPApplyAlphaMultiply4444)( + uint8_t* rgba4444, int w, int h, int stride); + +// Dispatch the values from alpha[] plane to the ARGB destination 'dst'. +// Returns true if alpha[] plane has non-trivial values different from 0xff. +extern int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT alpha, + int alpha_stride, int width, int height, + uint8_t* WEBP_RESTRICT dst, int dst_stride); + +// Transfer packed 8b alpha[] values to green channel in dst[], zero'ing the +// A/R/B values. 'dst_stride' is the stride for dst[] in uint32_t units. +extern void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT alpha, + int alpha_stride, int width, int height, + uint32_t* WEBP_RESTRICT dst, + int dst_stride); + +// Extract the alpha values from 32b values in argb[] and pack them into alpha[] +// (this is the opposite of WebPDispatchAlpha). +// Returns true if there's only trivial 0xff alpha values. +extern int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT argb, + int argb_stride, int width, int height, + uint8_t* WEBP_RESTRICT alpha, + int alpha_stride); + +// Extract the green values from 32b values in argb[] and pack them into alpha[] +// (this is the opposite of WebPDispatchAlphaToGreen). +extern void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT alpha, int size); + +// Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B). +// Un-Multiply operation transforms x into x * 255 / A. + +// Pre-Multiply or Un-Multiply (if 'inverse' is true) argb values in a row. +extern void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse); + +// Same a WebPMultARGBRow(), but for several rows. +void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows, + int inverse); + +// Same for a row of single values, with side alpha values. +extern void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr, + const uint8_t* WEBP_RESTRICT const alpha, + int width, int inverse); + +// Same a WebPMultRow(), but for several 'num_rows' rows. +void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride, + const uint8_t* WEBP_RESTRICT alpha, int alpha_stride, + int width, int num_rows, int inverse); + +// Plain-C versions, used as fallback by some implementations. +void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr, + const uint8_t* WEBP_RESTRICT const alpha, + int width, int inverse); +void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse); + +#ifdef WORDS_BIGENDIAN +// ARGB packing function: a/r/g/b input is rgba or bgra order. +extern void (*WebPPackARGB)(const uint8_t* WEBP_RESTRICT a, + const uint8_t* WEBP_RESTRICT r, + const uint8_t* WEBP_RESTRICT g, + const uint8_t* WEBP_RESTRICT b, + int len, uint32_t* WEBP_RESTRICT out); +#endif + +// RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order. +extern void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r, + const uint8_t* WEBP_RESTRICT g, + const uint8_t* WEBP_RESTRICT b, + int len, int step, uint32_t* WEBP_RESTRICT out); + +// This function returns true if src[i] contains a value different from 0xff. +extern int (*WebPHasAlpha8b)(const uint8_t* src, int length); +// This function returns true if src[4*i] contains a value different from 0xff. +extern int (*WebPHasAlpha32b)(const uint8_t* src, int length); +// replaces transparent values in src[] by 'color'. +extern void (*WebPAlphaReplace)(uint32_t* src, int length, uint32_t color); + +// To be called first before using the above. +void WebPInitAlphaProcessing(void); + +//------------------------------------------------------------------------------ +// Filter functions + +typedef enum { // Filter types. + WEBP_FILTER_NONE = 0, + WEBP_FILTER_HORIZONTAL, + WEBP_FILTER_VERTICAL, + WEBP_FILTER_GRADIENT, + WEBP_FILTER_LAST = WEBP_FILTER_GRADIENT + 1, // end marker + WEBP_FILTER_BEST, // meta-types + WEBP_FILTER_FAST +} WEBP_FILTER_TYPE; + +typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height, + int stride, uint8_t* out); +// In-place un-filtering. +// Warning! 'prev_line' pointer can be equal to 'cur_line' or 'preds'. +typedef void (*WebPUnfilterFunc)(const uint8_t* prev_line, const uint8_t* preds, + uint8_t* cur_line, int width); + +// Filter the given data using the given predictor. +// 'in' corresponds to a 2-dimensional pixel array of size (stride * height) +// in raster order. +// 'stride' is number of bytes per scan line (with possible padding). +// 'out' should be pre-allocated. +extern WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; + +// In-place reconstruct the original data from the given filtered data. +// The reconstruction will be done for 'num_rows' rows starting from 'row' +// (assuming rows upto 'row - 1' are already reconstructed). +extern WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST]; + +// To be called first before using the above. +void VP8FiltersInit(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_DSP_H_ diff --git a/libraries/webp/src/dsp/enc.c b/libraries/webp/src/dsp/enc.c new file mode 100644 index 00000000000..395ad05b0bc --- /dev/null +++ b/libraries/webp/src/dsp/enc.c @@ -0,0 +1,830 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical encoding functions. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include // for abs() + +#include "src/dsp/dsp.h" +#include "src/enc/vp8i_enc.h" + +static WEBP_INLINE uint8_t clip_8b(int v) { + return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; +} + +#if !WEBP_NEON_OMIT_C_CODE +static WEBP_INLINE int clip_max(int v, int max) { + return (v > max) ? max : v; +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//------------------------------------------------------------------------------ +// Compute susceptibility based on DCT-coeff histograms: +// the higher, the "easier" the macroblock is to compress. + +const int VP8DspScan[16 + 4 + 4] = { + // Luma + 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, + 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, + 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, + 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS, + + 0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U + 8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V +}; + +// general-purpose util function +void VP8SetHistogramData(const int distribution[MAX_COEFF_THRESH + 1], + VP8Histogram* const histo) { + int max_value = 0, last_non_zero = 1; + int k; + for (k = 0; k <= MAX_COEFF_THRESH; ++k) { + const int value = distribution[k]; + if (value > 0) { + if (value > max_value) max_value = value; + last_non_zero = k; + } + } + histo->max_value = max_value; + histo->last_non_zero = last_non_zero; +} + +#if !WEBP_NEON_OMIT_C_CODE +static void CollectHistogram_C(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block, + VP8Histogram* const histo) { + int j; + int distribution[MAX_COEFF_THRESH + 1] = { 0 }; + for (j = start_block; j < end_block; ++j) { + int k; + int16_t out[16]; + + VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + + // Convert coefficients to bin. + for (k = 0; k < 16; ++k) { + const int v = abs(out[k]) >> 3; + const int clipped_value = clip_max(v, MAX_COEFF_THRESH); + ++distribution[clipped_value]; + } + } + VP8SetHistogramData(distribution, histo); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//------------------------------------------------------------------------------ +// run-time tables (~4k) + +static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255] + +// We declare this variable 'volatile' to prevent instruction reordering +// and make sure it's set to true _last_ (so as to be thread-safe) +static volatile int tables_ok = 0; + +static WEBP_TSAN_IGNORE_FUNCTION void InitTables(void) { + if (!tables_ok) { + int i; + for (i = -255; i <= 255 + 255; ++i) { + clip1[255 + i] = clip_8b(i); + } + tables_ok = 1; + } +} + + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +#if !WEBP_NEON_OMIT_C_CODE + +#define STORE(x, y, v) \ + dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3)) + +static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, + uint8_t* dst) { + int C[4 * 4], *tmp; + int i; + tmp = C; + for (i = 0; i < 4; ++i) { // vertical pass + const int a = in[0] + in[8]; + const int b = in[0] - in[8]; + const int c = + WEBP_TRANSFORM_AC3_MUL2(in[4]) - WEBP_TRANSFORM_AC3_MUL1(in[12]); + const int d = + WEBP_TRANSFORM_AC3_MUL1(in[4]) + WEBP_TRANSFORM_AC3_MUL2(in[12]); + tmp[0] = a + d; + tmp[1] = b + c; + tmp[2] = b - c; + tmp[3] = a - d; + tmp += 4; + in++; + } + + tmp = C; + for (i = 0; i < 4; ++i) { // horizontal pass + const int dc = tmp[0] + 4; + const int a = dc + tmp[8]; + const int b = dc - tmp[8]; + const int c = + WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]); + const int d = + WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]); + STORE(0, i, a + d); + STORE(1, i, b + c); + STORE(2, i, b - c); + STORE(3, i, a - d); + tmp++; + } +} + +static void ITransform_C(const uint8_t* ref, const int16_t* in, uint8_t* dst, + int do_two) { + ITransformOne(ref, in, dst); + if (do_two) { + ITransformOne(ref + 4, in + 16, dst + 4); + } +} + +static void FTransform_C(const uint8_t* src, const uint8_t* ref, int16_t* out) { + int i; + int tmp[16]; + for (i = 0; i < 4; ++i, src += BPS, ref += BPS) { + const int d0 = src[0] - ref[0]; // 9bit dynamic range ([-255,255]) + const int d1 = src[1] - ref[1]; + const int d2 = src[2] - ref[2]; + const int d3 = src[3] - ref[3]; + const int a0 = (d0 + d3); // 10b [-510,510] + const int a1 = (d1 + d2); + const int a2 = (d1 - d2); + const int a3 = (d0 - d3); + tmp[0 + i * 4] = (a0 + a1) * 8; // 14b [-8160,8160] + tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 1812) >> 9; // [-7536,7542] + tmp[2 + i * 4] = (a0 - a1) * 8; + tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 937) >> 9; + } + for (i = 0; i < 4; ++i) { + const int a0 = (tmp[0 + i] + tmp[12 + i]); // 15b + const int a1 = (tmp[4 + i] + tmp[ 8 + i]); + const int a2 = (tmp[4 + i] - tmp[ 8 + i]); + const int a3 = (tmp[0 + i] - tmp[12 + i]); + out[0 + i] = (a0 + a1 + 7) >> 4; // 12b + out[4 + i] = ((a2 * 2217 + a3 * 5352 + 12000) >> 16) + (a3 != 0); + out[8 + i] = (a0 - a1 + 7) >> 4; + out[12+ i] = ((a3 * 2217 - a2 * 5352 + 51000) >> 16); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +static void FTransform2_C(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + VP8FTransform(src, ref, out); + VP8FTransform(src + 4, ref + 4, out + 16); +} + +#if !WEBP_NEON_OMIT_C_CODE +static void FTransformWHT_C(const int16_t* in, int16_t* out) { + // input is 12b signed + int32_t tmp[16]; + int i; + for (i = 0; i < 4; ++i, in += 64) { + const int a0 = (in[0 * 16] + in[2 * 16]); // 13b + const int a1 = (in[1 * 16] + in[3 * 16]); + const int a2 = (in[1 * 16] - in[3 * 16]); + const int a3 = (in[0 * 16] - in[2 * 16]); + tmp[0 + i * 4] = a0 + a1; // 14b + tmp[1 + i * 4] = a3 + a2; + tmp[2 + i * 4] = a3 - a2; + tmp[3 + i * 4] = a0 - a1; + } + for (i = 0; i < 4; ++i) { + const int a0 = (tmp[0 + i] + tmp[8 + i]); // 15b + const int a1 = (tmp[4 + i] + tmp[12+ i]); + const int a2 = (tmp[4 + i] - tmp[12+ i]); + const int a3 = (tmp[0 + i] - tmp[8 + i]); + const int b0 = a0 + a1; // 16b + const int b1 = a3 + a2; + const int b2 = a3 - a2; + const int b3 = a0 - a1; + out[ 0 + i] = b0 >> 1; // 15b + out[ 4 + i] = b1 >> 1; + out[ 8 + i] = b2 >> 1; + out[12 + i] = b3 >> 1; + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +#undef STORE + +//------------------------------------------------------------------------------ +// Intra predictions + +static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) { + int j; + for (j = 0; j < size; ++j) { + memset(dst + j * BPS, value, size); + } +} + +static WEBP_INLINE void VerticalPred(uint8_t* dst, + const uint8_t* top, int size) { + int j; + if (top != NULL) { + for (j = 0; j < size; ++j) memcpy(dst + j * BPS, top, size); + } else { + Fill(dst, 127, size); + } +} + +static WEBP_INLINE void HorizontalPred(uint8_t* dst, + const uint8_t* left, int size) { + if (left != NULL) { + int j; + for (j = 0; j < size; ++j) { + memset(dst + j * BPS, left[j], size); + } + } else { + Fill(dst, 129, size); + } +} + +static WEBP_INLINE void TrueMotion(uint8_t* dst, const uint8_t* left, + const uint8_t* top, int size) { + int y; + if (left != NULL) { + if (top != NULL) { + const uint8_t* const clip = clip1 + 255 - left[-1]; + for (y = 0; y < size; ++y) { + const uint8_t* const clip_table = clip + left[y]; + int x; + for (x = 0; x < size; ++x) { + dst[x] = clip_table[top[x]]; + } + dst += BPS; + } + } else { + HorizontalPred(dst, left, size); + } + } else { + // true motion without left samples (hence: with default 129 value) + // is equivalent to VE prediction where you just copy the top samples. + // Note that if top samples are not available, the default value is + // then 129, and not 127 as in the VerticalPred case. + if (top != NULL) { + VerticalPred(dst, top, size); + } else { + Fill(dst, 129, size); + } + } +} + +static WEBP_INLINE void DCMode(uint8_t* dst, const uint8_t* left, + const uint8_t* top, + int size, int round, int shift) { + int DC = 0; + int j; + if (top != NULL) { + for (j = 0; j < size; ++j) DC += top[j]; + if (left != NULL) { // top and left present + for (j = 0; j < size; ++j) DC += left[j]; + } else { // top, but no left + DC += DC; + } + DC = (DC + round) >> shift; + } else if (left != NULL) { // left but no top + for (j = 0; j < size; ++j) DC += left[j]; + DC += DC; + DC = (DC + round) >> shift; + } else { // no top, no left, nothing. + DC = 0x80; + } + Fill(dst, DC, size); +} + +//------------------------------------------------------------------------------ +// Chroma 8x8 prediction (paragraph 12.2) + +static void IntraChromaPreds_C(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + // U block + DCMode(C8DC8 + dst, left, top, 8, 8, 4); + VerticalPred(C8VE8 + dst, top, 8); + HorizontalPred(C8HE8 + dst, left, 8); + TrueMotion(C8TM8 + dst, left, top, 8); + // V block + dst += 8; + if (top != NULL) top += 8; + if (left != NULL) left += 16; + DCMode(C8DC8 + dst, left, top, 8, 8, 4); + VerticalPred(C8VE8 + dst, top, 8); + HorizontalPred(C8HE8 + dst, left, 8); + TrueMotion(C8TM8 + dst, left, top, 8); +} + +//------------------------------------------------------------------------------ +// luma 16x16 prediction (paragraph 12.3) + +static void Intra16Preds_C(uint8_t* dst, + const uint8_t* left, const uint8_t* top) { + DCMode(I16DC16 + dst, left, top, 16, 16, 5); + VerticalPred(I16VE16 + dst, top, 16); + HorizontalPred(I16HE16 + dst, left, 16); + TrueMotion(I16TM16 + dst, left, top, 16); +} + +//------------------------------------------------------------------------------ +// luma 4x4 prediction + +#define DST(x, y) dst[(x) + (y) * BPS] +#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2)) +#define AVG2(a, b) (((a) + (b) + 1) >> 1) + +static void VE4(uint8_t* dst, const uint8_t* top) { // vertical + const uint8_t vals[4] = { + AVG3(top[-1], top[0], top[1]), + AVG3(top[ 0], top[1], top[2]), + AVG3(top[ 1], top[2], top[3]), + AVG3(top[ 2], top[3], top[4]) + }; + int i; + for (i = 0; i < 4; ++i) { + memcpy(dst + i * BPS, vals, 4); + } +} + +static void HE4(uint8_t* dst, const uint8_t* top) { // horizontal + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + WebPUint32ToMem(dst + 0 * BPS, 0x01010101U * AVG3(X, I, J)); + WebPUint32ToMem(dst + 1 * BPS, 0x01010101U * AVG3(I, J, K)); + WebPUint32ToMem(dst + 2 * BPS, 0x01010101U * AVG3(J, K, L)); + WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(K, L, L)); +} + +static void DC4(uint8_t* dst, const uint8_t* top) { + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i]; + Fill(dst, dc >> 3, 4); +} + +static void RD4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + DST(0, 3) = AVG3(J, K, L); + DST(0, 2) = DST(1, 3) = AVG3(I, J, K); + DST(0, 1) = DST(1, 2) = DST(2, 3) = AVG3(X, I, J); + DST(0, 0) = DST(1, 1) = DST(2, 2) = DST(3, 3) = AVG3(A, X, I); + DST(1, 0) = DST(2, 1) = DST(3, 2) = AVG3(B, A, X); + DST(2, 0) = DST(3, 1) = AVG3(C, B, A); + DST(3, 0) = AVG3(D, C, B); +} + +static void LD4(uint8_t* dst, const uint8_t* top) { + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + const int E = top[4]; + const int F = top[5]; + const int G = top[6]; + const int H = top[7]; + DST(0, 0) = AVG3(A, B, C); + DST(1, 0) = DST(0, 1) = AVG3(B, C, D); + DST(2, 0) = DST(1, 1) = DST(0, 2) = AVG3(C, D, E); + DST(3, 0) = DST(2, 1) = DST(1, 2) = DST(0, 3) = AVG3(D, E, F); + DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G); + DST(3, 2) = DST(2, 3) = AVG3(F, G, H); + DST(3, 3) = AVG3(G, H, H); +} + +static void VR4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + DST(0, 0) = DST(1, 2) = AVG2(X, A); + DST(1, 0) = DST(2, 2) = AVG2(A, B); + DST(2, 0) = DST(3, 2) = AVG2(B, C); + DST(3, 0) = AVG2(C, D); + + DST(0, 3) = AVG3(K, J, I); + DST(0, 2) = AVG3(J, I, X); + DST(0, 1) = DST(1, 3) = AVG3(I, X, A); + DST(1, 1) = DST(2, 3) = AVG3(X, A, B); + DST(2, 1) = DST(3, 3) = AVG3(A, B, C); + DST(3, 1) = AVG3(B, C, D); +} + +static void VL4(uint8_t* dst, const uint8_t* top) { + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + const int E = top[4]; + const int F = top[5]; + const int G = top[6]; + const int H = top[7]; + DST(0, 0) = AVG2(A, B); + DST(1, 0) = DST(0, 2) = AVG2(B, C); + DST(2, 0) = DST(1, 2) = AVG2(C, D); + DST(3, 0) = DST(2, 2) = AVG2(D, E); + + DST(0, 1) = AVG3(A, B, C); + DST(1, 1) = DST(0, 3) = AVG3(B, C, D); + DST(2, 1) = DST(1, 3) = AVG3(C, D, E); + DST(3, 1) = DST(2, 3) = AVG3(D, E, F); + DST(3, 2) = AVG3(E, F, G); + DST(3, 3) = AVG3(F, G, H); +} + +static void HU4(uint8_t* dst, const uint8_t* top) { + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + DST(0, 0) = AVG2(I, J); + DST(2, 0) = DST(0, 1) = AVG2(J, K); + DST(2, 1) = DST(0, 2) = AVG2(K, L); + DST(1, 0) = AVG3(I, J, K); + DST(3, 0) = DST(1, 1) = AVG3(J, K, L); + DST(3, 1) = DST(1, 2) = AVG3(K, L, L); + DST(3, 2) = DST(2, 2) = + DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; +} + +static void HD4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + + DST(0, 0) = DST(2, 1) = AVG2(I, X); + DST(0, 1) = DST(2, 2) = AVG2(J, I); + DST(0, 2) = DST(2, 3) = AVG2(K, J); + DST(0, 3) = AVG2(L, K); + + DST(3, 0) = AVG3(A, B, C); + DST(2, 0) = AVG3(X, A, B); + DST(1, 0) = DST(3, 1) = AVG3(I, X, A); + DST(1, 1) = DST(3, 2) = AVG3(J, I, X); + DST(1, 2) = DST(3, 3) = AVG3(K, J, I); + DST(1, 3) = AVG3(L, K, J); +} + +static void TM4(uint8_t* dst, const uint8_t* top) { + int x, y; + const uint8_t* const clip = clip1 + 255 - top[-1]; + for (y = 0; y < 4; ++y) { + const uint8_t* const clip_table = clip + top[-2 - y]; + for (x = 0; x < 4; ++x) { + dst[x] = clip_table[top[x]]; + } + dst += BPS; + } +} + +#undef DST +#undef AVG3 +#undef AVG2 + +// Left samples are top[-5 .. -2], top_left is top[-1], top are +// located at top[0..3], and top right is top[4..7] +static void Intra4Preds_C(uint8_t* dst, const uint8_t* top) { + DC4(I4DC4 + dst, top); + TM4(I4TM4 + dst, top); + VE4(I4VE4 + dst, top); + HE4(I4HE4 + dst, top); + RD4(I4RD4 + dst, top); + VR4(I4VR4 + dst, top); + LD4(I4LD4 + dst, top); + VL4(I4VL4 + dst, top); + HD4(I4HD4 + dst, top); + HU4(I4HU4 + dst, top); +} + +//------------------------------------------------------------------------------ +// Metric + +#if !WEBP_NEON_OMIT_C_CODE +static WEBP_INLINE int GetSSE(const uint8_t* a, const uint8_t* b, + int w, int h) { + int count = 0; + int y, x; + for (y = 0; y < h; ++y) { + for (x = 0; x < w; ++x) { + const int diff = (int)a[x] - b[x]; + count += diff * diff; + } + a += BPS; + b += BPS; + } + return count; +} + +static int SSE16x16_C(const uint8_t* a, const uint8_t* b) { + return GetSSE(a, b, 16, 16); +} +static int SSE16x8_C(const uint8_t* a, const uint8_t* b) { + return GetSSE(a, b, 16, 8); +} +static int SSE8x8_C(const uint8_t* a, const uint8_t* b) { + return GetSSE(a, b, 8, 8); +} +static int SSE4x4_C(const uint8_t* a, const uint8_t* b) { + return GetSSE(a, b, 4, 4); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +static void Mean16x4_C(const uint8_t* ref, uint32_t dc[4]) { + int k, x, y; + for (k = 0; k < 4; ++k) { + uint32_t avg = 0; + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + avg += ref[x + y * BPS]; + } + } + dc[k] = avg; + ref += 4; // go to next 4x4 block. + } +} + +//------------------------------------------------------------------------------ +// Texture distortion +// +// We try to match the spectral content (weighted) between source and +// reconstructed samples. + +#if !WEBP_NEON_OMIT_C_CODE +// Hadamard transform +// Returns the weighted sum of the absolute value of transformed coefficients. +// w[] contains a row-major 4 by 4 symmetric matrix. +static int TTransform(const uint8_t* in, const uint16_t* w) { + int sum = 0; + int tmp[16]; + int i; + // horizontal pass + for (i = 0; i < 4; ++i, in += BPS) { + const int a0 = in[0] + in[2]; + const int a1 = in[1] + in[3]; + const int a2 = in[1] - in[3]; + const int a3 = in[0] - in[2]; + tmp[0 + i * 4] = a0 + a1; + tmp[1 + i * 4] = a3 + a2; + tmp[2 + i * 4] = a3 - a2; + tmp[3 + i * 4] = a0 - a1; + } + // vertical pass + for (i = 0; i < 4; ++i, ++w) { + const int a0 = tmp[0 + i] + tmp[8 + i]; + const int a1 = tmp[4 + i] + tmp[12+ i]; + const int a2 = tmp[4 + i] - tmp[12+ i]; + const int a3 = tmp[0 + i] - tmp[8 + i]; + const int b0 = a0 + a1; + const int b1 = a3 + a2; + const int b2 = a3 - a2; + const int b3 = a0 - a1; + + sum += w[ 0] * abs(b0); + sum += w[ 4] * abs(b1); + sum += w[ 8] * abs(b2); + sum += w[12] * abs(b3); + } + return sum; +} + +static int Disto4x4_C(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + const int sum1 = TTransform(a, w); + const int sum2 = TTransform(b, w); + return abs(sum2 - sum1) >> 5; +} + +static int Disto16x16_C(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4_C(a + x + y, b + x + y, w); + } + } + return D; +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//------------------------------------------------------------------------------ +// Quantization +// + +static const uint8_t kZigzag[16] = { + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +// Simple quantization +static int QuantizeBlock_C(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + int last = -1; + int n; + for (n = 0; n < 16; ++n) { + const int j = kZigzag[n]; + const int sign = (in[j] < 0); + const uint32_t coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; + if (coeff > mtx->zthresh_[j]) { + const uint32_t Q = mtx->q_[j]; + const uint32_t iQ = mtx->iq_[j]; + const uint32_t B = mtx->bias_[j]; + int level = QUANTDIV(coeff, iQ, B); + if (level > MAX_LEVEL) level = MAX_LEVEL; + if (sign) level = -level; + in[j] = level * (int)Q; + out[n] = level; + if (level) last = n; + } else { + out[n] = 0; + in[j] = 0; + } + } + return (last >= 0); +} + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC +static int Quantize2Blocks_C(int16_t in[32], int16_t out[32], + const VP8Matrix* const mtx) { + int nz; + nz = VP8EncQuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0; + nz |= VP8EncQuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1; + return nz; +} +#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + +//------------------------------------------------------------------------------ +// Block copy + +static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int w, int h) { + int y; + for (y = 0; y < h; ++y) { + memcpy(dst, src, w); + src += BPS; + dst += BPS; + } +} + +static void Copy4x4_C(const uint8_t* src, uint8_t* dst) { + Copy(src, dst, 4, 4); +} + +static void Copy16x8_C(const uint8_t* src, uint8_t* dst) { + Copy(src, dst, 16, 8); +} + +//------------------------------------------------------------------------------ +// Initialization + +// Speed-critical function pointers. We have to initialize them to the default +// implementations within VP8EncDspInit(). +VP8CHisto VP8CollectHistogram; +VP8Idct VP8ITransform; +VP8Fdct VP8FTransform; +VP8Fdct VP8FTransform2; +VP8WHT VP8FTransformWHT; +VP8Intra4Preds VP8EncPredLuma4; +VP8IntraPreds VP8EncPredLuma16; +VP8IntraPreds VP8EncPredChroma8; +VP8Metric VP8SSE16x16; +VP8Metric VP8SSE8x8; +VP8Metric VP8SSE16x8; +VP8Metric VP8SSE4x4; +VP8WMetric VP8TDisto4x4; +VP8WMetric VP8TDisto16x16; +VP8MeanMetric VP8Mean16x4; +VP8QuantizeBlock VP8EncQuantizeBlock; +VP8Quantize2Blocks VP8EncQuantize2Blocks; +VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT; +VP8BlockCopy VP8Copy4x4; +VP8BlockCopy VP8Copy16x8; + +extern VP8CPUInfo VP8GetCPUInfo; +extern void VP8EncDspInitSSE2(void); +extern void VP8EncDspInitSSE41(void); +extern void VP8EncDspInitNEON(void); +extern void VP8EncDspInitMIPS32(void); +extern void VP8EncDspInitMIPSdspR2(void); +extern void VP8EncDspInitMSA(void); + +WEBP_DSP_INIT_FUNC(VP8EncDspInit) { + VP8DspInit(); // common inverse transforms + InitTables(); + + // default C implementations +#if !WEBP_NEON_OMIT_C_CODE + VP8ITransform = ITransform_C; + VP8FTransform = FTransform_C; + VP8FTransformWHT = FTransformWHT_C; + VP8TDisto4x4 = Disto4x4_C; + VP8TDisto16x16 = Disto16x16_C; + VP8CollectHistogram = CollectHistogram_C; + VP8SSE16x16 = SSE16x16_C; + VP8SSE16x8 = SSE16x8_C; + VP8SSE8x8 = SSE8x8_C; + VP8SSE4x4 = SSE4x4_C; +#endif + +#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC + VP8EncQuantizeBlock = QuantizeBlock_C; + VP8EncQuantize2Blocks = Quantize2Blocks_C; +#endif + + VP8FTransform2 = FTransform2_C; + VP8EncPredLuma4 = Intra4Preds_C; + VP8EncPredLuma16 = Intra16Preds_C; + VP8EncPredChroma8 = IntraChromaPreds_C; + VP8Mean16x4 = Mean16x4_C; + VP8EncQuantizeBlockWHT = QuantizeBlock_C; + VP8Copy4x4 = Copy4x4_C; + VP8Copy16x8 = Copy16x8_C; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8EncDspInitSSE2(); +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + VP8EncDspInitSSE41(); + } +#endif + } +#endif +#if defined(WEBP_USE_MIPS32) + if (VP8GetCPUInfo(kMIPS32)) { + VP8EncDspInitMIPS32(); + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + VP8EncDspInitMIPSdspR2(); + } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8EncDspInitMSA(); + } +#endif + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + VP8EncDspInitNEON(); + } +#endif + + assert(VP8ITransform != NULL); + assert(VP8FTransform != NULL); + assert(VP8FTransformWHT != NULL); + assert(VP8TDisto4x4 != NULL); + assert(VP8TDisto16x16 != NULL); + assert(VP8CollectHistogram != NULL); + assert(VP8SSE16x16 != NULL); + assert(VP8SSE16x8 != NULL); + assert(VP8SSE8x8 != NULL); + assert(VP8SSE4x4 != NULL); + assert(VP8EncQuantizeBlock != NULL); + assert(VP8EncQuantize2Blocks != NULL); + assert(VP8FTransform2 != NULL); + assert(VP8EncPredLuma4 != NULL); + assert(VP8EncPredLuma16 != NULL); + assert(VP8EncPredChroma8 != NULL); + assert(VP8Mean16x4 != NULL); + assert(VP8EncQuantizeBlockWHT != NULL); + assert(VP8Copy4x4 != NULL); + assert(VP8Copy16x8 != NULL); +} diff --git a/libraries/webp/src/dsp/enc_mips32.c b/libraries/webp/src/dsp/enc_mips32.c new file mode 100644 index 00000000000..50518a5f1ae --- /dev/null +++ b/libraries/webp/src/dsp/enc_mips32.c @@ -0,0 +1,673 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS version of speed-critical encoding functions. +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) +// Jovan Zelincevic (jovan.zelincevic@imgtec.com) +// Slobodan Prijic (slobodan.prijic@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS32) + +#include "src/dsp/mips_macro.h" +#include "src/enc/vp8i_enc.h" +#include "src/enc/cost_enc.h" + +static const int kC1 = WEBP_TRANSFORM_AC3_C1; +static const int kC2 = WEBP_TRANSFORM_AC3_C2; + +// macro for one vertical pass in ITransformOne +// MUL macro inlined +// temp0..temp15 holds tmp[0]..tmp[15] +// A..D - offsets in bytes to load from in buffer +// TEMP0..TEMP3 - registers for corresponding tmp elements +// TEMP4..TEMP5 - temporary registers +#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \ + "lh %[temp16], " #A "(%[temp20]) \n\t" \ + "lh %[temp18], " #B "(%[temp20]) \n\t" \ + "lh %[temp17], " #C "(%[temp20]) \n\t" \ + "lh %[temp19], " #D "(%[temp20]) \n\t" \ + "addu %[" #TEMP4 "], %[temp16], %[temp18] \n\t" \ + "subu %[temp16], %[temp16], %[temp18] \n\t" \ + "mul %[" #TEMP0 "], %[temp17], %[kC2] \n\t" \ + MUL_SHIFT_C1_IO(temp17, temp18) \ + MUL_SHIFT_C1(temp18, temp19) \ + "mul %[temp19], %[temp19], %[kC2] \n\t" \ + "sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\n" \ + "sra %[temp19], %[temp19], 16 \n\n" \ + "subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp18] \n\t" \ + "addu %[" #TEMP3 "], %[temp17], %[temp19] \n\t" \ + "addu %[" #TEMP0 "], %[" #TEMP4 "], %[" #TEMP3 "] \n\t" \ + "addu %[" #TEMP1 "], %[temp16], %[" #TEMP2 "] \n\t" \ + "subu %[" #TEMP2 "], %[temp16], %[" #TEMP2 "] \n\t" \ + "subu %[" #TEMP3 "], %[" #TEMP4 "], %[" #TEMP3 "] \n\t" + +// macro for one horizontal pass in ITransformOne +// MUL and STORE macros inlined +// a = clip_8b(a) is replaced with: a = max(a, 0); a = min(a, 255) +// temp0..temp15 holds tmp[0]..tmp[15] +// A - offset in bytes to load from ref and store to dst buffer +// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements +#define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \ + "addiu %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \ + "addu %[temp16], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ + "subu %[temp17], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ + "mul %[" #TEMP0 "], %[" #TEMP4 "], %[kC2] \n\t" \ + MUL_SHIFT_C1_IO(TEMP4, TEMP8) \ + MUL_SHIFT_C1(TEMP8, TEMP12) \ + "mul %[" #TEMP12 "], %[" #TEMP12 "], %[kC2] \n\t" \ + "sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \ + "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \ + "subu %[temp18], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ + "addu %[temp19], %[" #TEMP4 "], %[" #TEMP12 "] \n\t" \ + "addu %[" #TEMP0 "], %[temp16], %[temp19] \n\t" \ + "addu %[" #TEMP4 "], %[temp17], %[temp18] \n\t" \ + "subu %[" #TEMP8 "], %[temp17], %[temp18] \n\t" \ + "subu %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \ + "lw %[temp20], 0(%[args]) \n\t" \ + "sra %[" #TEMP0 "], %[" #TEMP0 "], 3 \n\t" \ + "sra %[" #TEMP4 "], %[" #TEMP4 "], 3 \n\t" \ + "sra %[" #TEMP8 "], %[" #TEMP8 "], 3 \n\t" \ + "sra %[" #TEMP12 "], %[" #TEMP12 "], 3 \n\t" \ + "lbu %[temp16], 0+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \ + "lbu %[temp17], 1+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \ + "lbu %[temp18], 2+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \ + "lbu %[temp19], 3+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \ + "addu %[" #TEMP0 "], %[temp16], %[" #TEMP0 "] \n\t" \ + "addu %[" #TEMP4 "], %[temp17], %[" #TEMP4 "] \n\t" \ + "addu %[" #TEMP8 "], %[temp18], %[" #TEMP8 "] \n\t" \ + "addu %[" #TEMP12 "], %[temp19], %[" #TEMP12 "] \n\t" \ + "slt %[temp16], %[" #TEMP0 "], $zero \n\t" \ + "slt %[temp17], %[" #TEMP4 "], $zero \n\t" \ + "slt %[temp18], %[" #TEMP8 "], $zero \n\t" \ + "slt %[temp19], %[" #TEMP12 "], $zero \n\t" \ + "movn %[" #TEMP0 "], $zero, %[temp16] \n\t" \ + "movn %[" #TEMP4 "], $zero, %[temp17] \n\t" \ + "movn %[" #TEMP8 "], $zero, %[temp18] \n\t" \ + "movn %[" #TEMP12 "], $zero, %[temp19] \n\t" \ + "addiu %[temp20], $zero, 255 \n\t" \ + "slt %[temp16], %[" #TEMP0 "], %[temp20] \n\t" \ + "slt %[temp17], %[" #TEMP4 "], %[temp20] \n\t" \ + "slt %[temp18], %[" #TEMP8 "], %[temp20] \n\t" \ + "slt %[temp19], %[" #TEMP12 "], %[temp20] \n\t" \ + "movz %[" #TEMP0 "], %[temp20], %[temp16] \n\t" \ + "movz %[" #TEMP4 "], %[temp20], %[temp17] \n\t" \ + "lw %[temp16], 8(%[args]) \n\t" \ + "movz %[" #TEMP8 "], %[temp20], %[temp18] \n\t" \ + "movz %[" #TEMP12 "], %[temp20], %[temp19] \n\t" \ + "sb %[" #TEMP0 "], 0+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \ + "sb %[" #TEMP4 "], 1+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \ + "sb %[" #TEMP8 "], 2+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \ + "sb %[" #TEMP12 "], 3+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" + +// Does one or two inverse transforms. +static WEBP_INLINE void ITransformOne_MIPS32(const uint8_t* ref, + const int16_t* in, + uint8_t* dst) { + int temp0, temp1, temp2, temp3, temp4, temp5, temp6; + int temp7, temp8, temp9, temp10, temp11, temp12, temp13; + int temp14, temp15, temp16, temp17, temp18, temp19, temp20; + const int* args[3] = {(const int*)ref, (const int*)in, (const int*)dst}; + + __asm__ volatile( + "lw %[temp20], 4(%[args]) \n\t" + VERTICAL_PASS(0, 16, 8, 24, temp4, temp0, temp1, temp2, temp3) + VERTICAL_PASS(2, 18, 10, 26, temp8, temp4, temp5, temp6, temp7) + VERTICAL_PASS(4, 20, 12, 28, temp12, temp8, temp9, temp10, temp11) + VERTICAL_PASS(6, 22, 14, 30, temp20, temp12, temp13, temp14, temp15) + + HORIZONTAL_PASS(0, temp0, temp4, temp8, temp12) + HORIZONTAL_PASS(1, temp1, temp5, temp9, temp13) + HORIZONTAL_PASS(2, temp2, temp6, temp10, temp14) + HORIZONTAL_PASS(3, temp3, temp7, temp11, temp15) + + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11), + [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14), + [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17), + [temp18]"=&r"(temp18), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20) + : [args]"r"(args), [kC1]"r"(kC1), [kC2]"r"(kC2) + : "memory", "hi", "lo" + ); +} + +static void ITransform_MIPS32(const uint8_t* ref, const int16_t* in, + uint8_t* dst, int do_two) { + ITransformOne_MIPS32(ref, in, dst); + if (do_two) { + ITransformOne_MIPS32(ref + 4, in + 16, dst + 4); + } +} + +#undef VERTICAL_PASS +#undef HORIZONTAL_PASS + +// macro for one pass through for loop in QuantizeBlock +// QUANTDIV macro inlined +// J - offset in bytes (kZigzag[n] * 2) +// K - offset in bytes (kZigzag[n] * 4) +// N - offset in bytes (n * 2) +#define QUANTIZE_ONE(J, K, N) \ + "lh %[temp0], " #J "(%[ppin]) \n\t" \ + "lhu %[temp1], " #J "(%[ppsharpen]) \n\t" \ + "lw %[temp2], " #K "(%[ppzthresh]) \n\t" \ + "sra %[sign], %[temp0], 15 \n\t" \ + "xor %[coeff], %[temp0], %[sign] \n\t" \ + "subu %[coeff], %[coeff], %[sign] \n\t" \ + "addu %[coeff], %[coeff], %[temp1] \n\t" \ + "slt %[temp4], %[temp2], %[coeff] \n\t" \ + "addiu %[temp5], $zero, 0 \n\t" \ + "addiu %[level], $zero, 0 \n\t" \ + "beqz %[temp4], 2f \n\t" \ + "lhu %[temp1], " #J "(%[ppiq]) \n\t" \ + "lw %[temp2], " #K "(%[ppbias]) \n\t" \ + "lhu %[temp3], " #J "(%[ppq]) \n\t" \ + "mul %[level], %[coeff], %[temp1] \n\t" \ + "addu %[level], %[level], %[temp2] \n\t" \ + "sra %[level], %[level], 17 \n\t" \ + "slt %[temp4], %[max_level], %[level] \n\t" \ + "movn %[level], %[max_level], %[temp4] \n\t" \ + "xor %[level], %[level], %[sign] \n\t" \ + "subu %[level], %[level], %[sign] \n\t" \ + "mul %[temp5], %[level], %[temp3] \n\t" \ +"2: \n\t" \ + "sh %[temp5], " #J "(%[ppin]) \n\t" \ + "sh %[level], " #N "(%[pout]) \n\t" + +static int QuantizeBlock_MIPS32(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + int temp0, temp1, temp2, temp3, temp4, temp5; + int sign, coeff, level, i; + int max_level = MAX_LEVEL; + + int16_t* ppin = &in[0]; + int16_t* pout = &out[0]; + const uint16_t* ppsharpen = &mtx->sharpen_[0]; + const uint32_t* ppzthresh = &mtx->zthresh_[0]; + const uint16_t* ppq = &mtx->q_[0]; + const uint16_t* ppiq = &mtx->iq_[0]; + const uint32_t* ppbias = &mtx->bias_[0]; + + __asm__ volatile( + QUANTIZE_ONE( 0, 0, 0) + QUANTIZE_ONE( 2, 4, 2) + QUANTIZE_ONE( 8, 16, 4) + QUANTIZE_ONE(16, 32, 6) + QUANTIZE_ONE(10, 20, 8) + QUANTIZE_ONE( 4, 8, 10) + QUANTIZE_ONE( 6, 12, 12) + QUANTIZE_ONE(12, 24, 14) + QUANTIZE_ONE(18, 36, 16) + QUANTIZE_ONE(24, 48, 18) + QUANTIZE_ONE(26, 52, 20) + QUANTIZE_ONE(20, 40, 22) + QUANTIZE_ONE(14, 28, 24) + QUANTIZE_ONE(22, 44, 26) + QUANTIZE_ONE(28, 56, 28) + QUANTIZE_ONE(30, 60, 30) + + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [sign]"=&r"(sign), [coeff]"=&r"(coeff), + [level]"=&r"(level) + : [pout]"r"(pout), [ppin]"r"(ppin), + [ppiq]"r"(ppiq), [max_level]"r"(max_level), + [ppbias]"r"(ppbias), [ppzthresh]"r"(ppzthresh), + [ppsharpen]"r"(ppsharpen), [ppq]"r"(ppq) + : "memory", "hi", "lo" + ); + + // moved out from macro to increase possibility for earlier breaking + for (i = 15; i >= 0; i--) { + if (out[i]) return 1; + } + return 0; +} + +static int Quantize2Blocks_MIPS32(int16_t in[32], int16_t out[32], + const VP8Matrix* const mtx) { + int nz; + nz = QuantizeBlock_MIPS32(in + 0 * 16, out + 0 * 16, mtx) << 0; + nz |= QuantizeBlock_MIPS32(in + 1 * 16, out + 1 * 16, mtx) << 1; + return nz; +} + +#undef QUANTIZE_ONE + +// macro for one horizontal pass in Disto4x4 (TTransform) +// two calls of function TTransform are merged into single one +// A - offset in bytes to load from a and b buffers +// E..H - offsets in bytes to store first results to tmp buffer +// E1..H1 - offsets in bytes to store second results to tmp buffer +#define HORIZONTAL_PASS(A, E, F, G, H, E1, F1, G1, H1) \ + "lbu %[temp0], 0+" XSTR(BPS) "*" #A "(%[a]) \n\t" \ + "lbu %[temp1], 1+" XSTR(BPS) "*" #A "(%[a]) \n\t" \ + "lbu %[temp2], 2+" XSTR(BPS) "*" #A "(%[a]) \n\t" \ + "lbu %[temp3], 3+" XSTR(BPS) "*" #A "(%[a]) \n\t" \ + "lbu %[temp4], 0+" XSTR(BPS) "*" #A "(%[b]) \n\t" \ + "lbu %[temp5], 1+" XSTR(BPS) "*" #A "(%[b]) \n\t" \ + "lbu %[temp6], 2+" XSTR(BPS) "*" #A "(%[b]) \n\t" \ + "lbu %[temp7], 3+" XSTR(BPS) "*" #A "(%[b]) \n\t" \ + "addu %[temp8], %[temp0], %[temp2] \n\t" \ + "subu %[temp0], %[temp0], %[temp2] \n\t" \ + "addu %[temp2], %[temp1], %[temp3] \n\t" \ + "subu %[temp1], %[temp1], %[temp3] \n\t" \ + "addu %[temp3], %[temp4], %[temp6] \n\t" \ + "subu %[temp4], %[temp4], %[temp6] \n\t" \ + "addu %[temp6], %[temp5], %[temp7] \n\t" \ + "subu %[temp5], %[temp5], %[temp7] \n\t" \ + "addu %[temp7], %[temp8], %[temp2] \n\t" \ + "subu %[temp2], %[temp8], %[temp2] \n\t" \ + "addu %[temp8], %[temp0], %[temp1] \n\t" \ + "subu %[temp0], %[temp0], %[temp1] \n\t" \ + "addu %[temp1], %[temp3], %[temp6] \n\t" \ + "subu %[temp3], %[temp3], %[temp6] \n\t" \ + "addu %[temp6], %[temp4], %[temp5] \n\t" \ + "subu %[temp4], %[temp4], %[temp5] \n\t" \ + "sw %[temp7], " #E "(%[tmp]) \n\t" \ + "sw %[temp2], " #H "(%[tmp]) \n\t" \ + "sw %[temp8], " #F "(%[tmp]) \n\t" \ + "sw %[temp0], " #G "(%[tmp]) \n\t" \ + "sw %[temp1], " #E1 "(%[tmp]) \n\t" \ + "sw %[temp3], " #H1 "(%[tmp]) \n\t" \ + "sw %[temp6], " #F1 "(%[tmp]) \n\t" \ + "sw %[temp4], " #G1 "(%[tmp]) \n\t" + +// macro for one vertical pass in Disto4x4 (TTransform) +// two calls of function TTransform are merged into single one +// since only one accu is available in mips32r1 instruction set +// first is done second call of function TTransform and after +// that first one. +// const int sum1 = TTransform(a, w); +// const int sum2 = TTransform(b, w); +// return abs(sum2 - sum1) >> 5; +// (sum2 - sum1) is calculated with madds (sub2) and msubs (sub1) +// A..D - offsets in bytes to load first results from tmp buffer +// A1..D1 - offsets in bytes to load second results from tmp buffer +// E..H - offsets in bytes to load from w buffer +#define VERTICAL_PASS(A, B, C, D, A1, B1, C1, D1, E, F, G, H) \ + "lw %[temp0], " #A1 "(%[tmp]) \n\t" \ + "lw %[temp1], " #C1 "(%[tmp]) \n\t" \ + "lw %[temp2], " #B1 "(%[tmp]) \n\t" \ + "lw %[temp3], " #D1 "(%[tmp]) \n\t" \ + "addu %[temp8], %[temp0], %[temp1] \n\t" \ + "subu %[temp0], %[temp0], %[temp1] \n\t" \ + "addu %[temp1], %[temp2], %[temp3] \n\t" \ + "subu %[temp2], %[temp2], %[temp3] \n\t" \ + "addu %[temp3], %[temp8], %[temp1] \n\t" \ + "subu %[temp8], %[temp8], %[temp1] \n\t" \ + "addu %[temp1], %[temp0], %[temp2] \n\t" \ + "subu %[temp0], %[temp0], %[temp2] \n\t" \ + "sra %[temp4], %[temp3], 31 \n\t" \ + "sra %[temp5], %[temp1], 31 \n\t" \ + "sra %[temp6], %[temp0], 31 \n\t" \ + "sra %[temp7], %[temp8], 31 \n\t" \ + "xor %[temp3], %[temp3], %[temp4] \n\t" \ + "xor %[temp1], %[temp1], %[temp5] \n\t" \ + "xor %[temp0], %[temp0], %[temp6] \n\t" \ + "xor %[temp8], %[temp8], %[temp7] \n\t" \ + "subu %[temp3], %[temp3], %[temp4] \n\t" \ + "subu %[temp1], %[temp1], %[temp5] \n\t" \ + "subu %[temp0], %[temp0], %[temp6] \n\t" \ + "subu %[temp8], %[temp8], %[temp7] \n\t" \ + "lhu %[temp4], " #E "(%[w]) \n\t" \ + "lhu %[temp5], " #F "(%[w]) \n\t" \ + "lhu %[temp6], " #G "(%[w]) \n\t" \ + "lhu %[temp7], " #H "(%[w]) \n\t" \ + "madd %[temp4], %[temp3] \n\t" \ + "madd %[temp5], %[temp1] \n\t" \ + "madd %[temp6], %[temp0] \n\t" \ + "madd %[temp7], %[temp8] \n\t" \ + "lw %[temp0], " #A "(%[tmp]) \n\t" \ + "lw %[temp1], " #C "(%[tmp]) \n\t" \ + "lw %[temp2], " #B "(%[tmp]) \n\t" \ + "lw %[temp3], " #D "(%[tmp]) \n\t" \ + "addu %[temp8], %[temp0], %[temp1] \n\t" \ + "subu %[temp0], %[temp0], %[temp1] \n\t" \ + "addu %[temp1], %[temp2], %[temp3] \n\t" \ + "subu %[temp2], %[temp2], %[temp3] \n\t" \ + "addu %[temp3], %[temp8], %[temp1] \n\t" \ + "subu %[temp1], %[temp8], %[temp1] \n\t" \ + "addu %[temp8], %[temp0], %[temp2] \n\t" \ + "subu %[temp0], %[temp0], %[temp2] \n\t" \ + "sra %[temp2], %[temp3], 31 \n\t" \ + "xor %[temp3], %[temp3], %[temp2] \n\t" \ + "subu %[temp3], %[temp3], %[temp2] \n\t" \ + "msub %[temp4], %[temp3] \n\t" \ + "sra %[temp2], %[temp8], 31 \n\t" \ + "sra %[temp3], %[temp0], 31 \n\t" \ + "sra %[temp4], %[temp1], 31 \n\t" \ + "xor %[temp8], %[temp8], %[temp2] \n\t" \ + "xor %[temp0], %[temp0], %[temp3] \n\t" \ + "xor %[temp1], %[temp1], %[temp4] \n\t" \ + "subu %[temp8], %[temp8], %[temp2] \n\t" \ + "subu %[temp0], %[temp0], %[temp3] \n\t" \ + "subu %[temp1], %[temp1], %[temp4] \n\t" \ + "msub %[temp5], %[temp8] \n\t" \ + "msub %[temp6], %[temp0] \n\t" \ + "msub %[temp7], %[temp1] \n\t" + +static int Disto4x4_MIPS32(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int tmp[32]; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; + + __asm__ volatile( + HORIZONTAL_PASS(0, 0, 4, 8, 12, 64, 68, 72, 76) + HORIZONTAL_PASS(1, 16, 20, 24, 28, 80, 84, 88, 92) + HORIZONTAL_PASS(2, 32, 36, 40, 44, 96, 100, 104, 108) + HORIZONTAL_PASS(3, 48, 52, 56, 60, 112, 116, 120, 124) + "mthi $zero \n\t" + "mtlo $zero \n\t" + VERTICAL_PASS( 0, 16, 32, 48, 64, 80, 96, 112, 0, 8, 16, 24) + VERTICAL_PASS( 4, 20, 36, 52, 68, 84, 100, 116, 2, 10, 18, 26) + VERTICAL_PASS( 8, 24, 40, 56, 72, 88, 104, 120, 4, 12, 20, 28) + VERTICAL_PASS(12, 28, 44, 60, 76, 92, 108, 124, 6, 14, 22, 30) + "mflo %[temp0] \n\t" + "sra %[temp1], %[temp0], 31 \n\t" + "xor %[temp0], %[temp0], %[temp1] \n\t" + "subu %[temp0], %[temp0], %[temp1] \n\t" + "sra %[temp0], %[temp0], 5 \n\t" + + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8) + : [a]"r"(a), [b]"r"(b), [w]"r"(w), [tmp]"r"(tmp) + : "memory", "hi", "lo" + ); + + return temp0; +} + +#undef VERTICAL_PASS +#undef HORIZONTAL_PASS + +static int Disto16x16_MIPS32(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4_MIPS32(a + x + y, b + x + y, w); + } + } + return D; +} + +// macro for one horizontal pass in FTransform +// temp0..temp15 holds tmp[0]..tmp[15] +// A - offset in bytes to load from src and ref buffers +// TEMP0..TEMP3 - registers for corresponding tmp elements +#define HORIZONTAL_PASS(A, TEMP0, TEMP1, TEMP2, TEMP3) \ + "lw %[" #TEMP1 "], 0(%[args]) \n\t" \ + "lw %[" #TEMP2 "], 4(%[args]) \n\t" \ + "lbu %[temp16], 0+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ + "lbu %[temp17], 0+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \ + "lbu %[temp18], 1+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ + "lbu %[temp19], 1+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \ + "subu %[temp20], %[temp16], %[temp17] \n\t" \ + "lbu %[temp16], 2+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ + "lbu %[temp17], 2+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \ + "subu %[" #TEMP0 "], %[temp18], %[temp19] \n\t" \ + "lbu %[temp18], 3+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ + "lbu %[temp19], 3+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \ + "subu %[" #TEMP1 "], %[temp16], %[temp17] \n\t" \ + "subu %[" #TEMP2 "], %[temp18], %[temp19] \n\t" \ + "addu %[" #TEMP3 "], %[temp20], %[" #TEMP2 "] \n\t" \ + "subu %[" #TEMP2 "], %[temp20], %[" #TEMP2 "] \n\t" \ + "addu %[temp20], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \ + "subu %[" #TEMP0 "], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \ + "mul %[temp16], %[" #TEMP2 "], %[c5352] \n\t" \ + "mul %[temp17], %[" #TEMP2 "], %[c2217] \n\t" \ + "mul %[temp18], %[" #TEMP0 "], %[c5352] \n\t" \ + "mul %[temp19], %[" #TEMP0 "], %[c2217] \n\t" \ + "addu %[" #TEMP1 "], %[" #TEMP3 "], %[temp20] \n\t" \ + "subu %[temp20], %[" #TEMP3 "], %[temp20] \n\t" \ + "sll %[" #TEMP0 "], %[" #TEMP1 "], 3 \n\t" \ + "sll %[" #TEMP2 "], %[temp20], 3 \n\t" \ + "addiu %[temp16], %[temp16], 1812 \n\t" \ + "addiu %[temp17], %[temp17], 937 \n\t" \ + "addu %[temp16], %[temp16], %[temp19] \n\t" \ + "subu %[temp17], %[temp17], %[temp18] \n\t" \ + "sra %[" #TEMP1 "], %[temp16], 9 \n\t" \ + "sra %[" #TEMP3 "], %[temp17], 9 \n\t" + +// macro for one vertical pass in FTransform +// temp0..temp15 holds tmp[0]..tmp[15] +// A..D - offsets in bytes to store to out buffer +// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements +#define VERTICAL_PASS(A, B, C, D, TEMP0, TEMP4, TEMP8, TEMP12) \ + "addu %[temp16], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \ + "subu %[temp19], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \ + "addu %[temp17], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \ + "subu %[temp18], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \ + "mul %[" #TEMP8 "], %[temp19], %[c2217] \n\t" \ + "mul %[" #TEMP12 "], %[temp18], %[c2217] \n\t" \ + "mul %[" #TEMP4 "], %[temp19], %[c5352] \n\t" \ + "mul %[temp18], %[temp18], %[c5352] \n\t" \ + "addiu %[temp16], %[temp16], 7 \n\t" \ + "addu %[" #TEMP0 "], %[temp16], %[temp17] \n\t" \ + "sra %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \ + "addu %[" #TEMP12 "], %[" #TEMP12 "], %[" #TEMP4 "] \n\t" \ + "subu %[" #TEMP4 "], %[temp16], %[temp17] \n\t" \ + "sra %[" #TEMP4 "], %[" #TEMP4 "], 4 \n\t" \ + "addiu %[" #TEMP8 "], %[" #TEMP8 "], 30000 \n\t" \ + "addiu %[" #TEMP12 "], %[" #TEMP12 "], 12000 \n\t" \ + "addiu %[" #TEMP8 "], %[" #TEMP8 "], 21000 \n\t" \ + "subu %[" #TEMP8 "], %[" #TEMP8 "], %[temp18] \n\t" \ + "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \ + "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \ + "addiu %[temp16], %[" #TEMP12 "], 1 \n\t" \ + "movn %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \ + "sh %[" #TEMP0 "], " #A "(%[temp20]) \n\t" \ + "sh %[" #TEMP4 "], " #C "(%[temp20]) \n\t" \ + "sh %[" #TEMP8 "], " #D "(%[temp20]) \n\t" \ + "sh %[" #TEMP12 "], " #B "(%[temp20]) \n\t" + +static void FTransform_MIPS32(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; + int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16; + int temp17, temp18, temp19, temp20; + const int c2217 = 2217; + const int c5352 = 5352; + const int* const args[3] = + { (const int*)src, (const int*)ref, (const int*)out }; + + __asm__ volatile( + HORIZONTAL_PASS(0, temp0, temp1, temp2, temp3) + HORIZONTAL_PASS(1, temp4, temp5, temp6, temp7) + HORIZONTAL_PASS(2, temp8, temp9, temp10, temp11) + HORIZONTAL_PASS(3, temp12, temp13, temp14, temp15) + "lw %[temp20], 8(%[args]) \n\t" + VERTICAL_PASS(0, 8, 16, 24, temp0, temp4, temp8, temp12) + VERTICAL_PASS(2, 10, 18, 26, temp1, temp5, temp9, temp13) + VERTICAL_PASS(4, 12, 20, 28, temp2, temp6, temp10, temp14) + VERTICAL_PASS(6, 14, 22, 30, temp3, temp7, temp11, temp15) + + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11), + [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14), + [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17), + [temp18]"=&r"(temp18), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20) + : [args]"r"(args), [c2217]"r"(c2217), [c5352]"r"(c5352) + : "memory", "hi", "lo" + ); +} + +#undef VERTICAL_PASS +#undef HORIZONTAL_PASS + +#if !defined(WORK_AROUND_GCC) + +#define GET_SSE_INNER(A, B, C, D) \ + "lbu %[temp0], " #A "(%[a]) \n\t" \ + "lbu %[temp1], " #A "(%[b]) \n\t" \ + "lbu %[temp2], " #B "(%[a]) \n\t" \ + "lbu %[temp3], " #B "(%[b]) \n\t" \ + "lbu %[temp4], " #C "(%[a]) \n\t" \ + "lbu %[temp5], " #C "(%[b]) \n\t" \ + "lbu %[temp6], " #D "(%[a]) \n\t" \ + "lbu %[temp7], " #D "(%[b]) \n\t" \ + "subu %[temp0], %[temp0], %[temp1] \n\t" \ + "subu %[temp2], %[temp2], %[temp3] \n\t" \ + "subu %[temp4], %[temp4], %[temp5] \n\t" \ + "subu %[temp6], %[temp6], %[temp7] \n\t" \ + "madd %[temp0], %[temp0] \n\t" \ + "madd %[temp2], %[temp2] \n\t" \ + "madd %[temp4], %[temp4] \n\t" \ + "madd %[temp6], %[temp6] \n\t" + +#define GET_SSE(A, B, C, D) \ + GET_SSE_INNER(A, A + 1, A + 2, A + 3) \ + GET_SSE_INNER(B, B + 1, B + 2, B + 3) \ + GET_SSE_INNER(C, C + 1, C + 2, C + 3) \ + GET_SSE_INNER(D, D + 1, D + 2, D + 3) + +static int SSE16x16_MIPS32(const uint8_t* a, const uint8_t* b) { + int count; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + + __asm__ volatile( + "mult $zero, $zero \n\t" + + GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS) + GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS) + GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS) + GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS) + GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS) + GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS) + GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS) + GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS) + GET_SSE( 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS) + GET_SSE( 9 * BPS, 4 + 9 * BPS, 8 + 9 * BPS, 12 + 9 * BPS) + GET_SSE(10 * BPS, 4 + 10 * BPS, 8 + 10 * BPS, 12 + 10 * BPS) + GET_SSE(11 * BPS, 4 + 11 * BPS, 8 + 11 * BPS, 12 + 11 * BPS) + GET_SSE(12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS) + GET_SSE(13 * BPS, 4 + 13 * BPS, 8 + 13 * BPS, 12 + 13 * BPS) + GET_SSE(14 * BPS, 4 + 14 * BPS, 8 + 14 * BPS, 12 + 14 * BPS) + GET_SSE(15 * BPS, 4 + 15 * BPS, 8 + 15 * BPS, 12 + 15 * BPS) + + "mflo %[count] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count) + : [a]"r"(a), [b]"r"(b) + : "memory", "hi", "lo" + ); + return count; +} + +static int SSE16x8_MIPS32(const uint8_t* a, const uint8_t* b) { + int count; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + + __asm__ volatile( + "mult $zero, $zero \n\t" + + GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS) + GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS) + GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS) + GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS) + GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS) + GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS) + GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS) + GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS) + + "mflo %[count] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count) + : [a]"r"(a), [b]"r"(b) + : "memory", "hi", "lo" + ); + return count; +} + +static int SSE8x8_MIPS32(const uint8_t* a, const uint8_t* b) { + int count; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + + __asm__ volatile( + "mult $zero, $zero \n\t" + + GET_SSE(0 * BPS, 4 + 0 * BPS, 1 * BPS, 4 + 1 * BPS) + GET_SSE(2 * BPS, 4 + 2 * BPS, 3 * BPS, 4 + 3 * BPS) + GET_SSE(4 * BPS, 4 + 4 * BPS, 5 * BPS, 4 + 5 * BPS) + GET_SSE(6 * BPS, 4 + 6 * BPS, 7 * BPS, 4 + 7 * BPS) + + "mflo %[count] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count) + : [a]"r"(a), [b]"r"(b) + : "memory", "hi", "lo" + ); + return count; +} + +static int SSE4x4_MIPS32(const uint8_t* a, const uint8_t* b) { + int count; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + + __asm__ volatile( + "mult $zero, $zero \n\t" + + GET_SSE(0 * BPS, 1 * BPS, 2 * BPS, 3 * BPS) + + "mflo %[count] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count) + : [a]"r"(a), [b]"r"(b) + : "memory", "hi", "lo" + ); + return count; +} + +#undef GET_SSE +#undef GET_SSE_INNER + +#endif // !WORK_AROUND_GCC + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspInitMIPS32(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMIPS32(void) { + VP8ITransform = ITransform_MIPS32; + VP8FTransform = FTransform_MIPS32; + + VP8EncQuantizeBlock = QuantizeBlock_MIPS32; + VP8EncQuantize2Blocks = Quantize2Blocks_MIPS32; + + VP8TDisto4x4 = Disto4x4_MIPS32; + VP8TDisto16x16 = Disto16x16_MIPS32; + +#if !defined(WORK_AROUND_GCC) + VP8SSE16x16 = SSE16x16_MIPS32; + VP8SSE8x8 = SSE8x8_MIPS32; + VP8SSE16x8 = SSE16x8_MIPS32; + VP8SSE4x4 = SSE4x4_MIPS32; +#endif +} + +#else // !WEBP_USE_MIPS32 + +WEBP_DSP_INIT_STUB(VP8EncDspInitMIPS32) + +#endif // WEBP_USE_MIPS32 diff --git a/libraries/webp/src/dsp/enc_mips_dsp_r2.c b/libraries/webp/src/dsp/enc_mips_dsp_r2.c new file mode 100644 index 00000000000..e1431f3bef2 --- /dev/null +++ b/libraries/webp/src/dsp/enc_mips_dsp_r2.c @@ -0,0 +1,1517 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS version of speed-critical encoding functions. +// +// Author(s): Darko Laus (darko.laus@imgtec.com) +// Mirko Raus (mirko.raus@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +#include "src/dsp/mips_macro.h" +#include "src/enc/cost_enc.h" +#include "src/enc/vp8i_enc.h" + +static const int kC1 = WEBP_TRANSFORM_AC3_C1; +static const int kC2 = WEBP_TRANSFORM_AC3_C2; + +// O - output +// I - input (macro doesn't change it) +#define ADD_SUB_HALVES_X4(O0, O1, O2, O3, O4, O5, O6, O7, \ + I0, I1, I2, I3, I4, I5, I6, I7) \ + "addq.ph %[" #O0 "], %[" #I0 "], %[" #I1 "] \n\t" \ + "subq.ph %[" #O1 "], %[" #I0 "], %[" #I1 "] \n\t" \ + "addq.ph %[" #O2 "], %[" #I2 "], %[" #I3 "] \n\t" \ + "subq.ph %[" #O3 "], %[" #I2 "], %[" #I3 "] \n\t" \ + "addq.ph %[" #O4 "], %[" #I4 "], %[" #I5 "] \n\t" \ + "subq.ph %[" #O5 "], %[" #I4 "], %[" #I5 "] \n\t" \ + "addq.ph %[" #O6 "], %[" #I6 "], %[" #I7 "] \n\t" \ + "subq.ph %[" #O7 "], %[" #I6 "], %[" #I7 "] \n\t" + +// IO - input/output +#define ABS_X8(IO0, IO1, IO2, IO3, IO4, IO5, IO6, IO7) \ + "absq_s.ph %[" #IO0 "], %[" #IO0 "] \n\t" \ + "absq_s.ph %[" #IO1 "], %[" #IO1 "] \n\t" \ + "absq_s.ph %[" #IO2 "], %[" #IO2 "] \n\t" \ + "absq_s.ph %[" #IO3 "], %[" #IO3 "] \n\t" \ + "absq_s.ph %[" #IO4 "], %[" #IO4 "] \n\t" \ + "absq_s.ph %[" #IO5 "], %[" #IO5 "] \n\t" \ + "absq_s.ph %[" #IO6 "], %[" #IO6 "] \n\t" \ + "absq_s.ph %[" #IO7 "], %[" #IO7 "] \n\t" + +// dpa.w.ph $ac0 temp0 ,temp1 +// $ac += temp0[31..16] * temp1[31..16] + temp0[15..0] * temp1[15..0] +// dpax.w.ph $ac0 temp0 ,temp1 +// $ac += temp0[31..16] * temp1[15..0] + temp0[15..0] * temp1[31..16] +// O - output +// I - input (macro doesn't change it) +#define MUL_HALF(O0, I0, I1, I2, I3, I4, I5, I6, I7, \ + I8, I9, I10, I11, I12, I13, I14, I15) \ + "mult $ac0, $zero, $zero \n\t" \ + "dpa.w.ph $ac0, %[" #I2 "], %[" #I0 "] \n\t" \ + "dpax.w.ph $ac0, %[" #I5 "], %[" #I6 "] \n\t" \ + "dpa.w.ph $ac0, %[" #I8 "], %[" #I9 "] \n\t" \ + "dpax.w.ph $ac0, %[" #I11 "], %[" #I4 "] \n\t" \ + "dpa.w.ph $ac0, %[" #I12 "], %[" #I7 "] \n\t" \ + "dpax.w.ph $ac0, %[" #I13 "], %[" #I1 "] \n\t" \ + "dpa.w.ph $ac0, %[" #I14 "], %[" #I3 "] \n\t" \ + "dpax.w.ph $ac0, %[" #I15 "], %[" #I10 "] \n\t" \ + "mflo %[" #O0 "], $ac0 \n\t" + +#define OUTPUT_EARLY_CLOBBER_REGS_17() \ + OUTPUT_EARLY_CLOBBER_REGS_10(), \ + [temp11]"=&r"(temp11), [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), \ + [temp14]"=&r"(temp14), [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), \ + [temp17]"=&r"(temp17) + +// macro for one horizontal pass in FTransform +// temp0..temp15 holds tmp[0]..tmp[15] +// A - offset in bytes to load from src and ref buffers +// TEMP0..TEMP3 - registers for corresponding tmp elements +#define HORIZONTAL_PASS(A, TEMP0, TEMP1, TEMP2, TEMP3) \ + "lw %[" #TEMP0 "], 0(%[args]) \n\t" \ + "lw %[" #TEMP1 "], 4(%[args]) \n\t" \ + "lw %[" #TEMP2 "], " XSTR(BPS) "*" #A "(%[" #TEMP0 "]) \n\t" \ + "lw %[" #TEMP3 "], " XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ + "preceu.ph.qbl %[" #TEMP0 "], %[" #TEMP2 "] \n\t" \ + "preceu.ph.qbl %[" #TEMP1 "], %[" #TEMP3 "] \n\t" \ + "preceu.ph.qbr %[" #TEMP2 "], %[" #TEMP2 "] \n\t" \ + "preceu.ph.qbr %[" #TEMP3 "], %[" #TEMP3 "] \n\t" \ + "subq.ph %[" #TEMP0 "], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \ + "subq.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP3 "] \n\t" \ + "rotr %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \ + "addq.ph %[" #TEMP1 "], %[" #TEMP2 "], %[" #TEMP0 "] \n\t" \ + "subq.ph %[" #TEMP3 "], %[" #TEMP2 "], %[" #TEMP0 "] \n\t" \ + "seh %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \ + "sra %[temp16], %[" #TEMP1 "], 16 \n\t" \ + "seh %[temp19], %[" #TEMP3 "] \n\t" \ + "sra %[" #TEMP3 "], %[" #TEMP3 "], 16 \n\t" \ + "subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp16] \n\t" \ + "addu %[" #TEMP0 "], %[" #TEMP0 "], %[temp16] \n\t" \ + "mul %[temp17], %[temp19], %[c2217] \n\t" \ + "mul %[temp18], %[" #TEMP3 "], %[c5352] \n\t" \ + "mul %[" #TEMP1 "], %[temp19], %[c5352] \n\t" \ + "mul %[temp16], %[" #TEMP3 "], %[c2217] \n\t" \ + "sll %[" #TEMP2 "], %[" #TEMP2 "], 3 \n\t" \ + "sll %[" #TEMP0 "], %[" #TEMP0 "], 3 \n\t" \ + "subu %[" #TEMP3 "], %[temp17], %[temp18] \n\t" \ + "addu %[" #TEMP1 "], %[temp16], %[" #TEMP1 "] \n\t" \ + "addiu %[" #TEMP3 "], %[" #TEMP3 "], 937 \n\t" \ + "addiu %[" #TEMP1 "], %[" #TEMP1 "], 1812 \n\t" \ + "sra %[" #TEMP3 "], %[" #TEMP3 "], 9 \n\t" \ + "sra %[" #TEMP1 "], %[" #TEMP1 "], 9 \n\t" + +// macro for one vertical pass in FTransform +// temp0..temp15 holds tmp[0]..tmp[15] +// A..D - offsets in bytes to store to out buffer +// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements +#define VERTICAL_PASS(A, B, C, D, TEMP0, TEMP4, TEMP8, TEMP12) \ + "addu %[temp16], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \ + "subu %[temp19], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \ + "addu %[temp17], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \ + "subu %[temp18], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \ + "mul %[" #TEMP8 "], %[temp19], %[c2217] \n\t" \ + "mul %[" #TEMP12 "], %[temp18], %[c2217] \n\t" \ + "mul %[" #TEMP4 "], %[temp19], %[c5352] \n\t" \ + "mul %[temp18], %[temp18], %[c5352] \n\t" \ + "addiu %[temp16], %[temp16], 7 \n\t" \ + "addu %[" #TEMP0 "], %[temp16], %[temp17] \n\t" \ + "sra %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \ + "addu %[" #TEMP12 "], %[" #TEMP12 "], %[" #TEMP4 "] \n\t" \ + "subu %[" #TEMP4 "], %[temp16], %[temp17] \n\t" \ + "sra %[" #TEMP4 "], %[" #TEMP4 "], 4 \n\t" \ + "addiu %[" #TEMP8 "], %[" #TEMP8 "], 30000 \n\t" \ + "addiu %[" #TEMP12 "], %[" #TEMP12 "], 12000 \n\t" \ + "addiu %[" #TEMP8 "], %[" #TEMP8 "], 21000 \n\t" \ + "subu %[" #TEMP8 "], %[" #TEMP8 "], %[temp18] \n\t" \ + "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \ + "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \ + "addiu %[temp16], %[" #TEMP12 "], 1 \n\t" \ + "movn %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \ + "sh %[" #TEMP0 "], " #A "(%[temp20]) \n\t" \ + "sh %[" #TEMP4 "], " #C "(%[temp20]) \n\t" \ + "sh %[" #TEMP8 "], " #D "(%[temp20]) \n\t" \ + "sh %[" #TEMP12 "], " #B "(%[temp20]) \n\t" + +static void FTransform_MIPSdspR2(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + const int c2217 = 2217; + const int c5352 = 5352; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; + int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16; + int temp17, temp18, temp19, temp20; + const int* const args[3] = + { (const int*)src, (const int*)ref, (const int*)out }; + + __asm__ volatile ( + HORIZONTAL_PASS(0, temp0, temp1, temp2, temp3) + HORIZONTAL_PASS(1, temp4, temp5, temp6, temp7) + HORIZONTAL_PASS(2, temp8, temp9, temp10, temp11) + HORIZONTAL_PASS(3, temp12, temp13, temp14, temp15) + "lw %[temp20], 8(%[args]) \n\t" + VERTICAL_PASS(0, 8, 16, 24, temp0, temp4, temp8, temp12) + VERTICAL_PASS(2, 10, 18, 26, temp1, temp5, temp9, temp13) + VERTICAL_PASS(4, 12, 20, 28, temp2, temp6, temp10, temp14) + VERTICAL_PASS(6, 14, 22, 30, temp3, temp7, temp11, temp15) + OUTPUT_EARLY_CLOBBER_REGS_18(), + [temp0]"=&r"(temp0), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20) + : [args]"r"(args), [c2217]"r"(c2217), [c5352]"r"(c5352) + : "memory", "hi", "lo" + ); +} + +#undef VERTICAL_PASS +#undef HORIZONTAL_PASS + +static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, + uint8_t* dst) { + int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; + int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18; + + __asm__ volatile ( + "ulw %[temp1], 0(%[in]) \n\t" + "ulw %[temp2], 16(%[in]) \n\t" + LOAD_IN_X2(temp5, temp6, 24, 26) + ADD_SUB_HALVES(temp3, temp4, temp1, temp2) + LOAD_IN_X2(temp1, temp2, 8, 10) + MUL_SHIFT_SUM(temp7, temp8, temp9, temp10, temp11, temp12, temp13, temp14, + temp10, temp8, temp9, temp7, temp1, temp2, temp5, temp6, + temp13, temp11, temp14, temp12) + INSERT_HALF_X2(temp8, temp7, temp10, temp9) + "ulw %[temp17], 4(%[in]) \n\t" + "ulw %[temp18], 20(%[in]) \n\t" + ADD_SUB_HALVES(temp1, temp2, temp3, temp8) + ADD_SUB_HALVES(temp5, temp6, temp4, temp7) + ADD_SUB_HALVES(temp7, temp8, temp17, temp18) + LOAD_IN_X2(temp17, temp18, 12, 14) + LOAD_IN_X2(temp9, temp10, 28, 30) + MUL_SHIFT_SUM(temp11, temp12, temp13, temp14, temp15, temp16, temp4, temp17, + temp12, temp14, temp11, temp13, temp17, temp18, temp9, temp10, + temp15, temp4, temp16, temp17) + INSERT_HALF_X2(temp11, temp12, temp13, temp14) + ADD_SUB_HALVES(temp17, temp8, temp8, temp11) + ADD_SUB_HALVES(temp3, temp4, temp7, temp12) + + // horizontal + SRA_16(temp9, temp10, temp11, temp12, temp1, temp2, temp5, temp6) + INSERT_HALF_X2(temp1, temp6, temp5, temp2) + SRA_16(temp13, temp14, temp15, temp16, temp3, temp4, temp17, temp8) + "repl.ph %[temp2], 0x4 \n\t" + INSERT_HALF_X2(temp3, temp8, temp17, temp4) + "addq.ph %[temp1], %[temp1], %[temp2] \n\t" + "addq.ph %[temp6], %[temp6], %[temp2] \n\t" + ADD_SUB_HALVES(temp2, temp4, temp1, temp3) + ADD_SUB_HALVES(temp5, temp7, temp6, temp8) + MUL_SHIFT_SUM(temp1, temp3, temp6, temp8, temp9, temp13, temp17, temp18, + temp3, temp13, temp1, temp9, temp9, temp13, temp11, temp15, + temp6, temp17, temp8, temp18) + MUL_SHIFT_SUM(temp6, temp8, temp18, temp17, temp11, temp15, temp12, temp16, + temp8, temp15, temp6, temp11, temp12, temp16, temp10, temp14, + temp18, temp12, temp17, temp16) + INSERT_HALF_X2(temp1, temp3, temp9, temp13) + INSERT_HALF_X2(temp6, temp8, temp11, temp15) + SHIFT_R_SUM_X2(temp9, temp10, temp11, temp12, temp13, temp14, temp15, + temp16, temp2, temp4, temp5, temp7, temp3, temp1, temp8, + temp6) + PACK_2_HALVES_TO_WORD(temp1, temp2, temp3, temp4, temp9, temp12, temp13, + temp16, temp11, temp10, temp15, temp14) + LOAD_WITH_OFFSET_X4(temp10, temp11, temp14, temp15, ref, + 0, 0, 0, 0, + 0, 1, 2, 3, + BPS) + CONVERT_2_BYTES_TO_HALF(temp5, temp6, temp7, temp8, temp17, temp18, temp10, + temp11, temp10, temp11, temp14, temp15) + STORE_SAT_SUM_X2(temp5, temp6, temp7, temp8, temp17, temp18, temp10, temp11, + temp9, temp12, temp1, temp2, temp13, temp16, temp3, temp4, + dst, 0, 1, 2, 3, BPS) + + OUTPUT_EARLY_CLOBBER_REGS_18() + : [dst]"r"(dst), [in]"r"(in), [kC1]"r"(kC1), [kC2]"r"(kC2), [ref]"r"(ref) + : "memory", "hi", "lo" + ); +} + +static void ITransform_MIPSdspR2(const uint8_t* ref, const int16_t* in, + uint8_t* dst, int do_two) { + ITransformOne(ref, in, dst); + if (do_two) { + ITransformOne(ref + 4, in + 16, dst + 4); + } +} + +static int Disto4x4_MIPSdspR2(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; + int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17; + + __asm__ volatile ( + LOAD_WITH_OFFSET_X4(temp1, temp2, temp3, temp4, a, + 0, 0, 0, 0, + 0, 1, 2, 3, + BPS) + CONVERT_2_BYTES_TO_HALF(temp5, temp6, temp7, temp8, temp9,temp10, temp11, + temp12, temp1, temp2, temp3, temp4) + ADD_SUB_HALVES_X4(temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, + temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12) + PACK_2_HALVES_TO_WORD(temp9, temp10, temp11, temp12, temp1, temp3, temp5, + temp7, temp2, temp4, temp6, temp8) + ADD_SUB_HALVES_X4(temp2, temp4, temp6, temp8, temp9, temp1, temp3, temp10, + temp1, temp9, temp3, temp10, temp5, temp11, temp7, temp12) + ADD_SUB_HALVES_X4(temp5, temp11, temp7, temp2, temp9, temp3, temp6, temp12, + temp2, temp9, temp6, temp3, temp4, temp1, temp8, temp10) + ADD_SUB_HALVES_X4(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2, + temp5, temp7, temp11, temp2, temp9, temp6, temp3, temp12) + ABS_X8(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2) + LOAD_WITH_OFFSET_X4(temp3, temp6, temp9, temp12, w, + 0, 4, 8, 12, + 0, 0, 0, 0, + 0) + LOAD_WITH_OFFSET_X4(temp13, temp14, temp15, temp16, w, + 0, 4, 8, 12, + 1, 1, 1, 1, + 16) + MUL_HALF(temp17, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, + temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16) + LOAD_WITH_OFFSET_X4(temp1, temp2, temp3, temp4, b, + 0, 0, 0, 0, + 0, 1, 2, 3, + BPS) + CONVERT_2_BYTES_TO_HALF(temp5,temp6, temp7, temp8, temp9,temp10, temp11, + temp12, temp1, temp2, temp3, temp4) + ADD_SUB_HALVES_X4(temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, + temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12) + PACK_2_HALVES_TO_WORD(temp9, temp10, temp11, temp12, temp1, temp3, temp5, + temp7, temp2, temp4, temp6, temp8) + ADD_SUB_HALVES_X4(temp2, temp4, temp6, temp8, temp9, temp1, temp3, temp10, + temp1, temp9, temp3, temp10, temp5, temp11, temp7, temp12) + ADD_SUB_HALVES_X4(temp5, temp11, temp7, temp2, temp9, temp3, temp6, temp12, + temp2, temp9, temp6, temp3, temp4, temp1, temp8, temp10) + ADD_SUB_HALVES_X4(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2, + temp5, temp7, temp11, temp2, temp9, temp6, temp3, temp12) + ABS_X8(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2) + LOAD_WITH_OFFSET_X4(temp3, temp6, temp9, temp12, w, + 0, 4, 8, 12, + 0, 0, 0, 0, + 0) + LOAD_WITH_OFFSET_X4(temp13, temp14, temp15, temp16, w, + 0, 4, 8, 12, + 1, 1, 1, 1, + 16) + MUL_HALF(temp3, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, + temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16) + OUTPUT_EARLY_CLOBBER_REGS_17() + : [a]"r"(a), [b]"r"(b), [w]"r"(w) + : "memory", "hi", "lo" + ); + return abs(temp3 - temp17) >> 5; +} + +static int Disto16x16_MIPSdspR2(const uint8_t* const a, + const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4_MIPSdspR2(a + x + y, b + x + y, w); + } + } + return D; +} + +//------------------------------------------------------------------------------ +// Intra predictions + +#define FILL_PART(J, SIZE) \ + "usw %[value], 0+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \ + "usw %[value], 4+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \ + ".if " #SIZE " == 16 \n\t" \ + "usw %[value], 8+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \ + "usw %[value], 12+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \ + ".endif \n\t" + +#define FILL_8_OR_16(DST, VALUE, SIZE) do { \ + int value = (VALUE); \ + __asm__ volatile ( \ + "replv.qb %[value], %[value] \n\t" \ + FILL_PART( 0, SIZE) \ + FILL_PART( 1, SIZE) \ + FILL_PART( 2, SIZE) \ + FILL_PART( 3, SIZE) \ + FILL_PART( 4, SIZE) \ + FILL_PART( 5, SIZE) \ + FILL_PART( 6, SIZE) \ + FILL_PART( 7, SIZE) \ + ".if " #SIZE " == 16 \n\t" \ + FILL_PART( 8, 16) \ + FILL_PART( 9, 16) \ + FILL_PART(10, 16) \ + FILL_PART(11, 16) \ + FILL_PART(12, 16) \ + FILL_PART(13, 16) \ + FILL_PART(14, 16) \ + FILL_PART(15, 16) \ + ".endif \n\t" \ + : [value]"+&r"(value) \ + : [dst]"r"((DST)) \ + : "memory" \ + ); \ +} while (0) + +#define VERTICAL_PRED(DST, TOP, SIZE) \ +static WEBP_INLINE void VerticalPred##SIZE(uint8_t* (DST), \ + const uint8_t* (TOP)) { \ + int j; \ + if ((TOP)) { \ + for (j = 0; j < (SIZE); ++j) memcpy((DST) + j * BPS, (TOP), (SIZE)); \ + } else { \ + FILL_8_OR_16((DST), 127, (SIZE)); \ + } \ +} + +VERTICAL_PRED(dst, top, 8) +VERTICAL_PRED(dst, top, 16) + +#undef VERTICAL_PRED + +#define HORIZONTAL_PRED(DST, LEFT, SIZE) \ +static WEBP_INLINE void HorizontalPred##SIZE(uint8_t* (DST), \ + const uint8_t* (LEFT)) { \ + if (LEFT) { \ + int j; \ + for (j = 0; j < (SIZE); ++j) { \ + memset((DST) + j * BPS, (LEFT)[j], (SIZE)); \ + } \ + } else { \ + FILL_8_OR_16((DST), 129, (SIZE)); \ + } \ +} + +HORIZONTAL_PRED(dst, left, 8) +HORIZONTAL_PRED(dst, left, 16) + +#undef HORIZONTAL_PRED + +#define CLIPPING() \ + "preceu.ph.qbl %[temp2], %[temp0] \n\t" \ + "preceu.ph.qbr %[temp0], %[temp0] \n\t" \ + "preceu.ph.qbl %[temp3], %[temp1] \n\t" \ + "preceu.ph.qbr %[temp1], %[temp1] \n\t" \ + "addu.ph %[temp2], %[temp2], %[leftY_1] \n\t" \ + "addu.ph %[temp0], %[temp0], %[leftY_1] \n\t" \ + "addu.ph %[temp3], %[temp3], %[leftY_1] \n\t" \ + "addu.ph %[temp1], %[temp1], %[leftY_1] \n\t" \ + "shll_s.ph %[temp2], %[temp2], 7 \n\t" \ + "shll_s.ph %[temp0], %[temp0], 7 \n\t" \ + "shll_s.ph %[temp3], %[temp3], 7 \n\t" \ + "shll_s.ph %[temp1], %[temp1], 7 \n\t" \ + "precrqu_s.qb.ph %[temp0], %[temp2], %[temp0] \n\t" \ + "precrqu_s.qb.ph %[temp1], %[temp3], %[temp1] \n\t" + +#define CLIP_8B_TO_DST(DST, LEFT, TOP, SIZE) do { \ + int leftY_1 = ((int)(LEFT)[y] << 16) + (LEFT)[y]; \ + int temp0, temp1, temp2, temp3; \ + __asm__ volatile ( \ + "replv.ph %[leftY_1], %[leftY_1] \n\t" \ + "ulw %[temp0], 0(%[top]) \n\t" \ + "ulw %[temp1], 4(%[top]) \n\t" \ + "subu.ph %[leftY_1], %[leftY_1], %[left_1] \n\t" \ + CLIPPING() \ + "usw %[temp0], 0(%[dst]) \n\t" \ + "usw %[temp1], 4(%[dst]) \n\t" \ + ".if " #SIZE " == 16 \n\t" \ + "ulw %[temp0], 8(%[top]) \n\t" \ + "ulw %[temp1], 12(%[top]) \n\t" \ + CLIPPING() \ + "usw %[temp0], 8(%[dst]) \n\t" \ + "usw %[temp1], 12(%[dst]) \n\t" \ + ".endif \n\t" \ + : [leftY_1]"+&r"(leftY_1), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \ + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3) \ + : [left_1]"r"(left_1), [top]"r"((TOP)), [dst]"r"((DST)) \ + : "memory" \ + ); \ +} while (0) + +#define CLIP_TO_DST(DST, LEFT, TOP, SIZE) do { \ + int y; \ + const int left_1 = ((int)(LEFT)[-1] << 16) + (LEFT)[-1]; \ + for (y = 0; y < (SIZE); ++y) { \ + CLIP_8B_TO_DST((DST), (LEFT), (TOP), (SIZE)); \ + (DST) += BPS; \ + } \ +} while (0) + +#define TRUE_MOTION(DST, LEFT, TOP, SIZE) \ +static WEBP_INLINE void TrueMotion##SIZE(uint8_t* (DST), const uint8_t* (LEFT),\ + const uint8_t* (TOP)) { \ + if ((LEFT) != NULL) { \ + if ((TOP) != NULL) { \ + CLIP_TO_DST((DST), (LEFT), (TOP), (SIZE)); \ + } else { \ + HorizontalPred##SIZE((DST), (LEFT)); \ + } \ + } else { \ + /* true motion without left samples (hence: with default 129 value) */ \ + /* is equivalent to VE prediction where you just copy the top samples. */ \ + /* Note that if top samples are not available, the default value is */ \ + /* then 129, and not 127 as in the VerticalPred case. */ \ + if ((TOP) != NULL) { \ + VerticalPred##SIZE((DST), (TOP)); \ + } else { \ + FILL_8_OR_16((DST), 129, (SIZE)); \ + } \ + } \ +} + +TRUE_MOTION(dst, left, top, 8) +TRUE_MOTION(dst, left, top, 16) + +#undef TRUE_MOTION +#undef CLIP_TO_DST +#undef CLIP_8B_TO_DST +#undef CLIPPING + +static WEBP_INLINE void DCMode16(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + int DC, DC1; + int temp0, temp1, temp2, temp3; + + __asm__ volatile( + "beqz %[top], 2f \n\t" + LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, top, + 0, 4, 8, 12, + 0, 0, 0, 0, + 0) + "raddu.w.qb %[temp0], %[temp0] \n\t" + "raddu.w.qb %[temp1], %[temp1] \n\t" + "raddu.w.qb %[temp2], %[temp2] \n\t" + "raddu.w.qb %[temp3], %[temp3] \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "addu %[temp2], %[temp2], %[temp3] \n\t" + "addu %[DC], %[temp0], %[temp2] \n\t" + "move %[DC1], %[DC] \n\t" + "beqz %[left], 1f \n\t" + LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, left, + 0, 4, 8, 12, + 0, 0, 0, 0, + 0) + "raddu.w.qb %[temp0], %[temp0] \n\t" + "raddu.w.qb %[temp1], %[temp1] \n\t" + "raddu.w.qb %[temp2], %[temp2] \n\t" + "raddu.w.qb %[temp3], %[temp3] \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "addu %[temp2], %[temp2], %[temp3] \n\t" + "addu %[DC1], %[temp0], %[temp2] \n\t" + "1: \n\t" + "addu %[DC], %[DC], %[DC1] \n\t" + "j 3f \n\t" + "2: \n\t" + "beqz %[left], 4f \n\t" + LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, left, + 0, 4, 8, 12, + 0, 0, 0, 0, + 0) + "raddu.w.qb %[temp0], %[temp0] \n\t" + "raddu.w.qb %[temp1], %[temp1] \n\t" + "raddu.w.qb %[temp2], %[temp2] \n\t" + "raddu.w.qb %[temp3], %[temp3] \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "addu %[temp2], %[temp2], %[temp3] \n\t" + "addu %[DC], %[temp0], %[temp2] \n\t" + "addu %[DC], %[DC], %[DC] \n\t" + "3: \n\t" + "shra_r.w %[DC], %[DC], 5 \n\t" + "j 5f \n\t" + "4: \n\t" + "li %[DC], 0x80 \n\t" + "5: \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [DC]"=&r"(DC), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [DC1]"=&r"(DC1) + : [left]"r"(left), [top]"r"(top) + : "memory" + ); + + FILL_8_OR_16(dst, DC, 16); +} + +static WEBP_INLINE void DCMode8(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + int DC, DC1; + int temp0, temp1, temp2, temp3; + + __asm__ volatile( + "beqz %[top], 2f \n\t" + "ulw %[temp0], 0(%[top]) \n\t" + "ulw %[temp1], 4(%[top]) \n\t" + "raddu.w.qb %[temp0], %[temp0] \n\t" + "raddu.w.qb %[temp1], %[temp1] \n\t" + "addu %[DC], %[temp0], %[temp1] \n\t" + "move %[DC1], %[DC] \n\t" + "beqz %[left], 1f \n\t" + "ulw %[temp2], 0(%[left]) \n\t" + "ulw %[temp3], 4(%[left]) \n\t" + "raddu.w.qb %[temp2], %[temp2] \n\t" + "raddu.w.qb %[temp3], %[temp3] \n\t" + "addu %[DC1], %[temp2], %[temp3] \n\t" + "1: \n\t" + "addu %[DC], %[DC], %[DC1] \n\t" + "j 3f \n\t" + "2: \n\t" + "beqz %[left], 4f \n\t" + "ulw %[temp2], 0(%[left]) \n\t" + "ulw %[temp3], 4(%[left]) \n\t" + "raddu.w.qb %[temp2], %[temp2] \n\t" + "raddu.w.qb %[temp3], %[temp3] \n\t" + "addu %[DC], %[temp2], %[temp3] \n\t" + "addu %[DC], %[DC], %[DC] \n\t" + "3: \n\t" + "shra_r.w %[DC], %[DC], 4 \n\t" + "j 5f \n\t" + "4: \n\t" + "li %[DC], 0x80 \n\t" + "5: \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [DC]"=&r"(DC), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [DC1]"=&r"(DC1) + : [left]"r"(left), [top]"r"(top) + : "memory" + ); + + FILL_8_OR_16(dst, DC, 8); +} + +static void DC4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1; + __asm__ volatile( + "ulw %[temp0], 0(%[top]) \n\t" + "ulw %[temp1], -5(%[top]) \n\t" + "raddu.w.qb %[temp0], %[temp0] \n\t" + "raddu.w.qb %[temp1], %[temp1] \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "addiu %[temp0], %[temp0], 4 \n\t" + "srl %[temp0], %[temp0], 3 \n\t" + "replv.qb %[temp0], %[temp0] \n\t" + "usw %[temp0], 0*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp0], 2*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp0], 3*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void TM4(uint8_t* dst, const uint8_t* top) { + int a10, a32, temp0, temp1, temp2, temp3, temp4, temp5; + const int c35 = 0xff00ff; + __asm__ volatile ( + "lbu %[temp1], 0(%[top]) \n\t" + "lbu %[a10], 1(%[top]) \n\t" + "lbu %[temp2], 2(%[top]) \n\t" + "lbu %[a32], 3(%[top]) \n\t" + "ulw %[temp0], -5(%[top]) \n\t" + "lbu %[temp4], -1(%[top]) \n\t" + "append %[a10], %[temp1], 16 \n\t" + "append %[a32], %[temp2], 16 \n\t" + "replv.ph %[temp4], %[temp4] \n\t" + "shrl.ph %[temp1], %[temp0], 8 \n\t" + "and %[temp0], %[temp0], %[c35] \n\t" + "subu.ph %[temp1], %[temp1], %[temp4] \n\t" + "subu.ph %[temp0], %[temp0], %[temp4] \n\t" + "srl %[temp2], %[temp1], 16 \n\t" + "srl %[temp3], %[temp0], 16 \n\t" + "replv.ph %[temp2], %[temp2] \n\t" + "replv.ph %[temp3], %[temp3] \n\t" + "replv.ph %[temp4], %[temp1] \n\t" + "replv.ph %[temp5], %[temp0] \n\t" + "addu.ph %[temp0], %[temp3], %[a10] \n\t" + "addu.ph %[temp1], %[temp3], %[a32] \n\t" + "addu.ph %[temp3], %[temp2], %[a10] \n\t" + "addu.ph %[temp2], %[temp2], %[a32] \n\t" + "shll_s.ph %[temp0], %[temp0], 7 \n\t" + "shll_s.ph %[temp1], %[temp1], 7 \n\t" + "shll_s.ph %[temp3], %[temp3], 7 \n\t" + "shll_s.ph %[temp2], %[temp2], 7 \n\t" + "precrqu_s.qb.ph %[temp0], %[temp1], %[temp0] \n\t" + "precrqu_s.qb.ph %[temp1], %[temp2], %[temp3] \n\t" + "addu.ph %[temp2], %[temp5], %[a10] \n\t" + "addu.ph %[temp3], %[temp5], %[a32] \n\t" + "addu.ph %[temp5], %[temp4], %[a10] \n\t" + "addu.ph %[temp4], %[temp4], %[a32] \n\t" + "shll_s.ph %[temp2], %[temp2], 7 \n\t" + "shll_s.ph %[temp3], %[temp3], 7 \n\t" + "shll_s.ph %[temp4], %[temp4], 7 \n\t" + "shll_s.ph %[temp5], %[temp5], 7 \n\t" + "precrqu_s.qb.ph %[temp2], %[temp3], %[temp2] \n\t" + "precrqu_s.qb.ph %[temp3], %[temp4], %[temp5] \n\t" + "usw %[temp1], 0*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp3], 2*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp2], 3*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [a10]"=&r"(a10), [a32]"=&r"(a32) + : [c35]"r"(c35), [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void VE4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1, temp2, temp3, temp4, temp5, temp6; + __asm__ volatile( + "ulw %[temp0], -1(%[top]) \n\t" + "ulh %[temp1], 3(%[top]) \n\t" + "preceu.ph.qbr %[temp2], %[temp0] \n\t" + "preceu.ph.qbl %[temp3], %[temp0] \n\t" + "preceu.ph.qbr %[temp4], %[temp1] \n\t" + "packrl.ph %[temp5], %[temp3], %[temp2] \n\t" + "packrl.ph %[temp6], %[temp4], %[temp3] \n\t" + "shll.ph %[temp5], %[temp5], 1 \n\t" + "shll.ph %[temp6], %[temp6], 1 \n\t" + "addq.ph %[temp2], %[temp5], %[temp2] \n\t" + "addq.ph %[temp6], %[temp6], %[temp4] \n\t" + "addq.ph %[temp2], %[temp2], %[temp3] \n\t" + "addq.ph %[temp6], %[temp6], %[temp3] \n\t" + "shra_r.ph %[temp2], %[temp2], 2 \n\t" + "shra_r.ph %[temp6], %[temp6], 2 \n\t" + "precr.qb.ph %[temp4], %[temp6], %[temp2] \n\t" + "usw %[temp4], 0*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp4], 1*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp4], 2*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp4], 3*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void HE4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1, temp2, temp3, temp4, temp5, temp6; + __asm__ volatile( + "ulw %[temp0], -4(%[top]) \n\t" + "lbu %[temp1], -5(%[top]) \n\t" + "preceu.ph.qbr %[temp2], %[temp0] \n\t" + "preceu.ph.qbl %[temp3], %[temp0] \n\t" + "replv.ph %[temp4], %[temp1] \n\t" + "packrl.ph %[temp5], %[temp3], %[temp2] \n\t" + "packrl.ph %[temp6], %[temp2], %[temp4] \n\t" + "shll.ph %[temp5], %[temp5], 1 \n\t" + "shll.ph %[temp6], %[temp6], 1 \n\t" + "addq.ph %[temp3], %[temp3], %[temp5] \n\t" + "addq.ph %[temp3], %[temp3], %[temp2] \n\t" + "addq.ph %[temp2], %[temp2], %[temp6] \n\t" + "addq.ph %[temp2], %[temp2], %[temp4] \n\t" + "shra_r.ph %[temp3], %[temp3], 2 \n\t" + "shra_r.ph %[temp2], %[temp2], 2 \n\t" + "replv.qb %[temp0], %[temp3] \n\t" + "replv.qb %[temp1], %[temp2] \n\t" + "srl %[temp3], %[temp3], 16 \n\t" + "srl %[temp2], %[temp2], 16 \n\t" + "replv.qb %[temp3], %[temp3] \n\t" + "replv.qb %[temp2], %[temp2] \n\t" + "usw %[temp3], 0*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp2], 2*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp1], 3*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void RD4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1, temp2, temp3, temp4, temp5; + int temp6, temp7, temp8, temp9, temp10, temp11; + __asm__ volatile( + "ulw %[temp0], -5(%[top]) \n\t" + "ulw %[temp1], -1(%[top]) \n\t" + "preceu.ph.qbl %[temp2], %[temp0] \n\t" + "preceu.ph.qbr %[temp3], %[temp0] \n\t" + "preceu.ph.qbr %[temp4], %[temp1] \n\t" + "preceu.ph.qbl %[temp5], %[temp1] \n\t" + "packrl.ph %[temp6], %[temp2], %[temp3] \n\t" + "packrl.ph %[temp7], %[temp4], %[temp2] \n\t" + "packrl.ph %[temp8], %[temp5], %[temp4] \n\t" + "shll.ph %[temp6], %[temp6], 1 \n\t" + "addq.ph %[temp9], %[temp2], %[temp6] \n\t" + "shll.ph %[temp7], %[temp7], 1 \n\t" + "addq.ph %[temp9], %[temp9], %[temp3] \n\t" + "shll.ph %[temp8], %[temp8], 1 \n\t" + "shra_r.ph %[temp9], %[temp9], 2 \n\t" + "addq.ph %[temp10], %[temp4], %[temp7] \n\t" + "addq.ph %[temp11], %[temp5], %[temp8] \n\t" + "addq.ph %[temp10], %[temp10], %[temp2] \n\t" + "addq.ph %[temp11], %[temp11], %[temp4] \n\t" + "shra_r.ph %[temp10], %[temp10], 2 \n\t" + "shra_r.ph %[temp11], %[temp11], 2 \n\t" + "lbu %[temp0], 3(%[top]) \n\t" + "lbu %[temp1], 2(%[top]) \n\t" + "lbu %[temp2], 1(%[top]) \n\t" + "sll %[temp1], %[temp1], 1 \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "addu %[temp0], %[temp0], %[temp2] \n\t" + "precr.qb.ph %[temp9], %[temp10], %[temp9] \n\t" + "shra_r.w %[temp0], %[temp0], 2 \n\t" + "precr.qb.ph %[temp10], %[temp11], %[temp10] \n\t" + "usw %[temp9], 3*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp10], 1*" XSTR(BPS) "(%[dst]) \n\t" + "prepend %[temp9], %[temp11], 8 \n\t" + "prepend %[temp10], %[temp0], 8 \n\t" + "usw %[temp9], 2*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp10], 0*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void VR4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8, temp9; + __asm__ volatile ( + "ulw %[temp0], -4(%[top]) \n\t" + "ulw %[temp1], 0(%[top]) \n\t" + "preceu.ph.qbl %[temp2], %[temp0] \n\t" + "preceu.ph.qbr %[temp0], %[temp0] \n\t" + "preceu.ph.qbla %[temp3], %[temp1] \n\t" + "preceu.ph.qbra %[temp1], %[temp1] \n\t" + "packrl.ph %[temp7], %[temp3], %[temp2] \n\t" + "addqh_r.ph %[temp4], %[temp1], %[temp3] \n\t" + "move %[temp6], %[temp1] \n\t" + "append %[temp1], %[temp2], 16 \n\t" + "shll.ph %[temp9], %[temp6], 1 \n\t" + "addqh_r.ph %[temp5], %[temp7], %[temp6] \n\t" + "shll.ph %[temp8], %[temp7], 1 \n\t" + "addu.ph %[temp3], %[temp7], %[temp3] \n\t" + "addu.ph %[temp1], %[temp1], %[temp6] \n\t" + "packrl.ph %[temp7], %[temp2], %[temp0] \n\t" + "addu.ph %[temp6], %[temp0], %[temp2] \n\t" + "addu.ph %[temp3], %[temp3], %[temp9] \n\t" + "addu.ph %[temp1], %[temp1], %[temp8] \n\t" + "shll.ph %[temp7], %[temp7], 1 \n\t" + "shra_r.ph %[temp3], %[temp3], 2 \n\t" + "shra_r.ph %[temp1], %[temp1], 2 \n\t" + "addu.ph %[temp6], %[temp6], %[temp7] \n\t" + "shra_r.ph %[temp6], %[temp6], 2 \n\t" + "precrq.ph.w %[temp8], %[temp4], %[temp5] \n\t" + "append %[temp4], %[temp5], 16 \n\t" + "precrq.ph.w %[temp2], %[temp3], %[temp1] \n\t" + "append %[temp3], %[temp1], 16 \n\t" + "precr.qb.ph %[temp8], %[temp8], %[temp4] \n\t" + "precr.qb.ph %[temp3], %[temp2], %[temp3] \n\t" + "usw %[temp8], 0*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp3], 1*" XSTR(BPS) "(%[dst]) \n\t" + "append %[temp3], %[temp6], 8 \n\t" + "srl %[temp6], %[temp6], 16 \n\t" + "append %[temp8], %[temp6], 8 \n\t" + "usw %[temp3], 3*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp8], 2*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void LD4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1, temp2, temp3, temp4, temp5; + int temp6, temp7, temp8, temp9, temp10, temp11; + __asm__ volatile( + "ulw %[temp0], 0(%[top]) \n\t" + "ulw %[temp1], 4(%[top]) \n\t" + "preceu.ph.qbl %[temp2], %[temp0] \n\t" + "preceu.ph.qbr %[temp3], %[temp0] \n\t" + "preceu.ph.qbr %[temp4], %[temp1] \n\t" + "preceu.ph.qbl %[temp5], %[temp1] \n\t" + "packrl.ph %[temp6], %[temp2], %[temp3] \n\t" + "packrl.ph %[temp7], %[temp4], %[temp2] \n\t" + "packrl.ph %[temp8], %[temp5], %[temp4] \n\t" + "shll.ph %[temp6], %[temp6], 1 \n\t" + "addq.ph %[temp9], %[temp2], %[temp6] \n\t" + "shll.ph %[temp7], %[temp7], 1 \n\t" + "addq.ph %[temp9], %[temp9], %[temp3] \n\t" + "shll.ph %[temp8], %[temp8], 1 \n\t" + "shra_r.ph %[temp9], %[temp9], 2 \n\t" + "addq.ph %[temp10], %[temp4], %[temp7] \n\t" + "addq.ph %[temp11], %[temp5], %[temp8] \n\t" + "addq.ph %[temp10], %[temp10], %[temp2] \n\t" + "addq.ph %[temp11], %[temp11], %[temp4] \n\t" + "shra_r.ph %[temp10], %[temp10], 2 \n\t" + "shra_r.ph %[temp11], %[temp11], 2 \n\t" + "srl %[temp1], %[temp1], 24 \n\t" + "sll %[temp1], %[temp1], 1 \n\t" + "raddu.w.qb %[temp5], %[temp5] \n\t" + "precr.qb.ph %[temp9], %[temp10], %[temp9] \n\t" + "precr.qb.ph %[temp10], %[temp11], %[temp10] \n\t" + "addu %[temp1], %[temp1], %[temp5] \n\t" + "shra_r.w %[temp1], %[temp1], 2 \n\t" + "usw %[temp9], 0*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp10], 2*" XSTR(BPS) "(%[dst]) \n\t" + "prepend %[temp9], %[temp11], 8 \n\t" + "prepend %[temp10], %[temp1], 8 \n\t" + "usw %[temp9], 1*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp10], 3*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void VL4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8, temp9; + __asm__ volatile ( + "ulw %[temp0], 0(%[top]) \n\t" + "ulw %[temp1], 4(%[top]) \n\t" + "preceu.ph.qbla %[temp2], %[temp0] \n\t" + "preceu.ph.qbra %[temp0], %[temp0] \n\t" + "preceu.ph.qbl %[temp3], %[temp1] \n\t" + "preceu.ph.qbr %[temp1], %[temp1] \n\t" + "addqh_r.ph %[temp4], %[temp0], %[temp2] \n\t" + "packrl.ph %[temp7], %[temp1], %[temp0] \n\t" + "precrq.ph.w %[temp6], %[temp1], %[temp2] \n\t" + "shll.ph %[temp9], %[temp2], 1 \n\t" + "addqh_r.ph %[temp5], %[temp7], %[temp2] \n\t" + "shll.ph %[temp8], %[temp7], 1 \n\t" + "addu.ph %[temp2], %[temp2], %[temp6] \n\t" + "addu.ph %[temp0], %[temp0], %[temp7] \n\t" + "packrl.ph %[temp7], %[temp3], %[temp1] \n\t" + "addu.ph %[temp6], %[temp1], %[temp3] \n\t" + "addu.ph %[temp2], %[temp2], %[temp8] \n\t" + "addu.ph %[temp0], %[temp0], %[temp9] \n\t" + "shll.ph %[temp7], %[temp7], 1 \n\t" + "shra_r.ph %[temp2], %[temp2], 2 \n\t" + "shra_r.ph %[temp0], %[temp0], 2 \n\t" + "addu.ph %[temp6], %[temp6], %[temp7] \n\t" + "shra_r.ph %[temp6], %[temp6], 2 \n\t" + "precrq.ph.w %[temp8], %[temp5], %[temp4] \n\t" + "append %[temp5], %[temp4], 16 \n\t" + "precrq.ph.w %[temp3], %[temp2], %[temp0] \n\t" + "append %[temp2], %[temp0], 16 \n\t" + "precr.qb.ph %[temp8], %[temp8], %[temp5] \n\t" + "precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t" + "usw %[temp8], 0*" XSTR(BPS) "(%[dst]) \n\t" + "prepend %[temp8], %[temp6], 8 \n\t" + "usw %[temp3], 1*" XSTR(BPS) "(%[dst]) \n\t" + "srl %[temp6], %[temp6], 16 \n\t" + "prepend %[temp3], %[temp6], 8 \n\t" + "usw %[temp8], 2*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp3], 3*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void HD4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8, temp9; + __asm__ volatile ( + "ulw %[temp0], -5(%[top]) \n\t" + "ulw %[temp1], -1(%[top]) \n\t" + "preceu.ph.qbla %[temp2], %[temp0] \n\t" + "preceu.ph.qbra %[temp0], %[temp0] \n\t" + "preceu.ph.qbl %[temp3], %[temp1] \n\t" + "preceu.ph.qbr %[temp1], %[temp1] \n\t" + "addqh_r.ph %[temp4], %[temp0], %[temp2] \n\t" + "packrl.ph %[temp7], %[temp1], %[temp0] \n\t" + "precrq.ph.w %[temp6], %[temp1], %[temp2] \n\t" + "shll.ph %[temp9], %[temp2], 1 \n\t" + "addqh_r.ph %[temp5], %[temp7], %[temp2] \n\t" + "shll.ph %[temp8], %[temp7], 1 \n\t" + "addu.ph %[temp2], %[temp2], %[temp6] \n\t" + "addu.ph %[temp0], %[temp0], %[temp7] \n\t" + "packrl.ph %[temp7], %[temp3], %[temp1] \n\t" + "addu.ph %[temp6], %[temp1], %[temp3] \n\t" + "addu.ph %[temp2], %[temp2], %[temp8] \n\t" + "addu.ph %[temp0], %[temp0], %[temp9] \n\t" + "shll.ph %[temp7], %[temp7], 1 \n\t" + "shra_r.ph %[temp2], %[temp2], 2 \n\t" + "shra_r.ph %[temp0], %[temp0], 2 \n\t" + "addu.ph %[temp6], %[temp6], %[temp7] \n\t" + "shra_r.ph %[temp6], %[temp6], 2 \n\t" + "precrq.ph.w %[temp1], %[temp2], %[temp5] \n\t" + "precrq.ph.w %[temp3], %[temp0], %[temp4] \n\t" + "precr.qb.ph %[temp7], %[temp6], %[temp1] \n\t" + "precr.qb.ph %[temp6], %[temp1], %[temp3] \n\t" + "usw %[temp7], 0*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp6], 1*" XSTR(BPS) "(%[dst]) \n\t" + "append %[temp2], %[temp5], 16 \n\t" + "append %[temp0], %[temp4], 16 \n\t" + "precr.qb.ph %[temp5], %[temp3], %[temp2] \n\t" + "precr.qb.ph %[temp4], %[temp2], %[temp0] \n\t" + "usw %[temp5], 2*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp4], 3*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +static void HU4(uint8_t* dst, const uint8_t* top) { + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + __asm__ volatile ( + "ulw %[temp0], -5(%[top]) \n\t" + "preceu.ph.qbl %[temp1], %[temp0] \n\t" + "preceu.ph.qbr %[temp2], %[temp0] \n\t" + "packrl.ph %[temp3], %[temp1], %[temp2] \n\t" + "replv.qb %[temp7], %[temp2] \n\t" + "addqh_r.ph %[temp4], %[temp1], %[temp3] \n\t" + "addqh_r.ph %[temp5], %[temp3], %[temp2] \n\t" + "shll.ph %[temp6], %[temp3], 1 \n\t" + "addu.ph %[temp3], %[temp2], %[temp3] \n\t" + "addu.ph %[temp6], %[temp1], %[temp6] \n\t" + "shll.ph %[temp0], %[temp2], 1 \n\t" + "addu.ph %[temp6], %[temp6], %[temp2] \n\t" + "addu.ph %[temp0], %[temp3], %[temp0] \n\t" + "shra_r.ph %[temp6], %[temp6], 2 \n\t" + "shra_r.ph %[temp0], %[temp0], 2 \n\t" + "packrl.ph %[temp3], %[temp6], %[temp5] \n\t" + "precrq.ph.w %[temp2], %[temp6], %[temp4] \n\t" + "append %[temp0], %[temp5], 16 \n\t" + "precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t" + "usw %[temp3], 0*" XSTR(BPS) "(%[dst]) \n\t" + "precr.qb.ph %[temp1], %[temp7], %[temp0] \n\t" + "usw %[temp7], 3*" XSTR(BPS) "(%[dst]) \n\t" + "packrl.ph %[temp2], %[temp1], %[temp3] \n\t" + "usw %[temp1], 2*" XSTR(BPS) "(%[dst]) \n\t" + "usw %[temp2], 1*" XSTR(BPS) "(%[dst]) \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7) + : [top]"r"(top), [dst]"r"(dst) + : "memory" + ); +} + +//------------------------------------------------------------------------------ +// Chroma 8x8 prediction (paragraph 12.2) + +static void IntraChromaPreds_MIPSdspR2(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + // U block + DCMode8(C8DC8 + dst, left, top); + VerticalPred8(C8VE8 + dst, top); + HorizontalPred8(C8HE8 + dst, left); + TrueMotion8(C8TM8 + dst, left, top); + // V block + dst += 8; + if (top) top += 8; + if (left) left += 16; + DCMode8(C8DC8 + dst, left, top); + VerticalPred8(C8VE8 + dst, top); + HorizontalPred8(C8HE8 + dst, left); + TrueMotion8(C8TM8 + dst, left, top); +} + +//------------------------------------------------------------------------------ +// luma 16x16 prediction (paragraph 12.3) + +static void Intra16Preds_MIPSdspR2(uint8_t* dst, + const uint8_t* left, const uint8_t* top) { + DCMode16(I16DC16 + dst, left, top); + VerticalPred16(I16VE16 + dst, top); + HorizontalPred16(I16HE16 + dst, left); + TrueMotion16(I16TM16 + dst, left, top); +} + +// Left samples are top[-5 .. -2], top_left is top[-1], top are +// located at top[0..3], and top right is top[4..7] +static void Intra4Preds_MIPSdspR2(uint8_t* dst, const uint8_t* top) { + DC4(I4DC4 + dst, top); + TM4(I4TM4 + dst, top); + VE4(I4VE4 + dst, top); + HE4(I4HE4 + dst, top); + RD4(I4RD4 + dst, top); + VR4(I4VR4 + dst, top); + LD4(I4LD4 + dst, top); + VL4(I4VL4 + dst, top); + HD4(I4HD4 + dst, top); + HU4(I4HU4 + dst, top); +} + +//------------------------------------------------------------------------------ +// Metric + +#if !defined(WORK_AROUND_GCC) + +#define GET_SSE_INNER(A) \ + "lw %[temp0], " #A "(%[a]) \n\t" \ + "lw %[temp1], " #A "(%[b]) \n\t" \ + "preceu.ph.qbr %[temp2], %[temp0] \n\t" \ + "preceu.ph.qbl %[temp0], %[temp0] \n\t" \ + "preceu.ph.qbr %[temp3], %[temp1] \n\t" \ + "preceu.ph.qbl %[temp1], %[temp1] \n\t" \ + "subq.ph %[temp2], %[temp2], %[temp3] \n\t" \ + "subq.ph %[temp0], %[temp0], %[temp1] \n\t" \ + "dpa.w.ph $ac0, %[temp2], %[temp2] \n\t" \ + "dpa.w.ph $ac0, %[temp0], %[temp0] \n\t" + +#define GET_SSE(A, B, C, D) \ + GET_SSE_INNER(A) \ + GET_SSE_INNER(B) \ + GET_SSE_INNER(C) \ + GET_SSE_INNER(D) + +static int SSE16x16_MIPSdspR2(const uint8_t* a, const uint8_t* b) { + int count; + int temp0, temp1, temp2, temp3; + __asm__ volatile ( + "mult $zero, $zero \n\t" + GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS) + GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS) + GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS) + GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS) + GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS) + GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS) + GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS) + GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS) + GET_SSE( 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS) + GET_SSE( 9 * BPS, 4 + 9 * BPS, 8 + 9 * BPS, 12 + 9 * BPS) + GET_SSE(10 * BPS, 4 + 10 * BPS, 8 + 10 * BPS, 12 + 10 * BPS) + GET_SSE(11 * BPS, 4 + 11 * BPS, 8 + 11 * BPS, 12 + 11 * BPS) + GET_SSE(12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS) + GET_SSE(13 * BPS, 4 + 13 * BPS, 8 + 13 * BPS, 12 + 13 * BPS) + GET_SSE(14 * BPS, 4 + 14 * BPS, 8 + 14 * BPS, 12 + 14 * BPS) + GET_SSE(15 * BPS, 4 + 15 * BPS, 8 + 15 * BPS, 12 + 15 * BPS) + "mflo %[count] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [count]"=&r"(count) + : [a]"r"(a), [b]"r"(b) + : "memory", "hi", "lo" + ); + return count; +} + +static int SSE16x8_MIPSdspR2(const uint8_t* a, const uint8_t* b) { + int count; + int temp0, temp1, temp2, temp3; + __asm__ volatile ( + "mult $zero, $zero \n\t" + GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS) + GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS) + GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS) + GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS) + GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS) + GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS) + GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS) + GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS) + "mflo %[count] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [count]"=&r"(count) + : [a]"r"(a), [b]"r"(b) + : "memory", "hi", "lo" + ); + return count; +} + +static int SSE8x8_MIPSdspR2(const uint8_t* a, const uint8_t* b) { + int count; + int temp0, temp1, temp2, temp3; + __asm__ volatile ( + "mult $zero, $zero \n\t" + GET_SSE(0 * BPS, 4 + 0 * BPS, 1 * BPS, 4 + 1 * BPS) + GET_SSE(2 * BPS, 4 + 2 * BPS, 3 * BPS, 4 + 3 * BPS) + GET_SSE(4 * BPS, 4 + 4 * BPS, 5 * BPS, 4 + 5 * BPS) + GET_SSE(6 * BPS, 4 + 6 * BPS, 7 * BPS, 4 + 7 * BPS) + "mflo %[count] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [count]"=&r"(count) + : [a]"r"(a), [b]"r"(b) + : "memory", "hi", "lo" + ); + return count; +} + +static int SSE4x4_MIPSdspR2(const uint8_t* a, const uint8_t* b) { + int count; + int temp0, temp1, temp2, temp3; + __asm__ volatile ( + "mult $zero, $zero \n\t" + GET_SSE(0 * BPS, 1 * BPS, 2 * BPS, 3 * BPS) + "mflo %[count] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [count]"=&r"(count) + : [a]"r"(a), [b]"r"(b) + : "memory", "hi", "lo" + ); + return count; +} + +#undef GET_SSE +#undef GET_SSE_INNER + +#endif // !WORK_AROUND_GCC + +#undef FILL_8_OR_16 +#undef FILL_PART +#undef OUTPUT_EARLY_CLOBBER_REGS_17 +#undef MUL_HALF +#undef ABS_X8 +#undef ADD_SUB_HALVES_X4 + +//------------------------------------------------------------------------------ +// Quantization +// + +// macro for one pass through for loop in QuantizeBlock reading 2 values at time +// QUANTDIV macro inlined +// J - offset in bytes (kZigzag[n] * 2) +// K - offset in bytes (kZigzag[n] * 4) +// N - offset in bytes (n * 2) +// N1 - offset in bytes ((n + 1) * 2) +#define QUANTIZE_ONE(J, K, N, N1) \ + "ulw %[temp1], " #J "(%[ppin]) \n\t" \ + "ulw %[temp2], " #J "(%[ppsharpen]) \n\t" \ + "lhu %[temp3], " #K "(%[ppzthresh]) \n\t" \ + "lhu %[temp6], " #K "+4(%[ppzthresh]) \n\t" \ + "absq_s.ph %[temp4], %[temp1] \n\t" \ + "ins %[temp3], %[temp6], 16, 16 \n\t" \ + "addu.ph %[coeff], %[temp4], %[temp2] \n\t" \ + "shra.ph %[sign], %[temp1], 15 \n\t" \ + "li %[level], 0x10001 \n\t" \ + "cmp.lt.ph %[temp3], %[coeff] \n\t" \ + "lhu %[temp1], " #J "(%[ppiq]) \n\t" \ + "pick.ph %[temp5], %[level], $0 \n\t" \ + "lw %[temp2], " #K "(%[ppbias]) \n\t" \ + "beqz %[temp5], 0f \n\t" \ + "lhu %[temp3], " #J "(%[ppq]) \n\t" \ + "beq %[temp5], %[level], 1f \n\t" \ + "andi %[temp5], %[temp5], 0x1 \n\t" \ + "andi %[temp4], %[coeff], 0xffff \n\t" \ + "beqz %[temp5], 2f \n\t" \ + "mul %[level], %[temp4], %[temp1] \n\t" \ + "sh $0, " #J "+2(%[ppin]) \n\t" \ + "sh $0, " #N1 "(%[pout]) \n\t" \ + "addu %[level], %[level], %[temp2] \n\t" \ + "sra %[level], %[level], 17 \n\t" \ + "slt %[temp4], %[max_level], %[level] \n\t" \ + "movn %[level], %[max_level], %[temp4] \n\t" \ + "andi %[temp6], %[sign], 0xffff \n\t" \ + "xor %[level], %[level], %[temp6] \n\t" \ + "subu %[level], %[level], %[temp6] \n\t" \ + "mul %[temp5], %[level], %[temp3] \n\t" \ + "or %[ret], %[ret], %[level] \n\t" \ + "sh %[level], " #N "(%[pout]) \n\t" \ + "sh %[temp5], " #J "(%[ppin]) \n\t" \ + "j 3f \n\t" \ +"2: \n\t" \ + "lhu %[temp1], " #J "+2(%[ppiq]) \n\t" \ + "srl %[temp5], %[coeff], 16 \n\t" \ + "mul %[level], %[temp5], %[temp1] \n\t" \ + "lw %[temp2], " #K "+4(%[ppbias]) \n\t" \ + "lhu %[temp3], " #J "+2(%[ppq]) \n\t" \ + "addu %[level], %[level], %[temp2] \n\t" \ + "sra %[level], %[level], 17 \n\t" \ + "srl %[temp6], %[sign], 16 \n\t" \ + "slt %[temp4], %[max_level], %[level] \n\t" \ + "movn %[level], %[max_level], %[temp4] \n\t" \ + "xor %[level], %[level], %[temp6] \n\t" \ + "subu %[level], %[level], %[temp6] \n\t" \ + "mul %[temp5], %[level], %[temp3] \n\t" \ + "sh $0, " #J "(%[ppin]) \n\t" \ + "sh $0, " #N "(%[pout]) \n\t" \ + "or %[ret], %[ret], %[level] \n\t" \ + "sh %[temp5], " #J "+2(%[ppin]) \n\t" \ + "sh %[level], " #N1 "(%[pout]) \n\t" \ + "j 3f \n\t" \ +"1: \n\t" \ + "lhu %[temp1], " #J "(%[ppiq]) \n\t" \ + "lw %[temp2], " #K "(%[ppbias]) \n\t" \ + "ulw %[temp3], " #J "(%[ppq]) \n\t" \ + "andi %[temp5], %[coeff], 0xffff \n\t" \ + "srl %[temp0], %[coeff], 16 \n\t" \ + "lhu %[temp6], " #J "+2(%[ppiq]) \n\t" \ + "lw %[coeff], " #K "+4(%[ppbias]) \n\t" \ + "mul %[level], %[temp5], %[temp1] \n\t" \ + "mul %[temp4], %[temp0], %[temp6] \n\t" \ + "addu %[level], %[level], %[temp2] \n\t" \ + "addu %[temp4], %[temp4], %[coeff] \n\t" \ + "precrq.ph.w %[level], %[temp4], %[level] \n\t" \ + "shra.ph %[level], %[level], 1 \n\t" \ + "cmp.lt.ph %[max_level1],%[level] \n\t" \ + "pick.ph %[level], %[max_level], %[level] \n\t" \ + "xor %[level], %[level], %[sign] \n\t" \ + "subu.ph %[level], %[level], %[sign] \n\t" \ + "mul.ph %[temp3], %[level], %[temp3] \n\t" \ + "or %[ret], %[ret], %[level] \n\t" \ + "sh %[level], " #N "(%[pout]) \n\t" \ + "srl %[level], %[level], 16 \n\t" \ + "sh %[level], " #N1 "(%[pout]) \n\t" \ + "usw %[temp3], " #J "(%[ppin]) \n\t" \ + "j 3f \n\t" \ +"0: \n\t" \ + "sh $0, " #N "(%[pout]) \n\t" \ + "sh $0, " #N1 "(%[pout]) \n\t" \ + "usw $0, " #J "(%[ppin]) \n\t" \ +"3: \n\t" + +static int QuantizeBlock_MIPSdspR2(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + int temp0, temp1, temp2, temp3, temp4, temp5,temp6; + int sign, coeff, level; + int max_level = MAX_LEVEL; + int max_level1 = max_level << 16 | max_level; + int ret = 0; + + int16_t* ppin = &in[0]; + int16_t* pout = &out[0]; + const uint16_t* ppsharpen = &mtx->sharpen_[0]; + const uint32_t* ppzthresh = &mtx->zthresh_[0]; + const uint16_t* ppq = &mtx->q_[0]; + const uint16_t* ppiq = &mtx->iq_[0]; + const uint32_t* ppbias = &mtx->bias_[0]; + + __asm__ volatile ( + QUANTIZE_ONE( 0, 0, 0, 2) + QUANTIZE_ONE( 4, 8, 10, 12) + QUANTIZE_ONE( 8, 16, 4, 8) + QUANTIZE_ONE(12, 24, 14, 24) + QUANTIZE_ONE(16, 32, 6, 16) + QUANTIZE_ONE(20, 40, 22, 26) + QUANTIZE_ONE(24, 48, 18, 20) + QUANTIZE_ONE(28, 56, 28, 30) + + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [sign]"=&r"(sign), [coeff]"=&r"(coeff), + [level]"=&r"(level), [temp6]"=&r"(temp6), [ret]"+&r"(ret) + : [ppin]"r"(ppin), [pout]"r"(pout), [max_level1]"r"(max_level1), + [ppiq]"r"(ppiq), [max_level]"r"(max_level), + [ppbias]"r"(ppbias), [ppzthresh]"r"(ppzthresh), + [ppsharpen]"r"(ppsharpen), [ppq]"r"(ppq) + : "memory", "hi", "lo" + ); + + return (ret != 0); +} + +static int Quantize2Blocks_MIPSdspR2(int16_t in[32], int16_t out[32], + const VP8Matrix* const mtx) { + int nz; + nz = QuantizeBlock_MIPSdspR2(in + 0 * 16, out + 0 * 16, mtx) << 0; + nz |= QuantizeBlock_MIPSdspR2(in + 1 * 16, out + 1 * 16, mtx) << 1; + return nz; +} + +#undef QUANTIZE_ONE + +// macro for one horizontal pass in FTransformWHT +// temp0..temp7 holds tmp[0]..tmp[15] +// A, B, C, D - offset in bytes to load from in buffer +// TEMP0, TEMP1 - registers for corresponding tmp elements +#define HORIZONTAL_PASS_WHT(A, B, C, D, TEMP0, TEMP1) \ + "lh %[" #TEMP0 "], " #A "(%[in]) \n\t" \ + "lh %[" #TEMP1 "], " #B "(%[in]) \n\t" \ + "lh %[temp8], " #C "(%[in]) \n\t" \ + "lh %[temp9], " #D "(%[in]) \n\t" \ + "ins %[" #TEMP1 "], %[" #TEMP0 "], 16, 16 \n\t" \ + "ins %[temp9], %[temp8], 16, 16 \n\t" \ + "subq.ph %[temp8], %[" #TEMP1 "], %[temp9] \n\t" \ + "addq.ph %[temp9], %[" #TEMP1 "], %[temp9] \n\t" \ + "precrq.ph.w %[" #TEMP0 "], %[temp8], %[temp9] \n\t" \ + "append %[temp8], %[temp9], 16 \n\t" \ + "subq.ph %[" #TEMP1 "], %[" #TEMP0 "], %[temp8] \n\t" \ + "addq.ph %[" #TEMP0 "], %[" #TEMP0 "], %[temp8] \n\t" \ + "rotr %[" #TEMP1 "], %[" #TEMP1 "], 16 \n\t" + +// macro for one vertical pass in FTransformWHT +// temp0..temp7 holds tmp[0]..tmp[15] +// A, B, C, D - offsets in bytes to store to out buffer +// TEMP0, TEMP2, TEMP4 and TEMP6 - registers for corresponding tmp elements +#define VERTICAL_PASS_WHT(A, B, C, D, TEMP0, TEMP2, TEMP4, TEMP6) \ + "addq.ph %[temp8], %[" #TEMP0 "], %[" #TEMP4 "] \n\t" \ + "addq.ph %[temp9], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \ + "subq.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \ + "subq.ph %[" #TEMP6 "], %[" #TEMP0 "], %[" #TEMP4 "] \n\t" \ + "addqh.ph %[" #TEMP0 "], %[temp8], %[temp9] \n\t" \ + "subqh.ph %[" #TEMP4 "], %[" #TEMP6 "], %[" #TEMP2 "] \n\t" \ + "addqh.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \ + "subqh.ph %[" #TEMP6 "], %[temp8], %[temp9] \n\t" \ + "usw %[" #TEMP0 "], " #A "(%[out]) \n\t" \ + "usw %[" #TEMP2 "], " #B "(%[out]) \n\t" \ + "usw %[" #TEMP4 "], " #C "(%[out]) \n\t" \ + "usw %[" #TEMP6 "], " #D "(%[out]) \n\t" + +static void FTransformWHT_MIPSdspR2(const int16_t* in, int16_t* out) { + int temp0, temp1, temp2, temp3, temp4; + int temp5, temp6, temp7, temp8, temp9; + + __asm__ volatile ( + HORIZONTAL_PASS_WHT( 0, 32, 64, 96, temp0, temp1) + HORIZONTAL_PASS_WHT(128, 160, 192, 224, temp2, temp3) + HORIZONTAL_PASS_WHT(256, 288, 320, 352, temp4, temp5) + HORIZONTAL_PASS_WHT(384, 416, 448, 480, temp6, temp7) + VERTICAL_PASS_WHT(0, 8, 16, 24, temp0, temp2, temp4, temp6) + VERTICAL_PASS_WHT(4, 12, 20, 28, temp1, temp3, temp5, temp7) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), + [temp9]"=&r"(temp9) + : [in]"r"(in), [out]"r"(out) + : "memory" + ); +} + +#undef VERTICAL_PASS_WHT +#undef HORIZONTAL_PASS_WHT + +// macro for converting coefficients to bin +// convert 8 coeffs at time +// A, B, C, D - offsets in bytes to load from out buffer +#define CONVERT_COEFFS_TO_BIN(A, B, C, D) \ + "ulw %[temp0], " #A "(%[out]) \n\t" \ + "ulw %[temp1], " #B "(%[out]) \n\t" \ + "ulw %[temp2], " #C "(%[out]) \n\t" \ + "ulw %[temp3], " #D "(%[out]) \n\t" \ + "absq_s.ph %[temp0], %[temp0] \n\t" \ + "absq_s.ph %[temp1], %[temp1] \n\t" \ + "absq_s.ph %[temp2], %[temp2] \n\t" \ + "absq_s.ph %[temp3], %[temp3] \n\t" \ + "shra.ph %[temp0], %[temp0], 3 \n\t" \ + "shra.ph %[temp1], %[temp1], 3 \n\t" \ + "shra.ph %[temp2], %[temp2], 3 \n\t" \ + "shra.ph %[temp3], %[temp3], 3 \n\t" \ + "shll_s.ph %[temp0], %[temp0], 10 \n\t" \ + "shll_s.ph %[temp1], %[temp1], 10 \n\t" \ + "shll_s.ph %[temp2], %[temp2], 10 \n\t" \ + "shll_s.ph %[temp3], %[temp3], 10 \n\t" \ + "shrl.ph %[temp0], %[temp0], 10 \n\t" \ + "shrl.ph %[temp1], %[temp1], 10 \n\t" \ + "shrl.ph %[temp2], %[temp2], 10 \n\t" \ + "shrl.ph %[temp3], %[temp3], 10 \n\t" \ + "shll.ph %[temp0], %[temp0], 2 \n\t" \ + "shll.ph %[temp1], %[temp1], 2 \n\t" \ + "shll.ph %[temp2], %[temp2], 2 \n\t" \ + "shll.ph %[temp3], %[temp3], 2 \n\t" \ + "ext %[temp4], %[temp0], 0, 16 \n\t" \ + "ext %[temp0], %[temp0], 16, 16 \n\t" \ + "addu %[temp4], %[temp4], %[dist] \n\t" \ + "addu %[temp0], %[temp0], %[dist] \n\t" \ + "ext %[temp5], %[temp1], 0, 16 \n\t" \ + "lw %[temp8], 0(%[temp4]) \n\t" \ + "ext %[temp1], %[temp1], 16, 16 \n\t" \ + "addu %[temp5], %[temp5], %[dist] \n\t" \ + "addiu %[temp8], %[temp8], 1 \n\t" \ + "sw %[temp8], 0(%[temp4]) \n\t" \ + "lw %[temp8], 0(%[temp0]) \n\t" \ + "addu %[temp1], %[temp1], %[dist] \n\t" \ + "ext %[temp6], %[temp2], 0, 16 \n\t" \ + "addiu %[temp8], %[temp8], 1 \n\t" \ + "sw %[temp8], 0(%[temp0]) \n\t" \ + "lw %[temp8], 0(%[temp5]) \n\t" \ + "ext %[temp2], %[temp2], 16, 16 \n\t" \ + "addu %[temp6], %[temp6], %[dist] \n\t" \ + "addiu %[temp8], %[temp8], 1 \n\t" \ + "sw %[temp8], 0(%[temp5]) \n\t" \ + "lw %[temp8], 0(%[temp1]) \n\t" \ + "addu %[temp2], %[temp2], %[dist] \n\t" \ + "ext %[temp7], %[temp3], 0, 16 \n\t" \ + "addiu %[temp8], %[temp8], 1 \n\t" \ + "sw %[temp8], 0(%[temp1]) \n\t" \ + "lw %[temp8], 0(%[temp6]) \n\t" \ + "ext %[temp3], %[temp3], 16, 16 \n\t" \ + "addu %[temp7], %[temp7], %[dist] \n\t" \ + "addiu %[temp8], %[temp8], 1 \n\t" \ + "sw %[temp8], 0(%[temp6]) \n\t" \ + "lw %[temp8], 0(%[temp2]) \n\t" \ + "addu %[temp3], %[temp3], %[dist] \n\t" \ + "addiu %[temp8], %[temp8], 1 \n\t" \ + "sw %[temp8], 0(%[temp2]) \n\t" \ + "lw %[temp8], 0(%[temp7]) \n\t" \ + "addiu %[temp8], %[temp8], 1 \n\t" \ + "sw %[temp8], 0(%[temp7]) \n\t" \ + "lw %[temp8], 0(%[temp3]) \n\t" \ + "addiu %[temp8], %[temp8], 1 \n\t" \ + "sw %[temp8], 0(%[temp3]) \n\t" + +static void CollectHistogram_MIPSdspR2(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block, + VP8Histogram* const histo) { + int j; + int distribution[MAX_COEFF_THRESH + 1] = { 0 }; + const int max_coeff = (MAX_COEFF_THRESH << 16) + MAX_COEFF_THRESH; + for (j = start_block; j < end_block; ++j) { + int16_t out[16]; + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; + + VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + + // Convert coefficients to bin. + __asm__ volatile ( + CONVERT_COEFFS_TO_BIN( 0, 4, 8, 12) + CONVERT_COEFFS_TO_BIN(16, 20, 24, 28) + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8) + : [dist]"r"(distribution), [out]"r"(out), [max_coeff]"r"(max_coeff) + : "memory" + ); + } + VP8SetHistogramData(distribution, histo); +} + +#undef CONVERT_COEFFS_TO_BIN + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspInitMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMIPSdspR2(void) { + VP8FTransform = FTransform_MIPSdspR2; + VP8FTransformWHT = FTransformWHT_MIPSdspR2; + VP8ITransform = ITransform_MIPSdspR2; + + VP8TDisto4x4 = Disto4x4_MIPSdspR2; + VP8TDisto16x16 = Disto16x16_MIPSdspR2; + + VP8EncPredLuma16 = Intra16Preds_MIPSdspR2; + VP8EncPredChroma8 = IntraChromaPreds_MIPSdspR2; + VP8EncPredLuma4 = Intra4Preds_MIPSdspR2; + +#if !defined(WORK_AROUND_GCC) + VP8SSE16x16 = SSE16x16_MIPSdspR2; + VP8SSE8x8 = SSE8x8_MIPSdspR2; + VP8SSE16x8 = SSE16x8_MIPSdspR2; + VP8SSE4x4 = SSE4x4_MIPSdspR2; +#endif + + VP8EncQuantizeBlock = QuantizeBlock_MIPSdspR2; + VP8EncQuantize2Blocks = Quantize2Blocks_MIPSdspR2; + + VP8CollectHistogram = CollectHistogram_MIPSdspR2; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(VP8EncDspInitMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/enc_msa.c b/libraries/webp/src/dsp/enc_msa.c new file mode 100644 index 00000000000..6f85add4bbd --- /dev/null +++ b/libraries/webp/src/dsp/enc_msa.c @@ -0,0 +1,896 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MSA version of encoder dsp functions. +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MSA) + +#include +#include "src/dsp/msa_macro.h" +#include "src/enc/vp8i_enc.h" + +//------------------------------------------------------------------------------ +// Transforms + +#define IDCT_1D_W(in0, in1, in2, in3, out0, out1, out2, out3) do { \ + v4i32 a1_m, b1_m, c1_m, d1_m; \ + const v4i32 cospi8sqrt2minus1 = __msa_fill_w(20091); \ + const v4i32 sinpi8sqrt2 = __msa_fill_w(35468); \ + v4i32 c_tmp1_m = in1 * sinpi8sqrt2; \ + v4i32 c_tmp2_m = in3 * cospi8sqrt2minus1; \ + v4i32 d_tmp1_m = in1 * cospi8sqrt2minus1; \ + v4i32 d_tmp2_m = in3 * sinpi8sqrt2; \ + \ + ADDSUB2(in0, in2, a1_m, b1_m); \ + SRAI_W2_SW(c_tmp1_m, c_tmp2_m, 16); \ + c_tmp2_m = c_tmp2_m + in3; \ + c1_m = c_tmp1_m - c_tmp2_m; \ + SRAI_W2_SW(d_tmp1_m, d_tmp2_m, 16); \ + d_tmp1_m = d_tmp1_m + in1; \ + d1_m = d_tmp1_m + d_tmp2_m; \ + BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \ +} while (0) + +static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, + uint8_t* dst) { + v8i16 input0, input1; + v4i32 in0, in1, in2, in3, hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3; + v4i32 res0, res1, res2, res3; + v16i8 dest0, dest1, dest2, dest3; + const v16i8 zero = { 0 }; + + LD_SH2(in, 8, input0, input1); + UNPCK_SH_SW(input0, in0, in1); + UNPCK_SH_SW(input1, in2, in3); + IDCT_1D_W(in0, in1, in2, in3, hz0, hz1, hz2, hz3); + TRANSPOSE4x4_SW_SW(hz0, hz1, hz2, hz3, hz0, hz1, hz2, hz3); + IDCT_1D_W(hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3); + SRARI_W4_SW(vt0, vt1, vt2, vt3, 3); + TRANSPOSE4x4_SW_SW(vt0, vt1, vt2, vt3, vt0, vt1, vt2, vt3); + LD_SB4(ref, BPS, dest0, dest1, dest2, dest3); + ILVR_B4_SW(zero, dest0, zero, dest1, zero, dest2, zero, dest3, + res0, res1, res2, res3); + ILVR_H4_SW(zero, res0, zero, res1, zero, res2, zero, res3, + res0, res1, res2, res3); + ADD4(res0, vt0, res1, vt1, res2, vt2, res3, vt3, res0, res1, res2, res3); + CLIP_SW4_0_255(res0, res1, res2, res3); + PCKEV_B2_SW(res0, res1, res2, res3, vt0, vt1); + res0 = (v4i32)__msa_pckev_b((v16i8)vt0, (v16i8)vt1); + ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS); +} + +static void ITransform_MSA(const uint8_t* ref, const int16_t* in, uint8_t* dst, + int do_two) { + ITransformOne(ref, in, dst); + if (do_two) { + ITransformOne(ref + 4, in + 16, dst + 4); + } +} + +static void FTransform_MSA(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + uint64_t out0, out1, out2, out3; + uint32_t in0, in1, in2, in3; + v4i32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 t0, t1, t2, t3; + v16u8 srcl0, srcl1, src0 = { 0 }, src1 = { 0 }; + const v8i16 mask0 = { 0, 4, 8, 12, 1, 5, 9, 13 }; + const v8i16 mask1 = { 3, 7, 11, 15, 2, 6, 10, 14 }; + const v8i16 mask2 = { 4, 0, 5, 1, 6, 2, 7, 3 }; + const v8i16 mask3 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + const v8i16 cnst0 = { 2217, -5352, 2217, -5352, 2217, -5352, 2217, -5352 }; + const v8i16 cnst1 = { 5352, 2217, 5352, 2217, 5352, 2217, 5352, 2217 }; + + LW4(src, BPS, in0, in1, in2, in3); + INSERT_W4_UB(in0, in1, in2, in3, src0); + LW4(ref, BPS, in0, in1, in2, in3); + INSERT_W4_UB(in0, in1, in2, in3, src1); + ILVRL_B2_UB(src0, src1, srcl0, srcl1); + HSUB_UB2_SH(srcl0, srcl1, t0, t1); + VSHF_H2_SH(t0, t1, t0, t1, mask0, mask1, t2, t3); + ADDSUB2(t2, t3, t0, t1); + t0 = SRLI_H(t0, 3); + VSHF_H2_SH(t0, t0, t1, t1, mask2, mask3, t3, t2); + tmp0 = __msa_hadd_s_w(t3, t3); + tmp2 = __msa_hsub_s_w(t3, t3); + FILL_W2_SW(1812, 937, tmp1, tmp3); + DPADD_SH2_SW(t2, t2, cnst0, cnst1, tmp3, tmp1); + SRAI_W2_SW(tmp1, tmp3, 9); + PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, t0, t1); + VSHF_H2_SH(t0, t1, t0, t1, mask0, mask1, t2, t3); + ADDSUB2(t2, t3, t0, t1); + VSHF_H2_SH(t0, t0, t1, t1, mask2, mask3, t3, t2); + tmp0 = __msa_hadd_s_w(t3, t3); + tmp2 = __msa_hsub_s_w(t3, t3); + ADDVI_W2_SW(tmp0, 7, tmp2, 7, tmp0, tmp2); + SRAI_W2_SW(tmp0, tmp2, 4); + FILL_W2_SW(12000, 51000, tmp1, tmp3); + DPADD_SH2_SW(t2, t2, cnst0, cnst1, tmp3, tmp1); + SRAI_W2_SW(tmp1, tmp3, 16); + UNPCK_R_SH_SW(t1, tmp4); + tmp5 = __msa_ceqi_w(tmp4, 0); + tmp4 = (v4i32)__msa_nor_v((v16u8)tmp5, (v16u8)tmp5); + tmp5 = __msa_fill_w(1); + tmp5 = (v4i32)__msa_and_v((v16u8)tmp5, (v16u8)tmp4); + tmp1 += tmp5; + PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, t0, t1); + out0 = __msa_copy_s_d((v2i64)t0, 0); + out1 = __msa_copy_s_d((v2i64)t0, 1); + out2 = __msa_copy_s_d((v2i64)t1, 0); + out3 = __msa_copy_s_d((v2i64)t1, 1); + SD4(out0, out1, out2, out3, out, 8); +} + +static void FTransformWHT_MSA(const int16_t* in, int16_t* out) { + v8i16 in0 = { 0 }; + v8i16 in1 = { 0 }; + v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 out0, out1; + const v8i16 mask0 = { 0, 1, 2, 3, 8, 9, 10, 11 }; + const v8i16 mask1 = { 4, 5, 6, 7, 12, 13, 14, 15 }; + const v8i16 mask2 = { 0, 4, 8, 12, 1, 5, 9, 13 }; + const v8i16 mask3 = { 3, 7, 11, 15, 2, 6, 10, 14 }; + + in0 = __msa_insert_h(in0, 0, in[ 0]); + in0 = __msa_insert_h(in0, 1, in[ 64]); + in0 = __msa_insert_h(in0, 2, in[128]); + in0 = __msa_insert_h(in0, 3, in[192]); + in0 = __msa_insert_h(in0, 4, in[ 16]); + in0 = __msa_insert_h(in0, 5, in[ 80]); + in0 = __msa_insert_h(in0, 6, in[144]); + in0 = __msa_insert_h(in0, 7, in[208]); + in1 = __msa_insert_h(in1, 0, in[ 48]); + in1 = __msa_insert_h(in1, 1, in[112]); + in1 = __msa_insert_h(in1, 2, in[176]); + in1 = __msa_insert_h(in1, 3, in[240]); + in1 = __msa_insert_h(in1, 4, in[ 32]); + in1 = __msa_insert_h(in1, 5, in[ 96]); + in1 = __msa_insert_h(in1, 6, in[160]); + in1 = __msa_insert_h(in1, 7, in[224]); + ADDSUB2(in0, in1, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + ADDSUB2(tmp2, tmp3, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); + ADDSUB2(in0, in1, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + ADDSUB2(tmp2, tmp3, out0, out1); + SRAI_H2_SH(out0, out1, 1); + ST_SH2(out0, out1, out, 8); +} + +static int TTransform_MSA(const uint8_t* in, const uint16_t* w) { + int sum; + uint32_t in0_m, in1_m, in2_m, in3_m; + v16i8 src0 = { 0 }; + v8i16 in0, in1, tmp0, tmp1, tmp2, tmp3; + v4i32 dst0, dst1; + const v16i8 zero = { 0 }; + const v8i16 mask0 = { 0, 1, 2, 3, 8, 9, 10, 11 }; + const v8i16 mask1 = { 4, 5, 6, 7, 12, 13, 14, 15 }; + const v8i16 mask2 = { 0, 4, 8, 12, 1, 5, 9, 13 }; + const v8i16 mask3 = { 3, 7, 11, 15, 2, 6, 10, 14 }; + + LW4(in, BPS, in0_m, in1_m, in2_m, in3_m); + INSERT_W4_SB(in0_m, in1_m, in2_m, in3_m, src0); + ILVRL_B2_SH(zero, src0, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); + ADDSUB2(in0, in1, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + ADDSUB2(tmp2, tmp3, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); + ADDSUB2(in0, in1, tmp0, tmp1); + VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); + ADDSUB2(tmp2, tmp3, tmp0, tmp1); + tmp0 = __msa_add_a_h(tmp0, (v8i16)zero); + tmp1 = __msa_add_a_h(tmp1, (v8i16)zero); + LD_SH2(w, 8, tmp2, tmp3); + DOTP_SH2_SW(tmp0, tmp1, tmp2, tmp3, dst0, dst1); + dst0 = dst0 + dst1; + sum = HADD_SW_S32(dst0); + return sum; +} + +static int Disto4x4_MSA(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + const int sum1 = TTransform_MSA(a, w); + const int sum2 = TTransform_MSA(b, w); + return abs(sum2 - sum1) >> 5; +} + +static int Disto16x16_MSA(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4_MSA(a + x + y, b + x + y, w); + } + } + return D; +} + +//------------------------------------------------------------------------------ +// Histogram + +static void CollectHistogram_MSA(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block, + VP8Histogram* const histo) { + int j; + int distribution[MAX_COEFF_THRESH + 1] = { 0 }; + for (j = start_block; j < end_block; ++j) { + int16_t out[16]; + VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + { + int k; + v8i16 coeff0, coeff1; + const v8i16 zero = { 0 }; + const v8i16 max_coeff_thr = __msa_ldi_h(MAX_COEFF_THRESH); + LD_SH2(&out[0], 8, coeff0, coeff1); + coeff0 = __msa_add_a_h(coeff0, zero); + coeff1 = __msa_add_a_h(coeff1, zero); + SRAI_H2_SH(coeff0, coeff1, 3); + coeff0 = __msa_min_s_h(coeff0, max_coeff_thr); + coeff1 = __msa_min_s_h(coeff1, max_coeff_thr); + ST_SH2(coeff0, coeff1, &out[0], 8); + for (k = 0; k < 16; ++k) { + ++distribution[out[k]]; + } + } + } + VP8SetHistogramData(distribution, histo); +} + +//------------------------------------------------------------------------------ +// Intra predictions + +// luma 4x4 prediction + +#define DST(x, y) dst[(x) + (y) * BPS] +#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) +#define AVG2(a, b) (((a) + (b) + 1) >> 1) + +static WEBP_INLINE void VE4(uint8_t* dst, const uint8_t* top) { // vertical + const v16u8 A1 = { 0 }; + const uint64_t val_m = LD(top - 1); + const v16u8 A = (v16u8)__msa_insert_d((v2i64)A1, 0, val_m); + const v16u8 B = SLDI_UB(A, A, 1); + const v16u8 C = SLDI_UB(A, A, 2); + const v16u8 AC = __msa_ave_u_b(A, C); + const v16u8 B2 = __msa_ave_u_b(B, B); + const v16u8 R = __msa_aver_u_b(AC, B2); + const uint32_t out = __msa_copy_s_w((v4i32)R, 0); + SW4(out, out, out, out, dst, BPS); +} + +static WEBP_INLINE void HE4(uint8_t* dst, const uint8_t* top) { // horizontal + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + WebPUint32ToMem(dst + 0 * BPS, 0x01010101U * AVG3(X, I, J)); + WebPUint32ToMem(dst + 1 * BPS, 0x01010101U * AVG3(I, J, K)); + WebPUint32ToMem(dst + 2 * BPS, 0x01010101U * AVG3(J, K, L)); + WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(K, L, L)); +} + +static WEBP_INLINE void DC4(uint8_t* dst, const uint8_t* top) { + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i]; + dc >>= 3; + dc = dc | (dc << 8) | (dc << 16) | (dc << 24); + SW4(dc, dc, dc, dc, dst, BPS); +} + +static WEBP_INLINE void RD4(uint8_t* dst, const uint8_t* top) { + const v16u8 A2 = { 0 }; + const uint64_t val_m = LD(top - 5); + const v16u8 A1 = (v16u8)__msa_insert_d((v2i64)A2, 0, val_m); + const v16u8 A = (v16u8)__msa_insert_b((v16i8)A1, 8, top[3]); + const v16u8 B = SLDI_UB(A, A, 1); + const v16u8 C = SLDI_UB(A, A, 2); + const v16u8 AC = __msa_ave_u_b(A, C); + const v16u8 B2 = __msa_ave_u_b(B, B); + const v16u8 R0 = __msa_aver_u_b(AC, B2); + const v16u8 R1 = SLDI_UB(R0, R0, 1); + const v16u8 R2 = SLDI_UB(R1, R1, 1); + const v16u8 R3 = SLDI_UB(R2, R2, 1); + const uint32_t val0 = __msa_copy_s_w((v4i32)R0, 0); + const uint32_t val1 = __msa_copy_s_w((v4i32)R1, 0); + const uint32_t val2 = __msa_copy_s_w((v4i32)R2, 0); + const uint32_t val3 = __msa_copy_s_w((v4i32)R3, 0); + SW4(val3, val2, val1, val0, dst, BPS); +} + +static WEBP_INLINE void LD4(uint8_t* dst, const uint8_t* top) { + const v16u8 A1 = { 0 }; + const uint64_t val_m = LD(top); + const v16u8 A = (v16u8)__msa_insert_d((v2i64)A1, 0, val_m); + const v16u8 B = SLDI_UB(A, A, 1); + const v16u8 C1 = SLDI_UB(A, A, 2); + const v16u8 C = (v16u8)__msa_insert_b((v16i8)C1, 6, top[7]); + const v16u8 AC = __msa_ave_u_b(A, C); + const v16u8 B2 = __msa_ave_u_b(B, B); + const v16u8 R0 = __msa_aver_u_b(AC, B2); + const v16u8 R1 = SLDI_UB(R0, R0, 1); + const v16u8 R2 = SLDI_UB(R1, R1, 1); + const v16u8 R3 = SLDI_UB(R2, R2, 1); + const uint32_t val0 = __msa_copy_s_w((v4i32)R0, 0); + const uint32_t val1 = __msa_copy_s_w((v4i32)R1, 0); + const uint32_t val2 = __msa_copy_s_w((v4i32)R2, 0); + const uint32_t val3 = __msa_copy_s_w((v4i32)R3, 0); + SW4(val0, val1, val2, val3, dst, BPS); +} + +static WEBP_INLINE void VR4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + DST(0, 0) = DST(1, 2) = AVG2(X, A); + DST(1, 0) = DST(2, 2) = AVG2(A, B); + DST(2, 0) = DST(3, 2) = AVG2(B, C); + DST(3, 0) = AVG2(C, D); + DST(0, 3) = AVG3(K, J, I); + DST(0, 2) = AVG3(J, I, X); + DST(0, 1) = DST(1, 3) = AVG3(I, X, A); + DST(1, 1) = DST(2, 3) = AVG3(X, A, B); + DST(2, 1) = DST(3, 3) = AVG3(A, B, C); + DST(3, 1) = AVG3(B, C, D); +} + +static WEBP_INLINE void VL4(uint8_t* dst, const uint8_t* top) { + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + const int E = top[4]; + const int F = top[5]; + const int G = top[6]; + const int H = top[7]; + DST(0, 0) = AVG2(A, B); + DST(1, 0) = DST(0, 2) = AVG2(B, C); + DST(2, 0) = DST(1, 2) = AVG2(C, D); + DST(3, 0) = DST(2, 2) = AVG2(D, E); + DST(0, 1) = AVG3(A, B, C); + DST(1, 1) = DST(0, 3) = AVG3(B, C, D); + DST(2, 1) = DST(1, 3) = AVG3(C, D, E); + DST(3, 1) = DST(2, 3) = AVG3(D, E, F); + DST(3, 2) = AVG3(E, F, G); + DST(3, 3) = AVG3(F, G, H); +} + +static WEBP_INLINE void HU4(uint8_t* dst, const uint8_t* top) { + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + DST(0, 0) = AVG2(I, J); + DST(2, 0) = DST(0, 1) = AVG2(J, K); + DST(2, 1) = DST(0, 2) = AVG2(K, L); + DST(1, 0) = AVG3(I, J, K); + DST(3, 0) = DST(1, 1) = AVG3(J, K, L); + DST(3, 1) = DST(1, 2) = AVG3(K, L, L); + DST(3, 2) = DST(2, 2) = + DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; +} + +static WEBP_INLINE void HD4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + DST(0, 0) = DST(2, 1) = AVG2(I, X); + DST(0, 1) = DST(2, 2) = AVG2(J, I); + DST(0, 2) = DST(2, 3) = AVG2(K, J); + DST(0, 3) = AVG2(L, K); + DST(3, 0) = AVG3(A, B, C); + DST(2, 0) = AVG3(X, A, B); + DST(1, 0) = DST(3, 1) = AVG3(I, X, A); + DST(1, 1) = DST(3, 2) = AVG3(J, I, X); + DST(1, 2) = DST(3, 3) = AVG3(K, J, I); + DST(1, 3) = AVG3(L, K, J); +} + +static WEBP_INLINE void TM4(uint8_t* dst, const uint8_t* top) { + const v16i8 zero = { 0 }; + const v8i16 TL = (v8i16)__msa_fill_h(top[-1]); + const v8i16 L0 = (v8i16)__msa_fill_h(top[-2]); + const v8i16 L1 = (v8i16)__msa_fill_h(top[-3]); + const v8i16 L2 = (v8i16)__msa_fill_h(top[-4]); + const v8i16 L3 = (v8i16)__msa_fill_h(top[-5]); + const v16u8 T1 = LD_UB(top); + const v8i16 T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1); + const v8i16 d = T - TL; + v8i16 r0, r1, r2, r3; + ADD4(d, L0, d, L1, d, L2, d, L3, r0, r1, r2, r3); + CLIP_SH4_0_255(r0, r1, r2, r3); + PCKEV_ST4x4_UB(r0, r1, r2, r3, dst, BPS); +} + +#undef DST +#undef AVG3 +#undef AVG2 + +static void Intra4Preds_MSA(uint8_t* dst, const uint8_t* top) { + DC4(I4DC4 + dst, top); + TM4(I4TM4 + dst, top); + VE4(I4VE4 + dst, top); + HE4(I4HE4 + dst, top); + RD4(I4RD4 + dst, top); + VR4(I4VR4 + dst, top); + LD4(I4LD4 + dst, top); + VL4(I4VL4 + dst, top); + HD4(I4HD4 + dst, top); + HU4(I4HU4 + dst, top); +} + +// luma 16x16 prediction + +#define STORE16x16(out, dst) do { \ + ST_UB8(out, out, out, out, out, out, out, out, dst + 0 * BPS, BPS); \ + ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); \ +} while (0) + +static WEBP_INLINE void VerticalPred16x16(uint8_t* dst, const uint8_t* top) { + if (top != NULL) { + const v16u8 out = LD_UB(top); + STORE16x16(out, dst); + } else { + const v16u8 out = (v16u8)__msa_fill_b(0x7f); + STORE16x16(out, dst); + } +} + +static WEBP_INLINE void HorizontalPred16x16(uint8_t* dst, + const uint8_t* left) { + if (left != NULL) { + int j; + for (j = 0; j < 16; j += 4) { + const v16u8 L0 = (v16u8)__msa_fill_b(left[0]); + const v16u8 L1 = (v16u8)__msa_fill_b(left[1]); + const v16u8 L2 = (v16u8)__msa_fill_b(left[2]); + const v16u8 L3 = (v16u8)__msa_fill_b(left[3]); + ST_UB4(L0, L1, L2, L3, dst, BPS); + dst += 4 * BPS; + left += 4; + } + } else { + const v16u8 out = (v16u8)__msa_fill_b(0x81); + STORE16x16(out, dst); + } +} + +static WEBP_INLINE void TrueMotion16x16(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + if (left != NULL) { + if (top != NULL) { + int j; + v8i16 d1, d2; + const v16i8 zero = { 0 }; + const v8i16 TL = (v8i16)__msa_fill_h(left[-1]); + const v16u8 T = LD_UB(top); + ILVRL_B2_SH(zero, T, d1, d2); + SUB2(d1, TL, d2, TL, d1, d2); + for (j = 0; j < 16; j += 4) { + v16i8 t0, t1, t2, t3; + v8i16 r0, r1, r2, r3, r4, r5, r6, r7; + const v8i16 L0 = (v8i16)__msa_fill_h(left[j + 0]); + const v8i16 L1 = (v8i16)__msa_fill_h(left[j + 1]); + const v8i16 L2 = (v8i16)__msa_fill_h(left[j + 2]); + const v8i16 L3 = (v8i16)__msa_fill_h(left[j + 3]); + ADD4(d1, L0, d1, L1, d1, L2, d1, L3, r0, r1, r2, r3); + ADD4(d2, L0, d2, L1, d2, L2, d2, L3, r4, r5, r6, r7); + CLIP_SH4_0_255(r0, r1, r2, r3); + CLIP_SH4_0_255(r4, r5, r6, r7); + PCKEV_B4_SB(r4, r0, r5, r1, r6, r2, r7, r3, t0, t1, t2, t3); + ST_SB4(t0, t1, t2, t3, dst, BPS); + dst += 4 * BPS; + } + } else { + HorizontalPred16x16(dst, left); + } + } else { + if (top != NULL) { + VerticalPred16x16(dst, top); + } else { + const v16u8 out = (v16u8)__msa_fill_b(0x81); + STORE16x16(out, dst); + } + } +} + +static WEBP_INLINE void DCMode16x16(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + int DC; + v16u8 out; + if (top != NULL && left != NULL) { + const v16u8 rtop = LD_UB(top); + const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); + const v16u8 rleft = LD_UB(left); + const v8u16 dcleft = __msa_hadd_u_h(rleft, rleft); + const v8u16 dctemp = dctop + dcleft; + DC = HADD_UH_U32(dctemp); + DC = (DC + 16) >> 5; + } else if (left != NULL) { // left but no top + const v16u8 rleft = LD_UB(left); + const v8u16 dcleft = __msa_hadd_u_h(rleft, rleft); + DC = HADD_UH_U32(dcleft); + DC = (DC + DC + 16) >> 5; + } else if (top != NULL) { // top but no left + const v16u8 rtop = LD_UB(top); + const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); + DC = HADD_UH_U32(dctop); + DC = (DC + DC + 16) >> 5; + } else { // no top, no left, nothing. + DC = 0x80; + } + out = (v16u8)__msa_fill_b(DC); + STORE16x16(out, dst); +} + +static void Intra16Preds_MSA(uint8_t* dst, + const uint8_t* left, const uint8_t* top) { + DCMode16x16(I16DC16 + dst, left, top); + VerticalPred16x16(I16VE16 + dst, top); + HorizontalPred16x16(I16HE16 + dst, left); + TrueMotion16x16(I16TM16 + dst, left, top); +} + +// Chroma 8x8 prediction + +#define CALC_DC8(in, out) do { \ + const v8u16 temp0 = __msa_hadd_u_h(in, in); \ + const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0); \ + const v2i64 temp2 = (v2i64)__msa_hadd_u_d(temp1, temp1); \ + const v2i64 temp3 = __msa_splati_d(temp2, 1); \ + const v2i64 temp4 = temp3 + temp2; \ + const v16i8 temp5 = (v16i8)__msa_srari_d(temp4, 4); \ + const v2i64 temp6 = (v2i64)__msa_splati_b(temp5, 0); \ + out = __msa_copy_s_d(temp6, 0); \ +} while (0) + +#define STORE8x8(out, dst) do { \ + SD4(out, out, out, out, dst + 0 * BPS, BPS); \ + SD4(out, out, out, out, dst + 4 * BPS, BPS); \ +} while (0) + +static WEBP_INLINE void VerticalPred8x8(uint8_t* dst, const uint8_t* top) { + if (top != NULL) { + const uint64_t out = LD(top); + STORE8x8(out, dst); + } else { + const uint64_t out = 0x7f7f7f7f7f7f7f7fULL; + STORE8x8(out, dst); + } +} + +static WEBP_INLINE void HorizontalPred8x8(uint8_t* dst, const uint8_t* left) { + if (left != NULL) { + int j; + for (j = 0; j < 8; j += 4) { + const v16u8 L0 = (v16u8)__msa_fill_b(left[0]); + const v16u8 L1 = (v16u8)__msa_fill_b(left[1]); + const v16u8 L2 = (v16u8)__msa_fill_b(left[2]); + const v16u8 L3 = (v16u8)__msa_fill_b(left[3]); + const uint64_t out0 = __msa_copy_s_d((v2i64)L0, 0); + const uint64_t out1 = __msa_copy_s_d((v2i64)L1, 0); + const uint64_t out2 = __msa_copy_s_d((v2i64)L2, 0); + const uint64_t out3 = __msa_copy_s_d((v2i64)L3, 0); + SD4(out0, out1, out2, out3, dst, BPS); + dst += 4 * BPS; + left += 4; + } + } else { + const uint64_t out = 0x8181818181818181ULL; + STORE8x8(out, dst); + } +} + +static WEBP_INLINE void TrueMotion8x8(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + if (left != NULL) { + if (top != NULL) { + int j; + const v8i16 TL = (v8i16)__msa_fill_h(left[-1]); + const v16u8 T1 = LD_UB(top); + const v16i8 zero = { 0 }; + const v8i16 T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1); + const v8i16 d = T - TL; + for (j = 0; j < 8; j += 4) { + uint64_t out0, out1, out2, out3; + v16i8 t0, t1; + v8i16 r0 = (v8i16)__msa_fill_h(left[j + 0]); + v8i16 r1 = (v8i16)__msa_fill_h(left[j + 1]); + v8i16 r2 = (v8i16)__msa_fill_h(left[j + 2]); + v8i16 r3 = (v8i16)__msa_fill_h(left[j + 3]); + ADD4(d, r0, d, r1, d, r2, d, r3, r0, r1, r2, r3); + CLIP_SH4_0_255(r0, r1, r2, r3); + PCKEV_B2_SB(r1, r0, r3, r2, t0, t1); + out0 = __msa_copy_s_d((v2i64)t0, 0); + out1 = __msa_copy_s_d((v2i64)t0, 1); + out2 = __msa_copy_s_d((v2i64)t1, 0); + out3 = __msa_copy_s_d((v2i64)t1, 1); + SD4(out0, out1, out2, out3, dst, BPS); + dst += 4 * BPS; + } + } else { + HorizontalPred8x8(dst, left); + } + } else { + if (top != NULL) { + VerticalPred8x8(dst, top); + } else { + const uint64_t out = 0x8181818181818181ULL; + STORE8x8(out, dst); + } + } +} + +static WEBP_INLINE void DCMode8x8(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + uint64_t out; + v16u8 src = { 0 }; + if (top != NULL && left != NULL) { + const uint64_t left_m = LD(left); + const uint64_t top_m = LD(top); + INSERT_D2_UB(left_m, top_m, src); + CALC_DC8(src, out); + } else if (left != NULL) { // left but no top + const uint64_t left_m = LD(left); + INSERT_D2_UB(left_m, left_m, src); + CALC_DC8(src, out); + } else if (top != NULL) { // top but no left + const uint64_t top_m = LD(top); + INSERT_D2_UB(top_m, top_m, src); + CALC_DC8(src, out); + } else { // no top, no left, nothing. + src = (v16u8)__msa_fill_b(0x80); + out = __msa_copy_s_d((v2i64)src, 0); + } + STORE8x8(out, dst); +} + +static void IntraChromaPreds_MSA(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + // U block + DCMode8x8(C8DC8 + dst, left, top); + VerticalPred8x8(C8VE8 + dst, top); + HorizontalPred8x8(C8HE8 + dst, left); + TrueMotion8x8(C8TM8 + dst, left, top); + // V block + dst += 8; + if (top != NULL) top += 8; + if (left != NULL) left += 16; + DCMode8x8(C8DC8 + dst, left, top); + VerticalPred8x8(C8VE8 + dst, top); + HorizontalPred8x8(C8HE8 + dst, left); + TrueMotion8x8(C8TM8 + dst, left, top); +} + +//------------------------------------------------------------------------------ +// Metric + +#define PACK_DOTP_UB4_SW(in0, in1, in2, in3, out0, out1, out2, out3) do { \ + v16u8 tmp0, tmp1; \ + v8i16 tmp2, tmp3; \ + ILVRL_B2_UB(in0, in1, tmp0, tmp1); \ + HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ + DOTP_SH2_SW(tmp2, tmp3, tmp2, tmp3, out0, out1); \ + ILVRL_B2_UB(in2, in3, tmp0, tmp1); \ + HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ + DOTP_SH2_SW(tmp2, tmp3, tmp2, tmp3, out2, out3); \ +} while (0) + +#define PACK_DPADD_UB4_SW(in0, in1, in2, in3, out0, out1, out2, out3) do { \ + v16u8 tmp0, tmp1; \ + v8i16 tmp2, tmp3; \ + ILVRL_B2_UB(in0, in1, tmp0, tmp1); \ + HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ + DPADD_SH2_SW(tmp2, tmp3, tmp2, tmp3, out0, out1); \ + ILVRL_B2_UB(in2, in3, tmp0, tmp1); \ + HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ + DPADD_SH2_SW(tmp2, tmp3, tmp2, tmp3, out2, out3); \ +} while (0) + +static int SSE16x16_MSA(const uint8_t* a, const uint8_t* b) { + uint32_t sum; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; + v4i32 out0, out1, out2, out3; + + LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); + PACK_DOTP_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); + a += 8 * BPS; + b += 8 * BPS; + LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); + PACK_DPADD_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); + out0 += out1; + out2 += out3; + out0 += out2; + sum = HADD_SW_S32(out0); + return sum; +} + +static int SSE16x8_MSA(const uint8_t* a, const uint8_t* b) { + uint32_t sum; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; + v4i32 out0, out1, out2, out3; + + LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); + PACK_DOTP_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); + PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); + out0 += out1; + out2 += out3; + out0 += out2; + sum = HADD_SW_S32(out0); + return sum; +} + +static int SSE8x8_MSA(const uint8_t* a, const uint8_t* b) { + uint32_t sum; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; + v16u8 t0, t1, t2, t3; + v4i32 out0, out1, out2, out3; + + LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); + ILVR_B4_UB(src0, src1, src2, src3, ref0, ref1, ref2, ref3, t0, t1, t2, t3); + PACK_DOTP_UB4_SW(t0, t2, t1, t3, out0, out1, out2, out3); + ILVR_B4_UB(src4, src5, src6, src7, ref4, ref5, ref6, ref7, t0, t1, t2, t3); + PACK_DPADD_UB4_SW(t0, t2, t1, t3, out0, out1, out2, out3); + out0 += out1; + out2 += out3; + out0 += out2; + sum = HADD_SW_S32(out0); + return sum; +} + +static int SSE4x4_MSA(const uint8_t* a, const uint8_t* b) { + uint32_t sum = 0; + uint32_t src0, src1, src2, src3, ref0, ref1, ref2, ref3; + v16u8 src = { 0 }, ref = { 0 }, tmp0, tmp1; + v8i16 diff0, diff1; + v4i32 out0, out1; + + LW4(a, BPS, src0, src1, src2, src3); + LW4(b, BPS, ref0, ref1, ref2, ref3); + INSERT_W4_UB(src0, src1, src2, src3, src); + INSERT_W4_UB(ref0, ref1, ref2, ref3, ref); + ILVRL_B2_UB(src, ref, tmp0, tmp1); + HSUB_UB2_SH(tmp0, tmp1, diff0, diff1); + DOTP_SH2_SW(diff0, diff1, diff0, diff1, out0, out1); + out0 += out1; + sum = HADD_SW_S32(out0); + return sum; +} + +//------------------------------------------------------------------------------ +// Quantization + +static int QuantizeBlock_MSA(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + int sum; + v8i16 in0, in1, sh0, sh1, out0, out1; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, sign0, sign1; + v4i32 s0, s1, s2, s3, b0, b1, b2, b3, t0, t1, t2, t3; + const v8i16 zero = { 0 }; + const v8i16 zigzag0 = { 0, 1, 4, 8, 5, 2, 3, 6 }; + const v8i16 zigzag1 = { 9, 12, 13, 10, 7, 11, 14, 15 }; + const v8i16 maxlevel = __msa_fill_h(MAX_LEVEL); + + LD_SH2(&in[0], 8, in0, in1); + LD_SH2(&mtx->sharpen_[0], 8, sh0, sh1); + tmp4 = __msa_add_a_h(in0, zero); + tmp5 = __msa_add_a_h(in1, zero); + ILVRL_H2_SH(sh0, tmp4, tmp0, tmp1); + ILVRL_H2_SH(sh1, tmp5, tmp2, tmp3); + HADD_SH4_SW(tmp0, tmp1, tmp2, tmp3, s0, s1, s2, s3); + sign0 = (in0 < zero); + sign1 = (in1 < zero); // sign + LD_SH2(&mtx->iq_[0], 8, tmp0, tmp1); // iq + ILVRL_H2_SW(zero, tmp0, t0, t1); + ILVRL_H2_SW(zero, tmp1, t2, t3); + LD_SW4(&mtx->bias_[0], 4, b0, b1, b2, b3); // bias + MUL4(t0, s0, t1, s1, t2, s2, t3, s3, t0, t1, t2, t3); + ADD4(b0, t0, b1, t1, b2, t2, b3, t3, b0, b1, b2, b3); + SRAI_W4_SW(b0, b1, b2, b3, 17); + PCKEV_H2_SH(b1, b0, b3, b2, tmp2, tmp3); + tmp0 = (tmp2 > maxlevel); + tmp1 = (tmp3 > maxlevel); + tmp2 = (v8i16)__msa_bmnz_v((v16u8)tmp2, (v16u8)maxlevel, (v16u8)tmp0); + tmp3 = (v8i16)__msa_bmnz_v((v16u8)tmp3, (v16u8)maxlevel, (v16u8)tmp1); + SUB2(zero, tmp2, zero, tmp3, tmp0, tmp1); + tmp2 = (v8i16)__msa_bmnz_v((v16u8)tmp2, (v16u8)tmp0, (v16u8)sign0); + tmp3 = (v8i16)__msa_bmnz_v((v16u8)tmp3, (v16u8)tmp1, (v16u8)sign1); + LD_SW4(&mtx->zthresh_[0], 4, t0, t1, t2, t3); // zthresh + t0 = (s0 > t0); + t1 = (s1 > t1); + t2 = (s2 > t2); + t3 = (s3 > t3); + PCKEV_H2_SH(t1, t0, t3, t2, tmp0, tmp1); + tmp4 = (v8i16)__msa_bmnz_v((v16u8)zero, (v16u8)tmp2, (v16u8)tmp0); + tmp5 = (v8i16)__msa_bmnz_v((v16u8)zero, (v16u8)tmp3, (v16u8)tmp1); + LD_SH2(&mtx->q_[0], 8, tmp0, tmp1); + MUL2(tmp4, tmp0, tmp5, tmp1, in0, in1); + VSHF_H2_SH(tmp4, tmp5, tmp4, tmp5, zigzag0, zigzag1, out0, out1); + ST_SH2(in0, in1, &in[0], 8); + ST_SH2(out0, out1, &out[0], 8); + out0 = __msa_add_a_h(out0, out1); + sum = HADD_SH_S32(out0); + return (sum > 0); +} + +static int Quantize2Blocks_MSA(int16_t in[32], int16_t out[32], + const VP8Matrix* const mtx) { + int nz; + nz = VP8EncQuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0; + nz |= VP8EncQuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1; + return nz; +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMSA(void) { + VP8ITransform = ITransform_MSA; + VP8FTransform = FTransform_MSA; + VP8FTransformWHT = FTransformWHT_MSA; + + VP8TDisto4x4 = Disto4x4_MSA; + VP8TDisto16x16 = Disto16x16_MSA; + VP8CollectHistogram = CollectHistogram_MSA; + + VP8EncPredLuma4 = Intra4Preds_MSA; + VP8EncPredLuma16 = Intra16Preds_MSA; + VP8EncPredChroma8 = IntraChromaPreds_MSA; + + VP8SSE16x16 = SSE16x16_MSA; + VP8SSE16x8 = SSE16x8_MSA; + VP8SSE8x8 = SSE8x8_MSA; + VP8SSE4x4 = SSE4x4_MSA; + + VP8EncQuantizeBlock = QuantizeBlock_MSA; + VP8EncQuantize2Blocks = Quantize2Blocks_MSA; + VP8EncQuantizeBlockWHT = QuantizeBlock_MSA; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8EncDspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/libraries/webp/src/dsp/enc_neon.c b/libraries/webp/src/dsp/enc_neon.c new file mode 100644 index 00000000000..6f641c9a761 --- /dev/null +++ b/libraries/webp/src/dsp/enc_neon.c @@ -0,0 +1,944 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// ARM NEON version of speed-critical encoding functions. +// +// adapted from libvpx (https://www.webmproject.org/code/) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include + +#include "src/dsp/neon.h" +#include "src/enc/vp8i_enc.h" + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +// Inverse transform. +// This code is pretty much the same as TransformOne in the dec_neon.c, except +// for subtraction to *ref. See the comments there for algorithmic explanations. + +static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1; +static const int16_t kC2 = + WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above. + +// This code works but is *slower* than the inlined-asm version below +// (with gcc-4.6). So we disable it for now. Later, it'll be conditional to +// WEBP_USE_INTRINSICS define. +// With gcc-4.8, it's a little faster speed than inlined-assembly. +#if defined(WEBP_USE_INTRINSICS) + +// Treats 'v' as an uint8x8_t and zero extends to an int16x8_t. +static WEBP_INLINE int16x8_t ConvertU8ToS16_NEON(uint32x2_t v) { + return vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(v))); +} + +// Performs unsigned 8b saturation on 'dst01' and 'dst23' storing the result +// to the corresponding rows of 'dst'. +static WEBP_INLINE void SaturateAndStore4x4_NEON(uint8_t* const dst, + const int16x8_t dst01, + const int16x8_t dst23) { + // Unsigned saturate to 8b. + const uint8x8_t dst01_u8 = vqmovun_s16(dst01); + const uint8x8_t dst23_u8 = vqmovun_s16(dst23); + + // Store the results. + vst1_lane_u32((uint32_t*)(dst + 0 * BPS), vreinterpret_u32_u8(dst01_u8), 0); + vst1_lane_u32((uint32_t*)(dst + 1 * BPS), vreinterpret_u32_u8(dst01_u8), 1); + vst1_lane_u32((uint32_t*)(dst + 2 * BPS), vreinterpret_u32_u8(dst23_u8), 0); + vst1_lane_u32((uint32_t*)(dst + 3 * BPS), vreinterpret_u32_u8(dst23_u8), 1); +} + +static WEBP_INLINE void Add4x4_NEON(const int16x8_t row01, + const int16x8_t row23, + const uint8_t* const ref, + uint8_t* const dst) { + uint32x2_t dst01 = vdup_n_u32(0); + uint32x2_t dst23 = vdup_n_u32(0); + + // Load the source pixels. + dst01 = vld1_lane_u32((uint32_t*)(ref + 0 * BPS), dst01, 0); + dst23 = vld1_lane_u32((uint32_t*)(ref + 2 * BPS), dst23, 0); + dst01 = vld1_lane_u32((uint32_t*)(ref + 1 * BPS), dst01, 1); + dst23 = vld1_lane_u32((uint32_t*)(ref + 3 * BPS), dst23, 1); + + { + // Convert to 16b. + const int16x8_t dst01_s16 = ConvertU8ToS16_NEON(dst01); + const int16x8_t dst23_s16 = ConvertU8ToS16_NEON(dst23); + + // Descale with rounding. + const int16x8_t out01 = vrsraq_n_s16(dst01_s16, row01, 3); + const int16x8_t out23 = vrsraq_n_s16(dst23_s16, row23, 3); + // Add the inverse transform. + SaturateAndStore4x4_NEON(dst, out01, out23); + } +} + +static WEBP_INLINE void Transpose8x2_NEON(const int16x8_t in0, + const int16x8_t in1, + int16x8x2_t* const out) { + // a0 a1 a2 a3 | b0 b1 b2 b3 => a0 b0 c0 d0 | a1 b1 c1 d1 + // c0 c1 c2 c3 | d0 d1 d2 d3 a2 b2 c2 d2 | a3 b3 c3 d3 + const int16x8x2_t tmp0 = vzipq_s16(in0, in1); // a0 c0 a1 c1 a2 c2 ... + // b0 d0 b1 d1 b2 d2 ... + *out = vzipq_s16(tmp0.val[0], tmp0.val[1]); +} + +static WEBP_INLINE void TransformPass_NEON(int16x8x2_t* const rows) { + // {rows} = in0 | in4 + // in8 | in12 + // B1 = in4 | in12 + const int16x8_t B1 = + vcombine_s16(vget_high_s16(rows->val[0]), vget_high_s16(rows->val[1])); + // C0 = kC1 * in4 | kC1 * in12 + // C1 = kC2 * in4 | kC2 * in12 + const int16x8_t C0 = vsraq_n_s16(B1, vqdmulhq_n_s16(B1, kC1), 1); + const int16x8_t C1 = vqdmulhq_n_s16(B1, kC2); + const int16x4_t a = vqadd_s16(vget_low_s16(rows->val[0]), + vget_low_s16(rows->val[1])); // in0 + in8 + const int16x4_t b = vqsub_s16(vget_low_s16(rows->val[0]), + vget_low_s16(rows->val[1])); // in0 - in8 + // c = kC2 * in4 - kC1 * in12 + // d = kC1 * in4 + kC2 * in12 + const int16x4_t c = vqsub_s16(vget_low_s16(C1), vget_high_s16(C0)); + const int16x4_t d = vqadd_s16(vget_low_s16(C0), vget_high_s16(C1)); + const int16x8_t D0 = vcombine_s16(a, b); // D0 = a | b + const int16x8_t D1 = vcombine_s16(d, c); // D1 = d | c + const int16x8_t E0 = vqaddq_s16(D0, D1); // a+d | b+c + const int16x8_t E_tmp = vqsubq_s16(D0, D1); // a-d | b-c + const int16x8_t E1 = vcombine_s16(vget_high_s16(E_tmp), vget_low_s16(E_tmp)); + Transpose8x2_NEON(E0, E1, rows); +} + +static void ITransformOne_NEON(const uint8_t* ref, + const int16_t* in, uint8_t* dst) { + int16x8x2_t rows; + INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8)); + TransformPass_NEON(&rows); + TransformPass_NEON(&rows); + Add4x4_NEON(rows.val[0], rows.val[1], ref, dst); +} + +#else + +static void ITransformOne_NEON(const uint8_t* ref, + const int16_t* in, uint8_t* dst) { + const int kBPS = BPS; + const int16_t kC1C2[] = { kC1, kC2, 0, 0 }; + + __asm__ volatile ( + "vld1.16 {q1, q2}, [%[in]] \n" + "vld1.16 {d0}, [%[kC1C2]] \n" + + // d2: in[0] + // d3: in[8] + // d4: in[4] + // d5: in[12] + "vswp d3, d4 \n" + + // q8 = {in[4], in[12]} * kC1 * 2 >> 16 + // q9 = {in[4], in[12]} * kC2 >> 16 + "vqdmulh.s16 q8, q2, d0[0] \n" + "vqdmulh.s16 q9, q2, d0[1] \n" + + // d22 = a = in[0] + in[8] + // d23 = b = in[0] - in[8] + "vqadd.s16 d22, d2, d3 \n" + "vqsub.s16 d23, d2, d3 \n" + + // q8 = in[4]/[12] * kC1 >> 16 + "vshr.s16 q8, q8, #1 \n" + + // Add {in[4], in[12]} back after the multiplication. + "vqadd.s16 q8, q2, q8 \n" + + // d20 = c = in[4]*kC2 - in[12]*kC1 + // d21 = d = in[4]*kC1 + in[12]*kC2 + "vqsub.s16 d20, d18, d17 \n" + "vqadd.s16 d21, d19, d16 \n" + + // d2 = tmp[0] = a + d + // d3 = tmp[1] = b + c + // d4 = tmp[2] = b - c + // d5 = tmp[3] = a - d + "vqadd.s16 d2, d22, d21 \n" + "vqadd.s16 d3, d23, d20 \n" + "vqsub.s16 d4, d23, d20 \n" + "vqsub.s16 d5, d22, d21 \n" + + "vzip.16 q1, q2 \n" + "vzip.16 q1, q2 \n" + + "vswp d3, d4 \n" + + // q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16 + // q9 = {tmp[4], tmp[12]} * kC2 >> 16 + "vqdmulh.s16 q8, q2, d0[0] \n" + "vqdmulh.s16 q9, q2, d0[1] \n" + + // d22 = a = tmp[0] + tmp[8] + // d23 = b = tmp[0] - tmp[8] + "vqadd.s16 d22, d2, d3 \n" + "vqsub.s16 d23, d2, d3 \n" + + "vshr.s16 q8, q8, #1 \n" + "vqadd.s16 q8, q2, q8 \n" + + // d20 = c = in[4]*kC2 - in[12]*kC1 + // d21 = d = in[4]*kC1 + in[12]*kC2 + "vqsub.s16 d20, d18, d17 \n" + "vqadd.s16 d21, d19, d16 \n" + + // d2 = tmp[0] = a + d + // d3 = tmp[1] = b + c + // d4 = tmp[2] = b - c + // d5 = tmp[3] = a - d + "vqadd.s16 d2, d22, d21 \n" + "vqadd.s16 d3, d23, d20 \n" + "vqsub.s16 d4, d23, d20 \n" + "vqsub.s16 d5, d22, d21 \n" + + "vld1.32 d6[0], [%[ref]], %[kBPS] \n" + "vld1.32 d6[1], [%[ref]], %[kBPS] \n" + "vld1.32 d7[0], [%[ref]], %[kBPS] \n" + "vld1.32 d7[1], [%[ref]], %[kBPS] \n" + + "sub %[ref], %[ref], %[kBPS], lsl #2 \n" + + // (val) + 4 >> 3 + "vrshr.s16 d2, d2, #3 \n" + "vrshr.s16 d3, d3, #3 \n" + "vrshr.s16 d4, d4, #3 \n" + "vrshr.s16 d5, d5, #3 \n" + + "vzip.16 q1, q2 \n" + "vzip.16 q1, q2 \n" + + // Must accumulate before saturating + "vmovl.u8 q8, d6 \n" + "vmovl.u8 q9, d7 \n" + + "vqadd.s16 q1, q1, q8 \n" + "vqadd.s16 q2, q2, q9 \n" + + "vqmovun.s16 d0, q1 \n" + "vqmovun.s16 d1, q2 \n" + + "vst1.32 d0[0], [%[dst]], %[kBPS] \n" + "vst1.32 d0[1], [%[dst]], %[kBPS] \n" + "vst1.32 d1[0], [%[dst]], %[kBPS] \n" + "vst1.32 d1[1], [%[dst]] \n" + + : [in] "+r"(in), [dst] "+r"(dst) // modified registers + : [kBPS] "r"(kBPS), [kC1C2] "r"(kC1C2), [ref] "r"(ref) // constants + : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" // clobbered + ); +} + +#endif // WEBP_USE_INTRINSICS + +static void ITransform_NEON(const uint8_t* ref, + const int16_t* in, uint8_t* dst, int do_two) { + ITransformOne_NEON(ref, in, dst); + if (do_two) { + ITransformOne_NEON(ref + 4, in + 16, dst + 4); + } +} + +// Load all 4x4 pixels into a single uint8x16_t variable. +static uint8x16_t Load4x4_NEON(const uint8_t* src) { + uint32x4_t out = vdupq_n_u32(0); + out = vld1q_lane_u32((const uint32_t*)(src + 0 * BPS), out, 0); + out = vld1q_lane_u32((const uint32_t*)(src + 1 * BPS), out, 1); + out = vld1q_lane_u32((const uint32_t*)(src + 2 * BPS), out, 2); + out = vld1q_lane_u32((const uint32_t*)(src + 3 * BPS), out, 3); + return vreinterpretq_u8_u32(out); +} + +// Forward transform. + +#if defined(WEBP_USE_INTRINSICS) + +static WEBP_INLINE void Transpose4x4_S16_NEON(const int16x4_t A, + const int16x4_t B, + const int16x4_t C, + const int16x4_t D, + int16x8_t* const out01, + int16x8_t* const out32) { + const int16x4x2_t AB = vtrn_s16(A, B); + const int16x4x2_t CD = vtrn_s16(C, D); + const int32x2x2_t tmp02 = vtrn_s32(vreinterpret_s32_s16(AB.val[0]), + vreinterpret_s32_s16(CD.val[0])); + const int32x2x2_t tmp13 = vtrn_s32(vreinterpret_s32_s16(AB.val[1]), + vreinterpret_s32_s16(CD.val[1])); + *out01 = vreinterpretq_s16_s64( + vcombine_s64(vreinterpret_s64_s32(tmp02.val[0]), + vreinterpret_s64_s32(tmp13.val[0]))); + *out32 = vreinterpretq_s16_s64( + vcombine_s64(vreinterpret_s64_s32(tmp13.val[1]), + vreinterpret_s64_s32(tmp02.val[1]))); +} + +static WEBP_INLINE int16x8_t DiffU8ToS16_NEON(const uint8x8_t a, + const uint8x8_t b) { + return vreinterpretq_s16_u16(vsubl_u8(a, b)); +} + +static void FTransform_NEON(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + int16x8_t d0d1, d3d2; // working 4x4 int16 variables + { + const uint8x16_t S0 = Load4x4_NEON(src); + const uint8x16_t R0 = Load4x4_NEON(ref); + const int16x8_t D0D1 = DiffU8ToS16_NEON(vget_low_u8(S0), vget_low_u8(R0)); + const int16x8_t D2D3 = DiffU8ToS16_NEON(vget_high_u8(S0), vget_high_u8(R0)); + const int16x4_t D0 = vget_low_s16(D0D1); + const int16x4_t D1 = vget_high_s16(D0D1); + const int16x4_t D2 = vget_low_s16(D2D3); + const int16x4_t D3 = vget_high_s16(D2D3); + Transpose4x4_S16_NEON(D0, D1, D2, D3, &d0d1, &d3d2); + } + { // 1rst pass + const int32x4_t kCst937 = vdupq_n_s32(937); + const int32x4_t kCst1812 = vdupq_n_s32(1812); + const int16x8_t a0a1 = vaddq_s16(d0d1, d3d2); // d0+d3 | d1+d2 (=a0|a1) + const int16x8_t a3a2 = vsubq_s16(d0d1, d3d2); // d0-d3 | d1-d2 (=a3|a2) + const int16x8_t a0a1_2 = vshlq_n_s16(a0a1, 3); + const int16x4_t tmp0 = vadd_s16(vget_low_s16(a0a1_2), + vget_high_s16(a0a1_2)); + const int16x4_t tmp2 = vsub_s16(vget_low_s16(a0a1_2), + vget_high_s16(a0a1_2)); + const int32x4_t a3_2217 = vmull_n_s16(vget_low_s16(a3a2), 2217); + const int32x4_t a2_2217 = vmull_n_s16(vget_high_s16(a3a2), 2217); + const int32x4_t a2_p_a3 = vmlal_n_s16(a2_2217, vget_low_s16(a3a2), 5352); + const int32x4_t a3_m_a2 = vmlsl_n_s16(a3_2217, vget_high_s16(a3a2), 5352); + const int16x4_t tmp1 = vshrn_n_s32(vaddq_s32(a2_p_a3, kCst1812), 9); + const int16x4_t tmp3 = vshrn_n_s32(vaddq_s32(a3_m_a2, kCst937), 9); + Transpose4x4_S16_NEON(tmp0, tmp1, tmp2, tmp3, &d0d1, &d3d2); + } + { // 2nd pass + // the (1<<16) addition is for the replacement: a3!=0 <-> 1-(a3==0) + const int32x4_t kCst12000 = vdupq_n_s32(12000 + (1 << 16)); + const int32x4_t kCst51000 = vdupq_n_s32(51000); + const int16x8_t a0a1 = vaddq_s16(d0d1, d3d2); // d0+d3 | d1+d2 (=a0|a1) + const int16x8_t a3a2 = vsubq_s16(d0d1, d3d2); // d0-d3 | d1-d2 (=a3|a2) + const int16x4_t a0_k7 = vadd_s16(vget_low_s16(a0a1), vdup_n_s16(7)); + const int16x4_t out0 = vshr_n_s16(vadd_s16(a0_k7, vget_high_s16(a0a1)), 4); + const int16x4_t out2 = vshr_n_s16(vsub_s16(a0_k7, vget_high_s16(a0a1)), 4); + const int32x4_t a3_2217 = vmull_n_s16(vget_low_s16(a3a2), 2217); + const int32x4_t a2_2217 = vmull_n_s16(vget_high_s16(a3a2), 2217); + const int32x4_t a2_p_a3 = vmlal_n_s16(a2_2217, vget_low_s16(a3a2), 5352); + const int32x4_t a3_m_a2 = vmlsl_n_s16(a3_2217, vget_high_s16(a3a2), 5352); + const int16x4_t tmp1 = vaddhn_s32(a2_p_a3, kCst12000); + const int16x4_t out3 = vaddhn_s32(a3_m_a2, kCst51000); + const int16x4_t a3_eq_0 = + vreinterpret_s16_u16(vceq_s16(vget_low_s16(a3a2), vdup_n_s16(0))); + const int16x4_t out1 = vadd_s16(tmp1, a3_eq_0); + vst1_s16(out + 0, out0); + vst1_s16(out + 4, out1); + vst1_s16(out + 8, out2); + vst1_s16(out + 12, out3); + } +} + +#else + +// adapted from vp8/encoder/arm/neon/shortfdct_neon.asm +static const int16_t kCoeff16[] = { + 5352, 5352, 5352, 5352, 2217, 2217, 2217, 2217 +}; +static const int32_t kCoeff32[] = { + 1812, 1812, 1812, 1812, + 937, 937, 937, 937, + 12000, 12000, 12000, 12000, + 51000, 51000, 51000, 51000 +}; + +static void FTransform_NEON(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + const int kBPS = BPS; + const uint8_t* src_ptr = src; + const uint8_t* ref_ptr = ref; + const int16_t* coeff16 = kCoeff16; + const int32_t* coeff32 = kCoeff32; + + __asm__ volatile ( + // load src into q4, q5 in high half + "vld1.8 {d8}, [%[src_ptr]], %[kBPS] \n" + "vld1.8 {d10}, [%[src_ptr]], %[kBPS] \n" + "vld1.8 {d9}, [%[src_ptr]], %[kBPS] \n" + "vld1.8 {d11}, [%[src_ptr]] \n" + + // load ref into q6, q7 in high half + "vld1.8 {d12}, [%[ref_ptr]], %[kBPS] \n" + "vld1.8 {d14}, [%[ref_ptr]], %[kBPS] \n" + "vld1.8 {d13}, [%[ref_ptr]], %[kBPS] \n" + "vld1.8 {d15}, [%[ref_ptr]] \n" + + // Pack the high values in to q4 and q6 + "vtrn.32 q4, q5 \n" + "vtrn.32 q6, q7 \n" + + // d[0-3] = src - ref + "vsubl.u8 q0, d8, d12 \n" + "vsubl.u8 q1, d9, d13 \n" + + // load coeff16 into q8(d16=5352, d17=2217) + "vld1.16 {q8}, [%[coeff16]] \n" + + // load coeff32 high half into q9 = 1812, q10 = 937 + "vld1.32 {q9, q10}, [%[coeff32]]! \n" + + // load coeff32 low half into q11=12000, q12=51000 + "vld1.32 {q11,q12}, [%[coeff32]] \n" + + // part 1 + // Transpose. Register dN is the same as dN in C + "vtrn.32 d0, d2 \n" + "vtrn.32 d1, d3 \n" + "vtrn.16 d0, d1 \n" + "vtrn.16 d2, d3 \n" + + "vadd.s16 d4, d0, d3 \n" // a0 = d0 + d3 + "vadd.s16 d5, d1, d2 \n" // a1 = d1 + d2 + "vsub.s16 d6, d1, d2 \n" // a2 = d1 - d2 + "vsub.s16 d7, d0, d3 \n" // a3 = d0 - d3 + + "vadd.s16 d0, d4, d5 \n" // a0 + a1 + "vshl.s16 d0, d0, #3 \n" // temp[0+i*4] = (a0+a1) << 3 + "vsub.s16 d2, d4, d5 \n" // a0 - a1 + "vshl.s16 d2, d2, #3 \n" // (temp[2+i*4] = (a0-a1) << 3 + + "vmlal.s16 q9, d7, d16 \n" // a3*5352 + 1812 + "vmlal.s16 q10, d7, d17 \n" // a3*2217 + 937 + "vmlal.s16 q9, d6, d17 \n" // a2*2217 + a3*5352 + 1812 + "vmlsl.s16 q10, d6, d16 \n" // a3*2217 + 937 - a2*5352 + + // temp[1+i*4] = (d2*2217 + d3*5352 + 1812) >> 9 + // temp[3+i*4] = (d3*2217 + 937 - d2*5352) >> 9 + "vshrn.s32 d1, q9, #9 \n" + "vshrn.s32 d3, q10, #9 \n" + + // part 2 + // transpose d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12] + "vtrn.32 d0, d2 \n" + "vtrn.32 d1, d3 \n" + "vtrn.16 d0, d1 \n" + "vtrn.16 d2, d3 \n" + + "vmov.s16 d26, #7 \n" + + "vadd.s16 d4, d0, d3 \n" // a1 = ip[0] + ip[12] + "vadd.s16 d5, d1, d2 \n" // b1 = ip[4] + ip[8] + "vsub.s16 d6, d1, d2 \n" // c1 = ip[4] - ip[8] + "vadd.s16 d4, d4, d26 \n" // a1 + 7 + "vsub.s16 d7, d0, d3 \n" // d1 = ip[0] - ip[12] + + "vadd.s16 d0, d4, d5 \n" // op[0] = a1 + b1 + 7 + "vsub.s16 d2, d4, d5 \n" // op[8] = a1 - b1 + 7 + + "vmlal.s16 q11, d7, d16 \n" // d1*5352 + 12000 + "vmlal.s16 q12, d7, d17 \n" // d1*2217 + 51000 + + "vceq.s16 d4, d7, #0 \n" + + "vshr.s16 d0, d0, #4 \n" + "vshr.s16 d2, d2, #4 \n" + + "vmlal.s16 q11, d6, d17 \n" // c1*2217 + d1*5352 + 12000 + "vmlsl.s16 q12, d6, d16 \n" // d1*2217 - c1*5352 + 51000 + + "vmvn d4, d4 \n" // !(d1 == 0) + // op[4] = (c1*2217 + d1*5352 + 12000)>>16 + "vshrn.s32 d1, q11, #16 \n" + // op[4] += (d1!=0) + "vsub.s16 d1, d1, d4 \n" + // op[12]= (d1*2217 - c1*5352 + 51000)>>16 + "vshrn.s32 d3, q12, #16 \n" + + // set result to out array + "vst1.16 {q0, q1}, [%[out]] \n" + : [src_ptr] "+r"(src_ptr), [ref_ptr] "+r"(ref_ptr), + [coeff32] "+r"(coeff32) // modified registers + : [kBPS] "r"(kBPS), [coeff16] "r"(coeff16), + [out] "r"(out) // constants + : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", + "q10", "q11", "q12", "q13" // clobbered + ); +} + +#endif + +#define LOAD_LANE_16b(VALUE, LANE) do { \ + (VALUE) = vld1_lane_s16(src, (VALUE), (LANE)); \ + src += stride; \ +} while (0) + +static void FTransformWHT_NEON(const int16_t* src, int16_t* out) { + const int stride = 16; + const int16x4_t zero = vdup_n_s16(0); + int32x4x4_t tmp0; + int16x4x4_t in; + INIT_VECTOR4(in, zero, zero, zero, zero); + LOAD_LANE_16b(in.val[0], 0); + LOAD_LANE_16b(in.val[1], 0); + LOAD_LANE_16b(in.val[2], 0); + LOAD_LANE_16b(in.val[3], 0); + LOAD_LANE_16b(in.val[0], 1); + LOAD_LANE_16b(in.val[1], 1); + LOAD_LANE_16b(in.val[2], 1); + LOAD_LANE_16b(in.val[3], 1); + LOAD_LANE_16b(in.val[0], 2); + LOAD_LANE_16b(in.val[1], 2); + LOAD_LANE_16b(in.val[2], 2); + LOAD_LANE_16b(in.val[3], 2); + LOAD_LANE_16b(in.val[0], 3); + LOAD_LANE_16b(in.val[1], 3); + LOAD_LANE_16b(in.val[2], 3); + LOAD_LANE_16b(in.val[3], 3); + + { + // a0 = in[0 * 16] + in[2 * 16] + // a1 = in[1 * 16] + in[3 * 16] + // a2 = in[1 * 16] - in[3 * 16] + // a3 = in[0 * 16] - in[2 * 16] + const int32x4_t a0 = vaddl_s16(in.val[0], in.val[2]); + const int32x4_t a1 = vaddl_s16(in.val[1], in.val[3]); + const int32x4_t a2 = vsubl_s16(in.val[1], in.val[3]); + const int32x4_t a3 = vsubl_s16(in.val[0], in.val[2]); + tmp0.val[0] = vaddq_s32(a0, a1); + tmp0.val[1] = vaddq_s32(a3, a2); + tmp0.val[2] = vsubq_s32(a3, a2); + tmp0.val[3] = vsubq_s32(a0, a1); + } + { + const int32x4x4_t tmp1 = Transpose4x4_NEON(tmp0); + // a0 = tmp[0 + i] + tmp[ 8 + i] + // a1 = tmp[4 + i] + tmp[12 + i] + // a2 = tmp[4 + i] - tmp[12 + i] + // a3 = tmp[0 + i] - tmp[ 8 + i] + const int32x4_t a0 = vaddq_s32(tmp1.val[0], tmp1.val[2]); + const int32x4_t a1 = vaddq_s32(tmp1.val[1], tmp1.val[3]); + const int32x4_t a2 = vsubq_s32(tmp1.val[1], tmp1.val[3]); + const int32x4_t a3 = vsubq_s32(tmp1.val[0], tmp1.val[2]); + const int32x4_t b0 = vhaddq_s32(a0, a1); // (a0 + a1) >> 1 + const int32x4_t b1 = vhaddq_s32(a3, a2); // (a3 + a2) >> 1 + const int32x4_t b2 = vhsubq_s32(a3, a2); // (a3 - a2) >> 1 + const int32x4_t b3 = vhsubq_s32(a0, a1); // (a0 - a1) >> 1 + const int16x4_t out0 = vmovn_s32(b0); + const int16x4_t out1 = vmovn_s32(b1); + const int16x4_t out2 = vmovn_s32(b2); + const int16x4_t out3 = vmovn_s32(b3); + + vst1_s16(out + 0, out0); + vst1_s16(out + 4, out1); + vst1_s16(out + 8, out2); + vst1_s16(out + 12, out3); + } +} +#undef LOAD_LANE_16b + +//------------------------------------------------------------------------------ +// Texture distortion +// +// We try to match the spectral content (weighted) between source and +// reconstructed samples. + +// a 0123, b 0123 +// a 4567, b 4567 +// a 89ab, b 89ab +// a cdef, b cdef +// +// transpose +// +// a 048c, b 048c +// a 159d, b 159d +// a 26ae, b 26ae +// a 37bf, b 37bf +// +static WEBP_INLINE int16x8x4_t DistoTranspose4x4S16_NEON(int16x8x4_t q4_in) { + const int16x8x2_t q2_tmp0 = vtrnq_s16(q4_in.val[0], q4_in.val[1]); + const int16x8x2_t q2_tmp1 = vtrnq_s16(q4_in.val[2], q4_in.val[3]); + const int32x4x2_t q2_tmp2 = vtrnq_s32(vreinterpretq_s32_s16(q2_tmp0.val[0]), + vreinterpretq_s32_s16(q2_tmp1.val[0])); + const int32x4x2_t q2_tmp3 = vtrnq_s32(vreinterpretq_s32_s16(q2_tmp0.val[1]), + vreinterpretq_s32_s16(q2_tmp1.val[1])); + q4_in.val[0] = vreinterpretq_s16_s32(q2_tmp2.val[0]); + q4_in.val[2] = vreinterpretq_s16_s32(q2_tmp2.val[1]); + q4_in.val[1] = vreinterpretq_s16_s32(q2_tmp3.val[0]); + q4_in.val[3] = vreinterpretq_s16_s32(q2_tmp3.val[1]); + return q4_in; +} + +static WEBP_INLINE int16x8x4_t DistoHorizontalPass_NEON( + const int16x8x4_t q4_in) { + // {a0, a1} = {in[0] + in[2], in[1] + in[3]} + // {a3, a2} = {in[0] - in[2], in[1] - in[3]} + const int16x8_t q_a0 = vaddq_s16(q4_in.val[0], q4_in.val[2]); + const int16x8_t q_a1 = vaddq_s16(q4_in.val[1], q4_in.val[3]); + const int16x8_t q_a3 = vsubq_s16(q4_in.val[0], q4_in.val[2]); + const int16x8_t q_a2 = vsubq_s16(q4_in.val[1], q4_in.val[3]); + int16x8x4_t q4_out; + // tmp[0] = a0 + a1 + // tmp[1] = a3 + a2 + // tmp[2] = a3 - a2 + // tmp[3] = a0 - a1 + INIT_VECTOR4(q4_out, + vabsq_s16(vaddq_s16(q_a0, q_a1)), + vabsq_s16(vaddq_s16(q_a3, q_a2)), + vabdq_s16(q_a3, q_a2), vabdq_s16(q_a0, q_a1)); + return q4_out; +} + +static WEBP_INLINE int16x8x4_t DistoVerticalPass_NEON(const uint8x8x4_t q4_in) { + const int16x8_t q_a0 = vreinterpretq_s16_u16(vaddl_u8(q4_in.val[0], + q4_in.val[2])); + const int16x8_t q_a1 = vreinterpretq_s16_u16(vaddl_u8(q4_in.val[1], + q4_in.val[3])); + const int16x8_t q_a2 = vreinterpretq_s16_u16(vsubl_u8(q4_in.val[1], + q4_in.val[3])); + const int16x8_t q_a3 = vreinterpretq_s16_u16(vsubl_u8(q4_in.val[0], + q4_in.val[2])); + int16x8x4_t q4_out; + + INIT_VECTOR4(q4_out, + vaddq_s16(q_a0, q_a1), vaddq_s16(q_a3, q_a2), + vsubq_s16(q_a3, q_a2), vsubq_s16(q_a0, q_a1)); + return q4_out; +} + +static WEBP_INLINE int16x4x4_t DistoLoadW_NEON(const uint16_t* w) { + const uint16x8_t q_w07 = vld1q_u16(&w[0]); + const uint16x8_t q_w8f = vld1q_u16(&w[8]); + int16x4x4_t d4_w; + INIT_VECTOR4(d4_w, + vget_low_s16(vreinterpretq_s16_u16(q_w07)), + vget_high_s16(vreinterpretq_s16_u16(q_w07)), + vget_low_s16(vreinterpretq_s16_u16(q_w8f)), + vget_high_s16(vreinterpretq_s16_u16(q_w8f))); + return d4_w; +} + +static WEBP_INLINE int32x2_t DistoSum_NEON(const int16x8x4_t q4_in, + const int16x4x4_t d4_w) { + int32x2_t d_sum; + // sum += w[ 0] * abs(b0); + // sum += w[ 4] * abs(b1); + // sum += w[ 8] * abs(b2); + // sum += w[12] * abs(b3); + int32x4_t q_sum0 = vmull_s16(d4_w.val[0], vget_low_s16(q4_in.val[0])); + int32x4_t q_sum1 = vmull_s16(d4_w.val[1], vget_low_s16(q4_in.val[1])); + int32x4_t q_sum2 = vmull_s16(d4_w.val[2], vget_low_s16(q4_in.val[2])); + int32x4_t q_sum3 = vmull_s16(d4_w.val[3], vget_low_s16(q4_in.val[3])); + q_sum0 = vmlsl_s16(q_sum0, d4_w.val[0], vget_high_s16(q4_in.val[0])); + q_sum1 = vmlsl_s16(q_sum1, d4_w.val[1], vget_high_s16(q4_in.val[1])); + q_sum2 = vmlsl_s16(q_sum2, d4_w.val[2], vget_high_s16(q4_in.val[2])); + q_sum3 = vmlsl_s16(q_sum3, d4_w.val[3], vget_high_s16(q4_in.val[3])); + + q_sum0 = vaddq_s32(q_sum0, q_sum1); + q_sum2 = vaddq_s32(q_sum2, q_sum3); + q_sum2 = vaddq_s32(q_sum0, q_sum2); + d_sum = vpadd_s32(vget_low_s32(q_sum2), vget_high_s32(q_sum2)); + d_sum = vpadd_s32(d_sum, d_sum); + return d_sum; +} + +#define LOAD_LANE_32b(src, VALUE, LANE) \ + (VALUE) = vld1_lane_u32((const uint32_t*)(src), (VALUE), (LANE)) + +// Hadamard transform +// Returns the weighted sum of the absolute value of transformed coefficients. +// w[] contains a row-major 4 by 4 symmetric matrix. +static int Disto4x4_NEON(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + uint32x2_t d_in_ab_0123 = vdup_n_u32(0); + uint32x2_t d_in_ab_4567 = vdup_n_u32(0); + uint32x2_t d_in_ab_89ab = vdup_n_u32(0); + uint32x2_t d_in_ab_cdef = vdup_n_u32(0); + uint8x8x4_t d4_in; + + // load data a, b + LOAD_LANE_32b(a + 0 * BPS, d_in_ab_0123, 0); + LOAD_LANE_32b(a + 1 * BPS, d_in_ab_4567, 0); + LOAD_LANE_32b(a + 2 * BPS, d_in_ab_89ab, 0); + LOAD_LANE_32b(a + 3 * BPS, d_in_ab_cdef, 0); + LOAD_LANE_32b(b + 0 * BPS, d_in_ab_0123, 1); + LOAD_LANE_32b(b + 1 * BPS, d_in_ab_4567, 1); + LOAD_LANE_32b(b + 2 * BPS, d_in_ab_89ab, 1); + LOAD_LANE_32b(b + 3 * BPS, d_in_ab_cdef, 1); + INIT_VECTOR4(d4_in, + vreinterpret_u8_u32(d_in_ab_0123), + vreinterpret_u8_u32(d_in_ab_4567), + vreinterpret_u8_u32(d_in_ab_89ab), + vreinterpret_u8_u32(d_in_ab_cdef)); + + { + // Vertical pass first to avoid a transpose (vertical and horizontal passes + // are commutative because w/kWeightY is symmetric) and subsequent + // transpose. + const int16x8x4_t q4_v = DistoVerticalPass_NEON(d4_in); + const int16x4x4_t d4_w = DistoLoadW_NEON(w); + // horizontal pass + const int16x8x4_t q4_t = DistoTranspose4x4S16_NEON(q4_v); + const int16x8x4_t q4_h = DistoHorizontalPass_NEON(q4_t); + int32x2_t d_sum = DistoSum_NEON(q4_h, d4_w); + + // abs(sum2 - sum1) >> 5 + d_sum = vabs_s32(d_sum); + d_sum = vshr_n_s32(d_sum, 5); + return vget_lane_s32(d_sum, 0); + } +} +#undef LOAD_LANE_32b + +static int Disto16x16_NEON(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4_NEON(a + x + y, b + x + y, w); + } + } + return D; +} + +//------------------------------------------------------------------------------ + +static void CollectHistogram_NEON(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block, + VP8Histogram* const histo) { + const uint16x8_t max_coeff_thresh = vdupq_n_u16(MAX_COEFF_THRESH); + int j; + int distribution[MAX_COEFF_THRESH + 1] = { 0 }; + for (j = start_block; j < end_block; ++j) { + int16_t out[16]; + FTransform_NEON(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + { + int k; + const int16x8_t a0 = vld1q_s16(out + 0); + const int16x8_t b0 = vld1q_s16(out + 8); + const uint16x8_t a1 = vreinterpretq_u16_s16(vabsq_s16(a0)); + const uint16x8_t b1 = vreinterpretq_u16_s16(vabsq_s16(b0)); + const uint16x8_t a2 = vshrq_n_u16(a1, 3); + const uint16x8_t b2 = vshrq_n_u16(b1, 3); + const uint16x8_t a3 = vminq_u16(a2, max_coeff_thresh); + const uint16x8_t b3 = vminq_u16(b2, max_coeff_thresh); + vst1q_s16(out + 0, vreinterpretq_s16_u16(a3)); + vst1q_s16(out + 8, vreinterpretq_s16_u16(b3)); + // Convert coefficients to bin. + for (k = 0; k < 16; ++k) { + ++distribution[out[k]]; + } + } + } + VP8SetHistogramData(distribution, histo); +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE void AccumulateSSE16_NEON(const uint8_t* const a, + const uint8_t* const b, + uint32x4_t* const sum) { + const uint8x16_t a0 = vld1q_u8(a); + const uint8x16_t b0 = vld1q_u8(b); + const uint8x16_t abs_diff = vabdq_u8(a0, b0); + const uint16x8_t prod1 = vmull_u8(vget_low_u8(abs_diff), + vget_low_u8(abs_diff)); + const uint16x8_t prod2 = vmull_u8(vget_high_u8(abs_diff), + vget_high_u8(abs_diff)); + /* pair-wise adds and widen */ + const uint32x4_t sum1 = vpaddlq_u16(prod1); + const uint32x4_t sum2 = vpaddlq_u16(prod2); + *sum = vaddq_u32(*sum, vaddq_u32(sum1, sum2)); +} + +// Horizontal sum of all four uint32_t values in 'sum'. +static int SumToInt_NEON(uint32x4_t sum) { +#if WEBP_AARCH64 + return (int)vaddvq_u32(sum); +#else + const uint64x2_t sum2 = vpaddlq_u32(sum); + const uint32x2_t sum3 = vadd_u32(vreinterpret_u32_u64(vget_low_u64(sum2)), + vreinterpret_u32_u64(vget_high_u64(sum2))); + return (int)vget_lane_u32(sum3, 0); +#endif +} + +static int SSE16x16_NEON(const uint8_t* a, const uint8_t* b) { + uint32x4_t sum = vdupq_n_u32(0); + int y; + for (y = 0; y < 16; ++y) { + AccumulateSSE16_NEON(a + y * BPS, b + y * BPS, &sum); + } + return SumToInt_NEON(sum); +} + +static int SSE16x8_NEON(const uint8_t* a, const uint8_t* b) { + uint32x4_t sum = vdupq_n_u32(0); + int y; + for (y = 0; y < 8; ++y) { + AccumulateSSE16_NEON(a + y * BPS, b + y * BPS, &sum); + } + return SumToInt_NEON(sum); +} + +static int SSE8x8_NEON(const uint8_t* a, const uint8_t* b) { + uint32x4_t sum = vdupq_n_u32(0); + int y; + for (y = 0; y < 8; ++y) { + const uint8x8_t a0 = vld1_u8(a + y * BPS); + const uint8x8_t b0 = vld1_u8(b + y * BPS); + const uint8x8_t abs_diff = vabd_u8(a0, b0); + const uint16x8_t prod = vmull_u8(abs_diff, abs_diff); + sum = vpadalq_u16(sum, prod); + } + return SumToInt_NEON(sum); +} + +static int SSE4x4_NEON(const uint8_t* a, const uint8_t* b) { + const uint8x16_t a0 = Load4x4_NEON(a); + const uint8x16_t b0 = Load4x4_NEON(b); + const uint8x16_t abs_diff = vabdq_u8(a0, b0); + const uint16x8_t prod1 = vmull_u8(vget_low_u8(abs_diff), + vget_low_u8(abs_diff)); + const uint16x8_t prod2 = vmull_u8(vget_high_u8(abs_diff), + vget_high_u8(abs_diff)); + /* pair-wise adds and widen */ + const uint32x4_t sum1 = vpaddlq_u16(prod1); + const uint32x4_t sum2 = vpaddlq_u16(prod2); + return SumToInt_NEON(vaddq_u32(sum1, sum2)); +} + +//------------------------------------------------------------------------------ + +// Compilation with gcc-4.6.x is problematic for now. +#if !defined(WORK_AROUND_GCC) + +static int16x8_t Quantize_NEON(int16_t* const in, + const VP8Matrix* const mtx, int offset) { + const uint16x8_t sharp = vld1q_u16(&mtx->sharpen_[offset]); + const uint16x8_t q = vld1q_u16(&mtx->q_[offset]); + const uint16x8_t iq = vld1q_u16(&mtx->iq_[offset]); + const uint32x4_t bias0 = vld1q_u32(&mtx->bias_[offset + 0]); + const uint32x4_t bias1 = vld1q_u32(&mtx->bias_[offset + 4]); + + const int16x8_t a = vld1q_s16(in + offset); // in + const uint16x8_t b = vreinterpretq_u16_s16(vabsq_s16(a)); // coeff = abs(in) + const int16x8_t sign = vshrq_n_s16(a, 15); // sign + const uint16x8_t c = vaddq_u16(b, sharp); // + sharpen + const uint32x4_t m0 = vmull_u16(vget_low_u16(c), vget_low_u16(iq)); + const uint32x4_t m1 = vmull_u16(vget_high_u16(c), vget_high_u16(iq)); + const uint32x4_t m2 = vhaddq_u32(m0, bias0); + const uint32x4_t m3 = vhaddq_u32(m1, bias1); // (coeff * iQ + bias) >> 1 + const uint16x8_t c0 = vcombine_u16(vshrn_n_u32(m2, 16), + vshrn_n_u32(m3, 16)); // QFIX=17 = 16+1 + const uint16x8_t c1 = vminq_u16(c0, vdupq_n_u16(MAX_LEVEL)); + const int16x8_t c2 = veorq_s16(vreinterpretq_s16_u16(c1), sign); + const int16x8_t c3 = vsubq_s16(c2, sign); // restore sign + const int16x8_t c4 = vmulq_s16(c3, vreinterpretq_s16_u16(q)); + vst1q_s16(in + offset, c4); + assert(QFIX == 17); // this function can't work as is if QFIX != 16+1 + return c3; +} + +static const uint8_t kShuffles[4][8] = { + { 0, 1, 2, 3, 8, 9, 16, 17 }, + { 10, 11, 4, 5, 6, 7, 12, 13 }, + { 18, 19, 24, 25, 26, 27, 20, 21 }, + { 14, 15, 22, 23, 28, 29, 30, 31 } +}; + +static int QuantizeBlock_NEON(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + const int16x8_t out0 = Quantize_NEON(in, mtx, 0); + const int16x8_t out1 = Quantize_NEON(in, mtx, 8); + uint8x8x4_t shuffles; + // vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use + // non-standard versions there. +#if defined(__APPLE__) && WEBP_AARCH64 && \ + defined(__apple_build_version__) && (__apple_build_version__< 6020037) + uint8x16x2_t all_out; + INIT_VECTOR2(all_out, vreinterpretq_u8_s16(out0), vreinterpretq_u8_s16(out1)); + INIT_VECTOR4(shuffles, + vtbl2q_u8(all_out, vld1_u8(kShuffles[0])), + vtbl2q_u8(all_out, vld1_u8(kShuffles[1])), + vtbl2q_u8(all_out, vld1_u8(kShuffles[2])), + vtbl2q_u8(all_out, vld1_u8(kShuffles[3]))); +#else + uint8x8x4_t all_out; + INIT_VECTOR4(all_out, + vreinterpret_u8_s16(vget_low_s16(out0)), + vreinterpret_u8_s16(vget_high_s16(out0)), + vreinterpret_u8_s16(vget_low_s16(out1)), + vreinterpret_u8_s16(vget_high_s16(out1))); + INIT_VECTOR4(shuffles, + vtbl4_u8(all_out, vld1_u8(kShuffles[0])), + vtbl4_u8(all_out, vld1_u8(kShuffles[1])), + vtbl4_u8(all_out, vld1_u8(kShuffles[2])), + vtbl4_u8(all_out, vld1_u8(kShuffles[3]))); +#endif + // Zigzag reordering + vst1_u8((uint8_t*)(out + 0), shuffles.val[0]); + vst1_u8((uint8_t*)(out + 4), shuffles.val[1]); + vst1_u8((uint8_t*)(out + 8), shuffles.val[2]); + vst1_u8((uint8_t*)(out + 12), shuffles.val[3]); + // test zeros + if (*(uint64_t*)(out + 0) != 0) return 1; + if (*(uint64_t*)(out + 4) != 0) return 1; + if (*(uint64_t*)(out + 8) != 0) return 1; + if (*(uint64_t*)(out + 12) != 0) return 1; + return 0; +} + +static int Quantize2Blocks_NEON(int16_t in[32], int16_t out[32], + const VP8Matrix* const mtx) { + int nz; + nz = QuantizeBlock_NEON(in + 0 * 16, out + 0 * 16, mtx) << 0; + nz |= QuantizeBlock_NEON(in + 1 * 16, out + 1 * 16, mtx) << 1; + return nz; +} + +#endif // !WORK_AROUND_GCC + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspInitNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitNEON(void) { + VP8ITransform = ITransform_NEON; + VP8FTransform = FTransform_NEON; + + VP8FTransformWHT = FTransformWHT_NEON; + + VP8TDisto4x4 = Disto4x4_NEON; + VP8TDisto16x16 = Disto16x16_NEON; + VP8CollectHistogram = CollectHistogram_NEON; + + VP8SSE16x16 = SSE16x16_NEON; + VP8SSE16x8 = SSE16x8_NEON; + VP8SSE8x8 = SSE8x8_NEON; + VP8SSE4x4 = SSE4x4_NEON; + +#if !defined(WORK_AROUND_GCC) + VP8EncQuantizeBlock = QuantizeBlock_NEON; + VP8EncQuantize2Blocks = Quantize2Blocks_NEON; +#endif +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(VP8EncDspInitNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/enc_sse2.c b/libraries/webp/src/dsp/enc_sse2.c new file mode 100644 index 00000000000..010624a2f71 --- /dev/null +++ b/libraries/webp/src/dsp/enc_sse2.c @@ -0,0 +1,1514 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 version of speed-critical encoding functions. +// +// Author: Christian Duvivier (cduvivier@google.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) +#include +#include // for abs() +#include + +#include "src/dsp/common_sse2.h" +#include "src/enc/cost_enc.h" +#include "src/enc/vp8i_enc.h" + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +// Does one inverse transform. +static void ITransform_One_SSE2(const uint8_t* ref, const int16_t* in, + uint8_t* dst) { + // This implementation makes use of 16-bit fixed point versions of two + // multiply constants: + // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16 + // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16 + // + // To be able to use signed 16-bit integers, we use the following trick to + // have constants within range: + // - Associated constants are obtained by subtracting the 16-bit fixed point + // version of one: + // k = K - (1 << 16) => K = k + (1 << 16) + // K1 = 85267 => k1 = 20091 + // K2 = 35468 => k2 = -30068 + // - The multiplication of a variable by a constant become the sum of the + // variable and the multiplication of that variable by the associated + // constant: + // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x + const __m128i k1k2 = _mm_set_epi16(-30068, -30068, -30068, -30068, + 20091, 20091, 20091, 20091); + const __m128i k2k1 = _mm_set_epi16(20091, 20091, 20091, 20091, + -30068, -30068, -30068, -30068); + const __m128i zero = _mm_setzero_si128(); + const __m128i zero_four = _mm_set_epi16(0, 0, 0, 0, 4, 4, 4, 4); + __m128i T01, T23; + + // Load and concatenate the transform coefficients. + const __m128i in01 = _mm_loadu_si128((const __m128i*)&in[0]); + const __m128i in23 = _mm_loadu_si128((const __m128i*)&in[8]); + // a00 a10 a20 a30 a01 a11 a21 a31 + // a02 a12 a22 a32 a03 a13 a23 a33 + + // Vertical pass and subsequent transpose. + { + const __m128i in1 = _mm_unpackhi_epi64(in01, in01); + const __m128i in3 = _mm_unpackhi_epi64(in23, in23); + + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3 + // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3 + const __m128i a_d3 = _mm_add_epi16(in01, in23); + const __m128i b_c3 = _mm_sub_epi16(in01, in23); + const __m128i c1d1 = _mm_mulhi_epi16(in1, k2k1); + const __m128i c2d2 = _mm_mulhi_epi16(in3, k1k2); + const __m128i c3 = _mm_unpackhi_epi64(b_c3, b_c3); + const __m128i c4 = _mm_sub_epi16(c1d1, c2d2); + const __m128i c = _mm_add_epi16(c3, c4); + const __m128i d4u = _mm_add_epi16(c1d1, c2d2); + const __m128i du = _mm_add_epi16(a_d3, d4u); + const __m128i d = _mm_unpackhi_epi64(du, du); + + // Second pass. + const __m128i comb_ab = _mm_unpacklo_epi64(a_d3, b_c3); + const __m128i comb_dc = _mm_unpacklo_epi64(d, c); + + const __m128i tmp01 = _mm_add_epi16(comb_ab, comb_dc); + const __m128i tmp32 = _mm_sub_epi16(comb_ab, comb_dc); + const __m128i tmp23 = _mm_shuffle_epi32(tmp32, _MM_SHUFFLE(1, 0, 3, 2)); + + const __m128i transpose_0 = _mm_unpacklo_epi16(tmp01, tmp23); + const __m128i transpose_1 = _mm_unpackhi_epi16(tmp01, tmp23); + // a00 a20 a01 a21 a02 a22 a03 a23 + // a10 a30 a11 a31 a12 a32 a13 a33 + + T01 = _mm_unpacklo_epi16(transpose_0, transpose_1); + T23 = _mm_unpackhi_epi16(transpose_0, transpose_1); + // a00 a10 a20 a30 a01 a11 a21 a31 + // a02 a12 a22 a32 a03 a13 a23 a33 + } + + // Horizontal pass and subsequent transpose. + { + const __m128i T1 = _mm_unpackhi_epi64(T01, T01); + const __m128i T3 = _mm_unpackhi_epi64(T23, T23); + + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i dc = _mm_add_epi16(T01, zero_four); + + // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3 + // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3 + const __m128i a_d3 = _mm_add_epi16(dc, T23); + const __m128i b_c3 = _mm_sub_epi16(dc, T23); + const __m128i c1d1 = _mm_mulhi_epi16(T1, k2k1); + const __m128i c2d2 = _mm_mulhi_epi16(T3, k1k2); + const __m128i c3 = _mm_unpackhi_epi64(b_c3, b_c3); + const __m128i c4 = _mm_sub_epi16(c1d1, c2d2); + const __m128i c = _mm_add_epi16(c3, c4); + const __m128i d4u = _mm_add_epi16(c1d1, c2d2); + const __m128i du = _mm_add_epi16(a_d3, d4u); + const __m128i d = _mm_unpackhi_epi64(du, du); + + // Second pass. + const __m128i comb_ab = _mm_unpacklo_epi64(a_d3, b_c3); + const __m128i comb_dc = _mm_unpacklo_epi64(d, c); + + const __m128i tmp01 = _mm_add_epi16(comb_ab, comb_dc); + const __m128i tmp32 = _mm_sub_epi16(comb_ab, comb_dc); + const __m128i tmp23 = _mm_shuffle_epi32(tmp32, _MM_SHUFFLE(1, 0, 3, 2)); + + const __m128i shifted01 = _mm_srai_epi16(tmp01, 3); + const __m128i shifted23 = _mm_srai_epi16(tmp23, 3); + // a00 a01 a02 a03 a10 a11 a12 a13 + // a20 a21 a22 a23 a30 a31 a32 a33 + + const __m128i transpose_0 = _mm_unpacklo_epi16(shifted01, shifted23); + const __m128i transpose_1 = _mm_unpackhi_epi16(shifted01, shifted23); + // a00 a20 a01 a21 a02 a22 a03 a23 + // a10 a30 a11 a31 a12 a32 a13 a33 + + T01 = _mm_unpacklo_epi16(transpose_0, transpose_1); + T23 = _mm_unpackhi_epi16(transpose_0, transpose_1); + // a00 a10 a20 a30 a01 a11 a21 a31 + // a02 a12 a22 a32 a03 a13 a23 a33 + } + + // Add inverse transform to 'ref' and store. + { + // Load the reference(s). + __m128i ref01, ref23, ref0123; + int32_t buf[4]; + + // Load four bytes/pixels per line. + const __m128i ref0 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[0 * BPS])); + const __m128i ref1 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[1 * BPS])); + const __m128i ref2 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[2 * BPS])); + const __m128i ref3 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[3 * BPS])); + ref01 = _mm_unpacklo_epi32(ref0, ref1); + ref23 = _mm_unpacklo_epi32(ref2, ref3); + + // Convert to 16b. + ref01 = _mm_unpacklo_epi8(ref01, zero); + ref23 = _mm_unpacklo_epi8(ref23, zero); + // Add the inverse transform(s). + ref01 = _mm_add_epi16(ref01, T01); + ref23 = _mm_add_epi16(ref23, T23); + // Unsigned saturate to 8b. + ref0123 = _mm_packus_epi16(ref01, ref23); + + _mm_storeu_si128((__m128i *)buf, ref0123); + + // Store four bytes/pixels per line. + WebPInt32ToMem(&dst[0 * BPS], buf[0]); + WebPInt32ToMem(&dst[1 * BPS], buf[1]); + WebPInt32ToMem(&dst[2 * BPS], buf[2]); + WebPInt32ToMem(&dst[3 * BPS], buf[3]); + } +} + +// Does two inverse transforms. +static void ITransform_Two_SSE2(const uint8_t* ref, const int16_t* in, + uint8_t* dst) { + // This implementation makes use of 16-bit fixed point versions of two + // multiply constants: + // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16 + // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16 + // + // To be able to use signed 16-bit integers, we use the following trick to + // have constants within range: + // - Associated constants are obtained by subtracting the 16-bit fixed point + // version of one: + // k = K - (1 << 16) => K = k + (1 << 16) + // K1 = 85267 => k1 = 20091 + // K2 = 35468 => k2 = -30068 + // - The multiplication of a variable by a constant become the sum of the + // variable and the multiplication of that variable by the associated + // constant: + // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x + const __m128i k1 = _mm_set1_epi16(20091); + const __m128i k2 = _mm_set1_epi16(-30068); + __m128i T0, T1, T2, T3; + + // Load and concatenate the transform coefficients (we'll do two inverse + // transforms in parallel). + __m128i in0, in1, in2, in3; + { + const __m128i tmp0 = _mm_loadu_si128((const __m128i*)&in[0]); + const __m128i tmp1 = _mm_loadu_si128((const __m128i*)&in[8]); + const __m128i tmp2 = _mm_loadu_si128((const __m128i*)&in[16]); + const __m128i tmp3 = _mm_loadu_si128((const __m128i*)&in[24]); + in0 = _mm_unpacklo_epi64(tmp0, tmp2); + in1 = _mm_unpackhi_epi64(tmp0, tmp2); + in2 = _mm_unpacklo_epi64(tmp1, tmp3); + in3 = _mm_unpackhi_epi64(tmp1, tmp3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + + // Vertical pass and subsequent transpose. + { + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i a = _mm_add_epi16(in0, in2); + const __m128i b = _mm_sub_epi16(in0, in2); + // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3 + const __m128i c1 = _mm_mulhi_epi16(in1, k2); + const __m128i c2 = _mm_mulhi_epi16(in3, k1); + const __m128i c3 = _mm_sub_epi16(in1, in3); + const __m128i c4 = _mm_sub_epi16(c1, c2); + const __m128i c = _mm_add_epi16(c3, c4); + // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3 + const __m128i d1 = _mm_mulhi_epi16(in1, k1); + const __m128i d2 = _mm_mulhi_epi16(in3, k2); + const __m128i d3 = _mm_add_epi16(in1, in3); + const __m128i d4 = _mm_add_epi16(d1, d2); + const __m128i d = _mm_add_epi16(d3, d4); + + // Second pass. + const __m128i tmp0 = _mm_add_epi16(a, d); + const __m128i tmp1 = _mm_add_epi16(b, c); + const __m128i tmp2 = _mm_sub_epi16(b, c); + const __m128i tmp3 = _mm_sub_epi16(a, d); + + // Transpose the two 4x4. + VP8Transpose_2_4x4_16b(&tmp0, &tmp1, &tmp2, &tmp3, &T0, &T1, &T2, &T3); + } + + // Horizontal pass and subsequent transpose. + { + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i four = _mm_set1_epi16(4); + const __m128i dc = _mm_add_epi16(T0, four); + const __m128i a = _mm_add_epi16(dc, T2); + const __m128i b = _mm_sub_epi16(dc, T2); + // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3 + const __m128i c1 = _mm_mulhi_epi16(T1, k2); + const __m128i c2 = _mm_mulhi_epi16(T3, k1); + const __m128i c3 = _mm_sub_epi16(T1, T3); + const __m128i c4 = _mm_sub_epi16(c1, c2); + const __m128i c = _mm_add_epi16(c3, c4); + // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3 + const __m128i d1 = _mm_mulhi_epi16(T1, k1); + const __m128i d2 = _mm_mulhi_epi16(T3, k2); + const __m128i d3 = _mm_add_epi16(T1, T3); + const __m128i d4 = _mm_add_epi16(d1, d2); + const __m128i d = _mm_add_epi16(d3, d4); + + // Second pass. + const __m128i tmp0 = _mm_add_epi16(a, d); + const __m128i tmp1 = _mm_add_epi16(b, c); + const __m128i tmp2 = _mm_sub_epi16(b, c); + const __m128i tmp3 = _mm_sub_epi16(a, d); + const __m128i shifted0 = _mm_srai_epi16(tmp0, 3); + const __m128i shifted1 = _mm_srai_epi16(tmp1, 3); + const __m128i shifted2 = _mm_srai_epi16(tmp2, 3); + const __m128i shifted3 = _mm_srai_epi16(tmp3, 3); + + // Transpose the two 4x4. + VP8Transpose_2_4x4_16b(&shifted0, &shifted1, &shifted2, &shifted3, &T0, &T1, + &T2, &T3); + } + + // Add inverse transform to 'ref' and store. + { + const __m128i zero = _mm_setzero_si128(); + // Load the reference(s). + __m128i ref0, ref1, ref2, ref3; + // Load eight bytes/pixels per line. + ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]); + ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]); + ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]); + ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]); + // Convert to 16b. + ref0 = _mm_unpacklo_epi8(ref0, zero); + ref1 = _mm_unpacklo_epi8(ref1, zero); + ref2 = _mm_unpacklo_epi8(ref2, zero); + ref3 = _mm_unpacklo_epi8(ref3, zero); + // Add the inverse transform(s). + ref0 = _mm_add_epi16(ref0, T0); + ref1 = _mm_add_epi16(ref1, T1); + ref2 = _mm_add_epi16(ref2, T2); + ref3 = _mm_add_epi16(ref3, T3); + // Unsigned saturate to 8b. + ref0 = _mm_packus_epi16(ref0, ref0); + ref1 = _mm_packus_epi16(ref1, ref1); + ref2 = _mm_packus_epi16(ref2, ref2); + ref3 = _mm_packus_epi16(ref3, ref3); + // Store eight bytes/pixels per line. + _mm_storel_epi64((__m128i*)&dst[0 * BPS], ref0); + _mm_storel_epi64((__m128i*)&dst[1 * BPS], ref1); + _mm_storel_epi64((__m128i*)&dst[2 * BPS], ref2); + _mm_storel_epi64((__m128i*)&dst[3 * BPS], ref3); + } +} + +// Does one or two inverse transforms. +static void ITransform_SSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst, + int do_two) { + if (do_two) { + ITransform_Two_SSE2(ref, in, dst); + } else { + ITransform_One_SSE2(ref, in, dst); + } +} + +static void FTransformPass1_SSE2(const __m128i* const in01, + const __m128i* const in23, + __m128i* const out01, + __m128i* const out32) { + const __m128i k937 = _mm_set1_epi32(937); + const __m128i k1812 = _mm_set1_epi32(1812); + + const __m128i k88p = _mm_set_epi16(8, 8, 8, 8, 8, 8, 8, 8); + const __m128i k88m = _mm_set_epi16(-8, 8, -8, 8, -8, 8, -8, 8); + const __m128i k5352_2217p = _mm_set_epi16(2217, 5352, 2217, 5352, + 2217, 5352, 2217, 5352); + const __m128i k5352_2217m = _mm_set_epi16(-5352, 2217, -5352, 2217, + -5352, 2217, -5352, 2217); + + // *in01 = 00 01 10 11 02 03 12 13 + // *in23 = 20 21 30 31 22 23 32 33 + const __m128i shuf01_p = _mm_shufflehi_epi16(*in01, _MM_SHUFFLE(2, 3, 0, 1)); + const __m128i shuf23_p = _mm_shufflehi_epi16(*in23, _MM_SHUFFLE(2, 3, 0, 1)); + // 00 01 10 11 03 02 13 12 + // 20 21 30 31 23 22 33 32 + const __m128i s01 = _mm_unpacklo_epi64(shuf01_p, shuf23_p); + const __m128i s32 = _mm_unpackhi_epi64(shuf01_p, shuf23_p); + // 00 01 10 11 20 21 30 31 + // 03 02 13 12 23 22 33 32 + const __m128i a01 = _mm_add_epi16(s01, s32); + const __m128i a32 = _mm_sub_epi16(s01, s32); + // [d0 + d3 | d1 + d2 | ...] = [a0 a1 | a0' a1' | ... ] + // [d0 - d3 | d1 - d2 | ...] = [a3 a2 | a3' a2' | ... ] + + const __m128i tmp0 = _mm_madd_epi16(a01, k88p); // [ (a0 + a1) << 3, ... ] + const __m128i tmp2 = _mm_madd_epi16(a01, k88m); // [ (a0 - a1) << 3, ... ] + const __m128i tmp1_1 = _mm_madd_epi16(a32, k5352_2217p); + const __m128i tmp3_1 = _mm_madd_epi16(a32, k5352_2217m); + const __m128i tmp1_2 = _mm_add_epi32(tmp1_1, k1812); + const __m128i tmp3_2 = _mm_add_epi32(tmp3_1, k937); + const __m128i tmp1 = _mm_srai_epi32(tmp1_2, 9); + const __m128i tmp3 = _mm_srai_epi32(tmp3_2, 9); + const __m128i s03 = _mm_packs_epi32(tmp0, tmp2); + const __m128i s12 = _mm_packs_epi32(tmp1, tmp3); + const __m128i s_lo = _mm_unpacklo_epi16(s03, s12); // 0 1 0 1 0 1... + const __m128i s_hi = _mm_unpackhi_epi16(s03, s12); // 2 3 2 3 2 3 + const __m128i v23 = _mm_unpackhi_epi32(s_lo, s_hi); + *out01 = _mm_unpacklo_epi32(s_lo, s_hi); + *out32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2)); // 3 2 3 2 3 2.. +} + +static void FTransformPass2_SSE2(const __m128i* const v01, + const __m128i* const v32, + int16_t* out) { + const __m128i zero = _mm_setzero_si128(); + const __m128i seven = _mm_set1_epi16(7); + const __m128i k5352_2217 = _mm_set_epi16(5352, 2217, 5352, 2217, + 5352, 2217, 5352, 2217); + const __m128i k2217_5352 = _mm_set_epi16(2217, -5352, 2217, -5352, + 2217, -5352, 2217, -5352); + const __m128i k12000_plus_one = _mm_set1_epi32(12000 + (1 << 16)); + const __m128i k51000 = _mm_set1_epi32(51000); + + // Same operations are done on the (0,3) and (1,2) pairs. + // a3 = v0 - v3 + // a2 = v1 - v2 + const __m128i a32 = _mm_sub_epi16(*v01, *v32); + const __m128i a22 = _mm_unpackhi_epi64(a32, a32); + + const __m128i b23 = _mm_unpacklo_epi16(a22, a32); + const __m128i c1 = _mm_madd_epi16(b23, k5352_2217); + const __m128i c3 = _mm_madd_epi16(b23, k2217_5352); + const __m128i d1 = _mm_add_epi32(c1, k12000_plus_one); + const __m128i d3 = _mm_add_epi32(c3, k51000); + const __m128i e1 = _mm_srai_epi32(d1, 16); + const __m128i e3 = _mm_srai_epi32(d3, 16); + // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16) + // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16) + const __m128i f1 = _mm_packs_epi32(e1, e1); + const __m128i f3 = _mm_packs_epi32(e3, e3); + // g1 = f1 + (a3 != 0); + // The compare will return (0xffff, 0) for (==0, !=0). To turn that into the + // desired (0, 1), we add one earlier through k12000_plus_one. + // -> g1 = f1 + 1 - (a3 == 0) + const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero)); + + // a0 = v0 + v3 + // a1 = v1 + v2 + const __m128i a01 = _mm_add_epi16(*v01, *v32); + const __m128i a01_plus_7 = _mm_add_epi16(a01, seven); + const __m128i a11 = _mm_unpackhi_epi64(a01, a01); + const __m128i c0 = _mm_add_epi16(a01_plus_7, a11); + const __m128i c2 = _mm_sub_epi16(a01_plus_7, a11); + // d0 = (a0 + a1 + 7) >> 4; + // d2 = (a0 - a1 + 7) >> 4; + const __m128i d0 = _mm_srai_epi16(c0, 4); + const __m128i d2 = _mm_srai_epi16(c2, 4); + + const __m128i d0_g1 = _mm_unpacklo_epi64(d0, g1); + const __m128i d2_f3 = _mm_unpacklo_epi64(d2, f3); + _mm_storeu_si128((__m128i*)&out[0], d0_g1); + _mm_storeu_si128((__m128i*)&out[8], d2_f3); +} + +static void FTransform_SSE2(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + const __m128i zero = _mm_setzero_si128(); + // Load src. + const __m128i src0 = _mm_loadl_epi64((const __m128i*)&src[0 * BPS]); + const __m128i src1 = _mm_loadl_epi64((const __m128i*)&src[1 * BPS]); + const __m128i src2 = _mm_loadl_epi64((const __m128i*)&src[2 * BPS]); + const __m128i src3 = _mm_loadl_epi64((const __m128i*)&src[3 * BPS]); + // 00 01 02 03 * + // 10 11 12 13 * + // 20 21 22 23 * + // 30 31 32 33 * + // Shuffle. + const __m128i src_0 = _mm_unpacklo_epi16(src0, src1); + const __m128i src_1 = _mm_unpacklo_epi16(src2, src3); + // 00 01 10 11 02 03 12 13 * * ... + // 20 21 30 31 22 22 32 33 * * ... + + // Load ref. + const __m128i ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]); + const __m128i ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]); + const __m128i ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]); + const __m128i ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]); + const __m128i ref_0 = _mm_unpacklo_epi16(ref0, ref1); + const __m128i ref_1 = _mm_unpacklo_epi16(ref2, ref3); + + // Convert both to 16 bit. + const __m128i src_0_16b = _mm_unpacklo_epi8(src_0, zero); + const __m128i src_1_16b = _mm_unpacklo_epi8(src_1, zero); + const __m128i ref_0_16b = _mm_unpacklo_epi8(ref_0, zero); + const __m128i ref_1_16b = _mm_unpacklo_epi8(ref_1, zero); + + // Compute the difference. + const __m128i row01 = _mm_sub_epi16(src_0_16b, ref_0_16b); + const __m128i row23 = _mm_sub_epi16(src_1_16b, ref_1_16b); + __m128i v01, v32; + + // First pass + FTransformPass1_SSE2(&row01, &row23, &v01, &v32); + + // Second pass + FTransformPass2_SSE2(&v01, &v32, out); +} + +static void FTransform2_SSE2(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + const __m128i zero = _mm_setzero_si128(); + + // Load src and convert to 16b. + const __m128i src0 = _mm_loadl_epi64((const __m128i*)&src[0 * BPS]); + const __m128i src1 = _mm_loadl_epi64((const __m128i*)&src[1 * BPS]); + const __m128i src2 = _mm_loadl_epi64((const __m128i*)&src[2 * BPS]); + const __m128i src3 = _mm_loadl_epi64((const __m128i*)&src[3 * BPS]); + const __m128i src_0 = _mm_unpacklo_epi8(src0, zero); + const __m128i src_1 = _mm_unpacklo_epi8(src1, zero); + const __m128i src_2 = _mm_unpacklo_epi8(src2, zero); + const __m128i src_3 = _mm_unpacklo_epi8(src3, zero); + // Load ref and convert to 16b. + const __m128i ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]); + const __m128i ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]); + const __m128i ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]); + const __m128i ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]); + const __m128i ref_0 = _mm_unpacklo_epi8(ref0, zero); + const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero); + const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero); + const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero); + // Compute difference. -> 00 01 02 03 00' 01' 02' 03' + const __m128i diff0 = _mm_sub_epi16(src_0, ref_0); + const __m128i diff1 = _mm_sub_epi16(src_1, ref_1); + const __m128i diff2 = _mm_sub_epi16(src_2, ref_2); + const __m128i diff3 = _mm_sub_epi16(src_3, ref_3); + + // Unpack and shuffle + // 00 01 02 03 0 0 0 0 + // 10 11 12 13 0 0 0 0 + // 20 21 22 23 0 0 0 0 + // 30 31 32 33 0 0 0 0 + const __m128i shuf01l = _mm_unpacklo_epi32(diff0, diff1); + const __m128i shuf23l = _mm_unpacklo_epi32(diff2, diff3); + const __m128i shuf01h = _mm_unpackhi_epi32(diff0, diff1); + const __m128i shuf23h = _mm_unpackhi_epi32(diff2, diff3); + __m128i v01l, v32l; + __m128i v01h, v32h; + + // First pass + FTransformPass1_SSE2(&shuf01l, &shuf23l, &v01l, &v32l); + FTransformPass1_SSE2(&shuf01h, &shuf23h, &v01h, &v32h); + + // Second pass + FTransformPass2_SSE2(&v01l, &v32l, out + 0); + FTransformPass2_SSE2(&v01h, &v32h, out + 16); +} + +static void FTransformWHTRow_SSE2(const int16_t* const in, __m128i* const out) { + const __m128i kMult = _mm_set_epi16(-1, 1, -1, 1, 1, 1, 1, 1); + const __m128i src0 = _mm_loadl_epi64((__m128i*)&in[0 * 16]); + const __m128i src1 = _mm_loadl_epi64((__m128i*)&in[1 * 16]); + const __m128i src2 = _mm_loadl_epi64((__m128i*)&in[2 * 16]); + const __m128i src3 = _mm_loadl_epi64((__m128i*)&in[3 * 16]); + const __m128i A01 = _mm_unpacklo_epi16(src0, src1); // A0 A1 | ... + const __m128i A23 = _mm_unpacklo_epi16(src2, src3); // A2 A3 | ... + const __m128i B0 = _mm_adds_epi16(A01, A23); // a0 | a1 | ... + const __m128i B1 = _mm_subs_epi16(A01, A23); // a3 | a2 | ... + const __m128i C0 = _mm_unpacklo_epi32(B0, B1); // a0 | a1 | a3 | a2 | ... + const __m128i C1 = _mm_unpacklo_epi32(B1, B0); // a3 | a2 | a0 | a1 | ... + const __m128i D = _mm_unpacklo_epi64(C0, C1); // a0 a1 a3 a2 a3 a2 a0 a1 + *out = _mm_madd_epi16(D, kMult); +} + +static void FTransformWHT_SSE2(const int16_t* in, int16_t* out) { + // Input is 12b signed. + __m128i row0, row1, row2, row3; + // Rows are 14b signed. + FTransformWHTRow_SSE2(in + 0 * 64, &row0); + FTransformWHTRow_SSE2(in + 1 * 64, &row1); + FTransformWHTRow_SSE2(in + 2 * 64, &row2); + FTransformWHTRow_SSE2(in + 3 * 64, &row3); + + { + // The a* are 15b signed. + const __m128i a0 = _mm_add_epi32(row0, row2); + const __m128i a1 = _mm_add_epi32(row1, row3); + const __m128i a2 = _mm_sub_epi32(row1, row3); + const __m128i a3 = _mm_sub_epi32(row0, row2); + const __m128i a0a3 = _mm_packs_epi32(a0, a3); + const __m128i a1a2 = _mm_packs_epi32(a1, a2); + + // The b* are 16b signed. + const __m128i b0b1 = _mm_add_epi16(a0a3, a1a2); + const __m128i b3b2 = _mm_sub_epi16(a0a3, a1a2); + const __m128i tmp_b2b3 = _mm_unpackhi_epi64(b3b2, b3b2); + const __m128i b2b3 = _mm_unpacklo_epi64(tmp_b2b3, b3b2); + + _mm_storeu_si128((__m128i*)&out[0], _mm_srai_epi16(b0b1, 1)); + _mm_storeu_si128((__m128i*)&out[8], _mm_srai_epi16(b2b3, 1)); + } +} + +//------------------------------------------------------------------------------ +// Compute susceptibility based on DCT-coeff histograms: +// the higher, the "easier" the macroblock is to compress. + +static void CollectHistogram_SSE2(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block, + VP8Histogram* const histo) { + const __m128i zero = _mm_setzero_si128(); + const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH); + int j; + int distribution[MAX_COEFF_THRESH + 1] = { 0 }; + for (j = start_block; j < end_block; ++j) { + int16_t out[16]; + int k; + + FTransform_SSE2(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + + // Convert coefficients to bin (within out[]). + { + // Load. + const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]); + const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]); + const __m128i d0 = _mm_sub_epi16(zero, out0); + const __m128i d1 = _mm_sub_epi16(zero, out1); + const __m128i abs0 = _mm_max_epi16(out0, d0); // abs(v), 16b + const __m128i abs1 = _mm_max_epi16(out1, d1); + // v = abs(out) >> 3 + const __m128i v0 = _mm_srai_epi16(abs0, 3); + const __m128i v1 = _mm_srai_epi16(abs1, 3); + // bin = min(v, MAX_COEFF_THRESH) + const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh); + const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh); + // Store. + _mm_storeu_si128((__m128i*)&out[0], bin0); + _mm_storeu_si128((__m128i*)&out[8], bin1); + } + + // Convert coefficients to bin. + for (k = 0; k < 16; ++k) { + ++distribution[out[k]]; + } + } + VP8SetHistogramData(distribution, histo); +} + +//------------------------------------------------------------------------------ +// Intra predictions + +// helper for chroma-DC predictions +static WEBP_INLINE void Put8x8uv_SSE2(uint8_t v, uint8_t* dst) { + int j; + const __m128i values = _mm_set1_epi8((char)v); + for (j = 0; j < 8; ++j) { + _mm_storel_epi64((__m128i*)(dst + j * BPS), values); + } +} + +static WEBP_INLINE void Put16_SSE2(uint8_t v, uint8_t* dst) { + int j; + const __m128i values = _mm_set1_epi8((char)v); + for (j = 0; j < 16; ++j) { + _mm_store_si128((__m128i*)(dst + j * BPS), values); + } +} + +static WEBP_INLINE void Fill_SSE2(uint8_t* dst, int value, int size) { + if (size == 4) { + int j; + for (j = 0; j < 4; ++j) { + memset(dst + j * BPS, value, 4); + } + } else if (size == 8) { + Put8x8uv_SSE2(value, dst); + } else { + Put16_SSE2(value, dst); + } +} + +static WEBP_INLINE void VE8uv_SSE2(uint8_t* dst, const uint8_t* top) { + int j; + const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); + for (j = 0; j < 8; ++j) { + _mm_storel_epi64((__m128i*)(dst + j * BPS), top_values); + } +} + +static WEBP_INLINE void VE16_SSE2(uint8_t* dst, const uint8_t* top) { + const __m128i top_values = _mm_load_si128((const __m128i*)top); + int j; + for (j = 0; j < 16; ++j) { + _mm_store_si128((__m128i*)(dst + j * BPS), top_values); + } +} + +static WEBP_INLINE void VerticalPred_SSE2(uint8_t* dst, + const uint8_t* top, int size) { + if (top != NULL) { + if (size == 8) { + VE8uv_SSE2(dst, top); + } else { + VE16_SSE2(dst, top); + } + } else { + Fill_SSE2(dst, 127, size); + } +} + +static WEBP_INLINE void HE8uv_SSE2(uint8_t* dst, const uint8_t* left) { + int j; + for (j = 0; j < 8; ++j) { + const __m128i values = _mm_set1_epi8((char)left[j]); + _mm_storel_epi64((__m128i*)dst, values); + dst += BPS; + } +} + +static WEBP_INLINE void HE16_SSE2(uint8_t* dst, const uint8_t* left) { + int j; + for (j = 0; j < 16; ++j) { + const __m128i values = _mm_set1_epi8((char)left[j]); + _mm_store_si128((__m128i*)dst, values); + dst += BPS; + } +} + +static WEBP_INLINE void HorizontalPred_SSE2(uint8_t* dst, + const uint8_t* left, int size) { + if (left != NULL) { + if (size == 8) { + HE8uv_SSE2(dst, left); + } else { + HE16_SSE2(dst, left); + } + } else { + Fill_SSE2(dst, 129, size); + } +} + +static WEBP_INLINE void TM_SSE2(uint8_t* dst, const uint8_t* left, + const uint8_t* top, int size) { + const __m128i zero = _mm_setzero_si128(); + int y; + if (size == 8) { + const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); + const __m128i top_base = _mm_unpacklo_epi8(top_values, zero); + for (y = 0; y < 8; ++y, dst += BPS) { + const int val = left[y] - left[-1]; + const __m128i base = _mm_set1_epi16(val); + const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero); + _mm_storel_epi64((__m128i*)dst, out); + } + } else { + const __m128i top_values = _mm_load_si128((const __m128i*)top); + const __m128i top_base_0 = _mm_unpacklo_epi8(top_values, zero); + const __m128i top_base_1 = _mm_unpackhi_epi8(top_values, zero); + for (y = 0; y < 16; ++y, dst += BPS) { + const int val = left[y] - left[-1]; + const __m128i base = _mm_set1_epi16(val); + const __m128i out_0 = _mm_add_epi16(base, top_base_0); + const __m128i out_1 = _mm_add_epi16(base, top_base_1); + const __m128i out = _mm_packus_epi16(out_0, out_1); + _mm_store_si128((__m128i*)dst, out); + } + } +} + +static WEBP_INLINE void TrueMotion_SSE2(uint8_t* dst, const uint8_t* left, + const uint8_t* top, int size) { + if (left != NULL) { + if (top != NULL) { + TM_SSE2(dst, left, top, size); + } else { + HorizontalPred_SSE2(dst, left, size); + } + } else { + // true motion without left samples (hence: with default 129 value) + // is equivalent to VE prediction where you just copy the top samples. + // Note that if top samples are not available, the default value is + // then 129, and not 127 as in the VerticalPred case. + if (top != NULL) { + VerticalPred_SSE2(dst, top, size); + } else { + Fill_SSE2(dst, 129, size); + } + } +} + +static WEBP_INLINE void DC8uv_SSE2(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); + const __m128i left_values = _mm_loadl_epi64((const __m128i*)left); + const __m128i combined = _mm_unpacklo_epi64(top_values, left_values); + const int DC = VP8HorizontalAdd8b(&combined) + 8; + Put8x8uv_SSE2(DC >> 4, dst); +} + +static WEBP_INLINE void DC8uvNoLeft_SSE2(uint8_t* dst, const uint8_t* top) { + const __m128i zero = _mm_setzero_si128(); + const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); + const __m128i sum = _mm_sad_epu8(top_values, zero); + const int DC = _mm_cvtsi128_si32(sum) + 4; + Put8x8uv_SSE2(DC >> 3, dst); +} + +static WEBP_INLINE void DC8uvNoTop_SSE2(uint8_t* dst, const uint8_t* left) { + // 'left' is contiguous so we can reuse the top summation. + DC8uvNoLeft_SSE2(dst, left); +} + +static WEBP_INLINE void DC8uvNoTopLeft_SSE2(uint8_t* dst) { + Put8x8uv_SSE2(0x80, dst); +} + +static WEBP_INLINE void DC8uvMode_SSE2(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + if (top != NULL) { + if (left != NULL) { // top and left present + DC8uv_SSE2(dst, left, top); + } else { // top, but no left + DC8uvNoLeft_SSE2(dst, top); + } + } else if (left != NULL) { // left but no top + DC8uvNoTop_SSE2(dst, left); + } else { // no top, no left, nothing. + DC8uvNoTopLeft_SSE2(dst); + } +} + +static WEBP_INLINE void DC16_SSE2(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + const __m128i top_row = _mm_load_si128((const __m128i*)top); + const __m128i left_row = _mm_load_si128((const __m128i*)left); + const int DC = + VP8HorizontalAdd8b(&top_row) + VP8HorizontalAdd8b(&left_row) + 16; + Put16_SSE2(DC >> 5, dst); +} + +static WEBP_INLINE void DC16NoLeft_SSE2(uint8_t* dst, const uint8_t* top) { + const __m128i top_row = _mm_load_si128((const __m128i*)top); + const int DC = VP8HorizontalAdd8b(&top_row) + 8; + Put16_SSE2(DC >> 4, dst); +} + +static WEBP_INLINE void DC16NoTop_SSE2(uint8_t* dst, const uint8_t* left) { + // 'left' is contiguous so we can reuse the top summation. + DC16NoLeft_SSE2(dst, left); +} + +static WEBP_INLINE void DC16NoTopLeft_SSE2(uint8_t* dst) { + Put16_SSE2(0x80, dst); +} + +static WEBP_INLINE void DC16Mode_SSE2(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + if (top != NULL) { + if (left != NULL) { // top and left present + DC16_SSE2(dst, left, top); + } else { // top, but no left + DC16NoLeft_SSE2(dst, top); + } + } else if (left != NULL) { // left but no top + DC16NoTop_SSE2(dst, left); + } else { // no top, no left, nothing. + DC16NoTopLeft_SSE2(dst); + } +} + +//------------------------------------------------------------------------------ +// 4x4 predictions + +#define DST(x, y) dst[(x) + (y) * BPS] +#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) +#define AVG2(a, b) (((a) + (b) + 1) >> 1) + +// We use the following 8b-arithmetic tricks: +// (a + 2 * b + c + 2) >> 2 = (AC + b + 1) >> 1 +// where: AC = (a + c) >> 1 = [(a + c + 1) >> 1] - [(a^c) & 1] +// and: +// (a + 2 * b + c + 2) >> 2 = (AB + BC + 1) >> 1 - (ab|bc)&lsb +// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1 +// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1 + +static WEBP_INLINE void VE4_SSE2(uint8_t* dst, + const uint8_t* top) { // vertical + const __m128i one = _mm_set1_epi8(1); + const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(top - 1)); + const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1); + const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2); + const __m128i a = _mm_avg_epu8(ABCDEFGH, CDEFGH00); + const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGH00), one); + const __m128i b = _mm_subs_epu8(a, lsb); + const __m128i avg = _mm_avg_epu8(b, BCDEFGH0); + const int vals = _mm_cvtsi128_si32(avg); + int i; + for (i = 0; i < 4; ++i) { + WebPInt32ToMem(dst + i * BPS, vals); + } +} + +static WEBP_INLINE void HE4_SSE2(uint8_t* dst, + const uint8_t* top) { // horizontal + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + WebPUint32ToMem(dst + 0 * BPS, 0x01010101U * AVG3(X, I, J)); + WebPUint32ToMem(dst + 1 * BPS, 0x01010101U * AVG3(I, J, K)); + WebPUint32ToMem(dst + 2 * BPS, 0x01010101U * AVG3(J, K, L)); + WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(K, L, L)); +} + +static WEBP_INLINE void DC4_SSE2(uint8_t* dst, const uint8_t* top) { + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i]; + Fill_SSE2(dst, dc >> 3, 4); +} + +static WEBP_INLINE void LD4_SSE2(uint8_t* dst, + const uint8_t* top) { // Down-Left + const __m128i one = _mm_set1_epi8(1); + const __m128i ABCDEFGH = _mm_loadl_epi64((const __m128i*)top); + const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1); + const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2); + const __m128i CDEFGHH0 = _mm_insert_epi16(CDEFGH00, top[7], 3); + const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, CDEFGHH0); + const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGHH0), one); + const __m128i avg2 = _mm_subs_epu8(avg1, lsb); + const __m128i abcdefg = _mm_avg_epu8(avg2, BCDEFGH0); + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcdefg )); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1))); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2))); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3))); +} + +static WEBP_INLINE void VR4_SSE2(uint8_t* dst, + const uint8_t* top) { // Vertical-Right + const __m128i one = _mm_set1_epi8(1); + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int X = top[-1]; + const __m128i XABCD = _mm_loadl_epi64((const __m128i*)(top - 1)); + const __m128i ABCD0 = _mm_srli_si128(XABCD, 1); + const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0); + const __m128i _XABCD = _mm_slli_si128(XABCD, 1); + const __m128i IXABCD = _mm_insert_epi16(_XABCD, (short)(I | (X << 8)), 0); + const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0); + const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one); + const __m128i avg2 = _mm_subs_epu8(avg1, lsb); + const __m128i efgh = _mm_avg_epu8(avg2, XABCD); + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcd )); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( efgh )); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1))); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1))); + + // these two are hard to implement in SSE2, so we keep the C-version: + DST(0, 2) = AVG3(J, I, X); + DST(0, 3) = AVG3(K, J, I); +} + +static WEBP_INLINE void VL4_SSE2(uint8_t* dst, + const uint8_t* top) { // Vertical-Left + const __m128i one = _mm_set1_epi8(1); + const __m128i ABCDEFGH = _mm_loadl_epi64((const __m128i*)top); + const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1); + const __m128i CDEFGH__ = _mm_srli_si128(ABCDEFGH, 2); + const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, BCDEFGH_); + const __m128i avg2 = _mm_avg_epu8(CDEFGH__, BCDEFGH_); + const __m128i avg3 = _mm_avg_epu8(avg1, avg2); + const __m128i lsb1 = _mm_and_si128(_mm_xor_si128(avg1, avg2), one); + const __m128i ab = _mm_xor_si128(ABCDEFGH, BCDEFGH_); + const __m128i bc = _mm_xor_si128(CDEFGH__, BCDEFGH_); + const __m128i abbc = _mm_or_si128(ab, bc); + const __m128i lsb2 = _mm_and_si128(abbc, lsb1); + const __m128i avg4 = _mm_subs_epu8(avg3, lsb2); + const uint32_t extra_out = + (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(avg4, 4)); + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( avg1 )); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( avg4 )); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1))); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1))); + + // these two are hard to get and irregular + DST(3, 2) = (extra_out >> 0) & 0xff; + DST(3, 3) = (extra_out >> 8) & 0xff; +} + +static WEBP_INLINE void RD4_SSE2(uint8_t* dst, + const uint8_t* top) { // Down-right + const __m128i one = _mm_set1_epi8(1); + const __m128i LKJIXABC = _mm_loadl_epi64((const __m128i*)(top - 5)); + const __m128i LKJIXABCD = _mm_insert_epi16(LKJIXABC, top[3], 4); + const __m128i KJIXABCD_ = _mm_srli_si128(LKJIXABCD, 1); + const __m128i JIXABCD__ = _mm_srli_si128(LKJIXABCD, 2); + const __m128i avg1 = _mm_avg_epu8(JIXABCD__, LKJIXABCD); + const __m128i lsb = _mm_and_si128(_mm_xor_si128(JIXABCD__, LKJIXABCD), one); + const __m128i avg2 = _mm_subs_epu8(avg1, lsb); + const __m128i abcdefg = _mm_avg_epu8(avg2, KJIXABCD_); + WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32( abcdefg )); + WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1))); + WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2))); + WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3))); +} + +static WEBP_INLINE void HU4_SSE2(uint8_t* dst, const uint8_t* top) { + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + DST(0, 0) = AVG2(I, J); + DST(2, 0) = DST(0, 1) = AVG2(J, K); + DST(2, 1) = DST(0, 2) = AVG2(K, L); + DST(1, 0) = AVG3(I, J, K); + DST(3, 0) = DST(1, 1) = AVG3(J, K, L); + DST(3, 1) = DST(1, 2) = AVG3(K, L, L); + DST(3, 2) = DST(2, 2) = + DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; +} + +static WEBP_INLINE void HD4_SSE2(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + + DST(0, 0) = DST(2, 1) = AVG2(I, X); + DST(0, 1) = DST(2, 2) = AVG2(J, I); + DST(0, 2) = DST(2, 3) = AVG2(K, J); + DST(0, 3) = AVG2(L, K); + + DST(3, 0) = AVG3(A, B, C); + DST(2, 0) = AVG3(X, A, B); + DST(1, 0) = DST(3, 1) = AVG3(I, X, A); + DST(1, 1) = DST(3, 2) = AVG3(J, I, X); + DST(1, 2) = DST(3, 3) = AVG3(K, J, I); + DST(1, 3) = AVG3(L, K, J); +} + +static WEBP_INLINE void TM4_SSE2(uint8_t* dst, const uint8_t* top) { + const __m128i zero = _mm_setzero_si128(); + const __m128i top_values = _mm_cvtsi32_si128(WebPMemToInt32(top)); + const __m128i top_base = _mm_unpacklo_epi8(top_values, zero); + int y; + for (y = 0; y < 4; ++y, dst += BPS) { + const int val = top[-2 - y] - top[-1]; + const __m128i base = _mm_set1_epi16(val); + const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero); + WebPInt32ToMem(dst, _mm_cvtsi128_si32(out)); + } +} + +#undef DST +#undef AVG3 +#undef AVG2 + +//------------------------------------------------------------------------------ +// luma 4x4 prediction + +// Left samples are top[-5 .. -2], top_left is top[-1], top are +// located at top[0..3], and top right is top[4..7] +static void Intra4Preds_SSE2(uint8_t* dst, const uint8_t* top) { + DC4_SSE2(I4DC4 + dst, top); + TM4_SSE2(I4TM4 + dst, top); + VE4_SSE2(I4VE4 + dst, top); + HE4_SSE2(I4HE4 + dst, top); + RD4_SSE2(I4RD4 + dst, top); + VR4_SSE2(I4VR4 + dst, top); + LD4_SSE2(I4LD4 + dst, top); + VL4_SSE2(I4VL4 + dst, top); + HD4_SSE2(I4HD4 + dst, top); + HU4_SSE2(I4HU4 + dst, top); +} + +//------------------------------------------------------------------------------ +// Chroma 8x8 prediction (paragraph 12.2) + +static void IntraChromaPreds_SSE2(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + // U block + DC8uvMode_SSE2(C8DC8 + dst, left, top); + VerticalPred_SSE2(C8VE8 + dst, top, 8); + HorizontalPred_SSE2(C8HE8 + dst, left, 8); + TrueMotion_SSE2(C8TM8 + dst, left, top, 8); + // V block + dst += 8; + if (top != NULL) top += 8; + if (left != NULL) left += 16; + DC8uvMode_SSE2(C8DC8 + dst, left, top); + VerticalPred_SSE2(C8VE8 + dst, top, 8); + HorizontalPred_SSE2(C8HE8 + dst, left, 8); + TrueMotion_SSE2(C8TM8 + dst, left, top, 8); +} + +//------------------------------------------------------------------------------ +// luma 16x16 prediction (paragraph 12.3) + +static void Intra16Preds_SSE2(uint8_t* dst, + const uint8_t* left, const uint8_t* top) { + DC16Mode_SSE2(I16DC16 + dst, left, top); + VerticalPred_SSE2(I16VE16 + dst, top, 16); + HorizontalPred_SSE2(I16HE16 + dst, left, 16); + TrueMotion_SSE2(I16TM16 + dst, left, top, 16); +} + +//------------------------------------------------------------------------------ +// Metric + +static WEBP_INLINE void SubtractAndAccumulate_SSE2(const __m128i a, + const __m128i b, + __m128i* const sum) { + // take abs(a-b) in 8b + const __m128i a_b = _mm_subs_epu8(a, b); + const __m128i b_a = _mm_subs_epu8(b, a); + const __m128i abs_a_b = _mm_or_si128(a_b, b_a); + // zero-extend to 16b + const __m128i zero = _mm_setzero_si128(); + const __m128i C0 = _mm_unpacklo_epi8(abs_a_b, zero); + const __m128i C1 = _mm_unpackhi_epi8(abs_a_b, zero); + // multiply with self + const __m128i sum1 = _mm_madd_epi16(C0, C0); + const __m128i sum2 = _mm_madd_epi16(C1, C1); + *sum = _mm_add_epi32(sum1, sum2); +} + +static WEBP_INLINE int SSE_16xN_SSE2(const uint8_t* a, const uint8_t* b, + int num_pairs) { + __m128i sum = _mm_setzero_si128(); + int32_t tmp[4]; + int i; + + for (i = 0; i < num_pairs; ++i) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[BPS * 0]); + const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[BPS * 0]); + const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[BPS * 1]); + const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[BPS * 1]); + __m128i sum1, sum2; + SubtractAndAccumulate_SSE2(a0, b0, &sum1); + SubtractAndAccumulate_SSE2(a1, b1, &sum2); + sum = _mm_add_epi32(sum, _mm_add_epi32(sum1, sum2)); + a += 2 * BPS; + b += 2 * BPS; + } + _mm_storeu_si128((__m128i*)tmp, sum); + return (tmp[3] + tmp[2] + tmp[1] + tmp[0]); +} + +static int SSE16x16_SSE2(const uint8_t* a, const uint8_t* b) { + return SSE_16xN_SSE2(a, b, 8); +} + +static int SSE16x8_SSE2(const uint8_t* a, const uint8_t* b) { + return SSE_16xN_SSE2(a, b, 4); +} + +#define LOAD_8x16b(ptr) \ + _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(ptr)), zero) + +static int SSE8x8_SSE2(const uint8_t* a, const uint8_t* b) { + const __m128i zero = _mm_setzero_si128(); + int num_pairs = 4; + __m128i sum = zero; + int32_t tmp[4]; + while (num_pairs-- > 0) { + const __m128i a0 = LOAD_8x16b(&a[BPS * 0]); + const __m128i a1 = LOAD_8x16b(&a[BPS * 1]); + const __m128i b0 = LOAD_8x16b(&b[BPS * 0]); + const __m128i b1 = LOAD_8x16b(&b[BPS * 1]); + // subtract + const __m128i c0 = _mm_subs_epi16(a0, b0); + const __m128i c1 = _mm_subs_epi16(a1, b1); + // multiply/accumulate with self + const __m128i d0 = _mm_madd_epi16(c0, c0); + const __m128i d1 = _mm_madd_epi16(c1, c1); + // collect + const __m128i sum01 = _mm_add_epi32(d0, d1); + sum = _mm_add_epi32(sum, sum01); + a += 2 * BPS; + b += 2 * BPS; + } + _mm_storeu_si128((__m128i*)tmp, sum); + return (tmp[3] + tmp[2] + tmp[1] + tmp[0]); +} +#undef LOAD_8x16b + +static int SSE4x4_SSE2(const uint8_t* a, const uint8_t* b) { + const __m128i zero = _mm_setzero_si128(); + + // Load values. Note that we read 8 pixels instead of 4, + // but the a/b buffers are over-allocated to that effect. + const __m128i a0 = _mm_loadl_epi64((const __m128i*)&a[BPS * 0]); + const __m128i a1 = _mm_loadl_epi64((const __m128i*)&a[BPS * 1]); + const __m128i a2 = _mm_loadl_epi64((const __m128i*)&a[BPS * 2]); + const __m128i a3 = _mm_loadl_epi64((const __m128i*)&a[BPS * 3]); + const __m128i b0 = _mm_loadl_epi64((const __m128i*)&b[BPS * 0]); + const __m128i b1 = _mm_loadl_epi64((const __m128i*)&b[BPS * 1]); + const __m128i b2 = _mm_loadl_epi64((const __m128i*)&b[BPS * 2]); + const __m128i b3 = _mm_loadl_epi64((const __m128i*)&b[BPS * 3]); + // Combine pair of lines. + const __m128i a01 = _mm_unpacklo_epi32(a0, a1); + const __m128i a23 = _mm_unpacklo_epi32(a2, a3); + const __m128i b01 = _mm_unpacklo_epi32(b0, b1); + const __m128i b23 = _mm_unpacklo_epi32(b2, b3); + // Convert to 16b. + const __m128i a01s = _mm_unpacklo_epi8(a01, zero); + const __m128i a23s = _mm_unpacklo_epi8(a23, zero); + const __m128i b01s = _mm_unpacklo_epi8(b01, zero); + const __m128i b23s = _mm_unpacklo_epi8(b23, zero); + // subtract, square and accumulate + const __m128i d0 = _mm_subs_epi16(a01s, b01s); + const __m128i d1 = _mm_subs_epi16(a23s, b23s); + const __m128i e0 = _mm_madd_epi16(d0, d0); + const __m128i e1 = _mm_madd_epi16(d1, d1); + const __m128i sum = _mm_add_epi32(e0, e1); + + int32_t tmp[4]; + _mm_storeu_si128((__m128i*)tmp, sum); + return (tmp[3] + tmp[2] + tmp[1] + tmp[0]); +} + +//------------------------------------------------------------------------------ + +static void Mean16x4_SSE2(const uint8_t* ref, uint32_t dc[4]) { + const __m128i mask = _mm_set1_epi16(0x00ff); + const __m128i a0 = _mm_loadu_si128((const __m128i*)&ref[BPS * 0]); + const __m128i a1 = _mm_loadu_si128((const __m128i*)&ref[BPS * 1]); + const __m128i a2 = _mm_loadu_si128((const __m128i*)&ref[BPS * 2]); + const __m128i a3 = _mm_loadu_si128((const __m128i*)&ref[BPS * 3]); + const __m128i b0 = _mm_srli_epi16(a0, 8); // hi byte + const __m128i b1 = _mm_srli_epi16(a1, 8); + const __m128i b2 = _mm_srli_epi16(a2, 8); + const __m128i b3 = _mm_srli_epi16(a3, 8); + const __m128i c0 = _mm_and_si128(a0, mask); // lo byte + const __m128i c1 = _mm_and_si128(a1, mask); + const __m128i c2 = _mm_and_si128(a2, mask); + const __m128i c3 = _mm_and_si128(a3, mask); + const __m128i d0 = _mm_add_epi32(b0, c0); + const __m128i d1 = _mm_add_epi32(b1, c1); + const __m128i d2 = _mm_add_epi32(b2, c2); + const __m128i d3 = _mm_add_epi32(b3, c3); + const __m128i e0 = _mm_add_epi32(d0, d1); + const __m128i e1 = _mm_add_epi32(d2, d3); + const __m128i f0 = _mm_add_epi32(e0, e1); + uint16_t tmp[8]; + _mm_storeu_si128((__m128i*)tmp, f0); + dc[0] = tmp[0] + tmp[1]; + dc[1] = tmp[2] + tmp[3]; + dc[2] = tmp[4] + tmp[5]; + dc[3] = tmp[6] + tmp[7]; +} + +//------------------------------------------------------------------------------ +// Texture distortion +// +// We try to match the spectral content (weighted) between source and +// reconstructed samples. + +// Hadamard transform +// Returns the weighted sum of the absolute value of transformed coefficients. +// w[] contains a row-major 4 by 4 symmetric matrix. +static int TTransform_SSE2(const uint8_t* inA, const uint8_t* inB, + const uint16_t* const w) { + int32_t sum[4]; + __m128i tmp_0, tmp_1, tmp_2, tmp_3; + const __m128i zero = _mm_setzero_si128(); + + // Load and combine inputs. + { + const __m128i inA_0 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 0]); + const __m128i inA_1 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 1]); + const __m128i inA_2 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 2]); + const __m128i inA_3 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 3]); + const __m128i inB_0 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 0]); + const __m128i inB_1 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 1]); + const __m128i inB_2 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 2]); + const __m128i inB_3 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 3]); + + // Combine inA and inB (we'll do two transforms in parallel). + const __m128i inAB_0 = _mm_unpacklo_epi32(inA_0, inB_0); + const __m128i inAB_1 = _mm_unpacklo_epi32(inA_1, inB_1); + const __m128i inAB_2 = _mm_unpacklo_epi32(inA_2, inB_2); + const __m128i inAB_3 = _mm_unpacklo_epi32(inA_3, inB_3); + tmp_0 = _mm_unpacklo_epi8(inAB_0, zero); + tmp_1 = _mm_unpacklo_epi8(inAB_1, zero); + tmp_2 = _mm_unpacklo_epi8(inAB_2, zero); + tmp_3 = _mm_unpacklo_epi8(inAB_3, zero); + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + } + + // Vertical pass first to avoid a transpose (vertical and horizontal passes + // are commutative because w/kWeightY is symmetric) and subsequent transpose. + { + // Calculate a and b (two 4x4 at once). + const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); + const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); + const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); + const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); + const __m128i b0 = _mm_add_epi16(a0, a1); + const __m128i b1 = _mm_add_epi16(a3, a2); + const __m128i b2 = _mm_sub_epi16(a3, a2); + const __m128i b3 = _mm_sub_epi16(a0, a1); + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + + // Transpose the two 4x4. + VP8Transpose_2_4x4_16b(&b0, &b1, &b2, &b3, &tmp_0, &tmp_1, &tmp_2, &tmp_3); + } + + // Horizontal pass and difference of weighted sums. + { + // Load all inputs. + const __m128i w_0 = _mm_loadu_si128((const __m128i*)&w[0]); + const __m128i w_8 = _mm_loadu_si128((const __m128i*)&w[8]); + + // Calculate a and b (two 4x4 at once). + const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); + const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); + const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); + const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); + const __m128i b0 = _mm_add_epi16(a0, a1); + const __m128i b1 = _mm_add_epi16(a3, a2); + const __m128i b2 = _mm_sub_epi16(a3, a2); + const __m128i b3 = _mm_sub_epi16(a0, a1); + + // Separate the transforms of inA and inB. + __m128i A_b0 = _mm_unpacklo_epi64(b0, b1); + __m128i A_b2 = _mm_unpacklo_epi64(b2, b3); + __m128i B_b0 = _mm_unpackhi_epi64(b0, b1); + __m128i B_b2 = _mm_unpackhi_epi64(b2, b3); + + { + const __m128i d0 = _mm_sub_epi16(zero, A_b0); + const __m128i d1 = _mm_sub_epi16(zero, A_b2); + const __m128i d2 = _mm_sub_epi16(zero, B_b0); + const __m128i d3 = _mm_sub_epi16(zero, B_b2); + A_b0 = _mm_max_epi16(A_b0, d0); // abs(v), 16b + A_b2 = _mm_max_epi16(A_b2, d1); + B_b0 = _mm_max_epi16(B_b0, d2); + B_b2 = _mm_max_epi16(B_b2, d3); + } + + // weighted sums + A_b0 = _mm_madd_epi16(A_b0, w_0); + A_b2 = _mm_madd_epi16(A_b2, w_8); + B_b0 = _mm_madd_epi16(B_b0, w_0); + B_b2 = _mm_madd_epi16(B_b2, w_8); + A_b0 = _mm_add_epi32(A_b0, A_b2); + B_b0 = _mm_add_epi32(B_b0, B_b2); + + // difference of weighted sums + A_b0 = _mm_sub_epi32(A_b0, B_b0); + _mm_storeu_si128((__m128i*)&sum[0], A_b0); + } + return sum[0] + sum[1] + sum[2] + sum[3]; +} + +static int Disto4x4_SSE2(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + const int diff_sum = TTransform_SSE2(a, b, w); + return abs(diff_sum) >> 5; +} + +static int Disto16x16_SSE2(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4_SSE2(a + x + y, b + x + y, w); + } + } + return D; +} + +//------------------------------------------------------------------------------ +// Quantization +// + +static WEBP_INLINE int DoQuantizeBlock_SSE2(int16_t in[16], int16_t out[16], + const uint16_t* const sharpen, + const VP8Matrix* const mtx) { + const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL); + const __m128i zero = _mm_setzero_si128(); + __m128i coeff0, coeff8; + __m128i out0, out8; + __m128i packed_out; + + // Load all inputs. + __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]); + __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]); + const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq_[0]); + const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq_[8]); + const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q_[0]); + const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q_[8]); + + // extract sign(in) (0x0000 if positive, 0xffff if negative) + const __m128i sign0 = _mm_cmpgt_epi16(zero, in0); + const __m128i sign8 = _mm_cmpgt_epi16(zero, in8); + + // coeff = abs(in) = (in ^ sign) - sign + coeff0 = _mm_xor_si128(in0, sign0); + coeff8 = _mm_xor_si128(in8, sign8); + coeff0 = _mm_sub_epi16(coeff0, sign0); + coeff8 = _mm_sub_epi16(coeff8, sign8); + + // coeff = abs(in) + sharpen + if (sharpen != NULL) { + const __m128i sharpen0 = _mm_loadu_si128((const __m128i*)&sharpen[0]); + const __m128i sharpen8 = _mm_loadu_si128((const __m128i*)&sharpen[8]); + coeff0 = _mm_add_epi16(coeff0, sharpen0); + coeff8 = _mm_add_epi16(coeff8, sharpen8); + } + + // out = (coeff * iQ + B) >> QFIX + { + // doing calculations with 32b precision (QFIX=17) + // out = (coeff * iQ) + const __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0); + const __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0); + const __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8); + const __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8); + __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H); + __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H); + __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H); + __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H); + // out = (coeff * iQ + B) + const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias_[0]); + const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias_[4]); + const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias_[8]); + const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias_[12]); + out_00 = _mm_add_epi32(out_00, bias_00); + out_04 = _mm_add_epi32(out_04, bias_04); + out_08 = _mm_add_epi32(out_08, bias_08); + out_12 = _mm_add_epi32(out_12, bias_12); + // out = QUANTDIV(coeff, iQ, B, QFIX) + out_00 = _mm_srai_epi32(out_00, QFIX); + out_04 = _mm_srai_epi32(out_04, QFIX); + out_08 = _mm_srai_epi32(out_08, QFIX); + out_12 = _mm_srai_epi32(out_12, QFIX); + + // pack result as 16b + out0 = _mm_packs_epi32(out_00, out_04); + out8 = _mm_packs_epi32(out_08, out_12); + + // if (coeff > 2047) coeff = 2047 + out0 = _mm_min_epi16(out0, max_coeff_2047); + out8 = _mm_min_epi16(out8, max_coeff_2047); + } + + // get sign back (if (sign[j]) out_n = -out_n) + out0 = _mm_xor_si128(out0, sign0); + out8 = _mm_xor_si128(out8, sign8); + out0 = _mm_sub_epi16(out0, sign0); + out8 = _mm_sub_epi16(out8, sign8); + + // in = out * Q + in0 = _mm_mullo_epi16(out0, q0); + in8 = _mm_mullo_epi16(out8, q8); + + _mm_storeu_si128((__m128i*)&in[0], in0); + _mm_storeu_si128((__m128i*)&in[8], in8); + + // zigzag the output before storing it. + // + // The zigzag pattern can almost be reproduced with a small sequence of + // shuffles. After it, we only need to swap the 7th (ending up in third + // position instead of twelfth) and 8th values. + { + __m128i outZ0, outZ8; + outZ0 = _mm_shufflehi_epi16(out0, _MM_SHUFFLE(2, 1, 3, 0)); + outZ0 = _mm_shuffle_epi32 (outZ0, _MM_SHUFFLE(3, 1, 2, 0)); + outZ0 = _mm_shufflehi_epi16(outZ0, _MM_SHUFFLE(3, 1, 0, 2)); + outZ8 = _mm_shufflelo_epi16(out8, _MM_SHUFFLE(3, 0, 2, 1)); + outZ8 = _mm_shuffle_epi32 (outZ8, _MM_SHUFFLE(3, 1, 2, 0)); + outZ8 = _mm_shufflelo_epi16(outZ8, _MM_SHUFFLE(1, 3, 2, 0)); + _mm_storeu_si128((__m128i*)&out[0], outZ0); + _mm_storeu_si128((__m128i*)&out[8], outZ8); + packed_out = _mm_packs_epi16(outZ0, outZ8); + } + { + const int16_t outZ_12 = out[12]; + const int16_t outZ_3 = out[3]; + out[3] = outZ_12; + out[12] = outZ_3; + } + + // detect if all 'out' values are zeroes or not + return (_mm_movemask_epi8(_mm_cmpeq_epi8(packed_out, zero)) != 0xffff); +} + +static int QuantizeBlock_SSE2(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + return DoQuantizeBlock_SSE2(in, out, &mtx->sharpen_[0], mtx); +} + +static int QuantizeBlockWHT_SSE2(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + return DoQuantizeBlock_SSE2(in, out, NULL, mtx); +} + +static int Quantize2Blocks_SSE2(int16_t in[32], int16_t out[32], + const VP8Matrix* const mtx) { + int nz; + const uint16_t* const sharpen = &mtx->sharpen_[0]; + nz = DoQuantizeBlock_SSE2(in + 0 * 16, out + 0 * 16, sharpen, mtx) << 0; + nz |= DoQuantizeBlock_SSE2(in + 1 * 16, out + 1 * 16, sharpen, mtx) << 1; + return nz; +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitSSE2(void) { + VP8CollectHistogram = CollectHistogram_SSE2; + VP8EncPredLuma16 = Intra16Preds_SSE2; + VP8EncPredChroma8 = IntraChromaPreds_SSE2; + VP8EncPredLuma4 = Intra4Preds_SSE2; + VP8EncQuantizeBlock = QuantizeBlock_SSE2; + VP8EncQuantize2Blocks = Quantize2Blocks_SSE2; + VP8EncQuantizeBlockWHT = QuantizeBlockWHT_SSE2; + VP8ITransform = ITransform_SSE2; + VP8FTransform = FTransform_SSE2; + VP8FTransform2 = FTransform2_SSE2; + VP8FTransformWHT = FTransformWHT_SSE2; + VP8SSE16x16 = SSE16x16_SSE2; + VP8SSE16x8 = SSE16x8_SSE2; + VP8SSE8x8 = SSE8x8_SSE2; + VP8SSE4x4 = SSE4x4_SSE2; + VP8TDisto4x4 = Disto4x4_SSE2; + VP8TDisto16x16 = Disto16x16_SSE2; + VP8Mean16x4 = Mean16x4_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(VP8EncDspInitSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/enc_sse41.c b/libraries/webp/src/dsp/enc_sse41.c new file mode 100644 index 00000000000..924035a6445 --- /dev/null +++ b/libraries/webp/src/dsp/enc_sse41.c @@ -0,0 +1,339 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE4 version of some encoding functions. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE41) +#include +#include // for abs() + +#include "src/dsp/common_sse2.h" +#include "src/enc/vp8i_enc.h" + +//------------------------------------------------------------------------------ +// Compute susceptibility based on DCT-coeff histograms. + +static void CollectHistogram_SSE41(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block, + VP8Histogram* const histo) { + const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH); + int j; + int distribution[MAX_COEFF_THRESH + 1] = { 0 }; + for (j = start_block; j < end_block; ++j) { + int16_t out[16]; + int k; + + VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + + // Convert coefficients to bin (within out[]). + { + // Load. + const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]); + const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]); + // v = abs(out) >> 3 + const __m128i abs0 = _mm_abs_epi16(out0); + const __m128i abs1 = _mm_abs_epi16(out1); + const __m128i v0 = _mm_srai_epi16(abs0, 3); + const __m128i v1 = _mm_srai_epi16(abs1, 3); + // bin = min(v, MAX_COEFF_THRESH) + const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh); + const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh); + // Store. + _mm_storeu_si128((__m128i*)&out[0], bin0); + _mm_storeu_si128((__m128i*)&out[8], bin1); + } + + // Convert coefficients to bin. + for (k = 0; k < 16; ++k) { + ++distribution[out[k]]; + } + } + VP8SetHistogramData(distribution, histo); +} + +//------------------------------------------------------------------------------ +// Texture distortion +// +// We try to match the spectral content (weighted) between source and +// reconstructed samples. + +// Hadamard transform +// Returns the weighted sum of the absolute value of transformed coefficients. +// w[] contains a row-major 4 by 4 symmetric matrix. +static int TTransform_SSE41(const uint8_t* inA, const uint8_t* inB, + const uint16_t* const w) { + int32_t sum[4]; + __m128i tmp_0, tmp_1, tmp_2, tmp_3; + + // Load and combine inputs. + { + const __m128i inA_0 = _mm_loadu_si128((const __m128i*)&inA[BPS * 0]); + const __m128i inA_1 = _mm_loadu_si128((const __m128i*)&inA[BPS * 1]); + const __m128i inA_2 = _mm_loadu_si128((const __m128i*)&inA[BPS * 2]); + // In SSE4.1, with gcc 4.8 at least (maybe other versions), + // _mm_loadu_si128 is faster than _mm_loadl_epi64. But for the last lump + // of inA and inB, _mm_loadl_epi64 is still used not to have an out of + // bound read. + const __m128i inA_3 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 3]); + const __m128i inB_0 = _mm_loadu_si128((const __m128i*)&inB[BPS * 0]); + const __m128i inB_1 = _mm_loadu_si128((const __m128i*)&inB[BPS * 1]); + const __m128i inB_2 = _mm_loadu_si128((const __m128i*)&inB[BPS * 2]); + const __m128i inB_3 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 3]); + + // Combine inA and inB (we'll do two transforms in parallel). + const __m128i inAB_0 = _mm_unpacklo_epi32(inA_0, inB_0); + const __m128i inAB_1 = _mm_unpacklo_epi32(inA_1, inB_1); + const __m128i inAB_2 = _mm_unpacklo_epi32(inA_2, inB_2); + const __m128i inAB_3 = _mm_unpacklo_epi32(inA_3, inB_3); + tmp_0 = _mm_cvtepu8_epi16(inAB_0); + tmp_1 = _mm_cvtepu8_epi16(inAB_1); + tmp_2 = _mm_cvtepu8_epi16(inAB_2); + tmp_3 = _mm_cvtepu8_epi16(inAB_3); + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + } + + // Vertical pass first to avoid a transpose (vertical and horizontal passes + // are commutative because w/kWeightY is symmetric) and subsequent transpose. + { + // Calculate a and b (two 4x4 at once). + const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); + const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); + const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); + const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); + const __m128i b0 = _mm_add_epi16(a0, a1); + const __m128i b1 = _mm_add_epi16(a3, a2); + const __m128i b2 = _mm_sub_epi16(a3, a2); + const __m128i b3 = _mm_sub_epi16(a0, a1); + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + + // Transpose the two 4x4. + VP8Transpose_2_4x4_16b(&b0, &b1, &b2, &b3, &tmp_0, &tmp_1, &tmp_2, &tmp_3); + } + + // Horizontal pass and difference of weighted sums. + { + // Load all inputs. + const __m128i w_0 = _mm_loadu_si128((const __m128i*)&w[0]); + const __m128i w_8 = _mm_loadu_si128((const __m128i*)&w[8]); + + // Calculate a and b (two 4x4 at once). + const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); + const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); + const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); + const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); + const __m128i b0 = _mm_add_epi16(a0, a1); + const __m128i b1 = _mm_add_epi16(a3, a2); + const __m128i b2 = _mm_sub_epi16(a3, a2); + const __m128i b3 = _mm_sub_epi16(a0, a1); + + // Separate the transforms of inA and inB. + __m128i A_b0 = _mm_unpacklo_epi64(b0, b1); + __m128i A_b2 = _mm_unpacklo_epi64(b2, b3); + __m128i B_b0 = _mm_unpackhi_epi64(b0, b1); + __m128i B_b2 = _mm_unpackhi_epi64(b2, b3); + + A_b0 = _mm_abs_epi16(A_b0); + A_b2 = _mm_abs_epi16(A_b2); + B_b0 = _mm_abs_epi16(B_b0); + B_b2 = _mm_abs_epi16(B_b2); + + // weighted sums + A_b0 = _mm_madd_epi16(A_b0, w_0); + A_b2 = _mm_madd_epi16(A_b2, w_8); + B_b0 = _mm_madd_epi16(B_b0, w_0); + B_b2 = _mm_madd_epi16(B_b2, w_8); + A_b0 = _mm_add_epi32(A_b0, A_b2); + B_b0 = _mm_add_epi32(B_b0, B_b2); + + // difference of weighted sums + A_b2 = _mm_sub_epi32(A_b0, B_b0); + _mm_storeu_si128((__m128i*)&sum[0], A_b2); + } + return sum[0] + sum[1] + sum[2] + sum[3]; +} + +static int Disto4x4_SSE41(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + const int diff_sum = TTransform_SSE41(a, b, w); + return abs(diff_sum) >> 5; +} + +static int Disto16x16_SSE41(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4_SSE41(a + x + y, b + x + y, w); + } + } + return D; +} + +//------------------------------------------------------------------------------ +// Quantization +// + +// Generates a pshufb constant for shuffling 16b words. +#define PSHUFB_CST(A,B,C,D,E,F,G,H) \ + _mm_set_epi8(2 * (H) + 1, 2 * (H) + 0, 2 * (G) + 1, 2 * (G) + 0, \ + 2 * (F) + 1, 2 * (F) + 0, 2 * (E) + 1, 2 * (E) + 0, \ + 2 * (D) + 1, 2 * (D) + 0, 2 * (C) + 1, 2 * (C) + 0, \ + 2 * (B) + 1, 2 * (B) + 0, 2 * (A) + 1, 2 * (A) + 0) + +static WEBP_INLINE int DoQuantizeBlock_SSE41(int16_t in[16], int16_t out[16], + const uint16_t* const sharpen, + const VP8Matrix* const mtx) { + const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL); + const __m128i zero = _mm_setzero_si128(); + __m128i out0, out8; + __m128i packed_out; + + // Load all inputs. + __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]); + __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]); + const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq_[0]); + const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq_[8]); + const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q_[0]); + const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q_[8]); + + // coeff = abs(in) + __m128i coeff0 = _mm_abs_epi16(in0); + __m128i coeff8 = _mm_abs_epi16(in8); + + // coeff = abs(in) + sharpen + if (sharpen != NULL) { + const __m128i sharpen0 = _mm_loadu_si128((const __m128i*)&sharpen[0]); + const __m128i sharpen8 = _mm_loadu_si128((const __m128i*)&sharpen[8]); + coeff0 = _mm_add_epi16(coeff0, sharpen0); + coeff8 = _mm_add_epi16(coeff8, sharpen8); + } + + // out = (coeff * iQ + B) >> QFIX + { + // doing calculations with 32b precision (QFIX=17) + // out = (coeff * iQ) + const __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0); + const __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0); + const __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8); + const __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8); + __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H); + __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H); + __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H); + __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H); + // out = (coeff * iQ + B) + const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias_[0]); + const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias_[4]); + const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias_[8]); + const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias_[12]); + out_00 = _mm_add_epi32(out_00, bias_00); + out_04 = _mm_add_epi32(out_04, bias_04); + out_08 = _mm_add_epi32(out_08, bias_08); + out_12 = _mm_add_epi32(out_12, bias_12); + // out = QUANTDIV(coeff, iQ, B, QFIX) + out_00 = _mm_srai_epi32(out_00, QFIX); + out_04 = _mm_srai_epi32(out_04, QFIX); + out_08 = _mm_srai_epi32(out_08, QFIX); + out_12 = _mm_srai_epi32(out_12, QFIX); + + // pack result as 16b + out0 = _mm_packs_epi32(out_00, out_04); + out8 = _mm_packs_epi32(out_08, out_12); + + // if (coeff > 2047) coeff = 2047 + out0 = _mm_min_epi16(out0, max_coeff_2047); + out8 = _mm_min_epi16(out8, max_coeff_2047); + } + + // put sign back + out0 = _mm_sign_epi16(out0, in0); + out8 = _mm_sign_epi16(out8, in8); + + // in = out * Q + in0 = _mm_mullo_epi16(out0, q0); + in8 = _mm_mullo_epi16(out8, q8); + + _mm_storeu_si128((__m128i*)&in[0], in0); + _mm_storeu_si128((__m128i*)&in[8], in8); + + // zigzag the output before storing it. The re-ordering is: + // 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15 + // -> 0 1 4[8]5 2 3 6 | 9 12 13 10 [7]11 14 15 + // There's only two misplaced entries ([8] and [7]) that are crossing the + // reg's boundaries. + // We use pshufb instead of pshuflo/pshufhi. + { + const __m128i kCst_lo = PSHUFB_CST(0, 1, 4, -1, 5, 2, 3, 6); + const __m128i kCst_7 = PSHUFB_CST(-1, -1, -1, -1, 7, -1, -1, -1); + const __m128i tmp_lo = _mm_shuffle_epi8(out0, kCst_lo); + const __m128i tmp_7 = _mm_shuffle_epi8(out0, kCst_7); // extract #7 + const __m128i kCst_hi = PSHUFB_CST(1, 4, 5, 2, -1, 3, 6, 7); + const __m128i kCst_8 = PSHUFB_CST(-1, -1, -1, 0, -1, -1, -1, -1); + const __m128i tmp_hi = _mm_shuffle_epi8(out8, kCst_hi); + const __m128i tmp_8 = _mm_shuffle_epi8(out8, kCst_8); // extract #8 + const __m128i out_z0 = _mm_or_si128(tmp_lo, tmp_8); + const __m128i out_z8 = _mm_or_si128(tmp_hi, tmp_7); + _mm_storeu_si128((__m128i*)&out[0], out_z0); + _mm_storeu_si128((__m128i*)&out[8], out_z8); + packed_out = _mm_packs_epi16(out_z0, out_z8); + } + + // detect if all 'out' values are zeroes or not + return (_mm_movemask_epi8(_mm_cmpeq_epi8(packed_out, zero)) != 0xffff); +} + +#undef PSHUFB_CST + +static int QuantizeBlock_SSE41(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + return DoQuantizeBlock_SSE41(in, out, &mtx->sharpen_[0], mtx); +} + +static int QuantizeBlockWHT_SSE41(int16_t in[16], int16_t out[16], + const VP8Matrix* const mtx) { + return DoQuantizeBlock_SSE41(in, out, NULL, mtx); +} + +static int Quantize2Blocks_SSE41(int16_t in[32], int16_t out[32], + const VP8Matrix* const mtx) { + int nz; + const uint16_t* const sharpen = &mtx->sharpen_[0]; + nz = DoQuantizeBlock_SSE41(in + 0 * 16, out + 0 * 16, sharpen, mtx) << 0; + nz |= DoQuantizeBlock_SSE41(in + 1 * 16, out + 1 * 16, sharpen, mtx) << 1; + return nz; +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspInitSSE41(void); +WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitSSE41(void) { + VP8CollectHistogram = CollectHistogram_SSE41; + VP8EncQuantizeBlock = QuantizeBlock_SSE41; + VP8EncQuantize2Blocks = Quantize2Blocks_SSE41; + VP8EncQuantizeBlockWHT = QuantizeBlockWHT_SSE41; + VP8TDisto4x4 = Disto4x4_SSE41; + VP8TDisto16x16 = Disto16x16_SSE41; +} + +#else // !WEBP_USE_SSE41 + +WEBP_DSP_INIT_STUB(VP8EncDspInitSSE41) + +#endif // WEBP_USE_SSE41 diff --git a/libraries/webp/src/dsp/filters.c b/libraries/webp/src/dsp/filters.c new file mode 100644 index 00000000000..c9232ff16a6 --- /dev/null +++ b/libraries/webp/src/dsp/filters.c @@ -0,0 +1,297 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Spatial prediction using various filters +// +// Author: Urvang (urvang@google.com) + +#include "src/dsp/dsp.h" +#include +#include +#include + +//------------------------------------------------------------------------------ +// Helpful macro. + +#define DCHECK(in, out) \ + do { \ + assert((in) != NULL); \ + assert((out) != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(stride >= width); \ + assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ + (void)height; /* Silence unused warning. */ \ + } while (0) + +#if !WEBP_NEON_OMIT_C_CODE +static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred, + uint8_t* dst, int length, int inverse) { + int i; + if (inverse) { + for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] + pred[i]); + } else { + for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] - pred[i]); + } +} + +//------------------------------------------------------------------------------ +// Horizontal filter. + +static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, + int inverse, uint8_t* out) { + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + preds = inverse ? out : in; + + if (row == 0) { + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLine_C(in + 1, preds, out + 1, width - 1, inverse); + row = 1; + preds += stride; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + // Leftmost pixel is predicted from above. + PredictLine_C(in, preds - stride, out, 1, inverse); + PredictLine_C(in + 1, preds, out + 1, width - 1, inverse); + ++row; + preds += stride; + in += stride; + out += stride; + } +} + +//------------------------------------------------------------------------------ +// Vertical filter. + +static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, + int inverse, uint8_t* out) { + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + preds = inverse ? out : in; + + if (row == 0) { + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLine_C(in + 1, preds, out + 1, width - 1, inverse); + row = 1; + in += stride; + out += stride; + } else { + // We are starting from in-between. Make sure 'preds' points to prev row. + preds -= stride; + } + + // Filter line-by-line. + while (row < last_row) { + PredictLine_C(in, preds, out, width, inverse); + ++row; + preds += stride; + in += stride; + out += stride; + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//------------------------------------------------------------------------------ +// Gradient filter. + +static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) { + const int g = a + b - c; + return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit +} + +#if !WEBP_NEON_OMIT_C_CODE +static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, + int inverse, uint8_t* out) { + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + preds = inverse ? out : in; + + // left prediction for top scan-line + if (row == 0) { + out[0] = in[0]; + PredictLine_C(in + 1, preds, out + 1, width - 1, inverse); + row = 1; + preds += stride; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + int w; + // leftmost pixel: predict from above. + PredictLine_C(in, preds - stride, out, 1, inverse); + for (w = 1; w < width; ++w) { + const int pred = GradientPredictor_C(preds[w - 1], + preds[w - stride], + preds[w - stride - 1]); + out[w] = (uint8_t)(in[w] + (inverse ? pred : -pred)); + } + ++row; + preds += stride; + in += stride; + out += stride; + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +#undef DCHECK + +//------------------------------------------------------------------------------ + +#if !WEBP_NEON_OMIT_C_CODE +static void HorizontalFilter_C(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoHorizontalFilter_C(data, width, height, stride, 0, height, 0, + filtered_data); +} + +static void VerticalFilter_C(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoVerticalFilter_C(data, width, height, stride, 0, height, 0, filtered_data); +} + +static void GradientFilter_C(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoGradientFilter_C(data, width, height, stride, 0, height, 0, filtered_data); +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//------------------------------------------------------------------------------ + +static void NoneUnfilter_C(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + (void)prev; + if (out != in) memcpy(out, in, width * sizeof(*out)); +} + +static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + uint8_t pred = (prev == NULL) ? 0 : prev[0]; + int i; + for (i = 0; i < width; ++i) { + out[i] = (uint8_t)(pred + in[i]); + pred = out[i]; + } +} + +#if !WEBP_NEON_OMIT_C_CODE +static void VerticalUnfilter_C(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_C(NULL, in, out, width); + } else { + int i; + for (i = 0; i < width; ++i) out[i] = (uint8_t)(prev[i] + in[i]); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +static void GradientUnfilter_C(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_C(NULL, in, out, width); + } else { + uint8_t top = prev[0], top_left = top, left = top; + int i; + for (i = 0; i < width; ++i) { + top = prev[i]; // need to read this first, in case prev==out + left = (uint8_t)(in[i] + GradientPredictor_C(left, top, top_left)); + top_left = top; + out[i] = left; + } + } +} + +//------------------------------------------------------------------------------ +// Init function + +WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; +WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST]; + +extern VP8CPUInfo VP8GetCPUInfo; +extern void VP8FiltersInitMIPSdspR2(void); +extern void VP8FiltersInitMSA(void); +extern void VP8FiltersInitNEON(void); +extern void VP8FiltersInitSSE2(void); + +WEBP_DSP_INIT_FUNC(VP8FiltersInit) { + WebPUnfilters[WEBP_FILTER_NONE] = NoneUnfilter_C; +#if !WEBP_NEON_OMIT_C_CODE + WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_C; + WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_C; +#endif + WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_C; + + WebPFilters[WEBP_FILTER_NONE] = NULL; +#if !WEBP_NEON_OMIT_C_CODE + WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_C; + WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_C; + WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_C; +#endif + + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8FiltersInitSSE2(); + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + VP8FiltersInitMIPSdspR2(); + } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8FiltersInitMSA(); + } +#endif + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + VP8FiltersInitNEON(); + } +#endif + + assert(WebPUnfilters[WEBP_FILTER_NONE] != NULL); + assert(WebPUnfilters[WEBP_FILTER_HORIZONTAL] != NULL); + assert(WebPUnfilters[WEBP_FILTER_VERTICAL] != NULL); + assert(WebPUnfilters[WEBP_FILTER_GRADIENT] != NULL); + assert(WebPFilters[WEBP_FILTER_HORIZONTAL] != NULL); + assert(WebPFilters[WEBP_FILTER_VERTICAL] != NULL); + assert(WebPFilters[WEBP_FILTER_GRADIENT] != NULL); +} diff --git a/libraries/webp/src/dsp/filters_mips_dsp_r2.c b/libraries/webp/src/dsp/filters_mips_dsp_r2.c new file mode 100644 index 00000000000..eca866f5789 --- /dev/null +++ b/libraries/webp/src/dsp/filters_mips_dsp_r2.c @@ -0,0 +1,404 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Spatial prediction using various filters +// +// Author(s): Branimir Vasic (branimir.vasic@imgtec.com) +// Djordje Pesut (djordje.pesut@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +#include "src/dsp/dsp.h" +#include +#include +#include + +//------------------------------------------------------------------------------ +// Helpful macro. + +#define DCHECK(in, out) \ + do { \ + assert(in != NULL); \ + assert(out != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(stride >= width); \ + assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ + (void)height; /* Silence unused warning. */ \ + } while (0) + +#define DO_PREDICT_LINE(SRC, DST, LENGTH, INVERSE) do { \ + const uint8_t* psrc = (uint8_t*)(SRC); \ + uint8_t* pdst = (uint8_t*)(DST); \ + const int ilength = (int)(LENGTH); \ + int temp0, temp1, temp2, temp3, temp4, temp5, temp6; \ + __asm__ volatile ( \ + ".set push \n\t" \ + ".set noreorder \n\t" \ + "srl %[temp0], %[length], 2 \n\t" \ + "beqz %[temp0], 4f \n\t" \ + " andi %[temp6], %[length], 3 \n\t" \ + ".if " #INVERSE " \n\t" \ + "1: \n\t" \ + "lbu %[temp1], -1(%[dst]) \n\t" \ + "lbu %[temp2], 0(%[src]) \n\t" \ + "lbu %[temp3], 1(%[src]) \n\t" \ + "lbu %[temp4], 2(%[src]) \n\t" \ + "lbu %[temp5], 3(%[src]) \n\t" \ + "addu %[temp1], %[temp1], %[temp2] \n\t" \ + "addu %[temp2], %[temp1], %[temp3] \n\t" \ + "addu %[temp3], %[temp2], %[temp4] \n\t" \ + "addu %[temp4], %[temp3], %[temp5] \n\t" \ + "sb %[temp1], 0(%[dst]) \n\t" \ + "sb %[temp2], 1(%[dst]) \n\t" \ + "sb %[temp3], 2(%[dst]) \n\t" \ + "sb %[temp4], 3(%[dst]) \n\t" \ + "addiu %[src], %[src], 4 \n\t" \ + "addiu %[temp0], %[temp0], -1 \n\t" \ + "bnez %[temp0], 1b \n\t" \ + " addiu %[dst], %[dst], 4 \n\t" \ + ".else \n\t" \ + "1: \n\t" \ + "ulw %[temp1], -1(%[src]) \n\t" \ + "ulw %[temp2], 0(%[src]) \n\t" \ + "addiu %[src], %[src], 4 \n\t" \ + "addiu %[temp0], %[temp0], -1 \n\t" \ + "subu.qb %[temp3], %[temp2], %[temp1] \n\t" \ + "usw %[temp3], 0(%[dst]) \n\t" \ + "bnez %[temp0], 1b \n\t" \ + " addiu %[dst], %[dst], 4 \n\t" \ + ".endif \n\t" \ + "4: \n\t" \ + "beqz %[temp6], 3f \n\t" \ + " nop \n\t" \ + "2: \n\t" \ + "lbu %[temp2], 0(%[src]) \n\t" \ + ".if " #INVERSE " \n\t" \ + "lbu %[temp1], -1(%[dst]) \n\t" \ + "addu %[temp3], %[temp1], %[temp2] \n\t" \ + ".else \n\t" \ + "lbu %[temp1], -1(%[src]) \n\t" \ + "subu %[temp3], %[temp1], %[temp2] \n\t" \ + ".endif \n\t" \ + "addiu %[src], %[src], 1 \n\t" \ + "sb %[temp3], 0(%[dst]) \n\t" \ + "addiu %[temp6], %[temp6], -1 \n\t" \ + "bnez %[temp6], 2b \n\t" \ + " addiu %[dst], %[dst], 1 \n\t" \ + "3: \n\t" \ + ".set pop \n\t" \ + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \ + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \ + [temp6]"=&r"(temp6), [dst]"+&r"(pdst), [src]"+&r"(psrc) \ + : [length]"r"(ilength) \ + : "memory" \ + ); \ + } while (0) + +static WEBP_INLINE void PredictLine_MIPSdspR2(const uint8_t* src, uint8_t* dst, + int length) { + DO_PREDICT_LINE(src, dst, length, 0); +} + +#define DO_PREDICT_LINE_VERTICAL(SRC, PRED, DST, LENGTH, INVERSE) do { \ + const uint8_t* psrc = (uint8_t*)(SRC); \ + const uint8_t* ppred = (uint8_t*)(PRED); \ + uint8_t* pdst = (uint8_t*)(DST); \ + const int ilength = (int)(LENGTH); \ + int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; \ + __asm__ volatile ( \ + ".set push \n\t" \ + ".set noreorder \n\t" \ + "srl %[temp0], %[length], 0x3 \n\t" \ + "beqz %[temp0], 4f \n\t" \ + " andi %[temp7], %[length], 0x7 \n\t" \ + "1: \n\t" \ + "ulw %[temp1], 0(%[src]) \n\t" \ + "ulw %[temp2], 0(%[pred]) \n\t" \ + "ulw %[temp3], 4(%[src]) \n\t" \ + "ulw %[temp4], 4(%[pred]) \n\t" \ + "addiu %[src], %[src], 8 \n\t" \ + ".if " #INVERSE " \n\t" \ + "addu.qb %[temp5], %[temp1], %[temp2] \n\t" \ + "addu.qb %[temp6], %[temp3], %[temp4] \n\t" \ + ".else \n\t" \ + "subu.qb %[temp5], %[temp1], %[temp2] \n\t" \ + "subu.qb %[temp6], %[temp3], %[temp4] \n\t" \ + ".endif \n\t" \ + "addiu %[pred], %[pred], 8 \n\t" \ + "usw %[temp5], 0(%[dst]) \n\t" \ + "usw %[temp6], 4(%[dst]) \n\t" \ + "addiu %[temp0], %[temp0], -1 \n\t" \ + "bnez %[temp0], 1b \n\t" \ + " addiu %[dst], %[dst], 8 \n\t" \ + "4: \n\t" \ + "beqz %[temp7], 3f \n\t" \ + " nop \n\t" \ + "2: \n\t" \ + "lbu %[temp1], 0(%[src]) \n\t" \ + "lbu %[temp2], 0(%[pred]) \n\t" \ + "addiu %[src], %[src], 1 \n\t" \ + "addiu %[pred], %[pred], 1 \n\t" \ + ".if " #INVERSE " \n\t" \ + "addu %[temp3], %[temp1], %[temp2] \n\t" \ + ".else \n\t" \ + "subu %[temp3], %[temp1], %[temp2] \n\t" \ + ".endif \n\t" \ + "sb %[temp3], 0(%[dst]) \n\t" \ + "addiu %[temp7], %[temp7], -1 \n\t" \ + "bnez %[temp7], 2b \n\t" \ + " addiu %[dst], %[dst], 1 \n\t" \ + "3: \n\t" \ + ".set pop \n\t" \ + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \ + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \ + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [pred]"+&r"(ppred), \ + [dst]"+&r"(pdst), [src]"+&r"(psrc) \ + : [length]"r"(ilength) \ + : "memory" \ + ); \ + } while (0) + +#define PREDICT_LINE_ONE_PASS(SRC, PRED, DST) do { \ + int temp1, temp2, temp3; \ + __asm__ volatile ( \ + "lbu %[temp1], 0(%[src]) \n\t" \ + "lbu %[temp2], 0(%[pred]) \n\t" \ + "subu %[temp3], %[temp1], %[temp2] \n\t" \ + "sb %[temp3], 0(%[dst]) \n\t" \ + : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3) \ + : [pred]"r"((PRED)), [dst]"r"((DST)), [src]"r"((SRC)) \ + : "memory" \ + ); \ + } while (0) + +//------------------------------------------------------------------------------ +// Horizontal filter. + +#define FILTER_LINE_BY_LINE do { \ + while (row < last_row) { \ + PREDICT_LINE_ONE_PASS(in, preds - stride, out); \ + DO_PREDICT_LINE(in + 1, out + 1, width - 1, 0); \ + ++row; \ + preds += stride; \ + in += stride; \ + out += stride; \ + } \ + } while (0) + +static WEBP_INLINE void DoHorizontalFilter_MIPSdspR2(const uint8_t* in, + int width, int height, + int stride, + int row, int num_rows, + uint8_t* out) { + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + preds = in; + + if (row == 0) { + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); + row = 1; + preds += stride; + in += stride; + out += stride; + } + + // Filter line-by-line. + FILTER_LINE_BY_LINE; +} +#undef FILTER_LINE_BY_LINE + +static void HorizontalFilter_MIPSdspR2(const uint8_t* data, + int width, int height, + int stride, uint8_t* filtered_data) { + DoHorizontalFilter_MIPSdspR2(data, width, height, stride, 0, height, + filtered_data); +} + +//------------------------------------------------------------------------------ +// Vertical filter. + +#define FILTER_LINE_BY_LINE do { \ + while (row < last_row) { \ + DO_PREDICT_LINE_VERTICAL(in, preds, out, width, 0); \ + ++row; \ + preds += stride; \ + in += stride; \ + out += stride; \ + } \ + } while (0) + +static WEBP_INLINE void DoVerticalFilter_MIPSdspR2(const uint8_t* in, + int width, int height, + int stride, + int row, int num_rows, + uint8_t* out) { + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + preds = in; + + if (row == 0) { + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } else { + // We are starting from in-between. Make sure 'preds' points to prev row. + preds -= stride; + } + + // Filter line-by-line. + FILTER_LINE_BY_LINE; +} +#undef FILTER_LINE_BY_LINE + +static void VerticalFilter_MIPSdspR2(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoVerticalFilter_MIPSdspR2(data, width, height, stride, 0, height, + filtered_data); +} + +//------------------------------------------------------------------------------ +// Gradient filter. + +static int GradientPredictor_MIPSdspR2(uint8_t a, uint8_t b, uint8_t c) { + int temp0; + __asm__ volatile ( + "addu %[temp0], %[a], %[b] \n\t" + "subu %[temp0], %[temp0], %[c] \n\t" + "shll_s.w %[temp0], %[temp0], 23 \n\t" + "precrqu_s.qb.ph %[temp0], %[temp0], $zero \n\t" + "srl %[temp0], %[temp0], 24 \n\t" + : [temp0]"=&r"(temp0) + : [a]"r"(a),[b]"r"(b),[c]"r"(c) + ); + return temp0; +} + +#define FILTER_LINE_BY_LINE(PREDS, OPERATION) do { \ + while (row < last_row) { \ + int w; \ + PREDICT_LINE_ONE_PASS(in, PREDS - stride, out); \ + for (w = 1; w < width; ++w) { \ + const int pred = GradientPredictor_MIPSdspR2(PREDS[w - 1], \ + PREDS[w - stride], \ + PREDS[w - stride - 1]); \ + out[w] = in[w] OPERATION pred; \ + } \ + ++row; \ + in += stride; \ + out += stride; \ + } \ + } while (0) + +static void DoGradientFilter_MIPSdspR2(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, uint8_t* out) { + const uint8_t* preds; + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + preds = in; + + // left prediction for top scan-line + if (row == 0) { + out[0] = in[0]; + PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); + row = 1; + preds += stride; + in += stride; + out += stride; + } + + // Filter line-by-line. + FILTER_LINE_BY_LINE(in, -); +} +#undef FILTER_LINE_BY_LINE + +static void GradientFilter_MIPSdspR2(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoGradientFilter_MIPSdspR2(data, width, height, stride, 0, height, + filtered_data); +} + +//------------------------------------------------------------------------------ + +static void HorizontalUnfilter_MIPSdspR2(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + out[0] = in[0] + (prev == NULL ? 0 : prev[0]); + DO_PREDICT_LINE(in + 1, out + 1, width - 1, 1); +} + +static void VerticalUnfilter_MIPSdspR2(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_MIPSdspR2(NULL, in, out, width); + } else { + DO_PREDICT_LINE_VERTICAL(in, prev, out, width, 1); + } +} + +static void GradientUnfilter_MIPSdspR2(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_MIPSdspR2(NULL, in, out, width); + } else { + uint8_t top = prev[0], top_left = top, left = top; + int i; + for (i = 0; i < width; ++i) { + top = prev[i]; // need to read this first, in case prev==dst + left = in[i] + GradientPredictor_MIPSdspR2(left, top, top_left); + top_left = top; + out[i] = left; + } + } +} + +#undef DO_PREDICT_LINE_VERTICAL +#undef PREDICT_LINE_ONE_PASS +#undef DO_PREDICT_LINE +#undef DCHECK + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8FiltersInitMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMIPSdspR2(void) { + WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_MIPSdspR2; + WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_MIPSdspR2; + WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_MIPSdspR2; + + WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_MIPSdspR2; + WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_MIPSdspR2; + WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_MIPSdspR2; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(VP8FiltersInitMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/filters_msa.c b/libraries/webp/src/dsp/filters_msa.c new file mode 100644 index 00000000000..33a1b20b70d --- /dev/null +++ b/libraries/webp/src/dsp/filters_msa.c @@ -0,0 +1,204 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MSA variant of alpha filters +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "src/dsp/msa_macro.h" + +#include + +static WEBP_INLINE void PredictLineInverse0(const uint8_t* src, + const uint8_t* pred, + uint8_t* dst, int length) { + v16u8 src0, pred0, dst0; + assert(length >= 0); + while (length >= 32) { + v16u8 src1, pred1, dst1; + LD_UB2(src, 16, src0, src1); + LD_UB2(pred, 16, pred0, pred1); + SUB2(src0, pred0, src1, pred1, dst0, dst1); + ST_UB2(dst0, dst1, dst, 16); + src += 32; + pred += 32; + dst += 32; + length -= 32; + } + if (length > 0) { + int i; + if (length >= 16) { + src0 = LD_UB(src); + pred0 = LD_UB(pred); + dst0 = src0 - pred0; + ST_UB(dst0, dst); + src += 16; + pred += 16; + dst += 16; + length -= 16; + } + for (i = 0; i < length; i++) { + dst[i] = src[i] - pred[i]; + } + } +} + +//------------------------------------------------------------------------------ +// Helpful macro. + +#define DCHECK(in, out) \ + do { \ + assert(in != NULL); \ + assert(out != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(stride >= width); \ + } while (0) + +//------------------------------------------------------------------------------ +// Horrizontal filter + +static void HorizontalFilter_MSA(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + const uint8_t* preds = data; + const uint8_t* in = data; + uint8_t* out = filtered_data; + int row = 1; + DCHECK(in, out); + + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLineInverse0(in + 1, preds, out + 1, width - 1); + preds += stride; + in += stride; + out += stride; + // Filter line-by-line. + while (row < height) { + // Leftmost pixel is predicted from above. + PredictLineInverse0(in, preds - stride, out, 1); + PredictLineInverse0(in + 1, preds, out + 1, width - 1); + ++row; + preds += stride; + in += stride; + out += stride; + } +} + +//------------------------------------------------------------------------------ +// Gradient filter + +static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput, + const uint8_t* ppred, + uint8_t* poutput, int stride, + int size) { + int w; + const v16i8 zero = { 0 }; + while (size >= 16) { + v16u8 pred0, dst0; + v8i16 a0, a1, b0, b1, c0, c1; + const v16u8 tmp0 = LD_UB(ppred - 1); + const v16u8 tmp1 = LD_UB(ppred - stride); + const v16u8 tmp2 = LD_UB(ppred - stride - 1); + const v16u8 src0 = LD_UB(pinput); + ILVRL_B2_SH(zero, tmp0, a0, a1); + ILVRL_B2_SH(zero, tmp1, b0, b1); + ILVRL_B2_SH(zero, tmp2, c0, c1); + ADD2(a0, b0, a1, b1, a0, a1); + SUB2(a0, c0, a1, c1, a0, a1); + CLIP_SH2_0_255(a0, a1); + pred0 = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0); + dst0 = src0 - pred0; + ST_UB(dst0, poutput); + ppred += 16; + pinput += 16; + poutput += 16; + size -= 16; + } + for (w = 0; w < size; ++w) { + const int pred = ppred[w - 1] + ppred[w - stride] - ppred[w - stride - 1]; + poutput[w] = pinput[w] - (pred < 0 ? 0 : pred > 255 ? 255 : pred); + } +} + + +static void GradientFilter_MSA(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + const uint8_t* in = data; + const uint8_t* preds = data; + uint8_t* out = filtered_data; + int row = 1; + DCHECK(in, out); + + // left prediction for top scan-line + out[0] = in[0]; + PredictLineInverse0(in + 1, preds, out + 1, width - 1); + preds += stride; + in += stride; + out += stride; + // Filter line-by-line. + while (row < height) { + out[0] = in[0] - preds[- stride]; + PredictLineGradient(preds + 1, in + 1, out + 1, stride, width - 1); + ++row; + preds += stride; + in += stride; + out += stride; + } +} + +//------------------------------------------------------------------------------ +// Vertical filter + +static void VerticalFilter_MSA(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + const uint8_t* in = data; + const uint8_t* preds = data; + uint8_t* out = filtered_data; + int row = 1; + DCHECK(in, out); + + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLineInverse0(in + 1, preds, out + 1, width - 1); + in += stride; + out += stride; + + // Filter line-by-line. + while (row < height) { + PredictLineInverse0(in, preds, out, width); + ++row; + preds += stride; + in += stride; + out += stride; + } +} + +#undef DCHECK + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8FiltersInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMSA(void) { + WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_MSA; + WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_MSA; + WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_MSA; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8FiltersInitMSA) + +#endif // WEBP_USE_MSA diff --git a/libraries/webp/src/dsp/filters_neon.c b/libraries/webp/src/dsp/filters_neon.c new file mode 100644 index 00000000000..b49e515af1f --- /dev/null +++ b/libraries/webp/src/dsp/filters_neon.c @@ -0,0 +1,331 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// NEON variant of alpha filters +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include +#include "src/dsp/neon.h" + +//------------------------------------------------------------------------------ +// Helpful macros. + +#define DCHECK(in, out) \ + do { \ + assert(in != NULL); \ + assert(out != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(stride >= width); \ + assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ + (void)height; /* Silence unused warning. */ \ + } while (0) + +// load eight u8 and widen to s16 +#define U8_TO_S16(A) vreinterpretq_s16_u16(vmovl_u8(A)) +#define LOAD_U8_TO_S16(A) U8_TO_S16(vld1_u8(A)) + +// shift left or right by N byte, inserting zeros +#define SHIFT_RIGHT_N_Q(A, N) vextq_u8((A), zero, (N)) +#define SHIFT_LEFT_N_Q(A, N) vextq_u8(zero, (A), (16 - (N)) % 16) + +// rotate left by N bytes +#define ROTATE_LEFT_N(A, N) vext_u8((A), (A), (N)) +// rotate right by N bytes +#define ROTATE_RIGHT_N(A, N) vext_u8((A), (A), (8 - (N)) % 8) + +static void PredictLine_NEON(const uint8_t* src, const uint8_t* pred, + uint8_t* dst, int length) { + int i; + assert(length >= 0); + for (i = 0; i + 16 <= length; i += 16) { + const uint8x16_t A = vld1q_u8(&src[i]); + const uint8x16_t B = vld1q_u8(&pred[i]); + const uint8x16_t C = vsubq_u8(A, B); + vst1q_u8(&dst[i], C); + } + for (; i < length; ++i) dst[i] = src[i] - pred[i]; +} + +// Special case for left-based prediction (when preds==dst-1 or preds==src-1). +static void PredictLineLeft_NEON(const uint8_t* src, uint8_t* dst, int length) { + PredictLine_NEON(src, src - 1, dst, length); +} + +//------------------------------------------------------------------------------ +// Horizontal filter. + +static WEBP_INLINE void DoHorizontalFilter_NEON(const uint8_t* in, + int width, int height, + int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + + if (row == 0) { + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + // Leftmost pixel is predicted from above. + out[0] = in[0] - in[-stride]; + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + ++row; + in += stride; + out += stride; + } +} + +static void HorizontalFilter_NEON(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoHorizontalFilter_NEON(data, width, height, stride, 0, height, + filtered_data); +} + +//------------------------------------------------------------------------------ +// Vertical filter. + +static WEBP_INLINE void DoVerticalFilter_NEON(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + + if (row == 0) { + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + PredictLine_NEON(in, in - stride, out, width); + ++row; + in += stride; + out += stride; + } +} + +static void VerticalFilter_NEON(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoVerticalFilter_NEON(data, width, height, stride, 0, height, + filtered_data); +} + +//------------------------------------------------------------------------------ +// Gradient filter. + +static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) { + const int g = a + b - c; + return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit +} + +static void GradientPredictDirect_NEON(const uint8_t* const row, + const uint8_t* const top, + uint8_t* const out, int length) { + int i; + for (i = 0; i + 8 <= length; i += 8) { + const uint8x8_t A = vld1_u8(&row[i - 1]); + const uint8x8_t B = vld1_u8(&top[i + 0]); + const int16x8_t C = vreinterpretq_s16_u16(vaddl_u8(A, B)); + const int16x8_t D = LOAD_U8_TO_S16(&top[i - 1]); + const uint8x8_t E = vqmovun_s16(vsubq_s16(C, D)); + const uint8x8_t F = vld1_u8(&row[i + 0]); + vst1_u8(&out[i], vsub_u8(F, E)); + } + for (; i < length; ++i) { + out[i] = row[i] - GradientPredictor_C(row[i - 1], top[i], top[i - 1]); + } +} + +static WEBP_INLINE void DoGradientFilter_NEON(const uint8_t* in, + int width, int height, + int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + + // left prediction for top scan-line + if (row == 0) { + out[0] = in[0]; + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + out[0] = in[0] - in[-stride]; + GradientPredictDirect_NEON(in + 1, in + 1 - stride, out + 1, width - 1); + ++row; + in += stride; + out += stride; + } +} + +static void GradientFilter_NEON(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoGradientFilter_NEON(data, width, height, stride, 0, height, + filtered_data); +} + +#undef DCHECK + +//------------------------------------------------------------------------------ +// Inverse transforms + +static void HorizontalUnfilter_NEON(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + int i; + const uint8x16_t zero = vdupq_n_u8(0); + uint8x16_t last; + out[0] = in[0] + (prev == NULL ? 0 : prev[0]); + if (width <= 1) return; + last = vsetq_lane_u8(out[0], zero, 0); + for (i = 1; i + 16 <= width; i += 16) { + const uint8x16_t A0 = vld1q_u8(&in[i]); + const uint8x16_t A1 = vaddq_u8(A0, last); + const uint8x16_t A2 = SHIFT_LEFT_N_Q(A1, 1); + const uint8x16_t A3 = vaddq_u8(A1, A2); + const uint8x16_t A4 = SHIFT_LEFT_N_Q(A3, 2); + const uint8x16_t A5 = vaddq_u8(A3, A4); + const uint8x16_t A6 = SHIFT_LEFT_N_Q(A5, 4); + const uint8x16_t A7 = vaddq_u8(A5, A6); + const uint8x16_t A8 = SHIFT_LEFT_N_Q(A7, 8); + const uint8x16_t A9 = vaddq_u8(A7, A8); + vst1q_u8(&out[i], A9); + last = SHIFT_RIGHT_N_Q(A9, 15); + } + for (; i < width; ++i) out[i] = in[i] + out[i - 1]; +} + +static void VerticalUnfilter_NEON(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_NEON(NULL, in, out, width); + } else { + int i; + assert(width >= 0); + for (i = 0; i + 16 <= width; i += 16) { + const uint8x16_t A = vld1q_u8(&in[i]); + const uint8x16_t B = vld1q_u8(&prev[i]); + const uint8x16_t C = vaddq_u8(A, B); + vst1q_u8(&out[i], C); + } + for (; i < width; ++i) out[i] = in[i] + prev[i]; + } +} + +// GradientUnfilter_NEON is correct but slower than the C-version, +// at least on ARM64. For armv7, it's a wash. +// So best is to disable it for now, but keep the idea around... +#if !defined(USE_GRADIENT_UNFILTER) +#define USE_GRADIENT_UNFILTER 0 // ALTERNATE_CODE +#endif + +#if (USE_GRADIENT_UNFILTER == 1) +#define GRAD_PROCESS_LANE(L) do { \ + const uint8x8_t tmp1 = ROTATE_RIGHT_N(pred, 1); /* rotate predictor in */ \ + const int16x8_t tmp2 = vaddq_s16(BC, U8_TO_S16(tmp1)); \ + const uint8x8_t delta = vqmovun_s16(tmp2); \ + pred = vadd_u8(D, delta); \ + out = vext_u8(out, ROTATE_LEFT_N(pred, (L)), 1); \ +} while (0) + +static void GradientPredictInverse_NEON(const uint8_t* const in, + const uint8_t* const top, + uint8_t* const row, int length) { + if (length > 0) { + int i; + uint8x8_t pred = vdup_n_u8(row[-1]); // left sample + uint8x8_t out = vdup_n_u8(0); + for (i = 0; i + 8 <= length; i += 8) { + const int16x8_t B = LOAD_U8_TO_S16(&top[i + 0]); + const int16x8_t C = LOAD_U8_TO_S16(&top[i - 1]); + const int16x8_t BC = vsubq_s16(B, C); // unclipped gradient basis B - C + const uint8x8_t D = vld1_u8(&in[i]); // base input + GRAD_PROCESS_LANE(0); + GRAD_PROCESS_LANE(1); + GRAD_PROCESS_LANE(2); + GRAD_PROCESS_LANE(3); + GRAD_PROCESS_LANE(4); + GRAD_PROCESS_LANE(5); + GRAD_PROCESS_LANE(6); + GRAD_PROCESS_LANE(7); + vst1_u8(&row[i], out); + } + for (; i < length; ++i) { + row[i] = in[i] + GradientPredictor_C(row[i - 1], top[i], top[i - 1]); + } + } +} +#undef GRAD_PROCESS_LANE + +static void GradientUnfilter_NEON(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_NEON(NULL, in, out, width); + } else { + out[0] = in[0] + prev[0]; // predict from above + GradientPredictInverse_NEON(in + 1, prev + 1, out + 1, width - 1); + } +} + +#endif // USE_GRADIENT_UNFILTER + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8FiltersInitNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitNEON(void) { + WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_NEON; + WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_NEON; +#if (USE_GRADIENT_UNFILTER == 1) + WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_NEON; +#endif + + WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_NEON; + WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_NEON; + WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(VP8FiltersInitNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/filters_sse2.c b/libraries/webp/src/dsp/filters_sse2.c new file mode 100644 index 00000000000..bb4b5d58748 --- /dev/null +++ b/libraries/webp/src/dsp/filters_sse2.c @@ -0,0 +1,342 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 variant of alpha filters +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) + +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Helpful macro. + +#define DCHECK(in, out) \ + do { \ + assert((in) != NULL); \ + assert((out) != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(stride >= width); \ + assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ + (void)height; /* Silence unused warning. */ \ + } while (0) + +static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred, + uint8_t* dst, int length) { + int i; + const int max_pos = length & ~31; + assert(length >= 0); + for (i = 0; i < max_pos; i += 32) { + const __m128i A0 = _mm_loadu_si128((const __m128i*)&src[i + 0]); + const __m128i A1 = _mm_loadu_si128((const __m128i*)&src[i + 16]); + const __m128i B0 = _mm_loadu_si128((const __m128i*)&pred[i + 0]); + const __m128i B1 = _mm_loadu_si128((const __m128i*)&pred[i + 16]); + const __m128i C0 = _mm_sub_epi8(A0, B0); + const __m128i C1 = _mm_sub_epi8(A1, B1); + _mm_storeu_si128((__m128i*)&dst[i + 0], C0); + _mm_storeu_si128((__m128i*)&dst[i + 16], C1); + } + for (; i < length; ++i) dst[i] = src[i] - pred[i]; +} + +// Special case for left-based prediction (when preds==dst-1 or preds==src-1). +static void PredictLineLeft_SSE2(const uint8_t* src, uint8_t* dst, int length) { + int i; + const int max_pos = length & ~31; + assert(length >= 0); + for (i = 0; i < max_pos; i += 32) { + const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + i + 0 )); + const __m128i B0 = _mm_loadu_si128((const __m128i*)(src + i + 0 - 1)); + const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + i + 16 )); + const __m128i B1 = _mm_loadu_si128((const __m128i*)(src + i + 16 - 1)); + const __m128i C0 = _mm_sub_epi8(A0, B0); + const __m128i C1 = _mm_sub_epi8(A1, B1); + _mm_storeu_si128((__m128i*)(dst + i + 0), C0); + _mm_storeu_si128((__m128i*)(dst + i + 16), C1); + } + for (; i < length; ++i) dst[i] = src[i] - src[i - 1]; +} + +//------------------------------------------------------------------------------ +// Horizontal filter. + +static WEBP_INLINE void DoHorizontalFilter_SSE2(const uint8_t* in, + int width, int height, + int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + + if (row == 0) { + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLineLeft_SSE2(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + // Leftmost pixel is predicted from above. + out[0] = in[0] - in[-stride]; + PredictLineLeft_SSE2(in + 1, out + 1, width - 1); + ++row; + in += stride; + out += stride; + } +} + +//------------------------------------------------------------------------------ +// Vertical filter. + +static WEBP_INLINE void DoVerticalFilter_SSE2(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + + if (row == 0) { + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLineLeft_SSE2(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + PredictLineTop_SSE2(in, in - stride, out, width); + ++row; + in += stride; + out += stride; + } +} + +//------------------------------------------------------------------------------ +// Gradient filter. + +static WEBP_INLINE int GradientPredictor_SSE2(uint8_t a, uint8_t b, uint8_t c) { + const int g = a + b - c; + return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit +} + +static void GradientPredictDirect_SSE2(const uint8_t* const row, + const uint8_t* const top, + uint8_t* const out, int length) { + const int max_pos = length & ~7; + int i; + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i < max_pos; i += 8) { + const __m128i A0 = _mm_loadl_epi64((const __m128i*)&row[i - 1]); + const __m128i B0 = _mm_loadl_epi64((const __m128i*)&top[i]); + const __m128i C0 = _mm_loadl_epi64((const __m128i*)&top[i - 1]); + const __m128i D = _mm_loadl_epi64((const __m128i*)&row[i]); + const __m128i A1 = _mm_unpacklo_epi8(A0, zero); + const __m128i B1 = _mm_unpacklo_epi8(B0, zero); + const __m128i C1 = _mm_unpacklo_epi8(C0, zero); + const __m128i E = _mm_add_epi16(A1, B1); + const __m128i F = _mm_sub_epi16(E, C1); + const __m128i G = _mm_packus_epi16(F, zero); + const __m128i H = _mm_sub_epi8(D, G); + _mm_storel_epi64((__m128i*)(out + i), H); + } + for (; i < length; ++i) { + const int delta = GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]); + out[i] = (uint8_t)(row[i] - delta); + } +} + +static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in, + int width, int height, int stride, + int row, int num_rows, + uint8_t* out) { + const size_t start_offset = row * stride; + const int last_row = row + num_rows; + DCHECK(in, out); + in += start_offset; + out += start_offset; + + // left prediction for top scan-line + if (row == 0) { + out[0] = in[0]; + PredictLineLeft_SSE2(in + 1, out + 1, width - 1); + row = 1; + in += stride; + out += stride; + } + + // Filter line-by-line. + while (row < last_row) { + out[0] = (uint8_t)(in[0] - in[-stride]); + GradientPredictDirect_SSE2(in + 1, in + 1 - stride, out + 1, width - 1); + ++row; + in += stride; + out += stride; + } +} + +#undef DCHECK + +//------------------------------------------------------------------------------ + +static void HorizontalFilter_SSE2(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoHorizontalFilter_SSE2(data, width, height, stride, 0, height, + filtered_data); +} + +static void VerticalFilter_SSE2(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoVerticalFilter_SSE2(data, width, height, stride, 0, height, filtered_data); +} + +static void GradientFilter_SSE2(const uint8_t* data, int width, int height, + int stride, uint8_t* filtered_data) { + DoGradientFilter_SSE2(data, width, height, stride, 0, height, filtered_data); +} + +//------------------------------------------------------------------------------ +// Inverse transforms + +static void HorizontalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + int i; + __m128i last; + out[0] = (uint8_t)(in[0] + (prev == NULL ? 0 : prev[0])); + if (width <= 1) return; + last = _mm_set_epi32(0, 0, 0, out[0]); + for (i = 1; i + 8 <= width; i += 8) { + const __m128i A0 = _mm_loadl_epi64((const __m128i*)(in + i)); + const __m128i A1 = _mm_add_epi8(A0, last); + const __m128i A2 = _mm_slli_si128(A1, 1); + const __m128i A3 = _mm_add_epi8(A1, A2); + const __m128i A4 = _mm_slli_si128(A3, 2); + const __m128i A5 = _mm_add_epi8(A3, A4); + const __m128i A6 = _mm_slli_si128(A5, 4); + const __m128i A7 = _mm_add_epi8(A5, A6); + _mm_storel_epi64((__m128i*)(out + i), A7); + last = _mm_srli_epi64(A7, 56); + } + for (; i < width; ++i) out[i] = (uint8_t)(in[i] + out[i - 1]); +} + +static void VerticalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_SSE2(NULL, in, out, width); + } else { + int i; + const int max_pos = width & ~31; + assert(width >= 0); + for (i = 0; i < max_pos; i += 32) { + const __m128i A0 = _mm_loadu_si128((const __m128i*)&in[i + 0]); + const __m128i A1 = _mm_loadu_si128((const __m128i*)&in[i + 16]); + const __m128i B0 = _mm_loadu_si128((const __m128i*)&prev[i + 0]); + const __m128i B1 = _mm_loadu_si128((const __m128i*)&prev[i + 16]); + const __m128i C0 = _mm_add_epi8(A0, B0); + const __m128i C1 = _mm_add_epi8(A1, B1); + _mm_storeu_si128((__m128i*)&out[i + 0], C0); + _mm_storeu_si128((__m128i*)&out[i + 16], C1); + } + for (; i < width; ++i) out[i] = (uint8_t)(in[i] + prev[i]); + } +} + +static void GradientPredictInverse_SSE2(const uint8_t* const in, + const uint8_t* const top, + uint8_t* const row, int length) { + if (length > 0) { + int i; + const int max_pos = length & ~7; + const __m128i zero = _mm_setzero_si128(); + __m128i A = _mm_set_epi32(0, 0, 0, row[-1]); // left sample + for (i = 0; i < max_pos; i += 8) { + const __m128i tmp0 = _mm_loadl_epi64((const __m128i*)&top[i]); + const __m128i tmp1 = _mm_loadl_epi64((const __m128i*)&top[i - 1]); + const __m128i B = _mm_unpacklo_epi8(tmp0, zero); + const __m128i C = _mm_unpacklo_epi8(tmp1, zero); + const __m128i D = _mm_loadl_epi64((const __m128i*)&in[i]); // base input + const __m128i E = _mm_sub_epi16(B, C); // unclipped gradient basis B - C + __m128i out = zero; // accumulator for output + __m128i mask_hi = _mm_set_epi32(0, 0, 0, 0xff); + int k = 8; + while (1) { + const __m128i tmp3 = _mm_add_epi16(A, E); // delta = A + B - C + const __m128i tmp4 = _mm_packus_epi16(tmp3, zero); // saturate delta + const __m128i tmp5 = _mm_add_epi8(tmp4, D); // add to in[] + A = _mm_and_si128(tmp5, mask_hi); // 1-complement clip + out = _mm_or_si128(out, A); // accumulate output + if (--k == 0) break; + A = _mm_slli_si128(A, 1); // rotate left sample + mask_hi = _mm_slli_si128(mask_hi, 1); // rotate mask + A = _mm_unpacklo_epi8(A, zero); // convert 8b->16b + } + A = _mm_srli_si128(A, 7); // prepare left sample for next iteration + _mm_storel_epi64((__m128i*)&row[i], out); + } + for (; i < length; ++i) { + const int delta = GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]); + row[i] = (uint8_t)(in[i] + delta); + } + } +} + +static void GradientUnfilter_SSE2(const uint8_t* prev, const uint8_t* in, + uint8_t* out, int width) { + if (prev == NULL) { + HorizontalUnfilter_SSE2(NULL, in, out, width); + } else { + out[0] = (uint8_t)(in[0] + prev[0]); // predict from above + GradientPredictInverse_SSE2(in + 1, prev + 1, out + 1, width - 1); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8FiltersInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) { + WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_SSE2; +#if defined(CHROMIUM) + // TODO(crbug.com/654974) + (void)VerticalUnfilter_SSE2; +#else + WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_SSE2; +#endif + WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_SSE2; + + WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_SSE2; + WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_SSE2; + WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(VP8FiltersInitSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/lossless.c b/libraries/webp/src/dsp/lossless.c new file mode 100644 index 00000000000..9f812094539 --- /dev/null +++ b/libraries/webp/src/dsp/lossless.c @@ -0,0 +1,681 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Image transforms and color space conversion methods for lossless decoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) +// Urvang Joshi (urvang@google.com) + +#include "src/dsp/dsp.h" + +#include +#include +#include +#include "src/dec/vp8li_dec.h" +#include "src/utils/endian_inl_utils.h" +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" + +//------------------------------------------------------------------------------ +// Image transforms. + +static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) { + return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1); +} + +static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) { + return Average2(Average2(a0, a2), a1); +} + +static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1, + uint32_t a2, uint32_t a3) { + return Average2(Average2(a0, a1), Average2(a2, a3)); +} + +static WEBP_INLINE uint32_t Clip255(uint32_t a) { + if (a < 256) { + return a; + } + // return 0, when a is a negative integer. + // return 255, when a is positive. + return ~a >> 24; +} + +static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) { + return Clip255((uint32_t)(a + b - c)); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1, + uint32_t c2) { + const int a = AddSubtractComponentFull(c0 >> 24, c1 >> 24, c2 >> 24); + const int r = AddSubtractComponentFull((c0 >> 16) & 0xff, + (c1 >> 16) & 0xff, + (c2 >> 16) & 0xff); + const int g = AddSubtractComponentFull((c0 >> 8) & 0xff, + (c1 >> 8) & 0xff, + (c2 >> 8) & 0xff); + const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff); + return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b; +} + +static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) { + return Clip255((uint32_t)(a + (a - b) / 2)); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1, + uint32_t c2) { + const uint32_t ave = Average2(c0, c1); + const int a = AddSubtractComponentHalf(ave >> 24, c2 >> 24); + const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff); + const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff); + const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff); + return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b; +} + +// gcc <= 4.9 on ARM generates incorrect code in Select() when Sub3() is +// inlined. +#if defined(__arm__) && defined(__GNUC__) && LOCAL_GCC_VERSION <= 0x409 +# define LOCAL_INLINE __attribute__ ((noinline)) +#else +# define LOCAL_INLINE WEBP_INLINE +#endif + +static LOCAL_INLINE int Sub3(int a, int b, int c) { + const int pb = b - c; + const int pa = a - c; + return abs(pb) - abs(pa); +} + +#undef LOCAL_INLINE + +static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) { + const int pa_minus_pb = + Sub3((a >> 24) , (b >> 24) , (c >> 24) ) + + Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) + + Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) + + Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff); + return (pa_minus_pb <= 0) ? a : b; +} + +//------------------------------------------------------------------------------ +// Predictors + +uint32_t VP8LPredictor0_C(const uint32_t* const left, + const uint32_t* const top) { + (void)top; + (void)left; + return ARGB_BLACK; +} +uint32_t VP8LPredictor1_C(const uint32_t* const left, + const uint32_t* const top) { + (void)top; + return *left; +} +uint32_t VP8LPredictor2_C(const uint32_t* const left, + const uint32_t* const top) { + (void)left; + return top[0]; +} +uint32_t VP8LPredictor3_C(const uint32_t* const left, + const uint32_t* const top) { + (void)left; + return top[1]; +} +uint32_t VP8LPredictor4_C(const uint32_t* const left, + const uint32_t* const top) { + (void)left; + return top[-1]; +} +uint32_t VP8LPredictor5_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average3(*left, top[0], top[1]); + return pred; +} +uint32_t VP8LPredictor6_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average2(*left, top[-1]); + return pred; +} +uint32_t VP8LPredictor7_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average2(*left, top[0]); + return pred; +} +uint32_t VP8LPredictor8_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average2(top[-1], top[0]); + (void)left; + return pred; +} +uint32_t VP8LPredictor9_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average2(top[0], top[1]); + (void)left; + return pred; +} +uint32_t VP8LPredictor10_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average4(*left, top[-1], top[0], top[1]); + return pred; +} +uint32_t VP8LPredictor11_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Select(top[0], *left, top[-1]); + return pred; +} +uint32_t VP8LPredictor12_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = ClampedAddSubtractFull(*left, top[0], top[-1]); + return pred; +} +uint32_t VP8LPredictor13_C(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = ClampedAddSubtractHalf(*left, top[0], top[-1]); + return pred; +} + +static void PredictorAdd0_C(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int x; + (void)upper; + for (x = 0; x < num_pixels; ++x) out[x] = VP8LAddPixels(in[x], ARGB_BLACK); +} +static void PredictorAdd1_C(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint32_t left = out[-1]; + (void)upper; + for (i = 0; i < num_pixels; ++i) { + out[i] = left = VP8LAddPixels(in[i], left); + } +} +GENERATE_PREDICTOR_ADD(VP8LPredictor2_C, PredictorAdd2_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor3_C, PredictorAdd3_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor4_C, PredictorAdd4_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor5_C, PredictorAdd5_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor6_C, PredictorAdd6_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor7_C, PredictorAdd7_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor8_C, PredictorAdd8_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor9_C, PredictorAdd9_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor10_C, PredictorAdd10_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor11_C, PredictorAdd11_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor12_C, PredictorAdd12_C) +GENERATE_PREDICTOR_ADD(VP8LPredictor13_C, PredictorAdd13_C) + +//------------------------------------------------------------------------------ + +// Inverse prediction. +static void PredictorInverseTransform_C(const VP8LTransform* const transform, + int y_start, int y_end, + const uint32_t* in, uint32_t* out) { + const int width = transform->xsize_; + if (y_start == 0) { // First Row follows the L (mode=1) mode. + PredictorAdd0_C(in, NULL, 1, out); + PredictorAdd1_C(in + 1, NULL, width - 1, out + 1); + in += width; + out += width; + ++y_start; + } + + { + int y = y_start; + const int tile_width = 1 << transform->bits_; + const int mask = tile_width - 1; + const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); + const uint32_t* pred_mode_base = + transform->data_ + (y >> transform->bits_) * tiles_per_row; + + while (y < y_end) { + const uint32_t* pred_mode_src = pred_mode_base; + int x = 1; + // First pixel follows the T (mode=2) mode. + PredictorAdd2_C(in, out - width, 1, out); + // .. the rest: + while (x < width) { + const VP8LPredictorAddSubFunc pred_func = + VP8LPredictorsAdd[((*pred_mode_src++) >> 8) & 0xf]; + int x_end = (x & ~mask) + tile_width; + if (x_end > width) x_end = width; + pred_func(in + x, out + x - width, x_end - x, out + x); + x = x_end; + } + in += width; + out += width; + ++y; + if ((y & mask) == 0) { // Use the same mask, since tiles are squares. + pred_mode_base += tiles_per_row; + } + } + } +} + +// Add green to blue and red channels (i.e. perform the inverse transform of +// 'subtract green'). +void VP8LAddGreenToBlueAndRed_C(const uint32_t* src, int num_pixels, + uint32_t* dst) { + int i; + for (i = 0; i < num_pixels; ++i) { + const uint32_t argb = src[i]; + const uint32_t green = ((argb >> 8) & 0xff); + uint32_t red_blue = (argb & 0x00ff00ffu); + red_blue += (green << 16) | green; + red_blue &= 0x00ff00ffu; + dst[i] = (argb & 0xff00ff00u) | red_blue; + } +} + +static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, + int8_t color) { + return ((int)color_pred * color) >> 5; +} + +static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, + VP8LMultipliers* const m) { + m->green_to_red_ = (color_code >> 0) & 0xff; + m->green_to_blue_ = (color_code >> 8) & 0xff; + m->red_to_blue_ = (color_code >> 16) & 0xff; +} + +void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, + const uint32_t* src, int num_pixels, + uint32_t* dst) { + int i; + for (i = 0; i < num_pixels; ++i) { + const uint32_t argb = src[i]; + const int8_t green = (int8_t)(argb >> 8); + const uint32_t red = argb >> 16; + int new_red = red & 0xff; + int new_blue = argb & 0xff; + new_red += ColorTransformDelta((int8_t)m->green_to_red_, green); + new_red &= 0xff; + new_blue += ColorTransformDelta((int8_t)m->green_to_blue_, green); + new_blue += ColorTransformDelta((int8_t)m->red_to_blue_, (int8_t)new_red); + new_blue &= 0xff; + dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); + } +} + +// Color space inverse transform. +static void ColorSpaceInverseTransform_C(const VP8LTransform* const transform, + int y_start, int y_end, + const uint32_t* src, uint32_t* dst) { + const int width = transform->xsize_; + const int tile_width = 1 << transform->bits_; + const int mask = tile_width - 1; + const int safe_width = width & ~mask; + const int remaining_width = width - safe_width; + const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); + int y = y_start; + const uint32_t* pred_row = + transform->data_ + (y >> transform->bits_) * tiles_per_row; + + while (y < y_end) { + const uint32_t* pred = pred_row; + VP8LMultipliers m = { 0, 0, 0 }; + const uint32_t* const src_safe_end = src + safe_width; + const uint32_t* const src_end = src + width; + while (src < src_safe_end) { + ColorCodeToMultipliers(*pred++, &m); + VP8LTransformColorInverse(&m, src, tile_width, dst); + src += tile_width; + dst += tile_width; + } + if (src < src_end) { // Left-overs using C-version. + ColorCodeToMultipliers(*pred++, &m); + VP8LTransformColorInverse(&m, src, remaining_width, dst); + src += remaining_width; + dst += remaining_width; + } + ++y; + if ((y & mask) == 0) pred_row += tiles_per_row; + } +} + +// Separate out pixels packed together using pixel-bundling. +// We define two methods for ARGB data (uint32_t) and alpha-only data (uint8_t). +#define COLOR_INDEX_INVERSE(FUNC_NAME, F_NAME, STATIC_DECL, TYPE, BIT_SUFFIX, \ + GET_INDEX, GET_VALUE) \ +static void F_NAME(const TYPE* src, const uint32_t* const color_map, \ + TYPE* dst, int y_start, int y_end, int width) { \ + int y; \ + for (y = y_start; y < y_end; ++y) { \ + int x; \ + for (x = 0; x < width; ++x) { \ + *dst++ = GET_VALUE(color_map[GET_INDEX(*src++)]); \ + } \ + } \ +} \ +STATIC_DECL void FUNC_NAME(const VP8LTransform* const transform, \ + int y_start, int y_end, const TYPE* src, \ + TYPE* dst) { \ + int y; \ + const int bits_per_pixel = 8 >> transform->bits_; \ + const int width = transform->xsize_; \ + const uint32_t* const color_map = transform->data_; \ + if (bits_per_pixel < 8) { \ + const int pixels_per_byte = 1 << transform->bits_; \ + const int count_mask = pixels_per_byte - 1; \ + const uint32_t bit_mask = (1 << bits_per_pixel) - 1; \ + for (y = y_start; y < y_end; ++y) { \ + uint32_t packed_pixels = 0; \ + int x; \ + for (x = 0; x < width; ++x) { \ + /* We need to load fresh 'packed_pixels' once every */ \ + /* 'pixels_per_byte' increments of x. Fortunately, pixels_per_byte */ \ + /* is a power of 2, so can just use a mask for that, instead of */ \ + /* decrementing a counter. */ \ + if ((x & count_mask) == 0) packed_pixels = GET_INDEX(*src++); \ + *dst++ = GET_VALUE(color_map[packed_pixels & bit_mask]); \ + packed_pixels >>= bits_per_pixel; \ + } \ + } \ + } else { \ + VP8LMapColor##BIT_SUFFIX(src, color_map, dst, y_start, y_end, width); \ + } \ +} + +COLOR_INDEX_INVERSE(ColorIndexInverseTransform_C, MapARGB_C, static, + uint32_t, 32b, VP8GetARGBIndex, VP8GetARGBValue) +COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha_C, , + uint8_t, 8b, VP8GetAlphaIndex, VP8GetAlphaValue) + +#undef COLOR_INDEX_INVERSE + +void VP8LInverseTransform(const VP8LTransform* const transform, + int row_start, int row_end, + const uint32_t* const in, uint32_t* const out) { + const int width = transform->xsize_; + assert(row_start < row_end); + assert(row_end <= transform->ysize_); + switch (transform->type_) { + case SUBTRACT_GREEN_TRANSFORM: + VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out); + break; + case PREDICTOR_TRANSFORM: + PredictorInverseTransform_C(transform, row_start, row_end, in, out); + if (row_end != transform->ysize_) { + // The last predicted row in this iteration will be the top-pred row + // for the first row in next iteration. + memcpy(out - width, out + (row_end - row_start - 1) * width, + width * sizeof(*out)); + } + break; + case CROSS_COLOR_TRANSFORM: + ColorSpaceInverseTransform_C(transform, row_start, row_end, in, out); + break; + case COLOR_INDEXING_TRANSFORM: + if (in == out && transform->bits_ > 0) { + // Move packed pixels to the end of unpacked region, so that unpacking + // can occur seamlessly. + // Also, note that this is the only transform that applies on + // the effective width of VP8LSubSampleSize(xsize_, bits_). All other + // transforms work on effective width of xsize_. + const int out_stride = (row_end - row_start) * width; + const int in_stride = (row_end - row_start) * + VP8LSubSampleSize(transform->xsize_, transform->bits_); + uint32_t* const src = out + out_stride - in_stride; + memmove(src, out, in_stride * sizeof(*src)); + ColorIndexInverseTransform_C(transform, row_start, row_end, src, out); + } else { + ColorIndexInverseTransform_C(transform, row_start, row_end, in, out); + } + break; + } +} + +//------------------------------------------------------------------------------ +// Color space conversion. + +static int is_big_endian(void) { + static const union { + uint16_t w; + uint8_t b[2]; + } tmp = { 1 }; + return (tmp.b[0] != 1); +} + +void VP8LConvertBGRAToRGB_C(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + *dst++ = (argb >> 16) & 0xff; + *dst++ = (argb >> 8) & 0xff; + *dst++ = (argb >> 0) & 0xff; + } +} + +void VP8LConvertBGRAToRGBA_C(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + *dst++ = (argb >> 16) & 0xff; + *dst++ = (argb >> 8) & 0xff; + *dst++ = (argb >> 0) & 0xff; + *dst++ = (argb >> 24) & 0xff; + } +} + +void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + const uint8_t rg = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf); + const uint8_t ba = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf); +#if (WEBP_SWAP_16BIT_CSP == 1) + *dst++ = ba; + *dst++ = rg; +#else + *dst++ = rg; + *dst++ = ba; +#endif + } +} + +void VP8LConvertBGRAToRGB565_C(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + const uint8_t rg = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7); + const uint8_t gb = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f); +#if (WEBP_SWAP_16BIT_CSP == 1) + *dst++ = gb; + *dst++ = rg; +#else + *dst++ = rg; + *dst++ = gb; +#endif + } +} + +void VP8LConvertBGRAToBGR_C(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + *dst++ = (argb >> 0) & 0xff; + *dst++ = (argb >> 8) & 0xff; + *dst++ = (argb >> 16) & 0xff; + } +} + +static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst, + int swap_on_big_endian) { + if (is_big_endian() == swap_on_big_endian) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + WebPUint32ToMem(dst, BSwap32(argb)); + dst += sizeof(argb); + } + } else { + memcpy(dst, src, num_pixels * sizeof(*src)); + } +} + +void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, + WEBP_CSP_MODE out_colorspace, uint8_t* const rgba) { + switch (out_colorspace) { + case MODE_RGB: + VP8LConvertBGRAToRGB(in_data, num_pixels, rgba); + break; + case MODE_RGBA: + VP8LConvertBGRAToRGBA(in_data, num_pixels, rgba); + break; + case MODE_rgbA: + VP8LConvertBGRAToRGBA(in_data, num_pixels, rgba); + WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0); + break; + case MODE_BGR: + VP8LConvertBGRAToBGR(in_data, num_pixels, rgba); + break; + case MODE_BGRA: + CopyOrSwap(in_data, num_pixels, rgba, 1); + break; + case MODE_bgrA: + CopyOrSwap(in_data, num_pixels, rgba, 1); + WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0); + break; + case MODE_ARGB: + CopyOrSwap(in_data, num_pixels, rgba, 0); + break; + case MODE_Argb: + CopyOrSwap(in_data, num_pixels, rgba, 0); + WebPApplyAlphaMultiply(rgba, 1, num_pixels, 1, 0); + break; + case MODE_RGBA_4444: + VP8LConvertBGRAToRGBA4444(in_data, num_pixels, rgba); + break; + case MODE_rgbA_4444: + VP8LConvertBGRAToRGBA4444(in_data, num_pixels, rgba); + WebPApplyAlphaMultiply4444(rgba, num_pixels, 1, 0); + break; + case MODE_RGB_565: + VP8LConvertBGRAToRGB565(in_data, num_pixels, rgba); + break; + default: + assert(0); // Code flow should not reach here. + } +} + +//------------------------------------------------------------------------------ + +VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed; +VP8LPredictorAddSubFunc VP8LPredictorsAdd[16]; +VP8LPredictorFunc VP8LPredictors[16]; + +// exposed plain-C implementations +VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16]; + +VP8LTransformColorInverseFunc VP8LTransformColorInverse; + +VP8LConvertFunc VP8LConvertBGRAToRGB; +VP8LConvertFunc VP8LConvertBGRAToRGBA; +VP8LConvertFunc VP8LConvertBGRAToRGBA4444; +VP8LConvertFunc VP8LConvertBGRAToRGB565; +VP8LConvertFunc VP8LConvertBGRAToBGR; + +VP8LMapARGBFunc VP8LMapColor32b; +VP8LMapAlphaFunc VP8LMapColor8b; + +extern VP8CPUInfo VP8GetCPUInfo; +extern void VP8LDspInitSSE2(void); +extern void VP8LDspInitSSE41(void); +extern void VP8LDspInitNEON(void); +extern void VP8LDspInitMIPSdspR2(void); +extern void VP8LDspInitMSA(void); + +#define COPY_PREDICTOR_ARRAY(IN, OUT) do { \ + (OUT)[0] = IN##0_C; \ + (OUT)[1] = IN##1_C; \ + (OUT)[2] = IN##2_C; \ + (OUT)[3] = IN##3_C; \ + (OUT)[4] = IN##4_C; \ + (OUT)[5] = IN##5_C; \ + (OUT)[6] = IN##6_C; \ + (OUT)[7] = IN##7_C; \ + (OUT)[8] = IN##8_C; \ + (OUT)[9] = IN##9_C; \ + (OUT)[10] = IN##10_C; \ + (OUT)[11] = IN##11_C; \ + (OUT)[12] = IN##12_C; \ + (OUT)[13] = IN##13_C; \ + (OUT)[14] = IN##0_C; /* <- padding security sentinels*/ \ + (OUT)[15] = IN##0_C; \ +} while (0); + +WEBP_DSP_INIT_FUNC(VP8LDspInit) { + COPY_PREDICTOR_ARRAY(VP8LPredictor, VP8LPredictors) + COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd) + COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd_C) + +#if !WEBP_NEON_OMIT_C_CODE + VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C; + + VP8LTransformColorInverse = VP8LTransformColorInverse_C; + + VP8LConvertBGRAToRGBA = VP8LConvertBGRAToRGBA_C; + VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C; + VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C; +#endif + + VP8LConvertBGRAToRGBA4444 = VP8LConvertBGRAToRGBA4444_C; + VP8LConvertBGRAToRGB565 = VP8LConvertBGRAToRGB565_C; + + VP8LMapColor32b = MapARGB_C; + VP8LMapColor8b = MapAlpha_C; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8LDspInitSSE2(); +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + VP8LDspInitSSE41(); + } +#endif + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + VP8LDspInitMIPSdspR2(); + } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8LDspInitMSA(); + } +#endif + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + VP8LDspInitNEON(); + } +#endif + + assert(VP8LAddGreenToBlueAndRed != NULL); + assert(VP8LTransformColorInverse != NULL); + assert(VP8LConvertBGRAToRGBA != NULL); + assert(VP8LConvertBGRAToRGB != NULL); + assert(VP8LConvertBGRAToBGR != NULL); + assert(VP8LConvertBGRAToRGBA4444 != NULL); + assert(VP8LConvertBGRAToRGB565 != NULL); + assert(VP8LMapColor32b != NULL); + assert(VP8LMapColor8b != NULL); +} +#undef COPY_PREDICTOR_ARRAY + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dsp/lossless.h b/libraries/webp/src/dsp/lossless.h new file mode 100644 index 00000000000..fac0ec65116 --- /dev/null +++ b/libraries/webp/src/dsp/lossless.h @@ -0,0 +1,259 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Image transforms and color space conversion methods for lossless decoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) + +#ifndef WEBP_DSP_LOSSLESS_H_ +#define WEBP_DSP_LOSSLESS_H_ + +#include "include/webp/types.h" +#include "include/webp/decode.h" + +#include "src/enc/histogram_enc.h" +#include "src/utils/utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Decoding + +typedef uint32_t (*VP8LPredictorFunc)(const uint32_t* const left, + const uint32_t* const top); +extern VP8LPredictorFunc VP8LPredictors[16]; + +uint32_t VP8LPredictor0_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor1_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor2_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor3_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor4_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor5_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor6_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor7_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor8_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor9_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor10_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor11_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor12_C(const uint32_t* const left, + const uint32_t* const top); +uint32_t VP8LPredictor13_C(const uint32_t* const left, + const uint32_t* const top); + +// These Add/Sub function expects upper[-1] and out[-1] to be readable. +typedef void (*VP8LPredictorAddSubFunc)(const uint32_t* in, + const uint32_t* upper, int num_pixels, + uint32_t* out); +extern VP8LPredictorAddSubFunc VP8LPredictorsAdd[16]; +extern VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16]; + +typedef void (*VP8LProcessDecBlueAndRedFunc)(const uint32_t* src, + int num_pixels, uint32_t* dst); +extern VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed; + +typedef struct { + // Note: the members are uint8_t, so that any negative values are + // automatically converted to "mod 256" values. + uint8_t green_to_red_; + uint8_t green_to_blue_; + uint8_t red_to_blue_; +} VP8LMultipliers; +typedef void (*VP8LTransformColorInverseFunc)(const VP8LMultipliers* const m, + const uint32_t* src, + int num_pixels, uint32_t* dst); +extern VP8LTransformColorInverseFunc VP8LTransformColorInverse; + +struct VP8LTransform; // Defined in dec/vp8li.h. + +// Performs inverse transform of data given transform information, start and end +// rows. Transform will be applied to rows [row_start, row_end[. +// The *in and *out pointers refer to source and destination data respectively +// corresponding to the intermediate row (row_start). +void VP8LInverseTransform(const struct VP8LTransform* const transform, + int row_start, int row_end, + const uint32_t* const in, uint32_t* const out); + +// Color space conversion. +typedef void (*VP8LConvertFunc)(const uint32_t* src, int num_pixels, + uint8_t* dst); +extern VP8LConvertFunc VP8LConvertBGRAToRGB; +extern VP8LConvertFunc VP8LConvertBGRAToRGBA; +extern VP8LConvertFunc VP8LConvertBGRAToRGBA4444; +extern VP8LConvertFunc VP8LConvertBGRAToRGB565; +extern VP8LConvertFunc VP8LConvertBGRAToBGR; + +// Converts from BGRA to other color spaces. +void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, + WEBP_CSP_MODE out_colorspace, uint8_t* const rgba); + +typedef void (*VP8LMapARGBFunc)(const uint32_t* src, + const uint32_t* const color_map, + uint32_t* dst, int y_start, + int y_end, int width); +typedef void (*VP8LMapAlphaFunc)(const uint8_t* src, + const uint32_t* const color_map, + uint8_t* dst, int y_start, + int y_end, int width); + +extern VP8LMapARGBFunc VP8LMapColor32b; +extern VP8LMapAlphaFunc VP8LMapColor8b; + +// Similar to the static method ColorIndexInverseTransform() that is part of +// lossless.c, but used only for alpha decoding. It takes uint8_t (rather than +// uint32_t) arguments for 'src' and 'dst'. +void VP8LColorIndexInverseTransformAlpha( + const struct VP8LTransform* const transform, int y_start, int y_end, + const uint8_t* src, uint8_t* dst); + +// Expose some C-only fallback functions +void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, + const uint32_t* src, int num_pixels, + uint32_t* dst); + +void VP8LConvertBGRAToRGB_C(const uint32_t* src, int num_pixels, uint8_t* dst); +void VP8LConvertBGRAToRGBA_C(const uint32_t* src, int num_pixels, uint8_t* dst); +void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src, + int num_pixels, uint8_t* dst); +void VP8LConvertBGRAToRGB565_C(const uint32_t* src, + int num_pixels, uint8_t* dst); +void VP8LConvertBGRAToBGR_C(const uint32_t* src, int num_pixels, uint8_t* dst); +void VP8LAddGreenToBlueAndRed_C(const uint32_t* src, int num_pixels, + uint32_t* dst); + +// Must be called before calling any of the above methods. +void VP8LDspInit(void); + +//------------------------------------------------------------------------------ +// Encoding + +typedef void (*VP8LProcessEncBlueAndRedFunc)(uint32_t* dst, int num_pixels); +extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; +typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m, + uint32_t* dst, int num_pixels); +extern VP8LTransformColorFunc VP8LTransformColor; +typedef void (*VP8LCollectColorBlueTransformsFunc)( + const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_blue, int red_to_blue, int histo[]); +extern VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms; + +typedef void (*VP8LCollectColorRedTransformsFunc)( + const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_red, int histo[]); +extern VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms; + +// Expose some C-only fallback functions +void VP8LTransformColor_C(const VP8LMultipliers* const m, + uint32_t* data, int num_pixels); +void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels); +void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_red, int histo[]); +void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_blue, int red_to_blue, + int histo[]); + +extern VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; +extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; + +// ----------------------------------------------------------------------------- +// Huffman-cost related functions. + +typedef uint32_t (*VP8LCostFunc)(const uint32_t* population, int length); +typedef uint32_t (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y, + int length); +typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256], + const int Y[256]); + +extern VP8LCostFunc VP8LExtraCost; +extern VP8LCostCombinedFunc VP8LExtraCostCombined; +extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; + +typedef struct { // small struct to hold counters + int counts[2]; // index: 0=zero streak, 1=non-zero streak + int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3] +} VP8LStreaks; + +typedef struct { // small struct to hold bit entropy results + float entropy; // entropy + uint32_t sum; // sum of the population + int nonzeros; // number of non-zero elements in the population + uint32_t max_val; // maximum value in the population + uint32_t nonzero_code; // index of the last non-zero in the population +} VP8LBitEntropy; + +void VP8LBitEntropyInit(VP8LBitEntropy* const entropy); + +// Get the combined symbol bit entropy and Huffman cost stats for the +// distributions 'X' and 'Y'. Those results can then be refined according to +// codec specific heuristics. +typedef void (*VP8LGetCombinedEntropyUnrefinedFunc)( + const uint32_t X[], const uint32_t Y[], int length, + VP8LBitEntropy* const bit_entropy, VP8LStreaks* const stats); +extern VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined; + +// Get the entropy for the distribution 'X'. +typedef void (*VP8LGetEntropyUnrefinedFunc)(const uint32_t X[], int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats); +extern VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; + +void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, + VP8LBitEntropy* const entropy); + +typedef void (*VP8LAddVectorFunc)(const uint32_t* a, const uint32_t* b, + uint32_t* out, int size); +extern VP8LAddVectorFunc VP8LAddVector; +typedef void (*VP8LAddVectorEqFunc)(const uint32_t* a, uint32_t* out, int size); +extern VP8LAddVectorEqFunc VP8LAddVectorEq; +void VP8LHistogramAdd(const VP8LHistogram* const a, + const VP8LHistogram* const b, + VP8LHistogram* const out); + +// ----------------------------------------------------------------------------- +// PrefixEncode() + +typedef int (*VP8LVectorMismatchFunc)(const uint32_t* const array1, + const uint32_t* const array2, int length); +// Returns the first index where array1 and array2 are different. +extern VP8LVectorMismatchFunc VP8LVectorMismatch; + +typedef void (*VP8LBundleColorMapFunc)(const uint8_t* const row, int width, + int xbits, uint32_t* dst); +extern VP8LBundleColorMapFunc VP8LBundleColorMap; +void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits, + uint32_t* dst); + +// Must be called before calling any of the above methods. +void VP8LEncDspInit(void); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_LOSSLESS_H_ diff --git a/libraries/webp/src/dsp/lossless_common.h b/libraries/webp/src/dsp/lossless_common.h new file mode 100644 index 00000000000..8f16b5da66e --- /dev/null +++ b/libraries/webp/src/dsp/lossless_common.h @@ -0,0 +1,191 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Image transforms and color space conversion methods for lossless decoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) +// Vincent Rabaud (vrabaud@google.com) + +#ifndef WEBP_DSP_LOSSLESS_COMMON_H_ +#define WEBP_DSP_LOSSLESS_COMMON_H_ + +#include "src/dsp/cpu.h" +#include "src/utils/utils.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Decoding + +// color mapping related functions. +static WEBP_INLINE uint32_t VP8GetARGBIndex(uint32_t idx) { + return (idx >> 8) & 0xff; +} + +static WEBP_INLINE uint8_t VP8GetAlphaIndex(uint8_t idx) { + return idx; +} + +static WEBP_INLINE uint32_t VP8GetARGBValue(uint32_t val) { + return val; +} + +static WEBP_INLINE uint8_t VP8GetAlphaValue(uint32_t val) { + return (val >> 8) & 0xff; +} + +//------------------------------------------------------------------------------ +// Misc methods. + +// Computes sampled size of 'size' when sampling using 'sampling bits'. +static WEBP_INLINE uint32_t VP8LSubSampleSize(uint32_t size, + uint32_t sampling_bits) { + return (size + (1 << sampling_bits) - 1) >> sampling_bits; +} + +// Converts near lossless quality into max number of bits shaved off. +static WEBP_INLINE int VP8LNearLosslessBits(int near_lossless_quality) { + // 100 -> 0 + // 80..99 -> 1 + // 60..79 -> 2 + // 40..59 -> 3 + // 20..39 -> 4 + // 0..19 -> 5 + return 5 - near_lossless_quality / 20; +} + +// ----------------------------------------------------------------------------- +// Faster logarithm for integers. Small values use a look-up table. + +// The threshold till approximate version of log_2 can be used. +// Practically, we can get rid of the call to log() as the two values match to +// very high degree (the ratio of these two is 0.99999x). +// Keeping a high threshold for now. +#define APPROX_LOG_WITH_CORRECTION_MAX 65536 +#define APPROX_LOG_MAX 4096 +#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086 +#define LOG_LOOKUP_IDX_MAX 256 +extern const float kLog2Table[LOG_LOOKUP_IDX_MAX]; +extern const float kSLog2Table[LOG_LOOKUP_IDX_MAX]; +typedef float (*VP8LFastLog2SlowFunc)(uint32_t v); + +extern VP8LFastLog2SlowFunc VP8LFastLog2Slow; +extern VP8LFastLog2SlowFunc VP8LFastSLog2Slow; + +static WEBP_INLINE float VP8LFastLog2(uint32_t v) { + return (v < LOG_LOOKUP_IDX_MAX) ? kLog2Table[v] : VP8LFastLog2Slow(v); +} +// Fast calculation of v * log2(v) for integer input. +static WEBP_INLINE float VP8LFastSLog2(uint32_t v) { + return (v < LOG_LOOKUP_IDX_MAX) ? kSLog2Table[v] : VP8LFastSLog2Slow(v); +} + +// ----------------------------------------------------------------------------- +// PrefixEncode() + +// Splitting of distance and length codes into prefixes and +// extra bits. The prefixes are encoded with an entropy code +// while the extra bits are stored just as normal bits. +static WEBP_INLINE void VP8LPrefixEncodeBitsNoLUT(int distance, int* const code, + int* const extra_bits) { + const int highest_bit = BitsLog2Floor(--distance); + const int second_highest_bit = (distance >> (highest_bit - 1)) & 1; + *extra_bits = highest_bit - 1; + *code = 2 * highest_bit + second_highest_bit; +} + +static WEBP_INLINE void VP8LPrefixEncodeNoLUT(int distance, int* const code, + int* const extra_bits, + int* const extra_bits_value) { + const int highest_bit = BitsLog2Floor(--distance); + const int second_highest_bit = (distance >> (highest_bit - 1)) & 1; + *extra_bits = highest_bit - 1; + *extra_bits_value = distance & ((1 << *extra_bits) - 1); + *code = 2 * highest_bit + second_highest_bit; +} + +#define PREFIX_LOOKUP_IDX_MAX 512 +typedef struct { + int8_t code_; + int8_t extra_bits_; +} VP8LPrefixCode; + +// These tables are derived using VP8LPrefixEncodeNoLUT. +extern const VP8LPrefixCode kPrefixEncodeCode[PREFIX_LOOKUP_IDX_MAX]; +extern const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX]; +static WEBP_INLINE void VP8LPrefixEncodeBits(int distance, int* const code, + int* const extra_bits) { + if (distance < PREFIX_LOOKUP_IDX_MAX) { + const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; + *code = prefix_code.code_; + *extra_bits = prefix_code.extra_bits_; + } else { + VP8LPrefixEncodeBitsNoLUT(distance, code, extra_bits); + } +} + +static WEBP_INLINE void VP8LPrefixEncode(int distance, int* const code, + int* const extra_bits, + int* const extra_bits_value) { + if (distance < PREFIX_LOOKUP_IDX_MAX) { + const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; + *code = prefix_code.code_; + *extra_bits = prefix_code.extra_bits_; + *extra_bits_value = kPrefixEncodeExtraBitsValue[distance]; + } else { + VP8LPrefixEncodeNoLUT(distance, code, extra_bits, extra_bits_value); + } +} + +// Sum of each component, mod 256. +static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE +uint32_t VP8LAddPixels(uint32_t a, uint32_t b) { + const uint32_t alpha_and_green = (a & 0xff00ff00u) + (b & 0xff00ff00u); + const uint32_t red_and_blue = (a & 0x00ff00ffu) + (b & 0x00ff00ffu); + return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); +} + +// Difference of each component, mod 256. +static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE +uint32_t VP8LSubPixels(uint32_t a, uint32_t b) { + const uint32_t alpha_and_green = + 0x00ff00ffu + (a & 0xff00ff00u) - (b & 0xff00ff00u); + const uint32_t red_and_blue = + 0xff00ff00u + (a & 0x00ff00ffu) - (b & 0x00ff00ffu); + return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); +} + +//------------------------------------------------------------------------------ +// Transform-related functions used in both encoding and decoding. + +// Macros used to create a batch predictor that iteratively uses a +// one-pixel predictor. + +// The predictor is added to the output pixel (which +// is therefore considered as a residual) to get the final prediction. +#define GENERATE_PREDICTOR_ADD(PREDICTOR, PREDICTOR_ADD) \ +static void PREDICTOR_ADD(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int x; \ + assert(upper != NULL); \ + for (x = 0; x < num_pixels; ++x) { \ + const uint32_t pred = (PREDICTOR)(&out[x - 1], upper + x); \ + out[x] = VP8LAddPixels(in[x], pred); \ + } \ +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_LOSSLESS_COMMON_H_ diff --git a/libraries/webp/src/dsp/lossless_enc.c b/libraries/webp/src/dsp/lossless_enc.c new file mode 100644 index 00000000000..997d56c2ad3 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_enc.c @@ -0,0 +1,954 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Image transform methods for lossless encoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) +// Urvang Joshi (urvang@google.com) + +#include "src/dsp/dsp.h" + +#include +#include +#include +#include "src/dec/vp8li_dec.h" +#include "src/utils/endian_inl_utils.h" +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" +#include "src/dsp/yuv.h" + +// lookup table for small values of log2(int) +const float kLog2Table[LOG_LOOKUP_IDX_MAX] = { + 0.0000000000000000f, 0.0000000000000000f, + 1.0000000000000000f, 1.5849625007211560f, + 2.0000000000000000f, 2.3219280948873621f, + 2.5849625007211560f, 2.8073549220576041f, + 3.0000000000000000f, 3.1699250014423121f, + 3.3219280948873621f, 3.4594316186372973f, + 3.5849625007211560f, 3.7004397181410921f, + 3.8073549220576041f, 3.9068905956085187f, + 4.0000000000000000f, 4.0874628412503390f, + 4.1699250014423121f, 4.2479275134435852f, + 4.3219280948873626f, 4.3923174227787606f, + 4.4594316186372973f, 4.5235619560570130f, + 4.5849625007211560f, 4.6438561897747243f, + 4.7004397181410917f, 4.7548875021634682f, + 4.8073549220576037f, 4.8579809951275718f, + 4.9068905956085187f, 4.9541963103868749f, + 5.0000000000000000f, 5.0443941193584533f, + 5.0874628412503390f, 5.1292830169449663f, + 5.1699250014423121f, 5.2094533656289501f, + 5.2479275134435852f, 5.2854022188622487f, + 5.3219280948873626f, 5.3575520046180837f, + 5.3923174227787606f, 5.4262647547020979f, + 5.4594316186372973f, 5.4918530963296747f, + 5.5235619560570130f, 5.5545888516776376f, + 5.5849625007211560f, 5.6147098441152083f, + 5.6438561897747243f, 5.6724253419714951f, + 5.7004397181410917f, 5.7279204545631987f, + 5.7548875021634682f, 5.7813597135246599f, + 5.8073549220576037f, 5.8328900141647412f, + 5.8579809951275718f, 5.8826430493618415f, + 5.9068905956085187f, 5.9307373375628866f, + 5.9541963103868749f, 5.9772799234999167f, + 6.0000000000000000f, 6.0223678130284543f, + 6.0443941193584533f, 6.0660891904577720f, + 6.0874628412503390f, 6.1085244567781691f, + 6.1292830169449663f, 6.1497471195046822f, + 6.1699250014423121f, 6.1898245588800175f, + 6.2094533656289501f, 6.2288186904958804f, + 6.2479275134435852f, 6.2667865406949010f, + 6.2854022188622487f, 6.3037807481771030f, + 6.3219280948873626f, 6.3398500028846243f, + 6.3575520046180837f, 6.3750394313469245f, + 6.3923174227787606f, 6.4093909361377017f, + 6.4262647547020979f, 6.4429434958487279f, + 6.4594316186372973f, 6.4757334309663976f, + 6.4918530963296747f, 6.5077946401986963f, + 6.5235619560570130f, 6.5391588111080309f, + 6.5545888516776376f, 6.5698556083309478f, + 6.5849625007211560f, 6.5999128421871278f, + 6.6147098441152083f, 6.6293566200796094f, + 6.6438561897747243f, 6.6582114827517946f, + 6.6724253419714951f, 6.6865005271832185f, + 6.7004397181410917f, 6.7142455176661224f, + 6.7279204545631987f, 6.7414669864011464f, + 6.7548875021634682f, 6.7681843247769259f, + 6.7813597135246599f, 6.7944158663501061f, + 6.8073549220576037f, 6.8201789624151878f, + 6.8328900141647412f, 6.8454900509443747f, + 6.8579809951275718f, 6.8703647195834047f, + 6.8826430493618415f, 6.8948177633079437f, + 6.9068905956085187f, 6.9188632372745946f, + 6.9307373375628866f, 6.9425145053392398f, + 6.9541963103868749f, 6.9657842846620869f, + 6.9772799234999167f, 6.9886846867721654f, + 7.0000000000000000f, 7.0112272554232539f, + 7.0223678130284543f, 7.0334230015374501f, + 7.0443941193584533f, 7.0552824355011898f, + 7.0660891904577720f, 7.0768155970508308f, + 7.0874628412503390f, 7.0980320829605263f, + 7.1085244567781691f, 7.1189410727235076f, + 7.1292830169449663f, 7.1395513523987936f, + 7.1497471195046822f, 7.1598713367783890f, + 7.1699250014423121f, 7.1799090900149344f, + 7.1898245588800175f, 7.1996723448363644f, + 7.2094533656289501f, 7.2191685204621611f, + 7.2288186904958804f, 7.2384047393250785f, + 7.2479275134435852f, 7.2573878426926521f, + 7.2667865406949010f, 7.2761244052742375f, + 7.2854022188622487f, 7.2946207488916270f, + 7.3037807481771030f, 7.3128829552843557f, + 7.3219280948873626f, 7.3309168781146167f, + 7.3398500028846243f, 7.3487281542310771f, + 7.3575520046180837f, 7.3663222142458160f, + 7.3750394313469245f, 7.3837042924740519f, + 7.3923174227787606f, 7.4008794362821843f, + 7.4093909361377017f, 7.4178525148858982f, + 7.4262647547020979f, 7.4346282276367245f, + 7.4429434958487279f, 7.4512111118323289f, + 7.4594316186372973f, 7.4676055500829976f, + 7.4757334309663976f, 7.4838157772642563f, + 7.4918530963296747f, 7.4998458870832056f, + 7.5077946401986963f, 7.5156998382840427f, + 7.5235619560570130f, 7.5313814605163118f, + 7.5391588111080309f, 7.5468944598876364f, + 7.5545888516776376f, 7.5622424242210728f, + 7.5698556083309478f, 7.5774288280357486f, + 7.5849625007211560f, 7.5924570372680806f, + 7.5999128421871278f, 7.6073303137496104f, + 7.6147098441152083f, 7.6220518194563764f, + 7.6293566200796094f, 7.6366246205436487f, + 7.6438561897747243f, 7.6510516911789281f, + 7.6582114827517946f, 7.6653359171851764f, + 7.6724253419714951f, 7.6794800995054464f, + 7.6865005271832185f, 7.6934869574993252f, + 7.7004397181410917f, 7.7073591320808825f, + 7.7142455176661224f, 7.7210991887071855f, + 7.7279204545631987f, 7.7347096202258383f, + 7.7414669864011464f, 7.7481928495894605f, + 7.7548875021634682f, 7.7615512324444795f, + 7.7681843247769259f, 7.7747870596011736f, + 7.7813597135246599f, 7.7879025593914317f, + 7.7944158663501061f, 7.8008998999203047f, + 7.8073549220576037f, 7.8137811912170374f, + 7.8201789624151878f, 7.8265484872909150f, + 7.8328900141647412f, 7.8392037880969436f, + 7.8454900509443747f, 7.8517490414160571f, + 7.8579809951275718f, 7.8641861446542797f, + 7.8703647195834047f, 7.8765169465649993f, + 7.8826430493618415f, 7.8887432488982591f, + 7.8948177633079437f, 7.9008668079807486f, + 7.9068905956085187f, 7.9128893362299619f, + 7.9188632372745946f, 7.9248125036057812f, + 7.9307373375628866f, 7.9366379390025709f, + 7.9425145053392398f, 7.9483672315846778f, + 7.9541963103868749f, 7.9600019320680805f, + 7.9657842846620869f, 7.9715435539507719f, + 7.9772799234999167f, 7.9829935746943103f, + 7.9886846867721654f, 7.9943534368588577f +}; + +const float kSLog2Table[LOG_LOOKUP_IDX_MAX] = { + 0.00000000f, 0.00000000f, 2.00000000f, 4.75488750f, + 8.00000000f, 11.60964047f, 15.50977500f, 19.65148445f, + 24.00000000f, 28.52932501f, 33.21928095f, 38.05374781f, + 43.01955001f, 48.10571634f, 53.30296891f, 58.60335893f, + 64.00000000f, 69.48686830f, 75.05865003f, 80.71062276f, + 86.43856190f, 92.23866588f, 98.10749561f, 104.04192499f, + 110.03910002f, 116.09640474f, 122.21143267f, 128.38196256f, + 134.60593782f, 140.88144886f, 147.20671787f, 153.58008562f, + 160.00000000f, 166.46500594f, 172.97373660f, 179.52490559f, + 186.11730005f, 192.74977453f, 199.42124551f, 206.13068654f, + 212.87712380f, 219.65963219f, 226.47733176f, 233.32938445f, + 240.21499122f, 247.13338933f, 254.08384998f, 261.06567603f, + 268.07820003f, 275.12078236f, 282.19280949f, 289.29369244f, + 296.42286534f, 303.57978409f, 310.76392512f, 317.97478424f, + 325.21187564f, 332.47473081f, 339.76289772f, 347.07593991f, + 354.41343574f, 361.77497759f, 369.16017124f, 376.56863518f, + 384.00000000f, 391.45390785f, 398.93001188f, 406.42797576f, + 413.94747321f, 421.48818752f, 429.04981119f, 436.63204548f, + 444.23460010f, 451.85719280f, 459.49954906f, 467.16140179f, + 474.84249102f, 482.54256363f, 490.26137307f, 497.99867911f, + 505.75424759f, 513.52785023f, 521.31926438f, 529.12827280f, + 536.95466351f, 544.79822957f, 552.65876890f, 560.53608414f, + 568.42998244f, 576.34027536f, 584.26677867f, 592.20931226f, + 600.16769996f, 608.14176943f, 616.13135206f, 624.13628279f, + 632.15640007f, 640.19154569f, 648.24156472f, 656.30630539f, + 664.38561898f, 672.47935976f, 680.58738488f, 688.70955430f, + 696.84573069f, 704.99577935f, 713.15956818f, 721.33696754f, + 729.52785023f, 737.73209140f, 745.94956849f, 754.18016116f, + 762.42375127f, 770.68022275f, 778.94946161f, 787.23135586f, + 795.52579543f, 803.83267219f, 812.15187982f, 820.48331383f, + 828.82687147f, 837.18245171f, 845.54995518f, 853.92928416f, + 862.32034249f, 870.72303558f, 879.13727036f, 887.56295522f, + 896.00000000f, 904.44831595f, 912.90781569f, 921.37841320f, + 929.86002376f, 938.35256392f, 946.85595152f, 955.37010560f, + 963.89494641f, 972.43039537f, 980.97637504f, 989.53280911f, + 998.09962237f, 1006.67674069f, 1015.26409097f, 1023.86160116f, + 1032.46920021f, 1041.08681805f, 1049.71438560f, 1058.35183469f, + 1066.99909811f, 1075.65610955f, 1084.32280357f, 1092.99911564f, + 1101.68498204f, 1110.38033993f, 1119.08512727f, 1127.79928282f, + 1136.52274614f, 1145.25545758f, 1153.99735821f, 1162.74838989f, + 1171.50849518f, 1180.27761738f, 1189.05570047f, 1197.84268914f, + 1206.63852876f, 1215.44316535f, 1224.25654560f, 1233.07861684f, + 1241.90932703f, 1250.74862473f, 1259.59645914f, 1268.45278005f, + 1277.31753781f, 1286.19068338f, 1295.07216828f, 1303.96194457f, + 1312.85996488f, 1321.76618236f, 1330.68055071f, 1339.60302413f, + 1348.53355734f, 1357.47210556f, 1366.41862452f, 1375.37307041f, + 1384.33539991f, 1393.30557020f, 1402.28353887f, 1411.26926400f, + 1420.26270412f, 1429.26381818f, 1438.27256558f, 1447.28890615f, + 1456.31280014f, 1465.34420819f, 1474.38309138f, 1483.42941118f, + 1492.48312945f, 1501.54420843f, 1510.61261078f, 1519.68829949f, + 1528.77123795f, 1537.86138993f, 1546.95871952f, 1556.06319119f, + 1565.17476976f, 1574.29342040f, 1583.41910860f, 1592.55180020f, + 1601.69146137f, 1610.83805860f, 1619.99155871f, 1629.15192882f, + 1638.31913637f, 1647.49314911f, 1656.67393509f, 1665.86146266f, + 1675.05570047f, 1684.25661744f, 1693.46418280f, 1702.67836605f, + 1711.89913698f, 1721.12646563f, 1730.36032233f, 1739.60067768f, + 1748.84750254f, 1758.10076802f, 1767.36044551f, 1776.62650662f, + 1785.89892323f, 1795.17766747f, 1804.46271172f, 1813.75402857f, + 1823.05159087f, 1832.35537170f, 1841.66534438f, 1850.98148244f, + 1860.30375965f, 1869.63214999f, 1878.96662767f, 1888.30716711f, + 1897.65374295f, 1907.00633003f, 1916.36490342f, 1925.72943838f, + 1935.09991037f, 1944.47629506f, 1953.85856831f, 1963.24670620f, + 1972.64068498f, 1982.04048108f, 1991.44607117f, 2000.85743204f, + 2010.27454072f, 2019.69737440f, 2029.12591044f, 2038.56012640f +}; + +const VP8LPrefixCode kPrefixEncodeCode[PREFIX_LOOKUP_IDX_MAX] = { + { 0, 0}, { 0, 0}, { 1, 0}, { 2, 0}, { 3, 0}, { 4, 1}, { 4, 1}, { 5, 1}, + { 5, 1}, { 6, 2}, { 6, 2}, { 6, 2}, { 6, 2}, { 7, 2}, { 7, 2}, { 7, 2}, + { 7, 2}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, + { 8, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, + { 9, 3}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, + {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, + {10, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, + {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, + {11, 4}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, + {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, + {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, + {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, + {12, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, + {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, + {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, + {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, + {13, 5}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, + {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, + {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, + {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, + {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, + {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, + {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, + {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, + {14, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, + {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, + {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, + {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, + {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, + {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, + {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, + {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, + {15, 6}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, + {16, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, +}; + +const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX] = { + 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, + 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126 +}; + +static float FastSLog2Slow_C(uint32_t v) { + assert(v >= LOG_LOOKUP_IDX_MAX); + if (v < APPROX_LOG_WITH_CORRECTION_MAX) { +#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ) + // use clz if available + const int log_cnt = BitsLog2Floor(v) - 7; + const uint32_t y = 1 << log_cnt; + int correction = 0; + const float v_f = (float)v; + const uint32_t orig_v = v; + v >>= log_cnt; +#else + int log_cnt = 0; + uint32_t y = 1; + int correction = 0; + const float v_f = (float)v; + const uint32_t orig_v = v; + do { + ++log_cnt; + v = v >> 1; + y = y << 1; + } while (v >= LOG_LOOKUP_IDX_MAX); +#endif + // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256 + // Xf = floor(Xf) * (1 + (v % y) / v) + // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v) + // The correction factor: log(1 + d) ~ d; for very small d values, so + // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v + // LOG_2_RECIPROCAL ~ 23/16 + correction = (23 * (orig_v & (y - 1))) >> 4; + return v_f * (kLog2Table[v] + log_cnt) + correction; + } else { + return (float)(LOG_2_RECIPROCAL * v * log((double)v)); + } +} + +static float FastLog2Slow_C(uint32_t v) { + assert(v >= LOG_LOOKUP_IDX_MAX); + if (v < APPROX_LOG_WITH_CORRECTION_MAX) { +#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ) + // use clz if available + const int log_cnt = BitsLog2Floor(v) - 7; + const uint32_t y = 1 << log_cnt; + const uint32_t orig_v = v; + double log_2; + v >>= log_cnt; +#else + int log_cnt = 0; + uint32_t y = 1; + const uint32_t orig_v = v; + double log_2; + do { + ++log_cnt; + v = v >> 1; + y = y << 1; + } while (v >= LOG_LOOKUP_IDX_MAX); +#endif + log_2 = kLog2Table[v] + log_cnt; + if (orig_v >= APPROX_LOG_MAX) { + // Since the division is still expensive, add this correction factor only + // for large values of 'v'. + const int correction = (23 * (orig_v & (y - 1))) >> 4; + log_2 += (double)correction / orig_v; + } + return (float)log_2; + } else { + return (float)(LOG_2_RECIPROCAL * log((double)v)); + } +} + +//------------------------------------------------------------------------------ +// Methods to calculate Entropy (Shannon). + +// Compute the combined Shanon's entropy for distribution {X} and {X+Y} +static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) { + int i; + float retval = 0.f; + int sumX = 0, sumXY = 0; + for (i = 0; i < 256; ++i) { + const int x = X[i]; + if (x != 0) { + const int xy = x + Y[i]; + sumX += x; + retval -= VP8LFastSLog2(x); + sumXY += xy; + retval -= VP8LFastSLog2(xy); + } else if (Y[i] != 0) { + sumXY += Y[i]; + retval -= VP8LFastSLog2(Y[i]); + } + } + retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY); + return retval; +} + +void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) { + entropy->entropy = 0.; + entropy->sum = 0; + entropy->nonzeros = 0; + entropy->max_val = 0; + entropy->nonzero_code = VP8L_NON_TRIVIAL_SYM; +} + +void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, + VP8LBitEntropy* const entropy) { + int i; + + VP8LBitEntropyInit(entropy); + + for (i = 0; i < n; ++i) { + if (array[i] != 0) { + entropy->sum += array[i]; + entropy->nonzero_code = i; + ++entropy->nonzeros; + entropy->entropy -= VP8LFastSLog2(array[i]); + if (entropy->max_val < array[i]) { + entropy->max_val = array[i]; + } + } + } + entropy->entropy += VP8LFastSLog2(entropy->sum); +} + +static WEBP_INLINE void GetEntropyUnrefinedHelper( + uint32_t val, int i, uint32_t* const val_prev, int* const i_prev, + VP8LBitEntropy* const bit_entropy, VP8LStreaks* const stats) { + const int streak = i - *i_prev; + + // Gather info for the bit entropy. + if (*val_prev != 0) { + bit_entropy->sum += (*val_prev) * streak; + bit_entropy->nonzeros += streak; + bit_entropy->nonzero_code = *i_prev; + bit_entropy->entropy -= VP8LFastSLog2(*val_prev) * streak; + if (bit_entropy->max_val < *val_prev) { + bit_entropy->max_val = *val_prev; + } + } + + // Gather info for the Huffman cost. + stats->counts[*val_prev != 0] += (streak > 3); + stats->streaks[*val_prev != 0][(streak > 3)] += streak; + + *val_prev = val; + *i_prev = i; +} + +static void GetEntropyUnrefined_C(const uint32_t X[], int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats) { + int i; + int i_prev = 0; + uint32_t x_prev = X[0]; + + memset(stats, 0, sizeof(*stats)); + VP8LBitEntropyInit(bit_entropy); + + for (i = 1; i < length; ++i) { + const uint32_t x = X[i]; + if (x != x_prev) { + GetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); + } + } + GetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); + + bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); +} + +static void GetCombinedEntropyUnrefined_C(const uint32_t X[], + const uint32_t Y[], + int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats) { + int i = 1; + int i_prev = 0; + uint32_t xy_prev = X[0] + Y[0]; + + memset(stats, 0, sizeof(*stats)); + VP8LBitEntropyInit(bit_entropy); + + for (i = 1; i < length; ++i) { + const uint32_t xy = X[i] + Y[i]; + if (xy != xy_prev) { + GetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, bit_entropy, stats); + } + } + GetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, bit_entropy, stats); + + bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); +} + +//------------------------------------------------------------------------------ + +void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) { + int i; + for (i = 0; i < num_pixels; ++i) { + const int argb = (int)argb_data[i]; + const int green = (argb >> 8) & 0xff; + const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff; + const uint32_t new_b = (((argb >> 0) & 0xff) - green) & 0xff; + argb_data[i] = ((uint32_t)argb & 0xff00ff00u) | (new_r << 16) | new_b; + } +} + +static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, int8_t color) { + return ((int)color_pred * color) >> 5; +} + +static WEBP_INLINE int8_t U32ToS8(uint32_t v) { + return (int8_t)(v & 0xff); +} + +void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data, + int num_pixels) { + int i; + for (i = 0; i < num_pixels; ++i) { + const uint32_t argb = data[i]; + const int8_t green = U32ToS8(argb >> 8); + const int8_t red = U32ToS8(argb >> 16); + int new_red = red & 0xff; + int new_blue = argb & 0xff; + new_red -= ColorTransformDelta((int8_t)m->green_to_red_, green); + new_red &= 0xff; + new_blue -= ColorTransformDelta((int8_t)m->green_to_blue_, green); + new_blue -= ColorTransformDelta((int8_t)m->red_to_blue_, red); + new_blue &= 0xff; + data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); + } +} + +static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red, + uint32_t argb) { + const int8_t green = U32ToS8(argb >> 8); + int new_red = argb >> 16; + new_red -= ColorTransformDelta((int8_t)green_to_red, green); + return (new_red & 0xff); +} + +static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue, + uint8_t red_to_blue, + uint32_t argb) { + const int8_t green = U32ToS8(argb >> 8); + const int8_t red = U32ToS8(argb >> 16); + int new_blue = argb & 0xff; + new_blue -= ColorTransformDelta((int8_t)green_to_blue, green); + new_blue -= ColorTransformDelta((int8_t)red_to_blue, red); + return (new_blue & 0xff); +} + +void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_red, int histo[]) { + while (tile_height-- > 0) { + int x; + for (x = 0; x < tile_width; ++x) { + ++histo[TransformColorRed((uint8_t)green_to_red, argb[x])]; + } + argb += stride; + } +} + +void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_blue, int red_to_blue, + int histo[]) { + while (tile_height-- > 0) { + int x; + for (x = 0; x < tile_width; ++x) { + ++histo[TransformColorBlue((uint8_t)green_to_blue, (uint8_t)red_to_blue, + argb[x])]; + } + argb += stride; + } +} + +//------------------------------------------------------------------------------ + +static int VectorMismatch_C(const uint32_t* const array1, + const uint32_t* const array2, int length) { + int match_len = 0; + + while (match_len < length && array1[match_len] == array2[match_len]) { + ++match_len; + } + return match_len; +} + +// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. +void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits, + uint32_t* dst) { + int x; + if (xbits > 0) { + const int bit_depth = 1 << (3 - xbits); + const int mask = (1 << xbits) - 1; + uint32_t code = 0xff000000; + for (x = 0; x < width; ++x) { + const int xsub = x & mask; + if (xsub == 0) { + code = 0xff000000; + } + code |= row[x] << (8 + bit_depth * xsub); + dst[x >> xbits] = code; + } + } else { + for (x = 0; x < width; ++x) dst[x] = 0xff000000 | (row[x] << 8); + } +} + +//------------------------------------------------------------------------------ + +static uint32_t ExtraCost_C(const uint32_t* population, int length) { + int i; + uint32_t cost = population[4] + population[5]; + assert(length % 2 == 0); + for (i = 2; i < length / 2 - 1; ++i) { + cost += i * (population[2 * i + 2] + population[2 * i + 3]); + } + return cost; +} + +static uint32_t ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y, + int length) { + int i; + uint32_t cost = X[4] + Y[4] + X[5] + Y[5]; + assert(length % 2 == 0); + for (i = 2; i < length / 2 - 1; ++i) { + const int xy0 = X[2 * i + 2] + Y[2 * i + 2]; + const int xy1 = X[2 * i + 3] + Y[2 * i + 3]; + cost += i * (xy0 + xy1); + } + return cost; +} + +//------------------------------------------------------------------------------ + +static void AddVector_C(const uint32_t* a, const uint32_t* b, uint32_t* out, + int size) { + int i; + for (i = 0; i < size; ++i) out[i] = a[i] + b[i]; +} + +static void AddVectorEq_C(const uint32_t* a, uint32_t* out, int size) { + int i; + for (i = 0; i < size; ++i) out[i] += a[i]; +} + +#define ADD(X, ARG, LEN) do { \ + if (a->is_used_[X]) { \ + if (b->is_used_[X]) { \ + VP8LAddVector(a->ARG, b->ARG, out->ARG, (LEN)); \ + } else { \ + memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \ + } \ + } else if (b->is_used_[X]) { \ + memcpy(&out->ARG[0], &b->ARG[0], (LEN) * sizeof(out->ARG[0])); \ + } else { \ + memset(&out->ARG[0], 0, (LEN) * sizeof(out->ARG[0])); \ + } \ +} while (0) + +#define ADD_EQ(X, ARG, LEN) do { \ + if (a->is_used_[X]) { \ + if (out->is_used_[X]) { \ + VP8LAddVectorEq(a->ARG, out->ARG, (LEN)); \ + } else { \ + memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \ + } \ + } \ +} while (0) + +void VP8LHistogramAdd(const VP8LHistogram* const a, + const VP8LHistogram* const b, VP8LHistogram* const out) { + int i; + const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_); + assert(a->palette_code_bits_ == b->palette_code_bits_); + + if (b != out) { + ADD(0, literal_, literal_size); + ADD(1, red_, NUM_LITERAL_CODES); + ADD(2, blue_, NUM_LITERAL_CODES); + ADD(3, alpha_, NUM_LITERAL_CODES); + ADD(4, distance_, NUM_DISTANCE_CODES); + for (i = 0; i < 5; ++i) { + out->is_used_[i] = (a->is_used_[i] | b->is_used_[i]); + } + } else { + ADD_EQ(0, literal_, literal_size); + ADD_EQ(1, red_, NUM_LITERAL_CODES); + ADD_EQ(2, blue_, NUM_LITERAL_CODES); + ADD_EQ(3, alpha_, NUM_LITERAL_CODES); + ADD_EQ(4, distance_, NUM_DISTANCE_CODES); + for (i = 0; i < 5; ++i) out->is_used_[i] |= a->is_used_[i]; + } +} +#undef ADD +#undef ADD_EQ + +//------------------------------------------------------------------------------ +// Image transforms. + +static void PredictorSub0_C(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i < num_pixels; ++i) out[i] = VP8LSubPixels(in[i], ARGB_BLACK); + (void)upper; +} + +static void PredictorSub1_C(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i < num_pixels; ++i) out[i] = VP8LSubPixels(in[i], in[i - 1]); + (void)upper; +} + +// It subtracts the prediction from the input pixel and stores the residual +// in the output pixel. +#define GENERATE_PREDICTOR_SUB(PREDICTOR_I) \ +static void PredictorSub##PREDICTOR_I##_C(const uint32_t* in, \ + const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int x; \ + assert(upper != NULL); \ + for (x = 0; x < num_pixels; ++x) { \ + const uint32_t pred = \ + VP8LPredictor##PREDICTOR_I##_C(&in[x - 1], upper + x); \ + out[x] = VP8LSubPixels(in[x], pred); \ + } \ +} + +GENERATE_PREDICTOR_SUB(2) +GENERATE_PREDICTOR_SUB(3) +GENERATE_PREDICTOR_SUB(4) +GENERATE_PREDICTOR_SUB(5) +GENERATE_PREDICTOR_SUB(6) +GENERATE_PREDICTOR_SUB(7) +GENERATE_PREDICTOR_SUB(8) +GENERATE_PREDICTOR_SUB(9) +GENERATE_PREDICTOR_SUB(10) +GENERATE_PREDICTOR_SUB(11) +GENERATE_PREDICTOR_SUB(12) +GENERATE_PREDICTOR_SUB(13) + +//------------------------------------------------------------------------------ + +VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; + +VP8LTransformColorFunc VP8LTransformColor; + +VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms; +VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms; + +VP8LFastLog2SlowFunc VP8LFastLog2Slow; +VP8LFastLog2SlowFunc VP8LFastSLog2Slow; + +VP8LCostFunc VP8LExtraCost; +VP8LCostCombinedFunc VP8LExtraCostCombined; +VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; + +VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; +VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined; + +VP8LAddVectorFunc VP8LAddVector; +VP8LAddVectorEqFunc VP8LAddVectorEq; + +VP8LVectorMismatchFunc VP8LVectorMismatch; +VP8LBundleColorMapFunc VP8LBundleColorMap; + +VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; +VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; + +extern VP8CPUInfo VP8GetCPUInfo; +extern void VP8LEncDspInitSSE2(void); +extern void VP8LEncDspInitSSE41(void); +extern void VP8LEncDspInitNEON(void); +extern void VP8LEncDspInitMIPS32(void); +extern void VP8LEncDspInitMIPSdspR2(void); +extern void VP8LEncDspInitMSA(void); + +WEBP_DSP_INIT_FUNC(VP8LEncDspInit) { + VP8LDspInit(); + +#if !WEBP_NEON_OMIT_C_CODE + VP8LSubtractGreenFromBlueAndRed = VP8LSubtractGreenFromBlueAndRed_C; + + VP8LTransformColor = VP8LTransformColor_C; +#endif + + VP8LCollectColorBlueTransforms = VP8LCollectColorBlueTransforms_C; + VP8LCollectColorRedTransforms = VP8LCollectColorRedTransforms_C; + + VP8LFastLog2Slow = FastLog2Slow_C; + VP8LFastSLog2Slow = FastSLog2Slow_C; + + VP8LExtraCost = ExtraCost_C; + VP8LExtraCostCombined = ExtraCostCombined_C; + VP8LCombinedShannonEntropy = CombinedShannonEntropy_C; + + VP8LGetEntropyUnrefined = GetEntropyUnrefined_C; + VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_C; + + VP8LAddVector = AddVector_C; + VP8LAddVectorEq = AddVectorEq_C; + + VP8LVectorMismatch = VectorMismatch_C; + VP8LBundleColorMap = VP8LBundleColorMap_C; + + VP8LPredictorsSub[0] = PredictorSub0_C; + VP8LPredictorsSub[1] = PredictorSub1_C; + VP8LPredictorsSub[2] = PredictorSub2_C; + VP8LPredictorsSub[3] = PredictorSub3_C; + VP8LPredictorsSub[4] = PredictorSub4_C; + VP8LPredictorsSub[5] = PredictorSub5_C; + VP8LPredictorsSub[6] = PredictorSub6_C; + VP8LPredictorsSub[7] = PredictorSub7_C; + VP8LPredictorsSub[8] = PredictorSub8_C; + VP8LPredictorsSub[9] = PredictorSub9_C; + VP8LPredictorsSub[10] = PredictorSub10_C; + VP8LPredictorsSub[11] = PredictorSub11_C; + VP8LPredictorsSub[12] = PredictorSub12_C; + VP8LPredictorsSub[13] = PredictorSub13_C; + VP8LPredictorsSub[14] = PredictorSub0_C; // <- padding security sentinels + VP8LPredictorsSub[15] = PredictorSub0_C; + + VP8LPredictorsSub_C[0] = PredictorSub0_C; + VP8LPredictorsSub_C[1] = PredictorSub1_C; + VP8LPredictorsSub_C[2] = PredictorSub2_C; + VP8LPredictorsSub_C[3] = PredictorSub3_C; + VP8LPredictorsSub_C[4] = PredictorSub4_C; + VP8LPredictorsSub_C[5] = PredictorSub5_C; + VP8LPredictorsSub_C[6] = PredictorSub6_C; + VP8LPredictorsSub_C[7] = PredictorSub7_C; + VP8LPredictorsSub_C[8] = PredictorSub8_C; + VP8LPredictorsSub_C[9] = PredictorSub9_C; + VP8LPredictorsSub_C[10] = PredictorSub10_C; + VP8LPredictorsSub_C[11] = PredictorSub11_C; + VP8LPredictorsSub_C[12] = PredictorSub12_C; + VP8LPredictorsSub_C[13] = PredictorSub13_C; + VP8LPredictorsSub_C[14] = PredictorSub0_C; // <- padding security sentinels + VP8LPredictorsSub_C[15] = PredictorSub0_C; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8LEncDspInitSSE2(); +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + VP8LEncDspInitSSE41(); + } +#endif + } +#endif +#if defined(WEBP_USE_MIPS32) + if (VP8GetCPUInfo(kMIPS32)) { + VP8LEncDspInitMIPS32(); + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + VP8LEncDspInitMIPSdspR2(); + } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + VP8LEncDspInitMSA(); + } +#endif + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + VP8LEncDspInitNEON(); + } +#endif + + assert(VP8LSubtractGreenFromBlueAndRed != NULL); + assert(VP8LTransformColor != NULL); + assert(VP8LCollectColorBlueTransforms != NULL); + assert(VP8LCollectColorRedTransforms != NULL); + assert(VP8LFastLog2Slow != NULL); + assert(VP8LFastSLog2Slow != NULL); + assert(VP8LExtraCost != NULL); + assert(VP8LExtraCostCombined != NULL); + assert(VP8LCombinedShannonEntropy != NULL); + assert(VP8LGetEntropyUnrefined != NULL); + assert(VP8LGetCombinedEntropyUnrefined != NULL); + assert(VP8LAddVector != NULL); + assert(VP8LAddVectorEq != NULL); + assert(VP8LVectorMismatch != NULL); + assert(VP8LBundleColorMap != NULL); + assert(VP8LPredictorsSub[0] != NULL); + assert(VP8LPredictorsSub[1] != NULL); + assert(VP8LPredictorsSub[2] != NULL); + assert(VP8LPredictorsSub[3] != NULL); + assert(VP8LPredictorsSub[4] != NULL); + assert(VP8LPredictorsSub[5] != NULL); + assert(VP8LPredictorsSub[6] != NULL); + assert(VP8LPredictorsSub[7] != NULL); + assert(VP8LPredictorsSub[8] != NULL); + assert(VP8LPredictorsSub[9] != NULL); + assert(VP8LPredictorsSub[10] != NULL); + assert(VP8LPredictorsSub[11] != NULL); + assert(VP8LPredictorsSub[12] != NULL); + assert(VP8LPredictorsSub[13] != NULL); + assert(VP8LPredictorsSub[14] != NULL); + assert(VP8LPredictorsSub[15] != NULL); + assert(VP8LPredictorsSub_C[0] != NULL); + assert(VP8LPredictorsSub_C[1] != NULL); + assert(VP8LPredictorsSub_C[2] != NULL); + assert(VP8LPredictorsSub_C[3] != NULL); + assert(VP8LPredictorsSub_C[4] != NULL); + assert(VP8LPredictorsSub_C[5] != NULL); + assert(VP8LPredictorsSub_C[6] != NULL); + assert(VP8LPredictorsSub_C[7] != NULL); + assert(VP8LPredictorsSub_C[8] != NULL); + assert(VP8LPredictorsSub_C[9] != NULL); + assert(VP8LPredictorsSub_C[10] != NULL); + assert(VP8LPredictorsSub_C[11] != NULL); + assert(VP8LPredictorsSub_C[12] != NULL); + assert(VP8LPredictorsSub_C[13] != NULL); + assert(VP8LPredictorsSub_C[14] != NULL); + assert(VP8LPredictorsSub_C[15] != NULL); +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dsp/lossless_enc_mips32.c b/libraries/webp/src/dsp/lossless_enc_mips32.c new file mode 100644 index 00000000000..e10f12da9d5 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_enc_mips32.c @@ -0,0 +1,397 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS version of lossless functions +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) +// Jovan Zelincevic (jovan.zelincevic@imgtec.com) + +#include "src/dsp/dsp.h" +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" + +#if defined(WEBP_USE_MIPS32) + +#include +#include +#include +#include + +static float FastSLog2Slow_MIPS32(uint32_t v) { + assert(v >= LOG_LOOKUP_IDX_MAX); + if (v < APPROX_LOG_WITH_CORRECTION_MAX) { + uint32_t log_cnt, y, correction; + const int c24 = 24; + const float v_f = (float)v; + uint32_t temp; + + // Xf = 256 = 2^8 + // log_cnt is index of leading one in upper 24 bits + __asm__ volatile( + "clz %[log_cnt], %[v] \n\t" + "addiu %[y], $zero, 1 \n\t" + "subu %[log_cnt], %[c24], %[log_cnt] \n\t" + "sllv %[y], %[y], %[log_cnt] \n\t" + "srlv %[temp], %[v], %[log_cnt] \n\t" + : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y), + [temp]"=r"(temp) + : [c24]"r"(c24), [v]"r"(v) + ); + + // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256 + // Xf = floor(Xf) * (1 + (v % y) / v) + // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v) + // The correction factor: log(1 + d) ~ d; for very small d values, so + // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v + // LOG_2_RECIPROCAL ~ 23/16 + + // (v % y) = (v % 2^log_cnt) = v & (2^log_cnt - 1) + correction = (23 * (v & (y - 1))) >> 4; + return v_f * (kLog2Table[temp] + log_cnt) + correction; + } else { + return (float)(LOG_2_RECIPROCAL * v * log((double)v)); + } +} + +static float FastLog2Slow_MIPS32(uint32_t v) { + assert(v >= LOG_LOOKUP_IDX_MAX); + if (v < APPROX_LOG_WITH_CORRECTION_MAX) { + uint32_t log_cnt, y; + const int c24 = 24; + double log_2; + uint32_t temp; + + __asm__ volatile( + "clz %[log_cnt], %[v] \n\t" + "addiu %[y], $zero, 1 \n\t" + "subu %[log_cnt], %[c24], %[log_cnt] \n\t" + "sllv %[y], %[y], %[log_cnt] \n\t" + "srlv %[temp], %[v], %[log_cnt] \n\t" + : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y), + [temp]"=r"(temp) + : [c24]"r"(c24), [v]"r"(v) + ); + + log_2 = kLog2Table[temp] + log_cnt; + if (v >= APPROX_LOG_MAX) { + // Since the division is still expensive, add this correction factor only + // for large values of 'v'. + + const uint32_t correction = (23 * (v & (y - 1))) >> 4; + log_2 += (double)correction / v; + } + return (float)log_2; + } else { + return (float)(LOG_2_RECIPROCAL * log((double)v)); + } +} + +// C version of this function: +// int i = 0; +// int64_t cost = 0; +// const uint32_t* pop = &population[4]; +// const uint32_t* LoopEnd = &population[length]; +// while (pop != LoopEnd) { +// ++i; +// cost += i * *pop; +// cost += i * *(pop + 1); +// pop += 2; +// } +// return cost; +static uint32_t ExtraCost_MIPS32(const uint32_t* const population, int length) { + int i, temp0, temp1; + const uint32_t* pop = &population[4]; + const uint32_t* const LoopEnd = &population[length]; + + __asm__ volatile( + "mult $zero, $zero \n\t" + "xor %[i], %[i], %[i] \n\t" + "beq %[pop], %[LoopEnd], 2f \n\t" + "1: \n\t" + "lw %[temp0], 0(%[pop]) \n\t" + "lw %[temp1], 4(%[pop]) \n\t" + "addiu %[i], %[i], 1 \n\t" + "addiu %[pop], %[pop], 8 \n\t" + "madd %[i], %[temp0] \n\t" + "madd %[i], %[temp1] \n\t" + "bne %[pop], %[LoopEnd], 1b \n\t" + "2: \n\t" + "mfhi %[temp0] \n\t" + "mflo %[temp1] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), + [i]"=&r"(i), [pop]"+r"(pop) + : [LoopEnd]"r"(LoopEnd) + : "memory", "hi", "lo" + ); + + return ((int64_t)temp0 << 32 | temp1); +} + +// C version of this function: +// int i = 0; +// int64_t cost = 0; +// const uint32_t* pX = &X[4]; +// const uint32_t* pY = &Y[4]; +// const uint32_t* LoopEnd = &X[length]; +// while (pX != LoopEnd) { +// const uint32_t xy0 = *pX + *pY; +// const uint32_t xy1 = *(pX + 1) + *(pY + 1); +// ++i; +// cost += i * xy0; +// cost += i * xy1; +// pX += 2; +// pY += 2; +// } +// return cost; +static uint32_t ExtraCostCombined_MIPS32(const uint32_t* const X, + const uint32_t* const Y, int length) { + int i, temp0, temp1, temp2, temp3; + const uint32_t* pX = &X[4]; + const uint32_t* pY = &Y[4]; + const uint32_t* const LoopEnd = &X[length]; + + __asm__ volatile( + "mult $zero, $zero \n\t" + "xor %[i], %[i], %[i] \n\t" + "beq %[pX], %[LoopEnd], 2f \n\t" + "1: \n\t" + "lw %[temp0], 0(%[pX]) \n\t" + "lw %[temp1], 0(%[pY]) \n\t" + "lw %[temp2], 4(%[pX]) \n\t" + "lw %[temp3], 4(%[pY]) \n\t" + "addiu %[i], %[i], 1 \n\t" + "addu %[temp0], %[temp0], %[temp1] \n\t" + "addu %[temp2], %[temp2], %[temp3] \n\t" + "addiu %[pX], %[pX], 8 \n\t" + "addiu %[pY], %[pY], 8 \n\t" + "madd %[i], %[temp0] \n\t" + "madd %[i], %[temp2] \n\t" + "bne %[pX], %[LoopEnd], 1b \n\t" + "2: \n\t" + "mfhi %[temp0] \n\t" + "mflo %[temp1] \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), + [i]"=&r"(i), [pX]"+r"(pX), [pY]"+r"(pY) + : [LoopEnd]"r"(LoopEnd) + : "memory", "hi", "lo" + ); + + return ((int64_t)temp0 << 32 | temp1); +} + +#define HUFFMAN_COST_PASS \ + __asm__ volatile( \ + "sll %[temp1], %[temp0], 3 \n\t" \ + "addiu %[temp3], %[streak], -3 \n\t" \ + "addu %[temp2], %[pstreaks], %[temp1] \n\t" \ + "blez %[temp3], 1f \n\t" \ + "srl %[temp1], %[temp1], 1 \n\t" \ + "addu %[temp3], %[pcnts], %[temp1] \n\t" \ + "lw %[temp0], 4(%[temp2]) \n\t" \ + "lw %[temp1], 0(%[temp3]) \n\t" \ + "addu %[temp0], %[temp0], %[streak] \n\t" \ + "addiu %[temp1], %[temp1], 1 \n\t" \ + "sw %[temp0], 4(%[temp2]) \n\t" \ + "sw %[temp1], 0(%[temp3]) \n\t" \ + "b 2f \n\t" \ + "1: \n\t" \ + "lw %[temp0], 0(%[temp2]) \n\t" \ + "addu %[temp0], %[temp0], %[streak] \n\t" \ + "sw %[temp0], 0(%[temp2]) \n\t" \ + "2: \n\t" \ + : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \ + [temp3]"=&r"(temp3), [temp0]"+r"(temp0) \ + : [pstreaks]"r"(pstreaks), [pcnts]"r"(pcnts), \ + [streak]"r"(streak) \ + : "memory" \ + ); + +// Returns the various RLE counts +static WEBP_INLINE void GetEntropyUnrefinedHelper( + uint32_t val, int i, uint32_t* const val_prev, int* const i_prev, + VP8LBitEntropy* const bit_entropy, VP8LStreaks* const stats) { + int* const pstreaks = &stats->streaks[0][0]; + int* const pcnts = &stats->counts[0]; + int temp0, temp1, temp2, temp3; + const int streak = i - *i_prev; + + // Gather info for the bit entropy. + if (*val_prev != 0) { + bit_entropy->sum += (*val_prev) * streak; + bit_entropy->nonzeros += streak; + bit_entropy->nonzero_code = *i_prev; + bit_entropy->entropy -= VP8LFastSLog2(*val_prev) * streak; + if (bit_entropy->max_val < *val_prev) { + bit_entropy->max_val = *val_prev; + } + } + + // Gather info for the Huffman cost. + temp0 = (*val_prev != 0); + HUFFMAN_COST_PASS + + *val_prev = val; + *i_prev = i; +} + +static void GetEntropyUnrefined_MIPS32(const uint32_t X[], int length, + VP8LBitEntropy* const bit_entropy, + VP8LStreaks* const stats) { + int i; + int i_prev = 0; + uint32_t x_prev = X[0]; + + memset(stats, 0, sizeof(*stats)); + VP8LBitEntropyInit(bit_entropy); + + for (i = 1; i < length; ++i) { + const uint32_t x = X[i]; + if (x != x_prev) { + GetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); + } + } + GetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); + + bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); +} + +static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[], + const uint32_t Y[], + int length, + VP8LBitEntropy* const entropy, + VP8LStreaks* const stats) { + int i = 1; + int i_prev = 0; + uint32_t xy_prev = X[0] + Y[0]; + + memset(stats, 0, sizeof(*stats)); + VP8LBitEntropyInit(entropy); + + for (i = 1; i < length; ++i) { + const uint32_t xy = X[i] + Y[i]; + if (xy != xy_prev) { + GetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, entropy, stats); + } + } + GetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, entropy, stats); + + entropy->entropy += VP8LFastSLog2(entropy->sum); +} + +#define ASM_START \ + __asm__ volatile( \ + ".set push \n\t" \ + ".set at \n\t" \ + ".set macro \n\t" \ + "1: \n\t" + +// P2 = P0 + P1 +// A..D - offsets +// E - temp variable to tell macro +// if pointer should be incremented +// literal_ and successive histograms could be unaligned +// so we must use ulw and usw +#define ADD_TO_OUT(A, B, C, D, E, P0, P1, P2) \ + "ulw %[temp0], " #A "(%[" #P0 "]) \n\t" \ + "ulw %[temp1], " #B "(%[" #P0 "]) \n\t" \ + "ulw %[temp2], " #C "(%[" #P0 "]) \n\t" \ + "ulw %[temp3], " #D "(%[" #P0 "]) \n\t" \ + "ulw %[temp4], " #A "(%[" #P1 "]) \n\t" \ + "ulw %[temp5], " #B "(%[" #P1 "]) \n\t" \ + "ulw %[temp6], " #C "(%[" #P1 "]) \n\t" \ + "ulw %[temp7], " #D "(%[" #P1 "]) \n\t" \ + "addu %[temp4], %[temp4], %[temp0] \n\t" \ + "addu %[temp5], %[temp5], %[temp1] \n\t" \ + "addu %[temp6], %[temp6], %[temp2] \n\t" \ + "addu %[temp7], %[temp7], %[temp3] \n\t" \ + "addiu %[" #P0 "], %[" #P0 "], 16 \n\t" \ + ".if " #E " == 1 \n\t" \ + "addiu %[" #P1 "], %[" #P1 "], 16 \n\t" \ + ".endif \n\t" \ + "usw %[temp4], " #A "(%[" #P2 "]) \n\t" \ + "usw %[temp5], " #B "(%[" #P2 "]) \n\t" \ + "usw %[temp6], " #C "(%[" #P2 "]) \n\t" \ + "usw %[temp7], " #D "(%[" #P2 "]) \n\t" \ + "addiu %[" #P2 "], %[" #P2 "], 16 \n\t" \ + "bne %[" #P0 "], %[LoopEnd], 1b \n\t" \ + ".set pop \n\t" \ + +#define ASM_END_COMMON_0 \ + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \ + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), \ + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \ + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), \ + [pa]"+r"(pa), [pout]"+r"(pout) + +#define ASM_END_COMMON_1 \ + : [LoopEnd]"r"(LoopEnd) \ + : "memory", "at" \ + ); + +#define ASM_END_0 \ + ASM_END_COMMON_0 \ + , [pb]"+r"(pb) \ + ASM_END_COMMON_1 + +#define ASM_END_1 \ + ASM_END_COMMON_0 \ + ASM_END_COMMON_1 + +static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb, + uint32_t* pout, int size) { + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + const int end = ((size) / 4) * 4; + const uint32_t* const LoopEnd = pa + end; + int i; + ASM_START + ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) + ASM_END_0 + for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i]; +} + +static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) { + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + const int end = ((size) / 4) * 4; + const uint32_t* const LoopEnd = pa + end; + int i; + ASM_START + ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) + ASM_END_1 + for (i = 0; i < size - end; ++i) pout[i] += pa[i]; +} + +#undef ASM_END_1 +#undef ASM_END_0 +#undef ASM_END_COMMON_1 +#undef ASM_END_COMMON_0 +#undef ADD_TO_OUT +#undef ASM_START + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LEncDspInitMIPS32(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPS32(void) { + VP8LFastSLog2Slow = FastSLog2Slow_MIPS32; + VP8LFastLog2Slow = FastLog2Slow_MIPS32; + VP8LExtraCost = ExtraCost_MIPS32; + VP8LExtraCostCombined = ExtraCostCombined_MIPS32; + VP8LGetEntropyUnrefined = GetEntropyUnrefined_MIPS32; + VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_MIPS32; + VP8LAddVector = AddVector_MIPS32; + VP8LAddVectorEq = AddVectorEq_MIPS32; +} + +#else // !WEBP_USE_MIPS32 + +WEBP_DSP_INIT_STUB(VP8LEncDspInitMIPS32) + +#endif // WEBP_USE_MIPS32 diff --git a/libraries/webp/src/dsp/lossless_enc_mips_dsp_r2.c b/libraries/webp/src/dsp/lossless_enc_mips_dsp_r2.c new file mode 100644 index 00000000000..5855e6ae156 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_enc_mips_dsp_r2.c @@ -0,0 +1,281 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Image transform methods for lossless encoder. +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) +// Jovan Zelincevic (jovan.zelincevic@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +#include "src/dsp/lossless.h" + +static void SubtractGreenFromBlueAndRed_MIPSdspR2(uint32_t* argb_data, + int num_pixels) { + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + uint32_t* const p_loop1_end = argb_data + (num_pixels & ~3); + uint32_t* const p_loop2_end = p_loop1_end + (num_pixels & 3); + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[argb_data], %[p_loop1_end], 3f \n\t" + " nop \n\t" + "0: \n\t" + "lw %[temp0], 0(%[argb_data]) \n\t" + "lw %[temp1], 4(%[argb_data]) \n\t" + "lw %[temp2], 8(%[argb_data]) \n\t" + "lw %[temp3], 12(%[argb_data]) \n\t" + "ext %[temp4], %[temp0], 8, 8 \n\t" + "ext %[temp5], %[temp1], 8, 8 \n\t" + "ext %[temp6], %[temp2], 8, 8 \n\t" + "ext %[temp7], %[temp3], 8, 8 \n\t" + "addiu %[argb_data], %[argb_data], 16 \n\t" + "replv.ph %[temp4], %[temp4] \n\t" + "replv.ph %[temp5], %[temp5] \n\t" + "replv.ph %[temp6], %[temp6] \n\t" + "replv.ph %[temp7], %[temp7] \n\t" + "subu.qb %[temp0], %[temp0], %[temp4] \n\t" + "subu.qb %[temp1], %[temp1], %[temp5] \n\t" + "subu.qb %[temp2], %[temp2], %[temp6] \n\t" + "subu.qb %[temp3], %[temp3], %[temp7] \n\t" + "sw %[temp0], -16(%[argb_data]) \n\t" + "sw %[temp1], -12(%[argb_data]) \n\t" + "sw %[temp2], -8(%[argb_data]) \n\t" + "bne %[argb_data], %[p_loop1_end], 0b \n\t" + " sw %[temp3], -4(%[argb_data]) \n\t" + "3: \n\t" + "beq %[argb_data], %[p_loop2_end], 2f \n\t" + " nop \n\t" + "1: \n\t" + "lw %[temp0], 0(%[argb_data]) \n\t" + "addiu %[argb_data], %[argb_data], 4 \n\t" + "ext %[temp4], %[temp0], 8, 8 \n\t" + "replv.ph %[temp4], %[temp4] \n\t" + "subu.qb %[temp0], %[temp0], %[temp4] \n\t" + "bne %[argb_data], %[p_loop2_end], 1b \n\t" + " sw %[temp0], -4(%[argb_data]) \n\t" + "2: \n\t" + ".set pop \n\t" + : [argb_data]"+&r"(argb_data), [temp0]"=&r"(temp0), + [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), + [temp7]"=&r"(temp7) + : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) + : "memory" + ); +} + +static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred, + int8_t color) { + return (uint32_t)((int)(color_pred) * color) >> 5; +} + +static void TransformColor_MIPSdspR2(const VP8LMultipliers* const m, + uint32_t* data, int num_pixels) { + int temp0, temp1, temp2, temp3, temp4, temp5; + uint32_t argb, argb1, new_red, new_red1; + const uint32_t G_to_R = m->green_to_red_; + const uint32_t G_to_B = m->green_to_blue_; + const uint32_t R_to_B = m->red_to_blue_; + uint32_t* const p_loop_end = data + (num_pixels & ~1); + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[data], %[p_loop_end], 1f \n\t" + " nop \n\t" + "replv.ph %[temp0], %[G_to_R] \n\t" + "replv.ph %[temp1], %[G_to_B] \n\t" + "replv.ph %[temp2], %[R_to_B] \n\t" + "shll.ph %[temp0], %[temp0], 8 \n\t" + "shll.ph %[temp1], %[temp1], 8 \n\t" + "shll.ph %[temp2], %[temp2], 8 \n\t" + "shra.ph %[temp0], %[temp0], 8 \n\t" + "shra.ph %[temp1], %[temp1], 8 \n\t" + "shra.ph %[temp2], %[temp2], 8 \n\t" + "0: \n\t" + "lw %[argb], 0(%[data]) \n\t" + "lw %[argb1], 4(%[data]) \n\t" + "lhu %[new_red], 2(%[data]) \n\t" + "lhu %[new_red1], 6(%[data]) \n\t" + "precrq.qb.ph %[temp3], %[argb], %[argb1] \n\t" + "precr.qb.ph %[temp4], %[argb], %[argb1] \n\t" + "preceu.ph.qbra %[temp3], %[temp3] \n\t" + "preceu.ph.qbla %[temp4], %[temp4] \n\t" + "shll.ph %[temp3], %[temp3], 8 \n\t" + "shll.ph %[temp4], %[temp4], 8 \n\t" + "shra.ph %[temp3], %[temp3], 8 \n\t" + "shra.ph %[temp4], %[temp4], 8 \n\t" + "mul.ph %[temp5], %[temp3], %[temp0] \n\t" + "mul.ph %[temp3], %[temp3], %[temp1] \n\t" + "mul.ph %[temp4], %[temp4], %[temp2] \n\t" + "addiu %[data], %[data], 8 \n\t" + "ins %[new_red1], %[new_red], 16, 16 \n\t" + "ins %[argb1], %[argb], 16, 16 \n\t" + "shra.ph %[temp5], %[temp5], 5 \n\t" + "shra.ph %[temp3], %[temp3], 5 \n\t" + "shra.ph %[temp4], %[temp4], 5 \n\t" + "subu.ph %[new_red1], %[new_red1], %[temp5] \n\t" + "subu.ph %[argb1], %[argb1], %[temp3] \n\t" + "preceu.ph.qbra %[temp5], %[new_red1] \n\t" + "subu.ph %[argb1], %[argb1], %[temp4] \n\t" + "preceu.ph.qbra %[temp3], %[argb1] \n\t" + "sb %[temp5], -2(%[data]) \n\t" + "sb %[temp3], -4(%[data]) \n\t" + "sra %[temp5], %[temp5], 16 \n\t" + "sra %[temp3], %[temp3], 16 \n\t" + "sb %[temp5], -6(%[data]) \n\t" + "bne %[data], %[p_loop_end], 0b \n\t" + " sb %[temp3], -8(%[data]) \n\t" + "1: \n\t" + ".set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [new_red1]"=&r"(new_red1), [new_red]"=&r"(new_red), + [argb]"=&r"(argb), [argb1]"=&r"(argb1), [data]"+&r"(data) + : [G_to_R]"r"(G_to_R), [R_to_B]"r"(R_to_B), + [G_to_B]"r"(G_to_B), [p_loop_end]"r"(p_loop_end) + : "memory", "hi", "lo" + ); + + if (num_pixels & 1) { + const uint32_t argb_ = data[0]; + const uint32_t green = argb_ >> 8; + const uint32_t red = argb_ >> 16; + uint32_t new_blue = argb_; + new_red = red; + new_red -= ColorTransformDelta(m->green_to_red_, green); + new_red &= 0xff; + new_blue -= ColorTransformDelta(m->green_to_blue_, green); + new_blue -= ColorTransformDelta(m->red_to_blue_, red); + new_blue &= 0xff; + data[0] = (argb_ & 0xff00ff00u) | (new_red << 16) | (new_blue); + } +} + +static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue, + uint8_t red_to_blue, + uint32_t argb) { + const uint32_t green = argb >> 8; + const uint32_t red = argb >> 16; + uint8_t new_blue = argb; + new_blue -= ColorTransformDelta(green_to_blue, green); + new_blue -= ColorTransformDelta(red_to_blue, red); + return (new_blue & 0xff); +} + +static void CollectColorBlueTransforms_MIPSdspR2(const uint32_t* argb, + int stride, + int tile_width, + int tile_height, + int green_to_blue, + int red_to_blue, + int histo[]) { + const int rtb = (red_to_blue << 16) | (red_to_blue & 0xffff); + const int gtb = (green_to_blue << 16) | (green_to_blue & 0xffff); + const uint32_t mask = 0xff00ffu; + while (tile_height-- > 0) { + int x; + const uint32_t* p_argb = argb; + argb += stride; + for (x = 0; x < (tile_width >> 1); ++x) { + int temp0, temp1, temp2, temp3, temp4, temp5, temp6; + __asm__ volatile ( + "lw %[temp0], 0(%[p_argb]) \n\t" + "lw %[temp1], 4(%[p_argb]) \n\t" + "precr.qb.ph %[temp2], %[temp0], %[temp1] \n\t" + "ins %[temp1], %[temp0], 16, 16 \n\t" + "shra.ph %[temp2], %[temp2], 8 \n\t" + "shra.ph %[temp3], %[temp1], 8 \n\t" + "mul.ph %[temp5], %[temp2], %[rtb] \n\t" + "mul.ph %[temp6], %[temp3], %[gtb] \n\t" + "and %[temp4], %[temp1], %[mask] \n\t" + "addiu %[p_argb], %[p_argb], 8 \n\t" + "shra.ph %[temp5], %[temp5], 5 \n\t" + "shra.ph %[temp6], %[temp6], 5 \n\t" + "subu.qb %[temp2], %[temp4], %[temp5] \n\t" + "subu.qb %[temp2], %[temp2], %[temp6] \n\t" + : [p_argb]"+&r"(p_argb), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), + [temp5]"=&r"(temp5), [temp6]"=&r"(temp6) + : [rtb]"r"(rtb), [gtb]"r"(gtb), [mask]"r"(mask) + : "memory", "hi", "lo" + ); + ++histo[(uint8_t)(temp2 >> 16)]; + ++histo[(uint8_t)temp2]; + } + if (tile_width & 1) { + ++histo[TransformColorBlue(green_to_blue, red_to_blue, *p_argb)]; + } + } +} + +static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red, + uint32_t argb) { + const uint32_t green = argb >> 8; + uint32_t new_red = argb >> 16; + new_red -= ColorTransformDelta(green_to_red, green); + return (new_red & 0xff); +} + +static void CollectColorRedTransforms_MIPSdspR2(const uint32_t* argb, + int stride, + int tile_width, + int tile_height, + int green_to_red, + int histo[]) { + const int gtr = (green_to_red << 16) | (green_to_red & 0xffff); + while (tile_height-- > 0) { + int x; + const uint32_t* p_argb = argb; + argb += stride; + for (x = 0; x < (tile_width >> 1); ++x) { + int temp0, temp1, temp2, temp3, temp4; + __asm__ volatile ( + "lw %[temp0], 0(%[p_argb]) \n\t" + "lw %[temp1], 4(%[p_argb]) \n\t" + "precrq.ph.w %[temp4], %[temp0], %[temp1] \n\t" + "ins %[temp1], %[temp0], 16, 16 \n\t" + "shra.ph %[temp3], %[temp1], 8 \n\t" + "mul.ph %[temp2], %[temp3], %[gtr] \n\t" + "addiu %[p_argb], %[p_argb], 8 \n\t" + "shra.ph %[temp2], %[temp2], 5 \n\t" + "subu.qb %[temp2], %[temp4], %[temp2] \n\t" + : [p_argb]"+&r"(p_argb), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4) + : [gtr]"r"(gtr) + : "memory", "hi", "lo" + ); + ++histo[(uint8_t)(temp2 >> 16)]; + ++histo[(uint8_t)temp2]; + } + if (tile_width & 1) { + ++histo[TransformColorRed(green_to_red, *p_argb)]; + } + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LEncDspInitMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPSdspR2(void) { + VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_MIPSdspR2; + VP8LTransformColor = TransformColor_MIPSdspR2; + VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_MIPSdspR2; + VP8LCollectColorRedTransforms = CollectColorRedTransforms_MIPSdspR2; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(VP8LEncDspInitMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/lossless_enc_msa.c b/libraries/webp/src/dsp/lossless_enc_msa.c new file mode 100644 index 00000000000..600dddfb592 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_enc_msa.c @@ -0,0 +1,148 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MSA variant of Image transform methods for lossless encoder. +// +// Authors: Prashant Patil (Prashant.Patil@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "src/dsp/lossless.h" +#include "src/dsp/msa_macro.h" + +#define TRANSFORM_COLOR_8(src0, src1, dst0, dst1, c0, c1, mask0, mask1) do { \ + v8i16 g0, g1, t0, t1, t2, t3; \ + v4i32 t4, t5; \ + VSHF_B2_SH(src0, src0, src1, src1, mask0, mask0, g0, g1); \ + DOTP_SB2_SH(g0, g1, c0, c0, t0, t1); \ + SRAI_H2_SH(t0, t1, 5); \ + t0 = __msa_subv_h((v8i16)src0, t0); \ + t1 = __msa_subv_h((v8i16)src1, t1); \ + t4 = __msa_srli_w((v4i32)src0, 16); \ + t5 = __msa_srli_w((v4i32)src1, 16); \ + DOTP_SB2_SH(t4, t5, c1, c1, t2, t3); \ + SRAI_H2_SH(t2, t3, 5); \ + SUB2(t0, t2, t1, t3, t0, t1); \ + VSHF_B2_UB(src0, t0, src1, t1, mask1, mask1, dst0, dst1); \ +} while (0) + +#define TRANSFORM_COLOR_4(src, dst, c0, c1, mask0, mask1) do { \ + const v16i8 g0 = VSHF_SB(src, src, mask0); \ + v8i16 t0 = __msa_dotp_s_h(c0, g0); \ + v8i16 t1; \ + v4i32 t2; \ + t0 = SRAI_H(t0, 5); \ + t0 = __msa_subv_h((v8i16)src, t0); \ + t2 = __msa_srli_w((v4i32)src, 16); \ + t1 = __msa_dotp_s_h(c1, (v16i8)t2); \ + t1 = SRAI_H(t1, 5); \ + t0 = t0 - t1; \ + dst = VSHF_UB(src, t0, mask1); \ +} while (0) + +static void TransformColor_MSA(const VP8LMultipliers* const m, uint32_t* data, + int num_pixels) { + v16u8 src0, dst0; + const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue_ | + (m->green_to_red_ << 16)); + const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue_); + const v16u8 mask0 = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, + 13, 255, 13, 255 }; + const v16u8 mask1 = { 16, 1, 18, 3, 20, 5, 22, 7, 24, 9, 26, 11, + 28, 13, 30, 15 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1; + LD_UB2(data, 4, src0, src1); + TRANSFORM_COLOR_8(src0, src1, dst0, dst1, g2br, r2b, mask0, mask1); + ST_UB2(dst0, dst1, data, 4); + data += 8; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(data); + TRANSFORM_COLOR_4(src0, dst0, g2br, r2b, mask0, mask1); + ST_UB(dst0, data); + data += 4; + num_pixels -= 4; + } + if (num_pixels > 0) { + src0 = LD_UB(data); + TRANSFORM_COLOR_4(src0, dst0, g2br, r2b, mask0, mask1); + if (num_pixels == 3) { + const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); + const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 2); + SD(pix_d, data + 0); + SW(pix_w, data + 2); + } else if (num_pixels == 2) { + const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); + SD(pix_d, data); + } else { + const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 0); + SW(pix_w, data); + } + } + } +} + +static void SubtractGreenFromBlueAndRed_MSA(uint32_t* argb_data, + int num_pixels) { + int i; + uint8_t* ptemp_data = (uint8_t*)argb_data; + v16u8 src0, dst0, tmp0; + const v16u8 mask = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, + 13, 255, 13, 255 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1, tmp1; + LD_UB2(ptemp_data, 16, src0, src1); + VSHF_B2_UB(src0, src1, src1, src0, mask, mask, tmp0, tmp1); + SUB2(src0, tmp0, src1, tmp1, dst0, dst1); + ST_UB2(dst0, dst1, ptemp_data, 16); + ptemp_data += 8 * 4; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(ptemp_data); + tmp0 = VSHF_UB(src0, src0, mask); + dst0 = src0 - tmp0; + ST_UB(dst0, ptemp_data); + ptemp_data += 4 * 4; + num_pixels -= 4; + } + for (i = 0; i < num_pixels; i++) { + const uint8_t b = ptemp_data[0]; + const uint8_t g = ptemp_data[1]; + const uint8_t r = ptemp_data[2]; + ptemp_data[0] = (b - g) & 0xff; + ptemp_data[2] = (r - g) & 0xff; + ptemp_data += 4; + } + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LEncDspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMSA(void) { + VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_MSA; + VP8LTransformColor = TransformColor_MSA; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8LEncDspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/libraries/webp/src/dsp/lossless_enc_neon.c b/libraries/webp/src/dsp/lossless_enc_neon.c new file mode 100644 index 00000000000..e32c7961a23 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_enc_neon.c @@ -0,0 +1,144 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// NEON variant of methods for lossless encoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include + +#include "src/dsp/lossless.h" +#include "src/dsp/neon.h" + +//------------------------------------------------------------------------------ +// Subtract-Green Transform + +// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use +// non-standard versions there. +#if defined(__APPLE__) && WEBP_AARCH64 && \ + defined(__apple_build_version__) && (__apple_build_version__< 6020037) +#define USE_VTBLQ +#endif + +#ifdef USE_VTBLQ +// 255 = byte will be zeroed +static const uint8_t kGreenShuffle[16] = { + 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255 +}; + +static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb, + const uint8x16_t shuffle) { + return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)), + vtbl1q_u8(argb, vget_high_u8(shuffle))); +} +#else // !USE_VTBLQ +// 255 = byte will be zeroed +static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 }; + +static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb, + const uint8x8_t shuffle) { + return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle), + vtbl1_u8(vget_high_u8(argb), shuffle)); +} +#endif // USE_VTBLQ + +static void SubtractGreenFromBlueAndRed_NEON(uint32_t* argb_data, + int num_pixels) { + const uint32_t* const end = argb_data + (num_pixels & ~3); +#ifdef USE_VTBLQ + const uint8x16_t shuffle = vld1q_u8(kGreenShuffle); +#else + const uint8x8_t shuffle = vld1_u8(kGreenShuffle); +#endif + for (; argb_data < end; argb_data += 4) { + const uint8x16_t argb = vld1q_u8((uint8_t*)argb_data); + const uint8x16_t greens = DoGreenShuffle_NEON(argb, shuffle); + vst1q_u8((uint8_t*)argb_data, vsubq_u8(argb, greens)); + } + // fallthrough and finish off with plain-C + VP8LSubtractGreenFromBlueAndRed_C(argb_data, num_pixels & 3); +} + +//------------------------------------------------------------------------------ +// Color Transform + +static void TransformColor_NEON(const VP8LMultipliers* const m, + uint32_t* argb_data, int num_pixels) { + // sign-extended multiplying constants, pre-shifted by 6. +#define CST(X) (((int16_t)(m->X << 8)) >> 6) + const int16_t rb[8] = { + CST(green_to_blue_), CST(green_to_red_), + CST(green_to_blue_), CST(green_to_red_), + CST(green_to_blue_), CST(green_to_red_), + CST(green_to_blue_), CST(green_to_red_) + }; + const int16x8_t mults_rb = vld1q_s16(rb); + const int16_t b2[8] = { + 0, CST(red_to_blue_), 0, CST(red_to_blue_), + 0, CST(red_to_blue_), 0, CST(red_to_blue_), + }; + const int16x8_t mults_b2 = vld1q_s16(b2); +#undef CST +#ifdef USE_VTBLQ + static const uint8_t kg0g0[16] = { + 255, 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13 + }; + const uint8x16_t shuffle = vld1q_u8(kg0g0); +#else + static const uint8_t k0g0g[8] = { 255, 1, 255, 1, 255, 5, 255, 5 }; + const uint8x8_t shuffle = vld1_u8(k0g0g); +#endif + const uint32x4_t mask_rb = vdupq_n_u32(0x00ff00ffu); // red-blue masks + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t in = vld1q_u8((uint8_t*)(argb_data + i)); + // 0 g 0 g + const uint8x16_t greens = DoGreenShuffle_NEON(in, shuffle); + // x dr x db1 + const int16x8_t A = vqdmulhq_s16(vreinterpretq_s16_u8(greens), mults_rb); + // r 0 b 0 + const int16x8_t B = vshlq_n_s16(vreinterpretq_s16_u8(in), 8); + // x db2 0 0 + const int16x8_t C = vqdmulhq_s16(B, mults_b2); + // 0 0 x db2 + const uint32x4_t D = vshrq_n_u32(vreinterpretq_u32_s16(C), 16); + // x dr x db + const int8x16_t E = vaddq_s8(vreinterpretq_s8_u32(D), + vreinterpretq_s8_s16(A)); + // 0 dr 0 db + const uint32x4_t F = vandq_u32(vreinterpretq_u32_s8(E), mask_rb); + const int8x16_t out = vsubq_s8(vreinterpretq_s8_u8(in), + vreinterpretq_s8_u32(F)); + vst1q_s8((int8_t*)(argb_data + i), out); + } + // fallthrough and finish off with plain-C + VP8LTransformColor_C(m, argb_data + i, num_pixels - i); +} + +#undef USE_VTBLQ + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LEncDspInitNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitNEON(void) { + VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_NEON; + VP8LTransformColor = TransformColor_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(VP8LEncDspInitNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/lossless_enc_sse2.c b/libraries/webp/src/dsp/lossless_enc_sse2.c new file mode 100644 index 00000000000..66cbaab7720 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_enc_sse2.c @@ -0,0 +1,669 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 variant of methods for lossless encoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) +#include +#include +#include "src/dsp/lossless.h" +#include "src/dsp/common_sse2.h" +#include "src/dsp/lossless_common.h" + +// For sign-extended multiplying constants, pre-shifted by 5: +#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5) + +//------------------------------------------------------------------------------ +// Subtract-Green Transform + +static void SubtractGreenFromBlueAndRed_SSE2(uint32_t* argb_data, + int num_pixels) { + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb + const __m128i A = _mm_srli_epi16(in, 8); // 0 a 0 g + const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); + const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // 0g0g + const __m128i out = _mm_sub_epi8(in, C); + _mm_storeu_si128((__m128i*)&argb_data[i], out); + } + // fallthrough and finish off with plain-C + if (i != num_pixels) { + VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); + } +} + +//------------------------------------------------------------------------------ +// Color Transform + +#define MK_CST_16(HI, LO) \ + _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) + +static void TransformColor_SSE2(const VP8LMultipliers* const m, + uint32_t* argb_data, int num_pixels) { + const __m128i mults_rb = MK_CST_16(CST_5b(m->green_to_red_), + CST_5b(m->green_to_blue_)); + const __m128i mults_b2 = MK_CST_16(CST_5b(m->red_to_blue_), 0); + const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); // alpha-green masks + const __m128i mask_rb = _mm_set1_epi32(0x00ff00ff); // red-blue masks + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb + const __m128i A = _mm_and_si128(in, mask_ag); // a 0 g 0 + const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); + const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // g0g0 + const __m128i D = _mm_mulhi_epi16(C, mults_rb); // x dr x db1 + const __m128i E = _mm_slli_epi16(in, 8); // r 0 b 0 + const __m128i F = _mm_mulhi_epi16(E, mults_b2); // x db2 0 0 + const __m128i G = _mm_srli_epi32(F, 16); // 0 0 x db2 + const __m128i H = _mm_add_epi8(G, D); // x dr x db + const __m128i I = _mm_and_si128(H, mask_rb); // 0 dr 0 db + const __m128i out = _mm_sub_epi8(in, I); + _mm_storeu_si128((__m128i*)&argb_data[i], out); + } + // fallthrough and finish off with plain-C + if (i != num_pixels) { + VP8LTransformColor_C(m, argb_data + i, num_pixels - i); + } +} + +//------------------------------------------------------------------------------ +#define SPAN 8 +static void CollectColorBlueTransforms_SSE2(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_blue, int red_to_blue, + int histo[]) { + const __m128i mults_r = MK_CST_16(CST_5b(red_to_blue), 0); + const __m128i mults_g = MK_CST_16(0, CST_5b(green_to_blue)); + const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask + const __m128i mask_b = _mm_set1_epi32(0x0000ff); // blue mask + int y; + for (y = 0; y < tile_height; ++y) { + const uint32_t* const src = argb + y * stride; + int i, x; + for (x = 0; x + SPAN <= tile_width; x += SPAN) { + uint16_t values[SPAN]; + const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]); + const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]); + const __m128i A0 = _mm_slli_epi16(in0, 8); // r 0 | b 0 + const __m128i A1 = _mm_slli_epi16(in1, 8); + const __m128i B0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0 + const __m128i B1 = _mm_and_si128(in1, mask_g); + const __m128i C0 = _mm_mulhi_epi16(A0, mults_r); // x db | 0 0 + const __m128i C1 = _mm_mulhi_epi16(A1, mults_r); + const __m128i D0 = _mm_mulhi_epi16(B0, mults_g); // 0 0 | x db + const __m128i D1 = _mm_mulhi_epi16(B1, mults_g); + const __m128i E0 = _mm_sub_epi8(in0, D0); // x x | x b' + const __m128i E1 = _mm_sub_epi8(in1, D1); + const __m128i F0 = _mm_srli_epi32(C0, 16); // 0 0 | x db + const __m128i F1 = _mm_srli_epi32(C1, 16); + const __m128i G0 = _mm_sub_epi8(E0, F0); // 0 0 | x b' + const __m128i G1 = _mm_sub_epi8(E1, F1); + const __m128i H0 = _mm_and_si128(G0, mask_b); // 0 0 | 0 b + const __m128i H1 = _mm_and_si128(G1, mask_b); + const __m128i I = _mm_packs_epi32(H0, H1); // 0 b' | 0 b' + _mm_storeu_si128((__m128i*)values, I); + for (i = 0; i < SPAN; ++i) ++histo[values[i]]; + } + } + { + const int left_over = tile_width & (SPAN - 1); + if (left_over > 0) { + VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride, + left_over, tile_height, + green_to_blue, red_to_blue, histo); + } + } +} + +static void CollectColorRedTransforms_SSE2(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_red, int histo[]) { + const __m128i mults_g = MK_CST_16(0, CST_5b(green_to_red)); + const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask + const __m128i mask = _mm_set1_epi32(0xff); + + int y; + for (y = 0; y < tile_height; ++y) { + const uint32_t* const src = argb + y * stride; + int i, x; + for (x = 0; x + SPAN <= tile_width; x += SPAN) { + uint16_t values[SPAN]; + const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]); + const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]); + const __m128i A0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0 + const __m128i A1 = _mm_and_si128(in1, mask_g); + const __m128i B0 = _mm_srli_epi32(in0, 16); // 0 0 | x r + const __m128i B1 = _mm_srli_epi32(in1, 16); + const __m128i C0 = _mm_mulhi_epi16(A0, mults_g); // 0 0 | x dr + const __m128i C1 = _mm_mulhi_epi16(A1, mults_g); + const __m128i E0 = _mm_sub_epi8(B0, C0); // x x | x r' + const __m128i E1 = _mm_sub_epi8(B1, C1); + const __m128i F0 = _mm_and_si128(E0, mask); // 0 0 | 0 r' + const __m128i F1 = _mm_and_si128(E1, mask); + const __m128i I = _mm_packs_epi32(F0, F1); + _mm_storeu_si128((__m128i*)values, I); + for (i = 0; i < SPAN; ++i) ++histo[values[i]]; + } + } + { + const int left_over = tile_width & (SPAN - 1); + if (left_over > 0) { + VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride, + left_over, tile_height, + green_to_red, histo); + } + } +} +#undef SPAN +#undef MK_CST_16 + +//------------------------------------------------------------------------------ + +// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But +// that's ok since the histogram values are less than 1<<28 (max picture size). +#define LINE_SIZE 16 // 8 or 16 +static void AddVector_SSE2(const uint32_t* a, const uint32_t* b, uint32_t* out, + int size) { + int i; + for (i = 0; i + LINE_SIZE <= size; i += LINE_SIZE) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]); + const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); +#if (LINE_SIZE == 16) + const __m128i a2 = _mm_loadu_si128((const __m128i*)&a[i + 8]); + const __m128i a3 = _mm_loadu_si128((const __m128i*)&a[i + 12]); +#endif + const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[i + 0]); + const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[i + 4]); +#if (LINE_SIZE == 16) + const __m128i b2 = _mm_loadu_si128((const __m128i*)&b[i + 8]); + const __m128i b3 = _mm_loadu_si128((const __m128i*)&b[i + 12]); +#endif + _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0)); + _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1)); +#if (LINE_SIZE == 16) + _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2)); + _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3)); +#endif + } + for (; i < size; ++i) { + out[i] = a[i] + b[i]; + } +} + +static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) { + int i; + for (i = 0; i + LINE_SIZE <= size; i += LINE_SIZE) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]); + const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); +#if (LINE_SIZE == 16) + const __m128i a2 = _mm_loadu_si128((const __m128i*)&a[i + 8]); + const __m128i a3 = _mm_loadu_si128((const __m128i*)&a[i + 12]); +#endif + const __m128i b0 = _mm_loadu_si128((const __m128i*)&out[i + 0]); + const __m128i b1 = _mm_loadu_si128((const __m128i*)&out[i + 4]); +#if (LINE_SIZE == 16) + const __m128i b2 = _mm_loadu_si128((const __m128i*)&out[i + 8]); + const __m128i b3 = _mm_loadu_si128((const __m128i*)&out[i + 12]); +#endif + _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0)); + _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1)); +#if (LINE_SIZE == 16) + _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2)); + _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3)); +#endif + } + for (; i < size; ++i) { + out[i] += a[i]; + } +} +#undef LINE_SIZE + +//------------------------------------------------------------------------------ +// Entropy + +// TODO(https://crbug.com/webp/499): this function produces different results +// from the C code due to use of double/float resulting in output differences +// when compared to -noasm. +#if !(defined(WEBP_HAVE_SLOW_CLZ_CTZ) || defined(__i386__) || defined(_M_IX86)) + +static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) { + int i; + float retval = 0.f; + int sumX = 0, sumXY = 0; + const __m128i zero = _mm_setzero_si128(); + + for (i = 0; i < 256; i += 16) { + const __m128i x0 = _mm_loadu_si128((const __m128i*)(X + i + 0)); + const __m128i y0 = _mm_loadu_si128((const __m128i*)(Y + i + 0)); + const __m128i x1 = _mm_loadu_si128((const __m128i*)(X + i + 4)); + const __m128i y1 = _mm_loadu_si128((const __m128i*)(Y + i + 4)); + const __m128i x2 = _mm_loadu_si128((const __m128i*)(X + i + 8)); + const __m128i y2 = _mm_loadu_si128((const __m128i*)(Y + i + 8)); + const __m128i x3 = _mm_loadu_si128((const __m128i*)(X + i + 12)); + const __m128i y3 = _mm_loadu_si128((const __m128i*)(Y + i + 12)); + const __m128i x4 = _mm_packs_epi16(_mm_packs_epi32(x0, x1), + _mm_packs_epi32(x2, x3)); + const __m128i y4 = _mm_packs_epi16(_mm_packs_epi32(y0, y1), + _mm_packs_epi32(y2, y3)); + const int32_t mx = _mm_movemask_epi8(_mm_cmpgt_epi8(x4, zero)); + int32_t my = _mm_movemask_epi8(_mm_cmpgt_epi8(y4, zero)) | mx; + while (my) { + const int32_t j = BitsCtz(my); + int xy; + if ((mx >> j) & 1) { + const int x = X[i + j]; + sumXY += x; + retval -= VP8LFastSLog2(x); + } + xy = X[i + j] + Y[i + j]; + sumX += xy; + retval -= VP8LFastSLog2(xy); + my &= my - 1; + } + } + retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY); + return retval; +} + +#else + +#define DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC // won't be faster + +#endif + +//------------------------------------------------------------------------------ + +static int VectorMismatch_SSE2(const uint32_t* const array1, + const uint32_t* const array2, int length) { + int match_len; + + if (length >= 12) { + __m128i A0 = _mm_loadu_si128((const __m128i*)&array1[0]); + __m128i A1 = _mm_loadu_si128((const __m128i*)&array2[0]); + match_len = 0; + do { + // Loop unrolling and early load both provide a speedup of 10% for the + // current function. Also, max_limit can be MAX_LENGTH=4096 at most. + const __m128i cmpA = _mm_cmpeq_epi32(A0, A1); + const __m128i B0 = + _mm_loadu_si128((const __m128i*)&array1[match_len + 4]); + const __m128i B1 = + _mm_loadu_si128((const __m128i*)&array2[match_len + 4]); + if (_mm_movemask_epi8(cmpA) != 0xffff) break; + match_len += 4; + + { + const __m128i cmpB = _mm_cmpeq_epi32(B0, B1); + A0 = _mm_loadu_si128((const __m128i*)&array1[match_len + 4]); + A1 = _mm_loadu_si128((const __m128i*)&array2[match_len + 4]); + if (_mm_movemask_epi8(cmpB) != 0xffff) break; + match_len += 4; + } + } while (match_len + 12 < length); + } else { + match_len = 0; + // Unroll the potential first two loops. + if (length >= 4 && + _mm_movemask_epi8(_mm_cmpeq_epi32( + _mm_loadu_si128((const __m128i*)&array1[0]), + _mm_loadu_si128((const __m128i*)&array2[0]))) == 0xffff) { + match_len = 4; + if (length >= 8 && + _mm_movemask_epi8(_mm_cmpeq_epi32( + _mm_loadu_si128((const __m128i*)&array1[4]), + _mm_loadu_si128((const __m128i*)&array2[4]))) == 0xffff) { + match_len = 8; + } + } + } + + while (match_len < length && array1[match_len] == array2[match_len]) { + ++match_len; + } + return match_len; +} + +// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. +static void BundleColorMap_SSE2(const uint8_t* const row, int width, int xbits, + uint32_t* dst) { + int x; + assert(xbits >= 0); + assert(xbits <= 3); + switch (xbits) { + case 0: { + const __m128i ff = _mm_set1_epi16((short)0xff00); + const __m128i zero = _mm_setzero_si128(); + // Store 0xff000000 | (row[x] << 8). + for (x = 0; x + 16 <= width; x += 16, dst += 16) { + const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); + const __m128i in_lo = _mm_unpacklo_epi8(zero, in); + const __m128i dst0 = _mm_unpacklo_epi16(in_lo, ff); + const __m128i dst1 = _mm_unpackhi_epi16(in_lo, ff); + const __m128i in_hi = _mm_unpackhi_epi8(zero, in); + const __m128i dst2 = _mm_unpacklo_epi16(in_hi, ff); + const __m128i dst3 = _mm_unpackhi_epi16(in_hi, ff); + _mm_storeu_si128((__m128i*)&dst[0], dst0); + _mm_storeu_si128((__m128i*)&dst[4], dst1); + _mm_storeu_si128((__m128i*)&dst[8], dst2); + _mm_storeu_si128((__m128i*)&dst[12], dst3); + } + break; + } + case 1: { + const __m128i ff = _mm_set1_epi16((short)0xff00); + const __m128i mul = _mm_set1_epi16(0x110); + for (x = 0; x + 16 <= width; x += 16, dst += 8) { + // 0a0b | (where a/b are 4 bits). + const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); + const __m128i tmp = _mm_mullo_epi16(in, mul); // aba0 + const __m128i pack = _mm_and_si128(tmp, ff); // ab00 + const __m128i dst0 = _mm_unpacklo_epi16(pack, ff); + const __m128i dst1 = _mm_unpackhi_epi16(pack, ff); + _mm_storeu_si128((__m128i*)&dst[0], dst0); + _mm_storeu_si128((__m128i*)&dst[4], dst1); + } + break; + } + case 2: { + const __m128i mask_or = _mm_set1_epi32((int)0xff000000); + const __m128i mul_cst = _mm_set1_epi16(0x0104); + const __m128i mask_mul = _mm_set1_epi16(0x0f00); + for (x = 0; x + 16 <= width; x += 16, dst += 4) { + // 000a000b000c000d | (where a/b/c/d are 2 bits). + const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); + const __m128i mul = _mm_mullo_epi16(in, mul_cst); // 00ab00b000cd00d0 + const __m128i tmp = _mm_and_si128(mul, mask_mul); // 00ab000000cd0000 + const __m128i shift = _mm_srli_epi32(tmp, 12); // 00000000ab000000 + const __m128i pack = _mm_or_si128(shift, tmp); // 00000000abcd0000 + // Convert to 0xff00**00. + const __m128i res = _mm_or_si128(pack, mask_or); + _mm_storeu_si128((__m128i*)dst, res); + } + break; + } + default: { + assert(xbits == 3); + for (x = 0; x + 16 <= width; x += 16, dst += 2) { + // 0000000a00000000b... | (where a/b are 1 bit). + const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); + const __m128i shift = _mm_slli_epi64(in, 7); + const uint32_t move = _mm_movemask_epi8(shift); + dst[0] = 0xff000000 | ((move & 0xff) << 8); + dst[1] = 0xff000000 | (move & 0xff00); + } + break; + } + } + if (x != width) { + VP8LBundleColorMap_C(row + x, width - x, xbits, dst); + } +} + +//------------------------------------------------------------------------------ +// Batch version of Predictor Transform subtraction + +static WEBP_INLINE void Average2_m128i(const __m128i* const a0, + const __m128i* const a1, + __m128i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m128i ones = _mm_set1_epi8(1); + const __m128i avg1 = _mm_avg_epu8(*a0, *a1); + const __m128i one = _mm_and_si128(_mm_xor_si128(*a0, *a1), ones); + *avg = _mm_sub_epi8(avg1, one); +} + +// Predictor0: ARGB_BLACK. +static void PredictorSub0_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i black = _mm_set1_epi32((int)ARGB_BLACK); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i res = _mm_sub_epi8(src, black); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[0](in + i, NULL, num_pixels - i, out + i); + } + (void)upper; +} + +#define GENERATE_PREDICTOR_1(X, IN) \ + static void PredictorSub##X##_SSE2(const uint32_t* const in, \ + const uint32_t* const upper, \ + int num_pixels, uint32_t* const out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ + const __m128i pred = _mm_loadu_si128((const __m128i*)&(IN)); \ + const __m128i res = _mm_sub_epi8(src, pred); \ + _mm_storeu_si128((__m128i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsSub_C[(X)](in + i, WEBP_OFFSET_PTR(upper, i), \ + num_pixels - i, out + i); \ + } \ + } + +GENERATE_PREDICTOR_1(1, in[i - 1]) // Predictor1: L +GENERATE_PREDICTOR_1(2, upper[i]) // Predictor2: T +GENERATE_PREDICTOR_1(3, upper[i + 1]) // Predictor3: TR +GENERATE_PREDICTOR_1(4, upper[i - 1]) // Predictor4: TL +#undef GENERATE_PREDICTOR_1 + +// Predictor5: avg2(avg2(L, TR), T) +static void PredictorSub5_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]); + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + __m128i avg, pred, res; + Average2_m128i(&L, &TR, &avg); + Average2_m128i(&avg, &T, &pred); + res = _mm_sub_epi8(src, pred); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[5](in + i, upper + i, num_pixels - i, out + i); + } +} + +#define GENERATE_PREDICTOR_2(X, A, B) \ +static void PredictorSub##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const __m128i tA = _mm_loadu_si128((const __m128i*)&(A)); \ + const __m128i tB = _mm_loadu_si128((const __m128i*)&(B)); \ + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ + __m128i pred, res; \ + Average2_m128i(&tA, &tB, &pred); \ + res = _mm_sub_epi8(src, pred); \ + _mm_storeu_si128((__m128i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsSub_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ +} + +GENERATE_PREDICTOR_2(6, in[i - 1], upper[i - 1]) // Predictor6: avg(L, TL) +GENERATE_PREDICTOR_2(7, in[i - 1], upper[i]) // Predictor7: avg(L, T) +GENERATE_PREDICTOR_2(8, upper[i - 1], upper[i]) // Predictor8: avg(TL, T) +GENERATE_PREDICTOR_2(9, upper[i], upper[i + 1]) // Predictor9: average(T, TR) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: avg(avg(L,TL), avg(T, TR)). +static void PredictorSub10_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]); + __m128i avgTTR, avgLTL, avg, res; + Average2_m128i(&T, &TR, &avgTTR); + Average2_m128i(&L, &TL, &avgLTL); + Average2_m128i(&avgTTR, &avgLTL, &avg); + res = _mm_sub_epi8(src, avg); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[10](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor11: select. +static void GetSumAbsDiff32_SSE2(const __m128i* const A, const __m128i* const B, + __m128i* const out) { + // We can unpack with any value on the upper 32 bits, provided it's the same + // on both operands (to that their sum of abs diff is zero). Here we use *A. + const __m128i A_lo = _mm_unpacklo_epi32(*A, *A); + const __m128i B_lo = _mm_unpacklo_epi32(*B, *A); + const __m128i A_hi = _mm_unpackhi_epi32(*A, *A); + const __m128i B_hi = _mm_unpackhi_epi32(*B, *A); + const __m128i s_lo = _mm_sad_epu8(A_lo, B_lo); + const __m128i s_hi = _mm_sad_epu8(A_hi, B_hi); + *out = _mm_packs_epi32(s_lo, s_hi); +} + +static void PredictorSub11_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + __m128i pa, pb; + GetSumAbsDiff32_SSE2(&T, &TL, &pa); // pa = sum |T-TL| + GetSumAbsDiff32_SSE2(&L, &TL, &pb); // pb = sum |L-TL| + { + const __m128i mask = _mm_cmpgt_epi32(pb, pa); + const __m128i A = _mm_and_si128(mask, L); + const __m128i B = _mm_andnot_si128(mask, T); + const __m128i pred = _mm_or_si128(A, B); // pred = (L > T)? L : T + const __m128i res = _mm_sub_epi8(src, pred); + _mm_storeu_si128((__m128i*)&out[i], res); + } + } + if (i != num_pixels) { + VP8LPredictorsSub_C[11](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictor12: ClampedSubSubtractFull. +static void PredictorSub12_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); + const __m128i L_lo = _mm_unpacklo_epi8(L, zero); + const __m128i L_hi = _mm_unpackhi_epi8(L, zero); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i T_lo = _mm_unpacklo_epi8(T, zero); + const __m128i T_hi = _mm_unpackhi_epi8(T, zero); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); + const __m128i TL_hi = _mm_unpackhi_epi8(TL, zero); + const __m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo); + const __m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi); + const __m128i pred_lo = _mm_add_epi16(L_lo, diff_lo); + const __m128i pred_hi = _mm_add_epi16(L_hi, diff_hi); + const __m128i pred = _mm_packus_epi16(pred_lo, pred_hi); + const __m128i res = _mm_sub_epi8(src, pred); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[12](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Predictors13: ClampedAddSubtractHalf +static void PredictorSub13_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 2 <= num_pixels; i += 2) { + // we can only process two pixels at a time + const __m128i L = _mm_loadl_epi64((const __m128i*)&in[i - 1]); + const __m128i src = _mm_loadl_epi64((const __m128i*)&in[i]); + const __m128i T = _mm_loadl_epi64((const __m128i*)&upper[i]); + const __m128i TL = _mm_loadl_epi64((const __m128i*)&upper[i - 1]); + const __m128i L_lo = _mm_unpacklo_epi8(L, zero); + const __m128i T_lo = _mm_unpacklo_epi8(T, zero); + const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); + const __m128i sum = _mm_add_epi16(T_lo, L_lo); + const __m128i avg = _mm_srli_epi16(sum, 1); + const __m128i A1 = _mm_sub_epi16(avg, TL_lo); + const __m128i bit_fix = _mm_cmpgt_epi16(TL_lo, avg); + const __m128i A2 = _mm_sub_epi16(A1, bit_fix); + const __m128i A3 = _mm_srai_epi16(A2, 1); + const __m128i A4 = _mm_add_epi16(avg, A3); + const __m128i pred = _mm_packus_epi16(A4, A4); + const __m128i res = _mm_sub_epi8(src, pred); + _mm_storel_epi64((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsSub_C[13](in + i, upper + i, num_pixels - i, out + i); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LEncDspInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) { + VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_SSE2; + VP8LTransformColor = TransformColor_SSE2; + VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE2; + VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE2; + VP8LAddVector = AddVector_SSE2; + VP8LAddVectorEq = AddVectorEq_SSE2; +#if !defined(DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC) + VP8LCombinedShannonEntropy = CombinedShannonEntropy_SSE2; +#endif + VP8LVectorMismatch = VectorMismatch_SSE2; + VP8LBundleColorMap = BundleColorMap_SSE2; + + VP8LPredictorsSub[0] = PredictorSub0_SSE2; + VP8LPredictorsSub[1] = PredictorSub1_SSE2; + VP8LPredictorsSub[2] = PredictorSub2_SSE2; + VP8LPredictorsSub[3] = PredictorSub3_SSE2; + VP8LPredictorsSub[4] = PredictorSub4_SSE2; + VP8LPredictorsSub[5] = PredictorSub5_SSE2; + VP8LPredictorsSub[6] = PredictorSub6_SSE2; + VP8LPredictorsSub[7] = PredictorSub7_SSE2; + VP8LPredictorsSub[8] = PredictorSub8_SSE2; + VP8LPredictorsSub[9] = PredictorSub9_SSE2; + VP8LPredictorsSub[10] = PredictorSub10_SSE2; + VP8LPredictorsSub[11] = PredictorSub11_SSE2; + VP8LPredictorsSub[12] = PredictorSub12_SSE2; + VP8LPredictorsSub[13] = PredictorSub13_SSE2; + VP8LPredictorsSub[14] = PredictorSub0_SSE2; // <- padding security sentinels + VP8LPredictorsSub[15] = PredictorSub0_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(VP8LEncDspInitSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/lossless_enc_sse41.c b/libraries/webp/src/dsp/lossless_enc_sse41.c new file mode 100644 index 00000000000..7ab83c2604b --- /dev/null +++ b/libraries/webp/src/dsp/lossless_enc_sse41.c @@ -0,0 +1,205 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE4.1 variant of methods for lossless encoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE41) +#include +#include +#include "src/dsp/lossless.h" + +//------------------------------------------------------------------------------ +// Cost operations. + +static WEBP_INLINE uint32_t HorizontalSum_SSE41(__m128i cost) { + cost = _mm_add_epi32(cost, _mm_srli_si128(cost, 8)); + cost = _mm_add_epi32(cost, _mm_srli_si128(cost, 4)); + return _mm_cvtsi128_si32(cost); +} + +static uint32_t ExtraCost_SSE41(const uint32_t* const a, int length) { + int i; + __m128i cost = _mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]); + assert(length % 8 == 0); + + for (i = 8; i + 8 <= length; i += 8) { + const int j = (i - 2) >> 1; + const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]); + const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); + const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j); + const __m128i a2 = _mm_hadd_epi32(a0, a1); + const __m128i mul = _mm_mullo_epi32(a2, w); + cost = _mm_add_epi32(mul, cost); + } + return HorizontalSum_SSE41(cost); +} + +static uint32_t ExtraCostCombined_SSE41(const uint32_t* const a, + const uint32_t* const b, int length) { + int i; + __m128i cost = _mm_add_epi32(_mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]), + _mm_set_epi32(2 * b[7], 2 * b[6], b[5], b[4])); + assert(length % 8 == 0); + + for (i = 8; i + 8 <= length; i += 8) { + const int j = (i - 2) >> 1; + const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]); + const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); + const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[i]); + const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[i + 4]); + const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j); + const __m128i a2 = _mm_hadd_epi32(a0, a1); + const __m128i b2 = _mm_hadd_epi32(b0, b1); + const __m128i mul = _mm_mullo_epi32(_mm_add_epi32(a2, b2), w); + cost = _mm_add_epi32(mul, cost); + } + return HorizontalSum_SSE41(cost); +} + +//------------------------------------------------------------------------------ +// Subtract-Green Transform + +static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data, + int num_pixels) { + int i; + const __m128i kCstShuffle = _mm_set_epi8(-1, 13, -1, 13, -1, 9, -1, 9, + -1, 5, -1, 5, -1, 1, -1, 1); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); + const __m128i in_0g0g = _mm_shuffle_epi8(in, kCstShuffle); + const __m128i out = _mm_sub_epi8(in, in_0g0g); + _mm_storeu_si128((__m128i*)&argb_data[i], out); + } + // fallthrough and finish off with plain-C + if (i != num_pixels) { + VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); + } +} + +//------------------------------------------------------------------------------ +// Color Transform + +// For sign-extended multiplying constants, pre-shifted by 5: +#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5) + +#define MK_CST_16(HI, LO) \ + _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) + +static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_blue, int red_to_blue, + int histo[]) { + const __m128i mult = + MK_CST_16(CST_5b(red_to_blue) + 256,CST_5b(green_to_blue)); + const __m128i perm = + _mm_setr_epi8(-1, 1, -1, 2, -1, 5, -1, 6, -1, 9, -1, 10, -1, 13, -1, 14); + if (tile_width >= 4) { + int y; + for (y = 0; y < tile_height; ++y) { + const uint32_t* const src = argb + y * stride; + const __m128i A1 = _mm_loadu_si128((const __m128i*)src); + const __m128i B1 = _mm_shuffle_epi8(A1, perm); + const __m128i C1 = _mm_mulhi_epi16(B1, mult); + const __m128i D1 = _mm_sub_epi16(A1, C1); + __m128i E = _mm_add_epi16(_mm_srli_epi32(D1, 16), D1); + int x; + for (x = 4; x + 4 <= tile_width; x += 4) { + const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x)); + __m128i B2, C2, D2; + ++histo[_mm_extract_epi8(E, 0)]; + B2 = _mm_shuffle_epi8(A2, perm); + ++histo[_mm_extract_epi8(E, 4)]; + C2 = _mm_mulhi_epi16(B2, mult); + ++histo[_mm_extract_epi8(E, 8)]; + D2 = _mm_sub_epi16(A2, C2); + ++histo[_mm_extract_epi8(E, 12)]; + E = _mm_add_epi16(_mm_srli_epi32(D2, 16), D2); + } + ++histo[_mm_extract_epi8(E, 0)]; + ++histo[_mm_extract_epi8(E, 4)]; + ++histo[_mm_extract_epi8(E, 8)]; + ++histo[_mm_extract_epi8(E, 12)]; + } + } + { + const int left_over = tile_width & 3; + if (left_over > 0) { + VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride, + left_over, tile_height, + green_to_blue, red_to_blue, histo); + } + } +} + +static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_red, int histo[]) { + + const __m128i mult = MK_CST_16(0, CST_5b(green_to_red)); + const __m128i mask_g = _mm_set1_epi32(0x0000ff00); + if (tile_width >= 4) { + int y; + for (y = 0; y < tile_height; ++y) { + const uint32_t* const src = argb + y * stride; + const __m128i A1 = _mm_loadu_si128((const __m128i*)src); + const __m128i B1 = _mm_and_si128(A1, mask_g); + const __m128i C1 = _mm_madd_epi16(B1, mult); + __m128i D = _mm_sub_epi16(A1, C1); + int x; + for (x = 4; x + 4 <= tile_width; x += 4) { + const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x)); + __m128i B2, C2; + ++histo[_mm_extract_epi8(D, 2)]; + B2 = _mm_and_si128(A2, mask_g); + ++histo[_mm_extract_epi8(D, 6)]; + C2 = _mm_madd_epi16(B2, mult); + ++histo[_mm_extract_epi8(D, 10)]; + ++histo[_mm_extract_epi8(D, 14)]; + D = _mm_sub_epi16(A2, C2); + } + ++histo[_mm_extract_epi8(D, 2)]; + ++histo[_mm_extract_epi8(D, 6)]; + ++histo[_mm_extract_epi8(D, 10)]; + ++histo[_mm_extract_epi8(D, 14)]; + } + } + { + const int left_over = tile_width & 3; + if (left_over > 0) { + VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride, + left_over, tile_height, green_to_red, + histo); + } + } +} + +#undef MK_CST_16 + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LEncDspInitSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE41(void) { + VP8LExtraCost = ExtraCost_SSE41; + VP8LExtraCostCombined = ExtraCostCombined_SSE41; + VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_SSE41; + VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE41; + VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE41; +} + +#else // !WEBP_USE_SSE41 + +WEBP_DSP_INIT_STUB(VP8LEncDspInitSSE41) + +#endif // WEBP_USE_SSE41 diff --git a/libraries/webp/src/dsp/lossless_mips_dsp_r2.c b/libraries/webp/src/dsp/lossless_mips_dsp_r2.c new file mode 100644 index 00000000000..bfe5ea6b386 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_mips_dsp_r2.c @@ -0,0 +1,701 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Image transforms and color space conversion methods for lossless decoder. +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) +// Jovan Zelincevic (jovan.zelincevic@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" + +#define MAP_COLOR_FUNCS(FUNC_NAME, TYPE, GET_INDEX, GET_VALUE) \ +static void FUNC_NAME(const TYPE* src, \ + const uint32_t* const color_map, \ + TYPE* dst, int y_start, int y_end, \ + int width) { \ + int y; \ + for (y = y_start; y < y_end; ++y) { \ + int x; \ + for (x = 0; x < (width >> 2); ++x) { \ + int tmp1, tmp2, tmp3, tmp4; \ + __asm__ volatile ( \ + ".ifc " #TYPE ", uint8_t \n\t" \ + "lbu %[tmp1], 0(%[src]) \n\t" \ + "lbu %[tmp2], 1(%[src]) \n\t" \ + "lbu %[tmp3], 2(%[src]) \n\t" \ + "lbu %[tmp4], 3(%[src]) \n\t" \ + "addiu %[src], %[src], 4 \n\t" \ + ".endif \n\t" \ + ".ifc " #TYPE ", uint32_t \n\t" \ + "lw %[tmp1], 0(%[src]) \n\t" \ + "lw %[tmp2], 4(%[src]) \n\t" \ + "lw %[tmp3], 8(%[src]) \n\t" \ + "lw %[tmp4], 12(%[src]) \n\t" \ + "ext %[tmp1], %[tmp1], 8, 8 \n\t" \ + "ext %[tmp2], %[tmp2], 8, 8 \n\t" \ + "ext %[tmp3], %[tmp3], 8, 8 \n\t" \ + "ext %[tmp4], %[tmp4], 8, 8 \n\t" \ + "addiu %[src], %[src], 16 \n\t" \ + ".endif \n\t" \ + "sll %[tmp1], %[tmp1], 2 \n\t" \ + "sll %[tmp2], %[tmp2], 2 \n\t" \ + "sll %[tmp3], %[tmp3], 2 \n\t" \ + "sll %[tmp4], %[tmp4], 2 \n\t" \ + "lwx %[tmp1], %[tmp1](%[color_map]) \n\t" \ + "lwx %[tmp2], %[tmp2](%[color_map]) \n\t" \ + "lwx %[tmp3], %[tmp3](%[color_map]) \n\t" \ + "lwx %[tmp4], %[tmp4](%[color_map]) \n\t" \ + ".ifc " #TYPE ", uint8_t \n\t" \ + "ext %[tmp1], %[tmp1], 8, 8 \n\t" \ + "ext %[tmp2], %[tmp2], 8, 8 \n\t" \ + "ext %[tmp3], %[tmp3], 8, 8 \n\t" \ + "ext %[tmp4], %[tmp4], 8, 8 \n\t" \ + "sb %[tmp1], 0(%[dst]) \n\t" \ + "sb %[tmp2], 1(%[dst]) \n\t" \ + "sb %[tmp3], 2(%[dst]) \n\t" \ + "sb %[tmp4], 3(%[dst]) \n\t" \ + "addiu %[dst], %[dst], 4 \n\t" \ + ".endif \n\t" \ + ".ifc " #TYPE ", uint32_t \n\t" \ + "sw %[tmp1], 0(%[dst]) \n\t" \ + "sw %[tmp2], 4(%[dst]) \n\t" \ + "sw %[tmp3], 8(%[dst]) \n\t" \ + "sw %[tmp4], 12(%[dst]) \n\t" \ + "addiu %[dst], %[dst], 16 \n\t" \ + ".endif \n\t" \ + : [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [tmp3]"=&r"(tmp3), \ + [tmp4]"=&r"(tmp4), [src]"+&r"(src), [dst]"+r"(dst) \ + : [color_map]"r"(color_map) \ + : "memory" \ + ); \ + } \ + for (x = 0; x < (width & 3); ++x) { \ + *dst++ = GET_VALUE(color_map[GET_INDEX(*src++)]); \ + } \ + } \ +} + +MAP_COLOR_FUNCS(MapARGB_MIPSdspR2, uint32_t, VP8GetARGBIndex, VP8GetARGBValue) +MAP_COLOR_FUNCS(MapAlpha_MIPSdspR2, uint8_t, VP8GetAlphaIndex, VP8GetAlphaValue) + +#undef MAP_COLOR_FUNCS + +static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1, + uint32_t c2) { + int temp0, temp1, temp2, temp3, temp4, temp5; + __asm__ volatile ( + "preceu.ph.qbr %[temp1], %[c0] \n\t" + "preceu.ph.qbl %[temp2], %[c0] \n\t" + "preceu.ph.qbr %[temp3], %[c1] \n\t" + "preceu.ph.qbl %[temp4], %[c1] \n\t" + "preceu.ph.qbr %[temp5], %[c2] \n\t" + "preceu.ph.qbl %[temp0], %[c2] \n\t" + "subq.ph %[temp3], %[temp3], %[temp5] \n\t" + "subq.ph %[temp4], %[temp4], %[temp0] \n\t" + "addq.ph %[temp1], %[temp1], %[temp3] \n\t" + "addq.ph %[temp2], %[temp2], %[temp4] \n\t" + "shll_s.ph %[temp1], %[temp1], 7 \n\t" + "shll_s.ph %[temp2], %[temp2], 7 \n\t" + "precrqu_s.qb.ph %[temp2], %[temp2], %[temp1] \n\t" + : [temp0]"=r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5) + : [c0]"r"(c0), [c1]"r"(c1), [c2]"r"(c2) + : "memory" + ); + return temp2; +} + +static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1, + uint32_t c2) { + int temp0, temp1, temp2, temp3, temp4, temp5; + __asm__ volatile ( + "adduh.qb %[temp5], %[c0], %[c1] \n\t" + "preceu.ph.qbr %[temp3], %[c2] \n\t" + "preceu.ph.qbr %[temp1], %[temp5] \n\t" + "preceu.ph.qbl %[temp2], %[temp5] \n\t" + "preceu.ph.qbl %[temp4], %[c2] \n\t" + "subq.ph %[temp3], %[temp1], %[temp3] \n\t" + "subq.ph %[temp4], %[temp2], %[temp4] \n\t" + "shrl.ph %[temp5], %[temp3], 15 \n\t" + "shrl.ph %[temp0], %[temp4], 15 \n\t" + "addq.ph %[temp3], %[temp3], %[temp5] \n\t" + "addq.ph %[temp4], %[temp0], %[temp4] \n\t" + "shra.ph %[temp3], %[temp3], 1 \n\t" + "shra.ph %[temp4], %[temp4], 1 \n\t" + "addq.ph %[temp1], %[temp1], %[temp3] \n\t" + "addq.ph %[temp2], %[temp2], %[temp4] \n\t" + "shll_s.ph %[temp1], %[temp1], 7 \n\t" + "shll_s.ph %[temp2], %[temp2], 7 \n\t" + "precrqu_s.qb.ph %[temp1], %[temp2], %[temp1] \n\t" + : [temp0]"=r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=r"(temp4), [temp5]"=&r"(temp5) + : [c0]"r"(c0), [c1]"r"(c1), [c2]"r"(c2) + : "memory" + ); + return temp1; +} + +static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) { + int temp0, temp1, temp2, temp3, temp4, temp5; + __asm__ volatile ( + "cmpgdu.lt.qb %[temp1], %[c], %[b] \n\t" + "pick.qb %[temp1], %[b], %[c] \n\t" + "pick.qb %[temp2], %[c], %[b] \n\t" + "cmpgdu.lt.qb %[temp4], %[c], %[a] \n\t" + "pick.qb %[temp4], %[a], %[c] \n\t" + "pick.qb %[temp5], %[c], %[a] \n\t" + "subu.qb %[temp3], %[temp1], %[temp2] \n\t" + "subu.qb %[temp0], %[temp4], %[temp5] \n\t" + "raddu.w.qb %[temp3], %[temp3] \n\t" + "raddu.w.qb %[temp0], %[temp0] \n\t" + "subu %[temp3], %[temp3], %[temp0] \n\t" + "slti %[temp0], %[temp3], 0x1 \n\t" + "movz %[a], %[b], %[temp0] \n\t" + : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp0]"=&r"(temp0), + [a]"+&r"(a) + : [b]"r"(b), [c]"r"(c) + ); + return a; +} + +static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) { + __asm__ volatile ( + "adduh.qb %[a0], %[a0], %[a1] \n\t" + : [a0]"+r"(a0) + : [a1]"r"(a1) + ); + return a0; +} + +static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) { + return Average2(Average2(a0, a2), a1); +} + +static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1, + uint32_t a2, uint32_t a3) { + return Average2(Average2(a0, a1), Average2(a2, a3)); +} + +static uint32_t Predictor5_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + return Average3(*left, top[0], top[1]); +} + +static uint32_t Predictor6_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + return Average2(*left, top[-1]); +} + +static uint32_t Predictor7_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + return Average2(*left, top[0]); +} + +static uint32_t Predictor8_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + (void)left; + return Average2(top[-1], top[0]); +} + +static uint32_t Predictor9_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + (void)left; + return Average2(top[0], top[1]); +} + +static uint32_t Predictor10_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + return Average4(*left, top[-1], top[0], top[1]); +} + +static uint32_t Predictor11_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + return Select(top[0], *left, top[-1]); +} + +static uint32_t Predictor12_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + return ClampedAddSubtractFull(*left, top[0], top[-1]); +} + +static uint32_t Predictor13_MIPSdspR2(const uint32_t* const left, + const uint32_t* const top) { + return ClampedAddSubtractHalf(*left, top[0], top[-1]); +} + +// Add green to blue and red channels (i.e. perform the inverse transform of +// 'subtract green'). +static void AddGreenToBlueAndRed_MIPSdspR2(const uint32_t* src, int num_pixels, + uint32_t* dst) { + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + const uint32_t* const p_loop1_end = src + (num_pixels & ~3); + const uint32_t* const p_loop2_end = src + num_pixels; + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[src], %[p_loop1_end], 3f \n\t" + " nop \n\t" + "0: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "lw %[temp1], 4(%[src]) \n\t" + "lw %[temp2], 8(%[src]) \n\t" + "lw %[temp3], 12(%[src]) \n\t" + "ext %[temp4], %[temp0], 8, 8 \n\t" + "ext %[temp5], %[temp1], 8, 8 \n\t" + "ext %[temp6], %[temp2], 8, 8 \n\t" + "ext %[temp7], %[temp3], 8, 8 \n\t" + "addiu %[src], %[src], 16 \n\t" + "addiu %[dst], %[dst], 16 \n\t" + "replv.ph %[temp4], %[temp4] \n\t" + "replv.ph %[temp5], %[temp5] \n\t" + "replv.ph %[temp6], %[temp6] \n\t" + "replv.ph %[temp7], %[temp7] \n\t" + "addu.qb %[temp0], %[temp0], %[temp4] \n\t" + "addu.qb %[temp1], %[temp1], %[temp5] \n\t" + "addu.qb %[temp2], %[temp2], %[temp6] \n\t" + "addu.qb %[temp3], %[temp3], %[temp7] \n\t" + "sw %[temp0], -16(%[dst]) \n\t" + "sw %[temp1], -12(%[dst]) \n\t" + "sw %[temp2], -8(%[dst]) \n\t" + "bne %[src], %[p_loop1_end], 0b \n\t" + " sw %[temp3], -4(%[dst]) \n\t" + "3: \n\t" + "beq %[src], %[p_loop2_end], 2f \n\t" + " nop \n\t" + "1: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "addiu %[src], %[src], 4 \n\t" + "addiu %[dst], %[dst], 4 \n\t" + "ext %[temp4], %[temp0], 8, 8 \n\t" + "replv.ph %[temp4], %[temp4] \n\t" + "addu.qb %[temp0], %[temp0], %[temp4] \n\t" + "bne %[src], %[p_loop2_end], 1b \n\t" + " sw %[temp0], -4(%[dst]) \n\t" + "2: \n\t" + ".set pop \n\t" + : [dst]"+&r"(dst), [src]"+&r"(src), [temp0]"=&r"(temp0), + [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), + [temp7]"=&r"(temp7) + : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) + : "memory" + ); +} + +static void TransformColorInverse_MIPSdspR2(const VP8LMultipliers* const m, + const uint32_t* src, int num_pixels, + uint32_t* dst) { + int temp0, temp1, temp2, temp3, temp4, temp5; + uint32_t argb, argb1, new_red; + const uint32_t G_to_R = m->green_to_red_; + const uint32_t G_to_B = m->green_to_blue_; + const uint32_t R_to_B = m->red_to_blue_; + const uint32_t* const p_loop_end = src + (num_pixels & ~1); + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[src], %[p_loop_end], 1f \n\t" + " nop \n\t" + "replv.ph %[temp0], %[G_to_R] \n\t" + "replv.ph %[temp1], %[G_to_B] \n\t" + "replv.ph %[temp2], %[R_to_B] \n\t" + "shll.ph %[temp0], %[temp0], 8 \n\t" + "shll.ph %[temp1], %[temp1], 8 \n\t" + "shll.ph %[temp2], %[temp2], 8 \n\t" + "shra.ph %[temp0], %[temp0], 8 \n\t" + "shra.ph %[temp1], %[temp1], 8 \n\t" + "shra.ph %[temp2], %[temp2], 8 \n\t" + "0: \n\t" + "lw %[argb], 0(%[src]) \n\t" + "lw %[argb1], 4(%[src]) \n\t" + "sw %[argb], 0(%[dst]) \n\t" + "sw %[argb1], 4(%[dst]) \n\t" + "addiu %[src], %[src], 8 \n\t" + "addiu %[dst], %[dst], 8 \n\t" + "precrq.qb.ph %[temp3], %[argb], %[argb1] \n\t" + "preceu.ph.qbra %[temp3], %[temp3] \n\t" + "shll.ph %[temp3], %[temp3], 8 \n\t" + "shra.ph %[temp3], %[temp3], 8 \n\t" + "mul.ph %[temp5], %[temp3], %[temp0] \n\t" + "mul.ph %[temp3], %[temp3], %[temp1] \n\t" + "precrq.ph.w %[new_red], %[argb], %[argb1] \n\t" + "ins %[argb1], %[argb], 16, 16 \n\t" + "shra.ph %[temp5], %[temp5], 5 \n\t" + "shra.ph %[temp3], %[temp3], 5 \n\t" + "addu.ph %[new_red], %[new_red], %[temp5] \n\t" + "addu.ph %[argb1], %[argb1], %[temp3] \n\t" + "preceu.ph.qbra %[temp5], %[new_red] \n\t" + "shll.ph %[temp4], %[temp5], 8 \n\t" + "shra.ph %[temp4], %[temp4], 8 \n\t" + "mul.ph %[temp4], %[temp4], %[temp2] \n\t" + "sb %[temp5], -2(%[dst]) \n\t" + "sra %[temp5], %[temp5], 16 \n\t" + "shra.ph %[temp4], %[temp4], 5 \n\t" + "addu.ph %[argb1], %[argb1], %[temp4] \n\t" + "preceu.ph.qbra %[temp3], %[argb1] \n\t" + "sb %[temp5], -6(%[dst]) \n\t" + "sb %[temp3], -4(%[dst]) \n\t" + "sra %[temp3], %[temp3], 16 \n\t" + "bne %[src], %[p_loop_end], 0b \n\t" + " sb %[temp3], -8(%[dst]) \n\t" + "1: \n\t" + ".set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [new_red]"=&r"(new_red), [argb]"=&r"(argb), + [argb1]"=&r"(argb1), [dst]"+&r"(dst), [src]"+&r"(src) + : [G_to_R]"r"(G_to_R), [R_to_B]"r"(R_to_B), + [G_to_B]"r"(G_to_B), [p_loop_end]"r"(p_loop_end) + : "memory", "hi", "lo" + ); + + // Fall-back to C-version for left-overs. + if (num_pixels & 1) VP8LTransformColorInverse_C(m, src, 1, dst); +} + +static void ConvertBGRAToRGB_MIPSdspR2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + int temp0, temp1, temp2, temp3; + const uint32_t* const p_loop1_end = src + (num_pixels & ~3); + const uint32_t* const p_loop2_end = src + num_pixels; + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[src], %[p_loop1_end], 3f \n\t" + " nop \n\t" + "0: \n\t" + "lw %[temp3], 12(%[src]) \n\t" + "lw %[temp2], 8(%[src]) \n\t" + "lw %[temp1], 4(%[src]) \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "ins %[temp3], %[temp2], 24, 8 \n\t" + "sll %[temp2], %[temp2], 8 \n\t" + "rotr %[temp3], %[temp3], 16 \n\t" + "ins %[temp2], %[temp1], 0, 16 \n\t" + "sll %[temp1], %[temp1], 8 \n\t" + "wsbh %[temp3], %[temp3] \n\t" + "balign %[temp0], %[temp1], 1 \n\t" + "wsbh %[temp2], %[temp2] \n\t" + "wsbh %[temp0], %[temp0] \n\t" + "usw %[temp3], 8(%[dst]) \n\t" + "rotr %[temp0], %[temp0], 16 \n\t" + "usw %[temp2], 4(%[dst]) \n\t" + "addiu %[src], %[src], 16 \n\t" + "usw %[temp0], 0(%[dst]) \n\t" + "bne %[src], %[p_loop1_end], 0b \n\t" + " addiu %[dst], %[dst], 12 \n\t" + "3: \n\t" + "beq %[src], %[p_loop2_end], 2f \n\t" + " nop \n\t" + "1: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "addiu %[src], %[src], 4 \n\t" + "wsbh %[temp1], %[temp0] \n\t" + "addiu %[dst], %[dst], 3 \n\t" + "ush %[temp1], -2(%[dst]) \n\t" + "sra %[temp0], %[temp0], 16 \n\t" + "bne %[src], %[p_loop2_end], 1b \n\t" + " sb %[temp0], -3(%[dst]) \n\t" + "2: \n\t" + ".set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src) + : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) + : "memory" + ); +} + +static void ConvertBGRAToRGBA_MIPSdspR2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + int temp0, temp1, temp2, temp3; + const uint32_t* const p_loop1_end = src + (num_pixels & ~3); + const uint32_t* const p_loop2_end = src + num_pixels; + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[src], %[p_loop1_end], 3f \n\t" + " nop \n\t" + "0: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "lw %[temp1], 4(%[src]) \n\t" + "lw %[temp2], 8(%[src]) \n\t" + "lw %[temp3], 12(%[src]) \n\t" + "wsbh %[temp0], %[temp0] \n\t" + "wsbh %[temp1], %[temp1] \n\t" + "wsbh %[temp2], %[temp2] \n\t" + "wsbh %[temp3], %[temp3] \n\t" + "addiu %[src], %[src], 16 \n\t" + "balign %[temp0], %[temp0], 1 \n\t" + "balign %[temp1], %[temp1], 1 \n\t" + "balign %[temp2], %[temp2], 1 \n\t" + "balign %[temp3], %[temp3], 1 \n\t" + "usw %[temp0], 0(%[dst]) \n\t" + "usw %[temp1], 4(%[dst]) \n\t" + "usw %[temp2], 8(%[dst]) \n\t" + "usw %[temp3], 12(%[dst]) \n\t" + "bne %[src], %[p_loop1_end], 0b \n\t" + " addiu %[dst], %[dst], 16 \n\t" + "3: \n\t" + "beq %[src], %[p_loop2_end], 2f \n\t" + " nop \n\t" + "1: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "wsbh %[temp0], %[temp0] \n\t" + "addiu %[src], %[src], 4 \n\t" + "balign %[temp0], %[temp0], 1 \n\t" + "usw %[temp0], 0(%[dst]) \n\t" + "bne %[src], %[p_loop2_end], 1b \n\t" + " addiu %[dst], %[dst], 4 \n\t" + "2: \n\t" + ".set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src) + : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) + : "memory" + ); +} + +static void ConvertBGRAToRGBA4444_MIPSdspR2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + int temp0, temp1, temp2, temp3, temp4, temp5; + const uint32_t* const p_loop1_end = src + (num_pixels & ~3); + const uint32_t* const p_loop2_end = src + num_pixels; + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[src], %[p_loop1_end], 3f \n\t" + " nop \n\t" + "0: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "lw %[temp1], 4(%[src]) \n\t" + "lw %[temp2], 8(%[src]) \n\t" + "lw %[temp3], 12(%[src]) \n\t" + "ext %[temp4], %[temp0], 28, 4 \n\t" + "ext %[temp5], %[temp0], 12, 4 \n\t" + "ins %[temp0], %[temp4], 0, 4 \n\t" + "ext %[temp4], %[temp1], 28, 4 \n\t" + "ins %[temp0], %[temp5], 16, 4 \n\t" + "ext %[temp5], %[temp1], 12, 4 \n\t" + "ins %[temp1], %[temp4], 0, 4 \n\t" + "ext %[temp4], %[temp2], 28, 4 \n\t" + "ins %[temp1], %[temp5], 16, 4 \n\t" + "ext %[temp5], %[temp2], 12, 4 \n\t" + "ins %[temp2], %[temp4], 0, 4 \n\t" + "ext %[temp4], %[temp3], 28, 4 \n\t" + "ins %[temp2], %[temp5], 16, 4 \n\t" + "ext %[temp5], %[temp3], 12, 4 \n\t" + "ins %[temp3], %[temp4], 0, 4 \n\t" + "precr.qb.ph %[temp1], %[temp1], %[temp0] \n\t" + "ins %[temp3], %[temp5], 16, 4 \n\t" + "addiu %[src], %[src], 16 \n\t" + "precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t" +#if (WEBP_SWAP_16BIT_CSP == 1) + "usw %[temp1], 0(%[dst]) \n\t" + "usw %[temp3], 4(%[dst]) \n\t" +#else + "wsbh %[temp1], %[temp1] \n\t" + "wsbh %[temp3], %[temp3] \n\t" + "usw %[temp1], 0(%[dst]) \n\t" + "usw %[temp3], 4(%[dst]) \n\t" +#endif + "bne %[src], %[p_loop1_end], 0b \n\t" + " addiu %[dst], %[dst], 8 \n\t" + "3: \n\t" + "beq %[src], %[p_loop2_end], 2f \n\t" + " nop \n\t" + "1: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "ext %[temp4], %[temp0], 28, 4 \n\t" + "ext %[temp5], %[temp0], 12, 4 \n\t" + "ins %[temp0], %[temp4], 0, 4 \n\t" + "ins %[temp0], %[temp5], 16, 4 \n\t" + "addiu %[src], %[src], 4 \n\t" + "precr.qb.ph %[temp0], %[temp0], %[temp0] \n\t" +#if (WEBP_SWAP_16BIT_CSP == 1) + "ush %[temp0], 0(%[dst]) \n\t" +#else + "wsbh %[temp0], %[temp0] \n\t" + "ush %[temp0], 0(%[dst]) \n\t" +#endif + "bne %[src], %[p_loop2_end], 1b \n\t" + " addiu %[dst], %[dst], 2 \n\t" + "2: \n\t" + ".set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [dst]"+&r"(dst), [src]"+&r"(src) + : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) + : "memory" + ); +} + +static void ConvertBGRAToRGB565_MIPSdspR2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + int temp0, temp1, temp2, temp3, temp4, temp5; + const uint32_t* const p_loop1_end = src + (num_pixels & ~3); + const uint32_t* const p_loop2_end = src + num_pixels; + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[src], %[p_loop1_end], 3f \n\t" + " nop \n\t" + "0: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "lw %[temp1], 4(%[src]) \n\t" + "lw %[temp2], 8(%[src]) \n\t" + "lw %[temp3], 12(%[src]) \n\t" + "ext %[temp4], %[temp0], 8, 16 \n\t" + "ext %[temp5], %[temp0], 5, 11 \n\t" + "ext %[temp0], %[temp0], 3, 5 \n\t" + "ins %[temp4], %[temp5], 0, 11 \n\t" + "ext %[temp5], %[temp1], 5, 11 \n\t" + "ins %[temp4], %[temp0], 0, 5 \n\t" + "ext %[temp0], %[temp1], 8, 16 \n\t" + "ext %[temp1], %[temp1], 3, 5 \n\t" + "ins %[temp0], %[temp5], 0, 11 \n\t" + "ext %[temp5], %[temp2], 5, 11 \n\t" + "ins %[temp0], %[temp1], 0, 5 \n\t" + "ext %[temp1], %[temp2], 8, 16 \n\t" + "ext %[temp2], %[temp2], 3, 5 \n\t" + "ins %[temp1], %[temp5], 0, 11 \n\t" + "ext %[temp5], %[temp3], 5, 11 \n\t" + "ins %[temp1], %[temp2], 0, 5 \n\t" + "ext %[temp2], %[temp3], 8, 16 \n\t" + "ext %[temp3], %[temp3], 3, 5 \n\t" + "ins %[temp2], %[temp5], 0, 11 \n\t" + "append %[temp0], %[temp4], 16 \n\t" + "ins %[temp2], %[temp3], 0, 5 \n\t" + "addiu %[src], %[src], 16 \n\t" + "append %[temp2], %[temp1], 16 \n\t" +#if (WEBP_SWAP_16BIT_CSP == 1) + "usw %[temp0], 0(%[dst]) \n\t" + "usw %[temp2], 4(%[dst]) \n\t" +#else + "wsbh %[temp0], %[temp0] \n\t" + "wsbh %[temp2], %[temp2] \n\t" + "usw %[temp0], 0(%[dst]) \n\t" + "usw %[temp2], 4(%[dst]) \n\t" +#endif + "bne %[src], %[p_loop1_end], 0b \n\t" + " addiu %[dst], %[dst], 8 \n\t" + "3: \n\t" + "beq %[src], %[p_loop2_end], 2f \n\t" + " nop \n\t" + "1: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "ext %[temp4], %[temp0], 8, 16 \n\t" + "ext %[temp5], %[temp0], 5, 11 \n\t" + "ext %[temp0], %[temp0], 3, 5 \n\t" + "ins %[temp4], %[temp5], 0, 11 \n\t" + "addiu %[src], %[src], 4 \n\t" + "ins %[temp4], %[temp0], 0, 5 \n\t" +#if (WEBP_SWAP_16BIT_CSP == 1) + "ush %[temp4], 0(%[dst]) \n\t" +#else + "wsbh %[temp4], %[temp4] \n\t" + "ush %[temp4], 0(%[dst]) \n\t" +#endif + "bne %[src], %[p_loop2_end], 1b \n\t" + " addiu %[dst], %[dst], 2 \n\t" + "2: \n\t" + ".set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), + [dst]"+&r"(dst), [src]"+&r"(src) + : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) + : "memory" + ); +} + +static void ConvertBGRAToBGR_MIPSdspR2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + int temp0, temp1, temp2, temp3; + const uint32_t* const p_loop1_end = src + (num_pixels & ~3); + const uint32_t* const p_loop2_end = src + num_pixels; + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "beq %[src], %[p_loop1_end], 3f \n\t" + " nop \n\t" + "0: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "lw %[temp1], 4(%[src]) \n\t" + "lw %[temp2], 8(%[src]) \n\t" + "lw %[temp3], 12(%[src]) \n\t" + "ins %[temp0], %[temp1], 24, 8 \n\t" + "sra %[temp1], %[temp1], 8 \n\t" + "ins %[temp1], %[temp2], 16, 16 \n\t" + "sll %[temp2], %[temp2], 8 \n\t" + "balign %[temp3], %[temp2], 1 \n\t" + "addiu %[src], %[src], 16 \n\t" + "usw %[temp0], 0(%[dst]) \n\t" + "usw %[temp1], 4(%[dst]) \n\t" + "usw %[temp3], 8(%[dst]) \n\t" + "bne %[src], %[p_loop1_end], 0b \n\t" + " addiu %[dst], %[dst], 12 \n\t" + "3: \n\t" + "beq %[src], %[p_loop2_end], 2f \n\t" + " nop \n\t" + "1: \n\t" + "lw %[temp0], 0(%[src]) \n\t" + "addiu %[src], %[src], 4 \n\t" + "addiu %[dst], %[dst], 3 \n\t" + "ush %[temp0], -3(%[dst]) \n\t" + "sra %[temp0], %[temp0], 16 \n\t" + "bne %[src], %[p_loop2_end], 1b \n\t" + " sb %[temp0], -1(%[dst]) \n\t" + "2: \n\t" + ".set pop \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src) + : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) + : "memory" + ); +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LDspInitMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitMIPSdspR2(void) { + VP8LMapColor32b = MapARGB_MIPSdspR2; + VP8LMapColor8b = MapAlpha_MIPSdspR2; + + VP8LPredictors[5] = Predictor5_MIPSdspR2; + VP8LPredictors[6] = Predictor6_MIPSdspR2; + VP8LPredictors[7] = Predictor7_MIPSdspR2; + VP8LPredictors[8] = Predictor8_MIPSdspR2; + VP8LPredictors[9] = Predictor9_MIPSdspR2; + VP8LPredictors[10] = Predictor10_MIPSdspR2; + VP8LPredictors[11] = Predictor11_MIPSdspR2; + VP8LPredictors[12] = Predictor12_MIPSdspR2; + VP8LPredictors[13] = Predictor13_MIPSdspR2; + + VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_MIPSdspR2; + VP8LTransformColorInverse = TransformColorInverse_MIPSdspR2; + + VP8LConvertBGRAToRGB = ConvertBGRAToRGB_MIPSdspR2; + VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_MIPSdspR2; + VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444_MIPSdspR2; + VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565_MIPSdspR2; + VP8LConvertBGRAToBGR = ConvertBGRAToBGR_MIPSdspR2; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(VP8LDspInitMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/lossless_msa.c b/libraries/webp/src/dsp/lossless_msa.c new file mode 100644 index 00000000000..9f5472078d9 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_msa.c @@ -0,0 +1,356 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MSA variant of methods for lossless decoder +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "src/dsp/lossless.h" +#include "src/dsp/msa_macro.h" + +//------------------------------------------------------------------------------ +// Colorspace conversion functions + +#define CONVERT16_BGRA_XXX(psrc, pdst, m0, m1, m2) do { \ + v16u8 src0, src1, src2, src3, dst0, dst1, dst2; \ + LD_UB4(psrc, 16, src0, src1, src2, src3); \ + VSHF_B2_UB(src0, src1, src1, src2, m0, m1, dst0, dst1); \ + dst2 = VSHF_UB(src2, src3, m2); \ + ST_UB2(dst0, dst1, pdst, 16); \ + ST_UB(dst2, pdst + 32); \ +} while (0) + +#define CONVERT12_BGRA_XXX(psrc, pdst, m0, m1, m2) do { \ + uint32_t pix_w; \ + v16u8 src0, src1, src2, dst0, dst1, dst2; \ + LD_UB3(psrc, 16, src0, src1, src2); \ + VSHF_B2_UB(src0, src1, src1, src2, m0, m1, dst0, dst1); \ + dst2 = VSHF_UB(src2, src2, m2); \ + ST_UB2(dst0, dst1, pdst, 16); \ + pix_w = __msa_copy_s_w((v4i32)dst2, 0); \ + SW(pix_w, pdst + 32); \ +} while (0) + +#define CONVERT8_BGRA_XXX(psrc, pdst, m0, m1) do { \ + uint64_t pix_d; \ + v16u8 src0, src1, src2 = { 0 }, dst0, dst1; \ + LD_UB2(psrc, 16, src0, src1); \ + VSHF_B2_UB(src0, src1, src1, src2, m0, m1, dst0, dst1); \ + ST_UB(dst0, pdst); \ + pix_d = __msa_copy_s_d((v2i64)dst1, 0); \ + SD(pix_d, pdst + 16); \ +} while (0) + +#define CONVERT4_BGRA_XXX(psrc, pdst, m) do { \ + const v16u8 src0 = LD_UB(psrc); \ + const v16u8 dst0 = VSHF_UB(src0, src0, m); \ + uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); \ + uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 2); \ + SD(pix_d, pdst + 0); \ + SW(pix_w, pdst + 8); \ +} while (0) + +#define CONVERT1_BGRA_BGR(psrc, pdst) do { \ + const int32_t b = (psrc)[0]; \ + const int32_t g = (psrc)[1]; \ + const int32_t r = (psrc)[2]; \ + (pdst)[0] = b; \ + (pdst)[1] = g; \ + (pdst)[2] = r; \ +} while (0) + +#define CONVERT1_BGRA_RGB(psrc, pdst) do { \ + const int32_t b = (psrc)[0]; \ + const int32_t g = (psrc)[1]; \ + const int32_t r = (psrc)[2]; \ + (pdst)[0] = r; \ + (pdst)[1] = g; \ + (pdst)[2] = b; \ +} while (0) + +#define TRANSFORM_COLOR_INVERSE_8(src0, src1, dst0, dst1, \ + c0, c1, mask0, mask1) do { \ + v8i16 g0, g1, t0, t1, t2, t3; \ + v4i32 t4, t5; \ + VSHF_B2_SH(src0, src0, src1, src1, mask0, mask0, g0, g1); \ + DOTP_SB2_SH(g0, g1, c0, c0, t0, t1); \ + SRAI_H2_SH(t0, t1, 5); \ + t0 = __msa_addv_h(t0, (v8i16)src0); \ + t1 = __msa_addv_h(t1, (v8i16)src1); \ + t4 = __msa_srli_w((v4i32)t0, 16); \ + t5 = __msa_srli_w((v4i32)t1, 16); \ + DOTP_SB2_SH(t4, t5, c1, c1, t2, t3); \ + SRAI_H2_SH(t2, t3, 5); \ + ADD2(t0, t2, t1, t3, t0, t1); \ + VSHF_B2_UB(src0, t0, src1, t1, mask1, mask1, dst0, dst1); \ +} while (0) + +#define TRANSFORM_COLOR_INVERSE_4(src, dst, c0, c1, mask0, mask1) do { \ + const v16i8 g0 = VSHF_SB(src, src, mask0); \ + v8i16 t0 = __msa_dotp_s_h(c0, g0); \ + v8i16 t1; \ + v4i32 t2; \ + t0 = SRAI_H(t0, 5); \ + t0 = __msa_addv_h(t0, (v8i16)src); \ + t2 = __msa_srli_w((v4i32)t0, 16); \ + t1 = __msa_dotp_s_h(c1, (v16i8)t2); \ + t1 = SRAI_H(t1, 5); \ + t0 = t0 + t1; \ + dst = VSHF_UB(src, t0, mask1); \ +} while (0) + +static void ConvertBGRAToRGBA_MSA(const uint32_t* src, + int num_pixels, uint8_t* dst) { + int i; + const uint8_t* ptemp_src = (const uint8_t*)src; + uint8_t* ptemp_dst = (uint8_t*)dst; + v16u8 src0, dst0; + const v16u8 mask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1; + LD_UB2(ptemp_src, 16, src0, src1); + VSHF_B2_UB(src0, src0, src1, src1, mask, mask, dst0, dst1); + ST_UB2(dst0, dst1, ptemp_dst, 16); + ptemp_src += 32; + ptemp_dst += 32; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(ptemp_src); + dst0 = VSHF_UB(src0, src0, mask); + ST_UB(dst0, ptemp_dst); + ptemp_src += 16; + ptemp_dst += 16; + num_pixels -= 4; + } + for (i = 0; i < num_pixels; i++) { + const uint8_t b = ptemp_src[2]; + const uint8_t g = ptemp_src[1]; + const uint8_t r = ptemp_src[0]; + const uint8_t a = ptemp_src[3]; + ptemp_dst[0] = b; + ptemp_dst[1] = g; + ptemp_dst[2] = r; + ptemp_dst[3] = a; + ptemp_src += 4; + ptemp_dst += 4; + } + } +} + +static void ConvertBGRAToBGR_MSA(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint8_t* ptemp_src = (const uint8_t*)src; + uint8_t* ptemp_dst = (uint8_t*)dst; + const v16u8 mask0 = { 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, + 16, 17, 18, 20 }; + const v16u8 mask1 = { 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18, 20, + 21, 22, 24, 25 }; + const v16u8 mask2 = { 10, 12, 13, 14, 16, 17, 18, 20, 21, 22, 24, 25, + 26, 28, 29, 30 }; + + while (num_pixels >= 16) { + CONVERT16_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1, mask2); + ptemp_src += 64; + ptemp_dst += 48; + num_pixels -= 16; + } + if (num_pixels > 0) { + if (num_pixels >= 12) { + CONVERT12_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1, mask2); + ptemp_src += 48; + ptemp_dst += 36; + num_pixels -= 12; + } else if (num_pixels >= 8) { + CONVERT8_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1); + ptemp_src += 32; + ptemp_dst += 24; + num_pixels -= 8; + } else if (num_pixels >= 4) { + CONVERT4_BGRA_XXX(ptemp_src, ptemp_dst, mask0); + ptemp_src += 16; + ptemp_dst += 12; + num_pixels -= 4; + } + if (num_pixels == 3) { + CONVERT1_BGRA_BGR(ptemp_src + 0, ptemp_dst + 0); + CONVERT1_BGRA_BGR(ptemp_src + 4, ptemp_dst + 3); + CONVERT1_BGRA_BGR(ptemp_src + 8, ptemp_dst + 6); + } else if (num_pixels == 2) { + CONVERT1_BGRA_BGR(ptemp_src + 0, ptemp_dst + 0); + CONVERT1_BGRA_BGR(ptemp_src + 4, ptemp_dst + 3); + } else if (num_pixels == 1) { + CONVERT1_BGRA_BGR(ptemp_src, ptemp_dst); + } + } +} + +static void ConvertBGRAToRGB_MSA(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint8_t* ptemp_src = (const uint8_t*)src; + uint8_t* ptemp_dst = (uint8_t*)dst; + const v16u8 mask0 = { 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, + 18, 17, 16, 22 }; + const v16u8 mask1 = { 5, 4, 10, 9, 8, 14, 13, 12, 18, 17, 16, 22, + 21, 20, 26, 25 }; + const v16u8 mask2 = { 8, 14, 13, 12, 18, 17, 16, 22, 21, 20, 26, 25, + 24, 30, 29, 28 }; + + while (num_pixels >= 16) { + CONVERT16_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1, mask2); + ptemp_src += 64; + ptemp_dst += 48; + num_pixels -= 16; + } + if (num_pixels) { + if (num_pixels >= 12) { + CONVERT12_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1, mask2); + ptemp_src += 48; + ptemp_dst += 36; + num_pixels -= 12; + } else if (num_pixels >= 8) { + CONVERT8_BGRA_XXX(ptemp_src, ptemp_dst, mask0, mask1); + ptemp_src += 32; + ptemp_dst += 24; + num_pixels -= 8; + } else if (num_pixels >= 4) { + CONVERT4_BGRA_XXX(ptemp_src, ptemp_dst, mask0); + ptemp_src += 16; + ptemp_dst += 12; + num_pixels -= 4; + } + if (num_pixels == 3) { + CONVERT1_BGRA_RGB(ptemp_src + 0, ptemp_dst + 0); + CONVERT1_BGRA_RGB(ptemp_src + 4, ptemp_dst + 3); + CONVERT1_BGRA_RGB(ptemp_src + 8, ptemp_dst + 6); + } else if (num_pixels == 2) { + CONVERT1_BGRA_RGB(ptemp_src + 0, ptemp_dst + 0); + CONVERT1_BGRA_RGB(ptemp_src + 4, ptemp_dst + 3); + } else if (num_pixels == 1) { + CONVERT1_BGRA_RGB(ptemp_src, ptemp_dst); + } + } +} + +static void AddGreenToBlueAndRed_MSA(const uint32_t* const src, int num_pixels, + uint32_t* dst) { + int i; + const uint8_t* in = (const uint8_t*)src; + uint8_t* out = (uint8_t*)dst; + v16u8 src0, dst0, tmp0; + const v16u8 mask = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, + 13, 255, 13, 255 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1, tmp1; + LD_UB2(in, 16, src0, src1); + VSHF_B2_UB(src0, src1, src1, src0, mask, mask, tmp0, tmp1); + ADD2(src0, tmp0, src1, tmp1, dst0, dst1); + ST_UB2(dst0, dst1, out, 16); + in += 32; + out += 32; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(in); + tmp0 = VSHF_UB(src0, src0, mask); + dst0 = src0 + tmp0; + ST_UB(dst0, out); + in += 16; + out += 16; + num_pixels -= 4; + } + for (i = 0; i < num_pixels; i++) { + const uint8_t b = in[0]; + const uint8_t g = in[1]; + const uint8_t r = in[2]; + out[0] = (b + g) & 0xff; + out[1] = g; + out[2] = (r + g) & 0xff; + out[4] = in[4]; + out += 4; + } + } +} + +static void TransformColorInverse_MSA(const VP8LMultipliers* const m, + const uint32_t* src, int num_pixels, + uint32_t* dst) { + v16u8 src0, dst0; + const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue_ | + (m->green_to_red_ << 16)); + const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue_); + const v16u8 mask0 = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, + 13, 255, 13, 255 }; + const v16u8 mask1 = { 16, 1, 18, 3, 20, 5, 22, 7, 24, 9, 26, 11, + 28, 13, 30, 15 }; + + while (num_pixels >= 8) { + v16u8 src1, dst1; + LD_UB2(src, 4, src0, src1); + TRANSFORM_COLOR_INVERSE_8(src0, src1, dst0, dst1, g2br, r2b, mask0, mask1); + ST_UB2(dst0, dst1, dst, 4); + src += 8; + dst += 8; + num_pixels -= 8; + } + if (num_pixels > 0) { + if (num_pixels >= 4) { + src0 = LD_UB(src); + TRANSFORM_COLOR_INVERSE_4(src0, dst0, g2br, r2b, mask0, mask1); + ST_UB(dst0, dst); + src += 4; + dst += 4; + num_pixels -= 4; + } + if (num_pixels > 0) { + src0 = LD_UB(src); + TRANSFORM_COLOR_INVERSE_4(src0, dst0, g2br, r2b, mask0, mask1); + if (num_pixels == 3) { + const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); + const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 2); + SD(pix_d, dst + 0); + SW(pix_w, dst + 2); + } else if (num_pixels == 2) { + const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); + SD(pix_d, dst); + } else { + const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 0); + SW(pix_w, dst); + } + } + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LDspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitMSA(void) { + VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_MSA; + VP8LConvertBGRAToBGR = ConvertBGRAToBGR_MSA; + VP8LConvertBGRAToRGB = ConvertBGRAToRGB_MSA; + + VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_MSA; + VP8LTransformColorInverse = TransformColorInverse_MSA; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(VP8LDspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/libraries/webp/src/dsp/lossless_neon.c b/libraries/webp/src/dsp/lossless_neon.c new file mode 100644 index 00000000000..e9960db38a7 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_neon.c @@ -0,0 +1,645 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// NEON variant of methods for lossless decoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include + +#include "src/dsp/lossless.h" +#include "src/dsp/neon.h" + +//------------------------------------------------------------------------------ +// Colorspace conversion functions + +#if !defined(WORK_AROUND_GCC) +// gcc 4.6.0 had some trouble (NDK-r9) with this code. We only use it for +// gcc-4.8.x at least. +static void ConvertBGRAToRGBA_NEON(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const end = src + (num_pixels & ~15); + for (; src < end; src += 16) { + uint8x16x4_t pixel = vld4q_u8((uint8_t*)src); + // swap B and R. (VSWP d0,d2 has no intrinsics equivalent!) + const uint8x16_t tmp = pixel.val[0]; + pixel.val[0] = pixel.val[2]; + pixel.val[2] = tmp; + vst4q_u8(dst, pixel); + dst += 64; + } + VP8LConvertBGRAToRGBA_C(src, num_pixels & 15, dst); // left-overs +} + +static void ConvertBGRAToBGR_NEON(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const end = src + (num_pixels & ~15); + for (; src < end; src += 16) { + const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src); + const uint8x16x3_t tmp = { { pixel.val[0], pixel.val[1], pixel.val[2] } }; + vst3q_u8(dst, tmp); + dst += 48; + } + VP8LConvertBGRAToBGR_C(src, num_pixels & 15, dst); // left-overs +} + +static void ConvertBGRAToRGB_NEON(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const end = src + (num_pixels & ~15); + for (; src < end; src += 16) { + const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src); + const uint8x16x3_t tmp = { { pixel.val[2], pixel.val[1], pixel.val[0] } }; + vst3q_u8(dst, tmp); + dst += 48; + } + VP8LConvertBGRAToRGB_C(src, num_pixels & 15, dst); // left-overs +} + +#else // WORK_AROUND_GCC + +// gcc-4.6.0 fallback + +static const uint8_t kRGBAShuffle[8] = { 2, 1, 0, 3, 6, 5, 4, 7 }; + +static void ConvertBGRAToRGBA_NEON(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const end = src + (num_pixels & ~1); + const uint8x8_t shuffle = vld1_u8(kRGBAShuffle); + for (; src < end; src += 2) { + const uint8x8_t pixels = vld1_u8((uint8_t*)src); + vst1_u8(dst, vtbl1_u8(pixels, shuffle)); + dst += 8; + } + VP8LConvertBGRAToRGBA_C(src, num_pixels & 1, dst); // left-overs +} + +static const uint8_t kBGRShuffle[3][8] = { + { 0, 1, 2, 4, 5, 6, 8, 9 }, + { 10, 12, 13, 14, 16, 17, 18, 20 }, + { 21, 22, 24, 25, 26, 28, 29, 30 } +}; + +static void ConvertBGRAToBGR_NEON(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const end = src + (num_pixels & ~7); + const uint8x8_t shuffle0 = vld1_u8(kBGRShuffle[0]); + const uint8x8_t shuffle1 = vld1_u8(kBGRShuffle[1]); + const uint8x8_t shuffle2 = vld1_u8(kBGRShuffle[2]); + for (; src < end; src += 8) { + uint8x8x4_t pixels; + INIT_VECTOR4(pixels, + vld1_u8((const uint8_t*)(src + 0)), + vld1_u8((const uint8_t*)(src + 2)), + vld1_u8((const uint8_t*)(src + 4)), + vld1_u8((const uint8_t*)(src + 6))); + vst1_u8(dst + 0, vtbl4_u8(pixels, shuffle0)); + vst1_u8(dst + 8, vtbl4_u8(pixels, shuffle1)); + vst1_u8(dst + 16, vtbl4_u8(pixels, shuffle2)); + dst += 8 * 3; + } + VP8LConvertBGRAToBGR_C(src, num_pixels & 7, dst); // left-overs +} + +static const uint8_t kRGBShuffle[3][8] = { + { 2, 1, 0, 6, 5, 4, 10, 9 }, + { 8, 14, 13, 12, 18, 17, 16, 22 }, + { 21, 20, 26, 25, 24, 30, 29, 28 } +}; + +static void ConvertBGRAToRGB_NEON(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const end = src + (num_pixels & ~7); + const uint8x8_t shuffle0 = vld1_u8(kRGBShuffle[0]); + const uint8x8_t shuffle1 = vld1_u8(kRGBShuffle[1]); + const uint8x8_t shuffle2 = vld1_u8(kRGBShuffle[2]); + for (; src < end; src += 8) { + uint8x8x4_t pixels; + INIT_VECTOR4(pixels, + vld1_u8((const uint8_t*)(src + 0)), + vld1_u8((const uint8_t*)(src + 2)), + vld1_u8((const uint8_t*)(src + 4)), + vld1_u8((const uint8_t*)(src + 6))); + vst1_u8(dst + 0, vtbl4_u8(pixels, shuffle0)); + vst1_u8(dst + 8, vtbl4_u8(pixels, shuffle1)); + vst1_u8(dst + 16, vtbl4_u8(pixels, shuffle2)); + dst += 8 * 3; + } + VP8LConvertBGRAToRGB_C(src, num_pixels & 7, dst); // left-overs +} + +#endif // !WORK_AROUND_GCC + +//------------------------------------------------------------------------------ +// Predictor Transform + +#define LOAD_U32_AS_U8(IN) vreinterpret_u8_u32(vdup_n_u32((IN))) +#define LOAD_U32P_AS_U8(IN) vreinterpret_u8_u32(vld1_u32((IN))) +#define LOADQ_U32_AS_U8(IN) vreinterpretq_u8_u32(vdupq_n_u32((IN))) +#define LOADQ_U32P_AS_U8(IN) vreinterpretq_u8_u32(vld1q_u32((IN))) +#define GET_U8_AS_U32(IN) vget_lane_u32(vreinterpret_u32_u8((IN)), 0) +#define GETQ_U8_AS_U32(IN) vgetq_lane_u32(vreinterpretq_u32_u8((IN)), 0) +#define STOREQ_U8_AS_U32P(OUT, IN) vst1q_u32((OUT), vreinterpretq_u32_u8((IN))) +#define ROTATE32_LEFT(L) vextq_u8((L), (L), 12) // D|C|B|A -> C|B|A|D + +static WEBP_INLINE uint8x8_t Average2_u8_NEON(uint32_t a0, uint32_t a1) { + const uint8x8_t A0 = LOAD_U32_AS_U8(a0); + const uint8x8_t A1 = LOAD_U32_AS_U8(a1); + return vhadd_u8(A0, A1); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractHalf_NEON(uint32_t c0, + uint32_t c1, + uint32_t c2) { + const uint8x8_t avg = Average2_u8_NEON(c0, c1); + // Remove one to c2 when bigger than avg. + const uint8x8_t C2 = LOAD_U32_AS_U8(c2); + const uint8x8_t cmp = vcgt_u8(C2, avg); + const uint8x8_t C2_1 = vadd_u8(C2, cmp); + // Compute half of the difference between avg and c2. + const int8x8_t diff_avg = vreinterpret_s8_u8(vhsub_u8(avg, C2_1)); + // Compute the sum with avg and saturate. + const int16x8_t avg_16 = vreinterpretq_s16_u16(vmovl_u8(avg)); + const uint8x8_t res = vqmovun_s16(vaddw_s8(avg_16, diff_avg)); + const uint32_t output = GET_U8_AS_U32(res); + return output; +} + +static WEBP_INLINE uint32_t Average2_NEON(uint32_t a0, uint32_t a1) { + const uint8x8_t avg_u8x8 = Average2_u8_NEON(a0, a1); + const uint32_t avg = GET_U8_AS_U32(avg_u8x8); + return avg; +} + +static WEBP_INLINE uint32_t Average3_NEON(uint32_t a0, uint32_t a1, + uint32_t a2) { + const uint8x8_t avg0 = Average2_u8_NEON(a0, a2); + const uint8x8_t A1 = LOAD_U32_AS_U8(a1); + const uint32_t avg = GET_U8_AS_U32(vhadd_u8(avg0, A1)); + return avg; +} + +static uint32_t Predictor5_NEON(const uint32_t* const left, + const uint32_t* const top) { + return Average3_NEON(*left, top[0], top[1]); +} +static uint32_t Predictor6_NEON(const uint32_t* const left, + const uint32_t* const top) { + return Average2_NEON(*left, top[-1]); +} +static uint32_t Predictor7_NEON(const uint32_t* const left, + const uint32_t* const top) { + return Average2_NEON(*left, top[0]); +} +static uint32_t Predictor13_NEON(const uint32_t* const left, + const uint32_t* const top) { + return ClampedAddSubtractHalf_NEON(*left, top[0], top[-1]); +} + +// Batch versions of those functions. + +// Predictor0: ARGB_BLACK. +static void PredictorAdd0_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const uint8x16_t black = vreinterpretq_u8_u32(vdupq_n_u32(ARGB_BLACK)); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t res = vaddq_u8(src, black); + STOREQ_U8_AS_U32P(&out[i], res); + } + VP8LPredictorsAdd_C[0](in + i, upper + i, num_pixels - i, out + i); +} + +// Predictor1: left. +static void PredictorAdd1_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const uint8x16_t zero = LOADQ_U32_AS_U8(0); + for (i = 0; i + 4 <= num_pixels; i += 4) { + // a | b | c | d + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + // 0 | a | b | c + const uint8x16_t shift0 = vextq_u8(zero, src, 12); + // a | a + b | b + c | c + d + const uint8x16_t sum0 = vaddq_u8(src, shift0); + // 0 | 0 | a | a + b + const uint8x16_t shift1 = vextq_u8(zero, sum0, 8); + // a | a + b | a + b + c | a + b + c + d + const uint8x16_t sum1 = vaddq_u8(sum0, shift1); + const uint8x16_t prev = LOADQ_U32_AS_U8(out[i - 1]); + const uint8x16_t res = vaddq_u8(sum1, prev); + STOREQ_U8_AS_U32P(&out[i], res); + } + VP8LPredictorsAdd_C[1](in + i, upper + i, num_pixels - i, out + i); +} + +// Macro that adds 32-bit integers from IN using mod 256 arithmetic +// per 8 bit channel. +#define GENERATE_PREDICTOR_1(X, IN) \ +static void PredictorAdd##X##_NEON(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); \ + const uint8x16_t other = LOADQ_U32P_AS_U8(&(IN)); \ + const uint8x16_t res = vaddq_u8(src, other); \ + STOREQ_U8_AS_U32P(&out[i], res); \ + } \ + VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ +} +// Predictor2: Top. +GENERATE_PREDICTOR_1(2, upper[i]) +// Predictor3: Top-right. +GENERATE_PREDICTOR_1(3, upper[i + 1]) +// Predictor4: Top-left. +GENERATE_PREDICTOR_1(4, upper[i - 1]) +#undef GENERATE_PREDICTOR_1 + +// Predictor5: average(average(left, TR), T) +#define DO_PRED5(LANE) do { \ + const uint8x16_t avgLTR = vhaddq_u8(L, TR); \ + const uint8x16_t avg = vhaddq_u8(avgLTR, T); \ + const uint8x16_t res = vaddq_u8(avg, src); \ + vst1q_lane_u32(&out[i + (LANE)], vreinterpretq_u32_u8(res), (LANE)); \ + L = ROTATE32_LEFT(res); \ +} while (0) + +static void PredictorAdd5_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i + 0]); + const uint8x16_t TR = LOADQ_U32P_AS_U8(&upper[i + 1]); + DO_PRED5(0); + DO_PRED5(1); + DO_PRED5(2); + DO_PRED5(3); + } + VP8LPredictorsAdd_C[5](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED5 + +#define DO_PRED67(LANE) do { \ + const uint8x16_t avg = vhaddq_u8(L, top); \ + const uint8x16_t res = vaddq_u8(avg, src); \ + vst1q_lane_u32(&out[i + (LANE)], vreinterpretq_u32_u8(res), (LANE)); \ + L = ROTATE32_LEFT(res); \ +} while (0) + +// Predictor6: average(left, TL) +static void PredictorAdd6_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t top = LOADQ_U32P_AS_U8(&upper[i - 1]); + DO_PRED67(0); + DO_PRED67(1); + DO_PRED67(2); + DO_PRED67(3); + } + VP8LPredictorsAdd_C[6](in + i, upper + i, num_pixels - i, out + i); +} + +// Predictor7: average(left, T) +static void PredictorAdd7_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t top = LOADQ_U32P_AS_U8(&upper[i]); + DO_PRED67(0); + DO_PRED67(1); + DO_PRED67(2); + DO_PRED67(3); + } + VP8LPredictorsAdd_C[7](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED67 + +#define GENERATE_PREDICTOR_2(X, IN) \ +static void PredictorAdd##X##_NEON(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); \ + const uint8x16_t Tother = LOADQ_U32P_AS_U8(&(IN)); \ + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); \ + const uint8x16_t avg = vhaddq_u8(T, Tother); \ + const uint8x16_t res = vaddq_u8(avg, src); \ + STOREQ_U8_AS_U32P(&out[i], res); \ + } \ + VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ +} +// Predictor8: average TL T. +GENERATE_PREDICTOR_2(8, upper[i - 1]) +// Predictor9: average T TR. +GENERATE_PREDICTOR_2(9, upper[i + 1]) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: average of (average of (L,TL), average of (T, TR)). +#define DO_PRED10(LANE) do { \ + const uint8x16_t avgLTL = vhaddq_u8(L, TL); \ + const uint8x16_t avg = vhaddq_u8(avgTTR, avgLTL); \ + const uint8x16_t res = vaddq_u8(avg, src); \ + vst1q_lane_u32(&out[i + (LANE)], vreinterpretq_u32_u8(res), (LANE)); \ + L = ROTATE32_LEFT(res); \ +} while (0) + +static void PredictorAdd10_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t TL = LOADQ_U32P_AS_U8(&upper[i - 1]); + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); + const uint8x16_t TR = LOADQ_U32P_AS_U8(&upper[i + 1]); + const uint8x16_t avgTTR = vhaddq_u8(T, TR); + DO_PRED10(0); + DO_PRED10(1); + DO_PRED10(2); + DO_PRED10(3); + } + VP8LPredictorsAdd_C[10](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED10 + +// Predictor11: select. +#define DO_PRED11(LANE) do { \ + const uint8x16_t sumLin = vaddq_u8(L, src); /* in + L */ \ + const uint8x16_t pLTL = vabdq_u8(L, TL); /* |L - TL| */ \ + const uint16x8_t sum_LTL = vpaddlq_u8(pLTL); \ + const uint32x4_t pa = vpaddlq_u16(sum_LTL); \ + const uint32x4_t mask = vcleq_u32(pa, pb); \ + const uint8x16_t res = vbslq_u8(vreinterpretq_u8_u32(mask), sumTin, sumLin); \ + vst1q_lane_u32(&out[i + (LANE)], vreinterpretq_u32_u8(res), (LANE)); \ + L = ROTATE32_LEFT(res); \ +} while (0) + +static void PredictorAdd11_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); + const uint8x16_t TL = LOADQ_U32P_AS_U8(&upper[i - 1]); + const uint8x16_t pTTL = vabdq_u8(T, TL); // |T - TL| + const uint16x8_t sum_TTL = vpaddlq_u8(pTTL); + const uint32x4_t pb = vpaddlq_u16(sum_TTL); + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t sumTin = vaddq_u8(T, src); // in + T + DO_PRED11(0); + DO_PRED11(1); + DO_PRED11(2); + DO_PRED11(3); + } + VP8LPredictorsAdd_C[11](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED11 + +// Predictor12: ClampedAddSubtractFull. +#define DO_PRED12(DIFF, LANE) do { \ + const uint8x8_t pred = \ + vqmovun_s16(vaddq_s16(vreinterpretq_s16_u16(L), (DIFF))); \ + const uint8x8_t res = \ + vadd_u8(pred, (LANE <= 1) ? vget_low_u8(src) : vget_high_u8(src)); \ + const uint16x8_t res16 = vmovl_u8(res); \ + vst1_lane_u32(&out[i + (LANE)], vreinterpret_u32_u8(res), (LANE) & 1); \ + /* rotate in the left predictor for next iteration */ \ + L = vextq_u16(res16, res16, 4); \ +} while (0) + +static void PredictorAdd12_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint16x8_t L = vmovl_u8(LOAD_U32_AS_U8(out[-1])); + for (i = 0; i + 4 <= num_pixels; i += 4) { + // load four pixels of source + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + // precompute the difference T - TL once for all, stored as s16 + const uint8x16_t TL = LOADQ_U32P_AS_U8(&upper[i - 1]); + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); + const int16x8_t diff_lo = + vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(T), vget_low_u8(TL))); + const int16x8_t diff_hi = + vreinterpretq_s16_u16(vsubl_u8(vget_high_u8(T), vget_high_u8(TL))); + // loop over the four reconstructed pixels + DO_PRED12(diff_lo, 0); + DO_PRED12(diff_lo, 1); + DO_PRED12(diff_hi, 2); + DO_PRED12(diff_hi, 3); + } + VP8LPredictorsAdd_C[12](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED12 + +// Predictor13: ClampedAddSubtractHalf +#define DO_PRED13(LANE, LOW_OR_HI) do { \ + const uint8x16_t avg = vhaddq_u8(L, T); \ + const uint8x16_t cmp = vcgtq_u8(TL, avg); \ + const uint8x16_t TL_1 = vaddq_u8(TL, cmp); \ + /* Compute half of the difference between avg and TL'. */ \ + const int8x8_t diff_avg = \ + vreinterpret_s8_u8(LOW_OR_HI(vhsubq_u8(avg, TL_1))); \ + /* Compute the sum with avg and saturate. */ \ + const int16x8_t avg_16 = vreinterpretq_s16_u16(vmovl_u8(LOW_OR_HI(avg))); \ + const uint8x8_t delta = vqmovun_s16(vaddw_s8(avg_16, diff_avg)); \ + const uint8x8_t res = vadd_u8(LOW_OR_HI(src), delta); \ + const uint8x16_t res2 = vcombine_u8(res, res); \ + vst1_lane_u32(&out[i + (LANE)], vreinterpret_u32_u8(res), (LANE) & 1); \ + L = ROTATE32_LEFT(res2); \ +} while (0) + +static void PredictorAdd13_NEON(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); + const uint8x16_t T = LOADQ_U32P_AS_U8(&upper[i]); + const uint8x16_t TL = LOADQ_U32P_AS_U8(&upper[i - 1]); + DO_PRED13(0, vget_low_u8); + DO_PRED13(1, vget_low_u8); + DO_PRED13(2, vget_high_u8); + DO_PRED13(3, vget_high_u8); + } + VP8LPredictorsAdd_C[13](in + i, upper + i, num_pixels - i, out + i); +} +#undef DO_PRED13 + +#undef LOAD_U32_AS_U8 +#undef LOAD_U32P_AS_U8 +#undef LOADQ_U32_AS_U8 +#undef LOADQ_U32P_AS_U8 +#undef GET_U8_AS_U32 +#undef GETQ_U8_AS_U32 +#undef STOREQ_U8_AS_U32P +#undef ROTATE32_LEFT + +//------------------------------------------------------------------------------ +// Subtract-Green Transform + +// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use +// non-standard versions there. +#if defined(__APPLE__) && WEBP_AARCH64 && \ + defined(__apple_build_version__) && (__apple_build_version__< 6020037) +#define USE_VTBLQ +#endif + +#ifdef USE_VTBLQ +// 255 = byte will be zeroed +static const uint8_t kGreenShuffle[16] = { + 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255 +}; + +static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb, + const uint8x16_t shuffle) { + return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)), + vtbl1q_u8(argb, vget_high_u8(shuffle))); +} +#else // !USE_VTBLQ +// 255 = byte will be zeroed +static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 }; + +static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb, + const uint8x8_t shuffle) { + return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle), + vtbl1_u8(vget_high_u8(argb), shuffle)); +} +#endif // USE_VTBLQ + +static void AddGreenToBlueAndRed_NEON(const uint32_t* src, int num_pixels, + uint32_t* dst) { + const uint32_t* const end = src + (num_pixels & ~3); +#ifdef USE_VTBLQ + const uint8x16_t shuffle = vld1q_u8(kGreenShuffle); +#else + const uint8x8_t shuffle = vld1_u8(kGreenShuffle); +#endif + for (; src < end; src += 4, dst += 4) { + const uint8x16_t argb = vld1q_u8((const uint8_t*)src); + const uint8x16_t greens = DoGreenShuffle_NEON(argb, shuffle); + vst1q_u8((uint8_t*)dst, vaddq_u8(argb, greens)); + } + // fallthrough and finish off with plain-C + VP8LAddGreenToBlueAndRed_C(src, num_pixels & 3, dst); +} + +//------------------------------------------------------------------------------ +// Color Transform + +static void TransformColorInverse_NEON(const VP8LMultipliers* const m, + const uint32_t* const src, + int num_pixels, uint32_t* dst) { +// sign-extended multiplying constants, pre-shifted by 6. +#define CST(X) (((int16_t)(m->X << 8)) >> 6) + const int16_t rb[8] = { + CST(green_to_blue_), CST(green_to_red_), + CST(green_to_blue_), CST(green_to_red_), + CST(green_to_blue_), CST(green_to_red_), + CST(green_to_blue_), CST(green_to_red_) + }; + const int16x8_t mults_rb = vld1q_s16(rb); + const int16_t b2[8] = { + 0, CST(red_to_blue_), 0, CST(red_to_blue_), + 0, CST(red_to_blue_), 0, CST(red_to_blue_), + }; + const int16x8_t mults_b2 = vld1q_s16(b2); +#undef CST +#ifdef USE_VTBLQ + static const uint8_t kg0g0[16] = { + 255, 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13 + }; + const uint8x16_t shuffle = vld1q_u8(kg0g0); +#else + static const uint8_t k0g0g[8] = { 255, 1, 255, 1, 255, 5, 255, 5 }; + const uint8x8_t shuffle = vld1_u8(k0g0g); +#endif + const uint32x4_t mask_ag = vdupq_n_u32(0xff00ff00u); + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const uint8x16_t in = vld1q_u8((const uint8_t*)(src + i)); + const uint32x4_t a0g0 = vandq_u32(vreinterpretq_u32_u8(in), mask_ag); + // 0 g 0 g + const uint8x16_t greens = DoGreenShuffle_NEON(in, shuffle); + // x dr x db1 + const int16x8_t A = vqdmulhq_s16(vreinterpretq_s16_u8(greens), mults_rb); + // x r' x b' + const int8x16_t B = vaddq_s8(vreinterpretq_s8_u8(in), + vreinterpretq_s8_s16(A)); + // r' 0 b' 0 + const int16x8_t C = vshlq_n_s16(vreinterpretq_s16_s8(B), 8); + // x db2 0 0 + const int16x8_t D = vqdmulhq_s16(C, mults_b2); + // 0 x db2 0 + const uint32x4_t E = vshrq_n_u32(vreinterpretq_u32_s16(D), 8); + // r' x b'' 0 + const int8x16_t F = vaddq_s8(vreinterpretq_s8_u32(E), + vreinterpretq_s8_s16(C)); + // 0 r' 0 b'' + const uint16x8_t G = vshrq_n_u16(vreinterpretq_u16_s8(F), 8); + const uint32x4_t out = vorrq_u32(vreinterpretq_u32_u16(G), a0g0); + vst1q_u32(dst + i, out); + } + // Fall-back to C-version for left-overs. + VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i); +} + +#undef USE_VTBLQ + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LDspInitNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitNEON(void) { + VP8LPredictors[5] = Predictor5_NEON; + VP8LPredictors[6] = Predictor6_NEON; + VP8LPredictors[7] = Predictor7_NEON; + VP8LPredictors[13] = Predictor13_NEON; + + VP8LPredictorsAdd[0] = PredictorAdd0_NEON; + VP8LPredictorsAdd[1] = PredictorAdd1_NEON; + VP8LPredictorsAdd[2] = PredictorAdd2_NEON; + VP8LPredictorsAdd[3] = PredictorAdd3_NEON; + VP8LPredictorsAdd[4] = PredictorAdd4_NEON; + VP8LPredictorsAdd[5] = PredictorAdd5_NEON; + VP8LPredictorsAdd[6] = PredictorAdd6_NEON; + VP8LPredictorsAdd[7] = PredictorAdd7_NEON; + VP8LPredictorsAdd[8] = PredictorAdd8_NEON; + VP8LPredictorsAdd[9] = PredictorAdd9_NEON; + VP8LPredictorsAdd[10] = PredictorAdd10_NEON; + VP8LPredictorsAdd[11] = PredictorAdd11_NEON; + VP8LPredictorsAdd[12] = PredictorAdd12_NEON; + VP8LPredictorsAdd[13] = PredictorAdd13_NEON; + + VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_NEON; + VP8LConvertBGRAToBGR = ConvertBGRAToBGR_NEON; + VP8LConvertBGRAToRGB = ConvertBGRAToRGB_NEON; + + VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_NEON; + VP8LTransformColorInverse = TransformColorInverse_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(VP8LDspInitNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/lossless_sse2.c b/libraries/webp/src/dsp/lossless_sse2.c new file mode 100644 index 00000000000..4b6a532c239 --- /dev/null +++ b/libraries/webp/src/dsp/lossless_sse2.c @@ -0,0 +1,712 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 variant of methods for lossless decoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) + +#include "src/dsp/common_sse2.h" +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" +#include + +//------------------------------------------------------------------------------ +// Predictor Transform + +static WEBP_INLINE uint32_t ClampedAddSubtractFull_SSE2(uint32_t c0, + uint32_t c1, + uint32_t c2) { + const __m128i zero = _mm_setzero_si128(); + const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c0), zero); + const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c1), zero); + const __m128i C2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c2), zero); + const __m128i V1 = _mm_add_epi16(C0, C1); + const __m128i V2 = _mm_sub_epi16(V1, C2); + const __m128i b = _mm_packus_epi16(V2, V2); + return (uint32_t)_mm_cvtsi128_si32(b); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractHalf_SSE2(uint32_t c0, + uint32_t c1, + uint32_t c2) { + const __m128i zero = _mm_setzero_si128(); + const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c0), zero); + const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c1), zero); + const __m128i B0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c2), zero); + const __m128i avg = _mm_add_epi16(C1, C0); + const __m128i A0 = _mm_srli_epi16(avg, 1); + const __m128i A1 = _mm_sub_epi16(A0, B0); + const __m128i BgtA = _mm_cmpgt_epi16(B0, A0); + const __m128i A2 = _mm_sub_epi16(A1, BgtA); + const __m128i A3 = _mm_srai_epi16(A2, 1); + const __m128i A4 = _mm_add_epi16(A0, A3); + const __m128i A5 = _mm_packus_epi16(A4, A4); + return (uint32_t)_mm_cvtsi128_si32(A5); +} + +static WEBP_INLINE uint32_t Select_SSE2(uint32_t a, uint32_t b, uint32_t c) { + int pa_minus_pb; + const __m128i zero = _mm_setzero_si128(); + const __m128i A0 = _mm_cvtsi32_si128((int)a); + const __m128i B0 = _mm_cvtsi32_si128((int)b); + const __m128i C0 = _mm_cvtsi32_si128((int)c); + const __m128i AC0 = _mm_subs_epu8(A0, C0); + const __m128i CA0 = _mm_subs_epu8(C0, A0); + const __m128i BC0 = _mm_subs_epu8(B0, C0); + const __m128i CB0 = _mm_subs_epu8(C0, B0); + const __m128i AC = _mm_or_si128(AC0, CA0); + const __m128i BC = _mm_or_si128(BC0, CB0); + const __m128i pa = _mm_unpacklo_epi8(AC, zero); // |a - c| + const __m128i pb = _mm_unpacklo_epi8(BC, zero); // |b - c| + const __m128i diff = _mm_sub_epi16(pb, pa); + { + int16_t out[8]; + _mm_storeu_si128((__m128i*)out, diff); + pa_minus_pb = out[0] + out[1] + out[2] + out[3]; + } + return (pa_minus_pb <= 0) ? a : b; +} + +static WEBP_INLINE void Average2_m128i(const __m128i* const a0, + const __m128i* const a1, + __m128i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m128i ones = _mm_set1_epi8(1); + const __m128i avg1 = _mm_avg_epu8(*a0, *a1); + const __m128i one = _mm_and_si128(_mm_xor_si128(*a0, *a1), ones); + *avg = _mm_sub_epi8(avg1, one); +} + +static WEBP_INLINE void Average2_uint32_SSE2(const uint32_t a0, + const uint32_t a1, + __m128i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m128i ones = _mm_set1_epi8(1); + const __m128i A0 = _mm_cvtsi32_si128((int)a0); + const __m128i A1 = _mm_cvtsi32_si128((int)a1); + const __m128i avg1 = _mm_avg_epu8(A0, A1); + const __m128i one = _mm_and_si128(_mm_xor_si128(A0, A1), ones); + *avg = _mm_sub_epi8(avg1, one); +} + +static WEBP_INLINE __m128i Average2_uint32_16_SSE2(uint32_t a0, uint32_t a1) { + const __m128i zero = _mm_setzero_si128(); + const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)a0), zero); + const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)a1), zero); + const __m128i sum = _mm_add_epi16(A1, A0); + return _mm_srli_epi16(sum, 1); +} + +static WEBP_INLINE uint32_t Average2_SSE2(uint32_t a0, uint32_t a1) { + __m128i output; + Average2_uint32_SSE2(a0, a1, &output); + return (uint32_t)_mm_cvtsi128_si32(output); +} + +static WEBP_INLINE uint32_t Average3_SSE2(uint32_t a0, uint32_t a1, + uint32_t a2) { + const __m128i zero = _mm_setzero_si128(); + const __m128i avg1 = Average2_uint32_16_SSE2(a0, a2); + const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)a1), zero); + const __m128i sum = _mm_add_epi16(avg1, A1); + const __m128i avg2 = _mm_srli_epi16(sum, 1); + const __m128i A2 = _mm_packus_epi16(avg2, avg2); + return (uint32_t)_mm_cvtsi128_si32(A2); +} + +static WEBP_INLINE uint32_t Average4_SSE2(uint32_t a0, uint32_t a1, + uint32_t a2, uint32_t a3) { + const __m128i avg1 = Average2_uint32_16_SSE2(a0, a1); + const __m128i avg2 = Average2_uint32_16_SSE2(a2, a3); + const __m128i sum = _mm_add_epi16(avg2, avg1); + const __m128i avg3 = _mm_srli_epi16(sum, 1); + const __m128i A0 = _mm_packus_epi16(avg3, avg3); + return (uint32_t)_mm_cvtsi128_si32(A0); +} + +static uint32_t Predictor5_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average3_SSE2(*left, top[0], top[1]); + return pred; +} +static uint32_t Predictor6_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average2_SSE2(*left, top[-1]); + return pred; +} +static uint32_t Predictor7_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average2_SSE2(*left, top[0]); + return pred; +} +static uint32_t Predictor8_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average2_SSE2(top[-1], top[0]); + (void)left; + return pred; +} +static uint32_t Predictor9_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average2_SSE2(top[0], top[1]); + (void)left; + return pred; +} +static uint32_t Predictor10_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Average4_SSE2(*left, top[-1], top[0], top[1]); + return pred; +} +static uint32_t Predictor11_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = Select_SSE2(top[0], *left, top[-1]); + return pred; +} +static uint32_t Predictor12_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = ClampedAddSubtractFull_SSE2(*left, top[0], top[-1]); + return pred; +} +static uint32_t Predictor13_SSE2(const uint32_t* const left, + const uint32_t* const top) { + const uint32_t pred = ClampedAddSubtractHalf_SSE2(*left, top[0], top[-1]); + return pred; +} + +// Batch versions of those functions. + +// Predictor0: ARGB_BLACK. +static void PredictorAdd0_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i black = _mm_set1_epi32((int)ARGB_BLACK); + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i res = _mm_add_epi8(src, black); + _mm_storeu_si128((__m128i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[0](in + i, NULL, num_pixels - i, out + i); + } + (void)upper; +} + +// Predictor1: left. +static void PredictorAdd1_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + __m128i prev = _mm_set1_epi32((int)out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + // a | b | c | d + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + // 0 | a | b | c + const __m128i shift0 = _mm_slli_si128(src, 4); + // a | a + b | b + c | c + d + const __m128i sum0 = _mm_add_epi8(src, shift0); + // 0 | 0 | a | a + b + const __m128i shift1 = _mm_slli_si128(sum0, 8); + // a | a + b | a + b + c | a + b + c + d + const __m128i sum1 = _mm_add_epi8(sum0, shift1); + const __m128i res = _mm_add_epi8(sum1, prev); + _mm_storeu_si128((__m128i*)&out[i], res); + // replicate prev output on the four lanes + prev = _mm_shuffle_epi32(res, (3 << 0) | (3 << 2) | (3 << 4) | (3 << 6)); + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[1](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Macro that adds 32-bit integers from IN using mod 256 arithmetic +// per 8 bit channel. +#define GENERATE_PREDICTOR_1(X, IN) \ +static void PredictorAdd##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ + const __m128i other = _mm_loadu_si128((const __m128i*)&(IN)); \ + const __m128i res = _mm_add_epi8(src, other); \ + _mm_storeu_si128((__m128i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ +} + +// Predictor2: Top. +GENERATE_PREDICTOR_1(2, upper[i]) +// Predictor3: Top-right. +GENERATE_PREDICTOR_1(3, upper[i + 1]) +// Predictor4: Top-left. +GENERATE_PREDICTOR_1(4, upper[i - 1]) +#undef GENERATE_PREDICTOR_1 + +// Due to averages with integers, values cannot be accumulated in parallel for +// predictors 5 to 7. +GENERATE_PREDICTOR_ADD(Predictor5_SSE2, PredictorAdd5_SSE2) +GENERATE_PREDICTOR_ADD(Predictor6_SSE2, PredictorAdd6_SSE2) +GENERATE_PREDICTOR_ADD(Predictor7_SSE2, PredictorAdd7_SSE2) + +#define GENERATE_PREDICTOR_2(X, IN) \ +static void PredictorAdd##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* out) { \ + int i; \ + for (i = 0; i + 4 <= num_pixels; i += 4) { \ + const __m128i Tother = _mm_loadu_si128((const __m128i*)&(IN)); \ + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); \ + const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ + __m128i avg, res; \ + Average2_m128i(&T, &Tother, &avg); \ + res = _mm_add_epi8(avg, src); \ + _mm_storeu_si128((__m128i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ +} +// Predictor8: average TL T. +GENERATE_PREDICTOR_2(8, upper[i - 1]) +// Predictor9: average T TR. +GENERATE_PREDICTOR_2(9, upper[i + 1]) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: average of (average of (L,TL), average of (T, TR)). +#define DO_PRED10(OUT) do { \ + __m128i avgLTL, avg; \ + Average2_m128i(&L, &TL, &avgLTL); \ + Average2_m128i(&avgTTR, &avgLTL, &avg); \ + L = _mm_add_epi8(avg, src); \ + out[i + (OUT)] = (uint32_t)_mm_cvtsi128_si32(L); \ +} while (0) + +#define DO_PRED10_SHIFT do { \ + /* Rotate the pre-computed values for the next iteration.*/ \ + avgTTR = _mm_srli_si128(avgTTR, 4); \ + TL = _mm_srli_si128(TL, 4); \ + src = _mm_srli_si128(src, 4); \ +} while (0) + +static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + __m128i L = _mm_cvtsi32_si128((int)out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]); + __m128i avgTTR; + Average2_m128i(&T, &TR, &avgTTR); + DO_PRED10(0); + DO_PRED10_SHIFT; + DO_PRED10(1); + DO_PRED10_SHIFT; + DO_PRED10(2); + DO_PRED10_SHIFT; + DO_PRED10(3); + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[10](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED10 +#undef DO_PRED10_SHIFT + +// Predictor11: select. +#define DO_PRED11(OUT) do { \ + const __m128i L_lo = _mm_unpacklo_epi32(L, T); \ + const __m128i TL_lo = _mm_unpacklo_epi32(TL, T); \ + const __m128i pb = _mm_sad_epu8(L_lo, TL_lo); /* pb = sum |L-TL|*/ \ + const __m128i mask = _mm_cmpgt_epi32(pb, pa); \ + const __m128i A = _mm_and_si128(mask, L); \ + const __m128i B = _mm_andnot_si128(mask, T); \ + const __m128i pred = _mm_or_si128(A, B); /* pred = (pa > b)? L : T*/ \ + L = _mm_add_epi8(src, pred); \ + out[i + (OUT)] = (uint32_t)_mm_cvtsi128_si32(L); \ +} while (0) + +#define DO_PRED11_SHIFT do { \ + /* Shift the pre-computed value for the next iteration.*/ \ + T = _mm_srli_si128(T, 4); \ + TL = _mm_srli_si128(TL, 4); \ + src = _mm_srli_si128(src, 4); \ + pa = _mm_srli_si128(pa, 4); \ +} while (0) + +static void PredictorAdd11_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + __m128i pa; + __m128i L = _mm_cvtsi32_si128((int)out[-1]); + for (i = 0; i + 4 <= num_pixels; i += 4) { + __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + { + // We can unpack with any value on the upper 32 bits, provided it's the + // same on both operands (so that their sum of abs diff is zero). Here we + // use T. + const __m128i T_lo = _mm_unpacklo_epi32(T, T); + const __m128i TL_lo = _mm_unpacklo_epi32(TL, T); + const __m128i T_hi = _mm_unpackhi_epi32(T, T); + const __m128i TL_hi = _mm_unpackhi_epi32(TL, T); + const __m128i s_lo = _mm_sad_epu8(T_lo, TL_lo); + const __m128i s_hi = _mm_sad_epu8(T_hi, TL_hi); + pa = _mm_packs_epi32(s_lo, s_hi); // pa = sum |T-TL| + } + DO_PRED11(0); + DO_PRED11_SHIFT; + DO_PRED11(1); + DO_PRED11_SHIFT; + DO_PRED11(2); + DO_PRED11_SHIFT; + DO_PRED11(3); + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[11](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED11 +#undef DO_PRED11_SHIFT + +// Predictor12: ClampedAddSubtractFull. +#define DO_PRED12(DIFF, LANE, OUT) do { \ + const __m128i all = _mm_add_epi16(L, (DIFF)); \ + const __m128i alls = _mm_packus_epi16(all, all); \ + const __m128i res = _mm_add_epi8(src, alls); \ + out[i + (OUT)] = (uint32_t)_mm_cvtsi128_si32(res); \ + L = _mm_unpacklo_epi8(res, zero); \ +} while (0) + +#define DO_PRED12_SHIFT(DIFF, LANE) do { \ + /* Shift the pre-computed value for the next iteration.*/ \ + if ((LANE) == 0) (DIFF) = _mm_srli_si128((DIFF), 8); \ + src = _mm_srli_si128(src, 4); \ +} while (0) + +static void PredictorAdd12_SSE2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int i; + const __m128i zero = _mm_setzero_si128(); + const __m128i L8 = _mm_cvtsi32_si128((int)out[-1]); + __m128i L = _mm_unpacklo_epi8(L8, zero); + for (i = 0; i + 4 <= num_pixels; i += 4) { + // Load 4 pixels at a time. + __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); + const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); + const __m128i T_lo = _mm_unpacklo_epi8(T, zero); + const __m128i T_hi = _mm_unpackhi_epi8(T, zero); + const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); + const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); + const __m128i TL_hi = _mm_unpackhi_epi8(TL, zero); + __m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo); + __m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi); + DO_PRED12(diff_lo, 0, 0); + DO_PRED12_SHIFT(diff_lo, 0); + DO_PRED12(diff_lo, 1, 1); + DO_PRED12_SHIFT(diff_lo, 1); + DO_PRED12(diff_hi, 0, 2); + DO_PRED12_SHIFT(diff_hi, 0); + DO_PRED12(diff_hi, 1, 3); + } + if (i != num_pixels) { + VP8LPredictorsAdd_C[12](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED12 +#undef DO_PRED12_SHIFT + +// Due to averages with integers, values cannot be accumulated in parallel for +// predictors 13. +GENERATE_PREDICTOR_ADD(Predictor13_SSE2, PredictorAdd13_SSE2) + +//------------------------------------------------------------------------------ +// Subtract-Green Transform + +static void AddGreenToBlueAndRed_SSE2(const uint32_t* const src, int num_pixels, + uint32_t* dst) { + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb + const __m128i A = _mm_srli_epi16(in, 8); // 0 a 0 g + const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); + const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // 0g0g + const __m128i out = _mm_add_epi8(in, C); + _mm_storeu_si128((__m128i*)&dst[i], out); + } + // fallthrough and finish off with plain-C + if (i != num_pixels) { + VP8LAddGreenToBlueAndRed_C(src + i, num_pixels - i, dst + i); + } +} + +//------------------------------------------------------------------------------ +// Color Transform + +static void TransformColorInverse_SSE2(const VP8LMultipliers* const m, + const uint32_t* const src, + int num_pixels, uint32_t* dst) { +// sign-extended multiplying constants, pre-shifted by 5. +#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend +#define MK_CST_16(HI, LO) \ + _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) + const __m128i mults_rb = MK_CST_16(CST(green_to_red_), CST(green_to_blue_)); + const __m128i mults_b2 = MK_CST_16(CST(red_to_blue_), 0); +#undef MK_CST_16 +#undef CST + const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); // alpha-green masks + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb + const __m128i A = _mm_and_si128(in, mask_ag); // a 0 g 0 + const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); + const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // g0g0 + const __m128i D = _mm_mulhi_epi16(C, mults_rb); // x dr x db1 + const __m128i E = _mm_add_epi8(in, D); // x r' x b' + const __m128i F = _mm_slli_epi16(E, 8); // r' 0 b' 0 + const __m128i G = _mm_mulhi_epi16(F, mults_b2); // x db2 0 0 + const __m128i H = _mm_srli_epi32(G, 8); // 0 x db2 0 + const __m128i I = _mm_add_epi8(H, F); // r' x b'' 0 + const __m128i J = _mm_srli_epi16(I, 8); // 0 r' 0 b'' + const __m128i out = _mm_or_si128(J, A); + _mm_storeu_si128((__m128i*)&dst[i], out); + } + // Fall-back to C-version for left-overs. + if (i != num_pixels) { + VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i); + } +} + +//------------------------------------------------------------------------------ +// Color-space conversion functions + +static void ConvertBGRAToRGB_SSE2(const uint32_t* src, int num_pixels, + uint8_t* dst) { + const __m128i* in = (const __m128i*)src; + __m128i* out = (__m128i*)dst; + + while (num_pixels >= 32) { + // Load the BGRA buffers. + __m128i in0 = _mm_loadu_si128(in + 0); + __m128i in1 = _mm_loadu_si128(in + 1); + __m128i in2 = _mm_loadu_si128(in + 2); + __m128i in3 = _mm_loadu_si128(in + 3); + __m128i in4 = _mm_loadu_si128(in + 4); + __m128i in5 = _mm_loadu_si128(in + 5); + __m128i in6 = _mm_loadu_si128(in + 6); + __m128i in7 = _mm_loadu_si128(in + 7); + VP8L32bToPlanar_SSE2(&in0, &in1, &in2, &in3); + VP8L32bToPlanar_SSE2(&in4, &in5, &in6, &in7); + // At this points, in1/in5 contains red only, in2/in6 green only ... + // Pack the colors in 24b RGB. + VP8PlanarTo24b_SSE2(&in1, &in5, &in2, &in6, &in3, &in7); + _mm_storeu_si128(out + 0, in1); + _mm_storeu_si128(out + 1, in5); + _mm_storeu_si128(out + 2, in2); + _mm_storeu_si128(out + 3, in6); + _mm_storeu_si128(out + 4, in3); + _mm_storeu_si128(out + 5, in7); + in += 8; + out += 6; + num_pixels -= 32; + } + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToRGB_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + +static void ConvertBGRAToRGBA_SSE2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const __m128i red_blue_mask = _mm_set1_epi32(0x00ff00ff); + const __m128i* in = (const __m128i*)src; + __m128i* out = (__m128i*)dst; + while (num_pixels >= 8) { + const __m128i A1 = _mm_loadu_si128(in++); + const __m128i A2 = _mm_loadu_si128(in++); + const __m128i B1 = _mm_and_si128(A1, red_blue_mask); // R 0 B 0 + const __m128i B2 = _mm_and_si128(A2, red_blue_mask); // R 0 B 0 + const __m128i C1 = _mm_andnot_si128(red_blue_mask, A1); // 0 G 0 A + const __m128i C2 = _mm_andnot_si128(red_blue_mask, A2); // 0 G 0 A + const __m128i D1 = _mm_shufflelo_epi16(B1, _MM_SHUFFLE(2, 3, 0, 1)); + const __m128i D2 = _mm_shufflelo_epi16(B2, _MM_SHUFFLE(2, 3, 0, 1)); + const __m128i E1 = _mm_shufflehi_epi16(D1, _MM_SHUFFLE(2, 3, 0, 1)); + const __m128i E2 = _mm_shufflehi_epi16(D2, _MM_SHUFFLE(2, 3, 0, 1)); + const __m128i F1 = _mm_or_si128(E1, C1); + const __m128i F2 = _mm_or_si128(E2, C2); + _mm_storeu_si128(out++, F1); + _mm_storeu_si128(out++, F2); + num_pixels -= 8; + } + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToRGBA_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + +static void ConvertBGRAToRGBA4444_SSE2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const __m128i mask_0x0f = _mm_set1_epi8(0x0f); + const __m128i mask_0xf0 = _mm_set1_epi8((char)0xf0); + const __m128i* in = (const __m128i*)src; + __m128i* out = (__m128i*)dst; + while (num_pixels >= 8) { + const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3 + const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7 + const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4... + const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6... + const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6... + const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7... + const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7 + const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7 + const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7 + const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7 + const __m128i ga1 = _mm_srli_epi16(ga0, 4); // g0-|g1-|...|a6-|a7- + const __m128i rb1 = _mm_and_si128(rb0, mask_0xf0); // -r0|-r1|...|-b6|-a7 + const __m128i ga2 = _mm_and_si128(ga1, mask_0x0f); // g0-|g1-|...|a6-|a7- + const __m128i rgba0 = _mm_or_si128(ga2, rb1); // rg0..rg7 | ba0..ba7 + const __m128i rgba1 = _mm_srli_si128(rgba0, 8); // ba0..ba7 | 0 +#if (WEBP_SWAP_16BIT_CSP == 1) + const __m128i rgba = _mm_unpacklo_epi8(rgba1, rgba0); // barg0...barg7 +#else + const __m128i rgba = _mm_unpacklo_epi8(rgba0, rgba1); // rgba0...rgba7 +#endif + _mm_storeu_si128(out++, rgba); + num_pixels -= 8; + } + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToRGBA4444_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + +static void ConvertBGRAToRGB565_SSE2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const __m128i mask_0xe0 = _mm_set1_epi8((char)0xe0); + const __m128i mask_0xf8 = _mm_set1_epi8((char)0xf8); + const __m128i mask_0x07 = _mm_set1_epi8(0x07); + const __m128i* in = (const __m128i*)src; + __m128i* out = (__m128i*)dst; + while (num_pixels >= 8) { + const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3 + const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7 + const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4... + const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6... + const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6... + const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7... + const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7 + const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7 + const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7 + const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7 + const __m128i rb1 = _mm_and_si128(rb0, mask_0xf8); // -r0..-r7|-b0..-b7 + const __m128i g_lo1 = _mm_srli_epi16(ga0, 5); + const __m128i g_lo2 = _mm_and_si128(g_lo1, mask_0x07); // g0-...g7-|xx (3b) + const __m128i g_hi1 = _mm_slli_epi16(ga0, 3); + const __m128i g_hi2 = _mm_and_si128(g_hi1, mask_0xe0); // -g0...-g7|xx (3b) + const __m128i b0 = _mm_srli_si128(rb1, 8); // -b0...-b7|0 + const __m128i rg1 = _mm_or_si128(rb1, g_lo2); // gr0...gr7|xx + const __m128i b1 = _mm_srli_epi16(b0, 3); + const __m128i gb1 = _mm_or_si128(b1, g_hi2); // bg0...bg7|xx +#if (WEBP_SWAP_16BIT_CSP == 1) + const __m128i rgba = _mm_unpacklo_epi8(gb1, rg1); // rggb0...rggb7 +#else + const __m128i rgba = _mm_unpacklo_epi8(rg1, gb1); // bgrb0...bgrb7 +#endif + _mm_storeu_si128(out++, rgba); + num_pixels -= 8; + } + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToRGB565_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + +static void ConvertBGRAToBGR_SSE2(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const __m128i mask_l = _mm_set_epi32(0, 0x00ffffff, 0, 0x00ffffff); + const __m128i mask_h = _mm_set_epi32(0x00ffffff, 0, 0x00ffffff, 0); + const __m128i* in = (const __m128i*)src; + const uint8_t* const end = dst + num_pixels * 3; + // the last storel_epi64 below writes 8 bytes starting at offset 18 + while (dst + 26 <= end) { + const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3 + const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7 + const __m128i a0l = _mm_and_si128(bgra0, mask_l); // bgr0|0|bgr0|0 + const __m128i a4l = _mm_and_si128(bgra4, mask_l); // bgr0|0|bgr0|0 + const __m128i a0h = _mm_and_si128(bgra0, mask_h); // 0|bgr0|0|bgr0 + const __m128i a4h = _mm_and_si128(bgra4, mask_h); // 0|bgr0|0|bgr0 + const __m128i b0h = _mm_srli_epi64(a0h, 8); // 000b|gr00|000b|gr00 + const __m128i b4h = _mm_srli_epi64(a4h, 8); // 000b|gr00|000b|gr00 + const __m128i c0 = _mm_or_si128(a0l, b0h); // rgbrgb00|rgbrgb00 + const __m128i c4 = _mm_or_si128(a4l, b4h); // rgbrgb00|rgbrgb00 + const __m128i c2 = _mm_srli_si128(c0, 8); + const __m128i c6 = _mm_srli_si128(c4, 8); + _mm_storel_epi64((__m128i*)(dst + 0), c0); + _mm_storel_epi64((__m128i*)(dst + 6), c2); + _mm_storel_epi64((__m128i*)(dst + 12), c4); + _mm_storel_epi64((__m128i*)(dst + 18), c6); + dst += 24; + num_pixels -= 8; + } + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, dst); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LDspInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) { + VP8LPredictors[5] = Predictor5_SSE2; + VP8LPredictors[6] = Predictor6_SSE2; + VP8LPredictors[7] = Predictor7_SSE2; + VP8LPredictors[8] = Predictor8_SSE2; + VP8LPredictors[9] = Predictor9_SSE2; + VP8LPredictors[10] = Predictor10_SSE2; + VP8LPredictors[11] = Predictor11_SSE2; + VP8LPredictors[12] = Predictor12_SSE2; + VP8LPredictors[13] = Predictor13_SSE2; + + VP8LPredictorsAdd[0] = PredictorAdd0_SSE2; + VP8LPredictorsAdd[1] = PredictorAdd1_SSE2; + VP8LPredictorsAdd[2] = PredictorAdd2_SSE2; + VP8LPredictorsAdd[3] = PredictorAdd3_SSE2; + VP8LPredictorsAdd[4] = PredictorAdd4_SSE2; + VP8LPredictorsAdd[5] = PredictorAdd5_SSE2; + VP8LPredictorsAdd[6] = PredictorAdd6_SSE2; + VP8LPredictorsAdd[7] = PredictorAdd7_SSE2; + VP8LPredictorsAdd[8] = PredictorAdd8_SSE2; + VP8LPredictorsAdd[9] = PredictorAdd9_SSE2; + VP8LPredictorsAdd[10] = PredictorAdd10_SSE2; + VP8LPredictorsAdd[11] = PredictorAdd11_SSE2; + VP8LPredictorsAdd[12] = PredictorAdd12_SSE2; + VP8LPredictorsAdd[13] = PredictorAdd13_SSE2; + + VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_SSE2; + VP8LTransformColorInverse = TransformColorInverse_SSE2; + + VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE2; + VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_SSE2; + VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444_SSE2; + VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565_SSE2; + VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(VP8LDspInitSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/lossless_sse41.c b/libraries/webp/src/dsp/lossless_sse41.c new file mode 100644 index 00000000000..bb7ce7611fa --- /dev/null +++ b/libraries/webp/src/dsp/lossless_sse41.c @@ -0,0 +1,133 @@ +// Copyright 2021 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE41 variant of methods for lossless decoder + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE41) + +#include "src/dsp/common_sse41.h" +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" + +//------------------------------------------------------------------------------ +// Color-space conversion functions + +static void TransformColorInverse_SSE41(const VP8LMultipliers* const m, + const uint32_t* const src, + int num_pixels, uint32_t* dst) { +// sign-extended multiplying constants, pre-shifted by 5. +#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend + const __m128i mults_rb = + _mm_set1_epi32((int)((uint32_t)CST(green_to_red_) << 16 | + (CST(green_to_blue_) & 0xffff))); + const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue_)); +#undef CST + const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); + const __m128i perm1 = _mm_setr_epi8(-1, 1, -1, 1, -1, 5, -1, 5, + -1, 9, -1, 9, -1, 13, -1, 13); + const __m128i perm2 = _mm_setr_epi8(-1, 2, -1, -1, -1, 6, -1, -1, + -1, 10, -1, -1, -1, 14, -1, -1); + int i; + for (i = 0; i + 4 <= num_pixels; i += 4) { + const __m128i A = _mm_loadu_si128((const __m128i*)(src + i)); + const __m128i B = _mm_shuffle_epi8(A, perm1); // argb -> g0g0 + const __m128i C = _mm_mulhi_epi16(B, mults_rb); + const __m128i D = _mm_add_epi8(A, C); + const __m128i E = _mm_shuffle_epi8(D, perm2); + const __m128i F = _mm_mulhi_epi16(E, mults_b2); + const __m128i G = _mm_add_epi8(D, F); + const __m128i out = _mm_blendv_epi8(G, A, mask_ag); + _mm_storeu_si128((__m128i*)&dst[i], out); + } + // Fall-back to C-version for left-overs. + if (i != num_pixels) { + VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i); + } +} + +//------------------------------------------------------------------------------ + +#define ARGB_TO_RGB_SSE41 do { \ + while (num_pixels >= 16) { \ + const __m128i in0 = _mm_loadu_si128(in + 0); \ + const __m128i in1 = _mm_loadu_si128(in + 1); \ + const __m128i in2 = _mm_loadu_si128(in + 2); \ + const __m128i in3 = _mm_loadu_si128(in + 3); \ + const __m128i a0 = _mm_shuffle_epi8(in0, perm0); \ + const __m128i a1 = _mm_shuffle_epi8(in1, perm1); \ + const __m128i a2 = _mm_shuffle_epi8(in2, perm2); \ + const __m128i a3 = _mm_shuffle_epi8(in3, perm3); \ + const __m128i b0 = _mm_blend_epi16(a0, a1, 0xc0); \ + const __m128i b1 = _mm_blend_epi16(a1, a2, 0xf0); \ + const __m128i b2 = _mm_blend_epi16(a2, a3, 0xfc); \ + _mm_storeu_si128(out + 0, b0); \ + _mm_storeu_si128(out + 1, b1); \ + _mm_storeu_si128(out + 2, b2); \ + in += 4; \ + out += 3; \ + num_pixels -= 16; \ + } \ +} while (0) + +static void ConvertBGRAToRGB_SSE41(const uint32_t* src, int num_pixels, + uint8_t* dst) { + const __m128i* in = (const __m128i*)src; + __m128i* out = (__m128i*)dst; + const __m128i perm0 = _mm_setr_epi8(2, 1, 0, 6, 5, 4, 10, 9, + 8, 14, 13, 12, -1, -1, -1, -1); + const __m128i perm1 = _mm_shuffle_epi32(perm0, 0x39); + const __m128i perm2 = _mm_shuffle_epi32(perm0, 0x4e); + const __m128i perm3 = _mm_shuffle_epi32(perm0, 0x93); + + ARGB_TO_RGB_SSE41; + + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToRGB_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + +static void ConvertBGRAToBGR_SSE41(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const __m128i* in = (const __m128i*)src; + __m128i* out = (__m128i*)dst; + const __m128i perm0 = _mm_setr_epi8(0, 1, 2, 4, 5, 6, 8, 9, 10, + 12, 13, 14, -1, -1, -1, -1); + const __m128i perm1 = _mm_shuffle_epi32(perm0, 0x39); + const __m128i perm2 = _mm_shuffle_epi32(perm0, 0x4e); + const __m128i perm3 = _mm_shuffle_epi32(perm0, 0x93); + + ARGB_TO_RGB_SSE41; + + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + +#undef ARGB_TO_RGB_SSE41 + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LDspInitSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE41(void) { + VP8LTransformColorInverse = TransformColorInverse_SSE41; + VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE41; + VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE41; +} + +#else // !WEBP_USE_SSE41 + +WEBP_DSP_INIT_STUB(VP8LDspInitSSE41) + +#endif // WEBP_USE_SSE41 diff --git a/libraries/webp/src/dsp/mips_macro.h b/libraries/webp/src/dsp/mips_macro.h new file mode 100644 index 00000000000..e810d3d3824 --- /dev/null +++ b/libraries/webp/src/dsp/mips_macro.h @@ -0,0 +1,210 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS common macros + +#ifndef WEBP_DSP_MIPS_MACRO_H_ +#define WEBP_DSP_MIPS_MACRO_H_ + +#if defined(__GNUC__) && defined(__ANDROID__) && LOCAL_GCC_VERSION == 0x409 +#define WORK_AROUND_GCC +#endif + +#define STR(s) #s +#define XSTR(s) STR(s) + +// O0[31..16 | 15..0] = I0[31..16 | 15..0] + I1[31..16 | 15..0] +// O1[31..16 | 15..0] = I0[31..16 | 15..0] - I1[31..16 | 15..0] +// O - output +// I - input (macro doesn't change it) +#define ADD_SUB_HALVES(O0, O1, \ + I0, I1) \ + "addq.ph %[" #O0 "], %[" #I0 "], %[" #I1 "] \n\t" \ + "subq.ph %[" #O1 "], %[" #I0 "], %[" #I1 "] \n\t" + +// O - output +// I - input (macro doesn't change it) +// I[0/1] - offset in bytes +#define LOAD_IN_X2(O0, O1, \ + I0, I1) \ + "lh %[" #O0 "], " #I0 "(%[in]) \n\t" \ + "lh %[" #O1 "], " #I1 "(%[in]) \n\t" + +// I0 - location +// I1..I9 - offsets in bytes +#define LOAD_WITH_OFFSET_X4(O0, O1, O2, O3, \ + I0, I1, I2, I3, I4, I5, I6, I7, I8, I9) \ + "ulw %[" #O0 "], " #I1 "+" XSTR(I9) "*" #I5 "(%[" #I0 "]) \n\t" \ + "ulw %[" #O1 "], " #I2 "+" XSTR(I9) "*" #I6 "(%[" #I0 "]) \n\t" \ + "ulw %[" #O2 "], " #I3 "+" XSTR(I9) "*" #I7 "(%[" #I0 "]) \n\t" \ + "ulw %[" #O3 "], " #I4 "+" XSTR(I9) "*" #I8 "(%[" #I0 "]) \n\t" + + +// O - output +// I - input (macro doesn't change it so it should be different from I) +#define MUL_SHIFT_C1(O, I) \ + "mul %[" #O "], %[" #I "], %[kC1] \n\t" \ + "sra %[" #O "], %[" #O "], 16 \n\t" \ + "addu %[" #O "], %[" #O "], %[" #I "] \n\t" +#define MUL_SHIFT_C2(O, I) \ + "mul %[" #O "], %[" #I "], %[kC2] \n\t" \ + "sra %[" #O "], %[" #O "], 16 \n\t" + +// Same as #define MUL_SHIFT_C1 but I and O are the same. It stores the +// intermediary result in TMP. +#define MUL_SHIFT_C1_IO(IO, TMP) \ + "mul %[" #TMP "], %[" #IO "], %[kC1] \n\t" \ + "sra %[" #TMP "], %[" #TMP "], 16 \n\t" \ + "addu %[" #IO "], %[" #TMP "], %[" #IO "] \n\t" + +// O - output +// IO - input/output +// I - input (macro doesn't change it) +#define MUL_SHIFT_SUM(O0, O1, O2, O3, O4, O5, O6, O7, \ + IO0, IO1, IO2, IO3, \ + I0, I1, I2, I3, I4, I5, I6, I7) \ + MUL_SHIFT_C2(O0, I0) \ + MUL_SHIFT_C1(O1, I0) \ + MUL_SHIFT_C2(O2, I1) \ + MUL_SHIFT_C1(O3, I1) \ + MUL_SHIFT_C2(O4, I2) \ + MUL_SHIFT_C1(O5, I2) \ + MUL_SHIFT_C2(O6, I3) \ + MUL_SHIFT_C1(O7, I3) \ + "addu %[" #IO0 "], %[" #IO0 "], %[" #I4 "] \n\t" \ + "addu %[" #IO1 "], %[" #IO1 "], %[" #I5 "] \n\t" \ + "subu %[" #IO2 "], %[" #IO2 "], %[" #I6 "] \n\t" \ + "subu %[" #IO3 "], %[" #IO3 "], %[" #I7 "] \n\t" + +// O - output +// I - input (macro doesn't change it) +#define INSERT_HALF_X2(O0, O1, \ + I0, I1) \ + "ins %[" #O0 "], %[" #I0 "], 16, 16 \n\t" \ + "ins %[" #O1 "], %[" #I1 "], 16, 16 \n\t" + +// O - output +// I - input (macro doesn't change it) +#define SRA_16(O0, O1, O2, O3, \ + I0, I1, I2, I3) \ + "sra %[" #O0 "], %[" #I0 "], 16 \n\t" \ + "sra %[" #O1 "], %[" #I1 "], 16 \n\t" \ + "sra %[" #O2 "], %[" #I2 "], 16 \n\t" \ + "sra %[" #O3 "], %[" #I3 "], 16 \n\t" + +// temp0[31..16 | 15..0] = temp8[31..16 | 15..0] + temp12[31..16 | 15..0] +// temp1[31..16 | 15..0] = temp8[31..16 | 15..0] - temp12[31..16 | 15..0] +// temp0[31..16 | 15..0] = temp0[31..16 >> 3 | 15..0 >> 3] +// temp1[31..16 | 15..0] = temp1[31..16 >> 3 | 15..0 >> 3] +// O - output +// I - input (macro doesn't change it) +#define SHIFT_R_SUM_X2(O0, O1, O2, O3, O4, O5, O6, O7, \ + I0, I1, I2, I3, I4, I5, I6, I7) \ + "addq.ph %[" #O0 "], %[" #I0 "], %[" #I4 "] \n\t" \ + "subq.ph %[" #O1 "], %[" #I0 "], %[" #I4 "] \n\t" \ + "addq.ph %[" #O2 "], %[" #I1 "], %[" #I5 "] \n\t" \ + "subq.ph %[" #O3 "], %[" #I1 "], %[" #I5 "] \n\t" \ + "addq.ph %[" #O4 "], %[" #I2 "], %[" #I6 "] \n\t" \ + "subq.ph %[" #O5 "], %[" #I2 "], %[" #I6 "] \n\t" \ + "addq.ph %[" #O6 "], %[" #I3 "], %[" #I7 "] \n\t" \ + "subq.ph %[" #O7 "], %[" #I3 "], %[" #I7 "] \n\t" \ + "shra.ph %[" #O0 "], %[" #O0 "], 3 \n\t" \ + "shra.ph %[" #O1 "], %[" #O1 "], 3 \n\t" \ + "shra.ph %[" #O2 "], %[" #O2 "], 3 \n\t" \ + "shra.ph %[" #O3 "], %[" #O3 "], 3 \n\t" \ + "shra.ph %[" #O4 "], %[" #O4 "], 3 \n\t" \ + "shra.ph %[" #O5 "], %[" #O5 "], 3 \n\t" \ + "shra.ph %[" #O6 "], %[" #O6 "], 3 \n\t" \ + "shra.ph %[" #O7 "], %[" #O7 "], 3 \n\t" + +// precrq.ph.w temp0, temp8, temp2 +// temp0 = temp8[31..16] | temp2[31..16] +// ins temp2, temp8, 16, 16 +// temp2 = temp8[31..16] | temp2[15..0] +// O - output +// IO - input/output +// I - input (macro doesn't change it) +#define PACK_2_HALVES_TO_WORD(O0, O1, O2, O3, \ + IO0, IO1, IO2, IO3, \ + I0, I1, I2, I3) \ + "precrq.ph.w %[" #O0 "], %[" #I0 "], %[" #IO0 "] \n\t" \ + "precrq.ph.w %[" #O1 "], %[" #I1 "], %[" #IO1 "] \n\t" \ + "ins %[" #IO0 "], %[" #I0 "], 16, 16 \n\t" \ + "ins %[" #IO1 "], %[" #I1 "], 16, 16 \n\t" \ + "precrq.ph.w %[" #O2 "], %[" #I2 "], %[" #IO2 "] \n\t" \ + "precrq.ph.w %[" #O3 "], %[" #I3 "], %[" #IO3 "] \n\t" \ + "ins %[" #IO2 "], %[" #I2 "], 16, 16 \n\t" \ + "ins %[" #IO3 "], %[" #I3 "], 16, 16 \n\t" + +// preceu.ph.qbr temp0, temp8 +// temp0 = 0 | 0 | temp8[23..16] | temp8[7..0] +// preceu.ph.qbl temp1, temp8 +// temp1 = temp8[23..16] | temp8[7..0] | 0 | 0 +// O - output +// I - input (macro doesn't change it) +#define CONVERT_2_BYTES_TO_HALF(O0, O1, O2, O3, O4, O5, O6, O7, \ + I0, I1, I2, I3) \ + "preceu.ph.qbr %[" #O0 "], %[" #I0 "] \n\t" \ + "preceu.ph.qbl %[" #O1 "], %[" #I0 "] \n\t" \ + "preceu.ph.qbr %[" #O2 "], %[" #I1 "] \n\t" \ + "preceu.ph.qbl %[" #O3 "], %[" #I1 "] \n\t" \ + "preceu.ph.qbr %[" #O4 "], %[" #I2 "] \n\t" \ + "preceu.ph.qbl %[" #O5 "], %[" #I2 "] \n\t" \ + "preceu.ph.qbr %[" #O6 "], %[" #I3 "] \n\t" \ + "preceu.ph.qbl %[" #O7 "], %[" #I3 "] \n\t" + +// temp0[31..16 | 15..0] = temp0[31..16 | 15..0] + temp8[31..16 | 15..0] +// temp0[31..16 | 15..0] = temp0[31..16 <<(s) 7 | 15..0 <<(s) 7] +// temp1..temp7 same as temp0 +// precrqu_s.qb.ph temp0, temp1, temp0: +// temp0 = temp1[31..24] | temp1[15..8] | temp0[31..24] | temp0[15..8] +// store temp0 to dst +// IO - input/output +// I - input (macro doesn't change it) +#define STORE_SAT_SUM_X2(IO0, IO1, IO2, IO3, IO4, IO5, IO6, IO7, \ + I0, I1, I2, I3, I4, I5, I6, I7, \ + I8, I9, I10, I11, I12, I13) \ + "addq.ph %[" #IO0 "], %[" #IO0 "], %[" #I0 "] \n\t" \ + "addq.ph %[" #IO1 "], %[" #IO1 "], %[" #I1 "] \n\t" \ + "addq.ph %[" #IO2 "], %[" #IO2 "], %[" #I2 "] \n\t" \ + "addq.ph %[" #IO3 "], %[" #IO3 "], %[" #I3 "] \n\t" \ + "addq.ph %[" #IO4 "], %[" #IO4 "], %[" #I4 "] \n\t" \ + "addq.ph %[" #IO5 "], %[" #IO5 "], %[" #I5 "] \n\t" \ + "addq.ph %[" #IO6 "], %[" #IO6 "], %[" #I6 "] \n\t" \ + "addq.ph %[" #IO7 "], %[" #IO7 "], %[" #I7 "] \n\t" \ + "shll_s.ph %[" #IO0 "], %[" #IO0 "], 7 \n\t" \ + "shll_s.ph %[" #IO1 "], %[" #IO1 "], 7 \n\t" \ + "shll_s.ph %[" #IO2 "], %[" #IO2 "], 7 \n\t" \ + "shll_s.ph %[" #IO3 "], %[" #IO3 "], 7 \n\t" \ + "shll_s.ph %[" #IO4 "], %[" #IO4 "], 7 \n\t" \ + "shll_s.ph %[" #IO5 "], %[" #IO5 "], 7 \n\t" \ + "shll_s.ph %[" #IO6 "], %[" #IO6 "], 7 \n\t" \ + "shll_s.ph %[" #IO7 "], %[" #IO7 "], 7 \n\t" \ + "precrqu_s.qb.ph %[" #IO0 "], %[" #IO1 "], %[" #IO0 "] \n\t" \ + "precrqu_s.qb.ph %[" #IO2 "], %[" #IO3 "], %[" #IO2 "] \n\t" \ + "precrqu_s.qb.ph %[" #IO4 "], %[" #IO5 "], %[" #IO4 "] \n\t" \ + "precrqu_s.qb.ph %[" #IO6 "], %[" #IO7 "], %[" #IO6 "] \n\t" \ + "usw %[" #IO0 "], " XSTR(I13) "*" #I9 "(%[" #I8 "]) \n\t" \ + "usw %[" #IO2 "], " XSTR(I13) "*" #I10 "(%[" #I8 "]) \n\t" \ + "usw %[" #IO4 "], " XSTR(I13) "*" #I11 "(%[" #I8 "]) \n\t" \ + "usw %[" #IO6 "], " XSTR(I13) "*" #I12 "(%[" #I8 "]) \n\t" + +#define OUTPUT_EARLY_CLOBBER_REGS_10() \ + : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), \ + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), \ + [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), [temp9]"=&r"(temp9), \ + [temp10]"=&r"(temp10) + +#define OUTPUT_EARLY_CLOBBER_REGS_18() \ + OUTPUT_EARLY_CLOBBER_REGS_10(), \ + [temp11]"=&r"(temp11), [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), \ + [temp14]"=&r"(temp14), [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), \ + [temp17]"=&r"(temp17), [temp18]"=&r"(temp18) + +#endif // WEBP_DSP_MIPS_MACRO_H_ diff --git a/libraries/webp/src/dsp/msa_macro.h b/libraries/webp/src/dsp/msa_macro.h new file mode 100644 index 00000000000..90adbbc3197 --- /dev/null +++ b/libraries/webp/src/dsp/msa_macro.h @@ -0,0 +1,1395 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MSA common macros +// +// Author(s): Prashant Patil (prashant.patil@imgtec.com) + +#ifndef WEBP_DSP_MSA_MACRO_H_ +#define WEBP_DSP_MSA_MACRO_H_ + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MSA) + +#include +#include + +#if defined(__clang__) + #define CLANG_BUILD +#endif + +#ifdef CLANG_BUILD + #define ALPHAVAL (-1) + #define ADDVI_H(a, b) __msa_addvi_h((v8i16)a, b) + #define ADDVI_W(a, b) __msa_addvi_w((v4i32)a, b) + #define SRAI_B(a, b) __msa_srai_b((v16i8)a, b) + #define SRAI_H(a, b) __msa_srai_h((v8i16)a, b) + #define SRAI_W(a, b) __msa_srai_w((v4i32)a, b) + #define SRLI_H(a, b) __msa_srli_h((v8i16)a, b) + #define SLLI_B(a, b) __msa_slli_b((v4i32)a, b) + #define ANDI_B(a, b) __msa_andi_b((v16u8)a, b) + #define ORI_B(a, b) __msa_ori_b((v16u8)a, b) +#else + #define ALPHAVAL (0xff) + #define ADDVI_H(a, b) (a + b) + #define ADDVI_W(a, b) (a + b) + #define SRAI_B(a, b) (a >> b) + #define SRAI_H(a, b) (a >> b) + #define SRAI_W(a, b) (a >> b) + #define SRLI_H(a, b) (a << b) + #define SLLI_B(a, b) (a << b) + #define ANDI_B(a, b) (a & b) + #define ORI_B(a, b) (a | b) +#endif + +#define LD_B(RTYPE, psrc) *((RTYPE*)(psrc)) +#define LD_UB(...) LD_B(v16u8, __VA_ARGS__) +#define LD_SB(...) LD_B(v16i8, __VA_ARGS__) + +#define LD_H(RTYPE, psrc) *((RTYPE*)(psrc)) +#define LD_UH(...) LD_H(v8u16, __VA_ARGS__) +#define LD_SH(...) LD_H(v8i16, __VA_ARGS__) + +#define LD_W(RTYPE, psrc) *((RTYPE*)(psrc)) +#define LD_UW(...) LD_W(v4u32, __VA_ARGS__) +#define LD_SW(...) LD_W(v4i32, __VA_ARGS__) + +#define ST_B(RTYPE, in, pdst) *((RTYPE*)(pdst)) = in +#define ST_UB(...) ST_B(v16u8, __VA_ARGS__) +#define ST_SB(...) ST_B(v16i8, __VA_ARGS__) + +#define ST_H(RTYPE, in, pdst) *((RTYPE*)(pdst)) = in +#define ST_UH(...) ST_H(v8u16, __VA_ARGS__) +#define ST_SH(...) ST_H(v8i16, __VA_ARGS__) + +#define ST_W(RTYPE, in, pdst) *((RTYPE*)(pdst)) = in +#define ST_UW(...) ST_W(v4u32, __VA_ARGS__) +#define ST_SW(...) ST_W(v4i32, __VA_ARGS__) + +#define MSA_LOAD_FUNC(TYPE, INSTR, FUNC_NAME) \ + static inline TYPE FUNC_NAME(const void* const psrc) { \ + const uint8_t* const psrc_m = (const uint8_t*)psrc; \ + TYPE val_m; \ + __asm__ volatile("" #INSTR " %[val_m], %[psrc_m] \n\t" \ + : [val_m] "=r"(val_m) \ + : [psrc_m] "m"(*psrc_m)); \ + return val_m; \ + } + +#define MSA_LOAD(psrc, FUNC_NAME) FUNC_NAME(psrc) + +#define MSA_STORE_FUNC(TYPE, INSTR, FUNC_NAME) \ + static inline void FUNC_NAME(TYPE val, void* const pdst) { \ + uint8_t* const pdst_m = (uint8_t*)pdst; \ + TYPE val_m = val; \ + __asm__ volatile(" " #INSTR " %[val_m], %[pdst_m] \n\t" \ + : [pdst_m] "=m"(*pdst_m) \ + : [val_m] "r"(val_m)); \ + } + +#define MSA_STORE(val, pdst, FUNC_NAME) FUNC_NAME(val, pdst) + +#if (__mips_isa_rev >= 6) + MSA_LOAD_FUNC(uint16_t, lh, msa_lh); + #define LH(psrc) MSA_LOAD(psrc, msa_lh) + MSA_LOAD_FUNC(uint32_t, lw, msa_lw); + #define LW(psrc) MSA_LOAD(psrc, msa_lw) + #if (__mips == 64) + MSA_LOAD_FUNC(uint64_t, ld, msa_ld); + #define LD(psrc) MSA_LOAD(psrc, msa_ld) + #else // !(__mips == 64) + #define LD(psrc) ((((uint64_t)MSA_LOAD(psrc + 4, msa_lw)) << 32) | \ + MSA_LOAD(psrc, msa_lw)) + #endif // (__mips == 64) + + MSA_STORE_FUNC(uint16_t, sh, msa_sh); + #define SH(val, pdst) MSA_STORE(val, pdst, msa_sh) + MSA_STORE_FUNC(uint32_t, sw, msa_sw); + #define SW(val, pdst) MSA_STORE(val, pdst, msa_sw) + MSA_STORE_FUNC(uint64_t, sd, msa_sd); + #define SD(val, pdst) MSA_STORE(val, pdst, msa_sd) +#else // !(__mips_isa_rev >= 6) + MSA_LOAD_FUNC(uint16_t, ulh, msa_ulh); + #define LH(psrc) MSA_LOAD(psrc, msa_ulh) + MSA_LOAD_FUNC(uint32_t, ulw, msa_ulw); + #define LW(psrc) MSA_LOAD(psrc, msa_ulw) + #if (__mips == 64) + MSA_LOAD_FUNC(uint64_t, uld, msa_uld); + #define LD(psrc) MSA_LOAD(psrc, msa_uld) + #else // !(__mips == 64) + #define LD(psrc) ((((uint64_t)MSA_LOAD(psrc + 4, msa_ulw)) << 32) | \ + MSA_LOAD(psrc, msa_ulw)) + #endif // (__mips == 64) + + MSA_STORE_FUNC(uint16_t, ush, msa_ush); + #define SH(val, pdst) MSA_STORE(val, pdst, msa_ush) + MSA_STORE_FUNC(uint32_t, usw, msa_usw); + #define SW(val, pdst) MSA_STORE(val, pdst, msa_usw) + #define SD(val, pdst) do { \ + uint8_t* const pdst_sd_m = (uint8_t*)(pdst); \ + const uint32_t val0_m = (uint32_t)(val & 0x00000000FFFFFFFF); \ + const uint32_t val1_m = (uint32_t)((val >> 32) & 0x00000000FFFFFFFF); \ + SW(val0_m, pdst_sd_m); \ + SW(val1_m, pdst_sd_m + 4); \ + } while (0) +#endif // (__mips_isa_rev >= 6) + +/* Description : Load 4 words with stride + * Arguments : Inputs - psrc, stride + * Outputs - out0, out1, out2, out3 + * Details : Load word in 'out0' from (psrc) + * Load word in 'out1' from (psrc + stride) + * Load word in 'out2' from (psrc + 2 * stride) + * Load word in 'out3' from (psrc + 3 * stride) + */ +#define LW4(psrc, stride, out0, out1, out2, out3) do { \ + const uint8_t* ptmp = (const uint8_t*)psrc; \ + out0 = LW(ptmp); \ + ptmp += stride; \ + out1 = LW(ptmp); \ + ptmp += stride; \ + out2 = LW(ptmp); \ + ptmp += stride; \ + out3 = LW(ptmp); \ +} while (0) + +/* Description : Store words with stride + * Arguments : Inputs - in0, in1, in2, in3, pdst, stride + * Details : Store word from 'in0' to (pdst) + * Store word from 'in1' to (pdst + stride) + * Store word from 'in2' to (pdst + 2 * stride) + * Store word from 'in3' to (pdst + 3 * stride) + */ +#define SW4(in0, in1, in2, in3, pdst, stride) do { \ + uint8_t* ptmp = (uint8_t*)pdst; \ + SW(in0, ptmp); \ + ptmp += stride; \ + SW(in1, ptmp); \ + ptmp += stride; \ + SW(in2, ptmp); \ + ptmp += stride; \ + SW(in3, ptmp); \ +} while (0) + +#define SW3(in0, in1, in2, pdst, stride) do { \ + uint8_t* ptmp = (uint8_t*)pdst; \ + SW(in0, ptmp); \ + ptmp += stride; \ + SW(in1, ptmp); \ + ptmp += stride; \ + SW(in2, ptmp); \ +} while (0) + +#define SW2(in0, in1, pdst, stride) do { \ + uint8_t* ptmp = (uint8_t*)pdst; \ + SW(in0, ptmp); \ + ptmp += stride; \ + SW(in1, ptmp); \ +} while (0) + +/* Description : Store 4 double words with stride + * Arguments : Inputs - in0, in1, in2, in3, pdst, stride + * Details : Store double word from 'in0' to (pdst) + * Store double word from 'in1' to (pdst + stride) + * Store double word from 'in2' to (pdst + 2 * stride) + * Store double word from 'in3' to (pdst + 3 * stride) + */ +#define SD4(in0, in1, in2, in3, pdst, stride) do { \ + uint8_t* ptmp = (uint8_t*)pdst; \ + SD(in0, ptmp); \ + ptmp += stride; \ + SD(in1, ptmp); \ + ptmp += stride; \ + SD(in2, ptmp); \ + ptmp += stride; \ + SD(in3, ptmp); \ +} while (0) + +/* Description : Load vectors with 16 byte elements with stride + * Arguments : Inputs - psrc, stride + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Load 16 byte elements in 'out0' from (psrc) + * Load 16 byte elements in 'out1' from (psrc + stride) + */ +#define LD_B2(RTYPE, psrc, stride, out0, out1) do { \ + out0 = LD_B(RTYPE, psrc); \ + out1 = LD_B(RTYPE, psrc + stride); \ +} while (0) +#define LD_UB2(...) LD_B2(v16u8, __VA_ARGS__) +#define LD_SB2(...) LD_B2(v16i8, __VA_ARGS__) + +#define LD_B3(RTYPE, psrc, stride, out0, out1, out2) do { \ + LD_B2(RTYPE, psrc, stride, out0, out1); \ + out2 = LD_B(RTYPE, psrc + 2 * stride); \ +} while (0) +#define LD_UB3(...) LD_B3(v16u8, __VA_ARGS__) +#define LD_SB3(...) LD_B3(v16i8, __VA_ARGS__) + +#define LD_B4(RTYPE, psrc, stride, out0, out1, out2, out3) do { \ + LD_B2(RTYPE, psrc, stride, out0, out1); \ + LD_B2(RTYPE, psrc + 2 * stride , stride, out2, out3); \ +} while (0) +#define LD_UB4(...) LD_B4(v16u8, __VA_ARGS__) +#define LD_SB4(...) LD_B4(v16i8, __VA_ARGS__) + +#define LD_B8(RTYPE, psrc, stride, \ + out0, out1, out2, out3, out4, out5, out6, out7) do { \ + LD_B4(RTYPE, psrc, stride, out0, out1, out2, out3); \ + LD_B4(RTYPE, psrc + 4 * stride, stride, out4, out5, out6, out7); \ +} while (0) +#define LD_UB8(...) LD_B8(v16u8, __VA_ARGS__) +#define LD_SB8(...) LD_B8(v16i8, __VA_ARGS__) + +/* Description : Load vectors with 8 halfword elements with stride + * Arguments : Inputs - psrc, stride + * Outputs - out0, out1 + * Details : Load 8 halfword elements in 'out0' from (psrc) + * Load 8 halfword elements in 'out1' from (psrc + stride) + */ +#define LD_H2(RTYPE, psrc, stride, out0, out1) do { \ + out0 = LD_H(RTYPE, psrc); \ + out1 = LD_H(RTYPE, psrc + stride); \ +} while (0) +#define LD_UH2(...) LD_H2(v8u16, __VA_ARGS__) +#define LD_SH2(...) LD_H2(v8i16, __VA_ARGS__) + +/* Description : Load vectors with 4 word elements with stride + * Arguments : Inputs - psrc, stride + * Outputs - out0, out1, out2, out3 + * Details : Load 4 word elements in 'out0' from (psrc + 0 * stride) + * Load 4 word elements in 'out1' from (psrc + 1 * stride) + * Load 4 word elements in 'out2' from (psrc + 2 * stride) + * Load 4 word elements in 'out3' from (psrc + 3 * stride) + */ +#define LD_W2(RTYPE, psrc, stride, out0, out1) do { \ + out0 = LD_W(RTYPE, psrc); \ + out1 = LD_W(RTYPE, psrc + stride); \ +} while (0) +#define LD_UW2(...) LD_W2(v4u32, __VA_ARGS__) +#define LD_SW2(...) LD_W2(v4i32, __VA_ARGS__) + +#define LD_W3(RTYPE, psrc, stride, out0, out1, out2) do { \ + LD_W2(RTYPE, psrc, stride, out0, out1); \ + out2 = LD_W(RTYPE, psrc + 2 * stride); \ +} while (0) +#define LD_UW3(...) LD_W3(v4u32, __VA_ARGS__) +#define LD_SW3(...) LD_W3(v4i32, __VA_ARGS__) + +#define LD_W4(RTYPE, psrc, stride, out0, out1, out2, out3) do { \ + LD_W2(RTYPE, psrc, stride, out0, out1); \ + LD_W2(RTYPE, psrc + 2 * stride, stride, out2, out3); \ +} while (0) +#define LD_UW4(...) LD_W4(v4u32, __VA_ARGS__) +#define LD_SW4(...) LD_W4(v4i32, __VA_ARGS__) + +/* Description : Store vectors of 16 byte elements with stride + * Arguments : Inputs - in0, in1, pdst, stride + * Details : Store 16 byte elements from 'in0' to (pdst) + * Store 16 byte elements from 'in1' to (pdst + stride) + */ +#define ST_B2(RTYPE, in0, in1, pdst, stride) do { \ + ST_B(RTYPE, in0, pdst); \ + ST_B(RTYPE, in1, pdst + stride); \ +} while (0) +#define ST_UB2(...) ST_B2(v16u8, __VA_ARGS__) +#define ST_SB2(...) ST_B2(v16i8, __VA_ARGS__) + +#define ST_B4(RTYPE, in0, in1, in2, in3, pdst, stride) do { \ + ST_B2(RTYPE, in0, in1, pdst, stride); \ + ST_B2(RTYPE, in2, in3, pdst + 2 * stride, stride); \ +} while (0) +#define ST_UB4(...) ST_B4(v16u8, __VA_ARGS__) +#define ST_SB4(...) ST_B4(v16i8, __VA_ARGS__) + +#define ST_B8(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ + pdst, stride) do { \ + ST_B4(RTYPE, in0, in1, in2, in3, pdst, stride); \ + ST_B4(RTYPE, in4, in5, in6, in7, pdst + 4 * stride, stride); \ +} while (0) +#define ST_UB8(...) ST_B8(v16u8, __VA_ARGS__) + +/* Description : Store vectors of 4 word elements with stride + * Arguments : Inputs - in0, in1, in2, in3, pdst, stride + * Details : Store 4 word elements from 'in0' to (pdst + 0 * stride) + * Store 4 word elements from 'in1' to (pdst + 1 * stride) + * Store 4 word elements from 'in2' to (pdst + 2 * stride) + * Store 4 word elements from 'in3' to (pdst + 3 * stride) + */ +#define ST_W2(RTYPE, in0, in1, pdst, stride) do { \ + ST_W(RTYPE, in0, pdst); \ + ST_W(RTYPE, in1, pdst + stride); \ +} while (0) +#define ST_UW2(...) ST_W2(v4u32, __VA_ARGS__) +#define ST_SW2(...) ST_W2(v4i32, __VA_ARGS__) + +#define ST_W3(RTYPE, in0, in1, in2, pdst, stride) do { \ + ST_W2(RTYPE, in0, in1, pdst, stride); \ + ST_W(RTYPE, in2, pdst + 2 * stride); \ +} while (0) +#define ST_UW3(...) ST_W3(v4u32, __VA_ARGS__) +#define ST_SW3(...) ST_W3(v4i32, __VA_ARGS__) + +#define ST_W4(RTYPE, in0, in1, in2, in3, pdst, stride) do { \ + ST_W2(RTYPE, in0, in1, pdst, stride); \ + ST_W2(RTYPE, in2, in3, pdst + 2 * stride, stride); \ +} while (0) +#define ST_UW4(...) ST_W4(v4u32, __VA_ARGS__) +#define ST_SW4(...) ST_W4(v4i32, __VA_ARGS__) + +/* Description : Store vectors of 8 halfword elements with stride + * Arguments : Inputs - in0, in1, pdst, stride + * Details : Store 8 halfword elements from 'in0' to (pdst) + * Store 8 halfword elements from 'in1' to (pdst + stride) + */ +#define ST_H2(RTYPE, in0, in1, pdst, stride) do { \ + ST_H(RTYPE, in0, pdst); \ + ST_H(RTYPE, in1, pdst + stride); \ +} while (0) +#define ST_UH2(...) ST_H2(v8u16, __VA_ARGS__) +#define ST_SH2(...) ST_H2(v8i16, __VA_ARGS__) + +/* Description : Store 2x4 byte block to destination memory from input vector + * Arguments : Inputs - in, stidx, pdst, stride + * Details : Index 'stidx' halfword element from 'in' vector is copied to + * the GP register and stored to (pdst) + * Index 'stidx+1' halfword element from 'in' vector is copied to + * the GP register and stored to (pdst + stride) + * Index 'stidx+2' halfword element from 'in' vector is copied to + * the GP register and stored to (pdst + 2 * stride) + * Index 'stidx+3' halfword element from 'in' vector is copied to + * the GP register and stored to (pdst + 3 * stride) + */ +#define ST2x4_UB(in, stidx, pdst, stride) do { \ + uint8_t* pblk_2x4_m = (uint8_t*)pdst; \ + const uint16_t out0_m = __msa_copy_s_h((v8i16)in, stidx); \ + const uint16_t out1_m = __msa_copy_s_h((v8i16)in, stidx + 1); \ + const uint16_t out2_m = __msa_copy_s_h((v8i16)in, stidx + 2); \ + const uint16_t out3_m = __msa_copy_s_h((v8i16)in, stidx + 3); \ + SH(out0_m, pblk_2x4_m); \ + pblk_2x4_m += stride; \ + SH(out1_m, pblk_2x4_m); \ + pblk_2x4_m += stride; \ + SH(out2_m, pblk_2x4_m); \ + pblk_2x4_m += stride; \ + SH(out3_m, pblk_2x4_m); \ +} while (0) + +/* Description : Store 4x4 byte block to destination memory from input vector + * Arguments : Inputs - in0, in1, pdst, stride + * Details : 'Idx0' word element from input vector 'in0' is copied to the + * GP register and stored to (pdst) + * 'Idx1' word element from input vector 'in0' is copied to the + * GP register and stored to (pdst + stride) + * 'Idx2' word element from input vector 'in0' is copied to the + * GP register and stored to (pdst + 2 * stride) + * 'Idx3' word element from input vector 'in0' is copied to the + * GP register and stored to (pdst + 3 * stride) + */ +#define ST4x4_UB(in0, in1, idx0, idx1, idx2, idx3, pdst, stride) do { \ + uint8_t* const pblk_4x4_m = (uint8_t*)pdst; \ + const uint32_t out0_m = __msa_copy_s_w((v4i32)in0, idx0); \ + const uint32_t out1_m = __msa_copy_s_w((v4i32)in0, idx1); \ + const uint32_t out2_m = __msa_copy_s_w((v4i32)in1, idx2); \ + const uint32_t out3_m = __msa_copy_s_w((v4i32)in1, idx3); \ + SW4(out0_m, out1_m, out2_m, out3_m, pblk_4x4_m, stride); \ +} while (0) + +#define ST4x8_UB(in0, in1, pdst, stride) do { \ + uint8_t* const pblk_4x8 = (uint8_t*)pdst; \ + ST4x4_UB(in0, in0, 0, 1, 2, 3, pblk_4x8, stride); \ + ST4x4_UB(in1, in1, 0, 1, 2, 3, pblk_4x8 + 4 * stride, stride); \ +} while (0) + +/* Description : Immediate number of elements to slide + * Arguments : Inputs - in0, in1, slide_val + * Outputs - out + * Return Type - as per RTYPE + * Details : Byte elements from 'in1' vector are slid into 'in0' by + * value specified in the 'slide_val' + */ +#define SLDI_B(RTYPE, in0, in1, slide_val) \ + (RTYPE)__msa_sldi_b((v16i8)in0, (v16i8)in1, slide_val) \ + +#define SLDI_UB(...) SLDI_B(v16u8, __VA_ARGS__) +#define SLDI_SB(...) SLDI_B(v16i8, __VA_ARGS__) +#define SLDI_SH(...) SLDI_B(v8i16, __VA_ARGS__) + +/* Description : Shuffle byte vector elements as per mask vector + * Arguments : Inputs - in0, in1, in2, in3, mask0, mask1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Byte elements from 'in0' & 'in1' are copied selectively to + * 'out0' as per control vector 'mask0' + */ +#define VSHF_B(RTYPE, in0, in1, mask) \ + (RTYPE)__msa_vshf_b((v16i8)mask, (v16i8)in1, (v16i8)in0) + +#define VSHF_UB(...) VSHF_B(v16u8, __VA_ARGS__) +#define VSHF_SB(...) VSHF_B(v16i8, __VA_ARGS__) +#define VSHF_UH(...) VSHF_B(v8u16, __VA_ARGS__) +#define VSHF_SH(...) VSHF_B(v8i16, __VA_ARGS__) + +#define VSHF_B2(RTYPE, in0, in1, in2, in3, mask0, mask1, out0, out1) do { \ + out0 = VSHF_B(RTYPE, in0, in1, mask0); \ + out1 = VSHF_B(RTYPE, in2, in3, mask1); \ +} while (0) +#define VSHF_B2_UB(...) VSHF_B2(v16u8, __VA_ARGS__) +#define VSHF_B2_SB(...) VSHF_B2(v16i8, __VA_ARGS__) +#define VSHF_B2_UH(...) VSHF_B2(v8u16, __VA_ARGS__) +#define VSHF_B2_SH(...) VSHF_B2(v8i16, __VA_ARGS__) + +/* Description : Shuffle halfword vector elements as per mask vector + * Arguments : Inputs - in0, in1, in2, in3, mask0, mask1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : halfword elements from 'in0' & 'in1' are copied selectively to + * 'out0' as per control vector 'mask0' + */ +#define VSHF_H2(RTYPE, in0, in1, in2, in3, mask0, mask1, out0, out1) do { \ + out0 = (RTYPE)__msa_vshf_h((v8i16)mask0, (v8i16)in1, (v8i16)in0); \ + out1 = (RTYPE)__msa_vshf_h((v8i16)mask1, (v8i16)in3, (v8i16)in2); \ +} while (0) +#define VSHF_H2_UH(...) VSHF_H2(v8u16, __VA_ARGS__) +#define VSHF_H2_SH(...) VSHF_H2(v8i16, __VA_ARGS__) + +/* Description : Dot product of byte vector elements + * Arguments : Inputs - mult0, mult1, cnst0, cnst1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Signed byte elements from 'mult0' are multiplied with + * signed byte elements from 'cnst0' producing a result + * twice the size of input i.e. signed halfword. + * The multiplication result of adjacent odd-even elements + * are added together and written to the 'out0' vector +*/ +#define DOTP_SB2(RTYPE, mult0, mult1, cnst0, cnst1, out0, out1) do { \ + out0 = (RTYPE)__msa_dotp_s_h((v16i8)mult0, (v16i8)cnst0); \ + out1 = (RTYPE)__msa_dotp_s_h((v16i8)mult1, (v16i8)cnst1); \ +} while (0) +#define DOTP_SB2_SH(...) DOTP_SB2(v8i16, __VA_ARGS__) + +/* Description : Dot product of halfword vector elements + * Arguments : Inputs - mult0, mult1, cnst0, cnst1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Signed halfword elements from 'mult0' are multiplied with + * signed halfword elements from 'cnst0' producing a result + * twice the size of input i.e. signed word. + * The multiplication result of adjacent odd-even elements + * are added together and written to the 'out0' vector + */ +#define DOTP_SH2(RTYPE, mult0, mult1, cnst0, cnst1, out0, out1) do { \ + out0 = (RTYPE)__msa_dotp_s_w((v8i16)mult0, (v8i16)cnst0); \ + out1 = (RTYPE)__msa_dotp_s_w((v8i16)mult1, (v8i16)cnst1); \ +} while (0) +#define DOTP_SH2_SW(...) DOTP_SH2(v4i32, __VA_ARGS__) + +/* Description : Dot product of unsigned word vector elements + * Arguments : Inputs - mult0, mult1, cnst0, cnst1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Unsigned word elements from 'mult0' are multiplied with + * unsigned word elements from 'cnst0' producing a result + * twice the size of input i.e. unsigned double word. + * The multiplication result of adjacent odd-even elements + * are added together and written to the 'out0' vector + */ +#define DOTP_UW2(RTYPE, mult0, mult1, cnst0, cnst1, out0, out1) do { \ + out0 = (RTYPE)__msa_dotp_u_d((v4u32)mult0, (v4u32)cnst0); \ + out1 = (RTYPE)__msa_dotp_u_d((v4u32)mult1, (v4u32)cnst1); \ +} while (0) +#define DOTP_UW2_UD(...) DOTP_UW2(v2u64, __VA_ARGS__) + +/* Description : Dot product & addition of halfword vector elements + * Arguments : Inputs - mult0, mult1, cnst0, cnst1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Signed halfword elements from 'mult0' are multiplied with + * signed halfword elements from 'cnst0' producing a result + * twice the size of input i.e. signed word. + * The multiplication result of adjacent odd-even elements + * are added to the 'out0' vector + */ +#define DPADD_SH2(RTYPE, mult0, mult1, cnst0, cnst1, out0, out1) do { \ + out0 = (RTYPE)__msa_dpadd_s_w((v4i32)out0, (v8i16)mult0, (v8i16)cnst0); \ + out1 = (RTYPE)__msa_dpadd_s_w((v4i32)out1, (v8i16)mult1, (v8i16)cnst1); \ +} while (0) +#define DPADD_SH2_SW(...) DPADD_SH2(v4i32, __VA_ARGS__) + +/* Description : Clips all signed halfword elements of input vector + * between 0 & 255 + * Arguments : Input/output - val + * Return Type - signed halfword + */ +#define CLIP_SH_0_255(val) do { \ + const v8i16 max_m = __msa_ldi_h(255); \ + val = __msa_maxi_s_h((v8i16)val, 0); \ + val = __msa_min_s_h(max_m, (v8i16)val); \ +} while (0) + +#define CLIP_SH2_0_255(in0, in1) do { \ + CLIP_SH_0_255(in0); \ + CLIP_SH_0_255(in1); \ +} while (0) + +#define CLIP_SH4_0_255(in0, in1, in2, in3) do { \ + CLIP_SH2_0_255(in0, in1); \ + CLIP_SH2_0_255(in2, in3); \ +} while (0) + +/* Description : Clips all unsigned halfword elements of input vector + * between 0 & 255 + * Arguments : Input - in + * Output - out_m + * Return Type - unsigned halfword + */ +#define CLIP_UH_0_255(in) do { \ + const v8u16 max_m = (v8u16)__msa_ldi_h(255); \ + in = __msa_maxi_u_h((v8u16) in, 0); \ + in = __msa_min_u_h((v8u16) max_m, (v8u16) in); \ +} while (0) + +#define CLIP_UH2_0_255(in0, in1) do { \ + CLIP_UH_0_255(in0); \ + CLIP_UH_0_255(in1); \ +} while (0) + +/* Description : Clips all signed word elements of input vector + * between 0 & 255 + * Arguments : Input/output - val + * Return Type - signed word + */ +#define CLIP_SW_0_255(val) do { \ + const v4i32 max_m = __msa_ldi_w(255); \ + val = __msa_maxi_s_w((v4i32)val, 0); \ + val = __msa_min_s_w(max_m, (v4i32)val); \ +} while (0) + +#define CLIP_SW4_0_255(in0, in1, in2, in3) do { \ + CLIP_SW_0_255(in0); \ + CLIP_SW_0_255(in1); \ + CLIP_SW_0_255(in2); \ + CLIP_SW_0_255(in3); \ +} while (0) + +/* Description : Horizontal addition of 4 signed word elements of input vector + * Arguments : Input - in (signed word vector) + * Output - sum_m (i32 sum) + * Return Type - signed word (GP) + * Details : 4 signed word elements of 'in' vector are added together and + * the resulting integer sum is returned + */ +static WEBP_INLINE int32_t func_hadd_sw_s32(v4i32 in) { + const v2i64 res0_m = __msa_hadd_s_d((v4i32)in, (v4i32)in); + const v2i64 res1_m = __msa_splati_d(res0_m, 1); + const v2i64 out = res0_m + res1_m; + int32_t sum_m = __msa_copy_s_w((v4i32)out, 0); + return sum_m; +} +#define HADD_SW_S32(in) func_hadd_sw_s32(in) + +/* Description : Horizontal addition of 8 signed halfword elements + * Arguments : Input - in (signed halfword vector) + * Output - sum_m (s32 sum) + * Return Type - signed word + * Details : 8 signed halfword elements of input vector are added + * together and the resulting integer sum is returned + */ +static WEBP_INLINE int32_t func_hadd_sh_s32(v8i16 in) { + const v4i32 res = __msa_hadd_s_w(in, in); + const v2i64 res0 = __msa_hadd_s_d(res, res); + const v2i64 res1 = __msa_splati_d(res0, 1); + const v2i64 res2 = res0 + res1; + const int32_t sum_m = __msa_copy_s_w((v4i32)res2, 0); + return sum_m; +} +#define HADD_SH_S32(in) func_hadd_sh_s32(in) + +/* Description : Horizontal addition of 8 unsigned halfword elements + * Arguments : Input - in (unsigned halfword vector) + * Output - sum_m (u32 sum) + * Return Type - unsigned word + * Details : 8 unsigned halfword elements of input vector are added + * together and the resulting integer sum is returned + */ +static WEBP_INLINE uint32_t func_hadd_uh_u32(v8u16 in) { + uint32_t sum_m; + const v4u32 res_m = __msa_hadd_u_w(in, in); + v2u64 res0_m = __msa_hadd_u_d(res_m, res_m); + v2u64 res1_m = (v2u64)__msa_splati_d((v2i64)res0_m, 1); + res0_m = res0_m + res1_m; + sum_m = __msa_copy_s_w((v4i32)res0_m, 0); + return sum_m; +} +#define HADD_UH_U32(in) func_hadd_uh_u32(in) + +/* Description : Horizontal addition of signed half word vector elements + Arguments : Inputs - in0, in1 + Outputs - out0, out1 + Return Type - as per RTYPE + Details : Each signed odd half word element from 'in0' is added to + even signed half word element from 'in0' (pairwise) and the + halfword result is written in 'out0' +*/ +#define HADD_SH2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_hadd_s_w((v8i16)in0, (v8i16)in0); \ + out1 = (RTYPE)__msa_hadd_s_w((v8i16)in1, (v8i16)in1); \ +} while (0) +#define HADD_SH2_SW(...) HADD_SH2(v4i32, __VA_ARGS__) + +#define HADD_SH4(RTYPE, in0, in1, in2, in3, out0, out1, out2, out3) do { \ + HADD_SH2(RTYPE, in0, in1, out0, out1); \ + HADD_SH2(RTYPE, in2, in3, out2, out3); \ +} while (0) +#define HADD_SH4_SW(...) HADD_SH4(v4i32, __VA_ARGS__) + +/* Description : Horizontal subtraction of unsigned byte vector elements + * Arguments : Inputs - in0, in1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Each unsigned odd byte element from 'in0' is subtracted from + * even unsigned byte element from 'in0' (pairwise) and the + * halfword result is written to 'out0' + */ +#define HSUB_UB2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_hsub_u_h((v16u8)in0, (v16u8)in0); \ + out1 = (RTYPE)__msa_hsub_u_h((v16u8)in1, (v16u8)in1); \ +} while (0) +#define HSUB_UB2_UH(...) HSUB_UB2(v8u16, __VA_ARGS__) +#define HSUB_UB2_SH(...) HSUB_UB2(v8i16, __VA_ARGS__) +#define HSUB_UB2_SW(...) HSUB_UB2(v4i32, __VA_ARGS__) + +/* Description : Set element n input vector to GPR value + * Arguments : Inputs - in0, in1, in2, in3 + * Output - out + * Return Type - as per RTYPE + * Details : Set element 0 in vector 'out' to value specified in 'in0' + */ +#define INSERT_W2(RTYPE, in0, in1, out) do { \ + out = (RTYPE)__msa_insert_w((v4i32)out, 0, in0); \ + out = (RTYPE)__msa_insert_w((v4i32)out, 1, in1); \ +} while (0) +#define INSERT_W2_UB(...) INSERT_W2(v16u8, __VA_ARGS__) +#define INSERT_W2_SB(...) INSERT_W2(v16i8, __VA_ARGS__) + +#define INSERT_W4(RTYPE, in0, in1, in2, in3, out) do { \ + out = (RTYPE)__msa_insert_w((v4i32)out, 0, in0); \ + out = (RTYPE)__msa_insert_w((v4i32)out, 1, in1); \ + out = (RTYPE)__msa_insert_w((v4i32)out, 2, in2); \ + out = (RTYPE)__msa_insert_w((v4i32)out, 3, in3); \ +} while (0) +#define INSERT_W4_UB(...) INSERT_W4(v16u8, __VA_ARGS__) +#define INSERT_W4_SB(...) INSERT_W4(v16i8, __VA_ARGS__) +#define INSERT_W4_SW(...) INSERT_W4(v4i32, __VA_ARGS__) + +/* Description : Set element n of double word input vector to GPR value + * Arguments : Inputs - in0, in1 + * Output - out + * Return Type - as per RTYPE + * Details : Set element 0 in vector 'out' to GPR value specified in 'in0' + * Set element 1 in vector 'out' to GPR value specified in 'in1' + */ +#define INSERT_D2(RTYPE, in0, in1, out) do { \ + out = (RTYPE)__msa_insert_d((v2i64)out, 0, in0); \ + out = (RTYPE)__msa_insert_d((v2i64)out, 1, in1); \ +} while (0) +#define INSERT_D2_UB(...) INSERT_D2(v16u8, __VA_ARGS__) +#define INSERT_D2_SB(...) INSERT_D2(v16i8, __VA_ARGS__) + +/* Description : Interleave even byte elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even byte elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVEV_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_b((v16i8)in1, (v16i8)in0); \ + out1 = (RTYPE)__msa_ilvev_b((v16i8)in3, (v16i8)in2); \ +} while (0) +#define ILVEV_B2_UB(...) ILVEV_B2(v16u8, __VA_ARGS__) +#define ILVEV_B2_SB(...) ILVEV_B2(v16i8, __VA_ARGS__) +#define ILVEV_B2_UH(...) ILVEV_B2(v8u16, __VA_ARGS__) +#define ILVEV_B2_SH(...) ILVEV_B2(v8i16, __VA_ARGS__) +#define ILVEV_B2_SD(...) ILVEV_B2(v2i64, __VA_ARGS__) + +/* Description : Interleave odd byte elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Odd byte elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVOD_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvod_b((v16i8)in1, (v16i8)in0); \ + out1 = (RTYPE)__msa_ilvod_b((v16i8)in3, (v16i8)in2); \ +} while (0) +#define ILVOD_B2_UB(...) ILVOD_B2(v16u8, __VA_ARGS__) +#define ILVOD_B2_SB(...) ILVOD_B2(v16i8, __VA_ARGS__) +#define ILVOD_B2_UH(...) ILVOD_B2(v8u16, __VA_ARGS__) +#define ILVOD_B2_SH(...) ILVOD_B2(v8i16, __VA_ARGS__) +#define ILVOD_B2_SD(...) ILVOD_B2(v2i64, __VA_ARGS__) + +/* Description : Interleave even halfword elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even halfword elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVEV_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_h((v8i16)in1, (v8i16)in0); \ + out1 = (RTYPE)__msa_ilvev_h((v8i16)in3, (v8i16)in2); \ +} while (0) +#define ILVEV_H2_UB(...) ILVEV_H2(v16u8, __VA_ARGS__) +#define ILVEV_H2_UH(...) ILVEV_H2(v8u16, __VA_ARGS__) +#define ILVEV_H2_SH(...) ILVEV_H2(v8i16, __VA_ARGS__) +#define ILVEV_H2_SW(...) ILVEV_H2(v4i32, __VA_ARGS__) + +/* Description : Interleave odd halfword elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Odd halfword elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVOD_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvod_h((v8i16)in1, (v8i16)in0); \ + out1 = (RTYPE)__msa_ilvod_h((v8i16)in3, (v8i16)in2); \ +} while (0) +#define ILVOD_H2_UB(...) ILVOD_H2(v16u8, __VA_ARGS__) +#define ILVOD_H2_UH(...) ILVOD_H2(v8u16, __VA_ARGS__) +#define ILVOD_H2_SH(...) ILVOD_H2(v8i16, __VA_ARGS__) +#define ILVOD_H2_SW(...) ILVOD_H2(v4i32, __VA_ARGS__) + +/* Description : Interleave even word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even word elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVEV_W2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_w((v4i32)in1, (v4i32)in0); \ + out1 = (RTYPE)__msa_ilvev_w((v4i32)in3, (v4i32)in2); \ +} while (0) +#define ILVEV_W2_UB(...) ILVEV_W2(v16u8, __VA_ARGS__) +#define ILVEV_W2_SB(...) ILVEV_W2(v16i8, __VA_ARGS__) +#define ILVEV_W2_UH(...) ILVEV_W2(v8u16, __VA_ARGS__) +#define ILVEV_W2_SD(...) ILVEV_W2(v2i64, __VA_ARGS__) + +/* Description : Interleave even-odd word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even word elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + * Odd word elements of 'in2' and 'in3' are interleaved + * and written to 'out1' + */ +#define ILVEVOD_W2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_w((v4i32)in1, (v4i32)in0); \ + out1 = (RTYPE)__msa_ilvod_w((v4i32)in3, (v4i32)in2); \ +} while (0) +#define ILVEVOD_W2_UB(...) ILVEVOD_W2(v16u8, __VA_ARGS__) +#define ILVEVOD_W2_UH(...) ILVEVOD_W2(v8u16, __VA_ARGS__) +#define ILVEVOD_W2_SH(...) ILVEVOD_W2(v8i16, __VA_ARGS__) +#define ILVEVOD_W2_SW(...) ILVEVOD_W2(v4i32, __VA_ARGS__) + +/* Description : Interleave even-odd half-word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even half-word elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + * Odd half-word elements of 'in2' and 'in3' are interleaved + * and written to 'out1' + */ +#define ILVEVOD_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_h((v8i16)in1, (v8i16)in0); \ + out1 = (RTYPE)__msa_ilvod_h((v8i16)in3, (v8i16)in2); \ +} while (0) +#define ILVEVOD_H2_UB(...) ILVEVOD_H2(v16u8, __VA_ARGS__) +#define ILVEVOD_H2_UH(...) ILVEVOD_H2(v8u16, __VA_ARGS__) +#define ILVEVOD_H2_SH(...) ILVEVOD_H2(v8i16, __VA_ARGS__) +#define ILVEVOD_H2_SW(...) ILVEVOD_H2(v4i32, __VA_ARGS__) + +/* Description : Interleave even double word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even double word elements of 'in0' and 'in1' are interleaved + * and written to 'out0' + */ +#define ILVEV_D2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvev_d((v2i64)in1, (v2i64)in0); \ + out1 = (RTYPE)__msa_ilvev_d((v2i64)in3, (v2i64)in2); \ +} while (0) +#define ILVEV_D2_UB(...) ILVEV_D2(v16u8, __VA_ARGS__) +#define ILVEV_D2_SB(...) ILVEV_D2(v16i8, __VA_ARGS__) +#define ILVEV_D2_SW(...) ILVEV_D2(v4i32, __VA_ARGS__) +#define ILVEV_D2_SD(...) ILVEV_D2(v2i64, __VA_ARGS__) + +/* Description : Interleave left half of byte elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Left half of byte elements of 'in0' and 'in1' are interleaved + * and written to 'out0'. + */ +#define ILVL_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvl_b((v16i8)in0, (v16i8)in1); \ + out1 = (RTYPE)__msa_ilvl_b((v16i8)in2, (v16i8)in3); \ +} while (0) +#define ILVL_B2_UB(...) ILVL_B2(v16u8, __VA_ARGS__) +#define ILVL_B2_SB(...) ILVL_B2(v16i8, __VA_ARGS__) +#define ILVL_B2_UH(...) ILVL_B2(v8u16, __VA_ARGS__) +#define ILVL_B2_SH(...) ILVL_B2(v8i16, __VA_ARGS__) +#define ILVL_B2_SW(...) ILVL_B2(v4i32, __VA_ARGS__) + +/* Description : Interleave right half of byte elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Right half of byte elements of 'in0' and 'in1' are interleaved + * and written to out0. + */ +#define ILVR_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_b((v16i8)in0, (v16i8)in1); \ + out1 = (RTYPE)__msa_ilvr_b((v16i8)in2, (v16i8)in3); \ +} while (0) +#define ILVR_B2_UB(...) ILVR_B2(v16u8, __VA_ARGS__) +#define ILVR_B2_SB(...) ILVR_B2(v16i8, __VA_ARGS__) +#define ILVR_B2_UH(...) ILVR_B2(v8u16, __VA_ARGS__) +#define ILVR_B2_SH(...) ILVR_B2(v8i16, __VA_ARGS__) +#define ILVR_B2_SW(...) ILVR_B2(v4i32, __VA_ARGS__) + +#define ILVR_B4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + ILVR_B2(RTYPE, in0, in1, in2, in3, out0, out1); \ + ILVR_B2(RTYPE, in4, in5, in6, in7, out2, out3); \ +} while (0) +#define ILVR_B4_UB(...) ILVR_B4(v16u8, __VA_ARGS__) +#define ILVR_B4_SB(...) ILVR_B4(v16i8, __VA_ARGS__) +#define ILVR_B4_UH(...) ILVR_B4(v8u16, __VA_ARGS__) +#define ILVR_B4_SH(...) ILVR_B4(v8i16, __VA_ARGS__) +#define ILVR_B4_SW(...) ILVR_B4(v4i32, __VA_ARGS__) + +/* Description : Interleave right half of halfword elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Right half of halfword elements of 'in0' and 'in1' are + * interleaved and written to 'out0'. + */ +#define ILVR_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_h((v8i16)in0, (v8i16)in1); \ + out1 = (RTYPE)__msa_ilvr_h((v8i16)in2, (v8i16)in3); \ +} while (0) +#define ILVR_H2_UB(...) ILVR_H2(v16u8, __VA_ARGS__) +#define ILVR_H2_SH(...) ILVR_H2(v8i16, __VA_ARGS__) +#define ILVR_H2_SW(...) ILVR_H2(v4i32, __VA_ARGS__) + +#define ILVR_H4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + ILVR_H2(RTYPE, in0, in1, in2, in3, out0, out1); \ + ILVR_H2(RTYPE, in4, in5, in6, in7, out2, out3); \ +} while (0) +#define ILVR_H4_UB(...) ILVR_H4(v16u8, __VA_ARGS__) +#define ILVR_H4_SH(...) ILVR_H4(v8i16, __VA_ARGS__) +#define ILVR_H4_SW(...) ILVR_H4(v4i32, __VA_ARGS__) + +/* Description : Interleave right half of double word elements from vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Right half of double word elements of 'in0' and 'in1' are + * interleaved and written to 'out0'. + */ +#define ILVR_D2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_d((v2i64)in0, (v2i64)in1); \ + out1 = (RTYPE)__msa_ilvr_d((v2i64)in2, (v2i64)in3); \ +} while (0) +#define ILVR_D2_UB(...) ILVR_D2(v16u8, __VA_ARGS__) +#define ILVR_D2_SB(...) ILVR_D2(v16i8, __VA_ARGS__) +#define ILVR_D2_SH(...) ILVR_D2(v8i16, __VA_ARGS__) + +#define ILVR_D4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + ILVR_D2(RTYPE, in0, in1, in2, in3, out0, out1); \ + ILVR_D2(RTYPE, in4, in5, in6, in7, out2, out3); \ +} while (0) +#define ILVR_D4_SB(...) ILVR_D4(v16i8, __VA_ARGS__) +#define ILVR_D4_UB(...) ILVR_D4(v16u8, __VA_ARGS__) + +/* Description : Interleave both left and right half of input vectors + * Arguments : Inputs - in0, in1 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Right half of byte elements from 'in0' and 'in1' are + * interleaved and written to 'out0' + */ +#define ILVRL_B2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_b((v16i8)in0, (v16i8)in1); \ + out1 = (RTYPE)__msa_ilvl_b((v16i8)in0, (v16i8)in1); \ +} while (0) +#define ILVRL_B2_UB(...) ILVRL_B2(v16u8, __VA_ARGS__) +#define ILVRL_B2_SB(...) ILVRL_B2(v16i8, __VA_ARGS__) +#define ILVRL_B2_UH(...) ILVRL_B2(v8u16, __VA_ARGS__) +#define ILVRL_B2_SH(...) ILVRL_B2(v8i16, __VA_ARGS__) +#define ILVRL_B2_SW(...) ILVRL_B2(v4i32, __VA_ARGS__) + +#define ILVRL_H2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_h((v8i16)in0, (v8i16)in1); \ + out1 = (RTYPE)__msa_ilvl_h((v8i16)in0, (v8i16)in1); \ +} while (0) +#define ILVRL_H2_UB(...) ILVRL_H2(v16u8, __VA_ARGS__) +#define ILVRL_H2_SB(...) ILVRL_H2(v16i8, __VA_ARGS__) +#define ILVRL_H2_SH(...) ILVRL_H2(v8i16, __VA_ARGS__) +#define ILVRL_H2_SW(...) ILVRL_H2(v4i32, __VA_ARGS__) +#define ILVRL_H2_UW(...) ILVRL_H2(v4u32, __VA_ARGS__) + +#define ILVRL_W2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_ilvr_w((v4i32)in0, (v4i32)in1); \ + out1 = (RTYPE)__msa_ilvl_w((v4i32)in0, (v4i32)in1); \ +} while (0) +#define ILVRL_W2_UB(...) ILVRL_W2(v16u8, __VA_ARGS__) +#define ILVRL_W2_SH(...) ILVRL_W2(v8i16, __VA_ARGS__) +#define ILVRL_W2_SW(...) ILVRL_W2(v4i32, __VA_ARGS__) +#define ILVRL_W2_UW(...) ILVRL_W2(v4u32, __VA_ARGS__) + +/* Description : Pack even byte elements of vector pairs + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even byte elements of 'in0' are copied to the left half of + * 'out0' & even byte elements of 'in1' are copied to the right + * half of 'out0'. + */ +#define PCKEV_B2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_pckev_b((v16i8)in0, (v16i8)in1); \ + out1 = (RTYPE)__msa_pckev_b((v16i8)in2, (v16i8)in3); \ +} while (0) +#define PCKEV_B2_SB(...) PCKEV_B2(v16i8, __VA_ARGS__) +#define PCKEV_B2_UB(...) PCKEV_B2(v16u8, __VA_ARGS__) +#define PCKEV_B2_SH(...) PCKEV_B2(v8i16, __VA_ARGS__) +#define PCKEV_B2_SW(...) PCKEV_B2(v4i32, __VA_ARGS__) + +#define PCKEV_B4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + PCKEV_B2(RTYPE, in0, in1, in2, in3, out0, out1); \ + PCKEV_B2(RTYPE, in4, in5, in6, in7, out2, out3); \ +} while (0) +#define PCKEV_B4_SB(...) PCKEV_B4(v16i8, __VA_ARGS__) +#define PCKEV_B4_UB(...) PCKEV_B4(v16u8, __VA_ARGS__) +#define PCKEV_B4_SH(...) PCKEV_B4(v8i16, __VA_ARGS__) +#define PCKEV_B4_SW(...) PCKEV_B4(v4i32, __VA_ARGS__) + +/* Description : Pack even halfword elements of vector pairs + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even halfword elements of 'in0' are copied to the left half of + * 'out0' & even halfword elements of 'in1' are copied to the + * right half of 'out0'. + */ +#define PCKEV_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_pckev_h((v8i16)in0, (v8i16)in1); \ + out1 = (RTYPE)__msa_pckev_h((v8i16)in2, (v8i16)in3); \ +} while (0) +#define PCKEV_H2_UH(...) PCKEV_H2(v8u16, __VA_ARGS__) +#define PCKEV_H2_SH(...) PCKEV_H2(v8i16, __VA_ARGS__) +#define PCKEV_H2_SW(...) PCKEV_H2(v4i32, __VA_ARGS__) +#define PCKEV_H2_UW(...) PCKEV_H2(v4u32, __VA_ARGS__) + +/* Description : Pack even word elements of vector pairs + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Even word elements of 'in0' are copied to the left half of + * 'out0' & even word elements of 'in1' are copied to the + * right half of 'out0'. + */ +#define PCKEV_W2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_pckev_w((v4i32)in0, (v4i32)in1); \ + out1 = (RTYPE)__msa_pckev_w((v4i32)in2, (v4i32)in3); \ +} while (0) +#define PCKEV_W2_UH(...) PCKEV_W2(v8u16, __VA_ARGS__) +#define PCKEV_W2_SH(...) PCKEV_W2(v8i16, __VA_ARGS__) +#define PCKEV_W2_SW(...) PCKEV_W2(v4i32, __VA_ARGS__) +#define PCKEV_W2_UW(...) PCKEV_W2(v4u32, __VA_ARGS__) + +/* Description : Pack odd halfword elements of vector pairs + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Odd halfword elements of 'in0' are copied to the left half of + * 'out0' & odd halfword elements of 'in1' are copied to the + * right half of 'out0'. + */ +#define PCKOD_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_pckod_h((v8i16)in0, (v8i16)in1); \ + out1 = (RTYPE)__msa_pckod_h((v8i16)in2, (v8i16)in3); \ +} while (0) +#define PCKOD_H2_UH(...) PCKOD_H2(v8u16, __VA_ARGS__) +#define PCKOD_H2_SH(...) PCKOD_H2(v8i16, __VA_ARGS__) +#define PCKOD_H2_SW(...) PCKOD_H2(v4i32, __VA_ARGS__) +#define PCKOD_H2_UW(...) PCKOD_H2(v4u32, __VA_ARGS__) + +/* Description : Arithmetic immediate shift right all elements of word vector + * Arguments : Inputs - in0, in1, shift + * Outputs - in place operation + * Return Type - as per input vector RTYPE + * Details : Each element of vector 'in0' is right shifted by 'shift' and + * the result is written in-place. 'shift' is a GP variable. + */ +#define SRAI_W2(RTYPE, in0, in1, shift_val) do { \ + in0 = (RTYPE)SRAI_W(in0, shift_val); \ + in1 = (RTYPE)SRAI_W(in1, shift_val); \ +} while (0) +#define SRAI_W2_SW(...) SRAI_W2(v4i32, __VA_ARGS__) +#define SRAI_W2_UW(...) SRAI_W2(v4u32, __VA_ARGS__) + +#define SRAI_W4(RTYPE, in0, in1, in2, in3, shift_val) do { \ + SRAI_W2(RTYPE, in0, in1, shift_val); \ + SRAI_W2(RTYPE, in2, in3, shift_val); \ +} while (0) +#define SRAI_W4_SW(...) SRAI_W4(v4i32, __VA_ARGS__) +#define SRAI_W4_UW(...) SRAI_W4(v4u32, __VA_ARGS__) + +/* Description : Arithmetic shift right all elements of half-word vector + * Arguments : Inputs - in0, in1, shift + * Outputs - in place operation + * Return Type - as per input vector RTYPE + * Details : Each element of vector 'in0' is right shifted by 'shift' and + * the result is written in-place. 'shift' is a GP variable. + */ +#define SRAI_H2(RTYPE, in0, in1, shift_val) do { \ + in0 = (RTYPE)SRAI_H(in0, shift_val); \ + in1 = (RTYPE)SRAI_H(in1, shift_val); \ +} while (0) +#define SRAI_H2_SH(...) SRAI_H2(v8i16, __VA_ARGS__) +#define SRAI_H2_UH(...) SRAI_H2(v8u16, __VA_ARGS__) + +/* Description : Arithmetic rounded shift right all elements of word vector + * Arguments : Inputs - in0, in1, shift + * Outputs - in place operation + * Return Type - as per input vector RTYPE + * Details : Each element of vector 'in0' is right shifted by 'shift' and + * the result is written in-place. 'shift' is a GP variable. + */ +#define SRARI_W2(RTYPE, in0, in1, shift) do { \ + in0 = (RTYPE)__msa_srari_w((v4i32)in0, shift); \ + in1 = (RTYPE)__msa_srari_w((v4i32)in1, shift); \ +} while (0) +#define SRARI_W2_SW(...) SRARI_W2(v4i32, __VA_ARGS__) + +#define SRARI_W4(RTYPE, in0, in1, in2, in3, shift) do { \ + SRARI_W2(RTYPE, in0, in1, shift); \ + SRARI_W2(RTYPE, in2, in3, shift); \ +} while (0) +#define SRARI_W4_SH(...) SRARI_W4(v8i16, __VA_ARGS__) +#define SRARI_W4_UW(...) SRARI_W4(v4u32, __VA_ARGS__) +#define SRARI_W4_SW(...) SRARI_W4(v4i32, __VA_ARGS__) + +/* Description : Shift right arithmetic rounded double words + * Arguments : Inputs - in0, in1, shift + * Outputs - in place operation + * Return Type - as per RTYPE + * Details : Each element of vector 'in0' is shifted right arithmetically by + * the number of bits in the corresponding element in the vector + * 'shift'. The last discarded bit is added to shifted value for + * rounding and the result is written in-place. + * 'shift' is a vector. + */ +#define SRAR_D2(RTYPE, in0, in1, shift) do { \ + in0 = (RTYPE)__msa_srar_d((v2i64)in0, (v2i64)shift); \ + in1 = (RTYPE)__msa_srar_d((v2i64)in1, (v2i64)shift); \ +} while (0) +#define SRAR_D2_SW(...) SRAR_D2(v4i32, __VA_ARGS__) +#define SRAR_D2_SD(...) SRAR_D2(v2i64, __VA_ARGS__) +#define SRAR_D2_UD(...) SRAR_D2(v2u64, __VA_ARGS__) + +#define SRAR_D4(RTYPE, in0, in1, in2, in3, shift) do { \ + SRAR_D2(RTYPE, in0, in1, shift); \ + SRAR_D2(RTYPE, in2, in3, shift); \ +} while (0) +#define SRAR_D4_SD(...) SRAR_D4(v2i64, __VA_ARGS__) +#define SRAR_D4_UD(...) SRAR_D4(v2u64, __VA_ARGS__) + +/* Description : Addition of 2 pairs of half-word vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Details : Each element in 'in0' is added to 'in1' and result is written + * to 'out0'. + */ +#define ADDVI_H2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)ADDVI_H(in0, in1); \ + out1 = (RTYPE)ADDVI_H(in2, in3); \ +} while (0) +#define ADDVI_H2_SH(...) ADDVI_H2(v8i16, __VA_ARGS__) +#define ADDVI_H2_UH(...) ADDVI_H2(v8u16, __VA_ARGS__) + +/* Description : Addition of 2 pairs of word vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Details : Each element in 'in0' is added to 'in1' and result is written + * to 'out0'. + */ +#define ADDVI_W2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)ADDVI_W(in0, in1); \ + out1 = (RTYPE)ADDVI_W(in2, in3); \ +} while (0) +#define ADDVI_W2_SW(...) ADDVI_W2(v4i32, __VA_ARGS__) + +/* Description : Fill 2 pairs of word vectors with GP registers + * Arguments : Inputs - in0, in1 + * Outputs - out0, out1 + * Details : GP register in0 is replicated in each word element of out0 + * GP register in1 is replicated in each word element of out1 + */ +#define FILL_W2(RTYPE, in0, in1, out0, out1) do { \ + out0 = (RTYPE)__msa_fill_w(in0); \ + out1 = (RTYPE)__msa_fill_w(in1); \ +} while (0) +#define FILL_W2_SW(...) FILL_W2(v4i32, __VA_ARGS__) + +/* Description : Addition of 2 pairs of vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Details : Each element in 'in0' is added to 'in1' and result is written + * to 'out0'. + */ +#define ADD2(in0, in1, in2, in3, out0, out1) do { \ + out0 = in0 + in1; \ + out1 = in2 + in3; \ +} while (0) + +#define ADD4(in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + ADD2(in0, in1, in2, in3, out0, out1); \ + ADD2(in4, in5, in6, in7, out2, out3); \ +} while (0) + +/* Description : Subtraction of 2 pairs of vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Details : Each element in 'in1' is subtracted from 'in0' and result is + * written to 'out0'. + */ +#define SUB2(in0, in1, in2, in3, out0, out1) do { \ + out0 = in0 - in1; \ + out1 = in2 - in3; \ +} while (0) + +#define SUB3(in0, in1, in2, in3, in4, in5, out0, out1, out2) do { \ + out0 = in0 - in1; \ + out1 = in2 - in3; \ + out2 = in4 - in5; \ +} while (0) + +#define SUB4(in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + out0 = in0 - in1; \ + out1 = in2 - in3; \ + out2 = in4 - in5; \ + out3 = in6 - in7; \ +} while (0) + +/* Description : Addition - Subtraction of input vectors + * Arguments : Inputs - in0, in1 + * Outputs - out0, out1 + * Details : Each element in 'in1' is added to 'in0' and result is + * written to 'out0'. + * Each element in 'in1' is subtracted from 'in0' and result is + * written to 'out1'. + */ +#define ADDSUB2(in0, in1, out0, out1) do { \ + out0 = in0 + in1; \ + out1 = in0 - in1; \ +} while (0) + +/* Description : Multiplication of pairs of vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1 + * Details : Each element from 'in0' is multiplied with elements from 'in1' + * and the result is written to 'out0' + */ +#define MUL2(in0, in1, in2, in3, out0, out1) do { \ + out0 = in0 * in1; \ + out1 = in2 * in3; \ +} while (0) + +#define MUL4(in0, in1, in2, in3, in4, in5, in6, in7, \ + out0, out1, out2, out3) do { \ + MUL2(in0, in1, in2, in3, out0, out1); \ + MUL2(in4, in5, in6, in7, out2, out3); \ +} while (0) + +/* Description : Sign extend halfword elements from right half of the vector + * Arguments : Input - in (halfword vector) + * Output - out (sign extended word vector) + * Return Type - signed word + * Details : Sign bit of halfword elements from input vector 'in' is + * extracted and interleaved with same vector 'in0' to generate + * 4 word elements keeping sign intact + */ +#define UNPCK_R_SH_SW(in, out) do { \ + const v8i16 sign_m = __msa_clti_s_h((v8i16)in, 0); \ + out = (v4i32)__msa_ilvr_h(sign_m, (v8i16)in); \ +} while (0) + +/* Description : Sign extend halfword elements from input vector and return + * the result in pair of vectors + * Arguments : Input - in (halfword vector) + * Outputs - out0, out1 (sign extended word vectors) + * Return Type - signed word + * Details : Sign bit of halfword elements from input vector 'in' is + * extracted and interleaved right with same vector 'in0' to + * generate 4 signed word elements in 'out0' + * Then interleaved left with same vector 'in0' to + * generate 4 signed word elements in 'out1' + */ +#define UNPCK_SH_SW(in, out0, out1) do { \ + const v8i16 tmp_m = __msa_clti_s_h((v8i16)in, 0); \ + ILVRL_H2_SW(tmp_m, in, out0, out1); \ +} while (0) + +/* Description : Butterfly of 4 input vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1, out2, out3 + * Details : Butterfly operation + */ +#define BUTTERFLY_4(in0, in1, in2, in3, out0, out1, out2, out3) do { \ + out0 = in0 + in3; \ + out1 = in1 + in2; \ + out2 = in1 - in2; \ + out3 = in0 - in3; \ +} while (0) + +/* Description : Transpose 16x4 block into 4x16 with byte elements in vectors + * Arguments : Inputs - in0, in1, in2, in3, in4, in5, in6, in7, + * in8, in9, in10, in11, in12, in13, in14, in15 + * Outputs - out0, out1, out2, out3 + * Return Type - unsigned byte + */ +#define TRANSPOSE16x4_UB_UB(in0, in1, in2, in3, in4, in5, in6, in7, \ + in8, in9, in10, in11, in12, in13, in14, in15, \ + out0, out1, out2, out3) do { \ + v2i64 tmp0_m, tmp1_m, tmp2_m, tmp3_m, tmp4_m, tmp5_m; \ + ILVEV_W2_SD(in0, in4, in8, in12, tmp2_m, tmp3_m); \ + ILVEV_W2_SD(in1, in5, in9, in13, tmp0_m, tmp1_m); \ + ILVEV_D2_UB(tmp2_m, tmp3_m, tmp0_m, tmp1_m, out1, out3); \ + ILVEV_W2_SD(in2, in6, in10, in14, tmp4_m, tmp5_m); \ + ILVEV_W2_SD(in3, in7, in11, in15, tmp0_m, tmp1_m); \ + ILVEV_D2_SD(tmp4_m, tmp5_m, tmp0_m, tmp1_m, tmp2_m, tmp3_m); \ + ILVEV_B2_SD(out1, out3, tmp2_m, tmp3_m, tmp0_m, tmp1_m); \ + ILVEVOD_H2_UB(tmp0_m, tmp1_m, tmp0_m, tmp1_m, out0, out2); \ + ILVOD_B2_SD(out1, out3, tmp2_m, tmp3_m, tmp0_m, tmp1_m); \ + ILVEVOD_H2_UB(tmp0_m, tmp1_m, tmp0_m, tmp1_m, out1, out3); \ +} while (0) + +/* Description : Transpose 16x8 block into 8x16 with byte elements in vectors + * Arguments : Inputs - in0, in1, in2, in3, in4, in5, in6, in7, + * in8, in9, in10, in11, in12, in13, in14, in15 + * Outputs - out0, out1, out2, out3, out4, out5, out6, out7 + * Return Type - unsigned byte + */ +#define TRANSPOSE16x8_UB_UB(in0, in1, in2, in3, in4, in5, in6, in7, \ + in8, in9, in10, in11, in12, in13, in14, in15, \ + out0, out1, out2, out3, out4, out5, \ + out6, out7) do { \ + v8i16 tmp0_m, tmp1_m, tmp4_m, tmp5_m, tmp6_m, tmp7_m; \ + v4i32 tmp2_m, tmp3_m; \ + ILVEV_D2_UB(in0, in8, in1, in9, out7, out6); \ + ILVEV_D2_UB(in2, in10, in3, in11, out5, out4); \ + ILVEV_D2_UB(in4, in12, in5, in13, out3, out2); \ + ILVEV_D2_UB(in6, in14, in7, in15, out1, out0); \ + ILVEV_B2_SH(out7, out6, out5, out4, tmp0_m, tmp1_m); \ + ILVOD_B2_SH(out7, out6, out5, out4, tmp4_m, tmp5_m); \ + ILVEV_B2_UB(out3, out2, out1, out0, out5, out7); \ + ILVOD_B2_SH(out3, out2, out1, out0, tmp6_m, tmp7_m); \ + ILVEV_H2_SW(tmp0_m, tmp1_m, out5, out7, tmp2_m, tmp3_m); \ + ILVEVOD_W2_UB(tmp2_m, tmp3_m, tmp2_m, tmp3_m, out0, out4); \ + ILVOD_H2_SW(tmp0_m, tmp1_m, out5, out7, tmp2_m, tmp3_m); \ + ILVEVOD_W2_UB(tmp2_m, tmp3_m, tmp2_m, tmp3_m, out2, out6); \ + ILVEV_H2_SW(tmp4_m, tmp5_m, tmp6_m, tmp7_m, tmp2_m, tmp3_m); \ + ILVEVOD_W2_UB(tmp2_m, tmp3_m, tmp2_m, tmp3_m, out1, out5); \ + ILVOD_H2_SW(tmp4_m, tmp5_m, tmp6_m, tmp7_m, tmp2_m, tmp3_m); \ + ILVEVOD_W2_UB(tmp2_m, tmp3_m, tmp2_m, tmp3_m, out3, out7); \ +} while (0) + +/* Description : Transpose 4x4 block with word elements in vectors + * Arguments : Inputs - in0, in1, in2, in3 + * Outputs - out0, out1, out2, out3 + * Return Type - as per RTYPE + */ +#define TRANSPOSE4x4_W(RTYPE, in0, in1, in2, in3, \ + out0, out1, out2, out3) do { \ + v4i32 s0_m, s1_m, s2_m, s3_m; \ + ILVRL_W2_SW(in1, in0, s0_m, s1_m); \ + ILVRL_W2_SW(in3, in2, s2_m, s3_m); \ + out0 = (RTYPE)__msa_ilvr_d((v2i64)s2_m, (v2i64)s0_m); \ + out1 = (RTYPE)__msa_ilvl_d((v2i64)s2_m, (v2i64)s0_m); \ + out2 = (RTYPE)__msa_ilvr_d((v2i64)s3_m, (v2i64)s1_m); \ + out3 = (RTYPE)__msa_ilvl_d((v2i64)s3_m, (v2i64)s1_m); \ +} while (0) +#define TRANSPOSE4x4_SW_SW(...) TRANSPOSE4x4_W(v4i32, __VA_ARGS__) + +/* Description : Add block 4x4 + * Arguments : Inputs - in0, in1, in2, in3, pdst, stride + * Details : Least significant 4 bytes from each input vector are added to + * the destination bytes, clipped between 0-255 and stored. + */ +#define ADDBLK_ST4x4_UB(in0, in1, in2, in3, pdst, stride) do { \ + uint32_t src0_m, src1_m, src2_m, src3_m; \ + v8i16 inp0_m, inp1_m, res0_m, res1_m; \ + v16i8 dst0_m = { 0 }; \ + v16i8 dst1_m = { 0 }; \ + const v16i8 zero_m = { 0 }; \ + ILVR_D2_SH(in1, in0, in3, in2, inp0_m, inp1_m); \ + LW4(pdst, stride, src0_m, src1_m, src2_m, src3_m); \ + INSERT_W2_SB(src0_m, src1_m, dst0_m); \ + INSERT_W2_SB(src2_m, src3_m, dst1_m); \ + ILVR_B2_SH(zero_m, dst0_m, zero_m, dst1_m, res0_m, res1_m); \ + ADD2(res0_m, inp0_m, res1_m, inp1_m, res0_m, res1_m); \ + CLIP_SH2_0_255(res0_m, res1_m); \ + PCKEV_B2_SB(res0_m, res0_m, res1_m, res1_m, dst0_m, dst1_m); \ + ST4x4_UB(dst0_m, dst1_m, 0, 1, 0, 1, pdst, stride); \ +} while (0) + +/* Description : Pack even byte elements, extract 0 & 2 index words from pair + * of results and store 4 words in destination memory as per + * stride + * Arguments : Inputs - in0, in1, in2, in3, pdst, stride + */ +#define PCKEV_ST4x4_UB(in0, in1, in2, in3, pdst, stride) do { \ + v16i8 tmp0_m, tmp1_m; \ + PCKEV_B2_SB(in1, in0, in3, in2, tmp0_m, tmp1_m); \ + ST4x4_UB(tmp0_m, tmp1_m, 0, 2, 0, 2, pdst, stride); \ +} while (0) + +/* Description : average with rounding (in0 + in1 + 1) / 2. + * Arguments : Inputs - in0, in1, in2, in3, + * Outputs - out0, out1 + * Return Type - as per RTYPE + * Details : Each unsigned byte element from 'in0' vector is added with + * each unsigned byte element from 'in1' vector. Then the average + * with rounding is calculated and written to 'out0' + */ +#define AVER_UB2(RTYPE, in0, in1, in2, in3, out0, out1) do { \ + out0 = (RTYPE)__msa_aver_u_b((v16u8)in0, (v16u8)in1); \ + out1 = (RTYPE)__msa_aver_u_b((v16u8)in2, (v16u8)in3); \ +} while (0) +#define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__) + +#endif // WEBP_USE_MSA +#endif // WEBP_DSP_MSA_MACRO_H_ diff --git a/libraries/webp/src/dsp/neon.h b/libraries/webp/src/dsp/neon.h new file mode 100644 index 00000000000..14acb4044ba --- /dev/null +++ b/libraries/webp/src/dsp/neon.h @@ -0,0 +1,104 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// NEON common code. + +#ifndef WEBP_DSP_NEON_H_ +#define WEBP_DSP_NEON_H_ + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include + +// Right now, some intrinsics functions seem slower, so we disable them +// everywhere except newer clang/gcc or aarch64 where the inline assembly is +// incompatible. +#if LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 9) || WEBP_AARCH64 +#define WEBP_USE_INTRINSICS // use intrinsics when possible +#endif + +#define INIT_VECTOR2(v, a, b) do { \ + v.val[0] = a; \ + v.val[1] = b; \ +} while (0) + +#define INIT_VECTOR3(v, a, b, c) do { \ + v.val[0] = a; \ + v.val[1] = b; \ + v.val[2] = c; \ +} while (0) + +#define INIT_VECTOR4(v, a, b, c, d) do { \ + v.val[0] = a; \ + v.val[1] = b; \ + v.val[2] = c; \ + v.val[3] = d; \ +} while (0) + +// if using intrinsics, this flag avoids some functions that make gcc-4.6.3 +// crash ("internal compiler error: in immed_double_const, at emit-rtl."). +// (probably similar to gcc.gnu.org/bugzilla/show_bug.cgi?id=48183) +#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || WEBP_AARCH64) +#define WORK_AROUND_GCC +#endif + +static WEBP_INLINE int32x4x4_t Transpose4x4_NEON(const int32x4x4_t rows) { + uint64x2x2_t row01, row23; + + row01.val[0] = vreinterpretq_u64_s32(rows.val[0]); + row01.val[1] = vreinterpretq_u64_s32(rows.val[1]); + row23.val[0] = vreinterpretq_u64_s32(rows.val[2]); + row23.val[1] = vreinterpretq_u64_s32(rows.val[3]); + // Transpose 64-bit values (there's no vswp equivalent) + { + const uint64x1_t row0h = vget_high_u64(row01.val[0]); + const uint64x1_t row2l = vget_low_u64(row23.val[0]); + const uint64x1_t row1h = vget_high_u64(row01.val[1]); + const uint64x1_t row3l = vget_low_u64(row23.val[1]); + row01.val[0] = vcombine_u64(vget_low_u64(row01.val[0]), row2l); + row23.val[0] = vcombine_u64(row0h, vget_high_u64(row23.val[0])); + row01.val[1] = vcombine_u64(vget_low_u64(row01.val[1]), row3l); + row23.val[1] = vcombine_u64(row1h, vget_high_u64(row23.val[1])); + } + { + const int32x4x2_t out01 = vtrnq_s32(vreinterpretq_s32_u64(row01.val[0]), + vreinterpretq_s32_u64(row01.val[1])); + const int32x4x2_t out23 = vtrnq_s32(vreinterpretq_s32_u64(row23.val[0]), + vreinterpretq_s32_u64(row23.val[1])); + int32x4x4_t out; + out.val[0] = out01.val[0]; + out.val[1] = out01.val[1]; + out.val[2] = out23.val[0]; + out.val[3] = out23.val[1]; + return out; + } +} + +#if 0 // Useful debug macro. +#include +#define PRINT_REG(REG, SIZE) do { \ + int i; \ + printf("%s \t[%d]: 0x", #REG, SIZE); \ + if (SIZE == 8) { \ + uint8_t _tmp[8]; \ + vst1_u8(_tmp, (REG)); \ + for (i = 0; i < 8; ++i) printf("%.2x ", _tmp[i]); \ + } else if (SIZE == 16) { \ + uint16_t _tmp[4]; \ + vst1_u16(_tmp, (REG)); \ + for (i = 0; i < 4; ++i) printf("%.4x ", _tmp[i]); \ + } \ + printf("\n"); \ +} while (0) +#endif + +#endif // WEBP_USE_NEON +#endif // WEBP_DSP_NEON_H_ diff --git a/libraries/webp/src/dsp/quant.h b/libraries/webp/src/dsp/quant.h new file mode 100644 index 00000000000..28300383109 --- /dev/null +++ b/libraries/webp/src/dsp/quant.h @@ -0,0 +1,91 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- + +#ifndef WEBP_DSP_QUANT_H_ +#define WEBP_DSP_QUANT_H_ + +#include + +#include "src/dsp/dsp.h" +#include "include/webp/types.h" + +#if defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) && \ + !defined(WEBP_HAVE_NEON_RTCD) +#include + +#define IsFlat IsFlat_NEON + +static uint32_t horizontal_add_uint32x4(const uint32x4_t a) { +#if WEBP_AARCH64 + return vaddvq_u32(a); +#else + const uint64x2_t b = vpaddlq_u32(a); + const uint32x2_t c = vadd_u32(vreinterpret_u32_u64(vget_low_u64(b)), + vreinterpret_u32_u64(vget_high_u64(b))); + return vget_lane_u32(c, 0); +#endif +} + +static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks, + int thresh) { + const int16x8_t tst_ones = vdupq_n_s16(-1); + uint32x4_t sum = vdupq_n_u32(0); + int i; + + for (i = 0; i < num_blocks; ++i) { + // Set DC to zero. + const int16x8_t a_0 = vsetq_lane_s16(0, vld1q_s16(levels), 0); + const int16x8_t a_1 = vld1q_s16(levels + 8); + + const uint16x8_t b_0 = vshrq_n_u16(vtstq_s16(a_0, tst_ones), 15); + const uint16x8_t b_1 = vshrq_n_u16(vtstq_s16(a_1, tst_ones), 15); + + sum = vpadalq_u16(sum, b_0); + sum = vpadalq_u16(sum, b_1); + + levels += 16; + } + return thresh >= (int)horizontal_add_uint32x4(sum); +} + +#else + +#define IsFlat IsFlat_C + +static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks, + int thresh) { + int score = 0; + while (num_blocks-- > 0) { // TODO(skal): refine positional scoring? + int i; + for (i = 1; i < 16; ++i) { // omit DC, we're only interested in AC + score += (levels[i] != 0); + if (score > thresh) return 0; + } + levels += 16; + } + return 1; +} + +#endif // defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) && + // !defined(WEBP_HAVE_NEON_RTCD) + +static WEBP_INLINE int IsFlatSource16(const uint8_t* src) { + const uint32_t v = src[0] * 0x01010101u; + int i; + for (i = 0; i < 16; ++i) { + if (memcmp(src + 0, &v, 4) || memcmp(src + 4, &v, 4) || + memcmp(src + 8, &v, 4) || memcmp(src + 12, &v, 4)) { + return 0; + } + src += BPS; + } + return 1; +} + +#endif // WEBP_DSP_QUANT_H_ diff --git a/libraries/webp/src/dsp/rescaler.c b/libraries/webp/src/dsp/rescaler.c new file mode 100644 index 00000000000..325d8be1808 --- /dev/null +++ b/libraries/webp/src/dsp/rescaler.c @@ -0,0 +1,252 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/dsp/dsp.h" +#include "src/utils/rescaler_utils.h" + +//------------------------------------------------------------------------------ +// Implementations of critical functions ImportRow / ExportRow + +#define ROUNDER (WEBP_RESCALER_ONE >> 1) +#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) +#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) + +//------------------------------------------------------------------------------ +// Row import + +void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk, + const uint8_t* src) { + const int x_stride = wrk->num_channels; + const int x_out_max = wrk->dst_width * wrk->num_channels; + int channel; + assert(!WebPRescalerInputDone(wrk)); + assert(wrk->x_expand); + for (channel = 0; channel < x_stride; ++channel) { + int x_in = channel; + int x_out = channel; + // simple bilinear interpolation + int accum = wrk->x_add; + rescaler_t left = (rescaler_t)src[x_in]; + rescaler_t right = + (wrk->src_width > 1) ? (rescaler_t)src[x_in + x_stride] : left; + x_in += x_stride; + while (1) { + wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; + x_out += x_stride; + if (x_out >= x_out_max) break; + accum -= wrk->x_sub; + if (accum < 0) { + left = right; + x_in += x_stride; + assert(x_in < wrk->src_width * x_stride); + right = (rescaler_t)src[x_in]; + accum += wrk->x_add; + } + } + assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); + } +} + +void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk, + const uint8_t* src) { + const int x_stride = wrk->num_channels; + const int x_out_max = wrk->dst_width * wrk->num_channels; + int channel; + assert(!WebPRescalerInputDone(wrk)); + assert(!wrk->x_expand); + for (channel = 0; channel < x_stride; ++channel) { + int x_in = channel; + int x_out = channel; + uint32_t sum = 0; + int accum = 0; + while (x_out < x_out_max) { + uint32_t base = 0; + accum += wrk->x_add; + while (accum > 0) { + accum -= wrk->x_sub; + assert(x_in < wrk->src_width * x_stride); + base = src[x_in]; + sum += base; + x_in += x_stride; + } + { // Emit next horizontal pixel. + const rescaler_t frac = base * (-accum); + wrk->frow[x_out] = sum * wrk->x_sub - frac; + // fresh fractional start for next pixel + sum = (int)MULT_FIX(frac, wrk->fx_scale); + } + x_out += x_stride; + } + assert(accum == 0); + } +} + +//------------------------------------------------------------------------------ +// Row export + +void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) { + int x_out; + uint8_t* const dst = wrk->dst; + rescaler_t* const irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* const frow = wrk->frow; + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(wrk->y_expand); + assert(wrk->y_sub != 0); + if (wrk->y_accum == 0) { + for (x_out = 0; x_out < x_out_max; ++x_out) { + const uint32_t J = frow[x_out]; + const int v = (int)MULT_FIX(J, wrk->fy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + } + } else { + const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); + const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); + for (x_out = 0; x_out < x_out_max; ++x_out) { + const uint64_t I = (uint64_t)A * frow[x_out] + + (uint64_t)B * irow[x_out]; + const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); + const int v = (int)MULT_FIX(J, wrk->fy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + } + } +} + +void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) { + int x_out; + uint8_t* const dst = wrk->dst; + rescaler_t* const irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* const frow = wrk->frow; + const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(!wrk->y_expand); + if (yscale) { + for (x_out = 0; x_out < x_out_max; ++x_out) { + const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale); + const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + irow[x_out] = frac; // new fractional start + } + } else { + for (x_out = 0; x_out < x_out_max; ++x_out) { + const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + irow[x_out] = 0; + } + } +} + +#undef MULT_FIX_FLOOR +#undef MULT_FIX +#undef ROUNDER + +//------------------------------------------------------------------------------ +// Main entry calls + +void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) { + assert(!WebPRescalerInputDone(wrk)); + if (!wrk->x_expand) { + WebPRescalerImportRowShrink(wrk, src); + } else { + WebPRescalerImportRowExpand(wrk, src); + } +} + +void WebPRescalerExportRow(WebPRescaler* const wrk) { + if (wrk->y_accum <= 0) { + assert(!WebPRescalerOutputDone(wrk)); + if (wrk->y_expand) { + WebPRescalerExportRowExpand(wrk); + } else if (wrk->fxy_scale) { + WebPRescalerExportRowShrink(wrk); + } else { // special case + int i; + assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1); + assert(wrk->src_width == 1 && wrk->dst_width <= 2); + for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { + wrk->dst[i] = wrk->irow[i]; + wrk->irow[i] = 0; + } + } + wrk->y_accum += wrk->y_add; + wrk->dst += wrk->dst_stride; + ++wrk->dst_y; + } +} + +//------------------------------------------------------------------------------ + +WebPRescalerImportRowFunc WebPRescalerImportRowExpand; +WebPRescalerImportRowFunc WebPRescalerImportRowShrink; + +WebPRescalerExportRowFunc WebPRescalerExportRowExpand; +WebPRescalerExportRowFunc WebPRescalerExportRowShrink; + +extern VP8CPUInfo VP8GetCPUInfo; +extern void WebPRescalerDspInitSSE2(void); +extern void WebPRescalerDspInitMIPS32(void); +extern void WebPRescalerDspInitMIPSdspR2(void); +extern void WebPRescalerDspInitMSA(void); +extern void WebPRescalerDspInitNEON(void); + +WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) { +#if !defined(WEBP_REDUCE_SIZE) +#if !WEBP_NEON_OMIT_C_CODE + WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C; + WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C; +#endif + + WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C; + WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C; + + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + WebPRescalerDspInitSSE2(); + } +#endif +#if defined(WEBP_USE_MIPS32) + if (VP8GetCPUInfo(kMIPS32)) { + WebPRescalerDspInitMIPS32(); + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + WebPRescalerDspInitMIPSdspR2(); + } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + WebPRescalerDspInitMSA(); + } +#endif + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + WebPRescalerDspInitNEON(); + } +#endif + + assert(WebPRescalerExportRowExpand != NULL); + assert(WebPRescalerExportRowShrink != NULL); + assert(WebPRescalerImportRowExpand != NULL); + assert(WebPRescalerImportRowShrink != NULL); +#endif // WEBP_REDUCE_SIZE +} diff --git a/libraries/webp/src/dsp/rescaler_mips32.c b/libraries/webp/src/dsp/rescaler_mips32.c new file mode 100644 index 00000000000..61f63c616cf --- /dev/null +++ b/libraries/webp/src/dsp/rescaler_mips32.c @@ -0,0 +1,295 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS version of rescaling functions +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS32) && !defined(WEBP_REDUCE_SIZE) + +#include +#include "src/utils/rescaler_utils.h" + +//------------------------------------------------------------------------------ +// Row import + +static void ImportRowShrink_MIPS32(WebPRescaler* const wrk, + const uint8_t* src) { + const int x_stride = wrk->num_channels; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const int fx_scale = wrk->fx_scale; + const int x_add = wrk->x_add; + const int x_sub = wrk->x_sub; + const int x_stride1 = x_stride << 2; + int channel; + assert(!wrk->x_expand); + assert(!WebPRescalerInputDone(wrk)); + + for (channel = 0; channel < x_stride; ++channel) { + const uint8_t* src1 = src + channel; + rescaler_t* frow = wrk->frow + channel; + int temp1, temp2, temp3; + int base, frac, sum; + int accum, accum1; + int loop_c = x_out_max - channel; + + __asm__ volatile ( + "li %[temp1], 0x8000 \n\t" + "li %[temp2], 0x10000 \n\t" + "li %[sum], 0 \n\t" + "li %[accum], 0 \n\t" + "1: \n\t" + "addu %[accum], %[accum], %[x_add] \n\t" + "li %[base], 0 \n\t" + "blez %[accum], 3f \n\t" + "2: \n\t" + "lbu %[base], 0(%[src1]) \n\t" + "subu %[accum], %[accum], %[x_sub] \n\t" + "addu %[src1], %[src1], %[x_stride] \n\t" + "addu %[sum], %[sum], %[base] \n\t" + "bgtz %[accum], 2b \n\t" + "3: \n\t" + "negu %[accum1], %[accum] \n\t" + "mul %[frac], %[base], %[accum1] \n\t" + "mul %[temp3], %[sum], %[x_sub] \n\t" + "subu %[loop_c], %[loop_c], %[x_stride] \n\t" + "mult %[temp1], %[temp2] \n\t" + "maddu %[frac], %[fx_scale] \n\t" + "mfhi %[sum] \n\t" + "subu %[temp3], %[temp3], %[frac] \n\t" + "sw %[temp3], 0(%[frow]) \n\t" + "addu %[frow], %[frow], %[x_stride1] \n\t" + "bgtz %[loop_c], 1b \n\t" + : [accum]"=&r"(accum), [src1]"+r"(src1), [temp3]"=&r"(temp3), + [sum]"=&r"(sum), [base]"=&r"(base), [frac]"=&r"(frac), + [frow]"+r"(frow), [accum1]"=&r"(accum1), + [temp2]"=&r"(temp2), [temp1]"=&r"(temp1) + : [x_stride]"r"(x_stride), [fx_scale]"r"(fx_scale), + [x_sub]"r"(x_sub), [x_add]"r"(x_add), + [loop_c]"r"(loop_c), [x_stride1]"r"(x_stride1) + : "memory", "hi", "lo" + ); + assert(accum == 0); + } +} + +static void ImportRowExpand_MIPS32(WebPRescaler* const wrk, + const uint8_t* src) { + const int x_stride = wrk->num_channels; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const int x_add = wrk->x_add; + const int x_sub = wrk->x_sub; + const int src_width = wrk->src_width; + const int x_stride1 = x_stride << 2; + int channel; + assert(wrk->x_expand); + assert(!WebPRescalerInputDone(wrk)); + + for (channel = 0; channel < x_stride; ++channel) { + const uint8_t* src1 = src + channel; + rescaler_t* frow = wrk->frow + channel; + int temp1, temp2, temp3, temp4; + int frac; + int accum; + int x_out = channel; + + __asm__ volatile ( + "addiu %[temp3], %[src_width], -1 \n\t" + "lbu %[temp2], 0(%[src1]) \n\t" + "addu %[src1], %[src1], %[x_stride] \n\t" + "bgtz %[temp3], 0f \n\t" + "addiu %[temp1], %[temp2], 0 \n\t" + "b 3f \n\t" + "0: \n\t" + "lbu %[temp1], 0(%[src1]) \n\t" + "3: \n\t" + "addiu %[accum], %[x_add], 0 \n\t" + "1: \n\t" + "subu %[temp3], %[temp2], %[temp1] \n\t" + "mul %[temp3], %[temp3], %[accum] \n\t" + "mul %[temp4], %[temp1], %[x_add] \n\t" + "addu %[temp3], %[temp4], %[temp3] \n\t" + "sw %[temp3], 0(%[frow]) \n\t" + "addu %[frow], %[frow], %[x_stride1] \n\t" + "addu %[x_out], %[x_out], %[x_stride] \n\t" + "subu %[temp3], %[x_out], %[x_out_max] \n\t" + "bgez %[temp3], 2f \n\t" + "subu %[accum], %[accum], %[x_sub] \n\t" + "bgez %[accum], 4f \n\t" + "addiu %[temp2], %[temp1], 0 \n\t" + "addu %[src1], %[src1], %[x_stride] \n\t" + "lbu %[temp1], 0(%[src1]) \n\t" + "addu %[accum], %[accum], %[x_add] \n\t" + "4: \n\t" + "b 1b \n\t" + "2: \n\t" + : [src1]"+r"(src1), [accum]"=&r"(accum), [temp1]"=&r"(temp1), + [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), + [x_out]"+r"(x_out), [frac]"=&r"(frac), [frow]"+r"(frow) + : [x_stride]"r"(x_stride), [x_add]"r"(x_add), [x_sub]"r"(x_sub), + [x_stride1]"r"(x_stride1), [src_width]"r"(src_width), + [x_out_max]"r"(x_out_max) + : "memory", "hi", "lo" + ); + assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); + } +} + +//------------------------------------------------------------------------------ +// Row export + +static void ExportRowExpand_MIPS32(WebPRescaler* const wrk) { + uint8_t* dst = wrk->dst; + rescaler_t* irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* frow = wrk->frow; + int temp0, temp1, temp3, temp4, temp5, loop_end; + const int temp2 = (int)wrk->fy_scale; + const int temp6 = x_out_max << 2; + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(wrk->y_expand); + assert(wrk->y_sub != 0); + if (wrk->y_accum == 0) { + __asm__ volatile ( + "li %[temp3], 0x10000 \n\t" + "li %[temp4], 0x8000 \n\t" + "addu %[loop_end], %[frow], %[temp6] \n\t" + "1: \n\t" + "lw %[temp0], 0(%[frow]) \n\t" + "addiu %[dst], %[dst], 1 \n\t" + "addiu %[frow], %[frow], 4 \n\t" + "mult %[temp3], %[temp4] \n\t" + "maddu %[temp0], %[temp2] \n\t" + "mfhi %[temp5] \n\t" + "sb %[temp5], -1(%[dst]) \n\t" + "bne %[frow], %[loop_end], 1b \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), + [dst]"+r"(dst), [loop_end]"=&r"(loop_end) + : [temp2]"r"(temp2), [temp6]"r"(temp6) + : "memory", "hi", "lo" + ); + } else { + const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); + const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); + __asm__ volatile ( + "li %[temp3], 0x10000 \n\t" + "li %[temp4], 0x8000 \n\t" + "addu %[loop_end], %[frow], %[temp6] \n\t" + "1: \n\t" + "lw %[temp0], 0(%[frow]) \n\t" + "lw %[temp1], 0(%[irow]) \n\t" + "addiu %[dst], %[dst], 1 \n\t" + "mult %[temp3], %[temp4] \n\t" + "maddu %[A], %[temp0] \n\t" + "maddu %[B], %[temp1] \n\t" + "addiu %[frow], %[frow], 4 \n\t" + "addiu %[irow], %[irow], 4 \n\t" + "mfhi %[temp5] \n\t" + "mult %[temp3], %[temp4] \n\t" + "maddu %[temp5], %[temp2] \n\t" + "mfhi %[temp5] \n\t" + "sb %[temp5], -1(%[dst]) \n\t" + "bne %[frow], %[loop_end], 1b \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), + [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end) + : [temp2]"r"(temp2), [temp6]"r"(temp6), [A]"r"(A), [B]"r"(B) + : "memory", "hi", "lo" + ); + } +} + +#if 0 // disabled for now. TODO(skal): make match the C-code +static void ExportRowShrink_MIPS32(WebPRescaler* const wrk) { + const int x_out_max = wrk->dst_width * wrk->num_channels; + uint8_t* dst = wrk->dst; + rescaler_t* irow = wrk->irow; + const rescaler_t* frow = wrk->frow; + const int yscale = wrk->fy_scale * (-wrk->y_accum); + int temp0, temp1, temp3, temp4, temp5, loop_end; + const int temp2 = (int)wrk->fxy_scale; + const int temp6 = x_out_max << 2; + + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(!wrk->y_expand); + assert(wrk->fxy_scale != 0); + if (yscale) { + __asm__ volatile ( + "li %[temp3], 0x10000 \n\t" + "li %[temp4], 0x8000 \n\t" + "addu %[loop_end], %[frow], %[temp6] \n\t" + "1: \n\t" + "lw %[temp0], 0(%[frow]) \n\t" + "mult %[temp3], %[temp4] \n\t" + "addiu %[frow], %[frow], 4 \n\t" + "maddu %[temp0], %[yscale] \n\t" + "mfhi %[temp1] \n\t" + "lw %[temp0], 0(%[irow]) \n\t" + "addiu %[dst], %[dst], 1 \n\t" + "addiu %[irow], %[irow], 4 \n\t" + "subu %[temp0], %[temp0], %[temp1] \n\t" + "mult %[temp3], %[temp4] \n\t" + "maddu %[temp0], %[temp2] \n\t" + "mfhi %[temp5] \n\t" + "sw %[temp1], -4(%[irow]) \n\t" + "sb %[temp5], -1(%[dst]) \n\t" + "bne %[frow], %[loop_end], 1b \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), + [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end) + : [temp2]"r"(temp2), [yscale]"r"(yscale), [temp6]"r"(temp6) + : "memory", "hi", "lo" + ); + } else { + __asm__ volatile ( + "li %[temp3], 0x10000 \n\t" + "li %[temp4], 0x8000 \n\t" + "addu %[loop_end], %[irow], %[temp6] \n\t" + "1: \n\t" + "lw %[temp0], 0(%[irow]) \n\t" + "addiu %[dst], %[dst], 1 \n\t" + "addiu %[irow], %[irow], 4 \n\t" + "mult %[temp3], %[temp4] \n\t" + "maddu %[temp0], %[temp2] \n\t" + "mfhi %[temp5] \n\t" + "sw $zero, -4(%[irow]) \n\t" + "sb %[temp5], -1(%[dst]) \n\t" + "bne %[irow], %[loop_end], 1b \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow), + [dst]"+r"(dst), [loop_end]"=&r"(loop_end) + : [temp2]"r"(temp2), [temp6]"r"(temp6) + : "memory", "hi", "lo" + ); + } +} +#endif // 0 + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPRescalerDspInitMIPS32(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPS32(void) { + WebPRescalerImportRowExpand = ImportRowExpand_MIPS32; + WebPRescalerImportRowShrink = ImportRowShrink_MIPS32; + WebPRescalerExportRowExpand = ExportRowExpand_MIPS32; +// WebPRescalerExportRowShrink = ExportRowShrink_MIPS32; +} + +#else // !WEBP_USE_MIPS32 + +WEBP_DSP_INIT_STUB(WebPRescalerDspInitMIPS32) + +#endif // WEBP_USE_MIPS32 diff --git a/libraries/webp/src/dsp/rescaler_mips_dsp_r2.c b/libraries/webp/src/dsp/rescaler_mips_dsp_r2.c new file mode 100644 index 00000000000..419b741fa51 --- /dev/null +++ b/libraries/webp/src/dsp/rescaler_mips_dsp_r2.c @@ -0,0 +1,314 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS version of rescaling functions +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) && !defined(WEBP_REDUCE_SIZE) + +#include +#include "src/utils/rescaler_utils.h" + +#define ROUNDER (WEBP_RESCALER_ONE >> 1) +#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) +#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) + +//------------------------------------------------------------------------------ +// Row export + +#if 0 // disabled for now. TODO(skal): make match the C-code +static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) { + int i; + const int x_out_max = wrk->dst_width * wrk->num_channels; + uint8_t* dst = wrk->dst; + rescaler_t* irow = wrk->irow; + const rescaler_t* frow = wrk->frow; + const int yscale = wrk->fy_scale * (-wrk->y_accum); + int temp0, temp1, temp2, temp3, temp4, temp5, loop_end; + const int temp7 = (int)wrk->fxy_scale; + const int temp6 = (x_out_max & ~0x3) << 2; + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(!wrk->y_expand); + assert(wrk->fxy_scale != 0); + if (yscale) { + if (x_out_max >= 4) { + int temp8, temp9, temp10, temp11; + __asm__ volatile ( + "li %[temp3], 0x10000 \n\t" + "li %[temp4], 0x8000 \n\t" + "addu %[loop_end], %[frow], %[temp6] \n\t" + "1: \n\t" + "lw %[temp0], 0(%[frow]) \n\t" + "lw %[temp1], 4(%[frow]) \n\t" + "lw %[temp2], 8(%[frow]) \n\t" + "lw %[temp5], 12(%[frow]) \n\t" + "mult $ac0, %[temp3], %[temp4] \n\t" + "maddu $ac0, %[temp0], %[yscale] \n\t" + "mult $ac1, %[temp3], %[temp4] \n\t" + "maddu $ac1, %[temp1], %[yscale] \n\t" + "mult $ac2, %[temp3], %[temp4] \n\t" + "maddu $ac2, %[temp2], %[yscale] \n\t" + "mult $ac3, %[temp3], %[temp4] \n\t" + "maddu $ac3, %[temp5], %[yscale] \n\t" + "addiu %[frow], %[frow], 16 \n\t" + "mfhi %[temp0], $ac0 \n\t" + "mfhi %[temp1], $ac1 \n\t" + "mfhi %[temp2], $ac2 \n\t" + "mfhi %[temp5], $ac3 \n\t" + "lw %[temp8], 0(%[irow]) \n\t" + "lw %[temp9], 4(%[irow]) \n\t" + "lw %[temp10], 8(%[irow]) \n\t" + "lw %[temp11], 12(%[irow]) \n\t" + "addiu %[dst], %[dst], 4 \n\t" + "addiu %[irow], %[irow], 16 \n\t" + "subu %[temp8], %[temp8], %[temp0] \n\t" + "subu %[temp9], %[temp9], %[temp1] \n\t" + "subu %[temp10], %[temp10], %[temp2] \n\t" + "subu %[temp11], %[temp11], %[temp5] \n\t" + "mult $ac0, %[temp3], %[temp4] \n\t" + "maddu $ac0, %[temp8], %[temp7] \n\t" + "mult $ac1, %[temp3], %[temp4] \n\t" + "maddu $ac1, %[temp9], %[temp7] \n\t" + "mult $ac2, %[temp3], %[temp4] \n\t" + "maddu $ac2, %[temp10], %[temp7] \n\t" + "mult $ac3, %[temp3], %[temp4] \n\t" + "maddu $ac3, %[temp11], %[temp7] \n\t" + "mfhi %[temp8], $ac0 \n\t" + "mfhi %[temp9], $ac1 \n\t" + "mfhi %[temp10], $ac2 \n\t" + "mfhi %[temp11], $ac3 \n\t" + "sw %[temp0], -16(%[irow]) \n\t" + "sw %[temp1], -12(%[irow]) \n\t" + "sw %[temp2], -8(%[irow]) \n\t" + "sw %[temp5], -4(%[irow]) \n\t" + "sb %[temp8], -4(%[dst]) \n\t" + "sb %[temp9], -3(%[dst]) \n\t" + "sb %[temp10], -2(%[dst]) \n\t" + "sb %[temp11], -1(%[dst]) \n\t" + "bne %[frow], %[loop_end], 1b \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), + [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end), + [temp8]"=&r"(temp8), [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), + [temp11]"=&r"(temp11), [temp2]"=&r"(temp2) + : [temp7]"r"(temp7), [yscale]"r"(yscale), [temp6]"r"(temp6) + : "memory", "hi", "lo", "$ac1hi", "$ac1lo", + "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo" + ); + } + for (i = 0; i < (x_out_max & 0x3); ++i) { + const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(*frow++, yscale); + const int v = (int)MULT_FIX(*irow - frac, wrk->fxy_scale); + *dst++ = (v > 255) ? 255u : (uint8_t)v; + *irow++ = frac; // new fractional start + } + } else { + if (x_out_max >= 4) { + __asm__ volatile ( + "li %[temp3], 0x10000 \n\t" + "li %[temp4], 0x8000 \n\t" + "addu %[loop_end], %[irow], %[temp6] \n\t" + "1: \n\t" + "lw %[temp0], 0(%[irow]) \n\t" + "lw %[temp1], 4(%[irow]) \n\t" + "lw %[temp2], 8(%[irow]) \n\t" + "lw %[temp5], 12(%[irow]) \n\t" + "addiu %[dst], %[dst], 4 \n\t" + "addiu %[irow], %[irow], 16 \n\t" + "mult $ac0, %[temp3], %[temp4] \n\t" + "maddu $ac0, %[temp0], %[temp7] \n\t" + "mult $ac1, %[temp3], %[temp4] \n\t" + "maddu $ac1, %[temp1], %[temp7] \n\t" + "mult $ac2, %[temp3], %[temp4] \n\t" + "maddu $ac2, %[temp2], %[temp7] \n\t" + "mult $ac3, %[temp3], %[temp4] \n\t" + "maddu $ac3, %[temp5], %[temp7] \n\t" + "mfhi %[temp0], $ac0 \n\t" + "mfhi %[temp1], $ac1 \n\t" + "mfhi %[temp2], $ac2 \n\t" + "mfhi %[temp5], $ac3 \n\t" + "sw $zero, -16(%[irow]) \n\t" + "sw $zero, -12(%[irow]) \n\t" + "sw $zero, -8(%[irow]) \n\t" + "sw $zero, -4(%[irow]) \n\t" + "sb %[temp0], -4(%[dst]) \n\t" + "sb %[temp1], -3(%[dst]) \n\t" + "sb %[temp2], -2(%[dst]) \n\t" + "sb %[temp5], -1(%[dst]) \n\t" + "bne %[irow], %[loop_end], 1b \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow), + [dst]"+r"(dst), [loop_end]"=&r"(loop_end), [temp2]"=&r"(temp2) + : [temp7]"r"(temp7), [temp6]"r"(temp6) + : "memory", "hi", "lo", "$ac1hi", "$ac1lo", + "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo" + ); + } + for (i = 0; i < (x_out_max & 0x3); ++i) { + const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale); + *dst++ = (v > 255) ? 255u : (uint8_t)v; + *irow++ = 0; + } + } +} +#endif // 0 + +static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) { + int i; + uint8_t* dst = wrk->dst; + rescaler_t* irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* frow = wrk->frow; + int temp0, temp1, temp2, temp3, temp4, temp5, loop_end; + const int temp6 = (x_out_max & ~0x3) << 2; + const int temp7 = (int)wrk->fy_scale; + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(wrk->y_expand); + assert(wrk->y_sub != 0); + if (wrk->y_accum == 0) { + if (x_out_max >= 4) { + __asm__ volatile ( + "li %[temp4], 0x10000 \n\t" + "li %[temp5], 0x8000 \n\t" + "addu %[loop_end], %[frow], %[temp6] \n\t" + "1: \n\t" + "lw %[temp0], 0(%[frow]) \n\t" + "lw %[temp1], 4(%[frow]) \n\t" + "lw %[temp2], 8(%[frow]) \n\t" + "lw %[temp3], 12(%[frow]) \n\t" + "addiu %[dst], %[dst], 4 \n\t" + "addiu %[frow], %[frow], 16 \n\t" + "mult $ac0, %[temp4], %[temp5] \n\t" + "maddu $ac0, %[temp0], %[temp7] \n\t" + "mult $ac1, %[temp4], %[temp5] \n\t" + "maddu $ac1, %[temp1], %[temp7] \n\t" + "mult $ac2, %[temp4], %[temp5] \n\t" + "maddu $ac2, %[temp2], %[temp7] \n\t" + "mult $ac3, %[temp4], %[temp5] \n\t" + "maddu $ac3, %[temp3], %[temp7] \n\t" + "mfhi %[temp0], $ac0 \n\t" + "mfhi %[temp1], $ac1 \n\t" + "mfhi %[temp2], $ac2 \n\t" + "mfhi %[temp3], $ac3 \n\t" + "sb %[temp0], -4(%[dst]) \n\t" + "sb %[temp1], -3(%[dst]) \n\t" + "sb %[temp2], -2(%[dst]) \n\t" + "sb %[temp3], -1(%[dst]) \n\t" + "bne %[frow], %[loop_end], 1b \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), + [dst]"+r"(dst), [loop_end]"=&r"(loop_end), [temp2]"=&r"(temp2) + : [temp7]"r"(temp7), [temp6]"r"(temp6) + : "memory", "hi", "lo", "$ac1hi", "$ac1lo", + "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo" + ); + } + for (i = 0; i < (x_out_max & 0x3); ++i) { + const uint32_t J = *frow++; + const int v = (int)MULT_FIX(J, wrk->fy_scale); + *dst++ = (v > 255) ? 255u : (uint8_t)v; + } + } else { + const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); + const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); + if (x_out_max >= 4) { + int temp8, temp9, temp10, temp11; + __asm__ volatile ( + "li %[temp8], 0x10000 \n\t" + "li %[temp9], 0x8000 \n\t" + "addu %[loop_end], %[frow], %[temp6] \n\t" + "1: \n\t" + "lw %[temp0], 0(%[frow]) \n\t" + "lw %[temp1], 4(%[frow]) \n\t" + "lw %[temp2], 8(%[frow]) \n\t" + "lw %[temp3], 12(%[frow]) \n\t" + "lw %[temp4], 0(%[irow]) \n\t" + "lw %[temp5], 4(%[irow]) \n\t" + "lw %[temp10], 8(%[irow]) \n\t" + "lw %[temp11], 12(%[irow]) \n\t" + "addiu %[dst], %[dst], 4 \n\t" + "mult $ac0, %[temp8], %[temp9] \n\t" + "maddu $ac0, %[A], %[temp0] \n\t" + "maddu $ac0, %[B], %[temp4] \n\t" + "mult $ac1, %[temp8], %[temp9] \n\t" + "maddu $ac1, %[A], %[temp1] \n\t" + "maddu $ac1, %[B], %[temp5] \n\t" + "mult $ac2, %[temp8], %[temp9] \n\t" + "maddu $ac2, %[A], %[temp2] \n\t" + "maddu $ac2, %[B], %[temp10] \n\t" + "mult $ac3, %[temp8], %[temp9] \n\t" + "maddu $ac3, %[A], %[temp3] \n\t" + "maddu $ac3, %[B], %[temp11] \n\t" + "addiu %[frow], %[frow], 16 \n\t" + "addiu %[irow], %[irow], 16 \n\t" + "mfhi %[temp0], $ac0 \n\t" + "mfhi %[temp1], $ac1 \n\t" + "mfhi %[temp2], $ac2 \n\t" + "mfhi %[temp3], $ac3 \n\t" + "mult $ac0, %[temp8], %[temp9] \n\t" + "maddu $ac0, %[temp0], %[temp7] \n\t" + "mult $ac1, %[temp8], %[temp9] \n\t" + "maddu $ac1, %[temp1], %[temp7] \n\t" + "mult $ac2, %[temp8], %[temp9] \n\t" + "maddu $ac2, %[temp2], %[temp7] \n\t" + "mult $ac3, %[temp8], %[temp9] \n\t" + "maddu $ac3, %[temp3], %[temp7] \n\t" + "mfhi %[temp0], $ac0 \n\t" + "mfhi %[temp1], $ac1 \n\t" + "mfhi %[temp2], $ac2 \n\t" + "mfhi %[temp3], $ac3 \n\t" + "sb %[temp0], -4(%[dst]) \n\t" + "sb %[temp1], -3(%[dst]) \n\t" + "sb %[temp2], -2(%[dst]) \n\t" + "sb %[temp3], -1(%[dst]) \n\t" + "bne %[frow], %[loop_end], 1b \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), + [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), + [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end), + [temp8]"=&r"(temp8), [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), + [temp11]"=&r"(temp11), [temp2]"=&r"(temp2) + : [temp7]"r"(temp7), [temp6]"r"(temp6), [A]"r"(A), [B]"r"(B) + : "memory", "hi", "lo", "$ac1hi", "$ac1lo", + "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo" + ); + } + for (i = 0; i < (x_out_max & 0x3); ++i) { + const uint64_t I = (uint64_t)A * *frow++ + + (uint64_t)B * *irow++; + const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); + const int v = (int)MULT_FIX(J, wrk->fy_scale); + *dst++ = (v > 255) ? 255u : (uint8_t)v; + } + } +} + +#undef MULT_FIX_FLOOR +#undef MULT_FIX +#undef ROUNDER + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPRescalerDspInitMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPSdspR2(void) { + WebPRescalerExportRowExpand = ExportRowExpand_MIPSdspR2; +// WebPRescalerExportRowShrink = ExportRowShrink_MIPSdspR2; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(WebPRescalerDspInitMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/rescaler_msa.c b/libraries/webp/src/dsp/rescaler_msa.c new file mode 100644 index 00000000000..256dbdd4375 --- /dev/null +++ b/libraries/webp/src/dsp/rescaler_msa.c @@ -0,0 +1,443 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MSA version of rescaling functions +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MSA) && !defined(WEBP_REDUCE_SIZE) + +#include + +#include "src/utils/rescaler_utils.h" +#include "src/dsp/msa_macro.h" + +#define ROUNDER (WEBP_RESCALER_ONE >> 1) +#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) +#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) + +#define CALC_MULT_FIX_16(in0, in1, in2, in3, scale, shift, dst) do { \ + v4u32 tmp0, tmp1, tmp2, tmp3; \ + v16u8 t0, t1, t2, t3, t4, t5; \ + v2u64 out0, out1, out2, out3; \ + ILVRL_W2_UW(zero, in0, tmp0, tmp1); \ + ILVRL_W2_UW(zero, in1, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, scale, scale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_B2_UB(out1, out0, out3, out2, t0, t1); \ + ILVRL_W2_UW(zero, in2, tmp0, tmp1); \ + ILVRL_W2_UW(zero, in3, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, scale, scale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_B2_UB(out1, out0, out3, out2, t2, t3); \ + PCKEV_B2_UB(t1, t0, t3, t2, t4, t5); \ + dst = (v16u8)__msa_pckev_b((v16i8)t5, (v16i8)t4); \ +} while (0) + +#define CALC_MULT_FIX_4(in0, scale, shift, dst) do { \ + v4u32 tmp0, tmp1; \ + v16i8 t0, t1; \ + v2u64 out0, out1; \ + ILVRL_W2_UW(zero, in0, tmp0, tmp1); \ + DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1); \ + SRAR_D2_UD(out0, out1, shift); \ + t0 = __msa_pckev_b((v16i8)out1, (v16i8)out0); \ + t1 = __msa_pckev_b(t0, t0); \ + t0 = __msa_pckev_b(t1, t1); \ + dst = __msa_copy_s_w((v4i32)t0, 0); \ +} while (0) + +#define CALC_MULT_FIX1_16(in0, in1, in2, in3, fyscale, shift, \ + dst0, dst1, dst2, dst3) do { \ + v4u32 tmp0, tmp1, tmp2, tmp3; \ + v2u64 out0, out1, out2, out3; \ + ILVRL_W2_UW(zero, in0, tmp0, tmp1); \ + ILVRL_W2_UW(zero, in1, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, fyscale, fyscale, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, fyscale, fyscale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_W2_UW(out1, out0, out3, out2, dst0, dst1); \ + ILVRL_W2_UW(zero, in2, tmp0, tmp1); \ + ILVRL_W2_UW(zero, in3, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, fyscale, fyscale, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, fyscale, fyscale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_W2_UW(out1, out0, out3, out2, dst2, dst3); \ +} while (0) + +#define CALC_MULT_FIX1_4(in0, scale, shift, dst) do { \ + v4u32 tmp0, tmp1; \ + v2u64 out0, out1; \ + ILVRL_W2_UW(zero, in0, tmp0, tmp1); \ + DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1); \ + SRAR_D2_UD(out0, out1, shift); \ + dst = (v4u32)__msa_pckev_w((v4i32)out1, (v4i32)out0); \ +} while (0) + +#define CALC_MULT_FIX2_16(in0, in1, in2, in3, mult, scale, shift, \ + dst0, dst1) do { \ + v4u32 tmp0, tmp1, tmp2, tmp3; \ + v2u64 out0, out1, out2, out3; \ + ILVRL_W2_UW(in0, in2, tmp0, tmp1); \ + ILVRL_W2_UW(in1, in3, tmp2, tmp3); \ + DOTP_UW2_UD(tmp0, tmp1, mult, mult, out0, out1); \ + DOTP_UW2_UD(tmp2, tmp3, mult, mult, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + DOTP_UW2_UD(out0, out1, scale, scale, out0, out1); \ + DOTP_UW2_UD(out2, out3, scale, scale, out2, out3); \ + SRAR_D4_UD(out0, out1, out2, out3, shift); \ + PCKEV_B2_UB(out1, out0, out3, out2, dst0, dst1); \ +} while (0) + +#define CALC_MULT_FIX2_4(in0, in1, mult, scale, shift, dst) do { \ + v4u32 tmp0, tmp1; \ + v2u64 out0, out1; \ + v16i8 t0, t1; \ + ILVRL_W2_UW(in0, in1, tmp0, tmp1); \ + DOTP_UW2_UD(tmp0, tmp1, mult, mult, out0, out1); \ + SRAR_D2_UD(out0, out1, shift); \ + DOTP_UW2_UD(out0, out1, scale, scale, out0, out1); \ + SRAR_D2_UD(out0, out1, shift); \ + t0 = __msa_pckev_b((v16i8)out1, (v16i8)out0); \ + t1 = __msa_pckev_b(t0, t0); \ + t0 = __msa_pckev_b(t1, t1); \ + dst = __msa_copy_s_w((v4i32)t0, 0); \ +} while (0) + +static WEBP_INLINE void ExportRowExpand_0(const uint32_t* frow, uint8_t* dst, + int length, + WebPRescaler* const wrk) { + const v4u32 scale = (v4u32)__msa_fill_w(wrk->fy_scale); + const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); + const v4i32 zero = { 0 }; + + while (length >= 16) { + v4u32 src0, src1, src2, src3; + v16u8 out; + LD_UW4(frow, 4, src0, src1, src2, src3); + CALC_MULT_FIX_16(src0, src1, src2, src3, scale, shift, out); + ST_UB(out, dst); + length -= 16; + frow += 16; + dst += 16; + } + if (length > 0) { + int x_out; + if (length >= 12) { + uint32_t val0_m, val1_m, val2_m; + v4u32 src0, src1, src2; + LD_UW3(frow, 4, src0, src1, src2); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + CALC_MULT_FIX_4(src1, scale, shift, val1_m); + CALC_MULT_FIX_4(src2, scale, shift, val2_m); + SW3(val0_m, val1_m, val2_m, dst, 4); + length -= 12; + frow += 12; + dst += 12; + } else if (length >= 8) { + uint32_t val0_m, val1_m; + v4u32 src0, src1; + LD_UW2(frow, 4, src0, src1); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + CALC_MULT_FIX_4(src1, scale, shift, val1_m); + SW2(val0_m, val1_m, dst, 4); + length -= 8; + frow += 8; + dst += 8; + } else if (length >= 4) { + uint32_t val0_m; + const v4u32 src0 = LD_UW(frow); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + SW(val0_m, dst); + length -= 4; + frow += 4; + dst += 4; + } + for (x_out = 0; x_out < length; ++x_out) { + const uint32_t J = frow[x_out]; + const int v = (int)MULT_FIX(J, wrk->fy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + } + } +} + +static WEBP_INLINE void ExportRowExpand_1(const uint32_t* frow, uint32_t* irow, + uint8_t* dst, int length, + WebPRescaler* const wrk) { + const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); + const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); + const v4i32 B1 = __msa_fill_w(B); + const v4i32 A1 = __msa_fill_w(A); + const v4i32 AB = __msa_ilvr_w(A1, B1); + const v4u32 scale = (v4u32)__msa_fill_w(wrk->fy_scale); + const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); + + while (length >= 16) { + v4u32 frow0, frow1, frow2, frow3, irow0, irow1, irow2, irow3; + v16u8 t0, t1, t2, t3, t4, t5; + LD_UW4(frow, 4, frow0, frow1, frow2, frow3); + LD_UW4(irow, 4, irow0, irow1, irow2, irow3); + CALC_MULT_FIX2_16(frow0, frow1, irow0, irow1, AB, scale, shift, t0, t1); + CALC_MULT_FIX2_16(frow2, frow3, irow2, irow3, AB, scale, shift, t2, t3); + PCKEV_B2_UB(t1, t0, t3, t2, t4, t5); + t0 = (v16u8)__msa_pckev_b((v16i8)t5, (v16i8)t4); + ST_UB(t0, dst); + frow += 16; + irow += 16; + dst += 16; + length -= 16; + } + if (length > 0) { + int x_out; + if (length >= 12) { + uint32_t val0_m, val1_m, val2_m; + v4u32 frow0, frow1, frow2, irow0, irow1, irow2; + LD_UW3(frow, 4, frow0, frow1, frow2); + LD_UW3(irow, 4, irow0, irow1, irow2); + CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m); + CALC_MULT_FIX2_4(frow1, irow1, AB, scale, shift, val1_m); + CALC_MULT_FIX2_4(frow2, irow2, AB, scale, shift, val2_m); + SW3(val0_m, val1_m, val2_m, dst, 4); + frow += 12; + irow += 12; + dst += 12; + length -= 12; + } else if (length >= 8) { + uint32_t val0_m, val1_m; + v4u32 frow0, frow1, irow0, irow1; + LD_UW2(frow, 4, frow0, frow1); + LD_UW2(irow, 4, irow0, irow1); + CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m); + CALC_MULT_FIX2_4(frow1, irow1, AB, scale, shift, val1_m); + SW2(val0_m, val1_m, dst, 4); + frow += 4; + irow += 4; + dst += 4; + length -= 4; + } else if (length >= 4) { + uint32_t val0_m; + const v4u32 frow0 = LD_UW(frow + 0); + const v4u32 irow0 = LD_UW(irow + 0); + CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m); + SW(val0_m, dst); + frow += 4; + irow += 4; + dst += 4; + length -= 4; + } + for (x_out = 0; x_out < length; ++x_out) { + const uint64_t I = (uint64_t)A * frow[x_out] + + (uint64_t)B * irow[x_out]; + const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); + const int v = (int)MULT_FIX(J, wrk->fy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + } + } +} + +static void RescalerExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) { + uint8_t* dst = wrk->dst; + rescaler_t* irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* frow = wrk->frow; + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(wrk->y_expand); + assert(wrk->y_sub != 0); + if (wrk->y_accum == 0) { + ExportRowExpand_0(frow, dst, x_out_max, wrk); + } else { + ExportRowExpand_1(frow, irow, dst, x_out_max, wrk); + } +} + +#if 0 // disabled for now. TODO(skal): make match the C-code +static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow, + uint8_t* dst, int length, + const uint32_t yscale, + WebPRescaler* const wrk) { + const v4u32 y_scale = (v4u32)__msa_fill_w(yscale); + const v4u32 fxyscale = (v4u32)__msa_fill_w(wrk->fxy_scale); + const v4u32 shiftval = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); + const v4i32 zero = { 0 }; + + while (length >= 16) { + v4u32 src0, src1, src2, src3, frac0, frac1, frac2, frac3; + v16u8 out; + LD_UW4(frow, 4, src0, src1, src2, src3); + CALC_MULT_FIX1_16(src0, src1, src2, src3, y_scale, shiftval, + frac0, frac1, frac2, frac3); + LD_UW4(irow, 4, src0, src1, src2, src3); + SUB4(src0, frac0, src1, frac1, src2, frac2, src3, frac3, + src0, src1, src2, src3); + CALC_MULT_FIX_16(src0, src1, src2, src3, fxyscale, shiftval, out); + ST_UB(out, dst); + ST_UW4(frac0, frac1, frac2, frac3, irow, 4); + frow += 16; + irow += 16; + dst += 16; + length -= 16; + } + if (length > 0) { + int x_out; + if (length >= 12) { + uint32_t val0_m, val1_m, val2_m; + v4u32 src0, src1, src2, frac0, frac1, frac2; + LD_UW3(frow, 4, src0, src1, src2); + CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0); + CALC_MULT_FIX1_4(src1, y_scale, shiftval, frac1); + CALC_MULT_FIX1_4(src2, y_scale, shiftval, frac2); + LD_UW3(irow, 4, src0, src1, src2); + SUB3(src0, frac0, src1, frac1, src2, frac2, src0, src1, src2); + CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m); + CALC_MULT_FIX_4(src1, fxyscale, shiftval, val1_m); + CALC_MULT_FIX_4(src2, fxyscale, shiftval, val2_m); + SW3(val0_m, val1_m, val2_m, dst, 4); + ST_UW3(frac0, frac1, frac2, irow, 4); + frow += 12; + irow += 12; + dst += 12; + length -= 12; + } else if (length >= 8) { + uint32_t val0_m, val1_m; + v4u32 src0, src1, frac0, frac1; + LD_UW2(frow, 4, src0, src1); + CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0); + CALC_MULT_FIX1_4(src1, y_scale, shiftval, frac1); + LD_UW2(irow, 4, src0, src1); + SUB2(src0, frac0, src1, frac1, src0, src1); + CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m); + CALC_MULT_FIX_4(src1, fxyscale, shiftval, val1_m); + SW2(val0_m, val1_m, dst, 4); + ST_UW2(frac0, frac1, irow, 4); + frow += 8; + irow += 8; + dst += 8; + length -= 8; + } else if (length >= 4) { + uint32_t val0_m; + v4u32 frac0; + v4u32 src0 = LD_UW(frow); + CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0); + src0 = LD_UW(irow); + src0 = src0 - frac0; + CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m); + SW(val0_m, dst); + ST_UW(frac0, irow); + frow += 4; + irow += 4; + dst += 4; + length -= 4; + } + for (x_out = 0; x_out < length; ++x_out) { + const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale); + const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + irow[x_out] = frac; + } + } +} + +static WEBP_INLINE void ExportRowShrink_1(uint32_t* irow, uint8_t* dst, + int length, + WebPRescaler* const wrk) { + const v4u32 scale = (v4u32)__msa_fill_w(wrk->fxy_scale); + const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); + const v4i32 zero = { 0 }; + + while (length >= 16) { + v4u32 src0, src1, src2, src3; + v16u8 dst0; + LD_UW4(irow, 4, src0, src1, src2, src3); + CALC_MULT_FIX_16(src0, src1, src2, src3, scale, shift, dst0); + ST_UB(dst0, dst); + ST_SW4(zero, zero, zero, zero, irow, 4); + length -= 16; + irow += 16; + dst += 16; + } + if (length > 0) { + int x_out; + if (length >= 12) { + uint32_t val0_m, val1_m, val2_m; + v4u32 src0, src1, src2; + LD_UW3(irow, 4, src0, src1, src2); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + CALC_MULT_FIX_4(src1, scale, shift, val1_m); + CALC_MULT_FIX_4(src2, scale, shift, val2_m); + SW3(val0_m, val1_m, val2_m, dst, 4); + ST_SW3(zero, zero, zero, irow, 4); + length -= 12; + irow += 12; + dst += 12; + } else if (length >= 8) { + uint32_t val0_m, val1_m; + v4u32 src0, src1; + LD_UW2(irow, 4, src0, src1); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + CALC_MULT_FIX_4(src1, scale, shift, val1_m); + SW2(val0_m, val1_m, dst, 4); + ST_SW2(zero, zero, irow, 4); + length -= 8; + irow += 8; + dst += 8; + } else if (length >= 4) { + uint32_t val0_m; + const v4u32 src0 = LD_UW(irow + 0); + CALC_MULT_FIX_4(src0, scale, shift, val0_m); + SW(val0_m, dst); + ST_SW(zero, irow); + length -= 4; + irow += 4; + dst += 4; + } + for (x_out = 0; x_out < length; ++x_out) { + const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + irow[x_out] = 0; + } + } +} + +static void RescalerExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) { + uint8_t* dst = wrk->dst; + rescaler_t* irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* frow = wrk->frow; + const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(!wrk->y_expand); + if (yscale) { + ExportRowShrink_0(frow, irow, dst, x_out_max, yscale, wrk); + } else { + ExportRowShrink_1(irow, dst, x_out_max, wrk); + } +} +#endif // 0 + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPRescalerDspInitMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMSA(void) { + WebPRescalerExportRowExpand = RescalerExportRowExpand_MIPSdspR2; +// WebPRescalerExportRowShrink = RescalerExportRowShrink_MIPSdspR2; +} + +#else // !WEBP_USE_MSA + +WEBP_DSP_INIT_STUB(WebPRescalerDspInitMSA) + +#endif // WEBP_USE_MSA diff --git a/libraries/webp/src/dsp/rescaler_neon.c b/libraries/webp/src/dsp/rescaler_neon.c new file mode 100644 index 00000000000..957a92dbc9f --- /dev/null +++ b/libraries/webp/src/dsp/rescaler_neon.c @@ -0,0 +1,192 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// NEON version of rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) && !defined(WEBP_REDUCE_SIZE) + +#include +#include +#include "src/dsp/neon.h" +#include "src/utils/rescaler_utils.h" + +#define ROUNDER (WEBP_RESCALER_ONE >> 1) +#define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) +#define MULT_FIX_FLOOR_C(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) + +#define LOAD_32x4(SRC, DST) const uint32x4_t DST = vld1q_u32((SRC)) +#define LOAD_32x8(SRC, DST0, DST1) \ + LOAD_32x4(SRC + 0, DST0); \ + LOAD_32x4(SRC + 4, DST1) + +#define STORE_32x8(SRC0, SRC1, DST) do { \ + vst1q_u32((DST) + 0, SRC0); \ + vst1q_u32((DST) + 4, SRC1); \ +} while (0) + +#if (WEBP_RESCALER_RFIX == 32) +#define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1)) +// note: B is actualy scale>>1. See MAKE_HALF_CST +#define MULT_FIX(A, B) \ + vreinterpretq_u32_s32(vqrdmulhq_s32(vreinterpretq_s32_u32((A)), (B))) +#define MULT_FIX_FLOOR(A, B) \ + vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32((A)), (B))) +#else +#error "MULT_FIX/WEBP_RESCALER_RFIX need some more work" +#endif + +static uint32x4_t Interpolate_NEON(const rescaler_t* const frow, + const rescaler_t* const irow, + uint32_t A, uint32_t B) { + LOAD_32x4(frow, A0); + LOAD_32x4(irow, B0); + const uint64x2_t C0 = vmull_n_u32(vget_low_u32(A0), A); + const uint64x2_t C1 = vmull_n_u32(vget_high_u32(A0), A); + const uint64x2_t D0 = vmlal_n_u32(C0, vget_low_u32(B0), B); + const uint64x2_t D1 = vmlal_n_u32(C1, vget_high_u32(B0), B); + const uint32x4_t E = vcombine_u32( + vrshrn_n_u64(D0, WEBP_RESCALER_RFIX), + vrshrn_n_u64(D1, WEBP_RESCALER_RFIX)); + return E; +} + +static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) { + int x_out; + uint8_t* const dst = wrk->dst; + rescaler_t* const irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const int max_span = x_out_max & ~7; + const rescaler_t* const frow = wrk->frow; + const uint32_t fy_scale = wrk->fy_scale; + const int32x4_t fy_scale_half = MAKE_HALF_CST(fy_scale); + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(wrk->y_expand); + assert(wrk->y_sub != 0); + if (wrk->y_accum == 0) { + for (x_out = 0; x_out < max_span; x_out += 8) { + LOAD_32x4(frow + x_out + 0, A0); + LOAD_32x4(frow + x_out + 4, A1); + const uint32x4_t B0 = MULT_FIX(A0, fy_scale_half); + const uint32x4_t B1 = MULT_FIX(A1, fy_scale_half); + const uint16x4_t C0 = vmovn_u32(B0); + const uint16x4_t C1 = vmovn_u32(B1); + const uint8x8_t D = vqmovn_u16(vcombine_u16(C0, C1)); + vst1_u8(dst + x_out, D); + } + for (; x_out < x_out_max; ++x_out) { + const uint32_t J = frow[x_out]; + const int v = (int)MULT_FIX_C(J, fy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + } + } else { + const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); + const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); + for (x_out = 0; x_out < max_span; x_out += 8) { + const uint32x4_t C0 = + Interpolate_NEON(frow + x_out + 0, irow + x_out + 0, A, B); + const uint32x4_t C1 = + Interpolate_NEON(frow + x_out + 4, irow + x_out + 4, A, B); + const uint32x4_t D0 = MULT_FIX(C0, fy_scale_half); + const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half); + const uint16x4_t E0 = vmovn_u32(D0); + const uint16x4_t E1 = vmovn_u32(D1); + const uint8x8_t F = vqmovn_u16(vcombine_u16(E0, E1)); + vst1_u8(dst + x_out, F); + } + for (; x_out < x_out_max; ++x_out) { + const uint64_t I = (uint64_t)A * frow[x_out] + + (uint64_t)B * irow[x_out]; + const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); + const int v = (int)MULT_FIX_C(J, fy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + } + } +} + +static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) { + int x_out; + uint8_t* const dst = wrk->dst; + rescaler_t* const irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const int max_span = x_out_max & ~7; + const rescaler_t* const frow = wrk->frow; + const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); + const uint32_t fxy_scale = wrk->fxy_scale; + const uint32x4_t zero = vdupq_n_u32(0); + const int32x4_t yscale_half = MAKE_HALF_CST(yscale); + const int32x4_t fxy_scale_half = MAKE_HALF_CST(fxy_scale); + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(!wrk->y_expand); + if (yscale) { + for (x_out = 0; x_out < max_span; x_out += 8) { + LOAD_32x8(frow + x_out, in0, in1); + LOAD_32x8(irow + x_out, in2, in3); + const uint32x4_t A0 = MULT_FIX_FLOOR(in0, yscale_half); + const uint32x4_t A1 = MULT_FIX_FLOOR(in1, yscale_half); + const uint32x4_t B0 = vqsubq_u32(in2, A0); + const uint32x4_t B1 = vqsubq_u32(in3, A1); + const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half); + const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half); + const uint16x4_t D0 = vmovn_u32(C0); + const uint16x4_t D1 = vmovn_u32(C1); + const uint8x8_t E = vqmovn_u16(vcombine_u16(D0, D1)); + vst1_u8(dst + x_out, E); + STORE_32x8(A0, A1, irow + x_out); + } + for (; x_out < x_out_max; ++x_out) { + const uint32_t frac = (uint32_t)MULT_FIX_FLOOR_C(frow[x_out], yscale); + const int v = (int)MULT_FIX_C(irow[x_out] - frac, fxy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + irow[x_out] = frac; // new fractional start + } + } else { + for (x_out = 0; x_out < max_span; x_out += 8) { + LOAD_32x8(irow + x_out, in0, in1); + const uint32x4_t A0 = MULT_FIX(in0, fxy_scale_half); + const uint32x4_t A1 = MULT_FIX(in1, fxy_scale_half); + const uint16x4_t B0 = vmovn_u32(A0); + const uint16x4_t B1 = vmovn_u32(A1); + const uint8x8_t C = vqmovn_u16(vcombine_u16(B0, B1)); + vst1_u8(dst + x_out, C); + STORE_32x8(zero, zero, irow + x_out); + } + for (; x_out < x_out_max; ++x_out) { + const int v = (int)MULT_FIX_C(irow[x_out], fxy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + irow[x_out] = 0; + } + } +} + +#undef MULT_FIX_FLOOR_C +#undef MULT_FIX_C +#undef MULT_FIX_FLOOR +#undef MULT_FIX +#undef ROUNDER + +//------------------------------------------------------------------------------ + +extern void WebPRescalerDspInitNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitNEON(void) { + WebPRescalerExportRowExpand = RescalerExportRowExpand_NEON; + WebPRescalerExportRowShrink = RescalerExportRowShrink_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(WebPRescalerDspInitNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/rescaler_sse2.c b/libraries/webp/src/dsp/rescaler_sse2.c new file mode 100644 index 00000000000..3f18e94e935 --- /dev/null +++ b/libraries/webp/src/dsp/rescaler_sse2.c @@ -0,0 +1,366 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 Rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) && !defined(WEBP_REDUCE_SIZE) +#include + +#include +#include "src/utils/rescaler_utils.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// Implementations of critical functions ImportRow / ExportRow + +#define ROUNDER (WEBP_RESCALER_ONE >> 1) +#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) +#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) + +// input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0 +static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) { + const __m128i zero = _mm_setzero_si128(); + const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH + const __m128i B = _mm_unpacklo_epi8(A, zero); // A0B0C0D0E0F0G0H0 + const __m128i C = _mm_srli_si128(B, 8); // E0F0G0H0 + *out = _mm_unpacklo_epi16(B, C); +} + +// input: 8 bytes ABCDEFGH -> output: A0B0C0D0E0F0G0H0 +static void LoadEightPixels_SSE2(const uint8_t* const src, __m128i* out) { + const __m128i zero = _mm_setzero_si128(); + const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH + *out = _mm_unpacklo_epi8(A, zero); +} + +static void RescalerImportRowExpand_SSE2(WebPRescaler* const wrk, + const uint8_t* src) { + rescaler_t* frow = wrk->frow; + const rescaler_t* const frow_end = frow + wrk->dst_width * wrk->num_channels; + const int x_add = wrk->x_add; + int accum = x_add; + __m128i cur_pixels; + + // SSE2 implementation only works with 16b signed arithmetic at max. + if (wrk->src_width < 8 || accum >= (1 << 15)) { + WebPRescalerImportRowExpand_C(wrk, src); + return; + } + + assert(!WebPRescalerInputDone(wrk)); + assert(wrk->x_expand); + if (wrk->num_channels == 4) { + LoadTwoPixels_SSE2(src, &cur_pixels); + src += 4; + while (1) { + const __m128i mult = _mm_set1_epi32(((x_add - accum) << 16) | accum); + const __m128i out = _mm_madd_epi16(cur_pixels, mult); + _mm_storeu_si128((__m128i*)frow, out); + frow += 4; + if (frow >= frow_end) break; + accum -= wrk->x_sub; + if (accum < 0) { + LoadTwoPixels_SSE2(src, &cur_pixels); + src += 4; + accum += x_add; + } + } + } else { + int left; + const uint8_t* const src_limit = src + wrk->src_width - 8; + LoadEightPixels_SSE2(src, &cur_pixels); + src += 7; + left = 7; + while (1) { + const __m128i mult = _mm_cvtsi32_si128(((x_add - accum) << 16) | accum); + const __m128i out = _mm_madd_epi16(cur_pixels, mult); + assert(sizeof(*frow) == sizeof(uint32_t)); + WebPInt32ToMem((uint8_t*)frow, _mm_cvtsi128_si32(out)); + frow += 1; + if (frow >= frow_end) break; + accum -= wrk->x_sub; + if (accum < 0) { + if (--left) { + cur_pixels = _mm_srli_si128(cur_pixels, 2); + } else if (src <= src_limit) { + LoadEightPixels_SSE2(src, &cur_pixels); + src += 7; + left = 7; + } else { // tail + cur_pixels = _mm_srli_si128(cur_pixels, 2); + cur_pixels = _mm_insert_epi16(cur_pixels, src[1], 1); + src += 1; + left = 1; + } + accum += x_add; + } + } + } + assert(accum == 0); +} + +static void RescalerImportRowShrink_SSE2(WebPRescaler* const wrk, + const uint8_t* src) { + const int x_sub = wrk->x_sub; + int accum = 0; + const __m128i zero = _mm_setzero_si128(); + const __m128i mult0 = _mm_set1_epi16(x_sub); + const __m128i mult1 = _mm_set1_epi32(wrk->fx_scale); + const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER); + __m128i sum = zero; + rescaler_t* frow = wrk->frow; + const rescaler_t* const frow_end = wrk->frow + 4 * wrk->dst_width; + + if (wrk->num_channels != 4 || wrk->x_add > (x_sub << 7)) { + WebPRescalerImportRowShrink_C(wrk, src); + return; + } + assert(!WebPRescalerInputDone(wrk)); + assert(!wrk->x_expand); + + for (; frow < frow_end; frow += 4) { + __m128i base = zero; + accum += wrk->x_add; + while (accum > 0) { + const __m128i A = _mm_cvtsi32_si128(WebPMemToInt32(src)); + src += 4; + base = _mm_unpacklo_epi8(A, zero); + // To avoid overflow, we need: base * x_add / x_sub < 32768 + // => x_add < x_sub << 7. That's a 1/128 reduction ratio limit. + sum = _mm_add_epi16(sum, base); + accum -= x_sub; + } + { // Emit next horizontal pixel. + const __m128i mult = _mm_set1_epi16(-accum); + const __m128i frac0 = _mm_mullo_epi16(base, mult); // 16b x 16b -> 32b + const __m128i frac1 = _mm_mulhi_epu16(base, mult); + const __m128i frac = _mm_unpacklo_epi16(frac0, frac1); // frac is 32b + const __m128i A0 = _mm_mullo_epi16(sum, mult0); + const __m128i A1 = _mm_mulhi_epu16(sum, mult0); + const __m128i B0 = _mm_unpacklo_epi16(A0, A1); // sum * x_sub + const __m128i frow_out = _mm_sub_epi32(B0, frac); // sum * x_sub - frac + const __m128i D0 = _mm_srli_epi64(frac, 32); + const __m128i D1 = _mm_mul_epu32(frac, mult1); // 32b x 16b -> 64b + const __m128i D2 = _mm_mul_epu32(D0, mult1); + const __m128i E1 = _mm_add_epi64(D1, rounder); + const __m128i E2 = _mm_add_epi64(D2, rounder); + const __m128i F1 = _mm_shuffle_epi32(E1, 1 | (3 << 2)); + const __m128i F2 = _mm_shuffle_epi32(E2, 1 | (3 << 2)); + const __m128i G = _mm_unpacklo_epi32(F1, F2); + sum = _mm_packs_epi32(G, zero); + _mm_storeu_si128((__m128i*)frow, frow_out); + } + } + assert(accum == 0); +} + +//------------------------------------------------------------------------------ +// Row export + +// load *src as epi64, multiply by mult and store result in [out0 ... out3] +static WEBP_INLINE void LoadDispatchAndMult_SSE2(const rescaler_t* const src, + const __m128i* const mult, + __m128i* const out0, + __m128i* const out1, + __m128i* const out2, + __m128i* const out3) { + const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + 0)); + const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + 4)); + const __m128i A2 = _mm_srli_epi64(A0, 32); + const __m128i A3 = _mm_srli_epi64(A1, 32); + if (mult != NULL) { + *out0 = _mm_mul_epu32(A0, *mult); + *out1 = _mm_mul_epu32(A1, *mult); + *out2 = _mm_mul_epu32(A2, *mult); + *out3 = _mm_mul_epu32(A3, *mult); + } else { + *out0 = A0; + *out1 = A1; + *out2 = A2; + *out3 = A3; + } +} + +static WEBP_INLINE void ProcessRow_SSE2(const __m128i* const A0, + const __m128i* const A1, + const __m128i* const A2, + const __m128i* const A3, + const __m128i* const mult, + uint8_t* const dst) { + const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER); + const __m128i mask = _mm_set_epi32(~0, 0, ~0, 0); + const __m128i B0 = _mm_mul_epu32(*A0, *mult); + const __m128i B1 = _mm_mul_epu32(*A1, *mult); + const __m128i B2 = _mm_mul_epu32(*A2, *mult); + const __m128i B3 = _mm_mul_epu32(*A3, *mult); + const __m128i C0 = _mm_add_epi64(B0, rounder); + const __m128i C1 = _mm_add_epi64(B1, rounder); + const __m128i C2 = _mm_add_epi64(B2, rounder); + const __m128i C3 = _mm_add_epi64(B3, rounder); + const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX); + const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX); +#if (WEBP_RESCALER_RFIX < 32) + const __m128i D2 = + _mm_and_si128(_mm_slli_epi64(C2, 32 - WEBP_RESCALER_RFIX), mask); + const __m128i D3 = + _mm_and_si128(_mm_slli_epi64(C3, 32 - WEBP_RESCALER_RFIX), mask); +#else + const __m128i D2 = _mm_and_si128(C2, mask); + const __m128i D3 = _mm_and_si128(C3, mask); +#endif + const __m128i E0 = _mm_or_si128(D0, D2); + const __m128i E1 = _mm_or_si128(D1, D3); + const __m128i F = _mm_packs_epi32(E0, E1); + const __m128i G = _mm_packus_epi16(F, F); + _mm_storel_epi64((__m128i*)dst, G); +} + +static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) { + int x_out; + uint8_t* const dst = wrk->dst; + rescaler_t* const irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* const frow = wrk->frow; + const __m128i mult = _mm_set_epi32(0, wrk->fy_scale, 0, wrk->fy_scale); + + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0 && wrk->y_sub + wrk->y_accum >= 0); + assert(wrk->y_expand); + if (wrk->y_accum == 0) { + for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) { + __m128i A0, A1, A2, A3; + LoadDispatchAndMult_SSE2(frow + x_out, NULL, &A0, &A1, &A2, &A3); + ProcessRow_SSE2(&A0, &A1, &A2, &A3, &mult, dst + x_out); + } + for (; x_out < x_out_max; ++x_out) { + const uint32_t J = frow[x_out]; + const int v = (int)MULT_FIX(J, wrk->fy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + } + } else { + const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); + const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); + const __m128i mA = _mm_set_epi32(0, A, 0, A); + const __m128i mB = _mm_set_epi32(0, B, 0, B); + const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER); + for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) { + __m128i A0, A1, A2, A3, B0, B1, B2, B3; + LoadDispatchAndMult_SSE2(frow + x_out, &mA, &A0, &A1, &A2, &A3); + LoadDispatchAndMult_SSE2(irow + x_out, &mB, &B0, &B1, &B2, &B3); + { + const __m128i C0 = _mm_add_epi64(A0, B0); + const __m128i C1 = _mm_add_epi64(A1, B1); + const __m128i C2 = _mm_add_epi64(A2, B2); + const __m128i C3 = _mm_add_epi64(A3, B3); + const __m128i D0 = _mm_add_epi64(C0, rounder); + const __m128i D1 = _mm_add_epi64(C1, rounder); + const __m128i D2 = _mm_add_epi64(C2, rounder); + const __m128i D3 = _mm_add_epi64(C3, rounder); + const __m128i E0 = _mm_srli_epi64(D0, WEBP_RESCALER_RFIX); + const __m128i E1 = _mm_srli_epi64(D1, WEBP_RESCALER_RFIX); + const __m128i E2 = _mm_srli_epi64(D2, WEBP_RESCALER_RFIX); + const __m128i E3 = _mm_srli_epi64(D3, WEBP_RESCALER_RFIX); + ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult, dst + x_out); + } + } + for (; x_out < x_out_max; ++x_out) { + const uint64_t I = (uint64_t)A * frow[x_out] + + (uint64_t)B * irow[x_out]; + const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); + const int v = (int)MULT_FIX(J, wrk->fy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + } + } +} + +static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) { + int x_out; + uint8_t* const dst = wrk->dst; + rescaler_t* const irow = wrk->irow; + const int x_out_max = wrk->dst_width * wrk->num_channels; + const rescaler_t* const frow = wrk->frow; + const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); + assert(!WebPRescalerOutputDone(wrk)); + assert(wrk->y_accum <= 0); + assert(!wrk->y_expand); + if (yscale) { + const int scale_xy = wrk->fxy_scale; + const __m128i mult_xy = _mm_set_epi32(0, scale_xy, 0, scale_xy); + const __m128i mult_y = _mm_set_epi32(0, yscale, 0, yscale); + for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) { + __m128i A0, A1, A2, A3, B0, B1, B2, B3; + LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3); + LoadDispatchAndMult_SSE2(frow + x_out, &mult_y, &B0, &B1, &B2, &B3); + { + const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX); // = frac + const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX); + const __m128i D2 = _mm_srli_epi64(B2, WEBP_RESCALER_RFIX); + const __m128i D3 = _mm_srli_epi64(B3, WEBP_RESCALER_RFIX); + const __m128i E0 = _mm_sub_epi64(A0, D0); // irow[x] - frac + const __m128i E1 = _mm_sub_epi64(A1, D1); + const __m128i E2 = _mm_sub_epi64(A2, D2); + const __m128i E3 = _mm_sub_epi64(A3, D3); + const __m128i F2 = _mm_slli_epi64(D2, 32); + const __m128i F3 = _mm_slli_epi64(D3, 32); + const __m128i G0 = _mm_or_si128(D0, F2); + const __m128i G1 = _mm_or_si128(D1, F3); + _mm_storeu_si128((__m128i*)(irow + x_out + 0), G0); + _mm_storeu_si128((__m128i*)(irow + x_out + 4), G1); + ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out); + } + } + for (; x_out < x_out_max; ++x_out) { + const uint32_t frac = (int)MULT_FIX_FLOOR(frow[x_out], yscale); + const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + irow[x_out] = frac; // new fractional start + } + } else { + const uint32_t scale = wrk->fxy_scale; + const __m128i mult = _mm_set_epi32(0, scale, 0, scale); + const __m128i zero = _mm_setzero_si128(); + for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) { + __m128i A0, A1, A2, A3; + LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3); + _mm_storeu_si128((__m128i*)(irow + x_out + 0), zero); + _mm_storeu_si128((__m128i*)(irow + x_out + 4), zero); + ProcessRow_SSE2(&A0, &A1, &A2, &A3, &mult, dst + x_out); + } + for (; x_out < x_out_max; ++x_out) { + const int v = (int)MULT_FIX(irow[x_out], scale); + dst[x_out] = (v > 255) ? 255u : (uint8_t)v; + irow[x_out] = 0; + } + } +} + +#undef MULT_FIX_FLOOR +#undef MULT_FIX +#undef ROUNDER + +//------------------------------------------------------------------------------ + +extern void WebPRescalerDspInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitSSE2(void) { + WebPRescalerImportRowExpand = RescalerImportRowExpand_SSE2; + WebPRescalerImportRowShrink = RescalerImportRowShrink_SSE2; + WebPRescalerExportRowExpand = RescalerExportRowExpand_SSE2; + WebPRescalerExportRowShrink = RescalerExportRowShrink_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(WebPRescalerDspInitSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/ssim.c b/libraries/webp/src/dsp/ssim.c new file mode 100644 index 00000000000..9a1341ed958 --- /dev/null +++ b/libraries/webp/src/dsp/ssim.c @@ -0,0 +1,160 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// distortion calculation +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include // for abs() + +#include "src/dsp/dsp.h" + +#if !defined(WEBP_REDUCE_SIZE) + +//------------------------------------------------------------------------------ +// SSIM / PSNR + +// hat-shaped filter. Sum of coefficients is equal to 16. +static const uint32_t kWeight[2 * VP8_SSIM_KERNEL + 1] = { + 1, 2, 3, 4, 3, 2, 1 +}; +static const uint32_t kWeightSum = 16 * 16; // sum{kWeight}^2 + +static WEBP_INLINE double SSIMCalculation( + const VP8DistoStats* const stats, uint32_t N /*num samples*/) { + const uint32_t w2 = N * N; + const uint32_t C1 = 20 * w2; + const uint32_t C2 = 60 * w2; + const uint32_t C3 = 8 * 8 * w2; // 'dark' limit ~= 6 + const uint64_t xmxm = (uint64_t)stats->xm * stats->xm; + const uint64_t ymym = (uint64_t)stats->ym * stats->ym; + if (xmxm + ymym >= C3) { + const int64_t xmym = (int64_t)stats->xm * stats->ym; + const int64_t sxy = (int64_t)stats->xym * N - xmym; // can be negative + const uint64_t sxx = (uint64_t)stats->xxm * N - xmxm; + const uint64_t syy = (uint64_t)stats->yym * N - ymym; + // we descale by 8 to prevent overflow during the fnum/fden multiply. + const uint64_t num_S = (2 * (uint64_t)(sxy < 0 ? 0 : sxy) + C2) >> 8; + const uint64_t den_S = (sxx + syy + C2) >> 8; + const uint64_t fnum = (2 * xmym + C1) * num_S; + const uint64_t fden = (xmxm + ymym + C1) * den_S; + const double r = (double)fnum / fden; + assert(r >= 0. && r <= 1.0); + return r; + } + return 1.; // area is too dark to contribute meaningfully +} + +double VP8SSIMFromStats(const VP8DistoStats* const stats) { + return SSIMCalculation(stats, kWeightSum); +} + +double VP8SSIMFromStatsClipped(const VP8DistoStats* const stats) { + return SSIMCalculation(stats, stats->w); +} + +static double SSIMGetClipped_C(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2, + int xo, int yo, int W, int H) { + VP8DistoStats stats = { 0, 0, 0, 0, 0, 0 }; + const int ymin = (yo - VP8_SSIM_KERNEL < 0) ? 0 : yo - VP8_SSIM_KERNEL; + const int ymax = (yo + VP8_SSIM_KERNEL > H - 1) ? H - 1 + : yo + VP8_SSIM_KERNEL; + const int xmin = (xo - VP8_SSIM_KERNEL < 0) ? 0 : xo - VP8_SSIM_KERNEL; + const int xmax = (xo + VP8_SSIM_KERNEL > W - 1) ? W - 1 + : xo + VP8_SSIM_KERNEL; + int x, y; + src1 += ymin * stride1; + src2 += ymin * stride2; + for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) { + for (x = xmin; x <= xmax; ++x) { + const uint32_t w = kWeight[VP8_SSIM_KERNEL + x - xo] + * kWeight[VP8_SSIM_KERNEL + y - yo]; + const uint32_t s1 = src1[x]; + const uint32_t s2 = src2[x]; + stats.w += w; + stats.xm += w * s1; + stats.ym += w * s2; + stats.xxm += w * s1 * s1; + stats.xym += w * s1 * s2; + stats.yym += w * s2 * s2; + } + } + return VP8SSIMFromStatsClipped(&stats); +} + +static double SSIMGet_C(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2) { + VP8DistoStats stats = { 0, 0, 0, 0, 0, 0 }; + int x, y; + for (y = 0; y <= 2 * VP8_SSIM_KERNEL; ++y, src1 += stride1, src2 += stride2) { + for (x = 0; x <= 2 * VP8_SSIM_KERNEL; ++x) { + const uint32_t w = kWeight[x] * kWeight[y]; + const uint32_t s1 = src1[x]; + const uint32_t s2 = src2[x]; + stats.xm += w * s1; + stats.ym += w * s2; + stats.xxm += w * s1 * s1; + stats.xym += w * s1 * s2; + stats.yym += w * s2 * s2; + } + } + return VP8SSIMFromStats(&stats); +} + +#endif // !defined(WEBP_REDUCE_SIZE) + +//------------------------------------------------------------------------------ + +#if !defined(WEBP_DISABLE_STATS) +static uint32_t AccumulateSSE_C(const uint8_t* src1, + const uint8_t* src2, int len) { + int i; + uint32_t sse2 = 0; + assert(len <= 65535); // to ensure that accumulation fits within uint32_t + for (i = 0; i < len; ++i) { + const int32_t diff = src1[i] - src2[i]; + sse2 += diff * diff; + } + return sse2; +} +#endif + +//------------------------------------------------------------------------------ + +#if !defined(WEBP_REDUCE_SIZE) +VP8SSIMGetFunc VP8SSIMGet; +VP8SSIMGetClippedFunc VP8SSIMGetClipped; +#endif +#if !defined(WEBP_DISABLE_STATS) +VP8AccumulateSSEFunc VP8AccumulateSSE; +#endif + +extern VP8CPUInfo VP8GetCPUInfo; +extern void VP8SSIMDspInitSSE2(void); + +WEBP_DSP_INIT_FUNC(VP8SSIMDspInit) { +#if !defined(WEBP_REDUCE_SIZE) + VP8SSIMGetClipped = SSIMGetClipped_C; + VP8SSIMGet = SSIMGet_C; +#endif + +#if !defined(WEBP_DISABLE_STATS) + VP8AccumulateSSE = AccumulateSSE_C; +#endif + + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8SSIMDspInitSSE2(); + } +#endif + } +} diff --git a/libraries/webp/src/dsp/ssim_sse2.c b/libraries/webp/src/dsp/ssim_sse2.c new file mode 100644 index 00000000000..1dcb0eb0ec2 --- /dev/null +++ b/libraries/webp/src/dsp/ssim_sse2.c @@ -0,0 +1,165 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 version of distortion calculation +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) + +#include +#include + +#include "src/dsp/common_sse2.h" + +#if !defined(WEBP_DISABLE_STATS) + +// Helper function +static WEBP_INLINE void SubtractAndSquare_SSE2(const __m128i a, const __m128i b, + __m128i* const sum) { + // take abs(a-b) in 8b + const __m128i a_b = _mm_subs_epu8(a, b); + const __m128i b_a = _mm_subs_epu8(b, a); + const __m128i abs_a_b = _mm_or_si128(a_b, b_a); + // zero-extend to 16b + const __m128i zero = _mm_setzero_si128(); + const __m128i C0 = _mm_unpacklo_epi8(abs_a_b, zero); + const __m128i C1 = _mm_unpackhi_epi8(abs_a_b, zero); + // multiply with self + const __m128i sum1 = _mm_madd_epi16(C0, C0); + const __m128i sum2 = _mm_madd_epi16(C1, C1); + *sum = _mm_add_epi32(sum1, sum2); +} + +//------------------------------------------------------------------------------ +// SSIM / PSNR entry point + +static uint32_t AccumulateSSE_SSE2(const uint8_t* src1, + const uint8_t* src2, int len) { + int i = 0; + uint32_t sse2 = 0; + if (len >= 16) { + const int limit = len - 32; + int32_t tmp[4]; + __m128i sum1; + __m128i sum = _mm_setzero_si128(); + __m128i a0 = _mm_loadu_si128((const __m128i*)&src1[i]); + __m128i b0 = _mm_loadu_si128((const __m128i*)&src2[i]); + i += 16; + while (i <= limit) { + const __m128i a1 = _mm_loadu_si128((const __m128i*)&src1[i]); + const __m128i b1 = _mm_loadu_si128((const __m128i*)&src2[i]); + __m128i sum2; + i += 16; + SubtractAndSquare_SSE2(a0, b0, &sum1); + sum = _mm_add_epi32(sum, sum1); + a0 = _mm_loadu_si128((const __m128i*)&src1[i]); + b0 = _mm_loadu_si128((const __m128i*)&src2[i]); + i += 16; + SubtractAndSquare_SSE2(a1, b1, &sum2); + sum = _mm_add_epi32(sum, sum2); + } + SubtractAndSquare_SSE2(a0, b0, &sum1); + sum = _mm_add_epi32(sum, sum1); + _mm_storeu_si128((__m128i*)tmp, sum); + sse2 += (tmp[3] + tmp[2] + tmp[1] + tmp[0]); + } + + for (; i < len; ++i) { + const int32_t diff = src1[i] - src2[i]; + sse2 += diff * diff; + } + return sse2; +} +#endif // !defined(WEBP_DISABLE_STATS) + +#if !defined(WEBP_REDUCE_SIZE) + +static uint32_t HorizontalAdd16b_SSE2(const __m128i* const m) { + uint16_t tmp[8]; + const __m128i a = _mm_srli_si128(*m, 8); + const __m128i b = _mm_add_epi16(*m, a); + _mm_storeu_si128((__m128i*)tmp, b); + return (uint32_t)tmp[3] + tmp[2] + tmp[1] + tmp[0]; +} + +static uint32_t HorizontalAdd32b_SSE2(const __m128i* const m) { + const __m128i a = _mm_srli_si128(*m, 8); + const __m128i b = _mm_add_epi32(*m, a); + const __m128i c = _mm_add_epi32(b, _mm_srli_si128(b, 4)); + return (uint32_t)_mm_cvtsi128_si32(c); +} + +static const uint16_t kWeight[] = { 1, 2, 3, 4, 3, 2, 1, 0 }; + +#define ACCUMULATE_ROW(WEIGHT) do { \ + /* compute row weight (Wx * Wy) */ \ + const __m128i Wy = _mm_set1_epi16((WEIGHT)); \ + const __m128i W = _mm_mullo_epi16(Wx, Wy); \ + /* process 8 bytes at a time (7 bytes, actually) */ \ + const __m128i a0 = _mm_loadl_epi64((const __m128i*)src1); \ + const __m128i b0 = _mm_loadl_epi64((const __m128i*)src2); \ + /* convert to 16b and multiply by weight */ \ + const __m128i a1 = _mm_unpacklo_epi8(a0, zero); \ + const __m128i b1 = _mm_unpacklo_epi8(b0, zero); \ + const __m128i wa1 = _mm_mullo_epi16(a1, W); \ + const __m128i wb1 = _mm_mullo_epi16(b1, W); \ + /* accumulate */ \ + xm = _mm_add_epi16(xm, wa1); \ + ym = _mm_add_epi16(ym, wb1); \ + xxm = _mm_add_epi32(xxm, _mm_madd_epi16(a1, wa1)); \ + xym = _mm_add_epi32(xym, _mm_madd_epi16(a1, wb1)); \ + yym = _mm_add_epi32(yym, _mm_madd_epi16(b1, wb1)); \ + src1 += stride1; \ + src2 += stride2; \ +} while (0) + +static double SSIMGet_SSE2(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2) { + VP8DistoStats stats; + const __m128i zero = _mm_setzero_si128(); + __m128i xm = zero, ym = zero; // 16b accums + __m128i xxm = zero, yym = zero, xym = zero; // 32b accum + const __m128i Wx = _mm_loadu_si128((const __m128i*)kWeight); + assert(2 * VP8_SSIM_KERNEL + 1 == 7); + ACCUMULATE_ROW(1); + ACCUMULATE_ROW(2); + ACCUMULATE_ROW(3); + ACCUMULATE_ROW(4); + ACCUMULATE_ROW(3); + ACCUMULATE_ROW(2); + ACCUMULATE_ROW(1); + stats.xm = HorizontalAdd16b_SSE2(&xm); + stats.ym = HorizontalAdd16b_SSE2(&ym); + stats.xxm = HorizontalAdd32b_SSE2(&xxm); + stats.xym = HorizontalAdd32b_SSE2(&xym); + stats.yym = HorizontalAdd32b_SSE2(&yym); + return VP8SSIMFromStats(&stats); +} + +#endif // !defined(WEBP_REDUCE_SIZE) + +extern void VP8SSIMDspInitSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8SSIMDspInitSSE2(void) { +#if !defined(WEBP_DISABLE_STATS) + VP8AccumulateSSE = AccumulateSSE_SSE2; +#endif +#if !defined(WEBP_REDUCE_SIZE) + VP8SSIMGet = SSIMGet_SSE2; +#endif +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(VP8SSIMDspInitSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/upsampling.c b/libraries/webp/src/dsp/upsampling.c new file mode 100644 index 00000000000..983b9c42d36 --- /dev/null +++ b/libraries/webp/src/dsp/upsampling.c @@ -0,0 +1,328 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// YUV to RGB upsampling functions. +// +// Author: somnath@google.com (Somnath Banerjee) + +#include "src/dsp/dsp.h" +#include "src/dsp/yuv.h" + +#include + +//------------------------------------------------------------------------------ +// Fancy upsampler + +#ifdef FANCY_UPSAMPLING + +// Fancy upsampling functions to convert YUV to RGB +WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST]; + +// Given samples laid out in a square as: +// [a b] +// [c d] +// we interpolate u/v as: +// ([9*a + 3*b + 3*c + d 3*a + 9*b + 3*c + d] + [8 8]) / 16 +// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16 + +// We process u and v together stashed into 32bit (16bit each). +#define LOAD_UV(u, v) ((u) | ((v) << 16)) + +#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int x; \ + const int last_pixel_pair = (len - 1) >> 1; \ + uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \ + uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \ + assert(top_y != NULL); \ + { \ + const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ + FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \ + } \ + if (bottom_y != NULL) { \ + const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ + FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \ + } \ + for (x = 1; x <= last_pixel_pair; ++x) { \ + const uint32_t t_uv = LOAD_UV(top_u[x], top_v[x]); /* top sample */ \ + const uint32_t uv = LOAD_UV(cur_u[x], cur_v[x]); /* sample */ \ + /* precompute invariant values associated with first and second diagonals*/\ + const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \ + const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \ + const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \ + { \ + const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \ + const uint32_t uv1 = (diag_03 + t_uv) >> 1; \ + FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \ + top_dst + (2 * x - 1) * (XSTEP)); \ + FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \ + top_dst + (2 * x - 0) * (XSTEP)); \ + } \ + if (bottom_y != NULL) { \ + const uint32_t uv0 = (diag_03 + l_uv) >> 1; \ + const uint32_t uv1 = (diag_12 + uv) >> 1; \ + FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \ + bottom_dst + (2 * x - 1) * (XSTEP)); \ + FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \ + bottom_dst + (2 * x + 0) * (XSTEP)); \ + } \ + tl_uv = t_uv; \ + l_uv = uv; \ + } \ + if (!(len & 1)) { \ + { \ + const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ + FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \ + top_dst + (len - 1) * (XSTEP)); \ + } \ + if (bottom_y != NULL) { \ + const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ + FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \ + bottom_dst + (len - 1) * (XSTEP)); \ + } \ + } \ +} + +// All variants implemented. +#if !WEBP_NEON_OMIT_C_CODE +UPSAMPLE_FUNC(UpsampleRgbaLinePair_C, VP8YuvToRgba, 4) +UPSAMPLE_FUNC(UpsampleBgraLinePair_C, VP8YuvToBgra, 4) +#if !defined(WEBP_REDUCE_CSP) +UPSAMPLE_FUNC(UpsampleArgbLinePair_C, VP8YuvToArgb, 4) +UPSAMPLE_FUNC(UpsampleRgbLinePair_C, VP8YuvToRgb, 3) +UPSAMPLE_FUNC(UpsampleBgrLinePair_C, VP8YuvToBgr, 3) +UPSAMPLE_FUNC(UpsampleRgba4444LinePair_C, VP8YuvToRgba4444, 2) +UPSAMPLE_FUNC(UpsampleRgb565LinePair_C, VP8YuvToRgb565, 2) +#else +static void EmptyUpsampleFunc(const uint8_t* top_y, const uint8_t* bottom_y, + const uint8_t* top_u, const uint8_t* top_v, + const uint8_t* cur_u, const uint8_t* cur_v, + uint8_t* top_dst, uint8_t* bottom_dst, int len) { + (void)top_y; + (void)bottom_y; + (void)top_u; + (void)top_v; + (void)cur_u; + (void)cur_v; + (void)top_dst; + (void)bottom_dst; + (void)len; + assert(0); // COLORSPACE SUPPORT NOT COMPILED +} +#define UpsampleArgbLinePair_C EmptyUpsampleFunc +#define UpsampleRgbLinePair_C EmptyUpsampleFunc +#define UpsampleBgrLinePair_C EmptyUpsampleFunc +#define UpsampleRgba4444LinePair_C EmptyUpsampleFunc +#define UpsampleRgb565LinePair_C EmptyUpsampleFunc +#endif // WEBP_REDUCE_CSP + +#endif + +#undef LOAD_UV +#undef UPSAMPLE_FUNC + +#endif // FANCY_UPSAMPLING + +//------------------------------------------------------------------------------ + +#if !defined(FANCY_UPSAMPLING) +#define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* bot_u, const uint8_t* bot_v, \ + uint8_t* top_dst, uint8_t* bot_dst, int len) { \ + const int half_len = len >> 1; \ + int x; \ + assert(top_dst != NULL); \ + { \ + for (x = 0; x < half_len; ++x) { \ + FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x + 0); \ + FUNC(top_y[2 * x + 1], top_u[x], top_v[x], top_dst + 8 * x + 4); \ + } \ + if (len & 1) FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x); \ + } \ + if (bot_dst != NULL) { \ + for (x = 0; x < half_len; ++x) { \ + FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x + 0); \ + FUNC(bot_y[2 * x + 1], bot_u[x], bot_v[x], bot_dst + 8 * x + 4); \ + } \ + if (len & 1) FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x); \ + } \ +} + +DUAL_SAMPLE_FUNC(DualLineSamplerBGRA, VP8YuvToBgra) +DUAL_SAMPLE_FUNC(DualLineSamplerARGB, VP8YuvToArgb) +#undef DUAL_SAMPLE_FUNC + +#endif // !FANCY_UPSAMPLING + +WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) { + WebPInitUpsamplers(); +#ifdef FANCY_UPSAMPLING + return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB]; +#else + return (alpha_is_last ? DualLineSamplerBGRA : DualLineSamplerARGB); +#endif +} + +//------------------------------------------------------------------------------ +// YUV444 converter + +#define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \ +extern void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len); \ +void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + int i; \ + for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * (XSTEP)]); \ +} + +YUV444_FUNC(WebPYuv444ToRgba_C, VP8YuvToRgba, 4) +YUV444_FUNC(WebPYuv444ToBgra_C, VP8YuvToBgra, 4) +#if !defined(WEBP_REDUCE_CSP) +YUV444_FUNC(WebPYuv444ToRgb_C, VP8YuvToRgb, 3) +YUV444_FUNC(WebPYuv444ToBgr_C, VP8YuvToBgr, 3) +YUV444_FUNC(WebPYuv444ToArgb_C, VP8YuvToArgb, 4) +YUV444_FUNC(WebPYuv444ToRgba4444_C, VP8YuvToRgba4444, 2) +YUV444_FUNC(WebPYuv444ToRgb565_C, VP8YuvToRgb565, 2) +#else +static void EmptyYuv444Func(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + (void)y; + (void)u; + (void)v; + (void)dst; + (void)len; +} +#define WebPYuv444ToRgb_C EmptyYuv444Func +#define WebPYuv444ToBgr_C EmptyYuv444Func +#define WebPYuv444ToArgb_C EmptyYuv444Func +#define WebPYuv444ToRgba4444_C EmptyYuv444Func +#define WebPYuv444ToRgb565_C EmptyYuv444Func +#endif // WEBP_REDUCE_CSP + +#undef YUV444_FUNC + +WebPYUV444Converter WebPYUV444Converters[MODE_LAST]; + +extern VP8CPUInfo VP8GetCPUInfo; +extern void WebPInitYUV444ConvertersMIPSdspR2(void); +extern void WebPInitYUV444ConvertersSSE2(void); +extern void WebPInitYUV444ConvertersSSE41(void); + +WEBP_DSP_INIT_FUNC(WebPInitYUV444Converters) { + WebPYUV444Converters[MODE_RGBA] = WebPYuv444ToRgba_C; + WebPYUV444Converters[MODE_BGRA] = WebPYuv444ToBgra_C; + WebPYUV444Converters[MODE_RGB] = WebPYuv444ToRgb_C; + WebPYUV444Converters[MODE_BGR] = WebPYuv444ToBgr_C; + WebPYUV444Converters[MODE_ARGB] = WebPYuv444ToArgb_C; + WebPYUV444Converters[MODE_RGBA_4444] = WebPYuv444ToRgba4444_C; + WebPYUV444Converters[MODE_RGB_565] = WebPYuv444ToRgb565_C; + WebPYUV444Converters[MODE_rgbA] = WebPYuv444ToRgba_C; + WebPYUV444Converters[MODE_bgrA] = WebPYuv444ToBgra_C; + WebPYUV444Converters[MODE_Argb] = WebPYuv444ToArgb_C; + WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444_C; + + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + WebPInitYUV444ConvertersSSE2(); + } +#endif +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitYUV444ConvertersSSE41(); + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + WebPInitYUV444ConvertersMIPSdspR2(); + } +#endif + } +} + +//------------------------------------------------------------------------------ +// Main calls + +extern void WebPInitUpsamplersSSE2(void); +extern void WebPInitUpsamplersSSE41(void); +extern void WebPInitUpsamplersNEON(void); +extern void WebPInitUpsamplersMIPSdspR2(void); +extern void WebPInitUpsamplersMSA(void); + +WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) { +#ifdef FANCY_UPSAMPLING +#if !WEBP_NEON_OMIT_C_CODE + WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_C; + WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_C; + WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_C; + WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_C; + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_C; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_C; + WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_C; + WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_C; + WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_C; + WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_C; + WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_C; +#endif + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + WebPInitUpsamplersSSE2(); + } +#endif +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitUpsamplersSSE41(); + } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + WebPInitUpsamplersMIPSdspR2(); + } +#endif +#if defined(WEBP_USE_MSA) + if (VP8GetCPUInfo(kMSA)) { + WebPInitUpsamplersMSA(); + } +#endif + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + WebPInitUpsamplersNEON(); + } +#endif + + assert(WebPUpsamplers[MODE_RGBA] != NULL); + assert(WebPUpsamplers[MODE_BGRA] != NULL); + assert(WebPUpsamplers[MODE_rgbA] != NULL); + assert(WebPUpsamplers[MODE_bgrA] != NULL); +#if !defined(WEBP_REDUCE_CSP) || !WEBP_NEON_OMIT_C_CODE + assert(WebPUpsamplers[MODE_RGB] != NULL); + assert(WebPUpsamplers[MODE_BGR] != NULL); + assert(WebPUpsamplers[MODE_ARGB] != NULL); + assert(WebPUpsamplers[MODE_RGBA_4444] != NULL); + assert(WebPUpsamplers[MODE_RGB_565] != NULL); + assert(WebPUpsamplers[MODE_Argb] != NULL); + assert(WebPUpsamplers[MODE_rgbA_4444] != NULL); +#endif + +#endif // FANCY_UPSAMPLING +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/dsp/upsampling_mips_dsp_r2.c b/libraries/webp/src/dsp/upsampling_mips_dsp_r2.c new file mode 100644 index 00000000000..10d499d7712 --- /dev/null +++ b/libraries/webp/src/dsp/upsampling_mips_dsp_r2.c @@ -0,0 +1,291 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// YUV to RGB upsampling functions. +// +// Author(s): Branimir Vasic (branimir.vasic@imgtec.com) +// Djordje Pesut (djordje.pesut@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +#include +#include "src/dsp/yuv.h" + +#define YUV_TO_RGB(Y, U, V, R, G, B) do { \ + const int t1 = MultHi(Y, 19077); \ + const int t2 = MultHi(V, 13320); \ + R = MultHi(V, 26149); \ + G = MultHi(U, 6419); \ + B = MultHi(U, 33050); \ + R = t1 + R; \ + G = t1 - G; \ + B = t1 + B; \ + R = R - 14234; \ + G = G - t2 + 8708; \ + B = B - 17685; \ + __asm__ volatile ( \ + "shll_s.w %[" #R "], %[" #R "], 17 \n\t" \ + "shll_s.w %[" #G "], %[" #G "], 17 \n\t" \ + "shll_s.w %[" #B "], %[" #B "], 17 \n\t" \ + "precrqu_s.qb.ph %[" #R "], %[" #R "], $zero \n\t" \ + "precrqu_s.qb.ph %[" #G "], %[" #G "], $zero \n\t" \ + "precrqu_s.qb.ph %[" #B "], %[" #B "], $zero \n\t" \ + "srl %[" #R "], %[" #R "], 24 \n\t" \ + "srl %[" #G "], %[" #G "], 24 \n\t" \ + "srl %[" #B "], %[" #B "], 24 \n\t" \ + : [R]"+r"(R), [G]"+r"(G), [B]"+r"(B) \ + : \ + ); \ + } while (0) + +#if !defined(WEBP_REDUCE_CSP) +static WEBP_INLINE void YuvToRgb(int y, int u, int v, uint8_t* const rgb) { + int r, g, b; + YUV_TO_RGB(y, u, v, r, g, b); + rgb[0] = r; + rgb[1] = g; + rgb[2] = b; +} +static WEBP_INLINE void YuvToBgr(int y, int u, int v, uint8_t* const bgr) { + int r, g, b; + YUV_TO_RGB(y, u, v, r, g, b); + bgr[0] = b; + bgr[1] = g; + bgr[2] = r; +} +static WEBP_INLINE void YuvToRgb565(int y, int u, int v, uint8_t* const rgb) { + int r, g, b; + YUV_TO_RGB(y, u, v, r, g, b); + { + const int rg = (r & 0xf8) | (g >> 5); + const int gb = ((g << 3) & 0xe0) | (b >> 3); +#if (WEBP_SWAP_16BIT_CSP == 1) + rgb[0] = gb; + rgb[1] = rg; +#else + rgb[0] = rg; + rgb[1] = gb; +#endif + } +} +static WEBP_INLINE void YuvToRgba4444(int y, int u, int v, + uint8_t* const argb) { + int r, g, b; + YUV_TO_RGB(y, u, v, r, g, b); + { + const int rg = (r & 0xf0) | (g >> 4); + const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits +#if (WEBP_SWAP_16BIT_CSP == 1) + argb[0] = ba; + argb[1] = rg; +#else + argb[0] = rg; + argb[1] = ba; +#endif + } +} +#endif // WEBP_REDUCE_CSP + +//----------------------------------------------------------------------------- +// Alpha handling variants + +#if !defined(WEBP_REDUCE_CSP) +static WEBP_INLINE void YuvToArgb(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const argb) { + int r, g, b; + YUV_TO_RGB(y, u, v, r, g, b); + argb[0] = 0xff; + argb[1] = r; + argb[2] = g; + argb[3] = b; +} +#endif // WEBP_REDUCE_CSP +static WEBP_INLINE void YuvToBgra(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const bgra) { + int r, g, b; + YUV_TO_RGB(y, u, v, r, g, b); + bgra[0] = b; + bgra[1] = g; + bgra[2] = r; + bgra[3] = 0xff; +} +static WEBP_INLINE void YuvToRgba(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const rgba) { + int r, g, b; + YUV_TO_RGB(y, u, v, r, g, b); + rgba[0] = r; + rgba[1] = g; + rgba[2] = b; + rgba[3] = 0xff; +} + +//------------------------------------------------------------------------------ +// Fancy upsampler + +#ifdef FANCY_UPSAMPLING + +// Given samples laid out in a square as: +// [a b] +// [c d] +// we interpolate u/v as: +// ([9*a + 3*b + 3*c + d 3*a + 9*b + 3*c + d] + [8 8]) / 16 +// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16 + +// We process u and v together stashed into 32bit (16bit each). +#define LOAD_UV(u, v) ((u) | ((v) << 16)) + +#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int x; \ + const int last_pixel_pair = (len - 1) >> 1; \ + uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \ + uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \ + assert(top_y != NULL); \ + { \ + const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ + FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \ + } \ + if (bottom_y != NULL) { \ + const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ + FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \ + } \ + for (x = 1; x <= last_pixel_pair; ++x) { \ + const uint32_t t_uv = LOAD_UV(top_u[x], top_v[x]); /* top sample */ \ + const uint32_t uv = LOAD_UV(cur_u[x], cur_v[x]); /* sample */ \ + /* precompute invariant values associated with first and second diagonals*/\ + const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \ + const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \ + const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \ + { \ + const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \ + const uint32_t uv1 = (diag_03 + t_uv) >> 1; \ + FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \ + top_dst + (2 * x - 1) * XSTEP); \ + FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \ + top_dst + (2 * x - 0) * XSTEP); \ + } \ + if (bottom_y != NULL) { \ + const uint32_t uv0 = (diag_03 + l_uv) >> 1; \ + const uint32_t uv1 = (diag_12 + uv) >> 1; \ + FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \ + bottom_dst + (2 * x - 1) * XSTEP); \ + FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \ + bottom_dst + (2 * x + 0) * XSTEP); \ + } \ + tl_uv = t_uv; \ + l_uv = uv; \ + } \ + if (!(len & 1)) { \ + { \ + const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ + FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \ + top_dst + (len - 1) * XSTEP); \ + } \ + if (bottom_y != NULL) { \ + const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ + FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \ + bottom_dst + (len - 1) * XSTEP); \ + } \ + } \ +} + +// All variants implemented. +UPSAMPLE_FUNC(UpsampleRgbaLinePair, YuvToRgba, 4) +UPSAMPLE_FUNC(UpsampleBgraLinePair, YuvToBgra, 4) +#if !defined(WEBP_REDUCE_CSP) +UPSAMPLE_FUNC(UpsampleRgbLinePair, YuvToRgb, 3) +UPSAMPLE_FUNC(UpsampleBgrLinePair, YuvToBgr, 3) +UPSAMPLE_FUNC(UpsampleArgbLinePair, YuvToArgb, 4) +UPSAMPLE_FUNC(UpsampleRgba4444LinePair, YuvToRgba4444, 2) +UPSAMPLE_FUNC(UpsampleRgb565LinePair, YuvToRgb565, 2) +#endif // WEBP_REDUCE_CSP + +#undef LOAD_UV +#undef UPSAMPLE_FUNC + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitUpsamplersMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersMIPSdspR2(void) { + WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair; + WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair; + WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair; + WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair; +#if !defined(WEBP_REDUCE_CSP) + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair; + WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair; + WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair; + WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair; + WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair; + WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair; +#endif // WEBP_REDUCE_CSP +} + +#endif // FANCY_UPSAMPLING + +//------------------------------------------------------------------------------ +// YUV444 converter + +#define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + int i; \ + for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \ +} + +YUV444_FUNC(Yuv444ToRgba, YuvToRgba, 4) +YUV444_FUNC(Yuv444ToBgra, YuvToBgra, 4) +#if !defined(WEBP_REDUCE_CSP) +YUV444_FUNC(Yuv444ToRgb, YuvToRgb, 3) +YUV444_FUNC(Yuv444ToBgr, YuvToBgr, 3) +YUV444_FUNC(Yuv444ToArgb, YuvToArgb, 4) +YUV444_FUNC(Yuv444ToRgba4444, YuvToRgba4444, 2) +YUV444_FUNC(Yuv444ToRgb565, YuvToRgb565, 2) +#endif // WEBP_REDUCE_CSP + +#undef YUV444_FUNC + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitYUV444ConvertersMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersMIPSdspR2(void) { + WebPYUV444Converters[MODE_RGBA] = Yuv444ToRgba; + WebPYUV444Converters[MODE_BGRA] = Yuv444ToBgra; + WebPYUV444Converters[MODE_rgbA] = Yuv444ToRgba; + WebPYUV444Converters[MODE_bgrA] = Yuv444ToBgra; +#if !defined(WEBP_REDUCE_CSP) + WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb; + WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr; + WebPYUV444Converters[MODE_ARGB] = Yuv444ToArgb; + WebPYUV444Converters[MODE_RGBA_4444] = Yuv444ToRgba4444; + WebPYUV444Converters[MODE_RGB_565] = Yuv444ToRgb565; + WebPYUV444Converters[MODE_Argb] = Yuv444ToArgb; + WebPYUV444Converters[MODE_rgbA_4444] = Yuv444ToRgba4444; +#endif // WEBP_REDUCE_CSP +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 + +#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_MIPS_DSP_R2)) +WEBP_DSP_INIT_STUB(WebPInitUpsamplersMIPSdspR2) +#endif diff --git a/libraries/webp/src/dsp/upsampling_msa.c b/libraries/webp/src/dsp/upsampling_msa.c new file mode 100644 index 00000000000..f2e03e85e9d --- /dev/null +++ b/libraries/webp/src/dsp/upsampling_msa.c @@ -0,0 +1,688 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MSA version of YUV to RGB upsampling functions. +// +// Author: Prashant Patil (prashant.patil@imgtec.com) + +#include +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MSA) + +#include "src/dsp/msa_macro.h" +#include "src/dsp/yuv.h" + +#ifdef FANCY_UPSAMPLING + +#define ILVR_UW2(in, out0, out1) do { \ + const v8i16 t0 = (v8i16)__msa_ilvr_b((v16i8)zero, (v16i8)in); \ + out0 = (v4u32)__msa_ilvr_h((v8i16)zero, t0); \ + out1 = (v4u32)__msa_ilvl_h((v8i16)zero, t0); \ +} while (0) + +#define ILVRL_UW4(in, out0, out1, out2, out3) do { \ + v16u8 t0, t1; \ + ILVRL_B2_UB(zero, in, t0, t1); \ + ILVRL_H2_UW(zero, t0, out0, out1); \ + ILVRL_H2_UW(zero, t1, out2, out3); \ +} while (0) + +#define MULTHI_16(in0, in1, in2, in3, cnst, out0, out1) do { \ + const v4i32 const0 = (v4i32)__msa_fill_w(cnst * 256); \ + v4u32 temp0, temp1, temp2, temp3; \ + MUL4(in0, const0, in1, const0, in2, const0, in3, const0, \ + temp0, temp1, temp2, temp3); \ + PCKOD_H2_UH(temp1, temp0, temp3, temp2, out0, out1); \ +} while (0) + +#define MULTHI_8(in0, in1, cnst, out0) do { \ + const v4i32 const0 = (v4i32)__msa_fill_w(cnst * 256); \ + v4u32 temp0, temp1; \ + MUL2(in0, const0, in1, const0, temp0, temp1); \ + out0 = (v8u16)__msa_pckod_h((v8i16)temp1, (v8i16)temp0); \ +} while (0) + +#define CALC_R16(y0, y1, v0, v1, dst) do { \ + const v8i16 const_a = (v8i16)__msa_fill_h(14234); \ + const v8i16 a0 = __msa_adds_s_h((v8i16)y0, (v8i16)v0); \ + const v8i16 a1 = __msa_adds_s_h((v8i16)y1, (v8i16)v1); \ + v8i16 b0 = __msa_subs_s_h(a0, const_a); \ + v8i16 b1 = __msa_subs_s_h(a1, const_a); \ + SRAI_H2_SH(b0, b1, 6); \ + CLIP_SH2_0_255(b0, b1); \ + dst = (v16u8)__msa_pckev_b((v16i8)b1, (v16i8)b0); \ +} while (0) + +#define CALC_R8(y0, v0, dst) do { \ + const v8i16 const_a = (v8i16)__msa_fill_h(14234); \ + const v8i16 a0 = __msa_adds_s_h((v8i16)y0, (v8i16)v0); \ + v8i16 b0 = __msa_subs_s_h(a0, const_a); \ + b0 = SRAI_H(b0, 6); \ + CLIP_SH_0_255(b0); \ + dst = (v16u8)__msa_pckev_b((v16i8)b0, (v16i8)b0); \ +} while (0) + +#define CALC_G16(y0, y1, u0, u1, v0, v1, dst) do { \ + const v8i16 const_a = (v8i16)__msa_fill_h(8708); \ + v8i16 a0 = __msa_subs_s_h((v8i16)y0, (v8i16)u0); \ + v8i16 a1 = __msa_subs_s_h((v8i16)y1, (v8i16)u1); \ + const v8i16 b0 = __msa_subs_s_h(a0, (v8i16)v0); \ + const v8i16 b1 = __msa_subs_s_h(a1, (v8i16)v1); \ + a0 = __msa_adds_s_h(b0, const_a); \ + a1 = __msa_adds_s_h(b1, const_a); \ + SRAI_H2_SH(a0, a1, 6); \ + CLIP_SH2_0_255(a0, a1); \ + dst = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0); \ +} while (0) + +#define CALC_G8(y0, u0, v0, dst) do { \ + const v8i16 const_a = (v8i16)__msa_fill_h(8708); \ + v8i16 a0 = __msa_subs_s_h((v8i16)y0, (v8i16)u0); \ + const v8i16 b0 = __msa_subs_s_h(a0, (v8i16)v0); \ + a0 = __msa_adds_s_h(b0, const_a); \ + a0 = SRAI_H(a0, 6); \ + CLIP_SH_0_255(a0); \ + dst = (v16u8)__msa_pckev_b((v16i8)a0, (v16i8)a0); \ +} while (0) + +#define CALC_B16(y0, y1, u0, u1, dst) do { \ + const v8u16 const_a = (v8u16)__msa_fill_h(17685); \ + const v8u16 a0 = __msa_adds_u_h((v8u16)y0, u0); \ + const v8u16 a1 = __msa_adds_u_h((v8u16)y1, u1); \ + v8u16 b0 = __msa_subs_u_h(a0, const_a); \ + v8u16 b1 = __msa_subs_u_h(a1, const_a); \ + SRAI_H2_UH(b0, b1, 6); \ + CLIP_UH2_0_255(b0, b1); \ + dst = (v16u8)__msa_pckev_b((v16i8)b1, (v16i8)b0); \ +} while (0) + +#define CALC_B8(y0, u0, dst) do { \ + const v8u16 const_a = (v8u16)__msa_fill_h(17685); \ + const v8u16 a0 = __msa_adds_u_h((v8u16)y0, u0); \ + v8u16 b0 = __msa_subs_u_h(a0, const_a); \ + b0 = SRAI_H(b0, 6); \ + CLIP_UH_0_255(b0); \ + dst = (v16u8)__msa_pckev_b((v16i8)b0, (v16i8)b0); \ +} while (0) + +#define CALC_RGB16(y, u, v, R, G, B) do { \ + const v16u8 zero = { 0 }; \ + v8u16 y0, y1, u0, u1, v0, v1; \ + v4u32 p0, p1, p2, p3; \ + const v16u8 in_y = LD_UB(y); \ + const v16u8 in_u = LD_UB(u); \ + const v16u8 in_v = LD_UB(v); \ + ILVRL_UW4(in_y, p0, p1, p2, p3); \ + MULTHI_16(p0, p1, p2, p3, 19077, y0, y1); \ + ILVRL_UW4(in_v, p0, p1, p2, p3); \ + MULTHI_16(p0, p1, p2, p3, 26149, v0, v1); \ + CALC_R16(y0, y1, v0, v1, R); \ + MULTHI_16(p0, p1, p2, p3, 13320, v0, v1); \ + ILVRL_UW4(in_u, p0, p1, p2, p3); \ + MULTHI_16(p0, p1, p2, p3, 6419, u0, u1); \ + CALC_G16(y0, y1, u0, u1, v0, v1, G); \ + MULTHI_16(p0, p1, p2, p3, 33050, u0, u1); \ + CALC_B16(y0, y1, u0, u1, B); \ +} while (0) + +#define CALC_RGB8(y, u, v, R, G, B) do { \ + const v16u8 zero = { 0 }; \ + v8u16 y0, u0, v0; \ + v4u32 p0, p1; \ + const v16u8 in_y = LD_UB(y); \ + const v16u8 in_u = LD_UB(u); \ + const v16u8 in_v = LD_UB(v); \ + ILVR_UW2(in_y, p0, p1); \ + MULTHI_8(p0, p1, 19077, y0); \ + ILVR_UW2(in_v, p0, p1); \ + MULTHI_8(p0, p1, 26149, v0); \ + CALC_R8(y0, v0, R); \ + MULTHI_8(p0, p1, 13320, v0); \ + ILVR_UW2(in_u, p0, p1); \ + MULTHI_8(p0, p1, 6419, u0); \ + CALC_G8(y0, u0, v0, G); \ + MULTHI_8(p0, p1, 33050, u0); \ + CALC_B8(y0, u0, B); \ +} while (0) + +#define STORE16_3(a0, a1, a2, dst) do { \ + const v16u8 mask0 = { 0, 1, 16, 2, 3, 17, 4, 5, 18, 6, 7, 19, \ + 8, 9, 20, 10 }; \ + const v16u8 mask1 = { 0, 21, 1, 2, 22, 3, 4, 23, 5, 6, 24, 7, \ + 8, 25, 9, 10 }; \ + const v16u8 mask2 = { 26, 0, 1, 27, 2, 3, 28, 4, 5, 29, 6, 7, \ + 30, 8, 9, 31 }; \ + v16u8 out0, out1, out2, tmp0, tmp1, tmp2; \ + ILVRL_B2_UB(a1, a0, tmp0, tmp1); \ + out0 = VSHF_UB(tmp0, a2, mask0); \ + tmp2 = SLDI_UB(tmp1, tmp0, 11); \ + out1 = VSHF_UB(tmp2, a2, mask1); \ + tmp2 = SLDI_UB(tmp1, tmp1, 6); \ + out2 = VSHF_UB(tmp2, a2, mask2); \ + ST_UB(out0, dst + 0); \ + ST_UB(out1, dst + 16); \ + ST_UB(out2, dst + 32); \ +} while (0) + +#define STORE8_3(a0, a1, a2, dst) do { \ + int64_t out_m; \ + const v16u8 mask0 = { 0, 1, 16, 2, 3, 17, 4, 5, 18, 6, 7, 19, \ + 8, 9, 20, 10 }; \ + const v16u8 mask1 = { 11, 21, 12, 13, 22, 14, 15, 23, \ + 255, 255, 255, 255, 255, 255, 255, 255 }; \ + const v16u8 tmp0 = (v16u8)__msa_ilvr_b((v16i8)a1, (v16i8)a0); \ + v16u8 out0, out1; \ + VSHF_B2_UB(tmp0, a2, tmp0, a2, mask0, mask1, out0, out1); \ + ST_UB(out0, dst); \ + out_m = __msa_copy_s_d((v2i64)out1, 0); \ + SD(out_m, dst + 16); \ +} while (0) + +#define STORE16_4(a0, a1, a2, a3, dst) do { \ + v16u8 tmp0, tmp1, tmp2, tmp3; \ + v16u8 out0, out1, out2, out3; \ + ILVRL_B2_UB(a1, a0, tmp0, tmp1); \ + ILVRL_B2_UB(a3, a2, tmp2, tmp3); \ + ILVRL_H2_UB(tmp2, tmp0, out0, out1); \ + ILVRL_H2_UB(tmp3, tmp1, out2, out3); \ + ST_UB(out0, dst + 0); \ + ST_UB(out1, dst + 16); \ + ST_UB(out2, dst + 32); \ + ST_UB(out3, dst + 48); \ +} while (0) + +#define STORE8_4(a0, a1, a2, a3, dst) do { \ + v16u8 tmp0, tmp1, tmp2, tmp3; \ + ILVR_B2_UB(a1, a0, a3, a2, tmp0, tmp1); \ + ILVRL_H2_UB(tmp1, tmp0, tmp2, tmp3); \ + ST_UB(tmp2, dst + 0); \ + ST_UB(tmp3, dst + 16); \ +} while (0) + +#define STORE2_16(a0, a1, dst) do { \ + v16u8 out0, out1; \ + ILVRL_B2_UB(a1, a0, out0, out1); \ + ST_UB(out0, dst + 0); \ + ST_UB(out1, dst + 16); \ +} while (0) + +#define STORE2_8(a0, a1, dst) do { \ + const v16u8 out0 = (v16u8)__msa_ilvr_b((v16i8)a1, (v16i8)a0); \ + ST_UB(out0, dst); \ +} while (0) + +#define CALC_RGBA4444(y, u, v, out0, out1, N, dst) do { \ + CALC_RGB##N(y, u, v, R, G, B); \ + tmp0 = ANDI_B(R, 0xf0); \ + tmp1 = SRAI_B(G, 4); \ + RG = tmp0 | tmp1; \ + tmp0 = ANDI_B(B, 0xf0); \ + BA = ORI_B(tmp0, 0x0f); \ + STORE2_##N(out0, out1, dst); \ +} while (0) + +#define CALC_RGB565(y, u, v, out0, out1, N, dst) do { \ + CALC_RGB##N(y, u, v, R, G, B); \ + tmp0 = ANDI_B(R, 0xf8); \ + tmp1 = SRAI_B(G, 5); \ + RG = tmp0 | tmp1; \ + tmp0 = SLLI_B(G, 3); \ + tmp1 = ANDI_B(tmp0, 0xe0); \ + tmp0 = SRAI_B(B, 3); \ + GB = tmp0 | tmp1; \ + STORE2_##N(out0, out1, dst); \ +} while (0) + +static WEBP_INLINE int Clip8(int v) { + return v < 0 ? 0 : v > 255 ? 255 : v; +} + +static void YuvToRgb(int y, int u, int v, uint8_t* const rgb) { + const int y1 = MultHi(y, 19077); + const int r1 = y1 + MultHi(v, 26149) - 14234; + const int g1 = y1 - MultHi(u, 6419) - MultHi(v, 13320) + 8708; + const int b1 = y1 + MultHi(u, 33050) - 17685; + rgb[0] = Clip8(r1 >> 6); + rgb[1] = Clip8(g1 >> 6); + rgb[2] = Clip8(b1 >> 6); +} + +static void YuvToBgr(int y, int u, int v, uint8_t* const bgr) { + const int y1 = MultHi(y, 19077); + const int r1 = y1 + MultHi(v, 26149) - 14234; + const int g1 = y1 - MultHi(u, 6419) - MultHi(v, 13320) + 8708; + const int b1 = y1 + MultHi(u, 33050) - 17685; + bgr[0] = Clip8(b1 >> 6); + bgr[1] = Clip8(g1 >> 6); + bgr[2] = Clip8(r1 >> 6); +} + +#if !defined(WEBP_REDUCE_CSP) +static void YuvToRgb565(int y, int u, int v, uint8_t* const rgb) { + const int y1 = MultHi(y, 19077); + const int r1 = y1 + MultHi(v, 26149) - 14234; + const int g1 = y1 - MultHi(u, 6419) - MultHi(v, 13320) + 8708; + const int b1 = y1 + MultHi(u, 33050) - 17685; + const int r = Clip8(r1 >> 6); + const int g = Clip8(g1 >> 6); + const int b = Clip8(b1 >> 6); + const int rg = (r & 0xf8) | (g >> 5); + const int gb = ((g << 3) & 0xe0) | (b >> 3); +#if (WEBP_SWAP_16BIT_CSP == 1) + rgb[0] = gb; + rgb[1] = rg; +#else + rgb[0] = rg; + rgb[1] = gb; +#endif +} + +static void YuvToRgba4444(int y, int u, int v, uint8_t* const argb) { + const int y1 = MultHi(y, 19077); + const int r1 = y1 + MultHi(v, 26149) - 14234; + const int g1 = y1 - MultHi(u, 6419) - MultHi(v, 13320) + 8708; + const int b1 = y1 + MultHi(u, 33050) - 17685; + const int r = Clip8(r1 >> 6); + const int g = Clip8(g1 >> 6); + const int b = Clip8(b1 >> 6); + const int rg = (r & 0xf0) | (g >> 4); + const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits +#if (WEBP_SWAP_16BIT_CSP == 1) + argb[0] = ba; + argb[1] = rg; +#else + argb[0] = rg; + argb[1] = ba; +#endif +} + +static void YuvToArgb(uint8_t y, uint8_t u, uint8_t v, uint8_t* const argb) { + argb[0] = 0xff; + YuvToRgb(y, u, v, argb + 1); +} +#endif // WEBP_REDUCE_CSP + +static void YuvToBgra(uint8_t y, uint8_t u, uint8_t v, uint8_t* const bgra) { + YuvToBgr(y, u, v, bgra); + bgra[3] = 0xff; +} + +static void YuvToRgba(uint8_t y, uint8_t u, uint8_t v, uint8_t* const rgba) { + YuvToRgb(y, u, v, rgba); + rgba[3] = 0xff; +} + +#if !defined(WEBP_REDUCE_CSP) +static void YuvToRgbLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_3(R, G, B, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 3; + length -= 16; + } + if (length > 8) { + uint8_t temp[3 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(temp, u, v, R, G, B); + STORE16_3(R, G, B, temp); + memcpy(dst, temp, length * 3 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[3 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_3(R, G, B, temp); + memcpy(dst, temp, length * 3 * sizeof(*dst)); + } +} + +static void YuvToBgrLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_3(B, G, R, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 3; + length -= 16; + } + if (length > 8) { + uint8_t temp[3 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(temp, u, v, R, G, B); + STORE16_3(B, G, R, temp); + memcpy(dst, temp, length * 3 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[3 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_3(B, G, R, temp); + memcpy(dst, temp, length * 3 * sizeof(*dst)); + } +} +#endif // WEBP_REDUCE_CSP + +static void YuvToRgbaLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + const v16u8 A = (v16u8)__msa_ldi_b(ALPHAVAL); + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_4(R, G, B, A, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 4; + length -= 16; + } + if (length > 8) { + uint8_t temp[4 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(&temp[0], u, v, R, G, B); + STORE16_4(R, G, B, A, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[4 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_4(R, G, B, A, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } +} + +static void YuvToBgraLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + const v16u8 A = (v16u8)__msa_ldi_b(ALPHAVAL); + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_4(B, G, R, A, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 4; + length -= 16; + } + if (length > 8) { + uint8_t temp[4 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(temp, u, v, R, G, B); + STORE16_4(B, G, R, A, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[4 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_4(B, G, R, A, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } +} + +#if !defined(WEBP_REDUCE_CSP) +static void YuvToArgbLine(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B; + const v16u8 A = (v16u8)__msa_ldi_b(ALPHAVAL); + while (length >= 16) { + CALC_RGB16(y, u, v, R, G, B); + STORE16_4(A, R, G, B, dst); + y += 16; + u += 16; + v += 16; + dst += 16 * 4; + length -= 16; + } + if (length > 8) { + uint8_t temp[4 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB16(temp, u, v, R, G, B); + STORE16_4(A, R, G, B, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[4 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); + CALC_RGB8(temp, u, v, R, G, B); + STORE8_4(A, R, G, B, temp); + memcpy(dst, temp, length * 4 * sizeof(*dst)); + } +} + +static void YuvToRgba4444Line(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B, RG, BA, tmp0, tmp1; + while (length >= 16) { +#if (WEBP_SWAP_16BIT_CSP == 1) + CALC_RGBA4444(y, u, v, BA, RG, 16, dst); +#else + CALC_RGBA4444(y, u, v, RG, BA, 16, dst); +#endif + y += 16; + u += 16; + v += 16; + dst += 16 * 2; + length -= 16; + } + if (length > 8) { + uint8_t temp[2 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); +#if (WEBP_SWAP_16BIT_CSP == 1) + CALC_RGBA4444(temp, u, v, BA, RG, 16, temp); +#else + CALC_RGBA4444(temp, u, v, RG, BA, 16, temp); +#endif + memcpy(dst, temp, length * 2 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[2 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); +#if (WEBP_SWAP_16BIT_CSP == 1) + CALC_RGBA4444(temp, u, v, BA, RG, 8, temp); +#else + CALC_RGBA4444(temp, u, v, RG, BA, 8, temp); +#endif + memcpy(dst, temp, length * 2 * sizeof(*dst)); + } +} + +static void YuvToRgb565Line(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst, int length) { + v16u8 R, G, B, RG, GB, tmp0, tmp1; + while (length >= 16) { +#if (WEBP_SWAP_16BIT_CSP == 1) + CALC_RGB565(y, u, v, GB, RG, 16, dst); +#else + CALC_RGB565(y, u, v, RG, GB, 16, dst); +#endif + y += 16; + u += 16; + v += 16; + dst += 16 * 2; + length -= 16; + } + if (length > 8) { + uint8_t temp[2 * 16] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); +#if (WEBP_SWAP_16BIT_CSP == 1) + CALC_RGB565(temp, u, v, GB, RG, 16, temp); +#else + CALC_RGB565(temp, u, v, RG, GB, 16, temp); +#endif + memcpy(dst, temp, length * 2 * sizeof(*dst)); + } else if (length > 0) { + uint8_t temp[2 * 8] = { 0 }; + memcpy(temp, y, length * sizeof(*temp)); +#if (WEBP_SWAP_16BIT_CSP == 1) + CALC_RGB565(temp, u, v, GB, RG, 8, temp); +#else + CALC_RGB565(temp, u, v, RG, GB, 8, temp); +#endif + memcpy(dst, temp, length * 2 * sizeof(*dst)); + } +} +#endif // WEBP_REDUCE_CSP + +#define UPSAMPLE_32PIXELS(a, b, c, d) do { \ + v16u8 s = __msa_aver_u_b(a, d); \ + v16u8 t = __msa_aver_u_b(b, c); \ + const v16u8 st = s ^ t; \ + v16u8 ad = a ^ d; \ + v16u8 bc = b ^ c; \ + v16u8 t0 = ad | bc; \ + v16u8 t1 = t0 | st; \ + v16u8 t2 = ANDI_B(t1, 1); \ + v16u8 t3 = __msa_aver_u_b(s, t); \ + const v16u8 k = t3 - t2; \ + v16u8 diag1, diag2; \ + AVER_UB2_UB(t, k, s, k, t0, t1); \ + bc = bc & st; \ + ad = ad & st; \ + t = t ^ k; \ + s = s ^ k; \ + t2 = bc | t; \ + t3 = ad | s; \ + t2 = ANDI_B(t2, 1); \ + t3 = ANDI_B(t3, 1); \ + SUB2(t0, t2, t1, t3, diag1, diag2); \ + AVER_UB2_UB(a, diag1, b, diag2, t0, t1); \ + ILVRL_B2_UB(t1, t0, a, b); \ + if (pbot_y != NULL) { \ + AVER_UB2_UB(c, diag2, d, diag1, t0, t1); \ + ILVRL_B2_UB(t1, t0, c, d); \ + } \ +} while (0) + +#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bot_dst, int len) \ +{ \ + int size = (len - 1) >> 1; \ + uint8_t temp_u[64]; \ + uint8_t temp_v[64]; \ + const uint32_t tl_uv = ((top_u[0]) | ((top_v[0]) << 16)); \ + const uint32_t l_uv = ((cur_u[0]) | ((cur_v[0]) << 16)); \ + const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ + const uint8_t* ptop_y = &top_y[1]; \ + uint8_t* ptop_dst = top_dst + XSTEP; \ + const uint8_t* pbot_y = &bot_y[1]; \ + uint8_t* pbot_dst = bot_dst + XSTEP; \ + \ + FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \ + if (bot_y != NULL) { \ + const uint32_t uv1 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ + FUNC(bot_y[0], uv1 & 0xff, (uv1 >> 16), bot_dst); \ + } \ + while (size >= 16) { \ + v16u8 tu0, tu1, tv0, tv1, cu0, cu1, cv0, cv1; \ + LD_UB2(top_u, 1, tu0, tu1); \ + LD_UB2(cur_u, 1, cu0, cu1); \ + LD_UB2(top_v, 1, tv0, tv1); \ + LD_UB2(cur_v, 1, cv0, cv1); \ + UPSAMPLE_32PIXELS(tu0, tu1, cu0, cu1); \ + UPSAMPLE_32PIXELS(tv0, tv1, cv0, cv1); \ + ST_UB4(tu0, tu1, cu0, cu1, &temp_u[0], 16); \ + ST_UB4(tv0, tv1, cv0, cv1, &temp_v[0], 16); \ + FUNC##Line(ptop_y, &temp_u[ 0], &temp_v[0], ptop_dst, 32); \ + if (bot_y != NULL) { \ + FUNC##Line(pbot_y, &temp_u[32], &temp_v[32], pbot_dst, 32); \ + } \ + ptop_y += 32; \ + pbot_y += 32; \ + ptop_dst += XSTEP * 32; \ + pbot_dst += XSTEP * 32; \ + top_u += 16; \ + top_v += 16; \ + cur_u += 16; \ + cur_v += 16; \ + size -= 16; \ + } \ + if (size > 0) { \ + v16u8 tu0, tu1, tv0, tv1, cu0, cu1, cv0, cv1; \ + memcpy(&temp_u[ 0], top_u, 17 * sizeof(uint8_t)); \ + memcpy(&temp_u[32], cur_u, 17 * sizeof(uint8_t)); \ + memcpy(&temp_v[ 0], top_v, 17 * sizeof(uint8_t)); \ + memcpy(&temp_v[32], cur_v, 17 * sizeof(uint8_t)); \ + LD_UB2(&temp_u[ 0], 1, tu0, tu1); \ + LD_UB2(&temp_u[32], 1, cu0, cu1); \ + LD_UB2(&temp_v[ 0], 1, tv0, tv1); \ + LD_UB2(&temp_v[32], 1, cv0, cv1); \ + UPSAMPLE_32PIXELS(tu0, tu1, cu0, cu1); \ + UPSAMPLE_32PIXELS(tv0, tv1, cv0, cv1); \ + ST_UB4(tu0, tu1, cu0, cu1, &temp_u[0], 16); \ + ST_UB4(tv0, tv1, cv0, cv1, &temp_v[0], 16); \ + FUNC##Line(ptop_y, &temp_u[ 0], &temp_v[0], ptop_dst, size * 2); \ + if (bot_y != NULL) { \ + FUNC##Line(pbot_y, &temp_u[32], &temp_v[32], pbot_dst, size * 2); \ + } \ + top_u += size; \ + top_v += size; \ + cur_u += size; \ + cur_v += size; \ + } \ + if (!(len & 1)) { \ + const uint32_t t0 = ((top_u[0]) | ((top_v[0]) << 16)); \ + const uint32_t c0 = ((cur_u[0]) | ((cur_v[0]) << 16)); \ + const uint32_t tmp0 = (3 * t0 + c0 + 0x00020002u) >> 2; \ + FUNC(top_y[len - 1], tmp0 & 0xff, (tmp0 >> 16), \ + top_dst + (len - 1) * XSTEP); \ + if (bot_y != NULL) { \ + const uint32_t tmp1 = (3 * c0 + t0 + 0x00020002u) >> 2; \ + FUNC(bot_y[len - 1], tmp1 & 0xff, (tmp1 >> 16), \ + bot_dst + (len - 1) * XSTEP); \ + } \ + } \ +} + +UPSAMPLE_FUNC(UpsampleRgbaLinePair, YuvToRgba, 4) +UPSAMPLE_FUNC(UpsampleBgraLinePair, YuvToBgra, 4) +#if !defined(WEBP_REDUCE_CSP) +UPSAMPLE_FUNC(UpsampleRgbLinePair, YuvToRgb, 3) +UPSAMPLE_FUNC(UpsampleBgrLinePair, YuvToBgr, 3) +UPSAMPLE_FUNC(UpsampleArgbLinePair, YuvToArgb, 4) +UPSAMPLE_FUNC(UpsampleRgba4444LinePair, YuvToRgba4444, 2) +UPSAMPLE_FUNC(UpsampleRgb565LinePair, YuvToRgb565, 2) +#endif // WEBP_REDUCE_CSP + +//------------------------------------------------------------------------------ +// Entry point + +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +extern void WebPInitUpsamplersMSA(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersMSA(void) { + WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair; + WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair; + WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair; + WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair; +#if !defined(WEBP_REDUCE_CSP) + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair; + WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair; + WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair; + WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair; + WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair; + WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair; +#endif // WEBP_REDUCE_CSP +} + +#endif // FANCY_UPSAMPLING + +#endif // WEBP_USE_MSA + +#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_MSA)) +WEBP_DSP_INIT_STUB(WebPInitUpsamplersMSA) +#endif diff --git a/libraries/webp/src/dsp/upsampling_neon.c b/libraries/webp/src/dsp/upsampling_neon.c new file mode 100644 index 00000000000..bbc000ca2d3 --- /dev/null +++ b/libraries/webp/src/dsp/upsampling_neon.c @@ -0,0 +1,285 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// NEON version of YUV to RGB upsampling functions. +// +// Author: mans@mansr.com (Mans Rullgard) +// Based on SSE code by: somnath@google.com (Somnath Banerjee) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_NEON) + +#include +#include +#include +#include "src/dsp/neon.h" +#include "src/dsp/yuv.h" + +#ifdef FANCY_UPSAMPLING + +//----------------------------------------------------------------------------- +// U/V upsampling + +// Loads 9 pixels each from rows r1 and r2 and generates 16 pixels. +#define UPSAMPLE_16PIXELS(r1, r2, out) do { \ + const uint8x8_t a = vld1_u8(r1 + 0); \ + const uint8x8_t b = vld1_u8(r1 + 1); \ + const uint8x8_t c = vld1_u8(r2 + 0); \ + const uint8x8_t d = vld1_u8(r2 + 1); \ + /* a + b + c + d */ \ + const uint16x8_t ad = vaddl_u8(a, d); \ + const uint16x8_t bc = vaddl_u8(b, c); \ + const uint16x8_t abcd = vaddq_u16(ad, bc); \ + /* 3a + b + c + 3d */ \ + const uint16x8_t al = vaddq_u16(abcd, vshlq_n_u16(ad, 1)); \ + /* a + 3b + 3c + d */ \ + const uint16x8_t bl = vaddq_u16(abcd, vshlq_n_u16(bc, 1)); \ + \ + const uint8x8_t diag2 = vshrn_n_u16(al, 3); \ + const uint8x8_t diag1 = vshrn_n_u16(bl, 3); \ + \ + const uint8x8_t A = vrhadd_u8(a, diag1); \ + const uint8x8_t B = vrhadd_u8(b, diag2); \ + const uint8x8_t C = vrhadd_u8(c, diag2); \ + const uint8x8_t D = vrhadd_u8(d, diag1); \ + \ + uint8x8x2_t A_B, C_D; \ + INIT_VECTOR2(A_B, A, B); \ + INIT_VECTOR2(C_D, C, D); \ + vst2_u8(out + 0, A_B); \ + vst2_u8(out + 32, C_D); \ +} while (0) + +// Turn the macro into a function for reducing code-size when non-critical +static void Upsample16Pixels_NEON(const uint8_t* r1, const uint8_t* r2, + uint8_t* out) { + UPSAMPLE_16PIXELS(r1, r2, out); +} + +#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \ + uint8_t r1[9], r2[9]; \ + memcpy(r1, (tb), (num_pixels)); \ + memcpy(r2, (bb), (num_pixels)); \ + /* replicate last byte */ \ + memset(r1 + (num_pixels), r1[(num_pixels) - 1], 9 - (num_pixels)); \ + memset(r2 + (num_pixels), r2[(num_pixels) - 1], 9 - (num_pixels)); \ + Upsample16Pixels_NEON(r1, r2, out); \ +} + +//----------------------------------------------------------------------------- +// YUV->RGB conversion + +// note: we represent the 33050 large constant as 32768 + 282 +static const int16_t kCoeffs1[4] = { 19077, 26149, 6419, 13320 }; + +#define v255 vdup_n_u8(255) + +#define STORE_Rgb(out, r, g, b) do { \ + uint8x8x3_t r_g_b; \ + INIT_VECTOR3(r_g_b, r, g, b); \ + vst3_u8(out, r_g_b); \ +} while (0) + +#define STORE_Bgr(out, r, g, b) do { \ + uint8x8x3_t b_g_r; \ + INIT_VECTOR3(b_g_r, b, g, r); \ + vst3_u8(out, b_g_r); \ +} while (0) + +#define STORE_Rgba(out, r, g, b) do { \ + uint8x8x4_t r_g_b_v255; \ + INIT_VECTOR4(r_g_b_v255, r, g, b, v255); \ + vst4_u8(out, r_g_b_v255); \ +} while (0) + +#define STORE_Bgra(out, r, g, b) do { \ + uint8x8x4_t b_g_r_v255; \ + INIT_VECTOR4(b_g_r_v255, b, g, r, v255); \ + vst4_u8(out, b_g_r_v255); \ +} while (0) + +#define STORE_Argb(out, r, g, b) do { \ + uint8x8x4_t v255_r_g_b; \ + INIT_VECTOR4(v255_r_g_b, v255, r, g, b); \ + vst4_u8(out, v255_r_g_b); \ +} while (0) + +#if (WEBP_SWAP_16BIT_CSP == 0) +#define ZIP_U8(lo, hi) vzip_u8((lo), (hi)) +#else +#define ZIP_U8(lo, hi) vzip_u8((hi), (lo)) +#endif + +#define STORE_Rgba4444(out, r, g, b) do { \ + const uint8x8_t rg = vsri_n_u8(r, g, 4); /* shift g, insert r */ \ + const uint8x8_t ba = vsri_n_u8(b, v255, 4); /* shift a, insert b */ \ + const uint8x8x2_t rgba4444 = ZIP_U8(rg, ba); \ + vst1q_u8(out, vcombine_u8(rgba4444.val[0], rgba4444.val[1])); \ +} while (0) + +#define STORE_Rgb565(out, r, g, b) do { \ + const uint8x8_t rg = vsri_n_u8(r, g, 5); /* shift g and insert r */ \ + const uint8x8_t g1 = vshl_n_u8(g, 3); /* pre-shift g: 3bits */ \ + const uint8x8_t gb = vsri_n_u8(g1, b, 3); /* shift b and insert g */ \ + const uint8x8x2_t rgb565 = ZIP_U8(rg, gb); \ + vst1q_u8(out, vcombine_u8(rgb565.val[0], rgb565.val[1])); \ +} while (0) + +#define CONVERT8(FMT, XSTEP, N, src_y, src_uv, out, cur_x) do { \ + int i; \ + for (i = 0; i < N; i += 8) { \ + const int off = ((cur_x) + i) * XSTEP; \ + const uint8x8_t y = vld1_u8((src_y) + (cur_x) + i); \ + const uint8x8_t u = vld1_u8((src_uv) + i + 0); \ + const uint8x8_t v = vld1_u8((src_uv) + i + 16); \ + const int16x8_t Y0 = vreinterpretq_s16_u16(vshll_n_u8(y, 7)); \ + const int16x8_t U0 = vreinterpretq_s16_u16(vshll_n_u8(u, 7)); \ + const int16x8_t V0 = vreinterpretq_s16_u16(vshll_n_u8(v, 7)); \ + const int16x8_t Y1 = vqdmulhq_lane_s16(Y0, coeff1, 0); \ + const int16x8_t R0 = vqdmulhq_lane_s16(V0, coeff1, 1); \ + const int16x8_t G0 = vqdmulhq_lane_s16(U0, coeff1, 2); \ + const int16x8_t G1 = vqdmulhq_lane_s16(V0, coeff1, 3); \ + const int16x8_t B0 = vqdmulhq_n_s16(U0, 282); \ + const int16x8_t R1 = vqaddq_s16(Y1, R_Rounder); \ + const int16x8_t G2 = vqaddq_s16(Y1, G_Rounder); \ + const int16x8_t B1 = vqaddq_s16(Y1, B_Rounder); \ + const int16x8_t R2 = vqaddq_s16(R0, R1); \ + const int16x8_t G3 = vqaddq_s16(G0, G1); \ + const int16x8_t B2 = vqaddq_s16(B0, B1); \ + const int16x8_t G4 = vqsubq_s16(G2, G3); \ + const int16x8_t B3 = vqaddq_s16(B2, U0); \ + const uint8x8_t R = vqshrun_n_s16(R2, YUV_FIX2); \ + const uint8x8_t G = vqshrun_n_s16(G4, YUV_FIX2); \ + const uint8x8_t B = vqshrun_n_s16(B3, YUV_FIX2); \ + STORE_ ## FMT(out + off, R, G, B); \ + } \ +} while (0) + +#define CONVERT1(FUNC, XSTEP, N, src_y, src_uv, rgb, cur_x) { \ + int i; \ + for (i = 0; i < N; i++) { \ + const int off = ((cur_x) + i) * XSTEP; \ + const int y = src_y[(cur_x) + i]; \ + const int u = (src_uv)[i]; \ + const int v = (src_uv)[i + 16]; \ + FUNC(y, u, v, rgb + off); \ + } \ +} + +#define CONVERT2RGB_8(FMT, XSTEP, top_y, bottom_y, uv, \ + top_dst, bottom_dst, cur_x, len) { \ + CONVERT8(FMT, XSTEP, len, top_y, uv, top_dst, cur_x); \ + if (bottom_y != NULL) { \ + CONVERT8(FMT, XSTEP, len, bottom_y, (uv) + 32, bottom_dst, cur_x); \ + } \ +} + +#define CONVERT2RGB_1(FUNC, XSTEP, top_y, bottom_y, uv, \ + top_dst, bottom_dst, cur_x, len) { \ + CONVERT1(FUNC, XSTEP, len, top_y, uv, top_dst, cur_x); \ + if (bottom_y != NULL) { \ + CONVERT1(FUNC, XSTEP, len, bottom_y, (uv) + 32, bottom_dst, cur_x); \ + } \ +} + +#define NEON_UPSAMPLE_FUNC(FUNC_NAME, FMT, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int block; \ + /* 16 byte aligned array to cache reconstructed u and v */ \ + uint8_t uv_buf[2 * 32 + 15]; \ + uint8_t* const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ + const int uv_len = (len + 1) >> 1; \ + /* 9 pixels must be read-able for each block */ \ + const int num_blocks = (uv_len - 1) >> 3; \ + const int leftover = uv_len - num_blocks * 8; \ + const int last_pos = 1 + 16 * num_blocks; \ + \ + const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \ + const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \ + \ + const int16x4_t coeff1 = vld1_s16(kCoeffs1); \ + const int16x8_t R_Rounder = vdupq_n_s16(-14234); \ + const int16x8_t G_Rounder = vdupq_n_s16(8708); \ + const int16x8_t B_Rounder = vdupq_n_s16(-17685); \ + \ + /* Treat the first pixel in regular way */ \ + assert(top_y != NULL); \ + { \ + const int u0 = (top_u[0] + u_diag) >> 1; \ + const int v0 = (top_v[0] + v_diag) >> 1; \ + VP8YuvTo ## FMT(top_y[0], u0, v0, top_dst); \ + } \ + if (bottom_y != NULL) { \ + const int u0 = (cur_u[0] + u_diag) >> 1; \ + const int v0 = (cur_v[0] + v_diag) >> 1; \ + VP8YuvTo ## FMT(bottom_y[0], u0, v0, bottom_dst); \ + } \ + \ + for (block = 0; block < num_blocks; ++block) { \ + UPSAMPLE_16PIXELS(top_u, cur_u, r_uv); \ + UPSAMPLE_16PIXELS(top_v, cur_v, r_uv + 16); \ + CONVERT2RGB_8(FMT, XSTEP, top_y, bottom_y, r_uv, \ + top_dst, bottom_dst, 16 * block + 1, 16); \ + top_u += 8; \ + cur_u += 8; \ + top_v += 8; \ + cur_v += 8; \ + } \ + \ + UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv); \ + UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 16); \ + CONVERT2RGB_1(VP8YuvTo ## FMT, XSTEP, top_y, bottom_y, r_uv, \ + top_dst, bottom_dst, last_pos, len - last_pos); \ +} + +// NEON variants of the fancy upsampler. +NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePair_NEON, Rgba, 4) +NEON_UPSAMPLE_FUNC(UpsampleBgraLinePair_NEON, Bgra, 4) +#if !defined(WEBP_REDUCE_CSP) +NEON_UPSAMPLE_FUNC(UpsampleRgbLinePair_NEON, Rgb, 3) +NEON_UPSAMPLE_FUNC(UpsampleBgrLinePair_NEON, Bgr, 3) +NEON_UPSAMPLE_FUNC(UpsampleArgbLinePair_NEON, Argb, 4) +NEON_UPSAMPLE_FUNC(UpsampleRgba4444LinePair_NEON, Rgba4444, 2) +NEON_UPSAMPLE_FUNC(UpsampleRgb565LinePair_NEON, Rgb565, 2) +#endif // WEBP_REDUCE_CSP + +//------------------------------------------------------------------------------ +// Entry point + +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +extern void WebPInitUpsamplersNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersNEON(void) { + WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_NEON; + WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_NEON; + WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_NEON; + WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_NEON; +#if !defined(WEBP_REDUCE_CSP) + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_NEON; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_NEON; + WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_NEON; + WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_NEON; + WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_NEON; + WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_NEON; + WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_NEON; +#endif // WEBP_REDUCE_CSP +} + +#endif // FANCY_UPSAMPLING + +#endif // WEBP_USE_NEON + +#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_NEON)) +WEBP_DSP_INIT_STUB(WebPInitUpsamplersNEON) +#endif diff --git a/libraries/webp/src/dsp/upsampling_sse2.c b/libraries/webp/src/dsp/upsampling_sse2.c new file mode 100644 index 00000000000..77b4f7221eb --- /dev/null +++ b/libraries/webp/src/dsp/upsampling_sse2.c @@ -0,0 +1,267 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE2 version of YUV to RGB upsampling functions. +// +// Author: somnath@google.com (Somnath Banerjee) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE2) + +#include +#include +#include +#include "src/dsp/yuv.h" + +#ifdef FANCY_UPSAMPLING + +// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows +// u = (9*a + 3*b + 3*c + d + 8) / 16 +// = (a + (a + 3*b + 3*c + d) / 8 + 1) / 2 +// = (a + m + 1) / 2 +// where m = (a + 3*b + 3*c + d) / 8 +// = ((a + b + c + d) / 2 + b + c) / 4 +// +// Let's say k = (a + b + c + d) / 4. +// We can compute k as +// k = (s + t + 1) / 2 - ((a^d) | (b^c) | (s^t)) & 1 +// where s = (a + d + 1) / 2 and t = (b + c + 1) / 2 +// +// Then m can be written as +// m = (k + t + 1) / 2 - (((b^c) & (s^t)) | (k^t)) & 1 + +// Computes out = (k + in + 1) / 2 - ((ij & (s^t)) | (k^in)) & 1 +#define GET_M(ij, in, out) do { \ + const __m128i tmp0 = _mm_avg_epu8(k, (in)); /* (k + in + 1) / 2 */ \ + const __m128i tmp1 = _mm_and_si128((ij), st); /* (ij) & (s^t) */ \ + const __m128i tmp2 = _mm_xor_si128(k, (in)); /* (k^in) */ \ + const __m128i tmp3 = _mm_or_si128(tmp1, tmp2); /* ((ij) & (s^t)) | (k^in) */\ + const __m128i tmp4 = _mm_and_si128(tmp3, one); /* & 1 -> lsb_correction */ \ + (out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \ +} while (0) + +// pack and store two alternating pixel rows +#define PACK_AND_STORE(a, b, da, db, out) do { \ + const __m128i t_a = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \ + const __m128i t_b = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \ + const __m128i t_1 = _mm_unpacklo_epi8(t_a, t_b); \ + const __m128i t_2 = _mm_unpackhi_epi8(t_a, t_b); \ + _mm_store_si128(((__m128i*)(out)) + 0, t_1); \ + _mm_store_si128(((__m128i*)(out)) + 1, t_2); \ +} while (0) + +// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels. +#define UPSAMPLE_32PIXELS(r1, r2, out) do { \ + const __m128i one = _mm_set1_epi8(1); \ + const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \ + const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \ + const __m128i c = _mm_loadu_si128((const __m128i*)&(r2)[0]); \ + const __m128i d = _mm_loadu_si128((const __m128i*)&(r2)[1]); \ + \ + const __m128i s = _mm_avg_epu8(a, d); /* s = (a + d + 1) / 2 */ \ + const __m128i t = _mm_avg_epu8(b, c); /* t = (b + c + 1) / 2 */ \ + const __m128i st = _mm_xor_si128(s, t); /* st = s^t */ \ + \ + const __m128i ad = _mm_xor_si128(a, d); /* ad = a^d */ \ + const __m128i bc = _mm_xor_si128(b, c); /* bc = b^c */ \ + \ + const __m128i t1 = _mm_or_si128(ad, bc); /* (a^d) | (b^c) */ \ + const __m128i t2 = _mm_or_si128(t1, st); /* (a^d) | (b^c) | (s^t) */ \ + const __m128i t3 = _mm_and_si128(t2, one); /* (a^d) | (b^c) | (s^t) & 1 */ \ + const __m128i t4 = _mm_avg_epu8(s, t); \ + const __m128i k = _mm_sub_epi8(t4, t3); /* k = (a + b + c + d) / 4 */ \ + __m128i diag1, diag2; \ + \ + GET_M(bc, t, diag1); /* diag1 = (a + 3b + 3c + d) / 8 */ \ + GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \ + \ + /* pack the alternate pixels */ \ + PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \ + PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \ +} while (0) + +// Turn the macro into a function for reducing code-size when non-critical +static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[], + uint8_t* const out) { + UPSAMPLE_32PIXELS(r1, r2, out); +} + +#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \ + uint8_t r1[17], r2[17]; \ + memcpy(r1, (tb), (num_pixels)); \ + memcpy(r2, (bb), (num_pixels)); \ + /* replicate last byte */ \ + memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \ + memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \ + /* using the shared function instead of the macro saves ~3k code size */ \ + Upsample32Pixels_SSE2(r1, r2, out); \ +} + +#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \ + top_dst, bottom_dst, cur_x) do { \ + FUNC##32_SSE2((top_y) + (cur_x), r_u, r_v, (top_dst) + (cur_x) * (XSTEP)); \ + if ((bottom_y) != NULL) { \ + FUNC##32_SSE2((bottom_y) + (cur_x), r_u + 64, r_v + 64, \ + (bottom_dst) + (cur_x) * (XSTEP)); \ + } \ +} while (0) + +#define SSE2_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int uv_pos, pos; \ + /* 16byte-aligned array to cache reconstructed u and v */ \ + uint8_t uv_buf[14 * 32 + 15] = { 0 }; \ + uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~(uintptr_t)15); \ + uint8_t* const r_v = r_u + 32; \ + \ + assert(top_y != NULL); \ + { /* Treat the first pixel in regular way */ \ + const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \ + const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \ + const int u0_t = (top_u[0] + u_diag) >> 1; \ + const int v0_t = (top_v[0] + v_diag) >> 1; \ + FUNC(top_y[0], u0_t, v0_t, top_dst); \ + if (bottom_y != NULL) { \ + const int u0_b = (cur_u[0] + u_diag) >> 1; \ + const int v0_b = (cur_v[0] + v_diag) >> 1; \ + FUNC(bottom_y[0], u0_b, v0_b, bottom_dst); \ + } \ + } \ + /* For UPSAMPLE_32PIXELS, 17 u/v values must be read-able for each block */ \ + for (pos = 1, uv_pos = 0; pos + 32 + 1 <= len; pos += 32, uv_pos += 16) { \ + UPSAMPLE_32PIXELS(top_u + uv_pos, cur_u + uv_pos, r_u); \ + UPSAMPLE_32PIXELS(top_v + uv_pos, cur_v + uv_pos, r_v); \ + CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, pos); \ + } \ + if (len > 1) { \ + const int left_over = ((len + 1) >> 1) - (pos >> 1); \ + uint8_t* const tmp_top_dst = r_u + 4 * 32; \ + uint8_t* const tmp_bottom_dst = tmp_top_dst + 4 * 32; \ + uint8_t* const tmp_top = tmp_bottom_dst + 4 * 32; \ + uint8_t* const tmp_bottom = (bottom_y == NULL) ? NULL : tmp_top + 32; \ + assert(left_over > 0); \ + UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \ + UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \ + memcpy(tmp_top, top_y + pos, len - pos); \ + if (bottom_y != NULL) memcpy(tmp_bottom, bottom_y + pos, len - pos); \ + CONVERT2RGB_32(FUNC, XSTEP, tmp_top, tmp_bottom, tmp_top_dst, \ + tmp_bottom_dst, 0); \ + memcpy(top_dst + pos * (XSTEP), tmp_top_dst, (len - pos) * (XSTEP)); \ + if (bottom_y != NULL) { \ + memcpy(bottom_dst + pos * (XSTEP), tmp_bottom_dst, \ + (len - pos) * (XSTEP)); \ + } \ + } \ +} + +// SSE2 variants of the fancy upsampler. +SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePair_SSE2, VP8YuvToRgba, 4) +SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair_SSE2, VP8YuvToBgra, 4) + +#if !defined(WEBP_REDUCE_CSP) +SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePair_SSE2, VP8YuvToRgb, 3) +SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePair_SSE2, VP8YuvToBgr, 3) +SSE2_UPSAMPLE_FUNC(UpsampleArgbLinePair_SSE2, VP8YuvToArgb, 4) +SSE2_UPSAMPLE_FUNC(UpsampleRgba4444LinePair_SSE2, VP8YuvToRgba4444, 2) +SSE2_UPSAMPLE_FUNC(UpsampleRgb565LinePair_SSE2, VP8YuvToRgb565, 2) +#endif // WEBP_REDUCE_CSP + +#undef GET_M +#undef PACK_AND_STORE +#undef UPSAMPLE_32PIXELS +#undef UPSAMPLE_LAST_BLOCK +#undef CONVERT2RGB +#undef CONVERT2RGB_32 +#undef SSE2_UPSAMPLE_FUNC + +//------------------------------------------------------------------------------ +// Entry point + +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +extern void WebPInitUpsamplersSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE2(void) { + WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_SSE2; + WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_SSE2; + WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_SSE2; + WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_SSE2; +#if !defined(WEBP_REDUCE_CSP) + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_SSE2; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_SSE2; + WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_SSE2; + WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_SSE2; + WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_SSE2; + WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_SSE2; + WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_SSE2; +#endif // WEBP_REDUCE_CSP +} + +#endif // FANCY_UPSAMPLING + +//------------------------------------------------------------------------------ + +extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; +extern void WebPInitYUV444ConvertersSSE2(void); + +#define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \ +extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len); \ +static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + int i; \ + const int max_len = len & ~31; \ + for (i = 0; i < max_len; i += 32) { \ + CALL(y + i, u + i, v + i, dst + i * (XSTEP)); \ + } \ + if (i < len) { /* C-fallback */ \ + CALL_C(y + i, u + i, v + i, dst + i * (XSTEP), len - i); \ + } \ +} + +YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4) +YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4) +#if !defined(WEBP_REDUCE_CSP) +YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3) +YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3) +YUV444_FUNC(Yuv444ToArgb_SSE2, VP8YuvToArgb32_SSE2, WebPYuv444ToArgb_C, 4) +YUV444_FUNC(Yuv444ToRgba4444_SSE2, VP8YuvToRgba444432_SSE2, \ + WebPYuv444ToRgba4444_C, 2) +YUV444_FUNC(Yuv444ToRgb565_SSE2, VP8YuvToRgb56532_SSE2, WebPYuv444ToRgb565_C, 2) +#endif // WEBP_REDUCE_CSP + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE2(void) { + WebPYUV444Converters[MODE_RGBA] = Yuv444ToRgba_SSE2; + WebPYUV444Converters[MODE_BGRA] = Yuv444ToBgra_SSE2; + WebPYUV444Converters[MODE_rgbA] = Yuv444ToRgba_SSE2; + WebPYUV444Converters[MODE_bgrA] = Yuv444ToBgra_SSE2; +#if !defined(WEBP_REDUCE_CSP) + WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb_SSE2; + WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr_SSE2; + WebPYUV444Converters[MODE_ARGB] = Yuv444ToArgb_SSE2; + WebPYUV444Converters[MODE_RGBA_4444] = Yuv444ToRgba4444_SSE2; + WebPYUV444Converters[MODE_RGB_565] = Yuv444ToRgb565_SSE2; + WebPYUV444Converters[MODE_Argb] = Yuv444ToArgb_SSE2; + WebPYUV444Converters[MODE_rgbA_4444] = Yuv444ToRgba4444_SSE2; +#endif // WEBP_REDUCE_CSP +} + +#else + +WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersSSE2) + +#endif // WEBP_USE_SSE2 + +#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_SSE2)) +WEBP_DSP_INIT_STUB(WebPInitUpsamplersSSE2) +#endif diff --git a/libraries/webp/src/dsp/upsampling_sse41.c b/libraries/webp/src/dsp/upsampling_sse41.c new file mode 100644 index 00000000000..e38c88d5e67 --- /dev/null +++ b/libraries/webp/src/dsp/upsampling_sse41.c @@ -0,0 +1,239 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE41 version of YUV to RGB upsampling functions. +// +// Author: somnath@google.com (Somnath Banerjee) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE41) + +#include +#include +#include +#include "src/dsp/yuv.h" + +#ifdef FANCY_UPSAMPLING + +#if !defined(WEBP_REDUCE_CSP) + +// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows +// u = (9*a + 3*b + 3*c + d + 8) / 16 +// = (a + (a + 3*b + 3*c + d) / 8 + 1) / 2 +// = (a + m + 1) / 2 +// where m = (a + 3*b + 3*c + d) / 8 +// = ((a + b + c + d) / 2 + b + c) / 4 +// +// Let's say k = (a + b + c + d) / 4. +// We can compute k as +// k = (s + t + 1) / 2 - ((a^d) | (b^c) | (s^t)) & 1 +// where s = (a + d + 1) / 2 and t = (b + c + 1) / 2 +// +// Then m can be written as +// m = (k + t + 1) / 2 - (((b^c) & (s^t)) | (k^t)) & 1 + +// Computes out = (k + in + 1) / 2 - ((ij & (s^t)) | (k^in)) & 1 +#define GET_M(ij, in, out) do { \ + const __m128i tmp0 = _mm_avg_epu8(k, (in)); /* (k + in + 1) / 2 */ \ + const __m128i tmp1 = _mm_and_si128((ij), st); /* (ij) & (s^t) */ \ + const __m128i tmp2 = _mm_xor_si128(k, (in)); /* (k^in) */ \ + const __m128i tmp3 = _mm_or_si128(tmp1, tmp2); /* ((ij) & (s^t)) | (k^in) */\ + const __m128i tmp4 = _mm_and_si128(tmp3, one); /* & 1 -> lsb_correction */ \ + (out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \ +} while (0) + +// pack and store two alternating pixel rows +#define PACK_AND_STORE(a, b, da, db, out) do { \ + const __m128i t_a = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \ + const __m128i t_b = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \ + const __m128i t_1 = _mm_unpacklo_epi8(t_a, t_b); \ + const __m128i t_2 = _mm_unpackhi_epi8(t_a, t_b); \ + _mm_store_si128(((__m128i*)(out)) + 0, t_1); \ + _mm_store_si128(((__m128i*)(out)) + 1, t_2); \ +} while (0) + +// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels. +#define UPSAMPLE_32PIXELS(r1, r2, out) do { \ + const __m128i one = _mm_set1_epi8(1); \ + const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \ + const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \ + const __m128i c = _mm_loadu_si128((const __m128i*)&(r2)[0]); \ + const __m128i d = _mm_loadu_si128((const __m128i*)&(r2)[1]); \ + \ + const __m128i s = _mm_avg_epu8(a, d); /* s = (a + d + 1) / 2 */ \ + const __m128i t = _mm_avg_epu8(b, c); /* t = (b + c + 1) / 2 */ \ + const __m128i st = _mm_xor_si128(s, t); /* st = s^t */ \ + \ + const __m128i ad = _mm_xor_si128(a, d); /* ad = a^d */ \ + const __m128i bc = _mm_xor_si128(b, c); /* bc = b^c */ \ + \ + const __m128i t1 = _mm_or_si128(ad, bc); /* (a^d) | (b^c) */ \ + const __m128i t2 = _mm_or_si128(t1, st); /* (a^d) | (b^c) | (s^t) */ \ + const __m128i t3 = _mm_and_si128(t2, one); /* (a^d) | (b^c) | (s^t) & 1 */ \ + const __m128i t4 = _mm_avg_epu8(s, t); \ + const __m128i k = _mm_sub_epi8(t4, t3); /* k = (a + b + c + d) / 4 */ \ + __m128i diag1, diag2; \ + \ + GET_M(bc, t, diag1); /* diag1 = (a + 3b + 3c + d) / 8 */ \ + GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \ + \ + /* pack the alternate pixels */ \ + PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \ + PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \ +} while (0) + +// Turn the macro into a function for reducing code-size when non-critical +static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[], + uint8_t* const out) { + UPSAMPLE_32PIXELS(r1, r2, out); +} + +#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \ + uint8_t r1[17], r2[17]; \ + memcpy(r1, (tb), (num_pixels)); \ + memcpy(r2, (bb), (num_pixels)); \ + /* replicate last byte */ \ + memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \ + memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \ + /* using the shared function instead of the macro saves ~3k code size */ \ + Upsample32Pixels_SSE41(r1, r2, out); \ +} + +#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \ + top_dst, bottom_dst, cur_x) do { \ + FUNC##32_SSE41((top_y) + (cur_x), r_u, r_v, (top_dst) + (cur_x) * (XSTEP)); \ + if ((bottom_y) != NULL) { \ + FUNC##32_SSE41((bottom_y) + (cur_x), r_u + 64, r_v + 64, \ + (bottom_dst) + (cur_x) * (XSTEP)); \ + } \ +} while (0) + +#define SSE4_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int uv_pos, pos; \ + /* 16byte-aligned array to cache reconstructed u and v */ \ + uint8_t uv_buf[14 * 32 + 15] = { 0 }; \ + uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ + uint8_t* const r_v = r_u + 32; \ + \ + assert(top_y != NULL); \ + { /* Treat the first pixel in regular way */ \ + const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \ + const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \ + const int u0_t = (top_u[0] + u_diag) >> 1; \ + const int v0_t = (top_v[0] + v_diag) >> 1; \ + FUNC(top_y[0], u0_t, v0_t, top_dst); \ + if (bottom_y != NULL) { \ + const int u0_b = (cur_u[0] + u_diag) >> 1; \ + const int v0_b = (cur_v[0] + v_diag) >> 1; \ + FUNC(bottom_y[0], u0_b, v0_b, bottom_dst); \ + } \ + } \ + /* For UPSAMPLE_32PIXELS, 17 u/v values must be read-able for each block */ \ + for (pos = 1, uv_pos = 0; pos + 32 + 1 <= len; pos += 32, uv_pos += 16) { \ + UPSAMPLE_32PIXELS(top_u + uv_pos, cur_u + uv_pos, r_u); \ + UPSAMPLE_32PIXELS(top_v + uv_pos, cur_v + uv_pos, r_v); \ + CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, pos); \ + } \ + if (len > 1) { \ + const int left_over = ((len + 1) >> 1) - (pos >> 1); \ + uint8_t* const tmp_top_dst = r_u + 4 * 32; \ + uint8_t* const tmp_bottom_dst = tmp_top_dst + 4 * 32; \ + uint8_t* const tmp_top = tmp_bottom_dst + 4 * 32; \ + uint8_t* const tmp_bottom = (bottom_y == NULL) ? NULL : tmp_top + 32; \ + assert(left_over > 0); \ + UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \ + UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \ + memcpy(tmp_top, top_y + pos, len - pos); \ + if (bottom_y != NULL) memcpy(tmp_bottom, bottom_y + pos, len - pos); \ + CONVERT2RGB_32(FUNC, XSTEP, tmp_top, tmp_bottom, tmp_top_dst, \ + tmp_bottom_dst, 0); \ + memcpy(top_dst + pos * (XSTEP), tmp_top_dst, (len - pos) * (XSTEP)); \ + if (bottom_y != NULL) { \ + memcpy(bottom_dst + pos * (XSTEP), tmp_bottom_dst, \ + (len - pos) * (XSTEP)); \ + } \ + } \ +} + +// SSE4 variants of the fancy upsampler. +SSE4_UPSAMPLE_FUNC(UpsampleRgbLinePair_SSE41, VP8YuvToRgb, 3) +SSE4_UPSAMPLE_FUNC(UpsampleBgrLinePair_SSE41, VP8YuvToBgr, 3) + +#undef GET_M +#undef PACK_AND_STORE +#undef UPSAMPLE_32PIXELS +#undef UPSAMPLE_LAST_BLOCK +#undef CONVERT2RGB +#undef CONVERT2RGB_32 +#undef SSE4_UPSAMPLE_FUNC + +#endif // WEBP_REDUCE_CSP + +//------------------------------------------------------------------------------ +// Entry point + +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +extern void WebPInitUpsamplersSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE41(void) { +#if !defined(WEBP_REDUCE_CSP) + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_SSE41; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_SSE41; +#endif // WEBP_REDUCE_CSP +} + +#endif // FANCY_UPSAMPLING + +//------------------------------------------------------------------------------ + +extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; +extern void WebPInitYUV444ConvertersSSE41(void); + +#define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \ +extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len); \ +static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + int i; \ + const int max_len = len & ~31; \ + for (i = 0; i < max_len; i += 32) { \ + CALL(y + i, u + i, v + i, dst + i * (XSTEP)); \ + } \ + if (i < len) { /* C-fallback */ \ + CALL_C(y + i, u + i, v + i, dst + i * (XSTEP), len - i); \ + } \ +} + +#if !defined(WEBP_REDUCE_CSP) +YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3) +YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3) +#endif // WEBP_REDUCE_CSP + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE41(void) { +#if !defined(WEBP_REDUCE_CSP) + WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb_SSE41; + WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr_SSE41; +#endif // WEBP_REDUCE_CSP +} + +#else + +WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersSSE41) + +#endif // WEBP_USE_SSE41 + +#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_SSE41)) +WEBP_DSP_INIT_STUB(WebPInitUpsamplersSSE41) +#endif diff --git a/libraries/webp/src/dsp/yuv.c b/libraries/webp/src/dsp/yuv.c new file mode 100644 index 00000000000..8a04b85d82d --- /dev/null +++ b/libraries/webp/src/dsp/yuv.c @@ -0,0 +1,245 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// YUV->RGB conversion functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/yuv.h" + +#include +#include + +//----------------------------------------------------------------------------- +// Plain-C version + +#define ROW_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* y, \ + const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + const uint8_t* const end = dst + (len & ~1) * (XSTEP); \ + while (dst != end) { \ + FUNC(y[0], u[0], v[0], dst); \ + FUNC(y[1], u[0], v[0], dst + (XSTEP)); \ + y += 2; \ + ++u; \ + ++v; \ + dst += 2 * (XSTEP); \ + } \ + if (len & 1) { \ + FUNC(y[0], u[0], v[0], dst); \ + } \ +} \ + +// All variants implemented. +ROW_FUNC(YuvToRgbRow, VP8YuvToRgb, 3) +ROW_FUNC(YuvToBgrRow, VP8YuvToBgr, 3) +ROW_FUNC(YuvToRgbaRow, VP8YuvToRgba, 4) +ROW_FUNC(YuvToBgraRow, VP8YuvToBgra, 4) +ROW_FUNC(YuvToArgbRow, VP8YuvToArgb, 4) +ROW_FUNC(YuvToRgba4444Row, VP8YuvToRgba4444, 2) +ROW_FUNC(YuvToRgb565Row, VP8YuvToRgb565, 2) + +#undef ROW_FUNC + +// Main call for processing a plane with a WebPSamplerRowFunc function: +void WebPSamplerProcessPlane(const uint8_t* y, int y_stride, + const uint8_t* u, const uint8_t* v, int uv_stride, + uint8_t* dst, int dst_stride, + int width, int height, WebPSamplerRowFunc func) { + int j; + for (j = 0; j < height; ++j) { + func(y, u, v, dst, width); + y += y_stride; + if (j & 1) { + u += uv_stride; + v += uv_stride; + } + dst += dst_stride; + } +} + +//----------------------------------------------------------------------------- +// Main call + +WebPSamplerRowFunc WebPSamplers[MODE_LAST]; + +extern VP8CPUInfo VP8GetCPUInfo; +extern void WebPInitSamplersSSE2(void); +extern void WebPInitSamplersSSE41(void); +extern void WebPInitSamplersMIPS32(void); +extern void WebPInitSamplersMIPSdspR2(void); + +WEBP_DSP_INIT_FUNC(WebPInitSamplers) { + WebPSamplers[MODE_RGB] = YuvToRgbRow; + WebPSamplers[MODE_RGBA] = YuvToRgbaRow; + WebPSamplers[MODE_BGR] = YuvToBgrRow; + WebPSamplers[MODE_BGRA] = YuvToBgraRow; + WebPSamplers[MODE_ARGB] = YuvToArgbRow; + WebPSamplers[MODE_RGBA_4444] = YuvToRgba4444Row; + WebPSamplers[MODE_RGB_565] = YuvToRgb565Row; + WebPSamplers[MODE_rgbA] = YuvToRgbaRow; + WebPSamplers[MODE_bgrA] = YuvToBgraRow; + WebPSamplers[MODE_Argb] = YuvToArgbRow; + WebPSamplers[MODE_rgbA_4444] = YuvToRgba4444Row; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + WebPInitSamplersSSE2(); + } +#endif // WEBP_HAVE_SSE2 +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitSamplersSSE41(); + } +#endif // WEBP_HAVE_SSE41 +#if defined(WEBP_USE_MIPS32) + if (VP8GetCPUInfo(kMIPS32)) { + WebPInitSamplersMIPS32(); + } +#endif // WEBP_USE_MIPS32 +#if defined(WEBP_USE_MIPS_DSP_R2) + if (VP8GetCPUInfo(kMIPSdspR2)) { + WebPInitSamplersMIPSdspR2(); + } +#endif // WEBP_USE_MIPS_DSP_R2 + } +} + +//----------------------------------------------------------------------------- +// ARGB -> YUV converters + +static void ConvertARGBToY_C(const uint32_t* argb, uint8_t* y, int width) { + int i; + for (i = 0; i < width; ++i) { + const uint32_t p = argb[i]; + y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff, + YUV_HALF); + } +} + +void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v, + int src_width, int do_store) { + // No rounding. Last pixel is dealt with separately. + const int uv_width = src_width >> 1; + int i; + for (i = 0; i < uv_width; ++i) { + const uint32_t v0 = argb[2 * i + 0]; + const uint32_t v1 = argb[2 * i + 1]; + // VP8RGBToU/V expects four accumulated pixels. Hence we need to + // scale r/g/b value by a factor 2. We just shift v0/v1 one bit less. + const int r = ((v0 >> 15) & 0x1fe) + ((v1 >> 15) & 0x1fe); + const int g = ((v0 >> 7) & 0x1fe) + ((v1 >> 7) & 0x1fe); + const int b = ((v0 << 1) & 0x1fe) + ((v1 << 1) & 0x1fe); + const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2); + const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2); + if (do_store) { + u[i] = tmp_u; + v[i] = tmp_v; + } else { + // Approximated average-of-four. But it's an acceptable diff. + u[i] = (u[i] + tmp_u + 1) >> 1; + v[i] = (v[i] + tmp_v + 1) >> 1; + } + } + if (src_width & 1) { // last pixel + const uint32_t v0 = argb[2 * i + 0]; + const int r = (v0 >> 14) & 0x3fc; + const int g = (v0 >> 6) & 0x3fc; + const int b = (v0 << 2) & 0x3fc; + const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2); + const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2); + if (do_store) { + u[i] = tmp_u; + v[i] = tmp_v; + } else { + u[i] = (u[i] + tmp_u + 1) >> 1; + v[i] = (v[i] + tmp_v + 1) >> 1; + } + } +} + +//----------------------------------------------------------------------------- + +static void ConvertRGB24ToY_C(const uint8_t* rgb, uint8_t* y, int width) { + int i; + for (i = 0; i < width; ++i, rgb += 3) { + y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF); + } +} + +static void ConvertBGR24ToY_C(const uint8_t* bgr, uint8_t* y, int width) { + int i; + for (i = 0; i < width; ++i, bgr += 3) { + y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF); + } +} + +void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, + uint8_t* u, uint8_t* v, int width) { + int i; + for (i = 0; i < width; i += 1, rgb += 4) { + const int r = rgb[0], g = rgb[1], b = rgb[2]; + u[i] = VP8RGBToU(r, g, b, YUV_HALF << 2); + v[i] = VP8RGBToV(r, g, b, YUV_HALF << 2); + } +} + +//----------------------------------------------------------------------------- + +void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width); +void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width); +void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb, + uint8_t* u, uint8_t* v, int width); + +void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width); +void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v, + int src_width, int do_store); + +extern void WebPInitConvertARGBToYUVSSE2(void); +extern void WebPInitConvertARGBToYUVSSE41(void); +extern void WebPInitConvertARGBToYUVNEON(void); + +WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) { + WebPConvertARGBToY = ConvertARGBToY_C; + WebPConvertARGBToUV = WebPConvertARGBToUV_C; + + WebPConvertRGB24ToY = ConvertRGB24ToY_C; + WebPConvertBGR24ToY = ConvertBGR24ToY_C; + + WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C; + + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_HAVE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + WebPInitConvertARGBToYUVSSE2(); + } +#endif // WEBP_HAVE_SSE2 +#if defined(WEBP_HAVE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitConvertARGBToYUVSSE41(); + } +#endif // WEBP_HAVE_SSE41 + } + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || + (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { + WebPInitConvertARGBToYUVNEON(); + } +#endif // WEBP_HAVE_NEON + + assert(WebPConvertARGBToY != NULL); + assert(WebPConvertARGBToUV != NULL); + assert(WebPConvertRGB24ToY != NULL); + assert(WebPConvertBGR24ToY != NULL); + assert(WebPConvertRGBA32ToUV != NULL); +} diff --git a/libraries/webp/src/dsp/yuv.h b/libraries/webp/src/dsp/yuv.h new file mode 100644 index 00000000000..66a397d117b --- /dev/null +++ b/libraries/webp/src/dsp/yuv.h @@ -0,0 +1,210 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// inline YUV<->RGB conversion function +// +// The exact naming is Y'CbCr, following the ITU-R BT.601 standard. +// More information at: https://en.wikipedia.org/wiki/YCbCr +// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16 +// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128 +// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128 +// We use 16bit fixed point operations for RGB->YUV conversion (YUV_FIX). +// +// For the Y'CbCr to RGB conversion, the BT.601 specification reads: +// R = 1.164 * (Y-16) + 1.596 * (V-128) +// G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128) +// B = 1.164 * (Y-16) + 2.018 * (U-128) +// where Y is in the [16,235] range, and U/V in the [16,240] range. +// +// The fixed-point implementation used here is: +// R = (19077 . y + 26149 . v - 14234) >> 6 +// G = (19077 . y - 6419 . u - 13320 . v + 8708) >> 6 +// B = (19077 . y + 33050 . u - 17685) >> 6 +// where the '.' operator is the mulhi_epu16 variant: +// a . b = ((a << 8) * b) >> 16 +// that preserves 8 bits of fractional precision before final descaling. + +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DSP_YUV_H_ +#define WEBP_DSP_YUV_H_ + +#include "src/dsp/dsp.h" +#include "src/dec/vp8_dec.h" + +//------------------------------------------------------------------------------ +// YUV -> RGB conversion + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + YUV_FIX = 16, // fixed-point precision for RGB->YUV + YUV_HALF = 1 << (YUV_FIX - 1), + + YUV_FIX2 = 6, // fixed-point precision for YUV->RGB + YUV_MASK2 = (256 << YUV_FIX2) - 1 +}; + +//------------------------------------------------------------------------------ +// slower on x86 by ~7-8%, but bit-exact with the SSE2/NEON version + +static WEBP_INLINE int MultHi(int v, int coeff) { // _mm_mulhi_epu16 emulation + return (v * coeff) >> 8; +} + +static WEBP_INLINE int VP8Clip8(int v) { + return ((v & ~YUV_MASK2) == 0) ? (v >> YUV_FIX2) : (v < 0) ? 0 : 255; +} + +static WEBP_INLINE int VP8YUVToR(int y, int v) { + return VP8Clip8(MultHi(y, 19077) + MultHi(v, 26149) - 14234); +} + +static WEBP_INLINE int VP8YUVToG(int y, int u, int v) { + return VP8Clip8(MultHi(y, 19077) - MultHi(u, 6419) - MultHi(v, 13320) + 8708); +} + +static WEBP_INLINE int VP8YUVToB(int y, int u) { + return VP8Clip8(MultHi(y, 19077) + MultHi(u, 33050) - 17685); +} + +static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v, + uint8_t* const rgb) { + rgb[0] = VP8YUVToR(y, v); + rgb[1] = VP8YUVToG(y, u, v); + rgb[2] = VP8YUVToB(y, u); +} + +static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v, + uint8_t* const bgr) { + bgr[0] = VP8YUVToB(y, u); + bgr[1] = VP8YUVToG(y, u, v); + bgr[2] = VP8YUVToR(y, v); +} + +static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v, + uint8_t* const rgb) { + const int r = VP8YUVToR(y, v); // 5 usable bits + const int g = VP8YUVToG(y, u, v); // 6 usable bits + const int b = VP8YUVToB(y, u); // 5 usable bits + const int rg = (r & 0xf8) | (g >> 5); + const int gb = ((g << 3) & 0xe0) | (b >> 3); +#if (WEBP_SWAP_16BIT_CSP == 1) + rgb[0] = gb; + rgb[1] = rg; +#else + rgb[0] = rg; + rgb[1] = gb; +#endif +} + +static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v, + uint8_t* const argb) { + const int r = VP8YUVToR(y, v); // 4 usable bits + const int g = VP8YUVToG(y, u, v); // 4 usable bits + const int b = VP8YUVToB(y, u); // 4 usable bits + const int rg = (r & 0xf0) | (g >> 4); + const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits +#if (WEBP_SWAP_16BIT_CSP == 1) + argb[0] = ba; + argb[1] = rg; +#else + argb[0] = rg; + argb[1] = ba; +#endif +} + +//----------------------------------------------------------------------------- +// Alpha handling variants + +static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const argb) { + argb[0] = 0xff; + VP8YuvToRgb(y, u, v, argb + 1); +} + +static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const bgra) { + VP8YuvToBgr(y, u, v, bgra); + bgra[3] = 0xff; +} + +static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const rgba) { + VP8YuvToRgb(y, u, v, rgba); + rgba[3] = 0xff; +} + +//----------------------------------------------------------------------------- +// SSE2 extra functions (mostly for upsampling_sse2.c) + +#if defined(WEBP_USE_SSE2) + +// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst. +void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); +void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); +void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); +void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); +void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); +void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst); +void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); + +#endif // WEBP_USE_SSE2 + +//----------------------------------------------------------------------------- +// SSE41 extra functions (mostly for upsampling_sse41.c) + +#if defined(WEBP_USE_SSE41) + +// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst. +void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); +void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); + +#endif // WEBP_USE_SSE41 + +//------------------------------------------------------------------------------ +// RGB -> YUV conversion + +// Stub functions that can be called with various rounding values: +static WEBP_INLINE int VP8ClipUV(int uv, int rounding) { + uv = (uv + rounding + (128 << (YUV_FIX + 2))) >> (YUV_FIX + 2); + return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255; +} + +static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) { + const int luma = 16839 * r + 33059 * g + 6420 * b; + return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX; // no need to clip +} + +static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) { + const int u = -9719 * r - 19081 * g + 28800 * b; + return VP8ClipUV(u, rounding); +} + +static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) { + const int v = +28800 * r - 24116 * g - 4684 * b; + return VP8ClipUV(v, rounding); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_YUV_H_ diff --git a/libraries/webp/src/dsp/yuv_mips32.c b/libraries/webp/src/dsp/yuv_mips32.c new file mode 100644 index 00000000000..9d0a887824b --- /dev/null +++ b/libraries/webp/src/dsp/yuv_mips32.c @@ -0,0 +1,103 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS version of YUV to RGB upsampling functions. +// +// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) +// Jovan Zelincevic (jovan.zelincevic@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS32) + +#include "src/dsp/yuv.h" + +//------------------------------------------------------------------------------ +// simple point-sampling + +#define ROW_FUNC(FUNC_NAME, XSTEP, R, G, B, A) \ +static void FUNC_NAME(const uint8_t* y, \ + const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + int i, r, g, b; \ + int temp0, temp1, temp2, temp3, temp4; \ + for (i = 0; i < (len >> 1); i++) { \ + temp1 = MultHi(v[0], 26149); \ + temp3 = MultHi(v[0], 13320); \ + temp2 = MultHi(u[0], 6419); \ + temp4 = MultHi(u[0], 33050); \ + temp0 = MultHi(y[0], 19077); \ + temp1 -= 14234; \ + temp3 -= 8708; \ + temp2 += temp3; \ + temp4 -= 17685; \ + r = VP8Clip8(temp0 + temp1); \ + g = VP8Clip8(temp0 - temp2); \ + b = VP8Clip8(temp0 + temp4); \ + temp0 = MultHi(y[1], 19077); \ + dst[R] = r; \ + dst[G] = g; \ + dst[B] = b; \ + if (A) dst[A] = 0xff; \ + r = VP8Clip8(temp0 + temp1); \ + g = VP8Clip8(temp0 - temp2); \ + b = VP8Clip8(temp0 + temp4); \ + dst[R + XSTEP] = r; \ + dst[G + XSTEP] = g; \ + dst[B + XSTEP] = b; \ + if (A) dst[A + XSTEP] = 0xff; \ + y += 2; \ + ++u; \ + ++v; \ + dst += 2 * XSTEP; \ + } \ + if (len & 1) { \ + temp1 = MultHi(v[0], 26149); \ + temp3 = MultHi(v[0], 13320); \ + temp2 = MultHi(u[0], 6419); \ + temp4 = MultHi(u[0], 33050); \ + temp0 = MultHi(y[0], 19077); \ + temp1 -= 14234; \ + temp3 -= 8708; \ + temp2 += temp3; \ + temp4 -= 17685; \ + r = VP8Clip8(temp0 + temp1); \ + g = VP8Clip8(temp0 - temp2); \ + b = VP8Clip8(temp0 + temp4); \ + dst[R] = r; \ + dst[G] = g; \ + dst[B] = b; \ + if (A) dst[A] = 0xff; \ + } \ +} + +ROW_FUNC(YuvToRgbRow_MIPS32, 3, 0, 1, 2, 0) +ROW_FUNC(YuvToRgbaRow_MIPS32, 4, 0, 1, 2, 3) +ROW_FUNC(YuvToBgrRow_MIPS32, 3, 2, 1, 0, 0) +ROW_FUNC(YuvToBgraRow_MIPS32, 4, 2, 1, 0, 3) + +#undef ROW_FUNC + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitSamplersMIPS32(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersMIPS32(void) { + WebPSamplers[MODE_RGB] = YuvToRgbRow_MIPS32; + WebPSamplers[MODE_RGBA] = YuvToRgbaRow_MIPS32; + WebPSamplers[MODE_BGR] = YuvToBgrRow_MIPS32; + WebPSamplers[MODE_BGRA] = YuvToBgraRow_MIPS32; +} + +#else // !WEBP_USE_MIPS32 + +WEBP_DSP_INIT_STUB(WebPInitSamplersMIPS32) + +#endif // WEBP_USE_MIPS32 diff --git a/libraries/webp/src/dsp/yuv_mips_dsp_r2.c b/libraries/webp/src/dsp/yuv_mips_dsp_r2.c new file mode 100644 index 00000000000..cc8afcc7562 --- /dev/null +++ b/libraries/webp/src/dsp/yuv_mips_dsp_r2.c @@ -0,0 +1,134 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// MIPS DSPr2 version of YUV to RGB upsampling functions. +// +// Author(s): Branimir Vasic (branimir.vasic@imgtec.com) +// Djordje Pesut (djordje.pesut@imgtec.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_MIPS_DSP_R2) + +#include "src/dsp/yuv.h" + +//------------------------------------------------------------------------------ +// simple point-sampling + +#define ROW_FUNC_PART_1() \ + "lbu %[temp3], 0(%[v]) \n\t" \ + "lbu %[temp4], 0(%[u]) \n\t" \ + "lbu %[temp0], 0(%[y]) \n\t" \ + "mul %[temp1], %[t_con_1], %[temp3] \n\t" \ + "mul %[temp3], %[t_con_2], %[temp3] \n\t" \ + "mul %[temp2], %[t_con_3], %[temp4] \n\t" \ + "mul %[temp4], %[t_con_4], %[temp4] \n\t" \ + "mul %[temp0], %[t_con_5], %[temp0] \n\t" \ + "subu %[temp1], %[temp1], %[t_con_6] \n\t" \ + "subu %[temp3], %[temp3], %[t_con_7] \n\t" \ + "addu %[temp2], %[temp2], %[temp3] \n\t" \ + "subu %[temp4], %[temp4], %[t_con_8] \n\t" \ + +#define ROW_FUNC_PART_2(R, G, B, K) \ + "addu %[temp5], %[temp0], %[temp1] \n\t" \ + "subu %[temp6], %[temp0], %[temp2] \n\t" \ + "addu %[temp7], %[temp0], %[temp4] \n\t" \ +".if " #K " \n\t" \ + "lbu %[temp0], 1(%[y]) \n\t" \ +".endif \n\t" \ + "shll_s.w %[temp5], %[temp5], 17 \n\t" \ + "shll_s.w %[temp6], %[temp6], 17 \n\t" \ +".if " #K " \n\t" \ + "mul %[temp0], %[t_con_5], %[temp0] \n\t" \ +".endif \n\t" \ + "shll_s.w %[temp7], %[temp7], 17 \n\t" \ + "precrqu_s.qb.ph %[temp5], %[temp5], $zero \n\t" \ + "precrqu_s.qb.ph %[temp6], %[temp6], $zero \n\t" \ + "precrqu_s.qb.ph %[temp7], %[temp7], $zero \n\t" \ + "srl %[temp5], %[temp5], 24 \n\t" \ + "srl %[temp6], %[temp6], 24 \n\t" \ + "srl %[temp7], %[temp7], 24 \n\t" \ + "sb %[temp5], " #R "(%[dst]) \n\t" \ + "sb %[temp6], " #G "(%[dst]) \n\t" \ + "sb %[temp7], " #B "(%[dst]) \n\t" \ + +#define ASM_CLOBBER_LIST() \ + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \ + [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \ + [temp6]"=&r"(temp6), [temp7]"=&r"(temp7) \ + : [t_con_1]"r"(t_con_1), [t_con_2]"r"(t_con_2), [t_con_3]"r"(t_con_3), \ + [t_con_4]"r"(t_con_4), [t_con_5]"r"(t_con_5), [t_con_6]"r"(t_con_6), \ + [u]"r"(u), [v]"r"(v), [y]"r"(y), [dst]"r"(dst), \ + [t_con_7]"r"(t_con_7), [t_con_8]"r"(t_con_8) \ + : "memory", "hi", "lo" \ + +#define ROW_FUNC(FUNC_NAME, XSTEP, R, G, B, A) \ +static void FUNC_NAME(const uint8_t* y, \ + const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + int i; \ + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; \ + const int t_con_1 = 26149; \ + const int t_con_2 = 13320; \ + const int t_con_3 = 6419; \ + const int t_con_4 = 33050; \ + const int t_con_5 = 19077; \ + const int t_con_6 = 14234; \ + const int t_con_7 = 8708; \ + const int t_con_8 = 17685; \ + for (i = 0; i < (len >> 1); i++) { \ + __asm__ volatile ( \ + ROW_FUNC_PART_1() \ + ROW_FUNC_PART_2(R, G, B, 1) \ + ROW_FUNC_PART_2(R + XSTEP, G + XSTEP, B + XSTEP, 0) \ + ASM_CLOBBER_LIST() \ + ); \ + if (A) dst[A] = dst[A + XSTEP] = 0xff; \ + y += 2; \ + ++u; \ + ++v; \ + dst += 2 * XSTEP; \ + } \ + if (len & 1) { \ + __asm__ volatile ( \ + ROW_FUNC_PART_1() \ + ROW_FUNC_PART_2(R, G, B, 0) \ + ASM_CLOBBER_LIST() \ + ); \ + if (A) dst[A] = 0xff; \ + } \ +} + +ROW_FUNC(YuvToRgbRow_MIPSdspR2, 3, 0, 1, 2, 0) +ROW_FUNC(YuvToRgbaRow_MIPSdspR2, 4, 0, 1, 2, 3) +ROW_FUNC(YuvToBgrRow_MIPSdspR2, 3, 2, 1, 0, 0) +ROW_FUNC(YuvToBgraRow_MIPSdspR2, 4, 2, 1, 0, 3) + +#undef ROW_FUNC +#undef ASM_CLOBBER_LIST +#undef ROW_FUNC_PART_2 +#undef ROW_FUNC_PART_1 + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitSamplersMIPSdspR2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersMIPSdspR2(void) { + WebPSamplers[MODE_RGB] = YuvToRgbRow_MIPSdspR2; + WebPSamplers[MODE_RGBA] = YuvToRgbaRow_MIPSdspR2; + WebPSamplers[MODE_BGR] = YuvToBgrRow_MIPSdspR2; + WebPSamplers[MODE_BGRA] = YuvToBgraRow_MIPSdspR2; +} + +#else // !WEBP_USE_MIPS_DSP_R2 + +WEBP_DSP_INIT_STUB(WebPInitSamplersMIPSdspR2) + +#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libraries/webp/src/dsp/yuv_neon.c b/libraries/webp/src/dsp/yuv_neon.c new file mode 100644 index 00000000000..ff77b009801 --- /dev/null +++ b/libraries/webp/src/dsp/yuv_neon.c @@ -0,0 +1,180 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// YUV->RGB conversion functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/yuv.h" + +#if defined(WEBP_USE_NEON) + +#include +#include + +#include "src/dsp/neon.h" + +//----------------------------------------------------------------------------- + +static uint8x8_t ConvertRGBToY_NEON(const uint8x8_t R, + const uint8x8_t G, + const uint8x8_t B) { + const uint16x8_t r = vmovl_u8(R); + const uint16x8_t g = vmovl_u8(G); + const uint16x8_t b = vmovl_u8(B); + const uint16x4_t r_lo = vget_low_u16(r); + const uint16x4_t r_hi = vget_high_u16(r); + const uint16x4_t g_lo = vget_low_u16(g); + const uint16x4_t g_hi = vget_high_u16(g); + const uint16x4_t b_lo = vget_low_u16(b); + const uint16x4_t b_hi = vget_high_u16(b); + const uint32x4_t tmp0_lo = vmull_n_u16( r_lo, 16839u); + const uint32x4_t tmp0_hi = vmull_n_u16( r_hi, 16839u); + const uint32x4_t tmp1_lo = vmlal_n_u16(tmp0_lo, g_lo, 33059u); + const uint32x4_t tmp1_hi = vmlal_n_u16(tmp0_hi, g_hi, 33059u); + const uint32x4_t tmp2_lo = vmlal_n_u16(tmp1_lo, b_lo, 6420u); + const uint32x4_t tmp2_hi = vmlal_n_u16(tmp1_hi, b_hi, 6420u); + const uint16x8_t Y1 = vcombine_u16(vrshrn_n_u32(tmp2_lo, 16), + vrshrn_n_u32(tmp2_hi, 16)); + const uint16x8_t Y2 = vaddq_u16(Y1, vdupq_n_u16(16)); + return vqmovn_u16(Y2); +} + +static void ConvertRGB24ToY_NEON(const uint8_t* rgb, uint8_t* y, int width) { + int i; + for (i = 0; i + 8 <= width; i += 8, rgb += 3 * 8) { + const uint8x8x3_t RGB = vld3_u8(rgb); + const uint8x8_t Y = ConvertRGBToY_NEON(RGB.val[0], RGB.val[1], RGB.val[2]); + vst1_u8(y + i, Y); + } + for (; i < width; ++i, rgb += 3) { // left-over + y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF); + } +} + +static void ConvertBGR24ToY_NEON(const uint8_t* bgr, uint8_t* y, int width) { + int i; + for (i = 0; i + 8 <= width; i += 8, bgr += 3 * 8) { + const uint8x8x3_t BGR = vld3_u8(bgr); + const uint8x8_t Y = ConvertRGBToY_NEON(BGR.val[2], BGR.val[1], BGR.val[0]); + vst1_u8(y + i, Y); + } + for (; i < width; ++i, bgr += 3) { // left-over + y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF); + } +} + +static void ConvertARGBToY_NEON(const uint32_t* argb, uint8_t* y, int width) { + int i; + for (i = 0; i + 8 <= width; i += 8) { + const uint8x8x4_t RGB = vld4_u8((const uint8_t*)&argb[i]); + const uint8x8_t Y = ConvertRGBToY_NEON(RGB.val[2], RGB.val[1], RGB.val[0]); + vst1_u8(y + i, Y); + } + for (; i < width; ++i) { // left-over + const uint32_t p = argb[i]; + y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff, + YUV_HALF); + } +} + +//----------------------------------------------------------------------------- + +// computes: DST_s16 = [(C0 * r + C1 * g + C2 * b) >> 16] + CST +#define MULTIPLY_16b_PREAMBLE(r, g, b) \ + const int16x4_t r_lo = vreinterpret_s16_u16(vget_low_u16(r)); \ + const int16x4_t r_hi = vreinterpret_s16_u16(vget_high_u16(r)); \ + const int16x4_t g_lo = vreinterpret_s16_u16(vget_low_u16(g)); \ + const int16x4_t g_hi = vreinterpret_s16_u16(vget_high_u16(g)); \ + const int16x4_t b_lo = vreinterpret_s16_u16(vget_low_u16(b)); \ + const int16x4_t b_hi = vreinterpret_s16_u16(vget_high_u16(b)) + +#define MULTIPLY_16b(C0, C1, C2, CST, DST_s16) do { \ + const int32x4_t tmp0_lo = vmull_n_s16( r_lo, C0); \ + const int32x4_t tmp0_hi = vmull_n_s16( r_hi, C0); \ + const int32x4_t tmp1_lo = vmlal_n_s16(tmp0_lo, g_lo, C1); \ + const int32x4_t tmp1_hi = vmlal_n_s16(tmp0_hi, g_hi, C1); \ + const int32x4_t tmp2_lo = vmlal_n_s16(tmp1_lo, b_lo, C2); \ + const int32x4_t tmp2_hi = vmlal_n_s16(tmp1_hi, b_hi, C2); \ + const int16x8_t tmp3 = vcombine_s16(vshrn_n_s32(tmp2_lo, 16), \ + vshrn_n_s32(tmp2_hi, 16)); \ + DST_s16 = vaddq_s16(tmp3, vdupq_n_s16(CST)); \ +} while (0) + +// This needs to be a macro, since (128 << SHIFT) needs to be an immediate. +#define CONVERT_RGB_TO_UV(r, g, b, SHIFT, U_DST, V_DST) do { \ + MULTIPLY_16b_PREAMBLE(r, g, b); \ + MULTIPLY_16b(-9719, -19081, 28800, 128 << SHIFT, U_DST); \ + MULTIPLY_16b(28800, -24116, -4684, 128 << SHIFT, V_DST); \ +} while (0) + +static void ConvertRGBA32ToUV_NEON(const uint16_t* rgb, + uint8_t* u, uint8_t* v, int width) { + int i; + for (i = 0; i + 8 <= width; i += 8, rgb += 4 * 8) { + const uint16x8x4_t RGB = vld4q_u16((const uint16_t*)rgb); + int16x8_t U, V; + CONVERT_RGB_TO_UV(RGB.val[0], RGB.val[1], RGB.val[2], 2, U, V); + vst1_u8(u + i, vqrshrun_n_s16(U, 2)); + vst1_u8(v + i, vqrshrun_n_s16(V, 2)); + } + for (; i < width; i += 1, rgb += 4) { + const int r = rgb[0], g = rgb[1], b = rgb[2]; + u[i] = VP8RGBToU(r, g, b, YUV_HALF << 2); + v[i] = VP8RGBToV(r, g, b, YUV_HALF << 2); + } +} + +static void ConvertARGBToUV_NEON(const uint32_t* argb, uint8_t* u, uint8_t* v, + int src_width, int do_store) { + int i; + for (i = 0; i + 16 <= src_width; i += 16, u += 8, v += 8) { + const uint8x16x4_t RGB = vld4q_u8((const uint8_t*)&argb[i]); + const uint16x8_t R = vpaddlq_u8(RGB.val[2]); // pair-wise adds + const uint16x8_t G = vpaddlq_u8(RGB.val[1]); + const uint16x8_t B = vpaddlq_u8(RGB.val[0]); + int16x8_t U_tmp, V_tmp; + CONVERT_RGB_TO_UV(R, G, B, 1, U_tmp, V_tmp); + { + const uint8x8_t U = vqrshrun_n_s16(U_tmp, 1); + const uint8x8_t V = vqrshrun_n_s16(V_tmp, 1); + if (do_store) { + vst1_u8(u, U); + vst1_u8(v, V); + } else { + const uint8x8_t prev_u = vld1_u8(u); + const uint8x8_t prev_v = vld1_u8(v); + vst1_u8(u, vrhadd_u8(U, prev_u)); + vst1_u8(v, vrhadd_u8(V, prev_v)); + } + } + } + if (i < src_width) { // left-over + WebPConvertARGBToUV_C(argb + i, u, v, src_width - i, do_store); + } +} + + +//------------------------------------------------------------------------------ + +extern void WebPInitConvertARGBToYUVNEON(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVNEON(void) { + WebPConvertRGB24ToY = ConvertRGB24ToY_NEON; + WebPConvertBGR24ToY = ConvertBGR24ToY_NEON; + WebPConvertARGBToY = ConvertARGBToY_NEON; + WebPConvertARGBToUV = ConvertARGBToUV_NEON; + WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_NEON; +} + +#else // !WEBP_USE_NEON + +WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVNEON) + +#endif // WEBP_USE_NEON diff --git a/libraries/webp/src/dsp/yuv_sse2.c b/libraries/webp/src/dsp/yuv_sse2.c new file mode 100644 index 00000000000..01a48f9af2c --- /dev/null +++ b/libraries/webp/src/dsp/yuv_sse2.c @@ -0,0 +1,758 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// YUV->RGB conversion functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/yuv.h" + +#if defined(WEBP_USE_SSE2) + +#include +#include + +#include "src/dsp/common_sse2.h" +#include "src/utils/utils.h" + +//----------------------------------------------------------------------------- +// Convert spans of 32 pixels to various RGB formats for the fancy upsampler. + +// These constants are 14b fixed-point version of ITU-R BT.601 constants. +// R = (19077 * y + 26149 * v - 14234) >> 6 +// G = (19077 * y - 6419 * u - 13320 * v + 8708) >> 6 +// B = (19077 * y + 33050 * u - 17685) >> 6 +static void ConvertYUV444ToRGB_SSE2(const __m128i* const Y0, + const __m128i* const U0, + const __m128i* const V0, + __m128i* const R, + __m128i* const G, + __m128i* const B) { + const __m128i k19077 = _mm_set1_epi16(19077); + const __m128i k26149 = _mm_set1_epi16(26149); + const __m128i k14234 = _mm_set1_epi16(14234); + // 33050 doesn't fit in a signed short: only use this with unsigned arithmetic + const __m128i k33050 = _mm_set1_epi16((short)33050); + const __m128i k17685 = _mm_set1_epi16(17685); + const __m128i k6419 = _mm_set1_epi16(6419); + const __m128i k13320 = _mm_set1_epi16(13320); + const __m128i k8708 = _mm_set1_epi16(8708); + + const __m128i Y1 = _mm_mulhi_epu16(*Y0, k19077); + + const __m128i R0 = _mm_mulhi_epu16(*V0, k26149); + const __m128i R1 = _mm_sub_epi16(Y1, k14234); + const __m128i R2 = _mm_add_epi16(R1, R0); + + const __m128i G0 = _mm_mulhi_epu16(*U0, k6419); + const __m128i G1 = _mm_mulhi_epu16(*V0, k13320); + const __m128i G2 = _mm_add_epi16(Y1, k8708); + const __m128i G3 = _mm_add_epi16(G0, G1); + const __m128i G4 = _mm_sub_epi16(G2, G3); + + // be careful with the saturated *unsigned* arithmetic here! + const __m128i B0 = _mm_mulhi_epu16(*U0, k33050); + const __m128i B1 = _mm_adds_epu16(B0, Y1); + const __m128i B2 = _mm_subs_epu16(B1, k17685); + + // use logical shift for B2, which can be larger than 32767 + *R = _mm_srai_epi16(R2, 6); // range: [-14234, 30815] + *G = _mm_srai_epi16(G4, 6); // range: [-10953, 27710] + *B = _mm_srli_epi16(B2, 6); // range: [0, 34238] +} + +// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically. +static WEBP_INLINE __m128i Load_HI_16_SSE2(const uint8_t* src) { + const __m128i zero = _mm_setzero_si128(); + return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src)); +} + +// Load and replicate the U/V samples +static WEBP_INLINE __m128i Load_UV_HI_8_SSE2(const uint8_t* src) { + const __m128i zero = _mm_setzero_si128(); + const __m128i tmp0 = _mm_cvtsi32_si128(WebPMemToInt32(src)); + const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0); + return _mm_unpacklo_epi16(tmp1, tmp1); // replicate samples +} + +// Convert 32 samples of YUV444 to R/G/B +static void YUV444ToRGB_SSE2(const uint8_t* const y, + const uint8_t* const u, + const uint8_t* const v, + __m128i* const R, __m128i* const G, + __m128i* const B) { + const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_HI_16_SSE2(u), + V0 = Load_HI_16_SSE2(v); + ConvertYUV444ToRGB_SSE2(&Y0, &U0, &V0, R, G, B); +} + +// Convert 32 samples of YUV420 to R/G/B +static void YUV420ToRGB_SSE2(const uint8_t* const y, + const uint8_t* const u, + const uint8_t* const v, + __m128i* const R, __m128i* const G, + __m128i* const B) { + const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_UV_HI_8_SSE2(u), + V0 = Load_UV_HI_8_SSE2(v); + ConvertYUV444ToRGB_SSE2(&Y0, &U0, &V0, R, G, B); +} + +// Pack R/G/B/A results into 32b output. +static WEBP_INLINE void PackAndStore4_SSE2(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + const __m128i* const A, + uint8_t* const dst) { + const __m128i rb = _mm_packus_epi16(*R, *B); + const __m128i ga = _mm_packus_epi16(*G, *A); + const __m128i rg = _mm_unpacklo_epi8(rb, ga); + const __m128i ba = _mm_unpackhi_epi8(rb, ga); + const __m128i RGBA_lo = _mm_unpacklo_epi16(rg, ba); + const __m128i RGBA_hi = _mm_unpackhi_epi16(rg, ba); + _mm_storeu_si128((__m128i*)(dst + 0), RGBA_lo); + _mm_storeu_si128((__m128i*)(dst + 16), RGBA_hi); +} + +// Pack R/G/B/A results into 16b output. +static WEBP_INLINE void PackAndStore4444_SSE2(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + const __m128i* const A, + uint8_t* const dst) { +#if (WEBP_SWAP_16BIT_CSP == 0) + const __m128i rg0 = _mm_packus_epi16(*R, *G); + const __m128i ba0 = _mm_packus_epi16(*B, *A); +#else + const __m128i rg0 = _mm_packus_epi16(*B, *A); + const __m128i ba0 = _mm_packus_epi16(*R, *G); +#endif + const __m128i mask_0xf0 = _mm_set1_epi8((char)0xf0); + const __m128i rb1 = _mm_unpacklo_epi8(rg0, ba0); // rbrbrbrbrb... + const __m128i ga1 = _mm_unpackhi_epi8(rg0, ba0); // gagagagaga... + const __m128i rb2 = _mm_and_si128(rb1, mask_0xf0); + const __m128i ga2 = _mm_srli_epi16(_mm_and_si128(ga1, mask_0xf0), 4); + const __m128i rgba4444 = _mm_or_si128(rb2, ga2); + _mm_storeu_si128((__m128i*)dst, rgba4444); +} + +// Pack R/G/B results into 16b output. +static WEBP_INLINE void PackAndStore565_SSE2(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + uint8_t* const dst) { + const __m128i r0 = _mm_packus_epi16(*R, *R); + const __m128i g0 = _mm_packus_epi16(*G, *G); + const __m128i b0 = _mm_packus_epi16(*B, *B); + const __m128i r1 = _mm_and_si128(r0, _mm_set1_epi8((char)0xf8)); + const __m128i b1 = _mm_and_si128(_mm_srli_epi16(b0, 3), _mm_set1_epi8(0x1f)); + const __m128i g1 = + _mm_srli_epi16(_mm_and_si128(g0, _mm_set1_epi8((char)0xe0)), 5); + const __m128i g2 = _mm_slli_epi16(_mm_and_si128(g0, _mm_set1_epi8(0x1c)), 3); + const __m128i rg = _mm_or_si128(r1, g1); + const __m128i gb = _mm_or_si128(g2, b1); +#if (WEBP_SWAP_16BIT_CSP == 0) + const __m128i rgb565 = _mm_unpacklo_epi8(rg, gb); +#else + const __m128i rgb565 = _mm_unpacklo_epi8(gb, rg); +#endif + _mm_storeu_si128((__m128i*)dst, rgb565); +} + +// Pack the planar buffers +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... +static WEBP_INLINE void PlanarTo24b_SSE2(__m128i* const in0, __m128i* const in1, + __m128i* const in2, __m128i* const in3, + __m128i* const in4, __m128i* const in5, + uint8_t* const rgb) { + // The input is 6 registers of sixteen 8b but for the sake of explanation, + // let's take 6 registers of four 8b values. + // To pack, we will keep taking one every two 8b integer and move it + // around as follows: + // Input: + // r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7 + // Split the 6 registers in two sets of 3 registers: the first set as the even + // 8b bytes, the second the odd ones: + // r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7 + // Repeat the same permutations twice more: + // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7 + // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7 + VP8PlanarTo24b_SSE2(in0, in1, in2, in3, in4, in5); + + _mm_storeu_si128((__m128i*)(rgb + 0), *in0); + _mm_storeu_si128((__m128i*)(rgb + 16), *in1); + _mm_storeu_si128((__m128i*)(rgb + 32), *in2); + _mm_storeu_si128((__m128i*)(rgb + 48), *in3); + _mm_storeu_si128((__m128i*)(rgb + 64), *in4); + _mm_storeu_si128((__m128i*)(rgb + 80), *in5); +} + +void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + const __m128i kAlpha = _mm_set1_epi16(255); + int n; + for (n = 0; n < 32; n += 8, dst += 32) { + __m128i R, G, B; + YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B); + PackAndStore4_SSE2(&R, &G, &B, &kAlpha, dst); + } +} + +void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + const __m128i kAlpha = _mm_set1_epi16(255); + int n; + for (n = 0; n < 32; n += 8, dst += 32) { + __m128i R, G, B; + YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B); + PackAndStore4_SSE2(&B, &G, &R, &kAlpha, dst); + } +} + +void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + const __m128i kAlpha = _mm_set1_epi16(255); + int n; + for (n = 0; n < 32; n += 8, dst += 32) { + __m128i R, G, B; + YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B); + PackAndStore4_SSE2(&kAlpha, &R, &G, &B, dst); + } +} + +void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u, + const uint8_t* v, uint8_t* dst) { + const __m128i kAlpha = _mm_set1_epi16(255); + int n; + for (n = 0; n < 32; n += 8, dst += 16) { + __m128i R, G, B; + YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B); + PackAndStore4444_SSE2(&R, &G, &B, &kAlpha, dst); + } +} + +void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + int n; + for (n = 0; n < 32; n += 8, dst += 16) { + __m128i R, G, B; + YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B); + PackAndStore565_SSE2(&R, &G, &B, dst); + } +} + +void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; + + YUV444ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV444ToRGB_SSE2(y + 8, u + 8, v + 8, &R1, &G1, &B1); + YUV444ToRGB_SSE2(y + 16, u + 16, v + 16, &R2, &G2, &B2); + YUV444ToRGB_SSE2(y + 24, u + 24, v + 24, &R3, &G3, &B3); + + // Cast to 8b and store as RRRRGGGGBBBB. + rgb0 = _mm_packus_epi16(R0, R1); + rgb1 = _mm_packus_epi16(R2, R3); + rgb2 = _mm_packus_epi16(G0, G1); + rgb3 = _mm_packus_epi16(G2, G3); + rgb4 = _mm_packus_epi16(B0, B1); + rgb5 = _mm_packus_epi16(B2, B3); + + // Pack as RGBRGBRGBRGB. + PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); +} + +void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; + + YUV444ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV444ToRGB_SSE2(y + 8, u + 8, v + 8, &R1, &G1, &B1); + YUV444ToRGB_SSE2(y + 16, u + 16, v + 16, &R2, &G2, &B2); + YUV444ToRGB_SSE2(y + 24, u + 24, v + 24, &R3, &G3, &B3); + + // Cast to 8b and store as BBBBGGGGRRRR. + bgr0 = _mm_packus_epi16(B0, B1); + bgr1 = _mm_packus_epi16(B2, B3); + bgr2 = _mm_packus_epi16(G0, G1); + bgr3 = _mm_packus_epi16(G2, G3); + bgr4 = _mm_packus_epi16(R0, R1); + bgr5= _mm_packus_epi16(R2, R3); + + // Pack as BGRBGRBGRBGR. + PlanarTo24b_SSE2(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst); +} + +//----------------------------------------------------------------------------- +// Arbitrary-length row conversion functions + +static void YuvToRgbaRow_SSE2(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + const __m128i kAlpha = _mm_set1_epi16(255); + int n; + for (n = 0; n + 8 <= len; n += 8, dst += 32) { + __m128i R, G, B; + YUV420ToRGB_SSE2(y, u, v, &R, &G, &B); + PackAndStore4_SSE2(&R, &G, &B, &kAlpha, dst); + y += 8; + u += 4; + v += 4; + } + for (; n < len; ++n) { // Finish off + VP8YuvToRgba(y[0], u[0], v[0], dst); + dst += 4; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +static void YuvToBgraRow_SSE2(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + const __m128i kAlpha = _mm_set1_epi16(255); + int n; + for (n = 0; n + 8 <= len; n += 8, dst += 32) { + __m128i R, G, B; + YUV420ToRGB_SSE2(y, u, v, &R, &G, &B); + PackAndStore4_SSE2(&B, &G, &R, &kAlpha, dst); + y += 8; + u += 4; + v += 4; + } + for (; n < len; ++n) { // Finish off + VP8YuvToBgra(y[0], u[0], v[0], dst); + dst += 4; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +static void YuvToArgbRow_SSE2(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + const __m128i kAlpha = _mm_set1_epi16(255); + int n; + for (n = 0; n + 8 <= len; n += 8, dst += 32) { + __m128i R, G, B; + YUV420ToRGB_SSE2(y, u, v, &R, &G, &B); + PackAndStore4_SSE2(&kAlpha, &R, &G, &B, dst); + y += 8; + u += 4; + v += 4; + } + for (; n < len; ++n) { // Finish off + VP8YuvToArgb(y[0], u[0], v[0], dst); + dst += 4; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +static void YuvToRgbRow_SSE2(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + int n; + for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; + + YUV420ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV420ToRGB_SSE2(y + 8, u + 4, v + 4, &R1, &G1, &B1); + YUV420ToRGB_SSE2(y + 16, u + 8, v + 8, &R2, &G2, &B2); + YUV420ToRGB_SSE2(y + 24, u + 12, v + 12, &R3, &G3, &B3); + + // Cast to 8b and store as RRRRGGGGBBBB. + rgb0 = _mm_packus_epi16(R0, R1); + rgb1 = _mm_packus_epi16(R2, R3); + rgb2 = _mm_packus_epi16(G0, G1); + rgb3 = _mm_packus_epi16(G2, G3); + rgb4 = _mm_packus_epi16(B0, B1); + rgb5 = _mm_packus_epi16(B2, B3); + + // Pack as RGBRGBRGBRGB. + PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); + + y += 32; + u += 16; + v += 16; + } + for (; n < len; ++n) { // Finish off + VP8YuvToRgb(y[0], u[0], v[0], dst); + dst += 3; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +static void YuvToBgrRow_SSE2(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + int n; + for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; + + YUV420ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV420ToRGB_SSE2(y + 8, u + 4, v + 4, &R1, &G1, &B1); + YUV420ToRGB_SSE2(y + 16, u + 8, v + 8, &R2, &G2, &B2); + YUV420ToRGB_SSE2(y + 24, u + 12, v + 12, &R3, &G3, &B3); + + // Cast to 8b and store as BBBBGGGGRRRR. + bgr0 = _mm_packus_epi16(B0, B1); + bgr1 = _mm_packus_epi16(B2, B3); + bgr2 = _mm_packus_epi16(G0, G1); + bgr3 = _mm_packus_epi16(G2, G3); + bgr4 = _mm_packus_epi16(R0, R1); + bgr5 = _mm_packus_epi16(R2, R3); + + // Pack as BGRBGRBGRBGR. + PlanarTo24b_SSE2(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst); + + y += 32; + u += 16; + v += 16; + } + for (; n < len; ++n) { // Finish off + VP8YuvToBgr(y[0], u[0], v[0], dst); + dst += 3; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitSamplersSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE2(void) { + WebPSamplers[MODE_RGB] = YuvToRgbRow_SSE2; + WebPSamplers[MODE_RGBA] = YuvToRgbaRow_SSE2; + WebPSamplers[MODE_BGR] = YuvToBgrRow_SSE2; + WebPSamplers[MODE_BGRA] = YuvToBgraRow_SSE2; + WebPSamplers[MODE_ARGB] = YuvToArgbRow_SSE2; +} + +//------------------------------------------------------------------------------ +// RGB24/32 -> YUV converters + +// Load eight 16b-words from *src. +#define LOAD_16(src) _mm_loadu_si128((const __m128i*)(src)) +// Store either 16b-words into *dst +#define STORE_16(V, dst) _mm_storeu_si128((__m128i*)(dst), (V)) + +// Function that inserts a value of the second half of the in buffer in between +// every two char of the first half. +static WEBP_INLINE void RGB24PackedToPlanarHelper_SSE2( + const __m128i* const in /*in[6]*/, __m128i* const out /*out[6]*/) { + out[0] = _mm_unpacklo_epi8(in[0], in[3]); + out[1] = _mm_unpackhi_epi8(in[0], in[3]); + out[2] = _mm_unpacklo_epi8(in[1], in[4]); + out[3] = _mm_unpackhi_epi8(in[1], in[4]); + out[4] = _mm_unpacklo_epi8(in[2], in[5]); + out[5] = _mm_unpackhi_epi8(in[2], in[5]); +} + +// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers: +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// Similar to PlanarTo24bHelper(), but in reverse order. +static WEBP_INLINE void RGB24PackedToPlanar_SSE2( + const uint8_t* const rgb, __m128i* const out /*out[6]*/) { + __m128i tmp[6]; + tmp[0] = _mm_loadu_si128((const __m128i*)(rgb + 0)); + tmp[1] = _mm_loadu_si128((const __m128i*)(rgb + 16)); + tmp[2] = _mm_loadu_si128((const __m128i*)(rgb + 32)); + tmp[3] = _mm_loadu_si128((const __m128i*)(rgb + 48)); + tmp[4] = _mm_loadu_si128((const __m128i*)(rgb + 64)); + tmp[5] = _mm_loadu_si128((const __m128i*)(rgb + 80)); + + RGB24PackedToPlanarHelper_SSE2(tmp, out); + RGB24PackedToPlanarHelper_SSE2(out, tmp); + RGB24PackedToPlanarHelper_SSE2(tmp, out); + RGB24PackedToPlanarHelper_SSE2(out, tmp); + RGB24PackedToPlanarHelper_SSE2(tmp, out); +} + +// Convert 8 packed ARGB to r[], g[], b[] +static WEBP_INLINE void RGB32PackedToPlanar_SSE2(const uint32_t* const argb, + __m128i* const rgb /*in[6]*/) { + const __m128i zero = _mm_setzero_si128(); + __m128i a0 = LOAD_16(argb + 0); + __m128i a1 = LOAD_16(argb + 4); + __m128i a2 = LOAD_16(argb + 8); + __m128i a3 = LOAD_16(argb + 12); + VP8L32bToPlanar_SSE2(&a0, &a1, &a2, &a3); + rgb[0] = _mm_unpacklo_epi8(a1, zero); + rgb[1] = _mm_unpackhi_epi8(a1, zero); + rgb[2] = _mm_unpacklo_epi8(a2, zero); + rgb[3] = _mm_unpackhi_epi8(a2, zero); + rgb[4] = _mm_unpacklo_epi8(a3, zero); + rgb[5] = _mm_unpackhi_epi8(a3, zero); +} + +// This macro computes (RG * MULT_RG + GB * MULT_GB + ROUNDER) >> DESCALE_FIX +// It's a macro and not a function because we need to use immediate values with +// srai_epi32, e.g. +#define TRANSFORM(RG_LO, RG_HI, GB_LO, GB_HI, MULT_RG, MULT_GB, \ + ROUNDER, DESCALE_FIX, OUT) do { \ + const __m128i V0_lo = _mm_madd_epi16(RG_LO, MULT_RG); \ + const __m128i V0_hi = _mm_madd_epi16(RG_HI, MULT_RG); \ + const __m128i V1_lo = _mm_madd_epi16(GB_LO, MULT_GB); \ + const __m128i V1_hi = _mm_madd_epi16(GB_HI, MULT_GB); \ + const __m128i V2_lo = _mm_add_epi32(V0_lo, V1_lo); \ + const __m128i V2_hi = _mm_add_epi32(V0_hi, V1_hi); \ + const __m128i V3_lo = _mm_add_epi32(V2_lo, ROUNDER); \ + const __m128i V3_hi = _mm_add_epi32(V2_hi, ROUNDER); \ + const __m128i V5_lo = _mm_srai_epi32(V3_lo, DESCALE_FIX); \ + const __m128i V5_hi = _mm_srai_epi32(V3_hi, DESCALE_FIX); \ + (OUT) = _mm_packs_epi32(V5_lo, V5_hi); \ +} while (0) + +#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A)) +static WEBP_INLINE void ConvertRGBToY_SSE2(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + __m128i* const Y) { + const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384); + const __m128i kGB_y = MK_CST_16(16384, 6420); + const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF); + + const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G); + const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G); + const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B); + const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y); +} + +static WEBP_INLINE void ConvertRGBToUV_SSE2(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + __m128i* const U, + __m128i* const V) { + const __m128i kRG_u = MK_CST_16(-9719, -19081); + const __m128i kGB_u = MK_CST_16(0, 28800); + const __m128i kRG_v = MK_CST_16(28800, 0); + const __m128i kGB_v = MK_CST_16(-24116, -4684); + const __m128i kHALF_UV = _mm_set1_epi32(((128 << YUV_FIX) + YUV_HALF) << 2); + + const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G); + const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G); + const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B); + const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_u, kGB_u, + kHALF_UV, YUV_FIX + 2, *U); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_v, kGB_v, + kHALF_UV, YUV_FIX + 2, *V); +} + +#undef MK_CST_16 +#undef TRANSFORM + +static void ConvertRGB24ToY_SSE2(const uint8_t* rgb, uint8_t* y, int width) { + const int max_width = width & ~31; + int i; + for (i = 0; i < max_width; rgb += 3 * 16 * 2) { + __m128i rgb_plane[6]; + int j; + + RGB24PackedToPlanar_SSE2(rgb, rgb_plane); + + for (j = 0; j < 2; ++j, i += 16) { + const __m128i zero = _mm_setzero_si128(); + __m128i r, g, b, Y0, Y1; + + // Convert to 16-bit Y. + r = _mm_unpacklo_epi8(rgb_plane[0 + j], zero); + g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero); + b = _mm_unpacklo_epi8(rgb_plane[4 + j], zero); + ConvertRGBToY_SSE2(&r, &g, &b, &Y0); + + // Convert to 16-bit Y. + r = _mm_unpackhi_epi8(rgb_plane[0 + j], zero); + g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero); + b = _mm_unpackhi_epi8(rgb_plane[4 + j], zero); + ConvertRGBToY_SSE2(&r, &g, &b, &Y1); + + // Cast to 8-bit and store. + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + } + for (; i < width; ++i, rgb += 3) { // left-over + y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF); + } +} + +static void ConvertBGR24ToY_SSE2(const uint8_t* bgr, uint8_t* y, int width) { + const int max_width = width & ~31; + int i; + for (i = 0; i < max_width; bgr += 3 * 16 * 2) { + __m128i bgr_plane[6]; + int j; + + RGB24PackedToPlanar_SSE2(bgr, bgr_plane); + + for (j = 0; j < 2; ++j, i += 16) { + const __m128i zero = _mm_setzero_si128(); + __m128i r, g, b, Y0, Y1; + + // Convert to 16-bit Y. + b = _mm_unpacklo_epi8(bgr_plane[0 + j], zero); + g = _mm_unpacklo_epi8(bgr_plane[2 + j], zero); + r = _mm_unpacklo_epi8(bgr_plane[4 + j], zero); + ConvertRGBToY_SSE2(&r, &g, &b, &Y0); + + // Convert to 16-bit Y. + b = _mm_unpackhi_epi8(bgr_plane[0 + j], zero); + g = _mm_unpackhi_epi8(bgr_plane[2 + j], zero); + r = _mm_unpackhi_epi8(bgr_plane[4 + j], zero); + ConvertRGBToY_SSE2(&r, &g, &b, &Y1); + + // Cast to 8-bit and store. + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + } + for (; i < width; ++i, bgr += 3) { // left-over + y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF); + } +} + +static void ConvertARGBToY_SSE2(const uint32_t* argb, uint8_t* y, int width) { + const int max_width = width & ~15; + int i; + for (i = 0; i < max_width; i += 16) { + __m128i Y0, Y1, rgb[6]; + RGB32PackedToPlanar_SSE2(&argb[i], rgb); + ConvertRGBToY_SSE2(&rgb[0], &rgb[2], &rgb[4], &Y0); + ConvertRGBToY_SSE2(&rgb[1], &rgb[3], &rgb[5], &Y1); + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + for (; i < width; ++i) { // left-over + const uint32_t p = argb[i]; + y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff, + YUV_HALF); + } +} + +// Horizontal add (doubled) of two 16b values, result is 16b. +// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ... +static void HorizontalAddPack_SSE2(const __m128i* const A, + const __m128i* const B, + __m128i* const out) { + const __m128i k2 = _mm_set1_epi16(2); + const __m128i C = _mm_madd_epi16(*A, k2); + const __m128i D = _mm_madd_epi16(*B, k2); + *out = _mm_packs_epi32(C, D); +} + +static void ConvertARGBToUV_SSE2(const uint32_t* argb, + uint8_t* u, uint8_t* v, + int src_width, int do_store) { + const int max_width = src_width & ~31; + int i; + for (i = 0; i < max_width; i += 32, u += 16, v += 16) { + __m128i rgb[6], U0, V0, U1, V1; + RGB32PackedToPlanar_SSE2(&argb[i], rgb); + HorizontalAddPack_SSE2(&rgb[0], &rgb[1], &rgb[0]); + HorizontalAddPack_SSE2(&rgb[2], &rgb[3], &rgb[2]); + HorizontalAddPack_SSE2(&rgb[4], &rgb[5], &rgb[4]); + ConvertRGBToUV_SSE2(&rgb[0], &rgb[2], &rgb[4], &U0, &V0); + + RGB32PackedToPlanar_SSE2(&argb[i + 16], rgb); + HorizontalAddPack_SSE2(&rgb[0], &rgb[1], &rgb[0]); + HorizontalAddPack_SSE2(&rgb[2], &rgb[3], &rgb[2]); + HorizontalAddPack_SSE2(&rgb[4], &rgb[5], &rgb[4]); + ConvertRGBToUV_SSE2(&rgb[0], &rgb[2], &rgb[4], &U1, &V1); + + U0 = _mm_packus_epi16(U0, U1); + V0 = _mm_packus_epi16(V0, V1); + if (!do_store) { + const __m128i prev_u = LOAD_16(u); + const __m128i prev_v = LOAD_16(v); + U0 = _mm_avg_epu8(U0, prev_u); + V0 = _mm_avg_epu8(V0, prev_v); + } + STORE_16(U0, u); + STORE_16(V0, v); + } + if (i < src_width) { // left-over + WebPConvertARGBToUV_C(argb + i, u, v, src_width - i, do_store); + } +} + +// Convert 16 packed ARGB 16b-values to r[], g[], b[] +static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE2( + const uint16_t* const rgbx, + __m128i* const r, __m128i* const g, __m128i* const b) { + const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x + const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x + const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ... + const __m128i in3 = LOAD_16(rgbx + 24); // r6 | ... + // column-wise transpose + const __m128i A0 = _mm_unpacklo_epi16(in0, in1); + const __m128i A1 = _mm_unpackhi_epi16(in0, in1); + const __m128i A2 = _mm_unpacklo_epi16(in2, in3); + const __m128i A3 = _mm_unpackhi_epi16(in2, in3); + const __m128i B0 = _mm_unpacklo_epi16(A0, A1); // r0 r1 r2 r3 | g0 g1 .. + const __m128i B1 = _mm_unpackhi_epi16(A0, A1); // b0 b1 b2 b3 | x x x x + const __m128i B2 = _mm_unpacklo_epi16(A2, A3); // r4 r5 r6 r7 | g4 g5 .. + const __m128i B3 = _mm_unpackhi_epi16(A2, A3); // b4 b5 b6 b7 | x x x x + *r = _mm_unpacklo_epi64(B0, B2); + *g = _mm_unpackhi_epi64(B0, B2); + *b = _mm_unpacklo_epi64(B1, B3); +} + +static void ConvertRGBA32ToUV_SSE2(const uint16_t* rgb, + uint8_t* u, uint8_t* v, int width) { + const int max_width = width & ~15; + const uint16_t* const last_rgb = rgb + 4 * max_width; + while (rgb < last_rgb) { + __m128i r, g, b, U0, V0, U1, V1; + RGBA32PackedToPlanar_16b_SSE2(rgb + 0, &r, &g, &b); + ConvertRGBToUV_SSE2(&r, &g, &b, &U0, &V0); + RGBA32PackedToPlanar_16b_SSE2(rgb + 32, &r, &g, &b); + ConvertRGBToUV_SSE2(&r, &g, &b, &U1, &V1); + STORE_16(_mm_packus_epi16(U0, U1), u); + STORE_16(_mm_packus_epi16(V0, V1), v); + u += 16; + v += 16; + rgb += 2 * 32; + } + if (max_width < width) { // left-over + WebPConvertRGBA32ToUV_C(rgb, u, v, width - max_width); + } +} + +//------------------------------------------------------------------------------ + +extern void WebPInitConvertARGBToYUVSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) { + WebPConvertARGBToY = ConvertARGBToY_SSE2; + WebPConvertARGBToUV = ConvertARGBToUV_SSE2; + + WebPConvertRGB24ToY = ConvertRGB24ToY_SSE2; + WebPConvertBGR24ToY = ConvertBGR24ToY_SSE2; + + WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE2; +} + +#else // !WEBP_USE_SSE2 + +WEBP_DSP_INIT_STUB(WebPInitSamplersSSE2) +WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE2) + +#endif // WEBP_USE_SSE2 diff --git a/libraries/webp/src/dsp/yuv_sse41.c b/libraries/webp/src/dsp/yuv_sse41.c new file mode 100644 index 00000000000..f79b802e471 --- /dev/null +++ b/libraries/webp/src/dsp/yuv_sse41.c @@ -0,0 +1,615 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// YUV->RGB conversion functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/yuv.h" + +#if defined(WEBP_USE_SSE41) + +#include +#include + +#include "src/dsp/common_sse41.h" +#include "src/utils/utils.h" + +//----------------------------------------------------------------------------- +// Convert spans of 32 pixels to various RGB formats for the fancy upsampler. + +// These constants are 14b fixed-point version of ITU-R BT.601 constants. +// R = (19077 * y + 26149 * v - 14234) >> 6 +// G = (19077 * y - 6419 * u - 13320 * v + 8708) >> 6 +// B = (19077 * y + 33050 * u - 17685) >> 6 +static void ConvertYUV444ToRGB_SSE41(const __m128i* const Y0, + const __m128i* const U0, + const __m128i* const V0, + __m128i* const R, + __m128i* const G, + __m128i* const B) { + const __m128i k19077 = _mm_set1_epi16(19077); + const __m128i k26149 = _mm_set1_epi16(26149); + const __m128i k14234 = _mm_set1_epi16(14234); + // 33050 doesn't fit in a signed short: only use this with unsigned arithmetic + const __m128i k33050 = _mm_set1_epi16((short)33050); + const __m128i k17685 = _mm_set1_epi16(17685); + const __m128i k6419 = _mm_set1_epi16(6419); + const __m128i k13320 = _mm_set1_epi16(13320); + const __m128i k8708 = _mm_set1_epi16(8708); + + const __m128i Y1 = _mm_mulhi_epu16(*Y0, k19077); + + const __m128i R0 = _mm_mulhi_epu16(*V0, k26149); + const __m128i R1 = _mm_sub_epi16(Y1, k14234); + const __m128i R2 = _mm_add_epi16(R1, R0); + + const __m128i G0 = _mm_mulhi_epu16(*U0, k6419); + const __m128i G1 = _mm_mulhi_epu16(*V0, k13320); + const __m128i G2 = _mm_add_epi16(Y1, k8708); + const __m128i G3 = _mm_add_epi16(G0, G1); + const __m128i G4 = _mm_sub_epi16(G2, G3); + + // be careful with the saturated *unsigned* arithmetic here! + const __m128i B0 = _mm_mulhi_epu16(*U0, k33050); + const __m128i B1 = _mm_adds_epu16(B0, Y1); + const __m128i B2 = _mm_subs_epu16(B1, k17685); + + // use logical shift for B2, which can be larger than 32767 + *R = _mm_srai_epi16(R2, 6); // range: [-14234, 30815] + *G = _mm_srai_epi16(G4, 6); // range: [-10953, 27710] + *B = _mm_srli_epi16(B2, 6); // range: [0, 34238] +} + +// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically. +static WEBP_INLINE __m128i Load_HI_16_SSE41(const uint8_t* src) { + const __m128i zero = _mm_setzero_si128(); + return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src)); +} + +// Load and replicate the U/V samples +static WEBP_INLINE __m128i Load_UV_HI_8_SSE41(const uint8_t* src) { + const __m128i zero = _mm_setzero_si128(); + const __m128i tmp0 = _mm_cvtsi32_si128(WebPMemToInt32(src)); + const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0); + return _mm_unpacklo_epi16(tmp1, tmp1); // replicate samples +} + +// Convert 32 samples of YUV444 to R/G/B +static void YUV444ToRGB_SSE41(const uint8_t* const y, + const uint8_t* const u, + const uint8_t* const v, + __m128i* const R, __m128i* const G, + __m128i* const B) { + const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_HI_16_SSE41(u), + V0 = Load_HI_16_SSE41(v); + ConvertYUV444ToRGB_SSE41(&Y0, &U0, &V0, R, G, B); +} + +// Convert 32 samples of YUV420 to R/G/B +static void YUV420ToRGB_SSE41(const uint8_t* const y, + const uint8_t* const u, + const uint8_t* const v, + __m128i* const R, __m128i* const G, + __m128i* const B) { + const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_UV_HI_8_SSE41(u), + V0 = Load_UV_HI_8_SSE41(v); + ConvertYUV444ToRGB_SSE41(&Y0, &U0, &V0, R, G, B); +} + +// Pack the planar buffers +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... +static WEBP_INLINE void PlanarTo24b_SSE41( + __m128i* const in0, __m128i* const in1, __m128i* const in2, + __m128i* const in3, __m128i* const in4, __m128i* const in5, + uint8_t* const rgb) { + // The input is 6 registers of sixteen 8b but for the sake of explanation, + // let's take 6 registers of four 8b values. + // To pack, we will keep taking one every two 8b integer and move it + // around as follows: + // Input: + // r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7 + // Split the 6 registers in two sets of 3 registers: the first set as the even + // 8b bytes, the second the odd ones: + // r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7 + // Repeat the same permutations twice more: + // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7 + // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7 + VP8PlanarTo24b_SSE41(in0, in1, in2, in3, in4, in5); + + _mm_storeu_si128((__m128i*)(rgb + 0), *in0); + _mm_storeu_si128((__m128i*)(rgb + 16), *in1); + _mm_storeu_si128((__m128i*)(rgb + 32), *in2); + _mm_storeu_si128((__m128i*)(rgb + 48), *in3); + _mm_storeu_si128((__m128i*)(rgb + 64), *in4); + _mm_storeu_si128((__m128i*)(rgb + 80), *in5); +} + +void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; + + YUV444ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV444ToRGB_SSE41(y + 8, u + 8, v + 8, &R1, &G1, &B1); + YUV444ToRGB_SSE41(y + 16, u + 16, v + 16, &R2, &G2, &B2); + YUV444ToRGB_SSE41(y + 24, u + 24, v + 24, &R3, &G3, &B3); + + // Cast to 8b and store as RRRRGGGGBBBB. + rgb0 = _mm_packus_epi16(R0, R1); + rgb1 = _mm_packus_epi16(R2, R3); + rgb2 = _mm_packus_epi16(G0, G1); + rgb3 = _mm_packus_epi16(G2, G3); + rgb4 = _mm_packus_epi16(B0, B1); + rgb5 = _mm_packus_epi16(B2, B3); + + // Pack as RGBRGBRGBRGB. + PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); +} + +void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; + + YUV444ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV444ToRGB_SSE41(y + 8, u + 8, v + 8, &R1, &G1, &B1); + YUV444ToRGB_SSE41(y + 16, u + 16, v + 16, &R2, &G2, &B2); + YUV444ToRGB_SSE41(y + 24, u + 24, v + 24, &R3, &G3, &B3); + + // Cast to 8b and store as BBBBGGGGRRRR. + bgr0 = _mm_packus_epi16(B0, B1); + bgr1 = _mm_packus_epi16(B2, B3); + bgr2 = _mm_packus_epi16(G0, G1); + bgr3 = _mm_packus_epi16(G2, G3); + bgr4 = _mm_packus_epi16(R0, R1); + bgr5= _mm_packus_epi16(R2, R3); + + // Pack as BGRBGRBGRBGR. + PlanarTo24b_SSE41(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst); +} + +//----------------------------------------------------------------------------- +// Arbitrary-length row conversion functions + +static void YuvToRgbRow_SSE41(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + int n; + for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; + + YUV420ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV420ToRGB_SSE41(y + 8, u + 4, v + 4, &R1, &G1, &B1); + YUV420ToRGB_SSE41(y + 16, u + 8, v + 8, &R2, &G2, &B2); + YUV420ToRGB_SSE41(y + 24, u + 12, v + 12, &R3, &G3, &B3); + + // Cast to 8b and store as RRRRGGGGBBBB. + rgb0 = _mm_packus_epi16(R0, R1); + rgb1 = _mm_packus_epi16(R2, R3); + rgb2 = _mm_packus_epi16(G0, G1); + rgb3 = _mm_packus_epi16(G2, G3); + rgb4 = _mm_packus_epi16(B0, B1); + rgb5 = _mm_packus_epi16(B2, B3); + + // Pack as RGBRGBRGBRGB. + PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); + + y += 32; + u += 16; + v += 16; + } + for (; n < len; ++n) { // Finish off + VP8YuvToRgb(y[0], u[0], v[0], dst); + dst += 3; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +static void YuvToBgrRow_SSE41(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + int n; + for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; + + YUV420ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV420ToRGB_SSE41(y + 8, u + 4, v + 4, &R1, &G1, &B1); + YUV420ToRGB_SSE41(y + 16, u + 8, v + 8, &R2, &G2, &B2); + YUV420ToRGB_SSE41(y + 24, u + 12, v + 12, &R3, &G3, &B3); + + // Cast to 8b and store as BBBBGGGGRRRR. + bgr0 = _mm_packus_epi16(B0, B1); + bgr1 = _mm_packus_epi16(B2, B3); + bgr2 = _mm_packus_epi16(G0, G1); + bgr3 = _mm_packus_epi16(G2, G3); + bgr4 = _mm_packus_epi16(R0, R1); + bgr5 = _mm_packus_epi16(R2, R3); + + // Pack as BGRBGRBGRBGR. + PlanarTo24b_SSE41(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst); + + y += 32; + u += 16; + v += 16; + } + for (; n < len; ++n) { // Finish off + VP8YuvToBgr(y[0], u[0], v[0], dst); + dst += 3; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitSamplersSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE41(void) { + WebPSamplers[MODE_RGB] = YuvToRgbRow_SSE41; + WebPSamplers[MODE_BGR] = YuvToBgrRow_SSE41; +} + +//------------------------------------------------------------------------------ +// RGB24/32 -> YUV converters + +// Load eight 16b-words from *src. +#define LOAD_16(src) _mm_loadu_si128((const __m128i*)(src)) +// Store either 16b-words into *dst +#define STORE_16(V, dst) _mm_storeu_si128((__m128i*)(dst), (V)) + +#define WEBP_SSE41_SHUFF(OUT) do { \ + const __m128i tmp0 = _mm_shuffle_epi8(A0, shuff0); \ + const __m128i tmp1 = _mm_shuffle_epi8(A1, shuff1); \ + const __m128i tmp2 = _mm_shuffle_epi8(A2, shuff2); \ + const __m128i tmp3 = _mm_shuffle_epi8(A3, shuff0); \ + const __m128i tmp4 = _mm_shuffle_epi8(A4, shuff1); \ + const __m128i tmp5 = _mm_shuffle_epi8(A5, shuff2); \ + \ + /* OR everything to get one channel */ \ + const __m128i tmp6 = _mm_or_si128(tmp0, tmp1); \ + const __m128i tmp7 = _mm_or_si128(tmp3, tmp4); \ + out[OUT + 0] = _mm_or_si128(tmp6, tmp2); \ + out[OUT + 1] = _mm_or_si128(tmp7, tmp5); \ +} while (0); + +// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers: +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// Similar to PlanarTo24bHelper(), but in reverse order. +static WEBP_INLINE void RGB24PackedToPlanar_SSE41( + const uint8_t* const rgb, __m128i* const out /*out[6]*/) { + const __m128i A0 = _mm_loadu_si128((const __m128i*)(rgb + 0)); + const __m128i A1 = _mm_loadu_si128((const __m128i*)(rgb + 16)); + const __m128i A2 = _mm_loadu_si128((const __m128i*)(rgb + 32)); + const __m128i A3 = _mm_loadu_si128((const __m128i*)(rgb + 48)); + const __m128i A4 = _mm_loadu_si128((const __m128i*)(rgb + 64)); + const __m128i A5 = _mm_loadu_si128((const __m128i*)(rgb + 80)); + + // Compute RR. + { + const __m128i shuff0 = _mm_set_epi8( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 12, 9, 6, 3, 0); + const __m128i shuff1 = _mm_set_epi8( + -1, -1, -1, -1, -1, 14, 11, 8, 5, 2, -1, -1, -1, -1, -1, -1); + const __m128i shuff2 = _mm_set_epi8( + 13, 10, 7, 4, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + WEBP_SSE41_SHUFF(0) + } + // Compute GG. + { + const __m128i shuff0 = _mm_set_epi8( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 10, 7, 4, 1); + const __m128i shuff1 = _mm_set_epi8( + -1, -1, -1, -1, -1, 15, 12, 9, 6, 3, 0, -1, -1, -1, -1, -1); + const __m128i shuff2 = _mm_set_epi8( + 14, 11, 8, 5, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + WEBP_SSE41_SHUFF(2) + } + // Compute BB. + { + const __m128i shuff0 = _mm_set_epi8( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, 11, 8, 5, 2); + const __m128i shuff1 = _mm_set_epi8( + -1, -1, -1, -1, -1, -1, 13, 10, 7, 4, 1, -1, -1, -1, -1, -1); + const __m128i shuff2 = _mm_set_epi8( + 15, 12, 9, 6, 3, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + WEBP_SSE41_SHUFF(4) + } +} + +#undef WEBP_SSE41_SHUFF + +// Convert 8 packed ARGB to r[], g[], b[] +static WEBP_INLINE void RGB32PackedToPlanar_SSE41( + const uint32_t* const argb, __m128i* const rgb /*in[6]*/) { + const __m128i zero = _mm_setzero_si128(); + __m128i a0 = LOAD_16(argb + 0); + __m128i a1 = LOAD_16(argb + 4); + __m128i a2 = LOAD_16(argb + 8); + __m128i a3 = LOAD_16(argb + 12); + VP8L32bToPlanar_SSE41(&a0, &a1, &a2, &a3); + rgb[0] = _mm_unpacklo_epi8(a1, zero); + rgb[1] = _mm_unpackhi_epi8(a1, zero); + rgb[2] = _mm_unpacklo_epi8(a2, zero); + rgb[3] = _mm_unpackhi_epi8(a2, zero); + rgb[4] = _mm_unpacklo_epi8(a3, zero); + rgb[5] = _mm_unpackhi_epi8(a3, zero); +} + +// This macro computes (RG * MULT_RG + GB * MULT_GB + ROUNDER) >> DESCALE_FIX +// It's a macro and not a function because we need to use immediate values with +// srai_epi32, e.g. +#define TRANSFORM(RG_LO, RG_HI, GB_LO, GB_HI, MULT_RG, MULT_GB, \ + ROUNDER, DESCALE_FIX, OUT) do { \ + const __m128i V0_lo = _mm_madd_epi16(RG_LO, MULT_RG); \ + const __m128i V0_hi = _mm_madd_epi16(RG_HI, MULT_RG); \ + const __m128i V1_lo = _mm_madd_epi16(GB_LO, MULT_GB); \ + const __m128i V1_hi = _mm_madd_epi16(GB_HI, MULT_GB); \ + const __m128i V2_lo = _mm_add_epi32(V0_lo, V1_lo); \ + const __m128i V2_hi = _mm_add_epi32(V0_hi, V1_hi); \ + const __m128i V3_lo = _mm_add_epi32(V2_lo, ROUNDER); \ + const __m128i V3_hi = _mm_add_epi32(V2_hi, ROUNDER); \ + const __m128i V5_lo = _mm_srai_epi32(V3_lo, DESCALE_FIX); \ + const __m128i V5_hi = _mm_srai_epi32(V3_hi, DESCALE_FIX); \ + (OUT) = _mm_packs_epi32(V5_lo, V5_hi); \ +} while (0) + +#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A)) +static WEBP_INLINE void ConvertRGBToY_SSE41(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + __m128i* const Y) { + const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384); + const __m128i kGB_y = MK_CST_16(16384, 6420); + const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF); + + const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G); + const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G); + const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B); + const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y); +} + +static WEBP_INLINE void ConvertRGBToUV_SSE41(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + __m128i* const U, + __m128i* const V) { + const __m128i kRG_u = MK_CST_16(-9719, -19081); + const __m128i kGB_u = MK_CST_16(0, 28800); + const __m128i kRG_v = MK_CST_16(28800, 0); + const __m128i kGB_v = MK_CST_16(-24116, -4684); + const __m128i kHALF_UV = _mm_set1_epi32(((128 << YUV_FIX) + YUV_HALF) << 2); + + const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G); + const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G); + const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B); + const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_u, kGB_u, + kHALF_UV, YUV_FIX + 2, *U); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_v, kGB_v, + kHALF_UV, YUV_FIX + 2, *V); +} + +#undef MK_CST_16 +#undef TRANSFORM + +static void ConvertRGB24ToY_SSE41(const uint8_t* rgb, uint8_t* y, int width) { + const int max_width = width & ~31; + int i; + for (i = 0; i < max_width; rgb += 3 * 16 * 2) { + __m128i rgb_plane[6]; + int j; + + RGB24PackedToPlanar_SSE41(rgb, rgb_plane); + + for (j = 0; j < 2; ++j, i += 16) { + const __m128i zero = _mm_setzero_si128(); + __m128i r, g, b, Y0, Y1; + + // Convert to 16-bit Y. + r = _mm_unpacklo_epi8(rgb_plane[0 + j], zero); + g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero); + b = _mm_unpacklo_epi8(rgb_plane[4 + j], zero); + ConvertRGBToY_SSE41(&r, &g, &b, &Y0); + + // Convert to 16-bit Y. + r = _mm_unpackhi_epi8(rgb_plane[0 + j], zero); + g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero); + b = _mm_unpackhi_epi8(rgb_plane[4 + j], zero); + ConvertRGBToY_SSE41(&r, &g, &b, &Y1); + + // Cast to 8-bit and store. + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + } + for (; i < width; ++i, rgb += 3) { // left-over + y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF); + } +} + +static void ConvertBGR24ToY_SSE41(const uint8_t* bgr, uint8_t* y, int width) { + const int max_width = width & ~31; + int i; + for (i = 0; i < max_width; bgr += 3 * 16 * 2) { + __m128i bgr_plane[6]; + int j; + + RGB24PackedToPlanar_SSE41(bgr, bgr_plane); + + for (j = 0; j < 2; ++j, i += 16) { + const __m128i zero = _mm_setzero_si128(); + __m128i r, g, b, Y0, Y1; + + // Convert to 16-bit Y. + b = _mm_unpacklo_epi8(bgr_plane[0 + j], zero); + g = _mm_unpacklo_epi8(bgr_plane[2 + j], zero); + r = _mm_unpacklo_epi8(bgr_plane[4 + j], zero); + ConvertRGBToY_SSE41(&r, &g, &b, &Y0); + + // Convert to 16-bit Y. + b = _mm_unpackhi_epi8(bgr_plane[0 + j], zero); + g = _mm_unpackhi_epi8(bgr_plane[2 + j], zero); + r = _mm_unpackhi_epi8(bgr_plane[4 + j], zero); + ConvertRGBToY_SSE41(&r, &g, &b, &Y1); + + // Cast to 8-bit and store. + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + } + for (; i < width; ++i, bgr += 3) { // left-over + y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF); + } +} + +static void ConvertARGBToY_SSE41(const uint32_t* argb, uint8_t* y, int width) { + const int max_width = width & ~15; + int i; + for (i = 0; i < max_width; i += 16) { + __m128i Y0, Y1, rgb[6]; + RGB32PackedToPlanar_SSE41(&argb[i], rgb); + ConvertRGBToY_SSE41(&rgb[0], &rgb[2], &rgb[4], &Y0); + ConvertRGBToY_SSE41(&rgb[1], &rgb[3], &rgb[5], &Y1); + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + for (; i < width; ++i) { // left-over + const uint32_t p = argb[i]; + y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff, + YUV_HALF); + } +} + +// Horizontal add (doubled) of two 16b values, result is 16b. +// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ... +static void HorizontalAddPack_SSE41(const __m128i* const A, + const __m128i* const B, + __m128i* const out) { + const __m128i k2 = _mm_set1_epi16(2); + const __m128i C = _mm_madd_epi16(*A, k2); + const __m128i D = _mm_madd_epi16(*B, k2); + *out = _mm_packs_epi32(C, D); +} + +static void ConvertARGBToUV_SSE41(const uint32_t* argb, + uint8_t* u, uint8_t* v, + int src_width, int do_store) { + const int max_width = src_width & ~31; + int i; + for (i = 0; i < max_width; i += 32, u += 16, v += 16) { + __m128i rgb[6], U0, V0, U1, V1; + RGB32PackedToPlanar_SSE41(&argb[i], rgb); + HorizontalAddPack_SSE41(&rgb[0], &rgb[1], &rgb[0]); + HorizontalAddPack_SSE41(&rgb[2], &rgb[3], &rgb[2]); + HorizontalAddPack_SSE41(&rgb[4], &rgb[5], &rgb[4]); + ConvertRGBToUV_SSE41(&rgb[0], &rgb[2], &rgb[4], &U0, &V0); + + RGB32PackedToPlanar_SSE41(&argb[i + 16], rgb); + HorizontalAddPack_SSE41(&rgb[0], &rgb[1], &rgb[0]); + HorizontalAddPack_SSE41(&rgb[2], &rgb[3], &rgb[2]); + HorizontalAddPack_SSE41(&rgb[4], &rgb[5], &rgb[4]); + ConvertRGBToUV_SSE41(&rgb[0], &rgb[2], &rgb[4], &U1, &V1); + + U0 = _mm_packus_epi16(U0, U1); + V0 = _mm_packus_epi16(V0, V1); + if (!do_store) { + const __m128i prev_u = LOAD_16(u); + const __m128i prev_v = LOAD_16(v); + U0 = _mm_avg_epu8(U0, prev_u); + V0 = _mm_avg_epu8(V0, prev_v); + } + STORE_16(U0, u); + STORE_16(V0, v); + } + if (i < src_width) { // left-over + WebPConvertARGBToUV_C(argb + i, u, v, src_width - i, do_store); + } +} + +// Convert 16 packed ARGB 16b-values to r[], g[], b[] +static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE41( + const uint16_t* const rgbx, + __m128i* const r, __m128i* const g, __m128i* const b) { + const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x + const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x + const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ... + const __m128i in3 = LOAD_16(rgbx + 24); // r6 | ... + // aarrggbb as 16-bit. + const __m128i shuff0 = + _mm_set_epi8(-1, -1, -1, -1, 13, 12, 5, 4, 11, 10, 3, 2, 9, 8, 1, 0); + const __m128i shuff1 = + _mm_set_epi8(13, 12, 5, 4, -1, -1, -1, -1, 11, 10, 3, 2, 9, 8, 1, 0); + const __m128i A0 = _mm_shuffle_epi8(in0, shuff0); + const __m128i A1 = _mm_shuffle_epi8(in1, shuff1); + const __m128i A2 = _mm_shuffle_epi8(in2, shuff0); + const __m128i A3 = _mm_shuffle_epi8(in3, shuff1); + // R0R1G0G1 + // B0B1**** + // R2R3G2G3 + // B2B3**** + // (OR is used to free port 5 for the unpack) + const __m128i B0 = _mm_unpacklo_epi32(A0, A1); + const __m128i B1 = _mm_or_si128(A0, A1); + const __m128i B2 = _mm_unpacklo_epi32(A2, A3); + const __m128i B3 = _mm_or_si128(A2, A3); + // Gather the channels. + *r = _mm_unpacklo_epi64(B0, B2); + *g = _mm_unpackhi_epi64(B0, B2); + *b = _mm_unpackhi_epi64(B1, B3); +} + +static void ConvertRGBA32ToUV_SSE41(const uint16_t* rgb, + uint8_t* u, uint8_t* v, int width) { + const int max_width = width & ~15; + const uint16_t* const last_rgb = rgb + 4 * max_width; + while (rgb < last_rgb) { + __m128i r, g, b, U0, V0, U1, V1; + RGBA32PackedToPlanar_16b_SSE41(rgb + 0, &r, &g, &b); + ConvertRGBToUV_SSE41(&r, &g, &b, &U0, &V0); + RGBA32PackedToPlanar_16b_SSE41(rgb + 32, &r, &g, &b); + ConvertRGBToUV_SSE41(&r, &g, &b, &U1, &V1); + STORE_16(_mm_packus_epi16(U0, U1), u); + STORE_16(_mm_packus_epi16(V0, V1), v); + u += 16; + v += 16; + rgb += 2 * 32; + } + if (max_width < width) { // left-over + WebPConvertRGBA32ToUV_C(rgb, u, v, width - max_width); + } +} + +//------------------------------------------------------------------------------ + +extern void WebPInitConvertARGBToYUVSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE41(void) { + WebPConvertARGBToY = ConvertARGBToY_SSE41; + WebPConvertARGBToUV = ConvertARGBToUV_SSE41; + + WebPConvertRGB24ToY = ConvertRGB24ToY_SSE41; + WebPConvertBGR24ToY = ConvertBGR24ToY_SSE41; + + WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE41; +} + +//------------------------------------------------------------------------------ + +#else // !WEBP_USE_SSE41 + +WEBP_DSP_INIT_STUB(WebPInitSamplersSSE41) +WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE41) + +#endif // WEBP_USE_SSE41 diff --git a/libraries/webp/src/enc/alpha_enc.c b/libraries/webp/src/enc/alpha_enc.c new file mode 100644 index 00000000000..90842330c0f --- /dev/null +++ b/libraries/webp/src/enc/alpha_enc.c @@ -0,0 +1,450 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Alpha-plane compression. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include + +#include "src/enc/vp8i_enc.h" +#include "src/dsp/dsp.h" +#include "src/utils/filters_utils.h" +#include "src/utils/quant_levels_utils.h" +#include "src/utils/utils.h" +#include "include/webp/encode.h" +#include "include/webp/format_constants.h" + +// ----------------------------------------------------------------------------- +// Encodes the given alpha data via specified compression method 'method'. +// The pre-processing (quantization) is performed if 'quality' is less than 100. +// For such cases, the encoding is lossy. The valid range is [0, 100] for +// 'quality' and [0, 1] for 'method': +// 'method = 0' - No compression; +// 'method = 1' - Use lossless coder on the alpha plane only +// 'filter' values [0, 4] correspond to prediction modes none, horizontal, +// vertical & gradient filters. The prediction mode 4 will try all the +// prediction modes 0 to 3 and pick the best one. +// 'effort_level': specifies how much effort must be spent to try and reduce +// the compressed output size. In range 0 (quick) to 6 (slow). +// +// 'output' corresponds to the buffer containing compressed alpha data. +// This buffer is allocated by this method and caller should call +// WebPSafeFree(*output) when done. +// 'output_size' corresponds to size of this compressed alpha buffer. +// +// Returns 1 on successfully encoding the alpha and +// 0 if either: +// invalid quality or method, or +// memory allocation for the compressed data fails. + +#include "src/enc/vp8li_enc.h" + +static int EncodeLossless(const uint8_t* const data, int width, int height, + int effort_level, // in [0..6] range + int use_quality_100, VP8LBitWriter* const bw, + WebPAuxStats* const stats) { + int ok = 0; + WebPConfig config; + WebPPicture picture; + + if (!WebPPictureInit(&picture)) return 0; + picture.width = width; + picture.height = height; + picture.use_argb = 1; + picture.stats = stats; + if (!WebPPictureAlloc(&picture)) return 0; + + // Transfer the alpha values to the green channel. + WebPDispatchAlphaToGreen(data, width, picture.width, picture.height, + picture.argb, picture.argb_stride); + + if (!WebPConfigInit(&config)) return 0; + config.lossless = 1; + // Enable exact, or it would alter RGB values of transparent alpha, which is + // normally OK but not here since we are not encoding the input image but an + // internal encoding-related image containing necessary exact information in + // RGB channels. + config.exact = 1; + config.method = effort_level; // impact is very small + // Set a low default quality for encoding alpha. Ensure that Alpha quality at + // lower methods (3 and below) is less than the threshold for triggering + // costly 'BackwardReferencesTraceBackwards'. + // If the alpha quality is set to 100 and the method to 6, allow for a high + // lossless quality to trigger the cruncher. + config.quality = + (use_quality_100 && effort_level == 6) ? 100 : 8.f * effort_level; + assert(config.quality >= 0 && config.quality <= 100.f); + + ok = VP8LEncodeStream(&config, &picture, bw); + WebPPictureFree(&picture); + ok = ok && !bw->error_; + if (!ok) { + VP8LBitWriterWipeOut(bw); + return 0; + } + return 1; +} + +// ----------------------------------------------------------------------------- + +// Small struct to hold the result of a filter mode compression attempt. +typedef struct { + size_t score; + VP8BitWriter bw; + WebPAuxStats stats; +} FilterTrial; + +// This function always returns an initialized 'bw' object, even upon error. +static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, + int method, int filter, int reduce_levels, + int effort_level, // in [0..6] range + uint8_t* const tmp_alpha, + FilterTrial* result) { + int ok = 0; + const uint8_t* alpha_src; + WebPFilterFunc filter_func; + uint8_t header; + const size_t data_size = width * height; + const uint8_t* output = NULL; + size_t output_size = 0; + VP8LBitWriter tmp_bw; + + assert((uint64_t)data_size == (uint64_t)width * height); // as per spec + assert(filter >= 0 && filter < WEBP_FILTER_LAST); + assert(method >= ALPHA_NO_COMPRESSION); + assert(method <= ALPHA_LOSSLESS_COMPRESSION); + assert(sizeof(header) == ALPHA_HEADER_LEN); + + filter_func = WebPFilters[filter]; + if (filter_func != NULL) { + filter_func(data, width, height, width, tmp_alpha); + alpha_src = tmp_alpha; + } else { + alpha_src = data; + } + + if (method != ALPHA_NO_COMPRESSION) { + ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3); + ok = ok && EncodeLossless(alpha_src, width, height, effort_level, + !reduce_levels, &tmp_bw, &result->stats); + if (ok) { + output = VP8LBitWriterFinish(&tmp_bw); + if (tmp_bw.error_) { + VP8LBitWriterWipeOut(&tmp_bw); + memset(&result->bw, 0, sizeof(result->bw)); + return 0; + } + output_size = VP8LBitWriterNumBytes(&tmp_bw); + if (output_size > data_size) { + // compressed size is larger than source! Revert to uncompressed mode. + method = ALPHA_NO_COMPRESSION; + VP8LBitWriterWipeOut(&tmp_bw); + } + } else { + VP8LBitWriterWipeOut(&tmp_bw); + memset(&result->bw, 0, sizeof(result->bw)); + return 0; + } + } + + if (method == ALPHA_NO_COMPRESSION) { + output = alpha_src; + output_size = data_size; + ok = 1; + } + + // Emit final result. + header = method | (filter << 2); + if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; + + if (!VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size)) ok = 0; + ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN); + ok = ok && VP8BitWriterAppend(&result->bw, output, output_size); + + if (method != ALPHA_NO_COMPRESSION) { + VP8LBitWriterWipeOut(&tmp_bw); + } + ok = ok && !result->bw.error_; + result->score = VP8BitWriterSize(&result->bw); + return ok; +} + +// ----------------------------------------------------------------------------- + +static int GetNumColors(const uint8_t* data, int width, int height, + int stride) { + int j; + int colors = 0; + uint8_t color[256] = { 0 }; + + for (j = 0; j < height; ++j) { + int i; + const uint8_t* const p = data + j * stride; + for (i = 0; i < width; ++i) { + color[p[i]] = 1; + } + } + for (j = 0; j < 256; ++j) { + if (color[j] > 0) ++colors; + } + return colors; +} + +#define FILTER_TRY_NONE (1 << WEBP_FILTER_NONE) +#define FILTER_TRY_ALL ((1 << WEBP_FILTER_LAST) - 1) + +// Given the input 'filter' option, return an OR'd bit-set of filters to try. +static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height, + int filter, int effort_level) { + uint32_t bit_map = 0U; + if (filter == WEBP_FILTER_FAST) { + // Quick estimate of the best candidate. + int try_filter_none = (effort_level > 3); + const int kMinColorsForFilterNone = 16; + const int kMaxColorsForFilterNone = 192; + const int num_colors = GetNumColors(alpha, width, height, width); + // For low number of colors, NONE yields better compression. + filter = (num_colors <= kMinColorsForFilterNone) + ? WEBP_FILTER_NONE + : WebPEstimateBestFilter(alpha, width, height, width); + bit_map |= 1 << filter; + // For large number of colors, try FILTER_NONE in addition to the best + // filter as well. + if (try_filter_none || num_colors > kMaxColorsForFilterNone) { + bit_map |= FILTER_TRY_NONE; + } + } else if (filter == WEBP_FILTER_NONE) { + bit_map = FILTER_TRY_NONE; + } else { // WEBP_FILTER_BEST -> try all + bit_map = FILTER_TRY_ALL; + } + return bit_map; +} + +static void InitFilterTrial(FilterTrial* const score) { + score->score = (size_t)~0U; + VP8BitWriterInit(&score->bw, 0); +} + +static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height, + size_t data_size, int method, int filter, + int reduce_levels, int effort_level, + uint8_t** const output, + size_t* const output_size, + WebPAuxStats* const stats) { + int ok = 1; + FilterTrial best; + uint32_t try_map = + GetFilterMap(alpha, width, height, filter, effort_level); + InitFilterTrial(&best); + + if (try_map != FILTER_TRY_NONE) { + uint8_t* filtered_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size); + if (filtered_alpha == NULL) return 0; + + for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) { + if (try_map & 1) { + FilterTrial trial; + ok = EncodeAlphaInternal(alpha, width, height, method, filter, + reduce_levels, effort_level, filtered_alpha, + &trial); + if (ok && trial.score < best.score) { + VP8BitWriterWipeOut(&best.bw); + best = trial; + } else { + VP8BitWriterWipeOut(&trial.bw); + } + } + } + WebPSafeFree(filtered_alpha); + } else { + ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE, + reduce_levels, effort_level, NULL, &best); + } + if (ok) { +#if !defined(WEBP_DISABLE_STATS) + if (stats != NULL) { + stats->lossless_features = best.stats.lossless_features; + stats->histogram_bits = best.stats.histogram_bits; + stats->transform_bits = best.stats.transform_bits; + stats->cache_bits = best.stats.cache_bits; + stats->palette_size = best.stats.palette_size; + stats->lossless_size = best.stats.lossless_size; + stats->lossless_hdr_size = best.stats.lossless_hdr_size; + stats->lossless_data_size = best.stats.lossless_data_size; + } +#else + (void)stats; +#endif + *output_size = VP8BitWriterSize(&best.bw); + *output = VP8BitWriterBuf(&best.bw); + } else { + VP8BitWriterWipeOut(&best.bw); + } + return ok; +} + +static int EncodeAlpha(VP8Encoder* const enc, + int quality, int method, int filter, + int effort_level, + uint8_t** const output, size_t* const output_size) { + const WebPPicture* const pic = enc->pic_; + const int width = pic->width; + const int height = pic->height; + + uint8_t* quant_alpha = NULL; + const size_t data_size = width * height; + uint64_t sse = 0; + int ok = 1; + const int reduce_levels = (quality < 100); + + // quick correctness checks + assert((uint64_t)data_size == (uint64_t)width * height); // as per spec + assert(enc != NULL && pic != NULL && pic->a != NULL); + assert(output != NULL && output_size != NULL); + assert(width > 0 && height > 0); + assert(pic->a_stride >= width); + assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST); + + if (quality < 0 || quality > 100) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); + } + + if (method < ALPHA_NO_COMPRESSION || method > ALPHA_LOSSLESS_COMPRESSION) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); + } + + if (method == ALPHA_NO_COMPRESSION) { + // Don't filter, as filtering will make no impact on compressed size. + filter = WEBP_FILTER_NONE; + } + + quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size); + if (quant_alpha == NULL) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + + // Extract alpha data (width x height) from raw_data (stride x height). + WebPCopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height); + + if (reduce_levels) { // No Quantization required for 'quality = 100'. + // 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence + // mapped to moderate quality 70. Hence Quality:[0, 70] -> Levels:[2, 16] + // and Quality:]70, 100] -> Levels:]16, 256]. + const int alpha_levels = (quality <= 70) ? (2 + quality / 5) + : (16 + (quality - 70) * 8); + ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse); + } + + if (ok) { + VP8FiltersInit(); + ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method, + filter, reduce_levels, effort_level, output, + output_size, pic->stats); + if (!ok) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); // imprecise + } +#if !defined(WEBP_DISABLE_STATS) + if (pic->stats != NULL) { // need stats? + pic->stats->coded_size += (int)(*output_size); + enc->sse_[3] = sse; + } +#endif + } + + WebPSafeFree(quant_alpha); + return ok; +} + +//------------------------------------------------------------------------------ +// Main calls + +static int CompressAlphaJob(void* arg1, void* unused) { + VP8Encoder* const enc = (VP8Encoder*)arg1; + const WebPConfig* config = enc->config_; + uint8_t* alpha_data = NULL; + size_t alpha_size = 0; + const int effort_level = config->method; // maps to [0..6] + const WEBP_FILTER_TYPE filter = + (config->alpha_filtering == 0) ? WEBP_FILTER_NONE : + (config->alpha_filtering == 1) ? WEBP_FILTER_FAST : + WEBP_FILTER_BEST; + if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression, + filter, effort_level, &alpha_data, &alpha_size)) { + return 0; + } + if (alpha_size != (uint32_t)alpha_size) { // Soundness check. + WebPSafeFree(alpha_data); + return 0; + } + enc->alpha_data_size_ = (uint32_t)alpha_size; + enc->alpha_data_ = alpha_data; + (void)unused; + return 1; +} + +void VP8EncInitAlpha(VP8Encoder* const enc) { + WebPInitAlphaProcessing(); + enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_); + enc->alpha_data_ = NULL; + enc->alpha_data_size_ = 0; + if (enc->thread_level_ > 0) { + WebPWorker* const worker = &enc->alpha_worker_; + WebPGetWorkerInterface()->Init(worker); + worker->data1 = enc; + worker->data2 = NULL; + worker->hook = CompressAlphaJob; + } +} + +int VP8EncStartAlpha(VP8Encoder* const enc) { + if (enc->has_alpha_) { + if (enc->thread_level_ > 0) { + WebPWorker* const worker = &enc->alpha_worker_; + // Makes sure worker is good to go. + if (!WebPGetWorkerInterface()->Reset(worker)) { + return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + WebPGetWorkerInterface()->Launch(worker); + return 1; + } else { + return CompressAlphaJob(enc, NULL); // just do the job right away + } + } + return 1; +} + +int VP8EncFinishAlpha(VP8Encoder* const enc) { + if (enc->has_alpha_) { + if (enc->thread_level_ > 0) { + WebPWorker* const worker = &enc->alpha_worker_; + if (!WebPGetWorkerInterface()->Sync(worker)) return 0; // error + } + } + return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); +} + +int VP8EncDeleteAlpha(VP8Encoder* const enc) { + int ok = 1; + if (enc->thread_level_ > 0) { + WebPWorker* const worker = &enc->alpha_worker_; + // finish anything left in flight + ok = WebPGetWorkerInterface()->Sync(worker); + // still need to end the worker, even if !ok + WebPGetWorkerInterface()->End(worker); + } + WebPSafeFree(enc->alpha_data_); + enc->alpha_data_ = NULL; + enc->alpha_data_size_ = 0; + enc->has_alpha_ = 0; + return ok; +} diff --git a/libraries/webp/src/enc/analysis_enc.c b/libraries/webp/src/enc/analysis_enc.c new file mode 100644 index 00000000000..962eaa998f8 --- /dev/null +++ b/libraries/webp/src/enc/analysis_enc.c @@ -0,0 +1,483 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Macroblock analysis +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include + +#include "src/enc/vp8i_enc.h" +#include "src/enc/cost_enc.h" +#include "src/utils/utils.h" + +#define MAX_ITERS_K_MEANS 6 + +//------------------------------------------------------------------------------ +// Smooth the segment map by replacing isolated block by the majority of its +// neighbours. + +static void SmoothSegmentMap(VP8Encoder* const enc) { + int n, x, y; + const int w = enc->mb_w_; + const int h = enc->mb_h_; + const int majority_cnt_3_x_3_grid = 5; + uint8_t* const tmp = (uint8_t*)WebPSafeMalloc(w * h, sizeof(*tmp)); + assert((uint64_t)(w * h) == (uint64_t)w * h); // no overflow, as per spec + + if (tmp == NULL) return; + for (y = 1; y < h - 1; ++y) { + for (x = 1; x < w - 1; ++x) { + int cnt[NUM_MB_SEGMENTS] = { 0 }; + const VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; + int majority_seg = mb->segment_; + // Check the 8 neighbouring segment values. + cnt[mb[-w - 1].segment_]++; // top-left + cnt[mb[-w + 0].segment_]++; // top + cnt[mb[-w + 1].segment_]++; // top-right + cnt[mb[ - 1].segment_]++; // left + cnt[mb[ + 1].segment_]++; // right + cnt[mb[ w - 1].segment_]++; // bottom-left + cnt[mb[ w + 0].segment_]++; // bottom + cnt[mb[ w + 1].segment_]++; // bottom-right + for (n = 0; n < NUM_MB_SEGMENTS; ++n) { + if (cnt[n] >= majority_cnt_3_x_3_grid) { + majority_seg = n; + break; + } + } + tmp[x + y * w] = majority_seg; + } + } + for (y = 1; y < h - 1; ++y) { + for (x = 1; x < w - 1; ++x) { + VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; + mb->segment_ = tmp[x + y * w]; + } + } + WebPSafeFree(tmp); +} + +//------------------------------------------------------------------------------ +// set segment susceptibility alpha_ / beta_ + +static WEBP_INLINE int clip(int v, int m, int M) { + return (v < m) ? m : (v > M) ? M : v; +} + +static void SetSegmentAlphas(VP8Encoder* const enc, + const int centers[NUM_MB_SEGMENTS], + int mid) { + const int nb = enc->segment_hdr_.num_segments_; + int min = centers[0], max = centers[0]; + int n; + + if (nb > 1) { + for (n = 0; n < nb; ++n) { + if (min > centers[n]) min = centers[n]; + if (max < centers[n]) max = centers[n]; + } + } + if (max == min) max = min + 1; + assert(mid <= max && mid >= min); + for (n = 0; n < nb; ++n) { + const int alpha = 255 * (centers[n] - mid) / (max - min); + const int beta = 255 * (centers[n] - min) / (max - min); + enc->dqm_[n].alpha_ = clip(alpha, -127, 127); + enc->dqm_[n].beta_ = clip(beta, 0, 255); + } +} + +//------------------------------------------------------------------------------ +// Compute susceptibility based on DCT-coeff histograms: +// the higher, the "easier" the macroblock is to compress. + +#define MAX_ALPHA 255 // 8b of precision for susceptibilities. +#define ALPHA_SCALE (2 * MAX_ALPHA) // scaling factor for alpha. +#define DEFAULT_ALPHA (-1) +#define IS_BETTER_ALPHA(alpha, best_alpha) ((alpha) > (best_alpha)) + +static int FinalAlphaValue(int alpha) { + alpha = MAX_ALPHA - alpha; + return clip(alpha, 0, MAX_ALPHA); +} + +static int GetAlpha(const VP8Histogram* const histo) { + // 'alpha' will later be clipped to [0..MAX_ALPHA] range, clamping outer + // values which happen to be mostly noise. This leaves the maximum precision + // for handling the useful small values which contribute most. + const int max_value = histo->max_value; + const int last_non_zero = histo->last_non_zero; + const int alpha = + (max_value > 1) ? ALPHA_SCALE * last_non_zero / max_value : 0; + return alpha; +} + +static void InitHistogram(VP8Histogram* const histo) { + histo->max_value = 0; + histo->last_non_zero = 1; +} + +//------------------------------------------------------------------------------ +// Simplified k-Means, to assign Nb segments based on alpha-histogram + +static void AssignSegments(VP8Encoder* const enc, + const int alphas[MAX_ALPHA + 1]) { + // 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an + // explicit check is needed to avoid spurious warning about 'n + 1' exceeding + // array bounds of 'centers' with some compilers (noticed with gcc-4.9). + const int nb = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) ? + enc->segment_hdr_.num_segments_ : NUM_MB_SEGMENTS; + int centers[NUM_MB_SEGMENTS]; + int weighted_average = 0; + int map[MAX_ALPHA + 1]; + int a, n, k; + int min_a = 0, max_a = MAX_ALPHA, range_a; + // 'int' type is ok for histo, and won't overflow + int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS]; + + assert(nb >= 1); + assert(nb <= NUM_MB_SEGMENTS); + + // bracket the input + for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {} + min_a = n; + for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {} + max_a = n; + range_a = max_a - min_a; + + // Spread initial centers evenly + for (k = 0, n = 1; k < nb; ++k, n += 2) { + assert(n < 2 * nb); + centers[k] = min_a + (n * range_a) / (2 * nb); + } + + for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough + int total_weight; + int displaced; + // Reset stats + for (n = 0; n < nb; ++n) { + accum[n] = 0; + dist_accum[n] = 0; + } + // Assign nearest center for each 'a' + n = 0; // track the nearest center for current 'a' + for (a = min_a; a <= max_a; ++a) { + if (alphas[a]) { + while (n + 1 < nb && abs(a - centers[n + 1]) < abs(a - centers[n])) { + n++; + } + map[a] = n; + // accumulate contribution into best centroid + dist_accum[n] += a * alphas[a]; + accum[n] += alphas[a]; + } + } + // All point are classified. Move the centroids to the + // center of their respective cloud. + displaced = 0; + weighted_average = 0; + total_weight = 0; + for (n = 0; n < nb; ++n) { + if (accum[n]) { + const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n]; + displaced += abs(centers[n] - new_center); + centers[n] = new_center; + weighted_average += new_center * accum[n]; + total_weight += accum[n]; + } + } + weighted_average = (weighted_average + total_weight / 2) / total_weight; + if (displaced < 5) break; // no need to keep on looping... + } + + // Map each original value to the closest centroid + for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { + VP8MBInfo* const mb = &enc->mb_info_[n]; + const int alpha = mb->alpha_; + mb->segment_ = map[alpha]; + mb->alpha_ = centers[map[alpha]]; // for the record. + } + + if (nb > 1) { + const int smooth = (enc->config_->preprocessing & 1); + if (smooth) SmoothSegmentMap(enc); + } + + SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas. +} + +//------------------------------------------------------------------------------ +// Macroblock analysis: collect histogram for each mode, deduce the maximal +// susceptibility and set best modes for this macroblock. +// Segment assignment is done later. + +// Number of modes to inspect for alpha_ evaluation. We don't need to test all +// the possible modes during the analysis phase: we risk falling into a local +// optimum, or be subject to boundary effect +#define MAX_INTRA16_MODE 2 +#define MAX_INTRA4_MODE 2 +#define MAX_UV_MODE 2 + +static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) { + const int max_mode = MAX_INTRA16_MODE; + int mode; + int best_alpha = DEFAULT_ALPHA; + int best_mode = 0; + + VP8MakeLuma16Preds(it); + for (mode = 0; mode < max_mode; ++mode) { + VP8Histogram histo; + int alpha; + + InitHistogram(&histo); + VP8CollectHistogram(it->yuv_in_ + Y_OFF_ENC, + it->yuv_p_ + VP8I16ModeOffsets[mode], + 0, 16, &histo); + alpha = GetAlpha(&histo); + if (IS_BETTER_ALPHA(alpha, best_alpha)) { + best_alpha = alpha; + best_mode = mode; + } + } + VP8SetIntra16Mode(it, best_mode); + return best_alpha; +} + +static int FastMBAnalyze(VP8EncIterator* const it) { + // Empirical cut-off value, should be around 16 (~=block size). We use the + // [8-17] range and favor intra4 at high quality, intra16 for low quality. + const int q = (int)it->enc_->config_->quality; + const uint32_t kThreshold = 8 + (17 - 8) * q / 100; + int k; + uint32_t dc[16], m, m2; + for (k = 0; k < 16; k += 4) { + VP8Mean16x4(it->yuv_in_ + Y_OFF_ENC + k * BPS, &dc[k]); + } + for (m = 0, m2 = 0, k = 0; k < 16; ++k) { + m += dc[k]; + m2 += dc[k] * dc[k]; + } + if (kThreshold * m2 < m * m) { + VP8SetIntra16Mode(it, 0); // DC16 + } else { + const uint8_t modes[16] = { 0 }; // DC4 + VP8SetIntra4Mode(it, modes); + } + return 0; +} + +static int MBAnalyzeBestUVMode(VP8EncIterator* const it) { + int best_alpha = DEFAULT_ALPHA; + int smallest_alpha = 0; + int best_mode = 0; + const int max_mode = MAX_UV_MODE; + int mode; + + VP8MakeChroma8Preds(it); + for (mode = 0; mode < max_mode; ++mode) { + VP8Histogram histo; + int alpha; + InitHistogram(&histo); + VP8CollectHistogram(it->yuv_in_ + U_OFF_ENC, + it->yuv_p_ + VP8UVModeOffsets[mode], + 16, 16 + 4 + 4, &histo); + alpha = GetAlpha(&histo); + if (IS_BETTER_ALPHA(alpha, best_alpha)) { + best_alpha = alpha; + } + // The best prediction mode tends to be the one with the smallest alpha. + if (mode == 0 || alpha < smallest_alpha) { + smallest_alpha = alpha; + best_mode = mode; + } + } + VP8SetIntraUVMode(it, best_mode); + return best_alpha; +} + +static void MBAnalyze(VP8EncIterator* const it, + int alphas[MAX_ALPHA + 1], + int* const alpha, int* const uv_alpha) { + const VP8Encoder* const enc = it->enc_; + int best_alpha, best_uv_alpha; + + VP8SetIntra16Mode(it, 0); // default: Intra16, DC_PRED + VP8SetSkip(it, 0); // not skipped + VP8SetSegment(it, 0); // default segment, spec-wise. + + if (enc->method_ <= 1) { + best_alpha = FastMBAnalyze(it); + } else { + best_alpha = MBAnalyzeBestIntra16Mode(it); + } + best_uv_alpha = MBAnalyzeBestUVMode(it); + + // Final susceptibility mix + best_alpha = (3 * best_alpha + best_uv_alpha + 2) >> 2; + best_alpha = FinalAlphaValue(best_alpha); + alphas[best_alpha]++; + it->mb_->alpha_ = best_alpha; // for later remapping. + + // Accumulate for later complexity analysis. + *alpha += best_alpha; // mixed susceptibility (not just luma) + *uv_alpha += best_uv_alpha; +} + +static void DefaultMBInfo(VP8MBInfo* const mb) { + mb->type_ = 1; // I16x16 + mb->uv_mode_ = 0; + mb->skip_ = 0; // not skipped + mb->segment_ = 0; // default segment + mb->alpha_ = 0; +} + +//------------------------------------------------------------------------------ +// Main analysis loop: +// Collect all susceptibilities for each macroblock and record their +// distribution in alphas[]. Segments is assigned a-posteriori, based on +// this histogram. +// We also pick an intra16 prediction mode, which shouldn't be considered +// final except for fast-encode settings. We can also pick some intra4 modes +// and decide intra4/intra16, but that's usually almost always a bad choice at +// this stage. + +static void ResetAllMBInfo(VP8Encoder* const enc) { + int n; + for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { + DefaultMBInfo(&enc->mb_info_[n]); + } + // Default susceptibilities. + enc->dqm_[0].alpha_ = 0; + enc->dqm_[0].beta_ = 0; + // Note: we can't compute this alpha_ / uv_alpha_ -> set to default value. + enc->alpha_ = 0; + enc->uv_alpha_ = 0; + WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); +} + +// struct used to collect job result +typedef struct { + WebPWorker worker; + int alphas[MAX_ALPHA + 1]; + int alpha, uv_alpha; + VP8EncIterator it; + int delta_progress; +} SegmentJob; + +// main work call +static int DoSegmentsJob(void* arg1, void* arg2) { + SegmentJob* const job = (SegmentJob*)arg1; + VP8EncIterator* const it = (VP8EncIterator*)arg2; + int ok = 1; + if (!VP8IteratorIsDone(it)) { + uint8_t tmp[32 + WEBP_ALIGN_CST]; + uint8_t* const scratch = (uint8_t*)WEBP_ALIGN(tmp); + do { + // Let's pretend we have perfect lossless reconstruction. + VP8IteratorImport(it, scratch); + MBAnalyze(it, job->alphas, &job->alpha, &job->uv_alpha); + ok = VP8IteratorProgress(it, job->delta_progress); + } while (ok && VP8IteratorNext(it)); + } + return ok; +} + +#ifdef WEBP_USE_THREAD +static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) { + int i; + for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i]; + dst->alpha += src->alpha; + dst->uv_alpha += src->uv_alpha; +} +#endif + +// initialize the job struct with some tasks to perform +static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job, + int start_row, int end_row) { + WebPGetWorkerInterface()->Init(&job->worker); + job->worker.data1 = job; + job->worker.data2 = &job->it; + job->worker.hook = DoSegmentsJob; + VP8IteratorInit(enc, &job->it); + VP8IteratorSetRow(&job->it, start_row); + VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_); + memset(job->alphas, 0, sizeof(job->alphas)); + job->alpha = 0; + job->uv_alpha = 0; + // only one of both jobs can record the progress, since we don't + // expect the user's hook to be multi-thread safe + job->delta_progress = (start_row == 0) ? 20 : 0; +} + +// main entry point +int VP8EncAnalyze(VP8Encoder* const enc) { + int ok = 1; + const int do_segments = + enc->config_->emulate_jpeg_size || // We need the complexity evaluation. + (enc->segment_hdr_.num_segments_ > 1) || + (enc->method_ <= 1); // for method 0 - 1, we need preds_[] to be filled. + if (do_segments) { + const int last_row = enc->mb_h_; + const int total_mb = last_row * enc->mb_w_; +#ifdef WEBP_USE_THREAD + // We give a little more than a half work to the main thread. + const int split_row = (9 * last_row + 15) >> 4; + const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it + const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow); +#else + const int do_mt = 0; +#endif + const WebPWorkerInterface* const worker_interface = + WebPGetWorkerInterface(); + SegmentJob main_job; + if (do_mt) { +#ifdef WEBP_USE_THREAD + SegmentJob side_job; + // Note the use of '&' instead of '&&' because we must call the functions + // no matter what. + InitSegmentJob(enc, &main_job, 0, split_row); + InitSegmentJob(enc, &side_job, split_row, last_row); + // we don't need to call Reset() on main_job.worker, since we're calling + // WebPWorkerExecute() on it + ok &= worker_interface->Reset(&side_job.worker); + // launch the two jobs in parallel + if (ok) { + worker_interface->Launch(&side_job.worker); + worker_interface->Execute(&main_job.worker); + ok &= worker_interface->Sync(&side_job.worker); + ok &= worker_interface->Sync(&main_job.worker); + } + worker_interface->End(&side_job.worker); + if (ok) MergeJobs(&side_job, &main_job); // merge results together +#endif // WEBP_USE_THREAD + } else { + // Even for single-thread case, we use the generic Worker tools. + InitSegmentJob(enc, &main_job, 0, last_row); + worker_interface->Execute(&main_job.worker); + ok &= worker_interface->Sync(&main_job.worker); + } + worker_interface->End(&main_job.worker); + if (ok) { + enc->alpha_ = main_job.alpha / total_mb; + enc->uv_alpha_ = main_job.uv_alpha / total_mb; + AssignSegments(enc, main_job.alphas); + } + } else { // Use only one default segment. + ResetAllMBInfo(enc); + } + if (!ok) { + return WebPEncodingSetError(enc->pic_, + VP8_ENC_ERROR_OUT_OF_MEMORY); // imprecise + } + return ok; +} + diff --git a/libraries/webp/src/enc/backward_references_cost_enc.c b/libraries/webp/src/enc/backward_references_cost_enc.c new file mode 100644 index 00000000000..6968ef3c9f3 --- /dev/null +++ b/libraries/webp/src/enc/backward_references_cost_enc.c @@ -0,0 +1,795 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Improves a given set of backward references by analyzing its bit cost. +// The algorithm is similar to the Zopfli compression algorithm but tailored to +// images. +// +// Author: Vincent Rabaud (vrabaud@google.com) +// + +#include +#include + +#include "src/dsp/lossless_common.h" +#include "src/enc/backward_references_enc.h" +#include "src/enc/histogram_enc.h" +#include "src/utils/color_cache_utils.h" +#include "src/utils/utils.h" + +#define VALUES_IN_BYTE 256 + +extern void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs); +extern int VP8LDistanceToPlaneCode(int xsize, int dist); +extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, + const PixOrCopy v); + +typedef struct { + float alpha_[VALUES_IN_BYTE]; + float red_[VALUES_IN_BYTE]; + float blue_[VALUES_IN_BYTE]; + float distance_[NUM_DISTANCE_CODES]; + float* literal_; +} CostModel; + +static void ConvertPopulationCountTableToBitEstimates( + int num_symbols, const uint32_t population_counts[], float output[]) { + uint32_t sum = 0; + int nonzeros = 0; + int i; + for (i = 0; i < num_symbols; ++i) { + sum += population_counts[i]; + if (population_counts[i] > 0) { + ++nonzeros; + } + } + if (nonzeros <= 1) { + memset(output, 0, num_symbols * sizeof(*output)); + } else { + const float logsum = VP8LFastLog2(sum); + for (i = 0; i < num_symbols; ++i) { + output[i] = logsum - VP8LFastLog2(population_counts[i]); + } + } +} + +static int CostModelBuild(CostModel* const m, int xsize, int cache_bits, + const VP8LBackwardRefs* const refs) { + int ok = 0; + VP8LRefsCursor c = VP8LRefsCursorInit(refs); + VP8LHistogram* const histo = VP8LAllocateHistogram(cache_bits); + if (histo == NULL) goto Error; + + // The following code is similar to VP8LHistogramCreate but converts the + // distance to plane code. + VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 1); + while (VP8LRefsCursorOk(&c)) { + VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode, + xsize); + VP8LRefsCursorNext(&c); + } + + ConvertPopulationCountTableToBitEstimates( + VP8LHistogramNumCodes(histo->palette_code_bits_), histo->literal_, + m->literal_); + ConvertPopulationCountTableToBitEstimates( + VALUES_IN_BYTE, histo->red_, m->red_); + ConvertPopulationCountTableToBitEstimates( + VALUES_IN_BYTE, histo->blue_, m->blue_); + ConvertPopulationCountTableToBitEstimates( + VALUES_IN_BYTE, histo->alpha_, m->alpha_); + ConvertPopulationCountTableToBitEstimates( + NUM_DISTANCE_CODES, histo->distance_, m->distance_); + ok = 1; + + Error: + VP8LFreeHistogram(histo); + return ok; +} + +static WEBP_INLINE float GetLiteralCost(const CostModel* const m, uint32_t v) { + return m->alpha_[v >> 24] + + m->red_[(v >> 16) & 0xff] + + m->literal_[(v >> 8) & 0xff] + + m->blue_[v & 0xff]; +} + +static WEBP_INLINE float GetCacheCost(const CostModel* const m, uint32_t idx) { + const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx; + return m->literal_[literal_idx]; +} + +static WEBP_INLINE float GetLengthCost(const CostModel* const m, + uint32_t length) { + int code, extra_bits; + VP8LPrefixEncodeBits(length, &code, &extra_bits); + return m->literal_[VALUES_IN_BYTE + code] + extra_bits; +} + +static WEBP_INLINE float GetDistanceCost(const CostModel* const m, + uint32_t distance) { + int code, extra_bits; + VP8LPrefixEncodeBits(distance, &code, &extra_bits); + return m->distance_[code] + extra_bits; +} + +static WEBP_INLINE void AddSingleLiteralWithCostModel( + const uint32_t* const argb, VP8LColorCache* const hashers, + const CostModel* const cost_model, int idx, int use_color_cache, + float prev_cost, float* const cost, uint16_t* const dist_array) { + float cost_val = prev_cost; + const uint32_t color = argb[idx]; + const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1; + if (ix >= 0) { + // use_color_cache is true and hashers contains color + const float mul0 = 0.68f; + cost_val += GetCacheCost(cost_model, ix) * mul0; + } else { + const float mul1 = 0.82f; + if (use_color_cache) VP8LColorCacheInsert(hashers, color); + cost_val += GetLiteralCost(cost_model, color) * mul1; + } + if (cost[idx] > cost_val) { + cost[idx] = cost_val; + dist_array[idx] = 1; // only one is inserted. + } +} + +// ----------------------------------------------------------------------------- +// CostManager and interval handling + +// Empirical value to avoid high memory consumption but good for performance. +#define COST_CACHE_INTERVAL_SIZE_MAX 500 + +// To perform backward reference every pixel at index index_ is considered and +// the cost for the MAX_LENGTH following pixels computed. Those following pixels +// at index index_ + k (k from 0 to MAX_LENGTH) have a cost of: +// cost_ = distance cost at index + GetLengthCost(cost_model, k) +// and the minimum value is kept. GetLengthCost(cost_model, k) is cached in an +// array of size MAX_LENGTH. +// Instead of performing MAX_LENGTH comparisons per pixel, we keep track of the +// minimal values using intervals of constant cost. +// An interval is defined by the index_ of the pixel that generated it and +// is only useful in a range of indices from start_ to end_ (exclusive), i.e. +// it contains the minimum value for pixels between start_ and end_. +// Intervals are stored in a linked list and ordered by start_. When a new +// interval has a better value, old intervals are split or removed. There are +// therefore no overlapping intervals. +typedef struct CostInterval CostInterval; +struct CostInterval { + float cost_; + int start_; + int end_; + int index_; + CostInterval* previous_; + CostInterval* next_; +}; + +// The GetLengthCost(cost_model, k) are cached in a CostCacheInterval. +typedef struct { + float cost_; + int start_; + int end_; // Exclusive. +} CostCacheInterval; + +// This structure is in charge of managing intervals and costs. +// It caches the different CostCacheInterval, caches the different +// GetLengthCost(cost_model, k) in cost_cache_ and the CostInterval's (whose +// count_ is limited by COST_CACHE_INTERVAL_SIZE_MAX). +#define COST_MANAGER_MAX_FREE_LIST 10 +typedef struct { + CostInterval* head_; + int count_; // The number of stored intervals. + CostCacheInterval* cache_intervals_; + size_t cache_intervals_size_; + float cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k). + float* costs_; + uint16_t* dist_array_; + // Most of the time, we only need few intervals -> use a free-list, to avoid + // fragmentation with small allocs in most common cases. + CostInterval intervals_[COST_MANAGER_MAX_FREE_LIST]; + CostInterval* free_intervals_; + // These are regularly malloc'd remains. This list can't grow larger than than + // size COST_CACHE_INTERVAL_SIZE_MAX - COST_MANAGER_MAX_FREE_LIST, note. + CostInterval* recycled_intervals_; +} CostManager; + +static void CostIntervalAddToFreeList(CostManager* const manager, + CostInterval* const interval) { + interval->next_ = manager->free_intervals_; + manager->free_intervals_ = interval; +} + +static int CostIntervalIsInFreeList(const CostManager* const manager, + const CostInterval* const interval) { + return (interval >= &manager->intervals_[0] && + interval <= &manager->intervals_[COST_MANAGER_MAX_FREE_LIST - 1]); +} + +static void CostManagerInitFreeList(CostManager* const manager) { + int i; + manager->free_intervals_ = NULL; + for (i = 0; i < COST_MANAGER_MAX_FREE_LIST; ++i) { + CostIntervalAddToFreeList(manager, &manager->intervals_[i]); + } +} + +static void DeleteIntervalList(CostManager* const manager, + const CostInterval* interval) { + while (interval != NULL) { + const CostInterval* const next = interval->next_; + if (!CostIntervalIsInFreeList(manager, interval)) { + WebPSafeFree((void*)interval); + } // else: do nothing + interval = next; + } +} + +static void CostManagerClear(CostManager* const manager) { + if (manager == NULL) return; + + WebPSafeFree(manager->costs_); + WebPSafeFree(manager->cache_intervals_); + + // Clear the interval lists. + DeleteIntervalList(manager, manager->head_); + manager->head_ = NULL; + DeleteIntervalList(manager, manager->recycled_intervals_); + manager->recycled_intervals_ = NULL; + + // Reset pointers, count_ and cache_intervals_size_. + memset(manager, 0, sizeof(*manager)); + CostManagerInitFreeList(manager); +} + +static int CostManagerInit(CostManager* const manager, + uint16_t* const dist_array, int pix_count, + const CostModel* const cost_model) { + int i; + const int cost_cache_size = (pix_count > MAX_LENGTH) ? MAX_LENGTH : pix_count; + + manager->costs_ = NULL; + manager->cache_intervals_ = NULL; + manager->head_ = NULL; + manager->recycled_intervals_ = NULL; + manager->count_ = 0; + manager->dist_array_ = dist_array; + CostManagerInitFreeList(manager); + + // Fill in the cost_cache_. + // Has to be done in two passes due to a GCC bug on i686 + // related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 + for (i = 0; i < cost_cache_size; ++i) { + manager->cost_cache_[i] = GetLengthCost(cost_model, i); + } + manager->cache_intervals_size_ = 1; + for (i = 1; i < cost_cache_size; ++i) { + // Get the number of bound intervals. + if (manager->cost_cache_[i] != manager->cost_cache_[i - 1]) { + ++manager->cache_intervals_size_; + } + } + + // With the current cost model, we usually have below 20 intervals. + // The worst case scenario with a cost model would be if every length has a + // different cost, hence MAX_LENGTH but that is impossible with the current + // implementation that spirals around a pixel. + assert(manager->cache_intervals_size_ <= MAX_LENGTH); + manager->cache_intervals_ = (CostCacheInterval*)WebPSafeMalloc( + manager->cache_intervals_size_, sizeof(*manager->cache_intervals_)); + if (manager->cache_intervals_ == NULL) { + CostManagerClear(manager); + return 0; + } + + // Fill in the cache_intervals_. + { + CostCacheInterval* cur = manager->cache_intervals_; + + // Consecutive values in cost_cache_ are compared and if a big enough + // difference is found, a new interval is created and bounded. + cur->start_ = 0; + cur->end_ = 1; + cur->cost_ = manager->cost_cache_[0]; + for (i = 1; i < cost_cache_size; ++i) { + const float cost_val = manager->cost_cache_[i]; + if (cost_val != cur->cost_) { + ++cur; + // Initialize an interval. + cur->start_ = i; + cur->cost_ = cost_val; + } + cur->end_ = i + 1; + } + assert((size_t)(cur - manager->cache_intervals_) + 1 == + manager->cache_intervals_size_); + } + + manager->costs_ = (float*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_)); + if (manager->costs_ == NULL) { + CostManagerClear(manager); + return 0; + } + // Set the initial costs_ high for every pixel as we will keep the minimum. + for (i = 0; i < pix_count; ++i) manager->costs_[i] = FLT_MAX; + + return 1; +} + +// Given the cost and the position that define an interval, update the cost at +// pixel 'i' if it is smaller than the previously computed value. +static WEBP_INLINE void UpdateCost(CostManager* const manager, int i, + int position, float cost) { + const int k = i - position; + assert(k >= 0 && k < MAX_LENGTH); + + if (manager->costs_[i] > cost) { + manager->costs_[i] = cost; + manager->dist_array_[i] = k + 1; + } +} + +// Given the cost and the position that define an interval, update the cost for +// all the pixels between 'start' and 'end' excluded. +static WEBP_INLINE void UpdateCostPerInterval(CostManager* const manager, + int start, int end, int position, + float cost) { + int i; + for (i = start; i < end; ++i) UpdateCost(manager, i, position, cost); +} + +// Given two intervals, make 'prev' be the previous one of 'next' in 'manager'. +static WEBP_INLINE void ConnectIntervals(CostManager* const manager, + CostInterval* const prev, + CostInterval* const next) { + if (prev != NULL) { + prev->next_ = next; + } else { + manager->head_ = next; + } + + if (next != NULL) next->previous_ = prev; +} + +// Pop an interval in the manager. +static WEBP_INLINE void PopInterval(CostManager* const manager, + CostInterval* const interval) { + if (interval == NULL) return; + + ConnectIntervals(manager, interval->previous_, interval->next_); + if (CostIntervalIsInFreeList(manager, interval)) { + CostIntervalAddToFreeList(manager, interval); + } else { // recycle regularly malloc'd intervals too + interval->next_ = manager->recycled_intervals_; + manager->recycled_intervals_ = interval; + } + --manager->count_; + assert(manager->count_ >= 0); +} + +// Update the cost at index i by going over all the stored intervals that +// overlap with i. +// If 'do_clean_intervals' is set to something different than 0, intervals that +// end before 'i' will be popped. +static WEBP_INLINE void UpdateCostAtIndex(CostManager* const manager, int i, + int do_clean_intervals) { + CostInterval* current = manager->head_; + + while (current != NULL && current->start_ <= i) { + CostInterval* const next = current->next_; + if (current->end_ <= i) { + if (do_clean_intervals) { + // We have an outdated interval, remove it. + PopInterval(manager, current); + } + } else { + UpdateCost(manager, i, current->index_, current->cost_); + } + current = next; + } +} + +// Given a current orphan interval and its previous interval, before +// it was orphaned (which can be NULL), set it at the right place in the list +// of intervals using the start_ ordering and the previous interval as a hint. +static WEBP_INLINE void PositionOrphanInterval(CostManager* const manager, + CostInterval* const current, + CostInterval* previous) { + assert(current != NULL); + + if (previous == NULL) previous = manager->head_; + while (previous != NULL && current->start_ < previous->start_) { + previous = previous->previous_; + } + while (previous != NULL && previous->next_ != NULL && + previous->next_->start_ < current->start_) { + previous = previous->next_; + } + + if (previous != NULL) { + ConnectIntervals(manager, current, previous->next_); + } else { + ConnectIntervals(manager, current, manager->head_); + } + ConnectIntervals(manager, previous, current); +} + +// Insert an interval in the list contained in the manager by starting at +// interval_in as a hint. The intervals are sorted by start_ value. +static WEBP_INLINE void InsertInterval(CostManager* const manager, + CostInterval* const interval_in, + float cost, int position, int start, + int end) { + CostInterval* interval_new; + + if (start >= end) return; + if (manager->count_ >= COST_CACHE_INTERVAL_SIZE_MAX) { + // Serialize the interval if we cannot store it. + UpdateCostPerInterval(manager, start, end, position, cost); + return; + } + if (manager->free_intervals_ != NULL) { + interval_new = manager->free_intervals_; + manager->free_intervals_ = interval_new->next_; + } else if (manager->recycled_intervals_ != NULL) { + interval_new = manager->recycled_intervals_; + manager->recycled_intervals_ = interval_new->next_; + } else { // malloc for good + interval_new = (CostInterval*)WebPSafeMalloc(1, sizeof(*interval_new)); + if (interval_new == NULL) { + // Write down the interval if we cannot create it. + UpdateCostPerInterval(manager, start, end, position, cost); + return; + } + } + + interval_new->cost_ = cost; + interval_new->index_ = position; + interval_new->start_ = start; + interval_new->end_ = end; + PositionOrphanInterval(manager, interval_new, interval_in); + + ++manager->count_; +} + +// Given a new cost interval defined by its start at position, its length value +// and distance_cost, add its contributions to the previous intervals and costs. +// If handling the interval or one of its subintervals becomes to heavy, its +// contribution is added to the costs right away. +static WEBP_INLINE void PushInterval(CostManager* const manager, + float distance_cost, int position, + int len) { + size_t i; + CostInterval* interval = manager->head_; + CostInterval* interval_next; + const CostCacheInterval* const cost_cache_intervals = + manager->cache_intervals_; + // If the interval is small enough, no need to deal with the heavy + // interval logic, just serialize it right away. This constant is empirical. + const int kSkipDistance = 10; + + if (len < kSkipDistance) { + int j; + for (j = position; j < position + len; ++j) { + const int k = j - position; + float cost_tmp; + assert(k >= 0 && k < MAX_LENGTH); + cost_tmp = distance_cost + manager->cost_cache_[k]; + + if (manager->costs_[j] > cost_tmp) { + manager->costs_[j] = cost_tmp; + manager->dist_array_[j] = k + 1; + } + } + return; + } + + for (i = 0; i < manager->cache_intervals_size_ && + cost_cache_intervals[i].start_ < len; + ++i) { + // Define the intersection of the ith interval with the new one. + int start = position + cost_cache_intervals[i].start_; + const int end = position + (cost_cache_intervals[i].end_ > len + ? len + : cost_cache_intervals[i].end_); + const float cost = distance_cost + cost_cache_intervals[i].cost_; + + for (; interval != NULL && interval->start_ < end; + interval = interval_next) { + interval_next = interval->next_; + + // Make sure we have some overlap + if (start >= interval->end_) continue; + + if (cost >= interval->cost_) { + // When intervals are represented, the lower, the better. + // [**********************************************************[ + // start end + // [----------------------------------[ + // interval->start_ interval->end_ + // If we are worse than what we already have, add whatever we have so + // far up to interval. + const int start_new = interval->end_; + InsertInterval(manager, interval, cost, position, start, + interval->start_); + start = start_new; + if (start >= end) break; + continue; + } + + if (start <= interval->start_) { + if (interval->end_ <= end) { + // [----------------------------------[ + // interval->start_ interval->end_ + // [**************************************************************[ + // start end + // We can safely remove the old interval as it is fully included. + PopInterval(manager, interval); + } else { + // [------------------------------------[ + // interval->start_ interval->end_ + // [*****************************[ + // start end + interval->start_ = end; + break; + } + } else { + if (end < interval->end_) { + // [--------------------------------------------------------------[ + // interval->start_ interval->end_ + // [*****************************[ + // start end + // We have to split the old interval as it fully contains the new one. + const int end_original = interval->end_; + interval->end_ = start; + InsertInterval(manager, interval, interval->cost_, interval->index_, + end, end_original); + interval = interval->next_; + break; + } else { + // [------------------------------------[ + // interval->start_ interval->end_ + // [*****************************[ + // start end + interval->end_ = start; + } + } + } + // Insert the remaining interval from start to end. + InsertInterval(manager, interval, cost, position, start, end); + } +} + +static int BackwardReferencesHashChainDistanceOnly( + int xsize, int ysize, const uint32_t* const argb, int cache_bits, + const VP8LHashChain* const hash_chain, const VP8LBackwardRefs* const refs, + uint16_t* const dist_array) { + int i; + int ok = 0; + int cc_init = 0; + const int pix_count = xsize * ysize; + const int use_color_cache = (cache_bits > 0); + const size_t literal_array_size = + sizeof(float) * (VP8LHistogramNumCodes(cache_bits)); + const size_t cost_model_size = sizeof(CostModel) + literal_array_size; + CostModel* const cost_model = + (CostModel*)WebPSafeCalloc(1ULL, cost_model_size); + VP8LColorCache hashers; + CostManager* cost_manager = + (CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager)); + int offset_prev = -1, len_prev = -1; + float offset_cost = -1.f; + int first_offset_is_constant = -1; // initialized with 'impossible' value + int reach = 0; + + if (cost_model == NULL || cost_manager == NULL) goto Error; + + cost_model->literal_ = (float*)(cost_model + 1); + if (use_color_cache) { + cc_init = VP8LColorCacheInit(&hashers, cache_bits); + if (!cc_init) goto Error; + } + + if (!CostModelBuild(cost_model, xsize, cache_bits, refs)) { + goto Error; + } + + if (!CostManagerInit(cost_manager, dist_array, pix_count, cost_model)) { + goto Error; + } + + // We loop one pixel at a time, but store all currently best points to + // non-processed locations from this point. + dist_array[0] = 0; + // Add first pixel as literal. + AddSingleLiteralWithCostModel(argb, &hashers, cost_model, 0, use_color_cache, + 0.f, cost_manager->costs_, dist_array); + + for (i = 1; i < pix_count; ++i) { + const float prev_cost = cost_manager->costs_[i - 1]; + int offset, len; + VP8LHashChainFindCopy(hash_chain, i, &offset, &len); + + // Try adding the pixel as a literal. + AddSingleLiteralWithCostModel(argb, &hashers, cost_model, i, + use_color_cache, prev_cost, + cost_manager->costs_, dist_array); + + // If we are dealing with a non-literal. + if (len >= 2) { + if (offset != offset_prev) { + const int code = VP8LDistanceToPlaneCode(xsize, offset); + offset_cost = GetDistanceCost(cost_model, code); + first_offset_is_constant = 1; + PushInterval(cost_manager, prev_cost + offset_cost, i, len); + } else { + assert(offset_cost >= 0); + assert(len_prev >= 0); + assert(first_offset_is_constant == 0 || first_offset_is_constant == 1); + // Instead of considering all contributions from a pixel i by calling: + // PushInterval(cost_manager, prev_cost + offset_cost, i, len); + // we optimize these contributions in case offset_cost stays the same + // for consecutive pixels. This describes a set of pixels similar to a + // previous set (e.g. constant color regions). + if (first_offset_is_constant) { + reach = i - 1 + len_prev - 1; + first_offset_is_constant = 0; + } + + if (i + len - 1 > reach) { + // We can only be go further with the same offset if the previous + // length was maxed, hence len_prev == len == MAX_LENGTH. + // TODO(vrabaud), bump i to the end right away (insert cache and + // update cost). + // TODO(vrabaud), check if one of the points in between does not have + // a lower cost. + // Already consider the pixel at "reach" to add intervals that are + // better than whatever we add. + int offset_j, len_j = 0; + int j; + assert(len == MAX_LENGTH || len == pix_count - i); + // Figure out the last consecutive pixel within [i, reach + 1] with + // the same offset. + for (j = i; j <= reach; ++j) { + VP8LHashChainFindCopy(hash_chain, j + 1, &offset_j, &len_j); + if (offset_j != offset) { + VP8LHashChainFindCopy(hash_chain, j, &offset_j, &len_j); + break; + } + } + // Update the cost at j - 1 and j. + UpdateCostAtIndex(cost_manager, j - 1, 0); + UpdateCostAtIndex(cost_manager, j, 0); + + PushInterval(cost_manager, cost_manager->costs_[j - 1] + offset_cost, + j, len_j); + reach = j + len_j - 1; + } + } + } + + UpdateCostAtIndex(cost_manager, i, 1); + offset_prev = offset; + len_prev = len; + } + + ok = !refs->error_; + Error: + if (cc_init) VP8LColorCacheClear(&hashers); + CostManagerClear(cost_manager); + WebPSafeFree(cost_model); + WebPSafeFree(cost_manager); + return ok; +} + +// We pack the path at the end of *dist_array and return +// a pointer to this part of the array. Example: +// dist_array = [1x2xx3x2] => packed [1x2x1232], chosen_path = [1232] +static void TraceBackwards(uint16_t* const dist_array, + int dist_array_size, + uint16_t** const chosen_path, + int* const chosen_path_size) { + uint16_t* path = dist_array + dist_array_size; + uint16_t* cur = dist_array + dist_array_size - 1; + while (cur >= dist_array) { + const int k = *cur; + --path; + *path = k; + cur -= k; + } + *chosen_path = path; + *chosen_path_size = (int)(dist_array + dist_array_size - path); +} + +static int BackwardReferencesHashChainFollowChosenPath( + const uint32_t* const argb, int cache_bits, + const uint16_t* const chosen_path, int chosen_path_size, + const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs) { + const int use_color_cache = (cache_bits > 0); + int ix; + int i = 0; + int ok = 0; + int cc_init = 0; + VP8LColorCache hashers; + + if (use_color_cache) { + cc_init = VP8LColorCacheInit(&hashers, cache_bits); + if (!cc_init) goto Error; + } + + VP8LClearBackwardRefs(refs); + for (ix = 0; ix < chosen_path_size; ++ix) { + const int len = chosen_path[ix]; + if (len != 1) { + int k; + const int offset = VP8LHashChainFindOffset(hash_chain, i); + VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len)); + if (use_color_cache) { + for (k = 0; k < len; ++k) { + VP8LColorCacheInsert(&hashers, argb[i + k]); + } + } + i += len; + } else { + PixOrCopy v; + const int idx = + use_color_cache ? VP8LColorCacheContains(&hashers, argb[i]) : -1; + if (idx >= 0) { + // use_color_cache is true and hashers contains argb[i] + // push pixel as a color cache index + v = PixOrCopyCreateCacheIdx(idx); + } else { + if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); + v = PixOrCopyCreateLiteral(argb[i]); + } + VP8LBackwardRefsCursorAdd(refs, v); + ++i; + } + } + ok = !refs->error_; + Error: + if (cc_init) VP8LColorCacheClear(&hashers); + return ok; +} + +// Returns 1 on success. +extern int VP8LBackwardReferencesTraceBackwards( + int xsize, int ysize, const uint32_t* const argb, int cache_bits, + const VP8LHashChain* const hash_chain, + const VP8LBackwardRefs* const refs_src, VP8LBackwardRefs* const refs_dst); +int VP8LBackwardReferencesTraceBackwards(int xsize, int ysize, + const uint32_t* const argb, + int cache_bits, + const VP8LHashChain* const hash_chain, + const VP8LBackwardRefs* const refs_src, + VP8LBackwardRefs* const refs_dst) { + int ok = 0; + const int dist_array_size = xsize * ysize; + uint16_t* chosen_path = NULL; + int chosen_path_size = 0; + uint16_t* dist_array = + (uint16_t*)WebPSafeMalloc(dist_array_size, sizeof(*dist_array)); + + if (dist_array == NULL) goto Error; + + if (!BackwardReferencesHashChainDistanceOnly( + xsize, ysize, argb, cache_bits, hash_chain, refs_src, dist_array)) { + goto Error; + } + TraceBackwards(dist_array, dist_array_size, &chosen_path, &chosen_path_size); + if (!BackwardReferencesHashChainFollowChosenPath( + argb, cache_bits, chosen_path, chosen_path_size, hash_chain, + refs_dst)) { + goto Error; + } + ok = 1; + Error: + WebPSafeFree(dist_array); + return ok; +} diff --git a/libraries/webp/src/enc/backward_references_enc.c b/libraries/webp/src/enc/backward_references_enc.c new file mode 100644 index 00000000000..873aa8f22ca --- /dev/null +++ b/libraries/webp/src/enc/backward_references_enc.c @@ -0,0 +1,1065 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// + +#include "src/enc/backward_references_enc.h" + +#include +#include +#include + +#include "src/dsp/dsp.h" +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" +#include "src/enc/histogram_enc.h" +#include "src/enc/vp8i_enc.h" +#include "src/utils/color_cache_utils.h" +#include "src/utils/utils.h" +#include "include/webp/encode.h" + +#define MIN_BLOCK_SIZE 256 // minimum block size for backward references + +#define MAX_ENTROPY (1e30f) + +// 1M window (4M bytes) minus 120 special codes for short distances. +#define WINDOW_SIZE ((1 << WINDOW_SIZE_BITS) - 120) + +// Minimum number of pixels for which it is cheaper to encode a +// distance + length instead of each pixel as a literal. +#define MIN_LENGTH 4 + +// ----------------------------------------------------------------------------- + +static const uint8_t plane_to_code_lut[128] = { + 96, 73, 55, 39, 23, 13, 5, 1, 255, 255, 255, 255, 255, 255, 255, 255, + 101, 78, 58, 42, 26, 16, 8, 2, 0, 3, 9, 17, 27, 43, 59, 79, + 102, 86, 62, 46, 32, 20, 10, 6, 4, 7, 11, 21, 33, 47, 63, 87, + 105, 90, 70, 52, 37, 28, 18, 14, 12, 15, 19, 29, 38, 53, 71, 91, + 110, 99, 82, 66, 48, 35, 30, 24, 22, 25, 31, 36, 49, 67, 83, 100, + 115, 108, 94, 76, 64, 50, 44, 40, 34, 41, 45, 51, 65, 77, 95, 109, + 118, 113, 103, 92, 80, 68, 60, 56, 54, 57, 61, 69, 81, 93, 104, 114, + 119, 116, 111, 106, 97, 88, 84, 74, 72, 75, 85, 89, 98, 107, 112, 117 +}; + +extern int VP8LDistanceToPlaneCode(int xsize, int dist); +int VP8LDistanceToPlaneCode(int xsize, int dist) { + const int yoffset = dist / xsize; + const int xoffset = dist - yoffset * xsize; + if (xoffset <= 8 && yoffset < 8) { + return plane_to_code_lut[yoffset * 16 + 8 - xoffset] + 1; + } else if (xoffset > xsize - 8 && yoffset < 7) { + return plane_to_code_lut[(yoffset + 1) * 16 + 8 + (xsize - xoffset)] + 1; + } + return dist + 120; +} + +// Returns the exact index where array1 and array2 are different. For an index +// inferior or equal to best_len_match, the return value just has to be strictly +// inferior to best_len_match. The current behavior is to return 0 if this index +// is best_len_match, and the index itself otherwise. +// If no two elements are the same, it returns max_limit. +static WEBP_INLINE int FindMatchLength(const uint32_t* const array1, + const uint32_t* const array2, + int best_len_match, int max_limit) { + // Before 'expensive' linear match, check if the two arrays match at the + // current best length index. + if (array1[best_len_match] != array2[best_len_match]) return 0; + + return VP8LVectorMismatch(array1, array2, max_limit); +} + +// ----------------------------------------------------------------------------- +// VP8LBackwardRefs + +struct PixOrCopyBlock { + PixOrCopyBlock* next_; // next block (or NULL) + PixOrCopy* start_; // data start + int size_; // currently used size +}; + +extern void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs); +void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) { + assert(refs != NULL); + if (refs->tail_ != NULL) { + *refs->tail_ = refs->free_blocks_; // recycle all blocks at once + } + refs->free_blocks_ = refs->refs_; + refs->tail_ = &refs->refs_; + refs->last_block_ = NULL; + refs->refs_ = NULL; +} + +void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) { + assert(refs != NULL); + VP8LClearBackwardRefs(refs); + while (refs->free_blocks_ != NULL) { + PixOrCopyBlock* const next = refs->free_blocks_->next_; + WebPSafeFree(refs->free_blocks_); + refs->free_blocks_ = next; + } +} + +// Swaps the content of two VP8LBackwardRefs. +static void BackwardRefsSwap(VP8LBackwardRefs* const refs1, + VP8LBackwardRefs* const refs2) { + const int point_to_refs1 = + (refs1->tail_ != NULL && refs1->tail_ == &refs1->refs_); + const int point_to_refs2 = + (refs2->tail_ != NULL && refs2->tail_ == &refs2->refs_); + const VP8LBackwardRefs tmp = *refs1; + *refs1 = *refs2; + *refs2 = tmp; + if (point_to_refs2) refs1->tail_ = &refs1->refs_; + if (point_to_refs1) refs2->tail_ = &refs2->refs_; +} + +void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size) { + assert(refs != NULL); + memset(refs, 0, sizeof(*refs)); + refs->tail_ = &refs->refs_; + refs->block_size_ = + (block_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : block_size; +} + +VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs) { + VP8LRefsCursor c; + c.cur_block_ = refs->refs_; + if (refs->refs_ != NULL) { + c.cur_pos = c.cur_block_->start_; + c.last_pos_ = c.cur_pos + c.cur_block_->size_; + } else { + c.cur_pos = NULL; + c.last_pos_ = NULL; + } + return c; +} + +void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c) { + PixOrCopyBlock* const b = c->cur_block_->next_; + c->cur_pos = (b == NULL) ? NULL : b->start_; + c->last_pos_ = (b == NULL) ? NULL : b->start_ + b->size_; + c->cur_block_ = b; +} + +// Create a new block, either from the free list or allocated +static PixOrCopyBlock* BackwardRefsNewBlock(VP8LBackwardRefs* const refs) { + PixOrCopyBlock* b = refs->free_blocks_; + if (b == NULL) { // allocate new memory chunk + const size_t total_size = + sizeof(*b) + refs->block_size_ * sizeof(*b->start_); + b = (PixOrCopyBlock*)WebPSafeMalloc(1ULL, total_size); + if (b == NULL) { + refs->error_ |= 1; + return NULL; + } + b->start_ = (PixOrCopy*)((uint8_t*)b + sizeof(*b)); // not always aligned + } else { // recycle from free-list + refs->free_blocks_ = b->next_; + } + *refs->tail_ = b; + refs->tail_ = &b->next_; + refs->last_block_ = b; + b->next_ = NULL; + b->size_ = 0; + return b; +} + +// Return 1 on success, 0 on error. +static int BackwardRefsClone(const VP8LBackwardRefs* const from, + VP8LBackwardRefs* const to) { + const PixOrCopyBlock* block_from = from->refs_; + VP8LClearBackwardRefs(to); + while (block_from != NULL) { + PixOrCopyBlock* const block_to = BackwardRefsNewBlock(to); + if (block_to == NULL) return 0; + memcpy(block_to->start_, block_from->start_, + block_from->size_ * sizeof(PixOrCopy)); + block_to->size_ = block_from->size_; + block_from = block_from->next_; + } + return 1; +} + +extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, + const PixOrCopy v); +void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, + const PixOrCopy v) { + PixOrCopyBlock* b = refs->last_block_; + if (b == NULL || b->size_ == refs->block_size_) { + b = BackwardRefsNewBlock(refs); + if (b == NULL) return; // refs->error_ is set + } + b->start_[b->size_++] = v; +} + +// ----------------------------------------------------------------------------- +// Hash chains + +int VP8LHashChainInit(VP8LHashChain* const p, int size) { + assert(p->size_ == 0); + assert(p->offset_length_ == NULL); + assert(size > 0); + p->offset_length_ = + (uint32_t*)WebPSafeMalloc(size, sizeof(*p->offset_length_)); + if (p->offset_length_ == NULL) return 0; + p->size_ = size; + + return 1; +} + +void VP8LHashChainClear(VP8LHashChain* const p) { + assert(p != NULL); + WebPSafeFree(p->offset_length_); + + p->size_ = 0; + p->offset_length_ = NULL; +} + +// ----------------------------------------------------------------------------- + +static const uint32_t kHashMultiplierHi = 0xc6a4a793u; +static const uint32_t kHashMultiplierLo = 0x5bd1e996u; + +static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE +uint32_t GetPixPairHash64(const uint32_t* const argb) { + uint32_t key; + key = argb[1] * kHashMultiplierHi; + key += argb[0] * kHashMultiplierLo; + key = key >> (32 - HASH_BITS); + return key; +} + +// Returns the maximum number of hash chain lookups to do for a +// given compression quality. Return value in range [8, 86]. +static int GetMaxItersForQuality(int quality) { + return 8 + (quality * quality) / 128; +} + +static int GetWindowSizeForHashChain(int quality, int xsize) { + const int max_window_size = (quality > 75) ? WINDOW_SIZE + : (quality > 50) ? (xsize << 8) + : (quality > 25) ? (xsize << 6) + : (xsize << 4); + assert(xsize > 0); + return (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE : max_window_size; +} + +static WEBP_INLINE int MaxFindCopyLength(int len) { + return (len < MAX_LENGTH) ? len : MAX_LENGTH; +} + +int VP8LHashChainFill(VP8LHashChain* const p, int quality, + const uint32_t* const argb, int xsize, int ysize, + int low_effort, const WebPPicture* const pic, + int percent_range, int* const percent) { + const int size = xsize * ysize; + const int iter_max = GetMaxItersForQuality(quality); + const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize); + int remaining_percent = percent_range; + int percent_start = *percent; + int pos; + int argb_comp; + uint32_t base_position; + int32_t* hash_to_first_index; + // Temporarily use the p->offset_length_ as a hash chain. + int32_t* chain = (int32_t*)p->offset_length_; + assert(size > 0); + assert(p->size_ != 0); + assert(p->offset_length_ != NULL); + + if (size <= 2) { + p->offset_length_[0] = p->offset_length_[size - 1] = 0; + return 1; + } + + hash_to_first_index = + (int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index)); + if (hash_to_first_index == NULL) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + + percent_range = remaining_percent / 2; + remaining_percent -= percent_range; + + // Set the int32_t array to -1. + memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index)); + // Fill the chain linking pixels with the same hash. + argb_comp = (argb[0] == argb[1]); + for (pos = 0; pos < size - 2;) { + uint32_t hash_code; + const int argb_comp_next = (argb[pos + 1] == argb[pos + 2]); + if (argb_comp && argb_comp_next) { + // Consecutive pixels with the same color will share the same hash. + // We therefore use a different hash: the color and its repetition + // length. + uint32_t tmp[2]; + uint32_t len = 1; + tmp[0] = argb[pos]; + // Figure out how far the pixels are the same. + // The last pixel has a different 64 bit hash, as its next pixel does + // not have the same color, so we just need to get to the last pixel equal + // to its follower. + while (pos + (int)len + 2 < size && argb[pos + len + 2] == argb[pos]) { + ++len; + } + if (len > MAX_LENGTH) { + // Skip the pixels that match for distance=1 and length>MAX_LENGTH + // because they are linked to their predecessor and we automatically + // check that in the main for loop below. Skipping means setting no + // predecessor in the chain, hence -1. + memset(chain + pos, 0xff, (len - MAX_LENGTH) * sizeof(*chain)); + pos += len - MAX_LENGTH; + len = MAX_LENGTH; + } + // Process the rest of the hash chain. + while (len) { + tmp[1] = len--; + hash_code = GetPixPairHash64(tmp); + chain[pos] = hash_to_first_index[hash_code]; + hash_to_first_index[hash_code] = pos++; + } + argb_comp = 0; + } else { + // Just move one pixel forward. + hash_code = GetPixPairHash64(argb + pos); + chain[pos] = hash_to_first_index[hash_code]; + hash_to_first_index[hash_code] = pos++; + argb_comp = argb_comp_next; + } + + if (!WebPReportProgress( + pic, percent_start + percent_range * pos / (size - 2), percent)) { + WebPSafeFree(hash_to_first_index); + return 0; + } + } + // Process the penultimate pixel. + chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)]; + + WebPSafeFree(hash_to_first_index); + + percent_start += percent_range; + if (!WebPReportProgress(pic, percent_start, percent)) return 0; + percent_range = remaining_percent; + + // Find the best match interval at each pixel, defined by an offset to the + // pixel and a length. The right-most pixel cannot match anything to the right + // (hence a best length of 0) and the left-most pixel nothing to the left + // (hence an offset of 0). + assert(size > 2); + p->offset_length_[0] = p->offset_length_[size - 1] = 0; + for (base_position = size - 2; base_position > 0;) { + const int max_len = MaxFindCopyLength(size - 1 - base_position); + const uint32_t* const argb_start = argb + base_position; + int iter = iter_max; + int best_length = 0; + uint32_t best_distance = 0; + uint32_t best_argb; + const int min_pos = + (base_position > window_size) ? base_position - window_size : 0; + const int length_max = (max_len < 256) ? max_len : 256; + uint32_t max_base_position; + + pos = chain[base_position]; + if (!low_effort) { + int curr_length; + // Heuristic: use the comparison with the above line as an initialization. + if (base_position >= (uint32_t)xsize) { + curr_length = FindMatchLength(argb_start - xsize, argb_start, + best_length, max_len); + if (curr_length > best_length) { + best_length = curr_length; + best_distance = xsize; + } + --iter; + } + // Heuristic: compare to the previous pixel. + curr_length = + FindMatchLength(argb_start - 1, argb_start, best_length, max_len); + if (curr_length > best_length) { + best_length = curr_length; + best_distance = 1; + } + --iter; + // Skip the for loop if we already have the maximum. + if (best_length == MAX_LENGTH) pos = min_pos - 1; + } + best_argb = argb_start[best_length]; + + for (; pos >= min_pos && --iter; pos = chain[pos]) { + int curr_length; + assert(base_position > (uint32_t)pos); + + if (argb[pos + best_length] != best_argb) continue; + + curr_length = VP8LVectorMismatch(argb + pos, argb_start, max_len); + if (best_length < curr_length) { + best_length = curr_length; + best_distance = base_position - pos; + best_argb = argb_start[best_length]; + // Stop if we have reached a good enough length. + if (best_length >= length_max) break; + } + } + // We have the best match but in case the two intervals continue matching + // to the left, we have the best matches for the left-extended pixels. + max_base_position = base_position; + while (1) { + assert(best_length <= MAX_LENGTH); + assert(best_distance <= WINDOW_SIZE); + p->offset_length_[base_position] = + (best_distance << MAX_LENGTH_BITS) | (uint32_t)best_length; + --base_position; + // Stop if we don't have a match or if we are out of bounds. + if (best_distance == 0 || base_position == 0) break; + // Stop if we cannot extend the matching intervals to the left. + if (base_position < best_distance || + argb[base_position - best_distance] != argb[base_position]) { + break; + } + // Stop if we are matching at its limit because there could be a closer + // matching interval with the same maximum length. Then again, if the + // matching interval is as close as possible (best_distance == 1), we will + // never find anything better so let's continue. + if (best_length == MAX_LENGTH && best_distance != 1 && + base_position + MAX_LENGTH < max_base_position) { + break; + } + if (best_length < MAX_LENGTH) { + ++best_length; + max_base_position = base_position; + } + } + + if (!WebPReportProgress(pic, + percent_start + percent_range * + (size - 2 - base_position) / + (size - 2), + percent)) { + return 0; + } + } + + return WebPReportProgress(pic, percent_start + percent_range, percent); +} + +static WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache, + VP8LColorCache* const hashers, + VP8LBackwardRefs* const refs) { + PixOrCopy v; + if (use_color_cache) { + const uint32_t key = VP8LColorCacheGetIndex(hashers, pixel); + if (VP8LColorCacheLookup(hashers, key) == pixel) { + v = PixOrCopyCreateCacheIdx(key); + } else { + v = PixOrCopyCreateLiteral(pixel); + VP8LColorCacheSet(hashers, key, pixel); + } + } else { + v = PixOrCopyCreateLiteral(pixel); + } + VP8LBackwardRefsCursorAdd(refs, v); +} + +static int BackwardReferencesRle(int xsize, int ysize, + const uint32_t* const argb, + int cache_bits, VP8LBackwardRefs* const refs) { + const int pix_count = xsize * ysize; + int i, k; + const int use_color_cache = (cache_bits > 0); + VP8LColorCache hashers; + + if (use_color_cache && !VP8LColorCacheInit(&hashers, cache_bits)) { + return 0; + } + VP8LClearBackwardRefs(refs); + // Add first pixel as literal. + AddSingleLiteral(argb[0], use_color_cache, &hashers, refs); + i = 1; + while (i < pix_count) { + const int max_len = MaxFindCopyLength(pix_count - i); + const int rle_len = FindMatchLength(argb + i, argb + i - 1, 0, max_len); + const int prev_row_len = (i < xsize) ? 0 : + FindMatchLength(argb + i, argb + i - xsize, 0, max_len); + if (rle_len >= prev_row_len && rle_len >= MIN_LENGTH) { + VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, rle_len)); + // We don't need to update the color cache here since it is always the + // same pixel being copied, and that does not change the color cache + // state. + i += rle_len; + } else if (prev_row_len >= MIN_LENGTH) { + VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(xsize, prev_row_len)); + if (use_color_cache) { + for (k = 0; k < prev_row_len; ++k) { + VP8LColorCacheInsert(&hashers, argb[i + k]); + } + } + i += prev_row_len; + } else { + AddSingleLiteral(argb[i], use_color_cache, &hashers, refs); + i++; + } + } + if (use_color_cache) VP8LColorCacheClear(&hashers); + return !refs->error_; +} + +static int BackwardReferencesLz77(int xsize, int ysize, + const uint32_t* const argb, int cache_bits, + const VP8LHashChain* const hash_chain, + VP8LBackwardRefs* const refs) { + int i; + int i_last_check = -1; + int ok = 0; + int cc_init = 0; + const int use_color_cache = (cache_bits > 0); + const int pix_count = xsize * ysize; + VP8LColorCache hashers; + + if (use_color_cache) { + cc_init = VP8LColorCacheInit(&hashers, cache_bits); + if (!cc_init) goto Error; + } + VP8LClearBackwardRefs(refs); + for (i = 0; i < pix_count;) { + // Alternative#1: Code the pixels starting at 'i' using backward reference. + int offset = 0; + int len = 0; + int j; + VP8LHashChainFindCopy(hash_chain, i, &offset, &len); + if (len >= MIN_LENGTH) { + const int len_ini = len; + int max_reach = 0; + const int j_max = + (i + len_ini >= pix_count) ? pix_count - 1 : i + len_ini; + // Only start from what we have not checked already. + i_last_check = (i > i_last_check) ? i : i_last_check; + // We know the best match for the current pixel but we try to find the + // best matches for the current pixel AND the next one combined. + // The naive method would use the intervals: + // [i,i+len) + [i+len, length of best match at i+len) + // while we check if we can use: + // [i,j) (where j<=i+len) + [j, length of best match at j) + for (j = i_last_check + 1; j <= j_max; ++j) { + const int len_j = VP8LHashChainFindLength(hash_chain, j); + const int reach = + j + (len_j >= MIN_LENGTH ? len_j : 1); // 1 for single literal. + if (reach > max_reach) { + len = j - i; + max_reach = reach; + if (max_reach >= pix_count) break; + } + } + } else { + len = 1; + } + // Go with literal or backward reference. + assert(len > 0); + if (len == 1) { + AddSingleLiteral(argb[i], use_color_cache, &hashers, refs); + } else { + VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len)); + if (use_color_cache) { + for (j = i; j < i + len; ++j) VP8LColorCacheInsert(&hashers, argb[j]); + } + } + i += len; + } + + ok = !refs->error_; + Error: + if (cc_init) VP8LColorCacheClear(&hashers); + return ok; +} + +// Compute an LZ77 by forcing matches to happen within a given distance cost. +// We therefore limit the algorithm to the lowest 32 values in the PlaneCode +// definition. +#define WINDOW_OFFSETS_SIZE_MAX 32 +static int BackwardReferencesLz77Box(int xsize, int ysize, + const uint32_t* const argb, int cache_bits, + const VP8LHashChain* const hash_chain_best, + VP8LHashChain* hash_chain, + VP8LBackwardRefs* const refs) { + int i; + const int pix_count = xsize * ysize; + uint16_t* counts; + int window_offsets[WINDOW_OFFSETS_SIZE_MAX] = {0}; + int window_offsets_new[WINDOW_OFFSETS_SIZE_MAX] = {0}; + int window_offsets_size = 0; + int window_offsets_new_size = 0; + uint16_t* const counts_ini = + (uint16_t*)WebPSafeMalloc(xsize * ysize, sizeof(*counts_ini)); + int best_offset_prev = -1, best_length_prev = -1; + if (counts_ini == NULL) return 0; + + // counts[i] counts how many times a pixel is repeated starting at position i. + i = pix_count - 2; + counts = counts_ini + i; + counts[1] = 1; + for (; i >= 0; --i, --counts) { + if (argb[i] == argb[i + 1]) { + // Max out the counts to MAX_LENGTH. + counts[0] = counts[1] + (counts[1] != MAX_LENGTH); + } else { + counts[0] = 1; + } + } + + // Figure out the window offsets around a pixel. They are stored in a + // spiraling order around the pixel as defined by VP8LDistanceToPlaneCode. + { + int x, y; + for (y = 0; y <= 6; ++y) { + for (x = -6; x <= 6; ++x) { + const int offset = y * xsize + x; + int plane_code; + // Ignore offsets that bring us after the pixel. + if (offset <= 0) continue; + plane_code = VP8LDistanceToPlaneCode(xsize, offset) - 1; + if (plane_code >= WINDOW_OFFSETS_SIZE_MAX) continue; + window_offsets[plane_code] = offset; + } + } + // For narrow images, not all plane codes are reached, so remove those. + for (i = 0; i < WINDOW_OFFSETS_SIZE_MAX; ++i) { + if (window_offsets[i] == 0) continue; + window_offsets[window_offsets_size++] = window_offsets[i]; + } + // Given a pixel P, find the offsets that reach pixels unreachable from P-1 + // with any of the offsets in window_offsets[]. + for (i = 0; i < window_offsets_size; ++i) { + int j; + int is_reachable = 0; + for (j = 0; j < window_offsets_size && !is_reachable; ++j) { + is_reachable |= (window_offsets[i] == window_offsets[j] + 1); + } + if (!is_reachable) { + window_offsets_new[window_offsets_new_size] = window_offsets[i]; + ++window_offsets_new_size; + } + } + } + + hash_chain->offset_length_[0] = 0; + for (i = 1; i < pix_count; ++i) { + int ind; + int best_length = VP8LHashChainFindLength(hash_chain_best, i); + int best_offset; + int do_compute = 1; + + if (best_length >= MAX_LENGTH) { + // Do not recompute the best match if we already have a maximal one in the + // window. + best_offset = VP8LHashChainFindOffset(hash_chain_best, i); + for (ind = 0; ind < window_offsets_size; ++ind) { + if (best_offset == window_offsets[ind]) { + do_compute = 0; + break; + } + } + } + if (do_compute) { + // Figure out if we should use the offset/length from the previous pixel + // as an initial guess and therefore only inspect the offsets in + // window_offsets_new[]. + const int use_prev = + (best_length_prev > 1) && (best_length_prev < MAX_LENGTH); + const int num_ind = + use_prev ? window_offsets_new_size : window_offsets_size; + best_length = use_prev ? best_length_prev - 1 : 0; + best_offset = use_prev ? best_offset_prev : 0; + // Find the longest match in a window around the pixel. + for (ind = 0; ind < num_ind; ++ind) { + int curr_length = 0; + int j = i; + int j_offset = + use_prev ? i - window_offsets_new[ind] : i - window_offsets[ind]; + if (j_offset < 0 || argb[j_offset] != argb[i]) continue; + // The longest match is the sum of how many times each pixel is + // repeated. + do { + const int counts_j_offset = counts_ini[j_offset]; + const int counts_j = counts_ini[j]; + if (counts_j_offset != counts_j) { + curr_length += + (counts_j_offset < counts_j) ? counts_j_offset : counts_j; + break; + } + // The same color is repeated counts_pos times at j_offset and j. + curr_length += counts_j_offset; + j_offset += counts_j_offset; + j += counts_j_offset; + } while (curr_length <= MAX_LENGTH && j < pix_count && + argb[j_offset] == argb[j]); + if (best_length < curr_length) { + best_offset = + use_prev ? window_offsets_new[ind] : window_offsets[ind]; + if (curr_length >= MAX_LENGTH) { + best_length = MAX_LENGTH; + break; + } else { + best_length = curr_length; + } + } + } + } + + assert(i + best_length <= pix_count); + assert(best_length <= MAX_LENGTH); + if (best_length <= MIN_LENGTH) { + hash_chain->offset_length_[i] = 0; + best_offset_prev = 0; + best_length_prev = 0; + } else { + hash_chain->offset_length_[i] = + (best_offset << MAX_LENGTH_BITS) | (uint32_t)best_length; + best_offset_prev = best_offset; + best_length_prev = best_length; + } + } + hash_chain->offset_length_[0] = 0; + WebPSafeFree(counts_ini); + + return BackwardReferencesLz77(xsize, ysize, argb, cache_bits, hash_chain, + refs); +} + +// ----------------------------------------------------------------------------- + +static void BackwardReferences2DLocality(int xsize, + const VP8LBackwardRefs* const refs) { + VP8LRefsCursor c = VP8LRefsCursorInit(refs); + while (VP8LRefsCursorOk(&c)) { + if (PixOrCopyIsCopy(c.cur_pos)) { + const int dist = c.cur_pos->argb_or_distance; + const int transformed_dist = VP8LDistanceToPlaneCode(xsize, dist); + c.cur_pos->argb_or_distance = transformed_dist; + } + VP8LRefsCursorNext(&c); + } +} + +// Evaluate optimal cache bits for the local color cache. +// The input *best_cache_bits sets the maximum cache bits to use (passing 0 +// implies disabling the local color cache). The local color cache is also +// disabled for the lower (<= 25) quality. +// Returns 0 in case of memory error. +static int CalculateBestCacheSize(const uint32_t* argb, int quality, + const VP8LBackwardRefs* const refs, + int* const best_cache_bits) { + int i; + const int cache_bits_max = (quality <= 25) ? 0 : *best_cache_bits; + float entropy_min = MAX_ENTROPY; + int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 }; + VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1]; + VP8LRefsCursor c = VP8LRefsCursorInit(refs); + VP8LHistogram* histos[MAX_COLOR_CACHE_BITS + 1] = { NULL }; + int ok = 0; + + assert(cache_bits_max >= 0 && cache_bits_max <= MAX_COLOR_CACHE_BITS); + + if (cache_bits_max == 0) { + *best_cache_bits = 0; + // Local color cache is disabled. + return 1; + } + + // Allocate data. + for (i = 0; i <= cache_bits_max; ++i) { + histos[i] = VP8LAllocateHistogram(i); + if (histos[i] == NULL) goto Error; + VP8LHistogramInit(histos[i], i, /*init_arrays=*/ 1); + if (i == 0) continue; + cc_init[i] = VP8LColorCacheInit(&hashers[i], i); + if (!cc_init[i]) goto Error; + } + + // Find the cache_bits giving the lowest entropy. The search is done in a + // brute-force way as the function (entropy w.r.t cache_bits) can be + // anything in practice. + while (VP8LRefsCursorOk(&c)) { + const PixOrCopy* const v = c.cur_pos; + if (PixOrCopyIsLiteral(v)) { + const uint32_t pix = *argb++; + const uint32_t a = (pix >> 24) & 0xff; + const uint32_t r = (pix >> 16) & 0xff; + const uint32_t g = (pix >> 8) & 0xff; + const uint32_t b = (pix >> 0) & 0xff; + // The keys of the caches can be derived from the longest one. + int key = VP8LHashPix(pix, 32 - cache_bits_max); + // Do not use the color cache for cache_bits = 0. + ++histos[0]->blue_[b]; + ++histos[0]->literal_[g]; + ++histos[0]->red_[r]; + ++histos[0]->alpha_[a]; + // Deal with cache_bits > 0. + for (i = cache_bits_max; i >= 1; --i, key >>= 1) { + if (VP8LColorCacheLookup(&hashers[i], key) == pix) { + ++histos[i]->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key]; + } else { + VP8LColorCacheSet(&hashers[i], key, pix); + ++histos[i]->blue_[b]; + ++histos[i]->literal_[g]; + ++histos[i]->red_[r]; + ++histos[i]->alpha_[a]; + } + } + } else { + int code, extra_bits, extra_bits_value; + // We should compute the contribution of the (distance,length) + // histograms but those are the same independently from the cache size. + // As those constant contributions are in the end added to the other + // histogram contributions, we can ignore them, except for the length + // prefix that is part of the literal_ histogram. + int len = PixOrCopyLength(v); + uint32_t argb_prev = *argb ^ 0xffffffffu; + VP8LPrefixEncode(len, &code, &extra_bits, &extra_bits_value); + for (i = 0; i <= cache_bits_max; ++i) { + ++histos[i]->literal_[NUM_LITERAL_CODES + code]; + } + // Update the color caches. + do { + if (*argb != argb_prev) { + // Efficiency: insert only if the color changes. + int key = VP8LHashPix(*argb, 32 - cache_bits_max); + for (i = cache_bits_max; i >= 1; --i, key >>= 1) { + hashers[i].colors_[key] = *argb; + } + argb_prev = *argb; + } + argb++; + } while (--len != 0); + } + VP8LRefsCursorNext(&c); + } + + for (i = 0; i <= cache_bits_max; ++i) { + const float entropy = VP8LHistogramEstimateBits(histos[i]); + if (i == 0 || entropy < entropy_min) { + entropy_min = entropy; + *best_cache_bits = i; + } + } + ok = 1; + Error: + for (i = 0; i <= cache_bits_max; ++i) { + if (cc_init[i]) VP8LColorCacheClear(&hashers[i]); + VP8LFreeHistogram(histos[i]); + } + return ok; +} + +// Update (in-place) backward references for specified cache_bits. +static int BackwardRefsWithLocalCache(const uint32_t* const argb, + int cache_bits, + VP8LBackwardRefs* const refs) { + int pixel_index = 0; + VP8LColorCache hashers; + VP8LRefsCursor c = VP8LRefsCursorInit(refs); + if (!VP8LColorCacheInit(&hashers, cache_bits)) return 0; + + while (VP8LRefsCursorOk(&c)) { + PixOrCopy* const v = c.cur_pos; + if (PixOrCopyIsLiteral(v)) { + const uint32_t argb_literal = v->argb_or_distance; + const int ix = VP8LColorCacheContains(&hashers, argb_literal); + if (ix >= 0) { + // hashers contains argb_literal + *v = PixOrCopyCreateCacheIdx(ix); + } else { + VP8LColorCacheInsert(&hashers, argb_literal); + } + ++pixel_index; + } else { + // refs was created without local cache, so it can not have cache indexes. + int k; + assert(PixOrCopyIsCopy(v)); + for (k = 0; k < v->len; ++k) { + VP8LColorCacheInsert(&hashers, argb[pixel_index++]); + } + } + VP8LRefsCursorNext(&c); + } + VP8LColorCacheClear(&hashers); + return 1; +} + +static VP8LBackwardRefs* GetBackwardReferencesLowEffort( + int width, int height, const uint32_t* const argb, + int* const cache_bits, const VP8LHashChain* const hash_chain, + VP8LBackwardRefs* const refs_lz77) { + *cache_bits = 0; + if (!BackwardReferencesLz77(width, height, argb, 0, hash_chain, refs_lz77)) { + return NULL; + } + BackwardReferences2DLocality(width, refs_lz77); + return refs_lz77; +} + +extern int VP8LBackwardReferencesTraceBackwards( + int xsize, int ysize, const uint32_t* const argb, int cache_bits, + const VP8LHashChain* const hash_chain, + const VP8LBackwardRefs* const refs_src, VP8LBackwardRefs* const refs_dst); +static int GetBackwardReferences(int width, int height, + const uint32_t* const argb, int quality, + int lz77_types_to_try, int cache_bits_max, + int do_no_cache, + const VP8LHashChain* const hash_chain, + VP8LBackwardRefs* const refs, + int* const cache_bits_best) { + VP8LHistogram* histo = NULL; + int i, lz77_type; + // Index 0 is for a color cache, index 1 for no cache (if needed). + int lz77_types_best[2] = {0, 0}; + float bit_costs_best[2] = {FLT_MAX, FLT_MAX}; + VP8LHashChain hash_chain_box; + VP8LBackwardRefs* const refs_tmp = &refs[do_no_cache ? 2 : 1]; + int status = 0; + memset(&hash_chain_box, 0, sizeof(hash_chain_box)); + + histo = VP8LAllocateHistogram(MAX_COLOR_CACHE_BITS); + if (histo == NULL) goto Error; + + for (lz77_type = 1; lz77_types_to_try; + lz77_types_to_try &= ~lz77_type, lz77_type <<= 1) { + int res = 0; + float bit_cost = 0.f; + if ((lz77_types_to_try & lz77_type) == 0) continue; + switch (lz77_type) { + case kLZ77RLE: + res = BackwardReferencesRle(width, height, argb, 0, refs_tmp); + break; + case kLZ77Standard: + // Compute LZ77 with no cache (0 bits), as the ideal LZ77 with a color + // cache is not that different in practice. + res = BackwardReferencesLz77(width, height, argb, 0, hash_chain, + refs_tmp); + break; + case kLZ77Box: + if (!VP8LHashChainInit(&hash_chain_box, width * height)) goto Error; + res = BackwardReferencesLz77Box(width, height, argb, 0, hash_chain, + &hash_chain_box, refs_tmp); + break; + default: + assert(0); + } + if (!res) goto Error; + + // Start with the no color cache case. + for (i = 1; i >= 0; --i) { + int cache_bits = (i == 1) ? 0 : cache_bits_max; + + if (i == 1 && !do_no_cache) continue; + + if (i == 0) { + // Try with a color cache. + if (!CalculateBestCacheSize(argb, quality, refs_tmp, &cache_bits)) { + goto Error; + } + if (cache_bits > 0) { + if (!BackwardRefsWithLocalCache(argb, cache_bits, refs_tmp)) { + goto Error; + } + } + } + + if (i == 0 && do_no_cache && cache_bits == 0) { + // No need to re-compute bit_cost as it was computed at i == 1. + } else { + VP8LHistogramCreate(histo, refs_tmp, cache_bits); + bit_cost = VP8LHistogramEstimateBits(histo); + } + + if (bit_cost < bit_costs_best[i]) { + if (i == 1) { + // Do not swap as the full cache analysis would have the wrong + // VP8LBackwardRefs to start with. + if (!BackwardRefsClone(refs_tmp, &refs[1])) goto Error; + } else { + BackwardRefsSwap(refs_tmp, &refs[0]); + } + bit_costs_best[i] = bit_cost; + lz77_types_best[i] = lz77_type; + if (i == 0) *cache_bits_best = cache_bits; + } + } + } + assert(lz77_types_best[0] > 0); + assert(!do_no_cache || lz77_types_best[1] > 0); + + // Improve on simple LZ77 but only for high quality (TraceBackwards is + // costly). + for (i = 1; i >= 0; --i) { + if (i == 1 && !do_no_cache) continue; + if ((lz77_types_best[i] == kLZ77Standard || + lz77_types_best[i] == kLZ77Box) && + quality >= 25) { + const VP8LHashChain* const hash_chain_tmp = + (lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box; + const int cache_bits = (i == 1) ? 0 : *cache_bits_best; + float bit_cost_trace; + if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits, + hash_chain_tmp, &refs[i], + refs_tmp)) { + goto Error; + } + VP8LHistogramCreate(histo, refs_tmp, cache_bits); + bit_cost_trace = VP8LHistogramEstimateBits(histo); + if (bit_cost_trace < bit_costs_best[i]) { + BackwardRefsSwap(refs_tmp, &refs[i]); + } + } + + BackwardReferences2DLocality(width, &refs[i]); + + if (i == 1 && lz77_types_best[0] == lz77_types_best[1] && + *cache_bits_best == 0) { + // If the best cache size is 0 and we have the same best LZ77, just copy + // the data over and stop here. + if (!BackwardRefsClone(&refs[1], &refs[0])) goto Error; + break; + } + } + status = 1; + + Error: + VP8LHashChainClear(&hash_chain_box); + VP8LFreeHistogram(histo); + return status; +} + +int VP8LGetBackwardReferences( + int width, int height, const uint32_t* const argb, int quality, + int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache, + const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs, + int* const cache_bits_best, const WebPPicture* const pic, int percent_range, + int* const percent) { + if (low_effort) { + VP8LBackwardRefs* refs_best; + *cache_bits_best = cache_bits_max; + refs_best = GetBackwardReferencesLowEffort( + width, height, argb, cache_bits_best, hash_chain, refs); + if (refs_best == NULL) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + // Set it in first position. + BackwardRefsSwap(refs_best, &refs[0]); + } else { + if (!GetBackwardReferences(width, height, argb, quality, lz77_types_to_try, + cache_bits_max, do_no_cache, hash_chain, refs, + cache_bits_best)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + } + + return WebPReportProgress(pic, *percent + percent_range, percent); +} diff --git a/libraries/webp/src/enc/backward_references_enc.h b/libraries/webp/src/enc/backward_references_enc.h new file mode 100644 index 00000000000..26a6e85e2fd --- /dev/null +++ b/libraries/webp/src/enc/backward_references_enc.h @@ -0,0 +1,244 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// + +#ifndef WEBP_ENC_BACKWARD_REFERENCES_ENC_H_ +#define WEBP_ENC_BACKWARD_REFERENCES_ENC_H_ + +#include +#include +#include "include/webp/types.h" +#include "include/webp/encode.h" +#include "include/webp/format_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// The maximum allowed limit is 11. +#define MAX_COLOR_CACHE_BITS 10 + +// ----------------------------------------------------------------------------- +// PixOrCopy + +enum Mode { + kLiteral, + kCacheIdx, + kCopy, + kNone +}; + +typedef struct { + // mode as uint8_t to make the memory layout to be exactly 8 bytes. + uint8_t mode; + uint16_t len; + uint32_t argb_or_distance; +} PixOrCopy; + +static WEBP_INLINE PixOrCopy PixOrCopyCreateCopy(uint32_t distance, + uint16_t len) { + PixOrCopy retval; + retval.mode = kCopy; + retval.argb_or_distance = distance; + retval.len = len; + return retval; +} + +static WEBP_INLINE PixOrCopy PixOrCopyCreateCacheIdx(int idx) { + PixOrCopy retval; + assert(idx >= 0); + assert(idx < (1 << MAX_COLOR_CACHE_BITS)); + retval.mode = kCacheIdx; + retval.argb_or_distance = idx; + retval.len = 1; + return retval; +} + +static WEBP_INLINE PixOrCopy PixOrCopyCreateLiteral(uint32_t argb) { + PixOrCopy retval; + retval.mode = kLiteral; + retval.argb_or_distance = argb; + retval.len = 1; + return retval; +} + +static WEBP_INLINE int PixOrCopyIsLiteral(const PixOrCopy* const p) { + return (p->mode == kLiteral); +} + +static WEBP_INLINE int PixOrCopyIsCacheIdx(const PixOrCopy* const p) { + return (p->mode == kCacheIdx); +} + +static WEBP_INLINE int PixOrCopyIsCopy(const PixOrCopy* const p) { + return (p->mode == kCopy); +} + +static WEBP_INLINE uint32_t PixOrCopyLiteral(const PixOrCopy* const p, + int component) { + assert(p->mode == kLiteral); + return (p->argb_or_distance >> (component * 8)) & 0xff; +} + +static WEBP_INLINE uint32_t PixOrCopyLength(const PixOrCopy* const p) { + return p->len; +} + +static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) { + assert(p->mode == kCacheIdx); + assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS)); + return p->argb_or_distance; +} + +static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) { + assert(p->mode == kCopy); + return p->argb_or_distance; +} + +// ----------------------------------------------------------------------------- +// VP8LHashChain + +#define HASH_BITS 18 +#define HASH_SIZE (1 << HASH_BITS) + +// If you change this, you need MAX_LENGTH_BITS + WINDOW_SIZE_BITS <= 32 as it +// is used in VP8LHashChain. +#define MAX_LENGTH_BITS 12 +#define WINDOW_SIZE_BITS 20 +// We want the max value to be attainable and stored in MAX_LENGTH_BITS bits. +#define MAX_LENGTH ((1 << MAX_LENGTH_BITS) - 1) +#if MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32 +#error "MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32" +#endif + +typedef struct VP8LHashChain VP8LHashChain; +struct VP8LHashChain { + // The 20 most significant bits contain the offset at which the best match + // is found. These 20 bits are the limit defined by GetWindowSizeForHashChain + // (through WINDOW_SIZE = 1<<20). + // The lower 12 bits contain the length of the match. The 12 bit limit is + // defined in MaxFindCopyLength with MAX_LENGTH=4096. + uint32_t* offset_length_; + // This is the maximum size of the hash_chain that can be constructed. + // Typically this is the pixel count (width x height) for a given image. + int size_; +}; + +// Must be called first, to set size. +int VP8LHashChainInit(VP8LHashChain* const p, int size); +// Pre-compute the best matches for argb. pic and percent are for progress. +int VP8LHashChainFill(VP8LHashChain* const p, int quality, + const uint32_t* const argb, int xsize, int ysize, + int low_effort, const WebPPicture* const pic, + int percent_range, int* const percent); +void VP8LHashChainClear(VP8LHashChain* const p); // release memory + +static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p, + const int base_position) { + return p->offset_length_[base_position] >> MAX_LENGTH_BITS; +} + +static WEBP_INLINE int VP8LHashChainFindLength(const VP8LHashChain* const p, + const int base_position) { + return p->offset_length_[base_position] & ((1U << MAX_LENGTH_BITS) - 1); +} + +static WEBP_INLINE void VP8LHashChainFindCopy(const VP8LHashChain* const p, + int base_position, + int* const offset_ptr, + int* const length_ptr) { + *offset_ptr = VP8LHashChainFindOffset(p, base_position); + *length_ptr = VP8LHashChainFindLength(p, base_position); +} + +// ----------------------------------------------------------------------------- +// VP8LBackwardRefs (block-based backward-references storage) + +// maximum number of reference blocks the image will be segmented into +#define MAX_REFS_BLOCK_PER_IMAGE 16 + +typedef struct PixOrCopyBlock PixOrCopyBlock; // forward declaration +typedef struct VP8LBackwardRefs VP8LBackwardRefs; + +// Container for blocks chain +struct VP8LBackwardRefs { + int block_size_; // common block-size + int error_; // set to true if some memory error occurred + PixOrCopyBlock* refs_; // list of currently used blocks + PixOrCopyBlock** tail_; // for list recycling + PixOrCopyBlock* free_blocks_; // free-list + PixOrCopyBlock* last_block_; // used for adding new refs (internal) +}; + +// Initialize the object. 'block_size' is the common block size to store +// references (typically, width * height / MAX_REFS_BLOCK_PER_IMAGE). +void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size); +// Release memory for backward references. +void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs); + +// Cursor for iterating on references content +typedef struct { + // public: + PixOrCopy* cur_pos; // current position + // private: + PixOrCopyBlock* cur_block_; // current block in the refs list + const PixOrCopy* last_pos_; // sentinel for switching to next block +} VP8LRefsCursor; + +// Returns a cursor positioned at the beginning of the references list. +VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs); +// Returns true if cursor is pointing at a valid position. +static WEBP_INLINE int VP8LRefsCursorOk(const VP8LRefsCursor* const c) { + return (c->cur_pos != NULL); +} +// Move to next block of references. Internal, not to be called directly. +void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c); +// Move to next position, or NULL. Should not be called if !VP8LRefsCursorOk(). +static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) { + assert(c != NULL); + assert(VP8LRefsCursorOk(c)); + if (++c->cur_pos == c->last_pos_) VP8LRefsCursorNextBlock(c); +} + +// ----------------------------------------------------------------------------- +// Main entry points + +enum VP8LLZ77Type { + kLZ77Standard = 1, + kLZ77RLE = 2, + kLZ77Box = 4 +}; + +// Evaluates best possible backward references for specified quality. +// The input cache_bits to 'VP8LGetBackwardReferences' sets the maximum cache +// bits to use (passing 0 implies disabling the local color cache). +// The optimal cache bits is evaluated and set for the *cache_bits_best +// parameter with the matching refs_best. +// If do_no_cache == 0, refs is an array of 2 values and the best +// VP8LBackwardRefs is put in the first element. +// If do_no_cache != 0, refs is an array of 3 values and the best +// VP8LBackwardRefs is put in the first element, the best value with no-cache in +// the second element. +// In both cases, the last element is used as temporary internally. +// pic and percent are for progress. +// Returns false in case of error (stored in pic->error_code). +int VP8LGetBackwardReferences( + int width, int height, const uint32_t* const argb, int quality, + int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache, + const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs, + int* const cache_bits_best, const WebPPicture* const pic, int percent_range, + int* const percent); + +#ifdef __cplusplus +} +#endif + +#endif // WEBP_ENC_BACKWARD_REFERENCES_ENC_H_ diff --git a/libraries/webp/src/enc/config_enc.c b/libraries/webp/src/enc/config_enc.c new file mode 100644 index 00000000000..d8a47a5f3ae --- /dev/null +++ b/libraries/webp/src/enc/config_enc.c @@ -0,0 +1,157 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Coding tools configuration +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include "include/webp/encode.h" + +//------------------------------------------------------------------------------ +// WebPConfig +//------------------------------------------------------------------------------ + +int WebPConfigInitInternal(WebPConfig* config, + WebPPreset preset, float quality, int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) { + return 0; // caller/system version mismatch! + } + if (config == NULL) return 0; + + config->quality = quality; + config->target_size = 0; + config->target_PSNR = 0.; + config->method = 4; + config->sns_strength = 50; + config->filter_strength = 60; // mid-filtering + config->filter_sharpness = 0; + config->filter_type = 1; // default: strong (so U/V is filtered too) + config->partitions = 0; + config->segments = 4; + config->pass = 1; + config->qmin = 0; + config->qmax = 100; + config->show_compressed = 0; + config->preprocessing = 0; + config->autofilter = 0; + config->partition_limit = 0; + config->alpha_compression = 1; + config->alpha_filtering = 1; + config->alpha_quality = 100; + config->lossless = 0; + config->exact = 0; + config->image_hint = WEBP_HINT_DEFAULT; + config->emulate_jpeg_size = 0; + config->thread_level = 0; + config->low_memory = 0; + config->near_lossless = 100; + config->use_delta_palette = 0; + config->use_sharp_yuv = 0; + + // TODO(skal): tune. + switch (preset) { + case WEBP_PRESET_PICTURE: + config->sns_strength = 80; + config->filter_sharpness = 4; + config->filter_strength = 35; + config->preprocessing &= ~2; // no dithering + break; + case WEBP_PRESET_PHOTO: + config->sns_strength = 80; + config->filter_sharpness = 3; + config->filter_strength = 30; + config->preprocessing |= 2; + break; + case WEBP_PRESET_DRAWING: + config->sns_strength = 25; + config->filter_sharpness = 6; + config->filter_strength = 10; + break; + case WEBP_PRESET_ICON: + config->sns_strength = 0; + config->filter_strength = 0; // disable filtering to retain sharpness + config->preprocessing &= ~2; // no dithering + break; + case WEBP_PRESET_TEXT: + config->sns_strength = 0; + config->filter_strength = 0; // disable filtering to retain sharpness + config->preprocessing &= ~2; // no dithering + config->segments = 2; + break; + case WEBP_PRESET_DEFAULT: + default: + break; + } + return WebPValidateConfig(config); +} + +int WebPValidateConfig(const WebPConfig* config) { + if (config == NULL) return 0; + if (config->quality < 0 || config->quality > 100) return 0; + if (config->target_size < 0) return 0; + if (config->target_PSNR < 0) return 0; + if (config->method < 0 || config->method > 6) return 0; + if (config->segments < 1 || config->segments > 4) return 0; + if (config->sns_strength < 0 || config->sns_strength > 100) return 0; + if (config->filter_strength < 0 || config->filter_strength > 100) return 0; + if (config->filter_sharpness < 0 || config->filter_sharpness > 7) return 0; + if (config->filter_type < 0 || config->filter_type > 1) return 0; + if (config->autofilter < 0 || config->autofilter > 1) return 0; + if (config->pass < 1 || config->pass > 10) return 0; + if (config->qmin < 0 || config->qmax > 100 || config->qmin > config->qmax) { + return 0; + } + if (config->show_compressed < 0 || config->show_compressed > 1) return 0; + if (config->preprocessing < 0 || config->preprocessing > 7) return 0; + if (config->partitions < 0 || config->partitions > 3) return 0; + if (config->partition_limit < 0 || config->partition_limit > 100) return 0; + if (config->alpha_compression < 0) return 0; + if (config->alpha_filtering < 0) return 0; + if (config->alpha_quality < 0 || config->alpha_quality > 100) return 0; + if (config->lossless < 0 || config->lossless > 1) return 0; + if (config->near_lossless < 0 || config->near_lossless > 100) return 0; + if (config->image_hint >= WEBP_HINT_LAST) return 0; + if (config->emulate_jpeg_size < 0 || config->emulate_jpeg_size > 1) return 0; + if (config->thread_level < 0 || config->thread_level > 1) return 0; + if (config->low_memory < 0 || config->low_memory > 1) return 0; + if (config->exact < 0 || config->exact > 1) return 0; + if (config->use_delta_palette < 0 || config->use_delta_palette > 1) { + return 0; + } + if (config->use_sharp_yuv < 0 || config->use_sharp_yuv > 1) return 0; + + return 1; +} + +//------------------------------------------------------------------------------ + +#define MAX_LEVEL 9 + +// Mapping between -z level and -m / -q parameter settings. +static const struct { + uint8_t method_; + uint8_t quality_; +} kLosslessPresets[MAX_LEVEL + 1] = { + { 0, 0 }, { 1, 20 }, { 2, 25 }, { 3, 30 }, { 3, 50 }, + { 4, 50 }, { 4, 75 }, { 4, 90 }, { 5, 90 }, { 6, 100 } +}; + +int WebPConfigLosslessPreset(WebPConfig* config, int level) { + if (config == NULL || level < 0 || level > MAX_LEVEL) return 0; + config->lossless = 1; + config->method = kLosslessPresets[level].method_; + config->quality = kLosslessPresets[level].quality_; + return 1; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/enc/cost_enc.c b/libraries/webp/src/enc/cost_enc.c new file mode 100644 index 00000000000..48fd9bc3475 --- /dev/null +++ b/libraries/webp/src/enc/cost_enc.c @@ -0,0 +1,342 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Cost tables for level and modes +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/enc/cost_enc.h" + +//------------------------------------------------------------------------------ +// Level cost tables + +// For each given level, the following table gives the pattern of contexts to +// use for coding it (in [][0]) as well as the bit value to use for each +// context (in [][1]). +const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = { + {0x001, 0x000}, {0x007, 0x001}, {0x00f, 0x005}, + {0x00f, 0x00d}, {0x033, 0x003}, {0x033, 0x003}, {0x033, 0x023}, + {0x033, 0x023}, {0x033, 0x023}, {0x033, 0x023}, {0x0d3, 0x013}, + {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, + {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x093}, + {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, + {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, + {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, + {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x153} +}; + +static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) { + int pattern = VP8LevelCodes[level - 1][0]; + int bits = VP8LevelCodes[level - 1][1]; + int cost = 0; + int i; + for (i = 2; pattern; ++i) { + if (pattern & 1) { + cost += VP8BitCost(bits & 1, probas[i]); + } + bits >>= 1; + pattern >>= 1; + } + return cost; +} + +//------------------------------------------------------------------------------ +// Pre-calc level costs once for all + +void VP8CalculateLevelCosts(VP8EncProba* const proba) { + int ctype, band, ctx; + + if (!proba->dirty_) return; // nothing to do. + + for (ctype = 0; ctype < NUM_TYPES; ++ctype) { + int n; + for (band = 0; band < NUM_BANDS; ++band) { + for (ctx = 0; ctx < NUM_CTX; ++ctx) { + const uint8_t* const p = proba->coeffs_[ctype][band][ctx]; + uint16_t* const table = proba->level_cost_[ctype][band][ctx]; + const int cost0 = (ctx > 0) ? VP8BitCost(1, p[0]) : 0; + const int cost_base = VP8BitCost(1, p[1]) + cost0; + int v; + table[0] = VP8BitCost(0, p[1]) + cost0; + for (v = 1; v <= MAX_VARIABLE_LEVEL; ++v) { + table[v] = cost_base + VariableLevelCost(v, p); + } + // Starting at level 67 and up, the variable part of the cost is + // actually constant. + } + } + for (n = 0; n < 16; ++n) { // replicate bands. We don't need to sentinel. + for (ctx = 0; ctx < NUM_CTX; ++ctx) { + proba->remapped_costs_[ctype][n][ctx] = + proba->level_cost_[ctype][VP8EncBands[n]][ctx]; + } + } + } + proba->dirty_ = 0; +} + +//------------------------------------------------------------------------------ +// Mode cost tables. + +// These are the fixed probabilities (in the coding trees) turned into bit-cost +// by calling VP8BitCost(). +const uint16_t VP8FixedCostsUV[4] = { 302, 984, 439, 642 }; +// note: these values include the fixed VP8BitCost(1, 145) mode selection cost. +const uint16_t VP8FixedCostsI16[4] = { 663, 919, 872, 919 }; +const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES] = { + { { 40, 1151, 1723, 1874, 2103, 2019, 1628, 1777, 2226, 2137 }, + { 192, 469, 1296, 1308, 1849, 1794, 1781, 1703, 1713, 1522 }, + { 142, 910, 762, 1684, 1849, 1576, 1460, 1305, 1801, 1657 }, + { 559, 641, 1370, 421, 1182, 1569, 1612, 1725, 863, 1007 }, + { 299, 1059, 1256, 1108, 636, 1068, 1581, 1883, 869, 1142 }, + { 277, 1111, 707, 1362, 1089, 672, 1603, 1541, 1545, 1291 }, + { 214, 781, 1609, 1303, 1632, 2229, 726, 1560, 1713, 918 }, + { 152, 1037, 1046, 1759, 1983, 2174, 1358, 742, 1740, 1390 }, + { 512, 1046, 1420, 753, 752, 1297, 1486, 1613, 460, 1207 }, + { 424, 827, 1362, 719, 1462, 1202, 1199, 1476, 1199, 538 } }, + { { 240, 402, 1134, 1491, 1659, 1505, 1517, 1555, 1979, 2099 }, + { 467, 242, 960, 1232, 1714, 1620, 1834, 1570, 1676, 1391 }, + { 500, 455, 463, 1507, 1699, 1282, 1564, 982, 2114, 2114 }, + { 672, 643, 1372, 331, 1589, 1667, 1453, 1938, 996, 876 }, + { 458, 783, 1037, 911, 738, 968, 1165, 1518, 859, 1033 }, + { 504, 815, 504, 1139, 1219, 719, 1506, 1085, 1268, 1268 }, + { 333, 630, 1445, 1239, 1883, 3672, 799, 1548, 1865, 598 }, + { 399, 644, 746, 1342, 1856, 1350, 1493, 613, 1855, 1015 }, + { 622, 749, 1205, 608, 1066, 1408, 1290, 1406, 546, 971 }, + { 500, 753, 1041, 668, 1230, 1617, 1297, 1425, 1383, 523 } }, + { { 394, 553, 523, 1502, 1536, 981, 1608, 1142, 1666, 2181 }, + { 655, 430, 375, 1411, 1861, 1220, 1677, 1135, 1978, 1553 }, + { 690, 640, 245, 1954, 2070, 1194, 1528, 982, 1972, 2232 }, + { 559, 834, 741, 867, 1131, 980, 1225, 852, 1092, 784 }, + { 690, 875, 516, 959, 673, 894, 1056, 1190, 1528, 1126 }, + { 740, 951, 384, 1277, 1177, 492, 1579, 1155, 1846, 1513 }, + { 323, 775, 1062, 1776, 3062, 1274, 813, 1188, 1372, 655 }, + { 488, 971, 484, 1767, 1515, 1775, 1115, 503, 1539, 1461 }, + { 740, 1006, 998, 709, 851, 1230, 1337, 788, 741, 721 }, + { 522, 1073, 573, 1045, 1346, 887, 1046, 1146, 1203, 697 } }, + { { 105, 864, 1442, 1009, 1934, 1840, 1519, 1920, 1673, 1579 }, + { 534, 305, 1193, 683, 1388, 2164, 1802, 1894, 1264, 1170 }, + { 305, 518, 877, 1108, 1426, 3215, 1425, 1064, 1320, 1242 }, + { 683, 732, 1927, 257, 1493, 2048, 1858, 1552, 1055, 947 }, + { 394, 814, 1024, 660, 959, 1556, 1282, 1289, 893, 1047 }, + { 528, 615, 996, 940, 1201, 635, 1094, 2515, 803, 1358 }, + { 347, 614, 1609, 1187, 3133, 1345, 1007, 1339, 1017, 667 }, + { 218, 740, 878, 1605, 3650, 3650, 1345, 758, 1357, 1617 }, + { 672, 750, 1541, 558, 1257, 1599, 1870, 2135, 402, 1087 }, + { 592, 684, 1161, 430, 1092, 1497, 1475, 1489, 1095, 822 } }, + { { 228, 1056, 1059, 1368, 752, 982, 1512, 1518, 987, 1782 }, + { 494, 514, 818, 942, 965, 892, 1610, 1356, 1048, 1363 }, + { 512, 648, 591, 1042, 761, 991, 1196, 1454, 1309, 1463 }, + { 683, 749, 1043, 676, 841, 1396, 1133, 1138, 654, 939 }, + { 622, 1101, 1126, 994, 361, 1077, 1203, 1318, 877, 1219 }, + { 631, 1068, 857, 1650, 651, 477, 1650, 1419, 828, 1170 }, + { 555, 727, 1068, 1335, 3127, 1339, 820, 1331, 1077, 429 }, + { 504, 879, 624, 1398, 889, 889, 1392, 808, 891, 1406 }, + { 683, 1602, 1289, 977, 578, 983, 1280, 1708, 406, 1122 }, + { 399, 865, 1433, 1070, 1072, 764, 968, 1477, 1223, 678 } }, + { { 333, 760, 935, 1638, 1010, 529, 1646, 1410, 1472, 2219 }, + { 512, 494, 750, 1160, 1215, 610, 1870, 1868, 1628, 1169 }, + { 572, 646, 492, 1934, 1208, 603, 1580, 1099, 1398, 1995 }, + { 786, 789, 942, 581, 1018, 951, 1599, 1207, 731, 768 }, + { 690, 1015, 672, 1078, 582, 504, 1693, 1438, 1108, 2897 }, + { 768, 1267, 571, 2005, 1243, 244, 2881, 1380, 1786, 1453 }, + { 452, 899, 1293, 903, 1311, 3100, 465, 1311, 1319, 813 }, + { 394, 927, 942, 1103, 1358, 1104, 946, 593, 1363, 1109 }, + { 559, 1005, 1007, 1016, 658, 1173, 1021, 1164, 623, 1028 }, + { 564, 796, 632, 1005, 1014, 863, 2316, 1268, 938, 764 } }, + { { 266, 606, 1098, 1228, 1497, 1243, 948, 1030, 1734, 1461 }, + { 366, 585, 901, 1060, 1407, 1247, 876, 1134, 1620, 1054 }, + { 452, 565, 542, 1729, 1479, 1479, 1016, 886, 2938, 1150 }, + { 555, 1088, 1533, 950, 1354, 895, 834, 1019, 1021, 496 }, + { 704, 815, 1193, 971, 973, 640, 1217, 2214, 832, 578 }, + { 672, 1245, 579, 871, 875, 774, 872, 1273, 1027, 949 }, + { 296, 1134, 2050, 1784, 1636, 3425, 442, 1550, 2076, 722 }, + { 342, 982, 1259, 1846, 1848, 1848, 622, 568, 1847, 1052 }, + { 555, 1064, 1304, 828, 746, 1343, 1075, 1329, 1078, 494 }, + { 288, 1167, 1285, 1174, 1639, 1639, 833, 2254, 1304, 509 } }, + { { 342, 719, 767, 1866, 1757, 1270, 1246, 550, 1746, 2151 }, + { 483, 653, 694, 1509, 1459, 1410, 1218, 507, 1914, 1266 }, + { 488, 757, 447, 2979, 1813, 1268, 1654, 539, 1849, 2109 }, + { 522, 1097, 1085, 851, 1365, 1111, 851, 901, 961, 605 }, + { 709, 716, 841, 728, 736, 945, 941, 862, 2845, 1057 }, + { 512, 1323, 500, 1336, 1083, 681, 1342, 717, 1604, 1350 }, + { 452, 1155, 1372, 1900, 1501, 3290, 311, 944, 1919, 922 }, + { 403, 1520, 977, 2132, 1733, 3522, 1076, 276, 3335, 1547 }, + { 559, 1374, 1101, 615, 673, 2462, 974, 795, 984, 984 }, + { 547, 1122, 1062, 812, 1410, 951, 1140, 622, 1268, 651 } }, + { { 165, 982, 1235, 938, 1334, 1366, 1659, 1578, 964, 1612 }, + { 592, 422, 925, 847, 1139, 1112, 1387, 2036, 861, 1041 }, + { 403, 837, 732, 770, 941, 1658, 1250, 809, 1407, 1407 }, + { 896, 874, 1071, 381, 1568, 1722, 1437, 2192, 480, 1035 }, + { 640, 1098, 1012, 1032, 684, 1382, 1581, 2106, 416, 865 }, + { 559, 1005, 819, 914, 710, 770, 1418, 920, 838, 1435 }, + { 415, 1258, 1245, 870, 1278, 3067, 770, 1021, 1287, 522 }, + { 406, 990, 601, 1009, 1265, 1265, 1267, 759, 1017, 1277 }, + { 968, 1182, 1329, 788, 1032, 1292, 1705, 1714, 203, 1403 }, + { 732, 877, 1279, 471, 901, 1161, 1545, 1294, 755, 755 } }, + { { 111, 931, 1378, 1185, 1933, 1648, 1148, 1714, 1873, 1307 }, + { 406, 414, 1030, 1023, 1910, 1404, 1313, 1647, 1509, 793 }, + { 342, 640, 575, 1088, 1241, 1349, 1161, 1350, 1756, 1502 }, + { 559, 766, 1185, 357, 1682, 1428, 1329, 1897, 1219, 802 }, + { 473, 909, 1164, 771, 719, 2508, 1427, 1432, 722, 782 }, + { 342, 892, 785, 1145, 1150, 794, 1296, 1550, 973, 1057 }, + { 208, 1036, 1326, 1343, 1606, 3395, 815, 1455, 1618, 712 }, + { 228, 928, 890, 1046, 3499, 1711, 994, 829, 1720, 1318 }, + { 768, 724, 1058, 636, 991, 1075, 1319, 1324, 616, 825 }, + { 305, 1167, 1358, 899, 1587, 1587, 987, 1988, 1332, 501 } } +}; + +//------------------------------------------------------------------------------ +// helper functions for residuals struct VP8Residual. + +void VP8InitResidual(int first, int coeff_type, + VP8Encoder* const enc, VP8Residual* const res) { + res->coeff_type = coeff_type; + res->prob = enc->proba_.coeffs_[coeff_type]; + res->stats = enc->proba_.stats_[coeff_type]; + res->costs = enc->proba_.remapped_costs_[coeff_type]; + res->first = first; +} + +//------------------------------------------------------------------------------ +// Mode costs + +int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) { + const int x = (it->i4_ & 3), y = (it->i4_ >> 2); + VP8Residual res; + VP8Encoder* const enc = it->enc_; + int R = 0; + int ctx; + + VP8InitResidual(0, 3, enc, &res); + ctx = it->top_nz_[x] + it->left_nz_[y]; + VP8SetResidualCoeffs(levels, &res); + R += VP8GetResidualCost(ctx, &res); + return R; +} + +int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) { + VP8Residual res; + VP8Encoder* const enc = it->enc_; + int x, y; + int R = 0; + + VP8IteratorNzToBytes(it); // re-import the non-zero context + + // DC + VP8InitResidual(0, 1, enc, &res); + VP8SetResidualCoeffs(rd->y_dc_levels, &res); + R += VP8GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res); + + // AC + VP8InitResidual(1, 0, enc, &res); + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); + R += VP8GetResidualCost(ctx, &res); + it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0); + } + } + return R; +} + +int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) { + VP8Residual res; + VP8Encoder* const enc = it->enc_; + int ch, x, y; + int R = 0; + + VP8IteratorNzToBytes(it); // re-import the non-zero context + + VP8InitResidual(0, 2, enc, &res); + for (ch = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); + R += VP8GetResidualCost(ctx, &res); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0); + } + } + } + return R; +} + + +//------------------------------------------------------------------------------ +// Recording of token probabilities. + +// We keep the table-free variant around for reference, in case. +#define USE_LEVEL_CODE_TABLE + +// Simulate block coding, but only record statistics. +// Note: no need to record the fixed probas. +int VP8RecordCoeffs(int ctx, const VP8Residual* const res) { + int n = res->first; + // should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1 + proba_t* s = res->stats[n][ctx]; + if (res->last < 0) { + VP8RecordStats(0, s + 0); + return 0; + } + while (n <= res->last) { + int v; + VP8RecordStats(1, s + 0); // order of record doesn't matter + while ((v = res->coeffs[n++]) == 0) { + VP8RecordStats(0, s + 1); + s = res->stats[VP8EncBands[n]][0]; + } + VP8RecordStats(1, s + 1); + if (!VP8RecordStats(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1 + s = res->stats[VP8EncBands[n]][1]; + } else { + v = abs(v); +#if !defined(USE_LEVEL_CODE_TABLE) + if (!VP8RecordStats(v > 4, s + 3)) { + if (VP8RecordStats(v != 2, s + 4)) + VP8RecordStats(v == 4, s + 5); + } else if (!VP8RecordStats(v > 10, s + 6)) { + VP8RecordStats(v > 6, s + 7); + } else if (!VP8RecordStats((v >= 3 + (8 << 2)), s + 8)) { + VP8RecordStats((v >= 3 + (8 << 1)), s + 9); + } else { + VP8RecordStats((v >= 3 + (8 << 3)), s + 10); + } +#else + if (v > MAX_VARIABLE_LEVEL) { + v = MAX_VARIABLE_LEVEL; + } + + { + const int bits = VP8LevelCodes[v - 1][1]; + int pattern = VP8LevelCodes[v - 1][0]; + int i; + for (i = 0; (pattern >>= 1) != 0; ++i) { + const int mask = 2 << i; + if (pattern & 1) VP8RecordStats(!!(bits & mask), s + 3 + i); + } + } +#endif + s = res->stats[VP8EncBands[n]][2]; + } + } + if (n < 16) VP8RecordStats(0, s + 0); + return 1; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/enc/cost_enc.h b/libraries/webp/src/enc/cost_enc.h new file mode 100644 index 00000000000..a4b177b3423 --- /dev/null +++ b/libraries/webp/src/enc/cost_enc.h @@ -0,0 +1,82 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Cost tables for level and modes. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_ENC_COST_ENC_H_ +#define WEBP_ENC_COST_ENC_H_ + +#include +#include +#include "src/enc/vp8i_enc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// On-the-fly info about the current set of residuals. Handy to avoid +// passing zillions of params. +typedef struct VP8Residual VP8Residual; +struct VP8Residual { + int first; + int last; + const int16_t* coeffs; + + int coeff_type; + ProbaArray* prob; + StatsArray* stats; + CostArrayPtr costs; +}; + +void VP8InitResidual(int first, int coeff_type, + VP8Encoder* const enc, VP8Residual* const res); + +int VP8RecordCoeffs(int ctx, const VP8Residual* const res); + +// Record proba context used. +static WEBP_INLINE int VP8RecordStats(int bit, proba_t* const stats) { + proba_t p = *stats; + // An overflow is inbound. Note we handle this at 0xfffe0000u instead of + // 0xffff0000u to make sure p + 1u does not overflow. + if (p >= 0xfffe0000u) { + p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2. + } + // record bit count (lower 16 bits) and increment total count (upper 16 bits). + p += 0x00010000u + bit; + *stats = p; + return bit; +} + +// Cost of coding one event with probability 'proba'. +static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) { + return !bit ? VP8EntropyCost[proba] : VP8EntropyCost[255 - proba]; +} + +// Level cost calculations +extern const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2]; +void VP8CalculateLevelCosts(VP8EncProba* const proba); +static WEBP_INLINE int VP8LevelCost(const uint16_t* const table, int level) { + return VP8LevelFixedCosts[level] + + table[(level > MAX_VARIABLE_LEVEL) ? MAX_VARIABLE_LEVEL : level]; +} + +// Mode costs +extern const uint16_t VP8FixedCostsUV[4]; +extern const uint16_t VP8FixedCostsI16[4]; +extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES]; + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_ENC_COST_ENC_H_ diff --git a/libraries/webp/src/enc/filter_enc.c b/libraries/webp/src/enc/filter_enc.c new file mode 100644 index 00000000000..580800bfb87 --- /dev/null +++ b/libraries/webp/src/enc/filter_enc.c @@ -0,0 +1,235 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Selecting filter level +// +// Author: somnath@google.com (Somnath Banerjee) + +#include +#include "src/enc/vp8i_enc.h" +#include "src/dsp/dsp.h" + +// This table gives, for a given sharpness, the filtering strength to be +// used (at least) in order to filter a given edge step delta. +// This is constructed by brute force inspection: for all delta, we iterate +// over all possible filtering strength / thresh until needs_filter() returns +// true. +#define MAX_DELTA_SIZE 64 +static const uint8_t kLevelsFromDelta[8][MAX_DELTA_SIZE] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }, + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 17, 18, + 20, 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, + 44, 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 19, + 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, + 44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, + 21, 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, + 45, 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20, + 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44, + 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, + { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 20, + 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44, + 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, + { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21, + 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, 45, + 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, + { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, + 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, + 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 } +}; + +int VP8FilterStrengthFromDelta(int sharpness, int delta) { + const int pos = (delta < MAX_DELTA_SIZE) ? delta : MAX_DELTA_SIZE - 1; + assert(sharpness >= 0 && sharpness <= 7); + return kLevelsFromDelta[sharpness][pos]; +} + +//------------------------------------------------------------------------------ +// Paragraph 15.4: compute the inner-edge filtering strength + +#if !defined(WEBP_REDUCE_SIZE) + +static int GetILevel(int sharpness, int level) { + if (sharpness > 0) { + if (sharpness > 4) { + level >>= 2; + } else { + level >>= 1; + } + if (level > 9 - sharpness) { + level = 9 - sharpness; + } + } + if (level < 1) level = 1; + return level; +} + +static void DoFilter(const VP8EncIterator* const it, int level) { + const VP8Encoder* const enc = it->enc_; + const int ilevel = GetILevel(enc->config_->filter_sharpness, level); + const int limit = 2 * level + ilevel; + + uint8_t* const y_dst = it->yuv_out2_ + Y_OFF_ENC; + uint8_t* const u_dst = it->yuv_out2_ + U_OFF_ENC; + uint8_t* const v_dst = it->yuv_out2_ + V_OFF_ENC; + + // copy current block to yuv_out2_ + memcpy(y_dst, it->yuv_out_, YUV_SIZE_ENC * sizeof(uint8_t)); + + if (enc->filter_hdr_.simple_ == 1) { // simple + VP8SimpleHFilter16i(y_dst, BPS, limit); + VP8SimpleVFilter16i(y_dst, BPS, limit); + } else { // complex + const int hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; + VP8HFilter16i(y_dst, BPS, limit, ilevel, hev_thresh); + VP8HFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh); + VP8VFilter16i(y_dst, BPS, limit, ilevel, hev_thresh); + VP8VFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh); + } +} + +//------------------------------------------------------------------------------ +// SSIM metric for one macroblock + +static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) { + int x, y; + double sum = 0.; + + // compute SSIM in a 10 x 10 window + for (y = VP8_SSIM_KERNEL; y < 16 - VP8_SSIM_KERNEL; y++) { + for (x = VP8_SSIM_KERNEL; x < 16 - VP8_SSIM_KERNEL; x++) { + sum += VP8SSIMGetClipped(yuv1 + Y_OFF_ENC, BPS, yuv2 + Y_OFF_ENC, BPS, + x, y, 16, 16); + } + } + for (x = 1; x < 7; x++) { + for (y = 1; y < 7; y++) { + sum += VP8SSIMGetClipped(yuv1 + U_OFF_ENC, BPS, yuv2 + U_OFF_ENC, BPS, + x, y, 8, 8); + sum += VP8SSIMGetClipped(yuv1 + V_OFF_ENC, BPS, yuv2 + V_OFF_ENC, BPS, + x, y, 8, 8); + } + } + return sum; +} + +#endif // !defined(WEBP_REDUCE_SIZE) + +//------------------------------------------------------------------------------ +// Exposed APIs: Encoder should call the following 3 functions to adjust +// loop filter strength + +void VP8InitFilter(VP8EncIterator* const it) { +#if !defined(WEBP_REDUCE_SIZE) + if (it->lf_stats_ != NULL) { + int s, i; + for (s = 0; s < NUM_MB_SEGMENTS; s++) { + for (i = 0; i < MAX_LF_LEVELS; i++) { + (*it->lf_stats_)[s][i] = 0; + } + } + VP8SSIMDspInit(); + } +#else + (void)it; +#endif +} + +void VP8StoreFilterStats(VP8EncIterator* const it) { +#if !defined(WEBP_REDUCE_SIZE) + int d; + VP8Encoder* const enc = it->enc_; + const int s = it->mb_->segment_; + const int level0 = enc->dqm_[s].fstrength_; + + // explore +/-quant range of values around level0 + const int delta_min = -enc->dqm_[s].quant_; + const int delta_max = enc->dqm_[s].quant_; + const int step_size = (delta_max - delta_min >= 4) ? 4 : 1; + + if (it->lf_stats_ == NULL) return; + + // NOTE: Currently we are applying filter only across the sublock edges + // There are two reasons for that. + // 1. Applying filter on macro block edges will change the pixels in + // the left and top macro blocks. That will be hard to restore + // 2. Macro Blocks on the bottom and right are not yet compressed. So we + // cannot apply filter on the right and bottom macro block edges. + if (it->mb_->type_ == 1 && it->mb_->skip_) return; + + // Always try filter level zero + (*it->lf_stats_)[s][0] += GetMBSSIM(it->yuv_in_, it->yuv_out_); + + for (d = delta_min; d <= delta_max; d += step_size) { + const int level = level0 + d; + if (level <= 0 || level >= MAX_LF_LEVELS) { + continue; + } + DoFilter(it, level); + (*it->lf_stats_)[s][level] += GetMBSSIM(it->yuv_in_, it->yuv_out2_); + } +#else // defined(WEBP_REDUCE_SIZE) + (void)it; +#endif // !defined(WEBP_REDUCE_SIZE) +} + +void VP8AdjustFilterStrength(VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; +#if !defined(WEBP_REDUCE_SIZE) + if (it->lf_stats_ != NULL) { + int s; + for (s = 0; s < NUM_MB_SEGMENTS; s++) { + int i, best_level = 0; + // Improvement over filter level 0 should be at least 1e-5 (relatively) + double best_v = 1.00001 * (*it->lf_stats_)[s][0]; + for (i = 1; i < MAX_LF_LEVELS; i++) { + const double v = (*it->lf_stats_)[s][i]; + if (v > best_v) { + best_v = v; + best_level = i; + } + } + enc->dqm_[s].fstrength_ = best_level; + } + return; + } +#endif // !defined(WEBP_REDUCE_SIZE) + if (enc->config_->filter_strength > 0) { + int max_level = 0; + int s; + for (s = 0; s < NUM_MB_SEGMENTS; s++) { + VP8SegmentInfo* const dqm = &enc->dqm_[s]; + // this '>> 3' accounts for some inverse WHT scaling + const int delta = (dqm->max_edge_ * dqm->y2_.q_[1]) >> 3; + const int level = + VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, delta); + if (level > dqm->fstrength_) { + dqm->fstrength_ = level; + } + if (max_level < dqm->fstrength_) { + max_level = dqm->fstrength_; + } + } + enc->filter_hdr_.level_ = max_level; + } +} + +// ----------------------------------------------------------------------------- diff --git a/libraries/webp/src/enc/frame_enc.c b/libraries/webp/src/enc/frame_enc.c new file mode 100644 index 00000000000..1712310a2bc --- /dev/null +++ b/libraries/webp/src/enc/frame_enc.c @@ -0,0 +1,905 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// frame coding and analysis +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include + +#include "src/enc/cost_enc.h" +#include "src/enc/vp8i_enc.h" +#include "src/dsp/dsp.h" +#include "include/webp/format_constants.h" // RIFF constants + +#define SEGMENT_VISU 0 +#define DEBUG_SEARCH 0 // useful to track search convergence + +//------------------------------------------------------------------------------ +// multi-pass convergence + +#define HEADER_SIZE_ESTIMATE (RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + \ + VP8_FRAME_HEADER_SIZE) +#define DQ_LIMIT 0.4 // convergence is considered reached if dq < DQ_LIMIT +// we allow 2k of extra head-room in PARTITION0 limit. +#define PARTITION0_SIZE_LIMIT ((VP8_MAX_PARTITION0_SIZE - 2048ULL) << 11) + +static float Clamp(float v, float min, float max) { + return (v < min) ? min : (v > max) ? max : v; +} + +typedef struct { // struct for organizing convergence in either size or PSNR + int is_first; + float dq; + float q, last_q; + float qmin, qmax; + double value, last_value; // PSNR or size + double target; + int do_size_search; +} PassStats; + +static int InitPassStats(const VP8Encoder* const enc, PassStats* const s) { + const uint64_t target_size = (uint64_t)enc->config_->target_size; + const int do_size_search = (target_size != 0); + const float target_PSNR = enc->config_->target_PSNR; + + s->is_first = 1; + s->dq = 10.f; + s->qmin = 1.f * enc->config_->qmin; + s->qmax = 1.f * enc->config_->qmax; + s->q = s->last_q = Clamp(enc->config_->quality, s->qmin, s->qmax); + s->target = do_size_search ? (double)target_size + : (target_PSNR > 0.) ? target_PSNR + : 40.; // default, just in case + s->value = s->last_value = 0.; + s->do_size_search = do_size_search; + return do_size_search; +} + +static float ComputeNextQ(PassStats* const s) { + float dq; + if (s->is_first) { + dq = (s->value > s->target) ? -s->dq : s->dq; + s->is_first = 0; + } else if (s->value != s->last_value) { + const double slope = (s->target - s->value) / (s->last_value - s->value); + dq = (float)(slope * (s->last_q - s->q)); + } else { + dq = 0.; // we're done?! + } + // Limit variable to avoid large swings. + s->dq = Clamp(dq, -30.f, 30.f); + s->last_q = s->q; + s->last_value = s->value; + s->q = Clamp(s->q + s->dq, s->qmin, s->qmax); + return s->q; +} + +//------------------------------------------------------------------------------ +// Tables for level coding + +const uint8_t VP8Cat3[] = { 173, 148, 140 }; +const uint8_t VP8Cat4[] = { 176, 155, 140, 135 }; +const uint8_t VP8Cat5[] = { 180, 157, 141, 134, 130 }; +const uint8_t VP8Cat6[] = + { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 }; + +//------------------------------------------------------------------------------ +// Reset the statistics about: number of skips, token proba, level cost,... + +static void ResetStats(VP8Encoder* const enc) { + VP8EncProba* const proba = &enc->proba_; + VP8CalculateLevelCosts(proba); + proba->nb_skip_ = 0; +} + +//------------------------------------------------------------------------------ +// Skip decision probability + +#define SKIP_PROBA_THRESHOLD 250 // value below which using skip_proba is OK. + +static int CalcSkipProba(uint64_t nb, uint64_t total) { + return (int)(total ? (total - nb) * 255 / total : 255); +} + +// Returns the bit-cost for coding the skip probability. +static int FinalizeSkipProba(VP8Encoder* const enc) { + VP8EncProba* const proba = &enc->proba_; + const int nb_mbs = enc->mb_w_ * enc->mb_h_; + const int nb_events = proba->nb_skip_; + int size; + proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); + proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD); + size = 256; // 'use_skip_proba' bit + if (proba->use_skip_proba_) { + size += nb_events * VP8BitCost(1, proba->skip_proba_) + + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); + size += 8 * 256; // cost of signaling the skip_proba_ itself. + } + return size; +} + +// Collect statistics and deduce probabilities for next coding pass. +// Return the total bit-cost for coding the probability updates. +static int CalcTokenProba(int nb, int total) { + assert(nb <= total); + return nb ? (255 - nb * 255 / total) : 255; +} + +// Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability. +static int BranchCost(int nb, int total, int proba) { + return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba); +} + +static void ResetTokenStats(VP8Encoder* const enc) { + VP8EncProba* const proba = &enc->proba_; + memset(proba->stats_, 0, sizeof(proba->stats_)); +} + +static int FinalizeTokenProbas(VP8EncProba* const proba) { + int has_changed = 0; + int size = 0; + int t, b, c, p; + for (t = 0; t < NUM_TYPES; ++t) { + for (b = 0; b < NUM_BANDS; ++b) { + for (c = 0; c < NUM_CTX; ++c) { + for (p = 0; p < NUM_PROBAS; ++p) { + const proba_t stats = proba->stats_[t][b][c][p]; + const int nb = (stats >> 0) & 0xffff; + const int total = (stats >> 16) & 0xffff; + const int update_proba = VP8CoeffsUpdateProba[t][b][c][p]; + const int old_p = VP8CoeffsProba0[t][b][c][p]; + const int new_p = CalcTokenProba(nb, total); + const int old_cost = BranchCost(nb, total, old_p) + + VP8BitCost(0, update_proba); + const int new_cost = BranchCost(nb, total, new_p) + + VP8BitCost(1, update_proba) + + 8 * 256; + const int use_new_p = (old_cost > new_cost); + size += VP8BitCost(use_new_p, update_proba); + if (use_new_p) { // only use proba that seem meaningful enough. + proba->coeffs_[t][b][c][p] = new_p; + has_changed |= (new_p != old_p); + size += 8 * 256; + } else { + proba->coeffs_[t][b][c][p] = old_p; + } + } + } + } + } + proba->dirty_ = has_changed; + return size; +} + +//------------------------------------------------------------------------------ +// Finalize Segment probability based on the coding tree + +static int GetProba(int a, int b) { + const int total = a + b; + return (total == 0) ? 255 // that's the default probability. + : (255 * a + total / 2) / total; // rounded proba +} + +static void ResetSegments(VP8Encoder* const enc) { + int n; + for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { + enc->mb_info_[n].segment_ = 0; + } +} + +static void SetSegmentProbas(VP8Encoder* const enc) { + int p[NUM_MB_SEGMENTS] = { 0 }; + int n; + + for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { + const VP8MBInfo* const mb = &enc->mb_info_[n]; + ++p[mb->segment_]; + } +#if !defined(WEBP_DISABLE_STATS) + if (enc->pic_->stats != NULL) { + for (n = 0; n < NUM_MB_SEGMENTS; ++n) { + enc->pic_->stats->segment_size[n] = p[n]; + } + } +#endif + if (enc->segment_hdr_.num_segments_ > 1) { + uint8_t* const probas = enc->proba_.segments_; + probas[0] = GetProba(p[0] + p[1], p[2] + p[3]); + probas[1] = GetProba(p[0], p[1]); + probas[2] = GetProba(p[2], p[3]); + + enc->segment_hdr_.update_map_ = + (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255); + if (!enc->segment_hdr_.update_map_) ResetSegments(enc); + enc->segment_hdr_.size_ = + p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) + + p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) + + p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) + + p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2])); + } else { + enc->segment_hdr_.update_map_ = 0; + enc->segment_hdr_.size_ = 0; + } +} + +//------------------------------------------------------------------------------ +// Coefficient coding + +static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) { + int n = res->first; + // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 + const uint8_t* p = res->prob[n][ctx]; + if (!VP8PutBit(bw, res->last >= 0, p[0])) { + return 0; + } + + while (n < 16) { + const int c = res->coeffs[n++]; + const int sign = c < 0; + int v = sign ? -c : c; + if (!VP8PutBit(bw, v != 0, p[1])) { + p = res->prob[VP8EncBands[n]][0]; + continue; + } + if (!VP8PutBit(bw, v > 1, p[2])) { + p = res->prob[VP8EncBands[n]][1]; + } else { + if (!VP8PutBit(bw, v > 4, p[3])) { + if (VP8PutBit(bw, v != 2, p[4])) { + VP8PutBit(bw, v == 4, p[5]); + } + } else if (!VP8PutBit(bw, v > 10, p[6])) { + if (!VP8PutBit(bw, v > 6, p[7])) { + VP8PutBit(bw, v == 6, 159); + } else { + VP8PutBit(bw, v >= 9, 165); + VP8PutBit(bw, !(v & 1), 145); + } + } else { + int mask; + const uint8_t* tab; + if (v < 3 + (8 << 1)) { // VP8Cat3 (3b) + VP8PutBit(bw, 0, p[8]); + VP8PutBit(bw, 0, p[9]); + v -= 3 + (8 << 0); + mask = 1 << 2; + tab = VP8Cat3; + } else if (v < 3 + (8 << 2)) { // VP8Cat4 (4b) + VP8PutBit(bw, 0, p[8]); + VP8PutBit(bw, 1, p[9]); + v -= 3 + (8 << 1); + mask = 1 << 3; + tab = VP8Cat4; + } else if (v < 3 + (8 << 3)) { // VP8Cat5 (5b) + VP8PutBit(bw, 1, p[8]); + VP8PutBit(bw, 0, p[10]); + v -= 3 + (8 << 2); + mask = 1 << 4; + tab = VP8Cat5; + } else { // VP8Cat6 (11b) + VP8PutBit(bw, 1, p[8]); + VP8PutBit(bw, 1, p[10]); + v -= 3 + (8 << 3); + mask = 1 << 10; + tab = VP8Cat6; + } + while (mask) { + VP8PutBit(bw, !!(v & mask), *tab++); + mask >>= 1; + } + } + p = res->prob[VP8EncBands[n]][2]; + } + VP8PutBitUniform(bw, sign); + if (n == 16 || !VP8PutBit(bw, n <= res->last, p[0])) { + return 1; // EOB + } + } + return 1; +} + +static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it, + const VP8ModeScore* const rd) { + int x, y, ch; + VP8Residual res; + uint64_t pos1, pos2, pos3; + const int i16 = (it->mb_->type_ == 1); + const int segment = it->mb_->segment_; + VP8Encoder* const enc = it->enc_; + + VP8IteratorNzToBytes(it); + + pos1 = VP8BitWriterPos(bw); + if (i16) { + VP8InitResidual(0, 1, enc, &res); + VP8SetResidualCoeffs(rd->y_dc_levels, &res); + it->top_nz_[8] = it->left_nz_[8] = + PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res); + VP8InitResidual(1, 0, enc, &res); + } else { + VP8InitResidual(0, 3, enc, &res); + } + + // luma-AC + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); + it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res); + } + } + pos2 = VP8BitWriterPos(bw); + + // U/V + VP8InitResidual(0, 2, enc, &res); + for (ch = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + PutCoeffs(bw, ctx, &res); + } + } + } + pos3 = VP8BitWriterPos(bw); + it->luma_bits_ = pos2 - pos1; + it->uv_bits_ = pos3 - pos2; + it->bit_count_[segment][i16] += it->luma_bits_; + it->bit_count_[segment][2] += it->uv_bits_; + VP8IteratorBytesToNz(it); +} + +// Same as CodeResiduals, but doesn't actually write anything. +// Instead, it just records the event distribution. +static void RecordResiduals(VP8EncIterator* const it, + const VP8ModeScore* const rd) { + int x, y, ch; + VP8Residual res; + VP8Encoder* const enc = it->enc_; + + VP8IteratorNzToBytes(it); + + if (it->mb_->type_ == 1) { // i16x16 + VP8InitResidual(0, 1, enc, &res); + VP8SetResidualCoeffs(rd->y_dc_levels, &res); + it->top_nz_[8] = it->left_nz_[8] = + VP8RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res); + VP8InitResidual(1, 0, enc, &res); + } else { + VP8InitResidual(0, 3, enc, &res); + } + + // luma-AC + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); + it->top_nz_[x] = it->left_nz_[y] = VP8RecordCoeffs(ctx, &res); + } + } + + // U/V + VP8InitResidual(0, 2, enc, &res); + for (ch = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + VP8RecordCoeffs(ctx, &res); + } + } + } + + VP8IteratorBytesToNz(it); +} + +//------------------------------------------------------------------------------ +// Token buffer + +#if !defined(DISABLE_TOKEN_BUFFER) + +static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd, + VP8TBuffer* const tokens) { + int x, y, ch; + VP8Residual res; + VP8Encoder* const enc = it->enc_; + + VP8IteratorNzToBytes(it); + if (it->mb_->type_ == 1) { // i16x16 + const int ctx = it->top_nz_[8] + it->left_nz_[8]; + VP8InitResidual(0, 1, enc, &res); + VP8SetResidualCoeffs(rd->y_dc_levels, &res); + it->top_nz_[8] = it->left_nz_[8] = + VP8RecordCoeffTokens(ctx, &res, tokens); + VP8InitResidual(1, 0, enc, &res); + } else { + VP8InitResidual(0, 3, enc, &res); + } + + // luma-AC + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); + it->top_nz_[x] = it->left_nz_[y] = + VP8RecordCoeffTokens(ctx, &res, tokens); + } + } + + // U/V + VP8InitResidual(0, 2, enc, &res); + for (ch = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + VP8RecordCoeffTokens(ctx, &res, tokens); + } + } + } + VP8IteratorBytesToNz(it); + return !tokens->error_; +} + +#endif // !DISABLE_TOKEN_BUFFER + +//------------------------------------------------------------------------------ +// ExtraInfo map / Debug function + +#if !defined(WEBP_DISABLE_STATS) + +#if SEGMENT_VISU +static void SetBlock(uint8_t* p, int value, int size) { + int y; + for (y = 0; y < size; ++y) { + memset(p, value, size); + p += BPS; + } +} +#endif + +static void ResetSSE(VP8Encoder* const enc) { + enc->sse_[0] = 0; + enc->sse_[1] = 0; + enc->sse_[2] = 0; + // Note: enc->sse_[3] is managed by alpha.c + enc->sse_count_ = 0; +} + +static void StoreSSE(const VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + const uint8_t* const in = it->yuv_in_; + const uint8_t* const out = it->yuv_out_; + // Note: not totally accurate at boundary. And doesn't include in-loop filter. + enc->sse_[0] += VP8SSE16x16(in + Y_OFF_ENC, out + Y_OFF_ENC); + enc->sse_[1] += VP8SSE8x8(in + U_OFF_ENC, out + U_OFF_ENC); + enc->sse_[2] += VP8SSE8x8(in + V_OFF_ENC, out + V_OFF_ENC); + enc->sse_count_ += 16 * 16; +} + +static void StoreSideInfo(const VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + const VP8MBInfo* const mb = it->mb_; + WebPPicture* const pic = enc->pic_; + + if (pic->stats != NULL) { + StoreSSE(it); + enc->block_count_[0] += (mb->type_ == 0); + enc->block_count_[1] += (mb->type_ == 1); + enc->block_count_[2] += (mb->skip_ != 0); + } + + if (pic->extra_info != NULL) { + uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_]; + switch (pic->extra_info_type) { + case 1: *info = mb->type_; break; + case 2: *info = mb->segment_; break; + case 3: *info = enc->dqm_[mb->segment_].quant_; break; + case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break; + case 5: *info = mb->uv_mode_; break; + case 6: { + const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); + *info = (b > 255) ? 255 : b; break; + } + case 7: *info = mb->alpha_; break; + default: *info = 0; break; + } + } +#if SEGMENT_VISU // visualize segments and prediction modes + SetBlock(it->yuv_out_ + Y_OFF_ENC, mb->segment_ * 64, 16); + SetBlock(it->yuv_out_ + U_OFF_ENC, it->preds_[0] * 64, 8); + SetBlock(it->yuv_out_ + V_OFF_ENC, mb->uv_mode_ * 64, 8); +#endif +} + +static void ResetSideInfo(const VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + WebPPicture* const pic = enc->pic_; + if (pic->stats != NULL) { + memset(enc->block_count_, 0, sizeof(enc->block_count_)); + } + ResetSSE(enc); +} +#else // defined(WEBP_DISABLE_STATS) +static void ResetSSE(VP8Encoder* const enc) { + (void)enc; +} +static void StoreSideInfo(const VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + WebPPicture* const pic = enc->pic_; + if (pic->extra_info != NULL) { + if (it->x_ == 0 && it->y_ == 0) { // only do it once, at start + memset(pic->extra_info, 0, + enc->mb_w_ * enc->mb_h_ * sizeof(*pic->extra_info)); + } + } +} + +static void ResetSideInfo(const VP8EncIterator* const it) { + (void)it; +} +#endif // !defined(WEBP_DISABLE_STATS) + +static double GetPSNR(uint64_t mse, uint64_t size) { + return (mse > 0 && size > 0) ? 10. * log10(255. * 255. * size / mse) : 99; +} + +//------------------------------------------------------------------------------ +// StatLoop(): only collect statistics (number of skips, token usage, ...). +// This is used for deciding optimal probabilities. It also modifies the +// quantizer value if some target (size, PSNR) was specified. + +static void SetLoopParams(VP8Encoder* const enc, float q) { + // Make sure the quality parameter is inside valid bounds + q = Clamp(q, 0.f, 100.f); + + VP8SetSegmentParams(enc, q); // setup segment quantizations and filters + SetSegmentProbas(enc); // compute segment probabilities + + ResetStats(enc); + ResetSSE(enc); +} + +static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt, + int nb_mbs, int percent_delta, + PassStats* const s) { + VP8EncIterator it; + uint64_t size = 0; + uint64_t size_p0 = 0; + uint64_t distortion = 0; + const uint64_t pixel_count = (uint64_t)nb_mbs * 384; + + VP8IteratorInit(enc, &it); + SetLoopParams(enc, s->q); + do { + VP8ModeScore info; + VP8IteratorImport(&it, NULL); + if (VP8Decimate(&it, &info, rd_opt)) { + // Just record the number of skips and act like skip_proba is not used. + ++enc->proba_.nb_skip_; + } + RecordResiduals(&it, &info); + size += info.R + info.H; + size_p0 += info.H; + distortion += info.D; + if (percent_delta && !VP8IteratorProgress(&it, percent_delta)) { + return 0; + } + VP8IteratorSaveBoundary(&it); + } while (VP8IteratorNext(&it) && --nb_mbs > 0); + + size_p0 += enc->segment_hdr_.size_; + if (s->do_size_search) { + size += FinalizeSkipProba(enc); + size += FinalizeTokenProbas(&enc->proba_); + size = ((size + size_p0 + 1024) >> 11) + HEADER_SIZE_ESTIMATE; + s->value = (double)size; + } else { + s->value = GetPSNR(distortion, pixel_count); + } + return size_p0; +} + +static int StatLoop(VP8Encoder* const enc) { + const int method = enc->method_; + const int do_search = enc->do_search_; + const int fast_probe = ((method == 0 || method == 3) && !do_search); + int num_pass_left = enc->config_->pass; + const int task_percent = 20; + const int percent_per_pass = + (task_percent + num_pass_left / 2) / num_pass_left; + const int final_percent = enc->percent_ + task_percent; + const VP8RDLevel rd_opt = + (method >= 3 || do_search) ? RD_OPT_BASIC : RD_OPT_NONE; + int nb_mbs = enc->mb_w_ * enc->mb_h_; + PassStats stats; + + InitPassStats(enc, &stats); + ResetTokenStats(enc); + + // Fast mode: quick analysis pass over few mbs. Better than nothing. + if (fast_probe) { + if (method == 3) { // we need more stats for method 3 to be reliable. + nb_mbs = (nb_mbs > 200) ? nb_mbs >> 1 : 100; + } else { + nb_mbs = (nb_mbs > 200) ? nb_mbs >> 2 : 50; + } + } + + while (num_pass_left-- > 0) { + const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) || + (num_pass_left == 0) || + (enc->max_i4_header_bits_ == 0); + const uint64_t size_p0 = + OneStatPass(enc, rd_opt, nb_mbs, percent_per_pass, &stats); + if (size_p0 == 0) return 0; +#if (DEBUG_SEARCH > 0) + printf("#%d value:%.1lf -> %.1lf q:%.2f -> %.2f\n", + num_pass_left, stats.last_value, stats.value, stats.last_q, stats.q); +#endif + if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { + ++num_pass_left; + enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation... + continue; // ...and start over + } + if (is_last_pass) { + break; + } + // If no target size: just do several pass without changing 'q' + if (do_search) { + ComputeNextQ(&stats); + if (fabs(stats.dq) <= DQ_LIMIT) break; + } + } + if (!do_search || !stats.do_size_search) { + // Need to finalize probas now, since it wasn't done during the search. + FinalizeSkipProba(enc); + FinalizeTokenProbas(&enc->proba_); + } + VP8CalculateLevelCosts(&enc->proba_); // finalize costs + return WebPReportProgress(enc->pic_, final_percent, &enc->percent_); +} + +//------------------------------------------------------------------------------ +// Main loops +// + +static const uint8_t kAverageBytesPerMB[8] = { 50, 24, 16, 9, 7, 5, 3, 2 }; + +static int PreLoopInitialize(VP8Encoder* const enc) { + int p; + int ok = 1; + const int average_bytes_per_MB = kAverageBytesPerMB[enc->base_quant_ >> 4]; + const int bytes_per_parts = + enc->mb_w_ * enc->mb_h_ * average_bytes_per_MB / enc->num_parts_; + // Initialize the bit-writers + for (p = 0; ok && p < enc->num_parts_; ++p) { + ok = VP8BitWriterInit(enc->parts_ + p, bytes_per_parts); + } + if (!ok) { + VP8EncFreeBitWriters(enc); // malloc error occurred + return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + return ok; +} + +static int PostLoopFinalize(VP8EncIterator* const it, int ok) { + VP8Encoder* const enc = it->enc_; + if (ok) { // Finalize the partitions, check for extra errors. + int p; + for (p = 0; p < enc->num_parts_; ++p) { + VP8BitWriterFinish(enc->parts_ + p); + ok &= !enc->parts_[p].error_; + } + } + + if (ok) { // All good. Finish up. +#if !defined(WEBP_DISABLE_STATS) + if (enc->pic_->stats != NULL) { // finalize byte counters... + int i, s; + for (i = 0; i <= 2; ++i) { + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + enc->residual_bytes_[i][s] = (int)((it->bit_count_[s][i] + 7) >> 3); + } + } + } +#endif + VP8AdjustFilterStrength(it); // ...and store filter stats. + } else { + // Something bad happened -> need to do some memory cleanup. + VP8EncFreeBitWriters(enc); + return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + return ok; +} + +//------------------------------------------------------------------------------ +// VP8EncLoop(): does the final bitstream coding. + +static void ResetAfterSkip(VP8EncIterator* const it) { + if (it->mb_->type_ == 1) { + *it->nz_ = 0; // reset all predictors + it->left_nz_[8] = 0; + } else { + *it->nz_ &= (1 << 24); // preserve the dc_nz bit + } +} + +int VP8EncLoop(VP8Encoder* const enc) { + VP8EncIterator it; + int ok = PreLoopInitialize(enc); + if (!ok) return 0; + + StatLoop(enc); // stats-collection loop + + VP8IteratorInit(enc, &it); + VP8InitFilter(&it); + do { + VP8ModeScore info; + const int dont_use_skip = !enc->proba_.use_skip_proba_; + const VP8RDLevel rd_opt = enc->rd_opt_level_; + + VP8IteratorImport(&it, NULL); + // Warning! order is important: first call VP8Decimate() and + // *then* decide how to code the skip decision if there's one. + if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) { + CodeResiduals(it.bw_, &it, &info); + if (it.bw_->error_) { + // enc->pic_->error_code is set in PostLoopFinalize(). + ok = 0; + break; + } + } else { // reset predictors after a skip + ResetAfterSkip(&it); + } + StoreSideInfo(&it); + VP8StoreFilterStats(&it); + VP8IteratorExport(&it); + ok = VP8IteratorProgress(&it, 20); + VP8IteratorSaveBoundary(&it); + } while (ok && VP8IteratorNext(&it)); + + return PostLoopFinalize(&it, ok); +} + +//------------------------------------------------------------------------------ +// Single pass using Token Buffer. + +#if !defined(DISABLE_TOKEN_BUFFER) + +#define MIN_COUNT 96 // minimum number of macroblocks before updating stats + +int VP8EncTokenLoop(VP8Encoder* const enc) { + // Roughly refresh the proba eight times per pass + int max_count = (enc->mb_w_ * enc->mb_h_) >> 3; + int num_pass_left = enc->config_->pass; + int remaining_progress = 40; // percents + const int do_search = enc->do_search_; + VP8EncIterator it; + VP8EncProba* const proba = &enc->proba_; + const VP8RDLevel rd_opt = enc->rd_opt_level_; + const uint64_t pixel_count = (uint64_t)enc->mb_w_ * enc->mb_h_ * 384; + PassStats stats; + int ok; + + InitPassStats(enc, &stats); + ok = PreLoopInitialize(enc); + if (!ok) return 0; + + if (max_count < MIN_COUNT) max_count = MIN_COUNT; + + assert(enc->num_parts_ == 1); + assert(enc->use_tokens_); + assert(proba->use_skip_proba_ == 0); + assert(rd_opt >= RD_OPT_BASIC); // otherwise, token-buffer won't be useful + assert(num_pass_left > 0); + + while (ok && num_pass_left-- > 0) { + const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) || + (num_pass_left == 0) || + (enc->max_i4_header_bits_ == 0); + uint64_t size_p0 = 0; + uint64_t distortion = 0; + int cnt = max_count; + // The final number of passes is not trivial to know in advance. + const int pass_progress = remaining_progress / (2 + num_pass_left); + remaining_progress -= pass_progress; + VP8IteratorInit(enc, &it); + SetLoopParams(enc, stats.q); + if (is_last_pass) { + ResetTokenStats(enc); + VP8InitFilter(&it); // don't collect stats until last pass (too costly) + } + VP8TBufferClear(&enc->tokens_); + do { + VP8ModeScore info; + VP8IteratorImport(&it, NULL); + if (--cnt < 0) { + FinalizeTokenProbas(proba); + VP8CalculateLevelCosts(proba); // refresh cost tables for rd-opt + cnt = max_count; + } + VP8Decimate(&it, &info, rd_opt); + ok = RecordTokens(&it, &info, &enc->tokens_); + if (!ok) { + WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + break; + } + size_p0 += info.H; + distortion += info.D; + if (is_last_pass) { + StoreSideInfo(&it); + VP8StoreFilterStats(&it); + VP8IteratorExport(&it); + ok = VP8IteratorProgress(&it, pass_progress); + } + VP8IteratorSaveBoundary(&it); + } while (ok && VP8IteratorNext(&it)); + if (!ok) break; + + size_p0 += enc->segment_hdr_.size_; + if (stats.do_size_search) { + uint64_t size = FinalizeTokenProbas(&enc->proba_); + size += VP8EstimateTokenSize(&enc->tokens_, + (const uint8_t*)proba->coeffs_); + size = (size + size_p0 + 1024) >> 11; // -> size in bytes + size += HEADER_SIZE_ESTIMATE; + stats.value = (double)size; + } else { // compute and store PSNR + stats.value = GetPSNR(distortion, pixel_count); + } + +#if (DEBUG_SEARCH > 0) + printf("#%2d metric:%.1lf -> %.1lf last_q=%.2lf q=%.2lf dq=%.2lf " + " range:[%.1f, %.1f]\n", + num_pass_left, stats.last_value, stats.value, + stats.last_q, stats.q, stats.dq, stats.qmin, stats.qmax); +#endif + if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { + ++num_pass_left; + enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation... + if (is_last_pass) { + ResetSideInfo(&it); + } + continue; // ...and start over + } + if (is_last_pass) { + break; // done + } + if (do_search) { + ComputeNextQ(&stats); // Adjust q + } + } + if (ok) { + if (!stats.do_size_search) { + FinalizeTokenProbas(&enc->proba_); + } + ok = VP8EmitTokens(&enc->tokens_, enc->parts_ + 0, + (const uint8_t*)proba->coeffs_, 1); + } + ok = ok && WebPReportProgress(enc->pic_, enc->percent_ + remaining_progress, + &enc->percent_); + return PostLoopFinalize(&it, ok); +} + +#else + +int VP8EncTokenLoop(VP8Encoder* const enc) { + (void)enc; + return 0; // we shouldn't be here. +} + +#endif // DISABLE_TOKEN_BUFFER + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/enc/histogram_enc.c b/libraries/webp/src/enc/histogram_enc.c new file mode 100644 index 00000000000..aa164693e1e --- /dev/null +++ b/libraries/webp/src/enc/histogram_enc.c @@ -0,0 +1,1250 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include +#include + +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" +#include "src/enc/backward_references_enc.h" +#include "src/enc/histogram_enc.h" +#include "src/enc/vp8i_enc.h" +#include "src/utils/utils.h" + +#define MAX_BIT_COST FLT_MAX + +// Number of partitions for the three dominant (literal, red and blue) symbol +// costs. +#define NUM_PARTITIONS 4 +// The size of the bin-hash corresponding to the three dominant costs. +#define BIN_SIZE (NUM_PARTITIONS * NUM_PARTITIONS * NUM_PARTITIONS) +// Maximum number of histograms allowed in greedy combining algorithm. +#define MAX_HISTO_GREEDY 100 + +static void HistogramClear(VP8LHistogram* const p) { + uint32_t* const literal = p->literal_; + const int cache_bits = p->palette_code_bits_; + const int histo_size = VP8LGetHistogramSize(cache_bits); + memset(p, 0, histo_size); + p->palette_code_bits_ = cache_bits; + p->literal_ = literal; +} + +// Swap two histogram pointers. +static void HistogramSwap(VP8LHistogram** const A, VP8LHistogram** const B) { + VP8LHistogram* const tmp = *A; + *A = *B; + *B = tmp; +} + +static void HistogramCopy(const VP8LHistogram* const src, + VP8LHistogram* const dst) { + uint32_t* const dst_literal = dst->literal_; + const int dst_cache_bits = dst->palette_code_bits_; + const int literal_size = VP8LHistogramNumCodes(dst_cache_bits); + const int histo_size = VP8LGetHistogramSize(dst_cache_bits); + assert(src->palette_code_bits_ == dst_cache_bits); + memcpy(dst, src, histo_size); + dst->literal_ = dst_literal; + memcpy(dst->literal_, src->literal_, literal_size * sizeof(*dst->literal_)); +} + +int VP8LGetHistogramSize(int cache_bits) { + const int literal_size = VP8LHistogramNumCodes(cache_bits); + const size_t total_size = sizeof(VP8LHistogram) + sizeof(int) * literal_size; + assert(total_size <= (size_t)0x7fffffff); + return (int)total_size; +} + +void VP8LFreeHistogram(VP8LHistogram* const histo) { + WebPSafeFree(histo); +} + +void VP8LFreeHistogramSet(VP8LHistogramSet* const histo) { + WebPSafeFree(histo); +} + +void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, + VP8LHistogram* const histo) { + VP8LRefsCursor c = VP8LRefsCursorInit(refs); + while (VP8LRefsCursorOk(&c)) { + VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, NULL, 0); + VP8LRefsCursorNext(&c); + } +} + +void VP8LHistogramCreate(VP8LHistogram* const p, + const VP8LBackwardRefs* const refs, + int palette_code_bits) { + if (palette_code_bits >= 0) { + p->palette_code_bits_ = palette_code_bits; + } + HistogramClear(p); + VP8LHistogramStoreRefs(refs, p); +} + +void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits, + int init_arrays) { + p->palette_code_bits_ = palette_code_bits; + if (init_arrays) { + HistogramClear(p); + } else { + p->trivial_symbol_ = 0; + p->bit_cost_ = 0.; + p->literal_cost_ = 0.; + p->red_cost_ = 0.; + p->blue_cost_ = 0.; + memset(p->is_used_, 0, sizeof(p->is_used_)); + } +} + +VP8LHistogram* VP8LAllocateHistogram(int cache_bits) { + VP8LHistogram* histo = NULL; + const int total_size = VP8LGetHistogramSize(cache_bits); + uint8_t* const memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); + if (memory == NULL) return NULL; + histo = (VP8LHistogram*)memory; + // literal_ won't necessary be aligned. + histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); + VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0); + return histo; +} + +// Resets the pointers of the histograms to point to the bit buffer in the set. +static void HistogramSetResetPointers(VP8LHistogramSet* const set, + int cache_bits) { + int i; + const int histo_size = VP8LGetHistogramSize(cache_bits); + uint8_t* memory = (uint8_t*) (set->histograms); + memory += set->max_size * sizeof(*set->histograms); + for (i = 0; i < set->max_size; ++i) { + memory = (uint8_t*) WEBP_ALIGN(memory); + set->histograms[i] = (VP8LHistogram*) memory; + // literal_ won't necessary be aligned. + set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); + memory += histo_size; + } +} + +// Returns the total size of the VP8LHistogramSet. +static size_t HistogramSetTotalSize(int size, int cache_bits) { + const int histo_size = VP8LGetHistogramSize(cache_bits); + return (sizeof(VP8LHistogramSet) + size * (sizeof(VP8LHistogram*) + + histo_size + WEBP_ALIGN_CST)); +} + +VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) { + int i; + VP8LHistogramSet* set; + const size_t total_size = HistogramSetTotalSize(size, cache_bits); + uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); + if (memory == NULL) return NULL; + + set = (VP8LHistogramSet*)memory; + memory += sizeof(*set); + set->histograms = (VP8LHistogram**)memory; + set->max_size = size; + set->size = size; + HistogramSetResetPointers(set, cache_bits); + for (i = 0; i < size; ++i) { + VP8LHistogramInit(set->histograms[i], cache_bits, /*init_arrays=*/ 0); + } + return set; +} + +void VP8LHistogramSetClear(VP8LHistogramSet* const set) { + int i; + const int cache_bits = set->histograms[0]->palette_code_bits_; + const int size = set->max_size; + const size_t total_size = HistogramSetTotalSize(size, cache_bits); + uint8_t* memory = (uint8_t*)set; + + memset(memory, 0, total_size); + memory += sizeof(*set); + set->histograms = (VP8LHistogram**)memory; + set->max_size = size; + set->size = size; + HistogramSetResetPointers(set, cache_bits); + for (i = 0; i < size; ++i) { + set->histograms[i]->palette_code_bits_ = cache_bits; + } +} + +// Removes the histogram 'i' from 'set' by setting it to NULL. +static void HistogramSetRemoveHistogram(VP8LHistogramSet* const set, int i, + int* const num_used) { + assert(set->histograms[i] != NULL); + set->histograms[i] = NULL; + --*num_used; + // If we remove the last valid one, shrink until the next valid one. + if (i == set->size - 1) { + while (set->size >= 1 && set->histograms[set->size - 1] == NULL) { + --set->size; + } + } +} + +// ----------------------------------------------------------------------------- + +void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, + const PixOrCopy* const v, + int (*const distance_modifier)(int, int), + int distance_modifier_arg0) { + if (PixOrCopyIsLiteral(v)) { + ++histo->alpha_[PixOrCopyLiteral(v, 3)]; + ++histo->red_[PixOrCopyLiteral(v, 2)]; + ++histo->literal_[PixOrCopyLiteral(v, 1)]; + ++histo->blue_[PixOrCopyLiteral(v, 0)]; + } else if (PixOrCopyIsCacheIdx(v)) { + const int literal_ix = + NUM_LITERAL_CODES + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v); + assert(histo->palette_code_bits_ != 0); + ++histo->literal_[literal_ix]; + } else { + int code, extra_bits; + VP8LPrefixEncodeBits(PixOrCopyLength(v), &code, &extra_bits); + ++histo->literal_[NUM_LITERAL_CODES + code]; + if (distance_modifier == NULL) { + VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits); + } else { + VP8LPrefixEncodeBits( + distance_modifier(distance_modifier_arg0, PixOrCopyDistance(v)), + &code, &extra_bits); + } + ++histo->distance_[code]; + } +} + +// ----------------------------------------------------------------------------- +// Entropy-related functions. + +static WEBP_INLINE float BitsEntropyRefine(const VP8LBitEntropy* entropy) { + float mix; + if (entropy->nonzeros < 5) { + if (entropy->nonzeros <= 1) { + return 0; + } + // Two symbols, they will be 0 and 1 in a Huffman code. + // Let's mix in a bit of entropy to favor good clustering when + // distributions of these are combined. + if (entropy->nonzeros == 2) { + return 0.99f * entropy->sum + 0.01f * entropy->entropy; + } + // No matter what the entropy says, we cannot be better than min_limit + // with Huffman coding. I am mixing a bit of entropy into the + // min_limit since it produces much better (~0.5 %) compression results + // perhaps because of better entropy clustering. + if (entropy->nonzeros == 3) { + mix = 0.95f; + } else { + mix = 0.7f; // nonzeros == 4. + } + } else { + mix = 0.627f; + } + + { + float min_limit = 2.f * entropy->sum - entropy->max_val; + min_limit = mix * min_limit + (1.f - mix) * entropy->entropy; + return (entropy->entropy < min_limit) ? min_limit : entropy->entropy; + } +} + +float VP8LBitsEntropy(const uint32_t* const array, int n) { + VP8LBitEntropy entropy; + VP8LBitsEntropyUnrefined(array, n, &entropy); + + return BitsEntropyRefine(&entropy); +} + +static float InitialHuffmanCost(void) { + // Small bias because Huffman code length is typically not stored in + // full length. + static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3; + static const float kSmallBias = 9.1f; + return kHuffmanCodeOfHuffmanCodeSize - kSmallBias; +} + +// Finalize the Huffman cost based on streak numbers and length type (<3 or >=3) +static float FinalHuffmanCost(const VP8LStreaks* const stats) { + // The constants in this function are experimental and got rounded from + // their original values in 1/8 when switched to 1/1024. + float retval = InitialHuffmanCost(); + // Second coefficient: Many zeros in the histogram are covered efficiently + // by a run-length encode. Originally 2/8. + retval += stats->counts[0] * 1.5625f + 0.234375f * stats->streaks[0][1]; + // Second coefficient: Constant values are encoded less efficiently, but still + // RLE'ed. Originally 6/8. + retval += stats->counts[1] * 2.578125f + 0.703125f * stats->streaks[1][1]; + // 0s are usually encoded more efficiently than non-0s. + // Originally 15/8. + retval += 1.796875f * stats->streaks[0][0]; + // Originally 26/8. + retval += 3.28125f * stats->streaks[1][0]; + return retval; +} + +// Get the symbol entropy for the distribution 'population'. +// Set 'trivial_sym', if there's only one symbol present in the distribution. +static float PopulationCost(const uint32_t* const population, int length, + uint32_t* const trivial_sym, + uint8_t* const is_used) { + VP8LBitEntropy bit_entropy; + VP8LStreaks stats; + VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats); + if (trivial_sym != NULL) { + *trivial_sym = (bit_entropy.nonzeros == 1) ? bit_entropy.nonzero_code + : VP8L_NON_TRIVIAL_SYM; + } + // The histogram is used if there is at least one non-zero streak. + *is_used = (stats.streaks[1][0] != 0 || stats.streaks[1][1] != 0); + + return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); +} + +// trivial_at_end is 1 if the two histograms only have one element that is +// non-zero: both the zero-th one, or both the last one. +static WEBP_INLINE float GetCombinedEntropy(const uint32_t* const X, + const uint32_t* const Y, int length, + int is_X_used, int is_Y_used, + int trivial_at_end) { + VP8LStreaks stats; + if (trivial_at_end) { + // This configuration is due to palettization that transforms an indexed + // pixel into 0xff000000 | (pixel << 8) in VP8LBundleColorMap. + // BitsEntropyRefine is 0 for histograms with only one non-zero value. + // Only FinalHuffmanCost needs to be evaluated. + memset(&stats, 0, sizeof(stats)); + // Deal with the non-zero value at index 0 or length-1. + stats.streaks[1][0] = 1; + // Deal with the following/previous zero streak. + stats.counts[0] = 1; + stats.streaks[0][1] = length - 1; + return FinalHuffmanCost(&stats); + } else { + VP8LBitEntropy bit_entropy; + if (is_X_used) { + if (is_Y_used) { + VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats); + } else { + VP8LGetEntropyUnrefined(X, length, &bit_entropy, &stats); + } + } else { + if (is_Y_used) { + VP8LGetEntropyUnrefined(Y, length, &bit_entropy, &stats); + } else { + memset(&stats, 0, sizeof(stats)); + stats.counts[0] = 1; + stats.streaks[0][length > 3] = length; + VP8LBitEntropyInit(&bit_entropy); + } + } + + return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); + } +} + +// Estimates the Entropy + Huffman + other block overhead size cost. +float VP8LHistogramEstimateBits(VP8LHistogram* const p) { + return PopulationCost(p->literal_, + VP8LHistogramNumCodes(p->palette_code_bits_), NULL, + &p->is_used_[0]) + + PopulationCost(p->red_, NUM_LITERAL_CODES, NULL, &p->is_used_[1]) + + PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL, &p->is_used_[2]) + + PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL, &p->is_used_[3]) + + PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL, + &p->is_used_[4]) + + (float)VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES, + NUM_LENGTH_CODES) + + (float)VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES); +} + +// ----------------------------------------------------------------------------- +// Various histogram combine/cost-eval functions + +static int GetCombinedHistogramEntropy(const VP8LHistogram* const a, + const VP8LHistogram* const b, + float cost_threshold, float* cost) { + const int palette_code_bits = a->palette_code_bits_; + int trivial_at_end = 0; + assert(a->palette_code_bits_ == b->palette_code_bits_); + *cost += GetCombinedEntropy(a->literal_, b->literal_, + VP8LHistogramNumCodes(palette_code_bits), + a->is_used_[0], b->is_used_[0], 0); + *cost += (float)VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES, + b->literal_ + NUM_LITERAL_CODES, + NUM_LENGTH_CODES); + if (*cost > cost_threshold) return 0; + + if (a->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM && + a->trivial_symbol_ == b->trivial_symbol_) { + // A, R and B are all 0 or 0xff. + const uint32_t color_a = (a->trivial_symbol_ >> 24) & 0xff; + const uint32_t color_r = (a->trivial_symbol_ >> 16) & 0xff; + const uint32_t color_b = (a->trivial_symbol_ >> 0) & 0xff; + if ((color_a == 0 || color_a == 0xff) && + (color_r == 0 || color_r == 0xff) && + (color_b == 0 || color_b == 0xff)) { + trivial_at_end = 1; + } + } + + *cost += + GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES, a->is_used_[1], + b->is_used_[1], trivial_at_end); + if (*cost > cost_threshold) return 0; + + *cost += + GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES, a->is_used_[2], + b->is_used_[2], trivial_at_end); + if (*cost > cost_threshold) return 0; + + *cost += + GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES, + a->is_used_[3], b->is_used_[3], trivial_at_end); + if (*cost > cost_threshold) return 0; + + *cost += + GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES, + a->is_used_[4], b->is_used_[4], 0); + *cost += (float)VP8LExtraCostCombined(a->distance_, b->distance_, + NUM_DISTANCE_CODES); + if (*cost > cost_threshold) return 0; + + return 1; +} + +static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const a, + const VP8LHistogram* const b, + VP8LHistogram* const out) { + VP8LHistogramAdd(a, b, out); + out->trivial_symbol_ = (a->trivial_symbol_ == b->trivial_symbol_) + ? a->trivial_symbol_ + : VP8L_NON_TRIVIAL_SYM; +} + +// Performs out = a + b, computing the cost C(a+b) - C(a) - C(b) while comparing +// to the threshold value 'cost_threshold'. The score returned is +// Score = C(a+b) - C(a) - C(b), where C(a) + C(b) is known and fixed. +// Since the previous score passed is 'cost_threshold', we only need to compare +// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out +// early. +static float HistogramAddEval(const VP8LHistogram* const a, + const VP8LHistogram* const b, + VP8LHistogram* const out, float cost_threshold) { + float cost = 0; + const float sum_cost = a->bit_cost_ + b->bit_cost_; + cost_threshold += sum_cost; + + if (GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) { + HistogramAdd(a, b, out); + out->bit_cost_ = cost; + out->palette_code_bits_ = a->palette_code_bits_; + } + + return cost - sum_cost; +} + +// Same as HistogramAddEval(), except that the resulting histogram +// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit +// the term C(b) which is constant over all the evaluations. +static float HistogramAddThresh(const VP8LHistogram* const a, + const VP8LHistogram* const b, + float cost_threshold) { + float cost; + assert(a != NULL && b != NULL); + cost = -a->bit_cost_; + GetCombinedHistogramEntropy(a, b, cost_threshold, &cost); + return cost; +} + +// ----------------------------------------------------------------------------- + +// The structure to keep track of cost range for the three dominant entropy +// symbols. +typedef struct { + float literal_max_; + float literal_min_; + float red_max_; + float red_min_; + float blue_max_; + float blue_min_; +} DominantCostRange; + +static void DominantCostRangeInit(DominantCostRange* const c) { + c->literal_max_ = 0.; + c->literal_min_ = MAX_BIT_COST; + c->red_max_ = 0.; + c->red_min_ = MAX_BIT_COST; + c->blue_max_ = 0.; + c->blue_min_ = MAX_BIT_COST; +} + +static void UpdateDominantCostRange( + const VP8LHistogram* const h, DominantCostRange* const c) { + if (c->literal_max_ < h->literal_cost_) c->literal_max_ = h->literal_cost_; + if (c->literal_min_ > h->literal_cost_) c->literal_min_ = h->literal_cost_; + if (c->red_max_ < h->red_cost_) c->red_max_ = h->red_cost_; + if (c->red_min_ > h->red_cost_) c->red_min_ = h->red_cost_; + if (c->blue_max_ < h->blue_cost_) c->blue_max_ = h->blue_cost_; + if (c->blue_min_ > h->blue_cost_) c->blue_min_ = h->blue_cost_; +} + +static void UpdateHistogramCost(VP8LHistogram* const h) { + uint32_t alpha_sym, red_sym, blue_sym; + const float alpha_cost = + PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]); + const float distance_cost = + PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) + + (float)VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES); + const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_); + h->literal_cost_ = + PopulationCost(h->literal_, num_codes, NULL, &h->is_used_[0]) + + (float)VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES); + h->red_cost_ = + PopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym, &h->is_used_[1]); + h->blue_cost_ = + PopulationCost(h->blue_, NUM_LITERAL_CODES, &blue_sym, &h->is_used_[2]); + h->bit_cost_ = h->literal_cost_ + h->red_cost_ + h->blue_cost_ + + alpha_cost + distance_cost; + if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) { + h->trivial_symbol_ = VP8L_NON_TRIVIAL_SYM; + } else { + h->trivial_symbol_ = + ((uint32_t)alpha_sym << 24) | (red_sym << 16) | (blue_sym << 0); + } +} + +static int GetBinIdForEntropy(float min, float max, float val) { + const float range = max - min; + if (range > 0.) { + const float delta = val - min; + return (int)((NUM_PARTITIONS - 1e-6) * delta / range); + } else { + return 0; + } +} + +static int GetHistoBinIndex(const VP8LHistogram* const h, + const DominantCostRange* const c, int low_effort) { + int bin_id = GetBinIdForEntropy(c->literal_min_, c->literal_max_, + h->literal_cost_); + assert(bin_id < NUM_PARTITIONS); + if (!low_effort) { + bin_id = bin_id * NUM_PARTITIONS + + GetBinIdForEntropy(c->red_min_, c->red_max_, h->red_cost_); + bin_id = bin_id * NUM_PARTITIONS + + GetBinIdForEntropy(c->blue_min_, c->blue_max_, h->blue_cost_); + assert(bin_id < BIN_SIZE); + } + return bin_id; +} + +// Construct the histograms from backward references. +static void HistogramBuild( + int xsize, int histo_bits, const VP8LBackwardRefs* const backward_refs, + VP8LHistogramSet* const image_histo) { + int x = 0, y = 0; + const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits); + VP8LHistogram** const histograms = image_histo->histograms; + VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs); + assert(histo_bits > 0); + VP8LHistogramSetClear(image_histo); + while (VP8LRefsCursorOk(&c)) { + const PixOrCopy* const v = c.cur_pos; + const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits); + VP8LHistogramAddSinglePixOrCopy(histograms[ix], v, NULL, 0); + x += PixOrCopyLength(v); + while (x >= xsize) { + x -= xsize; + ++y; + } + VP8LRefsCursorNext(&c); + } +} + +// Copies the histograms and computes its bit_cost. +static const uint16_t kInvalidHistogramSymbol = (uint16_t)(-1); +static void HistogramCopyAndAnalyze(VP8LHistogramSet* const orig_histo, + VP8LHistogramSet* const image_histo, + int* const num_used, + uint16_t* const histogram_symbols) { + int i, cluster_id; + int num_used_orig = *num_used; + VP8LHistogram** const orig_histograms = orig_histo->histograms; + VP8LHistogram** const histograms = image_histo->histograms; + assert(image_histo->max_size == orig_histo->max_size); + for (cluster_id = 0, i = 0; i < orig_histo->max_size; ++i) { + VP8LHistogram* const histo = orig_histograms[i]; + UpdateHistogramCost(histo); + + // Skip the histogram if it is completely empty, which can happen for tiles + // with no information (when they are skipped because of LZ77). + if (!histo->is_used_[0] && !histo->is_used_[1] && !histo->is_used_[2] + && !histo->is_used_[3] && !histo->is_used_[4]) { + // The first histogram is always used. If an histogram is empty, we set + // its id to be the same as the previous one: this will improve + // compressibility for later LZ77. + assert(i > 0); + HistogramSetRemoveHistogram(image_histo, i, num_used); + HistogramSetRemoveHistogram(orig_histo, i, &num_used_orig); + histogram_symbols[i] = kInvalidHistogramSymbol; + } else { + // Copy histograms from orig_histo[] to image_histo[]. + HistogramCopy(histo, histograms[i]); + histogram_symbols[i] = cluster_id++; + assert(cluster_id <= image_histo->max_size); + } + } +} + +// Partition histograms to different entropy bins for three dominant (literal, +// red and blue) symbol costs and compute the histogram aggregate bit_cost. +static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo, + uint16_t* const bin_map, + int low_effort) { + int i; + VP8LHistogram** const histograms = image_histo->histograms; + const int histo_size = image_histo->size; + DominantCostRange cost_range; + DominantCostRangeInit(&cost_range); + + // Analyze the dominant (literal, red and blue) entropy costs. + for (i = 0; i < histo_size; ++i) { + if (histograms[i] == NULL) continue; + UpdateDominantCostRange(histograms[i], &cost_range); + } + + // bin-hash histograms on three of the dominant (literal, red and blue) + // symbol costs and store the resulting bin_id for each histogram. + for (i = 0; i < histo_size; ++i) { + // bin_map[i] is not set to a special value as its use will later be guarded + // by another (histograms[i] == NULL). + if (histograms[i] == NULL) continue; + bin_map[i] = GetHistoBinIndex(histograms[i], &cost_range, low_effort); + } +} + +// Merges some histograms with same bin_id together if it's advantageous. +// Sets the remaining histograms to NULL. +static void HistogramCombineEntropyBin( + VP8LHistogramSet* const image_histo, int* num_used, + const uint16_t* const clusters, uint16_t* const cluster_mappings, + VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins, + float combine_cost_factor, int low_effort) { + VP8LHistogram** const histograms = image_histo->histograms; + int idx; + struct { + int16_t first; // position of the histogram that accumulates all + // histograms with the same bin_id + uint16_t num_combine_failures; // number of combine failures per bin_id + } bin_info[BIN_SIZE]; + + assert(num_bins <= BIN_SIZE); + for (idx = 0; idx < num_bins; ++idx) { + bin_info[idx].first = -1; + bin_info[idx].num_combine_failures = 0; + } + + // By default, a cluster matches itself. + for (idx = 0; idx < *num_used; ++idx) cluster_mappings[idx] = idx; + for (idx = 0; idx < image_histo->size; ++idx) { + int bin_id, first; + if (histograms[idx] == NULL) continue; + bin_id = bin_map[idx]; + first = bin_info[bin_id].first; + if (first == -1) { + bin_info[bin_id].first = idx; + } else if (low_effort) { + HistogramAdd(histograms[idx], histograms[first], histograms[first]); + HistogramSetRemoveHistogram(image_histo, idx, num_used); + cluster_mappings[clusters[idx]] = clusters[first]; + } else { + // try to merge #idx into #first (both share the same bin_id) + const float bit_cost = histograms[idx]->bit_cost_; + const float bit_cost_thresh = -bit_cost * combine_cost_factor; + const float curr_cost_diff = HistogramAddEval( + histograms[first], histograms[idx], cur_combo, bit_cost_thresh); + if (curr_cost_diff < bit_cost_thresh) { + // Try to merge two histograms only if the combo is a trivial one or + // the two candidate histograms are already non-trivial. + // For some images, 'try_combine' turns out to be false for a lot of + // histogram pairs. In that case, we fallback to combining + // histograms as usual to avoid increasing the header size. + const int try_combine = + (cur_combo->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM) || + ((histograms[idx]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM) && + (histograms[first]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM)); + const int max_combine_failures = 32; + if (try_combine || + bin_info[bin_id].num_combine_failures >= max_combine_failures) { + // move the (better) merged histogram to its final slot + HistogramSwap(&cur_combo, &histograms[first]); + HistogramSetRemoveHistogram(image_histo, idx, num_used); + cluster_mappings[clusters[idx]] = clusters[first]; + } else { + ++bin_info[bin_id].num_combine_failures; + } + } + } + } + if (low_effort) { + // for low_effort case, update the final cost when everything is merged + for (idx = 0; idx < image_histo->size; ++idx) { + if (histograms[idx] == NULL) continue; + UpdateHistogramCost(histograms[idx]); + } + } +} + +// Implement a Lehmer random number generator with a multiplicative constant of +// 48271 and a modulo constant of 2^31 - 1. +static uint32_t MyRand(uint32_t* const seed) { + *seed = (uint32_t)(((uint64_t)(*seed) * 48271u) % 2147483647u); + assert(*seed > 0); + return *seed; +} + +// ----------------------------------------------------------------------------- +// Histogram pairs priority queue + +// Pair of histograms. Negative idx1 value means that pair is out-of-date. +typedef struct { + int idx1; + int idx2; + float cost_diff; + float cost_combo; +} HistogramPair; + +typedef struct { + HistogramPair* queue; + int size; + int max_size; +} HistoQueue; + +static int HistoQueueInit(HistoQueue* const histo_queue, const int max_size) { + histo_queue->size = 0; + histo_queue->max_size = max_size; + // We allocate max_size + 1 because the last element at index "size" is + // used as temporary data (and it could be up to max_size). + histo_queue->queue = (HistogramPair*)WebPSafeMalloc( + histo_queue->max_size + 1, sizeof(*histo_queue->queue)); + return histo_queue->queue != NULL; +} + +static void HistoQueueClear(HistoQueue* const histo_queue) { + assert(histo_queue != NULL); + WebPSafeFree(histo_queue->queue); + histo_queue->size = 0; + histo_queue->max_size = 0; +} + +// Pop a specific pair in the queue by replacing it with the last one +// and shrinking the queue. +static void HistoQueuePopPair(HistoQueue* const histo_queue, + HistogramPair* const pair) { + assert(pair >= histo_queue->queue && + pair < (histo_queue->queue + histo_queue->size)); + assert(histo_queue->size > 0); + *pair = histo_queue->queue[histo_queue->size - 1]; + --histo_queue->size; +} + +// Check whether a pair in the queue should be updated as head or not. +static void HistoQueueUpdateHead(HistoQueue* const histo_queue, + HistogramPair* const pair) { + assert(pair->cost_diff < 0.); + assert(pair >= histo_queue->queue && + pair < (histo_queue->queue + histo_queue->size)); + assert(histo_queue->size > 0); + if (pair->cost_diff < histo_queue->queue[0].cost_diff) { + // Replace the best pair. + const HistogramPair tmp = histo_queue->queue[0]; + histo_queue->queue[0] = *pair; + *pair = tmp; + } +} + +// Update the cost diff and combo of a pair of histograms. This needs to be +// called when the the histograms have been merged with a third one. +static void HistoQueueUpdatePair(const VP8LHistogram* const h1, + const VP8LHistogram* const h2, float threshold, + HistogramPair* const pair) { + const float sum_cost = h1->bit_cost_ + h2->bit_cost_; + pair->cost_combo = 0.; + GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair->cost_combo); + pair->cost_diff = pair->cost_combo - sum_cost; +} + +// Create a pair from indices "idx1" and "idx2" provided its cost +// is inferior to "threshold", a negative entropy. +// It returns the cost of the pair, or 0. if it superior to threshold. +static float HistoQueuePush(HistoQueue* const histo_queue, + VP8LHistogram** const histograms, int idx1, + int idx2, float threshold) { + const VP8LHistogram* h1; + const VP8LHistogram* h2; + HistogramPair pair; + + // Stop here if the queue is full. + if (histo_queue->size == histo_queue->max_size) return 0.; + assert(threshold <= 0.); + if (idx1 > idx2) { + const int tmp = idx2; + idx2 = idx1; + idx1 = tmp; + } + pair.idx1 = idx1; + pair.idx2 = idx2; + h1 = histograms[idx1]; + h2 = histograms[idx2]; + + HistoQueueUpdatePair(h1, h2, threshold, &pair); + + // Do not even consider the pair if it does not improve the entropy. + if (pair.cost_diff >= threshold) return 0.; + + histo_queue->queue[histo_queue->size++] = pair; + HistoQueueUpdateHead(histo_queue, &histo_queue->queue[histo_queue->size - 1]); + + return pair.cost_diff; +} + +// ----------------------------------------------------------------------------- + +// Combines histograms by continuously choosing the one with the highest cost +// reduction. +static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo, + int* const num_used) { + int ok = 0; + const int image_histo_size = image_histo->size; + int i, j; + VP8LHistogram** const histograms = image_histo->histograms; + // Priority queue of histogram pairs. + HistoQueue histo_queue; + + // image_histo_size^2 for the queue size is safe. If you look at + // HistogramCombineGreedy, and imagine that UpdateQueueFront always pushes + // data to the queue, you insert at most: + // - image_histo_size*(image_histo_size-1)/2 (the first two for loops) + // - image_histo_size - 1 in the last for loop at the first iteration of + // the while loop, image_histo_size - 2 at the second iteration ... + // therefore image_histo_size*(image_histo_size-1)/2 overall too + if (!HistoQueueInit(&histo_queue, image_histo_size * image_histo_size)) { + goto End; + } + + for (i = 0; i < image_histo_size; ++i) { + if (image_histo->histograms[i] == NULL) continue; + for (j = i + 1; j < image_histo_size; ++j) { + // Initialize queue. + if (image_histo->histograms[j] == NULL) continue; + HistoQueuePush(&histo_queue, histograms, i, j, 0.); + } + } + + while (histo_queue.size > 0) { + const int idx1 = histo_queue.queue[0].idx1; + const int idx2 = histo_queue.queue[0].idx2; + HistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]); + histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; + + // Remove merged histogram. + HistogramSetRemoveHistogram(image_histo, idx2, num_used); + + // Remove pairs intersecting the just combined best pair. + for (i = 0; i < histo_queue.size;) { + HistogramPair* const p = histo_queue.queue + i; + if (p->idx1 == idx1 || p->idx2 == idx1 || + p->idx1 == idx2 || p->idx2 == idx2) { + HistoQueuePopPair(&histo_queue, p); + } else { + HistoQueueUpdateHead(&histo_queue, p); + ++i; + } + } + + // Push new pairs formed with combined histogram to the queue. + for (i = 0; i < image_histo->size; ++i) { + if (i == idx1 || image_histo->histograms[i] == NULL) continue; + HistoQueuePush(&histo_queue, image_histo->histograms, idx1, i, 0.); + } + } + + ok = 1; + + End: + HistoQueueClear(&histo_queue); + return ok; +} + +// Perform histogram aggregation using a stochastic approach. +// 'do_greedy' is set to 1 if a greedy approach needs to be performed +// afterwards, 0 otherwise. +static int PairComparison(const void* idx1, const void* idx2) { + // To be used with bsearch: <0 when *idx1<*idx2, >0 if >, 0 when ==. + return (*(int*) idx1 - *(int*) idx2); +} +static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo, + int* const num_used, int min_cluster_size, + int* const do_greedy) { + int j, iter; + uint32_t seed = 1; + int tries_with_no_success = 0; + const int outer_iters = *num_used; + const int num_tries_no_success = outer_iters / 2; + VP8LHistogram** const histograms = image_histo->histograms; + // Priority queue of histogram pairs. Its size of 'kHistoQueueSize' + // impacts the quality of the compression and the speed: the smaller the + // faster but the worse for the compression. + HistoQueue histo_queue; + const int kHistoQueueSize = 9; + int ok = 0; + // mapping from an index in image_histo with no NULL histogram to the full + // blown image_histo. + int* mappings; + + if (*num_used < min_cluster_size) { + *do_greedy = 1; + return 1; + } + + mappings = (int*) WebPSafeMalloc(*num_used, sizeof(*mappings)); + if (mappings == NULL) return 0; + if (!HistoQueueInit(&histo_queue, kHistoQueueSize)) goto End; + // Fill the initial mapping. + for (j = 0, iter = 0; iter < image_histo->size; ++iter) { + if (histograms[iter] == NULL) continue; + mappings[j++] = iter; + } + assert(j == *num_used); + + // Collapse similar histograms in 'image_histo'. + for (iter = 0; + iter < outer_iters && *num_used >= min_cluster_size && + ++tries_with_no_success < num_tries_no_success; + ++iter) { + int* mapping_index; + float best_cost = + (histo_queue.size == 0) ? 0.f : histo_queue.queue[0].cost_diff; + int best_idx1 = -1, best_idx2 = 1; + const uint32_t rand_range = (*num_used - 1) * (*num_used); + // (*num_used) / 2 was chosen empirically. Less means faster but worse + // compression. + const int num_tries = (*num_used) / 2; + + // Pick random samples. + for (j = 0; *num_used >= 2 && j < num_tries; ++j) { + float curr_cost; + // Choose two different histograms at random and try to combine them. + const uint32_t tmp = MyRand(&seed) % rand_range; + uint32_t idx1 = tmp / (*num_used - 1); + uint32_t idx2 = tmp % (*num_used - 1); + if (idx2 >= idx1) ++idx2; + idx1 = mappings[idx1]; + idx2 = mappings[idx2]; + + // Calculate cost reduction on combination. + curr_cost = + HistoQueuePush(&histo_queue, histograms, idx1, idx2, best_cost); + if (curr_cost < 0) { // found a better pair? + best_cost = curr_cost; + // Empty the queue if we reached full capacity. + if (histo_queue.size == histo_queue.max_size) break; + } + } + if (histo_queue.size == 0) continue; + + // Get the best histograms. + best_idx1 = histo_queue.queue[0].idx1; + best_idx2 = histo_queue.queue[0].idx2; + assert(best_idx1 < best_idx2); + // Pop best_idx2 from mappings. + mapping_index = (int*) bsearch(&best_idx2, mappings, *num_used, + sizeof(best_idx2), &PairComparison); + assert(mapping_index != NULL); + memmove(mapping_index, mapping_index + 1, sizeof(*mapping_index) * + ((*num_used) - (mapping_index - mappings) - 1)); + // Merge the histograms and remove best_idx2 from the queue. + HistogramAdd(histograms[best_idx2], histograms[best_idx1], + histograms[best_idx1]); + histograms[best_idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; + HistogramSetRemoveHistogram(image_histo, best_idx2, num_used); + // Parse the queue and update each pair that deals with best_idx1, + // best_idx2 or image_histo_size. + for (j = 0; j < histo_queue.size;) { + HistogramPair* const p = histo_queue.queue + j; + const int is_idx1_best = p->idx1 == best_idx1 || p->idx1 == best_idx2; + const int is_idx2_best = p->idx2 == best_idx1 || p->idx2 == best_idx2; + int do_eval = 0; + // The front pair could have been duplicated by a random pick so + // check for it all the time nevertheless. + if (is_idx1_best && is_idx2_best) { + HistoQueuePopPair(&histo_queue, p); + continue; + } + // Any pair containing one of the two best indices should only refer to + // best_idx1. Its cost should also be updated. + if (is_idx1_best) { + p->idx1 = best_idx1; + do_eval = 1; + } else if (is_idx2_best) { + p->idx2 = best_idx1; + do_eval = 1; + } + // Make sure the index order is respected. + if (p->idx1 > p->idx2) { + const int tmp = p->idx2; + p->idx2 = p->idx1; + p->idx1 = tmp; + } + if (do_eval) { + // Re-evaluate the cost of an updated pair. + HistoQueueUpdatePair(histograms[p->idx1], histograms[p->idx2], 0., p); + if (p->cost_diff >= 0.) { + HistoQueuePopPair(&histo_queue, p); + continue; + } + } + HistoQueueUpdateHead(&histo_queue, p); + ++j; + } + tries_with_no_success = 0; + } + *do_greedy = (*num_used <= min_cluster_size); + ok = 1; + + End: + HistoQueueClear(&histo_queue); + WebPSafeFree(mappings); + return ok; +} + +// ----------------------------------------------------------------------------- +// Histogram refinement + +// Find the best 'out' histogram for each of the 'in' histograms. +// At call-time, 'out' contains the histograms of the clusters. +// Note: we assume that out[]->bit_cost_ is already up-to-date. +static void HistogramRemap(const VP8LHistogramSet* const in, + VP8LHistogramSet* const out, + uint16_t* const symbols) { + int i; + VP8LHistogram** const in_histo = in->histograms; + VP8LHistogram** const out_histo = out->histograms; + const int in_size = out->max_size; + const int out_size = out->size; + if (out_size > 1) { + for (i = 0; i < in_size; ++i) { + int best_out = 0; + float best_bits = MAX_BIT_COST; + int k; + if (in_histo[i] == NULL) { + // Arbitrarily set to the previous value if unused to help future LZ77. + symbols[i] = symbols[i - 1]; + continue; + } + for (k = 0; k < out_size; ++k) { + float cur_bits; + cur_bits = HistogramAddThresh(out_histo[k], in_histo[i], best_bits); + if (k == 0 || cur_bits < best_bits) { + best_bits = cur_bits; + best_out = k; + } + } + symbols[i] = best_out; + } + } else { + assert(out_size == 1); + for (i = 0; i < in_size; ++i) { + symbols[i] = 0; + } + } + + // Recompute each out based on raw and symbols. + VP8LHistogramSetClear(out); + out->size = out_size; + + for (i = 0; i < in_size; ++i) { + int idx; + if (in_histo[i] == NULL) continue; + idx = symbols[i]; + HistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]); + } +} + +static float GetCombineCostFactor(int histo_size, int quality) { + float combine_cost_factor = 0.16f; + if (quality < 90) { + if (histo_size > 256) combine_cost_factor /= 2.f; + if (histo_size > 512) combine_cost_factor /= 2.f; + if (histo_size > 1024) combine_cost_factor /= 2.f; + if (quality <= 50) combine_cost_factor /= 2.f; + } + return combine_cost_factor; +} + +// Given a HistogramSet 'set', the mapping of clusters 'cluster_mapping' and the +// current assignment of the cells in 'symbols', merge the clusters and +// assign the smallest possible clusters values. +static void OptimizeHistogramSymbols(const VP8LHistogramSet* const set, + uint16_t* const cluster_mappings, + int num_clusters, + uint16_t* const cluster_mappings_tmp, + uint16_t* const symbols) { + int i, cluster_max; + int do_continue = 1; + // First, assign the lowest cluster to each pixel. + while (do_continue) { + do_continue = 0; + for (i = 0; i < num_clusters; ++i) { + int k; + k = cluster_mappings[i]; + while (k != cluster_mappings[k]) { + cluster_mappings[k] = cluster_mappings[cluster_mappings[k]]; + k = cluster_mappings[k]; + } + if (k != cluster_mappings[i]) { + do_continue = 1; + cluster_mappings[i] = k; + } + } + } + // Create a mapping from a cluster id to its minimal version. + cluster_max = 0; + memset(cluster_mappings_tmp, 0, + set->max_size * sizeof(*cluster_mappings_tmp)); + assert(cluster_mappings[0] == 0); + // Re-map the ids. + for (i = 0; i < set->max_size; ++i) { + int cluster; + if (symbols[i] == kInvalidHistogramSymbol) continue; + cluster = cluster_mappings[symbols[i]]; + assert(symbols[i] < num_clusters); + if (cluster > 0 && cluster_mappings_tmp[cluster] == 0) { + ++cluster_max; + cluster_mappings_tmp[cluster] = cluster_max; + } + symbols[i] = cluster_mappings_tmp[cluster]; + } + + // Make sure all cluster values are used. + cluster_max = 0; + for (i = 0; i < set->max_size; ++i) { + if (symbols[i] == kInvalidHistogramSymbol) continue; + if (symbols[i] <= cluster_max) continue; + ++cluster_max; + assert(symbols[i] == cluster_max); + } +} + +static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) { + uint32_t size; + int i; + for (i = 0, size = 0; i < image_histo->size; ++i) { + if (image_histo->histograms[i] == NULL) continue; + image_histo->histograms[size++] = image_histo->histograms[i]; + } + image_histo->size = size; +} + +int VP8LGetHistoImageSymbols(int xsize, int ysize, + const VP8LBackwardRefs* const refs, int quality, + int low_effort, int histogram_bits, int cache_bits, + VP8LHistogramSet* const image_histo, + VP8LHistogram* const tmp_histo, + uint16_t* const histogram_symbols, + const WebPPicture* const pic, int percent_range, + int* const percent) { + const int histo_xsize = + histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1; + const int histo_ysize = + histogram_bits ? VP8LSubSampleSize(ysize, histogram_bits) : 1; + const int image_histo_raw_size = histo_xsize * histo_ysize; + VP8LHistogramSet* const orig_histo = + VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits); + // Don't attempt linear bin-partition heuristic for + // histograms of small sizes (as bin_map will be very sparse) and + // maximum quality q==100 (to preserve the compression gains at that level). + const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE; + int entropy_combine; + uint16_t* const map_tmp = + WebPSafeMalloc(2 * image_histo_raw_size, sizeof(*map_tmp)); + uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size; + int num_used = image_histo_raw_size; + if (orig_histo == NULL || map_tmp == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + // Construct the histograms from backward references. + HistogramBuild(xsize, histogram_bits, refs, orig_histo); + // Copies the histograms and computes its bit_cost. + // histogram_symbols is optimized + HistogramCopyAndAnalyze(orig_histo, image_histo, &num_used, + histogram_symbols); + + entropy_combine = + (num_used > entropy_combine_num_bins * 2) && (quality < 100); + + if (entropy_combine) { + uint16_t* const bin_map = map_tmp; + const float combine_cost_factor = + GetCombineCostFactor(image_histo_raw_size, quality); + const uint32_t num_clusters = num_used; + + HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort); + // Collapse histograms with similar entropy. + HistogramCombineEntropyBin( + image_histo, &num_used, histogram_symbols, cluster_mappings, tmp_histo, + bin_map, entropy_combine_num_bins, combine_cost_factor, low_effort); + OptimizeHistogramSymbols(image_histo, cluster_mappings, num_clusters, + map_tmp, histogram_symbols); + } + + // Don't combine the histograms using stochastic and greedy heuristics for + // low-effort compression mode. + if (!low_effort || !entropy_combine) { + const float x = quality / 100.f; + // cubic ramp between 1 and MAX_HISTO_GREEDY: + const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1)); + int do_greedy; + if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size, + &do_greedy)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + if (do_greedy) { + RemoveEmptyHistograms(image_histo); + if (!HistogramCombineGreedy(image_histo, &num_used)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + } + } + + // Find the optimal map from original histograms to the final ones. + RemoveEmptyHistograms(image_histo); + HistogramRemap(orig_histo, image_histo, histogram_symbols); + + if (!WebPReportProgress(pic, *percent + percent_range, percent)) { + goto Error; + } + + Error: + VP8LFreeHistogramSet(orig_histo); + WebPSafeFree(map_tmp); + return (pic->error_code == VP8_ENC_OK); +} diff --git a/libraries/webp/src/enc/histogram_enc.h b/libraries/webp/src/enc/histogram_enc.h new file mode 100644 index 00000000000..719a31b3435 --- /dev/null +++ b/libraries/webp/src/enc/histogram_enc.h @@ -0,0 +1,130 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// +// Models the histograms of literal and distance codes. + +#ifndef WEBP_ENC_HISTOGRAM_ENC_H_ +#define WEBP_ENC_HISTOGRAM_ENC_H_ + +#include + +#include "src/enc/backward_references_enc.h" +#include "include/webp/format_constants.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Not a trivial literal symbol. +#define VP8L_NON_TRIVIAL_SYM (0xffffffff) + +// A simple container for histograms of data. +typedef struct { + // literal_ contains green literal, palette-code and + // copy-length-prefix histogram + uint32_t* literal_; // Pointer to the allocated buffer for literal. + uint32_t red_[NUM_LITERAL_CODES]; + uint32_t blue_[NUM_LITERAL_CODES]; + uint32_t alpha_[NUM_LITERAL_CODES]; + // Backward reference prefix-code histogram. + uint32_t distance_[NUM_DISTANCE_CODES]; + int palette_code_bits_; + uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha + // literal symbols are single valued. + float bit_cost_; // cached value of bit cost. + float literal_cost_; // Cached values of dominant entropy costs: + float red_cost_; // literal, red & blue. + float blue_cost_; + uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance +} VP8LHistogram; + +// Collection of histograms with fixed capacity, allocated as one +// big memory chunk. Can be destroyed by calling WebPSafeFree(). +typedef struct { + int size; // number of slots currently in use + int max_size; // maximum capacity + VP8LHistogram** histograms; +} VP8LHistogramSet; + +// Create the histogram. +// +// The input data is the PixOrCopy data, which models the literals, stop +// codes and backward references (both distances and lengths). Also: if +// palette_code_bits is >= 0, initialize the histogram with this value. +void VP8LHistogramCreate(VP8LHistogram* const p, + const VP8LBackwardRefs* const refs, + int palette_code_bits); + +// Return the size of the histogram for a given cache_bits. +int VP8LGetHistogramSize(int cache_bits); + +// Set the palette_code_bits and reset the stats. +// If init_arrays is true, the arrays are also filled with 0's. +void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits, + int init_arrays); + +// Collect all the references into a histogram (without reset) +void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, + VP8LHistogram* const histo); + +// Free the memory allocated for the histogram. +void VP8LFreeHistogram(VP8LHistogram* const histo); + +// Free the memory allocated for the histogram set. +void VP8LFreeHistogramSet(VP8LHistogramSet* const histo); + +// Allocate an array of pointer to histograms, allocated and initialized +// using 'cache_bits'. Return NULL in case of memory error. +VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits); + +// Set the histograms in set to 0. +void VP8LHistogramSetClear(VP8LHistogramSet* const set); + +// Allocate and initialize histogram object with specified 'cache_bits'. +// Returns NULL in case of memory error. +// Special case of VP8LAllocateHistogramSet, with size equals 1. +VP8LHistogram* VP8LAllocateHistogram(int cache_bits); + +// Accumulate a token 'v' into a histogram. +void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, + const PixOrCopy* const v, + int (*const distance_modifier)(int, int), + int distance_modifier_arg0); + +static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) { + return NUM_LITERAL_CODES + NUM_LENGTH_CODES + + ((palette_code_bits > 0) ? (1 << palette_code_bits) : 0); +} + +// Builds the histogram image. pic and percent are for progress. +// Returns false in case of error (stored in pic->error_code). +int VP8LGetHistoImageSymbols(int xsize, int ysize, + const VP8LBackwardRefs* const refs, int quality, + int low_effort, int histogram_bits, int cache_bits, + VP8LHistogramSet* const image_histo, + VP8LHistogram* const tmp_histo, + uint16_t* const histogram_symbols, + const WebPPicture* const pic, int percent_range, + int* const percent); + +// Returns the entropy for the symbols in the input array. +float VP8LBitsEntropy(const uint32_t* const array, int n); + +// Estimate how many bits the combined entropy of literals and distance +// approximately maps to. +float VP8LHistogramEstimateBits(VP8LHistogram* const p); + +#ifdef __cplusplus +} +#endif + +#endif // WEBP_ENC_HISTOGRAM_ENC_H_ diff --git a/libraries/webp/src/enc/iterator_enc.c b/libraries/webp/src/enc/iterator_enc.c new file mode 100644 index 00000000000..29f91d8315b --- /dev/null +++ b/libraries/webp/src/enc/iterator_enc.c @@ -0,0 +1,459 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// VP8Iterator: block iterator +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/enc/vp8i_enc.h" + +//------------------------------------------------------------------------------ +// VP8Iterator +//------------------------------------------------------------------------------ + +static void InitLeft(VP8EncIterator* const it) { + it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = + (it->y_ > 0) ? 129 : 127; + memset(it->y_left_, 129, 16); + memset(it->u_left_, 129, 8); + memset(it->v_left_, 129, 8); + it->left_nz_[8] = 0; + if (it->top_derr_ != NULL) { + memset(&it->left_derr_, 0, sizeof(it->left_derr_)); + } +} + +static void InitTop(VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + const size_t top_size = enc->mb_w_ * 16; + memset(enc->y_top_, 127, 2 * top_size); + memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_)); + if (enc->top_derr_ != NULL) { + memset(enc->top_derr_, 0, enc->mb_w_ * sizeof(*enc->top_derr_)); + } +} + +void VP8IteratorSetRow(VP8EncIterator* const it, int y) { + VP8Encoder* const enc = it->enc_; + it->x_ = 0; + it->y_ = y; + it->bw_ = &enc->parts_[y & (enc->num_parts_ - 1)]; + it->preds_ = enc->preds_ + y * 4 * enc->preds_w_; + it->nz_ = enc->nz_; + it->mb_ = enc->mb_info_ + y * enc->mb_w_; + it->y_top_ = enc->y_top_; + it->uv_top_ = enc->uv_top_; + InitLeft(it); +} + +void VP8IteratorReset(VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + VP8IteratorSetRow(it, 0); + VP8IteratorSetCountDown(it, enc->mb_w_ * enc->mb_h_); // default + InitTop(it); + memset(it->bit_count_, 0, sizeof(it->bit_count_)); + it->do_trellis_ = 0; +} + +void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down) { + it->count_down_ = it->count_down0_ = count_down; +} + +int VP8IteratorIsDone(const VP8EncIterator* const it) { + return (it->count_down_ <= 0); +} + +void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) { + it->enc_ = enc; + it->yuv_in_ = (uint8_t*)WEBP_ALIGN(it->yuv_mem_); + it->yuv_out_ = it->yuv_in_ + YUV_SIZE_ENC; + it->yuv_out2_ = it->yuv_out_ + YUV_SIZE_ENC; + it->yuv_p_ = it->yuv_out2_ + YUV_SIZE_ENC; + it->lf_stats_ = enc->lf_stats_; + it->percent0_ = enc->percent_; + it->y_left_ = (uint8_t*)WEBP_ALIGN(it->yuv_left_mem_ + 1); + it->u_left_ = it->y_left_ + 16 + 16; + it->v_left_ = it->u_left_ + 16; + it->top_derr_ = enc->top_derr_; + VP8IteratorReset(it); +} + +int VP8IteratorProgress(const VP8EncIterator* const it, int delta) { + VP8Encoder* const enc = it->enc_; + if (delta && enc->pic_->progress_hook != NULL) { + const int done = it->count_down0_ - it->count_down_; + const int percent = (it->count_down0_ <= 0) + ? it->percent0_ + : it->percent0_ + delta * done / it->count_down0_; + return WebPReportProgress(enc->pic_, percent, &enc->percent_); + } + return 1; +} + +//------------------------------------------------------------------------------ +// Import the source samples into the cache. Takes care of replicating +// boundary pixels if necessary. + +static WEBP_INLINE int MinSize(int a, int b) { return (a < b) ? a : b; } + +static void ImportBlock(const uint8_t* src, int src_stride, + uint8_t* dst, int w, int h, int size) { + int i; + for (i = 0; i < h; ++i) { + memcpy(dst, src, w); + if (w < size) { + memset(dst + w, dst[w - 1], size - w); + } + dst += BPS; + src += src_stride; + } + for (i = h; i < size; ++i) { + memcpy(dst, dst - BPS, size); + dst += BPS; + } +} + +static void ImportLine(const uint8_t* src, int src_stride, + uint8_t* dst, int len, int total_len) { + int i; + for (i = 0; i < len; ++i, src += src_stride) dst[i] = *src; + for (; i < total_len; ++i) dst[i] = dst[len - 1]; +} + +void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32) { + const VP8Encoder* const enc = it->enc_; + const int x = it->x_, y = it->y_; + const WebPPicture* const pic = enc->pic_; + const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16; + const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8; + const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8; + const int w = MinSize(pic->width - x * 16, 16); + const int h = MinSize(pic->height - y * 16, 16); + const int uv_w = (w + 1) >> 1; + const int uv_h = (h + 1) >> 1; + + ImportBlock(ysrc, pic->y_stride, it->yuv_in_ + Y_OFF_ENC, w, h, 16); + ImportBlock(usrc, pic->uv_stride, it->yuv_in_ + U_OFF_ENC, uv_w, uv_h, 8); + ImportBlock(vsrc, pic->uv_stride, it->yuv_in_ + V_OFF_ENC, uv_w, uv_h, 8); + + if (tmp_32 == NULL) return; + + // Import source (uncompressed) samples into boundary. + if (x == 0) { + InitLeft(it); + } else { + if (y == 0) { + it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = 127; + } else { + it->y_left_[-1] = ysrc[- 1 - pic->y_stride]; + it->u_left_[-1] = usrc[- 1 - pic->uv_stride]; + it->v_left_[-1] = vsrc[- 1 - pic->uv_stride]; + } + ImportLine(ysrc - 1, pic->y_stride, it->y_left_, h, 16); + ImportLine(usrc - 1, pic->uv_stride, it->u_left_, uv_h, 8); + ImportLine(vsrc - 1, pic->uv_stride, it->v_left_, uv_h, 8); + } + + it->y_top_ = tmp_32 + 0; + it->uv_top_ = tmp_32 + 16; + if (y == 0) { + memset(tmp_32, 127, 32 * sizeof(*tmp_32)); + } else { + ImportLine(ysrc - pic->y_stride, 1, tmp_32, w, 16); + ImportLine(usrc - pic->uv_stride, 1, tmp_32 + 16, uv_w, 8); + ImportLine(vsrc - pic->uv_stride, 1, tmp_32 + 16 + 8, uv_w, 8); + } +} + +//------------------------------------------------------------------------------ +// Copy back the compressed samples into user space if requested. + +static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride, + int w, int h) { + while (h-- > 0) { + memcpy(dst, src, w); + dst += dst_stride; + src += BPS; + } +} + +void VP8IteratorExport(const VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + if (enc->config_->show_compressed) { + const int x = it->x_, y = it->y_; + const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC; + const uint8_t* const usrc = it->yuv_out_ + U_OFF_ENC; + const uint8_t* const vsrc = it->yuv_out_ + V_OFF_ENC; + const WebPPicture* const pic = enc->pic_; + uint8_t* const ydst = pic->y + (y * pic->y_stride + x) * 16; + uint8_t* const udst = pic->u + (y * pic->uv_stride + x) * 8; + uint8_t* const vdst = pic->v + (y * pic->uv_stride + x) * 8; + int w = (pic->width - x * 16); + int h = (pic->height - y * 16); + + if (w > 16) w = 16; + if (h > 16) h = 16; + + // Luma plane + ExportBlock(ysrc, ydst, pic->y_stride, w, h); + + { // U/V planes + const int uv_w = (w + 1) >> 1; + const int uv_h = (h + 1) >> 1; + ExportBlock(usrc, udst, pic->uv_stride, uv_w, uv_h); + ExportBlock(vsrc, vdst, pic->uv_stride, uv_w, uv_h); + } + } +} + +//------------------------------------------------------------------------------ +// Non-zero contexts setup/teardown + +// Nz bits: +// 0 1 2 3 Y +// 4 5 6 7 +// 8 9 10 11 +// 12 13 14 15 +// 16 17 U +// 18 19 +// 20 21 V +// 22 23 +// 24 DC-intra16 + +// Convert packed context to byte array +#define BIT(nz, n) (!!((nz) & (1 << (n)))) + +void VP8IteratorNzToBytes(VP8EncIterator* const it) { + const int tnz = it->nz_[0], lnz = it->nz_[-1]; + int* const top_nz = it->top_nz_; + int* const left_nz = it->left_nz_; + + // Top-Y + top_nz[0] = BIT(tnz, 12); + top_nz[1] = BIT(tnz, 13); + top_nz[2] = BIT(tnz, 14); + top_nz[3] = BIT(tnz, 15); + // Top-U + top_nz[4] = BIT(tnz, 18); + top_nz[5] = BIT(tnz, 19); + // Top-V + top_nz[6] = BIT(tnz, 22); + top_nz[7] = BIT(tnz, 23); + // DC + top_nz[8] = BIT(tnz, 24); + + // left-Y + left_nz[0] = BIT(lnz, 3); + left_nz[1] = BIT(lnz, 7); + left_nz[2] = BIT(lnz, 11); + left_nz[3] = BIT(lnz, 15); + // left-U + left_nz[4] = BIT(lnz, 17); + left_nz[5] = BIT(lnz, 19); + // left-V + left_nz[6] = BIT(lnz, 21); + left_nz[7] = BIT(lnz, 23); + // left-DC is special, iterated separately +} + +void VP8IteratorBytesToNz(VP8EncIterator* const it) { + uint32_t nz = 0; + const int* const top_nz = it->top_nz_; + const int* const left_nz = it->left_nz_; + // top + nz |= (top_nz[0] << 12) | (top_nz[1] << 13); + nz |= (top_nz[2] << 14) | (top_nz[3] << 15); + nz |= (top_nz[4] << 18) | (top_nz[5] << 19); + nz |= (top_nz[6] << 22) | (top_nz[7] << 23); + nz |= (top_nz[8] << 24); // we propagate the _top_ bit, esp. for intra4 + // left + nz |= (left_nz[0] << 3) | (left_nz[1] << 7); + nz |= (left_nz[2] << 11); + nz |= (left_nz[4] << 17) | (left_nz[6] << 21); + + *it->nz_ = nz; +} + +#undef BIT + +//------------------------------------------------------------------------------ +// Advance to the next position, doing the bookkeeping. + +void VP8IteratorSaveBoundary(VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + const int x = it->x_, y = it->y_; + const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC; + const uint8_t* const uvsrc = it->yuv_out_ + U_OFF_ENC; + if (x < enc->mb_w_ - 1) { // left + int i; + for (i = 0; i < 16; ++i) { + it->y_left_[i] = ysrc[15 + i * BPS]; + } + for (i = 0; i < 8; ++i) { + it->u_left_[i] = uvsrc[7 + i * BPS]; + it->v_left_[i] = uvsrc[15 + i * BPS]; + } + // top-left (before 'top'!) + it->y_left_[-1] = it->y_top_[15]; + it->u_left_[-1] = it->uv_top_[0 + 7]; + it->v_left_[-1] = it->uv_top_[8 + 7]; + } + if (y < enc->mb_h_ - 1) { // top + memcpy(it->y_top_, ysrc + 15 * BPS, 16); + memcpy(it->uv_top_, uvsrc + 7 * BPS, 8 + 8); + } +} + +int VP8IteratorNext(VP8EncIterator* const it) { + if (++it->x_ == it->enc_->mb_w_) { + VP8IteratorSetRow(it, ++it->y_); + } else { + it->preds_ += 4; + it->mb_ += 1; + it->nz_ += 1; + it->y_top_ += 16; + it->uv_top_ += 16; + } + return (0 < --it->count_down_); +} + +//------------------------------------------------------------------------------ +// Helper function to set mode properties + +void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) { + uint8_t* preds = it->preds_; + int y; + for (y = 0; y < 4; ++y) { + memset(preds, mode, 4); + preds += it->enc_->preds_w_; + } + it->mb_->type_ = 1; +} + +void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes) { + uint8_t* preds = it->preds_; + int y; + for (y = 4; y > 0; --y) { + memcpy(preds, modes, 4 * sizeof(*modes)); + preds += it->enc_->preds_w_; + modes += 4; + } + it->mb_->type_ = 0; +} + +void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode) { + it->mb_->uv_mode_ = mode; +} + +void VP8SetSkip(const VP8EncIterator* const it, int skip) { + it->mb_->skip_ = skip; +} + +void VP8SetSegment(const VP8EncIterator* const it, int segment) { + it->mb_->segment_ = segment; +} + +//------------------------------------------------------------------------------ +// Intra4x4 sub-blocks iteration +// +// We store and update the boundary samples into an array of 37 pixels. They +// are updated as we iterate and reconstructs each intra4x4 blocks in turn. +// The position of the samples has the following snake pattern: +// +// 16|17 18 19 20|21 22 23 24|25 26 27 28|29 30 31 32|33 34 35 36 <- Top-right +// --+-----------+-----------+-----------+-----------+ +// 15| 19| 23| 27| 31| +// 14| 18| 22| 26| 30| +// 13| 17| 21| 25| 29| +// 12|13 14 15 16|17 18 19 20|21 22 23 24|25 26 27 28| +// --+-----------+-----------+-----------+-----------+ +// 11| 15| 19| 23| 27| +// 10| 14| 18| 22| 26| +// 9| 13| 17| 21| 25| +// 8| 9 10 11 12|13 14 15 16|17 18 19 20|21 22 23 24| +// --+-----------+-----------+-----------+-----------+ +// 7| 11| 15| 19| 23| +// 6| 10| 14| 18| 22| +// 5| 9| 13| 17| 21| +// 4| 5 6 7 8| 9 10 11 12|13 14 15 16|17 18 19 20| +// --+-----------+-----------+-----------+-----------+ +// 3| 7| 11| 15| 19| +// 2| 6| 10| 14| 18| +// 1| 5| 9| 13| 17| +// 0| 1 2 3 4| 5 6 7 8| 9 10 11 12|13 14 15 16| +// --+-----------+-----------+-----------+-----------+ + +// Array to record the position of the top sample to pass to the prediction +// functions in dsp.c. +static const uint8_t VP8TopLeftI4[16] = { + 17, 21, 25, 29, + 13, 17, 21, 25, + 9, 13, 17, 21, + 5, 9, 13, 17 +}; + +void VP8IteratorStartI4(VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + int i; + + it->i4_ = 0; // first 4x4 sub-block + it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[0]; + + // Import the boundary samples + for (i = 0; i < 17; ++i) { // left + it->i4_boundary_[i] = it->y_left_[15 - i]; + } + for (i = 0; i < 16; ++i) { // top + it->i4_boundary_[17 + i] = it->y_top_[i]; + } + // top-right samples have a special case on the far right of the picture + if (it->x_ < enc->mb_w_ - 1) { + for (i = 16; i < 16 + 4; ++i) { + it->i4_boundary_[17 + i] = it->y_top_[i]; + } + } else { // else, replicate the last valid pixel four times + for (i = 16; i < 16 + 4; ++i) { + it->i4_boundary_[17 + i] = it->i4_boundary_[17 + 15]; + } + } + VP8IteratorNzToBytes(it); // import the non-zero context +} + +int VP8IteratorRotateI4(VP8EncIterator* const it, + const uint8_t* const yuv_out) { + const uint8_t* const blk = yuv_out + VP8Scan[it->i4_]; + uint8_t* const top = it->i4_top_; + int i; + + // Update the cache with 7 fresh samples + for (i = 0; i <= 3; ++i) { + top[-4 + i] = blk[i + 3 * BPS]; // store future top samples + } + if ((it->i4_ & 3) != 3) { // if not on the right sub-blocks #3, #7, #11, #15 + for (i = 0; i <= 2; ++i) { // store future left samples + top[i] = blk[3 + (2 - i) * BPS]; + } + } else { // else replicate top-right samples, as says the specs. + for (i = 0; i <= 3; ++i) { + top[i] = top[i + 4]; + } + } + // move pointers to next sub-block + ++it->i4_; + if (it->i4_ == 16) { // we're done + return 0; + } + + it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[it->i4_]; + return 1; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/enc/near_lossless_enc.c b/libraries/webp/src/enc/near_lossless_enc.c new file mode 100644 index 00000000000..5517a7e2711 --- /dev/null +++ b/libraries/webp/src/enc/near_lossless_enc.c @@ -0,0 +1,151 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Near-lossless image preprocessing adjusts pixel values to help +// compressibility with a guarantee of maximum deviation between original and +// resulting pixel values. +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// Converted to C by Aleksander Kramarz (akramarz@google.com) + +#include +#include + +#include "src/dsp/lossless_common.h" +#include "src/utils/utils.h" +#include "src/enc/vp8li_enc.h" + +#if (WEBP_NEAR_LOSSLESS == 1) + +#define MIN_DIM_FOR_NEAR_LOSSLESS 64 +#define MAX_LIMIT_BITS 5 + +// Quantizes the value up or down to a multiple of 1<> 1) + ((a >> bits) & 1); + assert(bits > 0); + if (biased > 0xff) return 0xff; + return biased & ~mask; +} + +// Applies FindClosestDiscretized to all channels of pixel. +static uint32_t ClosestDiscretizedArgb(uint32_t a, int bits) { + return + (FindClosestDiscretized(a >> 24, bits) << 24) | + (FindClosestDiscretized((a >> 16) & 0xff, bits) << 16) | + (FindClosestDiscretized((a >> 8) & 0xff, bits) << 8) | + (FindClosestDiscretized(a & 0xff, bits)); +} + +// Checks if distance between corresponding channel values of pixels a and b +// is within the given limit. +static int IsNear(uint32_t a, uint32_t b, int limit) { + int k; + for (k = 0; k < 4; ++k) { + const int delta = + (int)((a >> (k * 8)) & 0xff) - (int)((b >> (k * 8)) & 0xff); + if (delta >= limit || delta <= -limit) { + return 0; + } + } + return 1; +} + +static int IsSmooth(const uint32_t* const prev_row, + const uint32_t* const curr_row, + const uint32_t* const next_row, + int ix, int limit) { + // Check that all pixels in 4-connected neighborhood are smooth. + return (IsNear(curr_row[ix], curr_row[ix - 1], limit) && + IsNear(curr_row[ix], curr_row[ix + 1], limit) && + IsNear(curr_row[ix], prev_row[ix], limit) && + IsNear(curr_row[ix], next_row[ix], limit)); +} + +// Adjusts pixel values of image with given maximum error. +static void NearLossless(int xsize, int ysize, const uint32_t* argb_src, + int stride, int limit_bits, uint32_t* copy_buffer, + uint32_t* argb_dst) { + int x, y; + const int limit = 1 << limit_bits; + uint32_t* prev_row = copy_buffer; + uint32_t* curr_row = prev_row + xsize; + uint32_t* next_row = curr_row + xsize; + memcpy(curr_row, argb_src, xsize * sizeof(argb_src[0])); + memcpy(next_row, argb_src + stride, xsize * sizeof(argb_src[0])); + + for (y = 0; y < ysize; ++y, argb_src += stride, argb_dst += xsize) { + if (y == 0 || y == ysize - 1) { + memcpy(argb_dst, argb_src, xsize * sizeof(argb_src[0])); + } else { + memcpy(next_row, argb_src + stride, xsize * sizeof(argb_src[0])); + argb_dst[0] = argb_src[0]; + argb_dst[xsize - 1] = argb_src[xsize - 1]; + for (x = 1; x < xsize - 1; ++x) { + if (IsSmooth(prev_row, curr_row, next_row, x, limit)) { + argb_dst[x] = curr_row[x]; + } else { + argb_dst[x] = ClosestDiscretizedArgb(curr_row[x], limit_bits); + } + } + } + { + // Three-way swap. + uint32_t* const temp = prev_row; + prev_row = curr_row; + curr_row = next_row; + next_row = temp; + } + } +} + +int VP8ApplyNearLossless(const WebPPicture* const picture, int quality, + uint32_t* const argb_dst) { + int i; + const int xsize = picture->width; + const int ysize = picture->height; + const int stride = picture->argb_stride; + uint32_t* const copy_buffer = + (uint32_t*)WebPSafeMalloc(xsize * 3, sizeof(*copy_buffer)); + const int limit_bits = VP8LNearLosslessBits(quality); + assert(argb_dst != NULL); + assert(limit_bits > 0); + assert(limit_bits <= MAX_LIMIT_BITS); + if (copy_buffer == NULL) { + return 0; + } + // For small icon images, don't attempt to apply near-lossless compression. + if ((xsize < MIN_DIM_FOR_NEAR_LOSSLESS && + ysize < MIN_DIM_FOR_NEAR_LOSSLESS) || + ysize < 3) { + for (i = 0; i < ysize; ++i) { + memcpy(argb_dst + i * xsize, picture->argb + i * picture->argb_stride, + xsize * sizeof(*argb_dst)); + } + WebPSafeFree(copy_buffer); + return 1; + } + + NearLossless(xsize, ysize, picture->argb, stride, limit_bits, copy_buffer, + argb_dst); + for (i = limit_bits - 1; i != 0; --i) { + NearLossless(xsize, ysize, argb_dst, xsize, i, copy_buffer, argb_dst); + } + WebPSafeFree(copy_buffer); + return 1; +} +#else // (WEBP_NEAR_LOSSLESS == 1) + +// Define a stub to suppress compiler warnings. +extern void VP8LNearLosslessStub(void); +void VP8LNearLosslessStub(void) {} + +#endif // (WEBP_NEAR_LOSSLESS == 1) diff --git a/libraries/webp/src/enc/picture_csp_enc.c b/libraries/webp/src/enc/picture_csp_enc.c new file mode 100644 index 00000000000..a9280e6c305 --- /dev/null +++ b/libraries/webp/src/enc/picture_csp_enc.c @@ -0,0 +1,846 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebPPicture utils for colorspace conversion +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include + +#include "sharpyuv/sharpyuv.h" +#include "sharpyuv/sharpyuv_csp.h" +#include "src/enc/vp8i_enc.h" +#include "src/utils/random_utils.h" +#include "src/utils/utils.h" +#include "src/dsp/dsp.h" +#include "src/dsp/lossless.h" +#include "src/dsp/yuv.h" +#include "src/dsp/cpu.h" + +#if defined(WEBP_USE_THREAD) && !defined(_WIN32) +#include +#endif + +// Uncomment to disable gamma-compression during RGB->U/V averaging +#define USE_GAMMA_COMPRESSION + +// If defined, use table to compute x / alpha. +#define USE_INVERSE_ALPHA_TABLE + +#ifdef WORDS_BIGENDIAN +// uint32_t 0xff000000 is 0xff,00,00,00 in memory +#define CHANNEL_OFFSET(i) (i) +#else +// uint32_t 0xff000000 is 0x00,00,00,ff in memory +#define CHANNEL_OFFSET(i) (3-(i)) +#endif + +#define ALPHA_OFFSET CHANNEL_OFFSET(0) + +//------------------------------------------------------------------------------ +// Detection of non-trivial transparency + +// Returns true if alpha[] has non-0xff values. +static int CheckNonOpaque(const uint8_t* alpha, int width, int height, + int x_step, int y_step) { + if (alpha == NULL) return 0; + WebPInitAlphaProcessing(); + if (x_step == 1) { + for (; height-- > 0; alpha += y_step) { + if (WebPHasAlpha8b(alpha, width)) return 1; + } + } else { + for (; height-- > 0; alpha += y_step) { + if (WebPHasAlpha32b(alpha, width)) return 1; + } + } + return 0; +} + +// Checking for the presence of non-opaque alpha. +int WebPPictureHasTransparency(const WebPPicture* picture) { + if (picture == NULL) return 0; + if (picture->use_argb) { + if (picture->argb != NULL) { + return CheckNonOpaque((const uint8_t*)picture->argb + ALPHA_OFFSET, + picture->width, picture->height, + 4, picture->argb_stride * sizeof(*picture->argb)); + } + return 0; + } + return CheckNonOpaque(picture->a, picture->width, picture->height, + 1, picture->a_stride); +} + +//------------------------------------------------------------------------------ +// Code for gamma correction + +#if defined(USE_GAMMA_COMPRESSION) + +// Gamma correction compensates loss of resolution during chroma subsampling. +#define GAMMA_FIX 12 // fixed-point precision for linear values +#define GAMMA_TAB_FIX 7 // fixed-point fractional bits precision +#define GAMMA_TAB_SIZE (1 << (GAMMA_FIX - GAMMA_TAB_FIX)) +static const double kGamma = 0.80; +static const int kGammaScale = ((1 << GAMMA_FIX) - 1); +static const int kGammaTabScale = (1 << GAMMA_TAB_FIX); +static const int kGammaTabRounder = (1 << GAMMA_TAB_FIX >> 1); + +static int kLinearToGammaTab[GAMMA_TAB_SIZE + 1]; +static uint16_t kGammaToLinearTab[256]; +static volatile int kGammaTablesOk = 0; +static void InitGammaTables(void); +extern VP8CPUInfo VP8GetCPUInfo; + +WEBP_DSP_INIT_FUNC(InitGammaTables) { + if (!kGammaTablesOk) { + int v; + const double scale = (double)(1 << GAMMA_TAB_FIX) / kGammaScale; + const double norm = 1. / 255.; + for (v = 0; v <= 255; ++v) { + kGammaToLinearTab[v] = + (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5); + } + for (v = 0; v <= GAMMA_TAB_SIZE; ++v) { + kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5); + } + kGammaTablesOk = 1; + } +} + +static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { + return kGammaToLinearTab[v]; +} + +static WEBP_INLINE int Interpolate(int v) { + const int tab_pos = v >> (GAMMA_TAB_FIX + 2); // integer part + const int x = v & ((kGammaTabScale << 2) - 1); // fractional part + const int v0 = kLinearToGammaTab[tab_pos]; + const int v1 = kLinearToGammaTab[tab_pos + 1]; + const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x); // interpolate + assert(tab_pos + 1 < GAMMA_TAB_SIZE + 1); + return y; +} + +// Convert a linear value 'v' to YUV_FIX+2 fixed-point precision +// U/V value, suitable for RGBToU/V calls. +static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { + const int y = Interpolate(base_value << shift); // final uplifted value + return (y + kGammaTabRounder) >> GAMMA_TAB_FIX; // descale +} + +#else + +static void InitGammaTables(void) {} +static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; } +static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { + return (int)(base_value << shift); +} + +#endif // USE_GAMMA_COMPRESSION + +//------------------------------------------------------------------------------ +// RGB -> YUV conversion + +static int RGBToY(int r, int g, int b, VP8Random* const rg) { + return (rg == NULL) ? VP8RGBToY(r, g, b, YUV_HALF) + : VP8RGBToY(r, g, b, VP8RandomBits(rg, YUV_FIX)); +} + +static int RGBToU(int r, int g, int b, VP8Random* const rg) { + return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2) + : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2)); +} + +static int RGBToV(int r, int g, int b, VP8Random* const rg) { + return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2) + : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2)); +} + +//------------------------------------------------------------------------------ +// Sharp RGB->YUV conversion + +static const int kMinDimensionIterativeConversion = 4; + +//------------------------------------------------------------------------------ +// Main function + +static int PreprocessARGB(const uint8_t* r_ptr, + const uint8_t* g_ptr, + const uint8_t* b_ptr, + int step, int rgb_stride, + WebPPicture* const picture) { + const int ok = SharpYuvConvert( + r_ptr, g_ptr, b_ptr, step, rgb_stride, /*rgb_bit_depth=*/8, + picture->y, picture->y_stride, picture->u, picture->uv_stride, picture->v, + picture->uv_stride, /*yuv_bit_depth=*/8, picture->width, + picture->height, SharpYuvGetConversionMatrix(kSharpYuvMatrixWebp)); + if (!ok) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + return ok; +} + +//------------------------------------------------------------------------------ +// "Fast" regular RGB->YUV + +#define SUM4(ptr, step) LinearToGamma( \ + GammaToLinear((ptr)[0]) + \ + GammaToLinear((ptr)[(step)]) + \ + GammaToLinear((ptr)[rgb_stride]) + \ + GammaToLinear((ptr)[rgb_stride + (step)]), 0) \ + +#define SUM2(ptr) \ + LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1) + +#define SUM2ALPHA(ptr) ((ptr)[0] + (ptr)[rgb_stride]) +#define SUM4ALPHA(ptr) (SUM2ALPHA(ptr) + SUM2ALPHA((ptr) + 4)) + +#if defined(USE_INVERSE_ALPHA_TABLE) + +static const int kAlphaFix = 19; +// Following table is (1 << kAlphaFix) / a. The (v * kInvAlpha[a]) >> kAlphaFix +// formula is then equal to v / a in most (99.6%) cases. Note that this table +// and constant are adjusted very tightly to fit 32b arithmetic. +// In particular, they use the fact that the operands for 'v / a' are actually +// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3 +// with ai in [0..255] and pi in [0..1<> (kAlphaFix - 2)) + +#else + +#define DIVIDE_BY_ALPHA(sum, a) (4 * (sum) / (a)) + +#endif // USE_INVERSE_ALPHA_TABLE + +static WEBP_INLINE int LinearToGammaWeighted(const uint8_t* src, + const uint8_t* a_ptr, + uint32_t total_a, int step, + int rgb_stride) { + const uint32_t sum = + a_ptr[0] * GammaToLinear(src[0]) + + a_ptr[step] * GammaToLinear(src[step]) + + a_ptr[rgb_stride] * GammaToLinear(src[rgb_stride]) + + a_ptr[rgb_stride + step] * GammaToLinear(src[rgb_stride + step]); + assert(total_a > 0 && total_a <= 4 * 0xff); +#if defined(USE_INVERSE_ALPHA_TABLE) + assert((uint64_t)sum * kInvAlpha[total_a] < ((uint64_t)1 << 32)); +#endif + return LinearToGamma(DIVIDE_BY_ALPHA(sum, total_a), 0); +} + +static WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr, + const uint8_t* const g_ptr, + const uint8_t* const b_ptr, + int step, + uint8_t* const dst_y, + int width, + VP8Random* const rg) { + int i, j; + for (i = 0, j = 0; i < width; i += 1, j += step) { + dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg); + } +} + +static WEBP_INLINE void AccumulateRGBA(const uint8_t* const r_ptr, + const uint8_t* const g_ptr, + const uint8_t* const b_ptr, + const uint8_t* const a_ptr, + int rgb_stride, + uint16_t* dst, int width) { + int i, j; + // we loop over 2x2 blocks and produce one R/G/B/A value for each. + for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) { + const uint32_t a = SUM4ALPHA(a_ptr + j); + int r, g, b; + if (a == 4 * 0xff || a == 0) { + r = SUM4(r_ptr + j, 4); + g = SUM4(g_ptr + j, 4); + b = SUM4(b_ptr + j, 4); + } else { + r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride); + g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride); + b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride); + } + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + } + if (width & 1) { + const uint32_t a = 2u * SUM2ALPHA(a_ptr + j); + int r, g, b; + if (a == 4 * 0xff || a == 0) { + r = SUM2(r_ptr + j); + g = SUM2(g_ptr + j); + b = SUM2(b_ptr + j); + } else { + r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride); + g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride); + b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride); + } + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + } +} + +static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr, + const uint8_t* const g_ptr, + const uint8_t* const b_ptr, + int step, int rgb_stride, + uint16_t* dst, int width) { + int i, j; + for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) { + dst[0] = SUM4(r_ptr + j, step); + dst[1] = SUM4(g_ptr + j, step); + dst[2] = SUM4(b_ptr + j, step); + // MemorySanitizer may raise false positives with data that passes through + // RGBA32PackedToPlanar_16b_SSE41() due to incorrect modeling of shuffles. + // See https://crbug.com/webp/573. +#ifdef WEBP_MSAN + dst[3] = 0; +#endif + } + if (width & 1) { + dst[0] = SUM2(r_ptr + j); + dst[1] = SUM2(g_ptr + j); + dst[2] = SUM2(b_ptr + j); +#ifdef WEBP_MSAN + dst[3] = 0; +#endif + } +} + +static WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb, + uint8_t* const dst_u, + uint8_t* const dst_v, + int width, + VP8Random* const rg) { + int i; + for (i = 0; i < width; i += 1, rgb += 4) { + const int r = rgb[0], g = rgb[1], b = rgb[2]; + dst_u[i] = RGBToU(r, g, b, rg); + dst_v[i] = RGBToV(r, g, b, rg); + } +} + +extern void SharpYuvInit(VP8CPUInfo cpu_info_func); + +static int ImportYUVAFromRGBA(const uint8_t* r_ptr, + const uint8_t* g_ptr, + const uint8_t* b_ptr, + const uint8_t* a_ptr, + int step, // bytes per pixel + int rgb_stride, // bytes per scanline + float dithering, + int use_iterative_conversion, + WebPPicture* const picture) { + int y; + const int width = picture->width; + const int height = picture->height; + const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride); + const int is_rgb = (r_ptr < b_ptr); // otherwise it's bgr + + picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420; + picture->use_argb = 0; + + // disable smart conversion if source is too small (overkill). + if (width < kMinDimensionIterativeConversion || + height < kMinDimensionIterativeConversion) { + use_iterative_conversion = 0; + } + + if (!WebPPictureAllocYUVA(picture)) { + return 0; + } + if (has_alpha) { + assert(step == 4); +#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE) + assert(kAlphaFix + GAMMA_FIX <= 31); +#endif + } + + if (use_iterative_conversion) { + SharpYuvInit(VP8GetCPUInfo); + if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) { + return 0; + } + if (has_alpha) { + WebPExtractAlpha(a_ptr, rgb_stride, width, height, + picture->a, picture->a_stride); + } + } else { + const int uv_width = (width + 1) >> 1; + int use_dsp = (step == 3); // use special function in this case + // temporary storage for accumulated R/G/B values during conversion to U/V + uint16_t* const tmp_rgb = + (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb)); + uint8_t* dst_y = picture->y; + uint8_t* dst_u = picture->u; + uint8_t* dst_v = picture->v; + uint8_t* dst_a = picture->a; + + VP8Random base_rg; + VP8Random* rg = NULL; + if (dithering > 0.) { + VP8InitRandom(&base_rg, dithering); + rg = &base_rg; + use_dsp = 0; // can't use dsp in this case + } + WebPInitConvertARGBToYUV(); + InitGammaTables(); + + if (tmp_rgb == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + + // Downsample Y/U/V planes, two rows at a time + for (y = 0; y < (height >> 1); ++y) { + int rows_have_alpha = has_alpha; + if (use_dsp) { + if (is_rgb) { + WebPConvertRGB24ToY(r_ptr, dst_y, width); + WebPConvertRGB24ToY(r_ptr + rgb_stride, + dst_y + picture->y_stride, width); + } else { + WebPConvertBGR24ToY(b_ptr, dst_y, width); + WebPConvertBGR24ToY(b_ptr + rgb_stride, + dst_y + picture->y_stride, width); + } + } else { + ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); + ConvertRowToY(r_ptr + rgb_stride, + g_ptr + rgb_stride, + b_ptr + rgb_stride, step, + dst_y + picture->y_stride, width, rg); + } + dst_y += 2 * picture->y_stride; + if (has_alpha) { + rows_have_alpha &= !WebPExtractAlpha(a_ptr, rgb_stride, width, 2, + dst_a, picture->a_stride); + dst_a += 2 * picture->a_stride; + } + // Collect averaged R/G/B(/A) + if (!rows_have_alpha) { + AccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width); + } else { + AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb, width); + } + // Convert to U/V + if (rg == NULL) { + WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); + } else { + ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); + } + dst_u += picture->uv_stride; + dst_v += picture->uv_stride; + r_ptr += 2 * rgb_stride; + b_ptr += 2 * rgb_stride; + g_ptr += 2 * rgb_stride; + if (has_alpha) a_ptr += 2 * rgb_stride; + } + if (height & 1) { // extra last row + int row_has_alpha = has_alpha; + if (use_dsp) { + if (r_ptr < b_ptr) { + WebPConvertRGB24ToY(r_ptr, dst_y, width); + } else { + WebPConvertBGR24ToY(b_ptr, dst_y, width); + } + } else { + ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); + } + if (row_has_alpha) { + row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0); + } + // Collect averaged R/G/B(/A) + if (!row_has_alpha) { + // Collect averaged R/G/B + AccumulateRGB(r_ptr, g_ptr, b_ptr, step, /* rgb_stride = */ 0, + tmp_rgb, width); + } else { + AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /* rgb_stride = */ 0, + tmp_rgb, width); + } + if (rg == NULL) { + WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); + } else { + ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); + } + } + WebPSafeFree(tmp_rgb); + } + return 1; +} + +#undef SUM4 +#undef SUM2 +#undef SUM4ALPHA +#undef SUM2ALPHA + +//------------------------------------------------------------------------------ +// call for ARGB->YUVA conversion + +static int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace, + float dithering, int use_iterative_conversion) { + if (picture == NULL) return 0; + if (picture->argb == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); + } else if ((colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); + } else { + const uint8_t* const argb = (const uint8_t*)picture->argb; + const uint8_t* const a = argb + CHANNEL_OFFSET(0); + const uint8_t* const r = argb + CHANNEL_OFFSET(1); + const uint8_t* const g = argb + CHANNEL_OFFSET(2); + const uint8_t* const b = argb + CHANNEL_OFFSET(3); + + picture->colorspace = WEBP_YUV420; + return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride, + dithering, use_iterative_conversion, picture); + } +} + +int WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace, + float dithering) { + return PictureARGBToYUVA(picture, colorspace, dithering, 0); +} + +int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) { + return PictureARGBToYUVA(picture, colorspace, 0.f, 0); +} + +int WebPPictureSharpARGBToYUVA(WebPPicture* picture) { + return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1); +} +// for backward compatibility +int WebPPictureSmartARGBToYUVA(WebPPicture* picture) { + return WebPPictureSharpARGBToYUVA(picture); +} + +//------------------------------------------------------------------------------ +// call for YUVA -> ARGB conversion + +int WebPPictureYUVAToARGB(WebPPicture* picture) { + if (picture == NULL) return 0; + if (picture->y == NULL || picture->u == NULL || picture->v == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); + } + if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); + } + if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); + } + // Allocate a new argb buffer (discarding the previous one). + if (!WebPPictureAllocARGB(picture)) return 0; + picture->use_argb = 1; + + // Convert + { + int y; + const int width = picture->width; + const int height = picture->height; + const int argb_stride = 4 * picture->argb_stride; + uint8_t* dst = (uint8_t*)picture->argb; + const uint8_t* cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y; + WebPUpsampleLinePairFunc upsample = + WebPGetLinePairConverter(ALPHA_OFFSET > 0); + + // First row, with replicated top samples. + upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width); + cur_y += picture->y_stride; + dst += argb_stride; + // Center rows. + for (y = 1; y + 1 < height; y += 2) { + const uint8_t* const top_u = cur_u; + const uint8_t* const top_v = cur_v; + cur_u += picture->uv_stride; + cur_v += picture->uv_stride; + upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v, + dst, dst + argb_stride, width); + cur_y += 2 * picture->y_stride; + dst += 2 * argb_stride; + } + // Last row (if needed), with replicated bottom samples. + if (height > 1 && !(height & 1)) { + upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width); + } + // Insert alpha values if needed, in replacement for the default 0xff ones. + if (picture->colorspace & WEBP_CSP_ALPHA_BIT) { + for (y = 0; y < height; ++y) { + uint32_t* const argb_dst = picture->argb + y * picture->argb_stride; + const uint8_t* const src = picture->a + y * picture->a_stride; + int x; + for (x = 0; x < width; ++x) { + argb_dst[x] = (argb_dst[x] & 0x00ffffffu) | ((uint32_t)src[x] << 24); + } + } + } + } + return 1; +} + +//------------------------------------------------------------------------------ +// automatic import / conversion + +static int Import(WebPPicture* const picture, + const uint8_t* rgb, int rgb_stride, + int step, int swap_rb, int import_alpha) { + int y; + // swap_rb -> b,g,r,a , !swap_rb -> r,g,b,a + const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0); + const uint8_t* g_ptr = rgb + 1; + const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2); + const int width = picture->width; + const int height = picture->height; + + if (abs(rgb_stride) < (import_alpha ? 4 : 3) * width) return 0; + + if (!picture->use_argb) { + const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL; + return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, + 0.f /* no dithering */, 0, picture); + } + if (!WebPPictureAlloc(picture)) return 0; + + VP8LDspInit(); + WebPInitAlphaProcessing(); + + if (import_alpha) { + // dst[] byte order is {a,r,g,b} for big-endian, {b,g,r,a} for little endian + uint32_t* dst = picture->argb; + const int do_copy = (ALPHA_OFFSET == 3) && swap_rb; + assert(step == 4); + if (do_copy) { + for (y = 0; y < height; ++y) { + memcpy(dst, rgb, width * 4); + rgb += rgb_stride; + dst += picture->argb_stride; + } + } else { + for (y = 0; y < height; ++y) { +#ifdef WORDS_BIGENDIAN + // BGRA or RGBA input order. + const uint8_t* a_ptr = rgb + 3; + WebPPackARGB(a_ptr, r_ptr, g_ptr, b_ptr, width, dst); + r_ptr += rgb_stride; + g_ptr += rgb_stride; + b_ptr += rgb_stride; +#else + // RGBA input order. Need to swap R and B. + VP8LConvertBGRAToRGBA((const uint32_t*)rgb, width, (uint8_t*)dst); +#endif + rgb += rgb_stride; + dst += picture->argb_stride; + } + } + } else { + uint32_t* dst = picture->argb; + assert(step >= 3); + for (y = 0; y < height; ++y) { + WebPPackRGB(r_ptr, g_ptr, b_ptr, width, step, dst); + r_ptr += rgb_stride; + g_ptr += rgb_stride; + b_ptr += rgb_stride; + dst += picture->argb_stride; + } + } + return 1; +} + +// Public API + +#if !defined(WEBP_REDUCE_CSP) + +int WebPPictureImportBGR(WebPPicture* picture, + const uint8_t* bgr, int bgr_stride) { + return (picture != NULL && bgr != NULL) + ? Import(picture, bgr, bgr_stride, 3, 1, 0) + : 0; +} + +int WebPPictureImportBGRA(WebPPicture* picture, + const uint8_t* bgra, int bgra_stride) { + return (picture != NULL && bgra != NULL) + ? Import(picture, bgra, bgra_stride, 4, 1, 1) + : 0; +} + + +int WebPPictureImportBGRX(WebPPicture* picture, + const uint8_t* bgrx, int bgrx_stride) { + return (picture != NULL && bgrx != NULL) + ? Import(picture, bgrx, bgrx_stride, 4, 1, 0) + : 0; +} + +#endif // WEBP_REDUCE_CSP + +int WebPPictureImportRGB(WebPPicture* picture, + const uint8_t* rgb, int rgb_stride) { + return (picture != NULL && rgb != NULL) + ? Import(picture, rgb, rgb_stride, 3, 0, 0) + : 0; +} + +int WebPPictureImportRGBA(WebPPicture* picture, + const uint8_t* rgba, int rgba_stride) { + return (picture != NULL && rgba != NULL) + ? Import(picture, rgba, rgba_stride, 4, 0, 1) + : 0; +} + +int WebPPictureImportRGBX(WebPPicture* picture, + const uint8_t* rgbx, int rgbx_stride) { + return (picture != NULL && rgbx != NULL) + ? Import(picture, rgbx, rgbx_stride, 4, 0, 0) + : 0; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/enc/picture_enc.c b/libraries/webp/src/enc/picture_enc.c new file mode 100644 index 00000000000..5a2703541f2 --- /dev/null +++ b/libraries/webp/src/enc/picture_enc.c @@ -0,0 +1,304 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebPPicture class basis +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include + +#include "src/enc/vp8i_enc.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// WebPPicture +//------------------------------------------------------------------------------ + +static int DummyWriter(const uint8_t* data, size_t data_size, + const WebPPicture* const picture) { + // The following are to prevent 'unused variable' error message. + (void)data; + (void)data_size; + (void)picture; + return 1; +} + +int WebPPictureInitInternal(WebPPicture* picture, int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) { + return 0; // caller/system version mismatch! + } + if (picture != NULL) { + memset(picture, 0, sizeof(*picture)); + picture->writer = DummyWriter; + WebPEncodingSetError(picture, VP8_ENC_OK); + } + return 1; +} + +//------------------------------------------------------------------------------ + +int WebPValidatePicture(const WebPPicture* const picture) { + if (picture == NULL) return 0; + if (picture->width <= 0 || picture->height <= 0) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 || + picture->height <= 0 || picture->height / 4 > INT_MAX / 4) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + if (picture->colorspace != WEBP_YUV420 && + picture->colorspace != WEBP_YUV420A) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); + } + return 1; +} + +static void WebPPictureResetBufferARGB(WebPPicture* const picture) { + picture->memory_argb_ = NULL; + picture->argb = NULL; + picture->argb_stride = 0; +} + +static void WebPPictureResetBufferYUVA(WebPPicture* const picture) { + picture->memory_ = NULL; + picture->y = picture->u = picture->v = picture->a = NULL; + picture->y_stride = picture->uv_stride = 0; + picture->a_stride = 0; +} + +void WebPPictureResetBuffers(WebPPicture* const picture) { + WebPPictureResetBufferARGB(picture); + WebPPictureResetBufferYUVA(picture); +} + +int WebPPictureAllocARGB(WebPPicture* const picture) { + void* memory; + const int width = picture->width; + const int height = picture->height; + const uint64_t argb_size = (uint64_t)width * height; + + if (!WebPValidatePicture(picture)) return 0; + + WebPSafeFree(picture->memory_argb_); + WebPPictureResetBufferARGB(picture); + + // allocate a new buffer. + memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb)); + if (memory == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + picture->memory_argb_ = memory; + picture->argb = (uint32_t*)WEBP_ALIGN(memory); + picture->argb_stride = width; + return 1; +} + +int WebPPictureAllocYUVA(WebPPicture* const picture) { + const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT; + const int width = picture->width; + const int height = picture->height; + const int y_stride = width; + const int uv_width = (int)(((int64_t)width + 1) >> 1); + const int uv_height = (int)(((int64_t)height + 1) >> 1); + const int uv_stride = uv_width; + int a_width, a_stride; + uint64_t y_size, uv_size, a_size, total_size; + uint8_t* mem; + + if (!WebPValidatePicture(picture)) return 0; + + WebPSafeFree(picture->memory_); + WebPPictureResetBufferYUVA(picture); + + // alpha + a_width = has_alpha ? width : 0; + a_stride = a_width; + y_size = (uint64_t)y_stride * height; + uv_size = (uint64_t)uv_stride * uv_height; + a_size = (uint64_t)a_stride * height; + + total_size = y_size + a_size + 2 * uv_size; + + // Security and validation checks + if (width <= 0 || height <= 0 || // luma/alpha param error + uv_width <= 0 || uv_height <= 0) { // u/v param error + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + // allocate a new buffer. + mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem)); + if (mem == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + + // From now on, we're in the clear, we can no longer fail... + picture->memory_ = (void*)mem; + picture->y_stride = y_stride; + picture->uv_stride = uv_stride; + picture->a_stride = a_stride; + + // TODO(skal): we could align the y/u/v planes and adjust stride. + picture->y = mem; + mem += y_size; + + picture->u = mem; + mem += uv_size; + picture->v = mem; + mem += uv_size; + + if (a_size > 0) { + picture->a = mem; + mem += a_size; + } + (void)mem; // makes the static analyzer happy + return 1; +} + +int WebPPictureAlloc(WebPPicture* picture) { + if (picture != NULL) { + WebPPictureFree(picture); // erase previous buffer + + if (!picture->use_argb) { + return WebPPictureAllocYUVA(picture); + } else { + return WebPPictureAllocARGB(picture); + } + } + return 1; +} + +void WebPPictureFree(WebPPicture* picture) { + if (picture != NULL) { + WebPSafeFree(picture->memory_); + WebPSafeFree(picture->memory_argb_); + WebPPictureResetBuffers(picture); + } +} + +//------------------------------------------------------------------------------ +// WebPMemoryWriter: Write-to-memory + +void WebPMemoryWriterInit(WebPMemoryWriter* writer) { + writer->mem = NULL; + writer->size = 0; + writer->max_size = 0; +} + +int WebPMemoryWrite(const uint8_t* data, size_t data_size, + const WebPPicture* picture) { + WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr; + uint64_t next_size; + if (w == NULL) { + return 1; + } + next_size = (uint64_t)w->size + data_size; + if (next_size > w->max_size) { + uint8_t* new_mem; + uint64_t next_max_size = 2ULL * w->max_size; + if (next_max_size < next_size) next_max_size = next_size; + if (next_max_size < 8192ULL) next_max_size = 8192ULL; + new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1); + if (new_mem == NULL) { + return 0; + } + if (w->size > 0) { + memcpy(new_mem, w->mem, w->size); + } + WebPSafeFree(w->mem); + w->mem = new_mem; + // down-cast is ok, thanks to WebPSafeMalloc + w->max_size = (size_t)next_max_size; + } + if (data_size > 0) { + memcpy(w->mem + w->size, data, data_size); + w->size += data_size; + } + return 1; +} + +void WebPMemoryWriterClear(WebPMemoryWriter* writer) { + if (writer != NULL) { + WebPSafeFree(writer->mem); + writer->mem = NULL; + writer->size = 0; + writer->max_size = 0; + } +} + +//------------------------------------------------------------------------------ +// Simplest high-level calls: + +typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int); + +static size_t Encode(const uint8_t* rgba, int width, int height, int stride, + Importer import, float quality_factor, int lossless, + uint8_t** output) { + WebPPicture pic; + WebPConfig config; + WebPMemoryWriter wrt; + int ok; + + if (output == NULL) return 0; + + if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) || + !WebPPictureInit(&pic)) { + return 0; // shouldn't happen, except if system installation is broken + } + + config.lossless = !!lossless; + pic.use_argb = !!lossless; + pic.width = width; + pic.height = height; + pic.writer = WebPMemoryWrite; + pic.custom_ptr = &wrt; + WebPMemoryWriterInit(&wrt); + + ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic); + WebPPictureFree(&pic); + if (!ok) { + WebPMemoryWriterClear(&wrt); + *output = NULL; + return 0; + } + *output = wrt.mem; + return wrt.size; +} + +#define ENCODE_FUNC(NAME, IMPORTER) \ +size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \ + uint8_t** out) { \ + return Encode(in, w, h, bps, IMPORTER, q, 0, out); \ +} + +ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB) +ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA) +#if !defined(WEBP_REDUCE_CSP) +ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR) +ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA) +#endif // WEBP_REDUCE_CSP + +#undef ENCODE_FUNC + +#define LOSSLESS_DEFAULT_QUALITY 70. +#define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \ +size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \ + return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \ +} + +LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB) +LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA) +#if !defined(WEBP_REDUCE_CSP) +LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR) +LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA) +#endif // WEBP_REDUCE_CSP + +#undef LOSSLESS_ENCODE_FUNC + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/enc/picture_psnr_enc.c b/libraries/webp/src/enc/picture_psnr_enc.c new file mode 100644 index 00000000000..70d57322ad3 --- /dev/null +++ b/libraries/webp/src/enc/picture_psnr_enc.c @@ -0,0 +1,258 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebPPicture tools for measuring distortion +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "include/webp/encode.h" + +#if !(defined(WEBP_DISABLE_STATS) || defined(WEBP_REDUCE_SIZE)) + +#include +#include + +#include "src/dsp/dsp.h" +#include "src/enc/vp8i_enc.h" +#include "src/utils/utils.h" + +typedef double (*AccumulateFunc)(const uint8_t* src, int src_stride, + const uint8_t* ref, int ref_stride, + int w, int h); + +//------------------------------------------------------------------------------ +// local-min distortion +// +// For every pixel in the *reference* picture, we search for the local best +// match in the compressed image. This is not a symmetrical measure. + +#define RADIUS 2 // search radius. Shouldn't be too large. + +static double AccumulateLSIM(const uint8_t* src, int src_stride, + const uint8_t* ref, int ref_stride, + int w, int h) { + int x, y; + double total_sse = 0.; + for (y = 0; y < h; ++y) { + const int y_0 = (y - RADIUS < 0) ? 0 : y - RADIUS; + const int y_1 = (y + RADIUS + 1 >= h) ? h : y + RADIUS + 1; + for (x = 0; x < w; ++x) { + const int x_0 = (x - RADIUS < 0) ? 0 : x - RADIUS; + const int x_1 = (x + RADIUS + 1 >= w) ? w : x + RADIUS + 1; + double best_sse = 255. * 255.; + const double value = (double)ref[y * ref_stride + x]; + int i, j; + for (j = y_0; j < y_1; ++j) { + const uint8_t* const s = src + j * src_stride; + for (i = x_0; i < x_1; ++i) { + const double diff = s[i] - value; + const double sse = diff * diff; + if (sse < best_sse) best_sse = sse; + } + } + total_sse += best_sse; + } + } + return total_sse; +} +#undef RADIUS + +static double AccumulateSSE(const uint8_t* src, int src_stride, + const uint8_t* ref, int ref_stride, + int w, int h) { + int y; + double total_sse = 0.; + for (y = 0; y < h; ++y) { + total_sse += VP8AccumulateSSE(src, ref, w); + src += src_stride; + ref += ref_stride; + } + return total_sse; +} + +//------------------------------------------------------------------------------ + +static double AccumulateSSIM(const uint8_t* src, int src_stride, + const uint8_t* ref, int ref_stride, + int w, int h) { + const int w0 = (w < VP8_SSIM_KERNEL) ? w : VP8_SSIM_KERNEL; + const int w1 = w - VP8_SSIM_KERNEL - 1; + const int h0 = (h < VP8_SSIM_KERNEL) ? h : VP8_SSIM_KERNEL; + const int h1 = h - VP8_SSIM_KERNEL - 1; + int x, y; + double sum = 0.; + for (y = 0; y < h0; ++y) { + for (x = 0; x < w; ++x) { + sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); + } + } + for (; y < h1; ++y) { + for (x = 0; x < w0; ++x) { + sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); + } + for (; x < w1; ++x) { + const int off1 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * src_stride; + const int off2 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * ref_stride; + sum += VP8SSIMGet(src + off1, src_stride, ref + off2, ref_stride); + } + for (; x < w; ++x) { + sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); + } + } + for (; y < h; ++y) { + for (x = 0; x < w; ++x) { + sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); + } + } + return sum; +} + +//------------------------------------------------------------------------------ +// Distortion + +// Max value returned in case of exact similarity. +static const double kMinDistortion_dB = 99.; + +static double GetPSNR(double v, double size) { + return (v > 0. && size > 0.) ? -4.3429448 * log(v / (size * 255 * 255.)) + : kMinDistortion_dB; +} + +static double GetLogSSIM(double v, double size) { + v = (size > 0.) ? v / size : 1.; + return (v < 1.) ? -10.0 * log10(1. - v) : kMinDistortion_dB; +} + +int WebPPlaneDistortion(const uint8_t* src, size_t src_stride, + const uint8_t* ref, size_t ref_stride, + int width, int height, size_t x_step, + int type, float* distortion, float* result) { + uint8_t* allocated = NULL; + const AccumulateFunc metric = (type == 0) ? AccumulateSSE : + (type == 1) ? AccumulateSSIM : + AccumulateLSIM; + if (src == NULL || ref == NULL || + src_stride < x_step * width || ref_stride < x_step * width || + result == NULL || distortion == NULL) { + return 0; + } + + VP8SSIMDspInit(); + if (x_step != 1) { // extract a packed plane if needed + int x, y; + uint8_t* tmp1; + uint8_t* tmp2; + allocated = + (uint8_t*)WebPSafeMalloc(2ULL * width * height, sizeof(*allocated)); + if (allocated == NULL) return 0; + tmp1 = allocated; + tmp2 = tmp1 + (size_t)width * height; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + tmp1[x + y * width] = src[x * x_step + y * src_stride]; + tmp2[x + y * width] = ref[x * x_step + y * ref_stride]; + } + } + src = tmp1; + ref = tmp2; + } + *distortion = (float)metric(src, width, ref, width, width, height); + WebPSafeFree(allocated); + + *result = (type == 1) ? (float)GetLogSSIM(*distortion, (double)width * height) + : (float)GetPSNR(*distortion, (double)width * height); + return 1; +} + +#ifdef WORDS_BIGENDIAN +#define BLUE_OFFSET 3 // uint32_t 0x000000ff is 0x00,00,00,ff in memory +#else +#define BLUE_OFFSET 0 // uint32_t 0x000000ff is 0xff,00,00,00 in memory +#endif + +int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, + int type, float results[5]) { + int w, h, c; + int ok = 0; + WebPPicture p0, p1; + double total_size = 0., total_distortion = 0.; + if (src == NULL || ref == NULL || + src->width != ref->width || src->height != ref->height || + results == NULL) { + return 0; + } + + VP8SSIMDspInit(); + if (!WebPPictureInit(&p0) || !WebPPictureInit(&p1)) return 0; + w = src->width; + h = src->height; + if (!WebPPictureView(src, 0, 0, w, h, &p0)) goto Error; + if (!WebPPictureView(ref, 0, 0, w, h, &p1)) goto Error; + + // We always measure distortion in ARGB space. + if (p0.use_argb == 0 && !WebPPictureYUVAToARGB(&p0)) goto Error; + if (p1.use_argb == 0 && !WebPPictureYUVAToARGB(&p1)) goto Error; + for (c = 0; c < 4; ++c) { + float distortion; + const size_t stride0 = 4 * (size_t)p0.argb_stride; + const size_t stride1 = 4 * (size_t)p1.argb_stride; + // results are reported as BGRA + const int offset = c ^ BLUE_OFFSET; + if (!WebPPlaneDistortion((const uint8_t*)p0.argb + offset, stride0, + (const uint8_t*)p1.argb + offset, stride1, + w, h, 4, type, &distortion, results + c)) { + goto Error; + } + total_distortion += distortion; + total_size += w * h; + } + + results[4] = (type == 1) ? (float)GetLogSSIM(total_distortion, total_size) + : (float)GetPSNR(total_distortion, total_size); + ok = 1; + + Error: + WebPPictureFree(&p0); + WebPPictureFree(&p1); + return ok; +} + +#undef BLUE_OFFSET + +#else // defined(WEBP_DISABLE_STATS) +int WebPPlaneDistortion(const uint8_t* src, size_t src_stride, + const uint8_t* ref, size_t ref_stride, + int width, int height, size_t x_step, + int type, float* distortion, float* result) { + (void)src; + (void)src_stride; + (void)ref; + (void)ref_stride; + (void)width; + (void)height; + (void)x_step; + (void)type; + if (distortion == NULL || result == NULL) return 0; + *distortion = 0.f; + *result = 0.f; + return 1; +} + +int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, + int type, float results[5]) { + int i; + (void)src; + (void)ref; + (void)type; + if (results == NULL) return 0; + for (i = 0; i < 5; ++i) results[i] = 0.f; + return 1; +} + +#endif // !defined(WEBP_DISABLE_STATS) diff --git a/libraries/webp/src/enc/picture_rescale_enc.c b/libraries/webp/src/enc/picture_rescale_enc.c new file mode 100644 index 00000000000..b199ea73bb5 --- /dev/null +++ b/libraries/webp/src/enc/picture_rescale_enc.c @@ -0,0 +1,304 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebPPicture tools: copy, crop, rescaling and view. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "include/webp/encode.h" + +#include +#include + +#include "src/enc/vp8i_enc.h" + +#if !defined(WEBP_REDUCE_SIZE) +#include "src/utils/rescaler_utils.h" +#include "src/utils/utils.h" +#endif // !defined(WEBP_REDUCE_SIZE) + +#define HALVE(x) (((x) + 1) >> 1) + +// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them +// into 'dst'. Mark 'dst' as not owning any memory. +static void PictureGrabSpecs(const WebPPicture* const src, + WebPPicture* const dst) { + assert(src != NULL && dst != NULL); + *dst = *src; + WebPPictureResetBuffers(dst); +} + +//------------------------------------------------------------------------------ + +// Adjust top-left corner to chroma sample position. +static void SnapTopLeftPosition(const WebPPicture* const pic, + int* const left, int* const top) { + if (!pic->use_argb) { + *left &= ~1; + *top &= ~1; + } +} + +// Adjust top-left corner and verify that the sub-rectangle is valid. +static int AdjustAndCheckRectangle(const WebPPicture* const pic, + int* const left, int* const top, + int width, int height) { + SnapTopLeftPosition(pic, left, top); + if ((*left) < 0 || (*top) < 0) return 0; + if (width <= 0 || height <= 0) return 0; + if ((*left) + width > pic->width) return 0; + if ((*top) + height > pic->height) return 0; + return 1; +} + +#if !defined(WEBP_REDUCE_SIZE) +int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { + if (src == NULL || dst == NULL) return 0; + if (src == dst) return 1; + + PictureGrabSpecs(src, dst); + if (!WebPPictureAlloc(dst)) return 0; + + if (!src->use_argb) { + WebPCopyPlane(src->y, src->y_stride, + dst->y, dst->y_stride, dst->width, dst->height); + WebPCopyPlane(src->u, src->uv_stride, dst->u, dst->uv_stride, + HALVE(dst->width), HALVE(dst->height)); + WebPCopyPlane(src->v, src->uv_stride, dst->v, dst->uv_stride, + HALVE(dst->width), HALVE(dst->height)); + if (dst->a != NULL) { + WebPCopyPlane(src->a, src->a_stride, + dst->a, dst->a_stride, dst->width, dst->height); + } + } else { + WebPCopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride, + (uint8_t*)dst->argb, 4 * dst->argb_stride, + 4 * dst->width, dst->height); + } + return 1; +} +#endif // !defined(WEBP_REDUCE_SIZE) + +int WebPPictureIsView(const WebPPicture* picture) { + if (picture == NULL) return 0; + if (picture->use_argb) { + return (picture->memory_argb_ == NULL); + } + return (picture->memory_ == NULL); +} + +int WebPPictureView(const WebPPicture* src, + int left, int top, int width, int height, + WebPPicture* dst) { + if (src == NULL || dst == NULL) return 0; + + // verify rectangle position. + if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0; + + if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'. + PictureGrabSpecs(src, dst); + } + dst->width = width; + dst->height = height; + if (!src->use_argb) { + dst->y = src->y + top * src->y_stride + left; + dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1); + dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1); + dst->y_stride = src->y_stride; + dst->uv_stride = src->uv_stride; + if (src->a != NULL) { + dst->a = src->a + top * src->a_stride + left; + dst->a_stride = src->a_stride; + } + } else { + dst->argb = src->argb + top * src->argb_stride + left; + dst->argb_stride = src->argb_stride; + } + return 1; +} + +#if !defined(WEBP_REDUCE_SIZE) +//------------------------------------------------------------------------------ +// Picture cropping + +int WebPPictureCrop(WebPPicture* pic, + int left, int top, int width, int height) { + WebPPicture tmp; + + if (pic == NULL) return 0; + if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0; + + PictureGrabSpecs(pic, &tmp); + tmp.width = width; + tmp.height = height; + if (!WebPPictureAlloc(&tmp)) { + return WebPEncodingSetError(pic, tmp.error_code); + } + + if (!pic->use_argb) { + const int y_offset = top * pic->y_stride + left; + const int uv_offset = (top / 2) * pic->uv_stride + left / 2; + WebPCopyPlane(pic->y + y_offset, pic->y_stride, + tmp.y, tmp.y_stride, width, height); + WebPCopyPlane(pic->u + uv_offset, pic->uv_stride, + tmp.u, tmp.uv_stride, HALVE(width), HALVE(height)); + WebPCopyPlane(pic->v + uv_offset, pic->uv_stride, + tmp.v, tmp.uv_stride, HALVE(width), HALVE(height)); + + if (tmp.a != NULL) { + const int a_offset = top * pic->a_stride + left; + WebPCopyPlane(pic->a + a_offset, pic->a_stride, + tmp.a, tmp.a_stride, width, height); + } + } else { + const uint8_t* const src = + (const uint8_t*)(pic->argb + top * pic->argb_stride + left); + WebPCopyPlane(src, pic->argb_stride * 4, (uint8_t*)tmp.argb, + tmp.argb_stride * 4, width * 4, height); + } + WebPPictureFree(pic); + *pic = tmp; + return 1; +} + +//------------------------------------------------------------------------------ +// Simple picture rescaler + +static int RescalePlane(const uint8_t* src, + int src_width, int src_height, int src_stride, + uint8_t* dst, + int dst_width, int dst_height, int dst_stride, + rescaler_t* const work, + int num_channels) { + WebPRescaler rescaler; + int y = 0; + if (!WebPRescalerInit(&rescaler, src_width, src_height, + dst, dst_width, dst_height, dst_stride, + num_channels, work)) { + return 0; + } + while (y < src_height) { + y += WebPRescalerImport(&rescaler, src_height - y, + src + y * src_stride, src_stride); + WebPRescalerExport(&rescaler); + } + return 1; +} + +static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) { + assert(pic->argb != NULL); + WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb), + pic->width, pic->height, inverse); +} + +static void AlphaMultiplyY(WebPPicture* const pic, int inverse) { + if (pic->a != NULL) { + WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride, + pic->width, pic->height, inverse); + } +} + +int WebPPictureRescale(WebPPicture* picture, int width, int height) { + WebPPicture tmp; + int prev_width, prev_height; + rescaler_t* work; + + if (picture == NULL) return 0; + prev_width = picture->width; + prev_height = picture->height; + if (!WebPRescalerGetScaledDimensions( + prev_width, prev_height, &width, &height)) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + + PictureGrabSpecs(picture, &tmp); + tmp.width = width; + tmp.height = height; + if (!WebPPictureAlloc(&tmp)) { + return WebPEncodingSetError(picture, tmp.error_code); + } + + if (!picture->use_argb) { + work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work)); + if (work == NULL) { + WebPPictureFree(&tmp); + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + // If present, we need to rescale alpha first (for AlphaMultiplyY). + if (picture->a != NULL) { + WebPInitAlphaProcessing(); + if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride, + tmp.a, width, height, tmp.a_stride, work, 1)) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + } + + // We take transparency into account on the luma plane only. That's not + // totally exact blending, but still is a good approximation. + AlphaMultiplyY(picture, 0); + if (!RescalePlane(picture->y, prev_width, prev_height, picture->y_stride, + tmp.y, width, height, tmp.y_stride, work, 1) || + !RescalePlane(picture->u, HALVE(prev_width), HALVE(prev_height), + picture->uv_stride, tmp.u, HALVE(width), HALVE(height), + tmp.uv_stride, work, 1) || + !RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height), + picture->uv_stride, tmp.v, HALVE(width), HALVE(height), + tmp.uv_stride, work, 1)) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + AlphaMultiplyY(&tmp, 1); + } else { + work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work)); + if (work == NULL) { + WebPPictureFree(&tmp); + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + // In order to correctly interpolate colors, we need to apply the alpha + // weighting first (black-matting), scale the RGB values, and remove + // the premultiplication afterward (while preserving the alpha channel). + WebPInitAlphaProcessing(); + AlphaMultiplyARGB(picture, 0); + if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height, + picture->argb_stride * 4, (uint8_t*)tmp.argb, width, + height, tmp.argb_stride * 4, work, 4)) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + AlphaMultiplyARGB(&tmp, 1); + } + WebPPictureFree(picture); + WebPSafeFree(work); + *picture = tmp; + return 1; +} + +#else // defined(WEBP_REDUCE_SIZE) + +int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { + (void)src; + (void)dst; + return 0; +} + +int WebPPictureCrop(WebPPicture* pic, + int left, int top, int width, int height) { + (void)pic; + (void)left; + (void)top; + (void)width; + (void)height; + return 0; +} + +int WebPPictureRescale(WebPPicture* pic, int width, int height) { + (void)pic; + (void)width; + (void)height; + return 0; +} +#endif // !defined(WEBP_REDUCE_SIZE) diff --git a/libraries/webp/src/enc/picture_tools_enc.c b/libraries/webp/src/enc/picture_tools_enc.c new file mode 100644 index 00000000000..147cc18608c --- /dev/null +++ b/libraries/webp/src/enc/picture_tools_enc.c @@ -0,0 +1,274 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebPPicture tools: alpha handling, etc. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/enc/vp8i_enc.h" +#include "src/dsp/yuv.h" + +//------------------------------------------------------------------------------ +// Helper: clean up fully transparent area to help compressibility. + +#define SIZE 8 +#define SIZE2 (SIZE / 2) +static int IsTransparentARGBArea(const uint32_t* ptr, int stride, int size) { + int y, x; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + if (ptr[x] & 0xff000000u) { + return 0; + } + } + ptr += stride; + } + return 1; +} + +static void Flatten(uint8_t* ptr, int v, int stride, int size) { + int y; + for (y = 0; y < size; ++y) { + memset(ptr, v, size); + ptr += stride; + } +} + +static void FlattenARGB(uint32_t* ptr, uint32_t v, int stride, int size) { + int x, y; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) ptr[x] = v; + ptr += stride; + } +} + +// Smoothen the luma components of transparent pixels. Return true if the whole +// block is transparent. +static int SmoothenBlock(const uint8_t* a_ptr, int a_stride, uint8_t* y_ptr, + int y_stride, int width, int height) { + int sum = 0, count = 0; + int x, y; + const uint8_t* alpha_ptr = a_ptr; + uint8_t* luma_ptr = y_ptr; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + if (alpha_ptr[x] != 0) { + ++count; + sum += luma_ptr[x]; + } + } + alpha_ptr += a_stride; + luma_ptr += y_stride; + } + if (count > 0 && count < width * height) { + const uint8_t avg_u8 = (uint8_t)(sum / count); + alpha_ptr = a_ptr; + luma_ptr = y_ptr; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + if (alpha_ptr[x] == 0) luma_ptr[x] = avg_u8; + } + alpha_ptr += a_stride; + luma_ptr += y_stride; + } + } + return (count == 0); +} + +void WebPReplaceTransparentPixels(WebPPicture* const pic, uint32_t color) { + if (pic != NULL && pic->use_argb) { + int y = pic->height; + uint32_t* argb = pic->argb; + color &= 0xffffffu; // force alpha=0 + WebPInitAlphaProcessing(); + while (y-- > 0) { + WebPAlphaReplace(argb, pic->width, color); + argb += pic->argb_stride; + } + } +} + +void WebPCleanupTransparentArea(WebPPicture* pic) { + int x, y, w, h; + if (pic == NULL) return; + w = pic->width / SIZE; + h = pic->height / SIZE; + + // note: we ignore the left-overs on right/bottom, except for SmoothenBlock(). + if (pic->use_argb) { + uint32_t argb_value = 0; + for (y = 0; y < h; ++y) { + int need_reset = 1; + for (x = 0; x < w; ++x) { + const int off = (y * pic->argb_stride + x) * SIZE; + if (IsTransparentARGBArea(pic->argb + off, pic->argb_stride, SIZE)) { + if (need_reset) { + argb_value = pic->argb[off]; + need_reset = 0; + } + FlattenARGB(pic->argb + off, argb_value, pic->argb_stride, SIZE); + } else { + need_reset = 1; + } + } + } + } else { + const int width = pic->width; + const int height = pic->height; + const int y_stride = pic->y_stride; + const int uv_stride = pic->uv_stride; + const int a_stride = pic->a_stride; + uint8_t* y_ptr = pic->y; + uint8_t* u_ptr = pic->u; + uint8_t* v_ptr = pic->v; + const uint8_t* a_ptr = pic->a; + int values[3] = { 0 }; + if (a_ptr == NULL || y_ptr == NULL || u_ptr == NULL || v_ptr == NULL) { + return; + } + for (y = 0; y + SIZE <= height; y += SIZE) { + int need_reset = 1; + for (x = 0; x + SIZE <= width; x += SIZE) { + if (SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride, + SIZE, SIZE)) { + if (need_reset) { + values[0] = y_ptr[x]; + values[1] = u_ptr[x >> 1]; + values[2] = v_ptr[x >> 1]; + need_reset = 0; + } + Flatten(y_ptr + x, values[0], y_stride, SIZE); + Flatten(u_ptr + (x >> 1), values[1], uv_stride, SIZE2); + Flatten(v_ptr + (x >> 1), values[2], uv_stride, SIZE2); + } else { + need_reset = 1; + } + } + if (x < width) { + SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride, + width - x, SIZE); + } + a_ptr += SIZE * a_stride; + y_ptr += SIZE * y_stride; + u_ptr += SIZE2 * uv_stride; + v_ptr += SIZE2 * uv_stride; + } + if (y < height) { + const int sub_height = height - y; + for (x = 0; x + SIZE <= width; x += SIZE) { + SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride, + SIZE, sub_height); + } + if (x < width) { + SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride, + width - x, sub_height); + } + } + } +} + +#undef SIZE +#undef SIZE2 + +//------------------------------------------------------------------------------ +// Blend color and remove transparency info + +#define BLEND(V0, V1, ALPHA) \ + ((((V0) * (255 - (ALPHA)) + (V1) * (ALPHA)) * 0x101 + 256) >> 16) +#define BLEND_10BIT(V0, V1, ALPHA) \ + ((((V0) * (1020 - (ALPHA)) + (V1) * (ALPHA)) * 0x101 + 1024) >> 18) + +static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) { + return (0xff000000u | (r << 16) | (g << 8) | b); +} + +void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb) { + const int red = (background_rgb >> 16) & 0xff; + const int green = (background_rgb >> 8) & 0xff; + const int blue = (background_rgb >> 0) & 0xff; + int x, y; + if (picture == NULL) return; + if (!picture->use_argb) { + // omit last pixel during u/v loop + const int uv_width = (picture->width >> 1); + const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF); + // VP8RGBToU/V expects the u/v values summed over four pixels + const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF); + const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF); + const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT; + uint8_t* y_ptr = picture->y; + uint8_t* u_ptr = picture->u; + uint8_t* v_ptr = picture->v; + uint8_t* a_ptr = picture->a; + if (!has_alpha || a_ptr == NULL) return; // nothing to do + for (y = 0; y < picture->height; ++y) { + // Luma blending + for (x = 0; x < picture->width; ++x) { + const uint8_t alpha = a_ptr[x]; + if (alpha < 0xff) { + y_ptr[x] = BLEND(Y0, y_ptr[x], alpha); + } + } + // Chroma blending every even line + if ((y & 1) == 0) { + uint8_t* const a_ptr2 = + (y + 1 == picture->height) ? a_ptr : a_ptr + picture->a_stride; + for (x = 0; x < uv_width; ++x) { + // Average four alpha values into a single blending weight. + // TODO(skal): might lead to visible contouring. Can we do better? + const uint32_t alpha = + a_ptr[2 * x + 0] + a_ptr[2 * x + 1] + + a_ptr2[2 * x + 0] + a_ptr2[2 * x + 1]; + u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha); + v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha); + } + if (picture->width & 1) { // rightmost pixel + const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]); + u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha); + v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha); + } + } else { + u_ptr += picture->uv_stride; + v_ptr += picture->uv_stride; + } + memset(a_ptr, 0xff, picture->width); // reset alpha value to opaque + a_ptr += picture->a_stride; + y_ptr += picture->y_stride; + } + } else { + uint32_t* argb = picture->argb; + const uint32_t background = MakeARGB32(red, green, blue); + for (y = 0; y < picture->height; ++y) { + for (x = 0; x < picture->width; ++x) { + const int alpha = (argb[x] >> 24) & 0xff; + if (alpha != 0xff) { + if (alpha > 0) { + int r = (argb[x] >> 16) & 0xff; + int g = (argb[x] >> 8) & 0xff; + int b = (argb[x] >> 0) & 0xff; + r = BLEND(red, r, alpha); + g = BLEND(green, g, alpha); + b = BLEND(blue, b, alpha); + argb[x] = MakeARGB32(r, g, b); + } else { + argb[x] = background; + } + } + } + argb += picture->argb_stride; + } + } +} + +#undef BLEND +#undef BLEND_10BIT + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/enc/predictor_enc.c b/libraries/webp/src/enc/predictor_enc.c new file mode 100644 index 00000000000..b3d44b59d50 --- /dev/null +++ b/libraries/webp/src/enc/predictor_enc.c @@ -0,0 +1,792 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Image transform methods for lossless encoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) +// Urvang Joshi (urvang@google.com) +// Vincent Rabaud (vrabaud@google.com) + +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" +#include "src/enc/vp8i_enc.h" +#include "src/enc/vp8li_enc.h" + +#define MAX_DIFF_COST (1e30f) + +static const float kSpatialPredictorBias = 15.f; +static const int kPredLowEffort = 11; +static const uint32_t kMaskAlpha = 0xff000000; + +// Mostly used to reduce code size + readability +static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; } + +//------------------------------------------------------------------------------ +// Methods to calculate Entropy (Shannon). + +static float PredictionCostSpatial(const int counts[256], int weight_0, + float exp_val) { + const int significant_symbols = 256 >> 4; + const float exp_decay_factor = 0.6f; + float bits = (float)weight_0 * counts[0]; + int i; + for (i = 1; i < significant_symbols; ++i) { + bits += exp_val * (counts[i] + counts[256 - i]); + exp_val *= exp_decay_factor; + } + return (float)(-0.1 * bits); +} + +static float PredictionCostSpatialHistogram(const int accumulated[4][256], + const int tile[4][256]) { + int i; + float retval = 0.f; + for (i = 0; i < 4; ++i) { + const float kExpValue = 0.94f; + retval += PredictionCostSpatial(tile[i], 1, kExpValue); + retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]); + } + return (float)retval; +} + +static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) { + ++histo_argb[0][argb >> 24]; + ++histo_argb[1][(argb >> 16) & 0xff]; + ++histo_argb[2][(argb >> 8) & 0xff]; + ++histo_argb[3][argb & 0xff]; +} + +//------------------------------------------------------------------------------ +// Spatial transform functions. + +static WEBP_INLINE void PredictBatch(int mode, int x_start, int y, + int num_pixels, const uint32_t* current, + const uint32_t* upper, uint32_t* out) { + if (x_start == 0) { + if (y == 0) { + // ARGB_BLACK. + VP8LPredictorsSub[0](current, NULL, 1, out); + } else { + // Top one. + VP8LPredictorsSub[2](current, upper, 1, out); + } + ++x_start; + ++out; + --num_pixels; + } + if (y == 0) { + // Left one. + VP8LPredictorsSub[1](current + x_start, NULL, num_pixels, out); + } else { + VP8LPredictorsSub[mode](current + x_start, upper + x_start, num_pixels, + out); + } +} + +#if (WEBP_NEAR_LOSSLESS == 1) +static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; } + +static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) { + const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24)); + const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff)); + const int diff_g = abs((int)((p1 >> 8) & 0xff) - (int)((p2 >> 8) & 0xff)); + const int diff_b = abs((int)(p1 & 0xff) - (int)(p2 & 0xff)); + return GetMax(GetMax(diff_a, diff_r), GetMax(diff_g, diff_b)); +} + +static int MaxDiffAroundPixel(uint32_t current, uint32_t up, uint32_t down, + uint32_t left, uint32_t right) { + const int diff_up = MaxDiffBetweenPixels(current, up); + const int diff_down = MaxDiffBetweenPixels(current, down); + const int diff_left = MaxDiffBetweenPixels(current, left); + const int diff_right = MaxDiffBetweenPixels(current, right); + return GetMax(GetMax(diff_up, diff_down), GetMax(diff_left, diff_right)); +} + +static uint32_t AddGreenToBlueAndRed(uint32_t argb) { + const uint32_t green = (argb >> 8) & 0xff; + uint32_t red_blue = argb & 0x00ff00ffu; + red_blue += (green << 16) | green; + red_blue &= 0x00ff00ffu; + return (argb & 0xff00ff00u) | red_blue; +} + +static void MaxDiffsForRow(int width, int stride, const uint32_t* const argb, + uint8_t* const max_diffs, int used_subtract_green) { + uint32_t current, up, down, left, right; + int x; + if (width <= 2) return; + current = argb[0]; + right = argb[1]; + if (used_subtract_green) { + current = AddGreenToBlueAndRed(current); + right = AddGreenToBlueAndRed(right); + } + // max_diffs[0] and max_diffs[width - 1] are never used. + for (x = 1; x < width - 1; ++x) { + up = argb[-stride + x]; + down = argb[stride + x]; + left = current; + current = right; + right = argb[x + 1]; + if (used_subtract_green) { + up = AddGreenToBlueAndRed(up); + down = AddGreenToBlueAndRed(down); + right = AddGreenToBlueAndRed(right); + } + max_diffs[x] = MaxDiffAroundPixel(current, up, down, left, right); + } +} + +// Quantize the difference between the actual component value and its prediction +// to a multiple of quantization, working modulo 256, taking care not to cross +// a boundary (inclusive upper limit). +static uint8_t NearLosslessComponent(uint8_t value, uint8_t predict, + uint8_t boundary, int quantization) { + const int residual = (value - predict) & 0xff; + const int boundary_residual = (boundary - predict) & 0xff; + const int lower = residual & ~(quantization - 1); + const int upper = lower + quantization; + // Resolve ties towards a value closer to the prediction (i.e. towards lower + // if value comes after prediction and towards upper otherwise). + const int bias = ((boundary - value) & 0xff) < boundary_residual; + if (residual - lower < upper - residual + bias) { + // lower is closer to residual than upper. + if (residual > boundary_residual && lower <= boundary_residual) { + // Halve quantization step to avoid crossing boundary. This midpoint is + // on the same side of boundary as residual because midpoint >= residual + // (since lower is closer than upper) and residual is above the boundary. + return lower + (quantization >> 1); + } + return lower; + } else { + // upper is closer to residual than lower. + if (residual <= boundary_residual && upper > boundary_residual) { + // Halve quantization step to avoid crossing boundary. This midpoint is + // on the same side of boundary as residual because midpoint <= residual + // (since upper is closer than lower) and residual is below the boundary. + return lower + (quantization >> 1); + } + return upper & 0xff; + } +} + +static WEBP_INLINE uint8_t NearLosslessDiff(uint8_t a, uint8_t b) { + return (uint8_t)((((int)(a) - (int)(b))) & 0xff); +} + +// Quantize every component of the difference between the actual pixel value and +// its prediction to a multiple of a quantization (a power of 2, not larger than +// max_quantization which is a power of 2, smaller than max_diff). Take care if +// value and predict have undergone subtract green, which means that red and +// blue are represented as offsets from green. +static uint32_t NearLossless(uint32_t value, uint32_t predict, + int max_quantization, int max_diff, + int used_subtract_green) { + int quantization; + uint8_t new_green = 0; + uint8_t green_diff = 0; + uint8_t a, r, g, b; + if (max_diff <= 2) { + return VP8LSubPixels(value, predict); + } + quantization = max_quantization; + while (quantization >= max_diff) { + quantization >>= 1; + } + if ((value >> 24) == 0 || (value >> 24) == 0xff) { + // Preserve transparency of fully transparent or fully opaque pixels. + a = NearLosslessDiff((value >> 24) & 0xff, (predict >> 24) & 0xff); + } else { + a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization); + } + g = NearLosslessComponent((value >> 8) & 0xff, (predict >> 8) & 0xff, 0xff, + quantization); + if (used_subtract_green) { + // The green offset will be added to red and blue components during decoding + // to obtain the actual red and blue values. + new_green = ((predict >> 8) + g) & 0xff; + // The amount by which green has been adjusted during quantization. It is + // subtracted from red and blue for compensation, to avoid accumulating two + // quantization errors in them. + green_diff = NearLosslessDiff(new_green, (value >> 8) & 0xff); + } + r = NearLosslessComponent(NearLosslessDiff((value >> 16) & 0xff, green_diff), + (predict >> 16) & 0xff, 0xff - new_green, + quantization); + b = NearLosslessComponent(NearLosslessDiff(value & 0xff, green_diff), + predict & 0xff, 0xff - new_green, quantization); + return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} +#endif // (WEBP_NEAR_LOSSLESS == 1) + +// Stores the difference between the pixel and its prediction in "out". +// In case of a lossy encoding, updates the source image to avoid propagating +// the deviation further to pixels which depend on the current pixel for their +// predictions. +static WEBP_INLINE void GetResidual( + int width, int height, uint32_t* const upper_row, + uint32_t* const current_row, const uint8_t* const max_diffs, int mode, + int x_start, int x_end, int y, int max_quantization, int exact, + int used_subtract_green, uint32_t* const out) { + if (exact) { + PredictBatch(mode, x_start, y, x_end - x_start, current_row, upper_row, + out); + } else { + const VP8LPredictorFunc pred_func = VP8LPredictors[mode]; + int x; + for (x = x_start; x < x_end; ++x) { + uint32_t predict; + uint32_t residual; + if (y == 0) { + predict = (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left. + } else if (x == 0) { + predict = upper_row[x]; // Top. + } else { + predict = pred_func(¤t_row[x - 1], upper_row + x); + } +#if (WEBP_NEAR_LOSSLESS == 1) + if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 || + x == 0 || x == width - 1) { + residual = VP8LSubPixels(current_row[x], predict); + } else { + residual = NearLossless(current_row[x], predict, max_quantization, + max_diffs[x], used_subtract_green); + // Update the source image. + current_row[x] = VP8LAddPixels(predict, residual); + // x is never 0 here so we do not need to update upper_row like below. + } +#else + (void)max_diffs; + (void)height; + (void)max_quantization; + (void)used_subtract_green; + residual = VP8LSubPixels(current_row[x], predict); +#endif + if ((current_row[x] & kMaskAlpha) == 0) { + // If alpha is 0, cleanup RGB. We can choose the RGB values of the + // residual for best compression. The prediction of alpha itself can be + // non-zero and must be kept though. We choose RGB of the residual to be + // 0. + residual &= kMaskAlpha; + // Update the source image. + current_row[x] = predict & ~kMaskAlpha; + // The prediction for the rightmost pixel in a row uses the leftmost + // pixel + // in that row as its top-right context pixel. Hence if we change the + // leftmost pixel of current_row, the corresponding change must be + // applied + // to upper_row as well where top-right context is being read from. + if (x == 0 && y != 0) upper_row[width] = current_row[0]; + } + out[x - x_start] = residual; + } + } +} + +// Returns best predictor and updates the accumulated histogram. +// If max_quantization > 1, assumes that near lossless processing will be +// applied, quantizing residuals to multiples of quantization levels up to +// max_quantization (the actual quantization level depends on smoothness near +// the given pixel). +static int GetBestPredictorForTile(int width, int height, + int tile_x, int tile_y, int bits, + int accumulated[4][256], + uint32_t* const argb_scratch, + const uint32_t* const argb, + int max_quantization, + int exact, int used_subtract_green, + const uint32_t* const modes) { + const int kNumPredModes = 14; + const int start_x = tile_x << bits; + const int start_y = tile_y << bits; + const int tile_size = 1 << bits; + const int max_y = GetMin(tile_size, height - start_y); + const int max_x = GetMin(tile_size, width - start_x); + // Whether there exist columns just outside the tile. + const int have_left = (start_x > 0); + // Position and size of the strip covering the tile and adjacent columns if + // they exist. + const int context_start_x = start_x - have_left; +#if (WEBP_NEAR_LOSSLESS == 1) + const int context_width = max_x + have_left + (max_x < width - start_x); +#endif + const int tiles_per_row = VP8LSubSampleSize(width, bits); + // Prediction modes of the left and above neighbor tiles. + const int left_mode = (tile_x > 0) ? + (modes[tile_y * tiles_per_row + tile_x - 1] >> 8) & 0xff : 0xff; + const int above_mode = (tile_y > 0) ? + (modes[(tile_y - 1) * tiles_per_row + tile_x] >> 8) & 0xff : 0xff; + // The width of upper_row and current_row is one pixel larger than image width + // to allow the top right pixel to point to the leftmost pixel of the next row + // when at the right edge. + uint32_t* upper_row = argb_scratch; + uint32_t* current_row = upper_row + width + 1; + uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1); + float best_diff = MAX_DIFF_COST; + int best_mode = 0; + int mode; + int histo_stack_1[4][256]; + int histo_stack_2[4][256]; + // Need pointers to be able to swap arrays. + int (*histo_argb)[256] = histo_stack_1; + int (*best_histo)[256] = histo_stack_2; + int i, j; + uint32_t residuals[1 << MAX_TRANSFORM_BITS]; + assert(bits <= MAX_TRANSFORM_BITS); + assert(max_x <= (1 << MAX_TRANSFORM_BITS)); + + for (mode = 0; mode < kNumPredModes; ++mode) { + float cur_diff; + int relative_y; + memset(histo_argb, 0, sizeof(histo_stack_1)); + if (start_y > 0) { + // Read the row above the tile which will become the first upper_row. + // Include a pixel to the left if it exists; include a pixel to the right + // in all cases (wrapping to the leftmost pixel of the next row if it does + // not exist). + memcpy(current_row + context_start_x, + argb + (start_y - 1) * width + context_start_x, + sizeof(*argb) * (max_x + have_left + 1)); + } + for (relative_y = 0; relative_y < max_y; ++relative_y) { + const int y = start_y + relative_y; + int relative_x; + uint32_t* tmp = upper_row; + upper_row = current_row; + current_row = tmp; + // Read current_row. Include a pixel to the left if it exists; include a + // pixel to the right in all cases except at the bottom right corner of + // the image (wrapping to the leftmost pixel of the next row if it does + // not exist in the current row). + memcpy(current_row + context_start_x, + argb + y * width + context_start_x, + sizeof(*argb) * (max_x + have_left + (y + 1 < height))); +#if (WEBP_NEAR_LOSSLESS == 1) + if (max_quantization > 1 && y >= 1 && y + 1 < height) { + MaxDiffsForRow(context_width, width, argb + y * width + context_start_x, + max_diffs + context_start_x, used_subtract_green); + } +#endif + + GetResidual(width, height, upper_row, current_row, max_diffs, mode, + start_x, start_x + max_x, y, max_quantization, exact, + used_subtract_green, residuals); + for (relative_x = 0; relative_x < max_x; ++relative_x) { + UpdateHisto(histo_argb, residuals[relative_x]); + } + } + cur_diff = PredictionCostSpatialHistogram( + (const int (*)[256])accumulated, (const int (*)[256])histo_argb); + // Favor keeping the areas locally similar. + if (mode == left_mode) cur_diff -= kSpatialPredictorBias; + if (mode == above_mode) cur_diff -= kSpatialPredictorBias; + + if (cur_diff < best_diff) { + int (*tmp)[256] = histo_argb; + histo_argb = best_histo; + best_histo = tmp; + best_diff = cur_diff; + best_mode = mode; + } + } + + for (i = 0; i < 4; i++) { + for (j = 0; j < 256; j++) { + accumulated[i][j] += best_histo[i][j]; + } + } + + return best_mode; +} + +// Converts pixels of the image to residuals with respect to predictions. +// If max_quantization > 1, applies near lossless processing, quantizing +// residuals to multiples of quantization levels up to max_quantization +// (the actual quantization level depends on smoothness near the given pixel). +static void CopyImageWithPrediction(int width, int height, + int bits, uint32_t* const modes, + uint32_t* const argb_scratch, + uint32_t* const argb, + int low_effort, int max_quantization, + int exact, int used_subtract_green) { + const int tiles_per_row = VP8LSubSampleSize(width, bits); + // The width of upper_row and current_row is one pixel larger than image width + // to allow the top right pixel to point to the leftmost pixel of the next row + // when at the right edge. + uint32_t* upper_row = argb_scratch; + uint32_t* current_row = upper_row + width + 1; + uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1); +#if (WEBP_NEAR_LOSSLESS == 1) + uint8_t* lower_max_diffs = current_max_diffs + width; +#endif + int y; + + for (y = 0; y < height; ++y) { + int x; + uint32_t* const tmp32 = upper_row; + upper_row = current_row; + current_row = tmp32; + memcpy(current_row, argb + y * width, + sizeof(*argb) * (width + (y + 1 < height))); + + if (low_effort) { + PredictBatch(kPredLowEffort, 0, y, width, current_row, upper_row, + argb + y * width); + } else { +#if (WEBP_NEAR_LOSSLESS == 1) + if (max_quantization > 1) { + // Compute max_diffs for the lower row now, because that needs the + // contents of argb for the current row, which we will overwrite with + // residuals before proceeding with the next row. + uint8_t* const tmp8 = current_max_diffs; + current_max_diffs = lower_max_diffs; + lower_max_diffs = tmp8; + if (y + 2 < height) { + MaxDiffsForRow(width, width, argb + (y + 1) * width, lower_max_diffs, + used_subtract_green); + } + } +#endif + for (x = 0; x < width;) { + const int mode = + (modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff; + int x_end = x + (1 << bits); + if (x_end > width) x_end = width; + GetResidual(width, height, upper_row, current_row, current_max_diffs, + mode, x, x_end, y, max_quantization, exact, + used_subtract_green, argb + y * width + x); + x = x_end; + } + } + } +} + +// Finds the best predictor for each tile, and converts the image to residuals +// with respect to predictions. If near_lossless_quality < 100, applies +// near lossless processing, shaving off more bits of residuals for lower +// qualities. +int VP8LResidualImage(int width, int height, int bits, int low_effort, + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image, int near_lossless_quality, + int exact, int used_subtract_green, + const WebPPicture* const pic, int percent_range, + int* const percent) { + const int tiles_per_row = VP8LSubSampleSize(width, bits); + const int tiles_per_col = VP8LSubSampleSize(height, bits); + int percent_start = *percent; + int tile_y; + int histo[4][256]; + const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality); + if (low_effort) { + int i; + for (i = 0; i < tiles_per_row * tiles_per_col; ++i) { + image[i] = ARGB_BLACK | (kPredLowEffort << 8); + } + } else { + memset(histo, 0, sizeof(histo)); + for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) { + int tile_x; + for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) { + const int pred = GetBestPredictorForTile( + width, height, tile_x, tile_y, bits, histo, argb_scratch, argb, + max_quantization, exact, used_subtract_green, image); + image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8); + } + + if (!WebPReportProgress( + pic, percent_start + percent_range * tile_y / tiles_per_col, + percent)) { + return 0; + } + } + } + + CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb, + low_effort, max_quantization, exact, + used_subtract_green); + return WebPReportProgress(pic, percent_start + percent_range, percent); +} + +//------------------------------------------------------------------------------ +// Color transform functions. + +static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) { + m->green_to_red_ = 0; + m->green_to_blue_ = 0; + m->red_to_blue_ = 0; +} + +static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, + VP8LMultipliers* const m) { + m->green_to_red_ = (color_code >> 0) & 0xff; + m->green_to_blue_ = (color_code >> 8) & 0xff; + m->red_to_blue_ = (color_code >> 16) & 0xff; +} + +static WEBP_INLINE uint32_t MultipliersToColorCode( + const VP8LMultipliers* const m) { + return 0xff000000u | + ((uint32_t)(m->red_to_blue_) << 16) | + ((uint32_t)(m->green_to_blue_) << 8) | + m->green_to_red_; +} + +static float PredictionCostCrossColor(const int accumulated[256], + const int counts[256]) { + // Favor low entropy, locally and globally. + // Favor small absolute values for PredictionCostSpatial + static const float kExpValue = 2.4f; + return VP8LCombinedShannonEntropy(counts, accumulated) + + PredictionCostSpatial(counts, 3, kExpValue); +} + +static float GetPredictionCostCrossColorRed( + const uint32_t* argb, int stride, int tile_width, int tile_height, + VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red, + const int accumulated_red_histo[256]) { + int histo[256] = { 0 }; + float cur_diff; + + VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height, + green_to_red, histo); + + cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo); + if ((uint8_t)green_to_red == prev_x.green_to_red_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if ((uint8_t)green_to_red == prev_y.green_to_red_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (green_to_red == 0) { + cur_diff -= 3; + } + return cur_diff; +} + +static void GetBestGreenToRed( + const uint32_t* argb, int stride, int tile_width, int tile_height, + VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, + const int accumulated_red_histo[256], VP8LMultipliers* const best_tx) { + const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6] + int green_to_red_best = 0; + int iter, offset; + float best_diff = GetPredictionCostCrossColorRed( + argb, stride, tile_width, tile_height, prev_x, prev_y, + green_to_red_best, accumulated_red_histo); + for (iter = 0; iter < kMaxIters; ++iter) { + // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to + // one in color computation. Having initial delta here as 1 is sufficient + // to explore the range of (-2, 2). + const int delta = 32 >> iter; + // Try a negative and a positive delta from the best known value. + for (offset = -delta; offset <= delta; offset += 2 * delta) { + const int green_to_red_cur = offset + green_to_red_best; + const float cur_diff = GetPredictionCostCrossColorRed( + argb, stride, tile_width, tile_height, prev_x, prev_y, + green_to_red_cur, accumulated_red_histo); + if (cur_diff < best_diff) { + best_diff = cur_diff; + green_to_red_best = green_to_red_cur; + } + } + } + best_tx->green_to_red_ = (green_to_red_best & 0xff); +} + +static float GetPredictionCostCrossColorBlue( + const uint32_t* argb, int stride, int tile_width, int tile_height, + VP8LMultipliers prev_x, VP8LMultipliers prev_y, + int green_to_blue, int red_to_blue, const int accumulated_blue_histo[256]) { + int histo[256] = { 0 }; + float cur_diff; + + VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height, + green_to_blue, red_to_blue, histo); + + cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo); + if ((uint8_t)green_to_blue == prev_x.green_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if ((uint8_t)green_to_blue == prev_y.green_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if ((uint8_t)red_to_blue == prev_x.red_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if ((uint8_t)red_to_blue == prev_y.red_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (green_to_blue == 0) { + cur_diff -= 3; + } + if (red_to_blue == 0) { + cur_diff -= 3; + } + return cur_diff; +} + +#define kGreenRedToBlueNumAxis 8 +#define kGreenRedToBlueMaxIters 7 +static void GetBestGreenRedToBlue( + const uint32_t* argb, int stride, int tile_width, int tile_height, + VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, + const int accumulated_blue_histo[256], + VP8LMultipliers* const best_tx) { + const int8_t offset[kGreenRedToBlueNumAxis][2] = + {{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}}; + const int8_t delta_lut[kGreenRedToBlueMaxIters] = { 16, 16, 8, 4, 2, 2, 2 }; + const int iters = + (quality < 25) ? 1 : (quality > 50) ? kGreenRedToBlueMaxIters : 4; + int green_to_blue_best = 0; + int red_to_blue_best = 0; + int iter; + // Initial value at origin: + float best_diff = GetPredictionCostCrossColorBlue( + argb, stride, tile_width, tile_height, prev_x, prev_y, + green_to_blue_best, red_to_blue_best, accumulated_blue_histo); + for (iter = 0; iter < iters; ++iter) { + const int delta = delta_lut[iter]; + int axis; + for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) { + const int green_to_blue_cur = + offset[axis][0] * delta + green_to_blue_best; + const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best; + const float cur_diff = GetPredictionCostCrossColorBlue( + argb, stride, tile_width, tile_height, prev_x, prev_y, + green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo); + if (cur_diff < best_diff) { + best_diff = cur_diff; + green_to_blue_best = green_to_blue_cur; + red_to_blue_best = red_to_blue_cur; + } + if (quality < 25 && iter == 4) { + // Only axis aligned diffs for lower quality. + break; // next iter. + } + } + if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) { + // Further iterations would not help. + break; // out of iter-loop. + } + } + best_tx->green_to_blue_ = green_to_blue_best & 0xff; + best_tx->red_to_blue_ = red_to_blue_best & 0xff; +} +#undef kGreenRedToBlueMaxIters +#undef kGreenRedToBlueNumAxis + +static VP8LMultipliers GetBestColorTransformForTile( + int tile_x, int tile_y, int bits, + VP8LMultipliers prev_x, + VP8LMultipliers prev_y, + int quality, int xsize, int ysize, + const int accumulated_red_histo[256], + const int accumulated_blue_histo[256], + const uint32_t* const argb) { + const int max_tile_size = 1 << bits; + const int tile_y_offset = tile_y * max_tile_size; + const int tile_x_offset = tile_x * max_tile_size; + const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize); + const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize); + const int tile_width = all_x_max - tile_x_offset; + const int tile_height = all_y_max - tile_y_offset; + const uint32_t* const tile_argb = argb + tile_y_offset * xsize + + tile_x_offset; + VP8LMultipliers best_tx; + MultipliersClear(&best_tx); + + GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height, + prev_x, prev_y, quality, accumulated_red_histo, &best_tx); + GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height, + prev_x, prev_y, quality, accumulated_blue_histo, + &best_tx); + return best_tx; +} + +static void CopyTileWithColorTransform(int xsize, int ysize, + int tile_x, int tile_y, + int max_tile_size, + VP8LMultipliers color_transform, + uint32_t* argb) { + const int xscan = GetMin(max_tile_size, xsize - tile_x); + int yscan = GetMin(max_tile_size, ysize - tile_y); + argb += tile_y * xsize + tile_x; + while (yscan-- > 0) { + VP8LTransformColor(&color_transform, argb, xscan); + argb += xsize; + } +} + +int VP8LColorSpaceTransform(int width, int height, int bits, int quality, + uint32_t* const argb, uint32_t* image, + const WebPPicture* const pic, int percent_range, + int* const percent) { + const int max_tile_size = 1 << bits; + const int tile_xsize = VP8LSubSampleSize(width, bits); + const int tile_ysize = VP8LSubSampleSize(height, bits); + int percent_start = *percent; + int accumulated_red_histo[256] = { 0 }; + int accumulated_blue_histo[256] = { 0 }; + int tile_x, tile_y; + VP8LMultipliers prev_x, prev_y; + MultipliersClear(&prev_y); + MultipliersClear(&prev_x); + for (tile_y = 0; tile_y < tile_ysize; ++tile_y) { + for (tile_x = 0; tile_x < tile_xsize; ++tile_x) { + int y; + const int tile_x_offset = tile_x * max_tile_size; + const int tile_y_offset = tile_y * max_tile_size; + const int all_x_max = GetMin(tile_x_offset + max_tile_size, width); + const int all_y_max = GetMin(tile_y_offset + max_tile_size, height); + const int offset = tile_y * tile_xsize + tile_x; + if (tile_y != 0) { + ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y); + } + prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits, + prev_x, prev_y, + quality, width, height, + accumulated_red_histo, + accumulated_blue_histo, + argb); + image[offset] = MultipliersToColorCode(&prev_x); + CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset, + max_tile_size, prev_x, argb); + + // Gather accumulated histogram data. + for (y = tile_y_offset; y < all_y_max; ++y) { + int ix = y * width + tile_x_offset; + const int ix_end = ix + all_x_max - tile_x_offset; + for (; ix < ix_end; ++ix) { + const uint32_t pix = argb[ix]; + if (ix >= 2 && + pix == argb[ix - 2] && + pix == argb[ix - 1]) { + continue; // repeated pixels are handled by backward references + } + if (ix >= width + 2 && + argb[ix - 2] == argb[ix - width - 2] && + argb[ix - 1] == argb[ix - width - 1] && + pix == argb[ix - width]) { + continue; // repeated pixels are handled by backward references + } + ++accumulated_red_histo[(pix >> 16) & 0xff]; + ++accumulated_blue_histo[(pix >> 0) & 0xff]; + } + } + } + if (!WebPReportProgress( + pic, percent_start + percent_range * tile_y / tile_ysize, + percent)) { + return 0; + } + } + return 1; +} diff --git a/libraries/webp/src/enc/quant_enc.c b/libraries/webp/src/enc/quant_enc.c new file mode 100644 index 00000000000..6d8202d2771 --- /dev/null +++ b/libraries/webp/src/enc/quant_enc.c @@ -0,0 +1,1398 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Quantization +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include // for abs() + +#include "src/dsp/quant.h" +#include "src/enc/vp8i_enc.h" +#include "src/enc/cost_enc.h" + +#define DO_TRELLIS_I4 1 +#define DO_TRELLIS_I16 1 // not a huge gain, but ok at low bitrate. +#define DO_TRELLIS_UV 0 // disable trellis for UV. Risky. Not worth. +#define USE_TDISTO 1 + +#define MID_ALPHA 64 // neutral value for susceptibility +#define MIN_ALPHA 30 // lowest usable value for susceptibility +#define MAX_ALPHA 100 // higher meaningful value for susceptibility + +#define SNS_TO_DQ 0.9 // Scaling constant between the sns value and the QP + // power-law modulation. Must be strictly less than 1. + +// number of non-zero coeffs below which we consider the block very flat +// (and apply a penalty to complex predictions) +#define FLATNESS_LIMIT_I16 0 // I16 mode (special case) +#define FLATNESS_LIMIT_I4 3 // I4 mode +#define FLATNESS_LIMIT_UV 2 // UV mode +#define FLATNESS_PENALTY 140 // roughly ~1bit per block + +#define MULT_8B(a, b) (((a) * (b) + 128) >> 8) + +#define RD_DISTO_MULT 256 // distortion multiplier (equivalent of lambda) + +// #define DEBUG_BLOCK + +//------------------------------------------------------------------------------ + +#if defined(DEBUG_BLOCK) + +#include +#include + +static void PrintBlockInfo(const VP8EncIterator* const it, + const VP8ModeScore* const rd) { + int i, j; + const int is_i16 = (it->mb_->type_ == 1); + const uint8_t* const y_in = it->yuv_in_ + Y_OFF_ENC; + const uint8_t* const y_out = it->yuv_out_ + Y_OFF_ENC; + const uint8_t* const uv_in = it->yuv_in_ + U_OFF_ENC; + const uint8_t* const uv_out = it->yuv_out_ + U_OFF_ENC; + printf("SOURCE / OUTPUT / ABS DELTA\n"); + for (j = 0; j < 16; ++j) { + for (i = 0; i < 16; ++i) printf("%3d ", y_in[i + j * BPS]); + printf(" "); + for (i = 0; i < 16; ++i) printf("%3d ", y_out[i + j * BPS]); + printf(" "); + for (i = 0; i < 16; ++i) { + printf("%1d ", abs(y_in[i + j * BPS] - y_out[i + j * BPS])); + } + printf("\n"); + } + printf("\n"); // newline before the U/V block + for (j = 0; j < 8; ++j) { + for (i = 0; i < 8; ++i) printf("%3d ", uv_in[i + j * BPS]); + printf(" "); + for (i = 8; i < 16; ++i) printf("%3d ", uv_in[i + j * BPS]); + printf(" "); + for (i = 0; i < 8; ++i) printf("%3d ", uv_out[i + j * BPS]); + printf(" "); + for (i = 8; i < 16; ++i) printf("%3d ", uv_out[i + j * BPS]); + printf(" "); + for (i = 0; i < 8; ++i) { + printf("%1d ", abs(uv_out[i + j * BPS] - uv_in[i + j * BPS])); + } + printf(" "); + for (i = 8; i < 16; ++i) { + printf("%1d ", abs(uv_out[i + j * BPS] - uv_in[i + j * BPS])); + } + printf("\n"); + } + printf("\nD:%d SD:%d R:%d H:%d nz:0x%x score:%d\n", + (int)rd->D, (int)rd->SD, (int)rd->R, (int)rd->H, (int)rd->nz, + (int)rd->score); + if (is_i16) { + printf("Mode: %d\n", rd->mode_i16); + printf("y_dc_levels:"); + for (i = 0; i < 16; ++i) printf("%3d ", rd->y_dc_levels[i]); + printf("\n"); + } else { + printf("Modes[16]: "); + for (i = 0; i < 16; ++i) printf("%d ", rd->modes_i4[i]); + printf("\n"); + } + printf("y_ac_levels:\n"); + for (j = 0; j < 16; ++j) { + for (i = is_i16 ? 1 : 0; i < 16; ++i) { + printf("%4d ", rd->y_ac_levels[j][i]); + } + printf("\n"); + } + printf("\n"); + printf("uv_levels (mode=%d):\n", rd->mode_uv); + for (j = 0; j < 8; ++j) { + for (i = 0; i < 16; ++i) { + printf("%4d ", rd->uv_levels[j][i]); + } + printf("\n"); + } +} + +#endif // DEBUG_BLOCK + +//------------------------------------------------------------------------------ + +static WEBP_INLINE int clip(int v, int m, int M) { + return v < m ? m : v > M ? M : v; +} + +static const uint8_t kZigzag[16] = { + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +static const uint8_t kDcTable[128] = { + 4, 5, 6, 7, 8, 9, 10, 10, + 11, 12, 13, 14, 15, 16, 17, 17, + 18, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 25, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 37, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, + 91, 93, 95, 96, 98, 100, 101, 102, + 104, 106, 108, 110, 112, 114, 116, 118, + 122, 124, 126, 128, 130, 132, 134, 136, + 138, 140, 143, 145, 148, 151, 154, 157 +}; + +static const uint16_t kAcTable[128] = { + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 60, + 62, 64, 66, 68, 70, 72, 74, 76, + 78, 80, 82, 84, 86, 88, 90, 92, + 94, 96, 98, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 119, 122, 125, 128, + 131, 134, 137, 140, 143, 146, 149, 152, + 155, 158, 161, 164, 167, 170, 173, 177, + 181, 185, 189, 193, 197, 201, 205, 209, + 213, 217, 221, 225, 229, 234, 239, 245, + 249, 254, 259, 264, 269, 274, 279, 284 +}; + +static const uint16_t kAcTable2[128] = { + 8, 8, 9, 10, 12, 13, 15, 17, + 18, 20, 21, 23, 24, 26, 27, 29, + 31, 32, 34, 35, 37, 38, 40, 41, + 43, 44, 46, 48, 49, 51, 52, 54, + 55, 57, 58, 60, 62, 63, 65, 66, + 68, 69, 71, 72, 74, 75, 77, 79, + 80, 82, 83, 85, 86, 88, 89, 93, + 96, 99, 102, 105, 108, 111, 114, 117, + 120, 124, 127, 130, 133, 136, 139, 142, + 145, 148, 151, 155, 158, 161, 164, 167, + 170, 173, 176, 179, 184, 189, 193, 198, + 203, 207, 212, 217, 221, 226, 230, 235, + 240, 244, 249, 254, 258, 263, 268, 274, + 280, 286, 292, 299, 305, 311, 317, 323, + 330, 336, 342, 348, 354, 362, 370, 379, + 385, 393, 401, 409, 416, 424, 432, 440 +}; + +static const uint8_t kBiasMatrices[3][2] = { // [luma-ac,luma-dc,chroma][dc,ac] + { 96, 110 }, { 96, 108 }, { 110, 115 } +}; + +// Sharpening by (slightly) raising the hi-frequency coeffs. +// Hack-ish but helpful for mid-bitrate range. Use with care. +#define SHARPEN_BITS 11 // number of descaling bits for sharpening bias +static const uint8_t kFreqSharpening[16] = { + 0, 30, 60, 90, + 30, 60, 90, 90, + 60, 90, 90, 90, + 90, 90, 90, 90 +}; + +//------------------------------------------------------------------------------ +// Initialize quantization parameters in VP8Matrix + +// Returns the average quantizer +static int ExpandMatrix(VP8Matrix* const m, int type) { + int i, sum; + for (i = 0; i < 2; ++i) { + const int is_ac_coeff = (i > 0); + const int bias = kBiasMatrices[type][is_ac_coeff]; + m->iq_[i] = (1 << QFIX) / m->q_[i]; + m->bias_[i] = BIAS(bias); + // zthresh_ is the exact value such that QUANTDIV(coeff, iQ, B) is: + // * zero if coeff <= zthresh + // * non-zero if coeff > zthresh + m->zthresh_[i] = ((1 << QFIX) - 1 - m->bias_[i]) / m->iq_[i]; + } + for (i = 2; i < 16; ++i) { + m->q_[i] = m->q_[1]; + m->iq_[i] = m->iq_[1]; + m->bias_[i] = m->bias_[1]; + m->zthresh_[i] = m->zthresh_[1]; + } + for (sum = 0, i = 0; i < 16; ++i) { + if (type == 0) { // we only use sharpening for AC luma coeffs + m->sharpen_[i] = (kFreqSharpening[i] * m->q_[i]) >> SHARPEN_BITS; + } else { + m->sharpen_[i] = 0; + } + sum += m->q_[i]; + } + return (sum + 8) >> 4; +} + +static void CheckLambdaValue(int* const v) { if (*v < 1) *v = 1; } + +static void SetupMatrices(VP8Encoder* enc) { + int i; + const int tlambda_scale = + (enc->method_ >= 4) ? enc->config_->sns_strength + : 0; + const int num_segments = enc->segment_hdr_.num_segments_; + for (i = 0; i < num_segments; ++i) { + VP8SegmentInfo* const m = &enc->dqm_[i]; + const int q = m->quant_; + int q_i4, q_i16, q_uv; + m->y1_.q_[0] = kDcTable[clip(q + enc->dq_y1_dc_, 0, 127)]; + m->y1_.q_[1] = kAcTable[clip(q, 0, 127)]; + + m->y2_.q_[0] = kDcTable[ clip(q + enc->dq_y2_dc_, 0, 127)] * 2; + m->y2_.q_[1] = kAcTable2[clip(q + enc->dq_y2_ac_, 0, 127)]; + + m->uv_.q_[0] = kDcTable[clip(q + enc->dq_uv_dc_, 0, 117)]; + m->uv_.q_[1] = kAcTable[clip(q + enc->dq_uv_ac_, 0, 127)]; + + q_i4 = ExpandMatrix(&m->y1_, 0); + q_i16 = ExpandMatrix(&m->y2_, 1); + q_uv = ExpandMatrix(&m->uv_, 2); + + m->lambda_i4_ = (3 * q_i4 * q_i4) >> 7; + m->lambda_i16_ = (3 * q_i16 * q_i16); + m->lambda_uv_ = (3 * q_uv * q_uv) >> 6; + m->lambda_mode_ = (1 * q_i4 * q_i4) >> 7; + m->lambda_trellis_i4_ = (7 * q_i4 * q_i4) >> 3; + m->lambda_trellis_i16_ = (q_i16 * q_i16) >> 2; + m->lambda_trellis_uv_ = (q_uv * q_uv) << 1; + m->tlambda_ = (tlambda_scale * q_i4) >> 5; + + // none of these constants should be < 1 + CheckLambdaValue(&m->lambda_i4_); + CheckLambdaValue(&m->lambda_i16_); + CheckLambdaValue(&m->lambda_uv_); + CheckLambdaValue(&m->lambda_mode_); + CheckLambdaValue(&m->lambda_trellis_i4_); + CheckLambdaValue(&m->lambda_trellis_i16_); + CheckLambdaValue(&m->lambda_trellis_uv_); + CheckLambdaValue(&m->tlambda_); + + m->min_disto_ = 20 * m->y1_.q_[0]; // quantization-aware min disto + m->max_edge_ = 0; + + m->i4_penalty_ = 1000 * q_i4 * q_i4; + } +} + +//------------------------------------------------------------------------------ +// Initialize filtering parameters + +// Very small filter-strength values have close to no visual effect. So we can +// save a little decoding-CPU by turning filtering off for these. +#define FSTRENGTH_CUTOFF 2 + +static void SetupFilterStrength(VP8Encoder* const enc) { + int i; + // level0 is in [0..500]. Using '-f 50' as filter_strength is mid-filtering. + const int level0 = 5 * enc->config_->filter_strength; + for (i = 0; i < NUM_MB_SEGMENTS; ++i) { + VP8SegmentInfo* const m = &enc->dqm_[i]; + // We focus on the quantization of AC coeffs. + const int qstep = kAcTable[clip(m->quant_, 0, 127)] >> 2; + const int base_strength = + VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, qstep); + // Segments with lower complexity ('beta') will be less filtered. + const int f = base_strength * level0 / (256 + m->beta_); + m->fstrength_ = (f < FSTRENGTH_CUTOFF) ? 0 : (f > 63) ? 63 : f; + } + // We record the initial strength (mainly for the case of 1-segment only). + enc->filter_hdr_.level_ = enc->dqm_[0].fstrength_; + enc->filter_hdr_.simple_ = (enc->config_->filter_type == 0); + enc->filter_hdr_.sharpness_ = enc->config_->filter_sharpness; +} + +//------------------------------------------------------------------------------ + +// Note: if you change the values below, remember that the max range +// allowed by the syntax for DQ_UV is [-16,16]. +#define MAX_DQ_UV (6) +#define MIN_DQ_UV (-4) + +// We want to emulate jpeg-like behaviour where the expected "good" quality +// is around q=75. Internally, our "good" middle is around c=50. So we +// map accordingly using linear piece-wise function +static double QualityToCompression(double c) { + const double linear_c = (c < 0.75) ? c * (2. / 3.) : 2. * c - 1.; + // The file size roughly scales as pow(quantizer, 3.). Actually, the + // exponent is somewhere between 2.8 and 3.2, but we're mostly interested + // in the mid-quant range. So we scale the compressibility inversely to + // this power-law: quant ~= compression ^ 1/3. This law holds well for + // low quant. Finer modeling for high-quant would make use of kAcTable[] + // more explicitly. + const double v = pow(linear_c, 1 / 3.); + return v; +} + +static double QualityToJPEGCompression(double c, double alpha) { + // We map the complexity 'alpha' and quality setting 'c' to a compression + // exponent empirically matched to the compression curve of libjpeg6b. + // On average, the WebP output size will be roughly similar to that of a + // JPEG file compressed with same quality factor. + const double amin = 0.30; + const double amax = 0.85; + const double exp_min = 0.4; + const double exp_max = 0.9; + const double slope = (exp_min - exp_max) / (amax - amin); + // Linearly interpolate 'expn' from exp_min to exp_max + // in the [amin, amax] range. + const double expn = (alpha > amax) ? exp_min + : (alpha < amin) ? exp_max + : exp_max + slope * (alpha - amin); + const double v = pow(c, expn); + return v; +} + +static int SegmentsAreEquivalent(const VP8SegmentInfo* const S1, + const VP8SegmentInfo* const S2) { + return (S1->quant_ == S2->quant_) && (S1->fstrength_ == S2->fstrength_); +} + +static void SimplifySegments(VP8Encoder* const enc) { + int map[NUM_MB_SEGMENTS] = { 0, 1, 2, 3 }; + // 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an + // explicit check is needed to avoid a spurious warning about 'i' exceeding + // array bounds of 'dqm_' with some compilers (noticed with gcc-4.9). + const int num_segments = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) + ? enc->segment_hdr_.num_segments_ + : NUM_MB_SEGMENTS; + int num_final_segments = 1; + int s1, s2; + for (s1 = 1; s1 < num_segments; ++s1) { // find similar segments + const VP8SegmentInfo* const S1 = &enc->dqm_[s1]; + int found = 0; + // check if we already have similar segment + for (s2 = 0; s2 < num_final_segments; ++s2) { + const VP8SegmentInfo* const S2 = &enc->dqm_[s2]; + if (SegmentsAreEquivalent(S1, S2)) { + found = 1; + break; + } + } + map[s1] = s2; + if (!found) { + if (num_final_segments != s1) { + enc->dqm_[num_final_segments] = enc->dqm_[s1]; + } + ++num_final_segments; + } + } + if (num_final_segments < num_segments) { // Remap + int i = enc->mb_w_ * enc->mb_h_; + while (i-- > 0) enc->mb_info_[i].segment_ = map[enc->mb_info_[i].segment_]; + enc->segment_hdr_.num_segments_ = num_final_segments; + // Replicate the trailing segment infos (it's mostly cosmetics) + for (i = num_final_segments; i < num_segments; ++i) { + enc->dqm_[i] = enc->dqm_[num_final_segments - 1]; + } + } +} + +void VP8SetSegmentParams(VP8Encoder* const enc, float quality) { + int i; + int dq_uv_ac, dq_uv_dc; + const int num_segments = enc->segment_hdr_.num_segments_; + const double amp = SNS_TO_DQ * enc->config_->sns_strength / 100. / 128.; + const double Q = quality / 100.; + const double c_base = enc->config_->emulate_jpeg_size ? + QualityToJPEGCompression(Q, enc->alpha_ / 255.) : + QualityToCompression(Q); + for (i = 0; i < num_segments; ++i) { + // We modulate the base coefficient to accommodate for the quantization + // susceptibility and allow denser segments to be quantized more. + const double expn = 1. - amp * enc->dqm_[i].alpha_; + const double c = pow(c_base, expn); + const int q = (int)(127. * (1. - c)); + assert(expn > 0.); + enc->dqm_[i].quant_ = clip(q, 0, 127); + } + + // purely indicative in the bitstream (except for the 1-segment case) + enc->base_quant_ = enc->dqm_[0].quant_; + + // fill-in values for the unused segments (required by the syntax) + for (i = num_segments; i < NUM_MB_SEGMENTS; ++i) { + enc->dqm_[i].quant_ = enc->base_quant_; + } + + // uv_alpha_ is normally spread around ~60. The useful range is + // typically ~30 (quite bad) to ~100 (ok to decimate UV more). + // We map it to the safe maximal range of MAX/MIN_DQ_UV for dq_uv. + dq_uv_ac = (enc->uv_alpha_ - MID_ALPHA) * (MAX_DQ_UV - MIN_DQ_UV) + / (MAX_ALPHA - MIN_ALPHA); + // we rescale by the user-defined strength of adaptation + dq_uv_ac = dq_uv_ac * enc->config_->sns_strength / 100; + // and make it safe. + dq_uv_ac = clip(dq_uv_ac, MIN_DQ_UV, MAX_DQ_UV); + // We also boost the dc-uv-quant a little, based on sns-strength, since + // U/V channels are quite more reactive to high quants (flat DC-blocks + // tend to appear, and are unpleasant). + dq_uv_dc = -4 * enc->config_->sns_strength / 100; + dq_uv_dc = clip(dq_uv_dc, -15, 15); // 4bit-signed max allowed + + enc->dq_y1_dc_ = 0; // TODO(skal): dq-lum + enc->dq_y2_dc_ = 0; + enc->dq_y2_ac_ = 0; + enc->dq_uv_dc_ = dq_uv_dc; + enc->dq_uv_ac_ = dq_uv_ac; + + SetupFilterStrength(enc); // initialize segments' filtering, eventually + + if (num_segments > 1) SimplifySegments(enc); + + SetupMatrices(enc); // finalize quantization matrices +} + +//------------------------------------------------------------------------------ +// Form the predictions in cache + +// Must be ordered using {DC_PRED, TM_PRED, V_PRED, H_PRED} as index +const uint16_t VP8I16ModeOffsets[4] = { I16DC16, I16TM16, I16VE16, I16HE16 }; +const uint16_t VP8UVModeOffsets[4] = { C8DC8, C8TM8, C8VE8, C8HE8 }; + +// Must be indexed using {B_DC_PRED -> B_HU_PRED} as index +const uint16_t VP8I4ModeOffsets[NUM_BMODES] = { + I4DC4, I4TM4, I4VE4, I4HE4, I4RD4, I4VR4, I4LD4, I4VL4, I4HD4, I4HU4 +}; + +void VP8MakeLuma16Preds(const VP8EncIterator* const it) { + const uint8_t* const left = it->x_ ? it->y_left_ : NULL; + const uint8_t* const top = it->y_ ? it->y_top_ : NULL; + VP8EncPredLuma16(it->yuv_p_, left, top); +} + +void VP8MakeChroma8Preds(const VP8EncIterator* const it) { + const uint8_t* const left = it->x_ ? it->u_left_ : NULL; + const uint8_t* const top = it->y_ ? it->uv_top_ : NULL; + VP8EncPredChroma8(it->yuv_p_, left, top); +} + +void VP8MakeIntra4Preds(const VP8EncIterator* const it) { + VP8EncPredLuma4(it->yuv_p_, it->i4_top_); +} + +//------------------------------------------------------------------------------ +// Quantize + +// Layout: +// +----+----+ +// |YYYY|UUVV| 0 +// |YYYY|UUVV| 4 +// |YYYY|....| 8 +// |YYYY|....| 12 +// +----+----+ + +const uint16_t VP8Scan[16] = { // Luma + 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, + 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, + 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, + 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS, +}; + +static const uint16_t VP8ScanUV[4 + 4] = { + 0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U + 8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V +}; + +//------------------------------------------------------------------------------ +// Distortion measurement + +static const uint16_t kWeightY[16] = { + 38, 32, 20, 9, 32, 28, 17, 7, 20, 17, 10, 4, 9, 7, 4, 2 +}; + +static const uint16_t kWeightTrellis[16] = { +#if USE_TDISTO == 0 + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 +#else + 30, 27, 19, 11, + 27, 24, 17, 10, + 19, 17, 12, 8, + 11, 10, 8, 6 +#endif +}; + +// Init/Copy the common fields in score. +static void InitScore(VP8ModeScore* const rd) { + rd->D = 0; + rd->SD = 0; + rd->R = 0; + rd->H = 0; + rd->nz = 0; + rd->score = MAX_COST; +} + +static void CopyScore(VP8ModeScore* WEBP_RESTRICT const dst, + const VP8ModeScore* WEBP_RESTRICT const src) { + dst->D = src->D; + dst->SD = src->SD; + dst->R = src->R; + dst->H = src->H; + dst->nz = src->nz; // note that nz is not accumulated, but just copied. + dst->score = src->score; +} + +static void AddScore(VP8ModeScore* WEBP_RESTRICT const dst, + const VP8ModeScore* WEBP_RESTRICT const src) { + dst->D += src->D; + dst->SD += src->SD; + dst->R += src->R; + dst->H += src->H; + dst->nz |= src->nz; // here, new nz bits are accumulated. + dst->score += src->score; +} + +//------------------------------------------------------------------------------ +// Performs trellis-optimized quantization. + +// Trellis node +typedef struct { + int8_t prev; // best previous node + int8_t sign; // sign of coeff_i + int16_t level; // level +} Node; + +// Score state +typedef struct { + score_t score; // partial RD score + const uint16_t* costs; // shortcut to cost tables +} ScoreState; + +// If a coefficient was quantized to a value Q (using a neutral bias), +// we test all alternate possibilities between [Q-MIN_DELTA, Q+MAX_DELTA] +// We don't test negative values though. +#define MIN_DELTA 0 // how much lower level to try +#define MAX_DELTA 1 // how much higher +#define NUM_NODES (MIN_DELTA + 1 + MAX_DELTA) +#define NODE(n, l) (nodes[(n)][(l) + MIN_DELTA]) +#define SCORE_STATE(n, l) (score_states[n][(l) + MIN_DELTA]) + +static WEBP_INLINE void SetRDScore(int lambda, VP8ModeScore* const rd) { + rd->score = (rd->R + rd->H) * lambda + RD_DISTO_MULT * (rd->D + rd->SD); +} + +static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate, + score_t distortion) { + return rate * lambda + RD_DISTO_MULT * distortion; +} + +// Coefficient type. +enum { TYPE_I16_AC = 0, TYPE_I16_DC = 1, TYPE_CHROMA_A = 2, TYPE_I4_AC = 3 }; + +static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc, + int16_t in[16], int16_t out[16], + int ctx0, int coeff_type, + const VP8Matrix* WEBP_RESTRICT const mtx, + int lambda) { + const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type]; + CostArrayPtr const costs = + (CostArrayPtr)enc->proba_.remapped_costs_[coeff_type]; + const int first = (coeff_type == TYPE_I16_AC) ? 1 : 0; + Node nodes[16][NUM_NODES]; + ScoreState score_states[2][NUM_NODES]; + ScoreState* ss_cur = &SCORE_STATE(0, MIN_DELTA); + ScoreState* ss_prev = &SCORE_STATE(1, MIN_DELTA); + int best_path[3] = {-1, -1, -1}; // store best-last/best-level/best-previous + score_t best_score; + int n, m, p, last; + + { + score_t cost; + const int thresh = mtx->q_[1] * mtx->q_[1] / 4; + const int last_proba = probas[VP8EncBands[first]][ctx0][0]; + + // compute the position of the last interesting coefficient + last = first - 1; + for (n = 15; n >= first; --n) { + const int j = kZigzag[n]; + const int err = in[j] * in[j]; + if (err > thresh) { + last = n; + break; + } + } + // we don't need to go inspect up to n = 16 coeffs. We can just go up + // to last + 1 (inclusive) without losing much. + if (last < 15) ++last; + + // compute 'skip' score. This is the max score one can do. + cost = VP8BitCost(0, last_proba); + best_score = RDScoreTrellis(lambda, cost, 0); + + // initialize source node. + for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) { + const score_t rate = (ctx0 == 0) ? VP8BitCost(1, last_proba) : 0; + ss_cur[m].score = RDScoreTrellis(lambda, rate, 0); + ss_cur[m].costs = costs[first][ctx0]; + } + } + + // traverse trellis. + for (n = first; n <= last; ++n) { + const int j = kZigzag[n]; + const uint32_t Q = mtx->q_[j]; + const uint32_t iQ = mtx->iq_[j]; + const uint32_t B = BIAS(0x00); // neutral bias + // note: it's important to take sign of the _original_ coeff, + // so we don't have to consider level < 0 afterward. + const int sign = (in[j] < 0); + const uint32_t coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; + int level0 = QUANTDIV(coeff0, iQ, B); + int thresh_level = QUANTDIV(coeff0, iQ, BIAS(0x80)); + if (thresh_level > MAX_LEVEL) thresh_level = MAX_LEVEL; + if (level0 > MAX_LEVEL) level0 = MAX_LEVEL; + + { // Swap current and previous score states + ScoreState* const tmp = ss_cur; + ss_cur = ss_prev; + ss_prev = tmp; + } + + // test all alternate level values around level0. + for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) { + Node* const cur = &NODE(n, m); + const int level = level0 + m; + const int ctx = (level > 2) ? 2 : level; + const int band = VP8EncBands[n + 1]; + score_t base_score; + score_t best_cur_score; + int best_prev; + score_t cost, score; + + ss_cur[m].costs = costs[n + 1][ctx]; + if (level < 0 || level > thresh_level) { + ss_cur[m].score = MAX_COST; + // Node is dead. + continue; + } + + { + // Compute delta_error = how much coding this level will + // subtract to max_error as distortion. + // Here, distortion = sum of (|coeff_i| - level_i * Q_i)^2 + const int new_error = coeff0 - level * Q; + const int delta_error = + kWeightTrellis[j] * (new_error * new_error - coeff0 * coeff0); + base_score = RDScoreTrellis(lambda, 0, delta_error); + } + + // Inspect all possible non-dead predecessors. Retain only the best one. + // The base_score is added to all scores so it is only added for the final + // value after the loop. + cost = VP8LevelCost(ss_prev[-MIN_DELTA].costs, level); + best_cur_score = + ss_prev[-MIN_DELTA].score + RDScoreTrellis(lambda, cost, 0); + best_prev = -MIN_DELTA; + for (p = -MIN_DELTA + 1; p <= MAX_DELTA; ++p) { + // Dead nodes (with ss_prev[p].score >= MAX_COST) are automatically + // eliminated since their score can't be better than the current best. + cost = VP8LevelCost(ss_prev[p].costs, level); + // Examine node assuming it's a non-terminal one. + score = ss_prev[p].score + RDScoreTrellis(lambda, cost, 0); + if (score < best_cur_score) { + best_cur_score = score; + best_prev = p; + } + } + best_cur_score += base_score; + // Store best finding in current node. + cur->sign = sign; + cur->level = level; + cur->prev = best_prev; + ss_cur[m].score = best_cur_score; + + // Now, record best terminal node (and thus best entry in the graph). + if (level != 0 && best_cur_score < best_score) { + const score_t last_pos_cost = + (n < 15) ? VP8BitCost(0, probas[band][ctx][0]) : 0; + const score_t last_pos_score = RDScoreTrellis(lambda, last_pos_cost, 0); + score = best_cur_score + last_pos_score; + if (score < best_score) { + best_score = score; + best_path[0] = n; // best eob position + best_path[1] = m; // best node index + best_path[2] = best_prev; // best predecessor + } + } + } + } + + // Fresh start + // Beware! We must preserve in[0]/out[0] value for TYPE_I16_AC case. + if (coeff_type == TYPE_I16_AC) { + memset(in + 1, 0, 15 * sizeof(*in)); + memset(out + 1, 0, 15 * sizeof(*out)); + } else { + memset(in, 0, 16 * sizeof(*in)); + memset(out, 0, 16 * sizeof(*out)); + } + if (best_path[0] == -1) { + return 0; // skip! + } + + { + // Unwind the best path. + // Note: best-prev on terminal node is not necessarily equal to the + // best_prev for non-terminal. So we patch best_path[2] in. + int nz = 0; + int best_node = best_path[1]; + n = best_path[0]; + NODE(n, best_node).prev = best_path[2]; // force best-prev for terminal + + for (; n >= first; --n) { + const Node* const node = &NODE(n, best_node); + const int j = kZigzag[n]; + out[n] = node->sign ? -node->level : node->level; + nz |= node->level; + in[j] = out[n] * mtx->q_[j]; + best_node = node->prev; + } + return (nz != 0); + } +} + +#undef NODE + +//------------------------------------------------------------------------------ +// Performs: difference, transform, quantize, back-transform, add +// all at once. Output is the reconstructed block in *yuv_out, and the +// quantized levels in *levels. + +static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd, + uint8_t* WEBP_RESTRICT const yuv_out, + int mode) { + const VP8Encoder* const enc = it->enc_; + const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode]; + const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + int nz = 0; + int n; + int16_t tmp[16][16], dc_tmp[16]; + + for (n = 0; n < 16; n += 2) { + VP8FTransform2(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]); + } + VP8FTransformWHT(tmp[0], dc_tmp); + nz |= VP8EncQuantizeBlockWHT(dc_tmp, rd->y_dc_levels, &dqm->y2_) << 24; + + if (DO_TRELLIS_I16 && it->do_trellis_) { + int x, y; + VP8IteratorNzToBytes(it); + for (y = 0, n = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x, ++n) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + const int non_zero = TrellisQuantizeBlock( + enc, tmp[n], rd->y_ac_levels[n], ctx, TYPE_I16_AC, &dqm->y1_, + dqm->lambda_trellis_i16_); + it->top_nz_[x] = it->left_nz_[y] = non_zero; + rd->y_ac_levels[n][0] = 0; + nz |= non_zero << n; + } + } + } else { + for (n = 0; n < 16; n += 2) { + // Zero-out the first coeff, so that: a) nz is correct below, and + // b) finding 'last' non-zero coeffs in SetResidualCoeffs() is simplified. + tmp[n][0] = tmp[n + 1][0] = 0; + nz |= VP8EncQuantize2Blocks(tmp[n], rd->y_ac_levels[n], &dqm->y1_) << n; + assert(rd->y_ac_levels[n + 0][0] == 0); + assert(rd->y_ac_levels[n + 1][0] == 0); + } + } + + // Transform back + VP8TransformWHT(dc_tmp, tmp[0]); + for (n = 0; n < 16; n += 2) { + VP8ITransform(ref + VP8Scan[n], tmp[n], yuv_out + VP8Scan[n], 1); + } + + return nz; +} + +static int ReconstructIntra4(VP8EncIterator* WEBP_RESTRICT const it, + int16_t levels[16], + const uint8_t* WEBP_RESTRICT const src, + uint8_t* WEBP_RESTRICT const yuv_out, + int mode) { + const VP8Encoder* const enc = it->enc_; + const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode]; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + int nz = 0; + int16_t tmp[16]; + + VP8FTransform(src, ref, tmp); + if (DO_TRELLIS_I4 && it->do_trellis_) { + const int x = it->i4_ & 3, y = it->i4_ >> 2; + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + nz = TrellisQuantizeBlock(enc, tmp, levels, ctx, TYPE_I4_AC, &dqm->y1_, + dqm->lambda_trellis_i4_); + } else { + nz = VP8EncQuantizeBlock(tmp, levels, &dqm->y1_); + } + VP8ITransform(ref, tmp, yuv_out, 0); + return nz; +} + +//------------------------------------------------------------------------------ +// DC-error diffusion + +// Diffusion weights. We under-correct a bit (15/16th of the error is actually +// diffused) to avoid 'rainbow' chessboard pattern of blocks at q~=0. +#define C1 7 // fraction of error sent to the 4x4 block below +#define C2 8 // fraction of error sent to the 4x4 block on the right +#define DSHIFT 4 +#define DSCALE 1 // storage descaling, needed to make the error fit int8_t + +// Quantize as usual, but also compute and return the quantization error. +// Error is already divided by DSHIFT. +static int QuantizeSingle(int16_t* WEBP_RESTRICT const v, + const VP8Matrix* WEBP_RESTRICT const mtx) { + int V = *v; + const int sign = (V < 0); + if (sign) V = -V; + if (V > (int)mtx->zthresh_[0]) { + const int qV = QUANTDIV(V, mtx->iq_[0], mtx->bias_[0]) * mtx->q_[0]; + const int err = (V - qV); + *v = sign ? -qV : qV; + return (sign ? -err : err) >> DSCALE; + } + *v = 0; + return (sign ? -V : V) >> DSCALE; +} + +static void CorrectDCValues(const VP8EncIterator* WEBP_RESTRICT const it, + const VP8Matrix* WEBP_RESTRICT const mtx, + int16_t tmp[][16], + VP8ModeScore* WEBP_RESTRICT const rd) { + // | top[0] | top[1] + // --------+--------+--------- + // left[0] | tmp[0] tmp[1] <-> err0 err1 + // left[1] | tmp[2] tmp[3] err2 err3 + // + // Final errors {err1,err2,err3} are preserved and later restored + // as top[]/left[] on the next block. + int ch; + for (ch = 0; ch <= 1; ++ch) { + const int8_t* const top = it->top_derr_[it->x_][ch]; + const int8_t* const left = it->left_derr_[ch]; + int16_t (* const c)[16] = &tmp[ch * 4]; + int err0, err1, err2, err3; + c[0][0] += (C1 * top[0] + C2 * left[0]) >> (DSHIFT - DSCALE); + err0 = QuantizeSingle(&c[0][0], mtx); + c[1][0] += (C1 * top[1] + C2 * err0) >> (DSHIFT - DSCALE); + err1 = QuantizeSingle(&c[1][0], mtx); + c[2][0] += (C1 * err0 + C2 * left[1]) >> (DSHIFT - DSCALE); + err2 = QuantizeSingle(&c[2][0], mtx); + c[3][0] += (C1 * err1 + C2 * err2) >> (DSHIFT - DSCALE); + err3 = QuantizeSingle(&c[3][0], mtx); + // error 'err' is bounded by mtx->q_[0] which is 132 at max. Hence + // err >> DSCALE will fit in an int8_t type if DSCALE>=1. + assert(abs(err1) <= 127 && abs(err2) <= 127 && abs(err3) <= 127); + rd->derr[ch][0] = (int8_t)err1; + rd->derr[ch][1] = (int8_t)err2; + rd->derr[ch][2] = (int8_t)err3; + } +} + +static void StoreDiffusionErrors(VP8EncIterator* WEBP_RESTRICT const it, + const VP8ModeScore* WEBP_RESTRICT const rd) { + int ch; + for (ch = 0; ch <= 1; ++ch) { + int8_t* const top = it->top_derr_[it->x_][ch]; + int8_t* const left = it->left_derr_[ch]; + left[0] = rd->derr[ch][0]; // restore err1 + left[1] = 3 * rd->derr[ch][2] >> 2; // ... 3/4th of err3 + top[0] = rd->derr[ch][1]; // ... err2 + top[1] = rd->derr[ch][2] - left[1]; // ... 1/4th of err3. + } +} + +#undef C1 +#undef C2 +#undef DSHIFT +#undef DSCALE + +//------------------------------------------------------------------------------ + +static int ReconstructUV(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd, + uint8_t* WEBP_RESTRICT const yuv_out, int mode) { + const VP8Encoder* const enc = it->enc_; + const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode]; + const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + int nz = 0; + int n; + int16_t tmp[8][16]; + + for (n = 0; n < 8; n += 2) { + VP8FTransform2(src + VP8ScanUV[n], ref + VP8ScanUV[n], tmp[n]); + } + if (it->top_derr_ != NULL) CorrectDCValues(it, &dqm->uv_, tmp, rd); + + if (DO_TRELLIS_UV && it->do_trellis_) { + int ch, x, y; + for (ch = 0, n = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x, ++n) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + const int non_zero = TrellisQuantizeBlock( + enc, tmp[n], rd->uv_levels[n], ctx, TYPE_CHROMA_A, &dqm->uv_, + dqm->lambda_trellis_uv_); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = non_zero; + nz |= non_zero << n; + } + } + } + } else { + for (n = 0; n < 8; n += 2) { + nz |= VP8EncQuantize2Blocks(tmp[n], rd->uv_levels[n], &dqm->uv_) << n; + } + } + + for (n = 0; n < 8; n += 2) { + VP8ITransform(ref + VP8ScanUV[n], tmp[n], yuv_out + VP8ScanUV[n], 1); + } + return (nz << 16); +} + +//------------------------------------------------------------------------------ +// RD-opt decision. Reconstruct each modes, evalue distortion and bit-cost. +// Pick the mode is lower RD-cost = Rate + lambda * Distortion. + +static void StoreMaxDelta(VP8SegmentInfo* const dqm, const int16_t DCs[16]) { + // We look at the first three AC coefficients to determine what is the average + // delta between each sub-4x4 block. + const int v0 = abs(DCs[1]); + const int v1 = abs(DCs[2]); + const int v2 = abs(DCs[4]); + int max_v = (v1 > v0) ? v1 : v0; + max_v = (v2 > max_v) ? v2 : max_v; + if (max_v > dqm->max_edge_) dqm->max_edge_ = max_v; +} + +static void SwapModeScore(VP8ModeScore** a, VP8ModeScore** b) { + VP8ModeScore* const tmp = *a; + *a = *b; + *b = tmp; +} + +static void SwapPtr(uint8_t** a, uint8_t** b) { + uint8_t* const tmp = *a; + *a = *b; + *b = tmp; +} + +static void SwapOut(VP8EncIterator* const it) { + SwapPtr(&it->yuv_out_, &it->yuv_out2_); +} + +static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT rd) { + const int kNumBlocks = 16; + VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; + const int lambda = dqm->lambda_i16_; + const int tlambda = dqm->tlambda_; + const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; + VP8ModeScore rd_tmp; + VP8ModeScore* rd_cur = &rd_tmp; + VP8ModeScore* rd_best = rd; + int mode; + int is_flat = IsFlatSource16(it->yuv_in_ + Y_OFF_ENC); + + rd->mode_i16 = -1; + for (mode = 0; mode < NUM_PRED_MODES; ++mode) { + uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF_ENC; // scratch buffer + rd_cur->mode_i16 = mode; + + // Reconstruct + rd_cur->nz = ReconstructIntra16(it, rd_cur, tmp_dst, mode); + + // Measure RD-score + rd_cur->D = VP8SSE16x16(src, tmp_dst); + rd_cur->SD = + tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY)) : 0; + rd_cur->H = VP8FixedCostsI16[mode]; + rd_cur->R = VP8GetCostLuma16(it, rd_cur); + if (is_flat) { + // refine the first impression (which was in pixel space) + is_flat = IsFlat(rd_cur->y_ac_levels[0], kNumBlocks, FLATNESS_LIMIT_I16); + if (is_flat) { + // Block is very flat. We put emphasis on the distortion being very low! + rd_cur->D *= 2; + rd_cur->SD *= 2; + } + } + + // Since we always examine Intra16 first, we can overwrite *rd directly. + SetRDScore(lambda, rd_cur); + if (mode == 0 || rd_cur->score < rd_best->score) { + SwapModeScore(&rd_cur, &rd_best); + SwapOut(it); + } + } + if (rd_best != rd) { + memcpy(rd, rd_best, sizeof(*rd)); + } + SetRDScore(dqm->lambda_mode_, rd); // finalize score for mode decision. + VP8SetIntra16Mode(it, rd->mode_i16); + + // we have a blocky macroblock (only DCs are non-zero) with fairly high + // distortion, record max delta so we can later adjust the minimal filtering + // strength needed to smooth these blocks out. + if ((rd->nz & 0x100ffff) == 0x1000000 && rd->D > dqm->min_disto_) { + StoreMaxDelta(dqm, rd->y_dc_levels); + } +} + +//------------------------------------------------------------------------------ + +// return the cost array corresponding to the surrounding prediction modes. +static const uint16_t* GetCostModeI4(VP8EncIterator* WEBP_RESTRICT const it, + const uint8_t modes[16]) { + const int preds_w = it->enc_->preds_w_; + const int x = (it->i4_ & 3), y = it->i4_ >> 2; + const int left = (x == 0) ? it->preds_[y * preds_w - 1] : modes[it->i4_ - 1]; + const int top = (y == 0) ? it->preds_[-preds_w + x] : modes[it->i4_ - 4]; + return VP8FixedCostsI4[top][left]; +} + +static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd) { + const VP8Encoder* const enc = it->enc_; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + const int lambda = dqm->lambda_i4_; + const int tlambda = dqm->tlambda_; + const uint8_t* const src0 = it->yuv_in_ + Y_OFF_ENC; + uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF_ENC; + int total_header_bits = 0; + VP8ModeScore rd_best; + + if (enc->max_i4_header_bits_ == 0) { + return 0; + } + + InitScore(&rd_best); + rd_best.H = 211; // '211' is the value of VP8BitCost(0, 145) + SetRDScore(dqm->lambda_mode_, &rd_best); + VP8IteratorStartI4(it); + do { + const int kNumBlocks = 1; + VP8ModeScore rd_i4; + int mode; + int best_mode = -1; + const uint8_t* const src = src0 + VP8Scan[it->i4_]; + const uint16_t* const mode_costs = GetCostModeI4(it, rd->modes_i4); + uint8_t* best_block = best_blocks + VP8Scan[it->i4_]; + uint8_t* tmp_dst = it->yuv_p_ + I4TMP; // scratch buffer. + + InitScore(&rd_i4); + VP8MakeIntra4Preds(it); + for (mode = 0; mode < NUM_BMODES; ++mode) { + VP8ModeScore rd_tmp; + int16_t tmp_levels[16]; + + // Reconstruct + rd_tmp.nz = + ReconstructIntra4(it, tmp_levels, src, tmp_dst, mode) << it->i4_; + + // Compute RD-score + rd_tmp.D = VP8SSE4x4(src, tmp_dst); + rd_tmp.SD = + tlambda ? MULT_8B(tlambda, VP8TDisto4x4(src, tmp_dst, kWeightY)) + : 0; + rd_tmp.H = mode_costs[mode]; + + // Add flatness penalty, to avoid flat area to be mispredicted + // by a complex mode. + if (mode > 0 && IsFlat(tmp_levels, kNumBlocks, FLATNESS_LIMIT_I4)) { + rd_tmp.R = FLATNESS_PENALTY * kNumBlocks; + } else { + rd_tmp.R = 0; + } + + // early-out check + SetRDScore(lambda, &rd_tmp); + if (best_mode >= 0 && rd_tmp.score >= rd_i4.score) continue; + + // finish computing score + rd_tmp.R += VP8GetCostLuma4(it, tmp_levels); + SetRDScore(lambda, &rd_tmp); + + if (best_mode < 0 || rd_tmp.score < rd_i4.score) { + CopyScore(&rd_i4, &rd_tmp); + best_mode = mode; + SwapPtr(&tmp_dst, &best_block); + memcpy(rd_best.y_ac_levels[it->i4_], tmp_levels, + sizeof(rd_best.y_ac_levels[it->i4_])); + } + } + SetRDScore(dqm->lambda_mode_, &rd_i4); + AddScore(&rd_best, &rd_i4); + if (rd_best.score >= rd->score) { + return 0; + } + total_header_bits += (int)rd_i4.H; // <- equal to mode_costs[best_mode]; + if (total_header_bits > enc->max_i4_header_bits_) { + return 0; + } + // Copy selected samples if not in the right place already. + if (best_block != best_blocks + VP8Scan[it->i4_]) { + VP8Copy4x4(best_block, best_blocks + VP8Scan[it->i4_]); + } + rd->modes_i4[it->i4_] = best_mode; + it->top_nz_[it->i4_ & 3] = it->left_nz_[it->i4_ >> 2] = (rd_i4.nz ? 1 : 0); + } while (VP8IteratorRotateI4(it, best_blocks)); + + // finalize state + CopyScore(rd, &rd_best); + VP8SetIntra4Mode(it, rd->modes_i4); + SwapOut(it); + memcpy(rd->y_ac_levels, rd_best.y_ac_levels, sizeof(rd->y_ac_levels)); + return 1; // select intra4x4 over intra16x16 +} + +//------------------------------------------------------------------------------ + +static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd) { + const int kNumBlocks = 8; + const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; + const int lambda = dqm->lambda_uv_; + const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; + uint8_t* tmp_dst = it->yuv_out2_ + U_OFF_ENC; // scratch buffer + uint8_t* dst0 = it->yuv_out_ + U_OFF_ENC; + uint8_t* dst = dst0; + VP8ModeScore rd_best; + int mode; + + rd->mode_uv = -1; + InitScore(&rd_best); + for (mode = 0; mode < NUM_PRED_MODES; ++mode) { + VP8ModeScore rd_uv; + + // Reconstruct + rd_uv.nz = ReconstructUV(it, &rd_uv, tmp_dst, mode); + + // Compute RD-score + rd_uv.D = VP8SSE16x8(src, tmp_dst); + rd_uv.SD = 0; // not calling TDisto here: it tends to flatten areas. + rd_uv.H = VP8FixedCostsUV[mode]; + rd_uv.R = VP8GetCostUV(it, &rd_uv); + if (mode > 0 && IsFlat(rd_uv.uv_levels[0], kNumBlocks, FLATNESS_LIMIT_UV)) { + rd_uv.R += FLATNESS_PENALTY * kNumBlocks; + } + + SetRDScore(lambda, &rd_uv); + if (mode == 0 || rd_uv.score < rd_best.score) { + CopyScore(&rd_best, &rd_uv); + rd->mode_uv = mode; + memcpy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels)); + if (it->top_derr_ != NULL) { + memcpy(rd->derr, rd_uv.derr, sizeof(rd_uv.derr)); + } + SwapPtr(&dst, &tmp_dst); + } + } + VP8SetIntraUVMode(it, rd->mode_uv); + AddScore(rd, &rd_best); + if (dst != dst0) { // copy 16x8 block if needed + VP8Copy16x8(dst, dst0); + } + if (it->top_derr_ != NULL) { // store diffusion errors for next block + StoreDiffusionErrors(it, rd); + } +} + +//------------------------------------------------------------------------------ +// Final reconstruction and quantization. + +static void SimpleQuantize(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd) { + const VP8Encoder* const enc = it->enc_; + const int is_i16 = (it->mb_->type_ == 1); + int nz = 0; + + if (is_i16) { + nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF_ENC, it->preds_[0]); + } else { + VP8IteratorStartI4(it); + do { + const int mode = + it->preds_[(it->i4_ & 3) + (it->i4_ >> 2) * enc->preds_w_]; + const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_]; + uint8_t* const dst = it->yuv_out_ + Y_OFF_ENC + VP8Scan[it->i4_]; + VP8MakeIntra4Preds(it); + nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_], + src, dst, mode) << it->i4_; + } while (VP8IteratorRotateI4(it, it->yuv_out_ + Y_OFF_ENC)); + } + + nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF_ENC, it->mb_->uv_mode_); + rd->nz = nz; +} + +// Refine intra16/intra4 sub-modes based on distortion only (not rate). +static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it, + int try_both_modes, int refine_uv_mode, + VP8ModeScore* WEBP_RESTRICT const rd) { + score_t best_score = MAX_COST; + int nz = 0; + int mode; + int is_i16 = try_both_modes || (it->mb_->type_ == 1); + + const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; + // Some empiric constants, of approximate order of magnitude. + const int lambda_d_i16 = 106; + const int lambda_d_i4 = 11; + const int lambda_d_uv = 120; + score_t score_i4 = dqm->i4_penalty_; + score_t i4_bit_sum = 0; + const score_t bit_limit = try_both_modes ? it->enc_->mb_header_limit_ + : MAX_COST; // no early-out allowed + + if (is_i16) { // First, evaluate Intra16 distortion + int best_mode = -1; + const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; + for (mode = 0; mode < NUM_PRED_MODES; ++mode) { + const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode]; + const score_t score = (score_t)VP8SSE16x16(src, ref) * RD_DISTO_MULT + + VP8FixedCostsI16[mode] * lambda_d_i16; + if (mode > 0 && VP8FixedCostsI16[mode] > bit_limit) { + continue; + } + + if (score < best_score) { + best_mode = mode; + best_score = score; + } + } + if (it->x_ == 0 || it->y_ == 0) { + // avoid starting a checkerboard resonance from the border. See bug #432. + if (IsFlatSource16(src)) { + best_mode = (it->x_ == 0) ? 0 : 2; + try_both_modes = 0; // stick to i16 + } + } + VP8SetIntra16Mode(it, best_mode); + // we'll reconstruct later, if i16 mode actually gets selected + } + + // Next, evaluate Intra4 + if (try_both_modes || !is_i16) { + // We don't evaluate the rate here, but just account for it through a + // constant penalty (i4 mode usually needs more bits compared to i16). + is_i16 = 0; + VP8IteratorStartI4(it); + do { + int best_i4_mode = -1; + score_t best_i4_score = MAX_COST; + const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_]; + const uint16_t* const mode_costs = GetCostModeI4(it, rd->modes_i4); + + VP8MakeIntra4Preds(it); + for (mode = 0; mode < NUM_BMODES; ++mode) { + const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode]; + const score_t score = VP8SSE4x4(src, ref) * RD_DISTO_MULT + + mode_costs[mode] * lambda_d_i4; + if (score < best_i4_score) { + best_i4_mode = mode; + best_i4_score = score; + } + } + i4_bit_sum += mode_costs[best_i4_mode]; + rd->modes_i4[it->i4_] = best_i4_mode; + score_i4 += best_i4_score; + if (score_i4 >= best_score || i4_bit_sum > bit_limit) { + // Intra4 won't be better than Intra16. Bail out and pick Intra16. + is_i16 = 1; + break; + } else { // reconstruct partial block inside yuv_out2_ buffer + uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF_ENC + VP8Scan[it->i4_]; + nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_], + src, tmp_dst, best_i4_mode) << it->i4_; + } + } while (VP8IteratorRotateI4(it, it->yuv_out2_ + Y_OFF_ENC)); + } + + // Final reconstruction, depending on which mode is selected. + if (!is_i16) { + VP8SetIntra4Mode(it, rd->modes_i4); + SwapOut(it); + best_score = score_i4; + } else { + nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF_ENC, it->preds_[0]); + } + + // ... and UV! + if (refine_uv_mode) { + int best_mode = -1; + score_t best_uv_score = MAX_COST; + const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; + for (mode = 0; mode < NUM_PRED_MODES; ++mode) { + const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode]; + const score_t score = VP8SSE16x8(src, ref) * RD_DISTO_MULT + + VP8FixedCostsUV[mode] * lambda_d_uv; + if (score < best_uv_score) { + best_mode = mode; + best_uv_score = score; + } + } + VP8SetIntraUVMode(it, best_mode); + } + nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF_ENC, it->mb_->uv_mode_); + + rd->nz = nz; + rd->score = best_score; +} + +//------------------------------------------------------------------------------ +// Entry point + +int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd, + VP8RDLevel rd_opt) { + int is_skipped; + const int method = it->enc_->method_; + + InitScore(rd); + + // We can perform predictions for Luma16x16 and Chroma8x8 already. + // Luma4x4 predictions needs to be done as-we-go. + VP8MakeLuma16Preds(it); + VP8MakeChroma8Preds(it); + + if (rd_opt > RD_OPT_NONE) { + it->do_trellis_ = (rd_opt >= RD_OPT_TRELLIS_ALL); + PickBestIntra16(it, rd); + if (method >= 2) { + PickBestIntra4(it, rd); + } + PickBestUV(it, rd); + if (rd_opt == RD_OPT_TRELLIS) { // finish off with trellis-optim now + it->do_trellis_ = 1; + SimpleQuantize(it, rd); + } + } else { + // At this point we have heuristically decided intra16 / intra4. + // For method >= 2, pick the best intra4/intra16 based on SSE (~tad slower). + // For method <= 1, we don't re-examine the decision but just go ahead with + // quantization/reconstruction. + RefineUsingDistortion(it, (method >= 2), (method >= 1), rd); + } + is_skipped = (rd->nz == 0); + VP8SetSkip(it, is_skipped); + return is_skipped; +} diff --git a/libraries/webp/src/enc/syntax_enc.c b/libraries/webp/src/enc/syntax_enc.c new file mode 100644 index 00000000000..0149c85b649 --- /dev/null +++ b/libraries/webp/src/enc/syntax_enc.c @@ -0,0 +1,392 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Header syntax writing +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/utils/utils.h" +#include "include/webp/format_constants.h" // RIFF constants +#include "include/webp/mux_types.h" // ALPHA_FLAG +#include "src/enc/vp8i_enc.h" + +//------------------------------------------------------------------------------ +// Helper functions + +static int IsVP8XNeeded(const VP8Encoder* const enc) { + return !!enc->has_alpha_; // Currently the only case when VP8X is needed. + // This could change in the future. +} + +static int PutPaddingByte(const WebPPicture* const pic) { + const uint8_t pad_byte[1] = { 0 }; + return !!pic->writer(pad_byte, 1, pic); +} + +//------------------------------------------------------------------------------ +// Writers for header's various pieces (in order of appearance) + +static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc, + size_t riff_size) { + const WebPPicture* const pic = enc->pic_; + uint8_t riff[RIFF_HEADER_SIZE] = { + 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P' + }; + assert(riff_size == (uint32_t)riff_size); + PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); + if (!pic->writer(riff, sizeof(riff), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) { + const WebPPicture* const pic = enc->pic_; + uint8_t vp8x[CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE] = { + 'V', 'P', '8', 'X' + }; + uint32_t flags = 0; + + assert(IsVP8XNeeded(enc)); + assert(pic->width >= 1 && pic->height >= 1); + assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE); + + if (enc->has_alpha_) { + flags |= ALPHA_FLAG; + } + + PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE); + PutLE32(vp8x + CHUNK_HEADER_SIZE, flags); + PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1); + PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1); + if (!pic->writer(vp8x, sizeof(vp8x), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static WebPEncodingError PutAlphaChunk(const VP8Encoder* const enc) { + const WebPPicture* const pic = enc->pic_; + uint8_t alpha_chunk_hdr[CHUNK_HEADER_SIZE] = { + 'A', 'L', 'P', 'H' + }; + + assert(enc->has_alpha_); + + // Alpha chunk header. + PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size_); + if (!pic->writer(alpha_chunk_hdr, sizeof(alpha_chunk_hdr), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + + // Alpha chunk data. + if (!pic->writer(enc->alpha_data_, enc->alpha_data_size_, pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + + // Padding. + if ((enc->alpha_data_size_ & 1) && !PutPaddingByte(pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static WebPEncodingError PutVP8Header(const WebPPicture* const pic, + size_t vp8_size) { + uint8_t vp8_chunk_hdr[CHUNK_HEADER_SIZE] = { + 'V', 'P', '8', ' ' + }; + assert(vp8_size == (uint32_t)vp8_size); + PutLE32(vp8_chunk_hdr + TAG_SIZE, (uint32_t)vp8_size); + if (!pic->writer(vp8_chunk_hdr, sizeof(vp8_chunk_hdr), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static WebPEncodingError PutVP8FrameHeader(const WebPPicture* const pic, + int profile, size_t size0) { + uint8_t vp8_frm_hdr[VP8_FRAME_HEADER_SIZE]; + uint32_t bits; + + if (size0 >= VP8_MAX_PARTITION0_SIZE) { // partition #0 is too big to fit + return VP8_ENC_ERROR_PARTITION0_OVERFLOW; + } + + // Paragraph 9.1. + bits = 0 // keyframe (1b) + | (profile << 1) // profile (3b) + | (1 << 4) // visible (1b) + | ((uint32_t)size0 << 5); // partition length (19b) + vp8_frm_hdr[0] = (bits >> 0) & 0xff; + vp8_frm_hdr[1] = (bits >> 8) & 0xff; + vp8_frm_hdr[2] = (bits >> 16) & 0xff; + // signature + vp8_frm_hdr[3] = (VP8_SIGNATURE >> 16) & 0xff; + vp8_frm_hdr[4] = (VP8_SIGNATURE >> 8) & 0xff; + vp8_frm_hdr[5] = (VP8_SIGNATURE >> 0) & 0xff; + // dimensions + vp8_frm_hdr[6] = pic->width & 0xff; + vp8_frm_hdr[7] = pic->width >> 8; + vp8_frm_hdr[8] = pic->height & 0xff; + vp8_frm_hdr[9] = pic->height >> 8; + + if (!pic->writer(vp8_frm_hdr, sizeof(vp8_frm_hdr), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +// WebP Headers. +static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0, + size_t vp8_size, size_t riff_size) { + WebPPicture* const pic = enc->pic_; + WebPEncodingError err = VP8_ENC_OK; + + // RIFF header. + err = PutRIFFHeader(enc, riff_size); + if (err != VP8_ENC_OK) goto Error; + + // VP8X. + if (IsVP8XNeeded(enc)) { + err = PutVP8XHeader(enc); + if (err != VP8_ENC_OK) goto Error; + } + + // Alpha. + if (enc->has_alpha_) { + err = PutAlphaChunk(enc); + if (err != VP8_ENC_OK) goto Error; + } + + // VP8 header. + err = PutVP8Header(pic, vp8_size); + if (err != VP8_ENC_OK) goto Error; + + // VP8 frame header. + err = PutVP8FrameHeader(pic, enc->profile_, size0); + if (err != VP8_ENC_OK) goto Error; + + // All OK. + return 1; + + // Error. + Error: + return WebPEncodingSetError(pic, err); +} + +// Segmentation header +static void PutSegmentHeader(VP8BitWriter* const bw, + const VP8Encoder* const enc) { + const VP8EncSegmentHeader* const hdr = &enc->segment_hdr_; + const VP8EncProba* const proba = &enc->proba_; + if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) { + // We always 'update' the quant and filter strength values + const int update_data = 1; + int s; + VP8PutBitUniform(bw, hdr->update_map_); + if (VP8PutBitUniform(bw, update_data)) { + // we always use absolute values, not relative ones + VP8PutBitUniform(bw, 1); // (segment_feature_mode = 1. Paragraph 9.3.) + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + VP8PutSignedBits(bw, enc->dqm_[s].quant_, 7); + } + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + VP8PutSignedBits(bw, enc->dqm_[s].fstrength_, 6); + } + } + if (hdr->update_map_) { + for (s = 0; s < 3; ++s) { + if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) { + VP8PutBits(bw, proba->segments_[s], 8); + } + } + } + } +} + +// Filtering parameters header +static void PutFilterHeader(VP8BitWriter* const bw, + const VP8EncFilterHeader* const hdr) { + const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0); + VP8PutBitUniform(bw, hdr->simple_); + VP8PutBits(bw, hdr->level_, 6); + VP8PutBits(bw, hdr->sharpness_, 3); + if (VP8PutBitUniform(bw, use_lf_delta)) { + // '0' is the default value for i4x4_lf_delta_ at frame #0. + const int need_update = (hdr->i4x4_lf_delta_ != 0); + if (VP8PutBitUniform(bw, need_update)) { + // we don't use ref_lf_delta => emit four 0 bits + VP8PutBits(bw, 0, 4); + // we use mode_lf_delta for i4x4 + VP8PutSignedBits(bw, hdr->i4x4_lf_delta_, 6); + VP8PutBits(bw, 0, 3); // all others unused + } + } +} + +// Nominal quantization parameters +static void PutQuant(VP8BitWriter* const bw, + const VP8Encoder* const enc) { + VP8PutBits(bw, enc->base_quant_, 7); + VP8PutSignedBits(bw, enc->dq_y1_dc_, 4); + VP8PutSignedBits(bw, enc->dq_y2_dc_, 4); + VP8PutSignedBits(bw, enc->dq_y2_ac_, 4); + VP8PutSignedBits(bw, enc->dq_uv_dc_, 4); + VP8PutSignedBits(bw, enc->dq_uv_ac_, 4); +} + +// Partition sizes +static int EmitPartitionsSize(const VP8Encoder* const enc, + WebPPicture* const pic) { + uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)]; + int p; + for (p = 0; p < enc->num_parts_ - 1; ++p) { + const size_t part_size = VP8BitWriterSize(enc->parts_ + p); + if (part_size >= VP8_MAX_PARTITION_SIZE) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW); + } + buf[3 * p + 0] = (part_size >> 0) & 0xff; + buf[3 * p + 1] = (part_size >> 8) & 0xff; + buf[3 * p + 2] = (part_size >> 16) & 0xff; + } + if (p && !pic->writer(buf, 3 * p, pic)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); + } + return 1; +} + +//------------------------------------------------------------------------------ + +static int GeneratePartition0(VP8Encoder* const enc) { + VP8BitWriter* const bw = &enc->bw_; + const int mb_size = enc->mb_w_ * enc->mb_h_; + uint64_t pos1, pos2, pos3; + + pos1 = VP8BitWriterPos(bw); + if (!VP8BitWriterInit(bw, mb_size * 7 / 8)) { // ~7 bits per macroblock + return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + VP8PutBitUniform(bw, 0); // colorspace + VP8PutBitUniform(bw, 0); // clamp type + + PutSegmentHeader(bw, enc); + PutFilterHeader(bw, &enc->filter_hdr_); + VP8PutBits(bw, enc->num_parts_ == 8 ? 3 : + enc->num_parts_ == 4 ? 2 : + enc->num_parts_ == 2 ? 1 : 0, 2); + PutQuant(bw, enc); + VP8PutBitUniform(bw, 0); // no proba update + VP8WriteProbas(bw, &enc->proba_); + pos2 = VP8BitWriterPos(bw); + VP8CodeIntraModes(enc); + VP8BitWriterFinish(bw); + + pos3 = VP8BitWriterPos(bw); + +#if !defined(WEBP_DISABLE_STATS) + if (enc->pic_->stats) { + enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3); + enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3); + enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_; + } +#else + (void)pos1; + (void)pos2; + (void)pos3; +#endif + if (bw->error_) { + return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + return 1; +} + +void VP8EncFreeBitWriters(VP8Encoder* const enc) { + int p; + VP8BitWriterWipeOut(&enc->bw_); + for (p = 0; p < enc->num_parts_; ++p) { + VP8BitWriterWipeOut(enc->parts_ + p); + } +} + +int VP8EncWrite(VP8Encoder* const enc) { + WebPPicture* const pic = enc->pic_; + VP8BitWriter* const bw = &enc->bw_; + const int task_percent = 19; + const int percent_per_part = task_percent / enc->num_parts_; + const int final_percent = enc->percent_ + task_percent; + int ok = 0; + size_t vp8_size, pad, riff_size; + int p; + + // Partition #0 with header and partition sizes + ok = GeneratePartition0(enc); + if (!ok) return 0; + + // Compute VP8 size + vp8_size = VP8_FRAME_HEADER_SIZE + + VP8BitWriterSize(bw) + + 3 * (enc->num_parts_ - 1); + for (p = 0; p < enc->num_parts_; ++p) { + vp8_size += VP8BitWriterSize(enc->parts_ + p); + } + pad = vp8_size & 1; + vp8_size += pad; + + // Compute RIFF size + // At the minimum it is: "WEBPVP8 nnnn" + VP8 data size. + riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8_size; + if (IsVP8XNeeded(enc)) { // Add size for: VP8X header + data. + riff_size += CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; + } + if (enc->has_alpha_) { // Add size for: ALPH header + data. + const uint32_t padded_alpha_size = enc->alpha_data_size_ + + (enc->alpha_data_size_ & 1); + riff_size += CHUNK_HEADER_SIZE + padded_alpha_size; + } + // RIFF size should fit in 32-bits. + if (riff_size > 0xfffffffeU) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG); + } + + // Emit headers and partition #0 + { + const uint8_t* const part0 = VP8BitWriterBuf(bw); + const size_t size0 = VP8BitWriterSize(bw); + ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size) + && pic->writer(part0, size0, pic) + && EmitPartitionsSize(enc, pic); + VP8BitWriterWipeOut(bw); // will free the internal buffer. + } + + // Token partitions + for (p = 0; p < enc->num_parts_; ++p) { + const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p); + const size_t size = VP8BitWriterSize(enc->parts_ + p); + if (size) ok = ok && pic->writer(buf, size, pic); + VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer. + ok = ok && WebPReportProgress(pic, enc->percent_ + percent_per_part, + &enc->percent_); + } + + // Padding byte + if (ok && pad) { + ok = PutPaddingByte(pic); + } + + enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size); + ok = ok && WebPReportProgress(pic, final_percent, &enc->percent_); + if (!ok) WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); + return ok; +} + +//------------------------------------------------------------------------------ + diff --git a/libraries/webp/src/enc/token_enc.c b/libraries/webp/src/enc/token_enc.c new file mode 100644 index 00000000000..3a2192acac2 --- /dev/null +++ b/libraries/webp/src/enc/token_enc.c @@ -0,0 +1,262 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Paginated token buffer +// +// A 'token' is a bit value associated with a probability, either fixed +// or a later-to-be-determined after statistics have been collected. +// For dynamic probability, we just record the slot id (idx) for the probability +// value in the final probability array (uint8_t* probas in VP8EmitTokens). +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include + +#include "src/enc/cost_enc.h" +#include "src/enc/vp8i_enc.h" +#include "src/utils/utils.h" + +#if !defined(DISABLE_TOKEN_BUFFER) + +// we use pages to reduce the number of memcpy() +#define MIN_PAGE_SIZE 8192 // minimum number of token per page +#define FIXED_PROBA_BIT (1u << 14) + +typedef uint16_t token_t; // bit #15: bit value + // bit #14: flags for constant proba or idx + // bits #0..13: slot or constant proba +struct VP8Tokens { + VP8Tokens* next_; // pointer to next page +}; +// Token data is located in memory just after the next_ field. +// This macro is used to return their address and hide the trick. +#define TOKEN_DATA(p) ((const token_t*)&(p)[1]) + +//------------------------------------------------------------------------------ + +void VP8TBufferInit(VP8TBuffer* const b, int page_size) { + b->tokens_ = NULL; + b->pages_ = NULL; + b->last_page_ = &b->pages_; + b->left_ = 0; + b->page_size_ = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size; + b->error_ = 0; +} + +void VP8TBufferClear(VP8TBuffer* const b) { + if (b != NULL) { + VP8Tokens* p = b->pages_; + while (p != NULL) { + VP8Tokens* const next = p->next_; + WebPSafeFree(p); + p = next; + } + VP8TBufferInit(b, b->page_size_); + } +} + +static int TBufferNewPage(VP8TBuffer* const b) { + VP8Tokens* page = NULL; + if (!b->error_) { + const size_t size = sizeof(*page) + b->page_size_ * sizeof(token_t); + page = (VP8Tokens*)WebPSafeMalloc(1ULL, size); + } + if (page == NULL) { + b->error_ = 1; + return 0; + } + page->next_ = NULL; + + *b->last_page_ = page; + b->last_page_ = &page->next_; + b->left_ = b->page_size_; + b->tokens_ = (token_t*)TOKEN_DATA(page); + return 1; +} + +//------------------------------------------------------------------------------ + +#define TOKEN_ID(t, b, ctx) \ + (NUM_PROBAS * ((ctx) + NUM_CTX * ((b) + NUM_BANDS * (t)))) + +static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, uint32_t bit, + uint32_t proba_idx, + proba_t* const stats) { + assert(proba_idx < FIXED_PROBA_BIT); + assert(bit <= 1); + if (b->left_ > 0 || TBufferNewPage(b)) { + const int slot = --b->left_; + b->tokens_[slot] = (bit << 15) | proba_idx; + } + VP8RecordStats(bit, stats); + return bit; +} + +static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b, + uint32_t bit, uint32_t proba) { + assert(proba < 256); + assert(bit <= 1); + if (b->left_ > 0 || TBufferNewPage(b)) { + const int slot = --b->left_; + b->tokens_[slot] = (bit << 15) | FIXED_PROBA_BIT | proba; + } +} + +int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res, + VP8TBuffer* const tokens) { + const int16_t* const coeffs = res->coeffs; + const int coeff_type = res->coeff_type; + const int last = res->last; + int n = res->first; + uint32_t base_id = TOKEN_ID(coeff_type, n, ctx); + // should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1 + proba_t* s = res->stats[n][ctx]; + if (!AddToken(tokens, last >= 0, base_id + 0, s + 0)) { + return 0; + } + + while (n < 16) { + const int c = coeffs[n++]; + const int sign = c < 0; + const uint32_t v = sign ? -c : c; + if (!AddToken(tokens, v != 0, base_id + 1, s + 1)) { + base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 0); // ctx=0 + s = res->stats[VP8EncBands[n]][0]; + continue; + } + if (!AddToken(tokens, v > 1, base_id + 2, s + 2)) { + base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 1); // ctx=1 + s = res->stats[VP8EncBands[n]][1]; + } else { + if (!AddToken(tokens, v > 4, base_id + 3, s + 3)) { + if (AddToken(tokens, v != 2, base_id + 4, s + 4)) { + AddToken(tokens, v == 4, base_id + 5, s + 5); + } + } else if (!AddToken(tokens, v > 10, base_id + 6, s + 6)) { + if (!AddToken(tokens, v > 6, base_id + 7, s + 7)) { + AddConstantToken(tokens, v == 6, 159); + } else { + AddConstantToken(tokens, v >= 9, 165); + AddConstantToken(tokens, !(v & 1), 145); + } + } else { + int mask; + const uint8_t* tab; + uint32_t residue = v - 3; + if (residue < (8 << 1)) { // VP8Cat3 (3b) + AddToken(tokens, 0, base_id + 8, s + 8); + AddToken(tokens, 0, base_id + 9, s + 9); + residue -= (8 << 0); + mask = 1 << 2; + tab = VP8Cat3; + } else if (residue < (8 << 2)) { // VP8Cat4 (4b) + AddToken(tokens, 0, base_id + 8, s + 8); + AddToken(tokens, 1, base_id + 9, s + 9); + residue -= (8 << 1); + mask = 1 << 3; + tab = VP8Cat4; + } else if (residue < (8 << 3)) { // VP8Cat5 (5b) + AddToken(tokens, 1, base_id + 8, s + 8); + AddToken(tokens, 0, base_id + 10, s + 9); + residue -= (8 << 2); + mask = 1 << 4; + tab = VP8Cat5; + } else { // VP8Cat6 (11b) + AddToken(tokens, 1, base_id + 8, s + 8); + AddToken(tokens, 1, base_id + 10, s + 9); + residue -= (8 << 3); + mask = 1 << 10; + tab = VP8Cat6; + } + while (mask) { + AddConstantToken(tokens, !!(residue & mask), *tab++); + mask >>= 1; + } + } + base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 2); // ctx=2 + s = res->stats[VP8EncBands[n]][2]; + } + AddConstantToken(tokens, sign, 128); + if (n == 16 || !AddToken(tokens, n <= last, base_id + 0, s + 0)) { + return 1; // EOB + } + } + return 1; +} + +#undef TOKEN_ID + +//------------------------------------------------------------------------------ +// Final coding pass, with known probabilities + +int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw, + const uint8_t* const probas, int final_pass) { + const VP8Tokens* p = b->pages_; + assert(!b->error_); + while (p != NULL) { + const VP8Tokens* const next = p->next_; + const int N = (next == NULL) ? b->left_ : 0; + int n = b->page_size_; + const token_t* const tokens = TOKEN_DATA(p); + while (n-- > N) { + const token_t token = tokens[n]; + const int bit = (token >> 15) & 1; + if (token & FIXED_PROBA_BIT) { + VP8PutBit(bw, bit, token & 0xffu); // constant proba + } else { + VP8PutBit(bw, bit, probas[token & 0x3fffu]); + } + } + if (final_pass) WebPSafeFree((void*)p); + p = next; + } + if (final_pass) b->pages_ = NULL; + return 1; +} + +// Size estimation +size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) { + size_t size = 0; + const VP8Tokens* p = b->pages_; + assert(!b->error_); + while (p != NULL) { + const VP8Tokens* const next = p->next_; + const int N = (next == NULL) ? b->left_ : 0; + int n = b->page_size_; + const token_t* const tokens = TOKEN_DATA(p); + while (n-- > N) { + const token_t token = tokens[n]; + const int bit = token & (1 << 15); + if (token & FIXED_PROBA_BIT) { + size += VP8BitCost(bit, token & 0xffu); + } else { + size += VP8BitCost(bit, probas[token & 0x3fffu]); + } + } + p = next; + } + return size; +} + +//------------------------------------------------------------------------------ + +#else // DISABLE_TOKEN_BUFFER + +void VP8TBufferInit(VP8TBuffer* const b, int page_size) { + (void)b; + (void)page_size; +} +void VP8TBufferClear(VP8TBuffer* const b) { + (void)b; +} + +#endif // !DISABLE_TOKEN_BUFFER + diff --git a/libraries/webp/src/enc/tree_enc.c b/libraries/webp/src/enc/tree_enc.c new file mode 100644 index 00000000000..64ed28360b2 --- /dev/null +++ b/libraries/webp/src/enc/tree_enc.c @@ -0,0 +1,504 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Coding of token probabilities, intra modes and segments. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/enc/vp8i_enc.h" + +//------------------------------------------------------------------------------ +// Default probabilities + +// Paragraph 13.5 +const uint8_t + VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { + { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 }, + { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 }, + { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 } + }, + { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 }, + { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 }, + { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 }, + }, + { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 }, + { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 }, + { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 }, + }, + { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 }, + { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 }, + { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 } + }, + { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 }, + { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 }, + { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 } + }, + { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 }, + { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 }, + { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 } + }, + { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 }, + { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 }, + { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 } + }, + { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 }, + { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 }, + { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 } + }, + { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 }, + { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 }, + { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 } + }, + { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 }, + { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 }, + { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 } + }, + { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 }, + { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 }, + { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 } + }, + { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 }, + { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 }, + { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 } + }, + { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 }, + { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 }, + { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 } + }, + { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 } + } + }, + { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 }, + { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 }, + { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 } + }, + { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 }, + { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 }, + { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 } + }, + { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 }, + { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 }, + { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 } + }, + { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 }, + { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 }, + { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 }, + { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 } + }, + { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 }, + { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 }, + { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 } + }, + { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 }, + { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 }, + { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 } + }, + { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 }, + { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 }, + { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 } + }, + { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 }, + { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 }, + { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 } + }, + { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 }, + { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 }, + { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 } + }, + { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 }, + { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 }, + { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 } + }, + { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + } + } +}; + +void VP8DefaultProbas(VP8Encoder* const enc) { + VP8EncProba* const probas = &enc->proba_; + probas->use_skip_proba_ = 0; + memset(probas->segments_, 255u, sizeof(probas->segments_)); + memcpy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0)); + // Note: we could hard-code the level_costs_ corresponding to VP8CoeffsProba0, + // but that's ~11k of static data. Better call VP8CalculateLevelCosts() later. + probas->dirty_ = 1; +} + +// Paragraph 11.5. 900bytes. +static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = { + { { 231, 120, 48, 89, 115, 113, 120, 152, 112 }, + { 152, 179, 64, 126, 170, 118, 46, 70, 95 }, + { 175, 69, 143, 80, 85, 82, 72, 155, 103 }, + { 56, 58, 10, 171, 218, 189, 17, 13, 152 }, + { 114, 26, 17, 163, 44, 195, 21, 10, 173 }, + { 121, 24, 80, 195, 26, 62, 44, 64, 85 }, + { 144, 71, 10, 38, 171, 213, 144, 34, 26 }, + { 170, 46, 55, 19, 136, 160, 33, 206, 71 }, + { 63, 20, 8, 114, 114, 208, 12, 9, 226 }, + { 81, 40, 11, 96, 182, 84, 29, 16, 36 } }, + { { 134, 183, 89, 137, 98, 101, 106, 165, 148 }, + { 72, 187, 100, 130, 157, 111, 32, 75, 80 }, + { 66, 102, 167, 99, 74, 62, 40, 234, 128 }, + { 41, 53, 9, 178, 241, 141, 26, 8, 107 }, + { 74, 43, 26, 146, 73, 166, 49, 23, 157 }, + { 65, 38, 105, 160, 51, 52, 31, 115, 128 }, + { 104, 79, 12, 27, 217, 255, 87, 17, 7 }, + { 87, 68, 71, 44, 114, 51, 15, 186, 23 }, + { 47, 41, 14, 110, 182, 183, 21, 17, 194 }, + { 66, 45, 25, 102, 197, 189, 23, 18, 22 } }, + { { 88, 88, 147, 150, 42, 46, 45, 196, 205 }, + { 43, 97, 183, 117, 85, 38, 35, 179, 61 }, + { 39, 53, 200, 87, 26, 21, 43, 232, 171 }, + { 56, 34, 51, 104, 114, 102, 29, 93, 77 }, + { 39, 28, 85, 171, 58, 165, 90, 98, 64 }, + { 34, 22, 116, 206, 23, 34, 43, 166, 73 }, + { 107, 54, 32, 26, 51, 1, 81, 43, 31 }, + { 68, 25, 106, 22, 64, 171, 36, 225, 114 }, + { 34, 19, 21, 102, 132, 188, 16, 76, 124 }, + { 62, 18, 78, 95, 85, 57, 50, 48, 51 } }, + { { 193, 101, 35, 159, 215, 111, 89, 46, 111 }, + { 60, 148, 31, 172, 219, 228, 21, 18, 111 }, + { 112, 113, 77, 85, 179, 255, 38, 120, 114 }, + { 40, 42, 1, 196, 245, 209, 10, 25, 109 }, + { 88, 43, 29, 140, 166, 213, 37, 43, 154 }, + { 61, 63, 30, 155, 67, 45, 68, 1, 209 }, + { 100, 80, 8, 43, 154, 1, 51, 26, 71 }, + { 142, 78, 78, 16, 255, 128, 34, 197, 171 }, + { 41, 40, 5, 102, 211, 183, 4, 1, 221 }, + { 51, 50, 17, 168, 209, 192, 23, 25, 82 } }, + { { 138, 31, 36, 171, 27, 166, 38, 44, 229 }, + { 67, 87, 58, 169, 82, 115, 26, 59, 179 }, + { 63, 59, 90, 180, 59, 166, 93, 73, 154 }, + { 40, 40, 21, 116, 143, 209, 34, 39, 175 }, + { 47, 15, 16, 183, 34, 223, 49, 45, 183 }, + { 46, 17, 33, 183, 6, 98, 15, 32, 183 }, + { 57, 46, 22, 24, 128, 1, 54, 17, 37 }, + { 65, 32, 73, 115, 28, 128, 23, 128, 205 }, + { 40, 3, 9, 115, 51, 192, 18, 6, 223 }, + { 87, 37, 9, 115, 59, 77, 64, 21, 47 } }, + { { 104, 55, 44, 218, 9, 54, 53, 130, 226 }, + { 64, 90, 70, 205, 40, 41, 23, 26, 57 }, + { 54, 57, 112, 184, 5, 41, 38, 166, 213 }, + { 30, 34, 26, 133, 152, 116, 10, 32, 134 }, + { 39, 19, 53, 221, 26, 114, 32, 73, 255 }, + { 31, 9, 65, 234, 2, 15, 1, 118, 73 }, + { 75, 32, 12, 51, 192, 255, 160, 43, 51 }, + { 88, 31, 35, 67, 102, 85, 55, 186, 85 }, + { 56, 21, 23, 111, 59, 205, 45, 37, 192 }, + { 55, 38, 70, 124, 73, 102, 1, 34, 98 } }, + { { 125, 98, 42, 88, 104, 85, 117, 175, 82 }, + { 95, 84, 53, 89, 128, 100, 113, 101, 45 }, + { 75, 79, 123, 47, 51, 128, 81, 171, 1 }, + { 57, 17, 5, 71, 102, 57, 53, 41, 49 }, + { 38, 33, 13, 121, 57, 73, 26, 1, 85 }, + { 41, 10, 67, 138, 77, 110, 90, 47, 114 }, + { 115, 21, 2, 10, 102, 255, 166, 23, 6 }, + { 101, 29, 16, 10, 85, 128, 101, 196, 26 }, + { 57, 18, 10, 102, 102, 213, 34, 20, 43 }, + { 117, 20, 15, 36, 163, 128, 68, 1, 26 } }, + { { 102, 61, 71, 37, 34, 53, 31, 243, 192 }, + { 69, 60, 71, 38, 73, 119, 28, 222, 37 }, + { 68, 45, 128, 34, 1, 47, 11, 245, 171 }, + { 62, 17, 19, 70, 146, 85, 55, 62, 70 }, + { 37, 43, 37, 154, 100, 163, 85, 160, 1 }, + { 63, 9, 92, 136, 28, 64, 32, 201, 85 }, + { 75, 15, 9, 9, 64, 255, 184, 119, 16 }, + { 86, 6, 28, 5, 64, 255, 25, 248, 1 }, + { 56, 8, 17, 132, 137, 255, 55, 116, 128 }, + { 58, 15, 20, 82, 135, 57, 26, 121, 40 } }, + { { 164, 50, 31, 137, 154, 133, 25, 35, 218 }, + { 51, 103, 44, 131, 131, 123, 31, 6, 158 }, + { 86, 40, 64, 135, 148, 224, 45, 183, 128 }, + { 22, 26, 17, 131, 240, 154, 14, 1, 209 }, + { 45, 16, 21, 91, 64, 222, 7, 1, 197 }, + { 56, 21, 39, 155, 60, 138, 23, 102, 213 }, + { 83, 12, 13, 54, 192, 255, 68, 47, 28 }, + { 85, 26, 85, 85, 128, 128, 32, 146, 171 }, + { 18, 11, 7, 63, 144, 171, 4, 4, 246 }, + { 35, 27, 10, 146, 174, 171, 12, 26, 128 } }, + { { 190, 80, 35, 99, 180, 80, 126, 54, 45 }, + { 85, 126, 47, 87, 176, 51, 41, 20, 32 }, + { 101, 75, 128, 139, 118, 146, 116, 128, 85 }, + { 56, 41, 15, 176, 236, 85, 37, 9, 62 }, + { 71, 30, 17, 119, 118, 255, 17, 18, 138 }, + { 101, 38, 60, 138, 55, 70, 43, 26, 142 }, + { 146, 36, 19, 30, 171, 255, 97, 27, 20 }, + { 138, 45, 61, 62, 219, 1, 81, 188, 64 }, + { 32, 41, 20, 117, 151, 142, 20, 21, 163 }, + { 112, 19, 12, 61, 195, 128, 48, 4, 24 } } +}; + +static int PutI4Mode(VP8BitWriter* const bw, int mode, + const uint8_t* const prob) { + if (VP8PutBit(bw, mode != B_DC_PRED, prob[0])) { + if (VP8PutBit(bw, mode != B_TM_PRED, prob[1])) { + if (VP8PutBit(bw, mode != B_VE_PRED, prob[2])) { + if (!VP8PutBit(bw, mode >= B_LD_PRED, prob[3])) { + if (VP8PutBit(bw, mode != B_HE_PRED, prob[4])) { + VP8PutBit(bw, mode != B_RD_PRED, prob[5]); + } + } else { + if (VP8PutBit(bw, mode != B_LD_PRED, prob[6])) { + if (VP8PutBit(bw, mode != B_VL_PRED, prob[7])) { + VP8PutBit(bw, mode != B_HD_PRED, prob[8]); + } + } + } + } + } + } + return mode; +} + +static void PutI16Mode(VP8BitWriter* const bw, int mode) { + if (VP8PutBit(bw, (mode == TM_PRED || mode == H_PRED), 156)) { + VP8PutBit(bw, mode == TM_PRED, 128); // TM or HE + } else { + VP8PutBit(bw, mode == V_PRED, 163); // VE or DC + } +} + +static void PutUVMode(VP8BitWriter* const bw, int uv_mode) { + if (VP8PutBit(bw, uv_mode != DC_PRED, 142)) { + if (VP8PutBit(bw, uv_mode != V_PRED, 114)) { + VP8PutBit(bw, uv_mode != H_PRED, 183); // else: TM_PRED + } + } +} + +static void PutSegment(VP8BitWriter* const bw, int s, const uint8_t* p) { + if (VP8PutBit(bw, s >= 2, p[0])) p += 1; + VP8PutBit(bw, s & 1, p[1]); +} + +void VP8CodeIntraModes(VP8Encoder* const enc) { + VP8BitWriter* const bw = &enc->bw_; + VP8EncIterator it; + VP8IteratorInit(enc, &it); + do { + const VP8MBInfo* const mb = it.mb_; + const uint8_t* preds = it.preds_; + if (enc->segment_hdr_.update_map_) { + PutSegment(bw, mb->segment_, enc->proba_.segments_); + } + if (enc->proba_.use_skip_proba_) { + VP8PutBit(bw, mb->skip_, enc->proba_.skip_proba_); + } + if (VP8PutBit(bw, (mb->type_ != 0), 145)) { // i16x16 + PutI16Mode(bw, preds[0]); + } else { + const int preds_w = enc->preds_w_; + const uint8_t* top_pred = preds - preds_w; + int x, y; + for (y = 0; y < 4; ++y) { + int left = preds[-1]; + for (x = 0; x < 4; ++x) { + const uint8_t* const probas = kBModesProba[top_pred[x]][left]; + left = PutI4Mode(bw, preds[x], probas); + } + top_pred = preds; + preds += preds_w; + } + } + PutUVMode(bw, mb->uv_mode_); + } while (VP8IteratorNext(&it)); +} + +//------------------------------------------------------------------------------ +// Paragraph 13 + +const uint8_t + VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { + { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 }, + { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 } + }, + { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 }, + { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + } +}; + +void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas) { + int t, b, c, p; + for (t = 0; t < NUM_TYPES; ++t) { + for (b = 0; b < NUM_BANDS; ++b) { + for (c = 0; c < NUM_CTX; ++c) { + for (p = 0; p < NUM_PROBAS; ++p) { + const uint8_t p0 = probas->coeffs_[t][b][c][p]; + const int update = (p0 != VP8CoeffsProba0[t][b][c][p]); + if (VP8PutBit(bw, update, VP8CoeffsUpdateProba[t][b][c][p])) { + VP8PutBits(bw, p0, 8); + } + } + } + } + } + if (VP8PutBitUniform(bw, probas->use_skip_proba_)) { + VP8PutBits(bw, probas->skip_proba_, 8); + } +} + diff --git a/libraries/webp/src/enc/vp8i_enc.h b/libraries/webp/src/enc/vp8i_enc.h new file mode 100644 index 00000000000..553008816f7 --- /dev/null +++ b/libraries/webp/src/enc/vp8i_enc.h @@ -0,0 +1,523 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebP encoder: internal header. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_ENC_VP8I_ENC_H_ +#define WEBP_ENC_VP8I_ENC_H_ + +#include // for memcpy() +#include "src/dec/common_dec.h" +#include "src/dsp/dsp.h" +#include "src/utils/bit_writer_utils.h" +#include "src/utils/thread_utils.h" +#include "src/utils/utils.h" +#include "include/webp/encode.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Various defines and enums + +// version numbers +#define ENC_MAJ_VERSION 1 +#define ENC_MIN_VERSION 3 +#define ENC_REV_VERSION 2 + +enum { MAX_LF_LEVELS = 64, // Maximum loop filter level + MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost + MAX_LEVEL = 2047 // max level (note: max codable is 2047 + 67) + }; + +typedef enum { // Rate-distortion optimization levels + RD_OPT_NONE = 0, // no rd-opt + RD_OPT_BASIC = 1, // basic scoring (no trellis) + RD_OPT_TRELLIS = 2, // perform trellis-quant on the final decision only + RD_OPT_TRELLIS_ALL = 3 // trellis-quant for every scoring (much slower) +} VP8RDLevel; + +// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). +// The original or reconstructed samples can be accessed using VP8Scan[]. +// The predicted blocks can be accessed using offsets to yuv_p_ and +// the arrays VP8*ModeOffsets[]. +// * YUV Samples area (yuv_in_/yuv_out_/yuv_out2_) +// (see VP8Scan[] for accessing the blocks, along with +// Y_OFF_ENC/U_OFF_ENC/V_OFF_ENC): +// +----+----+ +// Y_OFF_ENC |YYYY|UUVV| +// U_OFF_ENC |YYYY|UUVV| +// V_OFF_ENC |YYYY|....| <- 25% wasted U/V area +// |YYYY|....| +// +----+----+ +// * Prediction area ('yuv_p_', size = PRED_SIZE_ENC) +// Intra16 predictions (16x16 block each, two per row): +// |I16DC16|I16TM16| +// |I16VE16|I16HE16| +// Chroma U/V predictions (16x8 block each, two per row): +// |C8DC8|C8TM8| +// |C8VE8|C8HE8| +// Intra 4x4 predictions (4x4 block each) +// |I4DC4 I4TM4 I4VE4 I4HE4|I4RD4 I4VR4 I4LD4 I4VL4| +// |I4HD4 I4HU4 I4TMP .....|.......................| <- ~31% wasted +#define YUV_SIZE_ENC (BPS * 16) +#define PRED_SIZE_ENC (32 * BPS + 16 * BPS + 8 * BPS) // I16+Chroma+I4 preds +#define Y_OFF_ENC (0) +#define U_OFF_ENC (16) +#define V_OFF_ENC (16 + 8) + +extern const uint16_t VP8Scan[16]; +extern const uint16_t VP8UVModeOffsets[4]; +extern const uint16_t VP8I16ModeOffsets[4]; +extern const uint16_t VP8I4ModeOffsets[NUM_BMODES]; + +// Layout of prediction blocks +// intra 16x16 +#define I16DC16 (0 * 16 * BPS) +#define I16TM16 (I16DC16 + 16) +#define I16VE16 (1 * 16 * BPS) +#define I16HE16 (I16VE16 + 16) +// chroma 8x8, two U/V blocks side by side (hence: 16x8 each) +#define C8DC8 (2 * 16 * BPS) +#define C8TM8 (C8DC8 + 1 * 16) +#define C8VE8 (2 * 16 * BPS + 8 * BPS) +#define C8HE8 (C8VE8 + 1 * 16) +// intra 4x4 +#define I4DC4 (3 * 16 * BPS + 0) +#define I4TM4 (I4DC4 + 4) +#define I4VE4 (I4DC4 + 8) +#define I4HE4 (I4DC4 + 12) +#define I4RD4 (I4DC4 + 16) +#define I4VR4 (I4DC4 + 20) +#define I4LD4 (I4DC4 + 24) +#define I4VL4 (I4DC4 + 28) +#define I4HD4 (3 * 16 * BPS + 4 * BPS) +#define I4HU4 (I4HD4 + 4) +#define I4TMP (I4HD4 + 8) + +typedef int64_t score_t; // type used for scores, rate, distortion +// Note that MAX_COST is not the maximum allowed by sizeof(score_t), +// in order to allow overflowing computations. +#define MAX_COST ((score_t)0x7fffffffffffffLL) + +#define QFIX 17 +#define BIAS(b) ((b) << (QFIX - 8)) +// Fun fact: this is the _only_ line where we're actually being lossy and +// discarding bits. +static WEBP_INLINE int QUANTDIV(uint32_t n, uint32_t iQ, uint32_t B) { + return (int)((n * iQ + B) >> QFIX); +} + +// Uncomment the following to remove token-buffer code: +// #define DISABLE_TOKEN_BUFFER + +// quality below which error-diffusion is enabled +#define ERROR_DIFFUSION_QUALITY 98 + +//------------------------------------------------------------------------------ +// Headers + +typedef uint32_t proba_t; // 16b + 16b +typedef uint8_t ProbaArray[NUM_CTX][NUM_PROBAS]; +typedef proba_t StatsArray[NUM_CTX][NUM_PROBAS]; +typedef uint16_t CostArray[NUM_CTX][MAX_VARIABLE_LEVEL + 1]; +typedef const uint16_t* (*CostArrayPtr)[NUM_CTX]; // for easy casting +typedef const uint16_t* CostArrayMap[16][NUM_CTX]; +typedef double LFStats[NUM_MB_SEGMENTS][MAX_LF_LEVELS]; // filter stats + +typedef struct VP8Encoder VP8Encoder; + +// segment features +typedef struct { + int num_segments_; // Actual number of segments. 1 segment only = unused. + int update_map_; // whether to update the segment map or not. + // must be 0 if there's only 1 segment. + int size_; // bit-cost for transmitting the segment map +} VP8EncSegmentHeader; + +// Struct collecting all frame-persistent probabilities. +typedef struct { + uint8_t segments_[3]; // probabilities for segment tree + uint8_t skip_proba_; // final probability of being skipped. + ProbaArray coeffs_[NUM_TYPES][NUM_BANDS]; // 1056 bytes + StatsArray stats_[NUM_TYPES][NUM_BANDS]; // 4224 bytes + CostArray level_cost_[NUM_TYPES][NUM_BANDS]; // 13056 bytes + CostArrayMap remapped_costs_[NUM_TYPES]; // 1536 bytes + int dirty_; // if true, need to call VP8CalculateLevelCosts() + int use_skip_proba_; // Note: we always use skip_proba for now. + int nb_skip_; // number of skipped blocks +} VP8EncProba; + +// Filter parameters. Not actually used in the code (we don't perform +// the in-loop filtering), but filled from user's config +typedef struct { + int simple_; // filtering type: 0=complex, 1=simple + int level_; // base filter level [0..63] + int sharpness_; // [0..7] + int i4x4_lf_delta_; // delta filter level for i4x4 relative to i16x16 +} VP8EncFilterHeader; + +//------------------------------------------------------------------------------ +// Informations about the macroblocks. + +typedef struct { + // block type + unsigned int type_:2; // 0=i4x4, 1=i16x16 + unsigned int uv_mode_:2; + unsigned int skip_:1; + unsigned int segment_:2; + uint8_t alpha_; // quantization-susceptibility +} VP8MBInfo; + +typedef struct VP8Matrix { + uint16_t q_[16]; // quantizer steps + uint16_t iq_[16]; // reciprocals, fixed point. + uint32_t bias_[16]; // rounding bias + uint32_t zthresh_[16]; // value below which a coefficient is zeroed + uint16_t sharpen_[16]; // frequency boosters for slight sharpening +} VP8Matrix; + +typedef struct { + VP8Matrix y1_, y2_, uv_; // quantization matrices + int alpha_; // quant-susceptibility, range [-127,127]. Zero is neutral. + // Lower values indicate a lower risk of blurriness. + int beta_; // filter-susceptibility, range [0,255]. + int quant_; // final segment quantizer. + int fstrength_; // final in-loop filtering strength + int max_edge_; // max edge delta (for filtering strength) + int min_disto_; // minimum distortion required to trigger filtering record + // reactivities + int lambda_i16_, lambda_i4_, lambda_uv_; + int lambda_mode_, lambda_trellis_, tlambda_; + int lambda_trellis_i16_, lambda_trellis_i4_, lambda_trellis_uv_; + + // lambda values for distortion-based evaluation + score_t i4_penalty_; // penalty for using Intra4 +} VP8SegmentInfo; + +typedef int8_t DError[2 /* u/v */][2 /* top or left */]; + +// Handy transient struct to accumulate score and info during RD-optimization +// and mode evaluation. +typedef struct { + score_t D, SD; // Distortion, spectral distortion + score_t H, R, score; // header bits, rate, score. + int16_t y_dc_levels[16]; // Quantized levels for luma-DC, luma-AC, chroma. + int16_t y_ac_levels[16][16]; + int16_t uv_levels[4 + 4][16]; + int mode_i16; // mode number for intra16 prediction + uint8_t modes_i4[16]; // mode numbers for intra4 predictions + int mode_uv; // mode number of chroma prediction + uint32_t nz; // non-zero blocks + int8_t derr[2][3]; // DC diffusion errors for U/V for blocks #1/2/3 +} VP8ModeScore; + +// Iterator structure to iterate through macroblocks, pointing to the +// right neighbouring data (samples, predictions, contexts, ...) +typedef struct { + int x_, y_; // current macroblock + uint8_t* yuv_in_; // input samples + uint8_t* yuv_out_; // output samples + uint8_t* yuv_out2_; // secondary buffer swapped with yuv_out_. + uint8_t* yuv_p_; // scratch buffer for prediction + VP8Encoder* enc_; // back-pointer + VP8MBInfo* mb_; // current macroblock + VP8BitWriter* bw_; // current bit-writer + uint8_t* preds_; // intra mode predictors (4x4 blocks) + uint32_t* nz_; // non-zero pattern + uint8_t i4_boundary_[37]; // 32+5 boundary samples needed by intra4x4 + uint8_t* i4_top_; // pointer to the current top boundary sample + int i4_; // current intra4x4 mode being tested + int top_nz_[9]; // top-non-zero context. + int left_nz_[9]; // left-non-zero. left_nz[8] is independent. + uint64_t bit_count_[4][3]; // bit counters for coded levels. + uint64_t luma_bits_; // macroblock bit-cost for luma + uint64_t uv_bits_; // macroblock bit-cost for chroma + LFStats* lf_stats_; // filter stats (borrowed from enc_) + int do_trellis_; // if true, perform extra level optimisation + int count_down_; // number of mb still to be processed + int count_down0_; // starting counter value (for progress) + int percent0_; // saved initial progress percent + + DError left_derr_; // left error diffusion (u/v) + DError* top_derr_; // top diffusion error - NULL if disabled + + uint8_t* y_left_; // left luma samples (addressable from index -1 to 15). + uint8_t* u_left_; // left u samples (addressable from index -1 to 7) + uint8_t* v_left_; // left v samples (addressable from index -1 to 7) + + uint8_t* y_top_; // top luma samples at position 'x_' + uint8_t* uv_top_; // top u/v samples at position 'x_', packed as 16 bytes + + // memory for storing y/u/v_left_ + uint8_t yuv_left_mem_[17 + 16 + 16 + 8 + WEBP_ALIGN_CST]; + // memory for yuv_* + uint8_t yuv_mem_[3 * YUV_SIZE_ENC + PRED_SIZE_ENC + WEBP_ALIGN_CST]; +} VP8EncIterator; + + // in iterator.c +// must be called first +void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it); +// restart a scan +void VP8IteratorReset(VP8EncIterator* const it); +// reset iterator position to row 'y' +void VP8IteratorSetRow(VP8EncIterator* const it, int y); +// set count down (=number of iterations to go) +void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down); +// return true if iteration is finished +int VP8IteratorIsDone(const VP8EncIterator* const it); +// Import uncompressed samples from source. +// If tmp_32 is not NULL, import boundary samples too. +// tmp_32 is a 32-bytes scratch buffer that must be aligned in memory. +void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32); +// export decimated samples +void VP8IteratorExport(const VP8EncIterator* const it); +// go to next macroblock. Returns false if not finished. +int VP8IteratorNext(VP8EncIterator* const it); +// save the yuv_out_ boundary values to top_/left_ arrays for next iterations. +void VP8IteratorSaveBoundary(VP8EncIterator* const it); +// Report progression based on macroblock rows. Return 0 for user-abort request. +int VP8IteratorProgress(const VP8EncIterator* const it, int delta); +// Intra4x4 iterations +void VP8IteratorStartI4(VP8EncIterator* const it); +// returns true if not done. +int VP8IteratorRotateI4(VP8EncIterator* const it, + const uint8_t* const yuv_out); + +// Non-zero context setup/teardown +void VP8IteratorNzToBytes(VP8EncIterator* const it); +void VP8IteratorBytesToNz(VP8EncIterator* const it); + +// Helper functions to set mode properties +void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode); +void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes); +void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode); +void VP8SetSkip(const VP8EncIterator* const it, int skip); +void VP8SetSegment(const VP8EncIterator* const it, int segment); + +//------------------------------------------------------------------------------ +// Paginated token buffer + +typedef struct VP8Tokens VP8Tokens; // struct details in token.c + +typedef struct { +#if !defined(DISABLE_TOKEN_BUFFER) + VP8Tokens* pages_; // first page + VP8Tokens** last_page_; // last page + uint16_t* tokens_; // set to (*last_page_)->tokens_ + int left_; // how many free tokens left before the page is full + int page_size_; // number of tokens per page +#endif + int error_; // true in case of malloc error +} VP8TBuffer; + +// initialize an empty buffer +void VP8TBufferInit(VP8TBuffer* const b, int page_size); +void VP8TBufferClear(VP8TBuffer* const b); // de-allocate pages memory + +#if !defined(DISABLE_TOKEN_BUFFER) + +// Finalizes bitstream when probabilities are known. +// Deletes the allocated token memory if final_pass is true. +int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw, + const uint8_t* const probas, int final_pass); + +// record the coding of coefficients without knowing the probabilities yet +int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res, + VP8TBuffer* const tokens); + +// Estimate the final coded size given a set of 'probas'. +size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas); + +#endif // !DISABLE_TOKEN_BUFFER + +//------------------------------------------------------------------------------ +// VP8Encoder + +struct VP8Encoder { + const WebPConfig* config_; // user configuration and parameters + WebPPicture* pic_; // input / output picture + + // headers + VP8EncFilterHeader filter_hdr_; // filtering information + VP8EncSegmentHeader segment_hdr_; // segment information + + int profile_; // VP8's profile, deduced from Config. + + // dimension, in macroblock units. + int mb_w_, mb_h_; + int preds_w_; // stride of the *preds_ prediction plane (=4*mb_w + 1) + + // number of partitions (1, 2, 4 or 8 = MAX_NUM_PARTITIONS) + int num_parts_; + + // per-partition boolean decoders. + VP8BitWriter bw_; // part0 + VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions + VP8TBuffer tokens_; // token buffer + + int percent_; // for progress + + // transparency blob + int has_alpha_; + uint8_t* alpha_data_; // non-NULL if transparency is present + uint32_t alpha_data_size_; + WebPWorker alpha_worker_; + + // quantization info (one set of DC/AC dequant factor per segment) + VP8SegmentInfo dqm_[NUM_MB_SEGMENTS]; + int base_quant_; // nominal quantizer value. Only used + // for relative coding of segments' quant. + int alpha_; // global susceptibility (<=> complexity) + int uv_alpha_; // U/V quantization susceptibility + // global offset of quantizers, shared by all segments + int dq_y1_dc_; + int dq_y2_dc_, dq_y2_ac_; + int dq_uv_dc_, dq_uv_ac_; + + // probabilities and statistics + VP8EncProba proba_; + uint64_t sse_[4]; // sum of Y/U/V/A squared errors for all macroblocks + uint64_t sse_count_; // pixel count for the sse_[] stats + int coded_size_; + int residual_bytes_[3][4]; + int block_count_[3]; + + // quality/speed settings + int method_; // 0=fastest, 6=best/slowest. + VP8RDLevel rd_opt_level_; // Deduced from method_. + int max_i4_header_bits_; // partition #0 safeness factor + int mb_header_limit_; // rough limit for header bits per MB + int thread_level_; // derived from config->thread_level + int do_search_; // derived from config->target_XXX + int use_tokens_; // if true, use token buffer + + // Memory + VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1) + uint8_t* preds_; // predictions modes: (4*mb_w+1) * (4*mb_h+1) + uint32_t* nz_; // non-zero bit context: mb_w+1 + uint8_t* y_top_; // top luma samples. + uint8_t* uv_top_; // top u/v samples. + // U and V are packed into 16 bytes (8 U + 8 V) + LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off) + DError* top_derr_; // diffusion error (NULL if disabled) +}; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + + // in tree.c +extern const uint8_t VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS]; +extern const uint8_t + VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS]; +// Reset the token probabilities to their initial (default) values +void VP8DefaultProbas(VP8Encoder* const enc); +// Write the token probabilities +void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas); +// Writes the partition #0 modes (that is: all intra modes) +void VP8CodeIntraModes(VP8Encoder* const enc); + + // in syntax.c +// Generates the final bitstream by coding the partition0 and headers, +// and appending an assembly of all the pre-coded token partitions. +// Return true if everything is ok. +int VP8EncWrite(VP8Encoder* const enc); +// Release memory allocated for bit-writing in VP8EncLoop & seq. +void VP8EncFreeBitWriters(VP8Encoder* const enc); + + // in frame.c +extern const uint8_t VP8Cat3[]; +extern const uint8_t VP8Cat4[]; +extern const uint8_t VP8Cat5[]; +extern const uint8_t VP8Cat6[]; + +// Form all the four Intra16x16 predictions in the yuv_p_ cache +void VP8MakeLuma16Preds(const VP8EncIterator* const it); +// Form all the four Chroma8x8 predictions in the yuv_p_ cache +void VP8MakeChroma8Preds(const VP8EncIterator* const it); +// Form all the ten Intra4x4 predictions in the yuv_p_ cache +// for the 4x4 block it->i4_ +void VP8MakeIntra4Preds(const VP8EncIterator* const it); +// Rate calculation +int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd); +int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]); +int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd); +// Main coding calls +int VP8EncLoop(VP8Encoder* const enc); +int VP8EncTokenLoop(VP8Encoder* const enc); + + // in webpenc.c +// Assign an error code to a picture. Return false for convenience. +int WebPEncodingSetError(const WebPPicture* const pic, WebPEncodingError error); +int WebPReportProgress(const WebPPicture* const pic, + int percent, int* const percent_store); + + // in analysis.c +// Main analysis loop. Decides the segmentations and complexity. +// Assigns a first guess for Intra16 and uvmode_ prediction modes. +int VP8EncAnalyze(VP8Encoder* const enc); + + // in quant.c +// Sets up segment's quantization values, base_quant_ and filter strengths. +void VP8SetSegmentParams(VP8Encoder* const enc, float quality); +// Pick best modes and fills the levels. Returns true if skipped. +int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd, + VP8RDLevel rd_opt); + + // in alpha.c +void VP8EncInitAlpha(VP8Encoder* const enc); // initialize alpha compression +int VP8EncStartAlpha(VP8Encoder* const enc); // start alpha coding process +int VP8EncFinishAlpha(VP8Encoder* const enc); // finalize compressed data +int VP8EncDeleteAlpha(VP8Encoder* const enc); // delete compressed data + +// autofilter +void VP8InitFilter(VP8EncIterator* const it); +void VP8StoreFilterStats(VP8EncIterator* const it); +void VP8AdjustFilterStrength(VP8EncIterator* const it); + +// returns the approximate filtering strength needed to smooth a edge +// step of 'delta', given a sharpness parameter 'sharpness'. +int VP8FilterStrengthFromDelta(int sharpness, int delta); + + // misc utils for picture_*.c: + +// Returns true if 'picture' is non-NULL and dimensions/colorspace are within +// their valid ranges. If returning false, the 'error_code' in 'picture' is +// updated. +int WebPValidatePicture(const WebPPicture* const picture); + +// Remove reference to the ARGB/YUVA buffer (doesn't free anything). +void WebPPictureResetBuffers(WebPPicture* const picture); + +// Allocates ARGB buffer according to set width/height (previous one is +// always free'd). Preserves the YUV(A) buffer. Returns false in case of error +// (invalid param, out-of-memory). +int WebPPictureAllocARGB(WebPPicture* const picture); + +// Allocates YUVA buffer according to set width/height (previous one is always +// free'd). Uses picture->csp to determine whether an alpha buffer is needed. +// Preserves the ARGB buffer. +// Returns false in case of error (invalid param, out-of-memory). +int WebPPictureAllocYUVA(WebPPicture* const picture); + +// Replace samples that are fully transparent by 'color' to help compressibility +// (no guarantee, though). Assumes pic->use_argb is true. +void WebPReplaceTransparentPixels(WebPPicture* const pic, uint32_t color); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_ENC_VP8I_ENC_H_ diff --git a/libraries/webp/src/enc/vp8l_enc.c b/libraries/webp/src/enc/vp8l_enc.c new file mode 100644 index 00000000000..60427a3b26f --- /dev/null +++ b/libraries/webp/src/enc/vp8l_enc.c @@ -0,0 +1,1893 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// main entry for the lossless encoder. +// +// Author: Vikas Arora (vikaas.arora@gmail.com) +// + +#include +#include + +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" +#include "src/enc/backward_references_enc.h" +#include "src/enc/histogram_enc.h" +#include "src/enc/vp8i_enc.h" +#include "src/enc/vp8li_enc.h" +#include "src/utils/bit_writer_utils.h" +#include "src/utils/huffman_encode_utils.h" +#include "src/utils/palette.h" +#include "src/utils/utils.h" +#include "include/webp/encode.h" +#include "include/webp/format_constants.h" + +// Maximum number of histogram images (sub-blocks). +#define MAX_HUFF_IMAGE_SIZE 2600 + +// ----------------------------------------------------------------------------- +// Palette + +// These five modes are evaluated and their respective entropy is computed. +typedef enum { + kDirect = 0, + kSpatial = 1, + kSubGreen = 2, + kSpatialSubGreen = 3, + kPalette = 4, + kPaletteAndSpatial = 5, + kNumEntropyIx = 6 +} EntropyIx; + +typedef enum { + kHistoAlpha = 0, + kHistoAlphaPred, + kHistoGreen, + kHistoGreenPred, + kHistoRed, + kHistoRedPred, + kHistoBlue, + kHistoBluePred, + kHistoRedSubGreen, + kHistoRedPredSubGreen, + kHistoBlueSubGreen, + kHistoBluePredSubGreen, + kHistoPalette, + kHistoTotal // Must be last. +} HistoIx; + +static void AddSingleSubGreen(uint32_t p, + uint32_t* const r, uint32_t* const b) { + const int green = (int)p >> 8; // The upper bits are masked away later. + ++r[(((int)p >> 16) - green) & 0xff]; + ++b[(((int)p >> 0) - green) & 0xff]; +} + +static void AddSingle(uint32_t p, + uint32_t* const a, uint32_t* const r, + uint32_t* const g, uint32_t* const b) { + ++a[(p >> 24) & 0xff]; + ++r[(p >> 16) & 0xff]; + ++g[(p >> 8) & 0xff]; + ++b[(p >> 0) & 0xff]; +} + +static WEBP_INLINE uint32_t HashPix(uint32_t pix) { + // Note that masking with 0xffffffffu is for preventing an + // 'unsigned int overflow' warning. Doesn't impact the compiled code. + return ((((uint64_t)pix + (pix >> 19)) * 0x39c5fba7ull) & 0xffffffffu) >> 24; +} + +static int AnalyzeEntropy(const uint32_t* argb, + int width, int height, int argb_stride, + int use_palette, + int palette_size, int transform_bits, + EntropyIx* const min_entropy_ix, + int* const red_and_blue_always_zero) { + // Allocate histogram set with cache_bits = 0. + uint32_t* histo; + + if (use_palette && palette_size <= 16) { + // In the case of small palettes, we pack 2, 4 or 8 pixels together. In + // practice, small palettes are better than any other transform. + *min_entropy_ix = kPalette; + *red_and_blue_always_zero = 1; + return 1; + } + histo = (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256); + if (histo != NULL) { + int i, x, y; + const uint32_t* prev_row = NULL; + const uint32_t* curr_row = argb; + uint32_t pix_prev = argb[0]; // Skip the first pixel. + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + const uint32_t pix = curr_row[x]; + const uint32_t pix_diff = VP8LSubPixels(pix, pix_prev); + pix_prev = pix; + if ((pix_diff == 0) || (prev_row != NULL && pix == prev_row[x])) { + continue; + } + AddSingle(pix, + &histo[kHistoAlpha * 256], + &histo[kHistoRed * 256], + &histo[kHistoGreen * 256], + &histo[kHistoBlue * 256]); + AddSingle(pix_diff, + &histo[kHistoAlphaPred * 256], + &histo[kHistoRedPred * 256], + &histo[kHistoGreenPred * 256], + &histo[kHistoBluePred * 256]); + AddSingleSubGreen(pix, + &histo[kHistoRedSubGreen * 256], + &histo[kHistoBlueSubGreen * 256]); + AddSingleSubGreen(pix_diff, + &histo[kHistoRedPredSubGreen * 256], + &histo[kHistoBluePredSubGreen * 256]); + { + // Approximate the palette by the entropy of the multiplicative hash. + const uint32_t hash = HashPix(pix); + ++histo[kHistoPalette * 256 + hash]; + } + } + prev_row = curr_row; + curr_row += argb_stride; + } + { + float entropy_comp[kHistoTotal]; + float entropy[kNumEntropyIx]; + int k; + int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen; + int j; + // Let's add one zero to the predicted histograms. The zeros are removed + // too efficiently by the pix_diff == 0 comparison, at least one of the + // zeros is likely to exist. + ++histo[kHistoRedPredSubGreen * 256]; + ++histo[kHistoBluePredSubGreen * 256]; + ++histo[kHistoRedPred * 256]; + ++histo[kHistoGreenPred * 256]; + ++histo[kHistoBluePred * 256]; + ++histo[kHistoAlphaPred * 256]; + + for (j = 0; j < kHistoTotal; ++j) { + entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256); + } + entropy[kDirect] = entropy_comp[kHistoAlpha] + + entropy_comp[kHistoRed] + + entropy_comp[kHistoGreen] + + entropy_comp[kHistoBlue]; + entropy[kSpatial] = entropy_comp[kHistoAlphaPred] + + entropy_comp[kHistoRedPred] + + entropy_comp[kHistoGreenPred] + + entropy_comp[kHistoBluePred]; + entropy[kSubGreen] = entropy_comp[kHistoAlpha] + + entropy_comp[kHistoRedSubGreen] + + entropy_comp[kHistoGreen] + + entropy_comp[kHistoBlueSubGreen]; + entropy[kSpatialSubGreen] = entropy_comp[kHistoAlphaPred] + + entropy_comp[kHistoRedPredSubGreen] + + entropy_comp[kHistoGreenPred] + + entropy_comp[kHistoBluePredSubGreen]; + entropy[kPalette] = entropy_comp[kHistoPalette]; + + // When including transforms, there is an overhead in bits from + // storing them. This overhead is small but matters for small images. + // For spatial, there are 14 transformations. + entropy[kSpatial] += VP8LSubSampleSize(width, transform_bits) * + VP8LSubSampleSize(height, transform_bits) * + VP8LFastLog2(14); + // For color transforms: 24 as only 3 channels are considered in a + // ColorTransformElement. + entropy[kSpatialSubGreen] += VP8LSubSampleSize(width, transform_bits) * + VP8LSubSampleSize(height, transform_bits) * + VP8LFastLog2(24); + // For palettes, add the cost of storing the palette. + // We empirically estimate the cost of a compressed entry as 8 bits. + // The palette is differential-coded when compressed hence a much + // lower cost than sizeof(uint32_t)*8. + entropy[kPalette] += palette_size * 8; + + *min_entropy_ix = kDirect; + for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) { + if (entropy[*min_entropy_ix] > entropy[k]) { + *min_entropy_ix = (EntropyIx)k; + } + } + assert((int)*min_entropy_ix <= last_mode_to_analyze); + *red_and_blue_always_zero = 1; + // Let's check if the histogram of the chosen entropy mode has + // non-zero red and blue values. If all are zero, we can later skip + // the cross color optimization. + { + static const uint8_t kHistoPairs[5][2] = { + { kHistoRed, kHistoBlue }, + { kHistoRedPred, kHistoBluePred }, + { kHistoRedSubGreen, kHistoBlueSubGreen }, + { kHistoRedPredSubGreen, kHistoBluePredSubGreen }, + { kHistoRed, kHistoBlue } + }; + const uint32_t* const red_histo = + &histo[256 * kHistoPairs[*min_entropy_ix][0]]; + const uint32_t* const blue_histo = + &histo[256 * kHistoPairs[*min_entropy_ix][1]]; + for (i = 1; i < 256; ++i) { + if ((red_histo[i] | blue_histo[i]) != 0) { + *red_and_blue_always_zero = 0; + break; + } + } + } + } + WebPSafeFree(histo); + return 1; + } else { + return 0; + } +} + +static int GetHistoBits(int method, int use_palette, int width, int height) { + // Make tile size a function of encoding method (Range: 0 to 6). + int histo_bits = (use_palette ? 9 : 7) - method; + while (1) { + const int huff_image_size = VP8LSubSampleSize(width, histo_bits) * + VP8LSubSampleSize(height, histo_bits); + if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break; + ++histo_bits; + } + return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS : + (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits; +} + +static int GetTransformBits(int method, int histo_bits) { + const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5; + const int res = + (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits; + assert(res <= MAX_TRANSFORM_BITS); + return res; +} + +// Set of parameters to be used in each iteration of the cruncher. +#define CRUNCH_SUBCONFIGS_MAX 2 +typedef struct { + int lz77_; + int do_no_cache_; +} CrunchSubConfig; +typedef struct { + int entropy_idx_; + PaletteSorting palette_sorting_type_; + CrunchSubConfig sub_configs_[CRUNCH_SUBCONFIGS_MAX]; + int sub_configs_size_; +} CrunchConfig; + +// +2 because we add a palette sorting configuration for kPalette and +// kPaletteAndSpatial. +#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2 * kPaletteSortingNum) + +static int EncoderAnalyze(VP8LEncoder* const enc, + CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX], + int* const crunch_configs_size, + int* const red_and_blue_always_zero) { + const WebPPicture* const pic = enc->pic_; + const int width = pic->width; + const int height = pic->height; + const WebPConfig* const config = enc->config_; + const int method = config->method; + const int low_effort = (config->method == 0); + int i; + int use_palette; + int n_lz77s; + // If set to 0, analyze the cache with the computed cache value. If 1, also + // analyze with no-cache. + int do_no_cache = 0; + assert(pic != NULL && pic->argb != NULL); + + // Check whether a palette is possible. + enc->palette_size_ = GetColorPalette(pic, enc->palette_sorted_); + use_palette = (enc->palette_size_ <= MAX_PALETTE_SIZE); + if (!use_palette) { + enc->palette_size_ = 0; + } + + // Empirical bit sizes. + enc->histo_bits_ = GetHistoBits(method, use_palette, + pic->width, pic->height); + enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_); + + if (low_effort) { + // AnalyzeEntropy is somewhat slow. + crunch_configs[0].entropy_idx_ = use_palette ? kPalette : kSpatialSubGreen; + crunch_configs[0].palette_sorting_type_ = + use_palette ? kSortedDefault : kUnusedPalette; + n_lz77s = 1; + *crunch_configs_size = 1; + } else { + EntropyIx min_entropy_ix; + // Try out multiple LZ77 on images with few colors. + n_lz77s = (enc->palette_size_ > 0 && enc->palette_size_ <= 16) ? 2 : 1; + if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, use_palette, + enc->palette_size_, enc->transform_bits_, + &min_entropy_ix, red_and_blue_always_zero)) { + return 0; + } + if (method == 6 && config->quality == 100) { + do_no_cache = 1; + // Go brute force on all transforms. + *crunch_configs_size = 0; + for (i = 0; i < kNumEntropyIx; ++i) { + // We can only apply kPalette or kPaletteAndSpatial if we can indeed use + // a palette. + if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) { + assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX); + if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) { + int sorting_method; + for (sorting_method = 0; sorting_method < kPaletteSortingNum; + ++sorting_method) { + const PaletteSorting typed_sorting_method = + (PaletteSorting)sorting_method; + // TODO(vrabaud) kSortedDefault should be tested. It is omitted + // for now for backward compatibility. + if (typed_sorting_method == kUnusedPalette || + typed_sorting_method == kSortedDefault) { + continue; + } + crunch_configs[(*crunch_configs_size)].entropy_idx_ = i; + crunch_configs[(*crunch_configs_size)].palette_sorting_type_ = + typed_sorting_method; + ++*crunch_configs_size; + } + } else { + crunch_configs[(*crunch_configs_size)].entropy_idx_ = i; + crunch_configs[(*crunch_configs_size)].palette_sorting_type_ = + kUnusedPalette; + ++*crunch_configs_size; + } + } + } + } else { + // Only choose the guessed best transform. + *crunch_configs_size = 1; + crunch_configs[0].entropy_idx_ = min_entropy_ix; + crunch_configs[0].palette_sorting_type_ = + use_palette ? kMinimizeDelta : kUnusedPalette; + if (config->quality >= 75 && method == 5) { + // Test with and without color cache. + do_no_cache = 1; + // If we have a palette, also check in combination with spatial. + if (min_entropy_ix == kPalette) { + *crunch_configs_size = 2; + crunch_configs[1].entropy_idx_ = kPaletteAndSpatial; + crunch_configs[1].palette_sorting_type_ = kMinimizeDelta; + } + } + } + } + // Fill in the different LZ77s. + assert(n_lz77s <= CRUNCH_SUBCONFIGS_MAX); + for (i = 0; i < *crunch_configs_size; ++i) { + int j; + for (j = 0; j < n_lz77s; ++j) { + assert(j < CRUNCH_SUBCONFIGS_MAX); + crunch_configs[i].sub_configs_[j].lz77_ = + (j == 0) ? kLZ77Standard | kLZ77RLE : kLZ77Box; + crunch_configs[i].sub_configs_[j].do_no_cache_ = do_no_cache; + } + crunch_configs[i].sub_configs_size_ = n_lz77s; + } + return 1; +} + +static int EncoderInit(VP8LEncoder* const enc) { + const WebPPicture* const pic = enc->pic_; + const int width = pic->width; + const int height = pic->height; + const int pix_cnt = width * height; + // we round the block size up, so we're guaranteed to have + // at most MAX_REFS_BLOCK_PER_IMAGE blocks used: + const int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1; + int i; + if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0; + + for (i = 0; i < 4; ++i) VP8LBackwardRefsInit(&enc->refs_[i], refs_block_size); + + return 1; +} + +// Returns false in case of memory error. +static int GetHuffBitLengthsAndCodes( + const VP8LHistogramSet* const histogram_image, + HuffmanTreeCode* const huffman_codes) { + int i, k; + int ok = 0; + uint64_t total_length_size = 0; + uint8_t* mem_buf = NULL; + const int histogram_image_size = histogram_image->size; + int max_num_symbols = 0; + uint8_t* buf_rle = NULL; + HuffmanTree* huff_tree = NULL; + + // Iterate over all histograms and get the aggregate number of codes used. + for (i = 0; i < histogram_image_size; ++i) { + const VP8LHistogram* const histo = histogram_image->histograms[i]; + HuffmanTreeCode* const codes = &huffman_codes[5 * i]; + assert(histo != NULL); + for (k = 0; k < 5; ++k) { + const int num_symbols = + (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) : + (k == 4) ? NUM_DISTANCE_CODES : 256; + codes[k].num_symbols = num_symbols; + total_length_size += num_symbols; + } + } + + // Allocate and Set Huffman codes. + { + uint16_t* codes; + uint8_t* lengths; + mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size, + sizeof(*lengths) + sizeof(*codes)); + if (mem_buf == NULL) goto End; + + codes = (uint16_t*)mem_buf; + lengths = (uint8_t*)&codes[total_length_size]; + for (i = 0; i < 5 * histogram_image_size; ++i) { + const int bit_length = huffman_codes[i].num_symbols; + huffman_codes[i].codes = codes; + huffman_codes[i].code_lengths = lengths; + codes += bit_length; + lengths += bit_length; + if (max_num_symbols < bit_length) { + max_num_symbols = bit_length; + } + } + } + + buf_rle = (uint8_t*)WebPSafeMalloc(1ULL, max_num_symbols); + huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * max_num_symbols, + sizeof(*huff_tree)); + if (buf_rle == NULL || huff_tree == NULL) goto End; + + // Create Huffman trees. + for (i = 0; i < histogram_image_size; ++i) { + HuffmanTreeCode* const codes = &huffman_codes[5 * i]; + VP8LHistogram* const histo = histogram_image->histograms[i]; + VP8LCreateHuffmanTree(histo->literal_, 15, buf_rle, huff_tree, codes + 0); + VP8LCreateHuffmanTree(histo->red_, 15, buf_rle, huff_tree, codes + 1); + VP8LCreateHuffmanTree(histo->blue_, 15, buf_rle, huff_tree, codes + 2); + VP8LCreateHuffmanTree(histo->alpha_, 15, buf_rle, huff_tree, codes + 3); + VP8LCreateHuffmanTree(histo->distance_, 15, buf_rle, huff_tree, codes + 4); + } + ok = 1; + End: + WebPSafeFree(huff_tree); + WebPSafeFree(buf_rle); + if (!ok) { + WebPSafeFree(mem_buf); + memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes)); + } + return ok; +} + +static void StoreHuffmanTreeOfHuffmanTreeToBitMask( + VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) { + // RFC 1951 will calm you down if you are worried about this funny sequence. + // This sequence is tuned from that, but more weighted for lower symbol count, + // and more spiking histograms. + static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = { + 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + }; + int i; + // Throw away trailing zeros: + int codes_to_store = CODE_LENGTH_CODES; + for (; codes_to_store > 4; --codes_to_store) { + if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) { + break; + } + } + VP8LPutBits(bw, codes_to_store - 4, 4); + for (i = 0; i < codes_to_store; ++i) { + VP8LPutBits(bw, code_length_bitdepth[kStorageOrder[i]], 3); + } +} + +static void ClearHuffmanTreeIfOnlyOneSymbol( + HuffmanTreeCode* const huffman_code) { + int k; + int count = 0; + for (k = 0; k < huffman_code->num_symbols; ++k) { + if (huffman_code->code_lengths[k] != 0) { + ++count; + if (count > 1) return; + } + } + for (k = 0; k < huffman_code->num_symbols; ++k) { + huffman_code->code_lengths[k] = 0; + huffman_code->codes[k] = 0; + } +} + +static void StoreHuffmanTreeToBitMask( + VP8LBitWriter* const bw, + const HuffmanTreeToken* const tokens, const int num_tokens, + const HuffmanTreeCode* const huffman_code) { + int i; + for (i = 0; i < num_tokens; ++i) { + const int ix = tokens[i].code; + const int extra_bits = tokens[i].extra_bits; + VP8LPutBits(bw, huffman_code->codes[ix], huffman_code->code_lengths[ix]); + switch (ix) { + case 16: + VP8LPutBits(bw, extra_bits, 2); + break; + case 17: + VP8LPutBits(bw, extra_bits, 3); + break; + case 18: + VP8LPutBits(bw, extra_bits, 7); + break; + } + } +} + +// 'huff_tree' and 'tokens' are pre-alloacted buffers. +static void StoreFullHuffmanCode(VP8LBitWriter* const bw, + HuffmanTree* const huff_tree, + HuffmanTreeToken* const tokens, + const HuffmanTreeCode* const tree) { + uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 }; + uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 }; + const int max_tokens = tree->num_symbols; + int num_tokens; + HuffmanTreeCode huffman_code; + huffman_code.num_symbols = CODE_LENGTH_CODES; + huffman_code.code_lengths = code_length_bitdepth; + huffman_code.codes = code_length_bitdepth_symbols; + + VP8LPutBits(bw, 0, 1); + num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens); + { + uint32_t histogram[CODE_LENGTH_CODES] = { 0 }; + uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 }; + int i; + for (i = 0; i < num_tokens; ++i) { + ++histogram[tokens[i].code]; + } + + VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code); + } + + StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth); + ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code); + { + int trailing_zero_bits = 0; + int trimmed_length = num_tokens; + int write_trimmed_length; + int length; + int i = num_tokens; + while (i-- > 0) { + const int ix = tokens[i].code; + if (ix == 0 || ix == 17 || ix == 18) { + --trimmed_length; // discount trailing zeros + trailing_zero_bits += code_length_bitdepth[ix]; + if (ix == 17) { + trailing_zero_bits += 3; + } else if (ix == 18) { + trailing_zero_bits += 7; + } + } else { + break; + } + } + write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12); + length = write_trimmed_length ? trimmed_length : num_tokens; + VP8LPutBits(bw, write_trimmed_length, 1); + if (write_trimmed_length) { + if (trimmed_length == 2) { + VP8LPutBits(bw, 0, 3 + 2); // nbitpairs=1, trimmed_length=2 + } else { + const int nbits = BitsLog2Floor(trimmed_length - 2); + const int nbitpairs = nbits / 2 + 1; + assert(trimmed_length > 2); + assert(nbitpairs - 1 < 8); + VP8LPutBits(bw, nbitpairs - 1, 3); + VP8LPutBits(bw, trimmed_length - 2, nbitpairs * 2); + } + } + StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code); + } +} + +// 'huff_tree' and 'tokens' are pre-alloacted buffers. +static void StoreHuffmanCode(VP8LBitWriter* const bw, + HuffmanTree* const huff_tree, + HuffmanTreeToken* const tokens, + const HuffmanTreeCode* const huffman_code) { + int i; + int count = 0; + int symbols[2] = { 0, 0 }; + const int kMaxBits = 8; + const int kMaxSymbol = 1 << kMaxBits; + + // Check whether it's a small tree. + for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) { + if (huffman_code->code_lengths[i] != 0) { + if (count < 2) symbols[count] = i; + ++count; + } + } + + if (count == 0) { // emit minimal tree for empty cases + // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0 + VP8LPutBits(bw, 0x01, 4); + } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) { + VP8LPutBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols. + VP8LPutBits(bw, count - 1, 1); + if (symbols[0] <= 1) { + VP8LPutBits(bw, 0, 1); // Code bit for small (1 bit) symbol value. + VP8LPutBits(bw, symbols[0], 1); + } else { + VP8LPutBits(bw, 1, 1); + VP8LPutBits(bw, symbols[0], 8); + } + if (count == 2) { + VP8LPutBits(bw, symbols[1], 8); + } + } else { + StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code); + } +} + +static WEBP_INLINE void WriteHuffmanCode(VP8LBitWriter* const bw, + const HuffmanTreeCode* const code, + int code_index) { + const int depth = code->code_lengths[code_index]; + const int symbol = code->codes[code_index]; + VP8LPutBits(bw, symbol, depth); +} + +static WEBP_INLINE void WriteHuffmanCodeWithExtraBits( + VP8LBitWriter* const bw, + const HuffmanTreeCode* const code, + int code_index, + int bits, + int n_bits) { + const int depth = code->code_lengths[code_index]; + const int symbol = code->codes[code_index]; + VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits); +} + +static int StoreImageToBitMask( + VP8LBitWriter* const bw, int width, int histo_bits, + const VP8LBackwardRefs* const refs, + const uint16_t* histogram_symbols, + const HuffmanTreeCode* const huffman_codes, const WebPPicture* const pic) { + const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1; + const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits); + // x and y trace the position in the image. + int x = 0; + int y = 0; + int tile_x = x & tile_mask; + int tile_y = y & tile_mask; + int histogram_ix = histogram_symbols[0]; + const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix; + VP8LRefsCursor c = VP8LRefsCursorInit(refs); + while (VP8LRefsCursorOk(&c)) { + const PixOrCopy* const v = c.cur_pos; + if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) { + tile_x = x & tile_mask; + tile_y = y & tile_mask; + histogram_ix = histogram_symbols[(y >> histo_bits) * histo_xsize + + (x >> histo_bits)]; + codes = huffman_codes + 5 * histogram_ix; + } + if (PixOrCopyIsLiteral(v)) { + static const uint8_t order[] = { 1, 2, 0, 3 }; + int k; + for (k = 0; k < 4; ++k) { + const int code = PixOrCopyLiteral(v, order[k]); + WriteHuffmanCode(bw, codes + k, code); + } + } else if (PixOrCopyIsCacheIdx(v)) { + const int code = PixOrCopyCacheIdx(v); + const int literal_ix = 256 + NUM_LENGTH_CODES + code; + WriteHuffmanCode(bw, codes, literal_ix); + } else { + int bits, n_bits; + int code; + + const int distance = PixOrCopyDistance(v); + VP8LPrefixEncode(v->len, &code, &n_bits, &bits); + WriteHuffmanCodeWithExtraBits(bw, codes, 256 + code, bits, n_bits); + + // Don't write the distance with the extra bits code since + // the distance can be up to 18 bits of extra bits, and the prefix + // 15 bits, totaling to 33, and our PutBits only supports up to 32 bits. + VP8LPrefixEncode(distance, &code, &n_bits, &bits); + WriteHuffmanCode(bw, codes + 4, code); + VP8LPutBits(bw, bits, n_bits); + } + x += PixOrCopyLength(v); + while (x >= width) { + x -= width; + ++y; + } + VP8LRefsCursorNext(&c); + } + if (bw->error_) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + return 1; +} + +// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31. +// pic and percent are for progress. +static int EncodeImageNoHuffman(VP8LBitWriter* const bw, + const uint32_t* const argb, + VP8LHashChain* const hash_chain, + VP8LBackwardRefs* const refs_array, int width, + int height, int quality, int low_effort, + const WebPPicture* const pic, int percent_range, + int* const percent) { + int i; + int max_tokens = 0; + VP8LBackwardRefs* refs; + HuffmanTreeToken* tokens = NULL; + HuffmanTreeCode huffman_codes[5] = {{0, NULL, NULL}}; + const uint16_t histogram_symbols[1] = {0}; // only one tree, one symbol + int cache_bits = 0; + VP8LHistogramSet* histogram_image = NULL; + HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( + 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); + if (huff_tree == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + // Calculate backward references from ARGB image. + if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, low_effort, + pic, percent_range / 2, percent)) { + goto Error; + } + if (!VP8LGetBackwardReferences(width, height, argb, quality, /*low_effort=*/0, + kLZ77Standard | kLZ77RLE, cache_bits, + /*do_no_cache=*/0, hash_chain, refs_array, + &cache_bits, pic, + percent_range - percent_range / 2, percent)) { + goto Error; + } + refs = &refs_array[0]; + histogram_image = VP8LAllocateHistogramSet(1, cache_bits); + if (histogram_image == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + VP8LHistogramSetClear(histogram_image); + + // Build histogram image and symbols from backward references. + VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]); + + // Create Huffman bit lengths and codes for each histogram image. + assert(histogram_image->size == 1); + if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + // No color cache, no Huffman image. + VP8LPutBits(bw, 0, 1); + + // Find maximum number of symbols for the huffman tree-set. + for (i = 0; i < 5; ++i) { + HuffmanTreeCode* const codes = &huffman_codes[i]; + if (max_tokens < codes->num_symbols) { + max_tokens = codes->num_symbols; + } + } + + tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens)); + if (tokens == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + // Store Huffman codes. + for (i = 0; i < 5; ++i) { + HuffmanTreeCode* const codes = &huffman_codes[i]; + StoreHuffmanCode(bw, huff_tree, tokens, codes); + ClearHuffmanTreeIfOnlyOneSymbol(codes); + } + + // Store actual literals. + if (!StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, huffman_codes, + pic)) { + goto Error; + } + + Error: + WebPSafeFree(tokens); + WebPSafeFree(huff_tree); + VP8LFreeHistogramSet(histogram_image); + WebPSafeFree(huffman_codes[0].codes); + return (pic->error_code == VP8_ENC_OK); +} + +// pic and percent are for progress. +static int EncodeImageInternal( + VP8LBitWriter* const bw, const uint32_t* const argb, + VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width, + int height, int quality, int low_effort, const CrunchConfig* const config, + int* cache_bits, int histogram_bits, size_t init_byte_position, + int* const hdr_size, int* const data_size, const WebPPicture* const pic, + int percent_range, int* const percent) { + const uint32_t histogram_image_xysize = + VP8LSubSampleSize(width, histogram_bits) * + VP8LSubSampleSize(height, histogram_bits); + int remaining_percent = percent_range; + int percent_start = *percent; + VP8LHistogramSet* histogram_image = NULL; + VP8LHistogram* tmp_histo = NULL; + int histogram_image_size = 0; + size_t bit_array_size = 0; + HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( + 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); + HuffmanTreeToken* tokens = NULL; + HuffmanTreeCode* huffman_codes = NULL; + uint16_t* const histogram_symbols = (uint16_t*)WebPSafeMalloc( + histogram_image_xysize, sizeof(*histogram_symbols)); + int sub_configs_idx; + int cache_bits_init, write_histogram_image; + VP8LBitWriter bw_init = *bw, bw_best; + int hdr_size_tmp; + VP8LHashChain hash_chain_histogram; // histogram image hash chain + size_t bw_size_best = ~(size_t)0; + assert(histogram_bits >= MIN_HUFFMAN_BITS); + assert(histogram_bits <= MAX_HUFFMAN_BITS); + assert(hdr_size != NULL); + assert(data_size != NULL); + + memset(&hash_chain_histogram, 0, sizeof(hash_chain_histogram)); + if (!VP8LBitWriterInit(&bw_best, 0)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + // Make sure we can allocate the different objects. + if (huff_tree == NULL || histogram_symbols == NULL || + !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + percent_range = remaining_percent / 5; + if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, + low_effort, pic, percent_range, percent)) { + goto Error; + } + percent_start += percent_range; + remaining_percent -= percent_range; + + // If the value is different from zero, it has been set during the palette + // analysis. + cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits; + // If several iterations will happen, clone into bw_best. + if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) && + !VP8LBitWriterClone(bw, &bw_best)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size_; + ++sub_configs_idx) { + const CrunchSubConfig* const sub_config = + &config->sub_configs_[sub_configs_idx]; + int cache_bits_best, i_cache; + int i_remaining_percent = remaining_percent / config->sub_configs_size_; + int i_percent_range = i_remaining_percent / 4; + i_remaining_percent -= i_percent_range; + + if (!VP8LGetBackwardReferences( + width, height, argb, quality, low_effort, sub_config->lz77_, + cache_bits_init, sub_config->do_no_cache_, hash_chain, + &refs_array[0], &cache_bits_best, pic, i_percent_range, percent)) { + goto Error; + } + + for (i_cache = 0; i_cache < (sub_config->do_no_cache_ ? 2 : 1); ++i_cache) { + const int cache_bits_tmp = (i_cache == 0) ? cache_bits_best : 0; + // Speed-up: no need to study the no-cache case if it was already studied + // in i_cache == 0. + if (i_cache == 1 && cache_bits_best == 0) break; + + // Reset the bit writer for this iteration. + VP8LBitWriterReset(&bw_init, bw); + + // Build histogram image and symbols from backward references. + histogram_image = + VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits_tmp); + tmp_histo = VP8LAllocateHistogram(cache_bits_tmp); + if (histogram_image == NULL || tmp_histo == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + i_percent_range = i_remaining_percent / 3; + i_remaining_percent -= i_percent_range; + if (!VP8LGetHistoImageSymbols( + width, height, &refs_array[i_cache], quality, low_effort, + histogram_bits, cache_bits_tmp, histogram_image, tmp_histo, + histogram_symbols, pic, i_percent_range, percent)) { + goto Error; + } + // Create Huffman bit lengths and codes for each histogram image. + histogram_image_size = histogram_image->size; + bit_array_size = 5 * histogram_image_size; + huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size, + sizeof(*huffman_codes)); + // Note: some histogram_image entries may point to tmp_histos[], so the + // latter need to outlive the following call to + // GetHuffBitLengthsAndCodes(). + if (huffman_codes == NULL || + !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + // Free combined histograms. + VP8LFreeHistogramSet(histogram_image); + histogram_image = NULL; + + // Free scratch histograms. + VP8LFreeHistogram(tmp_histo); + tmp_histo = NULL; + + // Color Cache parameters. + if (cache_bits_tmp > 0) { + VP8LPutBits(bw, 1, 1); + VP8LPutBits(bw, cache_bits_tmp, 4); + } else { + VP8LPutBits(bw, 0, 1); + } + + // Huffman image + meta huffman. + write_histogram_image = (histogram_image_size > 1); + VP8LPutBits(bw, write_histogram_image, 1); + if (write_histogram_image) { + uint32_t* const histogram_argb = (uint32_t*)WebPSafeMalloc( + histogram_image_xysize, sizeof(*histogram_argb)); + int max_index = 0; + uint32_t i; + if (histogram_argb == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + for (i = 0; i < histogram_image_xysize; ++i) { + const int symbol_index = histogram_symbols[i] & 0xffff; + histogram_argb[i] = (symbol_index << 8); + if (symbol_index >= max_index) { + max_index = symbol_index + 1; + } + } + histogram_image_size = max_index; + + VP8LPutBits(bw, histogram_bits - 2, 3); + i_percent_range = i_remaining_percent / 2; + i_remaining_percent -= i_percent_range; + if (!EncodeImageNoHuffman( + bw, histogram_argb, &hash_chain_histogram, &refs_array[2], + VP8LSubSampleSize(width, histogram_bits), + VP8LSubSampleSize(height, histogram_bits), quality, low_effort, + pic, i_percent_range, percent)) { + WebPSafeFree(histogram_argb); + goto Error; + } + WebPSafeFree(histogram_argb); + } + + // Store Huffman codes. + { + int i; + int max_tokens = 0; + // Find maximum number of symbols for the huffman tree-set. + for (i = 0; i < 5 * histogram_image_size; ++i) { + HuffmanTreeCode* const codes = &huffman_codes[i]; + if (max_tokens < codes->num_symbols) { + max_tokens = codes->num_symbols; + } + } + tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens)); + if (tokens == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + for (i = 0; i < 5 * histogram_image_size; ++i) { + HuffmanTreeCode* const codes = &huffman_codes[i]; + StoreHuffmanCode(bw, huff_tree, tokens, codes); + ClearHuffmanTreeIfOnlyOneSymbol(codes); + } + } + // Store actual literals. + hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position); + if (!StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache], + histogram_symbols, huffman_codes, pic)) { + goto Error; + } + // Keep track of the smallest image so far. + if (VP8LBitWriterNumBytes(bw) < bw_size_best) { + bw_size_best = VP8LBitWriterNumBytes(bw); + *cache_bits = cache_bits_tmp; + *hdr_size = hdr_size_tmp; + *data_size = + (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size); + VP8LBitWriterSwap(bw, &bw_best); + } + WebPSafeFree(tokens); + tokens = NULL; + if (huffman_codes != NULL) { + WebPSafeFree(huffman_codes->codes); + WebPSafeFree(huffman_codes); + huffman_codes = NULL; + } + } + } + VP8LBitWriterSwap(bw, &bw_best); + + if (!WebPReportProgress(pic, percent_start + remaining_percent, percent)) { + goto Error; + } + + Error: + WebPSafeFree(tokens); + WebPSafeFree(huff_tree); + VP8LFreeHistogramSet(histogram_image); + VP8LFreeHistogram(tmp_histo); + VP8LHashChainClear(&hash_chain_histogram); + if (huffman_codes != NULL) { + WebPSafeFree(huffman_codes->codes); + WebPSafeFree(huffman_codes); + } + WebPSafeFree(histogram_symbols); + VP8LBitWriterWipeOut(&bw_best); + return (pic->error_code == VP8_ENC_OK); +} + +// ----------------------------------------------------------------------------- +// Transforms + +static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height, + VP8LBitWriter* const bw) { + VP8LPutBits(bw, TRANSFORM_PRESENT, 1); + VP8LPutBits(bw, SUBTRACT_GREEN_TRANSFORM, 2); + VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height); +} + +static int ApplyPredictFilter(const VP8LEncoder* const enc, int width, + int height, int quality, int low_effort, + int used_subtract_green, VP8LBitWriter* const bw, + int percent_range, int* const percent) { + const int pred_bits = enc->transform_bits_; + const int transform_width = VP8LSubSampleSize(width, pred_bits); + const int transform_height = VP8LSubSampleSize(height, pred_bits); + // we disable near-lossless quantization if palette is used. + const int near_lossless_strength = + enc->use_palette_ ? 100 : enc->config_->near_lossless; + + if (!VP8LResidualImage( + width, height, pred_bits, low_effort, enc->argb_, enc->argb_scratch_, + enc->transform_data_, near_lossless_strength, enc->config_->exact, + used_subtract_green, enc->pic_, percent_range / 2, percent)) { + return 0; + } + VP8LPutBits(bw, TRANSFORM_PRESENT, 1); + VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); + assert(pred_bits >= 2); + VP8LPutBits(bw, pred_bits - 2, 3); + return EncodeImageNoHuffman( + bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_, + (VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height, + quality, low_effort, enc->pic_, percent_range - percent_range / 2, + percent); +} + +static int ApplyCrossColorFilter(const VP8LEncoder* const enc, int width, + int height, int quality, int low_effort, + VP8LBitWriter* const bw, int percent_range, + int* const percent) { + const int ccolor_transform_bits = enc->transform_bits_; + const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); + const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); + + if (!VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality, + enc->argb_, enc->transform_data_, enc->pic_, + percent_range / 2, percent)) { + return 0; + } + VP8LPutBits(bw, TRANSFORM_PRESENT, 1); + VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2); + assert(ccolor_transform_bits >= 2); + VP8LPutBits(bw, ccolor_transform_bits - 2, 3); + return EncodeImageNoHuffman( + bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_, + (VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height, + quality, low_effort, enc->pic_, percent_range - percent_range / 2, + percent); +} + +// ----------------------------------------------------------------------------- + +static int WriteRiffHeader(const WebPPicture* const pic, size_t riff_size, + size_t vp8l_size) { + uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { + 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', + 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, + }; + PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); + PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size); + return pic->writer(riff, sizeof(riff), pic); +} + +static int WriteImageSize(const WebPPicture* const pic, + VP8LBitWriter* const bw) { + const int width = pic->width - 1; + const int height = pic->height - 1; + assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION); + + VP8LPutBits(bw, width, VP8L_IMAGE_SIZE_BITS); + VP8LPutBits(bw, height, VP8L_IMAGE_SIZE_BITS); + return !bw->error_; +} + +static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) { + VP8LPutBits(bw, has_alpha, 1); + VP8LPutBits(bw, VP8L_VERSION, VP8L_VERSION_BITS); + return !bw->error_; +} + +static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw, + size_t* const coded_size) { + const uint8_t* const webpll_data = VP8LBitWriterFinish(bw); + const size_t webpll_size = VP8LBitWriterNumBytes(bw); + const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size; + const size_t pad = vp8l_size & 1; + const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad; + *coded_size = 0; + + if (bw->error_) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + + if (!WriteRiffHeader(pic, riff_size, vp8l_size) || + !pic->writer(webpll_data, webpll_size, pic)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); + } + + if (pad) { + const uint8_t pad_byte[1] = { 0 }; + if (!pic->writer(pad_byte, 1, pic)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); + } + } + *coded_size = CHUNK_HEADER_SIZE + riff_size; + return 1; +} + +// ----------------------------------------------------------------------------- + +static void ClearTransformBuffer(VP8LEncoder* const enc) { + WebPSafeFree(enc->transform_mem_); + enc->transform_mem_ = NULL; + enc->transform_mem_size_ = 0; +} + +// Allocates the memory for argb (W x H) buffer, 2 rows of context for +// prediction and transform data. +// Flags influencing the memory allocated: +// enc->transform_bits_ +// enc->use_predict_, enc->use_cross_color_ +static int AllocateTransformBuffer(VP8LEncoder* const enc, int width, + int height) { + const uint64_t image_size = (uint64_t)width * height; + // VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra + // pixel in each, plus 2 regular scanlines of bytes. + // TODO(skal): Clean up by using arithmetic in bytes instead of words. + const uint64_t argb_scratch_size = + enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) / + sizeof(uint32_t) + : 0; + const uint64_t transform_data_size = + (enc->use_predict_ || enc->use_cross_color_) + ? (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) * + VP8LSubSampleSize(height, enc->transform_bits_) + : 0; + const uint64_t max_alignment_in_words = + (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t); + const uint64_t mem_size = image_size + max_alignment_in_words + + argb_scratch_size + max_alignment_in_words + + transform_data_size; + uint32_t* mem = enc->transform_mem_; + if (mem == NULL || mem_size > enc->transform_mem_size_) { + ClearTransformBuffer(enc); + mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem)); + if (mem == NULL) { + return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + enc->transform_mem_ = mem; + enc->transform_mem_size_ = (size_t)mem_size; + enc->argb_content_ = kEncoderNone; + } + enc->argb_ = mem; + mem = (uint32_t*)WEBP_ALIGN(mem + image_size); + enc->argb_scratch_ = mem; + mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size); + enc->transform_data_ = mem; + + enc->current_width_ = width; + return 1; +} + +static int MakeInputImageCopy(VP8LEncoder* const enc) { + const WebPPicture* const picture = enc->pic_; + const int width = picture->width; + const int height = picture->height; + + if (!AllocateTransformBuffer(enc, width, height)) return 0; + if (enc->argb_content_ == kEncoderARGB) return 1; + + { + uint32_t* dst = enc->argb_; + const uint32_t* src = picture->argb; + int y; + for (y = 0; y < height; ++y) { + memcpy(dst, src, width * sizeof(*dst)); + dst += width; + src += picture->argb_stride; + } + } + enc->argb_content_ = kEncoderARGB; + assert(enc->current_width_ == width); + return 1; +} + +// ----------------------------------------------------------------------------- + +#define APPLY_PALETTE_GREEDY_MAX 4 + +static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[], + int palette_size, + uint32_t color) { + (void)palette_size; + assert(palette_size < APPLY_PALETTE_GREEDY_MAX); + assert(3 == APPLY_PALETTE_GREEDY_MAX - 1); + if (color == palette[0]) return 0; + if (color == palette[1]) return 1; + if (color == palette[2]) return 2; + return 3; +} + +static WEBP_INLINE uint32_t ApplyPaletteHash0(uint32_t color) { + // Focus on the green color. + return (color >> 8) & 0xff; +} + +#define PALETTE_INV_SIZE_BITS 11 +#define PALETTE_INV_SIZE (1 << PALETTE_INV_SIZE_BITS) + +static WEBP_INLINE uint32_t ApplyPaletteHash1(uint32_t color) { + // Forget about alpha. + return ((uint32_t)((color & 0x00ffffffu) * 4222244071ull)) >> + (32 - PALETTE_INV_SIZE_BITS); +} + +static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) { + // Forget about alpha. + return ((uint32_t)((color & 0x00ffffffu) * ((1ull << 31) - 1))) >> + (32 - PALETTE_INV_SIZE_BITS); +} + +// Use 1 pixel cache for ARGB pixels. +#define APPLY_PALETTE_FOR(COLOR_INDEX) do { \ + uint32_t prev_pix = palette[0]; \ + uint32_t prev_idx = 0; \ + for (y = 0; y < height; ++y) { \ + for (x = 0; x < width; ++x) { \ + const uint32_t pix = src[x]; \ + if (pix != prev_pix) { \ + prev_idx = COLOR_INDEX; \ + prev_pix = pix; \ + } \ + tmp_row[x] = prev_idx; \ + } \ + VP8LBundleColorMap(tmp_row, width, xbits, dst); \ + src += src_stride; \ + dst += dst_stride; \ + } \ +} while (0) + +// Remap argb values in src[] to packed palettes entries in dst[] +// using 'row' as a temporary buffer of size 'width'. +// We assume that all src[] values have a corresponding entry in the palette. +// Note: src[] can be the same as dst[] +static int ApplyPalette(const uint32_t* src, uint32_t src_stride, uint32_t* dst, + uint32_t dst_stride, const uint32_t* palette, + int palette_size, int width, int height, int xbits, + const WebPPicture* const pic) { + // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be + // made to work in-place. + uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row)); + int x, y; + + if (tmp_row == NULL) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + + if (palette_size < APPLY_PALETTE_GREEDY_MAX) { + APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix)); + } else { + int i, j; + uint16_t buffer[PALETTE_INV_SIZE]; + uint32_t (*const hash_functions[])(uint32_t) = { + ApplyPaletteHash0, ApplyPaletteHash1, ApplyPaletteHash2 + }; + + // Try to find a perfect hash function able to go from a color to an index + // within 1 << PALETTE_INV_SIZE_BITS in order to build a hash map to go + // from color to index in palette. + for (i = 0; i < 3; ++i) { + int use_LUT = 1; + // Set each element in buffer to max uint16_t. + memset(buffer, 0xff, sizeof(buffer)); + for (j = 0; j < palette_size; ++j) { + const uint32_t ind = hash_functions[i](palette[j]); + if (buffer[ind] != 0xffffu) { + use_LUT = 0; + break; + } else { + buffer[ind] = j; + } + } + if (use_LUT) break; + } + + if (i == 0) { + APPLY_PALETTE_FOR(buffer[ApplyPaletteHash0(pix)]); + } else if (i == 1) { + APPLY_PALETTE_FOR(buffer[ApplyPaletteHash1(pix)]); + } else if (i == 2) { + APPLY_PALETTE_FOR(buffer[ApplyPaletteHash2(pix)]); + } else { + uint32_t idx_map[MAX_PALETTE_SIZE]; + uint32_t palette_sorted[MAX_PALETTE_SIZE]; + PrepareMapToPalette(palette, palette_size, palette_sorted, idx_map); + APPLY_PALETTE_FOR( + idx_map[SearchColorNoIdx(palette_sorted, pix, palette_size)]); + } + } + WebPSafeFree(tmp_row); + return 1; +} +#undef APPLY_PALETTE_FOR +#undef PALETTE_INV_SIZE_BITS +#undef PALETTE_INV_SIZE +#undef APPLY_PALETTE_GREEDY_MAX + +// Note: Expects "enc->palette_" to be set properly. +static int MapImageFromPalette(VP8LEncoder* const enc, int in_place) { + const WebPPicture* const pic = enc->pic_; + const int width = pic->width; + const int height = pic->height; + const uint32_t* const palette = enc->palette_; + const uint32_t* src = in_place ? enc->argb_ : pic->argb; + const int src_stride = in_place ? enc->current_width_ : pic->argb_stride; + const int palette_size = enc->palette_size_; + int xbits; + + // Replace each input pixel by corresponding palette index. + // This is done line by line. + if (palette_size <= 4) { + xbits = (palette_size <= 2) ? 3 : 2; + } else { + xbits = (palette_size <= 16) ? 1 : 0; + } + + if (!AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height)) { + return 0; + } + if (!ApplyPalette(src, src_stride, + enc->argb_, enc->current_width_, + palette, palette_size, width, height, xbits, pic)) { + return 0; + } + enc->argb_content_ = kEncoderPalette; + return 1; +} + +// Save palette_[] to bitstream. +static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort, + VP8LEncoder* const enc, + int percent_range, int* const percent) { + int i; + uint32_t tmp_palette[MAX_PALETTE_SIZE]; + const int palette_size = enc->palette_size_; + const uint32_t* const palette = enc->palette_; + VP8LPutBits(bw, TRANSFORM_PRESENT, 1); + VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2); + assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE); + VP8LPutBits(bw, palette_size - 1, 8); + for (i = palette_size - 1; i >= 1; --i) { + tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]); + } + tmp_palette[0] = palette[0]; + return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, + &enc->refs_[0], palette_size, 1, /*quality=*/20, + low_effort, enc->pic_, percent_range, percent); +} + +// ----------------------------------------------------------------------------- +// VP8LEncoder + +static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, + const WebPPicture* const picture) { + VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc)); + if (enc == NULL) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + return NULL; + } + enc->config_ = config; + enc->pic_ = picture; + enc->argb_content_ = kEncoderNone; + + VP8LEncDspInit(); + + return enc; +} + +static void VP8LEncoderDelete(VP8LEncoder* enc) { + if (enc != NULL) { + int i; + VP8LHashChainClear(&enc->hash_chain_); + for (i = 0; i < 4; ++i) VP8LBackwardRefsClear(&enc->refs_[i]); + ClearTransformBuffer(enc); + WebPSafeFree(enc); + } +} + +// ----------------------------------------------------------------------------- +// Main call + +typedef struct { + const WebPConfig* config_; + const WebPPicture* picture_; + VP8LBitWriter* bw_; + VP8LEncoder* enc_; + CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX]; + int num_crunch_configs_; + int red_and_blue_always_zero_; + WebPAuxStats* stats_; +} StreamEncodeContext; + +static int EncodeStreamHook(void* input, void* data2) { + StreamEncodeContext* const params = (StreamEncodeContext*)input; + const WebPConfig* const config = params->config_; + const WebPPicture* const picture = params->picture_; + VP8LBitWriter* const bw = params->bw_; + VP8LEncoder* const enc = params->enc_; + const CrunchConfig* const crunch_configs = params->crunch_configs_; + const int num_crunch_configs = params->num_crunch_configs_; + const int red_and_blue_always_zero = params->red_and_blue_always_zero_; +#if !defined(WEBP_DISABLE_STATS) + WebPAuxStats* const stats = params->stats_; +#endif + const int quality = (int)config->quality; + const int low_effort = (config->method == 0); +#if (WEBP_NEAR_LOSSLESS == 1) + const int width = picture->width; +#endif + const int height = picture->height; + const size_t byte_position = VP8LBitWriterNumBytes(bw); + int percent = 2; // for WebPProgressHook +#if (WEBP_NEAR_LOSSLESS == 1) + int use_near_lossless = 0; +#endif + int hdr_size = 0; + int data_size = 0; + int use_delta_palette = 0; + int idx; + size_t best_size = ~(size_t)0; + VP8LBitWriter bw_init = *bw, bw_best; + (void)data2; + + if (!VP8LBitWriterInit(&bw_best, 0) || + (num_crunch_configs > 1 && !VP8LBitWriterClone(bw, &bw_best))) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + for (idx = 0; idx < num_crunch_configs; ++idx) { + const int entropy_idx = crunch_configs[idx].entropy_idx_; + int remaining_percent = 97 / num_crunch_configs, percent_range; + enc->use_palette_ = + (entropy_idx == kPalette) || (entropy_idx == kPaletteAndSpatial); + enc->use_subtract_green_ = + (entropy_idx == kSubGreen) || (entropy_idx == kSpatialSubGreen); + enc->use_predict_ = (entropy_idx == kSpatial) || + (entropy_idx == kSpatialSubGreen) || + (entropy_idx == kPaletteAndSpatial); + // When using a palette, R/B==0, hence no need to test for cross-color. + if (low_effort || enc->use_palette_) { + enc->use_cross_color_ = 0; + } else { + enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_; + } + // Reset any parameter in the encoder that is set in the previous iteration. + enc->cache_bits_ = 0; + VP8LBackwardRefsClear(&enc->refs_[0]); + VP8LBackwardRefsClear(&enc->refs_[1]); + +#if (WEBP_NEAR_LOSSLESS == 1) + // Apply near-lossless preprocessing. + use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ && + !enc->use_predict_; + if (use_near_lossless) { + if (!AllocateTransformBuffer(enc, width, height)) goto Error; + if ((enc->argb_content_ != kEncoderNearLossless) && + !VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + enc->argb_content_ = kEncoderNearLossless; + } else { + enc->argb_content_ = kEncoderNone; + } +#else + enc->argb_content_ = kEncoderNone; +#endif + + // Encode palette + if (enc->use_palette_) { + if (!PaletteSort(crunch_configs[idx].palette_sorting_type_, enc->pic_, + enc->palette_sorted_, enc->palette_size_, + enc->palette_)) { + WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + percent_range = remaining_percent / 4; + if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) { + goto Error; + } + remaining_percent -= percent_range; + if (!MapImageFromPalette(enc, use_delta_palette)) goto Error; + // If using a color cache, do not have it bigger than the number of + // colors. + if (enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { + enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1; + } + } + if (!use_delta_palette) { + // In case image is not packed. + if (enc->argb_content_ != kEncoderNearLossless && + enc->argb_content_ != kEncoderPalette) { + if (!MakeInputImageCopy(enc)) goto Error; + } + + // ----------------------------------------------------------------------- + // Apply transforms and write transform data. + + if (enc->use_subtract_green_) { + ApplySubtractGreen(enc, enc->current_width_, height, bw); + } + + if (enc->use_predict_) { + percent_range = remaining_percent / 3; + if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, + low_effort, enc->use_subtract_green_, bw, + percent_range, &percent)) { + goto Error; + } + remaining_percent -= percent_range; + } + + if (enc->use_cross_color_) { + percent_range = remaining_percent / 2; + if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, + low_effort, bw, percent_range, &percent)) { + goto Error; + } + remaining_percent -= percent_range; + } + } + + VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms. + + // ------------------------------------------------------------------------- + // Encode and write the transformed image. + if (!EncodeImageInternal( + bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_, + height, quality, low_effort, &crunch_configs[idx], + &enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size, + &data_size, picture, remaining_percent, &percent)) { + goto Error; + } + + // If we are better than what we already have. + if (VP8LBitWriterNumBytes(bw) < best_size) { + best_size = VP8LBitWriterNumBytes(bw); + // Store the BitWriter. + VP8LBitWriterSwap(bw, &bw_best); +#if !defined(WEBP_DISABLE_STATS) + // Update the stats. + if (stats != NULL) { + stats->lossless_features = 0; + if (enc->use_predict_) stats->lossless_features |= 1; + if (enc->use_cross_color_) stats->lossless_features |= 2; + if (enc->use_subtract_green_) stats->lossless_features |= 4; + if (enc->use_palette_) stats->lossless_features |= 8; + stats->histogram_bits = enc->histo_bits_; + stats->transform_bits = enc->transform_bits_; + stats->cache_bits = enc->cache_bits_; + stats->palette_size = enc->palette_size_; + stats->lossless_size = (int)(best_size - byte_position); + stats->lossless_hdr_size = hdr_size; + stats->lossless_data_size = data_size; + } +#endif + } + // Reset the bit writer for the following iteration if any. + if (num_crunch_configs > 1) VP8LBitWriterReset(&bw_init, bw); + } + VP8LBitWriterSwap(&bw_best, bw); + + Error: + VP8LBitWriterWipeOut(&bw_best); + // The hook should return false in case of error. + return (params->picture_->error_code == VP8_ENC_OK); +} + +int VP8LEncodeStream(const WebPConfig* const config, + const WebPPicture* const picture, + VP8LBitWriter* const bw_main) { + VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture); + VP8LEncoder* enc_side = NULL; + CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX]; + int num_crunch_configs_main, num_crunch_configs_side = 0; + int idx; + int red_and_blue_always_zero = 0; + WebPWorker worker_main, worker_side; + StreamEncodeContext params_main, params_side; + // The main thread uses picture->stats, the side thread uses stats_side. + WebPAuxStats stats_side; + VP8LBitWriter bw_side; + WebPPicture picture_side; + const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface(); + int ok_main; + + if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) { + VP8LEncoderDelete(enc_main); + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + + // Avoid "garbage value" error from Clang's static analysis tool. + if (!WebPPictureInit(&picture_side)) { + goto Error; + } + + // Analyze image (entropy, num_palettes etc) + if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, + &red_and_blue_always_zero) || + !EncoderInit(enc_main)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + // Split the configs between the main and side threads (if any). + if (config->thread_level > 0) { + num_crunch_configs_side = num_crunch_configs_main / 2; + for (idx = 0; idx < num_crunch_configs_side; ++idx) { + params_side.crunch_configs_[idx] = + crunch_configs[num_crunch_configs_main - num_crunch_configs_side + + idx]; + } + params_side.num_crunch_configs_ = num_crunch_configs_side; + } + num_crunch_configs_main -= num_crunch_configs_side; + for (idx = 0; idx < num_crunch_configs_main; ++idx) { + params_main.crunch_configs_[idx] = crunch_configs[idx]; + } + params_main.num_crunch_configs_ = num_crunch_configs_main; + + // Fill in the parameters for the thread workers. + { + const int params_size = (num_crunch_configs_side > 0) ? 2 : 1; + for (idx = 0; idx < params_size; ++idx) { + // Create the parameters for each worker. + WebPWorker* const worker = (idx == 0) ? &worker_main : &worker_side; + StreamEncodeContext* const param = + (idx == 0) ? ¶ms_main : ¶ms_side; + param->config_ = config; + param->red_and_blue_always_zero_ = red_and_blue_always_zero; + if (idx == 0) { + param->picture_ = picture; + param->stats_ = picture->stats; + param->bw_ = bw_main; + param->enc_ = enc_main; + } else { + // Create a side picture (error_code is not thread-safe). + if (!WebPPictureView(picture, /*left=*/0, /*top=*/0, picture->width, + picture->height, &picture_side)) { + assert(0); + } + picture_side.progress_hook = NULL; // Progress hook is not thread-safe. + param->picture_ = &picture_side; // No need to free a view afterwards. + param->stats_ = (picture->stats == NULL) ? NULL : &stats_side; + // Create a side bit writer. + if (!VP8LBitWriterClone(bw_main, &bw_side)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + param->bw_ = &bw_side; + // Create a side encoder. + enc_side = VP8LEncoderNew(config, &picture_side); + if (enc_side == NULL || !EncoderInit(enc_side)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + // Copy the values that were computed for the main encoder. + enc_side->histo_bits_ = enc_main->histo_bits_; + enc_side->transform_bits_ = enc_main->transform_bits_; + enc_side->palette_size_ = enc_main->palette_size_; + memcpy(enc_side->palette_, enc_main->palette_, + sizeof(enc_main->palette_)); + memcpy(enc_side->palette_sorted_, enc_main->palette_sorted_, + sizeof(enc_main->palette_sorted_)); + param->enc_ = enc_side; + } + // Create the workers. + worker_interface->Init(worker); + worker->data1 = param; + worker->data2 = NULL; + worker->hook = EncodeStreamHook; + } + } + + // Start the second thread if needed. + if (num_crunch_configs_side != 0) { + if (!worker_interface->Reset(&worker_side)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } +#if !defined(WEBP_DISABLE_STATS) + // This line is here and not in the param initialization above to remove a + // Clang static analyzer warning. + if (picture->stats != NULL) { + memcpy(&stats_side, picture->stats, sizeof(stats_side)); + } +#endif + worker_interface->Launch(&worker_side); + } + // Execute the main thread. + worker_interface->Execute(&worker_main); + ok_main = worker_interface->Sync(&worker_main); + worker_interface->End(&worker_main); + if (num_crunch_configs_side != 0) { + // Wait for the second thread. + const int ok_side = worker_interface->Sync(&worker_side); + worker_interface->End(&worker_side); + if (!ok_main || !ok_side) { + if (picture->error_code == VP8_ENC_OK) { + assert(picture_side.error_code != VP8_ENC_OK); + WebPEncodingSetError(picture, picture_side.error_code); + } + goto Error; + } + if (VP8LBitWriterNumBytes(&bw_side) < VP8LBitWriterNumBytes(bw_main)) { + VP8LBitWriterSwap(bw_main, &bw_side); +#if !defined(WEBP_DISABLE_STATS) + if (picture->stats != NULL) { + memcpy(picture->stats, &stats_side, sizeof(*picture->stats)); + } +#endif + } + } + + Error: + VP8LBitWriterWipeOut(&bw_side); + VP8LEncoderDelete(enc_main); + VP8LEncoderDelete(enc_side); + return (picture->error_code == VP8_ENC_OK); +} + +#undef CRUNCH_CONFIGS_MAX +#undef CRUNCH_SUBCONFIGS_MAX + +int VP8LEncodeImage(const WebPConfig* const config, + const WebPPicture* const picture) { + int width, height; + int has_alpha; + size_t coded_size; + int percent = 0; + int initial_size; + VP8LBitWriter bw; + + if (picture == NULL) return 0; + + if (config == NULL || picture->argb == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); + } + + width = picture->width; + height = picture->height; + // Initialize BitWriter with size corresponding to 16 bpp to photo images and + // 8 bpp for graphical images. + initial_size = (config->image_hint == WEBP_HINT_GRAPH) ? + width * height : width * height * 2; + if (!VP8LBitWriterInit(&bw, initial_size)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + if (!WebPReportProgress(picture, 1, &percent)) { + UserAbort: + WebPEncodingSetError(picture, VP8_ENC_ERROR_USER_ABORT); + goto Error; + } + // Reset stats (for pure lossless coding) + if (picture->stats != NULL) { + WebPAuxStats* const stats = picture->stats; + memset(stats, 0, sizeof(*stats)); + stats->PSNR[0] = 99.f; + stats->PSNR[1] = 99.f; + stats->PSNR[2] = 99.f; + stats->PSNR[3] = 99.f; + stats->PSNR[4] = 99.f; + } + + // Write image size. + if (!WriteImageSize(picture, &bw)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + has_alpha = WebPPictureHasTransparency(picture); + // Write the non-trivial Alpha flag and lossless version. + if (!WriteRealAlphaAndVersion(&bw, has_alpha)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort; + + // Encode main image stream. + if (!VP8LEncodeStream(config, picture, &bw)) goto Error; + + if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort; + + // Finish the RIFF chunk. + if (!WriteImage(picture, &bw, &coded_size)) goto Error; + + if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort; + +#if !defined(WEBP_DISABLE_STATS) + // Save size. + if (picture->stats != NULL) { + picture->stats->coded_size += (int)coded_size; + picture->stats->lossless_size = (int)coded_size; + } +#endif + + if (picture->extra_info != NULL) { + const int mb_w = (width + 15) >> 4; + const int mb_h = (height + 15) >> 4; + memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info)); + } + + Error: + if (bw.error_) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + VP8LBitWriterWipeOut(&bw); + return (picture->error_code == VP8_ENC_OK); +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/enc/vp8li_enc.h b/libraries/webp/src/enc/vp8li_enc.h new file mode 100644 index 00000000000..09032ecc77a --- /dev/null +++ b/libraries/webp/src/enc/vp8li_enc.h @@ -0,0 +1,124 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Lossless encoder: internal header. +// +// Author: Vikas Arora (vikaas.arora@gmail.com) + +#ifndef WEBP_ENC_VP8LI_ENC_H_ +#define WEBP_ENC_VP8LI_ENC_H_ + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif +// Either WEBP_NEAR_LOSSLESS is defined as 0 in config.h when compiling to +// disable near-lossless, or it is enabled by default. +#ifndef WEBP_NEAR_LOSSLESS +#define WEBP_NEAR_LOSSLESS 1 +#endif + +#include "src/enc/backward_references_enc.h" +#include "src/enc/histogram_enc.h" +#include "src/utils/bit_writer_utils.h" +#include "include/webp/encode.h" +#include "include/webp/format_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// maximum value of transform_bits_ in VP8LEncoder. +#define MAX_TRANSFORM_BITS 6 + +typedef enum { + kEncoderNone = 0, + kEncoderARGB, + kEncoderNearLossless, + kEncoderPalette +} VP8LEncoderARGBContent; + +typedef struct { + const WebPConfig* config_; // user configuration and parameters + const WebPPicture* pic_; // input picture. + + uint32_t* argb_; // Transformed argb image data. + VP8LEncoderARGBContent argb_content_; // Content type of the argb buffer. + uint32_t* argb_scratch_; // Scratch memory for argb rows + // (used for prediction). + uint32_t* transform_data_; // Scratch memory for transform data. + uint32_t* transform_mem_; // Currently allocated memory. + size_t transform_mem_size_; // Currently allocated memory size. + + int current_width_; // Corresponds to packed image width. + + // Encoding parameters derived from quality parameter. + int histo_bits_; + int transform_bits_; // <= MAX_TRANSFORM_BITS. + int cache_bits_; // If equal to 0, don't use color cache. + + // Encoding parameters derived from image characteristics. + int use_cross_color_; + int use_subtract_green_; + int use_predict_; + int use_palette_; + int palette_size_; + uint32_t palette_[MAX_PALETTE_SIZE]; + // Sorted version of palette_ for cache purposes. + uint32_t palette_sorted_[MAX_PALETTE_SIZE]; + + // Some 'scratch' (potentially large) objects. + struct VP8LBackwardRefs refs_[4]; // Backward Refs array for temporaries. + VP8LHashChain hash_chain_; // HashChain data for constructing + // backward references. +} VP8LEncoder; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + +// Encodes the picture. +// Returns 0 if config or picture is NULL or picture doesn't have valid argb +// input. +int VP8LEncodeImage(const WebPConfig* const config, + const WebPPicture* const picture); + +// Encodes the main image stream using the supplied bit writer. +// Returns false in case of error (stored in picture->error_code). +int VP8LEncodeStream(const WebPConfig* const config, + const WebPPicture* const picture, VP8LBitWriter* const bw); + +#if (WEBP_NEAR_LOSSLESS == 1) +// in near_lossless.c +// Near lossless preprocessing in RGB color-space. +int VP8ApplyNearLossless(const WebPPicture* const picture, int quality, + uint32_t* const argb_dst); +#endif + +//------------------------------------------------------------------------------ +// Image transforms in predictor.c. + +// pic and percent are for progress. +// Returns false in case of error (stored in pic->error_code). +int VP8LResidualImage(int width, int height, int bits, int low_effort, + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image, int near_lossless, int exact, + int used_subtract_green, const WebPPicture* const pic, + int percent_range, int* const percent); + +int VP8LColorSpaceTransform(int width, int height, int bits, int quality, + uint32_t* const argb, uint32_t* image, + const WebPPicture* const pic, int percent_range, + int* const percent); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_ENC_VP8LI_ENC_H_ diff --git a/libraries/webp/src/enc/webp_enc.c b/libraries/webp/src/enc/webp_enc.c new file mode 100644 index 00000000000..583fe6a8bbd --- /dev/null +++ b/libraries/webp/src/enc/webp_enc.c @@ -0,0 +1,410 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// WebP encoder: main entry point +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include +#include + +#include "src/enc/cost_enc.h" +#include "src/enc/vp8i_enc.h" +#include "src/enc/vp8li_enc.h" +#include "src/utils/utils.h" + +// #define PRINT_MEMORY_INFO + +#ifdef PRINT_MEMORY_INFO +#include +#endif + +//------------------------------------------------------------------------------ + +int WebPGetEncoderVersion(void) { + return (ENC_MAJ_VERSION << 16) | (ENC_MIN_VERSION << 8) | ENC_REV_VERSION; +} + +//------------------------------------------------------------------------------ +// VP8Encoder +//------------------------------------------------------------------------------ + +static void ResetSegmentHeader(VP8Encoder* const enc) { + VP8EncSegmentHeader* const hdr = &enc->segment_hdr_; + hdr->num_segments_ = enc->config_->segments; + hdr->update_map_ = (hdr->num_segments_ > 1); + hdr->size_ = 0; +} + +static void ResetFilterHeader(VP8Encoder* const enc) { + VP8EncFilterHeader* const hdr = &enc->filter_hdr_; + hdr->simple_ = 1; + hdr->level_ = 0; + hdr->sharpness_ = 0; + hdr->i4x4_lf_delta_ = 0; +} + +static void ResetBoundaryPredictions(VP8Encoder* const enc) { + // init boundary values once for all + // Note: actually, initializing the preds_[] is only needed for intra4. + int i; + uint8_t* const top = enc->preds_ - enc->preds_w_; + uint8_t* const left = enc->preds_ - 1; + for (i = -1; i < 4 * enc->mb_w_; ++i) { + top[i] = B_DC_PRED; + } + for (i = 0; i < 4 * enc->mb_h_; ++i) { + left[i * enc->preds_w_] = B_DC_PRED; + } + enc->nz_[-1] = 0; // constant +} + +// Mapping from config->method_ to coding tools used. +//-------------------+---+---+---+---+---+---+---+ +// Method | 0 | 1 | 2 | 3 |(4)| 5 | 6 | +//-------------------+---+---+---+---+---+---+---+ +// fast probe | x | | | x | | | | +//-------------------+---+---+---+---+---+---+---+ +// dynamic proba | ~ | x | x | x | x | x | x | +//-------------------+---+---+---+---+---+---+---+ +// fast mode analysis|[x]|[x]| | | x | x | x | +//-------------------+---+---+---+---+---+---+---+ +// basic rd-opt | | | | x | x | x | x | +//-------------------+---+---+---+---+---+---+---+ +// disto-refine i4/16| x | x | x | | | | | +//-------------------+---+---+---+---+---+---+---+ +// disto-refine uv | | x | x | | | | | +//-------------------+---+---+---+---+---+---+---+ +// rd-opt i4/16 | | | ~ | x | x | x | x | +//-------------------+---+---+---+---+---+---+---+ +// token buffer (opt)| | | | x | x | x | x | +//-------------------+---+---+---+---+---+---+---+ +// Trellis | | | | | | x |Ful| +//-------------------+---+---+---+---+---+---+---+ +// full-SNS | | | | | x | x | x | +//-------------------+---+---+---+---+---+---+---+ + +static void MapConfigToTools(VP8Encoder* const enc) { + const WebPConfig* const config = enc->config_; + const int method = config->method; + const int limit = 100 - config->partition_limit; + enc->method_ = method; + enc->rd_opt_level_ = (method >= 6) ? RD_OPT_TRELLIS_ALL + : (method >= 5) ? RD_OPT_TRELLIS + : (method >= 3) ? RD_OPT_BASIC + : RD_OPT_NONE; + enc->max_i4_header_bits_ = + 256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block + (limit * limit) / (100 * 100); // ... modulated with a quadratic curve. + + // partition0 = 512k max. + enc->mb_header_limit_ = + (score_t)256 * 510 * 8 * 1024 / (enc->mb_w_ * enc->mb_h_); + + enc->thread_level_ = config->thread_level; + + enc->do_search_ = (config->target_size > 0 || config->target_PSNR > 0); + if (!config->low_memory) { +#if !defined(DISABLE_TOKEN_BUFFER) + enc->use_tokens_ = (enc->rd_opt_level_ >= RD_OPT_BASIC); // need rd stats +#endif + if (enc->use_tokens_) { + enc->num_parts_ = 1; // doesn't work with multi-partition + } + } +} + +// Memory scaling with dimensions: +// memory (bytes) ~= 2.25 * w + 0.0625 * w * h +// +// Typical memory footprint (614x440 picture) +// encoder: 22111 +// info: 4368 +// preds: 17741 +// top samples: 1263 +// non-zero: 175 +// lf-stats: 0 +// total: 45658 +// Transient object sizes: +// VP8EncIterator: 3360 +// VP8ModeScore: 872 +// VP8SegmentInfo: 732 +// VP8EncProba: 18352 +// LFStats: 2048 +// Picture size (yuv): 419328 + +static VP8Encoder* InitVP8Encoder(const WebPConfig* const config, + WebPPicture* const picture) { + VP8Encoder* enc; + const int use_filter = + (config->filter_strength > 0) || (config->autofilter > 0); + const int mb_w = (picture->width + 15) >> 4; + const int mb_h = (picture->height + 15) >> 4; + const int preds_w = 4 * mb_w + 1; + const int preds_h = 4 * mb_h + 1; + const size_t preds_size = preds_w * preds_h * sizeof(*enc->preds_); + const int top_stride = mb_w * 16; + const size_t nz_size = (mb_w + 1) * sizeof(*enc->nz_) + WEBP_ALIGN_CST; + const size_t info_size = mb_w * mb_h * sizeof(*enc->mb_info_); + const size_t samples_size = + 2 * top_stride * sizeof(*enc->y_top_) // top-luma/u/v + + WEBP_ALIGN_CST; // align all + const size_t lf_stats_size = + config->autofilter ? sizeof(*enc->lf_stats_) + WEBP_ALIGN_CST : 0; + const size_t top_derr_size = + (config->quality <= ERROR_DIFFUSION_QUALITY || config->pass > 1) ? + mb_w * sizeof(*enc->top_derr_) : 0; + uint8_t* mem; + const uint64_t size = (uint64_t)sizeof(*enc) // main struct + + WEBP_ALIGN_CST // cache alignment + + info_size // modes info + + preds_size // prediction modes + + samples_size // top/left samples + + top_derr_size // top diffusion error + + nz_size // coeff context bits + + lf_stats_size; // autofilter stats + +#ifdef PRINT_MEMORY_INFO + printf("===================================\n"); + printf("Memory used:\n" + " encoder: %ld\n" + " info: %ld\n" + " preds: %ld\n" + " top samples: %ld\n" + " top diffusion: %ld\n" + " non-zero: %ld\n" + " lf-stats: %ld\n" + " total: %ld\n", + sizeof(*enc) + WEBP_ALIGN_CST, info_size, + preds_size, samples_size, top_derr_size, nz_size, lf_stats_size, size); + printf("Transient object sizes:\n" + " VP8EncIterator: %ld\n" + " VP8ModeScore: %ld\n" + " VP8SegmentInfo: %ld\n" + " VP8EncProba: %ld\n" + " LFStats: %ld\n", + sizeof(VP8EncIterator), sizeof(VP8ModeScore), + sizeof(VP8SegmentInfo), sizeof(VP8EncProba), + sizeof(LFStats)); + printf("Picture size (yuv): %ld\n", + mb_w * mb_h * 384 * sizeof(uint8_t)); + printf("===================================\n"); +#endif + mem = (uint8_t*)WebPSafeMalloc(size, sizeof(*mem)); + if (mem == NULL) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + return NULL; + } + enc = (VP8Encoder*)mem; + mem = (uint8_t*)WEBP_ALIGN(mem + sizeof(*enc)); + memset(enc, 0, sizeof(*enc)); + enc->num_parts_ = 1 << config->partitions; + enc->mb_w_ = mb_w; + enc->mb_h_ = mb_h; + enc->preds_w_ = preds_w; + enc->mb_info_ = (VP8MBInfo*)mem; + mem += info_size; + enc->preds_ = mem + 1 + enc->preds_w_; + mem += preds_size; + enc->nz_ = 1 + (uint32_t*)WEBP_ALIGN(mem); + mem += nz_size; + enc->lf_stats_ = lf_stats_size ? (LFStats*)WEBP_ALIGN(mem) : NULL; + mem += lf_stats_size; + + // top samples (all 16-aligned) + mem = (uint8_t*)WEBP_ALIGN(mem); + enc->y_top_ = mem; + enc->uv_top_ = enc->y_top_ + top_stride; + mem += 2 * top_stride; + enc->top_derr_ = top_derr_size ? (DError*)mem : NULL; + mem += top_derr_size; + assert(mem <= (uint8_t*)enc + size); + + enc->config_ = config; + enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2; + enc->pic_ = picture; + enc->percent_ = 0; + + MapConfigToTools(enc); + VP8EncDspInit(); + VP8DefaultProbas(enc); + ResetSegmentHeader(enc); + ResetFilterHeader(enc); + ResetBoundaryPredictions(enc); + VP8EncDspCostInit(); + VP8EncInitAlpha(enc); + + // lower quality means smaller output -> we modulate a little the page + // size based on quality. This is just a crude 1rst-order prediction. + { + const float scale = 1.f + config->quality * 5.f / 100.f; // in [1,6] + VP8TBufferInit(&enc->tokens_, (int)(mb_w * mb_h * 4 * scale)); + } + return enc; +} + +static int DeleteVP8Encoder(VP8Encoder* enc) { + int ok = 1; + if (enc != NULL) { + ok = VP8EncDeleteAlpha(enc); + VP8TBufferClear(&enc->tokens_); + WebPSafeFree(enc); + } + return ok; +} + +//------------------------------------------------------------------------------ + +#if !defined(WEBP_DISABLE_STATS) +static double GetPSNR(uint64_t err, uint64_t size) { + return (err > 0 && size > 0) ? 10. * log10(255. * 255. * size / err) : 99.; +} + +static void FinalizePSNR(const VP8Encoder* const enc) { + WebPAuxStats* stats = enc->pic_->stats; + const uint64_t size = enc->sse_count_; + const uint64_t* const sse = enc->sse_; + stats->PSNR[0] = (float)GetPSNR(sse[0], size); + stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4); + stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4); + stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2); + stats->PSNR[4] = (float)GetPSNR(sse[3], size); +} +#endif // !defined(WEBP_DISABLE_STATS) + +static void StoreStats(VP8Encoder* const enc) { +#if !defined(WEBP_DISABLE_STATS) + WebPAuxStats* const stats = enc->pic_->stats; + if (stats != NULL) { + int i, s; + for (i = 0; i < NUM_MB_SEGMENTS; ++i) { + stats->segment_level[i] = enc->dqm_[i].fstrength_; + stats->segment_quant[i] = enc->dqm_[i].quant_; + for (s = 0; s <= 2; ++s) { + stats->residual_bytes[s][i] = enc->residual_bytes_[s][i]; + } + } + FinalizePSNR(enc); + stats->coded_size = enc->coded_size_; + for (i = 0; i < 3; ++i) { + stats->block_count[i] = enc->block_count_[i]; + } + } +#else // defined(WEBP_DISABLE_STATS) + WebPReportProgress(enc->pic_, 100, &enc->percent_); // done! +#endif // !defined(WEBP_DISABLE_STATS) +} + +int WebPEncodingSetError(const WebPPicture* const pic, + WebPEncodingError error) { + assert((int)error < VP8_ENC_ERROR_LAST); + assert((int)error >= VP8_ENC_OK); + // The oldest error reported takes precedence over the new one. + if (pic->error_code == VP8_ENC_OK) { + ((WebPPicture*)pic)->error_code = error; + } + return 0; +} + +int WebPReportProgress(const WebPPicture* const pic, + int percent, int* const percent_store) { + if (percent_store != NULL && percent != *percent_store) { + *percent_store = percent; + if (pic->progress_hook && !pic->progress_hook(percent, pic)) { + // user abort requested + return WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT); + } + } + return 1; // ok +} +//------------------------------------------------------------------------------ + +int WebPEncode(const WebPConfig* config, WebPPicture* pic) { + int ok = 0; + if (pic == NULL) return 0; + + pic->error_code = VP8_ENC_OK; // all ok so far + if (config == NULL) { // bad params + return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); + } + if (!WebPValidateConfig(config)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); + } + if (!WebPValidatePicture(pic)) return 0; + if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); + } + + if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats)); + + if (!config->lossless) { + VP8Encoder* enc = NULL; + + if (pic->use_argb || pic->y == NULL || pic->u == NULL || pic->v == NULL) { + // Make sure we have YUVA samples. + if (config->use_sharp_yuv || (config->preprocessing & 4)) { + if (!WebPPictureSharpARGBToYUVA(pic)) { + return 0; + } + } else { + float dithering = 0.f; + if (config->preprocessing & 2) { + const float x = config->quality / 100.f; + const float x2 = x * x; + // slowly decreasing from max dithering at low quality (q->0) + // to 0.5 dithering amplitude at high quality (q->100) + dithering = 1.0f + (0.5f - 1.0f) * x2 * x2; + } + if (!WebPPictureARGBToYUVADithered(pic, WEBP_YUV420, dithering)) { + return 0; + } + } + } + + if (!config->exact) { + WebPCleanupTransparentArea(pic); + } + + enc = InitVP8Encoder(config, pic); + if (enc == NULL) return 0; // pic->error is already set. + // Note: each of the tasks below account for 20% in the progress report. + ok = VP8EncAnalyze(enc); + + // Analysis is done, proceed to actual coding. + ok = ok && VP8EncStartAlpha(enc); // possibly done in parallel + if (!enc->use_tokens_) { + ok = ok && VP8EncLoop(enc); + } else { + ok = ok && VP8EncTokenLoop(enc); + } + ok = ok && VP8EncFinishAlpha(enc); + + ok = ok && VP8EncWrite(enc); + StoreStats(enc); + if (!ok) { + VP8EncFreeBitWriters(enc); + } + ok &= DeleteVP8Encoder(enc); // must always be called, even if !ok + } else { + // Make sure we have ARGB samples. + if (pic->argb == NULL && !WebPPictureYUVAToARGB(pic)) { + return 0; + } + + if (!config->exact) { + WebPReplaceTransparentPixels(pic, 0x000000); + } + + ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem. + } + + return ok; +} diff --git a/libraries/webp/src/mux/anim_encode.c b/libraries/webp/src/mux/anim_encode.c new file mode 100644 index 00000000000..46d30e4e44e --- /dev/null +++ b/libraries/webp/src/mux/anim_encode.c @@ -0,0 +1,1611 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// AnimEncoder implementation. +// + +#include +#include +#include // for pow() +#include +#include // for abs() + +#include "src/mux/animi.h" +#include "src/utils/utils.h" +#include "include/webp/decode.h" +#include "include/webp/encode.h" +#include "include/webp/format_constants.h" +#include "include/webp/mux.h" +#include "include/webp/types.h" + +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif + +#define ERROR_STR_MAX_LENGTH 100 + +//------------------------------------------------------------------------------ +// Internal structs. + +// Stores frame rectangle dimensions. +typedef struct { + int x_offset_, y_offset_, width_, height_; +} FrameRectangle; + +// Used to store two candidates of encoded data for an animation frame. One of +// the two will be chosen later. +typedef struct { + WebPMuxFrameInfo sub_frame_; // Encoded frame rectangle. + WebPMuxFrameInfo key_frame_; // Encoded frame if it is a key-frame. + int is_key_frame_; // True if 'key_frame' has been chosen. +} EncodedFrame; + +struct WebPAnimEncoder { + const int canvas_width_; // Canvas width. + const int canvas_height_; // Canvas height. + const WebPAnimEncoderOptions options_; // Global encoding options. + + FrameRectangle prev_rect_; // Previous WebP frame rectangle. + WebPConfig last_config_; // Cached in case a re-encode is needed. + WebPConfig last_config_reversed_; // If 'last_config_' uses lossless, then + // this config uses lossy and vice versa; + // only valid if 'options_.allow_mixed' + // is true. + + WebPPicture* curr_canvas_; // Only pointer; we don't own memory. + + // Canvas buffers. + WebPPicture curr_canvas_copy_; // Possibly modified current canvas. + int curr_canvas_copy_modified_; // True if pixels in 'curr_canvas_copy_' + // differ from those in 'curr_canvas_'. + + WebPPicture prev_canvas_; // Previous canvas. + WebPPicture prev_canvas_disposed_; // Previous canvas disposed to background. + + // Encoded data. + EncodedFrame* encoded_frames_; // Array of encoded frames. + size_t size_; // Number of allocated frames. + size_t start_; // Frame start index. + size_t count_; // Number of valid frames. + size_t flush_count_; // If >0, 'flush_count' frames starting from + // 'start' are ready to be added to mux. + + // key-frame related. + int64_t best_delta_; // min(canvas size - frame size) over the frames. + // Can be negative in certain cases due to + // transparent pixels in a frame. + int keyframe_; // Index of selected key-frame relative to 'start_'. + int count_since_key_frame_; // Frames seen since the last key-frame. + + int first_timestamp_; // Timestamp of the first frame. + int prev_timestamp_; // Timestamp of the last added frame. + int prev_candidate_undecided_; // True if it's not yet decided if previous + // frame would be a sub-frame or a key-frame. + + // Misc. + int is_first_frame_; // True if first frame is yet to be added/being added. + int got_null_frame_; // True if WebPAnimEncoderAdd() has already been called + // with a NULL frame. + + size_t in_frame_count_; // Number of input frames processed so far. + size_t out_frame_count_; // Number of frames added to mux so far. This may be + // different from 'in_frame_count_' due to merging. + + WebPMux* mux_; // Muxer to assemble the WebP bitstream. + char error_str_[ERROR_STR_MAX_LENGTH]; // Error string. Empty if no error. +}; + +// ----------------------------------------------------------------------------- +// Life of WebPAnimEncoder object. + +#define DELTA_INFINITY (1ULL << 32) +#define KEYFRAME_NONE (-1) + +// Reset the counters in the WebPAnimEncoder. +static void ResetCounters(WebPAnimEncoder* const enc) { + enc->start_ = 0; + enc->count_ = 0; + enc->flush_count_ = 0; + enc->best_delta_ = DELTA_INFINITY; + enc->keyframe_ = KEYFRAME_NONE; +} + +static void DisableKeyframes(WebPAnimEncoderOptions* const enc_options) { + enc_options->kmax = INT_MAX; + enc_options->kmin = enc_options->kmax - 1; +} + +#define MAX_CACHED_FRAMES 30 + +static void SanitizeEncoderOptions(WebPAnimEncoderOptions* const enc_options) { + int print_warning = enc_options->verbose; + + if (enc_options->minimize_size) { + DisableKeyframes(enc_options); + } + + if (enc_options->kmax == 1) { // All frames will be key-frames. + enc_options->kmin = 0; + enc_options->kmax = 0; + return; + } else if (enc_options->kmax <= 0) { + DisableKeyframes(enc_options); + print_warning = 0; + } + + if (enc_options->kmin >= enc_options->kmax) { + enc_options->kmin = enc_options->kmax - 1; + if (print_warning) { + fprintf(stderr, "WARNING: Setting kmin = %d, so that kmin < kmax.\n", + enc_options->kmin); + } + } else { + const int kmin_limit = enc_options->kmax / 2 + 1; + if (enc_options->kmin < kmin_limit && kmin_limit < enc_options->kmax) { + // This ensures that enc.keyframe + kmin >= kmax is always true. So, we + // can flush all the frames in the 'count_since_key_frame == kmax' case. + enc_options->kmin = kmin_limit; + if (print_warning) { + fprintf(stderr, + "WARNING: Setting kmin = %d, so that kmin >= kmax / 2 + 1.\n", + enc_options->kmin); + } + } + } + // Limit the max number of frames that are allocated. + if (enc_options->kmax - enc_options->kmin > MAX_CACHED_FRAMES) { + enc_options->kmin = enc_options->kmax - MAX_CACHED_FRAMES; + if (print_warning) { + fprintf(stderr, + "WARNING: Setting kmin = %d, so that kmax - kmin <= %d.\n", + enc_options->kmin, MAX_CACHED_FRAMES); + } + } + assert(enc_options->kmin < enc_options->kmax); +} + +#undef MAX_CACHED_FRAMES + +static void DefaultEncoderOptions(WebPAnimEncoderOptions* const enc_options) { + enc_options->anim_params.loop_count = 0; + enc_options->anim_params.bgcolor = 0xffffffff; // White. + enc_options->minimize_size = 0; + DisableKeyframes(enc_options); + enc_options->allow_mixed = 0; + enc_options->verbose = 0; +} + +int WebPAnimEncoderOptionsInitInternal(WebPAnimEncoderOptions* enc_options, + int abi_version) { + if (enc_options == NULL || + WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_MUX_ABI_VERSION)) { + return 0; + } + DefaultEncoderOptions(enc_options); + return 1; +} + +// This starting value is more fit to WebPCleanupTransparentAreaLossless(). +#define TRANSPARENT_COLOR 0x00000000 + +static void ClearRectangle(WebPPicture* const picture, + int left, int top, int width, int height) { + int j; + for (j = top; j < top + height; ++j) { + uint32_t* const dst = picture->argb + j * picture->argb_stride; + int i; + for (i = left; i < left + width; ++i) { + dst[i] = TRANSPARENT_COLOR; + } + } +} + +static void WebPUtilClearPic(WebPPicture* const picture, + const FrameRectangle* const rect) { + if (rect != NULL) { + ClearRectangle(picture, rect->x_offset_, rect->y_offset_, + rect->width_, rect->height_); + } else { + ClearRectangle(picture, 0, 0, picture->width, picture->height); + } +} + +static void MarkNoError(WebPAnimEncoder* const enc) { + enc->error_str_[0] = '\0'; // Empty string. +} + +static void MarkError(WebPAnimEncoder* const enc, const char* str) { + if (snprintf(enc->error_str_, ERROR_STR_MAX_LENGTH, "%s.", str) < 0) { + assert(0); // FIX ME! + } +} + +static void MarkError2(WebPAnimEncoder* const enc, + const char* str, int error_code) { + if (snprintf(enc->error_str_, ERROR_STR_MAX_LENGTH, "%s: %d.", str, + error_code) < 0) { + assert(0); // FIX ME! + } +} + +WebPAnimEncoder* WebPAnimEncoderNewInternal( + int width, int height, const WebPAnimEncoderOptions* enc_options, + int abi_version) { + WebPAnimEncoder* enc; + + if (WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_MUX_ABI_VERSION)) { + return NULL; + } + if (width <= 0 || height <= 0 || + (width * (uint64_t)height) >= MAX_IMAGE_AREA) { + return NULL; + } + + enc = (WebPAnimEncoder*)WebPSafeCalloc(1, sizeof(*enc)); + if (enc == NULL) return NULL; + MarkNoError(enc); + + // Dimensions and options. + *(int*)&enc->canvas_width_ = width; + *(int*)&enc->canvas_height_ = height; + if (enc_options != NULL) { + *(WebPAnimEncoderOptions*)&enc->options_ = *enc_options; + SanitizeEncoderOptions((WebPAnimEncoderOptions*)&enc->options_); + } else { + DefaultEncoderOptions((WebPAnimEncoderOptions*)&enc->options_); + } + + // Canvas buffers. + if (!WebPPictureInit(&enc->curr_canvas_copy_) || + !WebPPictureInit(&enc->prev_canvas_) || + !WebPPictureInit(&enc->prev_canvas_disposed_)) { + goto Err; + } + enc->curr_canvas_copy_.width = width; + enc->curr_canvas_copy_.height = height; + enc->curr_canvas_copy_.use_argb = 1; + if (!WebPPictureAlloc(&enc->curr_canvas_copy_) || + !WebPPictureCopy(&enc->curr_canvas_copy_, &enc->prev_canvas_) || + !WebPPictureCopy(&enc->curr_canvas_copy_, &enc->prev_canvas_disposed_)) { + goto Err; + } + WebPUtilClearPic(&enc->prev_canvas_, NULL); + enc->curr_canvas_copy_modified_ = 1; + + // Encoded frames. + ResetCounters(enc); + // Note: one extra storage is for the previous frame. + enc->size_ = enc->options_.kmax - enc->options_.kmin + 1; + // We need space for at least 2 frames. But when kmin, kmax are both zero, + // enc->size_ will be 1. So we handle that special case below. + if (enc->size_ < 2) enc->size_ = 2; + enc->encoded_frames_ = + (EncodedFrame*)WebPSafeCalloc(enc->size_, sizeof(*enc->encoded_frames_)); + if (enc->encoded_frames_ == NULL) goto Err; + + enc->mux_ = WebPMuxNew(); + if (enc->mux_ == NULL) goto Err; + + enc->count_since_key_frame_ = 0; + enc->first_timestamp_ = 0; + enc->prev_timestamp_ = 0; + enc->prev_candidate_undecided_ = 0; + enc->is_first_frame_ = 1; + enc->got_null_frame_ = 0; + + return enc; // All OK. + + Err: + WebPAnimEncoderDelete(enc); + return NULL; +} + +// Release the data contained by 'encoded_frame'. +static void FrameRelease(EncodedFrame* const encoded_frame) { + if (encoded_frame != NULL) { + WebPDataClear(&encoded_frame->sub_frame_.bitstream); + WebPDataClear(&encoded_frame->key_frame_.bitstream); + memset(encoded_frame, 0, sizeof(*encoded_frame)); + } +} + +void WebPAnimEncoderDelete(WebPAnimEncoder* enc) { + if (enc != NULL) { + WebPPictureFree(&enc->curr_canvas_copy_); + WebPPictureFree(&enc->prev_canvas_); + WebPPictureFree(&enc->prev_canvas_disposed_); + if (enc->encoded_frames_ != NULL) { + size_t i; + for (i = 0; i < enc->size_; ++i) { + FrameRelease(&enc->encoded_frames_[i]); + } + WebPSafeFree(enc->encoded_frames_); + } + WebPMuxDelete(enc->mux_); + WebPSafeFree(enc); + } +} + +// ----------------------------------------------------------------------------- +// Frame addition. + +// Returns cached frame at the given 'position'. +static EncodedFrame* GetFrame(const WebPAnimEncoder* const enc, + size_t position) { + assert(enc->start_ + position < enc->size_); + return &enc->encoded_frames_[enc->start_ + position]; +} + +typedef int (*ComparePixelsFunc)(const uint32_t*, int, const uint32_t*, int, + int, int); + +// Returns true if 'length' number of pixels in 'src' and 'dst' are equal, +// assuming the given step sizes between pixels. +// 'max_allowed_diff' is unused and only there to allow function pointer use. +static WEBP_INLINE int ComparePixelsLossless(const uint32_t* src, int src_step, + const uint32_t* dst, int dst_step, + int length, int max_allowed_diff) { + (void)max_allowed_diff; + assert(length > 0); + while (length-- > 0) { + if (*src != *dst) { + return 0; + } + src += src_step; + dst += dst_step; + } + return 1; +} + +// Helper to check if each channel in 'src' and 'dst' is at most off by +// 'max_allowed_diff'. +static WEBP_INLINE int PixelsAreSimilar(uint32_t src, uint32_t dst, + int max_allowed_diff) { + const int src_a = (src >> 24) & 0xff; + const int src_r = (src >> 16) & 0xff; + const int src_g = (src >> 8) & 0xff; + const int src_b = (src >> 0) & 0xff; + const int dst_a = (dst >> 24) & 0xff; + const int dst_r = (dst >> 16) & 0xff; + const int dst_g = (dst >> 8) & 0xff; + const int dst_b = (dst >> 0) & 0xff; + + return (src_a == dst_a) && + (abs(src_r - dst_r) * dst_a <= (max_allowed_diff * 255)) && + (abs(src_g - dst_g) * dst_a <= (max_allowed_diff * 255)) && + (abs(src_b - dst_b) * dst_a <= (max_allowed_diff * 255)); +} + +// Returns true if 'length' number of pixels in 'src' and 'dst' are within an +// error bound, assuming the given step sizes between pixels. +static WEBP_INLINE int ComparePixelsLossy(const uint32_t* src, int src_step, + const uint32_t* dst, int dst_step, + int length, int max_allowed_diff) { + assert(length > 0); + while (length-- > 0) { + if (!PixelsAreSimilar(*src, *dst, max_allowed_diff)) { + return 0; + } + src += src_step; + dst += dst_step; + } + return 1; +} + +static int IsEmptyRect(const FrameRectangle* const rect) { + return (rect->width_ == 0) || (rect->height_ == 0); +} + +static int QualityToMaxDiff(float quality) { + const double val = pow(quality / 100., 0.5); + const double max_diff = 31 * (1 - val) + 1 * val; + return (int)(max_diff + 0.5); +} + +// Assumes that an initial valid guess of change rectangle 'rect' is passed. +static void MinimizeChangeRectangle(const WebPPicture* const src, + const WebPPicture* const dst, + FrameRectangle* const rect, + int is_lossless, float quality) { + int i, j; + const ComparePixelsFunc compare_pixels = + is_lossless ? ComparePixelsLossless : ComparePixelsLossy; + const int max_allowed_diff_lossy = QualityToMaxDiff(quality); + const int max_allowed_diff = is_lossless ? 0 : max_allowed_diff_lossy; + + // Assumption/correctness checks. + assert(src->width == dst->width && src->height == dst->height); + assert(rect->x_offset_ + rect->width_ <= dst->width); + assert(rect->y_offset_ + rect->height_ <= dst->height); + + // Left boundary. + for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) { + const uint32_t* const src_argb = + &src->argb[rect->y_offset_ * src->argb_stride + i]; + const uint32_t* const dst_argb = + &dst->argb[rect->y_offset_ * dst->argb_stride + i]; + if (compare_pixels(src_argb, src->argb_stride, dst_argb, dst->argb_stride, + rect->height_, max_allowed_diff)) { + --rect->width_; // Redundant column. + ++rect->x_offset_; + } else { + break; + } + } + if (rect->width_ == 0) goto NoChange; + + // Right boundary. + for (i = rect->x_offset_ + rect->width_ - 1; i >= rect->x_offset_; --i) { + const uint32_t* const src_argb = + &src->argb[rect->y_offset_ * src->argb_stride + i]; + const uint32_t* const dst_argb = + &dst->argb[rect->y_offset_ * dst->argb_stride + i]; + if (compare_pixels(src_argb, src->argb_stride, dst_argb, dst->argb_stride, + rect->height_, max_allowed_diff)) { + --rect->width_; // Redundant column. + } else { + break; + } + } + if (rect->width_ == 0) goto NoChange; + + // Top boundary. + for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) { + const uint32_t* const src_argb = + &src->argb[j * src->argb_stride + rect->x_offset_]; + const uint32_t* const dst_argb = + &dst->argb[j * dst->argb_stride + rect->x_offset_]; + if (compare_pixels(src_argb, 1, dst_argb, 1, rect->width_, + max_allowed_diff)) { + --rect->height_; // Redundant row. + ++rect->y_offset_; + } else { + break; + } + } + if (rect->height_ == 0) goto NoChange; + + // Bottom boundary. + for (j = rect->y_offset_ + rect->height_ - 1; j >= rect->y_offset_; --j) { + const uint32_t* const src_argb = + &src->argb[j * src->argb_stride + rect->x_offset_]; + const uint32_t* const dst_argb = + &dst->argb[j * dst->argb_stride + rect->x_offset_]; + if (compare_pixels(src_argb, 1, dst_argb, 1, rect->width_, + max_allowed_diff)) { + --rect->height_; // Redundant row. + } else { + break; + } + } + if (rect->height_ == 0) goto NoChange; + + if (IsEmptyRect(rect)) { + NoChange: + rect->x_offset_ = 0; + rect->y_offset_ = 0; + rect->width_ = 0; + rect->height_ = 0; + } +} + +// Snap rectangle to even offsets (and adjust dimensions if needed). +static WEBP_INLINE void SnapToEvenOffsets(FrameRectangle* const rect) { + rect->width_ += (rect->x_offset_ & 1); + rect->height_ += (rect->y_offset_ & 1); + rect->x_offset_ &= ~1; + rect->y_offset_ &= ~1; +} + +typedef struct { + int should_try_; // Should try this set of parameters. + int empty_rect_allowed_; // Frame with empty rectangle can be skipped. + FrameRectangle rect_ll_; // Frame rectangle for lossless compression. + WebPPicture sub_frame_ll_; // Sub-frame pic for lossless compression. + FrameRectangle rect_lossy_; // Frame rectangle for lossy compression. + // Could be smaller than rect_ll_ as pixels + // with small diffs can be ignored. + WebPPicture sub_frame_lossy_; // Sub-frame pic for lossless compression. +} SubFrameParams; + +static int SubFrameParamsInit(SubFrameParams* const params, + int should_try, int empty_rect_allowed) { + params->should_try_ = should_try; + params->empty_rect_allowed_ = empty_rect_allowed; + if (!WebPPictureInit(¶ms->sub_frame_ll_) || + !WebPPictureInit(¶ms->sub_frame_lossy_)) { + return 0; + } + return 1; +} + +static void SubFrameParamsFree(SubFrameParams* const params) { + WebPPictureFree(¶ms->sub_frame_ll_); + WebPPictureFree(¶ms->sub_frame_lossy_); +} + +// Given previous and current canvas, picks the optimal rectangle for the +// current frame based on 'is_lossless' and other parameters. Assumes that the +// initial guess 'rect' is valid. +static int GetSubRect(const WebPPicture* const prev_canvas, + const WebPPicture* const curr_canvas, int is_key_frame, + int is_first_frame, int empty_rect_allowed, + int is_lossless, float quality, + FrameRectangle* const rect, + WebPPicture* const sub_frame) { + if (!is_key_frame || is_first_frame) { // Optimize frame rectangle. + // Note: This behaves as expected for first frame, as 'prev_canvas' is + // initialized to a fully transparent canvas in the beginning. + MinimizeChangeRectangle(prev_canvas, curr_canvas, rect, + is_lossless, quality); + } + + if (IsEmptyRect(rect)) { + if (empty_rect_allowed) { // No need to get 'sub_frame'. + return 1; + } else { // Force a 1x1 rectangle. + rect->width_ = 1; + rect->height_ = 1; + assert(rect->x_offset_ == 0); + assert(rect->y_offset_ == 0); + } + } + + SnapToEvenOffsets(rect); + return WebPPictureView(curr_canvas, rect->x_offset_, rect->y_offset_, + rect->width_, rect->height_, sub_frame); +} + +// Picks optimal frame rectangle for both lossless and lossy compression. The +// initial guess for frame rectangles will be the full canvas. +static int GetSubRects(const WebPPicture* const prev_canvas, + const WebPPicture* const curr_canvas, int is_key_frame, + int is_first_frame, float quality, + SubFrameParams* const params) { + // Lossless frame rectangle. + params->rect_ll_.x_offset_ = 0; + params->rect_ll_.y_offset_ = 0; + params->rect_ll_.width_ = curr_canvas->width; + params->rect_ll_.height_ = curr_canvas->height; + if (!GetSubRect(prev_canvas, curr_canvas, is_key_frame, is_first_frame, + params->empty_rect_allowed_, 1, quality, + ¶ms->rect_ll_, ¶ms->sub_frame_ll_)) { + return 0; + } + // Lossy frame rectangle. + params->rect_lossy_ = params->rect_ll_; // seed with lossless rect. + return GetSubRect(prev_canvas, curr_canvas, is_key_frame, is_first_frame, + params->empty_rect_allowed_, 0, quality, + ¶ms->rect_lossy_, ¶ms->sub_frame_lossy_); +} + +static WEBP_INLINE int clip(int v, int min_v, int max_v) { + return (v < min_v) ? min_v : (v > max_v) ? max_v : v; +} + +int WebPAnimEncoderRefineRect( + const WebPPicture* const prev_canvas, const WebPPicture* const curr_canvas, + int is_lossless, float quality, int* const x_offset, int* const y_offset, + int* const width, int* const height) { + FrameRectangle rect; + int right, left, bottom, top; + if (prev_canvas == NULL || curr_canvas == NULL || + prev_canvas->width != curr_canvas->width || + prev_canvas->height != curr_canvas->height || + !prev_canvas->use_argb || !curr_canvas->use_argb) { + return 0; + } + right = clip(*x_offset + *width, 0, curr_canvas->width); + left = clip(*x_offset, 0, curr_canvas->width - 1); + bottom = clip(*y_offset + *height, 0, curr_canvas->height); + top = clip(*y_offset, 0, curr_canvas->height - 1); + rect.x_offset_ = left; + rect.y_offset_ = top; + rect.width_ = clip(right - left, 0, curr_canvas->width - rect.x_offset_); + rect.height_ = clip(bottom - top, 0, curr_canvas->height - rect.y_offset_); + MinimizeChangeRectangle(prev_canvas, curr_canvas, &rect, is_lossless, + quality); + SnapToEvenOffsets(&rect); + *x_offset = rect.x_offset_; + *y_offset = rect.y_offset_; + *width = rect.width_; + *height = rect.height_; + return 1; +} + +static void DisposeFrameRectangle(int dispose_method, + const FrameRectangle* const rect, + WebPPicture* const curr_canvas) { + assert(rect != NULL); + if (dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { + WebPUtilClearPic(curr_canvas, rect); + } +} + +static uint32_t RectArea(const FrameRectangle* const rect) { + return (uint32_t)rect->width_ * rect->height_; +} + +static int IsLosslessBlendingPossible(const WebPPicture* const src, + const WebPPicture* const dst, + const FrameRectangle* const rect) { + int i, j; + assert(src->width == dst->width && src->height == dst->height); + assert(rect->x_offset_ + rect->width_ <= dst->width); + assert(rect->y_offset_ + rect->height_ <= dst->height); + for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) { + for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) { + const uint32_t src_pixel = src->argb[j * src->argb_stride + i]; + const uint32_t dst_pixel = dst->argb[j * dst->argb_stride + i]; + const uint32_t dst_alpha = dst_pixel >> 24; + if (dst_alpha != 0xff && src_pixel != dst_pixel) { + // In this case, if we use blending, we can't attain the desired + // 'dst_pixel' value for this pixel. So, blending is not possible. + return 0; + } + } + } + return 1; +} + +static int IsLossyBlendingPossible(const WebPPicture* const src, + const WebPPicture* const dst, + const FrameRectangle* const rect, + float quality) { + const int max_allowed_diff_lossy = QualityToMaxDiff(quality); + int i, j; + assert(src->width == dst->width && src->height == dst->height); + assert(rect->x_offset_ + rect->width_ <= dst->width); + assert(rect->y_offset_ + rect->height_ <= dst->height); + for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) { + for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) { + const uint32_t src_pixel = src->argb[j * src->argb_stride + i]; + const uint32_t dst_pixel = dst->argb[j * dst->argb_stride + i]; + const uint32_t dst_alpha = dst_pixel >> 24; + if (dst_alpha != 0xff && + !PixelsAreSimilar(src_pixel, dst_pixel, max_allowed_diff_lossy)) { + // In this case, if we use blending, we can't attain the desired + // 'dst_pixel' value for this pixel. So, blending is not possible. + return 0; + } + } + } + return 1; +} + +// For pixels in 'rect', replace those pixels in 'dst' that are same as 'src' by +// transparent pixels. +// Returns true if at least one pixel gets modified. +static int IncreaseTransparency(const WebPPicture* const src, + const FrameRectangle* const rect, + WebPPicture* const dst) { + int i, j; + int modified = 0; + assert(src != NULL && dst != NULL && rect != NULL); + assert(src->width == dst->width && src->height == dst->height); + for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) { + const uint32_t* const psrc = src->argb + j * src->argb_stride; + uint32_t* const pdst = dst->argb + j * dst->argb_stride; + for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) { + if (psrc[i] == pdst[i] && pdst[i] != TRANSPARENT_COLOR) { + pdst[i] = TRANSPARENT_COLOR; + modified = 1; + } + } + } + return modified; +} + +#undef TRANSPARENT_COLOR + +// Replace similar blocks of pixels by a 'see-through' transparent block +// with uniform average color. +// Assumes lossy compression is being used. +// Returns true if at least one pixel gets modified. +static int FlattenSimilarBlocks(const WebPPicture* const src, + const FrameRectangle* const rect, + WebPPicture* const dst, float quality) { + const int max_allowed_diff_lossy = QualityToMaxDiff(quality); + int i, j; + int modified = 0; + const int block_size = 8; + const int y_start = (rect->y_offset_ + block_size) & ~(block_size - 1); + const int y_end = (rect->y_offset_ + rect->height_) & ~(block_size - 1); + const int x_start = (rect->x_offset_ + block_size) & ~(block_size - 1); + const int x_end = (rect->x_offset_ + rect->width_) & ~(block_size - 1); + assert(src != NULL && dst != NULL && rect != NULL); + assert(src->width == dst->width && src->height == dst->height); + assert((block_size & (block_size - 1)) == 0); // must be a power of 2 + // Iterate over each block and count similar pixels. + for (j = y_start; j < y_end; j += block_size) { + for (i = x_start; i < x_end; i += block_size) { + int cnt = 0; + int avg_r = 0, avg_g = 0, avg_b = 0; + int x, y; + const uint32_t* const psrc = src->argb + j * src->argb_stride + i; + uint32_t* const pdst = dst->argb + j * dst->argb_stride + i; + for (y = 0; y < block_size; ++y) { + for (x = 0; x < block_size; ++x) { + const uint32_t src_pixel = psrc[x + y * src->argb_stride]; + const int alpha = src_pixel >> 24; + if (alpha == 0xff && + PixelsAreSimilar(src_pixel, pdst[x + y * dst->argb_stride], + max_allowed_diff_lossy)) { + ++cnt; + avg_r += (src_pixel >> 16) & 0xff; + avg_g += (src_pixel >> 8) & 0xff; + avg_b += (src_pixel >> 0) & 0xff; + } + } + } + // If we have a fully similar block, we replace it with an + // average transparent block. This compresses better in lossy mode. + if (cnt == block_size * block_size) { + const uint32_t color = (0x00 << 24) | + ((avg_r / cnt) << 16) | + ((avg_g / cnt) << 8) | + ((avg_b / cnt) << 0); + for (y = 0; y < block_size; ++y) { + for (x = 0; x < block_size; ++x) { + pdst[x + y * dst->argb_stride] = color; + } + } + modified = 1; + } + } + } + return modified; +} + +static int EncodeFrame(const WebPConfig* const config, WebPPicture* const pic, + WebPMemoryWriter* const memory) { + pic->use_argb = 1; + pic->writer = WebPMemoryWrite; + pic->custom_ptr = memory; + if (!WebPEncode(config, pic)) { + return 0; + } + return 1; +} + +// Struct representing a candidate encoded frame including its metadata. +typedef struct { + WebPMemoryWriter mem_; + WebPMuxFrameInfo info_; + FrameRectangle rect_; + int evaluate_; // True if this candidate should be evaluated. +} Candidate; + +// Generates a candidate encoded frame given a picture and metadata. +static WebPEncodingError EncodeCandidate(WebPPicture* const sub_frame, + const FrameRectangle* const rect, + const WebPConfig* const encoder_config, + int use_blending, + Candidate* const candidate) { + WebPConfig config = *encoder_config; + WebPEncodingError error_code = VP8_ENC_OK; + assert(candidate != NULL); + memset(candidate, 0, sizeof(*candidate)); + + // Set frame rect and info. + candidate->rect_ = *rect; + candidate->info_.id = WEBP_CHUNK_ANMF; + candidate->info_.x_offset = rect->x_offset_; + candidate->info_.y_offset = rect->y_offset_; + candidate->info_.dispose_method = WEBP_MUX_DISPOSE_NONE; // Set later. + candidate->info_.blend_method = + use_blending ? WEBP_MUX_BLEND : WEBP_MUX_NO_BLEND; + candidate->info_.duration = 0; // Set in next call to WebPAnimEncoderAdd(). + + // Encode picture. + WebPMemoryWriterInit(&candidate->mem_); + + if (!config.lossless && use_blending) { + // Disable filtering to avoid blockiness in reconstructed frames at the + // time of decoding. + config.autofilter = 0; + config.filter_strength = 0; + } + if (!EncodeFrame(&config, sub_frame, &candidate->mem_)) { + error_code = sub_frame->error_code; + goto Err; + } + + candidate->evaluate_ = 1; + return error_code; + + Err: + WebPMemoryWriterClear(&candidate->mem_); + return error_code; +} + +static void CopyCurrentCanvas(WebPAnimEncoder* const enc) { + if (enc->curr_canvas_copy_modified_) { + WebPCopyPixels(enc->curr_canvas_, &enc->curr_canvas_copy_); + enc->curr_canvas_copy_.progress_hook = enc->curr_canvas_->progress_hook; + enc->curr_canvas_copy_.user_data = enc->curr_canvas_->user_data; + enc->curr_canvas_copy_modified_ = 0; + } +} + +enum { + LL_DISP_NONE = 0, + LL_DISP_BG, + LOSSY_DISP_NONE, + LOSSY_DISP_BG, + CANDIDATE_COUNT +}; + +#define MIN_COLORS_LOSSY 31 // Don't try lossy below this threshold. +#define MAX_COLORS_LOSSLESS 194 // Don't try lossless above this threshold. + +// Generates candidates for a given dispose method given pre-filled sub-frame +// 'params'. +static WebPEncodingError GenerateCandidates( + WebPAnimEncoder* const enc, Candidate candidates[CANDIDATE_COUNT], + WebPMuxAnimDispose dispose_method, int is_lossless, int is_key_frame, + SubFrameParams* const params, + const WebPConfig* const config_ll, const WebPConfig* const config_lossy) { + WebPEncodingError error_code = VP8_ENC_OK; + const int is_dispose_none = (dispose_method == WEBP_MUX_DISPOSE_NONE); + Candidate* const candidate_ll = + is_dispose_none ? &candidates[LL_DISP_NONE] : &candidates[LL_DISP_BG]; + Candidate* const candidate_lossy = is_dispose_none + ? &candidates[LOSSY_DISP_NONE] + : &candidates[LOSSY_DISP_BG]; + WebPPicture* const curr_canvas = &enc->curr_canvas_copy_; + const WebPPicture* const prev_canvas = + is_dispose_none ? &enc->prev_canvas_ : &enc->prev_canvas_disposed_; + int use_blending_ll, use_blending_lossy; + int evaluate_ll, evaluate_lossy; + + CopyCurrentCanvas(enc); + use_blending_ll = + !is_key_frame && + IsLosslessBlendingPossible(prev_canvas, curr_canvas, ¶ms->rect_ll_); + use_blending_lossy = + !is_key_frame && + IsLossyBlendingPossible(prev_canvas, curr_canvas, ¶ms->rect_lossy_, + config_lossy->quality); + + // Pick candidates to be tried. + if (!enc->options_.allow_mixed) { + evaluate_ll = is_lossless; + evaluate_lossy = !is_lossless; + } else if (enc->options_.minimize_size) { + evaluate_ll = 1; + evaluate_lossy = 1; + } else { // Use a heuristic for trying lossless and/or lossy compression. + const int num_colors = WebPGetColorPalette(¶ms->sub_frame_ll_, NULL); + evaluate_ll = (num_colors < MAX_COLORS_LOSSLESS); + evaluate_lossy = (num_colors >= MIN_COLORS_LOSSY); + } + + // Generate candidates. + if (evaluate_ll) { + CopyCurrentCanvas(enc); + if (use_blending_ll) { + enc->curr_canvas_copy_modified_ = + IncreaseTransparency(prev_canvas, ¶ms->rect_ll_, curr_canvas); + } + error_code = EncodeCandidate(¶ms->sub_frame_ll_, ¶ms->rect_ll_, + config_ll, use_blending_ll, candidate_ll); + if (error_code != VP8_ENC_OK) return error_code; + } + if (evaluate_lossy) { + CopyCurrentCanvas(enc); + if (use_blending_lossy) { + enc->curr_canvas_copy_modified_ = + FlattenSimilarBlocks(prev_canvas, ¶ms->rect_lossy_, curr_canvas, + config_lossy->quality); + } + error_code = + EncodeCandidate(¶ms->sub_frame_lossy_, ¶ms->rect_lossy_, + config_lossy, use_blending_lossy, candidate_lossy); + if (error_code != VP8_ENC_OK) return error_code; + enc->curr_canvas_copy_modified_ = 1; + } + return error_code; +} + +#undef MIN_COLORS_LOSSY +#undef MAX_COLORS_LOSSLESS + +static void GetEncodedData(const WebPMemoryWriter* const memory, + WebPData* const encoded_data) { + encoded_data->bytes = memory->mem; + encoded_data->size = memory->size; +} + +// Sets dispose method of the previous frame to be 'dispose_method'. +static void SetPreviousDisposeMethod(WebPAnimEncoder* const enc, + WebPMuxAnimDispose dispose_method) { + const size_t position = enc->count_ - 2; + EncodedFrame* const prev_enc_frame = GetFrame(enc, position); + assert(enc->count_ >= 2); // As current and previous frames are in enc. + + if (enc->prev_candidate_undecided_) { + assert(dispose_method == WEBP_MUX_DISPOSE_NONE); + prev_enc_frame->sub_frame_.dispose_method = dispose_method; + prev_enc_frame->key_frame_.dispose_method = dispose_method; + } else { + WebPMuxFrameInfo* const prev_info = prev_enc_frame->is_key_frame_ + ? &prev_enc_frame->key_frame_ + : &prev_enc_frame->sub_frame_; + prev_info->dispose_method = dispose_method; + } +} + +static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) { + const size_t position = enc->count_ - 1; + EncodedFrame* const prev_enc_frame = GetFrame(enc, position); + int new_duration; + + assert(enc->count_ >= 1); + assert(!prev_enc_frame->is_key_frame_ || + prev_enc_frame->sub_frame_.duration == + prev_enc_frame->key_frame_.duration); + assert(prev_enc_frame->sub_frame_.duration == + (prev_enc_frame->sub_frame_.duration & (MAX_DURATION - 1))); + assert(duration == (duration & (MAX_DURATION - 1))); + + new_duration = prev_enc_frame->sub_frame_.duration + duration; + if (new_duration >= MAX_DURATION) { // Special case. + // Separate out previous frame from earlier merged frames to avoid overflow. + // We add a 1x1 transparent frame for the previous frame, with blending on. + const FrameRectangle rect = { 0, 0, 1, 1 }; + const uint8_t lossless_1x1_bytes[] = { + 0x52, 0x49, 0x46, 0x46, 0x14, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, + 0x56, 0x50, 0x38, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x10, 0x88, 0x88, 0x08 + }; + const WebPData lossless_1x1 = { + lossless_1x1_bytes, sizeof(lossless_1x1_bytes) + }; + const uint8_t lossy_1x1_bytes[] = { + 0x52, 0x49, 0x46, 0x46, 0x40, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, + 0x56, 0x50, 0x38, 0x58, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x4c, 0x50, 0x48, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x50, 0x38, 0x20, 0x18, 0x00, 0x00, 0x00, + 0x30, 0x01, 0x00, 0x9d, 0x01, 0x2a, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x34, 0x25, 0xa4, 0x00, 0x03, 0x70, 0x00, 0xfe, 0xfb, 0xfd, 0x50, 0x00 + }; + const WebPData lossy_1x1 = { lossy_1x1_bytes, sizeof(lossy_1x1_bytes) }; + const int can_use_lossless = + (enc->last_config_.lossless || enc->options_.allow_mixed); + EncodedFrame* const curr_enc_frame = GetFrame(enc, enc->count_); + curr_enc_frame->is_key_frame_ = 0; + curr_enc_frame->sub_frame_.id = WEBP_CHUNK_ANMF; + curr_enc_frame->sub_frame_.x_offset = 0; + curr_enc_frame->sub_frame_.y_offset = 0; + curr_enc_frame->sub_frame_.dispose_method = WEBP_MUX_DISPOSE_NONE; + curr_enc_frame->sub_frame_.blend_method = WEBP_MUX_BLEND; + curr_enc_frame->sub_frame_.duration = duration; + if (!WebPDataCopy(can_use_lossless ? &lossless_1x1 : &lossy_1x1, + &curr_enc_frame->sub_frame_.bitstream)) { + return 0; + } + ++enc->count_; + ++enc->count_since_key_frame_; + enc->flush_count_ = enc->count_ - 1; + enc->prev_candidate_undecided_ = 0; + enc->prev_rect_ = rect; + } else { // Regular case. + // Increase duration of the previous frame by 'duration'. + prev_enc_frame->sub_frame_.duration = new_duration; + prev_enc_frame->key_frame_.duration = new_duration; + } + return 1; +} + +// Pick the candidate encoded frame with smallest size and release other +// candidates. +// TODO(later): Perhaps a rough SSIM/PSNR produced by the encoder should +// also be a criteria, in addition to sizes. +static void PickBestCandidate(WebPAnimEncoder* const enc, + Candidate* const candidates, int is_key_frame, + EncodedFrame* const encoded_frame) { + int i; + int best_idx = -1; + size_t best_size = ~0; + for (i = 0; i < CANDIDATE_COUNT; ++i) { + if (candidates[i].evaluate_) { + const size_t candidate_size = candidates[i].mem_.size; + if (candidate_size < best_size) { + best_idx = i; + best_size = candidate_size; + } + } + } + assert(best_idx != -1); + for (i = 0; i < CANDIDATE_COUNT; ++i) { + if (candidates[i].evaluate_) { + if (i == best_idx) { + WebPMuxFrameInfo* const dst = is_key_frame + ? &encoded_frame->key_frame_ + : &encoded_frame->sub_frame_; + *dst = candidates[i].info_; + GetEncodedData(&candidates[i].mem_, &dst->bitstream); + if (!is_key_frame) { + // Note: Previous dispose method only matters for non-keyframes. + // Also, we don't want to modify previous dispose method that was + // selected when a non key-frame was assumed. + const WebPMuxAnimDispose prev_dispose_method = + (best_idx == LL_DISP_NONE || best_idx == LOSSY_DISP_NONE) + ? WEBP_MUX_DISPOSE_NONE + : WEBP_MUX_DISPOSE_BACKGROUND; + SetPreviousDisposeMethod(enc, prev_dispose_method); + } + enc->prev_rect_ = candidates[i].rect_; // save for next frame. + } else { + WebPMemoryWriterClear(&candidates[i].mem_); + candidates[i].evaluate_ = 0; + } + } + } +} + +// Depending on the configuration, tries different compressions +// (lossy/lossless), dispose methods, blending methods etc to encode the current +// frame and outputs the best one in 'encoded_frame'. +// 'frame_skipped' will be set to true if this frame should actually be skipped. +static WebPEncodingError SetFrame(WebPAnimEncoder* const enc, + const WebPConfig* const config, + int is_key_frame, + EncodedFrame* const encoded_frame, + int* const frame_skipped) { + int i; + WebPEncodingError error_code = VP8_ENC_OK; + const WebPPicture* const curr_canvas = &enc->curr_canvas_copy_; + const WebPPicture* const prev_canvas = &enc->prev_canvas_; + Candidate candidates[CANDIDATE_COUNT]; + const int is_lossless = config->lossless; + const int consider_lossless = is_lossless || enc->options_.allow_mixed; + const int consider_lossy = !is_lossless || enc->options_.allow_mixed; + const int is_first_frame = enc->is_first_frame_; + + // First frame cannot be skipped as there is no 'previous frame' to merge it + // to. So, empty rectangle is not allowed for the first frame. + const int empty_rect_allowed_none = !is_first_frame; + + // Even if there is exact pixel match between 'disposed previous canvas' and + // 'current canvas', we can't skip current frame, as there may not be exact + // pixel match between 'previous canvas' and 'current canvas'. So, we don't + // allow empty rectangle in this case. + const int empty_rect_allowed_bg = 0; + + // If current frame is a key-frame, dispose method of previous frame doesn't + // matter, so we don't try dispose to background. + // Also, if key-frame insertion is on, and previous frame could be picked as + // either a sub-frame or a key-frame, then we can't be sure about what frame + // rectangle would be disposed. In that case too, we don't try dispose to + // background. + const int dispose_bg_possible = + !is_key_frame && !enc->prev_candidate_undecided_; + + SubFrameParams dispose_none_params; + SubFrameParams dispose_bg_params; + + WebPConfig config_ll = *config; + WebPConfig config_lossy = *config; + config_ll.lossless = 1; + config_lossy.lossless = 0; + enc->last_config_ = *config; + enc->last_config_reversed_ = config->lossless ? config_lossy : config_ll; + *frame_skipped = 0; + + if (!SubFrameParamsInit(&dispose_none_params, 1, empty_rect_allowed_none) || + !SubFrameParamsInit(&dispose_bg_params, 0, empty_rect_allowed_bg)) { + return VP8_ENC_ERROR_INVALID_CONFIGURATION; + } + + memset(candidates, 0, sizeof(candidates)); + + // Change-rectangle assuming previous frame was DISPOSE_NONE. + if (!GetSubRects(prev_canvas, curr_canvas, is_key_frame, is_first_frame, + config_lossy.quality, &dispose_none_params)) { + error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; + goto Err; + } + + if ((consider_lossless && IsEmptyRect(&dispose_none_params.rect_ll_)) || + (consider_lossy && IsEmptyRect(&dispose_none_params.rect_lossy_))) { + // Don't encode the frame at all. Instead, the duration of the previous + // frame will be increased later. + assert(empty_rect_allowed_none); + *frame_skipped = 1; + goto End; + } + + if (dispose_bg_possible) { + // Change-rectangle assuming previous frame was DISPOSE_BACKGROUND. + WebPPicture* const prev_canvas_disposed = &enc->prev_canvas_disposed_; + WebPCopyPixels(prev_canvas, prev_canvas_disposed); + DisposeFrameRectangle(WEBP_MUX_DISPOSE_BACKGROUND, &enc->prev_rect_, + prev_canvas_disposed); + + if (!GetSubRects(prev_canvas_disposed, curr_canvas, is_key_frame, + is_first_frame, config_lossy.quality, + &dispose_bg_params)) { + error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; + goto Err; + } + assert(!IsEmptyRect(&dispose_bg_params.rect_ll_)); + assert(!IsEmptyRect(&dispose_bg_params.rect_lossy_)); + + if (enc->options_.minimize_size) { // Try both dispose methods. + dispose_bg_params.should_try_ = 1; + dispose_none_params.should_try_ = 1; + } else if ((is_lossless && + RectArea(&dispose_bg_params.rect_ll_) < + RectArea(&dispose_none_params.rect_ll_)) || + (!is_lossless && + RectArea(&dispose_bg_params.rect_lossy_) < + RectArea(&dispose_none_params.rect_lossy_))) { + dispose_bg_params.should_try_ = 1; // Pick DISPOSE_BACKGROUND. + dispose_none_params.should_try_ = 0; + } + } + + if (dispose_none_params.should_try_) { + error_code = GenerateCandidates( + enc, candidates, WEBP_MUX_DISPOSE_NONE, is_lossless, is_key_frame, + &dispose_none_params, &config_ll, &config_lossy); + if (error_code != VP8_ENC_OK) goto Err; + } + + if (dispose_bg_params.should_try_) { + assert(!enc->is_first_frame_); + assert(dispose_bg_possible); + error_code = GenerateCandidates( + enc, candidates, WEBP_MUX_DISPOSE_BACKGROUND, is_lossless, is_key_frame, + &dispose_bg_params, &config_ll, &config_lossy); + if (error_code != VP8_ENC_OK) goto Err; + } + + PickBestCandidate(enc, candidates, is_key_frame, encoded_frame); + + goto End; + + Err: + for (i = 0; i < CANDIDATE_COUNT; ++i) { + if (candidates[i].evaluate_) { + WebPMemoryWriterClear(&candidates[i].mem_); + } + } + + End: + SubFrameParamsFree(&dispose_none_params); + SubFrameParamsFree(&dispose_bg_params); + return error_code; +} + +// Calculate the penalty incurred if we encode given frame as a key frame +// instead of a sub-frame. +static int64_t KeyFramePenalty(const EncodedFrame* const encoded_frame) { + return ((int64_t)encoded_frame->key_frame_.bitstream.size - + encoded_frame->sub_frame_.bitstream.size); +} + +static int CacheFrame(WebPAnimEncoder* const enc, + const WebPConfig* const config) { + int ok = 0; + int frame_skipped = 0; + WebPEncodingError error_code = VP8_ENC_OK; + const size_t position = enc->count_; + EncodedFrame* const encoded_frame = GetFrame(enc, position); + + ++enc->count_; + + if (enc->is_first_frame_) { // Add this as a key-frame. + error_code = SetFrame(enc, config, 1, encoded_frame, &frame_skipped); + if (error_code != VP8_ENC_OK) goto End; + assert(frame_skipped == 0); // First frame can't be skipped, even if empty. + assert(position == 0 && enc->count_ == 1); + encoded_frame->is_key_frame_ = 1; + enc->flush_count_ = 0; + enc->count_since_key_frame_ = 0; + enc->prev_candidate_undecided_ = 0; + } else { + ++enc->count_since_key_frame_; + if (enc->count_since_key_frame_ <= enc->options_.kmin) { + // Add this as a frame rectangle. + error_code = SetFrame(enc, config, 0, encoded_frame, &frame_skipped); + if (error_code != VP8_ENC_OK) goto End; + if (frame_skipped) goto Skip; + encoded_frame->is_key_frame_ = 0; + enc->flush_count_ = enc->count_ - 1; + enc->prev_candidate_undecided_ = 0; + } else { + int64_t curr_delta; + FrameRectangle prev_rect_key, prev_rect_sub; + + // Add this as a frame rectangle to enc. + error_code = SetFrame(enc, config, 0, encoded_frame, &frame_skipped); + if (error_code != VP8_ENC_OK) goto End; + if (frame_skipped) goto Skip; + prev_rect_sub = enc->prev_rect_; + + + // Add this as a key-frame to enc, too. + error_code = SetFrame(enc, config, 1, encoded_frame, &frame_skipped); + if (error_code != VP8_ENC_OK) goto End; + assert(frame_skipped == 0); // Key-frame cannot be an empty rectangle. + prev_rect_key = enc->prev_rect_; + + // Analyze size difference of the two variants. + curr_delta = KeyFramePenalty(encoded_frame); + if (curr_delta <= enc->best_delta_) { // Pick this as the key-frame. + if (enc->keyframe_ != KEYFRAME_NONE) { + EncodedFrame* const old_keyframe = GetFrame(enc, enc->keyframe_); + assert(old_keyframe->is_key_frame_); + old_keyframe->is_key_frame_ = 0; + } + encoded_frame->is_key_frame_ = 1; + enc->prev_candidate_undecided_ = 1; + enc->keyframe_ = (int)position; + enc->best_delta_ = curr_delta; + enc->flush_count_ = enc->count_ - 1; // We can flush previous frames. + } else { + encoded_frame->is_key_frame_ = 0; + enc->prev_candidate_undecided_ = 0; + } + // Note: We need '>=' below because when kmin and kmax are both zero, + // count_since_key_frame will always be > kmax. + if (enc->count_since_key_frame_ >= enc->options_.kmax) { + enc->flush_count_ = enc->count_ - 1; + enc->count_since_key_frame_ = 0; + enc->keyframe_ = KEYFRAME_NONE; + enc->best_delta_ = DELTA_INFINITY; + } + if (!enc->prev_candidate_undecided_) { + enc->prev_rect_ = + encoded_frame->is_key_frame_ ? prev_rect_key : prev_rect_sub; + } + } + } + + // Update previous to previous and previous canvases for next call. + WebPCopyPixels(enc->curr_canvas_, &enc->prev_canvas_); + enc->is_first_frame_ = 0; + + Skip: + ok = 1; + ++enc->in_frame_count_; + + End: + if (!ok || frame_skipped) { + FrameRelease(encoded_frame); + // We reset some counters, as the frame addition failed/was skipped. + --enc->count_; + if (!enc->is_first_frame_) --enc->count_since_key_frame_; + if (!ok) { + MarkError2(enc, "ERROR adding frame. WebPEncodingError", error_code); + } + } + enc->curr_canvas_->error_code = error_code; // report error_code + assert(ok || error_code != VP8_ENC_OK); + return ok; +} + +static int FlushFrames(WebPAnimEncoder* const enc) { + while (enc->flush_count_ > 0) { + WebPMuxError err; + EncodedFrame* const curr = GetFrame(enc, 0); + const WebPMuxFrameInfo* const info = + curr->is_key_frame_ ? &curr->key_frame_ : &curr->sub_frame_; + assert(enc->mux_ != NULL); + err = WebPMuxPushFrame(enc->mux_, info, 1); + if (err != WEBP_MUX_OK) { + MarkError2(enc, "ERROR adding frame. WebPMuxError", err); + return 0; + } + if (enc->options_.verbose) { + fprintf(stderr, "INFO: Added frame. offset:%d,%d dispose:%d blend:%d\n", + info->x_offset, info->y_offset, info->dispose_method, + info->blend_method); + } + ++enc->out_frame_count_; + FrameRelease(curr); + ++enc->start_; + --enc->flush_count_; + --enc->count_; + if (enc->keyframe_ != KEYFRAME_NONE) --enc->keyframe_; + } + + if (enc->count_ == 1 && enc->start_ != 0) { + // Move enc->start to index 0. + const int enc_start_tmp = (int)enc->start_; + EncodedFrame temp = enc->encoded_frames_[0]; + enc->encoded_frames_[0] = enc->encoded_frames_[enc_start_tmp]; + enc->encoded_frames_[enc_start_tmp] = temp; + FrameRelease(&enc->encoded_frames_[enc_start_tmp]); + enc->start_ = 0; + } + return 1; +} + +#undef DELTA_INFINITY +#undef KEYFRAME_NONE + +int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp, + const WebPConfig* encoder_config) { + WebPConfig config; + int ok; + + if (enc == NULL) { + return 0; + } + MarkNoError(enc); + + if (!enc->is_first_frame_) { + // Make sure timestamps are non-decreasing (integer wrap-around is OK). + const uint32_t prev_frame_duration = + (uint32_t)timestamp - enc->prev_timestamp_; + if (prev_frame_duration >= MAX_DURATION) { + if (frame != NULL) { + frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; + } + MarkError(enc, "ERROR adding frame: timestamps must be non-decreasing"); + return 0; + } + if (!IncreasePreviousDuration(enc, (int)prev_frame_duration)) { + return 0; + } + // IncreasePreviousDuration() may add a frame to avoid exceeding + // MAX_DURATION which could cause CacheFrame() to over read encoded_frames_ + // before the next flush. + if (enc->count_ == enc->size_ && !FlushFrames(enc)) { + return 0; + } + } else { + enc->first_timestamp_ = timestamp; + } + + if (frame == NULL) { // Special: last call. + enc->got_null_frame_ = 1; + enc->prev_timestamp_ = timestamp; + return 1; + } + + if (frame->width != enc->canvas_width_ || + frame->height != enc->canvas_height_) { + frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; + MarkError(enc, "ERROR adding frame: Invalid frame dimensions"); + return 0; + } + + if (!frame->use_argb) { // Convert frame from YUV(A) to ARGB. + if (enc->options_.verbose) { + fprintf(stderr, "WARNING: Converting frame from YUV(A) to ARGB format; " + "this incurs a small loss.\n"); + } + if (!WebPPictureYUVAToARGB(frame)) { + MarkError(enc, "ERROR converting frame from YUV(A) to ARGB"); + return 0; + } + } + + if (encoder_config != NULL) { + if (!WebPValidateConfig(encoder_config)) { + MarkError(enc, "ERROR adding frame: Invalid WebPConfig"); + return 0; + } + config = *encoder_config; + } else { + if (!WebPConfigInit(&config)) { + MarkError(enc, "Cannot Init config"); + return 0; + } + config.lossless = 1; + } + assert(enc->curr_canvas_ == NULL); + enc->curr_canvas_ = frame; // Store reference. + assert(enc->curr_canvas_copy_modified_ == 1); + CopyCurrentCanvas(enc); + + ok = CacheFrame(enc, &config) && FlushFrames(enc); + + enc->curr_canvas_ = NULL; + enc->curr_canvas_copy_modified_ = 1; + if (ok) { + enc->prev_timestamp_ = timestamp; + } + return ok; +} + +// ----------------------------------------------------------------------------- +// Bitstream assembly. + +WEBP_NODISCARD static int DecodeFrameOntoCanvas( + const WebPMuxFrameInfo* const frame, WebPPicture* const canvas) { + const WebPData* const image = &frame->bitstream; + WebPPicture sub_image; + WebPDecoderConfig config; + if (!WebPInitDecoderConfig(&config)) { + return 0; + } + WebPUtilClearPic(canvas, NULL); + if (WebPGetFeatures(image->bytes, image->size, &config.input) != + VP8_STATUS_OK) { + return 0; + } + if (!WebPPictureView(canvas, frame->x_offset, frame->y_offset, + config.input.width, config.input.height, &sub_image)) { + return 0; + } + config.output.is_external_memory = 1; + config.output.colorspace = MODE_BGRA; + config.output.u.RGBA.rgba = (uint8_t*)sub_image.argb; + config.output.u.RGBA.stride = sub_image.argb_stride * 4; + config.output.u.RGBA.size = config.output.u.RGBA.stride * sub_image.height; + + if (WebPDecode(image->bytes, image->size, &config) != VP8_STATUS_OK) { + return 0; + } + return 1; +} + +static int FrameToFullCanvas(WebPAnimEncoder* const enc, + const WebPMuxFrameInfo* const frame, + WebPData* const full_image) { + WebPPicture* const canvas_buf = &enc->curr_canvas_copy_; + WebPMemoryWriter mem1, mem2; + WebPMemoryWriterInit(&mem1); + WebPMemoryWriterInit(&mem2); + + if (!DecodeFrameOntoCanvas(frame, canvas_buf)) goto Err; + if (!EncodeFrame(&enc->last_config_, canvas_buf, &mem1)) goto Err; + GetEncodedData(&mem1, full_image); + + if (enc->options_.allow_mixed) { + if (!EncodeFrame(&enc->last_config_reversed_, canvas_buf, &mem2)) goto Err; + if (mem2.size < mem1.size) { + GetEncodedData(&mem2, full_image); + WebPMemoryWriterClear(&mem1); + } else { + WebPMemoryWriterClear(&mem2); + } + } + return 1; + + Err: + WebPMemoryWriterClear(&mem1); + WebPMemoryWriterClear(&mem2); + return 0; +} + +// Convert a single-frame animation to a non-animated image if appropriate. +// TODO(urvang): Can we pick one of the two heuristically (based on frame +// rectangle and/or presence of alpha)? +static WebPMuxError OptimizeSingleFrame(WebPAnimEncoder* const enc, + WebPData* const webp_data) { + WebPMuxError err = WEBP_MUX_OK; + int canvas_width, canvas_height; + WebPMuxFrameInfo frame; + WebPData full_image; + WebPData webp_data2; + WebPMux* const mux = WebPMuxCreate(webp_data, 0); + if (mux == NULL) return WEBP_MUX_BAD_DATA; + assert(enc->out_frame_count_ == 1); + WebPDataInit(&frame.bitstream); + WebPDataInit(&full_image); + WebPDataInit(&webp_data2); + + err = WebPMuxGetFrame(mux, 1, &frame); + if (err != WEBP_MUX_OK) goto End; + if (frame.id != WEBP_CHUNK_ANMF) goto End; // Non-animation: nothing to do. + err = WebPMuxGetCanvasSize(mux, &canvas_width, &canvas_height); + if (err != WEBP_MUX_OK) goto End; + if (!FrameToFullCanvas(enc, &frame, &full_image)) { + err = WEBP_MUX_BAD_DATA; + goto End; + } + err = WebPMuxSetImage(mux, &full_image, 1); + if (err != WEBP_MUX_OK) goto End; + err = WebPMuxAssemble(mux, &webp_data2); + if (err != WEBP_MUX_OK) goto End; + + if (webp_data2.size < webp_data->size) { // Pick 'webp_data2' if smaller. + WebPDataClear(webp_data); + *webp_data = webp_data2; + WebPDataInit(&webp_data2); + } + + End: + WebPDataClear(&frame.bitstream); + WebPDataClear(&full_image); + WebPMuxDelete(mux); + WebPDataClear(&webp_data2); + return err; +} + +int WebPAnimEncoderAssemble(WebPAnimEncoder* enc, WebPData* webp_data) { + WebPMux* mux; + WebPMuxError err; + + if (enc == NULL) { + return 0; + } + MarkNoError(enc); + + if (webp_data == NULL) { + MarkError(enc, "ERROR assembling: NULL input"); + return 0; + } + + if (enc->in_frame_count_ == 0) { + MarkError(enc, "ERROR: No frames to assemble"); + return 0; + } + + if (!enc->got_null_frame_ && enc->in_frame_count_ > 1 && enc->count_ > 0) { + // set duration of the last frame to be avg of durations of previous frames. + const double delta_time = + (uint32_t)enc->prev_timestamp_ - enc->first_timestamp_; + const int average_duration = (int)(delta_time / (enc->in_frame_count_ - 1)); + if (!IncreasePreviousDuration(enc, average_duration)) { + return 0; + } + } + + // Flush any remaining frames. + enc->flush_count_ = enc->count_; + if (!FlushFrames(enc)) { + return 0; + } + + // Set definitive canvas size. + mux = enc->mux_; + err = WebPMuxSetCanvasSize(mux, enc->canvas_width_, enc->canvas_height_); + if (err != WEBP_MUX_OK) goto Err; + + err = WebPMuxSetAnimationParams(mux, &enc->options_.anim_params); + if (err != WEBP_MUX_OK) goto Err; + + // Assemble into a WebP bitstream. + err = WebPMuxAssemble(mux, webp_data); + if (err != WEBP_MUX_OK) goto Err; + + if (enc->out_frame_count_ == 1) { + err = OptimizeSingleFrame(enc, webp_data); + if (err != WEBP_MUX_OK) goto Err; + } + return 1; + + Err: + MarkError2(enc, "ERROR assembling WebP", err); + return 0; +} + +const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc) { + if (enc == NULL) return NULL; + return enc->error_str_; +} + +WebPMuxError WebPAnimEncoderSetChunk( + WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data, + int copy_data) { + if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return WebPMuxSetChunk(enc->mux_, fourcc, chunk_data, copy_data); +} + +WebPMuxError WebPAnimEncoderGetChunk( + const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data) { + if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return WebPMuxGetChunk(enc->mux_, fourcc, chunk_data); +} + +WebPMuxError WebPAnimEncoderDeleteChunk( + WebPAnimEncoder* enc, const char fourcc[4]) { + if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return WebPMuxDeleteChunk(enc->mux_, fourcc); +} + +// ----------------------------------------------------------------------------- diff --git a/libraries/webp/src/mux/animi.h b/libraries/webp/src/mux/animi.h new file mode 100644 index 00000000000..4fc062508a7 --- /dev/null +++ b/libraries/webp/src/mux/animi.h @@ -0,0 +1,43 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Internal header for animation related functions. +// +// Author: Hui Su (huisu@google.com) + +#ifndef WEBP_MUX_ANIMI_H_ +#define WEBP_MUX_ANIMI_H_ + +#include "include/webp/mux.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Picks the optimal rectangle between two pictures, starting with initial +// values of offsets and dimensions that are passed in. The initial +// values will be clipped, if necessary, to make sure the rectangle is +// within the canvas. "use_argb" must be true for both pictures. +// Parameters: +// prev_canvas, curr_canvas - (in) two input pictures to compare. +// is_lossless, quality - (in) encoding settings. +// x_offset, y_offset, width, height - (in/out) rectangle between the two +// input pictures. +// Returns true on success. +int WebPAnimEncoderRefineRect( + const struct WebPPicture* const prev_canvas, + const struct WebPPicture* const curr_canvas, + int is_lossless, float quality, int* const x_offset, int* const y_offset, + int* const width, int* const height); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_MUX_ANIMI_H_ diff --git a/libraries/webp/src/mux/muxedit.c b/libraries/webp/src/mux/muxedit.c new file mode 100644 index 00000000000..48c6834a4dd --- /dev/null +++ b/libraries/webp/src/mux/muxedit.c @@ -0,0 +1,659 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Set and delete APIs for mux. +// +// Authors: Urvang (urvang@google.com) +// Vikas (vikasa@google.com) + +#include +#include "src/mux/muxi.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// Life of a mux object. + +static void MuxInit(WebPMux* const mux) { + assert(mux != NULL); + memset(mux, 0, sizeof(*mux)); + mux->canvas_width_ = 0; // just to be explicit + mux->canvas_height_ = 0; +} + +WebPMux* WebPNewInternal(int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { + return NULL; + } else { + WebPMux* const mux = (WebPMux*)WebPSafeMalloc(1ULL, sizeof(WebPMux)); + if (mux != NULL) MuxInit(mux); + return mux; + } +} + +// Delete all images in 'wpi_list'. +static void DeleteAllImages(WebPMuxImage** const wpi_list) { + while (*wpi_list != NULL) { + *wpi_list = MuxImageDelete(*wpi_list); + } +} + +static void MuxRelease(WebPMux* const mux) { + assert(mux != NULL); + DeleteAllImages(&mux->images_); + ChunkListDelete(&mux->vp8x_); + ChunkListDelete(&mux->iccp_); + ChunkListDelete(&mux->anim_); + ChunkListDelete(&mux->exif_); + ChunkListDelete(&mux->xmp_); + ChunkListDelete(&mux->unknown_); +} + +void WebPMuxDelete(WebPMux* mux) { + if (mux != NULL) { + MuxRelease(mux); + WebPSafeFree(mux); + } +} + +//------------------------------------------------------------------------------ +// Helper method(s). + +// Handy MACRO, makes MuxSet() very symmetric to MuxGet(). +#define SWITCH_ID_LIST(INDEX, LIST) \ + do { \ + if (idx == (INDEX)) { \ + err = ChunkAssignData(&chunk, data, copy_data, tag); \ + if (err == WEBP_MUX_OK) { \ + err = ChunkSetHead(&chunk, (LIST)); \ + if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \ + } \ + return err; \ + } \ + } while (0) + +static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, + const WebPData* const data, int copy_data) { + WebPChunk chunk; + WebPMuxError err = WEBP_MUX_NOT_FOUND; + const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag); + assert(mux != NULL); + assert(!IsWPI(kChunks[idx].id)); + + ChunkInit(&chunk); + SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_); + SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_); + SWITCH_ID_LIST(IDX_ANIM, &mux->anim_); + SWITCH_ID_LIST(IDX_EXIF, &mux->exif_); + SWITCH_ID_LIST(IDX_XMP, &mux->xmp_); + SWITCH_ID_LIST(IDX_UNKNOWN, &mux->unknown_); + return err; +} +#undef SWITCH_ID_LIST + +// Create data for frame given image data, offsets and duration. +static WebPMuxError CreateFrameData( + int width, int height, const WebPMuxFrameInfo* const info, + WebPData* const frame) { + uint8_t* frame_bytes; + const size_t frame_size = kChunks[IDX_ANMF].size; + + assert(width > 0 && height > 0 && info->duration >= 0); + assert(info->dispose_method == (info->dispose_method & 1)); + // Note: assertion on upper bounds is done in PutLE24(). + + frame_bytes = (uint8_t*)WebPSafeMalloc(1ULL, frame_size); + if (frame_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; + + PutLE24(frame_bytes + 0, info->x_offset / 2); + PutLE24(frame_bytes + 3, info->y_offset / 2); + + PutLE24(frame_bytes + 6, width - 1); + PutLE24(frame_bytes + 9, height - 1); + PutLE24(frame_bytes + 12, info->duration); + frame_bytes[15] = + (info->blend_method == WEBP_MUX_NO_BLEND ? 2 : 0) | + (info->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? 1 : 0); + + frame->bytes = frame_bytes; + frame->size = frame_size; + return WEBP_MUX_OK; +} + +// Outputs image data given a bitstream. The bitstream can either be a +// single-image WebP file or raw VP8/VP8L data. +// Also outputs 'is_lossless' to be true if the given bitstream is lossless. +static WebPMuxError GetImageData(const WebPData* const bitstream, + WebPData* const image, WebPData* const alpha, + int* const is_lossless) { + WebPDataInit(alpha); // Default: no alpha. + if (bitstream->size < TAG_SIZE || + memcmp(bitstream->bytes, "RIFF", TAG_SIZE)) { + // It is NOT webp file data. Return input data as is. + *image = *bitstream; + } else { + // It is webp file data. Extract image data from it. + const WebPMuxImage* wpi; + WebPMux* const mux = WebPMuxCreate(bitstream, 0); + if (mux == NULL) return WEBP_MUX_BAD_DATA; + wpi = mux->images_; + assert(wpi != NULL && wpi->img_ != NULL); + *image = wpi->img_->data_; + if (wpi->alpha_ != NULL) { + *alpha = wpi->alpha_->data_; + } + WebPMuxDelete(mux); + } + *is_lossless = VP8LCheckSignature(image->bytes, image->size); + return WEBP_MUX_OK; +} + +static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) { + WebPMuxError err = WEBP_MUX_NOT_FOUND; + assert(chunk_list); + while (*chunk_list) { + WebPChunk* const chunk = *chunk_list; + if (chunk->tag_ == tag) { + *chunk_list = ChunkDelete(chunk); + err = WEBP_MUX_OK; + } else { + chunk_list = &chunk->next_; + } + } + return err; +} + +static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, uint32_t tag) { + const WebPChunkId id = ChunkGetIdFromTag(tag); + assert(mux != NULL); + if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT; + return DeleteChunks(MuxGetChunkListFromId(mux, id), tag); +} + +//------------------------------------------------------------------------------ +// Set API(s). + +WebPMuxError WebPMuxSetChunk(WebPMux* mux, const char fourcc[4], + const WebPData* chunk_data, int copy_data) { + uint32_t tag; + WebPMuxError err; + if (mux == NULL || fourcc == NULL || chunk_data == NULL || + chunk_data->bytes == NULL || chunk_data->size > MAX_CHUNK_PAYLOAD) { + return WEBP_MUX_INVALID_ARGUMENT; + } + tag = ChunkGetTagFromFourCC(fourcc); + + // Delete existing chunk(s) with the same 'fourcc'. + err = MuxDeleteAllNamedData(mux, tag); + if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; + + // Add the given chunk. + return MuxSet(mux, tag, chunk_data, copy_data); +} + +// Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'. +static WebPMuxError AddDataToChunkList( + const WebPData* const data, int copy_data, uint32_t tag, + WebPChunk** chunk_list) { + WebPChunk chunk; + WebPMuxError err; + ChunkInit(&chunk); + err = ChunkAssignData(&chunk, data, copy_data, tag); + if (err != WEBP_MUX_OK) goto Err; + err = ChunkSetHead(&chunk, chunk_list); + if (err != WEBP_MUX_OK) goto Err; + return WEBP_MUX_OK; + Err: + ChunkRelease(&chunk); + return err; +} + +// Extracts image & alpha data from the given bitstream and then sets wpi.alpha_ +// and wpi.img_ appropriately. +static WebPMuxError SetAlphaAndImageChunks( + const WebPData* const bitstream, int copy_data, WebPMuxImage* const wpi) { + int is_lossless = 0; + WebPData image, alpha; + WebPMuxError err = GetImageData(bitstream, &image, &alpha, &is_lossless); + const int image_tag = + is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; + if (err != WEBP_MUX_OK) return err; + if (alpha.bytes != NULL) { + err = AddDataToChunkList(&alpha, copy_data, kChunks[IDX_ALPHA].tag, + &wpi->alpha_); + if (err != WEBP_MUX_OK) return err; + } + err = AddDataToChunkList(&image, copy_data, image_tag, &wpi->img_); + if (err != WEBP_MUX_OK) return err; + return MuxImageFinalize(wpi) ? WEBP_MUX_OK : WEBP_MUX_INVALID_ARGUMENT; +} + +WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream, + int copy_data) { + WebPMuxImage wpi; + WebPMuxError err; + + if (mux == NULL || bitstream == NULL || bitstream->bytes == NULL || + bitstream->size > MAX_CHUNK_PAYLOAD) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + if (mux->images_ != NULL) { + // Only one 'simple image' can be added in mux. So, remove present images. + DeleteAllImages(&mux->images_); + } + + MuxImageInit(&wpi); + err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi); + if (err != WEBP_MUX_OK) goto Err; + + // Add this WebPMuxImage to mux. + err = MuxImagePush(&wpi, &mux->images_); + if (err != WEBP_MUX_OK) goto Err; + + // All is well. + return WEBP_MUX_OK; + + Err: // Something bad happened. + MuxImageRelease(&wpi); + return err; +} + +WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info, + int copy_data) { + WebPMuxImage wpi; + WebPMuxError err; + + if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT; + + if (info->bitstream.bytes == NULL || + info->bitstream.size > MAX_CHUNK_PAYLOAD) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + if (mux->images_ != NULL) { + const WebPMuxImage* const image = mux->images_; + const uint32_t image_id = (image->header_ != NULL) ? + ChunkGetIdFromTag(image->header_->tag_) : WEBP_CHUNK_IMAGE; + if (image_id != info->id) { + return WEBP_MUX_INVALID_ARGUMENT; // Conflicting frame types. + } + } + + MuxImageInit(&wpi); + err = SetAlphaAndImageChunks(&info->bitstream, copy_data, &wpi); + if (err != WEBP_MUX_OK) goto Err; + assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful. + + { + WebPData frame; + const uint32_t tag = kChunks[IDX_ANMF].tag; + WebPMuxFrameInfo tmp = *info; + tmp.x_offset &= ~1; // Snap offsets to even. + tmp.y_offset &= ~1; + if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET || + tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET || + (tmp.duration < 0 || tmp.duration >= MAX_DURATION) || + tmp.dispose_method != (tmp.dispose_method & 1)) { + err = WEBP_MUX_INVALID_ARGUMENT; + goto Err; + } + err = CreateFrameData(wpi.width_, wpi.height_, &tmp, &frame); + if (err != WEBP_MUX_OK) goto Err; + // Add frame chunk (with copy_data = 1). + err = AddDataToChunkList(&frame, 1, tag, &wpi.header_); + WebPDataClear(&frame); // frame owned by wpi.header_ now. + if (err != WEBP_MUX_OK) goto Err; + } + + // Add this WebPMuxImage to mux. + err = MuxImagePush(&wpi, &mux->images_); + if (err != WEBP_MUX_OK) goto Err; + + // All is well. + return WEBP_MUX_OK; + + Err: // Something bad happened. + MuxImageRelease(&wpi); + return err; +} + +WebPMuxError WebPMuxSetAnimationParams(WebPMux* mux, + const WebPMuxAnimParams* params) { + WebPMuxError err; + uint8_t data[ANIM_CHUNK_SIZE]; + const WebPData anim = { data, ANIM_CHUNK_SIZE }; + + if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT; + if (params->loop_count < 0 || params->loop_count >= MAX_LOOP_COUNT) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // Delete any existing ANIM chunk(s). + err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag); + if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; + + // Set the animation parameters. + PutLE32(data, params->bgcolor); + PutLE16(data + 4, params->loop_count); + return MuxSet(mux, kChunks[IDX_ANIM].tag, &anim, 1); +} + +WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux, + int width, int height) { + WebPMuxError err; + if (mux == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if (width < 0 || height < 0 || + width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if (width * (uint64_t)height >= MAX_IMAGE_AREA) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if ((width * height) == 0 && (width | height) != 0) { + // one of width / height is zero, but not both -> invalid! + return WEBP_MUX_INVALID_ARGUMENT; + } + // If we already assembled a VP8X chunk, invalidate it. + err = MuxDeleteAllNamedData(mux, kChunks[IDX_VP8X].tag); + if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; + + mux->canvas_width_ = width; + mux->canvas_height_ = height; + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ +// Delete API(s). + +WebPMuxError WebPMuxDeleteChunk(WebPMux* mux, const char fourcc[4]) { + if (mux == NULL || fourcc == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return MuxDeleteAllNamedData(mux, ChunkGetTagFromFourCC(fourcc)); +} + +WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) { + if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return MuxImageDeleteNth(&mux->images_, nth); +} + +//------------------------------------------------------------------------------ +// Assembly of the WebP RIFF file. + +static WebPMuxError GetFrameInfo( + const WebPChunk* const frame_chunk, + int* const x_offset, int* const y_offset, int* const duration) { + const WebPData* const data = &frame_chunk->data_; + const size_t expected_data_size = ANMF_CHUNK_SIZE; + assert(frame_chunk->tag_ == kChunks[IDX_ANMF].tag); + assert(frame_chunk != NULL); + if (data->size != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT; + + *x_offset = 2 * GetLE24(data->bytes + 0); + *y_offset = 2 * GetLE24(data->bytes + 3); + *duration = GetLE24(data->bytes + 12); + return WEBP_MUX_OK; +} + +static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi, + int* const x_offset, int* const y_offset, + int* const duration, + int* const width, int* const height) { + const WebPChunk* const frame_chunk = wpi->header_; + WebPMuxError err; + assert(wpi != NULL); + assert(frame_chunk != NULL); + + // Get offsets and duration from ANMF chunk. + err = GetFrameInfo(frame_chunk, x_offset, y_offset, duration); + if (err != WEBP_MUX_OK) return err; + + // Get width and height from VP8/VP8L chunk. + if (width != NULL) *width = wpi->width_; + if (height != NULL) *height = wpi->height_; + return WEBP_MUX_OK; +} + +// Returns the tightest dimension for the canvas considering the image list. +static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux, + int* const width, int* const height) { + WebPMuxImage* wpi = NULL; + assert(mux != NULL); + assert(width != NULL && height != NULL); + + wpi = mux->images_; + assert(wpi != NULL); + assert(wpi->img_ != NULL); + + if (wpi->next_ != NULL) { + int max_x = 0, max_y = 0; + // if we have a chain of wpi's, header_ is necessarily set + assert(wpi->header_ != NULL); + // Aggregate the bounding box for animation frames. + for (; wpi != NULL; wpi = wpi->next_) { + int x_offset = 0, y_offset = 0, duration = 0, w = 0, h = 0; + const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset, + &duration, &w, &h); + const int max_x_pos = x_offset + w; + const int max_y_pos = y_offset + h; + if (err != WEBP_MUX_OK) return err; + assert(x_offset < MAX_POSITION_OFFSET); + assert(y_offset < MAX_POSITION_OFFSET); + + if (max_x_pos > max_x) max_x = max_x_pos; + if (max_y_pos > max_y) max_y = max_y_pos; + } + *width = max_x; + *height = max_y; + } else { + // For a single image, canvas dimensions are same as image dimensions. + *width = wpi->width_; + *height = wpi->height_; + } + return WEBP_MUX_OK; +} + +// VP8X format: +// Total Size : 10, +// Flags : 4 bytes, +// Width : 3 bytes, +// Height : 3 bytes. +static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { + WebPMuxError err = WEBP_MUX_OK; + uint32_t flags = 0; + int width = 0; + int height = 0; + uint8_t data[VP8X_CHUNK_SIZE]; + const WebPData vp8x = { data, VP8X_CHUNK_SIZE }; + const WebPMuxImage* images = NULL; + + assert(mux != NULL); + images = mux->images_; // First image. + if (images == NULL || images->img_ == NULL || + images->img_->data_.bytes == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // If VP8X chunk(s) is(are) already present, remove them (and later add new + // VP8X chunk with updated flags). + err = MuxDeleteAllNamedData(mux, kChunks[IDX_VP8X].tag); + if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; + + // Set flags. + if (mux->iccp_ != NULL && mux->iccp_->data_.bytes != NULL) { + flags |= ICCP_FLAG; + } + if (mux->exif_ != NULL && mux->exif_->data_.bytes != NULL) { + flags |= EXIF_FLAG; + } + if (mux->xmp_ != NULL && mux->xmp_->data_.bytes != NULL) { + flags |= XMP_FLAG; + } + if (images->header_ != NULL) { + if (images->header_->tag_ == kChunks[IDX_ANMF].tag) { + // This is an image with animation. + flags |= ANIMATION_FLAG; + } + } + if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) { + flags |= ALPHA_FLAG; // Some images have an alpha channel. + } + + err = GetAdjustedCanvasSize(mux, &width, &height); + if (err != WEBP_MUX_OK) return err; + + if (width <= 0 || height <= 0) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if (width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + if (mux->canvas_width_ != 0 || mux->canvas_height_ != 0) { + if (width > mux->canvas_width_ || height > mux->canvas_height_) { + return WEBP_MUX_INVALID_ARGUMENT; + } + width = mux->canvas_width_; + height = mux->canvas_height_; + } + + if (flags == 0 && mux->unknown_ == NULL) { + // For simple file format, VP8X chunk should not be added. + return WEBP_MUX_OK; + } + + if (MuxHasAlpha(images)) { + // This means some frames explicitly/implicitly contain alpha. + // Note: This 'flags' update must NOT be done for a lossless image + // without a VP8X chunk! + flags |= ALPHA_FLAG; + } + + PutLE32(data + 0, flags); // VP8X chunk flags. + PutLE24(data + 4, width - 1); // canvas width. + PutLE24(data + 7, height - 1); // canvas height. + + return MuxSet(mux, kChunks[IDX_VP8X].tag, &vp8x, 1); +} + +// Cleans up 'mux' by removing any unnecessary chunks. +static WebPMuxError MuxCleanup(WebPMux* const mux) { + int num_frames; + int num_anim_chunks; + + // If we have an image with a single frame, and its rectangle + // covers the whole canvas, convert it to a non-animated image + // (to avoid writing ANMF chunk unnecessarily). + WebPMuxError err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames); + if (err != WEBP_MUX_OK) return err; + if (num_frames == 1) { + WebPMuxImage* frame = NULL; + err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame); + if (err != WEBP_MUX_OK) return err; + // We know that one frame does exist. + assert(frame != NULL); + if (frame->header_ != NULL && + ((mux->canvas_width_ == 0 && mux->canvas_height_ == 0) || + (frame->width_ == mux->canvas_width_ && + frame->height_ == mux->canvas_height_))) { + assert(frame->header_->tag_ == kChunks[IDX_ANMF].tag); + ChunkDelete(frame->header_); // Removes ANMF chunk. + frame->header_ = NULL; + num_frames = 0; + } + } + // Remove ANIM chunk if this is a non-animated image. + err = WebPMuxNumChunks(mux, kChunks[IDX_ANIM].id, &num_anim_chunks); + if (err != WEBP_MUX_OK) return err; + if (num_anim_chunks >= 1 && num_frames == 0) { + err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag); + if (err != WEBP_MUX_OK) return err; + } + return WEBP_MUX_OK; +} + +// Total size of a list of images. +static size_t ImageListDiskSize(const WebPMuxImage* wpi_list) { + size_t size = 0; + while (wpi_list != NULL) { + size += MuxImageDiskSize(wpi_list); + wpi_list = wpi_list->next_; + } + return size; +} + +// Write out the given list of images into 'dst'. +static uint8_t* ImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) { + while (wpi_list != NULL) { + dst = MuxImageEmit(wpi_list, dst); + wpi_list = wpi_list->next_; + } + return dst; +} + +WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { + size_t size = 0; + uint8_t* data = NULL; + uint8_t* dst = NULL; + WebPMuxError err; + + if (assembled_data == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + // Clean up returned data, in case something goes wrong. + memset(assembled_data, 0, sizeof(*assembled_data)); + + if (mux == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // Finalize mux. + err = MuxCleanup(mux); + if (err != WEBP_MUX_OK) return err; + err = CreateVP8XChunk(mux); + if (err != WEBP_MUX_OK) return err; + + // Allocate data. + size = ChunkListDiskSize(mux->vp8x_) + ChunkListDiskSize(mux->iccp_) + + ChunkListDiskSize(mux->anim_) + ImageListDiskSize(mux->images_) + + ChunkListDiskSize(mux->exif_) + ChunkListDiskSize(mux->xmp_) + + ChunkListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE; + + data = (uint8_t*)WebPSafeMalloc(1ULL, size); + if (data == NULL) return WEBP_MUX_MEMORY_ERROR; + + // Emit header & chunks. + dst = MuxEmitRiffHeader(data, size); + dst = ChunkListEmit(mux->vp8x_, dst); + dst = ChunkListEmit(mux->iccp_, dst); + dst = ChunkListEmit(mux->anim_, dst); + dst = ImageListEmit(mux->images_, dst); + dst = ChunkListEmit(mux->exif_, dst); + dst = ChunkListEmit(mux->xmp_, dst); + dst = ChunkListEmit(mux->unknown_, dst); + assert(dst == data + size); + + // Validate mux. + err = MuxValidate(mux); + if (err != WEBP_MUX_OK) { + WebPSafeFree(data); + data = NULL; + size = 0; + } + + // Finalize data. + assembled_data->bytes = data; + assembled_data->size = size; + + return err; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/mux/muxi.h b/libraries/webp/src/mux/muxi.h new file mode 100644 index 00000000000..c0fb867b949 --- /dev/null +++ b/libraries/webp/src/mux/muxi.h @@ -0,0 +1,234 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Internal header for mux library. +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_MUX_MUXI_H_ +#define WEBP_MUX_MUXI_H_ + +#include +#include +#include "src/dec/vp8i_dec.h" +#include "src/dec/vp8li_dec.h" +#include "include/webp/mux.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Defines and constants. + +#define MUX_MAJ_VERSION 1 +#define MUX_MIN_VERSION 3 +#define MUX_REV_VERSION 2 + +// Chunk object. +typedef struct WebPChunk WebPChunk; +struct WebPChunk { + uint32_t tag_; + int owner_; // True if *data_ memory is owned internally. + // VP8X, ANIM, and other internally created chunks + // like ANMF are always owned. + WebPData data_; + WebPChunk* next_; +}; + +// MuxImage object. Store a full WebP image (including ANMF chunk, ALPH +// chunk and VP8/VP8L chunk), +typedef struct WebPMuxImage WebPMuxImage; +struct WebPMuxImage { + WebPChunk* header_; // Corresponds to WEBP_CHUNK_ANMF. + WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA. + WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE. + WebPChunk* unknown_; // Corresponds to WEBP_CHUNK_UNKNOWN. + int width_; + int height_; + int has_alpha_; // Through ALPH chunk or as part of VP8L. + int is_partial_; // True if only some of the chunks are filled. + WebPMuxImage* next_; +}; + +// Main mux object. Stores data chunks. +struct WebPMux { + WebPMuxImage* images_; + WebPChunk* iccp_; + WebPChunk* exif_; + WebPChunk* xmp_; + WebPChunk* anim_; + WebPChunk* vp8x_; + + WebPChunk* unknown_; + int canvas_width_; + int canvas_height_; +}; + +// CHUNK_INDEX enum: used for indexing within 'kChunks' (defined below) only. +// Note: the reason for having two enums ('WebPChunkId' and 'CHUNK_INDEX') is to +// allow two different chunks to have the same id (e.g. WebPChunkId +// 'WEBP_CHUNK_IMAGE' can correspond to CHUNK_INDEX 'IDX_VP8' or 'IDX_VP8L'). +typedef enum { + IDX_VP8X = 0, + IDX_ICCP, + IDX_ANIM, + IDX_ANMF, + IDX_ALPHA, + IDX_VP8, + IDX_VP8L, + IDX_EXIF, + IDX_XMP, + IDX_UNKNOWN, + + IDX_NIL, + IDX_LAST_CHUNK +} CHUNK_INDEX; + +#define NIL_TAG 0x00000000u // To signal void chunk. + +typedef struct { + uint32_t tag; + WebPChunkId id; + uint32_t size; +} ChunkInfo; + +extern const ChunkInfo kChunks[IDX_LAST_CHUNK]; + +//------------------------------------------------------------------------------ +// Chunk object management. + +// Initialize. +void ChunkInit(WebPChunk* const chunk); + +// Get chunk index from chunk tag. Returns IDX_UNKNOWN if not found. +CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag); + +// Get chunk id from chunk tag. Returns WEBP_CHUNK_UNKNOWN if not found. +WebPChunkId ChunkGetIdFromTag(uint32_t tag); + +// Convert a fourcc string to a tag. +uint32_t ChunkGetTagFromFourCC(const char fourcc[4]); + +// Get chunk index from fourcc. Returns IDX_UNKNOWN if given fourcc is unknown. +CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]); + +// Search for nth chunk with given 'tag' in the chunk list. +// nth = 0 means "last of the list". +WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag); + +// Fill the chunk with the given data. +WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, + int copy_data, uint32_t tag); + +// Sets 'chunk' as the only element in 'chunk_list' if it is empty. +// On success ownership is transferred from 'chunk' to the 'chunk_list'. +WebPMuxError ChunkSetHead(WebPChunk* const chunk, WebPChunk** const chunk_list); +// Sets 'chunk' at last position in the 'chunk_list'. +// On success ownership is transferred from 'chunk' to the 'chunk_list'. +// *chunk_list also points towards the last valid element of the initial +// *chunk_list. +WebPMuxError ChunkAppend(WebPChunk* const chunk, WebPChunk*** const chunk_list); + +// Releases chunk and returns chunk->next_. +WebPChunk* ChunkRelease(WebPChunk* const chunk); + +// Deletes given chunk & returns chunk->next_. +WebPChunk* ChunkDelete(WebPChunk* const chunk); + +// Deletes all chunks in the given chunk list. +void ChunkListDelete(WebPChunk** const chunk_list); + +// Returns size of the chunk including chunk header and padding byte (if any). +static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) { + assert(chunk_size <= MAX_CHUNK_PAYLOAD); + return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U); +} + +// Size of a chunk including header and padding. +static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) { + const size_t data_size = chunk->data_.size; + return SizeWithPadding(data_size); +} + +// Total size of a list of chunks. +size_t ChunkListDiskSize(const WebPChunk* chunk_list); + +// Write out the given list of chunks into 'dst'. +uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst); + +//------------------------------------------------------------------------------ +// MuxImage object management. + +// Initialize. +void MuxImageInit(WebPMuxImage* const wpi); + +// Releases image 'wpi' and returns wpi->next. +WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi); + +// Delete image 'wpi' and return the next image in the list or NULL. +// 'wpi' can be NULL. +WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi); + +// Count number of images matching the given tag id in the 'wpi_list'. +// If id == WEBP_CHUNK_NIL, all images will be matched. +int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id); + +// Update width/height/has_alpha info from chunks within wpi. +// Also remove ALPH chunk if not needed. +int MuxImageFinalize(WebPMuxImage* const wpi); + +// Check if given ID corresponds to an image related chunk. +static WEBP_INLINE int IsWPI(WebPChunkId id) { + switch (id) { + case WEBP_CHUNK_ANMF: + case WEBP_CHUNK_ALPHA: + case WEBP_CHUNK_IMAGE: return 1; + default: return 0; + } +} + +// Pushes 'wpi' at the end of 'wpi_list'. +WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list); + +// Delete nth image in the image list. +WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth); + +// Get nth image in the image list. +WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, + WebPMuxImage** wpi); + +// Total size of the given image. +size_t MuxImageDiskSize(const WebPMuxImage* const wpi); + +// Write out the given image into 'dst'. +uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst); + +//------------------------------------------------------------------------------ +// Helper methods for mux. + +// Checks if the given image list contains at least one image with alpha. +int MuxHasAlpha(const WebPMuxImage* images); + +// Write out RIFF header into 'data', given total data size 'size'. +uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size); + +// Returns the list where chunk with given ID is to be inserted in mux. +WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id); + +// Validates the given mux object. +WebPMuxError MuxValidate(const WebPMux* const mux); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_MUX_MUXI_H_ diff --git a/libraries/webp/src/mux/muxinternal.c b/libraries/webp/src/mux/muxinternal.c new file mode 100644 index 00000000000..75b6b416b99 --- /dev/null +++ b/libraries/webp/src/mux/muxinternal.c @@ -0,0 +1,549 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Internal objects and utils for mux. +// +// Authors: Urvang (urvang@google.com) +// Vikas (vikasa@google.com) + +#include +#include "src/mux/muxi.h" +#include "src/utils/utils.h" + +#define UNDEFINED_CHUNK_SIZE ((uint32_t)(-1)) + +const ChunkInfo kChunks[] = { + { MKFOURCC('V', 'P', '8', 'X'), WEBP_CHUNK_VP8X, VP8X_CHUNK_SIZE }, + { MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('A', 'N', 'I', 'M'), WEBP_CHUNK_ANIM, ANIM_CHUNK_SIZE }, + { MKFOURCC('A', 'N', 'M', 'F'), WEBP_CHUNK_ANMF, ANMF_CHUNK_SIZE }, + { MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('E', 'X', 'I', 'F'), WEBP_CHUNK_EXIF, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('X', 'M', 'P', ' '), WEBP_CHUNK_XMP, UNDEFINED_CHUNK_SIZE }, + { NIL_TAG, WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE }, + + { NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE } +}; + +//------------------------------------------------------------------------------ + +int WebPGetMuxVersion(void) { + return (MUX_MAJ_VERSION << 16) | (MUX_MIN_VERSION << 8) | MUX_REV_VERSION; +} + +//------------------------------------------------------------------------------ +// Life of a chunk object. + +void ChunkInit(WebPChunk* const chunk) { + assert(chunk); + memset(chunk, 0, sizeof(*chunk)); + chunk->tag_ = NIL_TAG; +} + +WebPChunk* ChunkRelease(WebPChunk* const chunk) { + WebPChunk* next; + if (chunk == NULL) return NULL; + if (chunk->owner_) { + WebPDataClear(&chunk->data_); + } + next = chunk->next_; + ChunkInit(chunk); + return next; +} + +//------------------------------------------------------------------------------ +// Chunk misc methods. + +CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag) { + int i; + for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { + if (tag == kChunks[i].tag) return (CHUNK_INDEX)i; + } + return IDX_UNKNOWN; +} + +WebPChunkId ChunkGetIdFromTag(uint32_t tag) { + int i; + for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { + if (tag == kChunks[i].tag) return kChunks[i].id; + } + return WEBP_CHUNK_UNKNOWN; +} + +uint32_t ChunkGetTagFromFourCC(const char fourcc[4]) { + return MKFOURCC(fourcc[0], fourcc[1], fourcc[2], fourcc[3]); +} + +CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]) { + const uint32_t tag = ChunkGetTagFromFourCC(fourcc); + return ChunkGetIndexFromTag(tag); +} + +//------------------------------------------------------------------------------ +// Chunk search methods. + +// Returns next chunk in the chunk list with the given tag. +static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) { + while (chunk != NULL && chunk->tag_ != tag) { + chunk = chunk->next_; + } + return chunk; +} + +WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) { + uint32_t iter = nth; + first = ChunkSearchNextInList(first, tag); + if (first == NULL) return NULL; + + while (--iter != 0) { + WebPChunk* next_chunk = ChunkSearchNextInList(first->next_, tag); + if (next_chunk == NULL) break; + first = next_chunk; + } + return ((nth > 0) && (iter > 0)) ? NULL : first; +} + +//------------------------------------------------------------------------------ +// Chunk writer methods. + +WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, + int copy_data, uint32_t tag) { + // For internally allocated chunks, always copy data & make it owner of data. + if (tag == kChunks[IDX_VP8X].tag || tag == kChunks[IDX_ANIM].tag) { + copy_data = 1; + } + + ChunkRelease(chunk); + + if (data != NULL) { + if (copy_data) { // Copy data. + if (!WebPDataCopy(data, &chunk->data_)) return WEBP_MUX_MEMORY_ERROR; + chunk->owner_ = 1; // Chunk is owner of data. + } else { // Don't copy data. + chunk->data_ = *data; + } + } + chunk->tag_ = tag; + return WEBP_MUX_OK; +} + +WebPMuxError ChunkSetHead(WebPChunk* const chunk, + WebPChunk** const chunk_list) { + WebPChunk* new_chunk; + + assert(chunk_list != NULL); + if (*chunk_list != NULL) { + return WEBP_MUX_NOT_FOUND; + } + + new_chunk = (WebPChunk*)WebPSafeMalloc(1ULL, sizeof(*new_chunk)); + if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR; + *new_chunk = *chunk; + chunk->owner_ = 0; + new_chunk->next_ = NULL; + *chunk_list = new_chunk; + return WEBP_MUX_OK; +} + +WebPMuxError ChunkAppend(WebPChunk* const chunk, + WebPChunk*** const chunk_list) { + WebPMuxError err; + assert(chunk_list != NULL && *chunk_list != NULL); + + if (**chunk_list == NULL) { + err = ChunkSetHead(chunk, *chunk_list); + } else { + WebPChunk* last_chunk = **chunk_list; + while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_; + err = ChunkSetHead(chunk, &last_chunk->next_); + if (err == WEBP_MUX_OK) *chunk_list = &last_chunk->next_; + } + return err; +} + +//------------------------------------------------------------------------------ +// Chunk deletion method(s). + +WebPChunk* ChunkDelete(WebPChunk* const chunk) { + WebPChunk* const next = ChunkRelease(chunk); + WebPSafeFree(chunk); + return next; +} + +void ChunkListDelete(WebPChunk** const chunk_list) { + while (*chunk_list != NULL) { + *chunk_list = ChunkDelete(*chunk_list); + } +} + +//------------------------------------------------------------------------------ +// Chunk serialization methods. + +static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) { + const size_t chunk_size = chunk->data_.size; + assert(chunk); + assert(chunk->tag_ != NIL_TAG); + PutLE32(dst + 0, chunk->tag_); + PutLE32(dst + TAG_SIZE, (uint32_t)chunk_size); + assert(chunk_size == (uint32_t)chunk_size); + memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_.bytes, chunk_size); + if (chunk_size & 1) + dst[CHUNK_HEADER_SIZE + chunk_size] = 0; // Add padding. + return dst + ChunkDiskSize(chunk); +} + +uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) { + while (chunk_list != NULL) { + dst = ChunkEmit(chunk_list, dst); + chunk_list = chunk_list->next_; + } + return dst; +} + +size_t ChunkListDiskSize(const WebPChunk* chunk_list) { + size_t size = 0; + while (chunk_list != NULL) { + size += ChunkDiskSize(chunk_list); + chunk_list = chunk_list->next_; + } + return size; +} + +//------------------------------------------------------------------------------ +// Life of a MuxImage object. + +void MuxImageInit(WebPMuxImage* const wpi) { + assert(wpi); + memset(wpi, 0, sizeof(*wpi)); +} + +WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) { + WebPMuxImage* next; + if (wpi == NULL) return NULL; + // There should be at most one chunk of header_, alpha_, img_ but we call + // ChunkListDelete to be safe + ChunkListDelete(&wpi->header_); + ChunkListDelete(&wpi->alpha_); + ChunkListDelete(&wpi->img_); + ChunkListDelete(&wpi->unknown_); + + next = wpi->next_; + MuxImageInit(wpi); + return next; +} + +//------------------------------------------------------------------------------ +// MuxImage search methods. + +// Get a reference to appropriate chunk list within an image given chunk tag. +static WebPChunk** GetChunkListFromId(const WebPMuxImage* const wpi, + WebPChunkId id) { + assert(wpi != NULL); + switch (id) { + case WEBP_CHUNK_ANMF: return (WebPChunk**)&wpi->header_; + case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_; + case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_; + default: return NULL; + } +} + +int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) { + int count = 0; + const WebPMuxImage* current; + for (current = wpi_list; current != NULL; current = current->next_) { + if (id == WEBP_CHUNK_NIL) { + ++count; // Special case: count all images. + } else { + const WebPChunk* const wpi_chunk = *GetChunkListFromId(current, id); + if (wpi_chunk != NULL) { + const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); + if (wpi_chunk_id == id) ++count; // Count images with a matching 'id'. + } + } + } + return count; +} + +// Outputs a pointer to 'prev_wpi->next_', +// where 'prev_wpi' is the pointer to the image at position (nth - 1). +// Returns true if nth image was found. +static int SearchImageToGetOrDelete(WebPMuxImage** wpi_list, uint32_t nth, + WebPMuxImage*** const location) { + uint32_t count = 0; + assert(wpi_list); + *location = wpi_list; + + if (nth == 0) { + nth = MuxImageCount(*wpi_list, WEBP_CHUNK_NIL); + if (nth == 0) return 0; // Not found. + } + + while (*wpi_list != NULL) { + WebPMuxImage* const cur_wpi = *wpi_list; + ++count; + if (count == nth) return 1; // Found. + wpi_list = &cur_wpi->next_; + *location = wpi_list; + } + return 0; // Not found. +} + +//------------------------------------------------------------------------------ +// MuxImage writer methods. + +WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) { + WebPMuxImage* new_wpi; + + while (*wpi_list != NULL) { + WebPMuxImage* const cur_wpi = *wpi_list; + if (cur_wpi->next_ == NULL) break; + wpi_list = &cur_wpi->next_; + } + + new_wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*new_wpi)); + if (new_wpi == NULL) return WEBP_MUX_MEMORY_ERROR; + *new_wpi = *wpi; + new_wpi->next_ = NULL; + + if (*wpi_list != NULL) { + (*wpi_list)->next_ = new_wpi; + } else { + *wpi_list = new_wpi; + } + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ +// MuxImage deletion methods. + +WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) { + // Delete the components of wpi. If wpi is NULL this is a noop. + WebPMuxImage* const next = MuxImageRelease(wpi); + WebPSafeFree(wpi); + return next; +} + +WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth) { + assert(wpi_list); + if (!SearchImageToGetOrDelete(wpi_list, nth, &wpi_list)) { + return WEBP_MUX_NOT_FOUND; + } + *wpi_list = MuxImageDelete(*wpi_list); + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ +// MuxImage reader methods. + +WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, + WebPMuxImage** wpi) { + assert(wpi_list); + assert(wpi); + if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, + (WebPMuxImage***)&wpi_list)) { + return WEBP_MUX_NOT_FOUND; + } + *wpi = (WebPMuxImage*)*wpi_list; + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ +// MuxImage serialization methods. + +// Size of an image. +size_t MuxImageDiskSize(const WebPMuxImage* const wpi) { + size_t size = 0; + if (wpi->header_ != NULL) size += ChunkDiskSize(wpi->header_); + if (wpi->alpha_ != NULL) size += ChunkDiskSize(wpi->alpha_); + if (wpi->img_ != NULL) size += ChunkDiskSize(wpi->img_); + if (wpi->unknown_ != NULL) size += ChunkListDiskSize(wpi->unknown_); + return size; +} + +// Special case as ANMF chunk encapsulates other image chunks. +static uint8_t* ChunkEmitSpecial(const WebPChunk* const header, + size_t total_size, uint8_t* dst) { + const size_t header_size = header->data_.size; + const size_t offset_to_next = total_size - CHUNK_HEADER_SIZE; + assert(header->tag_ == kChunks[IDX_ANMF].tag); + PutLE32(dst + 0, header->tag_); + PutLE32(dst + TAG_SIZE, (uint32_t)offset_to_next); + assert(header_size == (uint32_t)header_size); + memcpy(dst + CHUNK_HEADER_SIZE, header->data_.bytes, header_size); + if (header_size & 1) { + dst[CHUNK_HEADER_SIZE + header_size] = 0; // Add padding. + } + return dst + ChunkDiskSize(header); +} + +uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) { + // Ordering of chunks to be emitted is strictly as follows: + // 1. ANMF chunk (if present). + // 2. ALPH chunk (if present). + // 3. VP8/VP8L chunk. + assert(wpi); + if (wpi->header_ != NULL) { + dst = ChunkEmitSpecial(wpi->header_, MuxImageDiskSize(wpi), dst); + } + if (wpi->alpha_ != NULL) dst = ChunkEmit(wpi->alpha_, dst); + if (wpi->img_ != NULL) dst = ChunkEmit(wpi->img_, dst); + if (wpi->unknown_ != NULL) dst = ChunkListEmit(wpi->unknown_, dst); + return dst; +} + +//------------------------------------------------------------------------------ +// Helper methods for mux. + +int MuxHasAlpha(const WebPMuxImage* images) { + while (images != NULL) { + if (images->has_alpha_) return 1; + images = images->next_; + } + return 0; +} + +uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size) { + PutLE32(data + 0, MKFOURCC('R', 'I', 'F', 'F')); + PutLE32(data + TAG_SIZE, (uint32_t)size - CHUNK_HEADER_SIZE); + assert(size == (uint32_t)size); + PutLE32(data + TAG_SIZE + CHUNK_SIZE_BYTES, MKFOURCC('W', 'E', 'B', 'P')); + return data + RIFF_HEADER_SIZE; +} + +WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) { + assert(mux != NULL); + switch (id) { + case WEBP_CHUNK_VP8X: return (WebPChunk**)&mux->vp8x_; + case WEBP_CHUNK_ICCP: return (WebPChunk**)&mux->iccp_; + case WEBP_CHUNK_ANIM: return (WebPChunk**)&mux->anim_; + case WEBP_CHUNK_EXIF: return (WebPChunk**)&mux->exif_; + case WEBP_CHUNK_XMP: return (WebPChunk**)&mux->xmp_; + default: return (WebPChunk**)&mux->unknown_; + } +} + +static int IsNotCompatible(int feature, int num_items) { + return (feature != 0) != (num_items > 0); +} + +#define NO_FLAG ((WebPFeatureFlags)0) + +// Test basic constraints: +// retrieval, maximum number of chunks by index (use -1 to skip) +// and feature incompatibility (use NO_FLAG to skip). +// On success returns WEBP_MUX_OK and stores the chunk count in *num. +static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx, + WebPFeatureFlags feature, + uint32_t vp8x_flags, + int max, int* num) { + const WebPMuxError err = + WebPMuxNumChunks(mux, kChunks[idx].id, num); + if (err != WEBP_MUX_OK) return err; + if (max > -1 && *num > max) return WEBP_MUX_INVALID_ARGUMENT; + if (feature != NO_FLAG && IsNotCompatible(vp8x_flags & feature, *num)) { + return WEBP_MUX_INVALID_ARGUMENT; + } + return WEBP_MUX_OK; +} + +WebPMuxError MuxValidate(const WebPMux* const mux) { + int num_iccp; + int num_exif; + int num_xmp; + int num_anim; + int num_frames; + int num_vp8x; + int num_images; + int num_alpha; + uint32_t flags; + WebPMuxError err; + + // Verify mux is not NULL. + if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + // Verify mux has at least one image. + if (mux->images_ == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + err = WebPMuxGetFeatures(mux, &flags); + if (err != WEBP_MUX_OK) return err; + + // At most one color profile chunk. + err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp); + if (err != WEBP_MUX_OK) return err; + + // At most one EXIF metadata. + err = ValidateChunk(mux, IDX_EXIF, EXIF_FLAG, flags, 1, &num_exif); + if (err != WEBP_MUX_OK) return err; + + // At most one XMP metadata. + err = ValidateChunk(mux, IDX_XMP, XMP_FLAG, flags, 1, &num_xmp); + if (err != WEBP_MUX_OK) return err; + + // Animation: ANIMATION_FLAG, ANIM chunk and ANMF chunk(s) are consistent. + // At most one ANIM chunk. + err = ValidateChunk(mux, IDX_ANIM, NO_FLAG, flags, 1, &num_anim); + if (err != WEBP_MUX_OK) return err; + err = ValidateChunk(mux, IDX_ANMF, NO_FLAG, flags, -1, &num_frames); + if (err != WEBP_MUX_OK) return err; + + { + const int has_animation = !!(flags & ANIMATION_FLAG); + if (has_animation && (num_anim == 0 || num_frames == 0)) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if (!has_animation && (num_anim == 1 || num_frames > 0)) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if (!has_animation) { + const WebPMuxImage* images = mux->images_; + // There can be only one image. + if (images == NULL || images->next_ != NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + // Size must match. + if (mux->canvas_width_ > 0) { + if (images->width_ != mux->canvas_width_ || + images->height_ != mux->canvas_height_) { + return WEBP_MUX_INVALID_ARGUMENT; + } + } + } + } + + // Verify either VP8X chunk is present OR there is only one elem in + // mux->images_. + err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x); + if (err != WEBP_MUX_OK) return err; + err = ValidateChunk(mux, IDX_VP8, NO_FLAG, flags, -1, &num_images); + if (err != WEBP_MUX_OK) return err; + if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT; + + // ALPHA_FLAG & alpha chunk(s) are consistent. + // Note: ALPHA_FLAG can be set when there is actually no Alpha data present. + if (MuxHasAlpha(mux->images_)) { + if (num_vp8x > 0) { + // VP8X chunk is present, so it should contain ALPHA_FLAG. + if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT; + } else { + // VP8X chunk is not present, so ALPH chunks should NOT be present either. + err = WebPMuxNumChunks(mux, WEBP_CHUNK_ALPHA, &num_alpha); + if (err != WEBP_MUX_OK) return err; + if (num_alpha > 0) return WEBP_MUX_INVALID_ARGUMENT; + } + } + + return WEBP_MUX_OK; +} + +#undef NO_FLAG + +//------------------------------------------------------------------------------ + diff --git a/libraries/webp/src/mux/muxread.c b/libraries/webp/src/mux/muxread.c new file mode 100644 index 00000000000..afd3542e124 --- /dev/null +++ b/libraries/webp/src/mux/muxread.c @@ -0,0 +1,561 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Read APIs for mux. +// +// Authors: Urvang (urvang@google.com) +// Vikas (vikasa@google.com) + +#include +#include "src/mux/muxi.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// Helper method(s). + +// Handy MACRO. +#define SWITCH_ID_LIST(INDEX, LIST) \ + do { \ + if (idx == (INDEX)) { \ + const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \ + kChunks[(INDEX)].tag); \ + if (chunk) { \ + *data = chunk->data_; \ + return WEBP_MUX_OK; \ + } else { \ + return WEBP_MUX_NOT_FOUND; \ + } \ + } \ + } while (0) + +static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx, + uint32_t nth, WebPData* const data) { + assert(mux != NULL); + assert(idx != IDX_LAST_CHUNK); + assert(!IsWPI(kChunks[idx].id)); + WebPDataInit(data); + + SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_); + SWITCH_ID_LIST(IDX_ICCP, mux->iccp_); + SWITCH_ID_LIST(IDX_ANIM, mux->anim_); + SWITCH_ID_LIST(IDX_EXIF, mux->exif_); + SWITCH_ID_LIST(IDX_XMP, mux->xmp_); + assert(idx != IDX_UNKNOWN); + return WEBP_MUX_NOT_FOUND; +} +#undef SWITCH_ID_LIST + +// Fill the chunk with the given data (includes chunk header bytes), after some +// verifications. +static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk, + const uint8_t* data, size_t data_size, + size_t riff_size, int copy_data) { + uint32_t chunk_size; + WebPData chunk_data; + + // Correctness checks. + if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA; + chunk_size = GetLE32(data + TAG_SIZE); + if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA; + + { + const size_t chunk_disk_size = SizeWithPadding(chunk_size); + if (chunk_disk_size > riff_size) return WEBP_MUX_BAD_DATA; + if (chunk_disk_size > data_size) return WEBP_MUX_NOT_ENOUGH_DATA; + } + + // Data assignment. + chunk_data.bytes = data + CHUNK_HEADER_SIZE; + chunk_data.size = chunk_size; + return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0)); +} + +int MuxImageFinalize(WebPMuxImage* const wpi) { + const WebPChunk* const img = wpi->img_; + const WebPData* const image = &img->data_; + const int is_lossless = (img->tag_ == kChunks[IDX_VP8L].tag); + int w, h; + int vp8l_has_alpha = 0; + const int ok = is_lossless ? + VP8LGetInfo(image->bytes, image->size, &w, &h, &vp8l_has_alpha) : + VP8GetInfo(image->bytes, image->size, image->size, &w, &h); + assert(img != NULL); + if (ok) { + // Ignore ALPH chunk accompanying VP8L. + if (is_lossless && (wpi->alpha_ != NULL)) { + ChunkDelete(wpi->alpha_); + wpi->alpha_ = NULL; + } + wpi->width_ = w; + wpi->height_ = h; + wpi->has_alpha_ = vp8l_has_alpha || (wpi->alpha_ != NULL); + } + return ok; +} + +static int MuxImageParse(const WebPChunk* const chunk, int copy_data, + WebPMuxImage* const wpi) { + const uint8_t* bytes = chunk->data_.bytes; + size_t size = chunk->data_.size; + const uint8_t* const last = (bytes == NULL) ? NULL : bytes + size; + WebPChunk subchunk; + size_t subchunk_size; + WebPChunk** unknown_chunk_list = &wpi->unknown_; + ChunkInit(&subchunk); + + assert(chunk->tag_ == kChunks[IDX_ANMF].tag); + assert(!wpi->is_partial_); + + // ANMF. + { + const size_t hdr_size = ANMF_CHUNK_SIZE; + const WebPData temp = { bytes, hdr_size }; + // Each of ANMF chunk contain a header at the beginning. So, its size should + // be at least 'hdr_size'. + if (size < hdr_size) goto Fail; + if (ChunkAssignData(&subchunk, &temp, copy_data, + chunk->tag_) != WEBP_MUX_OK) { + goto Fail; + } + } + if (ChunkSetHead(&subchunk, &wpi->header_) != WEBP_MUX_OK) goto Fail; + wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks. + + // Rest of the chunks. + subchunk_size = ChunkDiskSize(&subchunk) - CHUNK_HEADER_SIZE; + bytes += subchunk_size; + size -= subchunk_size; + + while (bytes != last) { + ChunkInit(&subchunk); + if (ChunkVerifyAndAssign(&subchunk, bytes, size, size, + copy_data) != WEBP_MUX_OK) { + goto Fail; + } + switch (ChunkGetIdFromTag(subchunk.tag_)) { + case WEBP_CHUNK_ALPHA: + if (wpi->alpha_ != NULL) goto Fail; // Consecutive ALPH chunks. + if (ChunkSetHead(&subchunk, &wpi->alpha_) != WEBP_MUX_OK) goto Fail; + wpi->is_partial_ = 1; // Waiting for a VP8 chunk. + break; + case WEBP_CHUNK_IMAGE: + if (wpi->img_ != NULL) goto Fail; // Only 1 image chunk allowed. + if (ChunkSetHead(&subchunk, &wpi->img_) != WEBP_MUX_OK) goto Fail; + if (!MuxImageFinalize(wpi)) goto Fail; + wpi->is_partial_ = 0; // wpi is completely filled. + break; + case WEBP_CHUNK_UNKNOWN: + if (wpi->is_partial_) { + goto Fail; // Encountered an unknown chunk + // before some image chunks. + } + if (ChunkAppend(&subchunk, &unknown_chunk_list) != WEBP_MUX_OK) { + goto Fail; + } + break; + default: + goto Fail; + } + subchunk_size = ChunkDiskSize(&subchunk); + bytes += subchunk_size; + size -= subchunk_size; + } + if (wpi->is_partial_) goto Fail; + return 1; + + Fail: + ChunkRelease(&subchunk); + return 0; +} + +//------------------------------------------------------------------------------ +// Create a mux object from WebP-RIFF data. + +WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, + int version) { + size_t riff_size; + uint32_t tag; + const uint8_t* end; + WebPMux* mux = NULL; + WebPMuxImage* wpi = NULL; + const uint8_t* data; + size_t size; + WebPChunk chunk; + // Stores the end of the chunk lists so that it is faster to append data to + // their ends. + WebPChunk** chunk_list_ends[WEBP_CHUNK_NIL + 1] = { NULL }; + ChunkInit(&chunk); + + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { + return NULL; // version mismatch + } + if (bitstream == NULL) return NULL; + + data = bitstream->bytes; + size = bitstream->size; + + if (data == NULL) return NULL; + if (size < RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE) return NULL; + if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') || + GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) { + return NULL; + } + + mux = WebPMuxNew(); + if (mux == NULL) return NULL; + + tag = GetLE32(data + RIFF_HEADER_SIZE); + if (tag != kChunks[IDX_VP8].tag && + tag != kChunks[IDX_VP8L].tag && + tag != kChunks[IDX_VP8X].tag) { + goto Err; // First chunk should be VP8, VP8L or VP8X. + } + + riff_size = GetLE32(data + TAG_SIZE); + if (riff_size > MAX_CHUNK_PAYLOAD) goto Err; + + // Note this padding is historical and differs from demux.c which does not + // pad the file size. + riff_size = SizeWithPadding(riff_size); + if (riff_size < CHUNK_HEADER_SIZE) goto Err; + if (riff_size > size) goto Err; + // There's no point in reading past the end of the RIFF chunk. + if (size > riff_size + CHUNK_HEADER_SIZE) { + size = riff_size + CHUNK_HEADER_SIZE; + } + + end = data + size; + data += RIFF_HEADER_SIZE; + size -= RIFF_HEADER_SIZE; + + wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*wpi)); + if (wpi == NULL) goto Err; + MuxImageInit(wpi); + + // Loop over chunks. + while (data != end) { + size_t data_size; + WebPChunkId id; + if (ChunkVerifyAndAssign(&chunk, data, size, riff_size, + copy_data) != WEBP_MUX_OK) { + goto Err; + } + data_size = ChunkDiskSize(&chunk); + id = ChunkGetIdFromTag(chunk.tag_); + switch (id) { + case WEBP_CHUNK_ALPHA: + if (wpi->alpha_ != NULL) goto Err; // Consecutive ALPH chunks. + if (ChunkSetHead(&chunk, &wpi->alpha_) != WEBP_MUX_OK) goto Err; + wpi->is_partial_ = 1; // Waiting for a VP8 chunk. + break; + case WEBP_CHUNK_IMAGE: + if (ChunkSetHead(&chunk, &wpi->img_) != WEBP_MUX_OK) goto Err; + if (!MuxImageFinalize(wpi)) goto Err; + wpi->is_partial_ = 0; // wpi is completely filled. + PushImage: + // Add this to mux->images_ list. + if (MuxImagePush(wpi, &mux->images_) != WEBP_MUX_OK) goto Err; + MuxImageInit(wpi); // Reset for reading next image. + break; + case WEBP_CHUNK_ANMF: + if (wpi->is_partial_) goto Err; // Previous wpi is still incomplete. + if (!MuxImageParse(&chunk, copy_data, wpi)) goto Err; + ChunkRelease(&chunk); + goto PushImage; + default: // A non-image chunk. + if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before + // getting all chunks of an image. + if (chunk_list_ends[id] == NULL) { + chunk_list_ends[id] = + MuxGetChunkListFromId(mux, id); // List to add this chunk. + } + if (ChunkAppend(&chunk, &chunk_list_ends[id]) != WEBP_MUX_OK) goto Err; + if (id == WEBP_CHUNK_VP8X) { // grab global specs + if (data_size < CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE) goto Err; + mux->canvas_width_ = GetLE24(data + 12) + 1; + mux->canvas_height_ = GetLE24(data + 15) + 1; + } + break; + } + data += data_size; + size -= data_size; + ChunkInit(&chunk); + } + + // Incomplete image. + if (wpi->is_partial_) goto Err; + + // Validate mux if complete. + if (MuxValidate(mux) != WEBP_MUX_OK) goto Err; + + MuxImageDelete(wpi); + return mux; // All OK; + + Err: // Something bad happened. + ChunkRelease(&chunk); + MuxImageDelete(wpi); + WebPMuxDelete(mux); + return NULL; +} + +//------------------------------------------------------------------------------ +// Get API(s). + +// Validates that the given mux has a single image. +static WebPMuxError ValidateForSingleImage(const WebPMux* const mux) { + const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE); + const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_ANMF); + + if (num_images == 0) { + // No images in mux. + return WEBP_MUX_NOT_FOUND; + } else if (num_images == 1 && num_frames == 0) { + // Valid case (single image). + return WEBP_MUX_OK; + } else { + // Frame case OR an invalid mux. + return WEBP_MUX_INVALID_ARGUMENT; + } +} + +// Get the canvas width, height and flags after validating that VP8X/VP8/VP8L +// chunk and canvas size are valid. +static WebPMuxError MuxGetCanvasInfo(const WebPMux* const mux, + int* width, int* height, uint32_t* flags) { + int w, h; + uint32_t f = 0; + WebPData data; + assert(mux != NULL); + + // Check if VP8X chunk is present. + if (MuxGet(mux, IDX_VP8X, 1, &data) == WEBP_MUX_OK) { + if (data.size < VP8X_CHUNK_SIZE) return WEBP_MUX_BAD_DATA; + f = GetLE32(data.bytes + 0); + w = GetLE24(data.bytes + 4) + 1; + h = GetLE24(data.bytes + 7) + 1; + } else { + const WebPMuxImage* const wpi = mux->images_; + // Grab user-forced canvas size as default. + w = mux->canvas_width_; + h = mux->canvas_height_; + if (w == 0 && h == 0 && ValidateForSingleImage(mux) == WEBP_MUX_OK) { + // single image and not forced canvas size => use dimension of first frame + assert(wpi != NULL); + w = wpi->width_; + h = wpi->height_; + } + if (wpi != NULL) { + if (wpi->has_alpha_) f |= ALPHA_FLAG; + } + } + if (w * (uint64_t)h >= MAX_IMAGE_AREA) return WEBP_MUX_BAD_DATA; + + if (width != NULL) *width = w; + if (height != NULL) *height = h; + if (flags != NULL) *flags = f; + return WEBP_MUX_OK; +} + +WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux, int* width, int* height) { + if (mux == NULL || width == NULL || height == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + return MuxGetCanvasInfo(mux, width, height, NULL); +} + +WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { + if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return MuxGetCanvasInfo(mux, NULL, NULL, flags); +} + +static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width, + int height, uint32_t flags) { + const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; + assert(width >= 1 && height >= 1); + assert(width <= MAX_CANVAS_SIZE && height <= MAX_CANVAS_SIZE); + assert(width * (uint64_t)height < MAX_IMAGE_AREA); + PutLE32(dst, MKFOURCC('V', 'P', '8', 'X')); + PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE); + PutLE32(dst + CHUNK_HEADER_SIZE, flags); + PutLE24(dst + CHUNK_HEADER_SIZE + 4, width - 1); + PutLE24(dst + CHUNK_HEADER_SIZE + 7, height - 1); + return dst + vp8x_size; +} + +// Assemble a single image WebP bitstream from 'wpi'. +static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, + WebPData* const bitstream) { + uint8_t* dst; + + // Allocate data. + const int need_vp8x = (wpi->alpha_ != NULL); + const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0; + const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0; + // Note: No need to output ANMF chunk for a single image. + const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size + + ChunkDiskSize(wpi->img_); + uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size); + if (data == NULL) return WEBP_MUX_MEMORY_ERROR; + + // There should be at most one alpha_ chunk and exactly one img_ chunk. + assert(wpi->alpha_ == NULL || wpi->alpha_->next_ == NULL); + assert(wpi->img_ != NULL && wpi->img_->next_ == NULL); + + // Main RIFF header. + dst = MuxEmitRiffHeader(data, size); + + if (need_vp8x) { + dst = EmitVP8XChunk(dst, wpi->width_, wpi->height_, ALPHA_FLAG); // VP8X. + dst = ChunkListEmit(wpi->alpha_, dst); // ALPH. + } + + // Bitstream. + dst = ChunkListEmit(wpi->img_, dst); + assert(dst == data + size); + + // Output. + bitstream->bytes = data; + bitstream->size = size; + return WEBP_MUX_OK; +} + +WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4], + WebPData* chunk_data) { + CHUNK_INDEX idx; + if (mux == NULL || fourcc == NULL || chunk_data == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + idx = ChunkGetIndexFromFourCC(fourcc); + assert(idx != IDX_LAST_CHUNK); + if (IsWPI(kChunks[idx].id)) { // An image chunk. + return WEBP_MUX_INVALID_ARGUMENT; + } else if (idx != IDX_UNKNOWN) { // A known chunk type. + return MuxGet(mux, idx, 1, chunk_data); + } else { // An unknown chunk type. + const WebPChunk* const chunk = + ChunkSearchList(mux->unknown_, 1, ChunkGetTagFromFourCC(fourcc)); + if (chunk == NULL) return WEBP_MUX_NOT_FOUND; + *chunk_data = chunk->data_; + return WEBP_MUX_OK; + } +} + +static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi, + WebPMuxFrameInfo* const info) { + // Set some defaults for unrelated fields. + info->x_offset = 0; + info->y_offset = 0; + info->duration = 1; + info->dispose_method = WEBP_MUX_DISPOSE_NONE; + info->blend_method = WEBP_MUX_BLEND; + // Extract data for related fields. + info->id = ChunkGetIdFromTag(wpi->img_->tag_); + return SynthesizeBitstream(wpi, &info->bitstream); +} + +static WebPMuxError MuxGetFrameInternal(const WebPMuxImage* const wpi, + WebPMuxFrameInfo* const frame) { + const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag); + const WebPData* frame_data; + if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT; + assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame(). + // Get frame chunk. + frame_data = &wpi->header_->data_; + if (frame_data->size < kChunks[IDX_ANMF].size) return WEBP_MUX_BAD_DATA; + // Extract info. + frame->x_offset = 2 * GetLE24(frame_data->bytes + 0); + frame->y_offset = 2 * GetLE24(frame_data->bytes + 3); + { + const uint8_t bits = frame_data->bytes[15]; + frame->duration = GetLE24(frame_data->bytes + 12); + frame->dispose_method = + (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; + frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; + } + frame->id = ChunkGetIdFromTag(wpi->header_->tag_); + return SynthesizeBitstream(wpi, &frame->bitstream); +} + +WebPMuxError WebPMuxGetFrame( + const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame) { + WebPMuxError err; + WebPMuxImage* wpi; + + if (mux == NULL || frame == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // Get the nth WebPMuxImage. + err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, &wpi); + if (err != WEBP_MUX_OK) return err; + + // Get frame info. + if (wpi->header_ == NULL) { + return MuxGetImageInternal(wpi, frame); + } else { + return MuxGetFrameInternal(wpi, frame); + } +} + +WebPMuxError WebPMuxGetAnimationParams(const WebPMux* mux, + WebPMuxAnimParams* params) { + WebPData anim; + WebPMuxError err; + + if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + err = MuxGet(mux, IDX_ANIM, 1, &anim); + if (err != WEBP_MUX_OK) return err; + if (anim.size < kChunks[WEBP_CHUNK_ANIM].size) return WEBP_MUX_BAD_DATA; + params->bgcolor = GetLE32(anim.bytes); + params->loop_count = GetLE16(anim.bytes + 4); + + return WEBP_MUX_OK; +} + +// Get chunk index from chunk id. Returns IDX_NIL if not found. +static CHUNK_INDEX ChunkGetIndexFromId(WebPChunkId id) { + int i; + for (i = 0; kChunks[i].id != WEBP_CHUNK_NIL; ++i) { + if (id == kChunks[i].id) return (CHUNK_INDEX)i; + } + return IDX_NIL; +} + +// Count number of chunks matching 'tag' in the 'chunk_list'. +// If tag == NIL_TAG, any tag will be matched. +static int CountChunks(const WebPChunk* const chunk_list, uint32_t tag) { + int count = 0; + const WebPChunk* current; + for (current = chunk_list; current != NULL; current = current->next_) { + if (tag == NIL_TAG || current->tag_ == tag) { + count++; // Count chunks whose tags match. + } + } + return count; +} + +WebPMuxError WebPMuxNumChunks(const WebPMux* mux, + WebPChunkId id, int* num_elements) { + if (mux == NULL || num_elements == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + if (IsWPI(id)) { + *num_elements = MuxImageCount(mux->images_, id); + } else { + WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id); + const CHUNK_INDEX idx = ChunkGetIndexFromId(id); + *num_elements = CountChunks(*chunk_list, kChunks[idx].tag); + } + + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/utils/bit_reader_inl_utils.h b/libraries/webp/src/utils/bit_reader_inl_utils.h new file mode 100644 index 00000000000..57cc843ff3e --- /dev/null +++ b/libraries/webp/src/utils/bit_reader_inl_utils.h @@ -0,0 +1,196 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Specific inlined methods for boolean decoder [VP8GetBit() ...] +// This file should be included by the .c sources that actually need to call +// these methods. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_BIT_READER_INL_UTILS_H_ +#define WEBP_UTILS_BIT_READER_INL_UTILS_H_ + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include // for memcpy + +#include "src/dsp/dsp.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/endian_inl_utils.h" +#include "src/utils/utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Derived type lbit_t = natural type for memory I/O + +#if (BITS > 32) +typedef uint64_t lbit_t; +#elif (BITS > 16) +typedef uint32_t lbit_t; +#elif (BITS > 8) +typedef uint16_t lbit_t; +#else +typedef uint8_t lbit_t; +#endif + +extern const uint8_t kVP8Log2Range[128]; +extern const uint8_t kVP8NewRange[128]; + +// special case for the tail byte-reading +void VP8LoadFinalBytes(VP8BitReader* const br); + +//------------------------------------------------------------------------------ +// Inlined critical functions + +// makes sure br->value_ has at least BITS bits worth of data +static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE +void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) { + assert(br != NULL && br->buf_ != NULL); + // Read 'BITS' bits at a time if possible. + if (br->buf_ < br->buf_max_) { + // convert memory type to register type (with some zero'ing!) + bit_t bits; +#if defined(WEBP_USE_MIPS32) + // This is needed because of un-aligned read. + lbit_t in_bits; + lbit_t* p_buf_ = (lbit_t*)br->buf_; + __asm__ volatile( + ".set push \n\t" + ".set at \n\t" + ".set macro \n\t" + "ulw %[in_bits], 0(%[p_buf_]) \n\t" + ".set pop \n\t" + : [in_bits]"=r"(in_bits) + : [p_buf_]"r"(p_buf_) + : "memory", "at" + ); +#else + lbit_t in_bits; + memcpy(&in_bits, br->buf_, sizeof(in_bits)); +#endif + br->buf_ += BITS >> 3; +#if !defined(WORDS_BIGENDIAN) +#if (BITS > 32) + bits = BSwap64(in_bits); + bits >>= 64 - BITS; +#elif (BITS >= 24) + bits = BSwap32(in_bits); + bits >>= (32 - BITS); +#elif (BITS == 16) + bits = BSwap16(in_bits); +#else // BITS == 8 + bits = (bit_t)in_bits; +#endif // BITS > 32 +#else // WORDS_BIGENDIAN + bits = (bit_t)in_bits; + if (BITS != 8 * sizeof(bit_t)) bits >>= (8 * sizeof(bit_t) - BITS); +#endif + br->value_ = bits | (br->value_ << BITS); + br->bits_ += BITS; + } else { + VP8LoadFinalBytes(br); // no need to be inlined + } +} + +// Read a bit with proba 'prob'. Speed-critical function! +static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br, + int prob, const char label[]) { + // Don't move this declaration! It makes a big speed difference to store + // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't + // alter br->range_ value. + range_t range = br->range_; + if (br->bits_ < 0) { + VP8LoadNewBytes(br); + } + { + const int pos = br->bits_; + const range_t split = (range * prob) >> 8; + const range_t value = (range_t)(br->value_ >> pos); + const int bit = (value > split); + if (bit) { + range -= split; + br->value_ -= (bit_t)(split + 1) << pos; + } else { + range = split + 1; + } + { + const int shift = 7 ^ BitsLog2Floor(range); + range <<= shift; + br->bits_ -= shift; + } + br->range_ = range - 1; + BT_TRACK(br); + return bit; + } +} + +// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here) +static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE +int VP8GetSigned(VP8BitReader* WEBP_RESTRICT const br, int v, + const char label[]) { + if (br->bits_ < 0) { + VP8LoadNewBytes(br); + } + { + const int pos = br->bits_; + const range_t split = br->range_ >> 1; + const range_t value = (range_t)(br->value_ >> pos); + const int32_t mask = (int32_t)(split - value) >> 31; // -1 or 0 + br->bits_ -= 1; + br->range_ += (range_t)mask; + br->range_ |= 1; + br->value_ -= (bit_t)((split + 1) & (uint32_t)mask) << pos; + BT_TRACK(br); + return (v ^ mask) - mask; + } +} + +static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* WEBP_RESTRICT const br, + int prob, const char label[]) { + // Don't move this declaration! It makes a big speed difference to store + // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't + // alter br->range_ value. + range_t range = br->range_; + if (br->bits_ < 0) { + VP8LoadNewBytes(br); + } + { + const int pos = br->bits_; + const range_t split = (range * prob) >> 8; + const range_t value = (range_t)(br->value_ >> pos); + int bit; // Don't use 'const int bit = (value > split);", it's slower. + if (value > split) { + range -= split + 1; + br->value_ -= (bit_t)(split + 1) << pos; + bit = 1; + } else { + range = split; + bit = 0; + } + if (range <= (range_t)0x7e) { + const int shift = kVP8Log2Range[range]; + range = kVP8NewRange[range]; + br->bits_ -= shift; + } + br->range_ = range; + BT_TRACK(br); + return bit; + } +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_ diff --git a/libraries/webp/src/utils/bit_reader_utils.c b/libraries/webp/src/utils/bit_reader_utils.c new file mode 100644 index 00000000000..78aed577fcb --- /dev/null +++ b/libraries/webp/src/utils/bit_reader_utils.c @@ -0,0 +1,299 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Boolean decoder non-inlined methods +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include "src/dsp/cpu.h" +#include "src/utils/bit_reader_inl_utils.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// VP8BitReader + +void VP8BitReaderSetBuffer(VP8BitReader* const br, + const uint8_t* const start, + size_t size) { + br->buf_ = start; + br->buf_end_ = start + size; + br->buf_max_ = + (size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1 + : start; +} + +void VP8InitBitReader(VP8BitReader* const br, + const uint8_t* const start, size_t size) { + assert(br != NULL); + assert(start != NULL); + assert(size < (1u << 31)); // limit ensured by format and upstream checks + br->range_ = 255 - 1; + br->value_ = 0; + br->bits_ = -8; // to load the very first 8bits + br->eof_ = 0; + VP8BitReaderSetBuffer(br, start, size); + VP8LoadNewBytes(br); +} + +void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) { + if (br->buf_ != NULL) { + br->buf_ += offset; + br->buf_end_ += offset; + br->buf_max_ += offset; + } +} + +const uint8_t kVP8Log2Range[128] = { + 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0 +}; + +// range = ((range - 1) << kVP8Log2Range[range]) + 1 +const uint8_t kVP8NewRange[128] = { + 127, 127, 191, 127, 159, 191, 223, 127, + 143, 159, 175, 191, 207, 223, 239, 127, + 135, 143, 151, 159, 167, 175, 183, 191, + 199, 207, 215, 223, 231, 239, 247, 127, + 131, 135, 139, 143, 147, 151, 155, 159, + 163, 167, 171, 175, 179, 183, 187, 191, + 195, 199, 203, 207, 211, 215, 219, 223, + 227, 231, 235, 239, 243, 247, 251, 127, + 129, 131, 133, 135, 137, 139, 141, 143, + 145, 147, 149, 151, 153, 155, 157, 159, + 161, 163, 165, 167, 169, 171, 173, 175, + 177, 179, 181, 183, 185, 187, 189, 191, + 193, 195, 197, 199, 201, 203, 205, 207, + 209, 211, 213, 215, 217, 219, 221, 223, + 225, 227, 229, 231, 233, 235, 237, 239, + 241, 243, 245, 247, 249, 251, 253, 127 +}; + +void VP8LoadFinalBytes(VP8BitReader* const br) { + assert(br != NULL && br->buf_ != NULL); + // Only read 8bits at a time + if (br->buf_ < br->buf_end_) { + br->bits_ += 8; + br->value_ = (bit_t)(*br->buf_++) | (br->value_ << 8); + } else if (!br->eof_) { + br->value_ <<= 8; + br->bits_ += 8; + br->eof_ = 1; + } else { + br->bits_ = 0; // This is to avoid undefined behaviour with shifts. + } +} + +//------------------------------------------------------------------------------ +// Higher-level calls + +uint32_t VP8GetValue(VP8BitReader* const br, int bits, const char label[]) { + uint32_t v = 0; + while (bits-- > 0) { + v |= VP8GetBit(br, 0x80, label) << bits; + } + return v; +} + +int32_t VP8GetSignedValue(VP8BitReader* const br, int bits, + const char label[]) { + const int value = VP8GetValue(br, bits, label); + return VP8Get(br, label) ? -value : value; +} + +//------------------------------------------------------------------------------ +// VP8LBitReader + +#define VP8L_LOG8_WBITS 4 // Number of bytes needed to store VP8L_WBITS bits. + +#if defined(__arm__) || defined(_M_ARM) || WEBP_AARCH64 || \ + defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64__) || defined(_M_X64) +#define VP8L_USE_FAST_LOAD +#endif + +static const uint32_t kBitMask[VP8L_MAX_NUM_BIT_READ + 1] = { + 0, + 0x000001, 0x000003, 0x000007, 0x00000f, + 0x00001f, 0x00003f, 0x00007f, 0x0000ff, + 0x0001ff, 0x0003ff, 0x0007ff, 0x000fff, + 0x001fff, 0x003fff, 0x007fff, 0x00ffff, + 0x01ffff, 0x03ffff, 0x07ffff, 0x0fffff, + 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff +}; + +void VP8LInitBitReader(VP8LBitReader* const br, const uint8_t* const start, + size_t length) { + size_t i; + vp8l_val_t value = 0; + assert(br != NULL); + assert(start != NULL); + assert(length < 0xfffffff8u); // can't happen with a RIFF chunk. + + br->len_ = length; + br->val_ = 0; + br->bit_pos_ = 0; + br->eos_ = 0; + + if (length > sizeof(br->val_)) { + length = sizeof(br->val_); + } + for (i = 0; i < length; ++i) { + value |= (vp8l_val_t)start[i] << (8 * i); + } + br->val_ = value; + br->pos_ = length; + br->buf_ = start; +} + +void VP8LBitReaderSetBuffer(VP8LBitReader* const br, + const uint8_t* const buf, size_t len) { + assert(br != NULL); + assert(buf != NULL); + assert(len < 0xfffffff8u); // can't happen with a RIFF chunk. + br->buf_ = buf; + br->len_ = len; + // pos_ > len_ should be considered a param error. + br->eos_ = (br->pos_ > br->len_) || VP8LIsEndOfStream(br); +} + +static void VP8LSetEndOfStream(VP8LBitReader* const br) { + br->eos_ = 1; + br->bit_pos_ = 0; // To avoid undefined behaviour with shifts. +} + +// If not at EOS, reload up to VP8L_LBITS byte-by-byte +static void ShiftBytes(VP8LBitReader* const br) { + while (br->bit_pos_ >= 8 && br->pos_ < br->len_) { + br->val_ >>= 8; + br->val_ |= ((vp8l_val_t)br->buf_[br->pos_]) << (VP8L_LBITS - 8); + ++br->pos_; + br->bit_pos_ -= 8; + } + if (VP8LIsEndOfStream(br)) { + VP8LSetEndOfStream(br); + } +} + +void VP8LDoFillBitWindow(VP8LBitReader* const br) { + assert(br->bit_pos_ >= VP8L_WBITS); +#if defined(VP8L_USE_FAST_LOAD) + if (br->pos_ + sizeof(br->val_) < br->len_) { + br->val_ >>= VP8L_WBITS; + br->bit_pos_ -= VP8L_WBITS; + br->val_ |= (vp8l_val_t)HToLE32(WebPMemToUint32(br->buf_ + br->pos_)) << + (VP8L_LBITS - VP8L_WBITS); + br->pos_ += VP8L_LOG8_WBITS; + return; + } +#endif + ShiftBytes(br); // Slow path. +} + +uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) { + assert(n_bits >= 0); + // Flag an error if end_of_stream or n_bits is more than allowed limit. + if (!br->eos_ && n_bits <= VP8L_MAX_NUM_BIT_READ) { + const uint32_t val = VP8LPrefetchBits(br) & kBitMask[n_bits]; + const int new_bits = br->bit_pos_ + n_bits; + br->bit_pos_ = new_bits; + ShiftBytes(br); + return val; + } else { + VP8LSetEndOfStream(br); + return 0; + } +} + +//------------------------------------------------------------------------------ +// Bit-tracing tool + +#if (BITTRACE > 0) + +#include // for atexit() +#include +#include + +#define MAX_NUM_LABELS 32 +static struct { + const char* label; + int size; + int count; +} kLabels[MAX_NUM_LABELS]; + +static int last_label = 0; +static int last_pos = 0; +static const uint8_t* buf_start = NULL; +static int init_done = 0; + +static void PrintBitTraces(void) { + int i; + int scale = 1; + int total = 0; + const char* units = "bits"; +#if (BITTRACE == 2) + scale = 8; + units = "bytes"; +#endif + for (i = 0; i < last_label; ++i) total += kLabels[i].size; + if (total < 1) total = 1; // avoid rounding errors + printf("=== Bit traces ===\n"); + for (i = 0; i < last_label; ++i) { + const int skip = 16 - (int)strlen(kLabels[i].label); + const int value = (kLabels[i].size + scale - 1) / scale; + assert(skip > 0); + printf("%s \%*s: %6d %s \t[%5.2f%%] [count: %7d]\n", + kLabels[i].label, skip, "", value, units, + 100.f * kLabels[i].size / total, + kLabels[i].count); + } + total = (total + scale - 1) / scale; + printf("Total: %d %s\n", total, units); +} + +void BitTrace(const struct VP8BitReader* const br, const char label[]) { + int i, pos; + if (!init_done) { + memset(kLabels, 0, sizeof(kLabels)); + atexit(PrintBitTraces); + buf_start = br->buf_; + init_done = 1; + } + pos = (int)(br->buf_ - buf_start) * 8 - br->bits_; + // if there's a too large jump, we've changed partition -> reset counter + if (abs(pos - last_pos) > 32) { + buf_start = br->buf_; + pos = 0; + last_pos = 0; + } + if (br->range_ >= 0x7f) pos += kVP8Log2Range[br->range_ - 0x7f]; + for (i = 0; i < last_label; ++i) { + if (!strcmp(label, kLabels[i].label)) break; + } + if (i == MAX_NUM_LABELS) abort(); // overflow! + kLabels[i].label = label; + kLabels[i].size += pos - last_pos; + kLabels[i].count += 1; + if (i == last_label) ++last_label; + last_pos = pos; +} + +#endif // BITTRACE > 0 + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/utils/bit_reader_utils.h b/libraries/webp/src/utils/bit_reader_utils.h new file mode 100644 index 00000000000..2307b8b1ae9 --- /dev/null +++ b/libraries/webp/src/utils/bit_reader_utils.h @@ -0,0 +1,195 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Boolean decoder +// +// Author: Skal (pascal.massimino@gmail.com) +// Vikas Arora (vikaas.arora@gmail.com) + +#ifndef WEBP_UTILS_BIT_READER_UTILS_H_ +#define WEBP_UTILS_BIT_READER_UTILS_H_ + +#include +#ifdef _MSC_VER +#include // _byteswap_ulong +#endif +#include "src/dsp/cpu.h" +#include "include/webp/types.h" + +// Warning! This macro triggers quite some MACRO wizardry around func signature! +#if !defined(BITTRACE) +#define BITTRACE 0 // 0 = off, 1 = print bits, 2 = print bytes +#endif + +#if (BITTRACE > 0) +struct VP8BitReader; +extern void BitTrace(const struct VP8BitReader* const br, const char label[]); +#define BT_TRACK(br) BitTrace(br, label) +#define VP8Get(BR, L) VP8GetValue(BR, 1, L) +#else +#define BT_TRACK(br) +// We'll REMOVE the 'const char label[]' from all signatures and calls (!!): +#define VP8GetValue(BR, N, L) VP8GetValue(BR, N) +#define VP8Get(BR, L) VP8GetValue(BR, 1, L) +#define VP8GetSignedValue(BR, N, L) VP8GetSignedValue(BR, N) +#define VP8GetBit(BR, P, L) VP8GetBit(BR, P) +#define VP8GetBitAlt(BR, P, L) VP8GetBitAlt(BR, P) +#define VP8GetSigned(BR, V, L) VP8GetSigned(BR, V) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// The Boolean decoder needs to maintain infinite precision on the value_ field. +// However, since range_ is only 8bit, we only need an active window of 8 bits +// for value_. Left bits (MSB) gets zeroed and shifted away when value_ falls +// below 128, range_ is updated, and fresh bits read from the bitstream are +// brought in as LSB. To avoid reading the fresh bits one by one (slow), we +// cache BITS of them ahead. The total of (BITS + 8) bits must fit into a +// natural register (with type bit_t). To fetch BITS bits from bitstream we +// use a type lbit_t. +// +// BITS can be any multiple of 8 from 8 to 56 (inclusive). +// Pick values that fit natural register size. + +#if defined(__i386__) || defined(_M_IX86) // x86 32bit +#define BITS 24 +#elif defined(__x86_64__) || defined(_M_X64) // x86 64bit +#define BITS 56 +#elif defined(__arm__) || defined(_M_ARM) // ARM +#define BITS 24 +#elif WEBP_AARCH64 // ARM 64bit +#define BITS 56 +#elif defined(__mips__) // MIPS +#define BITS 24 +#else // reasonable default +#define BITS 24 +#endif + +//------------------------------------------------------------------------------ +// Derived types and constants: +// bit_t = natural register type for storing 'value_' (which is BITS+8 bits) +// range_t = register for 'range_' (which is 8bits only) + +#if (BITS > 24) +typedef uint64_t bit_t; +#else +typedef uint32_t bit_t; +#endif + +typedef uint32_t range_t; + +//------------------------------------------------------------------------------ +// Bitreader + +typedef struct VP8BitReader VP8BitReader; +struct VP8BitReader { + // boolean decoder (keep the field ordering as is!) + bit_t value_; // current value + range_t range_; // current range minus 1. In [127, 254] interval. + int bits_; // number of valid bits left + // read buffer + const uint8_t* buf_; // next byte to be read + const uint8_t* buf_end_; // end of read buffer + const uint8_t* buf_max_; // max packed-read position on buffer + int eof_; // true if input is exhausted +}; + +// Initialize the bit reader and the boolean decoder. +void VP8InitBitReader(VP8BitReader* const br, + const uint8_t* const start, size_t size); +// Sets the working read buffer. +void VP8BitReaderSetBuffer(VP8BitReader* const br, + const uint8_t* const start, size_t size); + +// Update internal pointers to displace the byte buffer by the +// relative offset 'offset'. +void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset); + +// return the next value made of 'num_bits' bits +uint32_t VP8GetValue(VP8BitReader* const br, int num_bits, const char label[]); + +// return the next value with sign-extension. +int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits, + const char label[]); + +// bit_reader_inl.h will implement the following methods: +// static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob, ...) +// static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v, ...) +// and should be included by the .c files that actually need them. +// This is to avoid recompiling the whole library whenever this file is touched, +// and also allowing platform-specific ad-hoc hacks. + +// ----------------------------------------------------------------------------- +// Bitreader for lossless format + +// maximum number of bits (inclusive) the bit-reader can handle: +#define VP8L_MAX_NUM_BIT_READ 24 + +#define VP8L_LBITS 64 // Number of bits prefetched (= bit-size of vp8l_val_t). +#define VP8L_WBITS 32 // Minimum number of bytes ready after VP8LFillBitWindow. + +typedef uint64_t vp8l_val_t; // right now, this bit-reader can only use 64bit. + +typedef struct { + vp8l_val_t val_; // pre-fetched bits + const uint8_t* buf_; // input byte buffer + size_t len_; // buffer length + size_t pos_; // byte position in buf_ + int bit_pos_; // current bit-reading position in val_ + int eos_; // true if a bit was read past the end of buffer +} VP8LBitReader; + +void VP8LInitBitReader(VP8LBitReader* const br, + const uint8_t* const start, + size_t length); + +// Sets a new data buffer. +void VP8LBitReaderSetBuffer(VP8LBitReader* const br, + const uint8_t* const buffer, size_t length); + +// Reads the specified number of bits from read buffer. +// Flags an error in case end_of_stream or n_bits is more than the allowed limit +// of VP8L_MAX_NUM_BIT_READ (inclusive). +// Flags eos_ if this read attempt is going to cross the read buffer. +uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits); + +// Return the prefetched bits, so they can be looked up. +static WEBP_INLINE uint32_t VP8LPrefetchBits(VP8LBitReader* const br) { + return (uint32_t)(br->val_ >> (br->bit_pos_ & (VP8L_LBITS - 1))); +} + +// Returns true if there was an attempt at reading bit past the end of +// the buffer. Doesn't set br->eos_ flag. +static WEBP_INLINE int VP8LIsEndOfStream(const VP8LBitReader* const br) { + assert(br->pos_ <= br->len_); + return br->eos_ || ((br->pos_ == br->len_) && (br->bit_pos_ > VP8L_LBITS)); +} + +// For jumping over a number of bits in the bit stream when accessed with +// VP8LPrefetchBits and VP8LFillBitWindow. +// This function does *not* set br->eos_, since it's speed-critical. +// Use with extreme care! +static WEBP_INLINE void VP8LSetBitPos(VP8LBitReader* const br, int val) { + br->bit_pos_ = val; +} + +// Advances the read buffer by 4 bytes to make room for reading next 32 bits. +// Speed critical, but infrequent part of the code can be non-inlined. +extern void VP8LDoFillBitWindow(VP8LBitReader* const br); +static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) { + if (br->bit_pos_ >= VP8L_WBITS) VP8LDoFillBitWindow(br); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_BIT_READER_UTILS_H_ diff --git a/libraries/webp/src/utils/bit_writer_utils.c b/libraries/webp/src/utils/bit_writer_utils.c new file mode 100644 index 00000000000..2f408508f11 --- /dev/null +++ b/libraries/webp/src/utils/bit_writer_utils.c @@ -0,0 +1,347 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Bit writing and boolean coder +// +// Author: Skal (pascal.massimino@gmail.com) +// Vikas Arora (vikaas.arora@gmail.com) + +#include +#include // for memcpy() +#include + +#include "src/utils/bit_writer_utils.h" +#include "src/utils/endian_inl_utils.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// VP8BitWriter + +static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) { + uint8_t* new_buf; + size_t new_size; + const uint64_t needed_size_64b = (uint64_t)bw->pos_ + extra_size; + const size_t needed_size = (size_t)needed_size_64b; + if (needed_size_64b != needed_size) { + bw->error_ = 1; + return 0; + } + if (needed_size <= bw->max_pos_) return 1; + // If the following line wraps over 32bit, the test just after will catch it. + new_size = 2 * bw->max_pos_; + if (new_size < needed_size) new_size = needed_size; + if (new_size < 1024) new_size = 1024; + new_buf = (uint8_t*)WebPSafeMalloc(1ULL, new_size); + if (new_buf == NULL) { + bw->error_ = 1; + return 0; + } + if (bw->pos_ > 0) { + assert(bw->buf_ != NULL); + memcpy(new_buf, bw->buf_, bw->pos_); + } + WebPSafeFree(bw->buf_); + bw->buf_ = new_buf; + bw->max_pos_ = new_size; + return 1; +} + +static void Flush(VP8BitWriter* const bw) { + const int s = 8 + bw->nb_bits_; + const int32_t bits = bw->value_ >> s; + assert(bw->nb_bits_ >= 0); + bw->value_ -= bits << s; + bw->nb_bits_ -= 8; + if ((bits & 0xff) != 0xff) { + size_t pos = bw->pos_; + if (!BitWriterResize(bw, bw->run_ + 1)) { + return; + } + if (bits & 0x100) { // overflow -> propagate carry over pending 0xff's + if (pos > 0) bw->buf_[pos - 1]++; + } + if (bw->run_ > 0) { + const int value = (bits & 0x100) ? 0x00 : 0xff; + for (; bw->run_ > 0; --bw->run_) bw->buf_[pos++] = value; + } + bw->buf_[pos++] = bits & 0xff; + bw->pos_ = pos; + } else { + bw->run_++; // delay writing of bytes 0xff, pending eventual carry. + } +} + +//------------------------------------------------------------------------------ +// renormalization + +static const uint8_t kNorm[128] = { // renorm_sizes[i] = 8 - log2(i) + 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0 +}; + +// range = ((range + 1) << kVP8Log2Range[range]) - 1 +static const uint8_t kNewRange[128] = { + 127, 127, 191, 127, 159, 191, 223, 127, 143, 159, 175, 191, 207, 223, 239, + 127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, + 247, 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, + 183, 187, 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, + 243, 247, 251, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, + 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, + 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, + 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, + 241, 243, 245, 247, 249, 251, 253, 127 +}; + +int VP8PutBit(VP8BitWriter* const bw, int bit, int prob) { + const int split = (bw->range_ * prob) >> 8; + if (bit) { + bw->value_ += split + 1; + bw->range_ -= split + 1; + } else { + bw->range_ = split; + } + if (bw->range_ < 127) { // emit 'shift' bits out and renormalize + const int shift = kNorm[bw->range_]; + bw->range_ = kNewRange[bw->range_]; + bw->value_ <<= shift; + bw->nb_bits_ += shift; + if (bw->nb_bits_ > 0) Flush(bw); + } + return bit; +} + +int VP8PutBitUniform(VP8BitWriter* const bw, int bit) { + const int split = bw->range_ >> 1; + if (bit) { + bw->value_ += split + 1; + bw->range_ -= split + 1; + } else { + bw->range_ = split; + } + if (bw->range_ < 127) { + bw->range_ = kNewRange[bw->range_]; + bw->value_ <<= 1; + bw->nb_bits_ += 1; + if (bw->nb_bits_ > 0) Flush(bw); + } + return bit; +} + +void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits) { + uint32_t mask; + assert(nb_bits > 0 && nb_bits < 32); + for (mask = 1u << (nb_bits - 1); mask; mask >>= 1) { + VP8PutBitUniform(bw, value & mask); + } +} + +void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits) { + if (!VP8PutBitUniform(bw, value != 0)) return; + if (value < 0) { + VP8PutBits(bw, ((-value) << 1) | 1, nb_bits + 1); + } else { + VP8PutBits(bw, value << 1, nb_bits + 1); + } +} + +//------------------------------------------------------------------------------ + +int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size) { + bw->range_ = 255 - 1; + bw->value_ = 0; + bw->run_ = 0; + bw->nb_bits_ = -8; + bw->pos_ = 0; + bw->max_pos_ = 0; + bw->error_ = 0; + bw->buf_ = NULL; + return (expected_size > 0) ? BitWriterResize(bw, expected_size) : 1; +} + +uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) { + VP8PutBits(bw, 0, 9 - bw->nb_bits_); + bw->nb_bits_ = 0; // pad with zeroes + Flush(bw); + return bw->buf_; +} + +int VP8BitWriterAppend(VP8BitWriter* const bw, + const uint8_t* data, size_t size) { + assert(data != NULL); + if (bw->nb_bits_ != -8) return 0; // Flush() must have been called + if (!BitWriterResize(bw, size)) return 0; + memcpy(bw->buf_ + bw->pos_, data, size); + bw->pos_ += size; + return 1; +} + +void VP8BitWriterWipeOut(VP8BitWriter* const bw) { + if (bw != NULL) { + WebPSafeFree(bw->buf_); + memset(bw, 0, sizeof(*bw)); + } +} + +//------------------------------------------------------------------------------ +// VP8LBitWriter + +// This is the minimum amount of size the memory buffer is guaranteed to grow +// when extra space is needed. +#define MIN_EXTRA_SIZE (32768ULL) + +// Returns 1 on success. +static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) { + uint8_t* allocated_buf; + size_t allocated_size; + const size_t max_bytes = bw->end_ - bw->buf_; + const size_t current_size = bw->cur_ - bw->buf_; + const uint64_t size_required_64b = (uint64_t)current_size + extra_size; + const size_t size_required = (size_t)size_required_64b; + if (size_required != size_required_64b) { + bw->error_ = 1; + return 0; + } + if (max_bytes > 0 && size_required <= max_bytes) return 1; + allocated_size = (3 * max_bytes) >> 1; + if (allocated_size < size_required) allocated_size = size_required; + // make allocated size multiple of 1k + allocated_size = (((allocated_size >> 10) + 1) << 10); + allocated_buf = (uint8_t*)WebPSafeMalloc(1ULL, allocated_size); + if (allocated_buf == NULL) { + bw->error_ = 1; + return 0; + } + if (current_size > 0) { + memcpy(allocated_buf, bw->buf_, current_size); + } + WebPSafeFree(bw->buf_); + bw->buf_ = allocated_buf; + bw->cur_ = bw->buf_ + current_size; + bw->end_ = bw->buf_ + allocated_size; + return 1; +} + +int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) { + memset(bw, 0, sizeof(*bw)); + return VP8LBitWriterResize(bw, expected_size); +} + +int VP8LBitWriterClone(const VP8LBitWriter* const src, + VP8LBitWriter* const dst) { + const size_t current_size = src->cur_ - src->buf_; + assert(src->cur_ >= src->buf_ && src->cur_ <= src->end_); + if (!VP8LBitWriterResize(dst, current_size)) return 0; + memcpy(dst->buf_, src->buf_, current_size); + dst->bits_ = src->bits_; + dst->used_ = src->used_; + dst->error_ = src->error_; + dst->cur_ = dst->buf_ + current_size; + return 1; +} + +void VP8LBitWriterWipeOut(VP8LBitWriter* const bw) { + if (bw != NULL) { + WebPSafeFree(bw->buf_); + memset(bw, 0, sizeof(*bw)); + } +} + +void VP8LBitWriterReset(const VP8LBitWriter* const bw_init, + VP8LBitWriter* const bw) { + bw->bits_ = bw_init->bits_; + bw->used_ = bw_init->used_; + bw->cur_ = bw->buf_ + (bw_init->cur_ - bw_init->buf_); + assert(bw->cur_ <= bw->end_); + bw->error_ = bw_init->error_; +} + +void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst) { + const VP8LBitWriter tmp = *src; + *src = *dst; + *dst = tmp; +} + +void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) { + // If needed, make some room by flushing some bits out. + if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { + const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE; + if (!CheckSizeOverflow(extra_size) || + !VP8LBitWriterResize(bw, (size_t)extra_size)) { + bw->cur_ = bw->buf_; + bw->error_ = 1; + return; + } + } + *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)bw->bits_); + bw->cur_ += VP8L_WRITER_BYTES; + bw->bits_ >>= VP8L_WRITER_BITS; + bw->used_ -= VP8L_WRITER_BITS; +} + +void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) { + assert(n_bits <= 32); + // That's the max we can handle: + assert(sizeof(vp8l_wtype_t) == 2); + if (n_bits > 0) { + vp8l_atype_t lbits = bw->bits_; + int used = bw->used_; + // Special case of overflow handling for 32bit accumulator (2-steps flush). +#if VP8L_WRITER_BITS == 16 + if (used + n_bits >= VP8L_WRITER_MAX_BITS) { + // Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below. + const int shift = VP8L_WRITER_MAX_BITS - used; + lbits |= (vp8l_atype_t)bits << used; + used = VP8L_WRITER_MAX_BITS; + n_bits -= shift; + bits >>= shift; + assert(n_bits <= VP8L_WRITER_MAX_BITS); + } +#endif + // If needed, make some room by flushing some bits out. + while (used >= VP8L_WRITER_BITS) { + if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { + const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE; + if (!CheckSizeOverflow(extra_size) || + !VP8LBitWriterResize(bw, (size_t)extra_size)) { + bw->cur_ = bw->buf_; + bw->error_ = 1; + return; + } + } + *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)lbits); + bw->cur_ += VP8L_WRITER_BYTES; + lbits >>= VP8L_WRITER_BITS; + used -= VP8L_WRITER_BITS; + } + bw->bits_ = lbits | ((vp8l_atype_t)bits << used); + bw->used_ = used + n_bits; + } +} + +uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) { + // flush leftover bits + if (VP8LBitWriterResize(bw, (bw->used_ + 7) >> 3)) { + while (bw->used_ > 0) { + *bw->cur_++ = (uint8_t)bw->bits_; + bw->bits_ >>= 8; + bw->used_ -= 8; + } + bw->used_ = 0; + } + return bw->buf_; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/utils/bit_writer_utils.h b/libraries/webp/src/utils/bit_writer_utils.h new file mode 100644 index 00000000000..8ccd5542390 --- /dev/null +++ b/libraries/webp/src/utils/bit_writer_utils.h @@ -0,0 +1,154 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Bit writing and boolean coder +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_BIT_WRITER_UTILS_H_ +#define WEBP_UTILS_BIT_WRITER_UTILS_H_ + +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Bit-writing + +typedef struct VP8BitWriter VP8BitWriter; +struct VP8BitWriter { + int32_t range_; // range-1 + int32_t value_; + int run_; // number of outstanding bits + int nb_bits_; // number of pending bits + uint8_t* buf_; // internal buffer. Re-allocated regularly. Not owned. + size_t pos_; + size_t max_pos_; + int error_; // true in case of error +}; + +// Initialize the object. Allocates some initial memory based on expected_size. +int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size); +// Finalize the bitstream coding. Returns a pointer to the internal buffer. +uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw); +// Release any pending memory and zeroes the object. Not a mandatory call. +// Only useful in case of error, when the internal buffer hasn't been grabbed! +void VP8BitWriterWipeOut(VP8BitWriter* const bw); + +int VP8PutBit(VP8BitWriter* const bw, int bit, int prob); +int VP8PutBitUniform(VP8BitWriter* const bw, int bit); +void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits); +void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits); + +// Appends some bytes to the internal buffer. Data is copied. +int VP8BitWriterAppend(VP8BitWriter* const bw, + const uint8_t* data, size_t size); + +// return approximate write position (in bits) +static WEBP_INLINE uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) { + const uint64_t nb_bits = 8 + bw->nb_bits_; // bw->nb_bits_ is <= 0, note + return (bw->pos_ + bw->run_) * 8 + nb_bits; +} + +// Returns a pointer to the internal buffer. +static WEBP_INLINE uint8_t* VP8BitWriterBuf(const VP8BitWriter* const bw) { + return bw->buf_; +} +// Returns the size of the internal buffer. +static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) { + return bw->pos_; +} + +//------------------------------------------------------------------------------ +// VP8LBitWriter + +#if defined(__x86_64__) || defined(_M_X64) // 64bit +typedef uint64_t vp8l_atype_t; // accumulator type +typedef uint32_t vp8l_wtype_t; // writing type +#define WSWAP HToLE32 +#define VP8L_WRITER_BYTES 4 // sizeof(vp8l_wtype_t) +#define VP8L_WRITER_BITS 32 // 8 * sizeof(vp8l_wtype_t) +#define VP8L_WRITER_MAX_BITS 64 // 8 * sizeof(vp8l_atype_t) +#else +typedef uint32_t vp8l_atype_t; +typedef uint16_t vp8l_wtype_t; +#define WSWAP HToLE16 +#define VP8L_WRITER_BYTES 2 +#define VP8L_WRITER_BITS 16 +#define VP8L_WRITER_MAX_BITS 32 +#endif + +typedef struct { + vp8l_atype_t bits_; // bit accumulator + int used_; // number of bits used in accumulator + uint8_t* buf_; // start of buffer + uint8_t* cur_; // current write position + uint8_t* end_; // end of buffer + + // After all bits are written (VP8LBitWriterFinish()), the caller must observe + // the state of error_. A value of 1 indicates that a memory allocation + // failure has happened during bit writing. A value of 0 indicates successful + // writing of bits. + int error_; +} VP8LBitWriter; + +static WEBP_INLINE size_t VP8LBitWriterNumBytes(const VP8LBitWriter* const bw) { + return (bw->cur_ - bw->buf_) + ((bw->used_ + 7) >> 3); +} + +// Returns false in case of memory allocation error. +int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size); +// Returns false in case of memory allocation error. +int VP8LBitWriterClone(const VP8LBitWriter* const src, + VP8LBitWriter* const dst); +// Finalize the bitstream coding. Returns a pointer to the internal buffer. +uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw); +// Release any pending memory and zeroes the object. +void VP8LBitWriterWipeOut(VP8LBitWriter* const bw); +// Resets the cursor of the BitWriter bw to when it was like in bw_init. +void VP8LBitWriterReset(const VP8LBitWriter* const bw_init, + VP8LBitWriter* const bw); +// Swaps the memory held by two BitWriters. +void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst); + +// Internal function for VP8LPutBits flushing 32 bits from the written state. +void VP8LPutBitsFlushBits(VP8LBitWriter* const bw); + +// PutBits internal function used in the 16 bit vp8l_wtype_t case. +void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits); + +// This function writes bits into bytes in increasing addresses (little endian), +// and within a byte least-significant-bit first. +// This function can write up to 32 bits in one go, but VP8LBitReader can only +// read 24 bits max (VP8L_MAX_NUM_BIT_READ). +// VP8LBitWriter's error_ flag is set in case of memory allocation error. +static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw, + uint32_t bits, int n_bits) { + if (sizeof(vp8l_wtype_t) == 4) { + if (n_bits > 0) { + if (bw->used_ >= 32) { + VP8LPutBitsFlushBits(bw); + } + bw->bits_ |= (vp8l_atype_t)bits << bw->used_; + bw->used_ += n_bits; + } + } else { + VP8LPutBitsInternal(bw, bits, n_bits); + } +} + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_BIT_WRITER_UTILS_H_ diff --git a/libraries/webp/src/utils/color_cache_utils.c b/libraries/webp/src/utils/color_cache_utils.c new file mode 100644 index 00000000000..7b5222b6e55 --- /dev/null +++ b/libraries/webp/src/utils/color_cache_utils.c @@ -0,0 +1,49 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Color Cache for WebP Lossless +// +// Author: Jyrki Alakuijala (jyrki@google.com) + +#include +#include +#include +#include "src/utils/color_cache_utils.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ +// VP8LColorCache. + +int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits) { + const int hash_size = 1 << hash_bits; + assert(color_cache != NULL); + assert(hash_bits > 0); + color_cache->colors_ = (uint32_t*)WebPSafeCalloc( + (uint64_t)hash_size, sizeof(*color_cache->colors_)); + if (color_cache->colors_ == NULL) return 0; + color_cache->hash_shift_ = 32 - hash_bits; + color_cache->hash_bits_ = hash_bits; + return 1; +} + +void VP8LColorCacheClear(VP8LColorCache* const color_cache) { + if (color_cache != NULL) { + WebPSafeFree(color_cache->colors_); + color_cache->colors_ = NULL; + } +} + +void VP8LColorCacheCopy(const VP8LColorCache* const src, + VP8LColorCache* const dst) { + assert(src != NULL); + assert(dst != NULL); + assert(src->hash_bits_ == dst->hash_bits_); + memcpy(dst->colors_, src->colors_, + ((size_t)1u << dst->hash_bits_) * sizeof(*dst->colors_)); +} diff --git a/libraries/webp/src/utils/color_cache_utils.h b/libraries/webp/src/utils/color_cache_utils.h new file mode 100644 index 00000000000..aa18df82e88 --- /dev/null +++ b/libraries/webp/src/utils/color_cache_utils.h @@ -0,0 +1,89 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Color Cache for WebP Lossless +// +// Authors: Jyrki Alakuijala (jyrki@google.com) +// Urvang Joshi (urvang@google.com) + +#ifndef WEBP_UTILS_COLOR_CACHE_UTILS_H_ +#define WEBP_UTILS_COLOR_CACHE_UTILS_H_ + +#include + +#include "src/dsp/dsp.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Main color cache struct. +typedef struct { + uint32_t* colors_; // color entries + int hash_shift_; // Hash shift: 32 - hash_bits_. + int hash_bits_; +} VP8LColorCache; + +static const uint32_t kHashMul = 0x1e35a7bdu; + +static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE +int VP8LHashPix(uint32_t argb, int shift) { + return (int)((argb * kHashMul) >> shift); +} + +static WEBP_INLINE uint32_t VP8LColorCacheLookup( + const VP8LColorCache* const cc, uint32_t key) { + assert((key >> cc->hash_bits_) == 0u); + return cc->colors_[key]; +} + +static WEBP_INLINE void VP8LColorCacheSet(const VP8LColorCache* const cc, + uint32_t key, uint32_t argb) { + assert((key >> cc->hash_bits_) == 0u); + cc->colors_[key] = argb; +} + +static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc, + uint32_t argb) { + const int key = VP8LHashPix(argb, cc->hash_shift_); + cc->colors_[key] = argb; +} + +static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc, + uint32_t argb) { + return VP8LHashPix(argb, cc->hash_shift_); +} + +// Return the key if cc contains argb, and -1 otherwise. +static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc, + uint32_t argb) { + const int key = VP8LHashPix(argb, cc->hash_shift_); + return (cc->colors_[key] == argb) ? key : -1; +} + +//------------------------------------------------------------------------------ + +// Initializes the color cache with 'hash_bits' bits for the keys. +// Returns false in case of memory error. +int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits); + +void VP8LColorCacheCopy(const VP8LColorCache* const src, + VP8LColorCache* const dst); + +// Delete the memory associated to color cache. +void VP8LColorCacheClear(VP8LColorCache* const color_cache); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} +#endif + +#endif // WEBP_UTILS_COLOR_CACHE_UTILS_H_ diff --git a/libraries/webp/src/utils/endian_inl_utils.h b/libraries/webp/src/utils/endian_inl_utils.h new file mode 100644 index 00000000000..44f15b6bd1d --- /dev/null +++ b/libraries/webp/src/utils/endian_inl_utils.h @@ -0,0 +1,93 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Endian related functions. + +#ifndef WEBP_UTILS_ENDIAN_INL_UTILS_H_ +#define WEBP_UTILS_ENDIAN_INL_UTILS_H_ + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include "src/dsp/dsp.h" +#include "include/webp/types.h" + +#if defined(WORDS_BIGENDIAN) +#define HToLE32 BSwap32 +#define HToLE16 BSwap16 +#else +#define HToLE32(x) (x) +#define HToLE16(x) (x) +#endif + +#if !defined(HAVE_CONFIG_H) +#if LOCAL_GCC_PREREQ(4,8) || __has_builtin(__builtin_bswap16) +#define HAVE_BUILTIN_BSWAP16 +#endif +#if LOCAL_GCC_PREREQ(4,3) || __has_builtin(__builtin_bswap32) +#define HAVE_BUILTIN_BSWAP32 +#endif +#if LOCAL_GCC_PREREQ(4,3) || __has_builtin(__builtin_bswap64) +#define HAVE_BUILTIN_BSWAP64 +#endif +#endif // !HAVE_CONFIG_H + +static WEBP_INLINE uint16_t BSwap16(uint16_t x) { +#if defined(HAVE_BUILTIN_BSWAP16) + return __builtin_bswap16(x); +#elif defined(_MSC_VER) + return _byteswap_ushort(x); +#else + // gcc will recognize a 'rorw $8, ...' here: + return (x >> 8) | ((x & 0xff) << 8); +#endif // HAVE_BUILTIN_BSWAP16 +} + +static WEBP_INLINE uint32_t BSwap32(uint32_t x) { +#if defined(WEBP_USE_MIPS32_R2) + uint32_t ret; + __asm__ volatile ( + "wsbh %[ret], %[x] \n\t" + "rotr %[ret], %[ret], 16 \n\t" + : [ret]"=r"(ret) + : [x]"r"(x) + ); + return ret; +#elif defined(HAVE_BUILTIN_BSWAP32) + return __builtin_bswap32(x); +#elif defined(__i386__) || defined(__x86_64__) + uint32_t swapped_bytes; + __asm__ volatile("bswap %0" : "=r"(swapped_bytes) : "0"(x)); + return swapped_bytes; +#elif defined(_MSC_VER) + return (uint32_t)_byteswap_ulong(x); +#else + return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); +#endif // HAVE_BUILTIN_BSWAP32 +} + +static WEBP_INLINE uint64_t BSwap64(uint64_t x) { +#if defined(HAVE_BUILTIN_BSWAP64) + return __builtin_bswap64(x); +#elif defined(__x86_64__) + uint64_t swapped_bytes; + __asm__ volatile("bswapq %0" : "=r"(swapped_bytes) : "0"(x)); + return swapped_bytes; +#elif defined(_MSC_VER) + return (uint64_t)_byteswap_uint64(x); +#else // generic code for swapping 64-bit values (suggested by bdb@) + x = ((x & 0xffffffff00000000ull) >> 32) | ((x & 0x00000000ffffffffull) << 32); + x = ((x & 0xffff0000ffff0000ull) >> 16) | ((x & 0x0000ffff0000ffffull) << 16); + x = ((x & 0xff00ff00ff00ff00ull) >> 8) | ((x & 0x00ff00ff00ff00ffull) << 8); + return x; +#endif // HAVE_BUILTIN_BSWAP64 +} + +#endif // WEBP_UTILS_ENDIAN_INL_UTILS_H_ diff --git a/libraries/webp/src/utils/filters_utils.c b/libraries/webp/src/utils/filters_utils.c new file mode 100644 index 00000000000..bbc2c34d93a --- /dev/null +++ b/libraries/webp/src/utils/filters_utils.c @@ -0,0 +1,76 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// filter estimation +// +// Author: Urvang (urvang@google.com) + +#include "src/utils/filters_utils.h" +#include +#include + +// ----------------------------------------------------------------------------- +// Quick estimate of a potentially interesting filter mode to try. + +#define SMAX 16 +#define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX) + +static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { + const int g = a + b - c; + return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit +} + +WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data, + int width, int height, int stride) { + int i, j; + int bins[WEBP_FILTER_LAST][SMAX]; + memset(bins, 0, sizeof(bins)); + + // We only sample every other pixels. That's enough. + for (j = 2; j < height - 1; j += 2) { + const uint8_t* const p = data + j * stride; + int mean = p[0]; + for (i = 2; i < width - 1; i += 2) { + const int diff0 = SDIFF(p[i], mean); + const int diff1 = SDIFF(p[i], p[i - 1]); + const int diff2 = SDIFF(p[i], p[i - width]); + const int grad_pred = + GradientPredictor(p[i - 1], p[i - width], p[i - width - 1]); + const int diff3 = SDIFF(p[i], grad_pred); + bins[WEBP_FILTER_NONE][diff0] = 1; + bins[WEBP_FILTER_HORIZONTAL][diff1] = 1; + bins[WEBP_FILTER_VERTICAL][diff2] = 1; + bins[WEBP_FILTER_GRADIENT][diff3] = 1; + mean = (3 * mean + p[i] + 2) >> 2; + } + } + { + int filter; + WEBP_FILTER_TYPE best_filter = WEBP_FILTER_NONE; + int best_score = 0x7fffffff; + for (filter = WEBP_FILTER_NONE; filter < WEBP_FILTER_LAST; ++filter) { + int score = 0; + for (i = 0; i < SMAX; ++i) { + if (bins[filter][i] > 0) { + score += i; + } + } + if (score < best_score) { + best_score = score; + best_filter = (WEBP_FILTER_TYPE)filter; + } + } + return best_filter; + } +} + +#undef SMAX +#undef SDIFF + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/utils/filters_utils.h b/libraries/webp/src/utils/filters_utils.h new file mode 100644 index 00000000000..e3d8c784c10 --- /dev/null +++ b/libraries/webp/src/utils/filters_utils.h @@ -0,0 +1,32 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Spatial prediction using various filters +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_UTILS_FILTERS_UTILS_H_ +#define WEBP_UTILS_FILTERS_UTILS_H_ + +#include "include/webp/types.h" +#include "src/dsp/dsp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Fast estimate of a potentially good filter. +WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data, + int width, int height, int stride); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_FILTERS_UTILS_H_ diff --git a/libraries/webp/src/utils/huffman_encode_utils.c b/libraries/webp/src/utils/huffman_encode_utils.c new file mode 100644 index 00000000000..638d8fb79d7 --- /dev/null +++ b/libraries/webp/src/utils/huffman_encode_utils.c @@ -0,0 +1,416 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// +// Entropy encoding (Huffman) for webp lossless. + +#include +#include +#include +#include "src/utils/huffman_encode_utils.h" +#include "src/utils/utils.h" +#include "include/webp/format_constants.h" + +// ----------------------------------------------------------------------------- +// Util function to optimize the symbol map for RLE coding + +// Heuristics for selecting the stride ranges to collapse. +static int ValuesShouldBeCollapsedToStrideAverage(int a, int b) { + return abs(a - b) < 4; +} + +// Change the population counts in a way that the consequent +// Huffman tree compression, especially its RLE-part, give smaller output. +static void OptimizeHuffmanForRle(int length, uint8_t* const good_for_rle, + uint32_t* const counts) { + // 1) Let's make the Huffman code more compatible with rle encoding. + int i; + for (; length >= 0; --length) { + if (length == 0) { + return; // All zeros. + } + if (counts[length - 1] != 0) { + // Now counts[0..length - 1] does not have trailing zeros. + break; + } + } + // 2) Let's mark all population counts that already can be encoded + // with an rle code. + { + // Let's not spoil any of the existing good rle codes. + // Mark any seq of 0's that is longer as 5 as a good_for_rle. + // Mark any seq of non-0's that is longer as 7 as a good_for_rle. + uint32_t symbol = counts[0]; + int stride = 0; + for (i = 0; i < length + 1; ++i) { + if (i == length || counts[i] != symbol) { + if ((symbol == 0 && stride >= 5) || + (symbol != 0 && stride >= 7)) { + int k; + for (k = 0; k < stride; ++k) { + good_for_rle[i - k - 1] = 1; + } + } + stride = 1; + if (i != length) { + symbol = counts[i]; + } + } else { + ++stride; + } + } + } + // 3) Let's replace those population counts that lead to more rle codes. + { + uint32_t stride = 0; + uint32_t limit = counts[0]; + uint32_t sum = 0; + for (i = 0; i < length + 1; ++i) { + if (i == length || good_for_rle[i] || + (i != 0 && good_for_rle[i - 1]) || + !ValuesShouldBeCollapsedToStrideAverage(counts[i], limit)) { + if (stride >= 4 || (stride >= 3 && sum == 0)) { + uint32_t k; + // The stride must end, collapse what we have, if we have enough (4). + uint32_t count = (sum + stride / 2) / stride; + if (count < 1) { + count = 1; + } + if (sum == 0) { + // Don't make an all zeros stride to be upgraded to ones. + count = 0; + } + for (k = 0; k < stride; ++k) { + // We don't want to change value at counts[i], + // that is already belonging to the next stride. Thus - 1. + counts[i - k - 1] = count; + } + } + stride = 0; + sum = 0; + if (i < length - 3) { + // All interesting strides have a count of at least 4, + // at least when non-zeros. + limit = (counts[i] + counts[i + 1] + + counts[i + 2] + counts[i + 3] + 2) / 4; + } else if (i < length) { + limit = counts[i]; + } else { + limit = 0; + } + } + ++stride; + if (i != length) { + sum += counts[i]; + if (stride >= 4) { + limit = (sum + stride / 2) / stride; + } + } + } + } +} + +// A comparer function for two Huffman trees: sorts first by 'total count' +// (more comes first), and then by 'value' (more comes first). +static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) { + const HuffmanTree* const t1 = (const HuffmanTree*)ptr1; + const HuffmanTree* const t2 = (const HuffmanTree*)ptr2; + if (t1->total_count_ > t2->total_count_) { + return -1; + } else if (t1->total_count_ < t2->total_count_) { + return 1; + } else { + assert(t1->value_ != t2->value_); + return (t1->value_ < t2->value_) ? -1 : 1; + } +} + +static void SetBitDepths(const HuffmanTree* const tree, + const HuffmanTree* const pool, + uint8_t* const bit_depths, int level) { + if (tree->pool_index_left_ >= 0) { + SetBitDepths(&pool[tree->pool_index_left_], pool, bit_depths, level + 1); + SetBitDepths(&pool[tree->pool_index_right_], pool, bit_depths, level + 1); + } else { + bit_depths[tree->value_] = level; + } +} + +// Create an optimal Huffman tree. +// +// (data,length): population counts. +// tree_limit: maximum bit depth (inclusive) of the codes. +// bit_depths[]: how many bits are used for the symbol. +// +// Returns 0 when an error has occurred. +// +// The catch here is that the tree cannot be arbitrarily deep +// +// count_limit is the value that is to be faked as the minimum value +// and this minimum value is raised until the tree matches the +// maximum length requirement. +// +// This algorithm is not of excellent performance for very long data blocks, +// especially when population counts are longer than 2**tree_limit, but +// we are not planning to use this with extremely long blocks. +// +// See https://en.wikipedia.org/wiki/Huffman_coding +static void GenerateOptimalTree(const uint32_t* const histogram, + int histogram_size, + HuffmanTree* tree, int tree_depth_limit, + uint8_t* const bit_depths) { + uint32_t count_min; + HuffmanTree* tree_pool; + int tree_size_orig = 0; + int i; + + for (i = 0; i < histogram_size; ++i) { + if (histogram[i] != 0) { + ++tree_size_orig; + } + } + + if (tree_size_orig == 0) { // pretty optimal already! + return; + } + + tree_pool = tree + tree_size_orig; + + // For block sizes with less than 64k symbols we never need to do a + // second iteration of this loop. + // If we actually start running inside this loop a lot, we would perhaps + // be better off with the Katajainen algorithm. + assert(tree_size_orig <= (1 << (tree_depth_limit - 1))); + for (count_min = 1; ; count_min *= 2) { + int tree_size = tree_size_orig; + // We need to pack the Huffman tree in tree_depth_limit bits. + // So, we try by faking histogram entries to be at least 'count_min'. + int idx = 0; + int j; + for (j = 0; j < histogram_size; ++j) { + if (histogram[j] != 0) { + const uint32_t count = + (histogram[j] < count_min) ? count_min : histogram[j]; + tree[idx].total_count_ = count; + tree[idx].value_ = j; + tree[idx].pool_index_left_ = -1; + tree[idx].pool_index_right_ = -1; + ++idx; + } + } + + // Build the Huffman tree. + qsort(tree, tree_size, sizeof(*tree), CompareHuffmanTrees); + + if (tree_size > 1) { // Normal case. + int tree_pool_size = 0; + while (tree_size > 1) { // Finish when we have only one root. + uint32_t count; + tree_pool[tree_pool_size++] = tree[tree_size - 1]; + tree_pool[tree_pool_size++] = tree[tree_size - 2]; + count = tree_pool[tree_pool_size - 1].total_count_ + + tree_pool[tree_pool_size - 2].total_count_; + tree_size -= 2; + { + // Search for the insertion point. + int k; + for (k = 0; k < tree_size; ++k) { + if (tree[k].total_count_ <= count) { + break; + } + } + memmove(tree + (k + 1), tree + k, (tree_size - k) * sizeof(*tree)); + tree[k].total_count_ = count; + tree[k].value_ = -1; + + tree[k].pool_index_left_ = tree_pool_size - 1; + tree[k].pool_index_right_ = tree_pool_size - 2; + tree_size = tree_size + 1; + } + } + SetBitDepths(&tree[0], tree_pool, bit_depths, 0); + } else if (tree_size == 1) { // Trivial case: only one element. + bit_depths[tree[0].value_] = 1; + } + + { + // Test if this Huffman tree satisfies our 'tree_depth_limit' criteria. + int max_depth = bit_depths[0]; + for (j = 1; j < histogram_size; ++j) { + if (max_depth < bit_depths[j]) { + max_depth = bit_depths[j]; + } + } + if (max_depth <= tree_depth_limit) { + break; + } + } + } +} + +// ----------------------------------------------------------------------------- +// Coding of the Huffman tree values + +static HuffmanTreeToken* CodeRepeatedValues(int repetitions, + HuffmanTreeToken* tokens, + int value, int prev_value) { + assert(value <= MAX_ALLOWED_CODE_LENGTH); + if (value != prev_value) { + tokens->code = value; + tokens->extra_bits = 0; + ++tokens; + --repetitions; + } + while (repetitions >= 1) { + if (repetitions < 3) { + int i; + for (i = 0; i < repetitions; ++i) { + tokens->code = value; + tokens->extra_bits = 0; + ++tokens; + } + break; + } else if (repetitions < 7) { + tokens->code = 16; + tokens->extra_bits = repetitions - 3; + ++tokens; + break; + } else { + tokens->code = 16; + tokens->extra_bits = 3; + ++tokens; + repetitions -= 6; + } + } + return tokens; +} + +static HuffmanTreeToken* CodeRepeatedZeros(int repetitions, + HuffmanTreeToken* tokens) { + while (repetitions >= 1) { + if (repetitions < 3) { + int i; + for (i = 0; i < repetitions; ++i) { + tokens->code = 0; // 0-value + tokens->extra_bits = 0; + ++tokens; + } + break; + } else if (repetitions < 11) { + tokens->code = 17; + tokens->extra_bits = repetitions - 3; + ++tokens; + break; + } else if (repetitions < 139) { + tokens->code = 18; + tokens->extra_bits = repetitions - 11; + ++tokens; + break; + } else { + tokens->code = 18; + tokens->extra_bits = 0x7f; // 138 repeated 0s + ++tokens; + repetitions -= 138; + } + } + return tokens; +} + +int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, + HuffmanTreeToken* tokens, int max_tokens) { + HuffmanTreeToken* const starting_token = tokens; + HuffmanTreeToken* const ending_token = tokens + max_tokens; + const int depth_size = tree->num_symbols; + int prev_value = 8; // 8 is the initial value for rle. + int i = 0; + assert(tokens != NULL); + while (i < depth_size) { + const int value = tree->code_lengths[i]; + int k = i + 1; + int runs; + while (k < depth_size && tree->code_lengths[k] == value) ++k; + runs = k - i; + if (value == 0) { + tokens = CodeRepeatedZeros(runs, tokens); + } else { + tokens = CodeRepeatedValues(runs, tokens, value, prev_value); + prev_value = value; + } + i += runs; + assert(tokens <= ending_token); + } + (void)ending_token; // suppress 'unused variable' warning + return (int)(tokens - starting_token); +} + +// ----------------------------------------------------------------------------- + +// Pre-reversed 4-bit values. +static const uint8_t kReversedBits[16] = { + 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, + 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf +}; + +static uint32_t ReverseBits(int num_bits, uint32_t bits) { + uint32_t retval = 0; + int i = 0; + while (i < num_bits) { + i += 4; + retval |= kReversedBits[bits & 0xf] << (MAX_ALLOWED_CODE_LENGTH + 1 - i); + bits >>= 4; + } + retval >>= (MAX_ALLOWED_CODE_LENGTH + 1 - num_bits); + return retval; +} + +// Get the actual bit values for a tree of bit depths. +static void ConvertBitDepthsToSymbols(HuffmanTreeCode* const tree) { + // 0 bit-depth means that the symbol does not exist. + int i; + int len; + uint32_t next_code[MAX_ALLOWED_CODE_LENGTH + 1]; + int depth_count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 }; + + assert(tree != NULL); + len = tree->num_symbols; + for (i = 0; i < len; ++i) { + const int code_length = tree->code_lengths[i]; + assert(code_length <= MAX_ALLOWED_CODE_LENGTH); + ++depth_count[code_length]; + } + depth_count[0] = 0; // ignore unused symbol + next_code[0] = 0; + { + uint32_t code = 0; + for (i = 1; i <= MAX_ALLOWED_CODE_LENGTH; ++i) { + code = (code + depth_count[i - 1]) << 1; + next_code[i] = code; + } + } + for (i = 0; i < len; ++i) { + const int code_length = tree->code_lengths[i]; + tree->codes[i] = ReverseBits(code_length, next_code[code_length]++); + } +} + +// ----------------------------------------------------------------------------- +// Main entry point + +void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit, + uint8_t* const buf_rle, HuffmanTree* const huff_tree, + HuffmanTreeCode* const huff_code) { + const int num_symbols = huff_code->num_symbols; + memset(buf_rle, 0, num_symbols * sizeof(*buf_rle)); + OptimizeHuffmanForRle(num_symbols, buf_rle, histogram); + GenerateOptimalTree(histogram, num_symbols, huff_tree, tree_depth_limit, + huff_code->code_lengths); + // Create the actual bit codes for the bit lengths. + ConvertBitDepthsToSymbols(huff_code); +} diff --git a/libraries/webp/src/utils/huffman_encode_utils.h b/libraries/webp/src/utils/huffman_encode_utils.h new file mode 100644 index 00000000000..bd59ffa3ccc --- /dev/null +++ b/libraries/webp/src/utils/huffman_encode_utils.h @@ -0,0 +1,60 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// +// Entropy encoding (Huffman) for webp lossless + +#ifndef WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_ +#define WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_ + +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Struct for holding the tree header in coded form. +typedef struct { + uint8_t code; // value (0..15) or escape code (16,17,18) + uint8_t extra_bits; // extra bits for escape codes +} HuffmanTreeToken; + +// Struct to represent the tree codes (depth and bits array). +typedef struct { + int num_symbols; // Number of symbols. + uint8_t* code_lengths; // Code lengths of the symbols. + uint16_t* codes; // Symbol Codes. +} HuffmanTreeCode; + +// Struct to represent the Huffman tree. +typedef struct { + uint32_t total_count_; // Symbol frequency. + int value_; // Symbol value. + int pool_index_left_; // Index for the left sub-tree. + int pool_index_right_; // Index for the right sub-tree. +} HuffmanTree; + +// Turn the Huffman tree into a token sequence. +// Returns the number of tokens used. +int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, + HuffmanTreeToken* tokens, int max_tokens); + +// Create an optimized tree, and tokenize it. +// 'buf_rle' and 'huff_tree' are pre-allocated and the 'tree' is the constructed +// huffman code tree. +void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit, + uint8_t* const buf_rle, HuffmanTree* const huff_tree, + HuffmanTreeCode* const huff_code); + +#ifdef __cplusplus +} +#endif + +#endif // WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_ diff --git a/libraries/webp/src/utils/huffman_utils.c b/libraries/webp/src/utils/huffman_utils.c new file mode 100644 index 00000000000..7f54118a04a --- /dev/null +++ b/libraries/webp/src/utils/huffman_utils.c @@ -0,0 +1,299 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for building and looking up Huffman trees. +// +// Author: Urvang Joshi (urvang@google.com) + +#include +#include +#include +#include "src/utils/huffman_utils.h" +#include "src/utils/utils.h" +#include "include/webp/format_constants.h" + +// Huffman data read via DecodeImageStream is represented in two (red and green) +// bytes. +#define MAX_HTREE_GROUPS 0x10000 + +HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups) { + HTreeGroup* const htree_groups = + (HTreeGroup*)WebPSafeMalloc(num_htree_groups, sizeof(*htree_groups)); + if (htree_groups == NULL) { + return NULL; + } + assert(num_htree_groups <= MAX_HTREE_GROUPS); + return htree_groups; +} + +void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups) { + if (htree_groups != NULL) { + WebPSafeFree(htree_groups); + } +} + +// Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the +// bit-wise reversal of the len least significant bits of key. +static WEBP_INLINE uint32_t GetNextKey(uint32_t key, int len) { + uint32_t step = 1 << (len - 1); + while (key & step) { + step >>= 1; + } + return step ? (key & (step - 1)) + step : key; +} + +// Stores code in table[0], table[step], table[2*step], ..., table[end]. +// Assumes that end is an integer multiple of step. +static WEBP_INLINE void ReplicateValue(HuffmanCode* table, + int step, int end, + HuffmanCode code) { + assert(end % step == 0); + do { + end -= step; + table[end] = code; + } while (end > 0); +} + +// Returns the table width of the next 2nd level table. count is the histogram +// of bit lengths for the remaining symbols, len is the code length of the next +// processed symbol +static WEBP_INLINE int NextTableBitSize(const int* const count, + int len, int root_bits) { + int left = 1 << (len - root_bits); + while (len < MAX_ALLOWED_CODE_LENGTH) { + left -= count[len]; + if (left <= 0) break; + ++len; + left <<= 1; + } + return len - root_bits; +} + +// sorted[code_lengths_size] is a pre-allocated array for sorting symbols +// by code length. +static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits, + const int code_lengths[], int code_lengths_size, + uint16_t sorted[]) { + HuffmanCode* table = root_table; // next available space in table + int total_size = 1 << root_bits; // total size root table + 2nd level table + int len; // current code length + int symbol; // symbol index in original or sorted table + // number of codes of each length: + int count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 }; + // offsets in sorted table for each length: + int offset[MAX_ALLOWED_CODE_LENGTH + 1]; + + assert(code_lengths_size != 0); + assert(code_lengths != NULL); + assert((root_table != NULL && sorted != NULL) || + (root_table == NULL && sorted == NULL)); + assert(root_bits > 0); + + // Build histogram of code lengths. + for (symbol = 0; symbol < code_lengths_size; ++symbol) { + if (code_lengths[symbol] > MAX_ALLOWED_CODE_LENGTH) { + return 0; + } + ++count[code_lengths[symbol]]; + } + + // Error, all code lengths are zeros. + if (count[0] == code_lengths_size) { + return 0; + } + + // Generate offsets into sorted symbol table by code length. + offset[1] = 0; + for (len = 1; len < MAX_ALLOWED_CODE_LENGTH; ++len) { + if (count[len] > (1 << len)) { + return 0; + } + offset[len + 1] = offset[len] + count[len]; + } + + // Sort symbols by length, by symbol order within each length. + for (symbol = 0; symbol < code_lengths_size; ++symbol) { + const int symbol_code_length = code_lengths[symbol]; + if (code_lengths[symbol] > 0) { + if (sorted != NULL) { + if(offset[symbol_code_length] >= code_lengths_size) { + return 0; + } + sorted[offset[symbol_code_length]++] = symbol; + } else { + offset[symbol_code_length]++; + } + } + } + + // Special case code with only one value. + if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) { + if (sorted != NULL) { + HuffmanCode code; + code.bits = 0; + code.value = (uint16_t)sorted[0]; + ReplicateValue(table, 1, total_size, code); + } + return total_size; + } + + { + int step; // step size to replicate values in current table + uint32_t low = 0xffffffffu; // low bits for current root entry + uint32_t mask = total_size - 1; // mask for low bits + uint32_t key = 0; // reversed prefix code + int num_nodes = 1; // number of Huffman tree nodes + int num_open = 1; // number of open branches in current tree level + int table_bits = root_bits; // key length of current table + int table_size = 1 << table_bits; // size of current table + symbol = 0; + // Fill in root table. + for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) { + num_open <<= 1; + num_nodes += num_open; + num_open -= count[len]; + if (num_open < 0) { + return 0; + } + if (root_table == NULL) continue; + for (; count[len] > 0; --count[len]) { + HuffmanCode code; + code.bits = (uint8_t)len; + code.value = (uint16_t)sorted[symbol++]; + ReplicateValue(&table[key], step, table_size, code); + key = GetNextKey(key, len); + } + } + + // Fill in 2nd level tables and add pointers to root table. + for (len = root_bits + 1, step = 2; len <= MAX_ALLOWED_CODE_LENGTH; + ++len, step <<= 1) { + num_open <<= 1; + num_nodes += num_open; + num_open -= count[len]; + if (num_open < 0) { + return 0; + } + for (; count[len] > 0; --count[len]) { + HuffmanCode code; + if ((key & mask) != low) { + if (root_table != NULL) table += table_size; + table_bits = NextTableBitSize(count, len, root_bits); + table_size = 1 << table_bits; + total_size += table_size; + low = key & mask; + if (root_table != NULL) { + root_table[low].bits = (uint8_t)(table_bits + root_bits); + root_table[low].value = (uint16_t)((table - root_table) - low); + } + } + if (root_table != NULL) { + code.bits = (uint8_t)(len - root_bits); + code.value = (uint16_t)sorted[symbol++]; + ReplicateValue(&table[key >> root_bits], step, table_size, code); + } + key = GetNextKey(key, len); + } + } + + // Check if tree is full. + if (num_nodes != 2 * offset[MAX_ALLOWED_CODE_LENGTH] - 1) { + return 0; + } + } + + return total_size; +} + +// Maximum code_lengths_size is 2328 (reached for 11-bit color_cache_bits). +// More commonly, the value is around ~280. +#define MAX_CODE_LENGTHS_SIZE \ + ((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES) +// Cut-off value for switching between heap and stack allocation. +#define SORTED_SIZE_CUTOFF 512 +int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits, + const int code_lengths[], int code_lengths_size) { + const int total_size = + BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL); + assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE); + if (total_size == 0 || root_table == NULL) return total_size; + + if (root_table->curr_segment->curr_table + total_size >= + root_table->curr_segment->start + root_table->curr_segment->size) { + // If 'root_table' does not have enough memory, allocate a new segment. + // The available part of root_table->curr_segment is left unused because we + // need a contiguous buffer. + const int segment_size = root_table->curr_segment->size; + struct HuffmanTablesSegment* next = + (HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next)); + if (next == NULL) return 0; + // Fill the new segment. + // We need at least 'total_size' but if that value is small, it is better to + // allocate a big chunk to prevent more allocations later. 'segment_size' is + // therefore chosen (any other arbitrary value could be chosen). + next->size = total_size > segment_size ? total_size : segment_size; + next->start = + (HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start)); + if (next->start == NULL) { + WebPSafeFree(next); + return 0; + } + next->curr_table = next->start; + next->next = NULL; + // Point to the new segment. + root_table->curr_segment->next = next; + root_table->curr_segment = next; + } + if (code_lengths_size <= SORTED_SIZE_CUTOFF) { + // use local stack-allocated array. + uint16_t sorted[SORTED_SIZE_CUTOFF]; + BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits, + code_lengths, code_lengths_size, sorted); + } else { // rare case. Use heap allocation. + uint16_t* const sorted = + (uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted)); + if (sorted == NULL) return 0; + BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits, + code_lengths, code_lengths_size, sorted); + WebPSafeFree(sorted); + } + return total_size; +} + +int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) { + // Have 'segment' point to the first segment for now, 'root'. + HuffmanTablesSegment* const root = &huffman_tables->root; + huffman_tables->curr_segment = root; + root->next = NULL; + // Allocate root. + root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start)); + if (root->start == NULL) return 0; + root->curr_table = root->start; + root->size = size; + return 1; +} + +void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) { + HuffmanTablesSegment *current, *next; + if (huffman_tables == NULL) return; + // Free the root node. + current = &huffman_tables->root; + next = current->next; + WebPSafeFree(current->start); + current->start = NULL; + current->next = NULL; + current = next; + // Free the following nodes. + while (current != NULL) { + next = current->next; + WebPSafeFree(current->start); + WebPSafeFree(current); + current = next; + } +} diff --git a/libraries/webp/src/utils/huffman_utils.h b/libraries/webp/src/utils/huffman_utils.h new file mode 100644 index 00000000000..aafa5a4e095 --- /dev/null +++ b/libraries/webp/src/utils/huffman_utils.h @@ -0,0 +1,114 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for building and looking up Huffman trees. +// +// Author: Urvang Joshi (urvang@google.com) + +#ifndef WEBP_UTILS_HUFFMAN_UTILS_H_ +#define WEBP_UTILS_HUFFMAN_UTILS_H_ + +#include +#include "include/webp/format_constants.h" +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HUFFMAN_TABLE_BITS 8 +#define HUFFMAN_TABLE_MASK ((1 << HUFFMAN_TABLE_BITS) - 1) + +#define LENGTHS_TABLE_BITS 7 +#define LENGTHS_TABLE_MASK ((1 << LENGTHS_TABLE_BITS) - 1) + + +// Huffman lookup table entry +typedef struct { + uint8_t bits; // number of bits used for this symbol + uint16_t value; // symbol value or table offset +} HuffmanCode; + +// long version for holding 32b values +typedef struct { + int bits; // number of bits used for this symbol, + // or an impossible value if not a literal code. + uint32_t value; // 32b packed ARGB value if literal, + // or non-literal symbol otherwise +} HuffmanCode32; + +// Contiguous memory segment of HuffmanCodes. +typedef struct HuffmanTablesSegment { + HuffmanCode* start; + // Pointer to where we are writing into the segment. Starts at 'start' and + // cannot go beyond 'start' + 'size'. + HuffmanCode* curr_table; + // Pointer to the next segment in the chain. + struct HuffmanTablesSegment* next; + int size; +} HuffmanTablesSegment; + +// Chained memory segments of HuffmanCodes. +typedef struct HuffmanTables { + HuffmanTablesSegment root; + // Currently processed segment. At first, this is 'root'. + HuffmanTablesSegment* curr_segment; +} HuffmanTables; + +// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on +// memory allocation error, 1 otherwise. +WEBP_NODISCARD int VP8LHuffmanTablesAllocate(int size, + HuffmanTables* huffman_tables); +void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables); + +#define HUFFMAN_PACKED_BITS 6 +#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS) + +// Huffman table group. +// Includes special handling for the following cases: +// - is_trivial_literal: one common literal base for RED/BLUE/ALPHA (not GREEN) +// - is_trivial_code: only 1 code (no bit is read from bitstream) +// - use_packed_table: few enough literal symbols, so all the bit codes +// can fit into a small look-up table packed_table[] +// The common literal base, if applicable, is stored in 'literal_arb'. +typedef struct HTreeGroup HTreeGroup; +struct HTreeGroup { + HuffmanCode* htrees[HUFFMAN_CODES_PER_META_CODE]; + int is_trivial_literal; // True, if huffman trees for Red, Blue & Alpha + // Symbols are trivial (have a single code). + uint32_t literal_arb; // If is_trivial_literal is true, this is the + // ARGB value of the pixel, with Green channel + // being set to zero. + int is_trivial_code; // true if is_trivial_literal with only one code + int use_packed_table; // use packed table below for short literal code + // table mapping input bits to a packed values, or escape case to literal code + HuffmanCode32 packed_table[HUFFMAN_PACKED_TABLE_SIZE]; +}; + +// Creates the instance of HTreeGroup with specified number of tree-groups. +WEBP_NODISCARD HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups); + +// Releases the memory allocated for HTreeGroup. +void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups); + +// Builds Huffman lookup table assuming code lengths are in symbol order. +// The 'code_lengths' is pre-allocated temporary memory buffer used for creating +// the huffman table. +// Returns built table size or 0 in case of error (invalid tree or +// memory error). +WEBP_NODISCARD int VP8LBuildHuffmanTable(HuffmanTables* const root_table, + int root_bits, + const int code_lengths[], + int code_lengths_size); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_HUFFMAN_UTILS_H_ diff --git a/libraries/webp/src/utils/palette.c b/libraries/webp/src/utils/palette.c new file mode 100644 index 00000000000..aa21b14d7d3 --- /dev/null +++ b/libraries/webp/src/utils/palette.c @@ -0,0 +1,402 @@ +// Copyright 2023 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for palette analysis. +// +// Author: Vincent Rabaud (vrabaud@google.com) + +#include "src/utils/palette.h" + +#include +#include + +#include "src/dsp/lossless_common.h" +#include "src/utils/color_cache_utils.h" +#include "src/utils/utils.h" +#include "include/webp/encode.h" +#include "include/webp/format_constants.h" + +// ----------------------------------------------------------------------------- + +// Palette reordering for smaller sum of deltas (and for smaller storage). + +static int PaletteCompareColorsForQsort(const void* p1, const void* p2) { + const uint32_t a = WebPMemToUint32((uint8_t*)p1); + const uint32_t b = WebPMemToUint32((uint8_t*)p2); + assert(a != b); + return (a < b) ? -1 : 1; +} + +static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) { + return (v <= 128) ? v : (256 - v); +} + +// Computes a value that is related to the entropy created by the +// palette entry diff. +// +// Note that the last & 0xff is a no-operation in the next statement, but +// removed by most compilers and is here only for regularity of the code. +static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) { + const uint32_t diff = VP8LSubPixels(col1, col2); + const int kMoreWeightForRGBThanForAlpha = 9; + uint32_t score; + score = PaletteComponentDistance((diff >> 0) & 0xff); + score += PaletteComponentDistance((diff >> 8) & 0xff); + score += PaletteComponentDistance((diff >> 16) & 0xff); + score *= kMoreWeightForRGBThanForAlpha; + score += PaletteComponentDistance((diff >> 24) & 0xff); + return score; +} + +static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) { + const uint32_t tmp = *col1; + *col1 = *col2; + *col2 = tmp; +} + +int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, int num_colors) { + int low = 0, hi = num_colors; + if (sorted[low] == color) return low; // loop invariant: sorted[low] != color + while (1) { + const int mid = (low + hi) >> 1; + if (sorted[mid] == color) { + return mid; + } else if (sorted[mid] < color) { + low = mid; + } else { + hi = mid; + } + } + assert(0); + return 0; +} + +void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors, + uint32_t sorted[], uint32_t idx_map[]) { + uint32_t i; + memcpy(sorted, palette, num_colors * sizeof(*sorted)); + qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort); + for (i = 0; i < num_colors; ++i) { + idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i; + } +} + +//------------------------------------------------------------------------------ + +#define COLOR_HASH_SIZE (MAX_PALETTE_SIZE * 4) +#define COLOR_HASH_RIGHT_SHIFT 22 // 32 - log2(COLOR_HASH_SIZE). + +int GetColorPalette(const WebPPicture* const pic, uint32_t* const palette) { + int i; + int x, y; + int num_colors = 0; + uint8_t in_use[COLOR_HASH_SIZE] = {0}; + uint32_t colors[COLOR_HASH_SIZE] = {0}; + const uint32_t* argb = pic->argb; + const int width = pic->width; + const int height = pic->height; + uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0] + assert(pic != NULL); + assert(pic->use_argb); + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + int key; + if (argb[x] == last_pix) { + continue; + } + last_pix = argb[x]; + key = VP8LHashPix(last_pix, COLOR_HASH_RIGHT_SHIFT); + while (1) { + if (!in_use[key]) { + colors[key] = last_pix; + in_use[key] = 1; + ++num_colors; + if (num_colors > MAX_PALETTE_SIZE) { + return MAX_PALETTE_SIZE + 1; // Exact count not needed. + } + break; + } else if (colors[key] == last_pix) { + break; // The color is already there. + } else { + // Some other color sits here, so do linear conflict resolution. + ++key; + key &= (COLOR_HASH_SIZE - 1); // Key mask. + } + } + } + argb += pic->argb_stride; + } + + if (palette != NULL) { // Fill the colors into palette. + num_colors = 0; + for (i = 0; i < COLOR_HASH_SIZE; ++i) { + if (in_use[i]) { + palette[num_colors] = colors[i]; + ++num_colors; + } + } + qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort); + } + return num_colors; +} + +#undef COLOR_HASH_SIZE +#undef COLOR_HASH_RIGHT_SHIFT + +// ----------------------------------------------------------------------------- + +// The palette has been sorted by alpha. This function checks if the other +// components of the palette have a monotonic development with regards to +// position in the palette. If all have monotonic development, there is +// no benefit to re-organize them greedily. A monotonic development +// would be spotted in green-only situations (like lossy alpha) or gray-scale +// images. +static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette, + int num_colors) { + uint32_t predict = 0x000000; + int i; + uint8_t sign_found = 0x00; + for (i = 0; i < num_colors; ++i) { + const uint32_t diff = VP8LSubPixels(palette[i], predict); + const uint8_t rd = (diff >> 16) & 0xff; + const uint8_t gd = (diff >> 8) & 0xff; + const uint8_t bd = (diff >> 0) & 0xff; + if (rd != 0x00) { + sign_found |= (rd < 0x80) ? 1 : 2; + } + if (gd != 0x00) { + sign_found |= (gd < 0x80) ? 8 : 16; + } + if (bd != 0x00) { + sign_found |= (bd < 0x80) ? 64 : 128; + } + predict = palette[i]; + } + return (sign_found & (sign_found << 1)) != 0; // two consequent signs. +} + +static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted, + int num_colors, uint32_t* const palette) { + uint32_t predict = 0x00000000; + int i, k; + memcpy(palette, palette_sorted, num_colors * sizeof(*palette)); + if (!PaletteHasNonMonotonousDeltas(palette_sorted, num_colors)) return; + // Find greedily always the closest color of the predicted color to minimize + // deltas in the palette. This reduces storage needs since the + // palette is stored with delta encoding. + for (i = 0; i < num_colors; ++i) { + int best_ix = i; + uint32_t best_score = ~0U; + for (k = i; k < num_colors; ++k) { + const uint32_t cur_score = PaletteColorDistance(palette[k], predict); + if (best_score > cur_score) { + best_score = cur_score; + best_ix = k; + } + } + SwapColor(&palette[best_ix], &palette[i]); + predict = palette[i]; + } +} + +// ----------------------------------------------------------------------------- +// Modified Zeng method from "A Survey on Palette Reordering +// Methods for Improving the Compression of Color-Indexed Images" by Armando J. +// Pinho and Antonio J. R. Neves. + +// Finds the biggest cooccurrence in the matrix. +static void CoOccurrenceFindMax(const uint32_t* const cooccurrence, + uint32_t num_colors, uint8_t* const c1, + uint8_t* const c2) { + // Find the index that is most frequently located adjacent to other + // (different) indexes. + uint32_t best_sum = 0u; + uint32_t i, j, best_cooccurrence; + *c1 = 0u; + for (i = 0; i < num_colors; ++i) { + uint32_t sum = 0; + for (j = 0; j < num_colors; ++j) sum += cooccurrence[i * num_colors + j]; + if (sum > best_sum) { + best_sum = sum; + *c1 = i; + } + } + // Find the index that is most frequently found adjacent to *c1. + *c2 = 0u; + best_cooccurrence = 0u; + for (i = 0; i < num_colors; ++i) { + if (cooccurrence[*c1 * num_colors + i] > best_cooccurrence) { + best_cooccurrence = cooccurrence[*c1 * num_colors + i]; + *c2 = i; + } + } + assert(*c1 != *c2); +} + +// Builds the cooccurrence matrix +static int CoOccurrenceBuild(const WebPPicture* const pic, + const uint32_t* const palette, uint32_t num_colors, + uint32_t* cooccurrence) { + uint32_t *lines, *line_top, *line_current, *line_tmp; + int x, y; + const uint32_t* src = pic->argb; + uint32_t prev_pix = ~src[0]; + uint32_t prev_idx = 0u; + uint32_t idx_map[MAX_PALETTE_SIZE] = {0}; + uint32_t palette_sorted[MAX_PALETTE_SIZE]; + lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines)); + if (lines == NULL) { + return 0; + } + line_top = &lines[0]; + line_current = &lines[pic->width]; + PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map); + for (y = 0; y < pic->height; ++y) { + for (x = 0; x < pic->width; ++x) { + const uint32_t pix = src[x]; + if (pix != prev_pix) { + prev_idx = idx_map[SearchColorNoIdx(palette_sorted, pix, num_colors)]; + prev_pix = pix; + } + line_current[x] = prev_idx; + // 4-connectivity is what works best as mentioned in "On the relation + // between Memon's and the modified Zeng's palette reordering methods". + if (x > 0 && prev_idx != line_current[x - 1]) { + const uint32_t left_idx = line_current[x - 1]; + ++cooccurrence[prev_idx * num_colors + left_idx]; + ++cooccurrence[left_idx * num_colors + prev_idx]; + } + if (y > 0 && prev_idx != line_top[x]) { + const uint32_t top_idx = line_top[x]; + ++cooccurrence[prev_idx * num_colors + top_idx]; + ++cooccurrence[top_idx * num_colors + prev_idx]; + } + } + line_tmp = line_top; + line_top = line_current; + line_current = line_tmp; + src += pic->argb_stride; + } + WebPSafeFree(lines); + return 1; +} + +struct Sum { + uint8_t index; + uint32_t sum; +}; + +static int PaletteSortModifiedZeng(const WebPPicture* const pic, + const uint32_t* const palette_in, + uint32_t num_colors, + uint32_t* const palette) { + uint32_t i, j, ind; + uint8_t remapping[MAX_PALETTE_SIZE]; + uint32_t* cooccurrence; + struct Sum sums[MAX_PALETTE_SIZE]; + uint32_t first, last; + uint32_t num_sums; + // TODO(vrabaud) check whether one color images should use palette or not. + if (num_colors <= 1) return 1; + // Build the co-occurrence matrix. + cooccurrence = + (uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence)); + if (cooccurrence == NULL) { + return 0; + } + if (!CoOccurrenceBuild(pic, palette_in, num_colors, cooccurrence)) { + WebPSafeFree(cooccurrence); + return 0; + } + + // Initialize the mapping list with the two best indices. + CoOccurrenceFindMax(cooccurrence, num_colors, &remapping[0], &remapping[1]); + + // We need to append and prepend to the list of remapping. To this end, we + // actually define the next start/end of the list as indices in a vector (with + // a wrap around when the end is reached). + first = 0; + last = 1; + num_sums = num_colors - 2; // -2 because we know the first two values + if (num_sums > 0) { + // Initialize the sums with the first two remappings and find the best one + struct Sum* best_sum = &sums[0]; + best_sum->index = 0u; + best_sum->sum = 0u; + for (i = 0, j = 0; i < num_colors; ++i) { + if (i == remapping[0] || i == remapping[1]) continue; + sums[j].index = i; + sums[j].sum = cooccurrence[i * num_colors + remapping[0]] + + cooccurrence[i * num_colors + remapping[1]]; + if (sums[j].sum > best_sum->sum) best_sum = &sums[j]; + ++j; + } + + while (num_sums > 0) { + const uint8_t best_index = best_sum->index; + // Compute delta to know if we need to prepend or append the best index. + int32_t delta = 0; + const int32_t n = num_colors - num_sums; + for (ind = first, j = 0; (ind + j) % num_colors != last + 1; ++j) { + const uint16_t l_j = remapping[(ind + j) % num_colors]; + delta += (n - 1 - 2 * (int32_t)j) * + (int32_t)cooccurrence[best_index * num_colors + l_j]; + } + if (delta > 0) { + first = (first == 0) ? num_colors - 1 : first - 1; + remapping[first] = best_index; + } else { + ++last; + remapping[last] = best_index; + } + // Remove best_sum from sums. + *best_sum = sums[num_sums - 1]; + --num_sums; + // Update all the sums and find the best one. + best_sum = &sums[0]; + for (i = 0; i < num_sums; ++i) { + sums[i].sum += cooccurrence[best_index * num_colors + sums[i].index]; + if (sums[i].sum > best_sum->sum) best_sum = &sums[i]; + } + } + } + assert((last + 1) % num_colors == first); + WebPSafeFree(cooccurrence); + + // Re-map the palette. + for (i = 0; i < num_colors; ++i) { + palette[i] = palette_in[remapping[(first + i) % num_colors]]; + } + return 1; +} + +// ----------------------------------------------------------------------------- + +int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic, + const uint32_t* const palette_sorted, uint32_t num_colors, + uint32_t* const palette) { + switch (method) { + case kSortedDefault: + // Nothing to do, we have already sorted the palette. + memcpy(palette, palette_sorted, num_colors * sizeof(*palette)); + return 1; + case kMinimizeDelta: + PaletteSortMinimizeDeltas(palette_sorted, num_colors, palette); + return 1; + case kModifiedZeng: + return PaletteSortModifiedZeng(pic, palette_sorted, num_colors, palette); + case kUnusedPalette: + case kPaletteSortingNum: + break; + } + + assert(0); + return 0; +} diff --git a/libraries/webp/src/utils/palette.h b/libraries/webp/src/utils/palette.h new file mode 100644 index 00000000000..655007ac426 --- /dev/null +++ b/libraries/webp/src/utils/palette.h @@ -0,0 +1,60 @@ +// Copyright 2023 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Utilities for palette analysis. +// +// Author: Vincent Rabaud (vrabaud@google.com) + +#ifndef WEBP_UTILS_PALETTE_H_ +#define WEBP_UTILS_PALETTE_H_ + +#include "include/webp/types.h" + +struct WebPPicture; + +// The different ways a palette can be sorted. +typedef enum PaletteSorting { + kSortedDefault = 0, + // Sorts by minimizing L1 deltas between consecutive colors, giving more + // weight to RGB colors. + kMinimizeDelta = 1, + // Implements the modified Zeng method from "A Survey on Palette Reordering + // Methods for Improving the Compression of Color-Indexed Images" by Armando + // J. Pinho and Antonio J. R. Neves. + kModifiedZeng = 2, + kUnusedPalette = 3, + kPaletteSortingNum = 4 +} PaletteSorting; + +// Returns the index of 'color' in the sorted palette 'sorted' of size +// 'num_colors'. +int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, int num_colors); + +// Sort palette in increasing order and prepare an inverse mapping array. +void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors, + uint32_t sorted[], uint32_t idx_map[]); + +// Returns count of unique colors in 'pic', assuming pic->use_argb is true. +// If the unique color count is more than MAX_PALETTE_SIZE, returns +// MAX_PALETTE_SIZE+1. +// If 'palette' is not NULL and the number of unique colors is less than or +// equal to MAX_PALETTE_SIZE, also outputs the actual unique colors into +// 'palette' in a sorted order. Note: 'palette' is assumed to be an array +// already allocated with at least MAX_PALETTE_SIZE elements. +int GetColorPalette(const struct WebPPicture* const pic, + uint32_t* const palette); + +// Sorts the palette according to the criterion defined by 'method'. +// 'palette_sorted' is the input palette sorted lexicographically, as done in +// PrepareMapToPalette. Returns 0 on memory allocation error. +int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic, + const uint32_t* const palette_sorted, uint32_t num_colors, + uint32_t* const palette); + +#endif // WEBP_UTILS_PALETTE_H_ diff --git a/libraries/webp/src/utils/quant_levels_dec_utils.c b/libraries/webp/src/utils/quant_levels_dec_utils.c new file mode 100644 index 00000000000..97e78937043 --- /dev/null +++ b/libraries/webp/src/utils/quant_levels_dec_utils.c @@ -0,0 +1,291 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Implement gradient smoothing: we replace a current alpha value by its +// surrounding average if it's close enough (that is: the change will be less +// than the minimum distance between two quantized level). +// We use sliding window for computing the 2d moving average. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/utils/quant_levels_dec_utils.h" + +#include // for memset + +#include "src/utils/utils.h" + +// #define USE_DITHERING // uncomment to enable ordered dithering (not vital) + +#define FIX 16 // fix-point precision for averaging +#define LFIX 2 // extra precision for look-up table +#define LUT_SIZE ((1 << (8 + LFIX)) - 1) // look-up table size + +#if defined(USE_DITHERING) + +#define DFIX 4 // extra precision for ordered dithering +#define DSIZE 4 // dithering size (must be a power of two) +// cf. https://en.wikipedia.org/wiki/Ordered_dithering +static const uint8_t kOrderedDither[DSIZE][DSIZE] = { + { 0, 8, 2, 10 }, // coefficients are in DFIX fixed-point precision + { 12, 4, 14, 6 }, + { 3, 11, 1, 9 }, + { 15, 7, 13, 5 } +}; + +#else +#define DFIX 0 +#endif + +typedef struct { + int width_, height_; // dimension + int stride_; // stride in bytes + int row_; // current input row being processed + uint8_t* src_; // input pointer + uint8_t* dst_; // output pointer + + int radius_; // filter radius (=delay) + int scale_; // normalization factor, in FIX bits precision + + void* mem_; // all memory + + // various scratch buffers + uint16_t* start_; + uint16_t* cur_; + uint16_t* end_; + uint16_t* top_; + uint16_t* average_; + + // input levels distribution + int num_levels_; // number of quantized levels + int min_, max_; // min and max level values + int min_level_dist_; // smallest distance between two consecutive levels + + int16_t* correction_; // size = 1 + 2*LUT_SIZE -> ~4k memory +} SmoothParams; + +//------------------------------------------------------------------------------ + +#define CLIP_8b_MASK (int)(~0U << (8 + DFIX)) +static WEBP_INLINE uint8_t clip_8b(int v) { + return (!(v & CLIP_8b_MASK)) ? (uint8_t)(v >> DFIX) : (v < 0) ? 0u : 255u; +} +#undef CLIP_8b_MASK + +// vertical accumulation +static void VFilter(SmoothParams* const p) { + const uint8_t* src = p->src_; + const int w = p->width_; + uint16_t* const cur = p->cur_; + const uint16_t* const top = p->top_; + uint16_t* const out = p->end_; + uint16_t sum = 0; // all arithmetic is modulo 16bit + int x; + + for (x = 0; x < w; ++x) { + uint16_t new_value; + sum += src[x]; + new_value = top[x] + sum; + out[x] = new_value - cur[x]; // vertical sum of 'r' pixels. + cur[x] = new_value; + } + // move input pointers one row down + p->top_ = p->cur_; + p->cur_ += w; + if (p->cur_ == p->end_) p->cur_ = p->start_; // roll-over + // We replicate edges, as it's somewhat easier as a boundary condition. + // That's why we don't update the 'src' pointer on top/bottom area: + if (p->row_ >= 0 && p->row_ < p->height_ - 1) { + p->src_ += p->stride_; + } +} + +// horizontal accumulation. We use mirror replication of missing pixels, as it's +// a little easier to implement (surprisingly). +static void HFilter(SmoothParams* const p) { + const uint16_t* const in = p->end_; + uint16_t* const out = p->average_; + const uint32_t scale = p->scale_; + const int w = p->width_; + const int r = p->radius_; + + int x; + for (x = 0; x <= r; ++x) { // left mirroring + const uint16_t delta = in[x + r - 1] + in[r - x]; + out[x] = (delta * scale) >> FIX; + } + for (; x < w - r; ++x) { // bulk middle run + const uint16_t delta = in[x + r] - in[x - r - 1]; + out[x] = (delta * scale) >> FIX; + } + for (; x < w; ++x) { // right mirroring + const uint16_t delta = + 2 * in[w - 1] - in[2 * w - 2 - r - x] - in[x - r - 1]; + out[x] = (delta * scale) >> FIX; + } +} + +// emit one filtered output row +static void ApplyFilter(SmoothParams* const p) { + const uint16_t* const average = p->average_; + const int w = p->width_; + const int16_t* const correction = p->correction_; +#if defined(USE_DITHERING) + const uint8_t* const dither = kOrderedDither[p->row_ % DSIZE]; +#endif + uint8_t* const dst = p->dst_; + int x; + for (x = 0; x < w; ++x) { + const int v = dst[x]; + if (v < p->max_ && v > p->min_) { + const int c = (v << DFIX) + correction[average[x] - (v << LFIX)]; +#if defined(USE_DITHERING) + dst[x] = clip_8b(c + dither[x % DSIZE]); +#else + dst[x] = clip_8b(c); +#endif + } + } + p->dst_ += p->stride_; // advance output pointer +} + +//------------------------------------------------------------------------------ +// Initialize correction table + +static void InitCorrectionLUT(int16_t* const lut, int min_dist) { + // The correction curve is: + // f(x) = x for x <= threshold2 + // f(x) = 0 for x >= threshold1 + // and a linear interpolation for range x=[threshold2, threshold1] + // (along with f(-x) = -f(x) symmetry). + // Note that: threshold2 = 3/4 * threshold1 + const int threshold1 = min_dist << LFIX; + const int threshold2 = (3 * threshold1) >> 2; + const int max_threshold = threshold2 << DFIX; + const int delta = threshold1 - threshold2; + int i; + for (i = 1; i <= LUT_SIZE; ++i) { + int c = (i <= threshold2) ? (i << DFIX) + : (i < threshold1) ? max_threshold * (threshold1 - i) / delta + : 0; + c >>= LFIX; + lut[+i] = +c; + lut[-i] = -c; + } + lut[0] = 0; +} + +static void CountLevels(SmoothParams* const p) { + int i, j, last_level; + uint8_t used_levels[256] = { 0 }; + const uint8_t* data = p->src_; + p->min_ = 255; + p->max_ = 0; + for (j = 0; j < p->height_; ++j) { + for (i = 0; i < p->width_; ++i) { + const int v = data[i]; + if (v < p->min_) p->min_ = v; + if (v > p->max_) p->max_ = v; + used_levels[v] = 1; + } + data += p->stride_; + } + // Compute the mininum distance between two non-zero levels. + p->min_level_dist_ = p->max_ - p->min_; + last_level = -1; + for (i = 0; i < 256; ++i) { + if (used_levels[i]) { + ++p->num_levels_; + if (last_level >= 0) { + const int level_dist = i - last_level; + if (level_dist < p->min_level_dist_) { + p->min_level_dist_ = level_dist; + } + } + last_level = i; + } + } +} + +// Initialize all params. +static int InitParams(uint8_t* const data, int width, int height, int stride, + int radius, SmoothParams* const p) { + const int R = 2 * radius + 1; // total size of the kernel + + const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start_); + const size_t size_m = width * sizeof(*p->average_); + const size_t size_lut = (1 + 2 * LUT_SIZE) * sizeof(*p->correction_); + const size_t total_size = size_scratch_m + size_m + size_lut; + uint8_t* mem = (uint8_t*)WebPSafeMalloc(1U, total_size); + + if (mem == NULL) return 0; + p->mem_ = (void*)mem; + + p->start_ = (uint16_t*)mem; + p->cur_ = p->start_; + p->end_ = p->start_ + R * width; + p->top_ = p->end_ - width; + memset(p->top_, 0, width * sizeof(*p->top_)); + mem += size_scratch_m; + + p->average_ = (uint16_t*)mem; + mem += size_m; + + p->width_ = width; + p->height_ = height; + p->stride_ = stride; + p->src_ = data; + p->dst_ = data; + p->radius_ = radius; + p->scale_ = (1 << (FIX + LFIX)) / (R * R); // normalization constant + p->row_ = -radius; + + // analyze the input distribution so we can best-fit the threshold + CountLevels(p); + + // correction table + p->correction_ = ((int16_t*)mem) + LUT_SIZE; + InitCorrectionLUT(p->correction_, p->min_level_dist_); + + return 1; +} + +static void CleanupParams(SmoothParams* const p) { + WebPSafeFree(p->mem_); +} + +int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride, + int strength) { + int radius = 4 * strength / 100; + + if (strength < 0 || strength > 100) return 0; + if (data == NULL || width <= 0 || height <= 0) return 0; // bad params + + // limit the filter size to not exceed the image dimensions + if (2 * radius + 1 > width) radius = (width - 1) >> 1; + if (2 * radius + 1 > height) radius = (height - 1) >> 1; + + if (radius > 0) { + SmoothParams p; + memset(&p, 0, sizeof(p)); + if (!InitParams(data, width, height, stride, radius, &p)) return 0; + if (p.num_levels_ > 2) { + for (; p.row_ < p.height_; ++p.row_) { + VFilter(&p); // accumulate average of input + // Need to wait few rows in order to prime the filter, + // before emitting some output. + if (p.row_ >= p.radius_) { + HFilter(&p); + ApplyFilter(&p); + } + } + } + CleanupParams(&p); + } + return 1; +} diff --git a/libraries/webp/src/utils/quant_levels_dec_utils.h b/libraries/webp/src/utils/quant_levels_dec_utils.h new file mode 100644 index 00000000000..9b1e73c776e --- /dev/null +++ b/libraries/webp/src/utils/quant_levels_dec_utils.h @@ -0,0 +1,35 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Alpha plane de-quantization utility +// +// Author: Vikas Arora (vikasa@google.com) + +#ifndef WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ +#define WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ + +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Apply post-processing to input 'data' of size 'width'x'height' assuming that +// the source was quantized to a reduced number of levels. 'stride' is in bytes. +// Strength is in [0..100] and controls the amount of dithering applied. +// Returns false in case of error (data is NULL, invalid parameters, +// malloc failure, ...). +int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride, + int strength); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ diff --git a/libraries/webp/src/utils/quant_levels_utils.c b/libraries/webp/src/utils/quant_levels_utils.c new file mode 100644 index 00000000000..d65ad3c29db --- /dev/null +++ b/libraries/webp/src/utils/quant_levels_utils.c @@ -0,0 +1,140 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Quantize levels for specified number of quantization-levels ([2, 256]). +// Min and max values are preserved (usual 0 and 255 for alpha plane). +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "src/utils/quant_levels_utils.h" + +#define NUM_SYMBOLS 256 + +#define MAX_ITER 6 // Maximum number of convergence steps. +#define ERROR_THRESHOLD 1e-4 // MSE stopping criterion. + +// ----------------------------------------------------------------------------- +// Quantize levels. + +int QuantizeLevels(uint8_t* const data, int width, int height, + int num_levels, uint64_t* const sse) { + int freq[NUM_SYMBOLS] = { 0 }; + int q_level[NUM_SYMBOLS] = { 0 }; + double inv_q_level[NUM_SYMBOLS] = { 0 }; + int min_s = 255, max_s = 0; + const size_t data_size = height * width; + int i, num_levels_in, iter; + double last_err = 1.e38, err = 0.; + const double err_threshold = ERROR_THRESHOLD * data_size; + + if (data == NULL) { + return 0; + } + + if (width <= 0 || height <= 0) { + return 0; + } + + if (num_levels < 2 || num_levels > 256) { + return 0; + } + + { + size_t n; + num_levels_in = 0; + for (n = 0; n < data_size; ++n) { + num_levels_in += (freq[data[n]] == 0); + if (min_s > data[n]) min_s = data[n]; + if (max_s < data[n]) max_s = data[n]; + ++freq[data[n]]; + } + } + + if (num_levels_in <= num_levels) goto End; // nothing to do! + + // Start with uniformly spread centroids. + for (i = 0; i < num_levels; ++i) { + inv_q_level[i] = min_s + (double)(max_s - min_s) * i / (num_levels - 1); + } + + // Fixed values. Won't be changed. + q_level[min_s] = 0; + q_level[max_s] = num_levels - 1; + assert(inv_q_level[0] == min_s); + assert(inv_q_level[num_levels - 1] == max_s); + + // k-Means iterations. + for (iter = 0; iter < MAX_ITER; ++iter) { + double q_sum[NUM_SYMBOLS] = { 0 }; + double q_count[NUM_SYMBOLS] = { 0 }; + int s, slot = 0; + + // Assign classes to representatives. + for (s = min_s; s <= max_s; ++s) { + // Keep track of the nearest neighbour 'slot' + while (slot < num_levels - 1 && + 2 * s > inv_q_level[slot] + inv_q_level[slot + 1]) { + ++slot; + } + if (freq[s] > 0) { + q_sum[slot] += s * freq[s]; + q_count[slot] += freq[s]; + } + q_level[s] = slot; + } + + // Assign new representatives to classes. + if (num_levels > 2) { + for (slot = 1; slot < num_levels - 1; ++slot) { + const double count = q_count[slot]; + if (count > 0.) { + inv_q_level[slot] = q_sum[slot] / count; + } + } + } + + // Compute convergence error. + err = 0.; + for (s = min_s; s <= max_s; ++s) { + const double error = s - inv_q_level[q_level[s]]; + err += freq[s] * error * error; + } + + // Check for convergence: we stop as soon as the error is no + // longer improving. + if (last_err - err < err_threshold) break; + last_err = err; + } + + // Remap the alpha plane to quantized values. + { + // double->int rounding operation can be costly, so we do it + // once for all before remapping. We also perform the data[] -> slot + // mapping, while at it (avoid one indirection in the final loop). + uint8_t map[NUM_SYMBOLS]; + int s; + size_t n; + for (s = min_s; s <= max_s; ++s) { + const int slot = q_level[s]; + map[s] = (uint8_t)(inv_q_level[slot] + .5); + } + // Final pass. + for (n = 0; n < data_size; ++n) { + data[n] = map[data[n]]; + } + } + End: + // Store sum of squared error if needed. + if (sse != NULL) *sse = (uint64_t)err; + + return 1; +} + diff --git a/libraries/webp/src/utils/quant_levels_utils.h b/libraries/webp/src/utils/quant_levels_utils.h new file mode 100644 index 00000000000..8e283ed1630 --- /dev/null +++ b/libraries/webp/src/utils/quant_levels_utils.h @@ -0,0 +1,36 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Alpha plane quantization utility +// +// Author: Vikas Arora (vikasa@google.com) + +#ifndef WEBP_UTILS_QUANT_LEVELS_UTILS_H_ +#define WEBP_UTILS_QUANT_LEVELS_UTILS_H_ + +#include + +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Replace the input 'data' of size 'width'x'height' with 'num-levels' +// quantized values. If not NULL, 'sse' will contain the sum of squared error. +// Valid range for 'num_levels' is [2, 256]. +// Returns false in case of error (data is NULL, or parameters are invalid). +int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels, + uint64_t* const sse); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_QUANT_LEVELS_UTILS_H_ diff --git a/libraries/webp/src/utils/random_utils.c b/libraries/webp/src/utils/random_utils.c new file mode 100644 index 00000000000..7edb3fefbb8 --- /dev/null +++ b/libraries/webp/src/utils/random_utils.c @@ -0,0 +1,43 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Pseudo-random utilities +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include "src/utils/random_utils.h" + +//------------------------------------------------------------------------------ + +// 31b-range values +static const uint32_t kRandomTable[VP8_RANDOM_TABLE_SIZE] = { + 0x0de15230, 0x03b31886, 0x775faccb, 0x1c88626a, 0x68385c55, 0x14b3b828, + 0x4a85fef8, 0x49ddb84b, 0x64fcf397, 0x5c550289, 0x4a290000, 0x0d7ec1da, + 0x5940b7ab, 0x5492577d, 0x4e19ca72, 0x38d38c69, 0x0c01ee65, 0x32a1755f, + 0x5437f652, 0x5abb2c32, 0x0faa57b1, 0x73f533e7, 0x685feeda, 0x7563cce2, + 0x6e990e83, 0x4730a7ed, 0x4fc0d9c6, 0x496b153c, 0x4f1403fa, 0x541afb0c, + 0x73990b32, 0x26d7cb1c, 0x6fcc3706, 0x2cbb77d8, 0x75762f2a, 0x6425ccdd, + 0x24b35461, 0x0a7d8715, 0x220414a8, 0x141ebf67, 0x56b41583, 0x73e502e3, + 0x44cab16f, 0x28264d42, 0x73baaefb, 0x0a50ebed, 0x1d6ab6fb, 0x0d3ad40b, + 0x35db3b68, 0x2b081e83, 0x77ce6b95, 0x5181e5f0, 0x78853bbc, 0x009f9494, + 0x27e5ed3c +}; + +void VP8InitRandom(VP8Random* const rg, float dithering) { + memcpy(rg->tab_, kRandomTable, sizeof(rg->tab_)); + rg->index1_ = 0; + rg->index2_ = 31; + rg->amp_ = (dithering < 0.0) ? 0 + : (dithering > 1.0) ? (1 << VP8_RANDOM_DITHER_FIX) + : (uint32_t)((1 << VP8_RANDOM_DITHER_FIX) * dithering); +} + +//------------------------------------------------------------------------------ + diff --git a/libraries/webp/src/utils/random_utils.h b/libraries/webp/src/utils/random_utils.h new file mode 100644 index 00000000000..700dc4d18ac --- /dev/null +++ b/libraries/webp/src/utils/random_utils.h @@ -0,0 +1,63 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Pseudo-random utilities +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_RANDOM_UTILS_H_ +#define WEBP_UTILS_RANDOM_UTILS_H_ + +#include +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define VP8_RANDOM_DITHER_FIX 8 // fixed-point precision for dithering +#define VP8_RANDOM_TABLE_SIZE 55 + +typedef struct { + int index1_, index2_; + uint32_t tab_[VP8_RANDOM_TABLE_SIZE]; + int amp_; +} VP8Random; + +// Initializes random generator with an amplitude 'dithering' in range [0..1]. +void VP8InitRandom(VP8Random* const rg, float dithering); + +// Returns a centered pseudo-random number with 'num_bits' amplitude. +// (uses D.Knuth's Difference-based random generator). +// 'amp' is in VP8_RANDOM_DITHER_FIX fixed-point precision. +static WEBP_INLINE int VP8RandomBits2(VP8Random* const rg, int num_bits, + int amp) { + int diff; + assert(num_bits + VP8_RANDOM_DITHER_FIX <= 31); + diff = rg->tab_[rg->index1_] - rg->tab_[rg->index2_]; + if (diff < 0) diff += (1u << 31); + rg->tab_[rg->index1_] = diff; + if (++rg->index1_ == VP8_RANDOM_TABLE_SIZE) rg->index1_ = 0; + if (++rg->index2_ == VP8_RANDOM_TABLE_SIZE) rg->index2_ = 0; + // sign-extend, 0-center + diff = (int)((uint32_t)diff << 1) >> (32 - num_bits); + diff = (diff * amp) >> VP8_RANDOM_DITHER_FIX; // restrict range + diff += 1 << (num_bits - 1); // shift back to 0.5-center + return diff; +} + +static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) { + return VP8RandomBits2(rg, num_bits, rg->amp_); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_RANDOM_UTILS_H_ diff --git a/libraries/webp/src/utils/rescaler_utils.c b/libraries/webp/src/utils/rescaler_utils.c new file mode 100644 index 00000000000..a0581a14b1a --- /dev/null +++ b/libraries/webp/src/utils/rescaler_utils.c @@ -0,0 +1,160 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include +#include +#include "src/dsp/dsp.h" +#include "src/utils/rescaler_utils.h" +#include "src/utils/utils.h" + +//------------------------------------------------------------------------------ + +int WebPRescalerInit(WebPRescaler* const rescaler, + int src_width, int src_height, + uint8_t* const dst, + int dst_width, int dst_height, int dst_stride, + int num_channels, rescaler_t* const work) { + const int x_add = src_width, x_sub = dst_width; + const int y_add = src_height, y_sub = dst_height; + const uint64_t total_size = 2ull * dst_width * num_channels * sizeof(*work); + if (!CheckSizeOverflow(total_size)) return 0; + + rescaler->x_expand = (src_width < dst_width); + rescaler->y_expand = (src_height < dst_height); + rescaler->src_width = src_width; + rescaler->src_height = src_height; + rescaler->dst_width = dst_width; + rescaler->dst_height = dst_height; + rescaler->src_y = 0; + rescaler->dst_y = 0; + rescaler->dst = dst; + rescaler->dst_stride = dst_stride; + rescaler->num_channels = num_channels; + + // for 'x_expand', we use bilinear interpolation + rescaler->x_add = rescaler->x_expand ? (x_sub - 1) : x_add; + rescaler->x_sub = rescaler->x_expand ? (x_add - 1) : x_sub; + if (!rescaler->x_expand) { // fx_scale is not used otherwise + rescaler->fx_scale = WEBP_RESCALER_FRAC(1, rescaler->x_sub); + } + // vertical scaling parameters + rescaler->y_add = rescaler->y_expand ? y_add - 1 : y_add; + rescaler->y_sub = rescaler->y_expand ? y_sub - 1 : y_sub; + rescaler->y_accum = rescaler->y_expand ? rescaler->y_sub : rescaler->y_add; + if (!rescaler->y_expand) { + // This is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast. + // Its value is <= WEBP_RESCALER_ONE, because dst_height <= rescaler->y_add + // and rescaler->x_add >= 1; + const uint64_t num = (uint64_t)dst_height * WEBP_RESCALER_ONE; + const uint64_t den = (uint64_t)rescaler->x_add * rescaler->y_add; + const uint64_t ratio = num / den; + if (ratio != (uint32_t)ratio) { + // When ratio == WEBP_RESCALER_ONE, we can't represent the ratio with the + // current fixed-point precision. This happens when src_height == + // rescaler->y_add (which == src_height), and rescaler->x_add == 1. + // => We special-case fxy_scale = 0, in WebPRescalerExportRow(). + rescaler->fxy_scale = 0; + } else { + rescaler->fxy_scale = (uint32_t)ratio; + } + rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->y_sub); + } else { + rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->x_add); + // rescaler->fxy_scale is unused here. + } + rescaler->irow = work; + rescaler->frow = work + num_channels * dst_width; + memset(work, 0, (size_t)total_size); + + WebPRescalerDspInit(); + return 1; +} + +int WebPRescalerGetScaledDimensions(int src_width, int src_height, + int* const scaled_width, + int* const scaled_height) { + assert(scaled_width != NULL); + assert(scaled_height != NULL); + { + int width = *scaled_width; + int height = *scaled_height; + const int max_size = INT_MAX / 2; + + // if width is unspecified, scale original proportionally to height ratio. + if (width == 0 && src_height > 0) { + width = + (int)(((uint64_t)src_width * height + src_height - 1) / src_height); + } + // if height is unspecified, scale original proportionally to width ratio. + if (height == 0 && src_width > 0) { + height = + (int)(((uint64_t)src_height * width + src_width - 1) / src_width); + } + // Check if the overall dimensions still make sense. + if (width <= 0 || height <= 0 || width > max_size || height > max_size) { + return 0; + } + + *scaled_width = width; + *scaled_height = height; + return 1; + } +} + +//------------------------------------------------------------------------------ +// all-in-one calls + +int WebPRescaleNeededLines(const WebPRescaler* const rescaler, + int max_num_lines) { + const int num_lines = + (rescaler->y_accum + rescaler->y_sub - 1) / rescaler->y_sub; + return (num_lines > max_num_lines) ? max_num_lines : num_lines; +} + +int WebPRescalerImport(WebPRescaler* const rescaler, int num_lines, + const uint8_t* src, int src_stride) { + int total_imported = 0; + while (total_imported < num_lines && + !WebPRescalerHasPendingOutput(rescaler)) { + if (rescaler->y_expand) { + rescaler_t* const tmp = rescaler->irow; + rescaler->irow = rescaler->frow; + rescaler->frow = tmp; + } + WebPRescalerImportRow(rescaler, src); + if (!rescaler->y_expand) { // Accumulate the contribution of the new row. + int x; + for (x = 0; x < rescaler->num_channels * rescaler->dst_width; ++x) { + rescaler->irow[x] += rescaler->frow[x]; + } + } + ++rescaler->src_y; + src += src_stride; + ++total_imported; + rescaler->y_accum -= rescaler->y_sub; + } + return total_imported; +} + +int WebPRescalerExport(WebPRescaler* const rescaler) { + int total_exported = 0; + while (WebPRescalerHasPendingOutput(rescaler)) { + WebPRescalerExportRow(rescaler); + ++total_exported; + } + return total_exported; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/utils/rescaler_utils.h b/libraries/webp/src/utils/rescaler_utils.h new file mode 100644 index 00000000000..478b48da735 --- /dev/null +++ b/libraries/webp/src/utils/rescaler_utils.h @@ -0,0 +1,102 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_RESCALER_UTILS_H_ +#define WEBP_UTILS_RESCALER_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "include/webp/types.h" + +#define WEBP_RESCALER_RFIX 32 // fixed-point precision for multiplies +#define WEBP_RESCALER_ONE (1ull << WEBP_RESCALER_RFIX) +#define WEBP_RESCALER_FRAC(x, y) \ + ((uint32_t)(((uint64_t)(x) << WEBP_RESCALER_RFIX) / (y))) + +// Structure used for on-the-fly rescaling +typedef uint32_t rescaler_t; // type for side-buffer +typedef struct WebPRescaler WebPRescaler; +struct WebPRescaler { + int x_expand; // true if we're expanding in the x direction + int y_expand; // true if we're expanding in the y direction + int num_channels; // bytes to jump between pixels + uint32_t fx_scale; // fixed-point scaling factors + uint32_t fy_scale; // '' + uint32_t fxy_scale; // '' + int y_accum; // vertical accumulator + int y_add, y_sub; // vertical increments + int x_add, x_sub; // horizontal increments + int src_width, src_height; // source dimensions + int dst_width, dst_height; // destination dimensions + int src_y, dst_y; // row counters for input and output + uint8_t* dst; + int dst_stride; + rescaler_t* irow, *frow; // work buffer +}; + +// Initialize a rescaler given scratch area 'work' and dimensions of src & dst. +// Returns false in case of error. +int WebPRescalerInit(WebPRescaler* const rescaler, + int src_width, int src_height, + uint8_t* const dst, + int dst_width, int dst_height, int dst_stride, + int num_channels, + rescaler_t* const work); + +// If either 'scaled_width' or 'scaled_height' (but not both) is 0 the value +// will be calculated preserving the aspect ratio, otherwise the values are +// left unmodified. Returns true on success, false if either value is 0 after +// performing the scaling calculation. +int WebPRescalerGetScaledDimensions(int src_width, int src_height, + int* const scaled_width, + int* const scaled_height); + +// Returns the number of input lines needed next to produce one output line, +// considering that the maximum available input lines are 'max_num_lines'. +int WebPRescaleNeededLines(const WebPRescaler* const rescaler, + int max_num_lines); + +// Import multiple rows over all channels, until at least one row is ready to +// be exported. Returns the actual number of lines that were imported. +int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows, + const uint8_t* src, int src_stride); + +// Export as many rows as possible. Return the numbers of rows written. +int WebPRescalerExport(WebPRescaler* const rescaler); + +// Return true if input is finished +static WEBP_INLINE +int WebPRescalerInputDone(const WebPRescaler* const rescaler) { + return (rescaler->src_y >= rescaler->src_height); +} +// Return true if output is finished +static WEBP_INLINE +int WebPRescalerOutputDone(const WebPRescaler* const rescaler) { + return (rescaler->dst_y >= rescaler->dst_height); +} + +// Return true if there are pending output rows ready. +static WEBP_INLINE +int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) { + return !WebPRescalerOutputDone(rescaler) && (rescaler->y_accum <= 0); +} + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_RESCALER_UTILS_H_ diff --git a/libraries/webp/src/utils/thread_utils.c b/libraries/webp/src/utils/thread_utils.c new file mode 100644 index 00000000000..4e470e17ac1 --- /dev/null +++ b/libraries/webp/src/utils/thread_utils.c @@ -0,0 +1,369 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Multi-threaded worker +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include // for memset() +#include "src/utils/thread_utils.h" +#include "src/utils/utils.h" + +#ifdef WEBP_USE_THREAD + +#if defined(_WIN32) + +#include +typedef HANDLE pthread_t; +typedef CRITICAL_SECTION pthread_mutex_t; + +#if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater +#define USE_WINDOWS_CONDITION_VARIABLE +typedef CONDITION_VARIABLE pthread_cond_t; +#else +typedef struct { + HANDLE waiting_sem_; + HANDLE received_sem_; + HANDLE signal_event_; +} pthread_cond_t; +#endif // _WIN32_WINNT >= 0x600 + +#ifndef WINAPI_FAMILY_PARTITION +#define WINAPI_PARTITION_DESKTOP 1 +#define WINAPI_FAMILY_PARTITION(x) x +#endif + +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define USE_CREATE_THREAD +#endif + +#else // !_WIN32 + +#include + +#endif // _WIN32 + +typedef struct { + pthread_mutex_t mutex_; + pthread_cond_t condition_; + pthread_t thread_; +} WebPWorkerImpl; + +#if defined(_WIN32) + +//------------------------------------------------------------------------------ +// simplistic pthread emulation layer + +#include + +// _beginthreadex requires __stdcall +#define THREADFN unsigned int __stdcall +#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val) + +#if _WIN32_WINNT >= 0x0501 // Windows XP or greater +#define WaitForSingleObject(obj, timeout) \ + WaitForSingleObjectEx(obj, timeout, FALSE /*bAlertable*/) +#endif + +static int pthread_create(pthread_t* const thread, const void* attr, + unsigned int (__stdcall* start)(void*), void* arg) { + (void)attr; +#ifdef USE_CREATE_THREAD + *thread = CreateThread(NULL, /* lpThreadAttributes */ + 0, /* dwStackSize */ + start, + arg, + 0, /* dwStackSize */ + NULL); /* lpThreadId */ +#else + *thread = (pthread_t)_beginthreadex(NULL, /* void *security */ + 0, /* unsigned stack_size */ + start, + arg, + 0, /* unsigned initflag */ + NULL); /* unsigned *thrdaddr */ +#endif + if (*thread == NULL) return 1; + SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL); + return 0; +} + +static int pthread_join(pthread_t thread, void** value_ptr) { + (void)value_ptr; + return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 || + CloseHandle(thread) == 0); +} + +// Mutex +static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) { + (void)mutexattr; +#if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater + InitializeCriticalSectionEx(mutex, 0 /*dwSpinCount*/, 0 /*Flags*/); +#else + InitializeCriticalSection(mutex); +#endif + return 0; +} + +static int pthread_mutex_lock(pthread_mutex_t* const mutex) { + EnterCriticalSection(mutex); + return 0; +} + +static int pthread_mutex_unlock(pthread_mutex_t* const mutex) { + LeaveCriticalSection(mutex); + return 0; +} + +static int pthread_mutex_destroy(pthread_mutex_t* const mutex) { + DeleteCriticalSection(mutex); + return 0; +} + +// Condition +static int pthread_cond_destroy(pthread_cond_t* const condition) { + int ok = 1; +#ifdef USE_WINDOWS_CONDITION_VARIABLE + (void)condition; +#else + ok &= (CloseHandle(condition->waiting_sem_) != 0); + ok &= (CloseHandle(condition->received_sem_) != 0); + ok &= (CloseHandle(condition->signal_event_) != 0); +#endif + return !ok; +} + +static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) { + (void)cond_attr; +#ifdef USE_WINDOWS_CONDITION_VARIABLE + InitializeConditionVariable(condition); +#else + condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL); + condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL); + condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); + if (condition->waiting_sem_ == NULL || + condition->received_sem_ == NULL || + condition->signal_event_ == NULL) { + pthread_cond_destroy(condition); + return 1; + } +#endif + return 0; +} + +static int pthread_cond_signal(pthread_cond_t* const condition) { + int ok = 1; +#ifdef USE_WINDOWS_CONDITION_VARIABLE + WakeConditionVariable(condition); +#else + if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { + // a thread is waiting in pthread_cond_wait: allow it to be notified + ok = SetEvent(condition->signal_event_); + // wait until the event is consumed so the signaler cannot consume + // the event via its own pthread_cond_wait. + ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != + WAIT_OBJECT_0); + } +#endif + return !ok; +} + +static int pthread_cond_wait(pthread_cond_t* const condition, + pthread_mutex_t* const mutex) { + int ok; +#ifdef USE_WINDOWS_CONDITION_VARIABLE + ok = SleepConditionVariableCS(condition, mutex, INFINITE); +#else + // note that there is a consumer available so the signal isn't dropped in + // pthread_cond_signal + if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) return 1; + // now unlock the mutex so pthread_cond_signal may be issued + pthread_mutex_unlock(mutex); + ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == + WAIT_OBJECT_0); + ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); + pthread_mutex_lock(mutex); +#endif + return !ok; +} + +#else // !_WIN32 +# define THREADFN void* +# define THREAD_RETURN(val) val +#endif // _WIN32 + +//------------------------------------------------------------------------------ + +static THREADFN ThreadLoop(void* ptr) { + WebPWorker* const worker = (WebPWorker*)ptr; + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + int done = 0; + while (!done) { + pthread_mutex_lock(&impl->mutex_); + while (worker->status_ == OK) { // wait in idling mode + pthread_cond_wait(&impl->condition_, &impl->mutex_); + } + if (worker->status_ == WORK) { + WebPGetWorkerInterface()->Execute(worker); + worker->status_ = OK; + } else if (worker->status_ == NOT_OK) { // finish the worker + done = 1; + } + // signal to the main thread that we're done (for Sync()) + // Note the associated mutex does not need to be held when signaling the + // condition. Unlocking the mutex first may improve performance in some + // implementations, avoiding the case where the waiting thread can't + // reacquire the mutex when woken. + pthread_mutex_unlock(&impl->mutex_); + pthread_cond_signal(&impl->condition_); + } + return THREAD_RETURN(NULL); // Thread is finished +} + +// main thread state control +static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) { + // No-op when attempting to change state on a thread that didn't come up. + // Checking status_ without acquiring the lock first would result in a data + // race. + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + if (impl == NULL) return; + + pthread_mutex_lock(&impl->mutex_); + if (worker->status_ >= OK) { + // wait for the worker to finish + while (worker->status_ != OK) { + pthread_cond_wait(&impl->condition_, &impl->mutex_); + } + // assign new status and release the working thread if needed + if (new_status != OK) { + worker->status_ = new_status; + // Note the associated mutex does not need to be held when signaling the + // condition. Unlocking the mutex first may improve performance in some + // implementations, avoiding the case where the waiting thread can't + // reacquire the mutex when woken. + pthread_mutex_unlock(&impl->mutex_); + pthread_cond_signal(&impl->condition_); + return; + } + } + pthread_mutex_unlock(&impl->mutex_); +} + +#endif // WEBP_USE_THREAD + +//------------------------------------------------------------------------------ + +static void Init(WebPWorker* const worker) { + memset(worker, 0, sizeof(*worker)); + worker->status_ = NOT_OK; +} + +static int Sync(WebPWorker* const worker) { +#ifdef WEBP_USE_THREAD + ChangeState(worker, OK); +#endif + assert(worker->status_ <= OK); + return !worker->had_error; +} + +static int Reset(WebPWorker* const worker) { + int ok = 1; + worker->had_error = 0; + if (worker->status_ < OK) { +#ifdef WEBP_USE_THREAD + WebPWorkerImpl* const impl = + (WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(WebPWorkerImpl)); + worker->impl_ = (void*)impl; + if (worker->impl_ == NULL) { + return 0; + } + if (pthread_mutex_init(&impl->mutex_, NULL)) { + goto Error; + } + if (pthread_cond_init(&impl->condition_, NULL)) { + pthread_mutex_destroy(&impl->mutex_); + goto Error; + } + pthread_mutex_lock(&impl->mutex_); + ok = !pthread_create(&impl->thread_, NULL, ThreadLoop, worker); + if (ok) worker->status_ = OK; + pthread_mutex_unlock(&impl->mutex_); + if (!ok) { + pthread_mutex_destroy(&impl->mutex_); + pthread_cond_destroy(&impl->condition_); + Error: + WebPSafeFree(impl); + worker->impl_ = NULL; + return 0; + } +#else + worker->status_ = OK; +#endif + } else if (worker->status_ > OK) { + ok = Sync(worker); + } + assert(!ok || (worker->status_ == OK)); + return ok; +} + +static void Execute(WebPWorker* const worker) { + if (worker->hook != NULL) { + worker->had_error |= !worker->hook(worker->data1, worker->data2); + } +} + +static void Launch(WebPWorker* const worker) { +#ifdef WEBP_USE_THREAD + ChangeState(worker, WORK); +#else + Execute(worker); +#endif +} + +static void End(WebPWorker* const worker) { +#ifdef WEBP_USE_THREAD + if (worker->impl_ != NULL) { + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + ChangeState(worker, NOT_OK); + pthread_join(impl->thread_, NULL); + pthread_mutex_destroy(&impl->mutex_); + pthread_cond_destroy(&impl->condition_); + WebPSafeFree(impl); + worker->impl_ = NULL; + } +#else + worker->status_ = NOT_OK; + assert(worker->impl_ == NULL); +#endif + assert(worker->status_ == NOT_OK); +} + +//------------------------------------------------------------------------------ + +static WebPWorkerInterface g_worker_interface = { + Init, Reset, Sync, Launch, Execute, End +}; + +int WebPSetWorkerInterface(const WebPWorkerInterface* const winterface) { + if (winterface == NULL || + winterface->Init == NULL || winterface->Reset == NULL || + winterface->Sync == NULL || winterface->Launch == NULL || + winterface->Execute == NULL || winterface->End == NULL) { + return 0; + } + g_worker_interface = *winterface; + return 1; +} + +const WebPWorkerInterface* WebPGetWorkerInterface(void) { + return &g_worker_interface; +} + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/utils/thread_utils.h b/libraries/webp/src/utils/thread_utils.h new file mode 100644 index 00000000000..6b8e364c66e --- /dev/null +++ b/libraries/webp/src/utils/thread_utils.h @@ -0,0 +1,90 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Multi-threaded worker +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_THREAD_UTILS_H_ +#define WEBP_UTILS_THREAD_UTILS_H_ + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// State of the worker thread object +typedef enum { + NOT_OK = 0, // object is unusable + OK, // ready to work + WORK // busy finishing the current task +} WebPWorkerStatus; + +// Function to be called by the worker thread. Takes two opaque pointers as +// arguments (data1 and data2), and should return false in case of error. +typedef int (*WebPWorkerHook)(void*, void*); + +// Synchronization object used to launch job in the worker thread +typedef struct { + void* impl_; // platform-dependent implementation worker details + WebPWorkerStatus status_; + WebPWorkerHook hook; // hook to call + void* data1; // first argument passed to 'hook' + void* data2; // second argument passed to 'hook' + int had_error; // return value of the last call to 'hook' +} WebPWorker; + +// The interface for all thread-worker related functions. All these functions +// must be implemented. +typedef struct { + // Must be called first, before any other method. + void (*Init)(WebPWorker* const worker); + // Must be called to initialize the object and spawn the thread. Re-entrant. + // Will potentially launch the thread. Returns false in case of error. + int (*Reset)(WebPWorker* const worker); + // Makes sure the previous work is finished. Returns true if worker->had_error + // was not set and no error condition was triggered by the working thread. + int (*Sync)(WebPWorker* const worker); + // Triggers the thread to call hook() with data1 and data2 arguments. These + // hook/data1/data2 values can be changed at any time before calling this + // function, but not be changed afterward until the next call to Sync(). + void (*Launch)(WebPWorker* const worker); + // This function is similar to Launch() except that it calls the + // hook directly instead of using a thread. Convenient to bypass the thread + // mechanism while still using the WebPWorker structs. Sync() must + // still be called afterward (for error reporting). + void (*Execute)(WebPWorker* const worker); + // Kill the thread and terminate the object. To use the object again, one + // must call Reset() again. + void (*End)(WebPWorker* const worker); +} WebPWorkerInterface; + +// Install a new set of threading functions, overriding the defaults. This +// should be done before any workers are started, i.e., before any encoding or +// decoding takes place. The contents of the interface struct are copied, it +// is safe to free the corresponding memory after this call. This function is +// not thread-safe. Return false in case of invalid pointer or methods. +WEBP_EXTERN int WebPSetWorkerInterface( + const WebPWorkerInterface* const winterface); + +// Retrieve the currently set thread worker interface. +WEBP_EXTERN const WebPWorkerInterface* WebPGetWorkerInterface(void); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_THREAD_UTILS_H_ diff --git a/libraries/webp/src/utils/utils.c b/libraries/webp/src/utils/utils.c new file mode 100644 index 00000000000..fd6b843dab3 --- /dev/null +++ b/libraries/webp/src/utils/utils.c @@ -0,0 +1,282 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Misc. common utility functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/utils/utils.h" + +#include +#include // for memcpy() + +#include "src/utils/palette.h" +#include "include/webp/encode.h" + +// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of +// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow, +// and not multi-thread safe!). +// An interesting alternative is valgrind's 'massif' tool: +// https://valgrind.org/docs/manual/ms-manual.html +// Here is an example command line: +/* valgrind --tool=massif --massif-out-file=massif.out \ + --stacks=yes --alloc-fn=WebPSafeMalloc --alloc-fn=WebPSafeCalloc + ms_print massif.out +*/ +// In addition: +// * if PRINT_MEM_TRAFFIC is defined, all the details of the malloc/free cycles +// are printed. +// * if MALLOC_FAIL_AT is defined, the global environment variable +// $MALLOC_FAIL_AT is used to simulate a memory error when calloc or malloc +// is called for the nth time. Example usage: +// export MALLOC_FAIL_AT=50 && ./examples/cwebp input.png +// * if MALLOC_LIMIT is defined, the global environment variable $MALLOC_LIMIT +// sets the maximum amount of memory (in bytes) made available to libwebp. +// This can be used to emulate environment with very limited memory. +// Example: export MALLOC_LIMIT=64000000 && ./examples/dwebp picture.webp + +// #define PRINT_MEM_INFO +// #define PRINT_MEM_TRAFFIC +// #define MALLOC_FAIL_AT +// #define MALLOC_LIMIT + +//------------------------------------------------------------------------------ +// Checked memory allocation + +#if defined(PRINT_MEM_INFO) + +#include + +static int num_malloc_calls = 0; +static int num_calloc_calls = 0; +static int num_free_calls = 0; +static int countdown_to_fail = 0; // 0 = off + +typedef struct MemBlock MemBlock; +struct MemBlock { + void* ptr_; + size_t size_; + MemBlock* next_; +}; + +static MemBlock* all_blocks = NULL; +static size_t total_mem = 0; +static size_t total_mem_allocated = 0; +static size_t high_water_mark = 0; +static size_t mem_limit = 0; + +static int exit_registered = 0; + +static void PrintMemInfo(void) { + fprintf(stderr, "\nMEMORY INFO:\n"); + fprintf(stderr, "num calls to: malloc = %4d\n", num_malloc_calls); + fprintf(stderr, " calloc = %4d\n", num_calloc_calls); + fprintf(stderr, " free = %4d\n", num_free_calls); + fprintf(stderr, "total_mem: %u\n", (uint32_t)total_mem); + fprintf(stderr, "total_mem allocated: %u\n", (uint32_t)total_mem_allocated); + fprintf(stderr, "high-water mark: %u\n", (uint32_t)high_water_mark); + while (all_blocks != NULL) { + MemBlock* b = all_blocks; + all_blocks = b->next_; + free(b); + } +} + +static void Increment(int* const v) { + if (!exit_registered) { +#if defined(MALLOC_FAIL_AT) + { + const char* const malloc_fail_at_str = getenv("MALLOC_FAIL_AT"); + if (malloc_fail_at_str != NULL) { + countdown_to_fail = atoi(malloc_fail_at_str); + } + } +#endif +#if defined(MALLOC_LIMIT) + { + const char* const malloc_limit_str = getenv("MALLOC_LIMIT"); +#if MALLOC_LIMIT > 1 + mem_limit = (size_t)MALLOC_LIMIT; +#endif + if (malloc_limit_str != NULL) { + mem_limit = atoi(malloc_limit_str); + } + } +#endif + (void)countdown_to_fail; + (void)mem_limit; + atexit(PrintMemInfo); + exit_registered = 1; + } + ++*v; +} + +static void AddMem(void* ptr, size_t size) { + if (ptr != NULL) { + MemBlock* const b = (MemBlock*)malloc(sizeof(*b)); + if (b == NULL) abort(); + b->next_ = all_blocks; + all_blocks = b; + b->ptr_ = ptr; + b->size_ = size; + total_mem += size; + total_mem_allocated += size; +#if defined(PRINT_MEM_TRAFFIC) +#if defined(MALLOC_FAIL_AT) + fprintf(stderr, "fail-count: %5d [mem=%u]\n", + num_malloc_calls + num_calloc_calls, (uint32_t)total_mem); +#else + fprintf(stderr, "Mem: %u (+%u)\n", (uint32_t)total_mem, (uint32_t)size); +#endif +#endif + if (total_mem > high_water_mark) high_water_mark = total_mem; + } +} + +static void SubMem(void* ptr) { + if (ptr != NULL) { + MemBlock** b = &all_blocks; + // Inefficient search, but that's just for debugging. + while (*b != NULL && (*b)->ptr_ != ptr) b = &(*b)->next_; + if (*b == NULL) { + fprintf(stderr, "Invalid pointer free! (%p)\n", ptr); + abort(); + } + { + MemBlock* const block = *b; + *b = block->next_; + total_mem -= block->size_; +#if defined(PRINT_MEM_TRAFFIC) + fprintf(stderr, "Mem: %u (-%u)\n", + (uint32_t)total_mem, (uint32_t)block->size_); +#endif + free(block); + } + } +} + +#else +#define Increment(v) do {} while (0) +#define AddMem(p, s) do {} while (0) +#define SubMem(p) do {} while (0) +#endif + +// Returns 0 in case of overflow of nmemb * size. +static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) { + const uint64_t total_size = nmemb * size; + if (nmemb == 0) return 1; + if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0; + if (!CheckSizeOverflow(total_size)) return 0; +#if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT) + if (countdown_to_fail > 0 && --countdown_to_fail == 0) { + return 0; // fake fail! + } +#endif +#if defined(PRINT_MEM_INFO) && defined(MALLOC_LIMIT) + if (mem_limit > 0) { + const uint64_t new_total_mem = (uint64_t)total_mem + total_size; + if (!CheckSizeOverflow(new_total_mem) || + new_total_mem > mem_limit) { + return 0; // fake fail! + } + } +#endif + + return 1; +} + +void* WebPSafeMalloc(uint64_t nmemb, size_t size) { + void* ptr; + Increment(&num_malloc_calls); + if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL; + assert(nmemb * size > 0); + ptr = malloc((size_t)(nmemb * size)); + AddMem(ptr, (size_t)(nmemb * size)); + return ptr; +} + +void* WebPSafeCalloc(uint64_t nmemb, size_t size) { + void* ptr; + Increment(&num_calloc_calls); + if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL; + assert(nmemb * size > 0); + ptr = calloc((size_t)nmemb, size); + AddMem(ptr, (size_t)(nmemb * size)); + return ptr; +} + +void WebPSafeFree(void* const ptr) { + if (ptr != NULL) { + Increment(&num_free_calls); + SubMem(ptr); + } + free(ptr); +} + +// Public API functions. + +void* WebPMalloc(size_t size) { + return WebPSafeMalloc(1, size); +} + +void WebPFree(void* ptr) { + WebPSafeFree(ptr); +} + +//------------------------------------------------------------------------------ + +void WebPCopyPlane(const uint8_t* src, int src_stride, + uint8_t* dst, int dst_stride, int width, int height) { + assert(src != NULL && dst != NULL); + assert(abs(src_stride) >= width && abs(dst_stride) >= width); + while (height-- > 0) { + memcpy(dst, src, width); + src += src_stride; + dst += dst_stride; + } +} + +void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) { + assert(src != NULL && dst != NULL); + assert(src->width == dst->width && src->height == dst->height); + assert(src->use_argb && dst->use_argb); + WebPCopyPlane((uint8_t*)src->argb, 4 * src->argb_stride, (uint8_t*)dst->argb, + 4 * dst->argb_stride, 4 * src->width, src->height); +} + +//------------------------------------------------------------------------------ + +int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) { + return GetColorPalette(pic, palette); +} + +//------------------------------------------------------------------------------ + +#if defined(WEBP_NEED_LOG_TABLE_8BIT) +const uint8_t WebPLogTable8bit[256] = { // 31 ^ clz(i) + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; +#endif + +//------------------------------------------------------------------------------ diff --git a/libraries/webp/src/utils/utils.h b/libraries/webp/src/utils/utils.h new file mode 100644 index 00000000000..7609f3d433a --- /dev/null +++ b/libraries/webp/src/utils/utils.h @@ -0,0 +1,209 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Misc. common utility functions +// +// Authors: Skal (pascal.massimino@gmail.com) +// Urvang (urvang@google.com) + +#ifndef WEBP_UTILS_UTILS_H_ +#define WEBP_UTILS_UTILS_H_ + +#ifdef HAVE_CONFIG_H +#include "include/webp/config.h" +#endif + +#include + +#include "include/webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Memory allocation + +// This is the maximum memory amount that libwebp will ever try to allocate. +#ifndef WEBP_MAX_ALLOCABLE_MEMORY +#if SIZE_MAX > (1ULL << 34) +#define WEBP_MAX_ALLOCABLE_MEMORY (1ULL << 34) +#else +// For 32-bit targets keep this below INT_MAX to avoid valgrind warnings. +#define WEBP_MAX_ALLOCABLE_MEMORY ((1ULL << 31) - (1 << 16)) +#endif +#endif // WEBP_MAX_ALLOCABLE_MEMORY + +static WEBP_INLINE int CheckSizeOverflow(uint64_t size) { + return size == (size_t)size; +} + +// size-checking safe malloc/calloc: verify that the requested size is not too +// large, or return NULL. You don't need to call these for constructs like +// malloc(sizeof(foo)), but only if there's picture-dependent size involved +// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this +// safe malloc() borrows the signature from calloc(), pointing at the dangerous +// underlying multiply involved. +WEBP_EXTERN void* WebPSafeMalloc(uint64_t nmemb, size_t size); +// Note that WebPSafeCalloc() expects the second argument type to be 'size_t' +// in order to favor the "calloc(num_foo, sizeof(foo))" pattern. +WEBP_EXTERN void* WebPSafeCalloc(uint64_t nmemb, size_t size); + +// Companion deallocation function to the above allocations. +WEBP_EXTERN void WebPSafeFree(void* const ptr); + +//------------------------------------------------------------------------------ +// Alignment + +#define WEBP_ALIGN_CST 31 +#define WEBP_ALIGN(PTR) (((uintptr_t)(PTR) + WEBP_ALIGN_CST) & \ + ~(uintptr_t)WEBP_ALIGN_CST) + +#include +// memcpy() is the safe way of moving potentially unaligned 32b memory. +static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) { + uint32_t A; + memcpy(&A, ptr, sizeof(A)); + return A; +} + +static WEBP_INLINE int32_t WebPMemToInt32(const uint8_t* const ptr) { + return (int32_t)WebPMemToUint32(ptr); +} + +static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) { + memcpy(ptr, &val, sizeof(val)); +} + +static WEBP_INLINE void WebPInt32ToMem(uint8_t* const ptr, int val) { + WebPUint32ToMem(ptr, (uint32_t)val); +} + +//------------------------------------------------------------------------------ +// Reading/writing data. + +// Read 16, 24 or 32 bits stored in little-endian order. +static WEBP_INLINE int GetLE16(const uint8_t* const data) { + return (int)(data[0] << 0) | (data[1] << 8); +} + +static WEBP_INLINE int GetLE24(const uint8_t* const data) { + return GetLE16(data) | (data[2] << 16); +} + +static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) { + return GetLE16(data) | ((uint32_t)GetLE16(data + 2) << 16); +} + +// Store 16, 24 or 32 bits in little-endian order. +static WEBP_INLINE void PutLE16(uint8_t* const data, int val) { + assert(val < (1 << 16)); + data[0] = (val >> 0) & 0xff; + data[1] = (val >> 8) & 0xff; +} + +static WEBP_INLINE void PutLE24(uint8_t* const data, int val) { + assert(val < (1 << 24)); + PutLE16(data, val & 0xffff); + data[2] = (val >> 16) & 0xff; +} + +static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) { + PutLE16(data, (int)(val & 0xffff)); + PutLE16(data + 2, (int)(val >> 16)); +} + +// use GNU builtins where available. +#if defined(__GNUC__) && \ + ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4) +// Returns (int)floor(log2(n)). n must be > 0. +static WEBP_INLINE int BitsLog2Floor(uint32_t n) { + return 31 ^ __builtin_clz(n); +} +// counts the number of trailing zero +static WEBP_INLINE int BitsCtz(uint32_t n) { return __builtin_ctz(n); } +#elif defined(_MSC_VER) && _MSC_VER > 1310 && \ + (defined(_M_X64) || defined(_M_IX86)) +#include +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) + +static WEBP_INLINE int BitsLog2Floor(uint32_t n) { + unsigned long first_set_bit; // NOLINT (runtime/int) + _BitScanReverse(&first_set_bit, n); + return first_set_bit; +} +static WEBP_INLINE int BitsCtz(uint32_t n) { + unsigned long first_set_bit; // NOLINT (runtime/int) + _BitScanForward(&first_set_bit, n); + return first_set_bit; +} +#else // default: use the (slow) C-version. +#define WEBP_HAVE_SLOW_CLZ_CTZ // signal that the Clz/Ctz function are slow +// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either +// based on table or not. Can be used as fallback if clz() is not available. +#define WEBP_NEED_LOG_TABLE_8BIT +extern const uint8_t WebPLogTable8bit[256]; +static WEBP_INLINE int WebPLog2FloorC(uint32_t n) { + int log_value = 0; + while (n >= 256) { + log_value += 8; + n >>= 8; + } + return log_value + WebPLogTable8bit[n]; +} + +static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); } + +static WEBP_INLINE int BitsCtz(uint32_t n) { + int i; + for (i = 0; i < 32; ++i, n >>= 1) { + if (n & 1) return i; + } + return 32; +} + +#endif + +//------------------------------------------------------------------------------ +// Pixel copying. + +struct WebPPicture; + +// Copy width x height pixels from 'src' to 'dst' honoring the strides. +WEBP_EXTERN void WebPCopyPlane(const uint8_t* src, int src_stride, + uint8_t* dst, int dst_stride, + int width, int height); + +// Copy ARGB pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are +// assumed to be already allocated and using ARGB data. +WEBP_EXTERN void WebPCopyPixels(const struct WebPPicture* const src, + struct WebPPicture* const dst); + +//------------------------------------------------------------------------------ +// Unique colors. + +// Returns count of unique colors in 'pic', assuming pic->use_argb is true. +// If the unique color count is more than MAX_PALETTE_SIZE, returns +// MAX_PALETTE_SIZE+1. +// If 'palette' is not NULL and number of unique colors is less than or equal to +// MAX_PALETTE_SIZE, also outputs the actual unique colors into 'palette'. +// Note: 'palette' is assumed to be an array already allocated with at least +// MAX_PALETTE_SIZE elements. +// TODO(vrabaud) remove whenever we can break the ABI. +WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic, + uint32_t* const palette); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_UTILS_UTILS_H_ diff --git a/libraries/zlib/CMakeLists.txt b/libraries/zlib/CMakeLists.txt deleted file mode 100644 index a1d6637a989..00000000000 --- a/libraries/zlib/CMakeLists.txt +++ /dev/null @@ -1,197 +0,0 @@ -cmake_minimum_required(VERSION 2.8.7) -set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) - -make_release_only() - -project(zlib C) - -set(VERSION "1.2.7") - -if(NOT DEFINED BUILD_SHARED_LIBS) - option(BUILD_SHARED_LIBS "Build a shared library form of zlib" OFF) -endif() - -set(ZLIBNAME z) - -include(CheckTypeSize) -include(CheckFunctionExists) -include(CheckIncludeFile) -include(CheckCSourceCompiles) -enable_testing() - -check_include_file(sys/types.h HAVE_SYS_TYPES_H) -check_include_file(stdint.h HAVE_STDINT_H) -check_include_file(stddef.h HAVE_STDDEF_H) - -# -# Check to see if we have large file support -# -set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) -# We add these other definitions here because CheckTypeSize.cmake -# in CMake 2.4.x does not automatically do so and we want -# compatibility with CMake 2.4.x. -if(HAVE_SYS_TYPES_H) - list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) -endif() -if(HAVE_STDINT_H) - list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) -endif() -if(HAVE_STDDEF_H) - list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) -endif() -check_type_size(off64_t OFF64_T) -if(HAVE_OFF64_T) - add_definitions(-D_LARGEFILE64_SOURCE=1) -endif() -set(CMAKE_REQUIRED_DEFINITIONS) # clear variable - -# -# Check for fseeko -# -check_function_exists(fseeko HAVE_FSEEKO) -if(NOT HAVE_FSEEKO) - add_definitions(-DNO_FSEEKO) -endif() - -# -# Check for unistd.h -# -check_include_file(unistd.h Z_HAVE_UNISTD_H) - -if(MSVC) - set(CMAKE_DEBUG_POSTFIX "d") - add_definitions(-D_CRT_SECURE_NO_DEPRECATE) - add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -endif() - -#if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) -# # If we're doing an out of source build and the user has a zconf.h -# # in their source tree... -# if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h) -# message(FATAL_ERROR -# "You must remove ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h " -# "from the source tree. This file is included with zlib " -# "but CMake generates this file for you automatically " -# "in the build directory.") -# endif() -#endif() -# -#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein -# ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) -#include_directories(${CMAKE_CURRENT_BINARY_DIR}) - - -#============================================================================ -# zlib -#============================================================================ - -set(ZLIB_PUBLIC_HDRS - zconf.h - zlib.h -) -set(ZLIB_PRIVATE_HDRS - crc32.h - deflate.h - gzguts.h - inffast.h - inffixed.h - inflate.h - inftrees.h - trees.h - zutil.h -) -set(ZLIB_SRCS - adler32.c - compress.c - crc32.c - deflate.c -# gzclose.c -# gzlib.c -# gzread.c -# gzwrite.c - inflate.c - infback.c - inftrees.c - inffast.c - trees.c - uncompr.c - zutil.c -# win32/zlib1.rc -) - -# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION -file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) -string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([0-9A-Za-z.]+)\".*" - "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) - -if(MINGW) - # This gets us DLL resource information when compiling on MinGW. - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj - COMMAND windres.exe - -D GCC_WINDRES - -I ${CMAKE_CURRENT_SOURCE_DIR} - -I ${CMAKE_CURRENT_BINARY_DIR} - -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj - -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) - set(ZLIB_SRCS ${ZLIB_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) -endif() - -add_library(${ZLIBNAME} STATIC ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) -set_target_properties(${ZLIBNAME} PROPERTIES DEFINE_SYMBOL ZLIB_DLL) - -set_target_properties(${ZLIBNAME} PROPERTIES SOVERSION 1) - -if(NOT CYGWIN) - # This property causes shared libraries on Linux to have the full version - # encoded into their final filename. We disable this on Cygwin because - # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll - # seems to be the default. - # - # This has no effect with MSVC, on that platform the version info for - # the DLL comes from the resource file win32/zlib1.rc - set_target_properties(${ZLIBNAME} PROPERTIES VERSION ${ZLIB_FULL_VERSION}) -endif() - -if(BUILD_SHARED_LIBS AND WIN32) - # Creates zlib1.dll when building shared library version - set_target_properties(${ZLIBNAME} PROPERTIES SUFFIX "1.dll") -else() - # On unix-like platforms the library is almost always called libz - set_target_properties(${ZLIBNAME} PROPERTIES OUTPUT_NAME z) -endif() - -if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) - install(TARGETS ${ZLIBNAME} - RUNTIME DESTINATION bin - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib ) -endif() -if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) - install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION include) -endif() -if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) - install(FILES zlib.3 DESTINATION share/man/man3) -endif() - -#============================================================================ -# Example binaries -#============================================================================ - -#add_executable(example example.c) -#target_link_libraries(example ${ZLIBNAME}) -#add_test(example example) - -#add_executable(minigzip minigzip.c) -#target_link_libraries(minigzip ${ZLIBNAME}) - -#if(HAVE_OFF64_T) -# add_executable(example64 example.c) -# target_link_libraries(example64 ${ZLIBNAME}) -# set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") -# add_test(example64 example64) -# -# add_executable(minigzip64 minigzip.c) -# target_link_libraries(minigzip64 ${ZLIBNAME}) -# set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") -#endif() diff --git a/libraries/zlib/ChangeLog b/libraries/zlib/ChangeLog deleted file mode 100644 index 30199a65a03..00000000000 --- a/libraries/zlib/ChangeLog +++ /dev/null @@ -1,1515 +0,0 @@ - - ChangeLog file for zlib - -Changes in 1.2.11 (15 Jan 2017) -- Fix deflate stored bug when pulling last block from window -- Permit immediate deflateParams changes before any deflate input - -Changes in 1.2.10 (2 Jan 2017) -- Avoid warnings on snprintf() return value -- Fix bug in deflate_stored() for zero-length input -- Fix bug in gzwrite.c that produced corrupt gzip files -- Remove files to be installed before copying them in Makefile.in -- Add warnings when compiling with assembler code - -Changes in 1.2.9 (31 Dec 2016) -- Fix contrib/minizip to permit unzipping with desktop API [Zouzou] -- Improve contrib/blast to return unused bytes -- Assure that gzoffset() is correct when appending -- Improve compress() and uncompress() to support large lengths -- Fix bug in test/example.c where error code not saved -- Remedy Coverity warning [Randers-Pehrson] -- Improve speed of gzprintf() in transparent mode -- Fix inflateInit2() bug when windowBits is 16 or 32 -- Change DEBUG macro to ZLIB_DEBUG -- Avoid uninitialized access by gzclose_w() -- Allow building zlib outside of the source directory -- Fix bug that accepted invalid zlib header when windowBits is zero -- Fix gzseek() problem on MinGW due to buggy _lseeki64 there -- Loop on write() calls in gzwrite.c in case of non-blocking I/O -- Add --warn (-w) option to ./configure for more compiler warnings -- Reject a window size of 256 bytes if not using the zlib wrapper -- Fix bug when level 0 used with Z_HUFFMAN or Z_RLE -- Add --debug (-d) option to ./configure to define ZLIB_DEBUG -- Fix bugs in creating a very large gzip header -- Add uncompress2() function, which returns the input size used -- Assure that deflateParams() will not switch functions mid-block -- Dramatically speed up deflation for level 0 (storing) -- Add gzfread(), duplicating the interface of fread() -- Add gzfwrite(), duplicating the interface of fwrite() -- Add deflateGetDictionary() function -- Use snprintf() for later versions of Microsoft C -- Fix *Init macros to use z_ prefix when requested -- Replace as400 with os400 for OS/400 support [Monnerat] -- Add crc32_z() and adler32_z() functions with size_t lengths -- Update Visual Studio project files [AraHaan] - -Changes in 1.2.8 (28 Apr 2013) -- Update contrib/minizip/iowin32.c for Windows RT [Vollant] -- Do not force Z_CONST for C++ -- Clean up contrib/vstudio [Roß] -- Correct spelling error in zlib.h -- Fix mixed line endings in contrib/vstudio - -Changes in 1.2.7.3 (13 Apr 2013) -- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc - -Changes in 1.2.7.2 (13 Apr 2013) -- Change check for a four-byte type back to hexadecimal -- Fix typo in win32/Makefile.msc -- Add casts in gzwrite.c for pointer differences - -Changes in 1.2.7.1 (24 Mar 2013) -- Replace use of unsafe string functions with snprintf if available -- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink] -- Fix gzgetc undefine when Z_PREFIX set [Turk] -- Eliminate use of mktemp in Makefile (not always available) -- Fix bug in 'F' mode for gzopen() -- Add inflateGetDictionary() function -- Correct comment in deflate.h -- Use _snprintf for snprintf in Microsoft C -- On Darwin, only use /usr/bin/libtool if libtool is not Apple -- Delete "--version" file if created by "ar --version" [Richard G.] -- Fix configure check for veracity of compiler error return codes -- Fix CMake compilation of static lib for MSVC2010 x64 -- Remove unused variable in infback9.c -- Fix argument checks in gzlog_compress() and gzlog_write() -- Clean up the usage of z_const and respect const usage within zlib -- Clean up examples/gzlog.[ch] comparisons of different types -- Avoid shift equal to bits in type (caused endless loop) -- Fix uninitialized value bug in gzputc() introduced by const patches -- Fix memory allocation error in examples/zran.c [Nor] -- Fix bug where gzopen(), gzclose() would write an empty file -- Fix bug in gzclose() when gzwrite() runs out of memory -- Check for input buffer malloc failure in examples/gzappend.c -- Add note to contrib/blast to use binary mode in stdio -- Fix comparisons of differently signed integers in contrib/blast -- Check for invalid code length codes in contrib/puff -- Fix serious but very rare decompression bug in inftrees.c -- Update inflateBack() comments, since inflate() can be faster -- Use underscored I/O function names for WINAPI_FAMILY -- Add _tr_flush_bits to the external symbols prefixed by --zprefix -- Add contrib/vstudio/vc10 pre-build step for static only -- Quote --version-script argument in CMakeLists.txt -- Don't specify --version-script on Apple platforms in CMakeLists.txt -- Fix casting error in contrib/testzlib/testzlib.c -- Fix types in contrib/minizip to match result of get_crc_table() -- Simplify contrib/vstudio/vc10 with 'd' suffix -- Add TOP support to win32/Makefile.msc -- Suport i686 and amd64 assembler builds in CMakeLists.txt -- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h -- Add vc11 and vc12 build files to contrib/vstudio -- Add gzvprintf() as an undocumented function in zlib -- Fix configure for Sun shell -- Remove runtime check in configure for four-byte integer type -- Add casts and consts to ease user conversion to C++ -- Add man pages for minizip and miniunzip -- In Makefile uninstall, don't rm if preceding cd fails -- Do not return Z_BUF_ERROR if deflateParam() has nothing to write - -Changes in 1.2.7 (2 May 2012) -- Replace use of memmove() with a simple copy for portability -- Test for existence of strerror -- Restore gzgetc_ for backward compatibility with 1.2.6 -- Fix build with non-GNU make on Solaris -- Require gcc 4.0 or later on Mac OS X to use the hidden attribute -- Include unistd.h for Watcom C -- Use __WATCOMC__ instead of __WATCOM__ -- Do not use the visibility attribute if NO_VIZ defined -- Improve the detection of no hidden visibility attribute -- Avoid using __int64 for gcc or solo compilation -- Cast to char * in gzprintf to avoid warnings [Zinser] -- Fix make_vms.com for VAX [Zinser] -- Don't use library or built-in byte swaps -- Simplify test and use of gcc hidden attribute -- Fix bug in gzclose_w() when gzwrite() fails to allocate memory -- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen() -- Fix bug in test/minigzip.c for configure --solo -- Fix contrib/vstudio project link errors [Mohanathas] -- Add ability to choose the builder in make_vms.com [Schweda] -- Add DESTDIR support to mingw32 win32/Makefile.gcc -- Fix comments in win32/Makefile.gcc for proper usage -- Allow overriding the default install locations for cmake -- Generate and install the pkg-config file with cmake -- Build both a static and a shared version of zlib with cmake -- Include version symbols for cmake builds -- If using cmake with MSVC, add the source directory to the includes -- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta] -- Move obsolete emx makefile to old [Truta] -- Allow the use of -Wundef when compiling or using zlib -- Avoid the use of the -u option with mktemp -- Improve inflate() documentation on the use of Z_FINISH -- Recognize clang as gcc -- Add gzopen_w() in Windows for wide character path names -- Rename zconf.h in CMakeLists.txt to move it out of the way -- Add source directory in CMakeLists.txt for building examples -- Look in build directory for zlib.pc in CMakeLists.txt -- Remove gzflags from zlibvc.def in vc9 and vc10 -- Fix contrib/minizip compilation in the MinGW environment -- Update ./configure for Solaris, support --64 [Mooney] -- Remove -R. from Solaris shared build (possible security issue) -- Avoid race condition for parallel make (-j) running example -- Fix type mismatch between get_crc_table() and crc_table -- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler] -- Fix the path to zlib.map in CMakeLists.txt -- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe] -- Add instructions to win32/Makefile.gcc for shared install [Torri] - -Changes in 1.2.6.1 (12 Feb 2012) -- Avoid the use of the Objective-C reserved name "id" -- Include io.h in gzguts.h for Microsoft compilers -- Fix problem with ./configure --prefix and gzgetc macro -- Include gz_header definition when compiling zlib solo -- Put gzflags() functionality back in zutil.c -- Avoid library header include in crc32.c for Z_SOLO -- Use name in GCC_CLASSIC as C compiler for coverage testing, if set -- Minor cleanup in contrib/minizip/zip.c [Vollant] -- Update make_vms.com [Zinser] -- Remove unnecessary gzgetc_ function -- Use optimized byte swap operations for Microsoft and GNU [Snyder] -- Fix minor typo in zlib.h comments [Rzesniowiecki] - -Changes in 1.2.6 (29 Jan 2012) -- Update the Pascal interface in contrib/pascal -- Fix function numbers for gzgetc_ in zlibvc.def files -- Fix configure.ac for contrib/minizip [Schiffer] -- Fix large-entry detection in minizip on 64-bit systems [Schiffer] -- Have ./configure use the compiler return code for error indication -- Fix CMakeLists.txt for cross compilation [McClure] -- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes] -- Fix compilation of contrib/minizip on FreeBSD [Marquez] -- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath] -- Include io.h for Turbo C / Borland C on all platforms [Truta] -- Make version explicit in contrib/minizip/configure.ac [Bosmans] -- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant] -- Minor cleanup up contrib/minizip/unzip.c [Vollant] -- Fix bug when compiling minizip with C++ [Vollant] -- Protect for long name and extra fields in contrib/minizip [Vollant] -- Avoid some warnings in contrib/minizip [Vollant] -- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip -- Add missing libs to minizip linker command -- Add support for VPATH builds in contrib/minizip -- Add an --enable-demos option to contrib/minizip/configure -- Add the generation of configure.log by ./configure -- Exit when required parameters not provided to win32/Makefile.gcc -- Have gzputc return the character written instead of the argument -- Use the -m option on ldconfig for BSD systems [Tobias] -- Correct in zlib.map when deflateResetKeep was added - -Changes in 1.2.5.3 (15 Jan 2012) -- Restore gzgetc function for binary compatibility -- Do not use _lseeki64 under Borland C++ [Truta] -- Update win32/Makefile.msc to build test/*.c [Truta] -- Remove old/visualc6 given CMakefile and other alternatives -- Update AS400 build files and documentation [Monnerat] -- Update win32/Makefile.gcc to build test/*.c [Truta] -- Permit stronger flushes after Z_BLOCK flushes -- Avoid extraneous empty blocks when doing empty flushes -- Permit Z_NULL arguments to deflatePending -- Allow deflatePrime() to insert bits in the middle of a stream -- Remove second empty static block for Z_PARTIAL_FLUSH -- Write out all of the available bits when using Z_BLOCK -- Insert the first two strings in the hash table after a flush - -Changes in 1.2.5.2 (17 Dec 2011) -- fix ld error: unable to find version dependency 'ZLIB_1.2.5' -- use relative symlinks for shared libs -- Avoid searching past window for Z_RLE strategy -- Assure that high-water mark initialization is always applied in deflate -- Add assertions to fill_window() in deflate.c to match comments -- Update python link in README -- Correct spelling error in gzread.c -- Fix bug in gzgets() for a concatenated empty gzip stream -- Correct error in comment for gz_make() -- Change gzread() and related to ignore junk after gzip streams -- Allow gzread() and related to continue after gzclearerr() -- Allow gzrewind() and gzseek() after a premature end-of-file -- Simplify gzseek() now that raw after gzip is ignored -- Change gzgetc() to a macro for speed (~40% speedup in testing) -- Fix gzclose() to return the actual error last encountered -- Always add large file support for windows -- Include zconf.h for windows large file support -- Include zconf.h.cmakein for windows large file support -- Update zconf.h.cmakein on make distclean -- Merge vestigial vsnprintf determination from zutil.h to gzguts.h -- Clarify how gzopen() appends in zlib.h comments -- Correct documentation of gzdirect() since junk at end now ignored -- Add a transparent write mode to gzopen() when 'T' is in the mode -- Update python link in zlib man page -- Get inffixed.h and MAKEFIXED result to match -- Add a ./config --solo option to make zlib subset with no library use -- Add undocumented inflateResetKeep() function for CAB file decoding -- Add --cover option to ./configure for gcc coverage testing -- Add #define ZLIB_CONST option to use const in the z_stream interface -- Add comment to gzdopen() in zlib.h to use dup() when using fileno() -- Note behavior of uncompress() to provide as much data as it can -- Add files in contrib/minizip to aid in building libminizip -- Split off AR options in Makefile.in and configure -- Change ON macro to Z_ARG to avoid application conflicts -- Facilitate compilation with Borland C++ for pragmas and vsnprintf -- Include io.h for Turbo C / Borland C++ -- Move example.c and minigzip.c to test/ -- Simplify incomplete code table filling in inflate_table() -- Remove code from inflate.c and infback.c that is impossible to execute -- Test the inflate code with full coverage -- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw) -- Add deflateResetKeep and fix inflateResetKeep to retain dictionary -- Fix gzwrite.c to accommodate reduced memory zlib compilation -- Have inflate() with Z_FINISH avoid the allocation of a window -- Do not set strm->adler when doing raw inflate -- Fix gzeof() to behave just like feof() when read is not past end of file -- Fix bug in gzread.c when end-of-file is reached -- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF -- Document gzread() capability to read concurrently written files -- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo] - -Changes in 1.2.5.1 (10 Sep 2011) -- Update FAQ entry on shared builds (#13) -- Avoid symbolic argument to chmod in Makefile.in -- Fix bug and add consts in contrib/puff [Oberhumer] -- Update contrib/puff/zeros.raw test file to have all block types -- Add full coverage test for puff in contrib/puff/Makefile -- Fix static-only-build install in Makefile.in -- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno] -- Add libz.a dependency to shared in Makefile.in for parallel builds -- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out -- Replace $(...) with `...` in configure for non-bash sh [Bowler] -- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen] -- Add solaris* to Linux* in configure to allow gcc use [Groffen] -- Add *bsd* to Linux* case in configure [Bar-Lev] -- Add inffast.obj to dependencies in win32/Makefile.msc -- Correct spelling error in deflate.h [Kohler] -- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc -- Add test to configure for GNU C looking for gcc in output of $cc -v -- Add zlib.pc generation to win32/Makefile.gcc [Weigelt] -- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not -- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense -- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser) -- Make stronger test in zconf.h to include unistd.h for LFS -- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack] -- Fix zlib.h LFS support when Z_PREFIX used -- Add updated as400 support (removed from old) [Monnerat] -- Avoid deflate sensitivity to volatile input data -- Avoid division in adler32_combine for NO_DIVIDE -- Clarify the use of Z_FINISH with deflateBound() amount of space -- Set binary for output file in puff.c -- Use u4 type for crc_table to avoid conversion warnings -- Apply casts in zlib.h to avoid conversion warnings -- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] -- Improve inflateSync() documentation to note indeterminancy -- Add deflatePending() function to return the amount of pending output -- Correct the spelling of "specification" in FAQ [Randers-Pehrson] -- Add a check in configure for stdarg.h, use for gzprintf() -- Check that pointers fit in ints when gzprint() compiled old style -- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] -- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] -- Add debug records in assmebler code [Londer] -- Update RFC references to use http://tools.ietf.org/html/... [Li] -- Add --archs option, use of libtool to configure for Mac OS X [Borstel] - -Changes in 1.2.5 (19 Apr 2010) -- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] -- Default to libdir as sharedlibdir in configure [Nieder] -- Update copyright dates on modified source files -- Update trees.c to be able to generate modified trees.h -- Exit configure for MinGW, suggesting win32/Makefile.gcc -- Check for NULL path in gz_open [Homurlu] - -Changes in 1.2.4.5 (18 Apr 2010) -- Set sharedlibdir in configure [Torok] -- Set LDFLAGS in Makefile.in [Bar-Lev] -- Avoid mkdir objs race condition in Makefile.in [Bowler] -- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays -- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C -- Don't use hidden attribute when it is a warning generator (e.g. Solaris) - -Changes in 1.2.4.4 (18 Apr 2010) -- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok] -- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty -- Try to use bash or ksh regardless of functionality of /bin/sh -- Fix configure incompatibility with NetBSD sh -- Remove attempt to run under bash or ksh since have better NetBSD fix -- Fix win32/Makefile.gcc for MinGW [Bar-Lev] -- Add diagnostic messages when using CROSS_PREFIX in configure -- Added --sharedlibdir option to configure [Weigelt] -- Use hidden visibility attribute when available [Frysinger] - -Changes in 1.2.4.3 (10 Apr 2010) -- Only use CROSS_PREFIX in configure for ar and ranlib if they exist -- Use CROSS_PREFIX for nm [Bar-Lev] -- Assume _LARGEFILE64_SOURCE defined is equivalent to true -- Avoid use of undefined symbols in #if with && and || -- Make *64 prototypes in gzguts.h consistent with functions -- Add -shared load option for MinGW in configure [Bowler] -- Move z_off64_t to public interface, use instead of off64_t -- Remove ! from shell test in configure (not portable to Solaris) -- Change +0 macro tests to -0 for possibly increased portability - -Changes in 1.2.4.2 (9 Apr 2010) -- Add consistent carriage returns to readme.txt's in masmx86 and masmx64 -- Really provide prototypes for *64 functions when building without LFS -- Only define unlink() in minigzip.c if unistd.h not included -- Update README to point to contrib/vstudio project files -- Move projects/vc6 to old/ and remove projects/ -- Include stdlib.h in minigzip.c for setmode() definition under WinCE -- Clean up assembler builds in win32/Makefile.msc [Rowe] -- Include sys/types.h for Microsoft for off_t definition -- Fix memory leak on error in gz_open() -- Symbolize nm as $NM in configure [Weigelt] -- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt] -- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined -- Fix bug in gzeof() to take into account unused input data -- Avoid initialization of structures with variables in puff.c -- Updated win32/README-WIN32.txt [Rowe] - -Changes in 1.2.4.1 (28 Mar 2010) -- Remove the use of [a-z] constructs for sed in configure [gentoo 310225] -- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech] -- Restore "for debugging" comment on sprintf() in gzlib.c -- Remove fdopen for MVS from gzguts.h -- Put new README-WIN32.txt in win32 [Rowe] -- Add check for shell to configure and invoke another shell if needed -- Fix big fat stinking bug in gzseek() on uncompressed files -- Remove vestigial F_OPEN64 define in zutil.h -- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE -- Avoid errors on non-LFS systems when applications define LFS macros -- Set EXE to ".exe" in configure for MINGW [Kahle] -- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill] -- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev] -- Add DLL install in win32/makefile.gcc [Bar-Lev] -- Allow Linux* or linux* from uname in configure [Bar-Lev] -- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev] -- Add cross-compilation prefixes to configure [Bar-Lev] -- Match type exactly in gz_load() invocation in gzread.c -- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func -- Provide prototypes for *64 functions when building zlib without LFS -- Don't use -lc when linking shared library on MinGW -- Remove errno.h check in configure and vestigial errno code in zutil.h - -Changes in 1.2.4 (14 Mar 2010) -- Fix VER3 extraction in configure for no fourth subversion -- Update zlib.3, add docs to Makefile.in to make .pdf out of it -- Add zlib.3.pdf to distribution -- Don't set error code in gzerror() if passed pointer is NULL -- Apply destination directory fixes to CMakeLists.txt [Lowman] -- Move #cmakedefine's to a new zconf.in.cmakein -- Restore zconf.h for builds that don't use configure or cmake -- Add distclean to dummy Makefile for convenience -- Update and improve INDEX, README, and FAQ -- Update CMakeLists.txt for the return of zconf.h [Lowman] -- Update contrib/vstudio/vc9 and vc10 [Vollant] -- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc -- Apply license and readme changes to contrib/asm686 [Raiter] -- Check file name lengths and add -c option in minigzip.c [Li] -- Update contrib/amd64 and contrib/masmx86/ [Vollant] -- Avoid use of "eof" parameter in trees.c to not shadow library variable -- Update make_vms.com for removal of zlibdefs.h [Zinser] -- Update assembler code and vstudio projects in contrib [Vollant] -- Remove outdated assembler code contrib/masm686 and contrib/asm586 -- Remove old vc7 and vc8 from contrib/vstudio -- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe] -- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open() -- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant] -- Remove *64 functions from win32/zlib.def (they're not 64-bit yet) -- Fix bug in void-returning vsprintf() case in gzwrite.c -- Fix name change from inflate.h in contrib/inflate86/inffas86.c -- Check if temporary file exists before removing in make_vms.com [Zinser] -- Fix make install and uninstall for --static option -- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta] -- Update readme.txt in contrib/masmx64 and masmx86 to assemble - -Changes in 1.2.3.9 (21 Feb 2010) -- Expunge gzio.c -- Move as400 build information to old -- Fix updates in contrib/minizip and contrib/vstudio -- Add const to vsnprintf test in configure to avoid warnings [Weigelt] -- Delete zconf.h (made by configure) [Weigelt] -- Change zconf.in.h to zconf.h.in per convention [Weigelt] -- Check for NULL buf in gzgets() -- Return empty string for gzgets() with len == 1 (like fgets()) -- Fix description of gzgets() in zlib.h for end-of-file, NULL return -- Update minizip to 1.1 [Vollant] -- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c -- Note in zlib.h that gzerror() should be used to distinguish from EOF -- Remove use of snprintf() from gzlib.c -- Fix bug in gzseek() -- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant] -- Fix zconf.h generation in CMakeLists.txt [Lowman] -- Improve comments in zconf.h where modified by configure - -Changes in 1.2.3.8 (13 Feb 2010) -- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer] -- Use z_off64_t in gz_zero() and gz_skip() to match state->skip -- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t) -- Revert to Makefile.in from 1.2.3.6 (live with the clutter) -- Fix missing error return in gzflush(), add zlib.h note -- Add *64 functions to zlib.map [Levin] -- Fix signed/unsigned comparison in gz_comp() -- Use SFLAGS when testing shared linking in configure -- Add --64 option to ./configure to use -m64 with gcc -- Fix ./configure --help to correctly name options -- Have make fail if a test fails [Levin] -- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson] -- Remove assembler object files from contrib - -Changes in 1.2.3.7 (24 Jan 2010) -- Always gzopen() with O_LARGEFILE if available -- Fix gzdirect() to work immediately after gzopen() or gzdopen() -- Make gzdirect() more precise when the state changes while reading -- Improve zlib.h documentation in many places -- Catch memory allocation failure in gz_open() -- Complete close operation if seek forward in gzclose_w() fails -- Return Z_ERRNO from gzclose_r() if close() fails -- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL -- Return zero for gzwrite() errors to match zlib.h description -- Return -1 on gzputs() error to match zlib.h description -- Add zconf.in.h to allow recovery from configure modification [Weigelt] -- Fix static library permissions in Makefile.in [Weigelt] -- Avoid warnings in configure tests that hide functionality [Weigelt] -- Add *BSD and DragonFly to Linux case in configure [gentoo 123571] -- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212] -- Avoid access of uninitialized data for first inflateReset2 call [Gomes] -- Keep object files in subdirectories to reduce the clutter somewhat -- Remove default Makefile and zlibdefs.h, add dummy Makefile -- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_ -- Remove zlibdefs.h completely -- modify zconf.h instead - -Changes in 1.2.3.6 (17 Jan 2010) -- Avoid void * arithmetic in gzread.c and gzwrite.c -- Make compilers happier with const char * for gz_error message -- Avoid unused parameter warning in inflate.c -- Avoid signed-unsigned comparison warning in inflate.c -- Indent #pragma's for traditional C -- Fix usage of strwinerror() in glib.c, change to gz_strwinerror() -- Correct email address in configure for system options -- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser] -- Update zlib.map [Brown] -- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok] -- Apply various fixes to CMakeLists.txt [Lowman] -- Add checks on len in gzread() and gzwrite() -- Add error message for no more room for gzungetc() -- Remove zlib version check in gzwrite() -- Defer compression of gzprintf() result until need to -- Use snprintf() in gzdopen() if available -- Remove USE_MMAP configuration determination (only used by minigzip) -- Remove examples/pigz.c (available separately) -- Update examples/gun.c to 1.6 - -Changes in 1.2.3.5 (8 Jan 2010) -- Add space after #if in zutil.h for some compilers -- Fix relatively harmless bug in deflate_fast() [Exarevsky] -- Fix same problem in deflate_slow() -- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown] -- Add deflate_rle() for faster Z_RLE strategy run-length encoding -- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding -- Change name of "write" variable in inffast.c to avoid library collisions -- Fix premature EOF from gzread() in gzio.c [Brown] -- Use zlib header window size if windowBits is 0 in inflateInit2() -- Remove compressBound() call in deflate.c to avoid linking compress.o -- Replace use of errno in gz* with functions, support WinCE [Alves] -- Provide alternative to perror() in minigzip.c for WinCE [Alves] -- Don't use _vsnprintf on later versions of MSVC [Lowman] -- Add CMake build script and input file [Lowman] -- Update contrib/minizip to 1.1 [Svensson, Vollant] -- Moved nintendods directory from contrib to . -- Replace gzio.c with a new set of routines with the same functionality -- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above -- Update contrib/minizip to 1.1b -- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h - -Changes in 1.2.3.4 (21 Dec 2009) -- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility -- Update comments in configure and Makefile.in for default --shared -- Fix test -z's in configure [Marquess] -- Build examplesh and minigzipsh when not testing -- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h -- Import LDFLAGS from the environment in configure -- Fix configure to populate SFLAGS with discovered CFLAGS options -- Adapt make_vms.com to the new Makefile.in [Zinser] -- Add zlib2ansi script for C++ compilation [Marquess] -- Add _FILE_OFFSET_BITS=64 test to make test (when applicable) -- Add AMD64 assembler code for longest match to contrib [Teterin] -- Include options from $SFLAGS when doing $LDSHARED -- Simplify 64-bit file support by introducing z_off64_t type -- Make shared object files in objs directory to work around old Sun cc -- Use only three-part version number for Darwin shared compiles -- Add rc option to ar in Makefile.in for when ./configure not run -- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4* -- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile -- Protect against _FILE_OFFSET_BITS being defined when compiling zlib -- Rename Makefile.in targets allstatic to static and allshared to shared -- Fix static and shared Makefile.in targets to be independent -- Correct error return bug in gz_open() by setting state [Brown] -- Put spaces before ;;'s in configure for better sh compatibility -- Add pigz.c (parallel implementation of gzip) to examples/ -- Correct constant in crc32.c to UL [Leventhal] -- Reject negative lengths in crc32_combine() -- Add inflateReset2() function to work like inflateEnd()/inflateInit2() -- Include sys/types.h for _LARGEFILE64_SOURCE [Brown] -- Correct typo in doc/algorithm.txt [Janik] -- Fix bug in adler32_combine() [Zhu] -- Catch missing-end-of-block-code error in all inflates and in puff - Assures that random input to inflate eventually results in an error -- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/ -- Update ENOUGH and its usage to reflect discovered bounds -- Fix gzerror() error report on empty input file [Brown] -- Add ush casts in trees.c to avoid pedantic runtime errors -- Fix typo in zlib.h uncompress() description [Reiss] -- Correct inflate() comments with regard to automatic header detection -- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays) -- Put new version of gzlog (2.0) in examples with interruption recovery -- Add puff compile option to permit invalid distance-too-far streams -- Add puff TEST command options, ability to read piped input -- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but - _LARGEFILE64_SOURCE not defined -- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart -- Fix deflateSetDictionary() to use all 32K for output consistency -- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h) -- Clear bytes after deflate lookahead to avoid use of uninitialized data -- Change a limit in inftrees.c to be more transparent to Coverity Prevent -- Update win32/zlib.def with exported symbols from zlib.h -- Correct spelling errors in zlib.h [Willem, Sobrado] -- Allow Z_BLOCK for deflate() to force a new block -- Allow negative bits in inflatePrime() to delete existing bit buffer -- Add Z_TREES flush option to inflate() to return at end of trees -- Add inflateMark() to return current state information for random access -- Add Makefile for NintendoDS to contrib [Costa] -- Add -w in configure compile tests to avoid spurious warnings [Beucler] -- Fix typos in zlib.h comments for deflateSetDictionary() -- Fix EOF detection in transparent gzread() [Maier] - -Changes in 1.2.3.3 (2 October 2006) -- Make --shared the default for configure, add a --static option -- Add compile option to permit invalid distance-too-far streams -- Add inflateUndermine() function which is required to enable above -- Remove use of "this" variable name for C++ compatibility [Marquess] -- Add testing of shared library in make test, if shared library built -- Use ftello() and fseeko() if available instead of ftell() and fseek() -- Provide two versions of all functions that use the z_off_t type for - binary compatibility -- a normal version and a 64-bit offset version, - per the Large File Support Extension when _LARGEFILE64_SOURCE is - defined; use the 64-bit versions by default when _FILE_OFFSET_BITS - is defined to be 64 -- Add a --uname= option to configure to perhaps help with cross-compiling - -Changes in 1.2.3.2 (3 September 2006) -- Turn off silly Borland warnings [Hay] -- Use off64_t and define _LARGEFILE64_SOURCE when present -- Fix missing dependency on inffixed.h in Makefile.in -- Rig configure --shared to build both shared and static [Teredesai, Truta] -- Remove zconf.in.h and instead create a new zlibdefs.h file -- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant] -- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt] - -Changes in 1.2.3.1 (16 August 2006) -- Add watcom directory with OpenWatcom make files [Daniel] -- Remove #undef of FAR in zconf.in.h for MVS [Fedtke] -- Update make_vms.com [Zinser] -- Use -fPIC for shared build in configure [Teredesai, Nicholson] -- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen] -- Use fdopen() (not _fdopen()) for Interix in zutil.h [Bäck] -- Add some FAQ entries about the contrib directory -- Update the MVS question in the FAQ -- Avoid extraneous reads after EOF in gzio.c [Brown] -- Correct spelling of "successfully" in gzio.c [Randers-Pehrson] -- Add comments to zlib.h about gzerror() usage [Brown] -- Set extra flags in gzip header in gzopen() like deflate() does -- Make configure options more compatible with double-dash conventions - [Weigelt] -- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen] -- Fix uninstall target in Makefile.in [Truta] -- Add pkgconfig support [Weigelt] -- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt] -- Replace set_data_type() with a more accurate detect_data_type() in - trees.c, according to the txtvsbin.txt document [Truta] -- Swap the order of #include and #include "zlib.h" in - gzio.c, example.c and minigzip.c [Truta] -- Shut up annoying VS2005 warnings about standard C deprecation [Rowe, - Truta] (where?) -- Fix target "clean" from win32/Makefile.bor [Truta] -- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe] -- Update zlib www home address in win32/DLL_FAQ.txt [Truta] -- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove] -- Enable browse info in the "Debug" and "ASM Debug" configurations in - the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta] -- Add pkgconfig support [Weigelt] -- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h, - for use in win32/zlib1.rc [Polushin, Rowe, Truta] -- Add a document that explains the new text detection scheme to - doc/txtvsbin.txt [Truta] -- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta] -- Move algorithm.txt into doc/ [Truta] -- Synchronize FAQ with website -- Fix compressBound(), was low for some pathological cases [Fearnley] -- Take into account wrapper variations in deflateBound() -- Set examples/zpipe.c input and output to binary mode for Windows -- Update examples/zlib_how.html with new zpipe.c (also web site) -- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems - that gcc became pickier in 4.0) -- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain - un-versioned, the patch adds versioning only for symbols introduced in - zlib-1.2.0 or later. It also declares as local those symbols which are - not designed to be exported." [Levin] -- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure -- Do not initialize global static by default in trees.c, add a response - NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess] -- Don't use strerror() in gzio.c under WinCE [Yakimov] -- Don't use errno.h in zutil.h under WinCE [Yakimov] -- Move arguments for AR to its usage to allow replacing ar [Marot] -- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson] -- Improve inflateInit() and inflateInit2() documentation -- Fix structure size comment in inflate.h -- Change configure help option from --h* to --help [Santos] - -Changes in 1.2.3 (18 July 2005) -- Apply security vulnerability fixes to contrib/infback9 as well -- Clean up some text files (carriage returns, trailing space) -- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] - -Changes in 1.2.2.4 (11 July 2005) -- Add inflatePrime() function for starting inflation at bit boundary -- Avoid some Visual C warnings in deflate.c -- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit - compile -- Fix some spelling errors in comments [Betts] -- Correct inflateInit2() error return documentation in zlib.h -- Add zran.c example of compressed data random access to examples - directory, shows use of inflatePrime() -- Fix cast for assignments to strm->state in inflate.c and infback.c -- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] -- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] -- Add cast in trees.c t avoid a warning [Oberhumer] -- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] -- Update make_vms.com [Zinser] -- Initialize state->write in inflateReset() since copied in inflate_fast() -- Be more strict on incomplete code sets in inflate_table() and increase - ENOUGH and MAXD -- this repairs a possible security vulnerability for - invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for - discovering the vulnerability and providing test cases. -- Add ia64 support to configure for HP-UX [Smith] -- Add error return to gzread() for format or i/o error [Levin] -- Use malloc.h for OS/2 [Necasek] - -Changes in 1.2.2.3 (27 May 2005) -- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile -- Typecast fread() return values in gzio.c [Vollant] -- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) -- Fix crc check bug in gzread() after gzungetc() [Heiner] -- Add the deflateTune() function to adjust internal compression parameters -- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) -- Remove an incorrect assertion in examples/zpipe.c -- Add C++ wrapper in infback9.h [Donais] -- Fix bug in inflateCopy() when decoding fixed codes -- Note in zlib.h how much deflateSetDictionary() actually uses -- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) -- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] -- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] -- Add gzdirect() function to indicate transparent reads -- Update contrib/minizip [Vollant] -- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] -- Add casts in crc32.c to avoid warnings [Oberhumer] -- Add contrib/masmx64 [Vollant] -- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] - -Changes in 1.2.2.2 (30 December 2004) -- Replace structure assignments in deflate.c and inflate.c with zmemcpy to - avoid implicit memcpy calls (portability for no-library compilation) -- Increase sprintf() buffer size in gzdopen() to allow for large numbers -- Add INFLATE_STRICT to check distances against zlib header -- Improve WinCE errno handling and comments [Chang] -- Remove comment about no gzip header processing in FAQ -- Add Z_FIXED strategy option to deflateInit2() to force fixed trees -- Add updated make_vms.com [Coghlan], update README -- Create a new "examples" directory, move gzappend.c there, add zpipe.c, - fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. -- Add FAQ entry and comments in deflate.c on uninitialized memory access -- Add Solaris 9 make options in configure [Gilbert] -- Allow strerror() usage in gzio.c for STDC -- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] -- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] -- Use z_off_t for adler32_combine() and crc32_combine() lengths -- Make adler32() much faster for small len -- Use OS_CODE in deflate() default gzip header - -Changes in 1.2.2.1 (31 October 2004) -- Allow inflateSetDictionary() call for raw inflate -- Fix inflate header crc check bug for file names and comments -- Add deflateSetHeader() and gz_header structure for custom gzip headers -- Add inflateGetheader() to retrieve gzip headers -- Add crc32_combine() and adler32_combine() functions -- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list -- Use zstreamp consistently in zlib.h (inflate_back functions) -- Remove GUNZIP condition from definition of inflate_mode in inflate.h - and in contrib/inflate86/inffast.S [Truta, Anderson] -- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] -- Update projects/README.projects and projects/visualc6 [Truta] -- Update win32/DLL_FAQ.txt [Truta] -- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] -- Deprecate Z_ASCII; use Z_TEXT instead [Truta] -- Use a new algorithm for setting strm->data_type in trees.c [Truta] -- Do not define an exit() prototype in zutil.c unless DEBUG defined -- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] -- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() -- Fix Darwin build version identification [Peterson] - -Changes in 1.2.2 (3 October 2004) -- Update zlib.h comments on gzip in-memory processing -- Set adler to 1 in inflateReset() to support Java test suite [Walles] -- Add contrib/dotzlib [Ravn] -- Update win32/DLL_FAQ.txt [Truta] -- Update contrib/minizip [Vollant] -- Move contrib/visual-basic.txt to old/ [Truta] -- Fix assembler builds in projects/visualc6/ [Truta] - -Changes in 1.2.1.2 (9 September 2004) -- Update INDEX file -- Fix trees.c to update strm->data_type (no one ever noticed!) -- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] -- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) -- Add limited multitasking protection to DYNAMIC_CRC_TABLE -- Add NO_vsnprintf for VMS in zutil.h [Mozilla] -- Don't declare strerror() under VMS [Mozilla] -- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize -- Update contrib/ada [Anisimkov] -- Update contrib/minizip [Vollant] -- Fix configure to not hardcode directories for Darwin [Peterson] -- Fix gzio.c to not return error on empty files [Brown] -- Fix indentation; update version in contrib/delphi/ZLib.pas and - contrib/pascal/zlibpas.pas [Truta] -- Update mkasm.bat in contrib/masmx86 [Truta] -- Update contrib/untgz [Truta] -- Add projects/README.projects [Truta] -- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] -- Update win32/DLL_FAQ.txt [Truta] -- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] -- Remove an unnecessary assignment to curr in inftrees.c [Truta] -- Add OS/2 to exe builds in configure [Poltorak] -- Remove err dummy parameter in zlib.h [Kientzle] - -Changes in 1.2.1.1 (9 January 2004) -- Update email address in README -- Several FAQ updates -- Fix a big fat bug in inftrees.c that prevented decoding valid - dynamic blocks with only literals and no distance codes -- - Thanks to "Hot Emu" for the bug report and sample file -- Add a note to puff.c on no distance codes case. - -Changes in 1.2.1 (17 November 2003) -- Remove a tab in contrib/gzappend/gzappend.c -- Update some interfaces in contrib for new zlib functions -- Update zlib version number in some contrib entries -- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] -- Support shared libraries on Hurd and KFreeBSD [Brown] -- Fix error in NO_DIVIDE option of adler32.c - -Changes in 1.2.0.8 (4 November 2003) -- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas -- Add experimental NO_DIVIDE #define in adler32.c - - Possibly faster on some processors (let me know if it is) -- Correct Z_BLOCK to not return on first inflate call if no wrap -- Fix strm->data_type on inflate() return to correctly indicate EOB -- Add deflatePrime() function for appending in the middle of a byte -- Add contrib/gzappend for an example of appending to a stream -- Update win32/DLL_FAQ.txt [Truta] -- Delete Turbo C comment in README [Truta] -- Improve some indentation in zconf.h [Truta] -- Fix infinite loop on bad input in configure script [Church] -- Fix gzeof() for concatenated gzip files [Johnson] -- Add example to contrib/visual-basic.txt [Michael B.] -- Add -p to mkdir's in Makefile.in [vda] -- Fix configure to properly detect presence or lack of printf functions -- Add AS400 support [Monnerat] -- Add a little Cygwin support [Wilson] - -Changes in 1.2.0.7 (21 September 2003) -- Correct some debug formats in contrib/infback9 -- Cast a type in a debug statement in trees.c -- Change search and replace delimiter in configure from % to # [Beebe] -- Update contrib/untgz to 0.2 with various fixes [Truta] -- Add build support for Amiga [Nikl] -- Remove some directories in old that have been updated to 1.2 -- Add dylib building for Mac OS X in configure and Makefile.in -- Remove old distribution stuff from Makefile -- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X -- Update links in README - -Changes in 1.2.0.6 (13 September 2003) -- Minor FAQ updates -- Update contrib/minizip to 1.00 [Vollant] -- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] -- Update POSTINC comment for 68060 [Nikl] -- Add contrib/infback9 with deflate64 decoding (unsupported) -- For MVS define NO_vsnprintf and undefine FAR [van Burik] -- Add pragma for fdopen on MVS [van Burik] - -Changes in 1.2.0.5 (8 September 2003) -- Add OF to inflateBackEnd() declaration in zlib.h -- Remember start when using gzdopen in the middle of a file -- Use internal off_t counters in gz* functions to properly handle seeks -- Perform more rigorous check for distance-too-far in inffast.c -- Add Z_BLOCK flush option to return from inflate at block boundary -- Set strm->data_type on return from inflate - - Indicate bits unused, if at block boundary, and if in last block -- Replace size_t with ptrdiff_t in crc32.c, and check for correct size -- Add condition so old NO_DEFLATE define still works for compatibility -- FAQ update regarding the Windows DLL [Truta] -- INDEX update: add qnx entry, remove aix entry [Truta] -- Install zlib.3 into mandir [Wilson] -- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] -- Adapt the zlib interface to the new DLL convention guidelines [Truta] -- Introduce ZLIB_WINAPI macro to allow the export of functions using - the WINAPI calling convention, for Visual Basic [Vollant, Truta] -- Update msdos and win32 scripts and makefiles [Truta] -- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] -- Add contrib/ada [Anisimkov] -- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] -- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] -- Add contrib/masm686 [Truta] -- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm - [Truta, Vollant] -- Update contrib/delphi; rename to contrib/pascal; add example [Truta] -- Remove contrib/delphi2; add a new contrib/delphi [Truta] -- Avoid inclusion of the nonstandard in contrib/iostream, - and fix some method prototypes [Truta] -- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip - [Truta] -- Avoid the use of backslash (\) in contrib/minizip [Vollant] -- Fix file time handling in contrib/untgz; update makefiles [Truta] -- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines - [Vollant] -- Remove contrib/vstudio/vc15_16 [Vollant] -- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] -- Update README.contrib [Truta] -- Invert the assignment order of match_head and s->prev[...] in - INSERT_STRING [Truta] -- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings - [Truta] -- Compare function pointers with 0, not with NULL or Z_NULL [Truta] -- Fix prototype of syncsearch in inflate.c [Truta] -- Introduce ASMINF macro to be enabled when using an ASM implementation - of inflate_fast [Truta] -- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] -- Modify test_gzio in example.c to take a single file name as a - parameter [Truta] -- Exit the example.c program if gzopen fails [Truta] -- Add type casts around strlen in example.c [Truta] -- Remove casting to sizeof in minigzip.c; give a proper type - to the variable compared with SUFFIX_LEN [Truta] -- Update definitions of STDC and STDC99 in zconf.h [Truta] -- Synchronize zconf.h with the new Windows DLL interface [Truta] -- Use SYS16BIT instead of __32BIT__ to distinguish between - 16- and 32-bit platforms [Truta] -- Use far memory allocators in small 16-bit memory models for - Turbo C [Truta] -- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in - zlibCompileFlags [Truta] -- Cygwin has vsnprintf [Wilson] -- In Windows16, OS_CODE is 0, as in MSDOS [Truta] -- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] - -Changes in 1.2.0.4 (10 August 2003) -- Minor FAQ updates -- Be more strict when checking inflateInit2's windowBits parameter -- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well -- Add gzip wrapper option to deflateInit2 using windowBits -- Add updated QNX rule in configure and qnx directory [Bonnefoy] -- Make inflate distance-too-far checks more rigorous -- Clean up FAR usage in inflate -- Add casting to sizeof() in gzio.c and minigzip.c - -Changes in 1.2.0.3 (19 July 2003) -- Fix silly error in gzungetc() implementation [Vollant] -- Update contrib/minizip and contrib/vstudio [Vollant] -- Fix printf format in example.c -- Correct cdecl support in zconf.in.h [Anisimkov] -- Minor FAQ updates - -Changes in 1.2.0.2 (13 July 2003) -- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons -- Attempt to avoid warnings in crc32.c for pointer-int conversion -- Add AIX to configure, remove aix directory [Bakker] -- Add some casts to minigzip.c -- Improve checking after insecure sprintf() or vsprintf() calls -- Remove #elif's from crc32.c -- Change leave label to inf_leave in inflate.c and infback.c to avoid - library conflicts -- Remove inflate gzip decoding by default--only enable gzip decoding by - special request for stricter backward compatibility -- Add zlibCompileFlags() function to return compilation information -- More typecasting in deflate.c to avoid warnings -- Remove leading underscore from _Capital #defines [Truta] -- Fix configure to link shared library when testing -- Add some Windows CE target adjustments [Mai] -- Remove #define ZLIB_DLL in zconf.h [Vollant] -- Add zlib.3 [Rodgers] -- Update RFC URL in deflate.c and algorithm.txt [Mai] -- Add zlib_dll_FAQ.txt to contrib [Truta] -- Add UL to some constants [Truta] -- Update minizip and vstudio [Vollant] -- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h -- Expand use of NO_DUMMY_DECL to avoid all dummy structures -- Added iostream3 to contrib [Schwardt] -- Replace rewind() with fseek() for WinCE [Truta] -- Improve setting of zlib format compression level flags - - Report 0 for huffman and rle strategies and for level == 0 or 1 - - Report 2 only for level == 6 -- Only deal with 64K limit when necessary at compile time [Truta] -- Allow TOO_FAR check to be turned off at compile time [Truta] -- Add gzclearerr() function [Souza] -- Add gzungetc() function - -Changes in 1.2.0.1 (17 March 2003) -- Add Z_RLE strategy for run-length encoding [Truta] - - When Z_RLE requested, restrict matches to distance one - - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE -- Correct FASTEST compilation to allow level == 0 -- Clean up what gets compiled for FASTEST -- Incorporate changes to zconf.in.h [Vollant] - - Refine detection of Turbo C need for dummy returns - - Refine ZLIB_DLL compilation - - Include additional header file on VMS for off_t typedef -- Try to use _vsnprintf where it supplants vsprintf [Vollant] -- Add some casts in inffast.c -- Enchance comments in zlib.h on what happens if gzprintf() tries to - write more than 4095 bytes before compression -- Remove unused state from inflateBackEnd() -- Remove exit(0) from minigzip.c, example.c -- Get rid of all those darn tabs -- Add "check" target to Makefile.in that does the same thing as "test" -- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in -- Update contrib/inflate86 [Anderson] -- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] -- Add msdos and win32 directories with makefiles [Truta] -- More additions and improvements to the FAQ - -Changes in 1.2.0 (9 March 2003) -- New and improved inflate code - - About 20% faster - - Does not allocate 32K window unless and until needed - - Automatically detects and decompresses gzip streams - - Raw inflate no longer needs an extra dummy byte at end - - Added inflateBack functions using a callback interface--even faster - than inflate, useful for file utilities (gzip, zip) - - Added inflateCopy() function to record state for random access on - externally generated deflate streams (e.g. in gzip files) - - More readable code (I hope) -- New and improved crc32() - - About 50% faster, thanks to suggestions from Rodney Brown -- Add deflateBound() and compressBound() functions -- Fix memory leak in deflateInit2() -- Permit setting dictionary for raw deflate (for parallel deflate) -- Fix const declaration for gzwrite() -- Check for some malloc() failures in gzio.c -- Fix bug in gzopen() on single-byte file 0x1f -- Fix bug in gzread() on concatenated file with 0x1f at end of buffer - and next buffer doesn't start with 0x8b -- Fix uncompress() to return Z_DATA_ERROR on truncated input -- Free memory at end of example.c -- Remove MAX #define in trees.c (conflicted with some libraries) -- Fix static const's in deflate.c, gzio.c, and zutil.[ch] -- Declare malloc() and free() in gzio.c if STDC not defined -- Use malloc() instead of calloc() in zutil.c if int big enough -- Define STDC for AIX -- Add aix/ with approach for compiling shared library on AIX -- Add HP-UX support for shared libraries in configure -- Add OpenUNIX support for shared libraries in configure -- Use $cc instead of gcc to build shared library -- Make prefix directory if needed when installing -- Correct Macintosh avoidance of typedef Byte in zconf.h -- Correct Turbo C memory allocation when under Linux -- Use libz.a instead of -lz in Makefile (assure use of compiled library) -- Update configure to check for snprintf or vsnprintf functions and their - return value, warn during make if using an insecure function -- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that - is lost when library is used--resolution is to build new zconf.h -- Documentation improvements (in zlib.h): - - Document raw deflate and inflate - - Update RFCs URL - - Point out that zlib and gzip formats are different - - Note that Z_BUF_ERROR is not fatal - - Document string limit for gzprintf() and possible buffer overflow - - Note requirement on avail_out when flushing - - Note permitted values of flush parameter of inflate() -- Add some FAQs (and even answers) to the FAQ -- Add contrib/inflate86/ for x86 faster inflate -- Add contrib/blast/ for PKWare Data Compression Library decompression -- Add contrib/puff/ simple inflate for deflate format description - -Changes in 1.1.4 (11 March 2002) -- ZFREE was repeated on same allocation on some error conditions. - This creates a security problem described in - http://www.zlib.org/advisory-2002-03-11.txt -- Returned incorrect error (Z_MEM_ERROR) on some invalid data -- Avoid accesses before window for invalid distances with inflate window - less than 32K. -- force windowBits > 8 to avoid a bug in the encoder for a window size - of 256 bytes. (A complete fix will be available in 1.1.5). - -Changes in 1.1.3 (9 July 1998) -- fix "an inflate input buffer bug that shows up on rare but persistent - occasions" (Mark) -- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) -- fix gzseek(..., SEEK_SET) in write mode -- fix crc check after a gzeek (Frank Faubert) -- fix miniunzip when the last entry in a zip file is itself a zip file - (J Lillge) -- add contrib/asm586 and contrib/asm686 (Brian Raiter) - See http://www.muppetlabs.com/~breadbox/software/assembly.html -- add support for Delphi 3 in contrib/delphi (Bob Dellaca) -- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) -- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) -- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) -- added a FAQ file - -- Support gzdopen on Mac with Metrowerks (Jason Linhart) -- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) -- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) -- avoid some warnings with Borland C (Tom Tanner) -- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) -- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) -- allow several arguments to configure (Tim Mooney, Frodo Looijaard) -- use libdir and includedir in Makefile.in (Tim Mooney) -- support shared libraries on OSF1 V4 (Tim Mooney) -- remove so_locations in "make clean" (Tim Mooney) -- fix maketree.c compilation error (Glenn, Mark) -- Python interface to zlib now in Python 1.5 (Jeremy Hylton) -- new Makefile.riscos (Rich Walker) -- initialize static descriptors in trees.c for embedded targets (Nick Smith) -- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) -- add the OS/2 files in Makefile.in too (Andrew Zabolotny) -- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) -- fix maketree.c to allow clean compilation of inffixed.h (Mark) -- fix parameter check in deflateCopy (Gunther Nikl) -- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) -- Many portability patches by Christian Spieler: - . zutil.c, zutil.h: added "const" for zmem* - . Make_vms.com: fixed some typos - . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists - . msdos/Makefile.msc: remove "default rtl link library" info from obj files - . msdos/Makefile.*: use model-dependent name for the built zlib library - . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: - new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) -- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) -- replace __far with _far for better portability (Christian Spieler, Tom Lane) -- fix test for errno.h in configure (Tim Newsham) - -Changes in 1.1.2 (19 March 98) -- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) - See http://www.winimage.com/zLibDll/unzip.html -- preinitialize the inflate tables for fixed codes, to make the code - completely thread safe (Mark) -- some simplifications and slight speed-up to the inflate code (Mark) -- fix gzeof on non-compressed files (Allan Schrum) -- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) -- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) -- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) -- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) -- do not wrap extern "C" around system includes (Tom Lane) -- mention zlib binding for TCL in README (Andreas Kupries) -- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) -- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) -- allow "configure --prefix $HOME" (Tim Mooney) -- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) -- move Makefile.sas to amiga/Makefile.sas - -Changes in 1.1.1 (27 Feb 98) -- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) -- remove block truncation heuristic which had very marginal effect for zlib - (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the - compression ratio on some files. This also allows inlining _tr_tally for - matches in deflate_slow. -- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) - -Changes in 1.1.0 (24 Feb 98) -- do not return STREAM_END prematurely in inflate (John Bowler) -- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) -- compile with -DFASTEST to get compression code optimized for speed only -- in minigzip, try mmap'ing the input file first (Miguel Albrecht) -- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain - on Sun but significant on HP) - -- add a pointer to experimental unzip library in README (Gilles Vollant) -- initialize variable gcc in configure (Chris Herborth) - -Changes in 1.0.9 (17 Feb 1998) -- added gzputs and gzgets functions -- do not clear eof flag in gzseek (Mark Diekhans) -- fix gzseek for files in transparent mode (Mark Diekhans) -- do not assume that vsprintf returns the number of bytes written (Jens Krinke) -- replace EXPORT with ZEXPORT to avoid conflict with other programs -- added compress2 in zconf.h, zlib.def, zlib.dnt -- new asm code from Gilles Vollant in contrib/asm386 -- simplify the inflate code (Mark): - . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() - . ZALLOC the length list in inflate_trees_fixed() instead of using stack - . ZALLOC the value area for huft_build() instead of using stack - . Simplify Z_FINISH check in inflate() - -- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 -- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) -- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with - the declaration of FAR (Gilles VOllant) -- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) -- read_buf buf parameter of type Bytef* instead of charf* -- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) -- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) -- fix check for presence of directories in "make install" (Ian Willis) - -Changes in 1.0.8 (27 Jan 1998) -- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) -- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) -- added compress2() to allow setting the compression level -- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) -- use constant arrays for the static trees in trees.c instead of computing - them at run time (thanks to Ken Raeburn for this suggestion). To create - trees.h, compile with GEN_TREES_H and run "make test". -- check return code of example in "make test" and display result -- pass minigzip command line options to file_compress -- simplifying code of inflateSync to avoid gcc 2.8 bug - -- support CC="gcc -Wall" in configure -s (QingLong) -- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) -- fix test for shared library support to avoid compiler warnings -- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) -- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) -- do not use fdopen for Metrowerks on Mac (Brad Pettit)) -- add checks for gzputc and gzputc in example.c -- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) -- use const for the CRC table (Ken Raeburn) -- fixed "make uninstall" for shared libraries -- use Tracev instead of Trace in infblock.c -- in example.c use correct compressed length for test_sync -- suppress +vnocompatwarnings in configure for HPUX (not always supported) - -Changes in 1.0.7 (20 Jan 1998) -- fix gzseek which was broken in write mode -- return error for gzseek to negative absolute position -- fix configure for Linux (Chun-Chung Chen) -- increase stack space for MSC (Tim Wegner) -- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) -- define EXPORTVA for gzprintf (Gilles Vollant) -- added man page zlib.3 (Rick Rodgers) -- for contrib/untgz, fix makedir() and improve Makefile - -- check gzseek in write mode in example.c -- allocate extra buffer for seeks only if gzseek is actually called -- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) -- add inflateSyncPoint in zconf.h -- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def - -Changes in 1.0.6 (19 Jan 1998) -- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and - gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) -- Fix a deflate bug occurring only with compression level 0 (thanks to - Andy Buckler for finding this one). -- In minigzip, pass transparently also the first byte for .Z files. -- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() -- check Z_FINISH in inflate (thanks to Marc Schluper) -- Implement deflateCopy (thanks to Adam Costello) -- make static libraries by default in configure, add --shared option. -- move MSDOS or Windows specific files to directory msdos -- suppress the notion of partial flush to simplify the interface - (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) -- suppress history buffer provided by application to simplify the interface - (this feature was not implemented anyway in 1.0.4) -- next_in and avail_in must be initialized before calling inflateInit or - inflateInit2 -- add EXPORT in all exported functions (for Windows DLL) -- added Makefile.nt (thanks to Stephen Williams) -- added the unsupported "contrib" directory: - contrib/asm386/ by Gilles Vollant - 386 asm code replacing longest_match(). - contrib/iostream/ by Kevin Ruland - A C++ I/O streams interface to the zlib gz* functions - contrib/iostream2/ by Tyge Løvset - Another C++ I/O streams interface - contrib/untgz/ by "Pedro A. Aranda Guti\irrez" - A very simple tar.gz file extractor using zlib - contrib/visual-basic.txt by Carlos Rios - How to use compress(), uncompress() and the gz* functions from VB. -- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression - level) in minigzip (thanks to Tom Lane) - -- use const for rommable constants in deflate -- added test for gzseek and gztell in example.c -- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) -- add undocumented function zError to convert error code to string - (for Tim Smithers) -- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. -- Use default memcpy for Symantec MSDOS compiler. -- Add EXPORT keyword for check_func (needed for Windows DLL) -- add current directory to LD_LIBRARY_PATH for "make test" -- create also a link for libz.so.1 -- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) -- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) -- added -soname for Linux in configure (Chun-Chung Chen, -- assign numbers to the exported functions in zlib.def (for Windows DLL) -- add advice in zlib.h for best usage of deflateSetDictionary -- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) -- allow compilation with ANSI keywords only enabled for TurboC in large model -- avoid "versionString"[0] (Borland bug) -- add NEED_DUMMY_RETURN for Borland -- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). -- allow compilation with CC -- defined STDC for OS/2 (David Charlap) -- limit external names to 8 chars for MVS (Thomas Lund) -- in minigzip.c, use static buffers only for 16-bit systems -- fix suffix check for "minigzip -d foo.gz" -- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) -- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) -- added makelcc.bat for lcc-win32 (Tom St Denis) -- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) -- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. -- check for unistd.h in configure (for off_t) -- remove useless check parameter in inflate_blocks_free -- avoid useless assignment of s->check to itself in inflate_blocks_new -- do not flush twice in gzclose (thanks to Ken Raeburn) -- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h -- use NO_ERRNO_H instead of enumeration of operating systems with errno.h -- work around buggy fclose on pipes for HP/UX -- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) -- fix configure if CC is already equal to gcc - -Changes in 1.0.5 (3 Jan 98) -- Fix inflate to terminate gracefully when fed corrupted or invalid data -- Use const for rommable constants in inflate -- Eliminate memory leaks on error conditions in inflate -- Removed some vestigial code in inflate -- Update web address in README - -Changes in 1.0.4 (24 Jul 96) -- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF - bit, so the decompressor could decompress all the correct data but went - on to attempt decompressing extra garbage data. This affected minigzip too. -- zlibVersion and gzerror return const char* (needed for DLL) -- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) -- use z_error only for DEBUG (avoid problem with DLLs) - -Changes in 1.0.3 (2 Jul 96) -- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS - small and medium models; this makes the library incompatible with previous - versions for these models. (No effect in large model or on other systems.) -- return OK instead of BUF_ERROR if previous deflate call returned with - avail_out as zero but there is nothing to do -- added memcmp for non STDC compilers -- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) -- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) -- better check for 16-bit mode MSC (avoids problem with Symantec) - -Changes in 1.0.2 (23 May 96) -- added Windows DLL support -- added a function zlibVersion (for the DLL support) -- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) -- Bytef is define's instead of typedef'd only for Borland C -- avoid reading uninitialized memory in example.c -- mention in README that the zlib format is now RFC1950 -- updated Makefile.dj2 -- added algorithm.doc - -Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] -- fix array overlay in deflate.c which sometimes caused bad compressed data -- fix inflate bug with empty stored block -- fix MSDOS medium model which was broken in 0.99 -- fix deflateParams() which could generate bad compressed data. -- Bytef is define'd instead of typedef'ed (work around Borland bug) -- added an INDEX file -- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), - Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) -- speed up adler32 for modern machines without auto-increment -- added -ansi for IRIX in configure -- static_init_done in trees.c is an int -- define unlink as delete for VMS -- fix configure for QNX -- add configure branch for SCO and HPUX -- avoid many warnings (unused variables, dead assignments, etc...) -- no fdopen for BeOS -- fix the Watcom fix for 32 bit mode (define FAR as empty) -- removed redefinition of Byte for MKWERKS -- work around an MWKERKS bug (incorrect merge of all .h files) - -Changes in 0.99 (27 Jan 96) -- allow preset dictionary shared between compressor and decompressor -- allow compression level 0 (no compression) -- add deflateParams in zlib.h: allow dynamic change of compression level - and compression strategy. -- test large buffers and deflateParams in example.c -- add optional "configure" to build zlib as a shared library -- suppress Makefile.qnx, use configure instead -- fixed deflate for 64-bit systems (detected on Cray) -- fixed inflate_blocks for 64-bit systems (detected on Alpha) -- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) -- always return Z_BUF_ERROR when deflate() has nothing to do -- deflateInit and inflateInit are now macros to allow version checking -- prefix all global functions and types with z_ with -DZ_PREFIX -- make falloc completely reentrant (inftrees.c) -- fixed very unlikely race condition in ct_static_init -- free in reverse order of allocation to help memory manager -- use zlib-1.0/* instead of zlib/* inside the tar.gz -- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith - -Wconversion -Wstrict-prototypes -Wmissing-prototypes" -- allow gzread on concatenated .gz files -- deflateEnd now returns Z_DATA_ERROR if it was premature -- deflate is finally (?) fully deterministic (no matches beyond end of input) -- Document Z_SYNC_FLUSH -- add uninstall in Makefile -- Check for __cpluplus in zlib.h -- Better test in ct_align for partial flush -- avoid harmless warnings for Borland C++ -- initialize hash_head in deflate.c -- avoid warning on fdopen (gzio.c) for HP cc -Aa -- include stdlib.h for STDC compilers -- include errno.h for Cray -- ignore error if ranlib doesn't exist -- call ranlib twice for NeXTSTEP -- use exec_prefix instead of prefix for libz.a -- renamed ct_* as _tr_* to avoid conflict with applications -- clear z->msg in inflateInit2 before any error return -- initialize opaque in example.c, gzio.c, deflate.c and inflate.c -- fixed typo in zconf.h (_GNUC__ => __GNUC__) -- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) -- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) -- in fcalloc, normalize pointer if size > 65520 bytes -- don't use special fcalloc for 32 bit Borland C++ -- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... -- use Z_BINARY instead of BINARY -- document that gzclose after gzdopen will close the file -- allow "a" as mode in gzopen. -- fix error checking in gzread -- allow skipping .gz extra-field on pipes -- added reference to Perl interface in README -- put the crc table in FAR data (I dislike more and more the medium model :) -- added get_crc_table -- added a dimension to all arrays (Borland C can't count). -- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast -- guard against multiple inclusion of *.h (for precompiled header on Mac) -- Watcom C pretends to be Microsoft C small model even in 32 bit mode. -- don't use unsized arrays to avoid silly warnings by Visual C++: - warning C4746: 'inflate_mask' : unsized array treated as '__far' - (what's wrong with far data in far model?). -- define enum out of inflate_blocks_state to allow compilation with C++ - -Changes in 0.95 (16 Aug 95) -- fix MSDOS small and medium model (now easier to adapt to any compiler) -- inlined send_bits -- fix the final (:-) bug for deflate with flush (output was correct but - not completely flushed in rare occasions). -- default window size is same for compression and decompression - (it's now sufficient to set MAX_WBITS in zconf.h). -- voidp -> voidpf and voidnp -> voidp (for consistency with other - typedefs and because voidnp was not near in large model). - -Changes in 0.94 (13 Aug 95) -- support MSDOS medium model -- fix deflate with flush (could sometimes generate bad output) -- fix deflateReset (zlib header was incorrectly suppressed) -- added support for VMS -- allow a compression level in gzopen() -- gzflush now calls fflush -- For deflate with flush, flush even if no more input is provided. -- rename libgz.a as libz.a -- avoid complex expression in infcodes.c triggering Turbo C bug -- work around a problem with gcc on Alpha (in INSERT_STRING) -- don't use inline functions (problem with some gcc versions) -- allow renaming of Byte, uInt, etc... with #define. -- avoid warning about (unused) pointer before start of array in deflate.c -- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c -- avoid reserved word 'new' in trees.c - -Changes in 0.93 (25 June 95) -- temporarily disable inline functions -- make deflate deterministic -- give enough lookahead for PARTIAL_FLUSH -- Set binary mode for stdin/stdout in minigzip.c for OS/2 -- don't even use signed char in inflate (not portable enough) -- fix inflate memory leak for segmented architectures - -Changes in 0.92 (3 May 95) -- don't assume that char is signed (problem on SGI) -- Clear bit buffer when starting a stored block -- no memcpy on Pyramid -- suppressed inftest.c -- optimized fill_window, put longest_match inline for gcc -- optimized inflate on stored blocks. -- untabify all sources to simplify patches - -Changes in 0.91 (2 May 95) -- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h -- Document the memory requirements in zconf.h -- added "make install" -- fix sync search logic in inflateSync -- deflate(Z_FULL_FLUSH) now works even if output buffer too short -- after inflateSync, don't scare people with just "lo world" -- added support for DJGPP - -Changes in 0.9 (1 May 95) -- don't assume that zalloc clears the allocated memory (the TurboC bug - was Mark's bug after all :) -- let again gzread copy uncompressed data unchanged (was working in 0.71) -- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented -- added a test of inflateSync in example.c -- moved MAX_WBITS to zconf.h because users might want to change that. -- document explicitly that zalloc(64K) on MSDOS must return a normalized - pointer (zero offset) -- added Makefiles for Microsoft C, Turbo C, Borland C++ -- faster crc32() - -Changes in 0.8 (29 April 95) -- added fast inflate (inffast.c) -- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this - is incompatible with previous versions of zlib which returned Z_OK. -- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) - (actually that was not a compiler bug, see 0.81 above) -- gzread no longer reads one extra byte in certain cases -- In gzio destroy(), don't reference a freed structure -- avoid many warnings for MSDOS -- avoid the ERROR symbol which is used by MS Windows - -Changes in 0.71 (14 April 95) -- Fixed more MSDOS compilation problems :( There is still a bug with - TurboC large model. - -Changes in 0.7 (14 April 95) -- Added full inflate support. -- Simplified the crc32() interface. The pre- and post-conditioning - (one's complement) is now done inside crc32(). WARNING: this is - incompatible with previous versions; see zlib.h for the new usage. - -Changes in 0.61 (12 April 95) -- workaround for a bug in TurboC. example and minigzip now work on MSDOS. - -Changes in 0.6 (11 April 95) -- added minigzip.c -- added gzdopen to reopen a file descriptor as gzFile -- added transparent reading of non-gziped files in gzread. -- fixed bug in gzread (don't read crc as data) -- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). -- don't allocate big arrays in the stack (for MSDOS) -- fix some MSDOS compilation problems - -Changes in 0.5: -- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but - not yet Z_FULL_FLUSH. -- support decompression but only in a single step (forced Z_FINISH) -- added opaque object for zalloc and zfree. -- added deflateReset and inflateReset -- added a variable zlib_version for consistency checking. -- renamed the 'filter' parameter of deflateInit2 as 'strategy'. - Added Z_FILTERED and Z_HUFFMAN_ONLY constants. - -Changes in 0.4: -- avoid "zip" everywhere, use zlib instead of ziplib. -- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush - if compression method == 8. -- added adler32 and crc32 -- renamed deflateOptions as deflateInit2, call one or the other but not both -- added the method parameter for deflateInit2. -- added inflateInit2 -- simplied considerably deflateInit and inflateInit by not supporting - user-provided history buffer. This is supported only in deflateInit2 - and inflateInit2. - -Changes in 0.3: -- prefix all macro names with Z_ -- use Z_FINISH instead of deflateEnd to finish compression. -- added Z_HUFFMAN_ONLY -- added gzerror() diff --git a/libraries/zlib/FAQ b/libraries/zlib/FAQ deleted file mode 100644 index 99b7cf92e45..00000000000 --- a/libraries/zlib/FAQ +++ /dev/null @@ -1,368 +0,0 @@ - - Frequently Asked Questions about zlib - - -If your question is not there, please check the zlib home page -http://zlib.net/ which may have more recent information. -The lastest zlib FAQ is at http://zlib.net/zlib_faq.html - - - 1. Is zlib Y2K-compliant? - - Yes. zlib doesn't handle dates. - - 2. Where can I get a Windows DLL version? - - The zlib sources can be compiled without change to produce a DLL. See the - file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the - precompiled DLL are found in the zlib web site at http://zlib.net/ . - - 3. Where can I get a Visual Basic interface to zlib? - - See - * http://marknelson.us/1997/01/01/zlib-engine/ - * win32/DLL_FAQ.txt in the zlib distribution - - 4. compress() returns Z_BUF_ERROR. - - Make sure that before the call of compress(), the length of the compressed - buffer is equal to the available size of the compressed buffer and not - zero. For Visual Basic, check that this parameter is passed by reference - ("as any"), not by value ("as long"). - - 5. deflate() or inflate() returns Z_BUF_ERROR. - - Before making the call, make sure that avail_in and avail_out are not zero. - When setting the parameter flush equal to Z_FINISH, also make sure that - avail_out is big enough to allow processing all pending input. Note that a - Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be - made with more input or output space. A Z_BUF_ERROR may in fact be - unavoidable depending on how the functions are used, since it is not - possible to tell whether or not there is more output pending when - strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a - heavily annotated example. - - 6. Where's the zlib documentation (man pages, etc.)? - - It's in zlib.h . Examples of zlib usage are in the files test/example.c - and test/minigzip.c, with more in examples/ . - - 7. Why don't you use GNU autoconf or libtool or ...? - - Because we would like to keep zlib as a very small and simple package. - zlib is rather portable and doesn't need much configuration. - - 8. I found a bug in zlib. - - Most of the time, such problems are due to an incorrect usage of zlib. - Please try to reproduce the problem with a small program and send the - corresponding source to us at zlib@gzip.org . Do not send multi-megabyte - data files without prior agreement. - - 9. Why do I get "undefined reference to gzputc"? - - If "make test" produces something like - - example.o(.text+0x154): undefined reference to `gzputc' - - check that you don't have old files libz.* in /usr/lib, /usr/local/lib or - /usr/X11R6/lib. Remove any old versions, then do "make install". - -10. I need a Delphi interface to zlib. - - See the contrib/delphi directory in the zlib distribution. - -11. Can zlib handle .zip archives? - - Not by itself, no. See the directory contrib/minizip in the zlib - distribution. - -12. Can zlib handle .Z files? - - No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt - the code of uncompress on your own. - -13. How can I make a Unix shared library? - - By default a shared (and a static) library is built for Unix. So: - - make distclean - ./configure - make - -14. How do I install a shared zlib library on Unix? - - After the above, then: - - make install - - However, many flavors of Unix come with a shared zlib already installed. - Before going to the trouble of compiling a shared version of zlib and - trying to install it, you may want to check if it's already there! If you - can #include , it's there. The -lz option will probably link to - it. You can check the version at the top of zlib.h or with the - ZLIB_VERSION symbol defined in zlib.h . - -15. I have a question about OttoPDF. - - We are not the authors of OttoPDF. The real author is on the OttoPDF web - site: Joel Hainley, jhainley@myndkryme.com. - -16. Can zlib decode Flate data in an Adobe PDF file? - - Yes. See http://www.pdflib.com/ . To modify PDF forms, see - http://sourceforge.net/projects/acroformtool/ . - -17. Why am I getting this "register_frame_info not found" error on Solaris? - - After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib - generates an error such as: - - ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: - symbol __register_frame_info: referenced symbol not found - - The symbol __register_frame_info is not part of zlib, it is generated by - the C compiler (cc or gcc). You must recompile applications using zlib - which have this problem. This problem is specific to Solaris. See - http://www.sunfreeware.com for Solaris versions of zlib and applications - using zlib. - -18. Why does gzip give an error on a file I make with compress/deflate? - - The compress and deflate functions produce data in the zlib format, which - is different and incompatible with the gzip format. The gz* functions in - zlib on the other hand use the gzip format. Both the zlib and gzip formats - use the same compressed data format internally, but have different headers - and trailers around the compressed data. - -19. Ok, so why are there two different formats? - - The gzip format was designed to retain the directory information about a - single file, such as the name and last modification date. The zlib format - on the other hand was designed for in-memory and communication channel - applications, and has a much more compact header and trailer and uses a - faster integrity check than gzip. - -20. Well that's nice, but how do I make a gzip file in memory? - - You can request that deflate write the gzip format instead of the zlib - format using deflateInit2(). You can also request that inflate decode the - gzip format using inflateInit2(). Read zlib.h for more details. - -21. Is zlib thread-safe? - - Yes. However any library routines that zlib uses and any application- - provided memory allocation routines must also be thread-safe. zlib's gz* - functions use stdio library routines, and most of zlib's functions use the - library memory allocation routines by default. zlib's *Init* functions - allow for the application to provide custom memory allocation routines. - - Of course, you should only operate on any given zlib or gzip stream from a - single thread at a time. - -22. Can I use zlib in my commercial application? - - Yes. Please read the license in zlib.h. - -23. Is zlib under the GNU license? - - No. Please read the license in zlib.h. - -24. The license says that altered source versions must be "plainly marked". So - what exactly do I need to do to meet that requirement? - - You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In - particular, the final version number needs to be changed to "f", and an - identification string should be appended to ZLIB_VERSION. Version numbers - x.x.x.f are reserved for modifications to zlib by others than the zlib - maintainers. For example, if the version of the base zlib you are altering - is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and - ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also - update the version strings in deflate.c and inftrees.c. - - For altered source distributions, you should also note the origin and - nature of the changes in zlib.h, as well as in ChangeLog and README, along - with the dates of the alterations. The origin should include at least your - name (or your company's name), and an email address to contact for help or - issues with the library. - - Note that distributing a compiled zlib library along with zlib.h and - zconf.h is also a source distribution, and so you should change - ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes - in zlib.h as you would for a full source distribution. - -25. Will zlib work on a big-endian or little-endian architecture, and can I - exchange compressed data between them? - - Yes and yes. - -26. Will zlib work on a 64-bit machine? - - Yes. It has been tested on 64-bit machines, and has no dependence on any - data types being limited to 32-bits in length. If you have any - difficulties, please provide a complete problem report to zlib@gzip.org - -27. Will zlib decompress data from the PKWare Data Compression Library? - - No. The PKWare DCL uses a completely different compressed data format than - does PKZIP and zlib. However, you can look in zlib's contrib/blast - directory for a possible solution to your problem. - -28. Can I access data randomly in a compressed stream? - - No, not without some preparation. If when compressing you periodically use - Z_FULL_FLUSH, carefully write all the pending data at those points, and - keep an index of those locations, then you can start decompression at those - points. You have to be careful to not use Z_FULL_FLUSH too often, since it - can significantly degrade compression. Alternatively, you can scan a - deflate stream once to generate an index, and then use that index for - random access. See examples/zran.c . - -29. Does zlib work on MVS, OS/390, CICS, etc.? - - It has in the past, but we have not heard of any recent evidence. There - were working ports of zlib 1.1.4 to MVS, but those links no longer work. - If you know of recent, successful applications of zlib on these operating - systems, please let us know. Thanks. - -30. Is there some simpler, easier to read version of inflate I can look at to - understand the deflate format? - - First off, you should read RFC 1951. Second, yes. Look in zlib's - contrib/puff directory. - -31. Does zlib infringe on any patents? - - As far as we know, no. In fact, that was originally the whole point behind - zlib. Look here for some more information: - - http://www.gzip.org/#faq11 - -32. Can zlib work with greater than 4 GB of data? - - Yes. inflate() and deflate() will process any amount of data correctly. - Each call of inflate() or deflate() is limited to input and output chunks - of the maximum value that can be stored in the compiler's "unsigned int" - type, but there is no limit to the number of chunks. Note however that the - strm.total_in and strm_total_out counters may be limited to 4 GB. These - counters are provided as a convenience and are not used internally by - inflate() or deflate(). The application can easily set up its own counters - updated after each call of inflate() or deflate() to count beyond 4 GB. - compress() and uncompress() may be limited to 4 GB, since they operate in a - single call. gzseek() and gztell() may be limited to 4 GB depending on how - zlib is compiled. See the zlibCompileFlags() function in zlib.h. - - The word "may" appears several times above since there is a 4 GB limit only - if the compiler's "long" type is 32 bits. If the compiler's "long" type is - 64 bits, then the limit is 16 exabytes. - -33. Does zlib have any security vulnerabilities? - - The only one that we are aware of is potentially in gzprintf(). If zlib is - compiled to use sprintf() or vsprintf(), then there is no protection - against a buffer overflow of an 8K string space (or other value as set by - gzbuffer()), other than the caller of gzprintf() assuring that the output - will not exceed 8K. On the other hand, if zlib is compiled to use - snprintf() or vsnprintf(), which should normally be the case, then there is - no vulnerability. The ./configure script will display warnings if an - insecure variation of sprintf() will be used by gzprintf(). Also the - zlibCompileFlags() function will return information on what variant of - sprintf() is used by gzprintf(). - - If you don't have snprintf() or vsnprintf() and would like one, you can - find a portable implementation here: - - http://www.ijs.si/software/snprintf/ - - Note that you should be using the most recent version of zlib. Versions - 1.1.3 and before were subject to a double-free vulnerability, and versions - 1.2.1 and 1.2.2 were subject to an access exception when decompressing - invalid compressed data. - -34. Is there a Java version of zlib? - - Probably what you want is to use zlib in Java. zlib is already included - as part of the Java SDK in the java.util.zip package. If you really want - a version of zlib written in the Java language, look on the zlib home - page for links: http://zlib.net/ . - -35. I get this or that compiler or source-code scanner warning when I crank it - up to maximally-pedantic. Can't you guys write proper code? - - Many years ago, we gave up attempting to avoid warnings on every compiler - in the universe. It just got to be a waste of time, and some compilers - were downright silly as well as contradicted each other. So now, we simply - make sure that the code always works. - -36. Valgrind (or some similar memory access checker) says that deflate is - performing a conditional jump that depends on an uninitialized value. - Isn't that a bug? - - No. That is intentional for performance reasons, and the output of deflate - is not affected. This only started showing up recently since zlib 1.2.x - uses malloc() by default for allocations, whereas earlier versions used - calloc(), which zeros out the allocated memory. Even though the code was - correct, versions 1.2.4 and later was changed to not stimulate these - checkers. - -37. Will zlib read the (insert any ancient or arcane format here) compressed - data format? - - Probably not. Look in the comp.compression FAQ for pointers to various - formats and associated software. - -38. How can I encrypt/decrypt zip files with zlib? - - zlib doesn't support encryption. The original PKZIP encryption is very - weak and can be broken with freely available programs. To get strong - encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib - compression. For PKZIP compatible "encryption", look at - http://www.info-zip.org/ - -39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? - - "gzip" is the gzip format, and "deflate" is the zlib format. They should - probably have called the second one "zlib" instead to avoid confusion with - the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 - correctly points to the zlib specification in RFC 1950 for the "deflate" - transfer encoding, there have been reports of servers and browsers that - incorrectly produce or expect raw deflate data per the deflate - specification in RFC 1951, most notably Microsoft. So even though the - "deflate" transfer encoding using the zlib format would be the more - efficient approach (and in fact exactly what the zlib format was designed - for), using the "gzip" transfer encoding is probably more reliable due to - an unfortunate choice of name on the part of the HTTP 1.1 authors. - - Bottom line: use the gzip format for HTTP 1.1 encoding. - -40. Does zlib support the new "Deflate64" format introduced by PKWare? - - No. PKWare has apparently decided to keep that format proprietary, since - they have not documented it as they have previous compression formats. In - any case, the compression improvements are so modest compared to other more - modern approaches, that it's not worth the effort to implement. - -41. I'm having a problem with the zip functions in zlib, can you help? - - There are no zip functions in zlib. You are probably using minizip by - Giles Vollant, which is found in the contrib directory of zlib. It is not - part of zlib. In fact none of the stuff in contrib is part of zlib. The - files in there are not supported by the zlib authors. You need to contact - the authors of the respective contribution for help. - -42. The match.asm code in contrib is under the GNU General Public License. - Since it's part of zlib, doesn't that mean that all of zlib falls under the - GNU GPL? - - No. The files in contrib are not part of zlib. They were contributed by - other authors and are provided as a convenience to the user within the zlib - distribution. Each item in contrib has its own license. - -43. Is zlib subject to export controls? What is its ECCN? - - zlib is not subject to export controls, and so is classified as EAR99. - -44. Can you please sign these lengthy legal documents and fax them back to us - so that we can use your software in our product? - - No. Go away. Shoo. diff --git a/libraries/zlib/INDEX b/libraries/zlib/INDEX deleted file mode 100644 index 2ba06412048..00000000000 --- a/libraries/zlib/INDEX +++ /dev/null @@ -1,68 +0,0 @@ -CMakeLists.txt cmake build file -ChangeLog history of changes -FAQ Frequently Asked Questions about zlib -INDEX this file -Makefile dummy Makefile that tells you to ./configure -Makefile.in template for Unix Makefile -README guess what -configure configure script for Unix -make_vms.com makefile for VMS -test/example.c zlib usages examples for build testing -test/minigzip.c minimal gzip-like functionality for build testing -test/infcover.c inf*.c code coverage for build coverage testing -treebuild.xml XML description of source file dependencies -zconf.h.cmakein zconf.h template for cmake -zconf.h.in zconf.h template for configure -zlib.3 Man page for zlib -zlib.3.pdf Man page in PDF format -zlib.map Linux symbol information -zlib.pc.in Template for pkg-config descriptor -zlib.pc.cmakein zlib.pc template for cmake -zlib2ansi perl script to convert source files for C++ compilation - -amiga/ makefiles for Amiga SAS C -as400/ makefiles for AS/400 -doc/ documentation for formats and algorithms -msdos/ makefiles for MSDOS -nintendods/ makefile for Nintendo DS -old/ makefiles for various architectures and zlib documentation - files that have not yet been updated for zlib 1.2.x -qnx/ makefiles for QNX -watcom/ makefiles for OpenWatcom -win32/ makefiles for Windows - - zlib public header files (required for library use): -zconf.h -zlib.h - - private source files used to build the zlib library: -adler32.c -compress.c -crc32.c -crc32.h -deflate.c -deflate.h -gzclose.c -gzguts.h -gzlib.c -gzread.c -gzwrite.c -infback.c -inffast.c -inffast.h -inffixed.h -inflate.c -inflate.h -inftrees.c -inftrees.h -trees.c -trees.h -uncompr.c -zutil.c -zutil.h - - source files for sample programs -See examples/README.examples - - unsupported contributions by third parties -See contrib/README.contrib diff --git a/libraries/zlib/README b/libraries/zlib/README deleted file mode 100644 index 51106de4753..00000000000 --- a/libraries/zlib/README +++ /dev/null @@ -1,115 +0,0 @@ -ZLIB DATA COMPRESSION LIBRARY - -zlib 1.2.11 is a general purpose data compression library. All the code is -thread safe. The data format used by the zlib library is described by RFCs -(Request for Comments) 1950 to 1952 in the files -http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and -rfc1952 (gzip format). - -All functions of the compression library are documented in the file zlib.h -(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example -of the library is given in the file test/example.c which also tests that -the library is working correctly. Another example is given in the file -test/minigzip.c. The compression library itself is composed of all source -files in the root directory. - -To compile all files and run the test program, follow the instructions given at -the top of Makefile.in. In short "./configure; make test", and if that goes -well, "make install" should work for most flavors of Unix. For Windows, use -one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use -make_vms.com. - -Questions about zlib should be sent to , or to Gilles Vollant - for the Windows DLL version. The zlib home page is -http://zlib.net/ . Before reporting a problem, please check this site to -verify that you have the latest version of zlib; otherwise get the latest -version and check whether the problem still exists or not. - -PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. - -Mark Nelson wrote an article about zlib for the Jan. 1997 -issue of Dr. Dobb's Journal; a copy of the article is available at -http://marknelson.us/1997/01/01/zlib-engine/ . - -The changes made in version 1.2.11 are documented in the file ChangeLog. - -Unsupported third party contributions are provided in directory contrib/ . - -zlib is available in Java using the java.util.zip package, documented at -http://java.sun.com/developer/technicalArticles/Programming/compression/ . - -A Perl interface to zlib written by Paul Marquess is available -at CPAN (Comprehensive Perl Archive Network) sites, including -http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . - -A Python interface to zlib written by A.M. Kuchling is -available in Python 1.5 and later versions, see -http://docs.python.org/library/zlib.html . - -zlib is built into tcl: http://wiki.tcl.tk/4610 . - -An experimental package to read and write files in .zip format, written on top -of zlib by Gilles Vollant , is available in the -contrib/minizip directory of zlib. - - -Notes for some targets: - -- For Windows DLL versions, please see win32/DLL_FAQ.txt - -- For 64-bit Irix, deflate.c must be compiled without any optimization. With - -O, one libpng test fails. The test works in 32 bit mode (with the -n32 - compiler flag). The compiler bug has been reported to SGI. - -- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works - when compiled with cc. - -- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is - necessary to get gzprintf working correctly. This is done by configure. - -- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with - other compilers. Use "make test" to check your compiler. - -- gzdopen is not supported on RISCOS or BEOS. - -- For PalmOs, see http://palmzlib.sourceforge.net/ - - -Acknowledgments: - - The deflate format used by zlib was defined by Phil Katz. The deflate and - zlib specifications were written by L. Peter Deutsch. Thanks to all the - people who reported problems and suggested various improvements in zlib; they - are too numerous to cite here. - -Copyright notice: - - (C) 1995-2017 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - -If you use the zlib library in a product, we would appreciate *not* receiving -lengthy legal documents to sign. The sources are provided for free but without -warranty of any kind. The library has been entirely written by Jean-loup -Gailly and Mark Adler; it does not include third-party code. - -If you redistribute modified sources, we would appreciate that you include in -the file ChangeLog history information documenting your changes. Please read -the FAQ for more information on the distribution of modified source versions. diff --git a/libraries/zlib/adler32.c b/libraries/zlib/adler32.c deleted file mode 100644 index d0be4380a39..00000000000 --- a/libraries/zlib/adler32.c +++ /dev/null @@ -1,186 +0,0 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011, 2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" - -local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); - -#define BASE 65521U /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* use NO_DIVIDE if your processor does not do division in hardware -- - try it both ways to see which is faster */ -#ifdef NO_DIVIDE -/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 - (thank you to John Reiser for pointing this out) */ -# define CHOP(a) \ - do { \ - unsigned long tmp = a >> 16; \ - a &= 0xffffUL; \ - a += (tmp << 4) - tmp; \ - } while (0) -# define MOD28(a) \ - do { \ - CHOP(a); \ - if (a >= BASE) a -= BASE; \ - } while (0) -# define MOD(a) \ - do { \ - CHOP(a); \ - MOD28(a); \ - } while (0) -# define MOD63(a) \ - do { /* this assumes a is not negative */ \ - z_off64_t tmp = a >> 32; \ - a &= 0xffffffffL; \ - a += (tmp << 8) - (tmp << 5) + tmp; \ - tmp = a >> 16; \ - a &= 0xffffL; \ - a += (tmp << 4) - tmp; \ - tmp = a >> 16; \ - a &= 0xffffL; \ - a += (tmp << 4) - tmp; \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -# define MOD28(a) a %= BASE -# define MOD63(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32_z(adler, buf, len) - uLong adler; - const Bytef *buf; - z_size_t len; -{ - unsigned long sum2; - unsigned n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { - adler += buf[0]; - if (adler >= BASE) - adler -= BASE; - sum2 += adler; - if (sum2 >= BASE) - sum2 -= BASE; - return adler | (sum2 << 16); - } - - /* initial Adler-32 value (deferred check for len == 1 speed) */ - if (buf == Z_NULL) - return 1L; - - /* in case short lengths are provided, keep it somewhat fast */ - if (len < 16) { - while (len--) { - adler += *buf++; - sum2 += adler; - } - if (adler >= BASE) - adler -= BASE; - MOD28(sum2); /* only added so many BASE's */ - return adler | (sum2 << 16); - } - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; /* NMAX is divisible by 16 */ - do { - DO16(buf); /* 16 sums unrolled */ - buf += 16; - } while (--n); - MOD(adler); - MOD(sum2); - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - if (len) { /* avoid modulos if none remaining */ - while (len >= 16) { - len -= 16; - DO16(buf); - buf += 16; - } - while (len--) { - adler += *buf++; - sum2 += adler; - } - MOD(adler); - MOD(sum2); - } - - /* return recombined sums */ - return adler | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - return adler32_z(adler, buf, len); -} - -/* ========================================================================= */ -local uLong adler32_combine_(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ - unsigned long sum1; - unsigned long sum2; - unsigned rem; - - /* for negative len, return invalid adler32 as a clue for debugging */ - if (len2 < 0) - return 0xffffffffUL; - - /* the derivation of this formula is left as an exercise for the reader */ - MOD63(len2); /* assumes len2 >= 0 */ - rem = (unsigned)len2; - sum1 = adler1 & 0xffff; - sum2 = rem * sum1; - MOD(sum2); - sum1 += (adler2 & 0xffff) + BASE - 1; - sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; - if (sum1 >= BASE) sum1 -= BASE; - if (sum1 >= BASE) sum1 -= BASE; - if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); - if (sum2 >= BASE) sum2 -= BASE; - return sum1 | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ - return adler32_combine_(adler1, adler2, len2); -} - -uLong ZEXPORT adler32_combine64(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ - return adler32_combine_(adler1, adler2, len2); -} diff --git a/libraries/zlib/algorithm.txt b/libraries/zlib/algorithm.txt deleted file mode 100644 index c97f495020b..00000000000 --- a/libraries/zlib/algorithm.txt +++ /dev/null @@ -1,209 +0,0 @@ -1. Compression algorithm (deflate) - -The deflation algorithm used by gzip (also zip and zlib) is a variation of -LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in -the input data. The second occurrence of a string is replaced by a -pointer to the previous string, in the form of a pair (distance, -length). Distances are limited to 32K bytes, and lengths are limited -to 258 bytes. When a string does not occur anywhere in the previous -32K bytes, it is emitted as a sequence of literal bytes. (In this -description, `string' must be taken as an arbitrary sequence of bytes, -and is not restricted to printable characters.) - -Literals or match lengths are compressed with one Huffman tree, and -match distances are compressed with another tree. The trees are stored -in a compact form at the start of each block. The blocks can have any -size (except that the compressed data for one block must fit in -available memory). A block is terminated when deflate() determines that -it would be useful to start another block with fresh trees. (This is -somewhat similar to the behavior of LZW-based _compress_.) - -Duplicated strings are found using a hash table. All input strings of -length 3 are inserted in the hash table. A hash index is computed for -the next 3 bytes. If the hash chain for this index is not empty, all -strings in the chain are compared with the current input string, and -the longest match is selected. - -The hash chains are searched starting with the most recent strings, to -favor small distances and thus take advantage of the Huffman encoding. -The hash chains are singly linked. There are no deletions from the -hash chains, the algorithm simply discards matches that are too old. - -To avoid a worst-case situation, very long hash chains are arbitrarily -truncated at a certain length, determined by a runtime option (level -parameter of deflateInit). So deflate() does not always find the longest -possible match but generally finds a match which is long enough. - -deflate() also defers the selection of matches with a lazy evaluation -mechanism. After a match of length N has been found, deflate() searches for -a longer match at the next input byte. If a longer match is found, the -previous match is truncated to a length of one (thus producing a single -literal byte) and the process of lazy evaluation begins again. Otherwise, -the original match is kept, and the next match search is attempted only N -steps later. - -The lazy match evaluation is also subject to a runtime parameter. If -the current match is long enough, deflate() reduces the search for a longer -match, thus speeding up the whole process. If compression ratio is more -important than speed, deflate() attempts a complete second search even if -the first match is already long enough. - -The lazy match evaluation is not performed for the fastest compression -modes (level parameter 1 to 3). For these fast modes, new strings -are inserted in the hash table only when no match was found, or -when the match is not too long. This degrades the compression ratio -but saves time since there are both fewer insertions and fewer searches. - - -2. Decompression algorithm (inflate) - -2.1 Introduction - -The key question is how to represent a Huffman code (or any prefix code) so -that you can decode fast. The most important characteristic is that shorter -codes are much more common than longer codes, so pay attention to decoding the -short codes fast, and let the long codes take longer to decode. - -inflate() sets up a first level table that covers some number of bits of -input less than the length of longest code. It gets that many bits from the -stream, and looks it up in the table. The table will tell if the next -code is that many bits or less and how many, and if it is, it will tell -the value, else it will point to the next level table for which inflate() -grabs more bits and tries to decode a longer code. - -How many bits to make the first lookup is a tradeoff between the time it -takes to decode and the time it takes to build the table. If building the -table took no time (and if you had infinite memory), then there would only -be a first level table to cover all the way to the longest code. However, -building the table ends up taking a lot longer for more bits since short -codes are replicated many times in such a table. What inflate() does is -simply to make the number of bits in the first table a variable, and then -to set that variable for the maximum speed. - -For inflate, which has 286 possible codes for the literal/length tree, the size -of the first table is nine bits. Also the distance trees have 30 possible -values, and the size of the first table is six bits. Note that for each of -those cases, the table ended up one bit longer than the ``average'' code -length, i.e. the code length of an approximately flat code which would be a -little more than eight bits for 286 symbols and a little less than five bits -for 30 symbols. - - -2.2 More details on the inflate table lookup - -Ok, you want to know what this cleverly obfuscated inflate tree actually -looks like. You are correct that it's not a Huffman tree. It is simply a -lookup table for the first, let's say, nine bits of a Huffman symbol. The -symbol could be as short as one bit or as long as 15 bits. If a particular -symbol is shorter than nine bits, then that symbol's translation is duplicated -in all those entries that start with that symbol's bits. For example, if the -symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a -symbol is nine bits long, it appears in the table once. - -If the symbol is longer than nine bits, then that entry in the table points -to another similar table for the remaining bits. Again, there are duplicated -entries as needed. The idea is that most of the time the symbol will be short -and there will only be one table look up. (That's whole idea behind data -compression in the first place.) For the less frequent long symbols, there -will be two lookups. If you had a compression method with really long -symbols, you could have as many levels of lookups as is efficient. For -inflate, two is enough. - -So a table entry either points to another table (in which case nine bits in -the above example are gobbled), or it contains the translation for the symbol -and the number of bits to gobble. Then you start again with the next -ungobbled bit. - -You may wonder: why not just have one lookup table for how ever many bits the -longest symbol is? The reason is that if you do that, you end up spending -more time filling in duplicate symbol entries than you do actually decoding. -At least for deflate's output that generates new trees every several 10's of -kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code -would take too long if you're only decoding several thousand symbols. At the -other extreme, you could make a new table for every bit in the code. In fact, -that's essentially a Huffman tree. But then you spend too much time -traversing the tree while decoding, even for short symbols. - -So the number of bits for the first lookup table is a trade of the time to -fill out the table vs. the time spent looking at the second level and above of -the table. - -Here is an example, scaled down: - -The code being decoded, with 10 symbols, from 1 to 6 bits long: - -A: 0 -B: 10 -C: 1100 -D: 11010 -E: 11011 -F: 11100 -G: 11101 -H: 11110 -I: 111110 -J: 111111 - -Let's make the first table three bits long (eight entries): - -000: A,1 -001: A,1 -010: A,1 -011: A,1 -100: B,2 -101: B,2 -110: -> table X (gobble 3 bits) -111: -> table Y (gobble 3 bits) - -Each entry is what the bits decode as and how many bits that is, i.e. how -many bits to gobble. Or the entry points to another table, with the number of -bits to gobble implicit in the size of the table. - -Table X is two bits long since the longest code starting with 110 is five bits -long: - -00: C,1 -01: C,1 -10: D,2 -11: E,2 - -Table Y is three bits long since the longest code starting with 111 is six -bits long: - -000: F,2 -001: F,2 -010: G,2 -011: G,2 -100: H,2 -101: H,2 -110: I,3 -111: J,3 - -So what we have here are three tables with a total of 20 entries that had to -be constructed. That's compared to 64 entries for a single table. Or -compared to 16 entries for a Huffman tree (six two entry tables and one four -entry table). Assuming that the code ideally represents the probability of -the symbols, it takes on the average 1.25 lookups per symbol. That's compared -to one lookup for the single table, or 1.66 lookups per symbol for the -Huffman tree. - -There, I think that gives you a picture of what's going on. For inflate, the -meaning of a particular symbol is often more than just a letter. It can be a -byte (a "literal"), or it can be either a length or a distance which -indicates a base value and a number of bits to fetch after the code that is -added to the base value. Or it might be the special end-of-block code. The -data structures created in inftrees.c try to encode all that information -compactly in the tables. - - -Jean-loup Gailly Mark Adler -jloup@gzip.org madler@alumni.caltech.edu - - -References: - -[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data -Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, -pp. 337-343. - -``DEFLATE Compressed Data Format Specification'' available in -http://tools.ietf.org/html/rfc1951 diff --git a/libraries/zlib/compress.c b/libraries/zlib/compress.c deleted file mode 100644 index e2db404abf8..00000000000 --- a/libraries/zlib/compress.c +++ /dev/null @@ -1,86 +0,0 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ - z_stream stream; - int err; - const uInt max = (uInt)-1; - uLong left; - - left = *destLen; - *destLen = 0; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - stream.next_out = dest; - stream.avail_out = 0; - stream.next_in = (z_const Bytef *)source; - stream.avail_in = 0; - - do { - if (stream.avail_out == 0) { - stream.avail_out = left > (uLong)max ? max : (uInt)left; - left -= stream.avail_out; - } - if (stream.avail_in == 0) { - stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; - sourceLen -= stream.avail_in; - } - err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); - } while (err == Z_OK); - - *destLen = stream.total_out; - deflateEnd(&stream); - return err == Z_STREAM_END ? Z_OK : err; -} - -/* =========================================================================== - */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} - -/* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then - this function needs to be updated. - */ -uLong ZEXPORT compressBound (sourceLen) - uLong sourceLen; -{ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + - (sourceLen >> 25) + 13; -} diff --git a/libraries/zlib/crc32.c b/libraries/zlib/crc32.c deleted file mode 100644 index 9580440c0e6..00000000000 --- a/libraries/zlib/crc32.c +++ /dev/null @@ -1,442 +0,0 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results in about a - * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id$ */ - -/* - Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore - protection on the static variables used to control the first-use generation - of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should - first call get_crc_table() to initialize the tables before allowing more than - one thread to use crc32(). - - DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. - */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -/* Definitions for doing the crc four data bytes at a time. */ -#if !defined(NOBYFOUR) && defined(Z_U4) -# define BYFOUR -#endif -#ifdef BYFOUR - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, z_size_t)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, z_size_t)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -/* Local functions for crc concatenation */ -local unsigned long gf2_matrix_times OF((unsigned long *mat, - unsigned long vec)); -local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); -local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); - - -#ifdef DYNAMIC_CRC_TABLE - -local volatile int crc_table_empty = 1; -local z_crc_t FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const z_crc_t FAR *)); -#endif /* MAKECRCH */ -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - z_crc_t c; - int n, k; - z_crc_t poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static volatile int first = 1; /* flag to limit concurrent making */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* See if another task is already doing this (not thread-safe, but better - than nothing -- significantly reduces duration of vulnerability in - case the advice about DYNAMIC_CRC_TABLE is ignored) */ - if (first) { - first = 0; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0; - for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) - poly |= (z_crc_t)1 << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (z_crc_t)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, - and then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = ZSWAP32(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = ZSWAP32(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - } - else { /* not first */ - /* wait for the other guy to finish (not efficient, but rare) */ - while (crc_table_empty) - ; - } - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const z_crc_t FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const z_crc_t FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", - (unsigned long)(table[n]), - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const z_crc_t FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const z_crc_t FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32_z(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - z_crc_t endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - uInt len; -{ - return crc32_z(crc, buf, len); -} - -#ifdef BYFOUR - -/* - This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit - integer pointer type. This violates the strict aliasing rule, where a - compiler can assume, for optimization purposes, that two pointers to - fundamentally different types won't ever point to the same memory. This can - manifest as a problem only if one of the pointers is written to. This code - only reads from those pointers. So long as this code remains isolated in - this compilation unit, there won't be a problem. For this reason, this code - should not be copied and pasted into a compilation unit in which other code - writes to the buffer that is passed to these routines. - */ - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - register z_crc_t c; - register const z_crc_t FAR *buf4; - - c = (z_crc_t)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *buf4++; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - register z_crc_t c; - register const z_crc_t FAR *buf4; - - c = ZSWAP32((z_crc_t)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(ZSWAP32(c)); -} - -#endif /* BYFOUR */ - -#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ - -/* ========================================================================= */ -local unsigned long gf2_matrix_times(mat, vec) - unsigned long *mat; - unsigned long vec; -{ - unsigned long sum; - - sum = 0; - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - return sum; -} - -/* ========================================================================= */ -local void gf2_matrix_square(square, mat) - unsigned long *square; - unsigned long *mat; -{ - int n; - - for (n = 0; n < GF2_DIM; n++) - square[n] = gf2_matrix_times(mat, mat[n]); -} - -/* ========================================================================= */ -local uLong crc32_combine_(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ - int n; - unsigned long row; - unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ - unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ - - /* degenerate case (also disallow negative lengths) */ - if (len2 <= 0) - return crc1; - - /* put operator for one zero bit in odd */ - odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ - row = 1; - for (n = 1; n < GF2_DIM; n++) { - odd[n] = row; - row <<= 1; - } - - /* put operator for two zero bits in even */ - gf2_matrix_square(even, odd); - - /* put operator for four zero bits in odd */ - gf2_matrix_square(odd, even); - - /* apply len2 zeros to crc1 (first square will put the operator for one - zero byte, eight zero bits, in even) */ - do { - /* apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - if (len2 == 0) - break; - - /* another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - } while (len2 != 0); - - /* return combined crc */ - crc1 ^= crc2; - return crc1; -} - -/* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - return crc32_combine_(crc1, crc2, len2); -} - -uLong ZEXPORT crc32_combine64(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ - return crc32_combine_(crc1, crc2, len2); -} diff --git a/libraries/zlib/crc32.h b/libraries/zlib/crc32.h deleted file mode 100644 index 9e0c7781025..00000000000 --- a/libraries/zlib/crc32.h +++ /dev/null @@ -1,441 +0,0 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const z_crc_t FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; diff --git a/libraries/zlib/deflate.c b/libraries/zlib/deflate.c deleted file mode 100644 index 1ec761448de..00000000000 --- a/libraries/zlib/deflate.c +++ /dev/null @@ -1,2163 +0,0 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://tools.ietf.org/html/rfc1951 - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id$ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local int deflateStateCheck OF((z_streamp strm)); -local void slide_hash OF((deflate_state *s)); -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local block_state deflate_rle OF((deflate_state *s, int flush)); -local block_state deflate_huff OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV -# pragma message("Assembler code may have bugs -- use at your own risk") - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef ZLIB_DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ -#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to UPDATE_HASH are made with consecutive input - * characters, so that a running hash key can be computed from the previous - * key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to INSERT_STRING are made with consecutive input - * characters and the first MIN_MATCH bytes of str are valid (except for - * the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* =========================================================================== - * Slide the hash table when sliding the window down (could be avoided with 32 - * bit values at the expense of memory usage). We slide even when level == 0 to - * keep the hash table consistent if we switch back to level > 0 later. - */ -local void slide_hash(s) - deflate_state *s; -{ - unsigned n, m; - Posf *p; - uInt wsize = s->w_size; - - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m - wsize : NIL); - } while (--n); - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m - wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif -} - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; -#endif - } - if (strm->zfree == (free_func)0) -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zfree = zcfree; -#endif - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - s->status = INIT_STATE; /* to pass state test in deflateReset() */ - - s->wrap = wrap; - s->gzhead = Z_NULL; - s->w_bits = (uInt)windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = (uInt)memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->high_water = 0; /* nothing written to s->window yet */ - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= - * Check for a valid deflate stream state. Return 0 if ok, 1 if not. - */ -local int deflateStateCheck (strm) - z_streamp strm; -{ - deflate_state *s; - if (strm == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) - return 1; - s = strm->state; - if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && -#ifdef GZIP - s->status != GZIP_STATE && -#endif - s->status != EXTRA_STATE && - s->status != NAME_STATE && - s->status != COMMENT_STATE && - s->status != HCRC_STATE && - s->status != BUSY_STATE && - s->status != FINISH_STATE)) - return 1; - return 0; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt str, n; - int wrap; - unsigned avail; - z_const unsigned char *next; - - if (deflateStateCheck(strm) || dictionary == Z_NULL) - return Z_STREAM_ERROR; - s = strm->state; - wrap = s->wrap; - if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) - return Z_STREAM_ERROR; - - /* when using zlib wrappers, compute Adler-32 for provided dictionary */ - if (wrap == 1) - strm->adler = adler32(strm->adler, dictionary, dictLength); - s->wrap = 0; /* avoid computing Adler-32 in read_buf */ - - /* if dictionary would fill window, just replace the history */ - if (dictLength >= s->w_size) { - if (wrap == 0) { /* already empty otherwise */ - CLEAR_HASH(s); - s->strstart = 0; - s->block_start = 0L; - s->insert = 0; - } - dictionary += dictLength - s->w_size; /* use the tail */ - dictLength = s->w_size; - } - - /* insert dictionary into window and hash */ - avail = strm->avail_in; - next = strm->next_in; - strm->avail_in = dictLength; - strm->next_in = (z_const Bytef *)dictionary; - fill_window(s); - while (s->lookahead >= MIN_MATCH) { - str = s->strstart; - n = s->lookahead - (MIN_MATCH-1); - do { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - } while (--n); - s->strstart = str; - s->lookahead = MIN_MATCH-1; - fill_window(s); - } - s->strstart += s->lookahead; - s->block_start = (long)s->strstart; - s->insert = s->lookahead; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - strm->next_in = next; - strm->avail_in = avail; - s->wrap = wrap; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) - z_streamp strm; - Bytef *dictionary; - uInt *dictLength; -{ - deflate_state *s; - uInt len; - - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; - s = strm->state; - len = s->strstart + s->lookahead; - if (len > s->w_size) - len = s->w_size; - if (dictionary != Z_NULL && len) - zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); - if (dictLength != Z_NULL) - *dictLength = len; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) - z_streamp strm; -{ - deflate_state *s; - - if (deflateStateCheck(strm)) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = -#ifdef GZIP - s->wrap == 2 ? GZIP_STATE : -#endif - s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - int ret; - - ret = deflateResetKeep(strm); - if (ret == Z_OK) - lm_init(strm->state); - return ret; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ - if (deflateStateCheck(strm) || strm->state->wrap != 2) - return Z_STREAM_ERROR; - strm->state->gzhead = head; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) - unsigned *pending; - int *bits; - z_streamp strm; -{ - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - if (pending != Z_NULL) - *pending = strm->state->pending; - if (bits != Z_NULL) - *bits = strm->state->bi_valid; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - deflate_state *s; - int put; - - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - s = strm->state; - if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) - return Z_BUF_ERROR; - do { - put = Buf_size - s->bi_valid; - if (put > bits) - put = bits; - s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); - s->bi_valid += put; - _tr_flush_bits(s); - value >>= put; - bits -= put; - } while (bits); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if ((strategy != s->strategy || func != configuration_table[level].func) && - s->high_water) { - /* Flush the last buffer: */ - int err = deflate(strm, Z_BLOCK); - if (err == Z_STREAM_ERROR) - return err; - if (strm->avail_out == 0) - return Z_BUF_ERROR; - } - if (s->level != level) { - if (s->level == 0 && s->matches != 0) { - if (s->matches == 1) - slide_hash(s); - else - CLEAR_HASH(s); - s->matches = 0; - } - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ - deflate_state *s; - - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - s = strm->state; - s->good_match = (uInt)good_length; - s->max_lazy_match = (uInt)max_lazy; - s->nice_match = nice_length; - s->max_chain_length = (uInt)max_chain; - return Z_OK; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong complen, wraplen; - - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; - - /* if can't get parameters, return conservative bound plus zlib wrapper */ - if (deflateStateCheck(strm)) - return complen + 6; - - /* compute wrapper length */ - s = strm->state; - switch (s->wrap) { - case 0: /* raw deflate */ - wraplen = 0; - break; - case 1: /* zlib wrapper */ - wraplen = 6 + (s->strstart ? 4 : 0); - break; -#ifdef GZIP - case 2: /* gzip wrapper */ - wraplen = 18; - if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ - Bytef *str; - if (s->gzhead->extra != Z_NULL) - wraplen += 2 + s->gzhead->extra_len; - str = s->gzhead->name; - if (str != Z_NULL) - do { - wraplen++; - } while (*str++); - str = s->gzhead->comment; - if (str != Z_NULL) - do { - wraplen++; - } while (*str++); - if (s->gzhead->hcrc) - wraplen += 2; - } - break; -#endif - default: /* for compiler happiness */ - wraplen = 6; - } - - /* if not default parameters, return conservative bound */ - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; - - /* default settings: return tight bound for that case */ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + - (sourceLen >> 25) + 13 - 6 + wraplen; -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output, except for - * some deflate_stored() output, goes through this function so some - * applications may wish to modify it to avoid allocating a large - * strm->next_out buffer and copying into it. (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len; - deflate_state *s = strm->state; - - _tr_flush_bits(s); - len = s->pending; - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, s->pending_out, len); - strm->next_out += len; - s->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; - if (s->pending == 0) { - s->pending_out = s->pending_buf; - } -} - -/* =========================================================================== - * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. - */ -#define HCRC_UPDATE(beg) \ - do { \ - if (s->gzhead->hcrc && s->pending > (beg)) \ - strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ - s->pending - (beg)); \ - } while (0) - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->avail_in != 0 && strm->next_in == Z_NULL) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - old_flush = s->last_flush; - s->last_flush = flush; - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Write the header */ - if (s->status == INIT_STATE) { - /* zlib header */ - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - } -#ifdef GZIP - if (s->status == GZIP_STATE) { - /* gzip header */ - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == Z_NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != Z_NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != Z_NULL) { - ulg beg = s->pending; /* start of bytes to update crc */ - uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; - while (s->pending + left > s->pending_buf_size) { - uInt copy = s->pending_buf_size - s->pending; - zmemcpy(s->pending_buf + s->pending, - s->gzhead->extra + s->gzindex, copy); - s->pending = s->pending_buf_size; - HCRC_UPDATE(beg); - s->gzindex += copy; - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - beg = 0; - left -= copy; - } - zmemcpy(s->pending_buf + s->pending, - s->gzhead->extra + s->gzindex, left); - s->pending += left; - HCRC_UPDATE(beg); - s->gzindex = 0; - } - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != Z_NULL) { - ulg beg = s->pending; /* start of bytes to update crc */ - int val; - do { - if (s->pending == s->pending_buf_size) { - HCRC_UPDATE(beg); - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - beg = 0; - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - HCRC_UPDATE(beg); - s->gzindex = 0; - } - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != Z_NULL) { - ulg beg = s->pending; /* start of bytes to update crc */ - int val; - do { - if (s->pending == s->pending_buf_size) { - HCRC_UPDATE(beg); - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - beg = 0; - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - HCRC_UPDATE(beg); - } - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) { - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - } - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - } - s->status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - } -#endif - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = s->level == 0 ? deflate_stored(s, flush) : - s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : - s->strategy == Z_RLE ? deflate_rle(s, flush) : - (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - if (s->lookahead == 0) { - s->strstart = 0; - s->block_start = 0L; - s->insert = 0; - } - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - - status = strm->state->status; - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (deflateStateCheck(source) || dest == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local unsigned read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - zmemcpy(buf, strm->next_in, len); - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, buf, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, buf, len); - } -#endif - strm->next_in += len; - strm->total_in += len; - - return len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->insert = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = (int)s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ - -#else /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for FASTEST only - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#endif /* FASTEST */ - -#ifdef ZLIB_DEBUG - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* ZLIB_DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - unsigned n; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - slide_hash(s); - more += wsize; - } - if (s->strm->avail_in == 0) break; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead + s->insert >= MIN_MATCH) { - uInt str = s->strstart - s->insert; - s->ins_h = s->window[str]; - UPDATE_HASH(s, s->ins_h, s->window[str + 1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - while (s->insert) { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - s->insert--; - if (s->lookahead + s->insert < MIN_MATCH) - break; - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ - if (s->high_water < s->window_size) { - ulg curr = s->strstart + (ulg)(s->lookahead); - ulg init; - - if (s->high_water < curr) { - /* Previous high water mark below current data -- zero WIN_INIT - * bytes or up to end of window, whichever is less. - */ - init = s->window_size - curr; - if (init > WIN_INIT) - init = WIN_INIT; - zmemzero(s->window + curr, (unsigned)init); - s->high_water = curr + init; - } - else if (s->high_water < (ulg)curr + WIN_INIT) { - /* High water mark at or above current data, but below current data - * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up - * to end of window, whichever is less. - */ - init = (ulg)curr + WIN_INIT - s->high_water; - if (init > s->window_size - s->high_water) - init = s->window_size - s->high_water; - zmemzero(s->window + s->high_water, (unsigned)init); - s->high_water += init; - } - } - - Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, - "not enough room for search"); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, last) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (last)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, last) { \ - FLUSH_BLOCK_ONLY(s, last); \ - if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ -} - -/* Maximum stored block length in deflate format (not including header). */ -#define MAX_STORED 65535 - -/* Minimum of a and b. */ -#define MIN(a, b) ((a) > (b) ? (b) : (a)) - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * - * In case deflateParams() is used to later switch to a non-zero compression - * level, s->matches (otherwise unused when storing) keeps track of the number - * of hash table slides to perform. If s->matches is 1, then one hash table - * slide will be done when switching. If s->matches is 2, the maximum value - * allowed here, then the hash table will be cleared, since two or more slides - * is the same as a clear. - * - * deflate_stored() is written to minimize the number of times an input byte is - * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Smallest worthy block size when not flushing or finishing. By default - * this is 32K. This can be as small as 507 bytes for memLevel == 1. For - * large input and output buffers, the stored block size will be larger. - */ - unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); - - /* Copy as many min_block or larger stored blocks directly to next_out as - * possible. If flushing, copy the remaining available input to next_out as - * stored blocks, if there is enough space. - */ - unsigned len, left, have, last = 0; - unsigned used = s->strm->avail_in; - do { - /* Set len to the maximum size block that we can copy directly with the - * available input data and output space. Set left to how much of that - * would be copied from what's left in the window. - */ - len = MAX_STORED; /* maximum deflate stored block length */ - have = (s->bi_valid + 42) >> 3; /* number of header bytes */ - if (s->strm->avail_out < have) /* need room for header */ - break; - /* maximum stored block length that will fit in avail_out: */ - have = s->strm->avail_out - have; - left = s->strstart - s->block_start; /* bytes left in window */ - if (len > (ulg)left + s->strm->avail_in) - len = left + s->strm->avail_in; /* limit len to the input */ - if (len > have) - len = have; /* limit len to the output */ - - /* If the stored block would be less than min_block in length, or if - * unable to copy all of the available input when flushing, then try - * copying to the window and the pending buffer instead. Also don't - * write an empty block when flushing -- deflate() does that. - */ - if (len < min_block && ((len == 0 && flush != Z_FINISH) || - flush == Z_NO_FLUSH || - len != left + s->strm->avail_in)) - break; - - /* Make a dummy stored block in pending to get the header bytes, - * including any pending bits. This also updates the debugging counts. - */ - last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; - _tr_stored_block(s, (char *)0, 0L, last); - - /* Replace the lengths in the dummy stored block with len. */ - s->pending_buf[s->pending - 4] = len; - s->pending_buf[s->pending - 3] = len >> 8; - s->pending_buf[s->pending - 2] = ~len; - s->pending_buf[s->pending - 1] = ~len >> 8; - - /* Write the stored block header bytes. */ - flush_pending(s->strm); - -#ifdef ZLIB_DEBUG - /* Update debugging counts for the data about to be copied. */ - s->compressed_len += len << 3; - s->bits_sent += len << 3; -#endif - - /* Copy uncompressed bytes from the window to next_out. */ - if (left) { - if (left > len) - left = len; - zmemcpy(s->strm->next_out, s->window + s->block_start, left); - s->strm->next_out += left; - s->strm->avail_out -= left; - s->strm->total_out += left; - s->block_start += left; - len -= left; - } - - /* Copy uncompressed bytes directly from next_in to next_out, updating - * the check value. - */ - if (len) { - read_buf(s->strm, s->strm->next_out, len); - s->strm->next_out += len; - s->strm->avail_out -= len; - s->strm->total_out += len; - } - } while (last == 0); - - /* Update the sliding window with the last s->w_size bytes of the copied - * data, or append all of the copied data to the existing window if less - * than s->w_size bytes were copied. Also update the number of bytes to - * insert in the hash tables, in the event that deflateParams() switches to - * a non-zero compression level. - */ - used -= s->strm->avail_in; /* number of input bytes directly copied */ - if (used) { - /* If any input was used, then no unused input remains in the window, - * therefore s->block_start == s->strstart. - */ - if (used >= s->w_size) { /* supplant the previous history */ - s->matches = 2; /* clear hash */ - zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); - s->strstart = s->w_size; - } - else { - if (s->window_size - s->strstart <= used) { - /* Slide the window down. */ - s->strstart -= s->w_size; - zmemcpy(s->window, s->window + s->w_size, s->strstart); - if (s->matches < 2) - s->matches++; /* add a pending slide_hash() */ - } - zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); - s->strstart += used; - } - s->block_start = s->strstart; - s->insert += MIN(used, s->w_size - s->insert); - } - if (s->high_water < s->strstart) - s->high_water = s->strstart; - - /* If the last block was written to next_out, then done. */ - if (last) - return finish_done; - - /* If flushing and all input has been consumed, then done. */ - if (flush != Z_NO_FLUSH && flush != Z_FINISH && - s->strm->avail_in == 0 && (long)s->strstart == s->block_start) - return block_done; - - /* Fill the window with any remaining input. */ - have = s->window_size - s->strstart - 1; - if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { - /* Slide the window down. */ - s->block_start -= s->w_size; - s->strstart -= s->w_size; - zmemcpy(s->window, s->window + s->w_size, s->strstart); - if (s->matches < 2) - s->matches++; /* add a pending slide_hash() */ - have += s->w_size; /* more space now */ - } - if (have > s->strm->avail_in) - have = s->strm->avail_in; - if (have) { - read_buf(s->strm, s->window + s->strstart, have); - s->strstart += have; - } - if (s->high_water < s->strstart) - s->high_water = s->strstart; - - /* There was not enough avail_out to write a complete worthy or flushed - * stored block to next_out. Write a stored block to pending instead, if we - * have enough input for a worthy block, or if flushing and there is enough - * room for the remaining input as a stored block in the pending buffer. - */ - have = (s->bi_valid + 42) >> 3; /* number of header bytes */ - /* maximum stored block length that will fit in pending: */ - have = MIN(s->pending_buf_size - have, MAX_STORED); - min_block = MIN(have, s->w_size); - left = s->strstart - s->block_start; - if (left >= min_block || - ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && - s->strm->avail_in == 0 && left <= have)) { - len = MIN(left, have); - last = flush == Z_FINISH && s->strm->avail_in == 0 && - len == left ? 1 : 0; - _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); - s->block_start += len; - flush_pending(s->strm); - } - - /* We've done all we can with the available input and output. */ - return last ? finish_started : need_more; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = NIL; - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s->match_length = longest_match (s, hash_head); - /* longest_match() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = NIL; - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s->match_length = longest_match (s, hash_head); - /* longest_match() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} -#endif /* FASTEST */ - -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - uInt prev; /* byte at distance one to match */ - Bytef *scan, *strend; /* scan goes up to strend for length of run */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest run, plus one for the unrolled loop. - */ - if (s->lookahead <= MAX_MATCH) { - fill_window(s); - if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - s->match_length = 0; - if (s->lookahead >= MIN_MATCH && s->strstart > 0) { - scan = s->window + s->strstart - 1; - prev = *scan; - if (prev == *++scan && prev == *++scan && prev == *++scan) { - strend = s->window + s->strstart + MAX_MATCH; - do { - } while (prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - scan < strend); - s->match_length = MAX_MATCH - (uInt)(strend - scan); - if (s->match_length > s->lookahead) - s->match_length = s->lookahead; - } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->strstart - 1, s->match_length); - - _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - s->strstart += s->match_length; - s->match_length = 0; - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} - -/* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ -local block_state deflate_huff(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we have a literal to write. */ - if (s->lookahead == 0) { - fill_window(s); - if (s->lookahead == 0) { - if (flush == Z_NO_FLUSH) - return need_more; - break; /* flush the current block */ - } - } - - /* Output a literal byte */ - s->match_length = 0; - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} diff --git a/libraries/zlib/deflate.h b/libraries/zlib/deflate.h deleted file mode 100644 index 23ecdd312bc..00000000000 --- a/libraries/zlib/deflate.h +++ /dev/null @@ -1,349 +0,0 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2016 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define Buf_size 16 -/* size of bit buffer in bi_buf */ - -#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ -#ifdef GZIP -# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ -#endif -#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ -#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ -#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ -#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ -#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ -#define FINISH_STATE 666 /* stream complete */ -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - const static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - ulg pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - gz_headerp gzhead; /* gzip header information to write */ - ulg gzindex; /* where in extra, name, or comment */ - Byte method; /* can only be DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to suppress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - uInt insert; /* bytes at end of window left to insert */ - -#ifdef ZLIB_DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - - ulg high_water; - /* High water mark offset in window for initialized bytes -- bytes above - * this are set to zero in order to avoid memory check warnings when - * longest match routines access bytes past the input. This is then - * updated to the new high water mark. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - -#define WIN_INIT MAX_MATCH -/* Number of bytes after end of data in window to initialize in order to avoid - memory checker errors from longest match routines */ - - /* in trees.c */ -void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); -int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); -void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef ZLIB_DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch ZLIB_INTERNAL _length_code[]; - extern uch ZLIB_INTERNAL _dist_code[]; -#else - extern const uch ZLIB_INTERNAL _length_code[]; - extern const uch ZLIB_INTERNAL _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (uch)(length); \ - ush dist = (ush)(distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ diff --git a/libraries/zlib/example.c b/libraries/zlib/example.c deleted file mode 100644 index 604736f15f6..00000000000 --- a/libraries/zlib/example.c +++ /dev/null @@ -1,565 +0,0 @@ -/* example.c -- usage example of the zlib compression library - * Copyright (C) 1995-2006 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zlib.h" -#include - -#ifdef STDC -# include -# include -#endif - -#if defined(VMS) || defined(RISCOS) -# define TESTFILE "foo-gz" -#else -# define TESTFILE "foo.gz" -#endif - -#define CHECK_ERR(err, msg) { \ - if (err != Z_OK) { \ - fprintf(stderr, "%s error: %d\n", msg, err); \ - exit(1); \ - } \ -} - -const char hello[] = "hello, hello!"; -/* "hello world" would be more standard, but the repeated "hello" - * stresses the compression code better, sorry... - */ - -const char dictionary[] = "hello"; -uLong dictId; /* Adler32 value of the dictionary */ - -void test_compress OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_gzio OF((const char *fname, - Byte *uncompr, uLong uncomprLen)); -void test_deflate OF((Byte *compr, uLong comprLen)); -void test_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_large_deflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_large_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_flush OF((Byte *compr, uLong *comprLen)); -void test_sync OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_dict_deflate OF((Byte *compr, uLong comprLen)); -void test_dict_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -int main OF((int argc, char *argv[])); - -/* =========================================================================== - * Test compress() and uncompress() - */ -void test_compress(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - uLong len = (uLong)strlen(hello)+1; - - err = compress(compr, &comprLen, (const Bytef*)hello, len); - CHECK_ERR(err, "compress"); - - strcpy((char*)uncompr, "garbage"); - - err = uncompress(uncompr, &uncomprLen, compr, comprLen); - CHECK_ERR(err, "uncompress"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad uncompress\n"); - exit(1); - } else { - printf("uncompress(): %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Test read/write of .gz files - */ -void test_gzio(fname, uncompr, uncomprLen) - const char *fname; /* compressed file name */ - Byte *uncompr; - uLong uncomprLen; -{ -#ifdef NO_GZCOMPRESS - fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); -#else - int err; - int len = (int)strlen(hello)+1; - gzFile file; - z_off_t pos; - - file = gzopen(fname, "wb"); - if (file == NULL) { - fprintf(stderr, "gzopen error\n"); - exit(1); - } - gzputc(file, 'h'); - if (gzputs(file, "ello") != 4) { - fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); - exit(1); - } - if (gzprintf(file, ", %s!", "hello") != 8) { - fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); - exit(1); - } - gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ - gzclose(file); - - file = gzopen(fname, "rb"); - if (file == NULL) { - fprintf(stderr, "gzopen error\n"); - exit(1); - } - strcpy((char*)uncompr, "garbage"); - - if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { - fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); - exit(1); - } - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); - exit(1); - } else { - printf("gzread(): %s\n", (char*)uncompr); - } - - pos = gzseek(file, -8L, SEEK_CUR); - if (pos != 6 || gztell(file) != pos) { - fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", - (long)pos, (long)gztell(file)); - exit(1); - } - - if (gzgetc(file) != ' ') { - fprintf(stderr, "gzgetc error\n"); - exit(1); - } - - if (gzungetc(' ', file) != ' ') { - fprintf(stderr, "gzungetc error\n"); - exit(1); - } - - gzgets(file, (char*)uncompr, (int)uncomprLen); - if (strlen((char*)uncompr) != 7) { /* " hello!" */ - fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); - exit(1); - } - if (strcmp((char*)uncompr, hello + 6)) { - fprintf(stderr, "bad gzgets after gzseek\n"); - exit(1); - } else { - printf("gzgets() after gzseek: %s\n", (char*)uncompr); - } - - gzclose(file); -#endif -} - -/* =========================================================================== - * Test deflate() with small buffers - */ -void test_deflate(compr, comprLen) - Byte *compr; - uLong comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - uLong len = (uLong)strlen(hello)+1; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_in = (Bytef*)hello; - c_stream.next_out = compr; - - while (c_stream.total_in != len && c_stream.total_out < comprLen) { - c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - } - /* Finish the stream, still forcing small buffers: */ - for (;;) { - c_stream.avail_out = 1; - err = deflate(&c_stream, Z_FINISH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "deflate"); - } - - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with small buffers - */ -void test_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = 0; - d_stream.next_out = uncompr; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { - d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "inflate"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad inflate\n"); - exit(1); - } else { - printf("inflate(): %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Test deflate() with large buffers and dynamic change of compression level - */ -void test_large_deflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_BEST_SPEED); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_out = compr; - c_stream.avail_out = (uInt)comprLen; - - /* At this point, uncompr is still mostly zeroes, so it should compress - * very well: - */ - c_stream.next_in = uncompr; - c_stream.avail_in = (uInt)uncomprLen; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - if (c_stream.avail_in != 0) { - fprintf(stderr, "deflate not greedy\n"); - exit(1); - } - - /* Feed in already compressed data and switch to no compression: */ - deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); - c_stream.next_in = compr; - c_stream.avail_in = (uInt)comprLen/2; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - - /* Switch back to compressing mode: */ - deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); - c_stream.next_in = uncompr; - c_stream.avail_in = (uInt)uncomprLen; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - fprintf(stderr, "deflate should report Z_STREAM_END\n"); - exit(1); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with large buffers - */ -void test_large_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = (uInt)comprLen; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - for (;;) { - d_stream.next_out = uncompr; /* discard the output */ - d_stream.avail_out = (uInt)uncomprLen; - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "large inflate"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (d_stream.total_out != 2*uncomprLen + comprLen/2) { - fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); - exit(1); - } else { - printf("large_inflate(): OK\n"); - } -} - -/* =========================================================================== - * Test deflate() with full flush - */ -void test_flush(compr, comprLen) - Byte *compr; - uLong *comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - uInt len = (uInt)strlen(hello)+1; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_in = (Bytef*)hello; - c_stream.next_out = compr; - c_stream.avail_in = 3; - c_stream.avail_out = (uInt)*comprLen; - err = deflate(&c_stream, Z_FULL_FLUSH); - CHECK_ERR(err, "deflate"); - - compr[3]++; /* force an error in first compressed block */ - c_stream.avail_in = len - 3; - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - CHECK_ERR(err, "deflate"); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); - - *comprLen = c_stream.total_out; -} - -/* =========================================================================== - * Test inflateSync() - */ -void test_sync(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = 2; /* just read the zlib header */ - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - d_stream.next_out = uncompr; - d_stream.avail_out = (uInt)uncomprLen; - - inflate(&d_stream, Z_NO_FLUSH); - CHECK_ERR(err, "inflate"); - - d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ - err = inflateSync(&d_stream); /* but skip the damaged part */ - CHECK_ERR(err, "inflateSync"); - - err = inflate(&d_stream, Z_FINISH); - if (err != Z_DATA_ERROR) { - fprintf(stderr, "inflate should report DATA_ERROR\n"); - /* Because of incorrect adler32 */ - exit(1); - } - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - printf("after inflateSync(): hel%s\n", (char *)uncompr); -} - -/* =========================================================================== - * Test deflate() with preset dictionary - */ -void test_dict_deflate(compr, comprLen) - Byte *compr; - uLong comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_BEST_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - err = deflateSetDictionary(&c_stream, - (const Bytef*)dictionary, sizeof(dictionary)); - CHECK_ERR(err, "deflateSetDictionary"); - - dictId = c_stream.adler; - c_stream.next_out = compr; - c_stream.avail_out = (uInt)comprLen; - - c_stream.next_in = (Bytef*)hello; - c_stream.avail_in = (uInt)strlen(hello)+1; - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - fprintf(stderr, "deflate should report Z_STREAM_END\n"); - exit(1); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with a preset dictionary - */ -void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = (uInt)comprLen; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - d_stream.next_out = uncompr; - d_stream.avail_out = (uInt)uncomprLen; - - for (;;) { - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - if (err == Z_NEED_DICT) { - if (d_stream.adler != dictId) { - fprintf(stderr, "unexpected dictionary"); - exit(1); - } - err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, - sizeof(dictionary)); - } - CHECK_ERR(err, "inflate with dict"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad inflate with dict\n"); - exit(1); - } else { - printf("inflate with dictionary: %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Usage: example [output.gz [input.gz]] - */ - -int main(argc, argv) - int argc; - char *argv[]; -{ - Byte *compr, *uncompr; - uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ - uLong uncomprLen = comprLen; - static const char* myVersion = ZLIB_VERSION; - - if (zlibVersion()[0] != myVersion[0]) { - fprintf(stderr, "incompatible zlib version\n"); - exit(1); - - } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { - fprintf(stderr, "warning: different zlib version\n"); - } - - printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", - ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); - - compr = (Byte*)calloc((uInt)comprLen, 1); - uncompr = (Byte*)calloc((uInt)uncomprLen, 1); - /* compr and uncompr are cleared to avoid reading uninitialized - * data and to ensure that uncompr compresses well. - */ - if (compr == Z_NULL || uncompr == Z_NULL) { - printf("out of memory\n"); - exit(1); - } - test_compress(compr, comprLen, uncompr, uncomprLen); - - test_gzio((argc > 1 ? argv[1] : TESTFILE), - uncompr, uncomprLen); - - test_deflate(compr, comprLen); - test_inflate(compr, comprLen, uncompr, uncomprLen); - - test_large_deflate(compr, comprLen, uncompr, uncomprLen); - test_large_inflate(compr, comprLen, uncompr, uncomprLen); - - test_flush(compr, &comprLen); - test_sync(compr, comprLen, uncompr, uncomprLen); - comprLen = uncomprLen; - - test_dict_deflate(compr, comprLen); - test_dict_inflate(compr, comprLen, uncompr, uncomprLen); - - free(compr); - free(uncompr); - - return 0; -} diff --git a/libraries/zlib/gzguts.h b/libraries/zlib/gzguts.h deleted file mode 100644 index 990a4d25149..00000000000 --- a/libraries/zlib/gzguts.h +++ /dev/null @@ -1,218 +0,0 @@ -/* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef _LARGEFILE64_SOURCE -# ifndef _LARGEFILE_SOURCE -# define _LARGEFILE_SOURCE 1 -# endif -# ifdef _FILE_OFFSET_BITS -# undef _FILE_OFFSET_BITS -# endif -#endif - -#ifdef HAVE_HIDDEN -# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) -#else -# define ZLIB_INTERNAL -#endif - -#include -#include "zlib.h" -#ifdef STDC -# include -# include -# include -#endif - -#ifndef _POSIX_SOURCE -# define _POSIX_SOURCE -#endif -#include - -#ifdef _WIN32 -# include -#endif - -#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) -# include -#endif - -#if defined(_WIN32) || defined(__CYGWIN__) -# define WIDECHAR -#endif - -#ifdef WINAPI_FAMILY -# define open _open -# define read _read -# define write _write -# define close _close -#endif - -#ifdef NO_DEFLATE /* for compatibility with old definition */ -# define NO_GZCOMPRESS -#endif - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif - -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif - -#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif - -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS -/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 -/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) -# define vsnprintf _vsnprintf -# endif -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -# ifdef VMS -# define NO_vsnprintf -# endif -# ifdef __OS400__ -# define NO_vsnprintf -# endif -# ifdef __MVS__ -# define NO_vsnprintf -# endif -#endif - -/* unlike snprintf (which is required in C99), _snprintf does not guarantee - null termination of the result -- however this is only used in gzlib.c where - the result is assured to fit in the space provided */ -#if defined(_MSC_VER) && _MSC_VER < 1900 -# define snprintf _snprintf -#endif - -#ifndef local -# define local static -#endif -/* since "static" is used to mean two completely different things in C, we - define "local" for the non-static meaning of "static", for readability - (compile with -Dlocal if your debugger can't find static symbols) */ - -/* gz* functions always use library allocation functions */ -#ifndef STDC - extern voidp malloc OF((uInt size)); - extern void free OF((voidpf ptr)); -#endif - -/* get errno and strerror definition */ -#if defined UNDER_CE -# include -# define zstrerror() gz_strwinerror((DWORD)GetLastError()) -#else -# ifndef NO_STRERROR -# include -# define zstrerror() strerror(errno) -# else -# define zstrerror() "stdio error (consult errno)" -# endif -#endif - -/* provide prototypes for these when building zlib without LFS */ -#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); -#endif - -/* default memLevel */ -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif - -/* default i/o buffer size -- double this for output when reading (this and - twice this must be able to fit in an unsigned type) */ -#define GZBUFSIZE 8192 - -/* gzip modes, also provide a little integrity check on the passed structure */ -#define GZ_NONE 0 -#define GZ_READ 7247 -#define GZ_WRITE 31153 -#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ - -/* values for gz_state how */ -#define LOOK 0 /* look for a gzip header */ -#define COPY 1 /* copy input directly */ -#define GZIP 2 /* decompress a gzip stream */ - -/* internal gzip file state data structure */ -typedef struct { - /* exposed contents for gzgetc() macro */ - struct gzFile_s x; /* "x" for exposed */ - /* x.have: number of bytes available at x.next */ - /* x.next: next output data to deliver or write */ - /* x.pos: current position in uncompressed data */ - /* used for both reading and writing */ - int mode; /* see gzip modes above */ - int fd; /* file descriptor */ - char *path; /* path or fd for error messages */ - unsigned size; /* buffer size, zero if not allocated yet */ - unsigned want; /* requested buffer size, default is GZBUFSIZE */ - unsigned char *in; /* input buffer (double-sized when writing) */ - unsigned char *out; /* output buffer (double-sized when reading) */ - int direct; /* 0 if processing gzip, 1 if transparent */ - /* just for reading */ - int how; /* 0: get header, 1: copy, 2: decompress */ - z_off64_t start; /* where the gzip data started, for rewinding */ - int eof; /* true if end of input file reached */ - int past; /* true if read requested past end */ - /* just for writing */ - int level; /* compression level */ - int strategy; /* compression strategy */ - /* seek request */ - z_off64_t skip; /* amount to skip (already rewound if backwards) */ - int seek; /* true if seek request pending */ - /* error information */ - int err; /* error code */ - char *msg; /* error message */ - /* zlib inflate or deflate stream */ - z_stream strm; /* stream structure in-place (not a pointer) */ -} gz_state; -typedef gz_state FAR *gz_statep; - -/* shared functions */ -void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); -#if defined UNDER_CE -char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); -#endif - -/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t - value -- needed when comparing unsigned to z_off64_t, which is signed - (possible z_off64_t types off_t, off64_t, and long are all signed) */ -#ifdef INT_MAX -# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) -#else -unsigned ZLIB_INTERNAL gz_intmax OF((void)); -# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) -#endif diff --git a/libraries/zlib/infback.c b/libraries/zlib/infback.c deleted file mode 100644 index 59679ecbfc5..00000000000 --- a/libraries/zlib/infback.c +++ /dev/null @@ -1,640 +0,0 @@ -/* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - This code is largely copied from inflate.c. Normally either infback.o or - inflate.o would be linked into an application--not both. The interface - with inffast.c is retained so that optimized assembler-coded versions of - inflate_fast() can be used with either inflate.c or infback.c. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - -/* - strm provides memory allocation functions in zalloc and zfree, or - Z_NULL to use the library memory allocation functions. - - windowBits is in the range 8..15, and window is a user-supplied - window and output buffer that is 2**windowBits bytes. - */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL || window == Z_NULL || - windowBits < 8 || windowBits > 15) - return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; -#endif - } - if (strm->zfree == (free_func)0) -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zfree = zcfree; -#endif - state = (struct inflate_state FAR *)ZALLOC(strm, 1, - sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->dmax = 32768U; - state->wbits = (uInt)windowBits; - state->wsize = 1U << windowBits; - state->window = window; - state->wnext = 0; - state->whave = 0; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -/* Macros for inflateBack(): */ - -/* Load returned state from inflate_fast() */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Set state from registers for inflate_fast() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Assure that some input is available. If input is requested, but denied, - then return a Z_BUF_ERROR from inflateBack(). */ -#define PULL() \ - do { \ - if (have == 0) { \ - have = in(in_desc, &next); \ - if (have == 0) { \ - next = Z_NULL; \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflateBack() - with an error if there is no input available. */ -#define PULLBYTE() \ - do { \ - PULL(); \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflateBack() with - an error. */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Assure that some output space is available, by writing out the window - if it's full. If the write fails, return from inflateBack() with a - Z_BUF_ERROR. */ -#define ROOM() \ - do { \ - if (left == 0) { \ - put = state->window; \ - left = state->wsize; \ - state->whave = left; \ - if (out(out_desc, put, left)) { \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* - strm provides the memory allocation functions and window buffer on input, - and provides information on the unused input on return. For Z_DATA_ERROR - returns, strm will also provide an error message. - - in() and out() are the call-back input and output functions. When - inflateBack() needs more input, it calls in(). When inflateBack() has - filled the window with output, or when it completes with data in the - window, it calls out() to write out the data. The application must not - change the provided input until in() is called again or inflateBack() - returns. The application must not change the window/output buffer until - inflateBack() returns. - - in() and out() are called with a descriptor parameter provided in the - inflateBack() call. This parameter can be a structure that provides the - information required to do the read or write, as well as accumulated - information on the input and output such as totals and check values. - - in() should return zero on failure. out() should return non-zero on - failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() - returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format - error, or Z_MEM_ERROR if it could not allocate memory for the state. - inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is Z_NULL or the state was not initialized. - */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ - struct inflate_state FAR *state; - z_const unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code here; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Check that the strm exists and that the state was initialized */ - if (strm == Z_NULL || strm->state == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* Reset the state */ - strm->msg = Z_NULL; - state->mode = TYPE; - state->last = 0; - state->whave = 0; - next = strm->next_in; - have = next != Z_NULL ? strm->avail_in : 0; - hold = 0; - bits = 0; - put = state->window; - left = state->wsize; - - /* Inflate until end of block marked as last */ - for (;;) - switch (state->mode) { - case TYPE: - /* determine and dispatch block type */ - if (state->last) { - BYTEBITS(); - state->mode = DONE; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - - case STORED: - /* get and verify stored block length */ - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - - /* copy stored block from input to output */ - while (state->length != 0) { - copy = state->length; - PULL(); - ROOM(); - if (copy > have) copy = have; - if (copy > left) copy = left; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - - case TABLE: - /* get dynamic table entries descriptor */ - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - - /* get code length code lengths (not a typo) */ - state->have = 0; - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - - /* get length and distance code code lengths */ - state->have = 0; - while (state->have < state->nlen + state->ndist) { - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.val < 16) { - DROPBITS(here.bits); - state->lens[state->have++] = here.val; - } - else { - if (here.val == 16) { - NEEDBITS(here.bits + 2); - DROPBITS(here.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = (unsigned)(state->lens[state->have - 1]); - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (here.val == 17) { - NEEDBITS(here.bits + 3); - DROPBITS(here.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(here.bits + 7); - DROPBITS(here.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* check for end-of-block code (better have one) */ - if (state->lens[256] == 0) { - strm->msg = (char *)"invalid code -- missing end-of-block"; - state->mode = BAD; - break; - } - - /* build code tables -- note: do not change the lenbits or distbits - values here (9 and 6) without reading the comments in inftrees.h - concerning the ENOUGH constants, which depend on those values */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= 6 && left >= 258) { - RESTORE(); - if (state->whave < state->wsize) - state->whave = state->wsize - left; - inflate_fast(strm, state->wsize); - LOAD(); - break; - } - - /* get a literal, length, or end-of-block code */ - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.op && (here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(here.bits); - state->length = (unsigned)here.val; - - /* process literal */ - if (here.op == 0) { - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - ROOM(); - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - } - - /* process end of block */ - if (here.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - - /* invalid code */ - if (here.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - - /* length code -- get extra bits, if any */ - state->extra = (unsigned)(here.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - - /* get distance code */ - for (;;) { - here = state->distcode[BITS(state->distbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if ((here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(here.bits); - if (here.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)here.val; - - /* get distance extra bits, if any */ - state->extra = (unsigned)(here.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->wsize - (state->whave < state->wsize ? - left : 0)) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - - /* copy match from window to output */ - do { - ROOM(); - copy = state->wsize - state->offset; - if (copy < left) { - from = put + copy; - copy = left - copy; - } - else { - from = put - state->offset; - copy = left; - } - if (copy > state->length) copy = state->length; - state->length -= copy; - left -= copy; - do { - *put++ = *from++; - } while (--copy); - } while (state->length != 0); - break; - - case DONE: - /* inflate stream terminated properly -- write leftover output */ - ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } - goto inf_leave; - - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - - default: /* can't happen, but makes compilers happy */ - ret = Z_STREAM_ERROR; - goto inf_leave; - } - - /* Return unused input */ - inf_leave: - strm->next_in = next; - strm->avail_in = have; - return ret; -} - -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} diff --git a/libraries/zlib/inffast.c b/libraries/zlib/inffast.c deleted file mode 100644 index 0dbd1dbc09f..00000000000 --- a/libraries/zlib/inffast.c +++ /dev/null @@ -1,323 +0,0 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2017 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef ASMINF -# pragma message("Assembler code may have bugs -- use at your own risk") -#else - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void ZLIB_INTERNAL inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - z_const unsigned char FAR *in; /* local strm->next_in */ - z_const unsigned char FAR *last; /* have enough input while in < last */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ -#ifdef INFLATE_STRICT - unsigned dmax; /* maximum distance from zlib header */ -#endif - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned wnext; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code here; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in; - last = in + (strm->avail_in - 5); - out = strm->next_out; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -#ifdef INFLATE_STRICT - dmax = state->dmax; -#endif - wsize = state->wsize; - whave = state->whave; - wnext = state->wnext; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - hold += (unsigned long)(*in++) << bits; - bits += 8; - } - here = lcode[hold & lmask]; - dolen: - op = (unsigned)(here.bits); - hold >>= op; - bits -= op; - op = (unsigned)(here.op); - if (op == 0) { /* literal */ - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - *out++ = (unsigned char)(here.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(here.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - hold += (unsigned long)(*in++) << bits; - bits += 8; - } - here = dcode[hold & dmask]; - dodist: - op = (unsigned)(here.bits); - hold >>= op; - bits -= op; - op = (unsigned)(here.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(here.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); -#ifdef INFLATE_STRICT - if (dist > dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - if (state->sane) { - strm->msg = - (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - if (len <= op - whave) { - do { - *out++ = 0; - } while (--len); - continue; - } - len -= op - whave; - do { - *out++ = 0; - } while (--op > whave); - if (op == 0) { - from = out - dist; - do { - *out++ = *from++; - } while (--len); - continue; - } -#endif - } - from = window; - if (wnext == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - *out++ = *from++; - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (wnext < op) { /* wrap around window */ - from += wsize + wnext - op; - op -= wnext; - if (op < len) { /* some from end of window */ - len -= op; - do { - *out++ = *from++; - } while (--op); - from = window; - if (wnext < len) { /* some from start of window */ - op = wnext; - len -= op; - do { - *out++ = *from++; - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += wnext - op; - if (op < len) { /* some from window */ - len -= op; - do { - *out++ = *from++; - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - *out++ = *from++; - *out++ = *from++; - *out++ = *from++; - len -= 3; - } - if (len) { - *out++ = *from++; - if (len > 1) - *out++ = *from++; - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - *out++ = *from++; - *out++ = *from++; - *out++ = *from++; - len -= 3; - } while (len > 2); - if (len) { - *out++ = *from++; - if (len > 1) - *out++ = *from++; - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - here = dcode[here.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - here = lcode[here.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in; - strm->next_out = out; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and wnext == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ diff --git a/libraries/zlib/inffast.h b/libraries/zlib/inffast.h deleted file mode 100644 index e5c1aa4ca8c..00000000000 --- a/libraries/zlib/inffast.h +++ /dev/null @@ -1,11 +0,0 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003, 2010 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/libraries/zlib/inffixed.h b/libraries/zlib/inffixed.h deleted file mode 100644 index d6283277694..00000000000 --- a/libraries/zlib/inffixed.h +++ /dev/null @@ -1,94 +0,0 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. - It is part of the implementation of this library and is - subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; diff --git a/libraries/zlib/inflate.c b/libraries/zlib/inflate.c deleted file mode 100644 index ac333e8c2ed..00000000000 --- a/libraries/zlib/inflate.c +++ /dev/null @@ -1,1561 +0,0 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common wnext == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local int inflateStateCheck OF((z_streamp strm)); -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, - unsigned copy)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, - unsigned len)); - -local int inflateStateCheck(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) - return 1; - state = (struct inflate_state FAR *)strm->state; - if (state == Z_NULL || state->strm != strm || - state->mode < HEAD || state->mode > SYNC) - return 1; - return 0; -} - -int ZEXPORT inflateResetKeep(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - if (state->wrap) /* to support ill-conceived Java test suite */ - strm->adler = state->wrap & 1; - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->dmax = 32768U; - state->head = Z_NULL; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - state->sane = 1; - state->back = -1; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - state->wsize = 0; - state->whave = 0; - state->wnext = 0; - return inflateResetKeep(strm); -} - -int ZEXPORT inflateReset2(strm, windowBits) -z_streamp strm; -int windowBits; -{ - int wrap; - struct inflate_state FAR *state; - - /* get the state */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* extract wrap request from windowBits parameter */ - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } - else { - wrap = (windowBits >> 4) + 5; -#ifdef GUNZIP - if (windowBits < 48) - windowBits &= 15; -#endif - } - - /* set number of window bits, free window if different */ - if (windowBits && (windowBits < 8 || windowBits > 15)) - return Z_STREAM_ERROR; - if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { - ZFREE(strm, state->window); - state->window = Z_NULL; - } - - /* update state and reset the rest of it */ - state->wrap = wrap; - state->wbits = (unsigned)windowBits; - return inflateReset(strm); -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - int ret; - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; -#endif - } - if (strm->zfree == (free_func)0) -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zfree = zcfree; -#endif - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->strm = strm; - state->window = Z_NULL; - state->mode = HEAD; /* to pass state test in inflateReset2() */ - ret = inflateReset2(strm, windowBits); - if (ret != Z_OK) { - ZFREE(strm, state); - strm->state = Z_NULL; - } - return ret; -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (bits < 0) { - state->hold = 0; - state->bits = 0; - return Z_OK; - } - if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; - value &= (1L << bits) - 1; - state->hold += (unsigned)value << state->bits; - state->bits += (uInt)bits; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, - state.lencode[low].bits, state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, end, copy) -z_streamp strm; -const Bytef *end; -unsigned copy; -{ - struct inflate_state FAR *state; - unsigned dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->wnext = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - if (copy >= state->wsize) { - zmemcpy(state->window, end - state->wsize, state->wsize); - state->wnext = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->wnext; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->wnext, end - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, end - copy, copy); - state->wnext = copy; - state->whave = state->wsize; - } - else { - state->wnext += dist; - if (state->wnext == state->wsize) state->wnext = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - z_const unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code here; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (inflateStateCheck(strm) || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - if (state->wbits == 0) - state->wbits = 15; - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (state->head != Z_NULL) - state->head->done = -1; - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - len = BITS(4) + 8; - if (state->wbits == 0) - state->wbits = len; - if (len > 15 || len > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - state->dmax = 1U << len; - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->head != Z_NULL) - state->head->text = (int)((hold >> 8) & 1); - if ((state->flags & 0x0200) && (state->wrap & 4)) - CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->head != Z_NULL) - state->head->time = hold; - if ((state->flags & 0x0200) && (state->wrap & 4)) - CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->head != Z_NULL) { - state->head->xflags = (int)(hold & 0xff); - state->head->os = (int)(hold >> 8); - } - if ((state->flags & 0x0200) && (state->wrap & 4)) - CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->head != Z_NULL) - state->head->extra_len = (unsigned)hold; - if ((state->flags & 0x0200) && (state->wrap & 4)) - CRC2(state->check, hold); - INITBITS(); - } - else if (state->head != Z_NULL) - state->head->extra = Z_NULL; - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; - zmemcpy(state->head->extra + len, next, - len + copy > state->head->extra_max ? - state->head->extra_max - len : copy); - } - if ((state->flags & 0x0200) && (state->wrap & 4)) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->length = 0; - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->name != Z_NULL && - state->length < state->head->name_max) - state->head->name[state->length++] = (Bytef)len; - } while (len && copy < have); - if ((state->flags & 0x0200) && (state->wrap & 4)) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->name = Z_NULL; - state->length = 0; - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->comment != Z_NULL && - state->length < state->head->comm_max) - state->head->comment[state->length++] = (Bytef)len; - } while (len && copy < have); - if ((state->flags & 0x0200) && (state->wrap & 4)) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->comment = Z_NULL; - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if ((state->wrap & 4) && hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - if (state->head != Z_NULL) { - state->head->hcrc = (int)((state->flags >> 9) & 1); - state->head->done = 1; - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = ZSWAP32(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN_; /* decode codes */ - if (flush == Z_TREES) { - DROPBITS(2); - goto inf_leave; - } - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY_; - if (flush == Z_TREES) goto inf_leave; - case COPY_: - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (const code FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.val < 16) { - DROPBITS(here.bits); - state->lens[state->have++] = here.val; - } - else { - if (here.val == 16) { - NEEDBITS(here.bits + 2); - DROPBITS(here.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (here.val == 17) { - NEEDBITS(here.bits + 3); - DROPBITS(here.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(here.bits + 7); - DROPBITS(here.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* check for end-of-block code (better have one) */ - if (state->lens[256] == 0) { - strm->msg = (char *)"invalid code -- missing end-of-block"; - state->mode = BAD; - break; - } - - /* build code tables -- note: do not change the lenbits or distbits - values here (9 and 6) without reading the comments in inftrees.h - concerning the ENOUGH constants, which depend on those values */ - state->next = state->codes; - state->lencode = (const code FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (const code FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN_; - if (flush == Z_TREES) goto inf_leave; - case LEN_: - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - if (state->mode == TYPE) - state->back = -1; - break; - } - state->back = 0; - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.op && (here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - state->back += last.bits; - } - DROPBITS(here.bits); - state->back += here.bits; - state->length = (unsigned)here.val; - if ((int)(here.op) == 0) { - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - state->mode = LIT; - break; - } - if (here.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->back = -1; - state->mode = TYPE; - break; - } - if (here.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(here.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - state->back += state->extra; - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->was = state->length; - state->mode = DIST; - case DIST: - for (;;) { - here = state->distcode[BITS(state->distbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if ((here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - state->back += last.bits; - } - DROPBITS(here.bits); - state->back += here.bits; - if (here.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)here.val; - state->extra = (unsigned)(here.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - state->back += state->extra; - } -#ifdef INFLATE_STRICT - if (state->offset > state->dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->whave) { - if (state->sane) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - Trace((stderr, "inflate.c too far\n")); - copy -= state->whave; - if (copy > state->length) copy = state->length; - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = 0; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; -#endif - } - if (copy > state->wnext) { - copy -= state->wnext; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->wnext - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if ((state->wrap & 4) && out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if ((state->wrap & 4) && ( -#ifdef GUNZIP - state->flags ? hold : -#endif - ZSWAP32(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (out != strm->avail_out && state->mode < BAD && - (state->mode < CHECK || flush != Z_FINISH))) - if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if ((state->wrap & 4) && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = (int)state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0) + - (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) -z_streamp strm; -Bytef *dictionary; -uInt *dictLength; -{ - struct inflate_state FAR *state; - - /* check state */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* copy dictionary */ - if (state->whave && dictionary != Z_NULL) { - zmemcpy(dictionary, state->window + state->wnext, - state->whave - state->wnext); - zmemcpy(dictionary + state->whave - state->wnext, - state->window, state->wnext); - } - if (dictLength != Z_NULL) - *dictLength = state->whave; - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long dictid; - int ret; - - /* check state */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->wrap != 0 && state->mode != DICT) - return Z_STREAM_ERROR; - - /* check for correct dictionary identifier */ - if (state->mode == DICT) { - dictid = adler32(0L, Z_NULL, 0); - dictid = adler32(dictid, dictionary, dictLength); - if (dictid != state->check) - return Z_DATA_ERROR; - } - - /* copy dictionary to window using updatewindow(), which will amend the - existing dictionary if appropriate */ - ret = updatewindow(strm, dictionary + dictLength, dictLength); - if (ret) { - state->mode = MEM; - return Z_MEM_ERROR; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ - struct inflate_state FAR *state; - - /* check state */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; - - /* save header structure */ - state->head = head; - head->done = 0; - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -const unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - unsigned wsize; - - /* check input */ - if (inflateStateCheck(source) || dest == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); - copy->strm = dest; - if (state->lencode >= state->codes && - state->lencode <= state->codes + ENOUGH - 1) { - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - } - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) { - wsize = 1U << state->wbits; - zmemcpy(window, state->window, wsize); - } - copy->window = window; - dest->state = (struct internal_state FAR *)copy; - return Z_OK; -} - -int ZEXPORT inflateUndermine(strm, subvert) -z_streamp strm; -int subvert; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - state->sane = !subvert; - return Z_OK; -#else - (void)subvert; - state->sane = 1; - return Z_DATA_ERROR; -#endif -} - -int ZEXPORT inflateValidate(strm, check) -z_streamp strm; -int check; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (check) - state->wrap |= 4; - else - state->wrap &= ~4; - return Z_OK; -} - -long ZEXPORT inflateMark(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) - return -(1L << 16); - state = (struct inflate_state FAR *)strm->state; - return (long)(((unsigned long)((long)state->back)) << 16) + - (state->mode == COPY ? state->length : - (state->mode == MATCH ? state->was - state->length : 0)); -} - -unsigned long ZEXPORT inflateCodesUsed(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (inflateStateCheck(strm)) return (unsigned long)-1; - state = (struct inflate_state FAR *)strm->state; - return (unsigned long)(state->next - state->codes); -} diff --git a/libraries/zlib/inflate.h b/libraries/zlib/inflate.h deleted file mode 100644 index a46cce6b6d0..00000000000 --- a/libraries/zlib/inflate.h +++ /dev/null @@ -1,125 +0,0 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD = 16180, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY_, /* i/o: same as COPY below, but only first time in */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN_, /* i: same as LEN below, but only first time in */ - LEN, /* i: waiting for length/lit/eob code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to BAD or MEM on error -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) or (raw) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> - HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - (raw) -> TYPEDO - Read deflate blocks: - TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK - STORED -> COPY_ -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN_ - LEN_ -> LEN - Read deflate codes in fixed or dynamic block: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* State maintained between inflate() calls -- approximately 7K bytes, not - including the allocated sliding window, which is up to 32K bytes. */ -struct inflate_state { - z_streamp strm; /* pointer back to this zlib stream */ - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip, - bit 2 true to validate check value */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - gz_headerp head; /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned wnext; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ - int sane; /* if false, allow invalid distance too far */ - int back; /* bits back of last unprocessed length/lit */ - unsigned was; /* initial length of match */ -}; diff --git a/libraries/zlib/inftrees.c b/libraries/zlib/inftrees.c deleted file mode 100644 index 2ea08fc13ea..00000000000 --- a/libraries/zlib/inftrees.c +++ /dev/null @@ -1,304 +0,0 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2017 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code here; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - unsigned match; /* use base and extra for symbol >= match */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) { /* no symbols to code at all */ - here.op = (unsigned char)64; /* invalid code marker */ - here.bits = (unsigned char)1; - here.val = (unsigned short)0; - *(*table)++ = here; /* make a table to force an error */ - *(*table)++ = here; - *bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min < max; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || max != 1)) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked for LENS and DIST tables against - the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in - the initial root table size constants. See the comments in inftrees.h - for more information. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - match = 20; - break; - case LENS: - base = lbase; - extra = lext; - match = 257; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - match = 0; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if ((type == LENS && used > ENOUGH_LENS) || - (type == DISTS && used > ENOUGH_DISTS)) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - here.bits = (unsigned char)(len - drop); - if (work[sym] + 1U < match) { - here.op = (unsigned char)0; - here.val = work[sym]; - } - else if (work[sym] >= match) { - here.op = (unsigned char)(extra[work[sym] - match]); - here.val = base[work[sym] - match]; - } - else { - here.op = (unsigned char)(32 + 64); /* end of block */ - here.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - next[(huff >> drop) + fill] = here; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if ((type == LENS && used > ENOUGH_LENS) || - (type == DISTS && used > ENOUGH_DISTS)) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* fill in remaining table entry if code is incomplete (guaranteed to have - at most one remaining entry, since if the code is incomplete, the - maximum code length that was allowed to get this far is one bit) */ - if (huff != 0) { - here.op = (unsigned char)64; /* invalid code marker */ - here.bits = (unsigned char)(len - drop); - here.val = (unsigned short)0; - next[huff] = here; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} diff --git a/libraries/zlib/inftrees.h b/libraries/zlib/inftrees.h deleted file mode 100644 index baa53a0b1a1..00000000000 --- a/libraries/zlib/inftrees.h +++ /dev/null @@ -1,62 +0,0 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005, 2010 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of the dynamic table. The maximum number of code structures is - 1444, which is the sum of 852 for literal/length codes and 592 for distance - codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that - program are the number of symbols, the initial root table size, and the - maximum bit length of a code. "enough 286 9 15" for literal/length codes - returns returns 852, and "enough 30 6 15" for distance codes returns 592. - The initial root table size (9 or 6) is found in the fifth argument of the - inflate_table() calls in inflate.c and infback.c. If the root table size is - changed, then these maximum sizes would be need to be recalculated and - updated. */ -#define ENOUGH_LENS 852 -#define ENOUGH_DISTS 592 -#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) - -/* Type of code to build for inflate_table() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); diff --git a/libraries/zlib/trees.c b/libraries/zlib/trees.c deleted file mode 100644 index 50cf4b4571c..00000000000 --- a/libraries/zlib/trees.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2017 Jean-loup Gailly - * detect_data_type() function provided freely by Cosmin Truta, 2006 - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id$ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef ZLIB_DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local const static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local const static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local const static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, const ct_data *ltree, - const ct_data *dtree)); -local int detect_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef ZLIB_DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* !ZLIB_DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef ZLIB_DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (ush)value << s->bi_valid; - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= (ush)value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !ZLIB_DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = (int)value;\ - s->bi_buf |= (ush)val << s->bi_valid;\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (ush)(value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* ZLIB_DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ -#ifdef NO_INIT_GLOBAL_POINTERS - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; -#endif - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef ZLIB_DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, - "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void ZLIB_INTERNAL _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef ZLIB_DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (unsigned)(bits + xbits); - if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); - } - if (overflow == 0) return; - - Tracev((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if ((unsigned) tree[m].Len != (unsigned) bits) { - Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - unsigned code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; - next_code[bits] = (ush)code; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ - bi_windup(s); /* align on byte boundary */ - put_short(s, (ush)stored_len); - put_short(s, (ush)~stored_len); - zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); - s->pending += stored_len; -#ifdef ZLIB_DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; - s->bits_sent += 2*16; - s->bits_sent += stored_len<<3; -#endif -} - -/* =========================================================================== - * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) - */ -void ZLIB_INTERNAL _tr_flush_bits(s) - deflate_state *s; -{ - bi_flush(s); -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - */ -void ZLIB_INTERNAL _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef ZLIB_DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and write out the encoded block. - */ -void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is binary or text */ - if (s->strm->data_type == Z_UNKNOWN) - s->strm->data_type = detect_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, last); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); - compress_block(s, (const ct_data *)static_ltree, - (const ct_data *)static_dtree); -#ifdef ZLIB_DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (const ct_data *)s->dyn_ltree, - (const ct_data *)s->dyn_dtree); -#ifdef ZLIB_DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (last) { - bi_windup(s); -#ifdef ZLIB_DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - const ct_data *ltree; /* literal tree */ - const ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= (unsigned)base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); -} - -/* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "black list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local int detect_data_type(s) - deflate_state *s; -{ - /* black_mask is the bit mask of black-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - unsigned long black_mask = 0xf3ffc07fUL; - int n; - - /* Check for non-textual ("black-listed") bytes. */ - for (n = 0; n <= 31; n++, black_mask >>= 1) - if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) - return Z_BINARY; - - /* Check for textual ("white-listed") bytes. */ - if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 - || s->dyn_ltree[13].Freq != 0) - return Z_TEXT; - for (n = 32; n < LITERALS; n++) - if (s->dyn_ltree[n].Freq != 0) - return Z_TEXT; - - /* There are no "black-listed" or "white-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} diff --git a/libraries/zlib/trees.h b/libraries/zlib/trees.h deleted file mode 100644 index d35639d82a2..00000000000 --- a/libraries/zlib/trees.h +++ /dev/null @@ -1,128 +0,0 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - diff --git a/libraries/zlib/uncompr.c b/libraries/zlib/uncompr.c deleted file mode 100644 index f03a1a865e3..00000000000 --- a/libraries/zlib/uncompr.c +++ /dev/null @@ -1,93 +0,0 @@ -/* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Decompresses the source buffer into the destination buffer. *sourceLen is - the byte length of the source buffer. Upon entry, *destLen is the total size - of the destination buffer, which must be large enough to hold the entire - uncompressed data. (The size of the uncompressed data must have been saved - previously by the compressor and transmitted to the decompressor by some - mechanism outside the scope of this compression library.) Upon exit, - *destLen is the size of the decompressed data and *sourceLen is the number - of source bytes consumed. Upon return, source + *sourceLen points to the - first unused input byte. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, or - Z_DATA_ERROR if the input data was corrupted, including if the input data is - an incomplete zlib stream. -*/ -int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong *sourceLen; -{ - z_stream stream; - int err; - const uInt max = (uInt)-1; - uLong len, left; - Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ - - len = *sourceLen; - if (*destLen) { - left = *destLen; - *destLen = 0; - } - else { - left = 1; - dest = buf; - } - - stream.next_in = (z_const Bytef *)source; - stream.avail_in = 0; - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - stream.next_out = dest; - stream.avail_out = 0; - - do { - if (stream.avail_out == 0) { - stream.avail_out = left > (uLong)max ? max : (uInt)left; - left -= stream.avail_out; - } - if (stream.avail_in == 0) { - stream.avail_in = len > (uLong)max ? max : (uInt)len; - len -= stream.avail_in; - } - err = inflate(&stream, Z_NO_FLUSH); - } while (err == Z_OK); - - *sourceLen -= len + stream.avail_in; - if (dest != buf) - *destLen = stream.total_out; - else if (stream.total_out && err == Z_BUF_ERROR) - left = 1; - - inflateEnd(&stream); - return err == Z_STREAM_END ? Z_OK : - err == Z_NEED_DICT ? Z_DATA_ERROR : - err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : - err; -} - -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return uncompress2(dest, destLen, source, &sourceLen); -} diff --git a/libraries/zlib/win32/zlib.def b/libraries/zlib/win32/zlib.def deleted file mode 100644 index a2188b00062..00000000000 --- a/libraries/zlib/win32/zlib.def +++ /dev/null @@ -1,94 +0,0 @@ -; zlib data compression library -EXPORTS -; basic functions - zlibVersion - deflate - deflateEnd - inflate - inflateEnd -; advanced functions - deflateSetDictionary - deflateGetDictionary - deflateCopy - deflateReset - deflateParams - deflateTune - deflateBound - deflatePending - deflatePrime - deflateSetHeader - inflateSetDictionary - inflateGetDictionary - inflateSync - inflateCopy - inflateReset - inflateReset2 - inflatePrime - inflateMark - inflateGetHeader - inflateBack - inflateBackEnd - zlibCompileFlags -; utility functions - compress - compress2 - compressBound - uncompress - uncompress2 - gzopen - gzdopen - gzbuffer - gzsetparams - gzread - gzfread - gzwrite - gzfwrite - gzprintf - gzvprintf - gzputs - gzgets - gzputc - gzgetc - gzungetc - gzflush - gzseek - gzrewind - gztell - gzoffset - gzeof - gzdirect - gzclose - gzclose_r - gzclose_w - gzerror - gzclearerr -; large file functions - gzopen64 - gzseek64 - gztell64 - gzoffset64 - adler32_combine64 - crc32_combine64 -; checksum functions - adler32 - adler32_z - crc32 - crc32_z - adler32_combine - crc32_combine -; various hacks, don't look :) - deflateInit_ - deflateInit2_ - inflateInit_ - inflateInit2_ - inflateBackInit_ - gzgetc_ - zError - inflateSyncPoint - get_crc_table - inflateUndermine - inflateValidate - inflateCodesUsed - inflateResetKeep - deflateResetKeep - gzopen_w diff --git a/libraries/zlib/win32/zlib1.rc b/libraries/zlib/win32/zlib1.rc deleted file mode 100644 index 234e641c329..00000000000 --- a/libraries/zlib/win32/zlib1.rc +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "../zlib.h" - -#ifdef GCC_WINDRES -VS_VERSION_INFO VERSIONINFO -#else -VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE -#endif - FILEVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 - PRODUCTVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS 1 -#else - FILEFLAGS 0 -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE 0 // not used -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904E4" - //language ID = U.S. English, char set = Windows, Multilingual - BEGIN - VALUE "FileDescription", "zlib data compression library\0" - VALUE "FileVersion", ZLIB_VERSION "\0" - VALUE "InternalName", "zlib1.dll\0" - VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" - VALUE "OriginalFilename", "zlib1.dll\0" - VALUE "ProductName", "zlib\0" - VALUE "ProductVersion", ZLIB_VERSION "\0" - VALUE "Comments", "For more information visit http://www.zlib.net/\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0409, 1252 - END -END diff --git a/libraries/zlib/zconf.h b/libraries/zlib/zconf.h deleted file mode 100644 index 5e1d68a004e..00000000000 --- a/libraries/zlib/zconf.h +++ /dev/null @@ -1,534 +0,0 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - * Even better than compiling with -DZ_PREFIX would be to use configure to set - * this permanently in zconf.h using "./configure --zprefix". - */ -#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ -# define Z_PREFIX_SET - -/* all linked symbols and init macros */ -# define _dist_code z__dist_code -# define _length_code z__length_code -# define _tr_align z__tr_align -# define _tr_flush_bits z__tr_flush_bits -# define _tr_flush_block z__tr_flush_block -# define _tr_init z__tr_init -# define _tr_stored_block z__tr_stored_block -# define _tr_tally z__tr_tally -# define adler32 z_adler32 -# define adler32_combine z_adler32_combine -# define adler32_combine64 z_adler32_combine64 -# define adler32_z z_adler32_z -# ifndef Z_SOLO -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# endif -# define crc32 z_crc32 -# define crc32_combine z_crc32_combine -# define crc32_combine64 z_crc32_combine64 -# define crc32_z z_crc32_z -# define deflate z_deflate -# define deflateBound z_deflateBound -# define deflateCopy z_deflateCopy -# define deflateEnd z_deflateEnd -# define deflateGetDictionary z_deflateGetDictionary -# define deflateInit z_deflateInit -# define deflateInit2 z_deflateInit2 -# define deflateInit2_ z_deflateInit2_ -# define deflateInit_ z_deflateInit_ -# define deflateParams z_deflateParams -# define deflatePending z_deflatePending -# define deflatePrime z_deflatePrime -# define deflateReset z_deflateReset -# define deflateResetKeep z_deflateResetKeep -# define deflateSetDictionary z_deflateSetDictionary -# define deflateSetHeader z_deflateSetHeader -# define deflateTune z_deflateTune -# define deflate_copyright z_deflate_copyright -# define get_crc_table z_get_crc_table -# ifndef Z_SOLO -# define gz_error z_gz_error -# define gz_intmax z_gz_intmax -# define gz_strwinerror z_gz_strwinerror -# define gzbuffer z_gzbuffer -# define gzclearerr z_gzclearerr -# define gzclose z_gzclose -# define gzclose_r z_gzclose_r -# define gzclose_w z_gzclose_w -# define gzdirect z_gzdirect -# define gzdopen z_gzdopen -# define gzeof z_gzeof -# define gzerror z_gzerror -# define gzflush z_gzflush -# define gzfread z_gzfread -# define gzfwrite z_gzfwrite -# define gzgetc z_gzgetc -# define gzgetc_ z_gzgetc_ -# define gzgets z_gzgets -# define gzoffset z_gzoffset -# define gzoffset64 z_gzoffset64 -# define gzopen z_gzopen -# define gzopen64 z_gzopen64 -# ifdef _WIN32 -# define gzopen_w z_gzopen_w -# endif -# define gzprintf z_gzprintf -# define gzputc z_gzputc -# define gzputs z_gzputs -# define gzread z_gzread -# define gzrewind z_gzrewind -# define gzseek z_gzseek -# define gzseek64 z_gzseek64 -# define gzsetparams z_gzsetparams -# define gztell z_gztell -# define gztell64 z_gztell64 -# define gzungetc z_gzungetc -# define gzvprintf z_gzvprintf -# define gzwrite z_gzwrite -# endif -# define inflate z_inflate -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define inflateBackInit z_inflateBackInit -# define inflateBackInit_ z_inflateBackInit_ -# define inflateCodesUsed z_inflateCodesUsed -# define inflateCopy z_inflateCopy -# define inflateEnd z_inflateEnd -# define inflateGetDictionary z_inflateGetDictionary -# define inflateGetHeader z_inflateGetHeader -# define inflateInit z_inflateInit -# define inflateInit2 z_inflateInit2 -# define inflateInit2_ z_inflateInit2_ -# define inflateInit_ z_inflateInit_ -# define inflateMark z_inflateMark -# define inflatePrime z_inflatePrime -# define inflateReset z_inflateReset -# define inflateReset2 z_inflateReset2 -# define inflateResetKeep z_inflateResetKeep -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateUndermine z_inflateUndermine -# define inflateValidate z_inflateValidate -# define inflate_copyright z_inflate_copyright -# define inflate_fast z_inflate_fast -# define inflate_table z_inflate_table -# ifndef Z_SOLO -# define uncompress z_uncompress -# define uncompress2 z_uncompress2 -# endif -# define zError z_zError -# ifndef Z_SOLO -# define zcalloc z_zcalloc -# define zcfree z_zcfree -# endif -# define zlibCompileFlags z_zlibCompileFlags -# define zlibVersion z_zlibVersion - -/* all zlib typedefs in zlib.h and zconf.h */ -# define Byte z_Byte -# define Bytef z_Bytef -# define alloc_func z_alloc_func -# define charf z_charf -# define free_func z_free_func -# ifndef Z_SOLO -# define gzFile z_gzFile -# endif -# define gz_header z_gz_header -# define gz_headerp z_gz_headerp -# define in_func z_in_func -# define intf z_intf -# define out_func z_out_func -# define uInt z_uInt -# define uIntf z_uIntf -# define uLong z_uLong -# define uLongf z_uLongf -# define voidp z_voidp -# define voidpc z_voidpc -# define voidpf z_voidpf - -/* all zlib structs in zlib.h and zconf.h */ -# define gz_header_s z_gz_header_s -# define internal_state z_internal_state - -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -#if defined(ZLIB_CONST) && !defined(z_const) -# define z_const const -#else -# define z_const -#endif - -#ifdef Z_SOLO - typedef unsigned long z_size_t; -#else -# define z_longlong long long -# if defined(NO_SIZE_T) - typedef unsigned NO_SIZE_T z_size_t; -# elif defined(STDC) -# include - typedef size_t z_size_t; -# else - typedef unsigned long z_size_t; -# endif -# undef z_longlong -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus about 7 kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -#ifndef Z_ARG /* function prototypes for stdarg */ -# if defined(STDC) || defined(Z_HAVE_STDARG_H) -# define Z_ARG(args) args -# else -# define Z_ARG(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) -# include -# if (UINT_MAX == 0xffffffffUL) -# define Z_U4 unsigned -# elif (ULONG_MAX == 0xffffffffUL) -# define Z_U4 unsigned long -# elif (USHRT_MAX == 0xffffffffUL) -# define Z_U4 unsigned short -# endif -#endif - -#ifdef Z_U4 - typedef Z_U4 z_crc_t; -#else - typedef unsigned long z_crc_t; -#endif - -#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ -# define Z_HAVE_UNISTD_H -#endif - -#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ -# define Z_HAVE_STDARG_H -#endif - -#ifdef STDC -# ifndef Z_SOLO -# include /* for off_t */ -# endif -#endif - -#if defined(STDC) || defined(Z_HAVE_STDARG_H) -# ifndef Z_SOLO -# include /* for va_list */ -# endif -#endif - -#ifdef _WIN32 -# ifndef Z_SOLO -# include /* for wchar_t */ -# endif -#endif - -/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and - * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even - * though the former does not conform to the LFS document), but considering - * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as - * equivalently requesting no 64-bit operations - */ -#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 -# undef _LARGEFILE64_SOURCE -#endif - -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H -#endif -#ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) -# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ -# ifdef VMS -# include /* for off_t */ -# endif -# ifndef z_off_t -# define z_off_t off_t -# endif -# endif -#endif - -#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 -# define Z_LFS64 -#endif - -#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) -# define Z_LARGE64 -#endif - -#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) -# define Z_WANT64 -#endif - -#if !defined(SEEK_SET) && !defined(Z_SOLO) -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif - -#ifndef z_off_t -# define z_off_t long -#endif - -#if !defined(_WIN32) && defined(Z_LARGE64) -# define z_off64_t off64_t -#else -# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) -# define z_off64_t __int64 -# else -# define z_off64_t z_off_t -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) - #pragma map(deflateInit_,"DEIN") - #pragma map(deflateInit2_,"DEIN2") - #pragma map(deflateEnd,"DEEND") - #pragma map(deflateBound,"DEBND") - #pragma map(inflateInit_,"ININ") - #pragma map(inflateInit2_,"ININ2") - #pragma map(inflateEnd,"INEND") - #pragma map(inflateSync,"INSY") - #pragma map(inflateSetDictionary,"INSEDI") - #pragma map(compressBound,"CMBND") - #pragma map(inflate_table,"INTABL") - #pragma map(inflate_fast,"INFA") - #pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ diff --git a/libraries/zlib/zlib.3 b/libraries/zlib/zlib.3 deleted file mode 100644 index bda4eb07370..00000000000 --- a/libraries/zlib/zlib.3 +++ /dev/null @@ -1,149 +0,0 @@ -.TH ZLIB 3 "15 Jan 2017" -.SH NAME -zlib \- compression/decompression library -.SH SYNOPSIS -[see -.I zlib.h -for full description] -.SH DESCRIPTION -The -.I zlib -library is a general purpose data compression library. -The code is thread safe, assuming that the standard library functions -used are thread safe, such as memory allocation routines. -It provides in-memory compression and decompression functions, -including integrity checks of the uncompressed data. -This version of the library supports only one compression method (deflation) -but other algorithms may be added later -with the same stream interface. -.LP -Compression can be done in a single step if the buffers are large enough -or can be done by repeated calls of the compression function. -In the latter case, -the application must provide more input and/or consume the output -(providing more output space) before each call. -.LP -The library also supports reading and writing files in -.IR gzip (1) -(.gz) format -with an interface similar to that of stdio. -.LP -The library does not install any signal handler. -The decoder checks the consistency of the compressed data, -so the library should never crash even in the case of corrupted input. -.LP -All functions of the compression library are documented in the file -.IR zlib.h . -The distribution source includes examples of use of the library -in the files -.I test/example.c -and -.IR test/minigzip.c, -as well as other examples in the -.IR examples/ -directory. -.LP -Changes to this version are documented in the file -.I ChangeLog -that accompanies the source. -.LP -.I zlib -is built in to many languages and operating systems, including but not limited to -Java, Python, .NET, PHP, Perl, Ruby, Swift, and Go. -.LP -An experimental package to read and write files in the .zip format, -written on top of -.I zlib -by Gilles Vollant (info@winimage.com), -is available at: -.IP -http://www.winimage.com/zLibDll/minizip.html -and also in the -.I contrib/minizip -directory of the main -.I zlib -source distribution. -.SH "SEE ALSO" -The -.I zlib -web site can be found at: -.IP -http://zlib.net/ -.LP -The data format used by the -.I zlib -library is described by RFC -(Request for Comments) 1950 to 1952 in the files: -.IP -http://tools.ietf.org/html/rfc1950 (for the zlib header and trailer format) -.br -http://tools.ietf.org/html/rfc1951 (for the deflate compressed data format) -.br -http://tools.ietf.org/html/rfc1952 (for the gzip header and trailer format) -.LP -Mark Nelson wrote an article about -.I zlib -for the Jan. 1997 issue of Dr. Dobb's Journal; -a copy of the article is available at: -.IP -http://marknelson.us/1997/01/01/zlib-engine/ -.SH "REPORTING PROBLEMS" -Before reporting a problem, -please check the -.I zlib -web site to verify that you have the latest version of -.IR zlib ; -otherwise, -obtain the latest version and see if the problem still exists. -Please read the -.I zlib -FAQ at: -.IP -http://zlib.net/zlib_faq.html -.LP -before asking for help. -Send questions and/or comments to zlib@gzip.org, -or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). -.SH AUTHORS AND LICENSE -Version 1.2.11 -.LP -Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler -.LP -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. -.LP -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: -.LP -.nr step 1 1 -.IP \n[step]. 3 -The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment in the product documentation would be -appreciated but is not required. -.IP \n+[step]. -Altered source versions must be plainly marked as such, and must not be -misrepresented as being the original software. -.IP \n+[step]. -This notice may not be removed or altered from any source distribution. -.LP -Jean-loup Gailly Mark Adler -.br -jloup@gzip.org madler@alumni.caltech.edu -.LP -The deflate format used by -.I zlib -was defined by Phil Katz. -The deflate and -.I zlib -specifications were written by L. Peter Deutsch. -Thanks to all the people who reported problems and suggested various -improvements in -.IR zlib ; -who are too numerous to cite here. -.LP -UNIX manual page by R. P. C. Rodgers, -U.S. National Library of Medicine (rodgers@nlm.nih.gov). -.\" end of man page diff --git a/libraries/zlib/zlib.3.pdf b/libraries/zlib/zlib.3.pdf deleted file mode 100644 index 6fa519c5bdf..00000000000 Binary files a/libraries/zlib/zlib.3.pdf and /dev/null differ diff --git a/libraries/zlib/zlib.h b/libraries/zlib/zlib.h deleted file mode 100644 index f09cdaf1e05..00000000000 --- a/libraries/zlib/zlib.h +++ /dev/null @@ -1,1912 +0,0 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.11, January 15th, 2017 - - Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 - (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.11" -#define ZLIB_VERNUM 0x12b0 -#define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 11 -#define ZLIB_VER_SUBREVISION 0 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed data. - This version of the library supports only one compression method (deflation) - but other algorithms will be added later and will have the same stream - interface. - - Compression can be done in a single step if the buffers are large enough, - or can be done by repeated calls of the compression function. In the latter - case, the application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip and raw deflate streams in - memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never crash - even in the case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - z_const Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total number of input bytes read so far */ - - Bytef *next_out; /* next output byte will go here */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total number of bytes output so far */ - - z_const char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text - for deflate, or the decoding state for inflate */ - uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has dropped - to zero. It must update next_out and avail_out when avail_out has dropped - to zero. The application must initialize zalloc, zfree and opaque before - calling the init function. All other fields are set by the compression - library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. In that case, zlib is thread-safe. When zalloc and zfree are - Z_NULL on entry to the initialization function, they are set to internal - routines that use the standard library functions malloc() and free(). - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this if - the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers - returned by zalloc for objects of exactly 65536 bytes *must* have their - offset normalized to zero. The default allocation function provided by this - library ensures this (see zutil.c). To reduce memory requirements and avoid - any allocation of 64K objects, at the expense of compression ratio, compile - the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or progress - reports. After compression, total_in holds the total size of the - uncompressed data and may be saved for use by the decompressor (particularly - if the decompressor wants to decompress everything in a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -#define Z_TREES 6 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field for deflate() */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is not - compatible with the zlib.h header file used by the application. This check - is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. If - zalloc and zfree are set to Z_NULL, deflateInit updates them to use default - allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at all - (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION - requests a default compromise between speed and compression (currently - equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if level is not a valid compression level, or - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). msg is set to null - if there is no error message. deflateInit does not perform any compression: - this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Generate more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary. Some output may be provided even if - flush is zero. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming more - output, and updating avail_in or avail_out accordingly; avail_out should - never be zero before the call. The application can consume the compressed - output when it wants, for example when the output buffer is full (avail_out - == 0), or after each call of deflate(). If deflate returns Z_OK and with - zero avail_out, it must be called again after making room in the output - buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more ouput - in that case. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumulate before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In - particular avail_in is zero after the call if enough output space has been - provided before the call.) Flushing may degrade compression for some - compression algorithms and so it should be used only when necessary. This - completes the current deflate block and follows it with an empty stored block - that is three bits plus filler bits to the next byte, followed by four bytes - (00 00 ff ff). - - If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the - output buffer, but the output is not aligned to a byte boundary. All of the - input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. - This completes the current deflate block and follows it with an empty fixed - codes block that is 10 bits long. This assures that enough bytes are output - in order for the decompressor to finish the block before the empty fixed - codes block. - - If flush is set to Z_BLOCK, a deflate block is completed and emitted, as - for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to - seven bits of the current block are held to be written as the next byte after - the next deflate block is completed. In this case, the decompressor may not - be provided enough bits at this point in order to complete decompression of - the data provided so far to the compressor. It may need to wait for the next - block to be emitted. This is for advanced applications that need to control - the emission of deflate blocks. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there was - enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this - function must be called again with Z_FINISH and more output space (updated - avail_out) but no more input data, until it returns with Z_STREAM_END or an - error. After deflate has returned Z_STREAM_END, the only possible operations - on the stream are deflateReset or deflateEnd. - - Z_FINISH can be used in the first deflate call after deflateInit if all the - compression is to be done in a single step. In order to complete in one - call, avail_out must be at least the value returned by deflateBound (see - below). Then deflate is guaranteed to return Z_STREAM_END. If not enough - output space is provided, deflate will not return Z_STREAM_END, and it must - be called again as described above. - - deflate() sets strm->adler to the Adler-32 checksum of all input read - so far (that is, total_in bytes). If a gzip stream is being generated, then - strm->adler will be the CRC-32 checksum of the input read so far. (See - deflateInit2 below.) - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is - considered binary. This field is only for information purposes and does not - affect the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was Z_NULL or the state was inadvertently written over - by the application), or Z_BUF_ERROR if no progress is possible (for example - avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and - deflate() can be called again with more input and more output space to - continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any pending - output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, msg - may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. In the current version of inflate, the provided input is not - read or consumed. The allocation of a sliding window will be deferred to - the first call of inflate (if the decompression does not complete on the - first call). If zalloc and zfree are set to Z_NULL, inflateInit updates - them to use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller, or Z_STREAM_ERROR if the parameters are - invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit does not perform any decompression. - Actual decompression will be done by inflate(). So next_in, and avail_in, - next_out, and avail_out are unused and unchanged. The current - implementation of inflateInit() does not process any header information -- - that is deferred until inflate() is called. -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), then next_in and avail_in are updated - accordingly, and processing will resume at this point for the next call of - inflate(). - - - Generate more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there is - no more input data or no more space in the output buffer (see below about - the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming more - output, and updating the next_* and avail_* values accordingly. If the - caller of inflate() does not provide both available input and available - output space, it is possible that there will be no progress made. The - application can consume the uncompressed output when it wants, for example - when the output buffer is full (avail_out == 0), or after each call of - inflate(). If inflate returns Z_OK and with zero avail_out, it must be - called again after making room in the output buffer because there might be - more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, - Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() - stop if and when it gets to the next deflate block boundary. When decoding - the zlib or gzip format, this will cause inflate() to return immediately - after the header and before the first block. When doing a raw inflate, - inflate() will go ahead and process the first block, and will return when it - gets to the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - To assist in this, on return inflate() always sets strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 if - inflate() is currently decoding the last block in the deflate stream, plus - 128 if inflate() returned immediately after decoding an end-of-block code or - decoding the complete header up to just before the first byte of the deflate - stream. The end-of-block will not be indicated until all of the uncompressed - data from that block has been written to strm->next_out. The number of - unused bits may in general be greater than seven, except when bit 7 of - data_type is set, in which case the number of unused bits will be less than - eight. data_type is set as noted here every time inflate() returns for all - flush options, and so can be used to determine the amount of currently - consumed input in bits. - - The Z_TREES option behaves as Z_BLOCK does, but it also returns when the - end of each deflate block header is reached, before any actual data in that - block is decoded. This allows the caller to determine the length of the - deflate block header for later use in random access within a deflate block. - 256 is added to the value of strm->data_type when inflate() returns - immediately after reaching the end of the deflate block header. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step (a - single call of inflate), the parameter flush should be set to Z_FINISH. In - this case all pending input is processed and all pending output is flushed; - avail_out must be large enough to hold all of the uncompressed data for the - operation to complete. (The size of the uncompressed data may have been - saved by the compressor for this purpose.) The use of Z_FINISH is not - required to perform an inflation in one step. However it may be used to - inform inflate that a faster approach can be used for the single inflate() - call. Z_FINISH also informs inflate to not maintain a sliding window if the - stream completes, which reduces inflate's memory footprint. If the stream - does not complete, either because not all of the stream is provided or not - enough output space is provided, then a sliding window will be allocated and - inflate() can be called again to continue the operation as if Z_NO_FLUSH had - been used. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the effects of the flush parameter in this implementation are - on the return value of inflate() as noted below, when inflate() returns early - when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of - memory for a sliding window when Z_FINISH is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the Adler-32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the Adler-32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed Adler-32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() can decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically, if requested when - initializing with inflateInit2(). Any information contained in the gzip - header is not retained unless inflateGetHeader() is used. When processing - gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output - produced so far. The CRC-32 is checked against the gzip trailer, as is the - uncompressed length, modulo 2^32. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value, in which case strm->msg points to a string with a more specific - error), Z_STREAM_ERROR if the stream structure was inconsistent (for example - next_in or next_out was Z_NULL, or the state was inadvertently written over - by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR - if no progress was possible or if there was not enough room in the output - buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may - then call inflateSync() to look for a good compression block if a partial - recovery of the data is to be attempted. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any pending - output. - - inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state - was inconsistent. -*/ - - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by the - caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - For the current implementation of deflate(), a windowBits value of 8 (a - window size of 256 bytes) is not supported. As a result, a request for 8 - will result in 9 (a 512-byte window). In that case, providing 8 to - inflateInit2() will result in an error when the zlib header with 9 is - checked against the initialization of inflate(). The remedy is to not use 8 - with deflateInit2() with this initialization, or at least in that case use 9 - with inflateInit2(). - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute a check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), no - header crc, and the operating system will be set to the appropriate value, - if the operating system was determined at compile time. If a gzip stream is - being written, strm->adler is a CRC-32 instead of an Adler-32. - - For raw deflate or gzip encoding, a request for a 256-byte window is - rejected as invalid, since only the zlib header provides a means of - transmitting the window size to the decompressor. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but is - slow and reduces compression ratio; memLevel=9 uses maximum memory for - optimal speed. The default value is 8. See zconf.h for total memory usage - as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as - fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The - strategy parameter only affects the compression ratio but not the - correctness of the compressed output even if it is not set appropriately. - Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler - decoder for special applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid - method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is - incompatible with the version assumed by the caller (ZLIB_VERSION). msg is - set to null if there is no error message. deflateInit2 does not perform any - compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. When using the zlib format, this - function must be called immediately after deflateInit, deflateInit2 or - deflateReset, and before any call of deflate. When doing raw deflate, this - function must be called either before any call of deflate, or immediately - after the completion of a deflate block, i.e. after all input has been - consumed and all output has been delivered when using any of the flush - options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The - compressor and decompressor must use exactly the same dictionary (see - inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size - provided in deflateInit or deflateInit2. Thus the strings most likely to be - useful should be put at the end of the dictionary, not at the front. In - addition, the current implementation of deflate will use at most the window - size minus 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the Adler-32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler-32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - Adler-32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if not at a block boundary for raw deflate). deflateSetDictionary does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); -/* - Returns the sliding dictionary being maintained by deflate. dictLength is - set to the number of bytes in the dictionary, and that many bytes are copied - to dictionary. dictionary must have enough space, where 32768 bytes is - always enough. If deflateGetDictionary() is called with dictionary equal to - Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. - - deflateGetDictionary() may return a length less than the window size, even - when more than the window size in input has been provided. It may return up - to 258 bytes less in that case, due to how zlib's implementation of deflate - manages the sliding window and lookahead for matches, where matches can be - up to 258 bytes long. If the application needs the last window-size bytes of - input, then that would need to be saved by the application outside of zlib. - - deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the - stream state is inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and can - consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being Z_NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, but - does not free and reallocate the internal compression state. The stream - will leave the compression level and any other attributes that may have been - set unchanged. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2(). This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different strategy. - If the compression approach (which is a function of the level) or the - strategy is changed, and if any input has been consumed in a previous - deflate() call, then the input available so far is compressed with the old - level and strategy using deflate(strm, Z_BLOCK). There are three approaches - for the compression levels 0, 1..3, and 4..9 respectively. The new level - and strategy will take effect at the next call of deflate(). - - If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does - not have enough output space to complete, then the parameter change will not - take effect. In this case, deflateParams() can be called again with the - same parameters and more output space to try again. - - In order to assure a change in the parameters on the first try, the - deflate stream should be flushed using deflate() with Z_BLOCK or other flush - request until strm.avail_out is not zero, before calling deflateParams(). - Then no more input data should be provided before the deflateParams() call. - If this is done, the old level and strategy will be applied to the data - compressed before deflateParams(), and the new level and strategy will be - applied to the the data compressed after deflateParams(). - - deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream - state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if - there was not enough output space to complete the compression of the - available input data before a change in the strategy or approach. Note that - in the case of a Z_BUF_ERROR, the parameters are not changed. A return - value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be - retried with more output space. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() or - deflateInit2(), and after deflateSetHeader(), if used. This would be used - to allocate an output buffer for deflation in a single pass, and so would be - called before deflate(). If that first deflate() call is provided the - sourceLen input bytes, an output buffer allocated to the size returned by - deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed - to return Z_STREAM_END. Note that it is possible for the compressed size to - be larger than the value returned by deflateBound() if flush options other - than Z_FINISH or Z_NO_FLUSH are used. -*/ - -ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, - unsigned *pending, - int *bits)); -/* - deflatePending() returns the number of bytes and bits of output that have - been generated, but not yet provided in the available output. The bytes not - provided would be due to the available output space having being consumed. - The number of bits of output not provided are between 0 and 7, where they - await more bits to join them in order to fill out a full byte. If pending - or bits are Z_NULL, then those values are not set. - - deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. - */ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the bits - leftover from a previous deflate stream when appending to it. As such, this - function can only be used for raw deflate, and must be used before the first - deflate() call after a deflateInit2() or deflateReset(). bits must be less - than or equal to 16, and that many of the least significant bits of value - will be inserted in the output. - - deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough - room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the - source stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be zero to request that inflate use the window size in - the zlib header of the compressed stream. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an Adler-32 or a CRC-32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a - CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see - below), inflate() will not automatically decode concatenated gzip streams. - inflate() will return Z_STREAM_END at the end of the gzip stream. The state - would need to be reset to continue decoding a subsequent gzip stream. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller, or Z_STREAM_ERROR if the parameters are - invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit2 does not perform any decompression - apart from possibly reading the zlib header if present: actual decompression - will be done by inflate(). (So next_in and avail_in may be modified, but - next_out and avail_out are unused and unchanged.) The current implementation - of inflateInit2() does not process any header information -- that is - deferred until inflate() is called. -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler-32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called at any - time to set the dictionary. If the provided dictionary is smaller than the - window and there is already data in the window, then the provided dictionary - will amend what's there. The application must insure that the dictionary - that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler-32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); -/* - Returns the sliding dictionary being maintained by inflate. dictLength is - set to the number of bytes in the dictionary, and that many bytes are copied - to dictionary. dictionary must have enough space, where 32768 bytes is - always enough. If inflateGetDictionary() is called with dictionary equal to - Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. - - inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the - stream state is inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a possible full flush point (see above - for the description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync searches for a 00 00 FF FF pattern in the compressed data. - All full flush points have this pattern, but not all occurrences of this - pattern are full flush points. - - inflateSync returns Z_OK if a possible full flush point has been found, - Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point - has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. - In the success case, the application may save the current current value of - total_in which indicates where valid compressed data was found. In the - error case, the application may repeatedly call inflateSync, providing more - input each time, until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being Z_NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate the internal decompression state. The - stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL). -*/ - -ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, - int windowBits)); -/* - This function is the same as inflateReset, but it also permits changing - the wrap and window size requests. The windowBits parameter is interpreted - the same as it is for inflateInit2. If the window size is changed, then the - memory allocated for the window is freed, and the window will be reallocated - by inflate() if needed. - - inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL), or if - the windowBits parameter is invalid. -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - If bits is negative, then the input stream bit buffer is emptied. Then - inflatePrime() can be called again to put bits in the buffer. This is used - to clear out bits leftover after feeding inflate a block description prior - to feeding inflate codes. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); -/* - This function returns two values, one in the lower 16 bits of the return - value, and the other in the remaining upper bits, obtained by shifting the - return value down 16 bits. If the upper value is -1 and the lower value is - zero, then inflate() is currently decoding information outside of a block. - If the upper value is -1 and the lower value is non-zero, then inflate is in - the middle of a stored block, with the lower value equaling the number of - bytes from the input remaining to copy. If the upper value is not -1, then - it is the number of bits back from the current bit position in the input of - the code (literal or length/distance pair) currently being processed. In - that case the lower value is the number of bytes already emitted for that - code. - - A code is being processed if inflate is waiting for more input to complete - decoding of the code, or if it has completed decoding but is waiting for - more output space to write the literal or match data. - - inflateMark() is used to mark locations in the input data for random - access, which may be at bit positions, and to note those cases where the - output of a code may span boundaries of random access blocks. The current - location in the input stream can be determined from avail_in and data_type - as noted in the description for the Z_BLOCK flush parameter for inflate. - - inflateMark returns the value noted above, or -65536 if the provided - source stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be - used to force inflate() to return immediately after header processing is - complete and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When any - of extra, name, or comment are not Z_NULL and the respective field is not - present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the parameters are invalid, Z_MEM_ERROR if the internal state could not be - allocated, or Z_VERSION_ERROR if the version of the library does not match - the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, - z_const unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is potentially more efficient than - inflate() for file i/o applications, in that it avoids copying between the - output and the sliding window by simply making the window itself the output - buffer. inflate() can be faster on modern CPUs when used with large - buffers. inflateBack() trusts the application to not change the output - buffer passed by the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free the - allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects only - the raw deflate stream to decompress. This is different from the default - behavior of inflate(), which expects a zlib header and trailer around the - deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero -- buf is ignored in that - case -- and inflateBack() will return a buffer error. inflateBack() will - call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. - out() should return zero on success, or non-zero on failure. If out() - returns non-zero, inflateBack() will return with an error. Neither in() nor - out() are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format error - in the deflate stream (in which case strm->msg is set to indicate the nature - of the error), or Z_STREAM_ERROR if the stream was not properly initialized. - In the case of Z_BUF_ERROR, an input or output error can be distinguished - using strm->next_in which will be Z_NULL only if in() returned an error. If - strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning - non-zero. (in() will always be called before out(), so strm->next_in is - assured to be defined if out() returns non-zero.) Note that inflateBack() - cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: ZLIB_DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - -#ifndef Z_SOLO - - /* utility functions */ - -/* - The following utility functions are implemented on top of the basic - stream-oriented functions. To simplify the interface, some default options - are assumed (compression level and memory usage, standard memory allocation - functions). The source code of these utility functions can be modified if - you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total size - of the destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed data. compress() is equivalent to compress2() with a level - parameter of Z_DEFAULT_COMPRESSION. - - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed data. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before a - compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total size - of the destination buffer, which must be large enough to hold the entire - uncompressed data. (The size of the uncompressed data must have been saved - previously by the compressor and transmitted to the decompressor by some - mechanism outside the scope of this compression library.) Upon exit, destLen - is the actual size of the uncompressed data. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In - the case where there is not enough room, uncompress() will fill the output - buffer with the uncompressed data up to that point. -*/ - -ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong *sourceLen)); -/* - Same as uncompress, except that sourceLen is a pointer, where the - length of the source is *sourceLen. On return, *sourceLen is the number of - source bytes consumed. -*/ - - /* gzip file access functions */ - -/* - This library supports reading and writing files in gzip (.gz) format with - an interface similar to that of stdio, using the functions that start with - "gz". The gzip format is different from the zlib format. gzip is a gzip - wrapper, documented in RFC 1952, wrapped around a deflate stream. -*/ - -typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ - -/* -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); - - Opens a gzip (.gz) file for reading or writing. The mode parameter is as - in fopen ("rb" or "wb") but can also include a compression level ("wb9") or - a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only - compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' - for fixed code compression as in "wb9F". (See the description of - deflateInit2 for more information about the strategy parameter.) 'T' will - request transparent writing or appending with no compression and not using - the gzip format. - - "a" can be used instead of "w" to request that the gzip stream that will - be written be appended to the file. "+" will result in an error, since - reading and writing to the same gzip file is not supported. The addition of - "x" when writing will create the file exclusively, which fails if the file - already exists. On systems that support it, the addition of "e" when - reading or writing will set the flag to close the file on an execve() call. - - These functions, as well as gzip, will read and decode a sequence of gzip - streams in a file. The append function of gzopen() can be used to create - such a file. (Also see gzflush() for another way to do this.) When - appending, gzopen does not test whether the file begins with a gzip stream, - nor does it look for the end of the gzip streams to begin appending. gzopen - will simply append a gzip stream to the existing file. - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. When - reading, this will be detected automatically by looking for the magic two- - byte gzip header. - - gzopen returns NULL if the file could not be opened, if there was - insufficient memory to allocate the gzFile state, or if an invalid mode was - specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). - errno can be checked to determine if the reason gzopen failed was that the - file could not be opened. -*/ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen associates a gzFile with the file descriptor fd. File descriptors - are obtained from calls like open, dup, creat, pipe or fileno (if the file - has been previously opened with fopen). The mode parameter is as in gzopen. - - The next call of gzclose on the returned gzFile will also close the file - descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor - fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, - mode);. The duplicated descriptor should be saved to avoid a leak, since - gzdopen does not close fd if it fails. If you are using fileno() to get the - file descriptor from a FILE *, then you will have to use dup() to avoid - double-close()ing the file descriptor. Both gzclose() and fclose() will - close the associated file descriptor, so they need to have different file - descriptors. - - gzdopen returns NULL if there was insufficient memory to allocate the - gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not - provided, or '+' was provided), or if fd is -1. The file descriptor is not - used until the next gz* read, write, seek, or close operation, so gzdopen - will not detect if fd is invalid (unless fd is -1). -*/ - -ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); -/* - Set the internal buffer size used by this library's functions. The - default buffer size is 8192 bytes. This function must be called after - gzopen() or gzdopen(), and before any other calls that read or write the - file. The buffer memory allocation is always deferred to the first read or - write. Three times that size in buffer space is allocated. A larger buffer - size of, for example, 64K or 128K bytes will noticeably increase the speed - of decompression (reading). - - The new buffer size also affects the maximum length for gzprintf(). - - gzbuffer() returns 0 on success, or -1 on failure, such as being called - too late. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. Previously provided - data is flushed before the parameter change. - - gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not - opened for writing, Z_ERRNO if there is an error writing the flushed data, - or Z_MEM_ERROR if there is a memory allocation error. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. If - the input file is not in gzip format, gzread copies the given number of - bytes into the buffer directly from the file. - - After reaching the end of a gzip stream in the input, gzread will continue - to read, looking for another gzip stream. Any number of gzip streams may be - concatenated in the input file, and will all be decompressed by gzread(). - If something other than a gzip stream is encountered after a gzip stream, - that remaining trailing garbage is ignored (and no error is returned). - - gzread can be used to read a gzip file that is being concurrently written. - Upon reaching the end of the input, gzread will return with the available - data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then - gzclearerr can be used to clear the end of file indicator in order to permit - gzread to be tried again. Z_OK indicates that a gzip stream was completed - on the last gzread. Z_BUF_ERROR indicates that the input file ended in the - middle of a gzip stream. Note that gzread does not return -1 in the event - of an incomplete gzip stream. This error is deferred until gzclose(), which - will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip - stream. Alternatively, gzerror can be used before gzclose to detect this - case. - - gzread returns the number of uncompressed bytes actually read, less than - len for end of file, or -1 for error. If len is too large to fit in an int, - then nothing is read, -1 is returned, and the error state is set to - Z_STREAM_ERROR. -*/ - -ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, - gzFile file)); -/* - Read up to nitems items of size size from file to buf, otherwise operating - as gzread() does. This duplicates the interface of stdio's fread(), with - size_t request and return types. If the library defines size_t, then - z_size_t is identical to size_t. If not, then z_size_t is an unsigned - integer type that can contain a pointer. - - gzfread() returns the number of full items read of size size, or zero if - the end of the file was reached and a full item could not be read, or if - there was an error. gzerror() must be consulted if zero is returned in - order to determine if there was an error. If the multiplication of size and - nitems overflows, i.e. the product does not fit in a z_size_t, then nothing - is read, zero is returned, and the error state is set to Z_STREAM_ERROR. - - In the event that the end of file is reached and only a partial item is - available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevetheless read into buf - and the end-of-file flag is set. The length of the partial item read is not - provided, but could be inferred from the result of gztell(). This behavior - is the same as the behavior of fread() implementations in common libraries, - but it prevents the direct use of gzfread() to read a concurrently written - file, reseting and retrying on end-of-file, when size is not 1. -*/ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes written or 0 in case of - error. -*/ - -ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, - z_size_t nitems, gzFile file)); -/* - gzfwrite() writes nitems items of size size from buf to file, duplicating - the interface of stdio's fwrite(), with size_t request and return types. If - the library defines size_t, then z_size_t is identical to size_t. If not, - then z_size_t is an unsigned integer type that can contain a pointer. - - gzfwrite() returns the number of full items written of size size, or zero - if there was an error. If the multiplication of size and nitems overflows, - i.e. the product does not fit in a z_size_t, then nothing is written, zero - is returned, and the error state is set to Z_STREAM_ERROR. -*/ - -ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the arguments to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written, or a negative zlib error code in case - of error. The number of uncompressed bytes written is limited to 8191, or - one less than the buffer size given to gzbuffer(). The caller should assure - that this limit is not exceeded. If it is exceeded, then gzprintf() will - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. - This can be determined using zlibCompileFlags(). -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or a - newline character is read and transferred to buf, or an end-of-file - condition is encountered. If any characters are read or if len == 1, the - string is terminated with a null character. If no characters are read due - to an end-of-file or len < 1, then the buffer is left untouched. - - gzgets returns buf which is a null-terminated string, or it returns NULL - for end-of-file or in case of error. If there was an error, the contents at - buf are indeterminate. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. gzputc - returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte or -1 - in case of end of file or error. This is implemented as a macro for speed. - As such, it does not do all of the checking the other functions do. I.e. - it does not check to see if file is NULL, nor whether the structure file - points to has been clobbered or not. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read as the first character - on the next read. At least one character of push-back is allowed. - gzungetc() returns the character pushed, or -1 on failure. gzungetc() will - fail if c is -1, and may fail if a character has been pushed but not read - yet. If gzungetc is used immediately after gzopen or gzdopen, at least the - output buffer size of pushed characters is allowed. (See gzbuffer above.) - The pushed character will be discarded if the stream is repositioned with - gzseek() or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter flush - is as in the deflate() function. The return value is the zlib error number - (see function gzerror below). gzflush is only permitted when writing. - - If the flush parameter is Z_FINISH, the remaining data is written and the - gzip stream is completed in the output. If gzwrite() is called again, a new - gzip stream will be started in the output. gzread() is able to read such - concatenated gzip streams. - - gzflush should be called only when strictly necessary because it will - degrade compression if called too often. -*/ - -/* -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); - - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -/* -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); - - Returns the starting position for the next gzread or gzwrite on the given - compressed file. This position represents a number of bytes in the - uncompressed data stream, and is zero when starting, even if appending or - reading a gzip stream from the middle of a file using gzdopen(). - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -/* -ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); - - Returns the current offset in the file being read or written. This offset - includes the count of bytes that precede the gzip stream, for example when - appending or when using gzdopen() for reading. When reading, the offset - does not include as yet unused buffered input. This information can be used - for a progress indicator. On error, gzoffset() returns -1. -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns true (1) if the end-of-file indicator has been set while reading, - false (0) otherwise. Note that the end-of-file indicator is set only if the - read tried to go past the end of the input, but came up short. Therefore, - just like feof(), gzeof() may return false even if there is no more data to - read, in the event that the last read request was for the exact number of - bytes remaining in the input file. This will happen if the input file size - is an exact multiple of the buffer size. - - If gzeof() returns true, then the read functions will return no more data, - unless the end-of-file indicator is reset by gzclearerr() and the input file - has grown since the previous end of file was detected. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns true (1) if file is being copied directly while reading, or false - (0) if file is a gzip stream being decompressed. - - If the input file is empty, gzdirect() will return true, since the input - does not contain a gzip stream. - - If gzdirect() is used immediately after gzopen() or gzdopen() it will - cause buffers to be allocated to allow reading the file to determine if it - is a gzip file. Therefore if gzbuffer() is used, it should be called before - gzdirect(). - - When writing, gzdirect() returns true (1) if transparent writing was - requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: - gzdirect() is not needed when writing. Transparent writing must be - explicitly requested, so the application already knows the answer. When - linking statically, using gzdirect() will include all of the zlib code for - gzip file reading and decompression, which may not be desired.) -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file and - deallocates the (de)compression state. Note that once file is closed, you - cannot call gzerror with file, since its structures have been deallocated. - gzclose must not be called more than once on the same file, just as free - must not be called more than once on the same allocation. - - gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a - file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the - last read ended in the middle of a gzip stream, or Z_OK on success. -*/ - -ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); -ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); -/* - Same as gzclose(), but gzclose_r() is only for use when reading, and - gzclose_w() is only for use when writing or appending. The advantage to - using these instead of gzclose() is that they avoid linking in zlib - compression or decompression code that is not used when only reading or only - writing respectively. If gzclose() is used, then both compression and - decompression code will be included the application when linking to a static - zlib library. -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the given - compressed file. errnum is set to zlib error number. If an error occurred - in the file system and not in the compression library, errnum is set to - Z_ERRNO and the application may consult errno to get the exact error code. - - The application must not modify the returned string. Future calls to - this function may invalidate the previously returned string. If file is - closed, then the string previously returned by gzerror will no longer be - available. - - gzerror() should be used to distinguish errors from end-of-file for those - functions above that do not distinguish those cases in their return values. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - -#endif /* !Z_SOLO */ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the compression - library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is Z_NULL, this function returns the - required initial value for the checksum. - - An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed - much faster. - - Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, - z_size_t len)); -/* - Same as adler32(), but with a size_t length. -*/ - -/* -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); - - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note - that the z_off_t type (like off_t) is a signed integer. If len2 is - negative, the result has no meaning or utility. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is Z_NULL, this function returns the required - initial value for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, - z_size_t len)); -/* - Same as crc32(), but with a size_t length. -*/ - -/* -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#ifdef Z_PREFIX_SET -# define z_deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) -# define z_inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) -# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) -# define z_inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ - (int)sizeof(z_stream)) -# define z_inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, (int)sizeof(z_stream)) -#else -# define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) -# define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) -# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) -# define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ - (int)sizeof(z_stream)) -# define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, (int)sizeof(z_stream)) -#endif - -#ifndef Z_SOLO - -/* gzgetc() macro and its supporting function and exposed data structure. Note - * that the real internal state is much larger than the exposed structure. - * This abbreviated structure exposes just enough for the gzgetc() macro. The - * user should not mess with these exposed elements, since their names or - * behavior could change in the future, perhaps even capriciously. They can - * only be used by the gzgetc() macro. You have been warned. - */ -struct gzFile_s { - unsigned have; - unsigned char *next; - z_off64_t pos; -}; -ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ -#ifdef Z_PREFIX_SET -# undef z_gzgetc -# define z_gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) -#else -# define gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) -#endif - -/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or - * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if - * both are true, the application gets the *64 functions, and the regular - * functions are changed to 64 bits) -- in case these are set on systems - * without large file support, _LFS64_LARGEFILE must also be true - */ -#ifdef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); -#endif - -#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) -# ifdef Z_PREFIX_SET -# define z_gzopen z_gzopen64 -# define z_gzseek z_gzseek64 -# define z_gztell z_gztell64 -# define z_gzoffset z_gzoffset64 -# define z_adler32_combine z_adler32_combine64 -# define z_crc32_combine z_crc32_combine64 -# else -# define gzopen gzopen64 -# define gzseek gzseek64 -# define gztell gztell64 -# define gzoffset gzoffset64 -# define adler32_combine adler32_combine64 -# define crc32_combine crc32_combine64 -# endif -# ifndef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); -# endif -#else - ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); -#endif - -#else /* Z_SOLO */ - - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); - -#endif /* !Z_SOLO */ - -/* undocumented functions */ -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); -ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); -ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); -ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); -ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); -#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) -ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, - const char *mode)); -#endif -#if defined(STDC) || defined(Z_HAVE_STDARG_H) -# ifndef Z_SOLO -ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, - const char *format, - va_list va)); -# endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ diff --git a/libraries/zlib/zutil.c b/libraries/zlib/zutil.c deleted file mode 100644 index a76c6b0c7e5..00000000000 --- a/libraries/zlib/zutil.c +++ /dev/null @@ -1,325 +0,0 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2017 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" -#ifndef Z_SOLO -# include "gzguts.h" -#endif - -z_const char * const z_errmsg[10] = { - (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ - (z_const char *)"stream end", /* Z_STREAM_END 1 */ - (z_const char *)"", /* Z_OK 0 */ - (z_const char *)"file error", /* Z_ERRNO (-1) */ - (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ - (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ - (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ - (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ - (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ - (z_const char *)"" -}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch ((int)(sizeof(uInt))) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch ((int)(sizeof(uLong))) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch ((int)(sizeof(voidpf))) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch ((int)(sizeof(z_off_t))) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef ZLIB_DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1L << 16; -#endif -#ifdef NO_GZIP - flags += 1L << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1L << 20; -#endif -#ifdef FASTEST - flags += 1L << 21; -#endif -#if defined(STDC) || defined(Z_HAVE_STDARG_H) -# ifdef NO_vsnprintf - flags += 1L << 25; -# ifdef HAS_vsprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1L << 26; -# endif -# endif -#else - flags += 1L << 24; -# ifdef NO_snprintf - flags += 1L << 25; -# ifdef HAS_sprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1L << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef ZLIB_DEBUG -#include -# ifndef verbose -# define verbose 0 -# endif -int ZLIB_INTERNAL z_verbose = verbose; - -void ZLIB_INTERNAL z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. - */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void ZLIB_INTERNAL zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int ZLIB_INTERNAL zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void ZLIB_INTERNAL zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - -#ifndef Z_SOLO - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf; - ulg bsize = (ulg)items*size; - - (void)opaque; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ - int n; - - (void)opaque; - - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) -{ - (void)opaque; - return _halloc((long)items, size); -} - -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ - (void)opaque; - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - (void)opaque; - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void ZLIB_INTERNAL zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - (void)opaque; - free(ptr); -} - -#endif /* MY_ZCALLOC */ - -#endif /* !Z_SOLO */ diff --git a/libraries/zlib/zutil.h b/libraries/zlib/zutil.h deleted file mode 100644 index b079ea6a80f..00000000000 --- a/libraries/zlib/zutil.h +++ /dev/null @@ -1,271 +0,0 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#ifdef HAVE_HIDDEN -# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) -#else -# define ZLIB_INTERNAL -#endif - -#include "zlib.h" - -#if defined(STDC) && !defined(Z_SOLO) -# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) -# include -# endif -# include -# include -#endif - -#ifdef Z_SOLO - typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ -#endif - -#ifndef local -# define local static -#endif -/* since "static" is used to mean two completely different things in C, we - define "local" for the non-static meaning of "static", for readability - (compile with -Dlocal if your debugger can't find static symbols) */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# ifndef Z_SOLO -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 1 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 2 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#ifdef __370__ -# if __TARGET_LIB__ < 0x20000000 -# define OS_CODE 4 -# elif __TARGET_LIB__ < 0x40000000 -# define OS_CODE 11 -# else -# define OS_CODE 8 -# endif -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 5 -#endif - -#ifdef OS2 -# define OS_CODE 6 -# if defined(M_I86) && !defined(Z_SOLO) -# include -# endif -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 7 -# ifndef Z_SOLO -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -# endif -#endif - -#ifdef __acorn -# define OS_CODE 13 -#endif - -#if defined(WIN32) && !defined(__CYGWIN__) -# define OS_CODE 10 -#endif - -#ifdef _BEOS_ -# define OS_CODE 16 -#endif - -#ifdef __TOS_OS400__ -# define OS_CODE 18 -#endif - -#ifdef __APPLE__ -# define OS_CODE 19 -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - -#if defined(__BORLANDC__) && !defined(MSDOS) - #pragma warn -8004 - #pragma warn -8008 - #pragma warn -8066 -#endif - -/* provide prototypes for these when building zlib without LFS */ -#if !defined(_WIN32) && \ - (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 3 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(pyr) || defined(Z_SOLO) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef ZLIB_DEBUG -# include - extern int ZLIB_INTERNAL z_verbose; - extern void ZLIB_INTERNAL z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - -#ifndef Z_SOLO - voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, - unsigned size)); - void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); -#endif - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -/* Reverse the bytes in a 32-bit value */ -#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -#endif /* ZUTIL_H */ diff --git a/options.checklist b/options.checklist new file mode 100644 index 00000000000..c2cfa95e28b --- /dev/null +++ b/options.checklist @@ -0,0 +1,34 @@ +N/A weapon_recoil Firing a weapon pushes the player back +---N/A (todo, lastenemy?) monsters_remember 1 Friendly monsters return to old target when losing current one +!LEVEL2_NOINFIGHTING monster_infighting 1 Monsters infight +LEVEL3_AVOIDMELEE monster_backing Ranged monsters will back away from close melee targets +COMPATF2_AVOID_HAZARDS monster_avoid_hazards 1 Monsters avoid hazards such as crushing ceilings +N/A monkeys Monsters can climb steep stairs +COMPATF_MBFMONSTERMOVE monster_friction 1 Monsters are affected by friction modifiers + help_friends Friendly monsters prefer targets of friends + player_helpers Number of dogs to spawn + friend_distance 128 Friendly monsters try to keep at least this distance apart +!LEVEL3_NOJUMPDOWN dog_jumping 1 Dogs can jump down from high ledges +N/A comp_telefrag Spawners only telefrag on Map 30 +COMPATF_DROPOFF comp_dropoff 01 Discourage / prevent enemies from walking off ledges (?) +COMPATF_CORPSEGIBS,BCOMPATF_VILEGHOSTS comp_vile Archviles can create ghosts +COMPATF_LIMITPAIN comp_pain Pain elementals don't spawn lost souls if there are over 20 +--- N/A (todo) comp_skull Lost souls can spawn past impassable lines +N/A comp_blazing Blazing doors have double sounds +COMPATF_NODOORLIGHT comp_doorlight Door lighting changes are abrupt +COMPATF_LIGHT,COMPATF_SHORTTEX (partial) comp_model Assorted physics quirks and bugs +N/A comp_god God mode is removed in sector 11 & ignored at 1000+ damage +N/A comp_falloff Don't pull monsters off ledges they are hanging off of +COMPATF2_FLOORMOVE comp_floors Assorted floor bugs +N/A comp_skymap Don't apply invulnerability palette to skies +---todo comp_pursuit 1 Monsters can infight immediately when alerted +N/A comp_doorstuck Monsters get stuck in door tracks +COMPATF2_STAYONLIFT comp_staylift Monsters don't prefer staying on lifts their target is on +N/A comp_zombie Dead players can activate things +COMPATF_STAIRINDEX comp_stairs Assorted stair bugs +N/A comp_infcheat ? +N/A comp_zerotags Allow tag zero actions +N/A comp_respawn Monsters not spawned at level start respawn at the origin +N/A comp_soul Buggy lost soul bouncing +COMPATF_CROSSDROPOFF comp_ledgeblock 10 Monsters are blocked by ledges (except when scrolling) +---todo comp_friendlyspawn 1 Spawned things inherit the friend attribute from the source \ No newline at end of file diff --git a/soundfont/gzdoom.sf2 b/soundfont/gzdoom.sf2 index 27cc01c187c..702f7ffcdd6 100644 Binary files a/soundfont/gzdoom.sf2 and b/soundfont/gzdoom.sf2 differ diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 7b5b2d35744..73e94ea8a0e 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -1,5 +1,5 @@ =============================================================================== -Universal Doom Map Format ZDoom extensions v1.15 - 14.12.2010 +Universal Doom Map Format ZDoom extensions v1.33 15.09.2023 Copyright (c) 2008 Christoph Oelckers. @@ -118,8 +118,11 @@ Note: All fields default to false unless mentioned otherwise. blockuse = ; // Line blocks all use actions blocksight = ; // Line blocks monster line of sight blockhitscan = ; // Line blocks hitscan attacks + blockfloaters = ; // Line blocks floating monsters' movement. + blocklandmonsters = ; // Line blocks walking monsters' movement. locknumber = ; // Line special is locked arg0str = ; // Alternate string-based version of arg0 + arg1str = ; // Alternate string-based version of arg1 moreids = ; // Additional line IDs, specified as a space separated list of numbers (e.g. "2 666 1003 4505") transparent = ; // true = line is a Strife transparent line (alpha 0.25) @@ -152,35 +155,49 @@ Note: All fields default to false unless mentioned otherwise. For lines with ACS specials (80-86 and 226), if arg0str is present and non-null, it will be used as the name of the script to execute, and arg0 will be ignored. + + lm_sampledist_line = ; // ZDRay customizable sampling distance for this line. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + lm_sampledist_top = ; // ZDRay customizable sampling distance for this line's top part. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + lm_sampledist_mid = ; // ZDRay customizable sampling distance for this line's middle part. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + lm_sampledist_bot = ; // ZDRay customizable sampling distance for this line's bottom part. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 } sidedef { - scalex_top = ; // X scale for upper texture, Default = 1.0. - scaley_top = ; // y scale for upper texture, Default = 1.0. - scalex_mid = ; // X scale for mid texture, Default = 1.0. - scaley_mid = ; // y scale for mid texture, Default = 1.0. - scalex_bottom = ; // X scale for lower texture, Default = 1.0. - scaley_bottom = ; // y scale for lower texture, Default = 1.0. - offsetx_top = ; // X offset for upper texture, Default = 0.0. - offsety_top = ; // y offset for upper texture, Default = 0.0. - offsetx_mid = ; // X offset for mid texture, Default = 0.0. - offsety_mid = ; // y offset for mid texture, Default = 0.0. - offsetx_bottom = ; // X offset for lower texture, Default = 0.0. - offsety_bottom = ; // y offset for lower texture, Default = 0.0. - // When global texture offsets are used they will - // be added on top of these values. - light = ; // This side's light level. Default is 0. - lightabsolute = ; // true = 'light' is an absolute value. Default is - // relative to the owning sector's light level. - lightfog = ; // true = This side's relative lighting is used even in - // foggy sectors. Default is to disable relative - // lighting in foggy sectors. - nofakecontrast = ; // Disables use of fake contrast on this sidedef. - smoothlighting = ; // Use smooth fake contrast. - clipmidtex = ; // Side's mid textures are clipped to floor and ceiling. - wrapmidtex = ; // Side's mid textures are wrapped. - nodecals = ; // Disables decals on the sidedef. + scalex_top = ; // X scale for upper texture, Default = 1.0. + scaley_top = ; // Y scale for upper texture, Default = 1.0. + scalex_mid = ; // X scale for mid texture, Default = 1.0. + scaley_mid = ; // Y scale for mid texture, Default = 1.0. + scalex_bottom = ; // X scale for lower texture, Default = 1.0. + scaley_bottom = ; // Y scale for lower texture, Default = 1.0. + offsetx_top = ; // X offset for upper texture, Default = 0.0. + offsety_top = ; // Y offset for upper texture, Default = 0.0. + offsetx_mid = ; // X offset for mid texture, Default = 0.0. + offsety_mid = ; // Y offset for mid texture, Default = 0.0. + offsetx_bottom = ; // X offset for lower texture, Default = 0.0. + offsety_bottom = ; // Y offset for lower texture, Default = 0.0. + // When global texture offsets are used they will + // be added on top of these values. + light = ; // This side's light level. Default is 0. + lightabsolute = ; // true = 'light' is an absolute value. Default is + // relative to the owning sector's light level. + light_top = ; // This side's top tier light level. Default is 0. + lightabsolute_top = ; // true = 'light_top' is an absolute value. Default is + // relative to the sidedef's resulting light level. + light_mid = ; // This side's mid tier light level. Default is 0. + lightabsolute_mid = ; // true = 'light_mid' is an absolute value. Default is + // relative to the sidedef's resulting light level. + light_bottom = ; // This side's bottom tier light level. Default is 0. + lightabsolute_bottom = ; // true = 'light_bottom' is an absolute value. Default is + // relative to the sidedef's resulting light level. + lightfog = ; // true = This side's relative lighting is used even in + // foggy sectors. Default is to disable relative + // lighting in foggy sectors. + nofakecontrast = ; // Disables use of fake contrast on this sidedef. + smoothlighting = ; // Use smooth fake contrast. + clipmidtex = ; // Side's mid textures are clipped to floor and ceiling. + wrapmidtex = ; // Side's mid textures are wrapped. + nodecals = ; // Disables decals on the sidedef. nogradient_top = ; // disables color gradient on upper tier. (Hardware rendering only.) flipgradient_top = ; // flips gradient colors on upper tier. (Hardware rendering only.) @@ -202,9 +219,6 @@ Note: All fields default to false unless mentioned otherwise. useowncolors_bottom = ; // Set to 1 to use the colors set in the sidedef. Default is using the colors from the owning sector. uppercolor_bottom = ; // Material color of the top of the lower tier. lowercolor_bottom = ; // Material color of the bottom of the lower tier. (Hardware rendering only.) - colorscalefactor_top = // scales the material color by the given factor. Default is 1. - colorscalefactor_mid = // scales the material color by the given factor. Default is 1. - colorscalefactor_bottom = // scales the material color by the given factor. Default is 1. useowncoloradd_top = ; // Controls where the advanced colorization properties are taken from. useowncoloradd_mid = ; // 0: From the containing sector, 1: from the given part of the linedef itself @@ -215,6 +229,27 @@ Note: All fields default to false unless mentioned otherwise. colorization_top = ; // Sets a colorization record for the upper texture. Colorization records must be defined in TEXTURES. colorization_mid = ; // Sets a colorization record for the middle texture. Colorization records must be defined in TEXTURES. colorization_bottom = ; // Sets a colorization record for the lower texture. Colorization records must be defined in TEXTURES. + + lm_sampledist_line = ; // ZDRay customizable sampling distance for this sidedef. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + lm_sampledist_top = ; // ZDRay customizable sampling distance for this sidedef's top part. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + lm_sampledist_mid = ; // ZDRay customizable sampling distance for this sidedef's middle part. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + lm_sampledist_bot = ; // ZDRay customizable sampling distance for this sidedef's bottom part. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + + skew_top = ; // enables skewing of wall textures, the skewing angle will be aligned to one of the 4 planes touching the floor. + skew_middle = ; // Vertical texture alignment defines the position at the leftmost point of the wall. + skew_bottom = ; // Possible values: 0 = no skewing, 1 = align to front floor, 2 = align to front ceiling, 3 = align to back floor, 4 = align to back ceiling. + // Front/Back are relative to the sidedef, not the owning linedef. Default = 0. + + xscroll = ; // wall scrolling X speed in map units per tic. + yscroll = ; // wall scrolling Y speed in map units per tic. + xscrolltop = ; // upper wall scrolling X speed in map units per tic. + yscrolltop = ; // upper wall scrolling Y speed in map units per tic. + xscrollmid = ; // mid wall scrolling X speed in map units per tic. + yscrollmid = ; // mid wall scrolling Y speed in map units per tic. + xscrollbottom = ; // lower wall scrolling X speed in map units per tic. + yscrollbottom = ; // lower wall scrolling Y speed in map units per tic. + + } sector @@ -313,6 +348,38 @@ Note: All fields default to false unless mentioned otherwise. healthfloorgroup = ; // ID of destructible object to synchronize hitpoints (optional, default is 0) healthceiling = ; // Amount of hitpoints for this sector (includes ceiling and top-outside linedef sides) healthceilinggroup = ; // ID of destructible object to synchronize hitpoints (optional, default is 0) + health3d = ; // Amount of hitpoints for this sector (includes 3D floors) + health3dgroup = ; // ID of destructible object to synchronize hitpoints (optional, default is 0) + + xscrollfloor = ; // X map units per frame to scroll the floor. + yscrollfloor = ; // Y map units per frame to scroll the floor. + scrollfloormode = ; // Floor scroll mode bit mask (1 = scroll textures, 2 = carry static objects, 4 = carry players, 8 = carry monsters. + xscrollceiling = ; // X map units per frame to scroll the ceiling. + yscrollceiling = ; // Y map units per frame to scroll the ceiling. + scrollceilingmode = ; // ceiling scroll mode bit mask (1 = scroll textures, 2 = carry static objects, 4 = carry players, 8 = carry monsters. + + scroll_ceil_x = ; // deprecated Eternity based alternatives for the above. + scroll_ceil_y = ; // Due to using unintuitive units of measurement and a more limited feature set they should not be used anymore. + scroll_ceil_type = ; + scroll_floor_x = ; + scroll_floor_y = ; + scroll_floor_type = ; + + friction = ; // sets the sector's friction factor. Must be between 0 and 1. + movefactor = // sets the sector's movement acceleration factor. Must be > 0. + + skyfloor = // defines lower sky for this sector. + skyceiling = // defines upper sky for this sector. + skyfloor2 = // defines secondary lower sky for this sector. (for lightning or transparent layers) + skyceiling2 = // defines secondary upper sky for this sector. + + colormap = ; // only provided for backwards compatibility. Do not use in GZDoom projects. + + xthrust = ; // applies thrust to actors - x-magnitude + ythrust = ; // applies thrust to actors - y-magnitude + thrustgroup = ; // specifies which actors get thrusted. Bitfield with (1 = static objects, 2 = player, 4 = monsters, 8 = projectiles, 16 = actors with +WINDTHRUST) + thrustlocation = ; // specifies where in the sector actors get thrusted: (1 = on the ground, 2 = in the air, 4 = on the ceiling) + * Note about dropactors @@ -320,6 +387,9 @@ Note: All fields default to false unless mentioned otherwise. for Doom format maps so any map converter converting to the ZDoomTranslated namespace should set this flag for each tagged sector. + lm_sampledist_floor = ; // ZDRay customizable sampling distance for this sector's floor. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + lm_sampledist_ceiling = ; // ZDRay customizable sampling distance for this sector's ceiling. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 0 + lm_dynamic = ; // ZDRay marks a sector's lightmaps as dynamic so that they may be updated in realtime (used for flickering lights, changing a lightmap light's position, color etc). Default = false } thing @@ -329,7 +399,9 @@ Note: All fields default to false unless mentioned otherwise. conversation = // Assigns a conversation dialogue to this thing. // Parameter is the conversation ID, 0 meaning none. countsecret = ; // Picking up this actor counts as a secret. + nocount = ; // When true, object does not count toward kills or items. arg0str = ; // Alternate string-based version of arg0 + arg1str = ; // Alternate string-based version of arg1 gravity = ; // Set per-actor gravity. Positive values are multiplied with the class's property, // negative values are used as their absolute. Default = 1.0. @@ -350,6 +422,12 @@ Note: All fields default to false unless mentioned otherwise. scale = ; // Vertical and horizontal scaling on thing. Default = 0 (ignored). floatbobphase = ; // Sets the thing's floatbobphase. Valid phase values are 0-63. Default = -1 (use actor class default). + lm_sampledist = ; // ZDRay lightmap sample distance for the entire map. Defines the map units each lightmap texel covers. Must be in powers of two. Default = 8 + lm_suncolor = ; // ZDRay lightmap sun color in hex. Default = "FFFFFF" + SoftShadowRadius = ; // ZDRay lightmap light and raytraced dynamic light soft shadow amount. Higher values produce softer shadows. Default = 5.0 + + friendlyseeblocks = ; // How far (in block units) a friendly monster can see other monsters. Default 10 + * Note about arg0str For things with ACS specials (80-86 and 226), if arg0str is present and non-null, it @@ -393,7 +471,6 @@ Note: All fields default to false unless mentioned otherwise. Bit 5 (Value 32): midtex3d Bit 6 (Value 64): checkswitchrange Bit 7 (Value 128): firstsideonly - When used in special 208 this arg should be cleared afterward. Special 121 is not being used by UDMF maps in ZDoom and should be completely @@ -508,6 +585,21 @@ Replaced tabs with spaces. 1.31 22.12.2019 Coloriation options added +1.32 28.06.2021 +Blocklandmonsters MBF21 flag + +1.33 06.11.2021 +Added separate light levels for sidedef tiers (top/mid/bottom) + +1.34 11.09.2023 +Added/updated ZDRay/lightmap-related properties. + +1.35 15.09.2023 +fixed omissions: Blocklandmonsters and Blockfloaters line flags. + +1.36 20.10.2023 +Sidedef skewing properties + =============================================================================== EOF =============================================================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb5b84fa7bf..37d5d483925 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required( VERSION 2.8.7 ) +cmake_minimum_required( VERSION 3.16.0 ) include(precompiled_headers) @@ -14,26 +14,7 @@ include( CheckIncludeFiles ) include( CheckLibraryExists ) include( FindPkgConfig ) -if( MSVC ) - find_package( ZMusic ) -else() - find_package( ZMusic REQUIRED ) -endif() - -if( MSVC AND NOT ZMUSIC_FOUND ) - # Use prebuilt library - set( ZMUSIC_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../bin/windows/zmusic" ) - set( ZMUSIC_INCLUDE_DIR ${ZMUSIC_ROOT_PATH}/include ) - set( ZMUSIC_LIBRARIES zmusic ) - if( ${ZDOOM_TARGET_ARCH} MATCHES "x86_64" ) - link_directories( ${ZMUSIC_ROOT_PATH}/64bit ) - else() - link_directories( ${ZMUSIC_ROOT_PATH}/32bit ) - endif() - set( ZMUSIC_FOUND TRUE ) -endif() - -if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) +if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) option( NO_STRIP "Do not strip Release or MinSizeRel builds" ) # At least some versions of Xcode fail if you strip with the linker # instead of the separate strip utility. @@ -46,61 +27,39 @@ if( APPLE ) option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON ) endif() -if( ${ZDOOM_TARGET_ARCH} MATCHES "x86_64" ) - set( X64 64 ) +option( ZDOOM_ENABLE_SWR "Enable software renderer" ON ) +if( NOT ZDOOM_ENABLE_SWR ) + add_definitions( -DNO_SWRENDERER ) +endif() + +target_architecture(TARGET_ARCHITECTURE) +message(STATUS "Architecture is ${TARGET_ARCHITECTURE}") + +if ( ${TARGET_ARCHITECTURE} MATCHES "arm64" ) + set (ARM64 aarch64) endif() -if( X64 OR ${ZDOOM_TARGET_ARCH} MATCHES "i386" ) +# Right now only 64 bit is supported. +if( ${TARGET_ARCHITECTURE} MATCHES "x86_64" ) + set( X64 64 ) add_definitions( -DARCH_IA32 ) endif() -if( NOT ZDOOM_LIBS ) - set( ZDOOM_LIBS "" ) +if( NOT PROJECT_LIBRARIES ) + set( PROJECT_LIBRARIES "" ) endif() +add_definitions( -DTHIS_IS_GZDOOM ) + if( WIN32 ) - if( X64 ) - set( WIN_TYPE Win64 ) - set( XBITS x64 ) - else() - set( WIN_TYPE Win32 ) - set( XBITS x86 ) - endif() add_definitions( -D_WIN32 ) - - if( MSVC ) # For VS 2017 and later. - # for modern Windows SDKs the DirectX headers should be available by default. - set( DX_dinput8_LIBRARY dinput8 ) - else() - - find_library( DX_dinput8_LIBRARY dinput8 - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - find_library( DX_dxguid_LIBRARY dxguid - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - - # Modern versions of the Windows SDK include dinput8.lib. Unfortunately, - # CMake cannot find these libraries via find_library. - if( NOT DX_dinput8_LIBRARY ) - # If we got this far, assume dinput8.lib is in the system library path. - set( DX_dinput8_LIBRARY dinput8 ) - endif() - - # Modern versions of the Windows SDK do NOT include dxguid.lib. Its contents - # were moved to dinput8.lib. - if( NOT DX_dxguid_LIBRARY ) - message( STATUS "Could not find dxguid.lib. Build may fail on old Windows SDKs.") - endif() - endif() - - set( ZDOOM_LIBS - opengl32 + set( PROJECT_LIBRARIES + psapi wsock32 winmm - "${DX_dinput8_LIBRARY}" + dinput8 ole32 user32 gdi32 @@ -109,17 +68,13 @@ if( WIN32 ) ws2_32 setupapi oleaut32 - dbghelp ) - - if( NOT ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} DelayImp ) - endif() + dbghelp + legacy_stdio_definitions ) - if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) + if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) if( DX_dxguid_LIBRARY ) - list( APPEND ZDOOM_LIBS "${DX_dxguid_LIBRARY}" ) + list( APPEND PROJECT_LIBRARIES "${DX_dxguid_LIBRARY}" ) endif() - list( APPEND ZDOOM_LIBS d3d9 ) endif() else() if( APPLE ) @@ -140,17 +95,17 @@ else() pkg_check_modules( GTK3 gtk+-3.0 ) if( GTK3_FOUND ) if( NOT DYN_GTK ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK3_LIBRARIES} ) + set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} ${GTK3_LIBRARIES} ) endif() - include_directories( ${GTK3_INCLUDE_DIRS} ) + include_directories( SYSTEM ${GTK3_INCLUDE_DIRS} ) link_directories( ${GTK3_LIBRARY_DIRS} ) else() pkg_check_modules( GTK2 gtk+-2.0 ) if( GTK2_FOUND ) if( NOT DYN_GTK ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} ) + set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} ${GTK2_LIBRARIES} ) endif() - include_directories( ${GTK2_INCLUDE_DIRS} ) + include_directories( SYSTEM ${GTK2_INCLUDE_DIRS} ) link_directories( ${GTK2_LIBRARY_DIRS} ) else() set( NO_GTK ON ) @@ -159,6 +114,13 @@ else() endif() endif() + if ( NOT WIN32 ) + option( NO_SDL_JOYSTICK "Disable SDL joystick support (Not applicable to Windows)" OFF ) + if ( NO_SDL_JOYSTICK ) + add_definitions( -DNO_SDL_JOYSTICK=1 ) + endif() + endif() + if( NO_GTK ) add_definitions( -DNO_GTK ) elseif( DYN_GTK ) @@ -170,26 +132,28 @@ else() # Non-Windows version also needs SDL except native OS X backend if( NOT APPLE OR NOT OSX_COCOA_BACKEND ) find_package( SDL2 REQUIRED ) - include_directories( "${SDL2_INCLUDE_DIR}" ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SDL2_LIBRARY}" ) + include_directories( SYSTEM "${SDL2_INCLUDE_DIR}" ) + set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} "${SDL2_LIBRARY}" ) endif() - find_path( FPU_CONTROL_DIR fpu_control.h ) - if( FPU_CONTROL_DIR ) - include_directories( ${FPU_CONTROL_DIR} ) - add_definitions( -DHAVE_FPU_CONTROL ) - endif() endif() if( NOT NO_OPENAL ) - if ( NOT DYN_OPENAL ) # DYN_OPENAL uses local copies of the headers. + if ( "vcpkg-openal-soft" IN_LIST VCPKG_MANIFEST_FEATURES ) + # Statically link to OpenAL from vcpkg + find_package( OpenAL CONFIG REQUIRED ) + list( APPEND PROJECT_LIBRARIES OpenAL::OpenAL ) + elseif ( NOT DYN_OPENAL ) # DYN_OPENAL uses local copies of the headers. find_package( OpenAL ) mark_as_advanced(CLEAR OPENAL_INCLUDE_DIR) if( OPENAL_INCLUDE_DIR ) - include_directories( ${OPENAL_INCLUDE_DIR} ) + include_directories( SYSTEM ${OPENAL_INCLUDE_DIR} ) mark_as_advanced(CLEAR OPENAL_LIBRARY) if( OPENAL_LIBRARY ) - set( ZDOOM_LIBS ${OPENAL_LIBRARY} ${ZDOOM_LIBS} ) + set( PROJECT_LIBRARIES ${OPENAL_LIBRARY} ${PROJECT_LIBRARIES} ) + if( APPLE ) + set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} "-framework AudioUnit -framework CoreAudio -framework ApplicationServices -framework AudioToolbox -framework CoreFoundation" ) + endif() else() set( NO_OPENAL ON ) endif() @@ -207,40 +171,8 @@ endif() # Decide on SSE setup -set( SSE_MATTERS NO ) - -# with global use of SSE 2 we do not need special handling for selected files -if (NOT ZDOOM_USE_SSE2) - # SSE only matters on 32-bit targets. We check compiler flags to know if we can do it. - if( CMAKE_SIZEOF_VOID_P MATCHES "4" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES ppc ) - CHECK_CXX_COMPILER_FLAG( "-msse2 -mfpmath=sse" CAN_DO_MFPMATH ) - CHECK_CXX_COMPILER_FLAG( -arch:SSE2 CAN_DO_ARCHSSE2 ) - if( CAN_DO_MFPMATH ) - set( SSE1_ENABLE "-msse -mfpmath=sse" ) - set( SSE2_ENABLE "-msse2 -mfpmath=sse" ) - set( SSE_MATTERS YES ) - elseif( CAN_DO_ARCHSSE2 ) - set( SSE1_ENABLE -arch:SSE ) - set( SSE2_ENABLE -arch:SSE2 ) - set( SSE_MATTERS YES ) - endif() - endif() -endif() - if( X64 ) set( HAVE_MMX 1 ) -else( X64 ) - set( SAFE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ) - - if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmmx") - endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - - CHECK_CXX_SOURCE_COMPILES("#include - int main(void) { __m64 v = _m_from_int(0); }" - HAVE_MMX) - - set( CMAKE_CXX_FLAGS ${SAFE_CMAKE_CXX_FLAGS} ) endif( X64 ) CHECK_CXX_SOURCE_COMPILES("#include @@ -260,7 +192,7 @@ endif (MSVC) # Set up flags for GCC -if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) +if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) if( PROFILE ) set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" ) @@ -268,7 +200,6 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" ) endif() - set( REL_CXX_FLAGS "-fno-rtti" ) if( NOT PROFILE AND NOT APPLE ) # On OS X frame pointers are required for exception handling, at least with Clang set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" ) @@ -309,7 +240,7 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" ) endif() - if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) + if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) if( APPLE OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "3.6" ) set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" ) endif() @@ -317,45 +248,11 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" ) - # ARM processors (Raspberry Pi, et al) - enable ARM NEON support. - if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") - set (USE_ARMV8 0 CACHE BOOL "Use ARMv8 instructions - Raspberry Pi 3") - if (USE_ARMV8) - set( CMAKE_CXX_FLAGS "-mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mtune=cortex-a53 -mhard-float -DNO_SSE ${CMAKE_CXX_FLAGS}" ) - else () - set( CMAKE_CXX_FLAGS "-mcpu=cortex-a7 -mfpu=neon-vfpv4 -mtune=cortex-a7 -mhard-float -DNO_SSE ${CMAKE_CXX_FLAGS}" ) - endif () - endif () - if( NOT X64 AND NOT CAN_DO_MFPMATH ) set( CMAKE_C_FLAGS "-DNO_SSE ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-DNO_SSE ${CMAKE_CXX_FLAGS}" ) endif() - # Use the highest C++ standard available since VS2015 compiles with C++14 - # but we only require C++11. The recommended way to do this in CMake is to - # probably to use target_compile_features, but I don't feel like maintaining - # a list of features we use. - CHECK_CXX_COMPILER_FLAG( "-std=gnu++14" CAN_DO_CPP14 ) - if ( CAN_DO_CPP14 ) - set ( CMAKE_CXX_FLAGS "-std=gnu++14 ${CMAKE_CXX_FLAGS}" ) - else () - CHECK_CXX_COMPILER_FLAG( "-std=gnu++1y" CAN_DO_CPP1Y ) - if ( CAN_DO_CPP1Y ) - set ( CMAKE_CXX_FLAGS "-std=gnu++1y ${CMAKE_CXX_FLAGS}" ) - else () - CHECK_CXX_COMPILER_FLAG( "-std=gnu++11" CAN_DO_CPP11 ) - if ( CAN_DO_CPP11 ) - set ( CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}" ) - else () - CHECK_CXX_COMPILER_FLAG( "-std=gnu++0x" CAN_DO_CPP0X ) - if ( CAN_DO_CPP0X ) - set ( CMAKE_CXX_FLAGS "-std=gnu++0x ${CMAKE_CXX_FLAGS}" ) - endif () - endif () - endif () - endif () - # Remove extra warnings when using the official DirectX headers. # Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid, # which is a royal pain. The previous version I had been using was fine with them. @@ -372,6 +269,10 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC" ) endif() + + if(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") + set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -ljemalloc") + endif() if( NOT NO_STRIP ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s" ) @@ -381,25 +282,12 @@ endif() # Check for thread_local keyword, it's optional at the moment -CHECK_CXX_SOURCE_COMPILES("thread_local int i; int main() { i = 0; }" - HAVE_THREAD_LOCAL) - -if( NOT HAVE_THREAD_LOCAL ) +if ( NOT (cxx_thread_local IN_LIST CMAKE_CXX_COMPILE_FEATURES) ) message( SEND_ERROR "C++ compiler doesn't support thread_local storage duration specifier" ) endif() # Check for functions that may or may not exist. -CHECK_FUNCTION_EXISTS( filelength FILELENGTH_EXISTS ) -if( FILELENGTH_EXISTS ) - add_definitions( -DHAVE_FILELENGTH=1 ) -endif() - -CHECK_FUNCTION_EXISTS( strupr STRUPR_EXISTS ) -if( NOT STRUPR_EXISTS ) - add_definitions( -DNEED_STRUPR=1 ) -endif() - require_stricmp() require_strnicmp() @@ -416,7 +304,7 @@ if( UNIX ) add_definitions( -DNO_CLOCK_GETTIME ) endif() else() - set( ZDOOM_LIBS ${ZDOOM_LIBS} rt ) + list( APPEND PROJECT_LIBRARIES rt ) endif() endif() @@ -429,119 +317,195 @@ add_custom_target( revision_check ALL WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) -# Libraries ZDoom needs +# required libraries -set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${CMAKE_DL_LIBS}" ) +set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} miniz "${BZIP2_LIBRARIES}" "${CMAKE_DL_LIBS}" "${DRPC_LIBRARIES}") if (HAVE_VULKAN) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "glslang" "SPIRV" "OGLCompiler") + list( APPEND PROJECT_LIBRARIES "zvulkan" ) endif() -include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${ZMUSIC_INCLUDE_DIR}" ) + +list( APPEND PROJECT_LIBRARIES "zwidget" ) +list( APPEND PROJECT_LIBRARIES "webp" ) + +# ZMUSIC + +if( MSVC ) + find_package( ZMusic ) +else() + find_package( ZMusic REQUIRED ) +endif() + +message("Building for target architecture: ${TARGET_ARCHITECTURE}") + +if( MSVC AND NOT ZMUSIC_FOUND ) + # Use prebuilt library + set( ZMUSIC_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../bin/windows/zmusic" ) + set( ZMUSIC_INCLUDE_DIR ${ZMUSIC_ROOT_PATH}/include ) + set( ZMUSIC_LIBRARIES zmusic ) + if( X64 ) + link_directories( ${ZMUSIC_ROOT_PATH}/64bit ) + elseif( ARM64 ) + link_directories( ${ZMUSIC_ROOT_PATH}/arm64 ) + else() + link_directories( ${ZMUSIC_ROOT_PATH}/32bit ) + endif() + set( ZMUSIC_FOUND TRUE ) +endif() + + +# VPX + +if( MSVC AND NOT VPX_FOUND ) + # Use prebuilt library + set( VPX_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../bin/Windows/vpx" ) + set( VPX_INCLUDE_DIR ${VPX_ROOT_PATH}/include ) + set( VPX_LIBRARIES libvpx ) + if ( NOT ARM64 ) + set (VPX_LIBRARIES ${VPX_LIBRARIES} libcompat-to-msvc ) + endif() + if( ARM64 ) + link_directories( ${VPX_ROOT_PATH}/lib/arm64 ) + elseif( X64 ) + link_directories( ${VPX_ROOT_PATH}/lib/64 ) + else() + link_directories( ${VPX_ROOT_PATH}/lib/32 ) + # Workaround for "error LNK2026: module unsafe for SAFESEH image." + set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO" ) + endif() + set( VPX_FOUND TRUE ) +endif() + +if( VPX_FOUND ) + add_definitions( "-DUSE_LIBVPX=1" ) + include_directories( SYSTEM "${VPX_INCLUDE_DIR}" ) + set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} ${VPX_LIBRARIES} ) +else() + message( SEND_ERROR "Could not find libvpx" ) +endif() + +include_directories( SYSTEM "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${ZMUSIC_INCLUDE_DIR}" "${DRPC_INCLUDE_DIR}") if( ${HAVE_VM_JIT} ) add_definitions( -DHAVE_VM_JIT ) - include_directories( "${ASMJIT_INCLUDE_DIR}" ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ASMJIT_LIBRARIES}") + include_directories( SYSTEM "${ASMJIT_INCLUDE_DIR}" ) + set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} "${ASMJIT_LIBRARIES}") endif() # Start defining source files for ZDoom set( PLAT_WIN32_SOURCES - win32/hardware.cpp - win32/i_crash.cpp - win32/i_input.cpp - win32/i_keyboard.cpp - win32/i_mouse.cpp - win32/i_dijoy.cpp - win32/i_rawps2.cpp - win32/i_xinput.cpp - win32/i_main.cpp - win32/i_system.cpp - win32/i_specialpaths.cpp - win32/st_start.cpp - win32/st_start_util.cpp - win32/gl_sysfb.cpp - win32/base_sysfb.cpp - win32/win32basevideo.cpp - win32/win32glvideo.cpp - win32/win32polyvideo.cpp) - + win32/i_steam.cpp + common/platform/win32/hardware.cpp + common/platform/win32/i_input.cpp + common/platform/win32/i_keyboard.cpp + common/platform/win32/i_mouse.cpp + common/platform/win32/i_dijoy.cpp + common/platform/win32/i_rawps2.cpp + common/platform/win32/i_xinput.cpp + common/platform/win32/i_main.cpp + common/platform/win32/i_mainwindow.cpp + common/platform/win32/i_system.cpp + common/platform/win32/i_specialpaths.cpp + common/platform/win32/st_start.cpp + common/platform/win32/gl_sysfb.cpp + common/platform/win32/base_sysfb.cpp + common/platform/win32/win32basevideo.cpp + common/platform/win32/win32glvideo.cpp + ) + if (HAVE_VULKAN) - set (PLAT_WIN32_SOURCES ${PLAT_WIN32_SOURCES} win32/win32vulkanvideo.cpp ) + list (APPEND PLAT_WIN32_SOURCES common/platform/win32/win32vulkanvideo.cpp ) +endif() + +# todo: implement an actual crash catcher for ARM +# for now this is purely experimental +if (NOT ${TARGET_ARCHITECTURE} MATCHES "arm" ) + set (PLAT_WIN32_SOURCES ${PLAT_WIN32_SOURCES} common/platform/win32/i_crash.cpp ) +endif() +if (MSVC AND ${TARGET_ARCHITECTURE} MATCHES "arm") + set (PLAT_WIN32_SOURCES ${PLAT_WIN32_SOURCES} common/platform/win32/i_crash_arm.cpp ) + add_definitions( -DNO_SSE -D__ARM__ -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN) endif() set( PLAT_POSIX_SOURCES posix/i_steam.cpp - posix/i_system_posix.cpp ) + common/platform/posix/i_system_posix.cpp ) set( PLAT_SDL_SOURCES - posix/sdl/crashcatcher.c - posix/sdl/hardware.cpp - posix/sdl/i_gui.cpp - posix/sdl/i_input.cpp - posix/sdl/i_joystick.cpp - posix/sdl/i_main.cpp - posix/sdl/i_system.cpp - posix/sdl/sdlglvideo.cpp - posix/sdl/st_start.cpp ) + common/platform/posix/sdl/crashcatcher.c + common/platform/posix/sdl/hardware.cpp + common/platform/posix/sdl/i_gui.cpp + common/platform/posix/sdl/i_input.cpp + common/platform/posix/sdl/i_joystick.cpp + common/platform/posix/sdl/i_main.cpp + common/platform/posix/sdl/i_system.cpp + common/platform/posix/sdl/sdlglvideo.cpp + common/platform/posix/sdl/st_start.cpp ) set( PLAT_UNIX_SOURCES - posix/unix/i_specialpaths.cpp - posix/unix/gtk_dialogs.cpp ) + common/platform/posix/unix/i_specialpaths.cpp + common/platform/posix/unix/gtk_dialogs.cpp ) set( PLAT_OSX_SOURCES - posix/osx/iwadpicker_cocoa.mm - posix/osx/i_specialpaths.mm + common/platform/posix/osx/iwadpicker_cocoa.mm + common/platform/posix/osx/i_specialpaths.mm posix/osx/zdoom.icns ) set( PLAT_COCOA_SOURCES - posix/cocoa/i_input.mm - posix/cocoa/i_joystick.cpp - posix/cocoa/i_main.mm - posix/cocoa/i_system.mm - posix/cocoa/i_video.mm - posix/cocoa/st_console.mm - posix/cocoa/st_start.mm ) + common/platform/posix/cocoa/i_input.mm + common/platform/posix/cocoa/i_joystick.cpp + common/platform/posix/cocoa/i_main.mm + common/platform/posix/cocoa/i_system.mm + common/platform/posix/cocoa/i_video.mm + common/platform/posix/cocoa/st_console.mm + common/platform/posix/cocoa/st_start.mm ) if( WIN32 ) - set( SYSTEM_SOURCES_DIR win32 ) + set( SYSTEM_SOURCES_DIR common/platform/win32 ) set( SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ) set( OTHER_SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ${PLAT_UNIX_SOURCES} ) set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc ) elseif( APPLE ) if( OSX_COCOA_BACKEND ) - set( SYSTEM_SOURCES_DIR posix posix/cocoa ) + set( SYSTEM_SOURCES_DIR common/platform/posix common/platform/posix/cocoa ) set( SYSTEM_SOURCES ${PLAT_COCOA_SOURCES} ) set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_UNIX_SOURCES} ) else() - set( SYSTEM_SOURCES_DIR posix posix/sdl ) + set( SYSTEM_SOURCES_DIR common/platform/posix common/platform/posix/sdl ) set( SYSTEM_SOURCES ${PLAT_SDL_SOURCES} ) - set( PLAT_OSX_SOURCES ${PLAT_OSX_SOURCES} posix/sdl/i_system.mm ) + set( PLAT_OSX_SOURCES ${PLAT_OSX_SOURCES} common/platform/posix/sdl/i_system.mm ) set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_COCOA_SOURCES} ${PLAT_UNIX_SOURCES} ) endif() set( SYSTEM_SOURCES ${SYSTEM_SOURCES} ${PLAT_POSIX_SOURCES} ${PLAT_OSX_SOURCES} ) set_source_files_properties( posix/osx/zdoom.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) - set_source_files_properties( posix/osx/iwadpicker_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-exceptions ) + set_source_files_properties( common/platform/posix/osx/iwadpicker_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-exceptions ) else() - set( SYSTEM_SOURCES_DIR posix posix/sdl ) + option (SYSTEMINSTALL "Set global progdir based on CMake Install Dir" OFF) + + set( SYSTEM_SOURCES_DIR common/platform/posix common/platform/posix/sdl ) set( SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_UNIX_SOURCES} ) set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ) + + if ( SYSTEMINSTALL ) + add_definitions( -DPROGDIR="${CMAKE_INSTALL_PREFIX}/${INSTALL_PK3_PATH}" ) + endif() endif() if( HAVE_MMX ) add_definitions( -DHAVE_MMX=1 ) set( SYSTEM_SOURCES ${SYSTEM_SOURCES} - gamedata/textures/hires/hqnx_asm/hq2x_asm.cpp - gamedata/textures/hires/hqnx_asm/hq3x_asm.cpp - gamedata/textures/hires/hqnx_asm/hq4x_asm.cpp - gamedata/textures/hires/hqnx_asm/hqnx_asm_Image.cpp) + common/textures/hires/hqnx_asm/hq2x_asm.cpp + common/textures/hires/hqnx_asm/hq3x_asm.cpp + common/textures/hires/hqnx_asm/hq4x_asm.cpp + common/textures/hires/hqnx_asm/hqnx_asm_Image.cpp) - if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) + if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set_source_files_properties( - gamedata/textures/hires/hqnx_asm/hq2x_asm.cpp - gamedata/textures/hires/hqnx_asm/hq3x_asm.cpp - gamedata/textures/hires/hqnx_asm/hq4x_asm.cpp - gamedata/textures/hires/hqresize.cpp + common/textures/hires/hqnx_asm/hq2x_asm.cpp + common/textures/hires/hqnx_asm/hq3x_asm.cpp + common/textures/hires/hqnx_asm/hq4x_asm.cpp + common/textures/hires/hqresize.cpp PROPERTIES COMPILE_FLAGS "-mmmx" ) - endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) + endif( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) endif( HAVE_MMX ) if( HAVE_PARALLEL_FOR ) @@ -566,12 +530,12 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CUR DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/gamedata/xlat/xlat_parser.y ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h - COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/zcc-parse.lemon - DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/zcc-parse.lemon ) + COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/frontend/zcc-parse.lemon + DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/frontend/zcc-parse.lemon ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h - COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/utility/sc_man_scanner.re - DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/utility/sc_man_scanner.re ) + COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/common/engine/sc_man_scanner.re + DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/common/engine/sc_man_scanner.re ) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) @@ -593,34 +557,66 @@ file( GLOB HEADER_FILES gamedata/*.h gamedata/resourcefiles/*.h gamedata/fonts/*.h - gamedata/textures/*.h - gamedata/textures/hires/hqnx/*.h - gamedata/textures/hires/hqnx_asm/*.h - gamedata/textures/hires/xbr/*.h gamedata/xlat/*.h intermission/*.h maploader/*.h menu/*.h sound/*.h sound/backend/*.h* - sound/music/*.h* posix/*.h - posix/cocoa/*.h - posix/sdl/*.h - win32/*.h r_data/*.h - r_data/models/*.h - utility/rapidjson/*.h - utility/sfmt/*.h - utility/math./*h + common/audio/sound/thirdparty/*.h + common/audio/sound/*.h + common/audio/music/*.h* + common/2d/*.h + common/console/*.h + common/cutscenes/*.h + common/utility/*.h + common/engine/*.h + common/menu/*.h + common/statusbar/*.h + common/fonts/*.h + common/objects/*.h + common/filesystem/include/*.h + common/filesystem/source/*.h + common/platform/posix/cocoa/*.h + common/platform/posix/sdl/*.h + common/platform/win32/*.h + common/models/*.h + common/textures/*.h + common/startscreen/*.h + common/widgets/*.h + common/textures/hires/hqnx/*.h + common/textures/hires/hqnx_asm/*.h + common/textures/hires/xbr/*.h + common/thirdparty/*.h + common/thirdparty/rapidjson/*.h + common/thirdparty/math/*h + common/thirdparty/libsmackerdec/include/*.h + common/thirdparty/utf8proc/*.h + common/rendering/*.h + common/rendering/gl_load/*.h + common/rendering/gles/*.h + common/rendering/hwrenderer/data/*.h + common/rendering/vulkan/*.h + common/rendering/vulkan/system/*.h + common/rendering/vulkan/renderer/*.h + common/rendering/vulkan/shaders/*.h + common/rendering/vulkan/textures/*.h + common/scripting/core/*h + common/scripting/vm/*h + common/scripting/jit/*h + common/scripting/interface/*.h + common/scripting/backend/*.h + common/scripting/frontend/*.h + utility/*.h + launcher/*.h scripting/*.h scripting/backend/*.h scripting/decorate/*.h scripting/zscript/*.h - scripting/vm/*.h sound/midisources/*.h - sound/thirdparty/*.h rendering/*.h rendering/2d/*.h rendering/swrenderer/*.h @@ -632,42 +628,18 @@ file( GLOB HEADER_FILES rendering/swrenderer/plane/*.h rendering/swrenderer/things/*.h rendering/swrenderer/viewport/*.h - rendering/polyrenderer/*.h - rendering/polyrenderer/math/*.h - rendering/polyrenderer/drawers/*.h - rendering/polyrenderer/backend/*.h - rendering/hwrenderer/data/*.h - rendering/hwrenderer/dynlights/*.h - rendering/hwrenderer/models/*.h - rendering/hwrenderer/postprocessing/*.h + rendering/hwrenderer/*.h rendering/hwrenderer/scene/*.h - rendering/hwrenderer/textures/*.h - rendering/hwrenderer/utility/*.h - rendering/vulkan/*.h - rendering/vulkan/system/*.h - rendering/vulkan/renderer/*.h - rendering/vulkan/shaders/*.h - rendering/vulkan/textures/*.h - rendering/gl/*.h - rendering/gl/models/*.h - rendering/gl/renderer/*.h - rendering/gl/scene/*.h - rendering/gl/shaders/*.h - rendering/gl/system/*.h - rendering/gl/textures/*.h - rendering/gl_load/*.h *.h ) set ( SWRENDER_SOURCES rendering/swrenderer/r_swcolormaps.cpp rendering/swrenderer/r_swrenderer.cpp - rendering/swrenderer/r_memory.cpp rendering/swrenderer/r_renderthread.cpp rendering/swrenderer/drawers/r_draw.cpp rendering/swrenderer/drawers/r_draw_pal.cpp rendering/swrenderer/drawers/r_draw_rgba.cpp - rendering/swrenderer/drawers/r_thread.cpp rendering/swrenderer/scene/r_3dfloors.cpp rendering/swrenderer/scene/r_light.cpp rendering/swrenderer/scene/r_opaque_pass.cpp @@ -697,7 +669,6 @@ set ( SWRENDER_SOURCES rendering/swrenderer/things/r_sprite.cpp rendering/swrenderer/things/r_wallsprite.cpp rendering/swrenderer/things/r_decal.cpp - rendering/swrenderer/things/r_model.cpp rendering/swrenderer/plane/r_visibleplane.cpp rendering/swrenderer/plane/r_visibleplanelist.cpp rendering/swrenderer/plane/r_skyplane.cpp @@ -706,65 +677,46 @@ set ( SWRENDER_SOURCES rendering/swrenderer/plane/r_slopeplane.cpp ) -set( POLYRENDER_SOURCES - rendering/polyrenderer/drawers/poly_triangle.cpp - rendering/polyrenderer/drawers/poly_thread.cpp - rendering/polyrenderer/drawers/screen_triangle.cpp - rendering/polyrenderer/drawers/screen_scanline_setup.cpp - rendering/polyrenderer/drawers/screen_shader.cpp - rendering/polyrenderer/drawers/screen_blend.cpp -) - # These files will be flagged as "headers" so that they appear in project files # without being compiled. set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} ${SWRENDER_SOURCES} - ${POLYRENDER_SOURCES} sc_man_scanner.h - utility/sc_man_scanner.re + common/engine/sc_man_scanner.re g_statusbar/sbarinfo_commands.cpp gamedata/xlat/xlat_parser.y xlat_parser.c xlat_parser.h - scripting/zscript/zcc-parse.lemon + common/scripting/frontend/zcc-parse.lemon zcc-parse.c zcc-parse.h - win32/zdoom.natvis + common/platform/win32/zutil.natvis ) set( VM_JIT_SOURCES - scripting/vm/jit.cpp - scripting/vm/jit_runtime.cpp - scripting/vm/jit_call.cpp - scripting/vm/jit_flow.cpp - scripting/vm/jit_load.cpp - scripting/vm/jit_math.cpp - scripting/vm/jit_move.cpp - scripting/vm/jit_store.cpp + common/scripting/jit/jit.cpp + common/scripting/jit/jit_runtime.cpp + common/scripting/jit/jit_call.cpp + common/scripting/jit/jit_flow.cpp + common/scripting/jit/jit_load.cpp + common/scripting/jit/jit_math.cpp + common/scripting/jit/jit_move.cpp + common/scripting/jit/jit_store.cpp ) -# This is disabled for now because I cannot find a way to give the .pch file a different name. -# Visual C++ 2015 seems hell-bent on only allowing one .pch file with the same name as the executable. -#enable_precompiled_headers( g_pch2.h FASTMATH_PCH_SOURCES ) - # Enable fast math for some sources set( FASTMATH_SOURCES rendering/swrenderer/r_all.cpp rendering/swrenderer/r_swscene.cpp - rendering/polyrenderer/poly_all.cpp - sound/music/music_midi_base.cpp - sound/backend/oalsound.cpp - gamedata/textures/hires/hqnx/init.cpp - gamedata/textures/hires/hqnx/hq2x.cpp - gamedata/textures/hires/hqnx/hq3x.cpp - gamedata/textures/hires/hqnx/hq4x.cpp - gamedata/textures/hires/xbr/xbrz.cpp - gamedata/textures/hires/xbr/xbrz_old.cpp - rendering/gl_load/gl_load.c - rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp - rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp - rendering/hwrenderer/dynlights/hw_dynlightdata.cpp + common/textures/hires/hqnx/init.cpp + common/textures/hires/hqnx/hq2x.cpp + common/textures/hires/hqnx/hq3x.cpp + common/textures/hires/hqnx/hq4x.cpp + common/textures/hires/xbr/xbrz.cpp + common/textures/hires/xbr/xbrz_old.cpp + common/rendering/gl_load/gl_load.c + rendering/hwrenderer/hw_dynlightdata.cpp rendering/hwrenderer/scene/hw_bsp.cpp rendering/hwrenderer/scene/hw_fakeflat.cpp rendering/hwrenderer/scene/hw_decal.cpp @@ -781,43 +733,61 @@ set( FASTMATH_SOURCES rendering/hwrenderer/scene/hw_walls.cpp rendering/hwrenderer/scene/hw_walls_vertex.cpp rendering/hwrenderer/scene/hw_weapon.cpp - r_data/models/models.cpp - utility/matrix.cpp + common/utility/matrix.cpp ) -#Vulkan stuff must go into a separate list later because it needs to be disabled for some platforms +#Vulkan stuff must go into a separate list because it needs to be disabled for some platforms set (VULKAN_SOURCES - rendering/vulkan/system/vk_device.cpp - rendering/vulkan/system/vk_swapchain.cpp - rendering/vulkan/system/vk_builders.cpp - rendering/vulkan/system/vk_framebuffer.cpp - rendering/vulkan/system/vk_buffers.cpp - rendering/vulkan/renderer/vk_renderstate.cpp - rendering/vulkan/renderer/vk_renderpass.cpp - rendering/vulkan/renderer/vk_streambuffer.cpp - rendering/vulkan/renderer/vk_postprocess.cpp - rendering/vulkan/renderer/vk_renderbuffers.cpp - rendering/vulkan/shaders/vk_shader.cpp - rendering/vulkan/textures/vk_samplers.cpp - rendering/vulkan/textures/vk_hwtexture.cpp - rendering/vulkan/textures/vk_imagetransition.cpp - rendering/vulkan/thirdparty/volk/volk.c - rendering/vulkan/thirdparty/vk_mem_alloc/vk_mem_alloc.cpp + common/rendering/vulkan/system/vk_renderdevice.cpp + common/rendering/vulkan/system/vk_commandbuffer.cpp + common/rendering/vulkan/system/vk_hwbuffer.cpp + common/rendering/vulkan/system/vk_buffer.cpp + common/rendering/vulkan/renderer/vk_renderstate.cpp + common/rendering/vulkan/renderer/vk_renderpass.cpp + common/rendering/vulkan/renderer/vk_streambuffer.cpp + common/rendering/vulkan/renderer/vk_postprocess.cpp + common/rendering/vulkan/renderer/vk_pprenderstate.cpp + common/rendering/vulkan/renderer/vk_descriptorset.cpp + common/rendering/vulkan/renderer/vk_raytrace.cpp + common/rendering/vulkan/shaders/vk_shader.cpp + common/rendering/vulkan/shaders/vk_ppshader.cpp + common/rendering/vulkan/textures/vk_samplers.cpp + common/rendering/vulkan/textures/vk_hwtexture.cpp + common/rendering/vulkan/textures/vk_pptexture.cpp + common/rendering/vulkan/textures/vk_imagetransition.cpp + common/rendering/vulkan/textures/vk_renderbuffers.cpp + common/rendering/vulkan/textures/vk_texture.cpp + common/rendering/vulkan/textures/vk_framebuffer.cpp ) +if (HAVE_GLES2) + set (GLES_SOURCES + common/rendering/gles/gles_system.cpp + common/rendering/gles/gles_renderer.cpp + common/rendering/gles/gles_framebuffer.cpp + common/rendering/gles/gles_renderstate.cpp + common/rendering/gles/gles_renderbuffers.cpp + common/rendering/gles/gles_postprocess.cpp + common/rendering/gles/gles_postprocessstate.cpp + common/rendering/gles/gles_buffers.cpp + common/rendering/gles/gles_hwtexture.cpp + common/rendering/gles/gles_shader.cpp + common/rendering/gles/gles_shaderprogram.cpp + common/rendering/gles/gles_samplers.cpp + common/rendering/gles/glad/src/glad.c + ) + + list (APPEND FASTMATH_SOURCES ${GLES_SOURCES}) +endif() + if (HAVE_VULKAN) - set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${VULKAN_SOURCES}) + list (APPEND FASTMATH_SOURCES ${VULKAN_SOURCES}) endif() -set (POLYBACKEND_SOURCES - rendering/polyrenderer/backend/poly_framebuffer.cpp - rendering/polyrenderer/backend/poly_buffers.cpp - rendering/polyrenderer/backend/poly_hwtexture.cpp - rendering/polyrenderer/backend/poly_renderstate.cpp -) -set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${POLYBACKEND_SOURCES}) +set (FASTMATH_SOURCES ${FASTMATH_SOURCES}) set (PCH_SOURCES + common/thirdparty/richpresence.cpp am_map.cpp playsim/bots/b_bot.cpp playsim/bots/b_func.cpp @@ -825,24 +795,17 @@ set (PCH_SOURCES playsim/bots/b_move.cpp playsim/bots/b_think.cpp bbannouncer.cpp - console/c_bind.cpp console/c_cmds.cpp - console/c_console.cpp - console/c_consolebuffer.cpp - console/c_cvars.cpp - console/c_dispatch.cpp - console/c_expr.cpp + console/c_notifybuffer.cpp console/c_functions.cpp ct_chat.cpp d_iwad.cpp d_main.cpp + d_defcvars.cpp d_anonstats.cpp d_net.cpp d_netinfo.cpp d_protocol.cpp - dobject.cpp - dobjgc.cpp - dobjtype.cpp doomstat.cpp g_cvars.cpp g_dumpinfo.cpp @@ -850,11 +813,8 @@ set (PCH_SOURCES g_hub.cpp g_level.cpp gameconfigfile.cpp - gitinfo.cpp hu_scores.cpp - i_net.cpp m_cheat.cpp - m_joy.cpp m_misc.cpp playsim/p_acs.cpp playsim/p_actionfunctions.cpp @@ -878,20 +838,13 @@ set (PCH_SOURCES playsim/p_user.cpp rendering/r_utility.cpp rendering/r_sky.cpp - rendering/r_videoscale.cpp sound/s_advsound.cpp - sound/s_environment.cpp - sound/s_reverbedit.cpp sound/s_sndseq.cpp sound/s_doomsound.cpp - sound/s_sound.cpp - sound/s_music.cpp - serializer.cpp + serializer_doom.cpp scriptutil.cpp st_stuff.cpp - rendering/v_framebuffer.cpp r_data/v_palette.cpp - rendering/v_video.cpp wi_stuff.cpp gamedata/a_keys.cpp gamedata/a_weapons.cpp @@ -899,9 +852,7 @@ set (PCH_SOURCES gamedata/g_mapinfo.cpp gamedata/g_skill.cpp gamedata/gi.cpp - gamedata/stringtable.cpp gamedata/umapinfo.cpp - gamedata/w_wad.cpp gamedata/d_dehacked.cpp gamedata/g_doomedmap.cpp gamedata/info.cpp @@ -920,10 +871,12 @@ set (PCH_SOURCES playsim/mapthinkers/a_pillar.cpp playsim/mapthinkers/a_plats.cpp playsim/mapthinkers/a_pusher.cpp + playsim/mapthinkers/a_thruster.cpp playsim/mapthinkers/a_scroll.cpp playsim/mapthinkers/dsectoreffect.cpp playsim/a_pickups.cpp playsim/a_action.cpp + playsim/a_corona.cpp playsim/a_decals.cpp playsim/a_dynlight.cpp playsim/a_flashfader.cpp @@ -948,47 +901,16 @@ set (PCH_SOURCES g_statusbar/sbarinfo.cpp g_statusbar/sbar_mugshot.cpp g_statusbar/shared_sbar.cpp - rendering/2d/f_wipe.cpp - rendering/2d/v_2ddrawer.cpp - rendering/2d/v_drawtext.cpp rendering/2d/v_blend.cpp - rendering/2d/v_draw.cpp - rendering/gl/renderer/gl_renderer.cpp - rendering/gl/renderer/gl_renderstate.cpp - rendering/gl/renderer/gl_renderbuffers.cpp - rendering/gl/renderer/gl_postprocess.cpp - rendering/gl/renderer/gl_postprocessstate.cpp - rendering/gl/renderer/gl_stereo3d.cpp - rendering/gl/renderer/gl_scene.cpp - rendering/gl/shaders/gl_shader.cpp - rendering/gl/shaders/gl_shaderprogram.cpp - rendering/gl_load/gl_interface.cpp - rendering/gl/system/gl_framebuffer.cpp - rendering/gl/system/gl_debug.cpp - rendering/gl/system/gl_buffers.cpp - rendering/gl/textures/gl_hwtexture.cpp - rendering/gl/textures/gl_samplers.cpp - rendering/hwrenderer/data/hw_vertexbuilder.cpp - rendering/hwrenderer/data/flatvertices.cpp - rendering/hwrenderer/data/hw_viewpointbuffer.cpp - rendering/hwrenderer/dynlights/hw_aabbtree.cpp - rendering/hwrenderer/dynlights/hw_shadowmap.cpp - rendering/hwrenderer/dynlights/hw_lightbuffer.cpp - rendering/hwrenderer/models/hw_models.cpp - rendering/hwrenderer/scene/hw_skydome.cpp + rendering/hwrenderer/hw_entrypoint.cpp + rendering/hwrenderer/hw_vertexbuilder.cpp + rendering/hwrenderer/doom_aabbtree.cpp + rendering/hwrenderer/doom_levelmesh.cpp + rendering/hwrenderer/hw_models.cpp + rendering/hwrenderer/hw_precache.cpp + rendering/hwrenderer/scene/hw_lighting.cpp rendering/hwrenderer/scene/hw_drawlistadd.cpp - rendering/hwrenderer/scene/hw_renderstate.cpp - rendering/hwrenderer/postprocessing/hw_postprocess.cpp - rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp - rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp - rendering/hwrenderer/textures/hw_material.cpp - rendering/hwrenderer/textures/hw_precache.cpp - rendering/hwrenderer/utility/hw_clock.cpp - rendering/hwrenderer/utility/hw_cvars.cpp - rendering/hwrenderer/utility/hw_draw2d.cpp - rendering/hwrenderer/utility/hw_lighting.cpp - rendering/hwrenderer/utility/hw_shaderpatcher.cpp - rendering/hwrenderer/utility/hw_vrmodes.cpp + rendering/hwrenderer/scene/hw_setcolor.cpp maploader/edata.cpp maploader/specials.cpp maploader/maploader.cpp @@ -1001,60 +923,12 @@ set (PCH_SOURCES maploader/renderinfo.cpp maploader/compatibility.cpp maploader/postprocessor.cpp - menu/joystickmenu.cpp + menu/doommenu.cpp menu/loadsavemenu.cpp - menu/menu.cpp - menu/menudef.cpp - menu/messagebox.cpp - menu/optionmenu.cpp menu/playermenu.cpp - menu/resolutionmenu.cpp - gamedata/resourcefiles/ancientzip.cpp - gamedata/resourcefiles/file_7z.cpp - gamedata/resourcefiles/file_grp.cpp - gamedata/resourcefiles/file_lump.cpp - gamedata/resourcefiles/file_rff.cpp - gamedata/resourcefiles/file_wad.cpp - gamedata/resourcefiles/file_zip.cpp - gamedata/resourcefiles/file_pak.cpp - gamedata/resourcefiles/file_directory.cpp - gamedata/resourcefiles/resourcefile.cpp gamedata/textures/animations.cpp gamedata/textures/anim_switches.cpp - gamedata/textures/bitmap.cpp - gamedata/textures/texture.cpp - gamedata/textures/image.cpp - gamedata/textures/imagetexture.cpp - gamedata/textures/texturemanager.cpp - gamedata/textures/multipatchtexturebuilder.cpp - gamedata/textures/skyboxtexture.cpp - gamedata/textures/formats/automaptexture.cpp - gamedata/textures/formats/brightmaptexture.cpp - gamedata/textures/formats/buildtexture.cpp - gamedata/textures/formats/canvastexture.cpp - gamedata/textures/formats/ddstexture.cpp - gamedata/textures/formats/flattexture.cpp - gamedata/textures/formats/fontchars.cpp - gamedata/textures/formats/imgztexture.cpp - gamedata/textures/formats/jpegtexture.cpp - gamedata/textures/formats/md5check.cpp - gamedata/textures/formats/multipatchtexture.cpp - gamedata/textures/formats/patchtexture.cpp - gamedata/textures/formats/pcxtexture.cpp - gamedata/textures/formats/pngtexture.cpp - gamedata/textures/formats/rawpagetexture.cpp - gamedata/textures/formats/emptytexture.cpp - gamedata/textures/formats/shadertexture.cpp - gamedata/textures/formats/tgatexture.cpp - gamedata/textures/formats/stbtexture.cpp - gamedata/textures/hires/hqresize.cpp - gamedata/fonts/singlelumpfont.cpp - gamedata/fonts/singlepicfont.cpp - gamedata/fonts/specialfont.cpp - gamedata/fonts/font.cpp - gamedata/fonts/hexfont.cpp - gamedata/fonts/v_font.cpp - gamedata/fonts/v_text.cpp + gamedata/textures/buildloader.cpp gamedata/p_xlat.cpp gamedata/xlat/parse_xlat.cpp gamedata/xlat/parsecontext.cpp @@ -1070,81 +944,240 @@ set (PCH_SOURCES intermission/intermission.cpp intermission/intermission_parse.cpp r_data/colormaps.cpp - r_data/cycler.cpp r_data/gldefs.cpp r_data/a_dynlightdata.cpp r_data/r_translate.cpp r_data/sprites.cpp r_data/portalgroups.cpp - r_data/voxels.cpp - r_data/renderstyle.cpp + r_data/voxeldef.cpp r_data/r_canvastexture.cpp r_data/r_interpolate.cpp r_data/r_vanillatrans.cpp r_data/r_sections.cpp - r_data/models/models_md3.cpp - r_data/models/models_md2.cpp - r_data/models/models_voxel.cpp - r_data/models/models_ue1.cpp - r_data/models/models_obj.cpp - scripting/symbols.cpp + r_data/models.cpp scripting/vmiterators.cpp scripting/vmthunks.cpp scripting/vmthunks_actors.cpp - scripting/types.cpp scripting/thingdef.cpp scripting/thingdef_data.cpp scripting/thingdef_properties.cpp - scripting/backend/codegen.cpp - scripting/backend/scopebarrier.cpp - scripting/backend/dynarrays.cpp - scripting/backend/vmbuilder.cpp - scripting/backend/vmdisasm.cpp + scripting/backend/codegen_doom.cpp scripting/decorate/olddecorations.cpp scripting/decorate/thingdef_exp.cpp scripting/decorate/thingdef_parse.cpp scripting/decorate/thingdef_states.cpp - scripting/vm/vmexec.cpp - scripting/vm/vmframe.cpp - scripting/zscript/ast.cpp - scripting/zscript/zcc_compile.cpp - scripting/zscript/zcc_parser.cpp - utility/sfmt/SFMT.cpp - sound/music/i_music.cpp - sound/music/i_soundfont.cpp - sound/backend/i_sound.cpp - sound/music/music_config.cpp + scripting/zscript/zcc_compile_doom.cpp rendering/swrenderer/textures/r_swtexture.cpp rendering/swrenderer/textures/warptexture.cpp rendering/swrenderer/textures/swcanvastexture.cpp events.cpp - utility/i_module.cpp - utility/palette.cpp - utility/files.cpp - utility/files_decompress.cpp - utility/m_png.cpp - utility/m_random.cpp - utility/memarena.cpp - utility/md5.cpp + launcher/launcherwindow.cpp + launcher/launcherbanner.cpp + launcher/launcherbuttonbar.cpp + launcher/playgamepage.cpp + launcher/settingspage.cpp + + common/audio/sound/i_sound.cpp + common/audio/sound/oalsound.cpp + common/audio/sound/s_environment.cpp + common/audio/sound/s_sound.cpp + common/audio/sound/s_reverbedit.cpp + common/audio/music/music_midi_base.cpp + common/audio/music/music.cpp + common/audio/music/i_music.cpp + common/audio/music/i_soundfont.cpp + common/audio/music/music_config.cpp + common/2d/v_2ddrawer.cpp + common/2d/v_drawtext.cpp + common/2d/v_draw.cpp + common/2d/wipe.cpp + common/thirdparty/animlib.cpp + common/thirdparty/gain_analysis.cpp + common/thirdparty/sfmt/SFMT.cpp + common/startscreen/startscreen.cpp + common/startscreen/startscreen_heretic.cpp + common/startscreen/startscreen_hexen.cpp + common/startscreen/startscreen_strife.cpp + common/startscreen/startscreen_generic.cpp + common/startscreen/endoom.cpp + common/widgets/errorwindow.cpp + common/widgets/netstartwindow.cpp + common/widgets/widgetresourcedata.cpp + common/fonts/singlelumpfont.cpp + common/fonts/singlepicfont.cpp + common/fonts/specialfont.cpp + common/fonts/font.cpp + common/fonts/hexfont.cpp + common/fonts/v_font.cpp + common/fonts/v_text.cpp + common/textures/hw_ihwtexture.cpp + common/textures/hw_material.cpp + common/textures/bitmap.cpp + common/textures/m_png.cpp + common/textures/texture.cpp + common/textures/gametexture.cpp + common/textures/image.cpp + common/textures/imagetexture.cpp + common/textures/texturemanager.cpp + common/textures/multipatchtexturebuilder.cpp + common/textures/skyboxtexture.cpp + common/textures/animtexture.cpp + common/textures/v_collection.cpp + common/textures/formats/automaptexture.cpp + common/textures/formats/brightmaptexture.cpp + common/textures/formats/buildtexture.cpp + common/textures/formats/ddstexture.cpp + common/textures/formats/flattexture.cpp + common/textures/formats/fontchars.cpp + common/textures/formats/imgztexture.cpp + common/textures/formats/md5check.cpp + common/textures/formats/multipatchtexture.cpp + common/textures/formats/patchtexture.cpp + common/textures/formats/pcxtexture.cpp + common/textures/formats/pngtexture.cpp + common/textures/formats/rawpagetexture.cpp + common/textures/formats/startuptexture.cpp + common/textures/formats/emptytexture.cpp + common/textures/formats/shadertexture.cpp + common/textures/formats/tgatexture.cpp + common/textures/formats/stbtexture.cpp + common/textures/formats/anmtexture.cpp + common/textures/formats/startscreentexture.cpp + common/textures/formats/qoitexture.cpp + common/textures/formats/webptexture.cpp + common/textures/hires/hqresize.cpp + common/models/models_md3.cpp + common/models/models_md2.cpp + common/models/models_voxel.cpp + common/models/models_ue1.cpp + common/models/models_obj.cpp + common/models/models_iqm.cpp + common/models/model.cpp + common/models/voxels.cpp + common/console/c_commandline.cpp + common/console/c_buttons.cpp + common/console/c_bind.cpp + common/console/c_enginecmds.cpp + common/console/c_consolebuffer.cpp + common/console/c_cvars.cpp + common/console/c_dispatch.cpp + common/console/c_commandbuffer.cpp + common/console/c_console.cpp + common/console/c_notifybufferbase.cpp + common/console/c_tabcomplete.cpp + common/console/c_expr.cpp + common/cutscenes/playmve.cpp + common/cutscenes/movieplayer.cpp + common/cutscenes/screenjob.cpp + common/utility/engineerrors.cpp + common/utility/i_module.cpp + common/utility/gitinfo.cpp + common/utility/m_alloc.cpp + common/utility/utf8.cpp + common/utility/palette.cpp + common/utility/memarena.cpp + common/utility/cmdlib.cpp + common/utility/configfile.cpp + common/utility/i_time.cpp + common/utility/m_argv.cpp + common/utility/s_playlist.cpp + common/utility/name.cpp + common/utility/r_memory.cpp + common/utility/writezip.cpp + common/thirdparty/base64.cpp + common/thirdparty/md5.cpp + common/thirdparty/superfasthash.cpp + common/thirdparty/libsmackerdec/src/BitReader.cpp + common/thirdparty/libsmackerdec/src/FileStream.cpp + common/thirdparty/libsmackerdec/src/HuffmanVLC.cpp + common/thirdparty/libsmackerdec/src/LogError.cpp + common/thirdparty/libsmackerdec/src/SmackerDecoder.cpp + common/engine/cycler.cpp + common/engine/d_event.cpp + common/engine/date.cpp + common/engine/stats.cpp + common/engine/sc_man.cpp + common/engine/palettecontainer.cpp + common/engine/stringtable.cpp + common/engine/i_net.cpp + common/engine/i_interface.cpp + common/engine/renderstyle.cpp + common/engine/v_colortables.cpp + common/engine/serializer.cpp + common/engine/m_joy.cpp + common/engine/m_random.cpp + common/objects/autosegs.cpp + common/objects/dobject.cpp + common/objects/dobjgc.cpp + common/objects/dobjtype.cpp + common/menu/joystickmenu.cpp + common/menu/menu.cpp + common/menu/messagebox.cpp + common/menu/optionmenu.cpp + common/menu/resolutionmenu.cpp + common/menu/menudef.cpp + common/menu/savegamemanager.cpp + common/statusbar/base_sbar.cpp + + common/rendering/v_framebuffer.cpp + common/rendering/v_video.cpp + common/rendering/r_thread.cpp + common/rendering/r_videoscale.cpp + common/rendering/hwrenderer/hw_draw2d.cpp + common/rendering/hwrenderer/data/hw_clock.cpp + common/rendering/hwrenderer/data/hw_skydome.cpp + common/rendering/hwrenderer/data/flatvertices.cpp + common/rendering/hwrenderer/data/hw_viewpointbuffer.cpp + common/rendering/hwrenderer/data/hw_modelvertexbuffer.cpp + common/rendering/hwrenderer/data/hw_cvars.cpp + common/rendering/hwrenderer/data/hw_vrmodes.cpp + common/rendering/hwrenderer/data/hw_lightbuffer.cpp + common/rendering/hwrenderer/data/hw_bonebuffer.cpp + common/rendering/hwrenderer/data/hw_aabbtree.cpp + common/rendering/hwrenderer/data/hw_shadowmap.cpp + common/rendering/hwrenderer/data/hw_shaderpatcher.cpp + common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp + common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp + common/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp + common/rendering/hwrenderer/postprocessing/hw_postprocessshader_ccmds.cpp + common/rendering/gl_load/gl_interface.cpp + common/rendering/gl/gl_renderer.cpp + common/rendering/gl/gl_stereo3d.cpp + common/rendering/gl/gl_framebuffer.cpp + common/rendering/gl/gl_renderstate.cpp + common/rendering/gl/gl_renderbuffers.cpp + common/rendering/gl/gl_postprocess.cpp + common/rendering/gl/gl_postprocessstate.cpp + common/rendering/gl/gl_debug.cpp + common/rendering/gl/gl_buffers.cpp + common/rendering/gl/gl_hwtexture.cpp + common/rendering/gl/gl_samplers.cpp + common/rendering/gl/gl_shader.cpp + common/rendering/gl/gl_shaderprogram.cpp + common/scripting/core/maps.cpp + common/scripting/core/dictionary.cpp + common/scripting/core/dynarrays.cpp + common/scripting/core/symbols.cpp + common/scripting/core/types.cpp + common/scripting/core/scopebarrier.cpp + common/scripting/core/vmdisasm.cpp + common/scripting/core/imports.cpp + common/scripting/vm/vmexec.cpp + common/scripting/vm/vmframe.cpp + common/scripting/interface/stringformat.cpp + common/scripting/interface/vmnatives.cpp + common/scripting/frontend/ast.cpp + common/scripting/frontend/zcc_compile.cpp + common/scripting/frontend/zcc_parser.cpp + common/scripting/backend/vmbuilder.cpp + common/scripting/backend/codegen.cpp + utility/nodebuilder/nodebuild.cpp utility/nodebuilder/nodebuild_classify_nosse2.cpp utility/nodebuilder/nodebuild_events.cpp utility/nodebuilder/nodebuild_extract.cpp utility/nodebuilder/nodebuild_gl.cpp utility/nodebuilder/nodebuild_utility.cpp - utility/sc_man.cpp - utility/stats.cpp - utility/cmdlib.cpp - utility/configfile.cpp - utility/i_time.cpp - utility/m_alloc.cpp - utility/m_argv.cpp - utility/m_bbox.cpp - utility/name.cpp - utility/s_playlist.cpp - utility/v_collection.cpp - utility/utf8.cpp - utility/zstrformat.cpp ) if( ${HAVE_VM_JIT} ) @@ -1153,66 +1186,128 @@ else() set( NOT_COMPILED_SOURCE_FILES ${NOT_COMPILED_SOURCE_FILES} ${VM_JIT_SOURCES} ) endif() -if( MSVC ) - enable_precompiled_headers( g_pch.h PCH_SOURCES ) -else() - # Temporary solution for compilers other than MSVC - set_source_files_properties( ${PCH_SOURCES} PROPERTIES COMPILE_FLAGS "-include g_pch.h" ) -endif() - -add_executable( zdoom WIN32 MACOSX_BUNDLE +set( GAME_SOURCES ${HEADER_FILES} ${NOT_COMPILED_SOURCE_FILES} - __autostart.cpp ${SYSTEM_SOURCES} ${FASTMATH_SOURCES} ${PCH_SOURCES} - utility/x86.cpp - utility/strnatcmp.c - utility/zstring.cpp - utility/dictionary.cpp - utility/math/asin.c - utility/math/atan.c - utility/math/const.c - utility/math/cosh.c - utility/math/exp.c - utility/math/isnan.c - utility/math/log.c - utility/math/log10.c - utility/math/mtherr.c - utility/math/polevl.c - utility/math/pow.c - utility/math/powi.c - utility/math/sin.c - utility/math/sinh.c - utility/math/sqrt.c - utility/math/tan.c - utility/math/tanh.c - utility/math/fastsin.cpp - zzautozend.cpp + common/utility/x86.cpp + common/thirdparty/strnatcmp.c + common/thirdparty/utf8proc/utf8proc.c + common/thirdparty/stb/stb_sprintf.c + common/utility/zstring.cpp + common/utility/findfile.cpp + common/thirdparty/math/asin.c + common/thirdparty/math/atan.c + common/thirdparty/math/const.c + common/thirdparty/math/cosh.c + common/thirdparty/math/exp.c + common/thirdparty/math/isnan.c + common/thirdparty/math/log.c + common/thirdparty/math/log10.c + common/thirdparty/math/mtherr.c + common/thirdparty/math/polevl.c + common/thirdparty/math/pow.c + common/thirdparty/math/powi.c + common/thirdparty/math/sin.c + common/thirdparty/math/sinh.c + common/thirdparty/math/sqrt.c + common/thirdparty/math/tan.c + common/thirdparty/math/tanh.c + common/thirdparty/math/fastsin.cpp + + common/filesystem/source/filesystem.cpp + common/filesystem/source/ancientzip.cpp + common/filesystem/source/file_7z.cpp + common/filesystem/source/file_grp.cpp + common/filesystem/source/file_lump.cpp + common/filesystem/source/file_rff.cpp + common/filesystem/source/file_wad.cpp + common/filesystem/source/file_zip.cpp + common/filesystem/source/file_pak.cpp + common/filesystem/source/file_whres.cpp + common/filesystem/source/file_ssi.cpp + common/filesystem/source/file_hog.cpp + common/filesystem/source/file_mvl.cpp + common/filesystem/source/file_directory.cpp + common/filesystem/source/resourcefile.cpp + common/filesystem/source/files.cpp + common/filesystem/source/files_decompress.cpp + common/filesystem/source/fs_findfile.cpp + common/filesystem/source/fs_stringpool.cpp + common/filesystem/source/unicode.cpp + common/filesystem/source/critsec.cpp + ) +set( GAME_NONPCH_SOURCES ${GAME_SOURCES} ) +list( REMOVE_ITEM GAME_NONPCH_SOURCES ${PCH_SOURCES} ) + +add_executable( zdoom WIN32 MACOSX_BUNDLE ${GAME_SOURCES} ) + +target_precompile_headers( zdoom PRIVATE g_pch.h ) + set_source_files_properties( ${FASTMATH_SOURCES} PROPERTIES COMPILE_FLAGS ${ZD_FASTMATH_FLAG} ) set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" ) -set_source_files_properties( utility/sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" ) +set_source_files_properties( common/engine/sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" ) set_source_files_properties( ${NOT_COMPILED_SOURCE_FILES} PROPERTIES HEADER_FILE_ONLY TRUE ) +set_source_files_properties( ${GAME_NONPCH_SOURCES} common/textures/hires/hqresize.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE ) if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") # [BL] Solaris requires these to be explicitly linked. - set( ZDOOM_LIBS ${ZDOOM_LIBS} nsl socket) + set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} nsl socket) endif() if( UNIX ) find_package( Backtrace ) if(Backtrace_FOUND) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${Backtrace_LIBRARIES} ) + set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} ${Backtrace_LIBRARIES} ) endif() endif() -target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa lzma ${ZMUSIC_LIBRARIES} ) - -include_directories( . +target_link_libraries( zdoom ${PROJECT_LIBRARIES} lzma ${ZMUSIC_LIBRARIES} ) + +include_directories( + BEFORE + . + common/audio/sound + common/audio/music + common/2d + common/cutscenes + common/thirdparty/libsmackerdec/include + common/thirdparty + common/thirdparty/stb + common/thirdparty/utf8proc + common/textures + common/textures/formats + common/textures/hires + common/textures + common/models + common/filesystem/include + common/utility + common/console + common/engine + common/menu + common/statusbar + common/fonts + common/objects + common/startscreen + common/widgets + common/rendering + common/rendering/hwrenderer/data + common/rendering/gl_load + common/rendering/gl + common/rendering/gles + common/rendering/gles/glad/include + common/rendering/gles/Mali_OpenGL_ES_Emulator/include + common/scripting/vm + common/scripting/jit + common/scripting/core + common/scripting/interface + common/scripting/frontend + common/scripting/backend g_statusbar console playsim @@ -1222,23 +1317,24 @@ include_directories( . gamedata/textures gamedata/fonts rendering + rendering/hwrenderer rendering/2d r_data sound - sound/music + menu sound/backend xlat utility utility/nodebuilder scripting - scripting/vm + scripting/zscript rendering - rendering/vulkan/thirdparty - ../libraries/gdtoa - ../libraries/glslang/glslang/Public - ../libraries/glslang/spirv - ${CMAKE_BINARY_DIR}/libraries/gdtoa - ${SYSTEM_SOURCES_DIR} ) + launcher + ../libraries/ZVulkan/include + ../libraries/ZWidget/include + ../libraries/webp/include + ${SYSTEM_SOURCES_DIR} +) add_dependencies( zdoom revision_check ) @@ -1271,7 +1367,7 @@ if( MSVC ) set_target_properties(zdoom PROPERTIES LINK_FLAGS ${LINKERSTUFF}) add_custom_command(TARGET zdoom POST_BUILD - COMMAND "mt.exe" -manifest \"${CMAKE_CURRENT_SOURCE_DIR}\\win32\\zdoom.exe.manifest\" -outputresource:\"$\"\;\#1 + COMMAND "mt.exe" -manifest \"${CMAKE_CURRENT_SOURCE_DIR}\\common\\platform\\win32\\manifest.xml\" -outputresource:\"$\"\;\#1 COMMENT "Adding manifest..." ) @@ -1281,7 +1377,14 @@ if( NOT WIN32 AND NOT APPLE ) FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME} ]; then ln -sf ${CMAKE_CURRENT_BINARY_DIR}/${ZDOOM_EXE_NAME} ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME}; fi" ) add_custom_command( TARGET zdoom POST_BUILD COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make - COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/link-make ) + IF ("${INSTALL_RPATH}" STREQUAL "") + set_target_properties(zdoom PROPERTIES + #allow libzmusic.so.1 library in same folder as executable at runtime + INSTALL_RPATH "\$ORIGIN:\$ORIGIN/zmusic/build/source" + BUILD_WITH_INSTALL_RPATH ON + ) + endif() endif() add_custom_command(TARGET zdoom POST_BUILD @@ -1293,20 +1396,26 @@ add_custom_command(TARGET zdoom POST_BUILD ${CMAKE_SOURCE_DIR}/fm_banks/gs-by-papiezak-and-sneakernets.wopn $/fm_banks/gs-by-papiezak-and-sneakernets.wopn ) -if( CMAKE_COMPILER_IS_GNUCXX ) - # GCC misoptimizes this file - set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" ) +if (VCPKG_TOOLCHAIN) + x_vcpkg_install_local_dependencies(TARGETS zdoom DESTINATION ".") +endif() + +if( WIN32 ) + set( INSTALL_SOUNDFONT_PATH . CACHE STRING "Directory where soundfonts and WOPL/WOPN banks will be placed during install." ) +else() + set( INSTALL_SOUNDFONT_PATH share/games/doom CACHE STRING "Directory where soundfonts and WOPL/WOPN banks will be placed during install." ) endif() -if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) +install(DIRECTORY "${PROJECT_BINARY_DIR}/soundfonts" "${PROJECT_BINARY_DIR}/fm_banks" + DESTINATION ${INSTALL_SOUNDFONT_PATH} + COMPONENT "Soundfont resources") + +if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) # Need to enable intrinsics for these files. - if( SSE_MATTERS ) - set_property( SOURCE - rendering/polyrenderer/poly_all.cpp - rendering/swrenderer/r_all.cpp - utility/palette.cpp - utility/x86.cpp - APPEND_STRING PROPERTY COMPILE_FLAGS " -msse2 -mmmx" ) - endif() + set_property( SOURCE + common/utility/palette.cpp + common/utility/x86.cpp + rendering/swrenderer/r_all.cpp + APPEND_STRING PROPERTY COMPILE_FLAGS " ${SSE2_ENABLE}" ) endif() if( APPLE ) @@ -1319,6 +1428,7 @@ if( APPLE ) set_target_properties(zdoom PROPERTIES LINK_FLAGS "${LINK_FRAMEWORKS}" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "org.drdteam.gzdoom" XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "" ) # Dymanic libraries like libvulkan.dylib or libMoltenVK.dylib will be loaded by dlopen() @@ -1327,30 +1437,21 @@ if( APPLE ) endif() if( WIN32 ) - set( INSTALL_PATH . CACHE STRING "Directory where the zdoom executable will be placed during install." ) + set( INSTALL_PATH . CACHE STRING "Directory where the executable will be placed during install." ) else() - set( INSTALL_PATH bin CACHE STRING "Directory where the zdoom executable will be placed during install." ) + set( INSTALL_PATH bin CACHE STRING "Directory where the executable will be placed during install." ) endif() install(TARGETS zdoom DESTINATION ${INSTALL_PATH} COMPONENT "Game executable") source_group("Audio Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/.+") -source_group("Audio Files\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/backend/.+") -source_group("Audio Files\\Music formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/musicformats/.+") -source_group("Audio Files\\Third-party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/thirdparty/.+") source_group("Game Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/.+") -source_group("Game Data\\Resource Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/resourcefiles/.+") source_group("Game Data\\Fonts" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/fonts/.+") -source_group("Game Data\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/textures/.+") -source_group("Game Data\\Textures\\Hires" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/textures/hires/.+") -source_group("Game Data\\Textures\\Hires\\HQ Resize" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/textures/hires/hqnx/.+") -source_group("Game Data\\Textures\\Hires\\HQ Resize MMX version" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/textures/hires/hqnx_asm/.+") -source_group("Game Data\\Textures\\Hires\\XBRZ" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/textures/hires/xbr/.+") -source_group("Game Data\\Textures\\Formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/textures/formats/.+") source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+") source_group("Map Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/maploader/.+") source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+") +source_group("Console" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/console/.+") source_group("Playsim" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/playsim/.+") source_group("Playsim\\Bots" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/playsim/bots/.+") source_group("Playsim\\FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/playsim/fragglescript/.+") @@ -1358,33 +1459,7 @@ source_group("Playsim\\Map Thinkers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE source_group("Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/.+") source_group("Rendering\\2D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/2d/.+") source_group("Rendering\\Hardware Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/.+") -source_group("Rendering\\Hardware Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/data/.+") -source_group("Rendering\\Hardware Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/dynlights/.+") -source_group("Rendering\\Hardware Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/models/.+") -source_group("Rendering\\Hardware Renderer\\Postprocessing" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/postprocessing/.+") -source_group("Rendering\\Hardware Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/renderer/.+") source_group("Rendering\\Hardware Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/scene/.+") -source_group("Rendering\\Hardware Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/shaders/.+") -source_group("Rendering\\Hardware Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/system/.+") -source_group("Rendering\\Hardware Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/textures/.+") -source_group("Rendering\\Hardware Renderer\\Utilities" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/utility/.+") -source_group("Rendering\\Vulkan Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/vulkan/system/.+") -source_group("Rendering\\Vulkan Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/vulkan/renderer/.+") -source_group("Rendering\\Vulkan Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/vulkan/shaders/.+") -source_group("Rendering\\Vulkan Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/vulkan/textures/.+") -source_group("Rendering\\Vulkan Renderer\\Third Party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/vulkan/thirdparty/.+") -source_group("Rendering\\Vulkan Renderer\\Third Party\\Volk" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/vulkan/thirdparty/volk/.+") -source_group("Rendering\\Vulkan Renderer\\Third Party\\Vk_Mem_Alloc" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/vulkan/thirdparty/vk_mem_alloc.+") -source_group("Rendering\\OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl_load/.+") -source_group("Rendering\\OpenGL Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/.+") -source_group("Rendering\\OpenGL Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/data/.+") -source_group("Rendering\\OpenGL Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/dynlights/.+") -source_group("Rendering\\OpenGL Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/renderer/.+") -source_group("Rendering\\OpenGL Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/scene/.+") -source_group("Rendering\\OpenGL Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/shaders/.+") -source_group("Rendering\\OpenGL Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/system/.+") -source_group("Rendering\\OpenGL Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/textures/.+") -source_group("Rendering\\OpenGL Renderer\\Utilities" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/utility/.+") source_group("Rendering\\Software Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/.+") source_group("Rendering\\Software Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/drawers/.+") source_group("Rendering\\Software Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/scene/.+") @@ -1393,30 +1468,75 @@ source_group("Rendering\\Software Renderer\\Line" REGULAR_EXPRESSION "^${CMAKE_C source_group("Rendering\\Software Renderer\\Plane" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/plane/.+") source_group("Rendering\\Software Renderer\\Things" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/things/.+") source_group("Rendering\\Software Renderer\\Viewport" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/viewport/.+") -source_group("Rendering\\Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/.+") -source_group("Rendering\\Poly Renderer\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/math/.+") -source_group("Rendering\\Poly Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/drawers/.+") -source_group("Rendering\\Poly Renderer\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/backend/.+") source_group("Render Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+") -source_group("Render Data\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/models/.+") source_group("Render Interface" FILES r_defs.h r_renderer.h r_sky.cpp r_sky.h r_state.h r_utility.cpp r_utility.h) source_group("Platforms\\POSIX Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/.+") -source_group("Platforms\\Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/cocoa/.+") -source_group("Platforms\\OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/.+") -source_group("Platforms\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+") -source_group("Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+") source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+") source_group("Scripting\\Decorate frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+") -source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h) +source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+") source_group("Scripting\\Compiler backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/backend/.+") -source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+") source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+") +source_group("Common" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/.+") +source_group("Common\\Audio" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/audio/.+") +source_group("Common\\Audio\\Sound" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/audio/sound/.+") +source_group("Common\\Audio\\Sound\\Third-party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/audio/sound/thirdparty/.+") +source_group("Common\\Audio\\Music" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/audio/music.+") +source_group("Common\\Console" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/console/.+") +source_group("Common\\Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/utility/.+") +source_group("Common\\Engine" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/engine/.+") +source_group("Common\\2D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/2d/.+") +source_group("Common\\Cutscenes" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/cutscenes/.+") +source_group("Common\\Objects" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/objects/.+") +source_group("Common\\Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/menu/.+") +source_group("Common\\Fonts" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/fonts/.+") +source_group("Common\\File System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/filesystem/.+") +source_group("Common\\File System\\Include" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/filesystem/include/.+") +source_group("Common\\File System\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/filesystem/source/.+") +source_group("Common\\Startscreen" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/startscreen/.+") +source_group("Common\\Widgets" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/widgets/.+") +source_group("Common\\Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/.+") +source_group("Common\\Scripting\\Interface" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/interface/.+") +source_group("Common\\Scripting\\Frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/frontend/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h) +source_group("Common\\Scripting\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/backend/.+") +source_group("Common\\Scripting\\Core" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/core/.+") +source_group("Common\\Scripting\\JIT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/jit/.+") +source_group("Common\\Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/scripting/vm/.+") +source_group("Common\\Platforms\\Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/platform/posix/cocoa/.+") +source_group("Common\\Platforms\\OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/platform/posix/osx/.+") +source_group("Common\\Platforms\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/platform/posix/unix/.+") +source_group("Common\\Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/platform/posix/sdl/.+") +source_group("Common\\Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/platform/win32/.+") +source_group("Common\\Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/.+") +source_group("Common\\Rendering\\Hardware Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/hwrenderer/.+") +source_group("Common\\Rendering\\Hardware Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/hwrenderer/data/.+") +source_group("Common\\Rendering\\Hardware Renderer\\Postprocessing" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/hwrenderer/postprocessing/.+") +source_group("Common\\Rendering\\OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/gl_load/.+") +source_group("Common\\Rendering\\OpenGL Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/gl/.+") +source_group("Common\\Rendering\\GLES Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/gles/.+") +source_group("Common\\Rendering\\Vulkan Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/system/.+") +source_group("Common\\Rendering\\Vulkan Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/renderer/.+") +source_group("Common\\Rendering\\Vulkan Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/shaders/.+") +source_group("Common\\Rendering\\Vulkan Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/textures/.+") +source_group("Common\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/models/.+") +source_group("Common\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/.+") +source_group("Common\\Textures\\Hires" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/hires/.+") +source_group("Common\\Textures\\Hires\\HQ Resize" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/hires/hqnx/.+") +source_group("Common\\Textures\\Hires\\HQ Resize MMX version" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/hires/hqnx_asm/.+") +source_group("Common\\Textures\\Hires\\XBRZ" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/hires/xbr/.+") +source_group("Common\\Textures\\Formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/formats/.+") +source_group("Common\\Third Party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/.+") +source_group("Common\\Third Party\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/math/.+") +source_group("Common\\Third Party\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/rapidjson/.+") +source_group("Common\\Third Party\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/sfmt/.+") +source_group("Common\\Third Party\\stb" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/stb/.+") +source_group("Common\\Third Party\\utf8proc" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/utf8proc/.+") source_group("Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/.+") source_group("Utility\\Node Builder" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/nodebuilder/.+") -source_group("Utility\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/math/.+") -source_group("Utility\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/rapidjson/.+") -source_group("Utility\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/sfmt/.+") +source_group("Utility\\Smackerdec" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/smackerdec/.+") +source_group("Utility\\Smackerdec\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/libsmackerdec/include/.+") +source_group("Utility\\Smackerdec\\Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/libsmackerdec/src/.+") source_group("Statusbar" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_statusbar/.+") +source_group("Launcher" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/launcher/.+") source_group("Versioning" FILES version.h win32/zdoom.rc) source_group("Xlat" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/xlat/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h) -source_group("Source Files" FILES ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h utility/sc_man_scanner.re) +source_group("Source Files" FILES ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h common/engine/sc_man_scanner.re) diff --git a/src/__autostart.cpp b/src/__autostart.cpp deleted file mode 100644 index 13e104d7537..00000000000 --- a/src/__autostart.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* -** autostart.cpp -** This file contains the heads of lists stored in special data segments -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** The particular scheme used here was chosen because it's small. -** -** An alternative that will work with any C++ compiler is to use static -** classes to build these lists at run time. Under Visual C++, doing things -** that way can require a lot of extra space, which is why I'm doing things -** this way. -** -** In the case of PClass lists (section creg), I orginally used the -** constructor to do just that, and the code for that still exists if you -** compile with something other than Visual C++ or GCC. -*/ - -#include "autosegs.h" - -#if defined(_MSC_VER) - -// The various reg sections are used to group pointers spread across multiple -// source files into cohesive arrays in the final executable. We don't -// actually care about these sections themselves and merge them all into -// a single section during the final link. (.rdata is the standard section -// for initialized read-only data.) - -#pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.freg=.rdata") -#pragma comment(linker, "/merge:.greg=.rdata /merge:.yreg=.rdata") - -#pragma section(".areg$a",read) -__declspec(allocate(".areg$a")) void *const ARegHead = 0; - -#pragma section(".creg$a",read) -__declspec(allocate(".creg$a")) void *const CRegHead = 0; - -#pragma section(".freg$a",read) -__declspec(allocate(".freg$a")) void *const FRegHead = 0; - -#pragma section(".greg$a",read) -__declspec(allocate(".greg$a")) void *const GRegHead = 0; - -#pragma section(".yreg$a",read) -__declspec(allocate(".yreg$a")) void *const YRegHead = 0; - -// We want visual styles support under XP -#if defined _M_IX86 - -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") - -#elif defined _M_IA64 - -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") - -#elif defined _M_X64 - -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") - -#else - -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") - -#endif - -#elif defined(__GNUC__) - -#include "doomtype.h" - -// I don't know of an easy way to merge sections together with the GNU linker, -// so GCC users will see all of these sections appear in the final executable. -// (There are linker scripts, but that apparently involves extracting the -// default script from ld and then modifying it.) - -void *const ARegHead __attribute__((section(SECTION_AREG))) = 0; -void *const CRegHead __attribute__((section(SECTION_CREG))) = 0; -void *const FRegHead __attribute__((section(SECTION_FREG))) = 0; -void *const GRegHead __attribute__((section(SECTION_GREG))) = 0; -void *const YRegHead __attribute__((section(SECTION_YREG))) = 0; - -#else - -#error Please fix autostart.cpp for your compiler - -#endif diff --git a/src/am_map.cpp b/src/am_map.cpp index 3c246e5f455..c547884b2e2 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -29,24 +29,26 @@ #include #include "doomdef.h" -#include "templates.h" + #include "g_level.h" #include "st_stuff.h" #include "p_local.h" #include "p_lnspec.h" -#include "w_wad.h" +#include "filesystem.h" #include "a_sharedglobal.h" #include "d_event.h" #include "gi.h" #include "p_setup.h" #include "c_bind.h" -#include "serializer.h" +#include "serializer_doom.h" #include "r_sky.h" #include "sbar.h" #include "d_player.h" #include "p_blockmap.h" #include "g_game.h" #include "v_video.h" +#include "d_main.h" +#include "v_draw.h" #include "m_cheat.h" #include "c_dispatch.h" @@ -65,6 +67,9 @@ #include "g_levellocals.h" #include "actorinlines.h" #include "earcut.hpp" +#include "c_buttons.h" +#include "d_buttons.h" +#include "texturemanager.h" //============================================================================= @@ -80,8 +85,10 @@ enum // C++ cannot do static const floats in a class, so these need to be global... static const double PLAYERRADIUS = 16.; // player radius for automap checking -static const double M_ZOOMIN = (1.02); // how much zoom-in per tic - goes to 2x in 1 second -static const double M_ZOOMOUT = (1 / 1.02); // how much zoom-out per tic - pulls out to 0.5x in 1 second +static const double M_ZOOMIN = 2; // how much zoom-in per second +static const double M_ZOOMOUT = 0.2; // how much zoom-out per second +static const double M_OLDZOOMIN = (1.02); // for am_zoom +static const double M_OLDZOOMOUT = (1 / 1.02); static FTextureID marknums[AM_NUMMARKPOINTS]; // numbers used for marking by the automap bool automapactive = false; @@ -124,6 +131,9 @@ struct islope_t //============================================================================= CVAR(Bool, am_textured, false, CVAR_ARCHIVE) +CVAR(Float, am_linealpha, 1.0f, CVAR_ARCHIVE) +CVAR(Int, am_linethickness, 1, CVAR_ARCHIVE) +CVAR(Int, am_lineantialiasing, 0, CVAR_ARCHIVE) CVAR(Bool, am_thingrenderstyles, true, CVAR_ARCHIVE) CVAR(Int, am_showsubsector, -1, 0); @@ -146,7 +156,15 @@ CUSTOM_CVAR(Int, am_cheat, 0, 0) CVAR(Int, am_rotate, 0, CVAR_ARCHIVE); -CVAR(Int, am_overlay, 0, CVAR_ARCHIVE); +CUSTOM_CVAR(Int, am_overlay, 0, CVAR_ARCHIVE) +{ + // stop overlay if we're told not to use it anymore. + if (automapactive && viewactive && (self == 0)) + { + automapactive = false; + viewactive = true; + } +} CVAR(Bool, am_showsecrets, true, CVAR_ARCHIVE); CVAR(Bool, am_showmonsters, true, CVAR_ARCHIVE); CVAR(Bool, am_showitems, false, CVAR_ARCHIVE); @@ -187,7 +205,7 @@ CUSTOM_CVAR(Int, am_emptyspacemargin, 0, CVAR_ARCHIVE) CVAR(Bool, am_followplayer, true, CVAR_ARCHIVE) CVAR(Bool, am_portaloverlay, true, CVAR_ARCHIVE) CVAR(Bool, am_showgrid, false, CVAR_ARCHIVE) -CVAR(Float, am_zoomdir, 0, CVAR_ARCHIVE) +CVAR(Float, am_zoomdir, 0.f, CVAR_ARCHIVE) static const char *const DEFAULT_FONT_NAME = "AMMNUMx"; CVAR(String, am_markfont, DEFAULT_FONT_NAME, CVAR_ARCHIVE) @@ -198,19 +216,19 @@ CCMD(am_togglefollow) am_followplayer = !am_followplayer; if (primaryLevel && primaryLevel->automap) primaryLevel->automap->ResetFollowLocation(); - Printf("%s\n", GStrings(am_followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF")); + Printf("%s\n", GStrings.GetString(am_followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF")); } CCMD(am_togglegrid) { am_showgrid = !am_showgrid; - Printf("%s\n", GStrings(am_showgrid ? "AMSTR_GRIDON" : "AMSTR_GRIDOFF")); + Printf("%s\n", GStrings.GetString(am_showgrid ? "AMSTR_GRIDON" : "AMSTR_GRIDOFF")); } CCMD(am_toggletexture) { am_textured = !am_textured; - Printf("%s\n", GStrings(am_textured ? "AMSTR_TEXON" : "AMSTR_TEXOFF")); + Printf("%s\n", GStrings.GetString(am_textured ? "AMSTR_TEXON" : "AMSTR_TEXOFF")); } CCMD(am_setmark) @@ -220,7 +238,7 @@ CCMD(am_setmark) int m = primaryLevel->automap->addMark(); if (m >= 0) { - Printf("%s %d\n", GStrings("AMSTR_MARKEDSPOT"), m); + Printf("%s %d\n", GStrings.GetString("AMSTR_MARKEDSPOT"), m); } } } @@ -229,7 +247,7 @@ CCMD(am_clearmarks) { if (primaryLevel && primaryLevel->automap && primaryLevel->automap->clearMarks()) { - Printf("%s\n", GStrings("AMSTR_MARKSCLEARED")); + Printf("%s\n", GStrings.GetString("AMSTR_MARKSCLEARED")); } } @@ -317,30 +335,26 @@ CVAR (Color, am_ovportalcolor, 0x004022, CVAR_ARCHIVE); struct AMColor { - int Index; uint32_t RGB; void FromCVar(FColorCVar & cv) { - Index = cv.GetIndex(); RGB = uint32_t(cv) | MAKEARGB(255, 0, 0, 0); } void FromRGB(int r,int g, int b) { RGB = MAKEARGB(255, r, g, b); - Index = ColorMatcher.Pick(r, g, b); } void setInvalid() { - Index = -1; - RGB = -1; + RGB = 0; } bool isValid() const { - return Index > -1; + return RGB != 0; } }; @@ -416,11 +430,11 @@ struct AMColorset bool forcebackground; bool defined; // only for mod specific colorsets: must be true to be usable - void initFromCVars(FColorCVar **values) + void initFromCVars(FColorCVarRef **values) { for(int i=0;iget())); } uint32_t ba = *(values[0]); @@ -508,7 +522,7 @@ static const int AUTOMAP_LINE_COLORS[AMLS_COUNT] = // //============================================================================= -static FColorCVar *cv_standard[] = { +static FColorCVarRef *cv_standard[] = { &am_backcolor, &am_yourcolor, &am_wallcolor, @@ -535,7 +549,7 @@ static FColorCVar *cv_standard[] = { &am_portalcolor }; -static FColorCVar *cv_overlay[] = { +static FColorCVarRef *cv_overlay[] = { &am_backcolor, // this will not be used in overlay mode &am_ovyourcolor, &am_ovwallcolor, @@ -566,11 +580,11 @@ CCMD(am_restorecolors) { for (unsigned i = 0; i < countof(cv_standard); i++) { - cv_standard[i]->ResetToDefault(); + cv_standard[i]->get()->ResetToDefault(); } for (unsigned i = 0; i < countof(cv_overlay); i++) { - cv_overlay[i]->ResetToDefault(); + cv_overlay[i]->get()->ResetToDefault(); } } @@ -786,9 +800,9 @@ void FMapInfoParser::ParseAMColors(bool overlay) { sc.MustGetToken(TK_StringConst); FString color = sc.String; - FString colorName = V_GetColorStringByName(color); + FString colorName = V_GetColorStringByName(color.GetChars()); if(!colorName.IsEmpty()) color = colorName; - int colorval = V_GetColorFromString(nullptr, color); + int colorval = V_GetColorFromString(color.GetChars()); cset.c[i].FromRGB(RPART(colorval), GPART(colorval), BPART(colorval)); colorset = true; break; @@ -831,7 +845,7 @@ static void AM_ParseArrow(TArray &Arrow, const char *lumpname) { const int R = int((8 * PLAYERRADIUS) / 7); FScanner sc; - int lump = Wads.CheckNumForFullName(lumpname, true); + int lump = fileSystem.CheckNumForFullName(lumpname, true); if (lump >= 0) { sc.OpenLumpNum(lump); @@ -866,10 +880,10 @@ void AM_StaticInit() CheatKey.Clear(); EasyKey.Clear(); - if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow); - if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow); - AM_ParseArrow(CheatKey, gameinfo.mCheatKey); - AM_ParseArrow(EasyKey, gameinfo.mEasyKey); + if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow.GetChars()); + if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow.GetChars()); + AM_ParseArrow(CheatKey, gameinfo.mCheatKey.GetChars()); + AM_ParseArrow(EasyKey, gameinfo.mEasyKey.GetChars()); if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined"); char namebuf[9]; @@ -989,8 +1003,8 @@ class DAutomap :public DAutomapBase void calcMinMaxMtoF(); - void DrawMarker(FTexture *tex, double x, double y, int yadjust, - INTBOOL flip, double xscale, double yscale, int translation, double alpha, uint32_t fillcolor, FRenderStyle renderstyle); + void DrawMarker(FGameTexture *tex, double x, double y, int yadjust, + INTBOOL flip, double xscale, double yscale, FTranslationID translation, double alpha, uint32_t fillcolor, FRenderStyle renderstyle); void rotatePoint(double *x, double *y); void rotate(double *x, double *y, DAngle an); @@ -1004,7 +1018,7 @@ class DAutomap :public DAutomapBase void ScrollParchment(double dmapx, double dmapy); void changeWindowLoc(); void maxOutWindowScale(); - void changeWindowScale(); + void changeWindowScale(double delta); void clearFB(const AMColor &color); bool clipMline(mline_t *ml, fline_t *fl); void drawMline(mline_t *ml, const AMColor &color); @@ -1188,11 +1202,11 @@ void DAutomap::findMinMaxBoundaries () void DAutomap::calcMinMaxMtoF() { const double safe_frame = 1.0 - am_emptyspacemargin / 100.0; - double a = safe_frame * (SCREENWIDTH / max_w); + double a = safe_frame * (twod->GetWidth() / max_w); double b = safe_frame * (StatusBar->GetTopOfStatusbar() / max_h); min_scale_mtof = a < b ? a : b; - max_scale_mtof = SCREENHEIGHT / (2*PLAYERRADIUS); + max_scale_mtof = twod->GetHeight() / (2*PLAYERRADIUS); } //============================================================================= @@ -1236,12 +1250,12 @@ void DAutomap::ScrollParchment (double dmapx, double dmapy) if (mapback.isValid()) { - FTexture *backtex = TexMan.GetTexture(mapback); + auto backtex = TexMan.GetGameTexture(mapback); if (backtex != nullptr) { - int pwidth = backtex->GetDisplayWidth(); - int pheight = backtex->GetDisplayHeight(); + int pwidth = int(backtex->GetDisplayWidth() * CleanXfac); + int pheight = int(backtex->GetDisplayHeight() * CleanYfac); while(mapxstart > 0) mapxstart -= pwidth; @@ -1275,11 +1289,11 @@ void DAutomap::changeWindowLoc () incx = m_paninc.x; incy = m_paninc.y; - oincx = incx = m_paninc.x * SCREENWIDTH / 320; - oincy = incy = m_paninc.y * SCREENHEIGHT / 200; + oincx = incx = m_paninc.x * twod->GetWidth() / 320; + oincy = incy = m_paninc.y * twod->GetHeight() / 200; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { - rotate(&incx, &incy, players[consoleplayer].camera->Angles.Yaw - 90.); + rotate(&incx, &incy, players[consoleplayer].camera->InterpolatedAngles(r_viewpoint.TicFrac).Yaw - DAngle::fromDeg(90.)); } m_x += incx; @@ -1306,8 +1320,8 @@ void DAutomap::startDisplay() m_paninc.x = m_paninc.y = 0; mtof_zoommul = 1.; - m_w = FTOM(SCREENWIDTH); - m_h = FTOM(SCREENHEIGHT); + m_w = FTOM(twod->GetWidth()); + m_h = FTOM(twod->GetHeight()); // find player to center on initially if (!playeringame[pnum = consoleplayer]) @@ -1354,7 +1368,7 @@ void DAutomap::LevelInit () } else { - mapback = TexMan.CheckForTexture(Level->info->MapBackground, ETextureType::MiscPatch); + mapback = TexMan.CheckForTexture(Level->info->MapBackground.GetChars(), ETextureType::MiscPatch); } clearMarks(); @@ -1413,7 +1427,7 @@ void DAutomap::NewResolution() minOutWindowScale(); else if (scale_mtof > max_scale_mtof) maxOutWindowScale(); - f_w = screen->GetWidth(); + f_w = twod->GetWidth(); f_h = StatusBar->GetTopOfStatusbar(); activateNewScale(); } @@ -1433,7 +1447,7 @@ bool DAutomap::Responder (event_t *ev, bool last) { // check for am_pan* and ignore in follow mode const char *defbind = AutomapBindings.GetBind(ev->data1); - if (!strnicmp(defbind, "+am_pan", 7)) return false; + if (defbind && !strnicmp(defbind, "+am_pan", 7)) return false; } bool res = C_DoKey(ev, &AutomapBindings, nullptr); @@ -1442,7 +1456,7 @@ bool DAutomap::Responder (event_t *ev, bool last) // If this is a release event we also need to check if it released a button in the main Bindings // so that that button does not get stuck. const char *defbind = Bindings.GetBind(ev->data1); - return (defbind[0] != '+'); // Let G_Responder handle button releases + return (!defbind || defbind[0] != '+'); // Let G_Responder handle button releases } return res; } @@ -1456,25 +1470,26 @@ bool DAutomap::Responder (event_t *ev, bool last) // //============================================================================= -void DAutomap::changeWindowScale () +void DAutomap::changeWindowScale (double delta) { + double mtof_zoommul; if (am_zoomdir > 0) { - mtof_zoommul = M_ZOOMIN * am_zoomdir; + mtof_zoommul = M_OLDZOOMIN * am_zoomdir; } else if (am_zoomdir < 0) { - mtof_zoommul = M_ZOOMOUT / -am_zoomdir; + mtof_zoommul = M_OLDZOOMOUT / -am_zoomdir; } - else if (Button_AM_ZoomIn.bDown) + else if (buttonMap.ButtonDown(Button_AM_ZoomIn)) { - mtof_zoommul = M_ZOOMIN; + mtof_zoommul = (1 + (M_ZOOMIN - 1) * delta); } - else if (Button_AM_ZoomOut.bDown) + else if (buttonMap.ButtonDown(Button_AM_ZoomOut)) { - mtof_zoommul = M_ZOOMOUT; + mtof_zoommul = (1 + (M_ZOOMOUT - 1) * delta); } else { @@ -1505,7 +1520,7 @@ void DAutomap::doFollowPlayer () if (cam != nullptr) { double delta = cam->player ? cam->player->viewz - cam->Z() : cam->GetCameraHeight(); - DVector3 ampos = cam->GetPortalTransition(delta); + DVector3 ampos = cam->InterpolatedPosition(r_viewpoint.TicFrac); if (f_oldloc.x != ampos.X || f_oldloc.y != ampos.Y) { @@ -1519,7 +1534,7 @@ void DAutomap::doFollowPlayer () sy = (f_oldloc.y - ampos.Y); if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { - rotate(&sx, &sy, cam->Angles.Yaw - 90); + rotate(&sx, &sy, cam->InterpolatedAngles(r_viewpoint.TicFrac).Yaw - DAngle::fromDeg(90)); } ScrollParchment(sx, sy); @@ -1541,27 +1556,6 @@ void DAutomap::Ticker () return; amclock++; - - if (am_followplayer) - { - doFollowPlayer(); - } - else - { - m_paninc.x = m_paninc.y = 0; - if (Button_AM_PanLeft.bDown) m_paninc.x -= FTOM(F_PANINC); - if (Button_AM_PanRight.bDown) m_paninc.x += FTOM(F_PANINC); - if (Button_AM_PanUp.bDown) m_paninc.y += FTOM(F_PANINC); - if (Button_AM_PanDown.bDown) m_paninc.y -= FTOM(F_PANINC); - } - - // Change the zoom if necessary - if (Button_AM_ZoomIn.bDown || Button_AM_ZoomOut.bDown || am_zoomdir != 0) - changeWindowScale(); - - // Change x,y location - //if (m_paninc.x || m_paninc.y) - changeWindowLoc(); } @@ -1585,15 +1579,15 @@ void DAutomap::clearFB (const AMColor &color) if (!drawback) { - screen->Clear (0, 0, f_w, f_h, color.Index, color.RGB); + ClearRect(twod, 0, 0, f_w, f_h, -1, color.RGB); } else { - FTexture *backtex = TexMan.GetTexture(mapback); + auto backtex = TexMan.GetGameTexture(mapback); if (backtex != nullptr) { - int pwidth = backtex->GetDisplayWidth(); - int pheight = backtex->GetDisplayHeight(); + int pwidth = int(backtex->GetDisplayWidth() * CleanXfac); + int pheight = int(backtex->GetDisplayHeight() * CleanYfac); int x, y; //blit the automap background to the screen. @@ -1601,7 +1595,7 @@ void DAutomap::clearFB (const AMColor &color) { for (x = int(mapxstart); x < f_w; x += pwidth) { - screen->DrawTexture (backtex, x, y, DTA_ClipBottom, f_h, DTA_TopOffset, 0, DTA_LeftOffset, 0, TAG_DONE); + DrawTexture(twod, backtex, x, y, DTA_ClipBottom, f_h, DTA_TopOffset, 0, DTA_LeftOffset, 0, DTA_DestWidth, pwidth, DTA_DestHeight, pheight, TAG_DONE); } } } @@ -1752,7 +1746,68 @@ void DAutomap::drawMline (mline_t *ml, const AMColor &color) if (clipMline (ml, &fl)) { - screen->DrawLine (f_x + fl.a.x, f_y + fl.a.y, f_x + fl.b.x, f_y + fl.b.y, color.Index, color.RGB); + const int x1 = f_x + fl.a.x; + const int y1 = f_y + fl.a.y; + const int x2 = f_x + fl.b.x; + const int y2 = f_y + fl.b.y; + + if (am_lineantialiasing) { + // Draw 5 lines (am_linethickness 2) or 9 lines (am_linethickness >= 3) + // slightly offset from each other, but with lower opacity + // as a bruteforce way to achieve antialiased line drawing. + const int aa_alpha_divide = am_linethickness >= 3 ? 3 : 2; + + // Subtract to line thickness to compensate for the antialiasing making lines thicker. + const int aa_linethickness = max(1, am_linethickness - 2); + + if (aa_linethickness >= 2) { + // Top row. + twod->AddThickLine(DVector2(x1 - 1, y1 - 1), DVector2(x2 - 1, y2 - 1), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddThickLine(DVector2(x1 + 1, y1 - 1), DVector2(x2 + 1, y2 - 1), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddThickLine(DVector2(x1, y1 - 1), DVector2(x2, y2 - 1), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + + // Middle row. + twod->AddThickLine(DVector2(x1 - 1, y1), DVector2(x2 - 1, y2), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddThickLine(DVector2(x1 + 1, y1), DVector2(x2 + 1, y2), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddThickLine(DVector2(x1, y1), DVector2(x2, y2), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + + // Bottom row. + twod->AddThickLine(DVector2(x1 - 1, y1 + 1), DVector2(x2 - 1, y2 + 1), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddThickLine(DVector2(x1 + 1, y1 + 1), DVector2(x2 + 1, y2 + 1), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddThickLine(DVector2(x1, y1 - 1), DVector2(x2, y2 - 1), aa_linethickness, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + } else { + // Use more efficient thin line drawing routine. + // Top row. + if (am_linethickness >= 3) { + // If original line thickness is 2, do not add diagonal lines to allow thin lines to be represented. + // This part is not needed for thick antialiased drawing, as original line thickness is always greater than 3. + twod->AddLine(DVector2(x1 - 1, y1 - 1), DVector2(x2 - 1, y2 - 1), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddLine(DVector2(x1 + 1, y1 - 1), DVector2(x2 + 1, y2 - 1), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + } + twod->AddLine(DVector2(x1, y1 - 1), DVector2(x2, y2 - 1), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + + // Middle row. + twod->AddLine(DVector2(x1 - 1, y1), DVector2(x2 - 1, y2), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddLine(DVector2(x1 + 1, y1), DVector2(x2 + 1, y2), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddLine(DVector2(x1, y1), DVector2(x2, y2), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + + // Bottom row. + if (am_linethickness >= 3) { + // If original line thickness is 2, do not add diagonal lines to allow thin lines to be represented. + // This part is not needed for thick antialiased drawing, as original line thickness is always greater than 3. + twod->AddLine(DVector2(x1 - 1, y1 + 1), DVector2(x2 - 1, y2 + 1), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + twod->AddLine(DVector2(x1 + 1, y1 + 1), DVector2(x2 + 1, y2 + 1), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + } + twod->AddLine(DVector2(x1, y1 - 1), DVector2(x2, y2 - 1), nullptr, color.RGB, uint8_t(am_linealpha * 255 / aa_alpha_divide)); + } + } else { + if (am_linethickness >= 2) { + twod->AddThickLine(DVector2(x1, y1), DVector2(x2, y2), am_linethickness, color.RGB, uint8_t(am_linealpha * 255)); + } else { + // Use more efficient thin line drawing routine. + twod->AddLine(DVector2(x1, y1), DVector2(x2, y2), nullptr, color.RGB, uint8_t(am_linealpha * 255)); + } + } } } @@ -1841,7 +1896,7 @@ sector_t * AM_FakeFlat(AActor *viewer, sector_t * sec, sector_t * dest) { if (sec->GetHeightSec() == nullptr) return sec; - DVector3 pos = viewer->Pos(); + DVector3 pos = viewer->InterpolatedPosition(r_viewpoint.TicFrac); if (viewer->player) { @@ -1965,6 +2020,9 @@ void DAutomap::drawSubsectors() PalEntry flatcolor; mpoint_t originpt; + auto lm = getRealLightmode(Level, false); + bool softlightramp = !V_IsHardwareRenderer() || lm == ELightMode::Doom || lm == ELightMode::DoomDark; + auto &subsectors = Level->subsectors; for (unsigned i = 0; i < subsectors.Size(); ++i) { @@ -2081,14 +2139,14 @@ void DAutomap::drawSubsectors() } // Apply the floor's rotation to the texture origin. - if (rotation != 0) + if (rotation != nullAngle) { rotate(&originpt.x, &originpt.y, rotation); } // Apply the automap's rotation to the texture origin. if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { - rotation = rotation + 90. - players[consoleplayer].camera->Angles.Yaw; + rotation = rotation + DAngle::fromDeg(90.) - players[consoleplayer].camera->InterpolatedAngles(r_viewpoint.TicFrac).Yaw; rotatePoint(&originpt.x, &originpt.y); } originx = f_x + ((originpt.x - m_x) * scale); @@ -2133,7 +2191,24 @@ void DAutomap::drawSubsectors() } else indices.clear(); - screen->FillSimplePoly(TexMan.GetTexture(maptex, true), + // Use an equation similar to player sprites to determine shade + + // Convert a light level into an unbounded colormap index (shade). + // Why the +12? I wish I knew, but experimentation indicates it + // is necessary in order to best reproduce Doom's original lighting. + double fadelevel; + if (softlightramp) + { + double map = (NUMCOLORMAPS * 2.) - ((floorlight + 12) * (NUMCOLORMAPS / 128.)); + fadelevel = clamp((map - 12) / NUMCOLORMAPS, 0.0, 1.0); + } + else + { + // for the hardware renderer's light modes that use a linear light scale this must do the same. Otherwise the automap gets too dark. + fadelevel = 1. - clamp(floorlight, 0, 255) / 255.f; + } + + twod->AddPoly(TexMan.GetGameTexture(maptex, true), &points[0], points.Size(), originx, originy, scale / scalex, @@ -2141,8 +2216,7 @@ void DAutomap::drawSubsectors() rotation, colormap, flatcolor, - floorlight, - f_y + f_h, + fadelevel, indices.data(), indices.size()); } } @@ -2550,7 +2624,7 @@ void DAutomap::drawWalls (bool allmap) } else if (line.flags & ML_SECRET) { // secret door - if (am_cheat != 0 && line.backsector != nullptr) + if (am_cheat != 0 && am_cheat < 4 && line.backsector != nullptr) drawMline(&l, AMColors.SecretWallColor); else drawMline(&l, AMColors.WallColor); @@ -2635,7 +2709,7 @@ void DAutomap::drawWalls (bool allmap) void DAutomap::rotate(double *xp, double *yp, DAngle a) { - static DAngle angle_saved = 0.; + static DAngle angle_saved = nullAngle; static double sinrot = 0; static double cosrot = 1; @@ -2667,7 +2741,7 @@ void DAutomap::rotatePoint (double *x, double *y) double pivoty = m_y + m_h/2; *x -= pivotx; *y -= pivoty; - rotate (x, y, -players[consoleplayer].camera->Angles.Yaw + 90.); + rotate (x, y, -players[consoleplayer].camera->InterpolatedAngles(r_viewpoint.TicFrac).Yaw + DAngle::fromDeg(90.)); *x += pivotx; *y += pivoty; } @@ -2693,7 +2767,7 @@ void DAutomap::drawLineCharacter(const mline_t *lineguy, size_t lineguylines, do l.a.y *= scale; } - if (angle != 0) + if (angle != nullAngle) rotate(&l.a.x, &l.a.y, angle); l.a.x += x; @@ -2708,7 +2782,7 @@ void DAutomap::drawLineCharacter(const mline_t *lineguy, size_t lineguylines, do l.b.y *= scale; } - if (angle != 0) + if (angle != nullAngle) rotate(&l.b.x, &l.b.y, angle); l.b.x += x; @@ -2742,17 +2816,17 @@ void DAutomap::drawPlayers () int numarrowlines; double vh = players[consoleplayer].viewheight; - DVector2 pos = am_portaloverlay? players[consoleplayer].camera->GetPortalTransition(vh) : players[consoleplayer].camera->Pos(); + DVector2 pos = players[consoleplayer].mo->InterpolatedPosition(r_viewpoint.TicFrac).XY(); pt.x = pos.X; pt.y = pos.Y; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { - angle = 90.; + angle = DAngle::fromDeg(90.); rotatePoint (&pt.x, &pt.y); } else { - angle = players[consoleplayer].camera->Angles.Yaw; + angle = players[consoleplayer].mo->InterpolatedAngles(r_viewpoint.TicFrac).Yaw; } if (am_cheat != 0 && CheatMapArrow.Size() > 0) @@ -2806,16 +2880,17 @@ void DAutomap::drawPlayers () if (p->mo != nullptr) { - DVector3 pos = p->mo->PosRelative(MapPortalGroup); + DVector2 pos = p->mo->InterpolatedPosition(r_viewpoint.TicFrac).XY(); + pos += Level->Displacements.getOffset(Level->PointInSector(pos)->PortalGroup, MapPortalGroup); pt.x = pos.X; pt.y = pos.Y; - angle = p->mo->Angles.Yaw; + angle = p->mo->InterpolatedAngles(r_viewpoint.TicFrac).Yaw; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { rotatePoint (&pt.x, &pt.y); - angle -= players[consoleplayer].camera->Angles.Yaw - 90.; + angle -= players[consoleplayer].camera->InterpolatedAngles(r_viewpoint.TicFrac).Yaw - DAngle::fromDeg(90.); } drawLineCharacter(&MapArrow[0], MapArrow.Size(), 0, angle, color, pt.x, pt.y); @@ -2844,12 +2919,12 @@ void DAutomap::drawKeys () p.x = pos.X; p.y = pos.Y; - angle = key->Angles.Yaw; + angle = key->InterpolatedAngles(r_viewpoint.TicFrac).Yaw; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { rotatePoint (&p.x, &p.y); - angle += -players[consoleplayer].camera->Angles.Yaw + 90.; + angle += -players[consoleplayer].camera->InterpolatedAngles(r_viewpoint.TicFrac).Yaw + DAngle::fromDeg(90.); } if (key->flags & MF_SPECIAL) @@ -2861,7 +2936,7 @@ void DAutomap::drawKeys () if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); else color = AMColors[AMColors.ThingColor_CountItem]; - drawLineCharacter(&EasyKey[0], EasyKey.Size(), 0, 0., color, p.x, p.y); + drawLineCharacter(&EasyKey[0], EasyKey.Size(), 0, nullAngle, color, p.x, p.y); } } } @@ -2884,35 +2959,36 @@ void DAutomap::drawThings () while (t) { if (am_cheat > 0 || !(t->flags6 & MF6_NOTONAUTOMAP) - || (am_thingrenderstyles && !(t->renderflags & RF_INVISIBLE))) + || (am_thingrenderstyles && !(t->renderflags & RF_INVISIBLE) && !(t->flags6 & MF6_NOTONAUTOMAP))) { - DVector3 pos = t->PosRelative(MapPortalGroup); + DVector3 fracPos = t->InterpolatedPosition(r_viewpoint.TicFrac); + FVector2 pos = FVector2(float(fracPos.X),float(fracPos.Y)) + FVector2(t->Level->Displacements.getOffset(sec.PortalGroup, MapPortalGroup)) + FVector2(t->AutomapOffsets); p.x = pos.X; p.y = pos.Y; if (am_showthingsprites > 0 && t->sprite > 0) { - FTexture *texture = nullptr; + FGameTexture *texture = nullptr; spriteframe_t *frame; int rotation = 0; - // try all modes backwards until a valid texture has been found. + // try all modes backwards until a valid texture has been found. for(int show = am_showthingsprites; show > 0 && texture == nullptr; show--) { const spritedef_t& sprite = sprites[t->sprite]; const size_t spriteIndex = sprite.spriteframes + (show > 1 ? t->frame : 0); frame = &SpriteFrames[spriteIndex]; - DAngle angle = 270. + 22.5 - t->Angles.Yaw; - if (frame->Texture[0] != frame->Texture[1]) angle += 180. / 16; + DAngle angle = DAngle::fromDeg(270.) - t->InterpolatedAngles(r_viewpoint.TicFrac).Yaw - t->SpriteRotation; + if (frame->Texture[0] != frame->Texture[1]) angle += DAngle::fromDeg(180. / 16); if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { - angle += players[consoleplayer].camera->Angles.Yaw - 90.; + angle += players[consoleplayer].camera->InterpolatedAngles(r_viewpoint.TicFrac).Yaw - DAngle::fromDeg(90.); } - rotation = int((angle.Normalized360() * (16. / 360.)).Degrees); + rotation = int((angle.Normalized360() * (16. / 360.)).Degrees()); const FTextureID textureID = frame->Texture[show > 2 ? rotation : 0]; - texture = TexMan.GetTexture(textureID, true); + texture = TexMan.GetGameTexture(textureID, true); } if (texture == nullptr) goto drawTriangle; // fall back to standard display if no sprite can be found. @@ -2928,12 +3004,12 @@ void DAutomap::drawThings () else { drawTriangle: - angle = t->Angles.Yaw; + angle = t->InterpolatedAngles(r_viewpoint.TicFrac).Yaw; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { rotatePoint (&p.x, &p.y); - angle += -players[consoleplayer].camera->Angles.Yaw + 90.; + angle += -players[consoleplayer].camera->InterpolatedAngles(r_viewpoint.TicFrac).Yaw + DAngle::fromDeg(90.); } color = AMColors[AMColors.ThingColor]; @@ -2955,7 +3031,7 @@ void DAutomap::drawThings () if (G_SkillProperty(SKILLP_EasyKey) || am_showkeys_always) { // Already drawn by AM_drawKeys(), so don't draw again - color.Index = -1; + color.RGB = 0; } else if (am_showkeys) { @@ -2963,8 +3039,8 @@ void DAutomap::drawThings () if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); else color = AMColors[AMColors.ThingColor_CountItem]; - drawLineCharacter(&CheatKey[0], CheatKey.Size(), 0, 0., color, p.x, p.y); - color.Index = -1; + drawLineCharacter(&CheatKey[0], CheatKey.Size(), 0, nullAngle, color, p.x, p.y); + color.RGB = 0; } else { @@ -2977,7 +3053,7 @@ void DAutomap::drawThings () color = AMColors[AMColors.ThingColor_Item]; } - if (color.Index != -1) + if (color.isValid()) { drawLineCharacter(thintriangle_guy.data(), thintriangle_guy.size(), 16, angle, color, p.x, p.y); } @@ -2992,7 +3068,7 @@ void DAutomap::drawThings () { { -1, 1 }, { -1, -1 } }, }; - drawLineCharacter (box, 4, t->radius, angle - t->Angles.Yaw, color, p.x, p.y); + drawLineCharacter (box, 4, t->radius, angle - t->InterpolatedAngles(r_viewpoint.TicFrac).Yaw, color, p.x, p.y); } } } @@ -3007,26 +3083,31 @@ void DAutomap::drawThings () // //============================================================================= -void DAutomap::DrawMarker (FTexture *tex, double x, double y, int yadjust, - INTBOOL flip, double xscale, double yscale, int translation, double alpha, uint32_t fillcolor, FRenderStyle renderstyle) +void DAutomap::DrawMarker (FGameTexture *tex, double x, double y, int yadjust, + INTBOOL flip, double xscale, double yscale, FTranslationID translation, double alpha, uint32_t fillcolor, FRenderStyle renderstyle) { if (tex == nullptr || !tex->isValid()) { return; } + if (xscale < 0) + { + flip = !flip; + xscale = -xscale; + } if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { rotatePoint (&x, &y); } - screen->DrawTexture (tex, CXMTOF(x) + f_x, CYMTOF(y) + yadjust + f_y, - DTA_DestWidthF, tex->GetDisplayWidthDouble() * CleanXfac * xscale, - DTA_DestHeightF, tex->GetDisplayHeightDouble() * CleanYfac * yscale, + DrawTexture(twod, tex, CXMTOF(x) + f_x, CYMTOF(y) + yadjust + f_y, + DTA_DestWidthF, tex->GetDisplayWidth() * CleanXfac * xscale, + DTA_DestHeightF, tex->GetDisplayHeight() * CleanYfac * yscale, DTA_ClipTop, f_y, DTA_ClipBottom, f_y + f_h, DTA_ClipLeft, f_x, DTA_ClipRight, f_x + f_w, DTA_FlipX, flip, - DTA_TranslationIndex, translation, + DTA_TranslationIndex, translation.index(), DTA_Alpha, alpha, DTA_FillColor, fillcolor, DTA_RenderStyle, renderstyle.AsDWORD, @@ -3056,8 +3137,8 @@ void DAutomap::drawMarks () if (font == nullptr) { - DrawMarker(TexMan.GetTexture(marknums[i], true), markpoints[i].x, markpoints[i].y, -3, 0, - 1, 1, 0, 1, 0, LegacyRenderStyles[STYLE_Normal]); + DrawMarker(TexMan.GetGameTexture(marknums[i], true), markpoints[i].x, markpoints[i].y, -3, 0, + 1, 1, NO_TRANSLATION, 1, 0, LegacyRenderStyles[STYLE_Normal]); } else { @@ -3070,7 +3151,7 @@ void DAutomap::drawMarks () rotatePoint (&x, &y); } - screen->DrawText(font, am_markcolor, CXMTOF(x), CYMTOF(y), numstr, TAG_DONE); + DrawText(twod, font, am_markcolor, CXMTOF(x), CYMTOF(y), numstr, TAG_DONE); } } } @@ -3098,18 +3179,18 @@ void DAutomap::drawAuthorMarkers () } FTextureID picnum; - FTexture *tex; + FGameTexture *tex; uint16_t flip = 0; if (mark->picnum.isValid()) { - tex = TexMan.GetTexture(mark->picnum, true); + tex = TexMan.GetGameTexture(mark->picnum, true); if (tex->GetRotations() != 0xFFFF) { spriteframe_t *sprframe = &SpriteFrames[tex->GetRotations()]; picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; - tex = TexMan.GetTexture(picnum); + tex = TexMan.GetGameTexture(picnum); } } else @@ -3124,17 +3205,26 @@ void DAutomap::drawAuthorMarkers () spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + mark->frame]; picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; - tex = TexMan.GetTexture(picnum); + tex = TexMan.GetGameTexture(picnum); } } auto it = Level->GetActorIterator(mark->args[0]); AActor *marked = mark->args[0] == 0 ? mark : it.Next(); + double xscale = mark->Scale.X; + double yscale = mark->Scale.Y; + // [MK] scale with automap zoom if args[2] is 1, otherwise keep a constant scale + if (mark->args[2] == 1) + { + xscale = MTOF(xscale); + yscale = MTOF(yscale); + } + while (marked != nullptr) { if (mark->args[1] == 0 || (mark->args[1] == 1 && (marked->subsector->flags & SSECMF_DRAWN))) { - DrawMarker (tex, marked->X(), marked->Y(), 0, flip, mark->Scale.X, mark->Scale.Y, mark->Translation, + DrawMarker (tex, marked->X(), marked->Y(), 0, flip, xscale, yscale, mark->Translation, mark->Alpha, mark->fillcolor, mark->RenderStyle); } marked = mark->args[0] != 0 ? it.Next() : nullptr; @@ -3150,7 +3240,7 @@ void DAutomap::drawAuthorMarkers () void DAutomap::drawCrosshair (const AMColor &color) { - screen->DrawPixel(f_w/2, (f_h+1)/2, color.Index, color.RGB); + twod->AddPixel(f_w/2, (f_h+1)/2, color.RGB); } //============================================================================= @@ -3161,9 +3251,38 @@ void DAutomap::drawCrosshair (const AMColor &color) void DAutomap::Drawer (int bottom) { + static uint64_t LastMS = 0; + // Use a delta to zoom/pan at a constant speed regardless of current FPS + uint64_t ms = screen->FrameTime; + double delta = (ms - LastMS) * 0.001; + if (!automapactive) return; + if (am_followplayer) + { + doFollowPlayer(); + } + else + { + m_paninc.x = m_paninc.y = 0; + if (buttonMap.ButtonDown(Button_AM_PanLeft)) + m_paninc.x -= FTOM(F_PANINC) * delta * TICRATE; + if (buttonMap.ButtonDown(Button_AM_PanRight)) + m_paninc.x += FTOM(F_PANINC) * delta * TICRATE; + if (buttonMap.ButtonDown(Button_AM_PanUp)) + m_paninc.y += FTOM(F_PANINC) * delta * TICRATE; + if (buttonMap.ButtonDown(Button_AM_PanDown)) + m_paninc.y -= FTOM(F_PANINC) * delta * TICRATE; + } + + // Change the zoom if necessary + if (buttonMap.ButtonDown(Button_AM_ZoomIn) || buttonMap.ButtonDown(Button_AM_ZoomOut) || am_zoomdir != 0) + changeWindowScale(delta); + + // Change x,y location + changeWindowLoc(); + bool allmap = (Level->flags2 & LEVEL2_ALLMAP) != 0; bool allthings = allmap && players[consoleplayer].mo->FindInventory(NAME_PowerScanner, true) != nullptr; @@ -3182,7 +3301,7 @@ void DAutomap::Drawer (int bottom) // [RH] Set f_? here now to handle automap overlaying // and view size adjustments. f_x = f_y = 0; - f_w = screen->GetWidth (); + f_w = twod->GetWidth (); f_h = bottom; clearFB(AMColors[AMColors.Background]); @@ -3216,6 +3335,8 @@ void DAutomap::Drawer (int bottom) drawMarks(); showSS(); + + LastMS = ms; } //============================================================================= @@ -3341,12 +3462,12 @@ void AM_ToggleMap() if (!automapactive) { // Reset AM buttons - Button_AM_PanLeft.Reset(); - Button_AM_PanRight.Reset(); - Button_AM_PanUp.Reset(); - Button_AM_PanDown.Reset(); - Button_AM_ZoomIn.Reset(); - Button_AM_ZoomOut.Reset(); + buttonMap.ClearButton(Button_AM_PanLeft); + buttonMap.ClearButton(Button_AM_PanRight); + buttonMap.ClearButton(Button_AM_PanUp); + buttonMap.ClearButton(Button_AM_PanDown); + buttonMap.ClearButton(Button_AM_ZoomIn); + buttonMap.ClearButton(Button_AM_ZoomOut); primaryLevel->automap->startDisplay(); automapactive = true; diff --git a/src/autosegs.h b/src/autosegs.h deleted file mode 100644 index 9cba04ad232..00000000000 --- a/src/autosegs.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -** autosegs.h -** Arrays built at link-time -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef AUTOSEGS_H -#define AUTOSEGS_H - -#if defined(__clang__) -#if defined(__has_feature) && __has_feature(address_sanitizer) -#define NO_SANITIZE __attribute__((no_sanitize("address"))) -#else -#define NO_SANITIZE -#endif -#else -#define NO_SANITIZE -#endif - -#define REGMARKER(x) (x) -typedef void * const REGINFO; -typedef void * NCREGINFO; - -// List of Action functons -extern REGINFO ARegHead; -extern REGINFO ARegTail; - -// List of TypeInfos -extern REGINFO CRegHead; -extern REGINFO CRegTail; - -// List of class fields -extern REGINFO FRegHead; -extern REGINFO FRegTail; - -// List of properties -extern REGINFO GRegHead; -extern REGINFO GRegTail; - -// List of MAPINFO map options -extern REGINFO YRegHead; -extern REGINFO YRegTail; - -class FAutoSegIterator -{ - public: - FAutoSegIterator(REGINFO &head, REGINFO &tail) - { - // Weirdness. Mingw's linker puts these together backwards. - if (&head <= &tail) - { - Head = &head; - Tail = &tail; - } - else - { - Head = &tail; - Tail = &head; - } - Probe = Head; - } - NCREGINFO operator*() const NO_SANITIZE - { - return *Probe; - } - FAutoSegIterator &operator++() NO_SANITIZE - { - do - { - ++Probe; - } while (*Probe == 0 && Probe < Tail); - return *this; - } - void Reset() - { - Probe = Head; - } - - protected: - REGINFO *Probe; - REGINFO *Head; - REGINFO *Tail; -}; - -#endif diff --git a/src/bbannouncer.cpp b/src/bbannouncer.cpp index a54ccd88f18..07bc2305e7c 100644 --- a/src/bbannouncer.cpp +++ b/src/bbannouncer.cpp @@ -82,52 +82,52 @@ static const char *BeginSounds[] = static const SoundAndString WorldKillSounds[] = { - { "BBA_EXCREMENT", "VO7.SFX" }, // Excrement - { "BBA_HAMBURGER", "VO8.SFX" }, // Hamburger - { "BBA_SCROTUM", "VO9.SFX" }, // Scrotum separation + { "TXT_SELFOBIT1", "VO7.SFX" }, // Excrement + { "TXT_SELFOBIT2", "VO8.SFX" }, // Hamburger + { "TXT_SELFOBIT3", "VO9.SFX" }, // Scrotum separation }; static const SoundAndString SuicideSounds[] = { - { "BBA_SUICIDE", "VO13.SFX" }, // Unassisted death - { "BBA_SUICIDE", "VO5.SFX" }, // Kevorkian approves - { "BBA_POPULATION", "VO12.SFX" }, // Population control - { "BBA_DARWIN", "VO16.SFX" } // Darwin award + { "TXT_SELFOBIT5", "VO13.SFX" }, // Unassisted death + { "TXT_SELFOBIT5", "VO5.SFX" }, // Kevorkian approves + { "TXT_SELFOBIT4", "VO12.SFX" }, // Population control + { "TXT_SELFOBIT6", "VO16.SFX" } // Darwin award }; static const SoundAndString KillSounds[] = { - { "BBA_BONED", "BONED.SFX" }, // Boned - { "BBA_CREAMED", "CREAMED.SFX" }, // Creamed - { "BBA_DECIMAT", "DECIMAT.SFX" }, // Decimated - { "BBA_DESTRO", "DESTRO.SFX" }, // Destroyed - { "BBA_DICED", "DICED.SFX" }, // Diced - { "BBA_DISEMBO", "DISEMBO.SFX" }, // Disembowled - { "BBA_FLATTE", "FLATTE.SFX" }, // Flattened - { "BBA_JUSTICE", "JUSTICE.SFX" }, // Justice - { "BBA_MADNESS", "MADNESS.SFX" }, // Madness - { "BBA_KILLED", "KILLED.SFX" }, // Killed - { "BBA_MINCMEAT", "MINCMEAT.SFX" }, // Mincemeat - { "BBA_MASSACR", "MASSACR.SFX" }, // Massacred - { "BBA_MUTILA", "MUTILA.SFX" }, // Mutilated - { "BBA_REAMED", "REAMED.SFX" }, // Reamed - { "BBA_RIPPED", "RIPPED.SFX" }, // Ripped - { "BBA_SLAUGHT", "SLAUGHT.SFX" }, // Slaughtered - { "BBA_SMASHED", "SMASHED.SFX" }, // Smashed - { "BBA_SODOMIZ", "SODOMIZ.SFX" }, // Sodomized - { "BBA_SPLATT", "SPLATT.SFX" }, // Splattered - { "BBA_SQUASH", "SQUASH.SFX" }, // Squashed - { "BBA_THROTTL", "THROTTL.SFX" }, // Throttled - { "BBA_WASTED", "WASTED.SFX" }, // Wasted - { "BBA_BODYBAG", "VO10.SFX" }, // Body bagged - { "BBA_HOSED", "VO25.SFX" }, // Hosed - { "BBA_TOAST", "VO27.SFX" }, // Toasted - { "BBA_HELL", "VO28.SFX" }, // Sent to hell - { "BBA_SPRAYED", "VO35.SFX" }, // Sprayed - { "BBA_DOGMEAT", "VO36.SFX" }, // Dog meat - { "BBA_BEATEN", "VO39.SFX" }, // Beaten like a cur - { "BBA_SNUFF", "VO41.SFX" }, // Snuffed - { "BBA_CASTRA", "CASTRA.SFX" }, // Castrated + { "TXT_OBITUARY1", "BONED.SFX" }, // Boned + { "TXT_OBITUARY3", "CREAMED.SFX" }, // Creamed + { "TXT_OBITUARY4", "DECIMAT.SFX" }, // Decimated + { "TXT_OBITUARY5", "DESTRO.SFX" }, // Destroyed + { "TXT_OBITUARY6", "DICED.SFX" }, // Diced + { "TXT_OBITUARY7", "DISEMBO.SFX" }, // Disembowled + { "TXT_OBITUARY8", "FLATTE.SFX" }, // Flattened + { "TXT_OBITUARY9", "JUSTICE.SFX" }, // Justice + { "TXT_OBITUARY10", "MADNESS.SFX" }, // Madness + { "TXT_OBITUARY11", "KILLED.SFX" }, // Killed + { "TXT_OBITUARY12", "MINCMEAT.SFX" }, // Mincemeat + { "TXT_OBITUARY13", "MASSACR.SFX" }, // Massacred + { "TXT_OBITUARY14", "MUTILA.SFX" }, // Mutilated + { "TXT_OBITUARY15", "REAMED.SFX" }, // Reamed + { "TXT_OBITUARY16", "RIPPED.SFX" }, // Ripped + { "TXT_OBITUARY17", "SLAUGHT.SFX" }, // Slaughtered + { "TXT_OBITUARY18", "SMASHED.SFX" }, // Smashed + { "TXT_OBITUARY19", "SODOMIZ.SFX" }, // Sodomized + { "TXT_OBITUARY20", "SPLATT.SFX" }, // Splattered + { "TXT_OBITUARY21", "SQUASH.SFX" }, // Squashed + { "TXT_OBITUARY22", "THROTTL.SFX" }, // Throttled + { "TXT_OBITUARY23", "WASTED.SFX" }, // Wasted + { "TXT_OBITUARY24", "VO10.SFX" }, // Body bagged + { "TXT_OBITUARY28", "VO25.SFX" }, // Hosed + { "TXT_OBITUARY26", "VO27.SFX" }, // Toasted + { "TXT_OBITUARY25", "VO28.SFX" }, // Sent to hell + { "TXT_OBITUARY29", "VO35.SFX" }, // Sprayed + { "TXT_OBITUARY30", "VO36.SFX" }, // Dog meat + { "TXT_OBITUARY31", "VO39.SFX" }, // Beaten like a cur + { "TXT_OBITUARY27", "VO41.SFX" }, // Snuffed + { "TXT_OBITUARY2", "CASTRA.SFX" }, // Castrated }; static const char *GoodJobSounds[] = @@ -261,7 +261,7 @@ bool AnnounceKill (AActor *killer, AActor *killee) playSound |= killer->CheckLocalView(); } - message = GStrings(choice->Message); + message = GStrings.GetString(choice->Message); if (message != NULL) { char assembled[1024]; @@ -293,7 +293,7 @@ bool AnnounceTelefrag (AActor *killer, AActor *killee) if (cl_bbannounce && multiplayer) { - const char *message = GStrings("OB_MPTELEFRAG"); + const char *message = GStrings.GetString("OB_MPTELEFRAG"); if (message != NULL) { char assembled[1024]; diff --git a/src/common/2d/v_2ddrawer.cpp b/src/common/2d/v_2ddrawer.cpp new file mode 100644 index 00000000000..717d607c67c --- /dev/null +++ b/src/common/2d/v_2ddrawer.cpp @@ -0,0 +1,1273 @@ +/* +** v_2ddrawer.h +** Device independent 2D draw list +** +**--------------------------------------------------------------------------- +** Copyright 2016-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include + +#include "v_2ddrawer.h" +#include "vectors.h" +#include "vm.h" +#include "c_cvars.h" +#include "v_draw.h" +#include "v_video.h" +#include "fcolormap.h" +#include "texturemanager.h" + +static F2DDrawer drawer = F2DDrawer(); +F2DDrawer* twod = &drawer; + +EXTERN_CVAR(Float, transsouls) +CVAR(Float, classic_scaling_factor, 1.0, CVAR_ARCHIVE) +CVAR(Float, classic_scaling_pixelaspect, 1.2f, CVAR_ARCHIVE) + +IMPLEMENT_CLASS(FCanvas, false, false) + +IMPLEMENT_CLASS(DShape2DTransform, false, false) + +static void Shape2DTransform_Clear(DShape2DTransform* self) +{ + self->transform.Identity(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Clear, Shape2DTransform_Clear) +{ + PARAM_SELF_PROLOGUE(DShape2DTransform); + Shape2DTransform_Clear(self); + return 0; +} + +static void Shape2DTransform_Rotate(DShape2DTransform* self, double angle) +{ + self->transform = DMatrix3x3::Rotate2D(angle) * self->transform; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Rotate, Shape2DTransform_Rotate) +{ + PARAM_SELF_PROLOGUE(DShape2DTransform); + PARAM_FLOAT(angle); + Shape2DTransform_Rotate(self, angle); + return 0; +} + +static void Shape2DTransform_Scale(DShape2DTransform* self, double x, double y) +{ + self->transform = DMatrix3x3::Scale2D(DVector2(x, y)) * self->transform; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Scale, Shape2DTransform_Scale) +{ + PARAM_SELF_PROLOGUE(DShape2DTransform); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + Shape2DTransform_Scale(self, x, y); + return 0; +} + +static void Shape2DTransform_Translate(DShape2DTransform* self, double x, double y) +{ + self->transform = DMatrix3x3::Translate2D(DVector2(x, y)) * self->transform; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Translate, Shape2DTransform_Translate) +{ + PARAM_SELF_PROLOGUE(DShape2DTransform); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + Shape2DTransform_Translate(self, x, y); + return 0; +} + +static void Shape2DTransform_From2D( + DShape2DTransform* self, + double m00, double m01, double m10, double m11, double vx, double vy +) +{ + self->transform.Cells[0][0] = m00; + self->transform.Cells[0][1] = m01; + self->transform.Cells[1][0] = m10; + self->transform.Cells[1][1] = m11; + + self->transform.Cells[0][2] = vx; + self->transform.Cells[1][2] = vy; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, From2D, Shape2DTransform_From2D) +{ + PARAM_SELF_PROLOGUE(DShape2DTransform); + PARAM_FLOAT(m00); + PARAM_FLOAT(m01); + PARAM_FLOAT(m10); + PARAM_FLOAT(m11); + PARAM_FLOAT(vx); + PARAM_FLOAT(vy); + Shape2DTransform_From2D(self, m00, m01, m10, m11, vx, vy); + return 0; +} + +IMPLEMENT_CLASS(DShape2D, false, false) + +static void Shape2D_SetTransform(DShape2D* self, DShape2DTransform *transform) +{ + self->transform = PARAM_NULLCHECK(transform, transform)->transform; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, SetTransform, Shape2D_SetTransform) +{ + PARAM_SELF_PROLOGUE(DShape2D); + PARAM_OBJECT_NOT_NULL(transform, DShape2DTransform); + Shape2D_SetTransform(self, transform); + return 0; +} + +static void Shape2D_Clear(DShape2D* self, int which) +{ + if (which & C_Verts) self->mVertices.Clear(); + if (which & C_Coords) self->mCoords.Clear(); + if (which & C_Indices) self->mIndices.Clear(); + self->bufferInfo->needsVertexUpload = true; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear) +{ + PARAM_SELF_PROLOGUE(DShape2D); + PARAM_INT(which); + Shape2D_Clear(self, which); + return 0; +} + +static void Shape2D_PushVertex(DShape2D* self, double x, double y) +{ + self->mVertices.Push(DVector2(x, y)); + self->bufferInfo->needsVertexUpload = true; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex) +{ + PARAM_SELF_PROLOGUE(DShape2D); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + Shape2D_PushVertex(self, x, y); + return 0; +} + +static void Shape2D_PushCoord(DShape2D* self, double u, double v) +{ + self->mCoords.Push(DVector2(u, v)); + self->bufferInfo->needsVertexUpload = true; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushCoord, Shape2D_PushCoord) +{ + PARAM_SELF_PROLOGUE(DShape2D); + PARAM_FLOAT(u); + PARAM_FLOAT(v); + Shape2D_PushCoord(self, u, v); + return 0; +} + +static void Shape2D_PushTriangle(DShape2D* self, int a, int b, int c) +{ + self->mIndices.Push(a); + self->mIndices.Push(b); + self->mIndices.Push(c); + self->bufferInfo->needsVertexUpload = true; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle) +{ + PARAM_SELF_PROLOGUE(DShape2D); + PARAM_INT(a); + PARAM_INT(b); + PARAM_INT(c); + Shape2D_PushTriangle(self, a, b, c); + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +int F2DDrawer::AddCommand(RenderCommand *data) +{ + data->mScreenFade = screenFade; + if (mData.Size() > 0 && data->isCompatible(mData.Last())) + { + // Merge with the last command. + mData.Last().mIndexCount += data->mIndexCount; + mData.Last().mVertCount += data->mVertCount; + return mData.Size(); + } + else + { + return mData.Push(*data); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddIndices(int firstvert, int count, ...) +{ + va_list ap; + va_start(ap, count); + int addr = mIndices.Reserve(count); + for (int i = 0; i < count; i++) + { + mIndices[addr + i] = firstvert + va_arg(ap, int); + } +} + +void F2DDrawer::AddIndices(int firstvert, TArray &v) +{ + int addr = mIndices.Reserve(v.Size()); + for (unsigned i = 0; i < v.Size(); i++) + { + mIndices[addr + i] = firstvert + v[i]; + } +} + +//========================================================================== +// +// SetStyle +// +// Patterned after R_SetPatchStyle. +// +//========================================================================== + +bool F2DDrawer::SetStyle(FGameTexture *tex, DrawParms &parms, PalEntry &vertexcolor, RenderCommand &quad) +{ + FRenderStyle style = parms.style; + float alpha; + bool stencilling; + + if (style.Flags & STYLEF_TransSoulsAlpha) + { + alpha = transsouls; + } + else if (style.Flags & STYLEF_Alpha1) + { + alpha = 1; + } + else + { + alpha = clamp(parms.Alpha, 0.f, 1.f); + } + + style.CheckFuzz(); + if (style.BlendOp == STYLEOP_Shadow || style.BlendOp == STYLEOP_Fuzz) + { + style = LegacyRenderStyles[STYLE_TranslucentStencil]; + alpha = 0.3f; + parms.fillcolor = 0; + } + else if (style.BlendOp == STYLEOP_FuzzOrAdd) + { + style.BlendOp = STYLEOP_Add; + } + else if (style.BlendOp == STYLEOP_FuzzOrSub) + { + style.BlendOp = STYLEOP_Sub; + } + else if (style.BlendOp == STYLEOP_FuzzOrRevSub) + { + style.BlendOp = STYLEOP_RevSub; + } + + stencilling = false; + + if (style.Flags & STYLEF_InvertOverlay) + { + // Only the overlay color is inverted, not the overlay alpha. + parms.colorOverlay.r = 255 - parms.colorOverlay.r; + parms.colorOverlay.g = 255 - parms.colorOverlay.g; + parms.colorOverlay.b = 255 - parms.colorOverlay.b; + } + + SetColorOverlay(parms.colorOverlay, alpha, vertexcolor, quad.mColor1); + + if (style.Flags & STYLEF_ColorIsFixed) + { + if (style.Flags & STYLEF_InvertSource) + { // Since the source color is a constant, we can invert it now + // without spending time doing it in the shader. + parms.fillcolor.r = 255 - parms.fillcolor.r; + parms.fillcolor.g = 255 - parms.fillcolor.g; + parms.fillcolor.b = 255 - parms.fillcolor.b; + style.Flags &= ~STYLEF_InvertSource; + } + if (parms.desaturate > 0) + { + // Desaturation can also be computed here without having to do it in the shader. + auto gray = parms.fillcolor.Luminance(); + auto notgray = 255 - gray; + parms.fillcolor.r = uint8_t((parms.fillcolor.r * notgray + gray * 255) / 255); + parms.fillcolor.g = uint8_t((parms.fillcolor.g * notgray + gray * 255) / 255); + parms.fillcolor.b = uint8_t((parms.fillcolor.b * notgray + gray * 255) / 255); + parms.desaturate = 0; + } + + // Set up the color mod to replace the color from the image data. + vertexcolor.r = parms.fillcolor.r; + vertexcolor.g = parms.fillcolor.g; + vertexcolor.b = parms.fillcolor.b; + + if (style.Flags & STYLEF_RedIsAlpha) + { + quad.mDrawMode = TM_ALPHATEXTURE; + } + else + { + quad.mDrawMode = TM_STENCIL; + } + } + else + { + if (style.Flags & STYLEF_RedIsAlpha) + { + quad.mDrawMode = TM_ALPHATEXTURE; + } + else if (style.Flags & STYLEF_InvertSource) + { + quad.mDrawMode = TM_INVERSE; + } + + if (parms.specialcolormap != nullptr) + { // draw with an invulnerability or similar colormap. + + auto scm = parms.specialcolormap; + + quad.mSpecialColormap[0] = PalEntry(255, int(scm->ColorizeStart[0] * 127.5f), int(scm->ColorizeStart[1] * 127.5f), int(scm->ColorizeStart[2] * 127.5f)); + quad.mSpecialColormap[1] = PalEntry(255, int(scm->ColorizeEnd[0] * 127.5f), int(scm->ColorizeEnd[1] * 127.5f), int(scm->ColorizeEnd[2] * 127.5f)); + quad.mColor1 = 0; // this disables the color overlay. + } + quad.mDesaturate = parms.desaturate; + } + // apply the element's own color. This is being blended with anything that came before. + vertexcolor = PalEntry((vertexcolor.a * parms.color.a) / 255, (vertexcolor.r * parms.color.r) / 255, (vertexcolor.g * parms.color.g) / 255, (vertexcolor.b * parms.color.b) / 255); + + if (!parms.masked) + { + // For TM_ALPHATEXTURE and TM_STENCIL the mask cannot be turned off because it would not yield a usable result. + if (quad.mDrawMode == TM_NORMAL) quad.mDrawMode = TM_OPAQUE; + else if (quad.mDrawMode == TM_INVERSE) quad.mDrawMode = TM_INVERTOPAQUE; + } + quad.mRenderStyle = parms.style; // this contains the blend mode and blend equation settings. + if (parms.burn) quad.mFlags |= DTF_Burn; + return true; +} + +//========================================================================== +// +// Draws a texture +// +//========================================================================== + +void F2DDrawer::SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor) +{ + if (color.a != 0 && (color & 0xffffff) != 0) + { + // overlay color uses premultiplied alpha. + int a = color.a * 256 / 255; + overlaycolor.r = (color.r * a) >> 8; + overlaycolor.g = (color.g * a) >> 8; + overlaycolor.b = (color.b * a) >> 8; + overlaycolor.a = 0; // The overlay gets added on top of the texture data so to preserve the pixel's alpha this must be 0. + } + else + { + overlaycolor = 0; + } + // Vertex intensity is the inverse of the overlay so that the shader can do a simple addition to combine them. + uint8_t light = 255 - color.a; + vertexcolor = PalEntry(int(alpha * 255), light, light, light); + + // The real color gets multiplied into vertexcolor later. +} + +//========================================================================== +// +// Draws a texture +// +//========================================================================== + +void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms) +{ + if (parms.style.BlendOp == STYLEOP_None) return; // not supposed to be drawn. + assert(img && img->isValid()); + + double xscale = parms.destwidth / parms.texwidth; + double yscale = parms.destheight / parms.texheight; + double u1, v1, u2, v2; + PalEntry vertexcolor; + + RenderCommand dg; + + dg.mType = DrawTypeTriangles; + dg.mVertCount = 4; + dg.mTexture = img; + if (img->isWarped()) dg.mFlags |= DTF_Wrap; + if (parms.indexed) dg.mFlags |= DTF_Indexed; + + dg.mTranslationId = NO_TRANSLATION; + SetStyle(img, parms, vertexcolor, dg); + if (parms.indexed) + { + dg.mLightLevel = vertexcolor.Luminance(); + vertexcolor = 0xffffffff; + } + + if (!img->isHardwareCanvas() && parms.TranslationId != INVALID_TRANSLATION) + { + dg.mTranslationId = parms.TranslationId; + } + u1 = parms.srcx; + v1 = parms.srcy; + u2 = parms.srcx + parms.srcwidth; + v2 = parms.srcy + parms.srcheight; + + if (parms.flipX) + { + std::swap(u1, u2); + } + + if (parms.flipY) + { + std::swap(v1, v2); + } + + auto osave = offset; + if (parms.nooffset) offset = { 0,0 }; + + if (parms.rotateangle == 0) + { + double x = parms.x - parms.left * xscale; + double y = parms.y - parms.top * yscale; + double w = parms.destwidth; + double h = parms.destheight; + + + // This is crap. Only kept for backwards compatibility with scripts that may have used it. + // Note that this only works for unflipped and unrotated full textures. + if (parms.windowleft > 0 || parms.windowright < parms.texwidth) + { + double wi = min(parms.windowright, parms.texwidth); + x += parms.windowleft * xscale; + w -= (parms.texwidth - wi + parms.windowleft) * xscale; + + u1 = float(u1 + parms.windowleft / parms.texwidth); + u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); + } + auto t = this->transform; + auto tCorners = { + (t * DVector3(x, y, 1.0)).XY(), + (t * DVector3(x, y + h, 1.0)).XY(), + (t * DVector3(x + w, y, 1.0)).XY(), + (t * DVector3(x + w, y + h, 1.0)).XY() + }; + double minx = std::min_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.X < d1.X; })->X; + double maxx = std::max_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.X < d1.X; })->X; + double miny = std::min_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.Y < d1.Y; })->Y; + double maxy = std::max_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.Y < d1.Y; })->Y; + + if (minx < (double)parms.lclip || miny < (double)parms.uclip || maxx >(double)parms.rclip || maxy >(double)parms.dclip) + { + dg.mScissor[0] = parms.lclip + int(offset.X); + dg.mScissor[1] = parms.uclip + int(offset.Y); + dg.mScissor[2] = parms.rclip + int(offset.X); + dg.mScissor[3] = parms.dclip + int(offset.Y); + dg.mFlags |= DTF_Scissor; + } + else + { + memset(dg.mScissor, 0, sizeof(dg.mScissor)); + } + + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + TwoDVertex* ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x, y, 0, u1, v1, vertexcolor); ptr++; + ptr->Set(x, y + h, 0, u1, v2, vertexcolor); ptr++; + ptr->Set(x + w, y, 0, u2, v1, vertexcolor); ptr++; + ptr->Set(x + w, y + h, 0, u2, v2, vertexcolor); ptr++; + } + else + { + double radang = parms.rotateangle * (pi::pi() / 180.); + double cosang = cos(radang); + double sinang = sin(radang); + double xd1 = -parms.left; + double yd1 = -parms.top; + double xd2 = xd1 + parms.texwidth; + double yd2 = yd1 + parms.texheight; + + double x1 = parms.x + xscale * (xd1 * cosang + yd1 * sinang); + double y1 = parms.y - yscale * (xd1 * sinang - yd1 * cosang); + + double x2 = parms.x + xscale * (xd1 * cosang + yd2 * sinang); + double y2 = parms.y - yscale * (xd1 * sinang - yd2 * cosang); + + double x3 = parms.x + xscale * (xd2 * cosang + yd1 * sinang); + double y3 = parms.y - yscale * (xd2 * sinang - yd1 * cosang); + + double x4 = parms.x + xscale * (xd2 * cosang + yd2 * sinang); + double y4 = parms.y - yscale * (xd2 * sinang - yd2 * cosang); + + dg.mScissor[0] = parms.lclip + int(offset.X); + dg.mScissor[1] = parms.uclip + int(offset.Y); + dg.mScissor[2] = parms.rclip + int(offset.X); + dg.mScissor[3] = parms.dclip + int(offset.Y); + dg.mFlags |= DTF_Scissor; + + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + TwoDVertex* ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x1, y1, 0, u1, v1, vertexcolor); ptr++; + ptr->Set(x2, y2, 0, u1, v2, vertexcolor); ptr++; + ptr->Set(x3, y3, 0, u2, v1, vertexcolor); ptr++; + ptr->Set(x4, y4, 0, u2, v2, vertexcolor); ptr++; + + } + dg.useTransform = true; + dg.transform = this->transform; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + dg.mIndexIndex = mIndices.Size(); + dg.mIndexCount += 6; + AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); + AddCommand(&dg); + offset = osave; +} + +static TArray> buffersToDestroy; + +void DShape2D::OnDestroy() { + if (lastParms) delete lastParms; + lastParms = nullptr; + mIndices.Reset(); + mVertices.Reset(); + mCoords.Reset(); + buffersToDestroy.Push(std::move(bufferInfo)); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms) +{ + // [MK] bail out if vertex/coord array sizes are mismatched + if ( shape->mVertices.Size() != shape->mCoords.Size() ) + ThrowAbortException(X_OTHER, "Mismatch in vertex/coord count: %u != %u", shape->mVertices.Size(), shape->mCoords.Size()); + + if (parms.style.BlendOp == STYLEOP_None) return; // not supposed to be drawn. + + PalEntry vertexcolor; + + RenderCommand dg; + + dg.mType = DrawTypeTriangles; + dg.mVertCount = shape->mVertices.Size(); + dg.mFlags |= DTF_Wrap; + dg.mTexture = img; + + dg.mTranslationId = NO_TRANSLATION; + SetStyle(img, parms, vertexcolor, dg); + + if (shape->lastParms == nullptr) { + shape->lastParms = new DrawParms(parms); + } + else if (shape->lastParms->vertexColorChange(parms)) { + shape->bufferInfo->needsVertexUpload = true; + if (!shape->bufferInfo->uploadedOnce) { + shape->bufferInfo->bufIndex = -1; + shape->bufferInfo->buffers.Clear(); + shape->bufferInfo->lastCommand = -1; + } + delete shape->lastParms; + shape->lastParms = new DrawParms(parms); + } + + if (!(img != nullptr && img->isHardwareCanvas()) && parms.TranslationId != INVALID_TRANSLATION) + dg.mTranslationId = parms.TranslationId; + + auto osave = offset; + if (parms.nooffset) offset = { 0,0 }; + + if (shape->bufferInfo->needsVertexUpload) + { + shape->minx = 16383; + shape->miny = 16383; + shape->maxx = -16384; + shape->maxy = -16384; + for ( int i=0; imVertices[i].X < shape->minx ) shape->minx = shape->mVertices[i].X; + if ( shape->mVertices[i].Y < shape->miny ) shape->miny = shape->mVertices[i].Y; + if ( shape->mVertices[i].X > shape->maxx ) shape->maxx = shape->mVertices[i].X; + if ( shape->mVertices[i].Y > shape->maxy ) shape->maxy = shape->mVertices[i].Y; + } + } + auto t = this->transform * shape->transform; + auto tCorners = { + (t * DVector3(shape->minx, shape->miny, 1.0)).XY(), + (t * DVector3(shape->minx, shape->maxy, 1.0)).XY(), + (t * DVector3(shape->maxx, shape->miny, 1.0)).XY(), + (t * DVector3(shape->maxx, shape->maxy, 1.0)).XY() + }; + double minx = std::min_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.X < d1.X; })->X; + double maxx = std::max_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.X < d1.X; })->X; + double miny = std::min_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.Y < d1.Y; })->Y; + double maxy = std::max_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.Y < d1.Y; })->Y; + if (minx < (double)parms.lclip || miny < (double)parms.uclip || maxx >(double)parms.rclip || maxy >(double)parms.dclip) + { + dg.mScissor[0] = parms.lclip + int(offset.X); + dg.mScissor[1] = parms.uclip + int(offset.Y); + dg.mScissor[2] = parms.rclip + int(offset.X); + dg.mScissor[3] = parms.dclip + int(offset.Y); + dg.mFlags |= DTF_Scissor; + } + else + memset(dg.mScissor, 0, sizeof(dg.mScissor)); + + dg.useTransform = true; + dg.transform = t; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + dg.shape2DBufInfo = shape->bufferInfo; + dg.shape2DIndexCount = shape->mIndices.Size(); + if (shape->bufferInfo->needsVertexUpload) + { + shape->bufferInfo->bufIndex += 1; + + shape->bufferInfo->buffers.Reserve(1); + + auto buf = &shape->bufferInfo->buffers[shape->bufferInfo->bufIndex]; + + auto verts = TArray(dg.mVertCount, true); + for ( int i=0; imVertices[i].X, shape->mVertices[i].Y, 0, shape->mCoords[i].X, shape->mCoords[i].Y, vertexcolor); + + for ( int i=0; imIndices.Size()); i+=3 ) + { + // [MK] bail out if any indices are out of bounds + for ( int j=0; j<3; j++ ) + { + if ( shape->mIndices[i+j] < 0 ) + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Triangle %u index %u is negative: %i\n", i/3, j, shape->mIndices[i+j]); + if ( shape->mIndices[i+j] >= dg.mVertCount ) + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Triangle %u index %u: %u, max: %u\n", i/3, j, shape->mIndices[i+j], dg.mVertCount-1); + } + } + + buf->UploadData(&verts[0], dg.mVertCount, &shape->mIndices[0], shape->mIndices.Size()); + shape->bufferInfo->needsVertexUpload = false; + shape->bufferInfo->uploadedOnce = true; + } + dg.shape2DBufIndex = shape->bufferInfo->bufIndex; + shape->bufferInfo->lastCommand += 1; + dg.shape2DCommandCounter = shape->bufferInfo->lastCommand; + AddCommand(&dg); + offset = osave; +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddPoly(FGameTexture *texture, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, + DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double fadelevel, + uint32_t *indices, size_t indexcount) +{ + RenderCommand poly; + + poly.mType = DrawTypeTriangles; + poly.mTexture = texture; + poly.mRenderStyle = DefaultRenderStyle(); + poly.mFlags |= DTF_Wrap; + poly.mDesaturate = colormap.Desaturation; + + PalEntry color0; + double invfade = 1. - fadelevel; + + color0.r = uint8_t(colormap.LightColor.r * invfade); + color0.g = uint8_t(colormap.LightColor.g * invfade); + color0.b = uint8_t(colormap.LightColor.b * invfade); + color0.a = 255; + + poly.mColor1.a = 0; + poly.mColor1.r = uint8_t(colormap.FadeColor.r * fadelevel); + poly.mColor1.g = uint8_t(colormap.FadeColor.g * fadelevel); + poly.mColor1.b = uint8_t(colormap.FadeColor.b * fadelevel); + + bool dorotate = rotation != nullAngle; + + float cosrot = (float)cos(rotation.Radians()); + float sinrot = (float)sin(rotation.Radians()); + + float uscale = float(1.f / (texture->GetDisplayWidth() * scalex)); + float vscale = float(1.f / (texture->GetDisplayHeight() * scaley)); + float ox = float(originx); + float oy = float(originy); + + poly.mVertCount = npoints; + poly.mVertIndex = (int)mVertices.Reserve(npoints); + for (int i = 0; i < npoints; ++i) + { + float u = points[i].X - 0.5f - ox; + float v = points[i].Y - 0.5f - oy; + if (dorotate) + { + float t = u; + u = t * cosrot - v * sinrot; + v = v * cosrot + t * sinrot; + } + mVertices[poly.mVertIndex+i].Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale, color0); + } + poly.mIndexIndex = mIndices.Size(); + + if (indices == nullptr || indexcount == 0) + { + poly.mIndexCount += (npoints - 2) * 3; + for (int i = 2; i < npoints; ++i) + { + AddIndices(poly.mVertIndex, 3, 0, i - 1, i); + } + } + else + { + poly.mIndexCount += (int)indexcount; + int addr = mIndices.Reserve(indexcount); + for (size_t i = 0; i < indexcount; i++) + { + mIndices[addr + i] = poly.mVertIndex + indices[i]; + } + } + poly.useTransform = true; + poly.transform = this->transform; + poly.transform.Cells[0][2] += offset.X; + poly.transform.Cells[1][2] += offset.Y; + + AddCommand(&poly); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, const unsigned int* ind, size_t idxcount, FTranslationID translation, PalEntry color, FRenderStyle style, const IntRect* clip) +{ + RenderCommand dg; + + if (!img || !img->isValid()) return; + + dg.mType = DrawTypeTriangles; + if (clip != nullptr) + { + dg.mScissor[0] = clip->Left() + int(offset.X); + dg.mScissor[1] = clip->Top() + int(offset.Y); + dg.mScissor[2] = clip->Right() + int(offset.X); + dg.mScissor[3] = clip->Bottom() + int(offset.Y); + dg.mFlags |= DTF_Scissor; + } + + dg.mTexture = img; + dg.mTranslationId = translation; + dg.mVertCount = (int)vtcount; + dg.mVertIndex = (int)mVertices.Reserve(vtcount); + dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent]; + dg.mIndexIndex = mIndices.Size(); + dg.mFlags |= DTF_Wrap; + auto ptr = &mVertices[dg.mVertIndex]; + + for (size_t i=0;iSet(vt[i].X, vt[i].Y, 0.f, vt[i].Z, vt[i].W, color); + ptr++; + } + dg.mIndexIndex = mIndices.Size(); + + if (idxcount > 0) + { + mIndices.Reserve(idxcount); + for (size_t i = 0; i < idxcount; i++) + { + mIndices[dg.mIndexIndex + i] = ind[i] + dg.mVertIndex; + } + dg.mIndexCount = (int)idxcount; + } + else + { + // If we have no index buffer, treat this as an unindexed list of triangles. + mIndices.Reserve(vtcount); + for (size_t i = 0; i < vtcount; i++) + { + mIndices[dg.mIndexIndex + i] = int(i + dg.mVertIndex); + } + dg.mIndexCount = (int)vtcount; + + } + dg.useTransform = true; + dg.transform = this->transform; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + AddCommand(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +float F2DDrawer::GetClassicFlatScalarWidth() +{ + float ar = 4.f / 3.f / (float)ActiveRatio((float)screen->GetWidth(), (float)screen->GetHeight()); + float sw = 320.f * classic_scaling_factor / (float)screen->GetWidth() / ar; + return sw; +} + +float F2DDrawer::GetClassicFlatScalarHeight() +{ + float sh = 240.f / classic_scaling_pixelaspect * classic_scaling_factor / (float)screen->GetHeight(); + return sh; +} + +void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin, double flatscale, PalEntry color, ERenderStyle style) +{ + float fU1, fU2, fV1, fV2; + + RenderCommand dg; + + dg.mType = DrawTypeTriangles; + dg.mRenderStyle = LegacyRenderStyles[style]; + dg.mTexture = src; + dg.mVertCount = 4; + dg.mTexture = src; + dg.mFlags = DTF_Wrap; + + float fs = 1.f / float(flatscale); + + float sw = GetClassicFlatScalarWidth(); + float sh = GetClassicFlatScalarHeight(); + + switch (local_origin) + { + default: + case 0: + fU1 = float(left) / (float)src->GetDisplayWidth() * fs; + fV1 = float(top) / (float)src->GetDisplayHeight() * fs; + fU2 = float(right) / (float)src->GetDisplayWidth() * fs; + fV2 = float(bottom) / (float)src->GetDisplayHeight() * fs; + break; + + case 1: + fU1 = 0; + fV1 = 0; + fU2 = float(right - left) / (float)src->GetDisplayWidth() * fs; + fV2 = float(bottom - top) / (float)src->GetDisplayHeight() * fs; + break; + + // The following are for drawing frames with elements of pnly one orientation + case 2: // flip vertically + fU1 = 0; + fV2 = 0; + fU2 = float(right - left) / (float)src->GetDisplayWidth() * fs; + fV1 = float(bottom - top) / (float)src->GetDisplayHeight() * fs; + break; + + case 3: // flip horizontally + fU2 = 0; + fV1 = 0; + fU1 = float(right - left) / (float)src->GetDisplayWidth() * fs; + fV2 = float(bottom - top) / (float)src->GetDisplayHeight() * fs; + break; + + case 4: // flip vertically and horizontally + fU2 = 0; + fV2 = 0; + fU1 = float(right - left) / (float)src->GetDisplayWidth() * fs; + fV1 = float(bottom - top) / (float)src->GetDisplayHeight() * fs; + break; + + + case 5: // flip coordinates + fU1 = 0; + fV1 = 0; + fU2 = float(bottom - top) / (float)src->GetDisplayWidth() * fs; + fV2 = float(right - left) / (float)src->GetDisplayHeight() * fs; + break; + + case 6: // flip coordinates and vertically + fU2 = 0; + fV1 = 0; + fU1 = float(bottom - top) / (float)src->GetDisplayWidth() * fs; + fV2 = float(right - left) / (float)src->GetDisplayHeight() * fs; + break; + + case 7: // flip coordinates and horizontally + fU1 = 0; + fV2 = 0; + fU2 = float(bottom - top) / (float)src->GetDisplayWidth() * fs; + fV1 = float(right - left) / (float)src->GetDisplayHeight() * fs; + break; + + case -1: // classic flat scaling + fU1 = float(left) / (float)src->GetDisplayWidth() * fs * sw; + fV1 = float(top) / (float)src->GetDisplayHeight() * fs * sh; + fU2 = float(right) / (float)src->GetDisplayWidth() * fs * sw; + fV2 = float(bottom) / (float)src->GetDisplayHeight() * fs * sh; + break; + + case -2: // classic scaling for screen bevel + fU1 = 0; + fV1 = 0; + fU2 = float(right - left) / (float)src->GetDisplayWidth() * fs * sw; + fV2 = float(bottom - top) / (float)src->GetDisplayHeight() * fs * sh; + break; + } + dg.mVertIndex = (int)mVertices.Reserve(4); + auto ptr = &mVertices[dg.mVertIndex]; + + ptr->Set(left, top, 0, fU1, fV1, color); ptr++; + if (local_origin < 4) + { + ptr->Set(left, bottom, 0, fU1, fV2, color); ptr++; + ptr->Set(right, top, 0, fU2, fV1, color); ptr++; + } + else + { + ptr->Set(left, bottom, 0, fU2, fV1, color); ptr++; + ptr->Set(right, top, 0, fU1, fV2, color); ptr++; + } + ptr->Set(right, bottom, 0, fU2, fV2, color); ptr++; + dg.useTransform = true; + dg.transform = this->transform; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + dg.mIndexIndex = mIndices.Size(); + dg.mIndexCount += 6; + AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); + AddCommand(&dg); +} + + +//=========================================================================== +// +// +// +//=========================================================================== + +void F2DDrawer::AddColorOnlyQuad(int x1, int y1, int w, int h, PalEntry color, FRenderStyle *style, bool prepend) +{ + RenderCommand dg; + + dg.mType = DrawTypeTriangles; + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + dg.mRenderStyle = style? *style : LegacyRenderStyles[STYLE_Translucent]; + auto ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x1, y1, 0, 0, 0, color); ptr++; + ptr->Set(x1, y1 + h, 0, 0, 0, color); ptr++; + ptr->Set(x1 + w, y1, 0, 0, 0, color); ptr++; + ptr->Set(x1 + w, y1 + h, 0, 0, 0, color); ptr++; + dg.useTransform = true; + dg.transform = this->transform; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + dg.mIndexIndex = mIndices.Size(); + dg.mIndexCount += 6; + AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); + if (!prepend) AddCommand(&dg); + else + { + // Only needed by Raze's fullscreen blends because they are being calculated late when half of the 2D content has already been submitted, + // This ensures they are below the HUD, not above it. + dg.mScreenFade = screenFade; + mData.Insert(0, dg); + } +} + +void F2DDrawer::ClearScreen(PalEntry color) +{ + AddColorOnlyQuad(0, 0, GetWidth(), GetHeight(), color); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddLine(const DVector2& v1, const DVector2& v2, const IntRect* clip, uint32_t color, uint8_t alpha) +{ + PalEntry p = (PalEntry)color; + p.a = alpha; + + RenderCommand dg; + + if (clip != nullptr) + { + dg.mScissor[0] = clip->Left() + int(offset.X); + dg.mScissor[1] = clip->Top() + int(offset.Y); + dg.mScissor[2] = clip->Right() + int(offset.X); + dg.mScissor[3] = clip->Bottom() + int(offset.Y); + dg.mFlags |= DTF_Scissor; + } + + dg.mType = DrawTypeLines; + dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent]; + dg.mVertCount = 2; + dg.mVertIndex = (int)mVertices.Reserve(2); + dg.useTransform = true; + dg.transform = this->transform; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + mVertices[dg.mVertIndex].Set(v1.X, v1.Y, 0, 0, 0, p); + mVertices[dg.mVertIndex+1].Set(v2.X, v2.Y, 0, 0, 0, p); + AddCommand(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddThickLine(const DVector2& v1, const DVector2& v2, double thickness, uint32_t color, uint8_t alpha) +{ + PalEntry p = (PalEntry)color; + p.a = alpha; + + DVector2 delta = v2 - v1; + DVector2 perp = delta.Rotated90CCW(); + perp.MakeUnit(); + perp *= thickness / 2; + + DVector2 corner0 = v1 + perp; + DVector2 corner1 = v1 - perp; + DVector2 corner2 = v2 + perp; + DVector2 corner3 = v2 - perp; + + RenderCommand dg; + + dg.mType = DrawTypeTriangles; + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent]; + auto ptr = &mVertices[dg.mVertIndex]; + ptr->Set(corner0.X, corner0.Y, 0, 0, 0, p); ptr++; + ptr->Set(corner1.X, corner1.Y, 0, 0, 0, p); ptr++; + ptr->Set(corner2.X, corner2.Y, 0, 0, 0, p); ptr++; + ptr->Set(corner3.X, corner3.Y, 0, 0, 0, p); ptr++; + dg.useTransform = true; + dg.transform = this->transform; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + dg.mIndexIndex = mIndices.Size(); + dg.mIndexCount += 6; + AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); + AddCommand(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddPixel(int x1, int y1, uint32_t color) +{ + PalEntry p = (PalEntry)color; + p.a = 255; + + RenderCommand dg; + + dg.mType = DrawTypePoints; + dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent]; + dg.mVertCount = 1; + dg.mVertIndex = (int)mVertices.Reserve(1); + mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p); + dg.useTransform = true; + dg.transform = this->transform; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + AddCommand(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddEnableStencil(bool on) +{ + RenderCommand dg; + + dg.isSpecial = SpecialDrawCommand::EnableStencil; + dg.stencilOn = on; + + AddCommand(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddSetStencil(int offs, int op, int flags) +{ + RenderCommand dg; + + dg.isSpecial = SpecialDrawCommand::SetStencil; + dg.stencilOffs = offs; + dg.stencilOp = op; + dg.stencilFlags = flags; + + AddCommand(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddClearStencil() +{ + RenderCommand dg; + + dg.isSpecial = SpecialDrawCommand::ClearStencil; + + AddCommand(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::Clear() +{ + if (!locked) + { + mVertices.Clear(); + mIndices.Clear(); + mData.Clear(); + mIsFirstPass = true; + } + screenFade = 1.f; +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::OnFrameDone() +{ + buffersToDestroy.Clear(); +} + +F2DVertexBuffer::F2DVertexBuffer() +{ + mVertexBuffer = screen->CreateVertexBuffer(); + mIndexBuffer = screen->CreateIndexBuffer(); + + static const FVertexBufferAttribute format[] = { + { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(F2DDrawer::TwoDVertex, x) }, + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(F2DDrawer::TwoDVertex, u) }, + { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(F2DDrawer::TwoDVertex, color0) } + }; + mVertexBuffer->SetFormat(1, 3, sizeof(F2DDrawer::TwoDVertex), format); +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray AllCanvases; + +class InitTextureCanvasGC +{ +public: + InitTextureCanvasGC() + { + GC::AddMarkerFunc([]() { + for (auto canvas : AllCanvases) + GC::Mark(canvas); + }); + } +}; + +FCanvas* GetTextureCanvas(const FString& texturename) +{ + FTextureID textureid = TexMan.CheckForTexture(texturename.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + if (textureid.isValid()) + { + // Only proceed if the texture is a canvas texture. + auto tex = TexMan.GetGameTexture(textureid); + if (tex && tex->GetTexture()->isCanvas()) + { + FCanvasTexture* canvasTex = static_cast(tex->GetTexture()); + if (!canvasTex->Canvas) + { + static InitTextureCanvasGC initCanvasGC; // Does the common code have a natural init function this could be moved to? + + canvasTex->Canvas = Create(); + canvasTex->Canvas->Tex = canvasTex; + canvasTex->Canvas->Drawer.SetSize(tex->GetTexelWidth(), tex->GetTexelHeight()); + AllCanvases.Push(canvasTex->Canvas); + } + return canvasTex->Canvas; + } + } + return nullptr; +} diff --git a/src/common/2d/v_2ddrawer.h b/src/common/2d/v_2ddrawer.h new file mode 100644 index 00000000000..c2be564dc9a --- /dev/null +++ b/src/common/2d/v_2ddrawer.h @@ -0,0 +1,361 @@ +#ifndef __2DDRAWER_H +#define __2DDRAWER_H + +#include "buffers.h" +#include "tarray.h" +#include "vectors.h" +#include "textures.h" +#include "renderstyle.h" +#include "dobject.h" +#include "refcounted.h" + +struct DrawParms; +struct FColormap; +struct IntRect; + +class DShape2DTransform : public DObject +{ + +DECLARE_CLASS(DShape2DTransform, DObject) +public: + DShape2DTransform() + { + transform.Identity(); + } + DMatrix3x3 transform; +}; + +// intermediate struct for shape drawing + +enum EClearWhich +{ + C_Verts = 1, + C_Coords = 2, + C_Indices = 4, +}; + +class F2DVertexBuffer; + +struct F2DPolygons +{ + TArray vertices; + TArray indices; + + unsigned AllocVertices(int num) + { + auto vindex = vertices.Reserve(num); + indices.Push(num); + return vindex; + } + +}; + +class DShape2D; +struct DShape2DBufferInfo; + +enum class SpecialDrawCommand { + NotSpecial, + + EnableStencil, + SetStencil, + ClearStencil, +}; + +class F2DDrawer +{ +public: + F2DDrawer() { + this->transform.Identity(); + } + + enum EDrawType : uint8_t + { + DrawTypeTriangles, + DrawTypeLines, + DrawTypePoints, + DrawTypeRotateSprite, + }; + + enum ETextureFlags : uint8_t + { + DTF_Wrap = 1, + DTF_Scissor = 2, + DTF_Burn = 4, + DTF_Indexed = 8, + }; + + + // This vertex type is hardware independent and needs conversion when put into a buffer. + struct TwoDVertex + { + float x, y, z; + float u, v; + PalEntry color0; + + void Set(float xx, float yy, float zz) + { + x = xx; + z = zz; + y = yy; + u = 0; + v = 0; + color0 = 0; + } + + void Set(double xx, double yy, double zz, double uu, double vv, PalEntry col) + { + x = (float)xx; + z = (float)zz; + y = (float)yy; + u = (float)uu; + v = (float)vv; + color0 = col; + } + + }; + + struct RenderCommand + { + SpecialDrawCommand isSpecial; + + bool stencilOn; + + int stencilOffs; + int stencilOp; + int stencilFlags; + + EDrawType mType; + int mVertIndex; + int mVertCount; + int mIndexIndex; + int mIndexCount; + + FGameTexture *mTexture; + FTranslationID mTranslationId; + PalEntry mSpecialColormap[2]; + int mScissor[4]; + int mDesaturate; + FRenderStyle mRenderStyle; + PalEntry mColor1; // Overlay color + ETexMode mDrawMode; + uint8_t mLightLevel; + uint8_t mFlags; + float mScreenFade; + + bool useTransform; + DMatrix3x3 transform; + + RefCountedPtr shape2DBufInfo; + int shape2DBufIndex; + int shape2DIndexCount; + int shape2DCommandCounter; + + RenderCommand() + { + memset((void*)this, 0, sizeof(*this)); + } + + // If these fields match, two draw commands can be batched. + bool isCompatible(const RenderCommand &other) const + { + if ( + isSpecial != SpecialDrawCommand::NotSpecial || + other.isSpecial != SpecialDrawCommand::NotSpecial + ) return false; + if (shape2DBufInfo != nullptr || other.shape2DBufInfo != nullptr) return false; + return mTexture == other.mTexture && + mType == other.mType && + mTranslationId == other.mTranslationId && + mSpecialColormap[0].d == other.mSpecialColormap[0].d && + mSpecialColormap[1].d == other.mSpecialColormap[1].d && + !memcmp(mScissor, other.mScissor, sizeof(mScissor)) && + mDesaturate == other.mDesaturate && + mRenderStyle == other.mRenderStyle && + mDrawMode == other.mDrawMode && + mFlags == other.mFlags && + mLightLevel == other.mLightLevel && + mColor1.d == other.mColor1.d && + useTransform == other.useTransform && + mScreenFade == other.mScreenFade && + ( + !useTransform || + ( + transform[0] == other.transform[0] && + transform[1] == other.transform[1] && + transform[2] == other.transform[2] + ) + ); + } + }; + + TArray mIndices; + TArray mVertices; + TArray mData; + int Width, Height; + bool isIn2D = false; + bool locked = false; // prevents clearing of the data so it can be reused multiple times (useful for screen fades) + float screenFade = 1.f; + DVector2 offset; + DMatrix3x3 transform; +public: + int fullscreenautoaspect = 3; + int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1; + + int AddCommand(RenderCommand *data); + void AddIndices(int firstvert, int count, ...); +private: + void AddIndices(int firstvert, TArray &v); + bool SetStyle(FGameTexture *tex, DrawParms &parms, PalEntry &color0, RenderCommand &quad); + void SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor); + +public: + float GetClassicFlatScalarWidth(); + float GetClassicFlatScalarHeight(); + void AddTexture(FGameTexture* img, DrawParms& parms); + void AddShape(FGameTexture *img, DShape2D *shape, DrawParms &parms); + void AddPoly(FGameTexture *texture, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, + DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double lightlevel, uint32_t *indices, size_t indexcount); + void AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, const unsigned int *ind, size_t idxcount, FTranslationID translation, PalEntry color, FRenderStyle style, const IntRect* clip); + void FillPolygon(int* rx1, int* ry1, int* xb1, int32_t npoints, int pic, int palette, int shade, int props, const FVector2& xtex, const FVector2& ytex, const FVector2& otex, + int clipx1, int clipy1, int clipx2, int clipy2); + void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin = false, double flatscale = 1.0, PalEntry color = 0xffffffff, ERenderStyle rs = STYLE_Normal); + + void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style = nullptr, bool prepend = false); + void ClearScreen(PalEntry color = 0xff000000); + void AddDim(PalEntry color, float damount, int x1, int y1, int w, int h); + void AddClear(int left, int top, int right, int bottom, int palcolor, uint32_t color); + + + void AddLine(const DVector2& v1, const DVector2& v2, const IntRect* clip, uint32_t color, uint8_t alpha = 255); + void AddThickLine(const DVector2& v1, const DVector2& v2, double thickness, uint32_t color, uint8_t alpha = 255); + void AddPixel(int x1, int y1, uint32_t color); + + void AddEnableStencil(bool on); + void AddSetStencil(int offs, int op, int flags); + void AddClearStencil(); + + void Clear(); + void Lock() { locked = true; } + void SetScreenFade(float factor) { screenFade = factor; } + void Unlock() { locked = false; } + int GetWidth() const { return Width; } + int GetHeight() const { return Height; } + void SetSize(int w, int h) { Width = w; Height = h; } + void Begin(int w, int h) { isIn2D = true; Width = w; Height = h; } + void End() { isIn2D = false; } + bool HasBegun2D() { return isIn2D; } + void OnFrameDone(); + + void ClearClipRect() { clipleft = cliptop = 0; clipwidth = clipheight = -1; } + void SetClipRect(int x, int y, int w, int h); + void GetClipRect(int* x, int* y, int* w, int* h); + + DVector2 SetOffset(const DVector2& vec) + { + auto v = offset; + offset = vec; + return v; + } + + void SetTransform(const DShape2DTransform& transform) + { + this->transform = transform.transform; + } + void ClearTransform() + { + this->transform.Identity(); + } + + int DrawCount() const + { + return mData.Size(); + } + + bool mIsFirstPass = true; +}; + +// DCanvas is already taken so using FCanvas instead. +class FCanvas : public DObject +{ + DECLARE_CLASS(FCanvas, DObject) +public: + F2DDrawer Drawer; + FCanvasTexture* Tex = nullptr; +}; + +struct DShape2DBufferInfo : RefCountedBase +{ + TArray buffers; + bool needsVertexUpload = true; + int bufIndex = -1; + int lastCommand = -1; + bool uploadedOnce = false; +}; + +class DShape2D : public DObject +{ + + DECLARE_CLASS(DShape2D,DObject) +public: + DShape2D() + : bufferInfo(new DShape2DBufferInfo) + { + transform.Identity(); + } + + TArray mIndices; + TArray mVertices; + TArray mCoords; + + double minx = 0.0; + double maxx = 0.0; + double miny = 0.0; + double maxy = 0.0; + + DMatrix3x3 transform; + + RefCountedPtr bufferInfo; + + DrawParms* lastParms = nullptr; + + void OnDestroy() override; +}; + + +//=========================================================================== +// +// Vertex buffer for 2D drawer +// +//=========================================================================== + +class F2DVertexBuffer +{ + IVertexBuffer *mVertexBuffer; + IIndexBuffer *mIndexBuffer; + + +public: + + F2DVertexBuffer(); + + ~F2DVertexBuffer() + { + delete mIndexBuffer; + delete mVertexBuffer; + } + + void UploadData(F2DDrawer::TwoDVertex *vertices, int vertcount, int *indices, int indexcount) + { + mVertexBuffer->SetData(vertcount * sizeof(*vertices), vertices, BufferUsageType::Stream); + mIndexBuffer->SetData(indexcount * sizeof(unsigned int), indices, BufferUsageType::Stream); + } + + std::pair GetBufferObjects() const + { + return std::make_pair(mVertexBuffer, mIndexBuffer); + } +}; + + +#endif diff --git a/src/common/2d/v_draw.cpp b/src/common/2d/v_draw.cpp new file mode 100644 index 00000000000..247a2916dcc --- /dev/null +++ b/src/common/2d/v_draw.cpp @@ -0,0 +1,1985 @@ +/* +** v_draw.cpp +** Draw patches and blocks to a canvas +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include "v_draw.h" +#include "vm.h" + +#include "texturemanager.h" +#include "r_videoscale.h" +#include "c_cvars.h" + +EXTERN_CVAR(Int, vid_aspect) +EXTERN_CVAR(Int, uiscale) +CVAR(Bool, ui_screenborder_classic_scaling, true, CVAR_ARCHIVE) + +// vid_allowtrueultrawide - preserve the classic behavior of stretching screen elements to 16:9 when false +// Defaults to "true" now because "21:9" (actually actually 64:27) screens are becoming more common, it's +// nonsense that graphics should not be able to actually use that extra screen space. + +extern bool setsizeneeded; +CUSTOM_CVAR(Int, vid_allowtrueultrawide, 1, CVAR_ARCHIVE|CVAR_NOINITCALL) +{ + setsizeneeded = true; +} + +static void VirtualToRealCoords(F2DDrawer* drawer, double Width, double Height, double& x, double& y, double& w, double& h, + double vwidth, double vheight, bool vbottom, bool handleaspect); + +// Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none. +int ActiveFakeRatio(int width, int height) +{ + int fakeratio = -1; + if ((vid_aspect >= 1) && (vid_aspect <= 6)) + { + // [SP] User wants to force aspect ratio; let them. + fakeratio = int(vid_aspect); + if (fakeratio == 3) + { + fakeratio = 0; + } + else if (fakeratio == 5) + { + fakeratio = 3; + } + } + return fakeratio; +} + +// Active screen ratio based on cvars and size +float ActiveRatio(int width, int height, float* trueratio) +{ + static float forcedRatioTypes[] = + { + 4 / 3.0f, + 16 / 9.0f, + 16 / 10.0f, + 17 / 10.0f, + 5 / 4.0f, + 17 / 10.0f, + 64 / 27.0f // 21:9 is actually 64:27 in reality - pow(4/3, 3.0) - https://en.wikipedia.org/wiki/21:9_aspect_ratio + }; + + float ratio = width / (float)height; + int fakeratio = ActiveFakeRatio(width, height); + + if (trueratio) + *trueratio = ratio; + return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : (ratio / ViewportPixelAspect()); +} + + +bool AspectTallerThanWide(float aspect) +{ + return aspect < 1.333f; +} + +int AspectBaseWidth(float aspect) +{ + return (int)round(240.0f * aspect * 3.0f); +} + +int AspectBaseHeight(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return (int)round(200.0f * (320.0f / (AspectBaseWidth(aspect) / 3.0f)) * 3.0f); + else + return (int)round((200.0f * (4.0f / 3.0f)) / aspect * 3.0f); +} + +double AspectPspriteOffset(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return 0.0; + else + return ((4.0 / 3.0) / aspect - 1.0) * 97.5; +} + +int AspectMultiplier(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return (int)round(320.0f / (AspectBaseWidth(aspect) / 3.0f) * 48.0f); + else + return (int)round(200.0f / (AspectBaseHeight(aspect) / 3.0f) * 48.0f); +} + +int GetUIScale(F2DDrawer *drawer, int altval) +{ + int scaleval; + if (altval > 0) scaleval = altval; + else if (uiscale == 0) + { + // Default should try to scale to 640x400 + int vscale = drawer->GetHeight() / 400; + int hscale = drawer->GetWidth() / 640; + scaleval = max(1, min(vscale, hscale)); + } + else scaleval = uiscale; + + // block scales that result in something larger than the current screen. + int vmax = drawer->GetHeight() / 200; + int hmax = drawer->GetWidth() / 320; + int max = std::max(vmax, hmax); + return std::max(1,min(scaleval, max)); +} + +// The new console font is twice as high, so the scaling calculation must factor that in. +int GetConScale(F2DDrawer* drawer, int altval) +{ + int scaleval; + if (altval > 0) scaleval = (altval+1) / 2; + else if (uiscale == 0) + { + // Default should try to scale to 640x400 + int vscale = drawer->GetHeight() / 720; + int hscale = drawer->GetWidth() / 1280; + scaleval = max(1, min(vscale, hscale)); + } + else scaleval = (uiscale+1) / 2; + + // block scales that result in something larger than the current screen. + int vmax = drawer->GetHeight() / 400; + int hmax = drawer->GetWidth() / 640; + int max = std::max(vmax, hmax); + return std::max(1, min(scaleval, max)); +} + + +// [RH] Stretch values to make a 320x200 image best fit the screen +// without using fractional steppings +int CleanXfac, CleanYfac; + +// [RH] Effective screen sizes that the above scale values give you +int CleanWidth, CleanHeight; + +// Above minus 1 (or 1, if they are already 1) +int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1; + + +//========================================================================== +// +// Internal texture drawing function +// +//========================================================================== + +void DoDrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int tags_first, Va_List& tags) +{ + DrawParms parms; + + if (!img || !img->isValid()) return; + bool res = ParseDrawTextureTags(drawer, img, x, y, tags_first, tags, &parms, DrawTexture_Normal); + va_end(tags.list); + if (!res) + { + return; + } + drawer->AddTexture(img, parms); +} + + +void DrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int tags_first, ...) +{ + Va_List tags; + va_start(tags.list, tags_first); + DoDrawTexture(drawer, img, x, y, tags_first, tags); +} + +void DrawTexture(F2DDrawer *drawer, FTextureID texid, bool animate, double x, double y, int tags_first, ...) +{ + Va_List tags; + va_start(tags.list, tags_first); + auto img = TexMan.GetGameTexture(texid, animate); + DoDrawTexture(drawer, img, x, y, tags_first, tags); +} + + +//========================================================================== +// +// ZScript texture drawing function +// +//========================================================================== + +int ListGetInt(VMVa_List &tags); + +void DoDrawTexture(F2DDrawer *drawer, FGameTexture *img, double x, double y, VMVa_List &args) +{ + DrawParms parms; + uint32_t tag = ListGetInt(args); + if (!img || !img->isValid()) return; + bool res = ParseDrawTextureTags(drawer, img, x, y, tag, args, &parms, DrawTexture_Normal); + if (!res) return; + drawer->AddTexture(img, parms); +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + PARAM_BOOL(animate); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + auto tex = TexMan.GameByIndex(texid, animate); + VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 }; + DoDrawTexture(twod, tex, x, y, args); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, DrawTexture) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_INT(texid); + PARAM_BOOL(animate); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + auto tex = TexMan.GameByIndex(texid, animate); + VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo + 5 }; + DoDrawTexture(&self->Drawer, tex, x, y, args); + self->Tex->NeedUpdate(); + return 0; +} + +//========================================================================== +// +// ZScript arbitrary textured shape drawing functions +// +//========================================================================== + +void DrawShape(F2DDrawer *drawer, FGameTexture *img, DShape2D *shape, int tags_first, ...) +{ + Va_List tags; + va_start(tags.list, tags_first); + DrawParms parms; + + bool res = ParseDrawTextureTags(drawer, img, 0, 0, tags_first, tags, &parms, DrawTexture_Normal); + va_end(tags.list); + if (!res) return; + drawer->AddShape(img, shape, parms); +} + +void DrawShape(F2DDrawer *drawer, FGameTexture *img, DShape2D *shape, VMVa_List &args) +{ + DrawParms parms; + uint32_t tag = ListGetInt(args); + + bool res = ParseDrawTextureTags(drawer, img, 0, 0, tag, args, &parms, DrawTexture_Normal); + if (!res) return; + drawer->AddShape(img, shape, parms); +} + +void DrawShapeFill(F2DDrawer *drawer, PalEntry color, double amount, DShape2D *shape, VMVa_List &args) +{ + DrawParms parms; + uint32_t tag = ListGetInt(args); + + bool res = ParseDrawTextureTags(drawer, nullptr, 0, 0, tag, args, &parms, DrawTexture_Fill, color, amount); + if (!res) return; + + drawer->AddShape(nullptr, shape, parms); +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawShape) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + PARAM_BOOL(animate); + PARAM_POINTER(shape, DShape2D); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + auto tex = TexMan.GameByIndex(texid, animate); + VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo + 3 }; + + DrawShape(twod, tex, shape, args); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, DrawShape) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_INT(texid); + PARAM_BOOL(animate); + PARAM_POINTER(shape, DShape2D); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + auto tex = TexMan.GameByIndex(texid, animate); + VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 }; + + DrawShape(&self->Drawer, tex, shape, args); + self->Tex->NeedUpdate(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawShapeFill) +{ + PARAM_PROLOGUE; + PARAM_COLOR(color); + PARAM_FLOAT(amount); + PARAM_POINTER(shape, DShape2D); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo + 3 }; + + DrawShapeFill(twod, color, amount, shape, args); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, DrawShapeFill) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_COLOR(color); + PARAM_FLOAT(amount); + PARAM_POINTER(shape, DShape2D); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 }; + + DrawShapeFill(&self->Drawer, color, amount, shape, args); + self->Tex->NeedUpdate(); + return 0; +} + +//========================================================================== +// +// Clipping rect +// +//========================================================================== + +void F2DDrawer::SetClipRect(int x, int y, int w, int h) +{ + if (x < 0) { w += x; x = 0; } + if (y < 0) { h += y; y = 0; } + if (x >= GetWidth()) { x = GetWidth(); w = 0; } + if (y >= GetHeight()) { x = GetHeight(); h = 0; } + clipleft = x; + clipwidth = w; + cliptop = y; + clipheight = h; +} + +DEFINE_ACTION_FUNCTION(_Screen, SetClipRect) +{ + PARAM_PROLOGUE; + PARAM_INT(x); + PARAM_INT(y); + PARAM_INT(w); + PARAM_INT(h); + twod->SetClipRect(x, y, w, h); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, SetClipRect) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_INT(x); + PARAM_INT(y); + PARAM_INT(w); + PARAM_INT(h); + self->Drawer.SetClipRect(x, y, w, h); + self->Tex->NeedUpdate(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Screen, ClearClipRect) +{ + PARAM_PROLOGUE; + twod->ClearClipRect(); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, ClearClipRect) +{ + PARAM_SELF_PROLOGUE(FCanvas); + self->Drawer.ClearClipRect(); + self->Tex->NeedUpdate(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Screen, ClearScreen) +{ + PARAM_PROLOGUE; + twod->ClearScreen(); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, ClearScreen) +{ + PARAM_SELF_PROLOGUE(FCanvas); + self->Drawer.ClearScreen(); + self->Tex->NeedUpdate(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Screen, SetScreenFade) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x); + twod->SetScreenFade(float(x)); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, SetScreenFade) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_FLOAT(x); + self->Drawer.SetScreenFade(float(x)); + self->Tex->NeedUpdate(); + return 0; +} + + +void F2DDrawer::GetClipRect(int *x, int *y, int *w, int *h) +{ + if (x) *x = clipleft; + if (y) *y = cliptop; + if (w) *w = clipwidth; + if (h) *h = clipheight; +} + +DEFINE_ACTION_FUNCTION(_Screen, GetClipRect) +{ + PARAM_PROLOGUE; + int x, y, w, h; + twod->GetClipRect(&x, &y, &w, &h); + if (numret > 0) ret[0].SetInt(x); + if (numret > 1) ret[1].SetInt(y); + if (numret > 2) ret[2].SetInt(w); + if (numret > 3) ret[3].SetInt(h); + return min(numret, 4); +} + +DEFINE_ACTION_FUNCTION(FCanvas, GetClipRect) +{ + PARAM_SELF_PROLOGUE(FCanvas); + int x, y, w, h; + self->Drawer.GetClipRect(&x, &y, &w, &h); + if (numret > 0) ret[0].SetInt(x); + if (numret > 1) ret[1].SetInt(y); + if (numret > 2) ret[2].SetInt(w); + if (numret > 3) ret[3].SetInt(h); + return min(numret, 4); +} + + +void CalcFullscreenScale(DrawParms *parms, double srcwidth, double srcheight, int oautoaspect, DoubleRect &rect) +{ + auto GetWidth = [=]() { return parms->viewport.width; }; + auto GetHeight = [=]() {return parms->viewport.height; }; + + int autoaspect = oautoaspect; + if (autoaspect == FSMode_ScaleToScreen) + { + rect.left = rect.top = 0; + rect.width = GetWidth(); + rect.height = GetHeight(); + return; + } + + double aspect; + if (srcheight == 200) srcheight = 240.; + else if (srcheight == 400) srcheight = 480; + aspect = srcwidth / srcheight; + rect.left = rect.top = 0; + auto screenratio = ActiveRatio(GetWidth(), GetHeight()); + if (autoaspect == FSMode_ScaleToFit43 || autoaspect == FSMode_ScaleToFit43Top || autoaspect == FSMode_ScaleToFit43Bottom) + { + // screen is wider than the image -> pillarbox it. 4:3 images must also be pillarboxed if the screen is taller than the image + if (screenratio >= aspect || aspect < 1.4) autoaspect = FSMode_ScaleToFit; + else if (screenratio > 1.32) autoaspect = FSMode_ScaleToFill; // on anything 4:3 and wider crop the sides of the image. + else + { + // special case: Crop image to 4:3 and then letterbox this. This avoids too much cropping on narrow windows. + double width4_3 = srcheight * (4. / 3.); + rect.width = (double)GetWidth() * srcwidth / width4_3; + rect.height = GetHeight() * screenratio * (3. / 4.); // use 4:3 for the image + rect.left = (double)GetWidth() * (-(srcwidth - width4_3) / 2) / width4_3; + switch (oautoaspect) + { + default: + rect.top = (GetHeight() - rect.height) / 2; + break; + case FSMode_ScaleToFit43Top: + rect.top = 0; + break; + case FSMode_ScaleToFit43Bottom: + rect.top = (GetHeight() - rect.height); + break; + } + return; + } + } + + if (autoaspect == FSMode_ScaleToHeight || (screenratio > aspect) ^ (autoaspect == FSMode_ScaleToFill)) + { + // pillarboxed or vertically cropped (i.e. scale to height) + rect.height = GetHeight(); + rect.width = GetWidth() * aspect / screenratio; + rect.left = (GetWidth() - rect.width) / 2; + } + else + { + // letterboxed or horizontally cropped (i.e. scale to width) + rect.width = GetWidth(); + rect.height = GetHeight() * screenratio / aspect; + switch (oautoaspect) + { + default: + rect.top = (GetHeight() - rect.height) / 2; + break; + case FSMode_ScaleToFit43Top: + rect.top = 0; + break; + case FSMode_ScaleToFit43Bottom: + rect.top = (GetHeight() - rect.height); + break; + } + } +} + +void GetFullscreenRect(double width, double height, int fsmode, DoubleRect* rect) +{ + DrawParms parms; + parms.viewport.width = twod->GetWidth(); + parms.viewport.height = twod->GetHeight(); + CalcFullscreenScale(&parms, width, height, fsmode, *rect); +} + +DEFINE_ACTION_FUNCTION(_Screen, GetFullscreenRect) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(virtw); + PARAM_FLOAT(virth); + PARAM_INT(fsmode); + + DrawParms parms; + DoubleRect rect; + parms.viewport.width = twod->GetWidth(); + parms.viewport.height = twod->GetHeight(); + CalcFullscreenScale(&parms, virtw, virth, fsmode, rect); + if (numret >= 1) ret[0].SetFloat(rect.left); + if (numret >= 2) ret[1].SetFloat(rect.top); + if (numret >= 3) ret[2].SetFloat(rect.width); + if (numret >= 4) ret[3].SetFloat(rect.height); + return min(numret, 4); +} + +DEFINE_ACTION_FUNCTION(FCanvas, GetFullscreenRect) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_FLOAT(virtw); + PARAM_FLOAT(virth); + PARAM_INT(fsmode); + + DrawParms parms; + DoubleRect rect; + parms.viewport.width = self->Drawer.GetWidth(); + parms.viewport.height = self->Drawer.GetHeight(); + CalcFullscreenScale(&parms, virtw, virth, fsmode, rect); + if (numret >= 1) ret[0].SetFloat(rect.left); + if (numret >= 2) ret[1].SetFloat(rect.top); + if (numret >= 3) ret[2].SetFloat(rect.width); + if (numret >= 4) ret[3].SetFloat(rect.height); + return min(numret, 4); +} + + +//========================================================================== +// +// Draw parameter parsing +// +//========================================================================== + +bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, double xx, double yy) +{ + auto GetWidth = [=]() { return parms->viewport.width; }; + auto GetHeight = [=]() {return parms->viewport.height; }; + if (img != NULL) + { + parms->x = xx; + parms->y = yy; + parms->texwidth = img->GetDisplayWidth(); + parms->texheight = img->GetDisplayHeight(); + if (parms->top == INT_MAX || parms->fortext) + { + parms->top = img->GetDisplayTopOffset(); + } + if (parms->left == INT_MAX || parms->fortext) + { + parms->left = img->GetDisplayLeftOffset(); + } + if (parms->destwidth == INT_MAX || parms->fortext) + { + parms->destwidth = parms->texwidth; + } + if (parms->destheight == INT_MAX || parms->fortext) + { + parms->destheight = parms->texheight; + } + parms->destwidth *= parms->patchscalex; + parms->destheight *= parms->patchscaley; + + if (parms->flipoffsets && parms->flipY) parms->top = parms->texheight - parms->top; + if (parms->flipoffsets && parms->flipX) parms->left = parms->texwidth - parms->left; + + switch (parms->cleanmode) + { + default: + break; + + case DTA_Clean: + parms->x = (parms->x - 160.0) * CleanXfac + (GetWidth() * 0.5); + parms->y = (parms->y - 100.0) * CleanYfac + (GetHeight() * 0.5); + parms->destwidth = parms->texwidth * CleanXfac; + parms->destheight = parms->texheight * CleanYfac; + break; + + case DTA_CleanTop: + parms->x = (parms->x - 160.0) * CleanXfac + (GetWidth() * 0.5); + parms->y = (parms->y) * CleanYfac; + parms->destwidth = parms->texwidth * CleanXfac; + parms->destheight = parms->texheight * CleanYfac; + break; + + case DTA_CleanNoMove: + parms->destwidth = parms->texwidth * CleanXfac; + parms->destheight = parms->texheight * CleanYfac; + break; + + case DTA_CleanNoMove_1: + parms->destwidth = parms->texwidth * CleanXfac_1; + parms->destheight = parms->texheight * CleanYfac_1; + break; + + case DTA_Base: + if (parms->fsscalemode > 0) + { + // First calculate the destination rect for an image of the given size and then reposition this object in it. + DoubleRect rect; + CalcFullscreenScale(parms, parms->virtWidth, parms->virtHeight, parms->fsscalemode, rect); + double adder = parms->keepratio < 0 ? 0 : parms->keepratio == 0 ? rect.left : 2 * rect.left; + parms->x = parms->viewport.left + adder + parms->x * rect.width / parms->virtWidth; + parms->y = parms->viewport.top + rect.top + parms->y * rect.height / parms->virtHeight; + parms->destwidth = parms->destwidth * rect.width / parms->virtWidth; + parms->destheight = parms->destheight * rect.height / parms->virtHeight; + return false; + } + break; + + case DTA_Fullscreen: + case DTA_FullscreenEx: + { + DoubleRect rect; + CalcFullscreenScale(parms, parms->texwidth, parms->texheight, parms->fsscalemode, rect); + parms->keepratio = -1; + parms->x = parms->viewport.left + rect.left; + parms->y = parms->viewport.top + rect.top; + parms->destwidth = rect.width; + parms->destheight = rect.height; + parms->top = parms->left = 0; + return false; // Do not call VirtualToRealCoords for this! + } + + case DTA_HUDRules: + case DTA_HUDRulesC: + { + // Note that this has been deprecated and become non-functional. The HUD should be drawn by the status bar. + bool xright = parms->x < 0; + bool ybot = parms->y < 0; + DVector2 scale = { 1., 1. }; + + parms->x *= scale.X; + if (parms->cleanmode == DTA_HUDRulesC) + parms->x += GetWidth() * 0.5; + else if (xright) + parms->x = GetWidth() + parms->x; + parms->y *= scale.Y; + if (ybot) + parms->y = GetHeight() + parms->y; + parms->destwidth = parms->texwidth * scale.X; + parms->destheight = parms->texheight * scale.Y; + break; + } + } + if (parms->virtWidth != GetWidth() || parms->virtHeight != GetHeight()) + { + VirtualToRealCoords(drawer, GetWidth(), GetHeight(), parms->x, parms->y, parms->destwidth, parms->destheight, + parms->virtWidth, parms->virtHeight, parms->virtBottom, !parms->keepratio); + } + parms->x += parms->viewport.left; + parms->y += parms->viewport.top; + } + + return false; +} + +//========================================================================== +// +// template helpers +// +//========================================================================== + +static void ListEnd(Va_List &tags) +{ + va_end(tags.list); +} + +static int ListGetInt(Va_List &tags) +{ + return va_arg(tags.list, int); +} + +static inline double ListGetDouble(Va_List &tags) +{ + return va_arg(tags.list, double); +} + +static inline FSpecialColormap * ListGetSpecialColormap(Va_List &tags) +{ + return va_arg(tags.list, FSpecialColormap *); +} + +static void ListEnd(VMVa_List &tags) +{ +} + +int ListGetInt(VMVa_List &tags) +{ + if (tags.curindex < tags.numargs) + { + if (tags.reginfo[tags.curindex] == REGT_INT) + { + return tags.args[tags.curindex++].i; + } + ThrowAbortException(X_OTHER, "Invalid parameter in draw function, int expected"); + } + return TAG_DONE; +} + +static inline double ListGetDouble(VMVa_List &tags) +{ + if (tags.curindex < tags.numargs) + { + if (tags.reginfo[tags.curindex] == REGT_FLOAT) + { + return tags.args[tags.curindex++].f; + } + if (tags.reginfo[tags.curindex] == REGT_INT) + { + return tags.args[tags.curindex++].i; + } + ThrowAbortException(X_OTHER, "Invalid parameter in draw function, float expected"); + } + return 0; +} + +static inline FSpecialColormap * ListGetSpecialColormap(VMVa_List &tags) +{ + ThrowAbortException(X_OTHER, "Invalid tag in draw function"); + return nullptr; +} + +//========================================================================== +// +// Main taglist parsing +// +//========================================================================== + +template +bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double y, uint32_t tag, T& tags, DrawParms *parms, int type, PalEntry fill, double fillalpha, bool scriptDifferences) +{ + INTBOOL boolval; + int intval; + bool fillcolorset = type == DrawTexture_Fill; + + if (type == DrawTexture_Normal) + { + if (img == NULL || !img->isValid()) + { + ListEnd(tags); + return false; + } + } + + // Do some sanity checks on the coordinates. + if (x < -16383 || x > 16383 || y < -16383 || y > 16383) + { + ListEnd(tags); + return false; + } + + parms->fortext = type == DrawTexture_Text; + parms->windowleft = 0; + parms->windowright = INT_MAX; + parms->dclip = drawer->GetHeight(); + parms->uclip = 0; + parms->lclip = 0; + parms->rclip = drawer->GetWidth(); + parms->left = INT_MAX; + parms->top = INT_MAX; + parms->destwidth = INT_MAX; + parms->destheight = INT_MAX; + parms->Alpha = type == DrawTexture_Fill ? (float)fillalpha : 1.f; + parms->fillcolor = type == DrawTexture_Fill ? fill : PalEntry(~0u); + parms->TranslationId = INVALID_TRANSLATION; + parms->colorOverlay = 0; + parms->alphaChannel = false; + parms->flipX = false; + parms->flipY = false; + parms->color = 0xffffffff; + //parms->shadowAlpha = 0; + parms->shadowColor = 0; + parms->virtWidth = INT_MAX; // these need to match the viewport if not explicitly set, but we do not know that yet. + parms->virtHeight = INT_MAX; + parms->keepratio = false; + parms->style.BlendOp = 255; // Dummy "not set" value + parms->masked = true; + parms->bilinear = false; + parms->specialcolormap = NULL; + parms->desaturate = 0; + parms->cleanmode = DTA_Base; + parms->scalex = parms->scaley = 1; + parms->cellx = parms->celly = 0; + parms->maxstrlen = INT_MAX; + parms->localize = scriptDifferences; + parms->virtBottom = false; + parms->srcx = 0.; + parms->srcy = 0.; + parms->srcwidth = 1.; + parms->srcheight = 1.; + parms->burn = false; + parms->monospace = EMonospacing::Off; + parms->spacing = 0; + parms->fsscalemode = -1; + parms->patchscalex = parms->patchscaley = 1; + parms->viewport = { 0,0,drawer->GetWidth(), drawer->GetHeight() }; + parms->rotateangle = 0; + parms->flipoffsets = false; + parms->indexed = false; + parms->nooffset = false; + + // Parse the tag list for attributes. (For floating point attributes, + // consider that the C ABI dictates that all floats be promoted to + // doubles when passed as function arguments.) + while (tag != TAG_DONE) + { + switch (tag) + { + default: + ListGetInt(tags); + break; + + case DTA_DestWidth: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->cleanmode = DTA_Base; + parms->destwidth = ListGetInt(tags); + break; + + case DTA_DestWidthF: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->cleanmode = DTA_Base; + parms->destwidth = ListGetDouble(tags); + break; + + case DTA_DestHeight: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->cleanmode = DTA_Base; + parms->destheight = ListGetInt(tags); + break; + + case DTA_DestHeightF: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->cleanmode = DTA_Base; + parms->destheight = ListGetDouble(tags); + break; + + case DTA_Clean: + case DTA_CleanTop: + boolval = ListGetInt(tags); + if (boolval) + { + parms->scalex = 1; + parms->scaley = 1; + parms->cleanmode = tag; + } + break; + + case DTA_CleanNoMove: + boolval = ListGetInt(tags); + if (boolval) + { + parms->scalex = CleanXfac; + parms->scaley = CleanYfac; + parms->cleanmode = tag; + } + break; + + case DTA_CleanNoMove_1: + boolval = ListGetInt(tags); + if (boolval) + { + parms->scalex = CleanXfac_1; + parms->scaley = CleanYfac_1; + parms->cleanmode = tag; + } + break; + + case DTA_320x200: + boolval = ListGetInt(tags); + if (boolval) + { + parms->cleanmode = DTA_Base; + parms->scalex = 1; + parms->scaley = 1; + parms->virtWidth = 320; + parms->virtHeight = 200; + } + break; + + case DTA_Bottom320x200: + boolval = ListGetInt(tags); + if (boolval) + { + parms->cleanmode = DTA_Base; + parms->scalex = 1; + parms->scaley = 1; + parms->virtWidth = 320; + parms->virtHeight = 200; + } + parms->virtBottom = true; + break; + + case DTA_HUDRules: + intval = ListGetInt(tags); + parms->cleanmode = intval == HUD_HorizCenter ? DTA_HUDRulesC : DTA_HUDRules; + break; + + case DTA_VirtualWidth: + parms->cleanmode = DTA_Base; + parms->virtWidth = ListGetInt(tags); + break; + + case DTA_VirtualWidthF: + parms->cleanmode = DTA_Base; + parms->virtWidth = ListGetDouble(tags); + break; + + case DTA_VirtualHeight: + parms->cleanmode = DTA_Base; + parms->virtHeight = ListGetInt(tags); + break; + + case DTA_VirtualHeightF: + parms->cleanmode = DTA_Base; + parms->virtHeight = ListGetDouble(tags); + break; + + case DTA_FullscreenScale: + intval = ListGetInt(tags); + if (intval >= FSMode_None && intval < FSMode_Max) + { + parms->fsscalemode = (int8_t)intval; + } + else if (intval >= FSMode_Predefined && intval < FSMode_Predefined_Max) + { + static const uint8_t modes[] = { FSMode_ScaleToFit43, FSMode_ScaleToFit43, FSMode_ScaleToFit43, FSMode_ScaleToFit43, FSMode_ScaleToFit43Top}; + static const uint16_t widths[] = { 320, 320, 640, 640, 320}; + static const uint16_t heights[] = { 200, 240, 400, 480, 200}; + parms->fsscalemode = modes[intval - FSMode_Predefined]; + parms->virtWidth = widths[intval - FSMode_Predefined]; + parms->virtHeight = heights[intval - FSMode_Predefined]; + } + break; + + case DTA_Fullscreen: + + boolval = ListGetInt(tags); + if (boolval) + { + assert(type != DrawTexture_Text); + if (img == NULL) return false; + parms->cleanmode = DTA_Fullscreen; + parms->fsscalemode = (uint8_t)twod->fullscreenautoaspect; + parms->virtWidth = img->GetDisplayWidth(); + parms->virtHeight = img->GetDisplayHeight(); + } + break; + + case DTA_FullscreenEx: + + intval = ListGetInt(tags); + if (intval >= 0 && intval <= 3) + { + assert(type != DrawTexture_Text); + if (img == NULL) return false; + parms->cleanmode = DTA_Fullscreen; + parms->fsscalemode = (uint8_t)intval; + parms->virtWidth = img->GetDisplayWidth(); + parms->virtHeight = img->GetDisplayHeight(); + } + break; + + case DTA_Alpha: + parms->Alpha = (float)(min(1., ListGetDouble(tags))); + break; + + case DTA_AlphaChannel: + parms->alphaChannel = ListGetInt(tags); + break; + + case DTA_FillColor: + parms->fillcolor = ListGetInt(tags); + if (parms->fillcolor != ~0u) + { + fillcolorset = true; + } + else if (parms->fillcolor != 0) + { + // The crosshair is the only thing which uses a non-black fill color. + parms->fillcolor = PalEntry(ColorMatcher.Pick(parms->fillcolor), RPART(parms->fillcolor), GPART(parms->fillcolor), BPART(parms->fillcolor)); + } + break; + + case DTA_TranslationIndex: + parms->TranslationId = FTranslationID::fromInt(ListGetInt(tags)); + break; + + case DTA_ColorOverlay: + parms->colorOverlay = ListGetInt(tags); + break; + + case DTA_Color: + parms->color = ListGetInt(tags); + break; + + case DTA_FlipX: + parms->flipX = ListGetInt(tags); + break; + + case DTA_FlipY: + parms->flipY = ListGetInt(tags); + break; + + case DTA_FlipOffsets: + parms->flipoffsets = ListGetInt(tags); + break; + + case DTA_NoOffset: + parms->nooffset = ListGetInt(tags); + break; + + case DTA_SrcX: + parms->srcx = ListGetDouble(tags) / img->GetDisplayWidth(); + break; + + case DTA_SrcY: + parms->srcy = ListGetDouble(tags) / img->GetDisplayHeight(); + break; + + case DTA_SrcWidth: + parms->srcwidth = ListGetDouble(tags) / img->GetDisplayWidth(); + break; + + case DTA_SrcHeight: + parms->srcheight = ListGetDouble(tags) / img->GetDisplayHeight(); + break; + + case DTA_TopOffset: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->top = ListGetInt(tags); + break; + + case DTA_TopOffsetF: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->top = ListGetDouble(tags); + break; + + case DTA_LeftOffset: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->left = ListGetInt(tags); + break; + + case DTA_LeftOffsetF: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->left = ListGetDouble(tags); + break; + + case DTA_TopLeft: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + if (ListGetInt(tags)) + { + parms->left = 0; + parms->top = 0; + } + break; + + case DTA_CenterOffset: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + if (ListGetInt(tags)) + { + parms->left = img->GetDisplayWidth() * 0.5; + parms->top = img->GetDisplayHeight() * 0.5; + } + break; + + case DTA_CenterOffsetRel: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + intval = ListGetInt(tags); + if (intval == 1) + { + parms->left = img->GetDisplayLeftOffset() + (img->GetDisplayWidth() * 0.5); + parms->top = img->GetDisplayTopOffset() + (img->GetDisplayHeight() * 0.5); + } + else if (intval == 2) + { + parms->left = img->GetDisplayLeftOffset() + floor(img->GetDisplayWidth() * 0.5); + parms->top = img->GetDisplayTopOffset() + floor(img->GetDisplayHeight() * 0.5); + } + break; + + case DTA_CenterBottomOffset: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + if (ListGetInt(tags)) + { + parms->left = img->GetDisplayWidth() * 0.5; + parms->top = img->GetDisplayHeight(); + } + break; + + case DTA_WindowLeft: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->windowleft = ListGetInt(tags); + break; + + case DTA_WindowLeftF: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->windowleft = ListGetDouble(tags); + break; + + case DTA_WindowRight: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->windowright = ListGetInt(tags); + break; + + case DTA_WindowRightF: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->windowright = ListGetDouble(tags); + break; + + case DTA_ClipTop: + parms->uclip = ListGetInt(tags); + if (parms->uclip < 0) + { + parms->uclip = 0; + } + break; + + case DTA_ClipBottom: + parms->dclip = ListGetInt(tags); + if (parms->dclip > drawer->GetHeight()) + { + parms->dclip = drawer->GetHeight(); + } + break; + + case DTA_ClipLeft: + parms->lclip = ListGetInt(tags); + if (parms->lclip < 0) + { + parms->lclip = 0; + } + break; + + case DTA_ClipRight: + parms->rclip = ListGetInt(tags); + if (parms->rclip > drawer->GetWidth()) + { + parms->rclip = drawer->GetWidth(); + } + break; + + case DTA_ShadowAlpha: + //parms->shadowAlpha = (float)min(1., ListGetDouble(tags)); + break; + + case DTA_ShadowColor: + parms->shadowColor = ListGetInt(tags); + break; + + case DTA_Shadow: + boolval = ListGetInt(tags); + if (boolval) + { + //parms->shadowAlpha = 0.5; + parms->shadowColor = 0; + } + else + { + //parms->shadowAlpha = 0; + } + break; + + case DTA_ScaleX: + parms->patchscalex = ListGetDouble(tags); + break; + + case DTA_ScaleY: + parms->patchscaley = ListGetDouble(tags); + break; + + case DTA_Masked: + parms->masked = ListGetInt(tags); + break; + + case DTA_BilinearFilter: + parms->bilinear = ListGetInt(tags); + break; + + case DTA_KeepRatio: + parms->keepratio = ListGetInt(tags) ? -1 : 0; + break; + + case DTA_Pin: + parms->keepratio = ListGetInt(tags); + break; + + case DTA_RenderStyle: + parms->style.AsDWORD = ListGetInt(tags); + break; + + case DTA_LegacyRenderStyle: // mainly for ZScript which does not handle FRenderStyle that well. + parms->style = (ERenderStyle)ListGetInt(tags); + break; + + case DTA_SpecialColormap: + parms->specialcolormap = ListGetSpecialColormap(tags); + break; + + case DTA_Desaturate: + parms->desaturate = ListGetInt(tags); + break; + + case DTA_TextLen: + parms->maxstrlen = ListGetInt(tags); + break; + + case DTA_Localize: + parms->localize = ListGetInt(tags); + break; + + case DTA_CellX: + parms->cellx = ListGetInt(tags); + break; + + case DTA_CellY: + parms->celly = ListGetInt(tags); + break; + + case DTA_Monospace: + parms->monospace = ListGetInt(tags); + break; + + case DTA_Spacing: + parms->spacing = ListGetInt(tags); + break; + + case DTA_Burn: + parms->burn = true; + break; + + case DTA_ViewportX: + parms->viewport.left = ListGetInt(tags); + break; + + case DTA_ViewportY: + parms->viewport.top = ListGetInt(tags); + break; + + case DTA_ViewportWidth: + parms->viewport.width = ListGetInt(tags); + break; + + case DTA_ViewportHeight: + parms->viewport.height = ListGetInt(tags); + break; + + case DTA_Rotate: + assert(type != DrawTexture_Text); + if (type == DrawTexture_Text) return false; + parms->rotateangle = ListGetDouble(tags); + break; + + case DTA_Indexed: + parms->indexed = !!ListGetInt(tags); + break; + } + tag = ListGetInt(tags); + } + ListEnd(tags); + + if (parms->virtWidth == INT_MAX) parms->virtWidth = parms->viewport.width; + if (parms->virtHeight == INT_MAX) parms->virtHeight = parms->viewport.height; + + auto clipleft = drawer->clipleft; + auto cliptop = drawer->cliptop; + auto clipwidth = drawer->clipwidth; + auto clipheight = drawer->clipheight; + // intersect with the canvas's clipping rectangle. + if (clipwidth >= 0 && clipheight >= 0) + { + if (parms->lclip < clipleft) parms->lclip = clipleft; + if (parms->rclip > clipleft + clipwidth) parms->rclip = clipleft + clipwidth; + if (parms->uclip < cliptop) parms->uclip = cliptop; + if (parms->dclip > cliptop + clipheight) parms->dclip = cliptop + clipheight; + } + + if (parms->uclip >= parms->dclip || parms->lclip >= parms->rclip) + { + return false; + } + + if (img != NULL) + { + SetTextureParms(drawer, parms, img, x, y); + + if (parms->destwidth <= 0 || parms->destheight <= 0) + { + return false; + } + } + + if (parms->style.BlendOp == 255) + { + if (fillcolorset) + { + if (parms->alphaChannel) + { + parms->style = STYLE_Shaded; + } + else if (parms->Alpha < 1.f) + { + parms->style = STYLE_TranslucentStencil; + } + else + { + parms->style = STYLE_Stencil; + } + } + else if (parms->Alpha < 1.f) + { + parms->style = STYLE_Translucent; + } + else + { + parms->style = STYLE_Normal; + } + } + return true; +} +// explicitly instantiate both versions for v_text.cpp. + +template bool ParseDrawTextureTags(F2DDrawer* drawer, FGameTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, int type, PalEntry fill, double fillalpha, bool scriptDifferences); +template bool ParseDrawTextureTags(F2DDrawer* drawer, FGameTexture *img, double x, double y, uint32_t tag, VMVa_List& tags, DrawParms *parms, int type, PalEntry fill, double fillalpha, bool scriptDifferences); + +//========================================================================== +// +// Coordinate conversion +// +//========================================================================== + +static void VirtualToRealCoords(F2DDrawer *drawer, double Width, double Height, double &x, double &y, double &w, double &h, + double vwidth, double vheight, bool vbottom, bool handleaspect) +{ + float myratio = float(handleaspect ? ActiveRatio (Width, Height) : (4.0 / 3.0)); + + // if 21:9 AR, map to 16:9 for all callers. + // this allows for black bars and stops the stretching of fullscreen images + + switch (vid_allowtrueultrawide) + { + case 1: + default: + myratio = min(64.0f / 27.0f, myratio); + break; + case 0: + myratio = min(16.0f / 9.0f, myratio); + case -1: + break; + } + + double right = x + w; + double bottom = y + h; + + if (myratio > 1.334f) + { // The target surface is either 16:9 or 16:10, so expand the + // specified virtual size to avoid undesired stretching of the + // image. Does not handle non-4:3 virtual sizes. I'll worry about + // those if somebody expresses a desire to use them. + x = (x - vwidth * 0.5) * Width * 960 / (vwidth * AspectBaseWidth(myratio)) + Width * 0.5; + w = (right - vwidth * 0.5) * Width * 960 / (vwidth * AspectBaseWidth(myratio)) + Width * 0.5 - x; + } + else + { + x = x * Width / vwidth; + w = right * Width / vwidth - x; + } + if (AspectTallerThanWide(myratio)) + { // The target surface is 5:4 + y = (y - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5; + h = (bottom - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5 - y; + if (vbottom) + { + y += (Height - Height * AspectMultiplier(myratio) / 48.0) * 0.5; + } + } + else + { + y = y * Height / vheight; + h = bottom * Height / vheight - y; + } +} + +void VirtualToRealCoords(F2DDrawer* drawer, double& x, double& y, double& w, double& h, + double vwidth, double vheight, bool vbottom, bool handleaspect) +{ + auto Width = drawer->GetWidth(); + auto Height = drawer->GetHeight(); + VirtualToRealCoords(drawer, Width, Height, x, y, w, h, vwidth, vheight, vbottom, handleaspect); +} + +DEFINE_ACTION_FUNCTION(_Screen, VirtualToRealCoords) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + PARAM_FLOAT(vw); + PARAM_FLOAT(vh); + PARAM_BOOL(vbottom); + PARAM_BOOL(handleaspect); + VirtualToRealCoords(twod, x, y, w, h, vw, vh, vbottom, handleaspect); + if (numret >= 1) ret[0].SetVector2(DVector2(x, y)); + if (numret >= 2) ret[1].SetVector2(DVector2(w, h)); + return min(numret, 2); +} + +DEFINE_ACTION_FUNCTION(FCanvas, VirtualToRealCoords) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + PARAM_FLOAT(vw); + PARAM_FLOAT(vh); + PARAM_BOOL(vbottom); + PARAM_BOOL(handleaspect); + VirtualToRealCoords(&self->Drawer, x, y, w, h, vw, vh, vbottom, handleaspect); + if (numret >= 1) ret[0].SetVector2(DVector2(x, y)); + if (numret >= 2) ret[1].SetVector2(DVector2(w, h)); + return min(numret, 2); +} + +void VirtualToRealCoordsInt(F2DDrawer *drawer, int &x, int &y, int &w, int &h, + int vwidth, int vheight, bool vbottom, bool handleaspect) +{ + double dx, dy, dw, dh; + + dx = x; + dy = y; + dw = w; + dh = h; + VirtualToRealCoords(drawer, dx, dy, dw, dh, vwidth, vheight, vbottom, handleaspect); + x = int(dx + 0.5); + y = int(dy + 0.5); + w = int(dx + dw + 0.5) - x; + h = int(dy + dh + 0.5) - y; +} + +//========================================================================== +// +// Draw a line +// +//========================================================================== + +static void DrawLine(double x1, double y1, double x2, double y2, uint32_t realcolor, int alpha) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + twod->AddLine(DVector2(x1, y1), DVector2(x2, y2), nullptr, realcolor | MAKEARGB(255, 0, 0, 0), alpha); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_Screen, DrawLine, DrawLine) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x0); + PARAM_FLOAT(y0); + PARAM_FLOAT(x1); + PARAM_FLOAT(y1); + PARAM_INT(color); + PARAM_INT(alpha); + DrawLine(x0, y0, x1, y1, color, alpha); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, DrawLine) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_FLOAT(x0); + PARAM_FLOAT(y0); + PARAM_FLOAT(x1); + PARAM_FLOAT(y1); + PARAM_INT(color); + PARAM_INT(alpha); + self->Drawer.AddLine(DVector2(x0, y0), DVector2(x1, y1), nullptr, color | MAKEARGB(255, 0, 0, 0), alpha); + self->Tex->NeedUpdate(); + return 0; +} + +static void DrawThickLine(double x1, double y1, double x2, double y2, double thickness, uint32_t realcolor, int alpha) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + twod->AddThickLine(DVector2(x1, y1), DVector2(x2, y2), thickness, realcolor, alpha); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_Screen, DrawThickLine, DrawThickLine) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x0); + PARAM_FLOAT(y0); + PARAM_FLOAT(x1); + PARAM_FLOAT(y1); + PARAM_FLOAT(thickness); + PARAM_INT(color); + PARAM_INT(alpha); + DrawThickLine(x0, y0, x1, y1, thickness, color, alpha); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, DrawThickLine) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_FLOAT(x0); + PARAM_FLOAT(y0); + PARAM_FLOAT(x1); + PARAM_FLOAT(y1); + PARAM_FLOAT(thickness); + PARAM_INT(color); + PARAM_INT(alpha); + self->Drawer.AddThickLine(DVector2(x0, y0), DVector2(x1, y1), thickness, color, alpha); + self->Tex->NeedUpdate(); + return 0; +} + +//========================================================================== +// +// ClearRect +// +// Set an area to a specified color. +// +//========================================================================== + +void ClearRect(F2DDrawer *drawer, int left, int top, int right, int bottom, int palcolor, uint32_t color) +{ + auto clipleft = drawer->clipleft; + auto cliptop = drawer->cliptop; + auto clipwidth = drawer->clipwidth; + auto clipheight = drawer->clipheight; + + if (clipwidth >= 0 && clipheight >= 0) + { + int w = right - left; + int h = bottom - top; + if (left < clipleft) + { + w -= (clipleft - left); + left = clipleft; + } + if (w > clipwidth) w = clipwidth; + if (w <= 0) return; + + if (top < cliptop) + { + h -= (cliptop - top); + top = cliptop; + } + if (h > clipheight) w = clipheight; + if (h <= 0) return; + right = left + w; + bottom = top + h; + } + + if (palcolor >= 0 && color == 0) + { + color = GPalette.BaseColors[palcolor] | 0xff000000; + } + drawer->AddColorOnlyQuad(left, top, right - left, bottom - top, color | 0xFF000000, nullptr); +} + +DEFINE_ACTION_FUNCTION(_Screen, Clear) +{ + PARAM_PROLOGUE; + PARAM_INT(x1); + PARAM_INT(y1); + PARAM_INT(x2); + PARAM_INT(y2); + PARAM_INT(color); + PARAM_INT(palcol); + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + ClearRect(twod, x1, y1, x2, y2, palcol, color); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, Clear) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_INT(x1); + PARAM_INT(y1); + PARAM_INT(x2); + PARAM_INT(y2); + PARAM_INT(color); + PARAM_INT(palcol); + ClearRect(&self->Drawer, x1, y1, x2, y2, palcol, color); + self->Tex->NeedUpdate(); + return 0; +} + +//========================================================================== +// +// DoDim +// +// Applies a colored overlay to an area of the screen. +// +//========================================================================== + +void DoDim(F2DDrawer *drawer, PalEntry color, float amount, int x1, int y1, int w, int h, FRenderStyle *style) +{ + if (amount <= 0) + { + return; + } + if (amount > 1) + { + amount = 1; + } + drawer->AddColorOnlyQuad(x1, y1, w, h, (color.d & 0xffffff) | (int(amount * 255) << 24), style); +} + +void Dim(F2DDrawer *drawer, PalEntry color, float damount, int x1, int y1, int w, int h, FRenderStyle *style) +{ + auto clipleft = drawer->clipleft; + auto cliptop = drawer->cliptop; + auto clipwidth = drawer->clipwidth; + auto clipheight = drawer->clipheight; + + if (clipwidth >= 0 && clipheight >= 0) + { + if (x1 < clipleft) + { + w -= (clipleft - x1); + x1 = clipleft; + } + if (w > clipwidth) w = clipwidth; + if (w <= 0) return; + + if (y1 < cliptop) + { + h -= (cliptop - y1); + y1 = cliptop; + } + if (h > clipheight) h = clipheight; + if (h <= 0) return; + } + DoDim(drawer, color, damount, x1, y1, w, h, style); +} + +DEFINE_ACTION_FUNCTION(_Screen, Dim) +{ + PARAM_PROLOGUE; + PARAM_INT(color); + PARAM_FLOAT(amount); + PARAM_INT(x1); + PARAM_INT(y1); + PARAM_INT(w); + PARAM_INT(h); + PARAM_INT(style); + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + Dim(twod, color, float(amount), x1, y1, w, h, &LegacyRenderStyles[style]); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, Dim) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_INT(color); + PARAM_FLOAT(amount); + PARAM_INT(x1); + PARAM_INT(y1); + PARAM_INT(w); + PARAM_INT(h); + PARAM_INT(style); + Dim(&self->Drawer, color, float(amount), x1, y1, w, h, &LegacyRenderStyles[style]); + self->Tex->NeedUpdate(); + return 0; +} + + +//========================================================================== +// +// screen->DrawBorder +// +//========================================================================== + +void DrawBorder (F2DDrawer *drawer, FTextureID texid, int x1, int y1, int x2, int y2) +{ + int filltype = (ui_screenborder_classic_scaling) ? -1 : 0; + if (texid.isValid()) + { + drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetGameTexture(texid, false), filltype); + } + else + { + ClearRect(drawer, x1, y1, x2, y2, 0, 0); + } +} + +//========================================================================== +// +// V_DrawFrame +// +// Draw a frame around the specified area using the view border +// frame graphics. The border is drawn outside the area, not in it. +// +//========================================================================== + +void DrawFrame(F2DDrawer* twod, PalEntry color, int left, int top, int width, int height, int thickness) +{ + // Sanity check for incomplete gameinfo + int offset = thickness == -1 ? twod->GetHeight() / 400 : thickness; + int right = left + width; + int bottom = top + height; + + // Draw top and bottom sides. + twod->AddColorOnlyQuad(left, top - offset, width, offset, color); + twod->AddColorOnlyQuad(left - offset, top - offset, offset, height + 2 * offset, color); + twod->AddColorOnlyQuad(left, bottom, width, offset, color); + twod->AddColorOnlyQuad(right, top - offset, offset, height + 2 * offset, color); +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawLineFrame) +{ + PARAM_PROLOGUE; + PARAM_COLOR(color); + PARAM_INT(left); + PARAM_INT(top); + PARAM_INT(width); + PARAM_INT(height); + PARAM_INT(thickness); + DrawFrame(twod, color, left, top, width, height, thickness); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, DrawLineFrame) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_COLOR(color); + PARAM_INT(left); + PARAM_INT(top); + PARAM_INT(width); + PARAM_INT(height); + PARAM_INT(thickness); + DrawFrame(&self->Drawer, color, left, top, width, height, thickness); + self->Tex->NeedUpdate(); + return 0; +} + +void V_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realheight, int* cleanx, int* cleany, int* _cx1, int* _cx2) +{ + if (designheight < 240 && realheight >= 480) designheight = 240; + *cleanx = *cleany = min(realwidth / designwidth, realheight / designheight); +} + + +DEFINE_ACTION_FUNCTION(_Screen, SetOffset) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + ACTION_RETURN_VEC2(twod->SetOffset(DVector2(x, y))); +} + +DEFINE_ACTION_FUNCTION(FCanvas, SetOffset) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + ACTION_RETURN_VEC2(self->Drawer.SetOffset(DVector2(x, y))); +} + +DEFINE_ACTION_FUNCTION(_Screen, EnableStencil) +{ + PARAM_PROLOGUE; + PARAM_BOOL(on); + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + twod->AddEnableStencil(on); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, EnableStencil) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_BOOL(on); + + self->Drawer.AddEnableStencil(on); + self->Tex->NeedUpdate(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Screen, SetStencil) +{ + PARAM_PROLOGUE; + PARAM_INT(offs); + PARAM_INT(op); + PARAM_INT(flags); + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + twod->AddSetStencil(offs, op, flags); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, SetStencil) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_INT(offs); + PARAM_INT(op); + PARAM_INT(flags); + + self->Drawer.AddSetStencil(offs, op, flags); + self->Tex->NeedUpdate(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Screen, ClearStencil) +{ + PARAM_PROLOGUE; + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + twod->AddClearStencil(); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, ClearStencil) +{ + PARAM_SELF_PROLOGUE(FCanvas); + + self->Drawer.AddClearStencil(); + self->Tex->NeedUpdate(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Screen, SetTransform) +{ + PARAM_PROLOGUE; + PARAM_OBJECT_NOT_NULL(transform, DShape2DTransform); + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + twod->SetTransform(*transform); + + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, SetTransform) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_OBJECT_NOT_NULL(transform, DShape2DTransform); + + self->Drawer.SetTransform(*transform); + self->Tex->NeedUpdate(); + + return 0; +} + +DEFINE_ACTION_FUNCTION(_Screen, ClearTransform) +{ + PARAM_PROLOGUE; + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + twod->ClearTransform(); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, ClearTransform) +{ + PARAM_SELF_PROLOGUE(FCanvas); + + self->Drawer.ClearTransform(); + self->Tex->NeedUpdate(); + return 0; +} diff --git a/src/common/2d/v_draw.h b/src/common/2d/v_draw.h new file mode 100644 index 00000000000..e98ca92456f --- /dev/null +++ b/src/common/2d/v_draw.h @@ -0,0 +1,340 @@ +#pragma once + +#include "v_2ddrawer.h" +#include "c_cvars.h" +#include "intrect.h" + +// TagItem definitions for DrawTexture. As far as I know, tag lists +// originated on the Amiga. +// +// Think of TagItems as an array of the following structure: +// +// struct TagItem { +// uint32_t ti_Tag; +// uint32_t ti_Data; +// }; + +enum tags : uint32_t +{ + TAG_DONE = (0), /* Used to indicate the end of the Tag list */ + TAG_END = (0), /* Ditto */ + /* list pointed to in ti_Data */ + + TAG_USER = ((uint32_t)(1u << 30)) +}; + +enum +{ + FSMode_None = 0, + FSMode_ScaleToFit = 1, + FSMode_ScaleToFill = 2, + FSMode_ScaleToFit43 = 3, + FSMode_ScaleToScreen = 4, + FSMode_ScaleToFit43Top = 5, + FSMode_ScaleToFit43Bottom = 6, + FSMode_ScaleToHeight = 7, + + + FSMode_Max, + + // These all use ScaleToFit43, their purpose is to cut down on verbosity because they imply the virtual screen size. + FSMode_Predefined = 1000, + FSMode_Fit320x200 = 1000, + FSMode_Fit320x240, + FSMode_Fit640x400, + FSMode_Fit640x480, + FSMode_Fit320x200Top, + FSMode_Predefined_Max, +}; + +enum +{ + DTA_Base = TAG_USER + 5000, + DTA_DestWidth, // width of area to draw to + DTA_DestHeight, // height of area to draw to + DTA_Alpha, // alpha value for translucency + DTA_FillColor, // color to stencil onto the destination + DTA_TranslationIndex, // translation table to recolor the source + DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor + DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac + DTA_320x200, // bool: scale texture size and position to fit on a virtual 320x200 screen + DTA_Bottom320x200, // bool: same as DTA_320x200 but centers virtual screen on bottom for 1280x1024 targets + DTA_CleanNoMove, // bool: like DTA_Clean but does not reposition output position + DTA_CleanNoMove_1, // bool: like DTA_CleanNoMove, but uses Clean[XY]fac_1 instead + DTA_FlipX, // bool: flip image horizontally //FIXME: Does not work with DTA_Window(Left|Right) + DTA_ShadowColor, // color of shadow + DTA_ShadowAlpha, // alpha of shadow + DTA_Shadow, // set shadow color and alphas to defaults + DTA_VirtualWidth, // pretend the canvas is this wide + DTA_VirtualHeight, // pretend the canvas is this tall + DTA_TopOffset, // override texture's top offset + DTA_LeftOffset, // override texture's left offset + DTA_CenterOffset, // bool: override texture's left and top offsets and set them for the texture's middle + DTA_CenterBottomOffset,// bool: override texture's left and top offsets and set them for the texture's bottom middle + DTA_WindowLeft, // don't draw anything left of this column (on source, not dest) + DTA_WindowRight, // don't draw anything at or to the right of this column (on source, not dest) + DTA_ClipTop, // don't draw anything above this row (on dest, not source) + DTA_ClipBottom, // don't draw anything at or below this row (on dest, not source) + DTA_ClipLeft, // don't draw anything to the left of this column (on dest, not source) + DTA_ClipRight, // don't draw anything at or to the right of this column (on dest, not source) + DTA_Masked, // true(default)=use masks from texture, false=ignore masks + DTA_HUDRules, // use fullscreen HUD rules to position and size textures + DTA_HUDRulesC, // only used internally for marking HUD_HorizCenter + DTA_KeepRatio, // doesn't adjust screen size for DTA_Virtual* if the aspect ratio is not 4:3 + DTA_RenderStyle, // same as render style for actors + DTA_ColorOverlay, // uint32_t: ARGB to overlay on top of image; limited to black for software + DTA_BilinearFilter, // bool: apply bilinear filtering to the image + DTA_SpecialColormap,// pointer to FSpecialColormapParameters + DTA_Desaturate, // explicit desaturation factor (does not do anything in Legacy OpenGL) + DTA_Fullscreen, // Draw image fullscreen (same as DTA_VirtualWidth/Height with graphics size.) + + // floating point duplicates of some of the above: + DTA_DestWidthF, + DTA_DestHeightF, + DTA_TopOffsetF, + DTA_LeftOffsetF, + DTA_VirtualWidthF, + DTA_VirtualHeightF, + DTA_WindowLeftF, + DTA_WindowRightF, + + // For DrawText calls: + DTA_TextLen, // stop after this many characters, even if \0 not hit + DTA_CellX, // horizontal size of character cell + DTA_CellY, // vertical size of character cell + + // New additions. + DTA_Color, + DTA_FlipY, // bool: flip image vertically + DTA_SrcX, // specify a source rectangle (this supersedes the poorly implemented DTA_WindowLeft/Right + DTA_SrcY, + DTA_SrcWidth, + DTA_SrcHeight, + DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle + DTA_Burn, // activates the burn shader for this element + DTA_Spacing, // Strings only: Additional spacing between characters + DTA_Monospace, // Fonts only: Use a fixed distance between characters. + + DTA_FullscreenEx, + DTA_FullscreenScale, + DTA_ScaleX, + DTA_ScaleY, + + DTA_ViewportX, // Defines the viewport on the screen that should be rendered to. + DTA_ViewportY, + DTA_ViewportWidth, + DTA_ViewportHeight, + DTA_CenterOffsetRel, // Apply texture offsets relative to center, instead of top left. This is standard alignment for Build's 2D content. + DTA_TopLeft, // always align to top left. Added to have a boolean condition for this alignment. + DTA_Pin, // Pin a non-widescreen image to the left/right edge of the screen. + DTA_Rotate, + DTA_FlipOffsets, // Flips offsets when using DTA_FlipX and DTA_FlipY, this cannot be automatic due to unexpected behavior with unoffsetted graphics. + DTA_Indexed, // Use an indexed texture combined with the given translation. + DTA_CleanTop, // Like DTA_Clean but aligns to the top of the screen instead of the center. + DTA_NoOffset, // Ignore 2D drawer's offset. + DTA_Localize, // localize drawn string, for DrawText only + +}; + +enum EMonospacing : int +{ + Off = 0, + CellLeft = 1, + CellCenter = 2, + CellRight = 3 +}; + +enum +{ + HUD_Normal, + HUD_HorizCenter +}; + + +class FFont; +struct FRemapTable; +class player_t; +typedef uint32_t angle_t; + +struct DrawParms +{ + double x, y; + double texwidth; + double texheight; + double destwidth; + double destheight; + double virtWidth; + double virtHeight; + double windowleft; + double windowright; + int cleanmode; + int dclip; + int uclip; + int lclip; + int rclip; + double top; + double left; + float Alpha; + PalEntry fillcolor; + FTranslationID TranslationId; + PalEntry colorOverlay; + PalEntry color; + int alphaChannel; + int flipX; + int flipY; + //float shadowAlpha; + int shadowColor; + int keepratio; + int masked; + int bilinear; + FRenderStyle style; + struct FSpecialColormap *specialcolormap; + int desaturate; + int scalex, scaley; + int cellx, celly; + int monospace; + int spacing; + int maxstrlen; + bool localize; + bool fortext; + bool virtBottom; + bool burn; + bool flipoffsets; + bool indexed; + bool nooffset; + int8_t fsscalemode; + double srcx, srcy; + double srcwidth, srcheight; + double patchscalex, patchscaley; + double rotateangle; + IntRect viewport; + + bool vertexColorChange(const DrawParms& other) { + return + this->Alpha != other.Alpha || + this->fillcolor != other.fillcolor || + this->colorOverlay != other.colorOverlay || + this->color != other.color || + this->style.Flags != other.style.Flags || + this->style.BlendOp != other.style.BlendOp || + this->desaturate != other.desaturate; + } +}; + +struct Va_List +{ + va_list list; +}; + +struct VMVa_List +{ + VMValue *args; + int curindex; + int numargs; + const uint8_t *reginfo; +}; + +float ActiveRatio (int width, int height, float *trueratio = NULL); +inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); } + +int AspectBaseWidth(float aspect); +int AspectBaseHeight(float aspect); +double AspectPspriteOffset(float aspect); +int AspectMultiplier(float aspect); +bool AspectTallerThanWide(float aspect); + +extern F2DDrawer* twod; + +int GetUIScale(F2DDrawer* drawer, int altval); +int GetConScale(F2DDrawer* drawer, int altval); + +EXTERN_CVAR(Int, uiscale); +EXTERN_CVAR(Int, con_scale); + +inline int active_con_scale(F2DDrawer *drawer) +{ + return GetConScale(drawer, con_scale); +} + +#ifdef DrawText +#undef DrawText // See WinUser.h for the definition of DrawText as a macro +#endif + +enum +{ + DrawTexture_Normal, + DrawTexture_Text, + DrawTexture_Fill, +}; + +template +bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture* img, double x, double y, uint32_t tag, T& tags, DrawParms* parms, int type, PalEntry fill = ~0u, double fillalpha = 0.0, bool scriptDifferences = false); + +template +void DrawTextCommon(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double y, const T* string, DrawParms& parms); +bool SetTextureParms(F2DDrawer *drawer, DrawParms* parms, FGameTexture* img, double x, double y); + +void GetFullscreenRect(double width, double height, int fsmode, DoubleRect* rect); + +void DrawText(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, const char* string, int tag_first, ...); +void DrawText(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, const char32_t* string, int tag_first, ...); +void DrawChar(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, int character, int tag_first, ...); + +void DrawTexture(F2DDrawer* drawer, FGameTexture* img, double x, double y, int tags_first, ...); +void DrawTexture(F2DDrawer *drawer, FTextureID texid, bool animate, double x, double y, int tags_first, ...); + +void DoDim(F2DDrawer* drawer, PalEntry color, float amount, int x1, int y1, int w, int h, FRenderStyle* style = nullptr); +void Dim(F2DDrawer* drawer, PalEntry color, float damount, int x1, int y1, int w, int h, FRenderStyle* style = nullptr); + +void DrawBorder(F2DDrawer* drawer, FTextureID, int x1, int y1, int x2, int y2); +void DrawFrame(F2DDrawer* twod, PalEntry color, int left, int top, int width, int height, int thickness); + +// Set an area to a specified color +void ClearRect(F2DDrawer* drawer, int left, int top, int right, int bottom, int palcolor, uint32_t color); + +void VirtualToRealCoords(F2DDrawer* drawer, double& x, double& y, double& w, double& h, double vwidth, double vheight, bool vbottom = false, bool handleaspect = true); + +// Code that uses these (i.e. SBARINFO) should probably be evaluated for using doubles all around instead. +void VirtualToRealCoordsInt(F2DDrawer* drawer, int& x, int& y, int& w, int& h, int vwidth, int vheight, bool vbottom = false, bool handleaspect = true); + +extern int CleanWidth, CleanHeight, CleanXfac, CleanYfac; +extern int CleanWidth_1, CleanHeight_1, CleanXfac_1, CleanYfac_1; + +void V_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realheight, int* cleanx, int* cleany, int* cx1 = NULL, int* cx2 = NULL); + +class ScaleOverrider +{ + int savedxfac, savedyfac, savedwidth, savedheight; + +public: + // This is to allow certain elements to use an optimal fullscreen scale which for the menu would be too large. + // The old code contained far too much mess to compensate for the menus which negatively affected everything else. + // However, for compatibility reasons the currently used variables cannot be changed so they have to be overridden temporarily. + // This class provides a safe interface for this because it ensures that the values get restored afterward. + // Currently, the intermission and the level summary screen use this. + ScaleOverrider(F2DDrawer *drawer) + { + savedxfac = CleanXfac; + savedyfac = CleanYfac; + savedwidth = CleanWidth; + savedheight = CleanHeight; + + if (drawer) + { + V_CalcCleanFacs(320, 200, drawer->GetWidth(), drawer->GetHeight(), &CleanXfac, &CleanYfac); + CleanWidth = drawer->GetWidth() / CleanXfac; + CleanHeight = drawer->GetHeight() / CleanYfac; + } + } + + ~ScaleOverrider() + { + CleanXfac = savedxfac; + CleanYfac = savedyfac; + CleanWidth = savedwidth; + CleanHeight = savedheight; + } +}; + +void Draw2D(F2DDrawer* drawer, FRenderState& state); +void Draw2D(F2DDrawer* drawer, FRenderState& state, int x, int y, int width, int height); diff --git a/src/common/2d/v_drawtext.cpp b/src/common/2d/v_drawtext.cpp new file mode 100644 index 00000000000..56415a84fd2 --- /dev/null +++ b/src/common/2d/v_drawtext.cpp @@ -0,0 +1,459 @@ +/* +** v_text.cpp +** Draws text to a canvas. Also has a text line-breaker thingy. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include + +#include "v_text.h" +#include "utf8.h" +#include "v_draw.h" +#include "gstrings.h" +#include "vm.h" +#include "printf.h" + + +int ListGetInt(VMVa_List &tags); + + +//========================================================================== +// +// Create a texture from a text in a given font. +// +//========================================================================== +#if 0 +FGameTexture * BuildTextTexture(FFont *font, const char *string, int textcolor) +{ + int w; + const uint8_t *ch; + int cx; + int cy; + int trans = -1; + int kerning; + FGameTexture *pic; + + kerning = font->GetDefaultKerning(); + + ch = (const uint8_t *)string; + cx = 0; + cy = 0; + + + IntRect box; + + while (auto c = GetCharFromString(ch)) + { + if (c == TEXTCOLOR_ESCAPE) + { + // Here we only want to measure the texture so just parse over the color. + V_ParseFontColor(ch, 0, 0); + continue; + } + + if (c == '\n') + { + cx = 0; + cy += font->GetHeight(); + continue; + } + + if (nullptr != (pic = font->GetChar(c, CR_UNTRANSLATED, &w, nullptr))) + { + auto img = pic->GetImage(); + auto offsets = img->GetOffsets(); + int x = cx - offsets.first; + int y = cy - offsets.second; + int ww = img->GetWidth(); + int h = img->GetHeight(); + + box.AddToRect(x, y); + box.AddToRect(x + ww, y + h); + } + cx += (w + kerning); + } + + cx = -box.left; + cy = -box.top; + + TArray part(strlen(string)); + + while (auto c = GetCharFromString(ch)) + { + if (c == TEXTCOLOR_ESCAPE) + { + EColorRange newcolor = V_ParseFontColor(ch, textcolor, textcolor); + if (newcolor != CR_UNDEFINED) + { + trans = font->GetColorTranslation(newcolor); + textcolor = newcolor; + } + continue; + } + + if (c == '\n') + { + cx = 0; + cy += font->GetHeight(); + continue; + } + + if (nullptr != (pic = font->GetChar(c, textcolor, &w, nullptr))) + { + auto img = pic->GetImage(); + auto offsets = img->GetOffsets(); + int x = cx - offsets.first; + int y = cy - offsets.second; + + auto &tp = part[part.Reserve(1)]; + + tp.OriginX = x; + tp.OriginY = y; + tp.Image = img; + tp.Translation = range; + } + cx += (w + kerning); + } + FMultiPatchTexture *image = new FMultiPatchTexture(box.width, box.height, part, false, false); + image->SetOffsets(-box.left, -box.top); + FImageTexture *tex = new FImageTexture(image, ""); + tex->SetUseType(ETextureType::MiscPatch); + TexMan.AddTexture(tex); + return tex; +} +#endif + + +//========================================================================== +// +// DrawChar +// +// Write a single character using the given font +// +//========================================================================== + +void DrawChar(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double y, int character, int tag_first, ...) +{ + if (font == NULL) + return; + + if (normalcolor >= NumTextColors) + normalcolor = CR_UNTRANSLATED; + + FGameTexture* pic; + int dummy; + + if (NULL != (pic = font->GetChar(character, normalcolor, &dummy))) + { + DrawParms parms; + Va_List tags; + va_start(tags.list, tag_first); + bool res = ParseDrawTextureTags(drawer, pic, x, y, tag_first, tags, &parms, DrawTexture_Normal); + va_end(tags.list); + if (!res) + { + return; + } + bool palettetrans = (normalcolor == CR_NATIVEPAL && parms.TranslationId != NO_TRANSLATION); + PalEntry color = 0xffffffff; + if (!palettetrans) parms.TranslationId = font->GetColorTranslation((EColorRange)normalcolor, &color); + parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255); + drawer->AddTexture(pic, parms); + } +} + +void DrawChar(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args) +{ + if (font == NULL) + return; + + if (normalcolor >= NumTextColors) + normalcolor = CR_UNTRANSLATED; + + FGameTexture *pic; + int dummy; + + if (NULL != (pic = font->GetChar(character, normalcolor, &dummy))) + { + DrawParms parms; + uint32_t tag = ListGetInt(args); + bool res = ParseDrawTextureTags(drawer, pic, x, y, tag, args, &parms, DrawTexture_Normal); + if (!res) return; + bool palettetrans = (normalcolor == CR_NATIVEPAL && parms.TranslationId != NO_TRANSLATION); + PalEntry color = 0xffffffff; + if (!palettetrans) parms.TranslationId = font->GetColorTranslation((EColorRange)normalcolor, &color); + parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255); + drawer->AddTexture(pic, parms); + } +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawChar) +{ + PARAM_PROLOGUE; + PARAM_POINTER(font, FFont); + PARAM_INT(cr); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(chr); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo + 5 }; + DrawChar(twod, font, cr, x, y, chr, args); + return 0; +} + +DEFINE_ACTION_FUNCTION(FCanvas, DrawChar) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_POINTER(font, FFont); + PARAM_INT(cr); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(chr); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + VMVa_List args = { param + 6, 0, numparam - 7, va_reginfo + 6 }; + DrawChar(&self->Drawer, font, cr, x, y, chr, args); + self->Tex->NeedUpdate(); + return 0; +} + +//========================================================================== +// +// DrawText +// +// Write a string using the given font +// +//========================================================================== + +// This is only needed as a dummy. The code using wide strings does not need color control. +EColorRange V_ParseFontColor(const char32_t *&color_value, int normalcolor, int boldcolor) { return CR_UNTRANSLATED; } + +template +void DrawTextCommon(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double y, const chartype *string, DrawParms &parms) +{ + int w; + const chartype *ch; + int c; + double cx; + double cy; + int boldcolor; + FTranslationID trans = INVALID_TRANSLATION; + int kerning; + FGameTexture *pic; + + double scalex = parms.scalex * parms.patchscalex; + double scaley = parms.scaley * parms.patchscaley; + + if (parms.celly == 0) parms.celly = font->GetHeight() + 1; + parms.celly = int (parms.celly * scaley); + + bool palettetrans = (normalcolor == CR_NATIVEPAL && parms.TranslationId != NO_TRANSLATION); + + if (normalcolor >= NumTextColors) + normalcolor = CR_UNTRANSLATED; + boldcolor = normalcolor ? normalcolor - 1 : NumTextColors - 1; + + PalEntry colorparm = parms.color; + PalEntry color = 0xffffffff; + trans = palettetrans? INVALID_TRANSLATION : font->GetColorTranslation((EColorRange)normalcolor, &color); + parms.color = PalEntry(colorparm.a, (color.r * colorparm.r) / 255, (color.g * colorparm.g) / 255, (color.b * colorparm.b) / 255); + + kerning = font->GetDefaultKerning(); + + ch = string; + cx = x; + cy = y; + + if (parms.monospace == EMonospacing::CellCenter) + cx += parms.spacing / 2; + else if (parms.monospace == EMonospacing::CellRight) + cx += parms.spacing; + + + auto currentcolor = normalcolor; + while (ch - string < parms.maxstrlen) + { + c = GetCharFromString(ch); + if (!c) + break; + + if (c == TEXTCOLOR_ESCAPE) + { + EColorRange newcolor = V_ParseFontColor(ch, normalcolor, boldcolor); + if (newcolor != CR_UNDEFINED) + { + trans = font->GetColorTranslation(newcolor, &color); + parms.color = PalEntry(colorparm.a, (color.r * colorparm.r) / 255, (color.g * colorparm.g) / 255, (color.b * colorparm.b) / 255); + currentcolor = newcolor; + } + continue; + } + + if (c == '\n') + { + cx = x; + cy += parms.celly; + continue; + } + + if (NULL != (pic = font->GetChar(c, currentcolor, &w))) + { + // if palette translation is used, font colors will be ignored. + if (!palettetrans) parms.TranslationId = trans; + SetTextureParms(drawer, &parms, pic, cx, cy); + if (parms.cellx) + { + w = parms.cellx; + parms.destwidth = parms.cellx; + parms.destheight = parms.celly; + } + if (parms.monospace == EMonospacing::CellLeft) + parms.left = 0; + else if (parms.monospace == EMonospacing::CellCenter) + parms.left = w / 2.; + else if (parms.monospace == EMonospacing::CellRight) + parms.left = w; + + drawer->AddTexture(pic, parms); + } + if (parms.monospace == EMonospacing::Off) + { + cx += (w + kerning + parms.spacing) * scalex; + } + else + { + cx += (parms.spacing) * scalex; + } + + } +} + + +// For now the 'drawer' parameter is a placeholder - this should be the way to handle it later to allow different drawers. +void DrawText(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double y, const char* string, int tag_first, ...) +{ + Va_List tags; + DrawParms parms; + + if (font == NULL || string == NULL) + return; + + va_start(tags.list, tag_first); + bool res = ParseDrawTextureTags(drawer, nullptr, 0, 0, tag_first, tags, &parms, DrawTexture_Text); + va_end(tags.list); + if (!res) + { + return; + } + const char *txt = (parms.localize && string[0] == '$') ? GStrings.GetString(&string[1]) : string; + DrawTextCommon(drawer, font, normalcolor, x, y, (const uint8_t*)string, parms); +} + + +void DrawText(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double y, const char32_t* string, int tag_first, ...) +{ + Va_List tags; + DrawParms parms; + + if (font == NULL || string == NULL) + return; + + va_start(tags.list, tag_first); + bool res = ParseDrawTextureTags(drawer, nullptr, 0, 0, tag_first, tags, &parms, DrawTexture_Text); + va_end(tags.list); + if (!res) + { + return; + } + // [Gutawer] right now nothing needs the char32_t version to have localisation support, and i don't know how to do it + assert(parms.localize == false); + DrawTextCommon(drawer, font, normalcolor, x, y, string, parms); +} + + +void DrawText(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double y, const FString& string, VMVa_List &args) +{ + DrawParms parms; + + if (font == NULL) + return; + + uint32_t tag = ListGetInt(args); + bool res = ParseDrawTextureTags(drawer, nullptr, 0, 0, tag, args, &parms, DrawTexture_Text, ~0u, 0.0, true); + if (!res) + { + return; + } + const char *txt = (parms.localize && string[0] == '$') ? GStrings.GetString(&string[1]) : string.GetChars(); + DrawTextCommon(drawer, font, normalcolor, x, y, (uint8_t*)txt, parms); +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawText) +{ + PARAM_PROLOGUE; + PARAM_POINTER_NOT_NULL(font, FFont); + PARAM_INT(cr); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_STRING(chr); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo + 5 }; + DrawText(twod, font, cr, x, y, chr, args); + return 0; +} + + +DEFINE_ACTION_FUNCTION(FCanvas, DrawText) +{ + PARAM_SELF_PROLOGUE(FCanvas); + PARAM_POINTER_NOT_NULL(font, FFont); + PARAM_INT(cr); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_STRING(chr); + + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + VMVa_List args = { param + 6, 0, numparam - 7, va_reginfo + 6 }; + DrawText(&self->Drawer, font, cr, x, y, chr, args); + self->Tex->NeedUpdate(); + return 0; +} diff --git a/src/common/2d/wipe.cpp b/src/common/2d/wipe.cpp new file mode 100644 index 00000000000..cc57ca29f31 --- /dev/null +++ b/src/common/2d/wipe.cpp @@ -0,0 +1,460 @@ +/* +** wipe.cpp +** Screen wipe implementation +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "v_video.h" +#include "m_random.h" +#include "wipe.h" + +#include "bitmap.h" +#include "hw_material.h" +#include "v_draw.h" +#include "s_soundinternal.h" +#include "i_time.h" + +class FBurnTexture : public FTexture +{ + TArray WorkBuffer; +public: + FBurnTexture(int w, int h) + : WorkBuffer(w*h, true) + { + Width = w; + Height = h; + } + + FBitmap GetBgraBitmap(const PalEntry*, int *trans) override + { + FBitmap bmp; + bmp.Create(Width, Height); + bmp.CopyPixelDataRGB(0, 0, (uint8_t*)WorkBuffer.Data(), Width, Height, 4, Width*4, 0, CF_RGBA, nullptr); + if (trans) *trans = 0; + return bmp; + } + + uint32_t *GetBuffer() + { + return WorkBuffer.Data(); + } +}; + +int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density) +{ + // This is a modified version of the fire that was once used + // on the player setup menu. + static int voop; + + int a, b; + uint8_t *from; + + // generator + from = &burnarray[width * height]; + b = voop; + voop += density / 3; + for (a = 0; a < density/8; a++) + { + unsigned int offs = (a+b) & (width - 1); + unsigned int v = M_Random(); + v = min(from[offs] + 4 + (v & 15) + (v >> 3) + (M_Random() & 31), 255u); + from[offs] = from[width*2 + ((offs + width*3/2) & (width - 1))] = v; + } + + density = min(density + 10, width * 7); + + from = burnarray; + for (b = 0; b <= height; b += 2) + { + uint8_t *pixel = from; + + // special case: first pixel on line + uint8_t *p = pixel + (width << 1); + unsigned int top = *p + *(p + width - 1) + *(p + 1); + unsigned int bottom = *(pixel + (width << 2)); + unsigned int c1 = (top + bottom) >> 2; + if (c1 > 1) c1--; + *pixel = c1; + *(pixel + width) = (c1 + bottom) >> 1; + pixel++; + + // main line loop + for (a = 1; a < width-1; a++) + { + // sum top pixels + p = pixel + (width << 1); + top = *p + *(p - 1) + *(p + 1); + + // bottom pixel + bottom = *(pixel + (width << 2)); + + // combine pixels + c1 = (top + bottom) >> 2; + if (c1 > 1) c1--; + + // store pixels + *pixel = c1; + *(pixel + width) = (c1 + bottom) >> 1; // interpolate + + // next pixel + pixel++; + } + + // special case: last pixel on line + p = pixel + (width << 1); + top = *p + *(p - 1) + *(p - width + 1); + bottom = *(pixel + (width << 2)); + c1 = (top + bottom) >> 2; + if (c1 > 1) c1--; + *pixel = c1; + *(pixel + width) = (c1 + bottom) >> 1; + + // next line + from += width << 1; + } + + // Check for done-ness. (Every pixel with level 126 or higher counts as done.) + for (a = width * height, from = burnarray; a != 0; --a, ++from) + { + if (*from < 126) + { + return density; + } + } + return -1; +} + + +// TYPES ------------------------------------------------------------------- + +class Wiper +{ +protected: + FGameTexture* startScreen = nullptr, * endScreen = nullptr; +public: + virtual ~Wiper(); + virtual bool Run(int ticks) = 0; + virtual void SetTextures(FGameTexture* startscreen, FGameTexture* endscreen) + { + startScreen = startscreen; + endScreen = endscreen; + } + + static Wiper* Create(int type); +}; + + +class Wiper_Crossfade : public Wiper +{ +public: + bool Run(int ticks) override; + +private: + int Clock = 0; +}; + +class Wiper_Melt : public Wiper +{ +public: + Wiper_Melt(); + bool Run(int ticks) override; + +private: + enum { WIDTH = 320, HEIGHT = 200 }; + int y[WIDTH]; +}; + +class Wiper_Burn : public Wiper +{ +public: + ~Wiper_Burn(); + bool Run(int ticks) override; + void SetTextures(FGameTexture *startscreen, FGameTexture *endscreen) override; + +private: + static const int WIDTH = 64, HEIGHT = 64; + uint8_t BurnArray[WIDTH * (HEIGHT + 5)] = {0}; + FBurnTexture *BurnTexture = nullptr; + int Density = 4; + int BurnTime = 8; +}; + +//=========================================================================== +// +// Screen wipes +// +//=========================================================================== + +Wiper *Wiper::Create(int type) +{ + switch(type) + { + case wipe_Burn: + return new Wiper_Burn; + + case wipe_Fade: + return new Wiper_Crossfade; + + case wipe_Melt: + return new Wiper_Melt; + + default: + return nullptr; + } +} + + + + +//========================================================================== +// +// OpenGLFrameBuffer :: WipeCleanup +// +// Release any resources that were specifically created for the wipe. +// +//========================================================================== + +Wiper::~Wiper() +{ + if (startScreen != nullptr) delete startScreen; + if (endScreen != nullptr) delete endScreen; +} + +//========================================================================== +// +// WIPE: CROSSFADE --------------------------------------------------------- +// +//========================================================================== + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Crossfade :: Run +// +// Fades the old screen into the new one over 32 ticks. +// +//========================================================================== + +bool Wiper_Crossfade::Run(int ticks) +{ + Clock += ticks; + DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); + DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); + return Clock >= 32; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Melt Constructor +// +//========================================================================== + +Wiper_Melt::Wiper_Melt() +{ + y[0] = -(M_Random() & 15); + for (int i = 1; i < WIDTH; ++i) + { + y[i] = clamp(y[i-1] + (M_Random() % 3) - 1, -15, 0); + } +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Melt :: Run +// +// Melts the old screen into the new one over 32 ticks. +// +//========================================================================== + +bool Wiper_Melt::Run(int ticks) +{ + bool done = false; + DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); + + // Copy the old screen in vertical strips on top of the new one. + while (ticks--) + { + done = true; + for (int i = 0; i < WIDTH; i++) + { + if (y[i] < HEIGHT) + { + if (y[i] < 0) + y[i]++; + else if (y[i] < 16) + y[i] += y[i] + 1; + else + y[i] = min(y[i] + 8, HEIGHT); + done = false; + } + if (ticks == 0) + { + struct { + int32_t x; + int32_t y; + } dpt; + struct { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; + } rect; + + // Only draw for the final tick. + + int w = startScreen->GetTexelWidth(); + int h = startScreen->GetTexelHeight(); + dpt.x = i * w / WIDTH; + dpt.y = max(0, y[i] * h / HEIGHT); + rect.left = dpt.x; + rect.top = 0; + rect.right = (i + 1) * w / WIDTH; + rect.bottom = h - dpt.y; + if (rect.bottom > rect.top) + { + DrawTexture(twod, startScreen, 0, dpt.y, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, DTA_Masked, false, TAG_DONE); + } + } + } + } + return done; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Burn Constructor +// +//========================================================================== + +void Wiper_Burn::SetTextures(FGameTexture *startscreen, FGameTexture *endscreen) +{ + startScreen = startscreen; + endScreen = endscreen; + BurnTexture = new FBurnTexture(WIDTH, HEIGHT); + auto mat = FMaterial::ValidateTexture(endScreen, false); + mat->ClearLayers(); + mat->AddTextureLayer(BurnTexture, false); +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Burn Destructor +// +//========================================================================== + +Wiper_Burn::~Wiper_Burn() +{ + if (BurnTexture != nullptr) delete BurnTexture; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Burn :: Run +// +//========================================================================== + +bool Wiper_Burn::Run(int ticks) +{ + bool done = false; + + + BurnTime += ticks; + ticks *= 2; + + // Make the fire burn + while (!done && ticks--) + { + Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); + done = (Density < 0); + } + + BurnTexture->CleanHardwareTextures(); + endScreen->CleanHardwareData(false); // this only cleans the descriptor sets for the Vulkan backend. We do not want to delete the wipe screen's hardware texture here. + + const uint8_t *src = BurnArray; + uint32_t *dest = (uint32_t *)BurnTexture->GetBuffer(); + for (int y = HEIGHT; y != 0; --y) + { + for (int x = WIDTH; x != 0; --x) + { + uint8_t s = clamp((*src++)*2, 0, 255); + *dest++ = MAKEARGB(s,255,255,255); + } + } + + DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); + DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Burn, true, DTA_Masked, false, TAG_DONE); + + // The fire may not always stabilize, so the wipe is forced to end + // after an arbitrary maximum time. + return done || (BurnTime > 40); +} + + +void PerformWipe(FTexture* startimg, FTexture* endimg, int wipe_type, bool stopsound, std::function overlaydrawer) +{ + // wipe update + uint64_t wipestart, nowtime, diff; + bool done; + + GSnd->SetSfxPaused(true, 1); + I_FreezeTime(true); + twod->End(); + assert(startimg != nullptr && endimg != nullptr); + auto starttex = MakeGameTexture(startimg, nullptr, ETextureType::SWCanvas); + auto endtex = MakeGameTexture(endimg, nullptr, ETextureType::SWCanvas); + auto wiper = Wiper::Create(wipe_type); + wiper->SetTextures(starttex, endtex); + + wipestart = I_msTime(); + + do + { + do + { + I_WaitVBL(2); + nowtime = I_msTime(); + diff = (nowtime - wipestart) * 40 / 1000; // Using 35 here feels too slow. + } while (diff < 1); + wipestart = nowtime; + twod->Begin(screen->GetWidth(), screen->GetHeight()); + done = wiper->Run(1); + if (overlaydrawer) overlaydrawer(); + twod->End(); + screen->Update(); + twod->OnFrameDone(); + + } while (!done); + delete wiper; + I_FreezeTime(false); + GSnd->SetSfxPaused(false, 1); + +} diff --git a/src/common/2d/wipe.h b/src/common/2d/wipe.h new file mode 100644 index 00000000000..08a7eeb3bd9 --- /dev/null +++ b/src/common/2d/wipe.h @@ -0,0 +1,21 @@ +#ifndef __F_WIPE_H__ +#define __F_WIPE_H__ + +#include "stdint.h" +#include + +class FTexture; + +enum +{ + wipe_None, // don't bother + wipe_Melt, // weird screen melt + wipe_Burn, // fade in shape of fire + wipe_Fade, // crossfade from old to new + wipe_NUMWIPES +}; + +void PerformWipe(FTexture* startimg, FTexture* endimg, int wipe_type, bool stopsound, std::function overlaydrawer); + + +#endif diff --git a/src/sound/music/i_music.cpp b/src/common/audio/music/i_music.cpp similarity index 87% rename from src/sound/music/i_music.cpp rename to src/common/audio/music/i_music.cpp index b171321d7d8..d190537d45a 100644 --- a/src/sound/music/i_music.cpp +++ b/src/common/audio/music/i_music.cpp @@ -37,33 +37,30 @@ #include #endif -#include +#include #include -#include "m_argv.h" -#include "w_wad.h" +#include "filesystem.h" #include "c_dispatch.h" -#include "templates.h" + #include "stats.h" +#include "cmdlib.h" #include "c_cvars.h" #include "c_console.h" -#include "vm.h" #include "v_text.h" #include "i_sound.h" #include "i_soundfont.h" #include "s_music.h" -#include "doomstat.h" #include "filereadermusicinterface.h" +using namespace FileSys; void I_InitSoundFonts(); EXTERN_CVAR (Int, snd_samplerate) EXTERN_CVAR (Int, snd_mididevice) - -static bool ungzip(uint8_t *data, int size, std::vector &newdata); - +EXTERN_CVAR(Float, snd_mastervolume) int nomusic = 0; //========================================================================== @@ -73,7 +70,7 @@ int nomusic = 0; // Maximum volume of MOD/stream music. //========================================================================== -CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVARD(Float, snd_musicvolume, 0.5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG, "controls music volume") { if (self < 0.f) self = 0.f; @@ -100,6 +97,12 @@ CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } +CUSTOM_CVARD(Bool, mus_enabled, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG, "enables/disables music") +{ + if (self) S_RestartMusic(); + else S_StopMusic(true); +} + //========================================================================== // // Callbacks for the music system. @@ -159,7 +162,7 @@ static void mus_sfclose(void* handle) reinterpret_cast(handle)->close(); } - +#ifndef ZMUSIC_LITE //========================================================================== // // Pass some basic working data to the music backend @@ -171,42 +174,42 @@ static void SetupGenMidi() { // The OPL renderer should not care about where this comes from. // Note: No I_Error here - this needs to be consistent with the rest of the music code. - auto lump = Wads.CheckNumForName("GENMIDI", ns_global); + auto lump = fileSystem.CheckNumForName("GENMIDI", ns_global); if (lump < 0) { Printf("No GENMIDI lump found. OPL playback not available.\n"); return; } - auto data = Wads.OpenLumpReader(lump); + auto genmidi = fileSystem.ReadFile(lump); - auto genmidi = data.Read(); - if (genmidi.Size() < 8 + 175 * 36 || memcmp(genmidi.Data(), "#OPL_II#", 8)) return; - ZMusic_SetGenMidi(genmidi.Data()+8); + if (genmidi.size() < 8 + 175 * 36 || memcmp(genmidi.data(), "#OPL_II#", 8)) return; + ZMusic_SetGenMidi(genmidi.bytes() + 8); } static void SetupWgOpn() { - int lump = Wads.CheckNumForFullName("xg.wopn"); + int lump = fileSystem.CheckNumForFullName("xg.wopn"); if (lump < 0) { return; } - FMemLump data = Wads.ReadLump(lump); - ZMusic_SetWgOpn(data.GetMem(), (uint32_t)data.GetSize()); + auto data = fileSystem.ReadFile(lump); + ZMusic_SetWgOpn(data.data(), (uint32_t)data.size()); } static void SetupDMXGUS() { - int lump = Wads.CheckNumForFullName("DMXGUS"); + int lump = fileSystem.CheckNumForName("DMXGUSC", ns_global); + if (lump < 0) lump = fileSystem.CheckNumForName("DMXGUS", ns_global); if (lump < 0) { return; } - FMemLump data = Wads.ReadLump(lump); - ZMusic_SetDmxGus(data.GetMem(), (uint32_t)data.GetSize()); + auto data = fileSystem.ReadFile(lump); + ZMusic_SetDmxGus(data.data(), (uint32_t)data.size()); } - +#endif //========================================================================== // @@ -214,16 +217,16 @@ static void SetupDMXGUS() // //========================================================================== -void I_InitMusic (void) +void I_InitMusic(int musicstate) { I_InitSoundFonts(); - snd_musicvolume.Callback (); + snd_musicvolume->Callback (); + + nomusic = musicstate; - nomusic = !!Args->CheckParm("-nomusic") || !!Args->CheckParm("-nosound"); + snd_mididevice->Callback(); - snd_mididevice.Callback(); - ZMusicCallbacks callbacks{}; callbacks.MessageFunc = zmusic_printfunc; @@ -235,9 +238,11 @@ void I_InitMusic (void) callbacks.SF_Close = mus_sfclose; ZMusic_SetCallbacks(&callbacks); +#ifndef ZMUSIC_LITE SetupGenMidi(); SetupDMXGUS(); SetupWgOpn(); +#endif } @@ -251,7 +256,7 @@ void I_SetRelativeVolume(float vol) { relative_volume = (float)vol; ChangeMusicSetting(zmusic_relative_volume, nullptr, (float)vol); - snd_musicvolume.Callback(); + snd_musicvolume->Callback(); } //========================================================================== // @@ -307,15 +312,15 @@ static ZMusic_MidiSource GetMIDISource(const char *fn) FString src = fn; if (src.Compare("*") == 0) src = mus_playing.name; - auto lump = Wads.CheckNumForName(src, ns_music); - if (lump < 0) lump = Wads.CheckNumForFullName(src); + auto lump = fileSystem.CheckNumForName(src.GetChars(), ns_music); + if (lump < 0) lump = fileSystem.CheckNumForFullName(src.GetChars()); if (lump < 0) { Printf("Cannot find MIDI lump %s.\n", src.GetChars()); return nullptr; } - auto wlump = Wads.OpenLumpReader(lump); + auto wlump = fileSystem.OpenFileReader(lump); uint32_t id[32 / 4]; @@ -332,7 +337,7 @@ static ZMusic_MidiSource GetMIDISource(const char *fn) } auto data = wlump.Read(); - auto source = ZMusic_CreateMIDISource(data.Data(), data.Size(), type); + auto source = ZMusic_CreateMIDISource(data.bytes(), data.size(), type); if (source == nullptr) { @@ -360,7 +365,7 @@ UNSAFE_CCMD (writewave) if (source == nullptr) return; EMidiDevice dev = MDEV_DEFAULT; - +#ifndef ZMUSIC_LITE if (argv.argc() >= 6) { if (!stricmp(argv[5], "WildMidi")) dev = MDEV_WILDMIDI; @@ -376,6 +381,7 @@ UNSAFE_CCMD (writewave) return; } } +#endif // We must stop the currently playing music to avoid interference between two synths. auto savedsong = mus_playing; S_StopMusic(true); @@ -385,7 +391,7 @@ UNSAFE_CCMD (writewave) Printf("MIDI dump of %s failed: %s\n",argv[1], ZMusic_GetLastError()); } - S_ChangeMusic(savedsong.name, savedsong.baseorder, savedsong.loop, true); + S_ChangeMusic(savedsong.name.GetChars(), savedsong.baseorder, savedsong.loop, true); } else { diff --git a/src/sound/music/i_music.h b/src/common/audio/music/i_music.h similarity index 90% rename from src/sound/music/i_music.h rename to src/common/audio/music/i_music.h index af45ec1fea6..aa2d48e628f 100644 --- a/src/sound/music/i_music.h +++ b/src/common/audio/music/i_music.h @@ -34,20 +34,25 @@ #ifndef __I_MUSIC_H__ #define __I_MUSIC_H__ -class FileReader; -struct FOptionValues; - // // MUSIC I/O // -void I_InitMusic (); -void I_BuildMIDIMenuList (FOptionValues *); +void I_InitMusic (int); // Volume. void I_SetRelativeVolume(float); void I_SetMusicVolume (double volume); -extern int nomusic; + +inline float AmplitudeTodB(float amplitude) +{ + return 20.0f * log10f(amplitude); +} + +inline float dBToAmplitude(float dB) +{ + return powf(10.0f, dB / 20.0f); +} #endif //__I_MUSIC_H__ diff --git a/src/sound/music/i_soundfont.cpp b/src/common/audio/music/i_soundfont.cpp similarity index 82% rename from src/sound/music/i_soundfont.cpp rename to src/common/audio/music/i_soundfont.cpp index 400f92cb6c4..9737374fc47 100644 --- a/src/sound/music/i_soundfont.cpp +++ b/src/common/audio/music/i_soundfont.cpp @@ -38,11 +38,14 @@ #include "i_soundinternal.h" #include "cmdlib.h" #include "i_system.h" -#include "gameconfigfile.h" #include "filereadermusicinterface.h" #include -#include "resourcefiles/resourcefile.h" +#include "fs_filesystem.h" #include "version.h" +#include "fs_findfile.h" +#include "i_interface.h" +#include "configfile.h" +#include "printf.h" //========================================================================== // @@ -65,7 +68,7 @@ std::pair FSoundFontReader::LookupFile(const char *name) for(int i = mPaths.Size()-1; i>=0; i--) { FString fullname = mPaths[i] + name; - auto fr = OpenFile(fullname); + auto fr = OpenFile(fullname.GetChars()); if (fr.isOpen()) return std::make_pair(std::move(fr), fullname); } } @@ -90,7 +93,7 @@ void FSoundFontReader::AddPath(const char *strp) if (str.Back() != '/') str += '/'; // always let it end with a slash. for (auto &s : mPaths) { - if (pathcmp(s.GetChars(), str) == 0) + if (pathcmp(s.GetChars(), str.GetChars()) == 0) { // move string to the back. mPaths.Delete(i); @@ -119,13 +122,13 @@ FileReader FSoundFontReader::Open(const char *name, std::string& filename) if (name == nullptr) { fr = OpenMainConfigFile(); - filename = MainConfigFileName(); + filename = MainConfigFileName().GetChars(); } else { auto res = LookupFile(name); fr = std::move(res.first); - filename = res.second; + filename = res.second.GetChars(); } return fr; } @@ -139,7 +142,7 @@ FileReader FSoundFontReader::Open(const char *name, std::string& filename) ZMusicCustomReader* FSoundFontReader::open_interface(const char* name) { std::string filename; - + FileReader fr = Open(name, filename); if (!fr.isOpen()) return nullptr; auto fri = GetMusicReader(fr); @@ -193,7 +196,8 @@ FileReader FSF2Reader::OpenFile(const char *name) FZipPatReader::FZipPatReader(const char *filename) { - resf = FResourceFile::OpenResourceFile(filename, true); + mAllowAbsolutePaths = true; + resf = FResourceFile::OpenResourceFile(filename); } FZipPatReader::~FZipPatReader() @@ -211,12 +215,13 @@ FileReader FZipPatReader::OpenFile(const char *name) FileReader fr; if (resf != nullptr) { - auto lump = resf->FindLump(name); - if (lump != nullptr) + auto lump = resf->FindEntry(name); + if (lump >= 0) { - return lump->NewReader(); + return resf->GetEntryReader(lump, FileSys::READER_NEW, FileSys::READERFLAG_SEEKABLE); } } + fr.OpenFile(name); return fr; } @@ -239,7 +244,7 @@ FPatchSetReader::FPatchSetReader(const char *filename) const char *paths[] = { "C:/TIMIDITY", "/TIMIDITY", - progdir + progdir.GetChars() }; #endif mAllowAbsolutePaths = true; @@ -253,7 +258,7 @@ FPatchSetReader::FPatchSetReader(const char *filename) for(auto c : paths) { FStringf fullname("%s/%s", c, filename); - if (fr.OpenFile(fullname)) + if (fr.OpenFile(fullname.GetChars())) { mFullPathToConfig = fullname; } @@ -262,7 +267,7 @@ FPatchSetReader::FPatchSetReader(const char *filename) if (mFullPathToConfig.Len() > 0) { FixPathSeperator(mFullPathToConfig); - mBasePath = ExtractFilePath(mFullPathToConfig); + mBasePath = ExtractFilePath(mFullPathToConfig.GetChars()); if (mBasePath.Len() > 0 && mBasePath.Back() != '/') mBasePath += '/'; } } @@ -271,7 +276,7 @@ FPatchSetReader::FPatchSetReader(const char *filename) FileReader FPatchSetReader::OpenMainConfigFile() { FileReader fr; - fr.OpenFile(mFullPathToConfig); + fr.OpenFile(mFullPathToConfig.GetChars()); return fr; } @@ -281,7 +286,7 @@ FileReader FPatchSetReader::OpenFile(const char *name) if (IsAbsPath(name)) path = name; else path = mBasePath + name; FileReader fr; - fr.OpenFile(path); + fr.OpenFile(path.GetChars()); return fr; } @@ -293,17 +298,17 @@ FileReader FPatchSetReader::OpenFile(const char *name) FLumpPatchSetReader::FLumpPatchSetReader(const char *filename) { - mLumpIndex = Wads.CheckNumForFullName(filename); + mLumpIndex = fileSystem.CheckNumForFullName(filename); mBasePath = filename; FixPathSeperator(mBasePath); - mBasePath = ExtractFilePath(mBasePath); + mBasePath = ExtractFilePath(mBasePath.GetChars()); if (mBasePath.Len() > 0 && mBasePath.Back() != '/') mBasePath += '/'; } FileReader FLumpPatchSetReader::OpenMainConfigFile() { - return Wads.ReopenLumpReader(mLumpIndex); + return fileSystem.ReopenFileReader(mLumpIndex); } FileReader FLumpPatchSetReader::OpenFile(const char *name) @@ -311,9 +316,9 @@ FileReader FLumpPatchSetReader::OpenFile(const char *name) FString path; if (IsAbsPath(name)) return FileReader(); // no absolute paths in the lump directory. path = mBasePath + name; - auto index = Wads.CheckNumForFullName(path); + auto index = fileSystem.CheckNumForFullName(path.GetChars()); if (index < 0) return FileReader(); - return Wads.ReopenLumpReader(index); + return fileSystem.ReopenFileReader(index); } //========================================================================== @@ -326,7 +331,7 @@ FileReader FLumpPatchSetReader::OpenFile(const char *name) // //========================================================================== -void FSoundFontManager::ProcessOneFile(const FString &fn) +void FSoundFontManager::ProcessOneFile(const char* fn) { auto fb = ExtractFileBase(fn, false); auto fbe = ExtractFileBase(fn, true); @@ -335,7 +340,7 @@ void FSoundFontManager::ProcessOneFile(const FString &fn) // We already got a soundfont with this name. Do not add again. if (!sfi.mName.CompareNoCase(fb)) return; } - + FileReader fr; if (fr.OpenFile(fn)) { @@ -362,10 +367,10 @@ void FSoundFontManager::ProcessOneFile(const FString &fn) auto zip = FResourceFile::OpenResourceFile(fn, true); if (zip != nullptr) { - if (zip->LumpCount() > 1) // Anything with just one lump cannot possibly be a packed GUS patch set so skip it right away and simplify the lookup code + if (zip->EntryCount() > 1) // Anything with just one lump cannot possibly be a packed GUS patch set so skip it right away and simplify the lookup code { - auto zipl = zip->FindLump("timidity.cfg"); - if (zipl != nullptr) + auto zipl = zip->FindEntry("timidity.cfg"); + if (zipl >= 0) { // It seems like this is what we are looking for FSoundFontInfo sft = { fb, fbe, fn, SF_GUS }; @@ -386,9 +391,7 @@ void FSoundFontManager::ProcessOneFile(const FString &fn) void FSoundFontManager::CollectSoundfonts() { - findstate_t c_file; - void *file; - + FConfigFile* GameConfig = sysCallbacks.GetConfig ? sysCallbacks.GetConfig() : nullptr; if (GameConfig != NULL && GameConfig->SetSection ("SoundfontSearch.Directories")) { const char *key; @@ -398,25 +401,23 @@ void FSoundFontManager::CollectSoundfonts() { if (stricmp (key, "Path") == 0) { + FileSys::FileList list; + FString dir; dir = NicePath(value); FixPathSeperator(dir); if (dir.IsNotEmpty()) { - if (dir.Back() != '/') dir += '/'; - FString mask = dir + '*'; - if ((file = I_FindFirst(mask, &c_file)) != ((void *)(-1))) + if (FileSys::ScanDirectory(list, dir.GetChars(), "*", true)) { - do + for(auto& entry : list) { - if (!(I_FindAttr(&c_file) & FA_DIREC)) + if (!entry.isDirectory) { - FStringf name("%s%s", dir.GetChars(), I_FindName(&c_file)); - ProcessOneFile(name); + ProcessOneFile(entry.FilePath.c_str()); } - } while (I_FindNext(file, &c_file) == 0); - I_FindClose(file); + } } } } @@ -425,7 +426,7 @@ void FSoundFontManager::CollectSoundfonts() if (soundfonts.Size() == 0) { - ProcessOneFile(NicePath("$PROGDIR/soundfonts/" GAMENAMELOWERCASE ".sf2")); + ProcessOneFile(NicePath("$PROGDIR/soundfonts/" GAMENAMELOWERCASE ".sf2").GetChars()); } } @@ -442,6 +443,7 @@ const FSoundFontInfo *FSoundFontManager::FindSoundFont(const char *name, int all // an empty name will pick the first one in a compatible format. if (allowed & sfi.type && (name == nullptr || *name == 0 || !sfi.mName.CompareNoCase(name) || !sfi.mNameExt.CompareNoCase(name))) { + DPrintf(DMSG_NOTIFY, "Found compatible soundfont %s\n", sfi.mNameExt.GetChars()); return &sfi; } } @@ -450,6 +452,7 @@ const FSoundFontInfo *FSoundFontManager::FindSoundFont(const char *name, int all { if (allowed & sfi.type) { + DPrintf(DMSG_NOTIFY, "Unable to find %s soundfont. Falling back to %s\n", name, sfi.mNameExt.GetChars()); return &sfi; } } @@ -462,28 +465,18 @@ const FSoundFontInfo *FSoundFontManager::FindSoundFont(const char *name, int all // //========================================================================== -FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *name, int allowed) +FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *const name, int allowed) { - + if (name == nullptr) return nullptr; // First check if the given name is inside the loaded resources. // To avoid clashes this will only be done if the name has the '.cfg' extension. // Sound fonts cannot be loaded this way. - if (name != nullptr) + const char *p = name + strlen(name) - 4; + if (p > name && !stricmp(p, ".cfg") && fileSystem.CheckNumForFullName(name) >= 0) { - const char *p = name + strlen(name) - 4; - if (p > name && !stricmp(p, ".cfg") && Wads.CheckNumForFullName(name) >= 0) - { - return new FLumpPatchSetReader(name); - } + return new FLumpPatchSetReader(name); } - auto sfi = FindSoundFont(name, allowed); - if (sfi != nullptr) - { - if (sfi->type == SF_SF2) return new FSF2Reader(sfi->mFilename); - else return new FZipPatReader(sfi->mFilename); - } - // The sound font collection did not yield any good results. // Next check if the file is a .sf file if (allowed & SF_SF2) { @@ -499,6 +492,7 @@ FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *name, int allowed } } } + // Next check if the file is a resource file (it should contains gus patches and a timidity.cfg file) if (allowed & SF_GUS) { FileReader fr; @@ -522,6 +516,13 @@ FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *name, int allowed return new FPatchSetReader(name); } } + // Lastly check in the sound font collection for a specific item or pick the first valid item available. + auto sfi = FindSoundFont(name, allowed); + if (sfi != nullptr) + { + if (sfi->type == SF_SF2) return new FSF2Reader(sfi->mFilename.GetChars()); + else return new FZipPatReader(sfi->mFilename.GetChars()); + } return nullptr; } diff --git a/src/sound/music/i_soundfont.h b/src/common/audio/music/i_soundfont.h similarity index 96% rename from src/sound/music/i_soundfont.h rename to src/common/audio/music/i_soundfont.h index 3ccdf827002..45e5b0ffa86 100644 --- a/src/sound/music/i_soundfont.h +++ b/src/common/audio/music/i_soundfont.h @@ -1,8 +1,8 @@ #pragma once -#include -#include "doomtype.h" -#include "w_wad.h" +#include "zstring.h" +#include "tarray.h" +#include "filesystem.h" #include "files.h" #include "filereadermusicinterface.h" @@ -29,13 +29,13 @@ class FSoundFontReader // When reading from an archive it will always be case insensitive, just like the lump manager. bool mCaseSensitivePaths = false; TArray mPaths; - - + + int pathcmp(const char *p1, const char *p2); - - + + public: - + virtual ~FSoundFontReader() {} virtual FileReader OpenMainConfigFile() = 0; // this is special because it needs to be synthesized for .sf files and set some restrictions for patch sets virtual FString MainConfigFileName() @@ -147,15 +147,15 @@ class FPatchSetReader : public FSoundFontReader class FSoundFontManager { TArray soundfonts; - - void ProcessOneFile(const FString & fn); - + + void ProcessOneFile(const char* fn); + public: void CollectSoundfonts(); const FSoundFontInfo *FindSoundFont(const char *name, int allowedtypes) const; FSoundFontReader *OpenSoundFont(const char *name, int allowedtypes); const auto &GetList() const { return soundfonts; } // This is for the menu - + }; diff --git a/src/common/audio/music/music.cpp b/src/common/audio/music/music.cpp new file mode 100644 index 00000000000..13837e93e71 --- /dev/null +++ b/src/common/audio/music/music.cpp @@ -0,0 +1,1068 @@ +/* +** +** music.cpp +** +** music engine +** +** Copyright 1999-2016 Randy Heit +** Copyright 2002-2016 Christoph Oelckers +** +**--------------------------------------------------------------------------- +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include + +#include "i_sound.h" +#include "i_music.h" +#include "printf.h" +#include "s_playlist.h" +#include "c_dispatch.h" +#include "filesystem.h" +#include "cmdlib.h" +#include "s_music.h" +#include "filereadermusicinterface.h" +#include +#include "md5.h" +#include "gain_analysis.h" +#include "i_specialpaths.h" +#include "configfile.h" +#include "c_cvars.h" +#include "md5.h" + + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +extern int nomusic; +extern float S_GetMusicVolume (const char *music); + +static void S_ActivatePlayList(bool goBack); + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static bool MusicPaused; // whether music is paused +MusPlayingInfo mus_playing; // music currently being played +static FPlayList PlayList; +float relative_volume = 1.f; +float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function +MusicVolumeMap MusicVolumes; +MidiDeviceMap MidiDevices; + +static int DefaultFindMusic(const char* fn) +{ + return -1; +} + +MusicCallbacks mus_cb = { nullptr, DefaultFindMusic }; + + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- +EXTERN_CVAR(Bool, mus_enabled) +EXTERN_CVAR(Float, snd_musicvolume) +EXTERN_CVAR(Int, snd_mididevice) +EXTERN_CVAR(Float, mod_dumb_mastervolume) +EXTERN_CVAR(Float, fluid_gain) + + +CVAR(Bool, mus_calcgain, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song. +CVAR(Bool, mus_usereplaygain, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song. + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// OpenMusic +// +// opens a FileReader for the music - used as a callback to keep +// implementation details out of the core player. +// +//========================================================================== + +static FileReader OpenMusic(const char* musicname) +{ + FileReader reader; + if (!FileExists(musicname)) + { + int lumpnum; + lumpnum = mus_cb.FindMusic(musicname); + if (lumpnum == -1) lumpnum = fileSystem.CheckNumForName(musicname, FileSys::ns_music); + if (lumpnum == -1) + { + Printf("Music \"%s\" not found\n", musicname); + } + else if (fileSystem.FileLength(lumpnum) != 0) + { + reader = fileSystem.ReopenFileReader(lumpnum); + } + } + else + { + // Load an external file. + reader.OpenFile(musicname); + } + return reader; +} + +void S_SetMusicCallbacks(MusicCallbacks* cb) +{ + mus_cb = *cb; + if (mus_cb.FindMusic == nullptr) mus_cb.FindMusic = DefaultFindMusic; // without this we are dead in the water. +} + +int MusicEnabled() // int return is for scripting +{ + return mus_enabled && !nomusic; +} + +//========================================================================== +// +// +// +// Create a sound system stream for the currently playing song +//========================================================================== + +static std::unique_ptr musicStream; +static TArray customStreams; + +SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, MusicCustomStreamType sampletype, StreamCallback cb, void *userdata) +{ + int flags = 0; + if (numchannels < 2) flags |= SoundStream::Mono; + if (sampletype == MusicSamplesFloat) flags |= SoundStream::Float; + auto stream = GSnd->CreateStream(cb, int(size), flags, samplerate, userdata); + if (stream) + { + stream->Play(true, 1); + customStreams.Push(stream); + } + return stream; +} + +void S_StopCustomStream(SoundStream *stream) +{ + if (stream) + { + stream->Stop(); + auto f = customStreams.Find(stream); + if (f < customStreams.Size()) customStreams.Delete(f); + delete stream; + } +} + +void S_PauseAllCustomStreams(bool on) +{ + static bool paused = false; + + if (paused == on) return; + paused = on; + for (auto s : customStreams) + { + s->SetPaused(on); + } +} + +static TArray convert; +static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata) +{ + bool written; + if (mus_playing.isfloat) + { + written = ZMusic_FillStream(mus_playing.handle, buff, len); + if (mus_playing.musicVolume != 1.f) + { + float* fbuf = (float*)buff; + for (int i = 0; i < len / 4; i++) + { + fbuf[i] *= mus_playing.musicVolume; + } + } + } + else + { + // To apply replay gain we need floating point streaming data, so 16 bit input needs to be converted here. + convert.Resize(len / 2); + written = ZMusic_FillStream(mus_playing.handle, convert.Data(), len/2); + float* fbuf = (float*)buff; + for (int i = 0; i < len / 4; i++) + { + fbuf[i] = convert[i] * mus_playing.musicVolume * (1.f/32768.f); + } + } + + if (!written) + { + memset((char*)buff, 0, len); + return false; + } + return true; +} + + +void S_CreateStream() +{ + if (!mus_playing.handle) return; + SoundStreamInfo fmt; + ZMusic_GetStreamInfo(mus_playing.handle, &fmt); + // always create a floating point streaming buffer so we can apply replay gain without risk of integer overflows. + mus_playing.isfloat = fmt.mNumChannels > 0; + if (!mus_playing.isfloat) fmt.mBufferSize *= 2; + if (fmt.mBufferSize > 0) // if buffer size is 0 the library will play the song itself (e.g. Windows system synth.) + { + int flags = SoundStream::Float; + if (abs(fmt.mNumChannels) < 2) flags |= SoundStream::Mono; + + musicStream.reset(GSnd->CreateStream(FillStream, fmt.mBufferSize, flags, fmt.mSampleRate, nullptr)); + if (musicStream) musicStream->Play(true, 1); + } +} + + +void S_PauseStream(bool paused) +{ + if (musicStream) musicStream->SetPaused(paused); +} + +void S_StopStream() +{ + if (musicStream) + { + musicStream->Stop(); + musicStream.reset(); + } +} + + +//========================================================================== +// +// starts playing this song +// +//========================================================================== + +static bool S_StartMusicPlaying(ZMusic_MusicStream song, bool loop, float rel_vol, int subsong) +{ + if (rel_vol > 0.f && !mus_usereplaygain) + { + float factor = relative_volume / saved_relative_volume; + saved_relative_volume = rel_vol; + I_SetRelativeVolume(saved_relative_volume * factor); + } + ZMusic_Stop(song); + // make sure the volume modifiers update properly in case replay gain settings have changed. + fluid_gain->Callback(); + mod_dumb_mastervolume->Callback(); + if (!ZMusic_Start(song, subsong, loop)) + { + return false; + } + + // Notify the sound system of the changed relative volume + snd_musicvolume->Callback(); + return true; +} + + +//========================================================================== +// +// S_PauseMusic +// +// Stop music, during game PAUSE. +//========================================================================== + +void S_PauseMusic () +{ + if (mus_playing.handle && !MusicPaused) + { + ZMusic_Pause(mus_playing.handle); + S_PauseStream(true); + MusicPaused = true; + } +} + +//========================================================================== +// +// S_ResumeMusic +// +// Resume music, after game PAUSE. +//========================================================================== + +void S_ResumeMusic () +{ + if (mus_playing.handle && MusicPaused) + { + ZMusic_Resume(mus_playing.handle); + S_PauseStream(false); + MusicPaused = false; + } +} + +//========================================================================== +// +// S_UpdateSound +// +//========================================================================== + +void S_UpdateMusic () +{ + if (mus_playing.handle != nullptr) + { + ZMusic_Update(mus_playing.handle); + + // [RH] Update music and/or playlist. IsPlaying() must be called + // to attempt to reconnect to broken net streams and to advance the + // playlist when the current song finishes. + if (!ZMusic_IsPlaying(mus_playing.handle)) + { + if (PlayList.GetNumSongs()) + { + PlayList.Advance(); + S_ActivatePlayList(false); + } + else + { + S_StopMusic(true); + } + } + } +} + +//========================================================================== +// +// Resets the music player if music playback was paused. +// +//========================================================================== + +void S_ResetMusic () +{ + // stop the old music if it has been paused. + // This ensures that the new music is started from the beginning + // if it's the same as the last one and it has been paused. + if (MusicPaused) S_StopMusic(true); + + // start new music for the level + MusicPaused = false; +} + + +//========================================================================== +// +// S_ActivatePlayList +// +// Plays the next song in the playlist. If no songs in the playlist can be +// played, then it is deleted. +//========================================================================== + +void S_ActivatePlayList (bool goBack) +{ + int startpos, pos; + + startpos = pos = PlayList.GetPosition (); + S_StopMusic (true); + while (!S_ChangeMusic (PlayList.GetSong (pos), 0, false, true)) + { + pos = goBack ? PlayList.Backup () : PlayList.Advance (); + if (pos == startpos) + { + PlayList.Clear(); + Printf ("Cannot play anything in the playlist.\n"); + return; + } + } +} + +//========================================================================== +// +// S_StartMusic +// +// Starts some music with the given name. +//========================================================================== + +bool S_StartMusic (const char *m_id) +{ + return S_ChangeMusic (m_id, 0, false); +} + +//========================================================================== +// +// S_ChangeMusic +// +// initiates playback of a song +// +//========================================================================== +static TMap gainMap; + +EXTERN_CVAR(String, fluid_patchset) +EXTERN_CVAR(String, timidity_config) +EXTERN_CVAR(String, midi_config) +EXTERN_CVAR(String, wildmidi_config) +EXTERN_CVAR(String, adl_custom_bank) +EXTERN_CVAR(Int, adl_bank) +EXTERN_CVAR(Bool, adl_use_custom_bank) +EXTERN_CVAR(String, opn_custom_bank) +EXTERN_CVAR(Bool, opn_use_custom_bank) +EXTERN_CVAR(Int, opl_core) + +static FString ReplayGainHash(ZMusicCustomReader* reader, int flength, int playertype, const char* _playparam) +{ + std::string playparam = _playparam; + + TArray buffer(50000, true); // for performance reasons only hash the start of the file. If we wanted to do this to large waveform songs it'd cause noticable lag. + uint8_t digest[16]; + char digestout[33]; + auto length = reader->read(reader, buffer.data(), 50000); + reader->seek(reader, 0, SEEK_SET); + MD5Context md5; + md5.Init(); + md5.Update(buffer.data(), (int)length); + md5.Final(digest); + + for (size_t j = 0; j < sizeof(digest); ++j) + { + snprintf(digestout + (j * 2), 3, "%02X", digest[j]); + } + digestout[32] = 0; + + auto type = ZMusic_IdentifyMIDIType((uint32_t*)buffer.data(), 32); + if (type == MIDI_NOTMIDI) return FStringf("%d:%s", flength, digestout); + + // get the default for MIDI synth + if (playertype == -1) + { + switch (snd_mididevice) + { + case -1: playertype = MDEV_FLUIDSYNTH; break; + case -2: playertype = MDEV_TIMIDITY; break; + case -3: playertype = MDEV_OPL; break; + case -4: playertype = MDEV_GUS; break; + case -5: playertype = MDEV_FLUIDSYNTH; break; + case -6: playertype = MDEV_WILDMIDI; break; + case -7: playertype = MDEV_ADL; break; + case -8: playertype = MDEV_OPN; break; + default: return ""; + } + } + else if (playertype == MDEV_SNDSYS) return ""; + + // get the default for used sound font. + if (playparam.empty()) + { + switch (playertype) + { + case MDEV_FLUIDSYNTH: playparam = fluid_patchset; break; + case MDEV_TIMIDITY: playparam = timidity_config; break; + case MDEV_GUS: playparam = midi_config; break; + case MDEV_WILDMIDI: playparam = wildmidi_config; break; + case MDEV_ADL: playparam = adl_use_custom_bank ? *adl_custom_bank : std::to_string(adl_bank); break; + case MDEV_OPN: playparam = opn_use_custom_bank ? *opn_custom_bank : ""; break; + case MDEV_OPL: playparam = std::to_string(opl_core); break; + + } + } + return FStringf("%d:%s:%d:%s", flength, digestout, playertype, playparam.c_str()).MakeUpper(); +} + +static void SaveGains() +{ + auto path = M_GetAppDataPath(true); + path << "/replaygain.ini"; + FConfigFile gains(path.GetChars()); + TMap::Iterator it(gainMap); + TMap::Pair* pair; + + if (gains.SetSection("Gains", true)) + { + while (it.NextPair(pair)) + { + gains.SetValueForKey(pair->Key.GetChars(), std::to_string(pair->Value).c_str()); + } + } + gains.WriteConfigFile(); +} + +static void ReadGains() +{ + static bool done = false; + if (done) return; + done = true; + auto path = M_GetAppDataPath(true); + path << "/replaygain.ini"; + FConfigFile gains(path.GetChars()); + if (gains.SetSection("Gains")) + { + const char* key; + const char* value; + + while (gains.NextInSection(key, value)) + { + gainMap.Insert(key, (float)strtod(value, nullptr)); + } + } +} + +CCMD(setreplaygain) +{ + // sets replay gain for current song to a fixed value + if (!mus_playing.handle || mus_playing.hash.IsEmpty()) + { + Printf("setreplaygain needs some music playing\n"); + return; + } + if (argv.argc() < 2) + { + Printf("Usage: setreplaygain {dB}\n"); + Printf("Current replay gain is %f dB\n", AmplitudeTodB(mus_playing.musicVolume)); + return; + } + float dB = (float)strtod(argv[1], nullptr); + if (dB > 10) dB = 10; // don't blast the speakers. Values above 2 or 3 are very rare. + gainMap.Insert(mus_playing.hash, dB); + SaveGains(); + mus_playing.musicVolume = (float)dBToAmplitude(dB); +} + +static void CheckReplayGain(const char *musicname, EMidiDevice playertype, const char *playparam) +{ + mus_playing.musicVolume = 1; + fluid_gain->Callback(); + mod_dumb_mastervolume->Callback(); + if (!mus_usereplaygain) return; + + FileReader reader = OpenMusic(musicname); + if (!reader.isOpen()) return; + int flength = (int)reader.GetLength(); + auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper. + + ReadGains(); + auto hash = ReplayGainHash(mreader, flength, playertype, playparam); + if (hash.IsEmpty()) return; // got nothing to measure. + mus_playing.hash = hash; + auto entry = gainMap.CheckKey(hash); + if (entry) + { + mus_playing.musicVolume = dBToAmplitude(*entry); + return; + } + if (!mus_calcgain) return; + + auto handle = ZMusic_OpenSong(mreader, playertype, playparam); + if (handle == nullptr) return; // not a music file + + if (!ZMusic_Start(handle, 0, false)) + { + ZMusic_Close(handle); + return; // unable to open + } + + SoundStreamInfo fmt; + ZMusic_GetStreamInfo(handle, &fmt); + if (fmt.mBufferSize == 0) + { + ZMusic_Close(handle); + return; // external player. + } + + int flags = SoundStream::Float; + if (abs(fmt.mNumChannels) < 2) flags |= SoundStream::Mono; + + TArray readbuffer(fmt.mBufferSize, true); + TArray lbuffer; + TArray rbuffer; + while (ZMusic_FillStream(handle, readbuffer.Data(), fmt.mBufferSize)) + { + unsigned index; + // 4 cases, all with different preparation needs. + if (fmt.mNumChannels == -2) // 16 bit stereo + { + int16_t* sbuf = (int16_t*)readbuffer.Data(); + int numsamples = fmt.mBufferSize / 4; + index = lbuffer.Reserve(numsamples); + rbuffer.Reserve(numsamples); + + for (int i = 0; i < numsamples; i++) + { + lbuffer[index + i] = sbuf[i * 2]; + rbuffer[index + i] = sbuf[i * 2 + 1]; + } + } + else if (fmt.mNumChannels == -1) // 16 bit mono + { + int16_t* sbuf = (int16_t*)readbuffer.Data(); + int numsamples = fmt.mBufferSize / 2; + index = lbuffer.Reserve(numsamples); + + for (int i = 0; i < numsamples; i++) + { + lbuffer[index + i] = sbuf[i]; + } + } + else if (fmt.mNumChannels == 1) // float mono + { + float* sbuf = (float*)readbuffer.Data(); + int numsamples = fmt.mBufferSize / 4; + index = lbuffer.Reserve(numsamples); + for (int i = 0; i < numsamples; i++) + { + lbuffer[index + i] = sbuf[i] * 32768.f; + } + } + else if (fmt.mNumChannels == 2) // float stereo + { + float* sbuf = (float*)readbuffer.Data(); + int numsamples = fmt.mBufferSize / 8; + auto addr = lbuffer.Reserve(numsamples); + rbuffer.Reserve(numsamples); + + for (int i = 0; i < numsamples; i++) + { + lbuffer[addr + i] = sbuf[i * 2] * 32768.f; + rbuffer[addr + i] = sbuf[i * 2 + 1] * 32768.f; + } + } + float accTime = lbuffer.Size() / (float)fmt.mSampleRate; + if (accTime > 8 * 60) break; // do at most 8 minutes, if the song forces a loop. + } + ZMusic_Close(handle); + + auto analyzer = std::make_unique(); + int result = analyzer->InitGainAnalysis(fmt.mSampleRate); + if (result == GAIN_ANALYSIS_OK) + { + result = analyzer->AnalyzeSamples(lbuffer.Data(), rbuffer.Size() == 0 ? nullptr : rbuffer.Data(), lbuffer.Size(), rbuffer.Size() == 0 ? 1 : 2); + if (result == GAIN_ANALYSIS_OK) + { + auto gain = analyzer->GetTitleGain(); + Printf("Calculated replay gain for %s (%s) at %f dB\n", musicname, hash.GetChars(), gain); + + gainMap.Insert(hash, gain); + mus_playing.musicVolume = dBToAmplitude(gain); + SaveGains(); + } + } +} + +bool S_ChangeMusic(const char* musicname, int order, bool looping, bool force) +{ + if (!MusicEnabled()) return false; // skip the entire procedure if music is globally disabled. + + if (!force && PlayList.GetNumSongs()) + { // Don't change if a playlist is active + return true; // do not report an error here. + } + // Do game specific lookup. + FString musicname_; + if (mus_cb.LookupFileName) + { + musicname_ = mus_cb.LookupFileName(musicname, order); + musicname = musicname_.GetChars(); + } + + if (musicname == nullptr || musicname[0] == 0) + { + // Don't choke if the map doesn't have a song attached + S_StopMusic (true); + mus_playing.name = ""; + mus_playing.LastSong = ""; + return true; + } + + if (!mus_playing.name.IsEmpty() && + mus_playing.handle != nullptr && + mus_playing.name.CompareNoCase(musicname) == 0 && + ZMusic_IsLooping(mus_playing.handle) == zmusic_bool(looping)) + { + if (order != mus_playing.baseorder) + { + if (ZMusic_SetSubsong(mus_playing.handle, order)) + { + mus_playing.baseorder = order; + } + } + else if (!ZMusic_IsPlaying(mus_playing.handle)) + { + if (!ZMusic_Start(mus_playing.handle, order, looping)) + { + Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); + } + S_CreateStream(); + + } + return true; + } + + ZMusic_MusicStream handle = nullptr; + + // Strip off any leading file:// component. + if (strncmp(musicname, "file://", 7) == 0) + { + musicname += 7; + } + + // opening the music must be done by the game because it's different depending on the game's file system use. + FileReader reader = OpenMusic(musicname); + if (!reader.isOpen()) return false; + auto m = reader.Read(); + reader.Seek(0, FileReader::SeekSet); + + // shutdown old music + S_StopMusic(true); + + // Just record it if volume is 0 or music was disabled + if (snd_musicvolume <= 0 || !mus_enabled) + { + mus_playing.loop = looping; + mus_playing.name = musicname; + mus_playing.baseorder = order; + mus_playing.LastSong = musicname; + return true; + } + + // load & register it + if (handle != nullptr) + { + mus_playing.handle = handle; + } + else + { + int lumpnum = mus_cb.FindMusic(musicname); + MidiDeviceSetting* devp = MidiDevices.CheckKey(lumpnum); + + auto volp = MusicVolumes.CheckKey(lumpnum); + if (volp) + { + mus_playing.musicVolume = *volp; + + } + else + { + CheckReplayGain(musicname, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : ""); + } + auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper. + mus_playing.handle = ZMusic_OpenSong(mreader, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : ""); + if (mus_playing.handle == nullptr) + { + Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); + } + } + + mus_playing.loop = looping; + mus_playing.name = musicname; + mus_playing.baseorder = 0; + mus_playing.LastSong = ""; + + if (mus_playing.handle != 0) + { // play it + if (!S_StartMusicPlaying(mus_playing.handle, looping, 1.f, order)) + { + Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); + return false; + } + + S_CreateStream(); + mus_playing.baseorder = order; + return true; + } + return false; +} + +//========================================================================== +// +// S_RestartMusic +// +//========================================================================== + +void S_RestartMusic () +{ + if (snd_musicvolume <= 0) return; + if (!mus_playing.LastSong.IsEmpty() && mus_enabled) + { + FString song = mus_playing.LastSong; + mus_playing.LastSong = ""; + S_ChangeMusic (song.GetChars(), mus_playing.baseorder, mus_playing.loop, true); + } + else + { + S_StopMusic(true); + } +} + +//========================================================================== +// +// S_MIDIDeviceChanged +// +//========================================================================== + + +void S_MIDIDeviceChanged(int newdev) +{ + auto song = mus_playing.handle; + if (song != nullptr && ZMusic_IsMIDI(song) && ZMusic_IsPlaying(song)) + { + // Reload the song to change the device + auto mi = mus_playing; + S_StopMusic(true); + S_ChangeMusic(mi.name.GetChars(), mi.baseorder, mi.loop); + } +} + +//========================================================================== +// +// S_GetMusic +// +//========================================================================== + +int S_GetMusic (const char **name) +{ + int order; + + if (mus_playing.name.IsNotEmpty()) + { + *name = mus_playing.name.GetChars(); + order = mus_playing.baseorder; + } + else + { + *name = nullptr; + order = 0; + } + return order; +} + +//========================================================================== +// +// S_StopMusic +// +//========================================================================== + +void S_StopMusic (bool force) +{ + try + { + // [RH] Don't stop if a playlist is active. + if ((force || PlayList.GetNumSongs() == 0) && !mus_playing.name.IsEmpty()) + { + if (mus_playing.handle != nullptr) + { + S_ResumeMusic(); + S_StopStream(); + ZMusic_Stop(mus_playing.handle); + auto h = mus_playing.handle; + mus_playing.handle = nullptr; + ZMusic_Close(h); + } + mus_playing.LastSong = std::move(mus_playing.name); + } + } + catch (const std::runtime_error& ) + { + //Printf("Unable to stop %s: %s\n", mus_playing.name.GetChars(), err.what()); + if (mus_playing.handle != nullptr) + { + auto h = mus_playing.handle; + mus_playing.handle = nullptr; + ZMusic_Close(h); + } + mus_playing.name = ""; + } +} + +//========================================================================== +// +// CCMD changemus +// +//========================================================================== + +CCMD (changemus) +{ + if (MusicEnabled()) + { + if (argv.argc() > 1) + { + PlayList.Clear(); + S_ChangeMusic (argv[1], argv.argc() > 2 ? atoi (argv[2]) : 0); + } + else + { + const char *currentmus = mus_playing.name.GetChars(); + if(currentmus != nullptr && *currentmus != 0) + { + Printf ("currently playing %s\n", currentmus); + } + else + { + Printf ("no music playing\n"); + } + } + } + else + { + Printf("Music is disabled\n"); + } +} + +//========================================================================== +// +// CCMD stopmus +// +//========================================================================== + +CCMD (stopmus) +{ + PlayList.Clear(); + S_StopMusic (false); + mus_playing.LastSong = ""; // forget the last played song so that it won't get restarted if some volume changes occur +} + +//========================================================================== +// +// CCMD playlist +// +//========================================================================== + +UNSAFE_CCMD (playlist) +{ + int argc = argv.argc(); + + if (argc < 2 || argc > 3) + { + Printf ("playlist [|shuffle]\n"); + } + else + { + if (!PlayList.ChangeList(argv[1])) + { + Printf("Could not open " TEXTCOLOR_BOLD "%s" TEXTCOLOR_NORMAL ": %s\n", argv[1], strerror(errno)); + return; + } + if (PlayList.GetNumSongs () > 0) + { + if (argc == 3) + { + if (stricmp (argv[2], "shuffle") == 0) + { + PlayList.Shuffle (); + } + else + { + PlayList.SetPosition (atoi (argv[2])); + } + } + S_ActivatePlayList (false); + } + } +} + +//========================================================================== +// +// CCMD playlistpos +// +//========================================================================== + +static bool CheckForPlaylist () +{ + if (PlayList.GetNumSongs() == 0) + { + Printf ("No playlist is playing.\n"); + return false; + } + return true; +} + +CCMD (playlistpos) +{ + if (CheckForPlaylist() && argv.argc() > 1) + { + PlayList.SetPosition (atoi (argv[1]) - 1); + S_ActivatePlayList (false); + } +} + +//========================================================================== +// +// CCMD playlistnext +// +//========================================================================== + +CCMD (playlistnext) +{ + if (CheckForPlaylist()) + { + PlayList.Advance (); + S_ActivatePlayList (false); + } +} + +//========================================================================== +// +// CCMD playlistprev +// +//========================================================================== + +CCMD (playlistprev) +{ + if (CheckForPlaylist()) + { + PlayList.Backup (); + S_ActivatePlayList (true); + } +} + +//========================================================================== +// +// CCMD playliststatus +// +//========================================================================== + +CCMD (playliststatus) +{ + if (CheckForPlaylist ()) + { + Printf ("Song %d of %d:\n%s\n", + PlayList.GetPosition () + 1, + PlayList.GetNumSongs (), + PlayList.GetSong (PlayList.GetPosition ())); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +CCMD(currentmusic) +{ + if (mus_playing.name.IsNotEmpty()) + { + Printf("Currently playing music '%s'\n", mus_playing.name.GetChars()); + } + else + { + Printf("Currently no music playing\n"); + } +} diff --git a/src/sound/music/music_config.cpp b/src/common/audio/music/music_config.cpp similarity index 86% rename from src/sound/music/music_config.cpp rename to src/common/audio/music/music_config.cpp index bd71a8fc916..efdb0563740 100644 --- a/src/sound/music/music_config.cpp +++ b/src/common/audio/music/music_config.cpp @@ -41,6 +41,7 @@ #include "version.h" #include +EXTERN_CVAR(Bool, mus_usereplaygain) //========================================================================== // // ADL Midi device @@ -63,7 +64,7 @@ auto ret = ChangeMusicSetting(zmusic_##key, mus_playing.handle,*self); \ if (ret) S_MIDIDeviceChanged(-1); - +#ifndef ZMUSIC_LITE CUSTOM_CVAR(Int, adl_chips_count, 6, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_CVAR(adl_chips_count); @@ -74,36 +75,36 @@ CUSTOM_CVAR(Int, adl_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIR FORWARD_CVAR(adl_emulator_id); } -CUSTOM_CVAR(Bool, adl_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Bool, adl_run_at_pcm_rate, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_BOOL_CVAR(adl_run_at_pcm_rate); } -CUSTOM_CVAR(Bool, adl_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Bool, adl_fullpan, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_BOOL_CVAR(adl_fullpan); } -CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_CVAR(adl_bank); } -CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Bool, adl_use_custom_bank, false, CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_BOOL_CVAR(adl_use_custom_bank); } -CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_STRING_CVAR(adl_custom_bank); } -CUSTOM_CVAR(Int, adl_volume_model, 3/*ADLMIDI_VolumeModel_DMX*/, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Int, adl_volume_model, 0 /*ADLMIDI_VolumeModel_AUTO*/, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { - FORWARD_CVAR(adl_bank); + FORWARD_CVAR(adl_volume_model); } - +#endif //========================================================================== // // Fluidsynth MIDI device @@ -122,7 +123,16 @@ CUSTOM_CVAR(String, fluid_patchset, GAMENAMELOWERCASE, CVAR_ARCHIVE | CVAR_GLOBA CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { - FORWARD_CVAR(fluid_gain); + if (!mus_usereplaygain) + { + FORWARD_CVAR(fluid_gain); + } + else + { + // Replay gain will disable the user setting for consistency. + float newval; + ChangeMusicSetting(zmusic_fluid_gain, mus_playing.handle, 0.5f, & newval); + } } CUSTOM_CVAR(Bool, fluid_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) @@ -191,7 +201,7 @@ CUSTOM_CVAR(Float, fluid_chorus_speed, 0.3f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | } // depth is in ms and actual maximum depends on the sample rate -CUSTOM_CVAR(Float, fluid_chorus_depth, 8, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Float, fluid_chorus_depth, 8.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_CVAR(fluid_chorus_depth); } @@ -223,6 +233,7 @@ CUSTOM_CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIR FORWARD_BOOL_CVAR(opl_fullpan); } +#ifndef ZMUSIC_LITE //========================================================================== // // OPN MIDI device @@ -240,22 +251,22 @@ CUSTOM_CVAR(Int, opn_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIR FORWARD_CVAR(opn_emulator_id); } -CUSTOM_CVAR(Bool, opn_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Bool, opn_run_at_pcm_rate, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_BOOL_CVAR(opn_run_at_pcm_rate); } -CUSTOM_CVAR(Bool, opn_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Bool, opn_fullpan, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_BOOL_CVAR(opn_fullpan); } -CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Bool, opn_use_custom_bank, false, CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_BOOL_CVAR(opn_use_custom_bank); } -CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_VIRTUAL) { FORWARD_STRING_CVAR(opn_custom_bank); } @@ -267,7 +278,7 @@ CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR //========================================================================== -CUSTOM_CVAR(String, midi_config, GAMENAMELOWERCASE, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(String, midi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_STRING_CVAR(gus_config); } @@ -333,7 +344,7 @@ CUSTOM_CVAR(Bool, timidity_channel_pressure, false, CVAR_ARCHIVE | CVAR_GLOBALCO FORWARD_BOOL_CVAR(timidity_channel_pressure); } -CUSTOM_CVAR(Int, timidity_lpf_def, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Int, timidity_lpf_def, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_CVAR(timidity_lpf_def); } @@ -373,21 +384,22 @@ CUSTOM_CVAR(Int, timidity_key_adjust, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR FORWARD_CVAR(timidity_key_adjust); } -CUSTOM_CVAR(Float, timidity_tempo_adjust, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Float, timidity_tempo_adjust, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_CVAR(timidity_tempo_adjust); } -CUSTOM_CVAR(Float, timidity_min_sustain_time, 5000, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Float, timidity_min_sustain_time, 5000.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_CVAR(timidity_min_sustain_time); } +#endif CUSTOM_CVAR(String, timidity_config, GAMENAMELOWERCASE, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { FORWARD_STRING_CVAR(timidity_config); } - +#ifndef ZMUSIC_LITE //========================================================================== // // WildMidi @@ -408,7 +420,7 @@ CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBAL { FORWARD_BOOL_CVAR(wildmidi_enhanced_resampling); } - +#endif //========================================================================== // @@ -451,6 +463,11 @@ CUSTOM_CVAR(Int, snd_streambuffersize, 64, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CV CUSTOM_CVAR(Int, mod_samplerate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { + if (self != 0 && self != 11025 && self != 22050 && self != 44100 && self != 48000) + { + self = 0; + return; + } FORWARD_CVAR(mod_samplerate); } @@ -486,6 +503,14 @@ CUSTOM_CVAR(Int, mod_autochip_scan_threshold, 12, CVAR_ARCHIVE | CVAR_GLOBAL CUSTOM_CVAR(Float, mod_dumb_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { - FORWARD_CVAR(mod_dumb_mastervolume); + if (!mus_usereplaygain) + { + FORWARD_CVAR(mod_dumb_mastervolume); + } + else + { + float newval; + ChangeMusicSetting(zmusic_mod_dumb_mastervolume, mus_playing.handle, 0.5f, &newval); + } } diff --git a/src/sound/music/music_midi_base.cpp b/src/common/audio/music/music_midi_base.cpp similarity index 98% rename from src/sound/music/music_midi_base.cpp rename to src/common/audio/music/music_midi_base.cpp index 3075af0500d..6ce9878010c 100644 --- a/src/sound/music/music_midi_base.cpp +++ b/src/common/audio/music/music_midi_base.cpp @@ -35,9 +35,11 @@ #include "c_dispatch.h" #include "v_text.h" -#include "menu/menu.h" +#include "menu.h" #include #include "s_music.h" +#include "c_cvars.h" +#include "printf.h" #define DEF_MIDIDEV -5 diff --git a/src/common/audio/music/s_music.h b/src/common/audio/music/s_music.h new file mode 100644 index 00000000000..cddfd36d626 --- /dev/null +++ b/src/common/audio/music/s_music.h @@ -0,0 +1,96 @@ + +#ifndef __S_MUSIC__ +#define __S_MUSIC__ + +#include "zstring.h" +#include "tarray.h" +#include "name.h" +#include "files.h" +#include + +class SoundStream; + + +enum MusicCustomStreamType : bool { + MusicSamples16bit, + MusicSamplesFloat +}; +int MusicEnabled(); +typedef bool(*StreamCallback)(SoundStream* stream, void* buff, int len, void* userdata); +SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, MusicCustomStreamType sampletype, StreamCallback cb, void *userdata); +void S_StopCustomStream(SoundStream* stream); +void S_PauseAllCustomStreams(bool on); + +struct MusicCallbacks +{ + FString(*LookupFileName)(const char* fn, int &order); + int(*FindMusic)(const char* fn); +}; +void S_SetMusicCallbacks(MusicCallbacks* cb); + +void S_CreateStream(); +void S_PauseStream(bool pause); +void S_StopStream(); +void S_SetStreamVolume(float vol); + + +// +void S_InitMusic (); +void S_ResetMusic (); + + +// Start music using +bool S_StartMusic (const char *music_name); + +// Start music using , and set whether looping +bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false); + +void S_RestartMusic (); +void S_MIDIDeviceChanged(int newdev); + +int S_GetMusic (const char **name); + +// Stops the music for sure. +void S_StopMusic (bool force); + +// Stop and resume music, during game PAUSE. +void S_PauseMusic (); +void S_ResumeMusic (); + +// +// Updates music & sounds +// +void S_UpdateMusic (); + +struct MidiDeviceSetting +{ + int device; + FString args; +}; + +typedef TMap MidiDeviceMap; +typedef TMap MusicVolumeMap; + +extern MidiDeviceMap MidiDevices; +extern MusicVolumeMap MusicVolumes; +extern MusicCallbacks mus_cb; + +struct MusPlayingInfo +{ + FString name; + ZMusic_MusicStream handle; + int lumpnum; + int baseorder; + float musicVolume; + bool loop; + bool isfloat; + FString LastSong; // last music that was played + FString hash; // for setting replay gain while playing. +}; + +extern MusPlayingInfo mus_playing; + +extern float relative_volume, saved_relative_volume; + + +#endif diff --git a/src/sound/backend/efx.h b/src/common/audio/sound/efx.h similarity index 87% rename from src/sound/backend/efx.h rename to src/common/audio/sound/efx.h index 0ccef95d6ba..addd25834a2 100644 --- a/src/sound/backend/efx.h +++ b/src/common/audio/sound/efx.h @@ -1,6 +1,7 @@ #ifndef AL_EFX_H #define AL_EFX_H +#include #ifdef __cplusplus extern "C" { @@ -201,12 +202,12 @@ extern "C" { /* Effect object function types. */ typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*); typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*); typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); @@ -214,12 +215,12 @@ typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); /* Filter object function types. */ typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*); typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*); typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); @@ -227,87 +228,87 @@ typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); /* Auxiliary Effect Slot object function types. */ typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*); typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*); typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); #ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); -AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects); +AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); +AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects); AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); -AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); - -AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); -AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters); +AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); +AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues); +AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); +AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues); +AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); +AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); +AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); + +AL_API void AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); +AL_API void AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters); AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); -AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); - -AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); -AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API void AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); +AL_API void AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues); +AL_API void AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); +AL_API void AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues); +AL_API void AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); +AL_API void AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API void AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); +AL_API void AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); + +AL_API void AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API void AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots); AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +AL_API void AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); +AL_API void AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues); +AL_API void AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); +AL_API void AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues); +AL_API void AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); +AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); +AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); #endif /* Filter ranges and defaults. */ /* Lowpass filter */ -#define LOWPASS_MIN_GAIN (0.0f) -#define LOWPASS_MAX_GAIN (1.0f) -#define LOWPASS_DEFAULT_GAIN (1.0f) +#define AL_LOWPASS_MIN_GAIN (0.0f) +#define AL_LOWPASS_MAX_GAIN (1.0f) +#define AL_LOWPASS_DEFAULT_GAIN (1.0f) -#define LOWPASS_MIN_GAINHF (0.0f) -#define LOWPASS_MAX_GAINHF (1.0f) -#define LOWPASS_DEFAULT_GAINHF (1.0f) +#define AL_LOWPASS_MIN_GAINHF (0.0f) +#define AL_LOWPASS_MAX_GAINHF (1.0f) +#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) /* Highpass filter */ -#define HIGHPASS_MIN_GAIN (0.0f) -#define HIGHPASS_MAX_GAIN (1.0f) -#define HIGHPASS_DEFAULT_GAIN (1.0f) +#define AL_HIGHPASS_MIN_GAIN (0.0f) +#define AL_HIGHPASS_MAX_GAIN (1.0f) +#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) -#define HIGHPASS_MIN_GAINLF (0.0f) -#define HIGHPASS_MAX_GAINLF (1.0f) -#define HIGHPASS_DEFAULT_GAINLF (1.0f) +#define AL_HIGHPASS_MIN_GAINLF (0.0f) +#define AL_HIGHPASS_MAX_GAINLF (1.0f) +#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) /* Bandpass filter */ -#define BANDPASS_MIN_GAIN (0.0f) -#define BANDPASS_MAX_GAIN (1.0f) -#define BANDPASS_DEFAULT_GAIN (1.0f) +#define AL_BANDPASS_MIN_GAIN (0.0f) +#define AL_BANDPASS_MAX_GAIN (1.0f) +#define AL_BANDPASS_DEFAULT_GAIN (1.0f) -#define BANDPASS_MIN_GAINHF (0.0f) -#define BANDPASS_MAX_GAINHF (1.0f) -#define BANDPASS_DEFAULT_GAINHF (1.0f) +#define AL_BANDPASS_MIN_GAINHF (0.0f) +#define AL_BANDPASS_MAX_GAINHF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) -#define BANDPASS_MIN_GAINLF (0.0f) -#define BANDPASS_MAX_GAINLF (1.0f) -#define BANDPASS_DEFAULT_GAINLF (1.0f) +#define AL_BANDPASS_MIN_GAINLF (0.0f) +#define AL_BANDPASS_MAX_GAINLF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINLF (1.0f) /* Effect parameter ranges and defaults. */ diff --git a/src/sound/backend/i_sound.cpp b/src/common/audio/sound/i_sound.cpp similarity index 90% rename from src/sound/backend/i_sound.cpp rename to src/common/audio/sound/i_sound.cpp index f1f0e3c87ac..dda757e8d78 100644 --- a/src/sound/backend/i_sound.cpp +++ b/src/common/audio/sound/i_sound.cpp @@ -50,12 +50,19 @@ EXTERN_CVAR (Float, snd_sfxvolume) -EXTERN_CVAR (Float, snd_musicvolume) -CVAR (Int, snd_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Int, snd_hrtf, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +EXTERN_CVAR(Float, snd_musicvolume) +CUSTOM_CVAR(Int, snd_samplerate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self != 0 && self != 8000 && self != 11025 && self != 22050 && self != 32000 && self != 44100 && self != 48000) + { + self = 0; + return; + } +} +CVAR(Int, snd_buffersize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, snd_hrtf, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -#if !defined(NO_OPENAL) +#if !defined(NO_OPENAL) #define DEF_BACKEND "openal" #else #define DEF_BACKEND "null" @@ -63,9 +70,6 @@ CVAR (Int, snd_hrtf, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(String, snd_backend, DEF_BACKEND, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -// killough 2/21/98: optionally use varying pitched sounds -CVAR (Bool, snd_pitched, false, CVAR_ARCHIVE) - SoundRenderer *GSnd; bool nosound; bool nosfx; @@ -84,7 +88,7 @@ void I_CloseSound (); // Maximum volume of all audio //========================================================================== -CUSTOM_CVAR(Float, snd_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, snd_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { if (self < 0.f) self = 0.f; @@ -92,8 +96,8 @@ CUSTOM_CVAR(Float, snd_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) self = 1.f; ChangeMusicSetting(zmusic_snd_mastervolume, nullptr, self); - snd_sfxvolume.Callback(); - snd_musicvolume.Callback(); + snd_sfxvolume->Callback(); + snd_musicvolume->Callback(); } //========================================================================== @@ -127,7 +131,7 @@ class NullSoundRenderer : public SoundRenderer void SetMusicVolume (float volume) { } - SoundHandle LoadSound(uint8_t *sfxdata, int length) + SoundHandle LoadSound(uint8_t *sfxdata, int length, int def_loop_start, int def_loop_end) { SoundHandle retval = { NULL }; return retval; @@ -171,11 +175,11 @@ class NullSoundRenderer : public SoundRenderer } // Starts a sound. - FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan, float startTime) + FISoundChannel *StartSound (SoundHandle sfx, float vol, float pitch, int chanflags, FISoundChannel *reuse_chan, float startTime) { return NULL; } - FISoundChannel *StartSound3D (SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime) + FISoundChannel *StartSound3D (SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, float pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime) { return NULL; } @@ -244,16 +248,15 @@ class NullSoundRenderer : public SoundRenderer void I_InitSound () { - FModule_SetProgDir(progdir); + FModule_SetProgDir(progdir.GetChars()); /* Get command line options: */ nosound = !!Args->CheckParm ("-nosound"); nosfx = !!Args->CheckParm ("-nosfx"); GSnd = NULL; - if (nosound || batchrun) + if (nosound) { GSnd = new NullSoundRenderer; - I_InitMusic (); return; } @@ -277,8 +280,7 @@ void I_InitSound () GSnd = new NullSoundRenderer; Printf (TEXTCOLOR_RED"Sound init failed. Using nosound.\n"); } - I_InitMusic (); - snd_sfxvolume.Callback (); + snd_sfxvolume->Callback (); } @@ -297,6 +299,7 @@ const char *GetSampleTypeName(SampleType type) { case SampleType_UInt8: return "Unsigned 8-bit"; case SampleType_Int16: return "Signed 16-bit"; + default: break; } return "(invalid sample type)"; } @@ -362,7 +365,7 @@ SoundHandle SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int length) i += 4; if (i + blocksize > length) { - okay = false; + //okay = false; break; } @@ -372,9 +375,9 @@ SoundHandle SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int length) case 1: // Sound data if (/*noextra &*/ (codec == -1 || codec == sfxdata[i + 1])) // NAM contains a VOC where a valid data block follows an extra block. { - frequency = 1000000/(256 - sfxdata[i]); + frequency = 1000000 / (256 - sfxdata[i]); channels = 1; - codec = sfxdata[i+1]; + codec = sfxdata[i + 1]; if (codec == 0) bits = 8; else if (codec == 4) @@ -445,7 +448,7 @@ SoundHandle SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int length) } // Second pass to write the data - if (okay) + if (okay && len > 0) { data = new uint8_t[len]; i = 26; @@ -488,3 +491,4 @@ SoundHandle SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int length) if (data) delete[] data; return retval; } + diff --git a/src/sound/backend/i_sound.h b/src/common/audio/sound/i_sound.h similarity index 88% rename from src/sound/backend/i_sound.h rename to src/common/audio/sound/i_sound.h index 573159242d1..e8e5a1a0e95 100644 --- a/src/sound/backend/i_sound.h +++ b/src/common/audio/sound/i_sound.h @@ -35,12 +35,13 @@ #ifndef __I_SOUND__ #define __I_SOUND__ +#include #include #include "i_soundinternal.h" -#include "utility/zstring.h" +#include "zstring.h" #include +#include "files.h" -class FileReader; struct FSoundChan; enum EStartSoundFlags @@ -62,7 +63,7 @@ enum ECodecType class SoundStream { public: - virtual ~SoundStream () {} + virtual ~SoundStream() = default; enum { // For CreateStream @@ -75,11 +76,18 @@ class SoundStream Loop = 16 }; + struct Position { + uint64_t samplesplayed; + std::chrono::nanoseconds latency; + }; + virtual bool Play(bool looping, float volume) = 0; virtual void Stop() = 0; virtual void SetVolume(float volume) = 0; virtual bool SetPaused(bool paused) = 0; virtual bool IsEnded() = 0; + // Be aware this can be called during the callback invocation after Play is called. + virtual Position GetPlayPosition() = 0; virtual FString GetStats(); }; @@ -97,7 +105,7 @@ class SoundRenderer virtual bool IsNull() { return false; } virtual void SetSfxVolume (float volume) = 0; virtual void SetMusicVolume (float volume) = 0; - virtual SoundHandle LoadSound(uint8_t *sfxdata, int length) = 0; + virtual SoundHandle LoadSound(uint8_t *sfxdata, int length, int def_loop_start, int def_loop_end) = 0; SoundHandle LoadSoundVoc(uint8_t *sfxdata, int length); virtual SoundHandle LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1) = 0; virtual void UnloadSound (SoundHandle sfx) = 0; // unloads a sound from memory @@ -107,10 +115,10 @@ class SoundRenderer // Streaming sounds. virtual SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) = 0; - + // Starts a sound. - virtual FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan, float startTime = 0.f) = 0; - virtual FISoundChannel *StartSound3D (SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime = 0.f) = 0; + virtual FISoundChannel *StartSound (SoundHandle sfx, float vol, float pitch, int chanflags, FISoundChannel *reuse_chan, float startTime = 0.f) = 0; + virtual FISoundChannel *StartSound3D (SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, float pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime = 0.f) = 0; // Stops a sound channel. virtual void StopChannel (FISoundChannel *chan) = 0; @@ -169,5 +177,6 @@ void I_CloseSound(); extern ReverbContainer *DefaultEnvironments[26]; bool IsOpenALPresent(); +void S_SoundReset(); #endif diff --git a/src/sound/backend/i_soundinternal.h b/src/common/audio/sound/i_soundinternal.h similarity index 81% rename from src/sound/backend/i_soundinternal.h rename to src/common/audio/sound/i_soundinternal.h index 1651d518d03..52dabeea3ac 100644 --- a/src/sound/backend/i_soundinternal.h +++ b/src/common/audio/sound/i_soundinternal.h @@ -5,7 +5,6 @@ #include #include "vectors.h" -#include "tarray.h" #include "tflags.h" enum EChanFlag @@ -18,6 +17,8 @@ enum EChanFlag CHANF_AREA = 128, // Sound plays from all around. Only valid with sector sounds. CHANF_LOOP = 256, + CHANF_PICKUP = CHANF_MAYBE_LOCAL, + CHANF_NONE = 0, CHANF_IS3D = 1, // internal: Sound is 3D. CHANF_EVICTED = 2, // internal: Sound was evicted. @@ -28,13 +29,14 @@ enum EChanFlag CHANF_NOSTOP = 4096, // only for A_PlaySound. Does not start if channel is playing something. CHANF_OVERLAP = 8192, // [MK] Does not stop any sounds in the channel and instead plays over them. CHANF_LOCAL = 16384, // only plays locally for the calling actor + CHANF_TRANSIENT = 32768, // Do not record in savegames - used for sounds that get restarted outside the sound system (e.g. ambients in SW and Blood) + CHANF_FORCE = 65536, // Start, even if sound is paused. + CHANF_SINGULAR = 0x20000, // Only start if no sound of this name is already playing. }; typedef TFlags EChanFlags; DEFINE_TFLAGS_OPERATORS(EChanFlags) -class FileReader; - // For convenience, this structure matches FMOD_REVERB_PROPERTIES. // Since I can't very well #include system-specific stuff in the // main game files, I duplicate it here. @@ -73,14 +75,17 @@ struct REVERB_PROPERTIES unsigned int Flags; }; -#define REVERB_FLAGS_DECAYTIMESCALE 0x00000001 -#define REVERB_FLAGS_REFLECTIONSSCALE 0x00000002 -#define REVERB_FLAGS_REFLECTIONSDELAYSCALE 0x00000004 -#define REVERB_FLAGS_REVERBSCALE 0x00000008 -#define REVERB_FLAGS_REVERBDELAYSCALE 0x00000010 -#define REVERB_FLAGS_DECAYHFLIMIT 0x00000020 -#define REVERB_FLAGS_ECHOTIMESCALE 0x00000040 -#define REVERB_FLAGS_MODULATIONTIMESCALE 0x00000080 +enum EReverbFlags +{ + REVERB_FLAGS_DECAYTIMESCALE = 0x00000001, + REVERB_FLAGS_REFLECTIONSSCALE = 0x00000002, + REVERB_FLAGS_REFLECTIONSDELAYSCALE = 0x00000004, + REVERB_FLAGS_REVERBSCALE = 0x00000008, + REVERB_FLAGS_REVERBDELAYSCALE = 0x00000010, + REVERB_FLAGS_DECAYHFLIMIT = 0x00000020, + REVERB_FLAGS_ECHOTIMESCALE = 0x00000040, + REVERB_FLAGS_MODULATIONTIMESCALE = 0x00000080, +}; struct ReverbContainer { @@ -139,9 +144,7 @@ struct FISoundChannel EChanFlags ChanFlags; }; -class SoundStream; - - +void S_SetSoundPaused(int state); #endif diff --git a/src/sound/backend/oalload.h b/src/common/audio/sound/oalload.h similarity index 100% rename from src/sound/backend/oalload.h rename to src/common/audio/sound/oalload.h diff --git a/src/sound/backend/oalsound.cpp b/src/common/audio/sound/oalsound.cpp similarity index 91% rename from src/sound/backend/oalsound.cpp rename to src/common/audio/sound/oalsound.cpp index c6c4af18e8e..8b20fb9c100 100644 --- a/src/sound/backend/oalsound.cpp +++ b/src/common/audio/sound/oalsound.cpp @@ -36,7 +36,7 @@ #include #include "c_cvars.h" -#include "templates.h" + #include "oalsound.h" #include "c_dispatch.h" #include "v_text.h" @@ -52,6 +52,11 @@ FModule OpenALModule{"OpenAL"}; #include "oalload.h" +CUSTOM_CVAR(Int, snd_channels, 128, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // number of channels available +{ + if (self < 64) self = 64; +} +CVAR(Bool, snd_waterreverb, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_alresampler, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -70,7 +75,7 @@ CVAR (String, snd_alresampler, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) #define OPENALLIB1 "libopenal.1.dylib" #define OPENALLIB2 "OpenAL.framework/OpenAL" #else // !__APPLE__ -#define OPENALLIB1 NicePath("$PROGDIR/" OPENALLIB) +#define OPENALLIB1 NicePath("$PROGDIR/" OPENALLIB).GetChars() #define OPENALLIB2 OPENALLIB #endif @@ -105,7 +110,6 @@ ReverbContainer *ForcedEnvironment; EXTERN_CVAR (Int, snd_channels) EXTERN_CVAR (Int, snd_samplerate) EXTERN_CVAR (Bool, snd_waterreverb) -EXTERN_CVAR (Bool, snd_pitched) EXTERN_CVAR (Int, snd_hrtf) @@ -176,8 +180,10 @@ class OpenALSoundStream : public SoundStream ALuint Source; std::atomic Playing; - bool Looping; + //bool Looping; ALfloat Volume; + uint64_t Offset = 0; + std::mutex Mutex; bool SetupSource() { @@ -222,7 +228,7 @@ class OpenALSoundStream : public SoundStream public: OpenALSoundStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f) + : Renderer(renderer), Source(0), Playing(false), Volume(1.0f) { memset(Buffers, 0, sizeof(Buffers)); Renderer->AddStream(this); @@ -258,6 +264,7 @@ class OpenALSoundStream : public SoundStream return true; /* Clear the buffer queue, then fill and queue each buffer */ + Offset = 0; alSourcei(Source, AL_BUFFER, 0); for(int i = 0;i < BufferCount;i++) { @@ -292,6 +299,7 @@ class OpenALSoundStream : public SoundStream alSourcei(Source, AL_BUFFER, 0); getALError(); + Offset = 0; Playing.store(false); } @@ -319,12 +327,49 @@ class OpenALSoundStream : public SoundStream virtual bool IsEnded() { return !Playing.load(); - } + } + + Position GetPlayPosition() override + { + using namespace std::chrono; + + std::lock_guard _{Mutex}; + ALint64SOFT offset[2]{}; + ALint state{}, queued{}; + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + if(Renderer->AL.SOFT_source_latency) + { + // AL_SAMPLE_OFFSET_LATENCY_SOFT fills offset[0] with the source sample + // offset in 32.32 fixed-point (which we chop off the sub-sample position + // since it's not crucial), and offset[1] with the playback latency in + // nanoseconds (how many nanoseconds until the sample point in offset[0] + // reaches the DAC). + Renderer->alGetSourcei64vSOFT(Source, AL_SAMPLE_OFFSET_LATENCY_SOFT, offset); + offset[0] >>= 32; + } + else + { + // Without AL_SOFT_source_latency, we can only get the sample offset, no + // latency info. + ALint ioffset{}; + alGetSourcei(Source, AL_SAMPLE_OFFSET, &ioffset); + offset[0] = ioffset; + offset[1] = 0; + } + alGetSourcei(Source, AL_SOURCE_STATE, &state); + // If the source is stopped, there was an underrun, so the play position is + // the end of the queue. + if(state == AL_STOPPED) + return Position{Offset + queued*(Data.Size()/FrameSize), nanoseconds{offset[1]}}; + // The offset is otherwise valid as long as the source has been started. + if(state != AL_INITIAL) + return Position{Offset + offset[0], nanoseconds{offset[1]}}; + return Position{0, nanoseconds{0}}; + } virtual FString GetStats() { FString stats; - size_t pos = 0, len = 0; ALfloat volume; ALint offset; ALint processed; @@ -382,8 +427,12 @@ class OpenALSoundStream : public SoundStream // Unqueue the oldest buffer, fill it with more data, and queue it // on the end - alSourceUnqueueBuffers(Source, 1, &bufid); - processed--; + { + std::lock_guard _{Mutex}; + alSourceUnqueueBuffers(Source, 1, &bufid); + Offset += Data.Size() / FrameSize; + processed--; + } if(Callback(this, &Data[0], Data.Size(), UserData)) { @@ -477,8 +526,6 @@ class OpenALSoundStream : public SoundStream #define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ -#define PITCH(pitch) (snd_pitched ? (pitch)/128.f : 1.f) - static size_t GetChannelCount(ChannelConfig chans) { switch(chans) @@ -551,6 +598,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); ALC.SOFT_HRTF = !!alcIsExtensionPresent(Device, "ALC_SOFT_HRTF"); ALC.SOFT_pause_device = !!alcIsExtensionPresent(Device, "ALC_SOFT_pause_device"); + ALC.SOFT_output_limiter = !!alcIsExtensionPresent(Device, "ALC_SOFT_output_limiter"); const ALCchar *current = NULL; if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) @@ -574,7 +622,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() // Make sure one source is capable of stereo output with the rest doing // mono, without running out of voices attribs.Push(ALC_MONO_SOURCES); - attribs.Push(std::max(snd_channels, 2) - 1); + attribs.Push(max(snd_channels, 2) - 1); attribs.Push(ALC_STEREO_SOURCES); attribs.Push(1); if(ALC.SOFT_HRTF) @@ -587,6 +635,11 @@ OpenALSoundRenderer::OpenALSoundRenderer() else attribs.Push(ALC_DONT_CARE_SOFT); } + if(ALC.SOFT_output_limiter) + { + attribs.Push(ALC_OUTPUT_LIMITER_SOFT); + attribs.Push(ALC_TRUE); + } // Other attribs..? attribs.Push(0); @@ -620,6 +673,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() AL.EXT_SOURCE_RADIUS = !!alIsExtensionPresent("AL_EXT_SOURCE_RADIUS"); AL.SOFT_deferred_updates = !!alIsExtensionPresent("AL_SOFT_deferred_updates"); AL.SOFT_loop_points = !!alIsExtensionPresent("AL_SOFT_loop_points"); + AL.SOFT_source_latency = !!alIsExtensionPresent("AL_SOFT_source_latency"); AL.SOFT_source_resampler = !!alIsExtensionPresent("AL_SOFT_source_resampler"); AL.SOFT_source_spatialize = !!alIsExtensionPresent("AL_SOFT_source_spatialize"); @@ -647,6 +701,8 @@ OpenALSoundRenderer::OpenALSoundRenderer() alProcessUpdatesSOFT = _wrap_ProcessUpdatesSOFT; } + if(AL.SOFT_source_latency) + LOAD_FUNC(alGetSourcei64vSOFT); if(AL.SOFT_source_resampler) LOAD_FUNC(alGetStringiSOFT); @@ -676,7 +732,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() // At least Apple's OpenAL implementation returns zeroes, // although it can generate reasonable number of sources. - const int numChannels = std::max(snd_channels, 2); + const int numChannels = max(snd_channels, 2); int numSources = numMono + numStereo; if (0 == numSources) @@ -684,7 +740,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() numSources = numChannels; } - Sources.Resize(std::min(numChannels, numSources)); + Sources.Resize(min(numChannels, numSources)); for(unsigned i = 0;i < Sources.Size();i++) { alGenSources(1, &Sources[i]); @@ -1046,7 +1102,7 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata, int length, int return retval; } -SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length) +SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, int def_loop_start, int def_loop_end) { SoundHandle retval = { NULL }; ALenum format = AL_NONE; @@ -1056,7 +1112,16 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length) uint32_t loop_start = 0, loop_end = ~0u; zmusic_bool startass = false, endass = false; - FindLoopTags(sfxdata, length, &loop_start, &startass, &loop_end, &endass); + if (def_loop_start < 0) + { + FindLoopTags(sfxdata, length, &loop_start, &startass, &loop_end, &endass); + } + else + { + loop_start = def_loop_start; + loop_end = def_loop_end; + startass = endass = true; + } auto decoder = CreateDecoder(sfxdata, length, true); if (!decoder) return retval; @@ -1082,7 +1147,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length) return retval; } - std::vector data; + TArray data; unsigned total = 0; unsigned got; @@ -1093,6 +1158,10 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length) data.resize(total * 2); } data.resize(total); + if (total == 0) + { + return retval; + } SoundDecoder_Close(decoder); ALenum err; @@ -1167,7 +1236,7 @@ SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int return stream; } -FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan, float startTime) +FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, float pitch, int chanflags, FISoundChannel *reuse_chan, float startTime) { if(FreeSfx.Size() == 0) { @@ -1213,9 +1282,9 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); } if(WasInWater && !(chanflags&SNDF_NOREVERB)) - alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + alSourcef(source, AL_PITCH, pitch * PITCH_MULT); else - alSourcef(source, AL_PITCH, PITCH(pitch)); + alSourcef(source, AL_PITCH, pitch); if(!reuse_chan || reuse_chan->StartTime == 0) { @@ -1269,7 +1338,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int } FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, - FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, + FRolloffInfo *rolloff, float distscale, float pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime) { float dist_sqr = (float)(pos - listener->position).LengthSquared(); @@ -1295,7 +1364,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener if(AL.EXT_source_distance_model) alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); + alSourcef(source, AL_MAX_DISTANCE, std::numeric_limits::max()); alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); manualRolloff = false; } @@ -1315,77 +1384,49 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener // when AL_EXT_source_distance_model is not supported, we have to play // around a bit to get appropriate distance attenation. What we do is // calculate the attenuation that should be applied, then given an - // Inverse Distance rolloff model with OpenAL, reverse the calculation - // to get the distance needed for that much attenuation. The Inverse - // Distance calculation is: + // Inverse Distance rolloff model with OpenAL, calculate the reference + // distance that will achieve that much attenuation with the current + // distance. The Inverse Distance calculation is: // // Gain = MinDist / (MinDist + RolloffFactor*(Distance - MinDist)) // - // Thus, the reverse is: - // - // Distance = (MinDist/Gain - MinDist)/RolloffFactor + MinDist - // - // This can be simplified by using a MinDist and RolloffFactor of 1, - // which makes it: + // Simplifying for RolloffFactor=1, it can be broken down by: // - // Distance = 1.0f/Gain; + // Gain = MinDist / (MinDist + (Distance - MinDist)) + // Gain = MinDist / Distance + // Gain * Distance = MinDist // - // The source position is then set that many units away from the - // listener position, and OpenAL takes care of the rest. + // The source's reference distance is then set according to the desired + // gain and effective distance from the listener, and OpenAL takes care + // of the rest. if(AL.EXT_source_distance_model) alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); - alSourcef(source, AL_MAX_DISTANCE, 100000.f); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); - - if(AL.EXT_SOURCE_RADIUS) - { - /* Since the OpenAL distance is decoupled from the sound's distance, get the OpenAL - * distance that corresponds to the area radius. */ - float gain = GetRolloff(rolloff, AREA_SOUND_RADIUS); - alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? - // Clamp in case the max distance is <= the area radius - ((gain > 0.00001f) ? 1.f/gain : 100000.f) : 0.f - ); - } - if(dist_sqr < (0.0004f*0.0004f)) - { - // Head relative - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - float gain = GetRolloff(rolloff, sqrtf(dist_sqr) * distscale); - FVector3 dir = pos - listener->position; - dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); - dir += listener->position; + float dist = sqrtf(dist_sqr); + float gain = GetRolloff(rolloff, dist * distscale); + // Don't let the ref distance go to 0, or else distance attenuation is + // lost with the inverse distance model. + alSourcef(source, AL_REFERENCE_DISTANCE, max(gain*dist, 0.0004f)); + alSourcef(source, AL_MAX_DISTANCE, std::numeric_limits::max()); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + } - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - } + if(dist_sqr < (0.0004f*0.0004f)) + { + // Head relative + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); } else { - if(AL.EXT_SOURCE_RADIUS) - alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f); - - if(dist_sqr < (0.0004f*0.0004f)) - { - // Head relative - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); - } + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); } alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); alSourcef(source, AL_DOPPLER_FACTOR, 0.f); + if(AL.EXT_SOURCE_RADIUS) + alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f); alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); @@ -1409,13 +1450,16 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); } if(WasInWater && !(chanflags&SNDF_NOREVERB)) - alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + alSourcef(source, AL_PITCH, pitch * PITCH_MULT); else - alSourcef(source, AL_PITCH, PITCH(pitch)); + alSourcef(source, AL_PITCH, pitch); if(!reuse_chan || reuse_chan->StartTime == 0) { - float st = (chanflags & SNDF_LOOP) ? fmod(startTime, (float)GetMSLength(sfx) / 1000.f) : clamp(startTime, 0.f, (float)GetMSLength(sfx) / 1000.f); + float sfxlength = (float)GetMSLength(sfx) / 1000.f; + float st = (chanflags & SNDF_LOOP) + ? (sfxlength > 0 ? fmod(startTime, sfxlength) : 0) + : clamp(startTime, 0.f, sfxlength); alSourcef(source, AL_SEC_OFFSET, st); } else @@ -1482,9 +1526,9 @@ void OpenALSoundRenderer::ChannelPitch(FISoundChannel *chan, float pitch) ALuint source = GET_PTRID(chan->SysChannel); if (WasInWater && !(chan->ChanFlags & CHANF_UI)) - alSourcef(source, AL_PITCH, std::max(pitch, 0.0001f)*PITCH_MULT); + alSourcef(source, AL_PITCH, max(pitch, 0.0001f)*PITCH_MULT); else - alSourcef(source, AL_PITCH, std::max(pitch, 0.0001f)); + alSourcef(source, AL_PITCH, max(pitch, 0.0001f)); } void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) @@ -1508,6 +1552,9 @@ void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) if((i=SfxGroup.Find(source)) < SfxGroup.Size()) SfxGroup.Delete(i); + if (!(chan->ChanFlags & CHANF_EVICTED)) + soundEngine->SoundDone(chan); + FreeSfx.Push(source); } @@ -1618,8 +1665,7 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh if(chan == NULL || chan->SysChannel == NULL) return; - FVector3 dir = pos - listener->position; - float dist_sqr = (float)dir.LengthSquared(); + float dist_sqr = (float)(pos - listener->position).LengthSquared(); chan->DistanceSqr = dist_sqr; alDeferUpdatesSOFT(); @@ -1634,13 +1680,13 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh { if(chan->ManualRolloff) { - float gain = GetRolloff(&chan->Rolloff, sqrtf(dist_sqr)*chan->DistanceScale); - dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); + float dist = sqrtf(dist_sqr); + float gain = GetRolloff(&chan->Rolloff, dist * chan->DistanceScale); + alSourcef(source, AL_REFERENCE_DISTANCE, max(gain*dist, 0.0004f)); } - dir += listener->position; alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); } alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); getALError(); @@ -1690,7 +1736,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) const_cast(env)->Modified = false; } - + // NOTE: Moving into and out of water will undo pitch variations on sounds. if(listener->underwater || env->SoftwareWater) { @@ -1728,7 +1774,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) { ALuint source = GET_PTRID(schan->SysChannel); if (source && !(schan->ChanFlags & CHANF_UI)) - alSourcef(source, AL_PITCH, schan->Pitch / 128.0f * PITCH_MULT); + alSourcef(source, AL_PITCH, schan->Pitch * PITCH_MULT); schan = schan->NextChan; } getALError(); @@ -1736,7 +1782,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) } else if(WasInWater) { - + WasInWater = false; if(EnvSlot != 0) @@ -1766,7 +1812,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) { ALuint source = GET_PTRID(schan->SysChannel); if (source && !(schan->ChanFlags & CHANF_UI)) - alSourcef(source, AL_PITCH, schan->Pitch / 128.0f); + alSourcef(source, AL_PITCH, schan->Pitch); schan = schan->NextChan; } getALError(); @@ -2061,8 +2107,9 @@ FSoundChan *OpenALSoundRenderer::FindLowestChannel() return lowest; } +#endif // NO_OPENAL -#include "menu/menu.h" +#include "menu.h" void I_BuildALDeviceList(FOptionValues* opt) { @@ -2116,5 +2163,3 @@ void I_BuildALResamplersList(FOptionValues* opt) #endif } - -#endif // NO_OPENAL diff --git a/src/common/audio/sound/oalsound.h b/src/common/audio/sound/oalsound.h new file mode 100644 index 00000000000..6e5c93a87a6 --- /dev/null +++ b/src/common/audio/sound/oalsound.h @@ -0,0 +1,200 @@ +#ifndef OALSOUND_H +#define OALSOUND_H + +#include +#include +#include +#include +#include + +#include "i_sound.h" +#include "s_soundinternal.h" + +#ifndef NO_OPENAL + +#ifdef DYN_OPENAL +#define AL_NO_PROTOTYPES +#include "thirdparty/al.h" +#include "thirdparty/alc.h" +#else +#include "al.h" +#include "alc.h" +#endif + +#include "thirdparty/alext.h" + + +class OpenALSoundStream; + +class OpenALSoundRenderer : public SoundRenderer +{ +public: + OpenALSoundRenderer(); + virtual ~OpenALSoundRenderer(); + + virtual void SetSfxVolume(float volume); + virtual void SetMusicVolume(float volume); + virtual SoundHandle LoadSound(uint8_t *sfxdata, int length, int def_loop_start, int def_loop_end); + virtual SoundHandle LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1); + virtual void UnloadSound(SoundHandle sfx); + virtual unsigned int GetMSLength(SoundHandle sfx); + virtual unsigned int GetSampleLength(SoundHandle sfx); + virtual float GetOutputRate(); + + // Streaming sounds. + virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata); + + // Starts a sound. + FISoundChannel *StartSound(SoundHandle sfx, float vol, float pitch, int chanflags, FISoundChannel *reuse_chan, float startTime) override; + FISoundChannel *StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, float pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime) override; + + // Changes a channel's volume. + virtual void ChannelVolume(FISoundChannel *chan, float volume); + + // Changes a channel's pitch. + virtual void ChannelPitch(FISoundChannel *chan, float pitch); + + // Stops a sound channel. + virtual void StopChannel(FISoundChannel *chan); + + // Returns position of sound on this channel, in samples. + virtual unsigned int GetPosition(FISoundChannel *chan); + + // Synchronizes following sound startups. + virtual void Sync(bool sync); + + // Pauses or resumes all sound effect channels. + virtual void SetSfxPaused(bool paused, int slot); + + // Pauses or resumes *every* channel, including environmental reverb. + virtual void SetInactive(SoundRenderer::EInactiveState inactive); + + // Updates the volume, separation, and pitch of a sound channel. + virtual void UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel); + + virtual void UpdateListener(SoundListener *); + virtual void UpdateSounds(); + + virtual void MarkStartTime(FISoundChannel*, float startTime); + virtual float GetAudibility(FISoundChannel*); + + + virtual bool IsValid(); + virtual void PrintStatus(); + virtual void PrintDriversList(); + virtual FString GatherStats(); + +private: + struct { + bool EXT_EFX; + bool EXT_disconnect; + bool SOFT_HRTF; + bool SOFT_pause_device; + bool SOFT_output_limiter; + } ALC; + struct { + bool EXT_source_distance_model; + bool EXT_SOURCE_RADIUS; + bool SOFT_deferred_updates; + bool SOFT_loop_points; + bool SOFT_source_latency; + bool SOFT_source_resampler; + bool SOFT_source_spatialize; + } AL; + + // EFX Extension function pointer variables. Loaded after context creation + // if EFX is supported. These pointers may be context- or device-dependant, + // thus can't be static + // Effect objects + LPALGENEFFECTS alGenEffects; + LPALDELETEEFFECTS alDeleteEffects; + LPALISEFFECT alIsEffect; + LPALEFFECTI alEffecti; + LPALEFFECTIV alEffectiv; + LPALEFFECTF alEffectf; + LPALEFFECTFV alEffectfv; + LPALGETEFFECTI alGetEffecti; + LPALGETEFFECTIV alGetEffectiv; + LPALGETEFFECTF alGetEffectf; + LPALGETEFFECTFV alGetEffectfv; + // Filter objects + LPALGENFILTERS alGenFilters; + LPALDELETEFILTERS alDeleteFilters; + LPALISFILTER alIsFilter; + LPALFILTERI alFilteri; + LPALFILTERIV alFilteriv; + LPALFILTERF alFilterf; + LPALFILTERFV alFilterfv; + LPALGETFILTERI alGetFilteri; + LPALGETFILTERIV alGetFilteriv; + LPALGETFILTERF alGetFilterf; + LPALGETFILTERFV alGetFilterfv; + // Auxiliary slot objects + LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots; + LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots; + LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot; + LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti; + LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv; + LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf; + LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv; + LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti; + LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; + LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; + LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; + + ALvoid (AL_APIENTRY*alDeferUpdatesSOFT)(void); + ALvoid (AL_APIENTRY*alProcessUpdatesSOFT)(void); + + LPALGETSTRINGISOFT alGetStringiSOFT; + + LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT; + + void (ALC_APIENTRY*alcDevicePauseSOFT)(ALCdevice *device); + void (ALC_APIENTRY*alcDeviceResumeSOFT)(ALCdevice *device); + + void BackgroundProc(); + void AddStream(OpenALSoundStream *stream); + void RemoveStream(OpenALSoundStream *stream); + + void LoadReverb(const ReverbContainer *env); + void PurgeStoppedSources(); + static FSoundChan *FindLowestChannel(); + + std::thread StreamThread; + std::mutex StreamLock; + std::condition_variable StreamWake; + std::atomic QuitThread; + + ALCdevice *Device; + ALCcontext *Context; + + TArray Sources; + + ALfloat SfxVolume; + ALfloat MusicVolume; + + int SFXPaused; + TArray FreeSfx; + TArray PausableSfx; + TArray ReverbSfx; + TArray SfxGroup; + + const ReverbContainer *PrevEnvironment; + + typedef TMap EffectMap; + typedef TMapIterator EffectMapIter; + ALuint EnvSlot; + ALuint EnvFilters[2]; + EffectMap EnvEffects; + + bool WasInWater; + + TArray Streams; + friend class OpenALSoundStream; + + ALCdevice *InitDevice(); +}; + +#endif // NO_OPENAL + +#endif diff --git a/src/sound/s_environment.cpp b/src/common/audio/sound/s_environment.cpp similarity index 96% rename from src/sound/s_environment.cpp rename to src/common/audio/sound/s_environment.cpp index 276770f6caa..5b4ea79f1e9 100644 --- a/src/sound/s_environment.cpp +++ b/src/common/audio/sound/s_environment.cpp @@ -34,8 +34,8 @@ #include "s_soundinternal.h" #include "sc_man.h" -#include "templates.h" -#include "m_misc.h" + +#include "cmdlib.h" FReverbField ReverbFields[] = @@ -183,9 +183,31 @@ static ReverbContainer Underwater = false }; -static ReverbContainer SewerPipe = +static ReverbContainer SewerPipe3 = { &Underwater, + "Sewer Pipe 3", + 0x1503, + true, + false, + {0,21, 1.7f, 0.80f, -1000, -1000, 0, 1.54f, 0.14f, 1.0f, 200, 0.014f, 0.0f,0.0f,0.0f, 1023, 0.021f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f }, + false +}; + +static ReverbContainer SewerPipe2 = +{ + &SewerPipe3, + "Sewer Pipe 2", + 0x1502, + true, + false, + {0,21, 1.7f, 0.80f, -1000, -1000, 0, 1.81f, 0.14f, 1.0f, 229, 0.014f, 0.0f,0.0f,0.0f, 1023, 0.021f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f }, + false +}; + +static ReverbContainer SewerPipe = +{ + &SewerPipe2, "Sewer Pipe", 0x1500, true, @@ -508,7 +530,7 @@ void S_ReadReverbDef (FScanner &sc) { const ReverbContainer *def; ReverbContainer *newenv; - REVERB_PROPERTIES props; + REVERB_PROPERTIES props = {}; char *name; int id1, id2, i, j; bool inited[NUM_REVERB_FIELDS]; @@ -516,7 +538,7 @@ void S_ReadReverbDef (FScanner &sc) while (sc.GetString ()) { - name = strdup (sc.String); + name = copystring(sc.String); sc.MustGetNumber (); id1 = sc.Number; sc.MustGetNumber (); diff --git a/src/sound/s_reverbedit.cpp b/src/common/audio/sound/s_reverbedit.cpp similarity index 96% rename from src/sound/s_reverbedit.cpp rename to src/common/audio/sound/s_reverbedit.cpp index 7c41b10eb3d..4c01da23a27 100644 --- a/src/sound/s_reverbedit.cpp +++ b/src/common/audio/sound/s_reverbedit.cpp @@ -33,20 +33,19 @@ ** */ -#include "doomtype.h" -#include "s_sound.h" +#include "s_soundinternal.h" #include "sc_man.h" #include "cmdlib.h" -#include "templates.h" -#include "w_wad.h" -#include "i_system.h" -#include "m_misc.h" +#include "filesystem.h" +#include "i_system.h" +#include "printf.h" +#include "i_specialpaths.h" #include "c_cvars.h" #include "c_dispatch.h" #include "vm.h" #include "dobject.h" -#include "menu/menu.h" +#include "menu.h" void S_ReadReverbDef (FScanner &sc); @@ -228,7 +227,7 @@ void ExportEnvironments(const char *filename, uint32_t count, const ReverbContai { FString dest = M_GetDocumentsPath() + filename; - FileWriter *f = FileWriter::Open(dest); + FileWriter *f = FileWriter::Open(dest.GetChars()); if (f != nullptr) { @@ -310,7 +309,6 @@ DEFINE_ACTION_FUNCTION(DReverbEdit, GetValue) } } ACTION_RETURN_FLOAT(v); - return 1; } DEFINE_ACTION_FUNCTION(DReverbEdit, SetValue) @@ -338,14 +336,12 @@ DEFINE_ACTION_FUNCTION(DReverbEdit, SetValue) } ACTION_RETURN_FLOAT(v); - return 1; } DEFINE_ACTION_FUNCTION(DReverbEdit, GrayCheck) { PARAM_PROLOGUE; ACTION_RETURN_BOOL(CurrentEnv->Builtin); - return 1; } DEFINE_ACTION_FUNCTION(DReverbEdit, GetSelectedEnvironment) @@ -473,12 +469,12 @@ static void SelectEnvironment(const char *envname) int newid = FirstFreeID(env->ID, env->Builtin); UCVarValue cv; cv.Int = HIBYTE(newid); - reverbedit_id1.ForceSet(cv, CVAR_Int); + reverbedit_id1->ForceSet(cv, CVAR_Int); cv.Int = LOBYTE(newid); - reverbedit_id2.ForceSet(cv, CVAR_Int); + reverbedit_id2->ForceSet(cv, CVAR_Int); FString selectname = SuggestNewName(env); cv.String = selectname.GetChars(); - reverbedit_name.ForceSet(cv, CVAR_String); + reverbedit_name->ForceSet(cv, CVAR_String); return; } } @@ -513,13 +509,13 @@ CCMD(createenvironment) { if (S_FindEnvironment(reverbedit_name)) { - M_StartMessage(FStringf("An environment with the name '%s' already exists", *reverbedit_name), 1); + M_StartMessage(FStringf("An environment with the name '%s' already exists", *reverbedit_name).GetChars(), 1); return; } int id = (reverbedit_id1 << 8) + reverbedit_id2; if (S_FindEnvironment(id)) { - M_StartMessage(FStringf("An environment with the ID (%d, %d) already exists", *reverbedit_id1, *reverbedit_id2), 1); + M_StartMessage(FStringf("An environment with the ID (%d, %d) already exists", *reverbedit_id1, *reverbedit_id2).GetChars(), 1); return; } @@ -543,7 +539,7 @@ void S_ParseReverbDef () { int lump, lastlump = 0; - while ((lump = Wads.FindLump ("REVERBS", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("REVERBS", &lastlump)) != -1) { FScanner sc; sc.OpenLumpNum(lump); diff --git a/src/sound/s_sound.cpp b/src/common/audio/sound/s_sound.cpp similarity index 75% rename from src/sound/s_sound.cpp rename to src/common/audio/sound/s_sound.cpp index a3250582e28..852d389f5ac 100644 --- a/src/sound/s_sound.cpp +++ b/src/common/audio/sound/s_sound.cpp @@ -36,19 +36,33 @@ #include #include -#include "templates.h" + #include "s_soundinternal.h" #include "m_swap.h" #include "superfasthash.h" - +#include "s_music.h" +#include "m_random.h" +#include "printf.h" +#include "c_cvars.h" +#include "gamestate.h" + +CVARD(Bool, snd_enabled, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enables/disables sound effects") +CVAR(Bool, i_soundinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, i_pauseinbackground, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +// killough 2/21/98: optionally use varying pitched sounds +CVAR(Bool, snd_pitched, false, CVAR_ARCHIVE) + +int SoundEnabled() +{ + return snd_enabled && !nosound && !nosfx; +} enum { DEFAULT_PITCH = 128, }; - +static FRandom pr_soundpitch ("SoundPitch"); SoundEngine* soundEngine; -int sfx_empty = -1; //========================================================================== // @@ -58,6 +72,7 @@ int sfx_empty = -1; void SoundEngine::Init(TArray &curve) { + StopAllChannels(); // Free all channels for use. while (Channels != NULL) { @@ -76,7 +91,7 @@ void SoundEngine::Clear() { StopAllChannels(); UnloadAllSounds(); - GetSounds().Clear(); + S_sfx.Clear(); ClearRandoms(); } @@ -106,11 +121,11 @@ void SoundEngine::Shutdown () // //========================================================================== -void SoundEngine::MarkUsed(int id) +void SoundEngine::MarkUsed(FSoundID sid) { - if ((unsigned)id < S_sfx.Size()) + if (isValidSoundId(sid)) { - S_sfx[id].bUsed = true; + S_sfx[sid.index()].bUsed = true; } } @@ -152,16 +167,11 @@ void SoundEngine::CacheMarkedSounds() void SoundEngine::CacheSound (sfxinfo_t *sfx) { - if (GSnd) + if (GSnd && !sfx->bTentative) { - if (sfx->bPlayerReserve) + while (!sfx->bRandomHeader && isValidSoundId(sfx->link)) { - return; - } - sfxinfo_t *orig = sfx; - while (!sfx->bRandomHeader && sfx->link != sfxinfo_t::NO_LINK) - { - sfx = &S_sfx[sfx->link]; + sfx = &S_sfx[sfx->link.index()]; } if (sfx->bRandomHeader) { @@ -184,7 +194,10 @@ void SoundEngine::CacheSound (sfxinfo_t *sfx) void SoundEngine::UnloadSound (sfxinfo_t *sfx) { if (sfx->data.isValid()) + { GSnd->UnloadSound(sfx->data); + DPrintf(DMSG_NOTIFY, "Unloaded sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); + } sfx->data.Clear(); } @@ -277,7 +290,7 @@ TArray SoundEngine::AllActiveChannels() // If the sound is forgettable, this is as good a time as // any to forget about it. And if it's a UI sound, it shouldn't // be stored in the savegame. - if (!(chan->ChanFlags & (CHANF_FORGETTABLE | CHANF_UI))) + if (!(chan->ChanFlags & (CHANF_FORGETTABLE | CHANF_UI | CHANF_TRANSIENT))) { chans.Push(chan); } @@ -304,7 +317,7 @@ FString SoundEngine::ListSoundChannels() CalcPosVel(chan, &chanorigin, nullptr); - output.AppendFormat("%s at (%1.5f, %1.5f, %1.5f)\n", (const char*)S_sfx[chan->SoundID].name.GetChars(), chanorigin.X, chanorigin.Y, chanorigin.Z); + output.AppendFormat("%s at (%1.5f, %1.5f, %1.5f)\n", (const char*)S_sfx[chan->SoundID.index()].name.GetChars(), chanorigin.X, chanorigin.Y, chanorigin.Z); count++; } } @@ -343,7 +356,7 @@ bool SoundEngine::ValidatePosVel(const FSoundChan* const chan, const FVector3& p FSoundID SoundEngine::ResolveSound(const void *, int, FSoundID soundid, float &attenuation) { - const sfxinfo_t &sfx = S_sfx[soundid]; + const sfxinfo_t &sfx = S_sfx[soundid.index()]; if (sfx.bRandomHeader) { @@ -357,6 +370,31 @@ FSoundID SoundEngine::ResolveSound(const void *, int, FSoundID soundid, float &a } } +//========================================================================== +// +// +// +//========================================================================== + +static float CalcPitch(int pitchmask, float defpitch, float defpitchmax) +{ + if (defpitch > 0.0) // $PitchSet overrides $PitchShift + { + if (defpitchmax > 0.0 && defpitch != defpitchmax) + { + defpitch = (float)pr_soundpitch.GenRand_Real1() * (defpitchmax - defpitch) + defpitch; + } + return defpitch; + } + + // Vary the sfx pitches. Overridden by $PitchSet and A_StartSound. + if (pitchmask != 0 && snd_pitched) + { + return (DEFAULT_PITCH - (pr_soundpitch() & pitchmask) + (pr_soundpitch() & pitchmask)) / (float)DEFAULT_PITCH; + } + return 1.f; +} + //========================================================================== // // S_StartSound @@ -374,13 +412,12 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, sfxinfo_t *sfx; EChanFlags chanflags = flags; int basepriority; - int org_id; - int pitch; + FSoundID org_id; FSoundChan *chan; FVector3 pos, vel; FRolloffInfo *rolloff; - if (sound_id <= 0 || volume <= 0 || nosfx || nosound ) + if (!isValidSoundId(sound_id) || volume <= 0 || nosfx || !SoundEnabled() || blockNewSounds) return NULL; // prevent crashes. @@ -394,11 +431,11 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, { return nullptr; } - - sfx = &S_sfx[sound_id]; + + sfx = &S_sfx[sound_id.index()]; // Scale volume according to SNDINFO data. - volume = std::min(volume * sfx->Volume, 1.f); + volume = min(volume * sfx->Volume, 1.f); if (volume <= 0) return NULL; @@ -406,21 +443,24 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, // the referenced sound so some additional checks are required int near_limit = sfx->NearLimit; float limit_range = sfx->LimitRange; - auto pitchmask = sfx->PitchMask; + float defpitch = sfx->DefPitch; + float defpitchmax = sfx->DefPitchMax; rolloff = &sfx->Rolloff; // Resolve player sounds, random sounds, and aliases while (sfx->link != sfxinfo_t::NO_LINK) { sound_id = ResolveSound(source, type, sound_id, attenuation); - if (sound_id < 0) return nullptr; - auto newsfx = &S_sfx[sound_id]; + if (!isValidSoundId(sound_id)) return nullptr; + auto newsfx = &S_sfx[sound_id.index()]; if (newsfx != sfx) { if (near_limit < 0) { near_limit = newsfx->NearLimit; limit_range = newsfx->LimitRange; + defpitch = newsfx->DefPitch; + defpitchmax = newsfx->DefPitchMax; } if (rolloff->MinDistance == 0) { @@ -448,7 +488,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, } // If this is a singular sound, don't play it if it's already playing. - if (sfx->bSingular && CheckSingular(sound_id)) + if ((sfx->bSingular || (flags & CHANF_SINGULAR)) && CheckSingular(sound_id)) { chanflags |= CHANF_EVICTED; } @@ -460,9 +500,8 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, near_limit = 0; } - // If this sound doesn't like playing near itself, don't play it if - // that's what would happen. (Does this really need the SOURCE_Actor restriction?) - if (near_limit > 0 && CheckSoundLimit(sfx, pos, near_limit, limit_range, type, type == SOURCE_Actor? source : nullptr, channel)) + // If this sound doesn't like playing near itself, don't play it if that's what would happen. + if (near_limit > 0 && CheckSoundLimit(sfx, pos, near_limit, limit_range, type, source, channel, attenuation)) { chanflags |= CHANF_EVICTED; } @@ -497,26 +536,9 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, int seen = 0; if (source != NULL && channel == CHAN_AUTO) { - // Select a channel that isn't already playing something. - // Try channel 0 first, then travel from channel 7 down. - if (!IsChannelUsed(type, source, 0, &seen)) - { - channel = 0; - } - else - { - for (channel = 7; channel > 0; --channel) - { - if (!IsChannelUsed(type, source, channel, &seen)) - { - break; - } - } - if (channel == 0) - { // Crap. No free channels. - return NULL; - } - } + // In the old sound system, 'AUTO' hijacked one of the other channels. + // Now, with CHANF_OVERLAP at our disposal that isn't needed anymore. Just set the flag and let all sounds play on channel 0. + chanflags |= CHANF_OVERLAP; } // If this actor is already playing something on the selected channel, stop it. @@ -540,21 +562,12 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, // sound is paused and a non-looped sound is being started. // Such a sound would play right after unpausing which wouldn't sound right. - if (!(chanflags & CHANF_LOOP) && !(chanflags & (CHANF_UI|CHANF_NOPAUSE)) && SoundPaused) + if (!(chanflags & CHANF_LOOP) && !(chanflags & (CHANF_UI|CHANF_NOPAUSE|CHANF_FORCE)) && SoundPaused) { return NULL; } - // Vary the sfx pitches. - if (pitchmask != 0) - { - pitch = DEFAULT_PITCH - (rand() & pitchmask) + (rand() & pitchmask); - } - else - { - pitch = DEFAULT_PITCH; - } - + float pitch = spitch > 0 ? spitch : CalcPitch(sfx->PitchMask, defpitch, defpitchmax); if (chanflags & CHANF_EVICTED) { chan = NULL; @@ -567,9 +580,10 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, if (chanflags & (CHANF_UI|CHANF_NOPAUSE)) startflags |= SNDF_NOPAUSE; if (chanflags & CHANF_UI) startflags |= SNDF_NOREVERB; + float sfxlength = (float)GSnd->GetMSLength(sfx->data) / 1000.f; startTime = (startflags & SNDF_LOOP) - ? fmod(startTime, (float)GSnd->GetMSLength(sfx->data) / 1000.f) - : clamp(startTime, 0.f, (float)GSnd->GetMSLength(sfx->data) / 1000.f); + ? (sfxlength > 0 ? fmodf(startTime, sfxlength) : 0.f) + : clamp(startTime, 0.f, sfxlength); if (attenuation > 0 && type != SOURCE_None) { @@ -586,7 +600,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, GSnd->MarkStartTime(chan); chanflags |= CHANF_EVICTED; } - if (attenuation > 0) + if (attenuation > 0 && type != SOURCE_None) { chanflags |= CHANF_IS3D | CHANF_JUSTSTARTED; } @@ -597,7 +611,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, if (chan != NULL) { chan->SoundID = sound_id; - chan->OrgID = FSoundID(org_id); + chan->OrgID = org_id; chan->EntChannel = channel; chan->Volume = float(volume); chan->ChanFlags |= chanflags; @@ -607,6 +621,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, chan->Priority = basepriority; chan->DistanceScale = float(attenuation); chan->SourceType = type; + chan->UserData = 0; if (type == SOURCE_Unattached) { chan->Point[0] = pt->X; chan->Point[1] = pt->Y; chan->Point[2] = pt->Z; @@ -615,9 +630,6 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, { chan->Source = source; } - - if (spitch > 0.0) - SetPitch(chan, spitch); } return chan; @@ -636,7 +648,7 @@ void SoundEngine::RestartChannel(FSoundChan *chan) assert(chan->ChanFlags & CHANF_EVICTED); FSoundChan *ochan; - sfxinfo_t *sfx = &S_sfx[chan->SoundID]; + sfxinfo_t *sfx = &S_sfx[chan->SoundID.index()]; // If this is a singular sound, don't play it if it's already playing. if (sfx->bSingular && CheckSingular(chan->SoundID)) @@ -671,7 +683,7 @@ void SoundEngine::RestartChannel(FSoundChan *chan) // If this sound doesn't like playing near itself, don't play it if // that's what would happen. - if (chan->NearLimit > 0 && CheckSoundLimit(&S_sfx[chan->SoundID], pos, chan->NearLimit, chan->LimitRange, 0, NULL, 0)) + if (chan->NearLimit > 0 && CheckSoundLimit(&S_sfx[chan->SoundID.index()], pos, chan->NearLimit, chan->LimitRange, 0, NULL, 0, chan->DistanceScale)) { return; } @@ -708,12 +720,11 @@ sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx) { unsigned int i; - // If the sound doesn't exist, replace it with the empty sound. - if (sfx->lumpnum == -1) + if (sfx->lumpnum == sfx_empty) { - sfx->lumpnum = sfx_empty; + return sfx; } - + // See if there is another sound already initialized with this lump. If so, // then set this one up as a link, and don't load the sound again. for (i = 0; i < S_sfx.Size(); i++) @@ -721,8 +732,8 @@ sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx) if (S_sfx[i].data.isValid() && S_sfx[i].link == sfxinfo_t::NO_LINK && S_sfx[i].lumpnum == sfx->lumpnum && (!sfx->bLoadRAW || (sfx->RawRate == S_sfx[i].RawRate))) // Raw sounds with different sample rates may not share buffers, even if they use the same source data. { - //DPrintf (DMSG_NOTIFY, "Linked %s to %s (%d)\n", sfx->name.GetChars(), S_sfx[i].name.GetChars(), i); - sfx->link = i; + DPrintf (DMSG_NOTIFY, "Linked %s to %s (%d)\n", sfx->name.GetChars(), S_sfx[i].name.GetChars(), i); + sfx->link = FSoundID::fromInt(i); // This is necessary to avoid using the rolloff settings of the linked sound if its // settings are different. if (sfx->Rolloff.MinDistance == 0) sfx->Rolloff = S_Rolloff; @@ -730,35 +741,35 @@ sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx) } } - //DPrintf(DMSG_NOTIFY, "Loading sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); + DPrintf(DMSG_NOTIFY, "Loading sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]); auto sfxdata = ReadSound(sfx->lumpnum); - int size = sfxdata.Size(); + int size = (int)sfxdata.size(); if (size > 8) { - int32_t dmxlen = LittleLong(((int32_t *)sfxdata.Data())[1]); - + auto sfxp = sfxdata.data(); + int32_t dmxlen = LittleLong(((int32_t *)sfxp)[1]); // If the sound is voc, use the custom loader. - if (strncmp ((const char *)sfxdata.Data(), "Creative Voice File", 19) == 0) + if (size > 19 && memcmp (sfxp, "Creative Voice File", 19) == 0) { - sfx->data = GSnd->LoadSoundVoc(sfxdata.Data(), size); + sfx->data = GSnd->LoadSoundVoc(sfxp, size); } // If the sound is raw, just load it as such. else if (sfx->bLoadRAW) { - sfx->data = GSnd->LoadSoundRaw(sfxdata.Data(), size, sfx->RawRate, 1, 8, sfx->LoopStart); + sfx->data = GSnd->LoadSoundRaw(sfxp, size, sfx->RawRate, 1, 8, sfx->LoopStart); } // Otherwise, try the sound as DMX format. - else if (((uint8_t *)sfxdata.Data())[0] == 3 && ((uint8_t *)sfxdata.Data())[1] == 0 && dmxlen <= size - 8) + else if (((uint8_t *)sfxp)[0] == 3 && ((uint8_t *)sfxp)[1] == 0 && dmxlen <= size - 8) { - int frequency = LittleShort(((uint16_t *)sfxdata.Data())[1]); + int frequency = LittleShort(((uint16_t *)sfxp)[1]); if (frequency == 0) frequency = 11025; - sfx->data = GSnd->LoadSoundRaw(sfxdata.Data()+8, dmxlen, frequency, 1, 8, sfx->LoopStart); + sfx->data = GSnd->LoadSoundRaw(sfxp+8, dmxlen, frequency, 1, 8, sfx->LoopStart); } // If that fails, let the sound system try and figure it out. else { - sfx->data = GSnd->LoadSound(sfxdata.Data(), size); + sfx->data = GSnd->LoadSound(sfxp, size, sfx->LoopStart, sfx->LoopEnd); } } @@ -783,7 +794,7 @@ sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx) // //========================================================================== -bool SoundEngine::CheckSingular(int sound_id) +bool SoundEngine::CheckSingular(FSoundID sound_id) { for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) { @@ -813,15 +824,15 @@ bool SoundEngine::CheckSingular(int sound_id) //========================================================================== bool SoundEngine::CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_limit, float limit_range, - int sourcetype, const void *actor, int channel) + int sourcetype, const void *actor, int channel, float attenuation) { FSoundChan *chan; int count; - + for (chan = Channels, count = 0; chan != NULL && count < near_limit; chan = chan->NextChan) { if (chan->ChanFlags & CHANF_FORGETTABLE) continue; - if (!(chan->ChanFlags & CHANF_EVICTED) && &S_sfx[chan->SoundID] == sfx) + if (!(chan->ChanFlags & CHANF_EVICTED) && &S_sfx[chan->SoundID.index()] == sfx) { FVector3 chanorigin; @@ -832,7 +843,9 @@ bool SoundEngine::CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_ } CalcPosVel(chan, &chanorigin, NULL); - if ((chanorigin - pos).LengthSquared() <= limit_range) + // scale the limit distance with the attenuation. An attenuation of 0 means the limit distance is infinite and all sounds within the level are inside the limit. + float attn = min(chan->DistanceScale, attenuation); + if (attn <= 0 || (chanorigin - pos).LengthSquared() <= limit_range / attn) { count++; } @@ -849,7 +862,7 @@ bool SoundEngine::CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_ // //========================================================================== -void SoundEngine::StopSoundID(int sound_id) +void SoundEngine::StopSoundID(FSoundID sound_id) { FSoundChan* chan = Channels; while (chan != NULL) @@ -871,13 +884,13 @@ void SoundEngine::StopSoundID(int sound_id) // //========================================================================== -void SoundEngine::StopSound (int channel, int sound_id) +void SoundEngine::StopSound (int channel, FSoundID sound_id) { FSoundChan *chan = Channels; while (chan != NULL) { FSoundChan *next = chan->NextChan; - if ((chan->SourceType == SOURCE_None && (sound_id == -1 || sound_id == chan->OrgID)) && (channel == CHAN_AUTO || channel == chan->EntChannel)) + if ((chan->SourceType == SOURCE_None && (sound_id == INVALID_SOUND || sound_id == chan->OrgID)) && (channel == CHAN_AUTO || channel == chan->EntChannel)) { StopChannel(chan); } @@ -893,7 +906,7 @@ void SoundEngine::StopSound (int channel, int sound_id) // //========================================================================== -void SoundEngine::StopSound(int sourcetype, const void* actor, int channel, int sound_id) +void SoundEngine::StopSound(int sourcetype, const void* actor, int channel, FSoundID sound_id) { FSoundChan* chan = Channels; while (chan != NULL) @@ -901,7 +914,7 @@ void SoundEngine::StopSound(int sourcetype, const void* actor, int channel, int FSoundChan* next = chan->NextChan; if (chan->SourceType == sourcetype && chan->Source == actor && - (sound_id == -1? (chan->EntChannel == channel || channel < 0) : (chan->OrgID == sound_id))) + (sound_id == INVALID_SOUND? (chan->EntChannel == channel || channel < 0) : (chan->OrgID == sound_id))) { StopChannel(chan); } @@ -920,12 +933,7 @@ void SoundEngine::StopSound(int sourcetype, const void* actor, int channel, int void SoundEngine::StopActorSounds(int sourcetype, const void* actor, int chanmin, int chanmax) { const bool all = (chanmin == 0 && chanmax == 0); - if (!all && chanmax > chanmin) - { - const int temp = chanmax; - chanmax = chanmin; - chanmin = temp; - } + if (chanmax < chanmin) std::swap(chanmin, chanmax); FSoundChan* chan = Channels; while (chan != nullptr) @@ -1046,13 +1054,13 @@ void SoundEngine::SetVolume(FSoundChan* chan, float volume) // //========================================================================== -void SoundEngine::ChangeSoundPitch(int sourcetype, const void *source, int channel, double pitch, int sound_id) +void SoundEngine::ChangeSoundPitch(int sourcetype, const void *source, int channel, double pitch, FSoundID sound_id) { for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) { if (chan->SourceType == sourcetype && chan->Source == source && - (sound_id == -1? (chan->EntChannel == channel) : (chan->OrgID == sound_id))) + (sound_id == INVALID_SOUND? (chan->EntChannel == channel) : (chan->OrgID == sound_id))) { SetPitch(chan, (float)pitch); } @@ -1063,8 +1071,8 @@ void SoundEngine::ChangeSoundPitch(int sourcetype, const void *source, int chann void SoundEngine::SetPitch(FSoundChan *chan, float pitch) { assert(chan != nullptr); - GSnd->ChannelPitch(chan, std::max(0.0001f, pitch)); - chan->Pitch = std::max(1, int(float(DEFAULT_PITCH) * pitch)); + GSnd->ChannelPitch(chan, max(0.0001f, pitch)); + chan->Pitch = pitch; } //========================================================================== @@ -1074,13 +1082,14 @@ void SoundEngine::SetPitch(FSoundChan *chan, float pitch) // Is a sound being played by a specific emitter? //========================================================================== -int SoundEngine::GetSoundPlayingInfo (int sourcetype, const void *source, int sound_id) +int SoundEngine::GetSoundPlayingInfo (int sourcetype, const void *source, FSoundID sound_id, int chann) { int count = 0; - if (sound_id > 0) + if (sound_id.isvalid()) { for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) { + if (chann != -1 && chann != chan->EntChannel) continue; if (chan->OrgID == sound_id && (sourcetype == SOURCE_Any || (chan->SourceType == sourcetype && chan->Source == source))) @@ -1089,6 +1098,17 @@ int SoundEngine::GetSoundPlayingInfo (int sourcetype, const void *source, int so } } } + else + { + for (FSoundChan* chan = Channels; chan != NULL; chan = chan->NextChan) + { + if (chann != -1 && chann != chan->EntChannel) continue; + if ((sourcetype == SOURCE_Any || (chan->SourceType == sourcetype && chan->Source == source))) + { + count++; + } + } + } return count; } @@ -1128,13 +1148,13 @@ bool SoundEngine::IsChannelUsed(int sourcetype, const void *actor, int channel, // //========================================================================== -bool SoundEngine::IsSourcePlayingSomething (int sourcetype, const void *actor, int channel, int sound_id) +bool SoundEngine::IsSourcePlayingSomething (int sourcetype, const void *actor, int channel, FSoundID sound_id) { for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) { if (chan->SourceType == sourcetype && (sourcetype == SOURCE_None || sourcetype == SOURCE_Unattached || chan->Source == actor)) { - if ((channel == 0 || chan->EntChannel == channel) && (sound_id <= 0 || chan->OrgID == sound_id)) + if ((channel == 0 || chan->EntChannel == channel) && (sound_id == INVALID_SOUND || chan->OrgID == sound_id)) { return true; } @@ -1330,7 +1350,7 @@ void SoundEngine::ChannelEnded(FISoundChannel *ichan) else { unsigned int pos = GSnd->GetPosition(schan); - unsigned int len = GSnd->GetSampleLength(S_sfx[schan->SoundID].data); + unsigned int len = GSnd->GetSampleLength(S_sfx[schan->SoundID.index()].data); if (pos == 0) { evicted = !!(schan->ChanFlags & CHANF_JUSTSTARTED); @@ -1342,13 +1362,29 @@ void SoundEngine::ChannelEnded(FISoundChannel *ichan) } if (!evicted) { - ReturnChannel(schan); + schan->ChanFlags &= ~CHANF_EVICTED; } else { schan->ChanFlags |= CHANF_EVICTED; schan->SysChannel = NULL; } + + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void SoundEngine::SoundDone(FISoundChannel* ichan) +{ + FSoundChan* schan = static_cast(ichan); + if (schan != NULL) + { + ReturnChannel(schan); } } @@ -1389,10 +1425,6 @@ void SoundEngine::StopChannel(FSoundChan *chan) if (!(chan->ChanFlags & CHANF_EVICTED)) { chan->ChanFlags |= CHANF_FORGETTABLE; - if (chan->SourceType == SOURCE_Actor) - { - chan->Source = NULL; - } } if (GSnd) GSnd->StopChannel(chan); } @@ -1426,29 +1458,19 @@ void SoundEngine::Reset() // Given a logical name, find the sound's index in S_sfx. //========================================================================== -int SoundEngine::FindSound(const char* logicalname) +FSoundID SoundEngine::FindSound(const char* logicalname) { - int i; - - if (logicalname != NULL) - { - i = S_sfx[MakeKey(logicalname) % S_sfx.Size()].index; - - while ((i != 0) && stricmp(S_sfx[i].name, logicalname)) - i = S_sfx[i].next; - - return i; - } - else - { - return 0; - } + if (!logicalname) return NO_SOUND; + FName name(logicalname, true); + if (name == NAME_None) return NO_SOUND; + auto p = SoundMap.CheckKey(name); + return p ? *p : NO_SOUND; } -int SoundEngine::FindSoundByResID(int resid) +FSoundID SoundEngine::FindSoundByResID(int resid) { auto p = ResIdMap.CheckKey(resid); - return p ? *p : 0; + return p ? *p : NO_SOUND; } //========================================================================== @@ -1459,18 +1481,41 @@ int SoundEngine::FindSoundByResID(int resid) // using the hash table. //========================================================================== -int SoundEngine::FindSoundNoHash(const char* logicalname) +FSoundID SoundEngine::FindSoundNoHash(const char* logicalname) +{ + if (!logicalname) return NO_SOUND; + FName name(logicalname, true); + if (name == NAME_None) return NO_SOUND; + + for (unsigned i = 1; i < S_sfx.Size(); i++) + { + if (S_sfx[i].name == name) + { + return FSoundID::fromInt(i); + } + } + return NO_SOUND; +} + +//========================================================================== +// +// S_FindSoundByResIDNoHash +// +// same with resource IDs. +//========================================================================== + +FSoundID SoundEngine::FindSoundByResIDNoHash(int resid) { unsigned int i; for (i = 1; i < S_sfx.Size(); i++) { - if (stricmp(S_sfx[i].name, logicalname) == 0) + if (S_sfx[i].ResourceId == resid) { - return i; + return FSoundID::fromInt(i); } } - return 0; + return NO_SOUND; } //========================================================================== @@ -1480,7 +1525,7 @@ int SoundEngine::FindSoundNoHash(const char* logicalname) // Given a sound lump, find the sound's index in S_sfx. //========================================================================== -int SoundEngine::FindSoundByLump(int lump) +FSoundID SoundEngine::FindSoundByLump(int lump) { if (lump != -1) { @@ -1488,9 +1533,9 @@ int SoundEngine::FindSoundByLump(int lump) for (i = 1; i < S_sfx.Size(); i++) if (S_sfx[i].lumpnum == lump) - return i; + return FSoundID::fromInt(i); } - return 0; + return NO_SOUND; } //========================================================================== @@ -1500,47 +1545,19 @@ int SoundEngine::FindSoundByLump(int lump) // Adds a new sound mapping to S_sfx. //========================================================================== -int SoundEngine::AddSoundLump(const char* logicalname, int lump, int CurrentPitchMask, int resid, int nearlimit) +FSoundID SoundEngine::AddSoundLump(const char* logicalname, int lump, int CurrentPitchMask, int resid, int nearlimit) { S_sfx.Reserve(1); sfxinfo_t &newsfx = S_sfx.Last(); - newsfx.data.Clear(); newsfx.name = logicalname; newsfx.lumpnum = lump; - newsfx.next = 0; - newsfx.index = 0; - newsfx.Volume = 1; - newsfx.Attenuation = 1; newsfx.PitchMask = CurrentPitchMask; newsfx.NearLimit = nearlimit; - newsfx.LimitRange = 256 * 256; - newsfx.bRandomHeader = false; - newsfx.bPlayerReserve = false; - newsfx.bLoadRAW = false; - newsfx.bPlayerCompat = false; - newsfx.b16bit = false; - newsfx.bUsed = false; - newsfx.bSingular = false; - newsfx.bTentative = false; - newsfx.bPlayerSilent = false; newsfx.ResourceId = resid; - newsfx.RawRate = 0; - newsfx.link = sfxinfo_t::NO_LINK; - newsfx.Rolloff.RolloffType = ROLLOFF_Doom; - newsfx.Rolloff.MinDistance = 0; - newsfx.Rolloff.MaxDistance = 0; - newsfx.LoopStart = -1; - - if (resid >= 0) ResIdMap[resid] = S_sfx.Size() - 1; - return (int)S_sfx.Size()-1; -} - -int SoundEngine::AddSfx(sfxinfo_t &sfx) -{ - S_sfx.Push(sfx); - if (sfx.ResourceId >= 0) ResIdMap[sfx.ResourceId] = S_sfx.Size() - 1; - return (int)S_sfx.Size() - 1; + newsfx.bTentative = false; + auto id = FSoundID::fromInt(S_sfx.Size() - 1); + return id; } @@ -1553,13 +1570,13 @@ int SoundEngine::AddSfx(sfxinfo_t &sfx) // an associated lump is created. //========================================================================== -int SoundEngine::FindSoundTentative(const char* name) +FSoundID SoundEngine::FindSoundTentative(const char* name, int nearlimit) { - int id = FindSoundNoHash(name); - if (id == 0) + auto id = FindSoundNoHash(name); + if (id == NO_SOUND) { - id = AddSoundLump(name, -1, 0); - S_sfx[id].bTentative = true; + id = AddSoundLump(name, -1, 0, -1, nearlimit); + S_sfx[id.index()].bTentative = true; } return id; } @@ -1577,12 +1594,12 @@ void SoundEngine::CacheRandomSound(sfxinfo_t* sfx) { if (sfx->bRandomHeader) { - const FRandomSoundList* list = &S_rnd[sfx->link]; + const FRandomSoundList* list = &S_rnd[sfx->link.index()]; for (unsigned i = 0; i < list->Choices.Size(); ++i) { - sfx = &S_sfx[list->Choices[i]]; + sfx = &S_sfx[list->Choices[i].index()]; sfx->bUsed = true; - CacheSound(&S_sfx[list->Choices[i]]); + CacheSound(&S_sfx[list->Choices[i].index()]); } } } @@ -1598,12 +1615,12 @@ void SoundEngine::CacheRandomSound(sfxinfo_t* sfx) unsigned int SoundEngine::GetMSLength(FSoundID sound) { - if ((unsigned int)sound >= S_sfx.Size()) + if (!isValidSoundId(sound)) { return 0; } - sfxinfo_t* sfx = &S_sfx[sound]; + sfxinfo_t* sfx = &S_sfx[sound.index()]; // Resolve player sounds, random sounds, and aliases if (sfx->link != sfxinfo_t::NO_LINK) @@ -1615,7 +1632,7 @@ unsigned int SoundEngine::GetMSLength(FSoundID sound) // I think the longest one makes more sense. int length = 0; - const FRandomSoundList* list = &S_rnd[sfx->link]; + const FRandomSoundList* list = &S_rnd[sfx->link.index()]; for (auto& me : list->Choices) { @@ -1627,7 +1644,7 @@ unsigned int SoundEngine::GetMSLength(FSoundID sound) } else { - sfx = &S_sfx[sfx->link]; + sfx = &S_sfx[sfx->link.index()]; } } @@ -1644,11 +1661,11 @@ unsigned int SoundEngine::GetMSLength(FSoundID sound) // is not the head of a random list, then the sound passed is returned. //========================================================================== -int SoundEngine::PickReplacement(int refid) +FSoundID SoundEngine::PickReplacement(FSoundID refid) { - while (S_sfx[refid].bRandomHeader) + while (S_sfx[refid.index()].bRandomHeader) { - const FRandomSoundList* list = &S_rnd[S_sfx[refid].link]; + const FRandomSoundList* list = &S_rnd[S_sfx[refid.index()].link.index()]; refid = list->Choices[rand() % int(list->Choices.Size())]; } return refid; @@ -1663,34 +1680,200 @@ int SoundEngine::PickReplacement(int refid) void SoundEngine::HashSounds() { - unsigned int i; - unsigned int j; - unsigned int size; - S_sfx.ShrinkToFit(); - size = S_sfx.Size(); - - // Mark all buckets as empty - for (i = 0; i < size; i++) - S_sfx[i].index = 0; + SoundMap.Clear(); + ResIdMap.Clear(); - // Now set up the chains - for (i = 1; i < size; i++) + for (unsigned i = 1; i < S_sfx.Size(); i++) { - j = MakeKey(S_sfx[i].name) % size; - S_sfx[i].next = S_sfx[j].index; - S_sfx[j].index = i; + SoundMap.Insert(S_sfx[i].name, FSoundID::fromInt(i)); + if (S_sfx[i].ResourceId != -1) + { + ResIdMap.Insert(S_sfx[i].ResourceId, FSoundID::fromInt(i)); + } } S_rnd.ShrinkToFit(); + + } -void SoundEngine::AddRandomSound(int Owner, TArray list) +void SoundEngine::AddRandomSound(FSoundID Owner, TArray list) { auto index = S_rnd.Reserve(1); auto& random = S_rnd.Last(); random.Choices = std::move(list); random.Owner = Owner; - S_sfx[Owner].link = index; - S_sfx[Owner].bRandomHeader = true; - S_sfx[Owner].NearLimit = -1; + S_sfx[Owner.index()].link = FSoundID::fromInt(index); + S_sfx[Owner.index()].bRandomHeader = true; + S_sfx[Owner.index()].NearLimit = -1; +} + +void S_SoundReset() +{ + S_StopMusic(true); + soundEngine->Reset(); + S_RestartMusic(); } + +//========================================================================== +// +// CCMD cachesound +// +//========================================================================== + +#include "s_music.h" +#include "vm.h" +#include "c_dispatch.h" +#include "stats.h" +#include "i_net.h" +#include "i_interface.h" + + +CCMD(cachesound) +{ + if (argv.argc() < 2) + { + Printf("Usage: cachesound ...\n"); + return; + } + for (int i = 1; i < argv.argc(); ++i) + { + FSoundID sfxnum = S_FindSound(argv[i]); + if (sfxnum != NO_SOUND) + { + soundEngine->CacheSound(sfxnum); + } + } +} + + +CCMD(listsoundchannels) +{ + Printf("%s", soundEngine->ListSoundChannels().GetChars()); +} + +// intentionally moved here to keep the s_music include out of the rest of the file. + +//========================================================================== +// +// S_PauseSound +// +// Stop music and sound effects, during game PAUSE. +//========================================================================== + +void S_PauseSound(bool notmusic, bool notsfx) +{ + if (!notmusic) + { + S_PauseMusic(); + } + if (!notsfx) + { + soundEngine->SetPaused(true); + GSnd->SetSfxPaused(true, 0); + } +} + +DEFINE_ACTION_FUNCTION(DObject, S_PauseSound) +{ + PARAM_PROLOGUE; + PARAM_BOOL(notmusic); + PARAM_BOOL(notsfx); + S_PauseSound(notmusic, notsfx); + return 0; +} + +//========================================================================== +// +// S_ResumeSound +// +// Resume music and sound effects, after game PAUSE. +//========================================================================== + +void S_ResumeSound(bool notsfx) +{ + S_ResumeMusic(); + if (!notsfx) + { + soundEngine->SetPaused(false); + GSnd->SetSfxPaused(false, 0); + } +} + +DEFINE_ACTION_FUNCTION(DObject, S_ResumeSound) +{ + PARAM_PROLOGUE; + PARAM_BOOL(notsfx); + S_ResumeSound(notsfx); + return 0; +} + +//========================================================================== +// +// S_SetSoundPaused +// +// Called with state non-zero when the app is active, zero when it isn't. +// +//========================================================================== + +void S_SetSoundPaused(int state) +{ + if (!netgame && (i_pauseinbackground)) + { + pauseext = !state; + } + + if ((state || i_soundinbackground) && !pauseext) + { + if (!paused) + S_ResumeSound(true); + if (GSnd != nullptr) + { + GSnd->SetInactive(SoundRenderer::INACTIVE_Active); + } + } + else + { + S_PauseSound(false, true); + if (GSnd != nullptr) + { + GSnd->SetInactive(gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL ? + SoundRenderer::INACTIVE_Complete : + SoundRenderer::INACTIVE_Mute); + } + } +} + + + +CCMD(snd_status) +{ + GSnd->PrintStatus(); +} + +CCMD(snd_listdrivers) +{ + GSnd->PrintDriversList(); +} + +//========================================================================== +// +// CCMD listsounds +// +//========================================================================== + +CCMD(listsounds) +{ + for (unsigned i = 1; i < soundEngine->GetNumSounds(); i++) + { + auto sfx = soundEngine->GetSfx(FSoundID::fromInt(i)); + Printf("%4d: name = %s, resId = %d, lumpnum = %d\n", i, sfx->name.GetChars(), sfx->ResourceId, sfx->lumpnum); + } +} + +ADD_STAT(sound) +{ + return GSnd->GatherStats(); +} + + diff --git a/src/common/audio/sound/s_soundinternal.h b/src/common/audio/sound/s_soundinternal.h new file mode 100644 index 00000000000..1d007faef1d --- /dev/null +++ b/src/common/audio/sound/s_soundinternal.h @@ -0,0 +1,440 @@ +#pragma once + +#include "i_sound.h" +#include "name.h" + +enum +{ + sfx_empty = -1 +}; + + + +// Rolloff types +enum +{ + ROLLOFF_Doom, // Linear rolloff with a logarithmic volume scale + ROLLOFF_Linear, // Linear rolloff with a linear volume scale + ROLLOFF_Log, // Logarithmic rolloff (standard hardware type) + ROLLOFF_Custom // Lookup volume from SNDCURVE +}; + + +// An index into the S_sfx[] array. +class FSoundID +{ +public: + FSoundID() = default; + +private: + constexpr FSoundID(int id) : ID(id) + { + } +public: + static constexpr FSoundID fromInt(int i) + { + return FSoundID(i); + } + FSoundID(const FSoundID &other) = default; + FSoundID &operator=(const FSoundID &other) = default; + bool operator !=(FSoundID other) const + { + return ID != other.ID; + } + bool operator ==(FSoundID other) const + { + return ID == other.ID; + } + bool operator ==(int other) const = delete; + bool operator !=(int other) const = delete; + constexpr int index() const + { + return ID; + } + constexpr bool isvalid() const + { + return ID > 0; + } +private: + + int ID; +}; + +constexpr FSoundID NO_SOUND = FSoundID::fromInt(0); +constexpr FSoundID INVALID_SOUND = FSoundID::fromInt(-1); + + struct FRandomSoundList + { + TArray Choices; + FSoundID Owner = NO_SOUND; + }; + + + // +// SoundFX struct. +// + struct sfxinfo_t + { + // Next field is for use by the system sound interface. + // A non-null data means the sound has been loaded. + SoundHandle data{}; + + FName name; // [RH] Sound name defined in SNDINFO + int lumpnum = sfx_empty; // lump number of sfx + + float Volume = 1.f; + + int ResourceId = -1; // Resource ID as implemented by Blood. Not used by Doom but added for completeness. + float LimitRange = 256 * 256; // Range for sound limiting (squared for faster computations) + float DefPitch = 0.f; // A defined pitch instead of a random one the sound plays at, similar to A_StartSound. + float DefPitchMax = 0.f; // Randomized range with stronger control over pitch itself. + + int16_t NearLimit = 4; // 0 means unlimited. + int16_t UserVal = 0; // repurpose this gap for something useful + uint8_t PitchMask = 0; + bool bRandomHeader = false; + bool bLoadRAW = false; + bool b16bit = false; + bool bUsed = false; + bool bSingular = false; + bool bTentative = true; + bool bExternal = false; + + int RawRate = 0; // Sample rate to use when bLoadRAW is true + int LoopStart = -1; // -1 means no specific loop defined + int LoopEnd = -1; // -1 means no specific loop defined + float Attenuation = 1.f; // Multiplies the attenuation passed to S_Sound. + + FSoundID link = NO_LINK; + constexpr static FSoundID NO_LINK = FSoundID::fromInt(-1); + + TArray UserData; + FRolloffInfo Rolloff{}; + }; + + +struct FSoundChan : public FISoundChannel +{ + FSoundChan *NextChan; // Next channel in this list. + FSoundChan **PrevChan; // Previous channel in this list. + FSoundID SoundID; // Sound ID of playing sound. + FSoundID OrgID; // Sound ID of sound used to start this channel. + float Volume; + int EntChannel; // Actor's sound channel. + int UserData; // Not used by the engine, the caller can use this to store some additional info. + float Pitch; // Pitch variation. + int16_t NearLimit; + int8_t Priority; + uint8_t SourceType; + float LimitRange; + const void *Source; + float Point[3]; // Sound is not attached to any source. +}; + + +// sound channels +// channel 0 never willingly overrides +// other channels (1-7) always override a playing sound on that channel +// +// CHAN_AUTO searches down from channel 7 until it finds a channel not in use +// CHAN_WEAPON is for weapons +// CHAN_VOICE is for oof, sight, or other voice sounds +// CHAN_ITEM is for small things and item pickup +// CHAN_BODY is for generic body sounds + +enum EChannel +{ + CHAN_AUTO = 0, + CHAN_WEAPON = 1, + CHAN_VOICE = 2, + CHAN_ITEM = 3, + CHAN_BODY = 4, + CHAN_5 = 5, + CHAN_6 = 6, + CHAN_7 = 7, +}; + + + +// sound attenuation values +#define ATTN_NONE 0.f // full volume the entire level +#define ATTN_NORM 1.f +#define ATTN_IDLE 1.001f +#define ATTN_STATIC 3.f // diminish very rapidly with distance + +enum // The core source types, implementations may extend this list as they see fit. +{ + SOURCE_Any = -1, // Input for check functions meaning 'any source' + SOURCE_Unattached, // Sound is not attached to any particular emitter. + SOURCE_None, // Sound is always on top of the listener. +}; + + +extern ReverbContainer *Environments; +extern ReverbContainer *DefaultEnvironments[26]; + +void S_ParseReverbDef (); +void S_UnloadReverbDef (); +void S_SetEnvironment (const ReverbContainer *settings); +ReverbContainer *S_FindEnvironment (const char *name); +ReverbContainer *S_FindEnvironment (int id); +void S_AddEnvironment (ReverbContainer *settings); + +class SoundEngine +{ +protected: + bool SoundPaused = false; // whether sound is paused + int RestartEvictionsAt = 0; // do not restart evicted channels before this time + SoundListener listener{}; + + FSoundChan* Channels = nullptr; + FSoundChan* FreeChannels = nullptr; + + // the complete set of sound effects + TArray S_sfx; + FRolloffInfo S_Rolloff{}; + TArray S_SoundCurve; + TMap SoundMap; + TMap ResIdMap; + TArray S_rnd; + bool blockNewSounds = false; + +private: + void LinkChannel(FSoundChan* chan, FSoundChan** head); + void UnlinkChannel(FSoundChan* chan); + void ReturnChannel(FSoundChan* chan); + void RestartChannel(FSoundChan* chan); + void RestoreEvictedChannel(FSoundChan* chan); + + bool IsChannelUsed(int sourcetype, const void* actor, int channel, int* seen); + // This is the actual sound positioning logic which needs to be provided by the client. + virtual void CalcPosVel(int type, const void* source, const float pt[3], int channel, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan *chan) = 0; + // This can be overridden by the clent to provide some diagnostics. The default lets everything pass. + virtual bool ValidatePosVel(int sourcetype, const void* source, const FVector3& pos, const FVector3& vel) { return true; } + + bool ValidatePosVel(const FSoundChan* const chan, const FVector3& pos, const FVector3& vel); + + // Checks if a copy of this sound is already playing. + bool CheckSingular(FSoundID sound_id); + virtual TArray ReadSound(int lumpnum) = 0; + +protected: + virtual bool CheckSoundLimit(sfxinfo_t* sfx, const FVector3& pos, int near_limit, float limit_range, int sourcetype, const void* actor, int channel, float attenuation); + virtual FSoundID ResolveSound(const void *ent, int srctype, FSoundID soundid, float &attenuation); + +public: + virtual ~SoundEngine() + { + Shutdown(); + } + void EvictAllChannels(); + + void BlockNewSounds(bool on) + { + blockNewSounds = on; + } + + virtual void StopChannel(FSoundChan* chan); + sfxinfo_t* LoadSound(sfxinfo_t* sfx); + sfxinfo_t* GetWritableSfx(FSoundID snd) + { + if ((unsigned)snd.index() >= S_sfx.Size()) return nullptr; + return &S_sfx[snd.index()]; + } + + const sfxinfo_t* GetSfx(FSoundID snd) + { + return GetWritableSfx(snd); + } + + unsigned GetNumSounds() const + { + return S_sfx.Size(); + } + + sfxinfo_t* AllocateSound() + { + return &S_sfx[S_sfx.Reserve(1)]; + } + + // Initializes sound stuff, including volume + // Sets channels, SFX and music volume, + // allocates channel buffer, sets S_sfx lookup. + // + void Init(TArray &sndcurve); + void InitData(); + void Clear(); + void Shutdown(); + + void StopAllChannels(void); + void SetPitch(FSoundChan* chan, float dpitch); + void SetVolume(FSoundChan* chan, float vol); + + FSoundChan* GetChannel(void* syschan); + void RestoreEvictedChannels(); + void CalcPosVel(FSoundChan* chan, FVector3* pos, FVector3* vel); + + // Loads a sound, including any random sounds it might reference. + virtual void CacheSound(sfxinfo_t* sfx); + void CacheSound(FSoundID sfx) { CacheSound(&S_sfx[sfx.index()]); } + void UnloadSound(sfxinfo_t* sfx); + void UnloadSound(int sfx) + { + UnloadSound(&S_sfx[sfx]); + } + + void UpdateSounds(int time); + + FSoundChan* StartSound(int sourcetype, const void* source, + const FVector3* pt, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, FRolloffInfo* rolloff = nullptr, float spitch = 0.0f, float startTime = 0.0f); + + // Stops an origin-less sound from playing from this channel. + void StopSoundID(FSoundID sound_id); + void StopSound(int channel, FSoundID sound_id = INVALID_SOUND); + void StopSound(int sourcetype, const void* actor, int channel, FSoundID sound_id = INVALID_SOUND); + void StopActorSounds(int sourcetype, const void* actor, int chanmin, int chanmax); + + void RelinkSound(int sourcetype, const void* from, const void* to, const FVector3* optpos); + void ChangeSoundVolume(int sourcetype, const void* source, int channel, double dvolume); + void ChangeSoundPitch(int sourcetype, const void* source, int channel, double pitch, FSoundID sound_id = INVALID_SOUND); + bool IsSourcePlayingSomething(int sourcetype, const void* actor, int channel, FSoundID sound_id = INVALID_SOUND); + + // Stop and resume music, during game PAUSE. + int GetSoundPlayingInfo(int sourcetype, const void* source, FSoundID sound_id, int chan = -1); + void UnloadAllSounds(); + void Reset(); + void MarkUsed(FSoundID num); + void CacheMarkedSounds(); + TArray AllActiveChannels(); + virtual void SetSoundPaused(int state) {} + + void MarkAllUnused() + { + for (auto & s: S_sfx) s.bUsed = false; + } + + bool isListener(const void* object) const + { + return object && listener.ListenerObject == object; + } + void SetListener(SoundListener& l) + { + listener = l; + } + const SoundListener& GetListener() const + { + return listener; + } + void SetRestartTime(int time) + { + RestartEvictionsAt = time; + } + void SetPaused(bool on) + { + SoundPaused = on; + } + FSoundChan* GetChannels() + { + return Channels; + } + const char *GetSoundName(FSoundID id) + { + return !id.isvalid() ? "" : S_sfx[id.index()].name.GetChars(); + } + FRolloffInfo& GlobalRolloff() // this is meant for sound list generators, not for gaining cheap access to the sound engine's innards. + { + return S_Rolloff; + } + FRandomSoundList *ResolveRandomSound(sfxinfo_t* sfx) + { + return &S_rnd[sfx->link.index()]; + } + void ClearRandoms() + { + S_rnd.Clear(); + } + int *GetUserData(FSoundID snd) + { + return S_sfx[snd.index()].UserData.Data(); + } + bool isValidSoundId(FSoundID sid) + { + int id = sid.index(); + return id > 0 && id < (int)S_sfx.Size() && !S_sfx[id].bTentative && (S_sfx[id].lumpnum != sfx_empty || S_sfx[id].bRandomHeader || S_sfx[id].link != sfxinfo_t::NO_LINK); + } + + template bool EnumerateChannels(func callback) + { + FSoundChan* chan = Channels; + while (chan) + { + auto next = chan->NextChan; + int res = callback(chan); + if (res) return res > 0; + chan = next; + } + return false; + } + + void SetDefaultRolloff(FRolloffInfo* ro) + { + S_Rolloff = *ro; + } + + void ChannelVirtualChanged(FISoundChannel* ichan, bool is_virtual); + FString ListSoundChannels(); + + // Allow this to be overridden for special needs. + virtual float GetRolloff(const FRolloffInfo* rolloff, float distance); + virtual void ChannelEnded(FISoundChannel* ichan); // allows the client to do bookkeeping on the sound. + virtual void SoundDone(FISoundChannel* ichan); // gets called when the sound has been completely taken down. + + // Lookup utilities. + FSoundID FindSound(const char* logicalname); + FSoundID FindSoundByResID(int rid); + FSoundID FindSoundNoHash(const char* logicalname); + FSoundID FindSoundByResIDNoHash(int rid); + FSoundID FindSoundByLump(int lump); + virtual FSoundID AddSoundLump(const char* logicalname, int lump, int CurrentPitchMask, int resid = -1, int nearlimit = 2); + FSoundID FindSoundTentative(const char* name, int nearlimit = 2); + void CacheRandomSound(sfxinfo_t* sfx); + unsigned int GetMSLength(FSoundID sound); + FSoundID PickReplacement(FSoundID refid); + void HashSounds(); + void AddRandomSound(FSoundID Owner, TArray list); + + TArray& GetSounds() //We still need this for a short time... + { + return S_sfx; + } + +}; + + +extern SoundEngine* soundEngine; + +struct FReverbField +{ + int Min, Max; + float REVERB_PROPERTIES::* Float; + int REVERB_PROPERTIES::* Int; + unsigned int Flag; +}; + + +inline FSoundID S_FindSoundByResID(int ndx) +{ + return soundEngine->FindSoundByResID(ndx); +} + +inline FSoundID S_FindSound(const char* name) +{ + return soundEngine->FindSound(name); +} + +inline FSoundID S_FindSound(const FString& name) +{ + return soundEngine->FindSound(name.GetChars()); +} + +int SoundEnabled(); diff --git a/src/sound/thirdparty/al.h b/src/common/audio/sound/thirdparty/al.h similarity index 100% rename from src/sound/thirdparty/al.h rename to src/common/audio/sound/thirdparty/al.h diff --git a/src/sound/thirdparty/alc.h b/src/common/audio/sound/thirdparty/alc.h similarity index 100% rename from src/sound/thirdparty/alc.h rename to src/common/audio/sound/thirdparty/alc.h diff --git a/src/common/audio/sound/thirdparty/alext.h b/src/common/audio/sound/thirdparty/alext.h new file mode 100644 index 00000000000..edfae47353b --- /dev/null +++ b/src/common/audio/sound/thirdparty/alext.h @@ -0,0 +1,643 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2008 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#ifndef AL_ALEXT_H +#define AL_ALEXT_H + +#include +/* Define int64 and uint64 types */ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + (defined(__cplusplus) && __cplusplus >= 201103L) +#include +typedef int64_t _alsoft_int64_t; +typedef uint64_t _alsoft_uint64_t; +#elif defined(_WIN32) +typedef __int64 _alsoft_int64_t; +typedef unsigned __int64 _alsoft_uint64_t; +#else +/* Fallback if nothing above works */ +#include +typedef int64_t _alsoft_int64_t; +typedef uint64_t _alsoft_uint64_t; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AL_LOKI_IMA_ADPCM_format +#define AL_LOKI_IMA_ADPCM_format 1 +#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 +#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 +#endif + +#ifndef AL_LOKI_WAVE_format +#define AL_LOKI_WAVE_format 1 +#define AL_FORMAT_WAVE_EXT 0x10002 +#endif + +#ifndef AL_EXT_vorbis +#define AL_EXT_vorbis 1 +#define AL_FORMAT_VORBIS_EXT 0x10003 +#endif + +#ifndef AL_LOKI_quadriphonic +#define AL_LOKI_quadriphonic 1 +#define AL_FORMAT_QUAD8_LOKI 0x10004 +#define AL_FORMAT_QUAD16_LOKI 0x10005 +#endif + +#ifndef AL_EXT_float32 +#define AL_EXT_float32 1 +#define AL_FORMAT_MONO_FLOAT32 0x10010 +#define AL_FORMAT_STEREO_FLOAT32 0x10011 +#endif + +#ifndef AL_EXT_double +#define AL_EXT_double 1 +#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 +#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 +#endif + +#ifndef AL_EXT_MULAW +#define AL_EXT_MULAW 1 +#define AL_FORMAT_MONO_MULAW_EXT 0x10014 +#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 +#endif + +#ifndef AL_EXT_ALAW +#define AL_EXT_ALAW 1 +#define AL_FORMAT_MONO_ALAW_EXT 0x10016 +#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 +#endif + +#ifndef ALC_LOKI_audio_channel +#define ALC_LOKI_audio_channel 1 +#define ALC_CHAN_MAIN_LOKI 0x500001 +#define ALC_CHAN_PCM_LOKI 0x500002 +#define ALC_CHAN_CD_LOKI 0x500003 +#endif + +#ifndef AL_EXT_MCFORMATS +#define AL_EXT_MCFORMATS 1 +/* Provides support for surround sound buffer formats with 8, 16, and 32-bit + * samples. + * + * QUAD8: Unsigned 8-bit, Quadraphonic (Front Left, Front Right, Rear Left, + * Rear Right). + * QUAD16: Signed 16-bit, Quadraphonic. + * QUAD32: 32-bit float, Quadraphonic. + * REAR8: Unsigned 8-bit, Rear Stereo (Rear Left, Rear Right). + * REAR16: Signed 16-bit, Rear Stereo. + * REAR32: 32-bit float, Rear Stereo. + * 51CHN8: Unsigned 8-bit, 5.1 Surround (Front Left, Front Right, Front Center, + * LFE, Side Left, Side Right). Note that some audio systems may label + * 5.1's Side channels as Rear or Surround; they are equivalent for the + * purposes of this extension. + * 51CHN16: Signed 16-bit, 5.1 Surround. + * 51CHN32: 32-bit float, 5.1 Surround. + * 61CHN8: Unsigned 8-bit, 6.1 Surround (Front Left, Front Right, Front Center, + * LFE, Rear Center, Side Left, Side Right). + * 61CHN16: Signed 16-bit, 6.1 Surround. + * 61CHN32: 32-bit float, 6.1 Surround. + * 71CHN8: Unsigned 8-bit, 7.1 Surround (Front Left, Front Right, Front Center, + * LFE, Rear Left, Rear Right, Side Left, Side Right). + * 71CHN16: Signed 16-bit, 7.1 Surround. + * 71CHN32: 32-bit float, 7.1 Surround. + */ +#define AL_FORMAT_QUAD8 0x1204 +#define AL_FORMAT_QUAD16 0x1205 +#define AL_FORMAT_QUAD32 0x1206 +#define AL_FORMAT_REAR8 0x1207 +#define AL_FORMAT_REAR16 0x1208 +#define AL_FORMAT_REAR32 0x1209 +#define AL_FORMAT_51CHN8 0x120A +#define AL_FORMAT_51CHN16 0x120B +#define AL_FORMAT_51CHN32 0x120C +#define AL_FORMAT_61CHN8 0x120D +#define AL_FORMAT_61CHN16 0x120E +#define AL_FORMAT_61CHN32 0x120F +#define AL_FORMAT_71CHN8 0x1210 +#define AL_FORMAT_71CHN16 0x1211 +#define AL_FORMAT_71CHN32 0x1212 +#endif + +#ifndef AL_EXT_MULAW_MCFORMATS +#define AL_EXT_MULAW_MCFORMATS 1 +#define AL_FORMAT_MONO_MULAW 0x10014 +#define AL_FORMAT_STEREO_MULAW 0x10015 +#define AL_FORMAT_QUAD_MULAW 0x10021 +#define AL_FORMAT_REAR_MULAW 0x10022 +#define AL_FORMAT_51CHN_MULAW 0x10023 +#define AL_FORMAT_61CHN_MULAW 0x10024 +#define AL_FORMAT_71CHN_MULAW 0x10025 +#endif + +#ifndef AL_EXT_IMA4 +#define AL_EXT_IMA4 1 +#define AL_FORMAT_MONO_IMA4 0x1300 +#define AL_FORMAT_STEREO_IMA4 0x1301 +#endif + +#ifndef AL_EXT_STATIC_BUFFER +#define AL_EXT_STATIC_BUFFER 1 +typedef void (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); +#endif +#endif + +#ifndef ALC_EXT_EFX +#define ALC_EXT_EFX 1 +#include "efx.h" +#endif + +#ifndef ALC_EXT_disconnect +#define ALC_EXT_disconnect 1 +#define ALC_CONNECTED 0x313 +#endif + +#ifndef ALC_EXT_thread_local_context +#define ALC_EXT_thread_local_context 1 +typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); +typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); +#endif +#endif + +#ifndef AL_EXT_source_distance_model +#define AL_EXT_source_distance_model 1 +#define AL_SOURCE_DISTANCE_MODEL 0x200 +#endif + +#ifndef AL_SOFT_buffer_sub_data +#define AL_SOFT_buffer_sub_data 1 +#define AL_BYTE_RW_OFFSETS_SOFT 0x1031 +#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 +typedef void (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); +#endif +#endif + +#ifndef AL_SOFT_loop_points +#define AL_SOFT_loop_points 1 +#define AL_LOOP_POINTS_SOFT 0x2015 +#endif + +#ifndef AL_EXT_FOLDBACK +#define AL_EXT_FOLDBACK 1 +#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" +#define AL_FOLDBACK_EVENT_BLOCK 0x4112 +#define AL_FOLDBACK_EVENT_START 0x4111 +#define AL_FOLDBACK_EVENT_STOP 0x4113 +#define AL_FOLDBACK_MODE_MONO 0x4101 +#define AL_FOLDBACK_MODE_STEREO 0x4102 +typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); +AL_API void AL_APIENTRY alRequestFoldbackStop(void); +#endif +#endif + +#ifndef ALC_EXT_DEDICATED +#define ALC_EXT_DEDICATED 1 +#define AL_DEDICATED_GAIN 0x0001 +#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 +#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 +#endif + +#ifndef AL_SOFT_buffer_samples +#define AL_SOFT_buffer_samples 1 +/* Channel configurations */ +#define AL_MONO_SOFT 0x1500 +#define AL_STEREO_SOFT 0x1501 +#define AL_REAR_SOFT 0x1502 +#define AL_QUAD_SOFT 0x1503 +#define AL_5POINT1_SOFT 0x1504 +#define AL_6POINT1_SOFT 0x1505 +#define AL_7POINT1_SOFT 0x1506 + +/* Sample types */ +#define AL_BYTE_SOFT 0x1400 +#define AL_UNSIGNED_BYTE_SOFT 0x1401 +#define AL_SHORT_SOFT 0x1402 +#define AL_UNSIGNED_SHORT_SOFT 0x1403 +#define AL_INT_SOFT 0x1404 +#define AL_UNSIGNED_INT_SOFT 0x1405 +#define AL_FLOAT_SOFT 0x1406 +#define AL_DOUBLE_SOFT 0x1407 +#define AL_BYTE3_SOFT 0x1408 +#define AL_UNSIGNED_BYTE3_SOFT 0x1409 + +/* Storage formats */ +#define AL_MONO8_SOFT 0x1100 +#define AL_MONO16_SOFT 0x1101 +#define AL_MONO32F_SOFT 0x10010 +#define AL_STEREO8_SOFT 0x1102 +#define AL_STEREO16_SOFT 0x1103 +#define AL_STEREO32F_SOFT 0x10011 +#define AL_QUAD8_SOFT 0x1204 +#define AL_QUAD16_SOFT 0x1205 +#define AL_QUAD32F_SOFT 0x1206 +#define AL_REAR8_SOFT 0x1207 +#define AL_REAR16_SOFT 0x1208 +#define AL_REAR32F_SOFT 0x1209 +#define AL_5POINT1_8_SOFT 0x120A +#define AL_5POINT1_16_SOFT 0x120B +#define AL_5POINT1_32F_SOFT 0x120C +#define AL_6POINT1_8_SOFT 0x120D +#define AL_6POINT1_16_SOFT 0x120E +#define AL_6POINT1_32F_SOFT 0x120F +#define AL_7POINT1_8_SOFT 0x1210 +#define AL_7POINT1_16_SOFT 0x1211 +#define AL_7POINT1_32F_SOFT 0x1212 + +/* Buffer attributes */ +#define AL_INTERNAL_FORMAT_SOFT 0x2008 +#define AL_BYTE_LENGTH_SOFT 0x2009 +#define AL_SAMPLE_LENGTH_SOFT 0x200A +#define AL_SEC_LENGTH_SOFT 0x200B + +typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); +typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); +#endif +#endif + +#ifndef AL_SOFT_direct_channels +#define AL_SOFT_direct_channels 1 +#define AL_DIRECT_CHANNELS_SOFT 0x1033 +#endif + +#ifndef ALC_SOFT_loopback +#define ALC_SOFT_loopback 1 +#define ALC_FORMAT_CHANNELS_SOFT 0x1990 +#define ALC_FORMAT_TYPE_SOFT 0x1991 + +/* Sample types */ +#define ALC_BYTE_SOFT 0x1400 +#define ALC_UNSIGNED_BYTE_SOFT 0x1401 +#define ALC_SHORT_SOFT 0x1402 +#define ALC_UNSIGNED_SHORT_SOFT 0x1403 +#define ALC_INT_SOFT 0x1404 +#define ALC_UNSIGNED_INT_SOFT 0x1405 +#define ALC_FLOAT_SOFT 0x1406 + +/* Channel configurations */ +#define ALC_MONO_SOFT 0x1500 +#define ALC_STEREO_SOFT 0x1501 +#define ALC_QUAD_SOFT 0x1503 +#define ALC_5POINT1_SOFT 0x1504 +#define ALC_6POINT1_SOFT 0x1505 +#define ALC_7POINT1_SOFT 0x1506 + +typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); +typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); +typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +#endif +#endif + +#ifndef AL_EXT_STEREO_ANGLES +#define AL_EXT_STEREO_ANGLES 1 +#define AL_STEREO_ANGLES 0x1030 +#endif + +#ifndef AL_EXT_SOURCE_RADIUS +#define AL_EXT_SOURCE_RADIUS 1 +#define AL_SOURCE_RADIUS 0x1031 +#endif + +#ifndef AL_SOFT_source_latency +#define AL_SOFT_source_latency 1 +#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 +#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 +typedef _alsoft_int64_t ALint64SOFT; +typedef _alsoft_uint64_t ALuint64SOFT; +typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); +AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); +AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); +AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); +#endif +#endif + +#ifndef ALC_EXT_DEFAULT_FILTER_ORDER +#define ALC_EXT_DEFAULT_FILTER_ORDER 1 +#define ALC_DEFAULT_FILTER_ORDER 0x1100 +#endif + +#ifndef AL_SOFT_deferred_updates +#define AL_SOFT_deferred_updates 1 +#define AL_DEFERRED_UPDATES_SOFT 0xC002 +typedef void (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); +typedef void (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alDeferUpdatesSOFT(void); +AL_API void AL_APIENTRY alProcessUpdatesSOFT(void); +#endif +#endif + +#ifndef AL_SOFT_block_alignment +#define AL_SOFT_block_alignment 1 +#define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C +#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D +#endif + +#ifndef AL_SOFT_MSADPCM +#define AL_SOFT_MSADPCM 1 +#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302 +#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303 +#endif + +#ifndef AL_SOFT_source_length +#define AL_SOFT_source_length 1 +/*#define AL_BYTE_LENGTH_SOFT 0x2009*/ +/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/ +/*#define AL_SEC_LENGTH_SOFT 0x200B*/ +#endif + +#ifndef ALC_SOFT_pause_device +#define ALC_SOFT_pause_device 1 +typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device); +typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device); +ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); +#endif +#endif + +#ifndef AL_EXT_BFORMAT +#define AL_EXT_BFORMAT 1 +/* Provides support for B-Format ambisonic buffers (first-order, FuMa scaling + * and layout). + * + * BFORMAT2D_8: Unsigned 8-bit, 3-channel non-periphonic (WXY). + * BFORMAT2D_16: Signed 16-bit, 3-channel non-periphonic (WXY). + * BFORMAT2D_FLOAT32: 32-bit float, 3-channel non-periphonic (WXY). + * BFORMAT3D_8: Unsigned 8-bit, 4-channel periphonic (WXYZ). + * BFORMAT3D_16: Signed 16-bit, 4-channel periphonic (WXYZ). + * BFORMAT3D_FLOAT32: 32-bit float, 4-channel periphonic (WXYZ). + */ +#define AL_FORMAT_BFORMAT2D_8 0x20021 +#define AL_FORMAT_BFORMAT2D_16 0x20022 +#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023 +#define AL_FORMAT_BFORMAT3D_8 0x20031 +#define AL_FORMAT_BFORMAT3D_16 0x20032 +#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033 +#endif + +#ifndef AL_EXT_MULAW_BFORMAT +#define AL_EXT_MULAW_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_MULAW 0x10031 +#define AL_FORMAT_BFORMAT3D_MULAW 0x10032 +#endif + +#ifndef ALC_SOFT_HRTF +#define ALC_SOFT_HRTF 1 +#define ALC_HRTF_SOFT 0x1992 +#define ALC_DONT_CARE_SOFT 0x0002 +#define ALC_HRTF_STATUS_SOFT 0x1993 +#define ALC_HRTF_DISABLED_SOFT 0x0000 +#define ALC_HRTF_ENABLED_SOFT 0x0001 +#define ALC_HRTF_DENIED_SOFT 0x0002 +#define ALC_HRTF_REQUIRED_SOFT 0x0003 +#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 +#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 +#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 +#define ALC_HRTF_SPECIFIER_SOFT 0x1995 +#define ALC_HRTF_ID_SOFT 0x1996 +typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); +typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); +#endif +#endif + +#ifndef AL_SOFT_gain_clamp_ex +#define AL_SOFT_gain_clamp_ex 1 +#define AL_GAIN_LIMIT_SOFT 0x200E +#endif + +#ifndef AL_SOFT_source_resampler +#define AL_SOFT_source_resampler +#define AL_NUM_RESAMPLERS_SOFT 0x1210 +#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 +#define AL_SOURCE_RESAMPLER_SOFT 0x1212 +#define AL_RESAMPLER_NAME_SOFT 0x1213 +typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); +#ifdef AL_ALEXT_PROTOTYPES +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); +#endif +#endif + +#ifndef AL_SOFT_source_spatialize +#define AL_SOFT_source_spatialize +#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 +#define AL_AUTO_SOFT 0x0002 +#endif + +#ifndef ALC_SOFT_output_limiter +#define ALC_SOFT_output_limiter +#define ALC_OUTPUT_LIMITER_SOFT 0x199A +#endif + +#ifndef ALC_SOFT_device_clock +#define ALC_SOFT_device_clock 1 +typedef _alsoft_int64_t ALCint64SOFT; +typedef _alsoft_uint64_t ALCuint64SOFT; +#define ALC_DEVICE_CLOCK_SOFT 0x1600 +#define ALC_DEVICE_LATENCY_SOFT 0x1601 +#define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602 +#define AL_SAMPLE_OFFSET_CLOCK_SOFT 0x1202 +#define AL_SEC_OFFSET_CLOCK_SOFT 0x1203 +typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); +#endif +#endif + +#ifndef AL_SOFT_direct_channels_remix +#define AL_SOFT_direct_channels_remix 1 +#define AL_DROP_UNMATCHED_SOFT 0x0001 +#define AL_REMIX_UNMATCHED_SOFT 0x0002 +#endif + +#ifndef AL_SOFT_bformat_ex +#define AL_SOFT_bformat_ex 1 +#define AL_AMBISONIC_LAYOUT_SOFT 0x1997 +#define AL_AMBISONIC_SCALING_SOFT 0x1998 + +/* Ambisonic layouts */ +#define AL_FUMA_SOFT 0x0000 +#define AL_ACN_SOFT 0x0001 + +/* Ambisonic scalings (normalization) */ +/*#define AL_FUMA_SOFT*/ +#define AL_SN3D_SOFT 0x0001 +#define AL_N3D_SOFT 0x0002 +#endif + +#ifndef ALC_SOFT_loopback_bformat +#define ALC_SOFT_loopback_bformat 1 +#define ALC_AMBISONIC_LAYOUT_SOFT 0x1997 +#define ALC_AMBISONIC_SCALING_SOFT 0x1998 +#define ALC_AMBISONIC_ORDER_SOFT 0x1999 +#define ALC_MAX_AMBISONIC_ORDER_SOFT 0x199B + +#define ALC_BFORMAT3D_SOFT 0x1507 + +/* Ambisonic layouts */ +#define ALC_FUMA_SOFT 0x0000 +#define ALC_ACN_SOFT 0x0001 + +/* Ambisonic scalings (normalization) */ +/*#define ALC_FUMA_SOFT*/ +#define ALC_SN3D_SOFT 0x0001 +#define ALC_N3D_SOFT 0x0002 +#endif + +#ifndef AL_SOFT_effect_target +#define AL_SOFT_effect_target +#define AL_EFFECTSLOT_TARGET_SOFT 0x199C +#endif + +#ifndef AL_SOFT_events +#define AL_SOFT_events 1 +#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0x19A2 +#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0x19A3 +#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0x19A4 +#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x19A5 +#define AL_EVENT_TYPE_DISCONNECTED_SOFT 0x19A6 +typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, + ALsizei length, const ALchar *message, + void *userParam); +typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); +typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); +typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); +typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable); +AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam); +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname); +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); +#endif +#endif + +#ifndef ALC_SOFT_reopen_device +#define ALC_SOFT_reopen_device +typedef ALCboolean (ALC_APIENTRY*LPALCREOPENDEVICESOFT)(ALCdevice *device, + const ALCchar *deviceName, const ALCint *attribs); +#ifdef AL_ALEXT_PROTOTYPES +ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device, const ALCchar *deviceName, + const ALCint *attribs); +#endif +#endif + +#ifndef AL_SOFT_callback_buffer +#define AL_SOFT_callback_buffer +#define AL_BUFFER_CALLBACK_FUNCTION_SOFT 0x19A0 +#define AL_BUFFER_CALLBACK_USER_PARAM_SOFT 0x19A1 +typedef ALsizei (AL_APIENTRY*ALBUFFERCALLBACKTYPESOFT)(ALvoid *userptr, ALvoid *sampledata, ALsizei numbytes); +typedef void (AL_APIENTRY*LPALBUFFERCALLBACKSOFT)(ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr); +typedef void (AL_APIENTRY*LPALGETBUFFERPTRSOFT)(ALuint buffer, ALenum param, ALvoid **value); +typedef void (AL_APIENTRY*LPALGETBUFFER3PTRSOFT)(ALuint buffer, ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3); +typedef void (AL_APIENTRY*LPALGETBUFFERPTRVSOFT)(ALuint buffer, ALenum param, ALvoid **values); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferCallbackSOFT(ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr); +AL_API void AL_APIENTRY alGetBufferPtrSOFT(ALuint buffer, ALenum param, ALvoid **ptr); +AL_API void AL_APIENTRY alGetBuffer3PtrSOFT(ALuint buffer, ALenum param, ALvoid **ptr0, ALvoid **ptr1, ALvoid **ptr2); +AL_API void AL_APIENTRY alGetBufferPtrvSOFT(ALuint buffer, ALenum param, ALvoid **ptr); +#endif +#endif + +#ifndef AL_SOFT_UHJ +#define AL_SOFT_UHJ +#define AL_FORMAT_UHJ2CHN8_SOFT 0x19A2 +#define AL_FORMAT_UHJ2CHN16_SOFT 0x19A3 +#define AL_FORMAT_UHJ2CHN_FLOAT32_SOFT 0x19A4 +#define AL_FORMAT_UHJ3CHN8_SOFT 0x19A5 +#define AL_FORMAT_UHJ3CHN16_SOFT 0x19A6 +#define AL_FORMAT_UHJ3CHN_FLOAT32_SOFT 0x19A7 +#define AL_FORMAT_UHJ4CHN8_SOFT 0x19A8 +#define AL_FORMAT_UHJ4CHN16_SOFT 0x19A9 +#define AL_FORMAT_UHJ4CHN_FLOAT32_SOFT 0x19AA + +#define AL_STEREO_MODE_SOFT 0x19B0 +#define AL_NORMAL_SOFT 0x0000 +#define AL_SUPER_STEREO_SOFT 0x0001 +#define AL_SUPER_STEREO_WIDTH_SOFT 0x19B1 +#endif + +#ifndef ALC_SOFT_output_mode +#define ALC_SOFT_output_mode +#define ALC_OUTPUT_MODE_SOFT 0x19AC +#define ALC_ANY_SOFT 0x19AD +/*#define ALC_MONO_SOFT 0x1500*/ +/*#define ALC_STEREO_SOFT 0x1501*/ +#define ALC_STEREO_BASIC_SOFT 0x19AE +#define ALC_STEREO_UHJ_SOFT 0x19AF +#define ALC_STEREO_HRTF_SOFT 0x19B2 +/*#define ALC_QUAD_SOFT 0x1503*/ +#define ALC_SURROUND_5_1_SOFT 0x1504 +#define ALC_SURROUND_6_1_SOFT 0x1505 +#define ALC_SURROUND_7_1_SOFT 0x1506 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/console/c_bind.cpp b/src/common/console/c_bind.cpp new file mode 100644 index 00000000000..fe794c736d6 --- /dev/null +++ b/src/common/console/c_bind.cpp @@ -0,0 +1,880 @@ +/* +** c_bind.cpp +** Functions for using and maintaining key bindings +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include + +#include "cmdlib.h" +#include "keydef.h" +#include "c_commandline.h" +#include "c_bind.h" +#include "c_dispatch.h" +#include "configfile.h" +#include "filesystem.h" + +#include "i_time.h" +#include "printf.h" +#include "sc_man.h" +#include "c_cvars.h" + +#include "d_eventbase.h" + +const char *KeyNames[NUM_KEYS] = +{ + // We use the DirectInput codes and assume a qwerty keyboard layout. + // See for the DIK_* codes + + nullptr, "Escape", "1", "2", "3", "4", "5", "6", //00 + "7", "8", "9", "0", "-", "=", "Backspace","Tab", //08 + "Q", "W", "E", "R", "T", "Y", "U", "I", //10 + "O", "P", "[", "]", "Enter", "Ctrl", "A", "S", //18 + "D", "F", "G", "H", "J", "K", "L", ";", //20 + "'", "`", "Shift", "\\", "Z", "X", "C", "V", //28 + "B", "N", "M", ",", ".", "/", "RShift", "KP*", //30 + "Alt", "Space", "CapsLock", "F1", "F2", "F3", "F4", "F5", //38 + "F6", "F7", "F8", "F9", "F10", "NumLock", "Scroll", "KP7", //40 + "KP8", "KP9", "KP-", "KP4", "KP5", "KP6", "KP+", "KP1", //48 + "KP2", "KP3", "KP0", "KP.", nullptr, nullptr, "OEM102", "F11", //50 + "F12", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //58 + nullptr, nullptr, nullptr, nullptr, "F13", "F14", "F15", "F16", //60 + "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", //68 + "Kana", nullptr, nullptr, "Abnt_C1", nullptr, nullptr, nullptr, nullptr, //70 + nullptr, "Convert", nullptr, "NoConvert",nullptr, "Yen", "Abnt_C2", nullptr, //78 + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //80 + nullptr, nullptr, nullptr, nullptr, nullptr, "KP=", nullptr, nullptr, //88 + "Circumflex","@", ":", "_", "Kanji", "Stop", "Ax", "Unlabeled",//90 + nullptr, "PrevTrack",nullptr, nullptr, "KP-Enter", "RCtrl", nullptr, nullptr, //98 + "Mute", "Calculator","Play", nullptr, "Stop", nullptr, nullptr, nullptr, //A0 + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "VolDown", nullptr, //A8 + "VolUp", nullptr, "WebHome", "KP,", nullptr, "KP/", nullptr, "SysRq", //B0 + "RAlt", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //B8 + nullptr, nullptr, nullptr, nullptr, nullptr, "Pause", nullptr, "Home", //C0 + "UpArrow", "PgUp", nullptr, "LeftArrow",nullptr, "RightArrow",nullptr, "End", //C8 + "DownArrow","PgDn", "Ins", "Del", nullptr, nullptr, nullptr, nullptr, //D0 +#ifdef __APPLE__ + nullptr, nullptr, nullptr, "Command", nullptr, "Apps", "Power", "Sleep", //D8 +#else // !__APPLE__ + nullptr, nullptr, nullptr, "LWin", "RWin", "Apps", "Power", "Sleep", //D8 +#endif // __APPLE__ + nullptr, nullptr, nullptr, "Wake", nullptr, "Search", "Favorites","Refresh", //E0 + "WebStop", "WebForward","WebBack", "MyComputer","Mail", "MediaSelect",nullptr, nullptr, //E8 + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //F0 + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //F8 + + // non-keyboard buttons that can be bound + "Mouse1", "Mouse2", "Mouse3", "Mouse4", // 8 mouse buttons + "Mouse5", "Mouse6", "Mouse7", "Mouse8", + + "Joy1", "Joy2", "Joy3", "Joy4", // 128 joystick buttons! + "Joy5", "Joy6", "Joy7", "Joy8", + "Joy9", "Joy10", "Joy11", "Joy12", + "Joy13", "Joy14", "Joy15", "Joy16", + "Joy17", "Joy18", "Joy19", "Joy20", + "Joy21", "Joy22", "Joy23", "Joy24", + "Joy25", "Joy26", "Joy27", "Joy28", + "Joy29", "Joy30", "Joy31", "Joy32", + "Joy33", "Joy34", "Joy35", "Joy36", + "Joy37", "Joy38", "Joy39", "Joy40", + "Joy41", "Joy42", "Joy43", "Joy44", + "Joy45", "Joy46", "Joy47", "Joy48", + "Joy49", "Joy50", "Joy51", "Joy52", + "Joy53", "Joy54", "Joy55", "Joy56", + "Joy57", "Joy58", "Joy59", "Joy60", + "Joy61", "Joy62", "Joy63", "Joy64", + "Joy65", "Joy66", "Joy67", "Joy68", + "Joy69", "Joy70", "Joy71", "Joy72", + "Joy73", "Joy74", "Joy75", "Joy76", + "Joy77", "Joy78", "Joy79", "Joy80", + "Joy81", "Joy82", "Joy83", "Joy84", + "Joy85", "Joy86", "Joy87", "Joy88", + "Joy89", "Joy90", "Joy91", "Joy92", + "Joy93", "Joy94", "Joy95", "Joy96", + "Joy97", "Joy98", "Joy99", "Joy100", + "Joy101", "Joy102", "Joy103", "Joy104", + "Joy105", "Joy106", "Joy107", "Joy108", + "Joy109", "Joy110", "Joy111", "Joy112", + "Joy113", "Joy114", "Joy115", "Joy116", + "Joy117", "Joy118", "Joy119", "Joy120", + "Joy121", "Joy122", "Joy123", "Joy124", + "Joy125", "Joy126", "Joy127", "Joy128", + + "POV1Up", "POV1Right","POV1Down", "POV1Left", // First POV hat + "POV2Up", "POV2Right","POV2Down", "POV2Left", // Second POV hat + "POV3Up", "POV3Right","POV3Down", "POV3Left", // Third POV hat + "POV4Up", "POV4Right","POV4Down", "POV4Left", // Fourth POV hat + + "MWheelUp", "MWheelDown", // the mouse wheel + "MWheelRight", "MWheelLeft", + + "Axis1Plus","Axis1Minus","Axis2Plus","Axis2Minus", // joystick axes as buttons + "Axis3Plus","Axis3Minus","Axis4Plus","Axis4Minus", + "Axis5Plus","Axis5Minus","Axis6Plus","Axis6Minus", + "Axis7Plus","Axis7Minus","Axis8Plus","Axis8Minus", + + "LStickRight","LStickLeft","LStickDown","LStickUp", // Gamepad axis-based buttons + "RStickRight","RStickLeft","RStickDown","RStickUp", + + "DPadUp","DPadDown","DPadLeft","DPadRight", // Gamepad buttons + "Pad_Start","Pad_Back","LThumb","RThumb", + "LShoulder","RShoulder","LTrigger","RTrigger", + "Pad_A", "Pad_B", "Pad_X", "Pad_Y" +}; + +FKeyBindings Bindings; +FKeyBindings DoubleBindings; +FKeyBindings AutomapBindings; + +static unsigned int DClickTime[NUM_KEYS]; +static FixedBitArray DClicked; + +//============================================================================= +// +// +// +//============================================================================= + +static int GetKeyFromName (const char *name) +{ + int i; + + // Names of the form #xxx are translated to key xxx automatically + if (name[0] == '#' && name[1] != 0) + { + return atoi (name + 1); + } + + // Otherwise, we scan the KeyNames[] array for a matching name + for (i = 0; i < NUM_KEYS; i++) + { + if (KeyNames[i] && !stricmp (KeyNames[i], name)) + return i; + } + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +static int GetConfigKeyFromName (const char *key) +{ + int keynum = GetKeyFromName(key); + if (keynum == 0) + { + if (stricmp (key, "LeftBracket") == 0) + { + keynum = GetKeyFromName ("["); + } + else if (stricmp (key, "RightBracket") == 0) + { + keynum = GetKeyFromName ("]"); + } + else if (stricmp (key, "Equals") == 0) + { + keynum = GetKeyFromName ("="); + } + else if (stricmp (key, "KP-Equals") == 0) + { + keynum = GetKeyFromName ("kp="); + } + } + return keynum; +} + +//============================================================================= +// +// +// +//============================================================================= + +const char *KeyName (int key) +{ + static char name[5]; + + if (KeyNames[key]) + return KeyNames[key]; + + mysnprintf (name, countof(name), "Key_%d", key); + return name; +} + +//============================================================================= +// +// +// +//============================================================================= + +static const char *ConfigKeyName(int keynum) +{ + const char *name = KeyName(keynum); + if (name[1] == 0) // Make sure given name is config-safe + { + if (name[0] == '[') + return "LeftBracket"; + else if (name[0] == ']') + return "RightBracket"; + else if (name[0] == '=') + return "Equals"; + else if (strcmp (name, "kp=") == 0) + return "KP-Equals"; + } + return name; +} + +//============================================================================= +// +// +// +//============================================================================= + +void C_NameKeys (char *str, int first, int second) +{ + int c = 0; + + *str = 0; + if (second == first) second = 0; + if (first) + { + c++; + strcpy (str, KeyName (first)); + if (second) + strcat (str, TEXTCOLOR_BLACK ", " TEXTCOLOR_NORMAL); + } + + if (second) + { + c++; + strcat (str, KeyName (second)); + } + + if (!c) + *str = '\0'; +} + +//============================================================================= +// +// +// +//============================================================================= + +FString C_NameKeys (int *keys, int count, bool colors) +{ + FString result; + for (int i = 0; i < count; i++) + { + int key = keys[i]; + if (key == 0) continue; + for (int j = 0; j < i; j++) + { + if (key == keys[j]) + { + key = 0; + break; + } + } + if (key == 0) continue; + if (result.IsNotEmpty()) result += colors? TEXTCOLOR_BLACK ", " TEXTCOLOR_NORMAL : ", "; + result += KeyName(key); + } + return result; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::DoBind (const char *key, const char *bind) +{ + int keynum = GetConfigKeyFromName (key); + if (keynum != 0) + { + Binds[keynum] = bind; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::UnbindAll () +{ + for (int i = 0; i < NUM_KEYS; ++i) + { + Binds[i] = ""; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::UnbindKey(const char *key) +{ + int i; + + if ( (i = GetKeyFromName (key)) ) + { + Binds[i] = ""; + } + else + { + Printf ("Unknown key \"%s\"\n", key); + return; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::PerformBind(FCommandLine &argv, const char *msg) +{ + int i; + + if (argv.argc() > 1) + { + i = GetKeyFromName (argv[1]); + if (!i) + { + Printf ("Unknown key \"%s\"\n", argv[1]); + return; + } + if (argv.argc() == 2) + { + Printf ("\"%s\" = \"%s\"\n", argv[1], Binds[i].GetChars()); + } + else + { + Binds[i] = argv[2]; + } + } + else + { + Printf ("%s:\n", msg); + + for (i = 0; i < NUM_KEYS; i++) + { + if (!Binds[i].IsEmpty()) + Printf ("%s \"%s\"\n", KeyName (i), Binds[i].GetChars()); + } + } +} + + +//============================================================================= +// +// This function is first called for functions in custom key sections. +// In this case, matchcmd is non-null, and only keys bound to that command +// are stored. If a match is found, its binding is set to "\1". +// After all custom key sections are saved, it is called one more for the +// normal Bindings and DoubleBindings sections for this game. In this case +// matchcmd is null and all keys will be stored. The config section was not +// previously cleared, so all old bindings are still in place. If the binding +// for a key is empty, the corresponding key in the config is removed as well. +// If a binding is "\1", then the binding itself is cleared, but nothing +// happens to the entry in the config. +// +//============================================================================= + +void FKeyBindings::ArchiveBindings(FConfigFile *f, const char *matchcmd) +{ + int i; + + for (i = 0; i < NUM_KEYS; i++) + { + if (Binds[i].IsEmpty()) + { + if (matchcmd == nullptr) + { + f->ClearKey(ConfigKeyName(i)); + } + } + else if (matchcmd == nullptr || Binds[i].CompareNoCase(matchcmd) == 0) + { + if (Binds[i][0] == '\1') + { + Binds[i] = ""; + continue; + } + f->SetValueForKey(ConfigKeyName(i), Binds[i].GetChars()); + if (matchcmd != nullptr) + { // If saving a specific command, set a marker so that + // it does not get saved in the general binding list. + Binds[i] = "\1"; + } + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + +int FKeyBindings::GetKeysForCommand (const char *cmd, int *first, int *second) +{ + int c, i; + + *first = *second = c = i = 0; + + if (cmd[0] == '\0') + { + return 0; + } + + while (i < NUM_KEYS && c < 2) + { + if (stricmp (cmd, Binds[i].GetChars()) == 0) + { + if (c++ == 0) + *first = i; + else + *second = i; + } + i++; + } + return c; +} + +//============================================================================= +// +// +// +//============================================================================= + +TArray FKeyBindings::GetKeysForCommand (const char *cmd) +{ + int i = 0; + TArray result; + + while (i < NUM_KEYS) + { + if (stricmp (cmd, Binds[i].GetChars()) == 0) + { + result.Push(i); + } + i++; + } + return result; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::UnbindACommand (const char *str) +{ + int i; + + for (i = 0; i < NUM_KEYS; i++) + { + if (!stricmp (str, Binds[i].GetChars())) + { + Binds[i] = ""; + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::DefaultBind(const char *keyname, const char *cmd) +{ + int key = GetKeyFromName (keyname); + if (key == 0) + { + Printf ("Unknown key \"%s\"\n", keyname); + return; + } + if (!Binds[key].IsEmpty()) + { // This key is already bound. + return; + } + for (int i = 0; i < NUM_KEYS; ++i) + { + if (!Binds[i].IsEmpty() && stricmp (Binds[i].GetChars(), cmd) == 0) + { // This command is already bound to a key. + return; + } + } + // It is safe to do the bind, so do it. + Binds[key] = cmd; +} + +//============================================================================= +// +// +// +//============================================================================= + +void C_UnbindAll () +{ + Bindings.UnbindAll(); + DoubleBindings.UnbindAll(); + AutomapBindings.UnbindAll(); +} + +UNSAFE_CCMD (unbindall) +{ + C_UnbindAll (); +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD (unbind) +{ + if (argv.argc() > 1) + { + Bindings.UnbindKey(argv[1]); + } +} + +CCMD (undoublebind) +{ + if (argv.argc() > 1) + { + DoubleBindings.UnbindKey(argv[1]); + } +} + +CCMD (unmapbind) +{ + if (argv.argc() > 1) + { + AutomapBindings.UnbindKey(argv[1]); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD (bind) +{ + Bindings.PerformBind(argv, "Current key bindings"); +} + +CCMD (doublebind) +{ + DoubleBindings.PerformBind(argv, "Current key doublebindings"); +} + +CCMD (mapbind) +{ + AutomapBindings.PerformBind(argv, "Current automap key bindings"); +} + +//========================================================================== +// +// CCMD defaultbind +// +// Binds a command to a key if that key is not already bound and if +// that command is not already bound to another key. +// +//========================================================================== + +CCMD (defaultbind) +{ + if (argv.argc() < 3) + { + Printf ("Usage: defaultbind \n"); + } + else + { + Bindings.DefaultBind(argv[1], argv[2]); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD(rebind) +{ + FKeyBindings* bindings; + + if (key == 0) + { + Printf("Rebind cannot be used from the console\n"); + return; + } + + if (key & KEY_DBLCLICKED) + { + bindings = &DoubleBindings; + key &= KEY_DBLCLICKED - 1; + } + else + { + bindings = &Bindings; + } + + if (argv.argc() > 1) + { + bindings->SetBind(key, argv[1]); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void ReadBindings(int lump, bool override) +{ + FScanner sc(lump); + + while (sc.GetString()) + { + FKeyBindings* dest = &Bindings; + int key; + + if (sc.Compare("unbind")) + { + sc.MustGetString(); + if (override) + { + // This is only for games to clear unsuitable base defaults, not for mods. + dest->UnbindKey(sc.String); + } + continue; + } + + // bind destination is optional and is the same as the console command + if (sc.Compare("bind")) + { + sc.MustGetString(); + } + else if (sc.Compare("doublebind")) + { + dest = &DoubleBindings; + sc.MustGetString(); + } + else if (sc.Compare("mapbind")) + { + dest = &AutomapBindings; + sc.MustGetString(); + } + else if (sc.Compare("unbind")) + { + sc.MustGetString(); + dest->UnbindKey(sc.String); + continue; + } + key = GetConfigKeyFromName(sc.String); + sc.MustGetString(); + dest->SetBind(key, sc.String, override); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void C_SetDefaultKeys(const char* baseconfig) +{ + auto lump = fileSystem.CheckNumForFullName("engine/commonbinds.txt"); + if (lump >= 0) + { + // Bail out if a mod tries to override this. Main game resources are allowed to do this, though. + auto fileno2 = fileSystem.GetFileContainer(lump); + if (fileno2 > fileSystem.GetMaxIwadNum()) + { + I_FatalError("File %s is overriding core lump %s.", + fileSystem.GetResourceFileFullName(fileno2), "engine/commonbinds.txt"); + } + + ReadBindings(lump, true); + } + int lastlump = 0; + + while ((lump = fileSystem.FindLumpFullName(baseconfig, &lastlump)) != -1) + { + // Read this only from the main game resources. + if (fileSystem.GetFileContainer(lump) <= fileSystem.GetMaxIwadNum()) + ReadBindings(lump, true); + } + + lastlump = 0; + while ((lump = fileSystem.FindLump("DEFBINDS", &lastlump)) != -1) + { + // [SW] - We need to check to see the origin of the DEFBINDS... if it + // Comes from an IWAD/IPK3/IPK7 allow it to override the users settings... + // If it comes from a user mod however, don't. + if (fileSystem.GetFileContainer(lump) > fileSystem.GetMaxIwadNum()) + ReadBindings(lump, false); + else + ReadBindings(lump, true); + } +} + +//============================================================================= +// +// +// +//============================================================================= +CVAR(Int, cl_defaultconfiguration, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + + +void C_BindDefaults() +{ + C_SetDefaultKeys(cl_defaultconfiguration == 1 ? "engine/origbinds.txt" : cl_defaultconfiguration == 2 ? "engine/leftbinds.txt" : "engine/defbinds.txt"); +} + +void C_SetDefaultBindings() +{ + C_UnbindAll(); + C_BindDefaults(); +} + + +CCMD(controlpreset) +{ + if (argv.argc() < 2) + { + Printf("Usage: Controlpreset {0,1,2}\n"); + return; + } + int v = atoi(argv[1]); + if (v < 0 || v > 2) return; + cl_defaultconfiguration = v; + C_SetDefaultBindings(); +} + +CCMD(binddefaults) +{ + C_BindDefaults(); +} + +//============================================================================= +// +// +// +//============================================================================= + +bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds) +{ + FString binding; + bool dclick; + unsigned int nowtime; + + if (ev->type != EV_KeyDown && ev->type != EV_KeyUp) + return false; + + if ((unsigned int)ev->data1 >= NUM_KEYS) + return false; + + dclick = false; + + nowtime = (unsigned)I_msTime(); + if (doublebinds != nullptr && int(DClickTime[ev->data1] - nowtime) > 0 && ev->type == EV_KeyDown) + { + // Key pressed for a double click + binding = doublebinds->GetBinding(ev->data1); + DClicked.Set(ev->data1); + dclick = true; + } + else + { + if (ev->type == EV_KeyDown) + { // Key pressed for a normal press + binding = binds->GetBinding(ev->data1); + if (doublebinds != nullptr) DClickTime[ev->data1] = nowtime + 571; + } + else if (doublebinds != nullptr && DClicked[ev->data1]) + { // Key released from a double click + binding = doublebinds->GetBinding(ev->data1); + DClicked.Clear(ev->data1); + DClickTime[ev->data1] = 0; + dclick = true; + } + else + { // Key released from a normal press + binding = binds->GetBinding(ev->data1); + } + } + + + if (binding.IsEmpty()) + { + binding = binds->GetBinding(ev->data1); + dclick = false; + } + + if (ev->type == EV_KeyUp && binding[0] != '+') + { + return false; + } + + if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256)) + { + char *copy = binding.LockBuffer(); + + if (ev->type == EV_KeyUp) + { + copy[0] = '-'; + } + + AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1); + return true; + } + return false; +} + diff --git a/src/console/c_bind.h b/src/common/console/c_bind.h similarity index 88% rename from src/console/c_bind.h rename to src/common/console/c_bind.h index ead6b8809fc..ada3cb84e6a 100644 --- a/src/console/c_bind.h +++ b/src/common/console/c_bind.h @@ -34,13 +34,16 @@ #ifndef __C_BINDINGS_H__ #define __C_BINDINGS_H__ -#include "doomdef.h" +#include "keydef.h" +#include "zstring.h" +#include "tarray.h" struct event_t; class FConfigFile; class FCommandLine; void C_NameKeys (char *str, int first, int second); +FString C_NameKeys (int *keys, int count, bool colors = false); class FKeyBindings { @@ -51,14 +54,16 @@ class FKeyBindings bool DoKey(event_t *ev); void ArchiveBindings(FConfigFile *F, const char *matchcmd = NULL); int GetKeysForCommand (const char *cmd, int *first, int *second); + TArray GetKeysForCommand (const char *cmd); void UnbindACommand (const char *str); void UnbindAll (); void UnbindKey(const char *key); void DoBind (const char *key, const char *bind); void DefaultBind(const char *keyname, const char *cmd); - void SetBind(unsigned int key, const char *bind) + void SetBind(unsigned int key, const char *bind, bool override = true) { + if (!override && Binds[key].IsNotEmpty()) return; if (key < NUM_KEYS) Binds[key] = bind; } @@ -69,8 +74,12 @@ class FKeyBindings const char *GetBind(unsigned int index) const { - if (index < NUM_KEYS) return Binds[index].GetChars(); - else return NULL; + if (index < NUM_KEYS) + { + auto c = Binds[index].GetChars(); + if (*c) return c; + } + return NULL; } }; @@ -78,7 +87,6 @@ class FKeyBindings extern FKeyBindings Bindings; extern FKeyBindings DoubleBindings; extern FKeyBindings AutomapBindings; -extern FKeyBindings MenuBindings; bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds); @@ -104,3 +112,4 @@ struct FKeySection extern TArray KeySections; #endif //__C_BINDINGS_H__ + diff --git a/src/common/console/c_buttons.cpp b/src/common/console/c_buttons.cpp new file mode 100644 index 00000000000..3464553e3c9 --- /dev/null +++ b/src/common/console/c_buttons.cpp @@ -0,0 +1,261 @@ +/* +** c_dispatch.cpp +** Functions for executing console commands and aliases +** +**--------------------------------------------------------------------------- +** Copyright 1998-2007 Randy Heit +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_buttons.h" + +#include "c_dispatch.h" +#include "printf.h" +#include "cmdlib.h" +#include "c_console.h" + +ButtonMap buttonMap; + + +//============================================================================= +// +// +// +//============================================================================= + +void ButtonMap::SetButtons(const char** names, int count) +{ + Buttons.Resize(count); + NumToName.Resize(count); + NameToNum.Clear(); + for(int i = 0; i < count; i++) + { + Buttons[i] = {}; + NameToNum.Insert(names[i], i); + NumToName[i] = names[i]; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +int ButtonMap::ListActionCommands (const char *pattern) +{ + char matcher[32]; + int count = 0; + + for (auto& btn : NumToName) + { + if (pattern == NULL || CheckWildcards (pattern, + (mysnprintf (matcher, countof(matcher), "+%s", btn.GetChars()), matcher))) + { + Printf ("+%s\n", btn.GetChars()); + count++; + } + if (pattern == NULL || CheckWildcards (pattern, + (mysnprintf (matcher, countof(matcher), "-%s", btn.GetChars()), matcher))) + { + Printf ("-%s\n", btn.GetChars()); + count++; + } + } + return count; +} + + +//============================================================================= +// +// +// +//============================================================================= + +int ButtonMap::FindButtonIndex (const char *key, int funclen) const +{ + if (!key) return -1; + + FName name = funclen == -1? FName(key, true) : FName(key, funclen, true); + if (name == NAME_None) return -1; + + auto res = NameToNum.CheckKey(name); + if (!res) return -1; + + return *res; +} + + +//============================================================================= +// +// +// +//============================================================================= + +void ButtonMap::ResetButtonTriggers () +{ + for (auto &button : Buttons) + { + button.ResetTriggers (); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void ButtonMap::ResetButtonStates () +{ + for (auto &btn : Buttons) + { + if (!btn.bReleaseLock) + { + btn.ReleaseKey (0); + } + btn.ResetTriggers (); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +bool FButtonStatus::PressKey (int keynum) +{ + int i, open; + + keynum &= KEY_DBLCLICKED-1; + + if (keynum == 0) + { // Issued from console instead of a key, so force on + Keys[0] = 0xffff; + for (i = MAX_KEYS-1; i > 0; --i) + { + Keys[i] = 0; + } + } + else + { + for (i = MAX_KEYS-1, open = -1; i >= 0; --i) + { + if (Keys[i] == 0) + { + open = i; + } + else if (Keys[i] == keynum) + { // Key is already down; do nothing + return false; + } + } + if (open < 0) + { // No free key slots, so do nothing + Printf ("More than %u keys pressed for a single action!\n", MAX_KEYS); + return false; + } + Keys[open] = keynum; + } + uint8_t wasdown = bDown; + bDown = bWentDown = true; + // Returns true if this key caused the button to go down. + return !wasdown; +} + +//============================================================================= +// +// +// +//============================================================================= + +bool FButtonStatus::ReleaseKey (int keynum) +{ + int i, numdown, match; + uint8_t wasdown = bDown; + + keynum &= KEY_DBLCLICKED-1; + + if (keynum == 0) + { // Issued from console instead of a key, so force off + for (i = MAX_KEYS-1; i >= 0; --i) + { + Keys[i] = 0; + } + bWentUp = true; + bDown = false; + } + else + { + for (i = MAX_KEYS-1, numdown = 0, match = -1; i >= 0; --i) + { + if (Keys[i] != 0) + { + ++numdown; + if (Keys[i] == keynum) + { + match = i; + } + } + } + if (match < 0) + { // Key was not down; do nothing + return false; + } + Keys[match] = 0; + bWentUp = true; + if (--numdown == 0) + { + bDown = false; + } + } + // Returns true if releasing this key caused the button to go up. + return wasdown && !bDown; +} + +//============================================================================= +// +// +// +//============================================================================= + +void ButtonMap::AddButtonTabCommands() +{ + // Add all the action commands for tab completion + for (auto& btn : NumToName) + { + char tname[16]; + strcpy (&tname[1], btn.GetChars()); + tname[0] = '+'; + C_AddTabCommand (tname); + tname[0] = '-'; + C_AddTabCommand (tname); + } +} diff --git a/src/common/console/c_buttons.h b/src/common/console/c_buttons.h new file mode 100644 index 00000000000..3bfbbd0fb03 --- /dev/null +++ b/src/common/console/c_buttons.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include "tarray.h" +#include "name.h" + +// Actions +struct FButtonStatus +{ + enum { MAX_KEYS = 6 }; // Maximum number of keys that can press this button + + uint16_t Keys[MAX_KEYS]; + bool bDown; // Button is down right now + bool bWentDown; // Button went down this tic + bool bWentUp; // Button went up this tic + bool bReleaseLock; // Lock ReleaseKey call in ResetButtonStates + void (*PressHandler)(); // for optional game-side customization + void (*ReleaseHandler)(); + + bool PressKey (int keynum); // Returns true if this key caused the button to be pressed. + bool ReleaseKey (int keynum); // Returns true if this key is no longer pressed. + void ResetTriggers () { bWentDown = bWentUp = false; } + void Reset () { bDown = bWentDown = bWentUp = false; } +}; + +class ButtonMap +{ + + TArray Buttons; + TArray NumToName; // The internal name of the button + TMap NameToNum; + +public: + void SetButtons(const char** names, int count); + + int NumButtons() const + { + return Buttons.Size(); + } + + int FindButtonIndex(const char* func, int funclen = -1) const; + + FButtonStatus* FindButton(const char* func, int funclen = -1) + { + int index = FindButtonIndex(func, funclen); + return index > -1 ? &Buttons[index] : nullptr; + } + + FButtonStatus* GetButton(int index) + { + return &Buttons[index]; + } + + void ResetButtonTriggers(); // Call ResetTriggers for all buttons + void ResetButtonStates(); // Same as above, but also clear bDown + int ListActionCommands(const char* pattern); + void AddButtonTabCommands(); + + + bool ButtonDown(int x) const + { + return Buttons[x].bDown; + } + + bool ButtonPressed(int x) const + { + return Buttons[x].bWentDown; + } + + bool ButtonReleased(int x) const + { + return Buttons[x].bWentUp; + } + + void ButtonSet(int x) const + { + Buttons[x].bDown = Buttons[x].bWentDown = true; + Buttons[x].bWentUp = false; + } + + void ClearButton(int x) + { + Buttons[x].Reset(); + } +}; + +extern ButtonMap buttonMap; diff --git a/src/common/console/c_commandbuffer.cpp b/src/common/console/c_commandbuffer.cpp new file mode 100644 index 00000000000..0c570da1424 --- /dev/null +++ b/src/common/console/c_commandbuffer.cpp @@ -0,0 +1,341 @@ +/* +** c_commandbuffer.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** Copyright 2010-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include "c_commandbuffer.h" +#include "v_draw.h" +#include "v_2ddrawer.h" +#include "v_font.h" +#include "utf8.h" + +FCommandBuffer CmdLine; + +FCommandBuffer::FCommandBuffer(const FCommandBuffer &o) +{ + Text = o.Text; + CursorPos = o.CursorPos; + StartPos = o.StartPos; +} + +FString FCommandBuffer::GetText() const +{ + FString build; + for (auto chr : Text) build.AppendCharacter(chr); + return build; +} + +void FCommandBuffer::Draw(int x, int y, int scale, bool cursor) +{ + if (scale == 1) + { + DrawChar(twod, CurrentConsoleFont, CR_ORANGE, x, y, '\x1c', TAG_DONE); + DrawText(twod, CurrentConsoleFont, CR_ORANGE, x + CurrentConsoleFont->GetCharWidth(0x1c), y, + &Text[StartPos], TAG_DONE); + + if (cursor) + { + DrawChar(twod, CurrentConsoleFont, CR_YELLOW, + x + CurrentConsoleFont->GetCharWidth(0x1c) + (CursorPosCells - StartPosCells) * CurrentConsoleFont->GetCharWidth(0xb), + y, '\xb', TAG_DONE); + } + } + else + { + DrawChar(twod, CurrentConsoleFont, CR_ORANGE, x, y, '\x1c', + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, + DTA_KeepRatio, true, TAG_DONE); + + DrawText(twod, CurrentConsoleFont, CR_ORANGE, x + CurrentConsoleFont->GetCharWidth(0x1c), y, + &Text[StartPos], + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, + DTA_KeepRatio, true, TAG_DONE); + + if (cursor) + { + DrawChar(twod, CurrentConsoleFont, CR_YELLOW, + x + CurrentConsoleFont->GetCharWidth(0x1c) + (CursorPosCells - StartPosCells) * CurrentConsoleFont->GetCharWidth(0xb), + y, '\xb', + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, + DTA_KeepRatio, true, TAG_DONE); + } + } +} + +unsigned FCommandBuffer::CalcCellSize(unsigned length) +{ + unsigned cellcount = 0; + for (unsigned i = 0; i < length; i++) + { + int w = NewConsoleFont->GetCharWidth(Text[i]); + cellcount += w / 9; + } + return cellcount; + +} + +unsigned FCommandBuffer::CharsForCells(unsigned cellin, bool *overflow) +{ + unsigned chars = 0; + int cells = cellin; + while (cells > 0) + { + int w = NewConsoleFont->GetCharWidth(Text[chars++]); + cells -= w / 9; + } + *overflow = (cells < 0); + return chars; +} + + +void FCommandBuffer::MakeStartPosGood() +{ + // Make sure both values point to something valid. + if (CursorPos > Text.length()) CursorPos = (unsigned)Text.length(); + if (StartPos > Text.length()) StartPos = (unsigned)Text.length(); + + CursorPosCells = CalcCellSize(CursorPos); + StartPosCells = CalcCellSize(StartPos); + unsigned LengthCells = CalcCellSize((unsigned)Text.length()); + + int n = StartPosCells; + unsigned cols = ConCols / active_con_scale(twod); + + if (StartPosCells >= LengthCells) + { // Start of visible line is beyond end of line + n = CursorPosCells - cols + 2; + } + if ((CursorPosCells - StartPosCells) >= cols - 2) + { // The cursor is beyond the visible part of the line + n = CursorPosCells - cols + 2; + } + if (StartPosCells > CursorPosCells) + { // The cursor is in front of the visible part of the line + n = CursorPosCells; + } + StartPosCells = max(0, n); + bool overflow; + StartPos = CharsForCells(StartPosCells, &overflow); + if (overflow) + { + // We ended up in the middle of a double cell character, so set the start to the following character. + StartPosCells++; + StartPos = CharsForCells(StartPosCells, &overflow); + } +} + +void FCommandBuffer::CursorStart() +{ + CursorPos = 0; + StartPos = 0; + CursorPosCells = 0; + StartPosCells = 0; +} + +void FCommandBuffer::CursorEnd() +{ + CursorPos = (unsigned)Text.length(); + MakeStartPosGood(); +} + +void FCommandBuffer::CursorLeft() +{ + if (CursorPos > 0) + { + MoveCursorLeft(); + MakeStartPosGood(); + } +} + +void FCommandBuffer::CursorRight() +{ + if (CursorPos < Text.length()) + { + MoveCursorRight(); + MakeStartPosGood(); + } +} + +void FCommandBuffer::CursorWordLeft() +{ + if (CursorPos > 0) + { + do MoveCursorLeft(); + while (CursorPos > 0 && Text[CursorPos - 1] != ' '); + MakeStartPosGood(); + } +} + +void FCommandBuffer::CursorWordRight() +{ + if (CursorPos < Text.length()) + { + do MoveCursorRight(); + while (CursorPos < Text.length() && Text[CursorPos] != ' '); + MakeStartPosGood(); + } +} + +void FCommandBuffer::DeleteLeft() +{ + if (CursorPos > 0) + { + MoveCursorLeft(); + Text.erase(CursorPos, 1); + MakeStartPosGood(); + } +} + +void FCommandBuffer::DeleteRight() +{ + if (CursorPos < Text.length()) + { + Text.erase(CursorPos, 1); + MakeStartPosGood(); + } +} + +void FCommandBuffer::DeleteWordLeft() +{ + if (CursorPos > 0) + { + auto now = CursorPos; + + CursorWordLeft(); + + if (AppendToYankBuffer) { + YankBuffer = Text.substr(CursorPos, now - CursorPos) + YankBuffer; + } else { + YankBuffer = Text.substr(CursorPos, now - CursorPos); + } + Text.erase(CursorPos, now - CursorPos); + MakeStartPosGood(); + } +} + +void FCommandBuffer::DeleteLineLeft() +{ + if (CursorPos > 0) + { + if (AppendToYankBuffer) { + YankBuffer = Text.substr(0, CursorPos) + YankBuffer; + } else { + YankBuffer = Text.substr(0, CursorPos); + } + Text.erase(0, CursorPos); + CursorStart(); + } +} + +void FCommandBuffer::DeleteLineRight() +{ + if (CursorPos < Text.length()) + { + if (AppendToYankBuffer) { + YankBuffer += Text.substr(CursorPos, Text.length() - CursorPos); + } else { + YankBuffer = Text.substr(CursorPos, Text.length() - CursorPos); + } + Text.resize(CursorPos); + CursorEnd(); + } +} + +void FCommandBuffer::AddChar(int character) +{ + if (Text.length() == 0) + { + Text += character; + } + else + { + Text.insert(CursorPos, 1, character); + } + CursorPos++; + MakeStartPosGood(); +} + +void FCommandBuffer::AddString(FString clip) +{ + if (clip.IsNotEmpty()) + { + // Only paste the first line. + auto brk = clip.IndexOfAny("\r\n\b"); + std::u32string build; + if (brk >= 0) + { + clip.Truncate(brk); + } + auto strp = (const uint8_t*)clip.GetChars(); + while (auto chr = GetCharFromString(strp)) build += chr; + + if (Text.length() == 0) + { + Text = build; + } + else + { + Text.insert(CursorPos, build); + } + CursorPos += (unsigned)build.length(); + MakeStartPosGood(); + } +} + +void FCommandBuffer::SetString(const FString &str) +{ + Text.clear(); + auto strp = (const uint8_t*)str.GetChars(); + while (auto chr = GetCharFromString(strp)) Text += chr; + + CursorEnd(); + MakeStartPosGood(); +} + +void FCommandBuffer::AddYankBuffer() +{ + if (YankBuffer.length() > 0) + { + if (Text.length() == 0) + { + Text = YankBuffer; + } + else + { + Text.insert(CursorPos, YankBuffer); + } + CursorPos += (unsigned)YankBuffer.length(); + MakeStartPosGood(); + } +} diff --git a/src/common/console/c_commandbuffer.h b/src/common/console/c_commandbuffer.h new file mode 100644 index 00000000000..637027b27ca --- /dev/null +++ b/src/common/console/c_commandbuffer.h @@ -0,0 +1,64 @@ +#pragma once +#include +#include "zstring.h" + +struct FCommandBuffer +{ +private: + std::u32string Text; + unsigned CursorPos = 0; + unsigned StartPos = 0; // First character to display + unsigned CursorPosCells = 0; + unsigned StartPosCells = 0; + + std::u32string YankBuffer; // Deleted text buffer + +public: + bool AppendToYankBuffer = false; // Append consecutive deletes to buffer + int ConCols; + + FCommandBuffer() = default; + + FCommandBuffer(const FCommandBuffer &o); + FString GetText() const; + + size_t TextLength() const + { + return Text.length(); + } + + void Draw(int x, int y, int scale, bool cursor); + unsigned CalcCellSize(unsigned length); + unsigned CharsForCells(unsigned cellin, bool *overflow); + void MakeStartPosGood(); + void CursorStart(); + void CursorEnd(); + +private: + void MoveCursorLeft() + { + CursorPos--; + } + + void MoveCursorRight() + { + CursorPos++; + } + +public: + void CursorLeft(); + void CursorRight(); + void CursorWordLeft(); + void CursorWordRight(); + void DeleteLeft(); + void DeleteRight(); + void DeleteWordLeft(); + void DeleteLineLeft(); + void DeleteLineRight(); + void AddChar(int character); + void AddString(FString clip); + void SetString(const FString &str); + void AddYankBuffer(); +}; + +extern FCommandBuffer CmdLine; diff --git a/src/common/console/c_commandline.cpp b/src/common/console/c_commandline.cpp new file mode 100644 index 00000000000..4f500ffe668 --- /dev/null +++ b/src/common/console/c_commandline.cpp @@ -0,0 +1,206 @@ +/* +** c_dispatch.cpp +** Functions for executing console commands and aliases +** +**--------------------------------------------------------------------------- +** Copyright 1998-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include + +#include "c_commandline.h" +#include "c_cvars.h" +#include "v_text.h" + +// ParseCommandLine +// +// Parse a command line (passed in args). If argc is non-NULL, it will +// be set to the number of arguments. If argv is non-NULL, it will be +// filled with pointers to each argument; argv[0] should be initialized +// to point to a buffer large enough to hold all the arguments. The +// return value is the necessary size of this buffer. +// +// Special processing: +// Inside quoted strings, \" becomes just " +// \\ becomes just a single backslash +// \c becomes just TEXTCOLOR_ESCAPE +// $ is replaced by the contents of + +static size_t ParseCommandLine(const char* args, int* argc, char** argv, bool no_escapes) +{ + int count; + char* buffstart; + char* buffplace; + + count = 0; + buffstart = NULL; + if (argv != NULL) + { + buffstart = argv[0]; + } + buffplace = buffstart; + + for (;;) + { + while (*args <= ' ' && *args) + { // skip white space + args++; + } + if (*args == 0) + { + break; + } + else if (*args == '\"') + { // read quoted string + char stuff; + if (argv != NULL) + { + argv[count] = buffplace; + } + count++; + args++; + do + { + stuff = *args++; + if (!no_escapes && stuff == '\\' && *args == '\"') + { + stuff = '\"', args++; + } + else if (!no_escapes && stuff == '\\' && *args == '\\') + { + args++; + } + else if (!no_escapes && stuff == '\\' && *args == 'c') + { + stuff = TEXTCOLOR_ESCAPE, args++; + } + else if (stuff == '\"') + { + stuff = 0; + } + else if (stuff == 0) + { + args--; + } + if (argv != NULL) + { + *buffplace = stuff; + } + buffplace++; + } while (stuff); + } + else + { // read unquoted string + const char* start = args++, * end; + FBaseCVar* var; + UCVarValue val; + + while (*args && *args > ' ' && *args != '\"') + args++; + if (*start == '$' && (var = FindCVarSub(start + 1, int(args - start - 1)))) + { + val = var->GetGenericRep(CVAR_String); + start = val.String; + end = start + strlen(start); + } + else + { + end = args; + } + if (argv != NULL) + { + argv[count] = buffplace; + while (start < end) + *buffplace++ = *start++; + *buffplace++ = 0; + } + else + { + buffplace += end - start + 1; + } + count++; + } + } + if (argc != NULL) + { + *argc = count; + } + return (buffplace - buffstart); +} + +FCommandLine::FCommandLine (const char *commandline, bool no_escapes) +{ + cmd = commandline; + _argc = -1; + _argv = NULL; + noescapes = no_escapes; +} + +FCommandLine::~FCommandLine () +{ + if (_argv != NULL) + { + delete[] _argv; + } +} + +void FCommandLine::Shift() +{ + // Only valid after _argv has been filled. + for (int i = 1; i < _argc; ++i) + { + _argv[i - 1] = _argv[i]; + } +} + +int FCommandLine::argc () +{ + if (_argc == -1) + { + argsize = ParseCommandLine (cmd, &_argc, NULL, noescapes); + } + return _argc; +} + +char *FCommandLine::operator[] (int i) +{ + if (_argv == NULL) + { + int count = argc(); + _argv = new char *[count + (argsize+sizeof(char*)-1)/sizeof(char*)]; + _argv[0] = (char *)_argv + count*sizeof(char *); + ParseCommandLine (cmd, NULL, _argv, noescapes); + } + return _argv[i]; +} diff --git a/src/common/console/c_commandline.h b/src/common/console/c_commandline.h new file mode 100644 index 00000000000..dc5466df1cb --- /dev/null +++ b/src/common/console/c_commandline.h @@ -0,0 +1,58 @@ +#pragma once +/* +** c_dispatch.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +class FConfigFile; +struct CCmdFuncParm; + + +// Class that can parse command lines +class FCommandLine +{ + friend int C_RegisterFunction(const char* name, const char* help, int (*func)(CCmdFuncParm const* const)); +public: + FCommandLine (const char *commandline, bool no_escapes = false); + ~FCommandLine (); + int argc (); + char *operator[] (int i); + const char *args () { return cmd; } + void Shift(); + +private: + const char *cmd; + bool noescapes; + int _argc; + char **_argv; + size_t argsize; +}; + diff --git a/src/common/console/c_console.cpp b/src/common/console/c_console.cpp new file mode 100644 index 00000000000..44c8ffacf6a --- /dev/null +++ b/src/common/console/c_console.cpp @@ -0,0 +1,1187 @@ +/* +** c_console.cpp +** Implements the console itself +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include + + +#include "version.h" +#include "c_bind.h" +#include "c_console.h" +#include "c_cvars.h" +#include "c_dispatch.h" +#include "gamestate.h" +#include "v_text.h" +#include "filesystem.h" +#include "d_gui.h" +#include "cmdlib.h" +#include "d_eventbase.h" +#include "c_consolebuffer.h" +#include "utf8.h" +#include "v_2ddrawer.h" +#include "v_draw.h" +#include "v_font.h" +#include "printf.h" +#include "i_time.h" +#include "texturemanager.h" +#include "v_draw.h" +#include "i_interface.h" +#include "v_video.h" +#include "i_system.h" +#include "menu.h" +#include "menustate.h" +#include "v_2ddrawer.h" +#include "c_notifybufferbase.h" +#include "g_input.h" +#include "c_commandbuffer.h" +#include "vm.h" + +#define LEFTMARGIN 8 +#define RIGHTMARGIN 8 +#define BOTTOMARGIN 12 + +extern bool AppActive; + +CUSTOM_CVAR(Int, con_buffersize, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + // ensure a minimum size + if (self >= 0 && self < 128) self = 128; +} + +double NotifyFontScale = 1; + +DEFINE_GLOBAL(NotifyFontScale) + +void C_SetNotifyFontScale(double scale) +{ + NotifyFontScale = scale; +} + + +FConsoleBuffer *conbuffer; + +static FTextureID conback; +static FTextureID conflat; +static uint32_t conshade; +static bool conline; + +extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE]; + +int ConWidth; +bool vidactive = false; +bool cursoron = false; +int ConBottom, ConScroll, RowAdjust; +uint64_t CursorTicker; +uint8_t ConsoleState = c_up; + +DEFINE_GLOBAL(ConsoleState) + +static int TopLine, InsertLine; + +static void ClearConsole (); + +struct GameAtExit +{ + GameAtExit(FString str) : Command(str) {} + + GameAtExit *Next; + FString Command; +}; + +static GameAtExit *ExitCmdList; + +#define SCROLLUP 1 +#define SCROLLDN 2 +#define SCROLLNO 0 + +// Buffer for AddToConsole() +static char *work = NULL; +static int worklen = 0; + +CUSTOM_CVAR(Int, con_scale, 0, CVAR_ARCHIVE) +{ + if (self < 0) self = 0; +} + +CUSTOM_CVAR(Float, con_alpha, 0.75f, CVAR_ARCHIVE) +{ + if (self < 0.f) self = 0.f; + if (self > 1.f) self = 1.f; +} + +// Show developer messages if true. +CUSTOM_CVAR(Int, developer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + FScriptPosition::Developer = self; +} + + +// Command to run when Ctrl-D is pressed at start of line +CVAR(String, con_ctrl_d, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + + +struct History +{ + struct History *Older; + struct History *Newer; + FString String; +}; + +#define MAXHISTSIZE 50 +static struct History *HistHead = NULL, *HistTail = NULL, *HistPos = NULL; +static int HistSize; + +static FNotifyBufferBase *NotifyStrings; + +void C_SetNotifyBuffer(FNotifyBufferBase* nbb) +{ + NotifyStrings = nbb; +} + + + +int PrintColors[PRINTLEVELS+2] = { CR_UNTRANSLATED, CR_GOLD, CR_GRAY, CR_GREEN, CR_GREEN, CR_UNTRANSLATED }; + +static void setmsgcolor (int index, int color); + +FILE *Logfile = NULL; + + +CVARD_NAMED(Int, msglevel, msg, 0, CVAR_ARCHIVE, "Filters HUD message by importance"); + +CUSTOM_CVAR (Int, msg0color, CR_UNTRANSLATED, CVAR_ARCHIVE) +{ + setmsgcolor (0, self); +} + +CUSTOM_CVAR (Int, msg1color, CR_GOLD, CVAR_ARCHIVE) +{ + setmsgcolor (1, self); +} + +CUSTOM_CVAR (Int, msg2color, CR_GRAY, CVAR_ARCHIVE) +{ + setmsgcolor (2, self); +} + +CUSTOM_CVAR (Int, msg3color, CR_GREEN, CVAR_ARCHIVE) +{ + setmsgcolor (3, self); +} + +CUSTOM_CVAR (Int, msg4color, CR_GREEN, CVAR_ARCHIVE) +{ + setmsgcolor (4, self); +} + +CUSTOM_CVAR (Int, msgmidcolor, CR_UNTRANSLATED, CVAR_ARCHIVE) +{ + setmsgcolor (PRINTLEVELS, self); +} + +CUSTOM_CVAR (Int, msgmidcolor2, CR_BROWN, CVAR_ARCHIVE) +{ + setmsgcolor (PRINTLEVELS+1, self); +} + +void C_InitConback(FTextureID fallback, bool tile, double brightness) +{ + conback = TexMan.CheckForTexture ("CONBACK", ETextureType::MiscPatch); + conflat = fallback; + if (!conback.isValid()) + { + conback.SetInvalid(); + conshade = MAKEARGB(uint8_t(255 - 255*brightness),0,0,0); + conline = true; + if (!tile) conback = fallback; + } + else + { + conshade = 0; + conline = false; + } +} + +void C_InitConsole (int width, int height, bool ingame) +{ + int cwidth, cheight; + + vidactive = ingame; + if (CurrentConsoleFont != NULL) + { + cwidth = CurrentConsoleFont->GetCharWidth ('M'); + cheight = CurrentConsoleFont->GetHeight(); + } + else + { + cwidth = cheight = 8; + } + ConWidth = (width - LEFTMARGIN - RIGHTMARGIN); + CmdLine.ConCols = ConWidth / cwidth; + + if (conbuffer == NULL) conbuffer = new FConsoleBuffer; +} + +//========================================================================== +// +// CCMD atexit +// +//========================================================================== + +UNSAFE_CCMD (atexit) +{ + if (argv.argc() == 1) + { + Printf ("Registered atexit commands:\n"); + GameAtExit *record = ExitCmdList; + while (record != NULL) + { + Printf ("%s\n", record->Command.GetChars()); + record = record->Next; + } + return; + } + for (int i = 1; i < argv.argc(); ++i) + { + GameAtExit *record = new GameAtExit(argv[i]); + record->Next = ExitCmdList; + ExitCmdList = record; + } +} + +//========================================================================== +// +// C_DeinitConsole +// +// Executes the contents of the atexit cvar, if any, at quit time. +// Then releases all of the console's memory. +// +//========================================================================== + +void C_DeinitConsole () +{ + GameAtExit *cmd = ExitCmdList; + + while (cmd != NULL) + { + GameAtExit *next = cmd->Next; + AddCommandString (cmd->Command.GetChars()); + delete cmd; + cmd = next; + } + + // Free command history + History *hist = HistTail; + + while (hist != NULL) + { + History *next = hist->Newer; + delete hist; + hist = next; + } + HistTail = HistHead = HistPos = NULL; + + // Free alias commands. (i.e. The "commands" that can be allocated + // at runtime.) + for (size_t i = 0; i < countof(Commands); ++i) + { + FConsoleCommand *command = Commands[i]; + + while (command != NULL) + { + FConsoleCommand *nextcmd = command->m_Next; + if (command->IsAlias()) + { + delete command; + } + command = nextcmd; + } + } + + // Make sure all tab commands are cleared before the memory for + // their names is deallocated. + C_ClearTabCommands (); + C_ClearDynCCmds(); + + // Free AddToConsole()'s work buffer + if (work != NULL) + { + free (work); + work = NULL; + worklen = 0; + } + + if (conbuffer != NULL) + { + delete conbuffer; + conbuffer = NULL; + } +} + +static void ClearConsole () +{ + if (conbuffer != NULL) + { + conbuffer->Clear(); + } + TopLine = InsertLine = 0; +} + +static void setmsgcolor (int index, int color) +{ + if ((unsigned)color >= (unsigned)NUM_TEXT_COLORS) + color = 0; + PrintColors[index] = color; +} + + +void AddToConsole (int printlevel, const char *text) +{ + conbuffer->AddText(printlevel, MakeUTF8(text)); +} + +//========================================================================== +// +// +// +//========================================================================== + +void WriteLineToLog(FILE *LogFile, const char *outline) +{ + // Strip out any color escape sequences before writing to the log file + TArray copy(strlen(outline) + 1); + const char * srcp = outline; + char * dstp = copy.Data(); + + while (*srcp != 0) + { + + if (*srcp != TEXTCOLOR_ESCAPE) + { + *dstp++ = *srcp++; + } + else if (srcp[1] == '[') + { + srcp += 2; + while (*srcp != ']' && *srcp != 0) srcp++; + if (*srcp == ']') srcp++; + } + else + { + if (srcp[1] != 0) srcp += 2; + else break; + } + } + *dstp = 0; + + fputs(copy.Data(), LogFile); + fflush(LogFile); +} + +extern bool gameisdead; + +int PrintString (int iprintlevel, const char *outline) +{ + if (gameisdead) + return 0; + + if (!conbuffer) return 0; // when called too early + int printlevel = iprintlevel & PRINT_TYPES; + if (*outline == '\0') + { + return 0; + } + if (printlevel != PRINT_LOG || Logfile != nullptr) + { + // Convert everything coming through here to UTF-8 so that all console text is in a consistent format + int count; + outline = MakeUTF8(outline, &count); + + if (printlevel != PRINT_LOG) + { + I_PrintStr(outline); + + conbuffer->AddText(printlevel, outline); + if (vidactive && screen && !(iprintlevel & PRINT_NONOTIFY) && NotifyStrings) + { + if (printlevel >= msglevel) + { + NotifyStrings->AddString(iprintlevel, outline); + } + } + } + if (Logfile != nullptr && !(iprintlevel & PRINT_NOLOG)) + { + WriteLineToLog(Logfile, outline); + } + return count; + } + return 0; // Don't waste time on calculating this if nothing at all was printed... +} + +int VPrintf (int printlevel, const char *format, va_list parms) +{ + FString outline; + outline.VFormat (format, parms); + return PrintString (printlevel, outline.GetChars()); +} + +int Printf (int printlevel, const char *format, ...) +{ + va_list argptr; + int count; + + va_start (argptr, format); + count = VPrintf (printlevel, format, argptr); + va_end (argptr); + + return count; +} + +int Printf (const char *format, ...) +{ + va_list argptr; + int count; + + va_start (argptr, format); + count = VPrintf (PRINT_HIGH, format, argptr); + va_end (argptr); + + return count; +} + +int DPrintf (int level, const char *format, ...) +{ + va_list argptr; + int count; + + if (developer >= level) + { + va_start (argptr, format); + count = VPrintf (PRINT_HIGH, format, argptr); + va_end (argptr); + return count; + } + else + { + return 0; + } +} + +void C_FlushDisplay () +{ + if (NotifyStrings) NotifyStrings->Clear(); +} + +void C_AdjustBottom () +{ + if (gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) + ConBottom = twod->GetHeight(); + else if (ConBottom > twod->GetHeight() / 2 || ConsoleState == c_down) + ConBottom = twod->GetHeight() / 2; +} + +void C_NewModeAdjust () +{ + C_InitConsole (screen->GetWidth(), screen->GetHeight(), true); + C_FlushDisplay (); + C_AdjustBottom (); +} + +int consoletic = 0; +void C_Ticker() +{ + static int lasttic = 0; + consoletic++; + + if (lasttic == 0) + lasttic = consoletic - 1; + + if (con_buffersize > 0) + { + conbuffer->ResizeBuffer(con_buffersize); + } + + if (ConsoleState != c_up) + { + if (ConsoleState == c_falling) + { + ConBottom += (consoletic - lasttic) * (twod->GetHeight() * 2 / 25); + if (ConBottom >= twod->GetHeight() / 2) + { + ConBottom = twod->GetHeight() / 2; + ConsoleState = c_down; + } + } + else if (ConsoleState == c_rising) + { + ConBottom -= (consoletic - lasttic) * (twod->GetHeight() * 2 / 25); + if (ConBottom <= 0) + { + ConsoleState = c_up; + ConBottom = 0; + } + } + } + + lasttic = consoletic; + if (NotifyStrings) NotifyStrings->Tick(); +} + +void C_DrawConsole () +{ + static int oldbottom = 0; + int lines, left, offset; + + int textScale = active_con_scale(twod); + + left = LEFTMARGIN; + lines = (ConBottom/textScale-CurrentConsoleFont->GetHeight()*2)/CurrentConsoleFont->GetHeight(); + if (-CurrentConsoleFont->GetHeight() + lines*CurrentConsoleFont->GetHeight() > ConBottom/textScale - CurrentConsoleFont->GetHeight()*7/2) + { + offset = -CurrentConsoleFont->GetHeight()/2; + lines--; + } + else + { + offset = -CurrentConsoleFont->GetHeight(); + } + + oldbottom = ConBottom; + + if (ConsoleState == c_up && gamestate == GS_LEVEL) + { + if (NotifyStrings) NotifyStrings->Draw(); + return; + } + else if (ConBottom) + { + int visheight; + + visheight = ConBottom; + + if (conback.isValid() && gamestate != GS_FULLCONSOLE) + { + DrawTexture (twod, conback, false, 0, visheight - screen->GetHeight(), + DTA_DestWidth, twod->GetWidth(), + DTA_DestHeight, twod->GetHeight(), + DTA_ColorOverlay, conshade, + DTA_Alpha, (gamestate != GS_FULLCONSOLE) ? (double)con_alpha : 1., + DTA_Masked, false, + TAG_DONE); + } + else + { + if (conflat.isValid() && gamestate != GS_FULLCONSOLE) + { + int conbright = 255 - APART(conshade); + PalEntry pe((uint8_t(255 * con_alpha)), conbright, conbright, conbright); + twod->AddFlatFill(0, visheight - screen->GetHeight(), screen->GetWidth(), visheight, TexMan.GetGameTexture(conflat), 1, CleanXfac, pe, STYLE_Shaded); + } + else + { + PalEntry pe((uint8_t)(con_alpha * 255), 0, 0, 0); + twod->AddColorOnlyQuad(0, 0, screen->GetWidth(), visheight, pe); + } + } + + if (conline && visheight < screen->GetHeight()) + { + twod->AddColorOnlyQuad(0, visheight, screen->GetWidth(), 1, 0xff000000); + } + + if (ConBottom >= 12) + { + if (textScale == 1) + DrawText(twod, CurrentConsoleFont, CR_ORANGE, twod->GetWidth() - 8 - + CurrentConsoleFont->StringWidth (GetVersionString()), + ConBottom / textScale - CurrentConsoleFont->GetHeight() - 4, + GetVersionString(), TAG_DONE); + else + DrawText(twod, CurrentConsoleFont, CR_ORANGE, twod->GetWidth() / textScale - 8 - + CurrentConsoleFont->StringWidth(GetVersionString()), + ConBottom / textScale - CurrentConsoleFont->GetHeight() - 4, + GetVersionString(), + DTA_VirtualWidth, twod->GetWidth() / textScale, + DTA_VirtualHeight, twod->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + + } + + } + + if (menuactive != MENU_Off) + { + return; + } + + if (lines > 0) + { + // No more enqueuing because adding new text to the console won't touch the actual print data. + conbuffer->FormatText(CurrentConsoleFont, ConWidth / textScale); + unsigned int consolelines = conbuffer->GetFormattedLineCount(); + FBrokenLines *blines = conbuffer->GetLines(); + if (blines != nullptr) + { + FBrokenLines* printline = blines + consolelines - 1 - RowAdjust; + + int bottomline = ConBottom / textScale - CurrentConsoleFont->GetHeight() * 2 - 4; + + for (FBrokenLines* p = printline; p >= blines && lines > 0; p--, lines--) + { + if (textScale == 1) + { + DrawText(twod, CurrentConsoleFont, CR_TAN, LEFTMARGIN, offset + lines * CurrentConsoleFont->GetHeight(), p->Text.GetChars(), TAG_DONE); + } + else + { + DrawText(twod, CurrentConsoleFont, CR_TAN, LEFTMARGIN, offset + lines * CurrentConsoleFont->GetHeight(), p->Text.GetChars(), + DTA_VirtualWidth, twod->GetWidth() / textScale, + DTA_VirtualHeight, twod->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + } + } + + if (ConBottom >= 20) + { + if (gamestate != GS_STARTUP) + { + auto now = I_msTime(); + if (now > CursorTicker) + { + CursorTicker = now + 500; + cursoron = !cursoron; + } + CmdLine.Draw(left, bottomline, textScale, cursoron); + } + if (RowAdjust && ConBottom >= CurrentConsoleFont->GetHeight() * 7 / 2) + { + // Indicate that the view has been scrolled up (10) + // and if we can scroll no further (12) + if (textScale == 1) + DrawChar(twod, CurrentConsoleFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, TAG_DONE); + else + DrawChar(twod, CurrentConsoleFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, + DTA_VirtualWidth, twod->GetWidth() / textScale, + DTA_VirtualHeight, twod->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + } + } + } + } +} + +void C_FullConsole () +{ + ConsoleState = c_down; + HistPos = NULL; + TabbedLast = false; + TabbedList = false; + gamestate = GS_FULLCONSOLE; + C_AdjustBottom (); +} + +void C_ToggleConsole () +{ + int togglestate; + if (gamestate == GS_INTRO) // blocked + { + return; + } + if (gamestate == GS_MENUSCREEN) + { + if (sysCallbacks.ToggleFullConsole) sysCallbacks.ToggleFullConsole(); + togglestate = c_down; + } + else if (!chatmodeon && (ConsoleState == c_up || ConsoleState == c_rising) && menuactive == MENU_Off) + { + ConsoleState = c_falling; + HistPos = NULL; + TabbedLast = false; + TabbedList = false; + togglestate = c_falling; + } + else if (gamestate != GS_FULLCONSOLE && gamestate != GS_STARTUP) + { + ConsoleState = c_rising; + C_FlushDisplay(); + togglestate = c_rising; + } + else return; + // This must be done as an event callback because the client code does not control the console toggling. + if (sysCallbacks.ConsoleToggled) sysCallbacks.ConsoleToggled(togglestate); +} + +void C_HideConsole () +{ + if (gamestate != GS_FULLCONSOLE) + { + ConsoleState = c_up; + ConBottom = 0; + HistPos = NULL; + } +} + +static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) +{ + int data1 = ev->data1; + bool keepappending = false; + + switch (ev->subtype) + { + default: + return false; + + case EV_GUI_Char: + if (ev->data2) + { + // Bash-style shortcuts + if (data1 == 'b') + { + buffer.CursorWordLeft(); + break; + } + else if (data1 == 'f') + { + buffer.CursorWordRight(); + break; + } + } + // Add keypress to command line + buffer.AddChar(data1); + HistPos = NULL; + TabbedLast = false; + TabbedList = false; + break; + + case EV_GUI_WheelUp: + case EV_GUI_WheelDown: + if (!(ev->data3 & GKM_SHIFT)) + { + data1 = GK_PGDN + EV_GUI_WheelDown - ev->subtype; + } + else + { + data1 = GK_DOWN + EV_GUI_WheelDown - ev->subtype; + } + // Intentional fallthrough + + case EV_GUI_KeyDown: + case EV_GUI_KeyRepeat: + switch (data1) + { + case '\t': + // Try to do tab-completion + C_TabComplete ((ev->data3 & GKM_SHIFT) ? false : true); + break; + + case GK_PGUP: + if (ev->data3 & (GKM_SHIFT|GKM_CTRL)) + { // Scroll console buffer up one page + RowAdjust += (twod->GetHeight()-4)/active_con_scale(twod) / + ((gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) ? CurrentConsoleFont->GetHeight() : CurrentConsoleFont->GetHeight()*2) - 3; + } + else if (RowAdjust < conbuffer->GetFormattedLineCount()) + { // Scroll console buffer up + if (ev->subtype == EV_GUI_WheelUp) + { + RowAdjust += 3; + } + else + { + RowAdjust++; + } + if (RowAdjust > conbuffer->GetFormattedLineCount()) + { + RowAdjust = conbuffer->GetFormattedLineCount(); + } + } + break; + + case GK_PGDN: + if (ev->data3 & (GKM_SHIFT|GKM_CTRL)) + { // Scroll console buffer down one page + const int scrollamt = (twod->GetHeight()-4)/active_con_scale(twod) / + ((gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) ? CurrentConsoleFont->GetHeight() : CurrentConsoleFont->GetHeight()*2) - 3; + if (RowAdjust < scrollamt) + { + RowAdjust = 0; + } + else + { + RowAdjust -= scrollamt; + } + } + else if (RowAdjust > 0) + { // Scroll console buffer down + if (ev->subtype == EV_GUI_WheelDown) + { + RowAdjust = max (0, RowAdjust - 3); + } + else + { + RowAdjust--; + } + } + break; + + case GK_HOME: + if (ev->data3 & GKM_CTRL) + { // Move to top of console buffer + RowAdjust = conbuffer->GetFormattedLineCount(); + } + else + { // Move cursor to start of line + buffer.CursorStart(); + } + break; + + case GK_END: + if (ev->data3 & GKM_CTRL) + { // Move to bottom of console buffer + RowAdjust = 0; + } + else + { // Move cursor to end of line + buffer.CursorEnd(); + } + break; + + case GK_LEFT: + // Move cursor left one character + buffer.CursorLeft(); + break; + + case GK_RIGHT: + // Move cursor right one character + buffer.CursorRight(); + break; + + case '\b': + // Erase character to left of cursor + buffer.DeleteLeft(); + TabbedLast = false; + TabbedList = false; + break; + + case GK_DEL: + // Erase character under cursor + buffer.DeleteRight(); + TabbedLast = false; + TabbedList = false; + break; + + case GK_UP: + // Move to previous entry in the command history + if (HistPos == NULL) + { + HistPos = HistHead; + } + else if (HistPos->Older) + { + HistPos = HistPos->Older; + } + + if (HistPos) + { + buffer.SetString(HistPos->String); + } + + TabbedLast = false; + TabbedList = false; + break; + + case GK_DOWN: + // Move to next entry in the command history + if (HistPos && HistPos->Newer) + { + HistPos = HistPos->Newer; + buffer.SetString(HistPos->String); + } + else + { + HistPos = NULL; + buffer.SetString(""); + } + TabbedLast = false; + TabbedList = false; + break; + + case 'X': + if (ev->data3 & GKM_CTRL) + { + buffer.SetString(""); + TabbedLast = TabbedList = false; + } + break; + + case 'D': + if (ev->data3 & GKM_CTRL && buffer.TextLength() == 0) + { // Control-D pressed on an empty line + if (strlen(con_ctrl_d) == 0) + { + break; // Replacement is empty, so do nothing + } + buffer.SetString(*con_ctrl_d); + } + else + { + break; + } + // Intentional fall-through for command(s) added with Ctrl-D + [[fallthrough]]; + + case '\r': + { + // Execute command line (ENTER) + FString bufferText = buffer.GetText(); + + bufferText.StripLeftRight(); + Printf(127, TEXTCOLOR_WHITE "]%s\n", bufferText.GetChars()); + + if (bufferText.Len() == 0) + { + // Command line is empty, so do nothing to the history + } + else if (HistHead && HistHead->String.CompareNoCase(bufferText) == 0) + { + // Command line was the same as the previous one, + // so leave the history list alone + } + else + { + // Command line is different from last command line, + // or there is nothing in the history list, + // so add it to the history list. + + History *temp = new History; + temp->String = bufferText; + temp->Older = HistHead; + if (HistHead) + { + HistHead->Newer = temp; + } + temp->Newer = NULL; + HistHead = temp; + + if (!HistTail) + { + HistTail = temp; + } + + if (HistSize == MAXHISTSIZE) + { + HistTail = HistTail->Newer; + delete HistTail->Older; + HistTail->Older = NULL; + } + else + { + HistSize++; + } + } + HistPos = NULL; + buffer.SetString(""); + AddCommandString(bufferText.GetChars()); + TabbedLast = false; + TabbedList = false; + break; + } + + case '`': + // Check to see if we have ` bound to the console before accepting + // it as a way to close the console. + if (Bindings.GetBinding(KEY_GRAVE).CompareNoCase("toggleconsole")) + { + break; + } + [[fallthrough]]; + case GK_ESCAPE: + // Close console and clear command line. But if we're in the + // fullscreen console mode, there's nothing to fall back on + // if it's closed, so open the main menu instead. + if (gamestate == GS_STARTUP || !AppActive) + { + return false; + } + else if (gamestate == GS_FULLCONSOLE) + { + C_DoCommand ("menu_main"); + } + else + { + buffer.SetString(""); + HistPos = NULL; + C_ToggleConsole (); + } + break; + + case 'C': + case 'V': + TabbedLast = false; + TabbedList = false; +#ifdef __APPLE__ + if (ev->data3 & GKM_META) +#else // !__APPLE__ + if (ev->data3 & GKM_CTRL) +#endif // __APPLE__ + { + if (data1 == 'C') + { // copy to clipboard + if (buffer.TextLength() > 0) + { + I_PutInClipboard(buffer.GetText().GetChars()); + } + } + else + { // paste from clipboard + buffer.AddString(I_GetFromClipboard(false)); + HistPos = NULL; + } + break; + } + break; + + // Bash-style shortcuts + case 'A': + if (ev->data3 & GKM_CTRL) + { + buffer.CursorStart(); + } + break; + case 'E': + if (ev->data3 & GKM_CTRL) + { + buffer.CursorEnd(); + } + break; + case 'W': + if (ev->data3 & GKM_CTRL) + { + buffer.DeleteWordLeft(); + keepappending = true; + TabbedLast = false; + TabbedList = false; + } + break; + case 'U': + if (ev->data3 & GKM_CTRL) + { + buffer.DeleteLineLeft(); + keepappending = true; + TabbedLast = false; + TabbedList = false; + } + break; + case 'K': + if (ev->data3 & GKM_CTRL) + { + buffer.DeleteLineRight(); + keepappending = true; + TabbedLast = false; + TabbedList = false; + } + break; + case 'Y': + if (ev->data3 & GKM_CTRL) + { + buffer.AddYankBuffer(); + TabbedLast = false; + TabbedList = false; + HistPos = NULL; + } + break; + } + break; + +#ifdef __unix__ + case EV_GUI_MButtonDown: + buffer.AddString(I_GetFromClipboard(true)); + HistPos = NULL; + break; +#endif + } + + buffer.AppendToYankBuffer = keepappending; + + // Ensure that the cursor is always visible while typing + CursorTicker = I_msTime() + 500; + cursoron = 1; + return true; +} + +bool C_Responder (event_t *ev) +{ + if (ev->type != EV_GUI_Event || + ConsoleState == c_up || + ConsoleState == c_rising || + menuactive != MENU_Off) + { + return false; + } + + return C_HandleKey(ev, CmdLine); +} + +CCMD (history) +{ + struct History *hist = HistTail; + + while (hist) + { + Printf (" %s\n", hist->String.GetChars()); + hist = hist->Newer; + } +} + +CCMD (clear) +{ + C_FlushDisplay (); + ClearConsole (); +} + +CCMD (echo) +{ + int last = argv.argc()-1; + for (int i = 1; i <= last; ++i) + { + FString formatted = strbin1 (argv[i]); + Printf ("%s%s", formatted.GetChars(), i!=last ? " " : "\n"); + } +} + +CCMD(toggleconsole) +{ + C_ToggleConsole(); +} + diff --git a/src/console/c_console.h b/src/common/console/c_console.h similarity index 87% rename from src/console/c_console.h rename to src/common/console/c_console.h index 276c8b79337..bae857f7dd3 100644 --- a/src/console/c_console.h +++ b/src/common/console/c_console.h @@ -35,17 +35,16 @@ #define __C_CONSOLE__ #include -#include "basictypes.h" +#include "basics.h" +#include "c_tabcomplete.h" +#include "textureid.h" struct event_t; -#define C_BLINKRATE (TICRATE/2) - -typedef enum cstate_t +enum cstate_t : uint8_t { c_up=0, c_down=1, c_falling=2, c_rising=3 -} -constate_e; +}; enum { @@ -53,12 +52,12 @@ enum }; extern int PrintColors[PRINTLEVELS + 2]; -extern constate_e ConsoleState; +extern uint8_t ConsoleState; // Initialize the console void C_InitConsole (int width, int height, bool ingame); void C_DeinitConsole (); -void C_InitConback(); +void C_InitConback(FTextureID fallback, bool tile, double lightlevel = 1.); // Adjust the console for a new screen mode void C_NewModeAdjust (void); @@ -76,16 +75,16 @@ void C_FullConsole (void); void C_HideConsole (void); void C_AdjustBottom (void); void C_FlushDisplay (void); +class FNotifyBufferBase; +void C_SetNotifyBuffer(FNotifyBufferBase *nbb); -class FFont; -void C_MidPrint (FFont *font, const char *message, bool bold = false); bool C_Responder (event_t *ev); -void C_AddTabCommand (const char *name); -void C_RemoveTabCommand (const char *name); -void C_ClearTabCommands(); // Removes all tab commands +extern double NotifyFontScale; +void C_SetNotifyFontScale(double scale); extern const char *console_bar; +extern int chatmodeon; #endif diff --git a/src/console/c_consolebuffer.cpp b/src/common/console/c_consolebuffer.cpp similarity index 99% rename from src/console/c_consolebuffer.cpp rename to src/common/console/c_consolebuffer.cpp index 4541422e45b..ea6be80e2e1 100644 --- a/src/console/c_consolebuffer.cpp +++ b/src/common/console/c_consolebuffer.cpp @@ -35,6 +35,7 @@ #include "c_console.h" #include "c_consolebuffer.h" +#include "printf.h" //========================================================================== @@ -71,7 +72,7 @@ FConsoleBuffer::FConsoleBuffer() void FConsoleBuffer::AddText(int printlevel, const char *text) { FString build = TEXTCOLOR_TAN; - + if (mAddType == REPLACELINE) { // Just wondering: Do we actually need this case? If so, it may need some work. @@ -84,15 +85,15 @@ void FConsoleBuffer::AddText(int printlevel, const char *text) printlevel = -1; mLastLineNeedsUpdate = true; } - + if (printlevel >= 0 && printlevel != PRINT_HIGH) { if (printlevel == 200) build = TEXTCOLOR_GREEN; else if (printlevel < PRINTLEVELS) build.Format("%c%c", TEXTCOLOR_ESCAPE, PrintColors[printlevel]+'A'); } - + size_t textsize = strlen(text); - + if (text[textsize-1] == '\r') { textsize--; diff --git a/src/console/c_consolebuffer.h b/src/common/console/c_consolebuffer.h similarity index 99% rename from src/console/c_consolebuffer.h rename to src/common/console/c_consolebuffer.h index 98a42b42e4e..8d4e235d586 100644 --- a/src/console/c_consolebuffer.h +++ b/src/common/console/c_consolebuffer.h @@ -32,6 +32,7 @@ **--------------------------------------------------------------------------- ** */ +#pragma once #include #include @@ -56,12 +57,12 @@ class FConsoleBuffer EAddType mAddType; int mTextLines; bool mBufferWasCleared; - + FFont *mLastFont; int mLastDisplayWidth; bool mLastLineNeedsUpdate; - + public: FConsoleBuffer(); void AddText(int printlevel, const char *string); diff --git a/src/common/console/c_cvars.cpp b/src/common/console/c_cvars.cpp new file mode 100644 index 00000000000..1cbe6772d07 --- /dev/null +++ b/src/common/console/c_cvars.cpp @@ -0,0 +1,2138 @@ +/* +** c_cvars.cpp +** Defines all the different console variable types +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include + +#include "cmdlib.h" +#include "configfile.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "c_cvars.h" +#include "engineerrors.h" +#include "printf.h" +#include "palutil.h" +#include "i_interface.h" +#include "gstrings.h" + +#include "dobject.h" +#include "dobjtype.h" +#include "dobjgc.h" + +#include "vm.h" + + + +struct FLatchedValue +{ + FBaseCVar *Variable; + UCVarValue Value; + ECVarType Type; + bool UnsafeContext; +}; + +static TArray LatchedValues; + +int cvar_defflags; + + +static ConsoleCallbacks* callbacks; + +// Install game-specific handlers, mainly to deal with serverinfo and userinfo CVARs. +// This is to keep the console independent of game implementation details for easier reusability. +void C_InstallHandlers(ConsoleCallbacks* cb) +{ + callbacks = cb; +} + +void C_InitCVars(int which) +{ + AutoSegs::CVarDecl.ForEach([](FCVarDecl* cvInfo) + { + FBaseCVar* newcvar; + switch(cvInfo->type) + { + default: + return; + + case CVAR_Int: + { + using callbacktype = void (*)(FIntCVar &); + newcvar = new FIntCVar(cvInfo->name, cvInfo->defaultval.Int, cvInfo->flags, reinterpret_cast(cvInfo->callbackp), cvInfo->description); + break; + } + case CVAR_Bool: + { + using callbacktype = void (*)(FBoolCVar &); + newcvar = new FBoolCVar(cvInfo->name, cvInfo->defaultval.Bool, cvInfo->flags, reinterpret_cast(cvInfo->callbackp), cvInfo->description); + break; + } + case CVAR_Float: + { + using callbacktype = void (*)(FFloatCVar &); + newcvar = new FFloatCVar(cvInfo->name, cvInfo->defaultval.Float, cvInfo->flags, reinterpret_cast(cvInfo->callbackp), cvInfo->description); + break; + } + case CVAR_String: + { + using callbacktype = void (*)(FStringCVar &); + newcvar = new FStringCVar(cvInfo->name, cvInfo->defaultval.String, cvInfo->flags, reinterpret_cast(cvInfo->callbackp), cvInfo->description); + break; + } + case CVAR_Color: + { + using callbacktype = void (*)(FColorCVar &); + newcvar = new FColorCVar(cvInfo->name, cvInfo->defaultval.Int, cvInfo->flags, reinterpret_cast(cvInfo->callbackp), cvInfo->description); + break; + } + + } + *(void**)cvInfo->refAddr = newcvar; + }); + AutoSegs::CVarDecl.ForEach([](FCVarDecl* cvInfo) + { + FBaseCVar* newcvar; + switch (cvInfo->type) + { + default: + return; + + case CVAR_Flag: + { + newcvar = new FFlagCVar(cvInfo->name, *cvInfo->defaultval.Pointer->get(), cvInfo->flags, cvInfo->description); + break; + } + case CVAR_Mask: + { + newcvar = new FMaskCVar(cvInfo->name, *cvInfo->defaultval.Pointer->get(), cvInfo->flags, cvInfo->description); + break; + } + + } + *(void**)cvInfo->refAddr = newcvar; + }); +} + +void C_UninitCVars() +{ + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair* pair; + while (it.NextPair(pair)) + { + auto var = pair->Value; + pair->Value = nullptr; + delete var; + } +} + +FBaseCVar::FBaseCVar (const char *var_name, uint32_t flags, void (*callback)(FBaseCVar &), const char *descr) +{ + if (var_name != nullptr && (flags & CVAR_SERVERINFO)) + { + // This limitation is imposed by network protocol which uses only 6 bits + // for name's length with terminating null character + static const size_t NAME_LENGHT_MAX = 63; + + if (strlen(var_name) > NAME_LENGHT_MAX) + { + I_FatalError("Name of the server console variable \"%s\" is too long.\n" + "Its length should not exceed %zu characters.\n", var_name, NAME_LENGHT_MAX); + } + } + + + + m_Callback = callback; + Flags = 0; + VarName = ""; + Description = descr; + + FBaseCVar* var = nullptr; + if (var_name) + { + var = FindCVar(var_name, NULL); + C_AddTabCommand (var_name); + VarName = var_name; + cvarMap.Insert(var_name, this); + } + + if (var) + { + ECVarType type; + UCVarValue value; + + value = var->GetFavoriteRep (&type); + ForceSet (value, type); + delete var; + + Flags = flags; + } + else + { + Flags = flags | CVAR_ISDEFAULT; + } +} + +FBaseCVar::~FBaseCVar () +{ + if (VarName.IsNotEmpty()) + { + FBaseCVar *var, *prev; + + var = FindCVar (VarName.GetChars(), &prev); + + if (var == this) + { + cvarMap.Remove(var->VarName); + C_RemoveTabCommand(VarName.GetChars()); + } + } +} + +void FBaseCVar::SetCallback(void (*callback)(FBaseCVar&)) +{ + m_Callback = callback; +} + +void FBaseCVar::ClearCallback() +{ + m_Callback = nullptr; +} + +void FBaseCVar::SetExtraDataPointer(void *pointer) +{ + m_ExtraDataPointer = pointer; +} + +void* FBaseCVar::GetExtraDataPointer() +{ + return m_ExtraDataPointer; +} + +const char *FBaseCVar::GetHumanString(int precision) const +{ + return GetGenericRep(CVAR_String).String; +} + +const char *FBaseCVar::GetHumanStringDefault(int precision) const +{ + return GetGenericRepDefault(CVAR_String).String; +} + +void FBaseCVar::ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend) +{ + DoSet (value, type); + if ((Flags & CVAR_USERINFO) && !nouserinfosend && !(Flags & CVAR_IGNORE)) + if (callbacks && callbacks->UserInfoChanged) callbacks->UserInfoChanged(this); + if (m_UseCallback) + Callback (); + + if ((Flags & CVAR_ARCHIVE) && !(Flags & CVAR_UNSAFECONTEXT)) + { + SafeValue = GetGenericRep(CVAR_String).String; + } + + Flags &= ~(CVAR_ISDEFAULT | CVAR_UNSAFECONTEXT); +} + +void FBaseCVar::SetGenericRep (UCVarValue value, ECVarType type) +{ + if ((Flags & CVAR_NOSET) && m_DoNoSet) + { + return; + } + if ((Flags & CVAR_LATCH) && callbacks && callbacks->MustLatch()) + { + FLatchedValue latch; + + latch.Variable = this; + latch.Type = type; + if (type != CVAR_String) + latch.Value = value; + else + latch.Value.String = copystring(value.String); + latch.UnsafeContext = !!(Flags & CVAR_UNSAFECONTEXT); + LatchedValues.Push (latch); + + Flags &= ~CVAR_UNSAFECONTEXT; + return; + } + if ((Flags & CVAR_SERVERINFO) && callbacks && callbacks->SendServerInfoChange) + { + if (callbacks->SendServerInfoChange(this, value, type)) return; + } + ForceSet (value, type); +} + +bool FBaseCVar::ToBool (UCVarValue value, ECVarType type) +{ + switch (type) + { + case CVAR_Bool: + return value.Bool; + + case CVAR_Color: + case CVAR_Int: + return !!value.Int; + + case CVAR_Float: + return value.Float != 0.f; + + case CVAR_String: + if (stricmp (value.String, "true") == 0) + return true; + else if (stricmp (value.String, "false") == 0) + return false; + else + return !!strtoll (value.String, NULL, 0); + + default: + return false; + } +} + +int FBaseCVar::ToInt (UCVarValue value, ECVarType type) +{ + int res; +#if __GNUC__ <= 2 + float tmp; +#endif + + switch (type) + { + case CVAR_Bool: res = (int)value.Bool; break; + case CVAR_Color: + case CVAR_Int: res = value.Int; break; +#if __GNUC__ <= 2 + case CVAR_Float: tmp = value.Float; res = (int)tmp; break; +#else + case CVAR_Float: res = (int)value.Float; break; +#endif + case CVAR_String: + { + if (stricmp (value.String, "true") == 0) + res = 1; + else if (stricmp (value.String, "false") == 0) + res = 0; + else + res = (int)strtoll (value.String, NULL, 0); + break; + } + default: res = 0; break; + } + return res; +} + +float FBaseCVar::ToFloat (UCVarValue value, ECVarType type) +{ + switch (type) + { + case CVAR_Bool: + return (float)value.Bool; + + case CVAR_Color: + case CVAR_Int: + return (float)value.Int; + + case CVAR_Float: + return value.Float; + + case CVAR_String: + return (float)strtod (value.String, NULL); + + default: + return 0.f; + } +} + +static char cstrbuf[40]; +static GUID cGUID; +static char truestr[] = "true"; +static char falsestr[] = "false"; + +const char *FBaseCVar::ToString (UCVarValue value, ECVarType type) +{ + switch (type) + { + case CVAR_Bool: + return value.Bool ? truestr : falsestr; + + case CVAR_String: + return value.String; + + case CVAR_Color: + case CVAR_Int: + mysnprintf (cstrbuf, countof(cstrbuf), "%i", value.Int); + break; + + case CVAR_Float: + IGNORE_FORMAT_PRE + mysnprintf (cstrbuf, countof(cstrbuf), "%g", value.Float); + IGNORE_FORMAT_POST + break; + + default: + strcpy (cstrbuf, ""); + break; + } + return cstrbuf; +} + +UCVarValue FBaseCVar::FromBool (bool value, ECVarType type) +{ + UCVarValue ret; + + switch (type) + { + case CVAR_Bool: + ret.Bool = value; + break; + + case CVAR_Int: + ret.Int = value; + break; + + case CVAR_Float: + ret.Float = value; + break; + + case CVAR_String: + ret.String = value ? truestr : falsestr; + break; + + default: + ret.Int = 0; + break; + } + + return ret; +} + +UCVarValue FBaseCVar::FromInt (int value, ECVarType type) +{ + UCVarValue ret; + + switch (type) + { + case CVAR_Bool: + ret.Bool = value != 0; + break; + + case CVAR_Int: + ret.Int = value; + break; + + case CVAR_Float: + ret.Float = (float)value; + break; + + case CVAR_String: + mysnprintf (cstrbuf, countof(cstrbuf), "%i", value); + ret.String = cstrbuf; + break; + + default: + ret.Int = 0; + break; + } + + return ret; +} + +UCVarValue FBaseCVar::FromFloat (float value, ECVarType type) +{ + UCVarValue ret; + + switch (type) + { + case CVAR_Bool: + ret.Bool = value != 0.f; + break; + + case CVAR_Int: + ret.Int = (int)value; + break; + + case CVAR_Float: + ret.Float = value; + break; + + case CVAR_String: + IGNORE_FORMAT_PRE + mysnprintf (cstrbuf, countof(cstrbuf), "%g", value); + IGNORE_FORMAT_POST + ret.String = cstrbuf; + break; + + default: + ret.Int = 0; + break; + } + + return ret; +} + +static uint8_t HexToByte (const char *hex) +{ + uint8_t v = 0; + for (int i = 0; i < 2; ++i) + { + v <<= 4; + if (hex[i] >= '0' && hex[i] <= '9') + { + v += hex[i] - '0'; + } + else if (hex[i] >= 'A' && hex[i] <= 'F') + { + v += hex[i] - 'A'; + } + else // The string is already verified to contain valid hexits + { + v += hex[i] - 'a'; + } + } + return v; +} + +UCVarValue FBaseCVar::FromString (const char *value, ECVarType type) +{ + UCVarValue ret; + + switch (type) + { + case CVAR_Bool: + if (stricmp (value, "true") == 0) + ret.Bool = true; + else if (stricmp (value, "false") == 0) + ret.Bool = false; + else + ret.Bool = strtoll (value, NULL, 0) != 0; + break; + + case CVAR_Int: + if (stricmp (value, "true") == 0) + ret.Int = 1; + else if (stricmp (value, "false") == 0) + ret.Int = 0; + else + ret.Int = (int)strtoll (value, NULL, 0); + break; + + case CVAR_Float: + ret.Float = (float)strtod (value, NULL); + break; + + case CVAR_String: + ret.String = const_cast(value); + break; + + default: + ret.Int = 0; + break; + } + + return ret; +} + +FBaseCVar *cvar_set (const char *var_name, const char *val) +{ + FBaseCVar *var; + + if ( (var = FindCVar (var_name, NULL)) ) + { + UCVarValue value; + value.String = const_cast(val); + var->SetGenericRep (value, CVAR_String); + } + + return var; +} + +FBaseCVar *cvar_forceset (const char *var_name, const char *val) +{ + FBaseCVar *var; + UCVarValue vval; + + if ( (var = FindCVar (var_name, NULL)) ) + { + vval.String = const_cast(val); + var->ForceSet (vval, CVAR_String); + } + + return var; +} + +void FBaseCVar::EnableNoSet () +{ + m_DoNoSet = true; +} + +void FBaseCVar::EnableCallbacks () +{ + m_UseCallback = true; + CVarMap::Iterator it(cvarMap); + CVarMap::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if (!(cvar->Flags & CVAR_NOINITCALL)) + { + cvar->Callback (); + } + } +} + +void FBaseCVar::InitZSCallbacks () +{ + CVarMap::Iterator it(cvarMap); + CVarMap::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if (cvar->Flags & CVAR_ZS_CUSTOM) + { + cvar->InstantiateZSCVar(); + } + } + GC::AddMarkerFunc(FBaseCVar::MarkZSCallbacks); +} + +void FBaseCVar::MarkZSCallbacks () { + CVarMap::Iterator it(cvarMap); + CVarMap::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if (cvar->Flags & CVAR_ZS_CUSTOM) + { + cvar->MarkZSCVar(); + } + } +} + +void FBaseCVar::DisableCallbacks () +{ + m_UseCallback = false; +} + +// +// Boolean cvar implementation +// + +FBoolCVar::FBoolCVar (const char *name, bool def, uint32_t flags, void (*callback)(FBoolCVar &), const char* descr) +: FBaseCVar (name, flags, reinterpret_cast(callback), descr) +{ + DefaultValue = def; + if (Flags & CVAR_ISDEFAULT) + Value = def; +} + +ECVarType FBoolCVar::GetRealType () const +{ + return CVAR_Bool; +} + +UCVarValue FBoolCVar::GetGenericRep (ECVarType type) const +{ + return FromBool (Value, type); +} + +UCVarValue FBoolCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Bool; + ret.Bool = Value; + return ret; +} + +UCVarValue FBoolCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromBool (DefaultValue, type); +} + +UCVarValue FBoolCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Bool; + ret.Bool = DefaultValue; + return ret; +} + +void FBoolCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + DefaultValue = ToBool (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FBoolCVar::DoSet (UCVarValue value, ECVarType type) +{ + Value = ToBool (value, type); +} + +// +// Integer cvar implementation +// + +FIntCVar::FIntCVar (const char *name, int def, uint32_t flags, void (*callback)(FIntCVar &), const char* descr) +: FBaseCVar (name, flags, reinterpret_cast(callback), descr) +{ + DefaultValue = def; + if (Flags & CVAR_ISDEFAULT) + Value = def; +} + +ECVarType FIntCVar::GetRealType () const +{ + return CVAR_Int; +} + +UCVarValue FIntCVar::GetGenericRep (ECVarType type) const +{ + return FromInt (Value, type); +} + +UCVarValue FIntCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Int; + ret.Int = Value; + return ret; +} + +UCVarValue FIntCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromInt (DefaultValue, type); +} + +UCVarValue FIntCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Int; + ret.Int = DefaultValue; + return ret; +} + +void FIntCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + DefaultValue = ToInt (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FIntCVar::DoSet (UCVarValue value, ECVarType type) +{ + Value = ToInt (value, type); +} + +// +// Floating point cvar implementation +// + +FFloatCVar::FFloatCVar (const char *name, float def, uint32_t flags, void (*callback)(FFloatCVar &), const char* descr) +: FBaseCVar (name, flags, reinterpret_cast(callback), descr) +{ + DefaultValue = def; + if (Flags & CVAR_ISDEFAULT) + Value = def; +} + +ECVarType FFloatCVar::GetRealType () const +{ + return CVAR_Float; +} + +const char *FFloatCVar::GetHumanString(int precision) const +{ + if (precision < 0) + { + precision = 6; + } + mysnprintf(cstrbuf, countof(cstrbuf), "%.*g", precision, Value); + return cstrbuf; +} + +const char *FFloatCVar::GetHumanStringDefault(int precision) const +{ + if (precision < 0) + { + precision = 6; + } + mysnprintf(cstrbuf, countof(cstrbuf), "%.*g", precision, DefaultValue); + return cstrbuf; +} + +UCVarValue FFloatCVar::GetGenericRep (ECVarType type) const +{ + return FromFloat (Value, type); +} + +UCVarValue FFloatCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Float; + ret.Float = Value; + return ret; +} + +UCVarValue FFloatCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromFloat (DefaultValue, type); +} + +UCVarValue FFloatCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Float; + ret.Float = DefaultValue; + return ret; +} + +void FFloatCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + DefaultValue = ToFloat (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FFloatCVar::DoSet (UCVarValue value, ECVarType type) +{ + Value = ToFloat (value, type); +} + +// +// String cvar implementation +// + +FStringCVar::FStringCVar (const char *name, const char *def, uint32_t flags, void (*callback)(FStringCVar &), const char* descr) +: FBaseCVar (name, flags, reinterpret_cast(callback), descr) +{ + mDefaultValue = def; + if (Flags & CVAR_ISDEFAULT) + mValue = def; + else + mValue = ""; +} + +FStringCVar::~FStringCVar () +{ +} + +ECVarType FStringCVar::GetRealType () const +{ + return CVAR_String; +} + +UCVarValue FStringCVar::GetGenericRep (ECVarType type) const +{ + return FromString (mValue.GetChars(), type); +} + +UCVarValue FStringCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_String; + ret.String = mValue.GetChars(); + return ret; +} + +UCVarValue FStringCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromString (mDefaultValue.GetChars(), type); +} + +UCVarValue FStringCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_String; + ret.String = mDefaultValue.GetChars(); + return ret; +} + +void FStringCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + mDefaultValue = ToString(value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FStringCVar::DoSet (UCVarValue value, ECVarType type) +{ + mValue = ToString (value, type); +} + +// +// Color cvar implementation +// + +FColorCVar::FColorCVar (const char *name, int def, uint32_t flags, void (*callback)(FColorCVar &), const char* descr) +: FIntCVar (name, def, flags, reinterpret_cast(callback), descr) +{ +} + +ECVarType FColorCVar::GetRealType () const +{ + return CVAR_Color; +} + +UCVarValue FColorCVar::GetGenericRep (ECVarType type) const +{ + return FromInt2 (Value, type); +} + +UCVarValue FColorCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromInt2 (DefaultValue, type); +} + +void FColorCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + DefaultValue = ToInt2 (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FColorCVar::DoSet (UCVarValue value, ECVarType type) +{ + Value = ToInt2 (value, type); +} + +UCVarValue FColorCVar::FromInt2 (int value, ECVarType type) +{ + if (type == CVAR_String) + { + UCVarValue ret; + mysnprintf (cstrbuf, countof(cstrbuf), "%02x %02x %02x", + RPART(value), GPART(value), BPART(value)); + ret.String = cstrbuf; + return ret; + } + return FromInt (value, type); +} + +int FColorCVar::ToInt2 (UCVarValue value, ECVarType type) +{ + int ret; + + if (type == CVAR_String) + { + FString string = V_GetColorStringByName(value.String); + // Only allow named colors after the screen exists (i.e. after + // we've got some lumps loaded, so X11R6RGB can be read). Since + // the only time this might be called before that is when loading + // zdoom.ini, this shouldn't be a problem. + + if (string.IsNotEmpty()) + { + ret = V_GetColorFromString (string.GetChars()); + } + else + { + ret = V_GetColorFromString (value.String); + } + } + else + { + ret = ToInt (value, type); + } + return ret; +} + +// +// More base cvar stuff +// + +void FBaseCVar::ResetColors () +{ + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto var = pair->Value; + + if (var->GetRealType () == CVAR_Color) + { + var->DoSet (var->GetGenericRep (CVAR_Int), CVAR_Int); + } + } +} + +void FBaseCVar::ResetToDefault () +{ + if (!(Flags & CVAR_ISDEFAULT)) + { + UCVarValue val; + ECVarType type; + + val = GetFavoriteRepDefault (&type); + SetGenericRep (val, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FBaseCVar::MarkUnsafe() +{ + if (!(Flags & CVAR_MOD) && UnsafeExecutionContext) + { + Flags |= CVAR_UNSAFECONTEXT; + } +} + +// +// Flag cvar implementation +// +// This type of cvar is not a "real" cvar. Instead, it gets and sets +// the value of a FIntCVar, modifying it bit-by-bit. As such, it has +// no default, and is not written to the .cfg or transferred around +// the network. The "host" cvar is responsible for that. +// + +FFlagCVar::FFlagCVar (const char *name, FIntCVar &realvar, uint32_t bitval, const char* descr) +: FBaseCVar (name, 0, NULL, descr), +ValueVar (realvar), +BitVal (bitval) +{ + int bit; + + Flags &= ~CVAR_ISDEFAULT; + + assert (bitval != 0); + + bit = 0; + while ((bitval >>= 1) != 0) + { + ++bit; + } + BitNum = bit; + + assert ((1u << BitNum) == BitVal); +} + +ECVarType FFlagCVar::GetRealType () const +{ + return CVAR_Flag; +} + +UCVarValue FFlagCVar::GetGenericRep (ECVarType type) const +{ + return FromBool ((ValueVar & BitVal) != 0, type); +} + +UCVarValue FFlagCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Bool; + ret.Bool = (ValueVar & BitVal) != 0; + return ret; +} + +UCVarValue FFlagCVar::GetGenericRepDefault (ECVarType type) const +{ + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + return FromBool ((def.Int & BitVal) != 0, type); +} + +UCVarValue FFlagCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + def.Bool = (def.Int & BitVal) != 0; + *type = CVAR_Bool; + return def; +} + +void FFlagCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + bool newdef = ToBool (value, type); + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + if (newdef) + def.Int |= BitVal; + else + def.Int &= ~BitVal; + ValueVar.SetGenericRepDefault (def, CVAR_Int); +} + +void FFlagCVar::DoSet (UCVarValue value, ECVarType type) +{ + bool newval = ToBool (value, type); + + // Server cvars that get changed by this need to use a special message, because + // changes are not processed until the next net update. This is a problem with + // exec scripts because all flags will base their changes off of the value of + // the "master" cvar at the time the script was run, overriding any changes + // another flag might have made to the same cvar earlier in the script. + if (ValueVar.GetFlags() && callbacks && callbacks->SendServerFlagChange) + { + if (callbacks->SendServerFlagChange(&ValueVar, BitNum, newval, false)) return; + } + int val = *ValueVar; + if (newval) + val |= BitVal; + else + val &= ~BitVal; + ValueVar = val; +} + +// +// Mask cvar implementation +// +// Similar to FFlagCVar but can have multiple bits +// + +FMaskCVar::FMaskCVar (const char *name, FIntCVar &realvar, uint32_t bitval, const char* descr) +: FBaseCVar (name, 0, NULL, descr), +ValueVar (realvar), +BitVal (bitval) +{ + int bit; + + Flags &= ~CVAR_ISDEFAULT; + + assert (bitval != 0); + + bit = 0; + while ((bitval & 1) == 0) + { + ++bit; + bitval >>= 1; + } + BitNum = bit; +} + +ECVarType FMaskCVar::GetRealType () const +{ + return CVAR_Mask; +} + +UCVarValue FMaskCVar::GetGenericRep (ECVarType type) const +{ + return FromInt ((ValueVar & BitVal) >> BitNum, type); +} + +UCVarValue FMaskCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Int; + ret.Int = (ValueVar & BitVal) >> BitNum; + return ret; +} + +UCVarValue FMaskCVar::GetGenericRepDefault (ECVarType type) const +{ + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + return FromInt ((def.Int & BitVal) >> BitNum, type); +} + +UCVarValue FMaskCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + def.Int = (def.Int & BitVal) >> BitNum; + *type = CVAR_Int; + return def; +} + +void FMaskCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + int val = ToInt(value, type) << BitNum; + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + def.Int &= ~BitVal; + def.Int |= val; + ValueVar.SetGenericRepDefault (def, CVAR_Int); +} + +void FMaskCVar::DoSet (UCVarValue value, ECVarType type) +{ + int val = ToInt(value, type) << BitNum; + + // Server cvars that get changed by this need to use a special message, because + // changes are not processed until the next net update. This is a problem with + // exec scripts because all flags will base their changes off of the value of + // the "master" cvar at the time the script was run, overriding any changes + // another flag might have made to the same cvar earlier in the script. + if (ValueVar.GetFlags() && callbacks && callbacks->SendServerFlagChange) + { + // The network interface needs to process each bit separately. + bool silent = false; + for(int i = 0; i < 32; i++) + { + if (BitVal & (1<SendServerFlagChange(&ValueVar, i, !!(val & (1 << i)), silent)) goto fallback; // the failure case here is either always or never. + silent = true; // only warn once if SendServerFlagChange needs to. + } + } + } + else + { + fallback: + int vval = *ValueVar; + vval &= ~BitVal; + vval |= val; + ValueVar = vval; + } +} + + +//////////////////////////////////////////////////////////////////////// +static int sortcvars (const void *a, const void *b) +{ + return strcmp (((*(FBaseCVar **)a))->GetName(), ((*(FBaseCVar **)b))->GetName()); +} + +void FilterCompactCVars (TArray &cvars, uint32_t filter) +{ + // Accumulate all cvars that match the filter flags. + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_IGNORE)) + cvars.Push(cvar); + } + // Now sort them, so they're in a deterministic order and not whatever + // order the linker put them in. + if (cvars.Size() > 0) + { + qsort(&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars); + } +} + +void C_WriteCVars (uint8_t **demo_p, uint32_t filter, bool compact) +{ + FString dump = C_GetMassCVarString(filter, compact); + size_t dumplen = dump.Len() + 1; // include terminating \0 + memcpy(*demo_p, dump.GetChars(), dumplen); + *demo_p += dumplen; +} + +FString C_GetMassCVarString (uint32_t filter, bool compact) +{ + FBaseCVar* cvar; + FString dump; + + if (compact) + { + TArray cvars; + dump.AppendFormat("\\\\%ux", filter); + FilterCompactCVars(cvars, filter); + while (cvars.Pop (cvar)) + { + UCVarValue val = cvar->GetGenericRep(CVAR_String); + dump << '\\' << val.String; + } + } + else + { + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + cvar = pair->Value; + if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_IGNORE))) + { + UCVarValue val = cvar->GetGenericRep(CVAR_String); + dump << '\\' << cvar->GetName() << '\\' << val.String; + } + } + } + return dump; +} + +void C_ReadCVars (uint8_t **demo_p) +{ + char *ptr = *((char **)demo_p); + char *breakpt; + + if (*ptr++ != '\\') + return; + + if (*ptr == '\\') + { // compact mode + TArray cvars; + FBaseCVar *cvar; + uint32_t filter; + + ptr++; + breakpt = strchr (ptr, '\\'); + *breakpt = 0; + filter = strtoul (ptr, NULL, 16); + *breakpt = '\\'; + ptr = breakpt + 1; + + FilterCompactCVars (cvars, filter); + + while (cvars.Pop (cvar)) + { + UCVarValue val; + breakpt = strchr (ptr, '\\'); + if (breakpt) + *breakpt = 0; + val.String = ptr; + cvar->ForceSet (val, CVAR_String); + if (breakpt) + { + *breakpt = '\\'; + ptr = breakpt + 1; + } + else + break; + } + } + else + { + char *value; + + while ( (breakpt = strchr (ptr, '\\')) ) + { + *breakpt = 0; + value = breakpt + 1; + if ( (breakpt = strchr (value, '\\')) ) + *breakpt = 0; + + cvar_set (ptr, value); + + *(value - 1) = '\\'; + if (breakpt) + { + *breakpt = '\\'; + ptr = breakpt + 1; + } + else + { + break; + } + } + } + *demo_p += strlen (*((char **)demo_p)) + 1; +} + +struct FCVarBackup +{ + FString Name, String; +}; +static TArray CVarBackups; + +void C_BackupCVars (void) +{ + assert(CVarBackups.Size() == 0); + CVarBackups.Clear(); + + FCVarBackup backup; + + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE)) && !(cvar->Flags & CVAR_LATCH)) + { + backup.Name = cvar->GetName(); + backup.String = cvar->GetGenericRep(CVAR_String).String; + CVarBackups.Push(backup); + } + } +} + +void C_RestoreCVars (void) +{ + for (unsigned int i = 0; i < CVarBackups.Size(); ++i) + { + cvar_set(CVarBackups[i].Name.GetChars(), CVarBackups[i].String.GetChars()); + } + C_ForgetCVars(); +} + +void C_ForgetCVars (void) +{ + CVarBackups.Clear(); +} + +FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev) +{ + if (var_name == nullptr) + return nullptr; + + FName vname(var_name, true); + if (vname == NAME_None) return nullptr; + auto find = cvarMap.CheckKey(vname); + return find? *find : nullptr; +} + +FBaseCVar *FindCVarSub (const char *var_name, int namelen) +{ + if (var_name == NULL) + return NULL; + + FName vname(var_name, namelen, true); + if (vname == NAME_None) return nullptr; + auto find = cvarMap.CheckKey(vname); + return find ? *find : nullptr; +} + +FBaseCVar *GetCVar(int playernum, const char *cvarname) +{ + FBaseCVar *cvar = FindCVar(cvarname, nullptr); + // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return nullptr. + if (cvar == nullptr || (cvar->GetFlags() & CVAR_IGNORE)) + { + return nullptr; + } + else + { + // For userinfo cvars, redirect to GetUserCVar + if ((cvar->GetFlags() & CVAR_USERINFO) && callbacks && callbacks->GetUserCVar) + { + return callbacks->GetUserCVar(playernum, cvarname); + } + return cvar; + } +} + +//=========================================================================== +// +// C_CreateCVar +// +// Create a new cvar with the specified name and type. It should not already +// exist. +// +//=========================================================================== + +FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, uint32_t flags) +{ + assert(FindCVar(var_name, NULL) == NULL); + flags |= CVAR_AUTO; + switch (var_type) + { + case CVAR_Bool: return new FBoolCVar(var_name, 0, flags); + case CVAR_Int: return new FIntCVar(var_name, 0, flags); + case CVAR_Float: return new FFloatCVar(var_name, 0, flags); + case CVAR_String: return new FStringCVar(var_name, NULL, flags); + case CVAR_Color: return new FColorCVar(var_name, 0, flags); + default: return NULL; + } +} + +FBaseCVar * C_CreateZSCustomCVar(const char *var_name, ECVarType var_type, uint32_t flags, FName className) +{ + assert(FindCVar(var_name, NULL) == NULL); + flags |= CVAR_AUTO | CVAR_ZS_CUSTOM; + switch (var_type) + { + case CVAR_Bool: return new FZSBoolCVar(var_name, 0, flags, className); + case CVAR_Int: return new FZSIntCVar(var_name, 0, flags, className); + case CVAR_Float: return new FZSFloatCVar(var_name, 0, flags, className); + case CVAR_String: return new FZSStringCVar(var_name, NULL, flags, className); + case CVAR_Color: return new FZSColorCVar(var_name, 0, flags, className); + default: return NULL; + } +} + +void UnlatchCVars (void) +{ + for (const FLatchedValue& var : LatchedValues) + { + uint32_t oldflags = var.Variable->Flags; + var.Variable->Flags &= ~(CVAR_LATCH | CVAR_SERVERINFO); + if (var.UnsafeContext) + var.Variable->Flags |= CVAR_UNSAFECONTEXT; + var.Variable->SetGenericRep (var.Value, var.Type); + if (var.Type == CVAR_String) + delete[] var.Value.String; + var.Variable->Flags = oldflags; + } + + LatchedValues.Clear(); +} + +void DestroyCVarsFlagged (uint32_t flags) +{ + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + + if(cvar->Flags & flags) + delete cvar; + } +} + +void C_SetCVarsToDefaults (void) +{ + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + // Only default save-able cvars + if (cvar->Flags & CVAR_ARCHIVE) + { + UCVarValue val; + ECVarType type; + val = cvar->GetFavoriteRepDefault (&type); + cvar->SetGenericRep (val, type); + } + } +} + +static int cvarcmp(const void* a, const void* b) +{ + FBaseCVar** A = (FBaseCVar**)a; + FBaseCVar** B = (FBaseCVar**)b; + return strcmp((*A)->GetName(), (*B)->GetName()); +} + +void C_ArchiveCVars (FConfigFile *f, uint32_t filter) +{ + TArray cvarlist; + + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if ((cvar->Flags & + (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MOD|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE|CVAR_CONFIG_ONLY)) + == filter) + { + cvarlist.Push(cvar); + } + } + qsort(cvarlist.Data(), cvarlist.Size(), sizeof(FBaseCVar*), cvarcmp); + for (auto cv : cvarlist) + { + const char* const value = (cv->Flags & CVAR_ISDEFAULT) + ? cv->GetGenericRep(CVAR_String).String + : cv->SafeValue.GetChars(); + f->SetValueForKey(cv->GetName(), value); + } +} + +EXTERN_CVAR(Bool, sv_cheats); + +void FBaseCVar::CmdSet (const char *newval) +{ + if ((GetFlags() & CVAR_CHEAT) && sysCallbacks.CheckCheatmode && sysCallbacks.CheckCheatmode(true, false)) + return; + + MarkUnsafe(); + + UCVarValue val; + + // Casting away the const is safe in this case. + val.String = const_cast(newval); + SetGenericRep (val, CVAR_String); + + if (GetFlags() & CVAR_NOSET) + Printf ("%s is write protected.\n", GetName()); + else if (GetFlags() & CVAR_LATCH) + Printf ("%s will be changed for next game.\n", GetName()); +} + +CCMD (set) +{ + if (argv.argc() != 3) + { + Printf ("usage: set \n"); + } + else + { + FBaseCVar *var; + + var = FindCVar (argv[1], NULL); + if (var == NULL) + var = new FStringCVar (argv[1], NULL, CVAR_AUTO | CVAR_UNSETTABLE | cvar_defflags); + + var->CmdSet (argv[2]); + } +} + +CCMD (unset) +{ + if (argv.argc() != 2) + { + Printf ("usage: unset \n"); + } + else + { + FBaseCVar *var = FindCVar (argv[1], NULL); + if (var != NULL) + { + if (var->GetFlags() & CVAR_UNSETTABLE) + { + delete var; + } + else + { + Printf ("Cannot unset %s\n", argv[1]); + } + } + } +} + +CCMD (resetcvar) +{ + if (argv.argc() != 2) + { + Printf ("usage: resetcvar \n"); + } + else + { + FBaseCVar *var = FindCVar (argv[1], NULL); + if (var != NULL) + { + var->ResetToDefault(); + } + else + { + Printf ("No such variable: %s\n", argv[1]); + } + } +} + +CCMD (get) +{ + FBaseCVar *var, *prev; + + if (argv.argc() >= 2) + { + if ( (var = FindCVar (argv[1], &prev)) ) + { + UCVarValue val; + val = var->GetGenericRep (CVAR_String); + Printf ("\"%s\" is \"%s\"\n", var->GetName(), val.String); + } + else + { + Printf ("\"%s\" is unset\n", argv[1]); + } + } + else + { + Printf ("get: need variable name\n"); + } +} + +CCMD (toggle) +{ + FBaseCVar *var, *prev; + UCVarValue val; + + if (argv.argc() > 1) + { + if ( (var = FindCVar (argv[1], &prev)) ) + { + var->MarkUnsafe(); + + val = var->GetGenericRep (CVAR_Bool); + val.Bool = !val.Bool; + var->SetGenericRep (val, CVAR_Bool); + auto msg = var->GetToggleMessage(val.Bool); + if (msg.IsNotEmpty()) + { + Printf(PRINT_NOTIFY, "%s\n", msg.GetChars()); + } + else Printf ("\"%s\" = \"%s\"\n", var->GetName(), + val.Bool ? "true" : "false"); + } + } +} + +void FBaseCVar::ListVars (const char *filter, int listtype) +{ + int count = 0; + + bool plain = listtype == LCT_Plain; + bool includedesc = listtype == LCT_FullSearch; + + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto var = pair->Value; + + bool ismatch; + + if (filter && includedesc) + { + // search always allow partial matches + // also allow matching to cvar name, localised description, and description language-id + + FString SearchString = FString("*") + filter + "*"; + ismatch = CheckWildcards (SearchString.GetChars(), var->GetName()) || + CheckWildcards (SearchString.GetChars(), var->GetDescription().GetChars()) || + CheckWildcards (SearchString.GetChars(), GStrings.localize(var->GetDescription().GetChars())); + } + else + { + ismatch = CheckWildcards (filter, var->GetName()); + } + + if (ismatch) + { + uint32_t flags = var->GetFlags(); + if (plain) + { // plain formatting does not include user-defined cvars + if (!(flags & CVAR_UNSETTABLE)) + { + ++count; + Printf ("%s : %s\n", var->GetName(), var->GetHumanString()); + } + } + else + { + ++count; + + Printf ("%c%c%c%c%c %s = %s", + flags & CVAR_ARCHIVE ? 'A' : ' ', + flags & CVAR_USERINFO ? 'U' : + flags & CVAR_SERVERINFO ? 'S' : + flags & CVAR_AUTO ? 'C' : ' ', + flags & CVAR_NOSET ? '-' : + flags & CVAR_LATCH ? 'L' : + flags & CVAR_UNSETTABLE ? '*' : ' ', + flags & CVAR_MOD ? 'M' : ' ', + flags & CVAR_IGNORE ? 'X' : ' ', + var->GetName(), + var->GetHumanString()); + + if (includedesc) + if (var->GetDescription().Len()) + Printf(" // \"%s\"\n", GStrings.localize(var->GetDescription().GetChars())); + else + Printf("\n"); + else + Printf("\n"); + + + } + } + } + Printf ("%d cvars\n", count); +} + +CCMD (cvarlist) +{ + if (argv.argc() == 1) + { + FBaseCVar::ListVars (NULL, LCT_Default); + } + else + { + FBaseCVar::ListVars (argv[1], LCT_Default); + } +} + +CCMD (cvarlistplain) +{ + FBaseCVar::ListVars (NULL, LCT_Plain); +} + +CCMD (cvarsearch) +{ + if (argv.argc() == 1) + { + FBaseCVar::ListVars (NULL, LCT_FullSearch); + } + else + { + FBaseCVar::ListVars (argv[1], LCT_FullSearch); + } +} + +CCMD (archivecvar) +{ + + if (argv.argc() == 1) + { + Printf ("Usage: archivecvar \n"); + } + else + { + FBaseCVar *var = FindCVar (argv[1], NULL); + + if (var != NULL && (var->GetFlags() & CVAR_AUTO)) + { + var->SetArchiveBit (); + } + } +} + +void C_ListCVarsWithoutDescription() +{ + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto var = pair->Value; + if (var->GetDescription().IsEmpty()) + { + Printf("%s\n", var->GetName()); + } + } +} + +CCMD(listcvarswithoutdescription) +{ + C_ListCVarsWithoutDescription(); +} + + +//=========================================================================== +// +// FZSIntCVar +// +//=========================================================================== + + +FZSIntCVar::FZSIntCVar(const char *name, int def, uint32_t flags, FName _className, const char* descr) + : FIntCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSIntCVar::CallCVarCallback(FZSIntCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomIntCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomIntCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value }; + VMReturn ret(&self.Value); + VMCall(func, param, 3, &ret, 1); + } +} + +void FZSIntCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomIntCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s",cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomIntCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSIntCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + +UCVarValue FZSIntCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + int val = ToInt(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomIntCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val }; + VMReturn ret(&val); + VMCall(func, param, 3, &ret, 1); + } + + UCVarValue v; + v.Int = val; + return v; +} + + +//=========================================================================== +// +// FZSFloatCVar +// +//=========================================================================== + + +FZSFloatCVar::FZSFloatCVar(const char *name, float def, uint32_t flags, FName _className, const char* descr) + : FFloatCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSFloatCVar::CallCVarCallback(FZSFloatCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomFloatCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomFloatCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , (double) self.Value }; + double v; + VMReturn ret(&v); + VMCall(func, param, 3, &ret, 1); + self.Value = (float) v; + } +} + +void FZSFloatCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomFloatCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomFloatCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSFloatCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + +UCVarValue FZSFloatCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + float val = ToFloat(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomFloatCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , (double) val }; + double v; + VMReturn ret(&v); + VMCall(func, param, 3, &ret, 1); + val = (float) v; + } + + UCVarValue v; + v.Float = val; + return v; +} + + +//=========================================================================== +// +// FZSStringCVar +// +//=========================================================================== + + +FZSStringCVar::FZSStringCVar(const char *name, const char * def, uint32_t flags, FName _className, const char* descr) + : FStringCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSStringCVar::CallCVarCallback(FZSStringCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomStringCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomStringCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , &self.mValue }; + VMReturn ret(&self.mValue); + VMCall(func, param, 3, &ret, 1); + } +} + +void FZSStringCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomStringCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomStringCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSStringCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + +UCVarValue FZSStringCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + FString val = ToString(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomStringCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , &val }; + VMReturn ret(&val); + VMCall(func, param, 3, &ret, 1); + } + + char * str = new char[val.Len() + 1]; + memcpy(str, val.GetChars(), val.Len() * sizeof(char)); + str[val.Len()] = '\0'; + + UCVarValue v; + v.String = str; + return v; +} + + +//=========================================================================== +// +// FZSBoolCVar +// +//=========================================================================== + + +FZSBoolCVar::FZSBoolCVar(const char *name, bool def, uint32_t flags, FName _className, const char* descr) + : FBoolCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSBoolCVar::CallCVarCallback(FZSBoolCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomBoolCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomBoolCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value }; + int v; + VMReturn ret(&v); + VMCall(func, param, 3, &ret, 1); + self.Value = v; + } +} + +void FZSBoolCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomBoolCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomBoolCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSBoolCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + +UCVarValue FZSBoolCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + bool val = ToFloat(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomBoolCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val }; + int v; + VMReturn ret(&v); + VMCall(func, param, 3, &ret, 1); + val = v; + } + + UCVarValue v; + v.Bool = val; + return v; +} + + +//=========================================================================== +// +// FZSColorCVar +// +//=========================================================================== + + +FZSColorCVar::FZSColorCVar(const char *name, int def, uint32_t flags, FName _className, const char* descr) + : FColorCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSColorCVar::CallCVarCallback(FZSColorCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomColorCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomColorCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value }; + VMReturn ret(&self.Value); + VMCall(func, param, 3, &ret, 1); + } +} + +void FZSColorCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomColorCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomColorCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSColorCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + +UCVarValue FZSColorCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + int val = ToInt(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomColorCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val }; + VMReturn ret(&val); + VMCall(func, param, 3, &ret, 1); + } + + UCVarValue v; + v.Int = val; + return v; +} \ No newline at end of file diff --git a/src/common/console/c_cvars.h b/src/common/console/c_cvars.h new file mode 100644 index 00000000000..47337523fea --- /dev/null +++ b/src/common/console/c_cvars.h @@ -0,0 +1,747 @@ +/* +** c_cvars.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __C_CVARS_H__ +#define __C_CVARS_H__ +#include "zstring.h" +#include "tarray.h" +#include "autosegs.h" +#include "name.h" +#include "dobjgc.h" + +class FSerializer; // this needs to go away. +/* +========================================================== + +CVARS (console variables) + +========================================================== +*/ + +enum +{ + CVAR_ARCHIVE = 1, // set to cause it to be saved to config. + CVAR_USERINFO = 1 << 1, // added to userinfo when changed. + CVAR_SERVERINFO = 1 << 2, // added to serverinfo when changed. + CVAR_NOSET = 1 << 3, // don't allow change from console at all, + // but can be set from the command line. + CVAR_LATCH = 1 << 4, // save changes until server restart. + CVAR_UNSETTABLE = 1 << 5, // can unset this var from console. + CVAR_DEMOSAVE = 1 << 6, // save the value of this cvar in a demo. + CVAR_ISDEFAULT = 1 << 7, // is cvar unchanged since creation? + CVAR_AUTO = 1 << 8, // allocated; needs to be freed when destroyed. + CVAR_NOINITCALL = 1 << 9, // don't call callback at game start. + CVAR_GLOBALCONFIG = 1 << 10, // cvar is saved to global config section. + CVAR_VIDEOCONFIG = 1 << 11, // cvar is saved to video config section (not implemented). + CVAR_NOSAVE = 1 << 12, // when used with CVAR_SERVERINFO, do not save var to savegame + // and config. + CVAR_MOD = 1 << 13, // cvar was defined by a mod. + CVAR_IGNORE = 1 << 14, // do not send cvar across the network/inaccesible from ACS + // (dummy mod cvar). + CVAR_CHEAT = 1 << 15, // can be set only when sv_cheats is enabled. + CVAR_UNSAFECONTEXT = 1 << 16, // cvar value came from unsafe context. + CVAR_VIRTUAL = 1 << 17, // do not invoke the callback recursively so it can be used to + // mirror an external variable. + CVAR_CONFIG_ONLY = 1 << 18, // do not save var to savegame and do not send it across network. + CVAR_ZS_CUSTOM = 1 << 19, // Custom CVar backed by a ZScript class + CVAR_ZS_CUSTOM_CLONE = 1 << 20, // Clone of a Custom ZScript CVar +}; + +enum ECVarType +{ + CVAR_Bool, + CVAR_Int, + CVAR_Float, + CVAR_String, + CVAR_Color, // stored as CVAR_Int + CVAR_Flag, // just redirects to another cvar + CVAR_Mask, // just redirects to another cvar + CVAR_Dummy, // Unknown +}; + +enum ListCCMDType +{ + LCT_Default, + LCT_Plain, + LCT_FullSearch, +}; + + +class FIntCVarRef; +union UCVarValue +{ + bool Bool; + int Int; + float Float; + const char* String; + FIntCVarRef* Pointer; + + UCVarValue() = default; + constexpr UCVarValue(bool v) : Bool(v) { } + constexpr UCVarValue(int v) : Int(v) { } + constexpr UCVarValue(float v) : Float(v) { } + constexpr UCVarValue(double v) : Float(float(v)) { } + constexpr UCVarValue(const char * v) : String(v) { } + constexpr UCVarValue(FIntCVarRef& v); +}; + +template constexpr UCVarValue CVarValue(bool v) { static_assert(t == CVAR_Bool); return v; } +template constexpr UCVarValue CVarValue(int v) { static_assert(t == CVAR_Int || t == CVAR_Color); return v; } +template constexpr UCVarValue CVarValue(float v) { static_assert(t == CVAR_Float); return v; } +template constexpr UCVarValue CVarValue(double v) { static_assert(t == CVAR_Float); return v; } +template constexpr UCVarValue CVarValue(const char* v) { static_assert(t == CVAR_String); return v; } +template constexpr UCVarValue CVarValue(FIntCVarRef& v) { static_assert(t == CVAR_Flag || t == CVAR_Mask); return v; } + +class FConfigFile; + +class FxCVar; + +class FBaseCVar; + +using CVarMap = TMap; +inline CVarMap cvarMap; + +// These are calls into the game code. Having these hard coded in the CVAR implementation has always been the biggest blocker +// for reusing the CVAR module outside of ZDoom. So now they get called through this struct for easier reusability. +struct ConsoleCallbacks +{ + void (*UserInfoChanged)(FBaseCVar*); + bool (*SendServerInfoChange)(FBaseCVar* cvar, UCVarValue value, ECVarType type); + bool (*SendServerFlagChange)(FBaseCVar* cvar, int bitnum, bool set, bool silent); + FBaseCVar* (*GetUserCVar)(int playernum, const char* cvarname); + bool (*MustLatch)(); + +}; + +class FBaseCVar +{ +public: + FBaseCVar (const char *name, uint32_t flags, void (*callback)(FBaseCVar &), const char *descr); + virtual ~FBaseCVar (); + + inline void Callback () + { + if (m_Callback && !inCallback) + { + inCallback = !!(Flags & CVAR_VIRTUAL); // Virtual CVARs never invoke the callback recursively, giving it a chance to manipulate the value without side effects. + m_Callback(*this); + inCallback = false; + } + } + + inline const char *GetName () const { return VarName.GetChars(); } + inline uint32_t GetFlags () const { return Flags; } + + void CmdSet (const char *newval); + void ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend=false); + void SetGenericRep (UCVarValue value, ECVarType type); + void ResetToDefault (); + void SetArchiveBit () { Flags |= CVAR_ARCHIVE; } + void MarkUnsafe(); + void MarkSafe() { Flags &= ~CVAR_UNSAFECONTEXT; } + void AddDescription(const FString& label) + { + if (Description.IsEmpty()) Description = label; + } + + int ToInt() + { + ECVarType vt; + auto val = GetFavoriteRep(&vt); + return ToInt(val, vt); + } + + virtual ECVarType GetRealType () const = 0; + + virtual const char *GetHumanString(int precision=-1) const; + virtual UCVarValue GetGenericRep (ECVarType type) const = 0; + virtual UCVarValue GetFavoriteRep (ECVarType *type) const = 0; + + virtual const char *GetHumanStringDefault(int precision = -1) const; + virtual UCVarValue GetGenericRepDefault (ECVarType type) const = 0; + virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const = 0; + virtual void SetGenericRepDefault (UCVarValue value, ECVarType type) = 0; + + virtual UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) + { // not valid for cvars that aren't custom zscript cvars, doesn't modify the actual cvar directly, just transforms the value + // FZSStringCVar allocates a buffer for the returned string that must be freed by the caller + return 0; + } + + FBaseCVar &operator= (const FBaseCVar &var) + { UCVarValue val; ECVarType type; val = var.GetFavoriteRep (&type); SetGenericRep (val, type); return *this; } + + static void EnableNoSet (); // enable the honoring of CVAR_NOSET + static void EnableCallbacks (); + static void DisableCallbacks (); + static void InitZSCallbacks (); + static void MarkZSCallbacks (); + static void ResetColors (); // recalc color cvars' indices after screen change + + static void ListVars (const char *filter, int listtype); + + const FString &GetDescription() const { return Description; }; + const FString& GetToggleMessage(int which) { return ToggleMessages[which]; } + void SetToggleMessages(const char* on, const char* off) + { + ToggleMessages[0] = off; + ToggleMessages[1] = on; + } + + void SetCallback(void (*callback)(FBaseCVar&)); + void ClearCallback(); + + void SetExtraDataPointer(void *pointer); + + void* GetExtraDataPointer(); + + int pnum = -1; + FName userinfoName; + +protected: + virtual void DoSet (UCVarValue value, ECVarType type) = 0; + virtual void InstantiateZSCVar() + {} + virtual void MarkZSCVar() + {} + + static bool ToBool (UCVarValue value, ECVarType type); + static int ToInt (UCVarValue value, ECVarType type); + static float ToFloat (UCVarValue value, ECVarType type); + static const char *ToString (UCVarValue value, ECVarType type); + static UCVarValue FromBool (bool value, ECVarType type); + static UCVarValue FromInt (int value, ECVarType type); + static UCVarValue FromFloat (float value, ECVarType type); + static UCVarValue FromString (const char *value, ECVarType type); + + FString VarName; + FString SafeValue; + FString Description; + FString ToggleMessages[2]; + uint32_t Flags; + bool inCallback = false; + +private: + FBaseCVar (const FBaseCVar &var) = delete; + FBaseCVar (const char *name, uint32_t flags); + void (*m_Callback)(FBaseCVar &); + + static inline bool m_UseCallback = false; + static inline bool m_DoNoSet = false; + + void *m_ExtraDataPointer; + + // These need to go away! + friend FString C_GetMassCVarString (uint32_t filter, bool compact); + friend void C_SerializeCVars(FSerializer& arc, const char* label, uint32_t filter); + friend void C_ReadCVars (uint8_t **demo_p); + friend void C_BackupCVars (void); + friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); + friend FBaseCVar *FindCVarSub (const char *var_name, int namelen); + friend void UnlatchCVars (void); + friend void DestroyCVarsFlagged (uint32_t flags); + friend void C_ArchiveCVars (FConfigFile *f, uint32_t filter); + friend void C_SetCVarsToDefaults (void); + friend void FilterCompactCVars (TArray &cvars, uint32_t filter); + friend void C_DeinitConsole(); + friend void C_ListCVarsWithoutDescription(); +}; + +// Returns a string with all cvars whose flags match filter. In compact mode, +// the cvar names are omitted to save space. +FString C_GetMassCVarString (uint32_t filter, bool compact=false); + +// Writes all cvars that could effect demo sync to *demo_p. These are +// cvars that have either CVAR_SERVERINFO or CVAR_DEMOSAVE set. +void C_WriteCVars (uint8_t **demo_p, uint32_t filter, bool compact=false); + +// Read all cvars from *demo_p and set them appropriately. +void C_ReadCVars (uint8_t **demo_p); + +void C_InstallHandlers(ConsoleCallbacks* cb); + +// Backup demo cvars. Called before a demo starts playing to save all +// cvars the demo might change. +void C_BackupCVars (void); + +// Finds a named cvar +FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); +FBaseCVar *FindCVarSub (const char *var_name, int namelen); + +// Used for ACS and DECORATE. +FBaseCVar *GetCVar(int playernum, const char *cvarname); + +// Create a new cvar with the specified name and type +FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, uint32_t flags); +FBaseCVar *C_CreateZSCustomCVar(const char *var_name, ECVarType var_type, uint32_t flags, FName className); + +// Called from G_InitNew() +void UnlatchCVars (void); + +// Destroy CVars with the matching flags; called from CCMD(restart) +void DestroyCVarsFlagged (uint32_t flags); + +// archive cvars to FILE f +void C_ArchiveCVars (FConfigFile *f, uint32_t filter); + +// initialize cvars to default values after they are created +void C_SetCVarsToDefaults (void); + +void FilterCompactCVars (TArray &cvars, uint32_t filter); + +void C_DeinitConsole(); +void C_InitCVars(int which); +void C_UninitCVars(); + +class FBoolCVar : public FBaseCVar +{ + friend class FxCVar; +public: + FBoolCVar (const char *name, bool def, uint32_t flags, void (*callback)(FBoolCVar &)=NULL, const char* descr = nullptr); + + virtual ECVarType GetRealType () const; + + virtual UCVarValue GetGenericRep (ECVarType type) const; + virtual UCVarValue GetFavoriteRep (ECVarType *type) const; + virtual UCVarValue GetGenericRepDefault (ECVarType type) const; + virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; + virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); + + inline bool operator= (bool boolval) + { UCVarValue val; val.Bool = boolval; SetGenericRep (val, CVAR_Bool); return boolval; } + inline operator bool () const { return Value; } + inline bool operator *() const { return Value; } + +protected: + virtual void DoSet (UCVarValue value, ECVarType type); + + bool Value; + bool DefaultValue; +}; + +class FIntCVar : public FBaseCVar +{ + friend class FxCVar; +public: + FIntCVar (const char *name, int def, uint32_t flags, void (*callback)(FIntCVar &)=NULL, const char* descr = nullptr); + + virtual ECVarType GetRealType () const; + + virtual UCVarValue GetGenericRep (ECVarType type) const; + virtual UCVarValue GetFavoriteRep (ECVarType *type) const; + virtual UCVarValue GetGenericRepDefault (ECVarType type) const; + virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; + virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); + + int operator= (int intval) + { UCVarValue val; val.Int = intval; SetGenericRep (val, CVAR_Int); return intval; } + inline operator int () const { return Value; } + inline int operator *() const { return Value; } + +protected: + virtual void DoSet (UCVarValue value, ECVarType type); + + int Value; + int DefaultValue; + + friend class FFlagCVar; +}; + +class FFloatCVar : public FBaseCVar +{ + friend class FxCVar; +public: + FFloatCVar (const char *name, float def, uint32_t flags, void (*callback)(FFloatCVar &)=NULL, const char* descr = nullptr); + + virtual ECVarType GetRealType () const override; + + virtual UCVarValue GetGenericRep (ECVarType type) const override ; + virtual UCVarValue GetFavoriteRep (ECVarType *type) const override; + virtual UCVarValue GetGenericRepDefault (ECVarType type) const override; + virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const override; + virtual void SetGenericRepDefault (UCVarValue value, ECVarType type) override; + const char *GetHumanString(int precision) const override; + const char *GetHumanStringDefault(int precision) const override; + + float operator= (float floatval) + { UCVarValue val; val.Float = floatval; SetGenericRep (val, CVAR_Float); return floatval; } + inline operator float () const { return Value; } + inline float operator *() const { return Value; } + +protected: + virtual void DoSet (UCVarValue value, ECVarType type) override; + + float Value; + float DefaultValue; +}; + +class FStringCVar : public FBaseCVar +{ + friend class FxCVar; +public: + FStringCVar (const char *name, const char *def, uint32_t flags, void (*callback)(FStringCVar &)=NULL, const char* descr = nullptr); + ~FStringCVar (); + + virtual ECVarType GetRealType () const; + + virtual UCVarValue GetGenericRep (ECVarType type) const; + virtual UCVarValue GetFavoriteRep (ECVarType *type) const; + virtual UCVarValue GetGenericRepDefault (ECVarType type) const; + virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; + virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); + + const char *operator= (const char *stringrep) + { UCVarValue val; val.String = const_cast(stringrep); SetGenericRep (val, CVAR_String); return stringrep; } + inline operator const char * () const { return mValue.GetChars(); } + inline const char *operator *() const { return mValue.GetChars(); } + +protected: + virtual void DoSet (UCVarValue value, ECVarType type); + + FString mValue; + FString mDefaultValue; +}; + +class FColorCVar : public FIntCVar +{ + friend class FxCVar; +public: + FColorCVar (const char *name, int def, uint32_t flags, void (*callback)(FColorCVar &)=NULL, const char* descr = nullptr); + + virtual ECVarType GetRealType () const; + + virtual UCVarValue GetGenericRep (ECVarType type) const; + virtual UCVarValue GetGenericRepDefault (ECVarType type) const; + virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); + + inline operator uint32_t () const { return Value; } + inline uint32_t operator *() const { return Value; } + +protected: + virtual void DoSet (UCVarValue value, ECVarType type); + + static UCVarValue FromInt2 (int value, ECVarType type); + static int ToInt2 (UCVarValue value, ECVarType type); +}; + +class FFlagCVar : public FBaseCVar +{ + friend class FxCVar; +public: + FFlagCVar (const char *name, FIntCVar &realvar, uint32_t bitval, const char* descr = nullptr); + + virtual ECVarType GetRealType () const; + + virtual UCVarValue GetGenericRep (ECVarType type) const; + virtual UCVarValue GetFavoriteRep (ECVarType *type) const; + virtual UCVarValue GetGenericRepDefault (ECVarType type) const; + virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; + virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); + + bool operator= (bool boolval) + { UCVarValue val; val.Bool = boolval; SetGenericRep (val, CVAR_Bool); return boolval; } + bool operator= (FFlagCVar &flag) + { UCVarValue val; val.Bool = !!flag; SetGenericRep (val, CVAR_Bool); return val.Bool; } + inline operator int () const { return (ValueVar & BitVal); } + inline int operator *() const { return (ValueVar & BitVal); } + +protected: + virtual void DoSet (UCVarValue value, ECVarType type); + + FIntCVar &ValueVar; + uint32_t BitVal; + int BitNum; +}; + +class FMaskCVar : public FBaseCVar +{ + friend class FxCVar; +public: + FMaskCVar (const char *name, FIntCVar &realvar, uint32_t bitval, const char* descr = nullptr); + + virtual ECVarType GetRealType () const; + + virtual UCVarValue GetGenericRep (ECVarType type) const; + virtual UCVarValue GetFavoriteRep (ECVarType *type) const; + virtual UCVarValue GetGenericRepDefault (ECVarType type) const; + virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; + virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); + + inline operator int () const { return (ValueVar & BitVal) >> BitNum; } + inline int operator *() const { return (ValueVar & BitVal) >> BitNum; } + +protected: + virtual void DoSet (UCVarValue value, ECVarType type); + + FIntCVar &ValueVar; + uint32_t BitVal; + int BitNum; +}; + +class FZSIntCVar : public FIntCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSIntCVar &); +public: + FZSIntCVar(const char *name, int def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; +}; + +class FZSFloatCVar : public FFloatCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSFloatCVar &); +public: + FZSFloatCVar(const char *name, float def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; +}; + +class FZSStringCVar : public FStringCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSStringCVar &); +public: + FZSStringCVar(const char *name, const char * def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; +}; + +class FZSBoolCVar : public FBoolCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSBoolCVar &); +public: + FZSBoolCVar(const char *name, bool def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; +}; + +class FZSColorCVar : public FColorCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSColorCVar &); +public: + FZSColorCVar(const char *name, int def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; +}; + +class FBoolCVarRef +{ + FBoolCVar* ref; +public: + + inline bool operator= (bool val) { *ref = val; return val; } + inline operator bool () const { return **ref; } + inline bool operator *() const { return **ref; } + inline FBoolCVar* operator->() { return ref; } + inline FBoolCVar* get() { return ref; } +}; + +class FIntCVarRef +{ + FIntCVar* ref; +public: + + int operator= (int val) { *ref = val; return val; } + inline operator int () const { return **ref; } + inline int operator *() const { return **ref; } + inline FIntCVar* operator->() { return ref; } + inline FIntCVar* get() { return ref; } +}; + +class FFloatCVarRef +{ + FFloatCVar* ref; +public: + + float operator= (float val) { *ref = val; return val; } + inline operator float () const { return **ref; } + inline float operator *() const { return **ref; } + inline FFloatCVar* operator->() { return ref; } + inline FFloatCVar* get() { return ref; } +}; + +class FStringCVarRef +{ + FStringCVar* ref; +public: + + const char* operator= (const char* val) { *ref = val; return val; } + inline operator const char* () const { return **ref; } + inline const char* operator *() const { return **ref; } + inline FStringCVar* operator->() { return ref; } + inline FStringCVar* get() { return ref; } +}; + +class FColorCVarRef +{ + FColorCVar* ref; +public: + + //uint32_t operator= (uint32_t val) { *ref = val; return val; } + inline operator uint32_t () const { return **ref; } + inline uint32_t operator *() const { return **ref; } + inline FColorCVar* operator->() { return ref; } + inline FColorCVar* get() { return ref; } +}; + +class FFlagCVarRef +{ + FFlagCVar* ref; +public: + inline bool operator= (bool val) { *ref = val; return val; } + inline bool operator= (const FFlagCVar& val) { *ref = val; return val; } + inline operator int () const { return **ref; } + inline int operator *() const { return **ref; } + inline FFlagCVar& operator->() { return *ref; } +}; + +class FMaskCVarRef +{ + FMaskCVar* ref; +public: + //int operator= (int val) { *ref = val; return val; } + inline operator int () const { return **ref; } + inline int operator *() const { return **ref; } + inline FMaskCVar& operator->() { return *ref; } +}; + + +extern int cvar_defflags; + +FBaseCVar *cvar_set (const char *var_name, const char *value); +FBaseCVar *cvar_forceset (const char *var_name, const char *value); + +inline FBaseCVar *cvar_set (const char *var_name, const uint8_t *value) { return cvar_set (var_name, (const char *)value); } +inline FBaseCVar *cvar_forceset (const char *var_name, const uint8_t *value) { return cvar_forceset (var_name, (const char *)value); } + +constexpr UCVarValue::UCVarValue(FIntCVarRef& v) : Pointer(&v) { } + +struct FCVarDecl +{ + void * refAddr; + ECVarType type; + unsigned int flags; + const char * name; + UCVarValue defaultval; + const char *description; + void* callbackp; // actually a function pointer with unspecified arguments. C++ does not like that much... +}; + + +// Restore demo cvars. Called after demo playback to restore all cvars +// that might possibly have been changed during the course of demo playback. +void C_RestoreCVars (void); + +void C_ForgetCVars (void); + + +#if defined(_MSC_VER) +#pragma section(SECTION_VREG,read) + +#define MSVC_VSEG __declspec(allocate(SECTION_VREG)) +#define GCC_VSEG +#else +#define MSVC_VSEG +#define GCC_VSEG __attribute__((section(SECTION_VREG))) __attribute__((used)) +#endif + +#define CUSTOM_CVAR(type,name,def,flags) \ + static void cvarfunc_##name(F##type##CVar &); \ + F##type##CVarRef name; \ + static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue(def), nullptr, reinterpret_cast(cvarfunc_##name) }; \ + extern FCVarDecl const *const cvardeclref_##name; \ + MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; \ + static void cvarfunc_##name(F##type##CVar &self) + + +#define CUSTOM_CVAR_NAMED(type,name,cname,def,flags) \ + static void cvarfunc_##name(F##type##CVar &); \ + F##type##CVarRef name; \ + static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #cname, CVarValue(def), nullptr, reinterpret_cast(cvarfunc_##name) }; \ + extern FCVarDecl const *const cvardeclref_##name; \ + MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; \ + static void cvarfunc_##name(F##type##CVar &self) + +#define CVAR(type,name,def,flags) \ + F##type##CVarRef name; \ + static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue(def), nullptr, nullptr}; \ + extern FCVarDecl const *const cvardeclref_##name; \ + MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; + +#define EXTERN_CVAR(type,name) extern F##type##CVarRef name; + +#define CUSTOM_CVARD(type,name,def,flags,descr) \ + static void cvarfunc_##name(F##type##CVar &); \ + F##type##CVarRef name; \ + static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue(def), descr, reinterpret_cast(cvarfunc_##name) }; \ + extern FCVarDecl const *const cvardeclref_##name; \ + MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; \ + static void cvarfunc_##name(F##type##CVar &self) + +#define CVARD(type,name,def,flags, descr) \ + F##type##CVarRef name; \ + static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #name, CVarValue(def), descr, nullptr}; \ + extern FCVarDecl const *const cvardeclref_##name; \ + MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; + +#define CVARD_NAMED(type,name,varname,def,flags, descr) \ + F##type##CVarRef name; \ + static FCVarDecl cvardecl_##name = { &name, CVAR_##type, (flags), #varname, CVarValue(def), descr, nullptr}; \ + extern FCVarDecl const *const cvardeclref_##name; \ + MSVC_VSEG FCVarDecl const *const cvardeclref_##name GCC_VSEG = &cvardecl_##name; + +#endif //__C_CVARS_H__ diff --git a/src/common/console/c_dispatch.cpp b/src/common/console/c_dispatch.cpp new file mode 100644 index 00000000000..8b6d738a02a --- /dev/null +++ b/src/common/console/c_dispatch.cpp @@ -0,0 +1,1152 @@ +/* +** c_dispatch.cpp +** Functions for executing console commands and aliases +** +**--------------------------------------------------------------------------- +** Copyright 1998-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include + + +#include "cmdlib.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "m_argv.h" +#include "gamestate.h" +#include "configfile.h" +#include "printf.h" +#include "c_cvars.h" +#include "c_buttons.h" +#include "findfile.h" +#include "gstrings.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +class FDelayedCommand +{ +public: + virtual ~FDelayedCommand() {} + +protected: + virtual bool Tick() = 0; + + friend class FDelayedCommandQueue; +}; + +class FWaitingCommand : public FDelayedCommand +{ +public: + FWaitingCommand(const char *cmd, int tics, bool unsafe) + : Command(cmd), TicsLeft(tics+1), IsUnsafe(unsafe) + {} + + bool Tick() override + { + if (--TicsLeft == 0) + { + UnsafeExecutionScope scope(IsUnsafe); + AddCommandString(Command.GetChars()); + return true; + } + return false; + } + + FString Command; + int TicsLeft; + bool IsUnsafe; +}; + +class FStoredCommand : public FDelayedCommand +{ +public: + FStoredCommand(FConsoleCommand *com, const char *cmd) + : Command(com), Text(cmd) + {} + + bool Tick() override + { + if (Text.IsNotEmpty() && Command != nullptr) + { + FCommandLine args(Text.GetChars()); + Command->Run(args, 0); + } + return true; + } + +private: + + FConsoleCommand *Command; + FString Text; +}; + +class FDelayedCommandQueue +{ + TDeletingArray delayedCommands; +public: + void Run() + { + for (unsigned i = 0; i < delayedCommands.Size(); i++) + { + if (delayedCommands[i]->Tick()) + { + delete delayedCommands[i]; + delayedCommands.Delete(i); + i--; + } + } + } + + void Clear() + { + delayedCommands.DeleteAndClear(); + } + + void AddCommand(FDelayedCommand * cmd) + { + delayedCommands.Push(cmd); + } +}; + +static FDelayedCommandQueue delayedCommandQueue; + +void C_RunDelayedCommands() +{ + delayedCommandQueue.Run(); +} + +void C_ClearDelayedCommands() +{ + delayedCommandQueue.Clear(); +} + + + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static FConsoleCommand *FindNameInHashTable (FConsoleCommand **table, const char *name, size_t namelen); +static FConsoleCommand *ScanChainForName (FConsoleCommand *start, const char *name, size_t namelen, FConsoleCommand **prev); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- +bool ParsingKeyConf, UnsafeExecutionContext; +FString StoredWarp; + +FConsoleCommand* Commands[FConsoleCommand::HASH_SIZE]; + + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static const char *KeyConfCommands[] = +{ + "alias", + "defaultbind", + "addkeysection", + "addmenukey", + "addslotdefault", + "weaponsection", + "setslot", + "addplayerclass", + "clearplayerclasses" +}; + +// CODE -------------------------------------------------------------------- + +void C_DoCommand (const char *cmd, int keynum) +{ + FConsoleCommand *com; + const char *end; + const char *beg; + + // Skip any beginning whitespace + while (*cmd > 0 && *cmd <= ' ') + cmd++; + + // Find end of the command name + if (*cmd == '\"') + { + for (end = beg = cmd+1; *end && *end != '\"'; ++end) + ; + } + else + { + beg = cmd; + for (end = cmd+1; *end > ' ' || *end < 0; ++end) + ; + } + + const size_t len = end - beg; + + if (ParsingKeyConf) + { + int i; + + for (i = countof(KeyConfCommands)-1; i >= 0; --i) + { + if (strnicmp (beg, KeyConfCommands[i], len) == 0 && + KeyConfCommands[i][len] == 0) + { + break; + } + } + if (i < 0) + { + Printf ("Invalid command for KEYCONF: %s\n", beg); + return; + } + } + + // Check if this is an action + if (*beg == '+' || *beg == '-') + { + auto button = buttonMap.FindButton(beg + 1, int(end - beg - 1)); + if (button != nullptr) + { + if (*beg == '+') + { + button->PressKey (keynum); + if (button->PressHandler) button->PressHandler(); + } + else + { + button->ReleaseKey (keynum); + if (button->ReleaseHandler) button->ReleaseHandler(); + } + return; + } + } + + // Parse it as a normal command + // Checking for matching commands follows this search order: + // 1. Check the Commands[] hash table + // 2. Check the CVars list + + if ( (com = FindNameInHashTable (Commands, beg, len)) ) + { + if (gamestate != GS_STARTUP || ParsingKeyConf || + (len == 3 && strnicmp (beg, "set", 3) == 0) || + (len == 7 && strnicmp (beg, "logfile", 7) == 0) || + (len == 9 && strnicmp (beg, "unbindall", 9) == 0) || + (len == 4 && strnicmp (beg, "bind", 4) == 0) || + (len == 4 && strnicmp (beg, "exec", 4) == 0) || + (len ==10 && strnicmp (beg, "doublebind", 10) == 0) || + (len == 6 && strnicmp (beg, "pullin", 6) == 0) + ) + { + FCommandLine args (beg); + com->Run (args, keynum); + } + else + { + if (len == 4 && strnicmp(beg, "warp", 4) == 0) + { + StoredWarp = beg; + } + else + { + auto command = new FStoredCommand(com, beg); + delayedCommandQueue.AddCommand(command); + } + } + } + else + { // Check for any console vars that match the command + FBaseCVar *var = FindCVarSub (beg, int(len)); + + if (var != NULL) + { + FCommandLine args (beg); + + if (args.argc() >= 2) + { // Set the variable + var->CmdSet (args[1]); + } + else + { // Get the variable's value + if (var->GetDescription().Len()) Printf("%s\n", GStrings.localize(var->GetDescription().GetChars())); + Printf ("\"%s\" is \"%s\" ", var->GetName(), var->GetHumanString()); + Printf ("(default: \"%s\")\n", var->GetHumanStringDefault()); + } + } + else + { // We don't know how to handle this command + Printf ("Unknown command \"%.*s\"\n", (int)len, beg); + } + } +} + +void AddCommandString (const char *text, int keynum) +{ + // Operate on a local copy instead of messing around with the data that's being passed in here. + TArray buffer(strlen(text) + 1, true); + memcpy(buffer.Data(), text, buffer.Size()); + char *cmd = buffer.Data(); + char *brkpt; + int more; + + if (cmd) + { + while (*cmd) + { + brkpt = cmd; + while (*brkpt != ';' && *brkpt != '\0') + { + if (*brkpt == '\"') + { + brkpt++; + while (*brkpt != '\0' && (*brkpt != '\"' || *(brkpt-1) == '\\')) + brkpt++; + } + if (*brkpt != '\0') + brkpt++; + } + if (*brkpt == ';') + { + *brkpt = '\0'; + more = 1; + } + else + { + more = 0; + } + // Intercept wait commands here. Note: wait must be lowercase + while (*cmd > 0 && *cmd <= ' ') + cmd++; + if (*cmd) + { + if (!ParsingKeyConf && + cmd[0] == 'w' && cmd[1] == 'a' && cmd[2] == 'i' && cmd[3] == 't' && + (cmd[4] == 0 || cmd[4] == ' ')) + { + int tics; + + if (cmd[4] == ' ') + { + tics = (int)strtoll (cmd + 5, NULL, 0); + } + else + { + tics = 1; + } + if (tics > 0) + { + if (more) + { // The remainder of the command will be executed later + // Note that deferred commands lose track of which key + // (if any) they were pressed from. + *brkpt = ';'; + auto command = new FWaitingCommand(brkpt, tics, UnsafeExecutionContext); + delayedCommandQueue.AddCommand(command); + } + return; + } + } + else + { + C_DoCommand (cmd, keynum); + } + } + if (more) + { + *brkpt = ';'; + } + cmd = brkpt + more; + } + } +} + +static FConsoleCommand *ScanChainForName (FConsoleCommand *start, const char *name, size_t namelen, FConsoleCommand **prev) +{ + int comp; + + *prev = NULL; + while (start) + { + comp = start->m_Name.CompareNoCase(name, namelen); + if (comp > 0) + return NULL; + else if (comp == 0 && start->m_Name[namelen] == 0) + return start; + + *prev = start; + start = start->m_Next; + } + return NULL; +} + +static FConsoleCommand *FindNameInHashTable (FConsoleCommand **table, const char *name, size_t namelen) +{ + FConsoleCommand *dummy; + + return ScanChainForName (table[MakeKey (name, namelen) % FConsoleCommand::HASH_SIZE], name, namelen, &dummy); +} + +bool FConsoleCommand::AddToHash (FConsoleCommand **table) +{ + unsigned int key; + FConsoleCommand *insert, **bucket; + + key = MakeKey (m_Name.GetChars()); + bucket = &table[key % HASH_SIZE]; + + if (ScanChainForName (*bucket, m_Name.GetChars(), m_Name.Len(), &insert)) + { + return false; + } + else + { + if (insert) + { + m_Next = insert->m_Next; + if (m_Next) + m_Next->m_Prev = &m_Next; + insert->m_Next = this; + m_Prev = &insert->m_Next; + } + else + { + m_Next = *bucket; + *bucket = this; + m_Prev = bucket; + if (m_Next) + m_Next->m_Prev = &m_Next; + } + } + return true; +} + +FConsoleCommand* FConsoleCommand::FindByName (const char* name) +{ + return FindNameInHashTable (Commands, name, strlen (name)); +} + +FConsoleCommand::FConsoleCommand (const char *name, CCmdRun runFunc) + : m_RunFunc (runFunc) +{ + int ag = strcmp (name, "kill"); + if (ag == 0) + ag=0; + m_Name = name; + + if (!AddToHash (Commands)) + Printf ("Adding CCMD %s twice.\n", name); + else + C_AddTabCommand (name); +} + +FConsoleCommand::~FConsoleCommand () +{ + *m_Prev = m_Next; + if (m_Next) + m_Next->m_Prev = m_Prev; + C_RemoveTabCommand (m_Name.GetChars()); +} + +void FConsoleCommand::Run(FCommandLine &argv, int key) +{ + m_RunFunc (argv, key); +} + +void FUnsafeConsoleCommand::Run(FCommandLine &args, int key) +{ + if (UnsafeExecutionContext) + { + Printf(TEXTCOLOR_RED "Cannot execute unsafe command " TEXTCOLOR_GOLD "%s\n", m_Name.GetChars()); + return; + } + + FConsoleCommand::Run (args, key); +} + +FConsoleAlias::FConsoleAlias (const char *name, const char *command, bool noSave) + : FConsoleCommand (name, NULL), + bRunning(false), bKill(false) +{ + m_Command[noSave] = command; + m_Command[!noSave] = FString(); + // If the command contains % characters, assume they are parameter markers + // for substitution when the command is executed. + bDoSubstitution = (strchr (command, '%') != NULL); +} + +FConsoleAlias::~FConsoleAlias () +{ + m_Command[1] = m_Command[0] = FString(); +} + +// Given an argument vector, reconstitute the command line it could have been produced from. +FString BuildString (int argc, FString *argv) +{ + if (argc == 1) + { + return *argv; + } + else + { + FString buf; + int arg; + + for (arg = 0; arg < argc; arg++) + { + if (argv[arg][0] == '\0') + { // It's an empty argument, we need to convert it to '""' + buf << "\"\" "; + } + else if (strchr(argv[arg].GetChars(), '"')) + { // If it contains one or more quotes, we need to escape them. + buf << '"'; + ptrdiff_t substr_start = 0, quotepos; + while ((quotepos = argv[arg].IndexOf('"', substr_start)) >= 0) + { + if (substr_start < quotepos) + { + buf << argv[arg].Mid(substr_start, quotepos - substr_start); + } + buf << "\\\""; + substr_start = quotepos + 1; + } + buf << argv[arg].Mid(substr_start) << "\" "; + } + else if (strchr(argv[arg].GetChars(), ' ')) + { // If it contains a space, it needs to be quoted. + buf << '"' << argv[arg] << "\" "; + } + else + { + buf << argv[arg] << ' '; + } + } + return buf; + } +} + +//=========================================================================== +// +// SubstituteAliasParams +// +// Given an command line and a set of arguments, replace instances of +// %x or %{x} in the command line with argument x. If argument x does not +// exist, then the empty string is substituted in its place. +// +// Substitution is not done inside of quoted strings, unless that string is +// prepended with a % character. +// +// To avoid a substitution, use %%. The %% will be replaced by a single %. +// +//=========================================================================== + +void FConsoleCommand::PrintCommand() +{ + Printf("%s\n", m_Name.GetChars()); +} + +FString SubstituteAliasParams (FString &command, FCommandLine &args) +{ + // Do substitution by replacing %x with the argument x. + // If there is no argument x, then %x is simply removed. + + // For some reason, strtoul's stop parameter is non-const. + char *p = command.LockBuffer(), *start = p; + unsigned long argnum; + FString buf; + bool inquote = false; + + while (*p != '\0') + { + if (p[0] == '%' && ((p[1] >= '0' && p[1] <= '9') || p[1] == '{')) + { + // Do a substitution. Output what came before this. + buf.AppendCStrPart (start, p - start); + + // Extract the argument number and substitute the corresponding argument. + argnum = strtoul (p + 1 + (p[1] == '{'), &start, 10); + if ((p[1] != '{' || *start == '}') && argnum < (unsigned long)args.argc()) + { + buf += args[argnum]; + } + p = (start += (p[1] == '{' && *start == '}')); + } + else if (p[0] == '%' && p[1] == '%') + { + // Do not substitute. Just collapse to a single %. + buf.AppendCStrPart (start, p - start + 1); + start = p = p + 2; + continue; + } + else if (p[0] == '%' && p[1] == '"') + { + // Collapse %" to " and remember that we're in a quote so when we + // see a " character again, we don't start skipping below. + if (!inquote) + { + inquote = true; + buf.AppendCStrPart(start, p - start); + start = p + 1; + } + else + { + inquote = false; + } + p += 2; + } + else if (p[0] == '\\' && p[1] == '"') + { + p += 2; + } + else if (p[0] == '"') + { + // Don't substitute inside quoted strings if it didn't start + // with a %" + if (!inquote) + { + p++; + while (*p != '\0' && (*p != '"' || *(p-1) == '\\')) + p++; + if (*p != '\0') + p++; + } + else + { + inquote = false; + p++; + } + } + else + { + p++; + } + } + // Return whatever was after the final substitution. + if (p > start) + { + buf.AppendCStrPart (start, p - start); + } + command.UnlockBuffer(); + + return buf; +} + +static int DumpHash (FConsoleCommand **table, bool aliases, const char *pattern=NULL) +{ + int bucket, count; + FConsoleCommand *cmd; + + for (bucket = count = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++) + { + cmd = table[bucket]; + while (cmd) + { + if (CheckWildcards (pattern, cmd->m_Name.GetChars())) + { + if (cmd->IsAlias()) + { + if (aliases) + { + ++count; + static_cast(cmd)->PrintAlias (); + } + } + else if (!aliases) + { + ++count; + cmd->PrintCommand (); + } + } + cmd = cmd->m_Next; + } + } + return count; +} + +void FConsoleAlias::PrintAlias () +{ + if (m_Command[0].IsNotEmpty()) + { + Printf (TEXTCOLOR_YELLOW "%s : %s\n", m_Name.GetChars(), m_Command[0].GetChars()); + } + if (m_Command[1].IsNotEmpty()) + { + Printf (TEXTCOLOR_ORANGE "%s : %s\n", m_Name.GetChars(), m_Command[1].GetChars()); + } +} + +void FConsoleAlias::Archive (FConfigFile *f) +{ + if (f != NULL && !m_Command[0].IsEmpty()) + { + f->SetValueForKey ("Name", m_Name.GetChars(), true); + f->SetValueForKey ("Command", m_Command[0].GetChars(), true); + } +} + +void C_ArchiveAliases (FConfigFile *f) +{ + int bucket; + FConsoleCommand *alias; + + for (bucket = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++) + { + alias = Commands[bucket]; + while (alias) + { + if (alias->IsAlias()) + static_cast(alias)->Archive (f); + alias = alias->m_Next; + } + } +} + +void C_ClearAliases () +{ + int bucket; + FConsoleCommand *alias; + + for (bucket = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++) + { + alias = Commands[bucket]; + while (alias) + { + FConsoleCommand *next = alias->m_Next; + if (alias->IsAlias()) + static_cast(alias)->SafeDelete(); + alias = next; + } + } +} + +CCMD(clearaliases) +{ + C_ClearAliases(); +} + + +// This is called only by the ini parser. +void C_SetAlias (const char *name, const char *cmd) +{ + FConsoleCommand *prev, *alias, **chain; + + chain = &Commands[MakeKey (name) % FConsoleCommand::HASH_SIZE]; + alias = ScanChainForName (*chain, name, strlen (name), &prev); + if (alias != NULL) + { + if (!alias->IsAlias ()) + { + //Printf (PRINT_BOLD, "%s is a command and cannot be an alias.\n", name); + return; + } + delete alias; + } + new FConsoleAlias (name, cmd, false); +} + +CCMD (alias) +{ + FConsoleCommand *prev, *alias, **chain; + + if (argv.argc() == 1) + { + Printf ("Current alias commands:\n"); + DumpHash (Commands, true); + } + else + { + chain = &Commands[MakeKey (argv[1]) % FConsoleCommand::HASH_SIZE]; + + if (argv.argc() == 2) + { // Remove the alias + + if ( (alias = ScanChainForName (*chain, argv[1], strlen (argv[1]), &prev))) + { + if (alias->IsAlias ()) + { + static_cast (alias)->SafeDelete (); + } + else + { + Printf ("%s is a normal command\n", alias->m_Name.GetChars()); + } + } + } + else + { // Add/change the alias + + alias = ScanChainForName (*chain, argv[1], strlen (argv[1]), &prev); + if (alias != NULL) + { + if (alias->IsAlias ()) + { + static_cast (alias)->Realias (argv[2], ParsingKeyConf); + } + else + { + Printf ("%s is a normal command\n", alias->m_Name.GetChars()); + alias = NULL; + } + } + else if (ParsingKeyConf) + { + new FUnsafeConsoleAlias (argv[1], argv[2]); + } + else + { + new FConsoleAlias (argv[1], argv[2], false); + } + } + } +} + +CCMD (cmdlist) +{ + int count; + const char *filter = (argv.argc() == 1 ? NULL : argv[1]); + + count = buttonMap.ListActionCommands (filter); + count += DumpHash (Commands, false, filter); + Printf ("%d commands\n", count); +} + +CCMD (key) +{ + if (argv.argc() > 1) + { + int i; + + for (i = 1; i < argv.argc(); ++i) + { + unsigned int hash = MakeKey (argv[i]); + Printf (" 0x%08x\n", hash); + } + } +} + +// Execute any console commands specified on the command line. +// These all begin with '+' as opposed to '-'. +FExecList *C_ParseCmdLineParams(FExecList *exec) +{ + for (int currArg = 1; currArg < Args->NumArgs(); ) + { + if (*Args->GetArg (currArg++) == '+') + { + FString cmdString; + int cmdlen = 1; + int argstart = currArg - 1; + + while (currArg < Args->NumArgs()) + { + if (*Args->GetArg (currArg) == '-' || *Args->GetArg (currArg) == '+') + break; + currArg++; + cmdlen++; + } + + cmdString = BuildString (cmdlen, Args->GetArgList (argstart)); + if (!cmdString.IsEmpty()) + { + if (exec == NULL) + { + exec = new FExecList; + } + exec->AddCommand(&cmdString[1]); + } + } + } + return exec; +} + +bool FConsoleCommand::IsAlias () +{ + return false; +} + +bool FConsoleAlias::IsAlias () +{ + return true; +} + +void FConsoleAlias::Run (FCommandLine &args, int key) +{ + if (bRunning) + { + Printf ("Alias %s tried to recurse.\n", m_Name.GetChars()); + return; + } + + int index = !m_Command[1].IsEmpty(); + FString savedcommand = m_Command[index], mycommand; + m_Command[index] = FString(); + + if (bDoSubstitution) + { + mycommand = SubstituteAliasParams (savedcommand, args); + } + else + { + mycommand = savedcommand; + } + + bRunning = true; + AddCommandString (mycommand.GetChars(), key); + bRunning = false; + if (m_Command[index].IsEmpty()) + { // The alias is unchanged, so put the command back so it can be used again. + // If the command had been non-empty, then that means that executing this + // alias caused it to realias itself, so the old command will be forgotten + // once this function returns. + m_Command[index] = savedcommand; + } + if (bKill) + { // The alias wants to remove itself + delete this; + } +} + +void FConsoleAlias::Realias (const char *command, bool noSave) +{ + if (!noSave && !m_Command[1].IsEmpty()) + { + noSave = true; + } + m_Command[noSave] = command; + + // If the command contains % characters, assume they are parameter markers + // for substitution when the command is executed. + bDoSubstitution = (strchr (command, '%') != NULL); + bKill = false; +} + +void FConsoleAlias::SafeDelete () +{ + if (!bRunning) + { + delete this; + } + else + { + bKill = true; + } +} + +void FUnsafeConsoleAlias::Run (FCommandLine &args, int key) +{ + UnsafeExecutionScope scope; + FConsoleAlias::Run(args, key); +} + +void FExecList::AddCommand(const char *cmd, const char *file) +{ + // Pullins are special and need to be separated from general commands. + // They also turned out to be a really bad idea, since they make things + // more complicated. :( + if (file != NULL && strnicmp(cmd, "pullin", 6) == 0 && isspace(cmd[6])) + { + FCommandLine line(cmd); + C_SearchForPullins(this, file, line); + } + // Recursive exec: Parse this file now. + else if (strnicmp(cmd, "exec", 4) == 0 && isspace(cmd[4])) + { + FCommandLine argv(cmd); + for (int i = 1; i < argv.argc(); ++i) + { + C_ParseExecFile(argv[i], this); + } + } + else + { + Commands.Push(cmd); + } +} + +void FExecList::ExecCommands() const +{ + for (unsigned i = 0; i < Commands.Size(); ++i) + { + AddCommandString(Commands[i].GetChars()); + } +} + +void FExecList::AddPullins(std::vector& wads, FConfigFile *config) const +{ + for (unsigned i = 0; i < Pullins.Size(); ++i) + { + D_AddFile(wads, Pullins[i].GetChars(), true, -1, config); + } +} + +FExecList *C_ParseExecFile(const char *file, FExecList *exec) +{ + char cmd[4096]; + + FileReader fr; + + if ( (fr.OpenFile(file)) ) + { + while (fr.Gets(cmd, countof(cmd)-1)) + { + // Comments begin with // + char *stop = cmd + strlen(cmd) - 1; + char *comment = cmd; + int inQuote = 0; + + if (*stop == '\n') + *stop-- = 0; + + while (comment < stop) + { + if (*comment == '\"') + { + inQuote ^= 1; + } + else if (!inQuote && *comment == '/' && *(comment + 1) == '/') + { + break; + } + comment++; + } + if (comment == cmd) + { // Comment at line beginning + continue; + } + else if (comment < stop) + { // Comment in middle of line + *comment = 0; + } + if (exec == NULL) + { + exec = new FExecList; + } + exec->AddCommand(cmd, file); + } + } + else + { + Printf ("Could not open \"%s\"\n", file); + } + return exec; +} + +bool C_ExecFile (const char *file) +{ + FExecList *exec = C_ParseExecFile(file, NULL); + if (exec != NULL) + { + exec->ExecCommands(); + if (exec->Pullins.Size() > 0) + { + Printf(TEXTCOLOR_BOLD "Notice: Pullin files were ignored.\n"); + } + delete exec; + } + return exec != NULL; +} + +void C_SearchForPullins(FExecList *exec, const char *file, FCommandLine &argv) +{ + const char *lastSlash; + + assert(exec != NULL); + assert(file != NULL); +#ifdef __unix__ + lastSlash = strrchr(file, '/'); +#else + const char *lastSlash1, *lastSlash2; + + lastSlash1 = strrchr(file, '/'); + lastSlash2 = strrchr(file, '\\'); + lastSlash = max(lastSlash1, lastSlash2); +#endif + + for (int i = 1; i < argv.argc(); ++i) + { + // Try looking for the wad in the same directory as the .cfg + // before looking for it in the current directory. + if (lastSlash != NULL) + { + FString path(file, (lastSlash - file) + 1); + path += argv[i]; + if (FileExists(path)) + { + exec->Pullins.Push(path); + continue; + } + } + exec->Pullins.Push(argv[i]); + } +} + +static TArray dynccmds; // This needs to be explicitly deleted before shutdown - the names in here may not be valid during the exit handler. +// +// C_RegisterFunction() -- dynamically register a CCMD. +// +int C_RegisterFunction(const char* pszName, const char* pszDesc, int (*func)(CCmdFuncPtr)) +{ + FString nname = pszName; + auto callback = [nname, pszDesc, func](FCommandLine& args, int key) + { + if (args.argc() > 0) args.operator[](0); + CCmdFuncParm param = { args.argc() - 1, nname.GetChars(), (const char**)args._argv + 1, args.cmd }; + if (func(¶m) != CCMD_OK && pszDesc) + { + Printf("%s\n", pszDesc); + } + }; + auto ccmd = new FConsoleCommand(pszName, callback); + dynccmds.Push(ccmd); + return 0; +} + + +void C_ClearDynCCmds() +{ + for (auto ccmd : dynccmds) + { + delete ccmd; + } + dynccmds.Clear(); +} + +CCMD (pullin) +{ + // Actual handling for pullin is now completely special-cased above + Printf (TEXTCOLOR_BOLD "Pullin" TEXTCOLOR_NORMAL " is only valid from .cfg\n" + "files and only when used at startup.\n"); +} + diff --git a/src/common/console/c_dispatch.h b/src/common/console/c_dispatch.h new file mode 100644 index 00000000000..e8b2bfdf0ac --- /dev/null +++ b/src/common/console/c_dispatch.h @@ -0,0 +1,214 @@ +/* +** c_dispatch.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __C_DISPATCH_H__ +#define __C_DISPATCH_H__ + +#include +#include +#include +#include +#include "c_console.h" +#include "tarray.h" +#include "c_commandline.h" +#include "zstring.h" + +class FConfigFile; + + +// Contains the contents of an exec'ed file +struct FExecList +{ + TArray Commands; + TArray Pullins; + + void AddCommand(const char *cmd, const char *file = nullptr); + void ExecCommands() const; + void AddPullins(std::vector &wads, FConfigFile *config) const; +}; + +extern bool ParsingKeyConf, UnsafeExecutionContext; +extern FString StoredWarp; // [RH] +warp at the command line + + +FExecList *C_ParseCmdLineParams(FExecList *exec); + +// Add commands to the console as if they were typed in. Can handle wait +// and semicolon-separated commands. This function may modify the source +// string, but the string will be restored to its original state before +// returning. Therefore, commands passed must not be in read-only memory. +void AddCommandString (const char *text, int keynum=0); + +void C_RunDelayedCommands(); +void C_ClearDelayedCommands(); + +// Process a single console command. Does not handle wait. +void C_DoCommand (const char *cmd, int keynum=0); + +FExecList *C_ParseExecFile(const char *file, FExecList *source); +void C_SearchForPullins(FExecList *exec, const char *file, class FCommandLine &args); +bool C_ExecFile(const char *file); +void C_ClearDynCCmds(); + +// Write out alias commands to a file for all current aliases. +void C_ArchiveAliases (FConfigFile *f); + +void C_SetAlias (const char *name, const char *cmd); +void C_ClearAliases (); + +// build a single string out of multiple strings +FString BuildString (int argc, FString *argv); + +typedef std::function CCmdRun;; + +class FConsoleCommand +{ +public: + FConsoleCommand (const char *name, CCmdRun RunFunc); + virtual ~FConsoleCommand (); + virtual bool IsAlias (); + void PrintCommand(); + + virtual void Run (FCommandLine &args, int key); + static FConsoleCommand* FindByName (const char* name); + + FConsoleCommand *m_Next, **m_Prev; + FString m_Name; + + enum { HASH_SIZE = 251 }; // Is this prime? + +protected: + FConsoleCommand (); + bool AddToHash (FConsoleCommand **table); + + CCmdRun m_RunFunc; + +}; + +#define CCMD(n) \ + void Cmd_##n (FCommandLine &, int key); \ + FConsoleCommand Cmd_##n##_Ref (#n, Cmd_##n); \ + void Cmd_##n (FCommandLine &argv, int key) + +class FUnsafeConsoleCommand : public FConsoleCommand +{ +public: + FUnsafeConsoleCommand (const char *name, CCmdRun RunFunc) + : FConsoleCommand (name, RunFunc) + { + } + + virtual void Run (FCommandLine &args, int key) override; +}; + +#define UNSAFE_CCMD(n) \ + static void Cmd_##n (FCommandLine &, int key); \ + static FUnsafeConsoleCommand Cmd_##n##_Ref (#n, Cmd_##n); \ + void Cmd_##n (FCommandLine &argv, int key) + +const int KEY_DBLCLICKED = 0x8000; + +class FConsoleAlias : public FConsoleCommand +{ +public: + FConsoleAlias (const char *name, const char *command, bool noSave); + ~FConsoleAlias (); + void Run (FCommandLine &args, int key); + bool IsAlias (); + void PrintAlias (); + void Archive (FConfigFile *f); + void Realias (const char *command, bool noSave); + void SafeDelete (); +protected: + FString m_Command[2]; // Slot 0 is saved to the ini, slot 1 is not. + bool bDoSubstitution; + bool bRunning; + bool bKill; +}; + +class FUnsafeConsoleAlias : public FConsoleAlias +{ +public: + FUnsafeConsoleAlias (const char *name, const char *command) + : FConsoleAlias (name, command, true) + { + } + + virtual void Run (FCommandLine &args, int key) override; +}; + +class UnsafeExecutionScope +{ + const bool wasEnabled; + +public: + explicit UnsafeExecutionScope(const bool enable = true) + : wasEnabled(UnsafeExecutionContext) + { + UnsafeExecutionContext = enable; + } + + ~UnsafeExecutionScope() + { + UnsafeExecutionContext = wasEnabled; + } +}; + + + +void execLogfile(const char *fn, bool append = false); + +enum +{ + CCMD_OK = 0, + CCMD_SHOWHELP = 1 +}; + +struct CCmdFuncParm +{ + int32_t numparms; + const char* name; + const char** parms; + const char* raw; +}; + +using CCmdFuncPtr = CCmdFuncParm const* const; + +// registers a function +// name = name of the function +// help = a short help string +// func = the entry point to the function +int C_RegisterFunction(const char* name, const char* help, int (*func)(CCmdFuncPtr)); + + +#endif //__C_DISPATCH_H__ diff --git a/src/common/console/c_enginecmds.cpp b/src/common/console/c_enginecmds.cpp new file mode 100644 index 00000000000..d6a2e027e24 --- /dev/null +++ b/src/common/console/c_enginecmds.cpp @@ -0,0 +1,311 @@ +/* +** c_cmds.cpp +** Miscellaneous game independent console commands. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef _WIN32 +#include +#else +#include +#endif + +#include +#include +#include +#include +#include "c_console.h" +#include "c_dispatch.h" +#include "engineerrors.h" +#include "printf.h" +#include "files.h" +#include "filesystem.h" +#include "gstrings.h" +#include "version.h" +#include "fs_findfile.h" +#include "md5.h" +#include "i_specialpaths.h" +#include "i_system.h" +#include "cmdlib.h" + +extern FILE* Logfile; + +CCMD (quit) +{ + throw CExitEvent(0); +} + +CCMD (exit) +{ + throw CExitEvent(0); +} + +CCMD (gameversion) +{ + Printf ("%s @ %s\nCommit %s\n", GetVersionString(), GetGitTime(), GetGitHash()); +} + +CCMD (print) +{ + if (argv.argc() != 2) + { + Printf ("print : Print a string from the string table\n"); + return; + } + const char *str = GStrings.CheckString(argv[1]); + if (str == NULL) + { + Printf ("%s unknown\n", argv[1]); + } + else + { + Printf ("%s\n", str); + } +} + +UNSAFE_CCMD (exec) +{ + if (argv.argc() < 2) + return; + + for (int i = 1; i < argv.argc(); ++i) + { + if (!C_ExecFile(argv[i])) + { + Printf ("Could not exec \"%s\"\n", argv[i]); + break; + } + } +} + +void execLogfile(const char *fn, bool append) +{ + if ((Logfile = fopen(fn, append? "a" : "w"))) + { + const char *timestr = myasctime(); + Printf("Log started: %s\n", timestr); + } + else + { + Printf("Could not start log\n"); + } +} + +UNSAFE_CCMD (logfile) +{ + + if (Logfile) + { + const char *timestr = myasctime(); + Printf("Log stopped: %s\n", timestr); + fclose (Logfile); + Logfile = NULL; + } + + if (argv.argc() >= 2) + { + execLogfile(argv[1], argv.argc() >=3? !!argv[2]:false); + } +} + +CCMD (error) +{ + if (argv.argc() > 1) + { + I_Error ("%s", argv[1]); + } + else + { + Printf ("Usage: error \n"); + } +} + +UNSAFE_CCMD (error_fatal) +{ + if (argv.argc() > 1) + { + I_FatalError ("%s", argv[1]); + } + else + { + Printf ("Usage: error_fatal \n"); + } +} + +//========================================================================== +// +// CCMD crashout +// +// Debugging routine for testing the crash logger. +// Useless in a win32 debug build, because that doesn't enable the crash logger. +// +//========================================================================== + +#if !defined(_WIN32) || !defined(_DEBUG) +UNSAFE_CCMD (crashout) +{ + *(volatile int *)0 = 0; +} +#endif + + +UNSAFE_CCMD (dir) +{ + FString path; + + if (argv.argc() > 1) + { + path = NicePath(argv[1]); + } + else + { + path = I_GetCWD();; + } + auto base = ExtractFileBase(path.GetChars(), true); + FString bpath; + if (base.IndexOfAny("*?") >= 0) + { + bpath = ExtractFilePath(path.GetChars()); + } + else + { + base = "*"; + bpath = path; + } + + FileSys::FileList list; + if (!FileSys::ScanDirectory(list, bpath.GetChars(), base.GetChars(), true)) + { + Printf ("Nothing matching %s\n", path.GetChars()); + } + else + { + Printf ("Listing of %s:\n", path.GetChars()); + for(auto& entry : list) + { + if (entry.isDirectory) + Printf (PRINT_BOLD, "%s \n", entry.FileName.c_str()); + else + Printf ("%s\n", entry.FileName.c_str()); + } + } +} + +//========================================================================== +// +// CCMD wdir +// +// Lists the contents of a loaded wad file. +// +//========================================================================== + +CCMD (wdir) +{ + int wadnum; + if (argv.argc() != 2) wadnum = -1; + else + { + wadnum = fileSystem.CheckIfResourceFileLoaded (argv[1]); + if (wadnum < 0) + { + Printf ("%s must be loaded to view its directory.\n", argv[1]); + return; + } + } + for (int i = 0; i < fileSystem.GetNumEntries(); ++i) + { + if (wadnum == -1 || fileSystem.GetFileContainer(i) == wadnum) + { + Printf ("%10ld %s\n", fileSystem.FileLength(i), fileSystem.GetFileFullName(i)); + } + } +} + +//========================================================================== +// +// CCMD md5sum +// +// Like the command-line tool, because I wanted to make sure I had it right. +// +//========================================================================== + +CCMD (md5sum) +{ + if (argv.argc() < 2) + { + Printf("Usage: md5sum ...\n"); + } + for (int i = 1; i < argv.argc(); ++i) + { + FileReader fr; + if (!fr.OpenFile(argv[i])) + { + Printf("%s: %s\n", argv[i], strerror(errno)); + } + else + { + MD5Context md5; + uint8_t readbuf[8192]; + size_t len; + + while ((len = fr.Read(readbuf, sizeof(readbuf))) > 0) + { + md5.Update(readbuf, (unsigned int)len); + } + md5.Final(readbuf); + for(int j = 0; j < 16; ++j) + { + Printf("%02x", readbuf[j]); + } + Printf(" *%s\n", argv[i]); + } + } +} + +CCMD(printlocalized) +{ + if (argv.argc() > 1) + { + if (argv.argc() > 2) + { + FString lang = argv[2]; + lang.ToLower(); + if (lang.Len() >= 2) + { + Printf("%s\n", GStrings.GetLanguageString(argv[1], MAKE_ID(lang[0], lang[1], lang[2], 0))); + return; + } + } + Printf("%s\n", GStrings.GetString(argv[1])); + } + +} + diff --git a/src/console/c_expr.cpp b/src/common/console/c_expr.cpp similarity index 99% rename from src/console/c_expr.cpp rename to src/common/console/c_expr.cpp index cde8527e251..4a48439b783 100644 --- a/src/console/c_expr.cpp +++ b/src/common/console/c_expr.cpp @@ -40,7 +40,8 @@ #include "c_dispatch.h" #include "c_cvars.h" -#include "doomtype.h" +#include "cmdlib.h" +#include "printf.h" // MACROS ------------------------------------------------------------------ @@ -82,7 +83,7 @@ bool IsFloat (const char *str); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static FProduction *ParseExpression (FCommandLine &argv, int &parsept); -static const char *IsNum (const char *str); +static const char *CIsNum (const char *str); static FStringProd *NewStringProd (const char *str); static FStringProd *NewStringProd (size_t len); static FDoubleProd *NewDoubleProd (double val); @@ -247,7 +248,7 @@ static FProduction *ParseExpression (FCommandLine &argv, int &parsept) bool IsFloat (const char *str) { const char *pt; - + if (*str == '+' || *str == '-') str++; @@ -257,13 +258,13 @@ bool IsFloat (const char *str) } else { - pt = IsNum (str); + pt = CIsNum (str); if (pt == NULL) return false; } if (*pt == '.') { - pt = IsNum (pt+1); + pt = CIsNum (pt+1); if (pt == NULL) return false; } @@ -272,7 +273,7 @@ bool IsFloat (const char *str) pt++; if (*pt == '+' || *pt == '-') pt++; - pt = IsNum (pt); + pt = CIsNum (pt); } return pt != NULL && *pt == 0; } @@ -283,7 +284,7 @@ bool IsFloat (const char *str) // //========================================================================== -static const char *IsNum (const char *str) +static const char *CIsNum (const char *str) { const char *start = str; @@ -366,7 +367,7 @@ static FStringProd *DoubleToString (FProduction *prod) static FDoubleProd *StringToDouble (FProduction *prod) { FDoubleProd *newprod; - + newprod = NewDoubleProd (atof (static_cast(prod)->Value)); M_Free (prod); return newprod; diff --git a/src/common/console/c_notifybufferbase.cpp b/src/common/console/c_notifybufferbase.cpp new file mode 100644 index 00000000000..11be81dd32e --- /dev/null +++ b/src/common/console/c_notifybufferbase.cpp @@ -0,0 +1,141 @@ +/* +** c_notifybufferbase.cpp +** Implements the buffer for the notification message +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "v_text.h" +#include "i_time.h" +#include "v_draw.h" +#include "c_notifybufferbase.h" + + +void FNotifyBufferBase::Shift(int maxlines) +{ + if (maxlines >= 0 && Text.Size() > (unsigned)maxlines) + { + Text.Delete(0, Text.Size() - maxlines); + } +} + +void FNotifyBufferBase::Clear() +{ + Text.Clear(); +} + + +void FNotifyBufferBase::AddString(int printlevel, FFont *printFont, const FString &source, int formatwidth, float keeptime, int maxlines) +{ + if (printFont == nullptr) return; // Without an initialized font we cannot handle the message (this is for those which come here before the font system is ready.) + LineHeight = printFont->GetHeight(); + TArray lines; + + if (AddType == APPENDLINE && Text.Size() > 0 && Text[Text.Size() - 1].PrintLevel == printlevel) + { + FString str = Text[Text.Size() - 1].Text + source; + lines = V_BreakLines (printFont, formatwidth, str); + } + else + { + lines = V_BreakLines (printFont, formatwidth, source); + if (AddType == APPENDLINE) + { + AddType = NEWLINE; + } + } + + if (lines.Size() == 0) + return; + + for (auto &line : lines) + { + FNotifyText newline; + + newline.Text = line.Text; + newline.TimeOut = int(keeptime * GameTicRate); + newline.Ticker = 0; + newline.PrintLevel = printlevel; + if (AddType == NEWLINE || Text.Size() == 0) + { + if (maxlines > 0) + { + Shift(maxlines - 1); + } + Text.Push(newline); + } + else + { + Text[Text.Size() - 1] = newline; + } + AddType = NEWLINE; + } + + switch (source[source.Len()-1]) + { + case '\r': AddType = REPLACELINE; break; + case '\n': AddType = NEWLINE; break; + default: AddType = APPENDLINE; break; + } + + TopGoal = 0; +} + +void FNotifyBufferBase::Tick() +{ + if (TopGoal > Top) + { + Top++; + } + else if (TopGoal < Top) + { + Top--; + } + + // Remove lines from the beginning that have expired. + unsigned i; + for (i = 0; i < Text.Size(); ++i) + { + Text[i].Ticker++; + } + + for (i = 0; i < Text.Size(); ++i) + { + if (Text[i].TimeOut != 0 && Text[i].TimeOut > Text[i].Ticker) + break; + } + if (i > 0) + { + Text.Delete(0, i); + Top += LineHeight; + } +} + diff --git a/src/common/console/c_notifybufferbase.h b/src/common/console/c_notifybufferbase.h new file mode 100644 index 00000000000..0257bb9db41 --- /dev/null +++ b/src/common/console/c_notifybufferbase.h @@ -0,0 +1,39 @@ +#pragma once +#include "zstring.h" +#include "tarray.h" + +class FFont; + +struct FNotifyText +{ + int TimeOut; + int Ticker; + int PrintLevel; + FString Text; +}; + +class FNotifyBufferBase +{ +public: + virtual ~FNotifyBufferBase() = default; + virtual void AddString(int printlevel, FString source) = 0; + virtual void Shift(int maxlines); + virtual void Clear(); + virtual void Tick(); + virtual void Draw() = 0; + +protected: + TArray Text; + int Top = 0; + int TopGoal = 0; + int LineHeight = 0; + enum { NEWLINE, APPENDLINE, REPLACELINE } AddType = NEWLINE; + + void AddString(int printlevel, FFont *printFont, const FString &source, int formatwidth, float keeptime, int maxlines); + +}; + + + + + diff --git a/src/common/console/c_tabcomplete.cpp b/src/common/console/c_tabcomplete.cpp new file mode 100644 index 00000000000..eccd64b0313 --- /dev/null +++ b/src/common/console/c_tabcomplete.cpp @@ -0,0 +1,322 @@ +/* +** c_tabcomplete.cpp +** Tab completion code +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "name.h" +#include "tarray.h" +#include "zstring.h" +#include "c_commandbuffer.h" +#include "c_cvars.h" +#include "c_tabcomplete.h" +#include "printf.h" +#include "c_dispatch.h" +#include "v_draw.h" +#include + + + +struct TabData +{ + int UseCount; + FName TabName; + + TabData() + : UseCount(0), TabName(NAME_None) + { + } + + TabData(const char *name) + : UseCount(1), TabName(name) + { + } + + TabData(const TabData &other) = default; +}; + +static TArray TabCommands (TArray::NoInit); +static int TabPos; // Last TabCommand tabbed to +static int TabStart; // First char in CmdLine to use for tab completion +static int TabSize; // Size of tab string + +bool TabbedLast; // True if last key pressed was tab +bool TabbedList; // True if tab list was shown +CVAR(Bool, con_notablist, false, CVAR_ARCHIVE) + +static bool FindTabCommand (const char *name, int *stoppos, int len) +{ + FName aname(name); + unsigned int i; + int cval = 1; + + for (i = 0; i < TabCommands.Size(); i++) + { + if (TabCommands[i].TabName == aname) + { + *stoppos = i; + return true; + } + cval = strnicmp (TabCommands[i].TabName.GetChars(), name, len); + if (cval >= 0) + break; + } + + *stoppos = i; + + return (cval == 0); +} + +void C_AddTabCommand (const char *name) +{ + int pos; + + if (FindTabCommand (name, &pos, INT_MAX)) + { + TabCommands[pos].UseCount++; + } + else + { + TabData tab(name); + TabCommands.Insert (pos, tab); + } +} + +void C_RemoveTabCommand (const char *name) +{ + if (TabCommands.Size() == 0) + { + // There are no tab commands that can be removed. + // This is important to skip construction of aname + // in case the NameManager has already been destroyed. + return; + } + + FName aname(name, true); + + if (aname == NAME_None) + { + return; + } + for (unsigned int i = 0; i < TabCommands.Size(); ++i) + { + if (TabCommands[i].TabName == aname) + { + if (--TabCommands[i].UseCount == 0) + { + TabCommands.Delete(i); + } + break; + } + } +} + +void C_ClearTabCommands () +{ + TabCommands.Clear(); +} + +static int FindDiffPoint (FName name1, const char *str2) +{ + const char *str1 = name1.GetChars(); + int i; + + for (i = 0; tolower(str1[i]) == tolower(str2[i]); i++) + if (str1[i] == 0 || str2[i] == 0) + break; + + return i; +} + +void C_TabComplete (bool goForward) +{ + unsigned i; + int diffpoint; + + auto CmdLineText = CmdLine.GetText(); + if (!TabbedLast) + { + bool cancomplete; + + + // Skip any spaces at beginning of command line + for (i = 0; i < CmdLineText.Len(); ++i) + { + if (CmdLineText[i] != ' ') + break; + } + if (i == CmdLineText.Len()) + { // Line was nothing but spaces + return; + } + TabStart = i; + + TabSize = (int)CmdLineText.Len() - TabStart; + + if (!FindTabCommand(&CmdLineText[TabStart], &TabPos, TabSize)) + return; // No initial matches + + // Show a list of possible completions, if more than one. + if (TabbedList || con_notablist) + { + cancomplete = true; + } + else + { + cancomplete = C_TabCompleteList (); + TabbedList = true; + } + + if (goForward) + { // Position just before the list of completions so that when TabPos + // gets advanced below, it will be at the first one. + --TabPos; + } + else + { // Find the last matching tab, then go one past it. + while (++TabPos < (int)TabCommands.Size()) + { + if (FindDiffPoint(TabCommands[TabPos].TabName, &CmdLineText[TabStart]) < TabSize) + { + break; + } + } + } + TabbedLast = true; + if (!cancomplete) + { + return; + } + } + + if ((goForward && ++TabPos == (int)TabCommands.Size()) || + (!goForward && --TabPos < 0)) + { + TabbedLast = false; + CmdLineText.Truncate(TabSize); + } + else + { + diffpoint = FindDiffPoint(TabCommands[TabPos].TabName, &CmdLineText[TabStart]); + + if (diffpoint < TabSize) + { + // No more matches + TabbedLast = false; + CmdLineText.Truncate(TabSize - TabStart); + } + else + { + CmdLineText.Truncate(TabStart); + CmdLineText << TabCommands[TabPos].TabName.GetChars() << ' '; + } + } + CmdLine.SetString(CmdLineText); + CmdLine.MakeStartPosGood(); +} + +bool C_TabCompleteList () +{ + int nummatches, i; + size_t maxwidth; + int commonsize = INT_MAX; + + nummatches = 0; + maxwidth = 0; + + auto CmdLineText = CmdLine.GetText(); + for (i = TabPos; i < (int)TabCommands.Size(); ++i) + { + if (FindDiffPoint (TabCommands[i].TabName, &CmdLineText[TabStart]) < TabSize) + { + break; + } + else + { + if (i > TabPos) + { + // This keeps track of the longest common prefix for all the possible + // completions, so we can fill in part of the command for the user if + // the longest common prefix is longer than what the user already typed. + int diffpt = FindDiffPoint (TabCommands[i-1].TabName, TabCommands[i].TabName.GetChars()); + if (diffpt < commonsize) + { + commonsize = diffpt; + } + } + nummatches++; + maxwidth = max (maxwidth, strlen (TabCommands[i].TabName.GetChars())); + } + } + if (nummatches > 1) + { + size_t x = 0; + maxwidth += 3; + Printf (TEXTCOLOR_BLUE "Completions for %s:\n", CmdLineText.GetChars()); + for (i = TabPos; nummatches > 0; ++i, --nummatches) + { + // [Dusk] Print console commands blue, CVars green, aliases red. + const char* colorcode = ""; + FConsoleCommand* ccmd; + if (FindCVar (TabCommands[i].TabName.GetChars(), NULL)) + colorcode = TEXTCOLOR_GREEN; + else if ((ccmd = FConsoleCommand::FindByName (TabCommands[i].TabName.GetChars())) != NULL) + { + if (ccmd->IsAlias()) + colorcode = TEXTCOLOR_RED; + else + colorcode = TEXTCOLOR_LIGHTBLUE; + } + + Printf ("%s%-*s", colorcode, int(maxwidth), TabCommands[i].TabName.GetChars()); + x += maxwidth; + if (x > CmdLine.ConCols / active_con_scale(twod) - maxwidth) + { + x = 0; + Printf ("\n"); + } + } + if (x != 0) + { + Printf ("\n"); + } + // Fill in the longest common prefix, if it's longer than what was typed. + if (TabSize != commonsize) + { + TabSize = commonsize; + CmdLineText.Truncate(TabStart); + CmdLineText.AppendCStrPart(TabCommands[TabPos].TabName.GetChars(), commonsize); + CmdLine.SetString(CmdLineText); + } + return false; + } + return true; +} diff --git a/src/common/console/c_tabcomplete.h b/src/common/console/c_tabcomplete.h new file mode 100644 index 00000000000..1bef4196bde --- /dev/null +++ b/src/common/console/c_tabcomplete.h @@ -0,0 +1,9 @@ +#pragma once + +void C_AddTabCommand (const char *name); +void C_RemoveTabCommand (const char *name); +void C_ClearTabCommands(); // Removes all tab commands +void C_TabComplete(bool goForward); +bool C_TabCompleteList(); +extern bool TabbedLast; // True if last key pressed was tab +extern bool TabbedList; // True if tab list was shown diff --git a/src/common/console/keydef.h b/src/common/console/keydef.h new file mode 100644 index 00000000000..1088067741c --- /dev/null +++ b/src/common/console/keydef.h @@ -0,0 +1,142 @@ +#pragma once + +#include +#include + +// +// Keyboard definition. Everything below = 0x100 matches +// a mode 1 keyboard scan code. +// + +enum EKeyCodes +{ + KEY_PAUSE = 0xc5, // DIK_PAUSE + KEY_RIGHTARROW = 0xcd, // DIK_RIGHT + KEY_LEFTARROW = 0xcb, // DIK_LEFT + KEY_UPARROW = 0xc8, // DIK_UP + KEY_DOWNARROW = 0xd0, // DIK_DOWN + KEY_ESCAPE = 0x01, // DIK_ESCAPE + KEY_ENTER = 0x1c, // DIK_RETURN + KEY_SPACE = 0x39, // DIK_SPACE + KEY_TAB = 0x0f, // DIK_TAB + KEY_F1 = 0x3b, // DIK_F1 + KEY_F2 = 0x3c, // DIK_F2 + KEY_F3 = 0x3d, // DIK_F3 + KEY_F4 = 0x3e, // DIK_F4 + KEY_F5 = 0x3f, // DIK_F5 + KEY_F6 = 0x40, // DIK_F6 + KEY_F7 = 0x41, // DIK_F7 + KEY_F8 = 0x42, // DIK_F8 + KEY_F9 = 0x43, // DIK_F9 + KEY_F10 = 0x44, // DIK_F10 + KEY_F11 = 0x57, // DIK_F11 + KEY_F12 = 0x58, // DIK_F12 + KEY_GRAVE = 0x29, // DIK_GRAVE + + KEY_BACKSPACE = 0x0e, // DIK_BACK + + KEY_EQUALS = 0x0d, // DIK_EQUALS + KEY_MINUS = 0x0c, // DIK_MINUS + + KEY_LSHIFT = 0x2A, // DIK_LSHIFT + KEY_LCTRL = 0x1d, // DIK_LCONTROL + KEY_LALT = 0x38, // DIK_LMENU + + KEY_RSHIFT = 0x36, + KEY_RCTRL = 0x9d, + KEY_RALT = 0xb8, + + KEY_INS = 0xd2, // DIK_INSERT + KEY_DEL = 0xd3, // DIK_DELETE + KEY_END = 0xcf, // DIK_END + KEY_HOME = 0xc7, // DIK_HOME + KEY_PGUP = 0xc9, // DIK_PRIOR + KEY_PGDN = 0xd1, // DIK_NEXT + + KEY_VOLUMEDOWN = 0xAE, // DIK_VOLUMEDOWN + KEY_VOLUMEUP = 0xB0, // DIK_VOLUMEUP + + KEY_FIRSTMOUSEBUTTON = 0x100, + KEY_MOUSE1 = 0x100, + KEY_MOUSE2 = 0x101, + KEY_MOUSE3 = 0x102, + KEY_MOUSE4 = 0x103, + KEY_MOUSE5 = 0x104, + KEY_MOUSE6 = 0x105, + KEY_MOUSE7 = 0x106, + KEY_MOUSE8 = 0x107, + + KEY_FIRSTJOYBUTTON = 0x108, + KEY_JOY1 = KEY_FIRSTJOYBUTTON+0, + KEY_JOY2, + KEY_JOY3, + KEY_JOY4, + KEY_JOY5, + KEY_JOY6, + KEY_JOY7, + KEY_JOY8, + KEY_JOY14 = KEY_FIRSTJOYBUTTON+13, + KEY_JOY15 = KEY_FIRSTJOYBUTTON+14, + KEY_LASTJOYBUTTON = 0x187, + KEY_JOYPOV1_UP = 0x188, + KEY_JOYPOV1_RIGHT = 0x189, + KEY_JOYPOV1_DOWN = 0x18a, + KEY_JOYPOV1_LEFT = 0x18b, + KEY_JOYPOV2_UP = 0x18c, + KEY_JOYPOV3_UP = 0x190, + KEY_JOYPOV4_UP = 0x194, + + KEY_MWHEELUP = 0x198, + KEY_MWHEELDOWN = 0x199, + KEY_MWHEELRIGHT = 0x19A, + KEY_MWHEELLEFT = 0x19B, + + KEY_JOYAXIS1PLUS = 0x19C, + KEY_JOYAXIS1MINUS = 0x19D, + KEY_JOYAXIS2PLUS = 0x19E, + KEY_JOYAXIS2MINUS = 0x19F, + KEY_JOYAXIS3PLUS = 0x1A0, + KEY_JOYAXIS3MINUS = 0x1A1, + KEY_JOYAXIS4PLUS = 0x1A2, + KEY_JOYAXIS4MINUS = 0x1A3, + KEY_JOYAXIS5PLUS = 0x1A4, + KEY_JOYAXIS5MINUS = 0x1A5, + KEY_JOYAXIS6PLUS = 0x1A6, + KEY_JOYAXIS6MINUS = 0x1A7, + KEY_JOYAXIS7PLUS = 0x1A8, + KEY_JOYAXIS7MINUS = 0x1A9, + KEY_JOYAXIS8PLUS = 0x1AA, + KEY_JOYAXIS8MINUS = 0x1AB, + + KEY_PAD_LTHUMB_RIGHT = 0x1AC, + KEY_PAD_LTHUMB_LEFT = 0x1AD, + KEY_PAD_LTHUMB_DOWN = 0x1AE, + KEY_PAD_LTHUMB_UP = 0x1AF, + + KEY_PAD_RTHUMB_RIGHT = 0x1B0, + KEY_PAD_RTHUMB_LEFT = 0x1B1, + KEY_PAD_RTHUMB_DOWN = 0x1B2, + KEY_PAD_RTHUMB_UP = 0x1B3, + + KEY_PAD_DPAD_UP = 0x1B4, + KEY_PAD_DPAD_DOWN = 0x1B5, + KEY_PAD_DPAD_LEFT = 0x1B6, + KEY_PAD_DPAD_RIGHT = 0x1B7, + KEY_PAD_START = 0x1B8, + KEY_PAD_BACK = 0x1B9, + KEY_PAD_LTHUMB = 0x1BA, + KEY_PAD_RTHUMB = 0x1BB, + KEY_PAD_LSHOULDER = 0x1BC, + KEY_PAD_RSHOULDER = 0x1BD, + KEY_PAD_LTRIGGER = 0x1BE, + KEY_PAD_RTRIGGER = 0x1BF, + KEY_PAD_A = 0x1C0, + KEY_PAD_B = 0x1C1, + KEY_PAD_X = 0x1C2, + KEY_PAD_Y = 0x1C3, + + NUM_KEYS = 0x1C4, + + NUM_JOYAXISBUTTONS = 8, +}; + diff --git a/src/common/cutscenes/movieplayer.cpp b/src/common/cutscenes/movieplayer.cpp new file mode 100644 index 00000000000..a1b04385f61 --- /dev/null +++ b/src/common/cutscenes/movieplayer.cpp @@ -0,0 +1,984 @@ +/* +** movieplayer.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "types.h" +#include "screenjob.h" +#include "i_time.h" +#include "v_2ddrawer.h" +#include "animlib.h" +#include "v_draw.h" +#include "s_soundinternal.h" +#include "animtexture.h" +#include "gamestate.h" +#include "SmackerDecoder.h" +#include "playmve.h" +#include +#include +#include "filesystem.h" +#include "vm.h" +#include "printf.h" +#include +#include +#include +#include "filereadermusicinterface.h" + +class MoviePlayer +{ +protected: + enum EMovieFlags + { + NOSOUNDCUTOFF = 1, + FIXEDVIEWPORT = 2, // Forces fixed 640x480 screen size like for Blood's intros. + NOMUSICCUTOFF = 4, + }; + + int flags; +public: + virtual void Start() {} + virtual bool Frame(uint64_t clock) = 0; + virtual void Stop() {} + virtual ~MoviePlayer() = default; + virtual FTextureID GetTexture() = 0; +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +// A simple filter is used to smooth out jittery timers +static const double AudioAvgFilterCoeff{std::pow(0.01, 1.0/10.0)}; +// A threshold is in place to avoid constantly skipping due to imprecise timers. +static constexpr double AudioSyncThreshold{0.03}; + +class MovieAudioTrack +{ + SoundStream *AudioStream = nullptr; + int SampleRate = 0; + int FrameSize = 0; + int64_t EndClockDiff = 0; + +public: + MovieAudioTrack() = default; + ~MovieAudioTrack() + { + if(AudioStream) + S_StopCustomStream(AudioStream); + } + + bool Start(int srate, int channels, MusicCustomStreamType sampletype, StreamCallback callback, void *ptr) + { + SampleRate = srate; + FrameSize = channels * ((sampletype == MusicSamples16bit) ? sizeof(int16_t) : sizeof(float)); + int bufsize = 40 * SampleRate / 1000 * FrameSize; + AudioStream = S_CreateCustomStream(bufsize, SampleRate, channels, sampletype, callback, ptr); + return !!AudioStream; + } + + void Finish() + { + if(AudioStream) + S_StopCustomStream(AudioStream); + AudioStream = nullptr; + } + + uint64_t GetClockTime(uint64_t clock) + { + // If there's no stream playing, report the frame clock adjusted by the audio + // end time. This ensures the returned clock keeps incrementing even after + // the audio stopped. + if(!AudioStream || EndClockDiff != 0) + return clock + EndClockDiff; + + auto pos = AudioStream->GetPlayPosition(); + int64_t postime = static_cast(pos.samplesplayed / double(SampleRate) * 1'000'000'000.0); + postime = std::max(0, postime - pos.latency.count()); + + if(AudioStream->IsEnded()) + { + // If the stream just ended, get the difference between the frame clock and + // the audio end time, so future calls keep incrementing the clock from this + // point. An alternative option may be to allow the AudioStream to hook into + // the audio device clock, which can keep incrementing at the same rate + // without the stream itself actually playing. + EndClockDiff = postime - clock; + } + + return static_cast(postime); + } + + SoundStream *GetAudioStream() const noexcept { return AudioStream; } + int GetSampleRate() const noexcept { return SampleRate; } + int GetFrameSize() const noexcept { return FrameSize; } +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class AnmPlayer : public MoviePlayer +{ + // This doesn't need its own class type + anim_t anim; + FileSys::FileData buffer; + int numframes = 0; + int curframe = 1; + int frametime = 0; + int nextframetime = 0; + AnimTextures animtex; + const TArray animSnd; + int frameTicks[3]; + +public: + bool isvalid() { return numframes > 0; } + + AnmPlayer(FileReader& fr, TArray& ans, const int *frameticks, int flags_) + : animSnd(std::move(ans)) + { + memcpy(frameTicks, frameticks, 3 * sizeof(int)); + flags = flags_; + buffer = fr.ReadPadded(1); + if (buffer.size() < 4) return; + fr.Close(); + + if (ANIM_LoadAnim(&anim, buffer.bytes(), buffer.size() - 1) < 0) + { + return; + } + numframes = ANIM_NumFrames(&anim); + animtex.SetSize(AnimTexture::Paletted, 320, 200); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool Frame(uint64_t clock) override + { + int currentclock = int(clock * 120 / 1'000'000'000); + + if (currentclock < nextframetime - 1) + { + return true; + } + + animtex.SetFrame(ANIM_GetPalette(&anim), ANIM_DrawFrame(&anim, curframe)); + frametime = currentclock; + + int delay = 20; + if (curframe == 1) delay = frameTicks[0]; + else if (curframe < numframes - 2) delay = frameTicks[1]; + else delay = frameTicks[2]; + nextframetime += delay; + + bool nostopsound = (flags & NOSOUNDCUTOFF); + for (unsigned i = 0; i < animSnd.Size(); i+=2) + { + if (animSnd[i] == curframe) + { + auto sound = FSoundID::fromInt(animSnd[i+1]); + if (sound == INVALID_SOUND) + soundEngine->StopAllChannels(); + else + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, nostopsound? CHANF_UI : CHANF_NONE, sound, 1.f, ATTN_NONE); + } + } + if (!nostopsound && curframe == numframes && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, INVALID_SOUND)) return true; + curframe++; + return curframe < numframes; + } + + void Stop() override + { + bool nostopsound = (flags & NOSOUNDCUTOFF); + if (!nostopsound) soundEngine->StopAllChannels(); + } + + + ~AnmPlayer() + { + animtex.Clean(); + } + + FTextureID GetTexture() override + { + return animtex.GetFrameID(); + } +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class MvePlayer : public MoviePlayer +{ + InterplayDecoder decoder; + MovieAudioTrack audioTrack; + bool failed = false; + + bool StreamCallback(SoundStream*, void *buff, int len) + { + return decoder.FillSamples(buff, len); + } + static bool StreamCallbackC(SoundStream *stream, void *buff, int len, void *userdata) + { return static_cast(userdata)->StreamCallback(stream, buff, len); } + +public: + bool isvalid() { return !failed; } + + MvePlayer(FileReader& fr) : decoder(SoundEnabled()) + { + failed = !decoder.Open(fr); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool Frame(uint64_t clock) override + { + if (failed) return false; + + if (!audioTrack.GetAudioStream() && decoder.HasAudio() && clock != 0) + { + S_StopMusic(true); + // start audio playback + if (!audioTrack.Start(decoder.GetSampleRate(), decoder.NumChannels(), MusicSamples16bit, StreamCallbackC, this)) + decoder.DisableAudio(); + } + + bool playon = decoder.RunFrame(audioTrack.GetClockTime(clock)); + return playon; + } + + ~MvePlayer() + { + audioTrack.Finish(); + + decoder.Close(); + } + + FTextureID GetTexture() override + { + return decoder.animTex().GetFrameID(); + } +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class VpxPlayer : public MoviePlayer +{ + bool failed = false; + FileReader fr; + AnimTextures animtex; + const TArray animSnd; + + ZMusic_MusicStream MusicStream = nullptr; + MovieAudioTrack AudioTrack; + + unsigned width, height; + TArray Pic; + TArray readBuf; + vpx_codec_iface_t *iface; + vpx_codec_ctx_t codec{}; + vpx_codec_iter_t iter = nullptr; + + double convrate; + + uint64_t nsecsperframe; + uint64_t nextframetime; + + int decstate = 0; + int framenum = 0; + int numframes; + int lastsoundframe = -1; +public: + int soundtrack = -1; + + bool StreamCallback(SoundStream*, void *buff, int len) + { + return ZMusic_FillStream(MusicStream, buff, len); + } + static bool StreamCallbackC(SoundStream *stream, void *buff, int len, void *userdata) + { return static_cast(userdata)->StreamCallback(stream, buff, len); } + +public: + bool isvalid() { return !failed; } + + VpxPlayer(FileReader& fr_, TArray& animSnd_, int flags_, int origframedelay, FString& error) : animSnd(std::move(animSnd_)) + { + fr = std::move(fr_); + flags = flags_; + + if (!ReadIVFHeader(origframedelay)) + { + // We should never get here, because any file failing this has been eliminated before this constructor got called. + error.Format("Failed reading IVF header\n"); + failed = true; + } + + Pic.Resize(width * height * 4); + + vpx_codec_dec_cfg_t cfg = { 1, width, height }; + if (vpx_codec_dec_init(&codec, iface, &cfg, 0)) + { + error.Format("Error initializing VPX codec.\n"); + failed = true; + } + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool ReadIVFHeader(int origframedelay) + { + // IVF format: http://wiki.multimedia.cx/index.php?title=IVF + uint32_t magic; fr.Read(&magic, 4); // do not byte swap! + if (magic != MAKE_ID('D', 'K', 'I', 'F')) return false; + uint16_t version = fr.ReadUInt16(); + if (version != 0) return false; + uint16_t length = fr.ReadUInt16(); + if (length != 32) return false; + fr.Read(&magic, 4); + + switch (magic) + { + case MAKE_ID('V', 'P', '8', '0'): + iface = &vpx_codec_vp8_dx_algo; break; + case MAKE_ID('V', 'P', '9', '0'): + iface = &vpx_codec_vp9_dx_algo; break; + default: + return false; + } + + width = fr.ReadUInt16(); + height = fr.ReadUInt16(); + uint32_t fpsdenominator = fr.ReadUInt32(); + uint32_t fpsnumerator = fr.ReadUInt32(); + numframes = fr.ReadUInt32(); + if (numframes == 0) return false; + fr.Seek(4, FileReader::SeekCur); + + if (fpsnumerator == 0 || fpsdenominator == 0) + { + // default to 30 fps if the header does not provide useful info. + fpsdenominator = 30; + fpsnumerator = 1; + } + + if (origframedelay < 1) + convrate = 0.0; + else + { + convrate = 120.0 * double(fpsnumerator); + convrate /= double(fpsdenominator) * double(origframedelay); + } + + nsecsperframe = int64_t(fpsnumerator) * 1'000'000'000 / fpsdenominator; + nextframetime = 0; + + return true; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool ReadFrame() + { + int corrupted = 0; + int framesize = fr.ReadInt32(); + fr.Seek(8, FileReader::SeekCur); + if (framesize == 0) return false; + + readBuf.Resize(framesize); + if (fr.Read(readBuf.Data(), framesize) != framesize) return false; + if (vpx_codec_decode(&codec, readBuf.Data(), readBuf.Size(), NULL, 0) != VPX_CODEC_OK) return false; + if (vpx_codec_control(&codec, VP8D_GET_FRAME_CORRUPTED, &corrupted) != VPX_CODEC_OK) return false; + return true; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + vpx_image_t *GetFrameData() + { + vpx_image_t *img; + do + { + if (decstate == 0) // first time / begin + { + if (!ReadFrame()) return nullptr; + decstate = 1; + } + + img = vpx_codec_get_frame(&codec, &iter); + if (img == nullptr) + { + decstate = 0; + iter = nullptr; + } + } while (img == nullptr); + + return img->d_w == width && img->d_h == height? img : nullptr; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + void SetPixel(uint8_t* dest, uint8_t y, uint8_t u, uint8_t v) + { + dest[0] = y; + dest[1] = u; + dest[2] = v; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + void Start() override + { + if (SoundStream *stream = AudioTrack.GetAudioStream()) + { + stream->SetPaused(false); + } + else if (soundtrack >= 0) + { + FileReader reader = fileSystem.ReopenFileReader(soundtrack); + if (reader.isOpen()) + { + MusicStream = ZMusic_OpenSong(GetMusicReader(reader), MDEV_DEFAULT, nullptr); + } + if (!MusicStream) + { + Printf(PRINT_BOLD, "Failed to decode %s\n", fileSystem.GetFileFullName(soundtrack, false)); + } + } + animtex.SetSize(AnimTexture::VPX, width, height); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool FormatSupported(vpx_img_fmt_t fmt) + { + return fmt == VPX_IMG_FMT_I420 || fmt == VPX_IMG_FMT_I444 || fmt == VPX_IMG_FMT_I422 || fmt == VPX_IMG_FMT_I440; + } + + + bool Frame(uint64_t clock) override + { + if (!AudioTrack.GetAudioStream() && MusicStream && clock != 0) + { + S_StopMusic(true); + + bool ok = false; + SoundStreamInfo info{}; + ZMusic_GetStreamInfo(MusicStream, &info); + // if mBufferSize == 0, the music stream is played externally (e.g. + // Windows' MIDI synth), which we can't keep synced. Play anyway? + if (info.mBufferSize > 0 && ZMusic_Start(MusicStream, 0, false)) + { + ok = AudioTrack.Start(info.mSampleRate, abs(info.mNumChannels), + (info.mNumChannels < 0) ? MusicSamples16bit : MusicSamplesFloat, &StreamCallbackC, this); + } + if (!ok) + { + ZMusic_Close(MusicStream); + MusicStream = nullptr; + } + } + + clock = AudioTrack.GetClockTime(clock); + + bool stop = false; + if (clock >= nextframetime) + { + + + nextframetime += nsecsperframe; + + while(clock >= nextframetime) + { // frameskipping + auto img = GetFrameData(); + framenum++; + nextframetime += nsecsperframe; + if (framenum >= numframes || !img) break; + } + + if (framenum < numframes) + { + auto img = GetFrameData(); + + if (!img || !FormatSupported(img->fmt)) + { + Printf(PRINT_BOLD, "Failed reading next frame\n"); + stop = true; + } + else + { + animtex.SetFrame(nullptr, img); + } + + framenum++; + } + if (framenum >= numframes) stop = true; + + bool nostopsound = (flags & NOSOUNDCUTOFF); + int soundframe = (convrate > 0.0) ? int(convrate * framenum) : framenum; + if (soundframe > lastsoundframe) + { + if (soundtrack == -1) + { + for (unsigned i = 0; i < animSnd.Size(); i += 2) + { + if (animSnd[i] == soundframe) + { + auto sound = FSoundID::fromInt(animSnd[i + 1]); + if (sound == INVALID_SOUND) + soundEngine->StopAllChannels(); + else + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, nostopsound ? CHANF_UI : CHANF_NONE, sound, 1.f, ATTN_NONE); + } + } + } + lastsoundframe = soundframe; + } + } + return !stop; + } + + void Stop() override + { + if (SoundStream *stream = AudioTrack.GetAudioStream()) + stream->SetPaused(true); + bool nostopsound = (flags & NOSOUNDCUTOFF); + if (!nostopsound) soundEngine->StopAllChannels(); + } + + ~VpxPlayer() + { + if(MusicStream) + { + AudioTrack.Finish(); + ZMusic_Close(MusicStream); + } + vpx_codec_destroy(&codec); + animtex.Clean(); + } + + FTextureID GetTexture() override + { + return animtex.GetFrameID(); + } +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +struct AudioData +{ + SmackerAudioInfo inf; + + int nWrite = 0; + int nRead = 0; +}; + +class SmkPlayer : public MoviePlayer +{ + SmackerHandle hSMK{}; + int numAudioTracks; + AudioData adata; + uint32_t nWidth, nHeight; + uint8_t palette[768]; + AnimTextures animtex; + TArray pFrame; + TArray audioBuffer; + int nFrames; + bool fullscreenScale; + uint64_t nFrameNs; + int nFrame = 0; + const TArray animSnd; + FString filename; + MovieAudioTrack AudioTrack; + bool hassound = false; + +public: + bool isvalid() { return hSMK.isValid; } + + bool StreamCallback(SoundStream* stream, void* buff, int len) + { + const int samplerate = AudioTrack.GetSampleRate(); + const int framesize = AudioTrack.GetFrameSize(); + + int avail = (adata.nWrite - adata.nRead) * 2; + + int wrote = 0; + while(wrote < len) + { + if (avail == 0) + { + auto read = Smacker_GetAudioData(hSMK, 0, audioBuffer.Data()); + if (read == 0) + { + if (wrote == 0) + return false; + break; + } + + adata.nWrite = read / 2; + avail = read; + } + + int todo = std::min(len-wrote, avail); + + memcpy((char*)buff+wrote, &audioBuffer[adata.nRead], todo); + adata.nRead += todo / 2; + if(adata.nRead == adata.nWrite) + adata.nRead = adata.nWrite = 0; + avail -= todo; + wrote += todo; + } + + if (wrote < len) + memset((char*)buff+wrote, 0, len-wrote); + return true; + } + static bool StreamCallbackC(SoundStream* stream, void* buff, int len, void* userdata) + { return static_cast(userdata)->StreamCallback(stream, buff, len); } + + + SmkPlayer(const char *fn, TArray& ans, int flags_) : animSnd(std::move(ans)) + { + hSMK = Smacker_Open(fn); + if (!hSMK.isValid) + { + return; + } + flags = flags_; + Smacker_GetFrameSize(hSMK, nWidth, nHeight); + pFrame.Resize(nWidth * nHeight + max(nWidth, nHeight)); + float frameRate = Smacker_GetFrameRate(hSMK); + nFrameNs = uint64_t(1'000'000'000 / frameRate); + nFrames = Smacker_GetNumFrames(hSMK); + Smacker_GetPalette(hSMK, palette); + + numAudioTracks = Smacker_GetNumAudioTracks(hSMK); + if (numAudioTracks && SoundEnabled()) + { + adata.nWrite = 0; + adata.nRead = 0; + adata.inf = Smacker_GetAudioTrackDetails(hSMK, 0); + if (adata.inf.idealBufferSize > 0) + { + audioBuffer.Resize(adata.inf.idealBufferSize / 2); + hassound = true; + } + for (int i = 1;i < numAudioTracks;++i) + Smacker_DisableAudioTrack(hSMK, i); + numAudioTracks = 1; + } + if (!hassound) + { + adata.inf = {}; + Smacker_DisableAudioTrack(hSMK, 0); + numAudioTracks = 0; + } + } + + //--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + + void Start() override + { + animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight); + if (SoundStream *stream = AudioTrack.GetAudioStream()) + stream->SetPaused(false); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool Frame(uint64_t clock) override + { + if (!AudioTrack.GetAudioStream() && numAudioTracks && clock != 0) + { + S_StopMusic(true); + + if (!AudioTrack.Start(adata.inf.sampleRate, adata.inf.nChannels, MusicSamples16bit, StreamCallbackC, this)) + { + Smacker_DisableAudioTrack(hSMK, 0); + numAudioTracks = 0; + } + } + + clock = AudioTrack.GetClockTime(clock); + int frame = int(clock / nFrameNs); + + twod->ClearScreen(); + if (frame >= nFrame) + { + nFrame++; + Smacker_GetNextFrame(hSMK); + Smacker_GetPalette(hSMK, palette); + Smacker_GetFrame(hSMK, pFrame.Data()); + animtex.SetFrame(palette, pFrame.Data()); + + bool nostopsound = (flags & NOSOUNDCUTOFF); + if (!hassound) for (unsigned i = 0; i < animSnd.Size(); i += 2) + { + if (animSnd[i] == nFrame) + { + auto sound = FSoundID::fromInt(animSnd[i + 1]); + if (sound == INVALID_SOUND) + soundEngine->StopAllChannels(); + else + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, nostopsound ? CHANF_UI | CHANF_FORCE : CHANF_FORCE, sound, 1.f, ATTN_NONE); + } + } + } + + return nFrame < nFrames; + } + + void Stop() override + { + if (SoundStream *stream = AudioTrack.GetAudioStream()) + stream->SetPaused(true); + bool nostopsound = (flags & NOSOUNDCUTOFF); + if (!nostopsound && !hassound) soundEngine->StopAllChannels(); + } + + ~SmkPlayer() + { + AudioTrack.Finish(); + Smacker_Close(hSMK); + animtex.Clean(); + } + + FTextureID GetTexture() override + { + return animtex.GetFrameID(); + } + +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +MoviePlayer* OpenMovie(const char* filename, TArray& ans, const int* frameticks, int flags, FString& error) +{ + FileReader fr; + // first try as .ivf - but only if sounds are provided - the decoder is video only. + if (ans.Size()) + { + auto fn = StripExtension(filename); + DefaultExtension(fn, ".ivf"); + fr = fileSystem.ReopenFileReader(fn.GetChars()); + } + + if (!fr.isOpen()) fr = fileSystem.ReopenFileReader(filename); + if (!fr.isOpen()) + { + size_t nLen = strlen(filename); + // Strip the drive letter and retry. + if (nLen >= 3 && isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/') + { + filename += 3; + fr = fileSystem.ReopenFileReader(filename); + } + if (!fr.isOpen()) + { + error.Format("%s: Unable to open video\n", filename); + return nullptr; + } + } + char id[20] = {}; + + fr.Read(&id, 20); + fr.Seek(-20, FileReader::SeekCur); + + if (!memcmp(id, "LPF ", 4)) + { + auto anm = new AnmPlayer(fr, ans, frameticks, flags); + if (!anm->isvalid()) + { + error.Format("%s: invalid ANM file.\n", filename); + delete anm; + return nullptr; + } + return anm; + } + else if (!memcmp(id, "SMK2", 4)) + { + fr.Close(); + auto anm = new SmkPlayer(filename, ans, flags); + if (!anm->isvalid()) + { + error.Format("%s: invalid SMK file.\n", filename); + delete anm; + return nullptr; + } + return anm; + } + else if (!memcmp(id, "Interplay MVE File", 18)) + { + auto anm = new MvePlayer(fr); + if (!anm->isvalid()) + { + delete anm; + return nullptr; + } + return anm; + } + else if (!memcmp(id, "DKIF\0\0 \0VP80", 12) || !memcmp(id, "DKIF\0\0 \0VP90", 12)) + { + auto anm = new VpxPlayer(fr, ans, frameticks ? frameticks[1] : 0, flags, error); + if (!anm->isvalid()) + { + delete anm; + return nullptr; + } + // VPX files have no sound track, so look for a same-named sound file with a known extension as the soundtrack to be played. + static const char* knownSoundExts[] = { "OGG", "FLAC", "MP3", "OPUS", "WAV" }; + FString name = StripExtension(filename); + anm->soundtrack = fileSystem.FindFileWithExtensions(name.GetChars(), knownSoundExts, countof(knownSoundExts)); + return anm; + } + // add more formats here. + else + { + error.Format("%s: Unknown video format\n", filename); + return nullptr; + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(_MoviePlayer, Create) +{ + PARAM_PROLOGUE; + PARAM_STRING(filename); + PARAM_POINTER(sndinf, TArray); + PARAM_INT(flags); + PARAM_INT(frametime); + PARAM_INT(firstframetime); + PARAM_INT(lastframetime); + + FString error; + if (firstframetime == -1) firstframetime = frametime; + if (lastframetime == -1) lastframetime = frametime; + int frametimes[] = { firstframetime, frametime, lastframetime }; + auto movie = OpenMovie(filename.GetChars(), *sndinf, frametime == -1? nullptr : frametimes, flags, error); + if (!movie) + { + Printf(TEXTCOLOR_YELLOW "%s", error.GetChars()); + } + ACTION_RETURN_POINTER(movie); +} + +DEFINE_ACTION_FUNCTION(_MoviePlayer, Start) +{ + PARAM_SELF_STRUCT_PROLOGUE(MoviePlayer); + I_FreezeTime(true); + self->Start(); + I_FreezeTime(false); + return 0; +} + +DEFINE_ACTION_FUNCTION(_MoviePlayer, Frame) +{ + PARAM_SELF_STRUCT_PROLOGUE(MoviePlayer); + PARAM_FLOAT(clock); + ACTION_RETURN_INT(self->Frame(int64_t(clock))); +} + +DEFINE_ACTION_FUNCTION(_MoviePlayer, Destroy) +{ + PARAM_SELF_STRUCT_PROLOGUE(MoviePlayer); + self->Stop(); + delete self; + return 0; +} + +DEFINE_ACTION_FUNCTION(_MoviePlayer, GetTexture) +{ + PARAM_SELF_STRUCT_PROLOGUE(MoviePlayer); + ACTION_RETURN_INT(self->GetTexture().GetIndex()); +} diff --git a/src/common/cutscenes/playmve.cpp b/src/common/cutscenes/playmve.cpp new file mode 100644 index 00000000000..3c49e961055 --- /dev/null +++ b/src/common/cutscenes/playmve.cpp @@ -0,0 +1,1189 @@ +/* + * InterplayDecoder + * Copyright (C) 2020 sirlemonhead + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +/* This code is based on interplayvideo.c, dpcm.c and ipmovie.c from the FFmpeg project which can be obtained + * from http://www.ffmpeg.org/. Below is the license from interplayvideo.c + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Interplay MVE Video Decoder + * Copyright (C) 2003 The FFmpeg project + * + * This file is part of FFmpeg. + * + * FFmpeg 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include +#include "playmve.h" +#include "printf.h" +#include "v_draw.h" +#include "s_music.h" +#include "cmdlib.h" + + + + +static const int16_t delta_table[] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 47, 51, 56, 61, + 66, 72, 79, 86, 94, 102, 112, 122, + 133, 145, 158, 173, 189, 206, 225, 245, + 267, 292, 318, 348, 379, 414, 452, 493, + 538, 587, 640, 699, 763, 832, 908, 991, + 1081, 1180, 1288, 1405, 1534, 1673, 1826, 1993, + 2175, 2373, 2590, 2826, 3084, 3365, 3672, 4008, + 4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, + 8794, 9597, 10472, 11428, 12471, 13609, 14851, 16206, + 17685, 19298, 21060, 22981, 25078, 27367, 29864, 32589, + -29973, -26728, -23186, -19322, -15105, -10503, -5481, -1, + 1, 1, 5481, 10503, 15105, 19322, 23186, 26728, + 29973, -32589, -29864, -27367, -25078, -22981, -21060, -19298, + -17685, -16206, -14851, -13609, -12471, -11428, -10472, -9597, + -8794, -8059, -7385, -6767, -6202, -5683, -5208, -4772, + -4373, -4008, -3672, -3365, -3084, -2826, -2590, -2373, + -2175, -1993, -1826, -1673, -1534, -1405, -1288, -1180, + -1081, -991, -908, -832, -763, -699, -640, -587, + -538, -493, -452, -414, -379, -348, -318, -292, + -267, -245, -225, -206, -189, -173, -158, -145, + -133, -122, -112, -102, -94, -86, -79, -72, + -66, -61, -56, -51, -47, -43, -42, -41, + -40, -39, -38, -37, -36, -35, -34, -33, + -32, -31, -30, -29, -28, -27, -26, -25, + -24, -23, -22, -21, -20, -19, -18, -17, + -16, -15, -14, -13, -12, -11, -10, -9, + -8, -7, -6, -5, -4, -3, -2, -1 +}; + + +// macros to fetch little-endian words from a bytestream +#define LE_16(x) ((uint16_t)((*(x)) | ((*((x)+1)) << 8))) +#define LE_32(x) (LE_16(x) | ((uint32_t)LE_16(x+2) << 16)) +#define LE_64(x) (LE_32(x) | ((uint64_t)LE_32(x+4) << 32)) + + +bool InterplayDecoder::FillSamples(void *buff, int len) +{ + for (int i = 0; i < len;) + { + if(audio.nRead < audio.nWrite) + { + int todo = std::min(audio.nWrite-audio.nRead, (len-i) / 2); + memcpy((char*)buff+i, &audio.samples[audio.nRead], todo*2); + audio.nRead += todo; + if (audio.nRead == audio.nWrite) + audio.nRead = audio.nWrite = 0; + i += todo*2; + continue; + } + + std::unique_lock plock(PacketMutex); + while (audio.Packets.empty()) + { + if (!bIsPlaying || ProcessNextChunk() >= CHUNK_SHUTDOWN) + { + bIsPlaying = false; + if (i == 0) + return false; + memset((char*)buff+i, 0, len-i); + return true; + } + } + AudioPacket pkt = std::move(audio.Packets.front()); + audio.Packets.pop_front(); + plock.unlock(); + + int nSamples = (int)pkt.nSize; + const uint8_t *samplePtr = pkt.pData.get(); + if (audio.bCompressed) + { + int predictor[2]; + + for (int ch = 0; ch < audio.nChannels; ch++) + { + predictor[ch] = (int16_t)LE_16(samplePtr); + samplePtr += 2; + + audio.samples[audio.nWrite++] = predictor[ch]; + } + + bool stereo = audio.nChannels == 2; + nSamples -= 2*audio.nChannels; + nSamples &= ~(int)stereo; + + int ch = 0; + for (int j = 0; j < nSamples; ++j) + { + predictor[ch] += delta_table[*samplePtr++]; + predictor[ch] = clamp(predictor[ch], -32768, 32767); + + audio.samples[audio.nWrite++] = predictor[ch]; + + // toggle channel + ch ^= stereo ? 1 : 0; + } + } + else if (audio.nBitDepth == 8) + { + for (int j = 0; j < nSamples; ++j) + audio.samples[audio.nWrite++] = ((*samplePtr++)-128) << 8; + } + else + { + nSamples /= 2; + for (int j = 0; j < nSamples; ++j) + { + audio.samples[audio.nWrite++] = (int16_t)LE_16(samplePtr); + samplePtr += 2; + } + } + } + return true; +} + +void InterplayDecoder::DisableAudio() +{ + if (bAudioEnabled) + { + std::unique_lock plock(PacketMutex); + bAudioEnabled = false; + audio.Packets.clear(); + } +} + + +InterplayDecoder::InterplayDecoder(bool soundenabled) +{ + bIsPlaying = false; + bAudioEnabled = soundenabled; + + nWidth = 0; + nHeight = 0; + nFrame = 0; + + memset(palette, 0, sizeof(palette)); + + nFps = 0.0; + nFrameDuration = 0; + nTimerRate = 0; + nTimerDiv = 0; + + pVideoBuffers[0] = nullptr; + pVideoBuffers[1] = nullptr; + + decodeMap.pData = nullptr; + decodeMap.nSize = 0; + + nCurrentVideoBuffer = 0; + nPreviousVideoBuffer = 1; + + videoStride = 0; +} + +InterplayDecoder::~InterplayDecoder() +{ + Close(); +} + +void InterplayDecoder::SwapFrames() +{ + int t = nPreviousVideoBuffer; + nPreviousVideoBuffer = nCurrentVideoBuffer; + nCurrentVideoBuffer = t; +} + +int InterplayDecoder::ProcessNextChunk() +{ + uint8_t chunkPreamble[CHUNK_PREAMBLE_SIZE]; + if (fr.Read(chunkPreamble, CHUNK_PREAMBLE_SIZE) != CHUNK_PREAMBLE_SIZE) { + Printf(TEXTCOLOR_RED "InterplayDecoder: could not read from file (EOF?)\n"); + return CHUNK_EOF; + } + + int chunkSize = LE_16(&chunkPreamble[0]); + int chunkType = LE_16(&chunkPreamble[2]); + + ChunkData.resize(chunkSize); + if (fr.Read(ChunkData.data(), chunkSize) != chunkSize) { + Printf(TEXTCOLOR_RED "InterplayDecoder: could not read from file (EOF?)\n"); + return CHUNK_BAD; + } + + const uint8_t *palPtr = nullptr; + const uint8_t *mapPtr = nullptr; + const uint8_t *vidPtr = nullptr; + int palStart = 0, palCount = 0; + int mapSize = 0, vidSize = 0; + + // iterate through individual opcodes + const uint8_t *chunkPtr = ChunkData.data(); + while (chunkSize > 0 && chunkType != CHUNK_BAD) + { + if (chunkSize < OPCODE_PREAMBLE_SIZE) + { + Printf(TEXTCOLOR_RED "InterplayDecoder: opcode size too small\n"); + return CHUNK_BAD; + } + int opcodeSize = LE_16(chunkPtr); + int opcodeType = chunkPtr[2]; + int opcodeVersion = chunkPtr[3]; + + chunkPtr += OPCODE_PREAMBLE_SIZE; + chunkSize -= OPCODE_PREAMBLE_SIZE; + if (chunkSize < opcodeSize) + { + Printf(TEXTCOLOR_RED "InterplayDecoder: opcode size too large for chunk\n"); + return CHUNK_BAD; + } + chunkSize -= opcodeSize; + + switch (opcodeType) + { + case OPCODE_END_OF_STREAM: + chunkPtr += opcodeSize; + break; + + case OPCODE_END_OF_CHUNK: + chunkPtr += opcodeSize; + break; + + case OPCODE_CREATE_TIMER: + nTimerRate = LE_32(chunkPtr); + nTimerDiv = LE_16(chunkPtr+4); + chunkPtr += 6; + nFrameDuration = ((uint64_t)nTimerRate * nTimerDiv) * 1000; + break; + + case OPCODE_INIT_AUDIO_BUFFERS: + { + // Skip 2 bytes + uint16_t flags = LE_16(chunkPtr+2); + audio.nSampleRate = LE_16(chunkPtr+4); + chunkPtr += 6; + + uint32_t nBufferBytes = (opcodeVersion == 0) ? LE_16(chunkPtr) : LE_32(chunkPtr); + chunkPtr += (opcodeVersion == 0) ? 2 : 4; + + audio.nChannels = (flags & 0x1) ? 2 : 1; + audio.nBitDepth = (flags & 0x2) ? 16 : 8; + audio.bCompressed = (opcodeVersion > 0 && (flags & 0x4)); + audio.samples = std::make_unique(nBufferBytes / (audio.nBitDepth/8)); + audio.nRead = audio.nWrite = 0; + break; + } + + case OPCODE_START_STOP_AUDIO: + chunkPtr += opcodeSize; + break; + + case OPCODE_INIT_VIDEO_BUFFERS: + { + assert(((opcodeVersion == 0 && opcodeSize >= 4) || + (opcodeVersion == 1 && opcodeSize >= 6) || + (opcodeVersion == 2 && opcodeSize >= 8)) && + opcodeSize <= 8 && ! videoStride); + + nWidth = LE_16(chunkPtr) * 8; + nHeight = LE_16(chunkPtr+2) * 8; + + int count, truecolour; + if (opcodeVersion > 0) + { + count = LE_16(chunkPtr+4); + if (opcodeVersion > 1) + { + truecolour = LE_16(chunkPtr+6); + assert(truecolour == 0); + } + } + chunkPtr += opcodeSize; + + pVideoBuffers[0] = new uint8_t[nWidth * nHeight]; + pVideoBuffers[1] = new uint8_t[nWidth * nHeight]; + + videoStride = nWidth; + + animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight); + break; + } + + case OPCODE_UNKNOWN_06: + case OPCODE_UNKNOWN_0E: + case OPCODE_UNKNOWN_10: + case OPCODE_UNKNOWN_12: + case OPCODE_UNKNOWN_13: + case OPCODE_UNKNOWN_14: + case OPCODE_UNKNOWN_15: + chunkPtr += opcodeSize; + break; + + case OPCODE_SEND_BUFFER: + //int nPalStart = LE_16(chunkPtr); + //int nPalCount = LE_16(chunkPtr+2); + + { + VideoPacket pkt; + pkt.pData = std::make_unique(palCount*3 + mapSize + vidSize); + pkt.nPalStart = palStart; + pkt.nPalCount = palCount; + pkt.nDecodeMapSize = mapSize; + pkt.nVideoDataSize = vidSize; + + if (palPtr) + memcpy(pkt.pData.get(), palPtr, palCount*3); + if (mapPtr) + memcpy(pkt.pData.get() + palCount*3, mapPtr, mapSize); + if (vidPtr) + memcpy(pkt.pData.get() + palCount*3 + mapSize, vidPtr, vidSize); + pkt.bSendFlag = true; + VideoPackets.emplace_back(std::move(pkt)); + } + + palPtr = nullptr; + palStart = palCount = 0; + mapPtr = nullptr; + mapSize = 0; + vidPtr = nullptr; + vidSize = 0; + + chunkPtr += opcodeSize; + break; + + case OPCODE_AUDIO_FRAME: + { + uint16_t seqIndex = LE_16(chunkPtr); + uint16_t streamMask = LE_16(chunkPtr+2); + uint16_t nSamples = LE_16(chunkPtr+4); // number of samples this chunk(?) + chunkPtr += 6; + + // We only bother with stream 0 + if (!(streamMask & 1) || !bAudioEnabled) + { + chunkPtr += opcodeSize - 6; + break; + } + + AudioPacket pkt; + pkt.nSize = opcodeSize - 6; + pkt.pData = std::make_unique(pkt.nSize); + memcpy(pkt.pData.get(), chunkPtr, pkt.nSize); + audio.Packets.emplace_back(std::move(pkt)); + + chunkPtr += opcodeSize - 6; + break; + } + + case OPCODE_SILENCE_FRAME: + chunkPtr += opcodeSize; + break; + + case OPCODE_INIT_VIDEO_MODE: + chunkPtr += opcodeSize; + break; + + case OPCODE_CREATE_GRADIENT: + chunkPtr += opcodeSize; + Printf("InterplayDecoder: Create gradient not supported.\n"); + break; + + case OPCODE_SET_PALETTE: + if (opcodeSize > 0x304 || opcodeSize < 4) { + Printf("set_palette opcode with invalid size\n"); + chunkType = CHUNK_BAD; + break; + } + + palStart = LE_16(chunkPtr); + palCount = LE_16(chunkPtr+2); + palPtr = chunkPtr + 4; + if (palStart > 255 || palStart+palCount > 256) { + Printf("set_palette indices out of range (%d -> %d)\n", palStart, palStart+palCount-1); + chunkType = CHUNK_BAD; + break; + } + if (opcodeSize-4 < palCount*3) { + Printf("set_palette opcode too small (%d < %d)\n", opcodeSize-4, palCount*3); + chunkType = CHUNK_BAD; + break; + } + + chunkPtr += opcodeSize; + break; + + case OPCODE_SET_PALETTE_COMPRESSED: + chunkPtr += opcodeSize; + Printf("InterplayDecoder: Set palette compressed not supported.\n"); + break; + + case OPCODE_SET_DECODING_MAP: + mapPtr = chunkPtr; + mapSize = opcodeSize; + + chunkPtr += opcodeSize; + break; + + case OPCODE_VIDEO_DATA: + vidPtr = chunkPtr; + vidSize = opcodeSize; + + chunkPtr += opcodeSize; + break; + + default: + Printf("InterplayDecoder: Unknown opcode (0x%x v%d, %d bytes).\n", opcodeType, opcodeVersion, opcodeSize); + chunkPtr += opcodeSize; + break; + } + } + + if (chunkType < CHUNK_SHUTDOWN && (palPtr || mapPtr || vidPtr)) + { + VideoPacket pkt; + pkt.pData = std::make_unique(palCount*3 + mapSize + vidSize); + pkt.nPalStart = palStart; + pkt.nPalCount = palCount; + pkt.nDecodeMapSize = mapSize; + pkt.nVideoDataSize = vidSize; + + if (palPtr) + memcpy(pkt.pData.get(), palPtr, palCount*3); + if(mapPtr) + memcpy(pkt.pData.get() + palCount*3, mapPtr, mapSize); + if(vidPtr) + memcpy(pkt.pData.get() + palCount*3 + mapSize, vidPtr, vidSize); + pkt.bSendFlag = false; + VideoPackets.emplace_back(std::move(pkt)); + } + + return chunkType; +} + + +void InterplayDecoder::Close() +{ + bIsPlaying = false; + fr.Close(); + + if (decodeMap.pData) { + delete[] decodeMap.pData; + decodeMap.pData = nullptr; + } + + if (pVideoBuffers[0]) { + delete[] pVideoBuffers[0]; + pVideoBuffers[0] = nullptr; + } + if (pVideoBuffers[1]) { + delete[] pVideoBuffers[1]; + pVideoBuffers[1] = nullptr; + } + +} + +bool InterplayDecoder::Open(FileReader &fr_) +{ + // open the file (read only) + char lsig[20]; + + // check the file signature + fr_.Read((uint8_t*)lsig, sizeof(lsig)); + if (memcmp(lsig, "Interplay MVE File\x1A\0", sizeof(lsig)) != 0) + { + Printf(TEXTCOLOR_RED "InterplayDecoder: Unknown MVE signature\n "); + return false; + } + + // skip the next 6 bytes + fr_.Seek(6, FileReader::SeekCur); + fr = std::move(fr_); + + if (ProcessNextChunk() != CHUNK_INIT_VIDEO) + { + Printf(TEXTCOLOR_RED "InterplayDecoder: First chunk not CHUNK_INIT_VIDEO\n"); + return false; + } + + uint8_t chunkPreamble[CHUNK_PREAMBLE_SIZE]; + if (fr.Read(chunkPreamble, CHUNK_PREAMBLE_SIZE) != CHUNK_PREAMBLE_SIZE) { + Printf(TEXTCOLOR_RED "InterplayDecoder: could not read from file (EOF?)\n"); + return false; + } + fr.Seek(-CHUNK_PREAMBLE_SIZE, FileReader::SeekCur); + + int chunkType = LE_16(&chunkPreamble[2]); + if (chunkType == CHUNK_VIDEO) + bAudioEnabled = false; + else if (bAudioEnabled) + { + if (ProcessNextChunk() != CHUNK_INIT_AUDIO) + { + Printf(TEXTCOLOR_RED "InterplayDecoder: Second non-video chunk not CHUNK_INIT_AUDIO\n"); + return false; + } + bAudioEnabled = audio.nSampleRate > 0; + } + + bIsPlaying = true; + + return true; +} + +bool InterplayDecoder::RunFrame(uint64_t clock) +{ + // handle timing - wait until we're ready to process the next frame. + if (nNextFrameTime > clock) { + return true; + } + nNextFrameTime += nFrameDuration; + + bool doFrame = false; + do + { + std::unique_lock plock(PacketMutex); + while (VideoPackets.empty()) + { + if (!bIsPlaying || ProcessNextChunk() >= CHUNK_SHUTDOWN) + { + bIsPlaying = false; + return false; + } + } + VideoPacket pkt = std::move(VideoPackets.front()); + VideoPackets.pop_front(); + plock.unlock(); + + const uint8_t *palData = pkt.pData.get(); + const uint8_t *mapData = palData + pkt.nPalCount*3; + const uint8_t *vidData = mapData + pkt.nDecodeMapSize; + + if (pkt.nPalCount > 0) + { + int nPalEnd = pkt.nPalStart + pkt.nPalCount; + for (int i = pkt.nPalStart; i < nPalEnd; i++) + { + palette[i].r = (*palData++) << 2; + palette[i].g = (*palData++) << 2; + palette[i].b = (*palData++) << 2; + palette[i].r |= palette[i].r >> 6; + palette[i].g |= palette[i].g >> 6; + palette[i].b |= palette[i].b >> 6; + } + } + + if (pkt.nDecodeMapSize > 0) + { + if (!decodeMap.pData) + { + decodeMap.pData = new uint8_t[pkt.nDecodeMapSize]; + decodeMap.nSize = pkt.nDecodeMapSize; + } + else + { + if (pkt.nDecodeMapSize != decodeMap.nSize) { + delete[] decodeMap.pData; + decodeMap.pData = new uint8_t[pkt.nDecodeMapSize]; + decodeMap.nSize = pkt.nDecodeMapSize; + } + } + + memcpy(decodeMap.pData, mapData, pkt.nDecodeMapSize); + } + + if (pkt.nVideoDataSize > 0 && decodeMap.nSize > 0) + { + auto pStart = vidData; + + // need to skip 14 bytes + ChunkPtr = pStart + 14; + + int i = 0; + for (uint32_t y = 0; y < nHeight; y += 8) + { + for (uint32_t x = 0; x < nWidth; x += 8) + { + uint32_t opcode; + + // alternate between getting low and high 4 bits + if (i & 1) { + opcode = decodeMap.pData[i >> 1] >> 4; + } + else { + opcode = decodeMap.pData[i >> 1] & 0x0F; + } + i++; + + int32_t offset = x + (y * videoStride); + + switch (opcode) + { + default: + break; + case 0: + DecodeBlock0(offset); + break; + case 1: + DecodeBlock1(offset); + break; + case 2: + DecodeBlock2(offset); + break; + case 3: + DecodeBlock3(offset); + break; + case 4: + DecodeBlock4(offset); + break; + case 5: + DecodeBlock5(offset); + break; + case 7: + DecodeBlock7(offset); + break; + case 8: + DecodeBlock8(offset); + break; + case 9: + DecodeBlock9(offset); + break; + case 10: + DecodeBlock10(offset); + break; + case 11: + DecodeBlock11(offset); + break; + case 12: + DecodeBlock12(offset); + break; + case 13: + DecodeBlock13(offset); + break; + case 14: + DecodeBlock14(offset); + break; + case 15: + DecodeBlock15(offset); + break; + } + } + } + + auto pEnd = ChunkPtr; + // we can end up with 1 byte left we need to skip + int nSkipBytes = pkt.nVideoDataSize - (int)(pEnd - pStart); + assert(nSkipBytes <= 1); + } + + doFrame = pkt.bSendFlag; + } while(!doFrame); + + animtex.SetFrame(&palette[0].r , GetCurrentFrame()); + + nFrame++; + SwapFrames(); + + return true; +} + +void InterplayDecoder::CopyBlock(uint8_t* pDest, uint8_t* pSrc) +{ + for (int y = 0; y < 8; y++) + { + memcpy(pDest, pSrc, 8); + pSrc += (intptr_t)videoStride; + pDest += (intptr_t)videoStride; + } +} + +void InterplayDecoder::DecodeBlock0(int32_t offset) +{ + // copy from the same offset but from the previous frame + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetPreviousFrame() + (intptr_t)offset; + + CopyBlock(pDest, pSrc); +} + +void InterplayDecoder::DecodeBlock1(int32_t offset) +{ + // nothing to do for this. +} + +void InterplayDecoder::DecodeBlock2(int32_t offset) +{ + // copy block from 2 frames ago using a motion vector; need 1 more byte + uint8_t B = *ChunkPtr++; + + int x, y; + + if (B < 56) { + x = 8 + (B % 7); + y = B / 7; + } + else { + x = -14 + ((B - 56) % 29); + y = 8 + ((B - 56) / 29); + } + + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetCurrentFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride); + + CopyBlock(pDest, pSrc); +} + +void InterplayDecoder::DecodeBlock3(int32_t offset) +{ + // copy 8x8 block from current frame from an up/left block + uint8_t B = *ChunkPtr++; + + int x, y; + + // need 1 more byte for motion + if (B < 56) { + x = -(8 + (B % 7)); + y = -(B / 7); + } + else { + x = -(-14 + ((B - 56) % 29)); + y = -(8 + ((B - 56) / 29)); + } + + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetCurrentFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride); + + CopyBlock(pDest, pSrc); +} + +void InterplayDecoder::DecodeBlock4(int32_t offset) +{ + // copy a block from the previous frame; need 1 more byte + int x, y; + uint8_t B, BL, BH; + + B = *ChunkPtr++; + + BL = B & 0x0F; + BH = (B >> 4) & 0x0F; + x = -8 + BL; + y = -8 + BH; + + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetPreviousFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride); + + CopyBlock(pDest, pSrc); +} + +void InterplayDecoder::DecodeBlock5(int32_t offset) +{ + // copy a block from the previous frame using an expanded range; need 2 more bytes + int8_t x = *ChunkPtr++; + int8_t y = *ChunkPtr++; + + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetPreviousFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride); + + CopyBlock(pDest, pSrc); +} + +// Block6 is unknown and skipped + +void InterplayDecoder::DecodeBlock7(int32_t offset) +{ + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint32_t flags = 0; + + uint8_t P[2]; + P[0] = *ChunkPtr++; + P[1] = *ChunkPtr++; + + // 2-color encoding + if (P[0] <= P[1]) + { + // need 8 more bytes from the stream + for (int y = 0; y < 8; y++) + { + flags = (*ChunkPtr++) | 0x100; + for (; flags != 1; flags >>= 1) { + *pBuffer++ = P[flags & 1]; + } + pBuffer += (videoStride - 8); + } + } + else + { + // need 2 more bytes from the stream + flags = LE_16(ChunkPtr); + ChunkPtr += 2; + + for (int y = 0; y < 8; y += 2) + { + for (int x = 0; x < 8; x += 2, flags >>= 1) + { + pBuffer[x] = + pBuffer[x + 1] = + pBuffer[x + videoStride] = + pBuffer[x + 1 + videoStride] = P[flags & 1]; + } + pBuffer += videoStride * 2; + } + } +} + +void InterplayDecoder::DecodeBlock8(int32_t offset) +{ + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint32_t flags = 0; + uint8_t P[4]; + + // 2-color encoding for each 4x4 quadrant, or 2-color encoding on either top and bottom or left and right halves + P[0] = *ChunkPtr++; + P[1] = *ChunkPtr++; + + if (P[0] <= P[1]) + { + for (int y = 0; y < 16; y++) + { + // new values for each 4x4 block + if (!(y & 3)) + { + if (y) { + P[0] = *ChunkPtr++; + P[1] = *ChunkPtr++; + } + flags = LE_16(ChunkPtr); + ChunkPtr += 2; + } + + for (int x = 0; x < 4; x++, flags >>= 1) { + *pBuffer++ = P[flags & 1]; + } + + pBuffer += videoStride - 4; + // switch to right half + if (y == 7) pBuffer -= 8 * videoStride - 4; + } + } + else + { + flags = LE_32(ChunkPtr); + ChunkPtr += 4; + P[2] = *ChunkPtr++; + P[3] = *ChunkPtr++; + + if (P[2] <= P[3]) + { + // vertical split; left & right halves are 2-color encoded + for (int y = 0; y < 16; y++) + { + for (int x = 0; x < 4; x++, flags >>= 1) { + *pBuffer++ = P[flags & 1]; + } + + pBuffer += videoStride - 4; + + // switch to right half + if (y == 7) { + pBuffer -= 8 * videoStride - 4; + P[0] = P[2]; + P[1] = P[3]; + flags = LE_32(ChunkPtr); + ChunkPtr += 4; + } + } + } + else + { + // horizontal split; top & bottom halves are 2-color encoded + for (int y = 0; y < 8; y++) + { + if (y == 4) { + P[0] = P[2]; + P[1] = P[3]; + flags = LE_32(ChunkPtr); + ChunkPtr += 4; + } + + for (int x = 0; x < 8; x++, flags >>= 1) + *pBuffer++ = P[flags & 1]; + + pBuffer += (videoStride - 8); + } + } + } +} + +void InterplayDecoder::DecodeBlock9(int32_t offset) +{ + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t P[4]; + + memcpy(P, ChunkPtr, 4); + ChunkPtr += 4; + + // 4-color encoding + if (P[0] <= P[1]) + { + if (P[2] <= P[3]) + { + // 1 of 4 colors for each pixel, need 16 more bytes + for (int y = 0; y < 8; y++) + { + // get the next set of 8 2-bit flags + int flags = LE_16(ChunkPtr); + ChunkPtr += 2; + + for (int x = 0; x < 8; x++, flags >>= 2) { + *pBuffer++ = P[flags & 0x03]; + } + + pBuffer += (videoStride - 8); + } + } + else + { + // 1 of 4 colors for each 2x2 block, need 4 more bytes + uint32_t flags = LE_32(ChunkPtr); + ChunkPtr += 4; + + for (int y = 0; y < 8; y += 2) + { + for (int x = 0; x < 8; x += 2, flags >>= 2) + { + pBuffer[x] = + pBuffer[x + 1] = + pBuffer[x + videoStride] = + pBuffer[x + 1 + videoStride] = P[flags & 0x03]; + } + + pBuffer += videoStride * 2; + } + } + } + else + { + // 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes + uint64_t flags = LE_64(ChunkPtr); + ChunkPtr += 8; + + if (P[2] <= P[3]) + { + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x += 2, flags >>= 2) + { + pBuffer[x] = + pBuffer[x + 1] = P[flags & 0x03]; + } + pBuffer += videoStride; + } + } + else + { + for (int y = 0; y < 8; y += 2) + { + for (int x = 0; x < 8; x++, flags >>= 2) + { + pBuffer[x] = + pBuffer[x + videoStride] = P[flags & 0x03]; + } + pBuffer += videoStride * 2; + } + } + } +} + +void InterplayDecoder::DecodeBlock10(int32_t offset) +{ + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t P[8]; + + memcpy(P, ChunkPtr, 4); + ChunkPtr += 4; + + // 4-color encoding for each 4x4 quadrant, or 4-color encoding on either top and bottom or left and right halves + if (P[0] <= P[1]) + { + int flags = 0; + + // 4-color encoding for each quadrant; need 32 bytes + for (int y = 0; y < 16; y++) + { + // new values for each 4x4 block + if (!(y & 3)) { + if (y) { + memcpy(P, ChunkPtr, 4); + ChunkPtr += 4; + } + flags = LE_32(ChunkPtr); + ChunkPtr += 4; + } + + for (int x = 0; x < 4; x++, flags >>= 2) { + *pBuffer++ = P[flags & 0x03]; + } + + pBuffer += videoStride - 4; + // switch to right half + if (y == 7) pBuffer -= 8 * videoStride - 4; + } + } + else + { + // vertical split? + int vert; + uint64_t flags = LE_64(ChunkPtr); + ChunkPtr += 8; + + memcpy(P + 4, ChunkPtr, 4); + ChunkPtr += 4; + vert = P[4] <= P[5]; + + // 4-color encoding for either left and right or top and bottom halves + for (int y = 0; y < 16; y++) + { + for (int x = 0; x < 4; x++, flags >>= 2) + *pBuffer++ = P[flags & 0x03]; + + if (vert) + { + pBuffer += videoStride - 4; + // switch to right half + if (y == 7) pBuffer -= 8 * videoStride - 4; + } + else if (y & 1) pBuffer += (videoStride - 8); + + // load values for second half + if (y == 7) { + memcpy(P, P + 4, 4); + flags = LE_64(ChunkPtr); + ChunkPtr += 8; + } + } + } +} + +void InterplayDecoder::DecodeBlock11(int32_t offset) +{ + // 64-color encoding (each pixel in block is a different color) + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + + for (int y = 0; y < 8; y++) + { + memcpy(pBuffer, ChunkPtr, 8); + ChunkPtr += 8; + pBuffer += videoStride; + } +} + +void InterplayDecoder::DecodeBlock12(int32_t offset) +{ + // 16-color block encoding: each 2x2 block is a different color + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + + for (int y = 0; y < 8; y += 2) + { + for (int x = 0; x < 8; x += 2) + { + pBuffer[x] = + pBuffer[x + 1] = + pBuffer[x + videoStride] = + pBuffer[x + 1 + videoStride] = *ChunkPtr++; + } + pBuffer += videoStride * 2; + } +} + +void InterplayDecoder::DecodeBlock13(int32_t offset) +{ + // 4-color block encoding: each 4x4 block is a different color + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t P[2] = {}; + + for (int y = 0; y < 8; y++) + { + if (!(y & 3)) + { + P[0] = *ChunkPtr++; + P[1] = *ChunkPtr++; + } + + memset(pBuffer, P[0], 4); + memset(pBuffer + 4, P[1], 4); + pBuffer += videoStride; + } +} + +void InterplayDecoder::DecodeBlock14(int32_t offset) +{ + // 1-color encoding : the whole block is 1 solid color + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t pix = *ChunkPtr++; + + for (int y = 0; y < 8; y++) + { + memset(pBuffer, pix, 8); + pBuffer += videoStride; + } +} + +void InterplayDecoder::DecodeBlock15(int32_t offset) +{ + // dithered encoding + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t P[2]; + + P[0] = *ChunkPtr++; + P[1] = *ChunkPtr++; + + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x += 2) + { + *pBuffer++ = P[y & 1]; + *pBuffer++ = P[!(y & 1)]; + } + pBuffer += (videoStride - 8); + } +} + +uint8_t* InterplayDecoder::GetCurrentFrame() +{ + return pVideoBuffers[nCurrentVideoBuffer]; +} + +uint8_t* InterplayDecoder::GetPreviousFrame() +{ + return pVideoBuffers[nPreviousVideoBuffer]; +} diff --git a/src/common/cutscenes/playmve.h b/src/common/cutscenes/playmve.h new file mode 100644 index 00000000000..9cb299038c2 --- /dev/null +++ b/src/common/cutscenes/playmve.h @@ -0,0 +1,213 @@ +/* + * InterplayDecoder + * Copyright (C) 2020 sirlemonhead + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +/* This code is based on interplayvideo.c, dpcm.c and ipmovie.c from the FFmpeg project which can be obtained + * from http://www.ffmpeg.org/. Below is the license from interplayvideo.c + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Interplay MVE Video Decoder + * Copyright (C) 2003 The FFmpeg project + * + * This file is part of FFmpeg. + * + * FFmpeg 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include +#include +#include +#include + +#include "files.h" +#include "animtexture.h" +#include "s_music.h" + +#ifndef playmve_h_ +#define playmve_h_ + +class InterplayDecoder +{ +public: + enum + { + CHUNK_PREAMBLE_SIZE = 4, + OPCODE_PREAMBLE_SIZE = 4, + + CHUNK_INIT_AUDIO = 0x0000, + CHUNK_AUDIO_ONLY = 0x0001, + CHUNK_INIT_VIDEO = 0x0002, + CHUNK_VIDEO = 0x0003, + CHUNK_SHUTDOWN = 0x0004, + CHUNK_END = 0x0005, + /* these last types are used internally */ + CHUNK_DONE = 0xFFFC, + CHUNK_NOMEM = 0xFFFD, + CHUNK_EOF = 0xFFFE, + CHUNK_BAD = 0xFFFF, + + OPCODE_END_OF_STREAM = 0x00, + OPCODE_END_OF_CHUNK = 0x01, + OPCODE_CREATE_TIMER = 0x02, + OPCODE_INIT_AUDIO_BUFFERS = 0x03, + OPCODE_START_STOP_AUDIO = 0x04, + OPCODE_INIT_VIDEO_BUFFERS = 0x05, + OPCODE_UNKNOWN_06 = 0x06, + OPCODE_SEND_BUFFER = 0x07, + OPCODE_AUDIO_FRAME = 0x08, + OPCODE_SILENCE_FRAME = 0x09, + OPCODE_INIT_VIDEO_MODE = 0x0A, + OPCODE_CREATE_GRADIENT = 0x0B, + OPCODE_SET_PALETTE = 0x0C, + OPCODE_SET_PALETTE_COMPRESSED = 0x0D, + OPCODE_UNKNOWN_0E = 0x0E, + OPCODE_SET_DECODING_MAP = 0x0F, + OPCODE_UNKNOWN_10 = 0x10, + OPCODE_VIDEO_DATA = 0x11, + OPCODE_UNKNOWN_12 = 0x12, + OPCODE_UNKNOWN_13 = 0x13, + OPCODE_UNKNOWN_14 = 0x14, + OPCODE_UNKNOWN_15 = 0x15, + + PALETTE_COUNT = 256, + kAudioBlocks = 20 // alloc a lot of blocks - need to store lots of audio data before video frames start. + }; + + InterplayDecoder(bool soundenabled); + ~InterplayDecoder(); + + bool Open(FileReader &fr); + void Close(); + + bool RunFrame(uint64_t clock); + + bool FillSamples(void *buff, int len); + + bool HasAudio() const noexcept { return bAudioEnabled; } + int NumChannels() const noexcept { return audio.nChannels; } + int GetSampleRate() const noexcept { return audio.nSampleRate; } + void DisableAudio(); + + AnimTextures& animTex() { return animtex; } + +private: + struct AudioPacket + { + size_t nSize = 0; + std::unique_ptr pData; + }; + + struct VideoPacket + { + uint16_t nPalStart=0, nPalCount=0; + uint32_t nDecodeMapSize = 0; + uint32_t nVideoDataSize = 0; + bool bSendFlag = false; + std::unique_ptr pData; + }; + + struct AudioData + { + int nChannels = 0; + uint16_t nSampleRate = 0; + uint8_t nBitDepth = 0; + bool bCompressed = false; + + std::unique_ptr samples; + int nWrite = 0; + int nRead = 0; + + std::deque Packets; + }; + AudioData audio; + + struct DecodeMap + { + uint8_t* pData; + uint32_t nSize; + }; + + struct Palette + { + uint8_t r; + uint8_t g; + uint8_t b; + }; + + uint8_t* GetCurrentFrame(); + uint8_t* GetPreviousFrame(); + void SwapFrames(); + void CopyBlock(uint8_t* pDest, uint8_t* pSrc); + void DecodeBlock0(int32_t offset); + void DecodeBlock1(int32_t offset); + void DecodeBlock2(int32_t offset); + void DecodeBlock3(int32_t offset); + void DecodeBlock4(int32_t offset); + void DecodeBlock5(int32_t offset); + void DecodeBlock7(int32_t offset); + void DecodeBlock8(int32_t offset); + void DecodeBlock9(int32_t offset); + void DecodeBlock10(int32_t offset); + void DecodeBlock11(int32_t offset); + void DecodeBlock12(int32_t offset); + void DecodeBlock13(int32_t offset); + void DecodeBlock14(int32_t offset); + void DecodeBlock15(int32_t offset); + + std::mutex PacketMutex; + FileReader fr; + + bool bIsPlaying, bAudioEnabled; + + uint32_t nTimerRate, nTimerDiv; + uint32_t nWidth, nHeight, nFrame; + double nFps; + uint64_t nFrameDuration; + + std::vector ChunkData; + int ProcessNextChunk(); + + std::deque VideoPackets; + uint8_t* pVideoBuffers[2]; + uint32_t nCurrentVideoBuffer, nPreviousVideoBuffer; + int32_t videoStride; + + const uint8_t *ChunkPtr = nullptr; + DecodeMap decodeMap; + + AnimTextures animtex; + Palette palette[256]; + uint64_t nNextFrameTime = 0; +}; + +#endif diff --git a/src/common/cutscenes/screenjob.cpp b/src/common/cutscenes/screenjob.cpp new file mode 100644 index 00000000000..fa3752ba700 --- /dev/null +++ b/src/common/cutscenes/screenjob.cpp @@ -0,0 +1,405 @@ +/* +** screenjob.cpp +** +** Generic cutscene display +** +**--------------------------------------------------------------------------- +** Copyright 2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "types.h" +#include "screenjob.h" +#include "i_time.h" +#include "v_2ddrawer.h" +#include "animlib.h" +#include "v_draw.h" +#include "s_soundinternal.h" +#include "animtexture.h" +#include "gamestate.h" +#include "vm.h" +#include "c_bind.h" +#include "c_console.h" +#include "gamestate.h" +#include "printf.h" +#include "c_dispatch.h" +#include "s_music.h" +#include "m_argv.h" +#include "i_interface.h" + +CVAR(Bool, inter_subtitles, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); + +CutsceneState cutscene; +static int ticks; + +//============================================================================= +// +// +// +//============================================================================= + +void Job_Init() +{ + static bool done = false; + if (!done) + { + done = true; + GC::AddMarkerFunc([] { GC::Mark(cutscene.runner); }); + } + cutscene.runnerclass = PClass::FindClass("ScreenJobRunner"); + if (!cutscene.runnerclass) I_FatalError("ScreenJobRunner not defined"); + cutscene.runnerclasstype = NewPointer(cutscene.runnerclass); +} + +//============================================================================= +// +// +// +//============================================================================= + +VMFunction* LookupFunction(const char* qname, bool validate) +{ + size_t p = strcspn(qname, "."); + if (p == 0) + I_Error("Call to undefined function %s", qname); + FName clsname(qname, p, true); + FName funcname(qname + p + 1, true); + + auto func = PClass::FindFunction(clsname, funcname); + if (func == nullptr) + I_Error("Call to undefined function %s", qname); + if (validate) + { + // these conditions must be met by all functions for this interface. + if (func->Proto->ReturnTypes.Size() != 0) I_Error("Bad cutscene function %s. Return value not allowed", qname); + if (func->ImplicitArgs != 0) I_Error("Bad cutscene function %s. Must be static", qname); + } + return func; +} + +//============================================================================= +// +// +// +//============================================================================= + +void CallCreateFunction(const char* qname, DObject* runner) +{ + auto func = LookupFunction(qname); + if (func->Proto->ArgumentTypes.Size() != 1) I_Error("Bad cutscene function %s. Must receive precisely one argument.", qname); + if (func->Proto->ArgumentTypes[0] != cutscene.runnerclasstype) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner reference.", qname); + VMValue val = runner; + VMCall(func, &val, 1, nullptr, 0); +} + +//============================================================================= +// +// +// +//============================================================================= + +DObject* CreateRunner(bool clearbefore) +{ + auto obj = cutscene.runnerclass->CreateNew(); + auto func = LookupFunction("ScreenJobRunner.Init", false); + VMValue val[3] = { obj, clearbefore, false }; + VMCall(func, val, 3, nullptr, 0); + return obj; +} + +//============================================================================= +// +// +// +//============================================================================= + +void AddGenericVideo(DObject* runner, const FString& fn, int soundid, int fps) +{ + auto func = LookupFunction("ScreenJobRunner.AddGenericVideo", false); + VMValue val[] = { runner, &fn, soundid, fps }; + VMCall(func, val, 4, nullptr, 0); +} + +//============================================================================= +// +// +// +//============================================================================= + +int CutsceneDef::GetSound() +{ + FSoundID id = INVALID_SOUND; + if (soundName.IsNotEmpty()) id = soundEngine->FindSound(soundName.GetChars()); + if (id == INVALID_SOUND) id = soundEngine->FindSoundByResID(soundID); + return id.index(); +} + +void CutsceneDef::Create(DObject* runner) +{ + if (function.IsNotEmpty()) + { + CallCreateFunction(function.GetChars(), runner); + } + else if (video.IsNotEmpty()) + { + AddGenericVideo(runner, video, GetSound(), framespersec); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void DeleteScreenJob() +{ + if (cutscene.runner) cutscene.runner->Destroy(); + cutscene.runner = nullptr; +} + +void EndScreenJob() +{ + DeleteScreenJob(); + if (cutscene.completion) cutscene.completion(false); + cutscene.completion = nullptr; +} + + +//============================================================================= +// +// +// +//============================================================================= + +bool ScreenJobResponder(event_t* ev) +{ + if (ev->type == EV_KeyDown) + { + // We never reach the key binding checks in G_Responder, so for the console we have to check for ourselves here. + auto binding = Bindings.GetBinding(ev->data1); + if (binding.CompareNoCase("toggleconsole") == 0) + { + C_ToggleConsole(); + return true; + } + if (binding.CompareNoCase("screenshot") == 0) + { + C_DoCommand("screenshot"); + return true; + } + } + FInputEvent evt = ev; + if (cutscene.runner) + { + ScaleOverrider ovr(twod); + IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, OnEvent) + { + int result = 0; + VMValue parm[] = { cutscene.runner, &evt }; + VMReturn ret(&result); + VMCall(func, parm, 2, &ret, 1); + return result; + } + } + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +bool ScreenJobTick() +{ + ticks++; + if (cutscene.runner) + { + ScaleOverrider ovr(twod); + IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, OnTick) + { + int result = 0; + VMValue parm[] = { cutscene.runner }; + VMReturn ret(&result); + VMCall(func, parm, 1, &ret, 1); + return result; + } + } + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +void ScreenJobDraw() +{ + double smoothratio = I_GetTimeFrac(); + + if (cutscene.runner) + { + twod->ClearScreen(); + ScaleOverrider ovr(twod); + IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, RunFrame) + { + VMValue parm[] = { cutscene.runner, smoothratio }; + VMCall(func, parm, 2, nullptr, 0); + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + +bool ScreenJobValidate() +{ + if (cutscene.runner) + { + ScaleOverrider ovr(twod); + IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, Validate) + { + int res; + VMValue parm[] = { cutscene.runner }; + VMReturn ret(&res); + VMCall(func, parm, 1, &ret, 1); + I_ResetFrameTime(); + return res; + } + } + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion_) +{ + if ((cs.function.IsNotEmpty() || cs.video.IsNotEmpty()) && cs.function.CompareNoCase("none") != 0) + { + cutscene.completion = completion_; + cutscene.runner = CreateRunner(); + GC::WriteBarrier(cutscene.runner); + try + { + cs.Create(cutscene.runner); + if (!ScreenJobValidate()) + { + DeleteScreenJob(); + return false; + } + if (sysCallbacks.StartCutscene) sysCallbacks.StartCutscene(flags & SJ_BLOCKUI); + } + catch (...) + { + DeleteScreenJob(); + throw; + } + return true; + } + return false; +} + +bool StartCutscene(const char* s, int flags, const CompletionFunc& completion) +{ + CutsceneDef def; + def.function = s; + return StartCutscene(def, flags, completion); +} + +//============================================================================= +// +// initiates a screen wipe. Needs to call the game code for it. +// +//============================================================================= + +DEFINE_ACTION_FUNCTION(DScreenJobRunner, setTransition) +{ + PARAM_PROLOGUE; + PARAM_INT(type); + + if (type && sysCallbacks.SetTransition) sysCallbacks.SetTransition(type); + return 0; +} + +//============================================================================= +// +// to block wipes on cutscenes that cannot handle it +// +//============================================================================= + +bool CanWipe() +{ + if (cutscene.runner == nullptr) return true; + IFVM(ScreenJobRunner, CanWipe) + { + int can; + VMReturn ret(&can); + VMValue param = cutscene.runner; + VMCall(func, ¶m, 1, &ret, 1); + return can; + } + return true; +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD(testcutscene) +{ + if (argv.argc() < 2) + { + Printf("Usage: testcutscene \n"); + return; + } + try + { + if (StartCutscene(argv[1], 0, [](bool) {})) + { + C_HideConsole(); + } + } + catch (const CRecoverableError& err) + { + Printf(TEXTCOLOR_RED "Unable to play cutscene: %s\n", err.what()); + } +} + + + diff --git a/src/common/cutscenes/screenjob.h b/src/common/cutscenes/screenjob.h new file mode 100644 index 00000000000..dce55e3b00f --- /dev/null +++ b/src/common/cutscenes/screenjob.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include "dobject.h" +#include "v_2ddrawer.h" +#include "d_eventbase.h" +#include "s_soundinternal.h" +#include "gamestate.h" +#include "zstring.h" +#include "c_cvars.h" + +EXTERN_CVAR(Bool, inter_subtitles) + +using CompletionFunc = std::function; + +void Job_Init(); + +enum +{ + SJ_BLOCKUI = 1, +}; + +struct CutsceneDef +{ + FString video; + FString function; + FString soundName; + int soundID = -1; // ResID not SoundID! + int framespersec = 0; // only relevant for ANM. + bool transitiononly = false; // only play when transitioning between maps, but not when starting on a map or ending a game. + + void Create(DObject* runner); + bool isdefined() { return video.IsNotEmpty() || function.IsNotEmpty(); } + int GetSound(); +}; + +void EndScreenJob(); +void DeleteScreenJob(); +bool ScreenJobResponder(event_t* ev); +bool ScreenJobTick(); +void ScreenJobDraw(); +bool ScreenJobValidate(); + +struct CutsceneDef; +bool StartCutscene(const char* s, int flags, const CompletionFunc& completion); +bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion_); +bool CanWipe(); + +VMFunction* LookupFunction(const char* qname, bool validate = true); +void CallCreateFunction(const char* qname, DObject* runner); +DObject* CreateRunner(bool clearbefore = true); +void AddGenericVideo(DObject* runner, const FString& fn, int soundid, int fps); + +struct CutsceneState +{ + DObject* runner; + PClass* runnerclass; + PType* runnerclasstype; + CompletionFunc completion; +}; + +extern CutsceneState cutscene; diff --git a/src/r_data/cycler.cpp b/src/common/engine/cycler.cpp similarity index 99% rename from src/r_data/cycler.cpp rename to src/common/engine/cycler.cpp index 1d0d28486b3..1dbf1fce024 100644 --- a/src/r_data/cycler.cpp +++ b/src/common/engine/cycler.cpp @@ -97,20 +97,20 @@ void FCycler::Update(double diff) { double mult, angle; double step = m_end - m_start; - + if (!m_shouldCycle) { return; } - + m_time += diff; if (m_time >= m_cycle) { m_time = m_cycle; } - + mult = m_time / m_cycle; - + switch (m_cycleType) { case CYCLE_Linear: @@ -149,7 +149,7 @@ void FCycler::Update(double diff) } break; } - + if (m_time == m_cycle) { m_time = 0.; diff --git a/src/r_data/cycler.h b/src/common/engine/cycler.h similarity index 99% rename from src/r_data/cycler.h rename to src/common/engine/cycler.h index 0b49e644d8a..a2789f9cab2 100644 --- a/src/r_data/cycler.h +++ b/src/common/engine/cycler.h @@ -23,7 +23,7 @@ class FCycler FCycler() = default; FCycler(const FCycler &other) = default; FCycler &operator=(const FCycler &other) = default; - + void Update(double diff); void SetParams(double start, double end, double cycle, bool update = false); void ShouldCycle(bool sc) { m_shouldCycle = sc; } diff --git a/src/common/engine/d_event.cpp b/src/common/engine/d_event.cpp new file mode 100644 index 00000000000..ce11d3b1e42 --- /dev/null +++ b/src/common/engine/d_event.cpp @@ -0,0 +1,269 @@ +/* +** c_dispatch.cpp +** Functions for executing console commands and aliases +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2003-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_bind.h" +#include "d_eventbase.h" +#include "c_console.h" +#include "d_gui.h" +#include "menu.h" +#include "utf8.h" +#include "m_joy.h" +#include "vm.h" +#include "gamestate.h" +#include "i_interface.h" + +int eventhead; +int eventtail; +event_t events[MAXEVENTS]; + +CVAR(Float, m_sensitivity_x, 2.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Float, m_sensitivity_y, 2.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, invertmouse, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE); // Invert mouse look down/up? +CVAR(Bool, invertmousex, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE); // Invert mouse look left/right? + + +//========================================================================== +// +// D_ProcessEvents +// +// Send all the events of the given timestamp down the responder chain. +// Events are asynchronous inputs generally generated by the game user. +// Events can be discarded if no responder claims them +// +//========================================================================== + +void D_ProcessEvents (void) +{ + FixedBitArray keywasdown; + TArray delayedevents; + + keywasdown.Zero(); + while (eventtail != eventhead) + { + event_t *ev = &events[eventtail]; + eventtail = (eventtail + 1) & (MAXEVENTS - 1); + + if (ev->type == EV_KeyUp && keywasdown[ev->data1]) + { + delayedevents.Push(ev); + continue; + } + + if (ev->type == EV_None) + continue; + if (ev->type == EV_DeviceChange) + UpdateJoystickMenu(I_UpdateDeviceList()); + + // allow the game to intercept Escape before dispatching it. + if (ev->type != EV_KeyDown || ev->data1 != KEY_ESCAPE || !sysCallbacks.WantEscape || !sysCallbacks.WantEscape()) + { + if (gamestate != GS_INTRO) // GS_INTRO blocks the UI. + { + if (C_Responder(ev)) + continue; // console ate the event + if (M_Responder(ev)) + continue; // menu ate the event + } + } + + if (sysCallbacks.G_Responder(ev) && ev->type == EV_KeyDown) keywasdown.Set(ev->data1); + } + + for (auto ev: delayedevents) + { + D_PostEvent(ev); + } +} + +//========================================================================== +// +// D_RemoveNextCharEvent +// +// Removes the next EV_GUI_Char event in the input queue. Used by the menu, +// since it (generally) consumes EV_GUI_KeyDown events and not EV_GUI_Char +// events, and it needs to ensure that there is no left over input when it's +// done. If there are multiple EV_GUI_KeyDowns before the EV_GUI_Char, then +// there are dead chars involved, so those should be removed, too. We do +// this by changing the message type to EV_None rather than by actually +// removing the event from the queue. +// +//========================================================================== + +void D_RemoveNextCharEvent() +{ + assert(events[eventtail].type == EV_GUI_Event && events[eventtail].subtype == EV_GUI_KeyDown); + for (int evnum = eventtail; evnum != eventhead; evnum = (evnum+1) & (MAXEVENTS-1)) + { + event_t *ev = &events[evnum]; + if (ev->type != EV_GUI_Event) + break; + if (ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_Char) + { + ev->type = EV_None; + if (ev->subtype == EV_GUI_Char) + break; + } + else + { + break; + } + } +} + + +//========================================================================== +// +// D_PostEvent +// +// Called by the I/O functions when input is detected. +// +//========================================================================== + +void D_PostEvent(event_t* ev) +{ + // Do not post duplicate consecutive EV_DeviceChange events. + if (ev->type == EV_DeviceChange && events[eventhead].type == EV_DeviceChange) + { + return; + } + if (sysCallbacks.DispatchEvent && sysCallbacks.DispatchEvent(ev)) + return; + + events[eventhead] = *ev; + eventhead = (eventhead + 1) & (MAXEVENTS - 1); +} + + +void PostMouseMove(int xx, int yy) +{ + event_t ev{}; + + ev.x = float(xx) * m_sensitivity_x; + ev.y = -float(yy) * m_sensitivity_y; + + if (invertmousex) ev.x = -ev.x; + if (invertmouse) ev.y = -ev.y; + + if (ev.x || ev.y) + { + ev.type = EV_Mouse; + D_PostEvent(&ev); + } +} + + +FInputEvent::FInputEvent(const event_t *ev) +{ + Type = (EGenericEvent)ev->type; + // we don't want the modders to remember what weird fields mean what for what events. + KeyScan = 0; + KeyChar = 0; + MouseX = 0; + MouseY = 0; + switch (Type) + { + case EV_None: + break; + case EV_KeyDown: + case EV_KeyUp: + KeyScan = ev->data1; + KeyChar = ev->data2; + KeyString = FString(char(ev->data1)); + break; + case EV_Mouse: + MouseX = int(ev->x); + MouseY = int(ev->y); + break; + default: + break; // EV_DeviceChange = wat? + } +} + +FUiEvent::FUiEvent(const event_t *ev) +{ + Type = (EGUIEvent)ev->subtype; + KeyChar = 0; + IsShift = false; + IsAlt = false; + IsCtrl = false; + MouseX = 0; + MouseY = 0; + // we don't want the modders to remember what weird fields mean what for what events. + switch (ev->subtype) + { + case EV_GUI_None: + break; + case EV_GUI_KeyDown: + case EV_GUI_KeyRepeat: + case EV_GUI_KeyUp: + KeyChar = ev->data1; + KeyString = FString(char(ev->data1)); + IsShift = !!(ev->data3 & GKM_SHIFT); + IsAlt = !!(ev->data3 & GKM_ALT); + IsCtrl = !!(ev->data3 & GKM_CTRL); + break; + case EV_GUI_Char: + KeyChar = ev->data1; + KeyString = MakeUTF8(ev->data1); + IsAlt = !!ev->data2; // only true for Win32, not sure about SDL + break; + default: // mouse event + // note: SDL input doesn't seem to provide these at all + //Printf("Mouse data: %d, %d, %d, %d\n", ev->x, ev->y, ev->data1, ev->data2); + MouseX = ev->data1; + MouseY = ev->data2; + IsShift = !!(ev->data3 & GKM_SHIFT); + IsAlt = !!(ev->data3 & GKM_ALT); + IsCtrl = !!(ev->data3 & GKM_CTRL); + break; + } +} + +DEFINE_FIELD_X(UiEvent, FUiEvent, Type); +DEFINE_FIELD_X(UiEvent, FUiEvent, KeyString); +DEFINE_FIELD_X(UiEvent, FUiEvent, KeyChar); +DEFINE_FIELD_X(UiEvent, FUiEvent, MouseX); +DEFINE_FIELD_X(UiEvent, FUiEvent, MouseY); +DEFINE_FIELD_X(UiEvent, FUiEvent, IsShift); +DEFINE_FIELD_X(UiEvent, FUiEvent, IsAlt); +DEFINE_FIELD_X(UiEvent, FUiEvent, IsCtrl); + +DEFINE_FIELD_X(InputEvent, FInputEvent, Type); +DEFINE_FIELD_X(InputEvent, FInputEvent, KeyScan); +DEFINE_FIELD_X(InputEvent, FInputEvent, KeyString); +DEFINE_FIELD_X(InputEvent, FInputEvent, KeyChar); +DEFINE_FIELD_X(InputEvent, FInputEvent, MouseX); +DEFINE_FIELD_X(InputEvent, FInputEvent, MouseY); + diff --git a/src/common/engine/d_eventbase.h b/src/common/engine/d_eventbase.h new file mode 100644 index 00000000000..992a5f400ca --- /dev/null +++ b/src/common/engine/d_eventbase.h @@ -0,0 +1,78 @@ +#pragma once +#include +#include "d_gui.h" +#include "zstring.h" + +// Input event types. +enum EGenericEvent +{ + EV_None, + EV_KeyDown, // data1: scan code, data2: Qwerty ASCII code + EV_KeyUp, // same + EV_Mouse, // x, y: mouse movement deltas + EV_GUI_Event, // subtype specifies actual event + EV_DeviceChange,// a device has been connected or removed +}; + +// Event structure. +struct event_t +{ + uint8_t type; + uint8_t subtype; + int16_t data1; // keys / mouse/joystick buttons + int16_t data2; + int16_t data3; + float x; // mouse/joystick x move + float y; // mouse/joystick y move +}; + + + +// Called by IO functions when input is detected. +void D_PostEvent (event_t* ev); +void D_RemoveNextCharEvent(); +void D_ProcessEvents(void); +void PostMouseMove(int x, int y); + +enum +{ + MAXEVENTS = 128 +}; + +extern event_t events[MAXEVENTS]; +extern int eventhead; +extern int eventtail; + +struct FUiEvent +{ + // this essentially translates event_t UI events to ZScript. + EGUIEvent Type; + // for keys/chars/whatever + FString KeyString; + int KeyChar; + // for mouse + int MouseX; + int MouseY; + // global (?) + bool IsShift; + bool IsCtrl; + bool IsAlt; + + FUiEvent(const event_t *ev); +}; + +struct FInputEvent +{ + // this translates regular event_t events to ZScript (not UI, UI events are sent via DUiEvent and only if requested!) + EGenericEvent Type = EV_None; + // for keys + int KeyScan; + FString KeyString; + int KeyChar; + // for mouse + int MouseX; + int MouseY; + + FInputEvent(const event_t *ev); +}; + diff --git a/src/d_gui.h b/src/common/engine/d_gui.h similarity index 100% rename from src/d_gui.h rename to src/common/engine/d_gui.h diff --git a/src/common/engine/date.cpp b/src/common/engine/date.cpp new file mode 100644 index 00000000000..63e3776b7b5 --- /dev/null +++ b/src/common/engine/date.cpp @@ -0,0 +1,248 @@ +/* +** date.cpp +** +** VM exports for engine backend classes +** +**--------------------------------------------------------------------------- +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include "c_dispatch.h" +#include "vm.h" +#include "zstring.h" +#include "printf.h" + +time_t epochoffset = 0; // epoch start in seconds (0 = January 1st, 1970) + + +//========================================================================== +// +// CCMD setdate +// +// Set the time to a specific value +// +//========================================================================== + +UNSAFE_CCMD(setdate) +{ + if (argv.argc() != 3) + { + Printf("setdate HH:MM:SS DD-MM-YYYY: Set the current date\n"); + return; + } + + time_t today; + time(&today); + struct tm* timeinfo = localtime(&today); + if (timeinfo != nullptr) + { + auto clock = FString(argv[1]).Split(":"); + auto date = FString(argv[2]).Split("-"); + if(clock.Size() != 3 || date.Size() != 3) + { + Printf("setdate HH:MM:SS DD-MM-YYYY: Set the current date\n"); + return; + } + + if(!clock[0].IsInt()) + { + Printf("Invalid hour\n"); + return; + } + if (!clock[1].IsInt()) + { + Printf("Invalid minutes\n"); + return; + } + if (!clock[2].IsInt()) + { + Printf("Invalid seconds\n"); + return; + } + if (!date[0].IsInt()) + { + Printf("Invalid day\n"); + return; + } + if (!date[1].IsInt()) + { + Printf("Invalid month\n"); + return; + } + if (!date[2].IsInt()) + { + Printf("Invalid year\n"); + return; + } + + //Set Date + timeinfo->tm_hour = int( clock[0].ToLong() ); + timeinfo->tm_min = int( clock[1].ToLong() ); + timeinfo->tm_sec = int( clock[2].ToLong() ); + timeinfo->tm_mday = int( date[0].ToLong() ); + timeinfo->tm_mon = int( date[1].ToLong() - 1); // Month interally is 0 - 11 + timeinfo->tm_year = int( date[2].ToLong() - 1900 ); // Year interally is 00 - 138 + + time_t newTime = mktime(timeinfo); + tm* t_old = localtime(&today); + time_t oldTime = mktime(t_old); + + if (newTime == -1 || oldTime == -1) + { + Printf("Unable to set the date\n"); + return; + } + + epochoffset = newTime - oldTime; + + // This deals with some inconsistent display behaviour for DST + // In this case, we want to emulate GCC's behaviour + today += epochoffset; + struct tm* t_new = localtime(&today); + if (t_new != nullptr) + { + char timeString[1024]; + if (strftime(timeString, sizeof(timeString), "%H", t_new)) + { + auto hour = FString(timeString).ToLong(); + if (hour - clock[0].ToLong() == -1 || hour - clock[0].ToLong() == 23) + epochoffset += 3600; + else if (hour - clock[0].ToLong() == 1 || hour - clock[0].ToLong() == -23) + epochoffset -= 3600; + } + } + + return; + } + else + { + Printf("Unable to set the date\n"); + return; + } +} + +CCMD(getdate) +{ + time_t now; + time(&now); + now += epochoffset; + struct tm* timeinfo = localtime(&now); + if (timeinfo != nullptr) + { + char timeString[1024]; + if (strftime(timeString, sizeof(timeString), "%H:%M:%S %d-%m-%Y%n", timeinfo)) + Printf("%s\n", timeString); + else + Printf("Error Retrieving Current Date\n"); + } + else + { + Printf("Error Retrieving Current Date\n"); + } +} + +//===================================================================================== +// +// +// +//===================================================================================== + +extern time_t epochoffset; + +static int GetEpochTime() +{ + time_t now; + time(&now); + return now != (time_t)(-1) ? int(now + epochoffset) : -1; +} + +//Returns an empty string if the Strf tokens are valid, otherwise returns the problematic token +static FString CheckStrfString(FString timeForm) +{ + // Valid Characters after % + const char validSingles[] = { 'a','A','b','B','c','C','d','D','e','F','g','G','h','H','I','j','m','M','n','p','r','R','S','t','T','u','U','V','w','W','x','X','y','Y','z','Z' }; + + timeForm.Substitute("%%", "%a"); //Prevent %% from causing tokenizing problems + timeForm = "a" + timeForm; //Prevent %* at the beginning from causing a false error from tokenizing + + auto tokens = timeForm.Split("%"); + for (auto t : tokens) + { + bool found = false; + // % at end + if (t.Len() == 0) return FString("%"); + + // Single Character + for (size_t i = 0; i < sizeof(validSingles) / sizeof(validSingles[0]); i++) + { + if (t[0] == validSingles[i]) + { + found = true; + break; + } + } + if (found) continue; + return FString("%") + t[0]; + } + return ""; +} + +static void FormatTime(const FString& timeForm, int timeVal, FString* result) +{ + FString error = CheckStrfString(timeForm); + if (!error.IsEmpty()) + ThrowAbortException(X_FORMAT_ERROR, "'%s' is not a valid format specifier of SystemTime.Format()", error.GetChars()); + + time_t val = timeVal; + struct tm* timeinfo = localtime(&val); + if (timeinfo != nullptr) + { + char timeString[1024]; + if (strftime(timeString, sizeof(timeString), timeForm.GetChars(), timeinfo)) + *result = timeString; + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(_SystemTime, Now, GetEpochTime) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(GetEpochTime()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_SystemTime, Format, FormatTime) +{ + PARAM_PROLOGUE; + PARAM_STRING(timeForm); + PARAM_INT(timeVal); + FString result; + FormatTime(timeForm, timeVal, &result); + ACTION_RETURN_STRING(result); +} + + diff --git a/src/common/engine/fcolormap.h b/src/common/engine/fcolormap.h new file mode 100644 index 00000000000..ffb0c136e2d --- /dev/null +++ b/src/common/engine/fcolormap.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include "palentry.h" + +// for internal use +struct FColormap +{ + PalEntry LightColor; // a is saturation (0 full, 31=b/w, other=custom colormap) + PalEntry FadeColor; // a is fadedensity>>1 + uint8_t Desaturation; + uint8_t BlendFactor; // This is for handling Legacy-style colormaps which use a different formula to calculate how the color affects lighting. + uint16_t FogDensity; + + void Clear() + { + LightColor = 0xffffff; + FadeColor = 0; + Desaturation = 0; + BlendFactor = 0; + FogDensity = 0; + } + + void MakeWhite() + { + LightColor = 0xffffff; + } + + void ClearColor() + { + LightColor = 0xffffff; + BlendFactor = 0; + Desaturation = 0; + } + + void CopyLight(FColormap &from) + { + LightColor = from.LightColor; + Desaturation = from.Desaturation; + BlendFactor = from.BlendFactor; + } + + void CopyFog(FColormap &from) + { + FadeColor = from.FadeColor; + FogDensity = from.FogDensity; + } + + void Decolorize() + { + LightColor.Decolorize(); + } + + bool operator == (const FColormap &other) + { + return LightColor == other.LightColor && FadeColor == other.FadeColor && Desaturation == other.Desaturation && + BlendFactor == other.BlendFactor && FogDensity == other.FogDensity; + } + + bool operator != (const FColormap &other) + { + return !operator==(other); + } + +}; + + diff --git a/src/common/engine/files.h b/src/common/engine/files.h new file mode 100644 index 00000000000..af6694cf058 --- /dev/null +++ b/src/common/engine/files.h @@ -0,0 +1,6 @@ +#pragma once +#include "fs_files.h" + +using FileSys::FileReader; +using FileSys::FileWriter; +using FileSys::BufferWriter; \ No newline at end of file diff --git a/src/common/engine/filesystem.h b/src/common/engine/filesystem.h new file mode 100644 index 00000000000..53f4916771a --- /dev/null +++ b/src/common/engine/filesystem.h @@ -0,0 +1,7 @@ +#pragma once +#include "fs_filesystem.h" + +using FileSys::FileSystem; +using FileSys::FResourceFile; + +inline FileSys::FileSystem fileSystem; diff --git a/src/g_input.h b/src/common/engine/g_input.h similarity index 95% rename from src/g_input.h rename to src/common/engine/g_input.h index 1a998014bd2..cc78d02ff38 100644 --- a/src/g_input.h +++ b/src/common/engine/g_input.h @@ -6,4 +6,4 @@ void I_PutInClipboard (const char *str); FString I_GetFromClipboard (bool use_primary_selection); void I_SetMouseCapture(); void I_ReleaseMouseCapture(); - +void I_GetEvent(); \ No newline at end of file diff --git a/src/common/engine/gamestate.h b/src/common/engine/gamestate.h new file mode 100644 index 00000000000..5f674a33b9d --- /dev/null +++ b/src/common/engine/gamestate.h @@ -0,0 +1,28 @@ +#pragma once + +// The current state of the game: whether we are +// playing, gazing at the intermission screen, +// the game final animation, or a demo. +enum gamestate_t : int +{ + GS_LEVEL, + GS_INTERMISSION, + GS_FINALE, + GS_DEMOSCREEN, + GS_FULLCONSOLE, // [RH] Fullscreen console + GS_HIDECONSOLE, // [RH] The menu just did something that should hide fs console + GS_STARTUP, // [RH] Console is fullscreen, and game is just starting + GS_TITLELEVEL, // [RH] A combination of GS_LEVEL and GS_DEMOSCREEN + GS_INTRO, + GS_CUTSCENE, + + GS_MENUSCREEN = GS_DEMOSCREEN, + + GS_FORCEWIPE = -1, + GS_FORCEWIPEFADE = -2, + GS_FORCEWIPEBURN = -3, + GS_FORCEWIPEMELT = -4 +}; + + +extern gamestate_t gamestate; diff --git a/src/gamedata/gstrings.h b/src/common/engine/gstrings.h similarity index 100% rename from src/gamedata/gstrings.h rename to src/common/engine/gstrings.h diff --git a/src/common/engine/i_interface.cpp b/src/common/engine/i_interface.cpp new file mode 100644 index 00000000000..dfedbe8eecd --- /dev/null +++ b/src/common/engine/i_interface.cpp @@ -0,0 +1,45 @@ +#include "i_interface.h" +#include "st_start.h" +#include "gamestate.h" +#include "startupinfo.h" +#include "c_cvars.h" +#include "gstrings.h" +#include "version.h" + +static_assert(sizeof(void*) == 8, + "Only LP64/LLP64 builds are officially supported. " + "Please do not attempt to build for other platforms; " + "even if the program succeeds in a MAP01 smoke test, " + "there are e.g. known visual artifacts " + " " + "that lead to a bad user experience."); + +// Some global engine variables taken out of the backend code. +FStartupScreen* StartWindow; +SystemCallbacks sysCallbacks; +FString endoomName; +bool batchrun; +float menuBlurAmount; + +bool AppActive = true; +int chatmodeon; +gamestate_t gamestate = GS_STARTUP; +bool ToggleFullscreen; +int paused; +bool pauseext; + +FStartupInfo GameStartupInfo; + +CVAR(Bool, queryiwad, QUERYIWADDEFAULT, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(String, defaultiwad, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, vid_fps, false, 0) + +EXTERN_CVAR(Bool, ui_generic) + +CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) +{ + GStrings.UpdateLanguage(self); + UpdateGenericUI(ui_generic); + if (sysCallbacks.LanguageChanged) sysCallbacks.LanguageChanged(self); +} + diff --git a/src/common/engine/i_interface.h b/src/common/engine/i_interface.h new file mode 100644 index 00000000000..4289bfeab77 --- /dev/null +++ b/src/common/engine/i_interface.h @@ -0,0 +1,70 @@ +#pragma once + +#include "zstring.h" +#include "intrect.h" +#include "name.h" + +struct event_t; +class FRenderState; +class FGameTexture; +class FTextureID; +enum EUpscaleFlags : int; +class FConfigFile; +struct FTranslationID; + +struct SystemCallbacks +{ + bool (*G_Responder)(event_t* ev); // this MUST be set, otherwise nothing will work + bool (*WantGuiCapture)(); + bool (*WantLeftButton)(); + bool (*NetGame)(); + bool (*WantNativeMouse)(); + bool (*CaptureModeInGame)(); + void (*CrashInfo)(char* buffer, size_t bufflen, const char* lfstr); + void (*PlayStartupSound)(const char* name); + bool (*IsSpecialUI)(); + bool (*DisableTextureFilter)(); + void (*OnScreenSizeChanged)(); + IntRect(*GetSceneRect)(); + FString(*GetLocationDescription)(); + void (*MenuDim)(); + FString(*GetPlayerName)(int i); + bool (*DispatchEvent)(event_t* ev); + bool (*CheckGame)(const char* nm); + void (*MenuClosed)(); + bool (*CheckMenudefOption)(const char* opt); + void (*ConsoleToggled)(int state); + bool (*PreBindTexture)(FRenderState* state, FGameTexture*& tex, EUpscaleFlags& flags, int& scaleflags, int& clampmode, int& translation, int& overrideshader); + void (*FontCharCreated)(FGameTexture* base, FGameTexture* untranslated); + void (*ToggleFullConsole)(); + void (*StartCutscene)(bool blockui); + void (*SetTransition)(int type); + bool (*CheckCheatmode)(bool printmsg, bool sponly); + void (*HudScaleChanged)(); + bool (*SetSpecialMenu)(FName& menu, int param); + void (*OnMenuOpen)(bool makesound); + void (*LanguageChanged)(const char*); + bool (*OkForLocalization)(FTextureID, const char*); + FConfigFile* (*GetConfig)(); + bool (*WantEscape)(); + FTranslationID(*RemapTranslation)(FTranslationID trans); +}; + +extern SystemCallbacks sysCallbacks; + +struct WadStuff +{ + FString Path; + FString Name; +}; + + +extern FString endoomName; +extern bool batchrun; +extern float menuBlurAmount; +extern bool generic_ui; +extern bool special_i; +extern int paused; +extern bool pauseext; + +void UpdateGenericUI(bool cvar); diff --git a/src/i_net.cpp b/src/common/engine/i_net.cpp similarity index 87% rename from src/i_net.cpp rename to src/common/engine/i_net.cpp index d6284abed93..33b4c126711 100644 --- a/src/i_net.cpp +++ b/src/common/engine/i_net.cpp @@ -1,11 +1,13 @@ +// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit +// $Id: i_net.c,v 1.2 1997/12/29 19:50:54 pekangas Exp $ +// +// Copyright (C) 1993-1996 by id Software, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -16,7 +18,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see http://www.gnu.org/licenses/ // -//----------------------------------------------------------------------------- +// +// +// Alternatively the following applies: +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// // // DESCRIPTION: // Low-level networking code. Uses BSD sockets for UDP networking. @@ -53,16 +67,15 @@ # endif #endif -#include "doomtype.h" #include "i_system.h" -#include "d_net.h" #include "m_argv.h" #include "m_crc32.h" -#include "d_player.h" #include "st_start.h" -#include "m_misc.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "cmdlib.h" +#include "printf.h" +#include "i_interface.h" + #include "i_net.h" @@ -91,6 +104,10 @@ typedef int SOCKET; typedef int socklen_t; #endif +bool netgame, multiplayer; +int consoleplayer; // i.e. myconnectindex in Build. +doomcom_t doomcom; + // // NETWORKING // @@ -143,13 +160,19 @@ struct PreGamePacket uint8_t TransmitBuffer[TRANSMIT_SIZE]; +FString GetPlayerName(int num) +{ + if (sysCallbacks.GetPlayerName) return sysCallbacks.GetPlayerName(sendplayer[num]); + else return FStringf("Player %d", sendplayer[num] + 1); +} + // // UDPsocket // SOCKET UDPsocket (void) { SOCKET s; - + // allocate a socket s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) @@ -170,7 +193,7 @@ void BindToLocalPort (SOCKET s, u_short port) address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(port); - + v = bind (s, (sockaddr *)&address, sizeof(address)); if (v == SOCKET_ERROR) I_FatalError ("BindToPort: %s", neterror ()); @@ -269,15 +292,15 @@ void PacketGet (void) if (err == WSAECONNRESET) { // The remote node aborted unexpectedly, so pretend it sent an exit packet - if (StartScreen != NULL) + if (StartWindow != NULL) { - StartScreen->NetMessage ("The connection from %s was dropped.\n", - players[sendplayer[node]].userinfo.GetName()); + I_NetMessage ("The connection from %s was dropped.\n", + GetPlayerName(node).GetChars()); } else { Printf("The connection from %s was dropped.\n", - players[sendplayer[node]].userinfo.GetName()); + GetPlayerName(node).GetChars()); } doomcom.data[0] = 0x80; // NCMD_EXIT @@ -396,12 +419,12 @@ void BuildAddress (sockaddr_in *address, const char *name) if (!isnamed) { - address->sin_addr.s_addr = inet_addr (target); + address->sin_addr.s_addr = inet_addr (target.GetChars()); Printf ("Node number %d, address %s\n", doomcom.numnodes, target.GetChars()); } else { - hostentry = gethostbyname (target); + hostentry = gethostbyname (target.GetChars()); if (!hostentry) I_FatalError ("gethostbyname: couldn't find %s\n%s", target.GetChars(), neterror()); address->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; @@ -436,7 +459,7 @@ void StartNetwork (bool autoPort) netgame = true; multiplayer = true; - + // create communication socket mysocket = UDPsocket (); BindToLocalPort (mysocket, autoPort ? 0 : DOOMPORT); @@ -488,7 +511,7 @@ static void SendConAck (int num_connected, int num_needed) { PreSend (&packet, 4, &sendaddress[node]); } - StartScreen->NetProgress (doomcom.numnodes); + I_NetProgress (doomcom.numnodes); } bool Host_CheckForConnects (void *userdata) @@ -513,7 +536,7 @@ bool Host_CheckForConnects (void *userdata) if (node == -1) { const uint8_t *s_addr_bytes = (const uint8_t *)&from->sin_addr; - StartScreen->NetMessage ("Got extra connect from %d.%d.%d.%d:%d", + I_NetMessage ("Got extra connect from %d.%d.%d.%d:%d", s_addr_bytes[0], s_addr_bytes[1], s_addr_bytes[2], s_addr_bytes[3], from->sin_port); packet.Message = PRE_ALLFULL; @@ -526,7 +549,7 @@ bool Host_CheckForConnects (void *userdata) { node = doomcom.numnodes++; sendaddress[node] = *from; - StartScreen->NetMessage ("Got connect from node %d.", node); + I_NetMessage ("Got connect from node %d.", node); } // Let the new guest (and everyone else) know we got their message. @@ -538,7 +561,7 @@ bool Host_CheckForConnects (void *userdata) node = FindNode (from); if (node >= 0) { - StartScreen->NetMessage ("Got disconnect from node %d.", node); + I_NetMessage ("Got disconnect from node %d.", node); doomcom.numnodes--; while (node < doomcom.numnodes) { @@ -685,10 +708,10 @@ bool HostGame (int i) doomcom.numnodes = 1; - StartScreen->NetInit ("Waiting for players", numplayers); + I_NetInit ("Waiting for players", numplayers); // Wait for numplayers-1 different connections - if (!StartScreen->NetLoop (Host_CheckForConnects, (void *)(intptr_t)numplayers)) + if (!I_NetLoop (Host_CheckForConnects, (void *)(intptr_t)numplayers)) { SendAbort(); return false; @@ -696,30 +719,30 @@ bool HostGame (int i) // Now inform everyone of all machines involved in the game memset (gotack, 0, sizeof(gotack)); - StartScreen->NetMessage ("Sending all here."); - StartScreen->NetInit ("Done waiting", 1); + I_NetMessage ("Sending all here."); + I_NetInit ("Done waiting", 1); - if (!StartScreen->NetLoop (Host_SendAllHere, (void *)gotack)) + if (!I_NetLoop (Host_SendAllHere, (void *)gotack)) { SendAbort(); return false; } // Now go - StartScreen->NetMessage ("Go"); + I_NetMessage ("Go"); packet.Fake = PRE_FAKE; packet.Message = PRE_GO; for (node = 1; node < doomcom.numnodes; node++) { // If we send the packets eight times to each guest, // hopefully at least one of them will get through. - for (int i = 8; i != 0; --i) + for (int ii = 8; ii != 0; --ii) { PreSend (&packet, 2, &sendaddress[node]); } } - StartScreen->NetMessage ("Total players: %d", doomcom.numnodes); + I_NetMessage ("Total players: %d", doomcom.numnodes); doomcom.id = DOOMCOM_ID; doomcom.numplayers = doomcom.numnodes; @@ -753,9 +776,9 @@ bool Guest_ContactHost (void *userdata) { if (packet.Message == PRE_CONACK) { - StartScreen->NetMessage ("Total players: %d", packet.NumNodes); - StartScreen->NetInit ("Waiting for other players", packet.NumNodes); - StartScreen->NetProgress (packet.NumPresent); + I_NetMessage ("Total players: %d", packet.NumNodes); + I_NetInit ("Waiting for other players", packet.NumNodes); + I_NetProgress (packet.NumPresent); return true; } else if (packet.Message == PRE_DISCONNECT) @@ -772,7 +795,7 @@ bool Guest_ContactHost (void *userdata) } // In case the progress bar could not be marqueed, bump it. - StartScreen->NetProgress (0); + I_NetProgress (0); return false; } @@ -791,7 +814,7 @@ bool Guest_WaitForOthers (void *userdata) switch (packet.Message) { case PRE_CONACK: - StartScreen->NetProgress (packet.NumPresent); + I_NetProgress (packet.NumPresent); break; case PRE_ALLHERE: @@ -802,7 +825,7 @@ bool Guest_WaitForOthers (void *userdata) doomcom.numnodes = packet.NumNodes + 2; sendplayer[0] = packet.ConsoleNum; // My player number doomcom.consoleplayer = packet.ConsoleNum; - StartScreen->NetMessage ("Console player number: %d", doomcom.consoleplayer); + I_NetMessage ("Console player number: %d", doomcom.consoleplayer); for (node = 0; node < packet.NumNodes; node++) { sendaddress[node+2].sin_addr.s_addr = packet.machines[node].address; @@ -816,14 +839,14 @@ bool Guest_WaitForOthers (void *userdata) } } - StartScreen->NetMessage ("Received All Here, sending ACK."); + I_NetMessage ("Received All Here, sending ACK."); packet.Fake = PRE_FAKE; packet.Message = PRE_ALLHEREACK; PreSend (&packet, 2, &sendaddress[1]); break; case PRE_GO: - StartScreen->NetMessage ("Received \"Go.\""); + I_NetMessage ("Received \"Go.\""); return true; case PRE_DISCONNECT: @@ -855,22 +878,22 @@ bool JoinGame (int i) // Let host know we are here - StartScreen->NetInit ("Contacting host", 0); + I_NetInit ("Contacting host", 0); - if (!StartScreen->NetLoop (Guest_ContactHost, NULL)) + if (!I_NetLoop (Guest_ContactHost, NULL)) { SendAbort(); return false; } // Wait for everyone else to connect - if (!StartScreen->NetLoop (Guest_WaitForOthers, 0)) + if (!I_NetLoop (Guest_WaitForOthers, 0)) { SendAbort(); return false; } - - StartScreen->NetMessage ("Total players: %d", doomcom.numnodes); + + I_NetMessage ("Total players: %d", doomcom.numnodes); doomcom.id = DOOMCOM_ID; doomcom.numplayers = doomcom.numnodes; @@ -880,11 +903,11 @@ bool JoinGame (int i) static int PrivateNetOf(in_addr in) { int addr = ntohl(in.s_addr); - if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0 + if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0 { return 0xC0A80000; } - else if ((addr & 0xFFF00000) == 0xAC100000) // 172.16.0.0 + else if ((addr & 0xFFFF0000) >= 0xAC100000 && (addr & 0xFFFF0000) <= 0xAC1F0000) // 172.16.0.0 - 172.31.0.0 { return 0xAC100000; } @@ -945,7 +968,7 @@ int I_InitNetwork (void) v = Args->CheckValue ("-dup"); if (v) { - doomcom.ticdup = clamp (atoi (v), 1, MAXTICDUP); + doomcom.ticdup = clamp (atoi (v), 1, MAXTICDUP); } else { @@ -1003,6 +1026,43 @@ void I_NetCmd (void) I_Error ("Bad net cmd: %i\n",doomcom.command); } +void I_NetMessage(const char* text, ...) +{ + // todo: use better abstraction once everything is migrated to in-game start screens. +#if defined _WIN32 || defined __APPLE__ + va_list ap; + va_start(ap, text); + VPrintf(PRINT_HIGH, text, ap); + Printf("\n"); + va_end(ap); +#else + FString str; + va_list argptr; + + va_start(argptr, text); + str.VFormat(text, argptr); + va_end(argptr); + fprintf(stderr, "\r%-40s\n", str.GetChars()); +#endif +} + +// todo: later these must be dispatched by the main menu, not the start screen. +void I_NetProgress(int val) +{ + StartWindow->NetProgress(val); +} +void I_NetInit(const char* msg, int num) +{ + StartWindow->NetInit(msg, num); +} +bool I_NetLoop(bool (*timer_callback)(void*), void* userdata) +{ + return StartWindow->NetLoop(timer_callback, userdata); +} +void I_NetDone() +{ + StartWindow->NetDone(); +} #ifdef __WIN32__ const char *neterror (void) { diff --git a/src/common/engine/i_net.h b/src/common/engine/i_net.h new file mode 100644 index 00000000000..c52072c863d --- /dev/null +++ b/src/common/engine/i_net.h @@ -0,0 +1,91 @@ +#ifndef __I_NET_H__ +#define __I_NET_H__ + +#include + +// Called by D_DoomMain. +int I_InitNetwork (void); +void I_NetCmd (void); +void I_NetMessage(const char*, ...); +void I_NetProgress(int val); +void I_NetInit(const char* msg, int num); +bool I_NetLoop(bool (*timer_callback)(void*), void* userdata); +void I_NetDone(); + +enum ENetConstants +{ + MAXNETNODES = 8, // max computers in a game + DOOMCOM_ID = 0x12345678, + BACKUPTICS = 36, // number of tics to remember + MAXTICDUP = 5, + LOCALCMDTICS =(BACKUPTICS*MAXTICDUP), + MAX_MSGLEN = 14000, + + CMD_SEND = 1, + CMD_GET = 2, +}; + +// [RH] +// New generic packet structure: +// +// Header: +// One byte with following flags. +// One byte with starttic +// One byte with master's maketic (master -> slave only!) +// If NCMD_RETRANSMIT set, one byte with retransmitfrom +// If NCMD_XTICS set, one byte with number of tics (minus 3, so theoretically up to 258 tics in one packet) +// If NCMD_QUITTERS, one byte with number of players followed by one byte with each player's consolenum +// If NCMD_MULTI, one byte with number of players followed by one byte with each player's consolenum +// - The first player's consolenum is not included in this list, because it always matches the sender +// +// For each tic: +// Two bytes with consistancy check, followed by tic data +// +// Setup packets are different, and are described just before D_ArbitrateNetStart(). + +enum ENCMD +{ + NCMD_EXIT = 0x80, + NCMD_RETRANSMIT = 0x40, + NCMD_SETUP = 0x20, + NCMD_MULTI = 0x10, // multiple players in this packet + NCMD_QUITTERS = 0x08, // one or more players just quit (packet server only) + NCMD_COMPRESSED = 0x04, // remainder of packet is compressed + + NCMD_XTICS = 0x03, // packet contains >2 tics + NCMD_2TICS = 0x02, // packet contains 2 tics + NCMD_1TICS = 0x01, // packet contains 1 tic + NCMD_0TICS = 0x00, // packet contains 0 tics +}; + +// +// Network packet data. +// +struct doomcom_t +{ + uint32_t id; // should be DOOMCOM_ID + int16_t intnum; // DOOM executes an int to execute commands + +// communication between DOOM and the driver + int16_t command; // CMD_SEND or CMD_GET + int16_t remotenode; // dest for send, set by get (-1 = no packet). + int16_t datalength; // bytes in data to be sent + +// info common to all nodes + int16_t numnodes; // console is always node 0. + int16_t ticdup; // 1 = no duplication, 2-5 = dup for slow nets + +// info specific to this node + int16_t consoleplayer; + int16_t numplayers; + +// packet data to be sent + uint8_t data[MAX_MSGLEN]; + +}; + +extern doomcom_t doomcom; +extern bool netgame, multiplayer; +extern int consoleplayer; + +#endif diff --git a/src/common/engine/i_specialpaths.h b/src/common/engine/i_specialpaths.h new file mode 100644 index 00000000000..01710b6725e --- /dev/null +++ b/src/common/engine/i_specialpaths.h @@ -0,0 +1,23 @@ +#pragma once + +#include "zstring.h" + +#ifdef __unix__ +FString GetUserFile (const char *path); +#endif +FString M_GetAppDataPath(bool create); +FString M_GetCachePath(bool create); +FString M_GetAutoexecPath(); +FString M_GetConfigPath(bool for_reading); +FString M_GetScreenshotsPath(); +FString M_GetSavegamesPath(); +FString M_GetDocumentsPath(); +FString M_GetDemoPath(); + +FString M_GetNormalizedPath(const char* path); + + +#ifdef __APPLE__ +FString M_GetMacAppSupportPath(const bool create = true); +void M_GetMacSearchDirectories(FString& user_docs, FString& user_app_support, FString& local_app_support); +#endif // __APPLE__ diff --git a/src/m_joy.cpp b/src/common/engine/m_joy.cpp similarity index 86% rename from src/m_joy.cpp rename to src/common/engine/m_joy.cpp index bd51a77df87..1e4b2f3e0ed 100644 --- a/src/m_joy.cpp +++ b/src/common/engine/m_joy.cpp @@ -33,9 +33,13 @@ // HEADER FILES ------------------------------------------------------------ #include +#include "vectors.h" #include "m_joy.h" -#include "gameconfigfile.h" -#include "d_event.h" +#include "configfile.h" +#include "i_interface.h" +#include "d_eventbase.h" +#include "cmdlib.h" +#include "printf.h" // MACROS ------------------------------------------------------------------ @@ -55,12 +59,12 @@ EXTERN_CVAR(Bool, joy_xinput) // PUBLIC DATA DEFINITIONS ------------------------------------------------- -CUSTOM_CVAR(Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) +CUSTOM_CVARD(Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL, "enables input from the joystick if it is present") { #ifdef _WIN32 - joy_ps2raw.Callback(); - joy_dinput.Callback(); - joy_xinput.Callback(); + joy_ps2raw->Callback(); + joy_dinput->Callback(); + joy_xinput->Callback(); #endif } @@ -89,11 +93,12 @@ IJoystickConfig::~IJoystickConfig() // //========================================================================== -static bool M_SetJoystickConfigSection(IJoystickConfig *joy, bool create) +static bool M_SetJoystickConfigSection(IJoystickConfig *joy, bool create, FConfigFile* GameConfig) { FString id = "Joy:"; id += joy->GetIdentifier(); - return GameConfig->SetSection(id, create); + if (!GameConfig) return false; + return GameConfig->SetSection(id.GetChars(), create); } //========================================================================== @@ -104,21 +109,41 @@ static bool M_SetJoystickConfigSection(IJoystickConfig *joy, bool create) bool M_LoadJoystickConfig(IJoystickConfig *joy) { + FConfigFile* GameConfig = sysCallbacks.GetConfig ? sysCallbacks.GetConfig() : nullptr; char key[32]; const char *value; int axislen; int numaxes; joy->SetDefaultConfig(); - if (!M_SetJoystickConfigSection(joy, false)) + if (!M_SetJoystickConfigSection(joy, false, GameConfig)) { return false; } + + assert(GameConfig); + + value = GameConfig->GetValueForKey("Enabled"); + if (value) + { + joy->SetEnabled((bool)atoi(value)); + } + + if(joy->AllowsEnabledInBackground()) + { + value = GameConfig->GetValueForKey("EnabledInBackground"); + if (value) + { + joy->SetEnabledInBackground((bool)atoi(value)); + } + } + value = GameConfig->GetValueForKey("Sensitivity"); - if (value != NULL) + if (value) { joy->SetSensitivity((float)atof(value)); } + numaxes = joy->GetNumAxes(); for (int i = 0; i < numaxes; ++i) { @@ -126,21 +151,21 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy) mysnprintf(key + axislen, countof(key) - axislen, "deadzone"); value = GameConfig->GetValueForKey(key); - if (value != NULL) + if (value) { joy->SetAxisDeadZone(i, (float)atof(value)); } mysnprintf(key + axislen, countof(key) - axislen, "scale"); value = GameConfig->GetValueForKey(key); - if (value != NULL) + if (value) { joy->SetAxisScale(i, (float)atof(value)); } mysnprintf(key + axislen, countof(key) - axislen, "map"); value = GameConfig->GetValueForKey(key); - if (value != NULL) + if (value) { EJoyAxis gameaxis = (EJoyAxis)atoi(value); if (gameaxis < JOYAXIS_None || gameaxis >= NUM_JOYAXIS) @@ -163,12 +188,23 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy) void M_SaveJoystickConfig(IJoystickConfig *joy) { + FConfigFile* GameConfig = sysCallbacks.GetConfig ? sysCallbacks.GetConfig() : nullptr; char key[32], value[32]; int axislen, numaxes; - if (M_SetJoystickConfigSection(joy, true)) + if (GameConfig != NULL && M_SetJoystickConfigSection(joy, true, GameConfig)) { GameConfig->ClearCurrentSection(); + if (!joy->GetEnabled()) + { + GameConfig->SetValueForKey("Enabled", "0"); + } + + if (!joy->AllowsEnabledInBackground() && joy->GetEnabledInBackground()) + { + GameConfig->SetValueForKey("EnabledInBackground", "1"); + } + if (!joy->IsSensitivityDefault()) { mysnprintf(value, countof(value), "%g", joy->GetSensitivity()); @@ -268,14 +304,14 @@ int Joy_XYAxesToButtons(double x, double y) double rad = atan2(y, x); if (rad < 0) { - rad += 2*M_PI; + rad += 2*pi::pi(); } // The circle is divided into eight segments for corresponding // button combinations. Each segment is pi/4 radians wide. We offset // by half this so that the segments are centered around the ideal lines // their buttons represent instead of being right on the lines. - rad += M_PI/8; // Offset - rad *= 4/M_PI; // Convert range from [0,2pi) to [0,8) + rad += pi::pi()/8; // Offset + rad *= 4/pi::pi(); // Convert range from [0,2pi) to [0,8) return JoyAngleButtons[int(rad) & 7]; } diff --git a/src/m_joy.h b/src/common/engine/m_joy.h similarity index 87% rename from src/m_joy.h rename to src/common/engine/m_joy.h index 042a59686d4..e8d9d3b1372 100644 --- a/src/m_joy.h +++ b/src/common/engine/m_joy.h @@ -1,7 +1,7 @@ #ifndef M_JOY_H #define M_JOY_H -#include "doomtype.h" +#include "basics.h" #include "tarray.h" #include "c_cvars.h" @@ -18,10 +18,10 @@ enum EJoyAxis }; // Generic configuration interface for a controller. -struct NOVTABLE IJoystickConfig +struct IJoystickConfig { virtual ~IJoystickConfig() = 0; - + virtual FString GetName() = 0; virtual float GetSensitivity() = 0; virtual void SetSensitivity(float scale) = 0; @@ -36,6 +36,13 @@ struct NOVTABLE IJoystickConfig virtual void SetAxisMap(int axis, EJoyAxis gameaxis) = 0; virtual void SetAxisScale(int axis, float scale) = 0; + virtual bool GetEnabled() = 0; + virtual void SetEnabled(bool enabled) = 0; + + virtual bool AllowsEnabledInBackground() = 0; + virtual bool GetEnabledInBackground() = 0; + virtual void SetEnabledInBackground(bool enabled) = 0; + // Used by the saver to not save properties that are at their defaults. virtual bool IsSensitivityDefault() = 0; virtual bool IsAxisDeadZoneDefault(int axis) = 0; diff --git a/src/utility/m_random.cpp b/src/common/engine/m_random.cpp similarity index 92% rename from src/utility/m_random.cpp rename to src/common/engine/m_random.cpp index 9a765b85155..3af14526bb8 100644 --- a/src/utility/m_random.cpp +++ b/src/common/engine/m_random.cpp @@ -59,11 +59,11 @@ #include -#include "doomstat.h" #include "m_random.h" #include "serializer.h" #include "m_crc32.h" #include "c_dispatch.h" +#include "printf.h" // MACROS ------------------------------------------------------------------ @@ -79,11 +79,7 @@ // EXTERNAL DATA DECLARATIONS ---------------------------------------------- -extern FRandom pr_spawnmobj; -extern FRandom pr_acs; -extern FRandom pr_chase; -extern FRandom pr_exrandom; -extern FRandom pr_damagemobj; +FRandom pr_exrandom("EX_Random"); // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -148,7 +144,6 @@ FRandom::FRandom () { #ifndef NDEBUG Name = NULL; - initialized = false; #endif Next = RNGList; RNGList = this; @@ -167,7 +162,6 @@ FRandom::FRandom (const char *name) { NameCRC = CalcCRC32 ((const uint8_t *)name, (unsigned int)strlen (name)); #ifndef NDEBUG - initialized = false; Name = name; // A CRC of 0 is reserved for nameless RNGs that don't get stored // in savegames. The chance is very low that you would get a CRC of 0, @@ -258,27 +252,7 @@ void FRandom::Init(uint32_t seed) // [RH] Use the RNG's name's CRC to modify the original seed. // This way, new RNGs can be added later, and it doesn't matter // which order they get initialized in. - uint32_t seeds[2] = { NameCRC, seed }; - InitByArray(seeds, 2); -} - -//========================================================================== -// -// FRandom :: StaticSumSeeds -// -// This function produces a uint32_t that can be used to check the consistancy -// of network games between different machines. Only a select few RNGs are -// used for the sum, because not all RNGs are important to network sync. -// -//========================================================================== - -uint32_t FRandom::StaticSumSeeds () -{ - return - pr_spawnmobj.sfmt.u[0] + pr_spawnmobj.idx + - pr_acs.sfmt.u[0] + pr_acs.idx + - pr_chase.sfmt.u[0] + pr_chase.idx + - pr_damagemobj.sfmt.u[0] + pr_damagemobj.idx; + SFMTObj::Init(NameCRC, seed); } //========================================================================== diff --git a/src/utility/m_random.h b/src/common/engine/m_random.h similarity index 83% rename from src/utility/m_random.h rename to src/common/engine/m_random.h index 250d88d1339..d9eec6c44c0 100644 --- a/src/utility/m_random.h +++ b/src/common/engine/m_random.h @@ -36,18 +36,23 @@ #define __M_RANDOM__ #include -#include "basictypes.h" -#include "sfmt/SFMT.h" +#include "basics.h" +#include "sfmt/SFMTObj.h" class FSerializer; -class FRandom +class FRandom : public SFMTObj { public: FRandom (); FRandom (const char *name); ~FRandom (); + int Seed() const + { + return sfmt.u[0] + idx; + } + // Returns a random number in the range [0,255] int operator()() { @@ -88,16 +93,6 @@ class FRandom void Init(uint32_t seed); - // SFMT interface - unsigned int GenRand32(); - uint64_t GenRand64(); - void FillArray32(uint32_t *array, int size); - void FillArray64(uint64_t *array, int size); - void InitGenRand(uint32_t seed); - void InitByArray(uint32_t *init_key, int key_length); - int GetMinArraySize32(); - int GetMinArraySize64(); - /* These real versions are due to Isaku Wada */ /** generates a random number on [0,1]-real-interval */ static inline double ToReal1(uint32_t v) @@ -173,7 +168,6 @@ class FRandom // Static interface static void StaticClearRandom (); - static uint32_t StaticSumSeeds (); static void StaticReadRNGState (FSerializer &arc); static void StaticWriteRNGState (FSerializer &file); static FRandom *StaticFindRNG(const char *name); @@ -190,29 +184,6 @@ class FRandom uint32_t NameCRC; static FRandom *RNGList; - - /*------------------------------------------- - SFMT internal state, index counter and flag - -------------------------------------------*/ - - void GenRandAll(); - void GenRandArray(w128_t *array, int size); - void PeriodCertification(); - - /** the 128-bit internal state array */ - union - { - w128_t w128[SFMT::N]; - unsigned int u[SFMT::N32]; - uint64_t u64[SFMT::N64]; - } sfmt; - /** index counter to the 32-bit internal state array */ - int idx; - /** a flag: it is 0 if and only if the internal state is not yet - * initialized. */ -#ifndef NDEBUG - bool initialized; -#endif }; extern uint32_t rngseed; // The starting seed (not part of state) diff --git a/src/common/engine/namedef.h b/src/common/engine/namedef.h new file mode 100644 index 00000000000..7f98beba083 --- /dev/null +++ b/src/common/engine/namedef.h @@ -0,0 +1,283 @@ +// common names + +// 'None' must always be the first name. +xx(None) +xx(Null) +xx(_) + +xx(Super) +xx(Object) +xx(Actor) +xx(Class) +xx(Thinker) +xx(VisualThinker) +xx(Crosshairs) + +xx(Untranslated) + +// Render styles +xx(Normal) +xx(SoulTrans) +xx(OptFuzzy) +xx(Add) +xx(Shaded) +xx(AddShaded) +xx(TranslucentStencil) +xx(Shadow) +xx(Subtract) +xx(Subtractive) +xx(FillColor) +xx(ColorBlend) +xx(ColorAdd) +xx(Multiply) + +// Special names for compiler backend +xx(Name) +xx(Clamp) +xx(Abs) +xx(Random) +xx(FRandom) +xx(Random2) +xx(RandomPick) +xx(FRandomPick) +xx(SetRandomSeed) +xx(BuiltinRandomSeed) +xx(BuiltinNew) +xx(GetClass) +xx(GetParentClass) +xx(GetClassName) +xx(IsAbstract) +xx(GetDefaultByType) +xx(Floor) +xx(Exp) +xx(Log) +xx(Log10) +xx(Ceil) +xx(ACos) +xx(ASin) +xx(ATan) +xx(Cos) +xx(Sin) +xx(Tan) +xx(CosH) +xx(SinH) +xx(TanH) +xx(Round) +xx(ATan2) +xx(VectorAngle) +xx(Sqrt) +xx(New) + +xx(Static) +xx(Staticconst) + +// compatibility crap that GZDoom needs in the backend. +xx(ACS_NamedExecuteWithResult) +xx(__decorate_internal_int__) +xx(__decorate_internal_bool__) +xx(__decorate_internal_float__) + +// Per-actor sound channels (for deprecated PlaySoundEx function) Do not separate this block!!! +xx(Auto) +xx(Weapon) +xx(Voice) +xx(Item) +xx(Body) +xx(SoundSlot5) +xx(SoundSlot6) +xx(SoundSlot7) + +xx(LevelLocals) +xx(Level) + +xy(menu_cursor, "menu/cursor") +xy(menu_choose, "menu/choose") +xy(menu_backup, "menu/backup") +xy(menu_clear, "menu/clear") +xy(menu_dismiss, "menu/dismiss") +xy(menu_change, "menu/change") +xy(menu_advance, "menu/advance") + +// basic type names +xx(Default) +xx(sByte) +xx(Byte) +xx(Short) +xx(uShort) +xx(Int) +xx(uInt) +xx(Bool) +xx(uint8) +xx(int8) +xx(uint16) +xx(int16) +xx(Float) +xx(Float32) +xx(Float64) +xx(Double) +xx(String) +xx(Vector) +xx(Map) +xx(MapIterator) +xx(Array) +xx(Function) +xx(Include) +xx(Sound) +xx(State) +xx(Fixed) +xx(Vector2) +xx(Vector3) +xx(Vector4) +xx(Quat) +xx(FVector2) +xx(FVector3) +xx(FVector4) +xx(FQuat) +xx(let) +xx(BlockThingsIterator) +xx(BlockLinesIterator) +xx(ActorIterator) +xx(ThinkerIterator) + +xx(Min) +xx(Max) +xx(Min_Normal) +xx(Min_Denormal) +xx(Epsilon) +xx(Equal_Epsilon) +xx(NaN) +xx(Infinity) +xx(Dig) +xx(Min_Exp) +xx(Max_Exp) +xx(Mant_Dig) +xx(Min_10_Exp) +xx(Max_10_Exp) + +// implicit function parameters +xx(self) +xx(invoker) +xx(stateinfo) + +xx(DamageFunction) +xx(Length) +xx(LengthSquared) +xx(Sum) +xx(Unit) +xx(Angle) +xx(PlusZ) +xx(ToVector) +xx(Size) +xx(Push) +xx(Insert) +xx(InsertNew) +xx(Remove) +xx(Get) +xx(GetIfExists) +xx(GetValue) +xx(GetKey) +xx(SetValue) +xx(CheckKey) +xx(CheckValue) +xx(Value) +xx(Copy) +xx(Move) +xx(Voidptr) +xx(StateLabel) +xx(SpriteID) +xx(TextureID) +xx(TranslationID) +xx(Overlay) +xx(IsValid) +xx(IsNull) +xx(Exists) +xx(SetInvalid) +xx(SetNull) +xx(Key) +xx(Index) +xx(Find) +xx(Call) + +// color channels +xx(a) +xx(r) +xx(g) +xx(b) + +xx(X) +xx(Y) +xx(Z) +xx(W) +xx(XY) +xx(XYZ) + +xx(Prototype) +xx(Void) +xx(Label) +xx(Pointer) +xx(Enum) +xx(StaticArray) +xx(DynArray) +xx(Struct) +xx(ReflectType) +xx(MessageBoxMenu) + +xx(Both) +xx(Physical) +xx(Visual) + +// blacklisted former CVARs (used by common menu code) +xx(snd_waterlp) +xx(snd_output) +xx(snd_output_format) +xx(snd_speakermode) +xx(snd_resampler) +xx(AlwaysRun) + +// menu names +xx(Mainmenu) +xx(Episodemenu) +xx(Skillmenu) +xx(Startgame) +xx(StartgameConfirm) +xx(StartgameConfirmed) +xx(Loadgamemenu) +xx(Savegamemenu) +xx(Optionsmenu) +xx(OptionsmenuSimple) +xx(OptionsmenuFull) +xx(Quitmenu) +xx(Savemenu) +xx(EndGameMenu) +xx(HelpMenu) +xx(SoundMenu) +xx(ConfirmPlayerReset) +xx(JoystickOptions) + +xx(OptionMenuItemSubmenu) +xx(OptionMenuItemCommand) +xx(OptionMenuItemControlBase) +xx(OptionMenuItemOptionBase) +xx(OptionMenuSliderBase) +xx(OptionMenuFieldBase) +xx(OptionMenuItemColorPicker) +xx(OptionMenuItemStaticText) +xx(OptionMenuItemStaticTextSwitchable) + +xx(Color) + +xx(Mididevices) +xx(Aldevices) +xx(Alresamplers) + +// Decorate compatibility functions +xx(BuiltinRandom) +xx(BuiltinRandom2) +xx(BuiltinFRandom) +xx(BuiltinNameToClass) +xx(BuiltinClassCast) +xx(BuiltinFunctionPtrCast) +xx(BuiltinFindTranslation) + +xx(ScreenJobRunner) +xx(Action) diff --git a/src/common/engine/palettecontainer.cpp b/src/common/engine/palettecontainer.cpp new file mode 100644 index 00000000000..29ec3599ffa --- /dev/null +++ b/src/common/engine/palettecontainer.cpp @@ -0,0 +1,825 @@ +/* +** r_translate.cpp +** Translation table handling +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "palutil.h" +#include "sc_man.h" +#include "m_crc32.h" +#include "printf.h" +#include "colormatcher.h" + +#include "palettecontainer.h" +#include "files.h" + +PaletteContainer GPalette; +FColorMatcher ColorMatcher; +extern uint8_t IcePalette[16][3]; + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void PaletteContainer::Init(int numslots, const uint8_t* indexmap) // This cannot be a constructor!!! +{ + if (numslots < 1) numslots = 1; + Clear(); + HasGlobalBrightmap = false; + // Make sure that index 0 is always the identity translation. + FRemapTable remap; + remap.MakeIdentity(); + remap.Inactive = true; + TranslationTables.Resize(numslots); + StoreTranslation(0, &remap); // make sure that translation ID 0 is the identity. + ColorMatcher.SetPalette(BaseColors); + ColorMatcher.SetIndexMap(indexmap); +} + +void PaletteContainer::SetPalette(const uint8_t* colors, int transparent_index) +{ + // Initialize all tables to the original palette. + // At this point we do not care about the transparent index yet. + for (int i = 0; i < 256; i++, colors += 3) + { + uniqueRemaps[0]->Palette[i] = BaseColors[i] = RawColors[i] = PalEntry(255, colors[0], colors[1], colors[2]); + Remap[i] = i; + } + + uniqueRemaps[0]->MakeIdentity(); // update the identity remap. + + // If the palette already has a transparent index, clear that color now + if (transparent_index >= 0 && transparent_index <= 255) + { + BaseColors[transparent_index] = 0; + uniqueRemaps[0]->Palette[transparent_index] = 0; + } + + uniqueRemaps[0]->crc32 = CalcCRC32((uint8_t*)uniqueRemaps[0]->Palette, sizeof(uniqueRemaps[0]->Palette)); + + + // Find white and black from the original palette so that they can be + // used to make an educated guess of the translucency % for a + // translucency map. + WhiteIndex = BestColor((uint32_t*)RawColors, 255, 255, 255, 0, 255); + BlackIndex = BestColor((uint32_t*)RawColors, 0, 0, 0, 0, 255); + + // The alphatexture translation. This is just a standard index as gray mapping and has no association with the palette. + auto remap = &GrayRamp; + remap->Remap[0] = 0; + remap->Palette[0] = 0; + for (int i = 1; i < 256; i++) + { + remap->Remap[i] = i; + remap->Palette[i] = PalEntry(255, i, i, i); + } + + // Palette to grayscale ramp. For internal use only, because the remap does not map to the palette. + remap = &GrayscaleMap; + remap->Remap[0] = 0; + remap->Palette[0] = 0; + for (int i = 1; i < 256; i++) + { + int r = GPalette.BaseColors[i].r; + int g = GPalette.BaseColors[i].g; + int b = GPalette.BaseColors[i].b; + int v = (r * 77 + g * 143 + b * 37) >> 8; + + remap->Remap[i] = v; + remap->Palette[i] = PalEntry(255, v, v, v); + } + + for (int i = 0; i < 256; ++i) + { + GrayMap[i] = ColorMatcher.Pick(i, i, i); + } + + // Create the ice translation table, based on Hexen's. Alas, the standard + // Doom palette has no good substitutes for these bluish-tinted grays, so + // they will just look gray unless you use a different PLAYPAL with Doom. + + uint8_t IcePaletteRemap[16]; + for (int i = 0; i < 16; ++i) + { + IcePaletteRemap[i] = ColorMatcher.Pick(IcePalette[i][0], IcePalette[i][1], IcePalette[i][2]); + } + remap = &IceMap; + remap->Remap[0] = 0; + remap->Palette[0] = 0; + for (int i = 1; i < 256; ++i) + { + int r = GPalette.BaseColors[i].r; + int g = GPalette.BaseColors[i].g; + int b = GPalette.BaseColors[i].b; + int v = (r * 77 + g * 143 + b * 37) >> 12; + remap->Remap[i] = IcePaletteRemap[v]; + remap->Palette[i] = PalEntry(255, IcePalette[v][0], IcePalette[v][1], IcePalette[v][2]); + } +} + + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void PaletteContainer::Clear() +{ + remapArena.FreeAllBlocks(); + uniqueRemaps.Reset(); + TranslationTables.Reset(); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +int PaletteContainer::DetermineTranslucency(FileReader& tranmap) +{ + uint8_t index; + PalEntry newcolor; + PalEntry newcolor2; + + if (!tranmap.isOpen()) return 255; + tranmap.Seek(GPalette.BlackIndex * 256 + GPalette.WhiteIndex, FileReader::SeekSet); + tranmap.Read(&index, 1); + + newcolor = GPalette.BaseColors[GPalette.Remap[index]]; + + tranmap.Seek(GPalette.WhiteIndex * 256 + GPalette.BlackIndex, FileReader::SeekSet); + tranmap.Read(&index, 1); + newcolor2 = GPalette.BaseColors[GPalette.Remap[index]]; + if (newcolor2.r == 255) // if black on white results in white it's either + // fully transparent or additive + { + return -newcolor.r; + } + return newcolor.r; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +FRemapTable* PaletteContainer::AddRemap(FRemapTable* remap) +{ + if (!remap) return uniqueRemaps[0]; + + remap->crc32 = CalcCRC32((uint8_t*)remap->Palette, sizeof(remap->Palette)); + + for (auto uremap : uniqueRemaps) + { + if (uremap->crc32 == remap->crc32 && uremap->NumEntries == remap->NumEntries && *uremap == *remap && remap->Inactive == uremap->Inactive) + return uremap; + } + auto newremap = (FRemapTable*)remapArena.Alloc(sizeof(FRemapTable)); + *newremap = *remap; + auto index = uniqueRemaps.Push(newremap); + newremap->Index = index; + return newremap; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void PaletteContainer::UpdateTranslation(FTranslationID trans, FRemapTable* remap) +{ + auto newremap = AddRemap(remap); + TranslationTables[GetTranslationType(trans)].SetVal(GetTranslationIndex(trans), newremap); +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +FTranslationID PaletteContainer::AddTranslation(int slot, FRemapTable* remap, int count) +{ + uint32_t id = 0; + for (int i = 0; i < count; i++) + { + auto newremap = AddRemap(&remap[i]); + id = TranslationTables[slot].Push(newremap); + } + return TRANSLATION(slot, id); +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void PaletteContainer::CopyTranslation(FTranslationID dest, FTranslationID src) +{ + TranslationTables[GetTranslationType(dest)].SetVal(GetTranslationIndex(dest), TranslationToTable(src.index())); +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +FRemapTable *PaletteContainer::TranslationToTable(int translation) const +{ + if (IsLuminosityTranslation(translation)) return nullptr; + unsigned int type = GetTranslationType(translation); + unsigned int index = GetTranslationIndex(translation); + + if (type >= TranslationTables.Size() || index >= NumTranslations(type)) + { + return uniqueRemaps[0]; // this is the identity table. + } + return GetTranslation(type, index); +} + +//---------------------------------------------------------------------------- +// +// Stores a copy of this translation but avoids duplicates +// +//---------------------------------------------------------------------------- + +FTranslationID PaletteContainer::StoreTranslation(int slot, FRemapTable *remap) +{ + unsigned int i; + + auto size = NumTranslations(slot); + for (i = 0; i < size; i++) + { + if (*remap == *TranslationToTable(TRANSLATION(slot, i).index())) + { + // A duplicate of this translation already exists + return TRANSLATION(slot, i); + } + } + if (size >= 65535) // Translation IDs only have 16 bits for the index. + { + I_Error("Too many DECORATE translations"); + } + return AddTranslation(slot, remap); +} + +//=========================================================================== +// +// Examines the colormap to see if some of the colors have to be +// considered fullbright all the time. +// +//=========================================================================== + +void PaletteContainer::GenerateGlobalBrightmapFromColormap(const uint8_t *cmapdata, int numlevels) +{ + GlobalBrightmap.MakeIdentity(); + memset(GlobalBrightmap.Remap, WhiteIndex, 256); + for (int i = 0; i < 256; i++) GlobalBrightmap.Palette[i] = PalEntry(255, 255, 255, 255); + for (int j = 0; j < numlevels; j++) + { + for (int i = 0; i < 256; i++) + { + // the palette comparison should be for ==0 but that gives false positives with Heretic + // and Hexen. + uint8_t mappedcolor = cmapdata[i]; // consider colormaps which already remap the base level. + if (cmapdata[i + j * 256] != mappedcolor || (RawColors[mappedcolor].r < 10 && RawColors[mappedcolor].g < 10 && RawColors[mappedcolor].b < 10)) + { + GlobalBrightmap.Remap[i] = BlackIndex; + GlobalBrightmap.Palette[i] = PalEntry(255, 0, 0, 0); + } + } + } + for (int i = 0; i < 256; i++) + { + HasGlobalBrightmap |= GlobalBrightmap.Remap[i] == WhiteIndex; + if (GlobalBrightmap.Remap[i] == WhiteIndex) DPrintf(DMSG_NOTIFY, "Marked color %d as fullbright\n", i); + } +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +static bool IndexOutOfRange(const int color) +{ + const bool outOfRange = color < 0 || color > 255; + + if (outOfRange) + { + Printf(TEXTCOLOR_ORANGE "Palette index %i is out of range [0..255]\n", color); + } + + return outOfRange; +} + +static bool IndexOutOfRange(const int start, const int end) +{ + const bool outOfRange = IndexOutOfRange(start); + return IndexOutOfRange(end) || outOfRange; +} + +static bool IndexOutOfRange(const int start1, const int end1, const int start2, const int end2) +{ + const bool outOfRange = IndexOutOfRange(start1, end1); + return IndexOutOfRange(start2, end2) || outOfRange; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +bool FRemapTable::operator==(const FRemapTable& o) const +{ + // Two translations are identical when they have the same amount of colors + // and the palette values for both are identical. + if (&o == this) return true; + if (o.NumEntries != NumEntries) return false; + return !memcmp(o.Palette, Palette, NumEntries * sizeof(*Palette)); +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void FRemapTable::MakeIdentity() +{ + int i; + + for (i = 0; i < NumEntries; ++i) + { + Remap[i] = i; + } + for (i = 0; i < NumEntries; ++i) + { + Palette[i] = GPalette.BaseColors[i]; + } + for (i = 1; i < NumEntries; ++i) + { + Palette[i].a = 255; + } +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +bool FRemapTable::IsIdentity() const +{ + for (int j = 0; j < 256; ++j) + { + if (Remap[j] != j) + { + return false; + } + } + return true; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +bool FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2) +{ + if (IndexOutOfRange(start, end, pal1, pal2)) + { + return false; + } + + double palcol, palstep; + + if (start > end) + { + std::swap (start, end); + std::swap (pal1, pal2); + } + else if (start == end) + { + start = GPalette.Remap[start]; + pal1 = GPalette.Remap[pal1]; + Remap[start] = pal1; + Palette[start] = GPalette.BaseColors[pal1]; + Palette[start].a = start == 0 ? 0 : 255; + return true; + } + palcol = pal1; + palstep = (pal2 - palcol) / (end - start); + for (int i = start; i <= end; palcol += palstep, ++i) + { + int j = GPalette.Remap[i], k = GPalette.Remap[int(round(palcol))]; + Remap[j] = k; + Palette[j] = GPalette.BaseColors[k]; + Palette[j].a = j == 0 ? 0 : 255; + } + return true; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +bool FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, int _r2, int _g2, int _b2) +{ + if (IndexOutOfRange(start, end)) + { + return false; + } + + double r1 = _r1; + double g1 = _g1; + double b1 = _b1; + double r2 = _r2; + double g2 = _g2; + double b2 = _b2; + double r, g, b; + double rs, gs, bs; + + if (start > end) + { + std::swap (start, end); + r = r2; + g = g2; + b = b2; + rs = r1 - r2; + gs = g1 - g2; + bs = b1 - b2; + } + else + { + r = r1; + g = g1; + b = b1; + rs = r2 - r1; + gs = g2 - g1; + bs = b2 - b1; + } + if (start == end) + { + start = GPalette.Remap[start]; + Palette[start] = PalEntry(start == 0 ? 0 : 255, int(r), int(g), int(b)); + Remap[start] = ColorMatcher.Pick(Palette[start]); + } + else + { + rs /= (end - start); + gs /= (end - start); + bs /= (end - start); + for (int i = start; i <= end; ++i) + { + int j = GPalette.Remap[i]; + Palette[j] = PalEntry(j == 0 ? 0 : 255, int(r), int(g), int(b)); + Remap[j] = ColorMatcher.Pick(Palette[j]); + r += rs; + g += gs; + b += bs; + } + } + return true; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +bool FRemapTable::AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2) +{ + if (IndexOutOfRange(start, end)) + { + return false; + } + + r1 = clamp(r1, 0.0, 2.0); + g1 = clamp(g1, 0.0, 2.0); + b1 = clamp(b1, 0.0, 2.0); + r2 = clamp(r2, 0.0, 2.0); + g2 = clamp(g2, 0.0, 2.0); + b2 = clamp(b2, 0.0, 2.0); + + if (start > end) + { + std::swap(start, end); + std::swap(r1, r2); + std::swap(g1, g2); + std::swap(b1, b2); + } + + r2 -= r1; + g2 -= g1; + b2 -= b1; + r1 *= 255; + g1 *= 255; + b1 *= 255; + + for(int c = start; c <= end; c++) + { + double intensity = (GPalette.BaseColors[c].r * 77 + + GPalette.BaseColors[c].g * 143 + + GPalette.BaseColors[c].b * 37) / 256.0; + + PalEntry pe = PalEntry( min(255, int(r1 + intensity*r2)), + min(255, int(g1 + intensity*g2)), + min(255, int(b1 + intensity*b2))); + + int cc = GPalette.Remap[c]; + + Remap[cc] = ColorMatcher.Pick(pe); + Palette[cc] = pe; + Palette[cc].a = cc == 0 ? 0:255; + } + return true; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +bool FRemapTable::AddColourisation(int start, int end, int r, int g, int b) +{ + if (IndexOutOfRange(start, end)) + { + return false; + } + + for (int i = start; i < end; ++i) + { + double br = GPalette.BaseColors[i].r; + double bg = GPalette.BaseColors[i].g; + double bb = GPalette.BaseColors[i].b; + double grey = (br * 0.299 + bg * 0.587 + bb * 0.114) / 255.0f; + if (grey > 1.0) grey = 1.0; + br = r * grey; + bg = g * grey; + bb = b * grey; + + int j = GPalette.Remap[i]; + Palette[j] = PalEntry(j == 0 ? 0 : 255, int(br), int(bg), int(bb)); + Remap[j] = ColorMatcher.Pick(Palette[j]); + } + return true; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +bool FRemapTable::AddTint(int start, int end, int r, int g, int b, int amount) +{ + if (IndexOutOfRange(start, end)) + { + return false; + } + + for (int i = start; i < end; ++i) + { + float br = GPalette.BaseColors[i].r; + float bg = GPalette.BaseColors[i].g; + float bb = GPalette.BaseColors[i].b; + float a = amount * 0.01f; + float ia = 1.0f - a; + br = br * ia + r * a; + bg = bg * ia + g * a; + bb = bb * ia + b * a; + + int j = GPalette.Remap[i]; + Palette[j] = PalEntry(j == 0 ? 0 : 255, int(br), int(bg), int(bb)); + Remap[j] = ColorMatcher.Pick(Palette[j]); + } + return true; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +bool FRemapTable::AddToTranslation(const char *range) +{ + int start,end; + FScanner sc; + + sc.OpenMem("translation", range, int(strlen(range))); + sc.SetCMode(true); + + sc.MustGetToken(TK_IntConst); + start = sc.Number; + sc.MustGetToken(':'); + sc.MustGetToken(TK_IntConst); + end = sc.Number; + sc.MustGetToken('='); + if (start < 0 || start > 255 || end < 0 || end > 255) + { + sc.ScriptError("Palette index out of range"); + return false; + } + + sc.MustGetAnyToken(); + + if (sc.TokenType == '[') + { + // translation using RGB values + int r1,g1,b1,r2,g2,b2; + + sc.MustGetToken(TK_IntConst); + r1 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + g1 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + b1 = sc.Number; + sc.MustGetToken(']'); + sc.MustGetToken(':'); + sc.MustGetToken('['); + + sc.MustGetToken(TK_IntConst); + r2 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + g2 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + b2 = sc.Number; + sc.MustGetToken(']'); + + return AddColorRange(start, end, r1, g1, b1, r2, g2, b2); + } + else if (sc.TokenType == '%') + { + // translation using RGB values + double r1,g1,b1,r2,g2,b2; + + sc.MustGetToken('['); + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + r1 = sc.Float; + sc.MustGetToken(','); + + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + g1 = sc.Float; + sc.MustGetToken(','); + + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + b1 = sc.Float; + sc.MustGetToken(']'); + sc.MustGetToken(':'); + sc.MustGetToken('['); + + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + r2 = sc.Float; + sc.MustGetToken(','); + + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + g2 = sc.Float; + sc.MustGetToken(','); + + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + b2 = sc.Float; + sc.MustGetToken(']'); + + return AddDesaturation(start, end, r1, g1, b1, r2, g2, b2); + } + else if (sc.TokenType == '#') + { + // Colourise translation + int r, g, b; + sc.MustGetToken('['); + sc.MustGetToken(TK_IntConst); + r = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + g = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + b = sc.Number; + sc.MustGetToken(']'); + + return AddColourisation(start, end, r, g, b); + } + else if (sc.TokenType == '@') + { + // Tint translation + int a, r, g, b; + + sc.MustGetToken(TK_IntConst); + a = sc.Number; + sc.MustGetToken('['); + sc.MustGetToken(TK_IntConst); + r = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + g = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + b = sc.Number; + sc.MustGetToken(']'); + + return AddTint(start, end, r, g, b, a); + } + else + { + int pal1, pal2; + + sc.TokenMustBe(TK_IntConst); + pal1 = sc.Number; + sc.MustGetToken(':'); + sc.MustGetToken(TK_IntConst); + pal2 = sc.Number; + return AddIndexRange(start, end, pal1, pal2); + } +} + +//---------------------------------------------------------------------------- +// +// Adds raw colors to a given translation +// +//---------------------------------------------------------------------------- + +bool FRemapTable::AddColors(int start, int count, const uint8_t*colors, int trans_color) +{ + int end = start + count; + if (IndexOutOfRange(start, end-1)) + { + return false; + } + + for (int i = start; i < end; ++i) + { + auto br = colors[0]; + auto bg = colors[1]; + auto bb = colors[2]; + colors += 3; + + int j = GPalette.Remap[i]; + Palette[j] = PalEntry(j == trans_color ? 0 : 255, br, bg, bb); + Remap[j] = ColorMatcher.Pick(Palette[j]); + } + return true; + +} + + diff --git a/src/common/engine/palettecontainer.h b/src/common/engine/palettecontainer.h new file mode 100644 index 00000000000..3c6da1a3674 --- /dev/null +++ b/src/common/engine/palettecontainer.h @@ -0,0 +1,245 @@ +#pragma once + +#include +#include "memarena.h" +#include "palentry.h" +#include "files.h" + +enum +{ + TRANSLATION_Internal = 0 +}; + + +struct FRemapTable +{ + FRemapTable(int count = 256) { NumEntries = count; } + + FRemapTable(const FRemapTable& o) = default; + FRemapTable& operator=(const FRemapTable& o) = default; + + bool operator==(const FRemapTable& o) const; + void MakeIdentity(); + bool IsIdentity() const; + bool AddIndexRange(int start, int end, int pal1, int pal2); + bool AddColorRange(int start, int end, int r1, int g1, int b1, int r2, int g2, int b2); + bool AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2); + bool AddColourisation(int start, int end, int r, int g, int b); + bool AddTint(int start, int end, int r, int g, int b, int amount); + bool AddToTranslation(const char* range); + bool AddColors(int start, int count, const uint8_t*, int trans_color = 0); + + uint8_t Remap[256]; // For the software renderer + PalEntry Palette[256]; // The ideal palette this maps to + int crc32; + int Index; + int NumEntries; // # of elements in this table (usually 256) + bool Inactive = false; // This table is inactive and should be treated as if it was passed as NULL + bool TwodOnly = false; // Only used for 2D rendering + bool ForFont = false; // Mark font translations because they may require different handling than the ones for sprites- + bool NoTransparency = false; // This palette has no transparent index and must be excluded from all treatment for that. + +private: +}; + + + +// outside facing translation ID +struct FTranslationID +{ +public: + FTranslationID() = default; + +private: + constexpr FTranslationID(int id) : ID(id) + { + } +public: + static constexpr FTranslationID fromInt(int i) + { + return FTranslationID(i); + } + FTranslationID(const FTranslationID& other) = default; + FTranslationID& operator=(const FTranslationID& other) = default; + bool operator !=(FTranslationID other) const + { + return ID != other.ID; + } + bool operator ==(FTranslationID other) const + { + return ID == other.ID; + } + constexpr int index() const + { + return ID; + } + constexpr bool isvalid() const + { + return ID >= 0; + } +private: + + int ID; +}; + +constexpr FTranslationID NO_TRANSLATION = FTranslationID::fromInt(0); +constexpr FTranslationID INVALID_TRANSLATION = FTranslationID::fromInt(-1); + +// A class that initializes unusued pointers to NULL. This is used so that when +// the TAutoGrowArray below is expanded, the new elements will be NULLed. +class FRemapTablePtr +{ +public: + FRemapTablePtr() throw() : Ptr(0) {} + FRemapTablePtr(FRemapTable* p) throw() : Ptr(p) {} + FRemapTablePtr(const FRemapTablePtr& p) throw() : Ptr(p.Ptr) {} + operator FRemapTable* () const throw() { return Ptr; } + FRemapTablePtr& operator= (FRemapTable* p) throw() { Ptr = p; return *this; } + FRemapTablePtr& operator= (FRemapTablePtr& p) throw() { Ptr = p.Ptr; return *this; } + FRemapTable& operator*() const throw() { return *Ptr; } + FRemapTable* operator->() const throw() { return Ptr; } +private: + FRemapTable* Ptr = nullptr; +}; + + +enum +{ + TRANSLATION_SHIFT = 16, + TRANSLATION_MASK = ((1 << TRANSLATION_SHIFT) - 1), + TRANSLATIONTYPE_MASK = (255 << TRANSLATION_SHIFT) +}; + +inline constexpr FTranslationID TRANSLATION(uint8_t a, uint32_t b) +{ + return FTranslationID::fromInt((a << TRANSLATION_SHIFT) | b); +} +inline constexpr FTranslationID MakeLuminosityTranslation(int range, uint8_t min, uint8_t max) +{ + // ensure that the value remains positive. + return FTranslationID::fromInt( (1 << 30) | ((range&0x3fff) << 16) | (min << 8) | max ); +} + +inline constexpr bool IsLuminosityTranslation(FTranslationID trans) +{ + return trans.index() > 0 && (trans.index() & (1 << 30)); +} + +inline constexpr bool IsLuminosityTranslation(int trans) +{ + return trans > 0 && (trans & (1 << 30)); +} + +inline constexpr int GetTranslationType(FTranslationID trans) +{ + assert(!IsLuminosityTranslation(trans)); + return (trans.index() & TRANSLATIONTYPE_MASK) >> TRANSLATION_SHIFT; +} + +inline constexpr int GetTranslationIndex(FTranslationID trans) +{ + assert(!IsLuminosityTranslation(trans)); + return (trans.index() & TRANSLATION_MASK); +} + +inline constexpr int GetTranslationType(int trans) +{ + assert(!IsLuminosityTranslation(trans)); + return (trans & TRANSLATIONTYPE_MASK) >> TRANSLATION_SHIFT; +} + +inline constexpr int GetTranslationIndex(int trans) +{ + assert(!IsLuminosityTranslation(trans)); + return (trans & TRANSLATION_MASK); +} + +class PaletteContainer +{ +public: + PalEntry BaseColors[256]; // non-gamma corrected palette + PalEntry RawColors[256]; // colors as read from the game data without the transparancy remap applied + uint8_t Remap[256]; // remap original palette indices to in-game indices + + uint8_t WhiteIndex; // white in original palette index + uint8_t BlackIndex; // black in original palette index + + bool HasGlobalBrightmap; + FRemapTable GlobalBrightmap; + FRemapTable GrayRamp; + FRemapTable GrayscaleMap; + FRemapTable IceMap; // This is used by the texture compositor so it must be globally accessible. + uint8_t GrayMap[256]; + + TArray uniqueRemaps; + +private: + FMemArena remapArena; + TArray> TranslationTables; +public: + void Init(int numslots, const uint8_t *indexmap); // This cannot be a constructor!!! + void SetPalette(const uint8_t* colors, int transparent_index = -1); + void Clear(); + int DetermineTranslucency(FileReader& file); + FRemapTable* AddRemap(FRemapTable* remap); + void UpdateTranslation(FTranslationID trans, FRemapTable* remap); + FTranslationID AddTranslation(int slot, FRemapTable* remap, int count = 1); + void CopyTranslation(FTranslationID dest, FTranslationID src); + FTranslationID StoreTranslation(int slot, FRemapTable* remap); + FRemapTable* TranslationToTable(int translation) const; + FRemapTable* TranslationToTable(FTranslationID translation) const + { + return TranslationToTable(translation.index()); + } + + void GenerateGlobalBrightmapFromColormap(const uint8_t* cmapdata, int numlevels); + + void PushIdentityTable(int slot) + { + AddTranslation(slot, nullptr); + } + + FRemapTable* GetTranslation(int slot, int index) const + { + if (TranslationTables.Size() <= (unsigned)slot) return nullptr; + return TranslationTables[slot].GetVal(index); + } + + void ClearTranslationSlot(int slot) + { + if (TranslationTables.Size() <= (unsigned)slot) return; + TranslationTables[slot].Clear(); + } + + unsigned NumTranslations(int slot) const + { + if (TranslationTables.Size() <= (unsigned)slot) return 0; + return TranslationTables[slot].Size(); + } + + +}; + +struct LuminosityTranslationDesc +{ + int colorrange; + int lum_min; + int lum_max; + + static LuminosityTranslationDesc fromInt(int translation) + { + LuminosityTranslationDesc t; + t.colorrange = (translation >> 16) & 0x3fff; + t.lum_min = (translation >> 8) & 0xff; + t.lum_max = translation & 0xff; + return t; + } + + static LuminosityTranslationDesc fromID(FTranslationID translation) + { + return fromInt(translation.index()); + } +}; + +extern PaletteContainer GPalette; + diff --git a/src/common/engine/printf.h b/src/common/engine/printf.h new file mode 100644 index 00000000000..990b199b907 --- /dev/null +++ b/src/common/engine/printf.h @@ -0,0 +1,95 @@ +#pragma once +#include + +#if defined __GNUC__ || defined __clang__ +# define ATTRIBUTE(attrlist) __attribute__(attrlist) +#else +# define ATTRIBUTE(attrlist) +#endif + +#include "stb_sprintf.h" + +// This header collects all things printf, so that this doesn't need to pull in other, far more dirty headers, just for outputting some text. +extern "C" int mysnprintf(char* buffer, size_t count, const char* format, ...) ATTRIBUTE((format(printf, 3, 4))); +extern "C" int myvsnprintf(char* buffer, size_t count, const char* format, va_list argptr) ATTRIBUTE((format(printf, 3, 0))); + +#define TEXTCOLOR_ESCAPE '\034' +#define TEXTCOLOR_ESCAPESTR "\034" + +#define TEXTCOLOR_BRICK "\034A" +#define TEXTCOLOR_TAN "\034B" +#define TEXTCOLOR_GRAY "\034C" +#define TEXTCOLOR_GREY "\034C" +#define TEXTCOLOR_GREEN "\034D" +#define TEXTCOLOR_BROWN "\034E" +#define TEXTCOLOR_GOLD "\034F" +#define TEXTCOLOR_RED "\034G" +#define TEXTCOLOR_BLUE "\034H" +#define TEXTCOLOR_ORANGE "\034I" +#define TEXTCOLOR_WHITE "\034J" +#define TEXTCOLOR_YELLOW "\034K" +#define TEXTCOLOR_UNTRANSLATED "\034L" +#define TEXTCOLOR_BLACK "\034M" +#define TEXTCOLOR_LIGHTBLUE "\034N" +#define TEXTCOLOR_CREAM "\034O" +#define TEXTCOLOR_OLIVE "\034P" +#define TEXTCOLOR_DARKGREEN "\034Q" +#define TEXTCOLOR_DARKRED "\034R" +#define TEXTCOLOR_DARKBROWN "\034S" +#define TEXTCOLOR_PURPLE "\034T" +#define TEXTCOLOR_DARKGRAY "\034U" +#define TEXTCOLOR_CYAN "\034V" +#define TEXTCOLOR_ICE "\034W" +#define TEXTCOLOR_FIRE "\034X" +#define TEXTCOLOR_SAPPHIRE "\034Y" +#define TEXTCOLOR_TEAL "\034Z" + +#define TEXTCOLOR_NORMAL "\034-" +#define TEXTCOLOR_BOLD "\034+" + +#define TEXTCOLOR_CHAT "\034*" +#define TEXTCOLOR_TEAMCHAT "\034!" + +// game print flags +enum +{ + PRINT_LOW, // pickup messages + PRINT_MEDIUM, // death messages + PRINT_HIGH, // critical messages + PRINT_CHAT, // chat messages + PRINT_TEAMCHAT, // chat messages from a teammate + PRINT_LOG, // only to logfile + PRINT_BOLD = 200, // What Printf_Bold used + PRINT_TYPES = 1023, // Bitmask. + PRINT_NONOTIFY = 1024, // Flag - do not add to notify buffer + PRINT_NOLOG = 2048, // Flag - do not print to log file + PRINT_NOTIFY = 4096, // Flag - add to game-native notify display - messages without this only go to the generic notification buffer. +}; + +enum +{ + DMSG_OFF, // no developer messages. + DMSG_ERROR, // general notification messages + DMSG_WARNING, // warnings + DMSG_NOTIFY, // general notification messages + DMSG_SPAMMY, // for those who want to see everything, regardless of its usefulness. +}; + + +[[noreturn]] void I_Error(const char *fmt, ...) ATTRIBUTE((format(printf,1,2))); +[[noreturn]] void I_FatalError(const char* fmt, ...) ATTRIBUTE((format(printf, 1, 2))); + +// This really could need some cleanup - the main problem is that it'd create +// lots of potential for merge conflicts. + +int PrintString (int iprintlevel, const char *outline); +int VPrintf(int printlevel, const char* format, va_list parms); +int Printf (int printlevel, const char *format, ...) ATTRIBUTE((format(printf,2,3))); +int Printf (const char *format, ...) ATTRIBUTE((format(printf,1,2))); +int DPrintf (int level, const char *format, ...) ATTRIBUTE((format(printf,2,3))); + +void I_DebugPrint(const char* cp); +void I_DebugPrintf(const char* fmt, ...); // Prints to the debugger's log. + +// flag to silence non-error output +extern bool batchrun; diff --git a/src/r_data/renderstyle.cpp b/src/common/engine/renderstyle.cpp similarity index 96% rename from src/r_data/renderstyle.cpp rename to src/common/engine/renderstyle.cpp index 80bc005396d..e31538b4f8a 100644 --- a/src/r_data/renderstyle.cpp +++ b/src/common/engine/renderstyle.cpp @@ -32,10 +32,9 @@ ** */ -#include "templates.h" +#include "basics.h" #include "renderstyle.h" #include "c_cvars.h" -#include "serializer.h" CVAR (Bool, r_drawtrans, true, 0) CVAR (Int, r_drawfuzz, 1, CVAR_ARCHIVE) @@ -158,8 +157,3 @@ void FRenderStyle::CheckFuzz() BlendOp = STYLEOP_Fuzz; } } - -FSerializer &Serialize(FSerializer &arc, const char *key, FRenderStyle &style, FRenderStyle *def) -{ - return arc.Array(key, &style.BlendOp, def ? &def->BlendOp : nullptr, 4); -} diff --git a/src/r_data/renderstyle.h b/src/common/engine/renderstyle.h similarity index 97% rename from src/r_data/renderstyle.h rename to src/common/engine/renderstyle.h index 64326fd3c0f..19d788e2ced 100644 --- a/src/r_data/renderstyle.h +++ b/src/common/engine/renderstyle.h @@ -39,10 +39,7 @@ #undef OPAQUE #endif -enum -{ - OPAQUE = 65536, -}; +constexpr int OPAQUE = 65536; enum ETexMode { @@ -58,7 +55,7 @@ enum ETexMode }; // Legacy render styles -enum ERenderStyle +enum ERenderStyle : int { STYLE_None, // Do not draw STYLE_Normal, // Normal; just copy the image to the screen @@ -109,6 +106,8 @@ enum ERenderAlpha STYLEALPHA_InvSrcCol, // Blend factor is 1.0 - color (HWR only) STYLEALPHA_DstCol, // Blend factor is dest. color (HWR only) STYLEALPHA_InvDstCol, // Blend factor is 1.0 - dest. color (HWR only) + STYLEALPHA_Dst, // Blend factor is dest. alpha + STYLEALPHA_InvDst, // Blend factor is 1.0 - dest. alpha STYLEALPHA_MAX }; diff --git a/src/utility/sc_man.cpp b/src/common/engine/sc_man.cpp similarity index 78% rename from src/utility/sc_man.cpp rename to src/common/engine/sc_man.cpp index faea890a204..ac7b4799f77 100644 --- a/src/utility/sc_man.cpp +++ b/src/common/engine/sc_man.cpp @@ -37,15 +37,19 @@ #include #include -#include "doomtype.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "sc_man.h" -#include "w_wad.h" #include "cmdlib.h" -#include "templates.h" -#include "doomstat.h" + +#include "printf.h" +#include "name.h" #include "v_text.h" +#include "zstring.h" +#include "name.h" +#include +#include "filesystem.h" + // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- @@ -95,106 +99,23 @@ void VersionInfo::operator=(const char *string) // //========================================================================== -FScanner::FScanner() +FScanner::FScanner(TMap* extsymbols) : symbols(extsymbols? *extsymbols : mysymbols) { ScriptOpen = false; } -//========================================================================== -// -// FScanner Destructor -// -//========================================================================== - -FScanner::~FScanner() -{ - // Humm... Nothing to do in here. -} - -//========================================================================== -// -// FScanner Copy Constructor -// -//========================================================================== - -FScanner::FScanner(const FScanner &other) -{ - ScriptOpen = false; - *this = other; -} - //========================================================================== // // FScanner OpenLumpNum Constructor // //========================================================================== -FScanner::FScanner(int lumpnum) +FScanner::FScanner(int lumpnum, TMap* extsymbols) : symbols(extsymbols ? *extsymbols : mysymbols) { ScriptOpen = false; OpenLumpNum(lumpnum); } -//========================================================================== -// -// FScanner :: operator = -// -//========================================================================== - -FScanner &FScanner::operator=(const FScanner &other) -{ - if (this == &other) - { - return *this; - } - if (!other.ScriptOpen) - { - Close(); - return *this; - } - - // Copy protected members - ScriptOpen = true; - ScriptName = other.ScriptName; - ScriptBuffer = other.ScriptBuffer; - ScriptPtr = other.ScriptPtr; - ScriptEndPtr = other.ScriptEndPtr; - AlreadyGot = other.AlreadyGot; - AlreadyGotLine = other.AlreadyGotLine; - LastGotToken = other.LastGotToken; - LastGotPtr = other.LastGotPtr; - LastGotLine = other.LastGotLine; - CMode = other.CMode; - Escape = other.Escape; - StateMode = other.StateMode; - StateOptions = other.StateOptions; - - // Copy public members - if (other.String == other.StringBuffer) - { - memcpy(StringBuffer, other.StringBuffer, sizeof(StringBuffer)); - BigStringBuffer = ""; - String = StringBuffer; - } - else - { - // Past practice means the string buffer must be writeable, which - // removes some of the benefit from using an FString to store - // the big string buffer. - BigStringBuffer = other.BigStringBuffer; - String = BigStringBuffer.LockBuffer(); - } - StringLen = other.StringLen; - TokenType = other.TokenType; - Number = other.Number; - Float = other.Float; - Line = other.Line; - End = other.End; - Crossed = other.Crossed; - - return *this; -} - //========================================================================== // // FScanner :: Open @@ -203,7 +124,7 @@ FScanner &FScanner::operator=(const FScanner &other) void FScanner::Open (const char *name) { - int lump = Wads.CheckNumForFullName(name, true); + int lump = fileSystem.CheckNumForFullName(name, true); if (lump == -1) { I_Error("Could not find script lump '%s'\n", name); @@ -215,7 +136,7 @@ void FScanner::Open (const char *name) // // FScanner :: OpenFile // -// Loads a script from a file. Uses new/delete for memory allocation. +// Loads a script from a file. // //========================================================================== @@ -227,9 +148,9 @@ bool FScanner::OpenFile (const char *name) if (!fr.OpenFile(name)) return false; auto filesize = fr.GetLength(); auto filebuff = fr.Read(); - if (filebuff.Size() == 0 && filesize > 0) return false; + if (filebuff.size() == 0 && filesize > 0) return false; - ScriptBuffer = FString((const char *)filebuff.Data(), filesize); + ScriptBuffer = FString(filebuff.string(), filesize); ScriptName = name; // This is used for error messages so the full file name is preferable LumpNum = -1; PrepareScript (); @@ -279,10 +200,13 @@ void FScanner :: OpenLumpNum (int lump) { Close (); { - FMemLump mem = Wads.ReadLump(lump); - ScriptBuffer = mem.GetString(); + auto len = fileSystem.FileLength(lump); + auto buff = ScriptBuffer.LockNewBuffer(len); + fileSystem.ReadFile(lump, buff); + buff[len] = 0; + ScriptBuffer.UnlockBuffer(); } - ScriptName = Wads.GetLumpFullPath(lump); + ScriptName = fileSystem.GetFileFullPath(lump).c_str(); LumpNum = lump; PrepareScript (); } @@ -297,6 +221,12 @@ void FScanner :: OpenLumpNum (int lump) void FScanner::PrepareScript () { + // If the file got a UTF-8 byte order mark, remove that. + if (ScriptBuffer.Len() > 3 && ScriptBuffer[0] == (char)0xEF && ScriptBuffer[1] == (char)0xBB && ScriptBuffer[2] == (char)0xBF) + { + ScriptBuffer = ScriptBuffer.Mid(3); + } + // The scanner requires the file to end with a '\n', so add one if // it doesn't already. if (ScriptBuffer.Len() == 0 || ScriptBuffer.Back() != '\n') @@ -330,6 +260,7 @@ void FScanner::PrepareScript () StateOptions = false; StringBuffer[0] = '\0'; BigStringBuffer = ""; + ParseError = false; } //========================================================================== @@ -397,6 +328,13 @@ void FScanner::RestorePos (const FScanner::SavedPos &pos) Crossed = false; } +long long FScanner::mystrtoll(const char* p, char** endp, int base) +{ + // Do not treat a leading 0 as an octal identifier if so desired. + if (NoOctals && *p == '0' && p[1] != 'x' && p[1] != 'X' && base == 0) base = 10; + return strtoll(p, endp, base); +} + //========================================================================== // // FScanner :: isText @@ -488,6 +426,7 @@ bool FScanner::ScanString (bool tokens) const char *marker, *tok; bool return_val; + ParseError = false; CheckOpen(); if (AlreadyGot) { @@ -511,7 +450,7 @@ bool FScanner::ScanString (bool tokens) LastGotLine = Line; // In case the generated scanner does not use marker, avoid compiler warnings. - marker; + // marker; #include "sc_man_scanner.h" LastGotToken = tokens; return return_val; @@ -587,7 +526,7 @@ bool FScanner::CheckString (const char *name) // //========================================================================== -bool FScanner::GetToken () +bool FScanner::GetToken (bool evaluate) { if (ScanString (true)) { @@ -605,7 +544,7 @@ bool FScanner::GetToken () } else { - BigNumber = strtoll(String, &stopper, 0); + BigNumber = mystrtoll(String, &stopper, 0); Number = (int)BigNumber;// clamp(BigNumber, 0, UINT_MAX); Float = Number; } @@ -617,7 +556,19 @@ bool FScanner::GetToken () } else if (TokenType == TK_StringConst) { - StringLen = strbin(String); + StringLen = strbin(const_cast(String)); + } + else if (TokenType == TK_Identifier && evaluate && symbols.CountUsed() > 0) + { + auto sym = symbols.CheckKey(String); + if (sym) + { + TokenType = sym->tokenType; + BigNumber = sym->Number; + Number = (int)sym->Number; + Float = sym->Float; + // String will retain the actual symbol name. + } } return true; } @@ -630,9 +581,9 @@ bool FScanner::GetToken () // //========================================================================== -void FScanner::MustGetAnyToken (void) +void FScanner::MustGetAnyToken (bool evaluate) { - if (GetToken () == false) + if (GetToken (evaluate) == false) { ScriptError ("Missing token (unexpected end of file)."); } @@ -660,9 +611,9 @@ void FScanner::TokenMustBe (int token) // //========================================================================== -void FScanner::MustGetToken (int token) +void FScanner::MustGetToken (int token, bool evaluate) { - MustGetAnyToken (); + MustGetAnyToken (evaluate); TokenMustBe(token); } @@ -675,9 +626,9 @@ void FScanner::MustGetToken (int token) // //========================================================================== -bool FScanner::CheckToken (int token) +bool FScanner::CheckToken (int token, bool evaluate) { - if (GetToken ()) + if (GetToken (evaluate)) { if (TokenType == token) { @@ -694,7 +645,7 @@ bool FScanner::CheckToken (int token) // //========================================================================== -bool FScanner::GetNumber () +bool FScanner::GetNumber (bool evaluate) { char *stopper; @@ -707,11 +658,25 @@ bool FScanner::GetNumber () } else { - BigNumber = strtoll(String, &stopper, 0); + BigNumber = mystrtoll(String, &stopper, 0); Number = (int)BigNumber;// clamp(BigNumber, 0, UINT_MAX); if (*stopper != 0) { + if (evaluate && symbols.CountUsed()) + { + auto sym = symbols.CheckKey(String); + if (sym && sym->tokenType == TK_IntConst) + { + BigNumber = sym->Number; + Number = (int)sym->Number; + Float = sym->Float; + // String will retain the actual symbol name. + return true; + } + + } ScriptError ("SC_GetNumber: Bad numeric constant \"%s\".", String); + return false; } } Float = Number; @@ -729,9 +694,9 @@ bool FScanner::GetNumber () // //========================================================================== -void FScanner::MustGetNumber () +void FScanner::MustGetNumber (bool evaluate) { - if (GetNumber() == false) + if (GetNumber(evaluate) == false) { ScriptError ("Missing integer (unexpected end of file)."); } @@ -746,7 +711,7 @@ void FScanner::MustGetNumber () // //========================================================================== -bool FScanner::CheckNumber () +bool FScanner::CheckNumber (bool evaluate) { char *stopper; @@ -764,10 +729,23 @@ bool FScanner::CheckNumber () } else { - BigNumber = strtoll (String, &stopper, 0); + BigNumber = mystrtoll (String, &stopper, 0); Number = (int)BigNumber;// clamp(BigNumber, 0, UINT_MAX); if (*stopper != 0) { + if (evaluate && symbols.CountUsed()) + { + auto sym = symbols.CheckKey(String); + if (sym && sym->tokenType == TK_IntConst) + { + BigNumber = sym->Number; + Number = (int)sym->Number; + Float = sym->Float; + // String will retain the actual symbol name. + return true; + } + + } UnGet(); return false; } @@ -789,7 +767,7 @@ bool FScanner::CheckNumber () // //========================================================================== -bool FScanner::CheckFloat () +bool FScanner::CheckFloat (bool evaluate) { char *stopper; @@ -800,10 +778,24 @@ bool FScanner::CheckFloat () UnGet(); return false; } - + Float = strtod (String, &stopper); if (*stopper != 0) { + if (evaluate && symbols.CountUsed()) + { + auto sym = symbols.CheckKey(String); + if (sym && sym->tokenType == TK_IntConst && sym->tokenType != TK_FloatConst) + { + BigNumber = sym->Number; + Number = (int)sym->Number; + Float = sym->Float; + // String will retain the actual symbol name. + return true; + } + + } + UnGet(); return false; } @@ -822,7 +814,7 @@ bool FScanner::CheckFloat () // //========================================================================== -bool FScanner::GetFloat () +bool FScanner::GetFloat (bool evaluate) { char *stopper; @@ -832,7 +824,21 @@ bool FScanner::GetFloat () Float = strtod (String, &stopper); if (*stopper != 0) { + if (evaluate && symbols.CountUsed()) + { + auto sym = symbols.CheckKey(String); + if (sym && sym->tokenType == TK_IntConst && sym->tokenType != TK_FloatConst) + { + BigNumber = sym->Number; + Number = (int)sym->Number; + Float = sym->Float; + // String will retain the actual symbol name. + return true; + } + } + ScriptError ("SC_GetFloat: Bad numeric constant \"%s\".", String); + return false; } Number = (int)Float; return true; @@ -849,9 +855,9 @@ bool FScanner::GetFloat () // //========================================================================== -void FScanner::MustGetFloat () +void FScanner::MustGetFloat (bool evaluate) { - if (GetFloat() == false) + if (GetFloat(evaluate) == false) { ScriptError ("Missing floating-point number (unexpected end of file)."); } @@ -935,44 +941,54 @@ bool FScanner::Compare (const char *text) // //========================================================================== -bool FScanner::ScanValue(bool allowfloat) +bool FScanner::ScanValue(bool allowfloat, bool evaluate) { bool neg = false; - if (!GetToken()) + if (!GetToken(evaluate)) { return false; } if (TokenType == '-' || TokenType == '+') { neg = TokenType == '-'; - if (!GetToken()) + if (!GetToken(evaluate)) { return false; } } - if (TokenType != TK_IntConst && (TokenType != TK_FloatConst || !allowfloat)) - { + + if (TokenType == TK_FloatConst && !allowfloat) return false; + + if (TokenType != TK_IntConst && TokenType != TK_FloatConst) + { + auto d = constants.CheckKey(String); + if (!d) return false; + if (!allowfloat && int64_t(*d) != *d) return false; + BigNumber = int64_t(*d); + Number = int(*d); + Float = *d; } if (neg) { + BigNumber = -BigNumber; Number = -Number; Float = -Float; } return true; } -bool FScanner::CheckValue(bool allowfloat) +bool FScanner::CheckValue(bool allowfloat, bool evaluate) { auto savedstate = SavePos(); - bool res = ScanValue(allowfloat); + bool res = ScanValue(allowfloat, evaluate); if (!res) RestorePos(savedstate); return res; } -void FScanner::MustGetValue(bool allowfloat) +void FScanner::MustGetValue(bool allowfloat, bool evaluate) { - if (!ScanValue(allowfloat)) ScriptError(allowfloat ? "Numeric constant expected" : "Integer constant expected"); + if (!ScanValue(allowfloat, evaluate)) ScriptError(allowfloat ? "Numeric constant expected" : "Integer constant expected"); } bool FScanner::CheckBoolToken() @@ -1036,9 +1052,7 @@ FString FScanner::TokenName (int token, const char *string) } else { - FString work; - work.Format ("Unknown(%d)", token); - return work; + work.Format("Unknown(%d)", token); } return work; } @@ -1076,7 +1090,14 @@ void FScanner::ScriptError (const char *message, ...) va_end (arglist); } - I_Error ("Script error, \"%s\" line %d:\n%s\n", ScriptName.GetChars(), + ParseError = true; + if (NoFatalErrors) + { + Printf(TEXTCOLOR_RED "%sScript error, \"%s\"" TEXTCOLOR_RED " line %d:\n" TEXTCOLOR_RED "%s\n", PrependMessage.GetChars(), ScriptName.GetChars(), + AlreadyGot ? AlreadyGotLine : Line, composed.GetChars()); + return; + } + I_Error ("%sScript error, \"%s\" line %d:\n%s\n", PrependMessage.GetChars(), ScriptName.GetChars(), AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); } @@ -1102,7 +1123,8 @@ void FScanner::ScriptMessage (const char *message, ...) va_end (arglist); } - Printf (TEXTCOLOR_RED "Script error, \"%s\"" TEXTCOLOR_RED " line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), + ParseError = true; + Printf (TEXTCOLOR_RED "%sScript error, \"%s\"" TEXTCOLOR_RED " line %d:\n" TEXTCOLOR_RED "%s\n", PrependMessage.GetChars(), ScriptName.GetChars(), AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); } @@ -1116,10 +1138,112 @@ void FScanner::CheckOpen() { if (ScriptOpen == false) { - I_FatalError ("SC_ call before SC_Open()."); + I_Error ("SC_ call before SC_Open()."); } } +//========================================================================== +// +// +// +//========================================================================== + +void FScanner::AddSymbol(const char *name, int64_t value) +{ + Symbol sym; + sym.tokenType = TK_IntConst; + sym.Number = value; + sym.Float = double(value); + symbols.Insert(name, sym); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FScanner::AddSymbol(const char* name, uint64_t value) +{ + Symbol sym; + sym.tokenType = TK_UIntConst; + sym.Number = value; + sym.Float = (double)value; + symbols.Insert(name, sym); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FScanner::SkipToEndOfBlock() +{ + int depth = 0; + while (1) + { + MustGetString(); // this will abort if it reaches the end of the file + if (Compare("{")) depth++; + else if (Compare("}")) + { + depth--; + if (depth < 0) return; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FScanner::AddSymbol(const char* name, double value) +{ + Symbol sym; + sym.tokenType = TK_FloatConst; + sym.Number = (int64_t)value; + sym.Float = value; + symbols.Insert(name, sym); +} + +//========================================================================== +// +// +// +//========================================================================== + +int FScanner::StartBraces(FScanner::SavedPos* braceend) +{ + if (CheckString("{")) + { + auto here = SavePos(); + SkipToEndOfBlock(); + *braceend = SavePos(); + RestorePos(here); + return 0; + } + else + { + ScriptError("'{' expected"); + return -1; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FScanner::FoundEndBrace(FScanner::SavedPos& braceend) +{ + auto here = SavePos(); + return here.SavedScriptPtr >= braceend.SavedScriptPtr; +} + + //========================================================================== // // a class that remembers a parser position @@ -1127,6 +1251,7 @@ void FScanner::CheckOpen() //========================================================================== int FScriptPosition::ErrorCounter; int FScriptPosition::WarnCounter; +int FScriptPosition::Developer; bool FScriptPosition::StrictErrors; // makes all OPTERROR messages real errors. bool FScriptPosition::errorout; // call I_Error instead of printing the error itself. @@ -1156,19 +1281,17 @@ FScriptPosition &FScriptPosition::operator=(FScanner &sc) // //========================================================================== -CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) - void FScriptPosition::Message (int severity, const char *message, ...) const { FString composed; - if (severity == MSG_DEBUGLOG && developer < DMSG_NOTIFY) return; - if (severity == MSG_DEBUGERROR && developer < DMSG_ERROR) return; - if (severity == MSG_DEBUGWARN && developer < DMSG_WARNING) return; - if (severity == MSG_DEBUGMSG && developer < DMSG_NOTIFY) return; + if (severity == MSG_DEBUGLOG && Developer < DMSG_NOTIFY) return; + if (severity == MSG_DEBUGERROR && Developer < DMSG_ERROR) return; + if (severity == MSG_DEBUGWARN && Developer < DMSG_WARNING) return; + if (severity == MSG_DEBUGMSG && Developer < DMSG_NOTIFY) return; if (severity == MSG_OPTERROR) { - severity = StrictErrors || strictdecorate ? MSG_ERROR : MSG_WARNING; + severity = StrictErrors? MSG_ERROR : MSG_WARNING; } // This is mainly for catching the error with an exception handler. if (severity == MSG_ERROR && errorout) severity = MSG_FATAL; @@ -1263,4 +1386,3 @@ int ParseHex(const char* hex, FScriptPosition* sc) return num; } - diff --git a/src/common/engine/sc_man.h b/src/common/engine/sc_man.h new file mode 100644 index 00000000000..5873523a12c --- /dev/null +++ b/src/common/engine/sc_man.h @@ -0,0 +1,314 @@ +#ifndef __SC_MAN_H__ +#define __SC_MAN_H__ + +#include +#include "zstring.h" +#include "tarray.h" +#include "name.h" +#include "basics.h" + +struct VersionInfo +{ + uint16_t major; + uint16_t minor; + uint32_t revision; + + constexpr bool operator <=(const VersionInfo& o) const + { + return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision >= this->revision); + } + constexpr bool operator >=(const VersionInfo& o) const + { + return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision <= this->revision); + } + constexpr bool operator > (const VersionInfo& o) const + { + return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision < this->revision); + } + constexpr bool operator < (const VersionInfo& o) const + { + return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision > this->revision); + } + void operator=(const char* string); +}; + +// Cannot be a constructor because Lemon would puke on it. +constexpr VersionInfo MakeVersion(unsigned int ma, unsigned int mi, unsigned int re = 0) +{ + return{ (uint16_t)ma, (uint16_t)mi, (uint32_t)re }; +} + + +class FScanner +{ +public: + struct SavedPos + { + const char *SavedScriptPtr; + int SavedScriptLine; + }; + + struct Symbol + { + int tokenType; + int64_t Number; + double Float; + }; + + using SymbolMap = TMap; + + SymbolMap mysymbols; + SymbolMap& symbols; + TMap& GetSymbols() { return symbols; } + + // Methods ------------------------------------------------------ + FScanner(TMap* extsymbols = nullptr); + FScanner(const FScanner& other) = delete; + FScanner& operator=(const FScanner& other) = delete; + FScanner(int lumpnum, TMap* extsymbols = nullptr); + ~FScanner() = default; + + void Open(const char *lumpname); + bool OpenFile(const char *filename); + void OpenMem(const char *name, const char *buffer, int size); + template + void OpenMem(const char* name, const T& buffer) + { + static_assert(sizeof(typename T::value_type) == 1); + OpenMem(name, (const char*)buffer.data(), (int)buffer.size()); + } + void OpenString(const char *name, FString buffer); + void OpenLumpNum(int lump); + void Close(); + void SetParseVersion(VersionInfo ver) + { + ParseVersion = ver; + } + + void SetCMode(bool cmode); + void SetNoOctals(bool cmode) { NoOctals = cmode; } + void SetNoFatalErrors(bool cmode) { NoFatalErrors = cmode; } + void SetEscape(bool esc); + void SetStateMode(bool stately); + void DisableStateOptions(); + const SavedPos SavePos(); + void RestorePos(const SavedPos &pos); + void AddSymbol(const char* name, int64_t value); + void AddSymbol(const char* name, uint64_t value); + inline void AddSymbol(const char* name, int32_t value) { return AddSymbol(name, int64_t(value)); } + inline void AddSymbol(const char* name, uint32_t value) { return AddSymbol(name, uint64_t(value)); } + void AddSymbol(const char* name, double value); + void SkipToEndOfBlock(); + int StartBraces(FScanner::SavedPos* braceend); + bool FoundEndBrace(FScanner::SavedPos& braceend); + + static FString TokenName(int token, const char *string=NULL); + + bool GetString(); + void MustGetString(); + void MustGetStringName(const char *name); + bool CheckString(const char *name); + + bool GetToken(bool evaluate = false); + void MustGetAnyToken(bool evaluate = false); + void TokenMustBe(int token); + void MustGetToken(int token, bool evaluate = false); + bool CheckToken(int token, bool evaluate = false); + bool CheckTokenId(ENamedName id); + + bool GetNumber(bool evaluate = false); + void MustGetNumber(bool evaluate = false); + bool CheckNumber(bool evaluate = false); + + bool GetNumber(int16_t& var, bool evaluate = false) + { + if (!GetNumber(evaluate)) return false; + var = Number; + return true; + } + + bool GetNumber(int& var, bool evaluate = false) + { + if (!GetNumber(evaluate)) return false; + var = Number; + return true; + } + + bool GetNumber(int64_t& var, bool evaluate = false) + { + if (!GetNumber(evaluate)) return false; + var = BigNumber; + return true; + } + + bool GetString(FString& var) + { + if (!GetString()) return false; + var = String; + return true; + } + + bool GetFloat(bool evaluate = false); + + bool GetFloat(double& var, bool evaluate = false) + { + if (!GetFloat(evaluate)) return false; + var = Float; + return true; + } + + bool GetFloat(float& var, bool evaluate = false) + { + if (!GetFloat(evaluate)) return false; + var = float(Float); + return true; + } + + void MustGetFloat(bool evaluate = false); + bool CheckFloat(bool evaluate = false); + + Symbol *LookupSymbol(FName name) + { + return symbols.CheckKey(name); + } + + // Token based variant + bool CheckValue(bool allowfloat, bool evaluate = true); + void MustGetValue(bool allowfloat, bool evaluate = true); + bool CheckBoolToken(); + void MustGetBoolToken(); + + void UnGet(); + + bool Compare(const char *text); + inline bool Compare(const std::initializer_list& list) + { + for (auto c : list) if (Compare(c)) return true; + return false; + } + int MatchString(const char * const *strings, size_t stride = sizeof(char*)); + int MustMatchString(const char * const *strings, size_t stride = sizeof(char*)); + int GetMessageLine(); + + void ScriptError(const char *message, ...) GCCPRINTF(2,3); + void ScriptMessage(const char *message, ...) GCCPRINTF(2,3); + void SetPrependMessage(const FString& message) { PrependMessage = message; } + + bool isText(); + + // Members ------------------------------------------------------ + char *String; + int StringLen; + int TokenType; + int Number; + int64_t BigNumber; + double Float; + int Line; + bool End; + bool ParseError = false; + bool Crossed; + int LumpNum; + FString ScriptName; + +protected: + long long mystrtoll(const char* p, char** endp, int base); + void PrepareScript(); + void CheckOpen(); + bool ScanString(bool tokens); + + // Strings longer than this minus one will be dynamically allocated. + static const int MAX_STRING_SIZE = 128; + + TMap constants; + + bool ScriptOpen; + FString ScriptBuffer; + const char *ScriptPtr; + const char *ScriptEndPtr; + char StringBuffer[MAX_STRING_SIZE]; + FString BigStringBuffer; + bool AlreadyGot; + int AlreadyGotLine; + bool LastGotToken; + const char *LastGotPtr; + int LastGotLine; + bool CMode; + bool NoOctals = false; + bool NoFatalErrors = false; + uint8_t StateMode; + bool StateOptions; + bool Escape; + VersionInfo ParseVersion = { 0, 0, 0 }; // no ZScript extensions by default + FString PrependMessage = ""; + + + bool ScanValue(bool allowfloat, bool evaluate); +}; + +enum +{ + TK_SequenceStart = 256, +#define xx(sym,str) sym, +#include "sc_man_tokens.h" + TK_LastToken +}; + + +//========================================================================== +// +// +// +//========================================================================== + +enum +{ + MSG_WARNING, + MSG_FATAL, + MSG_ERROR, + MSG_OPTERROR, + MSG_DEBUGERROR, + MSG_DEBUGWARN, + MSG_DEBUGMSG, + MSG_LOG, + MSG_DEBUGLOG, + MSG_MESSAGE +}; + +//========================================================================== +// +// a class that remembers a parser position +// +//========================================================================== + +struct FScriptPosition +{ + static int WarnCounter; + static int ErrorCounter; + static bool StrictErrors; + static int Developer; + static bool errorout; + FName FileName; + int ScriptLine; + + FScriptPosition() + { + FileName = NAME_None; + ScriptLine=0; + } + FScriptPosition(const FScriptPosition &other) = default; + FScriptPosition(FString fname, int line); + FScriptPosition(FScanner &sc); + FScriptPosition &operator=(const FScriptPosition &other) = default; + FScriptPosition &operator=(FScanner &sc); + void Message(int severity, const char *message,...) const GCCPRINTF(3,4); + static void ResetErrorCounter() + { + WarnCounter = 0; + ErrorCounter = 0; + } +}; + +int ParseHex(const char* hex, FScriptPosition* sc); + + +#endif //__SC_MAN_H__ diff --git a/src/utility/sc_man_scanner.re b/src/common/engine/sc_man_scanner.re similarity index 96% rename from src/utility/sc_man_scanner.re rename to src/common/engine/sc_man_scanner.re index 019327807d9..5af7e62f933 100644 --- a/src/utility/sc_man_scanner.re +++ b/src/common/engine/sc_man_scanner.re @@ -102,14 +102,14 @@ std2: ":" { RET(':'); } ";" { RET(';'); } "}" { StateMode = 0; StateOptions = false; RET('}'); } - + WSP+ { goto std1; } "\n" { goto newline; } - + TOKS = (NWS\[/":;}]); TOKS* ([/] (TOKS\[*]) TOKS*)* { RET(TK_NonWhitespace); } - + */ } else if (tokens) // A well-defined scanner, based on the c.re example. @@ -159,7 +159,7 @@ std2: 'class' { RET(TK_Class); } 'mixin' { RET(TK_Mixin); } 'enum' { RET(TK_Enum); } - 'name' { RET(TK_Name); } + 'name' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Name : TK_Identifier); } 'string' { RET(TK_String); } 'sound' { RET(TK_Sound); } 'state' { RET(TK_State); } @@ -167,14 +167,16 @@ std2: 'vector2' { RET(TK_Vector2); } 'vector3' { RET(TK_Vector3); } 'map' { RET(TK_Map); } + 'mapiterator' { RET(ParseVersion >= MakeVersion(4, 10, 0)? TK_MapIterator : TK_Identifier); } 'array' { RET(TK_Array); } + 'function' { RET(ParseVersion >= MakeVersion(4, 12, 0)? TK_FunctionType : TK_Identifier); } 'in' { RET(TK_In); } 'sizeof' { RET(TK_SizeOf); } 'alignof' { RET(TK_AlignOf); } /* Other keywords from UnrealScript */ 'abstract' { RET(TK_Abstract); } - 'foreach' { RET(TK_ForEach); } + 'foreach' { RET(ParseVersion >= MakeVersion(4, 10, 0)? TK_ForEach : TK_Identifier); } 'true' { RET(TK_True); } 'false' { RET(TK_False); } 'none' { RET(TK_None); } @@ -202,6 +204,8 @@ std2: 'super' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Super : TK_Identifier); } 'stop' { RET(TK_Stop); } 'null' { RET(TK_Null); } + 'nullptr' { RET(ParseVersion >= MakeVersion(4, 9, 0)? TK_Null : TK_Identifier); } + 'sealed' { RET(ParseVersion >= MakeVersion(4, 12, 0)? TK_Sealed : TK_Identifier); } 'is' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Is : TK_Identifier); } 'replaces' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Replaces : TK_Identifier); } @@ -218,11 +222,12 @@ std2: 'bright' { RET(StateOptions ? TK_Bright : TK_Identifier); } 'fast' { RET(StateOptions ? TK_Fast : TK_Identifier); } 'slow' { RET(StateOptions ? TK_Slow : TK_Identifier); } + 'ticadjust' { RET(StateOptions ? TK_NoDelay : TK_Identifier); } 'nodelay' { RET(StateOptions ? TK_NoDelay : TK_Identifier); } 'canraise' { RET(StateOptions ? TK_CanRaise : TK_Identifier); } 'offset' { RET(StateOptions ? TK_Offset : TK_Identifier); } 'light' { RET(StateOptions ? TK_Light : TK_Identifier); } - + /* other DECORATE top level keywords */ '#include' { RET(TK_Include); } diff --git a/src/utility/sc_man_tokens.h b/src/common/engine/sc_man_tokens.h similarity index 97% rename from src/utility/sc_man_tokens.h rename to src/common/engine/sc_man_tokens.h index 5aa6360fe9a..48700312517 100644 --- a/src/utility/sc_man_tokens.h +++ b/src/common/engine/sc_man_tokens.h @@ -122,13 +122,16 @@ xx(TK_Null, "'null'") xx(TK_Global, "'global'") xx(TK_Stop, "'stop'") xx(TK_Include, "'include'") +xx(TK_Sealed, "'sealed'") xx(TK_Is, "'is'") xx(TK_Replaces, "'replaces'") xx(TK_Vector2, "'vector2'") xx(TK_Vector3, "'vector3'") xx(TK_Map, "'map'") +xx(TK_MapIterator, "'mapiterator'") xx(TK_Array, "'array'") +xx(TK_FunctionType, "'function'") xx(TK_In, "'in'") xx(TK_SizeOf, "'sizeof'") xx(TK_AlignOf, "'alignof'") diff --git a/src/common/engine/serialize_obj.h b/src/common/engine/serialize_obj.h new file mode 100644 index 00000000000..c818d08fa4e --- /dev/null +++ b/src/common/engine/serialize_obj.h @@ -0,0 +1,17 @@ +#pragma once + +// These are in a separate header because they require some rather 'dirty' headers to work which should not be part of serializer.h + +template +FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, TObjPtr *) +{ + Serialize(arc, key, value.o, nullptr); + return arc; +} + +template +FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, T *) +{ + Serialize(arc, key, value.o, nullptr); + return arc; +} diff --git a/src/common/engine/serializer.cpp b/src/common/engine/serializer.cpp new file mode 100644 index 00000000000..dcf93084287 --- /dev/null +++ b/src/common/engine/serializer.cpp @@ -0,0 +1,1793 @@ +/* +** serializer.cpp +** Savegame wrapper around RapidJSON +** +**--------------------------------------------------------------------------- +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 // disable this insanity which is bound to make the code break over time. +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag + +#include +#include "rapidjson/rapidjson.h" +#include "rapidjson/writer.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/document.h" +#include "serializer.h" +#include "dobject.h" +#include "filesystem.h" +#include "v_font.h" +#include "v_text.h" +#include "cmdlib.h" +#include "utf8.h" +#include "printf.h" +#include "s_soundinternal.h" +#include "engineerrors.h" +#include "textures.h" +#include "texturemanager.h" +#include "base64.h" +#include "vm.h" +#include "i_interface.h" + +using namespace FileSys; + +extern DObject *WP_NOCHANGE; +bool save_full = false; // for testing. Should be removed afterward. + +#include "serializer_internal.h" + +//========================================================================== +// +// This will double-encode already existing UTF-8 content. +// The reason for this behavior is to preserve any original data coming through here, no matter what it is. +// If these are script-based strings, exact preservation in the serializer is very important. +// +//========================================================================== + +static TArray out; +const char *StringToUnicode(const char *cc, int size) +{ + int ch; + const uint8_t *c = (const uint8_t*)cc; + int count = 0; + int count1 = 0; + out.Clear(); + while ((ch = (*c++) & 255)) + { + count1++; + if (ch >= 128) count += 2; + else count++; + if (count1 == size && size > 0) break; + } + if (count == count1) return cc; // string is pure ASCII. + // we need to convert + out.Resize(count + 1); + out.Last() = 0; + c = (const uint8_t*)cc; + int i = 0; + while ((ch = (*c++))) + { + utf8_encode(ch, (uint8_t*)&out[i], &count1); + i += count1; + } + return &out[0]; +} + +const char *UnicodeToString(const char *cc) +{ + out.Resize((unsigned)strlen(cc) + 1); + int ndx = 0; + while (*cc != 0) + { + int size; + int c = utf8_decode((const uint8_t*)cc, &size); + if (c < 0 || c > 255) c = '?'; // This should never happen because all content was encoded with StringToUnicode which only produces code points 0-255. + out[ndx++] = c; + cc += size; + } + out[ndx] = 0; + return &out[0]; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::OpenWriter(bool pretty) +{ + if (w != nullptr || r != nullptr) return false; + + mErrors = 0; + w = new FWriter(pretty); + BeginObject(nullptr); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::OpenReader(const char *buffer, size_t length) +{ + if (w != nullptr || r != nullptr) return false; + + mErrors = 0; + r = new FReader(buffer, length); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::OpenReader(FCompressedBuffer *input) +{ + if (input->mSize <= 0 || input->mBuffer == nullptr) return false; + if (w != nullptr || r != nullptr) return false; + + mErrors = 0; + if (input->mMethod == METHOD_STORED) + { + r = new FReader((char*)input->mBuffer, input->mSize); + } + else + { + TArray unpacked(input->mSize); + input->Decompress(unpacked.Data()); + r = new FReader(unpacked.Data(), input->mSize); + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::Close() +{ + if (w == nullptr && r == nullptr) return; // double close? This should skip the I_Error at the bottom. + + if (w != nullptr) + { + delete w; + w = nullptr; + } + if (r != nullptr) + { + CloseReaderCustom(); + delete r; + r = nullptr; + } + if (mErrors > 0) + { + I_Error("%d errors parsing JSON", mErrors); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +unsigned FSerializer::ArraySize() +{ + if (r != nullptr && r->mObjects.Last().mObject->IsArray()) + { + return r->mObjects.Last().mObject->Size(); + } + else + { + return 0; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::canSkip() const +{ + return isWriting() && w->inObject(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::WriteKey(const char *key) +{ + if (isWriting() && w->inObject()) + { + assert(key != nullptr); + if (key == nullptr) + { + I_Error("missing element name"); + } + w->Key(key); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::BeginObject(const char *name) +{ + if (isWriting()) + { + WriteKey(name); + w->StartObject(); + w->mInObject.Push(true); + } + else + { + auto val = r->FindKey(name); + if (val != nullptr) + { + assert(val->IsObject()); + if (val->IsObject()) + { + r->mObjects.Push(FJSONObject(val)); + } + else + { + Printf(TEXTCOLOR_RED "Object expected for '%s'\n", name); + mErrors++; + return false; + } + } + else + { + return false; + } + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::HasKey(const char* name) +{ + if (isReading()) + { + return r->FindKey(name) != nullptr; + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::HasObject(const char* name) +{ + if (isReading()) + { + auto val = r->FindKey(name); + if (val != nullptr) + { + if (val->IsObject()) + { + return true; + } + } + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::EndObject() +{ + if (isWriting()) + { + if (w->inObject()) + { + w->EndObject(); + w->mInObject.Pop(); + } + else + { + assert(false && "EndObject call not inside an object"); + I_Error("EndObject call not inside an object"); + } + } + else + { + r->mObjects.Pop(); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FSerializer::BeginArray(const char *name) +{ + if (isWriting()) + { + WriteKey(name); + w->StartArray(); + w->mInObject.Push(false); + } + else + { + auto val = r->FindKey(name); + if (val != nullptr) + { + assert(val->IsArray()); + if (val->IsArray()) + { + r->mObjects.Push(FJSONObject(val)); + } + else + { + Printf(TEXTCOLOR_RED "Array expected for '%s'\n", name); + mErrors++; + return false; + } + } + else + { + return false; + } + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::EndArray() +{ + if (isWriting()) + { + if (!w->inObject()) + { + w->EndArray(); + w->mInObject.Pop(); + } + else + { + assert(false && "EndArray call not inside an array"); + I_Error("EndArray call not inside an array"); + } + } + else + { + r->mObjects.Pop(); + } +} + +//========================================================================== +// +// Special handler for script numbers +// +//========================================================================== + +FSerializer &FSerializer::ScriptNum(const char *key, int &num) +{ + if (isWriting()) + { + WriteKey(key); + if (num < 0) + { + w->String(FName(ENamedName(-num)).GetChars()); + } + else + { + w->Int(num); + } + } + else + { + auto val = r->FindKey(key); + if (val != nullptr) + { + if (val->IsInt()) + { + num = val->GetInt(); + } + else if (val->IsString()) + { + num = -FName(UnicodeToString(val->GetString())).GetIndex(); + } + else + { + assert(false && "Integer expected"); + Printf(TEXTCOLOR_RED "Integer expected for '%s'\n", key); + mErrors++; + } + } + } + return *this; +} + +//========================================================================== +// +// this is merely a placeholder to satisfy the VM's spriteid type. +// +//========================================================================== + +FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *def) +{ + if (isWriting()) + { + if (w->inObject() && def != nullptr && *def == spritenum) return *this; + WriteKey(key); + w->Int(spritenum); + } + else + { + auto val = r->FindKey(key); + if (val != nullptr && val->IsInt()) + { + spritenum = val->GetInt(); + } + } + return *this; +} + +//========================================================================== +// +// only here so that it can be virtually overridden. Without reference this cannot save anything. +// +//========================================================================== + +FSerializer& FSerializer::StatePointer(const char* key, void* ptraddr, bool *res) +{ + if (res) *res = false; + return *this; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr) +{ + if (isWriting()) + { + WriteKey(key); + if (charptr != nullptr) + w->String(charptr); + else + w->Null(); + } + else + { + auto val = r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + charptr = UnicodeToString(val->GetString()); + } + else + { + charptr = nullptr; + } + } + } + return *this; +} + +//========================================================================== +// +// Adds a string literal. This won't get double encoded, like a serialized string. +// +//========================================================================== + +FSerializer &FSerializer::AddString(const char *key, const char *charptr) +{ + if (isWriting()) + { + WriteKey(key); + w->StringU(MakeUTF8(charptr), false); + } + return *this; +} + +//========================================================================== +// +// Reads back a string without any processing. +// +//========================================================================== + +const char *FSerializer::GetString(const char *key) +{ + auto val = r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + return val->GetString(); + } + else + { + } + } + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +unsigned FSerializer::GetSize(const char *group) +{ + if (isWriting()) return -1; // we do not know this when writing. + + const rapidjson::Value *val = r->FindKey(group); + if (!val) return 0; + if (!val->IsArray()) return -1; + return val->Size(); +} + +//========================================================================== +// +// gets the key pointed to by the iterator, caches its value +// and returns the key string. +// +//========================================================================== + +const char *FSerializer::GetKey() +{ + if (isWriting()) return nullptr; // we do not know this when writing. + if (!r->mObjects.Last().mObject->IsObject()) return nullptr; // non-objects do not have keys. + auto &it = r->mObjects.Last().mIterator; + if (it == r->mObjects.Last().mObject->MemberEnd()) return nullptr; + r->mKeyValue = &it->value; + return (it++)->name.GetString(); +} + +//========================================================================== +// +// Writes out all collected objects +// +//========================================================================== + +void FSerializer::WriteObjects() +{ + if (isWriting() && w->mDObjects.Size()) + { + BeginArray("objects"); + // we cannot use the C++11 shorthand syntax here because the array may grow while being processed. + for (unsigned i = 0; i < w->mDObjects.Size(); i++) + { + auto obj = w->mDObjects[i]; + + if(obj->ObjectFlags & OF_Transient) continue; + + BeginObject(nullptr); + w->Key("classtype"); + w->String(obj->GetClass()->TypeName.GetChars()); + + obj->SerializeUserVars(*this); + obj->Serialize(*this); + obj->CheckIfSerialized(); + EndObject(); + } + EndArray(); + } +} + +//========================================================================== +// +// Writes out all collected objects +// +//========================================================================== + +void FSerializer::ReadObjects(bool hubtravel) +{ + bool founderrors = false; + + if (isReading() && BeginArray("objects")) + { + // Do not link any thinker that's being created here. This will be done by deserializing the thinker list later. + try + { + r->mDObjects.Resize(ArraySize()); + for (auto &p : r->mDObjects) + { + p = nullptr; + } + + // First iteration: create all the objects but do nothing with them yet. + for (unsigned i = 0; i < r->mDObjects.Size(); i++) + { + if (BeginObject(nullptr)) + { + FString clsname; // do not deserialize the class type directly so that we can print appropriate errors. + + Serialize(*this, "classtype", clsname, nullptr); + PClass *cls = PClass::FindClass(clsname); + if (cls == nullptr) + { + Printf(TEXTCOLOR_RED "Unknown object class '%s' in savegame\n", clsname.GetChars()); + founderrors = true; + r->mDObjects[i] = RUNTIME_CLASS(DObject)->CreateNew(); // make sure we got at least a valid pointer for the duration of the loading process. + r->mDObjects[i]->Destroy(); // but we do not want to keep this around, so destroy it right away. + } + else + { + r->mDObjects[i] = cls->CreateNew(); + } + EndObject(); + } + } + // Now that everything has been created and we can retrieve the pointers we can deserialize it. + r->mObjectsRead = true; + + if (!founderrors) + { + // Reset to start; + unsigned size = r->mObjects.Size(); + r->mObjects.Last().mIndex = 0; + + for (unsigned i = 0; i < r->mDObjects.Size(); i++) + { + auto obj = r->mDObjects[i]; + if (BeginObject(nullptr)) + { + if (obj != nullptr) + { + try + { + obj->SerializeUserVars(*this); + obj->Serialize(*this); + } + catch (CRecoverableError &err) + { + r->mObjects.Clamp(size); // close all inner objects. + // In case something in here throws an error, let's continue and deal with it later. + Printf(PRINT_NONOTIFY | PRINT_BOLD, TEXTCOLOR_RED "'%s'\n while restoring %s\n", err.GetMessage(), obj ? obj->GetClass()->TypeName.GetChars() : "invalid object"); + mErrors++; + } + } + EndObject(); + } + } + } + EndArray(); + + if (founderrors) + { + Printf(TEXTCOLOR_RED "Failed to restore all objects in savegame\n"); + mErrors++; + mObjectErrors++; + } + } + catch(...) + { + // nuke all objects we created here. + for (auto obj : r->mDObjects) + { + if (obj != nullptr && !(obj->ObjectFlags & OF_EuthanizeMe)) obj->Destroy(); + } + r->mDObjects.Clear(); + + // make sure this flag gets unset, even if something in here throws an error. + throw; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +const char *FSerializer::GetOutput(unsigned *len) +{ + if (isReading()) return nullptr; + WriteObjects(); + EndObject(); + if (len != nullptr) + { + *len = (unsigned)w->mOutString.GetSize(); + } + return w->mOutString.GetString(); +} + +//========================================================================== +// +// +// +//========================================================================== + +FCompressedBuffer FSerializer::GetCompressedOutput() +{ + if (isReading()) return{ 0,0,0,0,0,nullptr }; + FCompressedBuffer buff; + WriteObjects(); + EndObject(); + buff.filename = nullptr; + buff.mSize = (unsigned)w->mOutString.GetSize(); + buff.mCRC32 = crc32(0, (const Bytef*)w->mOutString.GetString(), buff.mSize); + + uint8_t *compressbuf = new uint8_t[buff.mSize+1]; + + z_stream stream; + int err; + + stream.next_in = (Bytef *)w->mOutString.GetString(); + stream.avail_in = (unsigned)buff.mSize; + stream.next_out = (Bytef*)compressbuf; + stream.avail_out = (unsigned)buff.mSize; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + // create output in zip-compatible form as required by FCompressedBuffer + err = deflateInit2(&stream, 8, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY); + if (err != Z_OK) + { + goto error; + } + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) + { + deflateEnd(&stream); + goto error; + } + buff.mCompressedSize = stream.total_out; + + err = deflateEnd(&stream); + if (err == Z_OK) + { + buff.mBuffer = new char[buff.mCompressedSize]; + buff.mMethod = METHOD_DEFLATE; + memcpy(buff.mBuffer, compressbuf, buff.mCompressedSize); + delete[] compressbuf; + return buff; + } + +error: + memcpy(compressbuf, w->mOutString.GetString(), buff.mSize + 1); + buff.mCompressedSize = buff.mSize; + buff.mMethod = METHOD_STORED; + return buff; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &FSerializer::SerializeMemory(const char *key, void* mem, size_t length) +{ + if (isWriting()) + { + auto array = base64_encode((const uint8_t*)mem, length); + AddString(key, (const char*)array.Data()); + } + else + { + auto cp = GetString(key); + if (key) + { + base64_decode(mem, length, cp); + } + } + return *this; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->Bool(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsBool()); + if (val->IsBool()) + { + value = val->GetBool(); + } + else + { + Printf(TEXTCOLOR_RED "boolean type expected for '%s'\n", key); + arc.mErrors++; + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_t *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->Int64(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsInt64()); + if (val->IsInt64()) + { + value = val->GetInt64(); + } + else + { + Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); + arc.mErrors++; + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint64_t *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->Uint64(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsUint64()); + if (val->IsUint64()) + { + value = val->GetUint64(); + } + else + { + Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); + arc.mErrors++; + } + } + } + return arc; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value, int32_t *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->Int(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsInt()); + if (val->IsInt()) + { + value = val->GetInt(); + } + else + { + Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); + arc.mErrors++; + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint32_t *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->Uint(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsUint()); + if (val->IsUint()) + { + value = val->GetUint(); + } + else + { + Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); + arc.mErrors++; + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval) +{ + int32_t vv = value; + int32_t vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (int8_t)vv; + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, int8_t &value, int8_t *defval) +{ + int32_t vv = value; + int32_t vvd = defval? *defval : value-1; + Serialize(arc, key, vv, &vvd); + value = (int8_t)vv; + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, uint8_t &value, uint8_t *defval) +{ + uint32_t vv = value; + uint32_t vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (uint8_t)vv; + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, int16_t &value, int16_t *defval) +{ + int32_t vv = value; + int32_t vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (int16_t)vv; + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, uint16_t &value, uint16_t *defval) +{ + uint32_t vv = value; + uint32_t vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (uint16_t)vv; + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->Double(value); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsNumber()); + if (val->IsNumber()) + { + value = val->GetDouble(); + } + else + { + Printf(TEXTCOLOR_RED "float type expected for '%s'\n", key); + arc.mErrors++; + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *defval) +{ + double vv = value; + double vvd = defval ? *defval : value - 1; + Serialize(arc, key, vv, &vvd); + value = (float)vv; + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + if (!value.Exists()) + { + arc.WriteKey(key); + arc.w->Null(); + return arc; + } + if (value.isNull()) + { + // save 'no texture' in a more space saving way + arc.WriteKey(key); + arc.w->Int(0); + return arc; + } + FTextureID chk = value; + if (chk.GetIndex() >= TexMan.NumTextures()) chk.SetNull(); + auto pic = TexMan.GetGameTexture(chk); + const char *name; + auto lump = pic->GetSourceLump(); + + if (TexMan.GetLinkedTexture(lump) == pic) + { + name = fileSystem.GetFileFullName(lump); + } + else + { + name = pic->GetName().GetChars(); + } + arc.WriteKey(key); + arc.w->StartArray(); + arc.w->String(name); + int ut = static_cast(pic->GetUseType()); + arc.w->Int(ut); + arc.w->EndArray(); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsArray()) + { + const rapidjson::Value &nameval = (*val)[0]; + const rapidjson::Value &typeval = (*val)[1]; + assert(nameval.IsString() && typeval.IsInt()); + if (nameval.IsString() && typeval.IsInt()) + { + value = TexMan.GetTextureID(UnicodeToString(nameval.GetString()), static_cast(typeval.GetInt())); + } + else + { + Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'\n", key); + value.SetNull(); + arc.mErrors++; + } + } + else if (val->IsNull()) + { + value.SetInvalid(); + } + else if (val->IsInt() && val->GetInt() == 0) + { + value.SetNull(); + } + else + { + assert(false && "not a texture"); + Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'\n", key); + value.SetNull(); + arc.mErrors++; + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval) +{ + int v = value.index(); + int* defv = (int*)defval; + Serialize(arc, key, v, defv); + + if (arc.isReading()) + { + // allow games to alter the loaded value to handle dynamic lists. + if (sysCallbacks.RemapTranslation) value = sysCallbacks.RemapTranslation(FTranslationID::fromInt(v)); + else value = FTranslationID::fromInt(v); + } + + return arc; +} + +//========================================================================== +// +// This never uses defval and instead uses 'null' as default +// because object pointers cannot be safely defaulted to anything else. +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode) +{ + if (retcode) *retcode = true; + if (arc.isWriting()) + { + if (value != nullptr && !(value->ObjectFlags & (OF_EuthanizeMe | OF_Transient))) + { + int ndx; + if (value == WP_NOCHANGE) + { + ndx = -1; + } + else + { + int *pndx = arc.w->mObjectMap.CheckKey(value); + if (pndx != nullptr) + { + ndx = *pndx; + } + else + { + ndx = arc.w->mDObjects.Push(value); + arc.w->mObjectMap[value] = ndx; + } + } + Serialize(arc, key, ndx, nullptr); + } + else if (!arc.w->inObject()) + { + arc.w->Null(); + } + } + else + { + if (!arc.r->mObjectsRead) + { + // If you want to read objects, you MUST call ReadObjects first, even if there's only nullptr's. + assert(false && "Attempt to read object reference without calling ReadObjects first"); + I_Error("Attempt to read object reference without calling ReadObjects first"); + } + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsNull()) + { + value = nullptr; + return arc; + } + else if (val->IsInt()) + { + int index = val->GetInt(); + if (index == -1) + { + value = WP_NOCHANGE; + } + else + { + assert(index >= 0 && index < (int)arc.r->mDObjects.Size()); + if (index >= 0 && index < (int)arc.r->mDObjects.Size()) + { + value = arc.r->mDObjects[index]; + } + else + { + assert(false && "invalid object reference"); + Printf(TEXTCOLOR_RED "Invalid object reference for '%s'\n", key); + value = nullptr; + arc.mErrors++; + if (retcode) *retcode = false; + } + } + return arc; + } + } + if (!retcode) + { + value = nullptr; + } + else + { + *retcode = false; + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + arc.w->String(value.GetChars()); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsString()); + if (val->IsString()) + { + value = UnicodeToString(val->GetString()); + } + else + { + Printf(TEXTCOLOR_RED "String expected for '%s'\n", key); + arc.mErrors++; + value = NAME_None; + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def) +{ + if (!arc.soundNamesAreUnique) + { + //If sound name here is not reliable, we need to save by index instead. + int id = sid.index(); + Serialize(arc, key, id, nullptr); + if (arc.isReading()) sid = FSoundID::fromInt(id); + } + else if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || sid != *def) + { + arc.WriteKey(key); + const char *sn = soundEngine->GetSoundName(sid); + if (sn != nullptr) arc.w->String(sn); + else arc.w->Null(); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsString() || val->IsNull()); + if (val->IsString()) + { + sid = S_FindSound(UnicodeToString(val->GetString())); + } + else if (val->IsNull()) + { + sid = NO_SOUND; + } + else + { + Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); + sid = NO_SOUND; + arc.mErrors++; + } + } + } + return arc; + +} + +//========================================================================== +// +// almost, but not quite the same as the above. +// +//========================================================================== + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&clst, PClass **def) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || clst != *def) + { + arc.WriteKey(key); + if (clst == nullptr) + { + arc.w->Null(); + } + else + { + arc.w->String(clst->TypeName.GetChars()); + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + clst = PClass::FindClass(UnicodeToString(val->GetString())); + } + else if (val->IsNull()) + { + clst = nullptr; + } + else + { + Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); + clst = nullptr; + arc.mErrors++; + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString *def) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || pstr.Compare(*def) != 0) + { + arc.WriteKey(key); + arc.w->String(pstr.GetChars()); + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsNull() || val->IsString()); + if (val->IsNull()) + { + pstr = ""; + } + else if (val->IsString()) + { + pstr = UnicodeToString(val->GetString()); + } + else + { + Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); + pstr = ""; + arc.mErrors++; + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def) +{ + if (arc.isWriting()) + { + FName n = font? font->GetName() : NAME_None; + return arc(key, n); + } + else + { + FName n = NAME_None; + arc(key, n); + font = n == NAME_None? nullptr : V_GetFont(n.GetChars()); + return arc; + } + +} + +//========================================================================== +// +// Dictionary +// +//========================================================================== + +FString DictionaryToString(const Dictionary &dict) +{ + Dictionary::ConstPair *pair; + Dictionary::ConstIterator i { dict.Map }; + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + writer.StartObject(); + + while (i.NextPair(pair)) + { + writer.Key(pair->Key.GetChars()); + writer.String(pair->Value.GetChars()); + } + + writer.EndObject(); + + FString contents { buffer.GetString(), buffer.GetSize() }; + return contents; +} + +Dictionary *DictionaryFromString(const FString &string) +{ + if (string.Compare("null") == 0) + { + return nullptr; + } + + Dictionary *const dict = Create(); + + if (string.IsEmpty()) + { + return dict; + } + + rapidjson::Document doc; + doc.Parse(string.GetChars(), string.Len()); + + if (doc.GetType() != rapidjson::Type::kObjectType) + { + I_Error("Dictionary is expected to be a JSON object."); + return dict; + } + + for (auto i = doc.MemberBegin(); i != doc.MemberEnd(); ++i) + { + if (i->value.GetType() != rapidjson::Type::kStringType) + { + I_Error("Dictionary value is expected to be a JSON string."); + return dict; + } + + dict->Map.Insert(i->name.GetString(), i->value.GetString()); + } + + return dict; +} + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary *&dict, Dictionary **) +{ + if (arc.isWriting()) + { + FString contents { dict ? DictionaryToString(*dict) : FString("null") }; + return arc(key, contents); + } + else + { + FString contents; + arc(key, contents); + dict = DictionaryFromString(contents); + return arc; + } +} + +template<> FSerializer& Serialize(FSerializer& arc, const char* key, VMFunction*& func, VMFunction**) +{ + if (arc.isWriting()) + { + arc.WriteKey(key); + if (func) arc.w->String(func->QualifiedName); + else arc.w->Null(); + } + else + { + func = nullptr; + + auto val = arc.r->FindKey(key); + if (val != nullptr && val->IsString()) + { + auto qname = val->GetString(); + size_t p = strcspn(qname, "."); + if (p != 0) + { + FName clsname(qname, p, true); + FName funcname(qname + p + 1, true); + func = PClass::FindFunction(clsname, funcname); + } + } + + } + return arc; +} + +//========================================================================== +// +// Handler to retrieve a numeric value of any kind. +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &value, NumericValue *defval) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || defval == nullptr || value != *defval) + { + arc.WriteKey(key); + switch (value.type) + { + case NumericValue::NM_signed: + arc.w->Int64(value.signedval); + break; + case NumericValue::NM_unsigned: + arc.w->Uint64(value.unsignedval); + break; + case NumericValue::NM_float: + arc.w->Double(value.floatval); + break; + default: + arc.w->Null(); + break; + } + } + } + else + { + auto val = arc.r->FindKey(key); + value.signedval = 0; + value.type = NumericValue::NM_invalid; + if (val != nullptr) + { + if (val->IsUint64()) + { + value.unsignedval = val->GetUint64(); + value.type = NumericValue::NM_unsigned; + } + else if (val->IsInt64()) + { + value.signedval = val->GetInt64(); + value.type = NumericValue::NM_signed; + } + else if (val->IsDouble()) + { + value.floatval = val->GetDouble(); + value.type = NumericValue::NM_float; + } + } + } + return arc; +} + +//========================================================================== +// +// PFunctionPointer +// +//========================================================================== + +void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p) +{ + if (arc.isWriting()) + { + if(p) + { + arc.BeginObject(key); + arc("Class",p->ClassName); + arc("Function",p->FunctionName); + arc.EndObject(); + } + else + { + arc.WriteKey(key); + arc.w->Null(); + } + } + else + { + assert(p); + auto v = arc.r->FindKey(key); + if(!v || v->IsNull()) + { + p = nullptr; + } + else if(v->IsObject()) + { + arc.r->mObjects.Push(FJSONObject(v)); // BeginObject + + const char * cstr; + arc.StringPtr("Class", cstr); + + if(!cstr) + { + arc.StringPtr("Function", cstr); + if(!cstr) + { + Printf(TEXTCOLOR_RED "Function Pointer missing Class and Function Fields in Object\n"); + } + else + { + Printf(TEXTCOLOR_RED "Function Pointer missing Class Field in Object\n"); + } + arc.mErrors++; + arc.EndObject(); + p = nullptr; + return; + } + + p->ClassName = FString(cstr); + arc.StringPtr("Function", cstr); + + if(!cstr) + { + Printf(TEXTCOLOR_RED "Function Pointer missing Function Field in Object\n"); + arc.mErrors++; + arc.EndObject(); + p = nullptr; + return; + } + p->FunctionName = FString(cstr); + arc.EndObject(); + } + else + { + Printf(TEXTCOLOR_RED "Function Pointer is not an Object\n"); + arc.mErrors++; + p = nullptr; + } + } +} + +bool FSerializer::ReadOptionalInt(const char * key, int &into) +{ + if(!isReading()) return false; + + auto val = r->FindKey(key); + if(val && val->IsInt()) + { + into = val->GetInt(); + return true; + } + return false; +} + +#include "renderstyle.h" +FSerializer& Serialize(FSerializer& arc, const char* key, FRenderStyle& style, FRenderStyle* def) +{ + return arc.Array(key, &style.BlendOp, def ? &def->BlendOp : nullptr, 4); +} + +SaveRecords saveRecords; diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h new file mode 100644 index 00000000000..ae25853d948 --- /dev/null +++ b/src/common/engine/serializer.h @@ -0,0 +1,428 @@ +#ifndef __SERIALIZER_H +#define __SERIALIZER_H + +#include +#include +#include "tarray.h" +#include "tflags.h" +#include "vectors.h" +#include "palentry.h" +#include "name.h" +#include "dictionary.h" + +extern bool save_full; + +struct FWriter; +struct FReader; +class PClass; +class FFont; +class FSoundID; +union FRenderStyle; +class DObject; +class FTextureID; +struct FTranslationID; + +inline bool nullcmp(const void *buffer, size_t length) +{ + const char *p = (const char *)buffer; + for (; length > 0; length--) + { + if (*p++ != 0) return false; + } + return true; +} + +struct NumericValue +{ + enum EType + { + NM_invalid, + NM_signed, + NM_unsigned, + NM_float + } type; + + union + { + int64_t signedval; + uint64_t unsignedval; + double floatval; + }; + + bool operator !=(const NumericValue &other) + { + return type != other.type || signedval != other.signedval; + } +}; + +struct FunctionPointerValue +{ + FString ClassName; + FString FunctionName; +}; + + +class FSerializer +{ + +public: + FWriter *w = nullptr; + FReader *r = nullptr; + bool soundNamesAreUnique = false; // While in GZDoom, sound names are unique, that isn't universally true - let the serializer handle both cases with a flag. + + unsigned ArraySize(); + void WriteKey(const char *key); + void WriteObjects(); + +private: + virtual void CloseReaderCustom() {} +public: + + ~FSerializer() + { + mErrors = 0; // The destructor may not throw an exception so silence the error checker. + Close(); + } + void SetUniqueSoundNames() { soundNamesAreUnique = true; } + bool OpenWriter(bool pretty = true); + bool OpenReader(const char *buffer, size_t length); + bool OpenReader(FileSys::FCompressedBuffer *input); + void Close(); + void ReadObjects(bool hubtravel); + bool BeginObject(const char *name); + void EndObject(); + bool HasKey(const char* name); + bool HasObject(const char* name); + bool BeginArray(const char *name); + void EndArray(); + unsigned GetSize(const char *group); + const char *GetKey(); + const char *GetOutput(unsigned *len = nullptr); + FileSys::FCompressedBuffer GetCompressedOutput(); + // The sprite serializer is a special case because it is needed by the VM to handle its 'spriteid' type. + virtual FSerializer &Sprite(const char *key, int32_t &spritenum, int32_t *def); + // This is only needed by the type system. + virtual FSerializer& StatePointer(const char* key, void* ptraddr, bool *res); + FSerializer& SerializeMemory(const char* key, void* mem, size_t length); + + FSerializer &StringPtr(const char *key, const char *&charptr); // This only retrieves the address but creates no permanent copy of the string unlike the regular char* serializer. + FSerializer &AddString(const char *key, const char *charptr); + const char *GetString(const char *key); + FSerializer &ScriptNum(const char *key, int &num); + + + bool ReadOptionalInt(const char * key, int &into); + + bool isReading() const + { + return r != nullptr; + } + + bool isWriting() const + { + return w != nullptr; + } + + bool canSkip() const; + + template + FSerializer &operator()(const char *key, T &obj) + { + return Serialize(*this, key, obj, (T*)nullptr); + } + + template + FSerializer &operator()(const char *key, T &obj, T &def) + { + return Serialize(*this, key, obj, save_full? nullptr : &def); + } + + template + FSerializer& operator()(const char* key, T& obj, T* def) + { + return Serialize(*this, key, obj, !def || save_full ? nullptr : def); + } + + template + FSerializer &Array(const char *key, T *obj, int count, bool fullcompare = false) + { + if (!save_full && fullcompare && isWriting() && nullcmp(obj, count * sizeof(T))) + { + return *this; + } + + if (BeginArray(key)) + { + if (isReading()) + { + int max = ArraySize(); + if (max < count) count = max; + } + for (int i = 0; i < count; i++) + { + Serialize(*this, nullptr, obj[i], (T*)nullptr); + } + EndArray(); + } + return *this; + } + + template + FSerializer &Array(const char *key, T *obj, T *def, int count, bool fullcompare = false) + { + if (!save_full && fullcompare && isWriting() && key != nullptr && def != nullptr && !memcmp(obj, def, count * sizeof(T))) + { + return *this; + } + if (BeginArray(key)) + { + if (isReading()) + { + int max = ArraySize(); + if (max < count) count = max; + } + for (int i = 0; i < count; i++) + { + Serialize(*this, nullptr, obj[i], def ? &def[i] : nullptr); + } + EndArray(); + } + return *this; + } + + template + FSerializer &SparseArray(const char *key, T *obj, int count, const Map &map, bool fullcompare = false) + { + if (BeginArray(key)) + { + int max = count; + if (isReading()) + { + max = ArraySize(); + } + for (int i = 0; i < count; i++) + { + if (map[i]) + { + Serialize(*this, nullptr, obj[i], (T*)nullptr); + if (--max < 0) break; + } + } + EndArray(); + } + return *this; + } + + template + FSerializer &Enum(const char *key, T &obj) + { + auto val = (typename std::underlying_type::type)obj; + Serialize(*this, key, val, nullptr); + obj = (T)val; + return *this; + } + + int mErrors = 0; + int mObjectErrors = 0; +}; + +FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval); + +FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_t *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint64_t *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value, int32_t *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint32_t *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, int8_t &value, int8_t *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, uint8_t &value, uint8_t *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, int16_t &value, int16_t *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, uint16_t &value, uint16_t *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode = nullptr); +FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *defval); +FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def); +FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def); +FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &mo, struct ModelOverride *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def); +FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); + +void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p); + +template >*/> +FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) +{ + DObject *v = static_cast(value); + Serialize(arc, key, v, nullptr); + value = static_cast(v); + return arc; +} + +template +FSerializer &Serialize(FSerializer &arc, const char *key, std::pair &value, std::pair *def) +{ + arc.BeginObject(key); + Serialize(arc, "first", value.first, def ? &def->first : nullptr); + Serialize(arc, "second", value.second, def ? &def->second : nullptr); + arc.EndObject(); + return arc; +} + +template +FSerializer &Serialize(FSerializer &arc, const char *key, TArray &value, TArray *def) +{ + if (arc.isWriting()) + { + if (value.Size() == 0 && key) return arc; // do not save empty arrays + } + bool res = arc.BeginArray(key); + if (arc.isReading()) + { + if (!res) + { + value.Clear(); + return arc; + } + value.Resize(arc.ArraySize()); + } + for (unsigned i = 0; i < value.Size(); i++) + { + Serialize(arc, nullptr, value[i], def? &(*def)[i] : nullptr); + } + arc.EndArray(); + return arc; +} + +template +FSerializer& Serialize(FSerializer& arc, const char* key, TPointer& value, TPointer* def) +{ + if (arc.isWriting()) + { + if (value.Data() == nullptr && key) return arc; + } + bool res = arc.BeginArray(key); + if (arc.isReading()) + { + if (!res || arc.ArraySize() == 0) + { + value.Clear(); + return arc; + } + value.Alloc(); + } + if (value.Data()) + { + Serialize(arc, nullptr, *value, def ? def->Data() : nullptr); + } + arc.EndArray(); + return arc; +} + + +template +FSerializer& Serialize(FSerializer& arc, const char* key, FixedBitArray& value, FixedBitArray* def) +{ + return arc.SerializeMemory(key, value.Storage(), value.StorageSize()); +} + +inline FSerializer& Serialize(FSerializer& arc, const char* key, BitArray& value, BitArray* def) +{ + return arc.SerializeMemory(key, value.Storage().Data(), value.Storage().Size()); +} + +template<> FSerializer& Serialize(FSerializer& arc, const char* key, PClass*& clst, PClass** def); +template<> FSerializer& Serialize(FSerializer& arc, const char* key, FFont*& font, FFont** def); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary *&dict, Dictionary **def); +template<> FSerializer& Serialize(FSerializer& arc, const char* key, VMFunction*& dict, VMFunction** def); + +inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector3 &p, DVector3 *def) +{ + return arc.Array(key, &p[0], def? &(*def)[0] : nullptr, 3, true); +} + +inline FSerializer &Serialize(FSerializer &arc, const char *key, DRotator &p, DRotator *def) +{ + return arc.Array(key, &p[0], def? &(*def)[0] : nullptr, 3, true); +} + +inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector2 &p, DVector2 *def) +{ + return arc.Array(key, &p[0], def? &(*def)[0] : nullptr, 2, true); +} + +inline FSerializer& Serialize(FSerializer& arc, const char* key, FVector4& p, FVector4* def) +{ + return arc.Array(key, &p[0], def ? &(*def)[0] : nullptr, 4, true); +} + +inline FSerializer& Serialize(FSerializer& arc, const char* key, FVector3& p, FVector3* def) +{ + return arc.Array(key, &p[0], def ? &(*def)[0] : nullptr, 3, true); +} + +inline FSerializer& Serialize(FSerializer& arc, const char* key, FVector2& p, FVector2* def) +{ + return arc.Array(key, &p[0], def ? &(*def)[0] : nullptr, 2, true); +} + +template +inline FSerializer &Serialize(FSerializer &arc, const char *key, TAngle &p, TAngle *def) +{ + return Serialize(arc, key, p.Degrees__(), def ? &def->Degrees__() : nullptr); +} + +inline FSerializer &Serialize(FSerializer &arc, const char *key, PalEntry &pe, PalEntry *def) +{ + return Serialize(arc, key, pe.d, def? &def->d : nullptr); +} + +FSerializer &Serialize(FSerializer &arc, const char *key, FRenderStyle &style, FRenderStyle *def); + +template +FSerializer &Serialize(FSerializer &arc, const char *key, TFlags &flags, TFlags *def) +{ + return Serialize(arc, key, flags.Value, def? &def->Value : nullptr); +} + +// Automatic save record registration + +struct SaveRecord +{ + const char* GameModule; + void (*Handler)(FSerializer& arc); + + SaveRecord(const char* nm, void (*handler)(FSerializer& arc)); +}; + +struct SaveRecords +{ + TArray records; + + void RunHandlers(const char* gameModule, FSerializer& arc) + { + for (auto record : records) + { + if (!strcmp(gameModule, record->GameModule)) + { + record->Handler(arc); + } + } + } +}; + +extern SaveRecords saveRecords; + +inline SaveRecord::SaveRecord(const char* nm, void (*handler)(FSerializer& arc)) +{ + GameModule = nm; + Handler = handler; + saveRecords.records.Push(this); +} + +FString DictionaryToString(const Dictionary &dict); +Dictionary *DictionaryFromString(const FString &string); + +#endif diff --git a/src/common/engine/serializer_internal.h b/src/common/engine/serializer_internal.h new file mode 100644 index 00000000000..05b6dcad0fd --- /dev/null +++ b/src/common/engine/serializer_internal.h @@ -0,0 +1,270 @@ +#pragma once +const char* UnicodeToString(const char* cc); +const char* StringToUnicode(const char* cc, int size = -1); + +//========================================================================== +// +// +// +//========================================================================== + +struct FJSONObject +{ + rapidjson::Value* mObject; + rapidjson::Value::MemberIterator mIterator; + int mIndex; + + FJSONObject(rapidjson::Value* v) + { + mObject = v; + if (v->IsObject()) mIterator = v->MemberBegin(); + else if (v->IsArray()) + { + mIndex = 0; + } + } +}; + +//========================================================================== +// +// some wrapper stuff to keep the RapidJSON dependencies out of the global headers. +// FSerializer should not expose any of this, although it is needed by special serializers. +// +//========================================================================== + +struct FWriter +{ + typedef rapidjson::Writer > Writer; + typedef rapidjson::PrettyWriter > PrettyWriter; + + Writer *mWriter1; + PrettyWriter *mWriter2; + TArray mInObject; + rapidjson::StringBuffer mOutString; + TArray mDObjects; + TMap mObjectMap; + + FWriter(bool pretty) + { + if (!pretty) + { + mWriter1 = new Writer(mOutString); + mWriter2 = nullptr; + } + else + { + mWriter1 = nullptr; + mWriter2 = new PrettyWriter(mOutString); + } + } + + ~FWriter() + { + if (mWriter1) delete mWriter1; + if (mWriter2) delete mWriter2; + } + + + bool inObject() const + { + return mInObject.Size() > 0 && mInObject.Last(); + } + + void StartObject() + { + if (mWriter1) mWriter1->StartObject(); + else if (mWriter2) mWriter2->StartObject(); + } + + void EndObject() + { + if (mWriter1) mWriter1->EndObject(); + else if (mWriter2) mWriter2->EndObject(); + } + + void StartArray() + { + if (mWriter1) mWriter1->StartArray(); + else if (mWriter2) mWriter2->StartArray(); + } + + void EndArray() + { + if (mWriter1) mWriter1->EndArray(); + else if (mWriter2) mWriter2->EndArray(); + } + + void Key(const char *k) + { + if (mWriter1) mWriter1->Key(k); + else if (mWriter2) mWriter2->Key(k); + } + + void Null() + { + if (mWriter1) mWriter1->Null(); + else if (mWriter2) mWriter2->Null(); + } + + void StringU(const char *k, bool encode) + { + if (encode) k = StringToUnicode(k); + if (mWriter1) mWriter1->String(k); + else if (mWriter2) mWriter2->String(k); + } + + void String(const char *k) + { + k = StringToUnicode(k); + if (mWriter1) mWriter1->String(k); + else if (mWriter2) mWriter2->String(k); + } + + void String(const char *k, int size) + { + k = StringToUnicode(k, size); + if (mWriter1) mWriter1->String(k); + else if (mWriter2) mWriter2->String(k); + } + + void Bool(bool k) + { + if (mWriter1) mWriter1->Bool(k); + else if (mWriter2) mWriter2->Bool(k); + } + + void Int(int32_t k) + { + if (mWriter1) mWriter1->Int(k); + else if (mWriter2) mWriter2->Int(k); + } + + void Int64(int64_t k) + { + if (mWriter1) mWriter1->Int64(k); + else if (mWriter2) mWriter2->Int64(k); + } + + void Uint(uint32_t k) + { + if (mWriter1) mWriter1->Uint(k); + else if (mWriter2) mWriter2->Uint(k); + } + + void Uint64(int64_t k) + { + if (mWriter1) mWriter1->Uint64(k); + else if (mWriter2) mWriter2->Uint64(k); + } + + void Double(double k) + { + if (mWriter1) + { + mWriter1->Double(k); + } + else if (mWriter2) + { + mWriter2->Double(k); + } + } + +}; + +//========================================================================== +// +// +// +//========================================================================== + +struct FReader +{ + TArray mObjects; + rapidjson::Document mDoc; + TArray mDObjects; + rapidjson::Value *mKeyValue = nullptr; + bool mObjectsRead = false; + + FReader(const char *buffer, size_t length) + { + mDoc.Parse(buffer, length); + mObjects.Push(FJSONObject(&mDoc)); + } + + rapidjson::Value *FindKey(const char *key) + { + FJSONObject &obj = mObjects.Last(); + + if (obj.mObject->IsObject()) + { + if (key == nullptr) + { + // we are performing an iteration of the object through GetKey. + auto p = mKeyValue; + mKeyValue = nullptr; + return p; + } + else + { + // Find the given key by name; + auto it = obj.mObject->FindMember(key); + if (it == obj.mObject->MemberEnd()) return nullptr; + return &it->value; + } + } + else if (obj.mObject->IsArray() && (unsigned)obj.mIndex < obj.mObject->Size()) + { + return &(*obj.mObject)[obj.mIndex++]; + } + return nullptr; + } +}; + +//========================================================================== +// +// +// +//========================================================================== + +template +FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T **defval, T *base, const int64_t count) +{ + assert(base != nullptr); + assert(count > 0); + if (arc.isReading() || !arc.w->inObject() || defval == nullptr || value != *defval) + { + int64_t vv = -1; + if (value != nullptr) + { + vv = value - base; + if (vv < 0 || vv >= count) + { + Printf("Trying to serialize out-of-bounds array value with key '%s', index = %" PRId64 ", size = %" PRId64 "\n", key, vv, count); + vv = -1; + } + } + Serialize(arc, key, vv, nullptr); + if (vv == -1) + value = nullptr; + else if (vv < 0 || vv >= count) + { + Printf("Trying to serialize out-of-bounds array value with key '%s', index = %" PRId64 ", size = %" PRId64 "\n", key, vv, count); + value = nullptr; + } + else + value = base + vv; + } + return arc; +} + +template +FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T **defval, TArray &array) +{ + if (array.Size() == 0) + { + Printf("Trying to serialize a value with key '%s' from empty array\n", key); + return arc; + } + return SerializePointer(arc, key, value, defval, array.Data(), array.Size()); +} + diff --git a/src/common/engine/st_start.h b/src/common/engine/st_start.h new file mode 100644 index 00000000000..a8b78aaa838 --- /dev/null +++ b/src/common/engine/st_start.h @@ -0,0 +1,103 @@ +#pragma once +/* +** st_start.h +** Interface for the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** The startup screen interface is based on a mix of Heretic and Hexen. +** Actual implementation is system-specific. +*/ +#include + +class FStartupScreen +{ +public: + static FStartupScreen *CreateInstance(int max_progress); + + FStartupScreen(int max_progress) + { + MaxPos = max_progress; + CurPos = 0; + NotchPos = 0; + } + + virtual ~FStartupScreen() = default; + + virtual void Progress() {} + + virtual void NetInit(const char *message, int num_players) {} + virtual void NetProgress(int count) {} + virtual void NetDone() {} + virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata) { return false; } + virtual void AppendStatusLine(const char* status) {} + virtual void LoadingStatus(const char* message, int colors) {} + +protected: + int MaxPos, CurPos, NotchPos; +}; + +class FBasicStartupScreen : public FStartupScreen +{ +public: + FBasicStartupScreen(int max_progress); + ~FBasicStartupScreen(); + + void Progress(); + void NetInit(const char* message, int num_players); + void NetProgress(int count); + void NetMessage(const char* format, ...); // cover for printf + void NetDone(); + bool NetLoop(bool (*timer_callback)(void*), void* userdata); +protected: + int NetMaxPos, NetCurPos; +}; + + + +extern FStartupScreen *StartWindow; + +//=========================================================================== +// +// DeleteStartupScreen +// +// Makes sure the startup screen has been deleted before quitting. +// +//=========================================================================== + +inline void DeleteStartupScreen() +{ + if (StartWindow != nullptr) + { + delete StartWindow; + StartWindow = nullptr; + } +} + + diff --git a/src/common/engine/startupinfo.h b/src/common/engine/startupinfo.h new file mode 100644 index 00000000000..c0dd608c10a --- /dev/null +++ b/src/common/engine/startupinfo.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include "zstring.h" + +struct FStartupInfo +{ + FString Name; + uint32_t FgColor; // Foreground color for title banner + uint32_t BkColor; // Background color for title banner + FString Song; + FString con; + FString def; + FString DiscordAppId = nullptr; + FString SteamAppId = nullptr; + int Type; + int LoadLights = -1; + int LoadBrightmaps = -1; + int LoadWidescreen = -1; + enum + { + DefaultStartup, + DoomStartup, + HereticStartup, + HexenStartup, + StrifeStartup, + }; +}; + + +extern FStartupInfo GameStartupInfo; + diff --git a/src/utility/stats.cpp b/src/common/engine/stats.cpp similarity index 85% rename from src/utility/stats.cpp rename to src/common/engine/stats.cpp index 817d1fe8b6a..70ad8e2f16f 100644 --- a/src/utility/stats.cpp +++ b/src/common/engine/stats.cpp @@ -32,11 +32,13 @@ ** */ -#include "doomtype.h" #include "stats.h" -#include "v_video.h" +#include "v_draw.h" #include "v_text.h" +#include "v_font.h" +#include "c_console.h" #include "c_dispatch.h" +#include "printf.h" FStat *FStat::FirstStat; @@ -78,17 +80,26 @@ void FStat::ToggleStat (const char *name) Printf ("Unknown stat: %s\n", name); } +void FStat::EnableStat(const char* name, bool on) +{ + FStat* stat = FindStat(name); + if (stat) + stat->m_Active = on; + else + Printf("Unknown stat: %s\n", name); +} + void FStat::ToggleStat () { m_Active = !m_Active; } -void FStat::PrintStat () +void FStat::PrintStat (F2DDrawer *drawer) { - int textScale = active_con_scale(); + int textScale = active_con_scale(drawer); int fontheight = NewConsoleFont->GetHeight() + 1; - int y = SCREENHEIGHT / textScale; + int y = drawer->GetHeight() / textScale; int count = 0; for (FStat *stat = FirstStat; stat != NULL; stat = stat->m_Next) @@ -105,9 +116,9 @@ void FStat::PrintStat () // Count number of linefeeds but ignore terminating ones. if (stattext[i] == '\n') y -= fontheight; } - screen->DrawText(NewConsoleFont, CR_GREEN, 5 / textScale, y, stattext, - DTA_VirtualWidth, screen->GetWidth() / textScale, - DTA_VirtualHeight, screen->GetHeight() / textScale, + DrawText(drawer, NewConsoleFont, CR_GREEN, 5 / textScale, y, stattext.GetChars(), + DTA_VirtualWidth, twod->GetWidth() / textScale, + DTA_VirtualHeight, twod->GetHeight() / textScale, DTA_KeepRatio, true, TAG_DONE); count++; } diff --git a/src/common/engine/stats.h b/src/common/engine/stats.h new file mode 100644 index 00000000000..c7473531e6c --- /dev/null +++ b/src/common/engine/stats.h @@ -0,0 +1,344 @@ +/* +** stats.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __STATS_H__ +#define __STATS_H__ + +#include "zstring.h" +#if defined __i386__ +#include "x86.h" +#endif + +#if !defined _WIN32 && !defined __APPLE__ + +#ifdef NO_CLOCK_GETTIME +class cycle_t +{ +public: + cycle_t &operator= (const cycle_t &o) { return *this; } + void Reset() {} + void Clock() {} + void ResetAndClock() {} + void Unclock() {} + double Time() { return 0; } + double TimeMS() { return 0; } +}; + +#else + +#include + +// [MK] try to use RDTSC on linux if possible +// avoids excess latency of clock_gettime() on some platforms +#ifdef __linux__ +extern bool PerfAvailable; +extern double PerfToSec, PerfToMillisec; + +inline uint64_t rdtsc() +{ +#ifdef __amd64__ + uint64_t tsc; + asm volatile("rdtsc; shlq $32, %%rdx; orq %%rdx, %%rax":"=a"(tsc)::"%rdx"); + return tsc; +#elif defined __ppc__ + unsigned int lower, upper, temp; + do + { + asm volatile ("mftbu %0 \n mftb %1 \n mftbu %2 \n" + : "=r"(upper), "=r"(lower), "=r"(temp)); + } + while (upper != temp); + return (static_cast(upper) << 32) | lower; +#elif defined __aarch64__ + uint64_t vct; + asm volatile("mrs %0, cntvct_el0":"=r"(vct)); + return vct; +#elif defined __i386__ + if (CPU.bRDTSC) + { + uint64_t tsc; + asm volatile ("\trdtsc\n" : "=A" (tsc)); + return tsc; + } + return 0; +#else + return 0; +#endif // __amd64__ +} +#endif + +class cycle_t +{ +public: + void Reset() + { + Sec = 0; + } + + void Clock() + { +#ifdef __linux__ + if ( PerfAvailable ) + { + int64_t time = rdtsc(); + Sec -= time * PerfToSec; + return; + } +#endif + timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + Sec -= ts.tv_sec + ts.tv_nsec * 1e-9; + } + + void ResetAndClock() + { + Reset(); + Clock(); + } + + void Unclock() + { +#ifdef __linux__ + if ( PerfAvailable ) + { + int64_t time = rdtsc(); + Sec += time * PerfToSec; + return; + } +#endif + timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + Sec += ts.tv_sec + ts.tv_nsec * 1e-9; + } + + double Time() + { + return Sec; + } + + double TimeMS() + { + return Sec * 1e3; + } + +private: + double Sec; +}; + +#endif + +#else + +// Windows and macOS + +extern double PerfToSec, PerfToMillisec; + +#if defined(_MSC_VER) && !defined(_M_ARM64) +// Trying to include intrin.h here results in some bizarre errors, so I'm just +// going to duplicate the function prototype instead. +//#include +extern "C" unsigned __int64 __rdtsc(void); +#pragma intrinsic(__rdtsc) +inline unsigned __int64 rdtsc() +{ + return __rdtsc(); +} +#elif defined(_MSC_VER) && defined(_M_ARM64) +#include +inline unsigned __int64 rdtsc() +{ + return _ReadStatusReg(ARM64_SYSREG(0b11, 0b011, 0b1001, 0b1101, 0b000)); //_ReadStatusReg(PMCCNTR_EL0); +} +#elif defined __APPLE__ && (defined __i386__ || defined __x86_64__) +inline uint64_t rdtsc() +{ + return __builtin_ia32_rdtsc(); +} +#else +inline uint64_t rdtsc() +{ +#ifdef __amd64__ + uint64_t tsc; + asm volatile ("rdtsc; shlq $32, %%rdx; orq %%rdx, %%rax" : "=a" (tsc) :: "%rdx"); + return tsc; +#elif defined __ppc__ + unsigned int lower, upper, temp; + do + { + asm volatile ("mftbu %0 \n mftb %1 \n mftbu %2 \n" + : "=r"(upper), "=r"(lower), "=r"(temp)); + } + while (upper != temp); + return (static_cast(upper) << 32) | lower; +#elif defined __aarch64__ + uint64_t vct; + asm volatile("mrs %0, cntvct_el0":"=r"(vct)); + return vct; +#elif defined __i386__ // i386 + if (CPU.bRDTSC) + { + uint64_t tsc; + asm volatile ("\trdtsc\n" : "=A" (tsc)); + return tsc; + } + return 0; +#else + return 0; +#endif // __amd64__ +} +#endif + +class cycle_t +{ +public: + void Reset() + { + Counter = 0; + } + + void ResetAndClock() + { + Counter = -static_cast(rdtsc()); + } + + void Clock() + { + int64_t time = rdtsc(); + Counter -= time; + } + + void Unclock(bool checkvar = true) + { + int64_t time = rdtsc(); + Counter += time; + } + + double Time() + { + return Counter * PerfToSec; + } + + double TimeMS() + { + return Counter * PerfToMillisec; + } + + int64_t GetRawCounter() + { + return Counter; + } + +private: + int64_t Counter; +}; + +#endif + +class glcycle_t : public cycle_t +{ +public: + static bool active; + void Clock() + { + if (active) cycle_t::Clock(); + } + + void Unclock() + { + if (active) cycle_t::Unclock(); + } +}; + +// Helper for code that uses a timer and has multiple exit points. +class Clocker +{ +public: + + explicit Clocker(glcycle_t& clck) + : clock(clck) + { + clock.Clock(); + } + + ~Clocker() + { // unlock + clock.Unclock(); + } + + Clocker(const Clocker&) = delete; + Clocker& operator=(const Clocker&) = delete; +private: + glcycle_t & clock; +}; + + +class F2DDrawer; + +class FStat +{ +public: + FStat (const char *name); + virtual ~FStat (); + + virtual FString GetStats () = 0; + + void ToggleStat (); + bool isActive() const + { + return m_Active; + } + + static void PrintStat (F2DDrawer *drawer); + static FStat *FindStat (const char *name); + static void ToggleStat (const char *name); + static void EnableStat(const char* name, bool on); + static void DumpRegisteredStats (); + +private: + FStat *m_Next; + const char *m_Name; + bool m_Active; + + static FStat *FirstStat; +}; + +#define ADD_STAT(n) \ + static class Stat_##n : public FStat { \ + public: \ + Stat_##n () : FStat (#n) {} \ + FString GetStats (); } Istaticstat##n; \ + FString Stat_##n::GetStats () + +#endif //__STATS_H__ diff --git a/src/gamedata/stringtable.cpp b/src/common/engine/stringtable.cpp similarity index 79% rename from src/gamedata/stringtable.cpp rename to src/common/engine/stringtable.cpp index 60befef90f4..d9d739b57aa 100644 --- a/src/gamedata/stringtable.cpp +++ b/src/common/engine/stringtable.cpp @@ -36,15 +36,10 @@ #include "stringtable.h" #include "cmdlib.h" -#include "w_wad.h" -#include "i_system.h" +#include "filesystem.h" #include "sc_man.h" -#include "c_dispatch.h" -#include "v_text.h" -#include "gi.h" -#include "d_player.h" - -EXTERN_CVAR(String, language) +#include "printf.h" +#include "i_interface.h" //========================================================================== // @@ -52,25 +47,28 @@ EXTERN_CVAR(String, language) // //========================================================================== -void FStringTable::LoadStrings () +void FStringTable::LoadStrings (FileSys::FileSystem& fileSystem, const char *language) { int lastlump, lump; + allStrings.Clear(); lastlump = 0; - while ((lump = Wads.FindLump("LMACROS", &lastlump)) != -1) + while ((lump = fileSystem.FindLump("LMACROS", &lastlump)) != -1) { - readMacros(lump); + auto lumpdata = fileSystem.ReadFile(lump); + readMacros(lumpdata.string(), lumpdata.size()); } lastlump = 0; - while ((lump = Wads.FindLump ("LANGUAGE", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("LANGUAGE", &lastlump)) != -1) { - auto lumpdata = Wads.ReadLumpIntoArray(lump); + auto lumpdata = fileSystem.ReadFile(lump); + auto filenum = fileSystem.GetFileContainer(lump); - if (!ParseLanguageCSV(lump, lumpdata)) - LoadLanguage (lump, lumpdata); + if (!ParseLanguageCSV(filenum, lumpdata.string(), lumpdata.size())) + LoadLanguage (filenum, lumpdata.string(), lumpdata.size()); } - UpdateLanguage(); + UpdateLanguage(language); allMacros.Clear(); } @@ -82,9 +80,9 @@ void FStringTable::LoadStrings () //========================================================================== -TArray> FStringTable::parseCSV(const TArray &buffer) +TArray> FStringTable::parseCSV(const char* buffer, size_t size) { - const size_t bufLength = buffer.Size(); + const size_t bufLength = size; TArray> data; TArray row; TArray cell; @@ -161,18 +159,15 @@ TArray> FStringTable::parseCSV(const TArray &buffer) // //========================================================================== -bool FStringTable::readMacros(int lumpnum) +bool FStringTable::readMacros(const char* buffer, size_t size) { - auto lumpdata = Wads.ReadLumpIntoArray(lumpnum); - auto data = parseCSV(lumpdata); + auto data = parseCSV(buffer, size); + allMacros.Clear(); for (unsigned i = 1; i < data.Size(); i++) { auto macroname = data[i][0]; - auto language = data[i][1]; - if (macroname.IsEmpty() || language.IsEmpty()) continue; - FStringf combined_name("%s/%s", language.GetChars(), macroname.GetChars()); - FName name = combined_name; + FName name = macroname.GetChars(); StringMacro macro; @@ -191,11 +186,11 @@ bool FStringTable::readMacros(int lumpnum) // //========================================================================== -bool FStringTable::ParseLanguageCSV(int lumpnum, const TArray &buffer) +bool FStringTable::ParseLanguageCSV(int filenum, const char* buffer, size_t size) { - if (buffer.Size() < 11) return false; - if (strnicmp((const char*)buffer.Data(), "default,", 8) && strnicmp((const char*)buffer.Data(), "identifier,", 11 )) return false; - auto data = parseCSV(buffer); + if (size < 11) return false; + if (strnicmp(buffer, "default,", 8) && strnicmp(buffer, "identifier,", 11 )) return false; + auto data = parseCSV(buffer, size); int labelcol = -1; int filtercol = -1; @@ -240,22 +235,37 @@ bool FStringTable::ParseLanguageCSV(int lumpnum, const TArray &buffer) if (filtercol > -1) { auto filterstr = row[filtercol]; - auto filter = filterstr.Split(" ", FString::TOK_SKIPEMPTY); - if (filter.Size() > 0 && filter.FindEx([](const auto &str) { return str.CompareNoCase(GameNames[gameinfo.gametype]) == 0; }) == filter.Size()) - continue; + if (filterstr.IsNotEmpty()) + { + bool ok = false; + if (sysCallbacks.CheckGame) + { + auto filter = filterstr.Split(" ", FString::TOK_SKIPEMPTY); + for (auto& entry : filter) + { + if (sysCallbacks.CheckGame(entry.GetChars())) + { + ok = true; + break; + } + } + } + if (!ok) continue; + } } - FName strName = row[labelcol]; + row[labelcol].StripLeftRight(); + FName strName = row[labelcol].GetChars(); if (hasDefaultEntry) { - DeleteForLabel(lumpnum, strName); + DeleteForLabel(filenum, strName); } for (auto &langentry : langrows) { auto str = row[langentry.first]; if (str.Len() > 0) { - InsertString(lumpnum, langentry.second, strName, str); + InsertString(filenum, langentry.second, strName, str); } else { @@ -273,14 +283,14 @@ bool FStringTable::ParseLanguageCSV(int lumpnum, const TArray &buffer) // //========================================================================== -void FStringTable::LoadLanguage (int lumpnum, const TArray &buffer) +void FStringTable::LoadLanguage (int lumpnum, const char* buffer, size_t size) { bool errordone = false; TArray activeMaps; FScanner sc; bool hasDefaultEntry = false; - sc.OpenMem("LANGUAGE", buffer); + sc.OpenMem("LANGUAGE", buffer, (int)size); sc.SetCMode (true); while (sc.GetString ()) { @@ -314,7 +324,7 @@ void FStringTable::LoadLanguage (int lumpnum, const TArray &buffer) } else { - sc.ScriptError ("The language code must be 2 or 3 characters long.\n'%s' is %lu characters long.", + sc.ScriptError ("The language code must be 2 or 3 characters long.\n'%s' is %zu characters long.", sc.String, len); } } @@ -348,14 +358,7 @@ void FStringTable::LoadLanguage (int lumpnum, const TArray &buffer) sc.MustGetStringName("ifgame"); sc.MustGetStringName("("); sc.MustGetString(); - if (sc.Compare("strifeteaser")) - { - skip |= (gameinfo.gametype != GAME_Strife) || !(gameinfo.flags & GI_SHAREWARE); - } - else - { - skip |= !sc.Compare(GameTypeName()); - } + skip |= (!sysCallbacks.CheckGame || !sysCallbacks.CheckGame(sc.String)); sc.MustGetStringName(")"); sc.MustGetString(); @@ -406,11 +409,10 @@ void FStringTable::DeleteString(int langid, FName label) // //========================================================================== -void FStringTable::DeleteForLabel(int lumpnum, FName label) +void FStringTable::DeleteForLabel(int filenum, FName label) { decltype(allStrings)::Iterator it(allStrings); decltype(allStrings)::Pair *pair; - auto filenum = Wads.GetLumpFile(lumpnum); while (it.NextPair(pair)) { @@ -429,11 +431,11 @@ void FStringTable::DeleteForLabel(int lumpnum, FName label) // //========================================================================== -void FStringTable::InsertString(int lumpnum, int langid, FName label, const FString &string) +void FStringTable::InsertString(int filenum, int langid, FName label, const FString &string) { const char *strlangid = (const char *)&langid; - TableElement te = { Wads.GetLumpFile(lumpnum), { string, string, string, string } }; - long index; + TableElement te = { filenum, { string, string, string, string } }; + ptrdiff_t index; while ((index = te.strings[0].IndexOf("@[")) >= 0) { auto endindex = te.strings[0].IndexOf(']', index); @@ -443,13 +445,12 @@ void FStringTable::InsertString(int lumpnum, int langid, FName label, const FStr break; } FString macroname(te.strings[0].GetChars() + index + 2, endindex - index - 2); - FStringf lookupstr("%s/%s", strlangid, macroname.GetChars()); FStringf replacee("@[%s]", macroname.GetChars()); - FName lookupname(lookupstr, true); + FName lookupname(macroname.GetChars(), true); auto replace = allMacros.CheckKey(lookupname); for (int i = 0; i < 4; i++) { - const char *replacement = replace && replace->Replacements[i] ? replace->Replacements[i] : ""; + const char *replacement = replace? replace->Replacements[i].GetChars() : ""; te.strings[i].Substitute(replacee, replacement); } } @@ -462,8 +463,10 @@ void FStringTable::InsertString(int lumpnum, int langid, FName label, const FStr // //========================================================================== -void FStringTable::UpdateLanguage() +void FStringTable::UpdateLanguage(const char *language) { + if (language) activeLanguage = language; + else language = activeLanguage.GetChars(); size_t langlen = strlen(language); int LanguageID = (langlen < 2 || langlen > 3) ? @@ -479,7 +482,7 @@ void FStringTable::UpdateLanguage() currentLanguageSet.Push(std::make_pair(lang_id, list)); }; - checkone(dehacked_table); + checkone(override_table); checkone(global_table); checkone(LanguageID); checkone(LanguageID & MAKE_ID(0xff, 0xff, 0, 0)); @@ -509,6 +512,26 @@ size_t FStringTable::ProcessEscapes (char *iptr) c = '\r'; else if (c == 't') c = '\t'; + else if (c == 'x') + { + c = 0; + for (int i = 0; i < 2; i++) + { + char cc = *iptr++; + if (cc >= '0' && cc <= '9') + c = (c << 4) + cc - '0'; + else if (cc >= 'a' && cc <= 'f') + c = (c << 4) + 10 + cc - 'a'; + else if (cc >= 'A' && cc <= 'F') + c = (c << 4) + 10 + cc - 'A'; + else + { + iptr--; + break; + } + } + if (c == 0) continue; + } else if (c == '\n') continue; } @@ -534,7 +557,7 @@ bool FStringTable::exists(const char *name) FName nm(name, true); if (nm != NAME_None) { - uint32_t defaultStrings[] = { default_table, global_table, dehacked_table }; + uint32_t defaultStrings[] = { default_table, global_table, override_table }; for (auto mapid : defaultStrings) { @@ -555,24 +578,34 @@ bool FStringTable::exists(const char *name) // //========================================================================== -const char *FStringTable::GetString(const char *name, uint32_t *langtable, int gender) const +const char *FStringTable::CheckString(const char *name, uint32_t *langtable, int gender) const { if (name == nullptr || *name == 0) { return nullptr; } - if (gender == -1) gender = players[consoleplayer].userinfo.GetGender(); + if (gender == -1) gender = defaultgender; if (gender < 0 || gender > 3) gender = 0; FName nm(name, true); if (nm != NAME_None) { + TableElement* bestItem = nullptr; for (auto map : currentLanguageSet) { auto item = map.second->CheckKey(nm); if (item) { + if (bestItem && bestItem->filenum > item->filenum) + { + // prioritize content from later files, even if the language doesn't fully match. + // This is mainly for Dehacked content. + continue; + } if (langtable) *langtable = map.first; - return item->strings[gender].GetChars(); + auto c = item->strings[gender].GetChars(); + if (c && *c == '$' && c[1] == '$') + c = CheckString(c + 2, langtable, gender); + return c; } } } @@ -581,7 +614,7 @@ const char *FStringTable::GetString(const char *name, uint32_t *langtable, int g //========================================================================== // -// Finds a string by name in a given language +// Finds a string by name in a given language without attempting any substitution // //========================================================================== @@ -591,7 +624,7 @@ const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable { return nullptr; } - if (gender == -1) gender = players[consoleplayer].userinfo.GetGender(); + if (gender == -1) gender = defaultgender; if (gender < 0 || gender > 3) gender = 0; FName nm(name, true); if (nm != NAME_None) @@ -612,10 +645,10 @@ bool FStringTable::MatchDefaultString(const char *name, const char *content) con // This only compares the first line to avoid problems with bad linefeeds. For the few cases where this feature is needed it is sufficient. auto c = GetLanguageString(name, FStringTable::default_table); if (!c) return false; - + // Check a secondary key, in case the text comparison cannot be done due to needed orthographic fixes (see Harmony's exit text) FStringf checkkey("%s_CHECK", name); - auto cc = GetLanguageString(checkkey, FStringTable::default_table); + auto cc = GetLanguageString(checkkey.GetChars(), FStringTable::default_table); if (cc) c = cc; return (c && !strnicmp(c, content, strcspn(content, "\n\r\t"))); @@ -628,9 +661,9 @@ bool FStringTable::MatchDefaultString(const char *name, const char *content) con // //========================================================================== -const char *FStringTable::operator() (const char *name) const +const char *FStringTable::GetString(const char *name) const { - const char *str = operator[] (name); + const char *str = CheckString(name, nullptr); return str ? str : name; } @@ -657,3 +690,7 @@ const char *StringMap::MatchString (const char *string) const } return nullptr; } + +FStringTable GStrings; + + diff --git a/src/common/engine/stringtable.h b/src/common/engine/stringtable.h new file mode 100644 index 00000000000..181d8c7f399 --- /dev/null +++ b/src/common/engine/stringtable.h @@ -0,0 +1,142 @@ +/* +** stringtable.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +** FStringTable +** +** This class manages a list of localizable strings stored in a wad file. +*/ + +#ifndef __STRINGTABLE_H__ +#define __STRINGTABLE_H__ + +#ifdef _MSC_VER +#pragma once +#endif + + +#include +#include +#include "basics.h" +#include "zstring.h" +#include "tarray.h" +#include "name.h" + + +struct TableElement +{ + int filenum; + FString strings[4]; +}; + +// This public interface is for Dehacked +class StringMap : public TMap +{ +public: + const char *MatchString(const char *string) const; +}; + + +struct StringMacro +{ + FString Replacements[4]; +}; + + +class FStringTable +{ +public: + enum : uint32_t + { + default_table = MAKE_ID('*', '*', 0, 0), + global_table = MAKE_ID('*', 0, 0, 0), + override_table = MAKE_ID('*', '*', '*', 0) + }; + + using LangMap = TMap; + using StringMacroMap = TMap; + + void LoadStrings(FileSys::FileSystem& fileSystem, const char *language); + void UpdateLanguage(const char* language); + StringMap GetDefaultStrings() { return allStrings[default_table]; } // Dehacked needs these for comparison + void SetOverrideStrings(StringMap & map) + { + allStrings.Insert(override_table, map); + UpdateLanguage(nullptr); + } + + const char *GetLanguageString(const char *name, uint32_t langtable, int gender = -1) const; + bool MatchDefaultString(const char *name, const char *content) const; + const char *CheckString(const char *name, uint32_t *langtable = nullptr, int gender = -1) const; + const char* GetString(const char* name) const; + const char* GetString(const FString& name) const { return GetString(name.GetChars()); } + bool exists(const char *name); + + void InsertString(int filenum, int langid, FName label, const FString& string); + void SetDefaultGender(int gender) { defaultgender = gender; } + +private: + + FString activeLanguage; + StringMacroMap allMacros; + LangMap allStrings; + TArray> currentLanguageSet; + int defaultgender = 0; + + void LoadLanguage (int lumpnum, const char* buffer, size_t size); + TArray> parseCSV(const char* buffer, size_t size); + bool ParseLanguageCSV(int filenum, const char* buffer, size_t size); + + bool readMacros(const char* buffer, size_t size); + void DeleteString(int langid, FName label); + void DeleteForLabel(int filenum, FName label); + + static size_t ProcessEscapes (char *str); +public: + static FString MakeMacro(const char *str) + { + if (*str == '$') return str; + return FString("$") + str; + } + + static FString MakeMacro(const char *str, size_t len) + { + if (*str == '$') return FString(str, len); + return "$" + FString(str, len); + } + + const char* localize(const char* str) + { + return *str == '$' ? GetString(str + 1) : str; + } +}; + +#endif //__STRINGTABLE_H__ diff --git a/src/common/engine/v_colortables.cpp b/src/common/engine/v_colortables.cpp new file mode 100644 index 00000000000..b891ff142dd --- /dev/null +++ b/src/common/engine/v_colortables.cpp @@ -0,0 +1,103 @@ +/* +** v_colortables.cpp +** Various color blending tables +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + + +#include "v_colortables.h" +#include "colormatcher.h" + +uint32_t Col2RGB8[65][256]; +uint32_t *Col2RGB8_LessPrecision[65]; +uint32_t Col2RGB8_Inverse[65][256]; +uint32_t Col2RGB8_2[63][256]; // this array's second dimension is called up by pointer as Col2RGB8_LessPrecision[] elsewhere. +ColorTable32k RGB32k; +ColorTable256k RGB256k; + + + +//========================================================================== +// +// BuildTransTable +// +// Build the tables necessary for blending - used by software rendering and +// texture composition +// +//========================================================================== + +void BuildTransTable (const PalEntry *palette) +{ + int r, g, b; + + // create the RGB555 lookup table + for (r = 0; r < 32; r++) + for (g = 0; g < 32; g++) + for (b = 0; b < 32; b++) + RGB32k.RGB[r][g][b] = ColorMatcher.Pick ((r<<3)|(r>>2), (g<<3)|(g>>2), (b<<3)|(b>>2)); + // create the RGB666 lookup table + for (r = 0; r < 64; r++) + for (g = 0; g < 64; g++) + for (b = 0; b < 64; b++) + RGB256k.RGB[r][g][b] = ColorMatcher.Pick ((r<<2)|(r>>4), (g<<2)|(g>>4), (b<<2)|(b>>4)); + + int x, y; + + // create the swizzled palette + for (x = 0; x < 65; x++) + for (y = 0; y < 256; y++) + Col2RGB8[x][y] = (((palette[y].r*x)>>4)<<20) | + ((palette[y].g*x)>>4) | + (((palette[y].b*x)>>4)<<10); + + // create the swizzled palette with the lsb of red and blue forced to 0 + // (for green, a 1 is okay since it never gets added into) + for (x = 1; x < 64; x++) + { + Col2RGB8_LessPrecision[x] = Col2RGB8_2[x-1]; + for (y = 0; y < 256; y++) + { + Col2RGB8_2[x-1][y] = Col2RGB8[x][y] & 0x3feffbff; + } + } + Col2RGB8_LessPrecision[0] = Col2RGB8[0]; + Col2RGB8_LessPrecision[64] = Col2RGB8[64]; + + // create the inverse swizzled palette + for (x = 0; x < 65; x++) + for (y = 0; y < 256; y++) + { + Col2RGB8_Inverse[x][y] = (((((255-palette[y].r)*x)>>4)<<20) | + (((255-palette[y].g)*x)>>4) | + ((((255-palette[y].b)*x)>>4)<<10)) & 0x3feffbff; + } +} + diff --git a/src/r_data/v_colortables.h b/src/common/engine/v_colortables.h similarity index 95% rename from src/r_data/v_colortables.h rename to src/common/engine/v_colortables.h index 42135229b93..3f237147f80 100644 --- a/src/r_data/v_colortables.h +++ b/src/common/engine/v_colortables.h @@ -1,5 +1,8 @@ #pragma once +#include +#include "palentry.h" + // extracted from v_video.h because this caused circular dependencies between v_video.h and textures.h // Translucency tables @@ -50,3 +53,5 @@ extern uint32_t Col2RGB8_Inverse[65][256]; // ------10000000001000000000100000 = 0x40100400 >> 5 // --11111-----11111-----11111----- = 0x40100400 - (0x40100400 >> 5) aka "white" // --111111111111111111111111111111 = 0x3FFFFFFF + +void BuildTransTable (const PalEntry *palette); diff --git a/src/common/filesystem/include/fs_decompress.h b/src/common/filesystem/include/fs_decompress.h new file mode 100644 index 00000000000..0ea062ddb4e --- /dev/null +++ b/src/common/filesystem/include/fs_decompress.h @@ -0,0 +1,63 @@ +#pragma once +#include "fs_files.h" + +namespace FileSys { + +// Zip compression methods, extended by some internal types to be passed to OpenDecompressor +enum ECompressionMethod +{ + METHOD_STORED = 0, + METHOD_SHRINK = 1, + METHOD_IMPLODE = 6, + METHOD_DEFLATE = 8, + METHOD_BZIP2 = 12, + METHOD_LZMA = 14, + METHOD_XZ = 95, + METHOD_PPMD = 98, + METHOD_LZSS = 1337, // not used in Zips - this is for Console Doom compression + METHOD_ZLIB = 1338, // Zlib stream with header, used by compressed nodes. + METHOD_RFFCRYPT = 1339, // not actual compression but can be put in here to make handling easier. + METHOD_IMPLODE_MIN = 1000, // having discrete types for these avoids keeping around the GPFlags word in Zips. + METHOD_IMPLODE_0 = 1000, + METHOD_IMPLODE_2 = 1002, + METHOD_IMPLODE_4 = 1004, + METHOD_IMPLODE_6 = 1006, + METHOD_IMPLODE_MAX = 1006, + METHOD_INVALID = 0x7fff, + METHOD_TRANSFEROWNER = 0x8000, +}; + +enum EDecompressFlags +{ + DCF_TRANSFEROWNER = 1, + DCF_SEEKABLE = 2, + DCF_EXCEPTIONS = 4, + DCF_CACHED = 8, +}; + +bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size length, int method, int flags = 0); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used. + +// This holds a compresed Zip entry with all needed info to decompress it. +struct FCompressedBuffer +{ + size_t mSize; + size_t mCompressedSize; + int mMethod; + unsigned mCRC32; + char* mBuffer; + const char* filename; + + bool Decompress(char* destbuffer); + void Clean() + { + mSize = mCompressedSize = 0; + if (mBuffer != nullptr) + { + delete[] mBuffer; + mBuffer = nullptr; + } + } +}; + + +} diff --git a/src/common/filesystem/include/fs_files.h b/src/common/filesystem/include/fs_files.h new file mode 100644 index 00000000000..7702f68de3f --- /dev/null +++ b/src/common/filesystem/include/fs_files.h @@ -0,0 +1,419 @@ +/* +** files.h +** Implements classes for reading from files or memory blocks +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** Copyright 2005-2023 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef FILES_H +#define FILES_H + +#include +#include +#include +#include +#include +#include +#include +#include "fs_swap.h" + +namespace FileSys { + +class FileSystemException : public std::exception +{ +protected: + static const int MAX_FSERRORTEXT = 1024; + char m_Message[MAX_FSERRORTEXT]; + +public: + FileSystemException(const char* error, ...) + { + va_list argptr; + va_start(argptr, error); + vsnprintf(m_Message, MAX_FSERRORTEXT, error, argptr); + va_end(argptr); + } + FileSystemException(const char* error, va_list argptr) + { + vsnprintf(m_Message, MAX_FSERRORTEXT, error, argptr); + } + char const* what() const noexcept override + { + return m_Message; + } +}; + +class FileReader; + +// an opaque memory buffer to the file's content. Can either own the memory or just point to an external buffer. +class FileData +{ + void* memory; + size_t length; + bool owned; + +public: + using value_type = uint8_t; + FileData() { memory = nullptr; length = 0; owned = true; } + FileData(const void* memory_, size_t len, bool own = true) + { + length = len; + if (own) + { + length = len; + memory = malloc(len); + owned = true; + if (memory_) memcpy(memory, memory_, len); + } + else + { + memory = (void*)memory_; + owned = false; + } + } + uint8_t* writable() const { return owned? (uint8_t*)memory : nullptr; } + const void* data() const { return memory; } + size_t size() const { return length; } + const char* string() const { return (const char*)memory; } + const uint8_t* bytes() const { return (const uint8_t*)memory; } + + FileData& operator = (const FileData& copy) + { + if (owned && memory) free(memory); + length = copy.length; + owned = copy.owned; + if (owned) + { + memory = malloc(length); + memcpy(memory, copy.memory, length); + } + else memory = copy.memory; + return *this; + } + + FileData& operator = (FileData&& copy) noexcept + { + if (owned && memory) free(memory); + length = copy.length; + owned = copy.owned; + memory = copy.memory; + copy.memory = nullptr; + copy.length = 0; + copy.owned = true; + return *this; + } + + FileData(const FileData& copy) + { + memory = nullptr; + *this = copy; + } + + ~FileData() + { + if (owned && memory) free(memory); + } + + void* allocate(size_t len) + { + if (!owned) memory = nullptr; + length = len; + owned = true; + memory = realloc(memory, length); + return memory; + } + + void set(const void* mem, size_t len) + { + memory = (void*)mem; + length = len; + owned = false; + } + + void clear() + { + if (owned && memory) free(memory); + memory = nullptr; + length = 0; + owned = true; + } + +}; + + +class FileReaderInterface +{ +public: + ptrdiff_t Length = -1; + virtual ~FileReaderInterface() {} + virtual ptrdiff_t Tell () const = 0; + virtual ptrdiff_t Seek (ptrdiff_t offset, int origin) = 0; + virtual ptrdiff_t Read (void *buffer, ptrdiff_t len) = 0; + virtual char *Gets(char *strbuf, ptrdiff_t len) = 0; + virtual const char *GetBuffer() const { return nullptr; } + ptrdiff_t GetLength () const { return Length; } +}; + +class FileReader +{ + FileReaderInterface *mReader = nullptr; + + FileReader(const FileReader &r) = delete; + FileReader &operator=(const FileReader &r) = delete; + +public: + + explicit FileReader(FileReaderInterface *r) + { + mReader = r; + } + + enum ESeek + { + SeekSet = SEEK_SET, + SeekCur = SEEK_CUR, + SeekEnd = SEEK_END + }; + + typedef ptrdiff_t Size; // let's not use 'long' here. + + FileReader() {} + + FileReader(FileReader &&r) noexcept + { + mReader = r.mReader; + r.mReader = nullptr; + } + + FileReader& operator =(FileReader &&r) noexcept + { + Close(); + mReader = r.mReader; + r.mReader = nullptr; + return *this; + } + + // This is for wrapping the actual reader for custom access where a managed FileReader won't work. + FileReaderInterface* GetInterface() + { + auto i = mReader; + mReader = nullptr; + return i; + } + + + ~FileReader() + { + Close(); + } + + bool isOpen() const + { + return mReader != nullptr; + } + + void Close() + { + if (mReader != nullptr) delete mReader; + mReader = nullptr; + } + + bool OpenFile(const char *filename, Size start = 0, Size length = -1, bool buffered = false); + bool OpenFilePart(FileReader &parent, Size start, Size length); + bool OpenMemory(const void *mem, Size length); // read directly from the buffer + bool OpenMemoryArray(FileData& data); // take the given array + + Size Tell() const + { + return mReader->Tell(); + } + + Size Seek(Size offset, ESeek origin) + { + return mReader->Seek(offset, origin); + } + + Size Read(void *buffer, Size len) const + { + return mReader->Read(buffer, len); + } + + FileData Read(size_t len); + FileData ReadPadded(size_t padding); + + FileData Read() + { + return Read(GetLength()); + } + + + char *Gets(char *strbuf, Size len) + { + return mReader->Gets(strbuf, len); + } + + const char *GetBuffer() + { + return mReader->GetBuffer(); + } + + Size GetLength() const + { + return mReader->GetLength(); + } + + uint8_t ReadUInt8() + { + uint8_t v = 0; + Read(&v, 1); + return v; + } + + int8_t ReadInt8() + { + int8_t v = 0; + Read(&v, 1); + return v; + } + + + uint16_t ReadUInt16() + { + uint16_t v = 0; + Read(&v, 2); + return byteswap::LittleShort(v); + } + + int16_t ReadInt16() + { + return (int16_t)ReadUInt16(); + } + + int16_t ReadUInt16BE() + { + uint16_t v = 0; + Read(&v, 2); + return byteswap::BigShort(v); + } + + int16_t ReadInt16BE() + { + return (int16_t)ReadUInt16BE(); + } + + uint32_t ReadUInt32() + { + uint32_t v = 0; + Read(&v, 4); + return byteswap::LittleLong(v); + } + + int32_t ReadInt32() + { + return (int32_t)ReadUInt32(); + } + + uint32_t ReadUInt32BE() + { + uint32_t v = 0; + Read(&v, 4); + return byteswap::BigLong(v); + } + + int32_t ReadInt32BE() + { + return (int32_t)ReadUInt32BE(); + } + + uint64_t ReadUInt64() + { + uint64_t v = 0; + Read(&v, 8); + // Prove to me that there's a relevant 64 bit Big Endian architecture and I fix this! :P + return v; + } + + + friend class FileSystem; +}; + + +class FileWriter +{ +protected: + bool OpenDirect(const char *filename); + +public: + FileWriter(FILE *f = nullptr) // if passed, this writer will take over the file. + { + File = f; + } + virtual ~FileWriter() + { + Close(); + } + + static FileWriter *Open(const char *filename); + + virtual size_t Write(const void *buffer, size_t len); + virtual ptrdiff_t Tell(); + virtual ptrdiff_t Seek(ptrdiff_t offset, int mode); + size_t Printf(const char *fmt, ...); + + virtual void Close() + { + if (File != NULL) fclose(File); + File = nullptr; + } + +protected: + + FILE *File; + +protected: + bool CloseOnDestruct; +}; + +class BufferWriter : public FileWriter +{ +protected: + std::vector mBuffer; +public: + + BufferWriter() {} + virtual size_t Write(const void *buffer, size_t len) override; + std::vector *GetBuffer() { return &mBuffer; } + std::vector&& TakeBuffer() { return std::move(mBuffer); } +}; + +} + +#endif diff --git a/src/common/filesystem/include/fs_filesystem.h b/src/common/filesystem/include/fs_filesystem.h new file mode 100644 index 00000000000..858b7483745 --- /dev/null +++ b/src/common/filesystem/include/fs_filesystem.h @@ -0,0 +1,183 @@ +#pragma once +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// File system I/O functions. +// +//----------------------------------------------------------------------------- + + + +#include "fs_files.h" +#include "resourcefile.h" + +namespace FileSys { + +union LumpShortName +{ + char String[9]; + + uint32_t dword; // These are for accessing the first 4 or 8 chars of + uint64_t qword; // Name as a unit without breaking strict aliasing rules +}; + + +struct FolderEntry +{ + const char *name; + unsigned lumpnum; +}; + +class FileSystem +{ +public: + FileSystem(); + ~FileSystem (); + + // The wadnum for the IWAD + int GetIwadNum() { return IwadIndex; } + void SetIwadNum(int x) { IwadIndex = x; } + + int GetMaxIwadNum() { return MaxIwadIndex; } + void SetMaxIwadNum(int x) { MaxIwadIndex = x; } + + bool InitSingleFile(const char *filename, FileSystemMessageFunc Printf = nullptr); + bool InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false, FILE* hashfile = nullptr); + void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf, FILE* hashfile); + int CheckIfResourceFileLoaded (const char *name) noexcept; + void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {} + + const char *GetResourceFileName (int filenum) const noexcept; + const char *GetResourceFileFullName (int wadnum) const noexcept; + + int GetFirstEntry(int wadnum) const noexcept; + int GetLastEntry(int wadnum) const noexcept; + int GetEntryCount(int wadnum) const noexcept; + + int CheckNumForName (const char *name, int namespc) const; + int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true) const; + int GetNumForName (const char *name, int namespc) const; + + inline int CheckNumForName (const uint8_t *name) const { return CheckNumForName ((const char *)name, ns_global); } + inline int CheckNumForName (const char *name) const { return CheckNumForName (name, ns_global); } + inline int CheckNumForName (const uint8_t *name, int ns) const { return CheckNumForName ((const char *)name, ns); } + inline int GetNumForName (const char *name) const { return GetNumForName (name, ns_global); } + inline int GetNumForName (const uint8_t *name) const { return GetNumForName ((const char *)name); } + inline int GetNumForName (const uint8_t *name, int ns) const { return GetNumForName ((const char *)name, ns); } + + int CheckNumForFullName (const char *cname, bool trynormal = false, int namespc = ns_global, bool ignoreext = false) const; + int CheckNumForFullName (const char *name, int wadfile) const; + int GetNumForFullName (const char *name) const; + int FindFile(const char* name) const + { + return CheckNumForFullName(name); + } + + bool FileExists(const char* name) const + { + return FindFile(name) >= 0; + } + + bool FileExists(const std::string& name) const + { + return FindFile(name.c_str()) >= 0; + } + + LumpShortName& GetShortName(int i); // may only be called before the hash chains are set up. + void RenameFile(int num, const char* fn); + bool CreatePathlessCopy(const char* name, int id, int flags); + + void ReadFile (int lump, void *dest); + // These should only be used if the file data really needs padding. + FileData ReadFile (int lump); + FileData ReadFile (const char *name) { return ReadFile (GetNumForName (name)); } + FileData ReadFileFullName(const char* name) { return ReadFile(GetNumForFullName(name)); } + + FileReader OpenFileReader(int lump, int readertype, int readerflags); // opens a reader that redirects to the containing file's one. + FileReader OpenFileReader(const char* name); + FileReader ReopenFileReader(const char* name, bool alwayscache = false); + FileReader OpenFileReader(int lump) + { + return OpenFileReader(lump, READER_SHARED, READERFLAG_SEEKABLE); + } + + FileReader ReopenFileReader(int lump, bool alwayscache = false) + { + return OpenFileReader(lump, alwayscache ? READER_CACHED : READER_NEW, READERFLAG_SEEKABLE); + } + + + int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication + int FindLumpMulti (const char **names, int *lastlump, bool anyns = false, int *nameindex = NULL); // same with multiple possible names + int FindLumpFullName(const char* name, int* lastlump, bool noext = false); + bool CheckFileName (int lump, const char *name); // [RH] True if lump's name == name + + int FindFileWithExtensions(const char* name, const char* const* exts, int count) const; + int FindResource(int resid, const char* type, int filenum = -1) const noexcept; + int GetResource(int resid, const char* type, int filenum = -1) const; + + + static uint32_t LumpNameHash (const char *name); // [RH] Create hash key from an 8-char name + + ptrdiff_t FileLength (int lump) const; + int GetFileFlags (int lump); // Return the flags for this lump + const char* GetFileShortName(int lump) const; + const char *GetFileFullName (int lump, bool returnshort = true) const; // [RH] Returns the lump's full name + std::string GetFileFullPath (int lump) const; // [RH] Returns wad's name + lump's full name + int GetFileContainer (int lump) const; // [RH] Returns wadnum for a specified lump + int GetFileNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to + void SetFileNamespace(int lump, int ns); + int GetResourceId(int lump) const; // Returns the RFF index number for this lump + const char* GetResourceType(int lump) const; + bool CheckFileName (int lump, const char *name) const; // [RH] Returns true if the names match + unsigned GetFilesInFolder(const char *path, std::vector &result, bool atomic) const; + + int GetNumEntries() const + { + return NumEntries; + } + + int GetNumWads() const + { + return (int)Files.size(); + } + + int AddFromBuffer(const char* name, char* data, int size, int id, int flags); + FileReader* GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD + void InitHashChains(); + +protected: + + struct LumpRecord; + + std::vector Files; + std::vector FileInfo; + + std::vector Hashes; // one allocation for all hash lists. + uint32_t *FirstLumpIndex = nullptr; // [RH] Hashing stuff moved out of lumpinfo structure + uint32_t *NextLumpIndex = nullptr; + + uint32_t *FirstLumpIndex_FullName = nullptr; // The same information for fully qualified paths from .zips + uint32_t *NextLumpIndex_FullName = nullptr; + + uint32_t *FirstLumpIndex_NoExt = nullptr; // The same information for fully qualified paths from .zips + uint32_t *NextLumpIndex_NoExt = nullptr; + + uint32_t* FirstLumpIndex_ResId = nullptr; // The same information for fully qualified paths from .zips + uint32_t* NextLumpIndex_ResId = nullptr; + + uint32_t NumEntries = 0; // Not necessarily the same as FileInfo.Size() + uint32_t NumWads = 0; + + int IwadIndex = -1; + int MaxIwadIndex = -1; + + StringPool* stringpool = nullptr; + +private: + void DeleteAll(); + void MoveLumpsInFolder(const char *); + +}; + +} \ No newline at end of file diff --git a/src/common/filesystem/include/fs_findfile.h b/src/common/filesystem/include/fs_findfile.h new file mode 100644 index 00000000000..d8a18c37417 --- /dev/null +++ b/src/common/filesystem/include/fs_findfile.h @@ -0,0 +1,38 @@ +#pragma once +// Directory searching routines + +#include +#include +#include + +namespace FileSys { + +struct FileListEntry +{ + std::string FileName; // file name only + std::string FilePath; // full path to file + std::string FilePathRel; // path relative to the scanned directory. + size_t Length = 0; + bool isDirectory = false; + bool isReadonly = false; + bool isHidden = false; + bool isSystem = false; +}; + +using FileList = std::vector; + +struct FCompressedBuffer; +bool ScanDirectory(std::vector& list, const char* dirpath, const char* match, bool nosubdir = false, bool readhidden = false); +bool FS_DirEntryExists(const char* pathname, bool* isdir); + +inline void FixPathSeparator(char* path) +{ + while (*path) + { + if (*path == '\\') + *path = '/'; + path++; + } +} + +} diff --git a/src/common/filesystem/include/fs_swap.h b/src/common/filesystem/include/fs_swap.h new file mode 100644 index 00000000000..12b988585f6 --- /dev/null +++ b/src/common/filesystem/include/fs_swap.h @@ -0,0 +1,122 @@ +// +// DESCRIPTION: +// Endianess handling, swapping 16bit and 32bit. +// +//----------------------------------------------------------------------------- + + +#ifndef __FS_SWAP_H__ +#define __FS_SWAP_H__ + +#include + +// Endianess handling. +// WAD files are stored little endian. + +#ifdef __APPLE__ +#include +#endif + +namespace FileSys { +namespace byteswap { + +#ifdef __APPLE__ + +inline unsigned short LittleShort(unsigned short x) +{ + return OSSwapLittleToHostInt16(x); +} + +inline unsigned int LittleLong(unsigned int x) +{ + return OSSwapLittleToHostInt32(x); +} + +inline unsigned short BigShort(unsigned short x) +{ + return OSSwapBigToHostInt16(x); +} + +inline unsigned int BigLong(unsigned int x) +{ + return OSSwapBigToHostInt32(x); +} + + +#elif defined __BIG_ENDIAN__ + +// Swap 16bit, that is, MSB and LSB byte. +// No masking with 0xFF should be necessary. +inline unsigned short LittleShort (unsigned short x) +{ + return (unsigned short)((x>>8) | (x<<8)); +} + +inline unsigned int LittleLong (unsigned int x) +{ + return (unsigned int)( + (x>>24) + | ((x>>8) & 0xff00) + | ((x<<8) & 0xff0000) + | (x<<24)); +} + +inline unsigned short BigShort(unsigned short x) +{ + return x; +} + +inline unsigned int BigLong(unsigned int x) +{ + return x; +} + +#else + +inline unsigned short LittleShort(unsigned short x) +{ + return x; +} + +inline unsigned int LittleLong(unsigned int x) +{ + return x; +} + +#ifdef _MSC_VER + +inline unsigned short BigShort(unsigned short x) +{ + return _byteswap_ushort(x); +} + +inline unsigned int BigLong(unsigned int x) +{ + return (unsigned int)_byteswap_ulong((unsigned long)x); +} + +#pragma warning (default: 4035) + +#else + +inline unsigned short BigShort (unsigned short x) +{ + return (unsigned short)((x>>8) | (x<<8)); +} + +inline unsigned int BigLong (unsigned int x) +{ + return (unsigned int)( + (x>>24) + | ((x>>8) & 0xff00) + | ((x<<8) & 0xff0000) + | (x<<24)); +} + +#endif + +#endif // __BIG_ENDIAN__ +} +} + +#endif // __M_SWAP_H__ diff --git a/src/common/filesystem/include/resourcefile.h b/src/common/filesystem/include/resourcefile.h new file mode 100644 index 00000000000..a23914444ed --- /dev/null +++ b/src/common/filesystem/include/resourcefile.h @@ -0,0 +1,210 @@ + + +#ifndef __RESFILE_H +#define __RESFILE_H + +#include +#include +#include +#include "fs_files.h" +#include "fs_decompress.h" + +namespace FileSys { + +class StringPool; +std::string ExtractBaseName(const char* path, bool include_extension = false); +void strReplace(std::string& str, const char* from, const char* to); + +// user context in which the file system gets opened. This also contains a few callbacks to avoid direct dependencies on the engine. +struct LumpFilterInfo +{ + std::vector gameTypeFilter; // this can contain multiple entries + + // The following are for checking if the root directory of a zip can be removed. + std::vector reservedFolders; + std::vector requiredPrefixes; + std::vector embeddings; + std::vector blockednames; // File names that will never be accepted (e.g. dehacked.exe for Doom) + std::function filenamecheck; // for scanning directories, this allows to eliminate unwanted content. + std::function postprocessFunc; +}; + +enum class FSMessageLevel +{ + Error = 1, + Warning = 2, + Attention = 3, + Message = 4, + DebugWarn = 5, + DebugNotify = 6, +}; + +// pass the text output function as parameter to avoid a hard dependency on higher level code. +using FileSystemMessageFunc = int(*)(FSMessageLevel msglevel, const char* format, ...); + + +class FResourceFile; + +// [RH] Namespaces from BOOM. +// These are needed here in the low level part so that WAD files can be properly set up. +typedef enum { + ns_hidden = -1, + + ns_global = 0, + ns_sprites, + ns_flats, + ns_colormaps, + ns_acslibrary, + ns_newtextures, + ns_bloodraw, // no longer used - kept for ZScript. + ns_bloodsfx, // no longer used - kept for ZScript. + ns_bloodmisc, // no longer used - kept for ZScript. + ns_strifevoices, + ns_hires, + ns_voxels, + + // These namespaces are only used to mark lumps in special subdirectories + // so that their contents doesn't interfere with the global namespace. + // searching for data in these namespaces works differently for lumps coming + // from Zips or other files. + ns_specialzipdirectory, + ns_sounds, + ns_patches, + ns_graphics, + ns_music, + + ns_firstskin, +} namespace_t; + +enum ELumpFlags +{ + RESFF_MAYBEFLAT = 1, // might be a flat inside a WAD outside F_START/END + RESFF_FULLPATH = 2, // contains a full path. This will trigger extended namespace checks when looking up short names. + RESFF_EMBEDDED = 4, // marks an embedded resource file for later processing. + RESFF_SHORTNAME = 8, // the stored name is a short extension-less name + RESFF_COMPRESSED = 16, // compressed or encrypted, i.e. cannot be read with the container file's reader. + RESFF_NEEDFILESTART = 32, // The real position is not known yet and needs to be calculated on access +}; + +enum EReaderType +{ + READER_SHARED = 0, // returns a view into the parent's reader. + READER_NEW = 1, // opens a new file handle + READER_CACHED = 2, // returns a MemoryArrayReader + READERFLAG_SEEKABLE = 1 // ensure the reader is seekable. +}; + +struct FResourceEntry +{ + size_t Length; + size_t CompressedSize; + const char* FileName; + size_t Position; + int ResourceID; + uint32_t CRC32; + uint16_t Flags; + uint16_t Method; + int16_t Namespace; +}; + +void SetMainThread(); + +class FResourceFile +{ +public: + FResourceFile(const char* filename, StringPool* sp); + FResourceFile(const char* filename, FileReader& r, StringPool* sp); + const char* NormalizeFileName(const char* fn, int fallbackcp = 0); + FResourceEntry* AllocateEntries(int count); + void GenerateHash(); + void PostProcessArchive(LumpFilterInfo* filter); +protected: + FileReader Reader; + const char* FileName; + FResourceEntry* Entries = nullptr; + uint32_t NumLumps; + char Hash[48]; + StringPool* stringpool; + + // for archives that can contain directories + virtual void SetEntryAddress(uint32_t entry) + { + Entries[entry].Flags &= ~RESFF_NEEDFILESTART; + } + bool IsFileInFolder(const char* const resPath); + void CheckEmbedded(uint32_t entry, LumpFilterInfo* lfi); + +private: + uint32_t FirstLump; + + int FilterLumps(const std::string& filtername, uint32_t max); + bool FindPrefixRange(const char* filter, uint32_t max, uint32_t &start, uint32_t &end); + void JunkLeftoverFilters(uint32_t max); + void FindCommonFolder(LumpFilterInfo* filter); + static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); + +public: + static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); + static FResourceFile *OpenResourceFile(const char *filename, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); + static FResourceFile *OpenDirectory(const char *filename, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); + virtual ~FResourceFile(); + // If this FResourceFile represents a directory, the Reader object is not usable so don't return it. + FileReader *GetContainerReader() { return Reader.isOpen()? &Reader : nullptr; } + const char* GetFileName() const { return FileName; } + uint32_t GetFirstEntry() const { return FirstLump; } + void SetFirstLump(uint32_t f) { FirstLump = f; } + const char* GetHash() const { return Hash; } + + int EntryCount() const { return NumLumps; } + int FindEntry(const char* name); + + size_t Length(uint32_t entry) + { + return (entry < NumLumps) ? Entries[entry].Length : 0; + } + size_t Offset(uint32_t entry) + { + return (entry < NumLumps) ? Entries[entry].Position : 0; + } + + // default is the safest reader type. + virtual FileReader GetEntryReader(uint32_t entry, int readertype = READER_NEW, int flags = READERFLAG_SEEKABLE); + + int GetEntryFlags(uint32_t entry) + { + return (entry < NumLumps) ? Entries[entry].Flags : 0; + } + + int GetEntryNamespace(uint32_t entry) + { + return (entry < NumLumps) ? Entries[entry].Namespace : (int)ns_hidden; + } + + int GetEntryResourceID(uint32_t entry) + { + return (entry < NumLumps) ? Entries[entry].ResourceID : -1; + } + + const char* getName(uint32_t entry) + { + return (entry < NumLumps) ? Entries[entry].FileName : nullptr; + } + + virtual FileData Read(uint32_t entry); + + virtual FCompressedBuffer GetRawData(uint32_t entry); + + FileReader Destroy() + { + auto fr = std::move(Reader); + delete this; + return fr; + } + + +}; + + +} + +#endif diff --git a/src/common/filesystem/include/w_zip.h b/src/common/filesystem/include/w_zip.h new file mode 100644 index 00000000000..50c39519f6c --- /dev/null +++ b/src/common/filesystem/include/w_zip.h @@ -0,0 +1,111 @@ +#ifndef __W_ZIP +#define __W_ZIP + +#if defined(__GNUC__) +#define FORCE_PACKED __attribute__((__packed__)) +#else +#define FORCE_PACKED +#endif + +#include + + +#pragma pack(1) +// FZipCentralInfo +struct FZipEndOfCentralDirectory +{ + uint32_t Magic; + uint16_t DiskNumber; + uint16_t FirstDisk; + uint16_t NumEntries; + uint16_t NumEntriesOnAllDisks; + uint32_t DirectorySize; + uint32_t DirectoryOffset; + uint16_t ZipCommentLength; +} FORCE_PACKED; + +struct FZipEndOfCentralDirectory64 +{ + uint32_t Magic; + uint64_t StructSize; + uint16_t VersionMadeBy; + uint16_t VersionNeeded; + uint32_t DiskNumber; + uint32_t FirstDisk; + uint64_t NumEntries; + uint64_t NumEntriesOnAllDisks; + uint64_t DirectorySize; + uint64_t DirectoryOffset; + uint16_t ZipCommentLength; +} FORCE_PACKED; + + +// FZipFileInfo +struct FZipCentralDirectoryInfo +{ + uint32_t Magic; + uint8_t VersionMadeBy[2]; + uint8_t VersionToExtract[2]; + uint16_t Flags; + uint16_t Method; + uint16_t ModTime; + uint16_t ModDate; + uint32_t CRC32; + uint32_t CompressedSize32; + uint32_t UncompressedSize32; + uint16_t NameLength; + uint16_t ExtraLength; + uint16_t CommentLength; + uint16_t StartingDiskNumber; + uint16_t InternalAttributes; + uint32_t ExternalAttributes; + uint32_t LocalHeaderOffset32; + // file name and other variable length info follows +} FORCE_PACKED; + +struct FZipCentralDirectoryInfo64BitExt +{ + uint16_t Type; + uint16_t Length; + uint64_t UncompressedSize; + uint64_t CompressedSize; + uint64_t LocalHeaderOffset; + uint32_t DiskNo; +} FORCE_PACKED; + +// FZipLocalHeader +struct FZipLocalFileHeader +{ + uint32_t Magic; + uint8_t VersionToExtract[2]; + uint16_t Flags; + uint16_t Method; + uint16_t ModTime; + uint16_t ModDate; + uint32_t CRC32; + uint32_t CompressedSize; + uint32_t UncompressedSize; + uint16_t NameLength; + uint16_t ExtraLength; + // file name and other variable length info follows +} FORCE_PACKED; + +#pragma pack() + +#ifndef MAKE_ID +#ifndef __BIG_ENDIAN__ +#define MAKE_ID(a,b,c,d) ((uint32_t)((a)|((b)<<8)|((c)<<16)|((d)<<24))) +#else +#define MAKE_ID(a,b,c,d) ((uint32_t)((d)|((c)<<8)|((b)<<16)|((a)<<24))) +#endif +#endif + + +#define ZIP_LOCALFILE MAKE_ID('P','K',3,4) +#define ZIP_CENTRALFILE MAKE_ID('P','K',1,2) +#define ZIP_ENDOFDIR MAKE_ID('P','K',5,6) + +// File header flags. +#define ZF_ENCRYPTED 0x1 + +#endif diff --git a/src/gamedata/resourcefiles/ancientzip.cpp b/src/common/filesystem/source/ancientzip.cpp similarity index 91% rename from src/gamedata/resourcefiles/ancientzip.cpp rename to src/common/filesystem/source/ancientzip.cpp index 0088d1f0084..9f5ebdfefe4 100644 --- a/src/gamedata/resourcefiles/ancientzip.cpp +++ b/src/common/filesystem/source/ancientzip.cpp @@ -44,8 +44,12 @@ #include +#include +#include #include "ancientzip.h" +namespace FileSys { + /**************************************************************** Bit-I/O variables and routines/macros @@ -123,7 +127,7 @@ static const unsigned char BitReverse4[] = { #define FIRST_BIT_LEN 8 #define REST_BIT_LEN 4 -void FZipExploder::InsertCode(TArray &decoder, unsigned int pos, int bits, unsigned short code, int len, unsigned char value) +void FZipExploder::InsertCode(std::vector &decoder, unsigned int pos, int bits, unsigned short code, int len, unsigned char value) { assert(len > 0); unsigned int node = pos + (code & ((1 << bits) - 1)); @@ -159,12 +163,12 @@ void FZipExploder::InsertCode(TArray &decoder, unsigned int pos, int b } } -unsigned int FZipExploder::InitTable(TArray &decoder, int numspots) +unsigned int FZipExploder::InitTable(std::vector &decoder, int numspots) { - unsigned int start = decoder.Size(); - decoder.Reserve(numspots); + size_t start = decoder.size(); + decoder.resize(decoder.size() + numspots); memset(&decoder[start], 0, sizeof(HuffNode)*numspots); - return start; + return (unsigned)start; } int FZipExploder::buildercmp(const void *a, const void *b) @@ -178,7 +182,7 @@ int FZipExploder::buildercmp(const void *a, const void *b) return d; } -int FZipExploder::BuildDecoder(TArray &decoder, TableBuilder *values, int numvals) +int FZipExploder::BuildDecoder(std::vector &decoder, TableBuilder *values, int numvals) { int i; @@ -216,7 +220,7 @@ int FZipExploder::BuildDecoder(TArray &decoder, TableBuilder *values, } -int FZipExploder::DecodeSFValue(const TArray &decoder) +int FZipExploder::DecodeSFValue(const std::vector &decoder) { unsigned int bits = FIRST_BIT_LEN, table = 0, code; const HuffNode *pos; @@ -234,7 +238,7 @@ int FZipExploder::DecodeSFValue(const TArray &decoder) } -int FZipExploder::DecodeSF(TArray &decoder, int numvals) +int FZipExploder::DecodeSF(std::vector &decoder, int numvals) { TableBuilder builder[256]; unsigned char a, c; @@ -310,7 +314,7 @@ int FZipExploder::Explode(unsigned char *out, unsigned int outsize, len += minMatchLen; dist++; if (bIdx + len > outsize) { - throw CExplosionError("Not enough output space"); + return -1; } if ((unsigned int)dist > bIdx) { /* Anything before the first input byte is zero. */ @@ -339,10 +343,19 @@ int FZipExploder::Explode(unsigned char *out, unsigned int outsize, int ShrinkLoop(unsigned char *out, unsigned int outsize, FileReader &_In, unsigned int InLeft) { + // don't allocate this on the stack, it's a bit on the large side. + struct work + { + unsigned char ReadBuf[256]; + unsigned short Parent[HSIZE]; + unsigned char Value[HSIZE], Stack[HSIZE]; + }; + auto s = std::make_unique(); + unsigned char* ReadBuf = s->ReadBuf; + unsigned short* Parent = s->Parent; + unsigned char* Value = s->Value, * Stack = s->Stack; + FileReader *In = &_In; - unsigned char ReadBuf[256]; - unsigned short Parent[HSIZE]; - unsigned char Value[HSIZE], Stack[HSIZE]; unsigned char *newstr; int len; int KwKwK, codesize = 9; /* start at 9 bits/code */ @@ -433,3 +446,5 @@ int ShrinkLoop(unsigned char *out, unsigned int outsize, FileReader &_In, unsign } return 0; } + +} diff --git a/src/common/filesystem/source/ancientzip.h b/src/common/filesystem/source/ancientzip.h new file mode 100644 index 00000000000..1f8d793fd54 --- /dev/null +++ b/src/common/filesystem/source/ancientzip.h @@ -0,0 +1,47 @@ +#pragma once +#include "fs_files.h" + +namespace FileSys { + +class FZipExploder +{ + unsigned int Hold, Bits; + FileReader *In; + unsigned int InLeft; + + /**************************************************************** + Shannon-Fano tree structures, variables and related routines + ****************************************************************/ + + struct HuffNode + { + unsigned char Value; + unsigned char Length; + unsigned short ChildTable; + }; + + struct TableBuilder + { + unsigned char Value; + unsigned char Length; + unsigned short Code; + }; + + std::vector LiteralDecoder; + std::vector DistanceDecoder; + std::vector LengthDecoder; + unsigned char ReadBuf[256]; + unsigned int bs, be; + + static int buildercmp(const void *a, const void *b); + void InsertCode(std::vector &decoder, unsigned int pos, int bits, unsigned short code, int len, unsigned char value); + unsigned int InitTable(std::vector &decoder, int numspots); + int BuildDecoder(std::vector &decoder, TableBuilder *values, int numvals); + int DecodeSFValue(const std::vector ¤tTree); + int DecodeSF(std::vector &decoder, int numvals); +public: + int Explode(unsigned char *out, unsigned int outsize, FileReader &in, unsigned int insize, int flags); +}; + +int ShrinkLoop(unsigned char *out, unsigned int outsize, FileReader &in, unsigned int insize); +} diff --git a/src/common/filesystem/source/critsec.cpp b/src/common/filesystem/source/critsec.cpp new file mode 100644 index 00000000000..b8b8c552207 --- /dev/null +++ b/src/common/filesystem/source/critsec.cpp @@ -0,0 +1,152 @@ +/* +** +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifdef _WIN32 + +#ifndef _WINNT_ +#define WIN32_LEAN_AND_MEAN +#include +#endif + +namespace FileSys { + +class FInternalCriticalSection +{ +public: + void Enter() + { + AcquireSRWLockExclusive(&CritSec); + } + void Leave() + { + ReleaseSRWLockExclusive(&CritSec); + } +private: + SRWLOCK CritSec = SRWLOCK_INIT; +}; + + +FInternalCriticalSection *CreateCriticalSection() +{ + return new FInternalCriticalSection(); +} + +void DeleteCriticalSection(FInternalCriticalSection *c) +{ + delete c; +} + +void EnterCriticalSection(FInternalCriticalSection *c) +{ + c->Enter(); +} + +void LeaveCriticalSection(FInternalCriticalSection *c) +{ + c->Leave(); +} + +#else + +#include "critsec.h" + +#include + +namespace FileSys { + +class FInternalCriticalSection +{ +public: + FInternalCriticalSection(); + ~FInternalCriticalSection(); + + void Enter(); + void Leave(); + +private: + pthread_mutex_t m_mutex; + +}; + +// TODO: add error handling + +FInternalCriticalSection::FInternalCriticalSection() +{ + pthread_mutexattr_t attributes; + pthread_mutexattr_init(&attributes); + pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_init(&m_mutex, &attributes); + + pthread_mutexattr_destroy(&attributes); +} + +FInternalCriticalSection::~FInternalCriticalSection() +{ + pthread_mutex_destroy(&m_mutex); +} + +void FInternalCriticalSection::Enter() +{ + pthread_mutex_lock(&m_mutex); +} + +void FInternalCriticalSection::Leave() +{ + pthread_mutex_unlock(&m_mutex); +} + + +FInternalCriticalSection *CreateCriticalSection() +{ + return new FInternalCriticalSection(); +} + +void DeleteCriticalSection(FInternalCriticalSection *c) +{ + delete c; +} + +void EnterCriticalSection(FInternalCriticalSection *c) +{ + c->Enter(); +} + +void LeaveCriticalSection(FInternalCriticalSection *c) +{ + c->Leave(); +} + +#endif + +} \ No newline at end of file diff --git a/src/common/filesystem/source/critsec.h b/src/common/filesystem/source/critsec.h new file mode 100644 index 00000000000..9ea56aab561 --- /dev/null +++ b/src/common/filesystem/source/critsec.h @@ -0,0 +1,39 @@ +#pragma once + +namespace FileSys { +// System independent critical sections without polluting the namespace with the operating system headers. +class FInternalCriticalSection; +FInternalCriticalSection *CreateCriticalSection(); +void DeleteCriticalSection(FInternalCriticalSection *c); +void EnterCriticalSection(FInternalCriticalSection *c); +void LeaveCriticalSection(FInternalCriticalSection *c); + +// This is just a convenience wrapper around the function interface adjusted to use std::lock_guard +class FCriticalSection +{ +public: + FCriticalSection() + { + c = CreateCriticalSection(); + } + + ~FCriticalSection() + { + DeleteCriticalSection(c); + } + + void lock() + { + EnterCriticalSection(c); + } + + void unlock() + { + LeaveCriticalSection(c); + } + +private: + FInternalCriticalSection *c; + +}; +} \ No newline at end of file diff --git a/src/common/filesystem/source/file_7z.cpp b/src/common/filesystem/source/file_7z.cpp new file mode 100644 index 00000000000..21d6049e37d --- /dev/null +++ b/src/common/filesystem/source/file_7z.cpp @@ -0,0 +1,375 @@ +/* +** file_7z.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2009 Randy Heit +** Copyright 2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +// Note that 7z made the unwise decision to include windows.h :( +#include "7z.h" +#include "7zCrc.h" +#include "resourcefile.h" +#include "fs_findfile.h" +#include "unicode.h" +#include "critsec.h" +#include + + +namespace FileSys { + +//----------------------------------------------------------------------- +// +// Interface classes to 7z library +// +//----------------------------------------------------------------------- + +extern ISzAlloc g_Alloc; + +struct CZDFileInStream +{ + ISeekInStream s; + FileReader &File; + + CZDFileInStream(FileReader &_file) + : File(_file) + { + s.Read = Read; + s.Seek = Seek; + } + + static SRes Read(const ISeekInStream *pp, void *buf, size_t *size) + { + CZDFileInStream *p = (CZDFileInStream *)pp; + auto numread = p->File.Read(buf, (ptrdiff_t)*size); + if (numread < 0) + { + *size = 0; + return SZ_ERROR_READ; + } + *size = numread; + return SZ_OK; + } + + static SRes Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin) + { + CZDFileInStream *p = (CZDFileInStream *)pp; + FileReader::ESeek move_method; + int res; + if (origin == SZ_SEEK_SET) + { + move_method = FileReader::SeekSet; + } + else if (origin == SZ_SEEK_CUR) + { + move_method = FileReader::SeekCur; + } + else if (origin == SZ_SEEK_END) + { + move_method = FileReader::SeekEnd; + } + else + { + return 1; + } + res = (int)p->File.Seek((ptrdiff_t)*pos, move_method); + *pos = p->File.Tell(); + return res; + } +}; + +struct C7zArchive +{ + CSzArEx DB; + CZDFileInStream ArchiveStream; + CLookToRead2 LookStream; + Byte StreamBuffer[1<<14]; + UInt32 BlockIndex; + Byte *OutBuffer; + size_t OutBufferSize; + + C7zArchive(FileReader &file) : ArchiveStream(file) + { + if (g_CrcTable[1] == 0) + { + CrcGenerateTable(); + } + file.Seek(0, FileReader::SeekSet); + LookToRead2_CreateVTable(&LookStream, false); + LookStream.realStream = &ArchiveStream.s; + LookToRead2_INIT(&LookStream); + LookStream.bufSize = sizeof(StreamBuffer); + LookStream.buf = StreamBuffer; + SzArEx_Init(&DB); + BlockIndex = 0xFFFFFFFF; + OutBuffer = NULL; + OutBufferSize = 0; + } + + ~C7zArchive() + { + if (OutBuffer != NULL) + { + IAlloc_Free(&g_Alloc, OutBuffer); + } + SzArEx_Free(&DB, &g_Alloc); + } + + SRes Open() + { + return SzArEx_Open(&DB, &LookStream.vt, &g_Alloc, &g_Alloc); + } + + SRes Extract(UInt32 file_index, char *buffer) + { + size_t offset, out_size_processed; + SRes res = SzArEx_Extract(&DB, &LookStream.vt, file_index, + &BlockIndex, &OutBuffer, &OutBufferSize, + &offset, &out_size_processed, + &g_Alloc, &g_Alloc); + if (res == SZ_OK) + { + memcpy(buffer, OutBuffer + offset, out_size_processed); + } + return res; + } +}; + +//========================================================================== +// +// 7-zip file +// +//========================================================================== + +class F7ZFile : public FResourceFile +{ + friend struct F7ZLump; + + C7zArchive *Archive; + FCriticalSection critsec; + +public: + F7ZFile(const char * filename, FileReader &filer, StringPool* sp); + bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); + virtual ~F7ZFile(); + FileData Read(uint32_t entry) override; + FileReader GetEntryReader(uint32_t entry, int, int) override; +}; + + + +//========================================================================== +// +// 7Z file +// +//========================================================================== + +F7ZFile::F7ZFile(const char * filename, FileReader &filer, StringPool* sp) + : FResourceFile(filename, filer, sp) +{ + Archive = nullptr; +} + + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool F7ZFile::Open(LumpFilterInfo *filter, FileSystemMessageFunc Printf) +{ + Archive = new C7zArchive(Reader); + int skipped = 0; + SRes res; + + res = Archive->Open(); + if (res != SZ_OK) + { + delete Archive; + Archive = NULL; + if (res == SZ_ERROR_UNSUPPORTED) + { + Printf(FSMessageLevel::Error, "%s: Decoder does not support this archive\n", FileName); + } + else if (res == SZ_ERROR_MEM) + { + Printf(FSMessageLevel::Error, "Cannot allocate memory\n"); + } + else if (res == SZ_ERROR_CRC) + { + Printf(FSMessageLevel::Error, "CRC error\n"); + } + else + { + Printf(FSMessageLevel::Error, "error #%d\n", res); + } + return false; + } + + CSzArEx* const archPtr = &Archive->DB; + + AllocateEntries(archPtr->NumFiles); + NumLumps = archPtr->NumFiles; + + std::u16string nameUTF16; + std::vector nameASCII; + + uint32_t j = 0; + for (uint32_t i = 0; i < NumLumps; ++i) + { + // skip Directories + if (SzArEx_IsDir(archPtr, i)) + { + continue; + } + + const size_t nameLength = SzArEx_GetFileNameUtf16(archPtr, i, NULL); + + if (0 == nameLength) + { + continue; + } + + nameUTF16.resize((unsigned)nameLength); + nameASCII.resize((unsigned)nameLength); + + SzArEx_GetFileNameUtf16(archPtr, i, (UInt16*)nameUTF16.data()); + utf16_to_utf8((uint16_t*)nameUTF16.data(), nameASCII); + + Entries[j].FileName = NormalizeFileName(nameASCII.data()); + Entries[j].Length = SzArEx_GetFileSize(archPtr, i); + Entries[j].Flags = RESFF_FULLPATH|RESFF_COMPRESSED; + Entries[j].ResourceID = -1; + Entries[j].Namespace = ns_global; + Entries[j].Method = METHOD_INVALID; + Entries[j].Position = i; + j++; + } + // Resize the lump record array to its actual size + NumLumps = j; + + if (NumLumps > 0) + { + // Quick check for unsupported compression method + + FileData temp(nullptr, Entries[0].Length); + + if (SZ_OK != Archive->Extract((UInt32)Entries[0].Position, (char*)temp.writable())) + { + Printf(FSMessageLevel::Error, "%s: unsupported 7z/LZMA file!\n", FileName); + return false; + } + } + + GenerateHash(); + PostProcessArchive(filter); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +F7ZFile::~F7ZFile() +{ + if (Archive != nullptr) + { + delete Archive; + } +} + +//========================================================================== +// +// Reads data for one entry into a buffer +// +//========================================================================== + +FileData F7ZFile::Read(uint32_t entry) +{ + FileData buffer; + if (entry < NumLumps && Entries[entry].Length > 0) + { + auto p = buffer.allocate(Entries[entry].Length); + // There is no realistic way to keep multiple references to a 7z file open without massive overhead so to make this thread-safe a mutex is the only option. + std::lock_guard lock(critsec); + SRes code = Archive->Extract((UInt32)Entries[entry].Position, (char*)p); + if (code != SZ_OK) buffer.clear(); + } + return buffer; +} + +//========================================================================== +// +// This can only return a FileReader to a memory buffer. +// +//========================================================================== + +FileReader F7ZFile::GetEntryReader(uint32_t entry, int, int) +{ + FileReader fr; + if (entry < 0 || entry >= NumLumps) return fr; + auto buffer = Read(entry); + if (buffer.size() > 0) + fr.OpenMemoryArray(buffer); + return fr; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[k7zSignatureSize]; + + if (file.GetLength() >= k7zSignatureSize) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, k7zSignatureSize); + file.Seek(0, FileReader::SeekSet); + if (!memcmp(head, k7zSignature, k7zSignatureSize)) + { + auto rf = new F7ZFile(filename, file, sp); + if (rf->Open(filter, Printf)) return rf; + + file = rf->Destroy(); + } + } + return NULL; +} + + +} diff --git a/src/common/filesystem/source/file_directory.cpp b/src/common/filesystem/source/file_directory.cpp new file mode 100644 index 00000000000..ca87fd9ea00 --- /dev/null +++ b/src/common/filesystem/source/file_directory.cpp @@ -0,0 +1,204 @@ +/* +** file_directory.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2008-2009 Randy Heit +** Copyright 2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + + +#include + +#include "resourcefile.h" +#include "fs_findfile.h" +#include "fs_stringpool.h" + +namespace FileSys { + +std::string FS_FullPath(const char* directory); + +//========================================================================== +// +// Zip file +// +//========================================================================== + +class FDirectory : public FResourceFile +{ + const bool nosubdir; + const char* mBasePath; + const char** SystemFilePath; + + + int AddDirectory(const char* dirpath, LumpFilterInfo* filter, FileSystemMessageFunc Printf); + +public: + FDirectory(const char * dirname, StringPool* sp, bool nosubdirflag = false); + bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); + FileReader GetEntryReader(uint32_t entry, int, int) override; +}; + + + +//========================================================================== +// +// +// +//========================================================================== + +FDirectory::FDirectory(const char * directory, StringPool* sp, bool nosubdirflag) + : FResourceFile("", sp), nosubdir(nosubdirflag) +{ + auto fn = FS_FullPath(directory); + if (fn.back() != '/') fn += '/'; + FileName = stringpool->Strdup(fn.c_str()); +} + +//========================================================================== +// +// Windows version +// +//========================================================================== + +int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSystemMessageFunc Printf) +{ + int count = 0; + + FileList list; + if (!ScanDirectory(list, dirpath, "*")) + { + Printf(FSMessageLevel::Error, "Could not scan '%s': %s\n", dirpath, strerror(errno)); + } + else + { + mBasePath = nullptr; + AllocateEntries((int)list.size()); + SystemFilePath = (const char**)stringpool->Alloc(list.size() * sizeof(const char*)); + for(auto& entry : list) + { + if (mBasePath == nullptr) + { + // extract the base path from the first entry to cover changes made in ScanDirectory. + auto full = entry.FilePath.rfind(entry.FilePathRel); + std::string path(entry.FilePath, 0, full); + mBasePath = stringpool->Strdup(path.c_str()); + } + if (!entry.isDirectory) + { + auto fi = entry.FileName; + for (auto& c : fi) c = tolower(c); + if (strstr(fi.c_str(), ".orig") || strstr(fi.c_str(), ".bak") || strstr(fi.c_str(), ".cache")) + { + // We shouldn't add backup files to the file system + continue; + } + + + if (filter == nullptr || filter->filenamecheck == nullptr || filter->filenamecheck(fi.c_str(), entry.FilePath.c_str())) + { + if (entry.Length > 0x7fffffff) + { + Printf(FSMessageLevel::Warning, "%s is larger than 2GB and will be ignored\n", entry.FilePath.c_str()); + continue; + } + // for accessing the file we need to retain the original unaltered path. + // On Linux this is important because its file system is case sensitive, + // but even on Windows the Unicode normalization is destructive + // for some characters and cannot be used for file names. + // Examples for this are the Turkish 'i's or the German ß. + SystemFilePath[count] = stringpool->Strdup(entry.FilePathRel.c_str()); + // for internal access we use the normalized form of the relative path. + // this is fine because the paths that get compared against this will also be normalized. + Entries[count].FileName = NormalizeFileName(entry.FilePathRel.c_str()); + Entries[count].CompressedSize = Entries[count].Length = entry.Length; + Entries[count].Flags = RESFF_FULLPATH; + Entries[count].ResourceID = -1; + Entries[count].Method = METHOD_STORED; + Entries[count].Namespace = ns_global; + Entries[count].Position = count; + count++; + } + } + } + } + return count; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FDirectory::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf) +{ + NumLumps = AddDirectory(FileName, filter, Printf); + PostProcessArchive(filter); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FileReader FDirectory::GetEntryReader(uint32_t entry, int readertype, int) +{ + FileReader fr; + if (entry < NumLumps) + { + std::string fn = mBasePath; + fn += SystemFilePath[Entries[entry].Position]; + fr.OpenFile(fn.c_str()); + if (readertype == READER_CACHED) + { + auto data = fr.Read(); + fr.OpenMemoryArray(data); + } + } + return fr; +} + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckDir(const char *filename, bool nosubdirflag, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + auto rf = new FDirectory(filename, sp, nosubdirflag); + if (rf->Open(filter, Printf)) return rf; + delete rf; + return nullptr; +} + +} diff --git a/src/common/filesystem/source/file_grp.cpp b/src/common/filesystem/source/file_grp.cpp new file mode 100644 index 00000000000..57206b4b102 --- /dev/null +++ b/src/common/filesystem/source/file_grp.cpp @@ -0,0 +1,131 @@ +/* +** file_grp.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "fs_swap.h" + +namespace FileSys { + using namespace byteswap; + +//========================================================================== +// +// +// +//========================================================================== + +struct GrpHeader +{ + uint32_t Magic[3]; + uint32_t NumLumps; +}; + +struct GrpLump +{ + union + { + struct + { + char Name[12]; + uint32_t Size; + }; + char NameWithZero[13]; + }; +}; + + +//========================================================================== +// +// Open it +// +//========================================================================== + +static bool OpenGrp(FResourceFile* file, LumpFilterInfo* filter) +{ + GrpHeader header; + + auto Reader = file->GetContainerReader(); + Reader->Read(&header, sizeof(header)); + uint32_t NumLumps = LittleLong(header.NumLumps); + auto Entries = file->AllocateEntries(NumLumps); + + GrpLump *fileinfo = new GrpLump[NumLumps]; + Reader->Read (fileinfo, NumLumps * sizeof(GrpLump)); + + int Position = sizeof(GrpHeader) + NumLumps * sizeof(GrpLump); + + for(uint32_t i = 0; i < NumLumps; i++) + { + Entries[i].Position = Position; + Entries[i].CompressedSize = Entries[i].Length = LittleLong(fileinfo[i].Size); + Position += fileinfo[i].Size; + Entries[i].Flags = 0; + Entries[i].Namespace = ns_global; + fileinfo[i].NameWithZero[12] = '\0'; // Be sure filename is null-terminated + Entries[i].ResourceID = -1; + Entries[i].Method = METHOD_STORED; + Entries[i].FileName = file->NormalizeFileName(fileinfo[i].Name); + } + file->GenerateHash(); + delete[] fileinfo; + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[12]; + + if (file.GetLength() >= 12) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 12); + file.Seek(0, FileReader::SeekSet); + if (!memcmp(head, "KenSilverman", 12)) + { + auto rf = new FResourceFile(filename, file, sp); + if (OpenGrp(rf, filter)) return rf; + file = rf->Destroy(); + } + } + return nullptr; +} + +} diff --git a/src/common/filesystem/source/file_hog.cpp b/src/common/filesystem/source/file_hog.cpp new file mode 100644 index 00000000000..d12f7e2d86e --- /dev/null +++ b/src/common/filesystem/source/file_hog.cpp @@ -0,0 +1,109 @@ +/* +** file_hog.cpp +** +** reads Descent .hog files +** +**--------------------------------------------------------------------------- +** Copyright 2023 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + + +#include "resourcefile.h" +#include "fs_swap.h" + +namespace FileSys { + using namespace byteswap; + + + + +static bool OpenHog(FResourceFile* rf, LumpFilterInfo* filter) +{ + auto Reader = rf->GetContainerReader(); + FileReader::Size length = Reader->GetLength(); + + std::vector entries; + // Hogs store their data as a list of file records, each containing a name, length and the actual data. + // To read the directory the entire file must be scanned. + while (Reader->Tell() <= length) + { + char name[13]; + + auto r = Reader->Read(&name, 13); + if (r < 13) break; + name[12] = 0; + uint32_t elength = Reader->ReadUInt32(); + + FResourceEntry Entry; + Entry.Position = Reader->Tell(); + Entry.CompressedSize = Entry.Length = elength; + Entry.Flags = 0; + Entry.CRC32 = 0; + Entry.Namespace = ns_global; + Entry.ResourceID = -1; + Entry.Method = METHOD_STORED; + Entry.FileName = rf->NormalizeFileName(name); + entries.push_back(Entry); + Reader->Seek(elength, FileReader::SeekCur); + } + auto Entries = rf->AllocateEntries((int)entries.size()); + memcpy(Entries, entries.data(), entries.size() * sizeof(Entries[0])); + rf->GenerateHash(); + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile* CheckHog(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[3]; + + if (file.GetLength() >= 20) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 3); + if (!memcmp(head, "DHF", 3)) + { + auto rf = new FResourceFile(filename, file, sp); + if (OpenHog(rf, filter)) return rf; + file = rf->Destroy(); + } + file.Seek(0, FileReader::SeekSet); + } + return nullptr; +} + + +} \ No newline at end of file diff --git a/src/common/filesystem/source/file_lump.cpp b/src/common/filesystem/source/file_lump.cpp new file mode 100644 index 00000000000..b01d46b5d36 --- /dev/null +++ b/src/common/filesystem/source/file_lump.cpp @@ -0,0 +1,72 @@ +/* +** file_lump.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" + +namespace FileSys { +//========================================================================== +// +// Open it +// +//========================================================================== + +static bool OpenLump(FResourceFile* file, LumpFilterInfo*) +{ + auto Entries = file->AllocateEntries(1); + Entries[0].FileName = file->NormalizeFileName(ExtractBaseName(file->GetFileName(), true).c_str()); + Entries[0].Namespace = ns_global; + Entries[0].ResourceID = -1; + Entries[0].Position = 0; + Entries[0].CompressedSize = Entries[0].Length = file->GetContainerReader()->GetLength(); + Entries[0].Method = METHOD_STORED; + Entries[0].Flags = 0; + return true; +} + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckLump(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + // always succeeds + auto rf = new FResourceFile(filename, file, sp); + if (OpenLump(rf, filter)) return rf; + file = rf->Destroy(); + return NULL; +} + +} diff --git a/src/common/filesystem/source/file_mvl.cpp b/src/common/filesystem/source/file_mvl.cpp new file mode 100644 index 00000000000..f08db316187 --- /dev/null +++ b/src/common/filesystem/source/file_mvl.cpp @@ -0,0 +1,98 @@ +/* +** file_mvl.cpp +** +** reads Descent2 .mvl files +** +**--------------------------------------------------------------------------- +** Copyright 2023 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + + +#include "resourcefile.h" +#include "fs_swap.h" + +namespace FileSys { + using namespace byteswap; + + + +static bool OpenMvl(FResourceFile* rf, LumpFilterInfo* filter) +{ + auto Reader = rf->GetContainerReader(); + auto count = Reader->ReadUInt32(); + auto Entries = rf->AllocateEntries(count); + size_t pos = 8 + (17 * count); // files start after the directory + + for (uint32_t i = 0; i < count; i++) + { + char name[13]; + Reader->Read(&name, 13); + name[12] = 0; + uint32_t elength = Reader->ReadUInt32(); + + Entries[i].Position = pos; + Entries[i].CompressedSize = Entries[i].Length = elength; + Entries[i].ResourceID = -1; + Entries[i].FileName = rf->NormalizeFileName(name); + + pos += elength; + } + + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile* CheckMvl(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[4]; + + if (file.GetLength() >= 20) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 4); + if (!memcmp(head, "DMVL", 4)) + { + auto rf = new FResourceFile(filename, file, sp); + if (OpenMvl(rf, filter)) return rf; + file = rf->Destroy(); + } + file.Seek(0, FileReader::SeekSet); + } + return nullptr; +} + + +} \ No newline at end of file diff --git a/src/common/filesystem/source/file_pak.cpp b/src/common/filesystem/source/file_pak.cpp new file mode 100644 index 00000000000..b66a0f3d99f --- /dev/null +++ b/src/common/filesystem/source/file_pak.cpp @@ -0,0 +1,121 @@ +/* +** file_pak.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" + +namespace FileSys { + + using namespace byteswap; +//========================================================================== +// +// +// +//========================================================================== + +struct dpackfile_t +{ + char name[56]; + uint32_t filepos, filelen; +} ; + +struct dpackheader_t +{ + uint32_t ident; // == IDPAKHEADER + uint32_t dirofs; + uint32_t dirlen; +} ; + + +//========================================================================== +// +// Open it +// +//========================================================================== + +static bool OpenPak(FResourceFile* file, LumpFilterInfo* filter) +{ + dpackheader_t header; + + auto Reader = file->GetContainerReader(); + Reader->Read(&header, sizeof(header)); + uint32_t NumLumps = header.dirlen / sizeof(dpackfile_t); + auto Entries = file->AllocateEntries(NumLumps); + header.dirofs = LittleLong(header.dirofs); + + Reader->Seek (header.dirofs, FileReader::SeekSet); + auto fd = Reader->Read (NumLumps * sizeof(dpackfile_t)); + auto fileinfo = (const dpackfile_t*)fd.data(); + + for(uint32_t i = 0; i < NumLumps; i++) + { + Entries[i].Position = LittleLong(fileinfo[i].filepos); + Entries[i].CompressedSize = Entries[i].Length = LittleLong(fileinfo[i].filelen); + Entries[i].Flags = RESFF_FULLPATH; + Entries[i].Namespace = ns_global; + Entries[i].ResourceID = -1; + Entries[i].Method = METHOD_STORED; + Entries[i].FileName = file->NormalizeFileName(fileinfo[i].name); + } + file->GenerateHash(); + file->PostProcessArchive(filter); + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[4]; + + if (file.GetLength() >= 12) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 4); + file.Seek(0, FileReader::SeekSet); + if (!memcmp(head, "PACK", 4)) + { + auto rf = new FResourceFile(filename, file, sp); + if (OpenPak(rf, filter)) return rf; + file = rf->Destroy(); + } + } + return NULL; +} + +} diff --git a/src/common/filesystem/source/file_rff.cpp b/src/common/filesystem/source/file_rff.cpp new file mode 100644 index 00000000000..673a08ce060 --- /dev/null +++ b/src/common/filesystem/source/file_rff.cpp @@ -0,0 +1,173 @@ +/* +** file_rff.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include "resourcefile.h" +#include "fs_swap.h" + +namespace FileSys { + using namespace byteswap; + +//========================================================================== +// +// +// +//========================================================================== + +struct RFFInfo +{ + // Should be "RFF\x18" + uint32_t Magic; + uint32_t Version; + uint32_t DirOfs; + uint32_t NumLumps; +}; + +struct RFFLump +{ + uint32_t DontKnow1[4]; + uint32_t FilePos; + uint32_t Size; + uint32_t DontKnow2; + uint32_t Time; + uint8_t Flags; + char Extension[3]; + char Name[8]; + uint32_t IndexNum; // Used by .sfx, possibly others +}; + +//========================================================================== +// +// BloodCrypt +// +//========================================================================== + +void BloodCrypt (void *data, int key, int len) +{ + int p = (uint8_t)key, i; + + for (i = 0; i < len; ++i) + { + ((uint8_t *)data)[i] ^= (unsigned char)(p+(i>>1)); + } +} + + +//========================================================================== +// +// Initializes a Blood RFF file +// +//========================================================================== + +static bool OpenRFF(FResourceFile* file, LumpFilterInfo*) +{ + RFFLump *lumps; + RFFInfo header; + + auto Reader = file->GetContainerReader(); + Reader->Read(&header, sizeof(header)); + + uint32_t NumLumps = LittleLong(header.NumLumps); + auto Entries = file->AllocateEntries(NumLumps); + header.DirOfs = LittleLong(header.DirOfs); + lumps = new RFFLump[header.NumLumps]; + Reader->Seek (LittleLong(header.DirOfs), FileReader::SeekSet); + Reader->Read (lumps, NumLumps * sizeof(RFFLump)); + BloodCrypt (lumps, LittleLong(header.DirOfs), NumLumps * sizeof(RFFLump)); + + for (uint32_t i = 0; i < NumLumps; ++i) + { + Entries[i].Position = LittleLong(lumps[i].FilePos); + Entries[i].CompressedSize = Entries[i].Length = LittleLong(lumps[i].Size); + Entries[i].Flags = 0; + Entries[i].Method = METHOD_STORED; + if (lumps[i].Flags & 0x10) + { + Entries[i].Flags = RESFF_COMPRESSED; // for purposes of decoding, compression and encryption are equivalent. + Entries[i].Method = METHOD_RFFCRYPT; + } + else + { + Entries[i].Flags = 0; + Entries[i].Method = METHOD_STORED; + } + Entries[i].Namespace = ns_global; + Entries[i].ResourceID = LittleLong(lumps[i].IndexNum); + + // Rearrange the name and extension to construct the fullname. + char name[13]; + strncpy(name, lumps[i].Name, 8); + name[8] = 0; + size_t len = strlen(name); + assert(len + 4 <= 12); + name[len+0] = '.'; + name[len+1] = lumps[i].Extension[0]; + name[len+2] = lumps[i].Extension[1]; + name[len+3] = lumps[i].Extension[2]; + name[len+4] = 0; + Entries[i].FileName = file->NormalizeFileName(name); + } + delete[] lumps; + file->GenerateHash(); + return true; +} + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[4]; + + if (file.GetLength() >= 16) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 4); + file.Seek(0, FileReader::SeekSet); + if (!memcmp(head, "RFF\x1a", 4)) + { + auto rf = new FResourceFile(filename, file, sp); + if (OpenRFF(rf, filter)) return rf; + file = rf->Destroy(); + } + } + return NULL; +} + + +} diff --git a/src/common/filesystem/source/file_ssi.cpp b/src/common/filesystem/source/file_ssi.cpp new file mode 100644 index 00000000000..82885c6bb7c --- /dev/null +++ b/src/common/filesystem/source/file_ssi.cpp @@ -0,0 +1,140 @@ +/* +** file_grp.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" + +namespace FileSys { + +//========================================================================== +// +// Open it +// Note that SSIs can contain embedded GRPs which must be flagged accordingly. +// +//========================================================================== + +static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilterInfo*) +{ + uint32_t NumLumps = EntryCount * 2; + auto Entries = file->AllocateEntries(NumLumps); + auto Reader = file->GetContainerReader(); + + + int32_t j = (version == 2 ? 267 : 254) + (EntryCount * 121); + for (uint32_t i = 0; i < NumLumps; i+=2) + { + char fn[13]; + int strlength = Reader->ReadUInt8(); + if (strlength > 12) strlength = 12; + + Reader->Read(fn, 12); + fn[strlength] = 0; + int flength = Reader->ReadInt32(); + + Entries[i].Position = j; + Entries[i].CompressedSize = Entries[i].Length = flength; + Entries[i].Flags = 0; + Entries[i].Namespace = ns_global; + Entries[i].Method = METHOD_STORED; + Entries[i].ResourceID = -1; + Entries[i].FileName = file->NormalizeFileName(fn); + if (strstr(fn, ".GRP")) Entries[i].Flags |= RESFF_EMBEDDED; + + // SSI files can swap the order of the extension's characters - but there's no reliable detection for this and it can be mixed inside the same container, + // so we have no choice but to create another file record for the altered name. + std::swap(fn[strlength - 1], fn[strlength - 3]); + + Entries[i + 1].Position = j; + Entries[i + 1].CompressedSize = Entries[i + 1].Length = flength; + Entries[i + 1].Flags = 0; + Entries[i + 1].Namespace = ns_global; + Entries[i + 1].ResourceID = -1; + Entries[i + 1].FileName = file->NormalizeFileName(fn); + Entries[i + 1].Method = METHOD_STORED; + if (strstr(fn, ".GRP")) Entries[i + 1].Flags |= RESFF_EMBEDDED; + + j += flength; + + Reader->Seek(104, FileReader::SeekCur); + file->GenerateHash(); + } + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char zerobuf[72]; + char buf[72]; + memset(zerobuf, 0, 72); + + auto skipstring = [&](size_t length) + { + size_t strlength = file.ReadUInt8(); + if (strlength > length) return false; + size_t count = file.Read(buf, length); + buf[length] = 0; + if (count != length || strlen(buf) != strlength) return false; + if (length != strlength && memcmp(buf + strlength, zerobuf, length - strlength)) return false; + return true; + }; + if (file.GetLength() >= 12) + { + // check if SSI + // this performs several checks because there is no "SSI" magic + int version = file.ReadInt32(); + if (version == 1 || version == 2) // if + { + int numfiles = file.ReadInt32(); + if (!skipstring(32)) return nullptr; + if (version == 2 && !skipstring(12)) return nullptr; + for (int i = 0; i < 3; i++) + { + if (!skipstring(70)) return nullptr; + } + auto ssi = new FResourceFile(filename, file, sp); + if (OpenSSI(ssi, version, numfiles, filter)) return ssi; + file = ssi->Destroy(); + } + } + return nullptr; +} + +} diff --git a/src/common/filesystem/source/file_wad.cpp b/src/common/filesystem/source/file_wad.cpp new file mode 100644 index 00000000000..4f8574b73d7 --- /dev/null +++ b/src/common/filesystem/source/file_wad.cpp @@ -0,0 +1,427 @@ +/* +** file_wad.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include "resourcefile.h" +#include "fs_filesystem.h" +#include "fs_swap.h" +#include "fs_stringpool.h" +#include "resourcefile.h" + +namespace FileSys { + using namespace byteswap; + +struct wadinfo_t +{ + // Should be "IWAD" or "PWAD". + uint32_t Magic; + uint32_t NumLumps; + uint32_t InfoTableOfs; +}; + +struct wadlump_t +{ + uint32_t FilePos; + uint32_t Size; + char Name[8]; +}; + +//========================================================================== +// +// Wad file +// +//========================================================================== + +class FWadFile : public FResourceFile +{ + bool IsMarker(int lump, const char *marker); + void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, FileSystemMessageFunc Printf, bool flathack=false); + void SkinHack (FileSystemMessageFunc Printf); + +public: + FWadFile(const char * filename, FileReader &file, StringPool* sp); + bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); +}; + + +//========================================================================== +// +// FWadFile::FWadFile +// +// Initializes a WAD file +// +//========================================================================== + +FWadFile::FWadFile(const char *filename, FileReader &file, StringPool* sp) + : FResourceFile(filename, file, sp) +{ +} + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf) +{ + wadinfo_t header; + uint32_t InfoTableOfs; + bool isBigEndian = false; // Little endian is assumed until proven otherwise + auto wadSize = Reader.GetLength(); + + Reader.Read(&header, sizeof(header)); + NumLumps = LittleLong(header.NumLumps); + InfoTableOfs = LittleLong(header.InfoTableOfs); + + // Check to see if the little endian interpretation is valid + // This should be sufficient to detect big endian wads. + if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) + { + NumLumps = BigLong(header.NumLumps); + InfoTableOfs = BigLong(header.InfoTableOfs); + isBigEndian = true; + + // Check again to detect broken wads + if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) + { + Printf(FSMessageLevel::Error, "%s: Bad directory offset.\n", FileName); + return false; + } + } + + Reader.Seek(InfoTableOfs, FileReader::SeekSet); + auto fd = Reader.Read(NumLumps * sizeof(wadlump_t)); + auto fileinfo = (const wadlump_t*)fd.data(); + + AllocateEntries(NumLumps); + + for(uint32_t i = 0; i < NumLumps; i++) + { + // WAD only supports ASCII. It is also the only format which can use valid backslashes in its names. + char n[9]; + int ishigh = 0; + for (int j = 0; j < 8; j++) + { + if (fileinfo[i].Name[j] & 0x80) ishigh |= 1 << j; + n[j] = tolower(fileinfo[i].Name[j]); + } + n[8] = 0; + if (ishigh == 1) n[0] &= 0x7f; + else if (ishigh > 1) + { + // This may not end up printing something proper because we do not know what encoding might have been used. + Printf(FSMessageLevel::Warning, "%s: Lump name %.8s contains invalid characters\n", FileName, fileinfo[i].Name); + } + + Entries[i].FileName = nullptr; + Entries[i].Position = isBigEndian ? BigLong(fileinfo[i].FilePos) : LittleLong(fileinfo[i].FilePos); + Entries[i].CompressedSize = Entries[i].Length = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size); + + Entries[i].Namespace = ns_global; + Entries[i].Flags = ishigh? RESFF_SHORTNAME | RESFF_COMPRESSED : RESFF_SHORTNAME; + Entries[i].Method = ishigh == 1? METHOD_LZSS : METHOD_STORED; + Entries[i].FileName = stringpool->Strdup(n); + // This doesn't set up the namespace yet. + } + for (uint32_t i = 0; i < NumLumps; i++) + { + if (Entries[i].Method == METHOD_LZSS) + { + // compressed size is implicit. + Entries[i].CompressedSize = (i == NumLumps - 1 ? Reader.GetLength() : Entries[i + 1].Position) - Entries[i].Position; + } + } + + + GenerateHash(); // Do this before the lump processing below. + + SetNamespace("s_start", "s_end", ns_sprites, Printf); + SetNamespace("f_start", "f_end", ns_flats, Printf, true); + SetNamespace("c_start", "c_end", ns_colormaps, Printf); + SetNamespace("a_start", "a_end", ns_acslibrary, Printf); + SetNamespace("tx_start", "tx_end", ns_newtextures, Printf); + SetNamespace("v_start", "v_end", ns_strifevoices, Printf); + SetNamespace("hi_start", "hi_end", ns_hires, Printf); + SetNamespace("vx_start", "vx_end", ns_voxels, Printf); + SkinHack(Printf); + + return true; +} + +//========================================================================== +// +// IsMarker +// +// (from BOOM) +// +//========================================================================== + +inline bool FWadFile::IsMarker(int lump, const char *marker) +{ + if (Entries[lump].FileName[0] == marker[0]) + { + return (!strcmp(Entries[lump].FileName, marker) || + (marker[1] == '_' && !strcmp(Entries[lump].FileName +1, marker))); + } + else return false; +} + +//========================================================================== +// +// SetNameSpace +// +// Sets namespace information for the lumps. It always looks for the first +// x_START and the last x_END lump, except when loading flats. In this case +// F_START may be absent and if that is the case all lumps with a size of +// 4096 will be flagged appropriately. +// +//========================================================================== + +// This class was supposed to be local in the function but GCC +// does not like that. +struct Marker +{ + int markertype; + unsigned int index; +}; + +void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, FileSystemMessageFunc Printf, bool flathack) +{ + bool warned = false; + int numstartmarkers = 0, numendmarkers = 0; + unsigned int i; + std::vector markers; + + for(i = 0; i < NumLumps; i++) + { + if (IsMarker(i, startmarker)) + { + Marker m = { 0, i }; + markers.push_back(m); + numstartmarkers++; + } + else if (IsMarker(i, endmarker)) + { + Marker m = { 1, i }; + markers.push_back(m); + numendmarkers++; + } + } + + if (numstartmarkers == 0) + { + if (numendmarkers == 0) return; // no markers found + + Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker); + + + if (flathack) + { + // We have found no F_START but one or more F_END markers. + // mark all lumps before the last F_END marker as potential flats. + unsigned int end = markers[markers.size()-1].index; + for(unsigned int ii = 0; ii < end; ii++) + { + if (Entries[ii].Length == 4096) + { + // We can't add this to the flats namespace but + // it needs to be flagged for the texture manager. + Printf(FSMessageLevel::DebugNotify, "%s: Marking %s as potential flat\n", FileName, Entries[ii].FileName); + Entries[ii].Flags |= RESFF_MAYBEFLAT; + } + } + } + return; + } + + i = 0; + while (i < markers.size()) + { + int start, end; + if (markers[i].markertype != 0) + { + Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker); + i++; + continue; + } + start = i++; + + // skip over subsequent x_START markers + while (i < markers.size() && markers[i].markertype == 0) + { + Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, startmarker); + i++; + continue; + } + // same for x_END markers + while (i < markers.size()-1 && (markers[i].markertype == 1 && markers[i+1].markertype == 1)) + { + Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, endmarker); + i++; + continue; + } + // We found a starting marker but no end marker. Ignore this block. + if (i >= markers.size()) + { + Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, startmarker, endmarker); + end = NumLumps; + } + else + { + end = markers[i++].index; + } + + // we found a marked block + Printf(FSMessageLevel::DebugNotify, "%s: Found %s block at (%d-%d)\n", FileName, startmarker, markers[start].index, end); + for(int j = markers[start].index + 1; j < end; j++) + { + if (Entries[j].Namespace != ns_global) + { + if (!warned) + { + Printf(FSMessageLevel::Warning, "%s: Overlapping namespaces found (lump %d)\n", FileName, j); + } + warned = true; + } + else if (space == ns_sprites && Entries[j].Length < 8) + { + // sf 26/10/99: + // ignore sprite lumps smaller than 8 bytes (the smallest possible) + // in size -- this was used by some dmadds wads + // as an 'empty' graphics resource + Printf(FSMessageLevel::DebugWarn, "%s: Skipped empty sprite %s (lump %d)\n", FileName, Entries[j].FileName, j); + } + else + { + Entries[j].Namespace = space; + } + } + } +} + + +//========================================================================== +// +// W_SkinHack +// +// Tests a wad file to see if it contains an S_SKIN marker. If it does, +// every lump in the wad is moved into a new namespace. Because skins are +// only supposed to replace player sprites, sounds, or faces, this should +// not be a problem. Yes, there are skins that replace more than that, but +// they are such a pain, and breaking them like this was done on purpose. +// This also renames any S_SKINxx lumps to just S_SKIN. +// +//========================================================================== + +void FWadFile::SkinHack (FileSystemMessageFunc Printf) +{ + // this being static is not a problem. The only relevant thing is that each skin gets a different number. + static int namespc = ns_firstskin; + bool skinned = false; + bool hasmap = false; + uint32_t i; + + for (i = 0; i < NumLumps; i++) + { + auto lump = &Entries[i]; + + if (!strnicmp(lump->FileName, "S_SKIN", 6)) + { // Wad has at least one skin. + lump->FileName = "S_SKIN"; + if (!skinned) + { + skinned = true; + uint32_t j; + + for (j = 0; j < NumLumps; j++) + { + Entries[j].Namespace = namespc; + } + namespc++; + } + } + // needless to say, this check is entirely useless these days as map names can be more diverse.. + if ((lump->FileName[0] == 'M' && + lump->FileName[1] == 'A' && + lump->FileName[2] == 'P' && + lump->FileName[3] >= '0' && lump->FileName[3] <= '9' && + lump->FileName[4] >= '0' && lump->FileName[4] <= '9' && + lump->FileName[5] == '\0') + || + (lump->FileName[0] == 'E' && + lump->FileName[1] >= '0' && lump->FileName[1] <= '9' && + lump->FileName[2] == 'M' && + lump->FileName[3] >= '0' && lump->FileName[3] <= '9' && + lump->FileName[4] == '\0')) + { + hasmap = true; + } + } + if (skinned && hasmap) + { + Printf(FSMessageLevel::Attention, "%s: The maps will not be loaded because it has a skin.\n", FileName); + Printf(FSMessageLevel::Attention, "You should remove the skin from the wad to play these maps.\n"); + } +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[4]; + + if (file.GetLength() >= 12) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 4); + file.Seek(0, FileReader::SeekSet); + if (!memcmp(head, "IWAD", 4) || !memcmp(head, "PWAD", 4)) + { + auto rf = new FWadFile(filename, file, sp); + if (rf->Open(filter, Printf)) return rf; + + file = rf->Destroy(); + } + } + return NULL; +} + +} diff --git a/src/common/filesystem/source/file_whres.cpp b/src/common/filesystem/source/file_whres.cpp new file mode 100644 index 00000000000..d1d2d1a508b --- /dev/null +++ b/src/common/filesystem/source/file_whres.cpp @@ -0,0 +1,129 @@ +/* +** file_whres.cpp +** +** reads a Witchaven/TekWar sound resource file +** +**--------------------------------------------------------------------------- +** Copyright 2009-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "fs_stringpool.h" +#include "fs_swap.h" + +namespace FileSys { + using namespace byteswap; + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool OpenWHRes(FResourceFile* file, LumpFilterInfo*) +{ + uint32_t directory[1024]; + + auto BaseName = ExtractBaseName(file->GetFileName()); + auto Reader = file->GetContainerReader(); + Reader->Seek(-4096, FileReader::SeekEnd); + Reader->Read(directory, 4096); + + int nl =1024/3; + + int k; + for (k = 0; k < nl; k++) + { + uint32_t offset = LittleLong(directory[k * 3]) * 4096; + uint32_t length = LittleLong(directory[k * 3 + 1]); + if (length == 0) + { + break; + } + } + auto Entries = file->AllocateEntries(k); + auto NumLumps = k; + + int i = 0; + for(k = 0; k < NumLumps; k++) + { + uint32_t offset = LittleLong(directory[k*3]) * 4096; + uint32_t length = LittleLong(directory[k*3+1]); + char num[6]; + snprintf(num, 6, "/%04d", k); + std::string synthname = BaseName + num; + + Entries[i].Position = offset; + Entries[i].CompressedSize = Entries[i].Length = length; + Entries[i].Flags = RESFF_FULLPATH; + Entries[i].Namespace = ns_global; + Entries[i].ResourceID = -1; + Entries[i].Method = METHOD_STORED; + Entries[i].FileName = file->NormalizeFileName(synthname.c_str()); + i++; + } + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckWHRes(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + if (file.GetLength() >= 8192) // needs to be at least 8192 to contain one file and the directory. + { + unsigned directory[1024]; + int nl =1024/3; + + file.Seek(-4096, FileReader::SeekEnd); + file.Read(directory, 4096); + auto size = file.GetLength(); + + uint32_t checkpos = 0; + for(int k = 0; k < nl; k++) + { + unsigned offset = LittleLong(directory[k*3]); + unsigned length = LittleLong(directory[k*3+1]); + if (length <= 0 && offset == 0) break; + if (offset != checkpos || length == 0 || offset + length >= (size_t)size - 4096 ) return nullptr; + checkpos += (length+4095) / 4096; + } + auto rf = new FResourceFile(filename, file, sp); + if (OpenWHRes(rf, filter)) return rf; + file = rf->Destroy(); + } + return NULL; +} + +} \ No newline at end of file diff --git a/src/common/filesystem/source/file_zip.cpp b/src/common/filesystem/source/file_zip.cpp new file mode 100644 index 00000000000..8351b714648 --- /dev/null +++ b/src/common/filesystem/source/file_zip.cpp @@ -0,0 +1,399 @@ +/* +** file_zip.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2023 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include +#include +#include "w_zip.h" +#include "ancientzip.h" +#include "resourcefile.h" +#include "fs_findfile.h" +#include "fs_swap.h" +#include "fs_stringpool.h" + +namespace FileSys { + using namespace byteswap; + +#define BUFREADCOMMENT (0x400) + +//----------------------------------------------------------------------- +// +// Finds the central directory end record in the end of the file. +// Taken from Quake3 source but the file in question is not GPL'ed. ;) +// +//----------------------------------------------------------------------- + +static uint32_t Zip_FindCentralDir(FileReader &fin, bool* zip64) +{ + unsigned char buf[BUFREADCOMMENT + 4]; + uint32_t FileSize; + uint32_t uBackRead; + uint32_t uMaxBack; // maximum size of global comment + uint32_t uPosFound=0; + + FileSize = (uint32_t)fin.GetLength(); + uMaxBack = std::min(0xffff, FileSize); + + uBackRead = 4; + while (uBackRead < uMaxBack) + { + uint32_t uReadSize, uReadPos; + int i; + if (uBackRead + BUFREADCOMMENT > uMaxBack) + uBackRead = uMaxBack; + else + uBackRead += BUFREADCOMMENT; + uReadPos = FileSize - uBackRead; + + uReadSize = std::min((BUFREADCOMMENT + 4), (FileSize - uReadPos)); + + if (fin.Seek(uReadPos, FileReader::SeekSet) != 0) break; + + if (fin.Read(buf, (int32_t)uReadSize) != (int32_t)uReadSize) break; + + for (i = (int)uReadSize - 3; (i--) > 0;) + { + if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 5 && buf[i+3] == 6 && !*zip64 && uPosFound == 0) + { + *zip64 = false; + uPosFound = uReadPos + i; + } + if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 6 && buf[i+3] == 6) + { + *zip64 = true; + uPosFound = uReadPos + i; + return uPosFound; + } + } + } + return uPosFound; +} + +//========================================================================== +// +// Zip file +// +//========================================================================== + +class FZipFile : public FResourceFile +{ + void SetEntryAddress(uint32_t entry) override; + +public: + FZipFile(const char* filename, FileReader& file, StringPool* sp); + bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); + FCompressedBuffer GetRawData(uint32_t entry) override; +}; + +//========================================================================== +// +// Zip file +// +//========================================================================== + +FZipFile::FZipFile(const char * filename, FileReader &file, StringPool* sp) +: FResourceFile(filename, file, sp) +{ +} + +bool FZipFile::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf) +{ + bool zip64 = false; + uint32_t centraldir = Zip_FindCentralDir(Reader, &zip64); + int skipped = 0; + + if (centraldir == 0) + { + Printf(FSMessageLevel::Error, "%s: ZIP file corrupt!\n", FileName); + return false; + } + + uint64_t dirsize, DirectoryOffset; + if (!zip64) + { + FZipEndOfCentralDirectory info; + // Read the central directory info. + Reader.Seek(centraldir, FileReader::SeekSet); + Reader.Read(&info, sizeof(FZipEndOfCentralDirectory)); + + // No multi-disk zips! + if (info.NumEntries != info.NumEntriesOnAllDisks || + info.FirstDisk != 0 || info.DiskNumber != 0) + { + Printf(FSMessageLevel::Error, "%s: Multipart Zip files are not supported.\n", FileName); + return false; + } + + NumLumps = LittleShort(info.NumEntries); + dirsize = LittleLong(info.DirectorySize); + DirectoryOffset = LittleLong(info.DirectoryOffset); + } + else + { + FZipEndOfCentralDirectory64 info; + // Read the central directory info. + Reader.Seek(centraldir, FileReader::SeekSet); + Reader.Read(&info, sizeof(FZipEndOfCentralDirectory64)); + + // No multi-disk zips! + if (info.NumEntries != info.NumEntriesOnAllDisks || + info.FirstDisk != 0 || info.DiskNumber != 0) + { + Printf(FSMessageLevel::Error, "%s: Multipart Zip files are not supported.\n", FileName); + return false; + } + + NumLumps = (uint32_t)info.NumEntries; + dirsize = info.DirectorySize; + DirectoryOffset = info.DirectoryOffset; + } + // Load the entire central directory. Too bad that this contains variable length entries... + void *directory = malloc(dirsize); + Reader.Seek(DirectoryOffset, FileReader::SeekSet); + Reader.Read(directory, dirsize); + + char *dirptr = (char*)directory; + + std::string name0, name1; + bool foundspeciallump = false; + bool foundprefix = false; + + // Check if all files have the same prefix so that this can be stripped out. + // This will only be done if there is either a MAPINFO, ZMAPINFO or GAMEINFO lump in the subdirectory, denoting a ZDoom mod. + if (NumLumps > 1) for (uint32_t i = 0; i < NumLumps; i++) + { + FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; + + int len = LittleShort(zip_fh->NameLength); + std::string name(dirptr + sizeof(FZipCentralDirectoryInfo), len); + + dirptr += sizeof(FZipCentralDirectoryInfo) + + LittleShort(zip_fh->NameLength) + + LittleShort(zip_fh->ExtraLength) + + LittleShort(zip_fh->CommentLength); + + if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. + { + free(directory); + Printf(FSMessageLevel::Error, "%s: Central directory corrupted.", FileName); + return false; + } + } + + dirptr = (char*)directory; + AllocateEntries(NumLumps); + auto Entry = Entries; + for (uint32_t i = 0; i < NumLumps; i++) + { + FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; + + int len = LittleShort(zip_fh->NameLength); + std::string name(dirptr + sizeof(FZipCentralDirectoryInfo), len); + dirptr += sizeof(FZipCentralDirectoryInfo) + + LittleShort(zip_fh->NameLength) + + LittleShort(zip_fh->ExtraLength) + + LittleShort(zip_fh->CommentLength); + + if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. + { + free(directory); + Printf(FSMessageLevel::Error, "%s: Central directory corrupted.", FileName); + return false; + } + + // skip Directories + if (name.empty() || (name.back() == '/' && LittleLong(zip_fh->UncompressedSize32) == 0)) + { + skipped++; + continue; + } + + // Ignore unknown compression formats + zip_fh->Method = LittleShort(zip_fh->Method); + if (zip_fh->Method != METHOD_STORED && + zip_fh->Method != METHOD_DEFLATE && + zip_fh->Method != METHOD_LZMA && + zip_fh->Method != METHOD_BZIP2 && + zip_fh->Method != METHOD_IMPLODE && + zip_fh->Method != METHOD_SHRINK && + zip_fh->Method != METHOD_XZ) + { + Printf(FSMessageLevel::Error, "%s: '%s' uses an unsupported compression algorithm (#%d).\n", FileName, name.c_str(), zip_fh->Method); + skipped++; + continue; + } + // Also ignore encrypted entries + zip_fh->Flags = LittleShort(zip_fh->Flags); + if (zip_fh->Flags & ZF_ENCRYPTED) + { + Printf(FSMessageLevel::Error, "%s: '%s' is encrypted. Encryption is not supported.\n", FileName, name.c_str()); + skipped++; + continue; + } + + uint32_t UncompressedSize =LittleLong(zip_fh->UncompressedSize32); + uint32_t CompressedSize = LittleLong(zip_fh->CompressedSize32); + uint64_t LocalHeaderOffset = LittleLong(zip_fh->LocalHeaderOffset32); + if (zip_fh->ExtraLength > 0) + { + uint8_t* rawext = (uint8_t*)zip_fh + sizeof(*zip_fh) + zip_fh->NameLength; + uint32_t ExtraLength = LittleLong(zip_fh->ExtraLength); + + while (ExtraLength > 0) + { + auto zip_64 = (FZipCentralDirectoryInfo64BitExt*)rawext; + uint32_t BlockLength = LittleLong(zip_64->Length); + rawext += BlockLength + 4; + ExtraLength -= BlockLength + 4; + if (LittleLong(zip_64->Type) == 1 && BlockLength >= 0x18) + { + if (zip_64->CompressedSize > 0x7fffffff || zip_64->UncompressedSize > 0x7fffffff) + { + // The file system is limited to 32 bit file sizes; + Printf(FSMessageLevel::Warning, "%s: '%s' is too large.\n", FileName, name.c_str()); + skipped++; + continue; + } + UncompressedSize = (uint32_t)zip_64->UncompressedSize; + CompressedSize = (uint32_t)zip_64->CompressedSize; + LocalHeaderOffset = zip_64->LocalHeaderOffset; + } + } + } + + Entry->FileName = NormalizeFileName(name.c_str()); + Entry->Length = UncompressedSize; + // The start of the Reader will be determined the first time it is accessed. + Entry->Flags = RESFF_FULLPATH | RESFF_NEEDFILESTART; + Entry->Method = uint8_t(zip_fh->Method); + if (Entry->Method != METHOD_STORED) Entry->Flags |= RESFF_COMPRESSED; + if (Entry->Method == METHOD_IMPLODE) + { + // for Implode merge the flags into the compression method to make handling in the file system easier and save one variable. + if ((zip_fh->Flags & 6) == 2) Entry->Method = METHOD_IMPLODE_2; + else if ((zip_fh->Flags & 6) == 4) Entry->Method = METHOD_IMPLODE_4; + else if ((zip_fh->Flags & 6) == 6) Entry->Method = METHOD_IMPLODE_6; + else Entry->Method = METHOD_IMPLODE_0; + } + Entry->CRC32 = zip_fh->CRC32; + Entry->CompressedSize = CompressedSize; + Entry->Position = LocalHeaderOffset; + + Entry++; + + } + // Resize the lump record array to its actual size + NumLumps -= skipped; + free(directory); + + GenerateHash(); + PostProcessArchive(filter); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FCompressedBuffer FZipFile::GetRawData(uint32_t entry) +{ + FCompressedBuffer cbuf; + + if (entry >= NumLumps || Entries[entry].Length == 0) + { + cbuf = { 0, 0, METHOD_STORED, 0, 0, nullptr }; + } + else + { + auto& e = Entries[entry]; + cbuf = { e.Length, e.CompressedSize, e.Method, e.CRC32, new char[e.CompressedSize] }; + if (e.Flags & RESFF_NEEDFILESTART) SetEntryAddress(entry); + Reader.Seek(e.Position, FileReader::SeekSet); + Reader.Read(cbuf.mBuffer, e.CompressedSize); + } + + return cbuf; +} + +//========================================================================== +// +// SetLumpAddress +// +//========================================================================== + +void FZipFile::SetEntryAddress(uint32_t entry) +{ + // This file is inside a zip and has not been opened before. + // Position points to the start of the local file header, which we must + // read and skip so that we can get to the actual file data. + FZipLocalFileHeader localHeader; + int skiplen; + + Reader.Seek(Entries[entry].Position, FileReader::SeekSet); + Reader.Read(&localHeader, sizeof(localHeader)); + skiplen = LittleShort(localHeader.NameLength) + LittleShort(localHeader.ExtraLength); + Entries[entry].Position += sizeof(localHeader) + skiplen; + Entries[entry].Flags &= ~RESFF_NEEDFILESTART; +} + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[4]; + + if (file.GetLength() >= (ptrdiff_t)sizeof(FZipLocalFileHeader)) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 4); + file.Seek(0, FileReader::SeekSet); + if (!memcmp(head, "PK\x3\x4", 4)) + { + auto rf = new FZipFile(filename, file, sp); + if (rf->Open(filter, Printf)) return rf; + file = rf->Destroy(); + } + } + return NULL; +} + + +} diff --git a/src/common/filesystem/source/files.cpp b/src/common/filesystem/source/files.cpp new file mode 100644 index 00000000000..ac058111981 --- /dev/null +++ b/src/common/filesystem/source/files.cpp @@ -0,0 +1,514 @@ +/* +** files.cpp +** Implements classes for reading from files or memory blocks +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** Copyright 2005-2008 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include +#include +#include "files_internal.h" + +namespace FileSys { + +#ifdef _WIN32 +std::wstring toWide(const char* str); +#endif + +FILE *myfopen(const char *filename, const char *flags) +{ +#ifndef _WIN32 + return fopen(filename, flags); +#else + auto widename = toWide(filename); + auto wideflags = toWide(flags); + return _wfopen(widename.c_str(), wideflags.c_str()); +#endif +} + +#ifdef _WIN32 +#define fseek _fseeki64 +#define ftell _ftelli64 +#endif + +//========================================================================== +// +// StdFileReader +// +// reads data from an stdio FILE* or part of it. +// +//========================================================================== + +class StdFileReader : public FileReaderInterface +{ + FILE *File = nullptr; + ptrdiff_t StartPos = 0; + ptrdiff_t FilePos = 0; + +public: + StdFileReader() + {} + + ~StdFileReader() + { + if (File != nullptr) + { + fclose(File); + } + File = nullptr; + } + + bool Open(const char *filename, ptrdiff_t startpos = 0, ptrdiff_t len = -1) + { + File = myfopen(filename, "rb"); + if (File == nullptr) return false; + FilePos = startpos; + StartPos = startpos; + Length = CalcFileLen(); + if (len >= 0 && len < Length) Length = len; + if (startpos > 0) Seek(0, SEEK_SET); + return true; + } + + ptrdiff_t Tell() const override + { + return FilePos - StartPos; + } + + ptrdiff_t Seek(ptrdiff_t offset, int origin) override + { + if (origin == SEEK_SET) + { + offset += StartPos; + } + else if (origin == SEEK_CUR) + { + offset += FilePos; + } + else if (origin == SEEK_END) + { + offset += StartPos + Length; + } + if (offset < StartPos || offset > StartPos + Length) return -1; // out of scope + + if (0 == fseek(File, offset, SEEK_SET)) + { + FilePos = offset; + return 0; + } + return -1; + } + + ptrdiff_t Read(void *buffer, ptrdiff_t len) override + { + assert(len >= 0); + if (len <= 0) return 0; + if (FilePos + len > StartPos + Length) + { + len = Length - FilePos + StartPos; + } + len = fread(buffer, 1, len, File); + FilePos += len; + return len; + } + + char *Gets(char *strbuf, ptrdiff_t len) override + { + if (len <= 0 || len > 0x7fffffff || FilePos >= StartPos + Length) return nullptr; + char *p = fgets(strbuf, (int)len, File); + if (p != nullptr) + { + ptrdiff_t old = FilePos; + FilePos = ftell(File); + if (FilePos - StartPos > Length) + { + strbuf[Length - old + StartPos] = 0; + } + } + return p; + } + +private: + ptrdiff_t CalcFileLen() const + { + ptrdiff_t endpos; + + fseek(File, 0, SEEK_END); + endpos = ftell(File); + fseek(File, 0, SEEK_SET); + return endpos; + } +}; + +//========================================================================== +// +// FileReaderRedirect +// +// like the above, but uses another File reader as its backing data +// +//========================================================================== + +class FileReaderRedirect : public FileReaderInterface +{ + FileReader *mReader = nullptr; + ptrdiff_t StartPos = 0; + ptrdiff_t FilePos = 0; + +public: + FileReaderRedirect(FileReader &parent, ptrdiff_t start, ptrdiff_t length) + { + mReader = &parent; + FilePos = start; + StartPos = start; + Length = length; + Seek(0, SEEK_SET); + } + + virtual ptrdiff_t Tell() const override + { + return FilePos - StartPos; + } + + virtual ptrdiff_t Seek(ptrdiff_t offset, int origin) override + { + switch (origin) + { + case SEEK_SET: + offset += StartPos; + break; + + case SEEK_END: + offset += StartPos + Length; + break; + + case SEEK_CUR: + offset += mReader->Tell(); + break; + } + if (offset < StartPos || offset > StartPos + Length) return -1; // out of scope + if (mReader->Seek(offset, FileReader::SeekSet) == 0) + { + FilePos = offset; + return 0; + } + return -1; + } + + virtual ptrdiff_t Read(void *buffer, ptrdiff_t len) override + { + assert(len >= 0); + if (len <= 0) return 0; + if (FilePos + len > StartPos + Length) + { + len = Length - FilePos + StartPos; + } + len = mReader->Read(buffer, len); + FilePos += len; + return len; + } + + virtual char *Gets(char *strbuf, ptrdiff_t len) override + { + if (len <= 0 || FilePos >= StartPos + Length) return nullptr; + char *p = mReader->Gets(strbuf, len); + if (p != nullptr) + { + ptrdiff_t old = FilePos; + FilePos = mReader->Tell(); + if (FilePos - StartPos > Length) + { + strbuf[Length - old + StartPos] = 0; + } + } + return p; + } + +}; + +//========================================================================== +// +// MemoryReader +// +// reads data from a block of memory +// +//========================================================================== + +ptrdiff_t MemoryReader::Tell() const +{ + return FilePos; +} + +ptrdiff_t MemoryReader::Seek(ptrdiff_t offset, int origin) +{ + switch (origin) + { + case SEEK_CUR: + offset += FilePos; + break; + + case SEEK_END: + offset += Length; + break; + + } + if (offset < 0 || offset > Length) return -1; + FilePos = std::clamp(offset, 0, Length); + return 0; +} + +ptrdiff_t MemoryReader::Read(void *buffer, ptrdiff_t len) +{ + if (len > Length - FilePos) len = Length - FilePos; + if (len<0) len = 0; + memcpy(buffer, bufptr + FilePos, len); + FilePos += len; + return len; +} + +char *MemoryReader::Gets(char *strbuf, ptrdiff_t len) +{ + if (len>Length - FilePos) len = Length - FilePos; + if (len <= 0) return nullptr; + + char *p = strbuf; + while (len > 1) + { + if (bufptr[FilePos] == 0) + { + FilePos++; + break; + } + if (bufptr[FilePos] != '\r') + { + *p++ = bufptr[FilePos]; + len--; + if (bufptr[FilePos] == '\n') + { + FilePos++; + break; + } + } + FilePos++; + } + if (p == strbuf) return nullptr; + *p++ = 0; + return strbuf; +} + +int BufferingReader::FillBuffer(ptrdiff_t newpos) +{ + if (newpos > Length) newpos = Length; + if (newpos <= bufferpos) return 0; + auto read = baseReader->Read(&buf.writable()[bufferpos], newpos - bufferpos); + bufferpos += read; + if (bufferpos == Length) + { + // we have read the entire file, so delete our data provider. + baseReader.reset(); + } + return newpos == bufferpos ? 0 : -1; +} + +ptrdiff_t BufferingReader::Seek(ptrdiff_t offset, int origin) +{ + if (-1 == MemoryReader::Seek(offset, origin)) return -1; + return FillBuffer(FilePos); +} + +ptrdiff_t BufferingReader::Read(void* buffer, ptrdiff_t len) +{ + if (FillBuffer(FilePos + len) < 0) return 0; + return MemoryReader::Read(buffer, len); +} + +char* BufferingReader::Gets(char* strbuf, ptrdiff_t len) +{ + if (FillBuffer(FilePos + len) < 0) return nullptr; + return MemoryReader::Gets(strbuf, len); +} + +//========================================================================== +// +// FileReader +// +// this wraps the different reader types in an object with value semantics. +// +//========================================================================== + +bool FileReader::OpenFile(const char *filename, FileReader::Size start, FileReader::Size length, bool buffered) +{ + auto reader = new StdFileReader; + if (!reader->Open(filename, start, length)) + { + delete reader; + return false; + } + Close(); + if (buffered) mReader = new BufferingReader(reader); + else mReader = reader; + return true; +} + +bool FileReader::OpenFilePart(FileReader &parent, FileReader::Size start, FileReader::Size length) +{ + auto reader = new FileReaderRedirect(parent, start, length); + Close(); + mReader = reader; + return true; +} + +bool FileReader::OpenMemory(const void *mem, FileReader::Size length) +{ + Close(); + mReader = new MemoryReader((const char *)mem, length); + return true; +} + +bool FileReader::OpenMemoryArray(FileData& data) +{ + Close(); + if (data.size() > 0) mReader = new MemoryArrayReader(data); + return true; +} + +FileData FileReader::Read(size_t len) +{ + FileData buffer; + if (len > 0) + { + Size length = mReader->Read(buffer.allocate(len), len); + if ((size_t)length < len) buffer.allocate(length); + } + return buffer; +} + +FileData FileReader::ReadPadded(size_t padding) +{ + auto len = GetLength(); + FileData buffer; + + if (len > 0) + { + auto p = (char*)buffer.allocate(len + padding); + Size length = mReader->Read(p, len); + if (length < len) buffer.clear(); + else memset(p + len, 0, padding); + } + return buffer; +} + + + +//========================================================================== +// +// FileWriter (the motivation here is to have a buffer writing subclass) +// +//========================================================================== + +bool FileWriter::OpenDirect(const char *filename) +{ + File = myfopen(filename, "wb"); + return (File != nullptr); +} + +FileWriter *FileWriter::Open(const char *filename) +{ + FileWriter *fwrit = new FileWriter(); + if (fwrit->OpenDirect(filename)) + { + return fwrit; + } + delete fwrit; + return nullptr; +} + +size_t FileWriter::Write(const void *buffer, size_t len) +{ + if (File != nullptr) + { + return fwrite(buffer, 1, len, File); + } + else + { + return 0; + } +} + +ptrdiff_t FileWriter::Tell() +{ + if (File != nullptr) + { + return ftell(File); + } + else + { + return 0; + } +} + +ptrdiff_t FileWriter::Seek(ptrdiff_t offset, int mode) +{ + if (File != nullptr) + { + return fseek(File, offset, mode); + } + else + { + return 0; + } +} + +size_t FileWriter::Printf(const char *fmt, ...) +{ + char c[300]; + va_list arglist; + va_start(arglist, fmt); + auto n = vsnprintf(c, 300, fmt, arglist); + std::string buf; + buf.resize(n + 1); + va_start(arglist, fmt); + vsnprintf(&buf.front(), n + 1, fmt, arglist); + va_end(arglist); + return Write(buf.c_str(), strlen(buf.c_str())); // Make sure we write no nullptr bytes. +} + +size_t BufferWriter::Write(const void *buffer, size_t len) +{ + size_t ofs = mBuffer.size(); + mBuffer.resize(ofs + len); + memcpy(&mBuffer[ofs], buffer, len); + return len; +} + +} diff --git a/src/common/filesystem/source/files_decompress.cpp b/src/common/filesystem/source/files_decompress.cpp new file mode 100644 index 00000000000..3f7dfb86598 --- /dev/null +++ b/src/common/filesystem/source/files_decompress.cpp @@ -0,0 +1,1026 @@ +/* +** files.cpp +** Implements classes for reading from files or memory blocks +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** Copyright 2005-2008 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// Caution: LzmaDec also pulls in windows.h! +#define NOMINMAX +#include "LzmaDec.h" +#include "Xz.h" +// CRC table needs to be generated prior to reading XZ compressed files. +#include "7zCrc.h" +#include +#include +#include +#include + +#include "fs_files.h" +#include "files_internal.h" +#include "ancientzip.h" +#include "fs_decompress.h" + +namespace FileSys { + using namespace byteswap; + + +class DecompressorBase : public FileReaderInterface +{ + bool exceptions = false; + +public: + // These do not work but need to be defined to satisfy the FileReaderInterface. + // They will just error out when called. + ptrdiff_t Tell() const override; + ptrdiff_t Seek(ptrdiff_t offset, int origin) override; + char* Gets(char* strbuf, ptrdiff_t len) override; + void DecompressionError(const char* error, ...) const; + void SetOwnsReader(); + void EnableExceptions(bool on) { exceptions = on; } + +protected: + DecompressorBase() + { + //seekable = false; + } + FileReader* File = nullptr; + FileReader OwnedFile; +}; + + +//========================================================================== +// +// DecompressionError +// +// Allows catching errors from the decompressor. The default is just to +// return failure from the calling function. +// +//========================================================================== + +void DecompressorBase::DecompressionError(const char *error, ...) const +{ + if (exceptions) + { + va_list argptr; + va_start(argptr, error); + throw FileSystemException(error, argptr); + va_end(argptr); + } +} + +ptrdiff_t DecompressorBase::Tell () const +{ + DecompressionError("Cannot get position of decompressor stream"); + return 0; +} +ptrdiff_t DecompressorBase::Seek (ptrdiff_t offset, int origin) +{ + DecompressionError("Cannot seek in decompressor stream"); + return 0; +} +char *DecompressorBase::Gets(char *strbuf, ptrdiff_t len) +{ + DecompressionError("Cannot use Gets on decompressor stream"); + return nullptr; +} + +void DecompressorBase::SetOwnsReader() +{ + OwnedFile = std::move(*File); + File = &OwnedFile; +} + +//========================================================================== +// +// +// +//========================================================================== + +static const char* ZLibError(int zerr) +{ + static const char* const errs[6] = { "Errno", "Stream Error", "Data Error", "Memory Error", "Buffer Error", "Version Error" }; + if (zerr >= 0 || zerr < -6) return "Unknown"; + else return errs[-zerr - 1]; +} + +//========================================================================== +// +// DecompressorZ +// +// The zlib wrapper +// reads data from a ZLib compressed stream +// +//========================================================================== + +class DecompressorZ : public DecompressorBase +{ + enum { BUFF_SIZE = 4096 }; + + bool SawEOF = false; + z_stream Stream; + uint8_t InBuff[BUFF_SIZE]; + +public: + bool Open (FileReader *file, bool zip) + { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + + int err; + + File = file; + FillBuffer (); + + Stream.zalloc = Z_NULL; + Stream.zfree = Z_NULL; + + if (!zip) err = inflateInit (&Stream); + else err = inflateInit2 (&Stream, -MAX_WBITS); + + if (err < Z_OK) + { + DecompressionError ("DecompressorZ: inflateInit failed: %s\n", ZLibError(err)); + return false; + } + return true; + } + + ~DecompressorZ () + { + inflateEnd (&Stream); + } + + ptrdiff_t Read (void *buffer, ptrdiff_t olen) override + { + int err = 0; + + if (File == nullptr) + { + DecompressionError("File not open"); + return 0; + } + auto len = olen; + if (len == 0) return 0; + + while (len > 0) + { + Stream.next_out = (Bytef*)buffer; + unsigned rlen = (unsigned)std::min(len, 0x40000000); + Stream.avail_out = rlen; + buffer = Stream.next_out + rlen; + len -= rlen; + + do + { + err = inflate(&Stream, Z_SYNC_FLUSH); + if (Stream.avail_in == 0 && !SawEOF) + { + FillBuffer(); + } + } while (err == Z_OK && Stream.avail_out != 0); + } + + if (err != Z_OK && err != Z_STREAM_END) + { + DecompressionError ("Corrupt zlib stream"); + return 0; + } + + if (Stream.avail_out != 0) + { + DecompressionError ("Ran out of data in zlib stream"); + return 0; + } + + return olen - Stream.avail_out; + } + + void FillBuffer () + { + auto numread = File->Read (InBuff, BUFF_SIZE); + + if (numread < BUFF_SIZE) + { + SawEOF = true; + } + Stream.next_in = InBuff; + Stream.avail_in = (uInt)numread; + } +}; + + +//========================================================================== +// +// DecompressorZ +// +// The bzip2 wrapper +// reads data from a libbzip2 compressed stream +// +//========================================================================== + +class DecompressorBZ2; +static DecompressorBZ2 * stupidGlobal; // Why does that dumb global error callback not pass the decompressor state? + // Thanks to that brain-dead interface we have to use a global variable to get the error to the proper handler. + +class DecompressorBZ2 : public DecompressorBase +{ + enum { BUFF_SIZE = 4096 }; + + bool SawEOF = false; + bz_stream Stream; + uint8_t InBuff[BUFF_SIZE]; + +public: + bool Open(FileReader *file) + { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + + int err; + + File = file; + stupidGlobal = this; + FillBuffer (); + + Stream.bzalloc = NULL; + Stream.bzfree = NULL; + Stream.opaque = NULL; + + err = BZ2_bzDecompressInit(&Stream, 0, 0); + + if (err != BZ_OK) + { + DecompressionError ("DecompressorBZ2: bzDecompressInit failed: %d\n", err); + return false; + } + return true; + } + + ~DecompressorBZ2 () + { + stupidGlobal = this; + BZ2_bzDecompressEnd (&Stream); + } + + ptrdiff_t Read (void *buffer, ptrdiff_t len) override + { + if (File == nullptr) + { + DecompressionError("File not open"); + return 0; + } + if (len == 0) return 0; + + int err = BZ_OK; + + stupidGlobal = this; + + while (len > 0) + { + Stream.next_out = (char*)buffer; + unsigned rlen = (unsigned)std::min(len, 0x40000000); + Stream.avail_out = rlen; + buffer = Stream.next_out + rlen; + len -= rlen; + + do + { + err = BZ2_bzDecompress(&Stream); + if (Stream.avail_in == 0 && !SawEOF) + { + FillBuffer(); + } + } while (err == BZ_OK && Stream.avail_out != 0); + } + + if (err != BZ_OK && err != BZ_STREAM_END) + { + DecompressionError ("Corrupt bzip2 stream"); + return 0; + } + + if (Stream.avail_out != 0) + { + DecompressionError ("Ran out of data in bzip2 stream"); + return 0; + } + + return len - Stream.avail_out; + } + + void FillBuffer () + { + auto numread = File->Read(InBuff, BUFF_SIZE); + + if (numread < BUFF_SIZE) + { + SawEOF = true; + } + Stream.next_in = (char *)InBuff; + Stream.avail_in = (unsigned)numread; + } + +}; + +//========================================================================== +// +// bz_internal_error +// +// libbzip2 wants this, since we build it with BZ_NO_STDIO set. +// +//========================================================================== + +extern "C" void bz_internal_error (int errcode) +{ + if (stupidGlobal) stupidGlobal->DecompressionError("libbzip2: internal error number %d\n", errcode); + else std::terminate(); +} + +//========================================================================== +// +// DecompressorLZMA +// +// The lzma wrapper +// reads data from a LZMA compressed stream +// +//========================================================================== + +static void *SzAlloc(ISzAllocPtr, size_t size) { return malloc(size); } +static void SzFree(ISzAllocPtr, void *address) { free(address); } +ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +// Wraps around a Decompressor to decompress a lzma stream +class DecompressorLZMA : public DecompressorBase +{ + enum { BUFF_SIZE = 4096 }; + + bool SawEOF = false; + CLzmaDec Stream; + size_t Size; + size_t InPos, InSize; + size_t OutProcessed; + uint8_t InBuff[BUFF_SIZE]; + +public: + + bool Open(FileReader *file, size_t uncompressed_size) + { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + + uint8_t header[4 + LZMA_PROPS_SIZE]; + int err; + File = file; + + Size = uncompressed_size; + OutProcessed = 0; + + // Read zip LZMA properties header + if (File->Read(header, sizeof(header)) < (ptrdiff_t)sizeof(header)) + { + DecompressionError("DecompressorLZMA: File too short\n"); + return false; + } + if (header[2] + header[3] * 256 != LZMA_PROPS_SIZE) + { + DecompressionError("DecompressorLZMA: LZMA props size is %d (expected %d)\n", + header[2] + header[3] * 256, LZMA_PROPS_SIZE); + return false; + } + + FillBuffer(); + + LzmaDec_Construct(&Stream); + err = LzmaDec_Allocate(&Stream, header + 4, LZMA_PROPS_SIZE, &g_Alloc); + + if (err != SZ_OK) + { + DecompressionError("DecompressorLZMA: LzmaDec_Allocate failed: %d\n", err); + return false; + } + + LzmaDec_Init(&Stream); + return true; + } + + ~DecompressorLZMA () + { + LzmaDec_Free(&Stream, &g_Alloc); + } + + ptrdiff_t Read (void *buffer, ptrdiff_t len) override + { + if (File == nullptr) + { + DecompressionError("File not open"); + return 0; + } + + int err; + Byte *next_out = (Byte *)buffer; + + do + { + ELzmaFinishMode finish_mode = LZMA_FINISH_ANY; + ELzmaStatus status; + size_t out_processed = len; + size_t in_processed = InSize; + + err = LzmaDec_DecodeToBuf(&Stream, next_out, &out_processed, InBuff + InPos, &in_processed, finish_mode, &status); + InPos += in_processed; + InSize -= in_processed; + next_out += out_processed; + len = (long)(len - out_processed); + if (err != SZ_OK) + { + DecompressionError ("Corrupt LZMA stream"); + return 0; + } + if (in_processed == 0 && out_processed == 0) + { + if (status != LZMA_STATUS_FINISHED_WITH_MARK) + { + DecompressionError ("Corrupt LZMA stream"); + return 0; + } + } + if (InSize == 0 && !SawEOF) + { + FillBuffer (); + } + } while (err == SZ_OK && len != 0); + + if (err != Z_OK && err != Z_STREAM_END) + { + DecompressionError ("Corrupt LZMA stream"); + return 0; + } + + if (len != 0) + { + DecompressionError ("Ran out of data in LZMA stream"); + return 0; + } + + return (ptrdiff_t)(next_out - (Byte *)buffer); + } + + void FillBuffer () + { + auto numread = File->Read(InBuff, BUFF_SIZE); + + if (numread < BUFF_SIZE) + { + SawEOF = true; + } + InPos = 0; + InSize = numread; + } + +}; + +//========================================================================== +// +// DecompressorXZ +// +// The XZ wrapper +// reads data from a XZ compressed stream +// +//========================================================================== + +// Wraps around a Decompressor to decompress a XZ stream +class DecompressorXZ : public DecompressorBase +{ + enum { BUFF_SIZE = 4096 }; + + bool SawEOF = false; + CXzUnpacker Stream; + size_t Size; + size_t InPos, InSize; + size_t OutProcessed; + uint8_t InBuff[BUFF_SIZE]; + +public: + + bool Open(FileReader *file, size_t uncompressed_size) + { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + + uint8_t header[12]; + File = file; + + Size = uncompressed_size; + OutProcessed = 0; + + // Read zip XZ properties header + if (File->Read(header, sizeof(header)) < (long)sizeof(header)) + { + DecompressionError("DecompressorXZ: File too short\n"); + return false; + } + + File->Seek(-(ptrdiff_t)sizeof(header), FileReader::SeekCur); + + FillBuffer(); + + XzUnpacker_Construct(&Stream, &g_Alloc); + XzUnpacker_Init(&Stream); + + return true; + } + + ~DecompressorXZ () + { + XzUnpacker_Free(&Stream); + } + + ptrdiff_t Read (void *buffer, ptrdiff_t len) override + { + if (File == nullptr) + { + DecompressionError("File not open"); + return 0; + } + + if (g_CrcTable[1] == 0) + { + CrcGenerateTable(); + } + + int err; + Byte *next_out = (Byte *)buffer; + + do + { + ECoderFinishMode finish_mode = CODER_FINISH_ANY; + ECoderStatus status; + size_t out_processed = len; + size_t in_processed = InSize; + + err = XzUnpacker_Code(&Stream, next_out, &out_processed, InBuff + InPos, &in_processed, SawEOF, finish_mode, &status); + InPos += in_processed; + InSize -= in_processed; + next_out += out_processed; + len = (long)(len - out_processed); + if (err != SZ_OK) + { + DecompressionError ("Corrupt XZ stream", err); + return 0; + } + if (in_processed == 0 && out_processed == 0) + { + if (status != CODER_STATUS_FINISHED_WITH_MARK) + { + DecompressionError ("Corrupt XZ stream"); + return 0; + } + } + if (InSize == 0 && !SawEOF) + { + FillBuffer (); + } + } while (err == SZ_OK && len != 0); + + if (err != Z_OK && err != Z_STREAM_END) + { + DecompressionError ("Corrupt XZ stream"); + return 0; + } + + if (len != 0) + { + DecompressionError ("Ran out of data in XZ stream"); + return 0; + } + + return (long)(next_out - (Byte *)buffer); + } + + void FillBuffer () + { + auto numread = File->Read(InBuff, BUFF_SIZE); + + if (numread < BUFF_SIZE) + { + SawEOF = true; + } + InPos = 0; + InSize = numread; + } + +}; + +//========================================================================== +// +// Console Doom LZSS wrapper. +// +//========================================================================== + +class DecompressorLZSS : public DecompressorBase +{ + enum { BUFF_SIZE = 4096, WINDOW_SIZE = 4096, INTERNAL_BUFFER_SIZE = 128 }; + + bool SawEOF; + uint8_t InBuff[BUFF_SIZE]; + + enum StreamState + { + STREAM_EMPTY, + STREAM_BITS, + STREAM_FLUSH, + STREAM_FINAL + }; + struct + { + StreamState State; + + uint8_t *In; + unsigned int AvailIn; + unsigned int InternalOut; + + uint8_t CFlags, Bits; + + uint8_t Window[WINDOW_SIZE+INTERNAL_BUFFER_SIZE]; + const uint8_t *WindowData; + uint8_t *InternalBuffer; + } Stream; + + void FillBuffer() + { + if(Stream.AvailIn) + memmove(InBuff, Stream.In, Stream.AvailIn); + + auto numread = File->Read(InBuff+Stream.AvailIn, BUFF_SIZE-Stream.AvailIn); + + if (numread < BUFF_SIZE) + { + SawEOF = true; + } + Stream.In = InBuff; + Stream.AvailIn = (unsigned)numread+Stream.AvailIn; + } + + // Reads a flag byte. + void PrepareBlocks() + { + assert(Stream.InternalBuffer == Stream.WindowData); + Stream.CFlags = *Stream.In++; + --Stream.AvailIn; + Stream.Bits = 0xFF; + Stream.State = STREAM_BITS; + } + + // Reads the next chunk in the block. Returns true if successful and + // returns false if it ran out of input data. + bool UncompressBlock() + { + if(Stream.CFlags & 1) + { + // Check to see if we have enough input + if(Stream.AvailIn < 2) + return false; + Stream.AvailIn -= 2; + + uint16_t pos = BigShort(*(uint16_t*)Stream.In); + uint8_t len = (pos & 0xF)+1; + pos >>= 4; + Stream.In += 2; + if(len == 1) + { + // We've reached the end of the stream. + Stream.State = STREAM_FINAL; + return true; + } + + const uint8_t* copyStart = Stream.InternalBuffer-pos-1; + + // Complete overlap: Single byte repeated + if(pos == 0) + memset(Stream.InternalBuffer, *copyStart, len); + // No overlap: One copy + else if(pos >= len) + memcpy(Stream.InternalBuffer, copyStart, len); + else + { + // Partial overlap: Copy in 2 or 3 chunks. + do + { + unsigned int copy = std::min(len, pos+1); + memcpy(Stream.InternalBuffer, copyStart, copy); + Stream.InternalBuffer += copy; + Stream.InternalOut += copy; + len -= copy; + pos += copy; // Increase our position since we can copy twice as much the next round. + } + while(len); + } + + Stream.InternalOut += len; + Stream.InternalBuffer += len; + } + else + { + // Uncompressed byte. + *Stream.InternalBuffer++ = *Stream.In++; + --Stream.AvailIn; + ++Stream.InternalOut; + } + + Stream.CFlags >>= 1; + Stream.Bits >>= 1; + + // If we're done with this block, flush the output + if(Stream.Bits == 0) + Stream.State = STREAM_FLUSH; + + return true; + } + +public: + bool Open(FileReader *file) + { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + + File = file; + Stream.State = STREAM_EMPTY; + Stream.WindowData = Stream.InternalBuffer = Stream.Window+WINDOW_SIZE; + Stream.InternalOut = 0; + Stream.AvailIn = 0; + + FillBuffer(); + return true; + } + + ~DecompressorLZSS() + { + } + + ptrdiff_t Read(void *buffer, ptrdiff_t len) override + { + if (len > 0xffffffff) len = 0xffffffff; // this format cannot be larger than 4GB. + + uint8_t *Out = (uint8_t*)buffer; + ptrdiff_t AvailOut = len; + + do + { + while(Stream.AvailIn) + { + if(Stream.State == STREAM_EMPTY) + PrepareBlocks(); + else if(Stream.State == STREAM_BITS && !UncompressBlock()) + break; + else + break; + } + + unsigned int copy = (unsigned)std::min(Stream.InternalOut, AvailOut); + if(copy > 0) + { + memcpy(Out, Stream.WindowData, copy); + Out += copy; + AvailOut -= copy; + + // Slide our window + memmove(Stream.Window, Stream.Window+copy, WINDOW_SIZE+INTERNAL_BUFFER_SIZE-copy); + Stream.InternalBuffer -= copy; + Stream.InternalOut -= copy; + } + + if(Stream.State == STREAM_FINAL) + break; + + if(Stream.InternalOut == 0 && Stream.State == STREAM_FLUSH) + Stream.State = STREAM_EMPTY; + + if(Stream.AvailIn < 2) + FillBuffer(); + } + while(AvailOut && Stream.State != STREAM_FINAL); + + assert(AvailOut == 0); + return (ptrdiff_t)(Out - (uint8_t*)buffer); + } +}; + + +bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size length, int method, int flags) +{ + FileReaderInterface* fr = nullptr; + DecompressorBase* dec = nullptr; + try + { + FileReader* p = &parent; + bool exceptions = !!(flags & DCF_EXCEPTIONS); + + switch (method) + { + case METHOD_DEFLATE: + case METHOD_ZLIB: + { + auto idec = new DecompressorZ; + fr = dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p, method == METHOD_DEFLATE)) + { + delete idec; + return false; + } + break; + } + case METHOD_BZIP2: + { + auto idec = new DecompressorBZ2; + fr = dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p)) + { + delete idec; + return false; + } + break; + } + case METHOD_LZMA: + { + auto idec = new DecompressorLZMA; + fr = dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p, length)) + { + delete idec; + return false; + } + break; + } + case METHOD_XZ: + { + auto idec = new DecompressorXZ; + fr = dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p, length)) + { + delete idec; + return false; + } + break; + } + case METHOD_LZSS: + { + auto idec = new DecompressorLZSS; + fr = dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p)) + { + delete idec; + return false; + } + break; + } + + // The decoders for these legacy formats can only handle the full data in one go so we have to perform the entire decompression here. + case METHOD_IMPLODE_0: + case METHOD_IMPLODE_2: + case METHOD_IMPLODE_4: + case METHOD_IMPLODE_6: + { + FileData buffer(nullptr, length); + FZipExploder exploder; + if (exploder.Explode(buffer.writable(), (unsigned)length, *p, (unsigned)p->GetLength(), method - METHOD_IMPLODE_MIN) == -1) + { + if (exceptions) + { + throw FileSystemException("DecompressImplode failed"); + } + return false; + } + fr = new MemoryArrayReader(buffer); + flags &= ~(DCF_SEEKABLE | DCF_CACHED); + break; + } + + case METHOD_SHRINK: + { + FileData buffer(nullptr, length); + ShrinkLoop(buffer.writable(), (unsigned)length, *p, (unsigned)p->GetLength()); // this never fails. + fr = new MemoryArrayReader(buffer); + flags &= ~(DCF_SEEKABLE | DCF_CACHED); + break; + } + + // While this could be made a buffering reader it isn't worth the effort because only stock RFFs are encrypted and they do not contain large files. + case METHOD_RFFCRYPT: + { + FileData buffer = p->Read(length); + auto bufr = buffer.writable(); + FileReader::Size cryptlen = std::min(length, 256); + + for (FileReader::Size i = 0; i < cryptlen; ++i) + { + bufr[i] ^= i >> 1; + } + fr = new MemoryArrayReader(buffer); + flags &= ~(DCF_SEEKABLE | DCF_CACHED); + break; + } + + default: + return false; + } + if (dec) + { + if (flags & DCF_TRANSFEROWNER) + { + dec->SetOwnsReader(); + } + dec->Length = length; + } + if ((flags & (DCF_CACHED| DCF_SEEKABLE))) // the buffering reader does not seem to be stable, so cache it instead until we find out what's wrong. + { + // read everything into a MemoryArrayReader. + FileData data(nullptr, length); + fr->Read(data.writable(), length); + delete fr; + fr = new MemoryArrayReader(data); + } + else if ((flags & DCF_SEEKABLE)) + { + // create a wrapper that can buffer the content so that seeking is possible + fr = new BufferingReader(fr); + } + self = FileReader(fr); + return true; + } + catch (...) + { + if (fr) delete fr; + throw; + } +} + + +bool FCompressedBuffer::Decompress(char* destbuffer) +{ + if (mMethod == METHOD_STORED) + { + memcpy(destbuffer, mBuffer, mSize); + return true; + } + else + { + FileReader mr; + mr.OpenMemory(mBuffer, mCompressedSize); + FileReader frz; + if (OpenDecompressor(frz, mr, mSize, mMethod)) + { + return frz.Read(destbuffer, mSize) != mSize; + } + } + return false; +} +} \ No newline at end of file diff --git a/src/common/filesystem/source/files_internal.h b/src/common/filesystem/source/files_internal.h new file mode 100644 index 00000000000..08f48659946 --- /dev/null +++ b/src/common/filesystem/source/files_internal.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include "fs_files.h" + +namespace FileSys { + +class MemoryReader : public FileReaderInterface +{ +protected: + const char * bufptr = nullptr; + ptrdiff_t FilePos = 0; + + MemoryReader() + {} + +public: + MemoryReader(const char *buffer, ptrdiff_t length) + { + bufptr = buffer; + Length = length; + FilePos = 0; + } + + ptrdiff_t Tell() const override; + ptrdiff_t Seek(ptrdiff_t offset, int origin) override; + ptrdiff_t Read(void *buffer, ptrdiff_t len) override; + char *Gets(char *strbuf, ptrdiff_t len) override; + virtual const char *GetBuffer() const override { return bufptr; } +}; + +class BufferingReader : public MemoryReader +{ + FileData buf; + std::unique_ptr baseReader; + ptrdiff_t bufferpos = 0; + + int FillBuffer(ptrdiff_t newpos); +public: + BufferingReader(FileReaderInterface* base) + : baseReader(base) + { + Length = base->Length; + buf.allocate(Length); + bufptr = (const char*)buf.data(); + } + + ptrdiff_t Seek(ptrdiff_t offset, int origin) override; + ptrdiff_t Read(void* buffer, ptrdiff_t len) override; + char* Gets(char* strbuf, ptrdiff_t len) override; +}; + +//========================================================================== +// +// MemoryArrayReader +// +// reads data from an array of memory +// +//========================================================================== + +class MemoryArrayReader : public MemoryReader +{ + FileData buf; + +public: + MemoryArrayReader() + { + FilePos = 0; + Length = 0; + } + + MemoryArrayReader(size_t len) + { + buf.allocate(len); + UpdateBuffer(); + } + + MemoryArrayReader(FileData& buffer) + { + buf = std::move(buffer); + UpdateBuffer(); + } + + void UpdateBuffer() + { + bufptr = (const char*)buf.data(); + FilePos = 0; + Length = buf.size(); + } +}; + +} diff --git a/src/common/filesystem/source/filesystem.cpp b/src/common/filesystem/source/filesystem.cpp new file mode 100644 index 00000000000..fee5f101143 --- /dev/null +++ b/src/common/filesystem/source/filesystem.cpp @@ -0,0 +1,1523 @@ +/* +** filesystem.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include +#include + +#include "resourcefile.h" +#include "fs_filesystem.h" +#include "fs_findfile.h" +#include "md5.hpp" +#include "fs_stringpool.h" + +namespace FileSys { + +// MACROS ------------------------------------------------------------------ + +#define NULL_INDEX (0xffffffff) + +static void UpperCopy(char* to, const char* from) +{ + int i; + + for (i = 0; i < 8 && from[i]; i++) + to[i] = toupper(from[i]); + for (; i < 8; i++) + to[i] = 0; +} + + +//djb2 +static uint32_t MakeHash(const char* str, size_t length = SIZE_MAX) +{ + uint32_t hash = 5381; + uint32_t c; + while (length-- > 0 && (c = *str++)) hash = hash * 33 + (c | 32); + return hash; +} + +static void md5Hash(FileReader& reader, uint8_t* digest) +{ + using namespace md5; + + md5_state_t state; + md5_init(&state); + md5_byte_t buffer[4096]; + while (auto len = reader.Read(buffer, 4096)) + { + md5_append(&state, buffer, len); + } + md5_finish(&state, digest); +} + + +struct FileSystem::LumpRecord +{ + FResourceFile *resfile; + LumpShortName shortName; + const char* LongName; + int resindex; + int16_t rfnum; // this is not necessarily the same as resfile's index! + int16_t Namespace; + int resourceId; + int flags; + + void SetFromLump(FResourceFile* file, int fileindex, int filenum, StringPool* sp, const char* name = nullptr) + { + resfile = file; + resindex = fileindex; + rfnum = filenum; + flags = 0; + + auto lflags = file->GetEntryFlags(fileindex); + if (!name) name = file->getName(fileindex); + if (lflags & RESFF_SHORTNAME) + { + UpperCopy(shortName.String, name); + shortName.String[8] = 0; + LongName = ""; + Namespace = file->GetEntryNamespace(fileindex); + resourceId = -1; + } + else if ((lflags & RESFF_EMBEDDED) || !name || !*name) + { + shortName.qword = 0; + LongName = ""; + Namespace = ns_hidden; + resourceId = -1; + } + else + { + LongName = name; + resourceId = file->GetEntryResourceID(fileindex); + + // Map some directories to WAD namespaces. + // Note that some of these namespaces don't exist in WADS. + // CheckNumForName will handle any request for these namespaces accordingly. + Namespace = !strncmp(LongName, "flats/", 6) ? ns_flats : + !strncmp(LongName, "textures/", 9) ? ns_newtextures : + !strncmp(LongName, "hires/", 6) ? ns_hires : + !strncmp(LongName, "sprites/", 8) ? ns_sprites : + !strncmp(LongName, "voxels/", 7) ? ns_voxels : + !strncmp(LongName, "colormaps/", 10) ? ns_colormaps : + !strncmp(LongName, "acs/", 4) ? ns_acslibrary : + !strncmp(LongName, "voices/", 7) ? ns_strifevoices : + !strncmp(LongName, "patches/", 8) ? ns_patches : + !strncmp(LongName, "graphics/", 9) ? ns_graphics : + !strncmp(LongName, "sounds/", 7) ? ns_sounds : + !strncmp(LongName, "music/", 6) ? ns_music : + !strchr(LongName, '/') ? ns_global : + ns_hidden; + + if (Namespace == ns_hidden) shortName.qword = 0; + else if (strstr(LongName, ".{")) + { + std::string longName = LongName; + ptrdiff_t encodedResID = longName.find_last_of(".{"); + if (resourceId == -1 && (size_t)encodedResID != std::string::npos) + { + const char* p = LongName + encodedResID; + char* q; + int id = (int)strtoull(p + 2, &q, 10); // only decimal numbers allowed here. + if (q[0] == '}' && (q[1] == '.' || q[1] == 0)) + { + longName.erase(longName.begin() + encodedResID, longName.begin() + (q - p) + 1); + resourceId = id; + } + LongName = sp->Strdup(longName.c_str()); + } + } + auto slash = strrchr(LongName, '/'); + std::string base = slash ? (slash + 1) : LongName; + auto dot = base.find_last_of('.'); + if (dot != std::string::npos) base.resize(dot); + UpperCopy(shortName.String, base.c_str()); + + // Since '\' can't be used as a file name's part inside a ZIP + // we have to work around this for sprites because it is a valid + // frame character. + if (Namespace == ns_sprites || Namespace == ns_voxels || Namespace == ns_hires) + { + char* c; + + while ((c = (char*)memchr(shortName.String, '^', 8))) + { + *c = '\\'; + } + } + } + } +}; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void PrintLastError (FileSystemMessageFunc Printf); + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// CODE -------------------------------------------------------------------- + +FileSystem::FileSystem() +{ +} + +FileSystem::~FileSystem () +{ + DeleteAll(); +} + +void FileSystem::DeleteAll () +{ + Hashes.clear(); + NumEntries = 0; + + FileInfo.clear(); + for (int i = (int)Files.size() - 1; i >= 0; --i) + { + delete Files[i]; + } + Files.clear(); + if (stringpool != nullptr) delete stringpool; + stringpool = nullptr; +} + +//========================================================================== +// +// InitMultipleFiles +// +// Pass a null terminated list of files to use. All files are optional, +// but at least one file must be found. File names can appear multiple +// times. The name searcher looks backwards, so a later file can +// override an earlier one. +// +//========================================================================== + +bool FileSystem::InitSingleFile(const char* filename, FileSystemMessageFunc Printf) +{ + std::vector filenames = { filename }; + return InitMultipleFiles(filenames, nullptr, Printf); +} + +bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates, FILE* hashfile) +{ + int numfiles; + + // the first call here will designate a main thread which may use shared file readers. All other thewads have to open new file handles. + SetMainThread(); + // open all the files, load headers, and count lumps + DeleteAll(); + numfiles = 0; + + stringpool = new StringPool(true); + stringpool->shared = true; // will be used by all owned resource files. + + // first, check for duplicates + if (!allowduplicates) + { + for (size_t i=0;iGetHash(); + MoveLumpsInFolder(path.c_str()); + } + + NumEntries = (uint32_t)FileInfo.size(); + if (NumEntries == 0) + { + return false; + } + if (filter && filter->postprocessFunc) filter->postprocessFunc(); + + // [RH] Set up hash table + InitHashChains (); + return true; +} + +//========================================================================== +// +// AddFromBuffer +// +// Adds an in-memory resource to the virtual directory +// +//========================================================================== + +int FileSystem::AddFromBuffer(const char* name, char* data, int size, int id, int flags) +{ + FileReader fr; + FileData blob(data, size); + fr.OpenMemoryArray(blob); + + // wrap this into a single lump resource file (should be done a little better later.) + auto rf = new FResourceFile(name, fr, stringpool); + auto Entries = rf->AllocateEntries(1); + Entries[0].FileName = rf->NormalizeFileName(ExtractBaseName(name, true).c_str()); + Entries[0].ResourceID = -1; + Entries[0].Length = size; + + Files.push_back(rf); + FileInfo.resize(FileInfo.size() + 1); + FileSystem::LumpRecord* lump_p = &FileInfo.back(); + lump_p->SetFromLump(rf, 0, (int)Files.size() - 1, stringpool); + return (int)FileInfo.size() - 1; +} + +//========================================================================== +// +// AddFile +// +// Files with a .wad extension are wadlink files with multiple lumps, +// other files are single lumps with the base filename for the lump name. +// +// [RH] Removed reload hack +//========================================================================== + +void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInfo* filter, FileSystemMessageFunc Printf, FILE* hashfile) +{ + int startlump; + bool isdir = false; + FileReader filereader; + + if (filer == nullptr) + { + // Does this exist? If so, is it a directory? + if (!FS_DirEntryExists(filename, &isdir)) + { + if (Printf) + { + Printf(FSMessageLevel::Error, "%s: File or Directory not found\n", filename); + PrintLastError(Printf); + } + return; + } + + if (!isdir) + { + if (!filereader.OpenFile(filename)) + { // Didn't find file + if (Printf) + { + Printf(FSMessageLevel::Error, "%s: File not found\n", filename); + PrintLastError(Printf); + } + return; + } + } + } + else filereader = std::move(*filer); + + startlump = NumEntries; + + FResourceFile *resfile; + + + if (!isdir) + resfile = FResourceFile::OpenResourceFile(filename, filereader, false, filter, Printf, stringpool); + else + resfile = FResourceFile::OpenDirectory(filename, filter, Printf, stringpool); + + if (resfile != NULL) + { + if (Printf) + Printf(FSMessageLevel::Message, "adding %s, %d lumps\n", filename, resfile->EntryCount()); + + uint32_t lumpstart = (uint32_t)FileInfo.size(); + + resfile->SetFirstLump(lumpstart); + Files.push_back(resfile); + for (int i = 0; i < resfile->EntryCount(); i++) + { + FileInfo.resize(FileInfo.size() + 1); + FileSystem::LumpRecord* lump_p = &FileInfo.back(); + lump_p->SetFromLump(resfile, i, (int)Files.size() - 1, stringpool); + } + + for (int i = 0; i < resfile->EntryCount(); i++) + { + int flags = resfile->GetEntryFlags(i); + if (flags & RESFF_EMBEDDED) + { + std::string path = filename; + path += ':'; + path += resfile->getName(i); + auto embedded = resfile->GetEntryReader(i, READER_CACHED); + AddFile(path.c_str(), &embedded, filter, Printf, hashfile); + } + } + + if (hashfile) + { + uint8_t cksum[16]; + char cksumout[33]; + memset(cksumout, 0, sizeof(cksumout)); + + if (filereader.isOpen()) + { + filereader.Seek(0, FileReader::SeekSet); + md5Hash(filereader, cksum); + + for (size_t j = 0; j < sizeof(cksum); ++j) + { + snprintf(cksumout + (j * 2), 3, "%02X", cksum[j]); + } + + fprintf(hashfile, "file: %s, hash: %s, size: %td\n", filename, cksumout, filereader.GetLength()); + } + + else + fprintf(hashfile, "file: %s, Directory structure\n", filename); + + for (int i = 0; i < resfile->EntryCount(); i++) + { + int flags = resfile->GetEntryFlags(i); + if (!(flags & RESFF_EMBEDDED)) + { + auto reader = resfile->GetEntryReader(i, READER_SHARED, 0); + md5Hash(filereader, cksum); + + for (size_t j = 0; j < sizeof(cksum); ++j) + { + snprintf(cksumout + (j * 2), 3, "%02X", cksum[j]); + } + + fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %zu\n", filename, resfile->getName(i), cksumout, (uint64_t)resfile->Length(i)); + } + } + } + return; + } +} + +//========================================================================== +// +// CheckIfResourceFileLoaded +// +// Returns true if the specified file is loaded, false otherwise. +// If a fully-qualified path is specified, then the file must match exactly. +// Otherwise, any file with that name will work, whatever its path. +// Returns the file's index if found, or -1 if not. +// +//========================================================================== + +int FileSystem::CheckIfResourceFileLoaded (const char *name) noexcept +{ + unsigned int i; + + if (strrchr (name, '/') != NULL) + { + for (i = 0; i < (unsigned)Files.size(); ++i) + { + if (stricmp (GetResourceFileFullName (i), name) == 0) + { + return i; + } + } + } + else + { + for (i = 0; i < (unsigned)Files.size(); ++i) + { + auto pth = ExtractBaseName(GetResourceFileName(i), true); + if (stricmp (pth.c_str(), name) == 0) + { + return i; + } + } + } + return -1; +} + +//========================================================================== +// +// CheckNumForName +// +// Returns -1 if name not found. The version with a third parameter will +// look exclusively in the specified wad for the lump. +// +// [RH] Changed to use hash lookup ala BOOM instead of a linear search +// and namespace parameter +//========================================================================== + +int FileSystem::CheckNumForName (const char *name, int space) const +{ + union + { + char uname[8]; + uint64_t qname; + }; + uint32_t i; + + if (name == NULL) + { + return -1; + } + + // Let's not search for names that are longer than 8 characters and contain path separators + // They are almost certainly full path names passed to this function. + if (strlen(name) > 8 && strpbrk(name, "/.")) + { + return -1; + } + + UpperCopy (uname, name); + i = FirstLumpIndex[MakeHash(uname, 8) % NumEntries]; + + while (i != NULL_INDEX) + { + + if (FileInfo[i].shortName.qword == qname) + { + auto &lump = FileInfo[i]; + if (lump.Namespace == space) break; + // If the lump is from one of the special namespaces exclusive to Zips + // the check has to be done differently: + // If we find a lump with this name in the global namespace that does not come + // from a Zip return that. WADs don't know these namespaces and single lumps must + // work as well. + auto lflags = lump.resfile->GetEntryFlags(lump.resindex); + if (space > ns_specialzipdirectory && lump.Namespace == ns_global && + !((lflags ^lump.flags) & RESFF_FULLPATH)) break; + } + i = NextLumpIndex[i]; + } + + return i != NULL_INDEX ? i : -1; +} + +int FileSystem::CheckNumForName (const char *name, int space, int rfnum, bool exact) const +{ + union + { + char uname[8]; + uint64_t qname; + }; + uint32_t i; + + if (rfnum < 0) + { + return CheckNumForName (name, space); + } + + UpperCopy (uname, name); + i = FirstLumpIndex[MakeHash (uname, 8) % NumEntries]; + + // If exact is true if will only find lumps in the same WAD, otherwise + // also those in earlier WADs. + + while (i != NULL_INDEX && + (FileInfo[i].shortName.qword != qname || FileInfo[i].Namespace != space || + (exact? (FileInfo[i].rfnum != rfnum) : (FileInfo[i].rfnum > rfnum)) )) + { + i = NextLumpIndex[i]; + } + + return i != NULL_INDEX ? i : -1; +} + +//========================================================================== +// +// GetNumForName +// +// Calls CheckNumForName, but bombs out if not found. +// +//========================================================================== + +int FileSystem::GetNumForName (const char *name, int space) const +{ + int i; + + i = CheckNumForName (name, space); + + if (i == -1) + throw FileSystemException("GetNumForName: %s not found!", name); + + return i; +} + + +//========================================================================== +// +// CheckNumForFullName +// +// Same as above but looks for a fully qualified name from a .zip +// These don't care about namespaces though because those are part +// of the path. +// +//========================================================================== + +int FileSystem::CheckNumForFullName (const char *name, bool trynormal, int namespc, bool ignoreext) const +{ + uint32_t i; + + if (name == NULL) + { + return -1; + } + if (*name == '/') name++; // ignore leading slashes in file names. + uint32_t *fli = ignoreext ? FirstLumpIndex_NoExt : FirstLumpIndex_FullName; + uint32_t *nli = ignoreext ? NextLumpIndex_NoExt : NextLumpIndex_FullName; + auto len = strlen(name); + + for (i = fli[MakeHash(name) % NumEntries]; i != NULL_INDEX; i = nli[i]) + { + if (strnicmp(name, FileInfo[i].LongName, len)) continue; + if (FileInfo[i].LongName[len] == 0) break; // this is a full match + if (ignoreext && FileInfo[i].LongName[len] == '.') + { + // is this the last '.' in the last path element, indicating that the remaining part of the name is only an extension? + if (strpbrk(FileInfo[i].LongName + len + 1, "./") == nullptr) break; + } + } + + if (i != NULL_INDEX) return i; + + if (trynormal && strlen(name) <= 8 && !strpbrk(name, "./")) + { + return CheckNumForName(name, namespc); + } + return -1; +} + +int FileSystem::CheckNumForFullName (const char *name, int rfnum) const +{ + uint32_t i; + + if (rfnum < 0) + { + return CheckNumForFullName (name); + } + + i = FirstLumpIndex_FullName[MakeHash (name) % NumEntries]; + + while (i != NULL_INDEX && + (stricmp(name, FileInfo[i].LongName) || FileInfo[i].rfnum != rfnum)) + { + i = NextLumpIndex_FullName[i]; + } + + return i != NULL_INDEX ? i : -1; +} + +//========================================================================== +// +// GetNumForFullName +// +// Calls CheckNumForFullName, but bombs out if not found. +// +//========================================================================== + +int FileSystem::GetNumForFullName (const char *name) const +{ + int i; + + i = CheckNumForFullName (name); + + if (i == -1) + throw FileSystemException("GetNumForFullName: %s not found!", name); + + return i; +} + +//========================================================================== +// +// FindFile +// +// Looks up a file by name, either with or without path and extension +// +//========================================================================== + +int FileSystem::FindFileWithExtensions(const char* name, const char *const *exts, int count) const +{ + uint32_t i; + + if (name == NULL) + { + return -1; + } + if (*name == '/') name++; // ignore leading slashes in file names. + uint32_t* fli = FirstLumpIndex_NoExt; + uint32_t* nli = NextLumpIndex_NoExt; + auto len = strlen(name); + + for (i = fli[MakeHash(name) % NumEntries]; i != NULL_INDEX; i = nli[i]) + { + if (strnicmp(name, FileInfo[i].LongName, len)) continue; + if (FileInfo[i].LongName[len] != '.') continue; // we are looking for extensions but this file doesn't have one. + + auto cp = FileInfo[i].LongName + len + 1; + // is this the last '.' in the last path element, indicating that the remaining part of the name is only an extension? + if (strpbrk(cp, "./") != nullptr) continue; // No, so it cannot be a valid entry. + + for (int j = 0; j < count; j++) + { + if (!stricmp(cp, exts[j])) return i; // found a match + } + } + return -1; +} + +//========================================================================== +// +// FindResource +// +// Looks for content based on Blood resource IDs. +// +//========================================================================== + +int FileSystem::FindResource (int resid, const char *type, int filenum) const noexcept +{ + uint32_t i; + + if (type == NULL || resid < 0) + { + return -1; + } + + uint32_t* fli = FirstLumpIndex_ResId; + uint32_t* nli = NextLumpIndex_ResId; + + for (i = fli[resid % NumEntries]; i != NULL_INDEX; i = nli[i]) + { + if (filenum > 0 && FileInfo[i].rfnum != filenum) continue; + if (FileInfo[i].resourceId != resid) continue; + auto extp = strrchr(FileInfo[i].LongName, '.'); + if (!extp) continue; + if (!stricmp(extp + 1, type)) return i; + } + return -1; +} + +//========================================================================== +// +// GetResource +// +// Calls GetResource, but bombs out if not found. +// +//========================================================================== + +int FileSystem::GetResource (int resid, const char *type, int filenum) const +{ + int i; + + i = FindResource (resid, type, filenum); + + if (i == -1) + { + throw FileSystemException("GetResource: %d of type %s not found!", resid, type); + } + return i; +} + +//========================================================================== +// +// FileLength +// +// Returns the buffer size needed to load the given lump. +// +//========================================================================== + +ptrdiff_t FileSystem::FileLength (int lump) const +{ + if ((size_t)lump >= NumEntries) + { + return -1; + } + const auto &lump_p = FileInfo[lump]; + return (int)lump_p.resfile->Length(lump_p.resindex); +} + +//========================================================================== +// +// +// +//========================================================================== + +int FileSystem::GetFileFlags (int lump) +{ + if ((size_t)lump >= NumEntries) + { + return 0; + } + + const auto& lump_p = FileInfo[lump]; + return lump_p.resfile->GetEntryFlags(lump_p.resindex) ^ lump_p.flags; +} + +//========================================================================== +// +// InitHashChains +// +// Prepares the lumpinfos for hashing. +// (Hey! This looks suspiciously like something from Boom! :-) +// +//========================================================================== + +void FileSystem::InitHashChains (void) +{ + unsigned int i, j; + + NumEntries = (uint32_t)FileInfo.size(); + Hashes.resize(8 * NumEntries); + // Mark all buckets as empty + memset(Hashes.data(), -1, Hashes.size() * sizeof(Hashes[0])); + FirstLumpIndex = &Hashes[0]; + NextLumpIndex = &Hashes[NumEntries]; + FirstLumpIndex_FullName = &Hashes[NumEntries * 2]; + NextLumpIndex_FullName = &Hashes[NumEntries * 3]; + FirstLumpIndex_NoExt = &Hashes[NumEntries * 4]; + NextLumpIndex_NoExt = &Hashes[NumEntries * 5]; + FirstLumpIndex_ResId = &Hashes[NumEntries * 6]; + NextLumpIndex_ResId = &Hashes[NumEntries * 7]; + + + // Now set up the chains + for (i = 0; i < (unsigned)NumEntries; i++) + { + j = MakeHash (FileInfo[i].shortName.String, 8) % NumEntries; + NextLumpIndex[i] = FirstLumpIndex[j]; + FirstLumpIndex[j] = i; + + // Do the same for the full paths + if (FileInfo[i].LongName[0] != 0) + { + j = MakeHash(FileInfo[i].LongName) % NumEntries; + NextLumpIndex_FullName[i] = FirstLumpIndex_FullName[j]; + FirstLumpIndex_FullName[j] = i; + + std::string nameNoExt = FileInfo[i].LongName; + auto dot = nameNoExt.find_last_of('.'); + auto slash = nameNoExt.find_last_of('/'); + if ((dot > slash || slash == std::string::npos) && dot != std::string::npos) nameNoExt.resize(dot); + + j = MakeHash(nameNoExt.c_str()) % NumEntries; + NextLumpIndex_NoExt[i] = FirstLumpIndex_NoExt[j]; + FirstLumpIndex_NoExt[j] = i; + + j = FileInfo[i].resourceId % NumEntries; + NextLumpIndex_ResId[i] = FirstLumpIndex_ResId[j]; + FirstLumpIndex_ResId[j] = i; + + } + } + FileInfo.shrink_to_fit(); + Files.shrink_to_fit(); +} + +//========================================================================== +// +// should only be called before the hash chains are set up. +// If done later this needs rehashing. +// +//========================================================================== + +LumpShortName& FileSystem::GetShortName(int i) +{ + if ((unsigned)i >= NumEntries) throw FileSystemException("GetShortName: Invalid index"); + return FileInfo[i].shortName; +} + +void FileSystem::RenameFile(int num, const char* newfn) +{ + if ((unsigned)num >= NumEntries) throw FileSystemException("RenameFile: Invalid index"); + FileInfo[num].LongName = stringpool->Strdup(newfn); + // This does not alter the short name - call GetShortname to do that! +} + +//========================================================================== +// +// MoveLumpsInFolder +// +// Moves all content from the given subfolder of the internal +// resources to the current end of the directory. +// Used to allow modifying content in the base files, this is needed +// so that Hacx and Harmony can override some content that clashes +// with localization, and to inject modifying data into mods, in case +// this is needed for some compatibility requirement. +// +//========================================================================== + +void FileSystem::MoveLumpsInFolder(const char *path) +{ + if (FileInfo.size() == 0) + { + return; + } + + auto len = strlen(path); + auto rfnum = FileInfo.back().rfnum; + + size_t i; + for (i = 0; i < FileInfo.size(); i++) + { + auto& li = FileInfo[i]; + if (li.rfnum >= GetIwadNum()) break; + if (strnicmp(li.LongName, path, len) == 0) + { + auto lic = li; // make a copy before pushing. + FileInfo.push_back(lic); + li.LongName = ""; //nuke the name of the old record. + li.shortName.qword = 0; + auto &ln = FileInfo.back(); + ln.SetFromLump(li.resfile, li.resindex, rfnum, stringpool, ln.LongName + len); + } + } +} + +//========================================================================== +// +// W_FindLump +// +// Find a named lump. Specifically allows duplicates for merging of e.g. +// SNDINFO lumps. +// +//========================================================================== + +int FileSystem::FindLump (const char *name, int *lastlump, bool anyns) +{ + if ((size_t)*lastlump >= FileInfo.size()) return -1; + union + { + char name8[8]; + uint64_t qname; + }; + + UpperCopy (name8, name); + + assert(lastlump != NULL && *lastlump >= 0); + + const LumpRecord * last = FileInfo.data() + FileInfo.size(); + + LumpRecord * lump_p = FileInfo.data() + *lastlump; + + while (lump_p < last) + { + if ((anyns || lump_p->Namespace == ns_global) && lump_p->shortName.qword == qname) + { + int lump = int(lump_p - FileInfo.data()); + *lastlump = lump + 1; + return lump; + } + lump_p++; + } + + *lastlump = NumEntries; + return -1; +} + +//========================================================================== +// +// W_FindLumpMulti +// +// Find a named lump. Specifically allows duplicates for merging of e.g. +// SNDINFO lumps. Returns everything having one of the passed names. +// +//========================================================================== + +int FileSystem::FindLumpMulti (const char **names, int *lastlump, bool anyns, int *nameindex) +{ + assert(lastlump != NULL && *lastlump >= 0); + + const LumpRecord * last = FileInfo.data() + FileInfo.size(); + + LumpRecord * lump_p = FileInfo.data() + *lastlump; + + while (lump_p < last) + { + if (anyns || lump_p->Namespace == ns_global) + { + + for(const char **name = names; *name != NULL; name++) + { + if (!strnicmp(*name, lump_p->shortName.String, 8)) + { + int lump = int(lump_p - FileInfo.data()); + *lastlump = lump + 1; + if (nameindex != NULL) *nameindex = int(name - names); + return lump; + } + } + } + lump_p++; + } + + *lastlump = NumEntries; + return -1; +} + +//========================================================================== +// +// W_FindLump +// +// Find a named lump. Specifically allows duplicates for merging of e.g. +// SNDINFO lumps. +// +//========================================================================== + +int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext) +{ + assert(lastlump != NULL && *lastlump >= 0); + + const LumpRecord * last = FileInfo.data() + FileInfo.size(); + + LumpRecord * lump_p = FileInfo.data() + *lastlump; + + if (!noext) + { + while (lump_p < last) + { + if (!stricmp(name, lump_p->LongName)) + { + int lump = int(lump_p - FileInfo.data()); + *lastlump = lump + 1; + return lump; + } + lump_p++; + } + } + else + { + auto len = strlen(name); + while (lump_p <= &FileInfo.back()) + { + auto res = strnicmp(name, lump_p->LongName, len); + if (res == 0) + { + auto p = lump_p->LongName + len; + if (*p == 0 || (*p == '.' && strpbrk(p + 1, "./") == 0)) + { + int lump = int(lump_p - FileInfo.data()); + *lastlump = lump + 1; + return lump; + } + } + lump_p++; + } + } + + + *lastlump = NumEntries; + return -1; +} + +//========================================================================== +// +// W_CheckLumpName +// +//========================================================================== + +bool FileSystem::CheckFileName (int lump, const char *name) +{ + if ((size_t)lump >= NumEntries) + return false; + + return !strnicmp (FileInfo[lump].shortName.String, name, 8); +} + +//========================================================================== +// +// GetLumpName +// +//========================================================================== + +const char* FileSystem::GetFileShortName(int lump) const +{ + if ((size_t)lump >= NumEntries) + return nullptr; + else + return FileInfo[lump].shortName.String; +} + +//========================================================================== +// +// FileSystem :: GetFileFullName +// +// Returns the lump's full name if it has one or its short name if not. +// +//========================================================================== + +const char *FileSystem::GetFileFullName (int lump, bool returnshort) const +{ + if ((size_t)lump >= NumEntries) + return NULL; + else if (FileInfo[lump].LongName[0] != 0) + return FileInfo[lump].LongName; + else if (returnshort) + return FileInfo[lump].shortName.String; + else return nullptr; +} + +//========================================================================== +// +// FileSystem :: GetFileFullPath +// +// Returns the name of the lump's wad prefixed to the lump's full name. +// +//========================================================================== + +std::string FileSystem::GetFileFullPath(int lump) const +{ + std::string foo; + + if ((size_t) lump < NumEntries) + { + foo = GetResourceFileName(FileInfo[lump].rfnum); + foo += ':'; + foo += +GetFileFullName(lump); + } + return foo; +} + +//========================================================================== +// +// GetFileNamespace +// +//========================================================================== + +int FileSystem::GetFileNamespace (int lump) const +{ + if ((size_t)lump >= NumEntries) + return ns_global; + else + return FileInfo[lump].Namespace; +} + +void FileSystem::SetFileNamespace(int lump, int ns) +{ + if ((size_t)lump < NumEntries) FileInfo[lump].Namespace = ns; +} + +//========================================================================== +// +// FileSystem :: GetResourceId +// +// Returns the index number for this lump. This is *not* the lump's position +// in the lump directory, but rather a special value that RFF can associate +// with files. Other archive types will return 0, since they don't have it. +// +//========================================================================== + +int FileSystem::GetResourceId(int lump) const +{ + if ((size_t)lump >= NumEntries) + return -1; + else + return FileInfo[lump].resourceId; +} + +//========================================================================== +// +// GetResourceType +// +// is equivalent with the extension +// +//========================================================================== + +const char *FileSystem::GetResourceType(int lump) const +{ + if ((size_t)lump >= NumEntries) + return nullptr; + else + { + auto p = strrchr(FileInfo[lump].LongName, '.'); + if (!p) return ""; // has no extension + if (strchr(p, '/')) return ""; // the '.' is part of a directory. + return p + 1; + } +} + +//========================================================================== +// +// GetFileContainer +// +//========================================================================== + +int FileSystem::GetFileContainer (int lump) const +{ + if ((size_t)lump >= FileInfo.size()) + return -1; + return FileInfo[lump].rfnum; +} + +//========================================================================== +// +// GetFilesInFolder +// +// Gets all lumps within a single folder in the hierarchy. +// If 'atomic' is set, it treats folders as atomic, i.e. only the +// content of the last found resource file having the given folder name gets used. +// +//========================================================================== + +static int folderentrycmp(const void *a, const void *b) +{ + auto A = (FolderEntry*)a; + auto B = (FolderEntry*)b; + return strcmp(A->name, B->name); +} + +//========================================================================== +// +// +// +//========================================================================== + +unsigned FileSystem::GetFilesInFolder(const char *inpath, std::vector &result, bool atomic) const +{ + std::string path = inpath; + FixPathSeparator(&path.front()); + for (auto& c : path) c = tolower(c); + if (path.back() != '/') path += '/'; + result.clear(); + for (size_t i = 0; i < FileInfo.size(); i++) + { + if (strncmp(FileInfo[i].LongName, path.c_str(), path.length()) == 0) + { + // Only if it hasn't been replaced. + if ((unsigned)CheckNumForFullName(FileInfo[i].LongName) == i) + { + FolderEntry fe{ FileInfo[i].LongName, (uint32_t)i }; + result.push_back(fe); + } + } + } + if (result.size()) + { + int maxfile = -1; + if (atomic) + { + // Find the highest resource file having content in the given folder. + for (auto & entry : result) + { + int thisfile = GetFileContainer(entry.lumpnum); + if (thisfile > maxfile) maxfile = thisfile; + } + // Delete everything from older files. + for (int i = (int)result.size() - 1; i >= 0; i--) + { + if (GetFileContainer(result[i].lumpnum) != maxfile) result.erase(result.begin() + i); + } + } + qsort(result.data(), result.size(), sizeof(FolderEntry), folderentrycmp); + } + return (unsigned)result.size(); +} + +//========================================================================== +// +// W_ReadFile +// +// Loads the lump into the given buffer, which must be >= W_LumpLength(). +// +//========================================================================== + +void FileSystem::ReadFile (int lump, void *dest) +{ + auto lumpr = OpenFileReader (lump); + auto size = lumpr.GetLength (); + auto numread = lumpr.Read (dest, size); + + if (numread != size) + { + throw FileSystemException("W_ReadFile: only read %td of %td on '%s'\n", + numread, size, FileInfo[lump].LongName); + } +} + + +//========================================================================== +// +// ReadFile - variant 2 +// +// Loads the lump into a newly created buffer and returns it. +// +//========================================================================== + +FileData FileSystem::ReadFile (int lump) +{ + if ((unsigned)lump >= (unsigned)FileInfo.size()) + { + throw FileSystemException("ReadFile: %u >= NumEntries", lump); + } + return FileInfo[lump].resfile->Read(FileInfo[lump].resindex); +} + +//========================================================================== +// +// OpenFileReader +// +// uses a more abstract interface to allow for easier low level optimization later +// +//========================================================================== + + +FileReader FileSystem::OpenFileReader(int lump, int readertype, int readerflags) +{ + if ((unsigned)lump >= (unsigned)FileInfo.size()) + { + throw FileSystemException("OpenFileReader: %u >= NumEntries", lump); + } + + auto file = FileInfo[lump].resfile; + return file->GetEntryReader(FileInfo[lump].resindex, readertype, readerflags); +} + +FileReader FileSystem::OpenFileReader(const char* name) +{ + FileReader fr; + auto lump = CheckNumForFullName(name); + if (lump >= 0) fr = OpenFileReader(lump); + return fr; +} + +FileReader FileSystem::ReopenFileReader(const char* name, bool alwayscache) +{ + FileReader fr; + auto lump = CheckNumForFullName(name); + if (lump >= 0) fr = ReopenFileReader(lump, alwayscache); + return fr; +} + +//========================================================================== +// +// GetFileReader +// +// Retrieves the File reader object to access the given WAD +// Careful: This is only useful for real WAD files! +// +//========================================================================== + +FileReader *FileSystem::GetFileReader(int rfnum) +{ + if ((uint32_t)rfnum >= Files.size()) + { + return NULL; + } + + return Files[rfnum]->GetContainerReader(); +} + +//========================================================================== +// +// GetResourceFileName +// +// Returns the name of the given wad. +// +//========================================================================== + +const char *FileSystem::GetResourceFileName (int rfnum) const noexcept +{ + const char *name, *slash; + + if ((uint32_t)rfnum >= Files.size()) + { + return NULL; + } + + name = Files[rfnum]->GetFileName(); + slash = strrchr (name, '/'); + return (slash != nullptr && slash[1] != 0) ? slash+1 : name; +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetFirstEntry (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.size()) + { + return 0; + } + + return Files[rfnum]->GetFirstEntry(); +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetLastEntry (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.size()) + { + return 0; + } + + return Files[rfnum]->GetFirstEntry() + Files[rfnum]->EntryCount() - 1; +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetEntryCount (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.size()) + { + return 0; + } + + return Files[rfnum]->EntryCount(); +} + + +//========================================================================== +// +// GetResourceFileFullName +// +// Returns the name of the given wad, including any path +// +//========================================================================== + +const char *FileSystem::GetResourceFileFullName (int rfnum) const noexcept +{ + if ((unsigned int)rfnum >= Files.size()) + { + return nullptr; + } + + return Files[rfnum]->GetFileName(); +} + + +//========================================================================== +// +// Clones an existing resource with different properties +// +//========================================================================== + +bool FileSystem::CreatePathlessCopy(const char *name, int id, int /*flags*/) +{ + std::string name2 = name, type2, path; + + // The old code said 'filename' and ignored the path, this looked like a bug. + FixPathSeparator(&name2.front()); + auto lump = FindFile(name2.c_str()); + if (lump < 0) return false; // Does not exist. + + auto oldlump = FileInfo[lump]; + auto slash = strrchr(oldlump.LongName, '/'); + + if (slash == nullptr) + { + FileInfo[lump].flags = RESFF_FULLPATH; + return true; // already is pathless. + } + + + // just create a new reference to the original data with a different name. + oldlump.LongName = slash + 1; + oldlump.resourceId = id; + oldlump.flags = RESFF_FULLPATH; + FileInfo.push_back(oldlump); + return true; +} + +//========================================================================== +// +// PrintLastError +// +//========================================================================== + +#ifdef _WIN32 +//#define WIN32_LEAN_AND_MEAN +//#include + +extern "C" { +__declspec(dllimport) unsigned long __stdcall FormatMessageA( + unsigned long dwFlags, + const void *lpSource, + unsigned long dwMessageId, + unsigned long dwLanguageId, + char **lpBuffer, + unsigned long nSize, + va_list *Arguments + ); +__declspec(dllimport) void * __stdcall LocalFree (void *); +__declspec(dllimport) unsigned long __stdcall GetLastError (); +} + +static void PrintLastError (FileSystemMessageFunc Printf) +{ + char *lpMsgBuf; + FormatMessageA(0x1300 /*FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS*/, + NULL, + GetLastError(), + 1 << 10 /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, // Default language + &lpMsgBuf, + 0, + NULL + ); + Printf (FSMessageLevel::Error, " %s\n", lpMsgBuf); + // Free the buffer. + LocalFree( lpMsgBuf ); +} +#else +static void PrintLastError (FileSystemMessageFunc Printf) +{ + Printf(FSMessageLevel::Error, " %s\n", strerror(errno)); +} +#endif + + +} diff --git a/src/common/filesystem/source/fs_findfile.cpp b/src/common/filesystem/source/fs_findfile.cpp new file mode 100644 index 00000000000..e3d515ab160 --- /dev/null +++ b/src/common/filesystem/source/fs_findfile.cpp @@ -0,0 +1,427 @@ +/* +** findfile.cpp +** Wrapper around the native directory scanning APIs +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2020 Christoph Oelckers +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "fs_findfile.h" +#include +#include +#include + +#ifndef _WIN32 + +#include +#include +#ifdef __FreeBSD__ +#include +#endif +#include +#include +#include + +#endif + +namespace FileSys { + +enum +{ + ZPATH_MAX = 260 +}; + +#ifndef _WIN32 + + +#else + + +enum +{ + FA_RDONLY = 1, + FA_HIDDEN = 2, + FA_SYSTEM = 4, + FA_DIREC = 16, + FA_ARCH = 32, +}; + +#endif + + +#ifndef _WIN32 + +struct findstate_t +{ + std::string path; + struct dirent** namelist; + int current; + int count; +}; + +static const char* FS_FindName(findstate_t* fileinfo) +{ + return (fileinfo->namelist[fileinfo->current]->d_name); +} + +enum +{ + FA_RDONLY = 1, + FA_HIDDEN = 2, + FA_SYSTEM = 4, + FA_DIREC = 8, + FA_ARCH = 16, +}; + + +static const char *pattern; + +static int matchfile(const struct dirent *ent) +{ + return fnmatch(pattern, ent->d_name, FNM_NOESCAPE) == 0; +} + +static void *FS_FindFirst(const char *const filespec, findstate_t *const fileinfo) +{ + const char* dir; + + const char *const slash = strrchr(filespec, '/'); + + if (slash) + { + pattern = slash + 1; + fileinfo->path = std::string(filespec, 0, slash - filespec + 1); + dir = fileinfo->path.c_str(); + } + else + { + pattern = filespec; + dir = "."; + } + + fileinfo->current = 0; + fileinfo->count = scandir(dir, &fileinfo->namelist, matchfile, alphasort); + + if (fileinfo->count > 0) + { + return fileinfo; + } + + return (void *)-1; +} + +static int FS_FindNext(void *const handle, findstate_t *const fileinfo) +{ + findstate_t *const state = static_cast(handle); + + if (state->current < fileinfo->count) + { + return ++state->current < fileinfo->count ? 0 : -1; + } + + return -1; +} + +static int FS_FindClose(void *const handle) +{ + findstate_t *const state = static_cast(handle); + + if (handle != (void *)-1 && state->count > 0) + { + for (int i = 0; i < state->count; ++i) + { + free(state->namelist[i]); + } + + free(state->namelist); + state->namelist = nullptr; + state->count = 0; + } + + return 0; +} + +static int FS_FindAttr(findstate_t *const fileinfo) +{ + dirent *const ent = fileinfo->namelist[fileinfo->current]; + const std::string path = fileinfo->path + ent->d_name; + bool isdir; + + if (FS_DirEntryExists(path.c_str(), &isdir)) + { + return isdir ? FA_DIREC : 0; + } + + return 0; +} + +std::string FS_FullPath(const char* directory) +{ + char fullpath[PATH_MAX]; + + if (realpath(directory, fullpath) != nullptr) + return fullpath; + + return directory; +} + +static size_t FS_GetFileSize(findstate_t* handle, const char* pathname) +{ + struct stat info; + bool res = stat(pathname, &info) == 0; + if (!res || (info.st_mode & S_IFDIR)) return 0; + return (size_t)info.st_size; +} + + +#else + +#include +#include + +std::wstring toWide(const char* str) +{ + int len = (int)strlen(str); + std::wstring wide; + if (len > 0) + { + int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, nullptr, 0); + wide.resize(size_needed); + MultiByteToWideChar(CP_UTF8, 0, str, len, &wide.front(), size_needed); + } + return wide; +} + +static std::string toUtf8(const wchar_t* str) +{ + auto len = wcslen(str); + std::string utf8; + if (len > 0) + { + int size_needed = WideCharToMultiByte(CP_UTF8, 0, str, (int)len, nullptr, 0, nullptr, nullptr); + utf8.resize(size_needed); + WideCharToMultiByte(CP_UTF8, 0, str, (int)len, &utf8.front(), size_needed, nullptr, nullptr); + } + return utf8; +} + +struct findstate_t +{ + struct FileTime + { + uint32_t lo, hi; + }; + // Mirror WIN32_FIND_DATAW in . We cannot pull in the Windows header here as it would pollute all consumers' symbol space. + struct WinData + { + uint32_t Attribs; + FileTime Times[3]; + uint32_t Size[2]; + uint32_t Reserved[2]; + wchar_t Name[ZPATH_MAX]; + wchar_t AltName[14]; + }; + WinData FindData; + std::string UTF8Name; +}; + + +static int FS_FindAttr(findstate_t* fileinfo) +{ + return fileinfo->FindData.Attribs; +} + +//========================================================================== +// +// FS_FindFirst +// +// Start a pattern matching sequence. +// +//========================================================================== + + +static void *FS_FindFirst(const char *filespec, findstate_t *fileinfo) +{ + static_assert(sizeof(WIN32_FIND_DATAW) == sizeof(fileinfo->FindData), "FindData size mismatch"); + return FindFirstFileW(toWide(filespec).c_str(), (LPWIN32_FIND_DATAW)&fileinfo->FindData); +} + +//========================================================================== +// +// FS_FindNext +// +// Return the next file in a pattern matching sequence. +// +//========================================================================== + +static int FS_FindNext(void *handle, findstate_t *fileinfo) +{ + return FindNextFileW((HANDLE)handle, (LPWIN32_FIND_DATAW)&fileinfo->FindData) == 0; +} + +//========================================================================== +// +// FS_FindClose +// +// Finish a pattern matching sequence. +// +//========================================================================== + +static int FS_FindClose(void *handle) +{ + return FindClose((HANDLE)handle); +} + +//========================================================================== +// +// FS_FindName +// +// Returns the name for an entry +// +//========================================================================== + +static const char *FS_FindName(findstate_t *fileinfo) +{ + fileinfo->UTF8Name = toUtf8(fileinfo->FindData.Name); + return fileinfo->UTF8Name.c_str(); +} + +std::string FS_FullPath(const char* directory) +{ + auto wdirectory = _wfullpath(nullptr, toWide(directory).c_str(), _MAX_PATH); + std::string sdirectory = toUtf8(wdirectory); + free((void*)wdirectory); + for (auto& c : sdirectory) if (c == '\\') c = '/'; + return sdirectory; +} + +static size_t FS_GetFileSize(findstate_t* handle, const char* pathname) +{ + return handle->FindData.Size[1] + ((uint64_t)handle->FindData.Size[0] << 32); +} + +#endif + + +//========================================================================== +// +// ScanDirectory +// +//========================================================================== + +static bool DoScanDirectory(FileList& list, const char* dirpath, const char* match, const char* relpath, bool nosubdir, bool readhidden) +{ + findstate_t find; + + std::string dirpathn = dirpath; + FixPathSeparator(&dirpathn.front()); + if (dirpathn[dirpathn.length() - 1] != '/') dirpathn += '/'; + + std::string dirmatch = dirpathn; + dirmatch += match; + + auto handle = FS_FindFirst(dirmatch.c_str(), &find); + if (handle == ((void*)(-1))) return false; + FileListEntry fl; + do + { + auto attr = FS_FindAttr(&find); + if (!readhidden && (attr & FA_HIDDEN)) + { + // Skip hidden files and directories. (Prevents SVN/git bookkeeping info from being included.) + continue; + } + auto fn = FS_FindName(&find); + + if (attr & FA_DIREC) + { + if (fn[0] == '.' && + (fn[1] == '\0' || + (fn[1] == '.' && fn[2] == '\0'))) + { + // Do not record . and .. directories. + continue; + } + } + + fl.FileName = fn; + fl.FilePath = dirpathn + fn; + fl.FilePathRel = relpath; + if (fl.FilePathRel.length() > 0) fl.FilePathRel += '/'; + fl.FilePathRel += fn; + fl.isDirectory = !!(attr & FA_DIREC); + fl.isReadonly = !!(attr & FA_RDONLY); + fl.isHidden = !!(attr & FA_HIDDEN); + fl.isSystem = !!(attr & FA_SYSTEM); + fl.Length = FS_GetFileSize(&find, fl.FilePath.c_str()); + list.push_back(fl); + if (!nosubdir && (attr & FA_DIREC)) + { + DoScanDirectory(list, fl.FilePath.c_str(), match, fl.FilePathRel.c_str(), false, readhidden); + fl.Length = 0; + } + } while (FS_FindNext(handle, &find) == 0); + FS_FindClose(handle); + return true; +} + + +bool ScanDirectory(std::vector& list, const char* dirpath, const char* match, bool nosubdir, bool readhidden) +{ + return DoScanDirectory(list, dirpath, match, "", nosubdir, readhidden); +} + +//========================================================================== +// +// DirEntryExists +// +// Returns true if the given path exists, be it a directory or a file. +// +//========================================================================== + +bool FS_DirEntryExists(const char* pathname, bool* isdir) +{ + if (isdir) *isdir = false; + if (pathname == NULL || *pathname == 0) + return false; + +#ifndef _WIN32 + struct stat info; + bool res = stat(pathname, &info) == 0; +#else + // Windows must use the wide version of stat to preserve non-standard paths. + auto wstr = toWide(pathname); + struct _stat64 info; + bool res = _wstat64(wstr.c_str(), &info) == 0; +#endif + if (isdir) *isdir = !!(info.st_mode & S_IFDIR); + return res; +} + +} diff --git a/src/common/filesystem/source/fs_stringpool.cpp b/src/common/filesystem/source/fs_stringpool.cpp new file mode 100644 index 00000000000..316078cae96 --- /dev/null +++ b/src/common/filesystem/source/fs_stringpool.cpp @@ -0,0 +1,131 @@ +/* +** stringpool.cpp +** allocate static strings from larger blocks +** +**--------------------------------------------------------------------------- +** Copyright 2010 Randy Heit +** Copyright 2023 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include "fs_stringpool.h" + +namespace FileSys { + +struct StringPool::Block +{ + Block *NextBlock; + void *Limit; // End of this block + void *Avail; // Start of free space in this block + void *alignme; // align to 16 bytes. + + void *Alloc(size_t size); +}; + +//========================================================================== +// +// StringPool Destructor +// +//========================================================================== + +StringPool::~StringPool() +{ + for (Block *next, *block = TopBlock; block != nullptr; block = next) + { + next = block->NextBlock; + free(block); + } + TopBlock = nullptr; +} + +//========================================================================== +// +// StringPool :: Alloc +// +//========================================================================== + +void *StringPool::Block::Alloc(size_t size) +{ + if ((char *)Avail + size > Limit) + { + return nullptr; + } + void *res = Avail; + Avail = ((char *)Avail + size); + return res; +} + +StringPool::Block *StringPool::AddBlock(size_t size) +{ + size += sizeof(Block); // Account for header size + + // Allocate a new block + if (size < BlockSize) + { + size = BlockSize; + } + auto mem = (Block *)malloc(size); + if (mem == nullptr) + { + + } + mem->Limit = (uint8_t *)mem + size; + mem->Avail = &mem[1]; + mem->NextBlock = TopBlock; + TopBlock = mem; + return mem; +} + +void *StringPool::Alloc(size_t size) +{ + Block *block; + + size = (size + 7) & ~7; + for (block = TopBlock; block != nullptr; block = block->NextBlock) + { + void *res = block->Alloc(size); + if (res != nullptr) + { + return res; + } + } + block = AddBlock(size); + return block->Alloc(size); +} + +const char* StringPool::Strdup(const char* str) +{ + char* p = (char*)Alloc(strlen(str) + 1); + strcpy(p, str); + return p; +} + +} diff --git a/src/common/filesystem/source/fs_stringpool.h b/src/common/filesystem/source/fs_stringpool.h new file mode 100644 index 00000000000..f327d14a3e0 --- /dev/null +++ b/src/common/filesystem/source/fs_stringpool.h @@ -0,0 +1,28 @@ +#pragma once + +namespace FileSys { +// Storage for all the static strings the file system must hold. +class StringPool +{ + // do not allow externally defining this. + friend class FileSystem; + friend class FResourceFile; +private: + StringPool(bool _shared, size_t blocksize = 10*1024) : TopBlock(nullptr), BlockSize(blocksize), shared(_shared) {} +public: + ~StringPool(); + const char* Strdup(const char*); + void* Alloc(size_t size); + +protected: + struct Block; + + Block *AddBlock(size_t size); + + Block *TopBlock; + size_t BlockSize; +public: + bool shared; +}; + +} diff --git a/src/common/filesystem/source/md5.hpp b/src/common/filesystem/source/md5.hpp new file mode 100644 index 00000000000..1ecde05d41f --- /dev/null +++ b/src/common/filesystem/source/md5.hpp @@ -0,0 +1,416 @@ +#pragma once +/* + md5.hpp is a reformulation of the md5.h and md5.c code from + http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to + function as a component of a header only library. This conversion was done by + Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The + changes are released under the same license as the original (listed below) +*/ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ + /* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + + + /* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +#include +#include + +namespace FileSys { + /// Provides MD5 hashing functionality + namespace md5 { + + typedef unsigned char md5_byte_t; /* 8-bit byte */ + typedef unsigned int md5_word_t; /* 32-bit word */ + + /* Define the state of the MD5 Algorithm. */ + typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ + } md5_state_t; + + /* Initialize the algorithm. */ + inline void md5_init(md5_state_t* pms); + + /* Append a string to the message. */ + inline void md5_append(md5_state_t* pms, md5_byte_t const* data, size_t nbytes); + + /* Finish the message and return the digest. */ + inline void md5_finish(md5_state_t* pms, md5_byte_t digest[16]); + +#undef ZSW_MD5_BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define ZSW_MD5_BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define ZSW_MD5_BYTE_ORDER 0 +#endif + +#define ZSW_MD5_T_MASK ((md5_word_t)~0) +#define ZSW_MD5_T1 /* 0xd76aa478 */ (ZSW_MD5_T_MASK ^ 0x28955b87) +#define ZSW_MD5_T2 /* 0xe8c7b756 */ (ZSW_MD5_T_MASK ^ 0x173848a9) +#define ZSW_MD5_T3 0x242070db +#define ZSW_MD5_T4 /* 0xc1bdceee */ (ZSW_MD5_T_MASK ^ 0x3e423111) +#define ZSW_MD5_T5 /* 0xf57c0faf */ (ZSW_MD5_T_MASK ^ 0x0a83f050) +#define ZSW_MD5_T6 0x4787c62a +#define ZSW_MD5_T7 /* 0xa8304613 */ (ZSW_MD5_T_MASK ^ 0x57cfb9ec) +#define ZSW_MD5_T8 /* 0xfd469501 */ (ZSW_MD5_T_MASK ^ 0x02b96afe) +#define ZSW_MD5_T9 0x698098d8 +#define ZSW_MD5_T10 /* 0x8b44f7af */ (ZSW_MD5_T_MASK ^ 0x74bb0850) +#define ZSW_MD5_T11 /* 0xffff5bb1 */ (ZSW_MD5_T_MASK ^ 0x0000a44e) +#define ZSW_MD5_T12 /* 0x895cd7be */ (ZSW_MD5_T_MASK ^ 0x76a32841) +#define ZSW_MD5_T13 0x6b901122 +#define ZSW_MD5_T14 /* 0xfd987193 */ (ZSW_MD5_T_MASK ^ 0x02678e6c) +#define ZSW_MD5_T15 /* 0xa679438e */ (ZSW_MD5_T_MASK ^ 0x5986bc71) +#define ZSW_MD5_T16 0x49b40821 +#define ZSW_MD5_T17 /* 0xf61e2562 */ (ZSW_MD5_T_MASK ^ 0x09e1da9d) +#define ZSW_MD5_T18 /* 0xc040b340 */ (ZSW_MD5_T_MASK ^ 0x3fbf4cbf) +#define ZSW_MD5_T19 0x265e5a51 +#define ZSW_MD5_T20 /* 0xe9b6c7aa */ (ZSW_MD5_T_MASK ^ 0x16493855) +#define ZSW_MD5_T21 /* 0xd62f105d */ (ZSW_MD5_T_MASK ^ 0x29d0efa2) +#define ZSW_MD5_T22 0x02441453 +#define ZSW_MD5_T23 /* 0xd8a1e681 */ (ZSW_MD5_T_MASK ^ 0x275e197e) +#define ZSW_MD5_T24 /* 0xe7d3fbc8 */ (ZSW_MD5_T_MASK ^ 0x182c0437) +#define ZSW_MD5_T25 0x21e1cde6 +#define ZSW_MD5_T26 /* 0xc33707d6 */ (ZSW_MD5_T_MASK ^ 0x3cc8f829) +#define ZSW_MD5_T27 /* 0xf4d50d87 */ (ZSW_MD5_T_MASK ^ 0x0b2af278) +#define ZSW_MD5_T28 0x455a14ed +#define ZSW_MD5_T29 /* 0xa9e3e905 */ (ZSW_MD5_T_MASK ^ 0x561c16fa) +#define ZSW_MD5_T30 /* 0xfcefa3f8 */ (ZSW_MD5_T_MASK ^ 0x03105c07) +#define ZSW_MD5_T31 0x676f02d9 +#define ZSW_MD5_T32 /* 0x8d2a4c8a */ (ZSW_MD5_T_MASK ^ 0x72d5b375) +#define ZSW_MD5_T33 /* 0xfffa3942 */ (ZSW_MD5_T_MASK ^ 0x0005c6bd) +#define ZSW_MD5_T34 /* 0x8771f681 */ (ZSW_MD5_T_MASK ^ 0x788e097e) +#define ZSW_MD5_T35 0x6d9d6122 +#define ZSW_MD5_T36 /* 0xfde5380c */ (ZSW_MD5_T_MASK ^ 0x021ac7f3) +#define ZSW_MD5_T37 /* 0xa4beea44 */ (ZSW_MD5_T_MASK ^ 0x5b4115bb) +#define ZSW_MD5_T38 0x4bdecfa9 +#define ZSW_MD5_T39 /* 0xf6bb4b60 */ (ZSW_MD5_T_MASK ^ 0x0944b49f) +#define ZSW_MD5_T40 /* 0xbebfbc70 */ (ZSW_MD5_T_MASK ^ 0x4140438f) +#define ZSW_MD5_T41 0x289b7ec6 +#define ZSW_MD5_T42 /* 0xeaa127fa */ (ZSW_MD5_T_MASK ^ 0x155ed805) +#define ZSW_MD5_T43 /* 0xd4ef3085 */ (ZSW_MD5_T_MASK ^ 0x2b10cf7a) +#define ZSW_MD5_T44 0x04881d05 +#define ZSW_MD5_T45 /* 0xd9d4d039 */ (ZSW_MD5_T_MASK ^ 0x262b2fc6) +#define ZSW_MD5_T46 /* 0xe6db99e5 */ (ZSW_MD5_T_MASK ^ 0x1924661a) +#define ZSW_MD5_T47 0x1fa27cf8 +#define ZSW_MD5_T48 /* 0xc4ac5665 */ (ZSW_MD5_T_MASK ^ 0x3b53a99a) +#define ZSW_MD5_T49 /* 0xf4292244 */ (ZSW_MD5_T_MASK ^ 0x0bd6ddbb) +#define ZSW_MD5_T50 0x432aff97 +#define ZSW_MD5_T51 /* 0xab9423a7 */ (ZSW_MD5_T_MASK ^ 0x546bdc58) +#define ZSW_MD5_T52 /* 0xfc93a039 */ (ZSW_MD5_T_MASK ^ 0x036c5fc6) +#define ZSW_MD5_T53 0x655b59c3 +#define ZSW_MD5_T54 /* 0x8f0ccc92 */ (ZSW_MD5_T_MASK ^ 0x70f3336d) +#define ZSW_MD5_T55 /* 0xffeff47d */ (ZSW_MD5_T_MASK ^ 0x00100b82) +#define ZSW_MD5_T56 /* 0x85845dd1 */ (ZSW_MD5_T_MASK ^ 0x7a7ba22e) +#define ZSW_MD5_T57 0x6fa87e4f +#define ZSW_MD5_T58 /* 0xfe2ce6e0 */ (ZSW_MD5_T_MASK ^ 0x01d3191f) +#define ZSW_MD5_T59 /* 0xa3014314 */ (ZSW_MD5_T_MASK ^ 0x5cfebceb) +#define ZSW_MD5_T60 0x4e0811a1 +#define ZSW_MD5_T61 /* 0xf7537e82 */ (ZSW_MD5_T_MASK ^ 0x08ac817d) +#define ZSW_MD5_T62 /* 0xbd3af235 */ (ZSW_MD5_T_MASK ^ 0x42c50dca) +#define ZSW_MD5_T63 0x2ad7d2bb +#define ZSW_MD5_T64 /* 0xeb86d391 */ (ZSW_MD5_T_MASK ^ 0x14792c6e) + + static void md5_process(md5_state_t* pms, md5_byte_t const* data /*[64]*/) { + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if ZSW_MD5_BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + md5_word_t const* X; +#endif + + { +#if ZSW_MD5_BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static int const w = 1; + + if (*((md5_byte_t const*)&w)) /* dynamic little-endian */ +#endif +#if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (md5_byte_t const*)0) & 3)) { + /* data are properly aligned */ + X = (md5_word_t const*)data; + } + else { + /* not aligned */ + std::memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if ZSW_MD5_BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if ZSW_MD5_BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t* xp = data; + int i; + +# if ZSW_MD5_BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ZSW_MD5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define ZSW_MD5_F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + ZSW_MD5_F(b,c,d) + X[k] + Ti;\ + a = ZSW_MD5_ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, ZSW_MD5_T1); + SET(d, a, b, c, 1, 12, ZSW_MD5_T2); + SET(c, d, a, b, 2, 17, ZSW_MD5_T3); + SET(b, c, d, a, 3, 22, ZSW_MD5_T4); + SET(a, b, c, d, 4, 7, ZSW_MD5_T5); + SET(d, a, b, c, 5, 12, ZSW_MD5_T6); + SET(c, d, a, b, 6, 17, ZSW_MD5_T7); + SET(b, c, d, a, 7, 22, ZSW_MD5_T8); + SET(a, b, c, d, 8, 7, ZSW_MD5_T9); + SET(d, a, b, c, 9, 12, ZSW_MD5_T10); + SET(c, d, a, b, 10, 17, ZSW_MD5_T11); + SET(b, c, d, a, 11, 22, ZSW_MD5_T12); + SET(a, b, c, d, 12, 7, ZSW_MD5_T13); + SET(d, a, b, c, 13, 12, ZSW_MD5_T14); + SET(c, d, a, b, 14, 17, ZSW_MD5_T15); + SET(b, c, d, a, 15, 22, ZSW_MD5_T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define ZSW_MD5_G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + ZSW_MD5_G(b,c,d) + X[k] + Ti;\ + a = ZSW_MD5_ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, ZSW_MD5_T17); + SET(d, a, b, c, 6, 9, ZSW_MD5_T18); + SET(c, d, a, b, 11, 14, ZSW_MD5_T19); + SET(b, c, d, a, 0, 20, ZSW_MD5_T20); + SET(a, b, c, d, 5, 5, ZSW_MD5_T21); + SET(d, a, b, c, 10, 9, ZSW_MD5_T22); + SET(c, d, a, b, 15, 14, ZSW_MD5_T23); + SET(b, c, d, a, 4, 20, ZSW_MD5_T24); + SET(a, b, c, d, 9, 5, ZSW_MD5_T25); + SET(d, a, b, c, 14, 9, ZSW_MD5_T26); + SET(c, d, a, b, 3, 14, ZSW_MD5_T27); + SET(b, c, d, a, 8, 20, ZSW_MD5_T28); + SET(a, b, c, d, 13, 5, ZSW_MD5_T29); + SET(d, a, b, c, 2, 9, ZSW_MD5_T30); + SET(c, d, a, b, 7, 14, ZSW_MD5_T31); + SET(b, c, d, a, 12, 20, ZSW_MD5_T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define ZSW_MD5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + ZSW_MD5_H(b,c,d) + X[k] + Ti;\ + a = ZSW_MD5_ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, ZSW_MD5_T33); + SET(d, a, b, c, 8, 11, ZSW_MD5_T34); + SET(c, d, a, b, 11, 16, ZSW_MD5_T35); + SET(b, c, d, a, 14, 23, ZSW_MD5_T36); + SET(a, b, c, d, 1, 4, ZSW_MD5_T37); + SET(d, a, b, c, 4, 11, ZSW_MD5_T38); + SET(c, d, a, b, 7, 16, ZSW_MD5_T39); + SET(b, c, d, a, 10, 23, ZSW_MD5_T40); + SET(a, b, c, d, 13, 4, ZSW_MD5_T41); + SET(d, a, b, c, 0, 11, ZSW_MD5_T42); + SET(c, d, a, b, 3, 16, ZSW_MD5_T43); + SET(b, c, d, a, 6, 23, ZSW_MD5_T44); + SET(a, b, c, d, 9, 4, ZSW_MD5_T45); + SET(d, a, b, c, 12, 11, ZSW_MD5_T46); + SET(c, d, a, b, 15, 16, ZSW_MD5_T47); + SET(b, c, d, a, 2, 23, ZSW_MD5_T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define ZSW_MD5_I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + ZSW_MD5_I(b,c,d) + X[k] + Ti;\ + a = ZSW_MD5_ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, ZSW_MD5_T49); + SET(d, a, b, c, 7, 10, ZSW_MD5_T50); + SET(c, d, a, b, 14, 15, ZSW_MD5_T51); + SET(b, c, d, a, 5, 21, ZSW_MD5_T52); + SET(a, b, c, d, 12, 6, ZSW_MD5_T53); + SET(d, a, b, c, 3, 10, ZSW_MD5_T54); + SET(c, d, a, b, 10, 15, ZSW_MD5_T55); + SET(b, c, d, a, 1, 21, ZSW_MD5_T56); + SET(a, b, c, d, 8, 6, ZSW_MD5_T57); + SET(d, a, b, c, 15, 10, ZSW_MD5_T58); + SET(c, d, a, b, 6, 15, ZSW_MD5_T59); + SET(b, c, d, a, 13, 21, ZSW_MD5_T60); + SET(a, b, c, d, 4, 6, ZSW_MD5_T61); + SET(d, a, b, c, 11, 10, ZSW_MD5_T62); + SET(c, d, a, b, 2, 15, ZSW_MD5_T63); + SET(b, c, d, a, 9, 21, ZSW_MD5_T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; + } + + void md5_init(md5_state_t* pms) { + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ ZSW_MD5_T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ ZSW_MD5_T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; + } + + void md5_append(md5_state_t* pms, md5_byte_t const* data, size_t nbytes) { + md5_byte_t const* p = data; + size_t left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += (md5_word_t)(nbytes >> 29); + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : static_cast(nbytes)); + + std::memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + std::memcpy(pms->buf, p, left); + } + + void md5_finish(md5_state_t* pms, md5_byte_t digest[16]) { + static md5_byte_t const pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); + } + + + } // md5 +} // fs_private + diff --git a/src/common/filesystem/source/resourcefile.cpp b/src/common/filesystem/source/resourcefile.cpp new file mode 100644 index 00000000000..81e2b785082 --- /dev/null +++ b/src/common/filesystem/source/resourcefile.cpp @@ -0,0 +1,733 @@ +/* +** resourcefile.cpp +** +** Base classes for resource file management +** +**--------------------------------------------------------------------------- +** Copyright 2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include +#include "resourcefile.h" +#include "md5.hpp" +#include "fs_stringpool.h" +#include "files_internal.h" +#include "unicode.h" +#include "fs_findfile.h" +#include "fs_decompress.h" +#include "wildcards.hpp" + +namespace FileSys { + +// this is for restricting shared file readers to the main thread. +thread_local bool mainThread; +void SetMainThread() +{ + // only set the global flag on the first thread calling this. + static bool done = false; + if (!done) + { + mainThread = done = true; + } +} + +std::string ExtractBaseName(const char* path, bool include_extension) +{ + const char* src, * dot; + + src = path + strlen(path) - 1; + + if (src >= path) + { + // back up until a / or the start + while (src != path && src[-1] != '/' && src[-1] != '\\') // check both on all systems for consistent behavior with archives. + src--; + + if (!include_extension && (dot = strrchr(src, '.'))) + { + return std::string(src, dot - src); + } + else + { + return std::string(src); + } + } + return std::string(); +} + +void strReplace(std::string& str, const char *from, const char* to) +{ + if (*from == 0) + return; + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) + { + str.replace(start_pos, strlen(from), to); + start_pos += strlen(to); + } +} + +//========================================================================== +// +// Checks for embedded resource files +// +//========================================================================== + +bool FResourceFile::IsFileInFolder(const char* const resPath) +{ + // Checks a special case when was put in + // directory inside + + const auto dirName = ExtractBaseName(FileName); + const auto fileName = ExtractBaseName(resPath, true); + const std::string filePath = dirName + '/' + fileName; + + return 0 == stricmp(filePath.c_str(), resPath); +} + +void FResourceFile::CheckEmbedded(uint32_t entry, LumpFilterInfo* lfi) +{ + // Checks for embedded archives + auto FullName = Entries[entry].FileName; + const char *c = strstr(FullName, ".wad"); // fixme: Use lfi for this. + if (c && strlen(c) == 4 && (!strchr(FullName, '/') || IsFileInFolder(FullName))) + { + Entries[entry].Flags |= RESFF_EMBEDDED; + } + else if (lfi) for (auto& fstr : lfi->embeddings) + { + if (!stricmp(FullName, fstr.c_str())) + { + Entries[entry].Flags |= RESFF_EMBEDDED; + } + } +} + + +//========================================================================== +// +// Opens a resource file +// +//========================================================================== + +typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); + +FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckHog(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckMvl(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckWHRes(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckLump(const char *filename,FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckDir(const char *filename, bool nosub, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); + +static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckSSI, CheckHog, CheckMvl, CheckWHRes, CheckLump }; + +static int nulPrintf(FSMessageLevel msg, const char* fmt, ...) +{ + return 0; +} + +FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + if (Printf == nullptr) Printf = nulPrintf; + for(auto func : funcs) + { + if (containeronly && func == CheckLump) break; + FResourceFile *resfile = func(filename, file, filter, Printf, sp); + if (resfile != NULL) return resfile; + } + return NULL; +} + +FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + return DoOpenResourceFile(filename, file, containeronly, filter, Printf, sp); +} + + +FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + FileReader file; + if (!file.OpenFile(filename)) return nullptr; + return DoOpenResourceFile(filename, file, containeronly, filter, Printf, sp); +} + +FResourceFile *FResourceFile::OpenDirectory(const char *filename, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + if (Printf == nullptr) Printf = nulPrintf; + return CheckDir(filename, false, filter, Printf, sp); +} + +//========================================================================== +// +// Resource file base class +// +//========================================================================== + +FResourceFile::FResourceFile(const char *filename, StringPool* sp) +{ + stringpool = sp ? sp : new StringPool(false); + FileName = stringpool->Strdup(filename); +} + +FResourceFile::FResourceFile(const char *filename, FileReader &r, StringPool* sp) + : FResourceFile(filename,sp) +{ + Reader = std::move(r); +} + +FResourceFile::~FResourceFile() +{ + if (!stringpool->shared) delete stringpool; +} + +//========================================================================== +// +// this is just for completeness. For non-Zips only an uncompressed lump can +// be returned. +// +//========================================================================== + +FCompressedBuffer FResourceFile::GetRawData(uint32_t entry) +{ + size_t LumpSize = entry << NumLumps ? Entries[entry].Length : 0; + FCompressedBuffer cbuf = { LumpSize, LumpSize, METHOD_STORED, 0, 0, LumpSize == 0? nullptr : new char[LumpSize] }; + if (LumpSize > 0) + { + auto fr = GetEntryReader(entry, READER_SHARED, 0); + size_t read = fr.Read(cbuf.mBuffer, LumpSize); + if (read < LumpSize) + { + delete cbuf.mBuffer; + cbuf.mBuffer = nullptr; + LumpSize = cbuf.mCompressedSize = cbuf.mSize = 0; + } + } + if (LumpSize > 0) + cbuf.mCRC32 = crc32(0, (uint8_t*)cbuf.mBuffer, LumpSize); + return cbuf; +} + + +//========================================================================== +// +// normalize the visible file name in the system +// to lowercase canonical precomposed Unicode. +// +//========================================================================== + +const char* FResourceFile::NormalizeFileName(const char* fn, int fallbackcp) +{ + if (!fn || !*fn) return ""; + auto norm = tolower_normalize(fn); + if (!norm) + { + if (fallbackcp == 437) + { + std::vector buffer; + ibm437_to_utf8(fn, buffer); + norm = tolower_normalize(buffer.data()); + } + // maybe handle other codepages + else + { + // if the filename is not valid UTF-8, nuke all bytes larger than 0x80 so that we still got something semi-usable + std::string ffn = fn; + for (auto& c : ffn) + { + if (c & 0x80) c = '@'; + } + norm = tolower_normalize(&ffn.front()); + } + } + FixPathSeparator(norm); + auto pooled = stringpool->Strdup(norm); + free(norm); + return pooled; + +} + +//========================================================================== +// +// allocate the Entries array +// this also uses the string pool to reduce maintenance +// +//========================================================================== + +FResourceEntry* FResourceFile::AllocateEntries(int count) +{ + NumLumps = count; + Entries = (FResourceEntry*)stringpool->Alloc(count * sizeof(FResourceEntry)); + memset(Entries, 0, count * sizeof(FResourceEntry)); + return Entries; +} + + +//--------------------------------------------------- +int entrycmp(const void* a, const void* b) +{ + FResourceEntry* rec1 = (FResourceEntry*)a; + FResourceEntry* rec2 = (FResourceEntry*)b; + // we are comparing lowercase UTF-8 here + return strcmp(rec1->FileName, rec2->FileName); +} + +//========================================================================== +// +// FResourceFile :: GenerateHash +// +// Generates a hash identifier for use in file identification. +// Potential uses are mod-wide compatibility settings or localization add-ons. +// This only hashes the directory but not the actual content +// +//========================================================================== + +void FResourceFile::GenerateHash() +{ + // hash the directory after sorting + using namespace FileSys::md5; + + auto n = snprintf(Hash, 48, "%08X-%04X-", (unsigned)Reader.GetLength(), NumLumps); + + md5_state_t state; + md5_init(&state); + + uint8_t digest[16]; + for(uint32_t i = 0; i < NumLumps; i++) + { + auto name = getName(i); + auto size = Length(i); + if (name == nullptr) + continue; + md5_append(&state, (const uint8_t*)name, (unsigned)strlen(name) + 1); + md5_append(&state, (const uint8_t*)&size, sizeof(size)); + } + md5_finish(&state, digest); + for (auto c : digest) + { + n += snprintf(Hash + n, 3, "%02X", c); + } +} + +//========================================================================== +// +// FResourceFile :: PostProcessArchive +// +// Sorts files by name. +// For files named "filter//*": Using the same filter rules as config +// autoloading, move them to the end and rename them without the "filter/" +// prefix. Filtered files that don't match are deleted. +// +//========================================================================== + +void FResourceFile::PostProcessArchive(LumpFilterInfo *filter) +{ + // only do this for archive types which contain full file names. All others are assumed to be pre-sorted. + if (NumLumps == 0 || !(Entries[0].Flags & RESFF_FULLPATH)) return; + + // First eliminate all unwanted files + if (filter) + { + for (uint32_t i = 0; i < NumLumps; i++) + { + std::string name = Entries[i].FileName; + for (auto& pattern : filter->blockednames) + { + if (wildcards::match(name, pattern)) + { + Entries[i].FileName = ""; + continue; + } + } + } + } + + // Entries in archives are sorted alphabetically. + qsort(Entries, NumLumps, sizeof(Entries[0]), entrycmp); + if (!filter) return; + FindCommonFolder(filter); + + // Filter out lumps using the same names as the Autoload.* sections + // in the ini file. We reduce the maximum lump concidered after + // each one so that we don't risk refiltering already filtered lumps. + uint32_t max = NumLumps; + + for (auto& LumpFilter : filter->gameTypeFilter) + { + ptrdiff_t len; + ptrdiff_t lastpos = -1; + std::string file; + while (size_t(len = LumpFilter.find_first_of('.', lastpos + 1)) != LumpFilter.npos) + { + max -= FilterLumps(std::string(LumpFilter, 0, len), max); + lastpos = len; + } + max -= FilterLumps(LumpFilter, max); + } + + JunkLeftoverFilters(max); + + for (uint32_t i = 0; i < NumLumps; i++) + { + CheckEmbedded(i, filter); + } + +} + +//========================================================================== +// +// FResourceFile :: FindCommonFolder +// +// Checks if all content is in a common folder that can be stripped out. +// +//========================================================================== + +void FResourceFile::FindCommonFolder(LumpFilterInfo* filter) +{ + std::string name0, name1; + bool foundspeciallump = false; + bool foundprefix = false; + + // try to find a path prefix. + for (uint32_t i = 0; i < NumLumps; i++) + { + if (*Entries[i].FileName == 0) continue; + std::string name = Entries[i].FileName; + + // first eliminate files we do not want to have. + // Some, like MacOS resource forks and executables are eliminated unconditionally, but the calling code can alsp pass a list of invalid content. + if (name.find("filter/") == 0) + return; // 'filter' is a reserved name of the file system. If this appears in the root we got no common folder, and 'filter' cannot be it. + + if (!foundprefix) + { + // check for special names, if one of these gets found this must be treated as a normal zip. + bool isspecial = name.find("/") == std::string::npos || + (filter && std::find(filter->reservedFolders.begin(), filter->reservedFolders.end(), name) != filter->reservedFolders.end()); + if (isspecial) break; + name0 = std::string(name, 0, name.rfind("/") + 1); + name1 = std::string(name, 0, name.find("/") + 1); + foundprefix = true; + } + + if (name.find(name0) != 0) + { + if (!name1.empty()) + { + name0 = name1; + if (name.find(name0) != 0) + { + name0 = ""; + } + } + if (name0.empty()) + break; + } + if (!foundspeciallump && filter) + { + // at least one of the more common definition lumps must be present. + for (auto& p : filter->requiredPrefixes) + { + if (name.find(name0 + p) == 0 || name.rfind(p) == size_t(name.length() - p.length())) + { + foundspeciallump = true; + break; + } + } + } + } + // If it ran through the list without finding anything it should not attempt any path remapping. + if (!foundspeciallump || name0.empty()) return; + + size_t pathlen = name0.length(); + for (uint32_t i = 0; i < NumLumps; i++) + { + if (Entries[i].FileName[0] == 0) continue; + Entries[i].FileName += pathlen; + + } +} + +//========================================================================== +// +// FResourceFile :: FilterLumps +// +// Finds any lumps between [0,) that match the pattern +// "filter//*" and moves them to the end of the lump list. +// Returns the number of lumps moved. +// +//========================================================================== + +int FResourceFile::FilterLumps(const std::string& filtername, uint32_t max) +{ + uint32_t start, end; + + if (filtername.empty()) + { + return 0; + } + std::string filter = "filter/" + filtername + '/'; + + bool found = FindPrefixRange(filter.c_str(), max, start, end); + + if (found) + { + + // Remove filter prefix from every name + for (uint32_t i = start; i < end; ++i) + { + assert(strnicmp(Entries[i].FileName, filter.c_str(), filter.length()) == 0); + Entries[i].FileName += filter.length(); + } + + // Move filtered lumps to the end of the lump list. + size_t count = (end - start); + auto from = Entries + start; + auto to = Entries + NumLumps - count; + assert (to >= from); + + if (from != to) + { + // Copy filtered lumps to a temporary buffer. + auto filteredlumps = new FResourceEntry[count]; + memcpy(filteredlumps, from, count * sizeof(*Entries)); + + // Shift lumps left to make room for the filtered ones at the end. + memmove(from, from + count, (NumLumps - end) * sizeof(*Entries)); + + // Copy temporary buffer to newly freed space. + memcpy(to, filteredlumps, count * sizeof(*Entries)); + + delete[] filteredlumps; + } + } + return end - start; +} + +//========================================================================== +// +// FResourceFile :: JunkLeftoverFilters +// +// Deletes any lumps beginning with "filter/" that were not matched. +// +//========================================================================== + +void FResourceFile::JunkLeftoverFilters(uint32_t max) +{ + uint32_t start, end; + if (FindPrefixRange("filter/", max, start, end)) + { + // Since the resource lumps may contain non-POD data besides the + // full name, we "delete" them by erasing their names so they + // can't be found. + for (uint32_t i = start; i < end; i++) + { + Entries[i].FileName = ""; + } + } +} + +//========================================================================== +// +// FResourceFile :: FindPrefixRange +// +// Finds a range of lumps that start with the prefix string. is left +// indicating the first matching one. is left at one plus the last +// matching one. +// +//========================================================================== + +bool FResourceFile::FindPrefixRange(const char* filter, uint32_t maxlump, uint32_t &start, uint32_t &end) +{ + uint32_t min, max, mid, inside; + int cmp = 0; + + end = start = 0; + + // Pretend that our range starts at 1 instead of 0 so that we can avoid + // unsigned overflow if the range starts at the first lump. + auto lumps = &Entries[-1]; + + // Binary search to find any match at all. + mid = min = 1, max = maxlump; + while (min <= max) + { + mid = min + (max - min) / 2; + auto lump = &lumps[mid]; + cmp = strnicmp(lump->FileName, filter, strlen(filter)); + if (cmp == 0) + break; + else if (cmp < 0) + min = mid + 1; + else + max = mid - 1; + } + if (max < min) + { // matched nothing + return false; + } + + // Binary search to find first match. + inside = mid; + min = 1, max = mid; + while (min <= max) + { + mid = min + (max - min) / 2; + auto lump = &lumps[mid]; + cmp = strnicmp(lump->FileName, filter, strlen(filter)); + // Go left on matches and right on misses. + if (cmp == 0) + max = mid - 1; + else + min = mid + 1; + } + start = mid + (cmp != 0) - 1; + + // Binary search to find last match. + min = inside, max = maxlump; + while (min <= max) + { + mid = min + (max - min) / 2; + auto lump = &lumps[mid]; + cmp = strnicmp(lump->FileName, filter, strlen(filter)); + // Go right on matches and left on misses. + if (cmp == 0) + min = mid + 1; + else + max = mid - 1; + } + end = mid - (cmp != 0); + return true; +} + +//========================================================================== +// +// Finds a lump by a given name. Used for savegames +// +//========================================================================== + +int FResourceFile::FindEntry(const char *name) +{ + auto norm_fn = tolower_normalize(name); + for (unsigned i = 0; i < NumLumps; i++) + { + if (!strcmp(norm_fn, getName(i))) + { + free(norm_fn); + return i; + } + } + free(norm_fn); + return -1; +} + + +//========================================================================== +// +// Caches a lump's content and increases the reference counter +// +//========================================================================== + +FileReader FResourceFile::GetEntryReader(uint32_t entry, int readertype, int readerflags) +{ + FileReader fr; + if (entry < NumLumps) + { + if (Entries[entry].Flags & RESFF_NEEDFILESTART) + { + SetEntryAddress(entry); + } + if (!(Entries[entry].Flags & RESFF_COMPRESSED)) + { + auto buf = Reader.GetBuffer(); + // if this is backed by a memory buffer, create a new reader directly referencing it. + if (buf != nullptr) + { + fr.OpenMemory(buf + Entries[entry].Position, Entries[entry].Length); + } + else + { + if (readertype == READER_SHARED && !mainThread) + readertype = READER_NEW; + if (readertype == READER_SHARED) + { + fr.OpenFilePart(Reader, Entries[entry].Position, Entries[entry].Length); + } + else if (readertype == READER_NEW) + { + fr.OpenFile(FileName, Entries[entry].Position, Entries[entry].Length); + } + else if (readertype == READER_CACHED) + { + Reader.Seek(Entries[entry].Position, FileReader::SeekSet); + auto data = Reader.Read(Entries[entry].Length); + fr.OpenMemoryArray(data); + } + } + } + else + { + FileReader fri; + if (readertype == READER_NEW || !mainThread) fri.OpenFile(FileName, Entries[entry].Position, Entries[entry].CompressedSize); + else fri.OpenFilePart(Reader, Entries[entry].Position, Entries[entry].CompressedSize); + int flags = DCF_TRANSFEROWNER | DCF_EXCEPTIONS; + if (readertype == READER_CACHED) flags |= DCF_CACHED; + else if (readerflags & READERFLAG_SEEKABLE) flags |= DCF_SEEKABLE; + OpenDecompressor(fr, fri, Entries[entry].Length, Entries[entry].Method, flags); + } + } + return fr; +} + +FileData FResourceFile::Read(uint32_t entry) +{ + if (!(Entries[entry].Flags & RESFF_COMPRESSED) && Reader.isOpen()) + { + auto buf = Reader.GetBuffer(); + // if this is backed by a memory buffer, we can just return a reference to the backing store. + if (buf != nullptr) + { + return FileData(buf + Entries[entry].Position, Entries[entry].Length, false); + } + } + + auto fr = GetEntryReader(entry, READER_SHARED, 0); + return fr.Read(entry < NumLumps ? Entries[entry].Length : 0); +} + + + +} diff --git a/src/common/filesystem/source/unicode.cpp b/src/common/filesystem/source/unicode.cpp new file mode 100644 index 00000000000..3d148270ae7 --- /dev/null +++ b/src/common/filesystem/source/unicode.cpp @@ -0,0 +1,161 @@ +/* +** unicode.cpp +** handling for conversion / comparison of filenames +** +**--------------------------------------------------------------------------- +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "unicode.h" +#include "utf8proc.h" + +namespace FileSys { +//========================================================================== +// +// +// +//========================================================================== + +static void utf8_encode(int32_t codepoint, std::vector& buffer) +{ + if (codepoint < 0 || codepoint > 0x10FFFF || (codepoint >= 0xD800 && codepoint < 0xDFFF)) + { + codepoint = 0xFFFD; + } + uint8_t buf[4]; + auto size = utf8proc_encode_char(codepoint, buf); + for(int i = 0; i < size; i++) + buffer.push_back(buf[i]); +} + + +//========================================================================== +// +// convert UTF16 to UTF8 (needed for 7z) +// +//========================================================================== + +void utf16_to_utf8(const unsigned short* in, std::vector& buffer) +{ + buffer.clear(); + if (!*in) return; + + while (int char1 = *in++) + { + if (char1 >= 0xD800 && char1 <= 0xDBFF) + { + int char2 = *in; + + if (char2 >= 0xDC00 && char2 <= 0xDFFF) + { + in++; + char1 -= 0xD800; + char2 -= 0xDC00; + char1 <<= 10; + char1 += char2; + char1 += 0x010000; + } + else + { + // invalid code point - replace with placeholder + char1 = 0xFFFD; + } + } + else if (char1 >= 0xDC00 && char1 <= 0xDFFF) + { + // invalid code point - replace with placeholder + char1 = 0xFFFD; + } + utf8_encode(char1, buffer); + } + buffer.push_back(0); +} + +//========================================================================== +// +// convert UTF16 to UTF8 (needed for Zip) +// +//========================================================================== + +void ibm437_to_utf8(const char* in, std::vector& buffer) +{ + static const uint16_t ibm437map[] = { + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0, + }; + + buffer.clear(); + if (!*in) return; + + while (int char1 = (uint8_t)*in++) + { + if (char1 >= 0x80) char1 = ibm437map[char1 - 0x80]; + utf8_encode(char1, buffer); + } + buffer.push_back(0); +} + +//========================================================================== +// +// create a normalized lowercase version of a string. +// +//========================================================================== + +char *tolower_normalize(const char *str) +{ + utf8proc_uint8_t *retval; + utf8proc_map((const uint8_t*)str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE | UTF8PROC_CASEFOLD)); + return (char*)retval; +} + +//========================================================================== +// +// validates the string for proper UTF-8 +// +//========================================================================== + +bool unicode_validate(const char* str) +{ + while (*str != 0) + { + int cp; + auto result = utf8proc_iterate((const uint8_t*)str, -1, &cp); + if (result < 0) return false; + } + return true; +} + + +} diff --git a/src/common/filesystem/source/unicode.h b/src/common/filesystem/source/unicode.h new file mode 100644 index 00000000000..8783dbc718e --- /dev/null +++ b/src/common/filesystem/source/unicode.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include +namespace FileSys { + +void utf16_to_utf8(const unsigned short* in, std::vector& buffer); +void ibm437_to_utf8(const char* in, std::vector& buffer); +char *tolower_normalize(const char *str); +bool unicode_validate(const char* str); + +} diff --git a/src/common/filesystem/source/wildcards.hpp b/src/common/filesystem/source/wildcards.hpp new file mode 100644 index 00000000000..9b8e4eac6b7 --- /dev/null +++ b/src/common/filesystem/source/wildcards.hpp @@ -0,0 +1,1833 @@ +// THIS FILE HAS BEEN GENERATED AUTOMATICALLY. DO NOT EDIT DIRECTLY. +// Generated: 2019-03-08 09:59:35.958950200 +// Copyright Tomas Zeman 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef WILDCARDS_HPP +#define WILDCARDS_HPP +#define WILDCARDS_VERSION_MAJOR 1 +#define WILDCARDS_VERSION_MINOR 5 +#define WILDCARDS_VERSION_PATCH 0 +#ifndef WILDCARDS_CARDS_HPP +#define WILDCARDS_CARDS_HPP +#include +namespace wildcards +{ +template +struct cards +{ +constexpr cards(T a, T s, T e) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{false}, +alt_enabled{false} +{ +} +constexpr cards(T a, T s, T e, T so, T sc, T sn, T ao, T ac, T ar) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{true}, +set_open{std::move(so)}, +set_close{std::move(sc)}, +set_not{std::move(sn)}, +alt_enabled{true}, +alt_open{std::move(ao)}, +alt_close{std::move(ac)}, +alt_or{std::move(ar)} +{ +} +T anything; +T single; +T escape; +bool set_enabled; +T set_open; +T set_close; +T set_not; +bool alt_enabled; +T alt_open; +T alt_close; +T alt_or; +}; +enum class cards_type +{ +standard, +extended +}; +template <> +struct cards +{ +constexpr cards(cards_type type = cards_type::extended) +: set_enabled{type == cards_type::extended}, alt_enabled{type == cards_type::extended} +{ +} +constexpr cards(char a, char s, char e) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{false}, +alt_enabled{false} +{ +} +constexpr cards(char a, char s, char e, char so, char sc, char sn, char ao, char ac, char ar) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{true}, +set_open{std::move(so)}, +set_close{std::move(sc)}, +set_not{std::move(sn)}, +alt_enabled{true}, +alt_open{std::move(ao)}, +alt_close{std::move(ac)}, +alt_or{std::move(ar)} +{ +} +char anything{'*'}; +char single{'?'}; +char escape{'\\'}; +bool set_enabled{true}; +char set_open{'['}; +char set_close{']'}; +char set_not{'!'}; +bool alt_enabled{true}; +char alt_open{'('}; +char alt_close{')'}; +char alt_or{'|'}; +}; +template <> +struct cards +{ +constexpr cards(cards_type type = cards_type::extended) +: set_enabled{type == cards_type::extended}, alt_enabled{type == cards_type::extended} +{ +} +constexpr cards(char16_t a, char16_t s, char16_t e) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{false}, +alt_enabled{false} +{ +} +constexpr cards(char16_t a, char16_t s, char16_t e, char16_t so, char16_t sc, char16_t sn, +char16_t ao, char16_t ac, char16_t ar) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{true}, +set_open{std::move(so)}, +set_close{std::move(sc)}, +set_not{std::move(sn)}, +alt_enabled{true}, +alt_open{std::move(ao)}, +alt_close{std::move(ac)}, +alt_or{std::move(ar)} +{ +} +char16_t anything{u'*'}; +char16_t single{u'?'}; +char16_t escape{u'\\'}; +bool set_enabled{true}; +char16_t set_open{u'['}; +char16_t set_close{u']'}; +char16_t set_not{u'!'}; +bool alt_enabled{true}; +char16_t alt_open{u'('}; +char16_t alt_close{u')'}; +char16_t alt_or{u'|'}; +}; +template <> +struct cards +{ +constexpr cards(cards_type type = cards_type::extended) +: set_enabled{type == cards_type::extended}, alt_enabled{type == cards_type::extended} +{ +} +constexpr cards(char32_t a, char32_t s, char32_t e) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{false}, +alt_enabled{false} +{ +} +constexpr cards(char32_t a, char32_t s, char32_t e, char32_t so, char32_t sc, char32_t sn, +char32_t ao, char32_t ac, char32_t ar) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{true}, +set_open{std::move(so)}, +set_close{std::move(sc)}, +set_not{std::move(sn)}, +alt_enabled{true}, +alt_open{std::move(ao)}, +alt_close{std::move(ac)}, +alt_or{std::move(ar)} +{ +} +char32_t anything{U'*'}; +char32_t single{U'?'}; +char32_t escape{U'\\'}; +bool set_enabled{true}; +char32_t set_open{U'['}; +char32_t set_close{U']'}; +char32_t set_not{U'!'}; +bool alt_enabled{true}; +char32_t alt_open{U'('}; +char32_t alt_close{U')'}; +char32_t alt_or{U'|'}; +}; +template <> +struct cards +{ +constexpr cards(cards_type type = cards_type::extended) +: set_enabled{type == cards_type::extended}, alt_enabled{type == cards_type::extended} +{ +} +constexpr cards(wchar_t a, wchar_t s, wchar_t e) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{false}, +alt_enabled{false} +{ +} +constexpr cards(wchar_t a, wchar_t s, wchar_t e, wchar_t so, wchar_t sc, wchar_t sn, wchar_t ao, +wchar_t ac, wchar_t ar) +: anything{std::move(a)}, +single{std::move(s)}, +escape{std::move(e)}, +set_enabled{true}, +set_open{std::move(so)}, +set_close{std::move(sc)}, +set_not{std::move(sn)}, +alt_enabled{true}, +alt_open{std::move(ao)}, +alt_close{std::move(ac)}, +alt_or{std::move(ar)} +{ +} +wchar_t anything{L'*'}; +wchar_t single{L'?'}; +wchar_t escape{L'\\'}; +bool set_enabled{true}; +wchar_t set_open{L'['}; +wchar_t set_close{L']'}; +wchar_t set_not{L'!'}; +bool alt_enabled{true}; +wchar_t alt_open{L'('}; +wchar_t alt_close{L')'}; +wchar_t alt_or{L'|'}; +}; +template +constexpr cards make_cards(T&& a, T&& s, T&& e) +{ +return {std::forward(a), std::forward(s), std::forward(e)}; +} +template +constexpr cards make_cards(T&& a, T&& s, T&& e, T&& so, T&& sc, T&& sn, T&& ao, T&& ac, T&& ar) +{ +return {std::forward(a), std::forward(s), std::forward(e), +std::forward(so), std::forward(sc), std::forward(sn), +std::forward(ao), std::forward(ac), std::forward(ar)}; +} +} +#endif +#ifndef WILDCARDS_MATCH_HPP +#define WILDCARDS_MATCH_HPP +#include +#include +#include +#ifndef CONFIG_HPP +#define CONFIG_HPP +#ifndef QUICKCPPLIB_HAS_FEATURE_H +#define QUICKCPPLIB_HAS_FEATURE_H +#if __cplusplus >= 201103L +#if !defined(__cpp_alias_templates) +#define __cpp_alias_templates 190000 +#endif +#if !defined(__cpp_attributes) +#define __cpp_attributes 190000 +#endif +#if !defined(__cpp_constexpr) +#if __cplusplus >= 201402L +#define __cpp_constexpr 201304 +#else +#define __cpp_constexpr 190000 +#endif +#endif +#if !defined(__cpp_decltype) +#define __cpp_decltype 190000 +#endif +#if !defined(__cpp_delegating_constructors) +#define __cpp_delegating_constructors 190000 +#endif +#if !defined(__cpp_explicit_conversion) +#define __cpp_explicit_conversion 190000 +#endif +#if !defined(__cpp_inheriting_constructors) +#define __cpp_inheriting_constructors 190000 +#endif +#if !defined(__cpp_initializer_lists) +#define __cpp_initializer_lists 190000 +#endif +#if !defined(__cpp_lambdas) +#define __cpp_lambdas 190000 +#endif +#if !defined(__cpp_nsdmi) +#define __cpp_nsdmi 190000 +#endif +#if !defined(__cpp_range_based_for) +#define __cpp_range_based_for 190000 +#endif +#if !defined(__cpp_raw_strings) +#define __cpp_raw_strings 190000 +#endif +#if !defined(__cpp_ref_qualifiers) +#define __cpp_ref_qualifiers 190000 +#endif +#if !defined(__cpp_rvalue_references) +#define __cpp_rvalue_references 190000 +#endif +#if !defined(__cpp_static_assert) +#define __cpp_static_assert 190000 +#endif +#if !defined(__cpp_unicode_characters) +#define __cpp_unicode_characters 190000 +#endif +#if !defined(__cpp_unicode_literals) +#define __cpp_unicode_literals 190000 +#endif +#if !defined(__cpp_user_defined_literals) +#define __cpp_user_defined_literals 190000 +#endif +#if !defined(__cpp_variadic_templates) +#define __cpp_variadic_templates 190000 +#endif +#endif +#if __cplusplus >= 201402L +#if !defined(__cpp_aggregate_nsdmi) +#define __cpp_aggregate_nsdmi 190000 +#endif +#if !defined(__cpp_binary_literals) +#define __cpp_binary_literals 190000 +#endif +#if !defined(__cpp_decltype_auto) +#define __cpp_decltype_auto 190000 +#endif +#if !defined(__cpp_generic_lambdas) +#define __cpp_generic_lambdas 190000 +#endif +#if !defined(__cpp_init_captures) +#define __cpp_init_captures 190000 +#endif +#if !defined(__cpp_return_type_deduction) +#define __cpp_return_type_deduction 190000 +#endif +#if !defined(__cpp_sized_deallocation) +#define __cpp_sized_deallocation 190000 +#endif +#if !defined(__cpp_variable_templates) +#define __cpp_variable_templates 190000 +#endif +#endif +#if defined(_MSC_VER) && !defined(__clang__) +#if !defined(__cpp_exceptions) && defined(_CPPUNWIND) +#define __cpp_exceptions 190000 +#endif +#if !defined(__cpp_rtti) && defined(_CPPRTTI) +#define __cpp_rtti 190000 +#endif +#if !defined(__cpp_alias_templates) && _MSC_VER >= 1800 +#define __cpp_alias_templates 190000 +#endif +#if !defined(__cpp_attributes) +#define __cpp_attributes 190000 +#endif +#if !defined(__cpp_constexpr) && _MSC_FULL_VER >= 190023506 +#define __cpp_constexpr 190000 +#endif +#if !defined(__cpp_decltype) && _MSC_VER >= 1600 +#define __cpp_decltype 190000 +#endif +#if !defined(__cpp_delegating_constructors) && _MSC_VER >= 1800 +#define __cpp_delegating_constructors 190000 +#endif +#if !defined(__cpp_explicit_conversion) && _MSC_VER >= 1800 +#define __cpp_explicit_conversion 190000 +#endif +#if !defined(__cpp_inheriting_constructors) && _MSC_VER >= 1900 +#define __cpp_inheriting_constructors 190000 +#endif +#if !defined(__cpp_initializer_lists) && _MSC_VER >= 1900 +#define __cpp_initializer_lists 190000 +#endif +#if !defined(__cpp_lambdas) && _MSC_VER >= 1600 +#define __cpp_lambdas 190000 +#endif +#if !defined(__cpp_nsdmi) && _MSC_VER >= 1900 +#define __cpp_nsdmi 190000 +#endif +#if !defined(__cpp_range_based_for) && _MSC_VER >= 1700 +#define __cpp_range_based_for 190000 +#endif +#if !defined(__cpp_raw_strings) && _MSC_VER >= 1800 +#define __cpp_raw_strings 190000 +#endif +#if !defined(__cpp_ref_qualifiers) && _MSC_VER >= 1900 +#define __cpp_ref_qualifiers 190000 +#endif +#if !defined(__cpp_rvalue_references) && _MSC_VER >= 1600 +#define __cpp_rvalue_references 190000 +#endif +#if !defined(__cpp_static_assert) && _MSC_VER >= 1600 +#define __cpp_static_assert 190000 +#endif +#if !defined(__cpp_user_defined_literals) && _MSC_VER >= 1900 +#define __cpp_user_defined_literals 190000 +#endif +#if !defined(__cpp_variadic_templates) && _MSC_VER >= 1800 +#define __cpp_variadic_templates 190000 +#endif +#if !defined(__cpp_binary_literals) && _MSC_VER >= 1900 +#define __cpp_binary_literals 190000 +#endif +#if !defined(__cpp_decltype_auto) && _MSC_VER >= 1900 +#define __cpp_decltype_auto 190000 +#endif +#if !defined(__cpp_generic_lambdas) && _MSC_VER >= 1900 +#define __cpp_generic_lambdas 190000 +#endif +#if !defined(__cpp_init_captures) && _MSC_VER >= 1900 +#define __cpp_init_captures 190000 +#endif +#if !defined(__cpp_return_type_deduction) && _MSC_VER >= 1900 +#define __cpp_return_type_deduction 190000 +#endif +#if !defined(__cpp_sized_deallocation) && _MSC_VER >= 1900 +#define __cpp_sized_deallocation 190000 +#endif +#if !defined(__cpp_variable_templates) && _MSC_FULL_VER >= 190023506 +#define __cpp_variable_templates 190000 +#endif +#endif +#if(defined(__GNUC__) && !defined(__clang__)) +#define QUICKCPPLIB_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if !defined(__cpp_exceptions) && defined(__EXCEPTIONS) +#define __cpp_exceptions 190000 +#endif +#if !defined(__cpp_rtti) && defined(__GXX_RTTI) +#define __cpp_rtti 190000 +#endif +#if defined(__GXX_EXPERIMENTAL_CXX0X__) +#if !defined(__cpp_alias_templates) && (QUICKCPPLIB_GCC >= 40700) +#define __cpp_alias_templates 190000 +#endif +#if !defined(__cpp_attributes) && (QUICKCPPLIB_GCC >= 40800) +#define __cpp_attributes 190000 +#endif +#if !defined(__cpp_constexpr) && (QUICKCPPLIB_GCC >= 40600) +#define __cpp_constexpr 190000 +#endif +#if !defined(__cpp_decltype) && (QUICKCPPLIB_GCC >= 40300) +#define __cpp_decltype 190000 +#endif +#if !defined(__cpp_delegating_constructors) && (QUICKCPPLIB_GCC >= 40700) +#define __cpp_delegating_constructors 190000 +#endif +#if !defined(__cpp_explicit_conversion) && (QUICKCPPLIB_GCC >= 40500) +#define __cpp_explicit_conversion 190000 +#endif +#if !defined(__cpp_inheriting_constructors) && (QUICKCPPLIB_GCC >= 40800) +#define __cpp_inheriting_constructors 190000 +#endif +#if !defined(__cpp_initializer_lists) && (QUICKCPPLIB_GCC >= 40800) +#define __cpp_initializer_lists 190000 +#endif +#if !defined(__cpp_lambdas) && (QUICKCPPLIB_GCC >= 40500) +#define __cpp_lambdas 190000 +#endif +#if !defined(__cpp_nsdmi) && (QUICKCPPLIB_GCC >= 40700) +#define __cpp_nsdmi 190000 +#endif +#if !defined(__cpp_range_based_for) && (QUICKCPPLIB_GCC >= 40600) +#define __cpp_range_based_for 190000 +#endif +#if !defined(__cpp_raw_strings) && (QUICKCPPLIB_GCC >= 40500) +#define __cpp_raw_strings 190000 +#endif +#if !defined(__cpp_ref_qualifiers) && (QUICKCPPLIB_GCC >= 40801) +#define __cpp_ref_qualifiers 190000 +#endif +#if !defined(__cpp_rvalue_references) && defined(__cpp_rvalue_reference) +#define __cpp_rvalue_references __cpp_rvalue_reference +#endif +#if !defined(__cpp_static_assert) && (QUICKCPPLIB_GCC >= 40300) +#define __cpp_static_assert 190000 +#endif +#if !defined(__cpp_unicode_characters) && (QUICKCPPLIB_GCC >= 40500) +#define __cpp_unicode_characters 190000 +#endif +#if !defined(__cpp_unicode_literals) && (QUICKCPPLIB_GCC >= 40500) +#define __cpp_unicode_literals 190000 +#endif +#if !defined(__cpp_user_defined_literals) && (QUICKCPPLIB_GCC >= 40700) +#define __cpp_user_defined_literals 190000 +#endif +#if !defined(__cpp_variadic_templates) && (QUICKCPPLIB_GCC >= 40400) +#define __cpp_variadic_templates 190000 +#endif +#endif +#endif +#if defined(__clang__) +#define QUICKCPPLIB_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#if !defined(__cpp_exceptions) && (defined(__EXCEPTIONS) || defined(_CPPUNWIND)) +#define __cpp_exceptions 190000 +#endif +#if !defined(__cpp_rtti) && (defined(__GXX_RTTI) || defined(_CPPRTTI)) +#define __cpp_rtti 190000 +#endif +#if defined(__GXX_EXPERIMENTAL_CXX0X__) +#if !defined(__cpp_alias_templates) && (QUICKCPPLIB_CLANG >= 30000) +#define __cpp_alias_templates 190000 +#endif +#if !defined(__cpp_attributes) && (QUICKCPPLIB_CLANG >= 30300) +#define __cpp_attributes 190000 +#endif +#if !defined(__cpp_constexpr) && (QUICKCPPLIB_CLANG >= 30100) +#define __cpp_constexpr 190000 +#endif +#if !defined(__cpp_decltype) && (QUICKCPPLIB_CLANG >= 20900) +#define __cpp_decltype 190000 +#endif +#if !defined(__cpp_delegating_constructors) && (QUICKCPPLIB_CLANG >= 30000) +#define __cpp_delegating_constructors 190000 +#endif +#if !defined(__cpp_explicit_conversion) && (QUICKCPPLIB_CLANG >= 30000) +#define __cpp_explicit_conversion 190000 +#endif +#if !defined(__cpp_inheriting_constructors) && (QUICKCPPLIB_CLANG >= 30300) +#define __cpp_inheriting_constructors 190000 +#endif +#if !defined(__cpp_initializer_lists) && (QUICKCPPLIB_CLANG >= 30100) +#define __cpp_initializer_lists 190000 +#endif +#if !defined(__cpp_lambdas) && (QUICKCPPLIB_CLANG >= 30100) +#define __cpp_lambdas 190000 +#endif +#if !defined(__cpp_nsdmi) && (QUICKCPPLIB_CLANG >= 30000) +#define __cpp_nsdmi 190000 +#endif +#if !defined(__cpp_range_based_for) && (QUICKCPPLIB_CLANG >= 30000) +#define __cpp_range_based_for 190000 +#endif +#if !defined(__cpp_raw_strings) && defined(__cpp_raw_string_literals) +#define __cpp_raw_strings __cpp_raw_string_literals +#endif +#if !defined(__cpp_raw_strings) && (QUICKCPPLIB_CLANG >= 30000) +#define __cpp_raw_strings 190000 +#endif +#if !defined(__cpp_ref_qualifiers) && (QUICKCPPLIB_CLANG >= 20900) +#define __cpp_ref_qualifiers 190000 +#endif +#if !defined(__cpp_rvalue_references) && defined(__cpp_rvalue_reference) +#define __cpp_rvalue_references __cpp_rvalue_reference +#endif +#if !defined(__cpp_rvalue_references) && (QUICKCPPLIB_CLANG >= 20900) +#define __cpp_rvalue_references 190000 +#endif +#if !defined(__cpp_static_assert) && (QUICKCPPLIB_CLANG >= 20900) +#define __cpp_static_assert 190000 +#endif +#if !defined(__cpp_unicode_characters) && (QUICKCPPLIB_CLANG >= 30000) +#define __cpp_unicode_characters 190000 +#endif +#if !defined(__cpp_unicode_literals) && (QUICKCPPLIB_CLANG >= 30000) +#define __cpp_unicode_literals 190000 +#endif +#if !defined(__cpp_user_defined_literals) && defined(__cpp_user_literals) +#define __cpp_user_defined_literals __cpp_user_literals +#endif +#if !defined(__cpp_user_defined_literals) && (QUICKCPPLIB_CLANG >= 30100) +#define __cpp_user_defined_literals 190000 +#endif +#if !defined(__cpp_variadic_templates) && (QUICKCPPLIB_CLANG >= 20900) +#define __cpp_variadic_templates 190000 +#endif +#endif +#endif +#endif +#define cfg_HAS_CONSTEXPR14 (__cpp_constexpr >= 201304) +#if cfg_HAS_CONSTEXPR14 +#define cfg_constexpr14 constexpr +#else +#define cfg_constexpr14 +#endif +#if cfg_HAS_CONSTEXPR14 && defined(__clang__) +#define cfg_HAS_FULL_FEATURED_CONSTEXPR14 1 +#else +#define cfg_HAS_FULL_FEATURED_CONSTEXPR14 1 +#endif +#endif +#ifndef CX_FUNCTIONAL_HPP +#define CX_FUNCTIONAL_HPP +#include +namespace cx +{ +template +struct less +{ +constexpr auto operator()(const T& lhs, const T& rhs) const -> decltype(lhs < rhs) +{ +return lhs < rhs; +} +}; +template <> +struct less +{ +template +constexpr auto operator()(T&& lhs, U&& rhs) const +-> decltype(std::forward(lhs) < std::forward(rhs)) +{ +return std::forward(lhs) < std::forward(rhs); +} +}; +template +struct equal_to +{ +constexpr auto operator()(const T& lhs, const T& rhs) const -> decltype(lhs == rhs) +{ +return lhs == rhs; +} +}; +template <> +struct equal_to +{ +template +constexpr auto operator()(T&& lhs, U&& rhs) const +-> decltype(std::forward(lhs) == std::forward(rhs)) +{ +return std::forward(lhs) == std::forward(rhs); +} +}; +} +#endif +#ifndef CX_ITERATOR_HPP +#define CX_ITERATOR_HPP +#include +#include +namespace cx +{ +template +constexpr It next(It it) +{ +return it + 1; +} +template +constexpr It prev(It it) +{ +return it - 1; +} +template +constexpr auto size(const C& c) -> decltype(c.size()) +{ +return c.size(); +} +template +constexpr std::size_t size(const T (&)[N]) +{ +return N; +} +template +constexpr auto empty(const C& c) -> decltype(c.empty()) +{ +return c.empty(); +} +template +constexpr bool empty(const T (&)[N]) +{ +return false; +} +template +constexpr bool empty(std::initializer_list il) +{ +return il.size() == 0; +} +template +constexpr auto begin(const C& c) -> decltype(c.begin()) +{ +return c.begin(); +} +template +constexpr auto begin(C& c) -> decltype(c.begin()) +{ +return c.begin(); +} +template +constexpr T* begin(T (&array)[N]) +{ +return &array[0]; +} +template +constexpr const E* begin(std::initializer_list il) +{ +return il.begin(); +} +template +constexpr auto cbegin(const C& c) -> decltype(cx::begin(c)) +{ +return cx::begin(c); +} +template +constexpr auto end(const C& c) -> decltype(c.end()) +{ +return c.end(); +} +template +constexpr auto end(C& c) -> decltype(c.end()) +{ +return c.end(); +} +template +constexpr T* end(T (&array)[N]) +{ +return &array[N]; +} +template +constexpr const E* end(std::initializer_list il) +{ +return il.end(); +} +template +constexpr auto cend(const C& c) -> decltype(cx::end(c)) +{ +return cx::end(c); +} +} +#endif +#ifndef WILDCARDS_UTILITY_HPP +#define WILDCARDS_UTILITY_HPP +#include +#include +namespace wildcards +{ +template +struct const_iterator +{ +using type = typename std::remove_cv< +typename std::remove_reference()))>::type>::type; +}; +template +using const_iterator_t = typename const_iterator::type; +template +struct iterator +{ +using type = typename std::remove_cv< +typename std::remove_reference()))>::type>::type; +}; +template +using iterator_t = typename iterator::type; +template +struct iterated_item +{ +using type = typename std::remove_cv< +typename std::remove_reference())>::type>::type; +}; +template +using iterated_item_t = typename iterated_item::type; +template +struct container_item +{ +using type = typename std::remove_cv< +typename std::remove_reference()))>::type>::type; +}; +template +using container_item_t = typename container_item::type; +} +#endif +namespace wildcards +{ +template +struct full_match_result +{ +bool res; +SequenceIterator s, send, s1; +PatternIterator p, pend, p1; +constexpr operator bool() const +{ +return res; +} +}; +namespace detail +{ +template +struct match_result +{ +bool res; +SequenceIterator s; +PatternIterator p; +constexpr operator bool() const +{ +return res; +} +}; +template +constexpr match_result make_match_result(bool res, +SequenceIterator s, +PatternIterator p) +{ +return {std::move(res), std::move(s), std::move(p)}; +} +template +constexpr full_match_result make_full_match_result( +SequenceIterator s, SequenceIterator send, PatternIterator p, PatternIterator pend, +match_result mr) +{ +return {std::move(mr.res), std::move(s), std::move(send), std::move(mr.s), +std::move(p), std::move(pend), std::move(mr.p)}; +} +#if !cfg_HAS_FULL_FEATURED_CONSTEXPR14 +constexpr bool throw_invalid_argument(const char* what_arg) +{ +return what_arg == nullptr ? false : throw std::invalid_argument(what_arg); +} +template +constexpr T throw_invalid_argument(T t, const char* what_arg) +{ +return what_arg == nullptr ? t : throw std::invalid_argument(what_arg); +} +constexpr bool throw_logic_error(const char* what_arg) +{ +return what_arg == nullptr ? false : throw std::logic_error(what_arg); +} +template +constexpr T throw_logic_error(T t, const char* what_arg) +{ +return what_arg == nullptr ? t : throw std::logic_error(what_arg); +} +#endif +enum class is_set_state +{ +open, +not_or_first, +first, +next +}; +template +constexpr bool is_set( +PatternIterator p, PatternIterator pend, +const cards>& c = cards>(), +is_set_state state = is_set_state::open) +{ +#if cfg_HAS_CONSTEXPR14 +if (!c.set_enabled) +{ +return false; +} +while (p != pend) +{ +switch (state) +{ +case is_set_state::open: +if (*p != c.set_open) +{ +return false; +} +state = is_set_state::not_or_first; +break; +case is_set_state::not_or_first: +if (*p == c.set_not) +{ +state = is_set_state::first; +} +else +{ +state = is_set_state::next; +} +break; +case is_set_state::first: +state = is_set_state::next; +break; +case is_set_state::next: +if (*p == c.set_close) +{ +return true; +} +break; +default: +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::logic_error( +"The program execution should never end up here throwing this exception"); +#else +return throw_logic_error( +"The program execution should never end up here throwing this exception"); +#endif +} +p = cx::next(p); +} +return false; +#else +return c.set_enabled && p != pend && +(state == is_set_state::open +? *p == c.set_open && is_set(cx::next(p), pend, c, is_set_state::not_or_first) +: +state == is_set_state::not_or_first +? *p == c.set_not ? is_set(cx::next(p), pend, c, is_set_state::first) +: is_set(cx::next(p), pend, c, is_set_state::next) +: state == is_set_state::first +? is_set(cx::next(p), pend, c, is_set_state::next) +: state == is_set_state::next +? *p == c.set_close || +is_set(cx::next(p), pend, c, is_set_state::next) +: throw std::logic_error("The program execution should never end up " +"here throwing this exception")); +#endif +} +enum class set_end_state +{ +open, +not_or_first, +first, +next +}; +template +constexpr PatternIterator set_end( +PatternIterator p, PatternIterator pend, +const cards>& c = cards>(), +set_end_state state = set_end_state::open) +{ +#if cfg_HAS_CONSTEXPR14 +if (!c.set_enabled) +{ +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The use of sets is disabled"); +#else +return throw_invalid_argument(p, "The use of sets is disabled"); +#endif +} +while (p != pend) +{ +switch (state) +{ +case set_end_state::open: +if (*p != c.set_open) +{ +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The given pattern is not a valid set"); +#else +return throw_invalid_argument(p, "The given pattern is not a valid set"); +#endif +} +state = set_end_state::not_or_first; +break; +case set_end_state::not_or_first: +if (*p == c.set_not) +{ +state = set_end_state::first; +} +else +{ +state = set_end_state::next; +} +break; +case set_end_state::first: +state = set_end_state::next; +break; +case set_end_state::next: +if (*p == c.set_close) +{ +return cx::next(p); +} +break; +default: +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::logic_error( +"The program execution should never end up here throwing this exception"); +#else +return throw_logic_error( +p, "The program execution should never end up here throwing this exception"); +#endif +} +p = cx::next(p); +} +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The given pattern is not a valid set"); +#else +return throw_invalid_argument(p, "The given pattern is not a valid set"); +#endif +#else +return !c.set_enabled +? throw std::invalid_argument("The use of sets is disabled") +: p == pend +? throw std::invalid_argument("The given pattern is not a valid set") +: +state == set_end_state::open +? *p == c.set_open +? set_end(cx::next(p), pend, c, set_end_state::not_or_first) +: throw std::invalid_argument("The given pattern is not a valid set") +: +state == set_end_state::not_or_first +? *p == c.set_not ? set_end(cx::next(p), pend, c, set_end_state::first) +: set_end(cx::next(p), pend, c, set_end_state::next) +: state == set_end_state::first +? set_end(cx::next(p), pend, c, set_end_state::next) +: state == set_end_state::next +? *p == c.set_close +? cx::next(p) +: set_end(cx::next(p), pend, c, set_end_state::next) +: throw std::logic_error( +"The program execution should never end up " +"here throwing this exception"); +#endif +} +enum class match_set_state +{ +open, +not_or_first_in, +first_out, +next_in, +next_out +}; +template > +constexpr match_result match_set( +SequenceIterator s, SequenceIterator send, PatternIterator p, PatternIterator pend, +const cards>& c = cards>(), +const EqualTo& equal_to = EqualTo(), match_set_state state = match_set_state::open) +{ +#if cfg_HAS_CONSTEXPR14 +if (!c.set_enabled) +{ +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The use of sets is disabled"); +#else +return throw_invalid_argument(make_match_result(false, s, p), "The use of sets is disabled"); +#endif +} +while (p != pend) +{ +switch (state) +{ +case match_set_state::open: +if (*p != c.set_open) +{ +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The given pattern is not a valid set"); +#else +return throw_invalid_argument(make_match_result(false, s, p), +"The given pattern is not a valid set"); +#endif +} +state = match_set_state::not_or_first_in; +break; +case match_set_state::not_or_first_in: +if (*p == c.set_not) +{ +state = match_set_state::first_out; +} +else +{ +if (s == send) +{ +return make_match_result(false, s, p); +} +if (equal_to(*s, *p)) +{ +return make_match_result(true, s, p); +} +state = match_set_state::next_in; +} +break; +case match_set_state::first_out: +if (s == send || equal_to(*s, *p)) +{ +return make_match_result(false, s, p); +} +state = match_set_state::next_out; +break; +case match_set_state::next_in: +if (*p == c.set_close || s == send) +{ +return make_match_result(false, s, p); +} +if (equal_to(*s, *p)) +{ +return make_match_result(true, s, p); +} +break; +case match_set_state::next_out: +if (*p == c.set_close) +{ +return make_match_result(true, s, p); +} +if (s == send || equal_to(*s, *p)) +{ +return make_match_result(false, s, p); +} +break; +default: +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::logic_error( +"The program execution should never end up here throwing this exception"); +#else +return throw_logic_error( +make_match_result(false, s, p), +"The program execution should never end up here throwing this exception"); +#endif +} +p = cx::next(p); +} +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The given pattern is not a valid set"); +#else +return throw_invalid_argument(make_match_result(false, s, p), +"The given pattern is not a valid set"); +#endif +#else +return !c.set_enabled +? throw std::invalid_argument("The use of sets is disabled") +: p == pend +? throw std::invalid_argument("The given pattern is not a valid set") +: state == match_set_state::open +? *p == c.set_open +? match_set(s, send, cx::next(p), pend, c, equal_to, +match_set_state::not_or_first_in) +: +throw std::invalid_argument("The given pattern is not a valid set") +: +state == match_set_state::not_or_first_in +? *p == c.set_not +? match_set(s, send, cx::next(p), pend, c, equal_to, +match_set_state::first_out) +: +s == send ? make_match_result(false, s, p) +: equal_to(*s, *p) +? make_match_result(true, s, p) +: match_set(s, send, cx::next(p), pend, c, +equal_to, match_set_state::next_in) +: +state == match_set_state::first_out +? s == send || equal_to(*s, *p) +? make_match_result(false, s, p) +: match_set(s, send, cx::next(p), pend, c, equal_to, +match_set_state::next_out) +: +state == match_set_state::next_in +? *p == c.set_close || s == send +? make_match_result(false, s, p) +: equal_to(*s, *p) ? make_match_result(true, s, p) +: match_set(s, send, cx::next(p), +pend, c, equal_to, state) +: +state == match_set_state::next_out +? *p == c.set_close +? make_match_result(true, s, p) +: s == send || equal_to(*s, *p) +? make_match_result(false, s, p) +: match_set(s, send, cx::next(p), pend, c, +equal_to, state) +: throw std::logic_error( +"The program execution should never end up " +"here " +"throwing this exception"); +#endif +} +enum class is_alt_state +{ +open, +next, +escape +}; +template +constexpr bool is_alt( +PatternIterator p, PatternIterator pend, +const cards>& c = cards>(), +is_alt_state state = is_alt_state::open, int depth = 0) +{ +#if cfg_HAS_CONSTEXPR14 +if (!c.alt_enabled) +{ +return false; +} +while (p != pend) +{ +switch (state) +{ +case is_alt_state::open: +if (*p != c.alt_open) +{ +return false; +} +state = is_alt_state::next; +++depth; +break; +case is_alt_state::next: +if (*p == c.escape) +{ +state = is_alt_state::escape; +} +else if (c.set_enabled && *p == c.set_open && +is_set(cx::next(p), pend, c, is_set_state::not_or_first)) +{ +p = cx::prev(set_end(cx::next(p), pend, c, set_end_state::not_or_first)); +} +else if (*p == c.alt_open) +{ +++depth; +} +else if (*p == c.alt_close) +{ +--depth; +if (depth == 0) +{ +return true; +} +} +break; +case is_alt_state::escape: +state = is_alt_state::next; +break; +default: +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::logic_error( +"The program execution should never end up here throwing this exception"); +#else +return throw_logic_error( +p, "The program execution should never end up here throwing this exception"); +#endif +} +p = cx::next(p); +} +return false; +#else +return c.alt_enabled && p != pend && +(state == is_alt_state::open +? *p == c.alt_open && is_alt(cx::next(p), pend, c, is_alt_state::next, depth + 1) +: state == is_alt_state::next +? *p == c.escape +? is_alt(cx::next(p), pend, c, is_alt_state::escape, depth) +: c.set_enabled && *p == c.set_open && +is_set(cx::next(p), pend, c, is_set_state::not_or_first) +? is_alt(set_end(cx::next(p), pend, c, set_end_state::not_or_first), +pend, c, state, depth) +: *p == c.alt_open +? is_alt(cx::next(p), pend, c, state, depth + 1) +: *p == c.alt_close +? depth == 1 || +is_alt(cx::next(p), pend, c, state, depth - 1) +: is_alt(cx::next(p), pend, c, state, depth) +: +state == is_alt_state::escape +? is_alt(cx::next(p), pend, c, is_alt_state::next, depth) +: throw std::logic_error( +"The program execution should never end up here throwing this " +"exception")); +#endif +} +enum class alt_end_state +{ +open, +next, +escape +}; +template +constexpr PatternIterator alt_end( +PatternIterator p, PatternIterator pend, +const cards>& c = cards>(), +alt_end_state state = alt_end_state::open, int depth = 0) +{ +#if cfg_HAS_CONSTEXPR14 +if (!c.alt_enabled) +{ +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The use of alternatives is disabled"); +#else +return throw_invalid_argument(p, "The use of alternatives is disabled"); +#endif +} +while (p != pend) +{ +switch (state) +{ +case alt_end_state::open: +if (*p != c.alt_open) +{ +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The given pattern is not a valid alternative"); +#else +return throw_invalid_argument(p, "The given pattern is not a valid alternative"); +#endif +} +state = alt_end_state::next; +++depth; +break; +case alt_end_state::next: +if (*p == c.escape) +{ +state = alt_end_state::escape; +} +else if (c.set_enabled && *p == c.set_open && +is_set(cx::next(p), pend, c, is_set_state::not_or_first)) +{ +p = cx::prev(set_end(cx::next(p), pend, c, set_end_state::not_or_first)); +} +else if (*p == c.alt_open) +{ +++depth; +} +else if (*p == c.alt_close) +{ +--depth; +if (depth == 0) +{ +return cx::next(p); +} +} +break; +case alt_end_state::escape: +state = alt_end_state::next; +break; +default: +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::logic_error( +"The program execution should never end up here throwing this exception"); +#else +return throw_logic_error( +p, "The program execution should never end up here throwing this exception"); +#endif +} +p = cx::next(p); +} +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The given pattern is not a valid alternative"); +#else +return throw_invalid_argument(p, "The given pattern is not a valid alternative"); +#endif +#else +return !c.alt_enabled +? throw std::invalid_argument("The use of alternatives is disabled") +: p == pend +? throw std::invalid_argument("The given pattern is not a valid alternative") +: state == alt_end_state::open +? *p == c.alt_open +? alt_end(cx::next(p), pend, c, alt_end_state::next, depth + 1) +: throw std::invalid_argument( +"The given pattern is not a valid alternative") +: state == alt_end_state::next +? *p == c.escape +? alt_end(cx::next(p), pend, c, alt_end_state::escape, depth) +: c.set_enabled && *p == c.set_open && +is_set(cx::next(p), pend, c, +is_set_state::not_or_first) +? alt_end(set_end(cx::next(p), pend, c, +set_end_state::not_or_first), +pend, c, state, depth) +: *p == c.alt_open +? alt_end(cx::next(p), pend, c, state, depth + 1) +: *p == c.alt_close +? depth == 1 ? cx::next(p) +: alt_end(cx::next(p), pend, c, +state, depth - 1) +: alt_end(cx::next(p), pend, c, state, depth) +: +state == alt_end_state::escape +? alt_end(cx::next(p), pend, c, alt_end_state::next, depth) +: throw std::logic_error( +"The program execution should never end up here throwing " +"this " +"exception"); +#endif +} +enum class alt_sub_end_state +{ +next, +escape +}; +template +constexpr PatternIterator alt_sub_end( +PatternIterator p, PatternIterator pend, +const cards>& c = cards>(), +alt_sub_end_state state = alt_sub_end_state::next, int depth = 1) +{ +#if cfg_HAS_CONSTEXPR14 +if (!c.alt_enabled) +{ +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The use of alternatives is disabled"); +#else +return throw_invalid_argument(p, "The use of alternatives is disabled"); +#endif +} +while (p != pend) +{ +switch (state) +{ +case alt_sub_end_state::next: +if (*p == c.escape) +{ +state = alt_sub_end_state::escape; +} +else if (c.set_enabled && *p == c.set_open && +is_set(cx::next(p), pend, c, is_set_state::not_or_first)) +{ +p = cx::prev(set_end(cx::next(p), pend, c, set_end_state::not_or_first)); +} +else if (*p == c.alt_open) +{ +++depth; +} +else if (*p == c.alt_close) +{ +--depth; +if (depth == 0) +{ +return p; +} +} +else if (*p == c.alt_or) +{ +if (depth == 1) +{ +return p; +} +} +break; +case alt_sub_end_state::escape: +state = alt_sub_end_state::next; +break; +default: +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::logic_error( +"The program execution should never end up here throwing this exception"); +#else +return throw_logic_error( +p, "The program execution should never end up here throwing this exception"); +#endif +} +p = cx::next(p); +} +#if cfg_HAS_FULL_FEATURED_CONSTEXPR14 +throw std::invalid_argument("The given pattern is not a valid alternative"); +#else +return throw_invalid_argument(p, "The given pattern is not a valid alternative"); +#endif +#else +return !c.alt_enabled +? throw std::invalid_argument("The use of alternatives is disabled") +: p == pend +? throw std::invalid_argument("The given pattern is not a valid alternative") +: state == alt_sub_end_state::next +? *p == c.escape +? alt_sub_end(cx::next(p), pend, c, alt_sub_end_state::escape, depth) +: c.set_enabled && *p == c.set_open && +is_set(cx::next(p), pend, c, is_set_state::not_or_first) +? alt_sub_end(set_end(cx::next(p), pend, c, +set_end_state::not_or_first), +pend, c, state, depth) +: *p == c.alt_open +? alt_sub_end(cx::next(p), pend, c, state, depth + 1) +: *p == c.alt_close +? depth == 1 ? p : alt_sub_end(cx::next(p), pend, +c, state, depth - 1) +: *p == c.alt_or +? depth == 1 ? p +: alt_sub_end(cx::next(p), pend, +c, state, depth) +: alt_sub_end(cx::next(p), pend, c, state, +depth) +: +state == alt_sub_end_state::escape +? alt_sub_end(cx::next(p), pend, c, alt_sub_end_state::next, depth) +: throw std::logic_error( +"The program execution should never end up here throwing " +"this " +"exception"); +#endif +} +template > +constexpr match_result match( +SequenceIterator s, SequenceIterator send, PatternIterator p, PatternIterator pend, +const cards>& c = cards>(), +const EqualTo& equal_to = EqualTo(), bool partial = false, bool escape = false); +template > +constexpr match_result match_alt( +SequenceIterator s, SequenceIterator send, PatternIterator p1, PatternIterator p1end, +PatternIterator p2, PatternIterator p2end, +const cards>& c = cards>(), +const EqualTo& equal_to = EqualTo(), bool partial = false) +{ +#if cfg_HAS_CONSTEXPR14 +auto result1 = match(s, send, p1, p1end, c, equal_to, true); +if (result1) +{ +auto result2 = match(result1.s, send, p2, p2end, c, equal_to, partial); +if (result2) +{ +return result2; +} +} +p1 = cx::next(p1end); +if (p1 == p2) +{ +return make_match_result(false, s, p1end); +} +return match_alt(s, send, p1, alt_sub_end(p1, p2, c), p2, p2end, c, equal_to, partial); +#else +return match(s, send, p1, p1end, c, equal_to, true) && +match(match(s, send, p1, p1end, c, equal_to, true).s, send, p2, p2end, c, equal_to, +partial) +? match(match(s, send, p1, p1end, c, equal_to, true).s, send, p2, p2end, c, equal_to, +partial) +: cx::next(p1end) == p2 +? make_match_result(false, s, p1end) +: match_alt(s, send, cx::next(p1end), alt_sub_end(cx::next(p1end), p2, c), p2, +p2end, c, equal_to, partial); +#endif +} +template +constexpr match_result match( +SequenceIterator s, SequenceIterator send, PatternIterator p, PatternIterator pend, +const cards>& c, const EqualTo& equal_to, bool partial, +bool escape) +{ +#if cfg_HAS_CONSTEXPR14 +if (p == pend) +{ +return make_match_result(partial || s == send, s, p); +} +if (escape) +{ +if (s == send || !equal_to(*s, *p)) +{ +return make_match_result(false, s, p); +} +return match(cx::next(s), send, cx::next(p), pend, c, equal_to, partial); +} +if (*p == c.anything) +{ +auto result = match(s, send, cx::next(p), pend, c, equal_to, partial); +if (result) +{ +return result; +} +if (s == send) +{ +return make_match_result(false, s, p); +} +return match(cx::next(s), send, p, pend, c, equal_to, partial); +} +if (*p == c.single) +{ +if (s == send) +{ +return make_match_result(false, s, p); +} +return match(cx::next(s), send, cx::next(p), pend, c, equal_to, partial); +} +if (*p == c.escape) +{ +return match(s, send, cx::next(p), pend, c, equal_to, partial, true); +} +if (c.set_enabled && *p == c.set_open && is_set(cx::next(p), pend, c, is_set_state::not_or_first)) +{ +auto result = +match_set(s, send, cx::next(p), pend, c, equal_to, match_set_state::not_or_first_in); +if (!result) +{ +return result; +} +return match(cx::next(s), send, set_end(cx::next(p), pend, c, set_end_state::not_or_first), +pend, c, equal_to, partial); +} +if (c.alt_enabled && *p == c.alt_open && is_alt(cx::next(p), pend, c, is_alt_state::next, 1)) +{ +auto p_alt_end = alt_end(cx::next(p), pend, c, alt_end_state::next, 1); +return match_alt(s, send, cx::next(p), alt_sub_end(cx::next(p), p_alt_end, c), p_alt_end, pend, +c, equal_to, partial); +} +if (s == send || !equal_to(*s, *p)) +{ +return make_match_result(false, s, p); +} +return match(cx::next(s), send, cx::next(p), pend, c, equal_to, partial); +#else +return p == pend +? make_match_result(partial || s == send, s, p) +: escape +? s == send || !equal_to(*s, *p) +? make_match_result(false, s, p) +: match(cx::next(s), send, cx::next(p), pend, c, equal_to, partial) +: *p == c.anything +? match(s, send, cx::next(p), pend, c, equal_to, partial) +? match(s, send, cx::next(p), pend, c, equal_to, partial) +: s == send ? make_match_result(false, s, p) +: match(cx::next(s), send, p, pend, c, equal_to, partial) +: *p == c.single +? s == send ? make_match_result(false, s, p) +: match(cx::next(s), send, cx::next(p), pend, c, +equal_to, partial) +: *p == c.escape +? match(s, send, cx::next(p), pend, c, equal_to, partial, true) +: c.set_enabled && *p == c.set_open && +is_set(cx::next(p), pend, c, +is_set_state::not_or_first) +? !match_set(s, send, cx::next(p), pend, c, equal_to, +match_set_state::not_or_first_in) +? match_set(s, send, cx::next(p), pend, c, +equal_to, +match_set_state::not_or_first_in) +: match(cx::next(s), send, +set_end(cx::next(p), pend, c, +set_end_state::not_or_first), +pend, c, equal_to, partial) +: c.alt_enabled && *p == c.alt_open && +is_alt(cx::next(p), pend, c, +is_alt_state::next, 1) +? match_alt( +s, send, cx::next(p), +alt_sub_end(cx::next(p), +alt_end(cx::next(p), pend, c, +alt_end_state::next, 1), +c), +alt_end(cx::next(p), pend, c, +alt_end_state::next, 1), +pend, c, equal_to, partial) +: s == send || !equal_to(*s, *p) +? make_match_result(false, s, p) +: match(cx::next(s), send, cx::next(p), pend, +c, equal_to, partial); +#endif +} +} +template > +constexpr full_match_result, const_iterator_t> match( +Sequence&& sequence, Pattern&& pattern, +const cards>& c = cards>(), +const EqualTo& equal_to = EqualTo()) +{ +return detail::make_full_match_result( +cx::cbegin(sequence), cx::cend(sequence), cx::cbegin(pattern), cx::cend(pattern), +detail::match(cx::cbegin(sequence), cx::cend(std::forward(sequence)), +cx::cbegin(pattern), cx::cend(std::forward(pattern)), c, equal_to)); +} +template , +typename = typename std::enable_if::value>::type> +constexpr full_match_result, const_iterator_t> match( +Sequence&& sequence, Pattern&& pattern, const EqualTo& equal_to) +{ +return match(std::forward(sequence), std::forward(pattern), +cards>(), equal_to); +} +} +#endif +#ifndef WILDCARDS_MATCHER_HPP +#define WILDCARDS_MATCHER_HPP +#include +#include +#include +#ifndef CX_STRING_VIEW_HPP +#define CX_STRING_VIEW_HPP +#include +#include +#ifndef CX_ALGORITHM_HPP +#define CX_ALGORITHM_HPP +namespace cx +{ +template +constexpr bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) +{ +#if cfg_HAS_CONSTEXPR14 +while (first1 != last1 && first2 != last2 && *first1 == *first2) +{ +++first1, ++first2; +} +return first1 == last1 && first2 == last2; +#else +return first1 != last1 && first2 != last2 && *first1 == *first2 +? equal(first1 + 1, last1, first2 + 1, last2) +: first1 == last1 && first2 == last2; +#endif +} +} +#endif +namespace cx +{ +template +class basic_string_view +{ +public: +using value_type = T; +constexpr basic_string_view() = default; +template +constexpr basic_string_view(const T (&str)[N]) : data_{&str[0]}, size_{N - 1} +{ +} +constexpr basic_string_view(const T* str, std::size_t s) : data_{str}, size_{s} +{ +} +constexpr const T* data() const +{ +return data_; +} +constexpr std::size_t size() const +{ +return size_; +} +constexpr bool empty() const +{ +return size() == 0; +} +constexpr const T* begin() const +{ +return data_; +} +constexpr const T* cbegin() const +{ +return begin(); +} +constexpr const T* end() const +{ +return data_ + size_; +} +constexpr const T* cend() const +{ +return end(); +} +private: +const T* data_{nullptr}; +std::size_t size_{0}; +}; +template +constexpr bool operator==(const basic_string_view& lhs, const basic_string_view& rhs) +{ +return equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} +template +constexpr bool operator!=(const basic_string_view& lhs, const basic_string_view& rhs) +{ +return !(lhs == rhs); +} +template +std::basic_ostream& operator<<(std::basic_ostream& o, const basic_string_view& s) +{ +o << s.data(); +return o; +} +template +constexpr basic_string_view make_string_view(const T (&str)[N]) +{ +return {str, N - 1}; +} +template +constexpr basic_string_view make_string_view(const T* str, std::size_t s) +{ +return {str, s}; +} +using string_view = basic_string_view; +using u16string_view = basic_string_view; +using u32string_view = basic_string_view; +using wstring_view = basic_string_view; +namespace literals +{ +constexpr string_view operator"" _sv(const char* str, std::size_t s) +{ +return {str, s}; +} +constexpr u16string_view operator"" _sv(const char16_t* str, std::size_t s) +{ +return {str, s}; +} +constexpr u32string_view operator"" _sv(const char32_t* str, std::size_t s) +{ +return {str, s}; +} +constexpr wstring_view operator"" _sv(const wchar_t* str, std::size_t s) +{ +return {str, s}; +} +} +} +#endif +namespace wildcards +{ +template > +class matcher +{ +public: +constexpr explicit matcher(Pattern&& pattern, const cards>& c = +cards>(), +const EqualTo& equal_to = EqualTo()) +: p_{cx::cbegin(pattern)}, +pend_{cx::cend(std::forward(pattern))}, +c_{c}, +equal_to_{equal_to} +{ +} +constexpr matcher(Pattern&& pattern, const EqualTo& equal_to) +: p_{cx::cbegin(pattern)}, +pend_{cx::cend(std::forward(pattern))}, +c_{cards>()}, +equal_to_{equal_to} +{ +} +template +constexpr full_match_result, const_iterator_t> matches( +Sequence&& sequence) const +{ +return detail::make_full_match_result( +cx::cbegin(sequence), cx::cend(sequence), p_, pend_, +detail::match(cx::cbegin(sequence), cx::cend(std::forward(sequence)), p_, pend_, +c_, equal_to_)); +} +private: +const_iterator_t p_; +const_iterator_t pend_; +cards> c_; +EqualTo equal_to_; +}; +template > +constexpr matcher make_matcher( +Pattern&& pattern, +const cards>& c = cards>(), +const EqualTo& equal_to = EqualTo()) +{ +return matcher{std::forward(pattern), c, equal_to}; +} +template , +typename = typename std::enable_if::value>::type> +constexpr matcher make_matcher(Pattern&& pattern, const EqualTo& equal_to) +{ +return make_matcher(std::forward(pattern), cards>(), equal_to); +} +namespace literals +{ +constexpr auto operator"" _wc(const char* str, std::size_t s) +-> decltype(make_matcher(cx::make_string_view(str, s + 1))) +{ +return make_matcher(cx::make_string_view(str, s + 1)); +} +constexpr auto operator"" _wc(const char16_t* str, std::size_t s) +-> decltype(make_matcher(cx::make_string_view(str, s + 1))) +{ +return make_matcher(cx::make_string_view(str, s + 1)); +} +constexpr auto operator"" _wc(const char32_t* str, std::size_t s) +-> decltype(make_matcher(cx::make_string_view(str, s + 1))) +{ +return make_matcher(cx::make_string_view(str, s + 1)); +} +constexpr auto operator"" _wc(const wchar_t* str, std::size_t s) +-> decltype(make_matcher(cx::make_string_view(str, s + 1))) +{ +return make_matcher(cx::make_string_view(str, s + 1)); +} +} +} +#endif +#endif diff --git a/src/common/fonts/font.cpp b/src/common/fonts/font.cpp new file mode 100644 index 00000000000..c0a9758be99 --- /dev/null +++ b/src/common/fonts/font.cpp @@ -0,0 +1,1148 @@ +/* +** v_font.cpp +** Font management +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include + + +#include "m_swap.h" +#include "v_font.h" +#include "printf.h" +#include "textures.h" +#include "filesystem.h" +#include "cmdlib.h" +#include "sc_man.h" +#include "gstrings.h" +#include "image.h" +#include "utf8.h" +#include "myiswalpha.h" +#include "fontchars.h" +#include "multipatchtexture.h" +#include "texturemanager.h" +#include "i_interface.h" + +#include "fontinternals.h" + +TArray sheetBitmaps; + + +//========================================================================== +// +// FFont :: FFont +// +// Loads a multi-texture font. +// +//========================================================================== + +FFont::FFont (const char *name, const char *nametemplate, const char *filetemplate, int lfirst, int lcount, int start, int fdlump, int spacewidth, bool notranslate, bool iwadonly, bool doomtemplate, GlyphSet *baseGlyphs) + : FFont(fdlump, name) +{ + int i; + FTextureID lump; + char buffer[12]; + DVector2 Scale = { 1, 1 }; + + noTranslate = notranslate; + GlobalKerning = false; + SpaceWidth = 0; + FontHeight = 0; + int FixedWidth = 0; + + TMap charMap; + int minchar = INT_MAX; + int maxchar = INT_MIN; + + // Read the font's configuration. + // This will not be done for the default fonts, because they are not atomic and the default content does not need it. + + std::vector folderdata; + if (filetemplate != nullptr) + { + FStringf path("fonts/%s/", filetemplate); + // If a name template is given, collect data from all resource files. + // For anything else, each folder is being treated as an atomic, self-contained unit and mixing from different glyph sets is blocked. + fileSystem.GetFilesInFolder(path.GetChars(), folderdata, nametemplate == nullptr); + + //if (nametemplate == nullptr) + { + FStringf infpath("fonts/%s/font.inf", filetemplate); + + size_t index; + for(index = 0; index < folderdata.size(); index++) + { + if (infpath.CompareNoCase(folderdata[index].name) == 0) break; + } + + if (index < folderdata.size()) + { + FScanner sc; + sc.OpenLumpNum(folderdata[index].lumpnum); + while (sc.GetToken()) + { + sc.TokenMustBe(TK_Identifier); + if (sc.Compare("Kerning")) + { + sc.MustGetValue(false); + GlobalKerning = sc.Number; + } + else if (sc.Compare("Altfont")) + { + sc.MustGetString(); + AltFontName = sc.String; + } + else if (sc.Compare("Scale")) + { + sc.MustGetValue(true); + Scale.Y = Scale.X = sc.Float; + if (sc.CheckToken(',')) + { + sc.MustGetValue(true); + Scale.Y = sc.Float; + } + } + else if (sc.Compare("SpaceWidth")) + { + sc.MustGetValue(false); + SpaceWidth = sc.Number; + } + else if (sc.Compare("FontHeight")) + { + sc.MustGetValue(false); + FontHeight = sc.Number; + } + else if (sc.Compare("CellSize")) + { + sc.MustGetValue(false); + FixedWidth = sc.Number; + sc.MustGetToken(','); + sc.MustGetValue(false); + FontHeight = sc.Number; + } + else if (sc.Compare("minluminosity")) + { + sc.MustGetValue(false); + MinLum = (int16_t)clamp(sc.Number, 0, 255); + } + else if (sc.Compare("maxluminosity")) + { + sc.MustGetValue(false); + MaxLum = (int16_t)clamp(sc.Number, 0, 255); + } + else if (sc.Compare("Translationtype")) + { + sc.MustGetToken(TK_Identifier); + if (sc.Compare("console")) + { + TranslationType = 1; + } + else if (sc.Compare("standard")) + { + TranslationType = 0; + } + else + { + sc.ScriptError("Unknown translation type %s", sc.String); + } + } + else if (sc.Compare("lowercaselatinonly")) + { + lowercaselatinonly = true; + } + + } + } + } + } + + if (FixedWidth > 0) + { + ReadSheetFont(folderdata, FixedWidth, FontHeight, Scale); + Type = Folder; + } + else + { + if (baseGlyphs) + { + // First insert everything from the given glyph set. + GlyphSet::Iterator it(*baseGlyphs); + GlyphSet::Pair* pair; + while (it.NextPair(pair)) + { + if (pair->Value && pair->Value->GetTexelWidth() > 0 && pair->Value->GetTexelHeight() > 0) + { + auto position = pair->Key; + if (position < minchar) minchar = position; + if (position > maxchar) maxchar = position; + charMap.Insert(position, pair->Value); + } + } + } + if (nametemplate != nullptr) + { + if (!iwadonly) + { + for (i = 0; i < lcount; i++) + { + int position = lfirst + i; + mysnprintf(buffer, countof(buffer), nametemplate, i + start); + + lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch); + if (doomtemplate && lump.isValid() && i + start == 121) + { // HACKHACK: Don't load STCFN121 in doom(2), because + // it's not really a lower-case 'y' but a '|'. + // Because a lot of wads with their own font seem to foolishly + // copy STCFN121 and make it a '|' themselves, wads must + // provide STCFN120 (x) and STCFN122 (z) for STCFN121 to load as a 'y'. + FStringf c120(nametemplate, 120); + FStringf c122(nametemplate, 122); + if (!TexMan.CheckForTexture(c120.GetChars(), ETextureType::MiscPatch).isValid() || + !TexMan.CheckForTexture(c122.GetChars(), ETextureType::MiscPatch).isValid()) + { + // insert the incorrectly named '|' graphic in its correct position. + position = 124; + } + } + if (lump.isValid()) + { + Type = Multilump; + if (position < minchar) minchar = position; + if (position > maxchar) maxchar = position; + charMap.Insert(position, TexMan.GetGameTexture(lump)); + } + } + } + else + { + FGameTexture *texs[256] = {}; + if (lcount > 256 - start) lcount = 256 - start; + for (i = 0; i < lcount; i++) + { + TArray array; + mysnprintf(buffer, countof(buffer), nametemplate, i + start); + + TexMan.ListTextures(buffer, array, true); + for (auto entry : array) + { + auto tex = TexMan.GetGameTexture(entry, false); + if (tex && !tex->isUserContent() && tex->GetUseType() == ETextureType::MiscPatch) + { + texs[i] = tex; + } + } + } + if (doomtemplate) + { + // Handle the misplaced '|'. + if (texs[121 - '!'] && !texs[120 - '!'] && !texs[122 - '!'] && !texs[124 - '!']) + { + texs[124 - '!'] = texs[121 - '!']; + texs[121 - '!'] = nullptr; + } + } + + for (i = 0; i < lcount; i++) + { + if (texs[i]) + { + int position = lfirst + i; + Type = Multilump; + if (position < minchar) minchar = position; + if (position > maxchar) maxchar = position; + charMap.Insert(position, texs[i]); + } + } + } + } + if (folderdata.size() > 0) + { + // all valid lumps must be named with a hex number that represents its Unicode character index. + for (auto &entry : folderdata) + { + char *endp; + auto base = ExtractFileBase(entry.name); + auto position = strtoll(base.GetChars(), &endp, 16); + if ((*endp == 0 || (*endp == '.' && position >= '!' && position < 0xffff))) + { + auto texlump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); + if (texlump.isValid()) + { + if ((int)position < minchar) minchar = (int)position; + if ((int)position > maxchar) maxchar = (int)position; + auto tex = TexMan.GetGameTexture(texlump); + tex->SetScale((float)Scale.X, (float)Scale.Y); + charMap.Insert((int)position, tex); + Type = Folder; + } + } + } + } + FirstChar = minchar; + LastChar = maxchar; + auto count = maxchar - minchar + 1; + Chars.Resize(count); + int fontheight = 0; + + for (i = 0; i < count; i++) + { + auto charlump = charMap.CheckKey(FirstChar + i); + if (charlump != nullptr) + { + auto pic = *charlump; + if (pic != nullptr) + { + double fheight = pic->GetDisplayHeight(); + double yoffs = pic->GetDisplayTopOffset(); + + int height = int(fheight + abs(yoffs) + 0.5); + if (height > fontheight) + { + fontheight = height; + } + } + + auto orig = pic->GetTexture(); + auto tex = MakeGameTexture(orig, nullptr, ETextureType::FontChar); + tex->CopySize(pic, true); + TexMan.AddGameTexture(tex); + Chars[i].OriginalPic = tex; + + if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(pic, Chars[i].OriginalPic); + + Chars[i].XMove = (int)Chars[i].OriginalPic->GetDisplayWidth(); + } + else + { + Chars[i].OriginalPic = nullptr; + Chars[i].XMove = INT_MIN; + } + } + + if (SpaceWidth == 0) // An explicit override from the .inf file must always take precedence + { + if (spacewidth != -1) + { + SpaceWidth = spacewidth; + } + else if ('N' - FirstChar >= 0 && 'N' - FirstChar < count && Chars['N' - FirstChar].OriginalPic != nullptr) + { + SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2; + } + else + { + SpaceWidth = 4; + } + } + if (FontHeight == 0) FontHeight = fontheight; + + FixXMoves(); + } +} + +class FSheetTexture : public FImageSource +{ + unsigned baseSheet; + int X, Y; + +public: + + FSheetTexture(unsigned source, int x, int y, int width, int height) + { + baseSheet = source; + Width = width; + Height = height; + X = x; + Y = y; + } + + int CopyPixels(FBitmap* dest, int conversion, int frame = 0) override + { + auto& pic = sheetBitmaps[baseSheet]; + dest->CopyPixelDataRGB(0, 0, pic.GetPixels() + 4 * (X + pic.GetWidth() * Y), Width, Height, 4, pic.GetWidth() * 4, 0, CF_BGRA); + return 0; + } + +}; +void FFont::ReadSheetFont(std::vector &folderdata, int width, int height, const DVector2 &Scale) +{ + TMap charMap; + int minchar = INT_MAX; + int maxchar = INT_MIN; + for (auto &entry : folderdata) + { + char *endp; + auto base = ExtractFileBase(entry.name); + auto position = strtoll(base.GetChars(), &endp, 16); + if ((*endp == 0 || (*endp == '.' && position >= 0 && position < 0xffff))) // Sheet fonts may fill in the low control chars. + { + auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); + if (lump.isValid()) + { + auto tex = TexMan.GetGameTexture(lump); + int numtex_x = tex->GetTexelWidth() / width; + int numtex_y = tex->GetTexelHeight() / height; + int maxinsheet = int(position) + numtex_x * numtex_y - 1; + if (minchar > position) minchar = int(position); + if (maxchar < maxinsheet) maxchar = maxinsheet; + + FBitmap* sheetimg = &sheetBitmaps[sheetBitmaps.Reserve(1)]; + sheetimg->Create(tex->GetTexelWidth(), tex->GetTexelHeight()); + tex->GetTexture()->GetImage()->CopyPixels(sheetimg, FImageSource::normal, 0); + + for (int y = 0; y < numtex_y; y++) + { + for (int x = 0; x < numtex_x; x++) + { + auto image = new FSheetTexture(sheetBitmaps.Size() - 1, x * width, y * height, width, height); + FImageTexture *imgtex = new FImageTexture(image); + auto gtex = MakeGameTexture(imgtex, nullptr, ETextureType::FontChar); + gtex->SetWorldPanning(true); + gtex->SetOffsets(0, 0, 0); + gtex->SetOffsets(1, 0, 0); + gtex->SetScale((float)Scale.X, (float)Scale.Y); + TexMan.AddGameTexture(gtex); + charMap.Insert(int(position) + x + y * numtex_x, gtex); + } + } + } + } + } + + + FirstChar = minchar; + bool map1252 = false; + if (minchar < 0x80 && maxchar >= 0xa0) // should be a settable option, but that'd probably cause more problems than it'd solve. + { + if (maxchar < 0x2122) maxchar = 0x2122; + map1252 = true; + } + LastChar = maxchar; + auto count = maxchar - minchar + 1; + Chars.Resize(count); + + for (int i = 0; i < count; i++) + { + auto lump = charMap.CheckKey(FirstChar + i); + if (lump != nullptr) + { + auto pic = (*lump)->GetTexture(); + Chars[i].OriginalPic = (*lump)->GetUseType() == ETextureType::FontChar? (*lump) : MakeGameTexture(pic, nullptr, ETextureType::FontChar); + Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); + Chars[i].OriginalPic->CopySize(*lump, true); + if (Chars[i].OriginalPic != *lump) TexMan.AddGameTexture(Chars[i].OriginalPic); + } + Chars[i].XMove = int(width / Scale.X); + } + + if (map1252) + { + // Move the Windows-1252 characters to their proper place. + for (int i = 0x80; i < 0xa0; i++) + { + if (win1252map[i - 0x80] != i && Chars[i - minchar].OriginalPic != nullptr && Chars[win1252map[i - 0x80] - minchar].OriginalPic == nullptr) + { + std::swap(Chars[i - minchar], Chars[win1252map[i - 0x80] - minchar]); + } + } + } + + SpaceWidth = width; +} + +//========================================================================== +// +// FFont :: ~FFont +// +//========================================================================== + +FFont::~FFont () +{ + FFont **prev = &FirstFont; + FFont *font = *prev; + + while (font != nullptr && font != this) + { + prev = &font->Next; + font = *prev; + } + + if (font != nullptr) + { + *prev = font->Next; + } +} + +//========================================================================== +// +// FFont :: CheckCase +// +//========================================================================== + +void FFont::CheckCase() +{ + int lowercount = 0, uppercount = 0; + for (unsigned i = 0; i < Chars.Size(); i++) + { + unsigned chr = i + FirstChar; + if (lowerforupper[chr] == chr && upperforlower[chr] == chr) + { + continue; // not a letter; + } + if (myislower(chr)) + { + if (Chars[i].OriginalPic != nullptr) lowercount++; + } + else + { + if (Chars[i].OriginalPic != nullptr) uppercount++; + } + } + if (lowercount == 0) return; // This is an uppercase-only font and we are done. + + // The ß needs special treatment because it is far more likely to be supplied lowercase only, even in an uppercase font. + if (Chars[0xdf - FirstChar].OriginalPic != nullptr) + { + if (LastChar < 0x1e9e) + { + Chars.Resize(0x1e9f - FirstChar); + LastChar = 0x1e9e; + } + if (Chars[0x1e9e - FirstChar].OriginalPic == nullptr) + { + std::swap(Chars[0xdf - FirstChar], Chars[0x1e9e - FirstChar]); + lowercount--; + uppercount++; + if (lowercount == 0) return; + } + } +} + +//========================================================================== +// +// FFont :: FindFont +// +// Searches for the named font in the list of loaded fonts, returning the +// font if it was found. The disk is not checked if it cannot be found. +// +//========================================================================== + +FFont *FFont::FindFont (FName name) +{ + if (name == NAME_None) + { + return nullptr; + } + FFont *font = FirstFont; + + while (font != nullptr) + { + if (font->FontName == name) return font; + font = font->Next; + } + return nullptr; +} + +//========================================================================== +// +// RecordTextureColors +// +// Given a 256 entry buffer, sets every entry that corresponds to a color +// used by the texture to 1. +// +//========================================================================== + +void RecordTextureColors (FImageSource *pic, uint32_t *usedcolors) +{ + int x; + + auto pixels = pic->GetPalettedPixels(false); + auto size = pic->GetWidth() * pic->GetHeight(); + + for(x = 0;x < size; x++) + { + usedcolors[pixels[x]]++; + } +} + +//========================================================================== +// +// RecordLuminosity +// +// Records minimum and maximum luminosity of a texture. +// +//========================================================================== + +static void RecordLuminosity(FImageSource* pic, int* minlum, int* maxlum) +{ + auto bitmap = pic->GetCachedBitmap(nullptr, FImageSource::normal); + auto pixels = bitmap.GetPixels(); + auto size = pic->GetWidth() * pic->GetHeight(); + + for (int x = 0; x < size; x++) + { + int xx = x * 4; + if (pixels[xx + 3] > 0) + { + int lum = Luminance(pixels[xx + 2], pixels[xx + 1], pixels[xx]); + if (lum < *minlum) *minlum = lum; + if (lum > *maxlum) *maxlum = lum; + } + } +} + +//========================================================================== +// +// RecordAllTextureColors +// +// Given a 256 entry buffer, sets every entry that corresponds to a color +// used by the font. +// +//========================================================================== + +void FFont::RecordAllTextureColors(uint32_t *usedcolors) +{ + for (unsigned int i = 0; i < Chars.Size(); i++) + { + if (Chars[i].OriginalPic) + { + auto pic = Chars[i].OriginalPic->GetTexture()->GetImage(); + if (pic) RecordTextureColors(pic, usedcolors); + } + } +} + +//========================================================================== +// +// compare +// +// Used for sorting colors by brightness. +// +//========================================================================== + +static int compare (const void *arg1, const void *arg2) +{ + if (RPART(GPalette.BaseColors[*((uint8_t *)arg1)]) * 299 + + GPART(GPalette.BaseColors[*((uint8_t *)arg1)]) * 587 + + BPART(GPalette.BaseColors[*((uint8_t *)arg1)]) * 114 < + RPART(GPalette.BaseColors[*((uint8_t *)arg2)]) * 299 + + GPART(GPalette.BaseColors[*((uint8_t *)arg2)]) * 587 + + BPART(GPalette.BaseColors[*((uint8_t *)arg2)]) * 114) + return -1; + else + return 1; +} + +//========================================================================== +// +// FFont :: GetLuminosity +// +//========================================================================== + +int FFont::GetLuminosity (uint32_t *colorsused, TArray &Luminosity, int* minlum, int* maxlum) +{ + double min, max, diver; + + Luminosity.Resize(256); + Luminosity[0] = 0.0; // [BL] Prevent uninitalized memory + max = 0.0; + min = 100000000.0; + for (int i = 1; i < 256; i++) + { + if (colorsused[i]) + { + Luminosity[i] = GPalette.BaseColors[i].r * 0.299 + GPalette.BaseColors[i].g * 0.587 + GPalette.BaseColors[i].b * 0.114; + if (Luminosity[i] > max) max = Luminosity[i]; + if (Luminosity[i] < min) min = Luminosity[i]; + } + else Luminosity[i] = -1; // this color is not of interest. + } + diver = 1.0 / (max - min); + for (int i = 1; i < 256; i++) + { + if (colorsused[i]) + { + Luminosity[i] = (Luminosity[i] - min) * diver; + } + } + if (minlum) *minlum = int(min); + if (maxlum) *maxlum = int(max); + + return 256; +} + +//========================================================================== +// +// FFont :: GetColorTranslation +// +//========================================================================== + +FTranslationID FFont::GetColorTranslation (EColorRange range, PalEntry *color) const +{ + // Single pic fonts do not set up their translation table and must always return 0. + if (Translations.Size() == 0) return NO_TRANSLATION; + assert(Translations.Size() == (unsigned)NumTextColors); + + if (noTranslate) + { + PalEntry retcolor = PalEntry(255, 255, 255, 255); + if (range >= 0 && range < NumTextColors && range != CR_UNTRANSLATED) + { + retcolor = TranslationColors[range]; + retcolor.a = 255; + } + if (color != nullptr) *color = retcolor; + } + if (range == CR_UNDEFINED) + return INVALID_TRANSLATION; + else if (range >= NumTextColors) + range = CR_UNTRANSLATED; + return Translations[range]; +} + +//========================================================================== +// +// FFont :: GetCharCode +// +// If the character code is in the font, returns it. If it is not, but it +// is lowercase and has an uppercase variant present, return that. Otherwise +// return -1. +// +//========================================================================== + +int FFont::GetCharCode(int code, bool needpic) const +{ + int newcode; + + if (code < 0 && code >= -128) + { + // regular chars turn negative when the 8th bit is set. + code &= 255; + } + if (special_i && needpic) + { + // We need one special case for Turkish: If we have a lowercase-only font (like Raven's) and want to print the capital I, it must map to the dotless ı, because its own glyph will be the dotted i. + // This checks if the font has no small i, but does define the small dotless ı. + if (!MixedCase && code == 'I' && LastChar >= 0x131 && Chars['i' - FirstChar].OriginalPic == nullptr && Chars[0x131 - FirstChar].OriginalPic != nullptr) + { + return 0x131; + } + // a similar check is needed for the small i in allcaps fonts. Here we cannot simply remap to an existing character, so the small dotted i must be placed at code point 0080. + if (code == 'i' && LastChar >= 0x80 && Chars[0x80 - FirstChar].OriginalPic != nullptr) + { + return 0x80; + } + } + + + if (code >= FirstChar && code <= LastChar && Chars[code - FirstChar].OriginalPic != nullptr) + { + return code; + } + + // Use different substitution logic based on the fonts content: + // In a font which has both upper and lower case, prefer unaccented small characters over capital ones. + // In a pure upper-case font, do not check for lower case replacements. + if (!MixedCase || (lowercaselatinonly && code >= 0x380 && code < 0x500)) + { + // Try converting lowercase characters to uppercase. + if (myislower(code)) + { + code = upperforlower[code]; + if (code >= FirstChar && code <= LastChar && Chars[code - FirstChar].OriginalPic != nullptr) + { + return code; + } + } + // Try stripping accents from accented characters. + while ((newcode = stripaccent(code)) != code) + { + code = newcode; + if (code >= FirstChar && code <= LastChar && Chars[code - FirstChar].OriginalPic != nullptr) + { + return code; + } + } + } + else + { + int originalcode = code; + + // Try stripping accents from accented characters. This may repeat to allow multi-step fallbacks. + while ((newcode = stripaccent(code)) != code) + { + code = newcode; + if (code >= FirstChar && code <= LastChar && Chars[code - FirstChar].OriginalPic != nullptr) + { + return code; + } + } + + code = originalcode; + if (myislower(code)) + { + int upper = upperforlower[code]; + // Stripping accents did not help - now try uppercase for lowercase + if (upper != code) return GetCharCode(upper, true); + } + + // Same for the uppercase character. Since we restart at the accented version this must go through the entire thing again. + while ((newcode = stripaccent(code)) != code) + { + code = newcode; + if (code >= FirstChar && code <= LastChar && Chars[code - FirstChar].OriginalPic != nullptr) + { + return code; + } + } + + } + + return -1; +} + +//========================================================================== +// +// FFont :: GetChar +// +//========================================================================== + +FGameTexture *FFont::GetChar (int code, int translation, int *const width) const +{ + code = GetCharCode(code, true); + int xmove = SpaceWidth; + + if (code >= 0) + { + code -= FirstChar; + xmove = Chars[code].XMove; + } + + if (width != nullptr) + { + *width = xmove; + } + if (code < 0) return nullptr; + + + assert(Chars[code].OriginalPic->GetUseType() == ETextureType::FontChar); + return Chars[code].OriginalPic; +} + +//========================================================================== +// +// FFont :: GetCharWidth +// +//========================================================================== + +int FFont::GetCharWidth (int code) const +{ + code = GetCharCode(code, true); + if (code >= 0) return Chars[code - FirstChar].XMove; + return SpaceWidth; +} + +//========================================================================== +// +// +// +//========================================================================== + +double GetBottomAlignOffset(FFont *font, int c) +{ + int w; + auto tex_zero = font->GetChar('0', CR_UNDEFINED, &w); + auto texc = font->GetChar(c, CR_UNDEFINED, &w); + double offset = 0; + if (texc) offset += texc->GetDisplayTopOffset(); + if (tex_zero) offset += -tex_zero->GetDisplayTopOffset() + tex_zero->GetDisplayHeight(); + return offset; +} + +//========================================================================== +// +// Checks if the font contains proper glyphs for all characters in the string +// +//========================================================================== + +bool FFont::CanPrint(const uint8_t *string) const +{ + if (!string) return true; + while (*string) + { + auto chr = GetCharFromString(string); + if (!MixedCase) chr = upperforlower[chr]; // For uppercase-only fonts we shouldn't check lowercase characters. + if (chr == TEXTCOLOR_ESCAPE) + { + // We do not need to check for UTF-8 in here. + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (chr != '\n') + { + int cc = GetCharCode(chr, false); + if (chr != cc && myiswalpha(chr) && cc != getAlternative(chr)) + { + return false; + } + } + } + + return true; +} + +//========================================================================== +// +// Find string width using this font +// +//========================================================================== + +int FFont::StringWidth(const uint8_t *string, int spacing) const +{ + int w = 0; + int maxw = 0; + + while (*string) + { + auto chr = GetCharFromString(string); + if (chr == TEXTCOLOR_ESCAPE) + { + // We do not need to check for UTF-8 in here. + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (chr == '\n') + { + if (w > maxw) + maxw = w; + w = 0; + } + else if (spacing >= 0) + { + w += GetCharWidth(chr) + GlobalKerning + spacing; + } + else + { + w -= spacing; + } + } + + return max(maxw, w); +} + +//========================================================================== +// +// Get the largest ascender in the first line of this text. +// +//========================================================================== + +int FFont::GetMaxAscender(const uint8_t* string) const +{ + int retval = 0; + + while (*string) + { + auto chr = GetCharFromString(string); + if (chr == TEXTCOLOR_ESCAPE) + { + // We do not need to check for UTF-8 in here. + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (chr == '\n') + { + break; + } + else + { + auto ctex = GetChar(chr, CR_UNTRANSLATED, nullptr); + if (ctex) + { + auto offs = int(ctex->GetDisplayTopOffset()); + if (offs > retval) retval = offs; + } + } + } + + return retval; +} + +//========================================================================== +// +// FFont :: LoadTranslations +// +//========================================================================== + +void FFont::LoadTranslations() +{ + unsigned int count = min(Chars.Size(), LastChar - FirstChar + 1); + + if (count == 0) return; + int minlum = 255, maxlum = 0; + for (unsigned int i = 0; i < count; i++) + { + if (Chars[i].OriginalPic) + { + auto pic = Chars[i].OriginalPic->GetTexture()->GetImage(); + RecordLuminosity(pic, &minlum, &maxlum); + } + } + + if (MinLum >= 0 && MinLum < minlum) minlum = MinLum; + if (MaxLum > maxlum) maxlum = MaxLum; + + // Here we can set everything to a luminosity translation. + Translations.Resize(NumTextColors); + for (int i = 0; i < NumTextColors; i++) + { + if (i == CR_UNTRANSLATED) Translations[i] = NO_TRANSLATION; + else Translations[i] = MakeLuminosityTranslation(i*2 + TranslationType, minlum, maxlum); + } +} + +//========================================================================== +// +// FFont :: FFont - default constructor +// +//========================================================================== + +FFont::FFont (int lump, FName nm) +{ + FirstChar = LastChar = 0; + Next = FirstFont; + FirstFont = this; + Lump = lump; + FontName = nm; + Cursor = '_'; + noTranslate = false; +} + +//========================================================================== +// +// FFont :: FixXMoves +// +// If a font has gaps in its characters, set the missing characters' +// XMoves to either SpaceWidth or the unaccented or uppercase variant's +// XMove. Missing XMoves must be initialized with INT_MIN beforehand. +// +//========================================================================== + +void FFont::FixXMoves() +{ + if (FirstChar < 'a' && LastChar >= 'z') + { + MixedCase = true; + // First check if this is a mixed case font. + // For this the basic Latin small characters all need to be present. + for (int i = 'a'; i <= 'z'; i++) + if (Chars[i - FirstChar].OriginalPic == nullptr) + { + MixedCase = false; + break; + } + } + + for (int i = 0; i <= LastChar - FirstChar; ++i) + { + if (Chars[i].XMove == INT_MIN) + { + // Try an uppercase character. + if (myislower(i + FirstChar)) + { + int upper = upperforlower[FirstChar + i]; + if (upper >= FirstChar && upper <= LastChar ) + { + Chars[i].XMove = Chars[upper - FirstChar].XMove; + continue; + } + } + // Try an unnaccented character. + int noaccent = stripaccent(i + FirstChar); + if (noaccent != i + FirstChar) + { + noaccent -= FirstChar; + if (noaccent >= 0) + { + Chars[i].XMove = Chars[noaccent].XMove; + continue; + } + } + Chars[i].XMove = SpaceWidth; + } + if (Chars[i].OriginalPic) + { + int ofs = (int)Chars[i].OriginalPic->GetDisplayTopOffset(); + if (ofs > Displacement) Displacement = ofs; + } + } +} + + +void FFont::ClearOffsets() +{ + for (auto& c : Chars) if (c.OriginalPic) c.OriginalPic->SetOffsets(0, 0); +} diff --git a/src/common/fonts/fontinternals.h b/src/common/fonts/fontinternals.h new file mode 100644 index 00000000000..149f9ab9f22 --- /dev/null +++ b/src/common/fonts/fontinternals.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "tarray.h" + +struct TranslationParm +{ + short RangeStart; // First level for this range + short RangeEnd; // Last level for this range + uint8_t Start[3]; // Start color for this range + uint8_t End[3]; // End color for this range +}; + +struct TempParmInfo +{ + unsigned int StartParm[2]; + unsigned int ParmLen[2]; + int Index; +}; +struct TempColorInfo +{ + FName Name; + unsigned int ParmInfo; + PalEntry LogColor; +}; + +struct TranslationMap +{ + FName Name; + int Number; +}; + +extern TArray TranslationParms[2]; +extern TArray TranslationLookup; +extern TArray TranslationColors; + +class FImageSource; diff --git a/src/common/fonts/hexfont.cpp b/src/common/fonts/hexfont.cpp new file mode 100644 index 00000000000..00dbf0830e2 --- /dev/null +++ b/src/common/fonts/hexfont.cpp @@ -0,0 +1,446 @@ +/* +** bdffont.cpp +** Management for the VGA consolefont +** +**--------------------------------------------------------------------------- +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "engineerrors.h" +#include "textures.h" +#include "image.h" +#include "v_font.h" +#include "filesystem.h" +#include "utf8.h" +#include "sc_man.h" +#include "texturemanager.h" + +#include "fontinternals.h" + + +struct HexDataSource +{ + int FirstChar = INT_MAX, LastChar = INT_MIN; + TArray glyphdata; + unsigned glyphmap[65536] = {}; + + PalEntry ConsolePal[18], SmallPal[18]; + + //========================================================================== + // + // parse a HEX font + // + //========================================================================== + + void ParseDefinition(FResourceFile* resf, int index) + { + FScanner sc; + + auto data = resf->Read(index); + sc.OpenMem("newconsolefont.hex", data.string(), (int)data.size()); + sc.SetCMode(true); + glyphdata.Push(0); // ensure that index 0 can be used as 'not present'. + while (sc.GetString()) + { + int codepoint = (int)strtoull(sc.String, nullptr, 16); + sc.MustGetStringName(":"); + sc.MustGetString(); + if (codepoint >= 0 && codepoint < 65536 && !sc.Compare("00000000000000000000000000000000")) // don't set up empty glyphs. + { + unsigned size = (unsigned)strlen(sc.String); + unsigned offset = glyphdata.Reserve(size / 2 + 1); + glyphmap[codepoint] = offset; + glyphdata[offset++] = size / 2; + for (unsigned i = 0; i < size; i += 2) + { + char hex[] = { sc.String[i], sc.String[i + 1], 0 }; + glyphdata[offset++] = (uint8_t)strtoull(hex, nullptr, 16); + } + if (codepoint < FirstChar) FirstChar = codepoint; + if (codepoint > LastChar) LastChar = codepoint; + } + } + + ConsolePal[0] = SmallPal[0] = 0; + for (int i = 1; i < 18; i++) + { + double lum = i == 1 ? 0.01 : 0.5 + (i - 2) * (0.5 / 17.); + uint8_t lumb = (uint8_t(lum * 255)); + + ConsolePal[i] = PalEntry(255, lumb, lumb, lumb); + lumb = i * 255 / 17; + SmallPal[i] = PalEntry(255, lumb, lumb, lumb); + } + } +}; + +static HexDataSource hexdata; + +// This is a font character that reads RLE compressed data. +class FHexFontChar : public FImageSource +{ +public: + FHexFontChar(uint8_t *sourcedata, int swidth, int width, int height); + + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap* bmp, int conversion, int frame = 0) override; + +protected: + int SourceWidth; + const uint8_t *SourceData; +}; + + +//========================================================================== +// +// FHexFontChar :: FHexFontChar +// +// Used by HEX fonts. +// +//========================================================================== + +FHexFontChar::FHexFontChar (uint8_t *sourcedata, int swidth, int width, int height) +: SourceData (sourcedata) +{ + SourceWidth = swidth; + Width = width; + Height = height; + LeftOffset = 0; + TopOffset = 0; +} + +//========================================================================== +// +// FHexFontChar :: Get8BitPixels +// +// The render style has no relevance here. +// +//========================================================================== + +PalettedPixels FHexFontChar::CreatePalettedPixels(int, int) +{ + int destSize = Width * Height; + PalettedPixels Pixels(destSize); + uint8_t *dest_p = Pixels.Data(); + const uint8_t *src_p = SourceData; + + memset(dest_p, 0, destSize); + for (int y = 0; y < Height; y++) + { + for (int x = 0; x < SourceWidth; x++) + { + int byte = *src_p++; + uint8_t *pixelstart = dest_p + 8 * x * Height + y; + for (int bit = 0; bit < 8; bit++) + { + if (byte & (128 >> bit)) + { + pixelstart[bit*Height] = y+2; + // Add a shadow at the bottom right, similar to the old console font. + if (y != Height - 1) + { + pixelstart[bit*Height + Height + 1] = 1; + } + } + } + } + } + return Pixels; +} + +int FHexFontChar::CopyPixels(FBitmap* bmp, int conversion, int frame) +{ + if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source. + PalEntry* palette = hexdata.ConsolePal; + auto ppix = CreatePalettedPixels(conversion); + bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr); + return 0; + +} + +class FHexFontChar2 : public FHexFontChar +{ +public: + FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height); + + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap* bmp, int conversion, int frame = 0) override; +}; + + +//========================================================================== +// +// FHexFontChar :: FHexFontChar +// +// Used by HEX fonts. +// +//========================================================================== + +FHexFontChar2::FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height) + : FHexFontChar(sourcedata, swidth, width, height) +{ +} + +//========================================================================== +// +// FHexFontChar :: Get8BitPixels +// +// The render style has no relevance here. +// +//========================================================================== + +PalettedPixels FHexFontChar2::CreatePalettedPixels(int, int) +{ + int destSize = Width * Height; + PalettedPixels Pixels(destSize); + uint8_t *dest_p = Pixels.Data(); + + assert(SourceData); + if (SourceData) + { + auto drawLayer = [&](int ix, int iy, int color) + { + const uint8_t *src_p = SourceData; + for (int y = 0; y < Height - 2; y++) + { + for (int x = 0; x < SourceWidth; x++) + { + int byte = *src_p++; + uint8_t *pixelstart = dest_p + (ix + 8 * x) * Height + (iy + y); + for (int bit = 0; bit < 8; bit++) + { + if (byte & (128 >> bit)) + { + pixelstart[bit*Height] = color; + } + } + } + } + }; + memset(dest_p, 0, destSize); + + const int darkcolor = 1; + const int brightcolor = 14; + for (int xx = 0; xx < 3; xx++) for (int yy = 0; yy < 3; yy++) if (xx != 1 || yy != 1) + drawLayer(xx, yy, darkcolor); + drawLayer(1, 1, brightcolor); + } + return Pixels; +} + +int FHexFontChar2::CopyPixels(FBitmap* bmp, int conversion, int frame) +{ + if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source. + PalEntry* palette = hexdata.SmallPal; + auto ppix = CreatePalettedPixels(conversion); + bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr); + return 0; +} + + + +class FHexFont : public FFont +{ + +public: + //========================================================================== + // + // FHexFont :: FHexFont + // + // Loads a HEX font + // + //========================================================================== + + FHexFont (const char *fontname, int lump) + : FFont(lump) + { + const int spacing = 9; + assert(lump >= 0); + + FontName = fontname; + + FirstChar = hexdata.FirstChar; + LastChar = hexdata.LastChar; + + FontHeight = 16; + SpaceWidth = 9; + GlobalKerning = 0; + + Chars.Resize(LastChar - FirstChar + 1); + for (int i = FirstChar; i <= LastChar; i++) + { + if (hexdata.glyphmap[i] > 0) + { + auto offset = hexdata.glyphmap[i]; + int size = hexdata.glyphdata[offset] / 16; + Chars[i - FirstChar].OriginalPic = MakeGameTexture(new FImageTexture(new FHexFontChar(&hexdata.glyphdata[offset + 1], size, size * 9, 16)), nullptr, ETextureType::FontChar); + Chars[i - FirstChar].XMove = size * spacing; + TexMan.AddGameTexture(Chars[i - FirstChar].OriginalPic); + } + else Chars[i - FirstChar].XMove = spacing; + + } + } + + //========================================================================== + // + // FHexFont :: LoadTranslations + // + //========================================================================== + + void LoadTranslations() + { + int minlum = hexdata.ConsolePal[1].r; + int maxlum = hexdata.ConsolePal[17].r; + + Translations.Resize(NumTextColors); + for (int i = 0; i < NumTextColors; i++) + { + if (i == CR_UNTRANSLATED) Translations[i] = NO_TRANSLATION; + else Translations[i] = MakeLuminosityTranslation(i * 2 + 1, minlum, maxlum); + } + } + +}; + + +class FHexFont2 : public FFont +{ + +public: + //========================================================================== + // + // FHexFont :: FHexFont + // + // Loads a HEX font + // + //========================================================================== + + FHexFont2(const char *fontname, int lump) + : FFont(lump) + { + const int spacing = 9; + assert(lump >= 0); + + FontName = fontname; + + FirstChar = hexdata.FirstChar; + LastChar = hexdata.LastChar; + + FontHeight = 18; + SpaceWidth = 9; + GlobalKerning = -1; + Chars.Resize(LastChar - FirstChar + 1); + for (int i = FirstChar; i <= LastChar; i++) + { + if (hexdata.glyphmap[i] > 0) + { + auto offset = hexdata.glyphmap[i]; + int size = hexdata.glyphdata[offset] / 16; + Chars[i - FirstChar].OriginalPic = MakeGameTexture(new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18)), nullptr, ETextureType::FontChar); + Chars[i - FirstChar].XMove = size * spacing; + TexMan.AddGameTexture(Chars[i - FirstChar].OriginalPic); + } + else Chars[i - FirstChar].XMove = spacing; + + } + } + + //========================================================================== + // + // FHexFont :: LoadTranslations + // + //========================================================================== + + void LoadTranslations() override + { + int minlum = hexdata.SmallPal[1].r; + int maxlum = hexdata.SmallPal[17].r; + + Translations.Resize(NumTextColors); + for (int i = 0; i < NumTextColors; i++) + { + if (i == CR_UNTRANSLATED) Translations[i] = NO_TRANSLATION; + else Translations[i] = MakeLuminosityTranslation(i * 2, minlum, maxlum); + } + } +}; + + +//========================================================================== +// +// +// +//========================================================================== + +FFont *CreateHexLumpFont (const char *fontname, int lump) +{ + assert(hexdata.FirstChar != INT_MAX); + return new FHexFont(fontname, lump); +} + +//========================================================================== +// +// +// +//========================================================================== + +FFont *CreateHexLumpFont2(const char *fontname, int lump) +{ + assert(hexdata.FirstChar != INT_MAX); + return new FHexFont2(fontname, lump); +} + +//========================================================================== +// +// +// +//========================================================================== + +uint8_t* GetHexChar(int codepoint) +{ + assert(hexdata.FirstChar != INT_MAX); + + if (hexdata.glyphmap[codepoint] > 0) + { + auto offset = hexdata.glyphmap[codepoint]; + return &hexdata.glyphdata[offset]; + } + return nullptr; +} + +void LoadHexFont(const char* filename) +{ + auto resf = FResourceFile::OpenResourceFile(filename); + if (resf == nullptr) I_FatalError("Unable to open %s", filename); + auto hexfont = resf->FindEntry("newconsolefont.hex"); + if (hexfont < 0) I_FatalError("Unable to find newconsolefont.hex in %s", filename); + hexdata.ParseDefinition(resf, hexfont); + delete resf; +} diff --git a/src/gamedata/fonts/myiswalpha.h b/src/common/fonts/myiswalpha.h similarity index 100% rename from src/gamedata/fonts/myiswalpha.h rename to src/common/fonts/myiswalpha.h diff --git a/src/common/fonts/singlelumpfont.cpp b/src/common/fonts/singlelumpfont.cpp new file mode 100644 index 00000000000..0d583940162 --- /dev/null +++ b/src/common/fonts/singlelumpfont.cpp @@ -0,0 +1,575 @@ +/* +** singlelumpfont.cpp +** Management for compiled font lumps +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "engineerrors.h" +#include "textures.h" +#include "image.h" +#include "v_font.h" +#include "filesystem.h" +#include "utf8.h" +#include "fontchars.h" +#include "texturemanager.h" +#include "m_swap.h" + +#include "fontinternals.h" + +/* Special file formats handled here: + +FON1 "console" fonts have the following header: + char Magic[4]; -- The characters "FON1" + uword CharWidth; -- Character cell width + uword CharHeight; -- Character cell height + +The FON1 header is followed by RLE character data for all 256 +8-bit ASCII characters. + + +FON2 "standard" fonts have the following header: + char Magic[4]; -- The characters "FON2" + uword FontHeight; -- Every character in a font has the same height + ubyte FirstChar; -- First character defined by this font. + ubyte LastChar; -- Last character definde by this font. + ubyte bConstantWidth; + ubyte ShadingType; + ubyte PaletteSize; -- size of palette in entries (not bytes!) + ubyte Flags; + +There is presently only one flag for FON2: + FOF_WHOLEFONTKERNING 1 -- The Kerning field is present in the file + +The FON2 header is followed by variable length data: + word Kerning; + -- only present if FOF_WHOLEFONTKERNING is set + + ubyte Palette[PaletteSize+1][3]; + -- The last entry is the delimiter color. The delimiter is not used + -- by the font but is used by imagetool when converting the font + -- back to an image. Color 0 is the transparent color and is also + -- used only for converting the font back to an image. The other + -- entries are all presorted in increasing order of brightness. + + ubyte CharacterData[...]; + -- RLE character data, in order +*/ + +class FSingleLumpFont : public FFont +{ +public: + FSingleLumpFont (const char *fontname, int lump); + void RecordAllTextureColors(uint32_t* usedcolors) override; + +protected: + void CheckFON1Chars (); + void FixupPalette (uint8_t *identity, const PalEntry *palette, int* minlum ,int* maxlum); + void LoadTranslations (); + void LoadFON1 (int lump, const uint8_t *data); + void LoadFON2 (int lump, const uint8_t *data); + void LoadBMF (int lump, const uint8_t *data); + + enum + { + FONT1, + FONT2, + BMFFONT + } FontType; + PalEntry Palette[256]; + bool RescalePalette; + int ActiveColors = -1; +}; + + +//========================================================================== +// +// FSingleLumpFont :: FSingleLumpFont +// +// Loads a FON1 or FON2 font resource. +// +//========================================================================== + +FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump) +{ + assert(lump >= 0); + + FontName = name; + + auto data1 = fileSystem.ReadFile (lump); + auto data = data1.bytes(); + + if (data[0] == 0xE1 && data[1] == 0xE6 && data[2] == 0xD5 && data[3] == 0x1A) + { + LoadBMF(lump, data); + Type = BMF; + } + else if (data[0] != 'F' || data[1] != 'O' || data[2] != 'N' || + (data[3] != '1' && data[3] != '2')) + { + I_Error ("%s is not a recognizable font", name); + } + else + { + switch (data[3]) + { + case '1': + LoadFON1 (lump, data); + Type = Fon1; + break; + + case '2': + LoadFON2 (lump, data); + Type = Fon2; + break; + } + } +} + +//========================================================================== +// +// FSingleLumpFont :: LoadTranslations +// +//========================================================================== + +void FSingleLumpFont::LoadTranslations() +{ + uint8_t identity[256]; + unsigned int count = LastChar - FirstChar + 1; + int minlum, maxlum; + + switch(FontType) + { + case FONT1: + CheckFON1Chars(); + minlum = 1; + maxlum = 255; + break; + + case BMFFONT: + case FONT2: + FixupPalette (identity, Palette, &minlum, &maxlum); + break; + + default: + // Should be unreachable. + I_Error("Unknown font type in FSingleLumpFont::LoadTranslation."); + return; + } + + for(unsigned int i = 0;i < count;++i) + { + if(Chars[i].OriginalPic) + static_cast(Chars[i].OriginalPic->GetTexture()->GetImage())->SetSourceRemap(Palette); + } + + Translations.Resize(NumTextColors); + for (int i = 0; i < NumTextColors; i++) + { + if (i == CR_UNTRANSLATED) Translations[i] = NO_TRANSLATION; + else Translations[i] = MakeLuminosityTranslation(i * 2 + (FontType == FONT1 ? 1 : 0), minlum, maxlum); + } +} + +//========================================================================== +// +// FSingleLumpFont :: LoadFON1 +// +// FON1 is used for the console font. +// +//========================================================================== + +void FSingleLumpFont::LoadFON1 (int lump, const uint8_t *data) +{ + int w, h; + + // The default console font is for Windows-1252 and fills the 0x80-0x9f range with valid glyphs. + // Since now all internal text is processed as Unicode, these have to be remapped to their proper places. + // The highest valid character in this range is 0x2122, so we need 0x2123 entries in our character table. + Chars.Resize(0x2123); + + w = data[4] + data[5]*256; + h = data[6] + data[7]*256; + + FontType = FONT1; + FontHeight = h; + SpaceWidth = w; + FirstChar = 0; + LastChar = 255; // This is to allow LoadTranslations to function. The way this is all set up really needs to be changed. + GlobalKerning = 0; + LastChar = 0x2122; + + // Move the Windows-1252 characters to their proper place. + for (int i = 0x80; i < 0xa0; i++) + { + if (win1252map[i-0x80] != i && Chars[i].OriginalPic != nullptr && Chars[win1252map[i - 0x80]].OriginalPic == nullptr) + { + std::swap(Chars[i], Chars[win1252map[i - 0x80]]); + } + } + Palette[0] = 0; + for (int i = 1; i < 256; i++) Palette[i] = PalEntry(255, i, i, i); +} + +//========================================================================== +// +// FSingleLumpFont :: LoadFON2 +// +// FON2 is used for everything but the console font. +// +//========================================================================== + +void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data) +{ + int count, i, totalwidth; + uint16_t *widths; + const uint8_t *palette; + const uint8_t *data_p; + + FontType = FONT2; + FontHeight = data[4] + data[5]*256; + FirstChar = data[6]; + LastChar = data[7]; + ActiveColors = data[10]+1; + RescalePalette = data[9] == 0; + + count = LastChar - FirstChar + 1; + Chars.Resize(count); + TArray widths2(count, true); + if (data[11] & 1) + { // Font specifies a kerning value. + GlobalKerning = LittleShort(*(int16_t *)&data[12]); + widths = (uint16_t *)(data + 14); + } + else + { // Font does not specify a kerning value. + GlobalKerning = 0; + widths = (uint16_t *)(data + 12); + } + totalwidth = 0; + + if (data[8]) + { // Font is mono-spaced. + totalwidth = LittleShort(widths[0]); + for (i = 0; i < count; ++i) + { + widths2[i] = totalwidth; + } + totalwidth *= count; + palette = (uint8_t *)&widths[1]; + } + else + { // Font has varying character widths. + for (i = 0; i < count; ++i) + { + widths2[i] = LittleShort(widths[i]); + totalwidth += widths2[i]; + } + palette = (uint8_t *)(widths + i); + } + + if (FirstChar <= ' ' && LastChar >= ' ') + { + SpaceWidth = widths2[' '-FirstChar]; + } + else if (FirstChar <= 'N' && LastChar >= 'N') + { + SpaceWidth = (widths2['N' - FirstChar] + 1) / 2; + } + else + { + SpaceWidth = totalwidth * 2 / (3 * count); + } + + Palette[0] = 0; + for (int pp = 1; pp < ActiveColors; pp++) + { + Palette[pp] = PalEntry(255, palette[pp * 3], palette[pp * 3 + 1], palette[pp * 3 + 2]); + } + + data_p = palette + ActiveColors*3; + + for (i = 0; i < count; ++i) + { + int destSize = widths2[i] * FontHeight; + Chars[i].XMove = widths2[i]; + if (destSize <= 0) + { + Chars[i].OriginalPic = nullptr; + } + else + { + Chars[i].OriginalPic = MakeGameTexture(new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)), nullptr, ETextureType::FontChar); + TexMan.AddGameTexture(Chars[i].OriginalPic); + do + { + int8_t code = *data_p++; + if (code >= 0) + { + data_p += code+1; + destSize -= code+1; + } + else if (code != -128) + { + data_p++; + destSize -= (-code)+1; + } + } while (destSize > 0); + } + if (destSize < 0) + { + i += FirstChar; + I_Error ("Overflow decompressing char %d (%c) of %s", i, i, FontName.GetChars()); + } + } +} + +//========================================================================== +// +// FSingleLumpFont :: LoadBMF +// +// Loads a BMF font. The file format is described at +// +// +//========================================================================== + +void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data) +{ + const uint8_t *chardata; + int numchars, count, totalwidth, nwidth; + int infolen; + int i, chari; + + FontType = BMFFONT; + FontHeight = data[5]; + GlobalKerning = (int8_t)data[8]; + ActiveColors = data[16]; + SpaceWidth = -1; + nwidth = -1; + RescalePalette = true; + + infolen = data[17 + ActiveColors*3]; + chardata = data + 18 + ActiveColors*3 + infolen; + numchars = chardata[0] + 256*chardata[1]; + chardata += 2; + + // Scan for lowest and highest characters defined and total font width. + FirstChar = 256; + LastChar = 0; + totalwidth = 0; + for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2]) + { + if ((chardata[chari+1] == 0 || chardata[chari+2] == 0) && chardata[chari+5] == 0) + { // Don't count empty characters. + continue; + } + if (chardata[chari] < FirstChar) + { + FirstChar = chardata[chari]; + } + if (chardata[chari] > LastChar) + { + LastChar = chardata[chari]; + } + totalwidth += chardata[chari+1]; + } + if (LastChar < FirstChar) + { + I_Error("BMF font defines no characters"); + } + count = LastChar - FirstChar + 1; + Chars.Resize(count); + // BMF palettes are only six bits per component. Fix that. + Palette[0] = 0; + for (i = 0; i < ActiveColors; ++i) + { + int r = (data[17 + i * 3] << 2) | (data[17 + i * 3] >> 4); + int g = (data[18 + i * 3] << 2) | (data[18 + i * 3] >> 4); + int b = (data[19 + i * 3] << 2) | (data[19 + i * 3] >> 4); + Palette[i + 1] = PalEntry(255, r, g, b); // entry 0 (transparent) is not stored in the font file. + } + ActiveColors++; + + // Now scan through the characters again, creating glyphs for each one. + for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2]) + { + assert(chardata[chari] - FirstChar >= 0); + assert(chardata[chari] - FirstChar < count); + if (chardata[chari] == ' ') + { + SpaceWidth = chardata[chari+5]; + } + else if (chardata[chari] == 'N') + { + nwidth = chardata[chari+5]; + } + Chars[chardata[chari] - FirstChar].XMove = chardata[chari+5]; + if (chardata[chari+1] == 0 || chardata[chari+2] == 0) + { // Empty character: skip it. + continue; + } + auto tex = MakeGameTexture(new FImageTexture(new FFontChar2(lump, int(chardata + chari + 6 - data), + chardata[chari+1], // width + chardata[chari+2], // height + -(int8_t)chardata[chari+3], // x offset + -(int8_t)chardata[chari+4] // y offset + )), nullptr, ETextureType::FontChar); + Chars[chardata[chari] - FirstChar].OriginalPic = tex; + TexMan.AddGameTexture(tex); + } + + // If the font did not define a space character, determine a suitable space width now. + if (SpaceWidth < 0) + { + if (nwidth >= 0) + { + SpaceWidth = nwidth; + } + else + { + SpaceWidth = totalwidth * 2 / (3 * count); + } + } + + FixXMoves(); +} + +//========================================================================== +// +// FSingleLumpFont :: CheckFON1Chars +// +// Scans a FON1 resource for all the color values it uses and sets up +// some tables. Data points to the RLE data for +// the characters. Also sets up the character textures. +// +//========================================================================== + +void FSingleLumpFont::CheckFON1Chars() +{ + auto memLump = fileSystem.ReadFile(Lump); + auto data = memLump.bytes(); + const uint8_t* data_p; + + data_p = data + 8; + + for (int i = 0; i < 256; ++i) + { + int destSize = SpaceWidth * FontHeight; + + if (!Chars[i].OriginalPic) + { + Chars[i].OriginalPic = MakeGameTexture(new FImageTexture(new FFontChar2(Lump, int(data_p - data), SpaceWidth, FontHeight)), nullptr, ETextureType::FontChar); + Chars[i].XMove = SpaceWidth; + TexMan.AddGameTexture(Chars[i].OriginalPic); + } + + // Advance to next char's data and count the used colors. + do + { + int8_t code = *data_p++; + if (code >= 0) + { + destSize -= code + 1; + while (code-- >= 0) + { + data_p++; + } + } + else if (code != -128) + { + data_p++; + destSize -= 1 - code; + } + } while (destSize > 0); + } + ActiveColors = 256; +} + +//========================================================================== +// +// FSingleLumpFont :: FixupPalette +// +// Finds the best matches for the colors used by a FON2 font and finds thr +// used luminosity range +// +//========================================================================== + +void FSingleLumpFont::FixupPalette (uint8_t *identity, const PalEntry *palette, int *pminlum, int *pmaxlum) +{ + double maxlum = 0.0; + double minlum = 100000000.0; + + identity[0] = 0; + palette++; // Skip the transparent color + + for (int i = 1; i < ActiveColors; ++i, palette ++) + { + int r = palette->r; + int g = palette->g; + int b = palette->b; + double lum = r*0.299 + g*0.587 + b*0.114; + identity[i] = ColorMatcher.Pick(r, g, b); + if (lum > maxlum) maxlum = lum; + if (lum < minlum) minlum = lum; + } + + if (pminlum) *pminlum = int(minlum); + if (pmaxlum) *pmaxlum = int(maxlum); +} + +//========================================================================== +// +// RecordAllTextureColors +// +// Given a 256 entry buffer, sets every entry that corresponds to a color +// used by the font. +// +//========================================================================== + +void FSingleLumpFont::RecordAllTextureColors(uint32_t* usedcolors) +{ + uint8_t identity[256]; + + if (FontType == BMFFONT || FontType == FONT2) + { + FixupPalette(identity, Palette, nullptr, nullptr); + for (int i = 0; i < 256; i++) + { + if (identity[i] != 0) usedcolors[identity[i]]++; + } + } +} + + +FFont *CreateSingleLumpFont (const char *fontname, int lump) +{ + return new FSingleLumpFont(fontname, lump); +} diff --git a/src/gamedata/fonts/singlepicfont.cpp b/src/common/fonts/singlepicfont.cpp similarity index 83% rename from src/gamedata/fonts/singlepicfont.cpp rename to src/common/fonts/singlepicfont.cpp index 12daba08186..30fdf87115a 100644 --- a/src/gamedata/fonts/singlepicfont.cpp +++ b/src/common/fonts/singlepicfont.cpp @@ -33,10 +33,11 @@ ** */ -#include "doomerrors.h" +#include "engineerrors.h" #include "textures.h" #include "v_font.h" -#include "w_wad.h" +#include "filesystem.h" +#include "texturemanager.h" class FSinglePicFont : public FFont { @@ -44,8 +45,8 @@ class FSinglePicFont : public FFont FSinglePicFont(const char *picname); // FFont interface - FTexture *GetChar(int code, int translation, int *const width, bool *redirected = nullptr) const override; - int GetCharWidth (int code) const; + FGameTexture *GetChar(int code, int translation, int *const width) const override; + int GetCharWidth (int code) const override; protected: FTextureID PicNum; @@ -64,25 +65,21 @@ class FSinglePicFont : public FFont FSinglePicFont::FSinglePicFont(const char *picname) : FFont(-1) // Since lump is only needed for priority information we don't need to worry about this here. { - FTextureID picnum = TexMan.CheckForTexture (picname, ETextureType::Any); + FTextureID texid = TexMan.CheckForTexture (picname, ETextureType::Any); - if (!picnum.isValid()) + if (!texid.isValid()) { I_FatalError ("%s is not a font or texture", picname); } - FTexture *pic = TexMan.GetTexture(picnum); + auto pic = TexMan.GetGameTexture(texid); FontName = picname; - FontHeight = pic->GetDisplayHeight(); - SpaceWidth = pic->GetDisplayWidth(); + FontHeight = (int)pic->GetDisplayHeight(); + SpaceWidth = (int)pic->GetDisplayWidth(); GlobalKerning = 0; FirstChar = LastChar = 'A'; - ActiveColors = 0; - PicNum = picnum; - - Next = FirstFont; - FirstFont = this; + PicNum = texid; } //========================================================================== @@ -93,13 +90,12 @@ FSinglePicFont::FSinglePicFont(const char *picname) : // //========================================================================== -FTexture *FSinglePicFont::GetChar (int code, int translation, int *const width, bool *redirected) const +FGameTexture *FSinglePicFont::GetChar (int code, int translation, int *const width) const { *width = SpaceWidth; - if (redirected) *redirected = false; if (code == 'a' || code == 'A') { - return TexMan.GetPalettedTexture(PicNum, true); + return TexMan.GetGameTexture(PicNum, true); } else { diff --git a/src/common/fonts/specialfont.cpp b/src/common/fonts/specialfont.cpp new file mode 100644 index 00000000000..9ab3d4f388a --- /dev/null +++ b/src/common/fonts/specialfont.cpp @@ -0,0 +1,206 @@ +/* +** v_font.cpp +** Font management +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "v_font.h" +#include "textures.h" +#include "image.h" +#include "fontchars.h" +#include "texturemanager.h" +#include "i_interface.h" + +#include "fontinternals.h" + +// Essentially a normal multilump font but with an explicit list of character patches +class FSpecialFont : public FFont +{ +public: + FSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); + + void LoadTranslations(); + +protected: + bool notranslate[256]; +}; + + +//========================================================================== +// +// FSpecialFont :: FSpecialFont +// +//========================================================================== + +FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) + : FFont(lump) +{ + int i; + TArray charlumps(count, true); + int maxyoffs; + FGameTexture *pic; + + memcpy(this->notranslate, notranslate, 256*sizeof(bool)); + + noTranslate = donttranslate; + FontName = name; + Chars.Resize(count); + FirstChar = first; + LastChar = first + count - 1; + FontHeight = 0; + GlobalKerning = false; + + maxyoffs = 0; + + for (i = 0; i < count; i++) + { + pic = charlumps[i] = lumplist[i]; + if (pic != nullptr) + { + int height = (int)pic->GetDisplayHeight(); + int yoffs = (int)pic->GetDisplayTopOffset(); + + if (yoffs > maxyoffs) + { + maxyoffs = yoffs; + } + height += abs (yoffs); + if (height > FontHeight) + { + FontHeight = height; + } + } + + if (charlumps[i] != nullptr) + { + auto charpic = charlumps[i]; + Chars[i].OriginalPic = MakeGameTexture(charpic->GetTexture(), nullptr, ETextureType::FontChar); + Chars[i].OriginalPic->CopySize(charpic, true); + TexMan.AddGameTexture(Chars[i].OriginalPic); + Chars[i].XMove = (int)Chars[i].OriginalPic->GetDisplayWidth(); + if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(charpic, Chars[i].OriginalPic); + } + else + { + Chars[i].OriginalPic = nullptr; + Chars[i].XMove = INT_MIN; + } + } + + // Special fonts normally don't have all characters so be careful here! + if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].OriginalPic != nullptr) + { + SpaceWidth = (Chars['N' - first].XMove + 1) / 2; + } + else + { + SpaceWidth = 4; + } + + FixXMoves(); +} + +//========================================================================== +// +// FSpecialFont :: LoadTranslations +// +//========================================================================== + +void FSpecialFont::LoadTranslations() +{ + FFont::LoadTranslations(); + + bool empty = true; + for (auto& c : Chars) + { + if (c.OriginalPic != nullptr) + { + empty = false; + break; + } + } + if (empty) return; // Font has no characters. + + bool needsnotrans = false; + // exclude the non-translated colors from the translation calculation + for (int i = 0; i < 256; i++) + if (notranslate[i]) + { + needsnotrans = true; + break; + } + + // If we have no non-translateable colors, we can use the base data as-is. + if (!needsnotrans) + { + return; + } + + // we only need to add special handling if there's colors that should not be translated. + // Obviously 'notranslate' should only be used on data that uses the base palette, otherwise results are undefined! + for (auto &trans : Translations) + { + if (!IsLuminosityTranslation(trans)) continue; // this should only happen for CR_UNTRANSLATED. + + FRemapTable remap(256); + remap.ForFont = true; + + uint8_t workpal[1024]; + for (int i = 0; i < 256; i++) + { + workpal[i * 4 + 0] = GPalette.BaseColors[i].b; + workpal[i * 4 + 1] = GPalette.BaseColors[i].g; + workpal[i * 4 + 2] = GPalette.BaseColors[i].r; + workpal[i * 4 + 3] = GPalette.BaseColors[i].a; + } + V_ApplyLuminosityTranslation(LuminosityTranslationDesc::fromID(trans), workpal, 256); + for (int i = 0; i < 256; i++) + { + if (!notranslate[i]) + { + remap.Palette[i] = PalEntry(workpal[i * 4 + 3], workpal[i * 4 + 2], workpal[i * 4 + 1], workpal[i * 4 + 0]); + remap.Remap[i] = ColorMatcher.Pick(remap.Palette[i]); + } + else + { + remap.Palette[i] = GPalette.BaseColors[i]; + remap.Remap[i] = i; + } + } + trans = GPalette.StoreTranslation(TRANSLATION_Internal, &remap); + } +} + +FFont *CreateSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) +{ + return new FSpecialFont(name, first, count, lumplist, notranslate, lump, donttranslate); +} diff --git a/src/common/fonts/v_font.cpp b/src/common/fonts/v_font.cpp new file mode 100644 index 00000000000..d838fb18130 --- /dev/null +++ b/src/common/fonts/v_font.cpp @@ -0,0 +1,969 @@ +/* +** v_font.cpp +** Font management +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include + + +#include "m_swap.h" +#include "v_font.h" +#include "filesystem.h" +#include "cmdlib.h" +#include "sc_man.h" +#include "gstrings.h" +#include "image.h" +#include "utf8.h" +#include "fontchars.h" +#include "textures.h" +#include "texturemanager.h" +#include "printf.h" +#include "palentry.h" + +#include "fontinternals.h" + +// MACROS ------------------------------------------------------------------ + +#define DEFAULT_LOG_COLOR PalEntry(223,223,223) + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static int TranslationMapCompare (const void *a, const void *b); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern int PrintColors[]; +extern TArray sheetBitmaps; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- +FFont* SmallFont, * SmallFont2, * BigFont, * BigUpper, * ConFont, * IntermissionFont, * NewConsoleFont, * NewSmallFont, + * CurrentConsoleFont, * OriginalSmallFont, * AlternativeSmallFont, * OriginalBigFont, *AlternativeBigFont; + +FFont *FFont::FirstFont = nullptr; +int NumTextColors; +static bool translationsLoaded; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +TArray TranslationParms[2]; +TArray TranslationLookup; +TArray TranslationColors; + +// CODE -------------------------------------------------------------------- + +FFont *V_GetFont(const char *name, const char *fontlumpname) +{ + if (name == nullptr) return nullptr; + if (!stricmp(name, "DBIGFONT")) name = "BigFont"; + else if (!stricmp(name, "CONFONT")) name = "ConsoleFont"; // several mods have used the name CONFONT directly and effectively duplicated the font. + else if (!stricmp(name, "INDEXFON")) name = "IndexFont"; // Same here - for whatever reason some people had to use its 8 character name... + FFont *font = FFont::FindFont (name); + if (font == nullptr) + { + if (!stricmp(name, "BIGUPPER")) + { + font = FFont::FindFont("BIGFONT"); + if (font) return font; + } + + int lump = -1; + int folderfile = -1; + + std::vector folderdata; + FStringf path("fonts/%s/", name); + + // Use a folder-based font only if it comes from a later file than the single lump version. + if (fileSystem.GetFilesInFolder(path.GetChars(), folderdata, true)) + { + // This assumes that any custom font comes in one piece and not distributed across multiple resource files. + folderfile = fileSystem.GetFileContainer(folderdata[0].lumpnum); + } + + + lump = fileSystem.CheckNumForFullName(fontlumpname? fontlumpname : name, true); + + if (lump != -1 && fileSystem.GetFileContainer(lump) >= folderfile) + { + uint32_t head; + { + auto lumpy = fileSystem.OpenFileReader (lump); + lumpy.Read (&head, 4); + } + if ((head & MAKE_ID(255,255,255,0)) == MAKE_ID('F','O','N',0) || + head == MAKE_ID(0xE1,0xE6,0xD5,0x1A)) + { + FFont *CreateSingleLumpFont (const char *fontname, int lump); + font = CreateSingleLumpFont (name, lump); + if (translationsLoaded) font->LoadTranslations(); + return font; + } + } + FTextureID texid = TexMan.CheckForTexture (name, ETextureType::Any); + if (texid.isValid()) + { + auto tex = TexMan.GetGameTexture(texid); + if (tex && tex->GetSourceLump() >= folderfile) + { + FFont *CreateSinglePicFont(const char *name); + font = CreateSinglePicFont (name); + return font; + } + } + if (folderdata.size() > 0) + { + font = new FFont(name, nullptr, name, 0, 0, 1, -1); + if (translationsLoaded) font->LoadTranslations(); + return font; + } + } + return font; +} + +//========================================================================== +// +// V_InitCustomFonts +// +// Initialize a list of custom multipatch fonts +// +//========================================================================== + +void V_InitCustomFonts() +{ + FScanner sc; + FGameTexture *lumplist[256]; + bool notranslate[256]; + bool donttranslate; + FString namebuffer, templatebuf; + int i; + int llump,lastlump=0; + int format; + int start; + int first; + int count; + int spacewidth = -1; + int kerning; + char cursor = '_'; + bool ignoreoffsets = false; + int MinLum = -1, MaxLum = -1; + + while ((llump = fileSystem.FindLump ("FONTDEFS", &lastlump)) != -1) + { + sc.OpenLumpNum(llump); + while (sc.GetString()) + { + memset (lumplist, 0, sizeof(lumplist)); + memset (notranslate, 0, sizeof(notranslate)); + donttranslate = false; + namebuffer = sc.String; + format = 0; + start = 33; + first = 33; + count = 223; + spacewidth = -1; + kerning = 0; + + sc.MustGetStringName ("{"); + while (!sc.CheckString ("}")) + { + sc.MustGetString(); + if (sc.Compare ("TEMPLATE")) + { + if (format == 2) goto wrong; + sc.MustGetString(); + templatebuf = sc.String; + format = 1; + } + else if (sc.Compare ("BASE")) + { + if (format == 2) goto wrong; + sc.MustGetNumber(); + start = sc.Number; + format = 1; + } + else if (sc.Compare ("FIRST")) + { + if (format == 2) goto wrong; + sc.MustGetNumber(); + first = sc.Number; + format = 1; + } + else if (sc.Compare ("COUNT")) + { + if (format == 2) goto wrong; + sc.MustGetNumber(); + count = sc.Number; + format = 1; + } + else if (sc.Compare ("CURSOR")) + { + sc.MustGetString(); + cursor = sc.String[0]; + } + else if (sc.Compare ("SPACEWIDTH")) + { + sc.MustGetNumber(); + spacewidth = sc.Number; + } + else if (sc.Compare("DONTTRANSLATE")) + { + donttranslate = true; + } + else if (sc.Compare ("NOTRANSLATION")) + { + if (format == 1) goto wrong; + while (sc.CheckNumber() && !sc.Crossed) + { + if (sc.Number >= 0 && sc.Number < 256) + notranslate[sc.Number] = true; + } + format = 2; + } + else if (sc.Compare("KERNING")) + { + sc.MustGetNumber(); + kerning = sc.Number; + } + else if (sc.Compare("ignoreoffsets")) + { + ignoreoffsets = true; + } + else if (sc.Compare("minluminosity")) + { + sc.MustGetValue(false); + MinLum = (int16_t)clamp(sc.Number, 0, 255); + } + else if (sc.Compare("maxluminosity")) + { + sc.MustGetValue(false); + MaxLum = (int16_t)clamp(sc.Number, 0, 255); + } + else + { + if (format == 1) goto wrong; + // The braces must be filtered so because they'd be treated as block terminators otherwise. + if (!strcmp(sc.String, "-{")) strcpy(sc.String, "{"); + if (!strcmp(sc.String, "-}")) strcpy(sc.String, "}"); + FGameTexture **p = &lumplist[*(unsigned char*)sc.String]; + sc.MustGetString(); + FTextureID texid = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); + if (texid.Exists()) + { + *p = TexMan.GetGameTexture(texid); + } + else if (fileSystem.GetFileContainer(sc.LumpNum) >= fileSystem.GetIwadNum()) + { + // Print a message only if this isn't in zdoom.pk3 + sc.ScriptMessage("%s: Unable to find texture in font definition for %s", sc.String, namebuffer.GetChars()); + } + format = 2; + } + } + if (format == 1) + { + FFont *fnt = new FFont(namebuffer.GetChars(), templatebuf.GetChars(), nullptr, first, count, start, llump, spacewidth, donttranslate); + fnt->SetCursor(cursor); + fnt->SetKerning(kerning); + if (ignoreoffsets) fnt->ClearOffsets(); + } + else if (format == 2) + { + for (i = 0; i < 256; i++) + { + if (lumplist[i] != nullptr) + { + first = i; + break; + } + } + for (i = 255; i >= 0; i--) + { + if (lumplist[i] != nullptr) + { + count = i - first + 1; + break; + } + } + if (count > 0) + { + FFont *CreateSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); + FFont *fnt = CreateSpecialFont(namebuffer.GetChars(), first, count, &lumplist[first], notranslate, llump, donttranslate); + fnt->SetCursor(cursor); + fnt->SetKerning(kerning); + if (spacewidth >= 0) fnt->SpaceWidth = spacewidth; + fnt->MinLum = MinLum; + fnt->MaxLum = MaxLum; + if (ignoreoffsets) fnt->ClearOffsets(); + } + } + else goto wrong; + } + sc.Close(); + } + return; + +wrong: + sc.ScriptError ("Invalid combination of properties in font '%s', %s not allowed", namebuffer.GetChars(), sc.String); +} + +//========================================================================== +// +// V_InitFontColors +// +// Reads the list of color translation definitions into memory. +// +//========================================================================== + +void V_InitFontColors () +{ + TArray names; + int lump, lastlump = 0; + TranslationParm tparm = { 0, 0, {0}, {0} }; // Silence GCC (for real with -Wextra ) + TArray parms; + TArray parminfo; + TArray colorinfo; + int c, parmchoice; + TempParmInfo info; + TempColorInfo cinfo; + PalEntry logcolor; + unsigned int i, j; + int k, index; + + info.Index = -1; + + TranslationParms[0].Clear(); + TranslationParms[1].Clear(); + TranslationLookup.Clear(); + TranslationColors.Clear(); + + while ((lump = fileSystem.FindLump ("TEXTCOLO", &lastlump)) != -1) + { + FScanner sc(lump); + while (sc.GetString()) + { + names.Clear(); + + logcolor = DEFAULT_LOG_COLOR; + + // Everything until the '{' is considered a valid name for the + // color range. + names.Push (sc.String); + while (sc.MustGetString(), !sc.Compare ("{")) + { + if (names[0] == NAME_Untranslated) + { + sc.ScriptError ("The \"untranslated\" color may not have any other names"); + } + names.Push (sc.String); + } + + parmchoice = 0; + info.StartParm[0] = parms.Size(); + info.StartParm[1] = 0; + info.ParmLen[1] = info.ParmLen[0] = 0; + tparm.RangeEnd = tparm.RangeStart = -1; + + while (sc.MustGetString(), !sc.Compare ("}")) + { + if (sc.Compare ("Console:")) + { + if (parmchoice == 1) + { + sc.ScriptError ("Each color may only have one set of console ranges"); + } + parmchoice = 1; + info.StartParm[1] = parms.Size(); + info.ParmLen[0] = info.StartParm[1] - info.StartParm[0]; + tparm.RangeEnd = tparm.RangeStart = -1; + } + else if (sc.Compare ("Flat:")) + { + sc.MustGetString(); + logcolor = V_GetColor (sc); + } + else + { + // Get first color + c = V_GetColor (sc); + tparm.Start[0] = RPART(c); + tparm.Start[1] = GPART(c); + tparm.Start[2] = BPART(c); + + // Get second color + sc.MustGetString(); + c = V_GetColor (sc); + tparm.End[0] = RPART(c); + tparm.End[1] = GPART(c); + tparm.End[2] = BPART(c); + + // Check for range specifier + if (sc.CheckNumber()) + { + if (tparm.RangeStart == -1 && sc.Number != 0) + { + sc.ScriptError ("The first color range must start at position 0"); + } + if (sc.Number < 0 || sc.Number > 256) + { + sc.ScriptError ("The color range must be within positions [0,256]"); + } + if (sc.Number <= tparm.RangeEnd) + { + sc.ScriptError ("The color range must not start before the previous one ends"); + } + tparm.RangeStart = sc.Number; + + sc.MustGetNumber(); + if (sc.Number < 0 || sc.Number > 256) + { + sc.ScriptError ("The color range must be within positions [0,256]"); + } + if (sc.Number <= tparm.RangeStart) + { + sc.ScriptError ("The color range end position must be larger than the start position"); + } + tparm.RangeEnd = sc.Number; + } + else + { + tparm.RangeStart = tparm.RangeEnd + 1; + tparm.RangeEnd = 256; + if (tparm.RangeStart >= tparm.RangeEnd) + { + sc.ScriptError ("The color has too many ranges"); + } + } + parms.Push (tparm); + } + } + info.ParmLen[parmchoice] = parms.Size() - info.StartParm[parmchoice]; + if (info.ParmLen[0] == 0) + { + if (names[0] != NAME_Untranslated) + { + sc.ScriptError ("There must be at least one normal range for a color"); + } + } + else + { + if (names[0] == NAME_Untranslated) + { + sc.ScriptError ("The \"untranslated\" color must be left undefined"); + } + } + if (info.ParmLen[1] == 0 && names[0] != NAME_Untranslated) + { // If a console translation is unspecified, make it white, since the console + // font has no color information stored with it. + tparm.RangeStart = 0; + tparm.RangeEnd = 256; + tparm.Start[2] = tparm.Start[1] = tparm.Start[0] = 0; + tparm.End[2] = tparm.End[1] = tparm.End[0] = 255; + info.StartParm[1] = parms.Push (tparm); + info.ParmLen[1] = 1; + } + cinfo.ParmInfo = parminfo.Push (info); + // Record this color information for each name it goes by + for (i = 0; i < names.Size(); ++i) + { + // Redefine duplicates in-place + for (j = 0; j < colorinfo.Size(); ++j) + { + if (colorinfo[j].Name == names[i]) + { + colorinfo[j].ParmInfo = cinfo.ParmInfo; + colorinfo[j].LogColor = logcolor; + break; + } + } + if (j == colorinfo.Size()) + { + cinfo.Name = names[i]; + cinfo.LogColor = logcolor; + colorinfo.Push (cinfo); + } + } + } + } + // Make permananent copies of all the color information we found. + for (i = 0, index = 0; i < colorinfo.Size(); ++i) + { + TranslationMap tmap; + TempParmInfo *pinfo; + + tmap.Name = colorinfo[i].Name; + pinfo = &parminfo[colorinfo[i].ParmInfo]; + if (pinfo->Index < 0) + { + // Write out the set of remappings for this color. + for (k = 0; k < 2; ++k) + { + for (j = 0; j < pinfo->ParmLen[k]; ++j) + { + TranslationParms[k].Push (parms[pinfo->StartParm[k] + j]); + } + } + TranslationColors.Push (colorinfo[i].LogColor); + pinfo->Index = index++; + } + tmap.Number = pinfo->Index; + TranslationLookup.Push (tmap); + } + // Leave a terminating marker at the ends of the lists. + tparm.RangeStart = -1; + TranslationParms[0].Push (tparm); + TranslationParms[1].Push (tparm); + // Sort the translation lookups for fast binary searching. + qsort (&TranslationLookup[0], TranslationLookup.Size(), sizeof(TranslationLookup[0]), TranslationMapCompare); + + NumTextColors = index; + assert (NumTextColors >= NUM_TEXT_COLORS); +} + +//========================================================================== +// +// TranslationMapCompare +// +//========================================================================== + +static int TranslationMapCompare (const void *a, const void *b) +{ + return int(((const TranslationMap *)a)->Name.GetIndex()) - int(((const TranslationMap *)b)->Name.GetIndex()); +} + +//========================================================================== +// +// V_FindFontColor +// +// Returns the color number for a particular named color range. +// +//========================================================================== + +EColorRange V_FindFontColor (FName name) +{ + int min = 0, max = TranslationLookup.Size() - 1; + + while (min <= max) + { + unsigned int mid = (min + max) / 2; + const TranslationMap *probe = &TranslationLookup[mid]; + if (probe->Name == name) + { + return EColorRange(probe->Number); + } + else if (probe->Name < name) + { + min = mid + 1; + } + else + { + max = mid - 1; + } + } + return CR_UNTRANSLATED; +} + +//========================================================================== +// +// CreateLuminosityTranslationRanges +// +// Create universal remap ranges for hardware rendering. +// +//========================================================================== +static PalEntry* paletteptr; + +static void CreateLuminosityTranslationRanges() +{ + paletteptr = (PalEntry*)ImageArena.Alloc(256 * ((NumTextColors * 2)) * sizeof(PalEntry)); + for (int l = 0; l < 2; l++) + { + auto parmstart = &TranslationParms[l][0]; + // Put the data into the image arena where it gets deleted with the rest of the texture data. + for (int p = 0; p < NumTextColors; p++) + { + // Intended storage order is Range 1, variant 1 - Range 1, variant 2, Range 2, variant 1, and so on. + // The storage of the ranges forces us to go through this differently... + PalEntry* palette = paletteptr + p * 512 + l * 256; + for (int v = 0; v < 256; v++) + { + palette[v].b = palette[v].g = palette[v].r = (uint8_t)v; + } + if (p != CR_UNTRANSLATED) // This table skips the untranslated entry. Do I need to say that the stored data format is garbage? >) + { + for (int v = 0; v < 256; v++) + { + // Find the color range that this luminosity value lies within. + const TranslationParm* parms = parmstart - 1; + do + { + parms++; + if (parms->RangeStart <= v && parms->RangeEnd >= v) + break; + } while (parms[1].RangeStart > parms[0].RangeEnd); + + // Linearly interpolate to find out which color this luminosity level gets. + int rangev = ((v - parms->RangeStart) << 8) / (parms->RangeEnd - parms->RangeStart); + int r = ((parms->Start[0] << 8) + rangev * (parms->End[0] - parms->Start[0])) >> 8; // red + int g = ((parms->Start[1] << 8) + rangev * (parms->End[1] - parms->Start[1])) >> 8; // green + int b = ((parms->Start[2] << 8) + rangev * (parms->End[2] - parms->Start[2])) >> 8; // blue + palette[v].r = (uint8_t)clamp(r, 0, 255); + palette[v].g = (uint8_t)clamp(g, 0, 255); + palette[v].b = (uint8_t)clamp(b, 0, 255); + } + // Advance to the next color range. + while (parmstart[1].RangeStart > parmstart[0].RangeEnd) + { + parmstart++; + } + parmstart++; + } + } + } +} + +//========================================================================== +// +// V_ApplyLuminosityTranslation +// +// Applies the translation to a bitmap for texture generation. +// +//========================================================================== + +void V_ApplyLuminosityTranslation(const LuminosityTranslationDesc& lum, uint8_t* pixel, int size) +{ + int colorrange = lum.colorrange; + if (colorrange >= NumTextColors * 2) return; + int lum_min = lum.lum_min; + int lum_max = lum.lum_max; + int lum_range = (lum_max - lum_min + 1); + PalEntry* remap = paletteptr + colorrange * 256; + + for (int i = 0; i < size; i++, pixel += 4) + { + // we must also process the transparent pixels here to ensure proper filtering on the characters' edges. + int gray = PalEntry(255, pixel[2], pixel[1], pixel[0]).Luminance(); + int lumadjust = (gray - lum_min) * 255 / lum_range; + int index = clamp(lumadjust, 0, 255); + PalEntry newcol = remap[index]; + // extend the range if we find colors outside what initial analysis provided. + if (gray < lum_min && lum_min != 0) + { + newcol.r = newcol.r * gray / lum_min; + newcol.g = newcol.g * gray / lum_min; + newcol.b = newcol.b * gray / lum_min; + } + else if (gray > lum_max && lum_max != 0) + { + newcol.r = clamp(newcol.r * gray / lum_max, 0, 255); + newcol.g = clamp(newcol.g * gray / lum_max, 0, 255); + newcol.b = clamp(newcol.b * gray / lum_max, 0, 255); + } + pixel[0] = newcol.b; + pixel[1] = newcol.g; + pixel[2] = newcol.r; + } +} + +//========================================================================== +// +// SetDefaultTranslation +// +// Builds a translation to map the stock font to a mod provided replacement. +// This probably won't work that well if the original font is extremely colorful. +// +//========================================================================== + +static void CalcDefaultTranslation(FFont* base, int index) +{ + uint32_t othercolors[256] = {}; + base->RecordAllTextureColors(othercolors); + + TArray otherluminosity; + base->GetLuminosity(othercolors, otherluminosity); + + PalEntry *remap = &paletteptr[index * 256]; + memset(remap, 0, 1024); + + for (unsigned i = 0; i < 256; i++) + { + auto lum = otherluminosity[i]; + if (lum >= 0 && lum <= 1) + { + int lumidx = int(lum * 255); + remap[lumidx] = GPalette.BaseColors[i]; + remap[lumidx].a = 255; + } + } + + // todo: fill the gaps. + //remap[0] = 0; + int lowindex = 0; + while (lowindex < 255 && remap[lowindex].a == 0) lowindex++; + lowindex++; + int highindex = lowindex + 1; + + while (lowindex < 255) + { + while (highindex <= 255 && remap[highindex].a == 0) highindex++; + if (lowindex == 0) + { + for (int i = 0; i < highindex; i++) remap[i] = remap[highindex]; + lowindex = highindex++; + } + else if (highindex > 256) + { + for (int i = lowindex + 1; i < highindex; i++) remap[i] = remap[lowindex]; + break; + } + else + { + for (int i = lowindex + 1; i < highindex; i++) + { + PalEntry color1 = remap[lowindex]; + PalEntry color2 = remap[highindex]; + double weight = (i - lowindex) / double(highindex - lowindex); + int r = int(color1.r + weight * (color2.r - color1.r)); + int g = int(color1.g + weight * (color2.g - color1.g)); + int b = int(color1.b + weight * (color2.b - color1.b)); + r = clamp(r, 0, 255); + g = clamp(g, 0, 255); + b = clamp(b, 0, 255); + remap[i] = PalEntry(255, r, g, b); + } + lowindex = highindex++; + } + } + +} + +//========================================================================== +// +// V_LogColorFromColorRange +// +// Returns the color to use for text in the startup/error log window. +// +//========================================================================== + +PalEntry V_LogColorFromColorRange (EColorRange range) +{ + if ((unsigned int)range >= TranslationColors.Size()) + { // Return default color + return DEFAULT_LOG_COLOR; + } + return TranslationColors[range]; +} + +//========================================================================== +// +// V_ParseFontColor +// +// Given a pointer to a color identifier (presumably just after a color +// escape character), return the color it identifies and advances +// color_value to just past it. +// +//========================================================================== + +EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int boldcolor) +{ + const uint8_t *ch = color_value; + int newcolor = *ch++; + + if (newcolor == '-') // Normal + { + newcolor = normalcolor; + } + else if (newcolor == '+') // Bold + { + newcolor = boldcolor; + } + else if (newcolor == '!') // Team chat + { + newcolor = PrintColors[PRINT_TEAMCHAT]; + } + else if (newcolor == '*') // Chat + { + newcolor = PrintColors[PRINT_CHAT]; + } + else if (newcolor == '[') // Named + { + const uint8_t *namestart = ch; + while (*ch != ']' && *ch != '\0') + { + ch++; + } + FName rangename((const char *)namestart, int(ch - namestart), true); + if (*ch != '\0') + { + ch++; + } + newcolor = V_FindFontColor (rangename); + } + else if (newcolor >= 'A' && newcolor < NUM_TEXT_COLORS + 'A') // Standard, uppercase + { + newcolor -= 'A'; + } + else if (newcolor >= 'a' && newcolor < NUM_TEXT_COLORS + 'a') // Standard, lowercase + { + newcolor -= 'a'; + } + else // Incomplete! + { + color_value = ch - (newcolor == '\0'); + return CR_UNDEFINED; + } + color_value = ch; + return EColorRange(newcolor); +} + +//========================================================================== +// +// V_InitFonts +// +// Fixme: This really needs to be a bit more flexible +// and less rigidly tied to the original game data. +// +//========================================================================== + +void V_InitFonts() +{ + sheetBitmaps.Clear(); + CreateLuminosityTranslationRanges(); + V_InitCustomFonts(); + + FFont *CreateHexLumpFont(const char *fontname, int lump); + FFont *CreateHexLumpFont2(const char *fontname, int lump); + + auto lump = fileSystem.CheckNumForFullName("newconsolefont.hex", 0); // This is always loaded from gzdoom.pk3 to prevent overriding it with incomplete replacements. + if (lump == -1) I_FatalError("newconsolefont.hex not found"); // This font is needed - do not start up without it. + NewConsoleFont = CreateHexLumpFont("NewConsoleFont", lump); + NewSmallFont = CreateHexLumpFont2("NewSmallFont", lump); + CurrentConsoleFont = NewConsoleFont; + ConFont = V_GetFont("ConsoleFont", "CONFONT"); + V_GetFont("IndexFont", "INDEXFON"); // detect potential replacements for this one. +} + +void V_LoadTranslations() +{ + for (auto font = FFont::FirstFont; font; font = font->Next) + { + if (!font->noTranslate) font->LoadTranslations(); + } + + if (BigFont) + { + CalcDefaultTranslation(BigFont, CR_UNTRANSLATED * 2 + 1); + if (OriginalBigFont != nullptr && OriginalBigFont != BigFont) + { + assert(IsLuminosityTranslation(OriginalBigFont->Translations[0])); + int sometrans = OriginalBigFont->Translations[0].index(); + sometrans &= ~(0x3fff << 16); + sometrans |= (CR_UNTRANSLATED * 2 + 1) << 16; + OriginalBigFont->Translations[CR_UNTRANSLATED] = FTranslationID::fromInt(sometrans); + OriginalBigFont->forceremap = true; + } + } + if (SmallFont) + { + CalcDefaultTranslation(SmallFont, CR_UNTRANSLATED * 2); + if (OriginalSmallFont != nullptr && OriginalSmallFont != SmallFont) + { + assert(IsLuminosityTranslation(OriginalSmallFont->Translations[0])); + int sometrans = OriginalSmallFont->Translations[0].index(); + sometrans &= ~(0x3fff << 16); + sometrans |= (CR_UNTRANSLATED * 2) << 16; + OriginalSmallFont->Translations[CR_UNTRANSLATED] = FTranslationID::fromInt(sometrans); + OriginalSmallFont->forceremap = true; + } + if (NewSmallFont != nullptr) + { + assert(IsLuminosityTranslation(NewSmallFont->Translations[0])); + int sometrans = NewSmallFont->Translations[0].index(); + sometrans &= ~(0x3fff << 16); + sometrans |= (CR_UNTRANSLATED * 2) << 16; + NewSmallFont->Translations[CR_UNTRANSLATED] = FTranslationID::fromInt(sometrans); + NewSmallFont->forceremap = true; + } + } + translationsLoaded = true; +} + + +void V_ClearFonts() +{ + while (FFont::FirstFont != nullptr) + { + delete FFont::FirstFont; + } + FFont::FirstFont = nullptr; + AlternativeSmallFont = OriginalSmallFont = CurrentConsoleFont = NewSmallFont = NewConsoleFont = SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = nullptr; + sheetBitmaps.Clear(); +} + +//========================================================================== +// +// CleanseString +// +// Does some mild sanity checking on a string: If it ends with an incomplete +// color escape, the escape is removed. +// +//========================================================================== + +char* CleanseString(char* str) +{ + char* escape = strrchr(str, TEXTCOLOR_ESCAPE); + if (escape != NULL) + { + if (escape[1] == '\0') + { + *escape = '\0'; + } + else if (escape[1] == '[') + { + char* close = strchr(escape + 2, ']'); + if (close == NULL) + { + *escape = '\0'; + } + } + } + return str; +} + diff --git a/src/common/fonts/v_font.h b/src/common/fonts/v_font.h new file mode 100644 index 00000000000..4e7596ef832 --- /dev/null +++ b/src/common/fonts/v_font.h @@ -0,0 +1,227 @@ +#pragma once +/* +** v_font.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + + +#include "filesystem.h" +#include "vectors.h" +#include "palentry.h" +#include "name.h" +#include "palettecontainer.h" + +class FGameTexture; +struct FRemapTable; +class FFont; + +FFont* V_GetFont(const char* fontname, const char* fontlumpname = nullptr); + +enum EColorRange : int +{ + CR_UNDEFINED = -1, + CR_NATIVEPAL = -1, + CR_BRICK, + CR_TAN, + CR_GRAY, + CR_GREY = CR_GRAY, + CR_GREEN, + CR_BROWN, + CR_GOLD, + CR_RED, + CR_BLUE, + CR_ORANGE, + CR_WHITE, + CR_YELLOW, + CR_UNTRANSLATED, + CR_BLACK, + CR_LIGHTBLUE, + CR_CREAM, + CR_OLIVE, + CR_DARKGREEN, + CR_DARKRED, + CR_DARKBROWN, + CR_PURPLE, + CR_DARKGRAY, + CR_CYAN, + CR_ICE, + CR_FIRE, + CR_SAPPHIRE, + CR_TEAL, + NUM_TEXT_COLORS, +}; + +extern int NumTextColors; + +using GlyphSet = TMap; + +class FFont +{ + friend void V_LoadTranslations(); +public: + + enum EFontType + { + Unknown, + Folder, + Multilump, + Fon1, + Fon2, + BMF, + Custom + }; + + FFont (const char *fontname, const char *nametemplate, const char *filetemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false, bool iwadonly = false, bool doomtemplate = false, GlyphSet *baseGlpyphs = nullptr); + FFont(int lump, FName nm = NAME_None); + virtual ~FFont (); + + virtual FGameTexture *GetChar (int code, int translation, int *const width) const; + virtual int GetCharWidth (int code) const; + FTranslationID GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; + int GetLump() const { return Lump; } + int GetSpaceWidth () const { return SpaceWidth; } + int GetHeight () const { return FontHeight; } + int GetDefaultKerning () const { return GlobalKerning; } + int GetMaxAscender(const uint8_t* text) const; + int GetMaxAscender(const char* text) const { return GetMaxAscender((uint8_t*)text); } + int GetMaxAscender(const FString &text) const { return GetMaxAscender((uint8_t*)text.GetChars()); } + virtual void LoadTranslations(); + FName GetName() const { return FontName; } + + static FFont *FindFont(FName fontname); + + // Return width of string in pixels (unscaled) + int StringWidth (const uint8_t *str, int spacing = 0) const; + inline int StringWidth (const char *str, int spacing = 0) const { return StringWidth ((const uint8_t *)str, spacing); } + inline int StringWidth (const FString &str, int spacing = 0) const { return StringWidth ((const uint8_t *)str.GetChars(), spacing); } + + // Checks if the font contains all characters to print this text. + bool CanPrint(const uint8_t *str) const; + inline bool CanPrint(const char *str) const { return CanPrint((const uint8_t *)str); } + inline bool CanPrint(const FString &str) const { return CanPrint((const uint8_t *)str.GetChars()); } + + inline FFont* AltFont() + { + if (AltFontName != NAME_None) return V_GetFont(AltFontName.GetChars()); + return nullptr; + } + + int GetCharCode(int code, bool needpic) const; + char GetCursor() const { return Cursor; } + void SetCursor(char c) { Cursor = c; } + void SetKerning(int c) { GlobalKerning = c; } + void SetHeight(int c) { FontHeight = c; } + void ClearOffsets(); + bool NoTranslate() const { return noTranslate; } + virtual void RecordAllTextureColors(uint32_t *usedcolors); + void CheckCase(); + void SetName(FName nm) { FontName = nm; } + + int GetDisplacement() const { return Displacement; } + + static int GetLuminosity(uint32_t* colorsused, TArray& Luminosity, int* minlum = nullptr, int* maxlum = nullptr); + EFontType GetType() const { return Type; } + + friend void V_InitCustomFonts(); + + void CopyFrom(const FFont& other) + { + Type = other.Type; + FirstChar = other.FirstChar; + LastChar = other.LastChar; + SpaceWidth = other.SpaceWidth; + FontHeight = other.FontHeight; + GlobalKerning = other.GlobalKerning; + TranslationType = other.TranslationType; + Displacement = other.Displacement; + Cursor = other.Cursor; + noTranslate = other.noTranslate; + MixedCase = other.MixedCase; + forceremap = other.forceremap; + Chars = other.Chars; + Translations = other.Translations; + lowercaselatinonly = other.lowercaselatinonly; + Lump = other.Lump; + } + +protected: + + void FixXMoves(); + + void ReadSheetFont(std::vector &folderdata, int width, int height, const DVector2 &Scale); + + EFontType Type = EFontType::Unknown; + FName AltFontName = NAME_None; + int FirstChar, LastChar; + int SpaceWidth; + int FontHeight; + int GlobalKerning; + int TranslationType = 0; + int Displacement = 0; + int16_t MinLum = -1, MaxLum = -1; + char Cursor; + bool noTranslate = false; + bool MixedCase = false; + bool forceremap = false; + bool lowercaselatinonly = false; + struct CharData + { + FGameTexture *OriginalPic = nullptr; + int XMove = INT_MIN; + }; + TArray Chars; + TArray Translations; + + int Lump; + FName FontName = NAME_None; + FFont *Next; + + static FFont *FirstFont; + friend struct FontsDeleter; + + friend void V_ClearFonts(); + friend void V_InitFonts(); +}; + +extern FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont, *OriginalSmallFont, *AlternativeSmallFont, *OriginalBigFont, *AlternativeBigFont; + +void V_InitFonts(); +void V_ClearFonts(); +EColorRange V_FindFontColor (FName name); +PalEntry V_LogColorFromColorRange (EColorRange range); +EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int boldcolor); +void V_InitFontColors(); +char* CleanseString(char* str); +void V_ApplyLuminosityTranslation(const LuminosityTranslationDesc& lum, uint8_t* pixel, int size); +void V_LoadTranslations(); +class FBitmap; + + diff --git a/src/common/fonts/v_text.cpp b/src/common/fonts/v_text.cpp new file mode 100644 index 00000000000..267b412bdfe --- /dev/null +++ b/src/common/fonts/v_text.cpp @@ -0,0 +1,331 @@ +/* +** v_text.cpp +** Draws text to a canvas. Also has a text line-breaker thingy. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include + +#include "v_text.h" +#include "v_font.h" +#include "utf8.h" + +#include "filesystem.h" + +#include "gstrings.h" +#include "vm.h" +#include "serializer.h" +#include "c_cvars.h" + +//========================================================================== +// +// Break long lines of text into multiple lines no longer than maxwidth pixels +// +//========================================================================== + +static void breakit (FBrokenLines *line, FFont *font, const uint8_t *start, const uint8_t *stop, FString &linecolor) +{ + if (!linecolor.IsEmpty()) + { + line->Text = TEXTCOLOR_ESCAPE; + line->Text += linecolor; + } + line->Text.AppendCStrPart ((const char *)start, stop - start); + line->Width = font->StringWidth (line->Text); +} + +TArray V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bool preservecolor) +{ + TArray Lines(128); + + const uint8_t *space = NULL, *start = string; + int c, w, nw; + FString lastcolor, linecolor; + bool lastWasSpace = false; + int kerning = font->GetDefaultKerning (); + + // The real isspace is a bit too badly defined, so use our own one + auto myisspace = [](int ch) { return ch == '\t' || ch == '\r' || ch == '\n' || ch == ' '; }; + + w = 0; + + while ( (c = GetCharFromString(string)) ) + { + if (c == TEXTCOLOR_ESCAPE) + { + if (*string) + { + if (*string == '[') + { + while (*string != ']' && *string != '\0') + { + string++; + } + if (*string != '\0') + { + string++; + } + } + } + continue; + } + + if (myisspace(c)) + { + if (!lastWasSpace) + { + space = string - 1; + lastWasSpace = true; + } + } + else + { + lastWasSpace = false; + } + + nw = font->GetCharWidth (c); + + if ((w > 0 && w + nw > maxwidth) || c == '\n') + { // Time to break the line + if (!space) + { + for (space = string - 1; (*space & 0xc0) == 0x80 && space > start; space--); + } + + auto index = Lines.Reserve(1); + for (const uint8_t* pos = start; pos < space; pos++) + { + if (*pos == TEXTCOLOR_ESCAPE) + { + pos++; + if (*pos) + { + if (*pos == '[') + { + const uint8_t* cstart = pos; + while (*pos != ']' && *pos != '\0') + { + pos++; + } + if (*pos != '\0') + { + pos++; + } + lastcolor = FString((const char*)cstart, pos - cstart); + } + else + { + lastcolor = *pos++; + } + } + } + } + breakit (&Lines[index], font, start, space, linecolor); + if (c == '\n' && !preservecolor) + { + lastcolor = ""; // Why, oh why, did I do it like this? + } + linecolor = lastcolor; + + w = 0; + lastWasSpace = false; + start = space; + space = NULL; + + while (*start && myisspace (*start) && *start != '\n') + start++; + if (*start == '\n') + start++; + else + while (*start && myisspace (*start)) + start++; + string = start; + } + else + { + w += nw + kerning; + } + } + + // String here is pointing one character after the '\0' + if (--string - start >= 1) + { + const uint8_t *s = start; + + while (s < string) + { + // If there is any non-white space in the remainder of the string, add it. + if (!myisspace (*s++)) + { + auto i = Lines.Reserve(1); + breakit (&Lines[i], font, start, string, linecolor); + break; + } + } + } + return Lines; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, FBrokenLines& g, FBrokenLines *def) +{ + if (arc.BeginObject(key)) + { + arc("text", g.Text) + ("width", g.Width) + .EndObject(); + } + return arc; +} + + + +class DBrokenLines : public DObject +{ + DECLARE_CLASS(DBrokenLines, DObject) + +public: + TArray mBroken; + + DBrokenLines() = default; + + DBrokenLines(TArray &broken) + { + mBroken = std::move(broken); + } + + void Serialize(FSerializer &arc) override + { + arc("lines", mBroken); + } +}; + +IMPLEMENT_CLASS(DBrokenLines, false, false); + +DEFINE_ACTION_FUNCTION(DBrokenLines, Count) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + ACTION_RETURN_INT(self->mBroken.Size()); +} + +DEFINE_ACTION_FUNCTION(DBrokenLines, StringWidth) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + PARAM_INT(index); + ACTION_RETURN_INT((unsigned)index >= self->mBroken.Size()? -1 : self->mBroken[index].Width); +} + +DEFINE_ACTION_FUNCTION(DBrokenLines, StringAt) +{ + + PARAM_SELF_PROLOGUE(DBrokenLines); + PARAM_INT(index); + ACTION_RETURN_STRING((unsigned)index >= self->mBroken.Size() ? -1 : self->mBroken[index].Text); +} + +DEFINE_ACTION_FUNCTION(FFont, BreakLines) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(text); + PARAM_INT(maxwidth); + + auto broken = V_BreakLines(self, maxwidth, text, true); + ACTION_RETURN_OBJECT(Create(broken)); +} + + +bool generic_ui; +bool special_i; + +bool CheckFontComplete(FFont* font) +{ + // Also check if the SmallFont contains all characters this language needs. + // If not, switch back to the original one. + return font->CanPrint(GStrings.CheckString("REQUIRED_CHARACTERS")); +} + +void UpdateGenericUI(bool cvar) +{ + auto switchstr = GStrings.CheckString("USE_GENERIC_FONT"); + generic_ui = (cvar || (switchstr && strtoll(switchstr, nullptr, 0))); + if (!generic_ui) + { + // Use the mod's SmallFont if it is complete. + // Otherwise use the stock Smallfont if it is complete. + // If none is complete, fall back to the VGA font. + // The font being set here will be used in 3 places: Notifications, centered messages and menu confirmations. + if (CheckFontComplete(SmallFont)) + { + AlternativeSmallFont = SmallFont; + } + else if (OriginalSmallFont && CheckFontComplete(OriginalSmallFont)) + { + AlternativeSmallFont = OriginalSmallFont; + } + else + { + AlternativeSmallFont = NewSmallFont; + } + + if (CheckFontComplete(BigFont)) + { + AlternativeBigFont = BigFont; + } + else if (OriginalBigFont && CheckFontComplete(OriginalBigFont)) + { + AlternativeBigFont = OriginalBigFont; + } + else + { + AlternativeBigFont = NewSmallFont; + } + } + // Turkish i crap. What a mess, just to save two code points... :( + switchstr = GStrings.CheckString("REQUIRED_CHARACTERS"); + special_i = switchstr && strstr(switchstr, "\xc4\xb0") != nullptr; // capital dotted i (İ). + if (special_i) + { + upperforlower['i'] = 0x130; + lowerforupper['I'] = 0x131; + } + else + { + upperforlower['i'] = 'I'; + lowerforupper['I'] = 'i'; + } +} + +CUSTOM_CVAR(Bool, ui_generic, false, CVAR_NOINITCALL) // This is for allowing to test the generic font system with all languages +{ + UpdateGenericUI(self); +} diff --git a/src/common/fonts/v_text.h b/src/common/fonts/v_text.h new file mode 100644 index 00000000000..7dbc13cdf24 --- /dev/null +++ b/src/common/fonts/v_text.h @@ -0,0 +1,52 @@ +/* +** v_text.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __V_TEXT_H__ +#define __V_TEXT_H__ + +#include "v_font.h" +#include "printf.h" + +struct FBrokenLines +{ + unsigned Width; + FString Text; +}; + +TArray V_BreakLines (FFont *font, int maxwidth, const uint8_t *str, bool preservecolor = false); +inline TArray V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false) + { return V_BreakLines (font, maxwidth, (const uint8_t *)str, preservecolor); } +inline TArray V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false) + { return V_BreakLines (font, maxwidth, (const uint8_t *)str.GetChars(), preservecolor); } + +#endif //__V_TEXT_H__ diff --git a/src/menu/joystickmenu.cpp b/src/common/menu/joystickmenu.cpp similarity index 81% rename from src/menu/joystickmenu.cpp rename to src/common/menu/joystickmenu.cpp index 388c012dfec..3d3e881b165 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/common/menu/joystickmenu.cpp @@ -32,7 +32,7 @@ ** */ -#include "menu/menu.h" +#include "menu.h" #include "m_joy.h" #include "vm.h" @@ -119,6 +119,40 @@ DEFINE_ACTION_FUNCTION(IJoystickConfig, GetNumAxes) ACTION_RETURN_INT(self->GetNumAxes()); } +DEFINE_ACTION_FUNCTION(IJoystickConfig, GetEnabled) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + ACTION_RETURN_BOOL(self->GetEnabled()); +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, SetEnabled) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + PARAM_BOOL(enabled); + self->SetEnabled(enabled); + return 0; +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, AllowsEnabledInBackground) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + ACTION_RETURN_BOOL(self->AllowsEnabledInBackground()); +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, GetEnabledInBackground) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + ACTION_RETURN_BOOL(self->GetEnabledInBackground()); +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, SetEnabledInBackground) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + PARAM_BOOL(enabled); + self->SetEnabledInBackground(enabled); + return 0; +} + void UpdateJoystickMenu(IJoystickConfig *selected) { @@ -160,12 +194,12 @@ void UpdateJoystickMenu(IJoystickConfig *selected) it = opt->GetItem("ConnectMessage2"); if (it != nullptr) it->SetValue(0, !use_joystick); - for (int i = 0; i < (int)Joysticks.Size(); ++i) + for (int ii = 0; ii < (int)Joysticks.Size(); ++ii) { - it = CreateOptionMenuItemJoyConfigMenu(Joysticks[i]->GetName(), Joysticks[i]); + it = CreateOptionMenuItemJoyConfigMenu(Joysticks[ii]->GetName().GetChars(), Joysticks[ii]); GC::WriteBarrier(opt, it); opt->mItems.Push(it); - if (i == itemnum) opt->mSelectedItem = opt->mItems.Size(); + if (ii == itemnum) opt->mSelectedItem = opt->mItems.Size(); } if (opt->mSelectedItem >= (int)opt->mItems.Size()) { @@ -179,15 +213,15 @@ void UpdateJoystickMenu(IJoystickConfig *selected) auto p = CurrentMenu->PointerVar("mJoy"); if (p != nullptr) { - unsigned i; - for (i = 0; i < Joysticks.Size(); ++i) + unsigned ii; + for (ii = 0; ii < Joysticks.Size(); ++ii) { - if (Joysticks[i] == p) + if (Joysticks[ii] == p) { break; } } - if (i == Joysticks.Size()) + if (ii == Joysticks.Size()) { CurrentMenu->Close(); } diff --git a/src/common/menu/menu.cpp b/src/common/menu/menu.cpp new file mode 100644 index 00000000000..a07dfd36fc9 --- /dev/null +++ b/src/common/menu/menu.cpp @@ -0,0 +1,1247 @@ +/* +** menu.cpp +** Menu base class and global interface +** +**--------------------------------------------------------------------------- +** Copyright 2010 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_dispatch.h" +#include "d_gui.h" +#include "c_buttons.h" +#include "c_console.h" +#include "c_bind.h" +#include "d_eventbase.h" +#include "g_input.h" +#include "configfile.h" +#include "gstrings.h" +#include "menu.h" +#include "vm.h" +#include "v_video.h" +#include "i_system.h" +#include "types.h" +#include "texturemanager.h" +#include "v_draw.h" +#include "vm.h" +#include "gamestate.h" +#include "i_interface.h" +#include "menustate.h" +#include "i_time.h" +#include "printf.h" + +int DMenu::InMenu; +static ScaleOverrider *CurrentScaleOverrider; +// +// Todo: Move these elsewhere +// +CVAR (Int, m_showinputgrid, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, m_blockcontrollers, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + +CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE) +CVAR(Int, m_use_mouse, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR(Int, m_show_backbutton, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR(Bool, m_cleanscale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +// Option Search +CVAR(Bool, os_isanyof, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + + +static DMenu *GetCurrentMenu() +{ + return CurrentMenu; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DMenu, GetCurrentMenu, GetCurrentMenu) +{ + ACTION_RETURN_OBJECT(CurrentMenu); +} + +static int GetMenuTime() +{ + return MenuTime; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DMenu, MenuTime, GetMenuTime) +{ + ACTION_RETURN_INT(MenuTime); +} + +EMenuState menuactive; +FButtonStatus MenuButtons[NUM_MKEYS]; +int MenuButtonTickers[NUM_MKEYS]; +bool MenuButtonOrigin[NUM_MKEYS]; +int BackbuttonTime; +float BackbuttonAlpha; +static bool MenuEnabled = true; +DMenu *CurrentMenu; +int MenuTime; +DObject* menuDelegate; +static MenuTransition transition; + + +extern PClass *DefaultListMenuClass; +extern PClass *DefaultOptionMenuClass; + + +#define KEY_REPEAT_DELAY (GameTicRate*5/12) +#define KEY_REPEAT_RATE (3) + +//============================================================================ +// +// +// +//============================================================================ + +IMPLEMENT_CLASS(DMenuDescriptor, false, false) +IMPLEMENT_CLASS(DListMenuDescriptor, false, false) +IMPLEMENT_CLASS(DOptionMenuDescriptor, false, false) +IMPLEMENT_CLASS(DImageScrollerDescriptor, false, false) + +DMenuDescriptor *GetMenuDescriptor(int name) +{ + DMenuDescriptor **desc = MenuDescriptors.CheckKey(ENamedName(name)); + return desc ? *desc : nullptr; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DMenuDescriptor, GetDescriptor, GetMenuDescriptor) +{ + PARAM_PROLOGUE; + PARAM_NAME(name); + ACTION_RETURN_OBJECT(GetMenuDescriptor(name.GetIndex())); +} + +size_t DMenuDescriptor::PropagateMark() +{ + for (auto item : mItems) GC::Mark(item); + return 0; +} + + +void DListMenuDescriptor::Reset() +{ + // Reset the default settings (ignore all other values in the struct) + mSelectOfsX = 0; + mSelectOfsY = 0; + mSelector.SetInvalid(); + mDisplayTop = 0; + mXpos = 0; + mYpos = 0; + mLinespacing = 0; + mNetgameMessage = ""; + mFont = NULL; + mFontColor = CR_UNTRANSLATED; + mFontColor2 = CR_UNTRANSLATED; + mFromEngine = false; + mVirtWidth = mVirtHeight = -1; // default to clean scaling +} + +DEFINE_ACTION_FUNCTION(DListMenuDescriptor, Reset) +{ + PARAM_SELF_PROLOGUE(DListMenuDescriptor); + self->Reset(); + return 0; +} + + +void DOptionMenuDescriptor::Reset() +{ + // Reset the default settings (ignore all other values in the struct) + mPosition = 0; + mScrollTop = 0; + mIndent = 0; + mDontDim = 0; + mFont = BigUpper; +} + +void M_MarkMenus() +{ + MenuDescriptorList::Iterator it(MenuDescriptors); + MenuDescriptorList::Pair *pair; + while (it.NextPair(pair)) + { + GC::Mark(pair->Value); + } + GC::Mark(CurrentMenu); + GC::Mark(menuDelegate); + GC::Mark(transition.previous); + GC::Mark(transition.current); +} + + +//============================================================================ +// +// Transition animation +// +//============================================================================ + +bool MenuTransition::StartTransition(DMenu* from, DMenu* to, MenuTransitionType animtype) +{ + if (!from->canAnimate() || !to->canAnimate() || animtype == MA_None) + { + return false; + } + else + { + start = I_GetTimeNS() * (120. / 1'000'000'000.); + length = 30; + dir = animtype == MA_Advance ? 1 : -1; + destroyprev = animtype == MA_Return; + previous = from; + current = to; + if (from) GC::WriteBarrier(from); + if (to) GC::WriteBarrier(to); + return true; + } +} + +bool MenuTransition::Draw() +{ + double now = I_GetTimeNS() * (120. / 1'000'000'000); + if (now < start + length) + { + double factor = screen->GetWidth()/2; + double phase = (now - start) / double(length) * M_PI + M_PI / 2; + DVector2 origin; + + origin.Y = 0; + origin.X = factor * dir * (sin(phase) - 1.); + twod->SetOffset(origin); + previous->CallDrawer(); + origin.X = factor * dir * (sin(phase) + 1.); + twod->SetOffset(origin); + current->CallDrawer(); + origin = { 0,0 }; + twod->SetOffset(origin); + return true; + } + if (destroyprev && previous) previous->Destroy(); + previous = nullptr; + current = nullptr; + return false; +} + + +//============================================================================ +// +// DMenu base class +// +//============================================================================ + +IMPLEMENT_CLASS(DMenu, false, true) + +IMPLEMENT_POINTERS_START(DMenu) + IMPLEMENT_POINTER(mParentMenu) +IMPLEMENT_POINTERS_END + +DMenu::DMenu(DMenu *parent) +{ + mParentMenu = parent; + mMouseCapture = false; + mBackbuttonSelected = false; + DontDim = false; + GC::WriteBarrier(this, parent); +} + +//============================================================================= +// +// +// +//============================================================================= + +bool DMenu::CallResponder(event_t *ev) +{ + if (ev->type == EV_GUI_Event) + { + IFVIRTUAL(DMenu, OnUIEvent) + { + FUiEvent e = ev; + VMValue params[] = { (DObject*)this, &e }; + int retval; + VMReturn ret(&retval); + InMenu++; + VMCall(func, params, 2, &ret, 1); + InMenu--; + return !!retval; + } + } + else + { + IFVIRTUAL(DMenu, OnInputEvent) + { + FInputEvent e = ev; + VMValue params[] = { (DObject*)this, &e }; + int retval; + VMReturn ret(&retval); + InMenu++; + VMCall(func, params, 2, &ret, 1); + InMenu--; + return !!retval; + } + } + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) +{ + IFVIRTUAL(DMenu, MenuEvent) + { + VMValue params[] = { (DObject*)this, mkey, fromcontroller }; + int retval; + VMReturn ret(&retval); + InMenu++; + VMCall(func, params, 3, &ret, 1); + InMenu--; + return !!retval; + } + else return false; +} +//============================================================================= +// +// +// +//============================================================================= + +static void SetMouseCapture(bool on) +{ + if (on) I_SetMouseCapture(); + else I_ReleaseMouseCapture(); +} +DEFINE_ACTION_FUNCTION_NATIVE(DMenu, SetMouseCapture, SetMouseCapture) +{ + PARAM_PROLOGUE; + PARAM_BOOL(on); + SetMouseCapture(on); + return 0; +} + +void DMenu::Close () +{ + if (CurrentMenu == nullptr) return; // double closing can happen in the save menu. + assert(CurrentMenu == this); + CurrentMenu = mParentMenu; + + if (CurrentMenu != nullptr) + { + GC::WriteBarrier(CurrentMenu); + IFVIRTUALPTR(CurrentMenu, DMenu, OnReturn) + { + VMValue params[] = { CurrentMenu }; + VMCall(func, params, 1, nullptr, 0); + } + if (transition.StartTransition(this, CurrentMenu, MA_Return)) + { + return; + } + } + + Destroy(); + if (CurrentMenu == nullptr) + { + M_ClearMenus(); + } +} + + +static void Close(DMenu *menu) +{ + menu->Close(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DMenu, Close, Close) +{ + PARAM_SELF_PROLOGUE(DMenu); + self->Close(); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +void DMenu::CallTicker() +{ + IFVIRTUAL(DMenu, Ticker) + { + VMValue params[] = { (DObject*)this }; + VMCall(func, params, 1, nullptr, 0); + } +} + + +void DMenu::CallDrawer() +{ + IFVIRTUAL(DMenu, Drawer) + { + VMValue params[] = { (DObject*)this }; + VMCall(func, params, 1, nullptr, 0); + twod->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. + } +} + +bool DMenu::TranslateKeyboardEvents() +{ + IFVIRTUAL(DMenu, TranslateKeyboardEvents) + { + VMValue params[] = { (DObject*)this }; + int retval; + VMReturn ret(&retval); + VMCall(func, params, countof(params), &ret, 1); + return !!retval; + } + return true; +} + +//============================================================================= +// +// +// +//============================================================================= + + +void M_StartControlPanel (bool makesound, bool scaleoverride) +{ + if (sysCallbacks.OnMenuOpen) sysCallbacks.OnMenuOpen(makesound); + // intro might call this repeatedly + if (CurrentMenu != nullptr) + return; + + buttonMap.ResetButtonStates (); + for (int i = 0; i < NUM_MKEYS; ++i) + { + MenuButtons[i].ReleaseKey(0); + } + + C_HideConsole (); // [RH] Make sure console goes bye bye. + menuactive = MENU_On; + BackbuttonTime = 0; + BackbuttonAlpha = 0; + if (scaleoverride && !CurrentScaleOverrider) CurrentScaleOverrider = new ScaleOverrider(twod); + else if (!scaleoverride && CurrentScaleOverrider) + { + delete CurrentScaleOverrider; + CurrentScaleOverrider = nullptr; + } +} + + +bool M_IsAnimated() +{ + if (ConsoleState == c_down) return false; + if (!CurrentMenu) return false; + if (CurrentMenu->Animated) return true; + if (transition.previous) return true; + return false; +} + + +//============================================================================= +// +// +// +//============================================================================= + +void M_ActivateMenu(DMenu *menu) +{ + if (menuactive == MENU_Off) menuactive = MENU_On; + if (CurrentMenu != nullptr) + { + if (CurrentMenu->mMouseCapture) + { + CurrentMenu->mMouseCapture = false; + I_ReleaseMouseCapture(); + } + transition.StartTransition(CurrentMenu, menu, MA_Advance); + } + CurrentMenu = menu; + GC::WriteBarrier(CurrentMenu); +} + +DEFINE_ACTION_FUNCTION(DMenu, ActivateMenu) +{ + PARAM_SELF_PROLOGUE(DMenu); + M_ActivateMenu(self); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +void M_SetMenu(FName menu, int param) +{ + if (sysCallbacks.SetSpecialMenu && !sysCallbacks.SetSpecialMenu(menu, param)) return; + + DMenuDescriptor **desc = MenuDescriptors.CheckKey(menu); + if (desc != nullptr) + { + + if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) + { + DListMenuDescriptor *ld = static_cast(*desc); + if (ld->mAutoselect >= 0 && ld->mAutoselect < (int)ld->mItems.Size()) + { + // recursively activate the autoselected item without ever creating this menu. + ld->mItems[ld->mAutoselect]->Activate(); + } + else + { + PClass *cls = ld->mClass; + if (cls == nullptr) cls = DefaultListMenuClass; + if (cls == nullptr) cls = PClass::FindClass("ListMenu"); + + DMenu *newmenu = (DMenu *)cls->CreateNew(); + IFVIRTUALPTRNAME(newmenu, "ListMenu", Init) + { + VMValue params[3] = { newmenu, CurrentMenu, ld }; + VMCall(func, params, 3, nullptr, 0); + } + M_ActivateMenu(newmenu); + } + } + else if ((*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) + { + DOptionMenuDescriptor *ld = static_cast(*desc); + PClass *cls = ld->mClass; + if (cls == nullptr) cls = DefaultOptionMenuClass; + if (cls == nullptr) cls = PClass::FindClass("OptionMenu"); + + DMenu *newmenu = (DMenu*)cls->CreateNew(); + IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init) + { + VMValue params[3] = { newmenu, CurrentMenu, ld }; + VMCall(func, params, 3, nullptr, 0); + } + M_ActivateMenu(newmenu); + } + else if ((*desc)->IsKindOf(RUNTIME_CLASS(DImageScrollerDescriptor))) + { + auto ld = static_cast(*desc); + PClass* cls = ld->mClass; + if (cls == nullptr) cls = DefaultOptionMenuClass; + if (cls == nullptr) cls = PClass::FindClass("ImageScrollerMenu"); + + DMenu* newmenu = (DMenu*)cls->CreateNew(); + IFVIRTUALPTRNAME(newmenu, "ImageScrollerMenu", Init) + { + VMValue params[3] = { newmenu, CurrentMenu, ld }; + VMCall(func, params, 3, nullptr, 0); + } + M_ActivateMenu(newmenu); + } + return; + } + else + { + PClass *menuclass = PClass::FindClass(menu); + if (menuclass != nullptr) + { + if (menuclass->IsDescendantOf("GenericMenu")) + { + DMenu *newmenu = (DMenu*)menuclass->CreateNew(); + + IFVIRTUALPTRNAME(newmenu, "GenericMenu", Init) + { + VMValue params[3] = { newmenu, CurrentMenu }; + VMCall(func, params, 2, nullptr, 0); + } + M_ActivateMenu(newmenu); + return; + } + } + } + Printf("Attempting to open menu of unknown type '%s'\n", menu.GetChars()); + M_ClearMenus(); +} + +DEFINE_ACTION_FUNCTION(DMenu, SetMenu) +{ + PARAM_PROLOGUE; + PARAM_NAME(menu); + PARAM_INT(mparam); + M_SetMenu(menu, mparam); + return 0; +} +//============================================================================= +// +// +// +//============================================================================= + +bool M_Responder (event_t *ev) +{ + int ch = 0; + bool keyup = false; + int mkey = NUM_MKEYS; + bool fromcontroller = true; + + if (chatmodeon) + { + return false; + } + + if (CurrentMenu != nullptr && menuactive != MENU_Off) + { + // There are a few input sources we are interested in: + // + // EV_KeyDown / EV_KeyUp : joysticks/gamepads/controllers + // EV_GUI_KeyDown / EV_GUI_KeyUp : the keyboard + // EV_GUI_Char : printable characters, which we want in string input mode + // + // This code previously listened for EV_GUI_KeyRepeat to handle repeating + // in the menus, but that doesn't work with gamepads, so now we combine + // the multiple inputs into buttons and handle the repetition manually. + if (ev->type == EV_GUI_Event) + { + fromcontroller = false; + if (ev->subtype == EV_GUI_KeyRepeat) + { + // We do our own key repeat handling but still want to eat the + // OS's repeated keys. + if (CurrentMenu->TranslateKeyboardEvents()) return true; + else return CurrentMenu->CallResponder(ev); + } + else if (ev->subtype == EV_GUI_BackButtonDown || ev->subtype == EV_GUI_BackButtonUp) + { + mkey = MKEY_Back; + keyup = ev->subtype == EV_GUI_BackButtonUp; + } + else if (ev->subtype != EV_GUI_KeyDown && ev->subtype != EV_GUI_KeyUp) + { + // do we want mouse input? + if (ev->subtype >= EV_GUI_FirstMouseEvent && ev->subtype <= EV_GUI_LastMouseEvent) + { + if (!m_use_mouse) + return true; + } + + // pass everything else on to the current menu + return CurrentMenu->CallResponder(ev); + } + else if (CurrentMenu->TranslateKeyboardEvents()) + { + ch = ev->data1; + keyup = ev->subtype == EV_GUI_KeyUp; + switch (ch) + { + case GK_BACK: mkey = MKEY_Back; break; + case GK_ESCAPE: mkey = MKEY_Back; break; + case GK_RETURN: mkey = MKEY_Enter; break; + case GK_UP: mkey = MKEY_Up; break; + case GK_DOWN: mkey = MKEY_Down; break; + case GK_LEFT: mkey = MKEY_Left; break; + case GK_RIGHT: mkey = MKEY_Right; break; + case GK_BACKSPACE: mkey = MKEY_Clear; break; + case GK_PGUP: mkey = MKEY_PageUp; break; + case GK_PGDN: mkey = MKEY_PageDown; break; + default: + if (!keyup) + { + return CurrentMenu->CallResponder(ev); + } + break; + } + } + } + else if (menuactive != MENU_WaitKey && (ev->type == EV_KeyDown || ev->type == EV_KeyUp)) + { + // eat blocked controller events without dispatching them. + if (ev->data1 >= KEY_FIRSTJOYBUTTON && m_blockcontrollers) return true; + + keyup = ev->type == EV_KeyUp; + + ch = ev->data1; + switch (ch) + { + case KEY_JOY1: + case KEY_JOY3: + case KEY_JOY15: + case KEY_PAD_A: + mkey = MKEY_Enter; + break; + + case KEY_JOY2: + case KEY_JOY14: + case KEY_PAD_B: + mkey = MKEY_Back; + break; + + case KEY_JOY4: + case KEY_PAD_X: + mkey = MKEY_Clear; + break; + + case KEY_JOY5: + case KEY_PAD_LSHOULDER: + mkey = MKEY_PageUp; + break; + + case KEY_JOY6: + case KEY_PAD_RSHOULDER: + mkey = MKEY_PageDown; + break; + + case KEY_PAD_DPAD_UP: + case KEY_PAD_LTHUMB_UP: + case KEY_JOYAXIS2MINUS: + case KEY_JOYPOV1_UP: + mkey = MKEY_Up; + break; + + case KEY_PAD_DPAD_DOWN: + case KEY_PAD_LTHUMB_DOWN: + case KEY_JOYAXIS2PLUS: + case KEY_JOYPOV1_DOWN: + mkey = MKEY_Down; + break; + + case KEY_PAD_DPAD_LEFT: + case KEY_PAD_LTHUMB_LEFT: + case KEY_JOYAXIS1MINUS: + case KEY_JOYPOV1_LEFT: + mkey = MKEY_Left; + break; + + case KEY_PAD_DPAD_RIGHT: + case KEY_PAD_LTHUMB_RIGHT: + case KEY_JOYAXIS1PLUS: + case KEY_JOYPOV1_RIGHT: + mkey = MKEY_Right; + break; + } + } + + if (mkey != NUM_MKEYS) + { + if (keyup) + { + MenuButtons[mkey].ReleaseKey(ch); + return false; + } + else + { + MenuButtons[mkey].PressKey(ch); + MenuButtonOrigin[mkey] = fromcontroller; + if (mkey <= MKEY_PageDown) + { + MenuButtonTickers[mkey] = KEY_REPEAT_DELAY; + } + CurrentMenu->CallMenuEvent(mkey, fromcontroller); + return true; + } + } + return CurrentMenu->CallResponder(ev) || !keyup; + } + else if (MenuEnabled) + { + if (ev->type == EV_KeyDown) + { + // Pop-up menu? + if (ev->data1 == KEY_ESCAPE) + { + M_StartControlPanel(true); + M_SetMenu(NAME_Mainmenu, -1); + return true; + } + return false; + } + else if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_LButtonDown && + ConsoleState != c_down && gamestate != GS_LEVEL && m_use_mouse) + { + M_StartControlPanel(true); + M_SetMenu(NAME_Mainmenu, -1); + return true; + } + } + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +void M_Ticker (void) +{ + MenuTime++; + if (CurrentMenu != nullptr && menuactive != MENU_Off) + { + CurrentMenu->CallTicker(); + } + + // Check again because menu could be closed from Ticker() + if (CurrentMenu != nullptr && menuactive != MENU_Off) + { + for (int i = 0; i < NUM_MKEYS; ++i) + { + if (MenuButtons[i].bDown) + { + if (MenuButtonTickers[i] > 0 && --MenuButtonTickers[i] <= 0) + { + MenuButtonTickers[i] = KEY_REPEAT_RATE; + CurrentMenu->CallMenuEvent(i, MenuButtonOrigin[i]); + } + } + } + if (BackbuttonTime > 0) + { + if (BackbuttonAlpha < 1.f) BackbuttonAlpha += .1f; + if (BackbuttonAlpha > 1.f) BackbuttonAlpha = 1.f; + BackbuttonTime--; + } + else + { + if (BackbuttonAlpha > 0) BackbuttonAlpha -= .1f; + if (BackbuttonAlpha < 0) BackbuttonAlpha = 0; + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void M_Drawer (void) +{ + PalEntry fade = 0; + + if (CurrentMenu != nullptr && menuactive != MENU_Off) + { + if (!CurrentMenu->DontBlur) screen->BlurScene(menuBlurAmount); + if (!CurrentMenu->DontDim) + { + if (sysCallbacks.MenuDim) sysCallbacks.MenuDim(); + } + bool going = false; + if (transition.previous) + { + going = transition.Draw(); + if (!going) + { + if (transition.dir == -1) delete transition.previous; + transition.previous = nullptr; + transition.current = nullptr; + } + } + if (!going) + { + CurrentMenu->CallDrawer(); + } + } +} + + +//============================================================================= +// +// +// +//============================================================================= + +void M_ClearMenus() +{ + if (menuactive == MENU_Off) return; + + transition.previous = transition.current = nullptr; + transition.dir = 0; + + while (CurrentMenu != nullptr) + { + DMenu* parent = CurrentMenu->mParentMenu; + CurrentMenu->Destroy(); + CurrentMenu = parent; + } + menuactive = MENU_Off; + if (CurrentScaleOverrider) delete CurrentScaleOverrider; + CurrentScaleOverrider = nullptr; + if (sysCallbacks.MenuClosed) sysCallbacks.MenuClosed(); +} + +//============================================================================= +// +// +// +//============================================================================= + +void M_PreviousMenu() +{ + if (CurrentMenu != nullptr) + { + DMenu* parent = CurrentMenu->mParentMenu; + CurrentMenu->Destroy(); + CurrentMenu = parent; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void M_Init (void) +{ + try + { + M_ParseMenuDefs(); + GC::AddMarkerFunc(M_MarkMenus); + } + catch (CVMAbortException &err) + { + menuDelegate = nullptr; + err.MaybePrintMessage(); + Printf(PRINT_NONOTIFY | PRINT_BOLD, "%s", err.stacktrace.GetChars()); + I_FatalError("Failed to initialize menus"); + } + catch (...) + { + menuDelegate = nullptr; + throw; + } + M_CreateMenus(); +} + + +//============================================================================= +// +// +// +//============================================================================= + +void M_EnableMenu (bool on) +{ + MenuEnabled = on; +} + + +//============================================================================= +// +// [RH] Most menus can now be accessed directly +// through console commands. +// +//============================================================================= + +CCMD (openmenu) +{ + if (argv.argc() < 2) + { + Printf("Usage: openmenu \"menu_name\"\n"); + return; + } + M_StartControlPanel (true); + M_SetMenu(argv[1], -1); +} + +CCMD (closemenu) +{ + M_ClearMenus(); +} + +CCMD (prevmenu) +{ + M_PreviousMenu(); +} + +CCMD(menuconsole) +{ + M_ClearMenus(); + C_ToggleConsole(); +} + +// This really should be in the script but we can't do scripted CCMDs yet. +CCMD(undocolorpic) +{ + if (CurrentMenu != NULL) + { + IFVIRTUALPTR(CurrentMenu, DMenu, ResetColor) + { + VMValue params[] = { (DObject*)CurrentMenu }; + VMCall(func, params, countof(params), nullptr, 0); + } + } +} + + +DEFINE_GLOBAL(menuactive) +DEFINE_GLOBAL(BackbuttonTime) +DEFINE_GLOBAL(BackbuttonAlpha) +DEFINE_GLOBAL(GameTicRate) +DEFINE_GLOBAL(menuDelegate) + +DEFINE_FIELD(DMenu, mParentMenu) +DEFINE_FIELD(DMenu, mMouseCapture); +DEFINE_FIELD(DMenu, mBackbuttonSelected); +DEFINE_FIELD(DMenu, DontDim); +DEFINE_FIELD(DMenu, DontBlur); +DEFINE_FIELD(DMenu, AnimatedTransition); +DEFINE_FIELD(DMenu, Animated); + +DEFINE_FIELD(DMenuDescriptor, mMenuName) +DEFINE_FIELD(DMenuDescriptor, mNetgameMessage) +DEFINE_FIELD(DMenuDescriptor, mClass) + +DEFINE_FIELD(DMenuItemBase, mXpos) +DEFINE_FIELD(DMenuItemBase, mYpos) +DEFINE_FIELD(DMenuItemBase, mAction) +DEFINE_FIELD(DMenuItemBase, mEnabled) + +DEFINE_FIELD(DListMenuDescriptor, mItems) +DEFINE_FIELD(DListMenuDescriptor, mSelectedItem) +DEFINE_FIELD(DListMenuDescriptor, mSelectOfsX) +DEFINE_FIELD(DListMenuDescriptor, mSelectOfsY) +DEFINE_FIELD(DListMenuDescriptor, mSelector) +DEFINE_FIELD(DListMenuDescriptor, mDisplayTop) +DEFINE_FIELD(DListMenuDescriptor, mXpos) +DEFINE_FIELD(DListMenuDescriptor, mYpos) +DEFINE_FIELD(DListMenuDescriptor, mWLeft) +DEFINE_FIELD(DListMenuDescriptor, mWRight) +DEFINE_FIELD(DListMenuDescriptor, mLinespacing) +DEFINE_FIELD(DListMenuDescriptor, mAutoselect) +DEFINE_FIELD(DListMenuDescriptor, mFont) +DEFINE_FIELD(DListMenuDescriptor, mFontColor) +DEFINE_FIELD(DListMenuDescriptor, mFontColor2) +DEFINE_FIELD(DListMenuDescriptor, mAnimatedTransition) +DEFINE_FIELD(DListMenuDescriptor, mAnimated) +DEFINE_FIELD(DListMenuDescriptor, mCenter) +DEFINE_FIELD(DListMenuDescriptor, mCenterText) +DEFINE_FIELD(DListMenuDescriptor, mDontDim) +DEFINE_FIELD(DListMenuDescriptor, mDontBlur) +DEFINE_FIELD(DListMenuDescriptor, mVirtWidth) +DEFINE_FIELD(DListMenuDescriptor, mVirtHeight) + +DEFINE_FIELD(DOptionMenuDescriptor, mItems) +DEFINE_FIELD(DOptionMenuDescriptor, mTitle) +DEFINE_FIELD(DOptionMenuDescriptor, mSelectedItem) +DEFINE_FIELD(DOptionMenuDescriptor, mDrawTop) +DEFINE_FIELD(DOptionMenuDescriptor, mScrollTop) +DEFINE_FIELD(DOptionMenuDescriptor, mScrollPos) +DEFINE_FIELD(DOptionMenuDescriptor, mIndent) +DEFINE_FIELD(DOptionMenuDescriptor, mPosition) +DEFINE_FIELD(DOptionMenuDescriptor, mDontDim) +DEFINE_FIELD(DOptionMenuDescriptor, mDontBlur) +DEFINE_FIELD(DOptionMenuDescriptor, mAnimatedTransition) +DEFINE_FIELD(DOptionMenuDescriptor, mAnimated) +DEFINE_FIELD(DOptionMenuDescriptor, mFont) + +DEFINE_FIELD(FOptionMenuSettings, mTitleColor) +DEFINE_FIELD(FOptionMenuSettings, mFontColor) +DEFINE_FIELD(FOptionMenuSettings, mFontColorValue) +DEFINE_FIELD(FOptionMenuSettings, mFontColorMore) +DEFINE_FIELD(FOptionMenuSettings, mFontColorHeader) +DEFINE_FIELD(FOptionMenuSettings, mFontColorHighlight) +DEFINE_FIELD(FOptionMenuSettings, mFontColorSelection) +DEFINE_FIELD(FOptionMenuSettings, mLinespacing) + +DEFINE_FIELD(DImageScrollerDescriptor, mItems) +DEFINE_FIELD(DImageScrollerDescriptor, textBackground) +DEFINE_FIELD(DImageScrollerDescriptor, textBackgroundBrightness) +DEFINE_FIELD(DImageScrollerDescriptor,textFont) +DEFINE_FIELD(DImageScrollerDescriptor, textScale) +DEFINE_FIELD(DImageScrollerDescriptor, mAnimatedTransition) +DEFINE_FIELD(DImageScrollerDescriptor, mAnimated) +DEFINE_FIELD(DImageScrollerDescriptor, mDontDim) +DEFINE_FIELD(DImageScrollerDescriptor, mDontBlur) +DEFINE_FIELD(DImageScrollerDescriptor, virtWidth) +DEFINE_FIELD(DImageScrollerDescriptor, virtHeight) + + +struct IJoystickConfig; +// These functions are used by dynamic menu creation. +DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, int v) +{ + auto c = PClass::FindClass("OptionMenuItemStaticText"); + auto p = c->CreateNew(); + FString namestr = name; + VMValue params[] = { p, &namestr, v }; + auto f = dyn_cast(c->FindSymbol("Init", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenuItemBase*)p; +} + +DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy) +{ + auto c = PClass::FindClass("OptionMenuItemJoyConfigMenu"); + auto p = c->CreateNew(); + FString namestr = label; + VMValue params[] = { p, &namestr, joy }; + auto f = dyn_cast(c->FindSymbol("Init", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenuItemBase*)p; +} + +DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center) +{ + auto c = PClass::FindClass("OptionMenuItemSubmenu"); + auto p = c->CreateNew(); + FString namestr = label; + VMValue params[] = { p, &namestr, cmd.GetIndex(), center, false }; + auto f = dyn_cast(c->FindSymbol("Init", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenuItemBase*)p; +} + +DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings) +{ + auto c = PClass::FindClass("OptionMenuItemControlBase"); + auto p = c->CreateNew(); + FString namestr = label; + VMValue params[] = { p, &namestr, cmd.GetIndex(), bindings }; + auto f = dyn_cast(c->FindSymbol("Init", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenuItemBase*)p; +} + +DMenuItemBase * CreateOptionMenuItemCommand(const char *label, FName cmd, bool centered) +{ + auto c = PClass::FindClass("OptionMenuItemCommand"); + auto p = c->CreateNew(); + FString namestr = label; + VMValue params[] = { p, &namestr, cmd.GetIndex(), centered, false }; + auto f = dyn_cast(c->FindSymbol("Init", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + auto unsafe = dyn_cast(c->FindSymbol("mUnsafe", false)); + unsafe->Type->SetValue(reinterpret_cast(p) + unsafe->Offset, 0); + return (DMenuItemBase*)p; +} + +DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param) +{ + auto c = PClass::FindClass("ListMenuItemPatchItem"); + auto p = c->CreateNew(); + FString keystr = FString(char(hotkey)); + VMValue params[] = { p, x, y, height, tex.GetIndex(), &keystr, command.GetIndex(), param }; + auto f = dyn_cast(c->FindSymbol("InitDirect", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenuItemBase*)p; +} + +DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param) +{ + auto c = PClass::FindClass("ListMenuItemTextItem"); + auto p = c->CreateNew(); + FString keystr = FString(char(hotkey)); + FString textstr = text; + VMValue params[] = { p, x, y, height, &keystr, &textstr, font, int(color1.d), int(color2.d), command.GetIndex(), param }; + auto f = dyn_cast(c->FindSymbol("InitDirect", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenuItemBase*)p; +} + +DMenuItemBase* CreateListMenuItemStaticText(double x, double y, const char* text, FFont* font, PalEntry color, bool centered) +{ + auto c = PClass::FindClass("ListMenuItemStaticText"); + auto p = c->CreateNew(); + FString textstr = text; + VMValue params[] = { p, x, y, &textstr, font, int(color.d), centered }; + auto f = dyn_cast(c->FindSymbol("InitDirect", false)); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenuItemBase*)p; +} + +bool DMenuItemBase::Activate() +{ + IFVIRTUAL(DMenuItemBase, Activate) + { + VMValue params[] = { (DObject*)this }; + int retval; + VMReturn ret(&retval); + VMCall(func, params, countof(params), &ret, 1); + return !!retval; + } + return false; +} + +bool DMenuItemBase::SetString(int i, const char *s) +{ + IFVIRTUAL(DMenuItemBase, SetString) + { + FString namestr = s; + VMValue params[] = { (DObject*)this, i, &namestr }; + int retval; + VMReturn ret(&retval); + VMCall(func, params, countof(params), &ret, 1); + return !!retval; + } + return false; +} + +bool DMenuItemBase::GetString(int i, char *s, int len) +{ + IFVIRTUAL(DMenuItemBase, GetString) + { + VMValue params[] = { (DObject*)this, i }; + int retval; + FString retstr; + VMReturn ret[2]; ret[0].IntAt(&retval); ret[1].StringAt(&retstr); + VMCall(func, params, countof(params), ret, 2); + strncpy(s, retstr.GetChars(), len); + return !!retval; + } + return false; +} + + +bool DMenuItemBase::SetValue(int i, int value) +{ + IFVIRTUAL(DMenuItemBase, SetValue) + { + VMValue params[] = { (DObject*)this, i, value }; + int retval; + VMReturn ret(&retval); + VMCall(func, params, countof(params), &ret, 1); + return !!retval; + } + return false; +} + +bool DMenuItemBase::GetValue(int i, int *pvalue) +{ + IFVIRTUAL(DMenuItemBase, GetValue) + { + VMValue params[] = { (DObject*)this, i }; + int retval[2]; + VMReturn ret[2]; ret[0].IntAt(&retval[0]); ret[1].IntAt(&retval[1]); + VMCall(func, params, countof(params), ret, 2); + *pvalue = retval[1]; + return !!retval[0]; + } + return false; +} + +IMPLEMENT_CLASS(DMenuItemBase, false, false) diff --git a/src/common/menu/menu.h b/src/common/menu/menu.h new file mode 100644 index 00000000000..a96e25929ca --- /dev/null +++ b/src/common/menu/menu.h @@ -0,0 +1,338 @@ +#ifndef __M_MENU_MENU_H__ +#define __M_MENU_MENU_H__ + + + + +#include "dobject.h" +#include "c_cvars.h" +#include "v_font.h" +#include "textures.h" + +EXTERN_CVAR(Float, snd_menuvolume) +EXTERN_CVAR(Int, m_use_mouse); + + +struct event_t; +class FTexture; +class FFont; +enum EColorRange : int; +class FKeyBindings; +struct FBrokenLines; + +enum EMenuKey +{ + MKEY_Up, + MKEY_Down, + MKEY_Left, + MKEY_Right, + MKEY_PageUp, + MKEY_PageDown, + //----------------- Keys past here do not repeat. + MKEY_Enter, + MKEY_Back, // Back to previous menu + MKEY_Clear, // Clear keybinding/flip player sprite preview + NUM_MKEYS, + + // These are not buttons but events sent from other menus + + MKEY_Input, // Sent when input is confirmed + MKEY_Abort, // Input aborted + MKEY_MBYes, + MKEY_MBNo, +}; + + +class DMenu; +extern DMenu *CurrentMenu; +extern int MenuTime; +class DMenuItemBase; +extern DObject* menuDelegate; + +//============================================================================= +// +// menu descriptor. This is created from the menu definition lump +// Items must be inserted in the order they are cycled through with the cursor +// +//============================================================================= + +class DMenuDescriptor : public DObject +{ + DECLARE_CLASS(DMenuDescriptor, DObject) +public: + FName mMenuName = NAME_None; + FString mNetgameMessage; + PClass *mClass = nullptr; + bool mProtected = false; + TArray mItems; + + size_t PropagateMark() override; +}; + + +class DListMenuDescriptor : public DMenuDescriptor +{ + DECLARE_CLASS(DListMenuDescriptor, DMenuDescriptor) + +public: + int mSelectedItem; + double mSelectOfsX; + double mSelectOfsY; + FTextureID mSelector; + int mDisplayTop; + double mXpos, mYpos; + int mWLeft, mWRight; + int mLinespacing; // needs to be stored for dynamically created menus + int mAutoselect; // this can only be set by internal menu creation functions + FFont *mFont; + EColorRange mFontColor; + EColorRange mFontColor2; + bool mCenter; + bool mCenterText; + bool mFromEngine; + bool mAnimated; + bool mAnimatedTransition; + bool mDontDim; + bool mDontBlur; + int mVirtWidth; + int mVirtHeight; + bool mCustomSizeSet; + bool mForceList; + + void Reset(); +}; + +struct FOptionMenuSettings +{ + EColorRange mTitleColor; + EColorRange mFontColor; + EColorRange mFontColorValue; + EColorRange mFontColorMore; + EColorRange mFontColorHeader; + EColorRange mFontColorHighlight; + EColorRange mFontColorSelection; + int mLinespacing; +}; + +class DOptionMenuDescriptor : public DMenuDescriptor +{ + DECLARE_CLASS(DOptionMenuDescriptor, DMenuDescriptor) + +public: + FString mTitle; + int mSelectedItem; + int mDrawTop; + int mScrollTop; + int mScrollPos; + int mIndent; + int mPosition; + bool mDontDim; + bool mDontBlur; + bool mAnimatedTransition; + bool mAnimated; + FFont *mFont; + + void CalcIndent(); + DMenuItemBase *GetItem(FName name); + void Reset(); + ~DOptionMenuDescriptor() = default; +}; + +class DImageScrollerDescriptor : public DMenuDescriptor +{ + DECLARE_CLASS(DOptionMenuDescriptor, DMenuDescriptor) +public: + FTextureID textBackground; + PalEntry textBackgroundBrightness; + + FFont *textFont; + double textScale; + bool mAnimatedTransition; + bool mAnimated; + bool mDontDim; + bool mDontBlur; + int virtWidth, virtHeight; + +}; + +typedef TMap MenuDescriptorList; + +extern FOptionMenuSettings OptionSettings; +extern MenuDescriptorList MenuDescriptors; + +#define CURSORSPACE (14 * CleanXfac_1) + +//============================================================================= +// +// +// +//============================================================================= + +struct FMenuRect +{ + int x, y; + int width, height; + + void set(int _x, int _y, int _w, int _h) + { + x = _x; + y = _y; + width = _w; + height = _h; + } + + bool inside(int _x, int _y) + { + return _x >= x && _x < x+width && _y >= y && _y < y+height; + } + +}; + + +enum MenuTransitionType +{ // Note: This enum is for logical categories, not visual types. + MA_None, + MA_Return, + MA_Advance, +}; + +class DMenu; + +struct MenuTransition +{ + DMenu* previous; + DMenu* current; + + double start; + int32_t length; + int8_t dir; + bool destroyprev; + + bool StartTransition(DMenu* from, DMenu* to, MenuTransitionType animtype); + bool Draw(); + +}; + + + +class DMenu : public DObject +{ + DECLARE_CLASS (DMenu, DObject) + HAS_OBJECT_POINTERS + + + +public: + enum + { + MOUSE_Click, + MOUSE_Move, + MOUSE_Release + }; + + TObjPtr mParentMenu; + bool mMouseCapture; + bool mBackbuttonSelected; + bool DontDim; + bool DontBlur; + bool Animated; + bool AnimatedTransition; + static int InMenu; + + DMenu(DMenu *parent = NULL); + bool TranslateKeyboardEvents(); + virtual void Close(); + + bool CallResponder(event_t *ev); + bool CallMenuEvent(int mkey, bool fromcontroller); + void CallTicker(); + void CallDrawer(); + bool canAnimate() { return AnimatedTransition; } +}; + +//============================================================================= +// +// base class for menu items +// +//============================================================================= + +class DMenuItemBase : public DObject +{ + DECLARE_CLASS(DMenuItemBase, DObject) +public: + double mXpos, mYpos; + FName mAction; + int mEnabled; + + bool Activate(); + bool SetString(int i, const char *s); + bool GetString(int i, char *s, int len); + bool SetValue(int i, int value); + bool GetValue(int i, int *pvalue); + void OffsetPositionY(int ydelta) { mYpos += ydelta; } + double GetY() { return mYpos; } +}; + +//============================================================================= +// +// +// +//============================================================================= +struct FOptionValues +{ + struct Pair + { + double Value; + FString TextValue; + FString Text; + }; + + TArray mValues; +}; + +typedef TMap< FName, FOptionValues* > FOptionMap; + +extern FOptionMap OptionValues; + + +//============================================================================= +// +// +// +//============================================================================= + +struct event_t; +void M_EnableMenu (bool on) ; +bool M_Responder (event_t *ev); +void M_Ticker (void); +void M_Drawer (void); +void M_Init (void); +void M_CreateMenus(); +void M_ActivateMenu(DMenu *menu); +void M_ClearMenus (); +void M_PreviousMenu (); +void M_ParseMenuDefs(); +void M_StartControlPanel(bool makeSound, bool scaleoverride = false); +void M_SetMenu(FName menu, int param = -1); +void M_StartMessage(const char *message, int messagemode, FName action = NAME_None); +DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar); +void M_MarkMenus(); +FTextureID GetMenuTexture(const char* const name); +void DeinitMenus(); +bool M_Active(); +bool M_IsAnimated(); + + +struct IJoystickConfig; +DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, int v = -1); +DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center); +DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings); +DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy); +DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param); +DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param); +DMenuItemBase * CreateOptionMenuItemCommand(const char *label, FName cmd, bool centered = false); +DMenuItemBase* CreateListMenuItemStaticText(double x, double y, const char* text, FFont* font, PalEntry color, bool centered = false); + +void UpdateVRModes(bool considerQuadBuffered=true); + +#endif diff --git a/src/common/menu/menudef.cpp b/src/common/menu/menudef.cpp new file mode 100644 index 00000000000..ad02001e0ce --- /dev/null +++ b/src/common/menu/menudef.cpp @@ -0,0 +1,1692 @@ +/* +** menudef.cpp +** MENUDEF parser amd menu generation code +** +**--------------------------------------------------------------------------- +** Copyright 2010 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include + +#include "menu.h" +#include "filesystem.h" +#include "c_bind.h" +#include "i_music.h" +#include "i_sound.h" +#include "cmdlib.h" +#include "vm.h" +#include "types.h" +#include "m_argv.h" +#include "i_soundfont.h" +#include "i_system.h" +#include "v_video.h" +#include "gstrings.h" +#include +#include "texturemanager.h" +#include "printf.h" +#include "i_interface.h" + + + +bool CheckSkipGameOptionBlock(FScanner& sc); + +MenuDescriptorList MenuDescriptors; +static DListMenuDescriptor *DefaultListMenuSettings; // contains common settings for all list menus +static DOptionMenuDescriptor *DefaultOptionMenuSettings; // contains common settings for all Option menus +FOptionMenuSettings OptionSettings; +FOptionMap OptionValues; +bool mustPrintErrors; +PClass *DefaultListMenuClass; +PClass *DefaultOptionMenuClass; + +void I_BuildALDeviceList(FOptionValues *opt); +void I_BuildALResamplersList(FOptionValues *opt); + + + +DEFINE_GLOBAL_NAMED(OptionSettings, OptionMenuSettings) + +DEFINE_ACTION_FUNCTION(FOptionValues, GetCount) +{ + PARAM_PROLOGUE; + PARAM_NAME(grp); + int cnt = 0; + FOptionValues **pGrp = OptionValues.CheckKey(grp); + if (pGrp != nullptr) + { + cnt = (*pGrp)->mValues.Size(); + } + ACTION_RETURN_INT(cnt); +} + +DEFINE_ACTION_FUNCTION(FOptionValues, GetValue) +{ + PARAM_PROLOGUE; + PARAM_NAME(grp); + PARAM_UINT(index); + double val = 0; + FOptionValues **pGrp = OptionValues.CheckKey(grp); + if (pGrp != nullptr) + { + if (index < (*pGrp)->mValues.Size()) + { + val = (*pGrp)->mValues[index].Value; + } + } + ACTION_RETURN_FLOAT(val); +} + +DEFINE_ACTION_FUNCTION(FOptionValues, GetTextValue) +{ + PARAM_PROLOGUE; + PARAM_NAME(grp); + PARAM_UINT(index); + FString val; + FOptionValues **pGrp = OptionValues.CheckKey(grp); + if (pGrp != nullptr) + { + if (index < (*pGrp)->mValues.Size()) + { + val = (*pGrp)->mValues[index].TextValue; + } + } + ACTION_RETURN_STRING(val); +} + +DEFINE_ACTION_FUNCTION(FOptionValues, GetText) +{ + PARAM_PROLOGUE; + PARAM_NAME(grp); + PARAM_UINT(index); + FString val; + FOptionValues **pGrp = OptionValues.CheckKey(grp); + if (pGrp != nullptr) + { + if (index < (*pGrp)->mValues.Size()) + { + val = (*pGrp)->mValues[index].Text; + } + } + ACTION_RETURN_STRING(val); +} + + +void DeinitMenus() +{ + M_ClearMenus(); + { + FOptionMap::Iterator it(OptionValues); + + FOptionMap::Pair *pair; + + while (it.NextPair(pair)) + { + delete pair->Value; + pair->Value = nullptr; + } + } + if (menuDelegate) + { + menuDelegate->Destroy(); + menuDelegate = nullptr; + } + MenuDescriptors.Clear(); + OptionValues.Clear(); +} + +FTextureID GetMenuTexture(const char* const name) +{ + const FTextureID texture = TexMan.CheckForTexture(name, ETextureType::MiscPatch); + + if (!texture.Exists() && mustPrintErrors) + { + Printf("Missing menu texture: \"%s\"\n", name); + } + + return texture; +} + +//============================================================================= +// +// +// +//============================================================================= + +static void SkipSubBlock(FScanner &sc) +{ + sc.MustGetStringName("{"); + sc.SkipToEndOfBlock(); +} + +//============================================================================= +// +// +// +//============================================================================= + +static bool CheckSkipGameBlock(FScanner &sc, bool yes = true) +{ + bool filter = false; + sc.MustGetStringName("("); + do + { + sc.MustGetString(); + if (sysCallbacks.CheckGame) filter |= sysCallbacks.CheckGame(sc.String); + } + while (sc.CheckString(",")); + sc.MustGetStringName(")"); + if (filter != yes) + { + SkipSubBlock(sc); + return !sc.CheckString("else"); + } + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +static bool CheckSkipOptionBlock(FScanner &sc) +{ + bool filter = false; + sc.MustGetStringName("("); + do + { + sc.MustGetString(); + if (sysCallbacks.CheckMenudefOption && sysCallbacks.CheckMenudefOption(sc.String)) filter = true; + else if (sc.Compare("Windows")) + { + #ifdef _WIN32 + filter = true; + #endif + } + else if (sc.Compare("unix")) + { + #ifdef __unix__ + filter = true; + #endif + } + else if (sc.Compare("Mac")) + { + #ifdef __APPLE__ + filter = true; + #endif + } + else if (sc.Compare("OpenAL")) + { + filter |= IsOpenALPresent(); + } + else if (sc.Compare("MMX")) + { + #ifdef HAVE_MMX + filter = true; + #endif + } + else if (sc.Compare("SWRender")) + { +#ifndef NO_SWRENDERER + filter = true; +#endif + } + } + while (sc.CheckString(",")); + sc.MustGetStringName(")"); + if (!filter) + { + SkipSubBlock(sc); + return !sc.CheckString("else"); + } + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +static void DoParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc, bool &sizecompatible, int insertIndex) +{ + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("else")) + { + SkipSubBlock(sc); + } + else if (sc.Compare("ifgame")) + { + if (!CheckSkipGameBlock(sc)) + { + // recursively parse sub-block + DoParseListMenuBody(sc, desc, sizecompatible, insertIndex); + } + } + else if (sc.Compare("ifnotgame")) + { + if (!CheckSkipGameBlock(sc, false)) + { + // recursively parse sub-block + DoParseListMenuBody(sc, desc, sizecompatible, insertIndex); + } + } + else if (sc.Compare("ifoption")) + { + if (!CheckSkipOptionBlock(sc)) + { + // recursively parse sub-block + DoParseListMenuBody(sc, desc, sizecompatible, insertIndex); + } + } + else if (sc.Compare("Class")) + { + sc.MustGetString(); + PClass *cls = PClass::FindClass(sc.String); + if (cls == nullptr || !cls->IsDescendantOf("ListMenu")) + { + sc.ScriptError("Unknown menu class '%s'", sc.String); + } + desc->mClass = cls; + sizecompatible = false; + } + else if (sc.Compare("Selector")) + { + sc.MustGetString(); + desc->mSelector = GetMenuTexture(sc.String); + sc.MustGetStringName(","); + sc.MustGetFloat(); + desc->mSelectOfsX = sc.Float; + sc.MustGetStringName(","); + sc.MustGetFloat(); + desc->mSelectOfsY = sc.Float; + } + else if (sc.Compare("Linespacing")) + { + sc.MustGetNumber(); + desc->mLinespacing = sc.Number; + } + else if (sc.Compare("Position")) + { + sc.MustGetFloat(); + desc->mXpos = sc.Float; + sc.MustGetStringName(","); + sc.MustGetFloat(); + desc->mYpos = sc.Float; + } + else if (sc.Compare("Centermenu")) + { + desc->mCenter = true; + } + else if (sc.Compare("Selecteditem")) + { + desc->mSelectedItem = desc->mItems.Size() - 1; + } + else if (sc.Compare("animatedtransition")) + { + desc->mAnimatedTransition = true; + } + else if (sc.Compare("animated")) + { + desc->mAnimated = true; + } + else if (sc.Compare("DontDim")) + { + desc->mDontDim = true; + } + else if (sc.Compare("DontBlur")) + { + desc->mDontBlur = true; + } + else if (sc.Compare("MouseWindow")) + { + sc.MustGetNumber(); + desc->mWLeft = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + desc->mWRight = sc.Number; + } + else if (sc.Compare("Font")) + { + sc.MustGetString(); + FFont *newfont = V_GetFont(sc.String); + if (newfont != nullptr) desc->mFont = newfont; + if (sc.CheckString(",")) + { + sc.MustGetString(); + desc->mFontColor2 = desc->mFontColor = V_FindFontColor((FName)sc.String); + if (sc.CheckString(",")) + { + sc.MustGetString(); + desc->mFontColor2 = V_FindFontColor((FName)sc.String); + } + } + else + { + desc->mFontColor = OptionSettings.mFontColor; + desc->mFontColor2 = OptionSettings.mFontColorValue; + } + } + else if (sc.Compare("NetgameMessage")) + { + sc.MustGetString(); + desc->mNetgameMessage = sc.String; + } + else if (sc.Compare("size")) + { + desc->mCustomSizeSet = true; + if (sc.CheckNumber()) + { + desc->mVirtWidth = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + desc->mVirtHeight = sc.Number; + } + else + { + sc.MustGetString(); + if (sc.Compare("clean")) + { + desc->mVirtWidth = -1; + } + else if (sc.Compare("optclean")) + { + desc->mVirtWidth = -2; + } + else + { + sc.ScriptError("Invalid value '%s' for 'size'", sc.String); + } + } + } + else if (sc.Compare("ForceList")) + { + desc->mForceList = true; + } + else if (sc.Compare("CenterText")) + { + desc->mCenterText = true; + } + else + { + // all item classes from which we know that they support sized scaling. + // If anything else comes through here the option to swich scaling mode is disabled for this menu. + static const char* const compatibles[] = { "StaticPatch", "StaticText", "StaticTextCentered", "TextItem", "PatchItem", "PlayerDisplay", nullptr }; + if (sc.MatchString(compatibles) < 0) sizecompatible = false; + + bool success = false; + FStringf buildname("ListMenuItem%s", sc.String); + PClass *cls = PClass::FindClass(buildname); + if (cls != nullptr && cls->IsDescendantOf("ListMenuItem")) + { + bool inserting = insertIndex >= 0; + bool isSelectable = cls->IsDescendantOf("ListMenuItemSelectable"); + double oldYpos = desc->mYpos; + + // [Player701] If this is a selectable item and we're inserting in the middle, + // set the Y position of the descriptor to the Y of the item we're inserting before. + if (isSelectable && inserting) + { + desc->mYpos = desc->mItems[insertIndex]->mYpos; + } + + auto func = dyn_cast(cls->FindSymbol("Init", true)); + if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protected init method. + { + auto &args = func->Variants[0].Proto->ArgumentTypes; + TArray params; + int start = 1; + + params.Push(0); + if (args.Size() > 1 && args[1] == NewPointer(PClass::FindClass("ListMenuDescriptor"))) + { + params.Push(desc); + start = 2; + } + auto TypeCVar = NewPointer(NewStruct("CVar", nullptr, true)); + + // Note that this array may not be reallocated so its initial size must be the maximum possible elements. + TArray strings(args.Size()); + for (unsigned i = start; i < args.Size(); i++) + { + sc.MustGetString(); + if (args[i] == TypeString) + { + strings.Push(sc.String); + params.Push(&strings.Last()); + } + else if (args[i] == TypeName) + { + params.Push(FName(sc.String).GetIndex()); + } + else if (args[i] == TypeColor) + { + params.Push(V_GetColor(sc)); + } + else if (args[i] == TypeFont) + { + auto f = V_GetFont(sc.String); + if (f == nullptr) + { + sc.ScriptError("Unknown font %s", sc.String); + } + params.Push(f); + } + else if (args[i] == TypeTextureID) + { + auto f = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); + if (!f.Exists()) + { + sc.ScriptMessage("Unknown texture %s", sc.String); + } + params.Push(f.GetIndex()); + } + else if (args[i]->isIntCompatible()) + { + char *endp; + int v = (int)strtoll(sc.String, &endp, 0); + if (*endp != 0) + { + // special check for font color ranges. + v = V_FindFontColor(sc.String); + if (v == CR_UNTRANSLATED && !sc.Compare("untranslated")) + { + // todo: check other data types that may get used. + sc.ScriptError("Integer expected, got %s", sc.String); + } + } + if (args[i] == TypeBool) v = !!v; + params.Push(v); + } + else if (args[i]->isFloat()) + { + char *endp; + double v = strtod(sc.String, &endp); + if (*endp != 0) + { + sc.ScriptError("Float expected, got %s", sc.String); + } + params.Push(v); + } + else if (args[i] == TypeCVar) + { + auto cv = FindCVar(sc.String, nullptr); + if (cv == nullptr && *sc.String) + { + sc.ScriptError("Unknown CVar %s", sc.String); + } + params.Push(cv); + } + else + { + sc.ScriptError("Invalid parameter type %s for menu item", args[i]->DescriptiveName()); + } + if (sc.CheckString(",")) + { + if (i == args.Size() - 1) + { + sc.ScriptError("Too many parameters for %s", cls->TypeName.GetChars()); + } + } + else + { + if (i < args.Size() - 1 && !(func->Variants[0].ArgFlags[i + 1] & VARF_Optional)) + { + sc.ScriptError("Insufficient parameters for %s", cls->TypeName.GetChars()); + } + break; + } + } + DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew(); + params[0] = item; + VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0); + + if (!inserting) + { + desc->mItems.Push(item); + } + else + { + // [Player701] Insert item in between + desc->mItems.Insert(insertIndex, item); + insertIndex++; + } + + if (isSelectable) + { + if (inserting) + { + // [Player701] If we've inserted a selectable item, + // shift all following selectable items downwards + // NB: index has been incremented, so we're not affecting the newly inserted item here. + for (unsigned int i = insertIndex; i < desc->mItems.Size(); i++) + { + auto litem = desc->mItems[i]; + if (litem->GetClass()->IsDescendantOf("ListMenuItemSelectable")) + { + desc->mItems[i]->mYpos += desc->mLinespacing; + } + } + } + + desc->mYpos = oldYpos + desc->mLinespacing; + if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size() - 1; + } + success = true; + } + } + if (!success) + { + sc.ScriptError("Unknown keyword '%s'", sc.String); + } + } + } + for (auto &p : desc->mItems) + { + GC::WriteBarrier(p); + } +} + +static void ParseListMenuBody(FScanner& sc, DListMenuDescriptor* desc, int insertIndex) +{ + bool sizecompatible = true; + DoParseListMenuBody(sc, desc, sizecompatible, insertIndex); + if (!desc->mCustomSizeSet && !sizecompatible) + { + // No custom size and incompatible items, + // so force clean scaling for this menu + desc->mVirtWidth = -1; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +static bool CheckCompatible(DMenuDescriptor *newd, DMenuDescriptor *oldd) +{ + if (oldd->mClass == nullptr) return true; + return newd->mClass->IsDescendantOf(oldd->mClass); +} + +static int GetGroup(DMenuItemBase *desc) +{ + if (desc->IsKindOf(NAME_OptionMenuItemCommand)) return 2; + if (desc->IsKindOf(NAME_OptionMenuItemSubmenu)) return 1; + if (desc->IsKindOf(NAME_OptionMenuItemControlBase)) return 3; + if (desc->IsKindOf(NAME_OptionMenuItemOptionBase)) return 4; + if (desc->IsKindOf(NAME_OptionMenuSliderBase)) return 4; + if (desc->IsKindOf(NAME_OptionMenuFieldBase)) return 4; + if (desc->IsKindOf(NAME_OptionMenuItemColorPicker)) return 4; + if (desc->IsKindOf(NAME_OptionMenuItemStaticText)) return 5; + if (desc->IsKindOf(NAME_OptionMenuItemStaticTextSwitchable)) return 5; + return 0; +} + +static bool FindMatchingItem(DMenuItemBase *desc) +{ + int grp = GetGroup(desc); + if (grp == 0) return false; // no idea what this is. + if (grp == 5) return true; // static texts always match + + FName name = desc->mAction; + + if (grp == 1) + { + // Check for presence of menu + auto menu = MenuDescriptors.CheckKey(name); + if (menu == nullptr) return false; + } + else if (grp == 4) + { + static const FName CVarBlacklist[] = { + NAME_snd_waterlp, NAME_snd_output, NAME_snd_output_format, NAME_snd_speakermode, NAME_snd_resampler, NAME_AlwaysRun }; + + // Check for presence of CVAR and blacklist + auto cv = FindCVar(name.GetChars(), nullptr); + if (cv == nullptr) return true; + + for (auto bname : CVarBlacklist) + { + if (name == bname) return true; + } + } + + MenuDescriptorList::Iterator it(MenuDescriptors); + MenuDescriptorList::Pair *pair; + while (it.NextPair(pair)) + { + for (auto item : pair->Value->mItems) + { + if (item->mAction == name && GetGroup(item) == grp) return true; + } + } + return false; +} + +static bool ReplaceMenu(FScanner &sc, DMenuDescriptor *desc) +{ + DMenuDescriptor **pOld = MenuDescriptors.CheckKey(desc->mMenuName); + if (pOld != nullptr && *pOld != nullptr) + { + if ((*pOld)->mProtected) + { + // If this tries to replace an option menu with an option menu, let's append all new entries to the old menu. + // Otherwise bail out because for list menus it's not that simple. + if (!desc->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)) || !(*pOld)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) + { + sc.ScriptMessage("Cannot replace protected menu %s.", desc->mMenuName.GetChars()); + return true; + } + for (int i = desc->mItems.Size()-1; i >= 0; i--) + { + if (FindMatchingItem(desc->mItems[i])) + { + desc->mItems.Delete(i); + } + } + if (desc->mItems.Size() > 0) + { + auto sep = CreateOptionMenuItemStaticText(" "); + (*pOld)->mItems.Push(sep); + sep = CreateOptionMenuItemStaticText("---------------", 1); + (*pOld)->mItems.Push(sep); + for (auto it : desc->mItems) + { + (*pOld)->mItems.Push(it); + } + desc->mItems.Clear(); + //sc.ScriptMessage("Merged %d items into %s", desc->mItems.Size(), desc->mMenuName.GetChars()); + } + return true; + } + + if (!CheckCompatible(desc, *pOld)) + { + sc.ScriptMessage("Tried to replace menu '%s' with a menu of different type", desc->mMenuName.GetChars()); + return true; + } + } + MenuDescriptors[desc->mMenuName] = desc; + GC::WriteBarrier(desc); + return false; +} + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseListMenu(FScanner &sc) +{ + sc.MustGetString(); + + DListMenuDescriptor *desc = Create(); + desc->Reset(); + desc->mMenuName = sc.String; + desc->mSelectedItem = -1; + desc->mAutoselect = -1; + desc->mSelectOfsX = DefaultListMenuSettings->mSelectOfsX; + desc->mSelectOfsY = DefaultListMenuSettings->mSelectOfsY; + desc->mSelector = DefaultListMenuSettings->mSelector; + desc->mDisplayTop = DefaultListMenuSettings->mDisplayTop; + desc->mXpos = DefaultListMenuSettings->mXpos; + desc->mYpos = DefaultListMenuSettings->mYpos; + desc->mLinespacing = DefaultListMenuSettings->mLinespacing; + desc->mNetgameMessage = DefaultListMenuSettings->mNetgameMessage; + desc->mFont = DefaultListMenuSettings->mFont; + desc->mFontColor = DefaultListMenuSettings->mFontColor; + desc->mFontColor2 = DefaultListMenuSettings->mFontColor2; + desc->mClass = nullptr; + desc->mWLeft = 0; + desc->mWRight = 0; + desc->mCenter = false; + desc->mCenterText = false; + desc->mFromEngine = fileSystem.GetFileContainer(sc.LumpNum) == 0; // flags menu if the definition is from the IWAD. + desc->mVirtWidth = -2; + desc->mCustomSizeSet = false; + desc->mAnimatedTransition = false; + desc->mAnimated = false; + desc->mDontDim = false; + desc->mDontBlur = false; + desc->mForceList = false; + if (DefaultListMenuSettings->mCustomSizeSet) + { + desc->mVirtHeight = DefaultListMenuSettings->mVirtHeight; + desc->mVirtWidth = DefaultListMenuSettings->mVirtWidth; + desc->mCustomSizeSet = true; + } + + ParseListMenuBody(sc, desc, -1); + ReplaceMenu(sc, desc); +} + +//============================================================================= +// +// [Player701] Common function for figuring out where to insert items +// for AddListMenu and AddOptionMenu +// +//============================================================================= + +static int GetInsertIndex(FScanner& sc, DMenuDescriptor* desc) +{ + bool before = sc.CheckString("BEFORE"); + bool after = sc.CheckString("AFTER"); + + int insertIndex = -1; + + if (before || after) + { + // Find an existing menu item to use as insertion point + sc.MustGetString(); + + int n = desc->mItems.Size(); + for (int i = 0; i < n; i++) + { + auto item = desc->mItems[i]; + + if (item->mAction == sc.String) + { + insertIndex = before ? i : i + 1; + break; + } + } + + // Inserting after the last item is the same as inserting at the end + if (insertIndex == n) insertIndex = -1; + + // Don't error out if we haven't found a suitable item + // to avoid backwards compatibility issues. + } + + return insertIndex; +} + +//============================================================================= +// +// [Player701] Allow extending list menus +// +//============================================================================= + +static void ParseAddListMenu(FScanner& sc) +{ + sc.MustGetString(); + + DMenuDescriptor** pOld = MenuDescriptors.CheckKey(sc.String); + if (pOld == nullptr || *pOld == nullptr || !(*pOld)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) + { + sc.ScriptError("%s is not a list menu that can be extended", sc.String); + return; + } + ParseListMenuBody(sc, (DListMenuDescriptor*)(*pOld), GetInsertIndex(sc, *pOld)); +} + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseOptionValue(FScanner &sc) +{ + FOptionValues *val = new FOptionValues; + sc.MustGetString(); + FName optname = sc.String; + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + FOptionValues::Pair &pair = val->mValues[val->mValues.Reserve(1)]; + sc.MustGetFloat(); + pair.Value = sc.Float; + sc.MustGetStringName(","); + sc.MustGetString(); + pair.Text = strbin1(sc.String); + } + FOptionValues **pOld = OptionValues.CheckKey(optname); + if (pOld != nullptr && *pOld != nullptr) + { + delete *pOld; + } + OptionValues[optname] = val; +} + + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseOptionString(FScanner &sc) +{ + FOptionValues *val = new FOptionValues; + sc.MustGetString(); + FName optname = sc.String; + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + FOptionValues::Pair &pair = val->mValues[val->mValues.Reserve(1)]; + sc.MustGetString(); + pair.Value = DBL_MAX; + pair.TextValue = sc.String; + sc.MustGetStringName(","); + sc.MustGetString(); + pair.Text = strbin1(sc.String); + } + FOptionValues **pOld = OptionValues.CheckKey(optname); + if (pOld != nullptr && *pOld != nullptr) + { + delete *pOld; + } + OptionValues[optname] = val; +} + + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseOptionSettings(FScanner &sc) +{ + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("else")) + { + SkipSubBlock(sc); + } + else if (sc.Compare("ifgame")) + { + if (!CheckSkipGameBlock(sc)) + { + // recursively parse sub-block + ParseOptionSettings(sc); + } + } + else if (sc.Compare("ifnotgame")) + { + if (!CheckSkipGameBlock(sc, false)) + { + // recursively parse sub-block + ParseOptionSettings(sc); + } + } + else if (sc.Compare("Linespacing")) + { + sc.MustGetNumber(); + // ignored + } + else if (sc.Compare("LabelOffset")) + { + sc.MustGetNumber(); + // ignored + } + else + { + sc.ScriptError("Unknown keyword '%s'", sc.String); + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc, int insertIndex) +{ + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("else")) + { + SkipSubBlock(sc); + } + else if (sc.Compare("ifgame")) + { + if (!CheckSkipGameBlock(sc)) + { + // recursively parse sub-block + ParseOptionMenuBody(sc, desc, insertIndex); + } + } + else if (sc.Compare("ifnotgame")) + { + if (!CheckSkipGameBlock(sc, false)) + { + // recursively parse sub-block + ParseOptionMenuBody(sc, desc, insertIndex); + } + } + else if (sc.Compare("ifoption")) + { + if (!CheckSkipOptionBlock(sc)) + { + // recursively parse sub-block + ParseOptionMenuBody(sc, desc, insertIndex); + } + } + else if (sc.Compare("Class")) + { + sc.MustGetString(); + PClass *cls = PClass::FindClass(sc.String); + if (cls == nullptr || !cls->IsDescendantOf("OptionMenu")) + { + sc.ScriptError("Unknown menu class '%s'", sc.String); + } + desc->mClass = cls; + } + else if (sc.Compare({ "Title", "Caption" })) + { + sc.MustGetString(); + desc->mTitle = sc.String; + } + else if (sc.Compare("Position")) + { + sc.MustGetNumber(); + desc->mPosition = sc.Number; + } + else if (sc.Compare("DefaultSelection")) + { + sc.MustGetNumber(); + desc->mSelectedItem = sc.Number; + } + else if (sc.Compare("ScrollTop")) + { + sc.MustGetNumber(); + desc->mScrollTop = sc.Number; + } + else if (sc.Compare("Indent")) + { + sc.MustGetNumber(); + desc->mIndent = sc.Number; + } + else if (sc.Compare("AnimatedTransition")) + { + desc->mAnimatedTransition = true; + } + else if (sc.Compare("Animated")) + { + desc->mAnimated = true; + } + else if (sc.Compare("DontDim")) + { + desc->mDontDim = true; + } + else if (sc.Compare("DontBlur")) + { + desc->mDontBlur = true; + } + else + { + bool success = false; + FStringf buildname("OptionMenuItem%s", sc.String); + // Handle one special case: MapControl maps to Control with one parameter different + PClass *cls = PClass::FindClass(buildname); + if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem")) + { + auto func = dyn_cast(cls->FindSymbol("Init", true)); + if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method. + { + auto &args = func->Variants[0].Proto->ArgumentTypes; + TArray params; + int start = 1; + + params.Push(0); + if (args.Size() > 1 && args[1] == NewPointer(PClass::FindClass("OptionMenuDescriptor"))) + { + params.Push(desc); + start = 2; + } + auto TypeCVar = NewPointer(NewStruct("CVar", nullptr, true)); + + // Note that this array may not be reallocated so its initial size must be the maximum possible elements. + TArray strings(args.Size()); + for (unsigned i = start; i < args.Size(); i++) + { + sc.MustGetString(); + if (args[i] == TypeString) + { + strings.Push(sc.String); + params.Push(&strings.Last()); + } + else if (args[i] == TypeName) + { + params.Push(FName(sc.String).GetIndex()); + } + else if (args[i] == TypeColor) + { + params.Push(V_GetColor(sc)); + } + else if (args[i] == TypeFont) + { + auto f = V_GetFont(sc.String); + if (f == nullptr) + { + sc.ScriptError("Unknown font %s", sc.String); + } + params.Push(f); + } + else if (args[i] == TypeTextureID) + { + auto f = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); + if (!f.Exists()) + { + sc.ScriptMessage("Unknown texture %s", sc.String); + } + params.Push(f.GetIndex()); + } + else if (args[i]->isIntCompatible()) + { + char *endp; + int v = (int)strtoll(sc.String, &endp, 0); + if (*endp != 0) + { + // special check for font color ranges. + v = V_FindFontColor(sc.String); + if (v == CR_UNTRANSLATED && !sc.Compare("untranslated")) + { + // todo: check other data types that may get used. + sc.ScriptError("Integer expected, got %s", sc.String); + } + // Color ranges need to be marked for option menu items to support an older feature where a boolean number could be passed instead. + v |= 0x12340000; + } + if (args[i] == TypeBool) v = !!v; + params.Push(v); + } + else if (args[i]->isFloat()) + { + char *endp; + double v = strtod(sc.String, &endp); + if (*endp != 0) + { + sc.ScriptError("Float expected, got %s", sc.String); + } + params.Push(v); + } + else if (args[i] == TypeCVar) + { + auto cv = FindCVar(sc.String, nullptr); + if (cv == nullptr && *sc.String) + { + if (func->Variants[0].ArgFlags[i] & VARF_Optional) + sc.ScriptMessage("Unknown CVar %s", sc.String); + else + sc.ScriptError("Unknown CVar %s", sc.String); + } + params.Push(cv); + } + else + { + sc.ScriptError("Invalid parameter type %s for menu item", args[i]->DescriptiveName()); + } + if (sc.CheckString(",")) + { + if (i == args.Size() - 1) + { + sc.ScriptError("Too many parameters for %s", cls->TypeName.GetChars()); + } + } + else + { + if (i < args.Size() - 1 && !(func->Variants[0].ArgFlags[i + 1] & VARF_Optional)) + { + sc.ScriptError("Insufficient parameters for %s", cls->TypeName.GetChars()); + } + break; + } + } + + DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew(); + params[0] = item; + VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0); + + if (insertIndex == -1) + { + desc->mItems.Push(item); + } + else + { + desc->mItems.Insert(insertIndex, item); + insertIndex++; + } + + success = true; + } + } + if (!success) + { + sc.ScriptError("Unknown keyword '%s'", sc.String); + } + } + } + for (auto &p : desc->mItems) + { + GC::WriteBarrier(p); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseOptionMenu(FScanner &sc) +{ + sc.MustGetString(); + + DOptionMenuDescriptor *desc = Create(); + desc->mFont = BigUpper; + desc->mMenuName = sc.String; + desc->mSelectedItem = -1; + desc->mScrollPos = 0; + desc->mClass = nullptr; + desc->mPosition = DefaultOptionMenuSettings->mPosition; + desc->mScrollTop = DefaultOptionMenuSettings->mScrollTop; + desc->mIndent = DefaultOptionMenuSettings->mIndent; + desc->mDontDim = false; + desc->mDontBlur = false; + desc->mAnimatedTransition = false; + desc->mAnimated = false; + desc->mProtected = sc.CheckString("protected"); + + ParseOptionMenuBody(sc, desc, -1); + ReplaceMenu(sc, desc); +} + + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseAddOptionMenu(FScanner &sc) +{ + sc.MustGetString(); + + DMenuDescriptor **pOld = MenuDescriptors.CheckKey(sc.String); + if (pOld == nullptr || *pOld == nullptr || !(*pOld)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) + { + sc.ScriptError("%s is not an option menu that can be extended", sc.String); + return; + } + ParseOptionMenuBody(sc, (DOptionMenuDescriptor*)(*pOld), GetInsertIndex(sc, *pOld)); +} + + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseImageScrollerBody(FScanner& sc, DImageScrollerDescriptor* desc) +{ + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("else")) + { + SkipSubBlock(sc); + } + else if (sc.Compare("ifgame")) + { + if (!CheckSkipGameBlock(sc)) + { + // recursively parse sub-block + ParseImageScrollerBody(sc, desc); + } + } + else if (sc.Compare("ifnotgame")) + { + if (!CheckSkipGameBlock(sc, false)) + { + // recursively parse sub-block + ParseImageScrollerBody(sc, desc); + } + } + else if (sc.Compare("ifoption")) + { + if (!CheckSkipOptionBlock(sc)) + { + // recursively parse sub-block + ParseImageScrollerBody(sc, desc); + } + } + else if (sc.Compare("Class")) + { + sc.MustGetString(); + PClass* cls = PClass::FindClass(sc.String); + if (cls == nullptr || !cls->IsDescendantOf("ImageScrollerMenu")) + { + sc.ScriptError("Unknown menu class '%s'", sc.String); + } + desc->mClass = cls; + } + else if (sc.Compare("animatedtransition")) + { + desc->mAnimatedTransition = true; + } + else if (sc.Compare("animated")) + { + desc->mAnimated = true; + } + else if (sc.Compare("DontDim")) + { + desc->mDontDim = true; + } + else if (sc.Compare("DontBlur")) + { + desc->mDontBlur = true; + } + else if (sc.Compare("textBackground")) + { + sc.MustGetString(); + desc->textBackground = GetMenuTexture(sc.String); + } + else if (sc.Compare("textBackgroundBrightness")) + { + sc.MustGetFloat(); + int bb = clamp(int(sc.Float * 255), 0, 255); + desc->textBackgroundBrightness = PalEntry(255, bb, bb, bb); + } + else if (sc.Compare("textScale")) + { + sc.MustGetFloat(); + desc->textScale = sc.Float; + } + else if (sc.Compare("textFont")) + { + sc.MustGetString(); + FFont* newfont = V_GetFont(sc.String); + if (newfont != nullptr) desc->textFont = newfont; + } + else + { + bool success = false; + FStringf buildname("ImageScrollerPage%s", sc.String); + // Handle one special case: MapControl maps to Control with one parameter different + PClass* cls = PClass::FindClass(buildname); + if (cls != nullptr && cls->IsDescendantOf("ImageScrollerPage")) + { + auto func = dyn_cast(cls->FindSymbol("Init", true)); + if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protected init method. + { + auto& args = func->Variants[0].Proto->ArgumentTypes; + TArray params; + + int start = 1; + + params.Push(0); + if (args.Size() > 1 && args[1] == NewPointer(PClass::FindClass("ImageScrollerDescriptor"))) + { + params.Push(desc); + start = 2; + } + auto TypeCVar = NewPointer(NewStruct("CVar", nullptr, true)); + + // Note that this array may not be reallocated so its initial size must be the maximum possible elements. + TArray strings(args.Size()); + for (unsigned i = start; i < args.Size(); i++) + { + sc.MustGetString(); + if (args[i] == TypeString) + { + strings.Push(sc.String); + params.Push(&strings.Last()); + } + else if (args[i] == TypeName) + { + params.Push(FName(sc.String).GetIndex()); + } + else if (args[i] == TypeColor) + { + params.Push(V_GetColor(sc)); + } + else if (args[i] == TypeFont) + { + auto f = V_GetFont(sc.String); + if (f == nullptr) + { + sc.ScriptError("Unknown font %s", sc.String); + } + params.Push(f); + } + else if (args[i] == TypeTextureID) + { + auto f = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); + if (!f.Exists()) + { + sc.ScriptMessage("Unknown texture %s", sc.String); + } + params.Push(f.GetIndex()); + } + else if (args[i]->isIntCompatible()) + { + char* endp; + int v = (int)strtoll(sc.String, &endp, 0); + if (*endp != 0) + { + // special check for font color ranges. + v = V_FindFontColor(sc.String); + if (v == CR_UNTRANSLATED && !sc.Compare("untranslated")) + { + // todo: check other data types that may get used. + sc.ScriptError("Integer expected, got %s", sc.String); + } + } + if (args[i] == TypeBool) v = !!v; + params.Push(v); + } + else if (args[i]->isFloat()) + { + char* endp; + double v = strtod(sc.String, &endp); + if (*endp != 0) + { + sc.ScriptError("Float expected, got %s", sc.String); + } + params.Push(v); + } + else if (args[i] == TypeCVar) + { + auto cv = FindCVar(sc.String, nullptr); + if (cv == nullptr && *sc.String) + { + if (func->Variants[0].ArgFlags[i] & VARF_Optional) + sc.ScriptMessage("Unknown CVar %s", sc.String); + else + sc.ScriptError("Unknown CVar %s", sc.String); + } + params.Push(cv); + } + else + { + sc.ScriptError("Invalid parameter type %s for image page", args[i]->DescriptiveName()); + } + if (sc.CheckString(",")) + { + if (i == args.Size() - 1) + { + sc.ScriptError("Too many parameters for %s", cls->TypeName.GetChars()); + } + } + else + { + if (i < args.Size() - 1 && !(func->Variants[0].ArgFlags[i + 1] & VARF_Optional)) + { + sc.ScriptError("Insufficient parameters for %s", cls->TypeName.GetChars()); + } + break; + } + } + + DMenuItemBase* item = (DMenuItemBase*)cls->CreateNew(); + params[0] = item; + VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0); + desc->mItems.Push((DMenuItemBase*)item); + + success = true; + } + } + if (!success) + { + sc.ScriptError("Unknown keyword '%s'", sc.String); + } + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + +static void ParseImageScroller(FScanner& sc) +{ + sc.MustGetString(); + + DImageScrollerDescriptor* desc = Create(); + + desc->mMenuName = sc.String; + desc->textBackground.SetInvalid(); + desc->textBackgroundBrightness = 0xffffffff; + desc->textFont = SmallFont; + desc->textScale = 1; + desc->mDontDim = false; + desc->mDontBlur = false; + desc->mAnimatedTransition = false; + desc->mAnimated = false; + desc->virtWidth = 320; + desc->virtHeight = 200; + + ParseImageScrollerBody(sc, desc); + bool scratch = ReplaceMenu(sc, desc); + if (scratch) delete desc; +} + + +//============================================================================= +// +// +// +//============================================================================= + +void M_ParseMenuDefs() +{ + int lump, lastlump = 0; + + // these are supposed to get GC'd after parsing is complete. + DefaultListMenuSettings = Create(); + DefaultOptionMenuSettings = Create(); + DefaultListMenuSettings->Reset(); + DefaultOptionMenuSettings->Reset(); + OptionSettings.mLinespacing = 17; + + int IWADMenu = fileSystem.CheckNumForName("MENUDEF", FileSys::ns_global, fileSystem.GetIwadNum()); + + while ((lump = fileSystem.FindLump ("MENUDEF", &lastlump)) != -1) + { + FScanner sc(lump); + + mustPrintErrors = lump >= IWADMenu; + sc.SetCMode(true); + while (sc.GetString()) + { + if (sc.Compare("LISTMENU")) + { + ParseListMenu(sc); + } + else if (sc.Compare("DEFAULTLISTMENU")) + { + bool s = false; + DoParseListMenuBody(sc, DefaultListMenuSettings, s, -1); + if (DefaultListMenuSettings->mItems.Size() > 0) + { + I_FatalError("You cannot add menu items to the menu default settings."); + } + } + else if (sc.Compare("ADDLISTMENU")) + { + ParseAddListMenu(sc); + } + else if (sc.Compare("OPTIONVALUE")) + { + ParseOptionValue(sc); + } + else if (sc.Compare("OPTIONSTRING")) + { + ParseOptionString(sc); + } + else if (sc.Compare("OPTIONMENUSETTINGS")) + { + ParseOptionSettings(sc); + } + else if (sc.Compare("OPTIONMENU")) + { + ParseOptionMenu(sc); + } + else if (sc.Compare("ADDOPTIONMENU")) + { + ParseAddOptionMenu(sc); + } + else if (sc.Compare("DEFAULTOPTIONMENU")) + { + ParseOptionMenuBody(sc, DefaultOptionMenuSettings, -1); + if (DefaultOptionMenuSettings->mItems.Size() > 0) + { + I_FatalError("You cannot add menu items to the menu default settings."); + } + } + else if (sc.Compare("IMAGESCROLLER")) + { + ParseImageScroller(sc); + } + else + { + sc.ScriptError("Unknown keyword '%s'", sc.String); + } + } + if (Args->CheckParm("-nocustommenu")) break; + } + DefaultListMenuClass = DefaultListMenuSettings->mClass; + DefaultListMenuSettings = nullptr; + DefaultOptionMenuClass = DefaultOptionMenuSettings->mClass; + DefaultOptionMenuSettings = nullptr; +} + + +//============================================================================= +// +// Initialize the music configuration submenus +// +//============================================================================= +extern "C" +{ + extern int adl_getBanksCount(); + extern const char *const *adl_getBankNames(); +} + +static void InitMusicMenus() +{ + DMenuDescriptor **advmenu = MenuDescriptors.CheckKey("AdvSoundOptions"); + auto soundfonts = sfmanager.GetList(); + std::tuple sfmenus[] = { std::make_tuple("GusConfigMenu", SF_GUS, "midi_config"), + std::make_tuple("WildMidiConfigMenu", SF_GUS, "wildmidi_config"), + std::make_tuple("TimidityConfigMenu", SF_SF2 | SF_GUS, "timidity_config"), + std::make_tuple("FluidPatchsetMenu", SF_SF2, "fluid_patchset"), + std::make_tuple("ADLMIDICustomBanksMenu", SF_WOPL, "adl_custom_bank"), + std::make_tuple("OPNMIDICustomBanksMenu", SF_WOPN, "opn_custom_bank")}; + + for (auto &p : sfmenus) + { + DMenuDescriptor **menu = MenuDescriptors.CheckKey(std::get<0>(p)); + + if (menu != nullptr) + { + if (soundfonts.Size() > 0) + { + for (auto &entry : soundfonts) + { + if (entry.type & std::get<1>(p)) + { + FString display = entry.mName; + display.ReplaceChars("_", ' '); + auto it = CreateOptionMenuItemCommand(display.GetChars(), FStringf("%s \"%s\"", std::get<2>(p), entry.mName.GetChars()), true); + static_cast(*menu)->mItems.Push(it); + } + } + } + else if (advmenu != nullptr) + { + // Remove the item for this submenu + auto d = static_cast(*advmenu); + auto it = d->GetItem(std::get<0>(p)); + if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); + } + } + } + + DMenuDescriptor **menu = MenuDescriptors.CheckKey("ADLBankMenu"); + + if (menu != nullptr) + { + const char* const* adl_bank_names; + int adl_banks_count = ZMusic_GetADLBanks(&adl_bank_names); + for (int i=0; i < adl_banks_count; i++) + { + auto it = CreateOptionMenuItemCommand(adl_bank_names[i], FStringf("adl_bank %d", i), true); + static_cast(*menu)->mItems.Push(it); + } + } +} + +//============================================================================= +// +// Special menus will be created once all engine data is loaded +// +//============================================================================= +void I_BuildMIDIMenuList(FOptionValues*); + +void M_CreateMenus() +{ + InitMusicMenus(); + FOptionValues **opt = OptionValues.CheckKey(NAME_Mididevices); + if (opt != nullptr) + { + I_BuildMIDIMenuList(*opt); + } + opt = OptionValues.CheckKey(NAME_Aldevices); + if (opt != nullptr) + { + I_BuildALDeviceList(*opt); + } + opt = OptionValues.CheckKey(NAME_Alresamplers); + if (opt != nullptr) + { + I_BuildALResamplersList(*opt); + } +} + + diff --git a/src/common/menu/menustate.h b/src/common/menu/menustate.h new file mode 100644 index 00000000000..5dfd386095d --- /dev/null +++ b/src/common/menu/menustate.h @@ -0,0 +1,10 @@ +#pragma once + +enum EMenuState : int +{ + MENU_Off, // Menu is closed + MENU_On, // Menu is opened + MENU_WaitKey, // Menu is opened and waiting for a key in the controls menu + MENU_OnNoPause, // Menu is opened but does not pause the game +}; +extern EMenuState menuactive; // Menu overlayed? diff --git a/src/common/menu/messagebox.cpp b/src/common/menu/messagebox.cpp new file mode 100644 index 00000000000..21f22d19052 --- /dev/null +++ b/src/common/menu/messagebox.cpp @@ -0,0 +1,104 @@ +/* +** messagebox.cpp +** Confirmation, notification screns +** +**--------------------------------------------------------------------------- +** Copyright 2010 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "menu.h" +#include "gstrings.h" +#include "i_video.h" +#include "c_dispatch.h" +#include "vm.h" +#include "menustate.h" + +FName MessageBoxClass = NAME_MessageBoxMenu; + +CVAR(Bool, m_quickexit, false, CVAR_ARCHIVE) + +typedef void(*hfunc)(); +DEFINE_ACTION_FUNCTION(DMessageBoxMenu, CallHandler) +{ + PARAM_PROLOGUE; + PARAM_POINTERTYPE(Handler, hfunc); + Handler(); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action = NAME_None, hfunc handler = nullptr) +{ + auto c = PClass::FindClass(MessageBoxClass); + if (!c->IsDescendantOf(NAME_MessageBoxMenu)) c = PClass::FindClass(NAME_MessageBoxMenu); + auto p = c->CreateNew(); + FString namestr = message; + + IFVIRTUALPTRNAME(p, NAME_MessageBoxMenu, Init) + { + VMValue params[] = { p, parent, &namestr, messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; + VMCall(func, params, countof(params), nullptr, 0); + return (DMenu*)p; + } + return nullptr; +} + +//============================================================================= +// +// +// +//============================================================================= + +void M_StartMessage(const char *message, int messagemode, FName action) +{ + if (CurrentMenu == NULL) + { + // only play a sound if no menu was active before + M_StartControlPanel(menuactive == MENU_Off); + } + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, message, messagemode, false, action); + newmenu->mParentMenu = CurrentMenu; + M_ActivateMenu(newmenu); +} + +DEFINE_ACTION_FUNCTION(DMenu, StartMessage) +{ + PARAM_PROLOGUE; + PARAM_STRING(msg); + PARAM_INT(mode); + PARAM_NAME(action); + M_StartMessage(msg.GetChars(), mode, action); + return 0; +} diff --git a/src/menu/optionmenu.cpp b/src/common/menu/optionmenu.cpp similarity index 85% rename from src/menu/optionmenu.cpp rename to src/common/menu/optionmenu.cpp index ebe27800baf..99069d1769f 100644 --- a/src/menu/optionmenu.cpp +++ b/src/common/menu/optionmenu.cpp @@ -33,7 +33,8 @@ */ #include "v_video.h" -#include "menu/menu.h" +#include "menu.h" +#include "vm.h" //============================================================================= @@ -52,3 +53,16 @@ DMenuItemBase *DOptionMenuDescriptor::GetItem(FName name) return NULL; } +void SetCVarDescription(FBaseCVar* cvar, const FString* label) +{ + cvar->AddDescription(*label); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_OptionMenuItemOption, SetCVarDescription, SetCVarDescription) +{ + PARAM_PROLOGUE; + PARAM_POINTER(cv, FBaseCVar); + PARAM_STRING(label); + SetCVarDescription(cv, &label); + return 0; +} \ No newline at end of file diff --git a/src/menu/resolutionmenu.cpp b/src/common/menu/resolutionmenu.cpp similarity index 91% rename from src/menu/resolutionmenu.cpp rename to src/common/menu/resolutionmenu.cpp index 39114c8e7fc..1920927bb0c 100644 --- a/src/menu/resolutionmenu.cpp +++ b/src/common/menu/resolutionmenu.cpp @@ -32,17 +32,16 @@ ** */ -#include "doomdef.h" -#include "doomstat.h" #include "c_dispatch.h" #include "c_cvars.h" #include "v_video.h" -#include "menu/menu.h" +#include "menu.h" +#include "printf.h" CVAR(Int, menu_resolution_custom_width, 640, 0) CVAR(Int, menu_resolution_custom_height, 480, 0) -EXTERN_CVAR(Bool, fullscreen) +EXTERN_CVAR(Bool, vid_fullscreen) EXTERN_CVAR(Bool, win_maximized) EXTERN_CVAR(Float, vid_scale_custompixelaspect) EXTERN_CVAR(Int, vid_scale_customwidth) @@ -66,7 +65,7 @@ CCMD (menu_resolution_set_custom) CCMD (menu_resolution_commit_changes) { - int do_fullscreen = fullscreen; + int do_fullscreen = vid_fullscreen; if (argv.argc() > 1) { do_fullscreen = atoi(argv[1]); @@ -81,11 +80,11 @@ CCMD (menu_resolution_commit_changes) } else { - fullscreen = true; + vid_fullscreen = true; vid_scalemode = 5; vid_scalefactor = 1.; - vid_scale_customwidth = menu_resolution_custom_width; - vid_scale_customheight = menu_resolution_custom_height; + vid_scale_customwidth = *menu_resolution_custom_width; + vid_scale_customheight = *menu_resolution_custom_height; vid_scale_custompixelaspect = 1.0; } } diff --git a/src/common/menu/savegamemanager.cpp b/src/common/menu/savegamemanager.cpp new file mode 100644 index 00000000000..1350930210c --- /dev/null +++ b/src/common/menu/savegamemanager.cpp @@ -0,0 +1,585 @@ +/* +** loadsavemenu.cpp +** The load game and save game menus +** +**--------------------------------------------------------------------------- +** Copyright 2001-2010 Randy Heit +** Copyright 2010-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "menu.h" +#include "version.h" +#include "m_png.h" +#include "filesystem.h" +#include "v_text.h" +#include "gstrings.h" +#include "serializer.h" +#include "vm.h" +#include "i_system.h" +#include "v_video.h" +#include "findfile.h" +#include "v_draw.h" +#include "savegamemanager.h" +#include "m_argv.h" +#include "i_specialpaths.h" + +CVAR(String, save_dir, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +FString SavegameFolder; + +//============================================================================= +// +// Save data maintenance +// +//============================================================================= + +void FSavegameManagerBase::ClearSaveGames() +{ + for (unsigned i = 0; ibNoDelete) + delete SaveGames[i]; + } + SaveGames.Clear(); +} + +FSavegameManagerBase::~FSavegameManagerBase() +{ + ClearSaveGames(); +} + +//============================================================================= +// +// Save data maintenance +// +//============================================================================= + +int FSavegameManagerBase::RemoveSaveSlot(int index) +{ + int listindex = SaveGames[0]->bNoDelete ? index - 1 : index; + if (listindex < 0) return index; + + RemoveFile(SaveGames[index]->Filename.GetChars()); + UnloadSaveData(); + + FSaveGameNode *file = SaveGames[index]; + + if (quickSaveSlot == SaveGames[index]) + { + quickSaveSlot = nullptr; + } + if (!file->bNoDelete) delete file; + + if (LastSaved == listindex) LastSaved = -1; + else if (LastSaved > listindex) LastSaved--; + if (LastAccessed == listindex) LastAccessed = -1; + else if (LastAccessed > listindex) LastAccessed--; + + SaveGames.Delete(index); + if ((unsigned)index >= SaveGames.Size()) index--; + ExtractSaveData(index); + return index; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveSaveSlot) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(sel); + ACTION_RETURN_INT(self->RemoveSaveSlot(sel)); +} + +//============================================================================= +// +// +// +//============================================================================= + +int FSavegameManagerBase::InsertSaveNode(FSaveGameNode *node) +{ + if (SaveGames.Size() == 0) + { + return SaveGames.Push(node); + } + + if (node->bOldVersion) + { // Add node at bottom of list + return SaveGames.Push(node); + } + else + { // Add node at top of list + unsigned int i = 0; + //if (SaveGames[0] == &NewSaveNode) i++; // To not insert above the "new savegame" dummy entry. + for (; i < SaveGames.Size(); i++) + { + if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0) + { + break; + } + } + SaveGames.Insert(i, node); + return i; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave) +{ + if (file.IsEmpty()) + return; + + ReadSaveStrings(); + + // See if the file is already in our list + for (unsigned i = 0; iFilename.Compare(file) == 0) +#else + if (node->Filename.CompareNoCase(file) == 0) +#endif + { + node->SaveTitle = title; + node->bOldVersion = false; + node->bMissingWads = false; + if (okForQuicksave) + { + if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; + LastAccessed = LastSaved = i; + } + return; + } + } + + auto node = new FSaveGameNode; + node->SaveTitle = title; + node->Filename = file; + node->bOldVersion = false; + node->bMissingWads = false; + int index = InsertSaveNode(node); + + if (okForQuicksave) + { + if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; + LastAccessed = LastSaved = index; + } + else + { + LastAccessed = ++LastSaved; + } +} + + +//============================================================================= +// +// Loads the savegame +// +//============================================================================= + +void FSavegameManagerBase::LoadSavegame(int Selected) +{ + PerformLoadGame(SaveGames[Selected]->Filename.GetChars(), true); + if (quickSaveSlot == (FSaveGameNode*)1) + { + quickSaveSlot = SaveGames[Selected]; + } + M_ClearMenus(); + LastAccessed = Selected; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(sel); + self->LoadSavegame(sel); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::DoSave(int Selected, const char *savegamestring) +{ + if (Selected != 0) + { + auto node = SaveGames[Selected]; + PerformSaveGame(node->Filename.GetChars(), savegamestring); + } + else + { + // Find an unused filename and save as that + FString filename; + int i; + + for (i = 0;; ++i) + { + filename = BuildSaveName("save", i); + if (!FileExists(filename)) + { + break; + } + } + PerformSaveGame(filename.GetChars(), savegamestring); + } + M_ClearMenus(); +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(sel); + PARAM_STRING(name); + self->DoSave(sel, name.GetChars()); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +unsigned FSavegameManagerBase::ExtractSaveData(int index) +{ + std::unique_ptr resf; + FSaveGameNode *node; + + if (index == -1) + { + if (SaveGames.Size() > 0 && SaveGames[0]->bNoDelete) + { + index = LastSaved + 1; + } + else + { + index = LastAccessed < 0? 0 : LastAccessed; + } + } + + UnloadSaveData(); + + if ((unsigned)index < SaveGames.Size() && + (node = SaveGames[index]) && + !node->Filename.IsEmpty() && + !node->bOldVersion && + ( (resf.reset(FResourceFile::OpenResourceFile(node->Filename.GetChars(), true))), resf != nullptr)) + { + auto info = resf->FindEntry("info.json"); + if (info < 0) + { + // this should not happen because the file has already been verified. + return index; + } + + auto data = resf->Read(info); + FSerializer arc; + if (!arc.OpenReader(data.string(), data.size())) + { + return index; + } + + SaveCommentString = ExtractSaveComment(arc); + + auto pic = resf->FindEntry("savepic.png"); + if (pic >= 0) + { + // This must use READER_CACHED or it will lock the savegame file. + FileReader picreader = resf->GetEntryReader(pic, FileSys::READER_CACHED, FileSys::READERFLAG_SEEKABLE); + PNGHandle *png = M_VerifyPNG(picreader); + if (png != nullptr) + { + SavePic = PNGTexture_CreateFromFile(png, node->Filename); + delete png; + if (SavePic && SavePic->GetDisplayWidth() == 1 && SavePic->GetDisplayHeight() == 1) + { + delete SavePic; + SavePic = nullptr; + } + } + } + } + return index; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::UnloadSaveData() +{ + if (SavePic != nullptr) + { + delete SavePic; + } + + SaveCommentString = ""; + SavePic = nullptr; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, UnloadSaveData) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + self->UnloadSaveData(); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::ClearSaveStuff() +{ + UnloadSaveData(); + if (quickSaveSlot == (FSaveGameNode*)1) + { + quickSaveSlot = nullptr; + } +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, ClearSaveStuff) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + self->ClearSaveStuff(); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +bool FSavegameManagerBase::DrawSavePic(int x, int y, int w, int h) +{ + if (SavePic == nullptr) return false; + DrawTexture(twod, SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE); + return true; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(x); + PARAM_INT(y); + PARAM_INT(w); + PARAM_INT(h); + ACTION_RETURN_BOOL(self->DrawSavePic(x, y, w, h)); +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::SetFileInfo(int Selected) +{ + if (!SaveGames[Selected]->Filename.IsEmpty()) + { + SaveCommentString.Format("File on disk:\n%s", SaveGames[Selected]->Filename.GetChars()); + } +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, SetFileInfo) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(i); + self->SetFileInfo(i); + return 0; +} + + +//============================================================================= +// +// +// +//============================================================================= + +unsigned FSavegameManagerBase::SavegameCount() +{ + return SaveGames.Size(); +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + ACTION_RETURN_INT(self->SavegameCount()); +} + +//============================================================================= +// +// +// +//============================================================================= + +FSaveGameNode *FSavegameManagerBase::GetSavegame(int i) +{ + if ((unsigned)i >= SaveGames.Size()) ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Bad savegame index"); + return SaveGames[i]; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(i); + ACTION_RETURN_POINTER(self->GetSavegame(i)); +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::InsertNewSaveNode() +{ + NewSaveNode.SaveTitle = GStrings.GetString("NEWSAVE"); + NewSaveNode.bNoDelete = true; + SaveGames.Insert(0, &NewSaveNode); +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, InsertNewSaveNode) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + self->InsertNewSaveNode(); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +bool FSavegameManagerBase::RemoveNewSaveNode() +{ + if (SaveGames[0] == &NewSaveNode) + { + SaveGames.Delete(0); + return true; + } + return false; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + ACTION_RETURN_INT(self->RemoveNewSaveNode()); +} + + +DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + self->ReadSaveStrings(); + return 0; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(sel); + ACTION_RETURN_INT(self->ExtractSaveData(sel)); +} + + +DEFINE_FIELD(FSaveGameNode, SaveTitle); +DEFINE_FIELD(FSaveGameNode, Filename); +DEFINE_FIELD(FSaveGameNode, bOldVersion); +DEFINE_FIELD(FSaveGameNode, bMissingWads); +DEFINE_FIELD(FSaveGameNode, bNoDelete); + +DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, WindowSize); +DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, quickSaveSlot); +DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, SaveCommentString); + +//============================================================================= +// +// todo: cache this - it never changes once set up. +// +//============================================================================= + +FString G_GetSavegamesFolder() +{ + FString name; + bool usefilter; + + if (const char* const dir = Args->CheckValue("-savedir")) + { + name = dir; + usefilter = false; //-savedir specifies an absolute save directory path. + } + else + { + name = **save_dir ? FString(save_dir) : M_GetSavegamesPath(); + usefilter = true; + } + + const size_t len = name.Len(); + if (len > 0) + { + FixPathSeperator(name); + if (name[len - 1] != '/') + name << '/'; + } + + if (usefilter && SavegameFolder.IsNotEmpty()) + name << SavegameFolder << '/'; + + name = NicePath(name.GetChars()); + CreatePath(name.GetChars()); + return name; +} + +//============================================================================= +// +// +// +//============================================================================= + +FString G_BuildSaveName(const char* prefix) +{ + FString name = G_GetSavegamesFolder() + prefix; + DefaultExtension(name, "." SAVEGAME_EXT); // only add an extension if the prefix doesn't have one already. + name = NicePath(name.GetChars()); + name.Substitute("\\", "/"); + return name; +} + diff --git a/src/common/menu/savegamemanager.h b/src/common/menu/savegamemanager.h new file mode 100644 index 00000000000..20b466b53d7 --- /dev/null +++ b/src/common/menu/savegamemanager.h @@ -0,0 +1,64 @@ +#pragma once + +#include "zstring.h" +#include "tarray.h" + +class FGameTexture; +class FSerializer; + +// The savegame manager contains too much code that is game specific. Parts are shareable but need more work first. +struct FSaveGameNode +{ + FString SaveTitle; + FString Filename; + bool bOldVersion = false; + bool bMissingWads = false; + bool bNoDelete = false; +}; + +struct FSavegameManagerBase +{ +protected: + TArray SaveGames; + FSaveGameNode NewSaveNode; + int LastSaved = -1; + int LastAccessed = -1; + FGameTexture *SavePic = nullptr; + +public: + int WindowSize = 0; + FString SaveCommentString; + FSaveGameNode *quickSaveSlot = nullptr; + virtual ~FSavegameManagerBase(); + +protected: + int InsertSaveNode(FSaveGameNode *node); + virtual void PerformSaveGame(const char *fn, const char *sgdesc) = 0; + virtual void PerformLoadGame(const char *fn, bool) = 0; + virtual FString ExtractSaveComment(FSerializer &arc) = 0; + virtual FString BuildSaveName(const char* prefix, int slot) = 0; +public: + void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave); + void ClearSaveGames(); + + virtual void ReadSaveStrings() = 0; + void UnloadSaveData(); + + int RemoveSaveSlot(int index); + void LoadSavegame(int Selected); + void DoSave(int Selected, const char *savegamestring); + unsigned ExtractSaveData(int index); + void ClearSaveStuff(); + bool DrawSavePic(int x, int y, int w, int h); + void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor); + void SetFileInfo(int Selected); + unsigned SavegameCount(); + FSaveGameNode *GetSavegame(int i); + void InsertNewSaveNode(); + bool RemoveNewSaveNode(); + +}; + +extern FString SavegameFolder; // specifies a subdirectory for the current IWAD. +FString G_GetSavegamesFolder(); +FString G_BuildSaveName(const char* prefix); diff --git a/src/common/models/bonecomponents.h b/src/common/models/bonecomponents.h new file mode 100644 index 00000000000..1e65389ea08 --- /dev/null +++ b/src/common/models/bonecomponents.h @@ -0,0 +1,16 @@ +#pragma once +#include "dobject.h" +#include "tarray.h" +#include "TRS.h" +#include "matrix.h" + + +class DBoneComponents : public DObject +{ + DECLARE_CLASS(DBoneComponents, DObject); +public: + TArray> trscomponents; + TArray> trsmatrix; + + DBoneComponents() = default; +}; diff --git a/src/common/models/model.cpp b/src/common/models/model.cpp new file mode 100644 index 00000000000..0f160341588 --- /dev/null +++ b/src/common/models/model.cpp @@ -0,0 +1,240 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2005-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_models.cpp +** +** General model handling code +** +**/ +#include // offsetof() macro. + +#include "filesystem.h" +#include "cmdlib.h" +#include "sc_man.h" +#include "m_crc32.h" +#include "printf.h" +#include "model_ue1.h" +#include "model_obj.h" +#include "model_md2.h" +#include "model_md3.h" +#include "model_kvx.h" +#include "model_iqm.h" +#include "i_time.h" +#include "voxels.h" +#include "texturemanager.h" +#include "modelrenderer.h" + +TDeletingArray Models; +TArray SpriteModelFrames; +TMap BaseSpriteModelFrames; + + +///////////////////////////////////////////////////////////////////////////// + +void FlushModels() +{ + for (int i = Models.Size() - 1; i >= 0; i--) + { + Models[i]->DestroyVertexBuffer(); + } +} + +///////////////////////////////////////////////////////////////////////////// + +FModel::FModel() +{ + for (int i = 0; i < NumModelRendererTypes; i++) + mVBuf[i] = nullptr; +} + +FModel::~FModel() +{ + DestroyVertexBuffer(); +} + +void FModel::DestroyVertexBuffer() +{ + for (int i = 0; i < NumModelRendererTypes; i++) + { + delete mVBuf[i]; + mVBuf[i] = nullptr; + } +} + +//=========================================================================== +// +// FindGFXFile +// +//=========================================================================== + +static int FindGFXFile(FString & fn) +{ + int lump = fileSystem.CheckNumForFullName(fn.GetChars()); // if we find something that matches the name plus the extension, return it and do not enter the substitution logic below. + if (lump != -1) return lump; + + int best = -1; + auto dot = fn.LastIndexOf('.'); + auto slash = fn.LastIndexOf('/'); + if (dot > slash) fn.Truncate(dot); + + static const char * extensions[] = { ".png", ".jpg", ".tga", ".pcx", nullptr }; + + for (const char ** extp=extensions; *extp; extp++) + { + lump = fileSystem.CheckNumForFullName((fn + *extp).GetChars()); + if (lump >= best) best = lump; + } + return best; +} + + +//=========================================================================== +// +// LoadSkin +// +//=========================================================================== + +FTextureID LoadSkin(const char * path, const char * fn) +{ + FString buffer; + + buffer.Format("%s%s", path, fn); + + int texlump = FindGFXFile(buffer); + const char * const texname = texlump < 0 ? fn : fileSystem.GetFileFullName(texlump); + return TexMan.CheckForTexture(texname, ETextureType::Any, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ForceLookup); +} + +//=========================================================================== +// +// ModelFrameHash +// +//=========================================================================== + +int ModelFrameHash(FSpriteModelFrame * smf) +{ + return crc32(0, (const unsigned char *)(&smf->type), offsetof(FSpriteModelFrame, hashnext) - offsetof(FSpriteModelFrame, type)); +} + +//=========================================================================== +// +// FindModel +// +//=========================================================================== + +unsigned FindModel(const char * path, const char * modelfile, bool silent) +{ + FModel * model = nullptr; + FString fullname; + + if (path) fullname.Format("%s%s", path, modelfile); + else fullname = modelfile; + int lump = fileSystem.CheckNumForFullName(fullname.GetChars()); + + if (lump<0) + { + Printf(PRINT_HIGH, "FindModel: '%s' not found\n", fullname.GetChars()); + return -1; + } + + for(unsigned i = 0; i< Models.Size(); i++) + { + if (Models[i]->mFileName.CompareNoCase(fullname) == 0) return i; + } + + auto len = fileSystem.FileLength(lump); + if (len >= 0x80000000ll) + { + Printf(PRINT_HIGH, "LoadModel: File to large: '%s'\n", fullname.GetChars()); + return -1; + } + + auto lumpd = fileSystem.ReadFile(lump); + const char * buffer = lumpd.string(); + + if ( (size_t)fullname.LastIndexOf("_d.3d") == fullname.Len()-5 ) + { + FString anivfile = fullname.GetChars(); + anivfile.Substitute("_d.3d","_a.3d"); + if ( fileSystem.CheckNumForFullName(anivfile.GetChars()) > 0 ) + { + model = new FUE1Model; + } + } + else if ( (size_t)fullname.LastIndexOf("_a.3d") == fullname.Len()-5 ) + { + FString datafile = fullname.GetChars(); + datafile.Substitute("_a.3d","_d.3d"); + if ( fileSystem.CheckNumForFullName(datafile.GetChars()) > 0 ) + { + model = new FUE1Model; + } + } + else if ( (size_t)fullname.LastIndexOf(".obj") == fullname.Len() - 4 ) + { + model = new FOBJModel; + } + else if (!memcmp(buffer, "DMDM", 4)) + { + model = new FDMDModel; + } + else if (!memcmp(buffer, "IDP2", 4)) + { + model = new FMD2Model; + } + else if (!memcmp(buffer, "IDP3", 4)) + { + model = new FMD3Model; + } + else if (!memcmp(buffer, "INTERQUAKEMODEL\0", 16)) + { + model = new IQMModel; + } + + if (model != nullptr) + { + if (!model->Load(path, lump, buffer, (int)len)) + { + delete model; + return -1; + } + } + else + { + // try loading as a voxel + FVoxel *voxel = R_LoadKVX(lump); + if (voxel != nullptr) + { + model = new FVoxelModel(voxel, true); + } + else + { + Printf(PRINT_HIGH, "LoadModel: Unknown model format in '%s'\n", fullname.GetChars()); + return -1; + } + } + // The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized + model->mFileName = fullname; + model->mFilePath = {path, modelfile}; + return Models.Push(model); +} + diff --git a/src/common/models/model.h b/src/common/models/model.h new file mode 100644 index 00000000000..7d5746e3317 --- /dev/null +++ b/src/common/models/model.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include "textureid.h" +#include "i_modelvertexbuffer.h" +#include "matrix.h" +#include "palettecontainer.h" +#include "TRS.h" +#include "tarray.h" +#include "name.h" + +class DBoneComponents; +class FModelRenderer; +class FGameTexture; +class IModelVertexBuffer; +class FModel; +struct FSpriteModelFrame; + +FTextureID LoadSkin(const char* path, const char* fn); +void FlushModels(); + +extern TDeletingArray Models; +extern TArray SpriteModelFrames; +extern TMap BaseSpriteModelFrames; + +#define MD3_MAX_SURFACES 32 +#define MIN_MODELS 4 + +struct FSpriteModelFrame +{ + uint8_t modelsAmount = 0; + TArray modelIDs; + TArray skinIDs; + TArray surfaceskinIDs; + TArray modelframes; + TArray animationIDs; + float xscale, yscale, zscale; + // [BB] Added zoffset, rotation parameters and flags. + // Added xoffset, yoffset + float xoffset, yoffset, zoffset; + float xrotate, yrotate, zrotate; + float rotationCenterX, rotationCenterY, rotationCenterZ; + float rotationSpeed; +private: + unsigned int flags; +public: + const void* type; // used for hashing, must point to something usable as identifier for the model's owner. + short sprite; + short frame; + int hashnext; + float angleoffset; + // added pithoffset, rolloffset. + float pitchoffset, rolloffset; // I don't want to bother with type transformations, so I made this variables float. + bool isVoxel; + unsigned int getFlags(class DActorModelData * defs) const; + friend void InitModels(); + friend void ParseModelDefLump(int Lump); +}; + + +enum ModelRendererType +{ + GLModelRendererType, + SWModelRendererType, + PolyModelRendererType, + NumModelRendererTypes +}; + +enum EFrameError +{ + FErr_NotFound = -1, + FErr_Voxel = -2, + FErr_Singleframe = -3 +}; + +class FModel +{ +public: + + FModel(); + virtual ~FModel(); + + virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0; + + virtual int FindFrame(const char * name, bool nodefault = false) = 0; + + // [RL0] these are used for decoupled iqm animations + virtual int FindFirstFrame(FName name) { return FErr_NotFound; } + virtual int FindLastFrame(FName name) { return FErr_NotFound; } + virtual double FindFramerate(FName name) { return FErr_NotFound; } + + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) = 0; + virtual void BuildVertexBuffer(FModelRenderer *renderer) = 0; + virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) = 0; + virtual float getAspectFactor(float vscale) { return 1.f; } + virtual const TArray* AttachAnimationData() { return nullptr; }; + virtual const TArray CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* bones, int index) { return {}; }; + + void SetVertexBuffer(int type, IModelVertexBuffer *buffer) { mVBuf[type] = buffer; } + IModelVertexBuffer *GetVertexBuffer(int type) const { return mVBuf[type]; } + void DestroyVertexBuffer(); + + bool hasSurfaces = false; + + FString mFileName; + std::pair mFilePath; + + FSpriteModelFrame *baseFrame; +private: + IModelVertexBuffer *mVBuf[NumModelRendererTypes]; +}; + +int ModelFrameHash(FSpriteModelFrame* smf); +unsigned FindModel(const char* path, const char* modelfile, bool silent = false); + diff --git a/src/common/models/model_iqm.h b/src/common/models/model_iqm.h new file mode 100644 index 00000000000..464f5c13ad9 --- /dev/null +++ b/src/common/models/model_iqm.h @@ -0,0 +1,230 @@ +#pragma once + +#include +#include "model.h" +#include "vectors.h" +#include "matrix.h" +#include "common/rendering/i_modelvertexbuffer.h" +#include "m_swap.h" +#include "name.h" + +class DBoneComponents; + +struct IQMMesh +{ + FString Name; + FString Material; + uint32_t FirstVertex; + uint32_t NumVertices; + uint32_t FirstTriangle; + uint32_t NumTriangles; + FTextureID Skin; +}; + +enum IQMVertexArrayType +{ + IQM_POSITION = 0, // float, 3 + IQM_TEXCOORD = 1, // float, 2 + IQM_NORMAL = 2, // float, 3 + IQM_TANGENT = 3, // float, 4 + IQM_BLENDINDEXES = 4, // ubyte, 4 + IQM_BLENDWEIGHTS = 5, // ubyte, 4 + IQM_COLOR = 6, // ubyte, 4 + IQM_CUSTOM = 0x10 +}; + +enum IQMVertexArrayFormat +{ + IQM_BYTE = 0, + IQM_UBYTE = 1, + IQM_SHORT = 2, + IQM_USHORT = 3, + IQM_INT = 4, + IQM_UINT = 5, + IQM_HALF = 6, + IQM_FLOAT = 7, + IQM_DOUBLE = 8, +}; + +struct IQMVertexArray +{ + IQMVertexArrayType Type; + uint32_t Flags; + IQMVertexArrayFormat Format; + uint32_t Size; + uint32_t Offset; +}; + +struct IQMTriangle +{ + uint32_t Vertex[3]; +}; + +struct IQMAdjacency +{ + uint32_t Triangle[3]; +}; + +struct IQMJoint +{ + FString Name; + int32_t Parent; // parent < 0 means this is a root bone + FVector3 Translate; + FVector4 Quaternion; + FVector3 Scale; +}; + +struct IQMPose +{ + int32_t Parent; // parent < 0 means this is a root bone + uint32_t ChannelMask; // mask of which 10 channels are present for this joint pose + float ChannelOffset[10]; + float ChannelScale[10]; + // channels 0..2 are translation and channels 3..6 are quaternion rotation + // rotation is in relative/parent local space + // channels 7..9 are scale + // output = (input*scale)*rotation + translation +}; + +struct IQMAnim +{ + FString Name; + uint32_t FirstFrame; + uint32_t NumFrames; + float Framerate; + bool Loop; +}; + +struct IQMBounds +{ + float BBMins[3]; + float BBMaxs[3]; + float XYRadius; + float Radius; +}; + +class IQMFileReader; + +class IQMModel : public FModel +{ +public: + IQMModel(); + ~IQMModel(); + + bool Load(const char* fn, int lumpnum, const char* buffer, int length) override; + int FindFrame(const char* name, bool nodefault) override; + int FindFirstFrame(FName name) override; + int FindLastFrame(FName name) override; + double FindFramerate(FName name) override; + void RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) override; + void BuildVertexBuffer(FModelRenderer* renderer) override; + void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override; + const TArray* AttachAnimationData() override; + const TArray CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* bones, int index) override; + +private: + void LoadGeometry(); + void UnloadGeometry(); + + void LoadPosition(IQMFileReader& reader, const IQMVertexArray& vertexArray); + void LoadTexcoord(IQMFileReader& reader, const IQMVertexArray& vertexArray); + void LoadNormal(IQMFileReader& reader, const IQMVertexArray& vertexArray); + void LoadBlendIndexes(IQMFileReader& reader, const IQMVertexArray& vertexArray); + void LoadBlendWeights(IQMFileReader& reader, const IQMVertexArray& vertexArray); + + int mLumpNum = -1; + + TMap NamedAnimations; + + TArray Meshes; + TArray Triangles; + TArray Adjacency; + TArray Joints; + TArray Poses; + TArray Anims; + TArray Bounds; + TArray VertexArrays; + uint32_t NumVertices = 0; + + TArray Vertices; + + TArray baseframe; + TArray inversebaseframe; + TArray TRSData; +}; + +struct IQMReadErrorException { }; + +class IQMFileReader +{ +public: + IQMFileReader(const void* buffer, int length) : buffer((const char*)buffer), length(length) { } + + uint8_t ReadUByte() + { + uint8_t value; + Read(&value, sizeof(uint8_t)); + return value; + } + + int32_t ReadInt32() + { + int32_t value; + Read(&value, sizeof(int32_t)); + value = LittleLong(value); + return value; + } + + int16_t ReadInt16() + { + int16_t value; + Read(&value, sizeof(int16_t)); + value = LittleShort(value); + return value; + } + + uint32_t ReadUInt32() + { + return ReadInt32(); + } + + uint16_t ReadUInt16() + { + return ReadInt16(); + } + + float ReadFloat() + { + float value; + Read(&value, sizeof(float)); + return value; + } + + FString ReadName(const TArray& textBuffer) + { + uint32_t nameOffset = ReadUInt32(); + if (nameOffset >= textBuffer.Size()) + throw IQMReadErrorException(); + return textBuffer.Data() + nameOffset; + } + + void Read(void* data, int size) + { + if (pos + size > length || size < 0 || size > 0x0fffffff) + throw IQMReadErrorException(); + memcpy(data, buffer + pos, size); + pos += size; + } + + void SeekTo(int newPos) + { + if (newPos < 0 || newPos > length) + throw IQMReadErrorException(); + pos = newPos; + } + +private: + const char* buffer = nullptr; + int length = 0; + int pos = 0; +}; diff --git a/src/common/models/model_kvx.h b/src/common/models/model_kvx.h new file mode 100644 index 00000000000..2175bcbca73 --- /dev/null +++ b/src/common/models/model_kvx.h @@ -0,0 +1,69 @@ +#pragma once + +#include "model.h" +#include "i_modelvertexbuffer.h" +#include "tarray.h" +#include "xs_Float.h" + +struct FVoxel; +struct kvxslab_t; +class FModelRenderer; +class FGameTexture; + +struct FVoxelVertexHash +{ + // Returns the hash value for a key. + hash_t Hash(const FModelVertex &key) + { + int ix = int(key.x); + int iy = int(key.y); + int iz = int(key.z); + return (hash_t)(ix + (iy<<9) + (iz<<18)); + } + + // Compares two keys, returning zero if they are the same. + int Compare(const FModelVertex &left, const FModelVertex &right) + { + return left.x != right.x || left.y != right.y || left.z != right.z || left.u != right.u || left.v != right.v; + } +}; + +struct FIndexInit +{ + void Init(unsigned int &value) + { + value = 0xffffffff; + } +}; + +typedef TMap FVoxelMap; + + +class FVoxelModel : public FModel +{ +protected: + FVoxel *mVoxel; + bool mOwningVoxel; // if created through MODELDEF deleting this object must also delete the voxel object + FTextureID mPalette; + unsigned int mNumIndices; + TArray mVertices; + TArray mIndices; + + void MakeSlabPolys(int x, int y, kvxslab_t *voxptr, FVoxelMap &check); + void AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3, int x4, int y4, int z4, uint8_t color, FVoxelMap &check); + unsigned int AddVertex(FModelVertex &vert, FVoxelMap &check); + +public: + FVoxelModel(FVoxel *voxel, bool owned); + ~FVoxelModel(); + bool Load(const char * fn, int lumpnum, const char * buffer, int length) override; + void Initialize(); + virtual int FindFrame(const char* name, bool nodefault) override; + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) override; + virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) override; + FTextureID GetPaletteTexture() const { return mPalette; } + void BuildVertexBuffer(FModelRenderer *renderer) override; + float getAspectFactor(float vscale) override; +}; + + diff --git a/src/common/models/model_md2.h b/src/common/models/model_md2.h new file mode 100644 index 00000000000..fd1646dc9bc --- /dev/null +++ b/src/common/models/model_md2.h @@ -0,0 +1,137 @@ +#pragma once +#include "model.h" + +#define MD2_MAGIC 0x32504449 +#define DMD_MAGIC 0x4D444D44 +#define MAX_LODS 4 + +class FDMDModel : public FModel +{ +protected: + + struct FTriangle + { + unsigned short vertexIndices[3]; + unsigned short textureIndices[3]; + }; + + + struct DMDHeader + { + int magic; + int version; + int flags; + }; + + struct DMDModelVertex + { + float xyz[3]; + }; + + struct FTexCoord + { + short s, t; + }; + + struct FGLCommandVertex + { + float s, t; + int index; + }; + + struct DMDInfo + { + int skinWidth; + int skinHeight; + int frameSize; + int numSkins; + int numVertices; + int numTexCoords; + int numFrames; + int numLODs; + int offsetSkins; + int offsetTexCoords; + int offsetFrames; + int offsetLODs; + int offsetEnd; + }; + + struct ModelFrame + { + char name[16]; + unsigned int vindex; + }; + + struct ModelFrameVertexData + { + DMDModelVertex *vertices; + DMDModelVertex *normals; + }; + + struct DMDLoDInfo + { + int numTriangles; + int numGlCommands; + int offsetTriangles; + int offsetGlCommands; + }; + + struct DMDLoD + { + FTriangle * triangles; + }; + + + int mLumpNum; + DMDHeader header; + DMDInfo info; + FTextureID * skins; + ModelFrame * frames; + bool allowTexComp; // Allow texture compression with this. + + // Temp data only needed for buffer construction + FTexCoord * texCoords; + ModelFrameVertexData *framevtx; + DMDLoDInfo lodInfo[MAX_LODS]; + DMDLoD lods[MAX_LODS]; + +public: + FDMDModel() + { + mLumpNum = -1; + frames = NULL; + skins = NULL; + for (int i = 0; i < MAX_LODS; i++) + { + lods[i].triangles = NULL; + } + info.numLODs = 0; + texCoords = NULL; + framevtx = NULL; + } + virtual ~FDMDModel(); + + virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) override; + virtual int FindFrame(const char* name, bool nodefault) override; + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) override; + virtual void LoadGeometry(); + virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) override; + + void UnloadGeometry(); + void BuildVertexBuffer(FModelRenderer *renderer); + +}; + +// This uses the same internal representation as DMD +class FMD2Model : public FDMDModel +{ +public: + FMD2Model() {} + virtual ~FMD2Model(); + + virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length); + virtual void LoadGeometry(); + +}; + + diff --git a/src/common/models/model_md3.h b/src/common/models/model_md3.h new file mode 100644 index 00000000000..045b1cc3b72 --- /dev/null +++ b/src/common/models/model_md3.h @@ -0,0 +1,75 @@ +#pragma once +#include "model.h" + +#define MD3_MAGIC 0x33504449 + +class FMD3Model : public FModel +{ + struct MD3Tag + { + // Currently I have no use for this + }; + + struct MD3TexCoord + { + float s,t; + }; + + struct MD3Vertex + { + float x,y,z; + float nx,ny,nz; + }; + + struct MD3Triangle + { + int VertIndex[3]; + }; + + struct MD3Surface + { + unsigned numVertices; + unsigned numTriangles; + unsigned numSkins; + + TArray Skins; + TArray Tris; + TArray Texcoords; + TArray Vertices; + + unsigned int vindex = UINT_MAX; // contains numframes arrays of vertices + unsigned int iindex = UINT_MAX; + + void UnloadGeometry() + { + Tris.Reset(); + Vertices.Reset(); + Texcoords.Reset(); + } + }; + + struct MD3Frame + { + // The bounding box information is of no use in the Doom engine + // That will still be done with the actor's size information. + char Name[16]; + float origin[3]; + }; + + int numTags; + int mLumpNum; + + TArray Frames; + TArray Surfaces; + +public: + FMD3Model() = default; + + virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) override; + virtual int FindFrame(const char* name, bool nodefault) override; + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) override; + void LoadGeometry(); + void BuildVertexBuffer(FModelRenderer *renderer); + virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) override; +}; + diff --git a/src/common/models/model_obj.h b/src/common/models/model_obj.h new file mode 100644 index 00000000000..4fc977c05f4 --- /dev/null +++ b/src/common/models/model_obj.h @@ -0,0 +1,106 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2018 Kevin Caccamo +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#ifndef __GL_MODELS_OBJ_H__ +#define __GL_MODELS_OBJ_H__ + +#include "model.h" +#include "sc_man.h" +#include "tarray.h" +#include "vectors.h" + +class FOBJModel : public FModel +{ +private: + const char *newSideSep = "$"; // OBJ side separator is /, which is parsed as a line comment by FScanner if two of them are next to each other. + bool hasMissingNormals; + bool hasSmoothGroups; + + enum class FaceElement + { + VertexIndex, + UVIndex, + VNormalIndex + }; + + struct OBJTriRef + { + unsigned int surf; + unsigned int tri; + OBJTriRef(): surf(0), tri(0) {} + OBJTriRef(unsigned int surf, unsigned int tri): surf(surf), tri(tri) {} + bool operator== (OBJTriRef other) { return surf == other.surf && tri == other.tri; } + }; + struct OBJFaceSide + { + int vertref; + int normref; + int uvref; + }; + struct OBJFace + { + unsigned int sideCount; + unsigned int smoothGroup; + OBJFaceSide sides[4]; + OBJFace(): sideCount(0), smoothGroup(0) {} + }; + struct OBJSurface // 1 surface per 'usemtl' + { + unsigned int numTris; // Number of triangulated faces + unsigned int numFaces; // Number of faces + unsigned int vbStart; // First index in vertex buffer + unsigned int faceStart; // Index of first face in faces array + OBJFace* tris; // Triangles + FTextureID skin; + OBJSurface(FTextureID skin): numTris(0), numFaces(0), vbStart(0), faceStart(0), tris(nullptr), skin(skin) {} + }; + + TArray verts; + TArray norms; + TArray uvs; + TArray faces; + TArray surfaces; + FScanner sc; + TArray* vertFaces; + + int ResolveIndex(int origIndex, FaceElement el); + template void ParseVector(TArray &array); + bool ParseFaceSide(const FString &side, OBJFace &face, int sidx); + void ConstructSurfaceTris(OBJSurface &surf); + void AddVertFaces(); + void TriangulateQuad(const OBJFace &quad, OBJFace *tris); + FVector3 RealignVector(FVector3 vecToRealign); + FVector2 FixUV(FVector2 vecToRealign); + FVector3 CalculateNormalFlat(unsigned int surfIdx, unsigned int triIdx); + FVector3 CalculateNormalFlat(OBJTriRef otr); + FVector3 CalculateNormalSmooth(unsigned int vidx, unsigned int smoothGroup); +public: + FOBJModel(): hasMissingNormals(false), hasSmoothGroups(false), vertFaces(nullptr) {} + ~FOBJModel(); + bool Load(const char* fn, int lumpnum, const char* buffer, int length) override; + int FindFrame(const char* name, bool nodefault) override; + void RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) override; + void BuildVertexBuffer(FModelRenderer* renderer) override; + void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override; +}; + +#endif diff --git a/src/common/models/model_ue1.h b/src/common/models/model_ue1.h new file mode 100644 index 00000000000..579002f8958 --- /dev/null +++ b/src/common/models/model_ue1.h @@ -0,0 +1,112 @@ +#pragma once + +#include +#include "model.h" +#include "vectors.h" + +class FUE1Model : public FModel +{ +public: + enum EPolyType + { + PT_Normal = 0, // normal renderstyle + PT_TwoSided = 1, // like normal, but don't cull backfaces + PT_Translucent = 2, // additive blending + PT_Masked = 3, // draw with alpha testing + PT_Modulated = 4, // overlay-like blending (rgb values below 128 darken, 128 is unchanged, and above 128 lighten) + // types mask + PT_Type = 7, + // flags + PT_WeaponTriangle = 0x08, // this poly is used for positioning a weapon attachment and should not be drawn + PT_Unlit = 0x10, // this poly is fullbright + PT_Curvy = 0x20, // this poly uses the facet normal + PT_EnvironmentMap = 0x40, // vertex UVs are remapped to their view-space X and Z normals, fake cubemap look + PT_NoSmooth = 0x80 // this poly forcibly uses nearest filtering + }; + + bool Load(const char * fn, int lumpnum, const char * buffer, int length) override; + int FindFrame(const char* name, bool nodefault) override; + void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) override; + void BuildVertexBuffer(FModelRenderer *renderer) override; + void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) override; + void LoadGeometry(); + void UnloadGeometry(); + FUE1Model() + { + mDataLump = -1; + mAnivLump = -1; + dhead = NULL; + dpolys = NULL; + ahead = NULL; + averts = NULL; + numVerts = 0; + numFrames = 0; + numPolys = 0; + numGroups = 0; + } + ~FUE1Model(); + +private: + int mDataLump, mAnivLump; + + // raw data structures + struct d3dhead + { + uint16_t numpolys, numverts; + uint16_t bogusrot, bogusframe; + uint32_t bogusnorm[3]; + uint32_t fixscale; + uint32_t unused[3]; + uint8_t padding[12]; + }; + struct d3dpoly + { + uint16_t vertices[3]; + uint8_t type, color; + uint8_t uv[3][2]; + uint8_t texnum, flags; + }; + struct a3dhead + { + uint16_t numframes, framesize; + }; + const d3dhead * dhead; + const d3dpoly * dpolys; + const a3dhead * ahead; + const uint32_t * averts; + struct dxvert + { + int16_t x, y, z, pad; + }; + const dxvert * dxverts; + + // converted data structures + struct UE1Vertex + { + FVector3 Pos, Normal; + TArray P; // polys that reference this vertex, used in normal computation to save time + int nP; // count of those polys + }; + struct UE1Poly + { + int V[3]; + FVector2 C[3]; + TArray Normals; + }; + struct UE1Group + { + TArray P; + int numPolys, texNum, type; + }; + + int numVerts; + int numFrames; + int numPolys; + int numGroups; + bool hasWeaponTriangle; + + TArray verts; + TArray polys; + TArray groups; + //TArray weapondata; // pseudo-bone generated from weapon triangle (not yet implemented) +}; diff --git a/src/common/models/modelrenderer.h b/src/common/models/modelrenderer.h new file mode 100644 index 00000000000..d2d774eab97 --- /dev/null +++ b/src/common/models/modelrenderer.h @@ -0,0 +1,29 @@ +#pragma once +#include "renderstyle.h" +#include "matrix.h" +#include "model.h" + +class FModelRenderer +{ +public: + virtual ~FModelRenderer() = default; + + virtual ModelRendererType GetType() const = 0; + + virtual void BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0; + virtual void EndDrawModel(FRenderStyle style, int smf_flags) = 0; + + virtual IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) = 0; + + virtual VSMatrix GetViewToWorldMatrix() = 0; + + virtual void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) = 0; + virtual void EndDrawHUDModel(FRenderStyle style, int smf_flags) = 0; + + virtual void SetInterpolation(double interpolation) = 0; + virtual void SetMaterial(FGameTexture *skin, bool clampNoFilter, FTranslationID translation) = 0; + virtual void DrawArrays(int start, int count) = 0; + virtual void DrawElements(int numIndices, size_t offset) = 0; + virtual int SetupFrame(FModel* model, unsigned int frame1, unsigned int frame2, unsigned int size, const TArray& bones, int boneStartIndex) { return -1; }; +}; + diff --git a/src/common/models/models_iqm.cpp b/src/common/models/models_iqm.cpp new file mode 100644 index 00000000000..891a19647e6 --- /dev/null +++ b/src/common/models/models_iqm.cpp @@ -0,0 +1,665 @@ + +#include "filesystem.h" +#include "cmdlib.h" +#include "model_iqm.h" +#include "texturemanager.h" +#include "modelrenderer.h" +#include "engineerrors.h" +#include "dobject.h" +#include "bonecomponents.h" + +IMPLEMENT_CLASS(DBoneComponents, false, false); + + +IQMModel::IQMModel() +{ +} + +IQMModel::~IQMModel() +{ +} + +bool IQMModel::Load(const char* path, int lumpnum, const char* buffer, int length) +{ + mLumpNum = lumpnum; + + try + { + IQMFileReader reader(buffer, length); + + char magic[16]; + reader.Read(magic, 16); + if (memcmp(magic, "INTERQUAKEMODEL\0", 16) != 0) + return false; + + uint32_t version = reader.ReadUInt32(); + if (version != 2) + return false; + + uint32_t filesize = reader.ReadUInt32(); + uint32_t flags = reader.ReadUInt32(); + uint32_t num_text = reader.ReadUInt32(); + uint32_t ofs_text = reader.ReadUInt32(); + uint32_t num_meshes = reader.ReadUInt32(); + uint32_t ofs_meshes = reader.ReadUInt32(); + uint32_t num_vertexarrays = reader.ReadUInt32(); + uint32_t num_vertices = reader.ReadUInt32(); + uint32_t ofs_vertexarrays = reader.ReadUInt32(); + uint32_t num_triangles = reader.ReadUInt32(); + uint32_t ofs_triangles = reader.ReadUInt32(); + uint32_t ofs_adjacency = reader.ReadUInt32(); + uint32_t num_joints = reader.ReadUInt32(); + uint32_t ofs_joints = reader.ReadUInt32(); + uint32_t num_poses = reader.ReadUInt32(); + uint32_t ofs_poses = reader.ReadUInt32(); + uint32_t num_anims = reader.ReadUInt32(); + uint32_t ofs_anims = reader.ReadUInt32(); + uint32_t num_frames = reader.ReadUInt32(); + uint32_t num_framechannels = reader.ReadUInt32(); + uint32_t ofs_frames = reader.ReadUInt32(); + uint32_t ofs_bounds = reader.ReadUInt32(); + uint32_t num_comment = reader.ReadUInt32(); + uint32_t ofs_comment = reader.ReadUInt32(); + uint32_t num_extensions = reader.ReadUInt32(); + uint32_t ofs_extensions = reader.ReadUInt32(); + + if (num_text == 0) + return false; + + TArray text(num_text, true); + reader.SeekTo(ofs_text); + reader.Read(text.Data(), text.Size()); + text[text.Size() - 1] = 0; + + Meshes.Resize(num_meshes); + Triangles.Resize(num_triangles); + Adjacency.Resize(num_triangles); + Joints.Resize(num_joints); + Poses.Resize(num_poses); + Anims.Resize(num_anims); + Bounds.Resize(num_frames); + VertexArrays.Resize(num_vertexarrays); + NumVertices = num_vertices; + + reader.SeekTo(ofs_meshes); + for (IQMMesh& mesh : Meshes) + { + mesh.Name = reader.ReadName(text); + mesh.Material = reader.ReadName(text); + mesh.FirstVertex = reader.ReadUInt32(); + mesh.NumVertices = reader.ReadUInt32(); + mesh.FirstTriangle = reader.ReadUInt32(); + mesh.NumTriangles = reader.ReadUInt32(); + mesh.Skin = LoadSkin(path, mesh.Material.GetChars()); + } + + reader.SeekTo(ofs_triangles); + for (IQMTriangle& triangle : Triangles) + { + triangle.Vertex[0] = reader.ReadUInt32(); + triangle.Vertex[1] = reader.ReadUInt32(); + triangle.Vertex[2] = reader.ReadUInt32(); + } + + reader.SeekTo(ofs_adjacency); + for (IQMAdjacency& adj : Adjacency) + { + adj.Triangle[0] = reader.ReadUInt32(); + adj.Triangle[1] = reader.ReadUInt32(); + adj.Triangle[2] = reader.ReadUInt32(); + } + + reader.SeekTo(ofs_joints); + for (IQMJoint& joint : Joints) + { + joint.Name = reader.ReadName(text); + joint.Parent = reader.ReadInt32(); + joint.Translate.X = reader.ReadFloat(); + joint.Translate.Y = reader.ReadFloat(); + joint.Translate.Z = reader.ReadFloat(); + joint.Quaternion.X = reader.ReadFloat(); + joint.Quaternion.Y = reader.ReadFloat(); + joint.Quaternion.Z = reader.ReadFloat(); + joint.Quaternion.W = reader.ReadFloat(); + joint.Quaternion.MakeUnit(); + joint.Scale.X = reader.ReadFloat(); + joint.Scale.Y = reader.ReadFloat(); + joint.Scale.Z = reader.ReadFloat(); + } + + reader.SeekTo(ofs_poses); + for (IQMPose& pose : Poses) + { + pose.Parent = reader.ReadInt32(); + pose.ChannelMask = reader.ReadUInt32(); + for (int i = 0; i < 10; i++) pose.ChannelOffset[i] = reader.ReadFloat(); + for (int i = 0; i < 10; i++) pose.ChannelScale[i] = reader.ReadFloat(); + } + + reader.SeekTo(ofs_anims); + for(unsigned i = 0; i < Anims.Size(); i++) + { + IQMAnim& anim = Anims[i]; + anim.Name = reader.ReadName(text); + NamedAnimations.Insert(anim.Name, i); + + anim.FirstFrame = reader.ReadUInt32(); + anim.NumFrames = reader.ReadUInt32(); + anim.Framerate = reader.ReadFloat(); + anim.Loop = !!(reader.ReadUInt32() & 1); + } + + baseframe.Resize(num_joints); + inversebaseframe.Resize(num_joints); + + for (uint32_t i = 0; i < num_joints; i++) + { + const IQMJoint& j = Joints[i]; + + VSMatrix m, invm; + m.loadIdentity(); + m.translate(j.Translate.X, j.Translate.Y, j.Translate.Z); + m.multQuaternion(j.Quaternion); + m.scale(j.Scale.X, j.Scale.Y, j.Scale.Z); + m.inverseMatrix(invm); + if (j.Parent >= 0) + { + baseframe[i] = baseframe[j.Parent]; + baseframe[i].multMatrix(m); + inversebaseframe[i] = invm; + inversebaseframe[i].multMatrix(inversebaseframe[j.Parent]); + } + else + { + baseframe[i] = m; + inversebaseframe[i] = invm; + } + } + + TRSData.Resize(num_frames * num_poses); + reader.SeekTo(ofs_frames); + for (uint32_t i = 0; i < num_frames; i++) + { + for (uint32_t j = 0; j < num_poses; j++) + { + const IQMPose& p = Poses[j]; + + FVector3 translate; + translate.X = p.ChannelOffset[0]; if (p.ChannelMask & 0x01) translate.X += reader.ReadUInt16() * p.ChannelScale[0]; + translate.Y = p.ChannelOffset[1]; if (p.ChannelMask & 0x02) translate.Y += reader.ReadUInt16() * p.ChannelScale[1]; + translate.Z = p.ChannelOffset[2]; if (p.ChannelMask & 0x04) translate.Z += reader.ReadUInt16() * p.ChannelScale[2]; + + FVector4 quaternion; + quaternion.X = p.ChannelOffset[3]; if (p.ChannelMask & 0x08) quaternion.X += reader.ReadUInt16() * p.ChannelScale[3]; + quaternion.Y = p.ChannelOffset[4]; if (p.ChannelMask & 0x10) quaternion.Y += reader.ReadUInt16() * p.ChannelScale[4]; + quaternion.Z = p.ChannelOffset[5]; if (p.ChannelMask & 0x20) quaternion.Z += reader.ReadUInt16() * p.ChannelScale[5]; + quaternion.W = p.ChannelOffset[6]; if (p.ChannelMask & 0x40) quaternion.W += reader.ReadUInt16() * p.ChannelScale[6]; + quaternion.MakeUnit(); + + FVector3 scale; + scale.X = p.ChannelOffset[7]; if (p.ChannelMask & 0x80) scale.X += reader.ReadUInt16() * p.ChannelScale[7]; + scale.Y = p.ChannelOffset[8]; if (p.ChannelMask & 0x100) scale.Y += reader.ReadUInt16() * p.ChannelScale[8]; + scale.Z = p.ChannelOffset[9]; if (p.ChannelMask & 0x200) scale.Z += reader.ReadUInt16() * p.ChannelScale[9]; + + TRSData[i * num_poses + j].translation = translate; + TRSData[i * num_poses + j].rotation = quaternion; + TRSData[i * num_poses + j].scaling = scale; + } + } + + //If a model doesn't have an animation loaded, it will crash. We don't want that! + if (num_frames <= 0) + { + num_frames = 1; + TRSData.Resize(num_joints); + + for (uint32_t j = 0; j < num_joints; j++) + { + FVector3 translate; + translate.X = Joints[j].Translate.X; + translate.Y = Joints[j].Translate.Y; + translate.Z = Joints[j].Translate.Z; + + FVector4 quaternion; + quaternion.X = Joints[j].Quaternion.X; + quaternion.Y = Joints[j].Quaternion.Y; + quaternion.Z = Joints[j].Quaternion.Z; + quaternion.W = Joints[j].Quaternion.W; + quaternion.MakeUnit(); + + FVector3 scale; + scale.X = Joints[j].Scale.X; + scale.Y = Joints[j].Scale.Y; + scale.Z = Joints[j].Scale.Z; + + TRSData[j].translation = translate; + TRSData[j].rotation = quaternion; + TRSData[j].scaling = scale; + } + } + + reader.SeekTo(ofs_bounds); + for (IQMBounds& bound : Bounds) + { + bound.BBMins[0] = reader.ReadFloat(); + bound.BBMins[1] = reader.ReadFloat(); + bound.BBMins[2] = reader.ReadFloat(); + bound.BBMaxs[0] = reader.ReadFloat(); + bound.BBMaxs[1] = reader.ReadFloat(); + bound.BBMaxs[2] = reader.ReadFloat(); + bound.XYRadius = reader.ReadFloat(); + bound.Radius = reader.ReadFloat(); + } + + reader.SeekTo(ofs_vertexarrays); + for (IQMVertexArray& vertexArray : VertexArrays) + { + vertexArray.Type = (IQMVertexArrayType)reader.ReadUInt32(); + vertexArray.Flags = reader.ReadUInt32(); + vertexArray.Format = (IQMVertexArrayFormat)reader.ReadUInt32(); + vertexArray.Size = reader.ReadUInt32(); + vertexArray.Offset = reader.ReadUInt32(); + } + + return true; + } + catch (IQMReadErrorException) + { + return false; + } +} + +void IQMModel::LoadGeometry() +{ + try + { + auto lumpdata = fileSystem.ReadFile(mLumpNum); + IQMFileReader reader(lumpdata.data(), (int)lumpdata.size()); + + Vertices.Resize(NumVertices); + for (IQMVertexArray& vertexArray : VertexArrays) + { + reader.SeekTo(vertexArray.Offset); + if (vertexArray.Type == IQM_POSITION) + { + LoadPosition(reader, vertexArray); + } + else if (vertexArray.Type == IQM_TEXCOORD) + { + LoadTexcoord(reader, vertexArray); + } + else if (vertexArray.Type == IQM_NORMAL) + { + LoadNormal(reader, vertexArray); + } + else if (vertexArray.Type == IQM_BLENDINDEXES) + { + LoadBlendIndexes(reader, vertexArray); + } + else if (vertexArray.Type == IQM_BLENDWEIGHTS) + { + LoadBlendWeights(reader, vertexArray); + } + } + } + catch (IQMReadErrorException) + { + } +} + +void IQMModel::LoadPosition(IQMFileReader& reader, const IQMVertexArray& vertexArray) +{ + float lu = 0.0f, lv = 0.0f, lindex = -1.0f; + if (vertexArray.Format == IQM_FLOAT && vertexArray.Size == 3) + { + for (FModelVertex& v : Vertices) + { + v.x = reader.ReadFloat(); + v.z = reader.ReadFloat(); + v.y = reader.ReadFloat(); + + v.lu = lu; + v.lv = lv; + v.lindex = lindex; + } + } + else + { + I_FatalError("Unsupported IQM_POSITION vertex format"); + } +} + +void IQMModel::LoadTexcoord(IQMFileReader& reader, const IQMVertexArray& vertexArray) +{ + if (vertexArray.Format == IQM_FLOAT && vertexArray.Size == 2) + { + for (FModelVertex& v : Vertices) + { + v.u = reader.ReadFloat(); + v.v = reader.ReadFloat(); + } + } + else + { + I_FatalError("Unsupported IQM_TEXCOORD vertex format"); + } +} + +void IQMModel::LoadNormal(IQMFileReader& reader, const IQMVertexArray& vertexArray) +{ + if (vertexArray.Format == IQM_FLOAT && vertexArray.Size == 3) + { + for (FModelVertex& v : Vertices) + { + float x = reader.ReadFloat(); + float y = reader.ReadFloat(); + float z = reader.ReadFloat(); + + v.SetNormal(x, z, y); + } + } + else + { + I_FatalError("Unsupported IQM_NORMAL vertex format"); + } +} + +void IQMModel::LoadBlendIndexes(IQMFileReader& reader, const IQMVertexArray& vertexArray) +{ + if (vertexArray.Format == IQM_UBYTE && vertexArray.Size == 4) + { + for (FModelVertex& v : Vertices) + { + int x = reader.ReadUByte(); + int y = reader.ReadUByte(); + int z = reader.ReadUByte(); + int w = reader.ReadUByte(); + v.SetBoneSelector(x, y, z, w); + } + } + else if (vertexArray.Format == IQM_INT && vertexArray.Size == 4) + { + for (FModelVertex& v : Vertices) + { + int x = reader.ReadInt32(); + int y = reader.ReadInt32(); + int z = reader.ReadInt32(); + int w = reader.ReadInt32(); + v.SetBoneSelector(x, y, z, w); + } + } + else + { + I_FatalError("Unsupported IQM_BLENDINDEXES vertex format"); + } +} + +void IQMModel::LoadBlendWeights(IQMFileReader& reader, const IQMVertexArray& vertexArray) +{ + if (vertexArray.Format == IQM_UBYTE && vertexArray.Size == 4) + { + for (FModelVertex& v : Vertices) + { + int x = reader.ReadUByte(); + int y = reader.ReadUByte(); + int z = reader.ReadUByte(); + int w = reader.ReadUByte(); + v.SetBoneWeight(x, y, z, w); + } + } + else if (vertexArray.Format == IQM_FLOAT && vertexArray.Size == 4) + { + for (FModelVertex& v : Vertices) + { + uint8_t x = (int)clamp(reader.ReadFloat() * 255.0f, 0.0f, 255.0f); + uint8_t y = (int)clamp(reader.ReadFloat() * 255.0f, 0.0f, 255.0f); + uint8_t z = (int)clamp(reader.ReadFloat() * 255.0f, 0.0f, 255.0f); + uint8_t w = (int)clamp(reader.ReadFloat() * 255.0f, 0.0f, 255.0f); + v.SetBoneWeight(x, y, z, w); + } + } + else + { + I_FatalError("Unsupported IQM_BLENDWEIGHTS vertex format"); + } +} + +void IQMModel::UnloadGeometry() +{ + Vertices.Reset(); +} + +int IQMModel::FindFrame(const char* name, bool nodefault) +{ + // [MK] allow looking up frames by animation name plus offset (using a colon as separator) + const char* colon = strrchr(name,':'); + size_t nlen = (colon==nullptr)?strlen(name):(colon-name); + for (unsigned i = 0; i < Anims.Size(); i++) + { + if (!strnicmp(name, Anims[i].Name.GetChars(), nlen)) + { + // if no offset is given, return the first frame + if (colon == nullptr) return Anims[i].FirstFrame; + unsigned offset = atoi(colon+1); + if (offset >= Anims[i].NumFrames) return FErr_NotFound; + return Anims[i].FirstFrame+offset; + } + } + return FErr_NotFound; +} + +int IQMModel::FindFirstFrame(FName name) +{ + int * nam = NamedAnimations.CheckKey(name); + if(nam) return Anims[*nam].FirstFrame; + return FErr_NotFound; +} + +int IQMModel::FindLastFrame(FName name) +{ + int * nam = NamedAnimations.CheckKey(name); + if(nam) return Anims[*nam].FirstFrame + Anims[*nam].NumFrames; + return FErr_NotFound; +} + +double IQMModel::FindFramerate(FName name) +{ + int * nam = NamedAnimations.CheckKey(name); + if(nam) return Anims[*nam].Framerate; + return FErr_NotFound; +} + +void IQMModel::RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame1, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) +{ + renderer->SetupFrame(this, 0, 0, NumVertices, boneData, boneStartPosition); + + FGameTexture* lastSkin = nullptr; + for (unsigned i = 0; i < Meshes.Size(); i++) + { + FGameTexture* meshSkin = skin; + + if (!meshSkin) + { + if (surfaceskinids && surfaceskinids[i].isValid()) + { + meshSkin = TexMan.GetGameTexture(surfaceskinids[i], true); + } + else if (Meshes[i].Skin.isValid()) + { + meshSkin = TexMan.GetGameTexture(Meshes[i].Skin, true); + } + else + { + continue; + } + } + + if (meshSkin->isValid()) + { + if (meshSkin != lastSkin) + { + renderer->SetMaterial(meshSkin, false, translation); + lastSkin = meshSkin; + } + renderer->DrawElements(Meshes[i].NumTriangles * 3, Meshes[i].FirstTriangle * 3 * sizeof(unsigned int)); + } + } +} + +void IQMModel::BuildVertexBuffer(FModelRenderer* renderer) +{ + if (!GetVertexBuffer(renderer->GetType())) + { + LoadGeometry(); + + auto vbuf = renderer->CreateVertexBuffer(true, true); + SetVertexBuffer(renderer->GetType(), vbuf); + + FModelVertex* vertptr = vbuf->LockVertexBuffer(Vertices.Size()); + memcpy(vertptr, Vertices.Data(), Vertices.Size() * sizeof(FModelVertex)); + vbuf->UnlockVertexBuffer(); + + unsigned int* indxptr = vbuf->LockIndexBuffer(Triangles.Size() * 3); + memcpy(indxptr, Triangles.Data(), Triangles.Size() * sizeof(unsigned int) * 3); + vbuf->UnlockIndexBuffer(); + + UnloadGeometry(); + } +} + +void IQMModel::AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) +{ + for (unsigned i = 0; i < Meshes.Size(); i++) + { + if (surfaceskinids && surfaceskinids[i].isValid()) + hitlist[surfaceskinids[i].GetIndex()] |= FTextureManager::HIT_Flat; + } +} + +const TArray* IQMModel::AttachAnimationData() +{ + return &TRSData; +} + +static TRS InterpolateBone(const TRS &from, const TRS &to, float t, float invt) +{ + TRS bone; + + bone.translation = from.translation * invt + to.translation * t; + bone.rotation = from.rotation * invt; + + if ((bone.rotation | to.rotation * t) < 0) + { + bone.rotation.X *= -1; bone.rotation.Y *= -1; bone.rotation.Z *= -1; bone.rotation.W *= -1; + } + + bone.rotation += to.rotation * t; + bone.rotation.MakeUnit(); + bone.scaling = from.scaling * invt + to.scaling * t; + + return bone; +} + +const TArray IQMModel::CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* boneComponentData, int index) +{ + const TArray& animationFrames = animationData ? *animationData : TRSData; + if (Joints.Size() > 0) + { + int numbones = Joints.SSize(); + + if (boneComponentData->trscomponents[index].SSize() != numbones) + boneComponentData->trscomponents[index].Resize(numbones); + if (boneComponentData->trsmatrix[index].SSize() != numbones) + boneComponentData->trsmatrix[index].Resize(numbones); + + frame1 = clamp(frame1, 0, (animationFrames.SSize() - 1) / numbones); + frame2 = clamp(frame2, 0, (animationFrames.SSize() - 1) / numbones); + + int offset1 = frame1 * numbones; + int offset2 = frame2 * numbones; + + int offset1_1 = frame1_prev * numbones; + int offset2_1 = frame2_prev * numbones; + + float invt = 1.0f - inter; + float invt1 = 1.0f - inter1_prev; + float invt2 = 1.0f - inter2_prev; + + float swapYZ[16] = { 0.0f }; + swapYZ[0 + 0 * 4] = 1.0f; + swapYZ[1 + 2 * 4] = 1.0f; + swapYZ[2 + 1 * 4] = 1.0f; + swapYZ[3 + 3 * 4] = 1.0f; + + TArray bones(numbones, true); + TArray modifiedBone(numbones, true); + for (int i = 0; i < numbones; i++) + { + TRS prev; + + if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0)) + { + prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1); + } + + TRS next; + + if(frame2 >= 0 && (frame2_prev >= 0 || inter2_prev < 0)) + { + next = inter2_prev <= 0 ? animationFrames[offset2 + i] : InterpolateBone(animationFrames[offset2_1 + i], animationFrames[offset2 + i], inter2_prev, invt2); + } + + TRS bone; + + if(frame1 >= 0 || inter < 0) + { + bone = inter < 0 ? animationFrames[offset1 + i] : InterpolateBone(prev, next , inter, invt); + } + + if (Joints[i].Parent >= 0 && modifiedBone[Joints[i].Parent]) + { + boneComponentData->trscomponents[index][i] = bone; + modifiedBone[i] = true; + } + else if (boneComponentData->trscomponents[index][i].Equals(bone)) + { + bones[i] = boneComponentData->trsmatrix[index][i]; + modifiedBone[i] = false; + continue; + } + else + { + boneComponentData->trscomponents[index][i] = bone; + modifiedBone[i] = true; + } + + VSMatrix m; + m.loadIdentity(); + m.translate(bone.translation.X, bone.translation.Y, bone.translation.Z); + m.multQuaternion(bone.rotation); + m.scale(bone.scaling.X, bone.scaling.Y, bone.scaling.Z); + + VSMatrix& result = bones[i]; + if (Joints[i].Parent >= 0) + { + result = bones[Joints[i].Parent]; + result.multMatrix(swapYZ); + result.multMatrix(baseframe[Joints[i].Parent]); + result.multMatrix(m); + result.multMatrix(inversebaseframe[i]); + } + else + { + result.loadMatrix(swapYZ); + result.multMatrix(m); + result.multMatrix(inversebaseframe[i]); + } + result.multMatrix(swapYZ); + } + + boneComponentData->trsmatrix[index] = bones; + + return bones; + } + return {}; +} diff --git a/src/r_data/models/models_md2.cpp b/src/common/models/models_md2.cpp similarity index 90% rename from src/r_data/models/models_md2.cpp rename to src/common/models/models_md2.cpp index d203bf15a40..280c4d265f1 100644 --- a/src/r_data/models/models_md2.cpp +++ b/src/common/models/models_md2.cpp @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -26,13 +26,20 @@ ** **/ -#include "w_wad.h" -#include "r_data/models/models.h" +#include "filesystem.h" +#include "model_md2.h" +#include "texturemanager.h" +#include "modelrenderer.h" +#include "printf.h" +#include "m_swap.h" #ifdef _MSC_VER #pragma warning(disable:4244) // warning C4244: conversion from 'double' to 'float', possible loss of data #endif +enum { VX, VZ, VY }; +#define NUMVERTEXNORMALS 162 + static float avertexnormals[NUMVERTEXNORMALS][3] = { #include "tab_anorms.h" }; @@ -170,8 +177,8 @@ bool FDMDModel::Load(const char * path, int lumpnum, const char * buffer, int le void FDMDModel::LoadGeometry() { static int axis[3] = { VX, VY, VZ }; - FMemLump lumpdata = Wads.ReadLump(mLumpNum); - const char *buffer = (const char *)lumpdata.GetMem(); + auto lumpdata = fileSystem.ReadFile(mLumpNum); + auto buffer = lumpdata.string(); texCoords = new FTexCoord[info.numTexCoords]; memcpy(texCoords, buffer + info.offsetTexCoords, info.numTexCoords * sizeof(FTexCoord)); @@ -211,10 +218,10 @@ void FDMDModel::LoadGeometry() memcpy(lods[i].triangles, buffer + lodInfo[i].offsetTriangles, lodInfo[i].numTriangles * sizeof(FTriangle)); for (int j = 0; j < lodInfo[i].numTriangles; j++) { - for (int k = 0; k < 3; k++) + for (int kk = 0; kk < 3; kk++) { - lods[i].triangles[j].textureIndices[k] = LittleShort(lods[i].triangles[j].textureIndices[k]); - lods[i].triangles[j].vertexIndices[k] = LittleShort(lods[i].triangles[j].vertexIndices[k]); + lods[i].triangles[j].textureIndices[kk] = LittleShort(lods[i].triangles[j].textureIndices[kk]); + lods[i].triangles[j].vertexIndices[kk] = LittleShort(lods[i].triangles[j].vertexIndices[kk]); } } } @@ -279,7 +286,7 @@ FDMDModel::~FDMDModel() void FDMDModel::BuildVertexBuffer(FModelRenderer *renderer) { - if (!GetVertexBuffer(renderer)) + if (!GetVertexBuffer(renderer->GetType())) { LoadGeometry(); @@ -287,7 +294,7 @@ void FDMDModel::BuildVertexBuffer(FModelRenderer *renderer) unsigned int vindex = 0; auto vbuf = renderer->CreateVertexBuffer(false, info.numFrames == 1); - SetVertexBuffer(renderer, vbuf); + SetVertexBuffer(renderer->GetType(), vbuf); FModelVertex *vertptr = vbuf->LockVertexBuffer(VertexBufferSize); @@ -300,7 +307,7 @@ void FDMDModel::BuildVertexBuffer(FModelRenderer *renderer) FTriangle *tri = lods[0].triangles; - for (int i = 0; i < lodInfo[0].numTriangles; i++) + for (int ii = 0; ii < lodInfo[0].numTriangles; ii++) { for (int j = 0; j < 3; j++) { @@ -326,7 +333,7 @@ void FDMDModel::BuildVertexBuffer(FModelRenderer *renderer) // //=========================================================================== -void FDMDModel::AddSkins(uint8_t *hitlist) +void FDMDModel::AddSkins(uint8_t *hitlist, const FTextureID*) { for (int i = 0; i < info.numSkins; i++) { @@ -342,13 +349,13 @@ void FDMDModel::AddSkins(uint8_t *hitlist) // FDMDModel::FindFrame // //=========================================================================== -int FDMDModel::FindFrame(const char * name) +int FDMDModel::FindFrame(const char* name, bool nodefault) { for (int i=0;i& boneData, int boneStartPosition) { if (frameno >= info.numFrames || frameno2 >= info.numFrames) return; if (!skin) { if (info.numSkins == 0 || !skins[0].isValid()) return; - skin = TexMan.GetTexture(skins[0], true); + skin = TexMan.GetGameTexture(skins[0], true); if (!skin) return; } renderer->SetInterpolation(inter); renderer->SetMaterial(skin, false, translation); - GetVertexBuffer(renderer)->SetupFrame(renderer, frames[frameno].vindex, frames[frameno2].vindex, lodInfo[0].numTriangles * 3); + renderer->SetupFrame(this, frames[frameno].vindex, frames[frameno2].vindex, lodInfo[0].numTriangles * 3, {}, -1); renderer->DrawArrays(0, lodInfo[0].numTriangles * 3); renderer->SetInterpolation(0.f); } - - //=========================================================================== // // Internal data structures of MD2 files - only used during loading @@ -496,8 +501,8 @@ void FMD2Model::LoadGeometry() { static int axis[3] = { VX, VY, VZ }; uint8_t *md2_frames; - FMemLump lumpdata = Wads.ReadLump(mLumpNum); - const char *buffer = (const char *)lumpdata.GetMem(); + auto lumpdata = fileSystem.ReadFile(mLumpNum); + auto buffer = lumpdata.string(); texCoords = new FTexCoord[info.numTexCoords]; memcpy(texCoords, (uint8_t*)buffer + info.offsetTexCoords, info.numTexCoords * sizeof(FTexCoord)); @@ -530,15 +535,15 @@ void FMD2Model::LoadGeometry() } lods[0].triangles = new FTriangle[lodInfo[0].numTriangles]; - + int cnt = lodInfo[0].numTriangles; memcpy(lods[0].triangles, buffer + lodInfo[0].offsetTriangles, sizeof(FTriangle) * cnt); for (int j = 0; j < cnt; j++) { - for (int k = 0; k < 3; k++) + for (int kk = 0; kk < 3; kk++) { - lods[0].triangles[j].textureIndices[k] = LittleShort(lods[0].triangles[j].textureIndices[k]); - lods[0].triangles[j].vertexIndices[k] = LittleShort(lods[0].triangles[j].vertexIndices[k]); + lods[0].triangles[j].textureIndices[kk] = LittleShort(lods[0].triangles[j].textureIndices[kk]); + lods[0].triangles[j].vertexIndices[kk] = LittleShort(lods[0].triangles[j].vertexIndices[kk]); } } } @@ -546,4 +551,3 @@ void FMD2Model::LoadGeometry() FMD2Model::~FMD2Model() { } - diff --git a/src/r_data/models/models_md3.cpp b/src/common/models/models_md3.cpp similarity index 79% rename from src/r_data/models/models_md3.cpp rename to src/common/models/models_md3.cpp index 49efceb4f33..327cbff88ac 100644 --- a/src/r_data/models/models_md3.cpp +++ b/src/common/models/models_md3.cpp @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -20,9 +20,12 @@ //-------------------------------------------------------------------------- // -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" -#include "r_data/models/models.h" +#include "model_md3.h" +#include "texturemanager.h" +#include "modelrenderer.h" +#include "m_swap.h" #define MAX_QPATH 64 @@ -131,7 +134,8 @@ bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int le auto numFrames = LittleLong(hdr->Num_Frames); auto numSurfaces = LittleLong(hdr->Num_Surfaces); - + hasSurfaces = numSurfaces > 1; + numTags = LittleLong(hdr->Num_Tags); md3_frame_t * frm = (md3_frame_t*)(buffer + LittleLong(hdr->Ofs_Frames)); @@ -139,7 +143,7 @@ bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int le Frames.Resize(numFrames); for (unsigned i = 0; i < numFrames; i++) { - strncpy(Frames[i].Name, frm[i].Name, 16); + strncpy(Frames[i].Name, frm[i].Name, 15); for (int j = 0; j < 3; j++) Frames[i].origin[j] = frm[i].localorigin[j]; } @@ -162,15 +166,15 @@ bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int le md3_shader_t * shader = (md3_shader_t*)(((char*)ss) + LittleLong(ss->Ofs_Shaders)); s->Skins.Resize(s->numSkins); - for (unsigned i = 0; i < s->numSkins; i++) + for (unsigned ii = 0; ii < s->numSkins; ii++) { // [BB] According to the MD3 spec, Name is supposed to include the full path. // ... and since some tools seem to output backslashes, these need to be replaced with forward slashes to work. - FixPathSeperator(shader[i].Name); - s->Skins[i] = LoadSkin("", shader[i].Name); + FixPathSeperator(shader[ii].Name); + s->Skins[ii] = LoadSkin("", shader[ii].Name); // [BB] Fall back and check if Name is relative. - if (!s->Skins[i].isValid()) - s->Skins[i] = LoadSkin(path, shader[i].Name); + if (!s->Skins[ii].isValid()) + s->Skins[ii] = LoadSkin(path, shader[ii].Name); } } mLumpNum = lumpnum; @@ -185,8 +189,8 @@ bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int le void FMD3Model::LoadGeometry() { - FMemLump lumpdata = Wads.ReadLump(mLumpNum); - const char *buffer = (const char *)lumpdata.GetMem(); + auto lumpdata = fileSystem.ReadFile(mLumpNum); + auto buffer = lumpdata.string(); md3_header_t * hdr = (md3_header_t *)buffer; md3_surface_t * surf = (md3_surface_t*)(buffer + LittleLong(hdr->Ofs_Surfaces)); @@ -201,31 +205,31 @@ void FMD3Model::LoadGeometry() md3_triangle_t * tris = (md3_triangle_t*)(((char*)ss) + LittleLong(ss->Ofs_Triangles)); s->Tris.Resize(s->numTriangles); - for (unsigned i = 0; i < s->numTriangles; i++) for (int j = 0; j < 3; j++) + for (unsigned ii = 0; ii < s->numTriangles; ii++) for (int j = 0; j < 3; j++) { - s->Tris[i].VertIndex[j] = LittleLong(tris[i].vt_index[j]); + s->Tris[ii].VertIndex[j] = LittleLong(tris[ii].vt_index[j]); } // Load texture coordinates md3_texcoord_t * tc = (md3_texcoord_t*)(((char*)ss) + LittleLong(ss->Ofs_Texcoord)); s->Texcoords.Resize(s->numVertices); - for (unsigned i = 0; i < s->numVertices; i++) + for (unsigned ii = 0; ii < s->numVertices; ii++) { - s->Texcoords[i].s = tc[i].s; - s->Texcoords[i].t = tc[i].t; + s->Texcoords[ii].s = tc[ii].s; + s->Texcoords[ii].t = tc[ii].t; } // Load vertices and texture coordinates md3_vertex_t * vt = (md3_vertex_t*)(((char*)ss) + LittleLong(ss->Ofs_XYZNormal)); s->Vertices.Resize(s->numVertices * Frames.Size()); - for (unsigned i = 0; i < s->numVertices * Frames.Size(); i++) + for (unsigned ii = 0; ii < s->numVertices * Frames.Size(); ii++) { - s->Vertices[i].x = LittleShort(vt[i].x) / 64.f; - s->Vertices[i].y = LittleShort(vt[i].y) / 64.f; - s->Vertices[i].z = LittleShort(vt[i].z) / 64.f; - UnpackVector(LittleShort(vt[i].n), s->Vertices[i].nx, s->Vertices[i].ny, s->Vertices[i].nz); + s->Vertices[ii].x = LittleShort(vt[ii].x) / 64.f; + s->Vertices[ii].y = LittleShort(vt[ii].y) / 64.f; + s->Vertices[ii].z = LittleShort(vt[ii].z) / 64.f; + UnpackVector(LittleShort(vt[ii].n), s->Vertices[ii].nx, s->Vertices[ii].ny, s->Vertices[ii].nz); } } } @@ -238,7 +242,7 @@ void FMD3Model::LoadGeometry() void FMD3Model::BuildVertexBuffer(FModelRenderer *renderer) { - if (!GetVertexBuffer(renderer)) + if (!GetVertexBuffer(renderer->GetType())) { LoadGeometry(); @@ -253,7 +257,7 @@ void FMD3Model::BuildVertexBuffer(FModelRenderer *renderer) } auto vbuf = renderer->CreateVertexBuffer(true, Frames.Size() == 1); - SetVertexBuffer(renderer, vbuf); + SetVertexBuffer(renderer->GetType(), vbuf); FModelVertex *vertptr = vbuf->LockVertexBuffer(vbufsize); unsigned int *indxptr = vbuf->LockIndexBuffer(ibufsize); @@ -300,13 +304,13 @@ void FMD3Model::BuildVertexBuffer(FModelRenderer *renderer) // //=========================================================================== -void FMD3Model::AddSkins(uint8_t *hitlist) +void FMD3Model::AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) { for (unsigned i = 0; i < Surfaces.Size(); i++) { - if (curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) + if (surfaceskinids && surfaceskinids[i].isValid()) { - hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].GetIndex()] |= FTextureManager::HIT_Flat; + hitlist[surfaceskinids[i].GetIndex()] |= FTextureManager::HIT_Flat; } MD3Surface * surf = &Surfaces[i]; @@ -326,13 +330,13 @@ void FMD3Model::AddSkins(uint8_t *hitlist) // //=========================================================================== -int FMD3Model::FindFrame(const char * name) +int FMD3Model::FindFrame(const char* name, bool nodefault) { for (unsigned i = 0; i < Frames.Size(); i++) { if (!stricmp(name, Frames[i].Name)) return i; } - return -1; + return FErr_NotFound; } //=========================================================================== @@ -341,7 +345,7 @@ int FMD3Model::FindFrame(const char * name) // //=========================================================================== -void FMD3Model::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frameno, int frameno2, double inter, int translation) +void FMD3Model::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frameno, int frameno2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) { if ((unsigned)frameno >= Frames.Size() || (unsigned)frameno2 >= Frames.Size()) return; @@ -352,16 +356,16 @@ void FMD3Model::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame // [BB] In case no skin is specified via MODELDEF, check if the MD3 has a skin for the current surface. // Note: Each surface may have a different skin. - FTexture *surfaceSkin = skin; + FGameTexture *surfaceSkin = skin; if (!surfaceSkin) { - if (curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) + if (surfaceskinids && surfaceskinids[i].isValid()) { - surfaceSkin = TexMan.GetTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i], true); + surfaceSkin = TexMan.GetGameTexture(surfaceskinids[i], true); } else if (surf->numSkins > 0 && surf->Skins[0].isValid()) { - surfaceSkin = TexMan.GetTexture(surf->Skins[0], true); + surfaceSkin = TexMan.GetGameTexture(surf->Skins[0], true); } if (!surfaceSkin) @@ -371,7 +375,7 @@ void FMD3Model::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame } renderer->SetMaterial(surfaceSkin, false, translation); - GetVertexBuffer(renderer)->SetupFrame(renderer, surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices, surf->numVertices); + renderer->SetupFrame(this, surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices, surf->numVertices, {}, -1); renderer->DrawElements(surf->numTriangles * 3, surf->iindex * sizeof(unsigned int)); } renderer->SetInterpolation(0.f); diff --git a/src/r_data/models/models_obj.cpp b/src/common/models/models_obj.cpp similarity index 89% rename from src/r_data/models/models_obj.cpp rename to src/common/models/models_obj.cpp index 89d2e60cbc0..43e89b1d218 100644 --- a/src/r_data/models/models_obj.cpp +++ b/src/common/models/models_obj.cpp @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -19,8 +19,12 @@ // //-------------------------------------------------------------------------- -#include "w_wad.h" -#include "r_data/models/models_obj.h" +#include "filesystem.h" +#include "model_obj.h" +#include "texturemanager.h" +#include "modelrenderer.h" +#include "printf.h" +#include "textureid.h" /** * Load an OBJ model @@ -33,15 +37,15 @@ */ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length) { - FString objName = Wads.GetLumpFullPath(lumpnum); + auto objName = fileSystem.GetFileFullPath(lumpnum); FString objBuf(buffer, length); // Do some replacements before we parse the OBJ string { // Ensure usemtl statements remain intact TArray mtlUsages; - TArray mtlUsageIdxs; - long bpos = 0, nlpos = 0, slashpos = 0; + TArray mtlUsageIdxs; + ptrdiff_t bpos = 0, nlpos = 0, slashpos = 0; while (1) { bpos = objBuf.IndexOf("\nusemtl", bpos); @@ -54,7 +58,7 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length } if (nlpos == -1) { - nlpos = (long)objBuf.Len(); + nlpos = objBuf.Len(); } FString lineStr(objBuf.GetChars() + bpos, nlpos - bpos); mtlUsages.Push(lineStr); @@ -72,7 +76,7 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length nlpos = objBuf.IndexOf('\n', bpos); if (nlpos == -1) { - nlpos = (long)objBuf.Len(); + nlpos = objBuf.Len(); } memcpy(wObjBuf + bpos, mtlUsages[i].GetChars(), nlpos - bpos); } @@ -97,7 +101,7 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length wObjBuf = nullptr; objBuf.UnlockBuffer(); } - sc.OpenString(objName, objBuf); + sc.OpenString(objName.c_str(), objBuf); FTextureID curMtl = FNullTextureID(); OBJSurface *curSurface = nullptr; @@ -218,6 +222,8 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length curSurface->faceStart = aggSurfFaceCount; surfaces.Push(*curSurface); delete curSurface; + hasSurfaces = surfaces.Size() > 1; + if (uvs.Size() == 0) { // Needed so that OBJs without UVs can work @@ -236,13 +242,12 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length */ template void FOBJModel::ParseVector(TArray &array) { - float coord[L]; - for (size_t axis = 0; axis < L; axis++) + T vec; + for (unsigned axis = 0; axis < L; axis++) { sc.MustGetFloat(); - coord[axis] = (float)sc.Float; + vec[axis] = (float)sc.Float; } - T vec(coord); array.Push(vec); } @@ -354,7 +359,7 @@ int FOBJModel::ResolveIndex(int origIndex, FaceElement el) */ void FOBJModel::BuildVertexBuffer(FModelRenderer *renderer) { - if (GetVertexBuffer(renderer)) + if (GetVertexBuffer(renderer->GetType())) { return; } @@ -374,7 +379,7 @@ void FOBJModel::BuildVertexBuffer(FModelRenderer *renderer) } auto vbuf = renderer->CreateVertexBuffer(false,true); - SetVertexBuffer(renderer, vbuf); + SetVertexBuffer(renderer->GetType(), vbuf); FModelVertex *vertptr = vbuf->LockVertexBuffer(vbufsize); @@ -539,7 +544,7 @@ inline FVector3 FOBJModel::RealignVector(FVector3 vecToRealign) */ inline FVector2 FOBJModel::FixUV(FVector2 vecToRealign) { - vecToRealign.Y *= -1; + vecToRealign.Y = 1-vecToRealign.Y; return vecToRealign; } @@ -610,9 +615,9 @@ FVector3 FOBJModel::CalculateNormalSmooth(unsigned int vidx, unsigned int smooth * @param name The name of the frame * @return The index of the frame */ -int FOBJModel::FindFrame(const char* name) +int FOBJModel::FindFrame(const char* name, bool nodefault) { - return 0; // OBJs are not animated. + return nodefault ? FErr_Singleframe : 0; // OBJs are not animated. } /** @@ -620,27 +625,30 @@ int FOBJModel::FindFrame(const char* name) * * @param renderer The model renderer * @param skin The loaded skin for the surface - * @param frameno Unused - * @param frameno2 Unused - * @param inter Unused + * @param frameno The first frame to interpolate between. Only prevents the model from rendering if it is < 0, since OBJ models are static. + * @param frameno2 The second frame to interpolate between. + * @param inter The amount to interpolate the two frames. * @param translation The translation for the skin */ -void FOBJModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frameno, int frameno2, double inter, int translation) +void FOBJModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frameno, int frameno2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) { + // Prevent the model from rendering if the frame number is < 0 + if (frameno < 0 || frameno2 < 0) return; + for (unsigned int i = 0; i < surfaces.Size(); i++) { OBJSurface *surf = &surfaces[i]; - FTexture *userSkin = skin; + FGameTexture *userSkin = skin; if (!userSkin) { - if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) + if (surfaceskinids && surfaceskinids[i].isValid()) { - userSkin = TexMan.GetTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i], true); + userSkin = TexMan.GetGameTexture(surfaceskinids[i], true); } else if (surf->skin.isValid()) { - userSkin = TexMan.GetTexture(surf->skin, true); + userSkin = TexMan.GetGameTexture(surf->skin, true); } } @@ -651,7 +659,7 @@ void FOBJModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame } renderer->SetMaterial(userSkin, false, translation); - GetVertexBuffer(renderer)->SetupFrame(renderer, surf->vbStart, surf->vbStart, surf->numTris * 3); + renderer->SetupFrame(this, surf->vbStart, surf->vbStart, surf->numTris * 3, {}, -1); renderer->DrawArrays(0, surf->numTris * 3); } } @@ -661,17 +669,17 @@ void FOBJModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame * * @param hitlist The list of textures */ -void FOBJModel::AddSkins(uint8_t* hitlist) +void FOBJModel::AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) { for (size_t i = 0; i < surfaces.Size(); i++) { - if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) + if (surfaceskinids && i < MD3_MAX_SURFACES && surfaceskinids[i].isValid()) { // Precache skins manually reassigned by the user. // On OBJs with lots of skins, such as Doom map OBJs exported from GZDB, // there may be too many skins for the user to manually change, unless // the limit is bumped or surfaceskinIDs is changed to a TArray. - hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].GetIndex()] |= FTextureManager::HIT_Flat; + hitlist[surfaceskinids[i].GetIndex()] |= FTextureManager::HIT_Flat; return; // No need to precache skin that was replaced } diff --git a/src/common/models/models_ue1.cpp b/src/common/models/models_ue1.cpp new file mode 100644 index 00000000000..81065926179 --- /dev/null +++ b/src/common/models/models_ue1.cpp @@ -0,0 +1,326 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright (c) 2018-2022 Marisa Kirisame, UnSX Team +// +// 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. +// +//-------------------------------------------------------------------------- +// + +#include "filesystem.h" +#include "cmdlib.h" +#include "model_ue1.h" +#include "texturemanager.h" +#include "modelrenderer.h" + +float unpackuvert( uint32_t n, int c ) +{ + switch( c ) + { + case 0: + return ((int16_t)((n&0x7ff)<<5))/128.f; + case 1: + return ((int16_t)(((n>>11)&0x7ff)<<5))/128.f; + case 2: + return ((int16_t)(((n>>22)&0x3ff)<<6))/128.f; + default: + return 0.f; + } +} + +bool FUE1Model::Load( const char *filename, int lumpnum, const char *buffer, int length ) +{ + int lumpnum2; + hasSurfaces = true; + FString realfilename = fileSystem.GetFileFullName(lumpnum); + if ( (size_t)realfilename.IndexOf("_d.3d") == realfilename.Len()-5 ) + { + realfilename.Substitute("_d.3d","_a.3d"); + lumpnum2 = fileSystem.CheckNumForFullName(realfilename.GetChars()); + mDataLump = lumpnum; + mAnivLump = lumpnum2; + } + else + { + realfilename.Substitute("_a.3d","_d.3d"); + lumpnum2 = fileSystem.CheckNumForFullName(realfilename.GetChars()); + mAnivLump = lumpnum; + mDataLump = lumpnum2; + } + return true; +} + +void FUE1Model::LoadGeometry() +{ + const char *buffer, *buffer2; + auto lump = fileSystem.ReadFile(mDataLump); + buffer = lump.string(); + auto lump2 = fileSystem.ReadFile(mAnivLump); + buffer2 = lump2.string(); + // map structures + dhead = (const d3dhead*)(buffer); + dpolys = (const d3dpoly*)(buffer+sizeof(d3dhead)); + ahead = (const a3dhead*)(buffer2); + // detect deus ex format + if ( (ahead->framesize/dhead->numverts) == 8 ) + { + averts = nullptr; + dxverts = (const dxvert*)(buffer2+sizeof(a3dhead)); + } + else + { + averts = (const uint32_t*)(buffer2+sizeof(a3dhead)); + dxverts = nullptr; + } + // set counters + numVerts = dhead->numverts; + numFrames = ahead->numframes; + numPolys = dhead->numpolys; + numGroups = 0; + // populate vertex arrays + for ( int i=0; i= numFrames) return FErr_NotFound; + return index; +} + +void FUE1Model::RenderFrame( FModelRenderer *renderer, FGameTexture *skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) +{ + // the moment of magic + if ( (frame < 0) || (frame2 < 0) || (frame >= numFrames) || (frame2 >= numFrames) ) return; + renderer->SetInterpolation(inter); + int vsize, fsize = 0, vofs = 0; + for ( int i=0; iSetMaterial(sskin,false,translation); + renderer->SetupFrame(this, vofs + frame * fsize, vofs + frame2 * fsize, vsize, {}, -1); + renderer->DrawArrays(0,vsize); + vofs += vsize; + } + renderer->SetInterpolation(0.f); +} + +void FUE1Model::BuildVertexBuffer( FModelRenderer *renderer ) +{ + if (GetVertexBuffer(renderer->GetType())) + return; + LoadGeometry(); + int vsize = 0; + for ( int i=0; iCreateVertexBuffer(false,numFrames==1); + SetVertexBuffer(renderer->GetType(), vbuf); + FModelVertex *vptr = vbuf->LockVertexBuffer(vsize); + int vidx = 0; + for ( int i=0; iSet(V.Pos.X,V.Pos.Y,V.Pos.Z,C.X,C.Y); + if ( groups[j].type&PT_Curvy ) // use facet normal + { + vert->SetNormal(polys[groups[j].P[k]].Normals[i].X, + polys[groups[j].P[k]].Normals[i].Y, + polys[groups[j].P[k]].Normals[i].Z); + } + else vert->SetNormal(V.Normal.X,V.Normal.Y,V.Normal.Z); + } + } + } + } + vbuf->UnlockVertexBuffer(); + UnloadGeometry(); // don't forget this, save precious RAM +} + +void FUE1Model::AddSkins( uint8_t *hitlist, const FTextureID* surfaceskinids) +{ + for (int i = 0; i < numGroups; i++) + { + int ssIndex = groups[i].texNum; + if (surfaceskinids && surfaceskinids[ssIndex].isValid()) + hitlist[surfaceskinids[ssIndex].GetIndex()] |= FTextureManager::HIT_Flat; + } +} + +FUE1Model::~FUE1Model() +{ + groups.Reset(); +} diff --git a/src/r_data/models/models_voxel.cpp b/src/common/models/models_voxel.cpp similarity index 85% rename from src/r_data/models/models_voxel.cpp rename to src/common/models/models_voxel.cpp index b0acb941c2f..e6cd5f8373d 100644 --- a/src/r_data/models/models_voxel.cpp +++ b/src/common/models/models_voxel.cpp @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -26,13 +26,18 @@ ** **/ -#include "w_wad.h" -#include "g_level.h" +#include "filesystem.h" #include "colormatcher.h" -#include "textures/bitmap.h" -#include "g_levellocals.h" -#include "models.h" +#include "bitmap.h" +#include "model_kvx.h" #include "image.h" +#include "texturemanager.h" +#include "modelrenderer.h" +#include "voxels.h" +#include "texturemanager.h" +#include "palettecontainer.h" +#include "textures.h" +#include "imagehelpers.h" #ifdef _MSC_VER #pragma warning(disable:4244) // warning C4244: conversion from 'double' to 'float', possible loss of data @@ -52,8 +57,8 @@ class FVoxelTexture : public FImageSource public: FVoxelTexture(FVoxel *voxel); - int CopyPixels(FBitmap *bmp, int conversion) override; - TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; protected: FVoxel *SourceVox; @@ -79,10 +84,10 @@ FVoxelTexture::FVoxelTexture(FVoxel *vox) // //=========================================================================== -TArray FVoxelTexture::CreatePalettedPixels(int conversion) +PalettedPixels FVoxelTexture::CreatePalettedPixels(int conversion, int frame) { // GetPixels gets called when a translated palette is used so we still need to implement it here. - TArray Pixels(256, true); + PalettedPixels Pixels(256); uint8_t *pp = SourceVox->Palette.Data(); if(pp != NULL) @@ -95,6 +100,7 @@ TArray FVoxelTexture::CreatePalettedPixels(int conversion) pe.b = (pp[2] << 2) | (pp[2] >> 4); // Alphatexture handling is just for completeness, but rather unlikely to be used ever. Pixels[i] = conversion == luminance ? pe.r : ColorMatcher.Pick(pe); + } } else @@ -104,6 +110,7 @@ TArray FVoxelTexture::CreatePalettedPixels(int conversion) Pixels[i] = (uint8_t)i; } } + ImageHelpers::FlipSquareBlock(Pixels.Data(), Width); return Pixels; } @@ -116,7 +123,7 @@ TArray FVoxelTexture::CreatePalettedPixels(int conversion) // //=========================================================================== -int FVoxelTexture::CopyPixels(FBitmap *bmp, int conversion) +int FVoxelTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { PalEntry pe[256]; uint8_t bitmap[256]; @@ -156,7 +163,7 @@ FVoxelModel::FVoxelModel(FVoxel *voxel, bool owned) { mVoxel = voxel; mOwningVoxel = owned; - mPalette = TexMan.AddTexture(new FImageTexture(new FVoxelTexture(voxel))); + mPalette = TexMan.AddGameTexture(MakeGameTexture(new FImageTexture(new FVoxelTexture(voxel)), nullptr, ETextureType::Override)); } //=========================================================================== @@ -198,13 +205,12 @@ void FVoxelModel::AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3 float PivotX = mVoxel->Mips[0].Pivot.X; float PivotY = mVoxel->Mips[0].Pivot.Y; float PivotZ = mVoxel->Mips[0].Pivot.Z; - int h = mVoxel->Mips[0].SizeZ; FModelVertex vert; unsigned int indx[4]; vert.packedNormal = 0; // currently this is not being used for voxels. - vert.u = (((col & 15) * 255 / 16) + 7) / 255.f; - vert.v = (((col / 16) * 255 / 16) + 7) / 255.f; + vert.u = (((col & 15) + 0.5f) / 16.f); + vert.v = (((col / 16) + 0.5f) / 16.f); vert.x = x1 - PivotX; vert.z = -y1 + PivotY; @@ -279,8 +285,8 @@ void FVoxelModel::MakeSlabPolys(int x, int y, kvxslab_t *voxptr, FVoxelMap &chec } if (cull & 32) { - int z = ztop+zleng-1; - AddFace(x+1, y, z+1, x, y, z+1, x+1, y+1, z+1, x, y+1, z+1, voxptr->col[zleng-1], check); + int zz = ztop+zleng-1; + AddFace(x+1, y, zz+1, x, y, zz+1, x+1, y+1, zz+1, x, y+1, zz+1, voxptr->col[zleng-1], check); } } @@ -318,12 +324,12 @@ void FVoxelModel::Initialize() void FVoxelModel::BuildVertexBuffer(FModelRenderer *renderer) { - if (!GetVertexBuffer(renderer)) + if (!GetVertexBuffer(renderer->GetType())) { Initialize(); auto vbuf = renderer->CreateVertexBuffer(true, true); - SetVertexBuffer(renderer, vbuf); + SetVertexBuffer(renderer->GetType(), vbuf); FModelVertex *vertptr = vbuf->LockVertexBuffer(mVertices.Size()); unsigned int *indxptr = vbuf->LockIndexBuffer(mIndices.Size()); @@ -350,7 +356,7 @@ void FVoxelModel::BuildVertexBuffer(FModelRenderer *renderer) // //=========================================================================== -void FVoxelModel::AddSkins(uint8_t *hitlist) +void FVoxelModel::AddSkins(uint8_t *hitlist, const FTextureID*) { hitlist[mPalette.GetIndex()] |= FTextureManager::HIT_Flat; } @@ -372,9 +378,9 @@ bool FVoxelModel::Load(const char * fn, int lumpnum, const char * buffer, int le // //=========================================================================== -int FVoxelModel::FindFrame(const char * name) +int FVoxelModel::FindFrame(const char* name, bool nodefault) { - return 0; + return nodefault ? FErr_Voxel : 0; // -2, not -1 because voxels are special. } //=========================================================================== @@ -383,9 +389,9 @@ int FVoxelModel::FindFrame(const char * name) // //=========================================================================== -float FVoxelModel::getAspectFactor(FLevelLocals *Level) +float FVoxelModel::getAspectFactor(float stretch) { - return Level->info->pixelstretch; + return stretch; } //=========================================================================== @@ -394,10 +400,9 @@ float FVoxelModel::getAspectFactor(FLevelLocals *Level) // //=========================================================================== -void FVoxelModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation) +void FVoxelModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID*, const TArray& boneData, int boneStartPosition) { renderer->SetMaterial(skin, true, translation); - GetVertexBuffer(renderer)->SetupFrame(renderer, 0, 0, 0); + renderer->SetupFrame(this, 0, 0, 0, {}, -1); renderer->DrawElements(mNumIndices, 0); } - diff --git a/src/r_data/models/tab_anorms.h b/src/common/models/tab_anorms.h similarity index 100% rename from src/r_data/models/tab_anorms.h rename to src/common/models/tab_anorms.h diff --git a/src/common/models/voxels.cpp b/src/common/models/voxels.cpp new file mode 100644 index 00000000000..4d13323530d --- /dev/null +++ b/src/common/models/voxels.cpp @@ -0,0 +1,491 @@ +/* +** voxels.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2010-2011 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include +#include +#include + +#include "m_swap.h" +#include "m_argv.h" +#include "filesystem.h" +#include "v_video.h" +#include "sc_man.h" +#include "voxels.h" +#include "printf.h" + +void VOX_AddVoxel(int sprnum, int frame, FVoxelDef *def); + +TDeletingArray Voxels; // used only to auto-delete voxels on exit. +TDeletingArray VoxelDefs; + +//========================================================================== +// +// GetVoxelRemap +// +// Calculates a remap table for the voxel's palette. Results are cached so +// passing the same palette repeatedly will not require repeated +// recalculations. +// +//========================================================================== + +static uint8_t *GetVoxelRemap(const uint8_t *pal) +{ + static uint8_t remap[256]; + static uint8_t oldpal[768]; + static bool firsttime = true; + + if (firsttime || memcmp(oldpal, pal, 768) != 0) + { // Not the same palette as last time, so recalculate. + firsttime = false; + memcpy(oldpal, pal, 768); + for (int i = 0; i < 256; ++i) + { + // The voxel palette uses VGA colors, so we have to expand it + // from 6 to 8 bits per component. + remap[i] = ColorMatcher.Pick( + (oldpal[i*3 + 0] << 2) | (oldpal[i*3 + 0] >> 4), + (oldpal[i*3 + 1] << 2) | (oldpal[i*3 + 1] >> 4), + (oldpal[i*3 + 2] << 2) | (oldpal[i*3 + 2] >> 4)); + } + } + return remap; +} + +//========================================================================== +// +// CopyVoxelSlabs +// +// Copy all the slabs in a block of slabs. +// +//========================================================================== + +static bool CopyVoxelSlabs(kvxslab_t *dest, const kvxslab_t *src, int size) +{ + while (size >= 3) + { + int slabzleng = src->zleng; + + if (3 + slabzleng > size) + { // slab is too tall + return false; + } + + dest->ztop = src->ztop; + dest->zleng = src->zleng; + dest->backfacecull = src->backfacecull; + + for (int j = 0; j < slabzleng; ++j) + { + dest->col[j] = src->col[j]; + } + slabzleng += 3; + src = (kvxslab_t *)((uint8_t *)src + slabzleng); + dest = (kvxslab_t *)((uint8_t *)dest + slabzleng); + size -= slabzleng; + } + return true; +} + +//========================================================================== +// +// RemapVoxelSlabs +// +// Remaps all the slabs in a block of slabs. +// +//========================================================================== + +static void RemapVoxelSlabs(kvxslab_t *dest, int size, const uint8_t *remap) +{ + while (size >= 3) + { + int slabzleng = dest->zleng; + + for (int j = 0; j < slabzleng; ++j) + { + dest->col[j] = remap[dest->col[j]]; + } + slabzleng += 3; + dest = (kvxslab_t *)((uint8_t *)dest + slabzleng); + size -= slabzleng; + } +} + +//========================================================================== +// +// R_LoadKVX +// +//========================================================================== + +#if defined __GNUC__ && !defined __clang__ +#pragma GCC push_options +#pragma GCC optimize ("-fno-tree-loop-vectorize") +#endif // __GNUC__ && !__clang__ + +FVoxel *R_LoadKVX(int lumpnum) +{ + const kvxslab_t *slabs[MAXVOXMIPS]; + FVoxel *voxel = new FVoxel; + const uint8_t *rawmip; + int mip, maxmipsize; + int i, j, n; + + auto lump = fileSystem.ReadFile(lumpnum); // FileData adds an extra 0 byte to the end. + auto rawvoxel = lump.bytes(); + int voxelsize = (int)(lump.size()); + if (voxelsize <= 768 + 4) return nullptr; + + // Oh, KVX, why couldn't you have a proper header? We'll just go through + // and collect each MIP level, doing lots of range checking, and if the + // last one doesn't end exactly 768 bytes before the end of the file, + // we'll reject it. + + for (mip = 0, rawmip = rawvoxel, maxmipsize = voxelsize - 768 - 4; + mip < MAXVOXMIPS; + mip++) + { + int numbytes = GetInt(rawmip); + if (numbytes > maxmipsize || numbytes < 24) + { + break; + } + rawmip += 4; + + FVoxelMipLevel *mipl = &voxel->Mips[mip]; + + // Load header data. + mipl->SizeX = GetInt(rawmip + 0); + mipl->SizeY = GetInt(rawmip + 4); + mipl->SizeZ = GetInt(rawmip + 8); + mipl->Pivot.X = GetInt(rawmip + 12) / 256.; + mipl->Pivot.Y = GetInt(rawmip + 16) / 256.; + mipl->Pivot.Z = GetInt(rawmip + 20) / 256.; + + // How much space do we have for voxdata? + int offsetsize = (mipl->SizeX + 1) * 4 + mipl->SizeX * (mipl->SizeY + 1) * 2; + int voxdatasize = numbytes - 24 - offsetsize; + if (voxdatasize < 0) + { // Clearly, not enough. + break; + } + if (voxdatasize != 0) + { // This mip level is not empty. + // Allocate slab data space. + mipl->OffsetX = new int[(numbytes - 24 + 3) / 4]; + mipl->OffsetXY = (short *)(mipl->OffsetX + mipl->SizeX + 1); + mipl->SlabData = (uint8_t *)(mipl->OffsetXY + mipl->SizeX * (mipl->SizeY + 1)); + + // Load x offsets. + for (i = 0, n = mipl->SizeX; i <= n; ++i) + { + // The X offsets stored in the KVX file are relative to the start of the + // X offsets array. Make them relative to voxdata instead. + mipl->OffsetX[i] = GetInt(rawmip + 24 + i * 4) - offsetsize; + } + + // The first X offset must be 0 (since we subtracted offsetsize), according to the spec: + // NOTE: xoffset[0] = (xsiz+1)*4 + xsiz*(ysiz+1)*2 (ALWAYS) + if (mipl->OffsetX[0] != 0) + { + break; + } + // And the final X offset must point just past the end of the voxdata. + if (mipl->OffsetX[mipl->SizeX] != voxdatasize) + { + break; + } + + // Load xy offsets. + i = 24 + i * 4; + for (j = 0, n *= mipl->SizeY + 1; j < n; ++j) + { + mipl->OffsetXY[j] = GetShort(rawmip + i + j * 2); + } + + // Ensure all offsets are within bounds. + for (i = 0; i < mipl->SizeX; ++i) + { + int xoff = mipl->OffsetX[i]; + for (j = 0; j < mipl->SizeY; ++j) + { + int yoff = mipl->OffsetXY[(mipl->SizeY + 1) * i + j]; + if (unsigned(xoff + yoff) > unsigned(voxdatasize)) + { + delete voxel; + return NULL; + } + } + } + + // Record slab location for the end. + slabs[mip] = (kvxslab_t *)(rawmip + 24 + offsetsize); + } + + // Time for the next mip Level. + rawmip += numbytes; + maxmipsize -= numbytes + 4; + } + // Did we get any mip levels, and if so, does the last one leave just + // enough room for the palette after it? + if (mip == 0 || rawmip != rawvoxel + voxelsize - 768) + { + delete voxel; + return NULL; + } + + // Do not count empty mips at the end. + for (; mip > 0; --mip) + { + if (voxel->Mips[mip - 1].SlabData != NULL) + break; + } + voxel->NumMips = mip; + + // Fix pivot data for submips, since some tools seem to like to just center these. + for (i = 1; i < mip; ++i) + { + voxel->Mips[i].Pivot = voxel->Mips[i - 1].Pivot / 2; + } + + for (i = 0; i < mip; ++i) + { + if (!CopyVoxelSlabs((kvxslab_t *)voxel->Mips[i].SlabData, slabs[i], voxel->Mips[i].OffsetX[voxel->Mips[i].SizeX])) + { // Invalid slabs encountered. Reject this voxel. + delete voxel; + return NULL; + } + } + + voxel->LumpNum = lumpnum; + voxel->Palette.Resize(768); + memcpy(voxel->Palette.Data(), rawvoxel + voxelsize - 768, 768); + + return voxel; +} + +#if defined __GNUC__ && !defined __clang__ +#pragma GCC pop_options +#endif // __GNUC__ && !__clang__ + +//========================================================================== +// +// +// +//========================================================================== + +FVoxelDef *R_LoadVoxelDef(int lumpnum, int spin) +{ + FVoxel *vox = R_LoadKVX(lumpnum); + if (vox == NULL) + { + Printf("%s is not a valid voxel file\n", fileSystem.GetFileFullName(lumpnum)); + return NULL; + } + else + { + FVoxelDef *voxdef = new FVoxelDef; + *voxdef = {}; + voxdef->Voxel = vox; + voxdef->Scale = 1.; + voxdef->DroppedSpin = voxdef->PlacedSpin = spin; + voxdef->AngleOffset = DAngle::fromDeg(90.); + + Voxels.Push(vox); + VoxelDefs.Push(voxdef); + return voxdef; + } +} + +//========================================================================== +// +// FVoxelMipLevel Constructor +// +//========================================================================== + +FVoxelMipLevel::FVoxelMipLevel() +{ + SizeZ = SizeY = SizeX = 0; + Pivot.Zero(); + OffsetX = NULL; + OffsetXY = NULL; + SlabData = NULL; +} + +//========================================================================== +// +// FVoxelMipLevel Destructor +// +//========================================================================== + +FVoxelMipLevel::~FVoxelMipLevel() +{ + if (OffsetX != NULL) + { + delete[] OffsetX; + } +} + +//========================================================================== +// +// FVoxelMipLevel :: GetSlabData +// +//========================================================================== + +uint8_t *FVoxelMipLevel::GetSlabData(bool wantremapped) const +{ + if (wantremapped && SlabDataRemapped.Size() > 0) return &SlabDataRemapped[0]; + return SlabData; +} + +//========================================================================== +// +// Create true color version of the slab data +// +//========================================================================== + +void FVoxel::CreateBgraSlabData() +{ + if (Bgramade) return; + Bgramade = true; + for (int i = 0; i < NumMips; ++i) + { + int size = Mips[i].OffsetX[Mips[i].SizeX]; + if (size <= 0) continue; + + Mips[i].SlabDataBgra.Resize(size); + + kvxslab_t *src = (kvxslab_t*)Mips[i].SlabData; + kvxslab_bgra_t *dest = (kvxslab_bgra_t*)&Mips[i].SlabDataBgra[0]; + + while (size >= 3) + { + dest->backfacecull = src->backfacecull; + dest->ztop = src->ztop; + dest->zleng = src->zleng; + + int slabzleng = src->zleng; + for (int j = 0; j < slabzleng; ++j) + { + int colorIndex = src->col[j]; + + uint32_t red, green, blue; + if (Palette.Size()) + { + red = (Palette[colorIndex * 3 + 0] << 2) | (Palette[colorIndex * 3 + 0] >> 4); + green = (Palette[colorIndex * 3 + 1] << 2) | (Palette[colorIndex * 3 + 1] >> 4); + blue = (Palette[colorIndex * 3 + 2] << 2) | (Palette[colorIndex * 3 + 2] >> 4); + } + else + { + red = GPalette.BaseColors[colorIndex].r; + green = GPalette.BaseColors[colorIndex].g; + blue = GPalette.BaseColors[colorIndex].b; + } + + dest->col[j] = 0xff000000 | (red << 16) | (green << 8) | blue; + } + slabzleng += 3; + + dest = (kvxslab_bgra_t *)((uint32_t *)dest + slabzleng); + src = (kvxslab_t *)((uint8_t *)src + slabzleng); + size -= slabzleng; + } + } +} + +//========================================================================== +// +// Remap the voxel to the game palette +// +//========================================================================== + +void FVoxel::Remap() +{ + if (Remapped) return; + Remapped = true; + if (Palette.Size()) + { + uint8_t *remap = GetVoxelRemap(Palette.Data()); + for (int i = 0; i < NumMips; ++i) + { + int size = Mips[i].OffsetX[Mips[i].SizeX]; + if (size <= 0) continue; + + Mips[i].SlabDataRemapped.Resize(size); + memcpy(&Mips[i].SlabDataRemapped [0], Mips[i].SlabData, size); + RemapVoxelSlabs((kvxslab_t *)&Mips[i].SlabDataRemapped[0], Mips[i].OffsetX[Mips[i].SizeX], remap); + } + } +} + +//========================================================================== +// +// Delete the voxel's built-in palette +// +//========================================================================== + +void FVoxel::RemovePalette() +{ + Palette.Reset(); +} + + +//========================================================================== +// +// VOX_GetVoxel +// +// Returns a voxel object for the given lump or NULL if it is not a valid +// voxel. If the voxel has already been loaded, it will be reused. +// +//========================================================================== + +FVoxel* VOX_GetVoxel(int lumpnum) +{ + // Is this voxel already loaded? If so, return it. + for (unsigned i = 0; i < Voxels.Size(); ++i) + { + if (Voxels[i]->LumpNum == lumpnum) + { + return Voxels[i]; + } + } + FVoxel* vox = R_LoadKVX(lumpnum); + if (vox != NULL) + { + Voxels.Push(vox); + } + return vox; +} + + diff --git a/src/r_data/voxels.h b/src/common/models/voxels.h similarity index 89% rename from src/r_data/voxels.h rename to src/common/models/voxels.h index 60a149be9cb..fe583fd936f 100644 --- a/src/r_data/voxels.h +++ b/src/common/models/voxels.h @@ -1,11 +1,13 @@ #ifndef __RES_VOXEL_H #define __RES_VOXEL_H -#include "doomdef.h" - +#include // [RH] Voxels from Build -#define MAXVOXMIPS 5 +enum +{ + MAXVOXMIPS = 5, +}; struct kvxslab_t { @@ -71,13 +73,20 @@ struct FVoxelDef int VoxeldefIndex; // Needed by GZDoom double Scale; DAngle AngleOffset;// added to actor's angle to compensate for wrong-facing voxels + double xoffset; + double yoffset; + double zoffset; + bool PitchFromMomentum; + bool UseActorPitch; + bool UseActorRoll; }; extern TDeletingArray Voxels; // used only to auto-delete voxels on exit. extern TDeletingArray VoxelDefs; +FVoxel* VOX_GetVoxel(int lumpnum); + FVoxel *R_LoadKVX(int lumpnum); FVoxelDef *R_LoadVoxelDef(int lumpnum, int spin); -void R_InitVoxels(); #endif diff --git a/src/common/objects/autosegs.cpp b/src/common/objects/autosegs.cpp new file mode 100644 index 00000000000..e9b3f935ff4 --- /dev/null +++ b/src/common/objects/autosegs.cpp @@ -0,0 +1,144 @@ +/* +** autostart.cpp +** This file contains the heads of lists stored in special data segments +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** The particular scheme used here was chosen because it's small. +** +** An alternative that will work with any C++ compiler is to use static +** classes to build these lists at run time. Under Visual C++, doing things +** that way can require a lot of extra space, which is why I'm doing things +** this way. +** +** In the case of PClass lists (section creg), I orginally used the +** constructor to do just that, and the code for that still exists if you +** compile with something other than Visual C++ or GCC. +*/ + +#include +#include "autosegs.h" + +#ifdef _WIN32 +#include +#include +#elif defined __MACH__ +#include +#include +#endif + + +#if defined _WIN32 || defined __MACH__ + +#define AUTOSEG_VARIABLE(name, autoseg) namespace AutoSegs{ FAutoSeg name{ AUTOSEG_STR(autoseg) }; } + +#else // Linux and others with ELF executables + +#define AUTOSEG_START(name) __start_##name +#define AUTOSEG_STOP(name) __stop_##name +#define AUTOSEG_VARIABLE(name, autoseg) \ + void* name##DummyPointer __attribute__((section(AUTOSEG_STR(autoseg)))) __attribute__((used)); \ + extern void* AUTOSEG_START(autoseg); \ + extern void* AUTOSEG_STOP(autoseg); \ + namespace AutoSegs { FAutoSeg name{ &AUTOSEG_START(autoseg), &AUTOSEG_STOP(autoseg) }; } + +#endif + +AUTOSEG_VARIABLE(ActionFunctons, AUTOSEG_AREG) +AUTOSEG_VARIABLE(TypeInfos, AUTOSEG_CREG) +AUTOSEG_VARIABLE(ClassFields, AUTOSEG_FREG) +AUTOSEG_VARIABLE(Properties, AUTOSEG_GREG) +AUTOSEG_VARIABLE(MapInfoOptions, AUTOSEG_YREG) +AUTOSEG_VARIABLE(CVarDecl, AUTOSEG_VREG) + +#undef AUTOSEG_VARIABLE +#undef AUTOSEG_STOP +#undef AUTOSEG_START + + +void FAutoSeg::Initialize() +{ +#ifdef _WIN32 + + const HMODULE selfModule = GetModuleHandle(nullptr); + const SIZE_T baseAddress = reinterpret_cast(selfModule); + + const PIMAGE_NT_HEADERS header = ImageNtHeader(selfModule); + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(header); + + for (WORD i = 0; i < header->FileHeader.NumberOfSections; ++i, ++section) + { + if (strncmp(reinterpret_cast(section->Name), name, IMAGE_SIZEOF_SHORT_NAME) == 0) + { + begin = reinterpret_cast(baseAddress + section->VirtualAddress); + end = reinterpret_cast(baseAddress + section->VirtualAddress + section->SizeOfRawData); + break; + } + } + +#elif defined __MACH__ + + unsigned long size; + + if (uint8_t *const section = getsectiondata(&_mh_execute_header, AUTOSEG_MACH_SEGMENT, name, &size)) + { + begin = reinterpret_cast(section); + end = reinterpret_cast(section + size); + } + +#else // Linux and others with ELF executables + + assert(false); + +#endif +} + + +#if defined(_MSC_VER) + +// We want visual styles support under XP +#if defined _M_IX86 + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#elif defined _M_IA64 + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#elif defined _M_X64 + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#else + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#endif + +#endif diff --git a/src/common/objects/autosegs.h b/src/common/objects/autosegs.h new file mode 100644 index 00000000000..e015ea9f583 --- /dev/null +++ b/src/common/objects/autosegs.h @@ -0,0 +1,183 @@ +/* +** autosegs.h +** Arrays built at link-time +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef AUTOSEGS_H +#define AUTOSEGS_H + +#include +#include + +#if defined(__clang__) +#if defined(__has_feature) && __has_feature(address_sanitizer) +#define NO_SANITIZE __attribute__((no_sanitize("address"))) +#else +#define NO_SANITIZE +#endif +#else +#define NO_SANITIZE +#endif + +#if defined _MSC_VER +#define NO_SANITIZE_M __declspec(no_sanitize_address) +#else +#define NO_SANITIZE_M +#endif + +class FAutoSeg +{ + const char *name; + void **begin; + void **end; + + template + struct ArgumentType; + + template + struct ArgumentType + { + using Type = Arg; + }; + + template + using ArgumentTypeT = typename ArgumentType::Type; + + template + struct ReturnType + { + using Type = std::invoke_result_t>; + }; + + template + using ReturnTypeT = typename ReturnType::Type; + + template + struct HasReturnType + { + static constexpr bool Value = std::is_same_v, Ret>; + }; + + template + static constexpr bool HasReturnTypeV = HasReturnType::Value; + + void Initialize(); + +public: + explicit FAutoSeg(const char *name) + : name(name) + , begin(nullptr) + , end(nullptr) + { + Initialize(); + } + + FAutoSeg(void** begin, void** end) + : name(nullptr) + , begin(begin) + , end(end) + { + } + + template + void NO_SANITIZE_M ForEach(Func func, std::enable_if_t> * = nullptr) + { + using CallableType = decltype(&Func::operator()); + using ArgType = typename ArgumentType::Type; + + for (void **it = begin; it < end; ++it) + { + if (intptr_t(it) > 0xffff && *it && intptr_t(*it) > 0xffff) + { + func(reinterpret_cast(*it)); + } + } + } + + template + void NO_SANITIZE_M ForEach(Func func, std::enable_if_t> * = nullptr) + { + using CallableType = decltype(&Func::operator()); + using ArgType = typename ArgumentType::Type; + + for (void **it = begin; it < end; ++it) + { + if (intptr_t(it) > 0xffff && *it && intptr_t(*it) > 0xffff) + { + if (!func(reinterpret_cast(*it))) + { + return; + }; + } + } + } +}; + +namespace AutoSegs +{ + extern FAutoSeg ActionFunctons; + extern FAutoSeg TypeInfos; + extern FAutoSeg ClassFields; + extern FAutoSeg Properties; + extern FAutoSeg MapInfoOptions; + extern FAutoSeg CVarDecl; +} + +#define AUTOSEG_AREG areg +#define AUTOSEG_CREG creg +#define AUTOSEG_FREG freg +#define AUTOSEG_GREG greg +#define AUTOSEG_YREG yreg +#define AUTOSEG_VREG vreg + +#define AUTOSEG_STR(string) AUTOSEG_STR2(string) +#define AUTOSEG_STR2(string) #string + +#ifdef __MACH__ +#define AUTOSEG_MACH_SEGMENT "__DATA" +#define AUTOSEG_MACH_SECTION(section) AUTOSEG_MACH_SEGMENT "," AUTOSEG_STR(section) +#define SECTION_AREG AUTOSEG_MACH_SECTION(AUTOSEG_AREG) +#define SECTION_CREG AUTOSEG_MACH_SECTION(AUTOSEG_CREG) +#define SECTION_FREG AUTOSEG_MACH_SECTION(AUTOSEG_FREG) +#define SECTION_GREG AUTOSEG_MACH_SECTION(AUTOSEG_GREG) +#define SECTION_YREG AUTOSEG_MACH_SECTION(AUTOSEG_YREG) +#define SECTION_VREG AUTOSEG_MACH_SECTION(AUTOSEG_VREG) +#else +#define SECTION_AREG AUTOSEG_STR(AUTOSEG_AREG) +#define SECTION_CREG AUTOSEG_STR(AUTOSEG_CREG) +#define SECTION_FREG AUTOSEG_STR(AUTOSEG_FREG) +#define SECTION_GREG AUTOSEG_STR(AUTOSEG_GREG) +#define SECTION_YREG AUTOSEG_STR(AUTOSEG_YREG) +#define SECTION_VREG AUTOSEG_STR(AUTOSEG_VREG) +#endif + +#endif diff --git a/src/common/objects/dobject.cpp b/src/common/objects/dobject.cpp new file mode 100644 index 00000000000..e124a975c7c --- /dev/null +++ b/src/common/objects/dobject.cpp @@ -0,0 +1,787 @@ +/* +** dobject.cpp +** Implements the base class DObject, which most other classes derive from +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include + +#include "dobject.h" +#include "cmdlib.h" +#include "c_dispatch.h" +#include "serializer.h" +#include "vm.h" +#include "types.h" +#include "i_time.h" +#include "printf.h" +#include "maps.h" + +//========================================================================== +// +// +// +//========================================================================== + +ClassReg DObject::RegistrationInfo = +{ + nullptr, // MyClass + "DObject", // Name + nullptr, // ParentType + nullptr, + nullptr, // Pointers + &DObject::InPlaceConstructor, // ConstructNative + nullptr, + sizeof(DObject), // SizeOf +}; +_DECLARE_TI(DObject) + +// This bit is needed in the playsim - but give it a less crappy name. +DEFINE_FIELD_BIT(DObject,ObjectFlags, bDestroyed, OF_EuthanizeMe) + + +//========================================================================== +// +// +// +//========================================================================== + +CCMD (dumpclasses) +{ + // This is by no means speed-optimized. But it's an informational console + // command that will be executed infrequently, so I don't mind. + struct DumpInfo + { + const PClass *Type; + DumpInfo *Next; + DumpInfo *Children; + + static DumpInfo *FindType (DumpInfo *root, const PClass *type) + { + if (root == NULL) + { + return root; + } + if (root->Type == type) + { + return root; + } + if (root->Next != NULL) + { + return FindType (root->Next, type); + } + if (root->Children != NULL) + { + return FindType (root->Children, type); + } + return NULL; + } + + static DumpInfo *AddType (DumpInfo **root, const PClass *type) + { + DumpInfo *info, *parentInfo; + + if (*root == NULL) + { + info = new DumpInfo; + info->Type = type; + info->Next = NULL; + info->Children = *root; + *root = info; + return info; + } + if (type->ParentClass == (*root)->Type) + { + parentInfo = *root; + } + else if (type == (*root)->Type) + { + return *root; + } + else + { + parentInfo = FindType (*root, type->ParentClass); + if (parentInfo == NULL) + { + parentInfo = AddType (root, type->ParentClass); + } + } + // Has this type already been added? + for (info = parentInfo->Children; info != NULL; info = info->Next) + { + if (info->Type == type) + { + return info; + } + } + info = new DumpInfo; + info->Type = type; + info->Next = parentInfo->Children; + info->Children = NULL; + parentInfo->Children = info; + return info; + } + + static void PrintTree (DumpInfo *root, int level) + { + Printf ("%*c%s\n", level, ' ', root->Type->TypeName.GetChars()); + if (root->Children != NULL) + { + PrintTree (root->Children, level + 2); + } + if (root->Next != NULL) + { + PrintTree (root->Next, level); + } + } + + static void FreeTree (DumpInfo *root) + { + if (root->Children != NULL) + { + FreeTree (root->Children); + } + if (root->Next != NULL) + { + FreeTree (root->Next); + } + delete root; + } + }; + + unsigned int i; + int shown, omitted; + DumpInfo *tree = NULL; + const PClass *root = NULL; + + if (argv.argc() > 1) + { + root = PClass::FindClass (argv[1]); + if (root == NULL) + { + Printf ("Class '%s' not found\n", argv[1]); + return; + } + } + + shown = omitted = 0; + DumpInfo::AddType (&tree, root != NULL ? root : RUNTIME_CLASS(DObject)); + for (i = 0; i < PClass::AllClasses.Size(); i++) + { + PClass *cls = PClass::AllClasses[i]; + if (root == NULL || cls == root || cls->IsDescendantOf(root)) + { + DumpInfo::AddType (&tree, cls); +// Printf (" %s\n", PClass::m_Types[i]->Name + 1); + shown++; + } + else + { + omitted++; + } + } + DumpInfo::PrintTree (tree, 2); + DumpInfo::FreeTree (tree); + Printf ("%d classes shown, %d omitted\n", shown, omitted); +} + +//========================================================================== +// +// +// +//========================================================================== + +void DObject::InPlaceConstructor (void *mem) +{ + new ((EInPlace *)mem) DObject; +} + +DObject::DObject () +: Class(0), ObjectFlags(0) +{ + ObjectFlags = GC::CurrentWhite & OF_WhiteBits; + ObjNext = GC::Root; + GCNext = nullptr; + GC::Root = this; +} + +DObject::DObject (PClass *inClass) +: Class(inClass), ObjectFlags(0) +{ + ObjectFlags = GC::CurrentWhite & OF_WhiteBits; + ObjNext = GC::Root; + GCNext = nullptr; + GC::Root = this; +} + +//========================================================================== +// +// +// +//========================================================================== + +DObject::~DObject () +{ + if (!PClass::bShutdown) + { + PClass *type = GetClass(); + if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) + { + if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released))) + { + Printf("Warning: '%s' is freed outside the GC process.\n", + type != NULL ? type->TypeName.GetChars() : "==some object=="); + } + + if (!(ObjectFlags & OF_Released)) + { + // Find all pointers that reference this object and NULL them. + Release(); + } + } + + if (nullptr != type) + { + type->DestroySpecials(this); + } + } +} + +void DObject::Release() +{ + DObject **probe; + + // Unlink this object from the GC list. + for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) + { + if (*probe == this) + { + *probe = ObjNext; + if (&ObjNext == GC::SweepPos) + { + GC::SweepPos = probe; + } + break; + } + } + + // If it's gray, also unlink it from the gray list. + if (this->IsGray()) + { + for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) + { + if (*probe == this) + { + *probe = GCNext; + break; + } + } + } + ObjNext = nullptr; + GCNext = nullptr; + ObjectFlags |= OF_Released; +} + +//========================================================================== +// +// +// +//========================================================================== + +void DObject::Destroy () +{ + RemoveFromNetwork(); + + // We cannot call the VM during shutdown because all the needed data has been or is in the process of being deleted. + if (PClass::bVMOperational) + { + IFVIRTUAL(DObject, OnDestroy) + { + VMValue params[1] = { (DObject*)this }; + VMCall(func, params, 1, nullptr, 0); + } + } + OnDestroy(); + ObjectFlags = (ObjectFlags & ~OF_Fixed) | OF_EuthanizeMe; + GC::WriteBarrier(this); +} + +DEFINE_ACTION_FUNCTION(DObject, Destroy) +{ + PARAM_SELF_PROLOGUE(DObject); + self->Destroy(); + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +template +static void PropagateMarkMap(M *map) +{ + TMapIterator it(*map); + typename M::Pair * p; + while(it.NextPair(p)) + { + GC::Mark(&p->Value); + } +} + +size_t DObject::PropagateMark() +{ + const PClass *info = GetClass(); + if (!PClass::bShutdown) + { + if (info->FlatPointers == nullptr) + { + info->BuildFlatPointers(); + assert(info->FlatPointers); + } + + for(size_t i = 0; i < info->FlatPointersSize; i++) + { + GC::Mark((DObject **)((uint8_t *)this + info->FlatPointers[i].first)); + } + + if (info->ArrayPointers == nullptr) + { + info->BuildArrayPointers(); + assert(info->ArrayPointers); + } + + for(size_t i = 0; i < info->ArrayPointersSize; i++) + { + auto aray = (TArray*)((uint8_t *)this + info->ArrayPointers[i].first); + for (auto &p : *aray) + { + GC::Mark(&p); + } + } + + if (info->MapPointers == nullptr) + { + info->BuildMapPointers(); + assert(info->MapPointers); + } + + for(size_t i = 0; i < info->MapPointersSize; i++) + { + PMap * type = static_cast(info->MapPointers[i].second); + if(type->KeyType->RegType == REGT_STRING) + { // FString,DObject* + PropagateMarkMap((ZSMap*)((uint8_t *)this + info->MapPointers[i].first)); + } + else + { // uint32_t,DObject* + PropagateMarkMap((ZSMap*)((uint8_t *)this + info->MapPointers[i].first)); + } + } + return info->Size; + } + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +template +static void MapPointerSubstitution(M *map, size_t &changed, DObject *old, DObject *notOld, const bool shouldSwap) +{ + TMapIterator it(*map); + typename M::Pair * p; + while(it.NextPair(p)) + { + if (p->Value == old) + { + if (shouldSwap) + { + p->Value = notOld; + changed++; + } + else if (p->Value != nullptr) + { + p->Value = nullptr; + changed++; + } + } + } +} + +size_t DObject::PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail) +{ + const PClass *info = GetClass(); + size_t changed = 0; + if (info->FlatPointers == nullptr) + { + info->BuildFlatPointers(); + assert(info->FlatPointers); + } + + for(size_t i = 0; i < info->FlatPointersSize; i++) + { + size_t offset = info->FlatPointers[i].first; + auto& obj = *(DObject**)((uint8_t*)this + offset); + + if (obj == old) + { + // If a pointer's type is null, that means it's native and anything native is safe to swap + // around due to its inherit type expansiveness. + if (info->FlatPointers[i].second == nullptr || notOld->IsKindOf(info->FlatPointers[i].second->PointedClass())) + { + obj = notOld; + changed++; + } + else if (nullOnFail && obj != nullptr) + { + obj = nullptr; + changed++; + } + } + } + + if (info->ArrayPointers == nullptr) + { + info->BuildArrayPointers(); + assert(info->ArrayPointers); + } + + for(size_t i = 0; i < info->ArrayPointersSize; i++) + { + const bool isType = notOld->IsKindOf(static_cast(info->ArrayPointers[i].second->ElementType)->PointedClass()); + + if (!isType && !nullOnFail) + continue; + + auto aray = (TArray*)((uint8_t*)this + info->ArrayPointers[i].first); + for (auto &p : *aray) + { + if (p == old) + { + if (isType) + { + p = notOld; + changed++; + } + else if (p != nullptr) + { + p = nullptr; + changed++; + } + } + } + } + + if (info->MapPointers == nullptr) + { + info->BuildMapPointers(); + assert(info->MapPointers); + } + + for(size_t i = 0; i < info->MapPointersSize; i++) + { + PMap * type = static_cast(info->MapPointers[i].second); + + const bool isType = notOld->IsKindOf(static_cast(type->ValueType)->PointedClass()); + if (!isType && !nullOnFail) + continue; + + if(type->KeyType->RegType == REGT_STRING) + { // FString,DObject* + MapPointerSubstitution((ZSMap*)((uint8_t *)this + info->MapPointers[i].first), changed, old, notOld, isType); + } + else + { // uint32_t,DObject* + MapPointerSubstitution((ZSMap*)((uint8_t *)this + info->MapPointers[i].first), changed, old, notOld, isType); + } + } + + return changed; +} + +//========================================================================== +// +// +// +//========================================================================== + +void DObject::SerializeUserVars(FSerializer &arc) +{ + if (arc.isWriting()) + { + // Write all fields that aren't serialized by native code. + GetClass()->WriteAllFields(arc, this); + } + else + { + GetClass()->ReadAllFields(arc, this); + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +void DObject::Serialize(FSerializer &arc) +{ + const auto SerializeFlag = [&](const char *const name, const EObjectFlags flag) + { + int value = ObjectFlags & flag; + int defaultvalue = 0; + arc(name, value, defaultvalue); + if (arc.isReading()) + { + ObjectFlags |= value; + } + }; + + SerializeFlag("justspawned", OF_JustSpawned); + SerializeFlag("spawned", OF_Spawned); + SerializeFlag("networked", OF_Networked); + + ObjectFlags |= OF_SerialSuccess; + + if (arc.isReading() && (ObjectFlags & OF_Networked)) + { + ClearNetworkID(); + EnableNetworking(true); + } +} + +void DObject::CheckIfSerialized () const +{ + if (!(ObjectFlags & OF_SerialSuccess)) + { + I_Error ( + "BUG: %s::Serialize\n" + "(or one of its superclasses) needs to call\n" + "Super::Serialize\n", + StaticType()->TypeName.GetChars()); + } +} + +DEFINE_ACTION_FUNCTION(DObject, MSTime) +{ + ACTION_RETURN_INT((uint32_t)I_msTime()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, MSTimef, I_msTimeF) +{ + ACTION_RETURN_FLOAT(I_msTimeF()); +} + +void *DObject::ScriptVar(FName field, PType *type) +{ + auto cls = GetClass(); + auto sym = dyn_cast(cls->FindSymbol(field, true)); + if (sym && (sym->Type == type || type == nullptr)) + { + if (!(sym->Flags & VARF_Meta)) + { + return (((char*)this) + sym->Offset); + } + else + { + return (cls->Meta + sym->Offset); + } + } + // This is only for internal use so I_Error is fine. + I_Error("Variable %s not found in %s\n", field.GetChars(), cls->TypeName.GetChars()); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void NetworkEntityManager::InitializeNetworkEntities() +{ + if (!s_netEntities.Size()) + s_netEntities.AppendFill(nullptr, NetIDStart); // Allocate the first 0-8 slots for the world and clients. +} + +// Clients need special handling since they always go in slots 1 - MAXPLAYERS. +void NetworkEntityManager::SetClientNetworkEntity(DObject* mo, const unsigned int playNum) +{ + // If resurrecting, we need to swap the corpse's position with the new pawn's + // position so it's no longer considered the client's body. + const uint32_t id = ClientNetIDStart + playNum; + DObject* const oldBody = s_netEntities[id]; + if (oldBody != nullptr) + { + if (oldBody == mo) + return; + + const uint32_t curID = mo->GetNetworkID(); + + s_netEntities[curID] = oldBody; + oldBody->ClearNetworkID(); + oldBody->SetNetworkID(curID); + + mo->ClearNetworkID(); + } + else + { + RemoveNetworkEntity(mo); // Free up its current id. + } + + s_netEntities[id] = mo; + mo->SetNetworkID(id); +} + +void NetworkEntityManager::AddNetworkEntity(DObject* const ent) +{ + if (ent->IsNetworked()) + return; + + // Slot 0 is reserved for the world. + // Clients go in the first 1 - MAXPLAYERS slots + // Everything else is first come first serve. + uint32_t id = WorldNetID; + if (s_openNetIDs.Size()) + { + s_openNetIDs.Pop(id); + s_netEntities[id] = ent; + } + else + { + id = s_netEntities.Push(ent); + } + + ent->SetNetworkID(id); +} + +void NetworkEntityManager::RemoveNetworkEntity(DObject* const ent) +{ + if (!ent->IsNetworked()) + return; + + const uint32_t id = ent->GetNetworkID(); + if (id == WorldNetID) + return; + + assert(s_netEntities[id] == ent); + if (id >= NetIDStart) + s_openNetIDs.Push(id); + s_netEntities[id] = nullptr; + ent->ClearNetworkID(); +} + +DObject* NetworkEntityManager::GetNetworkEntity(const uint32_t id) +{ + if (id == WorldNetID || id >= s_netEntities.Size()) + return nullptr; + + return s_netEntities[id]; +} + +//========================================================================== +// +// +// +//========================================================================== + +void DObject::SetNetworkID(const uint32_t id) +{ + if (!IsNetworked()) + { + ObjectFlags |= OF_Networked; + _networkID = id; + } +} + +void DObject::ClearNetworkID() +{ + ObjectFlags &= ~OF_Networked; + _networkID = NetworkEntityManager::WorldNetID; +} + +void DObject::EnableNetworking(const bool enable) +{ + if (enable) + NetworkEntityManager::AddNetworkEntity(this); + else + NetworkEntityManager::RemoveNetworkEntity(this); +} + +void DObject::RemoveFromNetwork() +{ + NetworkEntityManager::RemoveNetworkEntity(this); +} + +static unsigned int GetNetworkID(DObject* const self) +{ + return self->GetNetworkID(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, GetNetworkID, GetNetworkID) +{ + PARAM_SELF_PROLOGUE(DObject); + + ACTION_RETURN_INT(self->GetNetworkID()); +} + +static void EnableNetworking(DObject* const self, const bool enable) +{ + self->EnableNetworking(enable); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, EnableNetworking, EnableNetworking) +{ + PARAM_SELF_PROLOGUE(DObject); + PARAM_BOOL(enable); + + self->EnableNetworking(enable); + return 0; +} + +static DObject* GetNetworkEntity(const unsigned int id) +{ + return NetworkEntityManager::GetNetworkEntity(id); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, GetNetworkEntity, GetNetworkEntity) +{ + PARAM_PROLOGUE; + PARAM_UINT(id); + + ACTION_RETURN_OBJECT(NetworkEntityManager::GetNetworkEntity(id)); +} + diff --git a/src/dobject.h b/src/common/objects/dobject.h similarity index 89% rename from src/dobject.h rename to src/common/objects/dobject.h index a4e16dc0b92..c0b6aecb57a 100644 --- a/src/dobject.h +++ b/src/common/objects/dobject.h @@ -36,9 +36,12 @@ #include #include -#include "doomtype.h" - +#include "m_alloc.h" #include "vectors.h" +#include "name.h" +#include "palentry.h" +#include "textureid.h" +#include "autosegs.h" class PClass; class PType; @@ -108,7 +111,7 @@ enum EInPlace { EC_InPlace }; #define DECLARE_ABSTRACT_CLASS(cls,parent) \ public: \ - virtual PClass *StaticType() const; \ + PClass *StaticType() const override; \ static ClassReg RegistrationInfo, * const RegistrationInfoPtr; \ typedef parent Super; \ private: \ @@ -132,8 +135,8 @@ public: \ static const size_t PointerOffsets[]; #if defined(_MSC_VER) -# pragma section(".creg$u",read) -# define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo; +# pragma section(SECTION_CREG,read) +# define _DECLARE_TI(cls) __declspec(allocate(SECTION_CREG)) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo; #else # define _DECLARE_TI(cls) ClassReg * const cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo; #endif @@ -176,8 +179,6 @@ public: \ #include "dobjgc.h" -class AActor; - class DObject { public: @@ -242,10 +243,10 @@ class DObject inline DAngle &AngleVar(FName field); inline FString &StringVar(FName field); template T*& PointerVar(FName field); + inline int* IntArray(FName field); // This is only needed for swapping out PlayerPawns and absolutely nothing else! - virtual size_t PointerSubstitution (DObject *old, DObject *notOld); - static void StaticPointerSubstitution (AActor *old, AActor *notOld); + virtual size_t PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail); PClass *GetClass() const { @@ -265,7 +266,7 @@ class DObject void *operator new(size_t len, nonew&) { - return M_Malloc(len); + return M_Calloc(len, 1); } public: @@ -350,6 +351,18 @@ class DObject friend T* Create(Args&&... args); friend class JitCompiler; + +private: + // This is intentionally left unserialized. + uint32_t _networkID; + +public: + inline bool IsNetworked() const { return (ObjectFlags & OF_Networked); } + inline uint32_t GetNetworkID() const { return _networkID; } + void SetNetworkID(const uint32_t id); + void ClearNetworkID(); + void RemoveFromNetwork(); + virtual void EnableNetworking(const bool enable); }; // This is the only method aside from calling CreateNew that should be used for creating DObjects @@ -433,6 +446,11 @@ inline int &DObject::IntVar(FName field) return *(int*)ScriptVar(field, nullptr); } +inline int* DObject::IntArray(FName field) +{ + return (int*)ScriptVar(field, nullptr); +} + inline FTextureID &DObject::TextureIDVar(FName field) { return *(FTextureID*)ScriptVar(field, nullptr); @@ -469,4 +487,25 @@ inline T *&DObject::PointerVar(FName field) return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle. } + +class NetworkEntityManager +{ +private: + inline static TArray s_netEntities = {}; + inline static TArray s_openNetIDs = {}; + +public: + NetworkEntityManager() = delete; + + static constexpr uint32_t WorldNetID = 0u; + static constexpr uint32_t ClientNetIDStart = 1u; + inline static uint32_t NetIDStart;// = MAXPLAYERS + 1u; + + static void InitializeNetworkEntities(); + static void SetClientNetworkEntity(DObject* mo, const unsigned int playNum); + static void AddNetworkEntity(DObject* const ent); + static void RemoveNetworkEntity(DObject* const ent); + static DObject* GetNetworkEntity(const uint32_t id); +}; + #endif //__DOBJECT_H__ diff --git a/src/common/objects/dobjgc.cpp b/src/common/objects/dobjgc.cpp new file mode 100644 index 00000000000..d388e4836b4 --- /dev/null +++ b/src/common/objects/dobjgc.cpp @@ -0,0 +1,889 @@ +/* +** dobjgc.cpp +** The garbage collector. Based largely on Lua's. +** +**--------------------------------------------------------------------------- +** Copyright 2008-2022 Marisa Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +/****************************************************************************** +* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. +* +* 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. +******************************************************************************/ + +// HEADER FILES ------------------------------------------------------------ + +#include "dobject.h" + +#include "c_dispatch.h" +#include "menu.h" +#include "stats.h" +#include "printf.h" +#include "cmdlib.h" + +// MACROS ------------------------------------------------------------------ + +/* +@@ DEFAULT_GCPAUSE defines the default pause between garbage-collector cycles +@* as a percentage. +** CHANGE it if you want the GC to run faster or slower (higher values +** mean larger pauses which mean slower collection.) You can also change +** this value dynamically. +*/ +#define DEFAULT_GCPAUSE 150 // 150% (wait for memory to increase by half before next GC) + +/* +@@ DEFAULT_GCMUL defines the default speed of garbage collection relative to +@* memory allocation as a percentage. +** CHANGE it if you want to change the granularity of the garbage +** collection. (Higher values mean coarser collections. 0 represents +** infinity, where each step performs a full collection.) You can also +** change this value dynamically. +*/ +#ifndef _DEBUG +#define DEFAULT_GCMUL 600 // GC runs gcmul% the speed of memory allocation +#else +// Higher in debug builds to account for the extra time spent freeing objects +#define DEFAULT_GCMUL 800 +#endif + +// Minimum step size +#define GCMINSTEPSIZE (sizeof(DObject) * 16) + +// Sweeps traverse objects in chunks of this size +#define GCSWEEPGRANULARITY 40 + +// Cost of deleting an object +#ifndef _DEBUG +#define GCDELETECOST 75 +#else +// Freeing memory is much more costly in debug builds +#define GCDELETECOST 230 +#endif + +// Cost of destroying an object +#define GCDESTROYCOST 15 + +// TYPES ------------------------------------------------------------------- + +class FAveragizer +{ + // Number of allocations to track + static inline constexpr unsigned HistorySize = 512; + + size_t History[HistorySize]; + size_t TotalAmount; + int TotalCount; + unsigned NewestPos; + +public: + FAveragizer(); + void AddAlloc(size_t alloc); + size_t GetAverage(); +}; + +struct FStepStats +{ + cycle_t Clock[GC::GCS_COUNT]; + size_t BytesCovered[GC::GCS_COUNT]; + int Count[GC::GCS_COUNT]; + + void Format(FString &out); + void Reset(); +}; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static size_t CalcStepSize(); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +namespace GC +{ +size_t AllocBytes; +size_t RunningAllocBytes; +size_t RunningDeallocBytes; +size_t Threshold; +size_t Estimate; +DObject *Gray; +DObject *Root; +DObject *SoftRoots; +DObject **SweepPos; +DObject *ToDestroy; +uint32_t CurrentWhite = OF_White0 | OF_Fixed; +EGCState State = GCS_Pause; +int Pause = DEFAULT_GCPAUSE; +int StepMul = DEFAULT_GCMUL; +FStepStats StepStats; +FStepStats PrevStepStats; +bool FinalGC; +bool HadToDestroy; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static FAveragizer AllocHistory;// Tracks allocation rate over time +static cycle_t GCTime; // Track time spent in GC + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// CheckGC +// +// Check if it's time to collect, and do a collection step if it is. +// Also does some bookkeeping. Should be called fairly consistantly. +// +//========================================================================== + +void CheckGC() +{ + AllocHistory.AddAlloc(RunningAllocBytes); + RunningAllocBytes = 0; + if (State > GCS_Pause || AllocBytes >= Threshold) + { + Step(); + } +} + +//========================================================================== +// +// SetThreshold +// +// Sets the new threshold after a collection is finished. +// +//========================================================================== + +void SetThreshold() +{ + Threshold = (std::min(Estimate, AllocBytes) / 100) * Pause; +} + +//========================================================================== +// +// PropagateMark +// +// Marks the top-most gray object black and marks all objects it points to +// gray. +// +//========================================================================== + +size_t PropagateMark() +{ + DObject *obj = Gray; + assert(obj->IsGray()); + obj->Gray2Black(); + Gray = obj->GCNext; + return !(obj->ObjectFlags & OF_EuthanizeMe) ? obj->PropagateMark() : + obj->GetClass()->Size; +} + +//========================================================================== +// +// SweepObjects +// +// Runs a limited sweep on the object list, returning the number of bytes +// swept. +// +//========================================================================== + +static size_t SweepObjects(size_t count) +{ + DObject *curr; + int deadmask = OtherWhite(); + size_t swept = 0; + + while ((curr = *SweepPos) != nullptr && count-- > 0) + { + swept += curr->GetClass()->Size; + if ((curr->ObjectFlags ^ OF_WhiteBits) & deadmask) // not dead? + { + assert(!curr->IsDead() || (curr->ObjectFlags & OF_Fixed)); + curr->MakeWhite(); // make it white (for next cycle) + SweepPos = &curr->ObjNext; + } + else + { + assert(curr->IsDead()); + if (!(curr->ObjectFlags & OF_EuthanizeMe)) + { // The object must be destroyed before it can be deleted. + curr->GCNext = ToDestroy; + ToDestroy = curr; + SweepPos = &curr->ObjNext; + } + else + { // must erase 'curr' + *SweepPos = curr->ObjNext; + curr->ObjectFlags |= OF_Cleanup; + delete curr; + swept += GCDELETECOST; + } + } + } + return swept; +} + +//========================================================================== +// +// DestroyObjects +// +// Destroys up to count objects on a list linked on GCNext, returning the +// size of objects destroyed, for updating the estimate. +// +//========================================================================== + +static size_t DestroyObjects(size_t count) +{ + DObject *curr; + size_t bytes_destroyed = 0; + + while ((curr = ToDestroy) != nullptr && count-- > 0) + { + // Note that we cannot assume here that the object has not yet been destroyed. + // If destruction happens as the result of another object's destruction we may + // get entries here that have been destroyed already if that owning object was + // first in the list. + if (!(curr->ObjectFlags & OF_EuthanizeMe)) + { + bytes_destroyed += curr->GetClass()->Size + GCDESTROYCOST; + ToDestroy = curr->GCNext; + curr->GCNext = nullptr; + curr->Destroy(); + } + else + { + ToDestroy = curr->GCNext; + curr->GCNext = nullptr; + } + } + return bytes_destroyed; +} + +//========================================================================== +// +// Mark +// +// Mark a single object gray. +// +//========================================================================== + +void Mark(DObject **obj) +{ + DObject *lobj = *obj; + + //assert(lobj == nullptr || !(lobj->ObjectFlags & OF_Released)); + if (lobj != nullptr && !(lobj->ObjectFlags & OF_Released)) + { + if (lobj->ObjectFlags & OF_EuthanizeMe) + { + *obj = (DObject *)NULL; + } + else if (lobj->IsWhite()) + { + lobj->White2Gray(); + lobj->GCNext = Gray; + Gray = lobj; + } + } +} + +//========================================================================== +// +// MarkArray +// +// Mark an array of objects gray. +// +//========================================================================== + +void MarkArray(DObject **obj, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Mark(obj[i]); + } +} + +//========================================================================== +// +// CalcStepSize +// +// Decide how big a step should be, based on the current allocation rate. +// +//========================================================================== + +static size_t CalcStepSize() +{ + size_t avg = AllocHistory.GetAverage(); + return std::max(GCMINSTEPSIZE, avg * StepMul / 100); +} + +//========================================================================== +// +// MarkRoot +// +// Mark the root set of objects. +// +//========================================================================== + +TArray markers; +void AddMarkerFunc(GCMarkerFunc func) +{ + if (markers.Find(func) == markers.Size()) + markers.Push(func); +} + +static void MarkRoot() +{ + PrevStepStats = StepStats; + StepStats.Reset(); + + Gray = nullptr; + + for (auto func : markers) func(); + + // Mark soft roots. + if (SoftRoots != nullptr) + { + DObject **probe = &SoftRoots->ObjNext; + while (*probe != nullptr) + { + DObject *soft = *probe; + probe = &soft->ObjNext; + if ((soft->ObjectFlags & (OF_Rooted | OF_EuthanizeMe)) == OF_Rooted) + { + Mark(soft); + } + } + } + // Time to propagate the marks. + State = GCS_Propagate; +} + +//========================================================================== +// +// Atomic +// +// If there were any propagations that needed to be done atomicly, they +// would go here. It also sets things up for the sweep state. +// +//========================================================================== + +static void Atomic() +{ + // Flip current white + CurrentWhite = OtherWhite(); + SweepPos = &Root; + State = GCS_Sweep; + Estimate = AllocBytes; +} + +//========================================================================== +// +// SweepDone +// +// Sets up the Destroy phase, if there are any dead objects that haven't +// been destroyed yet, or skips to the Done state. +// +//========================================================================== + +static void SweepDone() +{ + HadToDestroy = ToDestroy != nullptr; + State = HadToDestroy ? GCS_Destroy : GCS_Done; +} + +//========================================================================== +// +// SingleStep +// +// Performs one step of the collector. +// +//========================================================================== + +static size_t SingleStep() +{ + switch (State) + { + case GCS_Pause: + MarkRoot(); // Start a new collection + return 0; + + case GCS_Propagate: + if (Gray != nullptr) + { + return PropagateMark(); + } + else + { // no more gray objects + Atomic(); // finish mark phase + return 0; + } + + case GCS_Sweep: { + RunningDeallocBytes = 0; + size_t swept = SweepObjects(GCSWEEPGRANULARITY); + Estimate -= RunningDeallocBytes; + if (*SweepPos == nullptr) + { // Nothing more to sweep? + SweepDone(); + } + return swept; + } + + case GCS_Destroy: { + size_t destroy_size; + destroy_size = DestroyObjects(GCSWEEPGRANULARITY); + Estimate -= destroy_size; + if (ToDestroy == nullptr) + { // Nothing more to destroy? + State = GCS_Done; + } + return destroy_size; + } + + case GCS_Done: + State = GCS_Pause; // end collection + SetThreshold(); + return 0; + + default: + assert(0); + return 0; + } +} + +//========================================================================== +// +// Step +// +// Performs enough single steps to cover bytes of memory. +// Some of those bytes might be "fake" to account for the cost of freeing +// or destroying object. +// +//========================================================================== + +void Step() +{ + GCTime.ResetAndClock(); + + auto enter_state = State; + StepStats.Count[enter_state]++; + StepStats.Clock[enter_state].Clock(); + + size_t did = 0; + size_t lim = CalcStepSize(); + + do + { + size_t done = SingleStep(); + did += done; + if (done < lim) + { + lim -= done; + } + else + { + lim = 0; + } + if (State != enter_state) + { + // Finish stats on old state + StepStats.Clock[enter_state].Unclock(); + StepStats.BytesCovered[enter_state] += did; + + // Start stats on new state + did = 0; + enter_state = State; + StepStats.Clock[enter_state].Clock(); + StepStats.Count[enter_state]++; + } + } while (lim && State != GCS_Pause); + + StepStats.Clock[enter_state].Unclock(); + StepStats.BytesCovered[enter_state] += did; + GCTime.Unclock(); +} + +//========================================================================== +// +// FullGC +// +// Collects everything in one fell swoop. +// +//========================================================================== + +void FullGC() +{ + bool ContinueCheck = true; + while (ContinueCheck) + { + ContinueCheck = false; + if (State <= GCS_Propagate) + { + // Reset sweep mark to sweep all elements (returning them to white) + SweepPos = &Root; + // Reset other collector lists + Gray = nullptr; + State = GCS_Sweep; + } + // Finish any pending GC stages + while (State != GCS_Pause) + { + SingleStep(); + } + // Loop until everything that can be destroyed and freed is + do + { + MarkRoot(); + while (State != GCS_Pause) + { + SingleStep(); + } + ContinueCheck |= HadToDestroy; + } while (HadToDestroy); + } +} + +//========================================================================== +// +// Barrier +// +// Implements a write barrier to maintain the invariant that a black node +// never points to a white node by making the node pointed at gray. +// +//========================================================================== + +void Barrier(DObject *pointing, DObject *pointed) +{ + assert(pointing == nullptr || (pointing->IsBlack() && !pointing->IsDead())); + assert(pointed->IsWhite() && !pointed->IsDead()); + assert(State != GCS_Destroy && State != GCS_Pause); + assert(!(pointed->ObjectFlags & OF_Released)); // if a released object gets here, something must be wrong. + if (pointed->ObjectFlags & OF_Released) return; // don't do anything with non-GC'd objects. + // The invariant only needs to be maintained in the propagate state. + if (State == GCS_Propagate) + { + pointed->White2Gray(); + pointed->GCNext = Gray; + Gray = pointed; + } + // In other states, we can mark the pointing object white so this + // barrier won't be triggered again, saving a few cycles in the future. + else if (pointing != nullptr) + { + pointing->MakeWhite(); + } +} + +void DelSoftRootHead() +{ + if (SoftRoots != nullptr) + { + // Don't let the destructor print a warning message + SoftRoots->ObjectFlags |= OF_YesReallyDelete; + delete SoftRoots; + } + SoftRoots = nullptr; +} + +//========================================================================== +// +// AddSoftRoot +// +// Marks an object as a soft root. A soft root behaves exactly like a root +// in MarkRoot, except it can be added at run-time. +// +//========================================================================== + +void AddSoftRoot(DObject *obj) +{ + DObject **probe; + + // Are there any soft roots yet? + if (SoftRoots == nullptr) + { + // Create a new object to root the soft roots off of, and stick + // it at the end of the object list, so we know that anything + // before it is not a soft root. + SoftRoots = Create(); + SoftRoots->ObjectFlags |= OF_Fixed; + probe = &Root; + while (*probe != nullptr) + { + probe = &(*probe)->ObjNext; + } + Root = SoftRoots->ObjNext; + SoftRoots->ObjNext = nullptr; + *probe = SoftRoots; + } + // Mark this object as rooted and move it after the SoftRoots marker. + probe = &Root; + while (*probe != nullptr && *probe != obj) + { + probe = &(*probe)->ObjNext; + } + *probe = (*probe)->ObjNext; + obj->ObjNext = SoftRoots->ObjNext; + SoftRoots->ObjNext = obj; + obj->ObjectFlags |= OF_Rooted; + WriteBarrier(obj); +} + +//========================================================================== +// +// DelSoftRoot +// +// Unroots an object so that it must be reachable or it will get collected. +// +//========================================================================== + +void DelSoftRoot(DObject *obj) +{ + DObject **probe; + + if (obj == nullptr || !(obj->ObjectFlags & OF_Rooted)) + { // Not rooted, so nothing to do. + return; + } + obj->ObjectFlags &= ~OF_Rooted; + // Move object out of the soft roots part of the list. + probe = &SoftRoots; + while (*probe != nullptr && *probe != obj) + { + probe = &(*probe)->ObjNext; + } + if (*probe == obj) + { + *probe = obj->ObjNext; + obj->ObjNext = Root; + Root = obj; + } +} + +} + +//========================================================================== +// +// FAveragizer - Constructor +// +//========================================================================== + +FAveragizer::FAveragizer() +{ + NewestPos = 0; + TotalAmount = 0; + TotalCount = 0; + memset(History, 0, sizeof(History)); +} + +//========================================================================== +// +// FAveragizer :: AddAlloc +// +//========================================================================== + +void FAveragizer::AddAlloc(size_t alloc) +{ + NewestPos = (NewestPos + 1) & (HistorySize - 1); + if (TotalCount < (int)HistorySize) + { + TotalCount++; + } + else + { + TotalAmount -= History[NewestPos]; + } + History[NewestPos] = alloc; + TotalAmount += alloc; +} + +//========================================================================== +// +// FAveragizer :: GetAverage +// +//========================================================================== + +size_t FAveragizer::GetAverage() +{ + return TotalCount != 0 ? TotalAmount / TotalCount : 0; +} + +//========================================================================== +// +// STAT gc +// +// Provides information about the current garbage collector state. +// +//========================================================================== + +ADD_STAT(gc) +{ + static const char *StateStrings[] = { + " Pause ", + "Propagate", + " Sweep ", + " Destroy ", + " Done " + }; + FString out; + double time = GC::State != GC::GCS_Pause ? GC::GCTime.TimeMS() : 0; + + GC::PrevStepStats.Format(out); + out << "\n"; + GC::StepStats.Format(out); + out.AppendFormat("\n%.2fms [%s] Rate:%3zuK (%3zuK) Alloc:%6zuK Est:%6zuK Thresh:%6zuK", + time, + StateStrings[GC::State], + (GC::AllocHistory.GetAverage() + 1023) >> 10, + (GC::CalcStepSize() + 1023) >> 10, + (GC::AllocBytes + 1023) >> 10, + (GC::Estimate + 1023) >> 10, + (GC::Threshold + 1023) >> 10); + return out; +} + +//========================================================================== +// +// FStepStats :: Reset +// +//========================================================================== + +void FStepStats::Reset() +{ + for (unsigned i = 0; i < countof(Count); ++i) + { + Count[i] = 0; + BytesCovered[i] = 0; + Clock[i].Reset(); + } +} + +//========================================================================== +// +// FStepStats :: Format +// +// Appends its stats to the given FString. +// +//========================================================================== + +void FStepStats::Format(FString &out) +{ + // Because everything in the default green is hard to distinguish, + // each stage has its own color. + for (int i = GC::GCS_Propagate; i < GC::GCS_Done; ++i) + { + int count = Count[i]; + double time = Clock[i].TimeMS(); + out.AppendFormat(TEXTCOLOR_ESCAPESTR "%c[%c%6zuK %4d*%.2fms]", + "-NKB"[i], /* Color codes */ + "-PSD"[i], /* Stage prefixes: (P)ropagate, (S)weep, (D)estroy */ + (BytesCovered[i] + 1023) >> 10, count, count != 0 ? time / count : time); + } + out << TEXTCOLOR_GREEN; +} + +//========================================================================== +// +// CCMD gc +// +// Controls various aspects of the collector. +// +//========================================================================== + +CCMD(gc) +{ + if (argv.argc() == 1) + { + Printf ("Usage: gc stop|now|full|count|pause [size]|stepmul [size]\n"); + return; + } + if (stricmp(argv[1], "stop") == 0) + { + GC::Threshold = ~(size_t)0 - 2; + } + else if (stricmp(argv[1], "now") == 0) + { + GC::Threshold = GC::AllocBytes; + } + else if (stricmp(argv[1], "full") == 0) + { + GC::FullGC(); + } + else if (stricmp(argv[1], "count") == 0) + { + int cnt = 0; + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++); + Printf("%d active objects counted\n", cnt); + } + else if (stricmp(argv[1], "pause") == 0) + { + if (argv.argc() == 2) + { + Printf ("Current GC pause is %d\n", GC::Pause); + } + else + { + GC::Pause = max(1,atoi(argv[2])); + } + } + else if (stricmp(argv[1], "stepmul") == 0) + { + if (argv.argc() == 2) + { + Printf ("Current GC stepmul is %d\n", GC::StepMul); + } + else + { + GC::StepMul = max(100, atoi(argv[2])); + } + } +} + diff --git a/src/common/objects/dobjgc.h b/src/common/objects/dobjgc.h new file mode 100644 index 00000000000..f5514255dba --- /dev/null +++ b/src/common/objects/dobjgc.h @@ -0,0 +1,328 @@ +#pragma once +#include +#include "tarray.h" +class DObject; +class FSerializer; + +enum EObjectFlags +{ + // GC flags + OF_White0 = 1 << 0, // Object is white (type 0) + OF_White1 = 1 << 1, // Object is white (type 1) + OF_Black = 1 << 2, // Object is black + OF_Fixed = 1 << 3, // Object is fixed (should not be collected) + OF_Rooted = 1 << 4, // Object is soft-rooted + OF_EuthanizeMe = 1 << 5, // Object wants to die + OF_Cleanup = 1 << 6, // Object is now being deleted by the collector + OF_YesReallyDelete = 1 << 7, // Object is being deleted outside the collector, and this is okay, so don't print a warning + + OF_WhiteBits = OF_White0 | OF_White1, + OF_MarkBits = OF_WhiteBits | OF_Black, + + // Other flags + OF_JustSpawned = 1 << 8, // Thinker was spawned this tic + OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls + OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list + OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk) + OF_Spawned = 1 << 12, // Thinker was spawned at all (some thinkers get deleted before spawning) + OF_Released = 1 << 13, // Object was released from the GC system and should not be processed by GC function + OF_Networked = 1 << 14, // Object has a unique network identifier that makes it synchronizable between all clients. +}; + +template class TObjPtr; + +namespace GC +{ + enum EGCState + { + GCS_Pause, + GCS_Propagate, + GCS_Sweep, + GCS_Destroy, + GCS_Done, + + GCS_COUNT + }; + + // Number of bytes currently allocated through M_Malloc/M_Realloc. + extern size_t AllocBytes; + + // Number of bytes allocated since last collection step. + extern size_t RunningAllocBytes; + + // Number of bytes freed since last collection step. + extern size_t RunningDeallocBytes; + + // Amount of memory to allocate before triggering a collection. + extern size_t Threshold; + + // List of gray objects. + extern DObject *Gray; + + // List of every object. + extern DObject *Root; + + // Current white value for potentially-live objects. + extern uint32_t CurrentWhite; + + // Current collector state. + extern EGCState State; + + // Position of GC sweep in the list of objects. + extern DObject **SweepPos; + + // Size of GC pause. + extern int Pause; + + // Size of GC steps. + extern int StepMul; + + // Is this the final collection just before exit? + extern bool FinalGC; + + // Current white value for known-dead objects. + static inline uint32_t OtherWhite() + { + return CurrentWhite ^ OF_WhiteBits; + } + + // Does one collection step. + void Step(); + + // Does a complete collection. + void FullGC(); + + // Handles the grunt work for a write barrier. + void Barrier(DObject *pointing, DObject *pointed); + + // Handles a write barrier. + static inline void WriteBarrier(DObject *pointing, DObject *pointed); + + // Handles a write barrier for a pointer that isn't inside an object. + static inline void WriteBarrier(DObject *pointed); + + // Handles a read barrier. + template inline T *ReadBarrier(T *&obj) + { + if (obj == NULL || !(obj->ObjectFlags & OF_EuthanizeMe)) + { + return obj; + } + return obj = NULL; + } + + // Handles a read barrier for a const pointer. This does not alter the source data, but only returns NULL if the object is destroyed. + template inline T* ReadBarrier(const T*& obj) + { + if (obj == NULL || !(obj->ObjectFlags & OF_EuthanizeMe)) + { + return obj; + } + return NULL; + } + + // Check if it's time to collect, and do a collection step if it is. + void CheckGC(); + + // Forces a collection to start now. + static inline void StartCollection() + { + Threshold = AllocBytes; + } + + // Marks a white object gray. If the object wants to die, the pointer + // is NULLed instead. + void Mark(DObject **obj); + + // Marks an array of objects. + void MarkArray(DObject **objs, size_t count); + + // For cleanup + void DelSoftRootHead(); + + // Soft-roots an object. + void AddSoftRoot(DObject *obj); + + // Unroots an object. + void DelSoftRoot(DObject *obj); + + template void Mark(T *&obj) + { + union + { + T *t; + DObject *o; + }; + o = obj; + Mark(&o); + obj = t; + } + template void Mark(TObjPtr &obj); + + template void MarkArray(T **obj, size_t count) + { + MarkArray((DObject **)(obj), count); + } + template void MarkArray(TObjPtr* obj, size_t count) + { + MarkArray((DObject**)(obj), count); + } + template void MarkArray(TArray &arr) + { + MarkArray(&arr[0], arr.Size()); + } + + using GCMarkerFunc = void(*)(); + void AddMarkerFunc(GCMarkerFunc func); + + // Report an allocation to the GC + static inline void ReportAlloc(size_t alloc) + { + AllocBytes += alloc; + RunningAllocBytes += alloc; + } + + // Report a deallocation to the GC + static inline void ReportDealloc(size_t dealloc) + { + AllocBytes -= dealloc; + RunningDeallocBytes += dealloc; + } + + // Report a reallocation to the GC + static inline void ReportRealloc(size_t oldsize, size_t newsize) + { + if (oldsize < newsize) + { + ReportAlloc(newsize - oldsize); + } + else + { + ReportDealloc(oldsize - newsize); + } + } +} + +// A template class to help with handling read barriers. It does not +// handle write barriers, because those can be handled more efficiently +// with knowledge of the object that holds the pointer. +template +class TObjPtr +{ + union + { + mutable T pp; + mutable DObject *o; + }; +public: + + constexpr TObjPtr& operator=(T q) noexcept + { + pp = q; + return *this; + } + + constexpr TObjPtr& operator=(std::nullptr_t nul) noexcept + { + o = nullptr; + return *this; + } + + // To allow NULL, too. + TObjPtr& operator=(const int val) noexcept + { + assert(val == 0); + o = nullptr; + return *this; + } + + // To allow NULL, too. In Clang NULL is a long. + TObjPtr& operator=(const long val) noexcept + { + assert(val == 0); + o = nullptr; + return *this; + } + + constexpr T Get() noexcept + { + return GC::ReadBarrier(pp); + } + + constexpr T Get() const noexcept + { + auto ppp = pp; + return GC::ReadBarrier(ppp); + } + + constexpr T ForceGet() const noexcept //for situations where the read barrier needs to be skipped. + { + return pp; + } + + constexpr operator T() noexcept + { + return GC::ReadBarrier(pp); + } + constexpr T &operator*() noexcept + { + T q = GC::ReadBarrier(pp); + assert(q != NULL); + return *q; + } + constexpr T operator->() noexcept + { + return GC::ReadBarrier(pp); + } + + constexpr const T operator->() const noexcept + { + return GC::ReadBarrier(pp); + } + + constexpr bool operator!=(T u) const noexcept + { + return GC::ReadBarrier(o) != u; + } + constexpr bool operator==(T u) const noexcept + { + return GC::ReadBarrier(o) == u; + } + + constexpr bool operator==(TObjPtr u) const noexcept + { + return ForceGet() == u.ForceGet(); + } + + template friend inline void GC::Mark(TObjPtr &obj); + template friend FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, TObjPtr *); + template friend FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, U *); + + friend class DObject; +}; + +// This is only needed because some parts of GCC do not treat a class with any constructor as trivial. +// TObjPtr needs to be fully trivial, though - some parts in the engine depend on it. +template +constexpr TObjPtr MakeObjPtr(T t) noexcept +{ + // since this exists to replace the constructor we cannot initialize in the declaration as this would require the constructor we want to avoid. + TObjPtr tt; + tt = t; + return tt; +} + +// Use barrier_cast instead of static_cast when you need to cast +// the contents of a TObjPtr to a related type. +template inline T barrier_cast(TObjPtr &o) +{ + return static_cast(static_cast(o)); +} + +namespace GC +{ + template inline void Mark(TObjPtr &obj) + { + GC::Mark(&obj.o); + } +} diff --git a/src/dobjtype.cpp b/src/common/objects/dobjtype.cpp similarity index 78% rename from src/dobjtype.cpp rename to src/common/objects/dobjtype.cpp index 53fe6829113..0d1bfdf9a87 100644 --- a/src/dobjtype.cpp +++ b/src/common/objects/dobjtype.cpp @@ -39,23 +39,19 @@ #include "dobject.h" #include "serializer.h" -#include "actor.h" #include "autosegs.h" #include "v_text.h" -#include "a_pickups.h" -#include "d_player.h" -#include "fragglescript/t_fs.h" -#include "a_keys.h" +#include "c_cvars.h" #include "vm.h" +#include "symbols.h" #include "types.h" -#include "scriptutil.h" -#include "i_system.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- +bool AreCompatiblePointerTypes(PType* dest, PType* source, bool forcompare = false); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -77,14 +73,14 @@ bool PClass::bVMOperational; // that does not work anymore. WP_NOCHANGE needs to point to a vaild object to work as intended. // This Object does not need to be garbage collected, though, but it needs to provide the proper structure so that the // GC can process it. -AActor *WP_NOCHANGE; +DObject *WP_NOCHANGE; DEFINE_GLOBAL(WP_NOCHANGE); // PRIVATE DATA DEFINITIONS ------------------------------------------------ // A harmless non-nullptr FlatPointer for classes without pointers. -static const size_t TheEnd = ~(size_t)0; +static const std::pair TheEnd = {~(size_t)0 , nullptr}; //========================================================================== // @@ -191,11 +187,11 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const // //========================================================================== -static int cregcmp (const void *a, const void *b) NO_SANITIZE +static NO_SANITIZE_M int cregcmp (const void *a, const void *b) NO_SANITIZE { const PClass *class1 = *(const PClass **)a; const PClass *class2 = *(const PClass **)b; - return strcmp(class1->TypeName, class2->TypeName); + return strcmp(class1->TypeName.GetChars(), class2->TypeName.GetChars()); } //========================================================================== @@ -210,20 +206,10 @@ void PClass::StaticInit () { Namespaces.GlobalNamespace = Namespaces.NewNamespace(0); - FAutoSegIterator probe(CRegHead, CRegTail); - - while (*++probe != nullptr) - { - ((ClassReg *)*probe)->RegisterClass (); - } - probe.Reset(); - for(auto cls : AllClasses) + AutoSegs::TypeInfos.ForEach([](ClassReg* typeInfo) { - if (cls->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - PClassActor::AllActorClasses.Push(static_cast(cls)); - } - } + typeInfo->RegisterClass(); + }); // Keep built-in classes in consistant order. I did this before, though // I'm not sure if this is really necessary to maintain any sort of sync. @@ -231,7 +217,7 @@ void PClass::StaticInit () // WP_NOCHANGE must point to a valid object, although it does not need to be a weapon. // A simple DObject is enough to give the GC the ability to deal with it, if subjected to it. - WP_NOCHANGE = (AActor*)Create(); + WP_NOCHANGE = Create(); WP_NOCHANGE->Release(); } @@ -243,6 +229,8 @@ void PClass::StaticInit () // //========================================================================== +void ClearServices(); + void PClass::StaticShutdown () { if (WP_NOCHANGE != nullptr) @@ -250,27 +238,24 @@ void PClass::StaticShutdown () delete WP_NOCHANGE; } + ClearServices(); // delete all variables containing pointers to script functions. for (auto p : FunctionPtrList) { *p = nullptr; } - ScriptUtil::Clear(); FunctionPtrList.Clear(); VMFunction::DeleteAll(); + // From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now. + // This flags DObject::Destroy not to call any scripted OnDestroy methods anymore. + bVMOperational = false; // Make a full garbage collection here so that all destroyed but uncollected higher level objects // that still exist are properly taken down before the low level data is deleted. GC::FullGC(); + GC::FullGC(); - // From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now. - // This flags DObject::Destroy not to call any scripted OnDestroy methods anymore. - bVMOperational = false; - for (auto &p : players) - { - p.PendingWeapon = nullptr; - } Namespaces.ReleaseSymbols(); // This must be done in two steps because the native classes are not ordered by inheritance, @@ -282,17 +267,12 @@ void PClass::StaticShutdown () TypeTable.Clear(); ClassDataAllocator.FreeAllBlocks(); AllClasses.Clear(); - PClassActor::AllActorClasses.Clear(); ClassMap.Clear(); - FAutoSegIterator probe(CRegHead, CRegTail); - - while (*++probe != nullptr) + AutoSegs::TypeInfos.ForEach([](ClassReg* typeInfo) { - auto cr = ((ClassReg *)*probe); - cr->MyClass = nullptr; - } - + typeInfo->MyClass = nullptr; + }); } //========================================================================== @@ -393,10 +373,6 @@ void PClass::InsertIntoHash (bool native) { ClassMap[TypeName] = this; } - if (!native && IsDescendantOf(RUNTIME_CLASS(AActor))) - { - PClassActor::AllActorClasses.Push(static_cast(this)); - } } //========================================================================== @@ -456,12 +432,16 @@ DObject *PClass::CreateNew() else memset (mem, 0, Size); - if (ConstructNative == nullptr) + if (ConstructNative == nullptr || bAbstract) { M_Free(mem); I_Error("Attempt to instantiate abstract class %s.", TypeName.GetChars()); } ConstructNative (mem); + + if (Defaults != nullptr) + ((DObject *)mem)->ObjectFlags |= ((DObject *)Defaults)->ObjectFlags & OF_Transient; + ((DObject *)mem)->SetClass (const_cast(this)); InitializeSpecials(mem, Defaults, &PClass::SpecialInits); return (DObject *)mem; @@ -548,90 +528,6 @@ void PClass::Derive(PClass *newclass, FName name) } -//========================================================================== -// -// PClassActor :: InitializeNativeDefaults -// -//========================================================================== - -void PClass::InitializeDefaults() -{ - if (IsDescendantOf(RUNTIME_CLASS(AActor))) - { - assert(Defaults == nullptr); - Defaults = (uint8_t *)M_Malloc(Size); - - ConstructNative(Defaults); - // We must unlink the defaults from the class list because it's just a static block of data to the engine. - DObject *optr = (DObject*)Defaults; - GC::Root = optr->ObjNext; - optr->ObjNext = nullptr; - optr->SetClass(this); - - // Copy the defaults from the parent but leave the DObject part alone because it contains important data. - if (ParentClass->Defaults != nullptr) - { - memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject)); - if (Size > ParentClass->Size) - { - memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size); - } - } - else - { - memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject)); - } - - assert(MetaSize >= ParentClass->MetaSize); - if (MetaSize != 0) - { - Meta = (uint8_t*)M_Malloc(MetaSize); - - // Copy the defaults from the parent but leave the DObject part alone because it contains important data. - if (ParentClass->Meta != nullptr) - { - memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); - if (MetaSize > ParentClass->MetaSize) - { - memset(Meta + ParentClass->MetaSize, 0, MetaSize - ParentClass->MetaSize); - } - } - else - { - memset(Meta, 0, MetaSize); - } - - if (MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); - else memset(Meta, 0, MetaSize); - } - } - - if (VMType != nullptr) // purely internal classes have no symbol table - { - if (bRuntimeClass) - { - // Copy parent values from the parent defaults. - assert(ParentClass != nullptr); - if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); - for (const PField *field : Fields) - { - if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) - { - field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); - } - } - } - if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); - for (const PField *field : Fields) - { - if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) - { - field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); - } - } - } -} - //========================================================================== // // PClass :: CreateDerivedClass @@ -640,7 +536,7 @@ void PClass::InitializeDefaults() // //========================================================================== -PClass *PClass::CreateDerivedClass(FName name, unsigned int size) +PClass *PClass::CreateDerivedClass(FName name, unsigned int size, bool *newlycreated, int fileno) { assert(size >= Size); PClass *type; @@ -648,6 +544,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) const PClass *existclass = FindClass(name); + if (newlycreated) *newlycreated = false; if (existclass != nullptr) { // This is a placeholder so fill it in @@ -679,8 +576,8 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->Size = size; if (size != TentativeClass) { - NewClassType(type); - type->InitializeDefaults(); + NewClassType(type, fileno); + if (newlycreated) *newlycreated = true; type->Virtuals = Virtuals; } else @@ -699,13 +596,13 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) // //========================================================================== -PField *PClass::AddField(FName name, PType *type, uint32_t flags) +PField *PClass::AddField(FName name, PType *type, uint32_t flags, int fileno) { PField *field; if (!(flags & VARF_Meta)) { unsigned oldsize = Size; - field = VMType->Symbols.AddField(name, type, flags, Size); + field = VMType->Symbols.AddField(name, type, flags, Size, nullptr, fileno); // Only initialize the defaults if they have already been created. // For ZScript this is not the case, it will first define all fields before @@ -720,7 +617,7 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) { // Same as above, but a different data storage. unsigned oldsize = MetaSize; - field = VMType->Symbols.AddField(name, type, flags, MetaSize); + field = VMType->Symbols.AddField(name, type, flags, MetaSize, nullptr, fileno); if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) { @@ -770,7 +667,9 @@ PClass *PClass::FindClassTentative(FName name) // //========================================================================== -int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc) +bool ShouldAllowGameSpecificVirtual(FName name, unsigned index, PType* arg, PType* varg); + +int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc, bool exactReturnType, bool ignorePointerReadOnly) { auto proto = variant->Proto; for (unsigned i = 0; i < Virtuals.Size(); i++) @@ -790,15 +689,32 @@ int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction { if (proto->ArgumentTypes[a] != vproto->ArgumentTypes[a]) { - fail = true; - break; + if(ignorePointerReadOnly && proto->ArgumentTypes[a]->isPointer() && vproto->ArgumentTypes[a]->isPointer()) + { + PPointer *ppa = proto->ArgumentTypes[a]->toPointer(); + PPointer *ppb = vproto->ArgumentTypes[a]->toPointer(); + + if(ppa->PointedType != ppb->PointedType) + { + fail = true; + break; + } + } + else if(!ShouldAllowGameSpecificVirtual(name, a, proto->ArgumentTypes[a], vproto->ArgumentTypes[a])) + { + fail = true; + break; + } } } if (fail) continue; for (unsigned a = 0; a < proto->ReturnTypes.Size(); a++) { - if (proto->ReturnTypes[a] != vproto->ReturnTypes[a]) + PType* expected = vproto->ReturnTypes[a]; + PType* actual = proto->ReturnTypes[a]; + + if (expected != actual && (exactReturnType || !AreCompatiblePointerTypes(expected, actual))) { fail = true; break; @@ -814,13 +730,17 @@ int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction if (!(parentfunc->Variants[0].ArgFlags[a] & VARF_Optional)) return -1; } - // Todo: extend the prototype + // Extend the prototype + TArray argumentTypes = proto->ArgumentTypes; + for (unsigned a = proto->ArgumentTypes.Size(); a < vproto->ArgumentTypes.Size(); a++) { - proto->ArgumentTypes.Push(vproto->ArgumentTypes[a]); + argumentTypes.Push(vproto->ArgumentTypes[a]); variant->ArgFlags.Push(parentfunc->Variants[0].ArgFlags[a]); variant->ArgNames.Push(NAME_None); } + + variant->Proto = NewPrototype(proto->ReturnTypes, argumentTypes); } return i; } @@ -846,75 +766,81 @@ PSymbol *PClass::FindSymbol(FName symname, bool searchparents) const // //========================================================================== -void PClass::BuildFlatPointers () +void PClass::BuildFlatPointers() const { + using pairType = std::pair; + if (FlatPointers != nullptr) { // Already built: Do nothing. return; } - else if (ParentClass == nullptr) - { // No parent (i.e. DObject: FlatPointers is the same as Pointers. - if (Pointers == nullptr) - { // No pointers: Make FlatPointers a harmless non-nullptr. - FlatPointers = &TheEnd; - } - else - { - FlatPointers = Pointers; - } - } else { - ParentClass->BuildFlatPointers (); - - TArray ScriptPointers; - - // Collect all pointers in scripted fields. These are not part of the Pointers list. - for (auto field : Fields) + TArray NativePointers; + if (Pointers != nullptr) { - if (!(field->Flags & VARF_Native)) + for (size_t i = 0; Pointers[i] != ~(size_t)0; i++) { - field->Type->SetPointer(Defaults, unsigned(field->Offset), &ScriptPointers); + NativePointers.Push({Pointers[i], nullptr}); // native pointers have a null type } } - if (Pointers == nullptr && ScriptPointers.Size() == 0) - { // No new pointers: Just use the same FlatPointers as the parent. - FlatPointers = ParentClass->FlatPointers; + if (ParentClass == nullptr) + { // No parent (i.e. DObject): FlatPointers is the same as Pointers. + if (NativePointers.Size() == 0) + { // No pointers: Make FlatPointers a harmless non-nullptr. + FlatPointers = (pairType*)(&TheEnd); + FlatPointersSize = 0; + } + else + { + pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * NativePointers.Size()); + memcpy(flat, NativePointers.Data(), sizeof(pairType) * NativePointers.Size()); + + FlatPointers = flat; + FlatPointersSize = NativePointers.Size(); + } } else - { // New pointers: Create a new FlatPointers array and add them. - int numPointers, numSuperPointers; + { + ParentClass->BuildFlatPointers(); - if (Pointers != nullptr) + TArray ScriptPointers; + + // Collect all pointers in scripted fields. These are not part of the Pointers list. + for (auto field : Fields) { - // Count pointers defined by this class. - for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++) + if (!(field->Flags & VARF_Native)) { + field->Type->SetPointer(Defaults, unsigned(field->Offset), &ScriptPointers); } } - else numPointers = 0; - - // Count pointers defined by superclasses. - for (numSuperPointers = 0; ParentClass->FlatPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++) - { } - // Concatenate them into a new array - size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); - if (numSuperPointers > 0) - { - memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); - } - if (numPointers > 0) - { - memcpy(flat + numSuperPointers, Pointers, sizeof(size_t)*numPointers); + if (NativePointers.Size() == 0 && ScriptPointers.Size() == 0) + { // No new pointers: Just use the same FlatPointers as the parent. + FlatPointers = ParentClass->FlatPointers; + FlatPointersSize = ParentClass->FlatPointersSize; } - if (ScriptPointers.Size() > 0) - { - memcpy(flat + numSuperPointers + numPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size()); + else + { // New pointers: Create a new FlatPointers array and add them. + // Concatenate them into a new array + pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->FlatPointersSize + NativePointers.Size() + ScriptPointers.Size())); + + if (ParentClass->FlatPointersSize > 0) + { + memcpy (flat, ParentClass->FlatPointers, sizeof(pairType) * ParentClass->FlatPointersSize); + } + if (NativePointers.Size() > 0) + { + memcpy(flat + ParentClass->FlatPointersSize, NativePointers.Data(), sizeof(pairType) * NativePointers.Size()); + } + if (ScriptPointers.Size() > 0) + { + memcpy(flat + ParentClass->FlatPointersSize + NativePointers.Size(), &ScriptPointers[0], sizeof(pairType) * ScriptPointers.Size()); + } + FlatPointers = flat; + FlatPointersSize = ParentClass->FlatPointersSize + NativePointers.Size() + ScriptPointers.Size(); } - flat[numSuperPointers + numPointers + ScriptPointers.Size()] = ~(size_t)0; - FlatPointers = flat; } } } @@ -927,21 +853,24 @@ void PClass::BuildFlatPointers () // //========================================================================== -void PClass::BuildArrayPointers() +void PClass::BuildArrayPointers() const { + using pairType = std::pair; + if (ArrayPointers != nullptr) { // Already built: Do nothing. return; } else if (ParentClass == nullptr) - { // No parent (i.e. DObject: FlatPointers is the same as Pointers. - ArrayPointers = &TheEnd; + { // No parent (i.e. DObject): Make ArrayPointers a harmless non-nullptr. + ArrayPointers = (pairType*)(&TheEnd); + ArrayPointersSize = 0; } else { ParentClass->BuildArrayPointers(); - TArray ScriptPointers; + TArray ScriptPointers; // Collect all arrays to pointers in scripted fields. for (auto field : Fields) @@ -955,28 +884,84 @@ void PClass::BuildArrayPointers() if (ScriptPointers.Size() == 0) { // No new pointers: Just use the same ArrayPointers as the parent. ArrayPointers = ParentClass->ArrayPointers; + ArrayPointersSize = ParentClass->ArrayPointersSize; } else - { // New pointers: Create a new FlatPointers array and add them. - int numSuperPointers; + { // New pointers: Create a new ArrayPointers array and add them. + // Concatenate them into a new array + pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->ArrayPointersSize + ScriptPointers.Size())); + if (ParentClass->ArrayPointersSize > 0) + { + memcpy(flat, ParentClass->ArrayPointers, sizeof(pairType) * ParentClass->ArrayPointersSize); + } - // Count pointers defined by superclasses. - for (numSuperPointers = 0; ParentClass->ArrayPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++) + if (ScriptPointers.Size() > 0) { + memcpy(flat + ParentClass->ArrayPointersSize, ScriptPointers.Data(), sizeof(pairType) * ScriptPointers.Size()); } + ArrayPointers = flat; + ArrayPointersSize = ParentClass->ArrayPointersSize + ScriptPointers.Size(); + } + } +} + +//========================================================================== +// +// PClass :: BuildMapPointers +// +// same as above, but creates a list to dynamic object arrays +// +//========================================================================== + +void PClass::BuildMapPointers() const +{ + using pairType = std::pair; + + if (MapPointers != nullptr) + { // Already built: Do nothing. + return; + } + else if (ParentClass == nullptr) + { // No parent (i.e. DObject): Make MapPointers a harmless non-nullptr. + MapPointers = (pairType*)(&TheEnd); + MapPointersSize = 0; + } + else + { + ParentClass->BuildMapPointers(); + + TArray ScriptPointers; + + // Collect all arrays to pointers in scripted fields. + for (auto field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetPointerMap(Defaults, unsigned(field->Offset), &ScriptPointers); + } + } + + if (ScriptPointers.Size() == 0) + { // No new pointers: Just use the same ArrayPointers as the parent. + MapPointers = ParentClass->MapPointers; + MapPointersSize = ParentClass->MapPointersSize; + } + else + { // New pointers: Create a new FlatPointers array and add them. // Concatenate them into a new array - size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); - if (numSuperPointers > 0) + pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->MapPointersSize + ScriptPointers.Size())); + if (ParentClass->MapPointersSize > 0) { - memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers); + memcpy(flat, ParentClass->MapPointers, sizeof(pairType) * ParentClass->MapPointersSize); } + if (ScriptPointers.Size() > 0) { - memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size()); + memcpy(flat + ParentClass->MapPointersSize, ScriptPointers.Data(), sizeof(pairType) * ScriptPointers.Size()); } - flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0; - ArrayPointers = flat; + MapPointers = flat; + MapPointersSize = ParentClass->MapPointersSize + ScriptPointers.Size(); } } } @@ -1027,3 +1012,31 @@ unsigned GetVirtualIndex(PClass *cls, const char *funcname) return VIndex; } + +void PClass::InitializeDefaults() +{ + if (VMType != nullptr) // purely internal classes have no symbol table + { + if (bRuntimeClass) + { + // Copy parent values from the parent defaults. + assert(ParentClass != nullptr); + if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); + for (const PField* field : Fields) + { + if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) + { + field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); + } + } + } + if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); + for (const PField* field : Fields) + { + if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) + { + field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); + } + } + } +} diff --git a/src/dobjtype.h b/src/common/objects/dobjtype.h similarity index 75% rename from src/dobjtype.h rename to src/common/objects/dobjtype.h index 3445e02baab..62e6f5ccc5d 100644 --- a/src/dobjtype.h +++ b/src/common/objects/dobjtype.h @@ -5,6 +5,8 @@ #error You must #include "dobject.h" to get dobjtype.h #endif +#include + typedef std::pair FTypeAndOffset; #if 0 @@ -17,14 +19,17 @@ class VMException : public DObject // An action function ------------------------------------------------------- -struct FState; -struct StateCallData; class VMFrameStack; struct VMValue; struct VMReturn; class VMFunction; class PClassType; struct FNamespaceManager; +class PSymbol; +class PField; +class PObjectPointer; +class PDynArray; +class PMap; enum { @@ -36,24 +41,30 @@ class PClass { protected: void Derive(PClass *newclass, FName name); - void InitializeSpecials(void *addr, void *defaults, TArray PClass::*Inits); void SetSuper(); public: + void InitializeSpecials(void* addr, void* defaults, TArray PClass::* Inits); void WriteAllFields(FSerializer &ar, const void *addr) const; bool ReadAllFields(FSerializer &ar, void *addr) const; - void InitializeDefaults(); - int FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc); + int FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc, bool exactReturnType, bool ignorePointerReadOnly); PSymbol *FindSymbol(FName symname, bool searchparents) const; - PField *AddField(FName name, PType *type, uint32_t flags); + PField *AddField(FName name, PType *type, uint32_t flags, int fileno = 0); + void InitializeDefaults(); static void StaticInit(); static void StaticShutdown(); // Per-class information ------------------------------------- PClass *ParentClass = nullptr; // the class this class derives from - const size_t *Pointers = nullptr; // object pointers defined by this class *only* - const size_t *FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default - const size_t *ArrayPointers = nullptr; // dynamic arrays containing object pointers. + const size_t * Pointers = nullptr; // native object pointers defined by this class *only* + + mutable size_t FlatPointersSize = 0; + mutable const std::pair * FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default. + mutable size_t ArrayPointersSize = 0; + mutable const std::pair * ArrayPointers = nullptr; // dynamic arrays containing object pointers. + mutable size_t MapPointersSize = 0; + mutable const std::pair * MapPointers = nullptr; // maps containing object pointers. + uint8_t *Defaults = nullptr; uint8_t *Meta = nullptr; // Per-class static script data unsigned Size = sizeof(DObject); @@ -63,11 +74,14 @@ class PClass bool bRuntimeClass = false; // class was defined at run-time, not compile-time bool bDecorateClass = false; // may be subject to some idiosyncracies due to DECORATE backwards compatibility bool bAbstract = false; + bool bSealed = false; + bool bFinal = false; bool bOptional = false; TArray Virtuals; // virtual function table TArray MetaInits; TArray SpecialInits; TArray Fields; + TArray SealedRestriction; PClassType *VMType = nullptr; void (*ConstructNative)(void *); @@ -77,11 +91,14 @@ class PClass ~PClass(); void InsertIntoHash(bool native); DObject *CreateNew(); - PClass *CreateDerivedClass(FName name, unsigned int size); + PClass *CreateDerivedClass(FName name, unsigned int size, bool *newlycreated = nullptr, int fileno = 0); void InitializeActorInfo(); - void BuildFlatPointers(); - void BuildArrayPointers(); + + void BuildFlatPointers() const; + void BuildArrayPointers() const; + void BuildMapPointers() const; + void DestroySpecials(void *addr); void DestroyMeta(void *addr); const PClass *NativeClass() const; diff --git a/src/posix/cocoa/gl_sysfb.h b/src/common/platform/posix/cocoa/gl_sysfb.h similarity index 100% rename from src/posix/cocoa/gl_sysfb.h rename to src/common/platform/posix/cocoa/gl_sysfb.h diff --git a/src/posix/cocoa/i_common.h b/src/common/platform/posix/cocoa/i_common.h similarity index 100% rename from src/posix/cocoa/i_common.h rename to src/common/platform/posix/cocoa/i_common.h diff --git a/src/posix/cocoa/i_input.mm b/src/common/platform/posix/cocoa/i_input.mm similarity index 81% rename from src/posix/cocoa/i_input.mm rename to src/common/platform/posix/cocoa/i_input.mm index 261f5e98b0e..46b380431ef 100644 --- a/src/posix/cocoa/i_input.mm +++ b/src/common/platform/posix/cocoa/i_input.mm @@ -38,41 +38,25 @@ #include "c_console.h" #include "c_cvars.h" #include "c_dispatch.h" -#include "d_event.h" +#include "d_eventbase.h" +#include "c_buttons.h" #include "d_gui.h" #include "dikeys.h" -#include "doomdef.h" -#include "doomstat.h" #include "v_video.h" -#include "events.h" -#include "g_game.h" -#include "g_levellocals.h" +#include "i_interface.h" +#include "menustate.h" +#include "engineerrors.h" +#include "keydef.h" EXTERN_CVAR(Int, m_use_mouse) CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) -{ - if (self < 0) - { - self = 0; - } - else if (self > 2) - { - self = 2; - } -} - - -extern int paused, chatmodeon; -extern constate_e ConsoleState; - +extern int paused; +extern bool ToggleFullscreen; bool GUICapture; @@ -88,22 +72,17 @@ void CheckGUICapture() { - bool wantCapture = (MENU_Off == menuactive) - ? (c_down == ConsoleState || c_falling == ConsoleState || chatmodeon) - : (MENU_On == menuactive || MENU_OnNoPause == menuactive); + bool wantCapt = sysCallbacks.WantGuiCapture && sysCallbacks.WantGuiCapture(); - // [ZZ] check active event handlers that want the UI processing - if (!wantCapture && primaryLevel->localEventManager->CheckUiProcessors()) + if (wantCapt != GUICapture) { - wantCapture = true; + GUICapture = wantCapt; + if (wantCapt) + { + buttonMap.ResetButtonStates(); + } } - if (wantCapture != GUICapture) - { - GUICapture = wantCapture; - - ResetButtonStates(); - } } void SetCursorPosition(const NSPoint position) @@ -152,24 +131,6 @@ void CenterCursor() SetCursorPosition(centerPoint); } -bool IsInGame() -{ - switch (mouse_capturemode) - { - default: - case 0: - return gamestate == GS_LEVEL; - - case 1: - return gamestate == GS_LEVEL - || gamestate == GS_INTERMISSION - || gamestate == GS_FINALE; - - case 2: - return true; - } -} - void CheckNativeMouse() { const bool windowed = (NULL == screen) || !screen->IsFullscreen(); @@ -187,8 +148,9 @@ void CheckNativeMouse() } else { + bool captureModeInGame = sysCallbacks.CaptureModeInGame && sysCallbacks.CaptureModeInGame(); wantNative = (!m_use_mouse || MENU_WaitKey != menuactive) - && (!IsInGame() || GUICapture || paused || demoplayback); + && (!captureModeInGame || GUICapture); } } else @@ -198,7 +160,7 @@ void CheckNativeMouse() && (MENU_On == menuactive || MENU_OnNoPause == menuactive); } - if (!wantNative && primaryLevel->localEventManager->CheckRequireMouse()) + if (!wantNative && sysCallbacks.WantNativeMouse && sysCallbacks.WantNativeMouse()) wantNative = true; I_SetNativeMouse(wantNative); @@ -321,11 +283,11 @@ uint8_t ModifierToDIK(const uint32_t modifier) { switch (modifier) { - case NSAlphaShiftKeyMask: return DIK_CAPITAL; - case NSShiftKeyMask: return DIK_LSHIFT; - case NSControlKeyMask: return DIK_LCONTROL; - case NSAlternateKeyMask: return DIK_LMENU; - case NSCommandKeyMask: return DIK_LWIN; + case NSEventModifierFlagCapsLock: return DIK_CAPITAL; + case NSEventModifierFlagShift: return DIK_LSHIFT; + case NSEventModifierFlagControl: return DIK_LCONTROL; + case NSEventModifierFlagOption: return DIK_LMENU; + case NSEventModifierFlagCommand: return DIK_LWIN; } return 0; @@ -333,20 +295,20 @@ uint8_t ModifierToDIK(const uint32_t modifier) int16_t ModifierFlagsToGUIKeyModifiers(NSEvent* theEvent) { - const NSUInteger modifiers([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask); - return ((modifiers & NSShiftKeyMask ) ? GKM_SHIFT : 0) - | ((modifiers & NSControlKeyMask ) ? GKM_CTRL : 0) - | ((modifiers & NSAlternateKeyMask) ? GKM_ALT : 0) - | ((modifiers & NSCommandKeyMask ) ? GKM_META : 0); + const NSUInteger modifiers([theEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask); + return ((modifiers & NSEventModifierFlagShift ) ? GKM_SHIFT : 0) + | ((modifiers & NSEventModifierFlagControl) ? GKM_CTRL : 0) + | ((modifiers & NSEventModifierFlagOption ) ? GKM_ALT : 0) + | ((modifiers & NSEventModifierFlagCommand) ? GKM_META : 0); } bool ShouldGenerateGUICharEvent(NSEvent* theEvent) { - const NSUInteger modifiers([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask); - return !(modifiers & NSControlKeyMask) - && !(modifiers & NSAlternateKeyMask) - && !(modifiers & NSCommandKeyMask) - && !(modifiers & NSFunctionKeyMask); + const NSUInteger modifiers([theEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask); + return !(modifiers & NSEventModifierFlagControl) + && !(modifiers & NSEventModifierFlagOption) + && !(modifiers & NSEventModifierFlagCommand) + && !(modifiers & NSEventModifierFlagFunction); } @@ -410,7 +372,7 @@ void ProcessKeyboardEventInMenu(NSEvent* theEvent) unichar realchar; event.type = EV_GUI_Event; - event.subtype = NSKeyDown == [theEvent type] ? EV_GUI_KeyDown : EV_GUI_KeyUp; + event.subtype = NSEventTypeKeyDown == [theEvent type] ? EV_GUI_KeyDown : EV_GUI_KeyUp; event.data2 = GetCharacterFromNSEvent(theEvent, &realchar); event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent); @@ -466,7 +428,7 @@ void ProcessKeyboardEventInMenu(NSEvent* theEvent) event.subtype = EV_GUI_Char; event.data1 = realchar; event.data2 = event.data3 & GKM_ALT; - + D_PostEvent(&event); } } @@ -523,43 +485,9 @@ void ProcessMouseMoveInMenu(NSEvent* theEvent) void ProcessMouseMoveInGame(NSEvent* theEvent) { int x([theEvent deltaX]); - int y(-[theEvent deltaY]); + int y([theEvent deltaY]); - if (0 == x && 0 == y) - { - return; - } - - if (!m_noprescale) - { - x *= 3; - y *= 2; - } - - event_t event = {}; - - static int lastX = 0, lastY = 0; - - if (m_filter) - { - event.x = (x + lastX) / 2; - event.y = (y + lastY) / 2; - } - else - { - event.x = x; - event.y = y; - } - - lastX = x; - lastY = y; - - if (0 != event.x || 0 != event.y) - { - event.type = EV_Mouse; - - D_PostEvent(&event); - } + PostMouseMove(x, y); } @@ -576,8 +504,8 @@ void ProcessKeyboardEvent(NSEvent* theEvent) if (k_allowfullscreentoggle && (kVK_ANSI_F == keyCode) - && (NSCommandKeyMask & [theEvent modifierFlags]) - && (NSKeyDown == [theEvent type]) + && (NSEventModifierFlagCommand & [theEvent modifierFlags]) + && (NSEventTypeKeyDown == [theEvent type]) && !isARepeat) { ToggleFullscreen = !ToggleFullscreen; @@ -592,7 +520,7 @@ void ProcessKeyboardEvent(NSEvent* theEvent) { event_t event = {}; - event.type = NSKeyDown == [theEvent type] ? EV_KeyDown : EV_KeyUp; + event.type = NSEventTypeKeyDown == [theEvent type] ? EV_KeyDown : EV_KeyUp; event.data1 = KEYCODE_TO_DIK[ keyCode ]; if (0 != event.data1) @@ -613,7 +541,7 @@ void ProcessKeyboardFlagsEvent(NSEvent* theEvent) } static const uint32_t FLAGS_MASK = - NSDeviceIndependentModifierFlagsMask & ~NSNumericPadKeyMask; + NSEventModifierFlagDeviceIndependentFlagsMask & ~NSEventModifierFlagNumericPad; const uint32_t modifiers = [theEvent modifierFlags] & FLAGS_MASK; static uint32_t oldModifiers = 0; @@ -682,12 +610,12 @@ void ProcessMouseButtonEvent(NSEvent* theEvent) switch (cocoaEventType) { - case NSLeftMouseDown: event.subtype = EV_GUI_LButtonDown; break; - case NSRightMouseDown: event.subtype = EV_GUI_RButtonDown; break; - case NSOtherMouseDown: event.subtype = EV_GUI_MButtonDown; break; - case NSLeftMouseUp: event.subtype = EV_GUI_LButtonUp; break; - case NSRightMouseUp: event.subtype = EV_GUI_RButtonUp; break; - case NSOtherMouseUp: event.subtype = EV_GUI_MButtonUp; break; + case NSEventTypeLeftMouseDown: event.subtype = EV_GUI_LButtonDown; break; + case NSEventTypeRightMouseDown: event.subtype = EV_GUI_RButtonDown; break; + case NSEventTypeOtherMouseDown: event.subtype = EV_GUI_MButtonDown; break; + case NSEventTypeLeftMouseUp: event.subtype = EV_GUI_LButtonUp; break; + case NSEventTypeRightMouseUp: event.subtype = EV_GUI_RButtonUp; break; + case NSEventTypeOtherMouseUp: event.subtype = EV_GUI_MButtonUp; break; default: break; } @@ -699,15 +627,15 @@ void ProcessMouseButtonEvent(NSEvent* theEvent) { switch (cocoaEventType) { - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: + case NSEventTypeLeftMouseDown: + case NSEventTypeRightMouseDown: + case NSEventTypeOtherMouseDown: event.type = EV_KeyDown; break; - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseUp: event.type = EV_KeyUp; break; @@ -715,7 +643,7 @@ void ProcessMouseButtonEvent(NSEvent* theEvent) break; } - event.data1 = MIN(KEY_MOUSE1 + [theEvent buttonNumber], NSInteger(KEY_MOUSE8)); + event.data1 = min(KEY_MOUSE1 + [theEvent buttonNumber], NSInteger(KEY_MOUSE8)); D_PostEvent(&event); } @@ -738,9 +666,9 @@ void ProcessMouseWheelEvent(NSEvent* theEvent) { return; } - + event_t event = {}; - + if (GUICapture) { event.type = EV_GUI_Event; @@ -752,7 +680,7 @@ void ProcessMouseWheelEvent(NSEvent* theEvent) event.type = isZeroDelta ? EV_KeyUp : EV_KeyDown; event.data1 = delta > 0.0f ? KEY_MWHEELUP : KEY_MWHEELDOWN; } - + D_PostEvent(&event); } @@ -765,36 +693,36 @@ void I_ProcessEvent(NSEvent* event) switch (eventType) { - case NSMouseMoved: + case NSEventTypeMouseMoved: ProcessMouseMoveEvent(event); break; - case NSLeftMouseDown: - case NSLeftMouseUp: - case NSRightMouseDown: - case NSRightMouseUp: - case NSOtherMouseDown: - case NSOtherMouseUp: + case NSEventTypeLeftMouseDown: + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseDown: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseDown: + case NSEventTypeOtherMouseUp: ProcessMouseButtonEvent(event); break; - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: + case NSEventTypeLeftMouseDragged: + case NSEventTypeRightMouseDragged: + case NSEventTypeOtherMouseDragged: ProcessMouseButtonEvent(event); ProcessMouseMoveEvent(event); break; - case NSScrollWheel: + case NSEventTypeScrollWheel: ProcessMouseWheelEvent(event); break; - case NSKeyDown: - case NSKeyUp: + case NSEventTypeKeyDown: + case NSEventTypeKeyUp: ProcessKeyboardEvent(event); break; - case NSFlagsChanged: + case NSEventTypeFlagsChanged: ProcessKeyboardFlagsEvent(event); break; diff --git a/src/common/platform/posix/cocoa/i_joystick.cpp b/src/common/platform/posix/cocoa/i_joystick.cpp new file mode 100644 index 00000000000..44d1fb961b3 --- /dev/null +++ b/src/common/platform/posix/cocoa/i_joystick.cpp @@ -0,0 +1,1265 @@ +/* + ** i_joystick.cpp + ** + **--------------------------------------------------------------------------- + ** Copyright 2012-2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. 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. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + **--------------------------------------------------------------------------- + ** + */ + +#include +#include +#include + +#include "d_eventbase.h" +#include "i_system.h" +#include "m_argv.h" +#include "m_joy.h" + +#include "v_text.h" +#include "printf.h" +#include "keydef.h" + + +EXTERN_CVAR(Bool, joy_axespolling) + + +namespace +{ + +FString ToFString(const CFStringRef string) +{ + if (NULL == string) + { + return FString(); + } + + const CFIndex stringLength = CFStringGetLength(string); + + if (0 == stringLength) + { + return FString(); + } + + const size_t bufferSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1; + + char buffer[bufferSize]; + memset(buffer, 0, bufferSize); + + CFStringGetCString(string, buffer, bufferSize, kCFStringEncodingUTF8); + + return FString(buffer); +} + + +// --------------------------------------------------------------------------- + + +class IOKitJoystick : public IJoystickConfig +{ +public: + explicit IOKitJoystick(io_object_t device); + virtual ~IOKitJoystick(); + + virtual FString GetName(); + virtual float GetSensitivity(); + virtual void SetSensitivity(float scale); + + virtual int GetNumAxes(); + virtual float GetAxisDeadZone(int axis); + virtual EJoyAxis GetAxisMap(int axis); + virtual const char* GetAxisName(int axis); + virtual float GetAxisScale(int axis); + + virtual void SetAxisDeadZone(int axis, float deadZone); + virtual void SetAxisMap(int axis, EJoyAxis gameAxis); + virtual void SetAxisScale(int axis, float scale); + + virtual bool IsSensitivityDefault(); + virtual bool IsAxisDeadZoneDefault(int axis); + virtual bool IsAxisMapDefault(int axis); + virtual bool IsAxisScaleDefault(int axis); + + virtual bool GetEnabled(); + virtual void SetEnabled(bool enabled); + + bool AllowsEnabledInBackground() { return false; } + bool GetEnabledInBackground() { return false; } + void SetEnabledInBackground(bool enabled) {} + + virtual void SetDefaultConfig(); + virtual FString GetIdentifier(); + + void AddAxes(float axes[NUM_JOYAXIS]) const; + + void Update(); + + void UseAxesPolling(bool axesPolling); + + io_object_t* GetNotificationPtr(); + +private: + IOHIDDeviceInterface** m_interface; + IOHIDQueueInterface** m_queue; + + FString m_name; + FString m_identifier; + + float m_sensitivity; + + struct AnalogAxis + { + IOHIDElementCookie cookie; + + char name[64]; + + float value; + + int32_t minValue; + int32_t maxValue; + + float deadZone; + float defaultDeadZone; + float sensitivity; + float defaultSensitivity; + + EJoyAxis gameAxis; + EJoyAxis defaultGameAxis; + + AnalogAxis() + { + memset(this, 0, sizeof *this); + } + }; + + TArray m_axes; + + struct DigitalButton + { + IOHIDElementCookie cookie; + int32_t value; + + explicit DigitalButton(const IOHIDElementCookie cookie) + : cookie(cookie) + , value(0) + { } + }; + + TArray m_buttons; + TArray m_POVs; + + bool m_enabled; + bool m_useAxesPolling; + + io_object_t m_notification; + + + static const float DEFAULT_DEADZONE; + static const float DEFAULT_SENSITIVITY; + + void ProcessAxes(); + bool ProcessAxis (const IOHIDEventStruct& event); + bool ProcessButton(const IOHIDEventStruct& event); + bool ProcessPOV (const IOHIDEventStruct& event); + + void GatherDeviceInfo(io_object_t device, CFDictionaryRef properties); + + static void GatherElementsHandler(const void* value, void* parameter); + void GatherCollectionElements(CFDictionaryRef properties); + + void AddAxis(CFDictionaryRef element); + void AddButton(CFDictionaryRef element); + void AddPOV(CFDictionaryRef element); + + void AddToQueue(IOHIDElementCookie cookie); + void RemoveFromQueue(IOHIDElementCookie cookie); +}; + + +const float IOKitJoystick::DEFAULT_DEADZONE = 0.25f; +const float IOKitJoystick::DEFAULT_SENSITIVITY = 1.0f; + + +IOHIDDeviceInterface** CreateDeviceInterface(const io_object_t device) +{ + IOCFPlugInInterface** plugInInterface = NULL; + SInt32 score = 0; + + const kern_return_t pluginResult = IOCreatePlugInInterfaceForService(device, + kIOHIDDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); + + IOHIDDeviceInterface** interface = NULL; + + if (KERN_SUCCESS == pluginResult) + { + // Call a method of the intermediate plug-in to create the device interface + + const HRESULT queryResult = (*plugInInterface)->QueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), reinterpret_cast(&interface)); + + IODestroyPlugInInterface(plugInInterface); // [?] or maybe (*plugInInterface)->Release(plugInInterface); + + if (S_OK == queryResult) + { + const IOReturn openResult = (*interface)->open(interface, 0); + + if (kIOReturnSuccess != openResult) + { + (*interface)->Release(interface); + + Printf(TEXTCOLOR_RED "IOHIDDeviceInterface::open() failed with code 0x%08X\n", openResult); + return NULL; + } + } + else + { + Printf(TEXTCOLOR_RED "IOCFPlugInInterface::QueryInterface() failed with code 0x%08X\n", + static_cast(queryResult)); + return NULL; + } + } + else + { + Printf(TEXTCOLOR_RED "IOCreatePlugInInterfaceForService() failed with code %i\n", pluginResult); + return NULL; + } + + return interface; +} + +IOHIDQueueInterface** CreateDeviceQueue(IOHIDDeviceInterface** const interface) +{ + if (NULL == interface) + { + return NULL; + } + + IOHIDQueueInterface** queue = (*interface)->allocQueue(interface); + + if (NULL == queue) + { + Printf(TEXTCOLOR_RED "IOHIDDeviceInterface::allocQueue() failed\n"); + return NULL; + } + + static const uint32_t QUEUE_FLAGS = 0; + static const uint32_t QUEUE_DEPTH = 0; + + const IOReturn queueResult = (*queue)->create(queue, QUEUE_FLAGS, QUEUE_DEPTH); + + if (kIOReturnSuccess != queueResult) + { + (*queue)->Release(queue); + + Printf(TEXTCOLOR_RED "IOHIDQueueInterface::create() failed with code 0x%08X\n", queueResult); + return NULL; + } + + return queue; +} + + +IOKitJoystick::IOKitJoystick(const io_object_t device) +: m_interface(CreateDeviceInterface(device)) +, m_queue(CreateDeviceQueue(m_interface)) +, m_sensitivity(DEFAULT_SENSITIVITY) +, m_enabled(true) +, m_useAxesPolling(true) +, m_notification(0) +{ + if (NULL == m_interface || NULL == m_queue) + { + return; + } + + CFMutableDictionaryRef properties = NULL; + const kern_return_t propertiesResult = + IORegistryEntryCreateCFProperties(device, &properties, kCFAllocatorDefault, kNilOptions); + + if (KERN_SUCCESS != propertiesResult || NULL == properties) + { + Printf(TEXTCOLOR_RED "IORegistryEntryCreateCFProperties() failed with code %i\n", propertiesResult); + return; + } + + GatherDeviceInfo(device, properties); + GatherCollectionElements(properties); + + CFRelease(properties); + + UseAxesPolling(joy_axespolling); + + (*m_queue)->start(m_queue); + + SetDefaultConfig(); +} + +IOKitJoystick::~IOKitJoystick() +{ + M_SaveJoystickConfig(this); + + if (0 != m_notification) + { + IOObjectRelease(m_notification); + } + + if (NULL != m_queue) + { + (*m_queue)->stop(m_queue); + (*m_queue)->dispose(m_queue); + (*m_queue)->Release(m_queue); + } + + if (NULL != m_interface) + { + (*m_interface)->close(m_interface); + (*m_interface)->Release(m_interface); + } +} + + +FString IOKitJoystick::GetName() +{ + return m_name; +} + + +float IOKitJoystick::GetSensitivity() +{ + return m_sensitivity; +} + +void IOKitJoystick::SetSensitivity(float scale) +{ + m_sensitivity = scale; +} + + +int IOKitJoystick::GetNumAxes() +{ + return static_cast(m_axes.Size()); +} + +#define IS_AXIS_VALID (static_cast(axis) < m_axes.Size()) + +float IOKitJoystick::GetAxisDeadZone(int axis) +{ + return IS_AXIS_VALID ? m_axes[axis].deadZone : 0.0f; +} + +EJoyAxis IOKitJoystick::GetAxisMap(int axis) +{ + return IS_AXIS_VALID ? m_axes[axis].gameAxis : JOYAXIS_None; +} + +const char* IOKitJoystick::GetAxisName(int axis) +{ + return IS_AXIS_VALID ? m_axes[axis].name : "Invalid"; +} + +float IOKitJoystick::GetAxisScale(int axis) +{ + return IS_AXIS_VALID ? m_axes[axis].sensitivity : 0.0f; +} + +void IOKitJoystick::SetAxisDeadZone(int axis, float deadZone) +{ + if (IS_AXIS_VALID) + { + m_axes[axis].deadZone = clamp(deadZone, 0.0f, 1.0f); + } +} + +void IOKitJoystick::SetAxisMap(int axis, EJoyAxis gameAxis) +{ + if (IS_AXIS_VALID) + { + m_axes[axis].gameAxis = (gameAxis> JOYAXIS_None && gameAxis = 3) + { + m_axes[0].gameAxis = JOYAXIS_Side; + m_axes[1].gameAxis = JOYAXIS_Forward; + m_axes[2].gameAxis = JOYAXIS_Yaw; + + // Four axes? First two are movement, last two are looking around. + + if (axisCount >= 4) + { + m_axes[3].gameAxis = JOYAXIS_Pitch; +// ??? m_axes[3].sensitivity = 0.75f; + + // Five axes? Use the fifth one for moving up and down. + + if (axisCount >= 5) + { + m_axes[4].gameAxis = JOYAXIS_Up; + } + } + } + + // If there is only one axis, then we make no assumptions about how + // the user might want to use it. + + // Preserve defaults for config saving. + + for (size_t i = 0; i < axisCount; ++i) + { + m_axes[i].defaultDeadZone = m_axes[i].deadZone; + m_axes[i].defaultSensitivity = m_axes[i].sensitivity; + m_axes[i].defaultGameAxis = m_axes[i].gameAxis; + } +} + + +FString IOKitJoystick::GetIdentifier() +{ + return m_identifier; +} + + +void IOKitJoystick::AddAxes(float axes[NUM_JOYAXIS]) const +{ + for (size_t i = 0, count = m_axes.Size(); i < count; ++i) + { + const EJoyAxis axis = m_axes[i].gameAxis; + + if (JOYAXIS_None == axis) + { + continue; + } + + axes[axis] -= m_axes[i].value; + } +} + + +void IOKitJoystick::UseAxesPolling(const bool axesPolling) +{ + m_useAxesPolling = axesPolling; + + for (size_t i = 0, count = m_axes.Size(); i < count; ++i) + { + AnalogAxis& axis = m_axes[i]; + + if (m_useAxesPolling) + { + RemoveFromQueue(axis.cookie); + } + else + { + AddToQueue(axis.cookie); + } + } +} + + +void IOKitJoystick::Update() +{ + if (NULL == m_queue) + { + return; + } + + IOHIDEventStruct event = { }; + AbsoluteTime zeroTime = { }; + + const IOReturn eventResult = (*m_queue)->getNextEvent(m_queue, &event, zeroTime, 0); + + if (kIOReturnSuccess == eventResult) + { + if (use_joystick && m_enabled) + { + ProcessAxis(event) || ProcessButton(event) || ProcessPOV(event); + } + } + else if (kIOReturnUnderrun != eventResult) + { + Printf(TEXTCOLOR_RED "IOHIDQueueInterface::getNextEvent() failed with code 0x%08X\n", eventResult); + } + + if(m_enabled) ProcessAxes(); +} + + +void IOKitJoystick::ProcessAxes() +{ + if (NULL == m_interface || !m_useAxesPolling) + { + return; + } + + for (size_t i = 0, count = m_axes.Size(); i < count; ++i) + { + AnalogAxis& axis = m_axes[i]; + + static const double scaledMin = -1; + static const double scaledMax = 1; + + IOHIDEventStruct event; + + if (kIOReturnSuccess == (*m_interface)->getElementValue(m_interface, axis.cookie, &event)) + { + const double scaledValue = scaledMin + + (event.value - axis.minValue) * (scaledMax - scaledMin) / (axis.maxValue - axis.minValue); + const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, NULL); + + axis.value = static_cast(filteredValue * m_sensitivity * axis.sensitivity); + } + else + { + axis.value = 0.0f; + } + } +} + + +bool IOKitJoystick::ProcessAxis(const IOHIDEventStruct& event) +{ + if (m_useAxesPolling) + { + return false; + } + + for (size_t i = 0, count = m_axes.Size(); i < count; ++i) + { + if (event.elementCookie != m_axes[i].cookie) + { + continue; + } + + AnalogAxis& axis = m_axes[i]; + + static const double scaledMin = -1; + static const double scaledMax = 1; + + const double scaledValue = scaledMin + + (event.value - axis.minValue) * (scaledMax - scaledMin) / (axis.maxValue - axis.minValue); + const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, NULL); + + axis.value = static_cast(filteredValue * m_sensitivity * axis.sensitivity); + + return true; + } + + return false; +} + +bool IOKitJoystick::ProcessButton(const IOHIDEventStruct& event) +{ + for (size_t i = 0, count = m_buttons.Size(); i < count; ++i) + { + if (event.elementCookie != m_buttons[i].cookie) + { + continue; + } + + int32_t& current = m_buttons[i].value; + const int32_t previous = current; + current = event.value; + + Joy_GenerateButtonEvents(previous, current, 1, static_cast(KEY_FIRSTJOYBUTTON + i)); + + return true; + } + + return false; +} + +bool IOKitJoystick::ProcessPOV(const IOHIDEventStruct& event) +{ + for (size_t i = 0, count = m_POVs.Size(); i ( + CFDictionaryGetValue(properties, CFSTR(kIOHIDManufacturerKey))); + CFStringRef productRef = static_cast( + CFDictionaryGetValue(properties, CFSTR(kIOHIDProductKey))); + CFNumberRef vendorIDRef = static_cast( + CFDictionaryGetValue(properties, CFSTR(kIOHIDVendorIDKey))); + CFNumberRef productIDRef = static_cast( + CFDictionaryGetValue(properties, CFSTR(kIOHIDProductIDKey))); + + CFMutableDictionaryRef usbProperties = NULL; + + if ( NULL == vendorRef || NULL == productRef + || NULL == vendorIDRef || NULL == productIDRef) + { + // OS X is not mirroring all USB properties to HID page, so need to look at USB device page also + // Step up two levels and get dictionary of USB properties + + io_registry_entry_t parent1; + kern_return_t ioResult = IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent1); + + if (KERN_SUCCESS == ioResult) + { + io_registry_entry_t parent2; + ioResult = IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent2); + + if (KERN_SUCCESS == ioResult) + { + ioResult = IORegistryEntryCreateCFProperties(parent2, &usbProperties, kCFAllocatorDefault, kNilOptions); + + if (KERN_SUCCESS != ioResult) + { + Printf(TEXTCOLOR_RED "IORegistryEntryCreateCFProperties() failed with code %i\n", ioResult); + } + + IOObjectRelease(parent2); + } + else + { + Printf(TEXTCOLOR_RED "IORegistryEntryGetParentEntry(2) failed with code %i\n", ioResult); + } + + IOObjectRelease(parent1); + } + else + { + Printf(TEXTCOLOR_RED "IORegistryEntryGetParentEntry(1) failed with code %i\n", ioResult); + } + } + + if (NULL != usbProperties) + { + if (NULL == vendorRef) + { + vendorRef = static_cast( + CFDictionaryGetValue(usbProperties, CFSTR("USB Vendor Name"))); + } + + if (NULL == productRef) + { + productRef = static_cast( + CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name"))); + } + + if (NULL == vendorIDRef) + { + vendorIDRef = static_cast( + CFDictionaryGetValue(usbProperties, CFSTR("idVendor"))); + } + + if (NULL == productIDRef) + { + productIDRef = static_cast( + CFDictionaryGetValue(usbProperties, CFSTR("idProduct"))); + } + } + + m_name += ToFString(vendorRef); + m_name += " "; + m_name += ToFString(productRef); + + int vendorID = 0, productID = 0; + + if (NULL != vendorIDRef) + { + CFNumberGetValue(vendorIDRef, kCFNumberIntType, &vendorID); + } + + if (NULL != productIDRef) + { + CFNumberGetValue(productIDRef, kCFNumberIntType, &productID); + } + + m_identifier.AppendFormat("VID_%04x_PID_%04x", vendorID, productID); + + if (NULL != usbProperties) + { + CFRelease(usbProperties); + } +} + + +long GetElementValue(const CFDictionaryRef element, const CFStringRef key) +{ + const CFNumberRef number = + static_cast(CFDictionaryGetValue(element, key)); + long result = 0; + + if (NULL != number && CFGetTypeID(number) == CFNumberGetTypeID()) + { + CFNumberGetValue(number, kCFNumberLongType, &result); + } + + return result; +} + +void IOKitJoystick::GatherElementsHandler(const void* value, void* parameter) +{ + assert(NULL != value); + assert(NULL != parameter); + + const CFDictionaryRef element = static_cast(value); + IOKitJoystick* thisPtr = static_cast(parameter); + + if (CFGetTypeID(element) != CFDictionaryGetTypeID()) + { + Printf(TEXTCOLOR_RED "IOKitJoystick: Encountered wrong element type\n"); + return; + } + + const long type = GetElementValue(element, CFSTR(kIOHIDElementTypeKey)); + + if (kIOHIDElementTypeCollection == type) + { + thisPtr->GatherCollectionElements(element); + } + else if (0 != type) + { + const long usagePage = GetElementValue(element, CFSTR(kIOHIDElementUsagePageKey)); + + if (kHIDPage_GenericDesktop == usagePage) + { + const long usage = GetElementValue(element, CFSTR(kIOHIDElementUsageKey)); + + if ( kHIDUsage_GD_Slider == usage + || kHIDUsage_GD_X == usage || kHIDUsage_GD_Y == usage || kHIDUsage_GD_Z == usage + || kHIDUsage_GD_Rx == usage || kHIDUsage_GD_Ry == usage || kHIDUsage_GD_Rz == usage) + { + thisPtr->AddAxis(element); + } + else if (kHIDUsage_GD_Hatswitch == usage && thisPtr->m_POVs.Size() < 4) + { + thisPtr->AddPOV(element); + } + } + else if (kHIDPage_Button == usagePage) + { + thisPtr->AddButton(element); + } + } +} + +void IOKitJoystick::GatherCollectionElements(const CFDictionaryRef properties) +{ + const CFArrayRef topElement = static_cast( + CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey))); + + if (NULL == topElement || CFGetTypeID(topElement) != CFArrayGetTypeID()) + { + Printf(TEXTCOLOR_RED "GatherCollectionElements: invalid properties dictionary\n"); + return; + } + + const CFRange range = { 0, CFArrayGetCount(topElement) }; + + CFArrayApplyFunction(topElement, range, GatherElementsHandler, this); +} + + +IOHIDElementCookie GetElementCookie(const CFDictionaryRef element) +{ + // Use C-style cast to avoid 32/64-bit IOHIDElementCookie type issue + return (IOHIDElementCookie)GetElementValue(element, CFSTR(kIOHIDElementCookieKey)); +} + +void IOKitJoystick::AddAxis(const CFDictionaryRef element) +{ + AnalogAxis axis; + + axis.cookie = GetElementCookie(element); + axis.minValue = GetElementValue(element, CFSTR(kIOHIDElementMinKey)); + axis.maxValue = GetElementValue(element, CFSTR(kIOHIDElementMaxKey)); + + const CFStringRef nameRef = static_cast( + CFDictionaryGetValue(element, CFSTR(kIOHIDElementNameKey))); + + if (NULL != nameRef && CFStringGetTypeID() == CFGetTypeID(nameRef)) + { + CFStringGetCString(nameRef, axis.name, sizeof(axis.name) - 1, kCFStringEncodingUTF8); + } + else + { + snprintf(axis.name, sizeof(axis.name), "Axis %i", m_axes.Size() + 1); + } + + m_axes.Push(axis); +} + +void IOKitJoystick::AddButton(CFDictionaryRef element) +{ + const DigitalButton button(GetElementCookie(element)); + + m_buttons.Push(button); + + AddToQueue(button.cookie); +} + +void IOKitJoystick::AddPOV(CFDictionaryRef element) +{ + const DigitalButton pov(GetElementCookie(element)); + + m_POVs.Push(pov); + + AddToQueue(pov.cookie); +} + + +void IOKitJoystick::AddToQueue(const IOHIDElementCookie cookie) +{ + if (NULL == m_queue) + { + return; + } + + if (!(*m_queue)->hasElement(m_queue, cookie)) + { + (*m_queue)->addElement(m_queue, cookie, 0); + } +} + +void IOKitJoystick::RemoveFromQueue(const IOHIDElementCookie cookie) +{ + if (NULL == m_queue) + { + return; + } + + if ((*m_queue)->hasElement(m_queue, cookie)) + { + (*m_queue)->removeElement(m_queue, cookie); + } +} + + +io_object_t* IOKitJoystick::GetNotificationPtr() +{ + return &m_notification; +} + + +// --------------------------------------------------------------------------- + + +class IOKitJoystickManager +{ +public: + IOKitJoystickManager(); + ~IOKitJoystickManager(); + + void GetJoysticks(TArray& joysticks) const; + + void AddAxes(float axes[NUM_JOYAXIS]) const; + + // Updates axes/buttons states + void Update(); + + void UseAxesPolling(bool axesPolling); + +private: + typedef TDeletingArray JoystickList; + JoystickList m_joysticks; + + static const size_t NOTIFICATION_PORT_COUNT = 2; + + IONotificationPortRef m_notificationPorts[NOTIFICATION_PORT_COUNT]; + io_iterator_t m_notifications [NOTIFICATION_PORT_COUNT]; + + // Rebuilds device list + void Rescan(int usagePage, int usage, size_t notificationPortIndex); + void AddDevices(IONotificationPortRef notificationPort, const io_iterator_t iterator); + + static void OnDeviceAttached(void* refcon, io_iterator_t iterator); + static void OnDeviceRemoved(void* refcon, io_service_t service, + natural_t messageType, void* messageArgument); +}; + + +IOKitJoystickManager* s_joystickManager; + + +IOKitJoystickManager::IOKitJoystickManager() +{ + memset(m_notifications, 0, sizeof m_notifications); + + for (size_t i = 0; i < NOTIFICATION_PORT_COUNT; ++i) + { + m_notificationPorts[i] = IONotificationPortCreate(kIOMasterPortDefault); + + if (NULL == m_notificationPorts[i]) + { + Printf(TEXTCOLOR_RED "IONotificationPortCreate(%zu) failed\n", i); + return; + } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), + IONotificationPortGetRunLoopSource(m_notificationPorts[i]), kCFRunLoopDefaultMode); + } + + Rescan(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, 0); + Rescan(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, 1); +} + +IOKitJoystickManager::~IOKitJoystickManager() +{ + for (size_t i = 0; i < NOTIFICATION_PORT_COUNT; ++i) + { + IONotificationPortRef& port = m_notificationPorts[i]; + + if (NULL != port) + { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), + IONotificationPortGetRunLoopSource(port), kCFRunLoopDefaultMode); + + IONotificationPortDestroy(port); + port = NULL; + } + + io_iterator_t& notification = m_notifications[i]; + + if (0 != notification) + { + IOObjectRelease(notification); + notification = 0; + } + } +} + + +void IOKitJoystickManager::GetJoysticks(TArray& joysticks) const +{ + const size_t joystickCount = m_joysticks.Size(); + + joysticks.Resize(joystickCount); + + for (size_t i = 0; i < joystickCount; ++i) + { + M_LoadJoystickConfig(m_joysticks[i]); + + joysticks[i] = m_joysticks[i]; + } +} + +void IOKitJoystickManager::AddAxes(float axes[NUM_JOYAXIS]) const +{ + for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) + { + m_joysticks[i]->AddAxes(axes); + } +} + + +void IOKitJoystickManager::Update() +{ + for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) + { + m_joysticks[i]->Update(); + } +} + + +void IOKitJoystickManager::UseAxesPolling(const bool axesPolling) +{ + for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) + { + m_joysticks[i]->UseAxesPolling(axesPolling); + } +} + + +void PostDeviceChangeEvent() +{ + event_t event = { EV_DeviceChange }; + D_PostEvent(&event); +} + + +void IOKitJoystickManager::Rescan(const int usagePage, const int usage, const size_t notificationPortIndex) +{ + CFMutableDictionaryRef deviceMatching = IOServiceMatching(kIOHIDDeviceKey); + + if (NULL == deviceMatching) + { + Printf(TEXTCOLOR_RED "IOServiceMatching() returned NULL\n"); + return; + } + + const CFNumberRef usagePageRef = + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage); + CFDictionarySetValue(deviceMatching, CFSTR(kIOHIDPrimaryUsagePageKey), usagePageRef); + + const CFNumberRef usageRef = + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + CFDictionarySetValue(deviceMatching, CFSTR(kIOHIDPrimaryUsageKey), usageRef); + + assert(notificationPortIndex < NOTIFICATION_PORT_COUNT); + io_iterator_t* iteratorPtr = &m_notifications[notificationPortIndex]; + + const IONotificationPortRef notificationPort = m_notificationPorts[notificationPortIndex]; + assert(NULL != notificationPort); + + const kern_return_t notificationResult = IOServiceAddMatchingNotification(notificationPort, + kIOFirstMatchNotification, deviceMatching, OnDeviceAttached, notificationPort, iteratorPtr); + + // IOServiceAddMatchingNotification() consumes one reference of matching dictionary + // Thus CFRelease(deviceMatching) is not needed + + CFRelease(usageRef); + CFRelease(usagePageRef); + + if (KERN_SUCCESS != notificationResult) + { + Printf(TEXTCOLOR_RED "IOServiceAddMatchingNotification() failed with code %i\n", notificationResult); + } + + AddDevices(notificationPort, *iteratorPtr); +} + +void IOKitJoystickManager::AddDevices(const IONotificationPortRef notificationPort, const io_iterator_t iterator) +{ + while (io_object_t device = IOIteratorNext(iterator)) + { + IOKitJoystick* joystick = new IOKitJoystick(device); + m_joysticks.Push(joystick); + + const kern_return_t notificationResult = IOServiceAddInterestNotification(notificationPort, + device, kIOGeneralInterest, OnDeviceRemoved, joystick, joystick->GetNotificationPtr()); + if (KERN_SUCCESS != notificationResult) + { + Printf(TEXTCOLOR_RED "IOServiceAddInterestNotification() failed with code %i\n", notificationResult); + } + + IOObjectRelease(device); + + PostDeviceChangeEvent(); + } +} + + +void IOKitJoystickManager::OnDeviceAttached(void* const refcon, const io_iterator_t iterator) +{ + assert(NULL != refcon); + const IONotificationPortRef notificationPort = static_cast(refcon); + + assert(NULL != s_joystickManager); + s_joystickManager->AddDevices(notificationPort, iterator); +} + +void IOKitJoystickManager::OnDeviceRemoved(void* const refcon, io_service_t, const natural_t messageType, void*) +{ + if (messageType != kIOMessageServiceIsTerminated) + { + return; + } + + assert(NULL != refcon); + IOKitJoystick* const joystick = static_cast(refcon); + + assert(NULL != s_joystickManager); + JoystickList& joysticks = s_joystickManager->m_joysticks; + + for (unsigned int i = 0, count = joysticks.Size(); i < count; ++i) + { + if (joystick == joysticks[i]) + { + joysticks.Delete(i); + break; + } + } + + delete joystick; + + PostDeviceChangeEvent(); +} + +} // unnamed namespace + + +// --------------------------------------------------------------------------- + + +void I_ShutdownInput() +{ + delete s_joystickManager; + s_joystickManager = NULL; +} + +void I_GetJoysticks(TArray& sticks) +{ + // Instances of IOKitJoystick depend on GameConfig object. + // M_SaveDefaultsFinal() must be called after destruction of IOKitJoystickManager. + // To ensure this, its initialization is moved here. + // As M_LoadDefaults() was already called at this moment, + // the order of atterm's functions will be correct + + if (NULL == s_joystickManager && !Args->CheckParm("-nojoy")) + { + s_joystickManager = new IOKitJoystickManager; + } + + if (NULL != s_joystickManager) + { + s_joystickManager->GetJoysticks(sticks); + } +} + +void I_GetAxes(float axes[NUM_JOYAXIS]) +{ + for (size_t i = 0; i < NUM_JOYAXIS; ++i) + { + axes[i] = 0.0f; + } + + if (use_joystick && NULL != s_joystickManager) + { + s_joystickManager->AddAxes(axes); + } +} + +IJoystickConfig* I_UpdateDeviceList() +{ + // Does nothing, device list is always kept up-to-date + + return NULL; +} + + +// --------------------------------------------------------------------------- + + +void I_ProcessJoysticks() +{ + if (NULL != s_joystickManager) + { + s_joystickManager->Update(); + } +} + + +// --------------------------------------------------------------------------- + + +CUSTOM_CVAR(Bool, joy_axespolling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (NULL != s_joystickManager) + { + s_joystickManager->UseAxesPolling(self); + } +} diff --git a/src/posix/cocoa/i_main.mm b/src/common/platform/posix/cocoa/i_main.mm similarity index 77% rename from src/posix/cocoa/i_main.mm rename to src/common/platform/posix/cocoa/i_main.mm index c55a82500f4..10f3a60ab63 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/common/platform/posix/cocoa/i_main.mm @@ -32,20 +32,22 @@ */ #include "i_common.h" -#include "s_sound.h" +#include "s_soundinternal.h" #include +#include #include "c_console.h" #include "c_cvars.h" #include "cmdlib.h" -#include "d_main.h" #include "i_system.h" #include "m_argv.h" #include "st_console.h" #include "version.h" -#include "doomerrors.h" +#include "printf.h" #include "s_music.h" +#include "engineerrors.h" +#include "zstring.h" #define ZD_UNUSED(VARIABLE) ((void)(VARIABLE)) @@ -54,12 +56,11 @@ // --------------------------------------------------------------------------- -CVAR (Bool, i_soundinbackground, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) EXTERN_CVAR(Int, vid_defwidth ) EXTERN_CVAR(Int, vid_defheight) EXTERN_CVAR(Bool, vid_vsync ) - +int GameMain(); // --------------------------------------------------------------------------- @@ -72,44 +73,105 @@ void Mac_I_FatalError(const char* const message) } -#if MAC_OS_X_VERSION_MAX_ALLOWED < 101000 +static bool ReadSystemVersionFromPlist(NSOperatingSystemVersion& version) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED < 110000 + // The version returned by macOS depends on the SDK which the software has been built against. + // When built against the 10.15 SDK or earlier, Big Sur returns 10.16 for compatibility with previous numbering. + // When built against the 11.0 SDK, it returns 11.0 for forward compatibility. + // https://eclecticlight.co/2020/08/13/macos-version-numbering-isnt-so-simple/ -// Available since 10.9 with no public declaration/definition until 10.10 + // It's impossible to load real SystemVersion.plist when linking with old SDK, i.e. when building for Intel CPU + // Any attempt to read this file is redirected to SystemVersionCompat.plist silently + // Workaround with the external process is needed in order to report correct macOS version -struct NSOperatingSystemVersion -{ - NSInteger majorVersion; - NSInteger minorVersion; - NSInteger patchVersion; -}; + const char *const plistPath = "/System/Library/CoreServices/SystemVersion.plist"; + struct stat dummy; -@interface NSProcessInfo(OperatingSystemVersion) -- (NSOperatingSystemVersion)operatingSystemVersion; -@end + if (stat(plistPath, &dummy) != 0) + return false; + + char commandLine[1024] = {}; + snprintf(commandLine, sizeof commandLine, "defaults read %s ProductVersion", plistPath); -#endif // before 10.10 + FILE *const versionFile = popen(commandLine, "r"); + + if (versionFile == nullptr) + return false; + + NSOperatingSystemVersion plistVersion = {}; + char versionString[256] = {}; + + if (fgets(versionString, sizeof versionString, versionFile)) + { + plistVersion.majorVersion = atoi(versionString); + + if (const char *minorVersionString = strstr(versionString, ".")) + { + minorVersionString++; + plistVersion.minorVersion = atoi(minorVersionString); + + if (const char *patchVersionString = strstr(minorVersionString, ".")) + { + patchVersionString++; + plistVersion.patchVersion = atoi(patchVersionString); + } + } + } + + fclose(versionFile); + + if (plistVersion.majorVersion != 0) + { + version = plistVersion; + return true; + } +#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 110000 + return false; +} + +FString sys_ostype; void I_DetectOS() { NSOperatingSystemVersion version = {}; - NSProcessInfo* const processInfo = [NSProcessInfo processInfo]; - if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) + if (!ReadSystemVersionFromPlist(version)) { - version = [processInfo operatingSystemVersion]; + NSProcessInfo *const processInfo = [NSProcessInfo processInfo]; + + if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) + { + version = [processInfo operatingSystemVersion]; + } } const char* name = "Unknown version"; - - if (10 == version.majorVersion) switch (version.minorVersion) + + switch (version.majorVersion) { - case 9: name = "OS X Mavericks"; break; - case 10: name = "OS X Yosemite"; break; - case 11: name = "OS X El Capitan"; break; - case 12: name = "macOS Sierra"; break; - case 13: name = "macOS High Sierra"; break; - case 14: name = "macOS Mojave"; break; - case 15: name = "macOS Catalina"; break; + case 10: + switch (version.minorVersion) + { + case 12: name = "Sierra"; break; + case 13: name = "High Sierra"; break; + case 14: name = "Mojave"; break; + case 15: name = "Catalina"; break; + case 16: name = "Big Sur"; break; + } + break; + case 11: + name = "Big Sur"; + break; + case 12: + name = "Monterey"; + break; + case 13: + name = "Ventura"; + break; + case 14: + name = "Sonoma"; + break; } char release[16] = "unknown"; @@ -121,17 +183,19 @@ void I_DetectOS() sysctlbyname("hw.model", model, &size, nullptr, 0); const char* const architecture = -#ifdef __i386__ - "32-bit Intel"; -#elif defined __x86_64__ - "64-bit Intel"; +#ifdef __x86_64__ + "64-bit Intel"; +#elif defined __aarch64__ + "64-bit ARM"; #else "Unknown"; #endif - - Printf("%s running %s %d.%d.%d (%s) %s\n", model, name, + + Printf("%s running macOS %s %d.%d.%d (%s) %s\n", model, name, int(version.majorVersion), int(version.minorVersion), int(version.patchVersion), release, architecture); + + sys_ostype.Format("macOS %d.%d %s", int(version.majorVersion), int(version.minorVersion), name); } @@ -156,20 +220,13 @@ int DoMain(int argc, char** argv) setenv("LC_NUMERIC", "C", 1); setlocale(LC_ALL, "C"); - // Set reasonable default values for video settings - - const NSSize screenSize = [[NSScreen mainScreen] frame].size; - vid_defwidth = static_cast(screenSize.width); - vid_defheight = static_cast(screenSize.height); - vid_vsync = true; - Args = new FArgs(argc, argv); NSString* exePath = [[NSBundle mainBundle] executablePath]; progdir = [[exePath stringByDeletingLastPathComponent] UTF8String]; progdir += "/"; - auto ret = D_DoomMain(); + auto ret = GameMain(); FConsoleWindow::DeleteInstance(); return ret; } @@ -211,14 +268,14 @@ @implementation ApplicationController - (void)keyDown:(NSEvent*)theEvent { // Empty but present to avoid playing of 'beep' alert sound - + ZD_UNUSED(theEvent); } - (void)keyUp:(NSEvent*)theEvent { // Empty but present to avoid playing of 'beep' alert sound - + ZD_UNUSED(theEvent); } @@ -228,8 +285,9 @@ - (void)keyUp:(NSEvent*)theEvent - (void)applicationDidBecomeActive:(NSNotification*)aNotification { ZD_UNUSED(aNotification); - - S_SetSoundPaused(1); + + if (GSnd) + S_SetSoundPaused(1); AppActive = true; } @@ -237,8 +295,9 @@ - (void)applicationDidBecomeActive:(NSNotification*)aNotification - (void)applicationWillResignActive:(NSNotification*)aNotification { ZD_UNUSED(aNotification); - - S_SetSoundPaused(i_soundinbackground); + + if (GSnd) + S_SetSoundPaused(0); AppActive = false; } @@ -289,7 +348,7 @@ - (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename for (size_t i = 0, count = s_argv.Size(); i < count; ++i) { - if (0 == strcmp(s_argv[i], charFileName)) + if (0 == strcmp(s_argv[i].GetChars(), charFileName)) { return FALSE; } @@ -319,7 +378,7 @@ - (void)processEvents:(NSTimer*)timer while (true) { - NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate dateWithTimeIntervalSinceNow:0] inMode:NSDefaultRunLoopMode dequeue:YES]; @@ -372,7 +431,7 @@ - (void)sendExitEvent:(id)sender [[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"] - setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask]; + setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand]; [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; diff --git a/src/common/platform/posix/cocoa/i_system.mm b/src/common/platform/posix/cocoa/i_system.mm new file mode 100644 index 00000000000..267bac31d9d --- /dev/null +++ b/src/common/platform/posix/cocoa/i_system.mm @@ -0,0 +1,197 @@ +/* + ** i_system.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2012-2018 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. 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. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + **--------------------------------------------------------------------------- + ** + */ + +#include "i_common.h" +#include "c_cvars.h" + +#include +#include + +#include "i_system.h" +#include "st_console.h" +#include "v_text.h" + +EXTERN_CVAR(Bool, longsavemessages) +double PerfToSec, PerfToMillisec; + +void CalculateCPUSpeed() +{ + long long frequency; + size_t size = sizeof frequency; + + if (0 == sysctlbyname("machdep.tsc.frequency", &frequency, &size, nullptr, 0) && 0 != frequency) + { + PerfToSec = 1.0 / frequency; + PerfToMillisec = 1000.0 / frequency; + + if (!batchrun) + { + Printf("CPU speed: %.0f MHz\n", 0.001 / PerfToMillisec); + } + } +} + + +void I_SetIWADInfo() +{ + FConsoleWindow::GetInstance().SetTitleText(); +} + + +void I_PrintStr(const char* const message) +{ + FConsoleWindow::GetInstance().AddText(message); + + // Strip out any color escape sequences before writing to output + char* const copy = new char[strlen(message) + 1]; + const char* srcp = message; + char* dstp = copy; + + while ('\0' != *srcp) + { + if (TEXTCOLOR_ESCAPE == *srcp) + { + if ('\0' != srcp[1]) + { + srcp += 2; + } + else + { + break; + } + } + else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character + { + *dstp++ = '-'; + ++srcp; + } + else if (0x1e == *srcp) // Middle bar character + { + *dstp++ = '='; + ++srcp; + } + else + { + *dstp++ = *srcp++; + } + } + + *dstp = '\0'; + + fputs(copy, stdout); + delete[] copy; + fflush(stdout); +} + + +void Mac_I_FatalError(const char* const message); + +void I_ShowFatalError(const char *message) +{ + Mac_I_FatalError(message); +} + + +int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad, int&, FString&) +{ + if (!showwin) + { + return defaultiwad; + } + + I_SetMainWindowVisible(false); + + extern int I_PickIWad_Cocoa(WadStuff*, int, bool, int); + const int result = I_PickIWad_Cocoa(wads, numwads, showwin, defaultiwad); + + I_SetMainWindowVisible(true); + + return result; +} + + +void I_PutInClipboard(const char* const string) +{ + NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; + NSString* const stringType = NSStringPboardType; + NSArray* const types = [NSArray arrayWithObjects:stringType, nil]; + NSString* const content = [NSString stringWithUTF8String:string]; + + [pasteBoard declareTypes:types + owner:nil]; + [pasteBoard setString:content + forType:stringType]; +} + +FString I_GetFromClipboard(bool returnNothing) +{ + if (returnNothing) + { + return FString(); + } + + NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; + NSString* const value = [pasteBoard stringForType:NSStringPboardType]; + + return FString([value UTF8String]); +} + + +unsigned int I_MakeRNGSeed() +{ + return static_cast(arc4random()); +} + +FString I_GetCWD() +{ + NSString *currentpath = [[NSFileManager defaultManager] currentDirectoryPath]; + return currentpath.UTF8String; +} + +bool I_ChDir(const char* path) +{ + return [[NSFileManager defaultManager] changeCurrentDirectoryPath:[NSString stringWithUTF8String:path]]; +} + +void I_OpenShellFolder(const char* folder) +{ + NSFileManager *filemgr = [NSFileManager defaultManager]; + NSString *currentpath = [filemgr currentDirectoryPath]; + + [filemgr changeCurrentDirectoryPath:[NSString stringWithUTF8String:folder]]; + if (longsavemessages) + Printf("Opening folder: %s\n", folder); + std::system("open ."); + [filemgr changeCurrentDirectoryPath:currentpath]; +} + diff --git a/src/posix/cocoa/i_video.mm b/src/common/platform/posix/cocoa/i_video.mm similarity index 88% rename from src/posix/cocoa/i_video.mm rename to src/common/platform/posix/cocoa/i_video.mm index 81b14e3cd28..88c1b9b7ea8 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/common/platform/posix/cocoa/i_video.mm @@ -31,12 +31,11 @@ ** */ -#include "gl_load/gl_load.h" +#include "gl_load.h" #ifdef HAVE_VULKAN -#define VK_USE_PLATFORM_MACOS_MVK -#define VK_USE_PLATFORM_METAL_EXT -#include "volk/volk.h" +#include +#include #endif #include "i_common.h" @@ -44,21 +43,26 @@ #include "v_video.h" #include "bitmap.h" #include "c_dispatch.h" -#include "doomstat.h" #include "hardware.h" #include "i_system.h" #include "m_argv.h" #include "m_png.h" -#include "swrenderer/r_swrenderer.h" #include "st_console.h" #include "v_text.h" #include "version.h" -#include "doomerrors.h" +#include "printf.h" +#include "gl_framebuffer.h" +#ifdef HAVE_GLES2 +#include "gles_framebuffer.h" +#endif + +#ifdef HAVE_VULKAN +#include "vulkan/system/vk_renderdevice.h" +#endif -#include "gl/system/gl_framebuffer.h" -#include "vulkan/system/vk_framebuffer.h" -#include "rendering/polyrenderer/backend/poly_framebuffer.h" +bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface); +extern bool ToggleFullscreen; @implementation NSWindow(ExitAppOnClose) @@ -95,10 +99,10 @@ - (void)enterFullscreenOnZoom EXTERN_CVAR(Bool, vid_hidpi) EXTERN_CVAR(Int, vid_defwidth) EXTERN_CVAR(Int, vid_defheight) -EXTERN_CVAR(Int, vid_preferbackend) EXTERN_CVAR(Bool, vk_debug) CVAR(Bool, mvk_debug, false, 0) +CVAR(Bool, vid_nativefullscreen, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CUSTOM_CVAR(Bool, vid_autoswitch, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { @@ -114,8 +118,8 @@ - (void)enterFullscreenOnZoom const NSInteger LEVEL_FULLSCREEN = NSMainMenuWindowLevel + 1; const NSInteger LEVEL_WINDOWED = NSNormalWindowLevel; - const NSUInteger STYLE_MASK_FULLSCREEN = NSBorderlessWindowMask; - const NSUInteger STYLE_MASK_WINDOWED = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask; + const NSUInteger STYLE_MASK_FULLSCREEN = NSWindowStyleMaskBorderless; + const NSUInteger STYLE_MASK_WINDOWED = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; } @@ -287,6 +291,7 @@ -(BOOL) isOpaque [window setOpaque:YES]; [window makeFirstResponder:appCtrl]; [window setAcceptsMouseMovedEvents:YES]; + [window exitAppOnClose]; NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; [nc addObserver:window @@ -368,14 +373,12 @@ void SetupOpenGLView(CocoaWindow* const window, const OpenGLProfile profile) public: CocoaVideo() { - ms_isVulkanEnabled = vid_preferbackend == 1 && NSAppKitVersionNumber >= 1404; // NSAppKitVersionNumber10_11 + ms_isVulkanEnabled = V_GetBackend() == 1 && NSAppKitVersionNumber >= 1404; // NSAppKitVersionNumber10_11 } ~CocoaVideo() { -#ifdef HAVE_VULKAN - delete m_vulkanDevice; -#endif + m_vulkanSurface.reset(); ms_window = nil; } @@ -429,8 +432,20 @@ void SetupOpenGLView(CocoaWindow* const window, const OpenGLProfile profile) try { - m_vulkanDevice = new VulkanDevice(); - fb = new VulkanFrameBuffer(nullptr, fullscreen, m_vulkanDevice); + VulkanInstanceBuilder builder; + builder.DebugLayer(vk_debug); + builder.RequireExtension(VK_KHR_SURFACE_EXTENSION_NAME); // KHR_surface, required + builder.OptionalExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME); // EXT_metal_surface, optional, preferred + builder.OptionalExtension(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); // MVK_macos_surface, optional, deprecated + auto vulkanInstance = builder.Create(); + + VkSurfaceKHR surfacehandle = nullptr; + if (!I_CreateVulkanSurface(vulkanInstance->Instance, &surfacehandle)) + VulkanError("I_CreateVulkanSurface failed"); + + m_vulkanSurface = std::make_shared(vulkanInstance, surfacehandle); + + fb = new VulkanRenderDevice(nullptr, vid_fullscreen, m_vulkanSurface); } catch (std::exception const&) { @@ -441,35 +456,34 @@ void SetupOpenGLView(CocoaWindow* const window, const OpenGLProfile profile) } else #endif - if (vid_preferbackend == 2) - { - SetupOpenGLView(ms_window, OpenGLProfile::Legacy); - fb = new PolyFrameBuffer(nullptr, fullscreen); - } - else - { - SetupOpenGLView(ms_window, OpenGLProfile::Core); - } + SetupOpenGLView(ms_window, OpenGLProfile::Core); if (fb == nullptr) { - fb = new OpenGLRenderer::OpenGLFrameBuffer(0, fullscreen); +#ifdef HAVE_GLES2 + if(V_GetBackend() != 0) + fb = new OpenGLESRenderer::OpenGLFrameBuffer(0, vid_fullscreen); + else +#endif + fb = new OpenGLRenderer::OpenGLFrameBuffer(0, vid_fullscreen); } fb->SetWindow(ms_window); - fb->SetMode(fullscreen, vid_hidpi); + fb->SetMode(vid_fullscreen, vid_hidpi); fb->SetSize(fb->GetClientWidth(), fb->GetClientHeight()); +#ifdef HAVE_VULKAN // This lame hack is a temporary workaround for strange performance issues // with fullscreen window and Core Animation's Metal layer // It is somehow related to initial window level and flags // Toggling fullscreen -> window -> fullscreen mysteriously solves the problem - if (ms_isVulkanEnabled && fullscreen) + if (ms_isVulkanEnabled && vid_fullscreen) { fb->SetMode(false, vid_hidpi); fb->SetMode(true, vid_hidpi); } +#endif return fb; } @@ -480,8 +494,9 @@ void SetupOpenGLView(CocoaWindow* const window, const OpenGLProfile profile) } private: - VulkanDevice *m_vulkanDevice = nullptr; - +#ifdef HAVE_VULKAN + std::shared_ptr m_vulkanSurface; +#endif static CocoaWindow* ms_window; static bool ms_isVulkanEnabled; @@ -542,10 +557,10 @@ void SetupOpenGLView(CocoaWindow* const window, const OpenGLProfile profile) return; } - if (fullscreen) + if (vid_fullscreen) { // Enter windowed mode in order to calculate title bar height - fullscreen = false; + vid_fullscreen = false; SetMode(false, m_hiDPI); } @@ -624,7 +639,6 @@ void SetupOpenGLView(CocoaWindow* const window, const OpenGLProfile profile) const NSRect frameSize = NSMakeRect(win_x, win_y, win_w, win_h); [m_window setFrame:frameSize display:YES]; [m_window enterFullscreenOnZoom]; - [m_window exitAppOnClose]; } void SystemBaseFrameBuffer::SetMode(const bool fullscreen, const bool hiDPI) @@ -641,7 +655,11 @@ void SetupOpenGLView(CocoaWindow* const window, const OpenGLProfile profile) [m_window.contentView layer].contentsScale = hiDPI ? m_window.screen.backingScaleFactor : 1.0; } - if (fullscreen) + if (vid_nativefullscreen && fullscreen != m_fullscreen) + { + [m_window toggleFullScreen:(nil)]; + } + else if (fullscreen) { SetFullscreenMode(); } @@ -733,7 +751,11 @@ void SetupOpenGLView(CocoaWindow* const window, const OpenGLProfile profile) NSOpenGLView* const glView = [m_window contentView]; [glView setWantsBestResolutionOpenGLSurface:hiDPI]; - if (fullscreen) + if (vid_nativefullscreen && fullscreen != m_fullscreen) + { + [m_window toggleFullScreen:(nil)]; + } + else if (fullscreen) { SetFullscreenMode(); } @@ -798,7 +820,7 @@ void I_InitGraphics() // --------------------------------------------------------------------------- -bool I_SetCursor(FTexture *cursorpic) +bool I_SetCursor(FGameTexture *cursorpic) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSCursor* cursor = nil; @@ -806,8 +828,8 @@ bool I_SetCursor(FTexture *cursorpic) if (NULL != cursorpic && cursorpic->isValid()) { // Create bitmap image representation - - auto sbuffer = cursorpic->CreateTexBuffer(0); + + auto sbuffer = cursorpic->GetTexture()->CreateTexBuffer(0); const NSInteger imageWidth = sbuffer.mWidth; const NSInteger imageHeight = sbuffer.mHeight; @@ -847,11 +869,11 @@ bool I_SetCursor(FTexture *cursorpic) cursor = [[NSCursor alloc] initWithImage:cursorImage hotSpot:NSMakePoint(0.0f, 0.0f)]; } - + SystemBaseFrameBuffer::SetCursor(cursor); - + [pool release]; - + return true; } @@ -897,63 +919,6 @@ void I_GetVulkanDrawableSize(int *width, int *height) } } -bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names) -{ - static std::vector extensions; - - if (extensions.empty()) - { - uint32_t extensionPropertyCount = 0; - vkEnumerateInstanceExtensionProperties(nullptr, &extensionPropertyCount, nullptr); - - std::vector extensionProperties(extensionPropertyCount); - vkEnumerateInstanceExtensionProperties(nullptr, &extensionPropertyCount, extensionProperties.data()); - - static const char* const EXTENSION_NAMES[] = - { - VK_KHR_SURFACE_EXTENSION_NAME, // KHR_surface, required - VK_EXT_METAL_SURFACE_EXTENSION_NAME, // EXT_metal_surface, optional, preferred - VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // MVK_macos_surface, optional, deprecated - }; - - for (const VkExtensionProperties ¤tProperties : extensionProperties) - { - for (const char *const extensionName : EXTENSION_NAMES) - { - if (strcmp(currentProperties.extensionName, extensionName) == 0) - { - extensions.push_back(extensionName); - } - } - } - } - - static const unsigned int extensionCount = static_cast(extensions.size()); - assert(extensionCount >= 2); // KHR_surface + at least one of the platform surface extentions - - if (count == nullptr && names == nullptr) - { - return false; - } - else if (names == nullptr) - { - *count = extensionCount; - return true; - } - else - { - const bool result = *count >= extensionCount; - *count = std::min(*count, extensionCount); - - for (unsigned int i = 0; i < *count; ++i) - { - names[i] = extensions[i]; - } - - return result; - } -} - bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface) { NSView *const view = CocoaVideo::GetWindow().contentView; diff --git a/src/posix/cocoa/st_console.h b/src/common/platform/posix/cocoa/st_console.h similarity index 100% rename from src/posix/cocoa/st_console.h rename to src/common/platform/posix/cocoa/st_console.h diff --git a/src/posix/cocoa/st_console.mm b/src/common/platform/posix/cocoa/st_console.mm similarity index 95% rename from src/posix/cocoa/st_console.mm rename to src/common/platform/posix/cocoa/st_console.mm index cd8dd2ea00c..1c45776e6cf 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/common/platform/posix/cocoa/st_console.mm @@ -32,12 +32,13 @@ */ #include "i_common.h" - -#include "d_main.h" +#include "startupinfo.h" #include "st_console.h" #include "v_text.h" #include "version.h" - +#include "palentry.h" +#include "v_video.h" +#include "v_font.h" static NSColor* RGB(const uint8_t red, const uint8_t green, const uint8_t blue) { @@ -103,7 +104,7 @@ NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMENAME, GetVersionString()]; [m_window initWithContentRect:initialRect - styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask + styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO]; [m_window setMinSize:[m_window frame].size]; @@ -339,17 +340,17 @@ static void UpdateTimed(const Function& function) // It's used in graphical startup screen, with Hexen style in particular // Native OS X backend doesn't implement this yet - if (DoomStartupInfo.FgColor == DoomStartupInfo.BkColor) + if (GameStartupInfo.FgColor == GameStartupInfo.BkColor) { - DoomStartupInfo.FgColor = ~DoomStartupInfo.FgColor; + GameStartupInfo.FgColor = ~GameStartupInfo.FgColor; } NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect]; - [titleText setStringValue:[NSString stringWithCString:DoomStartupInfo.Name + [titleText setStringValue:[NSString stringWithCString:GameStartupInfo.Name.GetChars() encoding:NSISOLatin1StringEncoding]]; - [titleText setAlignment:NSCenterTextAlignment]; - [titleText setTextColor:RGB(DoomStartupInfo.FgColor)]; - [titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)]; + [titleText setAlignment:NSTextAlignmentCenter]; + [titleText setTextColor:RGB(GameStartupInfo.FgColor)]; + [titleText setBackgroundColor:RGB(GameStartupInfo.BkColor)]; [titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]]; [titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; [titleText setSelectable:NO]; @@ -433,7 +434,7 @@ static void UpdateTimed(const Function& function) // Text with connected/total players count m_netCountText = [[NSTextField alloc] initWithFrame:NSMakeRect(428.0f, 64.0f, 72.0f, 16.0f)]; [m_netCountText setAutoresizingMask:NSViewMinXMargin]; - [m_netCountText setAlignment:NSRightTextAlignment]; + [m_netCountText setAlignment:NSTextAlignmentRight]; [m_netCountText setDrawsBackground:NO]; [m_netCountText setSelectable:NO]; [m_netCountText setBordered:NO]; @@ -509,7 +510,7 @@ static void UpdateTimed(const Function& function) if (m_netMaxPos > 1) { [m_netCountText setStringValue:[NSString stringWithFormat:@"%d / %d", m_netCurPos, m_netMaxPos]]; - [m_netProgressBar setDoubleValue:MIN(m_netCurPos, m_netMaxPos)]; + [m_netProgressBar setDoubleValue:min(m_netCurPos, m_netMaxPos)]; } } diff --git a/src/posix/cocoa/st_start.mm b/src/common/platform/posix/cocoa/st_start.mm similarity index 88% rename from src/posix/cocoa/st_start.mm rename to src/common/platform/posix/cocoa/st_start.mm index a98ca9873e9..ee6ea262784 100644 --- a/src/posix/cocoa/st_start.mm +++ b/src/common/platform/posix/cocoa/st_start.mm @@ -36,32 +36,16 @@ #import #include "c_cvars.h" -#include "doomtype.h" #include "st_console.h" #include "st_start.h" -#include "doomerrors.h" - - -FStartupScreen *StartScreen; - - -CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (self < 0) - { - self = 0; - } - else if (self > 2) - { - self = 2; - } -} +#include "printf.h" +#include "engineerrors.h" // --------------------------------------------------------------------------- -FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar) +FBasicStartupScreen::FBasicStartupScreen(int maxProgress) : FStartupScreen(maxProgress) { FConsoleWindow& consoleWindow = FConsoleWindow::GetInstance(); @@ -121,18 +105,6 @@ FConsoleWindow::GetInstance().NetProgress(count); } -void FBasicStartupScreen::NetMessage(const char* const format, ...) -{ - va_list args; - va_start(args, format); - - FString message; - message.VFormat(format, args); - va_end(args); - - Printf("%s\n", message.GetChars()); -} - void FBasicStartupScreen::NetDone() { FConsoleWindow::GetInstance().NetDone(); @@ -162,14 +134,5 @@ FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress) { - return new FBasicStartupScreen(maxProgress, true); -} - - -// --------------------------------------------------------------------------- - - -void ST_Endoom() -{ - throw CExitEvent(0); + return new FBasicStartupScreen(maxProgress); } diff --git a/src/posix/dikeys.h b/src/common/platform/posix/dikeys.h similarity index 100% rename from src/posix/dikeys.h rename to src/common/platform/posix/dikeys.h diff --git a/src/posix/hardware.h b/src/common/platform/posix/hardware.h similarity index 100% rename from src/posix/hardware.h rename to src/common/platform/posix/hardware.h diff --git a/src/common/platform/posix/i_system.h b/src/common/platform/posix/i_system.h new file mode 100644 index 00000000000..4d800d53b3b --- /dev/null +++ b/src/common/platform/posix/i_system.h @@ -0,0 +1,76 @@ +#ifndef __I_SYSTEM__ +#define __I_SYSTEM__ + +#include +#include + +#if defined(__sun) || defined(__sun__) || defined(__SRV4) || defined(__srv4__) +#define __solaris__ 1 +#endif + +#include +#include +#include "tarray.h" +#include "zstring.h" + +struct ticcmd_t; +struct WadStuff; + +#ifndef SHARE_DIR +#define SHARE_DIR "/usr/local/share/" +#endif + +void CalculateCPUSpeed(void); + +// Return a seed value for the RNG. +unsigned int I_MakeRNGSeed(); + + + +void I_StartFrame (void); + +void I_StartTic (void); + +// Print a console string +void I_PrintStr (const char *str); + +// Set the title string of the startup window +void I_SetIWADInfo (); + +// Pick from multiple IWADs to use +int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad, int&, FString &); + +// [RH] Checks the registry for Steam's install path, so we can scan its +// directories for IWADs if the user purchased any through Steam. +TArray I_GetSteamPath(); + +TArray I_GetGogPaths(); + +TArray I_GetBethesdaPath(); + +// The ini could not be saved at exit +bool I_WriteIniFailed (const char* filename); + +class FGameTexture; +bool I_SetCursor(FGameTexture *); + +static inline char *strlwr(char *str) +{ + char *ptr = str; + while(*ptr) + { + *ptr = tolower(*ptr); + ++ptr; + } + return str; +} + +inline int I_GetNumaNodeCount() { return 1; } +inline int I_GetNumaNodeThreadCount(int numaNode) { return std::max(std::thread::hardware_concurrency(), 1); } +inline void I_SetThreadNumaNode(std::thread &thread, int numaNode) { } + +FString I_GetCWD(); +bool I_ChDir(const char* path); +void I_OpenShellFolder(const char*); + +#endif diff --git a/src/common/platform/posix/i_system_posix.cpp b/src/common/platform/posix/i_system_posix.cpp new file mode 100644 index 00000000000..786706600aa --- /dev/null +++ b/src/common/platform/posix/i_system_posix.cpp @@ -0,0 +1,51 @@ +/* +**--------------------------------------------------------------------------- +** Copyright 2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include + +#ifdef __APPLE__ +#include +#endif // __APPLE__ + +#include "cmdlib.h" +#include "i_system.h" + + +bool I_WriteIniFailed(const char * filename) +{ + printf("The config file %s could not be saved:\n%s\n", filename, strerror(errno)); + return false; // return true to retry +} + +TArray I_GetBethesdaPath() +{ + // Bethesda.net Launcher is Windows only at the moment + return TArray(); +} diff --git a/src/posix/osx/i_specialpaths.mm b/src/common/platform/posix/osx/i_specialpaths.mm similarity index 86% rename from src/posix/osx/i_specialpaths.mm rename to src/common/platform/posix/osx/i_specialpaths.mm index 08be8c0bbb0..7d55157efd2 100644 --- a/src/posix/osx/i_specialpaths.mm +++ b/src/common/platform/posix/osx/i_specialpaths.mm @@ -36,9 +36,10 @@ #import #include "cmdlib.h" -#include "m_misc.h" #include "version.h" // for GAMENAME +#include "i_specialpaths.h" +FString M_GetMacAppSupportPath(const bool create); static FString GetSpecialPath(const NSSearchPathDirectory kind, const BOOL create = YES, const NSSearchPathDomainMask domain = NSUserDomainMask) { @@ -104,7 +105,7 @@ FString M_GetAppDataPath(bool create) } path += "/" GAMENAMELOWERCASE; - if (create) CreatePath(path); + if (create) CreatePath(path.GetChars()); return path; } @@ -126,7 +127,7 @@ FString M_GetCachePath(bool create) } path += "/zdoom/cache"; - if (create) CreatePath(path); + if (create) CreatePath(path.GetChars()); return path; } @@ -150,27 +151,6 @@ FString M_GetAutoexecPath() return path; } -//=========================================================================== -// -// M_GetCajunPath macOS -// -// Returns the location of the Cajun Bot definitions. -// -//=========================================================================== - -FString M_GetCajunPath(const char *botfilename) -{ - FString path; - - // Just copies the Windows code. Should this be more Mac-specific? - path << progdir << "zcajun/" << botfilename; - if (!FileExists(path)) - { - path = ""; - } - return path; -} - //=========================================================================== // // M_GetConfigPath macOS @@ -189,9 +169,9 @@ FString M_GetConfigPath(bool for_reading) { // There seems to be no way to get Preferences path via NSFileManager path += "/Preferences/"; - CreatePath(path); + CreatePath(path.GetChars()); - if (!DirExists(path)) + if (!DirExists(path.GetChars())) { path = FString(); } @@ -220,7 +200,7 @@ FString M_GetScreenshotsPath() { path += "/" GAME_DIR "/Screenshots/"; } - + CreatePath(path.GetChars()); return path; } @@ -261,5 +241,45 @@ FString M_GetDocumentsPath() path += "/" GAME_DIR "/"; } + CreatePath(path.GetChars()); + return path; +} + +//=========================================================================== +// +// M_GetDemoPath macOS +// +// Returns the path to the default demo directory. +// +//=========================================================================== + +FString M_GetDemoPath() +{ + FString path = GetSpecialPath(NSDocumentDirectory); + + if (path.IsNotEmpty()) + { + path += "/" GAME_DIR "/Demos/"; + } + + return path; +} + +//=========================================================================== +// +// M_NormalizedPath +// +// Normalizes the given path and returns the result. +// +//=========================================================================== + +FString M_GetNormalizedPath(const char* path) +{ + NSString *str = [NSString stringWithUTF8String:path]; + NSString *out; + if ([str completePathIntoString:&out caseSensitive:NO matchesIntoArray:nil filterTypes:nil]) + { + return out.UTF8String; + } return path; } diff --git a/src/posix/osx/iwadpicker_cocoa.mm b/src/common/platform/posix/osx/iwadpicker_cocoa.mm similarity index 90% rename from src/posix/osx/iwadpicker_cocoa.mm rename to src/common/platform/posix/osx/iwadpicker_cocoa.mm index fd9c600146b..f680829bfee 100644 --- a/src/posix/osx/iwadpicker_cocoa.mm +++ b/src/common/platform/posix/osx/iwadpicker_cocoa.mm @@ -34,13 +34,12 @@ */ #include "cmdlib.h" -#include "d_main.h" #include "version.h" #include "c_cvars.h" #include "m_argv.h" -#include "m_misc.h" #include "gameconfigfile.h" -#include "doomerrors.h" +#include "engineerrors.h" +#include "i_interface.h" #include #include @@ -67,8 +66,8 @@ @interface IWADTableData : NSObject - (void)dealloc; - (IWADTableData *)init:(WadStuff *) wads num:(int) numwads; -- (int)numberOfRowsInTableView:(NSTableView *)aTableView; -- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; +- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView; +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex; @end @implementation IWADTableData @@ -87,13 +86,13 @@ - (IWADTableData *)init:(WadStuff *) wads num:(int) numwads for(int i = 0;i < numwads;i++) { NSMutableDictionary *record = [[NSMutableDictionary alloc] initWithCapacity:NUM_COLUMNS]; - const char* filename = strrchr(wads[i].Path, '/'); + const char* filename = strrchr(wads[i].Path.GetChars(), '/'); if(filename == NULL) - filename = wads[i].Path; + filename = wads[i].Path.GetChars(); else filename++; [record setObject:[NSString stringWithUTF8String:filename] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_IWAD]]]; - [record setObject:[NSString stringWithUTF8String:wads[i].Name] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_GAME]]]; + [record setObject:[NSString stringWithUTF8String:wads[i].Name.GetChars()] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_GAME]]]; [data addObject:record]; [record release]; } @@ -101,12 +100,12 @@ - (IWADTableData *)init:(WadStuff *) wads num:(int) numwads return self; } -- (int)numberOfRowsInTableView:(NSTableView *)aTableView +- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { return [data count]; } -- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { NSParameterAssert(rowIndex >= 0 && (unsigned int) rowIndex < [data count]); NSMutableDictionary *record = [data objectAtIndex:rowIndex]; @@ -195,7 +194,7 @@ - (void)browseButtonPressed:(id) sender [openPanel setResolvesAliases:YES]; [openPanel setAllowedFileTypes:GetKnownExtensions()]; - if (NSOKButton == [openPanel runModal]) + if (NSModalResponseOK == [openPanel runModal]) { NSArray* files = [openPanel URLs]; NSMutableString* parameters = [NSMutableString string]; @@ -260,7 +259,7 @@ - (int)pickIWad:(WadStuff *)wads num:(int) numwads showWindow:(bool) showwin def id windowTitle = [NSString stringWithFormat:@"%s %s", GAMENAME, GetVersionString()]; NSRect frame = NSMakeRect(0, 0, 440, 450); - window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]; + window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSWindowStyleMaskTitled backing:NSBackingStoreBuffered defer:NO]; [window setTitle:windowTitle]; NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(18, 384, 402, 50)]; @@ -376,6 +375,8 @@ - (void)menuActionSent:(NSNotification*)notification return @"i386"; #elif defined __x86_64__ return @"x86_64"; +#elif defined __aarch64__ + return @"arm64"; #endif } @@ -383,34 +384,23 @@ static void RestartWithParameters(const WadStuff& wad, NSString* parameters) { assert(nil != parameters); - defaultiwad = wad.Name; - - GameConfig->DoGameSetup("Doom"); - M_SaveDefaults(NULL); - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @try { NSString* executablePath = [NSString stringWithUTF8String:Args->GetArg(0)]; + NSString* escapedParameters = [parameters stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; + NSString* cvarArgument = [NSString stringWithFormat:@"+osx_additional_parameters \"%@\"", escapedParameters]; NSMutableArray* const arguments = [[NSMutableArray alloc] init]; - - // The following value shoud be equal to NSAppKitVersionNumber10_5 - // It's hard-coded in order to build with earlier SDKs - const bool canSelectArchitecture = NSAppKitVersionNumber >= 949; - - if (canSelectArchitecture) - { - [arguments addObject:@"-arch"]; - [arguments addObject:GetArchitectureString()]; - [arguments addObject:executablePath]; - - executablePath = @"/usr/bin/arch"; - } - + [arguments addObject:@"-arch"]; + [arguments addObject:GetArchitectureString()]; + [arguments addObject:executablePath]; [arguments addObject:@"-iwad"]; - [arguments addObject:[NSString stringWithUTF8String:wad.Path]]; + [arguments addObject:[NSString stringWithUTF8String:wad.Path.GetChars()]]; + [arguments addObject:@"+defaultiwad"]; + [arguments addObject:[NSString stringWithUTF8String:wad.Name.GetChars()]]; + [arguments addObject:cvarArgument]; for (int i = 1, count = Args->NumArgs(); i < count; ++i) { @@ -432,7 +422,7 @@ static void RestartWithParameters(const WadStuff& wad, NSString* parameters) wordfree(&expansion); } - [NSTask launchedTaskWithLaunchPath:executablePath + [NSTask launchedTaskWithLaunchPath:@"/usr/bin/arch" arguments:arguments]; _exit(0); // to avoid atexit()'s functions @@ -453,11 +443,10 @@ int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad IWADPicker *picker = [IWADPicker alloc]; int ret = [picker pickIWad:wads num:numwads showWindow:showwin defaultWad:defaultiwad]; - NSString* parametersToAppend = [picker commandLineParameters]; - osx_additional_parameters = [parametersToAppend UTF8String]; - if (ret >= 0) { + NSString* parametersToAppend = [picker commandLineParameters]; + if (0 != [parametersToAppend length]) { RestartWithParameters(wads[ret], parametersToAppend); diff --git a/src/posix/readme.md b/src/common/platform/posix/readme.md similarity index 100% rename from src/posix/readme.md rename to src/common/platform/posix/readme.md diff --git a/src/posix/sdl/crashcatcher.c b/src/common/platform/posix/sdl/crashcatcher.c similarity index 97% rename from src/posix/sdl/crashcatcher.c rename to src/common/platform/posix/sdl/crashcatcher.c index be0e8f59902..c88e0fe8acb 100644 --- a/src/posix/sdl/crashcatcher.c +++ b/src/common/platform/posix/sdl/crashcatcher.c @@ -11,10 +11,12 @@ #ifndef PR_SET_PTRACER #define PR_SET_PTRACER 0x59616d61 #endif -#elif defined (__APPLE__) || defined (__FreeBSD__) || defined(__OpenBSD__) +#elif defined (__APPLE__) || defined (BSD) #include #endif +int I_FileAvailable(const char* filename); + static const char crash_switch[] = "--cc-handle-crash"; @@ -363,12 +365,11 @@ static void crash_handler(const char *logfile) if(logfile) { - const char *str; char buf[512]; - if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0) + if(I_FileAvailable("kdialog")) snprintf(buf, sizeof(buf), "kdialog --title \"Very Fatal Error\" --textbox \"%s\" 800 600", logfile); - else if((str=getenv("GNOME_DESKTOP_SESSION_ID")) && str[0] != '\0') + else if(I_FileAvailable("gxmessage")) snprintf(buf, sizeof(buf), "gxmessage -buttons \"Okay:0\" -geometry 800x600 -title \"Very Fatal Error\" -center -file \"%s\"", logfile); else snprintf(buf, sizeof(buf), "xmessage -buttons \"Okay:0\" -center -file \"%s\"", logfile); diff --git a/src/posix/sdl/gl_sysfb.h b/src/common/platform/posix/sdl/gl_sysfb.h similarity index 100% rename from src/posix/sdl/gl_sysfb.h rename to src/common/platform/posix/sdl/gl_sysfb.h diff --git a/src/common/platform/posix/sdl/hardware.cpp b/src/common/platform/posix/sdl/hardware.cpp new file mode 100644 index 00000000000..46daca4f964 --- /dev/null +++ b/src/common/platform/posix/sdl/hardware.cpp @@ -0,0 +1,85 @@ +/* +** hardware.cpp +** Somewhat OS-independant interface to the screen, mouse, keyboard, and stick +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include + +#include "i_system.h" +#include "hardware.h" +#include "c_dispatch.h" +#include "v_text.h" +#include "m_argv.h" +#include "c_console.h" +#include "printf.h" + +IVideo *Video; + +void I_RestartRenderer(); + + +void I_ShutdownGraphics () +{ + if (screen) + { + DFrameBuffer *s = screen; + screen = NULL; + delete s; + } + if (Video) + delete Video, Video = NULL; + + SDL_QuitSubSystem (SDL_INIT_VIDEO); +} + +void I_InitGraphics () +{ +#ifdef __APPLE__ + SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "0"); +#endif // __APPLE__ + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); + + if (SDL_InitSubSystem (SDL_INIT_VIDEO) < 0) + { + I_FatalError ("Could not initialize SDL video:\n%s\n", SDL_GetError()); + return; + } + + Printf("Using video driver %s\n", SDL_GetCurrentVideoDriver()); + + extern IVideo *gl_CreateVideo(); + Video = gl_CreateVideo(); + + if (Video == NULL) + I_FatalError ("Failed to initialize display"); +} diff --git a/src/posix/sdl/i_gui.cpp b/src/common/platform/posix/sdl/i_gui.cpp similarity index 94% rename from src/posix/sdl/i_gui.cpp rename to src/common/platform/posix/sdl/i_gui.cpp index 8ad9c8b9266..9290f063fdf 100644 --- a/src/posix/sdl/i_gui.cpp +++ b/src/common/platform/posix/sdl/i_gui.cpp @@ -36,23 +36,23 @@ #include #include "bitmap.h" -#include "v_palette.h" #include "textures.h" -bool I_SetCursor(FTexture *cursorpic) +bool I_SetCursor(FGameTexture *cursorpic) { static SDL_Cursor *cursor; static SDL_Surface *cursorSurface; if (cursorpic != NULL && cursorpic->isValid()) { - auto src = cursorpic->GetBgraBitmap(nullptr); + auto src = cursorpic->GetTexture()->GetBgraBitmap(nullptr); // Must be no larger than 32x32. if (src.GetWidth() > 32 || src.GetHeight() > 32) { return false; } + SDL_ShowCursor(SDL_DISABLE); if (cursorSurface == NULL) cursorSurface = SDL_CreateRGBSurface (0, 32, 32, 32, MAKEARGB(0,255,0,0), MAKEARGB(0,0,255,0), MAKEARGB(0,0,0,255), MAKEARGB(255,0,0,0)); @@ -68,6 +68,7 @@ bool I_SetCursor(FTexture *cursorpic) SDL_FreeCursor (cursor); cursor = SDL_CreateColorCursor (cursorSurface, 0, 0); SDL_SetCursor (cursor); + SDL_ShowCursor(SDL_ENABLE); } else { diff --git a/src/common/platform/posix/sdl/i_input.cpp b/src/common/platform/posix/sdl/i_input.cpp new file mode 100644 index 00000000000..02cf31e45fc --- /dev/null +++ b/src/common/platform/posix/sdl/i_input.cpp @@ -0,0 +1,498 @@ +/* +** i_input.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include +#include "m_argv.h" +#include "v_video.h" + +#include "d_eventbase.h" +#include "d_gui.h" +#include "c_buttons.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "dikeys.h" +#include "utf8.h" +#include "keydef.h" +#include "i_interface.h" +#include "engineerrors.h" +#include "i_interface.h" + + +static void I_CheckGUICapture (); +static void I_CheckNativeMouse (); + +bool GUICapture; +static bool NativeMouse = true; + +CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + + +extern int WaitingForKey; + +static const SDL_Keycode DIKToKeySym[256] = +{ + 0, SDLK_ESCAPE, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6, + SDLK_7, SDLK_8, SDLK_9, SDLK_0,SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSPACE, SDLK_TAB, + SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, SDLK_i, + SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, SDLK_RETURN, SDLK_LCTRL, SDLK_a, SDLK_s, + SDLK_d, SDLK_f, SDLK_g, SDLK_h, SDLK_j, SDLK_k, SDLK_l, SDLK_SEMICOLON, + SDLK_QUOTE, SDLK_BACKQUOTE, SDLK_LSHIFT, SDLK_BACKSLASH, SDLK_z, SDLK_x, SDLK_c, SDLK_v, + SDLK_b, SDLK_n, SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH, SDLK_RSHIFT, SDLK_KP_MULTIPLY, + SDLK_LALT, SDLK_SPACE, SDLK_CAPSLOCK, SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, + SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_NUMLOCKCLEAR, SDLK_SCROLLLOCK, SDLK_KP_7, + SDLK_KP_8, SDLK_KP_9, SDLK_KP_MINUS, SDLK_KP_4, SDLK_KP_5, SDLK_KP_6, SDLK_KP_PLUS, SDLK_KP_1, + SDLK_KP_2, SDLK_KP_3, SDLK_KP_0, SDLK_KP_PERIOD, 0, 0, 0, SDLK_F11, + SDLK_F12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, SDLK_F13, SDLK_F14, SDLK_F15, SDLK_F16, + SDLK_F17, SDLK_F18, SDLK_F19, SDLK_F20, SDLK_F21, SDLK_F22, SDLK_F23, SDLK_F24, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, SDLK_KP_EQUALS, 0, 0, + 0, SDLK_AT, SDLK_COLON, 0, 0, 0, 0, 0, + 0, 0, 0, 0, SDLK_KP_ENTER, SDLK_RCTRL, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, SDLK_KP_COMMA, 0, SDLK_KP_DIVIDE, 0, SDLK_SYSREQ, + SDLK_RALT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, SDLK_PAUSE, 0, SDLK_HOME, + SDLK_UP, SDLK_PAGEUP, 0, SDLK_LEFT, 0, SDLK_RIGHT, 0, SDLK_END, + SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE, 0, 0, 0, 0, + 0, 0, 0, SDLK_LGUI, SDLK_RGUI, SDLK_MENU, SDLK_POWER, SDLK_SLEEP, + 0, 0, 0, 0, 0, SDLK_AC_SEARCH, SDLK_AC_BOOKMARKS, SDLK_AC_REFRESH, + SDLK_AC_STOP, SDLK_AC_FORWARD, SDLK_AC_BACK, SDLK_COMPUTER, SDLK_MAIL, SDLK_MEDIASELECT, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const SDL_Scancode DIKToKeyScan[256] = +{ + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6, + SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9, SDL_SCANCODE_0 ,SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, SDL_SCANCODE_BACKSPACE, SDL_SCANCODE_TAB, + SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, SDL_SCANCODE_T, SDL_SCANCODE_Y, SDL_SCANCODE_U, SDL_SCANCODE_I, + SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_RETURN, SDL_SCANCODE_LCTRL, SDL_SCANCODE_A, SDL_SCANCODE_S, + SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H, SDL_SCANCODE_J, SDL_SCANCODE_K, SDL_SCANCODE_L, SDL_SCANCODE_SEMICOLON, + SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_GRAVE, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_BACKSLASH, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V, + SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M, SDL_SCANCODE_COMMA, SDL_SCANCODE_PERIOD, SDL_SCANCODE_SLASH, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_KP_MULTIPLY, + SDL_SCANCODE_LALT, SDL_SCANCODE_SPACE, SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_F1, SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5, + SDL_SCANCODE_F6, SDL_SCANCODE_F7, SDL_SCANCODE_F8, SDL_SCANCODE_F9, SDL_SCANCODE_F10, SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_KP_7, + SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_4, SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_KP_1, + SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_0, SDL_SCANCODE_KP_PERIOD, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F11, + SDL_SCANCODE_F12, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_F16, + SDL_SCANCODE_F17, SDL_SCANCODE_F18, SDL_SCANCODE_F19, SDL_SCANCODE_F20, SDL_SCANCODE_F21, SDL_SCANCODE_F22, SDL_SCANCODE_F23, SDL_SCANCODE_F24, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_EQUALS, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_RCTRL, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_COMMA, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_SYSREQ, + SDL_SCANCODE_RALT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_PAUSE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_HOME, + SDL_SCANCODE_UP, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_END, + SDL_SCANCODE_DOWN, SDL_SCANCODE_PAGEDOWN, SDL_SCANCODE_INSERT, SDL_SCANCODE_DELETE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LGUI, SDL_SCANCODE_RGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_POWER, SDL_SCANCODE_SLEEP, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_AC_SEARCH, SDL_SCANCODE_AC_BOOKMARKS, SDL_SCANCODE_AC_REFRESH, + SDL_SCANCODE_AC_STOP, SDL_SCANCODE_AC_FORWARD, SDL_SCANCODE_AC_BACK, SDL_SCANCODE_COMPUTER, SDL_SCANCODE_MAIL, SDL_SCANCODE_MEDIASELECT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN +}; + +static TMap InitKeySymMap () +{ + TMap KeySymToDIK; + + for (int i = 0; i < 256; ++i) + { + KeySymToDIK[DIKToKeySym[i]] = i; + } + KeySymToDIK[0] = 0; + KeySymToDIK[SDLK_RSHIFT] = DIK_LSHIFT; + KeySymToDIK[SDLK_RCTRL] = DIK_LCONTROL; + KeySymToDIK[SDLK_RALT] = DIK_LMENU; + // Depending on your Linux flavor, you may get SDLK_PRINT or SDLK_SYSREQ + KeySymToDIK[SDLK_PRINTSCREEN] = DIK_SYSRQ; + + return KeySymToDIK; +} +static const TMap KeySymToDIK(InitKeySymMap()); + +static TMap InitKeyScanMap () +{ + TMap KeyScanToDIK; + + for (int i = 0; i < 256; ++i) + { + KeyScanToDIK[DIKToKeyScan[i]] = i; + } + + return KeyScanToDIK; +} +static const TMap KeyScanToDIK(InitKeyScanMap()); + +static void I_CheckGUICapture () +{ + bool wantCapt = sysCallbacks.WantGuiCapture && sysCallbacks.WantGuiCapture(); + + if (wantCapt != GUICapture) + { + GUICapture = wantCapt; + if (wantCapt) + { + buttonMap.ResetButtonStates(); + } + } +} + +void I_SetMouseCapture() +{ + // Clear out any mouse movement. + SDL_GetRelativeMouseState (NULL, NULL); + SDL_SetRelativeMouseMode (SDL_TRUE); +} + +void I_ReleaseMouseCapture() +{ + SDL_SetRelativeMouseMode (SDL_FALSE); +} + +static void MouseRead () +{ + int x, y; + + if (NativeMouse) + { + return; + } + + SDL_GetRelativeMouseState (&x, &y); + PostMouseMove (x, y); +} + +static void I_CheckNativeMouse () +{ + bool focus = SDL_GetKeyboardFocus() != NULL; + + bool captureModeInGame = sysCallbacks.CaptureModeInGame && sysCallbacks.CaptureModeInGame(); + bool wantNative = !focus || (!use_mouse || GUICapture || !captureModeInGame); + + if (!wantNative && sysCallbacks.WantNativeMouse && sysCallbacks.WantNativeMouse()) + wantNative = true; + + if (wantNative != NativeMouse) + { + NativeMouse = wantNative; + SDL_ShowCursor (wantNative); + if (wantNative) + I_ReleaseMouseCapture (); + else + I_SetMouseCapture (); + } +} + +void MessagePump (const SDL_Event &sev) +{ + static int lastx = 0, lasty = 0; + int x, y; + event_t event = { 0,0,0,0,0,0,0 }; + + switch (sev.type) + { + case SDL_QUIT: + throw CExitEvent(0); + + case SDL_WINDOWEVENT: + extern void ProcessSDLWindowEvent(const SDL_WindowEvent &); + ProcessSDLWindowEvent(sev.window); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + if (!GUICapture) + { + event.type = sev.type == SDL_MOUSEBUTTONDOWN ? EV_KeyDown : EV_KeyUp; + + switch (sev.button.button) + { + case SDL_BUTTON_LEFT: event.data1 = KEY_MOUSE1; break; + case SDL_BUTTON_MIDDLE: event.data1 = KEY_MOUSE3; break; + case SDL_BUTTON_RIGHT: event.data1 = KEY_MOUSE2; break; + case SDL_BUTTON_X1: event.data1 = KEY_MOUSE4; break; + case SDL_BUTTON_X2: event.data1 = KEY_MOUSE5; break; + case 6: event.data1 = KEY_MOUSE6; break; + case 7: event.data1 = KEY_MOUSE7; break; + case 8: event.data1 = KEY_MOUSE8; break; + default: printf("SDL mouse button %s %d\n", + sev.type == SDL_MOUSEBUTTONDOWN ? "down" : "up", sev.button.button); break; + } + + if (event.data1 != 0) + { + D_PostEvent(&event); + } + } + else if ((sev.button.button >= SDL_BUTTON_LEFT && sev.button.button <= SDL_BUTTON_X2)) + { + int x, y; + SDL_GetMouseState(&x, &y); + + event.type = EV_GUI_Event; + event.data1 = x; + event.data2 = y; + + screen->ScaleCoordsFromWindow(event.data1, event.data2); + + if (sev.type == SDL_MOUSEBUTTONDOWN) + { + switch(sev.button.button) + { + case SDL_BUTTON_LEFT: event.subtype = EV_GUI_LButtonDown; break; + case SDL_BUTTON_MIDDLE: event.subtype = EV_GUI_MButtonDown; break; + case SDL_BUTTON_RIGHT: event.subtype = EV_GUI_RButtonDown; break; + case SDL_BUTTON_X1: event.subtype = EV_GUI_BackButtonDown; break; + case SDL_BUTTON_X2: event.subtype = EV_GUI_FwdButtonDown; break; + default: assert(false); event.subtype = EV_GUI_None; break; + } + } + else + { + switch(sev.button.button) + { + case SDL_BUTTON_LEFT: event.subtype = EV_GUI_LButtonUp; break; + case SDL_BUTTON_MIDDLE: event.subtype = EV_GUI_MButtonUp; break; + case SDL_BUTTON_RIGHT: event.subtype = EV_GUI_RButtonUp; break; + case SDL_BUTTON_X1: event.subtype = EV_GUI_BackButtonUp; break; + case SDL_BUTTON_X2: event.subtype = EV_GUI_FwdButtonUp; break; + default: assert(false); event.subtype = EV_GUI_None; break; + } + } + + SDL_Keymod kmod = SDL_GetModState(); + event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | + ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | + ((kmod & KMOD_ALT) ? GKM_ALT : 0); + + D_PostEvent(&event); + } + break; + + case SDL_MOUSEMOTION: + if (GUICapture) + { + event.data1 = sev.motion.x; + event.data2 = sev.motion.y; + + screen->ScaleCoordsFromWindow(event.data1, event.data2); + + event.type = EV_GUI_Event; + event.subtype = EV_GUI_MouseMove; + + SDL_Keymod kmod = SDL_GetModState(); + event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | + ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | + ((kmod & KMOD_ALT) ? GKM_ALT : 0); + + D_PostEvent(&event); + } + break; + + case SDL_MOUSEWHEEL: + if (GUICapture) + { + event.type = EV_GUI_Event; + + if (sev.wheel.y == 0) + event.subtype = sev.wheel.x > 0 ? EV_GUI_WheelRight : EV_GUI_WheelLeft; + else + event.subtype = sev.wheel.y > 0 ? EV_GUI_WheelUp : EV_GUI_WheelDown; + + SDL_Keymod kmod = SDL_GetModState(); + event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | + ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | + ((kmod & KMOD_ALT) ? GKM_ALT : 0); + + D_PostEvent (&event); + } + else + { + event.type = EV_KeyDown; + + if (sev.wheel.y != 0) + event.data1 = sev.wheel.y > 0 ? KEY_MWHEELUP : KEY_MWHEELDOWN; + else + event.data1 = sev.wheel.x > 0 ? KEY_MWHEELRIGHT : KEY_MWHEELLEFT; + + D_PostEvent (&event); + event.type = EV_KeyUp; + D_PostEvent (&event); + } + break; + + case SDL_KEYDOWN: + case SDL_KEYUP: + if (!GUICapture) + { + if (sev.key.repeat) + { + break; + } + + event.type = sev.type == SDL_KEYDOWN ? EV_KeyDown : EV_KeyUp; + + // Try to look up our key mapped key for conversion to DirectInput. + // If that fails, then we'll do a lookup against the scan code, + // which may not return the right key, but at least the key should + // work in the game. + if (const uint8_t *dik = KeySymToDIK.CheckKey (sev.key.keysym.sym)) + event.data1 = *dik; + else if (const uint8_t *dik = KeyScanToDIK.CheckKey (sev.key.keysym.scancode)) + event.data1 = *dik; + + if (event.data1) + { + if (sev.key.keysym.sym < 256) + { + event.data2 = sev.key.keysym.sym; + } + D_PostEvent (&event); + } + } + else + { + event.type = EV_GUI_Event; + event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp; + SDL_Keymod kmod = SDL_GetModState(); + event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | + ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | + ((kmod & KMOD_ALT) ? GKM_ALT : 0); + + if (event.subtype == EV_GUI_KeyDown && sev.key.repeat) + { + event.subtype = EV_GUI_KeyRepeat; + } + + switch (sev.key.keysym.sym) + { + case SDLK_KP_ENTER: event.data1 = GK_RETURN; break; + case SDLK_PAGEUP: event.data1 = GK_PGUP; break; + case SDLK_PAGEDOWN: event.data1 = GK_PGDN; break; + case SDLK_END: event.data1 = GK_END; break; + case SDLK_HOME: event.data1 = GK_HOME; break; + case SDLK_LEFT: event.data1 = GK_LEFT; break; + case SDLK_RIGHT: event.data1 = GK_RIGHT; break; + case SDLK_UP: event.data1 = GK_UP; break; + case SDLK_DOWN: event.data1 = GK_DOWN; break; + case SDLK_DELETE: event.data1 = GK_DEL; break; + case SDLK_ESCAPE: event.data1 = GK_ESCAPE; break; + case SDLK_F1: event.data1 = GK_F1; break; + case SDLK_F2: event.data1 = GK_F2; break; + case SDLK_F3: event.data1 = GK_F3; break; + case SDLK_F4: event.data1 = GK_F4; break; + case SDLK_F5: event.data1 = GK_F5; break; + case SDLK_F6: event.data1 = GK_F6; break; + case SDLK_F7: event.data1 = GK_F7; break; + case SDLK_F8: event.data1 = GK_F8; break; + case SDLK_F9: event.data1 = GK_F9; break; + case SDLK_F10: event.data1 = GK_F10; break; + case SDLK_F11: event.data1 = GK_F11; break; + case SDLK_F12: event.data1 = GK_F12; break; + default: + if (sev.key.keysym.sym < 256) + { + event.data1 = sev.key.keysym.sym; + } + break; + } + if (event.data1 < 128) + { + event.data1 = toupper(event.data1); + D_PostEvent (&event); + } + } + break; + + case SDL_TEXTINPUT: + if (GUICapture) + { + int size; + + int unichar = utf8_decode((const uint8_t*)sev.text.text, &size); + if (size != 4) + { + event.type = EV_GUI_Event; + event.subtype = EV_GUI_Char; + event.data1 = (int16_t)unichar; + event.data2 = !!(SDL_GetModState() & KMOD_ALT); + D_PostEvent (&event); + } + } + break; + + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + event.type = sev.type == SDL_JOYBUTTONDOWN ? EV_KeyDown : EV_KeyUp; + event.data1 = KEY_FIRSTJOYBUTTON + sev.jbutton.button; + if(event.data1 != 0) + D_PostEvent(&event); + break; + } +} + +void I_GetEvent () +{ + SDL_Event sev; + + while (SDL_PollEvent (&sev)) + { + MessagePump (sev); + } + if (use_mouse) + { + MouseRead (); + } +} + +void I_StartTic () +{ + I_CheckGUICapture (); + I_CheckNativeMouse (); + I_GetEvent (); +} + +void I_ProcessJoysticks (); +void I_StartFrame () +{ + I_ProcessJoysticks(); +} diff --git a/src/common/platform/posix/sdl/i_joystick.cpp b/src/common/platform/posix/sdl/i_joystick.cpp new file mode 100644 index 00000000000..42837ecba64 --- /dev/null +++ b/src/common/platform/posix/sdl/i_joystick.cpp @@ -0,0 +1,368 @@ +/* +** i_joystick.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include + +#include "basics.h" +#include "cmdlib.h" + +#include "m_joy.h" +#include "keydef.h" + +#define DEFAULT_DEADZONE 0.25f; + +// Very small deadzone so that floating point magic doesn't happen +#define MIN_DEADZONE 0.000001f + +class SDLInputJoystick: public IJoystickConfig +{ +public: + SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f) , Enabled(true) + { + Device = SDL_JoystickOpen(DeviceIndex); + if(Device != NULL) + { + NumAxes = SDL_JoystickNumAxes(Device); + NumHats = SDL_JoystickNumHats(Device); + + SetDefaultConfig(); + } + } + ~SDLInputJoystick() + { + if(Device != NULL) + M_SaveJoystickConfig(this); + SDL_JoystickClose(Device); + } + + bool IsValid() const + { + return Device != NULL; + } + + FString GetName() + { + return SDL_JoystickName(Device); + } + float GetSensitivity() + { + return Multiplier; + } + void SetSensitivity(float scale) + { + Multiplier = scale; + } + + int GetNumAxes() + { + return NumAxes + NumHats*2; + } + float GetAxisDeadZone(int axis) + { + return Axes[axis].DeadZone; + } + EJoyAxis GetAxisMap(int axis) + { + return Axes[axis].GameAxis; + } + const char *GetAxisName(int axis) + { + return Axes[axis].Name.GetChars(); + } + float GetAxisScale(int axis) + { + return Axes[axis].Multiplier; + } + + void SetAxisDeadZone(int axis, float zone) + { + Axes[axis].DeadZone = clamp(zone, MIN_DEADZONE, 1.f); + } + void SetAxisMap(int axis, EJoyAxis gameaxis) + { + Axes[axis].GameAxis = gameaxis; + } + void SetAxisScale(int axis, float scale) + { + Axes[axis].Multiplier = scale; + } + + // Used by the saver to not save properties that are at their defaults. + bool IsSensitivityDefault() + { + return Multiplier == 1.0f; + } + bool IsAxisDeadZoneDefault(int axis) + { + return Axes[axis].DeadZone <= MIN_DEADZONE; + } + bool IsAxisMapDefault(int axis) + { + if(axis >= 5) + return Axes[axis].GameAxis == JOYAXIS_None; + return Axes[axis].GameAxis == DefaultAxes[axis]; + } + bool IsAxisScaleDefault(int axis) + { + return Axes[axis].Multiplier == 1.0f; + } + + void SetDefaultConfig() + { + for(int i = 0;i < GetNumAxes();i++) + { + AxisInfo info; + if(i < NumAxes) + info.Name.Format("Axis %d", i+1); + else + info.Name.Format("Hat %d (%c)", (i-NumAxes)/2 + 1, (i-NumAxes)%2 == 0 ? 'x' : 'y'); + info.DeadZone = DEFAULT_DEADZONE; + info.Multiplier = 1.0f; + info.Value = 0.0; + info.ButtonValue = 0; + if(i >= 5) + info.GameAxis = JOYAXIS_None; + else + info.GameAxis = DefaultAxes[i]; + Axes.Push(info); + } + } + + bool GetEnabled() + { + return Enabled; + } + + void SetEnabled(bool enabled) + { + Enabled = enabled; + } + + bool AllowsEnabledInBackground() { return false; } + bool GetEnabledInBackground() { return false; } + void SetEnabledInBackground(bool enabled) {} + + FString GetIdentifier() + { + char id[16]; + snprintf(id, countof(id), "JS:%d", DeviceIndex); + return id; + } + + void AddAxes(float axes[NUM_JOYAXIS]) + { + // Add to game axes. + for (int i = 0; i < GetNumAxes(); ++i) + { + if(Axes[i].GameAxis != JOYAXIS_None) + axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier); + } + } + + void ProcessInput() + { + uint8_t buttonstate; + + for (int i = 0; i < NumAxes; ++i) + { + buttonstate = 0; + + Axes[i].Value = SDL_JoystickGetAxis(Device, i)/32767.0; + Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate); + + // Map button to axis + // X and Y are handled differently so if we have 2 or more axes then we'll use that code instead. + if (NumAxes == 1 || (i >= 2 && i < NUM_JOYAXISBUTTONS)) + { + Joy_GenerateButtonEvents(Axes[i].ButtonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2); + Axes[i].ButtonValue = buttonstate; + } + } + + if(NumAxes > 1) + { + buttonstate = Joy_XYAxesToButtons(Axes[0].Value, Axes[1].Value); + Joy_GenerateButtonEvents(Axes[0].ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS); + Axes[0].ButtonValue = buttonstate; + } + + // Map POV hats to buttons and axes. Why axes? Well apparently I have + // a gamepad where the left control stick is a POV hat (instead of the + // d-pad like you would expect, no that's pressure sensitive). Also + // KDE's joystick dialog maps them to axes as well. + for (int i = 0; i < NumHats; ++i) + { + AxisInfo &x = Axes[NumAxes + i*2]; + AxisInfo &y = Axes[NumAxes + i*2 + 1]; + + buttonstate = SDL_JoystickGetHat(Device, i); + + // If we're going to assume that we can pass SDL's value into + // Joy_GenerateButtonEvents then we might as well assume the format here. + if(buttonstate & 0x1) // Up + y.Value = -1.0; + else if(buttonstate & 0x4) // Down + y.Value = 1.0; + else + y.Value = 0.0; + if(buttonstate & 0x2) // Left + x.Value = 1.0; + else if(buttonstate & 0x8) // Right + x.Value = -1.0; + else + x.Value = 0.0; + + if(i < 4) + { + Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4); + x.ButtonValue = buttonstate; + } + } + } + +protected: + struct AxisInfo + { + FString Name; + float DeadZone; + float Multiplier; + EJoyAxis GameAxis; + double Value; + uint8_t ButtonValue; + }; + static const EJoyAxis DefaultAxes[5]; + + int DeviceIndex; + SDL_Joystick *Device; + + float Multiplier; + bool Enabled; + TArray Axes; + int NumAxes; + int NumHats; + + friend class SDLInputJoystickManager; +}; + +// [Nash 4 Feb 2024] seems like on Linux, the third axis is actually the Left Trigger, resulting in the player uncontrollably looking upwards. +const EJoyAxis SDLInputJoystick::DefaultAxes[5] = {JOYAXIS_Side, JOYAXIS_Forward, JOYAXIS_None, JOYAXIS_Yaw, JOYAXIS_Pitch}; + +class SDLInputJoystickManager +{ +public: + SDLInputJoystickManager() + { + for(int i = 0;i < SDL_NumJoysticks();i++) + { + SDLInputJoystick *device = new SDLInputJoystick(i); + if(device->IsValid()) + Joysticks.Push(device); + else + delete device; + } + } + ~SDLInputJoystickManager() + { + for(unsigned int i = 0;i < Joysticks.Size();i++) + delete Joysticks[i]; + } + + void AddAxes(float axes[NUM_JOYAXIS]) + { + for(unsigned int i = 0;i < Joysticks.Size();i++) + Joysticks[i]->AddAxes(axes); + } + void GetDevices(TArray &sticks) + { + for(unsigned int i = 0;i < Joysticks.Size();i++) + { + M_LoadJoystickConfig(Joysticks[i]); + sticks.Push(Joysticks[i]); + } + } + + void ProcessInput() const + { + for(unsigned int i = 0;i < Joysticks.Size();++i) + if(Joysticks[i]->Enabled) Joysticks[i]->ProcessInput(); + } +protected: + TArray Joysticks; +}; +static SDLInputJoystickManager *JoystickManager; + +void I_StartupJoysticks() +{ +#ifndef NO_SDL_JOYSTICK + if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0) + JoystickManager = new SDLInputJoystickManager(); +#endif +} +void I_ShutdownInput() +{ + if(JoystickManager) + { + delete JoystickManager; + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + } +} + +void I_GetJoysticks(TArray &sticks) +{ + sticks.Clear(); + + if (JoystickManager) + JoystickManager->GetDevices(sticks); +} + +void I_GetAxes(float axes[NUM_JOYAXIS]) +{ + for (int i = 0; i < NUM_JOYAXIS; ++i) + { + axes[i] = 0; + } + if (use_joystick && JoystickManager) + { + JoystickManager->AddAxes(axes); + } +} + +void I_ProcessJoysticks() +{ + if (use_joystick && JoystickManager) + JoystickManager->ProcessInput(); +} + +IJoystickConfig *I_UpdateDeviceList() +{ + return NULL; +} diff --git a/src/common/platform/posix/sdl/i_main.cpp b/src/common/platform/posix/sdl/i_main.cpp new file mode 100644 index 00000000000..4f29bb76ec3 --- /dev/null +++ b/src/common/platform/posix/sdl/i_main.cpp @@ -0,0 +1,204 @@ +/* +** i_main.cpp +** System-specific startup code. Eventually calls D_DoomMain. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "engineerrors.h" +#include "m_argv.h" +#include "c_console.h" +#include "version.h" +#include "cmdlib.h" +#include "engineerrors.h" +#include "i_system.h" +#include "i_interface.h" +#include "printf.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +extern "C" int cc_install_handlers(int, char**, int, int*, const char*, int(*)(char*, char*)); + +#ifdef __APPLE__ +void Mac_I_FatalError(const char* errortext); +#endif + +#ifdef __linux__ +void Linux_I_FatalError(const char* errortext); +#endif + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- +int GameMain(); + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- +FString sys_ostype; + +// The command line arguments. +FArgs *Args; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + + +// CODE -------------------------------------------------------------------- + + + +static int GetCrashInfo (char *buffer, char *end) +{ + if (sysCallbacks.CrashInfo) sysCallbacks.CrashInfo(buffer, end - buffer, "\n"); + return strlen(buffer); +} + +void I_DetectOS() +{ + FString operatingSystem; + + const char *paths[] = {"/etc/os-release", "/usr/lib/os-release"}; + + for (const char *path : paths) + { + struct stat dummy; + + if (stat(path, &dummy) != 0) + continue; + + char cmdline[256]; + snprintf(cmdline, sizeof cmdline, ". %s && echo ${PRETTY_NAME}", path); + + FILE *proc = popen(cmdline, "r"); + + if (proc == nullptr) + continue; + + char distribution[256] = {}; + fread(distribution, sizeof distribution - 1, 1, proc); + + const size_t length = strlen(distribution); + + if (length > 1) + { + distribution[length - 1] = '\0'; + operatingSystem = distribution; + } + + pclose(proc); + break; + } + + utsname unameInfo; + + if (uname(&unameInfo) == 0) + { + const char* const separator = operatingSystem.Len() > 0 ? ", " : ""; + operatingSystem.AppendFormat("%s%s %s on %s", separator, unameInfo.sysname, unameInfo.release, unameInfo.machine); + sys_ostype.Format("%s %s on %s", unameInfo.sysname, unameInfo.release, unameInfo.machine); + } + + if (operatingSystem.Len() > 0) + Printf("OS: %s\n", operatingSystem.GetChars()); +} + +void I_StartupJoysticks(); + +int main (int argc, char **argv) +{ +#if !defined (__APPLE__) + { + int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS }; + cc_install_handlers(argc, argv, 4, s, GAMENAMELOWERCASE "-crash.log", GetCrashInfo); + } +#endif // !__APPLE__ + + printf(GAMENAME" %s - %s - SDL version\nCompiled on %s\n", + GetVersionString(), GetGitTime(), __DATE__); + + seteuid (getuid ()); + // Set LC_NUMERIC environment variable in case some library decides to + // clear the setlocale call at least this will be correct. + // Note that the LANG environment variable is overridden by LC_* + setenv ("LC_NUMERIC", "C", 1); + + setlocale (LC_ALL, "C"); + + if (SDL_Init (0) < 0) + { + fprintf (stderr, "Could not initialize SDL:\n%s\n", SDL_GetError()); + return -1; + } + + printf("\n"); + + Args = new FArgs(argc, argv); + +#ifdef PROGDIR + progdir = PROGDIR; +#else + char program[PATH_MAX]; + if (realpath (argv[0], program) == NULL) + strcpy (program, argv[0]); + char *slash = strrchr (program, '/'); + if (slash != NULL) + { + *(slash + 1) = '\0'; + progdir = program; + } + else + { + progdir = "./"; + } +#endif + + I_StartupJoysticks(); + + const int result = GameMain(); + + SDL_Quit(); + + return result; +} diff --git a/src/common/platform/posix/sdl/i_system.cpp b/src/common/platform/posix/sdl/i_system.cpp new file mode 100644 index 00000000000..2c28368b005 --- /dev/null +++ b/src/common/platform/posix/sdl/i_system.cpp @@ -0,0 +1,390 @@ +/* +** i_system.cpp +** Main startup code +** +**--------------------------------------------------------------------------- +** Copyright 1999-2016 Randy Heit +** Copyright 2019-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#include +#endif + +#include + +#include "version.h" +#include "cmdlib.h" +#include "m_argv.h" +#include "i_sound.h" +#include "i_interface.h" +#include "v_font.h" +#include "c_cvars.h" +#include "palutil.h" +#include "st_start.h" +#include "printf.h" +#include "launcherwindow.h" + +#ifndef NO_GTK +bool I_GtkAvailable (); +void I_ShowFatalError_Gtk(const char* errortext); +#elif defined(__APPLE__) +int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad); +#endif + +double PerfToSec, PerfToMillisec; +CVAR(Bool, con_printansi, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE); +CVAR(Bool, con_4bitansi, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE); +EXTERN_CVAR(Bool, longsavemessages) + +extern FStartupScreen *StartWindow; + +void I_SetIWADInfo() +{ +} + +extern "C" int I_FileAvailable(const char* filename) +{ + FString cmd = "which {0} >/dev/null 2>&1"; + cmd.Substitute("{0}", filename); + + if (FILE* f = popen(cmd.GetChars(), "r")) + { + int status = pclose(f); + return WIFEXITED(status) && WEXITSTATUS(status) == 0; + } + + return 0; +} + +// +// I_Error +// + +#ifdef __APPLE__ +void Mac_I_FatalError(const char* errortext); +#endif + +#ifdef __unix__ +void Unix_I_FatalError(const char* errortext) +{ + // Close window or exit fullscreen and release mouse capture + SDL_QuitSubSystem(SDL_INIT_VIDEO); + + if(I_FileAvailable("kdialog")) + { + FString cmd; + cmd << "kdialog --title \"" GAMENAME " " << GetVersionString() + << "\" --msgbox \"" << errortext << "\""; + popen(cmd.GetChars(), "r"); + } +#ifndef NO_GTK + else if (I_GtkAvailable()) + { + I_ShowFatalError_Gtk(errortext); + } +#endif + else + { + FString title; + title << GAMENAME " " << GetVersionString(); + + if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title.GetChars(), errortext, NULL) < 0) + { + printf("\n%s\n", errortext); + } + } +} +#endif + + +void I_ShowFatalError(const char *message) +{ +#ifdef __APPLE__ + Mac_I_FatalError(message); +#elif defined __unix__ + Unix_I_FatalError(message); +#else + // ??? +#endif +} + +bool PerfAvailable; + +void CalculateCPUSpeed() +{ + PerfAvailable = false; + PerfToMillisec = PerfToSec = 0.; +#ifdef __aarch64__ + // [MK] on aarch64 rather than having to calculate cpu speed, there is + // already an independent frequency for the perf timer + uint64_t frq; + asm volatile("mrs %0, cntfrq_el0":"=r"(frq)); + PerfAvailable = true; + PerfToSec = 1./frq; + PerfToMillisec = PerfToSec*1000.; +#elif defined(__linux__) + // [MK] read from perf values if we can + struct perf_event_attr pe; + memset(&pe,0,sizeof(struct perf_event_attr)); + pe.type = PERF_TYPE_HARDWARE; + pe.size = sizeof(struct perf_event_attr); + pe.config = PERF_COUNT_HW_INSTRUCTIONS; + pe.disabled = 1; + pe.exclude_kernel = 1; + pe.exclude_hv = 1; + int fd = syscall(__NR_perf_event_open, &pe, 0, -1, -1, 0); + if (fd == -1) + { + return; + } + void *addr = mmap(nullptr, 4096, PROT_READ, MAP_SHARED, fd, 0); + if (addr == nullptr) + { + close(fd); + return; + } + struct perf_event_mmap_page *pc = (struct perf_event_mmap_page *)addr; + if (pc->cap_user_time != 1) + { + close(fd); + return; + } + double mhz = (1000LU << pc->time_shift) / (double)pc->time_mult; + PerfAvailable = true; + PerfToSec = .000001/mhz; + PerfToMillisec = PerfToSec*1000.; + if (!batchrun) Printf("CPU speed: %.0f MHz\n", mhz); + close(fd); +#endif +} + +void CleanProgressBar() +{ + if (!isatty(STDOUT_FILENO)) return; + struct winsize sizeOfWindow; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &sizeOfWindow); + fprintf(stdout,"\0337\033[%d;%dH\033[0J\0338",sizeOfWindow.ws_row, 0); + fflush(stdout); +} + +static int ProgressBarCurPos, ProgressBarMaxPos; + +void RedrawProgressBar(int CurPos, int MaxPos) +{ + if (!isatty(STDOUT_FILENO)) return; + CleanProgressBar(); + struct winsize sizeOfWindow; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &sizeOfWindow); + int windowColClamped = std::min((int)sizeOfWindow.ws_col, 512); + double progVal = std::clamp((double)CurPos / (double)MaxPos,0.0,1.0); + int curProgVal = std::clamp(int(windowColClamped * progVal),0,windowColClamped); + + char progressBuffer[512]; + memset(progressBuffer,'.',512); + progressBuffer[windowColClamped - 1] = 0; + int lengthOfStr = 0; + + while (curProgVal-- > 0) + { + progressBuffer[lengthOfStr++] = '='; + if (lengthOfStr >= windowColClamped - 1) break; + } + fprintf(stdout, "\0337\033[%d;%dH\033[2K[%s\033[%d;%dH]\0338", sizeOfWindow.ws_row, 0, progressBuffer, sizeOfWindow.ws_row, windowColClamped); + fflush(stdout); + ProgressBarCurPos = CurPos; + ProgressBarMaxPos = MaxPos; +} + +void I_PrintStr(const char *cp) +{ + const char * srcp = cp; + FString printData = ""; + bool terminal = isatty(STDOUT_FILENO); + + while (*srcp != 0) + { + if (*srcp == 0x1c && con_printansi && terminal) + { + srcp += 1; + const uint8_t* scratch = (const uint8_t*)srcp; // GCC does not like direct casting of the parameter. + EColorRange range = V_ParseFontColor(scratch, CR_UNTRANSLATED, CR_YELLOW); + srcp = (char*)scratch; + if (range != CR_UNDEFINED) + { + PalEntry color = V_LogColorFromColorRange(range); + if (con_4bitansi) + { + float h, s, v, r, g, b; + int attrib = 0; + + RGBtoHSV(color.r / 255.f, color.g / 255.f, color.b / 255.f, &h, &s, &v); + if (s != 0) + { // color + HSVtoRGB(&r, &g, &b, h, 1, 1); + if (r == 1) attrib = 0x1; + if (g == 1) attrib |= 0x2; + if (b == 1) attrib |= 0x4; + if (v > 0.6) attrib |= 0x8; + } + else + { // gray + if (v < 0.33) attrib = 0x8; + else if (v < 0.90) attrib = 0x7; + else attrib = 0xF; + } + + printData.AppendFormat("\033[%um",((attrib & 0x8) ? 90 : 30) + (attrib & 0x7)); + } + else printData.AppendFormat("\033[38;2;%u;%u;%um",color.r,color.g,color.b); + } + } + else if (*srcp != 0x1c && *srcp != 0x1d && *srcp != 0x1e && *srcp != 0x1f) + { + printData += *srcp++; + } + else + { + if (srcp[1] != 0) srcp += 2; + else break; + } + } + + if (StartWindow) CleanProgressBar(); + fputs(printData.GetChars(),stdout); + if (terminal) fputs("\033[0m",stdout); + if (StartWindow) RedrawProgressBar(ProgressBarCurPos,ProgressBarMaxPos); +} + +int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags, FString &extraArgs) +{ + if (!showwin) + { + return defaultiwad; + } + +#ifdef __APPLE__ + return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad); +#else + return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags, &extraArgs); +#endif +} + +void I_PutInClipboard (const char *str) +{ + SDL_SetClipboardText(str); +} + +FString I_GetFromClipboard (bool use_primary_selection) +{ + if(char *ret = SDL_GetClipboardText()) + { + FString text(ret); + SDL_free(ret); + return text; + } + return ""; +} + +FString I_GetCWD() +{ + char* curdir = getcwd(NULL,0); + if (!curdir) + { + return ""; + } + FString ret(curdir); + free(curdir); + return ret; +} + +bool I_ChDir(const char* path) +{ + return chdir(path) == 0; +} + +// Return a random seed, preferably one with lots of entropy. +unsigned int I_MakeRNGSeed() +{ + unsigned int seed; + int file; + + // Try reading from /dev/urandom first, then /dev/random, then + // if all else fails, use a crappy seed from time(). + seed = time(NULL); + file = open("/dev/urandom", O_RDONLY); + if (file < 0) + { + file = open("/dev/random", O_RDONLY); + } + if (file >= 0) + { + read(file, &seed, sizeof(seed)); + close(file); + } + return seed; +} + +void I_OpenShellFolder(const char* infolder) +{ + char* curdir = getcwd(NULL,0); + + if (!chdir(infolder)) + { + if (longsavemessages) + Printf("Opening folder: %s\n", infolder); + std::system("xdg-open ."); + chdir(curdir); + } + else + { + if (longsavemessages) + Printf("Unable to open directory '%s\n", infolder); + else + Printf("Unable to open requested directory\n"); + } + free(curdir); +} + diff --git a/src/common/platform/posix/sdl/i_system.mm b/src/common/platform/posix/sdl/i_system.mm new file mode 100644 index 00000000000..f9212f08cce --- /dev/null +++ b/src/common/platform/posix/sdl/i_system.mm @@ -0,0 +1,19 @@ +#include +#include "SDL.h" + +void Mac_I_FatalError(const char* errortext) +{ + // Close window or exit fullscreen and release mouse capture + SDL_Quit(); + + const CFStringRef errorString = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault, + errortext, kCFStringEncodingASCII, kCFAllocatorNull ); + if ( NULL != errorString ) + { + CFOptionFlags dummy; + + CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, + CFSTR( "Fatal Error" ), errorString, CFSTR( "Exit" ), NULL, NULL, &dummy ); + CFRelease( errorString ); + } +} diff --git a/src/common/platform/posix/sdl/sdlglvideo.cpp b/src/common/platform/posix/sdl/sdlglvideo.cpp new file mode 100644 index 00000000000..92bdb15a731 --- /dev/null +++ b/src/common/platform/posix/sdl/sdlglvideo.cpp @@ -0,0 +1,701 @@ +/* +** sdlglvideo.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Christoph Oelckers et.al. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include "i_module.h" +#include "i_soundinternal.h" +#include "i_system.h" +#include "i_video.h" +#include "m_argv.h" +#include "v_video.h" +#include "version.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "printf.h" + +#include "hardware.h" +#include "gl_sysfb.h" +#include "gl_system.h" + +#include "gl_renderer.h" +#include "gl_framebuffer.h" +#ifdef HAVE_GLES2 +#include "gles_framebuffer.h" +#endif + +#ifdef HAVE_VULKAN +#include "vulkan/system/vk_renderdevice.h" +#include +#include +#include +#include +#endif + +// MACROS ------------------------------------------------------------------ + +#if defined HAVE_VULKAN +#include +#endif // HAVE_VULKAN + +// TYPES ------------------------------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- +extern IVideo *Video; + +EXTERN_CVAR (Int, vid_adapter) +EXTERN_CVAR (Int, vid_displaybits) +EXTERN_CVAR (Int, vid_defwidth) +EXTERN_CVAR (Int, vid_defheight) +EXTERN_CVAR (Bool, cl_capfps) +EXTERN_CVAR(Bool, vk_debug) + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} +CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} + +CUSTOM_CVAR(String, vid_sdl_render_driver, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} + +CCMD(vid_list_sdl_render_drivers) +{ + for (int i = 0; i < SDL_GetNumRenderDrivers(); ++i) + { + SDL_RendererInfo info; + if (SDL_GetRenderDriverInfo(i, &info) == 0) + Printf("%s\n", info.name); + } +} + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +namespace Priv +{ + SDL_Window *window; + bool vulkanEnabled; + bool softpolyEnabled; + bool fullscreenSwitch; + int numberOfDisplays; + SDL_Rect* displayBounds = nullptr; + + void updateDisplayInfo() + { + Priv::numberOfDisplays = SDL_GetNumVideoDisplays(); + if (Priv::numberOfDisplays <= 0) { + Printf("%sWrong number of displays detected.\n", TEXTCOLOR_BOLD); + return; + } + Printf("Number of detected displays %d .\n", Priv::numberOfDisplays); + + if (Priv::displayBounds != nullptr) { + free(Priv::displayBounds); + } + Priv::displayBounds = (SDL_Rect*) calloc(Priv::numberOfDisplays, sizeof(SDL_Rect)); + + for (int i=0; i < Priv::numberOfDisplays; i++) { + if (0 != SDL_GetDisplayBounds(i, &Priv::displayBounds[i])) { + Printf("%sError getting display %d size: %s\n", TEXTCOLOR_BOLD, i, SDL_GetError()); + if (i == 0) { + free(Priv::displayBounds); + displayBounds = nullptr; + } + Priv::numberOfDisplays = i; + return; + } + } + } + + void CreateWindow(uint32_t extraFlags) + { + assert(Priv::window == nullptr); + + // Get displays and default display size + updateDisplayInfo(); + + // TODO control better when updateDisplayInfo fails + SDL_Rect* bounds = &displayBounds[vid_adapter % numberOfDisplays]; + + if (win_w <= 0 || win_h <= 0) + { + win_w = bounds->w * 8 / 10; + win_h = bounds->h * 8 / 10; + } + + int xWindowPos = (win_x <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_x; + int yWindowPos = (win_y <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_y; + Printf("Creating window [%dx%d] on adapter %d\n", (*win_w), (*win_h), (*vid_adapter)); + + FString caption; + caption.Format(GAMENAME " %s (%s)", GetVersionString(), GetGitTime()); + + const uint32_t windowFlags = (win_maximized ? SDL_WINDOW_MAXIMIZED : 0) | SDL_WINDOW_RESIZABLE | extraFlags; + Priv::window = SDL_CreateWindow(caption.GetChars(), xWindowPos, yWindowPos, win_w, win_h, windowFlags); + + if (Priv::window != nullptr) + { + // Enforce minimum size limit + SDL_SetWindowMinimumSize(Priv::window, VID_MIN_WIDTH, VID_MIN_HEIGHT); + // Tell SDL to start sending text input on Wayland. + if (strncasecmp(SDL_GetCurrentVideoDriver(), "wayland", 7) == 0) SDL_StartTextInput(); + } + } + + void DestroyWindow() + { + assert(Priv::window != nullptr); + + SDL_DestroyWindow(Priv::window); + Priv::window = nullptr; + + if (Priv::displayBounds != nullptr) { + free(Priv::displayBounds); + Priv::displayBounds = nullptr; + } + } + + void SetupPixelFormat(int multisample, const int *glver) + { + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + if (multisample > 0) { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisample); + } + if (gl_debug) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); + + if (gl_es) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + } + else if (glver[0] > 2) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, glver[0]); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, glver[1]); + } + else + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + } + } +} + +CUSTOM_CVAR(Int, vid_adapter, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (Priv::window != nullptr) { + // Get displays and default display size + Priv::updateDisplayInfo(); + + int display = (*self) % Priv::numberOfDisplays; + + // TODO control better when updateDisplayInfo fails + SDL_Rect* bounds = &Priv::displayBounds[vid_adapter % Priv::numberOfDisplays]; + + if (win_w <= 0 || win_h <= 0) + { + win_w = bounds->w * 8 / 10; + win_h = bounds->h * 8 / 10; + } + // Forces to set to the ini this vars to -1, so +vid_adapter keeps working the next time that the game it's launched + win_x = -1; + win_y = -1; + + if ((SDL_GetWindowFlags(Priv::window) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) { + + // TODO This not works. For some reason keeps stuck on the previus screen + /* + SDL_DisplayMode currentDisplayMode; + SDL_GetWindowDisplayMode(Priv::window, ¤tDisplayMode); + currentDisplayMode.w = win_w; + currentDisplayMode.h = win_h; + if ( 0 != SDL_SetWindowDisplayMode(Priv::window, ¤tDisplayMode)) { + Printf("A problem occured trying to change of display %s\n", SDL_GetError()); + } + */ + + // TODO This workaround also isn't working + /* + SDL_SetWindowFullscreen(Priv::window, 0); + SDL_SetWindowSize(Priv::window, win_w, win_h); + SDL_SetWindowPosition(Priv::window, bounds->x , bounds->y); + SDL_SetWindowFullscreen(Priv::window, SDL_WINDOW_FULLSCREEN_DESKTOP); + */ + Printf("Changing adapter on fullscreen, isn't full supported by SDL. Instead try to switch to windowed mode, change the adapter and then switch again to fullscreen.\n"); + + } else { + SDL_SetWindowSize(Priv::window, win_w, win_h); + SDL_SetWindowPosition(Priv::window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display)); + } + + display = SDL_GetWindowDisplayIndex(Priv::window); + if (display >= 0) { + Printf("New display is %d\n", display ); + } else { + Printf("A problem occured trying to change of display %s\n", SDL_GetError()); + } + } +} + +class SDLVideo : public IVideo +{ +public: + SDLVideo (); + ~SDLVideo (); + + void DumpAdapters(); + + DFrameBuffer *CreateFrameBuffer (); + +private: +#ifdef HAVE_VULKAN + std::shared_ptr surface; +#endif +}; + +// CODE -------------------------------------------------------------------- + +#ifdef HAVE_VULKAN +void I_GetVulkanDrawableSize(int *width, int *height) +{ + assert(Priv::vulkanEnabled); + assert(Priv::window != nullptr); + SDL_Vulkan_GetDrawableSize(Priv::window, width, height); +} + +bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names) +{ + assert(Priv::vulkanEnabled); + assert(Priv::window != nullptr); + return SDL_Vulkan_GetInstanceExtensions(Priv::window, count, names) == SDL_TRUE; +} + +bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface) +{ + assert(Priv::vulkanEnabled); + assert(Priv::window != nullptr); + return SDL_Vulkan_CreateSurface(Priv::window, instance, surface) == SDL_TRUE; +} +#endif + + +SDLVideo::SDLVideo () +{ + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + fprintf(stderr, "Video initialization failed: %s\n", SDL_GetError()); + return; + } + + // Fail gracefully if we somehow reach here after linking against a SDL2 library older than 2.0.6. + if (!SDL_VERSION_ATLEAST(2, 0, 6)) + { + I_FatalError("Only SDL 2.0.6 or later is supported."); + } + +#ifdef HAVE_VULKAN + Priv::vulkanEnabled = V_GetBackend() == 1; + + if (Priv::vulkanEnabled) + { + Priv::CreateWindow(SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN | (vid_fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)); + + if (Priv::window == nullptr) + { + Priv::vulkanEnabled = false; + } + } +#endif +} + +SDLVideo::~SDLVideo () +{ +#ifdef HAVE_VULKAN + surface.reset(); +#endif +} + +void SDLVideo::DumpAdapters() +{ + Priv::updateDisplayInfo(); + for (int i=0; i < Priv::numberOfDisplays; i++) { + Printf("%s%d. [%dx%d @ (%d,%d)]\n", + vid_adapter == i ? TEXTCOLOR_BOLD : "", + i, + Priv::displayBounds[i].w, + Priv::displayBounds[i].h, + Priv::displayBounds[i].x, + Priv::displayBounds[i].y + ); + } +} + + +DFrameBuffer *SDLVideo::CreateFrameBuffer () +{ + SystemBaseFrameBuffer *fb = nullptr; + + // first try Vulkan, if that fails OpenGL +#ifdef HAVE_VULKAN + if (Priv::vulkanEnabled) + { + try + { + unsigned int count = 64; + const char* names[64]; + if (!I_GetVulkanPlatformExtensions(&count, names)) + VulkanError("I_GetVulkanPlatformExtensions failed"); + + VulkanInstanceBuilder builder; + builder.DebugLayer(vk_debug); + for (unsigned int i = 0; i < count; i++) + builder.RequireExtension(names[i]); + auto instance = builder.Create(); + + VkSurfaceKHR surfacehandle = nullptr; + if (!I_CreateVulkanSurface(instance->Instance, &surfacehandle)) + VulkanError("I_CreateVulkanSurface failed"); + + surface = std::make_shared(instance, surfacehandle); + + fb = new VulkanRenderDevice(nullptr, vid_fullscreen, surface); + } + catch (CVulkanError const &error) + { + if (Priv::window != nullptr) + { + Priv::DestroyWindow(); + } + + Printf(TEXTCOLOR_RED "Initialization of Vulkan failed: %s\n", error.what()); + Priv::vulkanEnabled = false; + } + } +#endif + + if (fb == nullptr) + { +#ifdef HAVE_GLES2 + if (V_GetBackend() != 0) + fb = new OpenGLESRenderer::OpenGLFrameBuffer(0, vid_fullscreen); + else +#endif + fb = new OpenGLRenderer::OpenGLFrameBuffer(0, vid_fullscreen); + } + + return fb; +} + + +IVideo *gl_CreateVideo() +{ + return new SDLVideo(); +} + + +// FrameBuffer Implementation ----------------------------------------------- + +SystemBaseFrameBuffer::SystemBaseFrameBuffer (void *, bool fullscreen) +: DFrameBuffer (vid_defwidth, vid_defheight) +{ + if (Priv::window != nullptr) + { + SDL_SetWindowFullscreen(Priv::window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + SDL_ShowWindow(Priv::window); + } +} + +int SystemBaseFrameBuffer::GetClientWidth() +{ + int width = 0; + + +#ifdef HAVE_VULKAN + assert(Priv::vulkanEnabled); + SDL_Vulkan_GetDrawableSize(Priv::window, &width, nullptr); +#endif + + return width; +} + +int SystemBaseFrameBuffer::GetClientHeight() +{ + int height = 0; + +#ifdef HAVE_VULKAN + assert(Priv::vulkanEnabled); + SDL_Vulkan_GetDrawableSize(Priv::window, nullptr, &height); +#endif + + return height; +} + +bool SystemBaseFrameBuffer::IsFullscreen () +{ + return (SDL_GetWindowFlags(Priv::window) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; +} + +void SystemBaseFrameBuffer::ToggleFullscreen(bool yes) +{ + SDL_SetWindowFullscreen(Priv::window, yes ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + if ( !yes ) + { + if ( !Priv::fullscreenSwitch ) + { + Priv::fullscreenSwitch = true; + vid_fullscreen = false; + } + else + { + Priv::fullscreenSwitch = false; + SetWindowSize(win_w, win_h); + } + } +} + +void SystemBaseFrameBuffer::SetWindowSize(int w, int h) +{ + if (w < VID_MIN_WIDTH || h < VID_MIN_HEIGHT) + { + w = VID_MIN_WIDTH; + h = VID_MIN_HEIGHT; + } + win_w = w; + win_h = h; + if (vid_fullscreen) + { + vid_fullscreen = false; + } + else + { + win_maximized = false; + SDL_SetWindowSize(Priv::window, w, h); + SDL_SetWindowPosition(Priv::window, SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter), SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter)); + SetSize(GetClientWidth(), GetClientHeight()); + int x, y; + SDL_GetWindowPosition(Priv::window, &x, &y); + win_x = x; + win_y = y; + + } +} + + +SystemGLFrameBuffer::SystemGLFrameBuffer(void *hMonitor, bool fullscreen) +: SystemBaseFrameBuffer(hMonitor, fullscreen) +{ + // NOTE: Core profiles were added with GL 3.2, so there's no sense trying + // to set core 3.1 or 3.0. We could try a forward-compatible context + // instead, but that would be too restrictive (w.r.t. shaders). + static const int glvers[][2] = { + { 4, 6 }, { 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 }, + { 3, 3 }, { 3, 2 }, { 2, 0 }, + { 0, 0 }, + }; + int glveridx = 0; + int i; + + const char *version = Args->CheckValue("-glversion"); + if (version != NULL) + { + double gl_version = strtod(version, NULL) + 0.01; + int vermaj = (int)gl_version; + int vermin = (int)(gl_version*10.0) % 10; + + while (glvers[glveridx][0] > vermaj || (glvers[glveridx][0] == vermaj && + glvers[glveridx][1] > vermin)) + { + glveridx++; + if (glvers[glveridx][0] == 0) + { + glveridx = 0; + break; + } + } + } + + for ( ; glvers[glveridx][0] > 0; ++glveridx) + { + Priv::SetupPixelFormat(0, glvers[glveridx]); + Priv::CreateWindow(SDL_WINDOW_OPENGL | (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)); + + if (Priv::window == nullptr) + { + continue; + } + + GLContext = SDL_GL_CreateContext(Priv::window); + if (GLContext == nullptr) + { + Priv::DestroyWindow(); + } + else + { + break; + } + } + if (Priv::window == nullptr) + { + I_FatalError("Could not create OpenGL window:\n%s\n",SDL_GetError()); + } +} + +SystemGLFrameBuffer::~SystemGLFrameBuffer () +{ + if (Priv::window) + { + if (GLContext) + { + SDL_GL_DeleteContext(GLContext); + } + + Priv::DestroyWindow(); + } +} + +int SystemGLFrameBuffer::GetClientWidth() +{ + int width = 0; + SDL_GL_GetDrawableSize(Priv::window, &width, nullptr); + return width; +} + +int SystemGLFrameBuffer::GetClientHeight() +{ + int height = 0; + SDL_GL_GetDrawableSize(Priv::window, nullptr, &height); + return height; +} + +void SystemGLFrameBuffer::SetVSync( bool vsync ) +{ +#if defined (__APPLE__) + const GLint value = vsync ? 1 : 0; + CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, &value ); +#else + if (vsync) + { + if (SDL_GL_SetSwapInterval(-1) == -1) + SDL_GL_SetSwapInterval(1); + } + else + { + SDL_GL_SetSwapInterval(0); + } +#endif +} + +void SystemGLFrameBuffer::SwapBuffers() +{ + SDL_GL_SwapWindow(Priv::window); +} + + +void ProcessSDLWindowEvent(const SDL_WindowEvent &event) +{ + switch (event.event) + { + extern bool AppActive; + + case SDL_WINDOWEVENT_FOCUS_GAINED: + S_SetSoundPaused(1); + AppActive = true; + break; + + case SDL_WINDOWEVENT_FOCUS_LOST: + S_SetSoundPaused(0); + AppActive = false; + break; + + case SDL_WINDOWEVENT_MOVED: + if (!vid_fullscreen) + { + int top = 0, left = 0; + SDL_GetWindowBordersSize(Priv::window, &top, &left, nullptr, nullptr); + win_x = event.data1-left; + win_y = event.data2-top; + } + break; + + case SDL_WINDOWEVENT_RESIZED: + if (!vid_fullscreen && !Priv::fullscreenSwitch) + { + win_w = event.data1; + win_h = event.data2; + } + break; + + case SDL_WINDOWEVENT_MAXIMIZED: + win_maximized = true; + break; + + case SDL_WINDOWEVENT_RESTORED: + win_maximized = false; + break; + } +} + + +// each platform has its own specific version of this function. +void I_SetWindowTitle(const char* caption) +{ + if (caption) + { + SDL_SetWindowTitle(Priv::window, caption); + } + else + { + FString default_caption; + default_caption.Format(GAMENAME " %s (%s)", GetVersionString(), GetGitTime()); + SDL_SetWindowTitle(Priv::window, default_caption.GetChars()); + } +} + diff --git a/src/common/platform/posix/sdl/st_start.cpp b/src/common/platform/posix/sdl/st_start.cpp new file mode 100644 index 00000000000..019a66122b6 --- /dev/null +++ b/src/common/platform/posix/sdl/st_start.cpp @@ -0,0 +1,307 @@ +/* +** st_start.cpp +** Handles the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include + +#include "st_start.h" +#include "i_system.h" +#include "c_cvars.h" +#include "engineerrors.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +class FTTYStartupScreen : public FStartupScreen +{ + public: + FTTYStartupScreen(int max_progress); + ~FTTYStartupScreen(); + + void Progress(); + void NetInit(const char *message, int num_players); + void NetProgress(int count); + void NetDone(); + bool NetLoop(bool (*timer_callback)(void *), void *userdata); + protected: + bool DidNetInit; + int NetMaxPos, NetCurPos; + const char *TheNetMessage; + termios OldTermIOS; +}; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +extern void RedrawProgressBar(int CurPos, int MaxPos); +extern void CleanProgressBar(); + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static const char SpinnyProgressChars[4] = { '|', '/', '-', '\\' }; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// FStartupScreen :: CreateInstance +// +// Initializes the startup screen for the detected game. +// Sets the size of the progress bar and displays the startup screen. +// +//========================================================================== + +FStartupScreen *FStartupScreen::CreateInstance(int max_progress) +{ + return new FTTYStartupScreen(max_progress); +} + +//=========================================================================== +// +// FTTYStartupScreen Constructor +// +// Sets the size of the progress bar and displays the startup screen. +// +//=========================================================================== + +FTTYStartupScreen::FTTYStartupScreen(int max_progress) + : FStartupScreen(max_progress) +{ + DidNetInit = false; + NetMaxPos = 0; + NetCurPos = 0; + TheNetMessage = NULL; +} + +//=========================================================================== +// +// FTTYStartupScreen Destructor +// +// Called just before entering graphics mode to deconstruct the startup +// screen. +// +//=========================================================================== + +FTTYStartupScreen::~FTTYStartupScreen() +{ + NetDone(); // Just in case it wasn't called yet and needs to be. +} + +//=========================================================================== +// +// FTTYStartupScreen :: Progress +// +//=========================================================================== + +void FTTYStartupScreen::Progress() +{ + if (CurPos < MaxPos) + { + ++CurPos; + } + RedrawProgressBar(CurPos, MaxPos); +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetInit +// +// Sets stdin for unbuffered I/O, displays the given message, and shows +// a progress meter. +// +//=========================================================================== + +void FTTYStartupScreen::NetInit(const char *message, int numplayers) +{ + if (!DidNetInit) + { + termios rawtermios; + + CleanProgressBar(); + fprintf (stderr, "Press 'Q' to abort network game synchronization."); + // Set stdin to raw mode so we can get keypresses in ST_CheckNetAbort() + // immediately without waiting for an EOL. + tcgetattr (STDIN_FILENO, &OldTermIOS); + rawtermios = OldTermIOS; + rawtermios.c_lflag &= ~(ICANON | ECHO); + tcsetattr (STDIN_FILENO, TCSANOW, &rawtermios); + DidNetInit = true; + } + if (numplayers == 1) + { + // Status message without any real progress info. + fprintf (stderr, "\n%s.", message); + } + else + { + fprintf (stderr, "\n%s: ", message); + } + fflush (stderr); + TheNetMessage = message; + NetMaxPos = numplayers; + NetCurPos = 0; + NetProgress(1); // You always know about yourself +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetDone +// +// Restores the old stdin tty settings. +// +//=========================================================================== + +void FTTYStartupScreen::NetDone() +{ + CleanProgressBar(); + // Restore stdin settings + if (DidNetInit) + { + tcsetattr (STDIN_FILENO, TCSANOW, &OldTermIOS); + printf ("\n"); + DidNetInit = false; + } +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetProgress +// +// Sets the network progress meter. If count is 0, it gets bumped by 1. +// Otherwise, it is set to count. +// +//=========================================================================== + +void FTTYStartupScreen::NetProgress(int count) +{ + int i; + + if (count == 0) + { + NetCurPos++; + } + else if (count > 0) + { + NetCurPos = count; + } + if (NetMaxPos == 0) + { + // Spinny-type progress meter, because we're a guest waiting for the host. + fprintf (stderr, "\r%s: %c", TheNetMessage, SpinnyProgressChars[NetCurPos & 3]); + fflush (stderr); + } + else if (NetMaxPos > 1) + { + // Dotty-type progress meter. + fprintf (stderr, "\r%s: ", TheNetMessage); + for (i = 0; i < NetCurPos; ++i) + { + fputc ('.', stderr); + } + fprintf (stderr, "%*c[%2d/%2d]", NetMaxPos + 1 - NetCurPos, ' ', NetCurPos, NetMaxPos); + fflush (stderr); + } +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetLoop +// +// The timer_callback function is called at least two times per second +// and passed the userdata value. It should return true to stop the loop and +// return control to the caller or false to continue the loop. +// +// ST_NetLoop will return true if the loop was halted by the callback and +// false if the loop was halted because the user wants to abort the +// network synchronization. +// +//=========================================================================== + +bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) +{ + fd_set rfds; + struct timeval tv; + int retval; + char k; + bool stdin_eof = false; + + for (;;) + { + // Don't flood the network with packets on startup. + tv.tv_sec = 0; + tv.tv_usec = 500000; + + FD_ZERO (&rfds); + if (!stdin_eof) + { + FD_SET (STDIN_FILENO, &rfds); + } + + retval = select (1, &rfds, NULL, NULL, &tv); + + if (retval == -1) + { + // Error + } + else if (retval == 0) + { + if (timer_callback (userdata)) + { + fputc ('\n', stderr); + return true; + } + } + else + { + ssize_t amt = read (STDIN_FILENO, &k, 1); // Check input on stdin + if (amt == 0) + { + // EOF. Stop reading + stdin_eof = true; + } + else if (amt == 1) + { + if (k == 'q' || k == 'Q') + { + fprintf (stderr, "\nNetwork game synchronization aborted."); + return false; + } + } + } + } +} + diff --git a/src/common/platform/posix/unix/gtk_dialogs.cpp b/src/common/platform/posix/unix/gtk_dialogs.cpp new file mode 100644 index 00000000000..64afbe7e6d9 --- /dev/null +++ b/src/common/platform/posix/unix/gtk_dialogs.cpp @@ -0,0 +1,534 @@ +/* +** gtk_dialogs.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2008-2016 Braden Obrzut +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef NO_GTK + +#if !DYN_GTK +// Function addresses will never be NULL, but that's because we're using the +// same code for both dynamic and static. +#pragma GCC diagnostic ignored "-Waddress" +#endif + +#include +#if GTK_MAJOR_VERSION >= 3 +#include +#else +#include +typedef enum +{ + GTK_ALIGN_FULL, + GTK_ALIGN_START, + GTK_ALIGN_END, + GTK_ALIGN_CENTER, + GTK_ALIGN_BASELINE +} GtkAlign; +#endif + +#include "c_cvars.h" +#include "i_module.h" +#include "i_system.h" +#include "version.h" +#include "startupinfo.h" +#include "cmdlib.h" +#include "i_interface.h" +#include "printf.h" + +EXTERN_CVAR (Bool, queryiwad); +EXTERN_CVAR (Int, vid_preferbackend); +EXTERN_CVAR (Bool, vid_fullscreen); + +namespace Gtk { + +FModuleMaybe GtkModule{"GTK"}; +static int GtkAvailable = -1; + +#define DYN_GTK_SYM(x) const FModuleMaybe::Req x{#x}; +#define DYN_GTK_REQ_SYM(x, proto) const FModuleMaybe::Req x{#x}; +#if GTK_MAJOR_VERSION >= 3 +#define DYN_GTK_OPT2_SYM(x, proto) const FModuleMaybe::Opt x{#x}; +#define DYN_GTK_OPT3_SYM(x, proto) const FModuleMaybe::Opt x{#x}; +#else +#define DYN_GTK_OPT2_SYM(x, proto) const FModuleMaybe::Opt x{#x}; +#define DYN_GTK_OPT3_SYM(x, proto) const FModuleMaybe::Opt x{#x}; +#endif + +DYN_GTK_SYM(g_main_context_iteration); +DYN_GTK_SYM(g_signal_connect_data); +DYN_GTK_SYM(g_type_check_instance_cast); +DYN_GTK_SYM(g_type_check_instance_is_a); +DYN_GTK_SYM(g_value_get_int); +DYN_GTK_SYM(g_value_unset); +DYN_GTK_SYM(gtk_box_get_type); +DYN_GTK_SYM(gtk_box_pack_end); +DYN_GTK_SYM(gtk_box_pack_start); +DYN_GTK_SYM(gtk_box_set_spacing); +DYN_GTK_SYM(gtk_button_box_get_type); +DYN_GTK_SYM(gtk_button_box_set_layout); +DYN_GTK_SYM(gtk_button_new_with_label); +DYN_GTK_SYM(gtk_cell_renderer_text_new); +DYN_GTK_SYM(gtk_check_button_new_with_label); +DYN_GTK_SYM(gtk_radio_button_new_with_label); +DYN_GTK_SYM(gtk_radio_button_new_with_label_from_widget); +DYN_GTK_SYM(gtk_radio_button_get_type); +DYN_GTK_SYM(gtk_container_add); +DYN_GTK_SYM(gtk_container_get_type); +DYN_GTK_SYM(gtk_container_set_border_width); +DYN_GTK_SYM(gtk_init_check); +DYN_GTK_SYM(gtk_label_new); +DYN_GTK_SYM(gtk_list_store_append); +DYN_GTK_SYM(gtk_list_store_new); +DYN_GTK_SYM(gtk_list_store_set); +DYN_GTK_REQ_SYM(gtk_scrolled_window_new, GtkWidget* (*)(GtkAdjustment* hadjustment, GtkAdjustment* vadjustment)); +DYN_GTK_SYM(gtk_toggle_button_get_type); +DYN_GTK_SYM(gtk_toggle_button_set_active); +DYN_GTK_SYM(gtk_tree_model_get_type); +DYN_GTK_SYM(gtk_tree_model_get_value); +DYN_GTK_SYM(gtk_tree_selection_get_selected); +DYN_GTK_SYM(gtk_tree_selection_select_iter); +DYN_GTK_SYM(gtk_tree_view_append_column); +// Explicitly give the type so that attributes don't cause a warning. +DYN_GTK_REQ_SYM(gtk_tree_view_column_new_with_attributes, GtkTreeViewColumn *(*)(const gchar *, GtkCellRenderer *, ...)); +DYN_GTK_SYM(gtk_toggle_button_get_active); +DYN_GTK_SYM(gtk_tree_view_get_selection); +DYN_GTK_SYM(gtk_tree_view_get_type); +DYN_GTK_SYM(gtk_tree_view_new_with_model); +DYN_GTK_SYM(gtk_main); +DYN_GTK_SYM(gtk_main_quit); +DYN_GTK_SYM(gtk_widget_destroy); +DYN_GTK_SYM(gtk_widget_grab_default); +DYN_GTK_SYM(gtk_widget_get_type); +DYN_GTK_SYM(gtk_widget_set_can_default); +DYN_GTK_SYM(gtk_widget_show_all); +DYN_GTK_SYM(gtk_window_activate_default); +DYN_GTK_SYM(gtk_window_get_type); +DYN_GTK_SYM(gtk_window_new); +DYN_GTK_SYM(gtk_window_set_gravity); +DYN_GTK_SYM(gtk_window_set_position); +DYN_GTK_SYM(gtk_window_set_title); +DYN_GTK_SYM(gtk_window_set_resizable); +DYN_GTK_SYM(gtk_dialog_run); +DYN_GTK_SYM(gtk_dialog_get_type); + +// Gtk3 Only +DYN_GTK_OPT3_SYM(gtk_box_new, GtkWidget *(*)(GtkOrientation, gint)); +DYN_GTK_OPT3_SYM(gtk_button_box_new, GtkWidget *(*)(GtkOrientation)); +DYN_GTK_OPT3_SYM(gtk_widget_set_halign, void(*)(GtkWidget *, GtkAlign)); +DYN_GTK_OPT3_SYM(gtk_widget_set_valign, void(*)(GtkWidget *, GtkAlign)); +DYN_GTK_OPT3_SYM(gtk_message_dialog_new, GtkWidget* (*)(GtkWindow*, GtkDialogFlags, GtkMessageType, GtkButtonsType, const gchar*, ...)); +DYN_GTK_OPT3_SYM(gtk_scrolled_window_set_min_content_height, void (*)(GtkScrolledWindow*, gint)); + +// Gtk2 Only +DYN_GTK_OPT2_SYM(gtk_misc_get_type, GType(*)()); +DYN_GTK_OPT2_SYM(gtk_hbox_new, GtkWidget *(*)(gboolean, gint)); +DYN_GTK_OPT2_SYM(gtk_hbutton_box_new, GtkWidget *(*)()); +DYN_GTK_OPT2_SYM(gtk_misc_set_alignment, void(*)(GtkMisc *, gfloat, gfloat)); +DYN_GTK_OPT2_SYM(gtk_vbox_new, GtkWidget *(*)(gboolean, gint)); + +#undef DYN_GTK_SYM +#undef DYN_GTK_REQ_SYM +#undef DYN_GTK_OPT2_SYM +#undef DYN_GTK_OPT3_SYM + +// GtkTreeViews eats return keys. I want this to be like a Windows listbox +// where pressing Return can still activate the default button. +static gint AllowDefault(GtkWidget *widget, GdkEventKey *event, gpointer func_data) +{ + if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Return) + { + gtk_window_activate_default (GTK_WINDOW(func_data)); + } + return FALSE; +} + +// Double-clicking an entry in the list is the same as pressing OK. +static gint DoubleClickChecker(GtkWidget *widget, GdkEventButton *event, gpointer func_data) +{ + if (event->type == GDK_2BUTTON_PRESS) + { + *(int *)func_data = 1; + gtk_main_quit(); + } + return FALSE; +} + +// When the user presses escape, that should be the same as canceling the dialog. +static gint CheckEscape (GtkWidget *widget, GdkEventKey *event, gpointer func_data) +{ + if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Escape) + { + gtk_main_quit(); + } + return FALSE; +} + +static void ClickedOK(GtkButton *button, gpointer func_data) +{ + *(int *)func_data = 1; + gtk_main_quit(); +} + +class ZUIWidget +{ +public: + virtual ~ZUIWidget() = default; + + GtkWidget *widget = nullptr; +}; + +class ZUIWindow : public ZUIWidget +{ +public: + ZUIWindow(const char* title) + { + widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title (GTK_WINDOW(widget), title); + gtk_window_set_position (GTK_WINDOW(widget), GTK_WIN_POS_CENTER); + gtk_window_set_gravity (GTK_WINDOW(widget), GDK_GRAVITY_CENTER); + + gtk_container_set_border_width (GTK_CONTAINER(widget), 15); + + g_signal_connect (widget, "delete_event", G_CALLBACK(gtk_main_quit), NULL); + g_signal_connect (widget, "key_press_event", G_CALLBACK(CheckEscape), NULL); + } + + ~ZUIWindow() + { + if (GTK_IS_WINDOW(widget)) + { + gtk_widget_destroy (widget); + // If we don't do this, then the X window might not actually disappear. + while (g_main_context_iteration (NULL, FALSE)) {} + } + } + + void AddWidget(ZUIWidget* child) + { + gtk_container_add (GTK_CONTAINER(widget), child->widget); + } + + void RunModal() + { + gtk_widget_show_all (widget); + gtk_main (); + } +}; + +class ZUIVBox : public ZUIWidget +{ +public: + ZUIVBox() + { + if (gtk_box_new) // Gtk3 + widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); + else if (gtk_vbox_new) // Gtk2 + widget = gtk_vbox_new (FALSE, 10); + } + + void PackStart(ZUIWidget* child, bool expand, bool fill, int padding) + { + gtk_box_pack_start (GTK_BOX(widget), child->widget, expand, fill, padding); + } + + void PackEnd(ZUIWidget* child, bool expand, bool fill, int padding) + { + gtk_box_pack_end (GTK_BOX(widget), child->widget, expand, fill, padding); + } +}; + +class ZUILabel : public ZUIWidget +{ +public: + ZUILabel(const char* text) + { + widget = gtk_label_new (text); + + if (gtk_widget_set_halign && gtk_widget_set_valign) // Gtk3 + { + gtk_widget_set_halign (widget, GTK_ALIGN_START); + gtk_widget_set_valign (widget, GTK_ALIGN_START); + } + else if (gtk_misc_set_alignment && gtk_misc_get_type) // Gtk2 + gtk_misc_set_alignment (GTK_MISC(widget), 0, 0); + } +}; + +class ZUIListView : public ZUIWidget +{ +public: + ZUIListView(WadStuff *wads, int numwads, int defaultiwad) + { + // Create a list store with all the found IWADs. + store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); + for (int i = 0; i < numwads; ++i) + { + const char *filepart = strrchr (wads[i].Path.GetChars(), '/'); + if (filepart == NULL) + filepart = wads[i].Path.GetChars(); + else + filepart++; + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + 0, filepart, + 1, wads[i].Name.GetChars(), + 2, i, + -1); + if (i == defaultiwad) + { + defiter = iter; + } + } + + // Create the tree view control to show the list. + widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("IWAD", renderer, "text", 0, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(widget), column); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Game", renderer, "text", 1, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(widget), column); + + // Select the default IWAD. + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(widget)); + gtk_tree_selection_select_iter (selection, &defiter); + } + + int GetSelectedIndex() + { + GtkTreeModel *model; + GValue value = { 0, { {0} } }; + + // Find out which IWAD was selected. + gtk_tree_selection_get_selected (selection, &model, &iter); + gtk_tree_model_get_value (GTK_TREE_MODEL(model), &iter, 2, &value); + int i = g_value_get_int (&value); + g_value_unset (&value); + return i; + } + + void ConnectButtonPress(int *close_style) + { + g_signal_connect(G_OBJECT(widget), "button_press_event", G_CALLBACK(DoubleClickChecker), close_style); + } + + void ConnectKeyPress(ZUIWindow* window) + { + g_signal_connect(G_OBJECT(widget), "key_press_event", G_CALLBACK(AllowDefault), window->widget); + } + + GtkListStore *store = nullptr; + GtkCellRenderer *renderer = nullptr; + GtkTreeViewColumn *column = nullptr; + GtkTreeSelection *selection = nullptr; + GtkTreeIter iter, defiter; +}; + +class ZUIScrolledWindow : public ZUIWidget +{ +public: + ZUIScrolledWindow(ZUIWidget* child) + { + widget = gtk_scrolled_window_new(NULL, NULL); + if(gtk_scrolled_window_set_min_content_height) gtk_scrolled_window_set_min_content_height((GtkScrolledWindow*)widget,150); + gtk_container_add(GTK_CONTAINER(widget), child->widget); + } +}; + +class ZUIHBox : public ZUIWidget +{ +public: + ZUIHBox() + { + // Create the hbox for the bottom row. + if (gtk_box_new) // Gtk3 + widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + else if (gtk_hbox_new) // Gtk2 + widget = gtk_hbox_new (FALSE, 0); + } + + void PackStart(ZUIWidget* child, bool expand, bool fill, int padding) + { + gtk_box_pack_start (GTK_BOX(widget), child->widget, expand, fill, padding); + } + + void PackEnd(ZUIWidget* child, bool expand, bool fill, int padding) + { + gtk_box_pack_end (GTK_BOX(widget), child->widget, expand, fill, padding); + } +}; + +class ZUICheckButton : public ZUIWidget +{ +public: + ZUICheckButton(const char* text) + { + widget = gtk_check_button_new_with_label (text); + } + + void SetChecked(bool value) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), value); + } + + int GetChecked() + { + return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)); + } +}; + +class ZUIRadioButton : public ZUIWidget +{ +public: + ZUIRadioButton(const char* text) + { + widget = gtk_radio_button_new_with_label (nullptr, text); + } + + ZUIRadioButton(ZUIRadioButton* group, const char* text) + { + widget = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(group->widget), text); + } + + void SetChecked(bool value) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), value); + } + + int GetChecked() + { + return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)); + } +}; + +class ZUIButtonBox : public ZUIWidget +{ +public: + ZUIButtonBox() + { + if (gtk_button_box_new) // Gtk3 + widget = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + else if (gtk_hbutton_box_new) // Gtk2 + widget = gtk_hbutton_box_new (); + + gtk_button_box_set_layout (GTK_BUTTON_BOX(widget), GTK_BUTTONBOX_END); + gtk_box_set_spacing (GTK_BOX(widget), 10); + } + + void PackStart(ZUIWidget* child, bool expand, bool fill, int padding) + { + gtk_box_pack_start (GTK_BOX(widget), child->widget, expand, fill, padding); + } + + void PackEnd(ZUIWidget* child, bool expand, bool fill, int padding) + { + gtk_box_pack_end (GTK_BOX(widget), child->widget, expand, fill, padding); + } +}; + +class ZUIButton : public ZUIWidget +{ +public: + ZUIButton(const char* text, bool defaultButton) + { + widget = gtk_button_new_with_label (text); + + if (defaultButton) + { + gtk_widget_set_can_default (widget, true); + } + } + + void GrabDefault() + { + gtk_widget_grab_default (widget); + } + + void ConnectClickedOK(int *close_style) + { + g_signal_connect (widget, "clicked", G_CALLBACK(ClickedOK), close_style); + g_signal_connect (widget, "activate", G_CALLBACK(ClickedOK), close_style); + } + + void ConnectClickedExit(ZUIWindow* window) + { + g_signal_connect (widget, "clicked", G_CALLBACK(gtk_main_quit), &window->widget); + } +}; + + +static void ShowError(const char* errortext) +{ + ZUIWindow window("Fatal error"); + ZUIVBox vbox; + ZUILabel label(errortext); + ZUIButtonBox bbox; + ZUIButton exitButton("Exit", true); + + window.AddWidget(&vbox); + vbox.PackStart(&label, true, true, 0); + vbox.PackEnd(&bbox, false, false, 0); + bbox.PackEnd(&exitButton, false, false, 0); + + exitButton.ConnectClickedExit(&window); + + exitButton.GrabDefault(); + window.RunModal(); +} + +} // namespace Gtk + +void I_ShowFatalError_Gtk(const char* errortext) { + Gtk::ShowError(errortext); +} + +bool I_GtkAvailable() +{ + using namespace Gtk; + + if(GtkAvailable < 0) + { + if (!GtkModule.Load({"libgtk-3.so.0", "libgtk-x11-2.0.so.0"})) + { + GtkAvailable = 0; + return false; + } + + int argc = 0; + char **argv = nullptr; + GtkAvailable = Gtk::gtk_init_check (&argc, &argv); + } + + return GtkAvailable != 0; +} + +#endif diff --git a/src/common/platform/posix/unix/i_specialpaths.cpp b/src/common/platform/posix/unix/i_specialpaths.cpp new file mode 100644 index 00000000000..112e92ee791 --- /dev/null +++ b/src/common/platform/posix/unix/i_specialpaths.cpp @@ -0,0 +1,240 @@ +/* +** i_specialpaths.cpp +** Gets special system folders where data should be stored. (Unix version) +** +**--------------------------------------------------------------------------- +** Copyright 2013-2016 Randy Heit +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include "i_system.h" +#include "cmdlib.h" +#include "printf.h" +#include "engineerrors.h" + +#include "version.h" // for GAMENAME + + +FString GetUserFile (const char *file) +{ + FString path; + struct stat info; + + path = NicePath("$HOME/" GAME_DIR "/"); + + if (stat (path.GetChars(), &info) == -1) + { + struct stat extrainfo; + + // Sanity check for $HOME/.config + FString configPath = NicePath("$HOME/.config/"); + if (stat (configPath.GetChars(), &extrainfo) == -1) + { + if (mkdir (configPath.GetChars(), S_IRUSR | S_IWUSR | S_IXUSR) == -1) + { + I_FatalError ("Failed to create $HOME/.config directory:\n%s", strerror(errno)); + } + } + else if (!S_ISDIR(extrainfo.st_mode)) + { + I_FatalError ("$HOME/.config must be a directory"); + } + + // This can be removed after a release or two + // Transfer the old zdoom directory to the new location + bool moved = false; + FString oldpath = NicePath("$HOME/." GAMENAMELOWERCASE "/"); + if (stat (oldpath.GetChars(), &extrainfo) != -1) + { + if (rename(oldpath.GetChars(), path.GetChars()) == -1) + { + I_Error ("Failed to move old " GAMENAMELOWERCASE " directory (%s) to new location (%s).", + oldpath.GetChars(), path.GetChars()); + } + else + moved = true; + } + + if (!moved && mkdir (path.GetChars(), S_IRUSR | S_IWUSR | S_IXUSR) == -1) + { + I_FatalError ("Failed to create %s directory:\n%s", + path.GetChars(), strerror (errno)); + } + } + else + { + if (!S_ISDIR(info.st_mode)) + { + I_FatalError ("%s must be a directory", path.GetChars()); + } + } + path += file; + return path; +} + +//=========================================================================== +// +// M_GetAppDataPath Unix +// +// Returns the path for the AppData folder. +// +//=========================================================================== + +FString M_GetAppDataPath(bool create) +{ + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + FString path = NicePath("$HOME/.config/" GAMENAMELOWERCASE); + if (create) + { + CreatePath(path.GetChars()); + } + return path; +} + +//=========================================================================== +// +// M_GetCachePath Unix +// +// Returns the path for cache GL nodes. +// +//=========================================================================== + +FString M_GetCachePath(bool create) +{ + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + FString path = NicePath("$HOME/.config/zdoom/cache"); + if (create) + { + CreatePath(path.GetChars()); + } + return path; +} + +//=========================================================================== +// +// M_GetAutoexecPath Unix +// +// Returns the expected location of autoexec.cfg. +// +//=========================================================================== + +FString M_GetAutoexecPath() +{ + return GetUserFile("autoexec.cfg"); +} + +//=========================================================================== +// +// M_GetConfigPath Unix +// +// Returns the path to the config file. On Windows, this can vary for reading +// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try +// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. +// +//=========================================================================== + +FString M_GetConfigPath(bool for_reading) +{ + return GetUserFile(GAMENAMELOWERCASE ".ini"); +} + +//=========================================================================== +// +// M_GetScreenshotsPath Unix +// +// Returns the path to the default screenshots directory. +// +//=========================================================================== + +FString M_GetScreenshotsPath() +{ + return NicePath("$HOME/" GAME_DIR "/screenshots/"); +} + +//=========================================================================== +// +// M_GetSavegamesPath Unix +// +// Returns the path to the default save games directory. +// +//=========================================================================== + +FString M_GetSavegamesPath() +{ + return NicePath("$HOME/" GAME_DIR "/savegames/"); +} + +//=========================================================================== +// +// M_GetDocumentsPath Unix +// +// Returns the path to the default documents directory. +// +//=========================================================================== + +FString M_GetDocumentsPath() +{ + return NicePath("$HOME/" GAME_DIR "/"); +} + +//=========================================================================== +// +// M_GetDemoPath Unix +// +// Returns the path to the default demo directory. +// +//=========================================================================== + +FString M_GetDemoPath() +{ + return M_GetDocumentsPath() + "demo/"; +} + +//=========================================================================== +// +// M_NormalizedPath +// +// Normalizes the given path and returns the result. +// +//=========================================================================== + +FString M_GetNormalizedPath(const char* path) +{ + char *actualpath; + actualpath = realpath(path, NULL); + if (!actualpath) // error ? + return nullptr; + FString fullpath = actualpath; + return fullpath; +} + diff --git a/src/win32/afxres.h b/src/common/platform/win32/afxres.h similarity index 100% rename from src/win32/afxres.h rename to src/common/platform/win32/afxres.h diff --git a/src/win32/base_sysfb.cpp b/src/common/platform/win32/base_sysfb.cpp similarity index 84% rename from src/win32/base_sysfb.cpp rename to src/common/platform/win32/base_sysfb.cpp index 53384cf2b10..4d0219316f3 100644 --- a/src/win32/base_sysfb.cpp +++ b/src/common/platform/win32/base_sysfb.cpp @@ -39,23 +39,18 @@ #include "gl_sysfb.h" #include "hardware.h" -#include "x86.h" -#include "templates.h" + #include "version.h" #include "c_console.h" #include "v_video.h" #include "i_input.h" #include "i_system.h" -#include "doomstat.h" #include "v_text.h" #include "m_argv.h" -#include "doomerrors.h" #include "base_sysfb.h" #include "win32basevideo.h" #include "c_dispatch.h" - - -extern HWND Window; +#include "i_mainwindow.h" extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; @@ -88,7 +83,7 @@ EXTERN_CVAR(Int, vid_defheight) EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &displaysettings); scrwidth = (int)displaysettings.dmPelsWidth; scrheight = (int)displaysettings.dmPelsHeight; - GetWindowRect(Window, &rect); + GetWindowRect(mainwindow.GetHandle(), &rect); cx = scrwidth / 2; cy = scrheight / 2; if (in_w > 0) winw = in_w; @@ -142,11 +137,11 @@ void SystemBaseFrameBuffer::SaveWindowedPos() } // Make sure we only save the window position if it's not fullscreen. static const int WINDOW_STYLE = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX; - if ((GetWindowLong(Window, GWL_STYLE) & WINDOW_STYLE) == WINDOW_STYLE) + if ((GetWindowLong(mainwindow.GetHandle(), GWL_STYLE) & WINDOW_STYLE) == WINDOW_STYLE) { RECT wrect; - if (GetWindowRect(Window, &wrect)) + if (GetWindowRect(mainwindow.GetHandle(), &wrect)) { // If (win_x,win_y) specify to center the window, don't change them // if the window is still centered. @@ -174,7 +169,7 @@ void SystemBaseFrameBuffer::SaveWindowedPos() win_h = wrect.bottom - wrect.top; } - win_maximized = IsZoomed(Window) == TRUE; + win_maximized = IsZoomed(mainwindow.GetHandle()) == TRUE; } } @@ -207,10 +202,10 @@ void SystemBaseFrameBuffer::RestoreWindowedPos() } KeepWindowOnScreen(winx, winy, winw, winh, scrwidth, scrheight); } - SetWindowPos(Window, nullptr, winx, winy, winw, winh, SWP_NOZORDER | SWP_FRAMECHANGED); + SetWindowPos(mainwindow.GetHandle(), nullptr, winx, winy, winw, winh, SWP_NOZORDER | SWP_FRAMECHANGED); if (win_maximized && !Args->CheckParm("-0")) - ShowWindow(Window, SW_MAXIMIZE); + ShowWindow(mainwindow.GetHandle(), SW_MAXIMIZE); } //========================================================================== @@ -229,8 +224,8 @@ void SystemBaseFrameBuffer::SetWindowSize(int w, int h) { LONG style = WS_VISIBLE | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW; LONG exStyle = WS_EX_WINDOWEDGE; - SetWindowLong(Window, GWL_STYLE, style); - SetWindowLong(Window, GWL_EXSTYLE, exStyle); + SetWindowLong(mainwindow.GetHandle(), GWL_STYLE, style); + SetWindowLong(mainwindow.GetHandle(), GWL_EXSTYLE, exStyle); int winx, winy, winw, winh, scrwidth, scrheight; @@ -251,10 +246,10 @@ void SystemBaseFrameBuffer::SetWindowSize(int w, int h) KeepWindowOnScreen(winx, winy, winw, winh, scrwidth, scrheight); } - if (!fullscreen) + if (!vid_fullscreen) { - ShowWindow(Window, SW_SHOWNORMAL); - SetWindowPos(Window, nullptr, winx, winy, winw, winh, SWP_NOZORDER | SWP_FRAMECHANGED); + ShowWindow(mainwindow.GetHandle(), SW_SHOWNORMAL); + SetWindowPos(mainwindow.GetHandle(), nullptr, winx, winy, winw, winh, SWP_NOZORDER | SWP_FRAMECHANGED); win_maximized = false; SetSize(GetClientWidth(), GetClientHeight()); SaveWindowedPos(); @@ -266,7 +261,7 @@ void SystemBaseFrameBuffer::SetWindowSize(int w, int h) win_w = winw; win_h = winh; win_maximized = false; - fullscreen = false; + vid_fullscreen = false; } } } @@ -282,7 +277,7 @@ void SystemBaseFrameBuffer::PositionWindow(bool fullscreen, bool initialcall) RECT r; LONG style, exStyle; - RECT monRect; + RECT monRect = {}; if (!m_Fullscreen && fullscreen && !initialcall) SaveWindowedPos(); if (m_Monitor) @@ -305,9 +300,9 @@ void SystemBaseFrameBuffer::PositionWindow(bool fullscreen, bool initialcall) } } - ShowWindow(Window, SW_SHOW); + ShowWindow(mainwindow.GetHandle(), SW_SHOW); - GetWindowRect(Window, &r); + GetWindowRect(mainwindow.GetHandle(), &r); style = WS_VISIBLE | WS_CLIPSIBLINGS; exStyle = 0; @@ -319,13 +314,13 @@ void SystemBaseFrameBuffer::PositionWindow(bool fullscreen, bool initialcall) exStyle |= WS_EX_WINDOWEDGE; } - SetWindowLong(Window, GWL_STYLE, style); - SetWindowLong(Window, GWL_EXSTYLE, exStyle); + SetWindowLong(mainwindow.GetHandle(), GWL_STYLE, style); + SetWindowLong(mainwindow.GetHandle(), GWL_EXSTYLE, exStyle); if (fullscreen) { - SetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - MoveWindow(Window, monRect.left, monRect.top, monRect.right-monRect.left, monRect.bottom-monRect.top, FALSE); + SetWindowPos(mainwindow.GetHandle(), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + MoveWindow(mainwindow.GetHandle(), monRect.left, monRect.top, monRect.right-monRect.left, monRect.bottom-monRect.top, FALSE); // And now, seriously, it IS in the right place. Promise. } @@ -335,7 +330,7 @@ void SystemBaseFrameBuffer::PositionWindow(bool fullscreen, bool initialcall) // This doesn't restore the window size properly so we must force a set size the next tic. if (m_Fullscreen) { - ::fullscreen = false; + ::vid_fullscreen = false; } } @@ -355,9 +350,9 @@ SystemBaseFrameBuffer::SystemBaseFrameBuffer(void *hMonitor, bool fullscreen) : m_displayDeviceName = 0; PositionWindow(fullscreen, true); - HDC hDC = GetDC(Window); + HDC hDC = GetDC(mainwindow.GetHandle()); - ReleaseDC(Window, hDC); + ReleaseDC(mainwindow.GetHandle(), hDC); } //========================================================================== @@ -370,11 +365,10 @@ SystemBaseFrameBuffer::~SystemBaseFrameBuffer() { if (!m_Fullscreen) SaveWindowedPos(); - ShowWindow (Window, SW_SHOW); - SetWindowLong(Window, GWL_STYLE, WS_VISIBLE | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW); - SetWindowLong(Window, GWL_EXSTYLE, WS_EX_WINDOWEDGE); - SetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - I_GetEvent(); + ShowWindow (mainwindow.GetHandle(), SW_SHOW); + SetWindowLong(mainwindow.GetHandle(), GWL_STYLE, WS_VISIBLE | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW); + SetWindowLong(mainwindow.GetHandle(), GWL_EXSTYLE, WS_EX_WINDOWEDGE); + SetWindowPos(mainwindow.GetHandle(), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); static_cast(Video)->Shutdown(); } @@ -411,13 +405,13 @@ void SystemBaseFrameBuffer::ToggleFullscreen(bool yes) int SystemBaseFrameBuffer::GetClientWidth() { RECT rect = { 0 }; - GetClientRect(Window, &rect); + GetClientRect(mainwindow.GetHandle(), &rect); return rect.right - rect.left; } int SystemBaseFrameBuffer::GetClientHeight() { RECT rect = { 0 }; - GetClientRect(Window, &rect); + GetClientRect(mainwindow.GetHandle(), &rect); return rect.bottom - rect.top; } diff --git a/src/win32/base_sysfb.h b/src/common/platform/win32/base_sysfb.h similarity index 100% rename from src/win32/base_sysfb.h rename to src/common/platform/win32/base_sysfb.h diff --git a/src/win32/gl_sysfb.cpp b/src/common/platform/win32/gl_sysfb.cpp similarity index 85% rename from src/win32/gl_sysfb.cpp rename to src/common/platform/win32/gl_sysfb.cpp index c8a6e3ea79a..61073e968ca 100644 --- a/src/win32/gl_sysfb.cpp +++ b/src/common/platform/win32/gl_sysfb.cpp @@ -39,20 +39,19 @@ #include "gl_sysfb.h" #include "hardware.h" -#include "x86.h" -#include "templates.h" + #include "version.h" #include "c_console.h" #include "v_video.h" #include "i_input.h" #include "i_system.h" -#include "doomstat.h" #include "v_text.h" #include "m_argv.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "win32glvideo.h" +#include "i_mainwindow.h" -extern HWND Window; +extern "C" PROC zd_wglGetProcAddress(LPCSTR name); PFNWGLSWAPINTERVALEXTPROC myWglSwapIntervalExtProc; @@ -71,24 +70,24 @@ PFNWGLSWAPINTERVALEXTPROC myWglSwapIntervalExtProc; SystemGLFrameBuffer::SystemGLFrameBuffer(void *hMonitor, bool fullscreen) : SystemBaseFrameBuffer(hMonitor, fullscreen) { - if (!static_cast(Video)->InitHardware(Window, 0)) + if (!static_cast(Video)->InitHardware(mainwindow.GetHandle(), 0)) { I_FatalError("Unable to initialize OpenGL"); return; } - HDC hDC = GetDC(Window); + HDC hDC = GetDC(mainwindow.GetHandle()); const char *wglext = nullptr; - myWglSwapIntervalExtProc = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - auto myWglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); + myWglSwapIntervalExtProc = (PFNWGLSWAPINTERVALEXTPROC)zd_wglGetProcAddress("wglSwapIntervalEXT"); + auto myWglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)zd_wglGetProcAddress("wglGetExtensionsStringARB"); if (myWglGetExtensionsStringARB) { wglext = myWglGetExtensionsStringARB(hDC); } else { - auto myWglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); + auto myWglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)zd_wglGetProcAddress("wglGetExtensionsStringEXT"); if (myWglGetExtensionsStringEXT) { wglext = myWglGetExtensionsStringEXT(); @@ -102,7 +101,7 @@ SystemGLFrameBuffer::SystemGLFrameBuffer(void *hMonitor, bool fullscreen) : Syst SwapInterval = -1; } } - ReleaseDC(Window, hDC); + ReleaseDC(mainwindow.GetHandle(), hDC); } //========================================================================== @@ -111,9 +110,9 @@ SystemGLFrameBuffer::SystemGLFrameBuffer(void *hMonitor, bool fullscreen) : Syst // //========================================================================== EXTERN_CVAR(Bool, vid_vsync); -CUSTOM_CVAR(Bool, gl_control_tear, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Bool, gl_control_tear, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { - vid_vsync.Callback(); + vid_vsync->Callback(); } void SystemGLFrameBuffer::SetVSync (bool vsync) diff --git a/src/win32/gl_sysfb.h b/src/common/platform/win32/gl_sysfb.h similarity index 100% rename from src/win32/gl_sysfb.h rename to src/common/platform/win32/gl_sysfb.h diff --git a/src/common/platform/win32/hardware.cpp b/src/common/platform/win32/hardware.cpp new file mode 100644 index 00000000000..4aec98da8ae --- /dev/null +++ b/src/common/platform/win32/hardware.cpp @@ -0,0 +1,117 @@ +/* +** hardware.cpp +** Somewhat OS-independant interface to the screen, mouse, keyboard, and stick +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "hardware.h" +#include "c_dispatch.h" +#include "v_text.h" +#include "basics.h" +#include "m_argv.h" +#include "version.h" +#include "printf.h" +#include "win32glvideo.h" +#ifdef HAVE_VULKAN +#include "win32vulkanvideo.h" +#endif +#include "engineerrors.h" +#include "i_system.h" +#include "i_mainwindow.h" + +IVideo *Video; + +// do not include GL headers here, only declare the necessary functions. +IVideo *gl_CreateVideo(); + +void I_RestartRenderer(); +int currentcanvas = -1; +bool changerenderer; + +void I_ShutdownGraphics () +{ + if (screen) + { + DFrameBuffer *s = screen; + screen = NULL; + delete s; + } + if (Video) + delete Video, Video = NULL; +} + +void I_InitGraphics () +{ + // If the focus window is destroyed, it doesn't go back to the active window. + // (e.g. because the net pane was up, and a button on it had focus) + if (GetFocus() == NULL && GetActiveWindow() == mainwindow.GetHandle()) + { + // Make sure it's in the foreground and focused. (It probably is + // already foregrounded but may not be focused.) + SetForegroundWindow(mainwindow.GetHandle()); + SetFocus(mainwindow.GetHandle()); + // Note that when I start a 2-player game on the same machine, the + // window for the game that isn't focused, active, or foregrounded + // still receives a WM_ACTIVATEAPP message telling it that it's the + // active window. The window that is really the active window does + // not receive a WM_ACTIVATEAPP message, so both games think they + // are the active app. Huh? + } + +#ifdef HAVE_VULKAN + if (V_GetBackend() == 1) + { + // first try Vulkan, if that fails OpenGL + try + { + Video = new Win32VulkanVideo(); + } + catch (CVulkanError &error) + { + Printf(TEXTCOLOR_RED "Initialization of Vulkan failed: %s\n", error.what()); + Video = new Win32GLVideo(); + } + } + else +#endif + { + Video = new Win32GLVideo(); + } + + // we somehow STILL don't have a display!! + if (Video == NULL) + I_FatalError ("Failed to initialize display"); + +} diff --git a/src/win32/hardware.h b/src/common/platform/win32/hardware.h similarity index 100% rename from src/win32/hardware.h rename to src/common/platform/win32/hardware.h diff --git a/src/win32/i_crash.cpp b/src/common/platform/win32/i_crash.cpp similarity index 97% rename from src/win32/i_crash.cpp rename to src/common/platform/win32/i_crash.cpp index aea02799090..dd586928173 100644 --- a/src/win32/i_crash.cpp +++ b/src/common/platform/win32/i_crash.cpp @@ -34,6 +34,7 @@ // HEADER FILES ------------------------------------------------------------ +#pragma warning(disable:4996) #define WIN32_LEAN_AND_MEAN #include #include @@ -55,13 +56,19 @@ #include #include -#include "doomtype.h" +#include +#include #include "resource.h" #include "version.h" #include "m_swap.h" +#include "basics.h" +#include "zstring.h" +#include "printf.h" +#include "cmdlib.h" +#include "i_mainwindow.h" #include -#include +#include // MACROS ------------------------------------------------------------------ @@ -206,9 +213,6 @@ struct MiniDumpThreadData // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- -void I_FlushBufferedConsoleStuff(); - // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void AddFile (HANDLE file, const char *filename); @@ -334,7 +338,7 @@ static HANDLE WriteMyMiniDump (void) MINIDUMP_EXCEPTION_INFORMATION exceptor = { DbgThreadID, &CrashPointers, FALSE }; WCHAR dbghelpPath[MAX_PATH+12], *bs; WRITEDUMP pMiniDumpWriteDump; - HANDLE file; + HANDLE file = INVALID_HANDLE_VALUE; BOOL good = FALSE; HMODULE dbghelp = NULL; @@ -377,12 +381,14 @@ static HANDLE WriteMyMiniDump (void) { MiniDumpThreadData dumpdata = { file, pMiniDumpWriteDump, &exceptor }; DWORD id; - HANDLE thread = CreateThread (NULL, 0, WriteMiniDumpInAnotherThread, - &dumpdata, 0, &id); - WaitForSingleObject (thread, INFINITE); - if (GetExitCodeThread (thread, &id)) + HANDLE thread = CreateThread (NULL, 0, WriteMiniDumpInAnotherThread, &dumpdata, 0, &id); + if (thread != nullptr) { - good = id; + WaitForSingleObject(thread, INFINITE); + if (GetExitCodeThread(thread, &id)) + { + good = id; + } } } } @@ -439,41 +445,6 @@ void Writef (HANDLE file, const char *format, ...) // //========================================================================== -static DWORD CALLBACK WriteLogFileStreamer(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb) -{ - DWORD didwrite; - LONG p, pp; - - // Replace gray foreground color with black. - static const char *badfg = "\\red223\\green223\\blue223;"; - // 4321098 765432109 876543210 - // 2 1 0 - for (p = pp = 0; p < cb; ++p) - { - if (buffer[p] == badfg[pp]) - { - ++pp; - if (pp == 25) - { - buffer[p - 1] = buffer[p - 2] = buffer[p - 3] = - buffer[p - 9] = buffer[p -10] = buffer[p -11] = - buffer[p -18] = buffer[p -19] = buffer[p -20] = '0'; - break; - } - } - else - { - pp = 0; - } - } - - if (!WriteFile((HANDLE)cookie, buffer, cb, &didwrite, NULL)) - { - return 1; - } - *pcb = didwrite; - return 0; -} //========================================================================== // @@ -483,15 +454,21 @@ static DWORD CALLBACK WriteLogFileStreamer(DWORD_PTR cookie, LPBYTE buffer, LONG // //========================================================================== -HANDLE WriteLogFile(HWND edit) +HANDLE WriteLogFile() { HANDLE file; file = CreateTempFile(); if (file != INVALID_HANDLE_VALUE) { - EDITSTREAM streamer = { (DWORD_PTR)file, 0, WriteLogFileStreamer }; - SendMessage(edit, EM_STREAMOUT, SF_RTF, (LPARAM)&streamer); + auto writeFile = [&](const void* data, uint32_t size, uint32_t& written) -> bool + { + DWORD tmp = 0; + BOOL result = WriteFile(file, data, size, &tmp, nullptr); + written = tmp; + return result == TRUE; + }; + mainwindow.GetLog(writeFile); } return file; } @@ -504,7 +481,7 @@ HANDLE WriteLogFile(HWND edit) // //========================================================================== -void CreateCrashLog (const char *custominfo, DWORD customsize, HWND richlog) +void CreateCrashLog (const char *custominfo, DWORD customsize) { // Do not collect information more than once. if (NumFiles != 0) @@ -554,11 +531,7 @@ void CreateCrashLog (const char *custominfo, DWORD customsize, HWND richlog) AddFile (file, "local.txt"); } } - if (richlog != NULL) - { - I_FlushBufferedConsoleStuff(); - AddFile (WriteLogFile(richlog), "log.rtf"); - } + AddFile (WriteLogFile(), "log.rtf"); CloseHandle (DbgProcess); } @@ -704,14 +677,14 @@ HANDLE WriteTextReport () ctxt->Rip, ctxt->Rsp, ctxt->SegCs, ctxt->SegSs, ctxt->EFlags); #endif - DWORD j; + DWORD dw; - for (i = 0, j = 1; (size_t)i < sizeof(eflagsBits)/sizeof(eflagsBits[0]); j <<= 1, ++i) + for (i = 0, dw = 1; (size_t)i < sizeof(eflagsBits)/sizeof(eflagsBits[0]); dw <<= 1, ++i) { if (eflagsBits[i][0] != 'x') { Writef (file, " %c%c%c", eflagsBits[i][0], eflagsBits[i][1], - ctxt->EFlags & j ? '+' : '-'); + ctxt->EFlags & dw ? '+' : '-'); } } Writef (file, "\r\n"); @@ -800,8 +773,8 @@ static void AddToolHelp (HANDLE file) pCreateToolhelp32Snapshot = (CREATESNAPSHOT)GetProcAddress (kernel, "CreateToolhelp32Snapshot"); pThread32First = (THREADWALK)GetProcAddress (kernel, "Thread32First"); pThread32Next = (THREADWALK)GetProcAddress (kernel, "Thread32Next"); - pModule32First = (MODULEWALK)GetProcAddress (kernel, "Module32First"); - pModule32Next = (MODULEWALK)GetProcAddress (kernel, "Module32Next"); + pModule32First = (MODULEWALK)GetProcAddress (kernel, "Module32FirstW"); + pModule32Next = (MODULEWALK)GetProcAddress (kernel, "Module32NextW"); if (!(pCreateToolhelp32Snapshot && pThread32First && pThread32Next && pModule32First && pModule32Next)) @@ -846,12 +819,13 @@ static void AddToolHelp (HANDLE file) { do { + auto amod = FString(module.szModule); Writef (file, "%p - %p %c%s\r\n", module.modBaseAddr, module.modBaseAddr + module.modBaseSize - 1, module.modBaseAddr <= CrashPointers.ExceptionRecord->ExceptionAddress && module.modBaseAddr + module.modBaseSize > CrashPointers.ExceptionRecord->ExceptionAddress ? '*' : ' ', - module.szModule); + amod.GetChars()); } while (pModule32Next (snapshot, &module)); } @@ -1574,7 +1548,7 @@ static void AddZipFile (HANDLE ziphandle, TarFile *whichfile, short dosdate, sho local.ModDate = dosdate; local.UncompressedSize = LittleLong(whichfile->UncompressedSize); local.NameLength = LittleShort((uint16_t)strlen(whichfile->Filename)); - + whichfile->ZipOffset = SetFilePointer (ziphandle, 0, NULL, FILE_CURRENT); WriteFile (ziphandle, &local, sizeof(local), &wrote, NULL); WriteFile (ziphandle, whichfile->Filename, (DWORD)strlen(whichfile->Filename), &wrote, NULL); diff --git a/src/common/platform/win32/i_crash_arm.cpp b/src/common/platform/win32/i_crash_arm.cpp new file mode 100644 index 00000000000..2a61ab42c57 --- /dev/null +++ b/src/common/platform/win32/i_crash_arm.cpp @@ -0,0 +1,7 @@ +// Licensed to the Public Domain by Rachael Alexandersion (c) 2021 +// This file is nothing more than a stub. Please replace with a proper copyright notice if this function is implemented for ARM. Or just use the regular i_crash.cpp + +void DisplayCrashLog() +{ + // stub +} diff --git a/src/win32/i_dijoy.cpp b/src/common/platform/win32/i_dijoy.cpp similarity index 96% rename from src/win32/i_dijoy.cpp rename to src/common/platform/win32/i_dijoy.cpp index 4a435d8d8bd..33c4574c97b 100644 --- a/src/win32/i_dijoy.cpp +++ b/src/common/platform/win32/i_dijoy.cpp @@ -44,12 +44,16 @@ #include #include "i_input.h" -#include "d_event.h" -#include "templates.h" +#include "d_eventbase.h" + #include "gameconfigfile.h" #include "cmdlib.h" #include "v_text.h" #include "m_argv.h" +#include "keydef.h" +#include "printf.h" + +#include "i_mainwindow.h" #define SAFE_RELEASE(x) { if (x != NULL) { x->Release(); x = NULL; } } @@ -176,6 +180,13 @@ class FDInputJoystick : public FInputDevice, IJoystickConfig bool IsAxisMapDefault(int axis); bool IsAxisScaleDefault(int axis); + bool GetEnabled(); + void SetEnabled(bool enabled); + + bool AllowsEnabledInBackground() { return false; } + bool GetEnabledInBackground() { return false; } + void SetEnabledInBackground(bool enabled) {} + void SetDefaultConfig(); FString GetIdentifier(); @@ -215,6 +226,8 @@ class FDInputJoystick : public FInputDevice, IJoystickConfig DIOBJECTDATAFORMAT *Objects; DIDATAFORMAT DataFormat; + bool Enabled; + static BOOL CALLBACK EnumObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); void OrderAxes(); bool ReorderAxisPair(const GUID &x, const GUID &y, int pos); @@ -264,7 +277,6 @@ class FDInputJoystickManager : public FJoystickCollection // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern LPDIRECTINPUT8 g_pdi; -extern HWND Window; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -279,14 +291,6 @@ CUSTOM_CVAR(Bool, joy_dinput, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCA static const uint8_t POVButtons[9] = { 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09, 0x00 }; -//("dc12a687-737f-11cf-884d-00aa004b2e24") -static const IID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf, - { 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } }; - -//("4590f811-1d3a-11d0-891f-00aa004b2e24") -static const CLSID CLSID_WbemLocator = { 0x4590f811, 0x1d3a, 0x11d0, - { 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } }; - // CODE -------------------------------------------------------------------- //=========================================================================== @@ -302,6 +306,7 @@ FDInputJoystick::FDInputJoystick(const GUID *instance, FString &name) Instance = *instance; Name = name; Marked = false; + Enabled = true; } //=========================================================================== @@ -378,7 +383,7 @@ bool FDInputJoystick::GetDevice() Printf(TEXTCOLOR_ORANGE "Setting data format for %s failed.\n", Name.GetChars()); return false; } - hr = Device->SetCooperativeLevel(Window, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); + hr = Device->SetCooperativeLevel(mainwindow.GetHandle(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); if (FAILED(hr)) { Printf(TEXTCOLOR_ORANGE "Setting cooperative level for %s failed.\n", Name.GetChars()); @@ -415,12 +420,13 @@ void FDInputJoystick::ProcessInput() { hr = Device->Acquire(); } - if (FAILED(hr)) + if (FAILED(hr) || !Enabled) { return; } - state = (uint8_t *)alloca(DataFormat.dwDataSize); + TArray statearr(DataFormat.dwDataSize, true); + state = statearr.data(); hr = Device->GetDeviceState(DataFormat.dwDataSize, state); if (FAILED(hr)) return; @@ -457,7 +463,7 @@ void FDInputJoystick::ProcessInput() { // Since we sorted the axes, we know that the first two are definitely X and Y. // They are probably a single stick, so use angular position to determine buttons. - buttonstate = Joy_XYAxesToButtons(axisval, Axes[0].Value); + buttonstate = Joy_XYAxesToButtons(Axes[0].Value, axisval); Joy_GenerateButtonEvents(info->ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS); } info->ButtonValue = buttonstate; @@ -645,7 +651,7 @@ bool FDInputJoystick::ReorderAxisPair(const GUID &xid, const GUID &yid, int pos) } if (x == pos + 1 && y == pos) { // Xbox 360 Controllers return them in this order. - swapvalues(Axes[pos], Axes[pos + 1]); + std::swap(Axes[pos], Axes[pos + 1]); } else if (x != pos || y != pos + 1) { @@ -897,7 +903,7 @@ const char *FDInputJoystick::GetAxisName(int axis) { if (unsigned(axis) < Axes.Size()) { - return Axes[axis].Name; + return Axes[axis].Name.GetChars(); } return "Invalid"; } @@ -989,6 +995,28 @@ bool FDInputJoystick::IsAxisScaleDefault(int axis) return true; } +//=========================================================================== +// +// FDInputJoystick :: GetEnabled +// +//=========================================================================== + +bool FDInputJoystick::GetEnabled() +{ + return Enabled; +} + +//=========================================================================== +// +// FDInputJoystick :: SetEnabled +// +//=========================================================================== + +void FDInputJoystick::SetEnabled(bool enabled) +{ + Enabled = enabled; +} + //=========================================================================== // // FDInputJoystick :: IsAxisMapDefault diff --git a/src/common/platform/win32/i_input.cpp b/src/common/platform/win32/i_input.cpp new file mode 100644 index 00000000000..45a74fe0c11 --- /dev/null +++ b/src/common/platform/win32/i_input.cpp @@ -0,0 +1,789 @@ +/* +** i_input.cpp +** Handles input from keyboard, mouse, and joystick +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// DI3 only supports up to 4 mouse buttons, and I want the joystick to +// be read using DirectInput instead of winmm. + +#define WIN32_LEAN_AND_MEAN +#define __BYTEBOOL__ +#ifndef __GNUC__ +#define INITGUID +#endif +#define DIRECTINPUT_VERSION 0x800 +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +#ifndef GET_RAWINPUT_CODE_WPARAM +#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff) +#endif + + +#include "c_dispatch.h" +#include "m_argv.h" +#include "i_input.h" +#include "v_video.h" +#include "i_sound.h" +#include "d_gui.h" +#include "c_console.h" +#include "s_soundinternal.h" +#include "hardware.h" +#include "d_eventbase.h" +#include "v_text.h" +#include "version.h" +#include "engineerrors.h" +#include "i_system.h" +#include "i_interface.h" +#include "printf.h" +#include "c_buttons.h" +#include "cmdlib.h" +#include "i_mainwindow.h" + +// Compensate for w32api's lack +#ifndef GET_XBUTTON_WPARAM +#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) +#endif + + +#ifdef _DEBUG +#define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS +#else +//#define INGAME_PRIORITY_CLASS HIGH_PRIORITY_CLASS +#define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS +#endif + +FJoystickCollection *JoyDevices[NUM_JOYDEVICES]; + + +extern HINSTANCE g_hInst; + +bool GUICapture; +extern FMouse *Mouse; +extern FKeyboard *Keyboard; +extern bool ToggleFullscreen; + +bool VidResizing; + +extern BOOL vidactive; + +EXTERN_CVAR (String, language) +EXTERN_CVAR (Bool, lookstrafe) +EXTERN_CVAR (Bool, use_joystick) +EXTERN_CVAR (Bool, use_mouse) + +static int WheelDelta; +extern bool CursorState; + +void SetCursorState(bool visible); + +extern BOOL paused; +static bool noidle = false; + +LPDIRECTINPUT8 g_pdi; + +extern bool AppActive; + +int BlockMouseMove; + +static bool EventHandlerResultForNativeMouse; + + +EXTERN_CVAR(Bool, i_pauseinbackground); + + +CVAR (Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +static void I_CheckGUICapture () +{ + bool wantCapt = sysCallbacks.WantGuiCapture && sysCallbacks.WantGuiCapture(); + + if (wantCapt != GUICapture) + { + GUICapture = wantCapt; + if (wantCapt && Keyboard != NULL) + { + Keyboard->AllKeysUp(); + } + } +} + +void I_SetMouseCapture() +{ + SetCapture(mainwindow.GetHandle()); +} + +void I_ReleaseMouseCapture() +{ + ReleaseCapture(); +} + +bool GUIWndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) +{ + event_t ev = { EV_GUI_Event }; + + *result = 0; + + switch (message) + { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + if (message == WM_KEYUP || message == WM_SYSKEYUP) + { + ev.subtype = EV_GUI_KeyUp; + } + else + { + ev.subtype = (lParam & 0x40000000) ? EV_GUI_KeyRepeat : EV_GUI_KeyDown; + } + if (GetKeyState(VK_SHIFT) & 0x8000) ev.data3 |= GKM_SHIFT; + if (GetKeyState(VK_CONTROL) & 0x8000) ev.data3 |= GKM_CTRL; + if (GetKeyState(VK_MENU) & 0x8000) ev.data3 |= GKM_ALT; + if (wParam == VK_PROCESSKEY) + { // Use the scan code to determine the real virtual-key code. + // ImmGetVirtualKey() will supposedly do this, but it just returns + // VK_PROCESSKEY again. + wParam = MapVirtualKey((lParam >> 16) & 255, 1); + } + if ( (ev.data1 = MapVirtualKey(wParam, 2)) ) + { + D_PostEvent(&ev); + } + else + { + switch (wParam) + { + case VK_PRIOR: ev.data1 = GK_PGUP; break; + case VK_NEXT: ev.data1 = GK_PGDN; break; + case VK_END: ev.data1 = GK_END; break; + case VK_HOME: ev.data1 = GK_HOME; break; + case VK_LEFT: ev.data1 = GK_LEFT; break; + case VK_RIGHT: ev.data1 = GK_RIGHT; break; + case VK_UP: ev.data1 = GK_UP; break; + case VK_DOWN: ev.data1 = GK_DOWN; break; + case VK_DELETE: ev.data1 = GK_DEL; break; + case VK_ESCAPE: ev.data1 = GK_ESCAPE; break; + case VK_F1: ev.data1 = GK_F1; break; + case VK_F2: ev.data1 = GK_F2; break; + case VK_F3: ev.data1 = GK_F3; break; + case VK_F4: ev.data1 = GK_F4; break; + case VK_F5: ev.data1 = GK_F5; break; + case VK_F6: ev.data1 = GK_F6; break; + case VK_F7: ev.data1 = GK_F7; break; + case VK_F8: ev.data1 = GK_F8; break; + case VK_F9: ev.data1 = GK_F9; break; + case VK_F10: ev.data1 = GK_F10; break; + case VK_F11: ev.data1 = GK_F11; break; + case VK_F12: ev.data1 = GK_F12; break; + case VK_BROWSER_BACK: ev.data1 = GK_BACK; break; + } + if (ev.data1 != 0) + { + D_PostEvent(&ev); + } + } + // Return false for key downs so that we can handle special hotkeys + // in the main WndProc. + return ev.subtype == EV_GUI_KeyUp; + + case WM_CHAR: + case WM_SYSCHAR: + if (wParam >= ' ') // only send displayable characters + { + ev.subtype = EV_GUI_Char; + ev.data1 = wParam; + ev.data2 = (message == WM_SYSCHAR); + D_PostEvent(&ev); + return true; + } + break; + + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + case WM_MOUSEMOVE: + if (message >= WM_LBUTTONDOWN && message <= WM_LBUTTONDBLCLK) + { + ev.subtype = message - WM_LBUTTONDOWN + EV_GUI_LButtonDown; + } + else if (message >= WM_RBUTTONDOWN && message <= WM_RBUTTONDBLCLK) + { + ev.subtype = message - WM_RBUTTONDOWN + EV_GUI_RButtonDown; + } + else if (message >= WM_MBUTTONDOWN && message <= WM_MBUTTONDBLCLK) + { + ev.subtype = message - WM_MBUTTONDOWN + EV_GUI_MButtonDown; + } + else if (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONUP) + { + ev.subtype = message - WM_XBUTTONDOWN + EV_GUI_BackButtonDown; + if (GET_XBUTTON_WPARAM(wParam) == 2) + { + ev.subtype += EV_GUI_FwdButtonDown - EV_GUI_BackButtonDown; + } + else if (GET_XBUTTON_WPARAM(wParam) != 1) + { + break; + } + } + else if (message == WM_MOUSEMOVE) + { + ev.subtype = EV_GUI_MouseMove; + if (BlockMouseMove > 0) return true; + } + + ev.data1 = LOWORD(lParam); + ev.data2 = HIWORD(lParam); + if (screen != NULL) + { + screen->ScaleCoordsFromWindow(ev.data1, ev.data2); + } + + if (wParam & MK_SHIFT) ev.data3 |= GKM_SHIFT; + if (wParam & MK_CONTROL) ev.data3 |= GKM_CTRL; + if (GetKeyState(VK_MENU) & 0x8000) ev.data3 |= GKM_ALT; + + if (use_mouse) D_PostEvent(&ev); + return true; + + // Note: If the mouse is grabbed, it sends the mouse wheel events itself. + case WM_MOUSEWHEEL: + if (!use_mouse) return false; + if (wParam & MK_SHIFT) ev.data3 |= GKM_SHIFT; + if (wParam & MK_CONTROL) ev.data3 |= GKM_CTRL; + if (GetKeyState(VK_MENU) & 0x8000) ev.data3 |= GKM_ALT; + WheelDelta += (SHORT)HIWORD(wParam); + if (WheelDelta < 0) + { + ev.subtype = EV_GUI_WheelDown; + while (WheelDelta <= -WHEEL_DELTA) + { + D_PostEvent(&ev); + WheelDelta += WHEEL_DELTA; + } + } + else + { + ev.subtype = EV_GUI_WheelUp; + while (WheelDelta >= WHEEL_DELTA) + { + D_PostEvent(&ev); + WheelDelta -= WHEEL_DELTA; + } + } + return true; + } + return false; +} + +bool CallHook(FInputDevice *device, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) +{ + if (device == NULL) + { + return false; + } + *result = 0; + return device->WndProcHook(hWnd, message, wParam, lParam, result); +} + +LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT result; + + if (message == WM_INPUT) + { + UINT size; + + if (!GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)) && + size != 0) + { + TArray array(size, true); + uint8_t *buffer = array.data(); + if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER)) == size) + { + int code = GET_RAWINPUT_CODE_WPARAM(wParam); + if (Keyboard == NULL || !Keyboard->ProcessRawInput((RAWINPUT *)buffer, code)) + { + if (Mouse == NULL || !Mouse->ProcessRawInput((RAWINPUT *)buffer, code)) + { + if (JoyDevices[INPUT_RawPS2] != NULL) + { + JoyDevices[INPUT_RawPS2]->ProcessRawInput((RAWINPUT *)buffer, code); + } + } + } + } + } + return DefWindowProc(hWnd, message, wParam, lParam); + } + + if (CallHook(Keyboard, hWnd, message, wParam, lParam, &result)) + { + return result; + } + if (CallHook(Mouse, hWnd, message, wParam, lParam, &result)) + { + return result; + } + for (int i = 0; i < NUM_JOYDEVICES; ++i) + { + if (CallHook(JoyDevices[i], hWnd, message, wParam, lParam, &result)) + { + return result; + } + } + if (GUICapture && GUIWndProcHook(hWnd, message, wParam, lParam, &result)) + { + return result; + } + + if (message == WM_LBUTTONDOWN && sysCallbacks.WantLeftButton() && sysCallbacks.WantLeftButton()) + { + if (GUIWndProcHook(hWnd, message, wParam, lParam, &result)) + { + return result; + } + } + + + switch (message) + { + case WM_DESTROY: + SetPriorityClass (GetCurrentProcess(), NORMAL_PRIORITY_CLASS); + PostQuitMessage (0); + break; + + case WM_HOTKEY: + break; + + case WM_PAINT: + return DefWindowProc (hWnd, message, wParam, lParam); + + case WM_SETTINGCHANGE: + // If regional settings were changed, reget preferred languages + if (wParam == 0 && lParam != 0 && strcmp ((const char *)lParam, "intl") == 0) + { + language->Callback (); + } + return 0; + + case WM_KILLFOCUS: + I_CheckNativeMouse (true, false); // Make sure mouse gets released right away + break; + + case WM_SETFOCUS: + I_CheckNativeMouse (false, EventHandlerResultForNativeMouse); // This cannot call the event handler. Doing it from here is unsafe. + break; + + case WM_SETCURSOR: + if (!CursorState) + { + SetCursorState(false); // turn off window cursor + return TRUE; // Prevent Windows from setting cursor to window class cursor + } + else + { + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + + case WM_SIZE: + InvalidateRect (hWnd, NULL, FALSE); + break; + + case WM_KEYDOWN: + break; + + case WM_SYSKEYDOWN: + // Pressing Alt+Enter can toggle between fullscreen and windowed. + if (wParam == VK_RETURN && k_allowfullscreentoggle && !(lParam & 0x40000000)) + { + ToggleFullscreen = !ToggleFullscreen; + } + // Pressing Alt+F4 quits the program. + if (wParam == VK_F4 && !(lParam & 0x40000000)) + { + PostQuitMessage(0); + } + break; + + case WM_SYSCOMMAND: + // Prevent activation of the window menu with Alt+Space + if ((wParam & 0xFFF0) != SC_KEYMENU) + { + return DefWindowProc (hWnd, message, wParam, lParam); + } + break; + + case WM_DISPLAYCHANGE: + case WM_STYLECHANGED: + return DefWindowProc(hWnd, message, wParam, lParam); + + case WM_GETMINMAXINFO: + if (screen && !VidResizing) + { + LPMINMAXINFO mmi = (LPMINMAXINFO)lParam; + if (screen->IsFullscreen()) + { + RECT rect = { 0, 0, screen->GetWidth(), screen->GetHeight() }; + AdjustWindowRectEx(&rect, WS_VISIBLE | WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW); + mmi->ptMinTrackSize.x = rect.right - rect.left; + mmi->ptMinTrackSize.y = rect.bottom - rect.top; + } + else + { + RECT rect = { 0, 0, VID_MIN_WIDTH, VID_MIN_HEIGHT }; + AdjustWindowRectEx(&rect, GetWindowLongW(hWnd, GWL_STYLE), FALSE, GetWindowLongW(hWnd, GWL_EXSTYLE)); + mmi->ptMinTrackSize.x = rect.right - rect.left; + mmi->ptMinTrackSize.y = rect.bottom - rect.top; + } + return 0; + } + break; + + case WM_ACTIVATEAPP: + AppActive = (wParam == TRUE); + if (wParam || !i_pauseinbackground) + { + SetPriorityClass (GetCurrentProcess (), INGAME_PRIORITY_CLASS); + } + else if (!noidle && !(sysCallbacks.NetGame && sysCallbacks.NetGame())) + { + SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS); + } + S_SetSoundPaused (wParam); + break; + + case WM_ERASEBKGND: + return DefWindowProc(hWnd, message, wParam, lParam); + + case WM_DEVICECHANGE: + if (wParam == DBT_DEVNODES_CHANGED || + wParam == DBT_DEVICEARRIVAL || + wParam == DBT_CONFIGCHANGED) + { + event_t ev = { EV_DeviceChange }; + D_PostEvent(&ev); + } + return DefWindowProc (hWnd, message, wParam, lParam); + + default: + return DefWindowProc (hWnd, message, wParam, lParam); + } + + return 0; +} + +bool I_InitInput (void *hwnd) +{ + HRESULT hr; + + Printf ("I_InitInput\n"); + + noidle = !!Args->CheckParm ("-noidle"); + g_pdi = NULL; + + hr = DirectInput8Create(g_hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&g_pdi, NULL); + if (FAILED(hr)) + { + Printf(TEXTCOLOR_ORANGE "DirectInput8Create failed: %08lx\n", hr); + g_pdi = NULL; // Just to be sure DirectInput8Create didn't change it + } + + Printf ("I_StartupMouse\n"); + I_StartupMouse(); + + Printf ("I_StartupKeyboard\n"); + I_StartupKeyboard(); + + Printf ("I_StartupXInput\n"); + I_StartupXInput(); + + Printf ("I_StartupRawPS2\n"); + I_StartupRawPS2(); + + Printf ("I_StartupDirectInputJoystick\n"); + I_StartupDirectInputJoystick(); + + return TRUE; +} + + +// Free all input resources +void I_ShutdownInput () +{ + if (Keyboard != NULL) + { + delete Keyboard; + Keyboard = NULL; + } + if (Mouse != NULL) + { + delete Mouse; + Mouse = NULL; + } + for (int i = 0; i < NUM_JOYDEVICES; ++i) + { + if (JoyDevices[i] != NULL) + { + delete JoyDevices[i]; + JoyDevices[i] = NULL; + } + } + if (g_pdi) + { + g_pdi->Release (); + g_pdi = NULL; + } +} + +void I_GetEvent () +{ + MSG mess; + + // Briefly enter an alertable state so that if a secondary thread + // crashed, we will execute the APC it sent now. + SleepEx (0, TRUE); + + while (PeekMessage (&mess, NULL, 0, 0, PM_REMOVE)) + { + if (mess.message == WM_QUIT) + throw CExitEvent(mess.wParam); + + if (GUICapture) + { + TranslateMessage (&mess); + } + DispatchMessage (&mess); + } + + if (Keyboard != NULL) + { + Keyboard->ProcessInput(); + } + if (Mouse != NULL) + { + Mouse->ProcessInput(); + } +} + +// +// I_StartTic +// +void I_StartTic () +{ + BlockMouseMove--; + buttonMap.ResetButtonTriggers (); + I_CheckGUICapture (); + EventHandlerResultForNativeMouse = sysCallbacks.WantNativeMouse && sysCallbacks.WantNativeMouse(); + I_CheckNativeMouse (false, EventHandlerResultForNativeMouse); + I_GetEvent (); +} + +// +// I_StartFrame +// +void I_StartFrame () +{ + if (use_joystick) + { + for (int i = 0; i < NUM_JOYDEVICES; ++i) + { + if (JoyDevices[i] != NULL) + { + JoyDevices[i]->ProcessInput(); + } + } + } +} + +void I_GetAxes(float axes[NUM_JOYAXIS]) +{ + int i; + + for (i = 0; i < NUM_JOYAXIS; ++i) + { + axes[i] = 0; + } + if (use_joystick) + { + for (i = 0; i < NUM_JOYDEVICES; ++i) + { + if (JoyDevices[i] != NULL) + { + JoyDevices[i]->AddAxes(axes); + } + } + } +} + +void I_GetJoysticks(TArray &sticks) +{ + sticks.Clear(); + for (int i = 0; i < NUM_JOYDEVICES; ++i) + { + if (JoyDevices[i] != NULL) + { + JoyDevices[i]->GetDevices(sticks); + } + } +} + +// If a new controller was added, returns a pointer to it. +IJoystickConfig *I_UpdateDeviceList() +{ + IJoystickConfig *newone = NULL; + for (int i = 0; i < NUM_JOYDEVICES; ++i) + { + if (JoyDevices[i] != NULL) + { + IJoystickConfig *thisnewone = JoyDevices[i]->Rescan(); + if (newone == NULL) + { + newone = thisnewone; + } + } + } + return newone; +} + +void I_PutInClipboard (const char *str) +{ + if (str == NULL || !OpenClipboard (mainwindow.GetHandle())) + return; + EmptyClipboard (); + + auto wstr = WideString(str); + HGLOBAL cliphandle = GlobalAlloc (GMEM_DDESHARE, wstr.length() * 2 + 2); + if (cliphandle != nullptr) + { + wchar_t *ptr = (wchar_t *)GlobalLock (cliphandle); + if (ptr) + { + wcscpy(ptr, wstr.c_str()); + GlobalUnlock(cliphandle); + SetClipboardData(CF_UNICODETEXT, cliphandle); + } + } + CloseClipboard (); +} + +FString I_GetFromClipboard (bool return_nothing) +{ + FString retstr; + HGLOBAL cliphandle; + wchar_t *clipstr; + + if (return_nothing || !IsClipboardFormatAvailable (CF_UNICODETEXT) || !OpenClipboard (mainwindow.GetHandle())) + return retstr; + + cliphandle = GetClipboardData (CF_UNICODETEXT); + if (cliphandle != nullptr) + { + clipstr = (wchar_t *)GlobalLock (cliphandle); + if (clipstr != nullptr) + { + // Convert CR-LF pairs to just LF. + retstr = clipstr; + GlobalUnlock(clipstr); + retstr.Substitute("\r\n", "\n"); + } + } + + CloseClipboard (); + return retstr; +} + +//========================================================================== +// +// FInputDevice - Destructor +// +//========================================================================== + +FInputDevice::~FInputDevice() +{ +} + +//========================================================================== +// +// FInputDevice :: ProcessInput +// +// Gives subclasses an opportunity to do input handling that doesn't involve +// window messages. +// +//========================================================================== + +void FInputDevice::ProcessInput() +{ +} + +//========================================================================== +// +// FInputDevice :: ProcessRawInput +// +// Gives subclasses a chance to handle WM_INPUT messages. This is not part +// of WndProcHook so that we only need to fill the RAWINPUT buffer once +// per message and be sure it gets cleaned up properly. +// +//========================================================================== + +bool FInputDevice::ProcessRawInput(RAWINPUT *raw, int code) +{ + return false; +} + +//========================================================================== +// +// FInputDevice :: WndProcHook +// +// Gives subclasses a chance to intercept window messages. +// +//========================================================================== + +bool FInputDevice::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) +{ + return false; +} + diff --git a/src/win32/i_input.h b/src/common/platform/win32/i_input.h similarity index 96% rename from src/win32/i_input.h rename to src/common/platform/win32/i_input.h index 00f853e9b35..16a276ce839 100644 --- a/src/win32/i_input.h +++ b/src/common/platform/win32/i_input.h @@ -34,8 +34,7 @@ #ifndef __I_INPUT_H__ #define __I_INPUT_H__ -#include "doomtype.h" -#include "doomdef.h" +#include "basics.h" bool I_InitInput (void *hwnd); void I_ShutdownInput (); @@ -78,13 +77,11 @@ class FMouse : public FInputDevice virtual void Ungrab() = 0; protected: - void PostMouseMove(int x, int y); void WheelMoved(int axis, int wheelmove); void PostButtonEvent(int button, bool down); void ClearButtonState(); int WheelMove[2]; - int LastX, LastY; // for m_filter int ButtonState; // bit mask of current button states (1=down, 0=up) }; @@ -118,7 +115,7 @@ class FKeyboard : public FInputDevice void PostKeyEvent(int keynum, INTBOOL down, bool foreground); }; -class NOVTABLE FJoystickCollection : public FInputDevice +class FJoystickCollection : public FInputDevice { public: virtual void AddAxes(float axes[NUM_JOYAXIS]) = 0; diff --git a/src/win32/i_keyboard.cpp b/src/common/platform/win32/i_keyboard.cpp similarity index 96% rename from src/win32/i_keyboard.cpp rename to src/common/platform/win32/i_keyboard.cpp index 9567809f534..33cf6da5ba0 100644 --- a/src/win32/i_keyboard.cpp +++ b/src/common/platform/win32/i_keyboard.cpp @@ -39,7 +39,8 @@ #include #include "i_input.h" -#include "d_event.h" +#include "d_eventbase.h" +#include "i_mainwindow.h" // MACROS ------------------------------------------------------------------ @@ -58,7 +59,7 @@ class FDInputKeyboard : public FKeyboard public: FDInputKeyboard(); ~FDInputKeyboard(); - + bool GetDevice(); void ProcessInput(); @@ -87,9 +88,7 @@ class FRawKeyboard : public FKeyboard // EXTERNAL DATA DECLARATIONS ---------------------------------------------- -extern HWND Window; extern LPDIRECTINPUT8 g_pdi; -extern LPDIRECTINPUT g_pdi3; extern bool GUICapture; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -277,6 +276,8 @@ void FKeyboard::PostKeyEvent(int key, INTBOOL down, bool foreground) } ev.data1 = key; ev.data2 = Convert[key]; + ev.data3 = 0; + if (CheckKey(DIK_LSHIFT) || CheckKey(DIK_RSHIFT)) ev.data3 |= 1; D_PostEvent(&ev); } @@ -318,17 +319,13 @@ bool FDInputKeyboard::GetDevice() { HRESULT hr; - if (g_pdi3 != NULL) - { // DirectInput3 interface - hr = g_pdi3->CreateDevice(GUID_SysKeyboard, (LPDIRECTINPUTDEVICE*)&Device, NULL); - } - else if (g_pdi != NULL) + if (g_pdi != NULL) { // DirectInput8 interface hr = g_pdi->CreateDevice(GUID_SysKeyboard, &Device, NULL); } else { - hr = -1; + hr = E_FAIL; } if (FAILED(hr)) { @@ -345,7 +342,7 @@ bool FDInputKeyboard::GetDevice() return false; } - hr = Device->SetCooperativeLevel(Window, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + hr = Device->SetCooperativeLevel(mainwindow.GetHandle(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); if (FAILED(hr)) { goto ufailit; @@ -377,11 +374,11 @@ void FDInputKeyboard::ProcessInput() DIDEVICEOBJECTDATA od; DWORD dwElements; HRESULT hr; - bool foreground = (GetForegroundWindow() == Window); + bool foreground = (GetForegroundWindow() == mainwindow.GetHandle()); for (;;) { - DWORD cbObjectData = g_pdi3 ? sizeof(DIDEVICEOBJECTDATA_DX3) : sizeof(DIDEVICEOBJECTDATA); + DWORD cbObjectData = sizeof(DIDEVICEOBJECTDATA); dwElements = 1; hr = Device->GetDeviceData(cbObjectData, &od, &dwElements, 0); if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) @@ -446,7 +443,7 @@ bool FRawKeyboard::GetDevice() rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE; rid.usUsage = HID_GDP_KEYBOARD; rid.dwFlags = RIDEV_INPUTSINK; - rid.hwndTarget = Window; + rid.hwndTarget = mainwindow.GetHandle(); if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { return false; diff --git a/src/common/platform/win32/i_main.cpp b/src/common/platform/win32/i_main.cpp new file mode 100644 index 00000000000..acadc2dc823 --- /dev/null +++ b/src/common/platform/win32/i_main.cpp @@ -0,0 +1,572 @@ +/* +** i_main.cpp +** System-specific startup code. Eventually calls D_DoomMain. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +#ifdef _MSC_VER +#include +#include +#include +#endif +#include "resource.h" + +#include "engineerrors.h" +#include "hardware.h" + +#include "m_argv.h" +#include "i_module.h" +#include "c_console.h" +#include "version.h" +#include "i_input.h" +#include "filesystem.h" +#include "cmdlib.h" +#include "s_soundinternal.h" +#include "vm.h" +#include "i_system.h" +#include "gstrings.h" +#include "s_music.h" + +#include "stats.h" +#include "st_start.h" +#include "i_interface.h" +#include "startupinfo.h" +#include "printf.h" + +#include "i_mainwindow.h" + +// MACROS ------------------------------------------------------------------ + +// The main window's title. +#ifdef _M_X64 +#define X64 " 64-bit" +#elif _M_ARM64 +#define X64 " ARM-64" +#else +#define X64 "" +#endif + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); +void CreateCrashLog (const char *custominfo, DWORD customsize); +void DisplayCrashLog (); +void DestroyCustomCursor(); +int GameMain(); + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern EXCEPTION_POINTERS CrashPointers; +extern UINT TimerPeriod; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// The command line arguments. +FArgs *Args; + +HINSTANCE g_hInst; +HANDLE MainThread; +DWORD MainThreadID; +HANDLE StdOut; +bool FancyStdOut, AttachedStdOut; + +// CODE -------------------------------------------------------------------- + + +//========================================================================== +// +// I_SetIWADInfo +// +//========================================================================== + +void I_SetIWADInfo() +{ +} + +//========================================================================== +// +// DoMain +// +//========================================================================== + +int DoMain (HINSTANCE hInstance) +{ + LONG WinWidth, WinHeight; + int height, width, x, y; + RECT cRect; + TIMECAPS tc; + DEVMODE displaysettings; + + // Do not use the multibyte __argv here because we want UTF-8 arguments + // and those can only be done by converting the Unicode variants. + Args = new FArgs(); + auto argc = __argc; + auto wargv = __wargv; + for (int i = 0; i < argc; i++) + { + Args->AppendArg(FString(wargv[i])); + } + + if (Args->CheckParm("-stdout") || Args->CheckParm("-norun")) + { + // As a GUI application, we don't normally get a console when we start. + // If we were run from the shell and are on XP+, we can attach to its + // console. Otherwise, we can create a new one. If we already have a + // stdout handle, then we have been redirected and should just use that + // handle instead of creating a console window. + + StdOut = GetStdHandle(STD_OUTPUT_HANDLE); + if (StdOut != NULL) + { + // It seems that running from a shell always creates a std output + // for us, even if it doesn't go anywhere. (Running from Explorer + // does not.) If we can get file information for this handle, it's + // a file or pipe, so use it. Otherwise, pretend it wasn't there + // and find a console to use instead. + BY_HANDLE_FILE_INFORMATION info; + if (!GetFileInformationByHandle(StdOut, &info)) + { + StdOut = NULL; + } + } + if (StdOut == nullptr) + { + if (AttachConsole(ATTACH_PARENT_PROCESS)) + { + StdOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD foo; WriteFile(StdOut, "\n", 1, &foo, NULL); + AttachedStdOut = true; + } + if (StdOut == nullptr && AllocConsole()) + { + StdOut = GetStdHandle(STD_OUTPUT_HANDLE); + } + if (StdOut != nullptr) + { + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + DWORD mode; + if (GetConsoleMode(StdOut, &mode)) + { + if (SetConsoleMode(StdOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) + FancyStdOut = IsWindows10OrGreater(); // Windows 8.1 and lower do not understand ANSI formatting. + } + } + } + } + + // Set the timer to be as accurate as possible + if (timeGetDevCaps (&tc, sizeof(tc)) != TIMERR_NOERROR) + TimerPeriod = 1; // Assume minimum resolution of 1 ms + else + TimerPeriod = tc.wPeriodMin; + + timeBeginPeriod (TimerPeriod); + atexit([](){ timeEndPeriod(TimerPeriod); }); + + // Figure out what directory the program resides in. + WCHAR progbuff[1024]; + if (GetModuleFileNameW(nullptr, progbuff, sizeof progbuff) == 0) + { + MessageBoxA(nullptr, "Fatal", "Could not determine program location.", MB_ICONEXCLAMATION|MB_OK); + exit(-1); + } + + progbuff[1023] = '\0'; + if (auto lastsep = wcsrchr(progbuff, '\\')) + { + lastsep[1] = '\0'; + } + + progdir = progbuff; + FixPathSeperator(progdir); + + HDC screenDC = GetDC(0); + int dpi = GetDeviceCaps(screenDC, LOGPIXELSX); + ReleaseDC(0, screenDC); + width = (512 * dpi + 96 / 2) / 96; + height = (384 * dpi + 96 / 2) / 96; + + // Many Windows structures that specify their size do so with the first + // element. DEVMODE is not one of those structures. + memset (&displaysettings, 0, sizeof(displaysettings)); + displaysettings.dmSize = sizeof(displaysettings); + EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings); + x = (displaysettings.dmPelsWidth - width) / 2; + y = (displaysettings.dmPelsHeight - height) / 2; + + if (Args->CheckParm ("-0")) + { + x = y = 0; + } + + /* create window */ + FStringf caption("" GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); + mainwindow.Create(caption, x, y, width, height); + + GetClientRect (mainwindow.GetHandle(), &cRect); + + WinWidth = cRect.right; + WinHeight = cRect.bottom; + + CoInitialize (NULL); + atexit ([](){ CoUninitialize(); }); // beware of calling convention. + + int ret = GameMain (); + + if (mainwindow.CheckForRestart()) + { + HMODULE hModule = GetModuleHandleW(NULL); + WCHAR path[MAX_PATH]; + GetModuleFileNameW(hModule, path, MAX_PATH); + ShellExecuteW(NULL, L"open", path, GetCommandLineW(), NULL, SW_SHOWNORMAL); + } + + DestroyCustomCursor(); + if (ret == 1337) // special exit code for 'norun'. + { + if (!batchrun) + { + if (FancyStdOut && !AttachedStdOut) + { // Outputting to a new console window: Wait for a keypress before quitting. + DWORD bytes; + HANDLE stdinput = GetStdHandle(STD_INPUT_HANDLE); + + ShowWindow(mainwindow.GetHandle(), SW_HIDE); + if (StdOut != nullptr) WriteFile(StdOut, "Press any key to exit...", 24, &bytes, nullptr); + FlushConsoleInputBuffer(stdinput); + SetConsoleMode(stdinput, 0); + ReadConsole(stdinput, &bytes, 1, &bytes, NULL); + } + else if (StdOut == nullptr) + { + mainwindow.ShowErrorPane(nullptr); + } + } + } + return ret; +} + +void I_ShowFatalError(const char *msg) +{ + I_ShutdownGraphics (); + mainwindow.RestoreConView(); + S_StopMusic(true); + + if (CVMAbortException::stacktrace.IsNotEmpty()) + { + Printf("%s", CVMAbortException::stacktrace.GetChars()); + } + + if (!batchrun) + { + mainwindow.ShowErrorPane(msg); + } + else + { + Printf("%s\n", msg); + } +} + +// Here is how the error logging system works. +// +// To catch exceptions that occur in secondary threads, CatchAllExceptions is +// set as the UnhandledExceptionFilter for this process. It records the state +// of the thread at the time of the crash using CreateCrashLog and then queues +// an APC on the primary thread. When the APC executes, it raises a software +// exception that gets caught by the __try/__except block in WinMain. +// I_GetEvent calls SleepEx to put the primary thread in a waitable state +// periodically so that the APC has a chance to execute. +// +// Exceptions on the primary thread are caught by the __try/__except block in +// WinMain. Not only does it record the crash information, it also shuts +// everything down and displays a dialog with the information present. If a +// console log is being produced, the information will also be appended to it. +// +// If a debugger is running, CatchAllExceptions never executes, so secondary +// thread exceptions will always be caught by the debugger. For the primary +// thread, IsDebuggerPresent is called to determine if a debugger is present. +// Note that this function is not present on Windows 95, so we cannot +// statically link to it. +// +// To make this work with MinGW, you will need to use inline assembly +// because GCC offers no native support for Windows' SEH. + +//========================================================================== +// +// SleepForever +// +//========================================================================== + +void SleepForever () +{ + Sleep (INFINITE); +} + +//========================================================================== +// +// ExitMessedUp +// +// An exception occurred while exiting, so don't do any standard processing. +// Just die. +// +//========================================================================== + +LONG WINAPI ExitMessedUp (LPEXCEPTION_POINTERS foo) +{ + ExitProcess (1000); +} + +//========================================================================== +// +// ExitFatally +// +//========================================================================== + +void CALLBACK ExitFatally (ULONG_PTR dummy) +{ + SetUnhandledExceptionFilter (ExitMessedUp); + I_ShutdownGraphics (); + mainwindow.RestoreConView (); + DisplayCrashLog (); + exit(-1); +} + +#ifndef _M_ARM64 +//========================================================================== +// +// CatchAllExceptions +// +//========================================================================== + +namespace +{ + CONTEXT MainThreadContext; +} + +LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info) +{ +#ifdef _DEBUG + if (info->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) + { + return EXCEPTION_CONTINUE_SEARCH; + } +#endif + + static bool caughtsomething = false; + + if (caughtsomething) return EXCEPTION_EXECUTE_HANDLER; + caughtsomething = true; + + char *custominfo = (char *)HeapAlloc (GetProcessHeap(), 0, 16384); + + CrashPointers = *info; + if (sysCallbacks.CrashInfo && custominfo) sysCallbacks.CrashInfo(custominfo, 16384, "\r\n"); + CreateCrashLog (custominfo, (DWORD)strlen(custominfo)); + + // If the main thread crashed, then make it clean up after itself. + // Otherwise, put the crashing thread to sleep and signal the main thread to clean up. + if (GetCurrentThreadId() == MainThreadID) + { +#ifdef _M_X64 + *info->ContextRecord = MainThreadContext; +#else + info->ContextRecord->Eip = (DWORD_PTR)ExitFatally; +#endif // _M_X64 + } + else + { +#ifndef _M_X64 + info->ContextRecord->Eip = (DWORD_PTR)SleepForever; +#else + info->ContextRecord->Rip = (DWORD_PTR)SleepForever; +#endif + QueueUserAPC (ExitFatally, MainThread, 0); + } + return EXCEPTION_CONTINUE_EXECUTION; +} +#else // !_M_ARM64 +// stub this function for ARM64 +LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info) +{ + return EXCEPTION_CONTINUE_EXECUTION; +} +#endif // !_M_ARM64 + +//========================================================================== +// +// infiniterecursion +// +// Debugging routine for testing the crash logger. +// +//========================================================================== + +#ifdef _DEBUG +static void infiniterecursion(int foo) +{ + if (foo) + { + infiniterecursion(foo); + } +} +#endif + +// Setting this to 'true' allows getting the standard notification for a crash +// which offers the very important feature to open a debugger and see the crash in context right away. +CUSTOM_CVAR(Bool, disablecrashlog, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + SetUnhandledExceptionFilter(!*self ? CatchAllExceptions : nullptr); +} + +//========================================================================== +// +// WinMain +// +//========================================================================== + +int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE nothing, LPWSTR cmdline, int nCmdShow) +{ + g_hInst = hInstance; + + InitCommonControls (); // Load some needed controls and be pretty under XP + + // We need to load riched20.dll so that we can create the control. + if (NULL == LoadLibraryA ("riched20.dll")) + { + // This should only happen on basic Windows 95 installations, but since we + // don't support Windows 95, we have no obligation to provide assistance in + // getting it installed. + MessageBoxA(NULL, "Could not load riched20.dll", GAMENAME " Error", MB_OK | MB_ICONSTOP); + return 0; + } + +#if !defined(__GNUC__) && defined(_DEBUG) + if (__argc == 2 && __wargv != nullptr && wcscmp (__wargv[1], L"TestCrash") == 0) + { + __try + { + *(int *)0 = 0; + } + __except(CrashPointers = *GetExceptionInformation(), + CreateCrashLog ("TestCrash", 9), EXCEPTION_EXECUTE_HANDLER) + { + } + DisplayCrashLog (); + return 0; + } + if (__argc == 2 && __wargv != nullptr && wcscmp (__wargv[1], L"TestStackCrash") == 0) + { + __try + { + infiniterecursion(1); + } + __except(CrashPointers = *GetExceptionInformation(), + CreateCrashLog ("TestStackCrash", 14), EXCEPTION_EXECUTE_HANDLER) + { + } + DisplayCrashLog (); + return 0; + } +#endif + + MainThread = INVALID_HANDLE_VALUE; + DuplicateHandle (GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &MainThread, + 0, FALSE, DUPLICATE_SAME_ACCESS); + MainThreadID = GetCurrentThreadId(); + +#ifndef _DEBUG + if (MainThread != INVALID_HANDLE_VALUE) + { +#ifndef _M_ARM64 + SetUnhandledExceptionFilter (CatchAllExceptions); +#endif + +#ifdef _M_X64 + static bool setJumpResult = false; + RtlCaptureContext(&MainThreadContext); + if (setJumpResult) + { + ExitFatally(0); + return 0; + } + setJumpResult = true; +#endif // _M_X64 + } +#endif + +#if defined(_DEBUG) && defined(_MSC_VER) + // Uncomment this line to make the Visual C++ CRT check the heap before + // every allocation and deallocation. This will be slow, but it can be a + // great help in finding problem areas. + //_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF); + + // Enable leak checking at exit. + _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); + + // Use this to break at a specific allocation number. + //_crtBreakAlloc = 227524; +#endif + + int ret = DoMain (hInstance); + + CloseHandle (MainThread); + MainThread = INVALID_HANDLE_VALUE; + return ret; +} + +// each platform has its own specific version of this function. +void I_SetWindowTitle(const char* caption) +{ + mainwindow.SetWindowTitle(caption); +} diff --git a/src/common/platform/win32/i_mainwindow.cpp b/src/common/platform/win32/i_mainwindow.cpp new file mode 100644 index 00000000000..95dda5031f3 --- /dev/null +++ b/src/common/platform/win32/i_mainwindow.cpp @@ -0,0 +1,190 @@ + +#include "i_mainwindow.h" +#include "resource.h" +#include "startupinfo.h" +#include "gstrings.h" +#include "palentry.h" +#include "st_start.h" +#include "i_input.h" +#include "version.h" +#include "utf8.h" +#include "v_font.h" +#include "i_net.h" +#include "engineerrors.h" +#include "common/widgets/errorwindow.h" +#include "common/widgets/netstartwindow.h" +#include +#include +#include +#include + +#pragma comment(lib, "dwmapi.lib") + +MainWindow mainwindow; + +void MainWindow::Create(const FString& caption, int x, int y, int width, int height) +{ + static const WCHAR WinClassName[] = L"MainWindow"; + + HINSTANCE hInstance = GetModuleHandle(0); + + WNDCLASS WndClass; + WndClass.style = 0; + WndClass.lpfnWndProc = LConProc; + WndClass.cbClsExtra = 0; + WndClass.cbWndExtra = 0; + WndClass.hInstance = hInstance; + WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); + WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + WndClass.hbrBackground = CreateSolidBrush(RGB(0,0,0)); + WndClass.lpszMenuName = NULL; + WndClass.lpszClassName = WinClassName; + + /* register this new class with Windows */ + if (!RegisterClass((LPWNDCLASS)&WndClass)) + { + MessageBoxA(nullptr, "Could not register window class", "Fatal", MB_ICONEXCLAMATION | MB_OK); + exit(-1); + } + + std::wstring wcaption = caption.WideString(); + Window = CreateWindowExW( + WS_EX_APPWINDOW, + WinClassName, + wcaption.c_str(), + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, + x, y, width, height, + (HWND)NULL, + (HMENU)NULL, + hInstance, + NULL); + + if (!Window) + { + MessageBoxA(nullptr, "Unable to create main window", "Fatal", MB_ICONEXCLAMATION | MB_OK); + exit(-1); + } + + uint32_t bordercolor = RGB(51, 51, 51); + uint32_t captioncolor = RGB(33, 33, 33); + uint32_t textcolor = RGB(226, 223, 219); + + // Don't error check these as they only exist on Windows 11, and if they fail then that is OK. + DwmSetWindowAttribute(Window, 34/*DWMWA_BORDER_COLOR*/, &bordercolor, sizeof(uint32_t)); + DwmSetWindowAttribute(Window, 35/*DWMWA_CAPTION_COLOR*/, &captioncolor, sizeof(uint32_t)); + DwmSetWindowAttribute(Window, 36/*DWMWA_TEXT_COLOR*/, &textcolor, sizeof(uint32_t)); +} + +// Sets the main WndProc, hides all the child windows, and starts up in-game input. +void MainWindow::ShowGameView() +{ + if (GetWindowLongPtr(Window, GWLP_USERDATA) == 0) + { + SetWindowLongPtr(Window, GWLP_USERDATA, 1); + SetWindowLongPtr(Window, GWLP_WNDPROC, (LONG_PTR)WndProc); + I_InitInput(Window); + } +} + +// Returns the main window to its startup state. +void MainWindow::RestoreConView() +{ + I_ShutdownInput(); // Make sure the mouse pointer is available. + ShowWindow(Window, SW_HIDE); + + // Make sure the progress bar isn't visible. + DeleteStartupScreen(); +} + +// Shows an error message, preferably in the main window, but it can use a normal message box too. +void MainWindow::ShowErrorPane(const char* text) +{ + if (StartWindow) // Ensure that the network pane is hidden. + { + I_NetDone(); + } + + // PrintStr(text); + + size_t totalsize = 0; + for (const FString& line : bufferedConsoleStuff) + totalsize += line.Len(); + + std::string alltext; + alltext.reserve(totalsize); + for (const FString& line : bufferedConsoleStuff) + alltext.append(line.GetChars(), line.Len()); + + restartrequest = ErrorWindow::ExecModal(text, alltext); +} + +void MainWindow::ShowNetStartPane(const char* message, int maxpos) +{ + NetStartWindow::ShowNetStartPane(message, maxpos); +} + +void MainWindow::HideNetStartPane() +{ + NetStartWindow::HideNetStartPane(); +} + +void MainWindow::SetNetStartProgress(int pos) +{ + NetStartWindow::SetNetStartProgress(pos); +} + +bool MainWindow::RunMessageLoop(bool (*timer_callback)(void*), void* userdata) +{ + return NetStartWindow::RunMessageLoop(timer_callback, userdata); +} + +bool MainWindow::CheckForRestart() +{ + bool result = restartrequest; + restartrequest = false; + return result; +} + +// The main window's WndProc during startup. During gameplay, the WndProc in i_input.cpp is used instead. +LRESULT MainWindow::LConProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +void MainWindow::PrintStr(const char* cp) +{ + bufferedConsoleStuff.Push(cp); +} + +void MainWindow::GetLog(std::function writeData) +{ + for (const FString& line : bufferedConsoleStuff) + { + size_t pos = 0; + size_t len = line.Len(); + while (pos < len) + { + uint32_t size = (uint32_t)std::min(len - pos, 0x0fffffffULL); + uint32_t written = 0; + if (!writeData(&line[pos], size, written)) + return; + pos += written; + } + } +} + +// each platform has its own specific version of this function. +void MainWindow::SetWindowTitle(const char* caption) +{ + std::wstring widecaption; + if (!caption) + { + FStringf default_caption("" GAMENAME " %s (%s)", GetVersionString(), GetGitTime()); + widecaption = default_caption.WideString(); + } + else + { + widecaption = WideString(caption); + } + SetWindowText(Window, widecaption.c_str()); +} diff --git a/src/common/platform/win32/i_mainwindow.h b/src/common/platform/win32/i_mainwindow.h new file mode 100644 index 00000000000..3c0c7e55df4 --- /dev/null +++ b/src/common/platform/win32/i_mainwindow.h @@ -0,0 +1,45 @@ +#pragma once + +#include "zstring.h" +#include "printf.h" + +#include + +#define WIN32_LEAN_AND_MEAN +#include + +// The WndProc used when the game view is active +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +class MainWindow +{ +public: + void Create(const FString& title, int x, int y, int width, int height); + + void ShowGameView(); + void RestoreConView(); + + void ShowErrorPane(const char* text); + bool CheckForRestart(); + + void PrintStr(const char* cp); + void GetLog(std::function writeFile); + + void ShowNetStartPane(const char* message, int maxpos); + void SetNetStartProgress(int pos); + bool RunMessageLoop(bool (*timer_callback)(void*), void* userdata); + void HideNetStartPane(); + + void SetWindowTitle(const char* caption); + + HWND GetHandle() { return Window; } + +private: + static LRESULT CALLBACK LConProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + + HWND Window = 0; + bool restartrequest = false; + TArray bufferedConsoleStuff; +}; + +extern MainWindow mainwindow; diff --git a/src/win32/i_mouse.cpp b/src/common/platform/win32/i_mouse.cpp similarity index 90% rename from src/win32/i_mouse.cpp rename to src/common/platform/win32/i_mouse.cpp index ce1121c9720..e0050cc3ab9 100644 --- a/src/win32/i_mouse.cpp +++ b/src/common/platform/win32/i_mouse.cpp @@ -39,12 +39,14 @@ #include #include "i_input.h" -#include "d_event.h" +#include "d_eventbase.h" #include "d_gui.h" -#include "g_game.h" #include "hardware.h" -#include "menu/menu.h" -#include "events.h" +#include "menu.h" +#include "menustate.h" +#include "keydef.h" +#include "i_interface.h" +#include "i_mainwindow.h" // MACROS ------------------------------------------------------------------ @@ -85,7 +87,7 @@ class FDInputMouse : public FMouse public: FDInputMouse(); ~FDInputMouse(); - + bool GetDevice(); void ProcessInput(); bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); @@ -102,7 +104,7 @@ class FWin32Mouse : public FMouse public: FWin32Mouse(); ~FWin32Mouse(); - + bool GetDevice(); void ProcessInput(); bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); @@ -129,7 +131,7 @@ enum EMouseMode // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- -static void SetCursorState(bool visible); +void SetCursorState(bool visible); static FMouse *CreateWin32Mouse(); static FMouse *CreateDInputMouse(); static FMouse *CreateRawMouse(); @@ -137,9 +139,7 @@ static void CenterMouse(int x, int y, LONG *centx, LONG *centy); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- -extern HWND Window; extern LPDIRECTINPUT8 g_pdi; -extern LPDIRECTINPUT g_pdi3; extern bool GUICapture; extern int BlockMouseMove; @@ -161,8 +161,6 @@ bool NativeMouse; bool CursorState; CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, m_hidepointer, true, 0) CUSTOM_CVAR (Int, in_mouse, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) @@ -181,19 +179,6 @@ CUSTOM_CVAR (Int, in_mouse, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) } } -CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) -{ - if (self < 0) - { - self = 0; - } - else if (self > 2) - { - self = 2; - } -} - - // CODE -------------------------------------------------------------------- //========================================================================== @@ -204,18 +189,28 @@ CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) // //========================================================================== -static void SetCursorState(bool visible) +static bool mouse_shown = true; + +void SetCursorState(bool visible) { CursorState = visible || !m_hidepointer; - if (GetForegroundWindow() == Window) + if (GetForegroundWindow() == mainwindow.GetHandle()) { if (CursorState) { - SetCursor((HCURSOR)(intptr_t)GetClassLongPtr(Window, GCLP_HCURSOR)); + if(!mouse_shown) + { + ShowCursor(true); + mouse_shown = true; + } } else { - SetCursor(NULL); + if(mouse_shown) + { + ShowCursor(false); + mouse_shown = false; + } } } } @@ -233,7 +228,7 @@ static void CenterMouse(int curx, int cury, LONG *centxp, LONG *centyp) { RECT rect; - GetWindowRect(Window, &rect); + GetWindowRect(mainwindow.GetHandle(), &rect); int centx = (rect.left + rect.right) >> 1; int centy = (rect.top + rect.bottom) >> 1; @@ -251,28 +246,6 @@ static void CenterMouse(int curx, int cury, LONG *centxp, LONG *centyp) } } -//========================================================================== -// -// CaptureMode_InGame -// -//========================================================================== - -static bool CaptureMode_InGame() -{ - if (mouse_capturemode == 2) - { - return true; - } - else if (mouse_capturemode == 1) - { - return gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_FINALE; - } - else - { - return gamestate == GS_LEVEL; - } -} - //========================================================================== // // I_CheckNativeMouse @@ -294,7 +267,7 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult) } else { - if ((GetForegroundWindow() != Window) || preferNative || !use_mouse) + if (preferNative || !use_mouse) { want_native = true; } @@ -304,14 +277,19 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult) } else { + bool captureModeInGame = sysCallbacks.CaptureModeInGame && sysCallbacks.CaptureModeInGame(); want_native = ((!m_use_mouse || menuactive != MENU_WaitKey) && - (!CaptureMode_InGame() || GUICapture || paused || demoplayback)); + (!captureModeInGame || GUICapture)); } } if (!want_native && eventhandlerresult) want_native = true; + // The application should *never* grab the mouse cursor if its window doesn't have the focus. + if (GetForegroundWindow() != mainwindow.GetHandle()) + want_native = true; + //Printf ("%d %d %d\n", wantNative, preferNative, NativeMouse); if (want_native != NativeMouse) @@ -323,6 +301,12 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult) { BlockMouseMove = 3; Mouse->Ungrab(); + + if(!mouse_shown) + { + ShowCursor(true); + mouse_shown = true; + } } else { @@ -340,44 +324,11 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult) FMouse::FMouse() { - LastX = LastY = 0; ButtonState = 0; WheelMove[0] = 0; WheelMove[1] = 0; } -//========================================================================== -// -// FMouse :: PostMouseMove -// -// Posts a mouse movement event, potentially averaging it with the previous -// movement. If there is no movement to post, then no event is generated. -// -//========================================================================== - -void FMouse::PostMouseMove(int x, int y) -{ - event_t ev = { 0 }; - - if (m_filter) - { - ev.x = (x + LastX) / 2; - ev.y = (y + LastY) / 2; - } - else - { - ev.x = x; - ev.y = y; - } - LastX = x; - LastY = y; - if (ev.x | ev.y) - { - ev.type = EV_Mouse; - D_PostEvent(&ev); - } -} - //========================================================================== // // FMouse :: WheelMoved @@ -446,9 +397,18 @@ void FMouse::WheelMoved(int axis, int wheelmove) // //========================================================================== +CVAR(Bool, m_swapbuttons, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + void FMouse::PostButtonEvent(int button, bool down) { event_t ev = { 0 }; + + // Neither RawInput nor DirectInput check the GUI setting for swapped mouse buttons so we have to do our own implementation... + if (m_swapbuttons && button < 2) + { + button = 1 - button; + } + int mask = 1 << button; ev.data1 = KEY_MOUSE1 + button; @@ -548,7 +508,7 @@ bool FRawMouse::GetDevice() rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE; rid.usUsage = HID_GDP_MOUSE; rid.dwFlags = 0; - rid.hwndTarget = Window; + rid.hwndTarget = mainwindow.GetHandle(); if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { return false; @@ -574,7 +534,7 @@ void FRawMouse::Grab() rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE; rid.usUsage = HID_GDP_MOUSE; rid.dwFlags = RIDEV_CAPTUREMOUSE | RIDEV_NOLEGACY; - rid.hwndTarget = Window; + rid.hwndTarget = mainwindow.GetHandle(); if (RegisterRawInputDevices(&rid, 1, sizeof(rid))) { GetCursorPos(&UngrabbedPointerPos); @@ -652,8 +612,8 @@ bool FRawMouse::ProcessRawInput(RAWINPUT *raw, int code) { WheelMoved(1, (SHORT)raw->data.mouse.usButtonData); } - int x = m_noprescale ? raw->data.mouse.lLastX : raw->data.mouse.lLastX << 2; - int y = -raw->data.mouse.lLastY; + int x = raw->data.mouse.lLastX; + int y = raw->data.mouse.lLastY; PostMouseMove(x, y); if (x | y) { @@ -739,23 +699,19 @@ bool FDInputMouse::GetDevice() { HRESULT hr; - if (g_pdi3 != NULL) - { // DirectInput3 interface - hr = g_pdi3->CreateDevice(GUID_SysMouse, (LPDIRECTINPUTDEVICE*)&Device, NULL); - } - else if (g_pdi != NULL) + if (g_pdi != NULL) { // DirectInput8 interface hr = g_pdi->CreateDevice(GUID_SysMouse, &Device, NULL); } else { - hr = -1; + hr = E_FAIL; } if (FAILED(hr)) { return false; } - + // How many buttons does this mouse have? DIDEVCAPS_DX3 caps = { sizeof(caps) }; hr = Device->GetCapabilities((DIDEVCAPS *)&caps); @@ -776,7 +732,7 @@ bool FDInputMouse::GetDevice() return false; } - hr = Device->SetCooperativeLevel(Window, DISCL_EXCLUSIVE | DISCL_FOREGROUND); + hr = Device->SetCooperativeLevel(mainwindow.GetHandle(), DISCL_EXCLUSIVE | DISCL_FOREGROUND); if (FAILED(hr)) { goto ufailit; @@ -842,7 +798,7 @@ void FDInputMouse::ProcessInput() event_t ev = { 0 }; for (;;) { - DWORD cbObjectData = g_pdi3 ? sizeof(DIDEVICEOBJECTDATA_DX3) : sizeof(DIDEVICEOBJECTDATA); + DWORD cbObjectData = sizeof(DIDEVICEOBJECTDATA); dwElements = 1; hr = Device->GetDeviceData(cbObjectData, &od, &dwElements, 0); if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) @@ -879,7 +835,7 @@ void FDInputMouse::ProcessInput() } } } - PostMouseMove(m_noprescale ? dx : dx<<2, -dy); + PostMouseMove(dx, dy); } //========================================================================== @@ -984,18 +940,13 @@ void FWin32Mouse::ProcessInput() } x = pt.x - PrevX; - y = PrevY - pt.y; + y = pt.y - PrevY; - if (!m_noprescale) - { - x *= 3; - y *= 2; - } if (x | y) { CenterMouse(pt.x, pt.y, &PrevX, &PrevY); } - PostMouseMove(x, y); + PostMouseMove(2* x, 2* y); // The factor of 2 is needed to match this with raw mouse input. } //========================================================================== @@ -1129,11 +1080,11 @@ void FWin32Mouse::Grab() GetCursorPos(&UngrabbedPointerPos); ClipCursor(NULL); // helps with Win95? - GetClientRect(Window, &rect); + GetClientRect(mainwindow.GetHandle(), &rect); // Reposition the rect so that it only covers the client area. - ClientToScreen(Window, (LPPOINT)&rect.left); - ClientToScreen(Window, (LPPOINT)&rect.right); + ClientToScreen(mainwindow.GetHandle(), (LPPOINT)&rect.left); + ClientToScreen(mainwindow.GetHandle(), (LPPOINT)&rect.right); ClipCursor(&rect); SetCursorState(false); diff --git a/src/win32/i_rawps2.cpp b/src/common/platform/win32/i_rawps2.cpp similarity index 96% rename from src/win32/i_rawps2.cpp rename to src/common/platform/win32/i_rawps2.cpp index 0bf28efbacf..2f89739bd7d 100644 --- a/src/win32/i_rawps2.cpp +++ b/src/common/platform/win32/i_rawps2.cpp @@ -37,10 +37,14 @@ #include #include "i_input.h" -#include "d_event.h" -#include "templates.h" +#include "d_eventbase.h" + #include "gameconfigfile.h" #include "m_argv.h" +#include "cmdlib.h" +#include "keydef.h" + +#include "i_mainwindow.h" // MACROS ------------------------------------------------------------------ @@ -110,6 +114,13 @@ class FRawPS2Controller : public IJoystickConfig bool IsAxisMapDefault(int axis); bool IsAxisScaleDefault(int axis); + bool GetEnabled(); + void SetEnabled(bool enabled); + + bool AllowsEnabledInBackground() { return false; } + bool GetEnabledInBackground() { return false; } + void SetEnabledInBackground(bool enabled) {} + void SetDefaultConfig(); FString GetIdentifier(); @@ -149,6 +160,7 @@ class FRawPS2Controller : public IJoystickConfig bool Connected; bool Marked; bool Active; + bool Enabled; void Attached(); void Detached(); @@ -212,8 +224,6 @@ struct PS2Descriptor // EXTERNAL DATA DECLARATIONS ---------------------------------------------- -extern HWND Window; - // PUBLIC DATA DEFINITIONS ------------------------------------------------- CUSTOM_CVAR(Bool, joy_ps2raw, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL) @@ -374,6 +384,7 @@ FRawPS2Controller::FRawPS2Controller(HANDLE handle, EAdapterType type, int seque ControllerNumber = controller; Sequence = sequence; DeviceID = devid; + Enabled = true; // The EMS USB2 controller provides attachment status. The others do not. Connected = (Descriptors[type].ControllerStatus < 0); @@ -501,7 +512,7 @@ bool FRawPS2Controller::ProcessInput(RAWHID *raw, int code) // Generate events for buttons that have changed. int buttons = 0; - + // If we know we are digital, ignore the D-Pad. if (!digital) { @@ -536,7 +547,7 @@ void FRawPS2Controller::ProcessThumbstick(int value1, AxisInfo *axis1, int value { uint8_t buttonstate; double axisval1, axisval2; - + axisval1 = value1 * (2.0 / 255) - 1.0; axisval2 = value2 * (2.0 / 255) - 1.0; axisval1 = Joy_RemoveDeadZone(axisval1, axis1->DeadZone, NULL); @@ -847,6 +858,28 @@ bool FRawPS2Controller::IsAxisScaleDefault(int axis) return true; } +//=========================================================================== +// +// FRawPS2Controller :: GetEnabled +// +//=========================================================================== + +bool FRawPS2Controller::GetEnabled() +{ + return Enabled; +} + +//=========================================================================== +// +// FRawPS2Controller :: SetEnabled +// +//=========================================================================== + +void FRawPS2Controller::SetEnabled(bool enabled) +{ + Enabled = enabled; +} + //=========================================================================== // // FRawPS2Controller :: IsAxisMapDefault @@ -903,7 +936,7 @@ bool FRawPS2Manager::GetDevice() rid.usUsagePage = HID_GENERIC_DESKTOP_PAGE; rid.usUsage = HID_GDP_JOYSTICK; rid.dwFlags = RIDEV_INPUTSINK; - rid.hwndTarget = Window; + rid.hwndTarget = mainwindow.GetHandle(); if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { return false; @@ -970,7 +1003,7 @@ bool FRawPS2Manager::ProcessRawInput(RAWINPUT *raw, int code) { if (Devices[i]->Handle == raw->header.hDevice) { - if (Devices[i]->ProcessInput(&raw->data.hid, code)) + if (Devices[i]->Enabled && Devices[i]->ProcessInput(&raw->data.hid, code)) { return true; } @@ -1213,8 +1246,8 @@ int FRawPS2Manager::DeviceSort(const void *a, const void *b) if (lex == 0) { // Skip device part of the ID and sort the connection part - const char *ca = strchr(ha->DeviceID, '#'); - const char *cb = strchr(hb->DeviceID, '#'); + const char *ca = strchr(ha->DeviceID.GetChars(), '#'); + const char *cb = strchr(hb->DeviceID.GetChars(), '#'); const char *ea, *eb; // The last bit looks like a controller number. Strip it out to be safe // if this is a multi-controller adapter. @@ -1271,7 +1304,7 @@ void FRawPS2Manager::DoRegister() if (!Registered) { rid.dwFlags = RIDEV_INPUTSINK; - rid.hwndTarget = Window; + rid.hwndTarget = mainwindow.GetHandle(); if (RegisterRawInputDevices(&rid, 1, sizeof(rid))) { Registered = true; diff --git a/src/common/platform/win32/i_specialpaths.cpp b/src/common/platform/win32/i_specialpaths.cpp new file mode 100644 index 00000000000..8862024b78a --- /dev/null +++ b/src/common/platform/win32/i_specialpaths.cpp @@ -0,0 +1,454 @@ +/* +** i_specialpaths.cpp +** Gets special system folders where data should be stored. (Windows version) +** +**--------------------------------------------------------------------------- +** Copyright 2013-2016 Randy Heit +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include +#include + +#include "i_specialpaths.h" +#include "printf.h" +#include "cmdlib.h" +#include "findfile.h" +#include "version.h" // for GAMENAME +#include "gstrings.h" +#include "i_mainwindow.h" +#include "engineerrors.h" + + +static int isportable = -1; + +//=========================================================================== +// +// IsProgramDirectoryWritable +// +// If the program directory is writable, then dump everything in there for +// historical reasons. Otherwise, known folders get used instead. +// +//=========================================================================== + +bool IsPortable() +{ + // Cache this value so the semantics don't change during a single run + // of the program. (e.g. Somebody could add write access while the + // program is running.) + HANDLE file; + + if (isportable >= 0) + { + return !!isportable; + } + + // Consider 'Program Files' read only without actually checking. + bool found = false; + for (auto p : { L"ProgramFiles", L"ProgramFiles(x86)" }) + { + wchar_t buffer1[256]; + if (GetEnvironmentVariable(p, buffer1, 256)) + { + FString envpath(buffer1); + FixPathSeperator(envpath); + if (progdir.MakeLower().IndexOf(envpath.MakeLower()) == 0) + { + isportable = false; + return false; + } + } + } + + // A portable INI means that this storage location should also be portable if the file can be written to. + FStringf path("%s" GAMENAMELOWERCASE "_portable.ini", progdir.GetChars()); + if (FileExists(path)) + { + file = CreateFile(path.WideString().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + { + CloseHandle(file); + if (!batchrun) Printf("Using portable configuration\n"); + isportable = true; + return true; + } + } + + isportable = false; + return false; +} + +//=========================================================================== +// +// GetKnownFolder +// +// Returns the known_folder from SHGetKnownFolderPath +// +//=========================================================================== + +FString GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create) +{ + PWSTR wpath; + if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) + { + // This should never be triggered unless the OS was compromised + I_FatalError("Unable to retrieve known folder."); + } + FString path = FString(wpath); + FixPathSeperator(path); + CoTaskMemFree(wpath); + return path; +} + +//=========================================================================== +// +// M_GetAppDataPath Windows +// +// Returns the path for the AppData folder. +// +//=========================================================================== + +FString M_GetAppDataPath(bool create) +{ + FString path = GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create); + + path += "/" GAMENAMELOWERCASE; + if (create) + { + CreatePath(path.GetChars()); + } + return path; +} + +//=========================================================================== +// +// M_GetCachePath Windows +// +// Returns the path for cache GL nodes. +// +//=========================================================================== + +FString M_GetCachePath(bool create) +{ + FString path = GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create); + + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + path += "/zdoom/cache"; + if (create) + { + CreatePath(path.GetChars()); + } + return path; +} + +//=========================================================================== +// +// M_GetAutoexecPath Windows +// +// Returns the expected location of autoexec.cfg. +// +//=========================================================================== + +FString M_GetAutoexecPath() +{ + return "$PROGDIR/autoexec.cfg"; +} + +//=========================================================================== +// +// M_GetOldConfigPath +// +// Check if we have a config in a place that's no longer used. +// +//=========================================================================== + +FString M_GetOldConfigPath(int& type) +{ + FString path; + HRESULT hr; + + // construct "$PROGDIR/-$USER.ini" + WCHAR uname[UNLEN + 1]; + DWORD unamelen = UNLEN; + + path = progdir; + hr = GetUserNameW(uname, &unamelen); + if (SUCCEEDED(hr) && uname[0] != 0) + { + // Is it valid for a user name to have slashes? + // Check for them and substitute just in case. + auto probe = uname; + while (*probe != 0) + { + if (*probe == '\\' || *probe == '/') + *probe = '_'; + ++probe; + } + path << GAMENAMELOWERCASE "-" << FString(uname) << ".ini"; + type = 0; + if (FileExists(path)) + return path; + } + + // Check in app data where this was previously stored. + // We actually prefer to store the config in a more visible place so this is no longer used. + path = GetKnownFolder(CSIDL_APPDATA, FOLDERID_RoamingAppData, true); + path += "/" GAME_DIR "/" GAMENAMELOWERCASE ".ini"; + type = 1; + if (FileExists(path)) + return path; + + return ""; +} + +//=========================================================================== +// +// M_MigrateOldConfig +// +// Ask the user what to do with their old config. +// +//=========================================================================== + +int M_MigrateOldConfig() +{ + int selection = IDCANCEL; + auto globalstr = L"Move to Users/ folder"; + auto portablestr = L"Convert to portable installation"; + auto cancelstr = L"Cancel"; + auto titlestr = L"Migrate existing configuration"; + auto infostr = L"" GAMENAME " found a user specific config in the game folder"; + const TASKDIALOG_BUTTON buttons[] = { {IDYES, globalstr}, {IDNO, portablestr}, {IDCANCEL, cancelstr} }; + TASKDIALOGCONFIG taskDialogConfig = {}; + taskDialogConfig.cbSize = sizeof(TASKDIALOGCONFIG); + taskDialogConfig.pszMainIcon = TD_WARNING_ICON; + taskDialogConfig.pButtons = buttons; + taskDialogConfig.cButtons = countof(buttons); + taskDialogConfig.pszWindowTitle = titlestr; + taskDialogConfig.pszContent = infostr; + taskDialogConfig.hwndParent = mainwindow.GetHandle(); + taskDialogConfig.dwFlags = TDF_USE_COMMAND_LINKS; + TaskDialogIndirect(&taskDialogConfig, &selection, NULL, NULL); + if (selection == IDYES || selection == IDNO) return selection; + throw CExitEvent(3); +} + +//=========================================================================== +// +// M_GetConfigPath Windows +// +// Returns the path to the config file. On Windows, this can vary for reading +// vs writing. i.e. If the user specific ini does not exist, it will try +// to read from a neutral version, but never write to it. +// +//=========================================================================== + +FString M_GetConfigPath(bool for_reading) +{ + if (IsPortable()) + { + return FStringf("%s" GAMENAMELOWERCASE "_portable.ini", progdir.GetChars()); + } + + // Construct a user-specific config name + FString path = GetKnownFolder(CSIDL_APPDATA, FOLDERID_Documents, true); + path += "/My Games/" GAME_DIR; + CreatePath(path.GetChars()); + path += "/" GAMENAMELOWERCASE ".ini"; + if (!for_reading || FileExists(path)) + return path; + + // No config was found in the accepted locations. + // Look in previously valid places to see if we have something we can migrate + + int type = 0; + FString oldpath = M_GetOldConfigPath(type); + if (!oldpath.IsEmpty()) + { + if (type == 0) + { + // If we find a local per-user config, ask the user what to do with it. + int action = M_MigrateOldConfig(); + if (action == IDNO) + { + path.Format("%s" GAMENAMELOWERCASE "_portable.ini", progdir.GetChars()); + isportable = true; + } + } + bool res = MoveFileExW(WideString(oldpath.GetChars()).c_str(), WideString(path.GetChars()).c_str(), MOVEFILE_COPY_ALLOWED); + if (res) return path; + else return oldpath; // if we cannot move, just use the config where it was. It won't be written back, though and never be used again if a new one gets saved. + } + + // Fall back to the global template if nothing was found. + // If we are reading the config file, check if it exists. If not, fallback to base version. + if (for_reading) + { + if (!FileExists(path)) + { + path = progdir; + path << GAMENAMELOWERCASE ".ini"; + } + } + + return path; +} + +//=========================================================================== +// +// M_GetScreenshotsPath Windows +// +// Returns the path to the default screenshots directory. +// +//=========================================================================== + +FString M_GetScreenshotsPath() +{ + FString path; + + if (IsPortable()) + { + path << progdir << "Screenshots/"; + } + else if (IsWindows8OrGreater()) + { + path = GetKnownFolder(-1, FOLDERID_Screenshots, true); + + path << "/" GAMENAME "/"; + } + else + { + path = GetKnownFolder(CSIDL_MYPICTURES, FOLDERID_Pictures, true); + path << "/Screenshots/" GAMENAME "/"; + } + CreatePath(path.GetChars()); + return path; +} + +//=========================================================================== +// +// M_GetSavegamesPath Windows +// +// Returns the path to the default save games directory. +// +//=========================================================================== + +FString M_GetSavegamesPath() +{ + FString path; + + if (IsPortable()) + { + path << progdir << "Save/"; + } + // Try standard Saved Games folder + else + { + path = GetKnownFolder(-1, FOLDERID_SavedGames, true); + path << "/" GAMENAME "/"; + } + return path; +} + +//=========================================================================== +// +// M_GetDocumentsPath Windows +// +// Returns the path to the default documents directory. +// +//=========================================================================== + +FString M_GetDocumentsPath() +{ + FString path; + + if (IsPortable()) + { + return progdir; + } + // Try defacto My Documents/My Games folder + else + { + // I assume since this isn't a standard folder, it doesn't have a localized name either. + path = GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true); + path << "/My Games/" GAMENAME "/"; + CreatePath(path.GetChars()); + } + return path; +} + +//=========================================================================== +// +// M_GetDemoPath Windows +// +// Returns the path to the default demp directory. +// +//=========================================================================== + +FString M_GetDemoPath() +{ + FString path; + + // A portable INI means that this storage location should also be portable. + if (IsPortable()) + { + path << progdir << "Demos/"; + } + else + // Try defacto My Documents/My Games folder + { + // I assume since this isn't a standard folder, it doesn't have a localized name either. + path = GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true); + path << "/My Games/" GAMENAME "/"; + } + + return path; +} + +//=========================================================================== +// +// M_NormalizedPath +// +// Normalizes the given path and returns the result. +// +//=========================================================================== + +FString M_GetNormalizedPath(const char* path) +{ + std::wstring wpath = WideString(path); + wchar_t buffer[MAX_PATH]; + GetFullPathNameW(wpath.c_str(), MAX_PATH, buffer, nullptr); + FString result(buffer); + FixPathSeperator(result); + return result; +} diff --git a/src/common/platform/win32/i_system.cpp b/src/common/platform/win32/i_system.cpp new file mode 100644 index 00000000000..71a4ded122d --- /dev/null +++ b/src/common/platform/win32/i_system.cpp @@ -0,0 +1,841 @@ +/* +** i_system.cpp +** Timers, pre-console output, IWAD selection, and misc system routines. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright (C) 2007-2012 Skulltag Development Team +** Copyright (C) 2007-2016 Zandronum Development Team +** Copyright (C) 2017-2022 GZDoom Development Team +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. Redistributions in any form must be accompanied by information on how to +** obtain complete source code for the software and any accompanying software +** that uses the software. The source code must either be included in the +** distribution or be available for no more than the cost of distribution plus +** a nominal fee, and must be freely redistributable under reasonable +** conditions. For an executable file, complete source code means the source +** code for all modules it contains. It does not include source code for +** modules or files that typically accompany the major components of the +** operating system on which the executable file runs. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#pragma warning(disable:4996) +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include + +#include + +#include "hardware.h" +#include "printf.h" + +#include "version.h" +#include "i_sound.h" +#include "resource.h" +#include "stats.h" +#include "v_text.h" +#include "utf8.h" + +#include "i_input.h" +#include "c_dispatch.h" + +#include "v_font.h" +#include "i_system.h" +#include "bitmap.h" +#include "cmdlib.h" +#include "i_interface.h" +#include "i_mainwindow.h" + +#include "launcherwindow.h" + +// MACROS ------------------------------------------------------------------ + +#ifdef _MSC_VER +// Turn off "conversion from 'LONG_PTR' to 'LONG', possible loss of data" +// generated by SetClassLongPtr(). +#pragma warning(disable:4244) +#endif + +// TYPES ------------------------------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void DestroyCustomCursor(); + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static HCURSOR CreateCompatibleCursor(FBitmap &cursorpic, int leftofs, int topofs); +static HCURSOR CreateAlphaCursor(FBitmap &cursorpic, int leftofs, int topofs); +static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP color_mask); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +EXTERN_CVAR (Bool, queryiwad); +// Used on welcome/IWAD screen. +EXTERN_CVAR (Int, vid_preferbackend) +EXTERN_CVAR(Bool, longsavemessages) + +extern HANDLE StdOut; +extern bool FancyStdOut; +extern HINSTANCE g_hInst; +extern FILE *Logfile; +extern bool NativeMouse; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CVAR (String, queryiwad_key, "shift", CVAR_GLOBALCONFIG|CVAR_ARCHIVE); +CVAR (Bool, con_debugoutput, false, 0); + +double PerfToSec, PerfToMillisec; + +UINT TimerPeriod; + +const char* sys_ostype = ""; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static WadStuff *WadList; +static int NumWads; +static int DefaultWad; + +static HCURSOR CustomCursor; + +//========================================================================== +// +// I_DetectOS +// +// Determine which version of Windows the game is running on. +// +//========================================================================== + +void I_DetectOS(void) +{ + OSVERSIONINFOEX info; + const char *osname; + + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (!GetVersionEx((OSVERSIONINFO *)&info)) + { + // Retry with the older OSVERSIONINFO structure. + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((OSVERSIONINFO *)&info); + } + + switch (info.dwPlatformId) + { + case VER_PLATFORM_WIN32_NT: + osname = "NT"; + if (info.dwMajorVersion == 6) + { + if (info.dwMinorVersion == 0) + { + osname = (info.wProductType == VER_NT_WORKSTATION) ? "Vista" : "Server 2008"; + } + else if (info.dwMinorVersion == 1) + { + osname = (info.wProductType == VER_NT_WORKSTATION) ? "7" : "Server 2008 R2"; + } + else if (info.dwMinorVersion == 2) + { + // Starting with Windows 8.1, you need to specify in your manifest + // the highest version of Windows you support, which will also be the + // highest version of Windows this function returns. + osname = (info.wProductType == VER_NT_WORKSTATION) ? "8" : "Server 2012"; + } + else if (info.dwMinorVersion == 3) + { + osname = (info.wProductType == VER_NT_WORKSTATION) ? "8.1" : "Server 2012 R2"; + } + else if (info.dwMinorVersion == 4) + { + osname = (info.wProductType == VER_NT_WORKSTATION) ? "10 (beta)" : "Server 2016 (beta)"; + } + } + else if (info.dwMajorVersion == 10) + { + osname = (info.wProductType == VER_NT_WORKSTATION) ? (info.dwBuildNumber >= 22000 ? "11 (or higher)" : "10") : "Server 2016 (or higher)"; + } + break; + + default: + osname = "Unknown OS"; + break; + } + + if (!batchrun) Printf ("OS: Windows %s (NT %lu.%lu) Build %lu\n %s\n", + osname, + info.dwMajorVersion, info.dwMinorVersion, + info.dwBuildNumber, info.szCSDVersion); + + sys_ostype = osname; +} + +//========================================================================== +// +// CalculateCPUSpeed +// +// Make a decent guess at how much time elapses between TSC steps. This can +// vary over runtime depending on power management settings, so should not +// be used anywhere that truely accurate timing actually matters. +// +//========================================================================== + +void CalculateCPUSpeed() +{ + LARGE_INTEGER freq; + + QueryPerformanceFrequency (&freq); + + if (freq.QuadPart != 0) + { + LARGE_INTEGER count1, count2; + cycle_t ClockCalibration; + DWORD min_diff; + + ClockCalibration.Reset(); + + // Count cycles for at least 55 milliseconds. + // The performance counter may be very low resolution compared to CPU + // speeds today, so the longer we count, the more accurate our estimate. + // On the other hand, we don't want to count too long, because we don't + // want the user to notice us spend time here, since most users will + // probably never use the performance statistics. + min_diff = freq.LowPart * 11 / 200; + + // Minimize the chance of task switching during the testing by going very + // high priority. This is another reason to avoid timing for too long. + SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + + // Make sure we start timing on a counter boundary. + QueryPerformanceCounter(&count1); + do { QueryPerformanceCounter(&count2); } while (count1.QuadPart == count2.QuadPart); + + // Do the timing loop. + ClockCalibration.Clock(); + do { QueryPerformanceCounter(&count1); } while ((count1.QuadPart - count2.QuadPart) < min_diff); + ClockCalibration.Unclock(); + + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); + + PerfToSec = double(count1.QuadPart - count2.QuadPart) / (double(ClockCalibration.GetRawCounter()) * freq.QuadPart); + PerfToMillisec = PerfToSec * 1000.0; + } + + if (!batchrun) Printf ("CPU speed: %.0f MHz\n", 0.001 / PerfToMillisec); +} + +//========================================================================== +// +// I_PrintStr +// +// Send output to the list box shown during startup (and hidden during +// gameplay). +// +//========================================================================== + +static void PrintToStdOut(const char *cpt, HANDLE StdOut) +{ + const char* srcp = cpt; + FString printData = ""; + bool terminal = FancyStdOut; + + while (*srcp != 0) + { + if (*srcp == 0x1c && terminal) + { + srcp += 1; + const uint8_t* scratch = (const uint8_t*)srcp; // GCC does not like direct casting of the parameter. + EColorRange range = V_ParseFontColor(scratch, CR_UNTRANSLATED, CR_YELLOW); + srcp = (char*)scratch; + if (range != CR_UNDEFINED) + { + PalEntry color = V_LogColorFromColorRange(range); + printData.AppendFormat("\033[38;2;%u;%u;%um", color.r, color.g, color.b); + } + } + else if (*srcp != 0x1c && *srcp != 0x1d && *srcp != 0x1e && *srcp != 0x1f) + { + printData += *srcp++; + } + else + { + if (srcp[1] != 0) srcp += 2; + else break; + } + } + DWORD bytes_written; + WriteFile(StdOut, printData.GetChars(), (DWORD)printData.Len(), &bytes_written, NULL); + if (terminal) + WriteFile(StdOut, "\033[0m", 4, &bytes_written, NULL); +} + +void I_PrintStr(const char *cp) +{ + mainwindow.PrintStr(cp); + PrintToStdOut(cp, StdOut); +} + +//========================================================================== +// +// SetQueryIWAD +// +// The user had the "Don't ask again" box checked when they closed the +// IWAD selection dialog. +// +//========================================================================== + +static void SetQueryIWad(HWND dialog) +{ + HWND checkbox = GetDlgItem(dialog, IDC_DONTASKIWAD); + int state = (int)SendMessage(checkbox, BM_GETCHECK, 0, 0); + bool query = (state != BST_CHECKED); + + if (!query && queryiwad) + { + MessageBoxA(dialog, + "You have chosen not to show this dialog box in the future.\n" + "If you wish to see it again, hold down SHIFT while starting " GAMENAME ".", + "Don't ask me this again", + MB_OK | MB_ICONINFORMATION); + } + + queryiwad = query; +} + +//========================================================================== +// +// I_PickIWad +// +// Open a dialog to pick the IWAD, if there is more than one found. +// +//========================================================================== + +int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags, FString &extraArgs) +{ + int vkey; + if (stricmp(queryiwad_key, "shift") == 0) + { + vkey = VK_SHIFT; + } + else if (stricmp(queryiwad_key, "control") == 0 || stricmp (queryiwad_key, "ctrl") == 0) + { + vkey = VK_CONTROL; + } + else + { + vkey = 0; + } + if (showwin || (vkey != 0 && GetAsyncKeyState(vkey))) + { + return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags, &extraArgs); + } + return defaultiwad; +} + +//========================================================================== +// +// I_SetCursor +// +// Returns true if the cursor was successfully changed. +// +//========================================================================== + +bool I_SetCursor(FGameTexture *cursorpic) +{ + HCURSOR cursor; + + if (cursorpic != NULL && cursorpic->isValid()) + { + auto image = cursorpic->GetTexture()->GetBgraBitmap(nullptr); + // Must be no larger than 32x32. (is this still necessary? + if (image.GetWidth() > 32 || image.GetHeight() > 32) + { + return false; + } + // Fixme: This should get a raw image, not a texture. (Once raw images get implemented.) + int lo = cursorpic->GetTexelLeftOffset(); + int to = cursorpic->GetTexelTopOffset(); + + cursor = CreateAlphaCursor(image, lo, to); + if (cursor == NULL) + { + cursor = CreateCompatibleCursor(image, lo, to); + } + if (cursor == NULL) + { + return false; + } + // Replace the existing cursor with the new one. + DestroyCustomCursor(); + CustomCursor = cursor; + } + else + { + DestroyCustomCursor(); + cursor = LoadCursor(NULL, IDC_ARROW); + } + SetClassLongPtr(mainwindow.GetHandle(), GCLP_HCURSOR, (LONG_PTR)cursor); + if (NativeMouse) + { + POINT pt; + RECT client; + + // If the mouse pointer is within the window's client rect, set it now. + if (GetCursorPos(&pt) && GetClientRect(mainwindow.GetHandle(), &client) && + ClientToScreen(mainwindow.GetHandle(), (LPPOINT)&client.left) && + ClientToScreen(mainwindow.GetHandle(), (LPPOINT)&client.right)) + { + if (pt.x >= client.left && pt.x < client.right && + pt.y >= client.top && pt.y < client.bottom) + { + SetCursor(cursor); + } + } + } + return true; +} + +//========================================================================== +// +// CreateCompatibleCursor +// +// Creates a cursor with a 1-bit alpha channel. +// +//========================================================================== + +static HCURSOR CreateCompatibleCursor(FBitmap &bmp, int leftofs, int topofs) +{ + int picwidth = bmp.GetWidth(); + int picheight = bmp.GetHeight(); + + // Create bitmap masks for the cursor from the texture. + HDC dc = GetDC(NULL); + if (dc == NULL) + { + return nullptr; + } + HDC and_mask_dc = CreateCompatibleDC(dc); + HDC xor_mask_dc = CreateCompatibleDC(dc); + HBITMAP and_mask = CreateCompatibleBitmap(dc, 32, 32); + HBITMAP xor_mask = CreateCompatibleBitmap(dc, 32, 32); + ReleaseDC(NULL, dc); + + SelectObject(and_mask_dc, and_mask); + SelectObject(xor_mask_dc, xor_mask); + + // Initialize with an invisible cursor. + SelectObject(and_mask_dc, GetStockObject(WHITE_PEN)); + SelectObject(and_mask_dc, GetStockObject(WHITE_BRUSH)); + Rectangle(and_mask_dc, 0, 0, 32, 32); + SelectObject(xor_mask_dc, GetStockObject(BLACK_PEN)); + SelectObject(xor_mask_dc, GetStockObject(BLACK_BRUSH)); + Rectangle(xor_mask_dc, 0, 0, 32, 32); + + const uint8_t *pixels = bmp.GetPixels(); + + // Copy color data from the source texture to the cursor bitmaps. + for (int y = 0; y < picheight; ++y) + { + for (int x = 0; x < picwidth; ++x) + { + const uint8_t *bgra = &pixels[x*4 + y*bmp.GetPitch()]; + if (bgra[3] != 0) + { + SetPixelV(and_mask_dc, x, y, RGB(0,0,0)); + SetPixelV(xor_mask_dc, x, y, RGB(bgra[2], bgra[1], bgra[0])); + } + } + } + DeleteDC(and_mask_dc); + DeleteDC(xor_mask_dc); + + // Create the cursor from the bitmaps. + return CreateBitmapCursor(leftofs, topofs, and_mask, xor_mask); +} + +//========================================================================== +// +// CreateAlphaCursor +// +// Creates a cursor with a full alpha channel. +// +//========================================================================== + +static HCURSOR CreateAlphaCursor(FBitmap &source, int leftofs, int topofs) +{ + HDC dc; + BITMAPV5HEADER bi; + HBITMAP color, mono; + void *bits; + + // Find closest integer scale factor for the monitor DPI + HDC screenDC = GetDC(0); + int dpi = GetDeviceCaps(screenDC, LOGPIXELSX); + int scale = max((dpi + 96 / 2 - 1) / 96, 1); + ReleaseDC(0, screenDC); + + memset(&bi, 0, sizeof(bi)); + bi.bV5Size = sizeof(bi); + bi.bV5Width = 32 * scale; + bi.bV5Height = 32 * scale; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00FF0000; + bi.bV5GreenMask = 0x0000FF00; + bi.bV5BlueMask = 0x000000FF; + bi.bV5AlphaMask = 0xFF000000; + + dc = GetDC(NULL); + if (dc == NULL) + { + return NULL; + } + + // Create the DIB section with an alpha channel. + color = CreateDIBSection(dc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, &bits, NULL, 0); + ReleaseDC(NULL, dc); + + if (color == NULL) + { + return NULL; + } + + // Create an empty mask bitmap, since CreateIconIndirect requires this. + mono = CreateBitmap(32 * scale, 32 * scale, 1, 1, NULL); + if (mono == NULL) + { + DeleteObject(color); + return NULL; + } + + // Copy cursor to the color bitmap. Note that GDI bitmaps are upside down compared + // to normal conventions, so we create the FBitmap pointing at the last row and use + // a negative pitch so that Blit will use GDI's orientation. + if (scale == 1) + { + FBitmap bmp((uint8_t *)bits + 31 * 32 * 4, -32 * 4, 32, 32); + bmp.Blit(0, 0, source); + } + else + { + TArray unscaled; + unscaled.Resize(32 * 32); + for (int i = 0; i < 32 * 32; i++) unscaled[i] = 0; + FBitmap bmp((uint8_t *)&unscaled[0] + 31 * 32 * 4, -32 * 4, 32, 32); + bmp.Blit(0, 0, source); + uint32_t *scaled = (uint32_t*)bits; + for (int y = 0; y < 32 * scale; y++) + { + for (int x = 0; x < 32 * scale; x++) + { + scaled[x + y * 32 * scale] = unscaled[x / scale + y / scale * 32]; + } + } + } + + return CreateBitmapCursor(leftofs * scale, topofs * scale, mono, color); +} + +//========================================================================== +// +// CreateBitmapCursor +// +// Create the cursor from the bitmaps. Deletes the bitmaps before returning. +// +//========================================================================== + +static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP color_mask) +{ + ICONINFO iconinfo = + { + FALSE, // fIcon + (DWORD)xhot, // xHotspot + (DWORD)yhot, // yHotspot + and_mask, // hbmMask + color_mask // hbmColor + }; + HCURSOR cursor = CreateIconIndirect(&iconinfo); + + // Delete the bitmaps. + DeleteObject(and_mask); + DeleteObject(color_mask); + + return cursor; +} + +//========================================================================== +// +// DestroyCustomCursor +// +//========================================================================== + +void DestroyCustomCursor() +{ + if (CustomCursor != NULL) + { + DestroyCursor(CustomCursor); + CustomCursor = NULL; + } +} + +//========================================================================== +// +// I_WriteIniFailed +// +// Display a message when the config failed to save. +// +//========================================================================== + +bool I_WriteIniFailed(const char* filename) +{ + char *lpMsgBuf; + FString errortext; + + FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR)&lpMsgBuf, + 0, + NULL + ); + errortext.Format ("The config file %s could not be written:\n%s", filename, lpMsgBuf); + LocalFree (lpMsgBuf); + return MessageBoxA(mainwindow.GetHandle(), errortext.GetChars(), GAMENAME " configuration not saved", MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDRETRY; +} + + +//========================================================================== +// +// I_MakeRNGSeed +// +// Returns a 32-bit random seed, preferably one with lots of entropy. +// +//========================================================================== + +unsigned int I_MakeRNGSeed() +{ + unsigned int seed; + + // If RtlGenRandom is available, use that to avoid increasing the + // working set by pulling in all of the crytographic API. + HMODULE advapi = GetModuleHandleA("advapi32.dll"); + if (advapi != NULL) + { + BOOLEAN (APIENTRY *RtlGenRandom)(void *, ULONG) = + (BOOLEAN (APIENTRY *)(void *, ULONG))GetProcAddress(advapi, "SystemFunction036"); + if (RtlGenRandom != NULL) + { + if (RtlGenRandom(&seed, sizeof(seed))) + { + return seed; + } + } + } + + // Use the full crytographic API to produce a seed. If that fails, + // time() is used as a fallback. + HCRYPTPROV prov; + + if (!CryptAcquireContext(&prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + return (unsigned int)time(NULL); + } + if (!CryptGenRandom(prov, sizeof(seed), (uint8_t *)&seed)) + { + seed = (unsigned int)time(NULL); + } + CryptReleaseContext(prov, 0); + return seed; +} + +//========================================================================== +// +// I_GetLongPathName +// +// Returns the long version of the path, or the original if there isn't +// anything worth changing. +// +//========================================================================== + +FString I_GetLongPathName(const FString &shortpath) +{ + std::wstring wshortpath = shortpath.WideString(); + DWORD buffsize = GetLongPathNameW(wshortpath.c_str(), nullptr, 0); + if (buffsize == 0) + { // nothing to change (it doesn't exist, maybe?) + return shortpath; + } + TArray buff(buffsize, true); + DWORD buffsize2 = GetLongPathNameW(wshortpath.c_str(), buff.Data(), buffsize); + if (buffsize2 >= buffsize) + { // Failure! Just return the short path + return shortpath; + } + FString longpath(buff.Data()); + return longpath; +} + + +struct NumaNode +{ + uint64_t affinityMask = 0; + int threadCount = 0; +}; +static TArray numaNodes; + +static void SetupNumaNodes() +{ + if (numaNodes.Size() == 0) + { + // Query processors in the system + DWORD_PTR processMask = 0, systemMask = 0; + BOOL result = GetProcessAffinityMask(GetCurrentProcess(), &processMask, &systemMask); + if (result) + { + // Find the numa node each processor belongs to + std::map nodes; + for (int i = 0; i < sizeof(DWORD_PTR) * 8; i++) + { + DWORD_PTR processorMask = (((DWORD_PTR)1) << i); + if (processMask & processorMask) + { + UCHAR nodeNumber = 0; + result = GetNumaProcessorNode(i, &nodeNumber); + if (nodeNumber != 0xff) + { + nodes[nodeNumber].affinityMask |= (uint64_t)processorMask; + nodes[nodeNumber].threadCount++; + } + } + } + + // Convert map to a list + for (const auto &it : nodes) + { + numaNodes.Push(it.second); + } + } + + // Fall back to a single node if something went wrong + if (numaNodes.Size() == 0) + { + NumaNode node; + node.threadCount = std::thread::hardware_concurrency(); + if (node.threadCount == 0) + node.threadCount = 1; + numaNodes.Push(node); + } + } +} + +int I_GetNumaNodeCount() +{ + SetupNumaNodes(); + return numaNodes.Size(); +} + +int I_GetNumaNodeThreadCount(int numaNode) +{ + SetupNumaNodes(); + return numaNodes[numaNode].threadCount; +} + +void I_SetThreadNumaNode(std::thread &thread, int numaNode) +{ + if (numaNodes.Size() > 1) + { + HANDLE handle = (HANDLE)thread.native_handle(); + SetThreadAffinityMask(handle, (DWORD_PTR)numaNodes[numaNode].affinityMask); + } +} + +FString I_GetCWD() +{ + auto len = GetCurrentDirectoryW(0, nullptr); + TArray curdir(len + 1, true); + if (!GetCurrentDirectoryW(len + 1, curdir.Data())) + { + return ""; + } + FString returnv(curdir.Data()); + FixPathSeperator(returnv); + return returnv; +} + +bool I_ChDir(const char* path) +{ + return SetCurrentDirectoryW(WideString(path).c_str()); +} + + +void I_OpenShellFolder(const char* infolder) +{ + auto len = GetCurrentDirectoryW(0, nullptr); + TArray curdir(len + 1, true); + if (!GetCurrentDirectoryW(len + 1, curdir.Data())) + { + Printf("Unable to retrieve current directory\n"); + } + else if (SetCurrentDirectoryW(WideString(infolder).c_str())) + { + if (longsavemessages) + Printf("Opening folder: %s\n", infolder); + ShellExecuteW(NULL, L"open", L"explorer.exe", L".", NULL, SW_SHOWNORMAL); + SetCurrentDirectoryW(curdir.Data()); + } + else + { + if (longsavemessages) + Printf("Unable to open directory '%s\n", infolder); + else + Printf("Unable to open requested directory\n"); + } +} + diff --git a/src/common/platform/win32/i_system.h b/src/common/platform/win32/i_system.h new file mode 100644 index 00000000000..b70efb78b53 --- /dev/null +++ b/src/common/platform/win32/i_system.h @@ -0,0 +1,86 @@ + +#ifndef __I_SYSTEM__ +#define __I_SYSTEM__ + +#include "basics.h" +#include +#include "tarray.h" +#include "zstring.h" +#include "utf8.h" + +struct ticcmd_t; +struct WadStuff; + +// [RH] Detects the OS the game is running under. +void I_DetectOS (void); + +// Called by DoomMain. +void CalculateCPUSpeed (void); + +// Return a seed value for the RNG. +unsigned int I_MakeRNGSeed(); + + +void I_StartFrame (void); +void I_StartTic (void); + +// Set the mouse cursor. The texture must be 32x32. +class FGameTexture; +bool I_SetCursor(FGameTexture *cursor); + +// Repaint the pre-game console +void I_PaintConsole (void); + +// Print a console string +void I_PrintStr (const char *cp); + +// Set the title string of the startup window +void I_SetIWADInfo (); + +// Pick from multiple IWADs to use +int I_PickIWad(WadStuff* wads, int numwads, bool queryiwad, int defaultiwad, int& autoloadflags, FString &extraArgs); + +// The ini could not be saved at exit +bool I_WriteIniFailed (const char* filename); + +// [RH] Checks the registry for Steam's install path, so we can scan its +// directories for IWADs if the user purchased any through Steam. +TArray I_GetSteamPath(); + +// [GZ] Same deal for GOG paths +TArray I_GetGogPaths(); + +// Again for the Bethesda.net Launcher path +TArray I_GetBethesdaPath(); + +// Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of +// giving them proper prototypes under Win32, they are just macros for +// Get/SetWindowLong, meaning they take LONGs and not LONG_PTRs. +#ifdef _WIN64 +typedef long long WLONG_PTR; +#elif _MSC_VER +typedef _W64 long WLONG_PTR; +#else +typedef long WLONG_PTR; +#endif + +// Wrapper for GetLongPathName +FString I_GetLongPathName(const FString &shortpath); + +// Mirror WIN32_FIND_DATAA in +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif +#ifndef PATH_MAX +#define PATH_MAX 260 +#endif + +int I_GetNumaNodeCount(); +int I_GetNumaNodeThreadCount(int numaNode); +void I_SetThreadNumaNode(std::thread &thread, int numaNode); + +void I_OpenShellFolder(const char*); +FString I_GetCWD(); +bool I_ChDir(const char* path); + +#endif diff --git a/src/win32/i_xinput.cpp b/src/common/platform/win32/i_xinput.cpp similarity index 95% rename from src/win32/i_xinput.cpp rename to src/common/platform/win32/i_xinput.cpp index 63cfe294e70..0f3c1923782 100644 --- a/src/win32/i_xinput.cpp +++ b/src/common/platform/win32/i_xinput.cpp @@ -39,10 +39,12 @@ #include #include "i_input.h" -#include "d_event.h" -#include "templates.h" +#include "d_eventbase.h" + #include "gameconfigfile.h" #include "m_argv.h" +#include "cmdlib.h" +#include "keydef.h" // MACROS ------------------------------------------------------------------ @@ -63,6 +65,8 @@ #endif #endif +extern bool AppActive; + // TYPES ------------------------------------------------------------------- typedef DWORD (WINAPI *XInputGetStateType)(DWORD index, XINPUT_STATE *state); @@ -100,6 +104,13 @@ class FXInputController : public IJoystickConfig bool IsAxisMapDefault(int axis); bool IsAxisScaleDefault(int axis); + bool GetEnabled(); + void SetEnabled(bool enabled); + + bool AllowsEnabledInBackground() { return true; } + bool GetEnabledInBackground() { return EnabledInBackground; } + void SetEnabledInBackground(bool enabled) { EnabledInBackground = enabled; } + void SetDefaultConfig(); FString GetIdentifier(); @@ -136,6 +147,8 @@ class FXInputController : public IJoystickConfig DWORD LastPacketNumber; int LastButtons; bool Connected; + bool Enabled; + bool EnabledInBackground; void Attached(); void Detached(); @@ -219,6 +232,7 @@ FXInputController::FXInputController(int index) { Index = index; Connected = false; + Enabled = true; M_LoadJoystickConfig(this); } @@ -267,7 +281,7 @@ void FXInputController::ProcessInput() { Attached(); } - if (state.dwPacketNumber == LastPacketNumber) + if (state.dwPacketNumber == LastPacketNumber || !Enabled) { // Nothing has changed since last time. return; } @@ -308,7 +322,7 @@ void FXInputController::ProcessThumbstick(int value1, AxisInfo *axis1, { uint8_t buttonstate; double axisval1, axisval2; - + axisval1 = (value1 - SHRT_MIN) * 2.0 / 65536 - 1.0; axisval2 = (value2 - SHRT_MIN) * 2.0 / 65536 - 1.0; axisval1 = Joy_RemoveDeadZone(axisval1, axis1->DeadZone, NULL); @@ -335,7 +349,7 @@ void FXInputController::ProcessTrigger(int value, AxisInfo *axis, int base) { uint8_t buttonstate; double axisval; - + axisval = Joy_RemoveDeadZone(value / 256.0, axis->DeadZone, &buttonstate); Joy_GenerateButtonEvents(axis->ButtonValue, buttonstate, 1, base); axis->ButtonValue = buttonstate; @@ -434,9 +448,7 @@ void FXInputController::SetDefaultConfig() FString FXInputController::GetIdentifier() { - char id[16]; - mysnprintf(id, countof(id), "XI:%d", Index); - return id; + return FStringf("XI:%d", Index); } //========================================================================== @@ -628,6 +640,28 @@ bool FXInputController::IsAxisScaleDefault(int axis) return true; } +//=========================================================================== +// +// FXInputController :: GetEnabled +// +//=========================================================================== + +bool FXInputController::GetEnabled() +{ + return Enabled; +} + +//=========================================================================== +// +// FXInputController :: SetEnabled +// +//=========================================================================== + +void FXInputController::SetEnabled(bool enabled) +{ + Enabled = enabled; +} + //=========================================================================== // // FXInputController :: IsAxisMapDefault @@ -717,7 +751,10 @@ void FXInputManager::ProcessInput() { for (int i = 0; i < XUSER_MAX_COUNT; ++i) { - Devices[i]->ProcessInput(); + if(AppActive || Devices[i]->GetEnabledInBackground()) + { + Devices[i]->ProcessInput(); + } } } diff --git a/src/win32/zdoom.exe.manifest b/src/common/platform/win32/manifest.xml similarity index 100% rename from src/win32/zdoom.exe.manifest rename to src/common/platform/win32/manifest.xml diff --git a/src/win32/resource.h b/src/common/platform/win32/resource.h similarity index 98% rename from src/win32/resource.h rename to src/common/platform/win32/resource.h index f6eff618812..d00ee9bd9d1 100644 --- a/src/win32/resource.h +++ b/src/common/platform/win32/resource.h @@ -97,6 +97,7 @@ #define IDC_RADIO3 1086 #define IDC_WELCOME_VULKAN3 1086 #define IDCE_ROOM 1087 +#define IDC_WELCOME_VULKAN4 1187 #define IDCS_ROOM 1088 #define IDCE_ROOMHF 1089 #define IDCS_ROOMHF 1090 @@ -153,6 +154,7 @@ #define IDC_WELCOME_NOAUTOLOAD 4023 #define IDC_WELCOME_LIGHTS 4024 #define IDC_WELCOME_BRIGHTMAPS 4025 +#define IDC_WELCOME_WIDESCREEN 1087 #define IDC_WELCOME_VULKAN 4026 #define IDC_WELCOME_VULKAN1 4026 diff --git a/src/common/platform/win32/st_start.cpp b/src/common/platform/win32/st_start.cpp new file mode 100644 index 00000000000..8bc48d26e5a --- /dev/null +++ b/src/common/platform/win32/st_start.cpp @@ -0,0 +1,203 @@ +/* +** st_start.cpp +** Handles the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include "resource.h" + +#include "st_start.h" +#include "cmdlib.h" + +#include "i_system.h" +#include "i_input.h" +#include "hardware.h" +#include "filesystem.h" +#include "m_argv.h" +#include "engineerrors.h" +#include "s_music.h" +#include "printf.h" +#include "startupinfo.h" +#include "i_interface.h" +#include "texturemanager.h" +#include "i_mainwindow.h" + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +void ST_Util_SizeWindowForBitmap (int scale); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern HINSTANCE g_hInst; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// FStartupScreen :: CreateInstance +// +// Initializes the startup screen for the detected game. +// Sets the size of the progress bar and displays the startup screen. +// +//========================================================================== + +FStartupScreen *FStartupScreen::CreateInstance(int max_progress) +{ + return new FBasicStartupScreen(max_progress); +} + +//========================================================================== +// +// FBasicStartupScreen Constructor +// +// Shows a progress bar at the bottom of the window. +// +//========================================================================== + +FBasicStartupScreen::FBasicStartupScreen(int max_progress) +: FStartupScreen(max_progress) +{ + NetMaxPos = 0; + NetCurPos = 0; +} + +//========================================================================== +// +// FBasicStartupScreen Destructor +// +// Called just before entering graphics mode to deconstruct the startup +// screen. +// +//========================================================================== + +FBasicStartupScreen::~FBasicStartupScreen() +{ +} + +//========================================================================== +// +// FBasicStartupScreen :: Progress +// +// Bumps the progress meter one notch. +// +//========================================================================== + +void FBasicStartupScreen::Progress() +{ + if (CurPos < MaxPos) + { + CurPos++; + } +} + +//========================================================================== +// +// FBasicStartupScreen :: NetInit +// +// Shows the network startup pane if it isn't visible. Sets the message in +// the pane to the one provided. If numplayers is 0, then the progress bar +// is a scrolling marquee style. If numplayers is 1, then the progress bar +// is just a full bar. If numplayers is >= 2, then the progress bar is a +// normal one, and a progress count is also shown in the pane. +// +//========================================================================== + +void FBasicStartupScreen::NetInit(const char *message, int numplayers) +{ + NetMaxPos = numplayers; + mainwindow.ShowNetStartPane(message, numplayers); + + NetMaxPos = numplayers; + NetCurPos = 0; + NetProgress(1); // You always know about yourself +} + +//========================================================================== +// +// FBasicStartupScreen :: NetDone +// +// Removes the network startup pane. +// +//========================================================================== + +void FBasicStartupScreen::NetDone() +{ + mainwindow.HideNetStartPane(); +} + +//========================================================================== +// +// FBasicStartupScreen :: NetProgress +// +// Sets the network progress meter. If count is 0, it gets bumped by 1. +// Otherwise, it is set to count. +// +//========================================================================== + +void FBasicStartupScreen::NetProgress(int count) +{ + if (count == 0) + { + NetCurPos++; + } + else + { + NetCurPos = count; + } + + mainwindow.SetNetStartProgress(count); +} + +//========================================================================== +// +// FBasicStartupScreen :: NetLoop +// +// The timer_callback function is called at least two times per second +// and passed the userdata value. It should return true to stop the loop and +// return control to the caller or false to continue the loop. +// +// ST_NetLoop will return true if the loop was halted by the callback and +// false if the loop was halted because the user wants to abort the +// network synchronization. +// +//========================================================================== + +bool FBasicStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) +{ + return mainwindow.RunMessageLoop(timer_callback, userdata); +} diff --git a/src/win32/wglext.h b/src/common/platform/win32/wglext.h similarity index 100% rename from src/win32/wglext.h rename to src/common/platform/win32/wglext.h diff --git a/src/win32/win32basevideo.cpp b/src/common/platform/win32/win32basevideo.cpp similarity index 87% rename from src/win32/win32basevideo.cpp rename to src/common/platform/win32/win32basevideo.cpp index cc37848f165..b67af93d77a 100644 --- a/src/win32/win32basevideo.cpp +++ b/src/common/platform/win32/win32basevideo.cpp @@ -33,27 +33,23 @@ */ #include -#include -#include "wglext.h" -#include "gl_sysfb.h" #include "hardware.h" -#include "x86.h" -#include "templates.h" + #include "version.h" #include "c_console.h" #include "v_video.h" #include "i_input.h" #include "i_system.h" -#include "doomstat.h" #include "v_text.h" #include "m_argv.h" -#include "doomerrors.h" +#include "engineerrors.h" +#include "printf.h" #include "win32basevideo.h" +#include "cmdlib.h" +#include "i_mainwindow.h" -#include "gl/system/gl_framebuffer.h" - -CVAR(Int, vid_adapter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, vid_adapter, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) //========================================================================== // @@ -63,7 +59,7 @@ CVAR(Int, vid_adapter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) Win32BaseVideo::Win32BaseVideo() { - I_SetWndProc(); + mainwindow.ShowGameView(); GetDisplayDeviceName(); } @@ -74,6 +70,12 @@ Win32BaseVideo::Win32BaseVideo() // //========================================================================== +HMONITOR GetPrimaryMonitorHandle() +{ + const POINT ptZero = { 0, 0 }; + return MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); +} + struct MonitorEnumState { int curIdx; @@ -121,24 +123,29 @@ void Win32BaseVideo::GetDisplayDeviceName() mes.curIdx = 1; mes.hFoundMonitor = nullptr; + if (vid_adapter == 0) + { + mes.hFoundMonitor = GetPrimaryMonitorHandle(); + } + // Could also use EnumDisplayDevices, I guess. That might work. - if (EnumDisplayMonitors(0, 0, &GetDisplayDeviceNameMonitorEnumProc, LPARAM(&mes))) + else EnumDisplayMonitors(0, 0, &GetDisplayDeviceNameMonitorEnumProc, LPARAM(&mes)); + + if (mes.hFoundMonitor) { - if (mes.hFoundMonitor) - { - MONITORINFOEXA mi; + MONITORINFOEXA mi; - mi.cbSize = sizeof mi; + mi.cbSize = sizeof mi; - if (GetMonitorInfoA(mes.hFoundMonitor, &mi)) - { - strcpy(m_DisplayDeviceBuffer, mi.szDevice); - m_DisplayDeviceName = m_DisplayDeviceBuffer; + if (GetMonitorInfoA(mes.hFoundMonitor, &mi)) + { + strcpy(m_DisplayDeviceBuffer, mi.szDevice); + m_DisplayDeviceName = m_DisplayDeviceBuffer; - m_hMonitor = mes.hFoundMonitor; - } + m_hMonitor = mes.hFoundMonitor; } } + } //========================================================================== diff --git a/src/win32/win32basevideo.h b/src/common/platform/win32/win32basevideo.h similarity index 100% rename from src/win32/win32basevideo.h rename to src/common/platform/win32/win32basevideo.h diff --git a/src/win32/win32glvideo.cpp b/src/common/platform/win32/win32glvideo.cpp similarity index 83% rename from src/win32/win32glvideo.cpp rename to src/common/platform/win32/win32glvideo.cpp index e283c700c1d..bceb1908e7a 100644 --- a/src/win32/win32glvideo.cpp +++ b/src/common/platform/win32/win32glvideo.cpp @@ -34,24 +34,35 @@ #include #include +#include #include "wglext.h" +#include #include "gl_sysfb.h" #include "hardware.h" -#include "x86.h" -#include "templates.h" + #include "version.h" #include "c_console.h" #include "v_video.h" #include "i_input.h" #include "i_system.h" -#include "doomstat.h" #include "v_text.h" #include "m_argv.h" -#include "doomerrors.h" +#include "printf.h" +#include "engineerrors.h" #include "win32glvideo.h" -#include "gl/system/gl_framebuffer.h" +#include "gl_framebuffer.h" +#ifdef HAVE_GLES2 +#include "gles_framebuffer.h" +#endif + +extern "C" { +HGLRC zd_wglCreateContext(HDC Arg1); +BOOL zd_wglDeleteContext(HGLRC Arg1); +BOOL zd_wglMakeCurrent(HDC Arg1, HGLRC Arg2); +PROC zd_wglGetProcAddress(LPCSTR name); +} EXTERN_CVAR(Int, vid_adapter) EXTERN_CVAR(Bool, vid_hdr) @@ -72,7 +83,7 @@ CUSTOM_CVAR(Bool, vr_enable_quadbuffered, false, CVAR_ARCHIVE | CVAR_GLOBALCONFI extern bool vid_hdr_active; // these get used before GLEW is initialized so we have to use separate pointers with different names -PFNWGLCHOOSEPIXELFORMATARBPROC myWglChoosePixelFormatARB; // = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); +PFNWGLCHOOSEPIXELFORMATARBPROC myWglChoosePixelFormatARB; // = (PFNWGLCHOOSEPIXELFORMATARBPROC)zd_wglGetProcAddress("wglChoosePixelFormatARB"); PFNWGLCREATECONTEXTATTRIBSARBPROC myWglCreateContextAttribsARB; @@ -97,7 +108,13 @@ DFrameBuffer *Win32GLVideo::CreateFrameBuffer() { SystemGLFrameBuffer *fb; - fb = new OpenGLRenderer::OpenGLFrameBuffer(m_hMonitor, fullscreen); +#ifdef HAVE_GLES2 + if (V_GetBackend() != 0) + fb = new OpenGLESRenderer::OpenGLFrameBuffer(m_hMonitor, vid_fullscreen); + else +#endif + fb = new OpenGLRenderer::OpenGLFrameBuffer(m_hMonitor, vid_fullscreen); + return fb; } @@ -222,15 +239,15 @@ bool Win32GLVideo::SetPixelFormat() ::SetPixelFormat(hDC, pixelFormat, &pfd); - hRC = wglCreateContext(hDC); - wglMakeCurrent(hDC, hRC); + hRC = zd_wglCreateContext(hDC); + zd_wglMakeCurrent(hDC, hRC); - myWglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); - myWglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + myWglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)zd_wglGetProcAddress("wglChoosePixelFormatARB"); + myWglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)zd_wglGetProcAddress("wglCreateContextAttribsARB"); // any extra stuff here? - wglMakeCurrent(NULL, NULL); - wglDeleteContext(hRC); + zd_wglMakeCurrent(NULL, NULL); + zd_wglDeleteContext(hRC); ReleaseDC(dummy, hDC); ShutdownDummy(dummy); @@ -309,8 +326,7 @@ bool Win32GLVideo::SetupPixelFormat(int multisample) if (!myWglChoosePixelFormatARB(m_hDC, attributes.data(), attribsFloat, 1, &pixelFormat, &numFormats)) { - Printf("R_OPENGL: Couldn't choose pixel format. Retrying in compatibility mode\n"); - goto oldmethod; + I_FatalError("R_OPENGL: Couldn't choose pixel format. Retrying in compatibility mode\n"); } if (vid_hdr && numFormats == 0) // This card/driver doesn't support the rgb16f pixel format. Fall back to 8bpc @@ -326,8 +342,7 @@ bool Win32GLVideo::SetupPixelFormat(int multisample) if (!myWglChoosePixelFormatARB(m_hDC, attributes.data(), attribsFloat, 1, &pixelFormat, &numFormats)) { - Printf("R_OPENGL: Couldn't choose pixel format. Retrying in compatibility mode\n"); - goto oldmethod; + I_FatalError("R_OPENGL: Couldn't choose pixel format."); } } else if (vid_hdr) @@ -343,41 +358,12 @@ bool Win32GLVideo::SetupPixelFormat(int multisample) vr_enable_quadbuffered = false; goto again; } - Printf("R_OPENGL: No valid pixel formats found. Retrying in compatibility mode\n"); - goto oldmethod; + I_FatalError("R_OPENGL: No valid pixel formats found."); } } else { - oldmethod: - // If wglChoosePixelFormatARB is not found we have to do it the old fashioned way. - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, - 32, // color depth - 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 32, // z depth - 8, // stencil buffer - 0, - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; - - pixelFormat = ChoosePixelFormat(m_hDC, &pfd); - DescribePixelFormat(m_hDC, pixelFormat, sizeof(pfd), &pfd); - - if (pfd.dwFlags & PFD_GENERIC_FORMAT) - { - I_Error("R_OPENGL: OpenGL driver not accelerated!"); - return false; - } + I_FatalError("R_OPENGL: Unable to create an OpenGL render context. Insufficient driver support for context creation\n"); } if (!::SetPixelFormat(m_hDC, pixelFormat, NULL)) @@ -405,9 +391,6 @@ bool Win32GLVideo::InitHardware(HWND Window, int multisample) } int prof = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; - const char *version = Args->CheckValue("-glversion"); - - if (version != nullptr && strtod(version, nullptr) < 3.0) prof = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; for (; prof <= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; prof++) { @@ -415,8 +398,8 @@ bool Win32GLVideo::InitHardware(HWND Window, int multisample) if (myWglCreateContextAttribsARB != NULL) { // let's try to get the best version possible. Some drivers only give us the version we request - // which breaks all version checks for feature support. The highest used features we use are from version 4.4, and 3.0 is a requirement. - static int versions[] = { 46, 45, 44, 43, 42, 41, 40, 33, 32, 31, 30, -1 }; + // which breaks all version checks for feature support. The highest used features we use are from version 4.4, and 3.3 is a requirement. + static int versions[] = { 46, 45, 44, 43, 42, 41, 40, 33, -1 }; for (int i = 0; versions[i] > 0; i++) { @@ -435,22 +418,21 @@ bool Win32GLVideo::InitHardware(HWND Window, int multisample) if (m_hRC == NULL && prof == WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) { - m_hRC = wglCreateContext(m_hDC); + m_hRC = zd_wglCreateContext(m_hDC); if (m_hRC == NULL) { - I_Error("R_OPENGL: Unable to create an OpenGL render context.\n"); - return false; + I_FatalError("R_OPENGL: Unable to create an OpenGL render context.\n"); } } if (m_hRC != NULL) { - wglMakeCurrent(m_hDC, m_hRC); + zd_wglMakeCurrent(m_hDC, m_hRC); return true; } } // We get here if the driver doesn't support the modern context creation API which always means an old driver. - I_Error("R_OPENGL: Unable to create an OpenGL render context. Insufficient driver support for context creation\n"); + I_FatalError("R_OPENGL: Unable to create an OpenGL render context. Insufficient driver support for context creation\n"); return false; } @@ -464,8 +446,8 @@ void Win32GLVideo::Shutdown() { if (m_hRC) { - wglMakeCurrent(0, 0); - wglDeleteContext(m_hRC); + zd_wglMakeCurrent(0, 0); + zd_wglDeleteContext(m_hRC); } if (m_hDC) ReleaseDC(m_Window, m_hDC); } diff --git a/src/win32/win32glvideo.h b/src/common/platform/win32/win32glvideo.h similarity index 100% rename from src/win32/win32glvideo.h rename to src/common/platform/win32/win32glvideo.h diff --git a/src/win32/win32vulkanvideo.cpp b/src/common/platform/win32/win32vulkanvideo.cpp similarity index 87% rename from src/win32/win32vulkanvideo.cpp rename to src/common/platform/win32/win32vulkanvideo.cpp index d2c2e7b40d4..25cf661caca 100644 --- a/src/win32/win32vulkanvideo.cpp +++ b/src/common/platform/win32/win32vulkanvideo.cpp @@ -6,18 +6,16 @@ #define VK_USE_PLATFORM_WIN32_KHR #endif -#include "volk/volk.h" - - -extern HWND Window; +#include +#include "i_mainwindow.h" void I_GetVulkanDrawableSize(int *width, int *height) { - assert(Window); + assert(mainwindow.GetHandle()); RECT clientRect = { 0 }; - GetClientRect(Window, &clientRect); - + GetClientRect(mainwindow.GetHandle(), &clientRect); + if (width != nullptr) { *width = clientRect.right; @@ -67,7 +65,7 @@ bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface) windowCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; windowCreateInfo.pNext = nullptr; windowCreateInfo.flags = 0; - windowCreateInfo.hwnd = Window; + windowCreateInfo.hwnd = mainwindow.GetHandle(); windowCreateInfo.hinstance = GetModuleHandle(nullptr); const VkResult result = vkCreateWin32SurfaceKHR(instance, &windowCreateInfo, nullptr, surface); diff --git a/src/common/platform/win32/win32vulkanvideo.h b/src/common/platform/win32/win32vulkanvideo.h new file mode 100644 index 00000000000..1cd070f2a02 --- /dev/null +++ b/src/common/platform/win32/win32vulkanvideo.h @@ -0,0 +1,63 @@ +#pragma once + +#include "win32basevideo.h" +#include "c_cvars.h" +#include "vulkan/system/vk_renderdevice.h" +#include +#include + +void I_GetVulkanDrawableSize(int* width, int* height); +bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR* surface); +bool I_GetVulkanPlatformExtensions(unsigned int* count, const char** names); + +EXTERN_CVAR(Bool, vid_fullscreen) +EXTERN_CVAR(Bool, vk_debug) +EXTERN_CVAR(Int, vk_device) + +//========================================================================== +// +// +// +//========================================================================== + +class Win32VulkanVideo : public Win32BaseVideo +{ + std::shared_ptr surface; +public: + Win32VulkanVideo() + { + unsigned int count = 64; + const char* names[64]; + if (!I_GetVulkanPlatformExtensions(&count, names)) + VulkanError("I_GetVulkanPlatformExtensions failed"); + + VulkanInstanceBuilder builder; + builder.DebugLayer(vk_debug); + for (unsigned int i = 0; i < count; i++) + builder.RequireExtension(names[i]); + auto instance = builder.Create(); + + VkSurfaceKHR surfacehandle = nullptr; + if (!I_CreateVulkanSurface(instance->Instance, &surfacehandle)) + VulkanError("I_CreateVulkanSurface failed"); + + surface = std::make_shared(instance, surfacehandle); + } + + ~Win32VulkanVideo() + { + } + + void Shutdown() override + { + surface.reset(); + } + + DFrameBuffer *CreateFrameBuffer() override + { + auto fb = new VulkanRenderDevice(m_hMonitor, vid_fullscreen, surface); + return fb; + } + +protected: +}; diff --git a/src/win32/winres.h b/src/common/platform/win32/winres.h similarity index 98% rename from src/win32/winres.h rename to src/common/platform/win32/winres.h index 6d78230d84f..a2b8711a6a6 100644 --- a/src/win32/winres.h +++ b/src/common/platform/win32/winres.h @@ -10,6 +10,7 @@ // winres.h - Windows resource definitions // extracted from WINUSER.H and COMMCTRL.H +#pragma once #ifdef _AFX_MINREBUILD #pragma component(minrebuild, off) diff --git a/src/common/platform/win32/zutil.natvis b/src/common/platform/win32/zutil.natvis new file mode 100644 index 00000000000..9a257a7cf23 --- /dev/null +++ b/src/common/platform/win32/zutil.natvis @@ -0,0 +1,95 @@ + + + + + + Size = {Count} + + Count + Most + + Count + (value_type*)Array + + + + + + Size = {Count} + + Count + + Count + (value_type*)Array + + + + + + Size = {Count} + + Count + + Count + (value_type*)Array + + + + + + Size = {Count} + + Count + + Count + (value_type*)Array + + + + + + {FName::NameData.NameArray[Index].Text, s} + + + + {Chars, s} + + ((FStringData*)Chars - 1)->Len + ((FStringData*)Chars - 1)->AllocLen + ((FStringData*)Chars - 1)->RefCount + + + + + {Degrees} + + + + {TypeName} + + + + {Class->TypeName} + + + + <NULL> + {o->Class->TypeName} + + + + <None> + {TexMan.Textures[texnum].Texture->Name} + + texnum + TexMan.Textures[texnum].Texture + + + + + <No Sound Engine> + <None> + {soundEngine->S_sfx[ID].name} + + + diff --git a/src/common/rendering/gl/gl_buffers.cpp b/src/common/rendering/gl/gl_buffers.cpp new file mode 100644 index 00000000000..a576b64315e --- /dev/null +++ b/src/common/rendering/gl/gl_buffers.cpp @@ -0,0 +1,277 @@ +/* +** gl_buffers.cpp +** Low level vertex buffer class +** +**--------------------------------------------------------------------------- +** Copyright 2018-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +**/ + +#include +#include "gl_load.h" +#include "gl_buffers.h" +#include "gl_renderstate.h" +#include "v_video.h" +#include "flatvertices.h" + +namespace OpenGLRenderer +{ + +//========================================================================== +// +// basic buffer implementation +// +//========================================================================== + +static inline void InvalidateBufferState() +{ + gl_RenderState.ResetVertexBuffer(); // force rebinding of buffers on next Apply call. +} + +GLBuffer::GLBuffer(int usetype) + : mUseType(usetype) +{ + glGenBuffers(1, &mBufferId); +} + +GLBuffer::~GLBuffer() +{ + if (mBufferId != 0) + { + glBindBuffer(mUseType, mBufferId); + glUnmapBuffer(mUseType); + glBindBuffer(mUseType, 0); + glDeleteBuffers(1, &mBufferId); + } +} + +void GLBuffer::Bind() +{ + glBindBuffer(mUseType, mBufferId); +} + + +void GLBuffer::SetData(size_t size, const void *data, BufferUsageType usage) +{ + Bind(); + if (usage == BufferUsageType::Static) + { + glBufferData(mUseType, size, data, GL_STATIC_DRAW); + } + else if (usage == BufferUsageType::Stream) + { + glBufferData(mUseType, size, data, GL_STREAM_DRAW); + } + else if (usage == BufferUsageType::Persistent) + { + mPersistent = screen->BuffersArePersistent(); + if (mPersistent) + { + glBufferStorage(mUseType, size, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + map = glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + } + else + { + glBufferData(mUseType, size, nullptr, GL_STREAM_DRAW); + map = nullptr; + } + nomap = false; + } + else if (usage == BufferUsageType::Mappable) + { + glBufferData(mUseType, size, nullptr, GL_STATIC_DRAW); + map = nullptr; + } + buffersize = size; + InvalidateBufferState(); +} + +void GLBuffer::SetSubData(size_t offset, size_t size, const void *data) +{ + Bind(); + glBufferSubData(mUseType, offset, size, data); +} + +void GLBuffer::Map() +{ + assert(nomap == false); // do not allow mapping of static buffers. Vulkan cannot do that so it should be blocked in OpenGL, too. + if (!mPersistent && !nomap) + { + Bind(); + map = (FFlatVertex*)glMapBufferRange(mUseType, 0, buffersize, GL_MAP_WRITE_BIT|GL_MAP_UNSYNCHRONIZED_BIT); + InvalidateBufferState(); + } +} + +void GLBuffer::Unmap() +{ + assert(nomap == false); + if (!mPersistent && map != nullptr) + { + Bind(); + glUnmapBuffer(mUseType); + InvalidateBufferState(); + map = nullptr; + } +} + +void *GLBuffer::Lock(unsigned int size) +{ + // This initializes this buffer as a static object with no data. + SetData(size, nullptr, BufferUsageType::Mappable); + return glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT); +} + +void GLBuffer::Unlock() +{ + Bind(); + glUnmapBuffer(mUseType); + InvalidateBufferState(); +} + +void GLBuffer::Resize(size_t newsize) +{ + assert(!nomap); // only mappable buffers can be resized. + if (newsize > buffersize && !nomap) + { + // reallocate the buffer with twice the size + unsigned int oldbuffer = mBufferId; + + // first unmap the old buffer + Bind(); + glUnmapBuffer(mUseType); + + glGenBuffers(1, &mBufferId); + SetData(newsize, nullptr, BufferUsageType::Persistent); + glBindBuffer(GL_COPY_READ_BUFFER, oldbuffer); + + // copy contents and delete the old buffer. + glCopyBufferSubData(GL_COPY_READ_BUFFER, mUseType, 0, 0, buffersize); + glBindBuffer(GL_COPY_READ_BUFFER, 0); + glDeleteBuffers(1, &oldbuffer); + buffersize = newsize; + InvalidateBufferState(); + } +} + +void GLBuffer::GPUDropSync() +{ + if (mGLSync != NULL) + { + glDeleteSync(mGLSync); + } + + mGLSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void GLBuffer::GPUWaitSync() +{ + GLenum status = glClientWaitSync(mGLSync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000 * 1000 * 50); // Wait for a max of 50ms... + + if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED) + { + //Printf("Error on glClientWaitSync: %d\n", status); + } + + glDeleteSync(mGLSync); + + mGLSync = NULL; +} + +//=========================================================================== +// +// Vertex buffer implementation +// +//=========================================================================== + +void GLVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) +{ + static int VFmtToGLFmt[] = { GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT_2_10_10_10_REV, GL_UNSIGNED_BYTE }; + static uint8_t VFmtToSize[] = { 4, 3, 2, 1, 4, 4, 4 }; + static bool VFmtToNormalize[] = { false, false, false, false, true, true, false }; + static bool VFmtToIntegerType[] = { false, false, false, false, false, false, true }; + + mStride = stride; + mNumBindingPoints = numBindingPoints; + + for(int i = 0; i < numAttributes; i++) + { + if (attrs[i].location >= 0 && attrs[i].location < VATTR_MAX) + { + auto & attrinf = mAttributeInfo[attrs[i].location]; + attrinf.format = VFmtToGLFmt[attrs[i].format]; + attrinf.size = VFmtToSize[attrs[i].format]; + attrinf.offset = attrs[i].offset; + attrinf.bindingpoint = attrs[i].binding; + attrinf.normalize = VFmtToNormalize[attrs[i].format]; + attrinf.integerType = VFmtToIntegerType[attrs[i].format]; + } + } +} + +void GLVertexBuffer::Bind(int *offsets) +{ + int i = 0; + + // This is what gets called from RenderState.Apply. It shouldn't be called anywhere else if the render state is in use + GLBuffer::Bind(); + for(auto &attrinf : mAttributeInfo) + { + if (attrinf.size == 0) + { + glDisableVertexAttribArray(i); + } + else + { + glEnableVertexAttribArray(i); + size_t ofs = offsets == nullptr ? attrinf.offset : attrinf.offset + mStride * offsets[attrinf.bindingpoint]; + if (!attrinf.integerType) + glVertexAttribPointer(i, attrinf.size, attrinf.format, attrinf.normalize, (GLsizei)mStride, (void*)(intptr_t)ofs); + else + glVertexAttribIPointer(i, attrinf.size, attrinf.format, (GLsizei)mStride, (void*)(intptr_t)ofs); + } + i++; + } +} + +void GLDataBuffer::BindRange(FRenderState *state, size_t start, size_t length) +{ + glBindBufferRange(mUseType, mBindingPoint, mBufferId, start, length); +} + +void GLDataBuffer::BindBase() +{ + glBindBufferBase(mUseType, mBindingPoint, mBufferId); +} + + +GLVertexBuffer::GLVertexBuffer() : GLBuffer(GL_ARRAY_BUFFER) {} +GLIndexBuffer::GLIndexBuffer() : GLBuffer(GL_ELEMENT_ARRAY_BUFFER) {} +GLDataBuffer::GLDataBuffer(int bindingpoint, bool is_ssbo) : GLBuffer(is_ssbo ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER), mBindingPoint(bindingpoint) {} + +} \ No newline at end of file diff --git a/src/rendering/gl/system/gl_buffers.h b/src/common/rendering/gl/gl_buffers.h similarity index 82% rename from src/rendering/gl/system/gl_buffers.h rename to src/common/rendering/gl/gl_buffers.h index a9e44061d88..9bca819a12d 100644 --- a/src/rendering/gl/system/gl_buffers.h +++ b/src/common/rendering/gl/gl_buffers.h @@ -1,6 +1,7 @@ #pragma once -#include "hwrenderer/data/buffers.h" +#include "buffers.h" +#include "gl_load.h" #ifdef _MSC_VER // silence bogus warning C4250: 'GLVertexBuffer': inherits 'GLBuffer::GLBuffer::SetData' via dominance @@ -19,16 +20,20 @@ class GLBuffer : virtual public IBuffer int mAllocationSize = 0; bool mPersistent = false; bool nomap = true; + GLsync mGLSync = 0; GLBuffer(int usetype); ~GLBuffer(); - void SetData(size_t size, const void *data, bool staticdata) override; + void SetData(size_t size, const void *data, BufferUsageType usage) override; void SetSubData(size_t offset, size_t size, const void *data) override; void Map() override; void Unmap() override; void Resize(size_t newsize) override; void *Lock(unsigned int size) override; void Unlock() override; + + void GPUDropSync(); + void GPUWaitSync(); public: void Bind(); }; @@ -41,6 +46,8 @@ class GLVertexBuffer : public IVertexBuffer, public GLBuffer { int bindingpoint; int format; + bool normalize; + bool integerType; int size; int offset; }; @@ -50,7 +57,7 @@ class GLVertexBuffer : public IVertexBuffer, public GLBuffer size_t mStride = 0; public: - GLVertexBuffer() : GLBuffer(GL_ARRAY_BUFFER) {} + GLVertexBuffer(); void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override; void Bind(int *offsets); }; @@ -58,14 +65,14 @@ class GLVertexBuffer : public IVertexBuffer, public GLBuffer class GLIndexBuffer : public IIndexBuffer, public GLBuffer { public: - GLIndexBuffer() : GLBuffer(GL_ELEMENT_ARRAY_BUFFER) {} + GLIndexBuffer(); }; class GLDataBuffer : public IDataBuffer, public GLBuffer { int mBindingPoint; public: - GLDataBuffer(int bindingpoint, bool is_ssbo) : GLBuffer(is_ssbo? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER), mBindingPoint(bindingpoint) {} + GLDataBuffer(int bindingpoint, bool is_ssbo); void BindRange(FRenderState* state, size_t start, size_t length); void BindBase(); }; diff --git a/src/rendering/gl/system/gl_debug.cpp b/src/common/rendering/gl/gl_debug.cpp similarity index 90% rename from src/rendering/gl/system/gl_debug.cpp rename to src/common/rendering/gl/gl_debug.cpp index 2cf781a28b9..38625e73df0 100644 --- a/src/rendering/gl/system/gl_debug.cpp +++ b/src/common/rendering/gl/gl_debug.cpp @@ -1,34 +1,29 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2016 Magnus Norddahl -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// /* -** gl_debig.cpp -** OpenGL debugging support functions +** OpenGL debugging support functions +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. ** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. */ -#include "templates.h" -#include "gl_load/gl_system.h" -#include "gl/system/gl_debug.h" + +#include "gl_system.h" +#include "gl_debug.h" #include "stats.h" +#include "printf.h" #include #include #include diff --git a/src/rendering/gl/system/gl_debug.h b/src/common/rendering/gl/gl_debug.h similarity index 95% rename from src/rendering/gl/system/gl_debug.h rename to src/common/rendering/gl/gl_debug.h index a234a0879aa..e9d64a110a6 100644 --- a/src/rendering/gl/system/gl_debug.h +++ b/src/common/rendering/gl/gl_debug.h @@ -2,9 +2,8 @@ #define __GL_DEBUG_H #include -#include "gl_load/gl_interface.h" +#include "gl_interface.h" #include "c_cvars.h" -#include "r_defs.h" #include "v_video.h" namespace OpenGLRenderer diff --git a/src/common/rendering/gl/gl_framebuffer.cpp b/src/common/rendering/gl/gl_framebuffer.cpp new file mode 100644 index 00000000000..4b20db68f20 --- /dev/null +++ b/src/common/rendering/gl/gl_framebuffer.cpp @@ -0,0 +1,618 @@ +/* +** gl_framebuffer.cpp +** Implementation of the non-hardware specific parts of the +** OpenGL frame buffer +** +**--------------------------------------------------------------------------- +** Copyright 2010-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "gl_system.h" +#include "v_video.h" +#include "m_png.h" + +#include "i_time.h" + +#include "gl_interface.h" +#include "gl_framebuffer.h" +#include "gl_renderer.h" +#include "gl_renderbuffers.h" +#include "gl_samplers.h" +#include "hw_clock.h" +#include "hw_vrmodes.h" +#include "hw_skydome.h" +#include "hw_viewpointbuffer.h" +#include "hw_lightbuffer.h" +#include "hw_bonebuffer.h" +#include "gl_shaderprogram.h" +#include "gl_debug.h" +#include "r_videoscale.h" +#include "gl_buffers.h" +#include "gl_postprocessstate.h" +#include "v_draw.h" +#include "printf.h" +#include "gl_hwtexture.h" + +#include "flatvertices.h" +#include "hw_cvars.h" + +EXTERN_CVAR (Bool, vid_vsync) +EXTERN_CVAR(Int, gl_tonemap) +EXTERN_CVAR(Bool, cl_capfps) +EXTERN_CVAR(Int, gl_pipeline_depth); + +void gl_LoadExtensions(); +void gl_PrintStartupLog(); + +extern bool vid_hdr_active; + +namespace OpenGLRenderer +{ + FGLRenderer *GLRenderer; + +//========================================================================== +// +// +// +//========================================================================== + +OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, bool fullscreen) : + Super(hMonitor, fullscreen) +{ + // SetVSync needs to be at the very top to workaround a bug in Nvidia's OpenGL driver. + // If wglSwapIntervalEXT is called after glBindFramebuffer in a frame the setting is not changed! + Super::SetVSync(vid_vsync); + FHardwareTexture::InitGlobalState(); + + // Make sure all global variables tracking OpenGL context state are reset.. + gl_RenderState.Reset(); + + GLRenderer = nullptr; +} + +OpenGLFrameBuffer::~OpenGLFrameBuffer() +{ + PPResource::ResetAll(); + + if (mVertexData != nullptr) delete mVertexData; + if (mSkyData != nullptr) delete mSkyData; + if (mViewpoints != nullptr) delete mViewpoints; + if (mLights != nullptr) delete mLights; + if (mBones != nullptr) delete mBones; + mShadowMap.Reset(); + + if (GLRenderer) + { + delete GLRenderer; + GLRenderer = nullptr; + } +} + +//========================================================================== +// +// Initializes the GL renderer +// +//========================================================================== + +void OpenGLFrameBuffer::InitializeState() +{ + static bool first=true; + + if (first) + { + if (ogl_LoadFunctions() == ogl_LOAD_FAILED) + { + I_FatalError("Failed to load OpenGL functions."); + } + } + + gl_LoadExtensions(); + + mPipelineNbr = clamp(*gl_pipeline_depth, 1, HW_MAX_PIPELINE_BUFFERS); + mPipelineType = gl_pipeline_depth > 0; + + // Move some state to the framebuffer object for easier access. + hwcaps = gl.flags; + glslversion = gl.glslversion; + uniformblockalignment = gl.uniformblockalignment; + maxuniformblock = gl.maxuniformblock; + vendorstring = gl.vendorstring; + + if (first) + { + first=false; + gl_PrintStartupLog(); + } + + glDepthFunc(GL_LESS); + + glEnable(GL_DITHER); + glDisable(GL_CULL_FACE); + glDisable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + glEnable(GL_BLEND); + glEnable(GL_DEPTH_CLAMP); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LINE_SMOOTH); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetViewportRects(nullptr); + + mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight(), screen->mPipelineNbr); + mSkyData = new FSkyVertexBuffer; + mViewpoints = new HWViewpointBuffer(screen->mPipelineNbr); + mLights = new FLightBuffer(screen->mPipelineNbr); + mBones = new BoneBuffer(screen->mPipelineNbr); + GLRenderer = new FGLRenderer(this); + GLRenderer->Initialize(GetWidth(), GetHeight()); + static_cast(mLights->GetBuffer())->BindBase(); + static_cast(mBones->GetBuffer())->BindBase(); + + mDebug = std::make_unique(); + mDebug->Update(); +} + +//========================================================================== +// +// Updates the screen +// +//========================================================================== + +void OpenGLFrameBuffer::Update() +{ + twoD.Reset(); + Flush3D.Reset(); + + Flush3D.Clock(); + GLRenderer->Flush(); + Flush3D.Unclock(); + + Swap(); + Super::Update(); +} + +void OpenGLFrameBuffer::CopyScreenToBuffer(int width, int height, uint8_t* scr) +{ + IntRect bounds; + bounds.left = 0; + bounds.top = 0; + bounds.width = width; + bounds.height = height; + GLRenderer->CopyToBackbuffer(&bounds, false); + + // strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers + glFinish(); + glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, scr); +} + +//=========================================================================== +// +// Camera texture rendering +// +//=========================================================================== + +void OpenGLFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::function renderFunc) +{ + GLRenderer->StartOffscreen(); + GLRenderer->BindToFrameBuffer(tex); + + IntRect bounds; + bounds.left = bounds.top = 0; + bounds.width = FHardwareTexture::GetTexDimension(tex->GetWidth()); + bounds.height = FHardwareTexture::GetTexDimension(tex->GetHeight()); + + renderFunc(bounds); + GLRenderer->EndOffscreen(); + + tex->SetUpdated(true); + static_cast(screen)->camtexcount++; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +const char* OpenGLFrameBuffer::DeviceName() const +{ + return gl.modelstring; +} + +//========================================================================== +// +// Swap the buffers +// +//========================================================================== + +CVAR(Bool, gl_finishbeforeswap, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); + +void OpenGLFrameBuffer::Swap() +{ + bool swapbefore = gl_finishbeforeswap && camtexcount == 0; + Finish.Reset(); + Finish.Clock(); + if (gl_pipeline_depth < 1) + { + if (swapbefore) glFinish(); + FPSLimit(); + SwapBuffers(); + if (!swapbefore) glFinish(); + } + else + { + mVertexData->DropSync(); + + FPSLimit(); + SwapBuffers(); + + mVertexData->NextPipelineBuffer(); + mVertexData->WaitSync(); + + RenderState()->SetVertexBuffer(screen->mVertexData); // Needed for Raze because it does not reset it + } + Finish.Unclock(); + camtexcount = 0; + FHardwareTexture::UnbindAll(); + gl_RenderState.ClearLastMaterial(); + mDebug->Update(); +} + +//========================================================================== +// +// Enable/disable vertical sync +// +//========================================================================== + +void OpenGLFrameBuffer::SetVSync(bool vsync) +{ + // Switch to the default frame buffer because some drivers associate the vsync state with the bound FB object. + GLint oldDrawFramebufferBinding = 0, oldReadFramebufferBinding = 0; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDrawFramebufferBinding); + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldReadFramebufferBinding); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + Super::SetVSync(vsync); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDrawFramebufferBinding); + glBindFramebuffer(GL_READ_FRAMEBUFFER, oldReadFramebufferBinding); +} + +//=========================================================================== +// +// +//=========================================================================== + +void OpenGLFrameBuffer::SetTextureFilterMode() +{ + if (GLRenderer != nullptr && GLRenderer->mSamplerManager != nullptr) GLRenderer->mSamplerManager->SetTextureFilterMode(); +} + +IHardwareTexture *OpenGLFrameBuffer::CreateHardwareTexture(int numchannels) +{ + return new FHardwareTexture(numchannels); +} + +void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) +{ + if (mat->Source()->GetUseType() == ETextureType::SWCanvas) return; + + int numLayers = mat->NumLayers(); + MaterialLayerInfo* layer; + auto base = static_cast(mat->GetLayer(0, translation, &layer)); + + if (base->BindOrCreate(layer->layerTexture, 0, CLAMP_NONE, translation, layer->scaleFlags)) + { + for (int i = 1; i < numLayers; i++) + { + auto systex = static_cast(mat->GetLayer(i, 0, &layer)); + systex->BindOrCreate(layer->layerTexture, i, CLAMP_NONE, 0, layer->scaleFlags); + } + } + // unbind everything. + FHardwareTexture::UnbindAll(); + gl_RenderState.ClearLastMaterial(); +} + +IVertexBuffer *OpenGLFrameBuffer::CreateVertexBuffer() +{ + return new GLVertexBuffer; +} + +IIndexBuffer *OpenGLFrameBuffer::CreateIndexBuffer() +{ + return new GLIndexBuffer; +} + +IDataBuffer *OpenGLFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) +{ + return new GLDataBuffer(bindingpoint, ssbo); +} + +void OpenGLFrameBuffer::BlurScene(float amount) +{ + GLRenderer->BlurScene(amount); +} + +void OpenGLFrameBuffer::InitLightmap(int LMTextureSize, int LMTextureCount, TArray& LMTextureData) +{ + if (LMTextureData.Size() > 0) + { + GLint activeTex = 0; + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); + glActiveTexture(GL_TEXTURE0 + 17); + + if (GLRenderer->mLightMapID == 0) + glGenTextures(1, (GLuint*)&GLRenderer->mLightMapID); + + glBindTexture(GL_TEXTURE_2D_ARRAY, GLRenderer->mLightMapID); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB16F, LMTextureSize, LMTextureSize, LMTextureCount, 0, GL_RGB, GL_HALF_FLOAT, &LMTextureData[0]); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + + glActiveTexture(activeTex); + + LMTextureData.Reset(); // We no longer need this, release the memory + } +} + +void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds) +{ + Super::SetViewportRects(bounds); + if (!bounds) + { + auto vrmode = VRMode::GetVRMode(true); + vrmode->AdjustViewport(this); + } +} + +void OpenGLFrameBuffer::UpdatePalette() +{ + if (GLRenderer) + GLRenderer->ClearTonemapPalette(); +} + +FRenderState* OpenGLFrameBuffer::RenderState() +{ + return &gl_RenderState; +} + +void OpenGLFrameBuffer::AmbientOccludeScene(float m5) +{ + gl_RenderState.EnableDrawBuffers(1); + GLRenderer->AmbientOccludeScene(m5); + glViewport(screen->mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); + GLRenderer->mBuffers->BindSceneFB(true); + gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); + gl_RenderState.Apply(); +} + +void OpenGLFrameBuffer::FirstEye() +{ + GLRenderer->mBuffers->CurrentEye() = 0; // always begin at zero, in case eye count changed +} + +void OpenGLFrameBuffer::NextEye(int eyecount) +{ + GLRenderer->mBuffers->NextEye(eyecount); +} + +void OpenGLFrameBuffer::SetSceneRenderTarget(bool useSSAO) +{ + GLRenderer->mBuffers->BindSceneFB(useSSAO); +} + +void OpenGLFrameBuffer::UpdateShadowMap() +{ + if (mShadowMap.PerformUpdate()) + { + FGLDebug::PushGroup("ShadowMap"); + + FGLPostProcessState savedState; + + static_cast(screen->mShadowMap.mLightList)->BindBase(); + static_cast(screen->mShadowMap.mNodesBuffer)->BindBase(); + static_cast(screen->mShadowMap.mLinesBuffer)->BindBase(); + + GLRenderer->mBuffers->BindShadowMapFB(); + + GLRenderer->mShadowMapShader->Bind(); + GLRenderer->mShadowMapShader->Uniforms->ShadowmapQuality = gl_shadowmap_quality; + GLRenderer->mShadowMapShader->Uniforms->NodesCount = screen->mShadowMap.NodesCount(); + GLRenderer->mShadowMapShader->Uniforms.SetData(); + static_cast(GLRenderer->mShadowMapShader->Uniforms.GetBuffer())->BindBase(); + + glViewport(0, 0, gl_shadowmap_quality, 1024); + GLRenderer->RenderScreenQuad(); + + const auto& viewport = screen->mScreenViewport; + glViewport(viewport.left, viewport.top, viewport.width, viewport.height); + + GLRenderer->mBuffers->BindShadowMapTexture(16); + FGLDebug::PopGroup(); + screen->mShadowMap.FinishUpdate(); + } +} + +void OpenGLFrameBuffer::WaitForCommands(bool finish) +{ + glFinish(); +} + +void OpenGLFrameBuffer::SetSaveBuffers(bool yes) +{ + if (!GLRenderer) return; + if (yes) GLRenderer->mBuffers = GLRenderer->mSaveBuffers; + else GLRenderer->mBuffers = GLRenderer->mScreenBuffers; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void OpenGLFrameBuffer::BeginFrame() +{ + SetViewportRects(nullptr); + mViewpoints->Clear(); + if (GLRenderer != nullptr) + GLRenderer->BeginFrame(); +} + +//=========================================================================== +// +// Takes a screenshot +// +//=========================================================================== + +TArray OpenGLFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) +{ + const auto &viewport = mOutputLetterbox; + + // Grab what is in the back buffer. + // We cannot rely on SCREENWIDTH/HEIGHT here because the output may have been scaled. + TArray pixels; + pixels.Resize(viewport.width * viewport.height * 3); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(viewport.left, viewport.top, viewport.width, viewport.height, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]); + glPixelStorei(GL_PACK_ALIGNMENT, 4); + + // Copy to screenshot buffer: + int w = SCREENWIDTH; + int h = SCREENHEIGHT; + + TArray ScreenshotBuffer(w * h * 3, true); + + float rcpWidth = 1.0f / w; + float rcpHeight = 1.0f / h; + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++) + { + float u = (x + 0.5f) * rcpWidth; + float v = (y + 0.5f) * rcpHeight; + int sx = u * viewport.width; + int sy = v * viewport.height; + int sindex = (sx + sy * viewport.width) * 3; + int dindex = (x + (h - y - 1) * w) * 3; + ScreenshotBuffer[dindex] = pixels[sindex]; + ScreenshotBuffer[dindex + 1] = pixels[sindex + 1]; + ScreenshotBuffer[dindex + 2] = pixels[sindex + 2]; + } + } + + pitch = w * 3; + color_type = SS_RGB; + + // Screenshot should not use gamma correction if it was already applied to rendered image + gamma = 1; + if (vid_hdr_active && vid_fullscreen) + gamma *= 2.2f; + return ScreenshotBuffer; +} + +//=========================================================================== +// +// 2D drawing +// +//=========================================================================== + +void OpenGLFrameBuffer::Draw2D() +{ + if (GLRenderer != nullptr) + { + GLRenderer->mBuffers->BindCurrentFB(); + ::Draw2D(twod, gl_RenderState); + } +} + +void OpenGLFrameBuffer::PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) +{ + if (!swscene) GLRenderer->mBuffers->BlitSceneToTexture(); // Copy the resulting scene to the current post process texture + GLRenderer->PostProcessScene(fixedcm, flash, afterBloomDrawEndScene2D); +} + +bool OpenGLFrameBuffer::CompileNextShader() +{ + return GLRenderer->mShaderManager->CompileNextShader(); +} + +//========================================================================== +// +// OpenGLFrameBuffer :: WipeStartScreen +// +// Called before the current screen has started rendering. This needs to +// save what was drawn the previous frame so that it can be animated into +// what gets drawn this frame. +// +//========================================================================== + +FTexture *OpenGLFrameBuffer::WipeStartScreen() +{ + const auto &viewport = screen->mScreenViewport; + + auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); + tex->GetSystemTexture()->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, "WipeStartScreen"); + glFinish(); + static_cast(tex->GetSystemTexture())->Bind(0, false); + + GLRenderer->mBuffers->BindCurrentFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: WipeEndScreen +// +// The screen we want to animate to has just been drawn. +// +//========================================================================== + +FTexture *OpenGLFrameBuffer::WipeEndScreen() +{ + GLRenderer->Flush(); + const auto &viewport = screen->mScreenViewport; + auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); + tex->GetSystemTexture()->CreateTexture(NULL, viewport.width, viewport.height, 0, false, "WipeEndScreen"); + glFinish(); + static_cast(tex->GetSystemTexture())->Bind(0, false); + GLRenderer->mBuffers->BindCurrentFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; +} + +} diff --git a/src/common/rendering/gl/gl_framebuffer.h b/src/common/rendering/gl/gl_framebuffer.h new file mode 100644 index 00000000000..7b659db0a46 --- /dev/null +++ b/src/common/rendering/gl/gl_framebuffer.h @@ -0,0 +1,79 @@ +#ifndef __GL_FRAMEBUFFER +#define __GL_FRAMEBUFFER + +#include "gl_sysfb.h" +#include "m_png.h" + +#include + +namespace OpenGLRenderer +{ + +class FHardwareTexture; +class FGLDebug; + +class OpenGLFrameBuffer : public SystemGLFrameBuffer +{ + typedef SystemGLFrameBuffer Super; + + void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) override; + +public: + + OpenGLFrameBuffer(void *hMonitor, bool fullscreen) ; + ~OpenGLFrameBuffer(); + int Backend() override { return 2; } + bool CompileNextShader() override; + void InitializeState() override; + void Update() override; + + void AmbientOccludeScene(float m5) override; + void FirstEye() override; + void NextEye(int eyecount) override; + void SetSceneRenderTarget(bool useSSAO) override; + void UpdateShadowMap() override; + void WaitForCommands(bool finish) override; + void SetSaveBuffers(bool yes) override; + void CopyScreenToBuffer(int width, int height, uint8_t* buffer) override; + bool FlipSavePic() const override { return true; } + + FRenderState* RenderState() override; + void UpdatePalette() override; + const char* DeviceName() const override; + void SetTextureFilterMode() override; + IHardwareTexture *CreateHardwareTexture(int numchannels) override; + void PrecacheMaterial(FMaterial *mat, int translation) override; + void BeginFrame() override; + void SetViewportRects(IntRect *bounds) override; + void BlurScene(float amount) override; + IVertexBuffer *CreateVertexBuffer() override; + IIndexBuffer *CreateIndexBuffer() override; + IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override; + + void InitLightmap(int LMTextureSize, int LMTextureCount, TArray& LMTextureData) override; + + // Retrieves a buffer containing image data for a screenshot. + // Hint: Pitch can be negative for upside-down images, in which case buffer + // points to the last row in the buffer, which will be the first row output. + virtual TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override; + + void Swap(); + bool IsHWGammaActive() const { return HWGammaActive; } + + void SetVSync(bool vsync) override; + + void Draw2D() override; + void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) override; + + bool HWGammaActive = false; // Are we using hardware or software gamma? + std::unique_ptr mDebug; // Debug API + + FTexture *WipeStartScreen() override; + FTexture *WipeEndScreen() override; + + int camtexcount = 0; +}; + +} + +#endif //__GL_FRAMEBUFFER diff --git a/src/rendering/gl/textures/gl_hwtexture.cpp b/src/common/rendering/gl/gl_hwtexture.cpp similarity index 77% rename from src/rendering/gl/textures/gl_hwtexture.cpp rename to src/common/rendering/gl/gl_hwtexture.cpp index c864eedd2a0..37b066155b7 100644 --- a/src/rendering/gl/textures/gl_hwtexture.cpp +++ b/src/common/rendering/gl/gl_hwtexture.cpp @@ -1,50 +1,56 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2004-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// /* -** gltexture.cpp -** Low level OpenGL texture handling. These classes are also -** containers for the various translations a texture can have. +** gl_hwtexture.cpp +** GL texture abstraction +** +**--------------------------------------------------------------------------- +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** ** */ -#include "gl_load/gl_system.h" -#include "templates.h" +#include "gl_system.h" + #include "c_cvars.h" -#include "doomtype.h" -#include "r_data/colormaps.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_material.h" -#include "gl_load/gl_interface.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "gl/system/gl_debug.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_renderstate.h" -#include "gl/textures/gl_samplers.h" +#include "gl_interface.h" +#include "hw_cvars.h" +#include "gl_debug.h" +#include "gl_renderer.h" +#include "gl_renderstate.h" +#include "gl_samplers.h" +#include "gl_hwtexture.h" namespace OpenGLRenderer { -TexFilter_s TexFilter[]={ +TexFilter_s TexFilter[] = { {GL_NEAREST, GL_NEAREST, false}, {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, true}, {GL_LINEAR, GL_LINEAR, false}, @@ -54,20 +60,6 @@ TexFilter_s TexFilter[]={ {GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST, true}, }; -int TexFormat[]={ - GL_RGBA8, - GL_RGB5_A1, - GL_RGBA4, - GL_RGBA2, - // [BB] Added compressed texture formats. - GL_COMPRESSED_RGBA_ARB, - GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, -}; - - - //=========================================================================== // // Static texture data @@ -85,7 +77,7 @@ unsigned int FHardwareTexture::lastbound[FHardwareTexture::MAX_TEXTURES]; // //=========================================================================== -unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) +unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) { int rh,rw; int texformat = GL_RGBA8;// TexFormat[gl_texture_format]; @@ -156,7 +148,7 @@ unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int { sourcetype = GL_BGRA; } - + if (!firstCall && glBufferID > 0) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rw, rh, sourcetype, GL_UNSIGNED_BYTE, buffer); else @@ -246,11 +238,6 @@ unsigned int FHardwareTexture::Bind(int texunit, bool needmipmap) return 0; } -unsigned int FHardwareTexture::GetTextureHandle(int translation) -{ - return glTexID; -} - void FHardwareTexture::Unbind(int texunit) { if (lastbound[texunit] != 0) @@ -268,7 +255,6 @@ void FHardwareTexture::UnbindAll() { Unbind(texunit); } - gl_RenderState.ClearLastMaterial(); } //=========================================================================== @@ -315,21 +301,21 @@ void FHardwareTexture::BindToFrameBuffer(int width, int height) bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, int translation, int flags) { - int usebright = false; - - auto remap = TranslationToTable(translation); - translation = remap == nullptr ? 0 : remap->GetUniqueIndex(); - - bool needmipmap = (clampmode <= CLAMP_XY); + bool needmipmap = (clampmode <= CLAMP_XY) && !forcenofilter; // Bind it to the system. if (!Bind(texunit, needmipmap)) { - + if (flags & CTF_Indexed) + { + glTextureBytes = 1; + forcenofilter = true; + needmipmap = false; + } int w = 0, h = 0; // Create this texture - + FTextureBuffer texbuffer; if (!tex->isHardwareCanvas()) @@ -343,13 +329,13 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i w = tex->GetWidth(); h = tex->GetHeight(); } - if (!CreateTexture(texbuffer.mBuffer, w, h, texunit, needmipmap, translation, "FHardwareTexture.BindOrCreate")) + if (!CreateTexture(texbuffer.mBuffer, w, h, texunit, needmipmap, "FHardwareTexture.BindOrCreate")) { // could not create texture return false; } } - if (tex->isHardwareCanvas()) static_cast(tex)->NeedUpdate(); + if (forcenofilter && clampmode <= CLAMP_XY) clampmode += CLAMP_NOFILTER - CLAMP_NONE; GLRenderer->mSamplerManager->Bind(texunit, clampmode, 255); return true; } diff --git a/src/common/rendering/gl/gl_hwtexture.h b/src/common/rendering/gl/gl_hwtexture.h new file mode 100644 index 00000000000..1b3cdff2cc1 --- /dev/null +++ b/src/common/rendering/gl/gl_hwtexture.h @@ -0,0 +1,80 @@ +#pragma once +class FBitmap; +class FTexture; + +#include "tarray.h" +#include "hw_ihwtexture.h" + + +#ifdef LoadImage +#undef LoadImage +#endif + +#define SHADED_TEXTURE -1 +#define DIRECT_PALETTE -2 + +#include "tarray.h" +#include "gl_interface.h" +#include "hw_ihwtexture.h" + +class FCanvasTexture; + +namespace OpenGLRenderer +{ + +class FHardwareTexture : public IHardwareTexture +{ +public: + + static unsigned int lastbound[MAX_TEXTURES]; + + static int GetTexDimension(int value) + { + if (value > gl.max_texturesize) return gl.max_texturesize; + return value; + } + + static void InitGlobalState() { for (int i = 0; i < MAX_TEXTURES; i++) lastbound[i] = 0; } + +private: + + bool forcenofilter; + + unsigned int glTexID = 0; + unsigned int glDepthID = 0; // only used by camera textures + unsigned int glBufferID = 0; + int glTextureBytes; + bool mipmapped = false; + + int GetDepthBuffer(int w, int h); + +public: + FHardwareTexture(int numchannels = 4, bool disablefilter = false) + { + forcenofilter = disablefilter; + glTextureBytes = numchannels; + } + + ~FHardwareTexture(); + + static void Unbind(int texunit); + static void UnbindAll(); + + void BindToFrameBuffer(int w, int h); + + unsigned int Bind(int texunit, bool needmipmap); + bool BindOrCreate(FTexture* tex, int texunit, int clampmode, int translation, int flags); + + void AllocateBuffer(int w, int h, int texelsize); + uint8_t* MapBuffer(); + + unsigned int CreateTexture(unsigned char* buffer, int w, int h, int texunit, bool mipmap, const char* name); + unsigned int GetTextureHandle() + { + return glTexID; + } + + int numChannels() { return glTextureBytes; } +}; + +} diff --git a/src/rendering/gl/renderer/gl_postprocess.cpp b/src/common/rendering/gl/gl_postprocess.cpp similarity index 89% rename from src/rendering/gl/renderer/gl_postprocess.cpp rename to src/common/rendering/gl/gl_postprocess.cpp index f8618926848..f5ec0bfaef0 100644 --- a/src/rendering/gl/renderer/gl_postprocess.cpp +++ b/src/common/rendering/gl/gl_postprocess.cpp @@ -19,26 +19,23 @@ ** 3. This notice may not be removed or altered from any source distribution. */ -#include "gl_load/gl_system.h" -#include "gi.h" +#include "gl_system.h" #include "m_png.h" -#include "r_utility.h" -#include "d_player.h" -#include "gl/system/gl_buffers.h" -#include "gl/system/gl_framebuffer.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "gl/system/gl_debug.h" -#include "gl/renderer/gl_renderstate.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_postprocessstate.h" -#include "gl/shaders/gl_shaderprogram.h" +#include "gl_buffers.h" +#include "gl_framebuffer.h" +#include "gl_debug.h" +#include "gl_renderbuffers.h" +#include "gl_renderer.h" +#include "gl_postprocessstate.h" +#include "gl_shaderprogram.h" #include "hwrenderer/postprocessing/hw_postprocess.h" #include "hwrenderer/postprocessing/hw_postprocess_cvars.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "hwrenderer/data/flatvertices.h" -#include "gl/textures/gl_hwtexture.h" +#include "flatvertices.h" #include "r_videoscale.h" +#include "v_video.h" + +#include "hw_vrmodes.h" +#include "v_draw.h" extern bool vid_hdr_active; @@ -52,10 +49,10 @@ void FGLRenderer::RenderScreenQuad() { auto buffer = static_cast(screen->mVertexData->GetBufferObjects().first); buffer->Bind(nullptr); - glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4); + glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 3); } -void FGLRenderer::PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) +void FGLRenderer::PostProcessScene(int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) { int sceneWidth = mBuffers->GetSceneWidth(); int sceneHeight = mBuffers->GetSceneHeight(); @@ -64,8 +61,8 @@ void FGLRenderer::PostProcessScene(int fixedcm, const std::function &aft hw_postprocess.Pass1(&renderstate, fixedcm, sceneWidth, sceneHeight); mBuffers->BindCurrentFB(); - afterBloomDrawEndScene2D(); - hw_postprocess.Pass2(&renderstate, fixedcm, sceneWidth, sceneHeight); + if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D(); + hw_postprocess.Pass2(&renderstate, fixedcm, flash, sceneWidth, sceneHeight); } //----------------------------------------------------------------------------- @@ -127,7 +124,7 @@ void FGLRenderer::Flush() if (eyeCount - eye_ix > 1) mBuffers->NextEye(eyeCount); } - screen->Clear2D(); + twod->Clear(); FGLPostProcessState savedState; FGLDebug::PushGroup("PresentEyes"); @@ -147,7 +144,7 @@ void FGLRenderer::Flush() void FGLRenderer::CopyToBackbuffer(const IntRect *bounds, bool applyGamma) { screen->Draw2D(); // draw all pending 2D stuff before copying the buffer - screen->Clear2D(); + twod->Clear(); GLPPRenderState renderstate(mBuffers); hw_postprocess.customShaders.Run(&renderstate, "screen"); @@ -201,7 +198,7 @@ void FGLRenderer::DrawPresentTexture(const IntRect &box, bool applyGamma) } else { - mPresentShader->Uniforms->InvGamma = 1.0f / clamp(Gamma, 0.1f, 4.f); + mPresentShader->Uniforms->InvGamma = 1.0f / clamp(vid_gamma, 0.1f, 4.f); mPresentShader->Uniforms->Contrast = clamp(vid_contrast, 0.1f, 3.f); mPresentShader->Uniforms->Brightness = clamp(vid_brightness, -0.8f, 0.8f); mPresentShader->Uniforms->Saturation = clamp(vid_saturation, -15.0f, 15.f); diff --git a/src/rendering/gl/renderer/gl_postprocessstate.cpp b/src/common/rendering/gl/gl_postprocessstate.cpp similarity index 96% rename from src/rendering/gl/renderer/gl_postprocessstate.cpp rename to src/common/rendering/gl/gl_postprocessstate.cpp index e147e6adb53..e490e870886 100644 --- a/src/rendering/gl/renderer/gl_postprocessstate.cpp +++ b/src/common/rendering/gl/gl_postprocessstate.cpp @@ -19,10 +19,10 @@ ** 3. This notice may not be removed or altered from any source distribution. */ -#include "templates.h" -#include "gl_load/gl_system.h" -#include "gl_load/gl_interface.h" -#include "gl/renderer/gl_postprocessstate.h" + +#include "gl_system.h" +#include "gl_interface.h" +#include "gl_postprocessstate.h" namespace OpenGLRenderer { diff --git a/src/rendering/gl/renderer/gl_postprocessstate.h b/src/common/rendering/gl/gl_postprocessstate.h similarity index 93% rename from src/rendering/gl/renderer/gl_postprocessstate.h rename to src/common/rendering/gl/gl_postprocessstate.h index 57bef88fdb5..b21e73840d4 100644 --- a/src/rendering/gl/renderer/gl_postprocessstate.h +++ b/src/common/rendering/gl/gl_postprocessstate.h @@ -2,10 +2,9 @@ #define __GL_POSTPROCESSSTATE_H #include -#include "gl_load/gl_interface.h" +#include "gl_interface.h" #include "matrix.h" #include "c_cvars.h" -#include "r_defs.h" namespace OpenGLRenderer { diff --git a/src/rendering/gl/renderer/gl_renderbuffers.cpp b/src/common/rendering/gl/gl_renderbuffers.cpp similarity index 98% rename from src/rendering/gl/renderer/gl_renderbuffers.cpp rename to src/common/rendering/gl/gl_renderbuffers.cpp index 4f2077b2429..3ce335d7a6d 100644 --- a/src/rendering/gl/renderer/gl_renderbuffers.cpp +++ b/src/common/rendering/gl/gl_renderbuffers.cpp @@ -19,18 +19,21 @@ ** 3. This notice may not be removed or altered from any source distribution. */ -#include "gl_load/gl_system.h" +#include "gl_system.h" #include "v_video.h" -#include "gl_load/gl_interface.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "gl/system/gl_debug.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "gl/renderer/gl_postprocessstate.h" -#include "gl/shaders/gl_shaderprogram.h" -#include "gl/system/gl_buffers.h" +#include "gl_interface.h" +#include "printf.h" +#include "hw_cvars.h" +#include "gl_debug.h" +#include "gl_renderer.h" +#include "gl_renderbuffers.h" +#include "gl_postprocessstate.h" +#include "gl_shaderprogram.h" +#include "gl_buffers.h" + #include +EXTERN_CVAR(Int, gl_debug_level) CVAR(Int, gl_multisample, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); namespace OpenGLRenderer @@ -84,6 +87,7 @@ void FGLRenderBuffers::ClearScene() void FGLRenderBuffers::ClearPipeline() { + DeleteRenderBuffer(mPipelineDepthStencilBuf); for (int i = 0; i < NumPipelineTextures; i++) { DeleteFrameBuffer(mPipelineFB[i]); @@ -236,10 +240,11 @@ void FGLRenderBuffers::CreatePipeline(int width, int height) ClearPipeline(); ClearEyeBuffers(); + mPipelineDepthStencilBuf = CreateRenderBuffer("PipelineDepthStencil", GL_DEPTH24_STENCIL8, width, height); for (int i = 0; i < NumPipelineTextures; i++) { mPipelineTexture[i] = Create2DTexture("PipelineTexture", GL_RGBA16F, width, height); - mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i]); + mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i], mPipelineDepthStencilBuf); } } @@ -441,8 +446,6 @@ bool FGLRenderBuffers::CheckFrameBufferCompleteness() if (result == GL_FRAMEBUFFER_COMPLETE) return true; - bool FailedCreate = true; - if (gl_debug_level > 0) { FString error = "glCheckFramebufferStatus failed: "; @@ -833,8 +836,8 @@ FShaderProgram *GLPPRenderState::GetGLShader(PPShader *shader) prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, POSTPROCESS_BINDINGPOINT); prolog += shader->Defines; - glshader->Compile(FShaderProgram::Vertex, shader->VertexShader, "", shader->Version); - glshader->Compile(FShaderProgram::Fragment, shader->FragmentShader, prolog, shader->Version); + glshader->Compile(FShaderProgram::Vertex, shader->VertexShader.GetChars(), "", shader->Version); + glshader->Compile(FShaderProgram::Fragment, shader->FragmentShader.GetChars(), prolog.GetChars(), shader->Version); glshader->Link(shader->FragmentShader.GetChars()); if (!shader->Uniforms.empty()) glshader->SetUniformBufferLocation(POSTPROCESS_BINDINGPOINT, "Uniforms"); @@ -949,7 +952,7 @@ void GLPPRenderState::Draw() { if (!shader->Uniforms) shader->Uniforms.reset(screen->CreateDataBuffer(POSTPROCESS_BINDINGPOINT, false, false)); - shader->Uniforms->SetData(Uniforms.Data.Size(), Uniforms.Data.Data()); + shader->Uniforms->SetData(Uniforms.Data.Size(), Uniforms.Data.Data(), BufferUsageType::Static); static_cast(shader->Uniforms.get())->BindBase(); } @@ -989,4 +992,4 @@ int FGLRenderBuffers::NextEye(int eyeCount) return mCurrentEye; } -} // namespace OpenGLRenderer \ No newline at end of file +} // namespace OpenGLRenderer diff --git a/src/rendering/gl/renderer/gl_renderbuffers.h b/src/common/rendering/gl/gl_renderbuffers.h similarity index 99% rename from src/rendering/gl/renderer/gl_renderbuffers.h rename to src/common/rendering/gl/gl_renderbuffers.h index 4e1fd977c39..bb652e4958f 100644 --- a/src/rendering/gl/renderer/gl_renderbuffers.h +++ b/src/common/rendering/gl/gl_renderbuffers.h @@ -1,7 +1,6 @@ #pragma once -#include "gl/shaders/gl_shader.h" #include "hwrenderer/postprocessing/hw_postprocess.h" namespace OpenGLRenderer @@ -174,6 +173,7 @@ class FGLRenderBuffers static const int NumPipelineTextures = 2; int mCurrentPipelineTexture = 0; + PPGLRenderBuffer mPipelineDepthStencilBuf; // Buffers for the scene PPGLTexture mSceneMultisampleTex; @@ -209,4 +209,4 @@ class FGLRenderBuffers friend class GLPPRenderState; }; -} \ No newline at end of file +} diff --git a/src/common/rendering/gl/gl_renderer.cpp b/src/common/rendering/gl/gl_renderer.cpp new file mode 100644 index 00000000000..305ee0a9742 --- /dev/null +++ b/src/common/rendering/gl/gl_renderer.cpp @@ -0,0 +1,183 @@ +/* +** gl_renderer.cpp +** Renderer interface +** +**--------------------------------------------------------------------------- +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "gl_system.h" +#include "files.h" +#include "v_video.h" +#include "m_png.h" +#include "filesystem.h" +#include "i_time.h" +#include "cmdlib.h" +#include "version.h" +#include "gl_interface.h" +#include "gl_framebuffer.h" +#include "hw_cvars.h" +#include "gl_debug.h" +#include "gl_renderer.h" +#include "gl_renderstate.h" +#include "gl_renderbuffers.h" +#include "gl_shaderprogram.h" +#include "flatvertices.h" +#include "gl_samplers.h" +#include "hw_lightbuffer.h" +#include "r_videoscale.h" +#include "model.h" +#include "gl_postprocessstate.h" +#include "gl_buffers.h" +#include "texturemanager.h" + +EXTERN_CVAR(Int, screenblocks) + +namespace OpenGLRenderer +{ + +//=========================================================================== +// +// Renderer interface +// +//=========================================================================== + +//----------------------------------------------------------------------------- +// +// Initialize +// +//----------------------------------------------------------------------------- + +FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) +{ + framebuffer = fb; +} + +void FGLRenderer::Initialize(int width, int height) +{ + mScreenBuffers = new FGLRenderBuffers(); + mSaveBuffers = new FGLRenderBuffers(); + mBuffers = mScreenBuffers; + mPresentShader = new FPresentShader(); + mPresent3dCheckerShader = new FPresent3DCheckerShader(); + mPresent3dColumnShader = new FPresent3DColumnShader(); + mPresent3dRowShader = new FPresent3DRowShader(); + mShadowMapShader = new FShadowMapShader(); + + // needed for the core profile, because someone decided it was a good idea to remove the default VAO. + glGenVertexArrays(1, &mVAOID); + glBindVertexArray(mVAOID); + FGLDebug::LabelObject(GL_VERTEX_ARRAY, mVAOID, "FGLRenderer.mVAOID"); + + mFBID = 0; + mOldFBID = 0; + + mShaderManager = new FShaderManager; + mSamplerManager = new FSamplerManager; +} + +FGLRenderer::~FGLRenderer() +{ + FlushModels(); + TexMan.FlushAll(); + if (mShaderManager != nullptr) delete mShaderManager; + if (mSamplerManager != nullptr) delete mSamplerManager; + if (mFBID != 0) glDeleteFramebuffers(1, &mFBID); + if (mVAOID != 0) + { + glBindVertexArray(0); + glDeleteVertexArrays(1, &mVAOID); + } + if (mBuffers) delete mBuffers; + if (mSaveBuffers) delete mSaveBuffers; + if (mPresentShader) delete mPresentShader; + if (mPresent3dCheckerShader) delete mPresent3dCheckerShader; + if (mPresent3dColumnShader) delete mPresent3dColumnShader; + if (mPresent3dRowShader) delete mPresent3dRowShader; + if (mShadowMapShader) delete mShadowMapShader; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +bool FGLRenderer::StartOffscreen() +{ + bool firstBind = (mFBID == 0); + if (mFBID == 0) + glGenFramebuffers(1, &mFBID); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mOldFBID); + glBindFramebuffer(GL_FRAMEBUFFER, mFBID); + if (firstBind) + FGLDebug::LabelObject(GL_FRAMEBUFFER, mFBID, "OffscreenFB"); + return true; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void FGLRenderer::EndOffscreen() +{ + glBindFramebuffer(GL_FRAMEBUFFER, mOldFBID); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void FGLRenderer::BindToFrameBuffer(FTexture *tex) +{ + auto BaseLayer = static_cast(tex->GetHardwareTexture(0, 0)); + // must create the hardware texture first + BaseLayer->BindOrCreate(tex, 0, 0, 0, 0); + FHardwareTexture::Unbind(0); + gl_RenderState.ClearLastMaterial(); + BaseLayer->BindToFrameBuffer(tex->GetWidth(), tex->GetHeight()); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void FGLRenderer::BeginFrame() +{ + mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height); + mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT); +} + +} diff --git a/src/common/rendering/gl/gl_renderer.h b/src/common/rendering/gl/gl_renderer.h new file mode 100644 index 00000000000..cb276d8bc61 --- /dev/null +++ b/src/common/rendering/gl/gl_renderer.h @@ -0,0 +1,116 @@ +#ifndef __GL_RENDERER_H +#define __GL_RENDERER_H + +#include "v_video.h" +#include "vectors.h" +#include "matrix.h" +#include "gl_renderbuffers.h" +#include + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +struct particle_t; +class FCanvasTexture; +class FFlatVertexBuffer; +class FSkyVertexBuffer; +class HWPortal; +class FLightBuffer; +class DPSprite; +class FGLRenderBuffers; +class FGL2DDrawer; +class SWSceneDrawer; +class HWViewpointBuffer; +struct FRenderViewpoint; + +namespace OpenGLRenderer +{ + class FHardwareTexture; + class FShaderManager; + class FSamplerManager; + class OpenGLFrameBuffer; + class FPresentShaderBase; + class FPresentShader; + class FPresent3DCheckerShader; + class FPresent3DColumnShader; + class FPresent3DRowShader; + class FShadowMapShader; + +class FGLRenderer +{ +public: + + OpenGLFrameBuffer *framebuffer; + int mMirrorCount = 0; + int mPlaneMirrorCount = 0; + FShaderManager *mShaderManager = nullptr; + FSamplerManager *mSamplerManager = nullptr; + unsigned int mFBID; + unsigned int mVAOID; + unsigned int mStencilValue = 0; + + int mOldFBID; + + FGLRenderBuffers *mBuffers = nullptr; + FGLRenderBuffers *mScreenBuffers = nullptr; + FGLRenderBuffers *mSaveBuffers = nullptr; + FPresentShader *mPresentShader = nullptr; + FPresent3DCheckerShader *mPresent3dCheckerShader = nullptr; + FPresent3DColumnShader *mPresent3dColumnShader = nullptr; + FPresent3DRowShader *mPresent3dRowShader = nullptr; + FShadowMapShader *mShadowMapShader = nullptr; + + int mLightMapID = 0; + + //FRotator mAngles; + + FGLRenderer(OpenGLFrameBuffer *fb); + ~FGLRenderer() ; + + void Initialize(int width, int height); + + void ClearBorders(); + + void PresentStereo(); + void RenderScreenQuad(); + void PostProcessScene(int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D); + void AmbientOccludeScene(float m5); + void ClearTonemapPalette(); + void BlurScene(float gameinfobluramount); + void CopyToBackbuffer(const IntRect *bounds, bool applyGamma); + void DrawPresentTexture(const IntRect &box, bool applyGamma); + void Flush(); + void BeginFrame(); + + bool StartOffscreen(); + void EndOffscreen(); + + void BindToFrameBuffer(FTexture* tex); + +private: + + bool QuadStereoCheckInitialRenderContextState(); + void PresentAnaglyph(bool r, bool g, bool b); + void PresentSideBySide(int); + void PresentTopBottom(); + void prepareInterleavedPresent(FPresentShaderBase& shader); + void PresentColumnInterleaved(); + void PresentRowInterleaved(); + void PresentCheckerInterleaved(); + void PresentQuadStereo(); + +}; + +struct TexFilter_s +{ + int minfilter; + int magfilter; + bool mipmapping; +} ; + + +extern FGLRenderer *GLRenderer; + +} +#endif diff --git a/src/rendering/gl/renderer/gl_renderstate.cpp b/src/common/rendering/gl/gl_renderstate.cpp similarity index 85% rename from src/rendering/gl/renderer/gl_renderstate.cpp rename to src/common/rendering/gl/gl_renderstate.cpp index 60ed8d8cbb5..10baa3e663c 100644 --- a/src/rendering/gl/renderer/gl_renderstate.cpp +++ b/src/common/rendering/gl/gl_renderstate.cpp @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -25,21 +25,19 @@ ** */ -#include "templates.h" -#include "doomstat.h" -#include "r_data/colormaps.h" -#include "gl_load/gl_system.h" -#include "gl_load/gl_interface.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/scene/hw_skydome.h" -#include "gl/shaders/gl_shader.h" -#include "gl/renderer/gl_renderer.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "gl/textures/gl_hwtexture.h" -#include "gl/system/gl_buffers.h" -#include "hwrenderer/utility/hw_clock.h" + +#include "gl_system.h" +#include "gl_interface.h" +#include "hw_cvars.h" +#include "flatvertices.h" +#include "gl_shader.h" +#include "gl_renderer.h" +#include "hw_lightbuffer.h" +#include "hw_bonebuffer.h" +#include "gl_renderbuffers.h" +#include "gl_hwtexture.h" +#include "gl_buffers.h" +#include "hw_clock.h" #include "hwrenderer/data/hw_viewpointbuffer.h" namespace OpenGLRenderer @@ -126,7 +124,8 @@ bool FGLRenderState::ApplyShader() activeShader->muDesaturation.Set(mStreamData.uDesaturationFactor); activeShader->muFogEnabled.Set(fogset); - activeShader->muTextureMode.Set(mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode); + + activeShader->muTextureMode.Set(GetTextureModeAndFlags(mTempTM)); activeShader->muLightParms.Set(mLightParms); activeShader->muFogColor.Set(mStreamData.uFogColor); activeShader->muObjectColor.Set(mStreamData.uObjectColor); @@ -135,12 +134,17 @@ bool FGLRenderState::ApplyShader() activeShader->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.); activeShader->muAlphaThreshold.Set(mAlphaThreshold); activeShader->muLightIndex.Set(-1); + activeShader->muBoneIndexBase.Set(-1); activeShader->muClipSplit.Set(mClipSplit); activeShader->muSpecularMaterial.Set(mGlossiness, mSpecularLevel); activeShader->muAddColor.Set(mStreamData.uAddColor); activeShader->muTextureAddColor.Set(mStreamData.uTextureAddColor); activeShader->muTextureModulateColor.Set(mStreamData.uTextureModulateColor); activeShader->muTextureBlendColor.Set(mStreamData.uTextureBlendColor); + activeShader->muDetailParms.Set(&mStreamData.uDetailParms.X); +#ifdef NPOT_EMULATION + activeShader->muNpotEmulation.Set(&mStreamData.uNpotEmulation.X); +#endif if (mGlowEnabled || activeShader->currentglowstate) { @@ -166,6 +170,7 @@ bool FGLRenderState::ApplyShader() activeShader->currentsplitstate = mSplitEnabled; } + if (mTextureMatrixEnabled) { matrixToGL(mTextureMatrix, activeShader->texturematrix_index); @@ -199,7 +204,7 @@ bool FGLRenderState::ApplyShader() size_t start, size; index = screen->mLights->GetBinding(index, &start, &size); - if (start != mLastMappedLightIndex) + if (start != mLastMappedLightIndex || screen->mPipelineNbr > 1) // If multiple buffers always bind { mLastMappedLightIndex = start; static_cast(screen->mLights->GetBuffer())->BindRange(nullptr, start, size); @@ -207,6 +212,21 @@ bool FGLRenderState::ApplyShader() } activeShader->muLightIndex.Set(index); + + index = mBoneIndexBase; + if (!screen->mBones->GetBufferType() && index >= 0) // Uniform buffer fallback support + { + size_t start, size; + index = screen->mBones->GetBinding(index, &start, &size); + + if (start != mLastMappedBoneIndexBase || screen->mPipelineNbr > 1) // If multiple buffers always bind + { + mLastMappedBoneIndexBase = start; + static_cast(screen->mBones->GetBuffer())->BindRange(nullptr, start, size); + } + } + activeShader->muBoneIndexBase.Set(index); + return true; } @@ -293,7 +313,7 @@ void FGLRenderState::Apply() void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader) { - if (mat->tex->isHardwareCanvas()) + if (mat->Source()->isHardwareCanvas()) { mTempTM = TM_OPAQUE; } @@ -301,36 +321,46 @@ void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translatio { mTempTM = TM_NORMAL; } + auto tex = mat->Source(); mEffectState = overrideshader >= 0 ? overrideshader : mat->GetShaderIndex(); - mShaderTimer = mat->tex->shaderspeed; - SetSpecular(mat->tex->Glossiness, mat->tex->SpecularLevel); - - auto tex = mat->tex; - if (tex->UseType == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; - if (tex->isHardwareCanvas()) clampmode = CLAMP_CAMTEX; - else if ((tex->isWarped() || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; - + mShaderTimer = tex->GetShaderSpeed(); + SetSpecular(tex->GetGlossiness(), tex->GetSpecularLevel()); + if (tex->isHardwareCanvas()) static_cast(tex->GetTexture())->NeedUpdate(); + + clampmode = tex->GetClampMode(clampmode); + // avoid rebinding the same texture multiple times. if (mat == lastMaterial && lastClamp == clampmode && translation == lastTranslation) return; lastMaterial = mat; lastClamp = clampmode; lastTranslation = translation; - int usebright = false; int maxbound = 0; - int flags = mat->isExpanded() ? CTF_Expand : 0; - int numLayers = mat->GetLayers(); - auto base = static_cast(mat->GetLayer(0, translation)); + int numLayers = mat->NumLayers(); + MaterialLayerInfo* layer; + auto base = static_cast(mat->GetLayer(0, translation, &layer)); - if (base->BindOrCreate(tex, 0, clampmode, translation, flags)) + if (base->BindOrCreate(tex->GetTexture(), 0, clampmode, translation, layer->scaleFlags)) { - for (int i = 1; iscaleFlags & CTF_Indexed)) + { + for (int i = 1; i < numLayers; i++) + { + auto systex = static_cast(mat->GetLayer(i, 0, &layer)); + // fixme: Upscale flags must be disabled for certain layers. + systex->BindOrCreate(layer->layerTexture, i, clampmode, 0, layer->scaleFlags); + maxbound = i; + } + } + else { - FTexture *layer; - auto systex = static_cast(mat->GetLayer(i, 0, &layer)); - systex->BindOrCreate(layer, i, clampmode, 0, mat->isExpanded() ? CTF_Expand : 0); - maxbound = i; + for (int i = 1; i < 3; i++) + { + auto systex = static_cast(mat->GetLayer(i, translation, &layer)); + systex->Bind(i, false); + maxbound = i; + } } } // unbind everything from the last texture that's still active @@ -349,7 +379,7 @@ void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translatio void FGLRenderState::ApplyBlendMode() { - static int blendstyles[] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, }; + static int blendstyles[] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA }; static int renderops[] = { 0, GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; diff --git a/src/rendering/gl/renderer/gl_renderstate.h b/src/common/rendering/gl/gl_renderstate.h similarity index 88% rename from src/rendering/gl/renderer/gl_renderstate.h rename to src/common/rendering/gl/gl_renderstate.h index 9cb76db47a5..b89a02ad8c0 100644 --- a/src/rendering/gl/renderer/gl_renderstate.h +++ b/src/common/rendering/gl/gl_renderstate.h @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -23,16 +23,13 @@ #ifndef __GL_RENDERSTATE_H #define __GL_RENDERSTATE_H +#include #include -#include "gl_load/gl_interface.h" +#include "gl_interface.h" #include "matrix.h" -#include "hwrenderer/scene//hw_drawstructs.h" -#include "hwrenderer/scene//hw_renderstate.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_renderstate.h" +#include "hw_material.h" #include "c_cvars.h" -#include "r_defs.h" -#include "r_data/r_translate.h" -#include "g_levellocals.h" namespace OpenGLRenderer { @@ -40,7 +37,7 @@ namespace OpenGLRenderer class FShader; struct HWSectorPlane; -class FGLRenderState : public FRenderState +class FGLRenderState final : public FRenderState { uint8_t mLastDepthClamp : 1; @@ -69,6 +66,7 @@ class FGLRenderState : public FRenderState int lastTranslation = 0; int maxBoundMaterial = -1; size_t mLastMappedLightIndex = SIZE_MAX; + size_t mLastMappedBoneIndexBase = SIZE_MAX; IVertexBuffer *mCurrentVertexBuffer; int mCurrentVertexOffsets[2]; // one per binding point @@ -108,15 +106,16 @@ class FGLRenderState : public FRenderState mSpecularLevel = specularLevel; } - void EnableDrawBuffers(int count) override + void EnableDrawBuffers(int count, bool apply = false) override { - count = MIN(count, 3); + count = min(count, 3); if (mNumDrawBuffers != count) { static GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; glDrawBuffers(count, buffers); mNumDrawBuffers = count; } + if (apply) Apply(); } void ToggleState(int state, bool on); diff --git a/src/common/rendering/gl/gl_samplers.cpp b/src/common/rendering/gl/gl_samplers.cpp new file mode 100644 index 00000000000..5ed7cbc1917 --- /dev/null +++ b/src/common/rendering/gl/gl_samplers.cpp @@ -0,0 +1,141 @@ +/* +** gl_samplers.cpp +** +** Texture sampler handling +** +**--------------------------------------------------------------------------- +** Copyright 2015-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include "gl_system.h" +#include "c_cvars.h" + +#include "gl_interface.h" +#include "hw_cvars.h" +#include "gl_debug.h" +#include "gl_renderer.h" +#include "gl_samplers.h" +#include "hw_material.h" +#include "i_interface.h" + +namespace OpenGLRenderer +{ + +extern TexFilter_s TexFilter[]; + + +FSamplerManager::FSamplerManager() +{ + glGenSamplers(NUMSAMPLERS, mSamplers); + + glSamplerParameteri(mSamplers[CLAMP_X], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(mSamplers[CLAMP_Y], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(mSamplers[CLAMP_XY], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(mSamplers[CLAMP_XY], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(mSamplers[CLAMP_NOFILTER_X], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(mSamplers[CLAMP_NOFILTER_Y], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(mSamplers[CLAMP_NOFILTER_XY], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(mSamplers[CLAMP_NOFILTER_XY], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + for (int i = CLAMP_NOFILTER; i <= CLAMP_NOFILTER_XY; i++) + { + glSamplerParameteri(mSamplers[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glSamplerParameteri(mSamplers[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameterf(mSamplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); + + } + + glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameterf(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); + glSamplerParameterf(mSamplers[CLAMP_CAMTEX], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); + + SetTextureFilterMode(); + + + for (int i = 0; i < NUMSAMPLERS; i++) + { + FString name; + name.Format("mSamplers[%d]", i); + FGLDebug::LabelObject(GL_SAMPLER, mSamplers[i], name.GetChars()); + } +} + +FSamplerManager::~FSamplerManager() +{ + UnbindAll(); + glDeleteSamplers(NUMSAMPLERS, mSamplers); +} + +void FSamplerManager::UnbindAll() +{ + for (int i = 0; i < IHardwareTexture::MAX_TEXTURES; i++) + { + glBindSampler(i, 0); + } +} + +uint8_t FSamplerManager::Bind(int texunit, int num, int lastval) +{ + unsigned int samp = mSamplers[num]; + glBindSampler(texunit, samp); + return 255; +} + + +void FSamplerManager::SetTextureFilterMode() +{ + GLint bounds[IHardwareTexture::MAX_TEXTURES]; + + // Unbind all + for(int i = IHardwareTexture::MAX_TEXTURES-1; i >= 0; i--) + { + glActiveTexture(GL_TEXTURE0 + i); + glGetIntegerv(GL_SAMPLER_BINDING, &bounds[i]); + glBindSampler(i, 0); + } + + int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter() ? 0 : gl_texture_filter; + + for (int i = 0; i < 4; i++) + { + glSamplerParameteri(mSamplers[i], GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter); + glSamplerParameteri(mSamplers[i], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + glSamplerParameterf(mSamplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, filter > 0? gl_texture_filter_anisotropic : 1.0); + } + glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter); + glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + glSamplerParameteri(mSamplers[CLAMP_CAMTEX], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter); + glSamplerParameteri(mSamplers[CLAMP_CAMTEX], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + for(int i = 0; i < IHardwareTexture::MAX_TEXTURES; i++) + { + glBindSampler(i, bounds[i]); + } +} + + +} diff --git a/src/common/rendering/gl/gl_samplers.h b/src/common/rendering/gl/gl_samplers.h new file mode 100644 index 00000000000..109f910a5fe --- /dev/null +++ b/src/common/rendering/gl/gl_samplers.h @@ -0,0 +1,30 @@ +#ifndef __GL_SAMPLERS_H +#define __GL_SAMPLERS_H + +#include "gl_hwtexture.h" +#include "textures.h" + +namespace OpenGLRenderer +{ + + +class FSamplerManager +{ + unsigned int mSamplers[NUMSAMPLERS]; + + void UnbindAll(); + +public: + + FSamplerManager(); + ~FSamplerManager(); + + uint8_t Bind(int texunit, int num, int lastval); + void SetTextureFilterMode(); + + +}; + +} +#endif + diff --git a/src/common/rendering/gl/gl_shader.cpp b/src/common/rendering/gl/gl_shader.cpp new file mode 100644 index 00000000000..bafbf89b8eb --- /dev/null +++ b/src/common/rendering/gl/gl_shader.cpp @@ -0,0 +1,942 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2004-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_shader.cpp +** +** GLSL shader handling +** +*/ + +#include "gl_system.h" +#include "c_cvars.h" +#include "v_video.h" +#include "filesystem.h" +#include "engineerrors.h" +#include "cmdlib.h" +#include "md5.h" +#include "gl_shader.h" +#include "hw_shaderpatcher.h" +#include "shaderuniforms.h" +#include "hw_viewpointuniforms.h" +#include "hw_lightbuffer.h" +#include "hw_bonebuffer.h" +#include "i_specialpaths.h" +#include "printf.h" +#include "version.h" + +#include "gl_interface.h" +#include "gl_debug.h" +#include "matrix.h" +#include "gl_renderer.h" +#include +#include + +EXTERN_CVAR(Bool, r_skipmats) + +namespace OpenGLRenderer +{ + +struct ProgramBinary +{ + uint32_t format; + TArray data; +}; + +static const char *ShaderMagic = "ZDSC"; + +static std::map> ShaderCache; // Not a TMap because it doesn't support unique_ptr move semantics + +bool IsShaderCacheActive() +{ + static bool active = true; + static bool firstcall = true; + + if (firstcall) + { + const char *vendor = (const char *)glGetString(GL_VENDOR); + active = !(strstr(vendor, "Intel") == nullptr); + firstcall = false; + } + return active; +} + +static FString CalcProgramBinaryChecksum(const FString &vertex, const FString &fragment) +{ + const GLubyte *vendor = glGetString(GL_VENDOR); + const GLubyte *renderer = glGetString(GL_RENDERER); + const GLubyte *version = glGetString(GL_VERSION); + + uint8_t digest[16]; + MD5Context md5; + md5.Update(vendor, (unsigned int)strlen((const char*)vendor)); + md5.Update(renderer, (unsigned int)strlen((const char*)renderer)); + md5.Update(version, (unsigned int)strlen((const char*)version)); + md5.Update((const uint8_t *)vertex.GetChars(), (unsigned int)vertex.Len()); + md5.Update((const uint8_t *)fragment.GetChars(), (unsigned int)fragment.Len()); + md5.Final(digest); + + char hexdigest[33]; + for (int i = 0; i < 16; i++) + { + int v = digest[i] >> 4; + hexdigest[i * 2] = v < 10 ? ('0' + v) : ('a' + v - 10); + v = digest[i] & 15; + hexdigest[i * 2 + 1] = v < 10 ? ('0' + v) : ('a' + v - 10); + } + hexdigest[32] = 0; + return hexdigest; +} + +static FString CreateProgramCacheName(bool create) +{ + FString path = M_GetCachePath(create); + if (create) CreatePath(path.GetChars()); + path << "/shadercache.zdsc"; + return path; +} + +static void LoadShaders() +{ + static bool loaded = false; + if (loaded) + return; + loaded = true; + + try + { + FString path = CreateProgramCacheName(false); + FileReader fr; + if (!fr.OpenFile(path.GetChars())) + I_Error("Could not open shader file"); + + char magic[4]; + fr.Read(magic, 4); + if (memcmp(magic, ShaderMagic, 4) != 0) + I_Error("Not a shader cache file"); + + uint32_t count = fr.ReadUInt32(); + if (count > 512) + I_Error("Too many shaders cached"); + + for (uint32_t i = 0; i < count; i++) + { + char hexdigest[33]; + if (fr.Read(hexdigest, 32) != 32) + I_Error("Read error"); + hexdigest[32] = 0; + + std::unique_ptr binary(new ProgramBinary()); + binary->format = fr.ReadUInt32(); + uint32_t size = fr.ReadUInt32(); + if (size > 1024 * 1024) + I_Error("Shader too big, probably file corruption"); + + binary->data.Resize(size); + if (fr.Read(binary->data.Data(), binary->data.Size()) != binary->data.Size()) + I_Error("Read error"); + + ShaderCache[hexdigest] = std::move(binary); + } + } + catch (...) + { + ShaderCache.clear(); + } +} + +static void SaveShaders() +{ + FString path = CreateProgramCacheName(true); + std::unique_ptr fw(FileWriter::Open(path.GetChars())); + if (fw) + { + uint32_t count = (uint32_t)ShaderCache.size(); + fw->Write(ShaderMagic, 4); + fw->Write(&count, sizeof(uint32_t)); + for (const auto &it : ShaderCache) + { + uint32_t size = it.second->data.Size(); + fw->Write(it.first.GetChars(), 32); + fw->Write(&it.second->format, sizeof(uint32_t)); + fw->Write(&size, sizeof(uint32_t)); + fw->Write(it.second->data.Data(), it.second->data.Size()); + } + } +} + +TArray LoadCachedProgramBinary(const FString &vertex, const FString &fragment, uint32_t &binaryFormat) +{ + LoadShaders(); + + auto it = ShaderCache.find(CalcProgramBinaryChecksum(vertex, fragment)); + if (it != ShaderCache.end()) + { + binaryFormat = it->second->format; + return it->second->data; + } + else + { + binaryFormat = 0; + return {}; + } +} + +void SaveCachedProgramBinary(const FString &vertex, const FString &fragment, const TArray &binary, uint32_t binaryFormat) +{ + auto &entry = ShaderCache[CalcProgramBinaryChecksum(vertex, fragment)]; + entry.reset(new ProgramBinary()); + entry->format = binaryFormat; + entry->data = binary; + + SaveShaders(); +} + +bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * light_fragprog, const char * defines) +{ + static char buffer[10000]; + FString error; + + FString i_data = R"( + // these settings are actually pointless but there seem to be some old ATI drivers that fail to compile the shader without setting the precision here. + precision highp int; + precision highp float; + + // This must match the HWViewpointUniforms struct + layout(std140) uniform ViewpointUBO { + mat4 ProjectionMatrix; + mat4 ViewMatrix; + mat4 NormalViewMatrix; + + vec4 uCameraPos; + vec4 uClipLine; + + float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 + int uPalLightLevels; + int uViewHeight; // Software fuzz scaling + float uClipHeight; + float uClipHeightDirection; + int uShadowmapFilter; + + int uLightBlendMode; + }; + + uniform int uTextureMode; + uniform vec2 uClipSplit; + uniform float uAlphaThreshold; + + // colors + uniform vec4 uObjectColor; + uniform vec4 uObjectColor2; + uniform vec4 uDynLightColor; + uniform vec4 uAddColor; + uniform vec4 uTextureBlendColor; + uniform vec4 uTextureModulateColor; + uniform vec4 uTextureAddColor; + uniform vec4 uFogColor; + uniform float uDesaturationFactor; + uniform float uInterpolationFactor; + + // Glowing walls stuff + uniform vec4 uGlowTopPlane; + uniform vec4 uGlowTopColor; + uniform vec4 uGlowBottomPlane; + uniform vec4 uGlowBottomColor; + + uniform vec4 uGradientTopPlane; + uniform vec4 uGradientBottomPlane; + + uniform vec4 uSplitTopPlane; + uniform vec4 uSplitBottomPlane; + + uniform vec4 uDetailParms; + // Lighting + Fog + uniform vec4 uLightAttr; + #define uLightLevel uLightAttr.a + #define uFogDensity uLightAttr.b + #define uLightFactor uLightAttr.g + #define uLightDist uLightAttr.r + uniform int uFogEnabled; + + // dynamic lights + uniform int uLightIndex; + + // bone animation + uniform int uBoneIndexBase; + + // Blinn glossiness and specular level + uniform vec2 uSpecularMaterial; + + // matrices + uniform mat4 ModelMatrix; + uniform mat4 NormalModelMatrix; + uniform mat4 TextureMatrix; + + // light buffers + #ifdef SHADER_STORAGE_LIGHTS + layout(std430, binding = 1) buffer LightBufferSSO + { + vec4 lights[]; + }; + #elif defined NUM_UBO_LIGHTS + uniform LightBufferUBO + { + vec4 lights[NUM_UBO_LIGHTS]; + }; + #endif + + // bone matrix buffers + #ifdef SHADER_STORAGE_BONES + layout(std430, binding = 7) buffer BoneBufferSSO + { + mat4 bones[]; + }; + #elif defined NUM_UBO_BONES + uniform BoneBufferUBO + { + mat4 bones[NUM_UBO_BONES]; + }; + #endif + + // textures + uniform sampler2D tex; + uniform sampler2D ShadowMap; + uniform sampler2DArray LightMap; + uniform sampler2D texture2; + uniform sampler2D texture3; + uniform sampler2D texture4; + uniform sampler2D texture5; + uniform sampler2D texture6; + uniform sampler2D texture7; + uniform sampler2D texture8; + uniform sampler2D texture9; + uniform sampler2D texture10; + uniform sampler2D texture11; + uniform sampler2D texture12; + + // timer data + uniform float timer; + + // material types + #if defined(SPECULAR) + #define normaltexture texture2 + #define speculartexture texture3 + #define brighttexture texture4 + #define detailtexture texture5 + #define glowtexture texture6 + #elif defined(PBR) + #define normaltexture texture2 + #define metallictexture texture3 + #define roughnesstexture texture4 + #define aotexture texture5 + #define brighttexture texture6 + #define detailtexture texture7 + #define glowtexture texture8 + #else + #define brighttexture texture2 + #define detailtexture texture3 + #define glowtexture texture4 + #endif + + )"; + + +#ifdef __APPLE__ + // The noise functions are completely broken in macOS OpenGL drivers + // Garbage values are returned, and their infrequent usage causes extreme slowdown + // Also, these functions must return zeroes since GLSL 4.4 + i_data += "#define noise1(unused) 0.0\n"; + i_data += "#define noise2(unused) vec2(0)\n"; + i_data += "#define noise3(unused) vec3(0)\n"; + i_data += "#define noise4(unused) vec4(0)\n"; +#endif // __APPLE__ + +#ifdef NPOT_EMULATION + i_data += "#define NPOT_EMULATION\nuniform vec2 uNpotEmulation;\n"; +#endif + + int vp_lump = fileSystem.CheckNumForFullName(vert_prog_lump, 0); + if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump); + + int fp_lump = fileSystem.CheckNumForFullName(frag_prog_lump, 0); + if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump); + + + +// +// The following code uses GetChars on the strings to get rid of terminating 0 characters. Do not remove or the code may break! +// + FString vp_comb; + + assert(screen->mLights != NULL); + assert(screen->mBones != NULL); + + + if ((gl.flags & RFL_SHADER_STORAGE_BUFFER) && screen->allowSSBO()) + vp_comb << "#version 430 core\n#define SUPPORTS_SHADOWMAPS\n"; + else + vp_comb << "#version 330 core\n"; + + bool lightbuffertype = screen->mLights->GetBufferType(); + if (!lightbuffertype) + vp_comb.AppendFormat("#define NUM_UBO_LIGHTS %d\n#define NUM_UBO_BONES %d\n", screen->mLights->GetBlockSize(), screen->mBones->GetBlockSize()); + else + vp_comb << "#define SHADER_STORAGE_LIGHTS\n#define SHADER_STORAGE_BONES\n"; + + FString fp_comb = vp_comb; + vp_comb << defines << i_data.GetChars(); + fp_comb << "$placeholder$\n" << defines << i_data.GetChars(); + + vp_comb << "#line 1\n"; + fp_comb << "#line 1\n"; + + vp_comb << RemoveLayoutLocationDecl(GetStringFromLump(vp_lump), "out").GetChars() << "\n"; + fp_comb << RemoveLayoutLocationDecl(GetStringFromLump(fp_lump), "in").GetChars() << "\n"; + FString placeholder = "\n"; + + if (proc_prog_lump != NULL) + { + fp_comb << "#line 1\n"; + + if (*proc_prog_lump != '#') + { + int pp_lump = fileSystem.CheckNumForFullName(proc_prog_lump, 0); // if it's a core shader, ignore overrides by user mods. + if (pp_lump == -1) pp_lump = fileSystem.CheckNumForFullName(proc_prog_lump); + if (pp_lump == -1) I_Error("Unable to load '%s'", proc_prog_lump); + FString pp_data = GetStringFromLump(pp_lump); + + if (pp_data.IndexOf("ProcessMaterial") < 0 && pp_data.IndexOf("SetupMaterial") < 0) + { + // this looks like an old custom hardware shader. + + if (pp_data.IndexOf("GetTexCoord") >= 0) + { + int pl_lump = fileSystem.CheckNumForFullName("shaders/glsl/func_defaultmat2.fp", 0); + if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultmat2.fp"); + fp_comb << "\n" << GetStringFromLump(pl_lump); + } + else + { + int pl_lump = fileSystem.CheckNumForFullName("shaders/glsl/func_defaultmat.fp", 0); + if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultmat.fp"); + fp_comb << "\n" << GetStringFromLump(pl_lump); + + if (pp_data.IndexOf("ProcessTexel") < 0) + { + // this looks like an even older custom hardware shader. + // We need to replace the ProcessTexel call to make it work. + + fp_comb.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); + } + } + + if (pp_data.IndexOf("ProcessLight") >= 0) + { + // The ProcessLight signatured changed. Forward to the old one. + fp_comb << "\nvec4 ProcessLight(vec4 color);\n"; + fp_comb << "\nvec4 ProcessLight(Material material, vec4 color) { return ProcessLight(color); }\n"; + } + } + + fp_comb << RemoveLegacyUserUniforms(pp_data).GetChars(); + fp_comb.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders. + + if (pp_data.IndexOf("ProcessLight") < 0) + { + int pl_lump = fileSystem.CheckNumForFullName("shaders/glsl/func_defaultlight.fp", 0); + if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultlight.fp"); + fp_comb << "\n" << GetStringFromLump(pl_lump); + } + + // ProcessMaterial must be considered broken because it requires the user to fill in data they possibly cannot know all about. + if (pp_data.IndexOf("ProcessMaterial") >= 0 && pp_data.IndexOf("SetupMaterial") < 0) + { + // This reactivates the old logic and disables all features that cannot be supported with that method. + placeholder << "#define LEGACY_USER_SHADER\n"; + } + } + else + { + // Proc_prog_lump is not a lump name but the source itself (from generated shaders) + fp_comb << proc_prog_lump + 1; + } + } + fp_comb.Substitute("$placeholder$", placeholder); + + if (light_fragprog) + { + int pp_lump = fileSystem.CheckNumForFullName(light_fragprog, 0); + if (pp_lump == -1) I_Error("Unable to load '%s'", light_fragprog); + fp_comb << GetStringFromLump(pp_lump) << "\n"; + } + + if (gl.flags & RFL_NO_CLIP_PLANES) + { + // On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken. + // This will cause some glitches and regressions but is the only way to avoid total display garbage. + vp_comb.Substitute("gl_ClipDistance", "//"); + } + + hShader = glCreateProgram(); + FGLDebug::LabelObject(GL_PROGRAM, hShader, name); + + uint32_t binaryFormat = 0; + TArray binary; + if (IsShaderCacheActive()) + binary = LoadCachedProgramBinary(vp_comb, fp_comb, binaryFormat); + + bool linked = false; + if (binary.Size() > 0 && glProgramBinary) + { + glProgramBinary(hShader, binaryFormat, binary.Data(), binary.Size()); + GLint status = 0; + glGetProgramiv(hShader, GL_LINK_STATUS, &status); + linked = (status == GL_TRUE); + } + + if (!linked) + { + hVertProg = glCreateShader(GL_VERTEX_SHADER); + hFragProg = glCreateShader(GL_FRAGMENT_SHADER); + + FGLDebug::LabelObject(GL_SHADER, hVertProg, vert_prog_lump); + FGLDebug::LabelObject(GL_SHADER, hFragProg, frag_prog_lump); + + int vp_size = (int)vp_comb.Len(); + int fp_size = (int)fp_comb.Len(); + + const char *vp_ptr = vp_comb.GetChars(); + const char *fp_ptr = fp_comb.GetChars(); + + glShaderSource(hVertProg, 1, &vp_ptr, &vp_size); + glShaderSource(hFragProg, 1, &fp_ptr, &fp_size); + + glCompileShader(hVertProg); + glCompileShader(hFragProg); + + glAttachShader(hShader, hVertProg); + glAttachShader(hShader, hFragProg); + + glLinkProgram(hShader); + + glGetShaderInfoLog(hVertProg, 10000, NULL, buffer); + if (*buffer) + { + error << "Vertex shader:\n" << buffer << "\n"; + } + glGetShaderInfoLog(hFragProg, 10000, NULL, buffer); + if (*buffer) + { + error << "Fragment shader:\n" << buffer << "\n"; + } + + glGetProgramInfoLog(hShader, 10000, NULL, buffer); + if (*buffer) + { + error << "Linking:\n" << buffer << "\n"; + } + GLint status = 0; + glGetProgramiv(hShader, GL_LINK_STATUS, &status); + linked = (status == GL_TRUE); + if (!linked) + { + // only print message if there's an error. + I_Error("Init Shader '%s':\n%s\n", name, error.GetChars()); + } + else if (glProgramBinary && IsShaderCacheActive()) + { + int binaryLength = 0; + glGetProgramiv(hShader, GL_PROGRAM_BINARY_LENGTH, &binaryLength); + binary.Resize(binaryLength); + glGetProgramBinary(hShader, binary.Size(), &binaryLength, &binaryFormat, binary.Data()); + binary.Resize(binaryLength); + SaveCachedProgramBinary(vp_comb, fp_comb, binary, binaryFormat); + } + } + else + { + hVertProg = 0; + hFragProg = 0; + } + + muDesaturation.Init(hShader, "uDesaturationFactor"); + muFogEnabled.Init(hShader, "uFogEnabled"); + muTextureMode.Init(hShader, "uTextureMode"); + muLightParms.Init(hShader, "uLightAttr"); + muClipSplit.Init(hShader, "uClipSplit"); + muLightIndex.Init(hShader, "uLightIndex"); + muBoneIndexBase.Init(hShader, "uBoneIndexBase"); + muFogColor.Init(hShader, "uFogColor"); + muDynLightColor.Init(hShader, "uDynLightColor"); + muObjectColor.Init(hShader, "uObjectColor"); + muObjectColor2.Init(hShader, "uObjectColor2"); + muGlowBottomColor.Init(hShader, "uGlowBottomColor"); + muGlowTopColor.Init(hShader, "uGlowTopColor"); + muGlowBottomPlane.Init(hShader, "uGlowBottomPlane"); + muGlowTopPlane.Init(hShader, "uGlowTopPlane"); + muGradientBottomPlane.Init(hShader, "uGradientBottomPlane"); + muGradientTopPlane.Init(hShader, "uGradientTopPlane"); + muSplitBottomPlane.Init(hShader, "uSplitBottomPlane"); + muSplitTopPlane.Init(hShader, "uSplitTopPlane"); + muDetailParms.Init(hShader, "uDetailParms"); +#ifdef NPOT_EMULATION + muNpotEmulation.Init(hShader, "uNpotEmulation"); +#endif + muInterpolationFactor.Init(hShader, "uInterpolationFactor"); + muAlphaThreshold.Init(hShader, "uAlphaThreshold"); + muSpecularMaterial.Init(hShader, "uSpecularMaterial"); + muAddColor.Init(hShader, "uAddColor"); + muTextureAddColor.Init(hShader, "uTextureAddColor"); + muTextureModulateColor.Init(hShader, "uTextureModulateColor"); + muTextureBlendColor.Init(hShader, "uTextureBlendColor"); + muTimer.Init(hShader, "timer"); + + lights_index = glGetUniformLocation(hShader, "lights"); + modelmatrix_index = glGetUniformLocation(hShader, "ModelMatrix"); + texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix"); + normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix"); + + if (!lightbuffertype) + { + int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO"); + if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT); + + tempindex = glGetUniformBlockIndex(hShader, "BoneBufferUBO"); + if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, BONEBUF_BINDINGPOINT); + } + int tempindex = glGetUniformBlockIndex(hShader, "ViewpointUBO"); + if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, VIEWPOINT_BINDINGPOINT); + + glUseProgram(hShader); + + // set up other texture units (if needed by the shader) + for (int i = 2; i<16; i++) + { + char stringbuf[20]; + mysnprintf(stringbuf, 20, "texture%d", i); + tempindex = glGetUniformLocation(hShader, stringbuf); + if (tempindex != -1) glUniform1i(tempindex, i - 1); + } + + int shadowmapindex = glGetUniformLocation(hShader, "ShadowMap"); + if (shadowmapindex != -1) glUniform1i(shadowmapindex, 16); + + int lightmapindex = glGetUniformLocation(hShader, "LightMap"); + if (lightmapindex != -1) glUniform1i(lightmapindex, 17); + + glUseProgram(0); + return linked; +} + +//========================================================================== +// +// +// +//========================================================================== + +FShader::~FShader() +{ + glDeleteProgram(hShader); + if (hVertProg != 0) + glDeleteShader(hVertProg); + if (hFragProg != 0) + glDeleteShader(hFragProg); +} + + +//========================================================================== +// +// +// +//========================================================================== + +bool FShader::Bind() +{ + GLRenderer->mShaderManager->SetActiveShader(this); + return true; +} + +//========================================================================== +// +// Since all shaders are REQUIRED, any error here needs to be fatal +// +//========================================================================== + +FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType) +{ + FString defines; + if (shaderdefines) defines += shaderdefines; + // this can't be in the shader code due to ATI strangeness. + if (!usediscard) defines += "#define NO_ALPHATEST\n"; + if (passType == GBUFFER_PASS) defines += "#define GBUFFER_PASS\n"; + + FShader *shader = NULL; + try + { + shader = new FShader(ShaderName); + if (!shader->Load(ShaderName, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, LightModePath, defines.GetChars())) + { + I_FatalError("Unable to load shader %s\n", ShaderName); + } + } + catch(CRecoverableError &err) + { + if (shader != NULL) delete shader; + shader = NULL; + I_FatalError("Unable to load shader %s:\n%s\n", ShaderName, err.GetMessage()); + } + return shader; +} + +//========================================================================== +// +// +// +//========================================================================== + +FShaderManager::FShaderManager() +{ + for (int passType = 0; passType < MAX_PASS_TYPES; passType++) + mPassShaders.Push(new FShaderCollection((EPassType)passType)); +} + +bool FShaderManager::CompileNextShader() +{ + if (mPassShaders[mCompilePass]->CompileNextShader()) + { + mCompilePass++; + if (mCompilePass >= MAX_PASS_TYPES) + { + mCompilePass = -1; + return true; + } + } + return false; +} + +FShaderManager::~FShaderManager() +{ + glUseProgram(0); + mActiveShader = NULL; + + for (auto collection : mPassShaders) + delete collection; +} + +void FShaderManager::SetActiveShader(FShader *sh) +{ + if (mActiveShader != sh) + { + glUseProgram(sh!= NULL? sh->GetHandle() : 0); + mActiveShader = sh; + } +} + +FShader *FShaderManager::BindEffect(int effect, EPassType passType) +{ + if (passType < mPassShaders.Size() && mCompilePass == -1) + return mPassShaders[passType]->BindEffect(effect); + else + return nullptr; +} + +FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) +{ + if (mCompilePass > -1) + { + return mPassShaders[0]->Get(0, false); + } + if ((r_skipmats && eff >= 3 && eff <= 4)) + eff = 0; + + if (passType < mPassShaders.Size()) + return mPassShaders[passType]->Get(eff, alphateston); + else + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +FShaderCollection::FShaderCollection(EPassType passType) +{ + mPassType = passType; + mMaterialShaders.Clear(); + mMaterialShadersNAT.Clear(); + for (int i = 0; i < MAX_EFFECTS; i++) + { + mEffectShaders[i] = NULL; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FShaderCollection::~FShaderCollection() +{ + Clean(); +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FShaderCollection::CompileNextShader() +{ + int i = mCompileIndex; + if (mCompileState == 0) + { + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, mPassType); + mMaterialShaders.Push(shc); + mCompileIndex++; + if (defaultshaders[mCompileIndex].ShaderName == nullptr) + { + mCompileIndex = 0; + mCompileState++; + + } + } + else if (mCompileState == 1) + { + FShader *shc1 = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, mPassType); + mMaterialShadersNAT.Push(shc1); + mCompileIndex++; + if (mCompileIndex >= SHADER_NoTexture) + { + mCompileIndex = 0; + mCompileState++; + if (usershaders.Size() == 0) mCompileState++; + } + } + else if (mCompileState == 2) + { + FString name = ExtractFileBase(usershaders[i].shader.GetChars()); + FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines; + FShader *shc = Compile(name.GetChars(), usershaders[i].shader.GetChars(), defaultshaders[usershaders[i].shaderType].lightfunc, defines.GetChars(), true, mPassType); + mMaterialShaders.Push(shc); + mCompileIndex++; + if (mCompileIndex >= (int)usershaders.Size()) + { + mCompileIndex = 0; + mCompileState++; + } + } + else if (mCompileState == 3) + { + FShader *eff = new FShader(effectshaders[i].ShaderName); + if (!eff->Load(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1, + effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines)) + { + delete eff; + } + else mEffectShaders[i] = eff; + mCompileIndex++; + if (mCompileIndex >= MAX_EFFECTS) + { + return true; + } + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FShaderCollection::Clean() +{ + for (unsigned int i = 0; i < mMaterialShadersNAT.Size(); i++) + { + if (mMaterialShadersNAT[i] != NULL) delete mMaterialShadersNAT[i]; + } + for (unsigned int i = 0; i < mMaterialShaders.Size(); i++) + { + if (mMaterialShaders[i] != NULL) delete mMaterialShaders[i]; + } + for (int i = 0; i < MAX_EFFECTS; i++) + { + if (mEffectShaders[i] != NULL) delete mEffectShaders[i]; + mEffectShaders[i] = NULL; + } + mMaterialShaders.Clear(); + mMaterialShadersNAT.Clear(); +} + +//========================================================================== +// +// +// +//========================================================================== + +int FShaderCollection::Find(const char * shn) +{ + FName sfn = shn; + + for(unsigned int i=0;imName == sfn) + { + return i; + } + } + return -1; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FShader *FShaderCollection::BindEffect(int effect) +{ + if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL) + { + mEffectShaders[effect]->Bind(); + return mEffectShaders[effect]; + } + return NULL; +} + + +//========================================================================== +// +// +// +//========================================================================== + +void gl_DestroyUserShaders() +{ + // todo +} + +} diff --git a/src/rendering/gl/shaders/gl_shader.h b/src/common/rendering/gl/gl_shader.h similarity index 93% rename from src/rendering/gl/shaders/gl_shader.h rename to src/common/rendering/gl/gl_shader.h index e9d638446b0..b93299e08ae 100644 --- a/src/rendering/gl/shaders/gl_shader.h +++ b/src/common/rendering/gl/gl_shader.h @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -23,7 +23,7 @@ #ifndef __GL_SHADERS_H__ #define __GL_SHADERS_H__ -#include "gl/renderer/gl_renderstate.h" +#include "gl_renderstate.h" #include "name.h" extern bool gl_shaderactive; @@ -241,6 +241,7 @@ class FShader FBufferedUniform4f muLightParms; FBufferedUniform2f muClipSplit; FBufferedUniform1i muLightIndex; + FBufferedUniform1i muBoneIndexBase; FBufferedUniformPE muFogColor; FBufferedUniform4f muDynLightColor; FBufferedUniformPE muObjectColor; @@ -257,10 +258,14 @@ class FShader FUniform4f muGradientTopPlane; FUniform4f muSplitBottomPlane; FUniform4f muSplitTopPlane; + FUniform4f muDetailParms; FBufferedUniform1f muInterpolationFactor; FBufferedUniform1f muAlphaThreshold; FBufferedUniform2f muSpecularMaterial; FBufferedUniform1f muTimer; +#ifdef NPOT_EMULATION + FBufferedUniform2f muNpotEmulation; +#endif int lights_index; int modelmatrix_index; @@ -304,11 +309,13 @@ class FShaderManager FShader *BindEffect(int effect, EPassType passType); FShader *Get(unsigned int eff, bool alphateston, EPassType passType); -private: void SetActiveShader(FShader *sh); + bool CompileNextShader(); +private: FShader *mActiveShader = nullptr; TArray mPassShaders; + int mCompilePass = 0; friend class FShader; }; @@ -318,21 +325,23 @@ class FShaderCollection TArray mMaterialShaders; TArray mMaterialShadersNAT; FShader *mEffectShaders[MAX_EFFECTS]; + int mCompileState = 0, mCompileIndex = 0; + EPassType mPassType; void Clean(); - void CompileShaders(EPassType passType); - + public: FShaderCollection(EPassType passType); ~FShaderCollection(); FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType); int Find(const char *mame); + bool CompileNextShader(); FShader *BindEffect(int effect); FShader *Get(unsigned int eff, bool alphateston) { - // indices 0-2 match the warping modes, 3 is brightmap, 4 no texture, the following are custom - if (!alphateston && eff <= 3) + // indices 0-2 match the warping modes, 3 no texture, the following are custom + if (!alphateston && eff < SHADER_NoTexture && mCompileState == -1) { return mMaterialShadersNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway } diff --git a/src/rendering/gl/shaders/gl_shaderprogram.cpp b/src/common/rendering/gl/gl_shaderprogram.cpp similarity index 81% rename from src/rendering/gl/shaders/gl_shaderprogram.cpp rename to src/common/rendering/gl/gl_shaderprogram.cpp index 5cc48633210..1c4fd48a4df 100644 --- a/src/rendering/gl/shaders/gl_shaderprogram.cpp +++ b/src/common/rendering/gl/gl_shaderprogram.cpp @@ -1,38 +1,34 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2016 Magnus Norddahl -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// /* -** gl_shaderprogram.cpp -** GLSL shader program compile and link +** Postprocessing framework +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. ** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. */ -#include "gl_load/gl_system.h" +#include "gl_system.h" #include "v_video.h" -#include "gl_load/gl_interface.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "gl/system/gl_debug.h" -#include "gl/shaders/gl_shaderprogram.h" -#include "hwrenderer/utility/hw_shaderpatcher.h" -#include "w_wad.h" +#include "gl_interface.h" +#include "hw_cvars.h" +#include "gl_debug.h" +#include "gl_shaderprogram.h" +#include "hw_shaderpatcher.h" +#include "filesystem.h" +#include "printf.h" +#include "cmdlib.h" namespace OpenGLRenderer { @@ -91,9 +87,10 @@ void FShaderProgram::CreateShader(ShaderType type) void FShaderProgram::Compile(ShaderType type, const char *lumpName, const char *defines, int maxGlslVersion) { - int lump = Wads.CheckNumForFullName(lumpName); + int lump = fileSystem.CheckNumForFullName(lumpName); if (lump == -1) I_FatalError("Unable to load '%s'", lumpName); - FString code = Wads.ReadLump(lump).GetString().GetChars(); + FString code = GetStringFromLump(lump); + Compile(type, lumpName, code, defines, maxGlslVersion); } @@ -109,7 +106,7 @@ void FShaderProgram::CompileShader(ShaderType type) const auto &handle = mShaders[type]; - FGLDebug::LabelObject(GL_SHADER, handle, mShaderNames[type]); + FGLDebug::LabelObject(GL_SHADER, handle, mShaderNames[type].GetChars()); const FString &patchedCode = mShaderSources[type]; int lengths[1] = { (int)patchedCode.Len() }; @@ -188,7 +185,7 @@ void FShaderProgram::Link(const char *name) glUseProgram(mProgram); for (auto &uni : samplerstobind) { - auto index = glGetUniformLocation(mProgram, uni.first); + auto index = glGetUniformLocation(mProgram, uni.first.GetChars()); if (index >= 0) { glUniform1i(index, uni.second); @@ -268,7 +265,7 @@ FString FShaderProgram::PatchShader(ShaderType type, const FString &code, const // If we have 4.2, always use it because it adds important new syntax. if (maxGlslVersion < 420 && gl.glslversion >= 4.2f) maxGlslVersion = 420; - int shaderVersion = MIN((int)round(gl.glslversion * 10) * 10, maxGlslVersion); + int shaderVersion = min((int)round(gl.glslversion * 10) * 10, maxGlslVersion); patchedCode.AppendFormat("#version %d\n", shaderVersion); // TODO: Find some way to add extension requirements to the patching @@ -302,8 +299,8 @@ void FPresentShaderBase::Init(const char * vtx_shader_name, const char * program FString prolog = Uniforms.CreateDeclaration("Uniforms", PresentUniforms::Desc()); mShader.reset(new FShaderProgram()); - mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", prolog, 330); - mShader->Compile(FShaderProgram::Fragment, vtx_shader_name, prolog, 330); + mShader->Compile(FShaderProgram::Vertex, "shaders/pp/screenquad.vp", prolog.GetChars(), 330); + mShader->Compile(FShaderProgram::Fragment, vtx_shader_name, prolog.GetChars(), 330); mShader->Link(program_name); mShader->SetUniformBufferLocation(Uniforms.BindingPoint(), "Uniforms"); Uniforms.Init(); @@ -313,7 +310,7 @@ void FPresentShader::Bind() { if (!mShader) { - Init("shaders/glsl/present.fp", "shaders/glsl/present"); + Init("shaders/pp/present.fp", "shaders/pp/present"); } mShader->Bind(); } @@ -324,7 +321,7 @@ void FPresent3DCheckerShader::Bind() { if (!mShader) { - Init("shaders/glsl/present_checker3d.fp", "shaders/glsl/presentChecker3d"); + Init("shaders/pp/present_checker3d.fp", "shaders/pp/presentChecker3d"); } mShader->Bind(); } @@ -333,7 +330,7 @@ void FPresent3DColumnShader::Bind() { if (!mShader) { - Init("shaders/glsl/present_column3d.fp", "shaders/glsl/presentColumn3d"); + Init("shaders/pp/present_column3d.fp", "shaders/pp/presentColumn3d"); } mShader->Bind(); } @@ -342,7 +339,7 @@ void FPresent3DRowShader::Bind() { if (!mShader) { - Init("shaders/glsl/present_row3d.fp", "shaders/glsl/presentRow3d"); + Init("shaders/pp/present_row3d.fp", "shaders/pp/presentRow3d"); } mShader->Bind(); } @@ -356,8 +353,8 @@ void FShadowMapShader::Bind() FString prolog = Uniforms.CreateDeclaration("Uniforms", ShadowMapUniforms::Desc()); mShader.reset(new FShaderProgram()); - mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 430); - mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/shadowmap.fp", prolog, 430); + mShader->Compile(FShaderProgram::Vertex, "shaders/pp/screenquad.vp", "", 430); + mShader->Compile(FShaderProgram::Fragment, "shaders/pp/shadowmap.fp", prolog.GetChars(), 430); mShader->Link("shaders/glsl/shadowmap"); mShader->SetUniformBufferLocation(Uniforms.BindingPoint(), "Uniforms"); Uniforms.Init(); diff --git a/src/rendering/gl/shaders/gl_shaderprogram.h b/src/common/rendering/gl/gl_shaderprogram.h similarity index 98% rename from src/rendering/gl/shaders/gl_shaderprogram.h rename to src/common/rendering/gl/gl_shaderprogram.h index e073d62e046..90e25729743 100644 --- a/src/rendering/gl/shaders/gl_shaderprogram.h +++ b/src/common/rendering/gl/gl_shaderprogram.h @@ -1,7 +1,7 @@ #pragma once -#include "gl_load/gl_system.h" +#include "gl_system.h" #include "gl_shader.h" #include "hwrenderer/postprocessing/hw_postprocess.h" diff --git a/src/common/rendering/gl/gl_stereo3d.cpp b/src/common/rendering/gl/gl_stereo3d.cpp new file mode 100644 index 00000000000..c13914e2265 --- /dev/null +++ b/src/common/rendering/gl/gl_stereo3d.cpp @@ -0,0 +1,459 @@ +/* +** gl_stereo.cpp +** Stereoscopic 3D API +** +**--------------------------------------------------------------------------- +** Copyright 2015 Christopher Bruns +** Copyright 2016-2021 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +** +*/ + +#include "gl_system.h" +#include "gl_renderer.h" +#include "gl_renderbuffers.h" +#include "hw_vrmodes.h" +#include "gl_framebuffer.h" +#include "gl_postprocessstate.h" +#include "gl_framebuffer.h" +#include "gl_shaderprogram.h" +#include "gl_buffers.h" +#include "menu.h" + + +EXTERN_CVAR(Int, vr_mode) +EXTERN_CVAR(Float, vid_saturation) +EXTERN_CVAR(Float, vid_brightness) +EXTERN_CVAR(Float, vid_contrast) +EXTERN_CVAR(Int, gl_satformula) +EXTERN_CVAR(Int, gl_dither_bpc) + +#ifdef _WIN32 +EXTERN_CVAR(Bool, vr_enable_quadbuffered) +#endif + +void UpdateVRModes(bool considerQuadBuffered) +{ + FOptionValues** pVRModes = OptionValues.CheckKey("VRMode"); + if (pVRModes == nullptr) return; + + TArray& vals = (*pVRModes)->mValues; + TArray filteredValues; + int cnt = vals.Size(); + for (int i = 0; i < cnt; ++i) { + auto const& mode = vals[i]; + if (mode.Value == 7) { // Quad-buffered stereo +#ifdef _WIN32 + if (!vr_enable_quadbuffered) continue; +#else + continue; // Remove quad-buffered option on Mac and Linux +#endif + if (!considerQuadBuffered) continue; // Probably no compatible screen mode was found + } + filteredValues.Push(mode); + } + vals = filteredValues; +} + +namespace OpenGLRenderer +{ + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentAnaglyph(bool r, bool g, bool b) +{ + mBuffers->BindOutputFB(); + ClearBorders(); + + glColorMask(r, g, b, 1); + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + + glColorMask(!r, !g, !b, 1); + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + + glColorMask(1, 1, 1, 1); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentSideBySide(int vrmode) +{ + if (vrmode == VR_SIDEBYSIDEFULL || vrmode == VR_SIDEBYSIDESQUISHED) + { + mBuffers->BindOutputFB(); + ClearBorders(); + + // Compute screen regions to use for left and right eye views + int leftWidth = screen->mOutputLetterbox.width / 2; + int rightWidth = screen->mOutputLetterbox.width - leftWidth; + IntRect leftHalfScreen = screen->mOutputLetterbox; + leftHalfScreen.width = leftWidth; + IntRect rightHalfScreen = screen->mOutputLetterbox; + rightHalfScreen.width = rightWidth; + rightHalfScreen.left += leftWidth; + + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(leftHalfScreen, true); + + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(rightHalfScreen, true); + } + else if (vrmode == VR_SIDEBYSIDELETTERBOX) + { + mBuffers->BindOutputFB(); + screen->mOutputLetterbox.top = screen->mOutputLetterbox.height; + + ClearBorders(); + screen->mOutputLetterbox.top = 0; //reset so screenshots can be taken + + // Compute screen regions to use for left and right eye views + int leftWidth = screen->mOutputLetterbox.width / 2; + int rightWidth = screen->mOutputLetterbox.width - leftWidth; + //cut letterbox height in half + int height = screen->mOutputLetterbox.height / 2; + int top = height * .5; + IntRect leftHalfScreen = screen->mOutputLetterbox; + leftHalfScreen.width = leftWidth; + leftHalfScreen.height = height; + leftHalfScreen.top = top; + IntRect rightHalfScreen = screen->mOutputLetterbox; + rightHalfScreen.width = rightWidth; + rightHalfScreen.left += leftWidth; + //give it those cinematic black bars on top and bottom + rightHalfScreen.height = height; + rightHalfScreen.top = top; + + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(leftHalfScreen, true); + + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(rightHalfScreen, true); + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentTopBottom() +{ + mBuffers->BindOutputFB(); + ClearBorders(); + + // Compute screen regions to use for left and right eye views + int topHeight = screen->mOutputLetterbox.height / 2; + int bottomHeight = screen->mOutputLetterbox.height - topHeight; + IntRect topHalfScreen = screen->mOutputLetterbox; + topHalfScreen.height = topHeight; + topHalfScreen.top = topHeight; + IntRect bottomHalfScreen = screen->mOutputLetterbox; + bottomHalfScreen.height = bottomHeight; + bottomHalfScreen.top = 0; + + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(topHalfScreen, true); + + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(bottomHalfScreen, true); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::prepareInterleavedPresent(FPresentShaderBase& shader) +{ + mBuffers->BindOutputFB(); + ClearBorders(); + + + // Bind each eye texture, for composition in the shader + mBuffers->BindEyeTexture(0, 0); + mBuffers->BindEyeTexture(1, 1); + + glActiveTexture(GL_TEXTURE0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glActiveTexture(GL_TEXTURE1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + const IntRect& box = screen->mOutputLetterbox; + glViewport(box.left, box.top, box.width, box.height); + + shader.Bind(); + + if (framebuffer->IsHWGammaActive()) + { + shader.Uniforms->InvGamma = 1.0f; + shader.Uniforms->Contrast = 1.0f; + shader.Uniforms->Brightness = 0.0f; + shader.Uniforms->Saturation = 1.0f; + } + else + { + shader.Uniforms->InvGamma = 1.0f / clamp(vid_gamma, 0.1f, 4.f); + shader.Uniforms->Contrast = clamp(vid_contrast, 0.1f, 3.f); + shader.Uniforms->Brightness = clamp(vid_brightness, -0.8f, 0.8f); + shader.Uniforms->Saturation = clamp(vid_saturation, -15.0f, 15.0f); + shader.Uniforms->GrayFormula = static_cast(gl_satformula); + } + shader.Uniforms->HdrMode = 0; + shader.Uniforms->ColorScale = (gl_dither_bpc == -1) ? 255.0f : (float)((1 << gl_dither_bpc) - 1); + shader.Uniforms->Scale = { + screen->mScreenViewport.width / (float)mBuffers->GetWidth(), + screen->mScreenViewport.height / (float)mBuffers->GetHeight() + }; + shader.Uniforms->Offset = { 0.0f, 0.0f }; + shader.Uniforms.SetData(); + static_cast(shader.Uniforms.GetBuffer())->BindBase(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentColumnInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*mPresent3dColumnShader); + + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + + // Todo: + //auto clientoffset = screen->GetClientOffset(); + //auto windowHOffset = clientoffset.X % 2; + int windowHOffset = 0; + + mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset; + mPresent3dColumnShader->Uniforms.SetData(); + static_cast(mPresent3dColumnShader->Uniforms.GetBuffer())->BindBase(); + + RenderScreenQuad(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentRowInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*mPresent3dRowShader); + + // Todo: + //auto clientoffset = screen->GetClientOffset(); + //auto windowVOffset = clientoffset.Y % 2; + int windowVOffset = 0; + + mPresent3dRowShader->Uniforms->WindowPositionParity = + (windowVOffset + + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom + ) % 2; + + mPresent3dRowShader->Uniforms.SetData(); + static_cast(mPresent3dRowShader->Uniforms.GetBuffer())->BindBase(); + RenderScreenQuad(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentCheckerInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*mPresent3dCheckerShader); + + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + + //auto clientoffset = screen->GetClientOffset(); + //auto windowHOffset = clientoffset.X % 2; + //auto windowVOffset = clientoffset.Y % 2; + int windowHOffset = 0; + int windowVOffset = 0; + + mPresent3dCheckerShader->Uniforms->WindowPositionParity = + (windowVOffset + + windowHOffset + + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom + ) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset + + mPresent3dCheckerShader->Uniforms.SetData(); + static_cast(mPresent3dCheckerShader->Uniforms.GetBuffer())->BindBase(); + RenderScreenQuad(); +} + +//========================================================================== +// +// Sometimes the stereo render context is not ready immediately at start up +// +//========================================================================== + +bool FGLRenderer::QuadStereoCheckInitialRenderContextState() +{ + // Keep trying until we see at least one good OpenGL context to render to + bool bQuadStereoSupported = false; + bool bDecentContextWasFound = false; + int contextCheckCount = 0; + if ((!bDecentContextWasFound) && (contextCheckCount < 200)) + { + contextCheckCount += 1; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context + GLboolean supportsStereo, supportsBuffered; + glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered); + if (supportsBuffered) // Finally, a useful OpenGL context + { + // This block will be executed exactly ONCE during a game run + bDecentContextWasFound = true; // now we can stop checking every frame... + // Now check whether this context supports hardware stereo + glGetBooleanv(GL_STEREO, &supportsStereo); + bQuadStereoSupported = supportsStereo && supportsBuffered; + if (! bQuadStereoSupported) + UpdateVRModes(false); + } + } + return bQuadStereoSupported; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentQuadStereo() +{ + if (QuadStereoCheckInitialRenderContextState()) + { + mBuffers->BindOutputFB(); + + glDrawBuffer(GL_BACK_LEFT); + ClearBorders(); + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + + glDrawBuffer(GL_BACK_RIGHT); + ClearBorders(); + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + + glDrawBuffer(GL_BACK); + } + else + { + mBuffers->BindOutputFB(); + ClearBorders(); + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + } +} + + +void FGLRenderer::PresentStereo() +{ + auto vrmode = VRMode::GetVRMode(true); + const int eyeCount = vrmode->mEyeCount; + // Don't invalidate the bound framebuffer (..., false) + if (eyeCount > 1) + mBuffers->BlitToEyeTexture(mBuffers->CurrentEye(), false); + + switch (vr_mode) + { + default: + return; + + case VR_GREENMAGENTA: + PresentAnaglyph(false, true, false); + break; + + case VR_REDCYAN: + PresentAnaglyph(true, false, false); + break; + + case VR_AMBERBLUE: + PresentAnaglyph(true, true, false); + break; + + case VR_SIDEBYSIDEFULL: + case VR_SIDEBYSIDESQUISHED: + case VR_SIDEBYSIDELETTERBOX: + PresentSideBySide(vr_mode); + break; + + case VR_TOPBOTTOM: + PresentTopBottom(); + break; + + case VR_ROWINTERLEAVED: + PresentRowInterleaved(); + break; + + case VR_COLUMNINTERLEAVED: + PresentColumnInterleaved(); + break; + + case VR_CHECKERINTERLEAVED: + PresentCheckerInterleaved(); + break; + + case VR_QUADSTEREO: + PresentQuadStereo(); + break; + } +} + +} \ No newline at end of file diff --git a/src/rendering/gl_load/gl_extlist.txt b/src/common/rendering/gl_load/gl_extlist.txt similarity index 100% rename from src/rendering/gl_load/gl_extlist.txt rename to src/common/rendering/gl_load/gl_extlist.txt diff --git a/src/common/rendering/gl_load/gl_interface.cpp b/src/common/rendering/gl_load/gl_interface.cpp new file mode 100644 index 00000000000..f47e90b01f4 --- /dev/null +++ b/src/common/rendering/gl_load/gl_interface.cpp @@ -0,0 +1,251 @@ +/* +** gl_interface.cpp +** OpenGL system interface +** +**--------------------------------------------------------------------------- +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "gl_system.h" +#include "engineerrors.h" +#include "tarray.h" +#include "basics.h" +#include "m_argv.h" +#include "version.h" +#include "v_video.h" +#include "printf.h" +#include "gl_interface.h" + +static TArray m_Extensions; +RenderContext gl; +static double realglversion; +static bool bindless; + +//========================================================================== +// +// +// +//========================================================================== + +static void CollectExtensions() +{ + const char *extension; + + int max = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &max); + + // Use modern method to collect extensions + for (int i = 0; i < max; i++) + { + extension = (const char*)glGetStringi(GL_EXTENSIONS, i); + m_Extensions.Push(FString(extension)); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +static bool CheckExtension(const char *ext) +{ + for (unsigned int i = 0; i < m_Extensions.Size(); ++i) + { + if (m_Extensions[i].CompareNoCase(ext) == 0) return true; + } + + return false; +} + + + +//========================================================================== +// +// +// +//========================================================================== + +static void InitContext() +{ + gl.flags=0; +} + +//========================================================================== +// +// +// +//========================================================================== + +#define FUDGE_FUNC(name, ext) if (_ptrc_##name == NULL) _ptrc_##name = _ptrc_##name##ext; + + +void gl_LoadExtensions() +{ + int v = 0; + + InitContext(); + CollectExtensions(); + + const char *glversion = (const char*)glGetString(GL_VERSION); + + const char *version = Args->CheckValue("-glversion"); + realglversion = strtod(glversion, NULL); + + + if (version == NULL) + { + version = glversion; + } + else + { + double v1 = strtod(version, NULL); + if (v1 >= 3.0 && v1 < 3.3) + { + v1 = 3.3; // promote '3' to 3.3 to avoid falling back to the legacy path. + version = "3.3"; + } + if (realglversion < v1) version = glversion; + else Printf("Emulating OpenGL v %s\n", version); + } + + float gl_version = (float)strtod(version, NULL) + 0.01f; + + // Don't even start if it's lower than 2.0 or no framebuffers are available (The framebuffer extension is needed for glGenerateMipmapsEXT!) + if (gl_version < 3.3f) + { + I_FatalError("Unsupported OpenGL version.\nAt least OpenGL 3.3 is required to run " GAMENAME ".\n"); + } + + + // add 0.01 to account for roundoff errors making the number a tad smaller than the actual version + gl.glslversion = strtod((char*)glGetString(GL_SHADING_LANGUAGE_VERSION), NULL) + 0.01f; + + gl.vendorstring = (char*)glGetString(GL_VENDOR); + gl.modelstring = (char*)glGetString(GL_RENDERER); + + // first test for optional features + if (CheckExtension("GL_ARB_texture_compression")) gl.flags |= RFL_TEXTURE_COMPRESSION; + if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags |= RFL_TEXTURE_COMPRESSION_S3TC; + + if (gl_version < 4.f) + { +#ifdef _WIN32 + if (strstr(gl.vendorstring, "ATI Tech")) + { + gl.flags |= RFL_NO_CLIP_PLANES; // gl_ClipDistance is horribly broken on ATI GL3 drivers for Windows. + } +#endif + gl.glslversion = 3.31f; // Force GLSL down to 3.3. + } + else if (gl_version >= 4.5f) + { + // Assume that everything works without problems on GL 4.5 drivers where these things are core features. + gl.flags |= RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE; + + // Mesa implements shader storage only for fragment shaders. + // Just disable the feature there. The light buffer may just use a uniform buffer without any adverse effects. + glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &v); + if (v == 0) + gl.flags &= ~RFL_SHADER_STORAGE_BUFFER; + } + + + + if (gl_version >= 4.3f || CheckExtension("GL_ARB_invalidate_subdata")) gl.flags |= RFL_INVALIDATE_BUFFER; + if (gl_version >= 4.3f || CheckExtension("GL_KHR_debug")) gl.flags |= RFL_DEBUG; + + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &v); + gl.maxuniforms = v; + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &v); + gl.maxuniformblock = min(65536, v); + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v); + gl.uniformblockalignment = v; + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl.max_texturesize); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + bindless = CheckExtension("GL_ARB_bindless_texture"); +} + +//========================================================================== +// +// +// +//========================================================================== + +void gl_PrintStartupLog() +{ + int v = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &v); + + Printf ("GL_VENDOR: %s\n", glGetString(GL_VENDOR)); + Printf ("GL_RENDERER: %s\n", glGetString(GL_RENDERER)); + Printf ("GL_VERSION: %s (%s profile)\n", glGetString(GL_VERSION), (v & GL_CONTEXT_CORE_PROFILE_BIT)? "Core" : "Compatibility"); + Printf ("GL_SHADING_LANGUAGE_VERSION: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + Printf (PRINT_LOG, "GL_EXTENSIONS:"); + for (unsigned i = 0; i < m_Extensions.Size(); i++) + { + Printf(PRINT_LOG, " %s", m_Extensions[i].GetChars()); + } + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &v); + Printf("\nMax. texture size: %d\n", v); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &v); + Printf ("Max. texture units: %d\n", v); + glGetIntegerv(GL_MAX_VARYING_FLOATS, &v); + Printf ("Max. varying: %d\n", v); + + if (gl.flags & RFL_SHADER_STORAGE_BUFFER) + { + glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &v); + Printf("Max. combined shader storage blocks: %d\n", v); + glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &v); + Printf("Max. vertex shader storage blocks: %d\n", v); + } + else + { + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &v); + Printf("Max. uniform block size: %d\n", v); + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v); + Printf("Uniform block alignment: %d\n", v); + } +} + +void setGlVersion(double glv) +{ + realglversion = glv; +} + +std::pair gl_getInfo() +{ + // gl_ARB_bindless_texture is the closest we can get to determine Vulkan support from OpenGL. + // This isn't foolproof because Intel doesn't support it but for NVidia and AMD support of this extension means Vulkan support. + return std::make_pair(realglversion, bindless); +} diff --git a/src/rendering/gl_load/gl_interface.h b/src/common/rendering/gl_load/gl_interface.h similarity index 92% rename from src/rendering/gl_load/gl_interface.h rename to src/common/rendering/gl_load/gl_interface.h index f1f5801275e..a2e97db8d20 100644 --- a/src/rendering/gl_load/gl_interface.h +++ b/src/common/rendering/gl_load/gl_interface.h @@ -1,8 +1,6 @@ #ifndef R_RENDER #define R_RENDER -#include "basictypes.h" - struct RenderContext { unsigned int flags; diff --git a/src/rendering/gl_load/gl_load.c b/src/common/rendering/gl_load/gl_load.c similarity index 99% rename from src/rendering/gl_load/gl_load.c rename to src/common/rendering/gl_load/gl_load.c index 4bfbb78786f..d5ba4e49fef 100644 --- a/src/rendering/gl_load/gl_load.c +++ b/src/common/rendering/gl_load/gl_load.c @@ -9,7 +9,7 @@ static void* AppleGLGetProcAddress (const char *name) { static void* image = NULL; - + if (NULL == image) image = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY); @@ -61,16 +61,66 @@ static int TestPointer(const PROC pTest) ptrdiff_t iTest; if(!pTest) return 0; iTest = (ptrdiff_t)pTest; - + if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0; - + return 1; } +static HMODULE opengl32dll; +static HGLRC(WINAPI* createcontext)(HDC); +static BOOL(WINAPI* deletecontext)(HGLRC); +static BOOL(WINAPI* makecurrent)(HDC, HGLRC); +static PROC(WINAPI* getprocaddress)(LPCSTR name); +static void CheckOpenGL(void) +{ + if (opengl32dll == 0) + { + opengl32dll = LoadLibraryA("OpenGL32.DLL"); + if (opengl32dll != 0) + { + createcontext = (HGLRC(WINAPI*)(HDC)) GetProcAddress(opengl32dll, "wglCreateContext"); + deletecontext = (BOOL(WINAPI*)(HGLRC)) GetProcAddress(opengl32dll, "wglDeleteContext"); + makecurrent = (BOOL(WINAPI*)(HDC, HGLRC)) GetProcAddress(opengl32dll, "wglMakeCurrent"); + getprocaddress = (PROC(WINAPI*)(LPCSTR)) GetProcAddress(opengl32dll, "wglGetProcAddress"); + } + else + { + // Should this ever happen we have no choice but to hard abort, there is no good way to recover. + MessageBoxA(0, "OpenGL32.dll not found", "Fatal error", MB_OK | MB_ICONERROR | MB_TASKMODAL); + exit(3); + } + } +} + +HGLRC zd_wglCreateContext(HDC dc) +{ + CheckOpenGL(); + return createcontext(dc); +} + +BOOL zd_wglDeleteContext(HGLRC context) +{ + CheckOpenGL(); + return deletecontext(context); +} + +BOOL zd_wglMakeCurrent(HDC dc, HGLRC context) +{ + CheckOpenGL(); + return makecurrent(dc, context); +} + +PROC zd_wglGetProcAddress(LPCSTR name) +{ + CheckOpenGL(); + return getprocaddress(name); +} + static PROC WinGetProcAddress(const char *name) { HMODULE glMod = NULL; - PROC pFunc = wglGetProcAddress((LPCSTR)name); + PROC pFunc = zd_wglGetProcAddress((LPCSTR)name); if(TestPointer(pFunc)) { return pFunc; @@ -78,7 +128,7 @@ static PROC WinGetProcAddress(const char *name) glMod = GetModuleHandleA("OpenGL32.dll"); return (PROC)GetProcAddress(glMod, (LPCSTR)name); } - + #define IntGetProcAddress(name) WinGetProcAddress(name) #else #if defined(__APPLE__) @@ -3322,7 +3372,7 @@ static ogl_StrToExtMap *FindExtEntry(const char *extensionName) if(strcmp(extensionName, currLoc->extensionName) == 0) return currLoc; } - + return NULL; } @@ -3424,7 +3474,7 @@ int ogl_LoadFunctions() { int numFailed = 0; ClearExtensionVars(); - + _ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv"); if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED; _ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi"); @@ -3438,7 +3488,7 @@ int ogl_LoadFunctions() } numFailed = Load_Version_4_5(); - + if(numFailed == 0) return ogl_LOAD_SUCCEEDED; else @@ -3474,7 +3524,7 @@ int ogl_IsVersionGEQ(int majorVersion, int minorVersion) { if(g_major_version == 0) GetGLVersion(); - + if(majorVersion < g_major_version) return 1; if(majorVersion > g_major_version) return 0; if(minorVersion <= g_minor_version) return 1; diff --git a/src/rendering/gl_load/gl_load.h b/src/common/rendering/gl_load/gl_load.h similarity index 100% rename from src/rendering/gl_load/gl_load.h rename to src/common/rendering/gl_load/gl_load.h diff --git a/src/rendering/gl_load/gl_system.h b/src/common/rendering/gl_load/gl_system.h similarity index 95% rename from src/rendering/gl_load/gl_system.h rename to src/common/rendering/gl_load/gl_system.h index 0ad2f330349..6b40d73c034 100644 --- a/src/rendering/gl_load/gl_system.h +++ b/src/common/rendering/gl_load/gl_system.h @@ -14,7 +14,7 @@ #include #include #include -#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) #include #endif #include diff --git a/src/common/rendering/gles/glad/include/EGL/eglplatform.h b/src/common/rendering/gles/glad/include/EGL/eglplatform.h new file mode 100644 index 00000000000..d79f322e2dd --- /dev/null +++ b/src/common/rendering/gles/glad/include/EGL/eglplatform.h @@ -0,0 +1,125 @@ +#ifndef __eglplatform_h_ +#define __eglplatform_h_ + +/* +** Copyright (c) 2007-2013 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are 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 Materials. +** +** THE MATERIALS ARE 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 +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Platform-specific types and definitions for egl.h + * $Revision: 23432 $ on $Date: 2013-10-09 00:57:24 -0700 (Wed, 09 Oct 2013) $ + * + * Adopters may modify khrplatform.h and this file to suit their platform. + * You are encouraged to submit all modifications to the Khronos group so that + * they can be included in future versions of this file. Please submit changes + * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) + * by filing a bug against product "EGL" component "Registry". + */ + +#include + +/* Macros used in EGL function prototype declarations. + * + * EGL functions should be prototyped as: + * + * EGLAPI return-type EGLAPIENTRY eglFunction(arguments); + * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments); + * + * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h + */ + +#ifndef EGLAPI +#define EGLAPI KHRONOS_APICALL +#endif + +#ifndef EGLAPIENTRY +#define EGLAPIENTRY KHRONOS_APIENTRY +#endif +#define EGLAPIENTRYP EGLAPIENTRY* + +/* The types NativeDisplayType, NativeWindowType, and NativePixmapType + * are aliases of window-system-dependent types, such as X Display * or + * Windows Device Context. They must be defined in platform-specific + * code below. The EGL-prefixed versions of Native*Type are the same + * types, renamed in EGL 1.3 so all types in the API start with "EGL". + * + * Khronos STRONGLY RECOMMENDS that you use the default definitions + * provided below, since these changes affect both binary and source + * portability of applications using EGL running on different EGL + * implementations. + */ + +#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include + +typedef HDC EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +typedef HWND EGLNativeWindowType; + +#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ + +typedef int EGLNativeDisplayType; +typedef void *EGLNativeWindowType; +typedef void *EGLNativePixmapType; + +#elif defined(__ANDROID__) || defined(ANDROID) + +#include + +struct egl_native_pixmap_t; + +typedef struct ANativeWindow* EGLNativeWindowType; +typedef struct egl_native_pixmap_t* EGLNativePixmapType; +typedef void* EGLNativeDisplayType; + +#elif defined(__unix__) || defined(__APPLE__) + +/* X11 (tentative) */ +#include +#include + +typedef Display *EGLNativeDisplayType; +typedef Pixmap EGLNativePixmapType; +typedef Window EGLNativeWindowType; + +#else +#error "Platform not recognized" +#endif + +/* EGL 1.2 types, renamed for consistency in EGL 1.3 */ +typedef EGLNativeDisplayType NativeDisplayType; +typedef EGLNativePixmapType NativePixmapType; +typedef EGLNativeWindowType NativeWindowType; + + +/* Define EGLint. This must be a signed integral type large enough to contain + * all legal attribute names and values passed into and out of EGL, whether + * their type is boolean, bitmask, enumerant (symbolic constant), integer, + * handle, or other. While in general a 32-bit integer will suffice, if + * handles are 64 bit types, then EGLint should be defined as a signed 64-bit + * integer type. + */ +typedef khronos_int32_t EGLint; + +#endif /* __eglplatform_h */ diff --git a/src/common/rendering/gles/glad/include/KHR/khrplatform.h b/src/common/rendering/gles/glad/include/KHR/khrplatform.h new file mode 100644 index 00000000000..dd22d927018 --- /dev/null +++ b/src/common/rendering/gles/glad/include/KHR/khrplatform.h @@ -0,0 +1,290 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are 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 Materials. +** +** THE MATERIALS ARE 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 +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/src/common/rendering/gles/glad/include/glad/glad.h b/src/common/rendering/gles/glad/include/glad/glad.h new file mode 100644 index 00000000000..212864bc1ab --- /dev/null +++ b/src/common/rendering/gles/glad/include/glad/glad.h @@ -0,0 +1,874 @@ +/* + + OpenGL ES loader generated by glad 0.1.34 on Fri Mar 19 17:04:24 2021. + + Language/Generator: C/C++ + Specification: gl + APIs: gles2=2.0 + Profile: compatibility + Extensions: + + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="compatibility" --api="gles2=2.0" --generator="c" --spec="gl" --extensions="" + Online: + https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gles2%3D2.0 +*/ + + +#ifndef __glad_h_ +#define __glad_h_ + +#ifdef __gl2_h_ +#error OpenGL ES 2 header already included, remove this include, glad already provides it +#endif +#define __gl2_h_ + +#ifdef __gl3_h_ +#error OpenGL ES 3 header already included, remove this include, glad already provides it +#endif +#define __gl3_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define APIENTRY __stdcall +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY APIENTRY +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct gladGLversionStruct { + int major; + int minor; +}; + +typedef void* (* GLADloadproc)(const char *name); + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(_WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif + +GLAPI struct gladGLversionStruct GLVersion; +GLAPI int gladLoadGLES2Loader(GLADloadproc); + +#include +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +typedef khronos_intptr_t GLintptr; +typedef khronos_intptr_t GLintptrARB; +typedef khronos_ssize_t GLsizeiptr; +typedef khronos_ssize_t GLsizeiptrARB; +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (APIENTRY *GLVULKANPROCNV)(void); +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_FUNC_ADD 0x8006 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_COLOR 0x8005 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_STREAM_DRAW 0x88E0 +#define GL_STATIC_DRAW 0x88E4 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_CULL_FACE 0x0B44 +#define GL_BLEND 0x0BE2 +#define GL_DITHER 0x0BD0 +#define GL_STENCIL_TEST 0x0B90 +#define GL_DEPTH_TEST 0x0B71 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_LINE_WIDTH 0x0B21 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VIEWPORT 0x0BA2 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_FIXED 0x140C +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_SHADER_TYPE 0x8B4F +#define GL_DELETE_STATUS 0x8B80 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_INVERT 0x150A +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TEXTURE 0x1702 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_COMPILE_STATUS 0x8B81 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGB565 0x8D62 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_NONE 0 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#ifndef GL_ES_VERSION_2_0 +#define GL_ES_VERSION_2_0 1 +GLAPI int GLAD_GL_ES_VERSION_2_0; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d); +GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf; +#define glClearDepthf glad_glClearDepthf +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef; +#define glDepthRangef glad_glDepthRangef +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLFINISHPROC)(void); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(void); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; +#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void); +GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; +#define glReleaseShaderCompiler glad_glReleaseShaderCompiler +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length); +GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary; +#define glShaderBinary glad_glShaderBinary +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/rendering/gles/glad/include/glad/glad_egl.h b/src/common/rendering/gles/glad/include/glad/glad_egl.h new file mode 100644 index 00000000000..1c47f7cede6 --- /dev/null +++ b/src/common/rendering/gles/glad/include/glad/glad_egl.h @@ -0,0 +1,267 @@ +/* + + EGL loader generated by glad 0.1.34 on Sat Feb 20 22:54:45 2021. + + Language/Generator: C/C++ + Specification: egl + APIs: egl=1.4 + Profile: - + Extensions: + + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --api="egl=1.4" --generator="c" --spec="egl" --extensions="" + Online: + https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.4 +*/ + + +#ifndef __glad_egl_h_ + +#ifdef __egl_h_ +#error EGL header already included, remove this include, glad already provides it +#endif + +#define __glad_egl_h_ +#define __egl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define APIENTRY __stdcall +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (* GLADloadproc)(const char *name); + +GLAPI int gladLoadEGL(void); +GLAPI int gladLoadEGLLoader(GLADloadproc); + +#include +#include + +#define EGL_CAST(X,V) (X)(V) + +struct AHardwareBuffer; +struct wl_buffer; +struct wl_display; +struct wl_resource; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef intptr_t EGLAttribKHR; +typedef intptr_t EGLAttrib; +typedef void *EGLClientBuffer; +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDeviceEXT; +typedef void *EGLDisplay; +typedef void *EGLImage; +typedef void *EGLImageKHR; +typedef void *EGLLabelKHR; +typedef void *EGLObjectKHR; +typedef void *EGLOutputLayerEXT; +typedef void *EGLOutputPortEXT; +typedef void *EGLStreamKHR; +typedef void *EGLSurface; +typedef void *EGLSync; +typedef void *EGLSyncKHR; +typedef void *EGLSyncNV; +typedef void (*__eglMustCastToProperFunctionPointerType)(void); +typedef khronos_utime_nanoseconds_t EGLTimeKHR; +typedef khronos_utime_nanoseconds_t EGLTime; +typedef khronos_utime_nanoseconds_t EGLTimeNV; +typedef khronos_utime_nanoseconds_t EGLuint64NV; +typedef khronos_uint64_t EGLuint64KHR; +typedef khronos_stime_nanoseconds_t EGLnsecsANDROID; +typedef int EGLNativeFileDescriptorKHR; +typedef khronos_ssize_t EGLsizeiANDROID; +typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize); +typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize); +struct EGLClientPixmapHI { + void *pData; + EGLint iWidth; + EGLint iHeight; + EGLint iStride; +}; +typedef void (APIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message); +#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC +#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC +#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC +#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +#define EGL_BLUE_SIZE 0x3022 +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_CORE_NATIVE_ENGINE 0x305B +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_DONT_CARE EGL_CAST(EGLint,-1) +#define EGL_DRAW 0x3059 +#define EGL_EXTENSIONS 0x3055 +#define EGL_FALSE 0 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_HEIGHT 0x3056 +#define EGL_LARGEST_PBUFFER 0x3058 +#define EGL_LEVEL 0x3029 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +#define EGL_NONE 0x3038 +#define EGL_NON_CONFORMANT_CONFIG 0x3051 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0) +#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0) +#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0) +#define EGL_PBUFFER_BIT 0x0001 +#define EGL_PIXMAP_BIT 0x0002 +#define EGL_READ 0x305A +#define EGL_RED_SIZE 0x3024 +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SLOW_CONFIG 0x3050 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_SUCCESS 0x3000 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 +#define EGL_TRANSPARENT_RGB 0x3052 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRUE 1 +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_WIDTH 0x3057 +#define EGL_WINDOW_BIT 0x0004 +#define EGL_BACK_BUFFER 0x3084 +#define EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define EGL_CONTEXT_LOST 0x300E +#define EGL_MIN_SWAP_INTERVAL 0x303B +#define EGL_MAX_SWAP_INTERVAL 0x303C +#define EGL_MIPMAP_TEXTURE 0x3082 +#define EGL_MIPMAP_LEVEL 0x3083 +#define EGL_NO_TEXTURE 0x305C +#define EGL_TEXTURE_2D 0x305F +#define EGL_TEXTURE_FORMAT 0x3080 +#define EGL_TEXTURE_RGB 0x305D +#define EGL_TEXTURE_RGBA 0x305E +#define EGL_TEXTURE_TARGET 0x3081 +#define EGL_ALPHA_FORMAT 0x3088 +#define EGL_ALPHA_FORMAT_NONPRE 0x308B +#define EGL_ALPHA_FORMAT_PRE 0x308C +#define EGL_ALPHA_MASK_SIZE 0x303E +#define EGL_BUFFER_PRESERVED 0x3094 +#define EGL_BUFFER_DESTROYED 0x3095 +#define EGL_CLIENT_APIS 0x308D +#define EGL_COLORSPACE 0x3087 +#define EGL_COLORSPACE_sRGB 0x3089 +#define EGL_COLORSPACE_LINEAR 0x308A +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_CONTEXT_CLIENT_TYPE 0x3097 +#define EGL_DISPLAY_SCALING 10000 +#define EGL_HORIZONTAL_RESOLUTION 0x3090 +#define EGL_LUMINANCE_BUFFER 0x308F +#define EGL_LUMINANCE_SIZE 0x303D +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENVG_BIT 0x0002 +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_OPENVG_API 0x30A1 +#define EGL_OPENVG_IMAGE 0x3096 +#define EGL_PIXEL_ASPECT_RATIO 0x3092 +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_RENDER_BUFFER 0x3086 +#define EGL_RGB_BUFFER 0x308E +#define EGL_SINGLE_BUFFER 0x3085 +#define EGL_SWAP_BEHAVIOR 0x3093 +#define EGL_UNKNOWN EGL_CAST(EGLint,-1) +#define EGL_VERTICAL_RESOLUTION 0x3091 +#define EGL_CONFORMANT 0x3042 +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define EGL_MATCH_NATIVE_PIXMAP 0x3041 +#define EGL_OPENGL_ES2_BIT 0x0004 +#define EGL_VG_ALPHA_FORMAT 0x3088 +#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B +#define EGL_VG_ALPHA_FORMAT_PRE 0x308C +#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 +#define EGL_VG_COLORSPACE 0x3087 +#define EGL_VG_COLORSPACE_sRGB 0x3089 +#define EGL_VG_COLORSPACE_LINEAR 0x308A +#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 +#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0) +#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 +#define EGL_MULTISAMPLE_RESOLVE 0x3099 +#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A +#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B +#define EGL_OPENGL_API 0x30A2 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 +EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); +EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); +EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); +EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list); +EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx); +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface); +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); +EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); +EGLDisplay eglGetCurrentDisplay(void); +EGLSurface eglGetCurrentSurface(EGLint readdraw); +EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id); +EGLint eglGetError(void); +__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname); +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); +const char *eglQueryString(EGLDisplay dpy, EGLint name); +EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); +EGLBoolean eglTerminate(EGLDisplay dpy); +EGLBoolean eglWaitGL(void); +EGLBoolean eglWaitNative(EGLint engine); +EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval); +EGLBoolean eglBindAPI(EGLenum api); +EGLenum eglQueryAPI(void); +EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list); +EGLBoolean eglReleaseThread(void); +EGLBoolean eglWaitClient(void); +EGLContext eglGetCurrentContext(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/rendering/gles/glad/src/glad.c b/src/common/rendering/gles/glad/src/glad.c new file mode 100644 index 00000000000..6653cc3f63a --- /dev/null +++ b/src/common/rendering/gles/glad/src/glad.c @@ -0,0 +1,475 @@ +/* + + OpenGL ES loader generated by glad 0.1.34 on Fri Mar 19 17:04:24 2021. + + Language/Generator: C/C++ + Specification: gl + APIs: gles2=2.0 + Profile: compatibility + Extensions: + + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="compatibility" --api="gles2=2.0" --generator="c" --spec="gl" --extensions="" + Online: + https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gles2%3D2.0 +*/ + +#include +#include +#include +#include + +struct gladGLversionStruct GLVersion = { 0, 0 }; + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define _GLAD_IS_SOME_NEW_VERSION 1 +#endif + +static int max_loaded_major; +static int max_loaded_minor; + +static const char *exts = NULL; +static int num_exts_i = 0; +static char **exts_i = NULL; + +static int get_exts(void) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + exts = (const char *)glGetString(GL_EXTENSIONS); +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + unsigned int index; + + num_exts_i = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); + } + + if (exts_i == NULL) { + return 0; + } + + for(index = 0; index < (unsigned)num_exts_i; index++) { + const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp); + + char *local_str = (char*)malloc((len+1) * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char)); + } + exts_i[index] = local_str; + } + } +#endif + return 1; +} + +static void free_exts(void) { + if (exts_i != NULL) { + int index; + for(index = 0; index < num_exts_i; index++) { + free((char *)exts_i[index]); + } + free((void *)exts_i); + exts_i = NULL; + } +} + +static int has_ext(const char *ext) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + if(exts_i == NULL) return 0; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + + if(exts_i[index] != NULL && strcmp(e, ext) == 0) { + return 1; + } + } + } +#endif + + return 0; +} +int GLAD_GL_ES_VERSION_2_0 = 0; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +static void load_GL_ES_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_ES_VERSION_2_0) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); +} +static int find_extensionsGLES2(void) { + if (!get_exts()) return 0; + (void)&has_ext; + free_exts(); + return 1; +} + +static void find_coreGLES2(void) { + + /* Thank you @elmindreda + * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; + GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + if (GLVersion.major > 2 || (GLVersion.major >= 2 && GLVersion.minor >= 0)) { + max_loaded_major = 2; + max_loaded_minor = 0; + } +} + +int gladLoadGLES2Loader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGLES2(); + load_GL_ES_VERSION_2_0(load); + + if (!find_extensionsGLES2()) return 0; + return GLVersion.major != 0 || GLVersion.minor != 0; +} + diff --git a/src/common/rendering/gles/glad/src/glad_egl.c b/src/common/rendering/gles/glad/src/glad_egl.c new file mode 100644 index 00000000000..8d074404109 --- /dev/null +++ b/src/common/rendering/gles/glad/src/glad_egl.c @@ -0,0 +1,45 @@ +/* + + EGL loader generated by glad 0.1.34 on Sat Feb 20 22:54:45 2021. + + Language/Generator: C/C++ + Specification: egl + APIs: egl=1.4 + Profile: - + Extensions: + + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --api="egl=1.4" --generator="c" --spec="egl" --extensions="" + Online: + https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.4 +*/ + +#include +#include +#include +#include + +int gladLoadEGL(void) { + return gladLoadEGLLoader((GLADloadproc)eglGetProcAddress); +} + +static int find_extensionsEGL(void) { + return 1; +} + +static void find_coreEGL(void) { +} + +int gladLoadEGLLoader(GLADloadproc load) { + (void) load; + find_coreEGL(); + + if (!find_extensionsEGL()) return 0; + return 1; +} + diff --git a/src/common/rendering/gles/gles_buffers.cpp b/src/common/rendering/gles/gles_buffers.cpp new file mode 100644 index 00000000000..7f56f737f6b --- /dev/null +++ b/src/common/rendering/gles/gles_buffers.cpp @@ -0,0 +1,343 @@ +/* +** gl_buffers.cpp +** Low level vertex buffer class +** +**--------------------------------------------------------------------------- +** Copyright 2018-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +**/ + +#include +#include "gles_system.h" +#include "gles_buffers.h" +#include "gles_renderstate.h" +#include "v_video.h" +#include "flatvertices.h" + +namespace OpenGLESRenderer +{ + +//========================================================================== +// +// basic buffer implementation +// +//========================================================================== + +static inline void InvalidateBufferState() +{ + gl_RenderState.ResetVertexBuffer(); // force rebinding of buffers on next Apply call. +} + +GLBuffer::GLBuffer(int usetype) + : mUseType(usetype) +{ + if ((usetype == GL_ARRAY_BUFFER) || (usetype == GL_ELEMENT_ARRAY_BUFFER)) + { + glGenBuffers(1, &mBufferId); + isData = false; + } + else + { + isData = true; + } +} + +GLBuffer::~GLBuffer() +{ + if (mBufferId != 0) + { + if (gles.useMappedBuffers) + { + glBindBuffer(mUseType, mBufferId); + glUnmapBuffer(mUseType); + } + glBindBuffer(mUseType, 0); + glDeleteBuffers(1, &mBufferId); + } + + if (memory) + delete[] memory; +} + +void GLBuffer::Bind() +{ + if (!isData) + { + glBindBuffer(mUseType, mBufferId); + } +} + + +void GLBuffer::SetData(size_t size, const void* data, BufferUsageType usage) +{ + bool staticdata = (usage == BufferUsageType::Static || usage == BufferUsageType::Mappable); + if (isData || !gles.useMappedBuffers) + { + if (memory) + delete[] memory; + + memory = (char*)(new uint64_t[size / 8 + 16]); + + if (data) + memcpy(memory, data, size); + } + + if (!isData) + { + Bind(); + glBufferData(mUseType, size, data, staticdata ? GL_STATIC_DRAW : GL_STREAM_DRAW); + } + + if (!isData && gles.useMappedBuffers) + { + map = 0; + } + else + { + map = memory; + } + + buffersize = size; + InvalidateBufferState(); +} + +void GLBuffer::SetSubData(size_t offset, size_t size, const void *data) +{ + Bind(); + + memcpy(memory + offset, data, size); + + if (!isData) + { + glBufferSubData(mUseType, offset, size, data); + } +} + +void GLBuffer::Upload(size_t start, size_t size) +{ + if (!gles.useMappedBuffers) + { + Bind(); + + if(size) + glBufferSubData(mUseType, start, size, memory + start); + } +} + +void GLBuffer::Map() +{ + if (!isData && gles.useMappedBuffers) + { + Bind(); + map = (FFlatVertex*)glMapBufferRange(mUseType, 0, buffersize, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + } + else + { + map = memory; + } + InvalidateBufferState(); +} + +void GLBuffer::Unmap() +{ + if (!isData && gles.useMappedBuffers) + { + Bind(); + glUnmapBuffer(mUseType); + InvalidateBufferState(); + } +} + +void *GLBuffer::Lock(unsigned int size) +{ + // This initializes this buffer as a static object with no data. + SetData(size, nullptr, BufferUsageType::Mappable); + if (!isData && gles.useMappedBuffers) + { + return glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + } + else + { + return map; + } +} + +void GLBuffer::Unlock() +{ + if (!isData) + { + if (gles.useMappedBuffers) + { + Bind(); + glUnmapBuffer(mUseType); + InvalidateBufferState(); + } + else + { + Bind(); + glBufferData(mUseType, buffersize, map, GL_STATIC_DRAW); + InvalidateBufferState(); + } + } +} + +void GLBuffer::Resize(size_t newsize) +{ + if (newsize > buffersize) + { + if (isData) + { + // Create new bigger memory + char* memoryNew = (char*)(new uint64_t[newsize / 8 + 16]); + + // Copy old data + memcpy(memoryNew, memory, buffersize); + + // Delete old memory + delete[] memory; + + memory = memoryNew; + + buffersize = newsize; + } + else + { + // TODO + } + } +} + +void GLBuffer::GPUDropSync() +{ + if (gles.glesMode > GLES_MODE_GLES && gles.useMappedBuffers && glFenceSync && glDeleteSync) + { + if (mGLSync != NULL) + { + glDeleteSync(mGLSync); + } + + mGLSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } +} + +void GLBuffer::GPUWaitSync() +{ + if (gles.glesMode > GLES_MODE_GLES && gles.useMappedBuffers && glDeleteSync && glClientWaitSync) + { + GLenum status = glClientWaitSync(mGLSync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000 * 1000 * 50); // Wait for a max of 50ms... + + if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED) + { + //Printf("Error on glClientWaitSync: %d\n", status); + } + + glDeleteSync(mGLSync); + + mGLSync = NULL; + } +} + + +//=========================================================================== +// +// Vertex buffer implementation +// +//=========================================================================== + +void GLVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) +{ + static int VFmtToGLFmt[] = { GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT_2_10_10_10_REV, GL_UNSIGNED_BYTE }; // TODO Fix last entry GL_INT_2_10_10_10_REV, normals for models will be broken + static uint8_t VFmtToSize[] = {4, 3, 2, 1, 4, 4, 4}; + static bool VFmtToNormalize[] = { false, false, false, false, true, true, false }; + static bool VFmtToIntegerType[] = { false, false, false, false, false, false, true }; + + mStride = stride; + mNumBindingPoints = numBindingPoints; + + for(int i = 0; i < numAttributes; i++) + { + if (attrs[i].location >= 0 && attrs[i].location < VATTR_MAX) + { + auto & attrinf = mAttributeInfo[attrs[i].location]; + attrinf.format = VFmtToGLFmt[attrs[i].format]; + attrinf.size = VFmtToSize[attrs[i].format]; + attrinf.offset = attrs[i].offset; + attrinf.bindingpoint = attrs[i].binding; + attrinf.normalize = VFmtToNormalize[attrs[i].format]; + attrinf.integerType = VFmtToIntegerType[attrs[i].format]; + } + } +} + +void GLVertexBuffer::Bind(int *offsets) +{ + int i = 0; + + // This is what gets called from RenderState.Apply. It shouldn't be called anywhere else if the render state is in use + GLBuffer::Bind(); + for(auto &attrinf : mAttributeInfo) + { + if (attrinf.size == 0) + { + glDisableVertexAttribArray(i); + } + else + { + glEnableVertexAttribArray(i); + size_t ofs = offsets == nullptr ? attrinf.offset : attrinf.offset + mStride * offsets[attrinf.bindingpoint]; + if (!attrinf.integerType) + glVertexAttribPointer(i, attrinf.size, attrinf.format, attrinf.normalize, (GLsizei)mStride, (void*)(intptr_t)ofs); + else + { + if (gles.glesMode >= GLES_MODE_OGL3) + glVertexAttribIPointer(i, attrinf.size, attrinf.format, (GLsizei)mStride, (void*)(intptr_t)ofs); + } + } + i++; + } +} + +void GLDataBuffer::BindRange(FRenderState *state, size_t start, size_t length) +{ + if (mBindingPoint == 3)// VIEWPOINT_BINDINGPOINT + { + static_cast(state)->ApplyViewport(memory + start); + } +} + +void GLDataBuffer::BindBase() +{ + +} + + +GLVertexBuffer::GLVertexBuffer() : GLBuffer(GL_ARRAY_BUFFER) {} +GLIndexBuffer::GLIndexBuffer() : GLBuffer(GL_ELEMENT_ARRAY_BUFFER) {} +GLDataBuffer::GLDataBuffer(int bindingpoint, bool is_ssbo) : GLBuffer(0), mBindingPoint(bindingpoint) {} + +} \ No newline at end of file diff --git a/src/common/rendering/gles/gles_buffers.h b/src/common/rendering/gles/gles_buffers.h new file mode 100644 index 00000000000..50156ef7ee5 --- /dev/null +++ b/src/common/rendering/gles/gles_buffers.h @@ -0,0 +1,84 @@ +#pragma once + +#include "buffers.h" + +#ifdef _MSC_VER +// silence bogus warning C4250: 'GLVertexBuffer': inherits 'GLBuffer::GLBuffer::SetData' via dominance +// According to internet infos, the warning is erroneously emitted in this case. +#pragma warning(disable:4250) +#endif + +namespace OpenGLESRenderer +{ + +class GLBuffer : virtual public IBuffer +{ +protected: + const int mUseType; + unsigned int mBufferId = 0; + int mAllocationSize = 0; + bool mPersistent = false; + bool nomap = true; + GLsync mGLSync = 0; + + bool isData = false; + char *memory = nullptr; + + GLBuffer(int usetype); + ~GLBuffer(); + void SetData(size_t size, const void *data, BufferUsageType usage) override; + void SetSubData(size_t offset, size_t size, const void *data) override; + void Map() override; + void Unmap() override; + void Resize(size_t newsize) override; + void *Lock(unsigned int size) override; + void Unlock() override; + + void GPUDropSync(); + void GPUWaitSync(); +public: + void Bind(); + void Upload(size_t start, size_t end); +}; + + +class GLVertexBuffer : public IVertexBuffer, public GLBuffer +{ + // If this could use the modern (since GL 4.3) binding system, things would be simpler... :( + struct GLVertexBufferAttribute + { + int bindingpoint; + int format; + bool normalize; + bool integerType; + int size; + int offset; + }; + + int mNumBindingPoints; + GLVertexBufferAttribute mAttributeInfo[VATTR_MAX] = {}; // Thanks to OpenGL's state system this needs to contain info about every attribute that may ever be in use throughout the entire renderer. + size_t mStride = 0; + +public: + GLVertexBuffer(); + void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override; + void Bind(int *offsets); +}; + +class GLIndexBuffer : public IIndexBuffer, public GLBuffer +{ +public: + + GLIndexBuffer(); +}; + +class GLDataBuffer : public IDataBuffer, public GLBuffer +{ + int mBindingPoint; +public: + GLDataBuffer(int bindingpoint, bool is_ssbo); + void BindRange(FRenderState* state, size_t start, size_t length); + void BindBase(); +}; + +} \ No newline at end of file diff --git a/src/common/rendering/gles/gles_framebuffer.cpp b/src/common/rendering/gles/gles_framebuffer.cpp new file mode 100644 index 00000000000..bbade7896fd --- /dev/null +++ b/src/common/rendering/gles/gles_framebuffer.cpp @@ -0,0 +1,498 @@ +/* +** gl_framebuffer.cpp +** Implementation of the non-hardware specific parts of the +** OpenGL frame buffer +** +**--------------------------------------------------------------------------- +** Copyright 2010-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "gles_system.h" +#include "v_video.h" +#include "m_png.h" + +#include "i_time.h" + +#include "gles_framebuffer.h" +#include "gles_renderer.h" +#include "gles_samplers.h" +#include "gles_renderbuffers.h" +#include "hw_clock.h" +#include "hw_vrmodes.h" +#include "hw_skydome.h" +#include "hw_viewpointbuffer.h" +#include "hw_lightbuffer.h" +#include "hw_bonebuffer.h" +#include "gles_shaderprogram.h" +#include "r_videoscale.h" +#include "gles_buffers.h" +#include "gles_postprocessstate.h" +#include "v_draw.h" +#include "printf.h" +#include "gles_hwtexture.h" + +#include "flatvertices.h" +#include "hw_cvars.h" + +EXTERN_CVAR (Bool, vid_vsync) +EXTERN_CVAR(Int, gl_tonemap) +EXTERN_CVAR(Bool, cl_capfps) +EXTERN_CVAR(Int, gl_pipeline_depth); + +EXTERN_CVAR(Bool, gl_sort_textures); + +extern bool vid_hdr_active; + +namespace OpenGLESRenderer +{ + FGLRenderer *GLRenderer; + +//========================================================================== +// +// +// +//========================================================================== + +OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, bool fullscreen) : + Super(hMonitor, fullscreen) +{ + // SetVSync needs to be at the very top to workaround a bug in Nvidia's OpenGL driver. + // If wglSwapIntervalEXT is called after glBindFramebuffer in a frame the setting is not changed! + Super::SetVSync(vid_vsync); + FHardwareTexture::InitGlobalState(); + + // Make sure all global variables tracking OpenGL context state are reset.. + gl_RenderState.Reset(); + + GLRenderer = nullptr; +} + +OpenGLFrameBuffer::~OpenGLFrameBuffer() +{ + PPResource::ResetAll(); + + if (mVertexData != nullptr) delete mVertexData; + if (mSkyData != nullptr) delete mSkyData; + if (mViewpoints != nullptr) delete mViewpoints; + if (mLights != nullptr) delete mLights; + if (mBones != nullptr) delete mBones; + mShadowMap.Reset(); + + if (GLRenderer) + { + delete GLRenderer; + GLRenderer = nullptr; + } +} + +//========================================================================== +// +// Initializes the GL renderer +// +//========================================================================== + +void OpenGLFrameBuffer::InitializeState() +{ + static bool first=true; + + mPipelineNbr = gl_pipeline_depth == 0? min(4, HW_MAX_PIPELINE_BUFFERS) : clamp(*gl_pipeline_depth, 1, HW_MAX_PIPELINE_BUFFERS); + mPipelineType = 1; + + InitGLES(); + + // Move some state to the framebuffer object for easier access. + hwcaps = gles.flags; + vendorstring = gles.vendorstring; + + glDepthFunc(GL_LESS); + + glEnable(GL_DITHER); + glDisable(GL_CULL_FACE); + glDisable(GL_POLYGON_OFFSET_FILL); + + glEnable(GL_BLEND); + if (gles.depthClampAvailable) glEnable(GL_DEPTH_CLAMP); + + glDisable(GL_DEPTH_TEST); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + glClearDepthf(1.0f); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetViewportRects(nullptr); + + mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight(), mPipelineNbr); + mSkyData = new FSkyVertexBuffer; + mViewpoints = new HWViewpointBuffer(mPipelineNbr); + mLights = new FLightBuffer(mPipelineNbr); + mBones = new BoneBuffer(mPipelineNbr); + GLRenderer = new FGLRenderer(this); + GLRenderer->Initialize(GetWidth(), GetHeight()); + static_cast(mLights->GetBuffer())->BindBase(); + static_cast(mBones->GetBuffer())->BindBase(); +} + +//========================================================================== +// +// Updates the screen +// +//========================================================================== + +void OpenGLFrameBuffer::Update() +{ + twoD.Reset(); + Flush3D.Reset(); + + Flush3D.Clock(); + GLRenderer->Flush(); + Flush3D.Unclock(); + + Swap(); + Super::Update(); +} + +void OpenGLFrameBuffer::CopyScreenToBuffer(int width, int height, uint8_t* scr) +{ + IntRect bounds; + bounds.left = 0; + bounds.top = 0; + bounds.width = width; + bounds.height = height; + GLRenderer->CopyToBackbuffer(&bounds, false); + + // strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers + glFinish(); + glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, scr); +} + +//=========================================================================== +// +// Camera texture rendering +// +//=========================================================================== + +void OpenGLFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::function renderFunc) +{ + GLRenderer->StartOffscreen(); + GLRenderer->BindToFrameBuffer(tex); + + IntRect bounds; + bounds.left = bounds.top = 0; + bounds.width = FHardwareTexture::GetTexDimension(tex->GetWidth()); + bounds.height = FHardwareTexture::GetTexDimension(tex->GetHeight()); + + renderFunc(bounds); + GLRenderer->EndOffscreen(); + + tex->SetUpdated(true); + static_cast(screen)->camtexcount++; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +const char* OpenGLFrameBuffer::DeviceName() const +{ + return gles.modelstring; +} + +//========================================================================== +// +// Swap the buffers +// +//========================================================================== + + +void OpenGLFrameBuffer::Swap() +{ + + Finish.Reset(); + Finish.Clock(); + + mVertexData->DropSync(); + + FPSLimit(); + SwapBuffers(); + + mVertexData->NextPipelineBuffer(); + mVertexData->WaitSync(); + + RenderState()->SetVertexBuffer(screen->mVertexData); // Needed for Raze because it does not reset it + + Finish.Unclock(); + camtexcount = 0; + FHardwareTexture::UnbindAll(); + gl_RenderState.ClearLastMaterial(); +} + +//========================================================================== +// +// Enable/disable vertical sync +// +//========================================================================== + +void OpenGLFrameBuffer::SetVSync(bool vsync) +{ + Super::SetVSync(vsync); +} + +//=========================================================================== +// +// +//=========================================================================== + +void OpenGLFrameBuffer::SetTextureFilterMode() +{ + if (GLRenderer != nullptr && GLRenderer->mSamplerManager != nullptr) GLRenderer->mSamplerManager->SetTextureFilterMode(); +} + +IHardwareTexture *OpenGLFrameBuffer::CreateHardwareTexture(int numchannels) +{ + return new FHardwareTexture(numchannels); +} + +void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) +{ + if (mat->Source()->GetUseType() == ETextureType::SWCanvas) return; + + int numLayers = mat->NumLayers(); + MaterialLayerInfo* layer; + auto base = static_cast(mat->GetLayer(0, translation, &layer)); + + if (base->BindOrCreate(layer->layerTexture, 0, CLAMP_NONE, translation, layer->scaleFlags)) + { + for (int i = 1; i < numLayers; i++) + { + auto systex = static_cast(mat->GetLayer(i, 0, &layer)); + systex->BindOrCreate(layer->layerTexture, i, CLAMP_NONE, 0, layer->scaleFlags); + } + } + // unbind everything. + FHardwareTexture::UnbindAll(); + gl_RenderState.ClearLastMaterial(); +} + +IVertexBuffer *OpenGLFrameBuffer::CreateVertexBuffer() +{ + return new GLVertexBuffer; +} + +IIndexBuffer *OpenGLFrameBuffer::CreateIndexBuffer() +{ + return new GLIndexBuffer; +} + +IDataBuffer *OpenGLFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) +{ + return new GLDataBuffer(bindingpoint, ssbo); +} + + +void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds) +{ + Super::SetViewportRects(bounds); + if (!bounds) + { + auto vrmode = VRMode::GetVRMode(true); + vrmode->AdjustViewport(this); + } +} + + +FRenderState* OpenGLFrameBuffer::RenderState() +{ + return &gl_RenderState; +} + + +void OpenGLFrameBuffer::FirstEye() +{ + //GLRenderer->mBuffers->CurrentEye() = 0; // always begin at zero, in case eye count changed +} + +void OpenGLFrameBuffer::NextEye(int eyecount) +{ + //GLRenderer->mBuffers->NextEye(eyecount); +} + +void OpenGLFrameBuffer::SetSceneRenderTarget(bool useSSAO) +{ +#ifndef NO_RENDER_BUFFER + GLRenderer->mBuffers->BindSceneFB(useSSAO); +#endif +} + + + +void OpenGLFrameBuffer::WaitForCommands(bool finish) +{ + glFinish(); +} + + +//=========================================================================== +// +// +// +//=========================================================================== + +void OpenGLFrameBuffer::BeginFrame() +{ + SetViewportRects(nullptr); + mViewpoints->Clear(); + if (GLRenderer != nullptr) + GLRenderer->BeginFrame(); +} + +//=========================================================================== +// +// Takes a screenshot +// +//=========================================================================== + +TArray OpenGLFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) +{ + const auto &viewport = mOutputLetterbox; + + // Grab what is in the back buffer. + // We cannot rely on SCREENWIDTH/HEIGHT here because the output may have been scaled. + TArray pixels; + pixels.Resize(viewport.width * viewport.height * 3); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(viewport.left, viewport.top, viewport.width, viewport.height, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]); + glPixelStorei(GL_PACK_ALIGNMENT, 4); + + // Copy to screenshot buffer: + int w = SCREENWIDTH; + int h = SCREENHEIGHT; + + TArray ScreenshotBuffer(w * h * 3, true); + + float rcpWidth = 1.0f / w; + float rcpHeight = 1.0f / h; + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++) + { + float u = (x + 0.5f) * rcpWidth; + float v = (y + 0.5f) * rcpHeight; + int sx = u * viewport.width; + int sy = v * viewport.height; + int sindex = (sx + sy * viewport.width) * 3; + int dindex = (x + (h - y - 1) * w) * 3; + ScreenshotBuffer[dindex] = pixels[sindex]; + ScreenshotBuffer[dindex + 1] = pixels[sindex + 1]; + ScreenshotBuffer[dindex + 2] = pixels[sindex + 2]; + } + } + + pitch = w * 3; + color_type = SS_RGB; + + // Screenshot should not use gamma correction if it was already applied to rendered image + gamma = 1; + if (vid_hdr_active && vid_fullscreen) + gamma *= 2.2f; + return ScreenshotBuffer; +} + +//=========================================================================== +// +// 2D drawing +// +//=========================================================================== + +void OpenGLFrameBuffer::Draw2D() +{ + if (GLRenderer != nullptr) + { + GLRenderer->mBuffers->BindCurrentFB(); + ::Draw2D(twod, gl_RenderState); + } +} + +void OpenGLFrameBuffer::PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) +{ + //if (!swscene) GLRenderer->mBuffers->BlitSceneToTexture(); // Copy the resulting scene to the current post process texture + GLRenderer->PostProcessScene(fixedcm, flash, afterBloomDrawEndScene2D); +} + +//========================================================================== +// +// OpenGLFrameBuffer :: WipeStartScreen +// +// Called before the current screen has started rendering. This needs to +// save what was drawn the previous frame so that it can be animated into +// what gets drawn this frame. +// +//========================================================================== + +FTexture *OpenGLFrameBuffer::WipeStartScreen() +{ + const auto &viewport = screen->mScreenViewport; + + auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); + tex->GetSystemTexture()->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, "WipeStartScreen"); + glFinish(); + static_cast(tex->GetSystemTexture())->Bind(0, false); + + GLRenderer->mBuffers->BindCurrentFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: WipeEndScreen +// +// The screen we want to animate to has just been drawn. +// +//========================================================================== + +FTexture *OpenGLFrameBuffer::WipeEndScreen() +{ + GLRenderer->Flush(); + const auto &viewport = screen->mScreenViewport; + auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); + tex->GetSystemTexture()->CreateTexture(NULL, viewport.width, viewport.height, 0, false, "WipeEndScreen"); + glFinish(); + static_cast(tex->GetSystemTexture())->Bind(0, false); + GLRenderer->mBuffers->BindCurrentFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; +} + +} diff --git a/src/common/rendering/gles/gles_framebuffer.h b/src/common/rendering/gles/gles_framebuffer.h new file mode 100644 index 00000000000..3cf32f179d5 --- /dev/null +++ b/src/common/rendering/gles/gles_framebuffer.h @@ -0,0 +1,73 @@ +#ifndef __GLES_FRAMEBUFFER +#define __GLES_FRAMEBUFFER + +#include "gl_sysfb.h" +#include "m_png.h" + +#include + +namespace OpenGLESRenderer +{ + +class FHardwareTexture; + +class OpenGLFrameBuffer : public SystemGLFrameBuffer +{ + typedef SystemGLFrameBuffer Super; + + void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) override; + +public: + + explicit OpenGLFrameBuffer() {} + OpenGLFrameBuffer(void *hMonitor, bool fullscreen) ; + ~OpenGLFrameBuffer(); + int Backend() override { return 0; } + + void InitializeState() override; + void Update() override; + int GetShaderCount() override { return 0; } + + void FirstEye() override; + void NextEye(int eyecount) override; + void SetSceneRenderTarget(bool useSSAO) override; + void WaitForCommands(bool finish) override; + void CopyScreenToBuffer(int width, int height, uint8_t* buffer) override; + bool FlipSavePic() const override { return true; } + + FRenderState* RenderState() override; + + const char* DeviceName() const override; + void SetTextureFilterMode() override; + IHardwareTexture *CreateHardwareTexture(int numchannels) override; + void PrecacheMaterial(FMaterial *mat, int translation) override; + void BeginFrame() override; + void SetViewportRects(IntRect *bounds) override; + IVertexBuffer *CreateVertexBuffer() override; + IIndexBuffer *CreateIndexBuffer() override; + IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override; + + // Retrieves a buffer containing image data for a screenshot. + // Hint: Pitch can be negative for upside-down images, in which case buffer + // points to the last row in the buffer, which will be the first row output. + virtual TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override; + + void Swap(); + bool IsHWGammaActive() const { return HWGammaActive; } + + void SetVSync(bool vsync) override; + + void Draw2D() override; + void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) override; + + bool HWGammaActive = false; // Are we using hardware or software gamma? + + FTexture *WipeStartScreen() override; + FTexture *WipeEndScreen() override; + + int camtexcount = 0; +}; + +} + +#endif //__GL_FRAMEBUFFER diff --git a/src/common/rendering/gles/gles_hwtexture.cpp b/src/common/rendering/gles/gles_hwtexture.cpp new file mode 100644 index 00000000000..3f07c65d676 --- /dev/null +++ b/src/common/rendering/gles/gles_hwtexture.cpp @@ -0,0 +1,348 @@ +/* +** gl_hwtexture.cpp +** GL texture abstraction +** +**--------------------------------------------------------------------------- +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "gles_system.h" + +#include "c_cvars.h" +#include "hw_material.h" + +#include "hw_cvars.h" +#include "gles_renderer.h" +#include "gles_samplers.h" +#include "gles_renderstate.h" +#include "gles_hwtexture.h" + +namespace OpenGLESRenderer +{ + + +TexFilter_s TexFilter[] = { + {GL_NEAREST, GL_NEAREST, false}, + {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, true}, + {GL_LINEAR, GL_LINEAR, false}, + {GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, true}, + {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, true}, + {GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, true}, + {GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST, true}, +}; + +//=========================================================================== +// +// Static texture data +// +//=========================================================================== +unsigned int FHardwareTexture::lastbound[FHardwareTexture::MAX_TEXTURES]; + +//=========================================================================== +// +// Loads the texture image into the hardware +// +// NOTE: For some strange reason I was unable to find the source buffer +// should be one line higher than the actual texture. I got extremely +// strange crashes deep inside the GL driver when I didn't do it! +// +//=========================================================================== + +unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) +{ + int rh,rw; + int texformat = GL_RGBA;// TexFormat[gl_texture_format]; + bool deletebuffer=false; + + // When running in SW mode buffer will be null, so set it to the texBuffer already created + // There could be other use cases I do not know about which means this is a bad idea.. + if (buffer == nullptr) + buffer = texBuffer; + + bool firstCall = glTexID == 0; + if (firstCall) + { + glGenTextures(1, &glTexID); + } + + int textureBinding = UINT_MAX; + if (texunit == -1) glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); + if (texunit > 0) glActiveTexture(GL_TEXTURE0+texunit); + if (texunit >= 0) lastbound[texunit] = glTexID; + glBindTexture(GL_TEXTURE_2D, glTexID); + + + rw = GetTexDimension(w); + rh = GetTexDimension(h); + + if (!buffer) + { + // The texture must at least be initialized if no data is present. + mipmapped = false; + buffer=(unsigned char *)calloc(4,rw * (rh+1)); + deletebuffer=true; + //texheight=-h; + } + else + { + if (rw < w || rh < h) + { + // The texture is larger than what the hardware can handle so scale it down. + unsigned char * scaledbuffer=(unsigned char *)calloc(4,rw * (rh+1)); + if (scaledbuffer) + { + Resize(w, h, rw, rh, buffer, scaledbuffer); + deletebuffer=true; + buffer=scaledbuffer; + } + } + + + } + // store the physical size. + + int sourcetype; + + if (gles.glesMode == GLES_MODE_GLES) + { + if (glTextureBytes == 1) + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + sourcetype = GL_ALPHA; + texformat = GL_ALPHA; + } + else + { + sourcetype = GL_BGRA; // These two must be the same + texformat = GL_BGRA; + } + } + else + { + if (glTextureBytes == 1) //Use Red channel instread becuase Alpha does not work in OpenGL, swizzle later + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + sourcetype = GL_RED; + texformat = GL_RED; + } + else + { + sourcetype = GL_BGRA; + texformat = GL_RGBA; + } + } + + glTexImage2D(GL_TEXTURE_2D, 0, texformat, rw, rh, 0, sourcetype, GL_UNSIGNED_BYTE, buffer); + + if (gles.glesMode != GLES_MODE_GLES) + { + // The shader is using the alpha channel instead of red, this work on GLES but not on GL + // So the texture uses GL_RED and this swizzels the red channel into the alpha channel + if (glTextureBytes == 1) + { + GLint swizzleMask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + } + + if (deletebuffer && buffer) free(buffer); + + if (mipmap && TexFilter[gl_texture_filter].mipmapping) + { + glGenerateMipmap(GL_TEXTURE_2D); + mipmapped = true; + } + + if (texunit > 0) glActiveTexture(GL_TEXTURE0); + else if (texunit == -1) glBindTexture(GL_TEXTURE_2D, textureBinding); + return glTexID; +} + + +void FHardwareTexture::AllocateBuffer(int w, int h, int texelsize) +{ + if (texelsize < 1 || texelsize > 4) texelsize = 4; + glTextureBytes = texelsize; + bufferpitch = w; + + if (texBuffer) + delete[] texBuffer; + + texBuffer = new uint8_t[(w * h) * texelsize]; + return; +} + +uint8_t* FHardwareTexture::MapBuffer() +{ + return texBuffer; +} + +//=========================================================================== +// +// Destroys the texture +// +//=========================================================================== +FHardwareTexture::~FHardwareTexture() +{ + if (glTexID != 0) glDeleteTextures(1, &glTexID); + + if (texBuffer) + delete[] texBuffer; +} + + +//=========================================================================== +// +// Binds this patch +// +//=========================================================================== +unsigned int FHardwareTexture::Bind(int texunit, bool needmipmap) +{ + if (glTexID != 0) + { + if (lastbound[texunit] == glTexID) return glTexID; + lastbound[texunit] = glTexID; + if (texunit != 0) glActiveTexture(GL_TEXTURE0 + texunit); + glBindTexture(GL_TEXTURE_2D, glTexID); + // Check if we need mipmaps on a texture that was creted without them. + if (needmipmap && !mipmapped && TexFilter[gl_texture_filter].mipmapping) + { + glGenerateMipmap(GL_TEXTURE_2D); + mipmapped = true; + } + if (texunit != 0) glActiveTexture(GL_TEXTURE0); + return glTexID; + } + return 0; +} + +void FHardwareTexture::Unbind(int texunit) +{ + if (lastbound[texunit] != 0) + { + if (texunit != 0) glActiveTexture(GL_TEXTURE0+texunit); + glBindTexture(GL_TEXTURE_2D, 0); + if (texunit != 0) glActiveTexture(GL_TEXTURE0); + lastbound[texunit] = 0; + } +} + +void FHardwareTexture::UnbindAll() +{ + for(int texunit = 0; texunit < 16; texunit++) + { + Unbind(texunit); + } +} + +//=========================================================================== +// +// Creates a depth buffer for this texture +// +//=========================================================================== + +int FHardwareTexture::GetDepthBuffer(int width, int height) +{ + if (glDepthID == 0) + { + glGenRenderbuffers(1, &glDepthID); + glBindRenderbuffer(GL_RENDERBUFFER, glDepthID); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, + GetTexDimension(width), GetTexDimension(height)); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + return glDepthID; +} + + +//=========================================================================== +// +// Binds this texture's surfaces to the current framrbuffer +// +//=========================================================================== + +void FHardwareTexture::BindToFrameBuffer(int width, int height) +{ + width = GetTexDimension(width); + height = GetTexDimension(height); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexID, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, GetDepthBuffer(width, height)); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, GetDepthBuffer(width, height)); +} + + +//=========================================================================== +// +// Binds a texture to the renderer +// +//=========================================================================== + +bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, int translation, int flags) +{ + bool needmipmap = (clampmode <= CLAMP_XY) && !forcenofilter; + + // Bind it to the system. + if (!Bind(texunit, needmipmap)) + { + if (flags & CTF_Indexed) + { + glTextureBytes = 1; + forcenofilter = true; + needmipmap = false; + } + int w = 0, h = 0; + + // Create this texture + + FTextureBuffer texbuffer; + + if (!tex->isHardwareCanvas()) + { + texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); + w = texbuffer.mWidth; + h = texbuffer.mHeight; + } + else + { + w = tex->GetWidth(); + h = tex->GetHeight(); + } + if (!CreateTexture(texbuffer.mBuffer, w, h, texunit, needmipmap, "FHardwareTexture.BindOrCreate")) + { + // could not create texture + return false; + } + } + if (forcenofilter && clampmode <= CLAMP_XY) clampmode += CLAMP_NOFILTER - CLAMP_NONE; + GLRenderer->mSamplerManager->Bind(texunit, clampmode, 255); + return true; +} + +} diff --git a/src/common/rendering/gles/gles_hwtexture.h b/src/common/rendering/gles/gles_hwtexture.h new file mode 100644 index 00000000000..f367c5d3ad2 --- /dev/null +++ b/src/common/rendering/gles/gles_hwtexture.h @@ -0,0 +1,83 @@ +#pragma once +class FBitmap; +class FTexture; + +#include "tarray.h" +#include "hw_ihwtexture.h" + + +#ifdef LoadImage +#undef LoadImage +#endif + +#define SHADED_TEXTURE -1 +#define DIRECT_PALETTE -2 + +#include "tarray.h" +#include "gles_system.h" +#include "hw_ihwtexture.h" + +class FCanvasTexture; + +namespace OpenGLESRenderer +{ + +class FHardwareTexture : public IHardwareTexture +{ +public: + + static unsigned int lastbound[MAX_TEXTURES]; + + static int GetTexDimension(int value) + { + if (value > gles.max_texturesize) return gles.max_texturesize; + return value; + } + + static void InitGlobalState() { for (int i = 0; i < MAX_TEXTURES; i++) lastbound[i] = 0; } + +private: + + bool forcenofilter; + + unsigned int glTexID = 0; + unsigned int glDepthID = 0; // only used by camera textures + uint8_t* texBuffer; + + int glTextureBytes; + bool mipmapped = false; + + int GetDepthBuffer(int w, int h); + +public: + FHardwareTexture(int numchannels = 4, bool disablefilter = false) + { + forcenofilter = disablefilter; + glTextureBytes = numchannels; + + texBuffer = nullptr; + } + + ~FHardwareTexture(); + + static void Unbind(int texunit); + static void UnbindAll(); + + void BindToFrameBuffer(int w, int h); + + unsigned int Bind(int texunit, bool needmipmap); + bool BindOrCreate(FTexture* tex, int texunit, int clampmode, int translation, int flags); + + void AllocateBuffer(int w, int h, int texelsize); + uint8_t* MapBuffer(); + + unsigned int CreateTexture(unsigned char* buffer, int w, int h, int texunit, bool mipmap, const char* name); + unsigned int GetTextureHandle() + { + return glTexID; + } + + int numChannels() { return glTextureBytes; } +}; + +} diff --git a/src/common/rendering/gles/gles_postprocess.cpp b/src/common/rendering/gles/gles_postprocess.cpp new file mode 100644 index 00000000000..1bedaf9cc5c --- /dev/null +++ b/src/common/rendering/gles/gles_postprocess.cpp @@ -0,0 +1,226 @@ +/* +** Postprocessing framework +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "gles_system.h" +#include "m_png.h" +#include "gles_buffers.h" +#include "gles_framebuffer.h" +#include "gles_renderbuffers.h" +#include "gles_renderer.h" +#include "gles_postprocessstate.h" +#include "gles_shaderprogram.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "hwrenderer/postprocessing/hw_postprocess_cvars.h" +#include "flatvertices.h" +#include "r_videoscale.h" +#include "v_video.h" + +#include "hw_vrmodes.h" +#include "v_draw.h" + +extern bool vid_hdr_active; + + +namespace OpenGLESRenderer +{ + +int gl_dither_bpc = -1; + +void FGLRenderer::RenderScreenQuad() +{ + auto buffer = static_cast(screen->mVertexData->GetBufferObjects().first); + buffer->Bind(nullptr); + glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 3); +} + +void FGLRenderer::PostProcessScene(int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) +{ +#ifndef NO_RENDER_BUFFER + mBuffers->BindCurrentFB(); +#endif + if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D(); +} + + + +//----------------------------------------------------------------------------- +// +// Copies the rendered screen to its final destination +// +//----------------------------------------------------------------------------- + +void FGLRenderer::Flush() +{ + CopyToBackbuffer(nullptr, true); +} + +//----------------------------------------------------------------------------- +// +// Gamma correct while copying to frame buffer +// +//----------------------------------------------------------------------------- + +void FGLRenderer::CopyToBackbuffer(const IntRect *bounds, bool applyGamma) +{ +#ifdef NO_RENDER_BUFFER + mBuffers->BindOutputFB(); +#endif + screen->Draw2D(); // draw all pending 2D stuff before copying the buffer + twod->Clear(); + + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + + mBuffers->BindOutputFB(); + + IntRect box; + if (bounds) + { + box = *bounds; + } + else + { + ClearBorders(); + box = screen->mOutputLetterbox; + } + + mBuffers->BindCurrentTexture(0); +#ifndef NO_RENDER_BUFFER + DrawPresentTexture(box, applyGamma); +#endif +} + +void FGLRenderer::DrawPresentTexture(const IntRect &box, bool applyGamma) +{ + glViewport(box.left, box.top, box.width, box.height); + + mBuffers->BindDitherTexture(1); + + glActiveTexture(GL_TEXTURE0); + if (ViewportLinearScale()) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + mPresentShader->Bind(); + if (!applyGamma || framebuffer->IsHWGammaActive()) + { + mPresentShader->Uniforms->InvGamma = 1.0f; + mPresentShader->Uniforms->Contrast = 1.0f; + mPresentShader->Uniforms->Brightness = 0.0f; + mPresentShader->Uniforms->Saturation = 1.0f; + } + else + { + mPresentShader->Uniforms->InvGamma = 1.0f / clamp(vid_gamma, 0.1f, 4.f); + mPresentShader->Uniforms->Contrast = clamp(vid_contrast, 0.1f, 3.f); + mPresentShader->Uniforms->Brightness = clamp(vid_brightness, -0.8f, 0.8f); + mPresentShader->Uniforms->Saturation = clamp(vid_saturation, -15.0f, 15.f); + mPresentShader->Uniforms->GrayFormula = static_cast(gl_satformula); + } + if (vid_hdr_active && framebuffer->IsFullscreen()) + { + // Full screen exclusive mode treats a rgba16f frame buffer as linear. + // It probably will eventually in desktop mode too, but the DWM doesn't seem to support that. + mPresentShader->Uniforms->HdrMode = 1; + mPresentShader->Uniforms->ColorScale = (gl_dither_bpc == -1) ? 1023.0f : (float)((1 << gl_dither_bpc) - 1); + } + else + { + mPresentShader->Uniforms->HdrMode = 0; + mPresentShader->Uniforms->ColorScale = (gl_dither_bpc == -1) ? 255.0f : (float)((1 << gl_dither_bpc) - 1); + } + mPresentShader->Uniforms->Scale = { screen->mScreenViewport.width / (float)mBuffers->GetWidth(), screen->mScreenViewport.height / (float)mBuffers->GetHeight() }; + mPresentShader->Uniforms->Offset = { 0.0f, 0.0f }; + mPresentShader->Uniforms.SetData(); + + + for (size_t n = 0; n < mPresentShader->Uniforms.mFields.size(); n++) + { + UniformFieldDesc desc = mPresentShader->Uniforms.mFields[n]; + int loc = mPresentShader->Uniforms.UniformLocation[n]; + switch (desc.Type) + { + case UniformType::Int: + glUniform1i(loc, *((GLint*)(((char*)(&mPresentShader->Uniforms)) + desc.Offset))); + break; + case UniformType::Float: + glUniform1f(loc, *((GLfloat*)(((char*)(&mPresentShader->Uniforms)) + desc.Offset))); + break; + case UniformType::Vec2: + glUniform2fv(loc,1 , ((GLfloat*)(((char*)(&mPresentShader->Uniforms)) + desc.Offset))); + break; + default: + break; + } + } + + RenderScreenQuad(); +} + +//----------------------------------------------------------------------------- +// +// Fills the black bars around the screen letterbox +// +//----------------------------------------------------------------------------- + +void FGLRenderer::ClearBorders() +{ + const auto &box = screen->mOutputLetterbox; + + int clientWidth = framebuffer->GetClientWidth(); + int clientHeight = framebuffer->GetClientHeight(); + if (clientWidth == 0 || clientHeight == 0) + return; + + glViewport(0, 0, clientWidth, clientHeight); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glEnable(GL_SCISSOR_TEST); + if (box.top > 0) + { + glScissor(0, 0, clientWidth, box.top); + glClear(GL_COLOR_BUFFER_BIT); + } + if (clientHeight - box.top - box.height > 0) + { + glScissor(0, box.top + box.height, clientWidth, clientHeight - box.top - box.height); + glClear(GL_COLOR_BUFFER_BIT); + } + if (box.left > 0) + { + glScissor(0, box.top, box.left, box.height); + glClear(GL_COLOR_BUFFER_BIT); + } + if (clientWidth - box.left - box.width > 0) + { + glScissor(box.left + box.width, box.top, clientWidth - box.left - box.width, box.height); + glClear(GL_COLOR_BUFFER_BIT); + } + glDisable(GL_SCISSOR_TEST); +} + +} diff --git a/src/common/rendering/gles/gles_postprocessstate.cpp b/src/common/rendering/gles/gles_postprocessstate.cpp new file mode 100644 index 00000000000..ea89218375c --- /dev/null +++ b/src/common/rendering/gles/gles_postprocessstate.cpp @@ -0,0 +1,118 @@ +/* +** Postprocessing framework +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "gles_system.h" +#include "gles_postprocessstate.h" + +namespace OpenGLESRenderer +{ + +//----------------------------------------------------------------------------- +// +// Saves state modified by post processing shaders +// +//----------------------------------------------------------------------------- + +FGLPostProcessState::FGLPostProcessState() +{ + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); + glActiveTexture(GL_TEXTURE0); + SaveTextureBindings(1); + + glGetBooleanv(GL_BLEND, &blendEnabled); + glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); + glGetBooleanv(GL_DEPTH_TEST, &depthEnabled); + glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); + glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRgb); + glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha); + glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRgb); + glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha); + glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRgb); + glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); +} + +void FGLPostProcessState::SaveTextureBindings(unsigned int numUnits) +{ + while (textureBinding.Size() < numUnits) + { + unsigned int i = textureBinding.Size(); + + GLint texture; + glActiveTexture(GL_TEXTURE0 + i); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture); + glBindTexture(GL_TEXTURE_2D, 0); + textureBinding.Push(texture); + } + glActiveTexture(GL_TEXTURE0); +} + +//----------------------------------------------------------------------------- +// +// Restores state at the end of post processing +// +//----------------------------------------------------------------------------- + +FGLPostProcessState::~FGLPostProcessState() +{ + if (blendEnabled) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + + if (scissorEnabled) + glEnable(GL_SCISSOR_TEST); + else + glDisable(GL_SCISSOR_TEST); + + if (depthEnabled) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + + + glBlendEquationSeparate(blendEquationRgb, blendEquationAlpha); + glBlendFuncSeparate(blendSrcRgb, blendDestRgb, blendSrcAlpha, blendDestAlpha); + + glUseProgram(currentProgram); + + // Fully unbind to avoid incomplete texture warnings from Nvidia's driver when gl_debug_level 4 is active + for (unsigned int i = 0; i < textureBinding.Size(); i++) + { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, 0); + } + + + for (unsigned int i = 0; i < textureBinding.Size(); i++) + { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, textureBinding[i]); + } + + glActiveTexture(activeTex); +} + +} \ No newline at end of file diff --git a/src/common/rendering/gles/gles_postprocessstate.h b/src/common/rendering/gles/gles_postprocessstate.h new file mode 100644 index 00000000000..1a5ec760f1b --- /dev/null +++ b/src/common/rendering/gles/gles_postprocessstate.h @@ -0,0 +1,40 @@ +#ifndef __GL_POSTPROCESSSTATE_H +#define __GL_POSTPROCESSSTATE_H + +#include +#include "matrix.h" +#include "c_cvars.h" + +namespace OpenGLESRenderer +{ + +class FGLPostProcessState +{ +public: + FGLPostProcessState(); + ~FGLPostProcessState(); + + void SaveTextureBindings(unsigned int numUnits); + +private: + FGLPostProcessState(const FGLPostProcessState &) = delete; + FGLPostProcessState &operator=(const FGLPostProcessState &) = delete; + + GLint activeTex; + TArray textureBinding; + TArray samplerBinding; + GLboolean blendEnabled; + GLboolean scissorEnabled; + GLboolean depthEnabled; + GLboolean multisampleEnabled; + GLint currentProgram; + GLint blendEquationRgb; + GLint blendEquationAlpha; + GLint blendSrcRgb; + GLint blendSrcAlpha; + GLint blendDestRgb; + GLint blendDestAlpha; +}; + +} +#endif diff --git a/src/common/rendering/gles/gles_renderbuffers.cpp b/src/common/rendering/gles/gles_renderbuffers.cpp new file mode 100644 index 00000000000..002734b9972 --- /dev/null +++ b/src/common/rendering/gles/gles_renderbuffers.cpp @@ -0,0 +1,430 @@ +/* +** Postprocessing framework +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "gles_system.h" +#include "v_video.h" +#include "printf.h" +#include "hw_cvars.h" +#include "gles_renderer.h" +#include "gles_renderbuffers.h" +#include "gles_postprocessstate.h" +#include "gles_shaderprogram.h" +#include "gles_buffers.h" + +#include + +EXTERN_CVAR(Int, gl_debug_level) + +namespace OpenGLESRenderer +{ + + //========================================================================== + // + // Initialize render buffers and textures used in rendering passes + // + //========================================================================== + + FGLRenderBuffers::FGLRenderBuffers() + { + + } + + //========================================================================== + // + // Free render buffer resources + // + //========================================================================== + + FGLRenderBuffers::~FGLRenderBuffers() + { + ClearScene(); + + DeleteTexture(mDitherTexture); + } + + void FGLRenderBuffers::ClearScene() + { + DeleteFrameBuffer(mSceneFB); + DeleteRenderBuffer(mSceneDepthStencilBuf); + DeleteRenderBuffer(mSceneStencilBuf); + } + + void FGLRenderBuffers::DeleteTexture(PPGLTexture& tex) + { + if (tex.handle != 0) + glDeleteTextures(1, &tex.handle); + tex.handle = 0; + } + + void FGLRenderBuffers::DeleteRenderBuffer(PPGLRenderBuffer& buf) + { + if (buf.handle != 0) + glDeleteRenderbuffers(1, &buf.handle); + buf.handle = 0; + } + + void FGLRenderBuffers::DeleteFrameBuffer(PPGLFrameBuffer& fb) + { + if (fb.handle != 0) + glDeleteFramebuffers(1, &fb.handle); + fb.handle = 0; + } + + //========================================================================== + // + // Makes sure all render buffers have sizes suitable for rending at the + // specified resolution + // + //========================================================================== + + void FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHeight) + { + if (width <= 0 || height <= 0) + I_FatalError("Requested invalid render buffer sizes: screen = %dx%d", width, height); + + GLint activeTex; + GLint textureBinding; + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); + glActiveTexture(GL_TEXTURE0); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); + + if (width != mWidth || height != mHeight) + CreatePipeline(width, height); + + if (width != mWidth || height != mHeight ) + CreateScene(width, height); + + mWidth = width; + mHeight = height; + mSceneWidth = sceneWidth; + mSceneHeight = sceneHeight; + + glBindTexture(GL_TEXTURE_2D, textureBinding); + glActiveTexture(activeTex); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (FailedCreate) + { + ClearScene(); + mWidth = 0; + mHeight = 0; + mSceneWidth = 0; + mSceneHeight = 0; + I_FatalError("Unable to create render buffers."); + } + } + + //========================================================================== + // + // Creates the scene buffers + // + //========================================================================== + + void FGLRenderBuffers::CreateScene(int width, int height) + { + ClearScene(); + if(gles.depthStencilAvailable) + mSceneDepthStencilBuf = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); + else + { + mSceneDepthStencilBuf = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH_COMPONENT16, width, height); + mSceneStencilBuf = CreateRenderBuffer("SceneStencil", GL_STENCIL_INDEX8, width, height); + } + mSceneFB= CreateFrameBuffer("SceneFB", mSceneTex, mSceneDepthStencilBuf, mSceneStencilBuf); + } + + //========================================================================== + // + // Creates the buffers needed for post processing steps + // + //========================================================================== + + void FGLRenderBuffers::CreatePipeline(int width, int height) + { + mSceneTex = Create2DTexture("PipelineTexture", GL_RGBA, width, height); + } + + + + //========================================================================== + // + // Creates a 2D texture defaulting to linear filtering and clamp to edge + // + //========================================================================== + + PPGLTexture FGLRenderBuffers::Create2DTexture(const char* name, GLuint format, int width, int height, const void* data) + { + PPGLTexture tex; + tex.Width = width; + tex.Height = height; + glGenTextures(1, &tex.handle); + glBindTexture(GL_TEXTURE_2D, tex.handle); + + GLenum dataformat = 0, datatype = 0; + /* + switch (format) + { + case GL_RGBA: dataformat = GL_RGBA; datatype = GL_UNSIGNED_BYTE; break; + + case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break; + case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; + case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; + case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break; + case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break; + case GL_R16F: dataformat = GL_RED; datatype = GL_FLOAT; break; + case GL_RG32F: dataformat = GL_RG; datatype = GL_FLOAT; break; + case GL_RG16F: dataformat = GL_RG; datatype = GL_FLOAT; break; + case GL_RGB10_A2: dataformat = GL_RGBA; datatype = GL_UNSIGNED_INT_10_10_10_2; break; + case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break; + + case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX8_OES; datatype = GL_INT; break; + case GL_DEPTH24_STENCIL8_OES: dataformat = GL_DEPTH_STENCIL_OES; datatype = GL_UNSIGNED_INT_24_8; break; + default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture"); + } + */ + format = GL_RGBA; + dataformat = GL_RGBA; + datatype = GL_UNSIGNED_BYTE; + + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, dataformat, datatype, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + return tex; + } + + //========================================================================== + // + // Creates a render buffer + // + //========================================================================== + + PPGLRenderBuffer FGLRenderBuffers::CreateRenderBuffer(const char* name, GLuint format, int width, int height) + { + PPGLRenderBuffer buf; + glGenRenderbuffers(1, &buf.handle); + glBindRenderbuffer(GL_RENDERBUFFER, buf.handle); + + glRenderbufferStorage(GL_RENDERBUFFER, format, width, height); + return buf; + } + + //========================================================================== + // + // Creates a frame buffer + // + //========================================================================== + + PPGLFrameBuffer FGLRenderBuffers::CreateFrameBuffer(const char* name, PPGLTexture colorbuffer) + { + PPGLFrameBuffer fb; + glGenFramebuffers(1, &fb.handle); + glBindFramebuffer(GL_FRAMEBUFFER, fb.handle); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer.handle, 0); + if (CheckFrameBufferCompleteness()) + ClearFrameBuffer(false, false); + return fb; + } + + PPGLFrameBuffer FGLRenderBuffers::CreateFrameBuffer(const char* name, PPGLTexture colorbuffer, PPGLRenderBuffer depthstencil, PPGLRenderBuffer stencil) + { + PPGLFrameBuffer fb; + glGenFramebuffers(1, &fb.handle); + glBindFramebuffer(GL_FRAMEBUFFER, fb.handle); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer.handle, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthstencil.handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gles.depthStencilAvailable ? depthstencil.handle : stencil.handle); + if (CheckFrameBufferCompleteness()) + ClearFrameBuffer(true, true); + return fb; + } + + PPGLFrameBuffer FGLRenderBuffers::CreateFrameBuffer(const char* name, PPGLRenderBuffer colorbuffer, PPGLRenderBuffer depthstencil, PPGLRenderBuffer stencil) + { + PPGLFrameBuffer fb; + glGenFramebuffers(1, &fb.handle); + glBindFramebuffer(GL_FRAMEBUFFER, fb.handle); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer.handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthstencil.handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gles.depthStencilAvailable ? depthstencil.handle : stencil.handle); + if (CheckFrameBufferCompleteness()) + ClearFrameBuffer(true, true); + return fb; + } + + PPGLFrameBuffer FGLRenderBuffers::CreateFrameBuffer(const char* name, PPGLTexture colorbuffer0, PPGLTexture colorbuffer1, PPGLTexture colorbuffer2, PPGLTexture depthstencil, PPGLRenderBuffer stencil) + { + PPGLFrameBuffer fb; + glGenFramebuffers(1, &fb.handle); + glBindFramebuffer(GL_FRAMEBUFFER, fb.handle); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer0.handle, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthstencil.handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gles.depthStencilAvailable ? depthstencil.handle : stencil.handle); + + if (CheckFrameBufferCompleteness()) + ClearFrameBuffer(true, true); + return fb; + } + + //========================================================================== + // + // Verifies that the frame buffer setup is valid + // + //========================================================================== + + bool FGLRenderBuffers::CheckFrameBufferCompleteness() + { + GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (result == GL_FRAMEBUFFER_COMPLETE) + return true; + + FString error = "glCheckFramebufferStatus failed: "; + switch (result) + { + default: error.AppendFormat("error code %d", (int)result); break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break; + case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break; + } + Printf("%s\n", error.GetChars()); + + + return false; + } + + //========================================================================== + // + // Clear frame buffer to make sure it never contains uninitialized data + // + //========================================================================== + + void FGLRenderBuffers::ClearFrameBuffer(bool stencil, bool depth) + { + GLboolean scissorEnabled; + GLint stencilValue; + GLfloat depthValue; + glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); + glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &stencilValue); + glGetFloatv(GL_DEPTH_CLEAR_VALUE, &depthValue); + glDisable(GL_SCISSOR_TEST); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClearDepthf(0.0f); + glClearStencil(0); + GLenum flags = GL_COLOR_BUFFER_BIT; + if (stencil) + flags |= GL_STENCIL_BUFFER_BIT; + if (depth) + flags |= GL_DEPTH_BUFFER_BIT; + glClear(flags); + glClearStencil(stencilValue); + glClearDepthf(depthValue); + if (scissorEnabled) + glEnable(GL_SCISSOR_TEST); + } + + + void FGLRenderBuffers::BindDitherTexture(int texunit) + { + if (!mDitherTexture) + { + static const float data[64] = + { + .0078125, .2578125, .1328125, .3828125, .0234375, .2734375, .1484375, .3984375, + .7578125, .5078125, .8828125, .6328125, .7734375, .5234375, .8984375, .6484375, + .0703125, .3203125, .1953125, .4453125, .0859375, .3359375, .2109375, .4609375, + .8203125, .5703125, .9453125, .6953125, .8359375, .5859375, .9609375, .7109375, + .0390625, .2890625, .1640625, .4140625, .0546875, .3046875, .1796875, .4296875, + .7890625, .5390625, .9140625, .6640625, .8046875, .5546875, .9296875, .6796875, + .1015625, .3515625, .2265625, .4765625, .1171875, .3671875, .2421875, .4921875, + .8515625, .6015625, .9765625, .7265625, .8671875, .6171875, .9921875, .7421875, + }; + + glActiveTexture(GL_TEXTURE0 + texunit); + mDitherTexture = Create2DTexture("DitherTexture", GL_RGBA, 8, 8, data); + } + mDitherTexture.Bind(1, GL_NEAREST, GL_REPEAT); + } + + + //========================================================================== + // + // Makes the scene frame buffer active (multisample, depth, stecil, etc.) + // + //========================================================================== + + void FGLRenderBuffers::BindSceneFB(bool sceneData) + { + glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB.handle); + } + + //========================================================================== + // + // Binds the current scene/effect/hud texture to the specified texture unit + // + //========================================================================== + + void FGLRenderBuffers::BindCurrentTexture(int index, int filter, int wrap) + { + mSceneTex.Bind(index, filter, wrap); + } + + //========================================================================== + // + // Makes the frame buffer for the current texture active + // + //========================================================================== + + void FGLRenderBuffers::BindCurrentFB() + { +#ifndef NO_RENDER_BUFFER + mSceneFB.Bind(); +#endif + } + + //========================================================================== + // + // Makes the screen frame buffer active + // + //========================================================================== + + void FGLRenderBuffers::BindOutputFB() + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + //========================================================================== + // + // Returns true if render buffers are supported and should be used + // + //========================================================================== + + bool FGLRenderBuffers::FailedCreate = false; + + + + +} // namespace OpenGLRenderer \ No newline at end of file diff --git a/src/common/rendering/gles/gles_renderbuffers.h b/src/common/rendering/gles/gles_renderbuffers.h new file mode 100644 index 00000000000..3369a864f75 --- /dev/null +++ b/src/common/rendering/gles/gles_renderbuffers.h @@ -0,0 +1,152 @@ + +#pragma once + +#include "hwrenderer/postprocessing/hw_postprocess.h" + +namespace OpenGLESRenderer +{ + +class FGLRenderBuffers; + +class PPGLTexture +{ +public: + void Bind(int index, int filter = GL_NEAREST, int wrap = GL_CLAMP_TO_EDGE) + { + glActiveTexture(GL_TEXTURE0 + index); + glBindTexture(GL_TEXTURE_2D, handle); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); + } + + int Width = -1; + int Height = -1; + + explicit operator bool() const { return handle != 0; } + +private: + GLuint handle = 0; + + friend class FGLRenderBuffers; + friend class PPGLTextureBackend; +}; + +class PPGLFrameBuffer +{ +public: + void Bind() + { + glBindFramebuffer(GL_FRAMEBUFFER, handle); + } + + explicit operator bool() const { return handle != 0; } + +private: + GLuint handle = 0; + + friend class FGLRenderBuffers; + friend class PPGLTextureBackend; +}; + +class PPGLRenderBuffer +{ +private: + GLuint handle = 0; + + explicit operator bool() const { return handle != 0; } + + friend class FGLRenderBuffers; +}; + +class PPGLTextureBackend : public PPTextureBackend +{ +public: + ~PPGLTextureBackend() + { + if (Tex.handle != 0) + { + glDeleteTextures(1, &Tex.handle); + Tex.handle = 0; + } + if (FB.handle != 0) + { + glDeleteFramebuffers(1, &FB.handle); + FB.handle = 0; + } + } + + PPGLTexture Tex; + PPGLFrameBuffer FB; +}; + +class FShaderProgram; + + +class FGLRenderBuffers +{ +public: + FGLRenderBuffers(); + ~FGLRenderBuffers(); + + void Setup(int width, int height, int sceneWidth, int sceneHeight); + + void BindSceneFB(bool sceneData); + + + void BindCurrentTexture(int index, int filter = GL_NEAREST, int wrap = GL_CLAMP_TO_EDGE); + void BindCurrentFB(); + void BindNextFB(); + void NextTexture(); + + + void BindOutputFB(); + + void BindDitherTexture(int texunit); + + int GetWidth() const { return mWidth; } + int GetHeight() const { return mHeight; } + + int GetSceneWidth() const { return mSceneWidth; } + int GetSceneHeight() const { return mSceneHeight; } + +private: + void ClearScene(); + + void CreateScene(int width, int height); + void CreatePipeline(int width, int height); + + PPGLTexture Create2DTexture(const char *name, GLuint format, int width, int height, const void *data = nullptr); + PPGLRenderBuffer CreateRenderBuffer(const char *name, GLuint format, int width, int height); + PPGLFrameBuffer CreateFrameBuffer(const char *name, PPGLTexture colorbuffer); + PPGLFrameBuffer CreateFrameBuffer(const char *name, PPGLTexture colorbuffer, PPGLRenderBuffer depthstencil, PPGLRenderBuffer stencil); + PPGLFrameBuffer CreateFrameBuffer(const char *name, PPGLRenderBuffer colorbuffer, PPGLRenderBuffer depthstencil, PPGLRenderBuffer stencil); + PPGLFrameBuffer CreateFrameBuffer(const char *name, PPGLTexture colorbuffer0, PPGLTexture colorbuffer1, PPGLTexture colorbuffer2, PPGLTexture depthstencil, PPGLRenderBuffer stencil); + bool CheckFrameBufferCompleteness(); + void ClearFrameBuffer(bool stencil, bool depth); + void DeleteTexture(PPGLTexture &handle); + void DeleteRenderBuffer(PPGLRenderBuffer &handle); + void DeleteFrameBuffer(PPGLFrameBuffer &handle); + + int mWidth = 0; + int mHeight = 0; + int mSceneWidth = 0; + int mSceneHeight = 0; + + // Buffers for the scene + PPGLTexture mSceneDepthStencilTex; + PPGLTexture mSceneTex; + PPGLRenderBuffer mSceneDepthStencilBuf; + PPGLRenderBuffer mSceneStencilBuf; // This is only use when combined depth-stencil is not avaliable + PPGLFrameBuffer mSceneFB; + bool mSceneUsesTextures = false; + + PPGLTexture mDitherTexture; + + static bool FailedCreate; + + friend class GLPPRenderState; +}; + +} \ No newline at end of file diff --git a/src/common/rendering/gles/gles_renderer.cpp b/src/common/rendering/gles/gles_renderer.cpp new file mode 100644 index 00000000000..1a33b3bd7f2 --- /dev/null +++ b/src/common/rendering/gles/gles_renderer.cpp @@ -0,0 +1,158 @@ +/* +** gl_renderer.cpp +** Renderer interface +** +**--------------------------------------------------------------------------- +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "gles_system.h" +#include "files.h" +#include "v_video.h" +#include "m_png.h" +#include "filesystem.h" +#include "i_time.h" +#include "cmdlib.h" +#include "version.h" +#include "gles_framebuffer.h" +#include "hw_cvars.h" +#include "gles_renderer.h" +#include "gles_hwtexture.h" +#include "gles_renderstate.h" +#include "gles_samplers.h" +#include "gles_renderbuffers.h" +#include "gles_shaderprogram.h" +#include "flatvertices.h" +#include "hw_lightbuffer.h" +#include "r_videoscale.h" +#include "model.h" +#include "gles_postprocessstate.h" +#include "gles_buffers.h" +#include "texturemanager.h" + +EXTERN_CVAR(Int, screenblocks) + +namespace OpenGLESRenderer +{ + +//=========================================================================== +// +// Renderer interface +// +//=========================================================================== + +//----------------------------------------------------------------------------- +// +// Initialize +// +//----------------------------------------------------------------------------- + +FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) +{ + framebuffer = fb; +} + +void FGLRenderer::Initialize(int width, int height) +{ + mScreenBuffers = new FGLRenderBuffers(); + mBuffers = mScreenBuffers; + mPresentShader = new FPresentShader(); + + mFBID = 0; + mOldFBID = 0; + + mShaderManager = new FShaderManager; + mSamplerManager = new FSamplerManager; +} + +FGLRenderer::~FGLRenderer() +{ + FlushModels(); + TexMan.FlushAll(); + if (mShaderManager != nullptr) delete mShaderManager; + if (mFBID != 0) glDeleteFramebuffers(1, &mFBID); + + if (mBuffers) delete mBuffers; + if (mPresentShader) delete mPresentShader; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +bool FGLRenderer::StartOffscreen() +{ + if (mFBID == 0) + glGenFramebuffers(1, &mFBID); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mOldFBID); + glBindFramebuffer(GL_FRAMEBUFFER, mFBID); + return true; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void FGLRenderer::EndOffscreen() +{ + glBindFramebuffer(GL_FRAMEBUFFER, mOldFBID); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void FGLRenderer::BindToFrameBuffer(FTexture *tex) +{ + auto BaseLayer = static_cast(tex->GetHardwareTexture(0, 0)); + // must create the hardware texture first + BaseLayer->BindOrCreate(tex, 0, 0, 0, 0); + FHardwareTexture::Unbind(0); + gl_RenderState.ClearLastMaterial(); + BaseLayer->BindToFrameBuffer(tex->GetWidth(), tex->GetHeight()); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void FGLRenderer::BeginFrame() +{ + mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height); +} + +} diff --git a/src/common/rendering/gles/gles_renderer.h b/src/common/rendering/gles/gles_renderer.h new file mode 100644 index 00000000000..b1e7d234673 --- /dev/null +++ b/src/common/rendering/gles/gles_renderer.h @@ -0,0 +1,107 @@ +#ifndef __GL_RENDERER_H +#define __GL_RENDERER_H + +#include "v_video.h" +#include "vectors.h" +#include "matrix.h" +#include "gles_renderbuffers.h" +#include + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +struct particle_t; +class FCanvasTexture; +class FFlatVertexBuffer; +class FSkyVertexBuffer; +class HWPortal; +class FLightBuffer; +class BoneBuffer; +class DPSprite; +class FGLRenderBuffers; +class FGL2DDrawer; +class SWSceneDrawer; +class HWViewpointBuffer; +struct FRenderViewpoint; + +namespace OpenGLESRenderer +{ + class FHardwareTexture; + class FShaderManager; + class FSamplerManager; + class OpenGLFrameBuffer; + class FPresentShaderBase; + class FPresentShader; + class FPresent3DCheckerShader; + class FPresent3DColumnShader; + class FPresent3DRowShader; + class FShadowMapShader; + +class FGLRenderer +{ +public: + + OpenGLFrameBuffer *framebuffer; + int mMirrorCount = 0; + int mPlaneMirrorCount = 0; + FShaderManager *mShaderManager = nullptr; + FSamplerManager* mSamplerManager = nullptr; + unsigned int mFBID = 0; + unsigned int mStencilValue = 0; + + int mOldFBID = 0; + + FGLRenderBuffers *mBuffers = nullptr; + FGLRenderBuffers *mScreenBuffers = nullptr; + FPresentShader *mPresentShader = nullptr; + + //FRotator mAngles; + + FGLRenderer(OpenGLFrameBuffer *fb); + ~FGLRenderer() ; + + void Initialize(int width, int height); + + void ClearBorders(); + + void PresentStereo(); + void RenderScreenQuad(); + void PostProcessScene(int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D); + + void CopyToBackbuffer(const IntRect *bounds, bool applyGamma); + void DrawPresentTexture(const IntRect &box, bool applyGamma); + void Flush(); + void BeginFrame(); + + bool StartOffscreen(); + void EndOffscreen(); + + void BindToFrameBuffer(FTexture* tex); + +private: + + bool QuadStereoCheckInitialRenderContextState(); + void PresentAnaglyph(bool r, bool g, bool b); + void PresentSideBySide(int); + void PresentTopBottom(); + void prepareInterleavedPresent(FPresentShaderBase& shader); + void PresentColumnInterleaved(); + void PresentRowInterleaved(); + void PresentCheckerInterleaved(); + void PresentQuadStereo(); + +}; + +struct TexFilter_s +{ + int minfilter; + int magfilter; + bool mipmapping; +} ; + + +extern FGLRenderer *GLRenderer; + +} +#endif diff --git a/src/common/rendering/gles/gles_renderstate.cpp b/src/common/rendering/gles/gles_renderstate.cpp new file mode 100644 index 00000000000..5995fd3b638 --- /dev/null +++ b/src/common/rendering/gles/gles_renderstate.cpp @@ -0,0 +1,742 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2009-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_renderstate.cpp +** Render state maintenance +** +*/ + + +#include "gles_system.h" +#include "hw_cvars.h" +#include "flatvertices.h" +#include "gles_shader.h" +#include "gles_renderer.h" +#include "hw_lightbuffer.h" +#include "hw_bonebuffer.h" +#include "gles_renderbuffers.h" +#include "gles_hwtexture.h" +#include "gles_buffers.h" +#include "gles_renderer.h" +#include "gles_samplers.h" + +#include "hw_clock.h" +#include "printf.h" + +#include "hwrenderer/data/hw_viewpointbuffer.h" + +namespace OpenGLESRenderer +{ + +FGLRenderState gl_RenderState; + +static VSMatrix identityMatrix(1); + +static void matrixToGL(const VSMatrix &mat, int loc) +{ + glUniformMatrix4fv(loc, 1, false, (float*)&mat); +} + +//========================================================================== +// +// This only gets called once upon setup. +// With OpenGL the state is persistent and cannot be cleared, once set up. +// +//========================================================================== + +void FGLRenderState::Reset() +{ + FRenderState::Reset(); + mVertexBuffer = mCurrentVertexBuffer = nullptr; + mGlossiness = 0.0f; + mSpecularLevel = 0.0f; + mShaderTimer = 0.0f; + + stRenderStyle = DefaultRenderStyle(); + stSrcBlend = stDstBlend = -1; + stBlendEquation = -1; + stAlphaTest = 0; + mLastDepthClamp = true; + + mEffectState = 0; + activeShader = nullptr; + + mCurrentVertexBuffer = nullptr; + mCurrentVertexOffsets[0] = mVertexOffsets[0] = 0; + mCurrentIndexBuffer = nullptr; + +} + +//========================================================================== +// +// Apply shader settings +// +//========================================================================== + +bool FGLRenderState::ApplyShader() +{ + static const float nulvec[] = { 0.f, 0.f, 0.f, 0.f }; + + ShaderFlavourData flavour; + + // Need to calc light data now in order to select correct shader + float* lightPtr = NULL; + int modLights = 0; + int subLights = 0; + int addLights = 0; + int totalLights = 0; + + flavour.hasSpotLight = false; + + if (mLightIndex >= 0) + { + lightPtr = ((float*)screen->mLights->GetBuffer()->Memory()); + lightPtr += ((int64_t)mLightIndex * 4); + + // Calculate how much light data there is to upload, this is stored in the first 4 floats + modLights = int(lightPtr[1]) / LIGHT_VEC4_NUM; + subLights = (int(lightPtr[2]) - int(lightPtr[1])) / LIGHT_VEC4_NUM; + addLights = (int(lightPtr[3]) - int(lightPtr[2])) / LIGHT_VEC4_NUM; + + // Here we limit the number of lights, but don't change the light data so priority has to be mod, sub then add + if (modLights > (int)gles.maxlights) + modLights = gles.maxlights; + + if (modLights + subLights > (int)gles.maxlights) + subLights = gles.maxlights - modLights; + + if (modLights + subLights + addLights > (int)gles.maxlights) + addLights = gles.maxlights - modLights - subLights; + + totalLights = modLights + subLights + addLights; + + // Skip passed the first 4 floats so the upload below only contains light data + lightPtr += 4; + + float* findSpotsPtr = lightPtr + 11; // The 11th float contains '1' if the light is a spot light, see hw_dynlightdata.cpp + + for (int n = 0; n < totalLights; n++) + { + if (*findSpotsPtr > 0) // This is a spot light + { + flavour.hasSpotLight = true; + break; + } + findSpotsPtr += LIGHT_VEC4_NUM * 4; + } + } + + + int tm = GetTextureModeAndFlags(mTempTM); + flavour.textureMode = tm & 0xffff; + flavour.texFlags = tm >> 16; //Move flags to start of word + + if (mTextureClamp && flavour.textureMode == TM_NORMAL) flavour.textureMode = TM_CLAMPY; // fixme. Clamp can now be combined with all modes. + + if (flavour.textureMode == -1) + flavour.textureMode = 0; + + + flavour.blendFlags = (int)(mStreamData.uTextureAddColor.a + 0.01); + flavour.paletteInterpolate = !!(flavour.blendFlags & 0x4000); + + flavour.twoDFog = false; + flavour.fogEnabled = false; + flavour.fogEquationRadial = false; + flavour.colouredFog = false; + + flavour.fogEquationRadial = (gl_fogmode == 2); + + flavour.twoDFog = false; + flavour.fogEnabled = false; + flavour.colouredFog = false; + + if (mFogEnabled) + { + if (mFogEnabled == 2) + { + flavour.twoDFog = true; + } + else if (gl_fogmode) + { + flavour.fogEnabled = true; + + if ((GetFogColor() & 0xffffff) != 0) + flavour.colouredFog = true; + } + } + + flavour.doDesaturate = mStreamData.uDesaturationFactor != 0; + flavour.useULightLevel = (mLightParms[3] >= 0); //#define uLightLevel uLightAttr.a + + // Yes create shaders for all combinations of active lights to avoid more branches + flavour.dynLightsMod = (modLights > 0); + flavour.dynLightsSub = (subLights > 0); + flavour.dynLightsAdd = (addLights > 0); + + flavour.useObjectColor2 = (mStreamData.uObjectColor2.a > 0); + flavour.useGlowTopColor = mGlowEnabled && (mStreamData.uGlowTopColor[3] > 0); + flavour.useGlowBottomColor = mGlowEnabled && (mStreamData.uGlowBottomColor[3] > 0); + + flavour.useColorMap = (mColorMapSpecial >= CM_FIRSTSPECIALCOLORMAP) || (mColorMapFlash != 1); + + flavour.buildLighting = (mHwUniforms->mPalLightLevels >> 16) == 5; // Build engine mode + flavour.bandedSwLight = !!(mHwUniforms->mPalLightLevels & 0xFF); + +#ifdef NPOT_EMULATION + flavour.npotEmulation = (mStreamData.uNpotEmulation.Y != 0); +#endif + + if (mSpecialEffect > EFF_NONE) + { + activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect, mPassType, flavour); + } + else + { + activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, mPassType); + + activeShader->Bind(flavour); + } + + + if (mHwUniforms) + { + activeShader->cur->muProjectionMatrix.Set(&mHwUniforms->mProjectionMatrix); + activeShader->cur->muViewMatrix.Set(&mHwUniforms->mViewMatrix); + activeShader->cur->muNormalViewMatrix.Set(&mHwUniforms->mNormalViewMatrix); + activeShader->cur->muCameraPos.Set(&mHwUniforms->mCameraPos.X); + activeShader->cur->muClipLine.Set(&mHwUniforms->mClipLine.X); + activeShader->cur->muGlobVis.Set(mHwUniforms->mGlobVis); + activeShader->cur->muPalLightLevels.Set(mHwUniforms->mPalLightLevels & 0xFF); // JUST pass the pal levels, clear the top bits + activeShader->cur->muViewHeight.Set(mHwUniforms->mViewHeight); + activeShader->cur->muClipHeight.Set(mHwUniforms->mClipHeight); + activeShader->cur->muClipHeightDirection.Set(mHwUniforms->mClipHeightDirection); + //activeShader->cur->muShadowmapFilter.Set(mHwUniforms->mShadowmapFilter); + } + + glVertexAttrib4fv(VATTR_COLOR, &mStreamData.uVertexColor.X); + glVertexAttrib4fv(VATTR_NORMAL, &mStreamData.uVertexNormal.X); + + activeShader->cur->muDesaturation.Set(mStreamData.uDesaturationFactor); + //activeShader->cur->muFogEnabled.Set(fogset); + + activeShader->cur->muLightParms.Set(mLightParms); + activeShader->cur->muFogColor.Set(mStreamData.uFogColor); + activeShader->cur->muObjectColor.Set(mStreamData.uObjectColor); + activeShader->cur->muDynLightColor.Set(&mStreamData.uDynLightColor.X); + activeShader->cur->muInterpolationFactor.Set(mStreamData.uInterpolationFactor); + activeShader->cur->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.); + activeShader->cur->muAlphaThreshold.Set(mAlphaThreshold); + activeShader->cur->muBoneIndexBase.Set(-1); + activeShader->cur->muClipSplit.Set(mClipSplit); + activeShader->cur->muSpecularMaterial.Set(mGlossiness, mSpecularLevel); + activeShader->cur->muAddColor.Set(mStreamData.uAddColor); + activeShader->cur->muTextureAddColor.Set(mStreamData.uTextureAddColor); + activeShader->cur->muTextureModulateColor.Set(mStreamData.uTextureModulateColor); + activeShader->cur->muTextureBlendColor.Set(mStreamData.uTextureBlendColor); + activeShader->cur->muDetailParms.Set(&mStreamData.uDetailParms.X); +#ifdef NPOT_EMULATION + activeShader->cur->muNpotEmulation.Set(&mStreamData.uNpotEmulation.X); +#endif + + if (flavour.useColorMap) + { + if (mColorMapSpecial < CM_FIRSTSPECIALCOLORMAP || mColorMapSpecial >= CM_MAXCOLORMAP) + { + activeShader->cur->muFixedColormapStart.Set( 0,0,0, mColorMapFlash ); + activeShader->cur->muFixedColormapRange.Set( 0,0,0, 1.f ); + } + else + { + FSpecialColormap* scm = &SpecialColormaps[mColorMapSpecial - CM_FIRSTSPECIALCOLORMAP]; + + //uniforms.MapStart = { scm->ColorizeStart[0], scm->ColorizeStart[1], scm->ColorizeStart[2], flash }; + activeShader->cur->muFixedColormapStart.Set( scm->ColorizeStart[0], scm->ColorizeStart[1], scm->ColorizeStart[2], mColorMapFlash ); + activeShader->cur->muFixedColormapRange.Set( scm->ColorizeEnd[0] - scm->ColorizeStart[0], + scm->ColorizeEnd[1] - scm->ColorizeStart[1], scm->ColorizeEnd[2] - scm->ColorizeStart[2], 0.f ); + } + } + + if (mGlowEnabled || activeShader->cur->currentglowstate) + { + activeShader->cur->muGlowTopColor.Set(&mStreamData.uGlowTopColor.X); + activeShader->cur->muGlowBottomColor.Set(&mStreamData.uGlowBottomColor.X); + activeShader->cur->muGlowTopPlane.Set(&mStreamData.uGlowTopPlane.X); + activeShader->cur->muGlowBottomPlane.Set(&mStreamData.uGlowBottomPlane.X); + activeShader->cur->currentglowstate = mGlowEnabled; + } + + if (mGradientEnabled || activeShader->cur->currentgradientstate) + { + activeShader->cur->muObjectColor2.Set(mStreamData.uObjectColor2); + activeShader->cur->muGradientTopPlane.Set(&mStreamData.uGradientTopPlane.X); + activeShader->cur->muGradientBottomPlane.Set(&mStreamData.uGradientBottomPlane.X); + activeShader->cur->currentgradientstate = mGradientEnabled; + } + + if (mSplitEnabled || activeShader->cur->currentsplitstate) + { + activeShader->cur->muSplitTopPlane.Set(&mStreamData.uSplitTopPlane.X); + activeShader->cur->muSplitBottomPlane.Set(&mStreamData.uSplitBottomPlane.X); + activeShader->cur->currentsplitstate = mSplitEnabled; + } + + + if (mTextureMatrixEnabled) + { + matrixToGL(mTextureMatrix, activeShader->cur->texturematrix_index); + activeShader->cur->currentTextureMatrixState = true; + } + else if (activeShader->cur->currentTextureMatrixState) + { + activeShader->cur->currentTextureMatrixState = false; + matrixToGL(identityMatrix, activeShader->cur->texturematrix_index); + } + + if (mModelMatrixEnabled) + { + matrixToGL(mModelMatrix, activeShader->cur->modelmatrix_index); + VSMatrix norm; + norm.computeNormalMatrix(mModelMatrix); + matrixToGL(norm, activeShader->cur->normalmodelmatrix_index); + activeShader->cur->currentModelMatrixState = true; + } + else if (activeShader->cur->currentModelMatrixState) + { + activeShader->cur->currentModelMatrixState = false; + matrixToGL(identityMatrix, activeShader->cur->modelmatrix_index); + matrixToGL(identityMatrix, activeShader->cur->normalmodelmatrix_index); + } + + // Upload the light data + if (mLightIndex >= 0) + { + // Calculate the total number of vec4s we need + int totalVectors = totalLights * LIGHT_VEC4_NUM; + + if (totalVectors > (int)gles.numlightvectors) + totalVectors = gles.numlightvectors; + + glUniform4fv(activeShader->cur->lights_index, totalVectors, lightPtr); + + int range[4] = { 0, + modLights * LIGHT_VEC4_NUM, + (modLights + subLights) * LIGHT_VEC4_NUM, + (modLights + subLights + addLights) * LIGHT_VEC4_NUM }; + + activeShader->cur->muLightRange.Set(range); + } + + if (gles.glesMode >= GLES_MODE_OGL3) + { + // Upload bone data + // NOTE, this is pretty inefficient, it will be reloading the same data over and over in a single frame + // Need to add something to detect a start of new frame then only update the data when it's been changed + if ((mBoneIndexBase >= 0)) + { + float* bonesPtr = ((float*)screen->mBones->GetBuffer()->Memory()); + + int number = screen->mBones->GetCurrentIndex(); + + glUniformMatrix4fv(activeShader->cur->bones_index, number, false, bonesPtr); + + activeShader->cur->muBoneIndexBase.Set(mBoneIndexBase); + } + } + + return true; +} + + +//========================================================================== +// +// Apply State +// +//========================================================================== + +void FGLRenderState::ApplyState() +{ + if (mRenderStyle != stRenderStyle) + { + ApplyBlendMode(); + stRenderStyle = mRenderStyle; + } + + if (mSplitEnabled != stSplitEnabled) + { + stSplitEnabled = mSplitEnabled; + } + + if (mMaterial.mChanged) + { + ApplyMaterial(mMaterial.mMaterial, mMaterial.mClampMode, mMaterial.mTranslation, mMaterial.mOverrideShader); + mMaterial.mChanged = false; + } + + + if (mBias.mFactor == 0 && mBias.mUnits == 0) + { + glDisable(GL_POLYGON_OFFSET_FILL); + } + else + { + glEnable(GL_POLYGON_OFFSET_FILL); + } + glPolygonOffset(mBias.mFactor, mBias.mUnits); + mBias.mChanged = false; +} + +void FGLRenderState::ApplyBuffers() +{ + if (mVertexBuffer != mCurrentVertexBuffer || mVertexOffsets[0] != mCurrentVertexOffsets[0] || mVertexOffsets[1] != mCurrentVertexOffsets[1]) + { + assert(mVertexBuffer != nullptr); + static_cast(mVertexBuffer)->Bind(mVertexOffsets); + mCurrentVertexBuffer = mVertexBuffer; + mCurrentVertexOffsets[0] = mVertexOffsets[0]; + mCurrentVertexOffsets[1] = mVertexOffsets[1]; + } + if (mIndexBuffer != mCurrentIndexBuffer) + { + if (mIndexBuffer) static_cast(mIndexBuffer)->Bind(); + mCurrentIndexBuffer = mIndexBuffer; + } +} + +void FGLRenderState::Apply() +{ + ApplyState(); + ApplyBuffers(); + ApplyShader(); +} + +//=========================================================================== +// +// Binds a texture to the renderer +// +//=========================================================================== + +void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader) +{ + if (mat->Source()->isHardwareCanvas()) + { + mTempTM = TM_OPAQUE; + } + else + { + mTempTM = TM_NORMAL; + } + auto tex = mat->Source(); + mEffectState = overrideshader >= 0 ? overrideshader : mat->GetShaderIndex(); + mShaderTimer = tex->GetShaderSpeed(); + SetSpecular(tex->GetGlossiness(), tex->GetSpecularLevel()); + if (tex->isHardwareCanvas()) static_cast(tex->GetTexture())->NeedUpdate(); + + clampmode = tex->GetClampMode(clampmode); + + // avoid rebinding the same texture multiple times. + if (mat == lastMaterial && lastClamp == clampmode && translation == lastTranslation) return; + lastMaterial = mat; + lastClamp = clampmode; + lastTranslation = translation; + + int maxbound = 0; + + int numLayers = mat->NumLayers(); + MaterialLayerInfo* layer; + auto base = static_cast(mat->GetLayer(0, translation, &layer)); + + if (base->BindOrCreate(tex->GetTexture(), 0, clampmode, translation, layer->scaleFlags)) + { + if (!(layer->scaleFlags & CTF_Indexed)) + { + for (int i = 1; i < numLayers; i++) + { + auto systex = static_cast(mat->GetLayer(i, 0, &layer)); + // fixme: Upscale flags must be disabled for certain layers. + systex->BindOrCreate(layer->layerTexture, i, clampmode, 0, layer->scaleFlags); + maxbound = i; + } + } + else + { + for (int i = 1; i < 3; i++) + { + auto systex = static_cast(mat->GetLayer(i, translation, &layer)); + GLRenderer->mSamplerManager->Bind(i, CLAMP_NONE, 255); + systex->Bind(i, false); + maxbound = i; + } + } + } + // unbind everything from the last texture that's still active + for (int i = maxbound + 1; i <= maxBoundMaterial; i++) + { + FHardwareTexture::Unbind(i); + maxBoundMaterial = maxbound; + } +} + +//========================================================================== +// +// Apply blend mode from RenderStyle +// +//========================================================================== + +void FGLRenderState::ApplyBlendMode() +{ + static int blendstyles[] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA }; + static int renderops[] = { 0, GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; + + int srcblend = blendstyles[mRenderStyle.SrcAlpha%STYLEALPHA_MAX]; + int dstblend = blendstyles[mRenderStyle.DestAlpha%STYLEALPHA_MAX]; + int blendequation = renderops[mRenderStyle.BlendOp & 15]; + + if (blendequation == -1) // This was a fuzz style. + { + srcblend = GL_DST_COLOR; + dstblend = GL_ONE_MINUS_SRC_ALPHA; + blendequation = GL_FUNC_ADD; + } + + // Checks must be disabled until all draw code has been converted. + if (srcblend != stSrcBlend || dstblend != stDstBlend) + { + stSrcBlend = srcblend; + stDstBlend = dstblend; + glBlendFunc(srcblend, dstblend); + } + if (blendequation != stBlendEquation) + { + stBlendEquation = blendequation; + glBlendEquation(blendequation); + } + +} + +//========================================================================== +// +// API dependent draw calls +// +//========================================================================== + +static int dt2gl[] = { GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP }; + +void FGLRenderState::Draw(int dt, int index, int count, bool apply) +{ + if (apply) + { + Apply(); + } + drawcalls.Clock(); + glDrawArrays(dt2gl[dt], index, count); + drawcalls.Unclock(); +} + +void FGLRenderState::DrawIndexed(int dt, int index, int count, bool apply) +{ + if (apply) + { + Apply(); + } + drawcalls.Clock(); + glDrawElements(dt2gl[dt], count, GL_UNSIGNED_INT, (void*)(intptr_t)(index * sizeof(uint32_t))); + drawcalls.Unclock(); +} + +void FGLRenderState::SetDepthMask(bool on) +{ + glDepthMask(on); +} + +void FGLRenderState::SetDepthFunc(int func) +{ + static int df2gl[] = { GL_LESS, GL_LEQUAL, GL_ALWAYS }; + glDepthFunc(df2gl[func]); +} + +void FGLRenderState::SetDepthRange(float min, float max) +{ + glDepthRangef(min, max); +} + +void FGLRenderState::SetColorMask(bool r, bool g, bool b, bool a) +{ + glColorMask(r, g, b, a); +} + +void FGLRenderState::SetStencil(int offs, int op, int flags = -1) +{ + static int op2gl[] = { GL_KEEP, GL_INCR, GL_DECR }; + + glStencilFunc(GL_EQUAL, screen->stencilValue + offs, ~0); // draw sky into stencil + glStencilOp(GL_KEEP, GL_KEEP, op2gl[op]); // this stage doesn't modify the stencil + + if (flags != -1) + { + bool cmon = !(flags & SF_ColorMaskOff); + glColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer + glDepthMask(!(flags & SF_DepthMaskOff)); + } +} + +void FGLRenderState::ToggleState(int state, bool on) +{ + if (on) + { + glEnable(state); + } + else + { + glDisable(state); + } +} + +void FGLRenderState::SetCulling(int mode) +{ + if (mode != Cull_None) + { + glEnable(GL_CULL_FACE); + glFrontFace(mode == Cull_CCW ? GL_CCW : GL_CW); + } + else + { + glDisable(GL_CULL_FACE); + } +} + +void FGLRenderState::EnableClipDistance(int num, bool state) +{ + +} + +void FGLRenderState::Clear(int targets) +{ + // This always clears to default values. + int gltarget = 0; + if (targets & CT_Depth) + { + gltarget |= GL_DEPTH_BUFFER_BIT; + + glClearDepthf(1); + } + if (targets & CT_Stencil) + { + gltarget |= GL_STENCIL_BUFFER_BIT; + glClearStencil(0); + } + if (targets & CT_Color) + { + gltarget |= GL_COLOR_BUFFER_BIT; + glClearColor(screen->mSceneClearColor[0], screen->mSceneClearColor[1], screen->mSceneClearColor[2], screen->mSceneClearColor[3]); + } + glClear(gltarget); +} + +void FGLRenderState::EnableStencil(bool on) +{ + ToggleState(GL_STENCIL_TEST, on); +} + +void FGLRenderState::SetScissor(int x, int y, int w, int h) +{ + if (w > -1) + { + glEnable(GL_SCISSOR_TEST); + glScissor(x, y, w, h); + } + else + { + glDisable(GL_SCISSOR_TEST); + } +} + +void FGLRenderState::SetViewport(int x, int y, int w, int h) +{ + glViewport(x, y, w, h); +} + +void FGLRenderState::EnableDepthTest(bool on) +{ + ToggleState(GL_DEPTH_TEST, on); +} + +void FGLRenderState::EnableMultisampling(bool on) +{ + +} + +void FGLRenderState::EnableLineSmooth(bool on) +{ + +} + + +//========================================================================== +// +// +// +//========================================================================== +void FGLRenderState::ClearScreen() +{ + + screen->mViewpoints->Set2D(*this, SCREENWIDTH, SCREENHEIGHT); + SetColor(0, 0, 0); + Apply(); + + glDisable(GL_DEPTH_TEST); + + glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::FULLSCREEN_INDEX, 4); + + glEnable(GL_DEPTH_TEST); + +} + + + +//========================================================================== +// +// Below are less frequently altrered state settings which do not get +// buffered by the state object, but set directly instead. +// +//========================================================================== + +bool FGLRenderState::SetDepthClamp(bool on) +{ + bool res = mLastDepthClamp; + + if (gles.depthClampAvailable) + { + if (!on) glDisable(GL_DEPTH_CLAMP); + else glEnable(GL_DEPTH_CLAMP); + } + + mLastDepthClamp = on; + return res; +} +void FGLRenderState::ApplyViewport(void* data) +{ + mHwUniforms = reinterpret_cast(static_cast(data)); + +} +} diff --git a/src/common/rendering/gles/gles_renderstate.h b/src/common/rendering/gles/gles_renderstate.h new file mode 100644 index 00000000000..c0bee73c0d5 --- /dev/null +++ b/src/common/rendering/gles/gles_renderstate.h @@ -0,0 +1,144 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2009-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#ifndef __GL_RENDERSTATE_H +#define __GL_RENDERSTATE_H + +#include +#include +#include "matrix.h" +#include "hw_renderstate.h" +#include "hw_material.h" +#include "c_cvars.h" +#include "hwrenderer/data/hw_viewpointuniforms.h" + +namespace OpenGLESRenderer +{ + +class FShader; +struct HWSectorPlane; + +class FGLRenderState final : public FRenderState +{ + uint8_t mLastDepthClamp : 1; + + float mGlossiness, mSpecularLevel; + float mShaderTimer; + + int mEffectState; + int mTempTM = TM_NORMAL; + + FRenderStyle stRenderStyle; + int stSrcBlend, stDstBlend; + bool stAlphaTest; + bool stSplitEnabled; + int stBlendEquation; + + FShader *activeShader; + + int mNumDrawBuffers = 1; + + bool ApplyShader(); + void ApplyState(); + + // Texture binding state + FMaterial *lastMaterial = nullptr; + int lastClamp = 0; + int lastTranslation = 0; + int maxBoundMaterial = -1; + size_t mLastMappedLightIndex = SIZE_MAX; + size_t mLastMappedBoneIndexBase = SIZE_MAX; + + IVertexBuffer *mCurrentVertexBuffer; + int mCurrentVertexOffsets[2]; // one per binding point + IIndexBuffer *mCurrentIndexBuffer; + + HWViewpointUniforms* mHwUniforms = nullptr; + +public: + + FGLRenderState() + { + Reset(); + } + + void Reset(); + + void ClearLastMaterial() + { + lastMaterial = nullptr; + } + + void ApplyMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader); + + void Apply(); + void ApplyBuffers(); + void ApplyBlendMode(); + + void ResetVertexBuffer() + { + // forces rebinding with the next 'apply' call. + mCurrentVertexBuffer = nullptr; + mCurrentIndexBuffer = nullptr; + } + + void SetSpecular(float glossiness, float specularLevel) + { + mGlossiness = glossiness; + mSpecularLevel = specularLevel; + } + + void EnableDrawBuffers(int count, bool apply = false) override + { + + } + + void ToggleState(int state, bool on); + + void ClearScreen() override; + void Draw(int dt, int index, int count, bool apply = true) override; + void DrawIndexed(int dt, int index, int count, bool apply = true) override; + + bool SetDepthClamp(bool on) override; + void SetDepthMask(bool on) override; + void SetDepthFunc(int func) override; + void SetDepthRange(float min, float max) override; + void SetColorMask(bool r, bool g, bool b, bool a) override; + void SetStencil(int offs, int op, int flags) override; + void SetCulling(int mode) override; + void EnableClipDistance(int num, bool state) override; + void Clear(int targets) override; + void EnableStencil(bool on) override; + void SetScissor(int x, int y, int w, int h) override; + void SetViewport(int x, int y, int w, int h) override; + void EnableDepthTest(bool on) override; + void EnableMultisampling(bool on) override; + void EnableLineSmooth(bool on) override; + + void ApplyViewport(void* data); +}; + +extern FGLRenderState gl_RenderState; + +} + +#endif diff --git a/src/common/rendering/gles/gles_samplers.cpp b/src/common/rendering/gles/gles_samplers.cpp new file mode 100644 index 00000000000..17efe78ca60 --- /dev/null +++ b/src/common/rendering/gles/gles_samplers.cpp @@ -0,0 +1,217 @@ +/* +** gl_samplers.cpp +** +** Texture sampler handling +** +**--------------------------------------------------------------------------- +** Copyright 2015-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include "gles_system.h" +#include "c_cvars.h" + +#include "hw_cvars.h" + +#include "gles_renderer.h" +#include "gles_samplers.h" +#include "hw_material.h" +#include "i_interface.h" + +namespace OpenGLESRenderer +{ + +extern TexFilter_s TexFilter[]; + + +FSamplerManager::FSamplerManager() +{ + SetTextureFilterMode(); +} + +FSamplerManager::~FSamplerManager() +{ + +} + +void FSamplerManager::UnbindAll() +{ + +} + +uint8_t FSamplerManager::Bind(int texunit, int num, int lastval) +{ + + int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter() ? 0 : gl_texture_filter; + bool anisoAvailable = gles.anistropicFilterAvailable && (!sysCallbacks.DisableTextureFilter || !sysCallbacks.DisableTextureFilter()); + + glActiveTexture(GL_TEXTURE0 + texunit); + switch (num) + { + case CLAMP_NONE: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + if (lastval >= CLAMP_XY_NOMIP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic); + } + break; + + case CLAMP_X: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + if (lastval >= CLAMP_XY_NOMIP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic); + } + break; + + case CLAMP_Y: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (lastval >= CLAMP_XY_NOMIP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic); + } + break; + + case CLAMP_XY: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (lastval >= CLAMP_XY_NOMIP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic); + } + break; + + case CLAMP_XY_NOMIP: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0); + break; + + case CLAMP_NOFILTER: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0); + break; + + case CLAMP_NOFILTER_X: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0); + break; + + case CLAMP_NOFILTER_Y: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0); + break; + + case CLAMP_NOFILTER_XY: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0); + break; + + case CLAMP_CAMTEX: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + if (anisoAvailable) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0); + break; + } + glActiveTexture(GL_TEXTURE0); + return 255; +} + + +void FSamplerManager::SetTextureFilterMode() +{ + /* + GLRenderer->FlushTextures(); + + GLint bounds[IHardwareTexture::MAX_TEXTURES]; + + // Unbind all + for(int i = IHardwareTexture::MAX_TEXTURES-1; i >= 0; i--) + { + glActiveTexture(GL_TEXTURE0 + i); + glGetIntegerv(GL_SAMPLER_BINDING, &bounds[i]); + glBindSampler(i, 0); + } + + int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter() ? 0 : gl_texture_filter; + + for (int i = 0; i < 4; i++) + { + glSamplerParameteri(mSamplers[i], GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter); + glSamplerParameteri(mSamplers[i], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + glSamplerParameterf(mSamplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, filter > 0? gl_texture_filter_anisotropic : 1.0); + } + glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter); + glSamplerParameteri(mSamplers[CLAMP_XY_NOMIP], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + glSamplerParameteri(mSamplers[CLAMP_CAMTEX], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter); + glSamplerParameteri(mSamplers[CLAMP_CAMTEX], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); + for(int i = 0; i < IHardwareTexture::MAX_TEXTURES; i++) + { + glBindSampler(i, bounds[i]); + } + */ +} + + +} \ No newline at end of file diff --git a/src/common/rendering/gles/gles_samplers.h b/src/common/rendering/gles/gles_samplers.h new file mode 100644 index 00000000000..541b409b78a --- /dev/null +++ b/src/common/rendering/gles/gles_samplers.h @@ -0,0 +1,27 @@ +#ifndef __GLES_SAMPLERS_H +#define __GLES_SAMPLERS_H + +#include "gles_hwtexture.h" +#include "textures.h" + +namespace OpenGLESRenderer +{ + + +class FSamplerManager +{ + void UnbindAll(); + +public: + + FSamplerManager(); + ~FSamplerManager(); + + uint8_t Bind(int texunit, int num, int lastval); + void SetTextureFilterMode(); + +}; + +} +#endif + diff --git a/src/common/rendering/gles/gles_shader.cpp b/src/common/rendering/gles/gles_shader.cpp new file mode 100644 index 00000000000..dba9a233a69 --- /dev/null +++ b/src/common/rendering/gles/gles_shader.cpp @@ -0,0 +1,942 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2004-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_shader.cpp +** +** GLSL shader handling +** +*/ + +#include "gles_system.h" +#include "c_cvars.h" +#include "v_video.h" +#include "filesystem.h" +#include "engineerrors.h" +#include "cmdlib.h" +#include "md5.h" +#include "gles_shader.h" +#include "hw_shaderpatcher.h" +#include "shaderuniforms.h" +#include "hw_viewpointuniforms.h" +#include "hw_lightbuffer.h" +#include "i_specialpaths.h" +#include "printf.h" +#include "version.h" + +#include "matrix.h" +#include "gles_renderer.h" +#include +#include + +namespace OpenGLESRenderer +{ + +CVAR(Int, gles_glsl_precision, 2, 0); // 0 = low, 1 = medium, 2 = high + +FString GetGLSLPrecision() +{ + FString str = "precision highp int;\n \ + precision highp float;\n"; + + if (gles_glsl_precision == 0) + str.Substitute("highp", "lowp"); + else if (gles_glsl_precision == 1) + str.Substitute("highp", "mediump"); + + return str; +} + +struct ProgramBinary +{ + uint32_t format; + TArray data; +}; + +static const char *ShaderMagic = "ZDSC"; + +static std::map> ShaderCache; // Not a TMap because it doesn't support unique_ptr move semantics + +bool IsShaderCacheActive() +{ + static bool active = true; + static bool firstcall = true; + + if (firstcall) + { + const char *vendor = (const char *)glGetString(GL_VENDOR); + active = !(strstr(vendor, "Intel") == nullptr); + firstcall = false; + } + return active; +} + +static FString CalcProgramBinaryChecksum(const FString &vertex, const FString &fragment) +{ + const GLubyte *vendor = glGetString(GL_VENDOR); + const GLubyte *renderer = glGetString(GL_RENDERER); + const GLubyte *version = glGetString(GL_VERSION); + + uint8_t digest[16]; + MD5Context md5; + md5.Update(vendor, (unsigned int)strlen((const char*)vendor)); + md5.Update(renderer, (unsigned int)strlen((const char*)renderer)); + md5.Update(version, (unsigned int)strlen((const char*)version)); + md5.Update((const uint8_t *)vertex.GetChars(), (unsigned int)vertex.Len()); + md5.Update((const uint8_t *)fragment.GetChars(), (unsigned int)fragment.Len()); + md5.Final(digest); + + char hexdigest[33]; + for (int i = 0; i < 16; i++) + { + int v = digest[i] >> 4; + hexdigest[i * 2] = v < 10 ? ('0' + v) : ('a' + v - 10); + v = digest[i] & 15; + hexdigest[i * 2 + 1] = v < 10 ? ('0' + v) : ('a' + v - 10); + } + hexdigest[32] = 0; + return hexdigest; +} + +static FString CreateProgramCacheName(bool create) +{ + FString path = M_GetCachePath(create); + if (create) CreatePath(path.GetChars()); + path << "/shadercache.zdsc"; + return path; +} + +static void LoadShaders() +{ + static bool loaded = false; + if (loaded) + return; + loaded = true; + + try + { + FString path = CreateProgramCacheName(false); + FileReader fr; + if (!fr.OpenFile(path.GetChars())) + I_Error("Could not open shader file"); + + char magic[4]; + fr.Read(magic, 4); + if (memcmp(magic, ShaderMagic, 4) != 0) + I_Error("Not a shader cache file"); + + uint32_t count = fr.ReadUInt32(); + if (count > 512) + I_Error("Too many shaders cached"); + + for (uint32_t i = 0; i < count; i++) + { + char hexdigest[33]; + if (fr.Read(hexdigest, 32) != 32) + I_Error("Read error"); + hexdigest[32] = 0; + + std::unique_ptr binary(new ProgramBinary()); + binary->format = fr.ReadUInt32(); + uint32_t size = fr.ReadUInt32(); + if (size > 1024 * 1024) + I_Error("Shader too big, probably file corruption"); + + binary->data.Resize(size); + if (fr.Read(binary->data.Data(), binary->data.Size()) != binary->data.Size()) + I_Error("Read error"); + + ShaderCache[hexdigest] = std::move(binary); + } + } + catch (...) + { + ShaderCache.clear(); + } +} + +static void SaveShaders() +{ + FString path = CreateProgramCacheName(true); + std::unique_ptr fw(FileWriter::Open(path.GetChars())); + if (fw) + { + uint32_t count = (uint32_t)ShaderCache.size(); + fw->Write(ShaderMagic, 4); + fw->Write(&count, sizeof(uint32_t)); + for (const auto &it : ShaderCache) + { + uint32_t size = it.second->data.Size(); + fw->Write(it.first.GetChars(), 32); + fw->Write(&it.second->format, sizeof(uint32_t)); + fw->Write(&size, sizeof(uint32_t)); + fw->Write(it.second->data.Data(), it.second->data.Size()); + } + } +} + +TArray LoadCachedProgramBinary(const FString &vertex, const FString &fragment, uint32_t &binaryFormat) +{ + LoadShaders(); + + auto it = ShaderCache.find(CalcProgramBinaryChecksum(vertex, fragment)); + if (it != ShaderCache.end()) + { + binaryFormat = it->second->format; + return it->second->data; + } + else + { + binaryFormat = 0; + return {}; + } +} + +void SaveCachedProgramBinary(const FString &vertex, const FString &fragment, const TArray &binary, uint32_t binaryFormat) +{ + auto &entry = ShaderCache[CalcProgramBinaryChecksum(vertex, fragment)]; + entry.reset(new ProgramBinary()); + entry->format = binaryFormat; + entry->data = binary; + + SaveShaders(); +} + +bool FShader::Configure(const char* name, const char* vert_prog_lump, const char* fragprog, const char* fragprog2, const char* light_fragprog, const char* defines) +{ + mVertProg = vert_prog_lump; + mFragProg = fragprog; + mFragProg2 = fragprog2; + mLightProg = light_fragprog; + mDefinesBase = defines; + + return true; +} + +void FShader::LoadVariant() +{ + //mDefinesBase + Load(mName.GetChars(), mVertProg.GetChars(), mFragProg.GetChars(), mFragProg2.GetChars(), mLightProg.GetChars(), mDefinesBase.GetChars()); +} + +bool FShader::Load(const char * name, const char * vert_prog_lump_, const char * frag_prog_lump_, const char * proc_prog_lump_, const char * light_fragprog_, const char * defines) +{ + ShaderVariantData* shaderData = new ShaderVariantData(); + + FString vert_prog_lump = vert_prog_lump_; + FString frag_prog_lump = frag_prog_lump_; + FString proc_prog_lump = proc_prog_lump_; + FString light_fragprog = light_fragprog_; + + vert_prog_lump.Substitute("shaders/", "shaders_gles/"); + frag_prog_lump.Substitute("shaders/", "shaders_gles/"); + proc_prog_lump.Substitute("shaders/", "shaders_gles/"); + light_fragprog.Substitute("shaders/", "shaders_gles/"); + + //light_fragprog.Substitute("material_pbr", "material_normal"); + + if(light_fragprog.Len()) + light_fragprog = "shaders_gles/glsl/material_normal.fp"; // NOTE: Always use normal material for now, ignore others + + + static char buffer[10000]; + FString error; + + FString i_data = GetGLSLPrecision(); + + i_data += R"( + + // light buffers + uniform vec4 lights[MAXIMUM_LIGHT_VECTORS]; + + // bone matrix buffers + uniform mat4 bones[MAXIMUM_LIGHT_VECTORS]; + + uniform mat4 ProjectionMatrix; + uniform mat4 ViewMatrix; + uniform mat4 NormalViewMatrix; + + uniform vec4 uCameraPos; + uniform vec4 uClipLine; + + uniform float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 + uniform int uPalLightLevels; + uniform int uViewHeight; // Software fuzz scaling + uniform float uClipHeight; + uniform float uClipHeightDirection; + uniform int uShadowmapFilter; + + uniform int uTextureMode; + uniform vec2 uClipSplit; + uniform float uAlphaThreshold; + + // colors + uniform vec4 uObjectColor; + uniform vec4 uObjectColor2; + uniform vec4 uDynLightColor; + uniform vec4 uAddColor; + uniform vec4 uTextureBlendColor; + uniform vec4 uTextureModulateColor; + uniform vec4 uTextureAddColor; + uniform vec4 uFogColor; + uniform float uDesaturationFactor; + uniform float uInterpolationFactor; + + // Glowing walls stuff + uniform vec4 uGlowTopPlane; + uniform vec4 uGlowTopColor; + uniform vec4 uGlowBottomPlane; + uniform vec4 uGlowBottomColor; + + uniform vec4 uGradientTopPlane; + uniform vec4 uGradientBottomPlane; + + uniform vec4 uSplitTopPlane; + uniform vec4 uSplitBottomPlane; + + uniform vec4 uDetailParms; + // Lighting + Fog + uniform vec4 uLightAttr; + #define uLightLevel uLightAttr.a + #define uFogDensity uLightAttr.b + #define uLightFactor uLightAttr.g + #define uLightDist uLightAttr.r + //uniform int uFogEnabled; + + // dynamic lights + uniform ivec4 uLightRange; + + // bone animation + uniform int uBoneIndexBase; + + // Blinn glossiness and specular level + uniform vec2 uSpecularMaterial; + + // matrices + uniform mat4 ModelMatrix; + uniform mat4 NormalModelMatrix; + uniform mat4 TextureMatrix; + + uniform vec4 uFixedColormapStart; + uniform vec4 uFixedColormapRange; + + // textures + uniform sampler2D tex; + uniform sampler2D ShadowMap; + uniform sampler2D texture2; + uniform sampler2D texture3; + uniform sampler2D texture4; + uniform sampler2D texture5; + uniform sampler2D texture6; + uniform sampler2D texture7; + uniform sampler2D texture8; + uniform sampler2D texture9; + uniform sampler2D texture10; + uniform sampler2D texture11; + + // timer data + uniform float timer; + + // material types + #if defined(SPECULAR) + #define normaltexture texture2 + #define speculartexture texture3 + #define brighttexture texture4 + #define detailtexture texture5 + #define glowtexture texture6 + #elif defined(PBR) + #define normaltexture texture2 + #define metallictexture texture3 + #define roughnesstexture texture4 + #define aotexture texture5 + #define brighttexture texture6 + #define detailtexture texture7 + #define glowtexture texture8 + #else + #define brighttexture texture2 + #define detailtexture texture3 + #define glowtexture texture4 + #endif + )"; + +#ifdef NPOT_EMULATION + i_data += "#define NPOT_EMULATION\nuniform vec2 uNpotEmulation;\n"; +#endif + + int vp_lump = fileSystem.CheckNumForFullName(vert_prog_lump.GetChars(), 0); + if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump.GetChars()); + + int fp_lump = fileSystem.CheckNumForFullName(frag_prog_lump.GetChars(), 0); + if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump.GetChars()); + + + +// +// The following code uses GetChars on the strings to get rid of terminating 0 characters. Do not remove or the code may break! +// + FString vp_comb; + + assert(screen->mLights != NULL); + assert(screen->mBones != NULL); + + unsigned int lightbuffersize = screen->mLights->GetBlockSize(); + + vp_comb.Format("#version %s\n\n#define NO_CLIPDISTANCE_SUPPORT\n", gles.shaderVersionString); + + FString fp_comb = vp_comb; + vp_comb << defines << i_data.GetChars(); + fp_comb << "$placeholder$\n" << defines << i_data.GetChars(); + + vp_comb << "#line 1\n"; + fp_comb << "#line 1\n"; + + vp_comb << RemoveLayoutLocationDecl(GetStringFromLump(vp_lump), "out").GetChars() << "\n"; + fp_comb << RemoveLayoutLocationDecl(GetStringFromLump(fp_lump), "in").GetChars() << "\n"; + FString placeholder = "\n"; + + if (proc_prog_lump.Len()) + { + fp_comb << "#line 1\n"; + + if (proc_prog_lump[0] != '#') + { + int pp_lump = fileSystem.CheckNumForFullName(proc_prog_lump.GetChars()); + if (pp_lump == -1) I_Error("Unable to load '%s'", proc_prog_lump.GetChars()); + FString pp_data = GetStringFromLump(pp_lump); + + if (pp_data.IndexOf("ProcessMaterial") < 0 && pp_data.IndexOf("SetupMaterial") < 0) + { + // this looks like an old custom hardware shader. + + if (pp_data.IndexOf("GetTexCoord") >= 0) + { + int pl_lump = fileSystem.CheckNumForFullName("shaders_gles/glsl/func_defaultmat2.fp", 0); + if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders_gles/glsl/func_defaultmat2.fp"); + fp_comb << "\n" << GetStringFromLump(pl_lump); + } + else + { + int pl_lump = fileSystem.CheckNumForFullName("shaders_gles/glsl/func_defaultmat.fp", 0); + if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders_gles/glsl/func_defaultmat.fp"); + fp_comb << "\n" << GetStringFromLump(pl_lump); + + if (pp_data.IndexOf("ProcessTexel") < 0) + { + // this looks like an even older custom hardware shader. + // We need to replace the ProcessTexel call to make it work. + + fp_comb.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); + } + } + + if (pp_data.IndexOf("ProcessLight") >= 0) + { + // The ProcessLight signatured changed. Forward to the old one. + fp_comb << "\nvec4 ProcessLight(vec4 color);\n"; + fp_comb << "\nvec4 ProcessLight(Material material, vec4 color) { return ProcessLight(color); }\n"; + } + } + + fp_comb << RemoveLegacyUserUniforms(pp_data).GetChars(); + fp_comb.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders. + + if (pp_data.IndexOf("ProcessLight") < 0) + { + int pl_lump = fileSystem.CheckNumForFullName("shaders_gles/glsl/func_defaultlight.fp", 0); + if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders_gles/glsl/func_defaultlight.fp"); + fp_comb << "\n" << GetStringFromLump(pl_lump); + } + + // ProcessMaterial must be considered broken because it requires the user to fill in data they possibly cannot know all about. + if (pp_data.IndexOf("ProcessMaterial") >= 0 && pp_data.IndexOf("SetupMaterial") < 0) + { + // This reactivates the old logic and disables all features that cannot be supported with that method. + placeholder << "#define LEGACY_USER_SHADER\n"; + } + } + else + { + // Proc_prog_lump is not a lump name but the source itself (from generated shaders) + fp_comb << proc_prog_lump.GetChars() + 1; + } + } + fp_comb.Substitute("$placeholder$", placeholder); + + if (light_fragprog.Len()) + { + int pp_lump = fileSystem.CheckNumForFullName(light_fragprog.GetChars(), 0); + if (pp_lump == -1) I_Error("Unable to load '%s'", light_fragprog.GetChars()); + fp_comb << GetStringFromLump(pp_lump) << "\n"; + } + + if (gles.flags & RFL_NO_CLIP_PLANES) + { + // On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken. + // This will cause some glitches and regressions but is the only way to avoid total display garbage. + vp_comb.Substitute("gl_ClipDistance", "//"); + } + + shaderData->hShader = glCreateProgram(); + + uint32_t binaryFormat = 0; + TArray binary; + if (IsShaderCacheActive()) + binary = LoadCachedProgramBinary(vp_comb, fp_comb, binaryFormat); + + bool linked = false; + + if (!linked) + { + shaderData->hVertProg = glCreateShader(GL_VERTEX_SHADER); + shaderData->hFragProg = glCreateShader(GL_FRAGMENT_SHADER); + + int vp_size = (int)vp_comb.Len(); + int fp_size = (int)fp_comb.Len(); + + const char *vp_ptr = vp_comb.GetChars(); + const char *fp_ptr = fp_comb.GetChars(); + + glShaderSource(shaderData->hVertProg, 1, &vp_ptr, &vp_size); + glShaderSource(shaderData->hFragProg, 1, &fp_ptr, &fp_size); + + glCompileShader(shaderData->hVertProg); + glCompileShader(shaderData->hFragProg); + + glAttachShader(shaderData->hShader, shaderData->hVertProg); + glAttachShader(shaderData->hShader, shaderData->hFragProg); + + + glBindAttribLocation(shaderData->hShader, VATTR_VERTEX, "aPosition"); + glBindAttribLocation(shaderData->hShader, VATTR_TEXCOORD, "aTexCoord"); + glBindAttribLocation(shaderData->hShader, VATTR_COLOR, "aColor"); + glBindAttribLocation(shaderData->hShader, VATTR_VERTEX2, "aVertex2"); + glBindAttribLocation(shaderData->hShader, VATTR_NORMAL, "aNormal"); + glBindAttribLocation(shaderData->hShader, VATTR_NORMAL2, "aNormal2"); + glBindAttribLocation(shaderData->hShader, VATTR_BONEWEIGHT, "aBoneWeight"); + glBindAttribLocation(shaderData->hShader, VATTR_BONESELECTOR, "aBoneSelector"); + + + glLinkProgram(shaderData->hShader); + + glGetShaderInfoLog(shaderData->hVertProg, 10000, NULL, buffer); + if (*buffer) + { + error << "Vertex shader:\n" << buffer << "\n"; + } + glGetShaderInfoLog(shaderData->hFragProg, 10000, NULL, buffer); + if (*buffer) + { + error << "Fragment shader:\n" << buffer << "\n"; + } + + glGetProgramInfoLog(shaderData->hShader, 10000, NULL, buffer); + if (*buffer) + { + error << "Linking:\n" << buffer << "\n"; + } + GLint status = 0; + glGetProgramiv(shaderData->hShader, GL_LINK_STATUS, &status); + linked = (status == GL_TRUE); + + if (!linked) + { + // only print message if there's an error. + I_Error("Init Shader '%s':\n%s\n", name, error.GetChars()); + } + } + else + { + shaderData->hVertProg = 0; + shaderData->hFragProg = 0; + } + + shaderData->muProjectionMatrix.Init(shaderData->hShader, "ProjectionMatrix"); + shaderData->muViewMatrix.Init(shaderData->hShader, "ViewMatrix"); + shaderData->muNormalViewMatrix.Init(shaderData->hShader, "NormalViewMatrix"); + + shaderData->muCameraPos.Init(shaderData->hShader, "uCameraPos"); + shaderData->muClipLine.Init(shaderData->hShader, "uClipLine"); + + shaderData->muGlobVis.Init(shaderData->hShader, "uGlobVis"); + shaderData->muPalLightLevels.Init(shaderData->hShader, "uPalLightLevels"); + shaderData->muViewHeight.Init(shaderData->hShader, "uViewHeight"); + shaderData->muClipHeight.Init(shaderData->hShader, "uClipHeight"); + shaderData->muClipHeightDirection.Init(shaderData->hShader, "uClipHeightDirection"); + shaderData->muShadowmapFilter.Init(shaderData->hShader, "uShadowmapFilter"); + + //// + + shaderData->muDesaturation.Init(shaderData->hShader, "uDesaturationFactor"); + shaderData->muFogEnabled.Init(shaderData->hShader, "uFogEnabled"); + shaderData->muTextureMode.Init(shaderData->hShader, "uTextureMode"); + shaderData->muLightParms.Init(shaderData->hShader, "uLightAttr"); + shaderData->muClipSplit.Init(shaderData->hShader, "uClipSplit"); + shaderData->muLightRange.Init(shaderData->hShader, "uLightRange"); + shaderData->muBoneIndexBase.Init(shaderData->hShader, "uBoneIndexBase"); + shaderData->muFogColor.Init(shaderData->hShader, "uFogColor"); + shaderData->muDynLightColor.Init(shaderData->hShader, "uDynLightColor"); + shaderData->muObjectColor.Init(shaderData->hShader, "uObjectColor"); + shaderData->muObjectColor2.Init(shaderData->hShader, "uObjectColor2"); + shaderData->muGlowBottomColor.Init(shaderData->hShader, "uGlowBottomColor"); + shaderData->muGlowTopColor.Init(shaderData->hShader, "uGlowTopColor"); + shaderData->muGlowBottomPlane.Init(shaderData->hShader, "uGlowBottomPlane"); + shaderData->muGlowTopPlane.Init(shaderData->hShader, "uGlowTopPlane"); + shaderData->muGradientBottomPlane.Init(shaderData->hShader, "uGradientBottomPlane"); + shaderData->muGradientTopPlane.Init(shaderData->hShader, "uGradientTopPlane"); + shaderData->muSplitBottomPlane.Init(shaderData->hShader, "uSplitBottomPlane"); + shaderData->muSplitTopPlane.Init(shaderData->hShader, "uSplitTopPlane"); + shaderData->muDetailParms.Init(shaderData->hShader, "uDetailParms"); + shaderData->muInterpolationFactor.Init(shaderData->hShader, "uInterpolationFactor"); + shaderData->muAlphaThreshold.Init(shaderData->hShader, "uAlphaThreshold"); + shaderData->muSpecularMaterial.Init(shaderData->hShader, "uSpecularMaterial"); + shaderData->muAddColor.Init(shaderData->hShader, "uAddColor"); + shaderData->muTextureAddColor.Init(shaderData->hShader, "uTextureAddColor"); + shaderData->muTextureModulateColor.Init(shaderData->hShader, "uTextureModulateColor"); + shaderData->muTextureBlendColor.Init(shaderData->hShader, "uTextureBlendColor"); + shaderData->muTimer.Init(shaderData->hShader, "timer"); +#ifdef NPOT_EMULATION + shaderData->muNpotEmulation.Init(shaderData->hShader, "uNpotEmulation"); +#endif + shaderData->muFixedColormapStart.Init(shaderData->hShader, "uFixedColormapStart"); + shaderData->muFixedColormapRange.Init(shaderData->hShader, "uFixedColormapRange"); + + shaderData->lights_index = glGetUniformLocation(shaderData->hShader, "lights"); + shaderData->bones_index = glGetUniformLocation(shaderData->hShader, "bones"); + shaderData->modelmatrix_index = glGetUniformLocation(shaderData->hShader, "ModelMatrix"); + shaderData->texturematrix_index = glGetUniformLocation(shaderData->hShader, "TextureMatrix"); + shaderData->normalmodelmatrix_index = glGetUniformLocation(shaderData->hShader, "NormalModelMatrix"); + + + glUseProgram(shaderData->hShader); + + // set up other texture units (if needed by the shader) + for (int i = 2; i<16; i++) + { + char stringbuf[20]; + mysnprintf(stringbuf, 20, "texture%d", i); + int tempindex = glGetUniformLocation(shaderData->hShader, stringbuf); + if (tempindex >= 0) glUniform1i(tempindex, i - 1); + } + + int shadowmapindex = glGetUniformLocation(shaderData->hShader, "ShadowMap"); + if (shadowmapindex >= 0) glUniform1i(shadowmapindex, 16); + + glUseProgram(0); + + cur = shaderData; + + return linked; +} + +//========================================================================== +// +// +// +//========================================================================== + +FShader::~FShader() +{ + std::map::iterator it = variants.begin(); + + while (it != variants.end()) + { + glDeleteProgram(it->second->hShader); + if (it->second->hVertProg != 0) + glDeleteShader(it->second->hVertProg); + if (it->second->hFragProg != 0) + glDeleteShader(it->second->hFragProg); + it++; + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +bool FShader::Bind(ShaderFlavourData& flavour) +{ + uint32_t tag = CreateShaderTag(flavour); + + auto pos = variants.find(tag); + + if (pos == variants.end()) + { + FString variantConfig = "\n"; + + variantConfig.AppendFormat("#define MAXIMUM_LIGHT_VECTORS %d\n", gles.numlightvectors); + variantConfig.AppendFormat("#define DEF_TEXTURE_MODE %d\n", flavour.textureMode); + variantConfig.AppendFormat("#define DEF_TEXTURE_FLAGS %d\n", flavour.texFlags); + variantConfig.AppendFormat("#define DEF_BLEND_FLAGS %d\n", flavour.blendFlags & 0x7); + variantConfig.AppendFormat("#define DEF_FOG_2D %d\n", flavour.twoDFog); + variantConfig.AppendFormat("#define DEF_FOG_ENABLED %d\n", flavour.fogEnabled); + variantConfig.AppendFormat("#define DEF_FOG_RADIAL %d\n", flavour.fogEquationRadial); + variantConfig.AppendFormat("#define DEF_FOG_COLOURED %d\n", flavour.colouredFog); + variantConfig.AppendFormat("#define DEF_USE_U_LIGHT_LEVEL %d\n", flavour.useULightLevel); + + variantConfig.AppendFormat("#define DEF_DO_DESATURATE %d\n", flavour.doDesaturate); + + variantConfig.AppendFormat("#define DEF_DYNAMIC_LIGHTS_MOD %d\n", flavour.dynLightsMod); + variantConfig.AppendFormat("#define DEF_DYNAMIC_LIGHTS_SUB %d\n", flavour.dynLightsSub); + variantConfig.AppendFormat("#define DEF_DYNAMIC_LIGHTS_ADD %d\n", flavour.dynLightsAdd); + + variantConfig.AppendFormat("#define DEF_USE_OBJECT_COLOR_2 %d\n", flavour.useObjectColor2); + variantConfig.AppendFormat("#define DEF_USE_GLOW_TOP_COLOR %d\n", flavour.useGlowTopColor); + variantConfig.AppendFormat("#define DEF_USE_GLOW_BOTTOM_COLOR %d\n", flavour.useGlowBottomColor); + + variantConfig.AppendFormat("#define DEF_USE_COLOR_MAP %d\n", flavour.useColorMap); + variantConfig.AppendFormat("#define DEF_BUILD_LIGHTING %d\n", flavour.buildLighting); + variantConfig.AppendFormat("#define DEF_BANDED_SW_LIGHTING %d\n", flavour.bandedSwLight); + + variantConfig.AppendFormat("#define USE_GLSL_V100 %d\n", gles.forceGLSLv100); + +#ifdef NPOT_EMULATION + variantConfig.AppendFormat("#define DEF_NPOT_EMULATION %d\n", flavour.npotEmulation); +#endif + + variantConfig.AppendFormat("#define DEF_HAS_SPOTLIGHT %d\n", flavour.hasSpotLight); + variantConfig.AppendFormat("#define DEF_PALETTE_INTERPOLATE %d\n", flavour.paletteInterpolate); + + //Printf("Shader: %s, %08x %s", mFragProg2.GetChars(), tag, variantConfig.GetChars()); + + Load(mName.GetChars(), mVertProg.GetChars(), mFragProg.GetChars(), mFragProg2.GetChars(), mLightProg.GetChars(), (mDefinesBase + variantConfig).GetChars()); + variants.insert(std::make_pair(tag, cur)); + } + else + { + cur = pos->second; + } + + GLRenderer->mShaderManager->SetActiveShader(this->cur); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType) +{ + FString defines; + defines += shaderdefines; + // this can't be in the shader code due to ATI strangeness. + if (!usediscard) defines += "#define NO_ALPHATEST\n"; + + FShader *shader = new FShader(ShaderName); + shader->Configure(ShaderName, "shaders_gles/glsl/main.vp", "shaders_gles/glsl/main.fp", ShaderPath, LightModePath, defines.GetChars()); + return shader; +} + +//========================================================================== +// +// +// +//========================================================================== + +FShaderManager::FShaderManager() +{ + for (int passType = 0; passType < MAX_PASS_TYPES; passType++) + mPassShaders.Push(new FShaderCollection((EPassType)passType)); +} + +FShaderManager::~FShaderManager() +{ + glUseProgram(0); + mActiveShader = NULL; + + for (auto collection : mPassShaders) + delete collection; +} + +void FShaderManager::SetActiveShader(FShader::ShaderVariantData *sh) +{ + if (mActiveShader != sh) + { + glUseProgram(sh!= NULL? sh->GetHandle() : 0); + mActiveShader = sh; + } +} + +FShader *FShaderManager::BindEffect(int effect, EPassType passType, ShaderFlavourData &flavour) +{ + if (passType < mPassShaders.Size()) + return mPassShaders[passType]->BindEffect(effect, flavour); + else + return nullptr; +} + +FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) +{ + if (passType < mPassShaders.Size()) + return mPassShaders[passType]->Get(eff, alphateston); + else + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +FShaderCollection::FShaderCollection(EPassType passType) +{ + CompileShaders(passType); +} + +//========================================================================== +// +// +// +//========================================================================== + +FShaderCollection::~FShaderCollection() +{ + Clean(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FShaderCollection::CompileShaders(EPassType passType) +{ + mMaterialShaders.Clear(); + mMaterialShadersNAT.Clear(); + for (int i = 0; i < MAX_EFFECTS; i++) + { + mEffectShaders[i] = NULL; + } + + for(int i=0;defaultshaders[i].ShaderName != NULL;i++) + { + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, passType); + mMaterialShaders.Push(shc); + if (i < SHADER_NoTexture) + { + shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, passType); + mMaterialShadersNAT.Push(shc); + } + } + +#if 0 + for(unsigned i = 0; i < usershaders.Size(); i++) + { + FString name = ExtractFileBase(usershaders[i].shader); + FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines; + FShader *shc = Compile(name, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, passType); + mMaterialShaders.Push(shc); + } +#endif + + for(int i=0;iConfigure(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1, + effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines)) + { + delete eff; + } + else mEffectShaders[i] = eff; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FShaderCollection::Clean() +{ + for (unsigned int i = 0; i < mMaterialShadersNAT.Size(); i++) + { + if (mMaterialShadersNAT[i] != NULL) delete mMaterialShadersNAT[i]; + } + for (unsigned int i = 0; i < mMaterialShaders.Size(); i++) + { + if (mMaterialShaders[i] != NULL) delete mMaterialShaders[i]; + } + for (int i = 0; i < MAX_EFFECTS; i++) + { + if (mEffectShaders[i] != NULL) delete mEffectShaders[i]; + mEffectShaders[i] = NULL; + } + mMaterialShaders.Clear(); + mMaterialShadersNAT.Clear(); +} + +//========================================================================== +// +// +// +//========================================================================== + +int FShaderCollection::Find(const char * shn) +{ + FName sfn = shn; + + for(unsigned int i=0;imName == sfn) + { + return i; + } + } + return -1; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FShader *FShaderCollection::BindEffect(int effect, ShaderFlavourData& flavour) +{ + if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL) + { + mEffectShaders[effect]->Bind(flavour); + return mEffectShaders[effect]; + } + return NULL; +} + + +//========================================================================== +// +// +// +//========================================================================== + +void gl_DestroyUserShaders() +{ + // todo +} + +} diff --git a/src/common/rendering/gles/gles_shader.h b/src/common/rendering/gles/gles_shader.h new file mode 100644 index 00000000000..31ebffa39b1 --- /dev/null +++ b/src/common/rendering/gles/gles_shader.h @@ -0,0 +1,495 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2004-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#ifndef __GL_SHADERS_H__ +#define __GL_SHADERS_H__ + +#include + +#include "gles_renderstate.h" +#include "name.h" + +extern bool gl_shaderactive; + +struct HWViewpointUniforms; + +namespace OpenGLESRenderer +{ + class FShaderCollection; + +//========================================================================== +// +// +//========================================================================== + +class FUniform1i +{ + int mIndex; + +public: + void Init(GLuint hShader, const GLchar *name) + { + mIndex = glGetUniformLocation(hShader, name); + } + + void Set(int newvalue) + { + glUniform1i(mIndex, newvalue); + } +}; + +class FBufferedUniform1i +{ + int mBuffer; + int mIndex; + +public: + void Init(GLuint hShader, const GLchar *name) + { + mIndex = glGetUniformLocation(hShader, name); + mBuffer = 0; + } + + void Set(int newvalue) + { + if (newvalue != mBuffer) + { + mBuffer = newvalue; + glUniform1i(mIndex, newvalue); + } + } +}; + +class FBufferedUniform4i +{ + int mBuffer[4]; + int mIndex; + +public: + void Init(GLuint hShader, const GLchar *name) + { + mIndex = glGetUniformLocation(hShader, name); + memset(mBuffer, 0, sizeof(mBuffer)); + } + + void Set(const int *newvalue) + { + if (memcmp(newvalue, mBuffer, sizeof(mBuffer))) + { + memcpy(mBuffer, newvalue, sizeof(mBuffer)); + glUniform4iv(mIndex, 1, newvalue); + } + } +}; + +class FBufferedUniform1f +{ + float mBuffer; + int mIndex; + +public: + void Init(GLuint hShader, const GLchar *name) + { + mIndex = glGetUniformLocation(hShader, name); + mBuffer = 0; + } + + void Set(float newvalue) + { + if (newvalue != mBuffer) + { + mBuffer = newvalue; + glUniform1f(mIndex, newvalue); + } + } +}; + +class FBufferedUniform2f +{ + float mBuffer[2]; + int mIndex; + +public: + void Init(GLuint hShader, const GLchar *name) + { + mIndex = glGetUniformLocation(hShader, name); + memset(mBuffer, 0, sizeof(mBuffer)); + } + + void Set(const float *newvalue) + { + if (memcmp(newvalue, mBuffer, sizeof(mBuffer))) + { + memcpy(mBuffer, newvalue, sizeof(mBuffer)); + glUniform2fv(mIndex, 1, newvalue); + } + } + + void Set(float f1, float f2) + { + if (mBuffer[0] != f1 || mBuffer[1] != f2) + { + mBuffer[0] = f1; + mBuffer[1] = f2; + glUniform2fv(mIndex, 1, mBuffer); + } + } + +}; + +class FBufferedUniform4f +{ + float mBuffer[4]; + int mIndex; + +public: + void Init(GLuint hShader, const GLchar *name) + { + mIndex = glGetUniformLocation(hShader, name); + memset(mBuffer, 0, sizeof(mBuffer)); + } + + void Set(const float *newvalue) + { + if (memcmp(newvalue, mBuffer, sizeof(mBuffer))) + { + memcpy(mBuffer, newvalue, sizeof(mBuffer)); + glUniform4fv(mIndex, 1, newvalue); + } + } +}; + +class FUniform4f +{ + int mIndex; + +public: + void Init(GLuint hShader, const GLchar *name) + { + mIndex = glGetUniformLocation(hShader, name); + } + + void Set(const float *newvalue) + { + glUniform4fv(mIndex, 1, newvalue); + } + + void Set(float a, float b, float c, float d) + { + glUniform4f(mIndex, a, b, c, d); + } + + void Set(PalEntry newvalue) + { + glUniform4f(mIndex, newvalue.r / 255.f, newvalue.g / 255.f, newvalue.b / 255.f, newvalue.a / 255.f); + } + +}; + +class FBufferedUniformPE +{ + FVector4PalEntry mBuffer; + int mIndex; + +public: + void Init(GLuint hShader, const GLchar *name) + { + mIndex = glGetUniformLocation(hShader, name); + mBuffer = 0; + } + + void Set(const FVector4PalEntry &newvalue) + { + if (newvalue != mBuffer) + { + mBuffer = newvalue; + glUniform4f(mIndex, newvalue.r, newvalue.g, newvalue.b, newvalue.a); + } + } +}; + +class FBufferedUniformMat4fv +{ + VSMatrix mBuffer; + int mIndex; + +public: + void Init(GLuint hShader, const GLchar* name) + { + mIndex = glGetUniformLocation(hShader, name); + mBuffer = 0; + } + + void Set(const VSMatrix* newvalue) + { + //if (memcmp(newvalue, &mBuffer, sizeof(mBuffer))) // Breaks 2D menu for some reason.. + { + mBuffer = *newvalue; + glUniformMatrix4fv(mIndex, 1, false, (float*)newvalue); + } + } +}; + +class ShaderFlavourData +{ +public: + int textureMode; + int texFlags; + int blendFlags; + bool twoDFog; + bool fogEnabled; + bool fogEquationRadial; + bool colouredFog; + bool doDesaturate; + bool dynLightsMod; + bool dynLightsSub; + bool dynLightsAdd; + bool useULightLevel; + bool useObjectColor2; + bool useGlowTopColor; + bool useGlowBottomColor; + bool useColorMap; + + bool buildLighting; + bool bandedSwLight; + +#ifdef NPOT_EMULATION + bool npotEmulation; +#endif + + bool hasSpotLight; + bool paletteInterpolate; +}; + +class FShader +{ + friend class FShaderCollection; + friend class FGLRenderState; + + FName mName; + + FString mVertProg; + FString mFragProg; + FString mFragProg2; + FString mLightProg; + FString mDefinesBase; + + ///// +public: class ShaderVariantData + { + public: + + unsigned int hShader = 0; + unsigned int hVertProg = 0; + unsigned int hFragProg = 0; + + //int ProjectionMatrix_index = 0; + //int ViewMatrix_index = 0; + //int NormalViewMatrix_index = 0; + + FBufferedUniformMat4fv muProjectionMatrix; + FBufferedUniformMat4fv muViewMatrix; + FBufferedUniformMat4fv muNormalViewMatrix; + + FUniform4f muCameraPos; + FUniform4f muClipLine; + + FBufferedUniform1f muGlobVis; + FBufferedUniform1i muPalLightLevels; + FBufferedUniform1i muViewHeight; + FBufferedUniform1f muClipHeight; + FBufferedUniform1f muClipHeightDirection; + FBufferedUniform1i muShadowmapFilter; + ///// + + FBufferedUniform1f muDesaturation; + FBufferedUniform1i muFogEnabled; + FBufferedUniform1i muTextureMode; + FBufferedUniform4f muLightParms; + FBufferedUniform2f muClipSplit; + FBufferedUniform1i muBoneIndexBase; + FBufferedUniform4i muLightRange; + FBufferedUniformPE muFogColor; + FBufferedUniform4f muDynLightColor; + FBufferedUniformPE muObjectColor; + FBufferedUniformPE muObjectColor2; + FBufferedUniformPE muAddColor; + FBufferedUniformPE muTextureBlendColor; + FBufferedUniformPE muTextureModulateColor; + FBufferedUniformPE muTextureAddColor; + FUniform4f muGlowBottomColor; + FUniform4f muGlowTopColor; + FUniform4f muGlowBottomPlane; + FUniform4f muGlowTopPlane; + FUniform4f muGradientBottomPlane; + FUniform4f muGradientTopPlane; + FUniform4f muSplitBottomPlane; + FUniform4f muSplitTopPlane; + FUniform4f muDetailParms; + FBufferedUniform1f muInterpolationFactor; + FBufferedUniform1f muAlphaThreshold; + FBufferedUniform2f muSpecularMaterial; + FBufferedUniform1f muTimer; +#ifdef NPOT_EMULATION + FBufferedUniform2f muNpotEmulation; +#endif + FUniform4f muFixedColormapStart; + FUniform4f muFixedColormapRange; + + + int lights_index = 0; + int bones_index = 0; + int modelmatrix_index = 0; + int normalmodelmatrix_index = 0; + int texturematrix_index = 0; + + int currentglowstate = 0; + int currentgradientstate = 0; + int currentsplitstate = 0; + int currentcliplinestate = 0; + int currentfixedcolormap = 0; + bool currentTextureMatrixState = true;// by setting the matrix state to 'true' it is guaranteed to be set the first time the render state gets applied. + bool currentModelMatrixState = true; + + unsigned int GetHandle() const { return hShader; } + }; + + std::map variants; + + ShaderVariantData* cur = 0; + +public: + FShader(const char *name) + : mName(name) + { + + } + + ~FShader(); + + bool Load(const char * name, const char * vert_prog_lump, const char * fragprog, const char * fragprog2, const char * light_fragprog, const char *defines); + bool Configure(const char* name, const char* vert_prog_lump, const char* fragprog, const char* fragprog2, const char* light_fragprog, const char* defines); + + void LoadVariant(); + + + uint32_t CreateShaderTag(ShaderFlavourData &flavour) + { + uint32_t tag = 0; + tag |= (flavour.textureMode & 0x7); + + tag |= (flavour.texFlags & 7) << 3; + + tag |= (flavour.blendFlags & 7) << 6; + + tag |= (flavour.twoDFog & 1) << 7; + tag |= (flavour.fogEnabled & 1) << 8; + tag |= (flavour.fogEquationRadial & 1) << 9; + tag |= (flavour.colouredFog & 1) << 10; + + tag |= (flavour.doDesaturate & 1) << 11; + + tag |= (flavour.dynLightsMod & 1) << 12; + tag |= (flavour.dynLightsSub & 1) << 13; + tag |= (flavour.dynLightsAdd & 1) << 14; + tag |= (flavour.useULightLevel & 1) << 15; + tag |= (flavour.useObjectColor2 & 1) << 16; + tag |= (flavour.useGlowTopColor & 1) << 17; + tag |= (flavour.useGlowBottomColor & 1) << 18; + tag |= (flavour.useColorMap & 1) << 19; + tag |= (flavour.buildLighting & 1) << 20; + tag |= (flavour.bandedSwLight & 1) << 21; + +#ifdef NPOT_EMULATION + tag |= (flavour.npotEmulation & 1) << 22; +#endif + tag |= (flavour.hasSpotLight & 1) << 23; + tag |= (flavour.paletteInterpolate & 1) << 24; + + return tag; + } + + bool Bind(ShaderFlavourData& flavour); + + +}; + +//========================================================================== +// +// The global shader manager +// +//========================================================================== +class FShaderManager +{ +public: + FShaderManager(); + ~FShaderManager(); + + FShader *BindEffect(int effect, EPassType passType, ShaderFlavourData& flavour); + FShader *Get(unsigned int eff, bool alphateston, EPassType passType); + + void SetActiveShader(FShader::ShaderVariantData *sh); +private: + + FShader::ShaderVariantData *mActiveShader = nullptr; + TArray mPassShaders; + + friend class FShader; +}; + +class FShaderCollection +{ + TArray mMaterialShaders; + TArray mMaterialShadersNAT; + FShader *mEffectShaders[MAX_EFFECTS]; + + void Clean(); + void CompileShaders(EPassType passType); + +public: + FShaderCollection(EPassType passType); + ~FShaderCollection(); + FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType); + int Find(const char *mame); + FShader *BindEffect(int effect, ShaderFlavourData& flavour); + + FShader *Get(unsigned int eff, bool alphateston) + { + // indices 0-2 match the warping modes, 3 no texture, the following are custom + if (!alphateston && eff <= 2) + { + return mMaterialShadersNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway + } + if (eff < mMaterialShaders.Size()) + { + return mMaterialShaders[eff]; + } + else // This can happen if we try and active a user shader which is not loaded, so return default shader so it does not crash + { + return mMaterialShaders[0]; + } + } +}; + +} +#endif + diff --git a/src/common/rendering/gles/gles_shaderprogram.cpp b/src/common/rendering/gles/gles_shaderprogram.cpp new file mode 100644 index 00000000000..efc94c71dff --- /dev/null +++ b/src/common/rendering/gles/gles_shaderprogram.cpp @@ -0,0 +1,294 @@ +/* +** Postprocessing framework +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "gles_system.h" +#include "v_video.h" +#include "hw_cvars.h" +#include "gles_shaderprogram.h" +#include "hw_shaderpatcher.h" +#include "filesystem.h" +#include "printf.h" +#include "cmdlib.h" + +namespace OpenGLESRenderer +{ + +FString GetGLSLPrecision(); + +bool IsShaderCacheActive(); +TArray LoadCachedProgramBinary(const FString &vertex, const FString &fragment, uint32_t &binaryFormat); +void SaveCachedProgramBinary(const FString &vertex, const FString &fragment, const TArray &binary, uint32_t binaryFormat); + +FShaderProgram::FShaderProgram() +{ + for (int i = 0; i < NumShaderTypes; i++) + mShaders[i] = 0; +} + +//========================================================================== +// +// Free shader program resources +// +//========================================================================== + +FShaderProgram::~FShaderProgram() +{ + if (mProgram != 0) + glDeleteProgram(mProgram); + + for (int i = 0; i < NumShaderTypes; i++) + { + if (mShaders[i] != 0) + glDeleteShader(mShaders[i]); + } +} + +//========================================================================== +// +// Creates an OpenGL shader object for the specified type of shader +// +//========================================================================== + +void FShaderProgram::CreateShader(ShaderType type) +{ + GLenum gltype = 0; + switch (type) + { + default: + case Vertex: gltype = GL_VERTEX_SHADER; break; + case Fragment: gltype = GL_FRAGMENT_SHADER; break; + } + mShaders[type] = glCreateShader(gltype); +} + +//========================================================================== +// +// Compiles a shader and attaches it the program object +// +//========================================================================== + +void FShaderProgram::Compile(ShaderType type, const char *lumpName, const char *defines, int maxGlslVersion) +{ + int lump = fileSystem.CheckNumForFullName(lumpName); + if (lump == -1) I_FatalError("Unable to load '%s'", lumpName); + FString code = GetStringFromLump(lump); + Compile(type, lumpName, code, defines, maxGlslVersion); +} + +void FShaderProgram::Compile(ShaderType type, const char *name, const FString &code, const char *defines, int maxGlslVersion) +{ + mShaderNames[type] = name; + mShaderSources[type] = PatchShader(type, code, defines, maxGlslVersion); +} + +void FShaderProgram::CompileShader(ShaderType type) +{ + CreateShader(type); + + const auto &handle = mShaders[type]; + + + const FString &patchedCode = mShaderSources[type]; + int lengths[1] = { (int)patchedCode.Len() }; + const char *sources[1] = { patchedCode.GetChars() }; + glShaderSource(handle, 1, sources, lengths); + + glCompileShader(handle); + + GLint status = 0; + glGetShaderiv(handle, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) + { + I_FatalError("Compile Shader '%s':\n%s\n", mShaderNames[type].GetChars(), GetShaderInfoLog(handle).GetChars()); + } + else + { + if (mProgram == 0) + mProgram = glCreateProgram(); + glAttachShader(mProgram, handle); + } +} + +//========================================================================== +// +// Links a program with the compiled shaders +// +//========================================================================== + +void FShaderProgram::Link(const char *name) +{ + + uint32_t binaryFormat = 0; + TArray binary; + if (IsShaderCacheActive()) + binary = LoadCachedProgramBinary(mShaderSources[Vertex], mShaderSources[Fragment], binaryFormat); + + bool loadedFromBinary = false; + + if (!loadedFromBinary) + { + CompileShader(Vertex); + CompileShader(Fragment); + + glLinkProgram(mProgram); + + GLint status = 0; + glGetProgramiv(mProgram, GL_LINK_STATUS, &status); + if (status == GL_FALSE) + { + I_FatalError("Link Shader '%s':\n%s\n", name, GetProgramInfoLog(mProgram).GetChars()); + } + } + + // This is only for old OpenGL which didn't allow to set the binding from within the shader. + if (screen->glslversion < 4.20) + { + glUseProgram(mProgram); + for (auto &uni : samplerstobind) + { + auto index = glGetUniformLocation(mProgram, uni.first.GetChars()); + if (index >= 0) + { + glUniform1i(index, uni.second); + } + } + } + samplerstobind.Clear(); + samplerstobind.ShrinkToFit(); +} + +//========================================================================== +// +// Set uniform buffer location (only useful for GL 3.3) +// +//========================================================================== + +void FShaderProgram::SetUniformBufferLocation(int index, const char *name) +{ + +} + +//========================================================================== +// +// Makes the shader the active program +// +//========================================================================== + +void FShaderProgram::Bind() +{ + glUseProgram(mProgram); +} + +//========================================================================== +// +// Returns the shader info log (warnings and compile errors) +// +//========================================================================== + +FString FShaderProgram::GetShaderInfoLog(GLuint handle) +{ + static char buffer[10000]; + GLsizei length = 0; + buffer[0] = 0; + glGetShaderInfoLog(handle, 10000, &length, buffer); + return FString(buffer); +} + +//========================================================================== +// +// Returns the program info log (warnings and compile errors) +// +//========================================================================== + +FString FShaderProgram::GetProgramInfoLog(GLuint handle) +{ + static char buffer[10000]; + GLsizei length = 0; + buffer[0] = 0; + glGetProgramInfoLog(handle, 10000, &length, buffer); + return FString(buffer); +} + +//========================================================================== +// +// Patches a shader to be compatible with the version of OpenGL in use +// +//========================================================================== + +FString FShaderProgram::PatchShader(ShaderType type, const FString &code, const char *defines, int maxGlslVersion) +{ + FString patchedCode; + + patchedCode.AppendFormat("#version %s\n", gles.shaderVersionString); + + patchedCode += GetGLSLPrecision(); + + + if (defines) + patchedCode << defines; + + + patchedCode << "#line 1\n"; + patchedCode << RemoveLayoutLocationDecl(code, type == Vertex ? "out" : "in"); + + if (maxGlslVersion < 420) + { + // Here we must strip out all layout(binding) declarations for sampler uniforms and store them in 'samplerstobind' which can then be processed by the link function. + patchedCode = RemoveSamplerBindings(patchedCode, samplerstobind); + } + + return patchedCode; +} + +///////////////////////////////////////////////////////////////////////////// + +void FPresentShaderBase::Init(const char * vtx_shader_name, const char * program_name) +{ + FString prolog = Uniforms.CreateDeclaration("Uniforms", PresentUniforms::Desc()); + + mShader.reset(new FShaderProgram()); + mShader->Compile(FShaderProgram::Vertex, "shaders_gles/pp/screenquad.vp", prolog.GetChars(), 330); + mShader->Compile(FShaderProgram::Fragment, vtx_shader_name, prolog.GetChars(), 330); + mShader->Link(program_name); + mShader->Bind(); + Uniforms.Init(); + + Uniforms.UniformLocation.resize(Uniforms.mFields.size()); + + for (size_t n = 0; n < Uniforms.mFields.size(); n++) + { + int index = -1; + UniformFieldDesc desc = Uniforms.mFields[n]; + index = glGetUniformLocation(mShader->mProgram, desc.Name); + Uniforms.UniformLocation[n] = index; + } +} + +void FPresentShader::Bind() +{ + if (!mShader) + { + Init("shaders_gles/pp/present.fp", "shaders_gles/pp/present"); + } + mShader->Bind(); +} + +} diff --git a/src/common/rendering/gles/gles_shaderprogram.h b/src/common/rendering/gles/gles_shaderprogram.h new file mode 100644 index 00000000000..e464180546d --- /dev/null +++ b/src/common/rendering/gles/gles_shaderprogram.h @@ -0,0 +1,159 @@ + +#pragma once + +#include "gles_system.h" +#include "gles_shader.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" + +namespace OpenGLESRenderer +{ + +class FShaderProgram : public PPShaderBackend +{ +public: + FShaderProgram(); + ~FShaderProgram(); + + enum ShaderType + { + Vertex, + Fragment, + NumShaderTypes + }; + + void Compile(ShaderType type, const char *lumpName, const char *defines, int maxGlslVersion); + void Compile(ShaderType type, const char *name, const FString &code, const char *defines, int maxGlslVersion); + void Link(const char *name); + void SetUniformBufferLocation(int index, const char *name); + + void Bind(); + + GLuint Handle() { return mProgram; } + //explicit operator bool() const { return mProgram != 0; } + + std::unique_ptr Uniforms; + GLuint mProgram = 0; +private: + FShaderProgram(const FShaderProgram &) = delete; + FShaderProgram &operator=(const FShaderProgram &) = delete; + + void CompileShader(ShaderType type); + FString PatchShader(ShaderType type, const FString &code, const char *defines, int maxGlslVersion); + + void CreateShader(ShaderType type); + FString GetShaderInfoLog(GLuint handle); + FString GetProgramInfoLog(GLuint handle); + + + GLuint mShaders[NumShaderTypes]; + FString mShaderSources[NumShaderTypes]; + FString mShaderNames[NumShaderTypes]; + TArray> samplerstobind; +}; + +template +class ShaderUniformsGles +{ +public: + ShaderUniformsGles() + { + memset(&Values, 0, sizeof(Values)); + } + + ~ShaderUniformsGles() + { + if (mBuffer != nullptr) + delete mBuffer; + } + + FString CreateDeclaration(const char* name, const std::vector& fields) + { + mFields = fields; + FString decl; + decl += "\n"; + for (size_t i = 0; i < fields.size(); i++) + { + decl.AppendFormat("\tuniform %s %s;\n", GetTypeStr(fields[i].Type), fields[i].Name); + } + decl += "\n"; + return decl; + } + + void Init() + { + if (mBuffer == nullptr) + mBuffer = screen->CreateDataBuffer(-1, false, false); + } + + void SetData() + { + if (mBuffer != nullptr) + mBuffer->SetData(sizeof(T), &Values, BufferUsageType::Static); + } + + IDataBuffer* GetBuffer() const + { + // OpenGL needs to mess around with this in ways that should not be part of the interface. + return mBuffer; + } + + T* operator->() { return &Values; } + const T* operator->() const { return &Values; } + + T Values; + + std::vector mFields; + std::vector UniformLocation; + +private: + ShaderUniformsGles(const ShaderUniformsGles&) = delete; + ShaderUniformsGles& operator=(const ShaderUniformsGles&) = delete; + + IDataBuffer* mBuffer = nullptr; + +private: + static const char* GetTypeStr(UniformType type) + { + switch (type) + { + default: + case UniformType::Int: return "int"; + case UniformType::UInt: return "uint"; + case UniformType::Float: return "float"; + case UniformType::Vec2: return "vec2"; + case UniformType::Vec3: return "vec3"; + case UniformType::Vec4: return "vec4"; + case UniformType::IVec2: return "ivec2"; + case UniformType::IVec3: return "ivec3"; + case UniformType::IVec4: return "ivec4"; + case UniformType::UVec2: return "uvec2"; + case UniformType::UVec3: return "uvec3"; + case UniformType::UVec4: return "uvec4"; + case UniformType::Mat4: return "mat4"; + } + } +}; + + +class FPresentShaderBase +{ +public: + virtual ~FPresentShaderBase() {} + virtual void Bind() = 0; + + ShaderUniformsGles Uniforms; + +protected: + virtual void Init(const char * vtx_shader_name, const char * program_name); + std::unique_ptr mShader; +}; + +class FPresentShader : public FPresentShaderBase +{ +public: + void Bind() override; + +}; + + +} \ No newline at end of file diff --git a/src/common/rendering/gles/gles_system.cpp b/src/common/rendering/gles/gles_system.cpp new file mode 100644 index 00000000000..d9bedafdd70 --- /dev/null +++ b/src/common/rendering/gles/gles_system.cpp @@ -0,0 +1,237 @@ + + +#include "gles_system.h" +#include "tarray.h" +#include "v_video.h" +#include "printf.h" + +CVAR(Bool, gles_use_mapped_buffer, false, 0); +CVAR(Bool, gles_force_glsl_v100, false, 0); +CVAR(Int, gles_max_lights_per_surface, 32, 0); +EXTERN_CVAR(Bool, gl_customshader); +void setGlVersion(double glv); + + +#if USE_GLAD_LOADER + +PFNGLMAPBUFFERRANGEEXTPROC glMapBufferRange = NULL; +PFNGLUNMAPBUFFEROESPROC glUnmapBuffer = NULL; +PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = NULL; +PFNGLFENCESYNCPROC glFenceSync = NULL; +PFNGLCLIENTWAITSYNCPROC glClientWaitSync = NULL; +PFNGLDELETESYNCPROC glDeleteSync = NULL; + +#if defined _WIN32 + +#include + +static HMODULE opengl32dll; +static PROC(WINAPI* getprocaddress)(LPCSTR name); + +static void* LoadGLES2Proc(const char* name) +{ + HINSTANCE hGetProcIDDLL = LoadLibraryA("libGLESv2.dll"); + + int error = GetLastError(); + + void* addr = GetProcAddress(hGetProcIDDLL, name); + if (!addr) + { + //exit(1); + return nullptr; + } + else + { + return addr; + } +} + +#else + +#include + +static void* LoadGLES2Proc(const char* name) +{ + static void* glesLib = NULL; + + if (!glesLib) + { + int flags = RTLD_LOCAL | RTLD_NOW; + + glesLib = dlopen("libGLESv2_CM.so", flags); + if (!glesLib) + { + glesLib = dlopen("libGLESv2.so", flags); + } + if (!glesLib) + { + glesLib = dlopen("libGLESv2.so.2", flags); + } + } + + void* ret = NULL; + ret = dlsym(glesLib, name); + + return ret; +} + +#endif + +#endif // USE_GLAD_LOADER + +static TArray m_Extensions; + + +static void CollectExtensions() +{ + const char* supported = (char*)glGetString(GL_EXTENSIONS); + + if (nullptr != supported) + { + char* extensions = new char[strlen(supported) + 1]; + strcpy(extensions, supported); + + char* extension = strtok(extensions, " "); + + while (extension) + { + m_Extensions.Push(FString(extension)); + extension = strtok(nullptr, " "); + } + + delete[] extensions; + } +} + + +static bool CheckExtension(const char* ext) +{ + for (unsigned int i = 0; i < m_Extensions.Size(); ++i) + { + if (m_Extensions[i].CompareNoCase(ext) == 0) return true; + } + + return false; +} + +namespace OpenGLESRenderer +{ + RenderContextGLES gles; + + void InitGLES() + { + +#if USE_GLAD_LOADER + + if (!gladLoadGLES2Loader(&LoadGLES2Proc)) + { + exit(-1); + } + + glMapBufferRange = (PFNGLMAPBUFFERRANGEEXTPROC)LoadGLES2Proc("glMapBufferRange"); + glUnmapBuffer = (PFNGLUNMAPBUFFEROESPROC)LoadGLES2Proc("glUnmapBuffer"); + glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)LoadGLES2Proc("glVertexAttribIPointer"); + + glFenceSync = (PFNGLFENCESYNCPROC)LoadGLES2Proc("glFenceSync"); + glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)LoadGLES2Proc("glClientWaitSync"); + glDeleteSync = (PFNGLDELETESYNCPROC)LoadGLES2Proc("glDeleteSync"); +#else + static bool first = true; + + if (first) + { + if (ogl_LoadFunctions() == ogl_LOAD_FAILED) + { + //I_FatalError("Failed to load OpenGL functions."); + } + } + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); +#endif + CollectExtensions(); + + Printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR)); + Printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER)); + Printf("GL_VERSION: %s\n", glGetString(GL_VERSION)); + Printf("GL_SHADING_LANGUAGE_VERSION: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + Printf(PRINT_LOG, "GL_EXTENSIONS:\n"); + for (unsigned i = 0; i < m_Extensions.Size(); i++) + { + Printf(PRINT_LOG, " %s\n", m_Extensions[i].GetChars()); + } + const char* glVersionStr = (const char*)glGetString(GL_VERSION); + double glVersion = strtod(glVersionStr, NULL); + + Printf("GL Version parsed = %f\n", glVersion); + + gles.flags = RFL_NO_CLIP_PLANES; + + gles.useMappedBuffers = gles_use_mapped_buffer; + gles.forceGLSLv100 = gles_force_glsl_v100; + gles.maxlights = gles_max_lights_per_surface; + gles.numlightvectors = (gles.maxlights * LIGHT_VEC4_NUM); + + gles.modelstring = (char*)glGetString(GL_RENDERER); + gles.vendorstring = (char*)glGetString(GL_VENDOR); + + + gl_customshader = false; // Disable user shaders for GLES renderer + + GLint maxTextureSize[1]; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxTextureSize); + gles.max_texturesize = maxTextureSize[0]; + + Printf("GL_MAX_TEXTURE_SIZE: %d\n", gles.max_texturesize); + + + // Check if running on a GLES device, version string will start with 'OpenGL ES' + if (!strncmp(glVersionStr, "OpenGL ES", strlen("OpenGL ES"))) + { + gles.glesMode = GLES_MODE_GLES; + } + else // Else runnning on Desktop, check OpenGL version is 3 or above + { + if (glVersion > 3.29) + gles.glesMode = GLES_MODE_OGL3; // 3.3 or above + else + gles.glesMode = GLES_MODE_OGL2; // Below 3.3 + } + + + if (gles.glesMode == GLES_MODE_GLES) + { + Printf("GLES choosing mode: GLES_MODE_GLES\n"); + + gles.shaderVersionString = "100"; + gles.depthStencilAvailable = CheckExtension("GL_OES_packed_depth_stencil"); + gles.npotAvailable = CheckExtension("GL_OES_texture_npot"); + gles.depthClampAvailable = CheckExtension("GL_EXT_depth_clamp"); + gles.anistropicFilterAvailable = CheckExtension("GL_EXT_texture_filter_anisotropic"); + } + else if (gles.glesMode == GLES_MODE_OGL2) + { + Printf("GLES choosing mode: GLES_MODE_OGL2\n"); + + gles.shaderVersionString = "100"; + gles.depthStencilAvailable = true; + gles.npotAvailable = true; + gles.useMappedBuffers = true; + gles.depthClampAvailable = true; + gles.anistropicFilterAvailable = true; + } + else if (gles.glesMode == GLES_MODE_OGL3) + { + Printf("GLES choosing mode: GLES_MODE_OGL3\n"); + + gles.shaderVersionString = "330"; + gles.depthStencilAvailable = true; + gles.npotAvailable = true; + gles.useMappedBuffers = true; + gles.depthClampAvailable = true; + gles.anistropicFilterAvailable = true; + } + + setGlVersion(glVersion); + } +} diff --git a/src/common/rendering/gles/gles_system.h b/src/common/rendering/gles/gles_system.h new file mode 100644 index 00000000000..0edec6282fc --- /dev/null +++ b/src/common/rendering/gles/gles_system.h @@ -0,0 +1,123 @@ +#ifndef __GLES_SYSTEM_H +#define __GLES_SYSTEM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) +#include +#endif +#include + +#include +#include +#include + +#define USE_GLAD_LOADER 0 // Set to 1 to use the GLAD loader, otherwise use noramal GZDoom loader for PC + +#if (USE_GLAD_LOADER) + #include "glad/glad.h" + + // Below are used extensions for GLES + typedef void* (APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); + GLAPI PFNGLMAPBUFFERRANGEEXTPROC glMapBufferRange; + + typedef GLboolean(APIENTRYP PFNGLUNMAPBUFFEROESPROC)(GLenum target); + GLAPI PFNGLUNMAPBUFFEROESPROC glUnmapBuffer; + + typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); + GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer; + + typedef GLsync(APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); + GLAPI PFNGLFENCESYNCPROC glFenceSync; + + typedef GLenum(APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); + GLAPI PFNGLCLIENTWAITSYNCPROC glClientWaitSync; + + typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); + GLAPI PFNGLDELETESYNCPROC glDeleteSync; + + #define GL_DEPTH24_STENCIL8 0x88F0 + #define GL_MAP_PERSISTENT_BIT 0x0040 + #define GL_MAP_READ_BIT 0x0001 + #define GL_MAP_WRITE_BIT 0x0002 + #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 + #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 + #define GL_BGRA 0x80E1 + #define GL_DEPTH_CLAMP 0x864F + #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE + #define GL_INT_2_10_10_10_REV 0x8D9F + #define GL_RED 0x1903 + #define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 + #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 + #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 + #define GL_ALREADY_SIGNALED 0x911A + #define GL_CONDITION_SATISFIED 0x911C + +#else + #include "gl_load/gl_load.h" +#endif + +#if defined(__APPLE__) + #include +#endif + +// This is the number of vec4s make up the light data +#define LIGHT_VEC4_NUM 4 + +//#define NO_RENDER_BUFFER + +//#define NPOT_EMULATION + +namespace OpenGLESRenderer +{ + enum + { + GLES_MODE_GLES = 0, + GLES_MODE_OGL2 = 1, + GLES_MODE_OGL3 = 2, + }; + + struct RenderContextGLES + { + unsigned int flags; + unsigned int maxlights; + unsigned int numlightvectors; + bool useMappedBuffers; + bool depthStencilAvailable; + bool npotAvailable; + bool forceGLSLv100; + bool depthClampAvailable; + bool anistropicFilterAvailable; + int glesMode; + const char* shaderVersionString; + int max_texturesize; + char* vendorstring; + char* modelstring; + }; + + extern RenderContextGLES gles; + + void InitGLES(); +} + +#ifdef _MSC_VER +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4305) // truncate from double to float +#endif + +#endif //__GL_PCH_H diff --git a/src/common/rendering/hwrenderer/data/buffers.h b/src/common/rendering/hwrenderer/data/buffers.h new file mode 100644 index 00000000000..5e2c027284c --- /dev/null +++ b/src/common/rendering/hwrenderer/data/buffers.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include + +class FRenderState; + +#ifdef __ANDROID__ +#define HW_MAX_PIPELINE_BUFFERS 4 +#define HW_BLOCK_SSBO 1 +#else +// On desktop this is only useful fpr letting the GPU run in parallel with the playsim and for that 2 buffers are enough. +#define HW_MAX_PIPELINE_BUFFERS 2 +#endif + +// The low level code needs to know which attributes exist. +// OpenGL needs to change the state of all of them per buffer binding. +// VAOs are mostly useless for this because they lump buffer and binding state together which the model code does not want. +enum +{ + VATTR_VERTEX, + VATTR_TEXCOORD, + VATTR_COLOR, + VATTR_VERTEX2, + VATTR_NORMAL, + VATTR_NORMAL2, + VATTR_LIGHTMAP, + VATTR_BONEWEIGHT, + VATTR_BONESELECTOR, + VATTR_MAX +}; + +enum EVertexAttributeFormat +{ + VFmt_Float4, + VFmt_Float3, + VFmt_Float2, + VFmt_Float, + VFmt_Byte4, + VFmt_Packed_A2R10G10B10, + VFmt_Byte4_UInt +}; + +struct FVertexBufferAttribute +{ + int binding; + int location; + int format; + int offset; +}; + +enum class BufferUsageType +{ + Static, // initial data is not null, staticdata is true + Stream, // initial data is not null, staticdata is false + Persistent, // initial data is null, staticdata is false + Mappable // initial data is null, staticdata is true +}; + +class IBuffer +{ +protected: + size_t buffersize = 0; + void *map = nullptr; +public: + IBuffer() = default; + IBuffer(const IBuffer &) = delete; + IBuffer &operator=(const IBuffer &) = delete; + virtual ~IBuffer() = default; + + virtual void SetData(size_t size, const void *data, BufferUsageType type) = 0; + virtual void SetSubData(size_t offset, size_t size, const void *data) = 0; + virtual void *Lock(unsigned int size) = 0; + virtual void Unlock() = 0; + virtual void Resize(size_t newsize) = 0; + + virtual void Upload(size_t start, size_t size) {} // For unmappable buffers + + virtual void Map() {} // Only needed by old OpenGL but this needs to be in the interface. + virtual void Unmap() {} + void *Memory() { return map; } + size_t Size() { return buffersize; } + virtual void GPUDropSync() {} + virtual void GPUWaitSync() {} +}; + +class IVertexBuffer : virtual public IBuffer +{ +public: + virtual void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) = 0; +}; + +// This merely exists to have a dedicated type for index buffers to inherit from. +class IIndexBuffer : virtual public IBuffer +{ + // Element size is fixed to 4, thanks to OpenGL requiring this info to be coded into the glDrawElements call. + // This mostly prohibits a more flexible buffer setup but GZDoom doesn't use any other format anyway. + // Ob Vulkam, element size is a buffer property and of no concern to the drawing functions (as it should be.) +}; + +class IDataBuffer : virtual public IBuffer +{ + // Can be either uniform or shader storage buffer, depending on its needs. +public: + virtual void BindRange(FRenderState *state, size_t start, size_t length) = 0; + +}; diff --git a/src/common/rendering/hwrenderer/data/flatvertices.cpp b/src/common/rendering/hwrenderer/data/flatvertices.cpp new file mode 100644 index 00000000000..cfbfea08037 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/flatvertices.cpp @@ -0,0 +1,182 @@ +/* +** hw_flatvertices.cpp +** Creates flat vertex data for hardware rendering. +** +**--------------------------------------------------------------------------- +** Copyright 2010-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_cvars.h" +#include "flatvertices.h" +#include "v_video.h" +#include "cmdlib.h" +#include "printf.h" +#include "hwrenderer/data/buffers.h" + +//========================================================================== +// +// +// +//========================================================================== + +FFlatVertexBuffer::FFlatVertexBuffer(int width, int height, int pipelineNbr): + mPipelineNbr(pipelineNbr) +{ + vbo_shadowdata.Resize(NUM_RESERVED); + + // the first quad is reserved for handling coordinates through uniforms. + vbo_shadowdata[0].Set(0, 0, 0, 0, 0); + vbo_shadowdata[1].Set(1, 0, 0, 0, 0); + vbo_shadowdata[2].Set(2, 0, 0, 0, 0); + vbo_shadowdata[3].Set(3, 0, 0, 0, 0); + + // and the second one for the fullscreen quad used for blend overlays. + vbo_shadowdata[4].Set(0, 0, 0, 0, 0); + vbo_shadowdata[5].Set(0, (float)height, 0, 0, 1); + vbo_shadowdata[6].Set((float)width, 0, 0, 1, 0); + vbo_shadowdata[7].Set((float)width, (float)height, 0, 1, 1); + + // and this is for the postprocessing copy operation + vbo_shadowdata[8].Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); + vbo_shadowdata[9].Set(3.0f, -1.0f, 0, 2.f, 0.0f); + vbo_shadowdata[10].Set(-1.0f, 3.0f, 0, 0.0f, 2.f); + vbo_shadowdata[11].Set(3.0f, 3.0f, 0, 2.f, 2.f); // Note: not used anymore + + // The next two are the stencil caps. + vbo_shadowdata[12].Set(-32767.0f, 32767.0f, -32767.0f, 0, 0); + vbo_shadowdata[13].Set(-32767.0f, 32767.0f, 32767.0f, 0, 0); + vbo_shadowdata[14].Set(32767.0f, 32767.0f, 32767.0f, 0, 0); + vbo_shadowdata[15].Set(32767.0f, 32767.0f, -32767.0f, 0, 0); + + vbo_shadowdata[16].Set(-32767.0f, -32767.0f, -32767.0f, 0, 0); + vbo_shadowdata[17].Set(-32767.0f, -32767.0f, 32767.0f, 0, 0); + vbo_shadowdata[18].Set(32767.0f, -32767.0f, 32767.0f, 0, 0); + vbo_shadowdata[19].Set(32767.0f, -32767.0f, -32767.0f, 0, 0); + + mIndexBuffer = screen->CreateIndexBuffer(); + int data[4] = {}; + mIndexBuffer->SetData(4, data, BufferUsageType::Static); // On Vulkan this may not be empty, so set some dummy defaults to avoid crashes. + + + for (int n = 0; n < mPipelineNbr; n++) + { + mVertexBufferPipeline[n] = screen->CreateVertexBuffer(); + + unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex); + mVertexBufferPipeline[n]->SetData(bytesize, nullptr, BufferUsageType::Persistent); + + static const FVertexBufferAttribute format[] = { + { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FFlatVertex, x) }, + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FFlatVertex, u) }, + { 0, VATTR_LIGHTMAP, VFmt_Float3, (int)myoffsetof(FFlatVertex, lu) }, + }; + + mVertexBufferPipeline[n]->SetFormat(1, 3, sizeof(FFlatVertex), format); + } + + mVertexBuffer = mVertexBufferPipeline[mPipelinePos]; + + mIndex = mCurIndex = NUM_RESERVED; + mNumReserved = NUM_RESERVED; + Copy(0, NUM_RESERVED); +} + +//========================================================================== +// +// +// +//========================================================================== + +FFlatVertexBuffer::~FFlatVertexBuffer() +{ + for (int n = 0; n < mPipelineNbr; n++) + { + delete mVertexBufferPipeline[n]; + } + + delete mIndexBuffer; + mIndexBuffer = nullptr; + mVertexBuffer = nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FFlatVertexBuffer::OutputResized(int width, int height) +{ + vbo_shadowdata[4].Set(0, 0, 0, 0, 0); + vbo_shadowdata[5].Set(0, (float)height, 0, 0, 1); + vbo_shadowdata[6].Set((float)width, 0, 0, 1, 0); + vbo_shadowdata[7].Set((float)width, (float)height, 0, 1, 1); + Copy(4, 4); +} + +//========================================================================== +// +// +// +//========================================================================== + +std::pair FFlatVertexBuffer::AllocVertices(unsigned int count) +{ + FFlatVertex *p = GetBuffer(); + auto index = mCurIndex.fetch_add(count); + if (index + count >= BUFFER_SIZE_TO_USE) + { + // If a single scene needs 2'000'000 vertices there must be something very wrong. + I_FatalError("Out of vertex memory. Tried to allocate more than %u vertices for a single frame", index + count); + } + return std::make_pair(p, index); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FFlatVertexBuffer::Copy(int start, int count) +{ + IVertexBuffer* old = mVertexBuffer; + + for (int n = 0; n < mPipelineNbr; n++) + { + mVertexBuffer = mVertexBufferPipeline[n]; + Map(); + memcpy(GetBuffer(start), &vbo_shadowdata[0], count * sizeof(FFlatVertex)); + Unmap(); + mVertexBuffer->Upload(start * sizeof(FFlatVertex), count * sizeof(FFlatVertex)); + } + + mVertexBuffer = old; +} + diff --git a/src/common/rendering/hwrenderer/data/flatvertices.h b/src/common/rendering/hwrenderer/data/flatvertices.h new file mode 100644 index 00000000000..1056560a12a --- /dev/null +++ b/src/common/rendering/hwrenderer/data/flatvertices.h @@ -0,0 +1,158 @@ + +#ifndef _HW__VERTEXBUFFER_H +#define _HW__VERTEXBUFFER_H + +#include "tarray.h" +#include "hwrenderer/data/buffers.h" +#include +#include + +class FRenderState; +struct secplane_t; + +struct FFlatVertex +{ + float x, z, y; // world position + float u, v; // texture coordinates + float lu, lv; // lightmap texture coordinates + float lindex; // lightmap texture index + + void Set(float xx, float zz, float yy, float uu, float vv) + { + x = xx; + z = zz; + y = yy; + u = uu; + v = vv; + lindex = -1.0f; + } + + void Set(float xx, float zz, float yy, float uu, float vv, float llu, float llv, float llindex) + { + x = xx; + z = zz; + y = yy; + u = uu; + v = vv; + lu = llu; + lv = llv; + lindex = llindex; + } + + void SetVertex(float _x, float _y, float _z = 0) + { + x = _x; + z = _y; + y = _z; + } + + void SetTexCoord(float _u = 0, float _v = 0) + { + u = _u; + v = _v; + } + +}; + +class FFlatVertexBuffer +{ +public: + TArray vbo_shadowdata; + TArray ibo_data; + + int mPipelineNbr; + int mPipelinePos = 0; + + IVertexBuffer* mVertexBuffer; + IVertexBuffer *mVertexBufferPipeline[HW_MAX_PIPELINE_BUFFERS]; + IIndexBuffer *mIndexBuffer; + + + + unsigned int mIndex; + std::atomic mCurIndex; + unsigned int mNumReserved; + + unsigned int mMapStart; + + static const unsigned int BUFFER_SIZE = 2000000; + static const unsigned int BUFFER_SIZE_TO_USE = BUFFER_SIZE-500; + +public: + enum + { + QUAD_INDEX = 0, + FULLSCREEN_INDEX = 4, + PRESENT_INDEX = 8, + STENCILTOP_INDEX = 12, + STENCILBOTTOM_INDEX = 16, + + NUM_RESERVED = 20 + }; + + FFlatVertexBuffer(int width, int height, int pipelineNbr = 1); + ~FFlatVertexBuffer(); + + void OutputResized(int width, int height); + std::pair GetBufferObjects() const + { + return std::make_pair(mVertexBuffer, mIndexBuffer); + } + + void Copy(int start, int count); + + FFlatVertex *GetBuffer(int index) const + { + FFlatVertex *ff = (FFlatVertex*)mVertexBuffer->Memory(); + return &ff[index]; + } + + FFlatVertex *GetBuffer() const + { + return GetBuffer(mCurIndex); + } + + std::pair AllocVertices(unsigned int count); + + void Reset() + { + mCurIndex = mIndex; + } + + void NextPipelineBuffer() + { + mPipelinePos++; + mPipelinePos %= mPipelineNbr; + + mVertexBuffer = mVertexBufferPipeline[mPipelinePos]; + } + + void Map() + { + mMapStart = mCurIndex; + mVertexBuffer->Map(); + } + + void Unmap() + { + mVertexBuffer->Unmap(); + mVertexBuffer->Upload(mMapStart * sizeof(FFlatVertex), (mCurIndex - mMapStart) * sizeof(FFlatVertex)); + } + + void DropSync() + { + mVertexBuffer->GPUDropSync(); + } + + void WaitSync() + { + mVertexBuffer->GPUWaitSync(); + } + + int GetPipelinePos() + { + return mPipelinePos; + } +}; + +#endif diff --git a/src/common/rendering/hwrenderer/data/hw_aabbtree.cpp b/src/common/rendering/hwrenderer/data/hw_aabbtree.cpp new file mode 100644 index 00000000000..d7d221fe311 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_aabbtree.cpp @@ -0,0 +1,166 @@ +// +//--------------------------------------------------------------------------- +// AABB-tree used for ray testing +// Copyright(C) 2017 Magnus Norddahl +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include +#include "hw_aabbtree.h" + +namespace hwrenderer +{ + +TArray LevelAABBTree::FindNodePath(unsigned int line, unsigned int node) +{ + const AABBTreeNode &n = nodes[node]; + + if (n.aabb_left > treelines[line].x || n.aabb_right < treelines[line].x || + n.aabb_top > treelines[line].y || n.aabb_bottom < treelines[line].y) + { + return {}; + } + + TArray path; + if (n.line_index == -1) + { + path = FindNodePath(line, n.left_node); + if (path.Size() == 0) + path = FindNodePath(line, n.right_node); + + if (path.Size()) + path.Push(node); + } + else if (n.line_index == (int)line) + { + path.Push(node); + } + return path; +} + +double LevelAABBTree::RayTest(const DVector3 &ray_start, const DVector3 &ray_end) +{ + // Precalculate some of the variables used by the ray/line intersection test + DVector2 raydelta = (ray_end - ray_start).XY(); + double raydist2 = raydelta | raydelta; + DVector2 raynormal = DVector2(raydelta.Y, -raydelta.X); + double rayd = raynormal | ray_start.XY(); + if (raydist2 < 1.0) + return 1.0f; + + double hit_fraction = 1.0; + + // Walk the tree nodes + int stack[32]; + int stack_pos = 1; + stack[0] = nodes.Size() - 1; // root node is the last node in the list + while (stack_pos > 0) + { + int node_index = stack[stack_pos - 1]; + + if (!OverlapRayAABB(ray_start.XY(), ray_end.XY(), nodes[node_index])) + { + // If the ray doesn't overlap this node's AABB we're done for this subtree + stack_pos--; + } + else if (nodes[node_index].line_index != -1) // isLeaf(node_index) + { + // We reached a leaf node. Do a ray/line intersection test to see if we hit the line. + hit_fraction = std::min(IntersectRayLine(ray_start.XY(), ray_end.XY(), nodes[node_index].line_index, raydelta, rayd, raydist2), hit_fraction); + stack_pos--; + } + else if (stack_pos == 32) + { + stack_pos--; // stack overflow - tree is too deep! + } + else + { + // The ray overlaps the node's AABB. Examine its child nodes. + stack[stack_pos - 1] = nodes[node_index].left_node; + stack[stack_pos] = nodes[node_index].right_node; + stack_pos++; + } + } + + return hit_fraction; +} + +bool LevelAABBTree::OverlapRayAABB(const DVector2 &ray_start2d, const DVector2 &ray_end2d, const AABBTreeNode &node) +{ + // To do: simplify test to use a 2D test + DVector3 ray_start = DVector3(ray_start2d, 0.0); + DVector3 ray_end = DVector3(ray_end2d, 0.0); + DVector3 aabb_min = DVector3(node.aabb_left, node.aabb_top, -1.0); + DVector3 aabb_max = DVector3(node.aabb_right, node.aabb_bottom, 1.0); + + // Standard 3D ray/AABB overlapping test. + // The details for the math here can be found in Real-Time Rendering, 3rd Edition. + // We could use a 2D test here instead, which would probably simplify the math. + + DVector3 c = (ray_start + ray_end) * 0.5f; + DVector3 w = ray_end - c; + DVector3 h = (aabb_max - aabb_min) * 0.5f; // aabb.extents(); + + c -= (aabb_max + aabb_min) * 0.5f; // aabb.center(); + + DVector3 v = DVector3(fabs(w.X), fabs(w.Y), fabs(w.Z)); + + if (fabs(c.X) > v.X + h.X || fabs(c.Y) > v.Y + h.Y || fabs(c.Z) > v.Z + h.Z) + return false; // disjoint; + + if (fabs(c.Y * w.Z - c.Z * w.Y) > h.Y * v.Z + h.Z * v.Y || + fabs(c.X * w.Z - c.Z * w.X) > h.X * v.Z + h.Z * v.X || + fabs(c.X * w.Y - c.Y * w.X) > h.X * v.Y + h.Y * v.X) + return false; // disjoint; + + return true; // overlap; +} + +double LevelAABBTree::IntersectRayLine(const DVector2 &ray_start, const DVector2 &ray_end, int line_index, const DVector2 &raydelta, double rayd, double raydist2) +{ + // Check if two line segments intersects (the ray and the line). + // The math below does this by first finding the fractional hit for an infinitely long ray line. + // If that hit is within the line segment (0 to 1 range) then it calculates the fractional hit for where the ray would hit. + // + // This algorithm is homemade - I would not be surprised if there's a much faster method out there. + + const double epsilon = 0.0000001; + const AABBTreeLine &line = treelines[line_index]; + + DVector2 raynormal = DVector2(raydelta.Y, -raydelta.X); + + DVector2 line_pos(line.x, line.y); + DVector2 line_delta(line.dx, line.dy); + + double den = raynormal | line_delta; + if (fabs(den) > epsilon) + { + double t_line = (rayd - (raynormal | line_pos)) / den; + if (t_line >= 0.0 && t_line <= 1.0) + { + DVector2 linehitdelta = line_pos + line_delta * t_line - ray_start; + double t = (raydelta | linehitdelta) / raydist2; + return t > 0.0 ? t : 1.0; + } + } + + return 1.0; +} + + +} diff --git a/src/rendering/hwrenderer/dynlights/hw_aabbtree.h b/src/common/rendering/hwrenderer/data/hw_aabbtree.h similarity index 86% rename from src/rendering/hwrenderer/dynlights/hw_aabbtree.h rename to src/common/rendering/hwrenderer/data/hw_aabbtree.h index f435d68cef2..2bd0e15065b 100644 --- a/src/rendering/hwrenderer/dynlights/hw_aabbtree.h +++ b/src/common/rendering/hwrenderer/data/hw_aabbtree.h @@ -4,8 +4,6 @@ #include "tarray.h" #include "vectors.h" -struct FLevelLocals; - namespace hwrenderer { @@ -37,18 +35,22 @@ struct AABBTreeLine float dx, dy; }; -// Axis aligned bounding box tree used for ray testing treelines. class LevelAABBTree { -public: - // Constructs a tree for the current level - LevelAABBTree(FLevelLocals *lev); +protected: + // Nodes in the AABB tree. Last node is the root node. + TArray nodes; + + // Line segments for the leaf nodes in the tree. + TArray treelines; + int dynamicStartNode = 0; + int dynamicStartLine = 0; + +public: // Shoot a ray from ray_start to ray_end and return the closest hit as a fractional value between 0 and 1. Returns 1 if no line was hit. double RayTest(const DVector3 &ray_start, const DVector3 &ray_end); - bool Update(); - const void *Nodes() const { return nodes.Data(); } const void *Lines() const { return treelines.Data(); } size_t NodesSize() const { return nodes.Size() * sizeof(AABBTreeNode); } @@ -62,31 +64,20 @@ class LevelAABBTree size_t DynamicNodesOffset() const { return dynamicStartNode * sizeof(AABBTreeNode); } size_t DynamicLinesOffset() const { return dynamicStartLine * sizeof(AABBTreeLine); } -private: - bool GenerateTree(const FVector2 *centroids, bool dynamicsubtree); + virtual bool Update() = 0; + + virtual ~LevelAABBTree() = default; +protected: + + TArray FindNodePath(unsigned int line, unsigned int node); // Test if a ray overlaps an AABB node or not bool OverlapRayAABB(const DVector2 &ray_start2d, const DVector2 &ray_end2d, const AABBTreeNode &node); // Intersection test between a ray and a line segment double IntersectRayLine(const DVector2 &ray_start, const DVector2 &ray_end, int line_index, const DVector2 &raydelta, double rayd, double raydist2); - // Generate a tree node and its children recursively - int GenerateTreeNode(int *treelines, int num_lines, const FVector2 *centroids, int *work_buffer); - - TArray FindNodePath(unsigned int line, unsigned int node); - - // Nodes in the AABB tree. Last node is the root node. - TArray nodes; - - // Line segments for the leaf nodes in the tree. - TArray treelines; - - int dynamicStartNode = 0; - int dynamicStartLine = 0; - TArray mapLines; - FLevelLocals *Level; }; } // namespace diff --git a/src/common/rendering/hwrenderer/data/hw_bonebuffer.cpp b/src/common/rendering/hwrenderer/data/hw_bonebuffer.cpp new file mode 100644 index 00000000000..e6de0541143 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_bonebuffer.cpp @@ -0,0 +1,109 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2014-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include "hw_bonebuffer.h" +#include "hw_dynlightdata.h" +#include "shaderuniforms.h" + +static const int BONE_SIZE = (16*sizeof(float)); + +BoneBuffer::BoneBuffer(int pipelineNbr) : mPipelineNbr(pipelineNbr) +{ + int maxNumberOfBones = 80000; + + mBufferSize = maxNumberOfBones; + mByteSize = mBufferSize * BONE_SIZE; + + if (screen->useSSBO()) + { + mBufferType = true; + mBlockAlign = 0; + mBlockSize = mBufferSize; + mMaxUploadSize = mBlockSize; + } + else + { + mBufferType = false; + mBlockSize = screen->maxuniformblock / BONE_SIZE; + mBlockAlign = screen->uniformblockalignment < 64 ? 1 : screen->uniformblockalignment / BONE_SIZE; + mMaxUploadSize = (mBlockSize - mBlockAlign); + } + + for (int n = 0; n < mPipelineNbr; n++) + { + mBufferPipeline[n] = screen->CreateDataBuffer(BONEBUF_BINDINGPOINT, mBufferType, false); + mBufferPipeline[n]->SetData(mByteSize, nullptr, BufferUsageType::Persistent); + } + + Clear(); +} + +BoneBuffer::~BoneBuffer() +{ + delete mBuffer; +} + +void BoneBuffer::Clear() +{ + mIndex = 0; + + mPipelinePos++; + mPipelinePos %= mPipelineNbr; + + mBuffer = mBufferPipeline[mPipelinePos]; +} + +int BoneBuffer::UploadBones(const TArray& bones) +{ + int totalsize = bones.Size(); + if (totalsize > (int)mMaxUploadSize) + { + totalsize = mMaxUploadSize; + } + + uint8_t *mBufferPointer = (uint8_t*)mBuffer->Memory(); + assert(mBufferPointer != nullptr); + if (mBufferPointer == nullptr) return -1; + if (totalsize <= 0) return -1; // there are no bones + + unsigned int thisindex = mIndex.fetch_add(totalsize); + + if (thisindex + totalsize <= mBufferSize) + { + memcpy(mBufferPointer + thisindex * BONE_SIZE, bones.Data(), totalsize * BONE_SIZE); + return thisindex; + } + else + { + return -1; // Buffer is full. Since it is being used live at the point of the upload we cannot do much here but to abort. + } +} + +int BoneBuffer::GetBinding(unsigned int index, size_t* pOffset, size_t* pSize) +{ + // this function will only get called if a uniform buffer is used. For a shader storage buffer we only need to bind the buffer once at the start. + unsigned int offset = (index / mBlockAlign) * mBlockAlign; + + *pOffset = offset * BONE_SIZE; + *pSize = mBlockSize * BONE_SIZE; + return (index - offset); +} diff --git a/src/common/rendering/hwrenderer/data/hw_bonebuffer.h b/src/common/rendering/hwrenderer/data/hw_bonebuffer.h new file mode 100644 index 00000000000..44e74ffcfd5 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_bonebuffer.h @@ -0,0 +1,46 @@ +#pragma once + +#include "tarray.h" +#include "hwrenderer/data/buffers.h" +#include "common/utility/matrix.h" +#include +#include + +class FRenderState; + +class BoneBuffer +{ + IDataBuffer *mBuffer; + IDataBuffer* mBufferPipeline[HW_MAX_PIPELINE_BUFFERS]; + int mPipelineNbr; + int mPipelinePos = 0; + + bool mBufferType; + std::atomic mIndex; + unsigned int mBlockAlign; + unsigned int mBlockSize; + unsigned int mBufferSize; + unsigned int mByteSize; + unsigned int mMaxUploadSize; + +public: + BoneBuffer(int pipelineNbr = 1); + ~BoneBuffer(); + + void Clear(); + int UploadBones(const TArray &bones); + void Map() { mBuffer->Map(); } + void Unmap() { mBuffer->Unmap(); } + unsigned int GetBlockSize() const { return mBlockSize; } + bool GetBufferType() const { return mBufferType; } + int GetBinding(unsigned int index, size_t* pOffset, size_t* pSize); + + // Only for GLES to determin how much data is in the buffer + int GetCurrentIndex() { return mIndex; }; + + // OpenGL needs the buffer to mess around with the binding. + IDataBuffer* GetBuffer() const + { + return mBuffer; + } +}; diff --git a/src/rendering/hwrenderer/utility/hw_clock.cpp b/src/common/rendering/hwrenderer/data/hw_clock.cpp similarity index 92% rename from src/rendering/hwrenderer/utility/hw_clock.cpp rename to src/common/rendering/hwrenderer/data/hw_clock.cpp index dff667b1a74..ec2847944ec 100644 --- a/src/rendering/hwrenderer/utility/hw_clock.cpp +++ b/src/common/rendering/hwrenderer/data/hw_clock.cpp @@ -33,14 +33,13 @@ */ -#include "g_level.h" #include "c_console.h" #include "c_dispatch.h" -#include "r_utility.h" #include "v_video.h" -#include "g_levellocals.h" #include "hw_clock.h" #include "i_time.h" +#include "i_interface.h" +#include "printf.h" glcycle_t RenderWall,SetupWall,ClipWall; glcycle_t RenderFlat,SetupFlat; @@ -166,16 +165,12 @@ void CheckBench() FString compose; - auto &vp = r_viewpoint; - auto Level = vp.ViewLevel; - compose.Format("Map %s: \"%s\",\nx = %1.4f, y = %1.4f, z = %1.4f, angle = %1.4f, pitch = %1.4f\n", - Level->MapName.GetChars(), Level->LevelName.GetChars(), vp.Pos.X, vp.Pos.Y, vp.Pos.Z, vp.Angles.Yaw.Degrees, vp.Angles.Pitch.Degrees); - + if (sysCallbacks.GetLocationDescription) compose = sysCallbacks.GetLocationDescription(); + AppendRenderStats(compose); AppendRenderTimes(compose); AppendLightStats(compose); - //AppendMissingTextureStats(compose); - compose.AppendFormat("%llu fps\n\n", (unsigned long long)screen->GetLastFPS()); + compose << "\n\n\n"; FILE *f = fopen("benchmarks.txt", "at"); if (f != NULL) diff --git a/src/rendering/hwrenderer/utility/hw_clock.h b/src/common/rendering/hwrenderer/data/hw_clock.h similarity index 97% rename from src/rendering/hwrenderer/utility/hw_clock.h rename to src/common/rendering/hwrenderer/data/hw_clock.h index 8dec4a6de07..b2d9320b8ce 100644 --- a/src/rendering/hwrenderer/utility/hw_clock.h +++ b/src/common/rendering/hwrenderer/data/hw_clock.h @@ -2,7 +2,6 @@ #define __GL_CLOCK_H #include "stats.h" -#include "x86.h" #include "m_fixed.h" extern glcycle_t RenderWall,SetupWall,ClipWall; diff --git a/src/common/rendering/hwrenderer/data/hw_cvars.cpp b/src/common/rendering/hwrenderer/data/hw_cvars.cpp new file mode 100644 index 00000000000..a7967b92e3d --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_cvars.cpp @@ -0,0 +1,135 @@ +/* +** hw_cvars.cpp +** +** most of the hardware renderer's CVARs. +** +**--------------------------------------------------------------------------- +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + + + +#include "c_cvars.h" +#include "c_dispatch.h" +#include "v_video.h" +#include "hw_cvars.h" +#include "menu.h" +#include "printf.h" + + +CUSTOM_CVAR(Int, gl_fogmode, 2, CVAR_ARCHIVE | CVAR_NOINITCALL) +{ + if (self > 2) self = 2; + if (self < 0) self = 0; +} + + +// OpenGL stuff moved here +// GL related CVARs +CVAR(Bool, gl_portals, true, 0) +CVAR(Bool,gl_mirrors,true,0) // This is for debugging only! +CVAR(Bool,gl_mirror_envmap, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) +CVAR(Bool, gl_seamless, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +CUSTOM_CVAR(Int, r_mirror_recursions,4,CVAR_GLOBALCONFIG|CVAR_ARCHIVE) +{ + if (self<0) self=0; + if (self>10) self=10; +} +bool gl_plane_reflection_i; // This is needed in a header that cannot include the CVAR stuff... +CUSTOM_CVAR(Bool, gl_plane_reflection, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) +{ + gl_plane_reflection_i = self; +} + +CUSTOM_CVARD(Float, vid_gamma, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "adjusts gamma component of gamma ramp") +{ + if (self < 0) self = 1; + else if (self > 4) self = 4; +} + +CUSTOM_CVARD(Float, vid_contrast, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "adjusts contrast component of gamma ramp") +{ + if (self < 0) self = 0; + else if (self > 5) self = 5; +} + +CUSTOM_CVARD(Float, vid_brightness, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "adjusts brightness component of gamma ramp") +{ + if (self < -2) self = -2; + else if (self > 2) self = 2; +} + +CUSTOM_CVARD(Float, vid_saturation, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "adjusts saturation component of gamma ramp") +{ + if (self < -3) self = -3; + else if (self > 3) self = 3; +} + +CCMD (bumpgamma) +{ + // [RH] Gamma correction tables are now generated on the fly for *any* gamma level + // Q: What are reasonable limits to use here? + + float newgamma = vid_gamma + 0.1f; + + if (newgamma > 4.0) + newgamma = 1.0; + + vid_gamma = newgamma; + Printf ("Gamma correction level %g\n", newgamma); +} + + +CVAR(Int, gl_satformula, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); + +//========================================================================== +// +// Texture CVARs +// +//========================================================================== +CUSTOM_CVARD(Float, gl_texture_filter_anisotropic, 8.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL, "changes the OpenGL texture anisotropy setting") +{ + screen->SetTextureFilterMode(); +} + +CUSTOM_CVARD(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL, "changes the texture filtering settings") +{ + if (self < 0 || self > 6) self=4; + screen->SetTextureFilterMode(); +} + +CVAR(Bool, gl_precache, false, CVAR_ARCHIVE) + + +CUSTOM_CVAR(Int, gl_shadowmap_filter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0 || self > 8) self = 1; +} diff --git a/src/rendering/hwrenderer/utility/hw_cvars.h b/src/common/rendering/hwrenderer/data/hw_cvars.h similarity index 75% rename from src/rendering/hwrenderer/utility/hw_cvars.h rename to src/common/rendering/hwrenderer/data/hw_cvars.h index 8d184206dd6..7f84ba09e26 100644 --- a/src/rendering/hwrenderer/utility/hw_cvars.h +++ b/src/common/rendering/hwrenderer/data/hw_cvars.h @@ -1,12 +1,10 @@ #pragma once -#include "r_defs.h" #include "c_cvars.h" EXTERN_CVAR(Bool,gl_enhanced_nightvision) EXTERN_CVAR(Int, screenblocks); -EXTERN_CVAR(Bool, gl_texture) EXTERN_CVAR(Int, gl_texture_filter) EXTERN_CVAR(Float, gl_texture_filter_anisotropic) EXTERN_CVAR(Int, gl_texture_format) @@ -20,7 +18,6 @@ EXTERN_CVAR (Bool, gl_light_shadowmap); EXTERN_CVAR (Int, gl_shadowmap_quality); EXTERN_CVAR(Int, gl_fogmode) -EXTERN_CVAR(Int, gl_lightmode) EXTERN_CVAR(Bool,gl_mirror_envmap) EXTERN_CVAR(Bool,gl_mirrors) @@ -52,21 +49,11 @@ EXTERN_CVAR(Float, gl_ssao_blur_amount) EXTERN_CVAR(Int, gl_debug_level) EXTERN_CVAR(Bool, gl_debug_breakpoint) - -EXTERN_CVAR(Bool, gl_usecolorblending) -EXTERN_CVAR(Bool, gl_sprite_blend) -EXTERN_CVAR(Int, gl_spriteclip) -EXTERN_CVAR(Float, gl_sclipthreshold) -EXTERN_CVAR(Float, gl_sclipfactor) -EXTERN_CVAR(Int, gl_particles_style) -EXTERN_CVAR(Int, gl_billboard_mode) -EXTERN_CVAR(Bool, gl_billboard_faces_camera) -EXTERN_CVAR(Bool, gl_billboard_particles) -EXTERN_CVAR(Int, gl_enhanced_nv_stealth) -EXTERN_CVAR(Int, gl_fuzztype) - EXTERN_CVAR(Int, gl_shadowmap_filter) EXTERN_CVAR(Bool, gl_brightfog) EXTERN_CVAR(Bool, gl_lightadditivesurfaces) EXTERN_CVAR(Bool, gl_notexturefill) + +EXTERN_CVAR(Bool, r_radarclipper) +EXTERN_CVAR(Bool, r_dithertransparency) diff --git a/src/rendering/hwrenderer/dynlights/hw_dynlightdata.h b/src/common/rendering/hwrenderer/data/hw_dynlightdata.h similarity index 86% rename from src/rendering/hwrenderer/dynlights/hw_dynlightdata.h rename to src/common/rendering/hwrenderer/data/hw_dynlightdata.h index ec5f6d89ea8..7da1c1b5af0 100644 --- a/src/rendering/hwrenderer/dynlights/hw_dynlightdata.h +++ b/src/common/rendering/hwrenderer/data/hw_dynlightdata.h @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -23,8 +23,7 @@ #ifndef __GLC_DYNLIGHT_H #define __GLC_DYNLIGHT_H -#include "a_dynlight.h" - +#include "tarray.h" struct FDynLightData { @@ -52,9 +51,7 @@ struct FDynLightData if (siz[1] > max) siz[1] = max; if (siz[2] > max) siz[2] = max; } - - bool GetLight(int group, Plane & p, FDynamicLight * light, bool checkside); - void AddLightToList(int group, FDynamicLight * light, bool forceAttenuate); + }; diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h new file mode 100644 index 00000000000..c385f873859 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -0,0 +1,21 @@ + +#pragma once + +#include "tarray.h" +#include "vectors.h" + +namespace hwrenderer +{ + +class LevelMesh +{ +public: + virtual ~LevelMesh() = default; + + TArray MeshVertices; + TArray MeshUVIndex; + TArray MeshElements; + TArray MeshSurfaces; +}; + +} // namespace diff --git a/src/rendering/hwrenderer/dynlights/hw_lightbuffer.cpp b/src/common/rendering/hwrenderer/data/hw_lightbuffer.cpp similarity index 79% rename from src/rendering/hwrenderer/dynlights/hw_lightbuffer.cpp rename to src/common/rendering/hwrenderer/data/hw_lightbuffer.cpp index 30326155f8d..c4dceefe5ce 100644 --- a/src/rendering/hwrenderer/dynlights/hw_lightbuffer.cpp +++ b/src/common/rendering/hwrenderer/data/hw_lightbuffer.cpp @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, @@ -26,25 +26,22 @@ **/ #include "hw_lightbuffer.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/data/shaderuniforms.h" +#include "hw_dynlightdata.h" +#include "shaderuniforms.h" static const int ELEMENTS_PER_LIGHT = 4; // each light needs 4 vec4's. static const int ELEMENT_SIZE = (4*sizeof(float)); -FLightBuffer::FLightBuffer() +FLightBuffer::FLightBuffer(int pipelineNbr): + mPipelineNbr(pipelineNbr) { int maxNumberOfLights = 80000; - + mBufferSize = maxNumberOfLights * ELEMENTS_PER_LIGHT; mByteSize = mBufferSize * ELEMENT_SIZE; - - // Hack alert: On Intel's GL driver SSBO's perform quite worse than UBOs. - // We only want to disable using SSBOs for lights but not disable the feature entirely. - // Note that using an uniform buffer here will limit the number of lights per surface so it isn't done for NVidia and AMD. - if (screen->IsVulkan() || screen->IsPoly() || ((screen->hwcaps & RFL_SHADER_STORAGE_BUFFER) && !strstr(screen->vendorstring, "Intel"))) + + if (screen->useSSBO()) { mBufferType = true; mBlockAlign = 0; @@ -57,11 +54,15 @@ FLightBuffer::FLightBuffer() mBlockSize = screen->maxuniformblock / ELEMENT_SIZE; mBlockAlign = screen->uniformblockalignment / ELEMENT_SIZE; mMaxUploadSize = (mBlockSize - mBlockAlign); - mByteSize += screen->maxuniformblock; // to avoid mapping beyond the end of the buffer. + + //mByteSize += screen->maxuniformblock; // to avoid mapping beyond the end of the buffer. REMOVED this...This can try to allocate 100's of MB.. } - mBuffer = screen->CreateDataBuffer(LIGHTBUF_BINDINGPOINT, mBufferType, false); - mBuffer->SetData(mByteSize, nullptr, false); + for (int n = 0; n < mPipelineNbr; n++) + { + mBufferPipeline[n] = screen->CreateDataBuffer(LIGHTBUF_BINDINGPOINT, mBufferType, false); + mBufferPipeline[n]->SetData(mByteSize, nullptr, BufferUsageType::Persistent); + } Clear(); } @@ -74,6 +75,11 @@ FLightBuffer::~FLightBuffer() void FLightBuffer::Clear() { mIndex = 0; + + mPipelinePos++; + mPipelinePos %= mPipelineNbr; + + mBuffer = mBufferPipeline[mPipelinePos]; } int FLightBuffer::UploadLights(FDynLightData &data) @@ -87,7 +93,7 @@ int FLightBuffer::UploadLights(FDynLightData &data) if (totalsize > (int)mMaxUploadSize) { int diff = totalsize - (int)mMaxUploadSize; - + size2 -= diff; if (size2 < 0) { @@ -106,14 +112,14 @@ int FLightBuffer::UploadLights(FDynLightData &data) assert(mBufferPointer != nullptr); if (mBufferPointer == nullptr) return -1; if (totalsize <= 1) return -1; // there are no lights - + unsigned thisindex = mIndex.fetch_add(totalsize); float parmcnt[] = { 0, float(size0), float(size0 + size1), float(size0 + size1 + size2) }; if (thisindex + totalsize <= mBufferSize) { float *copyptr = mBufferPointer + thisindex*4; - + memcpy(©ptr[0], parmcnt, ELEMENT_SIZE); memcpy(©ptr[4], &data.arrays[0][0], size0 * ELEMENT_SIZE); memcpy(©ptr[4 + 4*size0], &data.arrays[1][0], size1 * ELEMENT_SIZE); diff --git a/src/rendering/hwrenderer/dynlights/hw_lightbuffer.h b/src/common/rendering/hwrenderer/data/hw_lightbuffer.h similarity index 84% rename from src/rendering/hwrenderer/dynlights/hw_lightbuffer.h rename to src/common/rendering/hwrenderer/data/hw_lightbuffer.h index df9d679a7fb..ad266bd94f6 100644 --- a/src/rendering/hwrenderer/dynlights/hw_lightbuffer.h +++ b/src/common/rendering/hwrenderer/data/hw_lightbuffer.h @@ -2,7 +2,7 @@ #define __GL_LIGHTBUFFER_H #include "tarray.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" +#include "hw_dynlightdata.h" #include "hwrenderer/data/buffers.h" #include #include @@ -12,6 +12,9 @@ class FRenderState; class FLightBuffer { IDataBuffer *mBuffer; + IDataBuffer* mBufferPipeline[HW_MAX_PIPELINE_BUFFERS]; + int mPipelineNbr; + int mPipelinePos = 0; bool mBufferType; std::atomic mIndex; @@ -20,12 +23,12 @@ class FLightBuffer unsigned int mBufferSize; unsigned int mByteSize; unsigned int mMaxUploadSize; - + void CheckSize(); public: - FLightBuffer(); + FLightBuffer(int pipelineNbr = 1); ~FLightBuffer(); void Clear(); int UploadLights(FDynLightData &data); @@ -43,7 +46,6 @@ class FLightBuffer }; -int gl_SetDynModelLight(AActor *self, int dynlightindex); #endif diff --git a/src/common/rendering/hwrenderer/data/hw_modelvertexbuffer.cpp b/src/common/rendering/hwrenderer/data/hw_modelvertexbuffer.cpp new file mode 100644 index 00000000000..9dff499f949 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_modelvertexbuffer.cpp @@ -0,0 +1,115 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2005-2020 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_models.cpp +** +** hardware renderer model handling code +** +**/ + + +#include "v_video.h" +#include "cmdlib.h" +#include "hw_modelvertexbuffer.h" + +//=========================================================================== +// +// +// +//=========================================================================== + +FModelVertexBuffer::FModelVertexBuffer(bool needindex, bool singleframe) +{ + mVertexBuffer = screen->CreateVertexBuffer(); + mIndexBuffer = needindex ? screen->CreateIndexBuffer() : nullptr; + + static const FVertexBufferAttribute format[] = { + { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FModelVertex, x) }, + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FModelVertex, u) }, + { 0, VATTR_NORMAL, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) }, + { 0, VATTR_LIGHTMAP, VFmt_Float3, (int)myoffsetof(FModelVertex, lu) }, + { 0, VATTR_BONESELECTOR, VFmt_Byte4_UInt, (int)myoffsetof(FModelVertex, boneselector[0])}, + { 0, VATTR_BONEWEIGHT, VFmt_Byte4, (int)myoffsetof(FModelVertex, boneweight[0]) }, + { 1, VATTR_VERTEX2, VFmt_Float3, (int)myoffsetof(FModelVertex, x) }, + { 1, VATTR_NORMAL2, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) } + }; + mVertexBuffer->SetFormat(2, 8, sizeof(FModelVertex), format); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +FModelVertexBuffer::~FModelVertexBuffer() +{ + if (mIndexBuffer) delete mIndexBuffer; + delete mVertexBuffer; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +FModelVertex *FModelVertexBuffer::LockVertexBuffer(unsigned int size) +{ + return static_cast(mVertexBuffer->Lock(size * sizeof(FModelVertex))); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void FModelVertexBuffer::UnlockVertexBuffer() +{ + mVertexBuffer->Unlock(); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +unsigned int *FModelVertexBuffer::LockIndexBuffer(unsigned int size) +{ + if (mIndexBuffer) return static_cast(mIndexBuffer->Lock(size * sizeof(unsigned int))); + else return nullptr; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void FModelVertexBuffer::UnlockIndexBuffer() +{ + if (mIndexBuffer) mIndexBuffer->Unlock(); +} + + diff --git a/src/common/rendering/hwrenderer/data/hw_modelvertexbuffer.h b/src/common/rendering/hwrenderer/data/hw_modelvertexbuffer.h new file mode 100644 index 00000000000..4907637d467 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_modelvertexbuffer.h @@ -0,0 +1,26 @@ +#pragma once + +#include "hwrenderer/data/buffers.h" +#include "i_modelvertexbuffer.h" + +class FModelRenderer; + +class FModelVertexBuffer : public IModelVertexBuffer +{ + IVertexBuffer *mVertexBuffer; + IIndexBuffer *mIndexBuffer; + +public: + + FModelVertexBuffer(bool needindex, bool singleframe); + ~FModelVertexBuffer(); + + FModelVertex *LockVertexBuffer(unsigned int size) override; + void UnlockVertexBuffer() override; + + unsigned int *LockIndexBuffer(unsigned int size) override; + void UnlockIndexBuffer() override; + + IVertexBuffer* vertexBuffer() const { return mVertexBuffer; } + IIndexBuffer* indexBuffer() const { return mIndexBuffer; } +}; diff --git a/src/rendering/hwrenderer/scene/hw_renderstate.h b/src/common/rendering/hwrenderer/data/hw_renderstate.h similarity index 76% rename from src/rendering/hwrenderer/scene/hw_renderstate.h rename to src/common/rendering/hwrenderer/data/hw_renderstate.h index 42092b2e1a9..41e4b50a372 100644 --- a/src/rendering/hwrenderer/scene/hw_renderstate.h +++ b/src/common/rendering/hwrenderer/data/hw_renderstate.h @@ -1,12 +1,11 @@ #pragma once -#include "v_palette.h" #include "vectors.h" -#include "g_levellocals.h" -#include "hw_drawstructs.h" -#include "hw_drawlist.h" #include "matrix.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_material.h" +#include "texmanip.h" +#include "version.h" +#include "i_interface.h" struct FColormap; class IVertexBuffer; @@ -26,7 +25,7 @@ enum ERenderEffect EFF_SPHEREMAP, EFF_BURN, EFF_STENCIL, - + EFF_DITHERTRANS, MAX_EFFECTS }; @@ -90,7 +89,7 @@ struct FStateVec4 struct FMaterialState { - FMaterial *mMaterial; + FMaterial *mMaterial = nullptr; int mClampMode; int mTranslation; int mOverrideShader; @@ -157,7 +156,7 @@ struct FVector4PalEntry r = newvalue.r * normScale; g = newvalue.g * normScale; b = newvalue.b * normScale; - a = 1; + a = newvalue.a; return *this; } @@ -199,6 +198,10 @@ struct StreamData FVector4 uSplitTopPlane; FVector4 uSplitBottomPlane; + + FVector4 uDetailParms; + FVector4 uNpotEmulation; + FVector4 padding1, padding2, padding3; }; class FRenderState @@ -208,20 +211,27 @@ class FRenderState uint8_t mTextureEnabled:1; uint8_t mGlowEnabled : 1; uint8_t mGradientEnabled : 1; - uint8_t mBrightmapEnabled : 1; uint8_t mModelMatrixEnabled : 1; uint8_t mTextureMatrixEnabled : 1; uint8_t mSplitEnabled : 1; + uint8_t mBrightmapEnabled : 1; int mLightIndex; + int mBoneIndexBase; int mSpecialEffect; int mTextureMode; + int mTextureClamp; + int mTextureModeFlags; int mSoftLight; float mLightParms[4]; float mAlphaThreshold; float mClipSplit[2]; + + int mColorMapSpecial; + float mColorMapFlash; + StreamData mStreamData = {}; PalEntry mFogColor; @@ -236,9 +246,9 @@ class FRenderState EPassType mPassType = NORMAL_PASS; - uint64_t firstFrame = 0; - public: + + uint64_t firstFrame = 0; VSMatrix mModelMatrix; VSMatrix mTextureMatrix; @@ -247,10 +257,12 @@ class FRenderState void Reset() { mTextureEnabled = true; - mGradientEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false; + mBrightmapEnabled = mGradientEnabled = mFogEnabled = mGlowEnabled = false; mFogColor = 0xffffffff; mStreamData.uFogColor = mFogColor; mTextureMode = -1; + mTextureClamp = 0; + mTextureModeFlags = 0; mStreamData.uDesaturationFactor = 0.0f; mAlphaThreshold = 0.5f; mModelMatrixEnabled = false; @@ -267,12 +279,16 @@ class FRenderState mLightParms[3] = -1.f; mSpecialEffect = EFF_NONE; mLightIndex = -1; + mBoneIndexBase = -1; mStreamData.uInterpolationFactor = 0; mRenderStyle = DefaultRenderStyle(); mMaterial.Reset(); mBias.Reset(); mPassType = NORMAL_PASS; + mColorMapSpecial = 0; + mColorMapFlash = 1; + mVertexBuffer = nullptr; mVertexOffsets[0] = mVertexOffsets[1] = 0; mIndexBuffer = nullptr; @@ -286,8 +302,11 @@ class FRenderState mStreamData.uGradientBottomPlane = { 0.0f, 0.0f, 0.0f, 0.0f }; mStreamData.uSplitTopPlane = { 0.0f, 0.0f, 0.0f, 0.0f }; mStreamData.uSplitBottomPlane = { 0.0f, 0.0f, 0.0f, 0.0f }; - mStreamData.uDynLightColor = { 0.0f, 0.0f, 0.0f, 0.0f }; - + mStreamData.uDynLightColor = { 0.0f, 0.0f, 0.0f, 1.0f }; + mStreamData.uDetailParms = { 0.0f, 0.0f, 0.0f, 0.0f }; +#ifdef NPOT_EMULATION + mStreamData.uNpotEmulation = { 0,0,0,0 }; +#endif mModelMatrix.loadIdentity(); mTextureMatrix.loadIdentity(); ClearClipSplit(); @@ -329,6 +348,12 @@ class FRenderState mStreamData.uDesaturationFactor = 0.0f; } + void SetTextureClamp(bool on) + { + if (on) mTextureClamp = TM_CLAMPY; + else mTextureClamp = 0; + } + void SetTextureMode(int mode) { mTextureMode = mode; @@ -338,15 +363,15 @@ class FRenderState { if (style.Flags & STYLEF_RedIsAlpha) { - mTextureMode = TM_ALPHATEXTURE; + SetTextureMode(TM_ALPHATEXTURE); } else if (style.Flags & STYLEF_ColorIsFixed) { - mTextureMode = TM_STENCIL; + SetTextureMode(TM_STENCIL); } else if (style.Flags & STYLEF_InvertSource) { - mTextureMode = TM_INVERSE; + SetTextureMode(TM_INVERSE); } } @@ -355,6 +380,14 @@ class FRenderState return mTextureMode; } + int GetTextureModeAndFlags(int tempTM) + { + int f = mTextureModeFlags; + if (!mBrightmapEnabled) f &= ~(TEXF_Brightmap | TEXF_Glowmap); + if (mTextureClamp) f |= TEXF_ClampY; + return (mTextureMode == TM_NORMAL && tempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode) | f; + } + void EnableTexture(bool on) { mTextureEnabled = on; @@ -427,33 +460,40 @@ class FRenderState mLightParms[3] = -1.f; } - void SetGlowPlanes(const secplane_t &top, const secplane_t &bottom) + void SetGlowPlanes(const FVector4 &tp, const FVector4& bp) + { + mStreamData.uGlowTopPlane = tp; + mStreamData.uGlowBottomPlane = bp; + } + + void SetGradientPlanes(const FVector4& tp, const FVector4& bp) { - auto &tn = top.Normal(); - auto &bn = bottom.Normal(); - mStreamData.uGlowTopPlane = { (float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD() }; - mStreamData.uGlowBottomPlane = { (float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD() }; + mStreamData.uGradientTopPlane = tp; + mStreamData.uGradientBottomPlane = bp; } - void SetGradientPlanes(const secplane_t &top, const secplane_t &bottom) + void SetSplitPlanes(const FVector4& tp, const FVector4& bp) { - auto &tn = top.Normal(); - auto &bn = bottom.Normal(); - mStreamData.uGradientTopPlane = { (float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD() }; - mStreamData.uGradientBottomPlane = { (float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD() }; + mStreamData.uSplitTopPlane = tp; + mStreamData.uSplitBottomPlane = bp; } - void SetSplitPlanes(const secplane_t &top, const secplane_t &bottom) + void SetDetailParms(float xscale, float yscale, float bias) { - auto &tn = top.Normal(); - auto &bn = bottom.Normal(); - mStreamData.uSplitTopPlane = { (float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD() }; - mStreamData.uSplitBottomPlane = { (float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD() }; + mStreamData.uDetailParms = { xscale, yscale, bias, 0 }; } void SetDynLight(float r, float g, float b) { - mStreamData.uDynLightColor = { r, g, b, 0.0f }; + mStreamData.uDynLightColor.X = r; + mStreamData.uDynLightColor.Y = g; + mStreamData.uDynLightColor.Z = b; + } + + void SetScreenFade(float f) + { + // This component is otherwise unused. + mStreamData.uDynLightColor.W = f; } void SetObjectColor(PalEntry pe) @@ -471,6 +511,13 @@ class FRenderState mStreamData.uAddColor = pe; } + void SetNpotEmulation(float factor, float offset) + { +#ifdef NPOT_EMULATION + mStreamData.uNpotEmulation = { offset, factor, 0, 0 }; +#endif + } + void ApplyTextureManipulation(TextureManipulation* texfx) { if (!texfx || texfx->AddColor.a == 0) @@ -486,6 +533,12 @@ class FRenderState mStreamData.uTextureBlendColor = texfx->BlendColor; } } + void SetTextureColors(float* modColor, float* addColor, float* blendColor) + { + mStreamData.uTextureAddColor.SetFlt(addColor[0], addColor[1], addColor[2], addColor[3]); + mStreamData.uTextureModulateColor.SetFlt(modColor[0], modColor[1], modColor[2], modColor[3]); + mStreamData.uTextureBlendColor.SetFlt(blendColor[0], blendColor[1], blendColor[2], blendColor[3]); + } void SetFog(PalEntry c, float d) { @@ -512,17 +565,14 @@ class FRenderState else mAlphaThreshold = thresh - 0.001f; } - void SetPlaneTextureRotation(HWSectorPlane *plane, FMaterial *texture) + void SetLightIndex(int index) { - if (hw_SetPlaneTextureRotation(plane, texture, mTextureMatrix)) - { - EnableTextureMatrix(true); - } + mLightIndex = index; } - void SetLightIndex(int index) + void SetBoneIndexBase(int index) { - mLightIndex = index; + mBoneIndexBase = index; } void SetRenderStyle(FRenderStyle rs) @@ -535,20 +585,31 @@ class FRenderState mRenderStyle = rs; } + auto GetDepthBias() + { + return mBias; + } + void SetDepthBias(float a, float b) { + mBias.mChanged |= mBias.mFactor != a || mBias.mUnits != b; mBias.mFactor = a; mBias.mUnits = b; - mBias.mChanged = true; + } + + void SetDepthBias(FDepthBiasState& bias) + { + SetDepthBias(bias.mFactor, bias.mUnits); } void ClearDepthBias() { + mBias.mChanged |= mBias.mFactor != 0 || mBias.mUnits != 0; mBias.mFactor = 0; mBias.mUnits = 0; - mBias.mChanged = true; } +private: void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader) { mMaterial.mMaterial = mat; @@ -556,8 +617,30 @@ class FRenderState mMaterial.mTranslation = translation; mMaterial.mOverrideShader = overrideshader; mMaterial.mChanged = true; + mTextureModeFlags = mat->GetLayerFlags(); + auto scale = mat->GetDetailScale(); + mStreamData.uDetailParms = { scale.X, scale.Y, 2, 0 }; + } + +public: + void SetMaterial(FGameTexture* tex, EUpscaleFlags upscalemask, int scaleflags, int clampmode, int translation, int overrideshader) + { + tex->setSeen(); + if (!sysCallbacks.PreBindTexture || !sysCallbacks.PreBindTexture(this, tex, upscalemask, scaleflags, clampmode, translation, overrideshader)) + { + if (shouldUpscale(tex, upscalemask)) scaleflags |= CTF_Upscale; + } + auto mat = FMaterial::ValidateTexture(tex, scaleflags); + assert(mat); + SetMaterial(mat, clampmode, translation, overrideshader); } + void SetMaterial(FGameTexture* tex, EUpscaleFlags upscalemask, int scaleflags, int clampmode, FTranslationID translation, int overrideshader) + { + SetMaterial(tex, upscalemask, scaleflags, clampmode, translation.index(), overrideshader); + } + + void SetClipSplit(float bottom, float top) { mClipSplit[0] = bottom; @@ -630,7 +713,11 @@ class FRenderState return mPassType; } - void CheckTimer(uint64_t ShaderStartTime); + void SetSpecialColormap(int cm, float flash) + { + mColorMapSpecial = cm; + mColorMapFlash = flash; + } // API-dependent render interface @@ -655,7 +742,7 @@ class FRenderState virtual void EnableDepthTest(bool on) = 0; // used by 2D, portals and render hacks. virtual void EnableMultisampling(bool on) = 0; // only active for 2D virtual void EnableLineSmooth(bool on) = 0; // constant setting for each 2D drawer operation - virtual void EnableDrawBuffers(int count) = 0; // Used by SSAO and EnableDrawBufferAttachments + virtual void EnableDrawBuffers(int count, bool apply = false) = 0; // Used by SSAO and EnableDrawBufferAttachments void SetColorMask(bool on) { diff --git a/src/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp b/src/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp new file mode 100644 index 00000000000..d32b09e2333 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp @@ -0,0 +1,312 @@ +/* +** hw_shaderpatcher.cpp +** Modifies shader source to account for different syntax versions or engine changes. +** +**--------------------------------------------------------------------------- +** Copyright(C) 2004-2018 Christoph Oelckers +** Copyright(C) 2016-2018 Magnus Norddahl +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + + +#include "cmdlib.h" +#include "hw_shaderpatcher.h" +#include "textures.h" +#include "hw_renderstate.h" +#include "v_video.h" + + +static bool IsGlslWhitespace(char c) +{ + switch (c) + { + case ' ': + case '\r': + case '\n': + case '\t': + case '\f': + return true; + default: + return false; + } +} + +static FString NextGlslToken(const char *chars, ptrdiff_t len, ptrdiff_t &pos) +{ + // Eat whitespace + ptrdiff_t tokenStart = pos; + while (tokenStart != len && IsGlslWhitespace(chars[tokenStart])) + tokenStart++; + + // Find token end + ptrdiff_t tokenEnd = tokenStart; + while (tokenEnd != len && !IsGlslWhitespace(chars[tokenEnd]) && chars[tokenEnd] != ';') + tokenEnd++; + + pos = tokenEnd; + return FString(chars + tokenStart, tokenEnd - tokenStart); +} + +static bool isShaderType(const char *name) +{ + return !strcmp(name, "sampler1D") || !strcmp(name, "sampler2D") || !strcmp(name, "sampler3D") || !strcmp(name, "samplerCube") || !strcmp(name, "sampler2DMS"); +} + +FString RemoveLegacyUserUniforms(FString code) +{ + // User shaders must declare their uniforms via the GLDEFS file. + + code.Substitute("uniform sampler2D tex;", " "); + code.Substitute("uniform float timer;", " "); + + // The following code searches for legacy uniform declarations in the shader itself and replaces them with whitespace. + + ptrdiff_t len = code.Len(); + char *chars = code.LockBuffer(); + + ptrdiff_t startIndex = 0; + while (true) + { + ptrdiff_t matchIndex = code.IndexOf("uniform", startIndex); + if (matchIndex == -1) + break; + + bool isLegacyUniformName = false; + + bool isKeywordStart = matchIndex == 0 || IsGlslWhitespace(chars[matchIndex - 1]); + bool isKeywordEnd = matchIndex + 7 == len || IsGlslWhitespace(chars[matchIndex + 7]); + if (isKeywordStart && isKeywordEnd) + { + ptrdiff_t pos = matchIndex + 7; + FString type = NextGlslToken(chars, len, pos); + FString identifier = NextGlslToken(chars, len, pos); + + isLegacyUniformName = type.Compare("float") == 0 && identifier.Compare("timer") == 0; + } + + if (isLegacyUniformName) + { + ptrdiff_t statementEndIndex = code.IndexOf(';', matchIndex + 7); + if (statementEndIndex == -1) + statementEndIndex = len; + for (ptrdiff_t i = matchIndex; i <= statementEndIndex; i++) + { + if (!IsGlslWhitespace(chars[i])) + chars[i] = ' '; + } + startIndex = statementEndIndex; + } + else + { + startIndex = matchIndex + 7; + } + } + + // Also remove all occurences of the token 'texture2d'. Some shaders may still use this deprecated function to access a sampler. + // Modern GLSL only allows use of 'texture'. + while (true) + { + ptrdiff_t matchIndex = code.IndexOf("texture2d", startIndex); + if (matchIndex == -1) + break; + + // Check if this is a real token. + bool isKeywordStart = matchIndex == 0 || !isalnum(chars[matchIndex - 1] & 255); + bool isKeywordEnd = matchIndex + 9 == len || !isalnum(chars[matchIndex + 9] & 255); + if (isKeywordStart && isKeywordEnd) + { + chars[matchIndex + 7] = chars[matchIndex + 8] = ' '; + } + startIndex = matchIndex + 9; + } + + code.UnlockBuffer(); + + return code; +} + +FString RemoveSamplerBindings(FString code, TArray> &samplerstobind) +{ + ptrdiff_t len = code.Len(); + char *chars = code.LockBuffer(); + + ptrdiff_t startIndex = 0; + ptrdiff_t startpos, endpos = 0; + while (true) + { + ptrdiff_t matchIndex = code.IndexOf("layout(binding", startIndex); + if (matchIndex == -1) + break; + + bool isSamplerUniformName = false; + + bool isKeywordStart = matchIndex == 0 || IsGlslWhitespace(chars[matchIndex - 1]); + bool isKeywordEnd = matchIndex + 14 == len || IsGlslWhitespace(chars[matchIndex + 14]) || chars[matchIndex + 14] == '='; + if (isKeywordStart && isKeywordEnd) + { + ptrdiff_t pos = matchIndex + 14; + startpos = matchIndex; + while (IsGlslWhitespace(chars[pos])) pos++; + if (chars[pos] == '=') + { + char *p; + pos++; + auto val = strtol(&chars[pos], &p, 0); + if (p != &chars[pos]) + { + pos = (p - chars); + while (IsGlslWhitespace(chars[pos])) pos++; + if (chars[pos] == ')') + { + endpos = ++pos; + FString uniform = NextGlslToken(chars, len, pos); + FString type = NextGlslToken(chars, len, pos); + FString identifier = NextGlslToken(chars, len, pos); + + isSamplerUniformName = uniform.Compare("uniform") == 0 && isShaderType(type.GetChars()); + if (isSamplerUniformName) + { + samplerstobind.Push(std::make_pair(identifier, val)); + for (auto posi = startpos; posi < endpos; posi++) + { + if (!IsGlslWhitespace(chars[posi])) + chars[posi] = ' '; + } + } + } + } + } + } + + if (isSamplerUniformName) + { + startIndex = endpos; + } + else + { + startIndex = matchIndex + 7; + } + } + + code.UnlockBuffer(); + + return code; +} + +FString RemoveLayoutLocationDecl(FString code, const char *inoutkeyword) +{ + char *chars = code.LockBuffer(); + + ptrdiff_t startIndex = 0; + while (true) + { + ptrdiff_t matchIndex = code.IndexOf("layout(location", startIndex); + if (matchIndex == -1) + break; + + ptrdiff_t endIndex = matchIndex; + + // Find end of layout declaration + while (chars[endIndex] != ')' && chars[endIndex] != 0) + endIndex++; + + if (chars[endIndex] == ')') + endIndex++; + else if (chars[endIndex] == 0) + break; + + // Skip whitespace + while (IsGlslWhitespace(chars[endIndex])) + endIndex++; + + // keyword following the declaration? + bool keywordFound = true; + ptrdiff_t i; + for (i = 0; inoutkeyword[i] != 0; i++) + { + if (chars[endIndex + i] != inoutkeyword[i]) + { + keywordFound = false; + break; + } + } + if (keywordFound && IsGlslWhitespace(chars[endIndex + i])) + { + // yes - replace declaration with spaces + for (auto ii = matchIndex; ii < endIndex; ii++) + chars[ii] = ' '; + } + + startIndex = endIndex; + } + + code.UnlockBuffer(); + + return code; +} + +///////////////////////////////////////////////////////////////////////////// + +// Note: the MaterialShaderIndex enum in gl_shader.h needs to be updated whenever this array is modified. +const FDefaultShader defaultshaders[] = +{ + {"Default", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", ""}, + {"Warp 1", "shaders/glsl/func_warp1.fp", "shaders/glsl/material_normal.fp", ""}, + {"Warp 2", "shaders/glsl/func_warp2.fp", "shaders/glsl/material_normal.fp", ""}, + {"Specular", "shaders/glsl/func_spec.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"}, + {"PBR","shaders/glsl/func_pbr.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"}, + {"Paletted", "shaders/glsl/func_paletted.fp", "shaders/glsl/material_nolight.fp", "#define PALETTE_EMULATION\n"}, + {"No Texture", "shaders/glsl/func_notexture.fp", "shaders/glsl/material_normal.fp", "#define NO_LAYERS\n"}, + {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", "shaders/glsl/material_normal.fp", ""}, + {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp", "shaders/glsl/material_normal.fp", ""}, + {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp", "shaders/glsl/material_normal.fp", ""}, + {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp", "shaders/glsl/material_normal.fp", ""}, + {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp", "shaders/glsl/material_normal.fp", ""}, + {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp", "shaders/glsl/material_normal.fp", ""}, + {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp", "shaders/glsl/material_normal.fp", ""}, + {"Software Fuzz", "shaders/glsl/fuzz_software.fp", "shaders/glsl/material_normal.fp", ""}, + {nullptr,nullptr,nullptr,nullptr} +}; + +const FEffectShader effectshaders[] = +{ + { "fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", nullptr, nullptr, "#define NO_ALPHATEST\n" }, + { "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" }, + { "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, + { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, + { "dithertrans", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define NO_ALPHATEST\n#define DITHERTRANS\n" }, +}; + +int DFrameBuffer::GetShaderCount() +{ + int i; + for (i = 0; defaultshaders[i].ShaderName != nullptr; i++); + + return MAX_PASS_TYPES * (countof(defaultshaders) - 1 + usershaders.Size() + MAX_EFFECTS + SHADER_NoTexture); +} + diff --git a/src/rendering/hwrenderer/utility/hw_shaderpatcher.h b/src/common/rendering/hwrenderer/data/hw_shaderpatcher.h similarity index 99% rename from src/rendering/hwrenderer/utility/hw_shaderpatcher.h rename to src/common/rendering/hwrenderer/data/hw_shaderpatcher.h index 7133441a29b..4a3a1c39fdc 100644 --- a/src/rendering/hwrenderer/utility/hw_shaderpatcher.h +++ b/src/common/rendering/hwrenderer/data/hw_shaderpatcher.h @@ -28,3 +28,4 @@ struct FEffectShader extern const FDefaultShader defaultshaders[]; extern const FEffectShader effectshaders[]; + diff --git a/src/common/rendering/hwrenderer/data/hw_shadowmap.cpp b/src/common/rendering/hwrenderer/data/hw_shadowmap.cpp new file mode 100644 index 00000000000..e5360984032 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_shadowmap.cpp @@ -0,0 +1,156 @@ +// +//--------------------------------------------------------------------------- +// 1D dynamic shadow maps (API independent part) +// Copyright(C) 2017 Magnus Norddahl +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include "hw_shadowmap.h" +#include "hw_cvars.h" +#include "hw_dynlightdata.h" +#include "buffers.h" +#include "shaderuniforms.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" + +/* + The 1D shadow maps are stored in a 1024x1024 texture as float depth values (R32F). + + Each line in the texture is assigned to a single light. For example, to grab depth values for light 20 + the fragment shader (main.fp) needs to sample from row 20. That is, the V texture coordinate needs + to be 20.5/1024. + + The texel row for each light is split into four parts. One for each direction, like a cube texture, + but then only in 2D where this reduces itself to a square. When main.fp samples from the shadow map + it first decides in which direction the fragment is (relative to the light), like cubemap sampling does + for 3D, but once again just for the 2D case. + + Texels 0-255 is Y positive, 256-511 is X positive, 512-767 is Y negative and 768-1023 is X negative. + + Generating the shadow map itself is done by FShadowMap::Update(). The shadow map texture's FBO is + bound and then a screen quad is drawn to make a fragment shader cover all texels. For each fragment + it shoots a ray and collects the distance to what it hit. + + The shadowmap.fp shader knows which light and texel it is processing by mapping gl_FragCoord.y back + to the light index, and it knows which direction to ray trace by looking at gl_FragCoord.x. For + example, if gl_FragCoord.y is 20.5, then it knows its processing light 20, and if gl_FragCoord.x is + 127.5, then it knows we are shooting straight ahead for the Y positive direction. + + Ray testing is done by uploading two GPU storage buffers - one holding AABB tree nodes, and one with + the line segments at the leaf nodes of the tree. The fragment shader then performs a test same way + as on the CPU, except everything uses indexes as pointers are not allowed in GLSL. +*/ + +cycle_t IShadowMap::UpdateCycles; +int IShadowMap::LightsProcessed; +int IShadowMap::LightsShadowmapped; + +CVAR(Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + +ADD_STAT(shadowmap) +{ + FString out; + out.Format("upload=%04.2f ms lights=%d shadowmapped=%d", IShadowMap::UpdateCycles.TimeMS(), IShadowMap::LightsProcessed, IShadowMap::LightsShadowmapped); + return out; +} + +CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + switch (self) + { + case 128: + case 256: + case 512: + case 1024: + break; + default: + self = 128; + break; + } +} + +bool IShadowMap::ShadowTest(const DVector3 &lpos, const DVector3 &pos) +{ + if (mAABBTree && gl_light_shadowmap) + return mAABBTree->RayTest(lpos, pos) >= 1.0f; + else + return true; +} + +bool IShadowMap::PerformUpdate() +{ + UpdateCycles.Reset(); + + LightsProcessed = 0; + LightsShadowmapped = 0; + + // CollectLights will be null if the calling code decides that shadowmaps are not needed. + if (CollectLights != nullptr) + { + UpdateCycles.Clock(); + UploadAABBTree(); + UploadLights(); + return true; + } + return false; +} + +void IShadowMap::UploadLights() +{ + mLights.Resize(1024 * 4); + CollectLights(); + + if (mLightList == nullptr) + mLightList = screen->CreateDataBuffer(LIGHTLIST_BINDINGPOINT, true, false); + + mLightList->SetData(sizeof(float) * mLights.Size(), &mLights[0], BufferUsageType::Stream); +} + + +void IShadowMap::UploadAABBTree() +{ + if (mNewTree) + { + mNewTree = false; + + if (!mNodesBuffer) + mNodesBuffer = screen->CreateDataBuffer(LIGHTNODES_BINDINGPOINT, true, false); + mNodesBuffer->SetData(mAABBTree->NodesSize(), mAABBTree->Nodes(), BufferUsageType::Static); + + if (!mLinesBuffer) + mLinesBuffer = screen->CreateDataBuffer(LIGHTLINES_BINDINGPOINT, true, false); + mLinesBuffer->SetData(mAABBTree->LinesSize(), mAABBTree->Lines(), BufferUsageType::Static); + } + else if (mAABBTree->Update()) + { + mNodesBuffer->SetSubData(mAABBTree->DynamicNodesOffset(), mAABBTree->DynamicNodesSize(), mAABBTree->DynamicNodes()); + mLinesBuffer->SetSubData(mAABBTree->DynamicLinesOffset(), mAABBTree->DynamicLinesSize(), mAABBTree->DynamicLines()); + } +} + +void IShadowMap::Reset() +{ + delete mLightList; mLightList = nullptr; + delete mNodesBuffer; mNodesBuffer = nullptr; + delete mLinesBuffer; mLinesBuffer = nullptr; +} + +IShadowMap::~IShadowMap() +{ + Reset(); +} + diff --git a/src/common/rendering/hwrenderer/data/hw_shadowmap.h b/src/common/rendering/hwrenderer/data/hw_shadowmap.h new file mode 100644 index 00000000000..3bc2eb98f88 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_shadowmap.h @@ -0,0 +1,92 @@ + +#pragma once + +#include "hw_aabbtree.h" +#include "stats.h" +#include +#include + +class IDataBuffer; + +class IShadowMap +{ +public: + IShadowMap() { } + virtual ~IShadowMap(); + + void Reset(); + + // Test if a world position is in shadow relative to the specified light and returns false if it is + bool ShadowTest(const DVector3 &lpos, const DVector3 &pos); + + static cycle_t UpdateCycles; + static int LightsProcessed; + static int LightsShadowmapped; + + bool PerformUpdate(); + void FinishUpdate() + { + UpdateCycles.Clock(); + } + + unsigned int NodesCount() const + { + assert(mAABBTree); + return mAABBTree->NodesCount(); + } + + void SetAABBTree(hwrenderer::LevelAABBTree* tree) + { + if (mAABBTree != tree) + { + mAABBTree = tree; + mNewTree = true; + } + } + + void SetCollectLights(std::function func) + { + CollectLights = std::move(func); + } + + void SetLight(int index, float x, float y, float z, float r) + { + index *= 4; + mLights[index] = x; + mLights[index + 1] = y; + mLights[index + 2] = z; + mLights[index + 3] = r; + } + + bool Enabled() const + { + return mAABBTree != nullptr; + } + +protected: + // Upload the AABB-tree to the GPU + void UploadAABBTree(); + void UploadLights(); + + // Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame + TArray mLights; + + // AABB-tree of the level, used for ray tests, owned by the playsim, not the renderer. + hwrenderer::LevelAABBTree* mAABBTree = nullptr; + bool mNewTree = false; + + IShadowMap(const IShadowMap &) = delete; + IShadowMap &operator=(IShadowMap &) = delete; + + // OpenGL storage buffer with the list of lights in the shadow map texture + // These buffers need to be accessed by the OpenGL backend directly so that they can be bound. +public: + IDataBuffer *mLightList = nullptr; + + // OpenGL storage buffers for the AABB tree + IDataBuffer *mNodesBuffer = nullptr; + IDataBuffer *mLinesBuffer = nullptr; + + std::function CollectLights = nullptr; + +}; diff --git a/src/common/rendering/hwrenderer/data/hw_skydome.cpp b/src/common/rendering/hwrenderer/data/hw_skydome.cpp new file mode 100644 index 00000000000..18108c8f230 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_skydome.cpp @@ -0,0 +1,577 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2003-2018 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** +** Draws the sky. Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky. +** +** for FSkyVertexBuffer::SkyVertex only: +**--------------------------------------------------------------------------- +** Copyright 2003 Tim Stump +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include "filesystem.h" +#include "cmdlib.h" +#include "bitmap.h" +#include "skyboxtexture.h" +#include "hw_material.h" +#include "hw_skydome.h" +#include "hw_renderstate.h" +#include "v_video.h" +#include "hwrenderer/data/buffers.h" +#include "version.h" + +//----------------------------------------------------------------------------- +// +// Shamelessly lifted from Doomsday (written by Jaakko Keränen) +// also shamelessly lifted from ZDoomGL! ;) +// +//----------------------------------------------------------------------------- +CVAR(Float, skyoffset, 0.f, 0) // for testing + + +struct SkyColor +{ + FTextureID Texture; + std::pair Colors; +}; + +static TArray SkyColors; + +std::pair& R_GetSkyCapColor(FGameTexture* tex) +{ + for (auto& sky : SkyColors) + { + if (sky.Texture == tex->GetID()) return sky.Colors; + } + + auto itex = tex->GetTexture(); + SkyColor sky; + + FBitmap bitmap = itex->GetBgraBitmap(nullptr); + int w = bitmap.GetWidth(); + int h = bitmap.GetHeight(); + + const uint32_t* buffer = (const uint32_t*)bitmap.GetPixels(); + if (buffer) + { + sky.Colors.first = averageColor((uint32_t*)buffer, w * min(30, h), 0); + if (h > 30) + { + sky.Colors.second = averageColor(((uint32_t*)buffer) + (h - 30) * w, w * 30, 0); + } + else sky.Colors.second = sky.Colors.first; + } + sky.Texture = tex->GetID(); + SkyColors.Push(sky); + + return SkyColors.Last().Colors; +} + + + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +FSkyVertexBuffer::FSkyVertexBuffer() +{ + CreateDome(); + mVertexBuffer = screen->CreateVertexBuffer(); + + static const FVertexBufferAttribute format[] = { + { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FSkyVertex, x) }, + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FSkyVertex, u) }, + { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(FSkyVertex, color) }, + { 0, VATTR_LIGHTMAP, VFmt_Float3, (int)myoffsetof(FSkyVertex, lu) }, + }; + mVertexBuffer->SetFormat(1, 4, sizeof(FSkyVertex), format); + mVertexBuffer->SetData(mVertices.Size() * sizeof(FSkyVertex), &mVertices[0], BufferUsageType::Static); +} + +FSkyVertexBuffer::~FSkyVertexBuffer() +{ + delete mVertexBuffer; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::SkyVertexDoom(int r, int c, bool zflip) +{ + static const FAngle maxSideAngle = FAngle::fromDeg(60.f); + static const float scale = 10000.; + + FAngle topAngle = FAngle::fromDeg((c / (float)mColumns * 360.f)); + FAngle sideAngle = maxSideAngle * float(mRows - r) / float(mRows); + float height = sideAngle.Sin(); + float realRadius = scale * sideAngle.Cos(); + FVector2 pos = topAngle.ToVector(realRadius); + float z = (!zflip) ? scale * height : -scale * height; + + FSkyVertex vert; + + vert.color = r == 0 ? 0xffffff : 0xffffffff; + + // And the texture coordinates. + if (!zflip) // Flipped Y is for the lower hemisphere. + { + vert.u = (-c / (float)mColumns); + vert.v = (r / (float)mRows); + } + else + { + vert.u = (-c / (float)mColumns); + vert.v = 1.0f + ((mRows - r) / (float)mRows); + } + + if (r != 4) z += 300; + // And finally the vertex. + vert.x = -pos.X; // Doom mirrors the sky vertically! + vert.y = z - 1.f; + vert.z = pos.Y; + + mVertices.Push(vert); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::SkyVertexBuild(int r, int c, bool zflip) +{ + static const FAngle maxSideAngle = FAngle::fromDeg(60.f); + static const float scale = 10000.; + + FAngle topAngle = FAngle::fromDeg((c / (float)mColumns * 360.f)); + FVector2 pos = topAngle.ToVector(scale); + float z = (!zflip) ? (mRows - r) * 4000.f : -(mRows - r) * 4000.f; + + FSkyVertex vert; + + vert.color = r == 0 ? 0xffffff : 0xffffffff; + + // And the texture coordinates. + if (zflip) r = mRows * 2 - r; + vert.u = 0.5f + (-c / (float)mColumns); + vert.v = (r / (float)(2*mRows)); + + // And finally the vertex. + vert.x = pos.X; + vert.y = z - 1.f; + vert.z = pos.Y; + + mVertices.Push(vert); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::CreateSkyHemisphereDoom(int hemi) +{ + int r, c; + bool zflip = !!(hemi & SKYHEMI_LOWER); + + mPrimStartDoom.Push(mVertices.Size()); + + for (c = 0; c < mColumns; c++) + { + SkyVertexDoom(1, c, zflip); + } + + // The total number of triangles per hemisphere can be calculated + // as follows: rows * columns * 2 + 2 (for the top cap). + for (r = 0; r < mRows; r++) + { + mPrimStartDoom.Push(mVertices.Size()); + for (c = 0; c <= mColumns; c++) + { + SkyVertexDoom(r + zflip, c, zflip); + SkyVertexDoom(r + 1 - zflip, c, zflip); + } + } +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::CreateSkyHemisphereBuild(int hemi) +{ + int r, c; + bool zflip = !!(hemi & SKYHEMI_LOWER); + + mPrimStartBuild.Push(mVertices.Size()); + + for (c = 0; c < mColumns; c++) + { + SkyVertexBuild(1, c, zflip); + } + + // The total number of triangles per hemisphere can be calculated + // as follows: rows * columns * 2 + 2 (for the top cap). + for (r = 0; r < mRows; r++) + { + mPrimStartBuild.Push(mVertices.Size()); + for (c = 0; c <= mColumns; c++) + { + SkyVertexBuild(r + zflip, c, zflip); + SkyVertexBuild(r + 1 - zflip, c, zflip); + } + } +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::CreateDome() +{ + // the first thing we put into the buffer is the fog layer object which is just 4 triangles around the viewpoint. + + mVertices.Reserve(12); + mVertices[0].Set(1.0f, 1.0f, -1.0f); + mVertices[1].Set(1.0f, -1.0f, -1.0f); + mVertices[2].Set(-1.0f, 0.0f, -1.0f); + + mVertices[3].Set(1.0f, 1.0f, -1.0f); + mVertices[4].Set(1.0f, -1.0f, -1.0f); + mVertices[5].Set(0.0f, 0.0f, 1.0f); + + mVertices[6].Set(-1.0f, 0.0f, -1.0f); + mVertices[7].Set(1.0f, 1.0f, -1.0f); + mVertices[8].Set(0.0f, 0.0f, 1.0f); + + mVertices[9].Set(1.0f, -1.0f, -1.0f); + mVertices[10].Set(-1.0f, 0.0f, -1.0f); + mVertices[11].Set(0.0f, 0.0f, 1.0f); + + mColumns = 128; + mRows = 4; + CreateSkyHemisphereDoom(SKYHEMI_UPPER); + CreateSkyHemisphereDoom(SKYHEMI_LOWER); + mPrimStartDoom.Push(mVertices.Size()); + + CreateSkyHemisphereBuild(SKYHEMI_UPPER); + CreateSkyHemisphereBuild(SKYHEMI_LOWER); + mPrimStartBuild.Push(mVertices.Size()); + + mSideStart = mVertices.Size(); + mFaceStart[0] = mSideStart + 10; + mFaceStart[1] = mFaceStart[0] + 4; + mFaceStart[2] = mFaceStart[1] + 4; + mFaceStart[3] = mFaceStart[2] + 4; + mFaceStart[4] = mFaceStart[3] + 4; + mFaceStart[5] = mFaceStart[4] + 4; + mFaceStart[6] = mFaceStart[5] + 4; + mVertices.Reserve(10 + 7*4); + FSkyVertex *ptr = &mVertices[mSideStart]; + + // all sides + ptr[0].SetXYZ(128.f, 128.f, -128.f, 0, 0); + ptr[1].SetXYZ(128.f, -128.f, -128.f, 0, 1); + ptr[2].SetXYZ(-128.f, 128.f, -128.f, 0.25f, 0); + ptr[3].SetXYZ(-128.f, -128.f, -128.f, 0.25f, 1); + ptr[4].SetXYZ(-128.f, 128.f, 128.f, 0.5f, 0); + ptr[5].SetXYZ(-128.f, -128.f, 128.f, 0.5f, 1); + ptr[6].SetXYZ(128.f, 128.f, 128.f, 0.75f, 0); + ptr[7].SetXYZ(128.f, -128.f, 128.f, 0.75f, 1); + ptr[8].SetXYZ(128.f, 128.f, -128.f, 1, 0); + ptr[9].SetXYZ(128.f, -128.f, -128.f, 1, 1); + + // north face + ptr[10].SetXYZ(128.f, 128.f, -128.f, 0, 0); + ptr[11].SetXYZ(-128.f, 128.f, -128.f, 1, 0); + ptr[12].SetXYZ(128.f, -128.f, -128.f, 0, 1); + ptr[13].SetXYZ(-128.f, -128.f, -128.f, 1, 1); + + // east face + ptr[14].SetXYZ(-128.f, 128.f, -128.f, 0, 0); + ptr[15].SetXYZ(-128.f, 128.f, 128.f, 1, 0); + ptr[16].SetXYZ(-128.f, -128.f, -128.f, 0, 1); + ptr[17].SetXYZ(-128.f, -128.f, 128.f, 1, 1); + + // south face + ptr[18].SetXYZ(-128.f, 128.f, 128.f, 0, 0); + ptr[19].SetXYZ(128.f, 128.f, 128.f, 1, 0); + ptr[20].SetXYZ(-128.f, -128.f, 128.f, 0, 1); + ptr[21].SetXYZ(128.f, -128.f, 128.f, 1, 1); + + // west face + ptr[22].SetXYZ(128.f, 128.f, 128.f, 0, 0); + ptr[23].SetXYZ(128.f, 128.f, -128.f, 1, 0); + ptr[24].SetXYZ(128.f, -128.f, 128.f, 0, 1); + ptr[25].SetXYZ(128.f, -128.f, -128.f, 1, 1); + + // bottom face + ptr[26].SetXYZ(128.f, -128.f, -128.f, 0, 0); + ptr[27].SetXYZ(-128.f, -128.f, -128.f, 1, 0); + ptr[28].SetXYZ(128.f, -128.f, 128.f, 0, 1); + ptr[29].SetXYZ(-128.f, -128.f, 128.f, 1, 1); + + // top face + ptr[30].SetXYZ(128.f, 128.f, -128.f, 0, 0); + ptr[31].SetXYZ(-128.f, 128.f, -128.f, 1, 0); + ptr[32].SetXYZ(128.f, 128.f, 128.f, 0, 1); + ptr[33].SetXYZ(-128.f, 128.f, 128.f, 1, 1); + + // top face flipped + ptr[34].SetXYZ(128.f, 128.f, -128.f, 0, 1); + ptr[35].SetXYZ(-128.f, 128.f, -128.f, 1, 1); + ptr[36].SetXYZ(128.f, 128.f, 128.f, 0, 0); + ptr[37].SetXYZ(-128.f, 128.f, 128.f, 1, 0); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelMatrix, VSMatrix &textureMatrix, bool tiled, float xscale, float yscale) +{ + float texw = tex->GetDisplayWidth(); + float texh = tex->GetDisplayHeight(); + + modelMatrix.loadIdentity(); + modelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f); + + if (xscale == 0) xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f; + auto texskyoffset = tex->GetSkyOffset() + skyoffset; + if (yscale == 0) + { + if (texh <= 128 && tiled) + { + modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f); + modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); + yscale = 240.f / texh; + } + else if (texh < 128) + { + // smaller sky textures must be tiled. We restrict it to 128 sky pixels, though + modelMatrix.translate(0.f, -1250.f, 0.f); + modelMatrix.scale(1.f, 128 / 230.f, 1.f); + yscale = float(128 / texh); // intentionally left as integer. + } + else if (texh < 200) + { + modelMatrix.translate(0.f, -1250.f, 0.f); + modelMatrix.scale(1.f, texh / 230.f, 1.f); + yscale = 1.f; + } + else if (texh <= 240) + { + modelMatrix.translate(0.f, (200 - texh + texskyoffset) * skyoffsetfactor, 0.f); + modelMatrix.scale(1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f, 1.f); + yscale = 1.f; + } + else + { + modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f); + modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); + yscale = 240.f / texh; + } + } + else + { + modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f); + modelMatrix.scale(1.f, 0.8f * 1.17f, 1.f); + } + textureMatrix.loadIdentity(); + textureMatrix.scale(mirror ? -xscale : xscale, yscale, 1.f); + textureMatrix.translate(1.f, y_offset / texh, 1.f); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::RenderRow(FRenderState& state, EDrawType prim, int row, TArray& mPrimStart, bool apply) +{ + state.Draw(prim, mPrimStart[row], mPrimStart[row + 1] - mPrimStart[row]); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::DoRenderDome(FRenderState& state, FGameTexture* tex, int mode, bool which, PalEntry color) +{ + auto& primStart = which ? mPrimStartBuild : mPrimStartDoom; + if (tex && tex->isValid()) + { + state.SetMaterial(tex, UF_Texture, 0, CLAMP_NONE, 0, -1); + state.EnableModelMatrix(true); + state.EnableTextureMatrix(true); + } + + int rc = mRows + 1; + + // The caps only get drawn for the main layer but not for the overlay. + if (mode == FSkyVertexBuffer::SKYMODE_MAINLAYER && tex != nullptr) + { + auto col = R_GetSkyCapColor(tex); + + col.first.r = col.first.r * color.r / 255; + col.first.g = col.first.g * color.g / 255; + col.first.b = col.first.b * color.b / 255; + col.second.r = col.second.r * color.r / 255; + col.second.g = col.second.g * color.g / 255; + col.second.b = col.second.b * color.b / 255; + + state.SetObjectColor(col.first); + state.EnableTexture(false); + RenderRow(state, DT_TriangleFan, 0, primStart); + + state.SetObjectColor(col.second); + RenderRow(state, DT_TriangleFan, rc, primStart); + state.EnableTexture(true); + } + state.SetObjectColor(0xffffffff); + for (int i = 1; i <= mRows; i++) + { + RenderRow(state, DT_TriangleStrip, i, primStart, i == 1); + RenderRow(state, DT_TriangleStrip, rc + i, primStart, false); + } + + state.EnableTextureMatrix(false); + state.EnableModelMatrix(false); +} + + +//----------------------------------------------------------------------------- +// +// This is only for Doom-style skies. +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled, float xscale, float yscale, PalEntry color) +{ + if (tex) + { + SetupMatrices(tex, x_offset, y_offset, mirror, mode, state.mModelMatrix, state.mTextureMatrix, tiled, xscale, yscale); + } + DoRenderDome(state, tex, mode, false, color); +} + + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::RenderBox(FRenderState& state, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2, PalEntry color) +{ + int faces; + + state.SetObjectColor(color); + state.EnableModelMatrix(true); + state.mModelMatrix.loadIdentity(); + state.mModelMatrix.scale(1, 1 / stretch, 1); // Undo the map's vertical scaling as skyboxes are true cubes. + + if (!sky2) + state.mModelMatrix.rotate(-180.0f + x_offset, skyrotatevector.X, skyrotatevector.Z, skyrotatevector.Y); + else + state.mModelMatrix.rotate(-180.0f + x_offset, skyrotatevector2.X, skyrotatevector2.Z, skyrotatevector2.Y); + + if (tex->GetSkyFace(5)) + { + faces = 4; + + // north + state.SetMaterial(tex->GetSkyFace(0), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(0), 4); + + // east + state.SetMaterial(tex->GetSkyFace(1), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(1), 4); + + // south + state.SetMaterial(tex->GetSkyFace(2), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(2), 4); + + // west + state.SetMaterial(tex->GetSkyFace(3), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(3), 4); + } + else + { + faces = 1; + state.SetMaterial(tex->GetSkyFace(0), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(-1), 10); + } + + // top + state.SetMaterial(tex->GetSkyFace(faces), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(tex->GetSkyFlip() ? 6 : 5), 4); + + // bottom + state.SetMaterial(tex->GetSkyFace(faces + 1), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(4), 4); + + state.EnableModelMatrix(false); + state.SetObjectColor(0xffffffff); +} + diff --git a/src/common/rendering/hwrenderer/data/hw_skydome.h b/src/common/rendering/hwrenderer/data/hw_skydome.h new file mode 100644 index 00000000000..f794e96bbdd --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_skydome.h @@ -0,0 +1,103 @@ +#pragma once + +#include "matrix.h" +#include "hwrenderer/data/buffers.h" +#include "hw_renderstate.h" +#include "skyboxtexture.h" + +class FGameTexture; +class FRenderState; +class IVertexBuffer; +struct HWSkyPortal; +struct HWDrawInfo; + +// 57 world units roughly represent one sky texel for the glTranslate call. +const int skyoffsetfactor = 57; + +struct FSkyVertex +{ + float x, y, z, u, v, lu, lv, lindex; + PalEntry color; + + void Set(float xx, float zz, float yy, float uu=0, float vv=0, PalEntry col=0xffffffff) + { + x = xx; + z = zz; + y = yy; + u = uu; + v = vv; + lu = 0.0f; + lv = 0.0f; + lindex = -1.0f; + color = col; + } + + void SetXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0, PalEntry col = 0xffffffff) + { + x = xx; + y = yy; + z = zz; + u = uu; + v = vv; + lu = 0.0f; + lv = 0.0f; + lindex = -1.0f; + color = col; + } + +}; + +class FSkyVertexBuffer +{ + friend struct HWSkyPortal; +public: + static const int SKYHEMI_UPPER = 1; + static const int SKYHEMI_LOWER = 2; + + enum + { + SKYMODE_MAINLAYER = 0, + SKYMODE_SECONDLAYER = 1, + SKYMODE_FOGLAYER = 2 + }; + + IVertexBuffer *mVertexBuffer; + + TArray mVertices; + TArray mPrimStartDoom; + TArray mPrimStartBuild; + + int mRows, mColumns; + + // indices for sky cubemap faces + int mFaceStart[7]; + int mSideStart; + + void SkyVertexDoom(int r, int c, bool yflip); + void SkyVertexBuild(int r, int c, bool yflip); + void CreateSkyHemisphereDoom(int hemi); + void CreateSkyHemisphereBuild(int hemi); + void CreateDome(); + +public: + + FSkyVertexBuffer(); + ~FSkyVertexBuffer(); + void SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelmatrix, VSMatrix &textureMatrix, bool tiled, float xscale = 0, float vertscale = 0); + std::pair GetBufferObjects() const + { + return std::make_pair(mVertexBuffer, nullptr); + } + + int FaceStart(int i) + { + if (i >= 0 && i < 7) return mFaceStart[i]; + else return mSideStart; + } + + void RenderRow(FRenderState& state, EDrawType prim, int row, TArray& mPrimStart, bool apply = true); + void DoRenderDome(FRenderState& state, FGameTexture* tex, int mode, bool which, PalEntry color = 0xffffffff); + void RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled, float xscale = 0, float yscale = 0, PalEntry color = 0xffffffff); + void RenderBox(FRenderState& state, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2, PalEntry color = 0xffffffff); + +}; diff --git a/src/common/rendering/hwrenderer/data/hw_viewpointbuffer.cpp b/src/common/rendering/hwrenderer/data/hw_viewpointbuffer.cpp new file mode 100644 index 00000000000..fabd0257c46 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_viewpointbuffer.cpp @@ -0,0 +1,137 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2018 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_viewpointbuffer.cpp +** Buffer data maintenance for per viewpoint uniform data +** +**/ + +#include "hwrenderer/data/shaderuniforms.h" +#include "hw_viewpointuniforms.h" +#include "hw_renderstate.h" +#include "hw_viewpointbuffer.h" +#include "hw_cvars.h" + +static const int INITIAL_BUFFER_SIZE = 100; // 100 viewpoints per frame should nearly always be enough + +HWViewpointBuffer::HWViewpointBuffer(int pipelineNbr): + mPipelineNbr(pipelineNbr) +{ + mBufferSize = INITIAL_BUFFER_SIZE; + mBlockAlign = ((sizeof(HWViewpointUniforms) / screen->uniformblockalignment) + 1) * screen->uniformblockalignment; + mByteSize = mBufferSize * mBlockAlign; + + for (int n = 0; n < mPipelineNbr; n++) + { + mBufferPipeline[n] = screen->CreateDataBuffer(VIEWPOINT_BINDINGPOINT, false, true); + mBufferPipeline[n]->SetData(mByteSize, nullptr, BufferUsageType::Persistent); + } + + Clear(); + mLastMappedIndex = UINT_MAX; +} + +HWViewpointBuffer::~HWViewpointBuffer() +{ + delete mBuffer; +} + + +void HWViewpointBuffer::CheckSize() +{ + if (mUploadIndex >= mBufferSize) + { + mBufferSize *= 2; + mByteSize *= 2; + for (int n = 0; n < mPipelineNbr; n++) + { + mBufferPipeline[n]->Resize(mByteSize); + } + } +} + +int HWViewpointBuffer::Bind(FRenderState &di, unsigned int index) +{ + if (index != mLastMappedIndex) + { + mLastMappedIndex = index; + mBuffer->BindRange(&di, index * mBlockAlign, mBlockAlign); + di.EnableClipDistance(0, mClipPlaneInfo[index]); + } + return index; +} + +void HWViewpointBuffer::Set2D(FRenderState &di, int width, int height, int pll) +{ + HWViewpointUniforms matrices; + + matrices.mViewMatrix.loadIdentity(); + matrices.mNormalViewMatrix.loadIdentity(); + matrices.mViewHeight = 0; + matrices.mGlobVis = 1.f; + matrices.mPalLightLevels = pll; + matrices.mClipLine.X = -10000000.0f; + matrices.mShadowmapFilter = gl_shadowmap_filter; + matrices.mLightBlendMode = 0; + + matrices.mProjectionMatrix.ortho(0, (float)width, (float)height, 0, -1.0f, 1.0f); + matrices.CalcDependencies(); + + CheckSize(); + mBuffer->Map(); + memcpy(((char*)mBuffer->Memory()) + mUploadIndex * mBlockAlign, &matrices, sizeof(matrices)); + mBuffer->Unmap(); + + mClipPlaneInfo.Push(0); + + Bind(di, mUploadIndex++); +} + +int HWViewpointBuffer::SetViewpoint(FRenderState &di, HWViewpointUniforms *vp) +{ + CheckSize(); + mBuffer->Map(); + memcpy(((char*)mBuffer->Memory()) + mUploadIndex * mBlockAlign, vp, sizeof(*vp)); + mBuffer->Unmap(); + + mClipPlaneInfo.Push(vp->mClipHeightDirection != 0.f || vp->mClipLine.X > -10000000.0f); + return Bind(di, mUploadIndex++); +} + +void HWViewpointBuffer::Clear() +{ + bool needNewPipeline = mUploadIndex > 0; // Clear might be called multiple times before any actual rendering + + mUploadIndex = 0; + mClipPlaneInfo.Clear(); + + if (needNewPipeline) + { + mLastMappedIndex = UINT_MAX; + + mPipelinePos++; + mPipelinePos %= mPipelineNbr; + } + + mBuffer = mBufferPipeline[mPipelinePos]; +} + diff --git a/src/common/rendering/hwrenderer/data/hw_viewpointbuffer.h b/src/common/rendering/hwrenderer/data/hw_viewpointbuffer.h new file mode 100644 index 00000000000..8efe61738fd --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_viewpointbuffer.h @@ -0,0 +1,36 @@ +#pragma once +#include "tarray.h" +#include "hwrenderer/data/buffers.h" + +struct HWViewpointUniforms; +class FRenderState; + +class HWViewpointBuffer +{ + IDataBuffer *mBuffer; + IDataBuffer* mBufferPipeline[HW_MAX_PIPELINE_BUFFERS]; + int mPipelineNbr; + int mPipelinePos = 0; + + unsigned int mBufferSize; + unsigned int mBlockAlign; + unsigned int mUploadIndex; + unsigned int mLastMappedIndex; + unsigned int mByteSize; + TArray mClipPlaneInfo; + + unsigned int mBlockSize; + + void CheckSize(); + +public: + + HWViewpointBuffer(int pipelineNbr = 1); + ~HWViewpointBuffer(); + void Clear(); + int Bind(FRenderState &di, unsigned int index); + void Set2D(FRenderState &di, int width, int height, int pll = 0); + int SetViewpoint(FRenderState &di, HWViewpointUniforms *vp); + unsigned int GetBlockSize() const { return mBlockSize; } +}; + diff --git a/src/rendering/hwrenderer/scene/hw_viewpointuniforms.h b/src/common/rendering/hwrenderer/data/hw_viewpointuniforms.h similarity index 77% rename from src/rendering/hwrenderer/scene/hw_viewpointuniforms.h rename to src/common/rendering/hwrenderer/data/hw_viewpointuniforms.h index 5a1a1749d18..def3b48089f 100644 --- a/src/rendering/hwrenderer/scene/hw_viewpointuniforms.h +++ b/src/common/rendering/hwrenderer/data/hw_viewpointuniforms.h @@ -1,10 +1,18 @@ #pragma once #include "matrix.h" -#include "r_utility.h" struct HWDrawInfo; +enum class ELightBlendMode : uint8_t +{ + CLAMP = 0, + CLAMP_COLOR = 1, + NOCLAMP = 2, + + DEFAULT = CLAMP, +}; + struct HWViewpointUniforms { VSMatrix mProjectionMatrix; @@ -20,13 +28,12 @@ struct HWViewpointUniforms float mClipHeightDirection = 0.f; int mShadowmapFilter = 1; + int mLightBlendMode = 0; + void CalcDependencies() { mNormalViewMatrix.computeNormalMatrix(mViewMatrix); } - - void SetDefaults(HWDrawInfo *drawInfo); - }; diff --git a/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp b/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp new file mode 100644 index 00000000000..8cb3c94e5c0 --- /dev/null +++ b/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp @@ -0,0 +1,215 @@ +/* +** hw_vrmodes.cpp +** Matrix handling for stereo 3D rendering +** +**--------------------------------------------------------------------------- +** Copyright 2015 Christopher Bruns +** Copyright 2016-2021 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "vectors.h" +#include "hw_cvars.h" +#include "hw_vrmodes.h" +#include "v_video.h" +#include "version.h" +#include "i_interface.h" + +// Set up 3D-specific console variables: +CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) + +// switch left and right eye views +CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) + +// intraocular distance in meters +CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS + +// distance between viewer and the display screen +CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS + +// default conversion between (vertical) DOOM units and meters +CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS + + +#define isqrt2 0.7071067812f +static VRMode vrmi_mono = { 1, 1.f, 1.f, 1.f,{ { 0.f, 1.f },{ 0.f, 0.f } } }; +static VRMode vrmi_stereo = { 2, 1.f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; +static VRMode vrmi_sbsfull = { 2, .5f, 1.f, 2.f,{ { -.5f, .5f },{ .5f, .5f } } }; +static VRMode vrmi_sbssquished = { 2, .5f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; +static VRMode vrmi_lefteye = { 1, 1.f, 1.f, 1.f, { { -.5f, 1.f },{ 0.f, 0.f } } }; +static VRMode vrmi_righteye = { 1, 1.f, 1.f, 1.f,{ { .5f, 1.f },{ 0.f, 0.f } } }; +static VRMode vrmi_topbottom = { 2, 1.f, .5f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; +static VRMode vrmi_checker = { 2, isqrt2, isqrt2, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; + +static float DEG2RAD(float deg) +{ + return deg * float(M_PI / 180.0); +} + +static float RAD2DEG(float rad) +{ + return rad * float(180. / M_PI); +} + +const VRMode *VRMode::GetVRMode(bool toscreen) +{ + int mode = !toscreen || (sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter()) ? 0 : vr_mode; + + switch (mode) + { + default: + case VR_MONO: + return &vrmi_mono; + + case VR_GREENMAGENTA: + case VR_REDCYAN: + case VR_QUADSTEREO: + case VR_AMBERBLUE: + case VR_SIDEBYSIDELETTERBOX: + return &vrmi_stereo; + + case VR_SIDEBYSIDESQUISHED: + case VR_COLUMNINTERLEAVED: + return &vrmi_sbssquished; + + case VR_SIDEBYSIDEFULL: + return &vrmi_sbsfull; + + case VR_TOPBOTTOM: + case VR_ROWINTERLEAVED: + return &vrmi_topbottom; + + case VR_LEFTEYEVIEW: + return &vrmi_lefteye; + + case VR_RIGHTEYEVIEW: + return &vrmi_righteye; + + case VR_CHECKERINTERLEAVED: + return &vrmi_checker; + } +} + +void VRMode::AdjustViewport(DFrameBuffer *screen) const +{ + screen->mSceneViewport.height = (int)(screen->mSceneViewport.height * mVerticalViewportScale); + screen->mSceneViewport.top = (int)(screen->mSceneViewport.top * mVerticalViewportScale); + screen->mSceneViewport.width = (int)(screen->mSceneViewport.width * mHorizontalViewportScale); + screen->mSceneViewport.left = (int)(screen->mSceneViewport.left * mHorizontalViewportScale); + + screen->mScreenViewport.height = (int)(screen->mScreenViewport.height * mVerticalViewportScale); + screen->mScreenViewport.top = (int)(screen->mScreenViewport.top * mVerticalViewportScale); + screen->mScreenViewport.width = (int)(screen->mScreenViewport.width * mHorizontalViewportScale); + screen->mScreenViewport.left = (int)(screen->mScreenViewport.left * mHorizontalViewportScale); +} + +VSMatrix VRMode::GetHUDSpriteProjection() const +{ + VSMatrix mat; + int w = screen->GetWidth(); + int h = screen->GetHeight(); + float scaled_w = w / mWeaponProjectionScale; + float left_ofs = (w - scaled_w) / 2.f; + mat.ortho(left_ofs, left_ofs + scaled_w, (float)h, 0, -1.0f, 1.0f); + return mat; +} + +float VREyeInfo::getShift() const +{ + auto res = mShiftFactor * vr_ipd; + return vr_swap_eyes ? -res : res; +} + +VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const +{ + VSMatrix result; + + if (iso_ortho) // Orthographic projection for isometric viewpoint + { + double zNear = -3.0/fovRatio; // screen->GetZNear(); + double zFar = screen->GetZFar(); + + double fH = tan(DEG2RAD(fov) / 2) / fovRatio; + double fW = fH * aspectRatio * mScaleFactor; + double left = -fW; + double right = fW; + double bottom = -fH; + double top = fH; + + VSMatrix fmat(1); + fmat.ortho((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar); + return fmat; + } + else if (mShiftFactor == 0) + { + float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio))); + result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar()); + return result; + } + else + { + double zNear = screen->GetZNear(); + double zFar = screen->GetZFar(); + + // For stereo 3D, use asymmetric frustum shift in projection matrix + // Q: shouldn't shift vary with roll angle, at least for desktop display? + // A: No. (lab) roll is not measured on desktop display (yet) + double frustumShift = zNear * getShift() / vr_screendist; // meters cancel, leaving doom units + // double frustumShift = 0; // Turning off shift for debugging + double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio; + double fW = fH * aspectRatio * mScaleFactor; + double left = -fW - frustumShift; + double right = fW - frustumShift; + double bottom = -fH; + double top = fH; + + VSMatrix fmat(1); + fmat.frustum((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar); + return fmat; + } +} + + + +/* virtual */ +DVector3 VREyeInfo::GetViewShift(float yaw) const +{ + if (mShiftFactor == 0) + { + // pass-through for Mono view + return { 0,0,0 }; + } + else + { + double dx = -cos(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift(); + double dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift(); + return { dx, dy, 0 }; + } +} + diff --git a/src/rendering/hwrenderer/utility/hw_vrmodes.h b/src/common/rendering/hwrenderer/data/hw_vrmodes.h similarity index 93% rename from src/rendering/hwrenderer/utility/hw_vrmodes.h rename to src/common/rendering/hwrenderer/data/hw_vrmodes.h index a80ecaf5785..98928152018 100644 --- a/src/rendering/hwrenderer/utility/hw_vrmodes.h +++ b/src/common/rendering/hwrenderer/data/hw_vrmodes.h @@ -14,6 +14,7 @@ enum VR_LEFTEYEVIEW = 5, VR_RIGHTEYEVIEW = 6, VR_QUADSTEREO = 7, + VR_SIDEBYSIDELETTERBOX = 8, VR_AMBERBLUE = 9, VR_TOPBOTTOM = 11, VR_ROWINTERLEAVED = 12, @@ -26,7 +27,7 @@ struct VREyeInfo float mShiftFactor; float mScaleFactor; - VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const; + VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const; DVector3 GetViewShift(float yaw) const; private: float getShift() const; diff --git a/src/rendering/hwrenderer/data/renderqueue.h b/src/common/rendering/hwrenderer/data/renderqueue.h similarity index 100% rename from src/rendering/hwrenderer/data/renderqueue.h rename to src/common/rendering/hwrenderer/data/renderqueue.h diff --git a/src/rendering/hwrenderer/data/shaderuniforms.h b/src/common/rendering/hwrenderer/data/shaderuniforms.h similarity index 96% rename from src/rendering/hwrenderer/data/shaderuniforms.h rename to src/common/rendering/hwrenderer/data/shaderuniforms.h index 2543b52b1f3..4b11a3755a7 100644 --- a/src/rendering/hwrenderer/data/shaderuniforms.h +++ b/src/common/rendering/hwrenderer/data/shaderuniforms.h @@ -11,7 +11,8 @@ enum VIEWPOINT_BINDINGPOINT = 3, LIGHTNODES_BINDINGPOINT = 4, LIGHTLINES_BINDINGPOINT = 5, - LIGHTLIST_BINDINGPOINT = 6 + LIGHTLIST_BINDINGPOINT = 6, + BONEBUF_BINDINGPOINT = 7 }; enum class UniformType @@ -129,7 +130,7 @@ class ShaderUniforms void SetData() { if (mBuffer != nullptr) - mBuffer->SetData(sizeof(T), &Values); + mBuffer->SetData(sizeof(T), &Values, BufferUsageType::Static); } IDataBuffer* GetBuffer() const diff --git a/src/common/rendering/hwrenderer/hw_draw2d.cpp b/src/common/rendering/hwrenderer/hw_draw2d.cpp new file mode 100644 index 00000000000..5c7100b34fa --- /dev/null +++ b/src/common/rendering/hwrenderer/hw_draw2d.cpp @@ -0,0 +1,263 @@ +/* +** hw_draw2d.cpp +** 2d drawer Renderer interface +** +**--------------------------------------------------------------------------- +** Copyright 2018-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "v_video.h" +#include "cmdlib.h" +#include "hwrenderer/data/buffers.h" +#include "flatvertices.h" +#include "hwrenderer/data/hw_viewpointbuffer.h" +#include "hw_clock.h" +#include "hw_cvars.h" +#include "hw_renderstate.h" +#include "r_videoscale.h" +#include "v_draw.h" + +//=========================================================================== +// +// Draws the 2D stuff. This is the version for OpenGL 3 and later. +// +//=========================================================================== + +CVAR(Bool, gl_aalines, false, CVAR_ARCHIVE) + +void Draw2D(F2DDrawer* drawer, FRenderState& state) +{ + const auto& mScreenViewport = screen->mScreenViewport; + Draw2D(drawer, state, mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); +} + +void Draw2D(F2DDrawer* drawer, FRenderState& state, int x, int y, int width, int height) +{ + twoD.Clock(); + + state.SetViewport(x, y, width, height); + screen->mViewpoints->Set2D(state, drawer->GetWidth(), drawer->GetHeight()); + + state.EnableStencil(false); + state.SetStencil(0, SOP_Keep, SF_AllOn); + state.Clear(CT_Stencil); + state.EnableDepthTest(false); + state.EnableMultisampling(false); + state.EnableLineSmooth(gl_aalines); + + auto &vertices = drawer->mVertices; + auto &indices = drawer->mIndices; + auto &commands = drawer->mData; + + if (commands.Size() == 0) + { + twoD.Unclock(); + return; + } + + if (drawer->mIsFirstPass) + { + for (auto &v : vertices) + { + // Change from BGRA to RGBA + std::swap(v.color0.r, v.color0.b); + } + } + F2DVertexBuffer vb; + vb.UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size()); + state.SetVertexBuffer(&vb); + state.EnableFog(false); + + for(auto &cmd : commands) + { + if (cmd.isSpecial != SpecialDrawCommand::NotSpecial) + { + if (cmd.isSpecial == SpecialDrawCommand::EnableStencil) + { + state.EnableStencil(cmd.stencilOn); + } + else if (cmd.isSpecial == SpecialDrawCommand::SetStencil) + { + state.SetStencil(cmd.stencilOffs, cmd.stencilOp, cmd.stencilFlags); + } + else if (cmd.isSpecial == SpecialDrawCommand::ClearStencil) + { + state.Clear(CT_Stencil); + } + continue; + } + + state.SetRenderStyle(cmd.mRenderStyle); + state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed)); + state.EnableFog(2); // Special 2D mode 'fog'. + state.SetScreenFade(cmd.mScreenFade); + + state.SetTextureMode(cmd.mDrawMode); + + int sciX, sciY, sciW, sciH; + if (cmd.mFlags & F2DDrawer::DTF_Scissor) + { + // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates + // Note that the origin here is the lower left corner! + sciX = screen->ScreenToWindowX(cmd.mScissor[0]); + sciY = screen->ScreenToWindowY(cmd.mScissor[3]); + sciW = screen->ScreenToWindowX(cmd.mScissor[2]) - sciX; + sciH = screen->ScreenToWindowY(cmd.mScissor[1]) - sciY; + // If coordinates turn out negative, clip to sceen here to avoid undefined behavior. + if (sciX < 0) sciW += sciX, sciX = 0; + if (sciY < 0) sciH += sciY, sciY = 0; + } + else + { + sciX = sciY = sciW = sciH = -1; + } + state.SetScissor(sciX, sciY, sciW, sciH); + + if (cmd.mSpecialColormap[0].a != 0) + { + state.SetTextureMode(TM_FIXEDCOLORMAP); + state.SetObjectColor(cmd.mSpecialColormap[0]); + state.SetAddColor(cmd.mSpecialColormap[1]); + } + state.SetFog(cmd.mColor1, 0); + state.SetColor(1, 1, 1, 1, cmd.mDesaturate); + if (cmd.mFlags & F2DDrawer::DTF_Indexed) state.SetSoftLightLevel(cmd.mLightLevel); + state.SetLightParms(0, 0); + + state.AlphaFunc(Alpha_Greater, 0.f); + + if (cmd.useTransform) + { + FLOATTYPE m[16] = { + 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + }; + for (size_t i = 0; i < 2; i++) + { + for (size_t j = 0; j < 2; j++) + { + m[4 * j + i] = (FLOATTYPE) cmd.transform.Cells[i][j]; + } + } + for (size_t i = 0; i < 2; i++) + { + m[4 * 3 + i] = (FLOATTYPE) cmd.transform.Cells[i][2]; + } + state.mModelMatrix.loadMatrix(m); + state.EnableModelMatrix(true); + } + + if (cmd.mTexture != nullptr && cmd.mTexture->isValid()) + { + auto flags = cmd.mTexture->GetUseType() >= ETextureType::Special? UF_None : cmd.mTexture->GetUseType() == ETextureType::FontChar? UF_Font : UF_Texture; + + auto scaleflags = cmd.mFlags & F2DDrawer::DTF_Indexed ? CTF_Indexed : 0; + state.SetMaterial(cmd.mTexture, flags, scaleflags, cmd.mFlags & F2DDrawer::DTF_Wrap ? CLAMP_NONE : CLAMP_XY_NOMIP, cmd.mTranslationId, -1); + state.EnableTexture(true); + + // Canvas textures are stored upside down + if (cmd.mTexture->isHardwareCanvas()) + { + state.mTextureMatrix.loadIdentity(); + state.mTextureMatrix.scale(1.f, -1.f, 1.f); + state.mTextureMatrix.translate(0.f, 1.f, 0.0f); + state.EnableTextureMatrix(true); + } + if (cmd.mFlags & F2DDrawer::DTF_Burn) + { + state.SetEffect(EFF_BURN); + } + } + else + { + state.EnableTexture(false); + } + + if (cmd.shape2DBufInfo != nullptr) + { + state.SetVertexBuffer(&cmd.shape2DBufInfo->buffers[cmd.shape2DBufIndex]); + state.DrawIndexed(DT_Triangles, 0, cmd.shape2DIndexCount); + state.SetVertexBuffer(&vb); + if (cmd.shape2DCommandCounter == cmd.shape2DBufInfo->lastCommand) + { + cmd.shape2DBufInfo->lastCommand = -1; + if (cmd.shape2DBufInfo->bufIndex > 0) + { + cmd.shape2DBufInfo->needsVertexUpload = true; + cmd.shape2DBufInfo->buffers.Clear(); + cmd.shape2DBufInfo->bufIndex = -1; + } + } + cmd.shape2DBufInfo->uploadedOnce = false; + } + else + { + switch (cmd.mType) + { + default: + case F2DDrawer::DrawTypeTriangles: + state.DrawIndexed(DT_Triangles, cmd.mIndexIndex, cmd.mIndexCount); + break; + + case F2DDrawer::DrawTypeLines: + state.Draw(DT_Lines, cmd.mVertIndex, cmd.mVertCount); + break; + + case F2DDrawer::DrawTypePoints: + state.Draw(DT_Points, cmd.mVertIndex, cmd.mVertCount); + break; + + } + } + state.SetObjectColor(0xffffffff); + state.SetObjectColor2(0); + state.SetAddColor(0); + state.EnableTextureMatrix(false); + state.EnableModelMatrix(false); + state.SetEffect(EFF_NONE); + + } + state.SetScissor(-1, -1, -1, -1); + + state.SetRenderStyle(STYLE_Translucent); + state.SetVertexBuffer(screen->mVertexData); + state.EnableStencil(false); + state.SetStencil(0, SOP_Keep, SF_AllOn); + state.EnableTexture(true); + state.EnableBrightmap(true); + state.SetTextureMode(TM_NORMAL); + state.EnableFog(false); + state.SetScreenFade(1); + state.SetSoftLightLevel(255); + state.ResetColor(); + drawer->mIsFirstPass = false; + twoD.Unclock(); +} diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocess.cpp b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp similarity index 91% rename from src/rendering/hwrenderer/postprocessing/hw_postprocess.cpp rename to src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp index 38905f7be9f..e339f926782 100644 --- a/src/rendering/hwrenderer/postprocessing/hw_postprocess.cpp +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp @@ -21,14 +21,18 @@ #include "v_video.h" #include "hw_postprocess.h" -#include "hwrenderer/utility/hw_cvars.h" +#include "hw_cvars.h" #include "hwrenderer/postprocessing/hw_postprocess_cvars.h" #include "hwrenderer/postprocessing/hw_postprocessshader.h" #include +#include "texturemanager.h" + +#include "stats.h" Postprocess hw_postprocess; PPResource *PPResource::First = nullptr; +TArray PostProcessShaders; bool gpuStatActive = false; bool keepGpuStatActive = false; @@ -322,9 +326,9 @@ void PPLensDistort::Render(PPRenderState *renderstate) // Scale factor to keep sampling within the input texture float r2 = aspect * aspect * 0.25f + 0.25f; float sqrt_r2 = sqrt(r2); - float f0 = 1.0f + MAX(r2 * (k[0] + kcube[0] * sqrt_r2), 0.0f); - float f2 = 1.0f + MAX(r2 * (k[2] + kcube[2] * sqrt_r2), 0.0f); - float f = MAX(f0, f2); + float f0 = 1.0f + max(r2 * (k[0] + kcube[0] * sqrt_r2), 0.0f); + float f2 = 1.0f + max(r2 * (k[2] + kcube[2] * sqrt_r2), 0.0f); + float f = max(f0, f2); float scale = 1.0f / f; LensUniforms uniforms; @@ -390,8 +394,8 @@ void PPFXAA::CreateShaders() if (LastQuality == gl_fxaa) return; - FXAALuma = { "shaders/glsl/fxaa.fp", "#define FXAA_LUMA_PASS\n", {} }; - FXAA = { "shaders/glsl/fxaa.fp", GetDefines(), FXAAUniforms::Desc(), GetMaxVersion() }; + FXAALuma = { "shaders/pp/fxaa.fp", "#define FXAA_LUMA_PASS\n", {} }; + FXAA = { "shaders/pp/fxaa.fp", GetDefines(), FXAAUniforms::Desc(), GetMaxVersion() }; LastQuality = gl_fxaa; } @@ -494,8 +498,8 @@ void PPCameraExposure::Render(PPRenderState *renderstate, int sceneWidth, int sc void PPCameraExposure::UpdateTextures(int width, int height) { - int firstwidth = MAX(width / 2, 1); - int firstheight = MAX(height / 2, 1); + int firstwidth = max(width / 2, 1); + int firstheight = max(height / 2, 1); if (ExposureLevels.size() > 0 && ExposureLevels[0].Viewport.width == firstwidth && ExposureLevels[0].Viewport.height == firstheight) { @@ -507,8 +511,8 @@ void PPCameraExposure::UpdateTextures(int width, int height) int i = 0; do { - width = MAX(width / 2, 1); - height = MAX(height / 2, 1); + width = max(width / 2, 1); + height = max(height / 2, 1); PPExposureLevel blevel; blevel.Viewport.left = 0; @@ -527,20 +531,26 @@ void PPCameraExposure::UpdateTextures(int width, int height) ///////////////////////////////////////////////////////////////////////////// -void PPColormap::Render(PPRenderState *renderstate, int fixedcm) +void PPColormap::Render(PPRenderState *renderstate, int fixedcm, float flash) { + ColormapUniforms uniforms; + if (fixedcm < CM_FIRSTSPECIALCOLORMAP || fixedcm >= CM_MAXCOLORMAP) { - return; - } + if (flash == 1.f) + return; - FSpecialColormap *scm = &SpecialColormaps[fixedcm - CM_FIRSTSPECIALCOLORMAP]; - float m[] = { scm->ColorizeEnd[0] - scm->ColorizeStart[0], - scm->ColorizeEnd[1] - scm->ColorizeStart[1], scm->ColorizeEnd[2] - scm->ColorizeStart[2], 0.f }; + uniforms.MapStart = { 0,0,0, flash }; + uniforms.MapRange = { 0,0,0, 1.f }; + } + else + { + FSpecialColormap* scm = &SpecialColormaps[fixedcm - CM_FIRSTSPECIALCOLORMAP]; - ColormapUniforms uniforms; - uniforms.MapStart = { scm->ColorizeStart[0], scm->ColorizeStart[1], scm->ColorizeStart[2], 0.f }; - uniforms.MapRange = m; + uniforms.MapStart = { scm->ColorizeStart[0], scm->ColorizeStart[1], scm->ColorizeStart[2], flash }; + uniforms.MapRange = { scm->ColorizeEnd[0] - scm->ColorizeStart[0], + scm->ColorizeEnd[1] - scm->ColorizeStart[1], scm->ColorizeEnd[2] - scm->ColorizeStart[2], 0.f }; + } renderstate->PushGroup("colormap"); @@ -560,7 +570,8 @@ void PPColormap::Render(PPRenderState *renderstate, int fixedcm) void PPTonemap::UpdateTextures() { - if (gl_tonemap == Palette && !PaletteTexture.Data) + // level.info->tonemap cannot be ETonemapMode::Palette, so it's fine to only check gl_tonemap here + if (ETonemapMode((int)gl_tonemap) == ETonemapMode::Palette && !PaletteTexture.Data) { std::shared_ptr data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; }); @@ -588,7 +599,9 @@ void PPTonemap::UpdateTextures() void PPTonemap::Render(PPRenderState *renderstate) { - if (gl_tonemap == 0) + ETonemapMode current_tonemap = (level_tonemap != ETonemapMode::None) ? level_tonemap : ETonemapMode((int)gl_tonemap); + + if (current_tonemap == ETonemapMode::None) { return; } @@ -596,14 +609,14 @@ void PPTonemap::Render(PPRenderState *renderstate) UpdateTextures(); PPShader *shader = nullptr; - switch (gl_tonemap) + switch (current_tonemap) { default: - case Linear: shader = &LinearShader; break; - case Reinhard: shader = &ReinhardShader; break; - case HejlDawson: shader = &HejlDawsonShader; break; - case Uncharted2: shader = &Uncharted2Shader; break; - case Palette: shader = &PaletteShader; break; + case ETonemapMode::Linear: shader = &LinearShader; break; + case ETonemapMode::Reinhard: shader = &ReinhardShader; break; + case ETonemapMode::HejlDawson: shader = &HejlDawsonShader; break; + case ETonemapMode::Uncharted2: shader = &Uncharted2Shader; break; + case ETonemapMode::Palette: shader = &PaletteShader; break; } renderstate->PushGroup("tonemap"); @@ -612,7 +625,7 @@ void PPTonemap::Render(PPRenderState *renderstate) renderstate->Shader = shader; renderstate->Viewport = screen->mScreenViewport; renderstate->SetInputCurrent(0); - if (gl_tonemap == Palette) + if (current_tonemap == ETonemapMode::Palette) renderstate->SetInputTexture(1, &PaletteTexture); renderstate->SetOutputNext(); renderstate->SetNoBlend(); @@ -676,14 +689,14 @@ void PPAmbientOcclusion::CreateShaders() #define NUM_STEPS %d.0 )", numDirections, numSteps); - LinearDepth = { "shaders/glsl/lineardepth.fp", "", LinearDepthUniforms::Desc() }; - LinearDepthMS = { "shaders/glsl/lineardepth.fp", "#define MULTISAMPLE\n", LinearDepthUniforms::Desc() }; - AmbientOcclude = { "shaders/glsl/ssao.fp", defines, SSAOUniforms::Desc() }; - AmbientOccludeMS = { "shaders/glsl/ssao.fp", defines + "\n#define MULTISAMPLE\n", SSAOUniforms::Desc() }; - BlurVertical = { "shaders/glsl/depthblur.fp", "#define BLUR_VERTICAL\n", DepthBlurUniforms::Desc() }; - BlurHorizontal = { "shaders/glsl/depthblur.fp", "#define BLUR_HORIZONTAL\n", DepthBlurUniforms::Desc() }; - Combine = { "shaders/glsl/ssaocombine.fp", "", AmbientCombineUniforms::Desc() }; - CombineMS = { "shaders/glsl/ssaocombine.fp", "#define MULTISAMPLE\n", AmbientCombineUniforms::Desc() }; + LinearDepth = { "shaders/pp/lineardepth.fp", "", LinearDepthUniforms::Desc() }; + LinearDepthMS = { "shaders/pp/lineardepth.fp", "#define MULTISAMPLE\n", LinearDepthUniforms::Desc() }; + AmbientOcclude = { "shaders/pp/ssao.fp", defines, SSAOUniforms::Desc() }; + AmbientOccludeMS = { "shaders/pp/ssao.fp", defines + "\n#define MULTISAMPLE\n", SSAOUniforms::Desc() }; + BlurVertical = { "shaders/pp/depthblur.fp", "#define BLUR_VERTICAL\n", DepthBlurUniforms::Desc() }; + BlurHorizontal = { "shaders/pp/depthblur.fp", "#define BLUR_HORIZONTAL\n", DepthBlurUniforms::Desc() }; + Combine = { "shaders/pp/ssaocombine.fp", "", AmbientCombineUniforms::Desc() }; + CombineMS = { "shaders/pp/ssaocombine.fp", "#define MULTISAMPLE\n", AmbientCombineUniforms::Desc() }; LastQuality = gl_ssao; } @@ -736,7 +749,7 @@ void PPAmbientOcclusion::Render(PPRenderState *renderstate, float m5, int sceneW LinearDepthUniforms linearUniforms; linearUniforms.SampleIndex = 0; linearUniforms.LinearizeDepthA = 1.0f / screen->GetZFar() - 1.0f / screen->GetZNear(); - linearUniforms.LinearizeDepthB = MAX(1.0f / screen->GetZNear(), 1.e-8f); + linearUniforms.LinearizeDepthB = max(1.0f / screen->GetZNear(), 1.e-8f); linearUniforms.InverseDepthRangeA = 1.0f; linearUniforms.InverseDepthRangeB = 0.0f; linearUniforms.Scale = sceneScale; @@ -861,7 +874,8 @@ PPPresent::PPPresent() ///////////////////////////////////////////////////////////////////////////// -void PPShadowMap::Update(PPRenderState *renderstate) + +void PPShadowMap::Update(PPRenderState* renderstate) { ShadowMapUniforms uniforms; uniforms.ShadowmapQuality = (float)gl_shadowmap_quality; @@ -999,14 +1013,15 @@ void PPCustomShaderInstance::SetTextures(PPRenderState *renderstate) while (it.NextPair(pair)) { FString name = pair->Value; - FTexture *tex = TexMan.GetTexture(TexMan.CheckForTexture(name, ETextureType::Any), true); - if (tex && tex->isValid()) + auto gtex = TexMan.GetGameTexture(TexMan.CheckForTexture(name.GetChars(), ETextureType::Any), true); + if (gtex && gtex->isValid()) { // Why does this completely circumvent the normal way of handling textures? // This absolutely needs fixing because it will also circumvent any potential caching system that may get implemented. // // To do: fix the above problem by adding PPRenderState::SetInput(FTexture *tex) + auto tex = gtex->GetTexture(); auto &pptex = Textures[tex]; if (!pptex) { @@ -1110,10 +1125,10 @@ void Postprocess::Pass1(PPRenderState* state, int fixedcm, int sceneWidth, int s bloom.RenderBloom(state, sceneWidth, sceneHeight, fixedcm); } -void Postprocess::Pass2(PPRenderState* state, int fixedcm, int sceneWidth, int sceneHeight) +void Postprocess::Pass2(PPRenderState* state, int fixedcm, float flash, int sceneWidth, int sceneHeight) { tonemap.Render(state); - colormap.Render(state, fixedcm); + colormap.Render(state, fixedcm, flash); lens.Render(state); fxaa.Render(state); customShaders.Run(state, "scene"); diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocess.h b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.h similarity index 90% rename from src/rendering/hwrenderer/postprocessing/hw_postprocess.h rename to src/common/rendering/hwrenderer/postprocessing/hw_postprocess.h index 8c74af83e56..357396da76d 100644 --- a/src/rendering/hwrenderer/postprocessing/hw_postprocess.h +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.h @@ -3,6 +3,7 @@ #include "hwrenderer/data/shaderuniforms.h" #include #include +#include "intrect.h" struct PostProcessShader; @@ -12,6 +13,19 @@ typedef IntRect PPViewport; class PPTexture; class PPShader; +enum class ETonemapMode : uint8_t +{ + None, + Uncharted2, + HejlDawson, + Reinhard, + Linear, + Palette, + NumTonemapModes +}; + + + enum class PPFilterMode { Nearest, Linear }; enum class PPWrapMode { Clamp, Repeat }; enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain, ShadowMap }; @@ -303,7 +317,7 @@ class PPShader : public PPResource void ResetBackend() override { Backend.reset(); } - FString VertexShader = "shaders/glsl/screenquad.vp"; + FString VertexShader = "shaders/pp/screenquad.vp"; FString FragmentShader; FString Defines; std::vector Uniforms; @@ -376,10 +390,10 @@ class PPBloom int lastWidth = 0; int lastHeight = 0; - PPShader BloomCombine = { "shaders/glsl/bloomcombine.fp", "", {} }; - PPShader BloomExtract = { "shaders/glsl/bloomextract.fp", "", ExtractUniforms::Desc() }; - PPShader BlurVertical = { "shaders/glsl/blur.fp", "#define BLUR_VERTICAL\n", BlurUniforms::Desc() }; - PPShader BlurHorizontal = { "shaders/glsl/blur.fp", "#define BLUR_HORIZONTAL\n", BlurUniforms::Desc() }; + PPShader BloomCombine = { "shaders/pp/bloomcombine.fp", "", {} }; + PPShader BloomExtract = { "shaders/pp/bloomextract.fp", "", ExtractUniforms::Desc() }; + PPShader BlurVertical = { "shaders/pp/blur.fp", "#define BLUR_VERTICAL\n", BlurUniforms::Desc() }; + PPShader BlurHorizontal = { "shaders/pp/blur.fp", "#define BLUR_HORIZONTAL\n", BlurUniforms::Desc() }; }; ///////////////////////////////////////////////////////////////////////////// @@ -412,7 +426,7 @@ class PPLensDistort void Render(PPRenderState *renderstate); private: - PPShader Lens = { "shaders/glsl/lensdistortion.fp", "", LensUniforms::Desc() }; + PPShader Lens = { "shaders/pp/lensdistortion.fp", "", LensUniforms::Desc() }; }; ///////////////////////////////////////////////////////////////////////////// @@ -504,9 +518,9 @@ class PPCameraExposure std::vector ExposureLevels; bool FirstExposureFrame = true; - PPShader ExposureExtract = { "shaders/glsl/exposureextract.fp", "", ExposureExtractUniforms::Desc() }; - PPShader ExposureAverage = { "shaders/glsl/exposureaverage.fp", "", {}, 400 }; - PPShader ExposureCombine = { "shaders/glsl/exposurecombine.fp", "", ExposureCombineUniforms::Desc() }; + PPShader ExposureExtract = { "shaders/pp/exposureextract.fp", "", ExposureExtractUniforms::Desc() }; + PPShader ExposureAverage = { "shaders/pp/exposureaverage.fp", "", {}, 400 }; + PPShader ExposureCombine = { "shaders/pp/exposurecombine.fp", "", ExposureCombineUniforms::Desc() }; }; ///////////////////////////////////////////////////////////////////////////// @@ -529,10 +543,10 @@ struct ColormapUniforms class PPColormap { public: - void Render(PPRenderState *renderstate, int fixedcm); + void Render(PPRenderState *renderstate, int fixedcm, float flash); private: - PPShader Colormap = { "shaders/glsl/colormap.fp", "", ColormapUniforms::Desc() }; + PPShader Colormap = { "shaders/pp/colormap.fp", "", ColormapUniforms::Desc() }; }; ///////////////////////////////////////////////////////////////////////////// @@ -540,6 +554,7 @@ class PPColormap class PPTonemap { public: + void SetTonemapMode(ETonemapMode tm) { level_tonemap = tm; } void Render(PPRenderState *renderstate); void ClearTonemapPalette() { PaletteTexture = {}; } @@ -548,22 +563,12 @@ class PPTonemap PPTexture PaletteTexture; - PPShader LinearShader = { "shaders/glsl/tonemap.fp", "#define LINEAR\n", {} }; - PPShader ReinhardShader = { "shaders/glsl/tonemap.fp", "#define REINHARD\n", {} }; - PPShader HejlDawsonShader = { "shaders/glsl/tonemap.fp", "#define HEJLDAWSON\n", {} }; - PPShader Uncharted2Shader = { "shaders/glsl/tonemap.fp", "#define UNCHARTED2\n", {} }; - PPShader PaletteShader = { "shaders/glsl/tonemap.fp", "#define PALETTE\n", {} }; - - enum TonemapMode - { - None, - Uncharted2, - HejlDawson, - Reinhard, - Linear, - Palette, - NumTonemapModes - }; + PPShader LinearShader = { "shaders/pp/tonemap.fp", "#define LINEAR\n", {} }; + PPShader ReinhardShader = { "shaders/pp/tonemap.fp", "#define REINHARD\n", {} }; + PPShader HejlDawsonShader = { "shaders/pp/tonemap.fp", "#define HEJLDAWSON\n", {} }; + PPShader Uncharted2Shader = { "shaders/pp/tonemap.fp", "#define UNCHARTED2\n", {} }; + PPShader PaletteShader = { "shaders/pp/tonemap.fp", "#define PALETTE\n", {} }; + ETonemapMode level_tonemap = ETonemapMode::None; }; ///////////////////////////////////////////////////////////////////////////// @@ -753,10 +758,10 @@ class PPPresent PPTexture Dither; - PPShader Present = { "shaders/glsl/present.fp", "", PresentUniforms::Desc() }; - PPShader Checker3D = { "shaders/glsl/present_checker3d.fp", "", PresentUniforms::Desc() }; - PPShader Column3D = { "shaders/glsl/present_column3d.fp", "", PresentUniforms::Desc() }; - PPShader Row3D = { "shaders/glsl/present_row3d.fp", "", PresentUniforms::Desc() }; + PPShader Present = { "shaders/pp/present.fp", "", PresentUniforms::Desc() }; + PPShader Checker3D = { "shaders/pp/present_checker3d.fp", "", PresentUniforms::Desc() }; + PPShader Column3D = { "shaders/pp/present_column3d.fp", "", PresentUniforms::Desc() }; + PPShader Row3D = { "shaders/pp/present_row3d.fp", "", PresentUniforms::Desc() }; }; struct ShadowMapUniforms @@ -777,15 +782,6 @@ struct ShadowMapUniforms } }; -class PPShadowMap -{ -public: - void Update(PPRenderState *renderstate); - -private: - PPShader ShadowMap = { "shaders/glsl/shadowmap.fp", "", ShadowMapUniforms::Desc() }; -}; - class PPCustomShaderInstance { public: @@ -819,6 +815,18 @@ class PPCustomShaders std::vector> mShaders; }; +class PPShadowMap +{ +public: + void Update(PPRenderState* renderstate); + +private: + PPShader ShadowMap = { "shaders/pp/shadowmap.fp", "", ShadowMapUniforms::Desc() }; +}; + + + + ///////////////////////////////////////////////////////////////////////////// class Postprocess @@ -836,8 +844,11 @@ class Postprocess PPCustomShaders customShaders; + void SetTonemapMode(ETonemapMode tm) { tonemap.SetTonemapMode(tm); } void Pass1(PPRenderState *state, int fixedcm, int sceneWidth, int sceneHeight); - void Pass2(PPRenderState* state, int fixedcm, int sceneWidth, int sceneHeight); + void Pass2(PPRenderState* state, int fixedcm, float flash, int sceneWidth, int sceneHeight); }; + extern Postprocess hw_postprocess; + diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp similarity index 100% rename from src/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp rename to src/common/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.h b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.h similarity index 100% rename from src/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.h rename to src/common/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.h diff --git a/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp new file mode 100644 index 00000000000..f23d4497f16 --- /dev/null +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp @@ -0,0 +1,139 @@ +/* +** Postprocessing framework +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "vm.h" +#include "hwrenderer/postprocessing/hw_postprocessshader.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" + +static void ShaderSetEnabled(const FString &shaderName, bool value) +{ + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name == shaderName) + shader.Enabled = value; + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(_PPShader, SetEnabled, ShaderSetEnabled) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_BOOL(value); + ShaderSetEnabled(shaderName, value); + + return 0; +} + +static void ShaderSetUniform1f(const FString &shaderName, const FString &uniformName, double value) +{ + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name == shaderName) + { + double *vec4 = shader.Uniforms[uniformName].Values; + vec4[0] = value; + vec4[1] = 0.0; + vec4[2] = 0.0; + vec4[3] = 1.0; + } + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(_PPShader, SetUniform1f, ShaderSetUniform1f) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_STRING(uniformName); + PARAM_FLOAT(value); + ShaderSetUniform1f(shaderName, uniformName, value); + return 0; +} + +DEFINE_ACTION_FUNCTION(_PPShader, SetUniform2f) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_STRING(uniformName); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name == shaderName) + { + double *vec4 = shader.Uniforms[uniformName].Values; + vec4[0] = x; + vec4[1] = y; + vec4[2] = 0.0; + vec4[3] = 1.0; + } + } + return 0; +} + +DEFINE_ACTION_FUNCTION(_PPShader, SetUniform3f) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_STRING(uniformName); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name == shaderName) + { + double *vec4 = shader.Uniforms[uniformName].Values; + vec4[0] = x; + vec4[1] = y; + vec4[2] = z; + vec4[3] = 1.0; + } + } + return 0; +} + +DEFINE_ACTION_FUNCTION(_PPShader, SetUniform1i) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_STRING(uniformName); + PARAM_INT(value); + + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name == shaderName) + { + double *vec4 = shader.Uniforms[uniformName].Values; + vec4[0] = (double)value; + vec4[1] = 0.0; + vec4[2] = 0.0; + vec4[3] = 1.0; + } + } + return 0; +} diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocessshader.h b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h similarity index 92% rename from src/rendering/hwrenderer/postprocessing/hw_postprocessshader.h rename to src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h index 523b8d8d021..7ecbd4f84cf 100644 --- a/src/rendering/hwrenderer/postprocessing/hw_postprocessshader.h +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h @@ -1,5 +1,8 @@ #pragma once +#include "zstring.h" +#include "tarray.h" + enum class PostProcessUniformType { Undefined, diff --git a/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader_ccmds.cpp b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader_ccmds.cpp new file mode 100644 index 00000000000..7ab93b3ec57 --- /dev/null +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader_ccmds.cpp @@ -0,0 +1,136 @@ +/* +** Debug ccmds for post-process shaders +** Copyright (c) 2022 Rachael Alexanderson +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "hwrenderer/postprocessing/hw_postprocessshader.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "printf.h" +#include "c_dispatch.h" + +CCMD (shaderenable) +{ + if (argv.argc() < 3) + { + Printf("Usage: shaderenable [name] [1/0/-1]\nState '-1' toggles the active shader state\n"); + return; + } + auto shaderName = argv[1]; + + int value = atoi(argv[2]); + + bool found = 0; + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name.Compare(shaderName) == 0) + { + if (value != -1) + shader.Enabled = value; + else + shader.Enabled = !shader.Enabled; //toggle + found = 1; + } + } + if (found && value != -1) + Printf("Changed active state of all instances of %s to %s\n", shaderName, value?"On":"Off"); + else if (found) + Printf("Toggled active state of all instances of %s\n", shaderName); + else + Printf("No shader named '%s' found\n", shaderName); +} + +CCMD (shaderuniform) +{ + if (argv.argc() < 3) + { + Printf("Usage: shaderuniform [shader name] [uniform name] [[value1 ..]]\n"); + return; + } + auto shaderName = argv[1]; + auto uniformName = argv[2]; + + bool found = 0; + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name.Compare(shaderName) == 0) + { + if (argv.argc() > 3) + { + double *vec4 = shader.Uniforms[uniformName].Values; + vec4[0] = argv.argc()>=4 ? atof(argv[3]) : 0.0; + vec4[1] = argv.argc()>=5 ? atof(argv[4]) : 0.0; + vec4[2] = argv.argc()>=6 ? atof(argv[5]) : 0.0; + vec4[3] = 1.0; + } + else + { + double *vec4 = shader.Uniforms[uniformName].Values; + Printf("Shader '%s' uniform '%s': %f %f %f\n", shaderName, uniformName, vec4[0], vec4[1], vec4[2]); + } + found = 1; + } + } + if (found && argv.argc() > 3) + Printf("Changed uniforms of %s named %s\n", shaderName, uniformName); + else if (!found) + Printf("No shader named '%s' found\n", shaderName); +} + +CCMD(listshaders) +{ + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + Printf("Shader (%i): %s\n", i, shader.Name.GetChars()); + } +} + +CCMD(listuniforms) +{ + if (argv.argc() < 2) + { + Printf("Usage: listuniforms [name]\n"); + return; + } + auto shaderName = argv[1]; + + bool found = 0; + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name.Compare(shaderName) == 0) + { + Printf("Shader '%s' uniforms:\n", shaderName); + + decltype(shader.Uniforms)::Iterator it(shader.Uniforms); + decltype(shader.Uniforms)::Pair* pair; + + while (it.NextPair(pair)) + { + double *vec4 = shader.Uniforms[pair->Key].Values; + Printf(" %s : %f %f %f\n", pair->Key.GetChars(), vec4[0], vec4[1], vec4[2]); + } + found = 1; + } + } + if (!found) + Printf("No shader named '%s' found\n", shaderName); +} diff --git a/src/common/rendering/i_modelvertexbuffer.h b/src/common/rendering/i_modelvertexbuffer.h new file mode 100644 index 00000000000..927fcfbf32d --- /dev/null +++ b/src/common/rendering/i_modelvertexbuffer.h @@ -0,0 +1,67 @@ +#pragma once + +#include "basics.h" + + +struct FModelVertex +{ + float x, y, z; // world position + float u, v; // texture coordinates + unsigned packedNormal; // normal vector as GL_INT_2_10_10_10_REV. + float lu, lv; // lightmap texture coordinates + float lindex; // lightmap texture index + uint8_t boneselector[4]; + uint8_t boneweight[4]; + + void Set(float xx, float yy, float zz, float uu, float vv) + { + x = xx; + y = yy; + z = zz; + u = uu; + v = vv; + lu = 0.0f; + lv = 0.0f; + lindex = -1.0f; + } + + void SetNormal(float nx, float ny, float nz) + { + int inx = clamp(int(nx * 512), -512, 511); + int iny = clamp(int(ny * 512), -512, 511); + int inz = clamp(int(nz * 512), -512, 511); + int inw = 0; + packedNormal = (inw << 30) | ((inz & 1023) << 20) | ((iny & 1023) << 10) | (inx & 1023); + } + + void SetBoneSelector(int x, int y, int z, int w) + { + boneselector[0] = x; + boneselector[1] = y; + boneselector[2] = z; + boneselector[3] = w; + } + + void SetBoneWeight(int x, int y, int z, int w) + { + boneweight[0] = x; + boneweight[1] = y; + boneweight[2] = z; + boneweight[3] = w; + } +}; + +#define VMO ((FModelVertex*)nullptr) + +class IModelVertexBuffer +{ +public: + virtual ~IModelVertexBuffer() { } + + virtual FModelVertex *LockVertexBuffer(unsigned int size) = 0; + virtual void UnlockVertexBuffer() = 0; + + virtual unsigned int *LockIndexBuffer(unsigned int size) = 0; + virtual void UnlockIndexBuffer() = 0; +}; + diff --git a/src/common/rendering/i_video.h b/src/common/rendering/i_video.h new file mode 100644 index 00000000000..f33d35caf9b --- /dev/null +++ b/src/common/rendering/i_video.h @@ -0,0 +1,32 @@ +#ifndef __I_VIDEO_H__ +#define __I_VIDEO_H__ + +#include + +class DFrameBuffer; + + +class IVideo +{ +public: + virtual ~IVideo() {} + + virtual DFrameBuffer *CreateFrameBuffer() = 0; + + bool SetResolution(); + + virtual void DumpAdapters(); +}; + +void I_InitGraphics(); +void I_ShutdownGraphics(); + +extern IVideo *Video; + +void I_PolyPresentInit(); +uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch); +void I_PolyPresentUnlock(int x, int y, int w, int h); +void I_PolyPresentDeinit(); + + +#endif // __I_VIDEO_H__ diff --git a/src/rendering/swrenderer/drawers/r_thread.cpp b/src/common/rendering/r_thread.cpp similarity index 91% rename from src/rendering/swrenderer/drawers/r_thread.cpp rename to src/common/rendering/r_thread.cpp index 5f1b8c6355c..c13ffe8fe34 100644 --- a/src/rendering/swrenderer/drawers/r_thread.cpp +++ b/src/common/rendering/r_thread.cpp @@ -21,25 +21,15 @@ */ #include -#include "templates.h" -#include "doomdef.h" + #include "i_system.h" -#include "w_wad.h" +#include "filesystem.h" #include "v_video.h" -#include "doomstat.h" -#include "st_stuff.h" -#include "g_game.h" -#include "g_level.h" #include "r_thread.h" -#include "swrenderer/r_memory.h" -#include "swrenderer/r_renderthread.h" -#include "polyrenderer/drawers/poly_triangle.h" +#include "r_memory.h" +#include "printf.h" #include -#ifdef WIN32 -void PeekThreadedErrorPane(); -#endif - CVAR(Int, r_multithreaded, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR(Int, r_debug_draw, 0, 0); @@ -64,7 +54,7 @@ void DrawerThreads::Execute(DrawerCommandQueuePtr commands) { if (!commands || commands->commands.empty()) return; - + auto queue = Instance(); queue->StartThreads(); @@ -105,12 +95,7 @@ void DrawerThreads::WaitForWorkers() std::unique_lock end_lock(queue->end_mutex); if (!queue->end_condition.wait_for(end_lock, 5s, [&]() { return queue->tasks_left == 0; })) { -#ifdef WIN32 - PeekThreadedErrorPane(); -#endif - // Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing - int *threadCrashed = nullptr; - *threadCrashed = 0xdeadbeef; + I_FatalError("Drawer threads did not finish within 5 seconds!"); } end_lock.unlock(); @@ -143,11 +128,6 @@ void DrawerThreads::WorkerMain(DrawerThread *thread) thread->current_queue++; thread->numa_start_y = thread->numa_node * screen->GetHeight() / thread->num_numa_nodes; thread->numa_end_y = (thread->numa_node + 1) * screen->GetHeight() / thread->num_numa_nodes; - if (thread->poly) - { - thread->poly->numa_start_y = thread->numa_start_y; - thread->poly->numa_end_y = thread->numa_end_y; - } start_lock.unlock(); // Do the work: diff --git a/src/rendering/swrenderer/drawers/r_thread.h b/src/common/rendering/r_thread.h similarity index 94% rename from src/rendering/swrenderer/drawers/r_thread.h rename to src/common/rendering/r_thread.h index 0d45b2caca6..4d44972acc1 100644 --- a/src/rendering/swrenderer/drawers/r_thread.h +++ b/src/common/rendering/r_thread.h @@ -22,18 +22,18 @@ #pragma once -#include "r_draw.h" #include #include #include #include #include +#include "c_cvars.h" +#include "basics.h" + // Use multiple threads when drawing EXTERN_CVAR(Int, r_multithreaded) -class PolyTriangleThreadData; - namespace swrenderer { class WallColumnDrawerArgs; } // Worker data for each thread executing drawer commands @@ -62,9 +62,6 @@ class DrawerThread // Working buffer used by the tilted (sloped) span drawer const uint8_t *tiltlighting[MAXWIDTH]; - std::shared_ptr poly; - std::shared_ptr columndrawer; - size_t debug_draw_pos = 0; // Checks if a line is rendered by this thread @@ -76,7 +73,7 @@ class DrawerThread // The number of lines to skip to reach the first line to be rendered by this thread int skipped_by_thread(int first_line) { - int clip_first_line = MAX(first_line, numa_start_y); + int clip_first_line = max(first_line, numa_start_y); int core_skip = (num_cores - (clip_first_line - core) % num_cores) % num_cores; return clip_first_line + core_skip - first_line; } @@ -84,9 +81,9 @@ class DrawerThread // The number of lines to be rendered by this thread int count_for_thread(int first_line, int count) { - count = MIN(count, numa_end_y - first_line); + count = min(count, numa_end_y - first_line); int c = (count - skipped_by_thread(first_line) + num_cores - 1) / num_cores; - return MAX(c, 0); + return max(c, 0); } // Calculate the dest address for the first line to be rendered by this thread @@ -154,17 +151,17 @@ class DrawerThreads static void WaitForWorkers(); static void ResetDebugDrawPos(); - + private: DrawerThreads(); ~DrawerThreads(); - + void StartThreads(); void StopThreads(); void WorkerMain(DrawerThread *thread); static DrawerThreads *Instance(); - + std::mutex threads_mutex; std::vector threads; @@ -180,7 +177,7 @@ class DrawerThreads size_t debug_draw_end = 0; DrawerThread single_core_thread; - + friend class DrawerCommandQueue; }; @@ -190,9 +187,9 @@ class DrawerCommandQueue { public: DrawerCommandQueue(RenderMemory *memoryAllocator); - + void Clear() { commands.clear(); } - + // Queue command to be executed by drawer worker threads template void Push(Types &&... args) @@ -210,13 +207,13 @@ class DrawerCommandQueue command.Execute(&threads->single_core_thread); } } - + private: // Allocate memory valid for the duration of a command execution void *AllocMemory(size_t size); - + std::vector commands; RenderMemory *FrameMemory; - + friend class DrawerThreads; }; diff --git a/src/rendering/r_videoscale.cpp b/src/common/rendering/r_videoscale.cpp similarity index 94% rename from src/rendering/r_videoscale.cpp rename to src/common/rendering/r_videoscale.cpp index 0fd61658074..705fe905f40 100644 --- a/src/rendering/r_videoscale.cpp +++ b/src/common/rendering/r_videoscale.cpp @@ -34,20 +34,16 @@ #include "c_dispatch.h" #include "c_cvars.h" #include "v_video.h" -#include "templates.h" -#include "r_videoscale.h" -#include "console/c_console.h" -#include "menu/menu.h" +#include "r_videoscale.h" +#include "cmdlib.h" +#include "v_draw.h" +#include "i_interface.h" +#include "printf.h" +#include "version.h" #define NUMSCALEMODES countof(vScaleTable) - -extern bool setsizeneeded, multiplayer, generic_ui; - -EXTERN_CVAR(Int, vid_aspect) - -EXTERN_CVAR(Bool, log_vgafont) -EXTERN_CVAR(Bool, dlg_vgafont) +extern bool setsizeneeded; CUSTOM_CVAR(Int, vid_scale_customwidth, VID_MIN_WIDTH, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { @@ -69,6 +65,9 @@ CUSTOM_CVAR(Float, vid_scale_custompixelaspect, 1.0, CVAR_ARCHIVE | CVAR_GLOBALC self = 1.0; } +static const int VID_MIN_UI_WIDTH = 640; +static const int VID_MIN_UI_HEIGHT = 400; + namespace { uint32_t min_width = VID_MIN_WIDTH; @@ -106,10 +105,8 @@ namespace // minimum set in GZDoom 4.0.0, but only while those fonts are required. static bool lastspecialUI = false; - bool isInActualMenu = false; - bool specialUI = (generic_ui || !!log_vgafont || !!dlg_vgafont || ConsoleState != c_up || multiplayer || - (menuactive == MENU_On && CurrentMenu && !CurrentMenu->IsKindOf("ConversationMenu"))); + bool specialUI = (!sysCallbacks.IsSpecialUI || sysCallbacks.IsSpecialUI()); if (specialUI == lastspecialUI) return; @@ -128,7 +125,7 @@ namespace min_height = VID_MIN_UI_HEIGHT; } } - + // the odd formatting of this struct definition is meant to resemble a table header. set your tab stops to 4 when editing this file. struct v_ScaleTable { bool isValid; uint32_t(*GetScaledWidth)(uint32_t Width, uint32_t Height); uint32_t(*GetScaledHeight)(uint32_t Width, uint32_t Height); float pixelAspect; bool isCustom; }; @@ -181,7 +178,7 @@ bool ViewportLinearScale() aspectmult = 1.f / aspectmult; if ((ViewportScaledWidth(x,y) > (x * aspectmult)) || (ViewportScaledHeight(x,y) > (y * aspectmult))) return true; - + return vid_scale_linear; } @@ -195,7 +192,7 @@ int ViewportScaledWidth(int width, int height) width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width; height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height; } - return (int)MAX((int32_t)min_width, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledWidth(width, height))); + return (int)max((int32_t)min_width, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledWidth(width, height))); } int ViewportScaledHeight(int width, int height) @@ -207,7 +204,7 @@ int ViewportScaledHeight(int width, int height) height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height; width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width; } - return (int)MAX((int32_t)min_height, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledHeight(width, height))); + return (int)max((int32_t)min_height, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledHeight(width, height))); } float ViewportPixelAspect() diff --git a/src/rendering/r_videoscale.h b/src/common/rendering/r_videoscale.h similarity index 100% rename from src/rendering/r_videoscale.h rename to src/common/rendering/r_videoscale.h diff --git a/src/common/rendering/v_framebuffer.cpp b/src/common/rendering/v_framebuffer.cpp new file mode 100644 index 00000000000..271348bc164 --- /dev/null +++ b/src/common/rendering/v_framebuffer.cpp @@ -0,0 +1,322 @@ +/* +** The base framebuffer class +** +**--------------------------------------------------------------------------- +** Copyright 1999-2016 Randy Heit +** Copyright 2005-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include + + +#include "v_video.h" + +#include "c_dispatch.h" +#include "hardware.h" +#include "r_videoscale.h" +#include "i_time.h" +#include "v_font.h" +#include "v_draw.h" +#include "i_time.h" +#include "v_2ddrawer.h" +#include "vm.h" +#include "i_interface.h" +#include "flatvertices.h" +#include "version.h" +#include "hw_material.h" + +#include +#include + + +CVAR(Bool, gl_scale_viewport, true, CVAR_ARCHIVE); + +EXTERN_CVAR(Int, vid_maxfps) +CVAR(Bool, cl_capfps, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +EXTERN_CVAR(Int, screenblocks) + +//========================================================================== +// +// DFrameBuffer Constructor +// +// A frame buffer canvas is the most common and represents the image that +// gets drawn to the screen. +// +//========================================================================== + +DFrameBuffer::DFrameBuffer (int width, int height) +{ + SetSize(width, height); +} + +DFrameBuffer::~DFrameBuffer() +{ +} + +void DFrameBuffer::SetSize(int width, int height) +{ + Width = ViewportScaledWidth(width, height); + Height = ViewportScaledHeight(width, height); +} + +//========================================================================== +// +// Palette stuff. +// +//========================================================================== + +void DFrameBuffer::Update() +{ + int initialWidth = GetClientWidth(); + int initialHeight = GetClientHeight(); + int clientWidth = ViewportScaledWidth(initialWidth, initialHeight); + int clientHeight = ViewportScaledHeight(initialWidth, initialHeight); + if (clientWidth < VID_MIN_WIDTH) clientWidth = VID_MIN_WIDTH; + if (clientHeight < VID_MIN_HEIGHT) clientHeight = VID_MIN_HEIGHT; + if (clientWidth > 0 && clientHeight > 0 && (GetWidth() != clientWidth || GetHeight() != clientHeight)) + { + SetVirtualSize(clientWidth, clientHeight); + V_OutputResized(clientWidth, clientHeight); + mVertexData->OutputResized(clientWidth, clientHeight); + } +} + +void DFrameBuffer::SetClearColor(int color) +{ + PalEntry pe = GPalette.BaseColors[color]; + mSceneClearColor[0] = pe.r / 255.f; + mSceneClearColor[1] = pe.g / 255.f; + mSceneClearColor[2] = pe.b / 255.f; + mSceneClearColor[3] = 1.f; +} + +//========================================================================== +// +// DFrameBuffer :: SetVSync +// +// Turns vertical sync on and off, if supported. +// +//========================================================================== + +void DFrameBuffer::SetVSync (bool vsync) +{ +} + +//========================================================================== +// +// DFrameBuffer :: WipeStartScreen +// +// Grabs a copy of the screen currently displayed to serve as the initial +// frame of a screen wipe. Also determines which screenwipe will be +// performed. +// +//========================================================================== + +FTexture *DFrameBuffer::WipeStartScreen() +{ + return nullptr; +} + +//========================================================================== +// +// DFrameBuffer :: WipeEndScreen +// +// Grabs a copy of the most-recently drawn, but not yet displayed, screen +// to serve as the final frame of a screen wipe. +// +//========================================================================== + +FTexture *DFrameBuffer::WipeEndScreen() +{ + return nullptr; +} + +//========================================================================== +// +// Calculates the viewport values needed for 2D and 3D operations +// +//========================================================================== + +void DFrameBuffer::SetViewportRects(IntRect *bounds) +{ + if (bounds) + { + mSceneViewport = *bounds; + mScreenViewport = *bounds; + mOutputLetterbox = *bounds; + mGameScreenWidth = mScreenViewport.width; + mGameScreenHeight = mScreenViewport.height; + return; + } + + // Back buffer letterbox for the final output + int clientWidth = GetClientWidth(); + int clientHeight = GetClientHeight(); + if (clientWidth == 0 || clientHeight == 0) + { + // When window is minimized there may not be any client area. + // Pretend to the rest of the render code that we just have a very small window. + clientWidth = 160; + clientHeight = 120; + } + int screenWidth = GetWidth(); + int screenHeight = GetHeight(); + float scaleX, scaleY; + scaleX = min(clientWidth / (float)screenWidth, clientHeight / ((float)screenHeight * ViewportPixelAspect())); + scaleY = scaleX * ViewportPixelAspect(); + mOutputLetterbox.width = (int)round(screenWidth * scaleX); + mOutputLetterbox.height = (int)round(screenHeight * scaleY); + mOutputLetterbox.left = (clientWidth - mOutputLetterbox.width) / 2; + mOutputLetterbox.top = (clientHeight - mOutputLetterbox.height) / 2; + + // The entire renderable area, including the 2D HUD + mScreenViewport.left = 0; + mScreenViewport.top = 0; + mScreenViewport.width = screenWidth; + mScreenViewport.height = screenHeight; + + // Viewport for the 3D scene + if (sysCallbacks.GetSceneRect) mSceneViewport = sysCallbacks.GetSceneRect(); + else mSceneViewport = mScreenViewport; + + // Scale viewports to fit letterbox + bool notScaled = ((mScreenViewport.width == ViewportScaledWidth(mScreenViewport.width, mScreenViewport.height)) && + (mScreenViewport.width == ViewportScaledHeight(mScreenViewport.width, mScreenViewport.height)) && + (ViewportPixelAspect() == 1.0)); + if (gl_scale_viewport && !IsFullscreen() && notScaled) + { + mScreenViewport.width = mOutputLetterbox.width; + mScreenViewport.height = mOutputLetterbox.height; + mSceneViewport.left = (int)round(mSceneViewport.left * scaleX); + mSceneViewport.top = (int)round(mSceneViewport.top * scaleY); + mSceneViewport.width = (int)round(mSceneViewport.width * scaleX); + mSceneViewport.height = (int)round(mSceneViewport.height * scaleY); + } + + mGameScreenWidth = GetWidth(); + mGameScreenHeight = GetHeight(); +} + +//=========================================================================== +// +// Calculates the OpenGL window coordinates for a zdoom screen position +// +//=========================================================================== + +int DFrameBuffer::ScreenToWindowX(int x) +{ + return mScreenViewport.left + (int)round(x * mScreenViewport.width / (float)mGameScreenWidth); +} + +int DFrameBuffer::ScreenToWindowY(int y) +{ + return mScreenViewport.top + mScreenViewport.height - (int)round(y * mScreenViewport.height / (float)mGameScreenHeight); +} + +void DFrameBuffer::ScaleCoordsFromWindow(int16_t &x, int16_t &y) +{ + int letterboxX = mOutputLetterbox.left; + int letterboxY = mOutputLetterbox.top; + int letterboxWidth = mOutputLetterbox.width; + int letterboxHeight = mOutputLetterbox.height; + + x = int16_t((x - letterboxX) * Width / letterboxWidth); + y = int16_t((y - letterboxY) * Height / letterboxHeight); +} + +void DFrameBuffer::FPSLimit() +{ + using namespace std::chrono; + using namespace std::this_thread; + + if (vid_maxfps <= 0 || cl_capfps) + return; + + uint64_t targetWakeTime = fpsLimitTime + 1'000'000 / vid_maxfps; + + while (true) + { + fpsLimitTime = duration_cast(steady_clock::now().time_since_epoch()).count(); + int64_t timeToWait = targetWakeTime - fpsLimitTime; + + if (timeToWait > 1'000'000 || timeToWait <= 0) + { + break; + } + + if (timeToWait <= 2'000) + { + // We are too close to the deadline. OS sleep is not precise enough to wake us before it elapses. + // Yield execution and check time again. + sleep_for(nanoseconds(0)); + } + else + { + // Sleep, but try to wake before deadline. + sleep_for(microseconds(timeToWait - 2'000)); + } + } +} + +FMaterial* DFrameBuffer::CreateMaterial(FGameTexture* tex, int scaleflags) +{ + return new FMaterial(tex, scaleflags); +} + + +//========================================================================== +// +// ZScript wrappers for inlines +// +//========================================================================== + +static int ScreenGetWidth() { return twod->GetWidth(); } +static int ScreenGetHeight() { return twod->GetHeight(); } + +DEFINE_ACTION_FUNCTION_NATIVE(_Screen, GetWidth, ScreenGetWidth) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(twod->GetWidth()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_Screen, GetHeight, ScreenGetHeight) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(twod->GetHeight()); +} + +DEFINE_ACTION_FUNCTION(_Screen, PaletteColor) +{ + PARAM_PROLOGUE; + PARAM_INT(index); + if (index < 0 || index > 255) index = 0; + else index = GPalette.BaseColors[index]; + ACTION_RETURN_INT(index); +} + diff --git a/src/common/rendering/v_video.cpp b/src/common/rendering/v_video.cpp new file mode 100644 index 00000000000..c19cbcdfff6 --- /dev/null +++ b/src/common/rendering/v_video.cpp @@ -0,0 +1,509 @@ +/* +** Video basics and init code. +** +**--------------------------------------------------------------------------- +** Copyright 1999-2016 Randy Heit +** Copyright 2005-2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + + +#include + +#include "i_system.h" +#include "c_cvars.h" +#include "x86.h" +#include "i_video.h" + +#include "c_console.h" + +#include "m_argv.h" + +#include "v_video.h" +#include "v_text.h" +#include "sc_man.h" + +#include "filesystem.h" +#include "c_dispatch.h" +#include "cmdlib.h" +#include "hardware.h" +#include "m_png.h" +#include "menu.h" +#include "vm.h" +#include "r_videoscale.h" +#include "i_time.h" +#include "version.h" +#include "texturemanager.h" +#include "i_interface.h" +#include "v_draw.h" + + +EXTERN_CVAR(Int, menu_resolution_custom_width) +EXTERN_CVAR(Int, menu_resolution_custom_height) + +CVAR(Int, win_x, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, win_y, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, win_w, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, win_h, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, win_maximized, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) + +CVAR(Bool, r_skipmats, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) + +// 0 means 'no pipelining' for non GLES2 and 4 elements for GLES2 +CUSTOM_CVAR(Int, gl_pipeline_depth, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (self < 0 || self >= HW_MAX_PIPELINE_BUFFERS) self = 0; + Printf("Changing the pipeline depth requires a restart for " GAMENAME ".\n"); +} + +CUSTOM_CVAR(Int, vid_maxfps, 500, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < GameTicRate && self != 0) + { + self = GameTicRate; + } + else if (self > 1000) + { + self = 1000; + } +} + +CUSTOM_CVAR(Int, vid_preferbackend, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + // [SP] This may seem pointless - but I don't want to implement live switching just + // yet - I'm pretty sure it's going to require a lot of reinits and destructions to + // do it right without memory leaks + + switch(self) + { +#ifdef HAVE_GLES2 + case 3: + self = 2; + return; // beware of recursions here. Assigning to 'self' will recursively call this handler again. + case 2: + Printf("Selecting OpenGLES 2.0 backend...\n"); + break; +#endif +#ifdef HAVE_VULKAN + case 1: + Printf("Selecting Vulkan backend...\n"); + break; +#endif + default: + Printf("Selecting OpenGL backend...\n"); + } + + Printf("Changing the video backend requires a restart for " GAMENAME ".\n"); +} + +int V_GetBackend() +{ + int v = vid_preferbackend; + if (v == 3) vid_preferbackend = v = 2; + else if (v < 0 || v > 3) v = 0; + return v; +} + + +CUSTOM_CVAR(Int, uiscale, 0, CVAR_ARCHIVE | CVAR_NOINITCALL) +{ + if (self < 0) + { + self = 0; + return; + } + if (sysCallbacks.OnScreenSizeChanged) + sysCallbacks.OnScreenSizeChanged(); + setsizeneeded = true; +} + + + +EXTERN_CVAR(Bool, r_blendmethod) + +int active_con_scale(); + +#define DBGBREAK assert(0) + +class DDummyFrameBuffer : public DFrameBuffer +{ + typedef DFrameBuffer Super; +public: + DDummyFrameBuffer (int width, int height) + : DFrameBuffer (0, 0) + { + SetVirtualSize(width, height); + } + // These methods should never be called. + void Update() override { DBGBREAK; } + bool IsFullscreen() override { DBGBREAK; return 0; } + int GetClientWidth() override { DBGBREAK; return 0; } + int GetClientHeight() override { DBGBREAK; return 0; } + void InitializeState() override {} + + float Gamma; +}; + +int DisplayWidth, DisplayHeight; + +// [RH] The framebuffer is no longer a mere byte array. +// There's also only one, not four. +DFrameBuffer *screen; + +CVAR (Int, vid_defwidth, 640, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Int, vid_defheight, 480, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, ticker, false, 0) + +CUSTOM_CVAR (Bool, vid_vsync, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (screen != NULL) + { + screen->SetVSync (*self); + } +} + +// [RH] Set true when vid_setmode command has been executed +bool setmodeneeded = false; +bool setsizeneeded = false; + +//========================================================================== +// +// DCanvas Constructor +// +//========================================================================== + +DCanvas::DCanvas (int _width, int _height, bool _bgra) +{ + // Init member vars + Width = _width; + Height = _height; + Bgra = _bgra; + Resize(_width, _height); +} + +//========================================================================== +// +// DCanvas Destructor +// +//========================================================================== + +DCanvas::~DCanvas () +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +void DCanvas::Resize(int width, int height, bool optimizepitch) +{ + Width = width; + Height = height; + + // Making the pitch a power of 2 is very bad for performance + // Try to maximize the number of cache lines that can be filled + // for each column drawing operation by making the pitch slightly + // longer than the width. The values used here are all based on + // empirical evidence. + + if (width <= 640 || !optimizepitch) + { + // For low resolutions, just keep the pitch the same as the width. + // Some speedup can be seen using the technique below, but the speedup + // is so marginal that I don't consider it worthwhile. + Pitch = width; + } + else + { + // If we couldn't figure out the CPU's L1 cache line size, assume + // it's 32 bytes wide. + if (CPU.DataL1LineSize == 0) + { + CPU.DataL1LineSize = 32; + } + // The Athlon and P3 have very different caches, apparently. + // I am going to generalize the Athlon's performance to all AMD + // processors and the P3's to all non-AMD processors. I don't know + // how smart that is, but I don't have a vast plethora of + // processors to test with. + if (CPU.bIsAMD) + { + Pitch = width + CPU.DataL1LineSize; + } + else + { + Pitch = width + max(0, CPU.DataL1LineSize - 8); + } + } + int bytes_per_pixel = Bgra ? 4 : 1; + Pixels.Resize(Pitch * height * bytes_per_pixel); + memset (Pixels.Data(), 0, Pixels.Size()); +} + + +CCMD(clean) +{ + Printf ("CleanXfac: %d\nCleanYfac: %d\n", CleanXfac, CleanYfac); +} + + +void V_UpdateModeSize (int width, int height) +{ + // This calculates the menu scale. + // The optimal scale will always be to fit a virtual 640 pixel wide display onto the screen. + // Exceptions are made for a few ranges where the available virtual width is > 480. + + // This reference size is being used so that on 800x450 (small 16:9) a scale of 2 gets used. + + CleanXfac = max(min(screen->GetWidth() / 400, screen->GetHeight() / 240), 1); + if (CleanXfac >= 4) CleanXfac--; // Otherwise we do not have enough space for the episode/skill menus in some languages. + CleanYfac = CleanXfac; + CleanWidth = screen->GetWidth() / CleanXfac; + CleanHeight = screen->GetHeight() / CleanYfac; + + int w = screen->GetWidth(); + int h = screen->GetHeight(); + + // clamp screen aspect ratio to 17:10, for anything wider the width will be reduced + double aspect = (double)w / h; + if (aspect > 1.7) w = int(w * 1.7 / aspect); + + int factor; + if (w < 640) factor = 1; + else if (w >= 1024 && w < 1280) factor = 2; + else if (w >= 1600 && w < 1920) factor = 3; + else factor = w / 640; + + if (w < 1360) factor = 1; + else if (w < 1920) factor = 2; + else factor = int(factor * 0.7); + + CleanYfac_1 = CleanXfac_1 = factor;// max(1, int(factor * 0.7)); + CleanWidth_1 = width / CleanXfac_1; + CleanHeight_1 = height / CleanYfac_1; + + DisplayWidth = width; + DisplayHeight = height; +} + +void V_OutputResized (int width, int height) +{ + V_UpdateModeSize(width, height); + // set new resolution in 2D drawer + twod->Begin(screen->GetWidth(), screen->GetHeight()); + twod->End(); + setsizeneeded = true; + C_NewModeAdjust(); + if (sysCallbacks.OnScreenSizeChanged) + sysCallbacks.OnScreenSizeChanged(); +} + +bool IVideo::SetResolution () +{ + DFrameBuffer *buff = CreateFrameBuffer(); + + if (buff == NULL) // this cannot really happen + { + return false; + } + + screen = buff; + screen->InitializeState(); + + V_UpdateModeSize(screen->GetWidth(), screen->GetHeight()); + + return true; +} + +// +// V_Init +// + +void V_InitScreenSize () +{ + const char *i; + int width, height, bits; + + width = height = bits = 0; + + if ( (i = Args->CheckValue ("-width")) ) + width = atoi (i); + + if ( (i = Args->CheckValue ("-height")) ) + height = atoi (i); + + if (width == 0) + { + if (height == 0) + { + width = vid_defwidth; + height = vid_defheight; + } + else + { + width = (height * 8) / 6; + } + } + else if (height == 0) + { + height = (width * 6) / 8; + } + // Remember the passed arguments for the next time the game starts up windowed. + vid_defwidth = width; + vid_defheight = height; +} + +void V_InitScreen() +{ + screen = new DDummyFrameBuffer (vid_defwidth, vid_defheight); +} + +void V_Init2() +{ + { + DFrameBuffer *s = screen; + screen = NULL; + delete s; + } + + UCVarValue val; + + val.Bool = !!Args->CheckParm("-devparm"); + ticker->SetGenericRepDefault(val, CVAR_Bool); + + + I_InitGraphics(); + + Video->SetResolution(); // this only fails via exceptions. + Printf ("Resolution: %d x %d\n", SCREENWIDTH, SCREENHEIGHT); + + // init these for the scaling menu + menu_resolution_custom_width = SCREENWIDTH; + menu_resolution_custom_height = SCREENHEIGHT; + + screen->SetVSync(vid_vsync); + FBaseCVar::ResetColors (); + C_NewModeAdjust(); + setsizeneeded = true; +} + +CUSTOM_CVAR (Int, vid_aspect, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) +{ + setsizeneeded = true; + if (sysCallbacks.OnScreenSizeChanged) + sysCallbacks.OnScreenSizeChanged(); +} + +DEFINE_ACTION_FUNCTION(_Screen, GetAspectRatio) +{ + ACTION_RETURN_FLOAT(ActiveRatio(screen->GetWidth(), screen->GetHeight(), nullptr)); +} + +CCMD(vid_setsize) +{ + if (argv.argc() < 3) + { + Printf("Usage: vid_setsize width height\n"); + } + else + { + screen->SetWindowSize((int)strtol(argv[1], nullptr, 0), (int)strtol(argv[2], nullptr, 0)); + V_OutputResized(screen->GetClientWidth(), screen->GetClientHeight()); + } +} + + +void IVideo::DumpAdapters () +{ + Printf("Multi-monitor support unavailable.\n"); +} + +CUSTOM_CVAR(Bool, vid_fullscreen, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + setmodeneeded = true; +} + +CUSTOM_CVAR(Bool, vid_hdr, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} + +CCMD(vid_listadapters) +{ + if (Video != NULL) + Video->DumpAdapters(); +} + +bool vid_hdr_active = false; + +DEFINE_GLOBAL(SmallFont) +DEFINE_GLOBAL(SmallFont2) +DEFINE_GLOBAL(BigFont) +DEFINE_GLOBAL(ConFont) +DEFINE_GLOBAL(NewConsoleFont) +DEFINE_GLOBAL(NewSmallFont) +DEFINE_GLOBAL(AlternativeSmallFont) +DEFINE_GLOBAL(AlternativeBigFont) +DEFINE_GLOBAL(OriginalSmallFont) +DEFINE_GLOBAL(OriginalBigFont) +DEFINE_GLOBAL(IntermissionFont) +DEFINE_GLOBAL(CleanXfac) +DEFINE_GLOBAL(CleanYfac) +DEFINE_GLOBAL(CleanWidth) +DEFINE_GLOBAL(CleanHeight) +DEFINE_GLOBAL(CleanXfac_1) +DEFINE_GLOBAL(CleanYfac_1) +DEFINE_GLOBAL(CleanWidth_1) +DEFINE_GLOBAL(CleanHeight_1) + +//========================================================================== +// +// CVAR transsouls +// +// How translucent things drawn with STYLE_SoulTrans are. Normally, only +// Lost Souls have this render style. +// Values less than 0.25 will automatically be set to +// 0.25 to ensure some degree of visibility. Likewise, values above 1.0 will +// be set to 1.0, because anything higher doesn't make sense. +// +//========================================================================== + +CUSTOM_CVAR(Float, transsouls, 0.75f, CVAR_ARCHIVE) +{ + if (self < 0.25f) + { + self = 0.25f; + } + else if (self > 1.f) + { + self = 1.f; + } +} + diff --git a/src/common/rendering/v_video.h b/src/common/rendering/v_video.h new file mode 100644 index 00000000000..ed428ee6715 --- /dev/null +++ b/src/common/rendering/v_video.h @@ -0,0 +1,325 @@ +/* +** v_video.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __V_VIDEO_H__ +#define __V_VIDEO_H__ + +#include +#include "basics.h" +#include "vectors.h" +#include "m_png.h" +#include "renderstyle.h" +#include "c_cvars.h" +#include "v_2ddrawer.h" +#include "intrect.h" +#include "hw_shadowmap.h" +#include "hw_levelmesh.h" +#include "buffers.h" +#include "files.h" + + +struct FPortalSceneState; +class FSkyVertexBuffer; +class IIndexBuffer; +class IVertexBuffer; +class IDataBuffer; +class FFlatVertexBuffer; +class HWViewpointBuffer; +class FLightBuffer; +struct HWDrawInfo; +class FMaterial; +class FGameTexture; +class FRenderState; +class BoneBuffer; + +enum EHWCaps +{ + // [BB] Added texture compression flags. + RFL_TEXTURE_COMPRESSION = 1, + RFL_TEXTURE_COMPRESSION_S3TC = 2, + + RFL_SHADER_STORAGE_BUFFER = 4, + RFL_BUFFER_STORAGE = 8, + + RFL_NO_CLIP_PLANES = 32, + + RFL_INVALIDATE_BUFFER = 64, + RFL_DEBUG = 128, +}; + + +extern int DisplayWidth, DisplayHeight; + +void V_UpdateModeSize (int width, int height); +void V_OutputResized (int width, int height); + +EXTERN_CVAR(Bool, vid_fullscreen) +EXTERN_CVAR(Int, win_x) +EXTERN_CVAR(Int, win_y) +EXTERN_CVAR(Int, win_w) +EXTERN_CVAR(Int, win_h) +EXTERN_CVAR(Bool, win_maximized) + +struct FColormap; +enum FTextureFormat : uint32_t; +class FModelRenderer; +struct SamplerUniform; + +// +// VIDEO +// +// +class DCanvas +{ +public: + DCanvas (int width, int height, bool bgra); + ~DCanvas (); + void Resize(int width, int height, bool optimizepitch = true); + + // Member variable access + inline uint8_t *GetPixels () const { return Pixels.Data(); } + inline int GetWidth () const { return Width; } + inline int GetHeight () const { return Height; } + inline int GetPitch () const { return Pitch; } + inline bool IsBgra() const { return Bgra; } + +protected: + TArray Pixels; + int Width; + int Height; + int Pitch; + bool Bgra; +}; + +class IHardwareTexture; +class FTexture; + + +class DFrameBuffer +{ +private: + int Width = 0; + int Height = 0; + +public: + // Hardware render state that needs to be exposed to the API independent part of the renderer. For ease of access this is stored in the base class. + int hwcaps = 0; // Capability flags + float glslversion = 0; // This is here so that the differences between old OpenGL and new OpenGL/Vulkan can be handled by platform independent code. + int instack[2] = { 0,0 }; // this is globally maintained state for portal recursion avoidance. + int stencilValue = 0; // Global stencil test value + unsigned int uniformblockalignment = 256; // Hardware dependent uniform buffer alignment. + unsigned int maxuniformblock = 65536; + const char *vendorstring; // We have to account for some issues with particular vendors. + FSkyVertexBuffer *mSkyData = nullptr; // the sky vertex buffer + FFlatVertexBuffer *mVertexData = nullptr; // Global vertex data + HWViewpointBuffer *mViewpoints = nullptr; // Viewpoint render data. + FLightBuffer *mLights = nullptr; // Dynamic lights + BoneBuffer* mBones = nullptr; // Model bones + IShadowMap mShadowMap; + + int mGameScreenWidth = 0; + int mGameScreenHeight = 0; + IntRect mScreenViewport; + IntRect mSceneViewport; + IntRect mOutputLetterbox; + float mSceneClearColor[4]{ 0,0,0,255 }; + + int mPipelineNbr = 1; // Number of HW buffers to pipeline + int mPipelineType = 0; + +public: + DFrameBuffer (int width=1, int height=1); + virtual ~DFrameBuffer(); + virtual void InitializeState() = 0; // For stuff that needs 'screen' set. + virtual bool IsVulkan() { return false; } + virtual bool IsPoly() { return false; } + virtual int GetShaderCount(); + virtual bool CompileNextShader() { return true; } + void SetAABBTree(hwrenderer::LevelAABBTree * tree) + { + mShadowMap.SetAABBTree(tree); + } + virtual void SetLevelMesh(hwrenderer::LevelMesh *mesh) { } + bool allowSSBO() const + { +#ifndef HW_BLOCK_SSBO + return true; +#else + return mPipelineType == 0; +#endif + } + + // SSBOs have quite worse performance for read only data, so keep this around only as long as Vulkan has not been adapted yet. + bool useSSBO() + { + return IsVulkan(); + } + + virtual DCanvas* GetCanvas() { return nullptr; } + + void SetSize(int width, int height); + void SetVirtualSize(int width, int height) + { + Width = width; + Height = height; + } + inline int GetWidth() const { return Width; } + inline int GetHeight() const { return Height; } + + FVector2 SceneScale() const + { + return { mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height }; + } + + FVector2 SceneOffset() const + { + return { mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height }; + } + + // Make the surface visible. + virtual void Update (); + + // Stores the palette with flash blended in into 256 dwords + // Mark the palette as changed. It will be updated on the next Update(). + virtual void UpdatePalette() {} + + // Returns true if running fullscreen. + virtual bool IsFullscreen () = 0; + virtual void ToggleFullscreen(bool yes) {} + + // Changes the vsync setting, if supported by the device. + virtual void SetVSync (bool vsync); + + // Delete any resources that need to be deleted after restarting with a different IWAD + virtual void SetTextureFilterMode() {} + virtual IHardwareTexture *CreateHardwareTexture(int numchannels) { return nullptr; } + virtual void PrecacheMaterial(FMaterial *mat, int translation) {} + virtual FMaterial* CreateMaterial(FGameTexture* tex, int scaleflags); + virtual void BeginFrame() {} + virtual void SetWindowSize(int w, int h) {} + virtual void StartPrecaching() {} + virtual FRenderState* RenderState() { return nullptr; } + + virtual int GetClientWidth() = 0; + virtual int GetClientHeight() = 0; + virtual void BlurScene(float amount) {} + + virtual void InitLightmap(int LMTextureSize, int LMTextureCount, TArray& LMTextureData) {} + + // Interface to hardware rendering resources + virtual IVertexBuffer *CreateVertexBuffer() { return nullptr; } + virtual IIndexBuffer *CreateIndexBuffer() { return nullptr; } + virtual IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) { return nullptr; } + bool BuffersArePersistent() { return !!(hwcaps & RFL_BUFFER_STORAGE); } + + // This is overridable in case Vulkan does it differently. + virtual bool RenderTextureIsFlipped() const + { + return true; + } + + // Report a game restart + void SetClearColor(int color); + virtual int Backend() { return 0; } + virtual const char* DeviceName() const { return "Unknown"; } + virtual void AmbientOccludeScene(float m5) {} + virtual void FirstEye() {} + virtual void NextEye(int eyecount) {} + virtual void SetSceneRenderTarget(bool useSSAO) {} + virtual void UpdateShadowMap() {} + virtual void WaitForCommands(bool finish) {} + virtual void SetSaveBuffers(bool yes) {} + virtual void ImageTransitionScene(bool unknown) {} + virtual void CopyScreenToBuffer(int width, int height, uint8_t* buffer) { memset(buffer, 0, width* height); } + virtual bool FlipSavePic() const { return false; } + virtual void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) {} + virtual void SetActiveRenderTarget() {} + + // Screen wiping + virtual FTexture *WipeStartScreen(); + virtual FTexture *WipeEndScreen(); + + virtual void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) { if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D(); } + + void ScaleCoordsFromWindow(int16_t &x, int16_t &y); + + virtual void Draw2D() {} + + virtual void SetViewportRects(IntRect *bounds); + int ScreenToWindowX(int x); + int ScreenToWindowY(int y); + + void FPSLimit(); + + // Retrieves a buffer containing image data for a screenshot. + // Hint: Pitch can be negative for upside-down images, in which case buffer + // points to the last row in the buffer, which will be the first row output. + virtual TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) { return TArray(); } + + static float GetZNear() { return 5.f; } + static float GetZFar() { return 65536.f; } + + // The original size of the framebuffer as selected in the video menu. + uint64_t FrameTime = 0; + +private: + uint64_t fpsLimitTime = 0; + + bool isIn2D = false; +}; + + +// This is the screen updated by I_FinishUpdate. +extern DFrameBuffer *screen; + +#define SCREENWIDTH (screen->GetWidth ()) +#define SCREENHEIGHT (screen->GetHeight ()) + +EXTERN_CVAR (Float, vid_gamma) + + +// Allocates buffer screens, call before R_Init. +void V_InitScreenSize(); +void V_InitScreen(); + +// Initializes graphics mode for the first time. +void V_Init2 (); + +void V_Shutdown (); +int V_GetBackend(); + +inline bool IsRatioWidescreen(int ratio) { return (ratio & 3) != 0; } +extern bool setsizeneeded, setmodeneeded; + + +#endif // __V_VIDEO_H__ diff --git a/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp b/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp new file mode 100644 index 00000000000..1c36f865ba2 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp @@ -0,0 +1,291 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_descriptorset.h" +#include "vk_streambuffer.h" +#include "vk_raytrace.h" +#include "vulkan/shaders/vk_shader.h" +#include "vulkan/textures/vk_samplers.h" +#include "vulkan/textures/vk_renderbuffers.h" +#include "vulkan/textures/vk_hwtexture.h" +#include "vulkan/textures/vk_texture.h" +#include +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_hwbuffer.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "vulkan/system/vk_buffer.h" +#include "flatvertices.h" +#include "hw_viewpointuniforms.h" +#include "v_2ddrawer.h" + +VkDescriptorSetManager::VkDescriptorSetManager(VulkanRenderDevice* fb) : fb(fb) +{ + CreateHWBufferSetLayout(); + CreateFixedSetLayout(); + CreateHWBufferPool(); + CreateFixedSetPool(); +} + +VkDescriptorSetManager::~VkDescriptorSetManager() +{ + while (!Materials.empty()) + RemoveMaterial(Materials.back()); +} + +void VkDescriptorSetManager::Init() +{ + UpdateFixedSet(); + UpdateHWBufferSet(); +} + +void VkDescriptorSetManager::Deinit() +{ + while (!Materials.empty()) + RemoveMaterial(Materials.back()); +} + +void VkDescriptorSetManager::BeginFrame() +{ + UpdateFixedSet(); + UpdateHWBufferSet(); +} + +void VkDescriptorSetManager::UpdateHWBufferSet() +{ + fb->GetCommands()->DrawDeleteList->Add(std::move(HWBufferSet)); + + HWBufferSet = HWBufferDescriptorPool->tryAllocate(HWBufferSetLayout.get()); + if (!HWBufferSet) + { + fb->GetCommands()->WaitForCommands(false); + HWBufferSet = HWBufferDescriptorPool->allocate(HWBufferSetLayout.get()); + } + + WriteDescriptors() + .AddBuffer(HWBufferSet.get(), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->GetBufferManager()->ViewpointUBO->mBuffer.get(), 0, sizeof(HWViewpointUniforms)) + .AddBuffer(HWBufferSet.get(), 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->GetBufferManager()->MatrixBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(MatricesUBO)) + .AddBuffer(HWBufferSet.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->GetBufferManager()->StreamBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(StreamUBO)) + .AddBuffer(HWBufferSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->LightBufferSSO->mBuffer.get()) + .AddBuffer(HWBufferSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->BoneBufferSSO->mBuffer.get()) + .Execute(fb->device.get()); +} + +void VkDescriptorSetManager::UpdateFixedSet() +{ + fb->GetCommands()->DrawDeleteList->Add(std::move(FixedSet)); + + FixedSet = FixedDescriptorPool->tryAllocate(FixedSetLayout.get()); + if (!FixedSet) + { + fb->GetCommands()->WaitForCommands(false); + FixedSet = FixedDescriptorPool->allocate(FixedSetLayout.get()); + } + + WriteDescriptors update; + update.AddCombinedImageSampler(FixedSet.get(), 0, fb->GetTextureManager()->Shadowmap.View.get(), fb->GetSamplerManager()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + update.AddCombinedImageSampler(FixedSet.get(), 1, fb->GetTextureManager()->Lightmap.View.get(), fb->GetSamplerManager()->LightmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + if (fb->RaytracingEnabled()) + update.AddAccelerationStructure(FixedSet.get(), 2, fb->GetRaytrace()->GetAccelStruct()); + update.Execute(fb->device.get()); +} + +void VkDescriptorSetManager::ResetHWTextureSets() +{ + for (auto mat : Materials) + mat->DeleteDescriptors(); + + auto deleteList = fb->GetCommands()->DrawDeleteList.get(); + for (auto& desc : TextureDescriptorPools) + { + deleteList->Add(std::move(desc)); + } + deleteList->Add(std::move(NullTextureDescriptorSet)); + + TextureDescriptorPools.clear(); + TextureDescriptorSetsLeft = 0; + TextureDescriptorsLeft = 0; +} + +VulkanDescriptorSet* VkDescriptorSetManager::GetNullTextureDescriptorSet() +{ + if (!NullTextureDescriptorSet) + { + NullTextureDescriptorSet = AllocateTextureDescriptorSet(SHADER_MIN_REQUIRED_TEXTURE_LAYERS); + + WriteDescriptors update; + for (int i = 0; i < SHADER_MIN_REQUIRED_TEXTURE_LAYERS; i++) + { + update.AddCombinedImageSampler(NullTextureDescriptorSet.get(), i, fb->GetTextureManager()->GetNullTextureView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + update.Execute(fb->device.get()); + } + + return NullTextureDescriptorSet.get(); +} + +std::unique_ptr VkDescriptorSetManager::AllocateTextureDescriptorSet(int numLayers) +{ + if (TextureDescriptorSetsLeft == 0 || TextureDescriptorsLeft < numLayers) + { + TextureDescriptorSetsLeft = 1000; + TextureDescriptorsLeft = 2000; + + TextureDescriptorPools.push_back(DescriptorPoolBuilder() + .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, TextureDescriptorsLeft) + .MaxSets(TextureDescriptorSetsLeft) + .DebugName("VkDescriptorSetManager.TextureDescriptorPool") + .Create(fb->device.get())); + } + + TextureDescriptorSetsLeft--; + TextureDescriptorsLeft -= numLayers; + return TextureDescriptorPools.back()->allocate(GetTextureSetLayout(numLayers)); +} + +VulkanDescriptorSetLayout* VkDescriptorSetManager::GetTextureSetLayout(int numLayers) +{ + if (TextureSetLayouts.size() < (size_t)numLayers) + TextureSetLayouts.resize(numLayers); + + auto& layout = TextureSetLayouts[numLayers - 1]; + if (layout) + return layout.get(); + + DescriptorSetLayoutBuilder builder; + for (int i = 0; i < numLayers; i++) + { + builder.AddBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + } + builder.DebugName("VkDescriptorSetManager.TextureSetLayout"); + layout = builder.Create(fb->device.get()); + return layout.get(); +} + +void VkDescriptorSetManager::AddMaterial(VkMaterial* texture) +{ + texture->it = Materials.insert(Materials.end(), texture); +} + +void VkDescriptorSetManager::RemoveMaterial(VkMaterial* texture) +{ + texture->DeleteDescriptors(); + texture->fb = nullptr; + Materials.erase(texture->it); +} + +VulkanDescriptorSet* VkDescriptorSetManager::GetInput(VkPPRenderPassSetup* passSetup, const TArray& textures, bool bindShadowMapBuffers) +{ + auto descriptors = AllocatePPDescriptorSet(passSetup->DescriptorLayout.get()); + descriptors->SetDebugName("VkPostprocess.descriptors"); + + WriteDescriptors write; + VkImageTransition imageTransition; + + for (unsigned int index = 0; index < textures.Size(); index++) + { + const PPTextureInput& input = textures[index]; + VulkanSampler* sampler = fb->GetSamplerManager()->Get(input.Filter, input.Wrap); + VkTextureImage* tex = fb->GetTextureManager()->GetTexture(input.Type, input.Texture); + + write.AddCombinedImageSampler(descriptors.get(), index, tex->DepthOnlyView ? tex->DepthOnlyView.get() : tex->View.get(), sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + imageTransition.AddImage(tex, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); + } + + if (bindShadowMapBuffers) + { + write.AddBuffer(descriptors.get(), LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->LightNodes->mBuffer.get()); + write.AddBuffer(descriptors.get(), LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->LightLines->mBuffer.get()); + write.AddBuffer(descriptors.get(), LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->LightList->mBuffer.get()); + } + + write.Execute(fb->device.get()); + imageTransition.Execute(fb->GetCommands()->GetDrawCommands()); + + VulkanDescriptorSet* set = descriptors.get(); + fb->GetCommands()->DrawDeleteList->Add(std::move(descriptors)); + return set; +} + +std::unique_ptr VkDescriptorSetManager::AllocatePPDescriptorSet(VulkanDescriptorSetLayout* layout) +{ + if (PPDescriptorPool) + { + auto descriptors = PPDescriptorPool->tryAllocate(layout); + if (descriptors) + return descriptors; + + fb->GetCommands()->DrawDeleteList->Add(std::move(PPDescriptorPool)); + } + + PPDescriptorPool = DescriptorPoolBuilder() + .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 200) + .AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4) + .MaxSets(100) + .DebugName("PPDescriptorPool") + .Create(fb->device.get()); + + return PPDescriptorPool->allocate(layout); +} + +void VkDescriptorSetManager::CreateHWBufferSetLayout() +{ + HWBufferSetLayout = DescriptorSetLayoutBuilder() + .AddBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT) + .DebugName("VkDescriptorSetManager.HWBufferSetLayout") + .Create(fb->device.get()); +} + +void VkDescriptorSetManager::CreateFixedSetLayout() +{ + DescriptorSetLayoutBuilder builder; + builder.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + if (fb->RaytracingEnabled()) + builder.AddBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.DebugName("VkDescriptorSetManager.FixedSetLayout"); + FixedSetLayout = builder.Create(fb->device.get()); +} + +void VkDescriptorSetManager::CreateHWBufferPool() +{ + HWBufferDescriptorPool = DescriptorPoolBuilder() + .AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 3 * maxSets) + .AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2 * maxSets) + .MaxSets(maxSets) + .DebugName("VkDescriptorSetManager.HWBufferDescriptorPool") + .Create(fb->device.get()); +} + +void VkDescriptorSetManager::CreateFixedSetPool() +{ + DescriptorPoolBuilder poolbuilder; + poolbuilder.AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2 * maxSets); + if (fb->RaytracingEnabled()) + poolbuilder.AddPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1 * maxSets); + poolbuilder.MaxSets(maxSets); + poolbuilder.DebugName("VkDescriptorSetManager.FixedDescriptorPool"); + FixedDescriptorPool = poolbuilder.Create(fb->device.get()); +} diff --git a/src/common/rendering/vulkan/renderer/vk_descriptorset.h b/src/common/rendering/vulkan/renderer/vk_descriptorset.h new file mode 100644 index 00000000000..bbba2a9188c --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_descriptorset.h @@ -0,0 +1,71 @@ + +#pragma once + +#include "zvulkan/vulkanobjects.h" +#include +#include "tarray.h" + +class VulkanRenderDevice; +class VkMaterial; +class PPTextureInput; +class VkPPRenderPassSetup; + +class VkDescriptorSetManager +{ +public: + VkDescriptorSetManager(VulkanRenderDevice* fb); + ~VkDescriptorSetManager(); + + void Init(); + void Deinit(); + void BeginFrame(); + void UpdateFixedSet(); + void UpdateHWBufferSet(); + void ResetHWTextureSets(); + + VulkanDescriptorSetLayout* GetHWBufferSetLayout() { return HWBufferSetLayout.get(); } + VulkanDescriptorSetLayout* GetFixedSetLayout() { return FixedSetLayout.get(); } + VulkanDescriptorSetLayout* GetTextureSetLayout(int numLayers); + + VulkanDescriptorSet* GetHWBufferDescriptorSet() { return HWBufferSet.get(); } + VulkanDescriptorSet* GetFixedDescriptorSet() { return FixedSet.get(); } + VulkanDescriptorSet* GetNullTextureDescriptorSet(); + + std::unique_ptr AllocateTextureDescriptorSet(int numLayers); + + VulkanDescriptorSet* GetInput(VkPPRenderPassSetup* passSetup, const TArray& textures, bool bindShadowMapBuffers); + + void AddMaterial(VkMaterial* texture); + void RemoveMaterial(VkMaterial* texture); + +private: + void CreateHWBufferSetLayout(); + void CreateFixedSetLayout(); + void CreateHWBufferPool(); + void CreateFixedSetPool(); + + std::unique_ptr AllocatePPDescriptorSet(VulkanDescriptorSetLayout* layout); + + VulkanRenderDevice* fb = nullptr; + + std::unique_ptr HWBufferSetLayout; + std::unique_ptr FixedSetLayout; + std::vector> TextureSetLayouts; + + std::unique_ptr HWBufferDescriptorPool; + std::unique_ptr FixedDescriptorPool; + + std::unique_ptr PPDescriptorPool; + + int TextureDescriptorSetsLeft = 0; + int TextureDescriptorsLeft = 0; + std::vector> TextureDescriptorPools; + + std::unique_ptr HWBufferSet; + std::unique_ptr FixedSet; + std::unique_ptr NullTextureDescriptorSet; + + std::list Materials; + + static const int maxSets = 10; +}; diff --git a/src/common/rendering/vulkan/renderer/vk_postprocess.cpp b/src/common/rendering/vulkan/renderer/vk_postprocess.cpp new file mode 100644 index 00000000000..20ca83fd6c2 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_postprocess.cpp @@ -0,0 +1,293 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_postprocess.h" +#include "vulkan/shaders/vk_shader.h" +#include +#include +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_hwbuffer.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "vulkan/renderer/vk_renderstate.h" +#include "vulkan/renderer/vk_pprenderstate.h" +#include "vulkan/shaders/vk_ppshader.h" +#include "vulkan/textures/vk_pptexture.h" +#include "vulkan/textures/vk_renderbuffers.h" +#include "vulkan/textures/vk_imagetransition.h" +#include "vulkan/textures/vk_texture.h" +#include "vulkan/textures/vk_framebuffer.h" +#include "hw_cvars.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "hwrenderer/postprocessing/hw_postprocess_cvars.h" +#include "hw_vrmodes.h" +#include "flatvertices.h" +#include "r_videoscale.h" + +EXTERN_CVAR(Int, gl_dither_bpc) + +VkPostprocess::VkPostprocess(VulkanRenderDevice* fb) : fb(fb) +{ +} + +VkPostprocess::~VkPostprocess() +{ +} + +void VkPostprocess::SetActiveRenderTarget() +{ + auto buffers = fb->GetBuffers(); + + VkImageTransition() + .AddImage(&buffers->PipelineImage[mCurrentPipelineImage], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false) + .AddImage(&buffers->PipelineDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false) + .Execute(fb->GetCommands()->GetDrawCommands()); + + fb->GetRenderState()->SetRenderTarget(&buffers->PipelineImage[mCurrentPipelineImage], buffers->PipelineDepthStencil.View.get(), buffers->GetWidth(), buffers->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_1_BIT); +} + +void VkPostprocess::PostProcessScene(int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) +{ + int sceneWidth = fb->GetBuffers()->GetSceneWidth(); + int sceneHeight = fb->GetBuffers()->GetSceneHeight(); + + VkPPRenderState renderstate(fb); + + hw_postprocess.Pass1(&renderstate, fixedcm, sceneWidth, sceneHeight); + SetActiveRenderTarget(); + afterBloomDrawEndScene2D(); + hw_postprocess.Pass2(&renderstate, fixedcm, flash, sceneWidth, sceneHeight); +} + +void VkPostprocess::BlitSceneToPostprocess() +{ + fb->GetRenderState()->EndRenderPass(); + + auto buffers = fb->GetBuffers(); + auto cmdbuffer = fb->GetCommands()->GetDrawCommands(); + + mCurrentPipelineImage = 0; + + VkImageTransition() + .AddImage(&buffers->SceneColor, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false) + .AddImage(&buffers->PipelineImage[mCurrentPipelineImage], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) + .Execute(fb->GetCommands()->GetDrawCommands()); + + if (buffers->GetSceneSamples() != VK_SAMPLE_COUNT_1_BIT) + { + auto sceneColor = buffers->SceneColor.Image.get(); + VkImageResolve resolve = {}; + resolve.srcOffset = { 0, 0, 0 }; + resolve.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + resolve.srcSubresource.mipLevel = 0; + resolve.srcSubresource.baseArrayLayer = 0; + resolve.srcSubresource.layerCount = 1; + resolve.dstOffset = { 0, 0, 0 }; + resolve.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + resolve.dstSubresource.mipLevel = 0; + resolve.dstSubresource.baseArrayLayer = 0; + resolve.dstSubresource.layerCount = 1; + resolve.extent = { (uint32_t)sceneColor->width, (uint32_t)sceneColor->height, 1 }; + cmdbuffer->resolveImage( + sceneColor->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + buffers->PipelineImage[mCurrentPipelineImage].Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &resolve); + } + else + { + auto sceneColor = buffers->SceneColor.Image.get(); + VkImageBlit blit = {}; + blit.srcOffsets[0] = { 0, 0, 0 }; + blit.srcOffsets[1] = { sceneColor->width, sceneColor->height, 1 }; + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.mipLevel = 0; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = 1; + blit.dstOffsets[0] = { 0, 0, 0 }; + blit.dstOffsets[1] = { sceneColor->width, sceneColor->height, 1 }; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.mipLevel = 0; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = 1; + cmdbuffer->blitImage( + sceneColor->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + buffers->PipelineImage[mCurrentPipelineImage].Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, VK_FILTER_NEAREST); + } +} + +void VkPostprocess::ImageTransitionScene(bool undefinedSrcLayout) +{ + auto buffers = fb->GetBuffers(); + + VkImageTransition() + .AddImage(&buffers->SceneColor, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, undefinedSrcLayout) + .AddImage(&buffers->SceneFog, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, undefinedSrcLayout) + .AddImage(&buffers->SceneNormal, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, undefinedSrcLayout) + .AddImage(&buffers->SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, undefinedSrcLayout) + .Execute(fb->GetCommands()->GetDrawCommands()); +} + +void VkPostprocess::BlitCurrentToImage(VkTextureImage *dstimage, VkImageLayout finallayout) +{ + fb->GetRenderState()->EndRenderPass(); + + auto srcimage = &fb->GetBuffers()->PipelineImage[mCurrentPipelineImage]; + auto cmdbuffer = fb->GetCommands()->GetDrawCommands(); + + VkImageTransition() + .AddImage(srcimage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false) + .AddImage(dstimage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) + .Execute(cmdbuffer); + + VkImageBlit blit = {}; + blit.srcOffsets[0] = { 0, 0, 0 }; + blit.srcOffsets[1] = { srcimage->Image->width, srcimage->Image->height, 1 }; + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.mipLevel = 0; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = 1; + blit.dstOffsets[0] = { 0, 0, 0 }; + blit.dstOffsets[1] = { dstimage->Image->width, dstimage->Image->height, 1 }; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.mipLevel = 0; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = 1; + + cmdbuffer->blitImage( + srcimage->Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstimage->Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, VK_FILTER_NEAREST); + + VkImageTransition() + .AddImage(dstimage, finallayout, false) + .Execute(cmdbuffer); +} + +void VkPostprocess::DrawPresentTexture(const IntRect &box, bool applyGamma, bool screenshot) +{ + VkPPRenderState renderstate(fb); + + if (!screenshot) // Already applied as we are actually copying the last frame here (GetScreenshotBuffer is called after swap) + hw_postprocess.customShaders.Run(&renderstate, "screen"); + + PresentUniforms uniforms; + if (!applyGamma) + { + uniforms.InvGamma = 1.0f; + uniforms.Contrast = 1.0f; + uniforms.Brightness = 0.0f; + uniforms.Saturation = 1.0f; + } + else + { + uniforms.InvGamma = 1.0f / clamp(vid_gamma, 0.1f, 4.f); + uniforms.Contrast = clamp(vid_contrast, 0.1f, 3.f); + uniforms.Brightness = clamp(vid_brightness, -0.8f, 0.8f); + uniforms.Saturation = clamp(vid_saturation, -15.0f, 15.f); + uniforms.GrayFormula = static_cast(gl_satformula); + } + uniforms.ColorScale = (gl_dither_bpc == -1) ? 255.0f : (float)((1 << gl_dither_bpc) - 1); + + if (screenshot) + { + uniforms.Scale = { screen->mScreenViewport.width / (float)fb->GetBuffers()->GetWidth(), screen->mScreenViewport.height / (float)fb->GetBuffers()->GetHeight() }; + uniforms.Offset = { 0.0f, 0.0f }; + } + else + { + uniforms.Scale = { screen->mScreenViewport.width / (float)fb->GetBuffers()->GetWidth(), -screen->mScreenViewport.height / (float)fb->GetBuffers()->GetHeight() }; + uniforms.Offset = { 0.0f, 1.0f }; + } + + if (applyGamma && fb->GetFramebufferManager()->SwapChain->Format().colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT && !screenshot) + { + uniforms.HdrMode = 1; + } + else + { + uniforms.HdrMode = 0; + } + + renderstate.Clear(); + renderstate.Shader = &hw_postprocess.present.Present; + renderstate.Uniforms.Set(uniforms); + renderstate.Viewport = box; + renderstate.SetInputCurrent(0, ViewportLinearScale() ? PPFilterMode::Linear : PPFilterMode::Nearest); + renderstate.SetInputTexture(1, &hw_postprocess.present.Dither, PPFilterMode::Nearest, PPWrapMode::Repeat); + if (screenshot) + renderstate.SetOutputNext(); + else + renderstate.SetOutputSwapChain(); + renderstate.SetNoBlend(); + renderstate.Draw(); +} + +void VkPostprocess::AmbientOccludeScene(float m5) +{ + int sceneWidth = fb->GetBuffers()->GetSceneWidth(); + int sceneHeight = fb->GetBuffers()->GetSceneHeight(); + + VkPPRenderState renderstate(fb); + hw_postprocess.ssao.Render(&renderstate, m5, sceneWidth, sceneHeight); + + ImageTransitionScene(false); +} + +void VkPostprocess::BlurScene(float gameinfobluramount) +{ + int sceneWidth = fb->GetBuffers()->GetSceneWidth(); + int sceneHeight = fb->GetBuffers()->GetSceneHeight(); + + VkPPRenderState renderstate(fb); + + auto vrmode = VRMode::GetVRMode(true); + int eyeCount = vrmode->mEyeCount; + for (int i = 0; i < eyeCount; ++i) + { + hw_postprocess.bloom.RenderBlur(&renderstate, sceneWidth, sceneHeight, gameinfobluramount); + if (eyeCount - i > 1) NextEye(eyeCount); + } +} + +void VkPostprocess::ClearTonemapPalette() +{ + hw_postprocess.tonemap.ClearTonemapPalette(); +} + +void VkPostprocess::UpdateShadowMap() +{ + if (screen->mShadowMap.PerformUpdate()) + { + VkPPRenderState renderstate(fb); + hw_postprocess.shadowmap.Update(&renderstate); + + VkImageTransition() + .AddImage(&fb->GetTextureManager()->Shadowmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false) + .Execute(fb->GetCommands()->GetDrawCommands()); + + screen->mShadowMap.FinishUpdate(); + } +} + +void VkPostprocess::NextEye(int eyeCount) +{ +} diff --git a/src/common/rendering/vulkan/renderer/vk_postprocess.h b/src/common/rendering/vulkan/renderer/vk_postprocess.h new file mode 100644 index 00000000000..138113837d8 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_postprocess.h @@ -0,0 +1,51 @@ + +#pragma once + +#include +#include +#include + +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "zvulkan/vulkanobjects.h" +#include "zvulkan/vulkanbuilders.h" +#include "vulkan/textures/vk_imagetransition.h" + +class FString; + +class VkPPShader; +class VkPPTexture; +class PipelineBarrier; +class VulkanRenderDevice; + +class VkPostprocess +{ +public: + VkPostprocess(VulkanRenderDevice* fb); + ~VkPostprocess(); + + void SetActiveRenderTarget(); + void PostProcessScene(int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D); + + void AmbientOccludeScene(float m5); + void BlurScene(float gameinfobluramount); + void ClearTonemapPalette(); + + void UpdateShadowMap(); + + void ImageTransitionScene(bool undefinedSrcLayout); + + void BlitSceneToPostprocess(); + void BlitCurrentToImage(VkTextureImage *image, VkImageLayout finallayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + void DrawPresentTexture(const IntRect &box, bool applyGamma, bool screenshot); + + int GetCurrentPipelineImage() const { return mCurrentPipelineImage; } + +private: + void NextEye(int eyeCount); + + VulkanRenderDevice* fb = nullptr; + + int mCurrentPipelineImage = 0; + + friend class VkPPRenderState; +}; diff --git a/src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp b/src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp new file mode 100644 index 00000000000..838ca3fe245 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp @@ -0,0 +1,139 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_pprenderstate.h" +#include "vk_postprocess.h" +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_commandbuffer.h" +#include +#include "vulkan/system/vk_buffer.h" +#include "vulkan/shaders/vk_ppshader.h" +#include "vulkan/textures/vk_pptexture.h" +#include "vulkan/textures/vk_renderbuffers.h" +#include "vulkan/textures/vk_samplers.h" +#include "vulkan/textures/vk_texture.h" +#include "vulkan/textures/vk_framebuffer.h" +#include "vulkan/renderer/vk_renderstate.h" +#include "vulkan/renderer/vk_descriptorset.h" +#include "flatvertices.h" + +VkPPRenderState::VkPPRenderState(VulkanRenderDevice* fb) : fb(fb) +{ +} + +void VkPPRenderState::PushGroup(const FString &name) +{ + fb->GetCommands()->PushGroup(name); +} + +void VkPPRenderState::PopGroup() +{ + fb->GetCommands()->PopGroup(); +} + +void VkPPRenderState::Draw() +{ + fb->GetRenderState()->EndRenderPass(); + + VkPPRenderPassKey key; + key.BlendMode = BlendMode; + key.InputTextures = Textures.Size(); + key.Uniforms = Uniforms.Data.Size(); + key.Shader = fb->GetShaderManager()->GetVkShader(Shader); + key.SwapChain = (Output.Type == PPTextureType::SwapChain); + key.ShadowMapBuffers = ShadowMapBuffers; + if (Output.Type == PPTextureType::PPTexture) + key.OutputFormat = fb->GetTextureManager()->GetTextureFormat(Output.Texture); + else if (Output.Type == PPTextureType::SwapChain) + key.OutputFormat = fb->GetFramebufferManager()->SwapChain->Format().format; + else if (Output.Type == PPTextureType::ShadowMap) + key.OutputFormat = VK_FORMAT_R32_SFLOAT; + else + key.OutputFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + + if (Output.Type == PPTextureType::SceneColor) + { + key.StencilTest = WhichDepthStencil::Scene; + key.Samples = fb->GetBuffers()->GetSceneSamples(); + } + else + { + key.StencilTest = WhichDepthStencil::None; + key.Samples = VK_SAMPLE_COUNT_1_BIT; + } + + auto passSetup = fb->GetRenderPassManager()->GetPPRenderPass(key); + + int framebufferWidth = 0, framebufferHeight = 0; + VulkanDescriptorSet *input = fb->GetDescriptorSetManager()->GetInput(passSetup, Textures, ShadowMapBuffers); + VulkanFramebuffer *output = fb->GetBuffers()->GetOutput(passSetup, Output, key.StencilTest, framebufferWidth, framebufferHeight); + + RenderScreenQuad(passSetup, input, output, framebufferWidth, framebufferHeight, Viewport.left, Viewport.top, Viewport.width, Viewport.height, Uniforms.Data.Data(), Uniforms.Data.Size(), key.StencilTest == WhichDepthStencil::Scene); + + // Advance to next PP texture if our output was sent there + if (Output.Type == PPTextureType::NextPipelineTexture) + { + auto pp = fb->GetPostprocess(); + pp->mCurrentPipelineImage = (pp->mCurrentPipelineImage + 1) % VkRenderBuffers::NumPipelineImages; + } +} + +void VkPPRenderState::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest) +{ + auto cmdbuffer = fb->GetCommands()->GetDrawCommands(); + + VkViewport viewport = { }; + viewport.x = (float)x; + viewport.y = (float)y; + viewport.width = (float)width; + viewport.height = (float)height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = { }; + scissor.offset.x = 0; + scissor.offset.y = 0; + scissor.extent.width = framebufferWidth; + scissor.extent.height = framebufferHeight; + + RenderPassBegin() + .RenderPass(passSetup->RenderPass.get()) + .RenderArea(0, 0, framebufferWidth, framebufferHeight) + .Framebuffer(framebuffer) + .AddClearColor(0.0f, 0.0f, 0.0f, 1.0f) + .Execute(cmdbuffer); + + VkBuffer vertexBuffers[] = { static_cast(screen->mVertexData->GetBufferObjects().first)->mBuffer->buffer }; + VkDeviceSize offsets[] = { 0 }; + + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->Pipeline.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->PipelineLayout.get(), 0, descriptorSet); + cmdbuffer->bindVertexBuffers(0, 1, vertexBuffers, offsets); + cmdbuffer->setViewport(0, 1, &viewport); + cmdbuffer->setScissor(0, 1, &scissor); + if (stencilTest) + cmdbuffer->setStencilReference(VK_STENCIL_FRONT_AND_BACK, screen->stencilValue); + if (pushConstantsSize > 0) + cmdbuffer->pushConstants(passSetup->PipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, pushConstantsSize, pushConstants); + cmdbuffer->draw(3, 1, FFlatVertexBuffer::PRESENT_INDEX, 0); + cmdbuffer->endRenderPass(); +} diff --git a/src/common/rendering/vulkan/renderer/vk_pprenderstate.h b/src/common/rendering/vulkan/renderer/vk_pprenderstate.h new file mode 100644 index 00000000000..b0824bc1883 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_pprenderstate.h @@ -0,0 +1,27 @@ + +#pragma once + +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include + +class VkPPRenderPassSetup; +class VkPPShader; +class VkPPTexture; +class VkTextureImage; +class VulkanRenderDevice; + +class VkPPRenderState : public PPRenderState +{ +public: + VkPPRenderState(VulkanRenderDevice* fb); + + void PushGroup(const FString &name) override; + void PopGroup() override; + + void Draw() override; + +private: + void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest); + + VulkanRenderDevice* fb = nullptr; +}; diff --git a/src/common/rendering/vulkan/renderer/vk_raytrace.cpp b/src/common/rendering/vulkan/renderer/vk_raytrace.cpp new file mode 100644 index 00000000000..084c475eb20 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_raytrace.cpp @@ -0,0 +1,279 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_raytrace.h" +#include "zvulkan/vulkanbuilders.h" +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "hw_levelmesh.h" + +VkRaytrace::VkRaytrace(VulkanRenderDevice* fb) : fb(fb) +{ + NullMesh.MeshVertices.Push({ -1.0f, -1.0f, -1.0f }); + NullMesh.MeshVertices.Push({ 1.0f, -1.0f, -1.0f }); + NullMesh.MeshVertices.Push({ 1.0f, 1.0f, -1.0f }); + NullMesh.MeshVertices.Push({ -1.0f, -1.0f, -1.0f }); + NullMesh.MeshVertices.Push({ -1.0f, 1.0f, -1.0f }); + NullMesh.MeshVertices.Push({ 1.0f, 1.0f, -1.0f }); + NullMesh.MeshVertices.Push({ -1.0f, -1.0f, 1.0f }); + NullMesh.MeshVertices.Push({ 1.0f, -1.0f, 1.0f }); + NullMesh.MeshVertices.Push({ 1.0f, 1.0f, 1.0f }); + NullMesh.MeshVertices.Push({ -1.0f, -1.0f, 1.0f }); + NullMesh.MeshVertices.Push({ -1.0f, 1.0f, 1.0f }); + NullMesh.MeshVertices.Push({ 1.0f, 1.0f, 1.0f }); + for (int i = 0; i < 3 * 4; i++) + NullMesh.MeshElements.Push(i); + + SetLevelMesh(nullptr); +} + +void VkRaytrace::SetLevelMesh(hwrenderer::LevelMesh* mesh) +{ + if (!mesh) + mesh = &NullMesh; + + if (mesh != Mesh) + { + Reset(); + Mesh = mesh; + if (fb->RaytracingEnabled()) + { + CreateVulkanObjects(); + } + } +} + +void VkRaytrace::Reset() +{ + auto deletelist = fb->GetCommands()->DrawDeleteList.get(); + deletelist->Add(std::move(vertexBuffer)); + deletelist->Add(std::move(indexBuffer)); + deletelist->Add(std::move(transferBuffer)); + deletelist->Add(std::move(blScratchBuffer)); + deletelist->Add(std::move(blAccelStructBuffer)); + deletelist->Add(std::move(blAccelStruct)); + deletelist->Add(std::move(tlTransferBuffer)); + deletelist->Add(std::move(tlScratchBuffer)); + deletelist->Add(std::move(tlInstanceBuffer)); + deletelist->Add(std::move(tlAccelStructBuffer)); + deletelist->Add(std::move(tlAccelStruct)); +} + +void VkRaytrace::CreateVulkanObjects() +{ + CreateVertexAndIndexBuffers(); + CreateBottomLevelAccelerationStructure(); + CreateTopLevelAccelerationStructure(); +} + +void VkRaytrace::CreateVertexAndIndexBuffers() +{ + static_assert(sizeof(FVector3) == 3 * 4, "sizeof(FVector3) is not 12 bytes!"); + + size_t vertexbuffersize = (size_t)Mesh->MeshVertices.Size() * sizeof(FVector3); + size_t indexbuffersize = (size_t)Mesh->MeshElements.Size() * sizeof(uint32_t); + size_t transferbuffersize = vertexbuffersize + indexbuffersize; + size_t vertexoffset = 0; + size_t indexoffset = vertexoffset + vertexbuffersize; + + transferBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .Size(transferbuffersize) + .DebugName("transferBuffer") + .Create(fb->device.get()); + + uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize); + memcpy(data + vertexoffset, Mesh->MeshVertices.Data(), vertexbuffersize); + memcpy(data + indexoffset, Mesh->MeshElements.Data(), indexbuffersize); + transferBuffer->Unmap(); + + vertexBuffer = BufferBuilder() + .Usage( + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR) + .Size(vertexbuffersize) + .DebugName("vertexBuffer") + .Create(fb->device.get()); + + indexBuffer = BufferBuilder() + .Usage( + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR) + .Size(indexbuffersize) + .DebugName("indexBuffer") + .Create(fb->device.get()); + + fb->GetCommands()->GetTransferCommands()->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset); + fb->GetCommands()->GetTransferCommands()->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset); + + // Finish transfer before using it for building + PipelineBarrier() + .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) + .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); +} + +void VkRaytrace::CreateBottomLevelAccelerationStructure() +{ + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; + VkAccelerationStructureGeometryKHR accelStructBLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; + VkAccelerationStructureGeometryKHR* geometries[] = { &accelStructBLDesc }; + VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; + + accelStructBLDesc.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + accelStructBLDesc.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + accelStructBLDesc.geometry.triangles = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR }; + accelStructBLDesc.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; + accelStructBLDesc.geometry.triangles.vertexData.deviceAddress = vertexBuffer->GetDeviceAddress(); + accelStructBLDesc.geometry.triangles.vertexStride = sizeof(FVector3); + accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; + accelStructBLDesc.geometry.triangles.indexData.deviceAddress = indexBuffer->GetDeviceAddress(); + accelStructBLDesc.geometry.triangles.maxVertex = Mesh->MeshVertices.Size() - 1; + + buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + buildInfo.geometryCount = 1; + buildInfo.ppGeometries = geometries; + + uint32_t maxPrimitiveCount = Mesh->MeshElements.Size() / 3; + + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; + vkGetAccelerationStructureBuildSizesKHR(fb->device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo); + + blAccelStructBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) + .Size(sizeInfo.accelerationStructureSize) + .DebugName("blAccelStructBuffer") + .Create(fb->device.get()); + + blAccelStruct = AccelerationStructureBuilder() + .Type(VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) + .Buffer(blAccelStructBuffer.get(), sizeInfo.accelerationStructureSize) + .DebugName("blAccelStruct") + .Create(fb->device.get()); + + blScratchBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) + .Size(sizeInfo.buildScratchSize) + .DebugName("blScratchBuffer") + .Create(fb->device.get()); + + buildInfo.dstAccelerationStructure = blAccelStruct->accelstruct; + buildInfo.scratchData.deviceAddress = blScratchBuffer->GetDeviceAddress(); + rangeInfo.primitiveCount = maxPrimitiveCount; + + fb->GetCommands()->GetTransferCommands()->buildAccelerationStructures(1, &buildInfo, rangeInfos); + + // Finish building before using it as input to a toplevel accel structure + PipelineBarrier() + .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR) + .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); +} + +void VkRaytrace::CreateTopLevelAccelerationStructure() +{ + VkAccelerationStructureInstanceKHR instance = {}; + instance.transform.matrix[0][0] = 1.0f; + instance.transform.matrix[1][1] = 1.0f; + instance.transform.matrix[2][2] = 1.0f; + instance.mask = 0xff; + instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; + instance.accelerationStructureReference = blAccelStruct->GetDeviceAddress(); + + tlTransferBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .Size(sizeof(VkAccelerationStructureInstanceKHR)) + .DebugName("tlTransferBuffer") + .Create(fb->device.get()); + + auto data = (uint8_t*)tlTransferBuffer->Map(0, sizeof(VkAccelerationStructureInstanceKHR)); + memcpy(data, &instance, sizeof(VkAccelerationStructureInstanceKHR)); + tlTransferBuffer->Unmap(); + + tlInstanceBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .Size(sizeof(VkAccelerationStructureInstanceKHR)) + .DebugName("tlInstanceBuffer") + .Create(fb->device.get()); + + fb->GetCommands()->GetTransferCommands()->copyBuffer(tlTransferBuffer.get(), tlInstanceBuffer.get()); + + // Finish transfering before using it as input + PipelineBarrier() + .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) + .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); + + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; + VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; + VkAccelerationStructureGeometryKHR* geometries[] = { &accelStructTLDesc }; + VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; + + buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + buildInfo.geometryCount = 1; + buildInfo.ppGeometries = geometries; + + accelStructTLDesc.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + accelStructTLDesc.geometry.instances = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR }; + accelStructTLDesc.geometry.instances.data.deviceAddress = tlInstanceBuffer->GetDeviceAddress(); + + uint32_t maxInstanceCount = 1; + + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; + vkGetAccelerationStructureBuildSizesKHR(fb->device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxInstanceCount, &sizeInfo); + + tlAccelStructBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) + .Size(sizeInfo.accelerationStructureSize) + .DebugName("tlAccelStructBuffer") + .Create(fb->device.get()); + + tlAccelStruct = AccelerationStructureBuilder() + .Type(VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) + .Buffer(tlAccelStructBuffer.get(), sizeInfo.accelerationStructureSize) + .DebugName("tlAccelStruct") + .Create(fb->device.get()); + + tlScratchBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) + .Size(sizeInfo.buildScratchSize) + .DebugName("tlScratchBuffer") + .Create(fb->device.get()); + + buildInfo.dstAccelerationStructure = tlAccelStruct->accelstruct; + buildInfo.scratchData.deviceAddress = tlScratchBuffer->GetDeviceAddress(); + rangeInfo.primitiveCount = 1; + + fb->GetCommands()->GetTransferCommands()->buildAccelerationStructures(1, &buildInfo, rangeInfos); + + // Finish building the accel struct before using as input in a fragment shader + PipelineBarrier() + .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_SHADER_READ_BIT) + .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +} diff --git a/src/common/rendering/vulkan/renderer/vk_raytrace.h b/src/common/rendering/vulkan/renderer/vk_raytrace.h new file mode 100644 index 00000000000..e54a9c623d6 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_raytrace.h @@ -0,0 +1,43 @@ + +#pragma once + +#include "zvulkan/vulkanobjects.h" +#include "hw_levelmesh.h" + +class VulkanRenderDevice; + +class VkRaytrace +{ +public: + VkRaytrace(VulkanRenderDevice* fb); + + void SetLevelMesh(hwrenderer::LevelMesh* mesh); + + VulkanAccelerationStructure* GetAccelStruct() { return tlAccelStruct.get(); } + +private: + void Reset(); + void CreateVulkanObjects(); + void CreateVertexAndIndexBuffers(); + void CreateBottomLevelAccelerationStructure(); + void CreateTopLevelAccelerationStructure(); + + VulkanRenderDevice* fb = nullptr; + + hwrenderer::LevelMesh NullMesh; + hwrenderer::LevelMesh* Mesh = nullptr; + + std::unique_ptr vertexBuffer; + std::unique_ptr indexBuffer; + std::unique_ptr transferBuffer; + + std::unique_ptr blScratchBuffer; + std::unique_ptr blAccelStructBuffer; + std::unique_ptr blAccelStruct; + + std::unique_ptr tlTransferBuffer; + std::unique_ptr tlScratchBuffer; + std::unique_ptr tlInstanceBuffer; + std::unique_ptr tlAccelStructBuffer; + std::unique_ptr tlAccelStruct; +}; diff --git a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp new file mode 100644 index 00000000000..522933581a1 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp @@ -0,0 +1,496 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_renderpass.h" +#include "vk_renderstate.h" +#include "vk_descriptorset.h" +#include "vk_raytrace.h" +#include "vulkan/textures/vk_renderbuffers.h" +#include "vulkan/textures/vk_samplers.h" +#include "vulkan/shaders/vk_shader.h" +#include "vulkan/shaders/vk_ppshader.h" +#include +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_hwbuffer.h" +#include "flatvertices.h" +#include "hw_viewpointuniforms.h" +#include "v_2ddrawer.h" +#include "i_specialpaths.h" +#include "cmdlib.h" + +VkRenderPassManager::VkRenderPassManager(VulkanRenderDevice* fb) : fb(fb) +{ + FString path = M_GetCachePath(true); + CreatePath(path.GetChars()); + CacheFilename = path + "/pipelinecache.zdpc"; + + PipelineCacheBuilder builder; + builder.DebugName("PipelineCache"); + + try + { + FileReader fr; + if (fr.OpenFile(CacheFilename.GetChars())) + { + std::vector data; + data.resize(fr.GetLength()); + if (fr.Read(data.data(), data.size()) == (FileReader::Size)data.size()) + { + builder.InitialData(data.data(), data.size()); + } + } + } + catch (...) + { + } + + PipelineCache = builder.Create(fb->device.get()); +} + +VkRenderPassManager::~VkRenderPassManager() +{ + try + { + auto data = PipelineCache->GetCacheData(); + std::unique_ptr fw(FileWriter::Open(CacheFilename.GetChars())); + if (fw) + fw->Write(data.data(), data.size()); + } + catch (...) + { + } +} + +void VkRenderPassManager::RenderBuffersReset() +{ + RenderPassSetup.clear(); + PPRenderPassSetup.clear(); +} + +VkRenderPassSetup *VkRenderPassManager::GetRenderPass(const VkRenderPassKey &key) +{ + auto &item = RenderPassSetup[key]; + if (!item) + item.reset(new VkRenderPassSetup(fb, key)); + return item.get(); +} + +int VkRenderPassManager::GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) +{ + for (size_t i = 0; i < VertexFormats.size(); i++) + { + const auto &f = VertexFormats[i]; + if (f.Attrs.size() == (size_t)numAttributes && f.NumBindingPoints == numBindingPoints && f.Stride == stride) + { + bool matches = true; + for (int j = 0; j < numAttributes; j++) + { + if (memcmp(&f.Attrs[j], &attrs[j], sizeof(FVertexBufferAttribute)) != 0) + { + matches = false; + break; + } + } + + if (matches) + return (int)i; + } + } + + VkVertexFormat fmt; + fmt.NumBindingPoints = numBindingPoints; + fmt.Stride = stride; + fmt.UseVertexData = 0; + for (int j = 0; j < numAttributes; j++) + { + if (attrs[j].location == VATTR_COLOR) + fmt.UseVertexData |= 1; + else if (attrs[j].location == VATTR_NORMAL) + fmt.UseVertexData |= 2; + fmt.Attrs.push_back(attrs[j]); + } + VertexFormats.push_back(fmt); + return (int)VertexFormats.size() - 1; +} + +VkVertexFormat *VkRenderPassManager::GetVertexFormat(int index) +{ + return &VertexFormats[index]; +} + +VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(int numLayers) +{ + if (PipelineLayouts.size() <= (size_t)numLayers) + PipelineLayouts.resize(numLayers + 1); + + auto &layout = PipelineLayouts[numLayers]; + if (layout) + return layout.get(); + + auto descriptors = fb->GetDescriptorSetManager(); + + PipelineLayoutBuilder builder; + builder.AddSetLayout(descriptors->GetFixedSetLayout()); + builder.AddSetLayout(descriptors->GetHWBufferSetLayout()); + if (numLayers != 0) + builder.AddSetLayout(descriptors->GetTextureSetLayout(numLayers)); + builder.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants)); + builder.DebugName("VkRenderPassManager.PipelineLayout"); + layout = builder.Create(fb->device.get()); + return layout.get(); +} + +VkPPRenderPassSetup* VkRenderPassManager::GetPPRenderPass(const VkPPRenderPassKey& key) +{ + auto& passSetup = PPRenderPassSetup[key]; + if (!passSetup) + passSetup.reset(new VkPPRenderPassSetup(fb, key)); + return passSetup.get(); +} + +///////////////////////////////////////////////////////////////////////////// + +VkRenderPassSetup::VkRenderPassSetup(VulkanRenderDevice* fb, const VkRenderPassKey &key) : PassKey(key), fb(fb) +{ +} + +std::unique_ptr VkRenderPassSetup::CreateRenderPass(int clearTargets) +{ + auto buffers = fb->GetBuffers(); + + VkFormat drawBufferFormats[] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R8G8B8A8_UNORM, buffers->SceneNormalFormat }; + + RenderPassBuilder builder; + + builder.AddAttachment( + PassKey.DrawBufferFormat, (VkSampleCountFlagBits)PassKey.Samples, + (clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + for (int i = 1; i < PassKey.DrawBuffers; i++) + { + builder.AddAttachment( + drawBufferFormats[i], (VkSampleCountFlagBits)PassKey.Samples, + (clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } + if (PassKey.DepthStencil) + { + builder.AddDepthStencilAttachment( + buffers->SceneDepthStencilFormat, (VkSampleCountFlagBits)PassKey.Samples, + (clearTargets & CT_Depth) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + (clearTargets & CT_Stencil) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } + builder.AddSubpass(); + for (int i = 0; i < PassKey.DrawBuffers; i++) + builder.AddSubpassColorAttachmentRef(i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + if (PassKey.DepthStencil) + { + builder.AddSubpassDepthStencilAttachmentRef(PassKey.DrawBuffers, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + builder.AddExternalSubpassDependency( + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); + } + else + { + builder.AddExternalSubpassDependency( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); + } + builder.DebugName("VkRenderPassSetup.RenderPass"); + return builder.Create(fb->device.get()); +} + +VulkanRenderPass *VkRenderPassSetup::GetRenderPass(int clearTargets) +{ + if (!RenderPasses[clearTargets]) + RenderPasses[clearTargets] = CreateRenderPass(clearTargets); + return RenderPasses[clearTargets].get(); +} + +VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key) +{ + auto &item = Pipelines[key]; + if (!item) + item = CreatePipeline(key); + return item.get(); +} + +std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key) +{ + GraphicsPipelineBuilder builder; + builder.Cache(fb->GetRenderPassManager()->GetCache()); + + VkShaderProgram *program; + if (key.SpecialEffect != EFF_NONE) + { + program = fb->GetShaderManager()->GetEffect(key.SpecialEffect, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); + } + else + { + program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); + } + builder.AddVertexShader(program->vert.get()); + builder.AddFragmentShader(program->frag.get()); + + const VkVertexFormat &vfmt = *fb->GetRenderPassManager()->GetVertexFormat(key.VertexFormat); + + for (int i = 0; i < vfmt.NumBindingPoints; i++) + builder.AddVertexBufferBinding(i, vfmt.Stride); + + const static VkFormat vkfmts[] = { + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R32G32B32_SFLOAT, + VK_FORMAT_R32G32_SFLOAT, + VK_FORMAT_R32_SFLOAT, + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_A2B10G10R10_SNORM_PACK32, + VK_FORMAT_R8G8B8A8_UINT + }; + + bool inputLocations[VATTR_MAX] = {}; + + for (size_t i = 0; i < vfmt.Attrs.size(); i++) + { + const auto &attr = vfmt.Attrs[i]; + builder.AddVertexAttribute(attr.location, attr.binding, vkfmts[attr.format], attr.offset); + inputLocations[attr.location] = true; + } + + // Vulkan requires an attribute binding for each location specified in the shader + for (int i = 0; i < VATTR_MAX; i++) + { + if (!inputLocations[i]) + builder.AddVertexAttribute(i, 0, i != 8 ? VK_FORMAT_R32G32B32_SFLOAT : VK_FORMAT_R8G8B8A8_UINT, 0); + } + + builder.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT); + builder.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR); + builder.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS); + builder.AddDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE); + + // Note: the actual values are ignored since we use dynamic viewport+scissor states + builder.Viewport(0.0f, 0.0f, 320.0f, 200.0f); + builder.Scissor(0, 0, 320, 200); + + static const VkPrimitiveTopology vktopology[] = { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP + }; + + static const VkStencilOp op2vk[] = { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_DECREMENT_AND_CLAMP }; + static const VkCompareOp depthfunc2vk[] = { VK_COMPARE_OP_LESS, VK_COMPARE_OP_LESS_OR_EQUAL, VK_COMPARE_OP_ALWAYS }; + + builder.Topology(vktopology[key.DrawType]); + builder.DepthStencilEnable(key.DepthTest, key.DepthWrite, key.StencilTest); + builder.DepthFunc(depthfunc2vk[key.DepthFunc]); + if (fb->device->EnabledFeatures.Features.depthClamp) + builder.DepthClampEnable(key.DepthClamp); + builder.DepthBias(key.DepthBias, 0.0f, 0.0f, 0.0f); + + // Note: CCW and CW is intentionally swapped here because the vulkan and opengl coordinate systems differ. + // main.vp addresses this by patching up gl_Position.z, which has the side effect of flipping the sign of the front face calculations. + builder.Cull(key.CullMode == Cull_None ? VK_CULL_MODE_NONE : VK_CULL_MODE_BACK_BIT, key.CullMode == Cull_CW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE); + + builder.Stencil(VK_STENCIL_OP_KEEP, op2vk[key.StencilPassOp], VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0); + + ColorBlendAttachmentBuilder blendbuilder; + blendbuilder.ColorWriteMask((VkColorComponentFlags)key.ColorMask); + BlendMode(blendbuilder, key.RenderStyle); + + for (int i = 0; i < PassKey.DrawBuffers; i++) + builder.AddColorBlendAttachment(blendbuilder.Create()); + + builder.RasterizationSamples((VkSampleCountFlagBits)PassKey.Samples); + + builder.Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.NumTextureLayers)); + builder.RenderPass(GetRenderPass(0)); + builder.DebugName("VkRenderPassSetup.Pipeline"); + + return builder.Create(fb->device.get()); +} + +///////////////////////////////////////////////////////////////////////////// + +VkPPRenderPassSetup::VkPPRenderPassSetup(VulkanRenderDevice* fb, const VkPPRenderPassKey& key) : fb(fb) +{ + CreateDescriptorLayout(key); + CreatePipelineLayout(key); + CreateRenderPass(key); + CreatePipeline(key); +} + +void VkPPRenderPassSetup::CreateDescriptorLayout(const VkPPRenderPassKey& key) +{ + DescriptorSetLayoutBuilder builder; + for (int i = 0; i < key.InputTextures; i++) + builder.AddBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + if (key.ShadowMapBuffers) + { + builder.AddBinding(LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + } + builder.DebugName("VkPPRenderPassSetup.DescriptorLayout"); + DescriptorLayout = builder.Create(fb->device.get()); +} + +void VkPPRenderPassSetup::CreatePipelineLayout(const VkPPRenderPassKey& key) +{ + PipelineLayoutBuilder builder; + builder.AddSetLayout(DescriptorLayout.get()); + if (key.Uniforms > 0) + builder.AddPushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0, key.Uniforms); + builder.DebugName("VkPPRenderPassSetup.PipelineLayout"); + PipelineLayout = builder.Create(fb->device.get()); +} + +void VkPPRenderPassSetup::CreatePipeline(const VkPPRenderPassKey& key) +{ + GraphicsPipelineBuilder builder; + builder.Cache(fb->GetRenderPassManager()->GetCache()); + builder.AddVertexShader(key.Shader->VertexShader.get()); + builder.AddFragmentShader(key.Shader->FragmentShader.get()); + + builder.AddVertexBufferBinding(0, sizeof(FFlatVertex)); + builder.AddVertexAttribute(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(FFlatVertex, x)); + builder.AddVertexAttribute(1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(FFlatVertex, u)); + builder.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT); + builder.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR); + // Note: the actual values are ignored since we use dynamic viewport+scissor states + builder.Viewport(0.0f, 0.0f, 320.0f, 200.0f); + builder.Scissor(0, 0, 320, 200); + if (key.StencilTest != WhichDepthStencil::None) + { + builder.AddDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE); + builder.DepthStencilEnable(false, false, true); + builder.Stencil(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0); + } + builder.Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); + + ColorBlendAttachmentBuilder blendbuilder; + BlendMode(blendbuilder, key.BlendMode); + builder.AddColorBlendAttachment(blendbuilder.Create()); + + builder.RasterizationSamples(key.Samples); + builder.Layout(PipelineLayout.get()); + builder.RenderPass(RenderPass.get()); + builder.DebugName("VkPPRenderPassSetup.Pipeline"); + Pipeline = builder.Create(fb->device.get()); +} + +void VkPPRenderPassSetup::CreateRenderPass(const VkPPRenderPassKey& key) +{ + RenderPassBuilder builder; + if (key.SwapChain) + builder.AddAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + else + builder.AddAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + if (key.StencilTest == WhichDepthStencil::Scene) + { + builder.AddDepthStencilAttachment( + fb->GetBuffers()->SceneDepthStencilFormat, key.Samples, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } + if (key.StencilTest == WhichDepthStencil::Pipeline) + { + builder.AddDepthStencilAttachment( + fb->GetBuffers()->PipelineDepthStencilFormat, key.Samples, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } + + builder.AddSubpass(); + builder.AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + if (key.StencilTest != WhichDepthStencil::None) + { + builder.AddSubpassDepthStencilAttachmentRef(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + builder.AddExternalSubpassDependency( + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT); + } + else + { + builder.AddExternalSubpassDependency( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT); + } + + builder.DebugName("VkPPRenderPassSetup.RenderPass"); + RenderPass = builder.Create(fb->device.get()); +} + +///////////////////////////////////////////////////////////////////////////// + +ColorBlendAttachmentBuilder& BlendMode(ColorBlendAttachmentBuilder& builder, const FRenderStyle& style) +{ + // Just in case Vulkan doesn't do this optimization itself + if (style.BlendOp == STYLEOP_Add && style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero && style.Flags == 0) + { + return builder; + } + + static const int blendstyles[] = { + VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_SRC_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_FACTOR_SRC_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, + VK_BLEND_FACTOR_DST_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, + VK_BLEND_FACTOR_DST_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, + }; + + static const int renderops[] = { + 0, VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + int srcblend = blendstyles[style.SrcAlpha % STYLEALPHA_MAX]; + int dstblend = blendstyles[style.DestAlpha % STYLEALPHA_MAX]; + int blendequation = renderops[style.BlendOp & 15]; + + if (blendequation == -1) // This was a fuzz style. + { + srcblend = VK_BLEND_FACTOR_DST_COLOR; + dstblend = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendequation = VK_BLEND_OP_ADD; + } + + return builder.BlendMode((VkBlendOp)blendequation, (VkBlendFactor)srcblend, (VkBlendFactor)dstblend); +} diff --git a/src/common/rendering/vulkan/renderer/vk_renderpass.h b/src/common/rendering/vulkan/renderer/vk_renderpass.h new file mode 100644 index 00000000000..a1f8ca39f6a --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_renderpass.h @@ -0,0 +1,152 @@ + +#pragma once + +#include "zvulkan/vulkanobjects.h" +#include "renderstyle.h" +#include "hwrenderer/data/buffers.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "hw_renderstate.h" +#include +#include + +class VulkanRenderDevice; +class VkPPShader; +class GraphicsPipelineBuilder; +class ColorBlendAttachmentBuilder; + +class VkPipelineKey +{ +public: + FRenderStyle RenderStyle; + int SpecialEffect; + int EffectState; + int AlphaTest; + int DepthWrite; + int DepthTest; + int DepthFunc; + int DepthClamp; + int DepthBias; + int StencilTest; + int StencilPassOp; + int ColorMask; + int CullMode; + int VertexFormat; + int DrawType; + int NumTextureLayers; + + bool operator<(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) < 0; } + bool operator==(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) == 0; } + bool operator!=(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) != 0; } +}; + +class VkRenderPassKey +{ +public: + int DepthStencil; + int Samples; + int DrawBuffers; + VkFormat DrawBufferFormat; + + bool operator<(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) < 0; } + bool operator==(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) == 0; } + bool operator!=(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) != 0; } +}; + +class VkRenderPassSetup +{ +public: + VkRenderPassSetup(VulkanRenderDevice* fb, const VkRenderPassKey &key); + + VulkanRenderPass *GetRenderPass(int clearTargets); + VulkanPipeline *GetPipeline(const VkPipelineKey &key); + + VkRenderPassKey PassKey; + std::unique_ptr RenderPasses[8]; + std::map> Pipelines; + +private: + std::unique_ptr CreateRenderPass(int clearTargets); + std::unique_ptr CreatePipeline(const VkPipelineKey &key); + + VulkanRenderDevice* fb = nullptr; +}; + +class VkVertexFormat +{ +public: + int NumBindingPoints; + size_t Stride; + std::vector Attrs; + int UseVertexData; +}; + +enum class WhichDepthStencil; + +class VkPPRenderPassKey +{ +public: + VkPPShader* Shader; + int Uniforms; + int InputTextures; + PPBlendMode BlendMode; + VkFormat OutputFormat; + int SwapChain; + int ShadowMapBuffers; + WhichDepthStencil StencilTest; + VkSampleCountFlagBits Samples; + + bool operator<(const VkPPRenderPassKey& other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) < 0; } + bool operator==(const VkPPRenderPassKey& other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) == 0; } + bool operator!=(const VkPPRenderPassKey& other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) != 0; } +}; + +class VkPPRenderPassSetup +{ +public: + VkPPRenderPassSetup(VulkanRenderDevice* fb, const VkPPRenderPassKey& key); + + std::unique_ptr DescriptorLayout; + std::unique_ptr PipelineLayout; + std::unique_ptr RenderPass; + std::unique_ptr Pipeline; + +private: + void CreateDescriptorLayout(const VkPPRenderPassKey& key); + void CreatePipelineLayout(const VkPPRenderPassKey& key); + void CreatePipeline(const VkPPRenderPassKey& key); + void CreateRenderPass(const VkPPRenderPassKey& key); + + VulkanRenderDevice* fb = nullptr; +}; + +ColorBlendAttachmentBuilder& BlendMode(ColorBlendAttachmentBuilder& builder, const FRenderStyle& style); + +class VkRenderPassManager +{ +public: + VkRenderPassManager(VulkanRenderDevice* fb); + ~VkRenderPassManager(); + + void RenderBuffersReset(); + + VkRenderPassSetup *GetRenderPass(const VkRenderPassKey &key); + int GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs); + VkVertexFormat *GetVertexFormat(int index); + VulkanPipelineLayout* GetPipelineLayout(int numLayers); + + VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key); + + VulkanPipelineCache* GetCache() { return PipelineCache.get(); } + +private: + VulkanRenderDevice* fb = nullptr; + + std::map> RenderPassSetup; + std::vector> PipelineLayouts; + std::vector VertexFormats; + + std::map> PPRenderPassSetup; + + FString CacheFilename; + std::unique_ptr PipelineCache; +}; diff --git a/src/rendering/vulkan/renderer/vk_renderstate.cpp b/src/common/rendering/vulkan/renderer/vk_renderstate.cpp similarity index 77% rename from src/rendering/vulkan/renderer/vk_renderstate.cpp rename to src/common/rendering/vulkan/renderer/vk_renderstate.cpp index abf2ba12a6a..76bd35cb09b 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/renderer/vk_renderstate.cpp @@ -21,26 +21,28 @@ */ #include "vk_renderstate.h" -#include "vulkan/system/vk_framebuffer.h" -#include "vulkan/system/vk_builders.h" +#include "vulkan/system/vk_renderdevice.h" +#include "zvulkan/vulkanbuilders.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "vulkan/system/vk_buffer.h" #include "vulkan/renderer/vk_renderpass.h" -#include "vulkan/renderer/vk_renderbuffers.h" +#include "vulkan/renderer/vk_descriptorset.h" +#include "vulkan/textures/vk_renderbuffers.h" #include "vulkan/textures/vk_hwtexture.h" -#include "templates.h" -#include "doomstat.h" -#include "r_data/colormaps.h" -#include "hwrenderer/scene/hw_skydome.h" -#include "hwrenderer/scene/hw_viewpointuniforms.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/data/flatvertices.h" + +#include "hw_skydome.h" +#include "hw_viewpointuniforms.h" +#include "hw_lightbuffer.h" +#include "hw_cvars.h" +#include "hw_clock.h" +#include "flatvertices.h" #include "hwrenderer/data/hw_viewpointbuffer.h" #include "hwrenderer/data/shaderuniforms.h" CVAR(Int, vk_submit_size, 1000, 0); +EXTERN_CVAR(Bool, r_skipmats) -VkRenderState::VkRenderState() +VkRenderState::VkRenderState(VulkanRenderDevice* fb) : fb(fb), mStreamBufferWriter(fb), mMatrixBufferWriter(fb) { Reset(); } @@ -183,7 +185,7 @@ void VkRenderState::Apply(int dt) mApplyCount++; if (mApplyCount >= vk_submit_size) { - GetVulkanFrameBuffer()->FlushCommands(false); + fb->GetCommands()->FlushCommands(false); mApplyCount = 0; } @@ -196,7 +198,7 @@ void VkRenderState::Apply(int dt) ApplyDepthBias(); ApplyPushConstants(); ApplyVertexBuffers(); - ApplyDynamicSet(); + ApplyHWBufferSet(); ApplyMaterial(); mNeedApply = false; @@ -217,7 +219,7 @@ void VkRenderState::ApplyRenderPass(int dt) // Find a pipeline that matches our state VkPipelineKey pipelineKey; pipelineKey.DrawType = dt; - pipelineKey.VertexFormat = static_cast(mVertexBuffer)->VertexFormat; + pipelineKey.VertexFormat = static_cast(mVertexBuffer)->VertexFormat; pipelineKey.RenderStyle = mRenderStyle; pipelineKey.DepthTest = mDepthTest; pipelineKey.DepthWrite = mDepthTest && mDepthWrite; @@ -228,7 +230,8 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.StencilPassOp = mStencilOp; pipelineKey.ColorMask = mColorMask; pipelineKey.CullMode = mCullMode; - pipelineKey.NumTextureLayers = mMaterial.mMaterial ? mMaterial.mMaterial->GetLayers() : 1; // Always force minimum 1 texture as the shader requires it + pipelineKey.NumTextureLayers = mMaterial.mMaterial ? mMaterial.mMaterial->NumLayers() : 0; + pipelineKey.NumTextureLayers = max(pipelineKey.NumTextureLayers, SHADER_MIN_REQUIRED_TEXTURE_LAYERS);// Always force minimum 8 textures as the shader requires it if (mSpecialEffect > EFF_NONE) { pipelineKey.SpecialEffect = mSpecialEffect; @@ -240,6 +243,8 @@ void VkRenderState::ApplyRenderPass(int dt) int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0); pipelineKey.SpecialEffect = EFF_NONE; pipelineKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture; + if (r_skipmats && pipelineKey.EffectState >= 3 && pipelineKey.EffectState <= 4) + pipelineKey.EffectState = 0; pipelineKey.AlphaTest = mAlphaThreshold >= 0.f; } @@ -249,7 +254,7 @@ void VkRenderState::ApplyRenderPass(int dt) if (!inRenderPass) { - mCommandBuffer = GetVulkanFrameBuffer()->GetDrawCommands(); + mCommandBuffer = fb->GetCommands()->GetDrawCommands(); mScissorChanged = true; mViewportChanged = true; mStencilRefChanged = true; @@ -331,13 +336,12 @@ void VkRenderState::ApplyViewport() void VkRenderState::ApplyStreamData() { - auto fb = GetVulkanFrameBuffer(); auto passManager = fb->GetRenderPassManager(); - mStreamData.useVertexData = passManager->GetVertexFormat(static_cast(mVertexBuffer)->VertexFormat)->UseVertexData; + mStreamData.useVertexData = passManager->GetVertexFormat(static_cast(mVertexBuffer)->VertexFormat)->UseVertexData; - if (mMaterial.mMaterial && mMaterial.mMaterial->tex) - mStreamData.timer = static_cast((double)(screen->FrameTime - firstFrame) * (double)mMaterial.mMaterial->tex->shaderspeed / 1000.); + if (mMaterial.mMaterial && mMaterial.mMaterial->Source()) + mStreamData.timer = static_cast((double)(screen->FrameTime - firstFrame) * (double)mMaterial.mMaterial->Source()->GetShaderSpeed() / 1000.); else mStreamData.timer = 0.0f; @@ -368,11 +372,11 @@ void VkRenderState::ApplyPushConstants() } int tempTM = TM_NORMAL; - if (mMaterial.mMaterial && mMaterial.mMaterial->tex && mMaterial.mMaterial->tex->isHardwareCanvas()) + if (mMaterial.mMaterial && mMaterial.mMaterial->Source()->isHardwareCanvas()) tempTM = TM_OPAQUE; mPushConstants.uFogEnabled = fogset; - mPushConstants.uTextureMode = mTextureMode == TM_NORMAL && tempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode; + mPushConstants.uTextureMode = GetTextureModeAndFlags(tempTM); mPushConstants.uLightDist = mLightParms[0]; mPushConstants.uLightFactor = mLightParms[1]; mPushConstants.uFogDensity = mLightParms[2]; @@ -380,13 +384,16 @@ void VkRenderState::ApplyPushConstants() mPushConstants.uAlphaThreshold = mAlphaThreshold; mPushConstants.uClipSplit = { mClipSplit[0], mClipSplit[1] }; - if (mMaterial.mMaterial && mMaterial.mMaterial->tex) - mPushConstants.uSpecularMaterial = { mMaterial.mMaterial->tex->Glossiness, mMaterial.mMaterial->tex->SpecularLevel }; + if (mMaterial.mMaterial) + { + auto source = mMaterial.mMaterial->Source(); + mPushConstants.uSpecularMaterial = { source->GetGlossiness(), source->GetSpecularLevel() }; + } mPushConstants.uLightIndex = mLightIndex; + mPushConstants.uBoneIndexBase = mBoneIndexBase; mPushConstants.uDataIndex = mStreamBufferWriter.DataIndex(); - auto fb = GetVulkanFrameBuffer(); auto passManager = fb->GetRenderPassManager(); mCommandBuffer->pushConstants(passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants); } @@ -404,8 +411,8 @@ void VkRenderState::ApplyVertexBuffers() { if ((mVertexBuffer != mLastVertexBuffer || mVertexOffsets[0] != mLastVertexOffsets[0] || mVertexOffsets[1] != mLastVertexOffsets[1]) && mVertexBuffer) { - auto vkbuf = static_cast(mVertexBuffer); - const VkVertexFormat *format = GetVulkanFrameBuffer()->GetRenderPassManager()->GetVertexFormat(vkbuf->VertexFormat); + auto vkbuf = static_cast(mVertexBuffer); + const VkVertexFormat *format = fb->GetRenderPassManager()->GetVertexFormat(vkbuf->VertexFormat); VkBuffer vertexBuffers[2] = { vkbuf->mBuffer->buffer, vkbuf->mBuffer->buffer }; VkDeviceSize offsets[] = { mVertexOffsets[0] * format->Stride, mVertexOffsets[1] * format->Stride }; mCommandBuffer->bindVertexBuffers(0, 2, vertexBuffers, offsets); @@ -416,7 +423,7 @@ void VkRenderState::ApplyVertexBuffers() if (mIndexBuffer != mLastIndexBuffer && mIndexBuffer) { - mCommandBuffer->bindIndexBuffer(static_cast(mIndexBuffer)->mBuffer->buffer, 0, VK_INDEX_TYPE_UINT32); + mCommandBuffer->bindIndexBuffer(static_cast(mIndexBuffer)->mBuffer->buffer, 0, VK_INDEX_TYPE_UINT32); mLastIndexBuffer = mIndexBuffer; } } @@ -425,28 +432,31 @@ void VkRenderState::ApplyMaterial() { if (mMaterial.mChanged) { - auto fb = GetVulkanFrameBuffer(); auto passManager = fb->GetRenderPassManager(); + auto descriptors = fb->GetDescriptorSetManager(); - VkHardwareTexture* base = mMaterial.mMaterial ? static_cast(mMaterial.mMaterial->GetLayer(0, mMaterial.mTranslation)) : nullptr; - VulkanDescriptorSet* descriptorset = base ? base->GetDescriptorSet(mMaterial) : passManager->GetNullTextureDescriptorSet(); + if (mMaterial.mMaterial && mMaterial.mMaterial->Source()->isHardwareCanvas()) static_cast(mMaterial.mMaterial->Source()->GetTexture())->NeedUpdate(); - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, descriptorset); + VulkanDescriptorSet* descriptorset = mMaterial.mMaterial ? static_cast(mMaterial.mMaterial)->GetDescriptorSet(mMaterial) : descriptors->GetNullTextureDescriptorSet(); + + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, fb->GetDescriptorSetManager()->GetFixedDescriptorSet()); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 2, descriptorset); mMaterial.mChanged = false; } } -void VkRenderState::ApplyDynamicSet() +void VkRenderState::ApplyHWBufferSet() { - auto fb = GetVulkanFrameBuffer(); uint32_t matrixOffset = mMatrixBufferWriter.Offset(); uint32_t streamDataOffset = mStreamBufferWriter.StreamDataOffset(); if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || streamDataOffset != mLastStreamDataOffset) { auto passManager = fb->GetRenderPassManager(); + auto descriptors = fb->GetDescriptorSetManager(); uint32_t offsets[3] = { mViewpointOffset, matrixOffset, streamDataOffset }; - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, passManager->DynamicSet.get(), 3, offsets); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, fb->GetDescriptorSetManager()->GetFixedDescriptorSet()); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, descriptors->GetHWBufferDescriptorSet(), 3, offsets); mLastViewpointOffset = mViewpointOffset; mLastMatricesOffset = matrixOffset; @@ -456,7 +466,7 @@ void VkRenderState::ApplyDynamicSet() void VkRenderState::WaitForStreamBuffers() { - GetVulkanFrameBuffer()->WaitForCommands(false); + fb->WaitForCommands(false); mApplyCount = 0; mStreamBufferWriter.Reset(); mMatrixBufferWriter.Reset(); @@ -499,7 +509,7 @@ void VkRenderState::EndFrame() mStreamBufferWriter.Reset(); } -void VkRenderState::EnableDrawBuffers(int count) +void VkRenderState::EnableDrawBuffers(int count, bool apply) { if (mRenderTarget.DrawBuffers != count) { @@ -522,8 +532,6 @@ void VkRenderState::SetRenderTarget(VkTextureImage *image, VulkanImageView *dept void VkRenderState::BeginRenderPass(VulkanCommandBuffer *cmdbuffer) { - auto fb = GetVulkanFrameBuffer(); - VkRenderPassKey key = {}; key.DrawBufferFormat = mRenderTarget.Format; key.Samples = mRenderTarget.Samples; @@ -537,17 +545,17 @@ void VkRenderState::BeginRenderPass(VulkanCommandBuffer *cmdbuffer) { auto buffers = fb->GetBuffers(); FramebufferBuilder builder; - builder.setRenderPass(mPassSetup->GetRenderPass(0)); - builder.setSize(mRenderTarget.Width, mRenderTarget.Height); - builder.addAttachment(mRenderTarget.Image->View.get()); + builder.RenderPass(mPassSetup->GetRenderPass(0)); + builder.Size(mRenderTarget.Width, mRenderTarget.Height); + builder.AddAttachment(mRenderTarget.Image->View.get()); if (key.DrawBuffers > 1) - builder.addAttachment(buffers->SceneFog.View.get()); + builder.AddAttachment(buffers->SceneFog.View.get()); if (key.DrawBuffers > 2) - builder.addAttachment(buffers->SceneNormal.View.get()); + builder.AddAttachment(buffers->SceneNormal.View.get()); if (key.DepthStencil) - builder.addAttachment(mRenderTarget.DepthStencil); - framebuffer = builder.create(GetVulkanFrameBuffer()->device); - framebuffer->SetDebugName("VkRenderPassSetup.Framebuffer"); + builder.AddAttachment(mRenderTarget.DepthStencil); + builder.DebugName("VkRenderPassSetup.Framebuffer"); + framebuffer = builder.Create(fb->device.get()); } // Only clear depth+stencil if the render target actually has that @@ -555,16 +563,16 @@ void VkRenderState::BeginRenderPass(VulkanCommandBuffer *cmdbuffer) mClearTargets &= ~(CT_Depth | CT_Stencil); RenderPassBegin beginInfo; - beginInfo.setRenderPass(mPassSetup->GetRenderPass(mClearTargets)); - beginInfo.setRenderArea(0, 0, mRenderTarget.Width, mRenderTarget.Height); - beginInfo.setFramebuffer(framebuffer.get()); - beginInfo.addClearColor(screen->mSceneClearColor[0], screen->mSceneClearColor[1], screen->mSceneClearColor[2], screen->mSceneClearColor[3]); + beginInfo.RenderPass(mPassSetup->GetRenderPass(mClearTargets)); + beginInfo.RenderArea(0, 0, mRenderTarget.Width, mRenderTarget.Height); + beginInfo.Framebuffer(framebuffer.get()); + beginInfo.AddClearColor(screen->mSceneClearColor[0], screen->mSceneClearColor[1], screen->mSceneClearColor[2], screen->mSceneClearColor[3]); if (key.DrawBuffers > 1) - beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 0.0f); + beginInfo.AddClearColor(0.0f, 0.0f, 0.0f, 0.0f); if (key.DrawBuffers > 2) - beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 0.0f); - beginInfo.addClearDepthStencil(1.0f, 0); - cmdbuffer->beginRenderPass(beginInfo); + beginInfo.AddClearColor(0.0f, 0.0f, 0.0f, 0.0f); + beginInfo.AddClearDepthStencil(1.0f, 0); + beginInfo.Execute(cmdbuffer); mMaterial.mChanged = true; mClearTargets = 0; @@ -577,7 +585,7 @@ void VkRenderStateMolten::Draw(int dt, int index, int count, bool apply) if (dt == DT_TriangleFan) { IIndexBuffer *oldIndexBuffer = mIndexBuffer; - mIndexBuffer = GetVulkanFrameBuffer()->FanToTrisIndexBuffer.get(); + mIndexBuffer = fb->GetBufferManager()->FanToTrisIndexBuffer.get(); if (apply || mNeedApply) Apply(DT_Triangles); diff --git a/src/rendering/vulkan/renderer/vk_renderstate.h b/src/common/rendering/vulkan/renderer/vk_renderstate.h similarity index 92% rename from src/rendering/vulkan/renderer/vk_renderstate.h rename to src/common/rendering/vulkan/renderer/vk_renderstate.h index 73c777eb08c..cc2e0d90812 100644 --- a/src/rendering/vulkan/renderer/vk_renderstate.h +++ b/src/common/rendering/vulkan/renderer/vk_renderstate.h @@ -1,24 +1,24 @@ #pragma once -#include "vulkan/system/vk_buffers.h" +#include "vulkan/system/vk_hwbuffer.h" #include "vulkan/shaders/vk_shader.h" #include "vulkan/renderer/vk_renderpass.h" #include "vulkan/renderer/vk_streambuffer.h" #include "name.h" -#include "hwrenderer/scene/hw_drawstructs.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_renderstate.h" +#include "hw_material.h" +class VulkanRenderDevice; class VkRenderPassSetup; class VkTextureImage; class VkRenderState : public FRenderState { public: - VkRenderState(); + VkRenderState(VulkanRenderDevice* fb); virtual ~VkRenderState() = default; // Draw commands @@ -42,7 +42,7 @@ class VkRenderState : public FRenderState void EnableDepthTest(bool on) override; void EnableMultisampling(bool on) override; void EnableLineSmooth(bool on) override; - void EnableDrawBuffers(int count) override; + void EnableDrawBuffers(int count, bool apply) override; void BeginFrame(); void SetRenderTarget(VkTextureImage *image, VulkanImageView *depthStencilView, int width, int height, VkFormat Format, VkSampleCountFlagBits samples); @@ -60,13 +60,15 @@ class VkRenderState : public FRenderState void ApplyStreamData(); void ApplyMatrices(); void ApplyPushConstants(); - void ApplyDynamicSet(); + void ApplyHWBufferSet(); void ApplyVertexBuffers(); void ApplyMaterial(); void BeginRenderPass(VulkanCommandBuffer *cmdbuffer); void WaitForStreamBuffers(); + VulkanRenderDevice* fb = nullptr; + bool mDepthClamp = true; VulkanCommandBuffer *mCommandBuffer = nullptr; VkPipelineKey mPipelineKey = {}; diff --git a/src/common/rendering/vulkan/renderer/vk_streambuffer.cpp b/src/common/rendering/vulkan/renderer/vk_streambuffer.cpp new file mode 100644 index 00000000000..0db0fb71a50 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_streambuffer.cpp @@ -0,0 +1,123 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_renderstate.h" +#include "vulkan/system/vk_renderdevice.h" +#include "zvulkan/vulkanbuilders.h" +#include "vulkan/system/vk_buffer.h" +#include "vulkan/renderer/vk_streambuffer.h" + +VkStreamBufferWriter::VkStreamBufferWriter(VulkanRenderDevice* fb) +{ + mBuffer = fb->GetBufferManager()->StreamBuffer.get(); +} + +bool VkStreamBufferWriter::Write(const StreamData& data) +{ + mDataIndex++; + if (mDataIndex == MAX_STREAM_DATA) + { + mDataIndex = 0; + mStreamDataOffset = mBuffer->NextStreamDataBlock(); + if (mStreamDataOffset == 0xffffffff) + return false; + } + uint8_t* ptr = (uint8_t*)mBuffer->UniformBuffer->Memory(); + memcpy(ptr + mStreamDataOffset + sizeof(StreamData) * mDataIndex, &data, sizeof(StreamData)); + return true; +} + +void VkStreamBufferWriter::Reset() +{ + mDataIndex = MAX_STREAM_DATA - 1; + mStreamDataOffset = 0; + mBuffer->Reset(); +} + +///////////////////////////////////////////////////////////////////////////// + +VkMatrixBufferWriter::VkMatrixBufferWriter(VulkanRenderDevice* fb) +{ + mBuffer = fb->GetBufferManager()->MatrixBuffer.get(); + mIdentityMatrix.loadIdentity(); +} + +template +static void BufferedSet(bool& modified, T& dst, const T& src) +{ + if (dst == src) + return; + dst = src; + modified = true; +} + +static void BufferedSet(bool& modified, VSMatrix& dst, const VSMatrix& src) +{ + if (memcmp(dst.get(), src.get(), sizeof(FLOATTYPE) * 16) == 0) + return; + dst = src; + modified = true; +} + +bool VkMatrixBufferWriter::Write(const VSMatrix& modelMatrix, bool modelMatrixEnabled, const VSMatrix& textureMatrix, bool textureMatrixEnabled) +{ + bool modified = (mOffset == 0); // always modified first call + + if (modelMatrixEnabled) + { + BufferedSet(modified, mMatrices.ModelMatrix, modelMatrix); + if (modified) + mMatrices.NormalModelMatrix.computeNormalMatrix(modelMatrix); + } + else + { + BufferedSet(modified, mMatrices.ModelMatrix, mIdentityMatrix); + BufferedSet(modified, mMatrices.NormalModelMatrix, mIdentityMatrix); + } + + if (textureMatrixEnabled) + { + BufferedSet(modified, mMatrices.TextureMatrix, textureMatrix); + } + else + { + BufferedSet(modified, mMatrices.TextureMatrix, mIdentityMatrix); + } + + if (modified) + { + mOffset = mBuffer->NextStreamDataBlock(); + if (mOffset == 0xffffffff) + return false; + + uint8_t* ptr = (uint8_t*)mBuffer->UniformBuffer->Memory(); + memcpy(ptr + mOffset, &mMatrices, sizeof(MatricesUBO)); + } + + return true; +} + +void VkMatrixBufferWriter::Reset() +{ + mOffset = 0; + mBuffer->Reset(); +} diff --git a/src/common/rendering/vulkan/renderer/vk_streambuffer.h b/src/common/rendering/vulkan/renderer/vk_streambuffer.h new file mode 100644 index 00000000000..3bae01fb1bc --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_streambuffer.h @@ -0,0 +1,42 @@ + +#pragma once + +#include "vulkan/system/vk_hwbuffer.h" +#include "vulkan/shaders/vk_shader.h" + +class VkStreamBuffer; +class VkMatrixBuffer; + +class VkStreamBufferWriter +{ +public: + VkStreamBufferWriter(VulkanRenderDevice* fb); + + bool Write(const StreamData& data); + void Reset(); + + uint32_t DataIndex() const { return mDataIndex; } + uint32_t StreamDataOffset() const { return mStreamDataOffset; } + +private: + VkStreamBuffer* mBuffer; + uint32_t mDataIndex = MAX_STREAM_DATA - 1; + uint32_t mStreamDataOffset = 0; +}; + +class VkMatrixBufferWriter +{ +public: + VkMatrixBufferWriter(VulkanRenderDevice* fb); + + bool Write(const VSMatrix& modelMatrix, bool modelMatrixEnabled, const VSMatrix& textureMatrix, bool textureMatrixEnabled); + void Reset(); + + uint32_t Offset() const { return mOffset; } + +private: + VkStreamBuffer* mBuffer; + MatricesUBO mMatrices = {}; + VSMatrix mIdentityMatrix; + uint32_t mOffset = 0; +}; diff --git a/src/common/rendering/vulkan/shaders/vk_ppshader.cpp b/src/common/rendering/vulkan/shaders/vk_ppshader.cpp new file mode 100644 index 00000000000..dcf72a06d2f --- /dev/null +++ b/src/common/rendering/vulkan/shaders/vk_ppshader.cpp @@ -0,0 +1,80 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_ppshader.h" +#include "vk_shader.h" +#include "vulkan/system/vk_renderdevice.h" +#include "zvulkan/vulkanbuilders.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "filesystem.h" +#include "cmdlib.h" + +VkPPShader::VkPPShader(VulkanRenderDevice* fb, PPShader *shader) : fb(fb) +{ + FString prolog; + if (!shader->Uniforms.empty()) + prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, -1); + prolog += shader->Defines; + + VertexShader = ShaderBuilder() + .Type(ShaderType::Vertex) + .AddSource(shader->VertexShader.GetChars(), LoadShaderCode(shader->VertexShader, "", shader->Version).GetChars()) + .DebugName(shader->VertexShader.GetChars()) + .Create(shader->VertexShader.GetChars(), fb->device.get()); + + FragmentShader = ShaderBuilder() + .Type(ShaderType::Fragment) + .AddSource(shader->FragmentShader.GetChars(), LoadShaderCode(shader->FragmentShader, prolog, shader->Version).GetChars()) + .DebugName(shader->FragmentShader.GetChars()) + .Create(shader->FragmentShader.GetChars(), fb->device.get()); + + fb->GetShaderManager()->AddVkPPShader(this); +} + +VkPPShader::~VkPPShader() +{ + if (fb) + fb->GetShaderManager()->RemoveVkPPShader(this); +} + +void VkPPShader::Reset() +{ + if (fb) + { + fb->GetCommands()->DrawDeleteList->Add(std::move(VertexShader)); + fb->GetCommands()->DrawDeleteList->Add(std::move(FragmentShader)); + } +} + +FString VkPPShader::LoadShaderCode(const FString &lumpName, const FString &defines, int version) +{ + int lump = fileSystem.CheckNumForFullName(lumpName.GetChars()); + if (lump == -1) I_FatalError("Unable to load '%s'", lumpName.GetChars()); + FString code = GetStringFromLump(lump); + + FString patchedCode; + patchedCode.AppendFormat("#version %d\n", 450); + patchedCode << defines; + patchedCode << "#line 1\n"; + patchedCode << code; + return patchedCode; +} diff --git a/src/common/rendering/vulkan/shaders/vk_ppshader.h b/src/common/rendering/vulkan/shaders/vk_ppshader.h new file mode 100644 index 00000000000..6bb5ce47503 --- /dev/null +++ b/src/common/rendering/vulkan/shaders/vk_ppshader.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include +#include + +class VulkanRenderDevice; + +class VkPPShader : public PPShaderBackend +{ +public: + VkPPShader(VulkanRenderDevice* fb, PPShader *shader); + ~VkPPShader(); + + void Reset(); + + VulkanRenderDevice* fb = nullptr; + std::list::iterator it; + + std::unique_ptr VertexShader; + std::unique_ptr FragmentShader; + +private: + FString LoadShaderCode(const FString &lumpname, const FString &defines, int version); +}; diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp new file mode 100644 index 00000000000..00734ac7f30 --- /dev/null +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -0,0 +1,498 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_shader.h" +#include "vk_ppshader.h" +#include "zvulkan/vulkanbuilders.h" +#include "vulkan/system/vk_renderdevice.h" +#include "hw_shaderpatcher.h" +#include "filesystem.h" +#include "engineerrors.h" +#include "version.h" +#include "cmdlib.h" + +bool VkShaderManager::CompileNextShader() +{ + const char *mainvp = "shaders/glsl/main.vp"; + const char *mainfp = "shaders/glsl/main.fp"; + int i = compileIndex; + + if (compileState == 0) + { + // regular material shaders + + VkShaderProgram prog; + prog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines); + prog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, compilePass == GBUFFER_PASS); + mMaterialShaders[compilePass].push_back(std::move(prog)); + + compileIndex++; + if (defaultshaders[compileIndex].ShaderName == nullptr) + { + compileIndex = 0; + compileState++; + } + } + else if (compileState == 1) + { + // NAT material shaders + + VkShaderProgram natprog; + natprog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines); + natprog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, compilePass == GBUFFER_PASS); + mMaterialShadersNAT[compilePass].push_back(std::move(natprog)); + + compileIndex++; + if (compileIndex == SHADER_NoTexture) + { + compileIndex = 0; + compileState++; + if (usershaders.Size() == 0) compileState++; + } + } + else if (compileState == 2) + { + // user shaders + + const FString& name = ExtractFileBase(usershaders[i].shader.GetChars()); + FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines; + + VkShaderProgram prog; + prog.vert = LoadVertShader(name, mainvp, defines.GetChars()); + prog.frag = LoadFragShader(name, mainfp, usershaders[i].shader.GetChars(), defaultshaders[usershaders[i].shaderType].lightfunc, defines.GetChars(), true, compilePass == GBUFFER_PASS); + mMaterialShaders[compilePass].push_back(std::move(prog)); + + compileIndex++; + if (compileIndex >= (int)usershaders.Size()) + { + compileIndex = 0; + compileState++; + } + } + else if (compileState == 3) + { + // Effect shaders + + VkShaderProgram prog; + prog.vert = LoadVertShader(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].defines); + prog.frag = LoadFragShader(effectshaders[i].ShaderName, effectshaders[i].fp1, effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines, true, compilePass == GBUFFER_PASS); + mEffectShaders[compilePass].push_back(std::move(prog)); + + compileIndex++; + if (compileIndex >= MAX_EFFECTS) + { + compileIndex = 0; + compilePass++; + if (compilePass == MAX_PASS_TYPES) + { + compileIndex = -1; // we're done. + return true; + } + compileState = 0; + } + } + return false; +} + +VkShaderManager::VkShaderManager(VulkanRenderDevice* fb) : fb(fb) +{ + //CompileNextShader(); +} + +VkShaderManager::~VkShaderManager() +{ +} + +void VkShaderManager::Deinit() +{ + while (!PPShaders.empty()) + RemoveVkPPShader(PPShaders.back()); +} + +VkShaderProgram *VkShaderManager::GetEffect(int effect, EPassType passType) +{ + if (compileIndex == -1 && effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[passType][effect].frag) + { + return &mEffectShaders[passType][effect]; + } + return nullptr; +} + +VkShaderProgram *VkShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) +{ + if (compileIndex != -1) + return &mMaterialShaders[0][0]; + // indices 0-2 match the warping modes, 3 no texture, the following are custom + if (!alphateston && eff < SHADER_NoTexture) + { + return &mMaterialShadersNAT[passType][eff]; // Non-alphatest shaders are only created for default, warp1+2. The rest won't get used anyway + } + else if (eff < (unsigned int)mMaterialShaders[passType].size()) + { + return &mMaterialShaders[passType][eff]; + } + return nullptr; +} + +static const char *shaderBindings = R"( + + layout(set = 0, binding = 0) uniform sampler2D ShadowMap; + layout(set = 0, binding = 1) uniform sampler2DArray LightMap; + #ifdef SUPPORTS_RAYTRACING + layout(set = 0, binding = 2) uniform accelerationStructureEXT TopLevelAS; + #endif + + // This must match the HWViewpointUniforms struct + layout(set = 1, binding = 0, std140) uniform ViewpointUBO { + mat4 ProjectionMatrix; + mat4 ViewMatrix; + mat4 NormalViewMatrix; + + vec4 uCameraPos; + vec4 uClipLine; + + float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 + int uPalLightLevels; + int uViewHeight; // Software fuzz scaling + float uClipHeight; + float uClipHeightDirection; + int uShadowmapFilter; + + int uLightBlendMode; + }; + + layout(set = 1, binding = 1, std140) uniform MatricesUBO { + mat4 ModelMatrix; + mat4 NormalModelMatrix; + mat4 TextureMatrix; + }; + + struct StreamData + { + vec4 uObjectColor; + vec4 uObjectColor2; + vec4 uDynLightColor; + vec4 uAddColor; + vec4 uTextureAddColor; + vec4 uTextureModulateColor; + vec4 uTextureBlendColor; + vec4 uFogColor; + float uDesaturationFactor; + float uInterpolationFactor; + float timer; // timer data for material shaders + int useVertexData; + vec4 uVertexColor; + vec4 uVertexNormal; + + vec4 uGlowTopPlane; + vec4 uGlowTopColor; + vec4 uGlowBottomPlane; + vec4 uGlowBottomColor; + + vec4 uGradientTopPlane; + vec4 uGradientBottomPlane; + + vec4 uSplitTopPlane; + vec4 uSplitBottomPlane; + + vec4 uDetailParms; + vec4 uNpotEmulation; + vec4 padding1, padding2, padding3; + }; + + layout(set = 1, binding = 2, std140) uniform StreamUBO { + StreamData data[MAX_STREAM_DATA]; + }; + + // light buffers + layout(set = 1, binding = 3, std430) buffer LightBufferSSO + { + vec4 lights[]; + }; + + // bone matrix buffers + layout(set = 1, binding = 4, std430) buffer BoneBufferSSO + { + mat4 bones[]; + }; + + // textures + layout(set = 2, binding = 0) uniform sampler2D tex; + layout(set = 2, binding = 1) uniform sampler2D texture2; + layout(set = 2, binding = 2) uniform sampler2D texture3; + layout(set = 2, binding = 3) uniform sampler2D texture4; + layout(set = 2, binding = 4) uniform sampler2D texture5; + layout(set = 2, binding = 5) uniform sampler2D texture6; + layout(set = 2, binding = 6) uniform sampler2D texture7; + layout(set = 2, binding = 7) uniform sampler2D texture8; + layout(set = 2, binding = 8) uniform sampler2D texture9; + layout(set = 2, binding = 9) uniform sampler2D texture10; + layout(set = 2, binding = 10) uniform sampler2D texture11; + layout(set = 2, binding = 11) uniform sampler2D texture12; + + // This must match the PushConstants struct + layout(push_constant) uniform PushConstants + { + int uTextureMode; + float uAlphaThreshold; + vec2 uClipSplit; + + // Lighting + Fog + float uLightLevel; + float uFogDensity; + float uLightFactor; + float uLightDist; + int uFogEnabled; + + // dynamic lights + int uLightIndex; + + // Blinn glossiness and specular level + vec2 uSpecularMaterial; + + // bone animation + int uBoneIndexBase; + + int uDataIndex; + int padding2, padding3; + }; + + // material types + #if defined(SPECULAR) + #define normaltexture texture2 + #define speculartexture texture3 + #define brighttexture texture4 + #define detailtexture texture5 + #define glowtexture texture6 + #elif defined(PBR) + #define normaltexture texture2 + #define metallictexture texture3 + #define roughnesstexture texture4 + #define aotexture texture5 + #define brighttexture texture6 + #define detailtexture texture7 + #define glowtexture texture8 + #else + #define brighttexture texture2 + #define detailtexture texture3 + #define glowtexture texture4 + #endif + + #define uObjectColor data[uDataIndex].uObjectColor + #define uObjectColor2 data[uDataIndex].uObjectColor2 + #define uDynLightColor data[uDataIndex].uDynLightColor + #define uAddColor data[uDataIndex].uAddColor + #define uTextureBlendColor data[uDataIndex].uTextureBlendColor + #define uTextureModulateColor data[uDataIndex].uTextureModulateColor + #define uTextureAddColor data[uDataIndex].uTextureAddColor + #define uFogColor data[uDataIndex].uFogColor + #define uDesaturationFactor data[uDataIndex].uDesaturationFactor + #define uInterpolationFactor data[uDataIndex].uInterpolationFactor + #define timer data[uDataIndex].timer + #define useVertexData data[uDataIndex].useVertexData + #define uVertexColor data[uDataIndex].uVertexColor + #define uVertexNormal data[uDataIndex].uVertexNormal + #define uGlowTopPlane data[uDataIndex].uGlowTopPlane + #define uGlowTopColor data[uDataIndex].uGlowTopColor + #define uGlowBottomPlane data[uDataIndex].uGlowBottomPlane + #define uGlowBottomColor data[uDataIndex].uGlowBottomColor + #define uGradientTopPlane data[uDataIndex].uGradientTopPlane + #define uGradientBottomPlane data[uDataIndex].uGradientBottomPlane + #define uSplitTopPlane data[uDataIndex].uSplitTopPlane + #define uSplitBottomPlane data[uDataIndex].uSplitBottomPlane + #define uDetailParms data[uDataIndex].uDetailParms + #define uNpotEmulation data[uDataIndex].uNpotEmulation + + #define SUPPORTS_SHADOWMAPS + #define VULKAN_COORDINATE_SYSTEM + #define HAS_UNIFORM_VERTEX_DATA + + // GLSL spec 4.60, 8.15. Noise Functions + // https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf + // "The noise functions noise1, noise2, noise3, and noise4 have been deprecated starting with version 4.4 of GLSL. + // When not generating SPIR-V they are defined to return the value 0.0 or a vector whose components are all 0.0. + // When generating SPIR-V the noise functions are not declared and may not be used." + // However, we need to support mods with custom shaders created for OpenGL renderer + float noise1(float) { return 0; } + vec2 noise2(vec2) { return vec2(0); } + vec3 noise3(vec3) { return vec3(0); } + vec4 noise4(vec4) { return vec4(0); } +)"; + +std::unique_ptr VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *defines) +{ + FString code = GetTargetGlslVersion(); + code << defines; + code << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n"; +#ifdef NPOT_EMULATION + code << "#define NPOT_EMULATION\n"; +#endif + code << shaderBindings; + if (!fb->device->EnabledFeatures.Features.shaderClipDistance) code << "#define NO_CLIPDISTANCE_SUPPORT\n"; + code << "#line 1\n"; + code << LoadPrivateShaderLump(vert_lump).GetChars() << "\n"; + + return ShaderBuilder() + .Type(ShaderType::Vertex) + .AddSource(shadername.GetChars(), code.GetChars()) + .DebugName(shadername.GetChars()) + .Create(shadername.GetChars(), fb->device.get()); +} + +std::unique_ptr VkShaderManager::LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines, bool alphatest, bool gbufferpass) +{ + FString code = GetTargetGlslVersion(); + if (fb->RaytracingEnabled()) + code << "\n#define SUPPORTS_RAYTRACING\n"; + code << defines; + code << "\n$placeholder$"; // here the code can later add more needed #defines. + code << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n"; +#ifdef NPOT_EMULATION + code << "#define NPOT_EMULATION\n"; +#endif + code << shaderBindings; + FString placeholder = "\n"; + + if (!fb->device->EnabledFeatures.Features.shaderClipDistance) code << "#define NO_CLIPDISTANCE_SUPPORT\n"; + if (!alphatest) code << "#define NO_ALPHATEST\n"; + if (gbufferpass) code << "#define GBUFFER_PASS\n"; + + code << "\n#line 1\n"; + code << LoadPrivateShaderLump(frag_lump).GetChars() << "\n"; + + if (material_lump) + { + if (material_lump[0] != '#') + { + FString pp_code = LoadPublicShaderLump(material_lump); + + if (pp_code.IndexOf("ProcessMaterial") < 0 && pp_code.IndexOf("SetupMaterial") < 0) + { + // this looks like an old custom hardware shader. + // add ProcessMaterial function that calls the older ProcessTexel function + + if (pp_code.IndexOf("GetTexCoord") >= 0) + { + code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultmat2.fp").GetChars() << "\n"; + } + else + { + code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultmat.fp").GetChars() << "\n"; + if (pp_code.IndexOf("ProcessTexel") < 0) + { + // this looks like an even older custom hardware shader. + // We need to replace the ProcessTexel call to make it work. + + code.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); + } + } + + if (pp_code.IndexOf("ProcessLight") >= 0) + { + // The ProcessLight signatured changed. Forward to the old one. + code << "\nvec4 ProcessLight(vec4 color);\n"; + code << "\nvec4 ProcessLight(Material material, vec4 color) { return ProcessLight(color); }\n"; + } + } + + code << "\n#line 1\n"; + code << RemoveLegacyUserUniforms(pp_code).GetChars(); + code.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders. + + if (pp_code.IndexOf("ProcessLight") < 0) + { + code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultlight.fp").GetChars() << "\n"; + } + + // ProcessMaterial must be considered broken because it requires the user to fill in data they possibly cannot know all about. + if (pp_code.IndexOf("ProcessMaterial") >= 0 && pp_code.IndexOf("SetupMaterial") < 0) + { + // This reactivates the old logic and disables all features that cannot be supported with that method. + placeholder << "#define LEGACY_USER_SHADER\n"; + } + } + else + { + // material_lump is not a lump name but the source itself (from generated shaders) + code << (material_lump + 1) << "\n"; + } + } + code.Substitute("$placeholder$", placeholder); + + if (light_lump) + { + code << "\n#line 1\n"; + code << LoadPrivateShaderLump(light_lump).GetChars(); + } + + return ShaderBuilder() + .Type(ShaderType::Fragment) + .AddSource(shadername.GetChars(), code.GetChars()) + .DebugName(shadername.GetChars()) + .Create(shadername.GetChars(), fb->device.get()); +} + +FString VkShaderManager::GetTargetGlslVersion() +{ + if (fb->device->Instance->ApiVersion == VK_API_VERSION_1_2) + { + return "#version 460\n#extension GL_EXT_ray_query : enable\n"; + } + else + { + return "#version 450 core\n"; + } +} + +FString VkShaderManager::LoadPublicShaderLump(const char *lumpname) +{ + int lump = fileSystem.CheckNumForFullName(lumpname, 0); + if (lump == -1) lump = fileSystem.CheckNumForFullName(lumpname); + if (lump == -1) I_Error("Unable to load '%s'", lumpname); + return GetStringFromLump(lump); +} + +FString VkShaderManager::LoadPrivateShaderLump(const char *lumpname) +{ + int lump = fileSystem.CheckNumForFullName(lumpname, 0); + if (lump == -1) I_Error("Unable to load '%s'", lumpname); + return GetStringFromLump(lump); +} + +VkPPShader* VkShaderManager::GetVkShader(PPShader* shader) +{ + if (!shader->Backend) + shader->Backend = std::make_unique(fb, shader); + return static_cast(shader->Backend.get()); +} + +void VkShaderManager::AddVkPPShader(VkPPShader* shader) +{ + shader->it = PPShaders.insert(PPShaders.end(), shader); +} + +void VkShaderManager::RemoveVkPPShader(VkPPShader* shader) +{ + shader->Reset(); + shader->fb = nullptr; + PPShaders.erase(shader->it); +} diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h new file mode 100644 index 00000000000..cac924916bf --- /dev/null +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -0,0 +1,101 @@ + +#pragma once + +#include + +#include "vectors.h" +#include "matrix.h" +#include "name.h" +#include "hw_renderstate.h" +#include + +#define SHADER_MIN_REQUIRED_TEXTURE_LAYERS 11 + +class VulkanRenderDevice; +class VulkanDevice; +class VulkanShader; +class VkPPShader; +class PPShader; + +struct MatricesUBO +{ + VSMatrix ModelMatrix; + VSMatrix NormalModelMatrix; + VSMatrix TextureMatrix; +}; + +#define MAX_STREAM_DATA ((int)(65536 / sizeof(StreamData))) + +struct StreamUBO +{ + StreamData data[MAX_STREAM_DATA]; +}; + +struct PushConstants +{ + int uTextureMode; + float uAlphaThreshold; + FVector2 uClipSplit; + + // Lighting + Fog + float uLightLevel; + float uFogDensity; + float uLightFactor; + float uLightDist; + int uFogEnabled; + + // dynamic lights + int uLightIndex; + + // Blinn glossiness and specular level + FVector2 uSpecularMaterial; + + // bone animation + int uBoneIndexBase; + + int uDataIndex; + int padding1, padding2, padding3; +}; + +class VkShaderProgram +{ +public: + std::unique_ptr vert; + std::unique_ptr frag; +}; + +class VkShaderManager +{ +public: + VkShaderManager(VulkanRenderDevice* fb); + ~VkShaderManager(); + + void Deinit(); + + VkShaderProgram *GetEffect(int effect, EPassType passType); + VkShaderProgram *Get(unsigned int eff, bool alphateston, EPassType passType); + bool CompileNextShader(); + + VkPPShader* GetVkShader(PPShader* shader); + + void AddVkPPShader(VkPPShader* shader); + void RemoveVkPPShader(VkPPShader* shader); + +private: + std::unique_ptr LoadVertShader(FString shadername, const char *vert_lump, const char *defines); + std::unique_ptr LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines, bool alphatest, bool gbufferpass); + + FString GetTargetGlslVersion(); + FString LoadPublicShaderLump(const char *lumpname); + FString LoadPrivateShaderLump(const char *lumpname); + + VulkanRenderDevice* fb = nullptr; + + std::vector mMaterialShaders[MAX_PASS_TYPES]; + std::vector mMaterialShadersNAT[MAX_PASS_TYPES]; + std::vector mEffectShaders[MAX_PASS_TYPES]; + uint8_t compilePass = 0, compileState = 0; + int compileIndex = 0; + + std::list PPShaders; +}; diff --git a/src/common/rendering/vulkan/system/vk_buffer.cpp b/src/common/rendering/vulkan/system/vk_buffer.cpp new file mode 100644 index 00000000000..cc1d0438762 --- /dev/null +++ b/src/common/rendering/vulkan/system/vk_buffer.cpp @@ -0,0 +1,134 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_buffer.h" +#include "vk_hwbuffer.h" +#include "vulkan/renderer/vk_streambuffer.h" +#include "hwrenderer/data/shaderuniforms.h" + +VkBufferManager::VkBufferManager(VulkanRenderDevice* fb) : fb(fb) +{ +} + +VkBufferManager::~VkBufferManager() +{ +} + +void VkBufferManager::Init() +{ + MatrixBuffer.reset(new VkStreamBuffer(this, sizeof(MatricesUBO), 50000)); + StreamBuffer.reset(new VkStreamBuffer(this, sizeof(StreamUBO), 300)); + + CreateFanToTrisIndexBuffer(); +} + +void VkBufferManager::Deinit() +{ + while (!Buffers.empty()) + RemoveBuffer(Buffers.back()); +} + +void VkBufferManager::AddBuffer(VkHardwareBuffer* buffer) +{ + buffer->it = Buffers.insert(Buffers.end(), buffer); +} + +void VkBufferManager::RemoveBuffer(VkHardwareBuffer* buffer) +{ + buffer->Reset(); + buffer->fb = nullptr; + Buffers.erase(buffer->it); + + for (VkHardwareDataBuffer** knownbuf : { &ViewpointUBO, &LightBufferSSO, &LightNodes, &LightLines, &LightList, &BoneBufferSSO }) + { + if (buffer == *knownbuf) *knownbuf = nullptr; + } +} + +IVertexBuffer* VkBufferManager::CreateVertexBuffer() +{ + return new VkHardwareVertexBuffer(fb); +} + +IIndexBuffer* VkBufferManager::CreateIndexBuffer() +{ + return new VkHardwareIndexBuffer(fb); +} + +IDataBuffer* VkBufferManager::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) +{ + auto buffer = new VkHardwareDataBuffer(fb, bindingpoint, ssbo, needsresize); + + switch (bindingpoint) + { + case LIGHTBUF_BINDINGPOINT: LightBufferSSO = buffer; break; + case VIEWPOINT_BINDINGPOINT: ViewpointUBO = buffer; break; + case LIGHTNODES_BINDINGPOINT: LightNodes = buffer; break; + case LIGHTLINES_BINDINGPOINT: LightLines = buffer; break; + case LIGHTLIST_BINDINGPOINT: LightList = buffer; break; + case BONEBUF_BINDINGPOINT: BoneBufferSSO = buffer; break; + case POSTPROCESS_BINDINGPOINT: break; + default: break; + } + + return buffer; +} + +void VkBufferManager::CreateFanToTrisIndexBuffer() +{ + TArray data; + for (int i = 2; i < 1000; i++) + { + data.Push(0); + data.Push(i - 1); + data.Push(i); + } + + FanToTrisIndexBuffer.reset(CreateIndexBuffer()); + FanToTrisIndexBuffer->SetData(sizeof(uint32_t) * data.Size(), data.Data(), BufferUsageType::Static); +} + +///////////////////////////////////////////////////////////////////////////// + +VkStreamBuffer::VkStreamBuffer(VkBufferManager* buffers, size_t structSize, size_t count) +{ + mBlockSize = static_cast((structSize + screen->uniformblockalignment - 1) / screen->uniformblockalignment * screen->uniformblockalignment); + + UniformBuffer = (VkHardwareDataBuffer*)buffers->CreateDataBuffer(-1, false, false); + UniformBuffer->SetData(mBlockSize * count, nullptr, BufferUsageType::Persistent); +} + +VkStreamBuffer::~VkStreamBuffer() +{ + delete UniformBuffer; +} + +uint32_t VkStreamBuffer::NextStreamDataBlock() +{ + mStreamDataOffset += mBlockSize; + if (mStreamDataOffset + (size_t)mBlockSize >= UniformBuffer->Size()) + { + mStreamDataOffset = 0; + return 0xffffffff; + } + return mStreamDataOffset; +} diff --git a/src/common/rendering/vulkan/system/vk_buffer.h b/src/common/rendering/vulkan/system/vk_buffer.h new file mode 100644 index 00000000000..21ee7765fd7 --- /dev/null +++ b/src/common/rendering/vulkan/system/vk_buffer.h @@ -0,0 +1,65 @@ + +#pragma once + +#include "zvulkan/vulkanobjects.h" +#include + +class VulkanRenderDevice; +class VkHardwareBuffer; +class VkHardwareDataBuffer; +class VkStreamBuffer; +class IIndexBuffer; +class IVertexBuffer; +class IDataBuffer; + +class VkBufferManager +{ +public: + VkBufferManager(VulkanRenderDevice* fb); + ~VkBufferManager(); + + void Init(); + void Deinit(); + + IVertexBuffer* CreateVertexBuffer(); + IIndexBuffer* CreateIndexBuffer(); + IDataBuffer* CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize); + + void AddBuffer(VkHardwareBuffer* buffer); + void RemoveBuffer(VkHardwareBuffer* buffer); + + VkHardwareDataBuffer* ViewpointUBO = nullptr; + VkHardwareDataBuffer* LightBufferSSO = nullptr; + VkHardwareDataBuffer* LightNodes = nullptr; + VkHardwareDataBuffer* LightLines = nullptr; + VkHardwareDataBuffer* LightList = nullptr; + VkHardwareDataBuffer* BoneBufferSSO = nullptr; + + std::unique_ptr MatrixBuffer; + std::unique_ptr StreamBuffer; + + std::unique_ptr FanToTrisIndexBuffer; + +private: + void CreateFanToTrisIndexBuffer(); + + VulkanRenderDevice* fb = nullptr; + + std::list Buffers; +}; + +class VkStreamBuffer +{ +public: + VkStreamBuffer(VkBufferManager* buffers, size_t structSize, size_t count); + ~VkStreamBuffer(); + + uint32_t NextStreamDataBlock(); + void Reset() { mStreamDataOffset = 0; } + + VkHardwareDataBuffer* UniformBuffer = nullptr; + +private: + uint32_t mBlockSize = 0; + uint32_t mStreamDataOffset = 0; +}; diff --git a/src/common/rendering/vulkan/system/vk_commandbuffer.cpp b/src/common/rendering/vulkan/system/vk_commandbuffer.cpp new file mode 100644 index 00000000000..683a3b7ffda --- /dev/null +++ b/src/common/rendering/vulkan/system/vk_commandbuffer.cpp @@ -0,0 +1,265 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_commandbuffer.h" +#include "vk_renderdevice.h" +#include "zvulkan/vulkanswapchain.h" +#include "zvulkan/vulkanbuilders.h" +#include "vulkan/textures/vk_framebuffer.h" +#include "vulkan/renderer/vk_renderstate.h" +#include "vulkan/renderer/vk_postprocess.h" +#include "hw_clock.h" +#include "v_video.h" + +extern int rendered_commandbuffers; +int current_rendered_commandbuffers; + +extern bool gpuStatActive; +extern bool keepGpuStatActive; +extern FString gpuStatOutput; + +VkCommandBufferManager::VkCommandBufferManager(VulkanRenderDevice* fb) : fb(fb) +{ + mCommandPool = CommandPoolBuilder() + .QueueFamily(fb->device->GraphicsFamily) + .DebugName("mCommandPool") + .Create(fb->device.get()); + + for (auto& semaphore : mSubmitSemaphore) + semaphore.reset(new VulkanSemaphore(fb->device.get())); + + for (auto& fence : mSubmitFence) + fence.reset(new VulkanFence(fb->device.get())); + + for (int i = 0; i < maxConcurrentSubmitCount; i++) + mSubmitWaitFences[i] = mSubmitFence[i]->fence; + + if (fb->device->GraphicsTimeQueries) + { + mTimestampQueryPool = QueryPoolBuilder() + .QueryType(VK_QUERY_TYPE_TIMESTAMP, MaxTimestampQueries) + .Create(fb->device.get()); + + GetDrawCommands()->resetQueryPool(mTimestampQueryPool.get(), 0, MaxTimestampQueries); + } +} + +VkCommandBufferManager::~VkCommandBufferManager() +{ +} + +VulkanCommandBuffer* VkCommandBufferManager::GetTransferCommands() +{ + if (!mTransferCommands) + { + mTransferCommands = mCommandPool->createBuffer(); + mTransferCommands->SetDebugName("VulkanRenderDevice.mTransferCommands"); + mTransferCommands->begin(); + } + return mTransferCommands.get(); +} + +VulkanCommandBuffer* VkCommandBufferManager::GetDrawCommands() +{ + if (!mDrawCommands) + { + mDrawCommands = mCommandPool->createBuffer(); + mDrawCommands->SetDebugName("VulkanRenderDevice.mDrawCommands"); + mDrawCommands->begin(); + } + return mDrawCommands.get(); +} + +void VkCommandBufferManager::BeginFrame() +{ + if (mNextTimestampQuery > 0) + { + GetDrawCommands()->resetQueryPool(mTimestampQueryPool.get(), 0, mNextTimestampQuery); + mNextTimestampQuery = 0; + } +} + +void VkCommandBufferManager::FlushCommands(VulkanCommandBuffer** commands, size_t count, bool finish, bool lastsubmit) +{ + int currentIndex = mNextSubmit % maxConcurrentSubmitCount; + + if (mNextSubmit >= maxConcurrentSubmitCount) + { + vkWaitForFences(fb->device->device, 1, &mSubmitFence[currentIndex]->fence, VK_TRUE, std::numeric_limits::max()); + vkResetFences(fb->device->device, 1, &mSubmitFence[currentIndex]->fence); + } + + QueueSubmit submit; + + for (size_t i = 0; i < count; i++) + submit.AddCommandBuffer(commands[i]); + + if (mNextSubmit > 0) + submit.AddWait(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, mSubmitSemaphore[(mNextSubmit - 1) % maxConcurrentSubmitCount].get()); + + if (finish && fb->GetFramebufferManager()->PresentImageIndex != -1) + { + submit.AddWait(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, fb->GetFramebufferManager()->SwapChainImageAvailableSemaphore.get()); + submit.AddSignal(fb->GetFramebufferManager()->RenderFinishedSemaphore.get()); + } + + if (!lastsubmit) + submit.AddSignal(mSubmitSemaphore[currentIndex].get()); + + submit.Execute(fb->device.get(), fb->device->GraphicsQueue, mSubmitFence[currentIndex].get()); + mNextSubmit++; +} + +void VkCommandBufferManager::FlushCommands(bool finish, bool lastsubmit, bool uploadOnly) +{ + if (!uploadOnly) + fb->GetRenderState()->EndRenderPass(); + + if ((!uploadOnly && mDrawCommands) || mTransferCommands) + { + VulkanCommandBuffer* commands[2]; + size_t count = 0; + + if (mTransferCommands) + { + mTransferCommands->end(); + commands[count++] = mTransferCommands.get(); + TransferDeleteList->Add(std::move(mTransferCommands)); + } + + if (!uploadOnly && mDrawCommands) + { + mDrawCommands->end(); + commands[count++] = mDrawCommands.get(); + DrawDeleteList->Add(std::move(mDrawCommands)); + } + + FlushCommands(commands, count, finish, lastsubmit); + + current_rendered_commandbuffers += (int)count; + } +} + +void VkCommandBufferManager::WaitForCommands(bool finish, bool uploadOnly) +{ + if (finish) + { + Finish.Reset(); + Finish.Clock(); + + fb->GetFramebufferManager()->AcquireImage(); + } + + FlushCommands(finish, true, uploadOnly); + + if (finish) + { + if (!fb->GetVSync()) + fb->FPSLimit(); + fb->GetFramebufferManager()->QueuePresent(); + } + + int numWaitFences = min(mNextSubmit, (int)maxConcurrentSubmitCount); + + if (numWaitFences > 0) + { + vkWaitForFences(fb->device->device, numWaitFences, mSubmitWaitFences, VK_TRUE, std::numeric_limits::max()); + vkResetFences(fb->device->device, numWaitFences, mSubmitWaitFences); + } + + DeleteFrameObjects(uploadOnly); + mNextSubmit = 0; + + if (finish) + { + Finish.Unclock(); + rendered_commandbuffers = current_rendered_commandbuffers; + current_rendered_commandbuffers = 0; + } +} + +void VkCommandBufferManager::DeleteFrameObjects(bool uploadOnly) +{ + TransferDeleteList = std::make_unique(); + if (!uploadOnly) + DrawDeleteList = std::make_unique(); +} + +void VkCommandBufferManager::PushGroup(const FString& name) +{ + if (!gpuStatActive) + return; + + if (mNextTimestampQuery < MaxTimestampQueries && fb->device->GraphicsTimeQueries) + { + TimestampQuery q; + q.name = name; + q.startIndex = mNextTimestampQuery++; + q.endIndex = 0; + GetDrawCommands()->writeTimestamp(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, mTimestampQueryPool.get(), q.startIndex); + mGroupStack.push_back(timeElapsedQueries.size()); + timeElapsedQueries.push_back(q); + } +} + +void VkCommandBufferManager::PopGroup() +{ + if (!gpuStatActive || mGroupStack.empty()) + return; + + TimestampQuery& q = timeElapsedQueries[mGroupStack.back()]; + mGroupStack.pop_back(); + + if (mNextTimestampQuery < MaxTimestampQueries && fb->device->GraphicsTimeQueries) + { + q.endIndex = mNextTimestampQuery++; + GetDrawCommands()->writeTimestamp(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, mTimestampQueryPool.get(), q.endIndex); + } +} + +void VkCommandBufferManager::UpdateGpuStats() +{ + uint64_t timestamps[MaxTimestampQueries]; + if (mNextTimestampQuery > 0) + mTimestampQueryPool->getResults(0, mNextTimestampQuery, sizeof(uint64_t) * mNextTimestampQuery, timestamps, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); + + double timestampPeriod = fb->device->PhysicalDevice.Properties.Properties.limits.timestampPeriod; + + gpuStatOutput = ""; + for (auto& q : timeElapsedQueries) + { + if (q.endIndex <= q.startIndex) + continue; + + int64_t timeElapsed = max(static_cast(timestamps[q.endIndex] - timestamps[q.startIndex]), (int64_t)0); + double timeNS = timeElapsed * timestampPeriod; + + FString out; + out.Format("%s=%04.2f ms\n", q.name.GetChars(), timeNS / 1000000.0f); + gpuStatOutput += out; + } + timeElapsedQueries.clear(); + mGroupStack.clear(); + + gpuStatActive = keepGpuStatActive; + keepGpuStatActive = false; +} diff --git a/src/common/rendering/vulkan/system/vk_commandbuffer.h b/src/common/rendering/vulkan/system/vk_commandbuffer.h new file mode 100644 index 00000000000..1ce16b021fb --- /dev/null +++ b/src/common/rendering/vulkan/system/vk_commandbuffer.h @@ -0,0 +1,89 @@ +#pragma once + +#include +#include +#include "zstring.h" + +class VulkanRenderDevice; + +class VkCommandBufferManager +{ +public: + VkCommandBufferManager(VulkanRenderDevice* fb); + ~VkCommandBufferManager(); + + void BeginFrame(); + + VulkanCommandBuffer* GetTransferCommands(); + VulkanCommandBuffer* GetDrawCommands(); + + void FlushCommands(bool finish, bool lastsubmit = false, bool uploadOnly = false); + + void WaitForCommands(bool finish) { WaitForCommands(finish, false); } + void WaitForCommands(bool finish, bool uploadOnly); + + void PushGroup(const FString& name); + void PopGroup(); + void UpdateGpuStats(); + + class DeleteList + { + public: + std::vector> Buffers; + std::vector> Samplers; + std::vector> Images; + std::vector> ImageViews; + std::vector> Framebuffers; + std::vector> AccelStructs; + std::vector> DescriptorPools; + std::vector> Descriptors; + std::vector> Shaders; + std::vector> CommandBuffers; + size_t TotalSize = 0; + + void Add(std::unique_ptr obj) { if (obj) { TotalSize += obj->size; Buffers.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { Samplers.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { Images.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { ImageViews.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { Framebuffers.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { AccelStructs.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { DescriptorPools.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { Descriptors.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { CommandBuffers.push_back(std::move(obj)); } } + void Add(std::unique_ptr obj) { if (obj) { Shaders.push_back(std::move(obj)); } } + }; + + std::unique_ptr TransferDeleteList = std::make_unique(); + std::unique_ptr DrawDeleteList = std::make_unique(); + + void DeleteFrameObjects(bool uploadOnly = false); + +private: + void FlushCommands(VulkanCommandBuffer** commands, size_t count, bool finish, bool lastsubmit); + + VulkanRenderDevice* fb = nullptr; + + std::unique_ptr mCommandPool; + + std::unique_ptr mTransferCommands; + std::unique_ptr mDrawCommands; + + enum { maxConcurrentSubmitCount = 8 }; + std::unique_ptr mSubmitSemaphore[maxConcurrentSubmitCount]; + std::unique_ptr mSubmitFence[maxConcurrentSubmitCount]; + VkFence mSubmitWaitFences[maxConcurrentSubmitCount]; + int mNextSubmit = 0; + + struct TimestampQuery + { + FString name; + uint32_t startIndex; + uint32_t endIndex; + }; + + enum { MaxTimestampQueries = 100 }; + std::unique_ptr mTimestampQueryPool; + int mNextTimestampQuery = 0; + std::vector mGroupStack; + std::vector timeElapsedQueries; +}; diff --git a/src/common/rendering/vulkan/system/vk_hwbuffer.cpp b/src/common/rendering/vulkan/system/vk_hwbuffer.cpp new file mode 100644 index 00000000000..7edfd471a42 --- /dev/null +++ b/src/common/rendering/vulkan/system/vk_hwbuffer.cpp @@ -0,0 +1,254 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_hwbuffer.h" +#include "zvulkan/vulkanbuilders.h" +#include "vk_renderdevice.h" +#include "vk_commandbuffer.h" +#include "vk_buffer.h" +#include "vulkan/renderer/vk_renderstate.h" +#include "vulkan/renderer/vk_descriptorset.h" +#include "engineerrors.h" + +VkHardwareBuffer::VkHardwareBuffer(VulkanRenderDevice* fb) : fb(fb) +{ + fb->GetBufferManager()->AddBuffer(this); +} + +VkHardwareBuffer::~VkHardwareBuffer() +{ + if (fb) + fb->GetBufferManager()->RemoveBuffer(this); +} + +void VkHardwareBuffer::Reset() +{ + if (fb) + { + if (mBuffer && map) + { + mBuffer->Unmap(); + map = nullptr; + } + if (mBuffer) + fb->GetCommands()->DrawDeleteList->Add(std::move(mBuffer)); + if (mStaging) + fb->GetCommands()->TransferDeleteList->Add(std::move(mStaging)); + } +} + +void VkHardwareBuffer::SetData(size_t size, const void *data, BufferUsageType usage) +{ + size_t bufsize = max(size, (size_t)16); // For supporting zero byte buffers + + // If SetData is called multiple times we have to keep the old buffers alive as there might still be draw commands referencing them + if (mBuffer) + { + fb->GetCommands()->DrawDeleteList->Add(std::move(mBuffer)); + } + if (mStaging) + { + fb->GetCommands()->TransferDeleteList->Add(std::move(mStaging)); + } + + if (usage == BufferUsageType::Static || usage == BufferUsageType::Stream) + { + // Note: we could recycle buffers here for the stream usage type to improve performance + + mPersistent = false; + + mBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | mBufferType, VMA_MEMORY_USAGE_GPU_ONLY) + .Size(bufsize) + .DebugName(usage == BufferUsageType::Static ? "VkHardwareBuffer.Static" : "VkHardwareBuffer.Stream") + .Create(fb->device.get()); + + mStaging = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .Size(bufsize) + .DebugName(usage == BufferUsageType::Static ? "VkHardwareBuffer.Staging.Static" : "VkHardwareBuffer.Staging.Stream") + .Create(fb->device.get()); + + if (data) + { + void* dst = mStaging->Map(0, bufsize); + memcpy(dst, data, size); + mStaging->Unmap(); + } + + fb->GetCommands()->GetTransferCommands()->copyBuffer(mStaging.get(), mBuffer.get()); + } + else if (usage == BufferUsageType::Persistent) + { + mPersistent = true; + + mBuffer = BufferBuilder() + .Usage(mBufferType, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) + .MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + .Size(bufsize) + .DebugName("VkHardwareBuffer.Persistent") + .Create(fb->device.get()); + + map = mBuffer->Map(0, bufsize); + if (data) + memcpy(map, data, size); + } + else if (usage == BufferUsageType::Mappable) + { + mPersistent = false; + + mBuffer = BufferBuilder() + .Usage(mBufferType, VMA_MEMORY_USAGE_UNKNOWN, 0) + .MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + .Size(bufsize) + .DebugName("VkHardwareBuffer.Mappable") + .Create(fb->device.get()); + + if (data) + { + void* dst = mBuffer->Map(0, bufsize); + memcpy(dst, data, size); + mBuffer->Unmap(); + } + } + + buffersize = size; +} + +void VkHardwareBuffer::SetSubData(size_t offset, size_t size, const void *data) +{ + size = max(size, (size_t)16); // For supporting zero byte buffers + + if (mStaging) + { + void *dst = mStaging->Map(offset, size); + memcpy(dst, data, size); + mStaging->Unmap(); + + fb->GetCommands()->GetTransferCommands()->copyBuffer(mStaging.get(), mBuffer.get(), offset, offset, size); + } + else + { + void *dst = mBuffer->Map(offset, size); + memcpy(dst, data, size); + mBuffer->Unmap(); + } +} + +void VkHardwareBuffer::Resize(size_t newsize) +{ + newsize = max(newsize, (size_t)16); // For supporting zero byte buffers + + // Grab old buffer + size_t oldsize = buffersize; + std::unique_ptr oldBuffer = std::move(mBuffer); + oldBuffer->Unmap(); + map = nullptr; + + // Create new buffer + mBuffer = BufferBuilder() + .Usage(mBufferType, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) + .MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + .Size(newsize) + .DebugName("VkHardwareBuffer.Resized") + .Create(fb->device.get()); + buffersize = newsize; + + // Transfer data from old to new + fb->GetCommands()->GetTransferCommands()->copyBuffer(oldBuffer.get(), mBuffer.get(), 0, 0, oldsize); + fb->GetCommands()->TransferDeleteList->Add(std::move(oldBuffer)); + fb->GetCommands()->WaitForCommands(false); + fb->GetDescriptorSetManager()->UpdateHWBufferSet(); // Old buffer may be part of the bound descriptor set + + // Fetch pointer to new buffer + map = mBuffer->Map(0, newsize); +} + +void VkHardwareBuffer::Map() +{ + if (!mPersistent) + map = mBuffer->Map(0, mBuffer->size); +} + +void VkHardwareBuffer::Unmap() +{ + if (!mPersistent) + { + mBuffer->Unmap(); + map = nullptr; + } +} + +void *VkHardwareBuffer::Lock(unsigned int size) +{ + size = max(size, (unsigned int)16); // For supporting zero byte buffers + + if (!mBuffer) + { + // The model mesh loaders lock multiple non-persistent buffers at the same time. This is not allowed in vulkan. + // VkDeviceMemory can only be mapped once and multiple non-persistent buffers may come from the same device memory object. + mStaticUpload.Resize(size); + map = mStaticUpload.Data(); + } + else if (!mPersistent) + { + map = mBuffer->Map(0, size); + } + return map; +} + +void VkHardwareBuffer::Unlock() +{ + if (!mBuffer) + { + map = nullptr; + SetData(mStaticUpload.Size(), mStaticUpload.Data(), BufferUsageType::Static); + mStaticUpload.Clear(); + } + else if (!mPersistent) + { + mBuffer->Unmap(); + map = nullptr; + } +} + +///////////////////////////////////////////////////////////////////////////// + +void VkHardwareVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) +{ + VertexFormat = fb->GetRenderPassManager()->GetVertexFormat(numBindingPoints, numAttributes, stride, attrs); +} + +///////////////////////////////////////////////////////////////////////////// + + +void VkHardwareDataBuffer::BindRange(FRenderState* state, size_t start, size_t length) +{ + static_cast(state)->Bind(bindingpoint, (uint32_t)start); +} + diff --git a/src/common/rendering/vulkan/system/vk_hwbuffer.h b/src/common/rendering/vulkan/system/vk_hwbuffer.h new file mode 100644 index 00000000000..95a02314146 --- /dev/null +++ b/src/common/rendering/vulkan/system/vk_hwbuffer.h @@ -0,0 +1,74 @@ +#pragma once + +#include "hwrenderer/data/buffers.h" +#include "zvulkan/vulkanobjects.h" +#include "tarray.h" +#include + +#ifdef _MSC_VER +// silence bogus warning C4250: 'VkHardwareVertexBuffer': inherits 'VkHardwareBuffer::VkHardwareBuffer::SetData' via dominance +// According to internet infos, the warning is erroneously emitted in this case. +#pragma warning(disable:4250) +#endif + +class VulkanRenderDevice; + +class VkHardwareBuffer : virtual public IBuffer +{ +public: + VkHardwareBuffer(VulkanRenderDevice* fb); + ~VkHardwareBuffer(); + + void Reset(); + + void SetData(size_t size, const void *data, BufferUsageType usage) override; + void SetSubData(size_t offset, size_t size, const void *data) override; + void Resize(size_t newsize) override; + + void Map() override; + void Unmap() override; + + void *Lock(unsigned int size) override; + void Unlock() override; + + VulkanRenderDevice* fb = nullptr; + std::list::iterator it; + + VkBufferUsageFlags mBufferType = 0; + std::unique_ptr mBuffer; + std::unique_ptr mStaging; + bool mPersistent = false; + TArray mStaticUpload; +}; + +class VkHardwareVertexBuffer : public IVertexBuffer, public VkHardwareBuffer +{ +public: + VkHardwareVertexBuffer(VulkanRenderDevice* fb) : VkHardwareBuffer(fb) { mBufferType = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; } + void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override; + + int VertexFormat = -1; +}; + +class VkHardwareIndexBuffer : public IIndexBuffer, public VkHardwareBuffer +{ +public: + VkHardwareIndexBuffer(VulkanRenderDevice* fb) : VkHardwareBuffer(fb) { mBufferType = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; } +}; + +class VkHardwareDataBuffer : public IDataBuffer, public VkHardwareBuffer +{ +public: + VkHardwareDataBuffer(VulkanRenderDevice* fb, int bindingpoint, bool ssbo, bool needresize) : VkHardwareBuffer(fb), bindingpoint(bindingpoint) + { + mBufferType = ssbo ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + if (needresize) + { + mBufferType |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + } + } + + void BindRange(FRenderState *state, size_t start, size_t length) override; + + int bindingpoint; +}; diff --git a/src/common/rendering/vulkan/system/vk_renderdevice.cpp b/src/common/rendering/vulkan/system/vk_renderdevice.cpp new file mode 100644 index 00000000000..91686de6a9c --- /dev/null +++ b/src/common/rendering/vulkan/system/vk_renderdevice.cpp @@ -0,0 +1,575 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include + +#include + +#include "v_video.h" +#include "m_png.h" + +#include "r_videoscale.h" +#include "i_time.h" +#include "v_text.h" +#include "version.h" +#include "v_draw.h" + +#include "hw_clock.h" +#include "hw_vrmodes.h" +#include "hw_cvars.h" +#include "hw_skydome.h" +#include "hwrenderer/data/hw_viewpointbuffer.h" +#include "flatvertices.h" +#include "hwrenderer/data/shaderuniforms.h" +#include "hw_lightbuffer.h" +#include "hw_bonebuffer.h" + +#include "vk_renderdevice.h" +#include "vk_hwbuffer.h" +#include "vulkan/renderer/vk_renderstate.h" +#include "vulkan/renderer/vk_renderpass.h" +#include "vulkan/renderer/vk_descriptorset.h" +#include "vulkan/renderer/vk_streambuffer.h" +#include "vulkan/renderer/vk_postprocess.h" +#include "vulkan/renderer/vk_raytrace.h" +#include "vulkan/shaders/vk_shader.h" +#include "vulkan/textures/vk_renderbuffers.h" +#include "vulkan/textures/vk_samplers.h" +#include "vulkan/textures/vk_hwtexture.h" +#include "vulkan/textures/vk_texture.h" +#include "vulkan/textures/vk_framebuffer.h" +#include +#include +#include +#include +#include "vulkan/system/vk_commandbuffer.h" +#include "vulkan/system/vk_buffer.h" +#include "engineerrors.h" +#include "c_dispatch.h" + +FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames = -1); + +EXTERN_CVAR(Int, gl_tonemap) +EXTERN_CVAR(Int, screenblocks) +EXTERN_CVAR(Bool, cl_capfps) + +CVAR(Bool, vk_raytrace, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + +// Physical device info +static std::vector SupportedDevices; +int vkversion; + +CUSTOM_CVAR(Bool, vk_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} + +CVAR(Bool, vk_debug_callstack, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + +CUSTOM_CVAR(Int, vk_device, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} + +CCMD(vk_listdevices) +{ + for (size_t i = 0; i < SupportedDevices.size(); i++) + { + Printf("#%d - %s\n", (int)i, SupportedDevices[i].Device->Properties.Properties.deviceName); + } +} + +void VulkanError(const char* text) +{ + throw CVulkanError(text); +} + +void VulkanPrintLog(const char* typestr, const std::string& msg) +{ + bool showcallstack = strstr(typestr, "error") != nullptr; + + if (showcallstack) + Printf("\n"); + + Printf(TEXTCOLOR_RED "[%s] ", typestr); + Printf(TEXTCOLOR_WHITE "%s\n", msg.c_str()); + + if (vk_debug_callstack && showcallstack) + { + FString callstack = JitCaptureStackTrace(0, true, 5); + if (!callstack.IsEmpty()) + Printf("%s\n", callstack.GetChars()); + } +} + +VulkanRenderDevice::VulkanRenderDevice(void *hMonitor, bool fullscreen, std::shared_ptr surface) : + Super(hMonitor, fullscreen) +{ + VulkanDeviceBuilder builder; + builder.OptionalRayQuery(); + builder.Surface(surface); + builder.SelectDevice(vk_device); + SupportedDevices = builder.FindDevices(surface->Instance); + device = builder.Create(surface->Instance); +} + +VulkanRenderDevice::~VulkanRenderDevice() +{ + vkDeviceWaitIdle(device->device); // make sure the GPU is no longer using any objects before RAII tears them down + + delete mVertexData; + delete mSkyData; + delete mViewpoints; + delete mLights; + delete mBones; + mShadowMap.Reset(); + + if (mDescriptorSetManager) + mDescriptorSetManager->Deinit(); + if (mTextureManager) + mTextureManager->Deinit(); + if (mBufferManager) + mBufferManager->Deinit(); + if (mShaderManager) + mShaderManager->Deinit(); + + mCommands->DeleteFrameObjects(); +} + +void VulkanRenderDevice::InitializeState() +{ + static bool first = true; + if (first) + { + PrintStartupLog(); + first = false; + } + + // Use the same names here as OpenGL returns. + switch (device->PhysicalDevice.Properties.Properties.vendorID) + { + case 0x1002: vendorstring = "ATI Technologies Inc."; break; + case 0x10DE: vendorstring = "NVIDIA Corporation"; break; + case 0x8086: vendorstring = "Intel"; break; + default: vendorstring = "Unknown"; break; + } + + hwcaps = RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE; + glslversion = 4.50f; + uniformblockalignment = (unsigned int)device->PhysicalDevice.Properties.Properties.limits.minUniformBufferOffsetAlignment; + maxuniformblock = device->PhysicalDevice.Properties.Properties.limits.maxUniformBufferRange; + + mCommands.reset(new VkCommandBufferManager(this)); + + mSamplerManager.reset(new VkSamplerManager(this)); + mTextureManager.reset(new VkTextureManager(this)); + mFramebufferManager.reset(new VkFramebufferManager(this)); + mBufferManager.reset(new VkBufferManager(this)); + mBufferManager->Init(); + + mScreenBuffers.reset(new VkRenderBuffers(this)); + mSaveBuffers.reset(new VkRenderBuffers(this)); + mActiveRenderBuffers = mScreenBuffers.get(); + + mPostprocess.reset(new VkPostprocess(this)); + mDescriptorSetManager.reset(new VkDescriptorSetManager(this)); + mRenderPassManager.reset(new VkRenderPassManager(this)); + mRaytrace.reset(new VkRaytrace(this)); + + mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight()); + mSkyData = new FSkyVertexBuffer; + mViewpoints = new HWViewpointBuffer; + mLights = new FLightBuffer(); + mBones = new BoneBuffer(); + + mShaderManager.reset(new VkShaderManager(this)); + mDescriptorSetManager->Init(); +#ifdef __APPLE__ + mRenderState.reset(new VkRenderStateMolten(this)); +#else + mRenderState.reset(new VkRenderState(this)); +#endif +} + +void VulkanRenderDevice::Update() +{ + twoD.Reset(); + Flush3D.Reset(); + + Flush3D.Clock(); + + GetPostprocess()->SetActiveRenderTarget(); + + Draw2D(); + twod->Clear(); + + mRenderState->EndRenderPass(); + mRenderState->EndFrame(); + + Flush3D.Unclock(); + + mCommands->WaitForCommands(true); + mCommands->UpdateGpuStats(); + + Super::Update(); +} + +bool VulkanRenderDevice::CompileNextShader() +{ + return mShaderManager->CompileNextShader(); +} + +void VulkanRenderDevice::RenderTextureView(FCanvasTexture* tex, std::function renderFunc) +{ + auto BaseLayer = static_cast(tex->GetHardwareTexture(0, 0)); + + VkTextureImage *image = BaseLayer->GetImage(tex, 0, 0); + VkTextureImage *depthStencil = BaseLayer->GetDepthStencil(tex); + + mRenderState->EndRenderPass(); + + VkImageTransition() + .AddImage(image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false) + .Execute(mCommands->GetDrawCommands()); + + mRenderState->SetRenderTarget(image, depthStencil->View.get(), image->Image->width, image->Image->height, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT); + + IntRect bounds; + bounds.left = bounds.top = 0; + bounds.width = min(tex->GetWidth(), image->Image->width); + bounds.height = min(tex->GetHeight(), image->Image->height); + + renderFunc(bounds); + + mRenderState->EndRenderPass(); + + VkImageTransition() + .AddImage(image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false) + .Execute(mCommands->GetDrawCommands()); + + mRenderState->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); + + tex->SetUpdated(true); +} + +void VulkanRenderDevice::PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) +{ + if (!swscene) mPostprocess->BlitSceneToPostprocess(); // Copy the resulting scene to the current post process texture + mPostprocess->PostProcessScene(fixedcm, flash, afterBloomDrawEndScene2D); +} + +const char* VulkanRenderDevice::DeviceName() const +{ + return device->PhysicalDevice.Properties.Properties.deviceName; +} + +void VulkanRenderDevice::SetVSync(bool vsync) +{ + mVSync = vsync; +} + +void VulkanRenderDevice::PrecacheMaterial(FMaterial *mat, int translation) +{ + if (mat->Source()->GetUseType() == ETextureType::SWCanvas) return; + + MaterialLayerInfo* layer; + + auto systex = static_cast(mat->GetLayer(0, translation, &layer)); + systex->GetImage(layer->layerTexture, translation, layer->scaleFlags); + + int numLayers = mat->NumLayers(); + for (int i = 1; i < numLayers; i++) + { + auto syslayer = static_cast(mat->GetLayer(i, 0, &layer)); + syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); + } +} + +IHardwareTexture *VulkanRenderDevice::CreateHardwareTexture(int numchannels) +{ + return new VkHardwareTexture(this, numchannels); +} + +FMaterial* VulkanRenderDevice::CreateMaterial(FGameTexture* tex, int scaleflags) +{ + return new VkMaterial(this, tex, scaleflags); +} + +IVertexBuffer *VulkanRenderDevice::CreateVertexBuffer() +{ + return GetBufferManager()->CreateVertexBuffer(); +} + +IIndexBuffer *VulkanRenderDevice::CreateIndexBuffer() +{ + return GetBufferManager()->CreateIndexBuffer(); +} + +IDataBuffer *VulkanRenderDevice::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) +{ + return GetBufferManager()->CreateDataBuffer(bindingpoint, ssbo, needsresize); +} + +void VulkanRenderDevice::SetTextureFilterMode() +{ + if (mSamplerManager) + { + mDescriptorSetManager->ResetHWTextureSets(); + mSamplerManager->ResetHWSamplers(); + } +} + +void VulkanRenderDevice::StartPrecaching() +{ + // Destroy the texture descriptors to avoid problems with potentially stale textures. + mDescriptorSetManager->ResetHWTextureSets(); +} + +void VulkanRenderDevice::BlurScene(float amount) +{ + if (mPostprocess) + mPostprocess->BlurScene(amount); +} + +void VulkanRenderDevice::UpdatePalette() +{ + if (mPostprocess) + mPostprocess->ClearTonemapPalette(); +} + +FTexture *VulkanRenderDevice::WipeStartScreen() +{ + SetViewportRects(nullptr); + + auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1); + auto systex = static_cast(tex->GetSystemTexture()); + + systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeStartScreen"); + + return tex; +} + +FTexture *VulkanRenderDevice::WipeEndScreen() +{ + GetPostprocess()->SetActiveRenderTarget(); + Draw2D(); + twod->Clear(); + + auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1); + auto systex = static_cast(tex->GetSystemTexture()); + + systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeEndScreen"); + + return tex; +} + +void VulkanRenderDevice::CopyScreenToBuffer(int w, int h, uint8_t *data) +{ + VkTextureImage image; + + // Convert from rgba16f to rgba8 using the GPU: + image.Image = ImageBuilder() + .Format(VK_FORMAT_R8G8B8A8_UNORM) + .Usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .Size(w, h) + .DebugName("CopyScreenToBuffer") + .Create(device.get()); + + GetPostprocess()->BlitCurrentToImage(&image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + // Staging buffer for download + auto staging = BufferBuilder() + .Size(w * h * 4) + .Usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU) + .DebugName("CopyScreenToBuffer") + .Create(device.get()); + + // Copy from image to buffer + VkBufferImageCopy region = {}; + region.imageExtent.width = w; + region.imageExtent.height = h; + region.imageExtent.depth = 1; + region.imageSubresource.layerCount = 1; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + mCommands->GetDrawCommands()->copyImageToBuffer(image.Image->image, image.Layout, staging->buffer, 1, ®ion); + + // Submit command buffers and wait for device to finish the work + mCommands->WaitForCommands(false); + + // Map and convert from rgba8 to rgb8 + uint8_t *dest = (uint8_t*)data; + uint8_t *pixels = (uint8_t*)staging->Map(0, w * h * 4); + int dindex = 0; + for (int y = 0; y < h; y++) + { + int sindex = (h - y - 1) * w * 4; + for (int x = 0; x < w; x++) + { + dest[dindex] = pixels[sindex]; + dest[dindex + 1] = pixels[sindex + 1]; + dest[dindex + 2] = pixels[sindex + 2]; + dindex += 3; + sindex += 4; + } + } + staging->Unmap(); +} + +void VulkanRenderDevice::SetActiveRenderTarget() +{ + mPostprocess->SetActiveRenderTarget(); +} + +TArray VulkanRenderDevice::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) +{ + int w = SCREENWIDTH; + int h = SCREENHEIGHT; + + IntRect box; + box.left = 0; + box.top = 0; + box.width = w; + box.height = h; + mPostprocess->DrawPresentTexture(box, true, true); + + TArray ScreenshotBuffer(w * h * 3, true); + CopyScreenToBuffer(w, h, ScreenshotBuffer.Data()); + + pitch = w * 3; + color_type = SS_RGB; + gamma = 1.0f; + return ScreenshotBuffer; +} + +void VulkanRenderDevice::BeginFrame() +{ + SetViewportRects(nullptr); + mViewpoints->Clear(); + mCommands->BeginFrame(); + mTextureManager->BeginFrame(); + mScreenBuffers->BeginFrame(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height); + mSaveBuffers->BeginFrame(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT); + mRenderState->BeginFrame(); + mDescriptorSetManager->BeginFrame(); +} + +void VulkanRenderDevice::InitLightmap(int LMTextureSize, int LMTextureCount, TArray& LMTextureData) +{ + if (LMTextureData.Size() > 0) + { + GetTextureManager()->SetLightmap(LMTextureSize, LMTextureCount, LMTextureData); + LMTextureData.Reset(); // We no longer need this, release the memory + } +} + +void VulkanRenderDevice::Draw2D() +{ + ::Draw2D(twod, *mRenderState); +} + +void VulkanRenderDevice::WaitForCommands(bool finish) +{ + mCommands->WaitForCommands(finish); +} + +unsigned int VulkanRenderDevice::GetLightBufferBlockSize() const +{ + return mLights->GetBlockSize(); +} + +void VulkanRenderDevice::PrintStartupLog() +{ + const auto &props = device->PhysicalDevice.Properties.Properties; + + FString deviceType; + switch (props.deviceType) + { + case VK_PHYSICAL_DEVICE_TYPE_OTHER: deviceType = "other"; break; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: deviceType = "integrated gpu"; break; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: deviceType = "discrete gpu"; break; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: deviceType = "virtual gpu"; break; + case VK_PHYSICAL_DEVICE_TYPE_CPU: deviceType = "cpu"; break; + default: deviceType.Format("%d", (int)props.deviceType); break; + } + + FString apiVersion, driverVersion; + apiVersion.Format("%d.%d.%d", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion)); + driverVersion.Format("%d.%d.%d", VK_VERSION_MAJOR(props.driverVersion), VK_VERSION_MINOR(props.driverVersion), VK_VERSION_PATCH(props.driverVersion)); + vkversion = VK_API_VERSION_MAJOR(props.apiVersion) * 100 + VK_API_VERSION_MINOR(props.apiVersion); + + Printf("Vulkan device: " TEXTCOLOR_ORANGE "%s\n", props.deviceName); + Printf("Vulkan device type: %s\n", deviceType.GetChars()); + Printf("Vulkan version: %s (api) %s (driver)\n", apiVersion.GetChars(), driverVersion.GetChars()); + + Printf(PRINT_LOG, "Vulkan extensions:"); + for (const VkExtensionProperties &p : device->PhysicalDevice.Extensions) + { + Printf(PRINT_LOG, " %s", p.extensionName); + } + Printf(PRINT_LOG, "\n"); + + const auto &limits = props.limits; + Printf("Max. texture size: %d\n", limits.maxImageDimension2D); + Printf("Max. uniform buffer range: %d\n", limits.maxUniformBufferRange); + Printf("Min. uniform buffer offset alignment: %" PRIu64 "\n", limits.minUniformBufferOffsetAlignment); +} + +void VulkanRenderDevice::SetLevelMesh(hwrenderer::LevelMesh* mesh) +{ + mRaytrace->SetLevelMesh(mesh); +} + +void VulkanRenderDevice::UpdateShadowMap() +{ + mPostprocess->UpdateShadowMap(); +} + +void VulkanRenderDevice::SetSaveBuffers(bool yes) +{ + if (yes) mActiveRenderBuffers = mSaveBuffers.get(); + else mActiveRenderBuffers = mScreenBuffers.get(); +} + +void VulkanRenderDevice::ImageTransitionScene(bool unknown) +{ + mPostprocess->ImageTransitionScene(unknown); +} + +FRenderState* VulkanRenderDevice::RenderState() +{ + return mRenderState.get(); +} + +void VulkanRenderDevice::AmbientOccludeScene(float m5) +{ + mPostprocess->AmbientOccludeScene(m5); +} + +void VulkanRenderDevice::SetSceneRenderTarget(bool useSSAO) +{ + mRenderState->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); +} + +bool VulkanRenderDevice::RaytracingEnabled() +{ + return vk_raytrace && device->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME); +} diff --git a/src/common/rendering/vulkan/system/vk_renderdevice.h b/src/common/rendering/vulkan/system/vk_renderdevice.h new file mode 100644 index 00000000000..6b11536711a --- /dev/null +++ b/src/common/rendering/vulkan/system/vk_renderdevice.h @@ -0,0 +1,125 @@ +#pragma once + +#include "gl_sysfb.h" +#include "engineerrors.h" +#include +#include + +struct FRenderViewpoint; +class VkSamplerManager; +class VkBufferManager; +class VkTextureManager; +class VkShaderManager; +class VkCommandBufferManager; +class VkDescriptorSetManager; +class VkRenderPassManager; +class VkFramebufferManager; +class VkRaytrace; +class VkRenderState; +class VkStreamBuffer; +class VkHardwareDataBuffer; +class VkHardwareTexture; +class VkRenderBuffers; +class VkPostprocess; +class SWSceneDrawer; + +class VulkanRenderDevice : public SystemBaseFrameBuffer +{ + typedef SystemBaseFrameBuffer Super; + + +public: + std::shared_ptr device; + + VkCommandBufferManager* GetCommands() { return mCommands.get(); } + VkShaderManager *GetShaderManager() { return mShaderManager.get(); } + VkSamplerManager *GetSamplerManager() { return mSamplerManager.get(); } + VkBufferManager* GetBufferManager() { return mBufferManager.get(); } + VkTextureManager* GetTextureManager() { return mTextureManager.get(); } + VkFramebufferManager* GetFramebufferManager() { return mFramebufferManager.get(); } + VkDescriptorSetManager* GetDescriptorSetManager() { return mDescriptorSetManager.get(); } + VkRenderPassManager *GetRenderPassManager() { return mRenderPassManager.get(); } + VkRaytrace* GetRaytrace() { return mRaytrace.get(); } + VkRenderState *GetRenderState() { return mRenderState.get(); } + VkPostprocess *GetPostprocess() { return mPostprocess.get(); } + VkRenderBuffers *GetBuffers() { return mActiveRenderBuffers; } + FRenderState* RenderState() override; + + unsigned int GetLightBufferBlockSize() const; + + VulkanRenderDevice(void *hMonitor, bool fullscreen, std::shared_ptr surface); + ~VulkanRenderDevice(); + bool IsVulkan() override { return true; } + + void Update() override; + + void InitializeState() override; + bool CompileNextShader() override; + void PrecacheMaterial(FMaterial *mat, int translation) override; + void UpdatePalette() override; + const char* DeviceName() const override; + int Backend() override { return 1; } + void SetTextureFilterMode() override; + void StartPrecaching() override; + void BeginFrame() override; + void InitLightmap(int LMTextureSize, int LMTextureCount, TArray& LMTextureData) override; + void BlurScene(float amount) override; + void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) override; + void AmbientOccludeScene(float m5) override; + void SetSceneRenderTarget(bool useSSAO) override; + void SetLevelMesh(hwrenderer::LevelMesh* mesh) override; + void UpdateShadowMap() override; + void SetSaveBuffers(bool yes) override; + void ImageTransitionScene(bool unknown) override; + void SetActiveRenderTarget() override; + + IHardwareTexture *CreateHardwareTexture(int numchannels) override; + FMaterial* CreateMaterial(FGameTexture* tex, int scaleflags) override; + IVertexBuffer *CreateVertexBuffer() override; + IIndexBuffer *CreateIndexBuffer() override; + IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override; + + FTexture *WipeStartScreen() override; + FTexture *WipeEndScreen() override; + + TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override; + + bool GetVSync() { return mVSync; } + void SetVSync(bool vsync) override; + + void Draw2D() override; + + void WaitForCommands(bool finish) override; + + bool RaytracingEnabled(); + +private: + void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) override; + void PrintStartupLog(); + void CopyScreenToBuffer(int w, int h, uint8_t *data) override; + + std::unique_ptr mCommands; + std::unique_ptr mBufferManager; + std::unique_ptr mSamplerManager; + std::unique_ptr mTextureManager; + std::unique_ptr mFramebufferManager; + std::unique_ptr mShaderManager; + std::unique_ptr mScreenBuffers; + std::unique_ptr mSaveBuffers; + std::unique_ptr mPostprocess; + std::unique_ptr mDescriptorSetManager; + std::unique_ptr mRenderPassManager; + std::unique_ptr mRaytrace; + std::unique_ptr mRenderState; + + VkRenderBuffers *mActiveRenderBuffers = nullptr; + + bool mVSync = false; +}; + +class CVulkanError : public CEngineError +{ +public: + CVulkanError() : CEngineError() {} + CVulkanError(const char* message) : CEngineError(message) {} +}; diff --git a/src/common/rendering/vulkan/textures/vk_framebuffer.cpp b/src/common/rendering/vulkan/textures/vk_framebuffer.cpp new file mode 100644 index 00000000000..c32e73b9d43 --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_framebuffer.cpp @@ -0,0 +1,79 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include +#include +#include +#include +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/renderer/vk_postprocess.h" +#include "vk_framebuffer.h" + +CVAR(Bool, vk_hdr, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, vk_exclusivefullscreen, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); + +VkFramebufferManager::VkFramebufferManager(VulkanRenderDevice* fb) : fb(fb) +{ + SwapChain = VulkanSwapChainBuilder() + .Create(fb->device.get()); + + SwapChainImageAvailableSemaphore = SemaphoreBuilder() + .DebugName("SwapChainImageAvailableSemaphore") + .Create(fb->device.get()); + + RenderFinishedSemaphore = SemaphoreBuilder() + .DebugName("RenderFinishedSemaphore") + .Create(fb->device.get()); +} + +VkFramebufferManager::~VkFramebufferManager() +{ +} + +void VkFramebufferManager::AcquireImage() +{ + bool exclusiveFullscreen = fb->IsFullscreen() && vk_exclusivefullscreen; + if (SwapChain->Lost() || fb->GetClientWidth() != CurrentWidth || fb->GetClientHeight() != CurrentHeight || fb->GetVSync() != CurrentVSync || CurrentHdr != vk_hdr || CurrentExclusiveFullscreen != exclusiveFullscreen) + { + Framebuffers.clear(); + + CurrentWidth = fb->GetClientWidth(); + CurrentHeight = fb->GetClientHeight(); + CurrentVSync = fb->GetVSync(); + CurrentHdr = vk_hdr; + CurrentExclusiveFullscreen = exclusiveFullscreen; + + SwapChain->Create(CurrentWidth, CurrentHeight, CurrentVSync ? 2 : 3, CurrentVSync, CurrentHdr, CurrentExclusiveFullscreen); + } + + PresentImageIndex = SwapChain->AcquireImage(SwapChainImageAvailableSemaphore.get()); + if (PresentImageIndex != -1) + { + fb->GetPostprocess()->DrawPresentTexture(fb->mOutputLetterbox, true, false); + } +} + +void VkFramebufferManager::QueuePresent() +{ + if (PresentImageIndex != -1) + SwapChain->QueuePresent(PresentImageIndex, RenderFinishedSemaphore.get()); +} diff --git a/src/common/rendering/vulkan/textures/vk_framebuffer.h b/src/common/rendering/vulkan/textures/vk_framebuffer.h new file mode 100644 index 00000000000..06cc6a261ce --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_framebuffer.h @@ -0,0 +1,36 @@ + +#pragma once + +#include "zvulkan/vulkanobjects.h" +#include +#include + +class VulkanRenderDevice; +enum class PPFilterMode; +enum class PPWrapMode; + +class VkFramebufferManager +{ +public: + VkFramebufferManager(VulkanRenderDevice* fb); + ~VkFramebufferManager(); + + void AcquireImage(); + void QueuePresent(); + + std::map> Framebuffers; + + std::shared_ptr SwapChain; + int PresentImageIndex = -1; + + std::unique_ptr SwapChainImageAvailableSemaphore; + std::unique_ptr RenderFinishedSemaphore; + +private: + VulkanRenderDevice* fb = nullptr; + int CurrentWidth = 0; + int CurrentHeight = 0; + bool CurrentVSync = false; + bool CurrentHdr = false; + bool CurrentExclusiveFullscreen = false; +}; diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp new file mode 100644 index 00000000000..a4975b79223 --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp @@ -0,0 +1,387 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + + +#include "c_cvars.h" +#include "hw_material.h" +#include "hw_cvars.h" +#include "hw_renderstate.h" +#include +#include +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "vulkan/textures/vk_samplers.h" +#include "vulkan/textures/vk_renderbuffers.h" +#include "vulkan/textures/vk_texture.h" +#include "vulkan/renderer/vk_descriptorset.h" +#include "vulkan/renderer/vk_postprocess.h" +#include "vulkan/shaders/vk_shader.h" +#include "vk_hwtexture.h" + +VkHardwareTexture::VkHardwareTexture(VulkanRenderDevice* fb, int numchannels) : fb(fb) +{ + mTexelsize = numchannels; + fb->GetTextureManager()->AddTexture(this); +} + +VkHardwareTexture::~VkHardwareTexture() +{ + if (fb) + fb->GetTextureManager()->RemoveTexture(this); +} + +void VkHardwareTexture::Reset() +{ + if (fb) + { + if (mappedSWFB) + { + mImage.Image->Unmap(); + mappedSWFB = nullptr; + } + + mImage.Reset(fb); + mDepthStencil.Reset(fb); + } +} + +VkTextureImage *VkHardwareTexture::GetImage(FTexture *tex, int translation, int flags) +{ + if (!mImage.Image) + { + CreateImage(tex, translation, flags); + } + return &mImage; +} + +VkTextureImage *VkHardwareTexture::GetDepthStencil(FTexture *tex) +{ + if (!mDepthStencil.View) + { + VkFormat format = fb->GetBuffers()->SceneDepthStencilFormat; + int w = tex->GetWidth(); + int h = tex->GetHeight(); + + mDepthStencil.Image = ImageBuilder() + .Size(w, h) + .Samples(VK_SAMPLE_COUNT_1_BIT) + .Format(format) + .Usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) + .DebugName("VkHardwareTexture.DepthStencil") + .Create(fb->device.get()); + + mDepthStencil.AspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + + mDepthStencil.View = ImageViewBuilder() + .Image(mDepthStencil.Image.get(), format, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) + .DebugName("VkHardwareTexture.DepthStencilView") + .Create(fb->device.get()); + + VkImageTransition() + .AddImage(&mDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true) + .Execute(fb->GetCommands()->GetTransferCommands()); + } + return &mDepthStencil; +} + +void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) +{ + if (!tex->isHardwareCanvas()) + { + FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); + bool indexed = flags & CTF_Indexed; + CreateTexture(texbuffer.mWidth, texbuffer.mHeight,indexed? 1 : 4, indexed? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed); + } + else + { + VkFormat format = tex->IsHDR() ? VK_FORMAT_R32G32B32A32_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM; + int w = tex->GetWidth(); + int h = tex->GetHeight(); + + mImage.Image = ImageBuilder() + .Format(format) + .Size(w, h) + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) + .DebugName("VkHardwareTexture.mImage") + .Create(fb->device.get()); + + mImage.View = ImageViewBuilder() + .Image(mImage.Image.get(), format) + .DebugName("VkHardwareTexture.mImageView") + .Create(fb->device.get()); + + VkImageTransition() + .AddImage(&mImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true) + .Execute(fb->GetCommands()->GetTransferCommands()); + } +} + +void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap) +{ + if (w <= 0 || h <= 0) + throw CVulkanError("Trying to create zero size texture"); + + int totalSize = w * h * pixelsize; + + auto stagingBuffer = BufferBuilder() + .Size(totalSize) + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .DebugName("VkHardwareTexture.mStagingBuffer") + .Create(fb->device.get()); + + uint8_t *data = (uint8_t*)stagingBuffer->Map(0, totalSize); + memcpy(data, pixels, totalSize); + stagingBuffer->Unmap(); + + mImage.Image = ImageBuilder() + .Format(format) + .Size(w, h, !mipmap ? 1 : GetMipLevels(w, h)) + .Usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) + .DebugName("VkHardwareTexture.mImage") + .Create(fb->device.get()); + + mImage.View = ImageViewBuilder() + .Image(mImage.Image.get(), format) + .DebugName("VkHardwareTexture.mImageView") + .Create(fb->device.get()); + + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + VkImageTransition() + .AddImage(&mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) + .Execute(cmdbuffer); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.depth = 1; + region.imageExtent.width = w; + region.imageExtent.height = h; + cmdbuffer->copyBufferToImage(stagingBuffer->buffer, mImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + if (mipmap) mImage.GenerateMipmaps(cmdbuffer); + + // If we queued more than 64 MB of data already: wait until the uploads finish before continuing + fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); + if (fb->GetCommands()->TransferDeleteList->TotalSize > 64 * 1024 * 1024) + fb->GetCommands()->WaitForCommands(false, true); +} + +int VkHardwareTexture::GetMipLevels(int w, int h) +{ + int levels = 1; + while (w > 1 || h > 1) + { + w = max(w >> 1, 1); + h = max(h >> 1, 1); + levels++; + } + return levels; +} + +void VkHardwareTexture::AllocateBuffer(int w, int h, int texelsize) +{ + if (mImage.Image && (mImage.Image->width != w || mImage.Image->height != h || mTexelsize != texelsize)) + { + Reset(); + } + + if (!mImage.Image) + { + VkFormat format = texelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM; + + VkDeviceSize allocatedBytes = 0; + mImage.Image = ImageBuilder() + .Format(format) + .Size(w, h) + .LinearTiling() + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) + .MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + .DebugName("VkHardwareTexture.mImage") + .Create(fb->device.get(), &allocatedBytes); + + mTexelsize = texelsize; + + mImage.View = ImageViewBuilder() + .Image(mImage.Image.get(), format) + .DebugName("VkHardwareTexture.mImageView") + .Create(fb->device.get()); + + VkImageTransition() + .AddImage(&mImage, VK_IMAGE_LAYOUT_GENERAL, true) + .Execute(fb->GetCommands()->GetTransferCommands()); + + bufferpitch = int(allocatedBytes / h / texelsize); + } +} + +uint8_t *VkHardwareTexture::MapBuffer() +{ + if (!mappedSWFB) + mappedSWFB = (uint8_t*)mImage.Image->Map(0, mImage.Image->width * mImage.Image->height * mTexelsize); + return mappedSWFB; +} + +unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) +{ + // CreateTexture is used by the software renderer to create a screen output but without any screen data. + if (buffer) + CreateTexture(w, h, mTexelsize, mTexelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM, buffer, mipmap); + return 0; +} + +void VkHardwareTexture::CreateWipeTexture(int w, int h, const char *name) +{ + VkFormat format = VK_FORMAT_B8G8R8A8_UNORM; + + mImage.Image = ImageBuilder() + .Format(format) + .Size(w, h) + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY) + .DebugName(name) + .Create(fb->device.get()); + + mTexelsize = 4; + + mImage.View = ImageViewBuilder() + .Image(mImage.Image.get(), format) + .DebugName(name) + .Create(fb->device.get()); + + if (fb->GetBuffers()->GetWidth() > 0 && fb->GetBuffers()->GetHeight() > 0) + { + fb->GetPostprocess()->BlitCurrentToImage(&mImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + else + { + // hwrenderer asked image data from a frame buffer that was never written into. Let's give it that.. + // (ideally the hwrenderer wouldn't do this, but the calling code is too complex for me to fix) + + VkImageTransition() + .AddImage(&mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) + .Execute(fb->GetCommands()->GetTransferCommands()); + + VkImageSubresourceRange range = {}; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + range.layerCount = 1; + range.levelCount = 1; + + VkClearColorValue value = {}; + value.float32[0] = 0.0f; + value.float32[1] = 0.0f; + value.float32[2] = 0.0f; + value.float32[3] = 1.0f; + fb->GetCommands()->GetTransferCommands()->clearColorImage(mImage.Image->image, mImage.Layout, &value, 1, &range); + + VkImageTransition() + .AddImage(&mImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false) + .Execute(fb->GetCommands()->GetTransferCommands()); + } +} + +///////////////////////////////////////////////////////////////////////////// + +VkMaterial::VkMaterial(VulkanRenderDevice* fb, FGameTexture* tex, int scaleflags) : FMaterial(tex, scaleflags), fb(fb) +{ + fb->GetDescriptorSetManager()->AddMaterial(this); +} + +VkMaterial::~VkMaterial() +{ + if (fb) + fb->GetDescriptorSetManager()->RemoveMaterial(this); +} + +void VkMaterial::DeleteDescriptors() +{ + if (fb) + { + auto deleteList = fb->GetCommands()->DrawDeleteList.get(); + for (auto& it : mDescriptorSets) + { + deleteList->Add(std::move(it.descriptor)); + } + mDescriptorSets.clear(); + } +} + +VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) +{ + auto base = Source(); + int clampmode = state.mClampMode; + int translation = state.mTranslation; + auto translationp = IsLuminosityTranslation(translation)? translation : intptr_t(GPalette.GetTranslation(GetTranslationType(translation), GetTranslationIndex(translation))); + + clampmode = base->GetClampMode(clampmode); + + for (auto& set : mDescriptorSets) + { + if (set.descriptor && set.clampmode == clampmode && set.remap == translationp) return set.descriptor.get(); + } + + int numLayers = NumLayers(); + + auto descriptor = fb->GetDescriptorSetManager()->AllocateTextureDescriptorSet(max(numLayers, SHADER_MIN_REQUIRED_TEXTURE_LAYERS)); + + descriptor->SetDebugName("VkHardwareTexture.mDescriptorSets"); + + VulkanSampler* sampler = fb->GetSamplerManager()->Get(clampmode); + + WriteDescriptors update; + MaterialLayerInfo *layer; + auto systex = static_cast(GetLayer(0, state.mTranslation, &layer)); + auto systeximage = systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags); + update.AddCombinedImageSampler(descriptor.get(), 0, systeximage->View.get(), sampler, systeximage->Layout); + + if (!(layer->scaleFlags & CTF_Indexed)) + { + for (int i = 1; i < numLayers; i++) + { + auto syslayer = static_cast(GetLayer(i, 0, &layer)); + auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); + update.AddCombinedImageSampler(descriptor.get(), i, syslayerimage->View.get(), sampler, syslayerimage->Layout); + } + } + else + { + for (int i = 1; i < 3; i++) + { + auto syslayer = static_cast(GetLayer(i, translation, &layer)); + auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); + update.AddCombinedImageSampler(descriptor.get(), i, syslayerimage->View.get(), sampler, syslayerimage->Layout); + } + numLayers = 3; + } + + auto dummyImage = fb->GetTextureManager()->GetNullTextureView(); + for (int i = numLayers; i < SHADER_MIN_REQUIRED_TEXTURE_LAYERS; i++) + { + update.AddCombinedImageSampler(descriptor.get(), i, dummyImage, sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + + update.Execute(fb->device.get()); + mDescriptorSets.emplace_back(clampmode, translationp, std::move(descriptor)); + return mDescriptorSets.back().descriptor.get(); +} + diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.h b/src/common/rendering/vulkan/textures/vk_hwtexture.h new file mode 100644 index 00000000000..2711bdb33d0 --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.h @@ -0,0 +1,91 @@ +#pragma once + +#ifdef LoadImage +#undef LoadImage +#endif + +#define SHADED_TEXTURE -1 +#define DIRECT_PALETTE -2 + +#include "tarray.h" +#include "hw_ihwtexture.h" +#include +#include "vk_imagetransition.h" +#include "hw_material.h" +#include + +struct FMaterialState; +class VulkanDescriptorSet; +class VulkanImage; +class VulkanImageView; +class VulkanBuffer; +class VulkanRenderDevice; +class FGameTexture; + +class VkHardwareTexture : public IHardwareTexture +{ + friend class VkMaterial; +public: + VkHardwareTexture(VulkanRenderDevice* fb, int numchannels); + ~VkHardwareTexture(); + + void Reset(); + + // Software renderer stuff + void AllocateBuffer(int w, int h, int texelsize) override; + uint8_t *MapBuffer() override; + unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) override; + + // Wipe screen + void CreateWipeTexture(int w, int h, const char *name); + + VkTextureImage *GetImage(FTexture *tex, int translation, int flags); + VkTextureImage *GetDepthStencil(FTexture *tex); + + VulkanRenderDevice* fb = nullptr; + std::list::iterator it; + +private: + void CreateImage(FTexture *tex, int translation, int flags); + + void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap); + static int GetMipLevels(int w, int h); + + VkTextureImage mImage; + int mTexelsize = 4; + + VkTextureImage mDepthStencil; + + uint8_t* mappedSWFB = nullptr; +}; + +class VkMaterial : public FMaterial +{ +public: + VkMaterial(VulkanRenderDevice* fb, FGameTexture* tex, int scaleflags); + ~VkMaterial(); + + VulkanDescriptorSet* GetDescriptorSet(const FMaterialState& state); + + void DeleteDescriptors() override; + + VulkanRenderDevice* fb = nullptr; + std::list::iterator it; + +private: + struct DescriptorEntry + { + int clampmode; + intptr_t remap; + std::unique_ptr descriptor; + + DescriptorEntry(int cm, intptr_t f, std::unique_ptr&& d) + { + clampmode = cm; + remap = f; + descriptor = std::move(d); + } + }; + + std::vector mDescriptorSets; +}; diff --git a/src/common/rendering/vulkan/textures/vk_imagetransition.cpp b/src/common/rendering/vulkan/textures/vk_imagetransition.cpp new file mode 100644 index 00000000000..dd281e7bdad --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_imagetransition.cpp @@ -0,0 +1,152 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_imagetransition.h" + +VkImageTransition& VkImageTransition::AddImage(VkTextureImage *image, VkImageLayout targetLayout, bool undefinedSrcLayout, int baseMipLevel, int levelCount) +{ + if (image->Layout == targetLayout) + return *this; + + VkAccessFlags srcAccess = 0; + VkAccessFlags dstAccess = 0; + VkImageAspectFlags aspectMask = image->AspectMask; + + switch (image->Layout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + srcAccess = 0; + srcStageMask |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + srcAccess = VK_ACCESS_TRANSFER_READ_BIT; + srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + srcAccess = VK_ACCESS_SHADER_READ_BIT; + srcStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + srcAccess = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + srcAccess = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + srcAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + srcStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + default: + I_FatalError("Unimplemented src image layout transition\n"); + } + + switch (targetLayout) + { + case VK_IMAGE_LAYOUT_GENERAL: + dstAccess = 0; + dstStageMask |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + dstAccess = VK_ACCESS_TRANSFER_READ_BIT; + dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + dstAccess = VK_ACCESS_SHADER_READ_BIT; + dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + dstAccess = VK_ACCESS_TRANSFER_WRITE_BIT; + dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + dstAccess = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dstStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + dstAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + default: + I_FatalError("Unimplemented dst image layout transition\n"); + } + + barrier.AddImage(image->Image.get(), undefinedSrcLayout ? VK_IMAGE_LAYOUT_UNDEFINED : image->Layout, targetLayout, srcAccess, dstAccess, aspectMask, baseMipLevel, levelCount); + needbarrier = true; + image->Layout = targetLayout; + return *this; +} + +void VkImageTransition::Execute(VulkanCommandBuffer *cmdbuffer) +{ + if (needbarrier) + barrier.Execute(cmdbuffer, srcStageMask, dstStageMask); +} + +///////////////////////////////////////////////////////////////////////////// + +void VkTextureImage::GenerateMipmaps(VulkanCommandBuffer *cmdbuffer) +{ + int mipWidth = Image->width; + int mipHeight = Image->height; + int i; + for (i = 1; mipWidth > 1 || mipHeight > 1; i++) + { + PipelineBarrier() + .AddImage(Image.get(), Layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, i - 1) + .AddImage(Image.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, i) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + Layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + int nextWidth = max(mipWidth >> 1, 1); + int nextHeight = max(mipHeight >> 1, 1); + + VkImageBlit blit = {}; + blit.srcOffsets[0] = { 0, 0, 0 }; + blit.srcOffsets[1] = { mipWidth, mipHeight, 1 }; + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.mipLevel = i - 1; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = 1; + blit.dstOffsets[0] = { 0, 0, 0 }; + blit.dstOffsets[1] = { nextWidth, nextHeight, 1 }; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.mipLevel = i; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = 1; + cmdbuffer->blitImage(Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); + + PipelineBarrier() + .AddImage(Image.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, i - 1) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + mipWidth = nextWidth; + mipHeight = nextHeight; + } + + PipelineBarrier() + .AddImage(Image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, i - 1) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + Layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; +} diff --git a/src/common/rendering/vulkan/textures/vk_imagetransition.h b/src/common/rendering/vulkan/textures/vk_imagetransition.h new file mode 100644 index 00000000000..9f1194bbf2d --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_imagetransition.h @@ -0,0 +1,49 @@ + +#pragma once + +#include "zvulkan/vulkanobjects.h" +#include "zvulkan/vulkanbuilders.h" +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "vulkan/renderer/vk_renderpass.h" + +class VkTextureImage +{ +public: + void Reset(VulkanRenderDevice* fb) + { + AspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + Layout = VK_IMAGE_LAYOUT_UNDEFINED; + auto deletelist = fb->GetCommands()->DrawDeleteList.get(); + deletelist->Add(std::move(PPFramebuffer)); + for (auto &it : RSFramebuffers) + deletelist->Add(std::move(it.second)); + RSFramebuffers.clear(); + deletelist->Add(std::move(DepthOnlyView)); + deletelist->Add(std::move(View)); + deletelist->Add(std::move(Image)); + } + + void GenerateMipmaps(VulkanCommandBuffer *cmdbuffer); + + std::unique_ptr Image; + std::unique_ptr View; + std::unique_ptr DepthOnlyView; + VkImageLayout Layout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageAspectFlags AspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + std::unique_ptr PPFramebuffer; + std::map> RSFramebuffers; +}; + +class VkImageTransition +{ +public: + VkImageTransition& AddImage(VkTextureImage *image, VkImageLayout targetLayout, bool undefinedSrcLayout, int baseMipLevel = 0, int levelCount = 1); + void Execute(VulkanCommandBuffer *cmdbuffer); + +private: + PipelineBarrier barrier; + VkPipelineStageFlags srcStageMask = 0; + VkPipelineStageFlags dstStageMask = 0; + bool needbarrier = false; +}; diff --git a/src/common/rendering/vulkan/textures/vk_pptexture.cpp b/src/common/rendering/vulkan/textures/vk_pptexture.cpp new file mode 100644 index 00000000000..94114d4b627 --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_pptexture.cpp @@ -0,0 +1,114 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_pptexture.h" +#include "vk_texture.h" +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_commandbuffer.h" + +VkPPTexture::VkPPTexture(VulkanRenderDevice* fb, PPTexture *texture) : fb(fb) +{ + VkFormat format; + int pixelsize; + switch (texture->Format) + { + default: + case PixelFormat::Rgba8: format = VK_FORMAT_R8G8B8A8_UNORM; pixelsize = 4; break; + case PixelFormat::Rgba16f: format = VK_FORMAT_R16G16B16A16_SFLOAT; pixelsize = 8; break; + case PixelFormat::R32f: format = VK_FORMAT_R32_SFLOAT; pixelsize = 4; break; + case PixelFormat::Rg16f: format = VK_FORMAT_R16G16_SFLOAT; pixelsize = 4; break; + case PixelFormat::Rgba16_snorm: format = VK_FORMAT_R16G16B16A16_SNORM; pixelsize = 8; break; + } + + ImageBuilder imgbuilder; + imgbuilder.Format(format); + imgbuilder.Size(texture->Width, texture->Height); + if (texture->Data) + imgbuilder.Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + else + imgbuilder.Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + imgbuilder.DebugName("VkPPTexture"); + if (!imgbuilder.IsFormatSupported(fb->device.get())) + I_FatalError("Vulkan device does not support the image format required by a postprocess texture\n"); + TexImage.Image = imgbuilder.Create(fb->device.get()); + Format = format; + + TexImage.View = ImageViewBuilder() + .Image(TexImage.Image.get(), format) + .DebugName("VkPPTextureView") + .Create(fb->device.get()); + + if (texture->Data) + { + size_t totalsize = texture->Width * texture->Height * pixelsize; + + Staging = BufferBuilder() + .Size(totalsize) + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .DebugName("VkPPTextureStaging") + .Create(fb->device.get()); + + VkImageTransition() + .AddImage(&TexImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true) + .Execute(fb->GetCommands()->GetTransferCommands()); + + void *data = Staging->Map(0, totalsize); + memcpy(data, texture->Data.get(), totalsize); + Staging->Unmap(); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.depth = 1; + region.imageExtent.width = texture->Width; + region.imageExtent.height = texture->Height; + fb->GetCommands()->GetTransferCommands()->copyBufferToImage(Staging->buffer, TexImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + VkImageTransition() + .AddImage(&TexImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false) + .Execute(fb->GetCommands()->GetTransferCommands()); + } + else + { + VkImageTransition() + .AddImage(&TexImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true) + .Execute(fb->GetCommands()->GetTransferCommands()); + } + + fb->GetTextureManager()->AddPPTexture(this); +} + +VkPPTexture::~VkPPTexture() +{ + if (fb) + fb->GetTextureManager()->RemovePPTexture(this); +} + +void VkPPTexture::Reset() +{ + if (fb) + { + TexImage.Reset(fb); + if (Staging) + fb->GetCommands()->DrawDeleteList->Add(std::move(Staging)); + } +} diff --git a/src/common/rendering/vulkan/textures/vk_pptexture.h b/src/common/rendering/vulkan/textures/vk_pptexture.h new file mode 100644 index 00000000000..e0544b0d029 --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_pptexture.h @@ -0,0 +1,25 @@ + +#pragma once + +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include +#include "vulkan/textures/vk_imagetransition.h" +#include + +class VulkanRenderDevice; + +class VkPPTexture : public PPTextureBackend +{ +public: + VkPPTexture(VulkanRenderDevice* fb, PPTexture *texture); + ~VkPPTexture(); + + void Reset(); + + VulkanRenderDevice* fb = nullptr; + std::list::iterator it; + + VkTextureImage TexImage; + std::unique_ptr Staging; + VkFormat Format; +}; diff --git a/src/common/rendering/vulkan/textures/vk_renderbuffers.cpp b/src/common/rendering/vulkan/textures/vk_renderbuffers.cpp new file mode 100644 index 00000000000..474934e675c --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_renderbuffers.cpp @@ -0,0 +1,305 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_renderbuffers.h" +#include "vulkan/renderer/vk_postprocess.h" +#include "vulkan/textures/vk_texture.h" +#include "vulkan/textures/vk_framebuffer.h" +#include "vulkan/shaders/vk_shader.h" +#include +#include +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "hw_cvars.h" + +VkRenderBuffers::VkRenderBuffers(VulkanRenderDevice* fb) : fb(fb) +{ +} + +VkRenderBuffers::~VkRenderBuffers() +{ +} + +VkSampleCountFlagBits VkRenderBuffers::GetBestSampleCount() +{ + const auto &limits = fb->device->PhysicalDevice.Properties.Properties.limits; + VkSampleCountFlags deviceSampleCounts = limits.sampledImageColorSampleCounts & limits.sampledImageDepthSampleCounts & limits.sampledImageStencilSampleCounts; + + int requestedSamples = clamp((int)gl_multisample, 0, 64); + + int samples = 1; + VkSampleCountFlags bit = VK_SAMPLE_COUNT_1_BIT; + VkSampleCountFlags best = bit; + while (samples <= requestedSamples) + { + if (deviceSampleCounts & bit) + { + best = bit; + } + samples <<= 1; + bit <<= 1; + } + return (VkSampleCountFlagBits)best; +} + +void VkRenderBuffers::BeginFrame(int width, int height, int sceneWidth, int sceneHeight) +{ + VkSampleCountFlagBits samples = GetBestSampleCount(); + + if (width != mWidth || height != mHeight || mSamples != samples) + { + fb->GetCommands()->WaitForCommands(false); + fb->GetRenderPassManager()->RenderBuffersReset(); + } + + if (width != mWidth || height != mHeight) + CreatePipeline(width, height); + + if (width != mWidth || height != mHeight || mSamples != samples) + CreateScene(width, height, samples); + + mWidth = width; + mHeight = height; + mSamples = samples; + mSceneWidth = sceneWidth; + mSceneHeight = sceneHeight; +} + +void VkRenderBuffers::CreatePipelineDepthStencil(int width, int height) +{ + ImageBuilder builder; + builder.Size(width, height); + builder.Format(PipelineDepthStencilFormat); + builder.Usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + if (!builder.IsFormatSupported(fb->device.get())) + { + PipelineDepthStencilFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; + builder.Format(PipelineDepthStencilFormat); + if (!builder.IsFormatSupported(fb->device.get())) + { + I_FatalError("This device does not support any of the required depth stencil image formats."); + } + } + builder.DebugName("VkRenderBuffers.PipelineDepthStencil"); + + PipelineDepthStencil.Image = builder.Create(fb->device.get()); + PipelineDepthStencil.AspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + + PipelineDepthStencil.View = ImageViewBuilder() + .Image(PipelineDepthStencil.Image.get(), PipelineDepthStencilFormat, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) + .DebugName("VkRenderBuffers.PipelineDepthStencilView") + .Create(fb->device.get()); + + PipelineDepthStencil.DepthOnlyView = ImageViewBuilder() + .Image(PipelineDepthStencil.Image.get(), PipelineDepthStencilFormat, VK_IMAGE_ASPECT_DEPTH_BIT) + .DebugName("VkRenderBuffers.PipelineDepthView") + .Create(fb->device.get()); +} + +void VkRenderBuffers::CreatePipeline(int width, int height) +{ + for (int i = 0; i < NumPipelineImages; i++) + { + PipelineImage[i].Reset(fb); + } + PipelineDepthStencil.Reset(fb); + + CreatePipelineDepthStencil(width, height); + + VkImageTransition barrier; + barrier.AddImage(&PipelineDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true); + for (int i = 0; i < NumPipelineImages; i++) + { + PipelineImage[i].Image = ImageBuilder() + .Size(width, height) + .Format(VK_FORMAT_R16G16B16A16_SFLOAT) + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .DebugName("VkRenderBuffers.PipelineImage") + .Create(fb->device.get()); + + PipelineImage[i].View = ImageViewBuilder() + .Image(PipelineImage[i].Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("VkRenderBuffers.PipelineView") + .Create(fb->device.get()); + + barrier.AddImage(&PipelineImage[i], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); + } + barrier.Execute(fb->GetCommands()->GetDrawCommands()); +} + +void VkRenderBuffers::CreateScene(int width, int height, VkSampleCountFlagBits samples) +{ + SceneColor.Reset(fb); + SceneDepthStencil.Reset(fb); + SceneNormal.Reset(fb); + SceneFog.Reset(fb); + + CreateSceneColor(width, height, samples); + CreateSceneDepthStencil(width, height, samples); + CreateSceneNormal(width, height, samples); + CreateSceneFog(width, height, samples); + + VkImageTransition() + .AddImage(&SceneColor, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true) + .AddImage(&SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true) + .AddImage(&SceneNormal, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true) + .AddImage(&SceneFog, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true) + .Execute(fb->GetCommands()->GetDrawCommands()); +} + +void VkRenderBuffers::CreateSceneColor(int width, int height, VkSampleCountFlagBits samples) +{ + SceneColor.Image = ImageBuilder() + .Size(width, height) + .Samples(samples) + .Format(VK_FORMAT_R16G16B16A16_SFLOAT) + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) + .DebugName("VkRenderBuffers.SceneColor") + .Create(fb->device.get()); + + SceneColor.View = ImageViewBuilder() + .Image(SceneColor.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("VkRenderBuffers.SceneColorView") + .Create(fb->device.get()); +} + +void VkRenderBuffers::CreateSceneDepthStencil(int width, int height, VkSampleCountFlagBits samples) +{ + ImageBuilder builder; + builder.Size(width, height); + builder.Samples(samples); + builder.Format(SceneDepthStencilFormat); + builder.Usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + if (!builder.IsFormatSupported(fb->device.get())) + { + SceneDepthStencilFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; + builder.Format(SceneDepthStencilFormat); + if (!builder.IsFormatSupported(fb->device.get())) + { + I_FatalError("This device does not support any of the required depth stencil image formats."); + } + } + builder.DebugName("VkRenderBuffers.SceneDepthStencil"); + + SceneDepthStencil.Image = builder.Create(fb->device.get()); + SceneDepthStencil.AspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + + SceneDepthStencil.View = ImageViewBuilder() + .Image(SceneDepthStencil.Image.get(), SceneDepthStencilFormat, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) + .DebugName("VkRenderBuffers.SceneDepthStencilView") + .Create(fb->device.get()); + + SceneDepthStencil.DepthOnlyView = ImageViewBuilder() + .Image(SceneDepthStencil.Image.get(), SceneDepthStencilFormat, VK_IMAGE_ASPECT_DEPTH_BIT) + .DebugName("VkRenderBuffers.SceneDepthView") + .Create(fb->device.get()); +} + +void VkRenderBuffers::CreateSceneFog(int width, int height, VkSampleCountFlagBits samples) +{ + SceneFog.Image = ImageBuilder() + .Size(width, height) + .Samples(samples) + .Format(VK_FORMAT_R8G8B8A8_UNORM) + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) + .DebugName("VkRenderBuffers.SceneFog") + .Create(fb->device.get()); + + SceneFog.View = ImageViewBuilder() + .Image(SceneFog.Image.get(), VK_FORMAT_R8G8B8A8_UNORM) + .DebugName("VkRenderBuffers.SceneFogView") + .Create(fb->device.get()); +} + +void VkRenderBuffers::CreateSceneNormal(int width, int height, VkSampleCountFlagBits samples) +{ + ImageBuilder builder; + builder.Size(width, height); + builder.Samples(samples); + builder.Format(SceneNormalFormat); + builder.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + if (!builder.IsFormatSupported(fb->device.get(), VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) + { + SceneNormalFormat = VK_FORMAT_R8G8B8A8_UNORM; + builder.Format(SceneNormalFormat); + } + builder.DebugName("VkRenderBuffers.SceneNormal"); + + SceneNormal.Image = builder.Create(fb->device.get()); + + SceneNormal.View = ImageViewBuilder() + .Image(SceneNormal.Image.get(), SceneNormalFormat) + .DebugName("VkRenderBuffers.SceneNormalView") + .Create(fb->device.get()); +} + +VulkanFramebuffer* VkRenderBuffers::GetOutput(VkPPRenderPassSetup* passSetup, const PPOutput& output, WhichDepthStencil stencilTest, int& framebufferWidth, int& framebufferHeight) +{ + VkTextureImage* tex = fb->GetTextureManager()->GetTexture(output.Type, output.Texture); + + VkImageView view; + std::unique_ptr* framebufferptr = nullptr; + int w, h; + if (tex) + { + VkImageTransition imageTransition; + imageTransition.AddImage(tex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, output.Type == PPTextureType::NextPipelineTexture); + if (stencilTest == WhichDepthStencil::Scene) + imageTransition.AddImage(&fb->GetBuffers()->SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false); + + if (stencilTest == WhichDepthStencil::Pipeline) + imageTransition.AddImage(&fb->GetBuffers()->PipelineDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false); + + imageTransition.Execute(fb->GetCommands()->GetDrawCommands()); + + view = tex->View->view; + w = tex->Image->width; + h = tex->Image->height; + framebufferptr = &tex->PPFramebuffer; + } + else + { + view = fb->GetFramebufferManager()->SwapChain->GetImageView(fb->GetFramebufferManager()->PresentImageIndex)->view; + framebufferptr = &fb->GetFramebufferManager()->Framebuffers[fb->GetFramebufferManager()->PresentImageIndex]; + w = fb->GetFramebufferManager()->SwapChain->Width(); + h = fb->GetFramebufferManager()->SwapChain->Height(); + } + + auto& framebuffer = *framebufferptr; + if (!framebuffer) + { + FramebufferBuilder builder; + builder.RenderPass(passSetup->RenderPass.get()); + builder.Size(w, h); + builder.AddAttachment(view); + if (stencilTest == WhichDepthStencil::Scene) + builder.AddAttachment(fb->GetBuffers()->SceneDepthStencil.View.get()); + if (stencilTest == WhichDepthStencil::Pipeline) + builder.AddAttachment(fb->GetBuffers()->PipelineDepthStencil.View.get()); + builder.DebugName("PPOutputFB"); + framebuffer = builder.Create(fb->device.get()); + } + + framebufferWidth = w; + framebufferHeight = h; + return framebuffer.get(); +} diff --git a/src/common/rendering/vulkan/textures/vk_renderbuffers.h b/src/common/rendering/vulkan/textures/vk_renderbuffers.h new file mode 100644 index 00000000000..360b366abca --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_renderbuffers.h @@ -0,0 +1,63 @@ + +#pragma once + +#include "zvulkan/vulkanobjects.h" +#include "vulkan/textures/vk_imagetransition.h" + +class VulkanRenderDevice; +class VkPPRenderPassSetup; +class PPOutput; + +enum class WhichDepthStencil { + None, + Scene, + Pipeline, +}; + +class VkRenderBuffers +{ +public: + VkRenderBuffers(VulkanRenderDevice* fb); + ~VkRenderBuffers(); + + void BeginFrame(int width, int height, int sceneWidth, int sceneHeight); + + int GetWidth() const { return mWidth; } + int GetHeight() const { return mHeight; } + int GetSceneWidth() const { return mSceneWidth; } + int GetSceneHeight() const { return mSceneHeight; } + VkSampleCountFlagBits GetSceneSamples() const { return mSamples; } + + VkTextureImage SceneColor; + VkTextureImage SceneDepthStencil; + VkTextureImage SceneNormal; + VkTextureImage SceneFog; + + VkFormat PipelineDepthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT; + VkFormat SceneDepthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT; + VkFormat SceneNormalFormat = VK_FORMAT_A2R10G10B10_UNORM_PACK32; + + static const int NumPipelineImages = 2; + VkTextureImage PipelineDepthStencil; + VkTextureImage PipelineImage[NumPipelineImages]; + + VulkanFramebuffer* GetOutput(VkPPRenderPassSetup* passSetup, const PPOutput& output, WhichDepthStencil stencilTest, int& framebufferWidth, int& framebufferHeight); + +private: + void CreatePipelineDepthStencil(int width, int height); + void CreatePipeline(int width, int height); + void CreateScene(int width, int height, VkSampleCountFlagBits samples); + void CreateSceneColor(int width, int height, VkSampleCountFlagBits samples); + void CreateSceneDepthStencil(int width, int height, VkSampleCountFlagBits samples); + void CreateSceneFog(int width, int height, VkSampleCountFlagBits samples); + void CreateSceneNormal(int width, int height, VkSampleCountFlagBits samples); + VkSampleCountFlagBits GetBestSampleCount(); + + VulkanRenderDevice* fb = nullptr; + + int mWidth = 0; + int mHeight = 0; + int mSceneWidth = 0; + int mSceneHeight = 0; + VkSampleCountFlagBits mSamples = VK_SAMPLE_COUNT_1_BIT; +}; diff --git a/src/common/rendering/vulkan/textures/vk_samplers.cpp b/src/common/rendering/vulkan/textures/vk_samplers.cpp new file mode 100644 index 00000000000..1ce86fea027 --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_samplers.cpp @@ -0,0 +1,189 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include +#include +#include +#include "c_cvars.h" +#include "v_video.h" +#include "hw_cvars.h" +#include "vulkan/system/vk_renderdevice.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "vk_samplers.h" +#include "hw_material.h" +#include "i_interface.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" + +struct VkTexFilter +{ + VkFilter minFilter; + VkFilter magFilter; + VkSamplerMipmapMode mipfilter; + bool mipmapping; +}; + +static VkTexFilter TexFilter[] = +{ + {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, false}, + {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, true}, + {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, false}, + {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, true}, + {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}, + {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}, + {VK_FILTER_LINEAR, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true} +}; + +struct VkTexClamp +{ + VkSamplerAddressMode clamp_u; + VkSamplerAddressMode clamp_v; +}; + +static VkTexClamp TexClamp[] = +{ + { VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT }, + { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT }, + { VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, + { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, +}; + +VkSamplerManager::VkSamplerManager(VulkanRenderDevice* fb) : fb(fb) +{ + CreateHWSamplers(); + CreateShadowmapSampler(); + CreateLightmapSampler(); +} + +VkSamplerManager::~VkSamplerManager() +{ +} + +void VkSamplerManager::ResetHWSamplers() +{ + DeleteHWSamplers(); + CreateHWSamplers(); +} + +void VkSamplerManager::CreateHWSamplers() +{ + int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter()? 0 : gl_texture_filter; + + for (int i = CLAMP_NONE; i <= CLAMP_XY; i++) + { + SamplerBuilder builder; + builder.MagFilter(TexFilter[filter].magFilter); + builder.MinFilter(TexFilter[filter].minFilter); + builder.AddressMode(TexClamp[i].clamp_u, TexClamp[i].clamp_v, VK_SAMPLER_ADDRESS_MODE_REPEAT); + builder.MipmapMode(TexFilter[filter].mipfilter); + if (TexFilter[filter].mipmapping) + { + builder.Anisotropy(gl_texture_filter_anisotropic); + builder.MaxLod(100.0f); // According to the spec this value is clamped so something high makes it usable for all textures. + } + else + { + builder.MaxLod(0.25f); + } + builder.DebugName("VkSamplerManager.mSamplers"); + mSamplers[i] = builder.Create(fb->device.get()); + } + + mSamplers[CLAMP_XY_NOMIP] = SamplerBuilder() + .MagFilter(TexFilter[filter].magFilter) + .MinFilter(TexFilter[filter].magFilter) + .AddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT) + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST) + .MaxLod(0.25f) + .DebugName("VkSamplerManager.mSamplers") + .Create(fb->device.get()); + + for (int i = CLAMP_NOFILTER; i <= CLAMP_NOFILTER_XY; i++) + { + mSamplers[i] = SamplerBuilder() + .MagFilter(VK_FILTER_NEAREST) + .MinFilter(VK_FILTER_NEAREST) + .AddressMode(TexClamp[i - CLAMP_NOFILTER].clamp_u, TexClamp[i - CLAMP_NOFILTER].clamp_v, VK_SAMPLER_ADDRESS_MODE_REPEAT) + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST) + .MaxLod(0.25f) + .DebugName("VkSamplerManager.mSamplers") + .Create(fb->device.get()); + } + + // CAMTEX is repeating with texture filter and no mipmap + mSamplers[CLAMP_CAMTEX] = SamplerBuilder() + .MagFilter(TexFilter[filter].magFilter) + .MinFilter(TexFilter[filter].magFilter) + .AddressMode(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT) + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST) + .MaxLod(0.25f) + .DebugName("VkSamplerManager.mSamplers") + .Create(fb->device.get()); +} + +void VkSamplerManager::DeleteHWSamplers() +{ + for (auto& sampler : mSamplers) + { + if (sampler) + fb->GetCommands()->DrawDeleteList->Add(std::move(sampler)); + } +} + +VulkanSampler* VkSamplerManager::Get(PPFilterMode filter, PPWrapMode wrap) +{ + int index = (((int)filter) << 1) | (int)wrap; + auto& sampler = mPPSamplers[index]; + if (sampler) + return sampler.get(); + + sampler = SamplerBuilder() + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST) + .MinFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR) + .MagFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR) + .AddressMode(wrap == PPWrapMode::Clamp ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE : VK_SAMPLER_ADDRESS_MODE_REPEAT) + .DebugName("VkPostprocess.mSamplers") + .Create(fb->device.get()); + + return sampler.get(); +} + +void VkSamplerManager::CreateShadowmapSampler() +{ + ShadowmapSampler = SamplerBuilder() + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST) + .MinFilter(VK_FILTER_NEAREST) + .MagFilter(VK_FILTER_NEAREST) + .AddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE) + .DebugName("VkRenderBuffers.ShadowmapSampler") + .Create(fb->device.get()); +} + +void VkSamplerManager::CreateLightmapSampler() +{ + LightmapSampler = SamplerBuilder() + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_LINEAR) + .MinFilter(VK_FILTER_LINEAR) + .MagFilter(VK_FILTER_LINEAR) + .AddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE) + .DebugName("VkRenderBuffers.LightmapSampler") + .Create(fb->device.get()); +} diff --git a/src/common/rendering/vulkan/textures/vk_samplers.h b/src/common/rendering/vulkan/textures/vk_samplers.h new file mode 100644 index 00000000000..a7f9ac68faf --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_samplers.h @@ -0,0 +1,34 @@ + +#pragma once + +#include "zvulkan/vulkanobjects.h" +#include + +class VulkanRenderDevice; +enum class PPFilterMode; +enum class PPWrapMode; + +class VkSamplerManager +{ +public: + VkSamplerManager(VulkanRenderDevice* fb); + ~VkSamplerManager(); + + void ResetHWSamplers(); + + VulkanSampler *Get(int no) const { return mSamplers[no].get(); } + VulkanSampler* Get(PPFilterMode filter, PPWrapMode wrap); + + std::unique_ptr ShadowmapSampler; + std::unique_ptr LightmapSampler; + +private: + void CreateHWSamplers(); + void DeleteHWSamplers(); + void CreateShadowmapSampler(); + void CreateLightmapSampler(); + + VulkanRenderDevice* fb = nullptr; + std::array, NUMSAMPLERS> mSamplers; + std::array, 4> mPPSamplers; +}; diff --git a/src/common/rendering/vulkan/textures/vk_texture.cpp b/src/common/rendering/vulkan/textures/vk_texture.cpp new file mode 100644 index 00000000000..b7d88a08a7a --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_texture.cpp @@ -0,0 +1,253 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_texture.h" +#include "vk_hwtexture.h" +#include "vk_pptexture.h" +#include "vk_renderbuffers.h" +#include "vulkan/renderer/vk_postprocess.h" +#include "hw_cvars.h" + +VkTextureManager::VkTextureManager(VulkanRenderDevice* fb) : fb(fb) +{ + CreateNullTexture(); + CreateShadowmap(); + CreateLightmap(); +} + +VkTextureManager::~VkTextureManager() +{ + while (!Textures.empty()) + RemoveTexture(Textures.back()); + while (!PPTextures.empty()) + RemovePPTexture(PPTextures.back()); +} + +void VkTextureManager::Deinit() +{ + while (!Textures.empty()) + RemoveTexture(Textures.back()); + while (!PPTextures.empty()) + RemovePPTexture(PPTextures.back()); +} + +void VkTextureManager::BeginFrame() +{ + if (!Shadowmap.Image || Shadowmap.Image->width != gl_shadowmap_quality) + { + Shadowmap.Reset(fb); + CreateShadowmap(); + } +} + +void VkTextureManager::AddTexture(VkHardwareTexture* texture) +{ + texture->it = Textures.insert(Textures.end(), texture); +} + +void VkTextureManager::RemoveTexture(VkHardwareTexture* texture) +{ + texture->Reset(); + texture->fb = nullptr; + Textures.erase(texture->it); +} + +void VkTextureManager::AddPPTexture(VkPPTexture* texture) +{ + texture->it = PPTextures.insert(PPTextures.end(), texture); +} + +void VkTextureManager::RemovePPTexture(VkPPTexture* texture) +{ + texture->Reset(); + texture->fb = nullptr; + PPTextures.erase(texture->it); +} + +VkTextureImage* VkTextureManager::GetTexture(const PPTextureType& type, PPTexture* pptexture) +{ + if (type == PPTextureType::CurrentPipelineTexture || type == PPTextureType::NextPipelineTexture) + { + int idx = fb->GetPostprocess()->GetCurrentPipelineImage(); + if (type == PPTextureType::NextPipelineTexture) + idx = (idx + 1) % VkRenderBuffers::NumPipelineImages; + + return &fb->GetBuffers()->PipelineImage[idx]; + } + else if (type == PPTextureType::PPTexture) + { + auto vktex = GetVkTexture(pptexture); + return &vktex->TexImage; + } + else if (type == PPTextureType::SceneColor) + { + return &fb->GetBuffers()->SceneColor; + } + else if (type == PPTextureType::SceneNormal) + { + return &fb->GetBuffers()->SceneNormal; + } + else if (type == PPTextureType::SceneFog) + { + return &fb->GetBuffers()->SceneFog; + } + else if (type == PPTextureType::SceneDepth) + { + return &fb->GetBuffers()->SceneDepthStencil; + } + else if (type == PPTextureType::ShadowMap) + { + return &Shadowmap; + } + else if (type == PPTextureType::SwapChain) + { + return nullptr; + } + else + { + I_FatalError("VkPPRenderState::GetTexture not implemented yet for this texture type"); + return nullptr; + } +} + +VkFormat VkTextureManager::GetTextureFormat(PPTexture* texture) +{ + return GetVkTexture(texture)->Format; +} + +VkPPTexture* VkTextureManager::GetVkTexture(PPTexture* texture) +{ + if (!texture->Backend) + texture->Backend = std::make_unique(fb, texture); + return static_cast(texture->Backend.get()); +} + +void VkTextureManager::CreateNullTexture() +{ + NullTexture = ImageBuilder() + .Format(VK_FORMAT_R8G8B8A8_UNORM) + .Size(1, 1) + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT) + .DebugName("VkDescriptorSetManager.NullTexture") + .Create(fb->device.get()); + + NullTextureView = ImageViewBuilder() + .Image(NullTexture.get(), VK_FORMAT_R8G8B8A8_UNORM) + .DebugName("VkDescriptorSetManager.NullTextureView") + .Create(fb->device.get()); + + PipelineBarrier() + .AddImage(NullTexture.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT) + .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +} + +void VkTextureManager::CreateShadowmap() +{ + Shadowmap.Image = ImageBuilder() + .Size(gl_shadowmap_quality, 1024) + .Format(VK_FORMAT_R32_SFLOAT) + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) + .DebugName("VkRenderBuffers.Shadowmap") + .Create(fb->device.get()); + + Shadowmap.View = ImageViewBuilder() + .Image(Shadowmap.Image.get(), VK_FORMAT_R32_SFLOAT) + .DebugName("VkRenderBuffers.ShadowmapView") + .Create(fb->device.get()); + + VkImageTransition() + .AddImage(&Shadowmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true) + .Execute(fb->GetCommands()->GetDrawCommands()); +} + +void VkTextureManager::CreateLightmap() +{ + TArray data; + data.Push(0); + data.Push(0); + data.Push(0); + data.Push(0x3c00); // half-float 1.0 + SetLightmap(1, 1, data); +} + +void VkTextureManager::SetLightmap(int LMTextureSize, int LMTextureCount, const TArray& LMTextureData) +{ + int w = LMTextureSize; + int h = LMTextureSize; + int count = LMTextureCount; + int pixelsize = 8; + + Lightmap.Reset(fb); + + Lightmap.Image = ImageBuilder() + .Size(w, h, 1, count) + .Format(VK_FORMAT_R16G16B16A16_SFLOAT) + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .DebugName("VkRenderBuffers.Lightmap") + .Create(fb->device.get()); + + Lightmap.View = ImageViewBuilder() + .Type(VK_IMAGE_VIEW_TYPE_2D_ARRAY) + .Image(Lightmap.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("VkRenderBuffers.LightmapView") + .Create(fb->device.get()); + + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + int totalSize = w * h * count * pixelsize; + + auto stagingBuffer = BufferBuilder() + .Size(totalSize) + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .DebugName("VkHardwareTexture.mStagingBuffer") + .Create(fb->device.get()); + + uint16_t one = 0x3c00; // half-float 1.0 + const uint16_t* src = LMTextureData.Data(); + uint16_t* data = (uint16_t*)stagingBuffer->Map(0, totalSize); + for (int i = w * h * count; i > 0; i--) + { + *(data++) = *(src++); + *(data++) = *(src++); + *(data++) = *(src++); + *(data++) = one; + } + stagingBuffer->Unmap(); + + VkImageTransition() + .AddImage(&Lightmap, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true, 0, count) + .Execute(cmdbuffer); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = count; + region.imageExtent.depth = 1; + region.imageExtent.width = w; + region.imageExtent.height = h; + cmdbuffer->copyBufferToImage(stagingBuffer->buffer, Lightmap.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + VkImageTransition() + .AddImage(&Lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, count) + .Execute(cmdbuffer); + + fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); +} diff --git a/src/common/rendering/vulkan/textures/vk_texture.h b/src/common/rendering/vulkan/textures/vk_texture.h new file mode 100644 index 00000000000..16b49001ac6 --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_texture.h @@ -0,0 +1,57 @@ + +#pragma once + +#include +#include "vulkan/textures/vk_imagetransition.h" +#include + +class VulkanRenderDevice; +class VkHardwareTexture; +class VkMaterial; +class VkPPTexture; +class VkTextureImage; +enum class PPTextureType; +class PPTexture; + +class VkTextureManager +{ +public: + VkTextureManager(VulkanRenderDevice* fb); + ~VkTextureManager(); + + void Deinit(); + + void BeginFrame(); + + void SetLightmap(int LMTextureSize, int LMTextureCount, const TArray& LMTextureData); + + VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex); + VkFormat GetTextureFormat(PPTexture* texture); + + void AddTexture(VkHardwareTexture* texture); + void RemoveTexture(VkHardwareTexture* texture); + + void AddPPTexture(VkPPTexture* texture); + void RemovePPTexture(VkPPTexture* texture); + + VulkanImage* GetNullTexture() { return NullTexture.get(); } + VulkanImageView* GetNullTextureView() { return NullTextureView.get(); } + + VkTextureImage Shadowmap; + VkTextureImage Lightmap; + +private: + void CreateNullTexture(); + void CreateShadowmap(); + void CreateLightmap(); + + VkPPTexture* GetVkTexture(PPTexture* texture); + + VulkanRenderDevice* fb = nullptr; + + std::list Textures; + std::list PPTextures; + + std::unique_ptr NullTexture; + std::unique_ptr NullTextureView; +}; diff --git a/src/scripting/backend/codegen.cpp b/src/common/scripting/backend/codegen.cpp similarity index 79% rename from src/scripting/backend/codegen.cpp rename to src/common/scripting/backend/codegen.cpp index 702f2b8f16c..5b1a975a6c2 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/common/scripting/backend/codegen.cpp @@ -18,10 +18,6 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be -** covered by the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or (at -** your option) any later version. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -38,21 +34,22 @@ */ #include -#include "actor.h" #include "cmdlib.h" -#include "a_pickups.h" -#include "thingdef.h" -#include "p_lnspec.h" #include "codegen.h" #include "v_text.h" -#include "w_wad.h" -#include "doomstat.h" -#include "g_levellocals.h" +#include "filesystem.h" #include "v_video.h" #include "utf8.h" +#include "texturemanager.h" +#include "m_random.h" +#include "v_font.h" +#include "palettecontainer.h" + extern FRandom pr_exrandom; FMemArena FxAlloc(65536); +CompileEnvironment compileEnvironment; +FTranslationID R_FindCustomTranslation(FName name); struct FLOP { @@ -86,7 +83,7 @@ static const FLOP FxFlops[] = { NAME_Round, FLOP_ROUND, [](double v) { return round(v); } }, }; -static bool AreCompatiblePointerTypes(PType* dest, PType* source, bool forcompare = false); +bool AreCompatiblePointerTypes(PType* dest, PType* source, bool forcompare = false); //========================================================================== // @@ -109,8 +106,8 @@ FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret if (fnc != nullptr) Class = fnc->OwningClass; } -FCompileContext::FCompileContext(PNamespace *cg, PContainerType *cls, bool fromdecorate) - : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1), CurGlobals(cg) +FCompileContext::FCompileContext(PNamespace *cg, PContainerType *cls, bool fromdecorate, const VersionInfo& info) + : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1), CurGlobals(cg), Version(info) { } @@ -148,7 +145,7 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) if (ReturnProto->ReturnTypes.Size() < proto->ReturnTypes.Size()) { // Make proto the shorter one to avoid code duplication below. - swapvalues(proto, ReturnProto); + std::swap(proto, ReturnProto); swapped = true; } // If one prototype returns nothing, they both must. @@ -165,7 +162,13 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) { PType* expected = ReturnProto->ReturnTypes[i]; PType* actual = proto->ReturnTypes[i]; - if (swapped) swapvalues(expected, actual); + if (swapped) std::swap(expected, actual); + // this must pass for older ZScripts. + if (Version < MakeVersion(4, 12, 0)) + { + if (expected == TypeTranslationID) expected = TypeSInt32; + if (actual == TypeTranslationID) actual = TypeSInt32; + } if (expected != actual && !AreCompatiblePointerTypes(expected, actual)) { // Incompatible @@ -182,12 +185,9 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) } } -// [ZZ] I find it really dumb that something called CheckReadOnly returns false for readonly. renamed. -bool FCompileContext::CheckWritable(int flags) +bool FCompileContext::IsWritable(int flags, int checkFileNo) { - if (!(flags & VARF_ReadOnly)) return false; - if (!(flags & VARF_InternalAccess)) return true; - return Wads.GetLumpFile(Lump) != 0; + return !(flags & VARF_ReadOnly) || ((flags & VARF_InternalAccess) && fileSystem.GetFileContainer(Lump) == checkFileNo); } FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) @@ -227,12 +227,6 @@ static PClass *FindClassType(FName name, FCompileContext &ctx) return nullptr; } -bool isActor(PContainerType *type) -{ - auto cls = PType::toClass(type); - return cls ? cls->Descriptor->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; -} - //========================================================================== // // ExpEmit @@ -271,7 +265,7 @@ void ExpEmit::Reuse(VMFunctionBuilder *build) // //========================================================================== -static PFunction *FindBuiltinFunction(FName funcname) +PFunction *FindBuiltinFunction(FName funcname) { return dyn_cast(RUNTIME_CLASS(DObject)->FindSymbol(funcname, true)); } @@ -282,7 +276,9 @@ static PFunction *FindBuiltinFunction(FName funcname) // //========================================================================== -static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare) +static bool AreCompatibleFnPtrTypes(PPrototype *to, PPrototype *from); + +bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare) { if (dest->isPointer() && source->isPointer()) { @@ -291,25 +287,36 @@ static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompar // null pointers can be assigned to everything, everything can be assigned to void pointers. if (fromtype == nullptr || totype == TypeVoidPtr) return true; // when comparing const-ness does not matter. - if (!forcompare && totype->IsConst != fromtype->IsConst) return false; + // If not comparing, then we should not allow const to be cast away. + if (!forcompare && fromtype->IsConst && !totype->IsConst) return false; // A type is always compatible to itself. if (fromtype == totype) return true; - // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type. if (source->isObjectPointer() && dest->isObjectPointer()) - { + { // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type. auto fromcls = static_cast(source)->PointedClass(); auto tocls = static_cast(dest)->PointedClass(); if (forcompare && tocls->IsDescendantOf(fromcls)) return true; return (fromcls->IsDescendantOf(tocls)); } - // The same rules apply to class pointers. A child type can be assigned to a variable of a parent type. - if (source->isClassPointer() && dest->isClassPointer()) - { + else if (source->isClassPointer() && dest->isClassPointer()) + { // The same rules apply to class pointers. A child type can be assigned to a variable of a parent type. auto fromcls = static_cast(source)->ClassRestriction; auto tocls = static_cast(dest)->ClassRestriction; if (forcompare && tocls->IsDescendantOf(fromcls)) return true; return (fromcls->IsDescendantOf(tocls)); } + else if(source->isFunctionPointer() && dest->isFunctionPointer()) + { + auto from = static_cast(source); + auto to = static_cast(dest); + if(from->PointedType == TypeVoid) return false; + + return to->PointedType == TypeVoid || (AreCompatibleFnPtrTypes((PPrototype *)to->PointedType, (PPrototype *)from->PointedType) && from->ArgFlags == to->ArgFlags && FScopeBarrier::CheckSidesForFunctionPointer(from->Scope, to->Scope)); + } + else if(source->isRealPointer() && dest->isRealPointer()) + { + return fromtype->PointedType == totype->PointedType; + } } return false; } @@ -495,12 +502,15 @@ int EncodeRegType(ExpEmit reg) else if (reg.RegCount == 2) { regtype |= REGT_MULTIREG2; - } else if (reg.RegCount == 3) { regtype |= REGT_MULTIREG3; } + else if (reg.RegCount == 4) + { + regtype |= REGT_MULTIREG4; + } return regtype; } @@ -533,10 +543,10 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) } else { - PSymbolConstString *csym = dyn_cast(sym); - if (csym != nullptr) + PSymbolConstString *csymbol = dyn_cast(sym); + if (csymbol != nullptr) { - x = new FxConstant(csym->Str, pos); + x = new FxConstant(csymbol->Str, pos); } else { @@ -584,19 +594,20 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) // //========================================================================== -FxVectorValue::FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z, const FScriptPosition &sc) +FxVectorValue::FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z, FxExpression* w, const FScriptPosition &sc) :FxExpression(EFX_VectorValue, sc) { - xyz[0] = x; - xyz[1] = y; - xyz[2] = z; + xyzw[0] = x; + xyzw[1] = y; + xyzw[2] = z; + xyzw[3] = w; isConst = false; ValueType = TypeVoid; // we do not know yet } FxVectorValue::~FxVectorValue() { - for (auto &a : xyz) + for (auto &a : xyzw) { SAFE_DELETE(a); } @@ -606,7 +617,8 @@ FxExpression *FxVectorValue::Resolve(FCompileContext&ctx) { bool fails = false; - for (auto &a : xyz) + // Cast every scalar to float64 + for (auto &a : xyzw) { if (a != nullptr) { @@ -614,7 +626,7 @@ FxExpression *FxVectorValue::Resolve(FCompileContext&ctx) if (a == nullptr) fails = true; else { - if (a->ValueType != TypeVector2) // a vec3 may be initialized with (vec2, z) + if (a->ValueType != TypeVector2 && a->ValueType != TypeVector3) // smaller vector can be used to initialize another vector { a = new FxFloatCast(a); a = a->Resolve(ctx); @@ -623,51 +635,89 @@ FxExpression *FxVectorValue::Resolve(FCompileContext&ctx) } } } + if (fails) { delete this; return nullptr; } - // at this point there are three legal cases: - // * two floats = vector2 - // * three floats = vector3 - // * vector2 + float = vector3 - if (xyz[0]->ValueType == TypeVector2) + + // The actual dimension of the Vector does not correspond to the amount of non-null elements in xyzw + // For example: '(asdf.xy, 1)' would be Vector3 where xyzw[0]->ValueType == TypeVector2 and xyzw[1]->ValueType == TypeFloat64 + + // Handle nesting and figure out the dimension of the vector + int vectorDimensions = 0; + + for (int i = 0; i < maxVectorDimensions && xyzw[i]; ++i) { - if (xyz[1]->ValueType != TypeFloat64 || xyz[2] != nullptr) + assert(dynamic_cast(xyzw[i])); + + if (xyzw[i]->ValueType == TypeFloat64) + { + vectorDimensions++; + } + else if (xyzw[i]->ValueType == TypeVector2 || xyzw[i]->ValueType == TypeVector3 || xyzw[i]->ValueType == TypeVector4) + { + // Solve nested vector + int regCount = xyzw[i]->ValueType->RegCount; + + if (regCount + vectorDimensions > maxVectorDimensions) + { + vectorDimensions += regCount; // Show proper number + goto too_big; + } + + // Nested initializer gets simplified + if (xyzw[i]->ExprType == EFX_VectorValue) + { + // Shifts current elements to leave space for unwrapping nested initialization + for (int l = maxVectorDimensions - 1; l > i; --l) + { + xyzw[l] = xyzw[l - regCount + 1]; + } + + auto vi = static_cast(xyzw[i]); + for (int j = 0; j < regCount; ++j) + { + xyzw[i + j] = vi->xyzw[j]; + vi->xyzw[j] = nullptr; // Preserve object after 'delete vi;' + } + delete vi; + + // We extracted something, let's iterate on that again: + --i; + continue; + } + else + { + vectorDimensions += regCount; + } + } + else { ScriptPosition.Message(MSG_ERROR, "Not a valid vector"); delete this; return nullptr; } - ValueType = TypeVector3; - if (xyz[0]->ExprType == EFX_VectorValue) - { - // If two vector initializers are nested, unnest them now. - auto vi = static_cast(xyz[0]); - xyz[2] = xyz[1]; - xyz[1] = vi->xyz[1]; - xyz[0] = vi->xyz[0]; - vi->xyz[0] = vi->xyz[1] = nullptr; // Don't delete our own expressions. - delete vi; - } } - else if (xyz[0]->ValueType == TypeFloat64 && xyz[1]->ValueType == TypeFloat64) - { - ValueType = xyz[2] == nullptr ? TypeVector2 : TypeVector3; - } - else + + switch (vectorDimensions) { - ScriptPosition.Message(MSG_ERROR, "Not a valid vector"); + case 2: ValueType = TypeVector2; break; + case 3: ValueType = TypeVector3; break; + case 4: ValueType = TypeVector4; break; + default: + too_big:; + ScriptPosition.Message(MSG_ERROR, "Vector of %d dimensions is not supported", vectorDimensions); delete this; return nullptr; } // check if all elements are constant. If so this can be emitted as a constant vector. isConst = true; - for (auto &a : xyz) + for (auto &a : xyzw) { - if (a != nullptr && !a->isConstant()) isConst = false; + if (a && !a->isConstant()) isConst = false; } return this; } @@ -685,102 +735,127 @@ static ExpEmit EmitKonst(VMFunctionBuilder *build, ExpEmit &emit) ExpEmit FxVectorValue::Emit(VMFunctionBuilder *build) { - // no const handling here. Ultimately it's too rarely used (i.e. the only fully constant vector ever allocated in ZDoom is the 0-vector in a very few places) - // and the negatives (excessive allocation of float constants) outweigh the positives (saved a few instructions) - assert(xyz[0] != nullptr); - assert(xyz[1] != nullptr); - if (ValueType == TypeVector2) + int vectorDimensions = ValueType->RegCount; + int vectorElements = 0; + for (auto& e : xyzw) { - ExpEmit tempxval = xyz[0]->Emit(build); - ExpEmit tempyval = xyz[1]->Emit(build); - ExpEmit xval = EmitKonst(build, tempxval); - ExpEmit yval = EmitKonst(build, tempyval); - assert(xval.RegType == REGT_FLOAT && yval.RegType == REGT_FLOAT); - if (yval.RegNum == xval.RegNum + 1) - { - // The results are already in two continuous registers so just return them as-is. - xval.RegCount++; - return xval; - } - else - { - // The values are not in continuous registers so they need to be copied together now. - ExpEmit out(build, REGT_FLOAT, 2); - build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); - build->Emit(OP_MOVEF, out.RegNum + 1, yval.RegNum); - xval.Free(build); - yval.Free(build); - return out; - } + if (e) vectorElements++; + } + assert(vectorElements > 0 && vectorElements <= 4); + + // We got at most 4 elements + ExpEmit tempVal[4]; + ExpEmit val[4]; + + // Init ExpEmit + for (int i = 0; i < vectorElements; ++i) + { + tempVal[i] = ExpEmit(xyzw[i]->Emit(build)); + val[i] = EmitKonst(build, tempVal[i]); } - else if (xyz[0]->ValueType == TypeVector2) // vec2+float + { - ExpEmit xyval = xyz[0]->Emit(build); - ExpEmit tempzval = xyz[1]->Emit(build); - ExpEmit zval = EmitKonst(build, tempzval); - assert(xyval.RegType == REGT_FLOAT && xyval.RegCount == 2 && zval.RegType == REGT_FLOAT); - if (zval.RegNum == xyval.RegNum + 2) + bool isContinuous = true; + + for (int i = 1; i < vectorElements; ++i) { - // The results are already in three continuous registers so just return them as-is. - xyval.RegCount++; - return xyval; + if (val[i - 1].RegNum + val[i - 1].RegCount != val[i].RegNum) + { + isContinuous = false; + break; + } } - else + + // all values are in continuous registers: + if (isContinuous) { - // The values are not in continuous registers so they need to be copied together now. - ExpEmit out(build, REGT_FLOAT, 3); - build->Emit(OP_MOVEV2, out.RegNum, xyval.RegNum); - build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); - xyval.Free(build); - zval.Free(build); - return out; + val[0].RegCount = vectorDimensions; + return val[0]; } } - else // 3*float + + ExpEmit out(build, REGT_FLOAT, vectorDimensions); + { - assert(xyz[2] != nullptr); - ExpEmit tempxval = xyz[0]->Emit(build); - ExpEmit tempyval = xyz[1]->Emit(build); - ExpEmit tempzval = xyz[2]->Emit(build); - ExpEmit xval = EmitKonst(build, tempxval); - ExpEmit yval = EmitKonst(build, tempyval); - ExpEmit zval = EmitKonst(build, tempzval); - assert(xval.RegType == REGT_FLOAT && yval.RegType == REGT_FLOAT && zval.RegType == REGT_FLOAT); - if (yval.RegNum == xval.RegNum + 1 && zval.RegNum == xval.RegNum + 2) - { - // The results are already in three continuous registers so just return them as-is. - xval.RegCount += 2; - return xval; - } - else + auto emitRegMove = [&](int regsToMove, int dstRegIndex, int srcRegIndex) { + assert(dstRegIndex < vectorDimensions); + assert(srcRegIndex < vectorDimensions); + assert(regsToMove > 0 && regsToMove <= 4); + build->Emit(regsToMove == 1 ? OP_MOVEF : OP_MOVEV2 + regsToMove - 2, out.RegNum + dstRegIndex, val[srcRegIndex].RegNum); + static_assert(OP_MOVEV2 + 1 == OP_MOVEV3); + static_assert(OP_MOVEV3 + 1 == OP_MOVEV4); + }; + + int regsToPush = 0; + int nextRegNum = val[0].RegNum; + int lastElementIndex = 0; + int reg = 0; + + // Use larger MOVE OPs for any groups of registers that are continuous including those across individual xyzw[] elements + for (int elementIndex = 0; elementIndex < vectorElements; ++elementIndex) { - // The values are not in continuous registers so they need to be copied together now. - ExpEmit out(build, REGT_FLOAT, 3); - //Try to optimize a bit... - if (yval.RegNum == xval.RegNum + 1) - { - build->Emit(OP_MOVEV2, out.RegNum, xval.RegNum); - build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); - } - else if (zval.RegNum == yval.RegNum + 1) + int regCount = xyzw[elementIndex]->ValueType->RegCount; + + if (nextRegNum != val[elementIndex].RegNum) { - build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); - build->Emit(OP_MOVEV2, out.RegNum+1, yval.RegNum); + emitRegMove(regsToPush, reg, lastElementIndex); + + reg += regsToPush; + regsToPush = regCount; + nextRegNum = val[elementIndex].RegNum + val[elementIndex].RegCount; + lastElementIndex = elementIndex; } else { - build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); - build->Emit(OP_MOVEF, out.RegNum + 1, yval.RegNum); - build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); + regsToPush += regCount; + nextRegNum = val[elementIndex].RegNum + val[elementIndex].RegCount; } - xval.Free(build); - yval.Free(build); - zval.Free(build); - return out; } + + // Emit move instructions on the last register + if (regsToPush > 0) + { + emitRegMove(regsToPush, reg, lastElementIndex); + } + } + + for (int i = 0; i < vectorElements; ++i) + { + val[i].Free(build); + val[i].~ExpEmit(); + } + + return out; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxQuaternionValue::FxQuaternionValue(FxExpression* x, FxExpression* y, FxExpression* z, FxExpression* w, const FScriptPosition& sc) : FxVectorValue(x, y, z, w, sc) +{ +} + +FxExpression* FxQuaternionValue::Resolve(FCompileContext& ctx) +{ + auto base = FxVectorValue::Resolve(ctx); + if (base) + { + if (base->ValueType->GetRegCount() != 4) + { + ScriptPosition.Message(MSG_ERROR, "Quat expression requires 4 arguments, got %d instead", base->ValueType->GetRegCount()); + delete base; + return nullptr; + } + + base->ValueType = TypeQuaternion; } + return base; } + //========================================================================== // // @@ -851,6 +926,17 @@ FxExpression *FxBoolCast::Resolve(FCompileContext &ctx) ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) { ExpEmit from = basex->Emit(build); + + if(from.Konst && from.RegType == REGT_INT) + { // this is needed here because the int const assign optimization returns a constant + ExpEmit to; + to.Konst = true; + to.RegType = REGT_INT; + to.RegNum = build->GetConstantInt(!!build->FindConstantInt(from.RegNum)); + return to; + } + + assert(!from.Konst); assert(basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER); @@ -917,6 +1003,19 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) if (basex->ValueType->GetRegType() == REGT_INT) { + if (basex->ValueType == TypeTranslationID) + { + // translation IDs must be entirely incompatible with ints, not even allowing an explicit conversion, + // but since the type was only introduced in version 4.12, older ZScript versions must allow this conversion. + if (ctx.Version < MakeVersion(4, 12, 0)) + { + FxExpression* x = basex; + x->ValueType = ValueType; + basex = nullptr; + delete this; + return x; + } + } if (basex->ValueType->isNumeric() || Explicit) // names can be converted to int, but only with an explicit type cast. { FxExpression *x = basex; @@ -930,7 +1029,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this serious error needs to be reduced to a warning. :( // At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE. if (!basex->isConstant()) - ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); + ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a %s", basex->ValueType->DescriptiveName()); else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast(basex)->GetValue().GetName().GetChars()); FxExpression * x = new FxConstant(0, ScriptPosition); delete this; @@ -943,7 +1042,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) { ExpVal constval = static_cast(basex)->GetValue(); FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); - if (constval.GetInt() != constval.GetFloat()) + if (constval.GetInt() != constval.GetFloat() && !Explicit) { ScriptPosition.Message(MSG_WARNING, "Truncation of floating point constant %f", constval.GetFloat()); } @@ -1051,7 +1150,8 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) { // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :( // At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE. - if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); + if (!basex->isConstant()) + ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a %s", basex->ValueType->DescriptiveName()); else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast(basex)->GetValue().GetName().GetChars()); FxExpression *x = new FxConstant(0.0, ScriptPosition); delete this; @@ -1075,7 +1175,15 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) { ExpEmit from = basex->Emit(build); - assert(!from.Konst); + if(from.Konst && from.RegType == REGT_INT) + { // this is needed here because the int const assign optimization returns a constant + ExpEmit to; + to.Konst = true; + to.RegType = REGT_FLOAT; + to.RegNum = build->GetConstantFloat(build->FindConstantInt(from.RegNum)); + return to; + } + assert(basex->ValueType->GetRegType() == REGT_INT); from.Free(build); ExpEmit to(build, REGT_FLOAT); @@ -1180,7 +1288,7 @@ ExpEmit FxNameCast::Emit(VMFunctionBuilder *build) assert(ptr.RegType == REGT_POINTER); ptr.Free(build); ExpEmit to(build, REGT_INT); - build->Emit(OP_LW, to.RegNum, ptr.RegNum, build->GetConstantInt(myoffsetof(PClassActor, TypeName))); + build->Emit(OP_LW, to.RegNum, ptr.RegNum, build->GetConstantInt(myoffsetof(PClass, TypeName))); return to; } } @@ -1243,7 +1351,7 @@ FxExpression *FxStringCast::Resolve(FCompileContext &ctx) if (basex->isConstant()) { ExpVal constval = static_cast(basex)->GetValue(); - FxExpression *x = new FxConstant(S_GetSoundName(constval.GetInt()), ScriptPosition); + FxExpression *x = new FxConstant(soundEngine->GetSoundName(FSoundID::fromInt(constval.GetInt())), ScriptPosition); delete this; return x; } @@ -1339,7 +1447,7 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx) } else { - FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString(), &ScriptPosition), ScriptPosition); + FxExpression *x = new FxConstant(V_GetColor(constval.GetString().GetChars(), &ScriptPosition), ScriptPosition); delete this; return x; } @@ -1419,7 +1527,7 @@ FxExpression *FxSoundCast::Resolve(FCompileContext &ctx) if (basex->isConstant()) { ExpVal constval = static_cast(basex)->GetValue(); - FxExpression *x = new FxConstant(FSoundID(constval.GetString()), ScriptPosition); + FxExpression *x = new FxConstant(S_FindSound(constval.GetString().GetChars()), ScriptPosition); delete this; return x; } @@ -1450,6 +1558,107 @@ ExpEmit FxSoundCast::Emit(VMFunctionBuilder *build) return to; } +//========================================================================== +// +// +// +//========================================================================== + +FxTranslationCast::FxTranslationCast(FxExpression* x) + : FxExpression(EFX_TranslationCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeTranslationID; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxTranslationCast::~FxTranslationCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression* FxTranslationCast::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType->isInt()) + { + // 0 is a valid constant for translations, meaning 'no translation at all'. note that this conversion ONLY allows a constant! + if (basex->isConstant() && static_cast(basex)->GetValue().GetInt() == 0) + { + FxExpression* x = basex; + x->ValueType = TypeTranslationID; + basex = nullptr; + delete this; + return x; + } + if (ctx.Version < MakeVersion(4, 12, 0)) + { + // only allow this conversion as a fallback + FxExpression* x = basex; + x->ValueType = TypeTranslationID; + basex = nullptr; + delete this; + return x; + } + } + else if (basex->ValueType == TypeString || basex->ValueType == TypeName) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression* x = new FxConstant(R_FindCustomTranslation(constval.GetName()), ScriptPosition); + x->ValueType = TypeTranslationID; + delete this; + return x; + } + else if (basex->ValueType == TypeString) + { + basex = new FxNameCast(basex, true); + basex = basex->Resolve(ctx); + } + return this; + } + ScriptPosition.Message(MSG_ERROR, "Cannot convert to translation ID"); + delete this; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxTranslationCast::Emit(VMFunctionBuilder* build) +{ + ExpEmit to(build, REGT_POINTER); + + VMFunction* callfunc; + auto sym = FindBuiltinFunction(NAME_BuiltinFindTranslation); + + assert(sym); + callfunc = sym->Variants[0].Implementation; + + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(build, basex); + emitters.AddReturn(REGT_INT); + return emitters.EmitCall(build); +} + + //========================================================================== // // @@ -1460,7 +1669,7 @@ FxFontCast::FxFontCast(FxExpression *x) : FxExpression(EFX_FontCast, x->ScriptPosition) { basex = x; - ValueType = TypeSound; + ValueType = TypeFont; } //========================================================================== @@ -1497,7 +1706,7 @@ FxExpression *FxFontCast::Resolve(FCompileContext &ctx) else if ((basex->ValueType == TypeString || basex->ValueType == TypeName) && basex->isConstant()) { ExpVal constval = static_cast(basex)->GetValue(); - FFont *font = V_GetFont(constval.GetString()); + FFont *font = V_GetFont(constval.GetString().GetChars()); // Font must exist. Most internal functions working with fonts do not like null pointers. // If checking is needed scripts will have to call Font.GetFont themselves. if (font == nullptr) @@ -1553,11 +1762,62 @@ FxTypeCast::~FxTypeCast() // //========================================================================== +FxConstant * FxTypeCast::convertRawFunctionToFunctionPointer(FxExpression * in, FScriptPosition &ScriptPosition) +{ + assert(in->isConstant() && in->ValueType == TypeRawFunction); + FxConstant *val = static_cast(in); + PFunction * fn = static_cast(val->value.pointer); + if(fn && (fn->Variants[0].Flags & (VARF_Virtual | VARF_Action | VARF_Method)) == 0) + { + val->ValueType = val->value.Type = NewFunctionPointer(fn->Variants[0].Proto, TArray(fn->Variants[0].ArgFlags), FScopeBarrier::SideFromFlags(fn->Variants[0].Flags)); + return val; + } + else if(fn && (fn->Variants[0].Flags & (VARF_Virtual | VARF_Action | VARF_Method)) == VARF_Method) + { + TArray flags(fn->Variants[0].ArgFlags); + flags[0] = 0; + val->ValueType = val->value.Type = NewFunctionPointer(fn->Variants[0].Proto, std::move(flags), FScopeBarrier::SideFromFlags(fn->Variants[0].Flags)); + return val; + } + else if(!fn) + { + val->ValueType = val->value.Type = NewFunctionPointer(nullptr, {}, -1); // Function + return val; + } + else + { + ScriptPosition.Message(MSG_ERROR, "virtual/action function pointers are not allowed"); + return nullptr; + } +} + FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); + if (compileEnvironment.SpecialTypeCast) + { + auto result = compileEnvironment.SpecialTypeCast(this, ctx); + if (result != this) return result; + } + + if (basex->isConstant() && basex->ValueType == TypeRawFunction && ValueType->isFunctionPointer()) + { + FxConstant *val = convertRawFunctionToFunctionPointer(basex, ScriptPosition); + if(!val) + { + delete this; + return nullptr; + } + } + else if (basex->isConstant() && basex->ValueType == TypeRawFunction && ValueType == TypeVMFunction) + { + FxConstant *val = static_cast(basex); + val->ValueType = val->value.Type = TypeVMFunction; + val->value.pointer = static_cast(val->value.pointer)->Variants[0].Implementation; + } + // first deal with the simple types if (ValueType == TypeError || basex->ValueType == TypeError || basex->ValueType == nullptr) { @@ -1631,6 +1891,14 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) delete this; return x; } + else if (ValueType == TypeTranslationID) + { + FxExpression* x = new FxTranslationCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } else if (ValueType == TypeColor) { FxExpression *x = new FxColorCast(basex); @@ -1647,97 +1915,39 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) delete this; return x; } - else if (ValueType == TypeStateLabel) + else if (ValueType->isClassPointer()) + { + FxExpression *x = new FxClassTypeCast(static_cast(ValueType), basex, Explicit); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + /* else if (ValueType->isEnum()) + { + // this is not yet ready and does not get assigned to actual values. + } + */ + else if (ValueType->isClass()) // this should never happen because the VM doesn't handle plain class types - just pointers { - if (basex->ValueType == TypeNullPtr) + if (basex->ValueType->isClass()) { - auto x = new FxConstant(0, ScriptPosition); - x->ValueType = TypeStateLabel; - delete this; - return x; + // class types are only compatible if the base type is a descendant of the result type. + auto fromtype = static_cast(basex->ValueType)->Descriptor; + auto totype = static_cast(ValueType)->Descriptor; + if (fromtype->IsDescendantOf(totype)) goto basereturn; } - // Right now this only supports string constants. There should be an option to pass a string variable, too. - if (basex->isConstant() && (basex->ValueType == TypeString || basex->ValueType == TypeName)) + } + else if (basex->IsNativeStruct() && ValueType->isRealPointer() && ValueType->toPointer()->PointedType == basex->ValueType) + { + bool writable; + basex->RequestAddress(ctx, &writable); + + if(!writable && !ValueType->toPointer()->IsConst && ctx.Version >= MakeVersion(4, 12)) { - FString s= static_cast(basex)->GetValue().GetString(); - if (s.Len() == 0 && !ctx.FromDecorate) // DECORATE should never get here at all, but let's better be safe. - { - ScriptPosition.Message(MSG_ERROR, "State jump to empty label."); - delete this; - return nullptr; - } - FxExpression *x = new FxMultiNameState(s, basex->ScriptPosition); - x = x->Resolve(ctx); - basex = nullptr; - delete this; - return x; - } - else if (basex->IsNumeric() && basex->ValueType != TypeSound && basex->ValueType != TypeColor) - { - if (ctx.StateIndex < 0) - { - ScriptPosition.Message(MSG_ERROR, "State jumps with index can only be used in anonymous state functions."); - delete this; - return nullptr; - } - if (ctx.StateCount != 1) - { - ScriptPosition.Message(MSG_ERROR, "State jumps with index cannot be used on multistate definitions"); - delete this; - return nullptr; - } - if (basex->isConstant()) - { - int i = static_cast(basex)->GetValue().GetInt(); - if (i <= 0) - { - ScriptPosition.Message(MSG_ERROR, "State index must be positive"); - delete this; - return nullptr; - } - FxExpression *x = new FxStateByIndex(ctx.StateIndex + i, ScriptPosition); - x = x->Resolve(ctx); - basex = nullptr; - delete this; - return x; - } - else - { - FxExpression *x = new FxRuntimeStateIndex(basex); - x = x->Resolve(ctx); - basex = nullptr; - delete this; - return x; - } - } - } - else if (ValueType->isClassPointer()) - { - FxExpression *x = new FxClassTypeCast(static_cast(ValueType), basex, Explicit); - x = x->Resolve(ctx); - basex = nullptr; - delete this; - return x; - } - /* else if (ValueType->isEnum()) - { - // this is not yet ready and does not get assigned to actual values. - } - */ - else if (ValueType->isClass()) // this should never happen because the VM doesn't handle plain class types - just pointers - { - if (basex->ValueType->isClass()) - { - // class types are only compatible if the base type is a descendant of the result type. - auto fromtype = static_cast(basex->ValueType)->Descriptor; - auto totype = static_cast(ValueType)->Descriptor; - if (fromtype->IsDescendantOf(totype)) goto basereturn; + ScriptPosition.Message(MSG_ERROR, "Trying to assign readonly value to writable type."); } - } - else if (basex->IsNativeStruct() && ValueType->isRealPointer() && ValueType->toPointer()->PointedType == basex->ValueType) - { - bool writable; - basex->RequestAddress(ctx, &writable); + basex->ValueType = ValueType; auto x = basex; basex = nullptr; @@ -1757,6 +1967,13 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) delete this; return x; } + else if ((basex->IsVector2() && IsVector2()) || (basex->IsVector3() && IsVector3()) || (basex->IsVector4() && IsVector4()) || (basex->IsQuaternion() && IsQuaternion())) + { + auto x = basex; + basex = nullptr; + delete this; + return x; + } // todo: pointers to class objects. // All other types are only compatible to themselves and have already been handled above by the equality check. // Anything that falls through here is not compatible and must print an error. @@ -1822,7 +2039,7 @@ FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) CHECKRESOLVED(); SAFE_RESOLVE(Operand, ctx); - if (Operand->IsNumeric() || Operand->IsVector()) + if (Operand->IsNumeric() || Operand->IsVector() || Operand->IsQuaternion()) { FxExpression *e = Operand; Operand = nullptr; @@ -1876,7 +2093,7 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) CHECKRESOLVED(); SAFE_RESOLVE(Operand, ctx); - if (Operand->IsNumeric() || Operand->IsVector()) + if (Operand->IsNumeric() || Operand->IsVector() || Operand->IsQuaternion()) { if (Operand->isConstant()) { @@ -1912,9 +2129,19 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) { - assert(ValueType == Operand->ValueType); + //assert(ValueType == Operand->ValueType); ExpEmit from = Operand->Emit(build); + if(from.Konst && from.RegType == REGT_INT) + { // this is needed here because the int const assign optimization returns a constant + ExpEmit to; + to.Konst = true; + to.RegType = REGT_INT; + to.RegNum = build->GetConstantInt(-build->FindConstantInt(from.RegNum)); + return to; + } + ExpEmit to; + assert(from.Konst == 0); assert(ValueType->GetRegCount() == from.RegCount); // Do it in-place, unless a local variable @@ -1949,6 +2176,10 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) build->Emit(OP_NEGV3, to.RegNum, from.RegNum); break; + case 4: + build->Emit(OP_NEGV4, to.RegNum, from.RegNum); + break; + } } return to; @@ -2030,10 +2261,20 @@ ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) { assert(Operand->ValueType->GetRegType() == REGT_INT); ExpEmit from = Operand->Emit(build); + + if(from.Konst && from.RegType == REGT_INT) + { // this is needed here because the int const assign optimization returns a constant + ExpEmit to; + to.Konst = true; + to.RegType = REGT_INT; + to.RegNum = build->GetConstantInt(~build->FindConstantInt(from.RegNum)); + return to; + } + from.Free(build); ExpEmit to(build, REGT_INT); assert(!from.Konst); - + build->Emit(OP_NOT, to.RegNum, from.RegNum, 0); return to; } @@ -2101,6 +2342,16 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) assert(Operand->ValueType == TypeBool); assert(ValueType == TypeBool || IsInteger()); // this may have been changed by an int cast. ExpEmit from = Operand->Emit(build); + + if(from.Konst && from.RegType == REGT_INT) + { // this is needed here because the int const assign optimization returns a constant + ExpEmit to; + to.Konst = true; + to.RegType = REGT_INT; + to.RegNum = build->GetConstantInt(!build->FindConstantInt(from.RegNum)); + return to; + } + from.Free(build); ExpEmit to(build, REGT_INT); assert(!from.Konst); @@ -2239,7 +2490,6 @@ FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) { assert(Token == TK_Incr || Token == TK_Decr); - assert(ValueType == Base->ValueType && IsNumeric()); int zero = build->GetConstantInt(0); int regtype = ValueType->GetRegType(); @@ -2326,7 +2576,6 @@ FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) { assert(Token == TK_Incr || Token == TK_Decr); - assert(ValueType == Base->ValueType && IsNumeric()); int zero = build->GetConstantInt(0); int regtype = ValueType->GetRegType(); @@ -2448,7 +2697,17 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Right, ctx); } } - else if (Base->ValueType == Right->ValueType) + else if (Right->IsNativeStruct() && Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType) + { + // allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers. + // For all other types this is not needed. Structs are not assignable and classes can only exist as references. + Right->RequestAddress(ctx, nullptr); + Right->ValueType = Base->ValueType; + } + else if ( Base->ValueType == Right->ValueType + || (Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType) + || (Right->ValueType->isRealPointer() && Right->ValueType->toPointer()->PointedType == Base->ValueType) + ) { if (Base->ValueType->isArray()) { @@ -2456,28 +2715,103 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) delete this; return nullptr; } - else if (Base->IsDynamicArray()) - { - ScriptPosition.Message(MSG_ERROR, "Cannot assign dynamic arrays, use Copy() or Move() function instead"); - delete this; - return nullptr; - } - if (!Base->IsVector() && Base->ValueType->isStruct()) + else if(!Base->IsVector() && !Base->IsQuaternion()) { - ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet"); - delete this; - return nullptr; + PType * btype = Base->ValueType; + + if(btype->isRealPointer()) + { + PType * p = static_cast(btype)->PointedType; + if( p->isDynArray() || p->isMap() + || (p->isStruct() && !static_cast(p)->isNative) + ) + { //un-pointer dynarrays, maps and non-native structs for assignment checking + btype = p; + } + } + + if (btype->isDynArray()) + { + if(ctx.Version >= MakeVersion(4, 11, 1)) + { + FArgumentList args; + args.Push(Right); + auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition); + Right = Base = nullptr; + delete this; + return call->Resolve(ctx); + } + else + { + if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer()) + { + ScriptPosition.Message(MSG_WARNING, "Dynamic Array assignments not allowed in ZScript versions below 4.11.1, use the Copy() or Move() functions instead\n" + TEXTCOLOR_RED " Assigning an out array pointer to another out array pointer\n" + " does not alter either of the underlying arrays' values\n" + " it only swaps the pointers below ZScript version 4.11.1!!"); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Dynamic Array assignments not allowed in ZScript versions below 4.11.1, use the Copy() or Move() functions instead"); + delete this; + return nullptr; + } + } + } + else if (btype->isMap()) + { + if(ctx.Version >= MakeVersion(4, 11, 1)) + { + FArgumentList args; + args.Push(Right); + auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition); + Right = Base = nullptr; + delete this; + return call->Resolve(ctx); + } + else + { + if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer()) + { // don't break existing code, but warn that it's a no-op + ScriptPosition.Message(MSG_WARNING, "Map assignments not allowed in ZScript versions below 4.11.1, use the Copy() or Move() functions instead\n" + TEXTCOLOR_RED " Assigning an out map pointer to another out map pointer\n" + " does not alter either of the underlying maps' values\n" + " it only swaps the pointers below ZScript version 4.11.1!!"); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Map assignments not allowed in ZScript versions below 4.11.1, use the Copy() or Move() functions instead"); + delete this; + return nullptr; + } + } + } + else if (btype->isMapIterator()) + { + ScriptPosition.Message(MSG_ERROR, "Cannot assign map iterators"); + delete this; + return nullptr; + } + else if (btype->isStruct()) + { + if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer()) + { // don't break existing code, but warn that it's a no-op + ScriptPosition.Message(MSG_WARNING, "Struct assignment not implemented yet\n" + TEXTCOLOR_RED " Assigning an out struct pointer to another out struct pointer\n" + " does not alter either of the underlying structs' values\n" + " it only swaps the pointers!!"); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet"); + delete this; + return nullptr; + } + } } + // Both types are the same so this is ok. } - else if (Right->IsNativeStruct() && Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType) - { - // allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers. - // For all other types this is not needed. Structs are not assignable and classes can only exist as references. - bool writable; - Right->RequestAddress(ctx, &writable); - Right->ValueType = Base->ValueType; - } else { // pass it to FxTypeCast for complete handling. @@ -2507,7 +2841,7 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) ExpEmit result; bool intconst = false; - int intconstval; + int intconstval = 0; if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT) { @@ -2563,7 +2897,15 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) } pointer.Free(build); - return result; + + if(intconst) + { //fix int constant return for assignment + return Right->Emit(build); + } + else + { + return result; + } } //========================================================================== @@ -2592,7 +2934,6 @@ FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx) ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) { - assert(ValueType == Assignment->ValueType); ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it if (!pointer.Target) { @@ -2658,6 +2999,12 @@ FxExpression *FxMultiAssign::Resolve(FCompileContext &ctx) } auto VMRight = static_cast(Right); auto rets = VMRight->GetReturnTypes(); + if (Base.Size() == 1) + { + Right->ScriptPosition.Message(MSG_ERROR, "Multi-assignment with only one element in function %s", VMRight->Function->SymbolName.GetChars()); + delete this; + return nullptr; + } if (rets.Size() < Base.Size()) { Right->ScriptPosition.Message(MSG_ERROR, "Insufficient returns in function %s", VMRight->Function->SymbolName.GetChars()); @@ -2704,6 +3051,75 @@ ExpEmit FxMultiAssign::Emit(VMFunctionBuilder *build) return LocalVarContainer->Emit(build); } + +//========================================================================== +// +// +// +//========================================================================== + +FxMultiAssignDecl::FxMultiAssignDecl(FArgumentList &base, FxExpression *right, const FScriptPosition &pos) + :FxExpression(EFX_MultiAssignDecl, pos) +{ + Base = std::move(base); + Right = right; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMultiAssignDecl::~FxMultiAssignDecl() +{ + SAFE_DELETE(Right); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMultiAssignDecl::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Right, ctx); + if (Right->ExprType != EFX_VMFunctionCall) + { + Right->ScriptPosition.Message(MSG_ERROR, "Function call expected on right side of multi-assigment"); + delete this; + return nullptr; + } + auto VMRight = static_cast(Right); + auto rets = VMRight->GetReturnTypes(); + if (Base.Size() == 1) + { + Right->ScriptPosition.Message(MSG_ERROR, "Multi-assignment with only one element in function %s", VMRight->Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + if (rets.Size() < Base.Size()) + { + Right->ScriptPosition.Message(MSG_ERROR, "Insufficient returns in function %s", VMRight->Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + FxSequence * DeclAndAssign = new FxSequence(ScriptPosition); + const unsigned int n = Base.Size(); + for (unsigned int i = 0; i < n; i++) + { + assert(Base[i]->ExprType == EFX_Identifier); + DeclAndAssign->Add(new FxLocalVariableDeclaration(rets[i], ((FxIdentifier*)Base[i])->Identifier, nullptr, 0, Base[i]->ScriptPosition)); + } + DeclAndAssign->Add(new FxMultiAssign(Base, Right, ScriptPosition)); + Right = nullptr; + delete this; + return DeclAndAssign->Resolve(ctx); +} + + //========================================================================== // // @@ -2736,13 +3152,26 @@ FxBinary::~FxBinary() // //========================================================================== -bool FxBinary::Promote(FCompileContext &ctx, bool forceint) +bool FxBinary::Promote(FCompileContext &ctx, bool forceint, bool shiftop) { // math operations of unsigned ints results in an unsigned int. (16 and 8 bit values never get here, they get promoted to regular ints elsewhere already.) if (left->ValueType == TypeUInt32 && right->ValueType == TypeUInt32) { ValueType = TypeUInt32; } + // If one side is an unsigned 32-bit int and the other side is a signed 32-bit int, the signed side is implicitly converted to unsigned, + else if (!ctx.FromDecorate && left->ValueType == TypeUInt32 && right->ValueType == TypeSInt32 && !shiftop && ctx.Version >= MakeVersion(4, 9, 0)) + { + right = new FxIntCast(right, false, false, true); + right = right->Resolve(ctx); + ValueType = TypeUInt32; + } + else if (!ctx.FromDecorate && left->ValueType == TypeSInt32 && right->ValueType == TypeUInt32 && !shiftop && ctx.Version >= MakeVersion(4, 9, 0)) + { + left = new FxIntCast(left, false, false, true); + left = left->Resolve(ctx); + ValueType = TypeUInt32; + } else if (left->IsInteger() && right->IsInteger()) { ValueType = TypeSInt32; // Addition and subtraction forces all integer-derived types to signed int. @@ -2786,6 +3215,15 @@ bool FxBinary::Promote(FCompileContext &ctx, bool forceint) delete this; return false; } + + // shift operators are different: The left operand defines the type and the right operand must always be made unsigned + if (shiftop) + { + ValueType = left->ValueType == TypeUInt32 ? TypeUInt32 : TypeSInt32; + right = new FxIntCast(right, false, false, true); + right = right->Resolve(ctx); + } + return true; } @@ -2818,22 +3256,28 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) return nullptr; } + if (compileEnvironment.CheckForCustomAddition) + { + auto result = compileEnvironment.CheckForCustomAddition(this, ctx); + if (result) + { + ABORT(right); + goto goon; + } + } + if (left->ValueType == TypeTextureID && right->IsInteger()) { ValueType = TypeTextureID; } - else if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant()) + else if (left->IsQuaternion() && right->IsQuaternion()) { - // This is the only special case of pointer addition that will be accepted - because it is used quite often in the existing game code. - ValueType = TypeState; - right = new FxMulDiv('*', right, new FxConstant((int)sizeof(FState), ScriptPosition)); // multiply by size here, so that constants can be better optimized. - right = right->Resolve(ctx); - ABORT(right); + ValueType = left->ValueType; } else if (left->IsVector() && right->IsVector()) { // a vector2 can be added to or subtracted from a vector 3 but it needs to be the right operand. - if (left->ValueType == right->ValueType || (left->ValueType == TypeVector3 && right->ValueType == TypeVector2)) + if (((left->IsVector3() || left->IsVector2()) && right->IsVector2()) || (left->IsVector3() && right->IsVector3()) || (left->IsVector4() && right->IsVector4())) { ValueType = left->ValueType; } @@ -2851,7 +3295,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) // To check: It may be that this could pass in DECORATE, although setting TypeVoid here would pretty much prevent that. goto error; } - +goon: if (left->isConstant() && right->isConstant()) { if (IsFloat()) @@ -2917,7 +3361,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) // Since addition is commutative, only the second operand may be a constant. if (op1.Konst) { - swapvalues(op1, op2); + std::swap(op1, op2); } assert(!op1.Konst); op1.Free(build); @@ -2926,14 +3370,22 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) if (IsVector()) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); - build->Emit(right->ValueType == TypeVector2? OP_ADDV2_RR : OP_ADDV3_RR, to.RegNum, op1.RegNum, op2.RegNum); - if (left->ValueType == TypeVector3 && right->ValueType == TypeVector2 && to.RegNum != op1.RegNum) + + build->Emit(right->IsVector4() ? OP_ADDV4_RR : right->IsVector3() ? OP_ADDV3_RR : OP_ADDV2_RR, to.RegNum, op1.RegNum, op2.RegNum); + if (left->IsVector3() && right->IsVector2() && to.RegNum != op1.RegNum) { // must move the z-coordinate build->Emit(OP_MOVEF, to.RegNum + 2, op1.RegNum + 2); } return to; } + else if (IsQuaternion()) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + assert(op1.RegCount == 4 && op2.RegCount == 4); + build->Emit(OP_ADDV4_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } else if (ValueType->GetRegType() == REGT_FLOAT) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); @@ -2959,7 +3411,14 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) if (IsVector()) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); - build->Emit(right->ValueType == TypeVector2 ? OP_SUBV2_RR : OP_SUBV3_RR, to.RegNum, op1.RegNum, op2.RegNum); + build->Emit(right->IsVector4() ? OP_SUBV4_RR : right->IsVector3() ? OP_SUBV3_RR : OP_SUBV2_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else if (IsQuaternion()) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + assert(op1.RegCount == 4 && op2.RegCount == 4); + build->Emit(OP_SUBV4_RR, to.RegNum, op1.RegNum, op2.RegNum); return to; } else if (ValueType->GetRegType() == REGT_FLOAT) @@ -3027,16 +3486,24 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) return nullptr; } - if (left->IsVector() || right->IsVector()) + if (left->IsVector() || right->IsVector() || left->IsQuaternion() || right->IsQuaternion()) { switch (Operator) { case '/': // For division, the vector must be the first operand. if (right->IsVector()) goto error; + [[fallthrough]]; case '*': - if (left->IsVector() && right->IsNumeric()) + if (Operator == '*' && left->IsQuaternion() && (right->IsVector3() || right->IsQuaternion())) + { + // quat * vec3 + // quat * quat + ValueType = right->ValueType; + break; + } + else if ((left->IsVector() || left->IsQuaternion()) && right->IsNumeric()) { if (right->IsInteger()) { @@ -3051,7 +3518,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) ValueType = left->ValueType; break; } - else if (right->IsVector() && left->IsNumeric()) + else if ((right->IsVector() || right->IsQuaternion()) && left->IsNumeric()) { if (left->IsInteger()) { @@ -3151,21 +3618,37 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) ExpEmit op1 = left->Emit(build); ExpEmit op2 = right->Emit(build); - if (IsVector()) + if (Operator == '*' && left->IsQuaternion() && right->IsQuaternion()) { - assert(Operator != '%'); - if (right->IsVector()) - { - swapvalues(op1, op2); - } - int op; - if (op2.Konst) - { - op = Operator == '*' ? (ValueType == TypeVector2 ? OP_MULVF2_RK : OP_MULVF3_RK) : (ValueType == TypeVector2 ? OP_DIVVF2_RK : OP_DIVVF3_RK); + op1.Free(build); + op2.Free(build); + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + build->Emit(OP_MULQQ_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else if (Operator == '*' && left->IsQuaternion() && right->IsVector3()) + { + op1.Free(build); + op2.Free(build); + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + build->Emit(OP_MULQV3_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else if (IsVector() || IsQuaternion()) + { + assert(Operator != '%'); + if (left->IsFloat()) + { + std::swap(op1, op2); + } + int op; + if (op2.Konst) + { + op = Operator == '*' ? (IsVector2() ? OP_MULVF2_RK : IsVector3() ? OP_MULVF3_RK : OP_MULVF4_RK) : (IsVector2() ? OP_DIVVF2_RK : IsVector3() ? OP_DIVVF3_RK : OP_DIVVF4_RK); } else { - op = Operator == '*' ? (ValueType == TypeVector2 ? OP_MULVF2_RR : OP_MULVF3_RR) : (ValueType == TypeVector2 ? OP_DIVVF2_RR : OP_DIVVF3_RR); + op = Operator == '*' ? (IsVector2() ? OP_MULVF2_RR : IsVector3() ? OP_MULVF3_RR : OP_MULVF4_RR) : (IsVector2() ? OP_DIVVF2_RR : IsVector3() ? OP_DIVVF3_RR : OP_DIVVF4_RR); } op1.Free(build); op2.Free(build); @@ -3179,7 +3662,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) // Multiplication is commutative, so only the second operand may be constant. if (op1.Konst) { - swapvalues(op1, op2); + std::swap(op1, op2); } assert(!op1.Konst); op1.Free(build); @@ -3351,6 +3834,16 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) delete left; left = x; } + else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12)) + { + right = new FxTypeCast(right, TypeSInt32, true); + SAFE_RESOLVE(right, ctx); + } + else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12)) + { + left = new FxTypeCast(left, TypeSInt32, true); + SAFE_RESOLVE(left, ctx); + } if (left->ValueType == TypeString || right->ValueType == TypeString) { @@ -3378,6 +3871,59 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) } else if (left->IsNumeric() && right->IsNumeric()) { + if (left->IsInteger() && right->IsInteger()) + { + if (ctx.Version >= MakeVersion(4, 9, 0)) + { + // We need to do more checks here to catch problem cases. + if (left->ValueType == TypeUInt32 && right->ValueType == TypeSInt32) + { + if (left->isConstant() && !right->isConstant()) + { + auto val = static_cast(left)->GetValue().GetUInt(); + if (val > INT_MAX) + { + ScriptPosition.Message(MSG_WARNING, "Comparison of signed value with out of range unsigned constant"); + } + } + else if (right->isConstant() && !left->isConstant()) + { + auto val = static_cast(right)->GetValue().GetInt(); + if (val < 0) + { + ScriptPosition.Message(MSG_WARNING, "Comparison of unsigned value with negative constant"); + } + } + else if (!left->isConstant() && !right->isConstant()) + { + ScriptPosition.Message(MSG_WARNING, "Comparison between signed and unsigned value"); + } + } + else if (left->ValueType == TypeSInt32 && right->ValueType == TypeUInt32) + { + if (left->isConstant() && !right->isConstant()) + { + auto val = static_cast(left)->GetValue().GetInt(); + if (val < 0) + { + ScriptPosition.Message(MSG_WARNING, "Comparison of unsigned value with negative constant"); + } + } + else if (right->isConstant() && !left->isConstant()) + { + auto val = static_cast(right)->GetValue().GetUInt(); + if (val > INT_MAX) + { + ScriptPosition.Message(MSG_WARNING, "Comparison of signed value with out of range unsigned constant"); + } + } + else if (!left->isConstant() && !right->isConstant()) + { + ScriptPosition.Message(MSG_WARNING, "Comparison between signed and unsigned value"); + } + } + } + } Promote(ctx); } else @@ -3576,7 +4122,8 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) return nullptr; } - if (left->ValueType != right->ValueType) // identical types are always comparable, if they can be placed in a register, so we can save most checks if this is the case. + // identical types are always comparable, if they can be placed in a register, so we can save most checks if this is the case. + if (left->ValueType != right->ValueType && !(left->IsVector2() && right->IsVector2()) && !(left->IsVector3() && right->IsVector3()) && !(left->IsVector4() && right->IsVector4()) && !(left->IsQuaternion() && right->IsQuaternion())) { FxExpression *x; if (left->IsNumeric() && right->ValueType == TypeString && (x = StringConstToChar(right))) @@ -3589,6 +4136,17 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) delete left; left = x; } + else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12)) + { + right = new FxIntCast(right, true, true); + SAFE_RESOLVE(right, ctx); + } + else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12)) + { + left = new FxTypeCast(left, TypeSInt32, true); + SAFE_RESOLVE(left, ctx); + } + // Special cases: Compare strings and names with names, sounds, colors, state labels and class types. // These are all types a string can be implicitly cast into, so for convenience, so they should when doing a comparison. if ((left->ValueType == TypeString || left->ValueType == TypeName) && @@ -3811,14 +4369,14 @@ ExpEmit FxCompareEq::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool // Only the second operand may be constant. if (op1.Konst) { - swapvalues(op1, op2); + std::swap(op1, op2); } assert(!op1.Konst); - assert(op1.RegCount >= 1 && op1.RegCount <= 3); + assert(op1.RegCount >= 1 && op1.RegCount <= 4); ExpEmit to(build, REGT_INT); - static int flops[] = { OP_EQF_R, OP_EQV2_R, OP_EQV3_R }; + static int flops[] = { OP_EQF_R, OP_EQV2_R, OP_EQV3_R, OP_EQV4_R }; instr = op1.RegType == REGT_INT ? OP_EQ_R : op1.RegType == REGT_FLOAT ? flops[op1.RegCount - 1] : OP_EQA_R; @@ -3934,7 +4492,7 @@ ExpEmit FxBitOp::Emit(VMFunctionBuilder *build) op2 = right->Emit(build); if (op1.Konst) { - swapvalues(op1, op2); + std::swap(op1, op2); } assert(!op1.Konst); rop = op2.RegNum; @@ -3982,7 +4540,7 @@ FxExpression *FxShift::Resolve(FCompileContext& ctx) if (left->IsNumeric() && right->IsNumeric()) { - if (!Promote(ctx, true)) return nullptr; + if (!Promote(ctx, true, true)) return nullptr; if ((left->ValueType == TypeUInt32 && ctx.Version >= MakeVersion(3, 7)) && Operator == TK_RShift) Operator = TK_URShift; } else @@ -4234,13 +4792,14 @@ ExpEmit FxConcat::Emit(VMFunctionBuilder *build) build->Emit(op1.RegType == REGT_INT ? OP_LK : op1.RegType == REGT_FLOAT ? OP_LKF : OP_LKP, nonconst.RegNum, op1.RegNum); op1 = nonconst; } - if (op1.RegType == REGT_FLOAT) cast = op1.RegCount == 1 ? CAST_F2S : op1.RegCount == 2 ? CAST_V22S : CAST_V32S; + if (op1.RegType == REGT_FLOAT) cast = op1.RegCount == 1 ? CAST_F2S : op1.RegCount == 2 ? CAST_V22S : op1.RegCount == 3 ? CAST_V32S : CAST_V42S; else if (left->ValueType == TypeUInt32) cast = CAST_U2S; else if (left->ValueType == TypeName) cast = CAST_N2S; else if (left->ValueType == TypeSound) cast = CAST_So2S; else if (left->ValueType == TypeColor) cast = CAST_Co2S; else if (left->ValueType == TypeSpriteID) cast = CAST_SID2S; else if (left->ValueType == TypeTextureID) cast = CAST_TID2S; + else if (left->ValueType == TypeTranslationID) cast = CAST_U2S; else if (op1.RegType == REGT_POINTER) cast = CAST_P2S; else if (op1.RegType == REGT_INT) cast = CAST_I2S; else assert(false && "Bad type for string concatenation"); @@ -4267,13 +4826,14 @@ ExpEmit FxConcat::Emit(VMFunctionBuilder *build) build->Emit(op2.RegType == REGT_INT ? OP_LK : op2.RegType == REGT_FLOAT ? OP_LKF : OP_LKP, nonconst.RegNum, op2.RegNum); op2 = nonconst; } - if (op2.RegType == REGT_FLOAT) cast = op2.RegCount == 1 ? CAST_F2S : op2.RegCount == 2 ? CAST_V22S : CAST_V32S; + if (op2.RegType == REGT_FLOAT) cast = op2.RegCount == 1 ? CAST_F2S : op2.RegCount == 2 ? CAST_V22S : op2.RegCount == 3 ? CAST_V32S : CAST_V42S; else if (right->ValueType == TypeUInt32) cast = CAST_U2S; else if (right->ValueType == TypeName) cast = CAST_N2S; else if (right->ValueType == TypeSound) cast = CAST_So2S; else if (right->ValueType == TypeColor) cast = CAST_Co2S; else if (right->ValueType == TypeSpriteID) cast = CAST_SID2S; else if (right->ValueType == TypeTextureID) cast = CAST_TID2S; + else if (right->ValueType == TypeTranslationID) cast = CAST_U2S; else if (op2.RegType == REGT_POINTER) cast = CAST_P2S; else if (op2.RegType == REGT_INT) cast = CAST_I2S; else assert(false && "Bad type for string concatenation"); @@ -4349,13 +4909,13 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) { if (b_left==0 || b_right==0) { - FxExpression *x = new FxConstant(true, ScriptPosition); + FxExpression *x = new FxConstant(false, ScriptPosition); delete this; return x; } else if (b_left==1 && b_right==1) { - FxExpression *x = new FxConstant(false, ScriptPosition); + FxExpression *x = new FxConstant(true, ScriptPosition); delete this; return x; } @@ -4464,7 +5024,7 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 1 : 0); build->Emit(OP_JMP, 1); build->BackpatchListToHere(no); - auto ctarget = build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1); + build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1); list.DeleteAndClear(); list.ShrinkToFit(); return to; @@ -4530,7 +5090,7 @@ ExpEmit FxDotCross::Emit(VMFunctionBuilder *build) ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); ExpEmit op1 = left->Emit(build); ExpEmit op2 = right->Emit(build); - int op = Operator == TK_Cross ? OP_CROSSV_RR : left->ValueType == TypeVector3 ? OP_DOTV3_RR : OP_DOTV2_RR; + int op = Operator == TK_Cross ? OP_CROSSV_RR : left->ValueType == TypeVector4 ? OP_DOTV4_RR : left->ValueType == TypeVector3 ? OP_DOTV3_RR : OP_DOTV2_RR; build->Emit(op, to.RegNum, op1.RegNum, op2.RegNum); op1.Free(build); op2.Free(build); @@ -4584,7 +5144,7 @@ FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx) } else { - left = new FxTypeCast(left, NewPointer(RUNTIME_CLASS(DObject)), false); + left = new FxTypeCast(left, NewPointer(RUNTIME_CLASS(DObject), true), false); ClassCheck = false; } right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), right, false); @@ -4745,11 +5305,24 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) ValueType = truex->ValueType; else if (falsex->IsPointer() && truex->ValueType == TypeNullPtr) ValueType = falsex->ValueType; + // translation IDs need a bit of glue for compatibility and the 0 literal. + else if (truex->IsInteger() && falsex->ValueType == TypeTranslationID) + { + truex = new FxTranslationCast(truex); + truex = truex->Resolve(ctx); + ValueType = ctx.Version < MakeVersion(4, 12, 0)? TypeSInt32 : TypeTranslationID; + } + else if (falsex->IsInteger() && truex->ValueType == TypeTranslationID) + { + falsex = new FxTranslationCast(falsex); + falsex = falsex->Resolve(ctx); + ValueType = ctx.Version < MakeVersion(4, 12, 0) ? TypeSInt32 : TypeTranslationID; + } + else ValueType = TypeVoid; - //else if (truex->ValueType != falsex->ValueType) - if (ValueType->GetRegType() == REGT_NIL) + if (truex == nullptr || falsex == nullptr || ValueType->GetRegType() == REGT_NIL) { ScriptPosition.Message(MSG_ERROR, "Incompatible types for ?: operator"); delete this; @@ -5062,6 +5635,23 @@ FxExpression *FxATan2::Resolve(FCompileContext &ctx) return this; } +//========================================================================== +// +// The atan2 opcode only takes registers as parameters, so any constants +// must be loaded into registers first. +// +//========================================================================== +ExpEmit FxATan2::ToReg(VMFunctionBuilder* build, FxExpression* val) +{ + if (val->isConstant()) + { + ExpEmit reg(build, REGT_FLOAT); + build->Emit(OP_LKF, reg.RegNum, build->GetConstantFloat(static_cast(val)->GetValue().GetFloat())); + return reg; + } + return val->Emit(build); +} + //========================================================================== // // @@ -5078,6 +5668,61 @@ ExpEmit FxATan2::Emit(VMFunctionBuilder *build) return out; } +//========================================================================== +// +// +// +//========================================================================== +FxATan2Vec::FxATan2Vec(FxExpression* v, const FScriptPosition& pos) + : FxExpression(EFX_ATan2Vec, pos) +{ + vval = v; +} + +//========================================================================== +// +// +// +//========================================================================== +FxATan2Vec::~FxATan2Vec() +{ + SAFE_DELETE(vval); +} + +//========================================================================== +// +// +// +//========================================================================== +FxExpression* FxATan2Vec::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(vval, ctx); + + if (!vval->IsVector()) + { + ScriptPosition.Message(MSG_ERROR, "vector value expected for parameter"); + delete this; + return nullptr; + } + ValueType = TypeFloat64; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== +ExpEmit FxATan2Vec::Emit(VMFunctionBuilder* build) +{ + ExpEmit vreg = vval->Emit(build); + vreg.Free(build); + ExpEmit out(build, REGT_FLOAT); + build->Emit(OP_ATAN2, out.RegNum, vreg.RegNum + 1, vreg.RegNum); + return out; +} + //========================================================================== // // @@ -5150,11 +5795,9 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx) //========================================================================== // -// The CVAR is for finding places where thinkers are created. -// Those will require code changes in ZScript 4.0. +// // //========================================================================== -CVAR(Bool, vm_warnthinkercreation, false, 0) static DObject *BuiltinNew(PClass *cls, int outerside, int backwardscompatible) { @@ -5173,28 +5816,9 @@ static DObject *BuiltinNew(PClass *cls, int outerside, int backwardscompatible) ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); return nullptr; } - // Creating actors here must be outright prohibited, - if (cls->IsDescendantOf(NAME_Actor)) - { - ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); - return nullptr; - } - if ((vm_warnthinkercreation || !backwardscompatible) && cls->IsDescendantOf(NAME_Thinker)) - { - // This must output a diagnostic warning - Printf("Using 'new' to create thinkers is deprecated."); - } // [ZZ] validate readonly and between scope construction if (outerside) FScopeBarrier::ValidateNew(cls, outerside - 1); - DObject *object; - if (!cls->IsDescendantOf(NAME_Thinker)) - { - object = cls->CreateNew(); - } - else - { - object = currentVMLevel->CreateThinker(cls); - } + DObject *object = cls->CreateNew(); return object; } @@ -5213,17 +5837,17 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build) // Call DecoRandom to generate a random number. VMFunction *callfunc; - auto sym = FindBuiltinFunction(NAME_BuiltinNew); - + auto sym = FindBuiltinFunction(compileEnvironment.CustomBuiltinNew != NAME_None? compileEnvironment.CustomBuiltinNew : NAME_BuiltinNew); + assert(sym); callfunc = sym->Variants[0].Implementation; - + FunctionCallEmitter emitters(callfunc); int outerside = -1; if (!val->isConstant()) { - int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags); + outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags); if (outerside == FScopeBarrier::Side_Virtual) outerside = FScopeBarrier::SideFromObjectFlags(CallingFunction->OwningClass->ScopeFlags); } @@ -5234,23 +5858,6 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build) return emitters.EmitCall(build); } -//========================================================================== -// -// The atan2 opcode only takes registers as parameters, so any constants -// must be loaded into registers first. -// -//========================================================================== -ExpEmit FxATan2::ToReg(VMFunctionBuilder *build, FxExpression *val) -{ - if (val->isConstant()) - { - ExpEmit reg(build, REGT_FLOAT); - build->Emit(OP_LKF, reg.RegNum, build->GetConstantFloat(static_cast(val)->GetValue().GetFloat())); - return reg; - } - return val->Emit(build); -} - //========================================================================== // // @@ -5348,7 +5955,6 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) else { ExpVal value = static_cast(choices[j])->GetValue(); - assert(value.Type == ValueType); if (Type == NAME_Min) { if (value.Type->GetRegType() == REGT_FLOAT) @@ -5659,8 +6265,6 @@ FxExpression *FxRandomPick::Resolve(FCompileContext &ctx) ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) { - unsigned i; - assert(choices.Size() > 0); // Call BuiltinRandom to generate a random number. @@ -5693,7 +6297,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) // Allocate space for the jump table. size_t jumptable = build->Emit(OP_JMP, 0); - for (i = 1; i < choices.Size(); ++i) + for (unsigned i = 1; i < choices.Size(); ++i) { build->Emit(OP_JMP, 0); } @@ -5729,7 +6333,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) } } // Backpatch each case (except the last, since it ends here) to jump to here. - for (i = 0; i < choices.Size() - 1; ++i) + for (unsigned i = 0; i < choices.Size() - 1; ++i) { build->BackpatchToHere(finishes[i]); } @@ -5978,8 +6582,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) { PSymbol * sym; FxExpression *newex = nullptr; - int num; - + CHECKRESOLVED(); // Local variables have highest priority. @@ -6006,32 +6609,13 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) } } - if (Identifier == NAME_Default) + if (compileEnvironment.CheckSpecialIdentifier) { - if (ctx.Function == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from constant declaration"); - delete this; - return nullptr; - } - if (ctx.Function->Variants[0].SelfClass == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from static function"); - delete this; - return nullptr; - } - if (!isActor(ctx.Function->Variants[0].SelfClass)) - { - ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); - delete this; - return nullptr; - } - - FxExpression * x = new FxClassDefaults(new FxSelf(ScriptPosition), ScriptPosition); - delete this; - return x->Resolve(ctx); + auto result = compileEnvironment.CheckSpecialIdentifier(this, ctx); + if (result != this) return result; } + // Ugh, the horror. Constants need to be taken from the owning class, but members from the self class to catch invalid accesses here... // see if the current class (if valid) defines something with this name. PSymbolTable *symtbl; @@ -6053,6 +6637,15 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ABORT(newex); goto foundit; } + else if (sym->IsKindOf(RUNTIME_CLASS(PFunction))) + { + if (ctx.Version >= MakeVersion(4, 11, 100)) + { + // VMFunction is only supported since 4.12 and Raze 1.8. + newex = new FxConstant(static_cast(sym), ScriptPosition); + goto foundit; + } + } } // now check in the owning class. @@ -6064,6 +6657,15 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) newex = FxConstant::MakeConstant(sym, ScriptPosition); goto foundit; } + else if (sym->IsKindOf(RUNTIME_CLASS(PFunction))) + { + if (ctx.Version >= MakeVersion(4, 11, 100)) + { + // VMFunction is only supported since 4.12 and Raze 1.8. + newex = new FxConstant(static_cast(sym), ScriptPosition); + goto foundit; + } + } else if (ctx.Function == nullptr) { ScriptPosition.Message(MSG_ERROR, "Unable to access class member %s from constant declaration", sym->SymbolName.GetChars()); @@ -6141,7 +6743,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) // even if it depends on some deprecated symbol. // The main motivation here is to keep the deprecated static functions accessing the global level variable as they were. // Print these only if debug output is active and at the highest verbosity level. - const bool internal = (ctx.Function->Variants[0].Flags & VARF_Deprecated) && Wads.GetLumpFile(ctx.Lump) == 0; + const bool internal = (ctx.Function->Variants[0].Flags & VARF_Deprecated) && fileSystem.GetFileContainer(ctx.Lump) == 0; const FString &deprecationMessage = vsym->DeprecationMessage; ScriptPosition.Message(internal ? MSG_DEBUGMSG : MSG_WARNING, @@ -6150,7 +6752,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) deprecationMessage.IsEmpty() ? "" : ", ", deprecationMessage.GetChars()); } } - + newex = new FxGlobalVariable(static_cast(sym), ScriptPosition); goto foundit; @@ -6163,12 +6765,10 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) } } - // and line specials - if (newex == nullptr && (num = P_FindLineSpecial(Identifier, nullptr, nullptr))) + if (compileEnvironment.CheckSpecialGlobalIdentifier) { - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num); - newex = new FxConstant(num, ScriptPosition); - goto foundit; + auto result = compileEnvironment.CheckSpecialGlobalIdentifier(this, ctx); + if (result != this) return result; } if (auto *cvar = FindCVar(Identifier.GetChars(), nullptr)) @@ -6182,7 +6782,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) newex = new FxCVar(cvar, ScriptPosition); goto foundit; } - + ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); delete this; return nullptr; @@ -6204,20 +6804,10 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * PSymbolTable *symtbl; bool isclass = objtype->isClass(); - if (Identifier == NAME_Default) + if (compileEnvironment.ResolveSpecialIdentifier) { - if (!isActor(objtype)) - { - ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); - delete object; - object = nullptr; - return nullptr; - } - - FxExpression * x = new FxClassDefaults(object, ScriptPosition); - object = nullptr; - delete this; - return x->Resolve(ctx); + auto result = compileEnvironment.ResolveSpecialIdentifier(this, object, objtype, ctx); + if (result != this) return result; } if (objtype != nullptr && (sym = objtype->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr) @@ -6371,7 +6961,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) // Thanks to the messed up search logic of the type system, which doesn't allow any search by type name for the basic types at all, // we have to do this manually, though and check for all types that may have values attached explicitly. // (What's the point of attached fields to types if you cannot even search for the types...???) - switch (id) + switch (id.GetIndex()) { default: type = nullptr; @@ -6435,7 +7025,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) SAFE_RESOLVE(Object, ctx); - // check for class or struct constants if the left side is a type name. + // check for class or struct constants/functions if the left side is a type name. if (Object->ValueType == TypeError) { if (ccls != nullptr) @@ -6449,6 +7039,16 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) delete this; return FxConstant::MakeConstant(sym, ScriptPosition); } + else if(sym->IsKindOf(RUNTIME_CLASS(PFunction))) + { + if (ctx.Version >= MakeVersion(4, 11, 100)) + { + // VMFunction is only supported since 4.12 and Raze 1.8. + auto x = new FxConstant(static_cast(sym), ScriptPosition); + delete this; + return x->Resolve(ctx); + } + } else { auto f = dyn_cast(sym); @@ -6483,7 +7083,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) if (Object->ValueType->isRealPointer()) { auto ptype = Object->ValueType->toPointer()->PointedType; - if (ptype->isContainer()) + if (ptype && ptype->isContainer()) { auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(ptype)); delete this; @@ -6526,10 +7126,10 @@ FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx) bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = !ctx.CheckWritable(Variable->VarFlags); + if (writable != nullptr) *writable = ctx.IsWritable(Variable->VarFlags); return true; } - + ExpEmit FxLocalVariable::Emit(VMFunctionBuilder *build) { // 'Out' variables are actually pointers but this fact must be hidden to the script. @@ -6667,56 +7267,6 @@ FxExpression *FxSuper::Resolve(FCompileContext& ctx) // //========================================================================== -FxClassDefaults::FxClassDefaults(FxExpression *X, const FScriptPosition &pos) - : FxExpression(EFX_ClassDefaults, pos) -{ - obj = X; -} - -FxClassDefaults::~FxClassDefaults() -{ - SAFE_DELETE(obj); -} - - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxClassDefaults::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(obj, ctx); - assert(obj->ValueType->isRealPointer()); - ValueType = NewPointer(obj->ValueType->toPointer()->PointedType, true); - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) -{ - ExpEmit ob = obj->Emit(build); - ob.Free(build); - ExpEmit meta(build, REGT_POINTER); - build->Emit(OP_CLSS, meta.RegNum, ob.RegNum); - build->Emit(OP_LP, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); - return meta; - -} - -//========================================================================== -// -// -// -//========================================================================== - FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos) : FxMemberBase(EFX_GlobalVariable, mem, pos) { @@ -6731,7 +7281,7 @@ FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos) bool FxGlobalVariable::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags); + if (writable != nullptr) *writable = AddressWritable && ctx.IsWritable(membervar->Flags, membervar->mDefFileNo); return true; } @@ -6798,12 +7348,12 @@ FxExpression *FxCVar::Resolve(FCompileContext &ctx) switch (CVar->GetRealType()) { case CVAR_Bool: - case CVAR_DummyBool: + case CVAR_Flag: ValueType = TypeBool; break; case CVAR_Int: - case CVAR_DummyInt: + case CVAR_Mask: ValueType = TypeSInt32; break; @@ -6855,11 +7405,11 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) break; case CVAR_String: - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value)); - build->Emit(OP_LCS, dest.RegNum, addr.RegNum, nul); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->mValue)); + build->Emit(OP_LS, dest.RegNum, addr.RegNum, nul); break; - case CVAR_DummyBool: + case CVAR_Flag: { int *pVal; auto cv = static_cast(CVar); @@ -6872,7 +7422,7 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) break; } - case CVAR_DummyInt: + case CVAR_Mask: { auto cv = static_cast(CVar); build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value)); @@ -6924,7 +7474,7 @@ FxStackVariable::~FxStackVariable() bool FxStackVariable::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags); + if (writable != nullptr) *writable = AddressWritable && ctx.IsWritable(membervar->Flags, membervar->mDefFileNo); return true; } @@ -6944,7 +7494,7 @@ FxExpression *FxStackVariable::Resolve(FCompileContext &ctx) ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build) { int offsetreg = -1; - + if (membervar->Offset != 0) offsetreg = build->GetConstantInt((int)membervar->Offset); if (AddressRequested) @@ -7021,12 +7571,12 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable) if (membervar->Flags & VARF_Meta) { // Meta variables are read only. - *writable = false; + if(writable != nullptr) *writable = false; } else if (writable != nullptr) { // [ZZ] original check. - bool bWritable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) && + bool bWritable = (AddressWritable && ctx.IsWritable(membervar->Flags, membervar->mDefFileNo) && (!classx->ValueType->isPointer() || !classx->ValueType->toPointer()->IsConst)); // [ZZ] implement write barrier between different scopes if (bWritable) @@ -7059,19 +7609,10 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(classx, ctx); - if (membervar->SymbolName == NAME_Default) + if (compileEnvironment.CheckSpecialMember) { - if (!classx->ValueType->isObjectPointer() - || !static_cast(classx->ValueType)->PointedClass()->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type"); - delete this; - return nullptr; - } - FxExpression * x = new FxClassDefaults(classx, ScriptPosition); - classx = nullptr; - delete this; - return x->Resolve(ctx); + auto result = compileEnvironment.CheckSpecialMember(this, ctx); + if (result != this) return result; } // [ZZ] support magic @@ -7133,7 +7674,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) classx = nullptr; return x; } - else if (classx->ExprType == EFX_LocalVariable && classx->IsVector()) // vectors are a special case because they are held in registers + else if (classx->ExprType == EFX_LocalVariable && (classx->IsVector() || classx->IsQuaternion())) // vectors are a special case because they are held in registers { // since this is a vector, all potential things that may get here are single float or an xy-vector. auto locvar = static_cast(classx); @@ -7145,7 +7686,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) { locvar->RegOffset = int(membervar->Offset); } - + locvar->ValueType = membervar->Type; classx = nullptr; delete this; @@ -7258,8 +7799,8 @@ FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition // //========================================================================== -FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index) -:FxExpression(EFX_ArrayElement, base->ScriptPosition) +FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index, bool nob) +:FxExpression(EFX_ArrayElement, base->ScriptPosition), noboundscheck(nob) { Array=base; index = _index; @@ -7427,7 +7968,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { PArray *arraytype; - + if (arrayispointer) { auto ptr = Array->ValueType->toPointer(); @@ -7449,7 +7990,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) ExpEmit start; ExpEmit bound; bool nestedarray = false; - + if (SizeAddr != ~0u) { bool ismeta = Array->ExprType == EFX_ClassMember && static_cast(Array)->membervar->Flags & VARF_Meta; @@ -7542,18 +8083,21 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) else { ExpEmit indexv(index->Emit(build)); - if (SizeAddr != ~0u || nestedarray) - { - build->Emit(OP_BOUND_R, indexv.RegNum, bound.RegNum); - bound.Free(build); - } - else if (arraytype->ElementCount > 65535) - { - build->Emit(OP_BOUND_K, indexv.RegNum, build->GetConstantInt(arraytype->ElementCount)); - } - else + if (!noboundscheck) // this is 'foreach' which is known to be inside the bounds. { - build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); + if (SizeAddr != ~0u || nestedarray) + { + build->Emit(OP_BOUND_R, indexv.RegNum, bound.RegNum); + bound.Free(build); + } + else if (arraytype->ElementCount > 65535) + { + build->Emit(OP_BOUND_K, indexv.RegNum, build->GetConstantInt(arraytype->ElementCount)); + } + else + { + build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); + } } if (!start.Konst) @@ -7598,7 +8142,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) else { static int LKR_Ops[] = { OP_LK_R, OP_LKF_R, OP_LKS_R, OP_LKP_R }; - assert(start.RegType == ValueType->GetRegType()); + //assert(start.RegType == ValueType->GetRegType()); ExpEmit dest(build, start.RegType); if (start.RegNum <= 255) { @@ -7666,7 +8210,7 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction // //========================================================================== -FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos) +FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos) : FxExpression(EFX_FunctionCall, pos) { MethodName = methodname; @@ -7674,7 +8218,7 @@ FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &a ArgList = std::move(args); if (rngname != NAME_None) { - switch (MethodName) + switch (MethodName.GetIndex()) { case NAME_Random: case NAME_FRandom: @@ -7709,7 +8253,7 @@ FxFunctionCall::~FxFunctionCall() // //========================================================================== -static bool CheckArgSize(FName fname, FArgumentList &args, int min, int max, FScriptPosition &sc) +bool CheckArgSize(FName fname, FArgumentList &args, int min, int max, FScriptPosition &sc) { int s = args.Size(); if (s < min) @@ -7725,6 +8269,52 @@ static bool CheckArgSize(FName fname, FArgumentList &args, int min, int max, FSc return true; } +//========================================================================== +// +// FindClassMemberFunction +// +// Looks for a name in a class's symbol table and outputs appropriate messages +// +//========================================================================== + +PFunction* FindClassMemberFunction(PContainerType* selfcls, PContainerType* funccls, FName name, FScriptPosition& sc, bool* error, const VersionInfo& version, bool nodeprecated) +{ + // Skip ACS_NamedExecuteWithResult. Anything calling this should use the builtin instead. + if (name == NAME_ACS_NamedExecuteWithResult) return nullptr; + + PSymbolTable* symtable; + auto symbol = selfcls->Symbols.FindSymbolInTable(name, symtable); + auto funcsym = dyn_cast(symbol); + + if (symbol != nullptr) + { + auto cls_ctx = PType::toClass(funccls); + auto cls_target = funcsym ? PType::toClass(funcsym->OwningClass) : nullptr; + if (funcsym == nullptr) + { + if (PClass::FindClass(name)) return nullptr; // Special case when a class's member variable hides a global class name. This should still work. + sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars()); + } + else if ((funcsym->Variants[0].Flags & VARF_Private) && symtable != &funccls->Symbols) + { + // private access is only allowed if the symbol table belongs to the class in which the current function is being defined. + sc.Message(MSG_ERROR, "%s is declared private and not accessible", symbol->SymbolName.GetChars()); + } + else if ((funcsym->Variants[0].Flags & VARF_Protected) && symtable != &funccls->Symbols && (!cls_ctx || !cls_target || !cls_ctx->Descriptor->IsDescendantOf(cls_target->Descriptor))) + { + sc.Message(MSG_ERROR, "%s is declared protected and not accessible", symbol->SymbolName.GetChars()); + } + // ZScript will skip this because it prints its own message. + else if ((funcsym->Variants[0].Flags & VARF_Deprecated) && funcsym->mVersion <= version && !nodeprecated) + { + sc.Message(MSG_WARNING, "Call to deprecated function %s", symbol->SymbolName.GetChars()); + } + } + // return nullptr if the name cannot be found in the symbol table so that the calling code can do other checks. + return funcsym; +} + + //========================================================================== // // @@ -7806,46 +8396,10 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } } - int min, max, special; - if (MethodName == NAME_ACS_NamedExecuteWithResult || MethodName == NAME_CallACS) - { - special = -ACS_ExecuteWithResult; - min = 1; - max = 5; - } - else - { - // This alias is needed because Actor has a Teleport function. - if (MethodName == NAME_TeleportSpecial) MethodName = NAME_Teleport; - special = P_FindLineSpecial(MethodName.GetChars(), &min, &max); - } - if (special != 0 && min >= 0) + if (compileEnvironment.CheckCustomGlobalFunctions) { - int paramcount = ArgList.Size(); - if (ctx.Function == nullptr || ctx.Class == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "Unable to call action special %s from constant declaration", MethodName.GetChars()); - delete this; - return nullptr; - } - else if (paramcount < min) - { - ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)", - MethodName.GetChars(), min, paramcount); - delete this; - return nullptr; - } - else if (paramcount > max) - { - ScriptPosition.Message(MSG_ERROR, "too many parameters for '%s' (expected %d, got %d)", - MethodName.GetChars(), max, paramcount); - delete this; - return nullptr; - } - FxExpression *self = (ctx.Function && (ctx.Function->Variants[0].Flags & VARF_Method) && isActor(ctx.Class)) ? new FxSelf(ScriptPosition) : (FxExpression*)new FxConstant(ScriptPosition); - FxExpression *x = new FxActionSpecialCall(self, special, ArgList, ScriptPosition); - delete this; - return x->Resolve(ctx); + auto result = compileEnvironment.CheckCustomGlobalFunctions(this, ctx); + if (result != this) return result; } PClass *cls = FindClassType(MethodName, ctx); @@ -7870,7 +8424,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) // Note that for all builtins the used arguments have to be nulled in the ArgList so that they won't get deleted before they get used. FxExpression *func = nullptr; - switch (MethodName) + switch (MethodName.GetIndex()) { case NAME_Color: if (ArgList.Size() == 3 || ArgList.Size() == 4) @@ -7900,6 +8454,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) MethodName == NAME_Name ? TypeName : MethodName == NAME_SpriteID ? TypeSpriteID : MethodName == NAME_TextureID ? TypeTextureID : + MethodName == NAME_TranslationID ? TypeTranslationID : MethodName == NAME_State ? TypeState : MethodName == NAME_Color ? TypeColor : (PType*)TypeSound; @@ -7929,14 +8484,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } break; - case NAME_GetDefaultByType: - if (CheckArgSize(NAME_GetDefaultByType, ArgList, 1, 1, ScriptPosition)) - { - func = new FxGetDefaultByType(ArgList[0]); - ArgList[0] = nullptr; - } - break; - case NAME_SetRandomSeed: if (CheckArgSize(NAME_Random, ArgList, 1, 1, ScriptPosition)) { @@ -8014,10 +8561,18 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) case NAME_ATan2: case NAME_VectorAngle: - if (CheckArgSize(MethodName, ArgList, 2, 2, ScriptPosition)) + if (CheckArgSize(MethodName, ArgList, 1, 2, ScriptPosition)) { - func = MethodName == NAME_ATan2 ? new FxATan2(ArgList[0], ArgList[1], ScriptPosition) : new FxATan2(ArgList[1], ArgList[0], ScriptPosition); - ArgList[0] = ArgList[1] = nullptr; + if (ArgList.Size() == 2) + { + func = MethodName == NAME_ATan2 ? new FxATan2(ArgList[0], ArgList[1], ScriptPosition) : new FxATan2(ArgList[1], ArgList[0], ScriptPosition); + ArgList[0] = ArgList[1] = nullptr; + } + else + { + func = new FxATan2Vec(ArgList[0], ScriptPosition); + ArgList[0] = nullptr; + } } break; @@ -8033,8 +8588,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } else if (!ArgList.Size()) { - auto cls = static_cast(ctx.Class)->Descriptor; - ArgList.Push(new FxConstant(cls, NewClassPointer(cls), ScriptPosition)); + auto clss = static_cast(ctx.Class)->Descriptor; + ArgList.Push(new FxConstant(clss, NewClassPointer(clss), ScriptPosition)); } func = new FxNew(ArgList[0]); @@ -8042,6 +8597,25 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } break; + case NAME_FQuat: + case NAME_Quat: + if (CheckArgSize(MethodName, ArgList, 1, 4, ScriptPosition)) + { + // Reuse vector expression + func = new FxQuaternionValue( + ArgList[0], + ArgList.Size() >= 2 ? ArgList[1] : nullptr, + ArgList.Size() >= 3 ? ArgList[2] : nullptr, + ArgList.Size() >= 4 ? ArgList[3] : nullptr, + ScriptPosition + ); + ArgList.Clear(); + + delete this; + auto vector = func->Resolve(ctx); + return vector; + } + break; default: ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars()); @@ -8063,7 +8637,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) // //========================================================================== -FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos) +FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos) : FxExpression(EFX_MemberFunctionCall, pos) { Self = self; @@ -8093,10 +8667,13 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) PContainerType *cls = nullptr; bool staticonly = false; bool novirtual = false; + bool fnptr = false; bool isreadonly = false; PContainerType *ccls = nullptr; + PFunction * afd_override = nullptr; + if (ctx.Class == nullptr) { // There's no way that a member function call can resolve to a constant so abort right away. @@ -8122,6 +8699,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) // because the resulting value type would cause problems in nearly every other place where identifiers are being used. // [ZZ] substitute ccls for String internal type. if (id == NAME_String) ccls = TypeStringStruct; + else if (id == NAME_Quat || id == NAME_FQuat) ccls = TypeQuaternionStruct; else ccls = FindContainerType(id, ctx); if (ccls != nullptr) static_cast(Self)->noglobal = true; } @@ -8169,7 +8747,13 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ValueType->isRealPointer()) { auto pointedType = Self->ValueType->toPointer()->PointedType; - if (pointedType && pointedType->isDynArray()) + + if(pointedType && pointedType->isStruct() && Self->ValueType->toPointer()->IsConst && ctx.Version >= MakeVersion(4, 12)) + { + isreadonly = true; + } + + if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator())) { Self = new FxOutVarDereference(Self, Self->ScriptPosition); SAFE_RESOLVE(Self, ctx); @@ -8202,6 +8786,15 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) // Note: These builtins would better be relegated to the actual type objects, instead of polluting this file, but that's a task for later. // Texture builtins. + if (Self->ValueType->isNumeric()) + { + if (MethodName == NAME_ToVector) + { + Self = new FxToVector(Self); + SAFE_RESOLVE(Self, ctx); + return Self; + } + } else if (Self->ValueType == TypeTextureID) { if (MethodName == NAME_IsValid || MethodName == NAME_IsNull || MethodName == NAME_Exists || MethodName == NAME_SetInvalid || MethodName == NAME_SetNull) @@ -8214,8 +8807,8 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } // No need to create a dedicated node here, all builtins map directly to trivial operations. Self->ValueType = TypeSInt32; // all builtins treat the texture index as integer. - FxExpression *x; - switch (MethodName) + FxExpression *x = nullptr; + switch (MethodName.GetIndex()) { case NAME_IsValid: x = new FxCompareRel('>', Self, new FxConstant(0, ScriptPosition)); @@ -8247,8 +8840,8 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) else if (Self->IsVector()) { - // handle builtins: Vectors got 2: Length and Unit. - if (MethodName == NAME_Length || MethodName == NAME_Unit) + // handle builtins: Vectors got 5. + if (MethodName == NAME_Length || MethodName == NAME_LengthSquared || MethodName == NAME_Sum || MethodName == NAME_Unit || MethodName == NAME_Angle) { if (ArgList.Size() > 0) { @@ -8261,8 +8854,40 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) delete this; return x->Resolve(ctx); } + else if (MethodName == NAME_PlusZ && Self->IsVector3()) + { + if (ArgList.Size() != 1) + { + ScriptPosition.Message(MSG_ERROR, "Incorrect number of parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + auto x = new FxVectorPlusZ(Self, MethodName, ArgList[0]); + Self = nullptr; + ArgList[0] = nullptr; + delete this; + return x->Resolve(ctx); + } } + else if (Self->IsQuaternion()) + { + // Reuse vector built-ins for quaternion + if (MethodName == NAME_Length || MethodName == NAME_LengthSquared || MethodName == NAME_Unit) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + auto x = new FxVectorBuiltin(Self, MethodName); + Self = nullptr; + delete this; + return x->Resolve(ctx); + } + Self->ValueType = TypeQuaternionStruct; + } else if (Self->ValueType == TypeString) { if (MethodName == NAME_Length) // This is an intrinsic because a dedicated opcode exists for it. @@ -8287,6 +8912,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } else { + if (PFunction **Override; ctx.Version >= MakeVersion(4, 11, 0) && (Override = static_cast(Self->ValueType)->FnOverrides.CheckKey(MethodName))) + { + afd_override = *Override; + } + auto elementType = static_cast(Self->ValueType)->ElementType; Self->ValueType = static_cast(Self->ValueType)->BackingType; bool isDynArrayObj = elementType->isObjectPointer(); @@ -8304,7 +8934,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (a->ValueType->isRealPointer()) { auto pointedType = a->ValueType->toPointer()->PointedType; - if (pointedType && pointedType->isDynArray()) + if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator())) { a = new FxOutVarDereference(a, a->ScriptPosition); SAFE_RESOLVE(a, ctx); @@ -8398,7 +9028,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) member->membervar = newfield; Self = nullptr; delete this; - member->ValueType = TypeUInt32; + member->ValueType = TypeSInt32; return member; } else @@ -8411,6 +9041,193 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } } } + else if(Self->IsMap()) + { + PMap * m = static_cast(Self->ValueType); + Self->ValueType = m->BackingType; + + auto mapKeyType = m->KeyType; + auto mapValueType = m->ValueType; + + bool isObjMap = mapValueType->isObjectPointer(); + + if (PFunction **Override; (Override = m->FnOverrides.CheckKey(MethodName))) + { + afd_override = *Override; + } + + // Adapted from DynArray codegen + + int idx = 0; + for (auto &a : ArgList) + { + a = a->Resolve(ctx); + if (a == nullptr) + { + delete this; + return nullptr; + } + if (a->ValueType->isRealPointer()) + { + auto pointedType = a->ValueType->toPointer()->PointedType; + if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator())) + { + a = new FxOutVarDereference(a, a->ScriptPosition); + SAFE_RESOLVE(a, ctx); + } + } + if (isObjMap && (MethodName == NAME_Insert && idx == 1)) + { + // Null pointers are always valid. + if (!a->isConstant() || static_cast(a)->GetValue().GetPointer() != nullptr) + { + if (!a->ValueType->isObjectPointer() || + !static_cast(mapValueType)->PointedClass()->IsAncestorOf(static_cast(a->ValueType)->PointedClass())) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument"); + delete this; + return nullptr; + } + } + } + + if (a->IsMap()) + { + // Copy and Move must turn their parameter into a pointer to the backing struct type. + auto o = static_cast(a->ValueType); + auto backingtype = o->BackingType; + if (mapKeyType != o->KeyType || mapValueType != o->ValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument"); + delete this; + return nullptr; + } + bool writable; + if (!a->RequestAddress(ctx, &writable)) + { + ScriptPosition.Message(MSG_ERROR, "Unable to dereference map variable"); + delete this; + return nullptr; + } + a->ValueType = NewPointer(backingtype); + + // Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.) + if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable) + { + auto member = static_cast(Self); + auto newfield = Create(NAME_None, backingtype, 0, member->membervar->Offset); + member->membervar = newfield; + } + } + else if (a->IsPointer() && Self->ValueType->isPointer()) + { + // the only case which must be checked up front is for pointer arrays receiving a new element. + // Since there is only one native backing class it uses a neutral void pointer as its argument, + // meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here. + if (a->ValueType != mapValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), mapValueType->DescriptiveName()); + delete this; + return nullptr; + } + } + idx++; + + } + } + else if(Self->IsMapIterator()) + { + PMapIterator * mi = static_cast(Self->ValueType); + Self->ValueType = mi->BackingType; + + auto mapKeyType = mi->KeyType; + auto mapValueType = mi->ValueType; + + bool isObjMap = mapValueType->isObjectPointer(); + + if (PFunction **Override; (Override = mi->FnOverrides.CheckKey(MethodName))) + { + afd_override = *Override; + } + + // Adapted from DynArray codegen + + int idx = 0; + for (auto &a : ArgList) + { + a = a->Resolve(ctx); + if (a == nullptr) + { + delete this; + return nullptr; + } + if (a->ValueType->isRealPointer()) + { + auto pointedType = a->ValueType->toPointer()->PointedType; + if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator())) + { + a = new FxOutVarDereference(a, a->ScriptPosition); + SAFE_RESOLVE(a, ctx); + } + } + if (isObjMap && (MethodName == NAME_SetValue && idx == 0)) + { + // Null pointers are always valid. + if (!a->isConstant() || static_cast(a)->GetValue().GetPointer() != nullptr) + { + if (!a->ValueType->isObjectPointer() || + !static_cast(mapValueType)->PointedClass()->IsAncestorOf(static_cast(a->ValueType)->PointedClass())) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument"); + delete this; + return nullptr; + } + } + } + + if (a->IsMap()) + { + // Copy and Move must turn their parameter into a pointer to the backing struct type. + auto o = static_cast(a->ValueType); + auto backingtype = o->BackingType; + if (mapKeyType != o->KeyType || mapValueType != o->ValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument"); + delete this; + return nullptr; + } + bool writable; + if (!a->RequestAddress(ctx, &writable)) + { + ScriptPosition.Message(MSG_ERROR, "Unable to dereference map variable"); + delete this; + return nullptr; + } + a->ValueType = NewPointer(backingtype); + + // Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.) + if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable) + { + auto member = static_cast(Self); + auto newfield = Create(NAME_None, backingtype, 0, member->membervar->Offset); + member->membervar = newfield; + } + } + else if (a->IsPointer() && Self->ValueType->isPointer()) + { + // the only case which must be checked up front is for pointer arrays receiving a new element. + // Since there is only one native backing class it uses a neutral void pointer as its argument, + // meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here. + if (a->ValueType != mapValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), mapValueType->DescriptiveName()); + delete this; + return nullptr; + } + } + idx++; + } + } if (MethodName == NAME_GetParentClass && @@ -8431,8 +9248,16 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return x->Resolve(ctx); } } + if (MethodName == NAME_IsAbstract && Self->ValueType->isClassPointer()) + { + if (CheckArgSize(NAME_IsAbstract, ArgList, 0, 0, ScriptPosition)) + { + auto x = new FxIsAbstract(Self); + return x->Resolve(ctx); + } + } - if (Self->ValueType->isRealPointer()) + if (Self->ValueType->isRealPointer() && Self->ValueType->toPointer()->PointedType) { auto ptype = Self->ValueType->toPointer()->PointedType; cls = ptype->toContainer(); @@ -8457,7 +9282,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return nullptr; } } - else if (Self->ValueType->isStruct()) + else if (Self->ValueType->isStruct() && !isreadonly) { bool writable; @@ -8466,6 +9291,22 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) cls = static_cast(Self->ValueType); Self->ValueType = NewPointer(Self->ValueType); } + else if (Self->ValueType->isFunctionPointer()) + { + auto fn = static_cast(Self->ValueType); + + if(MethodName == NAME_Call && fn->PointedType != TypeVoid) + { // calling a Function pointer isn't allowed + fnptr = true; + afd_override = fn->FakeFunction; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Unknown function %s", MethodName.GetChars()); + delete this; + return nullptr; + } + } else { ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s", MethodName.GetChars()); @@ -8477,7 +9318,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) isresolved: bool error = false; - PFunction *afd = FindClassMemberFunction(cls, ctx.Class, MethodName, ScriptPosition, &error, ctx.Version, !ctx.FromDecorate); + PFunction *afd = afd_override ? afd_override : FindClassMemberFunction(cls, ctx.Class, MethodName, ScriptPosition, &error, ctx.Version, !ctx.FromDecorate); if (error) { delete this; @@ -8539,8 +9380,8 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) { auto clstype = PType::toClass(ctx.Class); - auto ccls = PType::toClass(cls); - if (clstype == nullptr || ccls == nullptr || !clstype->Descriptor->IsDescendantOf(ccls->Descriptor)) + auto cclss = PType::toClass(cls); + if (clstype == nullptr || cclss == nullptr || !clstype->Descriptor->IsDescendantOf(cclss->Descriptor)) { ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here", cls->TypeName.GetChars(), MethodName.GetChars()); delete this; @@ -8585,8 +9426,8 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } // do not pass the self pointer to static functions. - auto self = (afd->Variants[0].Flags & VARF_Method) ? Self : nullptr; - auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, staticonly|novirtual); + auto self = ( fnptr || (afd->Variants[0].Flags & VARF_Method)) ? Self : nullptr; + auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, (staticonly || novirtual) && !fnptr); if (Self == self) Self = nullptr; delete this; return x->Resolve(ctx); @@ -8595,23 +9436,18 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) //========================================================================== // -// FxActionSpecialCall -// -// If special is negative, then the first argument will be treated as a -// name for ACS_NamedExecuteWithResult. +// FxVMFunctionCall // //========================================================================== -FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos) -: FxExpression(EFX_ActionSpecialCall, pos) +FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual) +: FxExpression(EFX_VMFunctionCall, pos) , FnPtrCall((self && self->ValueType) ? self->ValueType->isFunctionPointer() : false) { Self = self; - Special = special; + Function = func; ArgList = std::move(args); - while (ArgList.Size() < 5) - { - ArgList.Push(new FxConstant(0, ScriptPosition)); - } + NoVirtual = novirtual; + CallingFunction = nullptr; } //========================================================================== @@ -8620,9 +9456,8 @@ FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgum // //========================================================================== -FxActionSpecialCall::~FxActionSpecialCall() +FxVMFunctionCall::~FxVMFunctionCall() { - SAFE_DELETE(Self); } //========================================================================== @@ -8631,174 +9466,10 @@ FxActionSpecialCall::~FxActionSpecialCall() // //========================================================================== -FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) +PPrototype *FxVMFunctionCall::ReturnProto() { - CHECKRESOLVED(); - bool failed = false; - - SAFE_RESOLVE_OPT(Self, ctx); - for (unsigned i = 0; i < ArgList.Size(); i++) - { - ArgList[i] = ArgList[i]->Resolve(ctx); - if (ArgList[i] == nullptr) - { - failed = true; - } - else if (Special < 0 && i == 0) - { - if (ArgList[i]->ValueType == TypeString) - { - ArgList[i] = new FxNameCast(ArgList[i]); - ArgList[i] = ArgList[i]->Resolve(ctx); - if (ArgList[i] == nullptr) - { - failed = true; - } - } - else if (ArgList[i]->ValueType != TypeName) - { - ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i); - failed = true; - } - } - else if (!ArgList[i]->IsInteger()) - { - if (ArgList[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */) - { - ArgList[i] = new FxIntCast(ArgList[i], ctx.FromDecorate); - ArgList[i] = ArgList[i]->Resolve(ctx); - if (ArgList[i] == nullptr) - { - delete this; - return nullptr; - } - } - else - { - ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i); - failed = true; - } - } - } - - - if (failed) - { - delete this; - return nullptr; - } - ValueType = TypeSInt32; - return this; -} - - -//========================================================================== -// -// -// -//========================================================================== - -int BuiltinCallLineSpecial(int special, AActor *activator, int arg1, int arg2, int arg3, int arg4, int arg5) -{ - return P_ExecuteSpecial(currentVMLevel , special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinCallLineSpecial, BuiltinCallLineSpecial) -{ - PARAM_PROLOGUE; - PARAM_INT(special); - PARAM_OBJECT(activator, AActor); - PARAM_INT(arg1); - PARAM_INT(arg2); - PARAM_INT(arg3); - PARAM_INT(arg4); - PARAM_INT(arg5); - - ACTION_RETURN_INT(P_ExecuteSpecial(currentVMLevel, special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5)); -} - -ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) -{ - unsigned i = 0; - - // Call the BuiltinCallLineSpecial function to perform the desired special. - static uint8_t reginfo[] = { REGT_INT, REGT_POINTER, REGT_INT, REGT_INT, REGT_INT, REGT_INT, REGT_INT }; - auto sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial); - - assert(sym); - auto callfunc = sym->Variants[0].Implementation; - - FunctionCallEmitter emitters(callfunc); - - emitters.AddParameterIntConst(abs(Special)); // pass special number - emitters.AddParameter(build, Self); - - - for (; i < ArgList.Size(); ++i) - { - FxExpression *argex = ArgList[i]; - if (Special < 0 && i == 0) - { - assert(argex->ValueType == TypeName); - assert(argex->isConstant()); - emitters.AddParameterIntConst(-static_cast(argex)->GetValue().GetName()); - } - else - { - assert(argex->ValueType->GetRegType() == REGT_INT); - if (argex->isConstant()) - { - emitters.AddParameterIntConst(static_cast(argex)->GetValue().GetInt()); - } - else - { - emitters.AddParameter(build, argex); - } - } - } - ArgList.DeleteAndClear(); - ArgList.ShrinkToFit(); - - emitters.AddReturn(REGT_INT); - return emitters.EmitCall(build); -} - -//========================================================================== -// -// FxVMFunctionCall -// -//========================================================================== - -FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual) -: FxExpression(EFX_VMFunctionCall, pos) -{ - Self = self; - Function = func; - ArgList = std::move(args); - NoVirtual = novirtual; - CallingFunction = nullptr; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxVMFunctionCall::~FxVMFunctionCall() -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -PPrototype *FxVMFunctionCall::ReturnProto() -{ - if (hasStringArgs) - return FxExpression::ReturnProto(); + if (hasStringArgs) + return FxExpression::ReturnProto(); return Function->Variants[0].Proto; } @@ -8844,49 +9515,14 @@ VMFunction *FxVMFunctionCall::GetDirectFunction(PFunction *callingfunc, const Ve // definition can call that function directly without wrapping // it inside VM code. - if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual) && CheckAccessibility(ver) && CheckFunctionCompatiblity(ScriptPosition, callingfunc, Function)) + if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual) && !FnPtrCall && CheckAccessibility(ver) && CheckFunctionCompatiblity(ScriptPosition, callingfunc, Function)) { unsigned imp = Function->GetImplicitArgs(); if (Function->Variants[0].ArgFlags.Size() > imp && !(Function->Variants[0].ArgFlags[imp] & VARF_Optional)) return nullptr; return Function->Variants[0].Implementation; } - - return nullptr; -} - -//========================================================================== -// -// FxVMFunctionCall :: UnravelVarArgAJump -// -// Converts A_Jump(chance, a, b, c, d) -> A_Jump(chance, RandomPick[cajump](a, b, c, d)) -// so that varargs are restricted to either text formatting or graphics drawing. -// -//========================================================================== -extern FRandom pr_cajump; - -bool FxVMFunctionCall::UnravelVarArgAJump(FCompileContext &ctx) -{ - FArgumentList rplist; - for (unsigned i = 1; i < ArgList.Size(); i++) - { - // This needs a bit of casting voodoo because RandomPick wants integer parameters. - auto x = new FxIntCast(new FxTypeCast(ArgList[i], TypeStateLabel, true, true), true, true); - rplist.Push(x->Resolve(ctx)); - ArgList[i] = nullptr; - if (rplist[i - 1] == nullptr) - { - return false; - } - } - FxExpression *x = new FxRandomPick(&pr_cajump, rplist, false, ScriptPosition, true); - x = x->Resolve(ctx); - // This cannot be done with a cast because that interprets the value as an index. - // All we want here is to take the literal value and change its type. - if (x) x->ValueType = TypeStateLabel; - ArgList[1] = x; - ArgList.Clamp(2); - return x != nullptr; + return nullptr; } //========================================================================== @@ -8904,9 +9540,13 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) auto &argtypes = proto->ArgumentTypes; auto &argnames = Function->Variants[0].ArgNames; auto &argflags = Function->Variants[0].ArgFlags; - auto &defaults = Function->Variants[0].Implementation->DefaultArgs; + auto *defaults = FnPtrCall ? nullptr : &Function->Variants[0].Implementation->DefaultArgs; - int implicit = Function->GetImplicitArgs(); + if(FnPtrCall) static_cast(ctx.Function->Variants[0].Implementation)->blockJit = true; + + unsigned implicit = Function->GetImplicitArgs(); + + bool relaxed_named_arugments = (ctx.Version >= MakeVersion(4, 13)); if (!CheckAccessibility(ctx.Version)) { @@ -8921,38 +9561,145 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) return nullptr; } - // Unfortunately the PrintableName is the only safe thing to catch this special case here. - if (Function->Variants[0].Implementation->PrintableName.CompareNoCase("Actor.A_Jump [Native]") == 0) + if (compileEnvironment.ResolveSpecialFunction) { - // Unravel the varargs part of this function here so that the VM->native interface does not have to deal with it anymore. - if (ArgList.Size() > 2) - { - auto ret = UnravelVarArgAJump(ctx); - if (!ret) - { - return nullptr; - } - } + auto result = compileEnvironment.ResolveSpecialFunction(this, ctx); + if (!result) return nullptr; + } + + // [Player701] Catch attempts to call abstract functions directly at compile time + if (NoVirtual && Function->Variants[0].Implementation->VarFlags & VARF_Abstract) + { + ScriptPosition.Message(MSG_ERROR, "Cannot call abstract function %s", Function->Variants[0].Implementation->PrintableName); + delete this; + return nullptr; } CallingFunction = ctx.Function; if (ArgList.Size() > 0) { - if (argtypes.Size() == 0) + if ((argtypes.Size() == 0) || (argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size())) { ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars()); delete this; return nullptr; } - + + bool isvararg = (argtypes.Last() == nullptr); + + { + TDeletingArray OrderedArgs; + const unsigned count = (argtypes.Size() - implicit) - isvararg; + + OrderedArgs.Resize(count); + memset(OrderedArgs.Data(), 0, sizeof(FxExpression*) * count); + + unsigned index = 0; + unsigned n = ArgList.Size(); + + for(unsigned i = 0; i < n; i++) + { + if(ArgList[i]->ExprType == EFX_NamedNode) + { + if(FnPtrCall) + { + ScriptPosition.Message(MSG_ERROR, "Named arguments not supported in function pointer calls"); + delete this; + return nullptr; + } + else if((index >= count) && isvararg) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list."); + delete this; + return nullptr; + } + else + { + FName name = static_cast(ArgList[i])->name; + if(argnames[index + implicit] != name) + { + unsigned j; + + for (j = 0; j < count; j++) + { + if (argnames[j + implicit] == name) + { + if(!relaxed_named_arugments && !(argflags[j + implicit] & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed."); + } + else if(!relaxed_named_arugments && j < index) + { + ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars()); + } + + // i don't think this needs any further optimization? + // O(N^2) complexity technically but N isn't likely to be large, + // and the check itself is just an int comparison, so it should be fine + index = j; + + break; + } + } + + if(j == count) + { + ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars()); + delete this; + return nullptr; + } + } + else if(!relaxed_named_arugments && !(argflags[index + implicit] & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed."); + } + } + } + + if(index >= count) + { + if(isvararg) + { + OrderedArgs.Push(ArgList[i]); + ArgList[i] = nullptr; + index++; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + } + else + { + if(ArgList[i]->ExprType == EFX_NamedNode) + { + auto * node = static_cast(ArgList[i]); + OrderedArgs[index] = node->value; + node->value = nullptr; + } + else + { + OrderedArgs[index] = ArgList[i]; + } + ArgList[i] = nullptr; + index++; + } + } + + ArgList = std::move(OrderedArgs); + } + bool foundvarargs = false; PType * type = nullptr; int flag = 0; - if (argtypes.Size() > 0 && argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size()) + + int defaults_index = 0; + + for(unsigned i = 0; i < implicit; i++) { - ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars()); - delete this; - return nullptr; + defaults_index += argtypes[i]->GetRegCount(); } for (unsigned i = 0; i < ArgList.Size(); i++) @@ -8970,88 +9717,45 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) } assert(type != nullptr); - if (ArgList[i]->ExprType == EFX_NamedNode) + if(!foundvarargs) { - if (!(flag & VARF_Optional)) - { - ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed."); - delete this; - return nullptr; - } - if (foundvarargs) - { - ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list."); - delete this; - return nullptr; - } - unsigned j; - bool done = false; - FName name = static_cast(ArgList[i])->name; - for (j = 0; j < argnames.Size() - implicit; j++) + if(ArgList[i] == nullptr) { - if (argnames[j + implicit] == name) + if(!(flag & VARF_Optional)) { - if (j < i) - { - ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars()); - delete this; - return nullptr; - } - // copy the original argument into the list - auto old = static_cast(ArgList[i]); - ArgList[i] = old->value; - old->value = nullptr; - delete old; - // now fill the gap with constants created from the default list so that we got a full list of arguments. - int insert = j - i; - int skipdefs = 0; - // Defaults contain multiple entries for pointers so we need to calculate how much additional defaults we need to skip - for (unsigned k = 0; k < i + implicit; k++) + ScriptPosition.Message(MSG_ERROR, "Required argument %s has not been passed in call to %s", argnames[i + implicit].GetChars(), Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + + auto ntype = argtypes[i + implicit]; + // If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type. + if (argflags[i + implicit] & VARF_Ref) + { + assert(ntype->isPointer()); + ntype = TypeNullPtr; // the default of a reference type can only be a null pointer + } + if (ntype->GetRegCount() == 1) + { + ArgList[i] = new FxConstant(ntype, (*defaults)[defaults_index], ScriptPosition); + } + else + { + // Vectors need special treatment because they are not normal constants + FxConstant *cs[4] = { nullptr }; + for (int l = 0; l < ntype->GetRegCount(); l++) { - skipdefs += argtypes[k]->GetRegCount() - 1; + cs[l] = new FxConstant(TypeFloat64, (*defaults)[l + defaults_index], ScriptPosition); } - for (int k = 0; k < insert; k++) - { - auto ntype = argtypes[i + k + implicit]; - // If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type. - if (argflags[i + k + implicit] & VARF_Ref) - { - assert(ntype->isPointer()); - ntype = TypeNullPtr; // the default of a reference type can only be a null pointer - } - if (ntype->GetRegCount() == 1) - { - auto x = new FxConstant(ntype, defaults[i + k + skipdefs + implicit], ScriptPosition); - ArgList.Insert(i + k, x); - } - else - { - // Vectors need special treatment because they are not normal constants - FxConstant *cs[3] = { nullptr }; - for (int l = 0; l < ntype->GetRegCount(); l++) - { - cs[l] = new FxConstant(TypeFloat64, defaults[l + i + k + skipdefs + implicit], ScriptPosition); - } - FxExpression *x = new FxVectorValue(cs[0], cs[1], cs[2], ScriptPosition); - ArgList.Insert(i + k, x); - skipdefs += ntype->GetRegCount() - 1; - } - } - done = true; - break; + ArgList[i] = new FxVectorValue(cs[0], cs[1], cs[2], cs[3], ScriptPosition); } } - if (!done) - { - ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars()); - delete this; - return nullptr; - } - // re-get the proper info for the inserted node. - type = argtypes[i + implicit]; - flag = argflags[i + implicit]; + + defaults_index += argtypes[i + implicit]->GetRegCount(); } + assert(ArgList[i]); + FxExpression *x = nullptr; if (foundvarargs && (Function->Variants[0].Flags & VARF_VarArg)) { @@ -9078,10 +9782,10 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) bool writable; ArgList[i] = ArgList[i]->Resolve(ctx); // must be resolved before the address is requested. - if (ArgList[i]->ValueType->isRealPointer()) + if (ArgList[i] && ArgList[i]->ValueType->isRealPointer()) { auto pointedType = ArgList[i]->ValueType->toPointer()->PointedType; - if (pointedType && pointedType->isDynArray()) + if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator())) { ArgList[i] = new FxOutVarDereference(ArgList[i], ArgList[i]->ScriptPosition); SAFE_RESOLVE(ArgList[i], ctx); @@ -9167,6 +9871,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { ValueType = TypeVoid; } + return this; } @@ -9192,11 +9897,14 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } } - VMFunction *vmfunc = Function->Variants[0].Implementation; - bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual); + VMFunction *vmfunc = FnPtrCall ? nullptr : Function->Variants[0].Implementation; + bool staticcall = (FnPtrCall || (vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual); count = 0; - FunctionCallEmitter emitters(vmfunc); + + assert(!FnPtrCall || (FnPtrCall && Self && Self->ValueType && Self->ValueType->isFunctionPointer())); + + FunctionCallEmitter emitters(FnPtrCall ? FunctionCallEmitter(PType::toFunctionPointer(Self->ValueType)) : FunctionCallEmitter(vmfunc)); // Emit code to pass implied parameters ExpEmit selfemit; if (Function->Variants[0].Flags & VARF_Method) @@ -9240,43 +9948,57 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } } } + else if (FnPtrCall) + { + assert(Self != nullptr); + selfemit = Self->Emit(build); + assert(selfemit.RegType == REGT_POINTER); + build->Emit(OP_NULLCHECK, selfemit.RegNum, 0, 0); + staticcall = false; + } else staticcall = true; // Emit code to pass explicit parameters for (unsigned i = 0; i < ArgList.Size(); ++i) { emitters.AddParameter(build, ArgList[i]); } - // Complete the parameter list from the defaults. - auto &defaults = Function->Variants[0].Implementation->DefaultArgs; - for (unsigned i = emitters.Count(); i < defaults.Size(); i++) + if(!FnPtrCall) { - switch (defaults[i].Type) + // Complete the parameter list from the defaults. + auto &defaults = Function->Variants[0].Implementation->DefaultArgs; + for (unsigned i = emitters.Count(); i < defaults.Size(); i++) { - default: - case REGT_INT: - emitters.AddParameterIntConst(defaults[i].i); - break; - case REGT_FLOAT: - emitters.AddParameterFloatConst(defaults[i].f); - break; - case REGT_POINTER: - emitters.AddParameterPointerConst(defaults[i].a); - break; - case REGT_STRING: - emitters.AddParameterStringConst(defaults[i].s()); - break; + switch (defaults[i].Type) + { + default: + case REGT_INT: + emitters.AddParameterIntConst(defaults[i].i); + break; + case REGT_FLOAT: + emitters.AddParameterFloatConst(defaults[i].f); + break; + case REGT_POINTER: + emitters.AddParameterPointerConst(defaults[i].a); + break; + case REGT_STRING: + emitters.AddParameterStringConst(defaults[i].s()); + break; + } } } ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); if (!staticcall) emitters.SetVirtualReg(selfemit.RegNum); - int resultcount = vmfunc->Proto->ReturnTypes.Size() == 0 ? 0 : MAX(AssignCount, 1); - assert((unsigned)resultcount <= vmfunc->Proto->ReturnTypes.Size()); + PPrototype * proto = FnPtrCall ? static_cast(static_cast(Self->ValueType)->PointedType) : vmfunc->Proto; + + int resultcount = proto->ReturnTypes.Size() == 0 ? 0 : max(AssignCount, 1); + + assert((unsigned)resultcount <= proto->ReturnTypes.Size()); for (int i = 0; i < resultcount; i++) { - emitters.AddReturn(vmfunc->Proto->ReturnTypes[i]->GetRegType(), vmfunc->Proto->ReturnTypes[i]->GetRegCount()); + emitters.AddReturn(proto->ReturnTypes[i]->GetRegType(), proto->ReturnTypes[i]->GetRegCount()); } return emitters.EmitCall(build, resultcount > 1? &ReturnRegs : nullptr); } @@ -9387,77 +10109,203 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) return this; } -//========================================================================== -// -// -//========================================================================== - -ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) +//========================================================================== +// +// +//========================================================================== + +ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = ArgList[0]->Emit(build); + ExpEmit to; + assert(from.Konst == 0); + assert(ValueType->GetRegCount() == 1); + // Do it in-place, unless a local variable + if (from.Fixed) + { + to = ExpEmit(build, from.RegType); + from.Free(build); + } + else + { + to = from; + } + + build->Emit(OP_FLOP, to.RegNum, from.RegNum, FxFlops[Index].Flop); + ArgList.DeleteAndClear(); + ArgList.ShrinkToFit(); + return to; +} + +//========================================================================== +// +// +//========================================================================== + +FxVectorBuiltin::FxVectorBuiltin(FxExpression *self, FName name) + :FxExpression(EFX_VectorBuiltin, self->ScriptPosition), Function(name), Self(self) +{ +} + +FxVectorBuiltin::~FxVectorBuiltin() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxVectorBuiltin::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + assert(Self->IsVector() || Self->IsQuaternion()); // should never be created for anything else. + switch (Function.GetIndex()) + { + case NAME_Angle: + assert(Self->IsVector()); + case NAME_Length: + case NAME_LengthSquared: + case NAME_Sum: + ValueType = TypeFloat64; + break; + + case NAME_Unit: + ValueType = Self->ValueType; + break; + + default: + ValueType = TypeError; + assert(false); + break; + } + return this; +} + +ExpEmit FxVectorBuiltin::Emit(VMFunctionBuilder *build) +{ + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + ExpEmit op = Self->Emit(build); + + const int vecSize = (Self->ValueType == TypeVector2 || Self->ValueType == TypeFVector2) ? 2 + : (Self->ValueType == TypeVector3 || Self->ValueType == TypeFVector3) ? 3 : 4; + + if (Function == NAME_Length) + { + build->Emit(vecSize == 2 ? OP_LENV2 : vecSize == 3 ? OP_LENV3 : OP_LENV4, to.RegNum, op.RegNum); + } + else if (Function == NAME_LengthSquared) + { + build->Emit(vecSize == 2 ? OP_DOTV2_RR : vecSize == 3 ? OP_DOTV3_RR : OP_DOTV4_RR, to.RegNum, op.RegNum, op.RegNum); + } + else if (Function == NAME_Sum) + { + ExpEmit temp(build, ValueType->GetRegType(), 1); + build->Emit(OP_FLOP, to.RegNum, op.RegNum, FLOP_ABS); + build->Emit(OP_FLOP, temp.RegNum, op.RegNum + 1, FLOP_ABS); + build->Emit(OP_ADDF_RR, to.RegNum, to.RegNum, temp.RegNum); + if (vecSize > 2) + { + build->Emit(OP_FLOP, temp.RegNum, op.RegNum + 2, FLOP_ABS); + build->Emit(OP_ADDF_RR, to.RegNum, to.RegNum, temp.RegNum); + } + if (vecSize > 3) + { + build->Emit(OP_FLOP, temp.RegNum, op.RegNum + 3, FLOP_ABS); + build->Emit(OP_ADDF_RR, to.RegNum, to.RegNum, temp.RegNum); + } + } + else if (Function == NAME_Unit) + { + ExpEmit len(build, REGT_FLOAT); + build->Emit(vecSize == 2 ? OP_LENV2 : vecSize == 3 ? OP_LENV3 : OP_LENV4, len.RegNum, op.RegNum); + build->Emit(vecSize == 2 ? OP_DIVVF2_RR : vecSize == 3 ? OP_DIVVF3_RR : OP_DIVVF4_RR, to.RegNum, op.RegNum, len.RegNum); + len.Free(build); + } + else if (Function == NAME_Angle) + { + build->Emit(OP_ATAN2, to.RegNum, op.RegNum + 1, op.RegNum); + } + op.Free(build); + return to; +} + +//========================================================================== +// +// FxPlusZ +// +//========================================================================== + + +FxVectorPlusZ::FxVectorPlusZ(FxExpression* self, FName name, FxExpression* z) + :FxExpression(EFX_VectorBuiltin, self->ScriptPosition), Function(name), Self(self), Z(new FxFloatCast(z)) +{ +} + +FxVectorPlusZ::~FxVectorPlusZ() +{ + SAFE_DELETE(Self); + SAFE_DELETE(Z); +} + +FxExpression* FxVectorPlusZ::Resolve(FCompileContext& ctx) +{ + SAFE_RESOLVE(Self, ctx); + SAFE_RESOLVE(Z, ctx); + assert(Self->IsVector3()); // should never be created for anything else. + ValueType = Self->ValueType; + return this; +} + +ExpEmit FxVectorPlusZ::Emit(VMFunctionBuilder* build) { - assert(ValueType == ArgList[0]->ValueType); - ExpEmit from = ArgList[0]->Emit(build); - ExpEmit to; - assert(from.Konst == 0); - assert(ValueType->GetRegCount() == 1); - // Do it in-place, unless a local variable - if (from.Fixed) - { - to = ExpEmit(build, from.RegType); - from.Free(build); - } - else - { - to = from; - } + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + ExpEmit op = Self->Emit(build); + ExpEmit z = Z->Emit(build); - build->Emit(OP_FLOP, to.RegNum, from.RegNum, FxFlops[Index].Flop); - ArgList.DeleteAndClear(); - ArgList.ShrinkToFit(); + build->Emit(OP_MOVEV2, to.RegNum, op.RegNum); + build->Emit(z.Konst ? OP_ADDF_RK : OP_ADDF_RR, to.RegNum + 2, op.RegNum + 2, z.RegNum); + + op.Free(build); + z.Free(build); return to; } + //========================================================================== // +// FxPlusZ // //========================================================================== -FxVectorBuiltin::FxVectorBuiltin(FxExpression *self, FName name) - :FxExpression(EFX_VectorBuiltin, self->ScriptPosition), Function(name), Self(self) + +FxToVector::FxToVector(FxExpression* self) + :FxExpression(EFX_ToVector, self->ScriptPosition), Self(new FxFloatCast(self)) { } -FxVectorBuiltin::~FxVectorBuiltin() +FxToVector::~FxToVector() { SAFE_DELETE(Self); } -FxExpression *FxVectorBuiltin::Resolve(FCompileContext &ctx) +FxExpression* FxToVector::Resolve(FCompileContext& ctx) { SAFE_RESOLVE(Self, ctx); - assert(Self->IsVector()); // should never be created for anything else. - ValueType = Function == NAME_Length ? TypeFloat64 : Self->ValueType; + assert(Self->IsNumeric()); // should never be created for anything else. + ValueType = TypeVector2; return this; } -ExpEmit FxVectorBuiltin::Emit(VMFunctionBuilder *build) +ExpEmit FxToVector::Emit(VMFunctionBuilder* build) { ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); ExpEmit op = Self->Emit(build); - if (Function == NAME_Length) - { - build->Emit(Self->ValueType == TypeVector2 ? OP_LENV2 : OP_LENV3, to.RegNum, op.RegNum); - } - else - { - ExpEmit len(build, REGT_FLOAT); - build->Emit(Self->ValueType == TypeVector2 ? OP_LENV2 : OP_LENV3, len.RegNum, op.RegNum); - build->Emit(Self->ValueType == TypeVector2 ? OP_DIVVF2_RR : OP_DIVVF3_RR, to.RegNum, op.RegNum, len.RegNum); - len.Free(build); - } + + build->Emit(OP_FLOP, to.RegNum, op.RegNum, FLOP_COS_DEG); + build->Emit(OP_FLOP, to.RegNum + 1, op.RegNum, FLOP_SIN_DEG); + op.Free(build); return to; } + //========================================================================== // // @@ -9633,70 +10481,39 @@ ExpEmit FxGetClassName::Emit(VMFunctionBuilder *build) // //========================================================================== -FxGetDefaultByType::FxGetDefaultByType(FxExpression *self) - :FxExpression(EFX_GetDefaultByType, self->ScriptPosition) +FxIsAbstract::FxIsAbstract(FxExpression *self) + :FxExpression(EFX_IsAbstract, self->ScriptPosition) { Self = self; } -FxGetDefaultByType::~FxGetDefaultByType() +FxIsAbstract::~FxIsAbstract() { SAFE_DELETE(Self); } -FxExpression *FxGetDefaultByType::Resolve(FCompileContext &ctx) +FxExpression *FxIsAbstract::Resolve(FCompileContext &ctx) { SAFE_RESOLVE(Self, ctx); - PClass *cls = nullptr; - if (Self->ValueType == TypeString || Self->ValueType == TypeName) + if (!Self->ValueType->isClassPointer()) { - if (Self->isConstant()) - { - cls = PClass::FindActor(static_cast(Self)->GetValue().GetName()); - if (cls == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type, but got %s", static_cast(Self)->GetValue().GetString().GetChars()); - delete this; - return nullptr; - } - Self = new FxConstant(cls, NewClassPointer(cls), ScriptPosition); - } - else - { - // this is the ugly case. We do not know what we have and cannot do proper type casting. - // For now error out and let this case require explicit handling on the user side. - ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type, but got %s", static_cast(Self)->GetValue().GetString().GetChars()); - delete this; - return nullptr; - } - } - else - { - auto cp = PType::toClassPointer(Self->ValueType); - if (cp == nullptr || !cp->ClassRestriction->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type"); - delete this; - return nullptr; - } - cls = cp->ClassRestriction; + ScriptPosition.Message(MSG_ERROR, "IsAbstract() requires a class pointer"); + delete this; + return nullptr; } - ValueType = NewPointer(cls, true); + ValueType = TypeBool; return this; } -ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) +ExpEmit FxIsAbstract::Emit(VMFunctionBuilder *build) { ExpEmit op = Self->Emit(build); op.Free(build); - ExpEmit to(build, REGT_POINTER); - if (op.Konst) - { - build->Emit(OP_LKP, to.RegNum, op.RegNum); - op = to; - } - build->Emit(OP_LP, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + + ExpEmit to(build, REGT_INT); + build->Emit(OP_LBU, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, bAbstract))); + return to; } @@ -10195,7 +11012,7 @@ FxExpression *FxCaseStatement::Resolve(FCompileContext &ctx) } else { - CaseValue = static_cast(Condition)->GetValue().GetName(); + CaseValue = static_cast(Condition)->GetValue().GetName().GetIndex(); } } return this; @@ -10230,6 +11047,8 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); + SAFE_RESOLVE(Condition, ctx); + if (WhenTrue == nullptr && WhenFalse == nullptr) { // We don't do anything either way, so disappear delete this; @@ -10237,8 +11056,6 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) return new FxNop(ScriptPosition); } - SAFE_RESOLVE(Condition, ctx); - if (Condition->ValueType != TypeBool) { Condition = new FxBoolCast(Condition, false); @@ -10586,53 +11403,416 @@ FxExpression *FxForLoop::DoResolve(FCompileContext &ctx) ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); } - return this; + return this; +} + +ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) +{ + assert((Condition && Condition->ValueType == TypeBool && !Condition->isConstant()) || Condition == nullptr); + + size_t loopstart, loopend; + size_t codestart; + TArray yes, no; + + // Init statement (only used by DECORATE. ZScript is pulling it before the loop statement and enclosing the entire loop in a compound statement so that Init can have local variables.) + if (Init != nullptr) + { + ExpEmit init = Init->Emit(build); + init.Free(build); + } + + // Evaluate the condition and execute/break out of the loop. + codestart = build->GetAddress(); + if (Condition != nullptr) + { + Condition->EmitCompare(build, false, yes, no); + } + + build->BackpatchListToHere(yes); + // Execute the loop's content. + if (Code != nullptr) + { + Code->EmitStatement(build); + } + + // Iteration statement. + loopstart = build->GetAddress(); + if (Iteration != nullptr) + { + ExpEmit iter = Iteration->Emit(build); + iter.Free(build); + } + build->Backpatch(build->Emit(OP_JMP, 0), codestart); + + // End of loop. + loopend = build->GetAddress(); + build->BackpatchListToHere(no); + + Backpatch(build, loopstart, loopend); + return ExpEmit(); +} + +//========================================================================== +// +// FxForLoop +// +//========================================================================== + +FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos) + : FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Array3(arrayvar3), Array4(arrayvar4), Code(code) +{ + ValueType = TypeVoid; + if (Array != nullptr) Array->NeedResult = false; + if (Array2 != nullptr) Array2->NeedResult = false; + if (Array3 != nullptr) Array3->NeedResult = false; + if (Array4 != nullptr) Array4->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxForEachLoop::~FxForEachLoop() +{ + SAFE_DELETE(Array); + SAFE_DELETE(Array2); + SAFE_DELETE(Array3); + SAFE_DELETE(Array4); + SAFE_DELETE(Code); +} + +extern bool IsGameSpecificForEachLoop(FxForEachLoop *); +extern FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop *); + +FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Array, ctx); + SAFE_RESOLVE(Array2, ctx); + SAFE_RESOLVE(Array3, ctx); + SAFE_RESOLVE(Array4, ctx); + + + if(Array->ValueType->isMap() || Array->ValueType->isMapIterator()) + { + auto mapLoop = new FxTwoArgForEachLoop(NAME_None, loopVarName, Array, Array2, Array3, Array4, Code, ScriptPosition); + Array = Array2 = Array3 = Array4 = Code = nullptr; + delete this; + return mapLoop->Resolve(ctx); + } + else if(IsGameSpecificForEachLoop(this)) + { + return ResolveGameSpecificForEachLoop(this)->Resolve(ctx); + } + else + { + // Instead of writing a new code generator for this, convert this into + // + // int @size = array.Size(); + // for(int @i = 0; @i < @size; @i++) + // { + // let var = array[i]; + // body + // } + // and let the existing 'for' loop code sort out the rest. + + FName sizevar = "@size"; + FName itvar = "@i"; + + auto block = new FxCompoundStatement(ScriptPosition); + auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, {}, ScriptPosition); + auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition); + auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition); + block->Add(size); + block->Add(it); + + auto cit = new FxLocalVariable(it, ScriptPosition); + auto csiz = new FxLocalVariable(size, ScriptPosition); + auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition)); + + auto iit = new FxLocalVariable(it, ScriptPosition); + auto bump = new FxPreIncrDecr(iit, TK_Incr); + + auto ait = new FxLocalVariable(it, ScriptPosition); + auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element. + + auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition); + auto body = new FxCompoundStatement(ScriptPosition); + body->Add(assign); + body->Add(Code); + auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition); + block->Add(forloop); + Array2 = Array = nullptr; + Code = nullptr; + delete this; + return block->Resolve(ctx); + } +} + +//========================================================================== +// +// FxMapForEachLoop +// +//========================================================================== + +FxTwoArgForEachLoop::FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos) + : FxExpression(EFX_TwoArgForEachLoop,pos), keyVarName(kv), valueVarName(vv), MapExpr(mapexpr), MapExpr2(mapexpr2), MapExpr3(mapexpr3), MapExpr4(mapexpr4), Code(code) +{ + ValueType = TypeVoid; + if (MapExpr != nullptr) MapExpr->NeedResult = false; + if (MapExpr2 != nullptr) MapExpr2->NeedResult = false; + if (MapExpr3 != nullptr) MapExpr3->NeedResult = false; + if (MapExpr4 != nullptr) MapExpr4->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxTwoArgForEachLoop::~FxTwoArgForEachLoop() +{ + SAFE_DELETE(MapExpr); + SAFE_DELETE(MapExpr2); + SAFE_DELETE(MapExpr3); + SAFE_DELETE(MapExpr4); + SAFE_DELETE(Code); +} + +extern bool HasGameSpecificTwoArgForEachLoopTypeNames(); +extern const char * GetGameSpecificTwoArgForEachLoopTypeNames(); +extern bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *); +extern FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *); + +FxExpression *FxTwoArgForEachLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(MapExpr, ctx); + SAFE_RESOLVE(MapExpr2, ctx); + SAFE_RESOLVE(MapExpr3, ctx); + SAFE_RESOLVE(MapExpr4, ctx); + + bool is_iterator = false; + + if(IsGameSpecificTwoArgForEachLoop(this)) + { + return ResolveGameSpecificTwoArgForEachLoop(this)->Resolve(ctx); + } + else if(!(MapExpr->ValueType->isMap() || (is_iterator = MapExpr->ValueType->isMapIterator()))) + { + if(HasGameSpecificTwoArgForEachLoopTypeNames()) + { + ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be %s a map, or a map iterator, but is a %s", GetGameSpecificTwoArgForEachLoopTypeNames(), MapExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + else + { + ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be a map or a map iterator, but is a %s", MapExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + } + else if(valueVarName == NAME_None) + { + ScriptPosition.Message(MSG_ERROR, "missing value for foreach( k, v : m )"); + delete this; + return nullptr; + } + + + auto block = new FxCompoundStatement(ScriptPosition); + + auto valType = is_iterator ? static_cast(MapExpr->ValueType)->ValueType : static_cast(MapExpr->ValueType)->ValueType; + auto keyType = is_iterator ? static_cast(MapExpr->ValueType)->KeyType : static_cast(MapExpr->ValueType)->KeyType; + + auto v = new FxLocalVariableDeclaration(valType, valueVarName, nullptr, 0, ScriptPosition); + block->Add(v); + + if(keyVarName != NAME_None) + { + auto k = new FxLocalVariableDeclaration(keyType, keyVarName, nullptr, 0, ScriptPosition); + block->Add(k); + } + + + if(MapExpr->ValueType->isMapIterator()) + { + /* + { + KeyType k; + ValueType v; + if(it.ReInit()) while(it.Next()) + { + k = it.GetKey(); + v = it.GetValue(); + body + } + } + */ + + auto inner_block = new FxCompoundStatement(ScriptPosition); + + if(keyVarName != NAME_None) + { + inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr, "GetKey", {}, ScriptPosition), true)); + } + + inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr2, "GetValue", {}, ScriptPosition), true)); + inner_block->Add(Code); + + auto reInit = new FxMemberFunctionCall(MapExpr3, "ReInit", {}, ScriptPosition); + block->Add(new FxIfStatement(reInit, new FxWhileLoop(new FxMemberFunctionCall(MapExpr4, "Next", {}, ScriptPosition), inner_block, ScriptPosition), nullptr, ScriptPosition)); + + MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr; + delete this; + return block->Resolve(ctx); + } + else + { + /* + { + KeyType k; + ValueType v; + MapIterator @it; + @it.Init(map); + while(@it.Next()) + { + k = @it.GetKey(); + v = @it.GetValue(); + body + } + } + */ + + PType * itType = NewMapIterator(keyType, valType); + auto it = new FxLocalVariableDeclaration(itType, "@it", nullptr, 0, ScriptPosition); + block->Add(it); + + FArgumentList al_map; + al_map.Push(MapExpr); + + block->Add(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Init", std::move(al_map), ScriptPosition)); + + auto inner_block = new FxCompoundStatement(ScriptPosition); + + if(keyVarName != NAME_None) + { + inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetKey", {}, ScriptPosition), true)); + } + inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetValue", {}, ScriptPosition), true)); + inner_block->Add(Code); + + block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition)); + + delete MapExpr2; + delete MapExpr3; + delete MapExpr4; + MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr; + delete this; + return block->Resolve(ctx); + } +} + + +//========================================================================== +// +// FxThreeArgForEachLoop +// +//========================================================================== + +FxThreeArgForEachLoop::FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos) + : FxExpression(EFX_ThreeArgForEachLoop, pos), varVarName(vv), posVarName(pv), flagsVarName(fv), BlockIteratorExpr(blockiteartorexpr), Code(code) +{ + ValueType = TypeVoid; + if (BlockIteratorExpr != nullptr) BlockIteratorExpr->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxThreeArgForEachLoop::~FxThreeArgForEachLoop() +{ + SAFE_DELETE(BlockIteratorExpr); + SAFE_DELETE(Code); } -ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) +extern bool HasGameSpecificThreeArgForEachLoopTypeNames(); +extern const char * GetGameSpecificThreeArgForEachLoopTypeNames(); +extern bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *); +extern FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *); + +FxExpression *FxThreeArgForEachLoop::Resolve(FCompileContext &ctx) { - assert((Condition && Condition->ValueType == TypeBool && !Condition->isConstant()) || Condition == nullptr); + CHECKRESOLVED(); + SAFE_RESOLVE(BlockIteratorExpr, ctx); - size_t loopstart, loopend; - size_t codestart; - TArray yes, no; - // Init statement (only used by DECORATE. ZScript is pulling it before the loop statement and enclosing the entire loop in a compound statement so that Init can have local variables.) - if (Init != nullptr) + if(IsGameSpecificThreeArgForEachLoop(this)) { - ExpEmit init = Init->Emit(build); - init.Free(build); + return ResolveGameSpecificThreeArgForEachLoop(this)->Resolve(ctx); } - - // Evaluate the condition and execute/break out of the loop. - codestart = build->GetAddress(); - if (Condition != nullptr) + else { - Condition->EmitCompare(build, false, yes, no); + //put any non-game-specific typed for-each loops here } - build->BackpatchListToHere(yes); - // Execute the loop's content. - if (Code != nullptr) + if(HasGameSpecificThreeArgForEachLoopTypeNames()) { - Code->EmitStatement(build); + ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - 'it' must be %s but is a %s", GetGameSpecificThreeArgForEachLoopTypeNames(), BlockIteratorExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; } - - // Iteration statement. - loopstart = build->GetAddress(); - if (Iteration != nullptr) + else { - ExpEmit iter = Iteration->Emit(build); - iter.Free(build); + ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - three-arg foreach loops not supported"); + delete this; + return nullptr; } - build->Backpatch(build->Emit(OP_JMP, 0), codestart); +} - // End of loop. - loopend = build->GetAddress(); - build->BackpatchListToHere(no); +//========================================================================== +// +// FxCastForEachLoop +// +//========================================================================== - Backpatch(build, loopstart, loopend); - return ExpEmit(); +FxTypedForEachLoop::FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos) + : FxExpression(EFX_TypedForEachLoop, pos), className(cv), varName(vv), Expr(castiteartorexpr), Code(code) +{ + ValueType = TypeVoid; + if (Expr != nullptr) Expr->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxTypedForEachLoop::~FxTypedForEachLoop() +{ + SAFE_DELETE(Expr); + SAFE_DELETE(Code); +} + +extern bool HasGameSpecificTypedForEachLoopTypeNames(); +extern const char * GetGameSpecificTypedForEachLoopTypeNames(); +extern bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop *); +extern FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop *); + +FxExpression *FxTypedForEachLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Expr, ctx); + + if(IsGameSpecificTypedForEachLoop(this)) + { + return ResolveGameSpecificTypedForEachLoop(this)->Resolve(ctx); + } + else + { + //put any non-game-specific typed for-each loops here + } + + if(HasGameSpecificTypedForEachLoopTypeNames()) + { + ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be %s but is a %s",GetGameSpecificTypedForEachLoopTypeNames(), Expr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + else + { + ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - typed foreach loops not supported"); + delete this; + return nullptr; + } } //========================================================================== @@ -10735,6 +11915,10 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) { mismatchSeverity = MSG_ERROR; } + else if (protoRetCount > retCount) + { // also warn when returning less values then the return count + mismatchSeverity = ctx.Version >= MakeVersion(4, 12) ? MSG_ERROR : MSG_WARNING; + } } if (mismatchSeverity != -1) @@ -10755,7 +11939,7 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) else if (retCount == 1) { // If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.) - if (hasProto && protoRetCount > 0 && ctx.Function->SymbolName != NAME_None) + if (hasProto && protoRetCount > 0 && ctx.Function->SymbolName != NAME_None && Args[0]->ValueType != ctx.ReturnProto->ReturnTypes[0]) { Args[0] = new FxTypeCast(Args[0], ctx.ReturnProto->ReturnTypes[0], false, false); Args[0] = Args[0]->Resolve(ctx); @@ -10765,11 +11949,15 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) } else { + assert(ctx.ReturnProto != nullptr); for (unsigned i = 0; i < retCount; i++) { - Args[i] = new FxTypeCast(Args[i], ctx.ReturnProto->ReturnTypes[i], false, false); - Args[i] = Args[i]->Resolve(ctx); - if (Args[i] == nullptr) fail = true; + if (Args[i]->ValueType != ctx.ReturnProto->ReturnTypes[i]) + { + Args[i] = new FxTypeCast(Args[i], ctx.ReturnProto->ReturnTypes[i], false, false); + Args[i] = Args[i]->Resolve(ctx); + if (Args[i] == nullptr) fail = true; + } } if (fail) { @@ -10918,7 +12106,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) delete this; return nullptr; } - + if (basex->ValueType != TypeName && basex->ValueType != TypeString) { ScriptPosition.Message(MSG_ERROR, "Cannot convert %s to class type", basex->ValueType->DescriptiveName()); @@ -10935,7 +12123,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) { if (Explicit) cls = FindClassType(clsname, ctx); else cls = PClass::FindClass(clsname); - + if (cls == nullptr || cls->VMType == nullptr) { /* lax */ @@ -10999,7 +12187,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinNameToClass, NativeNameToClass) PARAM_NAME(clsname); PARAM_CLASS(desttype, DObject); - ACTION_RETURN_POINTER(NativeNameToClass(clsname, desttype)); + ACTION_RETURN_POINTER(NativeNameToClass(clsname.GetIndex(), desttype)); } ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) @@ -11136,35 +12324,24 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) //========================================================================== // -// Symbolic state labels. -// Conversion will not happen inside the compiler anymore because it causes -// just too many problems. -// //========================================================================== -FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) +FxFunctionPtrCast::FxFunctionPtrCast(PFunctionPointer *ftype, FxExpression *x) + : FxExpression(EFX_FunctionPtrCast, x->ScriptPosition) { - CHECKRESOLVED(); - ABORT(ctx.Class); - auto vclass = PType::toClass(ctx.Class); - assert(vclass != nullptr); - auto aclass = ValidateActor(vclass->Descriptor); + ValueType = ftype; + basex = x; +} - // This expression type can only be used from actors, for everything else it has already produced a compile error. - assert(aclass != nullptr && aclass->GetStateCount() > 0); +//========================================================================== +// +// +// +//========================================================================== - if (aclass->GetStateCount() <= index) - { - ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", - ctx.Class->TypeName.GetChars(), index); - delete this; - return nullptr; - } - int symlabel = StateLabels.AddPointer(aclass->GetStates() + index); - FxExpression *x = new FxConstant(symlabel, ScriptPosition); - x->ValueType = TypeStateLabel; - delete this; - return x; +FxFunctionPtrCast::~FxFunctionPtrCast() +{ + SAFE_DELETE(basex); } //========================================================================== @@ -11173,174 +12350,198 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) // //========================================================================== -FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) -: FxExpression(EFX_RuntimeStateIndex, index->ScriptPosition), Index(index) +static bool AreCompatibleFnPtrs(PFunctionPointer * to, PFunctionPointer * from); + +bool CanNarrowTo(PClass * from, PClass * to) { - ValueType = TypeStateLabel; + return from->IsAncestorOf(to); } -FxRuntimeStateIndex::~FxRuntimeStateIndex() +bool CanWidenTo(PClass * from, PClass * to) { - SAFE_DELETE(Index); + return to->IsAncestorOf(from); } -FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) +static bool AreCompatibleFnPtrTypes(PPrototype *to, PPrototype *from) { - CHECKRESOLVED(); - SAFE_RESOLVE(Index, ctx); + if(to->ArgumentTypes.Size() != from->ArgumentTypes.Size() + || to->ReturnTypes.Size() != from->ReturnTypes.Size()) return false; + int n = to->ArgumentTypes.Size(); - if (!Index->IsNumeric()) + //allow narrowing of arguments + for(int i = 0; i < n; i++) { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return nullptr; + PType * fromType = from->ArgumentTypes[i]; + PType * toType = to->ArgumentTypes[i]; + if(fromType->isFunctionPointer() && toType->isFunctionPointer()) + { + if(!AreCompatibleFnPtrs(static_cast(toType), static_cast(fromType))) return false; + } + else if(fromType->isClassPointer() && toType->isClassPointer()) + { + PClassPointer * fromClass = static_cast(fromType); + PClassPointer * toClass = static_cast(toType); + //allow narrowing parameters + if(!CanNarrowTo(fromClass->ClassRestriction, toClass->ClassRestriction)) return false; + } + else if(fromType->isObjectPointer() && toType->isObjectPointer()) + { + PObjectPointer * fromObj = static_cast(fromType); + PObjectPointer * toObj = static_cast(toType); + //allow narrowing parameters + if(!CanNarrowTo(fromObj->PointedClass(), toObj->PointedClass())) return false; + } + else if(fromType != toType) + { + return false; + } } - else if (Index->isConstant()) + + n = to->ReturnTypes.Size(); + + for(int i = 0; i < n; i++) { - int index = static_cast(Index)->GetValue().GetInt(); - if (index < 0 || (index == 0 && !ctx.FromDecorate)) + PType * fromType = from->ReturnTypes[i]; + PType * toType = to->ReturnTypes[i]; + if(fromType->isFunctionPointer() && toType->isFunctionPointer()) { - ScriptPosition.Message(MSG_ERROR, "State index must be positive"); - delete this; - return nullptr; + if(!AreCompatibleFnPtrs(static_cast(toType), static_cast(fromType))) return false; } - else if (index == 0) + else if(fromType->isClassPointer() && toType->isClassPointer()) { - int symlabel = StateLabels.AddPointer(nullptr); - auto x = new FxConstant(symlabel, ScriptPosition); - delete this; - x->ValueType = TypeStateLabel; - return x; + PClassPointer * fromClass = static_cast(fromType); + PClassPointer * toClass = static_cast(toType); + //allow widening returns + if(!CanWidenTo(fromClass->ClassRestriction, toClass->ClassRestriction)) return false; } - else + else if(fromType->isObjectPointer() && toType->isObjectPointer()) { - auto x = new FxStateByIndex(ctx.StateIndex + index, ScriptPosition); - delete this; - return x->Resolve(ctx); + PObjectPointer * fromObj = static_cast(fromType); + PObjectPointer * toObj = static_cast(toType); + //allow widening returns + if(!CanWidenTo(fromObj->PointedClass(), toObj->PointedClass())) return false; + } + else if(fromType != toType) + { + return false; } } - else if (Index->ValueType->GetRegType() != REGT_INT) - { // Float. - Index = new FxIntCast(Index, ctx.FromDecorate); - SAFE_RESOLVE(Index, ctx); - } + return true; +} - auto vclass = PType::toClass(ctx.Class); - assert(vclass != nullptr); - auto aclass = ValidateActor(vclass->Descriptor); - assert(aclass != nullptr && aclass->GetStateCount() > 0); +static bool AreCompatibleFnPtrs(PFunctionPointer * to, PFunctionPointer * from) +{ + if(to->PointedType == TypeVoid) return true; + else if(from->PointedType == TypeVoid) return false; - symlabel = StateLabels.AddPointer(aclass->GetStates() + ctx.StateIndex); - ValueType = TypeStateLabel; - return this; + PPrototype * toProto = (PPrototype *)to->PointedType; + PPrototype * fromProto = (PPrototype *)from->PointedType; + return + ( FScopeBarrier::CheckSidesForFunctionPointer(from->Scope, to->Scope) + /* + && toProto->ArgumentTypes == fromProto->ArgumentTypes + && toProto->ReturnTypes == fromProto->ReturnTypes + */ + && AreCompatibleFnPtrTypes(toProto, fromProto) + && to->ArgFlags == from->ArgFlags + ); } -ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) +FxExpression *FxFunctionPtrCast::Resolve(FCompileContext &ctx) { - ExpEmit out = Index->Emit(build); - // out = (clamp(Index, 0, 32767) << 16) | symlabel | 0x80000000; 0x80000000 is here to make it negative. - build->Emit(OP_MAX_RK, out.RegNum, out.RegNum, build->GetConstantInt(0)); - build->Emit(OP_MIN_RK, out.RegNum, out.RegNum, build->GetConstantInt(32767)); - build->Emit(OP_SLL_RI, out.RegNum, out.RegNum, 16); - build->Emit(OP_OR_RK, out.RegNum, out.RegNum, build->GetConstantInt(symlabel|0x80000000)); - return out; -} + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); -//========================================================================== -// -// -// -//========================================================================== + if (basex->isConstant() && basex->ValueType == TypeRawFunction) + { + FxConstant *val = FxTypeCast::convertRawFunctionToFunctionPointer(basex, ScriptPosition); + if(!val) + { + delete this; + return nullptr; + } + } -FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPosition &pos, PClassActor *checkclass) - :FxExpression(EFX_MultiNameState, pos) -{ - FName scopename = NAME_None; - FString statestring = _statestring; - int scopeindex = statestring.IndexOf("::"); + if (!(basex->ValueType && basex->ValueType->isFunctionPointer())) + { + delete this; + return nullptr; + } + auto to = static_cast(ValueType); + auto from = static_cast(basex->ValueType); - if (scopeindex >= 0) + if(from->PointedType == TypeVoid) + { // nothing to check at compile-time for casts from Function + return this; + } + else if(AreCompatibleFnPtrs(to, from)) + { // no need to do anything for (Function)(...) or compatible casts + basex->ValueType = ValueType; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + else { - scopename = FName(statestring, scopeindex, false); - statestring = statestring.Right(statestring.Len() - scopeindex - 2); + ScriptPosition.Message(MSG_ERROR, "Cannot cast %s to %s. The types are incompatible.", basex->ValueType->DescriptiveName(), to->DescriptiveName()); + delete this; + return nullptr; } - names = MakeStateNameList(statestring); - names.Insert(0, scopename); - scope = checkclass; } //========================================================================== // -// +// // //========================================================================== -FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) +PFunction *NativeFunctionPointerCast(PFunction *from, const PFunctionPointer *to) { - CHECKRESOLVED(); - ABORT(ctx.Class); - int symlabel; - - auto vclass = PType::toClass(ctx.Class); - //assert(vclass != nullptr); - auto clstype = vclass == nullptr? nullptr : ValidateActor(vclass->Descriptor); - - if (names[0] == NAME_None) - { - scope = nullptr; - } - else if (clstype == nullptr) - { - // not in an actor, so any further checks are pointless. - ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); - delete this; - return nullptr; - } - else if (names[0] == NAME_Super) - { - scope = ValidateActor(clstype->ParentClass); - } - else + if(to->PointedType == TypeVoid) { - scope = PClass::FindActor(names[0]); - if (scope == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars()); - delete this; - return nullptr; - } - else if (!scope->IsAncestorOf(clstype)) - { - ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); - delete this; - return nullptr; - } + return from; } - if (scope != nullptr) + else if(from && ((from->Variants[0].Flags & (VARF_Virtual | VARF_Action)) == 0) && FScopeBarrier::CheckSidesForFunctionPointer(FScopeBarrier::SideFromFlags(from->Variants[0].Flags), to->Scope)) { - FState *destination = nullptr; - // If the label is class specific we can resolve it right here - if (names[1] != NAME_None) + if(to->ArgFlags.Size() != from->Variants[0].ArgFlags.Size()) return nullptr; + int n = to->ArgFlags.Size(); + for(int i = from->GetImplicitArgs(); i < n; i++) // skip checking flags for implicit self { - destination = scope->FindState(names.Size()-1, &names[1], false); - if (destination == nullptr) + if(from->Variants[0].ArgFlags[i] != to->ArgFlags[i]) { - ScriptPosition.Message(MSG_OPTERROR, "Unknown state jump destination"); - /* lax */ - return this; + return nullptr; } } - symlabel = StateLabels.AddPointer(destination); + return AreCompatibleFnPtrTypes(static_cast(to->PointedType), from->Variants[0].Proto) ? from : nullptr; } else - { - names.Delete(0); - symlabel = StateLabels.AddNames(names); + { // cannot cast virtual/action functions to anything + return nullptr; } - FxExpression *x = new FxConstant(symlabel, ScriptPosition); - x->ValueType = TypeStateLabel; - delete this; - return x; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinFunctionPtrCast, NativeFunctionPointerCast) +{ + PARAM_PROLOGUE; + PARAM_POINTER(from, PFunction); + PARAM_POINTER(to, PFunctionPointer); + ACTION_RETURN_POINTER(NativeFunctionPointerCast(from, to)); +} + +ExpEmit FxFunctionPtrCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit funcptr = basex->Emit(build); + + auto sym = FindBuiltinFunction(NAME_BuiltinFunctionPtrCast); + assert(sym); + + FunctionCallEmitter emitters(sym->Variants[0].Implementation); + emitters.AddParameter(funcptr, false); + emitters.AddParameterPointerConst(ValueType); + + emitters.AddReturn(REGT_POINTER); + return emitters.EmitCall(build); } //========================================================================== @@ -11352,10 +12553,16 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p) :FxExpression(EFX_LocalVariableDeclaration, p) { + // Local FVector isn't different from Vector + if (type == TypeFVector2) type = TypeVector2; + else if (type == TypeFVector3) type = TypeVector3; + else if (type == TypeFVector4) type = TypeVector4; + else if (type == TypeFQuaternion) type = TypeQuaternion; + ValueType = type; VarFlags = varflags; Name = name; - RegCount = type == TypeVector2 ? 2 : type == TypeVector3 ? 3 : 1; + RegCount = type->RegCount; Init = initval; clearExpr = nullptr; } @@ -11379,7 +12586,7 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) { auto sfunc = static_cast(ctx.Function->Variants[0].Implementation); StackOffset = sfunc->AllocExtraStack(ValueType); - + if (Init != nullptr) { ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars()); @@ -11400,14 +12607,41 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) delete this; return nullptr; } - SAFE_RESOLVE_OPT(Init, ctx); - if (Init->ValueType->RegType == REGT_NIL) + SAFE_RESOLVE(Init, ctx); + + if(Init->isConstant() && Init->ValueType == TypeRawFunction) { - ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars()); - delete this; - return nullptr; + FxConstant *val = FxTypeCast::convertRawFunctionToFunctionPointer(Init, ScriptPosition); + if(!val) + { + delete this; + return nullptr; + } } + ValueType = Init->ValueType; + if (ValueType->RegType == REGT_NIL) + { + if (Init->IsStruct()) + { + bool writable = true; + + if(ctx.Version >= MakeVersion(4, 12, 0)) + { + Init->RequestAddress(ctx, &writable); + } + + ValueType = NewPointer(ValueType, !writable); + Init = new FxTypeCast(Init, ValueType, false); + SAFE_RESOLVE(Init, ctx); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars()); + delete this; + return nullptr; + } + } // check for undersized ints and floats. These are not allowed as local variables. if (IsInteger() && ValueType->Align < sizeof(int)) ValueType = TypeSInt32; else if (IsFloat() && ValueType->Align < sizeof(double)) ValueType = TypeFloat64; @@ -11429,8 +12663,7 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) if (IsDynamicArray()) { auto stackVar = new FxStackVariable(ValueType, StackOffset, ScriptPosition); - FArgumentList argsList; - clearExpr = new FxMemberFunctionCall(stackVar, "Clear", argsList, ScriptPosition); + clearExpr = new FxMemberFunctionCall(stackVar, "Clear", {}, ScriptPosition); SAFE_RESOLVE(clearExpr, ctx); } @@ -11748,10 +12981,9 @@ FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx) else { FArgumentList argsList; - argsList.Clear(); argsList.Push(v); - FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, argsList, (const FScriptPosition) v->ScriptPosition); + FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, std::move(argsList), (const FScriptPosition) v->ScriptPosition); SAFE_RESOLVE(funcCall, ctx); v = funcCall; @@ -11774,9 +13006,14 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) ClearDynamicArray(build); } + auto zero = build->GetConstantInt(0); auto elementSizeConst = build->GetConstantInt(static_cast(ValueType)->ElementSize); - auto arrOffsetReg = build->Registers[REGT_INT].Get(1); - build->Emit(OP_LK, arrOffsetReg, build->GetConstantInt(StackOffset)); + int arrOffsetReg = 0; + if (!isDynamicArray) + { + arrOffsetReg = build->Registers[REGT_POINTER].Get(1); + build->Emit(OP_ADDA_RK, arrOffsetReg, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); + } for (auto v : values) { @@ -11784,6 +13021,7 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) if (isDynamicArray) { + emitval.Free(build); continue; } @@ -11796,61 +13034,48 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) if (emitval.Konst) { auto constval = static_cast(v); - int regNum = build->Registers[regtype].Get(1); + auto regNum = build->Registers[regtype].Get(1); switch (regtype) { default: case REGT_INT: - build->Emit(OP_LK, regNum, build->GetConstantInt(constval->GetValue().GetInt())); - build->Emit(OP_SW_R, build->FramePointer.RegNum, regNum, arrOffsetReg); + build->Emit(OP_LK, regNum, emitval.RegNum); + build->Emit(OP_SW, arrOffsetReg, regNum, zero); break; case REGT_FLOAT: - build->Emit(OP_LKF, regNum, build->GetConstantFloat(constval->GetValue().GetFloat())); - build->Emit(OP_SDP_R, build->FramePointer.RegNum, regNum, arrOffsetReg); + build->Emit(OP_LKF, regNum, emitval.RegNum); + build->Emit(OP_SDP, arrOffsetReg, regNum, zero); break; case REGT_POINTER: - build->Emit(OP_LKP, regNum, build->GetConstantAddress(constval->GetValue().GetPointer())); - build->Emit(OP_SP_R, build->FramePointer.RegNum, regNum, arrOffsetReg); + build->Emit(OP_LKP, regNum, emitval.RegNum); + build->Emit(OP_SP, arrOffsetReg, regNum, zero); break; case REGT_STRING: - build->Emit(OP_LKS, regNum, build->GetConstantString(constval->GetValue().GetString())); - build->Emit(OP_SS_R, build->FramePointer.RegNum, regNum, arrOffsetReg); + build->Emit(OP_LKS, regNum, emitval.RegNum); + build->Emit(OP_SS, arrOffsetReg, regNum, zero); break; } + build->Registers[regtype].Return(regNum, 1); - - emitval.Free(build); } else { - switch (regtype) - { - default: - case REGT_INT: - build->Emit(OP_SW_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg); - break; - - case REGT_FLOAT: - build->Emit(OP_SDP_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg); - break; - - case REGT_POINTER: - build->Emit(OP_SP_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg); - break; - - case REGT_STRING: - build->Emit(OP_SS_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg); - break; - } - emitval.Free(build); + build->Emit(v->ValueType->GetStoreOp(), arrOffsetReg, emitval.RegNum, zero); } + emitval.Free(build); - build->Emit(OP_ADD_RK, arrOffsetReg, arrOffsetReg, elementSizeConst); + if (!isDynamicArray) + { + build->Emit(OP_ADDA_RK, arrOffsetReg, arrOffsetReg, elementSizeConst); + } + } + if (!isDynamicArray) + { + build->Registers[REGT_POINTER].Return(arrOffsetReg, 1); } - build->Registers[REGT_INT].Return(arrOffsetReg, 1); return ExpEmit(); } @@ -11884,7 +13109,7 @@ FxExpression *FxOutVarDereference::Resolve(FCompileContext &ctx) SelfType = Self->ValueType->toPointer()->PointedType; ValueType = SelfType; - if (SelfType->GetRegType() == REGT_NIL && !SelfType->isRealPointer() && !SelfType->isDynArray()) + if (SelfType->GetRegType() == REGT_NIL && !SelfType->isRealPointer() && !SelfType->isDynArray() && !SelfType->isMap() && !SelfType->isMapIterator()) { ScriptPosition.Message(MSG_ERROR, "Cannot dereference pointer"); delete this; @@ -11913,7 +13138,7 @@ ExpEmit FxOutVarDereference::Emit(VMFunctionBuilder *build) regType = REGT_POINTER; loadOp = OP_LP; } - else if (SelfType->isDynArray()) + else if (SelfType->isDynArray() || SelfType->isMap() || SelfType->isMapIterator()) { regType = REGT_POINTER; loadOp = OP_MOVEA; diff --git a/src/scripting/backend/codegen.h b/src/common/scripting/backend/codegen.h similarity index 87% rename from src/scripting/backend/codegen.h rename to src/common/scripting/backend/codegen.h index 4588f2447b3..cd37a7102b1 100644 --- a/src/scripting/backend/codegen.h +++ b/src/common/scripting/backend/codegen.h @@ -42,13 +42,15 @@ #include "m_random.h" #include "sc_man.h" -#include "s_sound.h" -#include "actor.h" +#include "s_soundinternal.h" #include "vmbuilder.h" #include "scopebarrier.h" #include "types.h" #include "vmintern.h" +#include "c_cvars.h" +#include "palettecontainer.h" +struct FState; // needed for FxConstant. Maybe move the state constructor to a subclass later? #define CHECKRESOLVED() if (isresolved) return this; isresolved=true; #define SAFE_DELETE(p) if (p!=NULL) { delete p; p=NULL; } @@ -92,7 +94,7 @@ struct FCompileContext FString VersionString; FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver); - FCompileContext(PNamespace *spc, PContainerType *cls, bool fromdecorate); // only to be used to resolve constants! + FCompileContext(PNamespace *spc, PContainerType *cls, bool fromdecorate, const VersionInfo& ver); // only to be used to resolve constants! PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt); @@ -100,7 +102,7 @@ struct FCompileContext void HandleJumps(int token, FxExpression *handler); void CheckReturn(PPrototype *proto, FScriptPosition &pos); - bool CheckWritable(int flags); + bool IsWritable(int flags, int checkFileNo = 0); FxLocalVariableDeclaration *FindLocalVariable(FName name); }; @@ -197,7 +199,7 @@ struct ExpVal const FString GetString() const { - return Type == TypeString ? *(FString *)&pointer : Type == TypeName ? FString(FName(ENamedName(Int)).GetChars()) : ""; + return Type == TypeString ? *(FString *)&pointer : Type == TypeName ? FString(FName(ENamedName(Int)).GetChars()) : FString(); } bool GetBool() const @@ -205,7 +207,7 @@ struct ExpVal int regtype = Type->GetRegType(); return regtype == REGT_INT ? !!Int : regtype == REGT_FLOAT ? Float!=0. : false; } - + FName GetName() const { if (Type == TypeString) @@ -231,6 +233,7 @@ enum EFxType EFX_StringCast, EFX_ColorCast, EFX_SoundCast, + EFX_TranslationCast, EFX_TypeCast, EFX_PlusSign, EFX_MinusSign, @@ -247,6 +250,7 @@ enum EFxType EFX_Conditional, EFX_Abs, EFX_ATan2, + EFX_ATan2Vec, EFX_New, EFX_MinMax, EFX_Random, @@ -270,10 +274,15 @@ enum EFxType EFX_WhileLoop, EFX_DoWhileLoop, EFX_ForLoop, + EFX_ForEachLoop, + EFX_TwoArgForEachLoop, + EFX_ThreeArgForEachLoop, + EFX_TypedForEachLoop, EFX_JumpStatement, EFX_ReturnStatement, EFX_ClassTypeCast, EFX_ClassPtrCast, + EFX_FunctionPtrCast, EFX_StateByIndex, EFX_RuntimeStateIndex, EFX_MultiNameState, @@ -283,6 +292,7 @@ enum EFxType EFX_SwitchStatement, EFX_CaseStatement, EFX_VectorValue, + EFX_VectorPlusZ, EFX_VectorBuiltin, EFX_TypeCheck, EFX_DynamicCast, @@ -290,6 +300,7 @@ enum EFxType EFX_Super, EFX_StackVariable, EFX_MultiAssign, + EFX_MultiAssignDecl, EFX_StaticArray, EFX_StaticArrayVariable, EFX_CVar, @@ -297,12 +308,14 @@ enum EFxType EFX_GetClass, EFX_GetParentClass, EFX_GetClassName, + EFX_IsAbstract, EFX_StrLen, EFX_ColorLiteral, EFX_GetDefaultByType, EFX_FontCast, EFX_LocalArrayDeclaration, EFX_OutVarDereference, + EFX_ToVector, EFX_COUNT }; @@ -323,7 +336,7 @@ class FxExpression public: virtual ~FxExpression() {} virtual FxExpression *Resolve(FCompileContext &ctx); - + virtual bool isConstant() const; virtual bool RequestAddress(FCompileContext &ctx, bool *writable); virtual PPrototype *ReturnProto(); @@ -334,12 +347,19 @@ class FxExpression bool IsFloat() const { return ValueType->isFloat(); } bool IsInteger() const { return ValueType->isNumeric() && ValueType->isIntCompatible(); } bool IsPointer() const { return ValueType->isPointer(); } - bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; }; + bool IsVector() const { return IsVector2() || IsVector3() || IsVector4(); }; + bool IsVector2() const { return ValueType == TypeVector2 || ValueType == TypeFVector2; }; + bool IsVector3() const { return ValueType == TypeVector3 || ValueType == TypeFVector3; }; + bool IsVector4() const { return ValueType == TypeVector4 || ValueType == TypeFVector4; }; + bool IsQuaternion() const { return ValueType == TypeQuaternion || ValueType == TypeFQuaternion || ValueType == TypeQuaternionStruct; }; bool IsBoolCompat() const { return ValueType->isScalar(); } bool IsObject() const { return ValueType->isObjectPointer(); } - bool IsArray() const { return ValueType->isArray() || (ValueType->isPointer() && ValueType->toPointer()->PointedType->isArray()); } - bool isStaticArray() const { return (ValueType->isPointer() && ValueType->toPointer()->PointedType->isStaticArray()); } // can only exist in pointer form. + bool IsArray() const { return ValueType->isArray() || (ValueType->isPointer() && ValueType->toPointer()->PointedType && ValueType->toPointer()->PointedType->isArray()); } + bool isStaticArray() const { return (ValueType->isPointer() && ValueType->toPointer()->PointedType && ValueType->toPointer()->PointedType->isStaticArray()); } // can only exist in pointer form. bool IsDynamicArray() const { return (ValueType->isDynArray()); } + bool IsMap() const { return ValueType->isMap(); } + bool IsMapIterator() const { return ValueType->isMapIterator(); } + bool IsStruct() const { return ValueType->isStruct(); } bool IsNativeStruct() const { return (ValueType->isStruct() && static_cast(ValueType)->isNative); } virtual ExpEmit Emit(VMFunctionBuilder *build); @@ -397,23 +417,6 @@ class FxMemberIdentifier : public FxIdentifier }; -//========================================================================== -// -// FxClassDefaults -// -//========================================================================== - -class FxClassDefaults : public FxExpression -{ - FxExpression *obj; - -public: - FxClassDefaults(FxExpression *, const FScriptPosition &); - ~FxClassDefaults(); - FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); -}; - //========================================================================== // // FxConstant @@ -456,14 +459,14 @@ class FxConstant : public FxExpression FxConstant(FSoundID val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { ValueType = value.Type = TypeSound; - value.Int = val; + value.Int = val.index(); isresolved = true; } FxConstant(FName val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { ValueType = value.Type = TypeName; - value.Int = val; + value.Int = val.GetIndex(); isresolved = true; } @@ -509,6 +512,27 @@ class FxConstant : public FxExpression isresolved = true; } + FxConstant(FTranslationID state, const FScriptPosition& pos) : FxExpression(EFX_Constant, pos) + { + value.Int = state.index(); + ValueType = value.Type = TypeTranslationID; + isresolved = true; + } + + FxConstant(VMFunction* state, const FScriptPosition& pos) : FxExpression(EFX_Constant, pos) + { + value.pointer = state; + ValueType = value.Type = TypeVMFunction; + isresolved = true; + } + + FxConstant(PFunction* rawptr, const FScriptPosition& pos) : FxExpression(EFX_Constant, pos) + { + value.pointer = rawptr; + ValueType = value.Type = TypeRawFunction; + isresolved = true; + } + FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { value.pointer = nullptr; @@ -540,7 +564,7 @@ class FxConstant : public FxExpression } ValueType = value.Type = type; } - + static FxExpression *MakeConstant(PSymbol *sym, const FScriptPosition &pos); bool isConstant() const @@ -553,6 +577,8 @@ class FxConstant : public FxExpression return value; } ExpEmit Emit(VMFunctionBuilder *build); + + friend class FxTypeCast; }; //========================================================================== @@ -563,26 +589,42 @@ class FxConstant : public FxExpression class FxVectorValue : public FxExpression { - FxExpression *xyz[3]; + constexpr static int maxVectorDimensions = 4; bool isConst; // gets set to true if all element are const (used by function defaults parser) public: + FxExpression *xyzw[maxVectorDimensions]; friend class ZCCCompiler; - FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z, const FScriptPosition &sc); + FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z, FxExpression* w, const FScriptPosition &sc); ~FxVectorValue(); FxExpression *Resolve(FCompileContext&); bool isConstVector(int dim) { - if (!isConst) return false; - return dim == 2 ? xyz[2] == nullptr : xyz[2] != nullptr; + if (!isConst) + return false; + return dim >= 0 && dim <= maxVectorDimensions && xyzw[dim - 1] && (dim == maxVectorDimensions || !xyzw[dim]); } ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxQuaternionValue : public FxVectorValue +{ +public: + FxQuaternionValue(FxExpression* x, FxExpression* y, FxExpression* z, FxExpression* w, const FScriptPosition& sc); + FxExpression* Resolve(FCompileContext&); +}; + + //========================================================================== // // @@ -685,6 +727,19 @@ class FxSoundCast : public FxExpression ExpEmit Emit(VMFunctionBuilder *build); }; +class FxTranslationCast : public FxExpression +{ + FxExpression* basex; + +public: + + FxTranslationCast(FxExpression* x); + ~FxTranslationCast(); + FxExpression* Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder* build); +}; + class FxFontCast : public FxExpression { FxExpression *basex; @@ -705,17 +760,18 @@ class FxFontCast : public FxExpression class FxTypeCast : public FxExpression { +public: FxExpression *basex; bool NoWarn; bool Explicit; -public: - FxTypeCast(FxExpression *x, PType *type, bool nowarn, bool explicitly = false); ~FxTypeCast(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); + + static FxConstant * convertRawFunctionToFunctionPointer(FxExpression * in, FScriptPosition &ScriptPosition); }; //========================================================================== @@ -893,6 +949,17 @@ class FxMultiAssign : public FxExpression ExpEmit Emit(VMFunctionBuilder *build); }; +class FxMultiAssignDecl : public FxExpression +{ + FArgumentList Base; + FxExpression *Right; +public: + FxMultiAssignDecl(FArgumentList &base, FxExpression *right, const FScriptPosition &pos); + ~FxMultiAssignDecl(); + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed into Declarations + FxMultiAssign , so it won't ever be emitted itself +}; + //========================================================================== // // FxAssignSelf @@ -924,7 +991,7 @@ class FxBinary : public FxExpression FxBinary(int, FxExpression*, FxExpression*); ~FxBinary(); - bool Promote(FCompileContext &ctx, bool forceint = false); + bool Promote(FCompileContext &ctx, bool forceint = false, bool shiftop = false); }; //========================================================================== @@ -1211,6 +1278,18 @@ class FxATan2 : public FxExpression ExpEmit ToReg(VMFunctionBuilder *build, FxExpression *val); }; +class FxATan2Vec : public FxExpression +{ + FxExpression* vval; + +public: + + FxATan2Vec(FxExpression* y, const FScriptPosition& pos); + ~FxATan2Vec(); + FxExpression* Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder* build); +}; + //========================================================================== // // @@ -1362,7 +1441,7 @@ class FxMemberBase : public FxExpression //========================================================================== // -// FxGlobalVariab�e +// FxGlobalVariable // //========================================================================== @@ -1521,8 +1600,9 @@ class FxArrayElement : public FxExpression bool AddressRequested; bool AddressWritable; bool arrayispointer = false; + bool noboundscheck; - FxArrayElement(FxExpression*, FxExpression*); + FxArrayElement(FxExpression*, FxExpression*, bool = false); ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); @@ -1538,13 +1618,13 @@ class FxArrayElement : public FxExpression class FxFunctionCall : public FxExpression { - FName MethodName; FRandom *RNG; - FArgumentList ArgList; public: + FName MethodName; + FArgumentList ArgList; - FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos); + FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos); ~FxFunctionCall(); FxExpression *Resolve(FCompileContext&); }; @@ -1561,10 +1641,11 @@ class FxMemberFunctionCall : public FxExpression FxExpression *Self; FName MethodName; FArgumentList ArgList; + bool ResolveSelf; public: - FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos); + FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos); ~FxMemberFunctionCall(); FxExpression *Resolve(FCompileContext&); }; @@ -1572,60 +1653,78 @@ class FxMemberFunctionCall : public FxExpression //========================================================================== // -// FxActionSpecialCall +// FxFlopFunctionCall // //========================================================================== -class FxActionSpecialCall : public FxExpression +class FxFlopFunctionCall : public FxExpression { - int Special; - FxExpression *Self; + int Index; FArgumentList ArgList; public: - FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos); - ~FxActionSpecialCall(); + FxFlopFunctionCall(size_t index, FArgumentList &args, const FScriptPosition &pos); + ~FxFlopFunctionCall(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== // -// FxFlopFunctionCall +// FxVectorBuiltin // //========================================================================== -class FxFlopFunctionCall : public FxExpression +class FxVectorBuiltin : public FxExpression { - int Index; - FArgumentList ArgList; + FName Function; + FxExpression *Self; public: - FxFlopFunctionCall(size_t index, FArgumentList &args, const FScriptPosition &pos); - ~FxFlopFunctionCall(); + FxVectorBuiltin(FxExpression *self, FName name); + ~FxVectorBuiltin(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== // -// FxVectorBuiltin +// FxPlusZ // //========================================================================== -class FxVectorBuiltin : public FxExpression +class FxVectorPlusZ : public FxExpression { FName Function; - FxExpression *Self; + FxExpression* Self; + FxExpression* Z; public: - FxVectorBuiltin(FxExpression *self, FName name); - ~FxVectorBuiltin(); - FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); + FxVectorPlusZ(FxExpression* self, FName name, FxExpression*); + ~FxVectorPlusZ(); + FxExpression* Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder* build); +}; + +//========================================================================== +// +// FxPlusZ +// +//========================================================================== + +class FxToVector : public FxExpression +{ + FxExpression* Self; + +public: + + FxToVector(FxExpression* self); + ~FxToVector(); + FxExpression* Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder* build); }; //========================================================================== @@ -1702,20 +1801,20 @@ class FxGetClassName : public FxExpression //========================================================================== // -// FxGetDefaultByType +// FxIsAbstract // //========================================================================== -class FxGetDefaultByType : public FxExpression +class FxIsAbstract : public FxExpression { - FxExpression *Self; + FxExpression* Self; public: - FxGetDefaultByType(FxExpression *self); - ~FxGetDefaultByType(); + FxIsAbstract(FxExpression* self); + ~FxIsAbstract(); FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); + ExpEmit Emit(VMFunctionBuilder* build); }; //========================================================================== @@ -1749,17 +1848,19 @@ class FxVMFunctionCall : public FxExpression bool NoVirtual; bool hasStringArgs = false; FxExpression *Self; - PFunction *Function; - FArgumentList ArgList; // for multi assignment int AssignCount = 0; TArray ReturnRegs; PFunction *CallingFunction; bool CheckAccessibility(const VersionInfo &ver); - bool UnravelVarArgAJump(FCompileContext&); public: + const bool FnPtrCall; + + FArgumentList ArgList; + PFunction* Function; + FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual); ~FxVMFunctionCall(); FxExpression *Resolve(FCompileContext&); @@ -1899,7 +2000,7 @@ class FxLoopStatement : public FxExpression : FxExpression(etype, pos) { } - + void Backpatch(VMFunctionBuilder *build, size_t loopstart, size_t loopend); FxExpression *Resolve(FCompileContext&) final; virtual FxExpression *DoResolve(FCompileContext&) = 0; @@ -1961,7 +2062,92 @@ class FxForLoop : public FxLoopStatement FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos); ~FxForLoop(); FxExpression *DoResolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); + ExpEmit Emit(VMFunctionBuilder* build); +}; + +//========================================================================== +// +// FxForLoop +// +//========================================================================== + +class FxForEachLoop : public FxLoopStatement +{ +public: + FName loopVarName; + FxExpression* Array; + FxExpression* Array2; + FxExpression* Array3; + FxExpression* Array4; + FxExpression* Code; + + FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos); + ~FxForEachLoop(); + FxExpression* DoResolve(FCompileContext&); +}; + +//========================================================================== +// +// FxTwoArgForEachLoop +// +//========================================================================== + +class FxTwoArgForEachLoop : public FxExpression +{ +public: + FName keyVarName; + FName valueVarName; + FxExpression* MapExpr; + FxExpression* MapExpr2; + FxExpression* MapExpr3; + FxExpression* MapExpr4; + FxExpression* Code; + + FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos); + ~FxTwoArgForEachLoop(); + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself +}; + +//========================================================================== +// +// FxThreeArgForEachLoop +// +//========================================================================== + +class FxThreeArgForEachLoop : public FxExpression +{ +public: + FName varVarName; + FName posVarName; + FName flagsVarName; + FxExpression* BlockIteratorExpr; + FxExpression* Code; + + FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos); + ~FxThreeArgForEachLoop(); + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself +}; + +//========================================================================== +// +// FxTypedForEachLoop +// +//========================================================================== + +class FxTypedForEachLoop : public FxExpression +{ +public: + FName className; + FName varName; + FxExpression* Expr; + FxExpression* Code; + + FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos); + ~FxTypedForEachLoop(); + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself }; //========================================================================== @@ -2042,56 +2228,20 @@ class FxClassPtrCast : public FxExpression //========================================================================== // -// Only used to resolve the old jump by index feature of DECORATE -// -//========================================================================== - -class FxStateByIndex : public FxExpression -{ - unsigned index; - -public: - - FxStateByIndex(int i, const FScriptPosition &pos) : FxExpression(EFX_StateByIndex, pos) - { - index = i; - } - FxExpression *Resolve(FCompileContext&); -}; - -//========================================================================== // -// Same as above except for expressions which means it will have to be -// evaluated at runtime // //========================================================================== -class FxRuntimeStateIndex : public FxExpression +class FxFunctionPtrCast : public FxExpression { - FxExpression *Index; - int symlabel; - -public: - FxRuntimeStateIndex(FxExpression *index); - ~FxRuntimeStateIndex(); - FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); -}; - -//========================================================================== -// -// -// -//========================================================================== + FxExpression *basex; -class FxMultiNameState : public FxExpression -{ - PClassActor *scope; - TArray names; public: - FxMultiNameState(const char *statestring, const FScriptPosition &pos, PClassActor *checkclass = nullptr); + FxFunctionPtrCast (PFunctionPointer *ftype, FxExpression *x); + ~FxFunctionPtrCast(); FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -2233,4 +2383,20 @@ class FxOutVarDereference : public FxExpression ExpEmit Emit(VMFunctionBuilder *build); }; + +struct CompileEnvironment +{ + FxExpression* (*SpecialTypeCast)(FxTypeCast* func, FCompileContext& ctx); + bool (*CheckForCustomAddition)(FxAddSub* func, FCompileContext& ctx); + FxExpression* (*CheckSpecialIdentifier)(FxIdentifier* func, FCompileContext& ctx); + FxExpression* (*CheckSpecialGlobalIdentifier)(FxIdentifier* func, FCompileContext& ctx); + FxExpression* (*ResolveSpecialIdentifier)(FxIdentifier* func, FxExpression*& object, PContainerType* objtype, FCompileContext& ctx); + FxExpression* (*CheckSpecialMember)(FxStructMember* func, FCompileContext& ctx); + FxExpression* (*CheckCustomGlobalFunctions)(FxFunctionCall* func, FCompileContext& ctx); + bool (*ResolveSpecialFunction)(FxVMFunctionCall* func, FCompileContext& ctx); + FName CustomBuiltinNew; //override the 'new' function if some classes need special treatment. +}; + +extern CompileEnvironment compileEnvironment; + #endif diff --git a/src/scripting/backend/vmbuilder.cpp b/src/common/scripting/backend/vmbuilder.cpp similarity index 90% rename from src/scripting/backend/vmbuilder.cpp rename to src/common/scripting/backend/vmbuilder.cpp index 8a6800d46be..71a766d9a79 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/common/scripting/backend/vmbuilder.cpp @@ -36,7 +36,13 @@ #include "codegen.h" #include "m_argv.h" #include "c_cvars.h" -#include "scripting/vm/jit.h" +#include "jit.h" +#include "filesystem.h" + +CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) + +EXTERN_CVAR(Bool, vm_jit) +EXTERN_CVAR(Bool, vm_jit_aot) struct VMRemap { @@ -287,6 +293,24 @@ unsigned VMFunctionBuilder::GetConstantAddress(void *ptr) } } + +//========================================================================== +// +// VMFunctionBuilder :: FindConstantInt +// +// Returns a constant register initialized with the given value. +// +//========================================================================== + +int VMFunctionBuilder::FindConstantInt(unsigned index) +{ + if(IntConstantList.Size() < index) + { + return IntConstantList[index]; + } + return 0; +} + //========================================================================== // // VMFunctionBuilder :: AllocConstants* @@ -295,7 +319,7 @@ unsigned VMFunctionBuilder::GetConstantAddress(void *ptr) // //========================================================================== -unsigned VMFunctionBuilder::AllocConstantsInt(unsigned count, int *values) +unsigned VMFunctionBuilder::AllocConstantsInt(unsigned int count, int *values) { unsigned addr = IntConstantList.Reserve(count); memcpy(&IntConstantList[addr], values, count * sizeof(int)); @@ -306,7 +330,7 @@ unsigned VMFunctionBuilder::AllocConstantsInt(unsigned count, int *values) return addr; } -unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned count, double *values) +unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned int count, double *values) { unsigned addr = FloatConstantList.Reserve(count); memcpy(&FloatConstantList[addr], values, count * sizeof(double)); @@ -317,7 +341,7 @@ unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned count, double *values) return addr; } -unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned count, void **ptrs) +unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned int count, void **ptrs) { unsigned addr = AddressConstantList.Reserve(count); memcpy(&AddressConstantList[addr], ptrs, count * sizeof(void *)); @@ -328,7 +352,7 @@ unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned count, void **ptrs) return addr; } -unsigned VMFunctionBuilder::AllocConstantsString(unsigned count, FString *ptrs) +unsigned VMFunctionBuilder::AllocConstantsString(unsigned int count, FString *ptrs) { unsigned addr = StringConstantList.Reserve(count); for (unsigned i = 0; i < count; i++) @@ -396,7 +420,7 @@ int VMFunctionBuilder::RegAvailability::Get(int count) { return -1; } - + mask = count == 32 ? ~0u : (1 << count) - 1; for (i = 0; i < 256 / 32; ++i) @@ -635,6 +659,7 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc) int chg; if (opa & REGT_MULTIREG2) chg = 2; else if (opa & REGT_MULTIREG3) chg = 3; + else if (opa & REGT_MULTIREG4) chg = 4; else chg = 1; ParamChange(chg); } @@ -765,13 +790,16 @@ FFunctionBuildList FunctionBuildList; VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, const VersionInfo &ver, PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum) { - auto func = code->GetDirectFunction(functype, ver); - if (func != nullptr) + if (code != nullptr) { - delete code; + auto func = code->GetDirectFunction(functype, ver); + if (func != nullptr) + { + delete code; - return func; + return func; + } } //Printf("Adding %s\n", name.GetChars()); @@ -784,7 +812,7 @@ VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, const VersionInfo it.PrintableName = name; it.Function = new VMScriptFunction; it.Function->Name = functype->SymbolName; - it.Function->PrintableName = name; + it.Function->QualifiedName = it.Function->PrintableName = ClassDataAllocator.Strdup(name.GetChars()); it.Function->ImplicitArgs = functype->GetImplicitArgs(); it.Proto = nullptr; it.FromDecorate = fromdecorate; @@ -813,6 +841,10 @@ void FFunctionBuildList::Build() for (auto &item : mItems) { + // [Player701] Do not emit code for abstract functions + bool isAbstract = item.Func->Variants[0].Implementation->VarFlags & VARF_Abstract; + if (isAbstract) continue; + assert(item.Code != NULL); // We don't know the return type in advance for anonymous functions. @@ -832,7 +864,7 @@ void FFunctionBuildList::Build() ctx.FunctionArgs.Push(local); } - FScriptPosition::StrictErrors = !item.FromDecorate; + FScriptPosition::StrictErrors = !item.FromDecorate || strictdecorate; item.Code = item.Code->Resolve(ctx); // If we need extra space, load the frame pointer into a register so that we do not have to call the wasteful LFP instruction more than once. if (item.Function->ExtraSpace > 0) @@ -872,7 +904,7 @@ void FFunctionBuildList::Build() // Emit code try { - sfunc->SourceFileName = item.Code->ScriptPosition.FileName; // remember the file name for printing error messages if something goes wrong in the VM. + sfunc->SourceFileName = item.Code->ScriptPosition.FileName.GetChars(); // remember the file name for printing error messages if something goes wrong in the VM. buildit.BeginStatement(item.Code); item.Code->Emit(&buildit); buildit.EndStatement(); @@ -899,6 +931,13 @@ void FFunctionBuildList::Build() disasmdump.Write(sfunc, item.PrintableName); sfunc->Unsafe = ctx.Unsafe; + + #if HAVE_VM_JIT + if(vm_jit && vm_jit_aot) + { + sfunc->JitCompile(); + } + #endif } catch (CRecoverableError &err) { @@ -910,15 +949,19 @@ void FFunctionBuildList::Build() disasmdump.Flush(); } VMFunction::CreateRegUseInfo(); - FScriptPosition::StrictErrors = false; + FScriptPosition::StrictErrors = strictdecorate; - if (FScriptPosition::ErrorCounter == 0 && Args->CheckParm("-dumpjit")) DumpJit(); + if (FScriptPosition::ErrorCounter == 0) + { + if (Args->CheckParm("-dumpjit")) DumpJit(true); + else if (Args->CheckParm("-dumpjitmod")) DumpJit(false); + } mItems.Clear(); mItems.ShrinkToFit(); FxAlloc.FreeAllBlocks(); } -void FFunctionBuildList::DumpJit() +void FFunctionBuildList::DumpJit(bool include_gzdoom_pk3) { #ifdef HAVE_VM_JIT FILE *dump = fopen("dumpjit.txt", "w"); @@ -927,13 +970,25 @@ void FFunctionBuildList::DumpJit() for (auto &item : mItems) { - JitDumpLog(dump, item.Function); + if(include_gzdoom_pk3 || fileSystem.GetFileContainer(item.Lump)) JitDumpLog(dump, item.Function); } fclose(dump); #endif // HAVE_VM_JIT } +FunctionCallEmitter::FunctionCallEmitter(VMFunction *func) +{ + target = func; + is_vararg = target->VarFlags & VARF_VarArg; +} + +FunctionCallEmitter::FunctionCallEmitter(class PFunctionPointer *func) +{ + fnptr = func; + is_vararg = false; // function pointers cannot point to vararg functions +} + void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *operand) { @@ -944,7 +999,7 @@ void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *o operand->ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value"); } numparams += where.RegCount; - if (target->VarFlags & VARF_VarArg) + if (is_vararg) for (unsigned i = 0; i < where.RegCount; i++) reginfo.Push(where.RegType & REGT_TYPE); emitters.push_back([=](VMFunctionBuilder *build) -> int @@ -967,7 +1022,7 @@ void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *o void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference) { numparams += emit.RegCount; - if (target->VarFlags & VARF_VarArg) + if (is_vararg) { if (reference) reginfo.Push(REGT_POINTER); else for (unsigned i = 0; i < emit.RegCount; i++) reginfo.Push(emit.RegType & REGT_TYPE); @@ -984,7 +1039,7 @@ void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference) void FunctionCallEmitter::AddParameterPointerConst(void *konst) { numparams++; - if (target->VarFlags & VARF_VarArg) + if (is_vararg) reginfo.Push(REGT_POINTER); emitters.push_back([=](VMFunctionBuilder *build) ->int { @@ -996,7 +1051,7 @@ void FunctionCallEmitter::AddParameterPointerConst(void *konst) void FunctionCallEmitter::AddParameterPointer(int index, bool konst) { numparams++; - if (target->VarFlags & VARF_VarArg) + if (is_vararg) reginfo.Push(REGT_POINTER); emitters.push_back([=](VMFunctionBuilder *build) ->int { @@ -1008,7 +1063,7 @@ void FunctionCallEmitter::AddParameterPointer(int index, bool konst) void FunctionCallEmitter::AddParameterFloatConst(double konst) { numparams++; - if (target->VarFlags & VARF_VarArg) + if (is_vararg) reginfo.Push(REGT_FLOAT); emitters.push_back([=](VMFunctionBuilder *build) ->int { @@ -1020,7 +1075,7 @@ void FunctionCallEmitter::AddParameterFloatConst(double konst) void FunctionCallEmitter::AddParameterIntConst(int konst) { numparams++; - if (target->VarFlags & VARF_VarArg) + if (is_vararg) reginfo.Push(REGT_INT); emitters.push_back([=](VMFunctionBuilder *build) ->int { @@ -1040,7 +1095,7 @@ void FunctionCallEmitter::AddParameterIntConst(int konst) void FunctionCallEmitter::AddParameterStringConst(const FString &konst) { numparams++; - if (target->VarFlags & VARF_VarArg) + if (is_vararg) reginfo.Push(REGT_STRING); emitters.push_back([=](VMFunctionBuilder *build) ->int { @@ -1049,8 +1104,6 @@ void FunctionCallEmitter::AddParameterStringConst(const FString &konst) }); } -EXTERN_CVAR(Bool, vm_jit) - ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray *ReturnRegs) { unsigned paramcount = 0; @@ -1059,7 +1112,7 @@ ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray paramcount += func(build); } assert(paramcount == numparams); - if (target->VarFlags & VARF_VarArg) + if (is_vararg) { // Pass a hidden type information parameter to vararg functions. // It would really be nicer to actually pass real types but that'd require a far more complex interface on the compiler side than what we have. @@ -1069,9 +1122,24 @@ ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray paramcount++; } + if(fnptr) + { + ExpEmit reg(build, REGT_POINTER); + assert(fnptr->Scope != -1); + assert(fnptr->PointedType != TypeVoid); + + // OP_LP , Load from memory. rA = *(rB + rkC) + // reg = &PFunction->Variants[0] -- PFunction::Variant* + build->Emit(OP_LP, reg.RegNum, virtualselfreg, build->GetConstantInt(offsetof(PFunction, Variants) + offsetof(FArray, Array))); + // reg = (&PFunction->Variants[0])->Implementation -- VMFunction* + build->Emit(OP_LP, reg.RegNum, reg.RegNum, build->GetConstantInt(offsetof(PFunction::Variant, Implementation))); - if (virtualselfreg == -1) + build->Emit(OP_CALL, reg.RegNum, paramcount, vm_jit? static_cast(fnptr->PointedType)->ReturnTypes.Size() : returns.Size()); + + reg.Free(build); + } + else if (virtualselfreg == -1) { build->Emit(OP_CALL_K, build->GetConstantAddress(target), paramcount, vm_jit ? target->Proto->ReturnTypes.Size() : returns.Size()); } @@ -1095,9 +1163,13 @@ ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray } if (vm_jit) // The JIT compiler needs this, but the VM interpreter does not. { - for (unsigned i = returns.Size(); i < target->Proto->ReturnTypes.Size(); i++) + assert(!fnptr || fnptr->PointedType != TypeVoid); + + PPrototype * proto = fnptr ? static_cast(fnptr->PointedType) : target->Proto; + + for (unsigned i = returns.Size(); i < proto->ReturnTypes.Size(); i++) { - ExpEmit reg(build, target->Proto->ReturnTypes[i]->RegType, target->Proto->ReturnTypes[i]->RegCount); + ExpEmit reg(build, proto->ReturnTypes[i]->RegType, proto->ReturnTypes[i]->RegCount); build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); reg.Free(build); } @@ -1138,7 +1210,7 @@ void VMDisassemblyDumper::Write(VMScriptFunction *sfunc, const FString &fname) assert(sfunc != nullptr); - DumpFunction(dump, sfunc, fname, (int)fname.Len()); + DumpFunction(dump, sfunc, fname.GetChars(), (int)fname.Len()); codesize += sfunc->CodeSize; datasize += sfunc->LineInfoCount * sizeof(FStatementInfo) + sfunc->ExtraSpace + sfunc->NumKonstD * sizeof(int) + sfunc->NumKonstA * sizeof(void*) + sfunc->NumKonstF * sizeof(double) + sfunc->NumKonstS * sizeof(FString); diff --git a/src/scripting/backend/vmbuilder.h b/src/common/scripting/backend/vmbuilder.h similarity index 94% rename from src/scripting/backend/vmbuilder.h rename to src/common/scripting/backend/vmbuilder.h index 8bb43565e6b..2ead8f9069d 100644 --- a/src/scripting/backend/vmbuilder.h +++ b/src/common/scripting/backend/vmbuilder.h @@ -65,6 +65,11 @@ class VMFunctionBuilder unsigned GetConstantAddress(void *ptr); unsigned GetConstantString(FString str); + int FindConstantInt(unsigned index); + //double FindConstantFloat(unsigned index); + //void * FindConstantAddress(unsigned index); + //const FString& FindConstantString(unsigned index); + unsigned AllocConstantsInt(unsigned int count, int *values); unsigned AllocConstantsFloat(unsigned int count, double *values); unsigned AllocConstantsAddress(unsigned int count, void **ptrs); @@ -155,7 +160,7 @@ class FFunctionBuildList TArray mItems; - void DumpJit(); + void DumpJit(bool include_gzdoom_pk3); public: VMFunction *AddFunction(PNamespace *curglobals, const VersionInfo &ver, PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum); @@ -180,13 +185,12 @@ class FunctionCallEmitter TArray reginfo; unsigned numparams = 0; // This counts the number of pushed elements, which can differ from the number of emitters with vectors. VMFunction *target = nullptr; + class PFunctionPointer *fnptr = nullptr; int virtualselfreg = -1; - + bool is_vararg; public: - FunctionCallEmitter(VMFunction *func) - { - target = func; - } + FunctionCallEmitter(VMFunction *func); + FunctionCallEmitter(class PFunctionPointer *func); void SetVirtualReg(int virtreg) { diff --git a/src/utility/dictionary.cpp b/src/common/scripting/core/dictionary.cpp similarity index 96% rename from src/utility/dictionary.cpp rename to src/common/scripting/core/dictionary.cpp index a6bcccc663e..6d2b1d0924d 100644 --- a/src/utility/dictionary.cpp +++ b/src/common/scripting/core/dictionary.cpp @@ -1,6 +1,6 @@ -#include "utility/dictionary.h" +#include "dictionary.h" -#include "scripting/vm/vm.h" +#include "vm.h" #include "serializer.h" #include @@ -29,7 +29,7 @@ void Dictionary::Serialize(FSerializer &arc) { Super::Serialize(arc); - constexpr char key[] { "dictionary" }; + static const char key[] = "dictionary"; if (arc.isWriting()) { @@ -43,7 +43,7 @@ void Dictionary::Serialize(FSerializer &arc) Dictionary *pointerToDeserializedDictionary; arc(key, pointerToDeserializedDictionary); Map.TransferFrom(pointerToDeserializedDictionary->Map); - delete pointerToDeserializedDictionary; + pointerToDeserializedDictionary->Destroy(); } } @@ -62,7 +62,7 @@ static void DictInsert(Dictionary *dict, const FString &key, const FString &valu static void DictAt(const Dictionary *dict, const FString &key, FString *result) { const FString *value = dict->Map.CheckKey(key); - *result = value ? *value : ""; + *result = value ? *value : FString(); } static void DictToString(const Dictionary *dict, FString *result) diff --git a/src/utility/dictionary.h b/src/common/scripting/core/dictionary.h similarity index 100% rename from src/utility/dictionary.h rename to src/common/scripting/core/dictionary.h diff --git a/src/scripting/backend/dynarrays.cpp b/src/common/scripting/core/dynarrays.cpp similarity index 91% rename from src/scripting/backend/dynarrays.cpp rename to src/common/scripting/core/dynarrays.cpp index daedd60e663..207c91fbcd9 100644 --- a/src/scripting/backend/dynarrays.cpp +++ b/src/common/scripting/core/dynarrays.cpp @@ -18,10 +18,6 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be -** covered by the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or (at -** your option) any later version. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -41,6 +37,7 @@ #include "dobject.h" #include "vm.h" #include "types.h" +#include "v_draw.h" // We need one specific type for each of the 8 integral VM types and instantiate the needed functions for each of them. // Dynamic arrays cannot hold structs because for every type there'd need to be an internal implementation which is impossible. @@ -91,11 +88,12 @@ template void ArrayDelete(T *self, int index, int count) template void ArrayInsert(T *self, int index, U val) { - //int oldSize = self->Size(); + int oldSize = self->Size(); self->Insert(index, static_cast(val)); - // Is this even necessary? All Insert does is inserting one defined element into the array and moving the rest. - // It never creates empty tailing entries. fillcount in the macro will always be 0 - //if (fill) { DYNARRAY_FILL_ITEMS_SKIP(1); } + if constexpr (fill) + { + for (unsigned i = oldSize; i < self->Size() - 1; i++) (*self)[i] = 0; + } } template void ArrayShrinkToFit(T *self) @@ -116,7 +114,7 @@ template void ArrayResize(T *self, int amount) { // This must ensure that all new entries get cleared. const int fillCount = int(self->Size() - oldSize); - if (fillCount > 0) memset(&(*self)[oldSize], 0, sizeof(*self)[0] * fillCount); + if (fillCount > 0) memset((void*)&(*self)[oldSize], 0, sizeof(*self)[0] * fillCount); } } @@ -125,6 +123,17 @@ template unsigned int ArrayReserve(T *self, int amount) return self->Reserve(amount); } +template<> unsigned int ArrayReserve(TArray *self, int amount) +{ + const unsigned int oldSize = self->Reserve(amount); + const unsigned int fillCount = self->Size() - oldSize; + + if (fillCount > 0) + memset(&(*self)[oldSize], 0, sizeof(DObject*) * fillCount); + + return oldSize; +} + template int ArrayMax(T *self) { return self->Max(); @@ -404,6 +413,28 @@ DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_I32, Push, ArrayPushPush(val)); } +DEFINE_ACTION_FUNCTION(FDynArray_I32, PushV) +{ + PARAM_SELF_STRUCT_PROLOGUE(FDynArray_I32); + PARAM_VA_POINTER(va_reginfo); // Get the hidden type information array + VMVa_List args = { param + 1, 0, numparam - 2, va_reginfo + 1 }; + while (args.curindex < args.numargs) + { + if (args.reginfo[args.curindex] == REGT_INT) + { + self->Push(args.args[args.curindex++].i); + } + else if (args.reginfo[args.curindex] == REGT_FLOAT) + { + self->Push(int(args.args[args.curindex++].f)); + } + else ThrowAbortException(X_OTHER, "Invalid parameter in pushv, int expected"); + } + + + ACTION_RETURN_INT(self->Size()-1); +} + DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_I32, Pop, ArrayPop) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_I32); @@ -811,27 +842,45 @@ DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Ptr, Clear, ArrayClear) // //----------------------------------------------------- -DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Copy, ArrayCopy) +void ObjArrayCopy(FDynArray_Obj *self, FDynArray_Obj *other) +{ + for (auto& elem : *other) GC::WriteBarrier(elem); + *self = *other; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Copy, ObjArrayCopy) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_Obj); PARAM_POINTER(other, FDynArray_Obj); - *self = *other; + ObjArrayCopy(self, other); return 0; } -DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Move, ArrayMove) +void ObjArrayMove(FDynArray_Obj *self, FDynArray_Obj *other) +{ + for (auto& elem : *other) GC::WriteBarrier(elem); + *self = std::move(*other); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Move, ObjArrayMove) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_Obj); PARAM_POINTER(other, FDynArray_Obj); - *self = std::move(*other); + ObjArrayMove(self, other); return 0; } -DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Append, ArrayAppend) +void ObjArrayAppend(FDynArray_Obj *self, FDynArray_Obj *other) +{ + for (auto& elem : *other) GC::WriteBarrier(elem); + self->Append(*other); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Append, ObjArrayAppend) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_Obj); PARAM_POINTER(other, FDynArray_Obj); - self->Append(*other); + ObjArrayAppend(self, other); return 0; } @@ -872,8 +921,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Delete, ArrayDelete) void ObjArrayInsert(FDynArray_Obj *self,int index, DObject *obj) { + int oldSize = self->Size(); GC::WriteBarrier(obj); self->Insert(index, obj); + for (unsigned i = oldSize; i < self->Size() - 1; i++) (*self)[i] = nullptr; } DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Insert, ObjArrayInsert) @@ -912,7 +963,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Reserve, ArrayReserveReserve(count)); + ACTION_RETURN_INT(ArrayReserve(self, count)); } DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_Obj, Max, ArrayMax) @@ -973,6 +1024,22 @@ DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_String, Push, ArrayPushPush(val)); } +DEFINE_ACTION_FUNCTION(FDynArray_String, PushV) +{ + PARAM_SELF_STRUCT_PROLOGUE(FDynArray_String); + PARAM_VA_POINTER(va_reginfo); // Get the hidden type information array + VMVa_List args = { param + 1, 0, numparam - 2, va_reginfo + 1 }; + while (args.curindex < args.numargs) + { + if (args.reginfo[args.curindex] == REGT_STRING) + { + self->Push(args.args[args.curindex++].s()); + } + else ThrowAbortException(X_OTHER, "Invalid parameter in pushv, string expected"); + } + ACTION_RETURN_INT(self->Size() - 1); +} + DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_String, Pop, ArrayPop) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_String); diff --git a/src/common/scripting/core/imports.cpp b/src/common/scripting/core/imports.cpp new file mode 100644 index 00000000000..ff6d7ceba7e --- /dev/null +++ b/src/common/scripting/core/imports.cpp @@ -0,0 +1,239 @@ +/* +** thingdef_data.cpp +** +** DECORATE data tables +** +**--------------------------------------------------------------------------- +** Copyright 2002-2020 Christoph Oelckers +** Copyright 2004-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "gstrings.h" +#include "v_font.h" +#include "menu.h" +#include "types.h" +#include "dictionary.h" +#include "vm.h" +#include "symbols.h" + +static TArray AFTable; +static TArray FieldTable; + + +//========================================================================== +// +// +// +//========================================================================== + +template +static int CompareClassNames(const char* const aname, const Desc& b) +{ + // ++ to get past the prefix letter of the native class name, which gets omitted by the FName for the class. + const char* bname = b.ClassName; + if ('\0' != *bname) ++bname; + return stricmp(aname, bname); +} + +template +static int CompareClassNames(const Desc& a, const Desc& b) +{ + // ++ to get past the prefix letter of the native class name, which gets omitted by the FName for the class. + const char* aname = a.ClassName; + if ('\0' != *aname) ++aname; + return CompareClassNames(aname, b); +} + +//========================================================================== +// +// Find a function by name using a binary search +// +//========================================================================== + +AFuncDesc *FindFunction(PContainerType *cls, const char * string) +{ + int min = 0, max = AFTable.Size() - 1; + + while (min <= max) + { + int mid = (min + max) / 2; + int lexval = CompareClassNames(cls->TypeName.GetChars(), AFTable[mid]); + if (lexval == 0) lexval = stricmp(string, AFTable[mid].FuncName); + if (lexval == 0) + { + return &AFTable[mid]; + } + else if (lexval > 0) + { + min = mid + 1; + } + else + { + max = mid - 1; + } + } + return nullptr; +} + +//========================================================================== +// +// Find a function by name using a binary search +// +//========================================================================== + +FieldDesc *FindField(PContainerType *cls, const char * string) +{ + int min = 0, max = FieldTable.Size() - 1; + const char * cname = cls ? cls->TypeName.GetChars() : ""; + + while (min <= max) + { + int mid = (min + max) / 2; + int lexval = CompareClassNames(cname, FieldTable[mid]); + if (lexval == 0) lexval = stricmp(string, FieldTable[mid].FieldName); + if (lexval == 0) + { + return &FieldTable[mid]; + } + else if (lexval > 0) + { + min = mid + 1; + } + else + { + max = mid - 1; + } + } + return nullptr; +} + + +//========================================================================== +// +// Find an action function in AActor's table +// +//========================================================================== + +VMFunction *FindVMFunction(PClass *cls, const char *name) +{ + auto f = dyn_cast(cls->FindSymbol(name, true)); + return f == nullptr ? nullptr : f->Variants[0].Implementation; +} + + +//========================================================================== +// +// Find an action function in AActor's table from a qualified name +// This cannot search in structs. sorry. :( +// +//========================================================================== + +VMFunction* FindVMFunction( const char* name) +{ + auto p = strchr(name, '.'); + if (p == nullptr) return nullptr; + std::string clsname(name, p - name); + auto cls = PClass::FindClass(clsname.c_str()); + if (cls == nullptr) return nullptr; + return FindVMFunction(cls, p + 1); +} + + +//========================================================================== +// +// Sorting helpers +// +//========================================================================== + +static int funccmp(const void * a, const void * b) +{ + int res = CompareClassNames(*(AFuncDesc*)a, *(AFuncDesc*)b); + if (res == 0) res = stricmp(((AFuncDesc*)a)->FuncName, ((AFuncDesc*)b)->FuncName); + return res; +} + +static int fieldcmp(const void * a, const void * b) +{ + int res = CompareClassNames(*(FieldDesc*)a, *(FieldDesc*)b); + if (res == 0) res = stricmp(((FieldDesc*)a)->FieldName, ((FieldDesc*)b)->FieldName); + return res; +} + +//========================================================================== +// +// Initialization +// +//========================================================================== + +void InitImports() +{ + auto fontstruct = NewStruct("Font", nullptr, true); + fontstruct->Size = sizeof(FFont); + fontstruct->Align = alignof(FFont); + NewPointer(fontstruct, false)->InstallHandlers( + [](FSerializer &ar, const char *key, const void *addr) + { + ar(key, *(FFont **)addr); + }, + [](FSerializer &ar, const char *key, void *addr) + { + Serialize(ar, key, *(FFont **)addr, nullptr); + return true; + } + ); + + // Create a sorted list of native action functions + AFTable.Clear(); + if (AFTable.Size() == 0) + { + AutoSegs::ActionFunctons.ForEach([](AFuncDesc *afunc) + { + assert(afunc->VMPointer != NULL); + *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->FuncName); + (*(afunc->VMPointer))->QualifiedName = ClassDataAllocator.Strdup(FStringf("%s.%s", afunc->ClassName + 1, afunc->FuncName).GetChars()); + (*(afunc->VMPointer))->PrintableName = ClassDataAllocator.Strdup(FStringf("%s.%s [Native]", afunc->ClassName+1, afunc->FuncName).GetChars()); + (*(afunc->VMPointer))->DirectNativeCall = afunc->DirectNative; + AFTable.Push(*afunc); + }); + AFTable.ShrinkToFit(); + qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); + } + + FieldTable.Clear(); + if (FieldTable.Size() == 0) + { + AutoSegs::ClassFields.ForEach([](FieldDesc *afield) + { + FieldTable.Push(*afield); + }); + FieldTable.ShrinkToFit(); + qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); + } +} + diff --git a/src/common/scripting/core/maps.cpp b/src/common/scripting/core/maps.cpp new file mode 100644 index 00000000000..bed5110de50 --- /dev/null +++ b/src/common/scripting/core/maps.cpp @@ -0,0 +1,635 @@ +#include "tarray.h" +#include "dobject.h" +#include "zstring.h" +#include "vm.h" +#include "types.h" +#include "v_draw.h" +#include "maps.h" + + +//========================================================================== +// +// MAP_GC_WRITE_BARRIER +// +//========================================================================== + + +#define MAP_GC_WRITE_BARRIER(x) { \ + TMapIterator it(*x);\ + typename M::Pair * p;\ + while(it.NextPair(p)){\ + GC::WriteBarrier(p->Value);\ + }\ +} + + +//========================================================================== +// +// MapCopy +// +//========================================================================== + + +template void MapCopy(M * self, M * other) +{ + if constexpr(std::is_same_v) + { + MAP_GC_WRITE_BARRIER(other); + } + *self = *other; // how does this handle self->info? TODO double check. + self->info->rev++; +} + + +//========================================================================== +// +// MapMove +// +//========================================================================== + + +template void MapMove(M * self, M * other) +{ + if constexpr(std::is_same_v) + { + MAP_GC_WRITE_BARRIER(other); + } + self->TransferFrom(*other); + self->info->rev++; + other->info->rev++; +} + + +//========================================================================== +// +// MapSwap +// +//========================================================================== + + +template void MapSwap(M * self, M * other) +{ + if constexpr(std::is_same_v) + { + MAP_GC_WRITE_BARRIER(other); + } + self->Swap(*other); + self->info->rev++; + other->info->rev++; +} + + +//========================================================================== +// +// MapClear +// +//========================================================================== + + +template void MapClear(M * self) +{ + if constexpr(std::is_same_v) + { + MAP_GC_WRITE_BARRIER(self); + } + self->Clear(); + self->info->rev++; +} + + +//========================================================================== +// +// +// +//========================================================================== + + +template +using expand_types_vm = +std::conditional_t || std::is_same_v, uint32_t , /* expand 8/16-bit to 32-bit */ + std::conditional_t , double , /* expand float to double */ + std::conditional_t , const FString & , T>>>; /* change String to String ref */ + +template unsigned int MapCountUsed(M * self) +{ + return self->CountUsed(); +} + +template expand_types_vm MapGet(M * self,expand_types_vm key) +{ + typename M::ValueType * v = self->CheckKey(key); + if (v) + { + if constexpr(std::is_same_v) + { + return GC::ReadBarrier(*v); + } + else + { + return *v; + } + } + else + { + typename M::ValueType n {}; + self->Insert(key,n); + self->info->rev++; // invalidate iterators + return n; + } +} + +template void MapGetString(M * self,expand_types_vm key, FString &out) +{ + FString * v = self->CheckKey(key); + if (v) { + out = *v; + } + else + { + out = FString(); + self->Insert(key,out); + self->info->rev++; // invalidate iterators + } +} + +template expand_types_vm MapGetIfExists(M * self,expand_types_vm key) +{ + typename M::ValueType * v = self->CheckKey(key); + if (v) { + if constexpr(std::is_same_v) + { + return GC::ReadBarrier(*v); + } + else + { + return *v; + } + } + else + { + return {}; + } +} + +template void MapGetIfExistsString(M * self,expand_types_vm key, FString &out) +{ + FString * v = self->CheckKey(key); + if (v) { + out = *v; + } + else + { + out = FString(); + } +} + +template int MapCheckKey(M * self, expand_types_vm key) +{ + return self->CheckKey(key) != nullptr; +} + +template expand_types_vm MapCheckValue(M * self,expand_types_vm key, int &exists) +{ + typename M::ValueType * v = self->CheckKey(key); + if ((exists = !!v)) { + if constexpr(std::is_same_v) + { + return GC::ReadBarrier(*v); + } + else + { + return *v; + } + } + else + { + return {}; + } +} + +template void MapCheckValueString(M * self,expand_types_vm key, FString &out, int &exists) +{ + FString * v = self->CheckKey(key); + if ((exists = !!v)) { + out = *v; + } + else + { + out = FString(); + } +} + + +//========================================================================== +// +// MapInsert +// +//========================================================================== + + +template void MapInsert(M * self, expand_types_vm key, expand_types_vm value) +{ + if constexpr(std::is_same_v) + { + MAP_GC_WRITE_BARRIER(self); + GC::WriteBarrier(value); + } + + if constexpr(std::is_same_v) + { + self->Insert(key,static_cast(value)); + } + else + { + self->Insert(key, value); + } + self->info->rev++; // invalidate iterators +} + + +//========================================================================== +// +// +// +//========================================================================== + + +template void MapInsertNew(M * self, expand_types_vm key) +{ + if constexpr(std::is_same_v) + { + MAP_GC_WRITE_BARRIER(self); + } + self->Insert(key,{}); + self->info->rev++; // invalidate iterators +} + +template void MapRemove(M * self, expand_types_vm key) +{ + self->Remove(key); + self->info->rev++; // invalidate iterators +} + + +//========================================================================== +// +// +// +//========================================================================== + + +template int MapIteratorInit(I * self, M * other) +{ + return self->Init(*other); +} + +template int MapIteratorReInit(I * self) +{ + return self->ReInit(); +} + +template int MapIteratorValid(I * self) +{ + return self->Valid(); +} + +template int MapIteratorNext(I * self) +{ + return self->Next(); +} + +template expand_types_vm MapIteratorGetKey(I * self) +{ + return self->GetKey(); +} + +template void MapIteratorGetKeyString(I * self, FString &out) +{ + out = self->GetKey(); +} + +template expand_types_vm MapIteratorGetValue(I * self) +{ + if constexpr(std::is_same_v) + { + return GC::ReadBarrier(self->GetValue()); + } + else + { + return self->GetValue(); + } +} + +template void MapIteratorGetValueString(I * self, FString &out) +{ + out = self->GetValue(); +} + +template void MapIteratorSetValue(I * self, expand_types_vm value) +{ + auto & val = self->GetValue(); + if constexpr(std::is_same_v) + { + GC::WriteBarrier(val); + GC::WriteBarrier(value); + } + + if constexpr(std::is_same_v) + { + val = static_cast(value); + } + else + { + val = value; + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +template void SetValType(T & ret,U & val){ + if constexpr(std::is_same_v) + { + ret[N].SetObject(val); + } + else if constexpr(std::is_same_v) + { + ret[N].SetPointer(val); + } + else if constexpr(std::is_same_v) + { + ret[N].SetInt(val); + } + else if constexpr(std::is_same_v) + { + ret[N].SetFloat(val); + } +} + +#define PARAM_VOIDPOINTER(X) PARAM_POINTER( X , void ) +#define PARAM_OBJPOINTER(X) PARAM_OBJECT( X , DObject ) + +#define _DEF_MAP( name, key_type, value_type, PARAM_KEY, PARAM_VALUE ) \ + typedef ZSMap name;\ + DEFINE_ACTION_FUNCTION_NATIVE( name , Copy , MapCopy< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_POINTER( other, name ); \ + MapCopy(self , other); \ + return 0; \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , Move , MapMove< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_POINTER( other, name ); \ + MapMove(self , other); \ + return 0; \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , Swap , MapSwap< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_POINTER( other, name ); \ + MapSwap(self , other); \ + return 0; \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , Clear , MapClear< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + MapClear(self); \ + return 0; \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, CountUsed, MapCountUsed< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_INT( MapCountUsed(self) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, CheckKey, MapCheckKey< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + ACTION_RETURN_BOOL( MapCheckKey(self, key) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, Insert, MapInsert< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + PARAM_VALUE( value ); \ + MapInsert(self, key, value); \ + return 0; \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, InsertNew, MapInsertNew< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + MapInsertNew(self, key); \ + return 0; \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, Remove, MapRemove< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + MapRemove(self, key); \ + return 0; \ + } + +#define DEF_MAP_X_X( name, key_type, value_type, PARAM_KEY, PARAM_VALUE , ACTION_RETURN_VALUE ) \ + _DEF_MAP( name , key_type , value_type , PARAM_KEY , PARAM_VALUE ) \ + DEFINE_ACTION_FUNCTION_NATIVE( name, Get, MapGet< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + ACTION_RETURN_VALUE( MapGet(self, key) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, GetIfExists, MapGetIfExists< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + ACTION_RETURN_VALUE( MapGetIfExists(self, key) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, CheckValue, MapCheckValue< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + int exists; \ + expand_types_vm out; \ + out = MapCheckValue(self, key, exists); \ + if (numret > 1) ret[1].SetInt(exists); \ + if (numret > 0) SetValType<0>(ret, out); \ + return numret; \ + } + +#define DEF_MAP_X_S( name, key_type, PARAM_KEY ) \ + _DEF_MAP( name , key_type , FString , PARAM_KEY , PARAM_STRING ) \ + DEFINE_ACTION_FUNCTION_NATIVE( name, Get, MapGetString< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + FString out; \ + MapGetString(self, key, out); \ + ACTION_RETURN_STRING( out ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, GetIfExists, MapGetIfExistsString< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + FString out; \ + MapGetIfExistsString(self, key, out); \ + ACTION_RETURN_STRING( out ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name, CheckValue, MapCheckValueString< name >) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_KEY( key ); \ + int exists; \ + FString out; \ + MapCheckValueString(self, key, out, exists); \ + if (numret > 1) ret[1].SetInt(exists); \ + if (numret > 0) ret[0].SetString(out); \ + return numret; \ + } + +#define COMMA , + +#define _DEF_MAP_IT( map_name , name, key_type, value_type, PARAM_VALUE ) \ + typedef ZSMapIterator name; \ + DEFINE_ACTION_FUNCTION_NATIVE( name , Init , MapIteratorInit< name COMMA map_name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_POINTER( other, map_name ); \ + ACTION_RETURN_BOOL( MapIteratorInit(self , other) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , ReInit , MapIteratorReInit< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_BOOL( MapIteratorReInit(self) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , Valid , MapIteratorValid< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_BOOL( MapIteratorValid(self) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , Next , MapIteratorNext< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_BOOL( MapIteratorNext(self) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , SetValue , MapIteratorSetValue< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + PARAM_VALUE( value ); \ + MapIteratorSetValue(self, value); \ + return 0; \ + } +/* + DEFINE_ACTION_FUNCTION_NATIVE( name , GetKey , MapIteratorGetKey< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_KEY( MapIteratorGetKey(self) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , GetValue , MapIteratorGetValue< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_VALUE( MapIteratorGetValue(self) ); \ + } \ +*/ + +#define DEF_MAP_IT_I_X( map_name , name , value_type , PARAM_VALUE , ACTION_RETURN_VALUE ) \ + _DEF_MAP_IT( map_name , name , uint32_t , value_type , PARAM_VALUE ) \ + DEFINE_ACTION_FUNCTION_NATIVE( name , GetKey , MapIteratorGetKey< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_INT( MapIteratorGetKey(self) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , GetValue , MapIteratorGetValue< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_VALUE( MapIteratorGetValue(self) ); \ + } + +#define DEF_MAP_IT_S_X( map_name , name , value_type , PARAM_VALUE , ACTION_RETURN_VALUE ) \ + _DEF_MAP_IT( map_name , name , FString , value_type , PARAM_VALUE ) \ + DEFINE_ACTION_FUNCTION_NATIVE( name , GetKey , MapIteratorGetKeyString< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + FString out; \ + MapIteratorGetKeyString(self , out); \ + ACTION_RETURN_STRING( out ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( name , GetValue , MapIteratorGetValue< name > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( name ); \ + ACTION_RETURN_VALUE( MapIteratorGetValue(self) ); \ + } + +#define DEF_MAP_IT_I_S() \ + _DEF_MAP_IT( FMap_I32_Str , FMapIterator_I32_Str , uint32_t , FString , PARAM_STRING ) \ + DEFINE_ACTION_FUNCTION_NATIVE( FMapIterator_I32_Str , GetKey , MapIteratorGetKey< FMapIterator_I32_Str > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_I32_Str ); \ + ACTION_RETURN_INT( MapIteratorGetKey(self) ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( FMapIterator_I32_Str , GetValue , MapIteratorGetValueString< FMapIterator_I32_Str > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_I32_Str ); \ + FString out; \ + MapIteratorGetValueString(self , out); \ + ACTION_RETURN_STRING( out ); \ + } + +#define DEF_MAP_IT_S_S() \ + _DEF_MAP_IT( FMap_Str_Str , FMapIterator_Str_Str , FString , FString , PARAM_STRING ) \ + DEFINE_ACTION_FUNCTION_NATIVE( FMapIterator_Str_Str , GetKey , MapIteratorGetKeyString< FMapIterator_Str_Str > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_Str_Str ); \ + FString out; \ + MapIteratorGetKeyString(self , out); \ + ACTION_RETURN_STRING( out ); \ + } \ + DEFINE_ACTION_FUNCTION_NATIVE( FMapIterator_Str_Str , GetValue , MapIteratorGetValueString< FMapIterator_Str_Str > ) \ + { \ + PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_Str_Str ); \ + FString out; \ + MapIteratorGetValueString(self , out); \ + ACTION_RETURN_STRING( out ); \ + } + + + +#define DEFINE_MAP_AND_IT_I_X( name , value_type , PARAM_VALUE , ACTION_RETURN_VALUE ) \ + DEF_MAP_X_X( FMap_ ## name , uint32_t , value_type , PARAM_INT , PARAM_VALUE , ACTION_RETURN_VALUE ) \ + DEF_MAP_IT_I_X( FMap_ ## name , FMapIterator_ ## name , value_type , PARAM_VALUE , ACTION_RETURN_VALUE ) + + +#define DEFINE_MAP_AND_IT_S_X( name , value_type , PARAM_VALUE , ACTION_RETURN_VALUE ) \ + DEF_MAP_X_X( FMap_ ## name , FString , value_type , PARAM_STRING , PARAM_VALUE , ACTION_RETURN_VALUE ) \ + DEF_MAP_IT_S_X( FMap_ ## name , FMapIterator_ ## name , value_type , PARAM_VALUE , ACTION_RETURN_VALUE ) + +#define DEFINE_MAP_AND_IT_I_S() \ + DEF_MAP_X_S( FMap_I32_Str , uint32_t , PARAM_INT ) \ + DEF_MAP_IT_I_S() + +#define DEFINE_MAP_AND_IT_S_S() \ + DEF_MAP_X_S( FMap_Str_Str , FString , PARAM_STRING ) \ + DEF_MAP_IT_S_S() + +DEFINE_MAP_AND_IT_I_X(I32_I8 , uint8_t , PARAM_INT , ACTION_RETURN_INT); +DEFINE_MAP_AND_IT_I_X(I32_I16 , uint16_t , PARAM_INT , ACTION_RETURN_INT); +DEFINE_MAP_AND_IT_I_X(I32_I32 , uint32_t , PARAM_INT , ACTION_RETURN_INT); +DEFINE_MAP_AND_IT_I_X(I32_F32 , float , PARAM_FLOAT , ACTION_RETURN_FLOAT); +DEFINE_MAP_AND_IT_I_X(I32_F64 , double , PARAM_FLOAT , ACTION_RETURN_FLOAT); +DEFINE_MAP_AND_IT_I_X(I32_Obj , DObject* , PARAM_OBJPOINTER , ACTION_RETURN_OBJECT); +DEFINE_MAP_AND_IT_I_X(I32_Ptr , void* , PARAM_VOIDPOINTER , ACTION_RETURN_POINTER); +DEFINE_MAP_AND_IT_I_S(); + +DEFINE_MAP_AND_IT_S_X(Str_I8 , uint8_t , PARAM_INT , ACTION_RETURN_INT); +DEFINE_MAP_AND_IT_S_X(Str_I16 , uint16_t , PARAM_INT , ACTION_RETURN_INT); +DEFINE_MAP_AND_IT_S_X(Str_I32 , uint32_t , PARAM_INT , ACTION_RETURN_INT); +DEFINE_MAP_AND_IT_S_X(Str_F32 , float , PARAM_FLOAT , ACTION_RETURN_FLOAT); +DEFINE_MAP_AND_IT_S_X(Str_F64 , double , PARAM_FLOAT , ACTION_RETURN_FLOAT); +DEFINE_MAP_AND_IT_S_X(Str_Obj , DObject* , PARAM_OBJPOINTER , ACTION_RETURN_OBJECT); +DEFINE_MAP_AND_IT_S_X(Str_Ptr , void* , PARAM_VOIDPOINTER , ACTION_RETURN_POINTER); +DEFINE_MAP_AND_IT_S_S(); \ No newline at end of file diff --git a/src/common/scripting/core/maps.h b/src/common/scripting/core/maps.h new file mode 100644 index 00000000000..ed303537b50 --- /dev/null +++ b/src/common/scripting/core/maps.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include "tarray.h" +#include "refcounted.h" + +class ZSMapInfo : public RefCountedBase +{ +public: + void * self = nullptr; + int rev = 0; +}; + +struct ZSFMap : FMap { + RefCountedPtr info; +}; + +template +class ZSMap : public TMap +{ +public: + RefCountedPtr info; + ZSMap() : + TMap(), info(new ZSMapInfo) + { + info->self = this; + } + ~ZSMap() + { + info->self = nullptr; + } +}; + +template +struct ZSMapIterator +{ + RefCountedPtr info; + TMapIterator *it = nullptr; + typename ZSMap::Pair *p = nullptr; + + typedef KT KeyType; + typedef VT ValueType; + + int rev = 0; + + ~ZSMapIterator() + { + if(it) delete it; + } + + bool Valid() + { + return it && p && info.get() && info->self && info->rev == rev; + } + + bool ReInit() + { + if(info.get() && info->self) { + if(it) delete it; + it = new TMapIterator(*static_cast*>(info->self)); + rev = info->rev; + p = nullptr; + return true; + } + return false; + } + + bool Init(ZSMap &m) + { + info = m.info; + return ReInit(); + } + + bool Next() + { + if(it && info.get() && info->self && info->rev == rev) + { + p = nullptr; + return it->NextPair(p); + } + else + { + ThrowAbortException(X_FORMAT_ERROR,"MapIterator::Next called from invalid iterator"); + } + } + + VT& GetValue() + { + if(p && info.get() && info->self && info->rev == rev) + { + return p->Value; + } + else + { + ThrowAbortException(X_FORMAT_ERROR,p ? "MapIterator::GetValue called from invalid iterator" : "MapIterator::GetValue called from invalid position"); + } + } + + const KT& GetKey() + { + if(p && info.get() && info->self && info->rev == rev) + { + return p->Key; + } + else + { + ThrowAbortException(X_FORMAT_ERROR,p ? "MapIterator::GetKey called from invalid iterator" : "MapIterator::GetKey called from invalid position"); + } + } +}; \ No newline at end of file diff --git a/src/scripting/backend/scopebarrier.cpp b/src/common/scripting/core/scopebarrier.cpp similarity index 94% rename from src/scripting/backend/scopebarrier.cpp rename to src/common/scripting/core/scopebarrier.cpp index f4d584c7baa..b2744357073 100644 --- a/src/scripting/backend/scopebarrier.cpp +++ b/src/common/scripting/core/scopebarrier.cpp @@ -208,9 +208,18 @@ void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name) } } +bool FScopeBarrier::CheckSidesForFunctionPointer(int from, int to) +{ + if(to == -1) return true; + + if(from == Side_Clear) from = Side_PlainData; + return ((from == to) || (from == Side_PlainData)); +} + // these are for vmexec.h void FScopeBarrier::ValidateNew(PClass* cls, int outerside) { + if (cls->VMType == nullptr) ThrowAbortException(X_OTHER,"Cannot instantiate invalid class %s", cls->TypeName.GetChars()); int innerside = FScopeBarrier::SideFromObjectFlags(cls->VMType->ScopeFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context" ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside)); @@ -220,5 +229,5 @@ void FScopeBarrier::ValidateCall(PClass* selftype, VMFunction *calledfunc, int o { int innerside = FScopeBarrier::SideFromObjectFlags(selftype->VMType->ScopeFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) - ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->PrintableName.GetChars(), FScopeBarrier::StringFromSide(outerside)); + ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->PrintableName, FScopeBarrier::StringFromSide(outerside)); } \ No newline at end of file diff --git a/src/scripting/backend/scopebarrier.h b/src/common/scripting/core/scopebarrier.h similarity index 96% rename from src/scripting/backend/scopebarrier.h rename to src/common/scripting/core/scopebarrier.h index fb931d2233b..08fc0a195a3 100644 --- a/src/scripting/backend/scopebarrier.h +++ b/src/common/scripting/core/scopebarrier.h @@ -46,7 +46,7 @@ struct FScopeBarrier // static int FlagsFromSide(int side); static EScopeFlags ObjectFlagsFromSide(int side); - + // used for errors static const char* StringFromSide(int side); @@ -62,6 +62,9 @@ struct FScopeBarrier // This struct is used so that the logic is in a single place. void AddFlags(int flags1, int flags2, const char* name); + + static bool CheckSidesForFunctionPointer(int from, int to); + // this is called from vmexec.h static void ValidateNew(PClass* cls, int scope); static void ValidateCall(PClass* selftype, VMFunction *calledfunc, int outerside); diff --git a/src/scripting/symbols.cpp b/src/common/scripting/core/symbols.cpp similarity index 98% rename from src/scripting/symbols.cpp rename to src/common/scripting/core/symbols.cpp index 64a52039fd6..d293cbbee4f 100644 --- a/src/scripting/symbols.cpp +++ b/src/common/scripting/core/symbols.cpp @@ -35,10 +35,11 @@ #include #include "dobject.h" -#include "templates.h" + #include "serializer.h" #include "types.h" #include "vm.h" +#include "printf.h" // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -136,7 +137,6 @@ PField::PField() { } - PField::PField(FName name, PType *type, uint32_t flags, size_t offset, int bitvalue) : PSymbol(name), Offset(offset), Type(type), Flags(flags) { @@ -330,10 +330,12 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) // //========================================================================== -PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align) +PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align, int fileno) { PField *field = Create(name, type, flags); + field->mDefFileNo = fileno; + // The new field is added to the end of this struct, alignment permitting. field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1); @@ -344,7 +346,7 @@ PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned // its fields. if (Align != nullptr) { - *Align = MAX(*Align, type->Align); + *Align = max(*Align, type->Align); } if (AddSymbol(field) == nullptr) @@ -364,10 +366,12 @@ PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned // //========================================================================== -PField *PSymbolTable::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +PField *PSymbolTable::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue, int fileno) { PField *field = Create(name, type, flags | VARF_Native | VARF_Transient, address, bitvalue); + field->mDefFileNo = fileno; + if (AddSymbol(field) == nullptr) { // name is already in use field->Destroy(); diff --git a/src/scripting/symbols.h b/src/common/scripting/core/symbols.h similarity index 91% rename from src/scripting/symbols.h rename to src/common/scripting/core/symbols.h index bba2ac8d104..b75d3a2ea21 100644 --- a/src/scripting/symbols.h +++ b/src/common/scripting/core/symbols.h @@ -1,6 +1,7 @@ // Note: This must not be included by anything but dobject.h! #pragma once +#include "sc_man.h" class VMFunction; class PType; @@ -8,6 +9,16 @@ class PPrototype; struct ZCC_TreeNode; class PContainerType; +// This is needed in common code, despite being Doom specific. +enum EStateUseFlags +{ + SUF_ACTOR = 1, + SUF_OVERLAY = 2, + SUF_WEAPON = 4, + SUF_ITEM = 8, +}; + + // Symbol information ------------------------------------------------------- class PTypeBase @@ -43,7 +54,7 @@ class PSymbolType : public PSymbol { DECLARE_CLASS(PSymbolType, PSymbol); public: - PType *Type; + PType *Type = nullptr; PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} PSymbolType() : PSymbol(NAME_None) {} @@ -55,7 +66,7 @@ class PSymbolTreeNode : public PSymbol { DECLARE_CLASS(PSymbolTreeNode, PSymbol); public: - struct ZCC_TreeNode *Node; + struct ZCC_TreeNode *Node = nullptr; PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {} PSymbolTreeNode() : PSymbol(NAME_None) {} @@ -77,6 +88,7 @@ class PField : public PSymbol uint32_t Flags; int BitValue; FString DeprecationMessage; + int mDefFileNo = 0; protected: PField(); }; @@ -135,11 +147,11 @@ class PSymbolConstNumeric : public PSymbolConst void *Pad; }; - PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} + PSymbolConstNumeric(FName name, PType *type=nullptr) : PSymbolConst(name, type), Float(0) {} PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} - PSymbolConstNumeric() {} + PSymbolConstNumeric() : Float(0) {} }; // A constant string value -------------------------------------------------- @@ -211,8 +223,8 @@ struct PSymbolTable // a symbol with the same name is already in the table. This symbol is // not copied and will be freed when the symbol table is destroyed. PSymbol *AddSymbol (PSymbol *sym); - PField *AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align = nullptr); - PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue); + PField *AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align = nullptr, int fileno = 0); + PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue, int fileno = 0); bool ReadFields(FSerializer &ar, void *addr, const char *TypeName) const; void WriteFields(FSerializer &ar, const void *addr, const void *def = nullptr) const; @@ -266,3 +278,8 @@ struct FNamespaceManager extern FNamespaceManager Namespaces; void RemoveUnusedSymbols(); + +struct AFuncDesc; +struct FieldDesc; +AFuncDesc *FindFunction(PContainerType *cls, const char * string); +FieldDesc *FindField(PContainerType *cls, const char * string); diff --git a/src/common/scripting/core/types.cpp b/src/common/scripting/core/types.cpp new file mode 100644 index 00000000000..8e13dcc521b --- /dev/null +++ b/src/common/scripting/core/types.cpp @@ -0,0 +1,3692 @@ +/* +** types.cpp +** Implements the VM type hierarchy +** +**--------------------------------------------------------------------------- +** Copyright 2008-2016 Randy Heit +** Copyright 2016-2017 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include + +#include "vmintern.h" +#include "s_soundinternal.h" +#include "types.h" +#include "printf.h" +#include "textureid.h" +#include "maps.h" +#include "palettecontainer.h" +#include "texturemanager.h" +#include "i_interface.h" + + +FTypeTable TypeTable; + +PErrorType *TypeError; +PErrorType *TypeAuto; +PVoidType *TypeVoid; +PInt *TypeSInt8, *TypeUInt8; +PInt *TypeSInt16, *TypeUInt16; +PInt *TypeSInt32, *TypeUInt32; +PBool *TypeBool; +PFloat *TypeFloat32, *TypeFloat64; +PString *TypeString; +PName *TypeName; +PSound *TypeSound; +PColor *TypeColor; +PTextureID *TypeTextureID; +PTranslationID* TypeTranslationID; +PSpriteID *TypeSpriteID; +PStatePointer *TypeState; +PPointer *TypeFont; +PStateLabel *TypeStateLabel; +PStruct *TypeVector2; +PStruct *TypeVector3; +PStruct* TypeVector4; +PStruct* TypeQuaternion; +PStruct* TypeFVector2; +PStruct* TypeFVector3; +PStruct* TypeFVector4; +PStruct* TypeFQuaternion; +PStruct *TypeColorStruct; +PStruct *TypeStringStruct; +PStruct* TypeQuaternionStruct; +PPointer *TypeNullPtr; +PPointer *TypeVoidPtr; +PPointer *TypeRawFunction; +PPointer* TypeVMFunction; + + +// CODE -------------------------------------------------------------------- + +void DumpTypeTable() +{ + int used = 0; + int min = INT_MAX; + int max = 0; + int all = 0; + int lens[10] = {0}; + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + int len = 0; + Printf("%4zu:", i); + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) + { + Printf(" -> %s", ty->DescriptiveName()); + len++; + all++; + } + if (len != 0) + { + used++; + if (len < min) + min = len; + if (len > max) + max = len; + } + if (len < (int)countof(lens)) + { + lens[len]++; + } + Printf("\n"); + } + Printf("Used buckets: %d/%zu (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); + Printf("Min bucket size: %d\n", min); + Printf("Max bucket size: %d\n", max); + Printf("Avg bucket size: %.2f\n", double(all) / used); + int j,k; + for (k = countof(lens)-1; k > 0; --k) + if (lens[k]) + break; + for (j = 0; j <= k; ++j) + Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); +} + +/* PType ******************************************************************/ + +//========================================================================== +// +// PType Parameterized Constructor +// +//========================================================================== + +PType::PType(unsigned int size, unsigned int align) +: Size(size), Align(align), HashNext(nullptr) +{ + mDescriptiveName = "Type"; + loadOp = OP_NOP; + storeOp = OP_NOP; + moveOp = OP_NOP; + RegType = REGT_NIL; + RegCount = 1; +} + +//========================================================================== +// +// PType Destructor +// +//========================================================================== + +PType::~PType() +{ +} + +//========================================================================== +// +// PType :: WriteValue +// +//========================================================================== + +void PType::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + assert(0 && "Cannot write value for this type"); +} + +//========================================================================== +// +// PType :: ReadValue +// +//========================================================================== + +bool PType::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + assert(0 && "Cannot read value for this type"); + return false; +} + +//========================================================================== +// +// PType :: SetDefaultValue +// +//========================================================================== + +void PType::SetDefaultValue(void *base, unsigned offset, TArray *stroffs) +{ +} + +//========================================================================== +// +// PType :: SetPointer* +// +//========================================================================== + +void PType::SetPointer(void *base, unsigned offset, TArray> *stroffs) +{ +} + +void PType::SetPointerArray(void *base, unsigned offset, TArray> *stroffs) +{ +} + +void PType::SetPointerMap(void *base, unsigned offset, TArray> *ptrofs) +{ +} + +//========================================================================== +// +// PType :: InitializeValue +// +//========================================================================== + +void PType::InitializeValue(void *addr, const void *def) const +{ +} + +//========================================================================== +// +// PType :: DestroyValue +// +//========================================================================== + +void PType::DestroyValue(void *addr) const +{ +} + +//========================================================================== +// +// PType :: SetValue +// +//========================================================================== + +void PType::SetValue(void *addr, int val) +{ + assert(0 && "Cannot set int value for this type"); +} + +void PType::SetValue(void *addr, double val) +{ + assert(0 && "Cannot set float value for this type"); +} + +//========================================================================== +// +// PType :: GetValue +// +//========================================================================== + +int PType::GetValueInt(void *addr) const +{ + assert(0 && "Cannot get value for this type"); + return 0; +} + +double PType::GetValueFloat(void *addr) const +{ + assert(0 && "Cannot get value for this type"); + return 0; +} + +//========================================================================== +// +// PType :: IsMatch +// +//========================================================================== + +bool PType::IsMatch(intptr_t id1, intptr_t id2) const +{ + return false; +} + +//========================================================================== +// +// PType :: GetTypeIDs +// +//========================================================================== + +void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = 0; + id2 = 0; +} + +//========================================================================== +// +// PType :: GetTypeIDs +// +//========================================================================== + +const char *PType::DescriptiveName() const +{ + return mDescriptiveName.GetChars(); +} + +//========================================================================== +// +// PType :: StaticInit STATIC +// +//========================================================================== + +void PType::StaticInit() +{ + // Create types and add them type the type table. + TypeTable.AddType(TypeError = new PErrorType, NAME_None); + TypeTable.AddType(TypeAuto = new PErrorType(2), NAME_None); + TypeTable.AddType(TypeVoid = new PVoidType, NAME_Void); + TypeTable.AddType(TypeSInt8 = new PInt(1, false), NAME_Int); + TypeTable.AddType(TypeUInt8 = new PInt(1, true), NAME_Int); + TypeTable.AddType(TypeSInt16 = new PInt(2, false), NAME_Int); + TypeTable.AddType(TypeUInt16 = new PInt(2, true), NAME_Int); + TypeTable.AddType(TypeSInt32 = new PInt(4, false), NAME_Int); + TypeTable.AddType(TypeUInt32 = new PInt(4, true), NAME_Int); + TypeTable.AddType(TypeBool = new PBool, NAME_Bool); + TypeTable.AddType(TypeFloat32 = new PFloat(4), NAME_Float); + TypeTable.AddType(TypeFloat64 = new PFloat(8), NAME_Float); + TypeTable.AddType(TypeString = new PString, NAME_String); + TypeTable.AddType(TypeName = new PName, NAME_Name); + TypeTable.AddType(TypeSound = new PSound, NAME_Sound); + TypeTable.AddType(TypeColor = new PColor, NAME_Color); + TypeTable.AddType(TypeState = new PStatePointer, NAME_Pointer); + TypeTable.AddType(TypeStateLabel = new PStateLabel, NAME_Label); + TypeTable.AddType(TypeNullPtr = new PPointer, NAME_Pointer); + TypeTable.AddType(TypeSpriteID = new PSpriteID, NAME_SpriteID); + TypeTable.AddType(TypeTextureID = new PTextureID, NAME_TextureID); + TypeTable.AddType(TypeTranslationID = new PTranslationID, NAME_TranslationID); + + TypeVoidPtr = NewPointer(TypeVoid, false); + TypeRawFunction = new PPointer; + TypeRawFunction->mDescriptiveName = "Raw Function Pointer"; + TypeVMFunction = NewPointer(NewStruct("VMFunction", nullptr, true)); + TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. + TypeStringStruct = NewStruct("Stringstruct", nullptr, true); + TypeQuaternionStruct = NewStruct("QuatStruct", nullptr, true); + TypeFont = NewPointer(NewStruct("Font", nullptr, true)); +#ifdef __BIG_ENDIAN__ + TypeColorStruct->AddField(NAME_a, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_b, TypeUInt8); +#else + TypeColorStruct->AddField(NAME_b, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_a, TypeUInt8); +#endif + + TypeVector2 = new PStruct(NAME_Vector2, nullptr); + TypeVector2->AddField(NAME_X, TypeFloat64); + TypeVector2->AddField(NAME_Y, TypeFloat64); + TypeTable.AddType(TypeVector2, NAME_Struct); + TypeVector2->loadOp = OP_LV2; + TypeVector2->storeOp = OP_SV2; + TypeVector2->moveOp = OP_MOVEV2; + TypeVector2->RegType = REGT_FLOAT; + TypeVector2->RegCount = 2; + TypeVector2->isOrdered = true; + + TypeVector3 = new PStruct(NAME_Vector3, nullptr); + TypeVector3->AddField(NAME_X, TypeFloat64); + TypeVector3->AddField(NAME_Y, TypeFloat64); + TypeVector3->AddField(NAME_Z, TypeFloat64); + // allow accessing xy as a vector2. This is not supposed to be serialized so it's marked transient + TypeVector3->Symbols.AddSymbol(Create(NAME_XY, TypeVector2, VARF_Transient, 0)); + TypeTable.AddType(TypeVector3, NAME_Struct); + TypeVector3->loadOp = OP_LV3; + TypeVector3->storeOp = OP_SV3; + TypeVector3->moveOp = OP_MOVEV3; + TypeVector3->RegType = REGT_FLOAT; + TypeVector3->RegCount = 3; + TypeVector3->isOrdered = true; + + TypeVector4 = new PStruct(NAME_Vector4, nullptr); + TypeVector4->AddField(NAME_X, TypeFloat64); + TypeVector4->AddField(NAME_Y, TypeFloat64); + TypeVector4->AddField(NAME_Z, TypeFloat64); + TypeVector4->AddField(NAME_W, TypeFloat64); + // allow accessing xyz as a vector3. This is not supposed to be serialized so it's marked transient + TypeVector4->Symbols.AddSymbol(Create(NAME_XYZ, TypeVector3, VARF_Transient, 0)); + TypeVector4->Symbols.AddSymbol(Create(NAME_XY, TypeVector2, VARF_Transient, 0)); + TypeTable.AddType(TypeVector4, NAME_Struct); + TypeVector4->loadOp = OP_LV4; + TypeVector4->storeOp = OP_SV4; + TypeVector4->moveOp = OP_MOVEV4; + TypeVector4->RegType = REGT_FLOAT; + TypeVector4->RegCount = 4; + TypeVector4->isOrdered = true; + + + TypeFVector2 = new PStruct(NAME_FVector2, nullptr); + TypeFVector2->AddField(NAME_X, TypeFloat32); + TypeFVector2->AddField(NAME_Y, TypeFloat32); + TypeTable.AddType(TypeFVector2, NAME_Struct); + TypeFVector2->loadOp = OP_LFV2; + TypeFVector2->storeOp = OP_SFV2; + TypeFVector2->moveOp = OP_MOVEV2; + TypeFVector2->RegType = REGT_FLOAT; + TypeFVector2->RegCount = 2; + TypeFVector2->isOrdered = true; + + TypeFVector3 = new PStruct(NAME_FVector3, nullptr); + TypeFVector3->AddField(NAME_X, TypeFloat32); + TypeFVector3->AddField(NAME_Y, TypeFloat32); + TypeFVector3->AddField(NAME_Z, TypeFloat32); + // allow accessing xy as a vector2 + TypeFVector3->Symbols.AddSymbol(Create(NAME_XY, TypeFVector2, VARF_Transient, 0)); + TypeTable.AddType(TypeFVector3, NAME_Struct); + TypeFVector3->loadOp = OP_LFV3; + TypeFVector3->storeOp = OP_SFV3; + TypeFVector3->moveOp = OP_MOVEV3; + TypeFVector3->RegType = REGT_FLOAT; + TypeFVector3->RegCount = 3; + TypeFVector3->isOrdered = true; + + TypeFVector4 = new PStruct(NAME_FVector4, nullptr); + TypeFVector4->AddField(NAME_X, TypeFloat32); + TypeFVector4->AddField(NAME_Y, TypeFloat32); + TypeFVector4->AddField(NAME_Z, TypeFloat32); + TypeFVector4->AddField(NAME_W, TypeFloat32); + // allow accessing xyz as a vector3 + TypeFVector4->Symbols.AddSymbol(Create(NAME_XYZ, TypeFVector3, VARF_Transient, 0)); + TypeFVector4->Symbols.AddSymbol(Create(NAME_XY, TypeFVector2, VARF_Transient, 0)); + TypeTable.AddType(TypeFVector4, NAME_Struct); + TypeFVector4->loadOp = OP_LFV4; + TypeFVector4->storeOp = OP_SFV4; + TypeFVector4->moveOp = OP_MOVEV4; + TypeFVector4->RegType = REGT_FLOAT; + TypeFVector4->RegCount = 4; + TypeFVector4->isOrdered = true; + + + TypeQuaternion = new PStruct(NAME_Quat, nullptr); + TypeQuaternion->AddField(NAME_X, TypeFloat64); + TypeQuaternion->AddField(NAME_Y, TypeFloat64); + TypeQuaternion->AddField(NAME_Z, TypeFloat64); + TypeQuaternion->AddField(NAME_W, TypeFloat64); + // allow vector access. + TypeQuaternion->Symbols.AddSymbol(Create(NAME_XYZ, TypeVector3, VARF_Transient, 0)); + TypeQuaternion->Symbols.AddSymbol(Create(NAME_XY, TypeVector2, VARF_Transient, 0)); + TypeTable.AddType(TypeQuaternion, NAME_Struct); + TypeQuaternion->loadOp = OP_LV4; + TypeQuaternion->storeOp = OP_SV4; + TypeQuaternion->moveOp = OP_MOVEV4; + TypeQuaternion->RegType = REGT_FLOAT; + TypeQuaternion->RegCount = 4; + TypeQuaternion->isOrdered = true; + + TypeFQuaternion = new PStruct(NAME_FQuat, nullptr); + TypeFQuaternion->AddField(NAME_X, TypeFloat32); + TypeFQuaternion->AddField(NAME_Y, TypeFloat32); + TypeFQuaternion->AddField(NAME_Z, TypeFloat32); + TypeFQuaternion->AddField(NAME_W, TypeFloat32); + // allow accessing xyz as a vector3 + TypeFQuaternion->Symbols.AddSymbol(Create(NAME_XYZ, TypeFVector3, VARF_Transient, 0)); + TypeFQuaternion->Symbols.AddSymbol(Create(NAME_XY, TypeFVector2, VARF_Transient, 0)); + TypeTable.AddType(TypeFQuaternion, NAME_Struct); + TypeFQuaternion->loadOp = OP_LFV4; + TypeFQuaternion->storeOp = OP_SFV4; + TypeFQuaternion->moveOp = OP_MOVEV4; + TypeFQuaternion->RegType = REGT_FLOAT; + TypeFQuaternion->RegCount = 4; + TypeFQuaternion->isOrdered = true; + + + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_sByte, TypeSInt8)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Byte, TypeUInt8)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Short, TypeSInt16)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_uShort, TypeUInt16)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Int, TypeSInt32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_uInt, TypeUInt32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Bool, TypeBool)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Float, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Double, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Float32, TypeFloat32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Float64, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_String, TypeString)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Name, TypeName)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Sound, TypeSound)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Color, TypeColor)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_State, TypeState)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Vector2, TypeVector2)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Vector3, TypeVector3)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Vector4, TypeVector4)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Quat, TypeQuaternion)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_FVector2, TypeFVector2)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_FVector3, TypeFVector3)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_FVector4, TypeFVector4)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_FQuat, TypeFQuaternion)); +} + + +/* PBasicType *************************************************************/ + +//========================================================================== +// +// PBasicType Parameterized Constructor +// +//========================================================================== + +PBasicType::PBasicType(unsigned int size, unsigned int align) +: PType(size, align) +{ + mDescriptiveName = "BasicType"; + Flags |= TYPE_Scalar; +} + +/* PCompoundType **********************************************************/ + +//========================================================================== +// +// PBasicType Parameterized Constructor +// +//========================================================================== + +PCompoundType::PCompoundType(unsigned int size, unsigned int align) + : PType(size, align) +{ + mDescriptiveName = "CompoundType"; +} + +/* PContainerType *************************************************************/ + +//========================================================================== +// +// PContainerType :: IsMatch +// +//========================================================================== + +bool PContainerType::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PTypeBase *outer = (const PTypeBase *)id1; + FName name = (ENamedName)(intptr_t)id2; + + return Outer == outer && TypeName == name; +} + +//========================================================================== +// +// PContainerType :: GetTypeIDs +// +//========================================================================== + +void PContainerType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)Outer; + id2 = TypeName.GetIndex(); +} + +/* PInt *******************************************************************/ + +//========================================================================== +// +// PInt Parameterized Constructor +// +//========================================================================== + +PInt::PInt(unsigned int size, bool unsign, bool compatible) +: PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible) +{ + mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size); + Flags |= TYPE_Int; + + MemberOnly = (size < 4); + if (!unsign) + { + int maxval = (1u << ((8 * size) - 1)) - 1; // compute as unsigned to prevent overflow before -1 + int minval = -maxval - 1; + Symbols.AddSymbol(Create(NAME_Min, this, minval)); + Symbols.AddSymbol(Create(NAME_Max, this, maxval)); + } + else + { + Symbols.AddSymbol(Create(NAME_Min, this, 0u)); + Symbols.AddSymbol(Create(NAME_Max, this, (uint32_t) (((uint64_t) 1u << (size * 8)) - 1uL))); + } + SetOps(); +} + +void PInt::SetOps() +{ + moveOp = OP_MOVE; + RegType = REGT_INT; + if (Size == 4) + { + storeOp = OP_SW; + loadOp = OP_LW; + } + else if (Size == 1) + { + storeOp = OP_SB; + loadOp = Unsigned ? OP_LBU : OP_LB; + } + else if (Size == 2) + { + storeOp = OP_SH; + loadOp = Unsigned ? OP_LHU : OP_LH; + } + else + { + assert(0 && "Unhandled integer size"); + storeOp = OP_NOP; + } +} + +//========================================================================== +// +// PInt :: WriteValue +// +//========================================================================== + +void PInt::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (Size == 8 && Unsigned) + { + // this is a special case that cannot be represented by an int64_t. + uint64_t val = *(uint64_t*)addr; + ar(key, val); + } + else + { + int64_t val; + switch (Size) + { + case 1: + val = Unsigned ? *(uint8_t*)addr : *(int8_t*)addr; + break; + + case 2: + val = Unsigned ? *(uint16_t*)addr : *(int16_t*)addr; + break; + + case 4: + val = Unsigned ? *(uint32_t*)addr : *(int32_t*)addr; + break; + + case 8: + val = *(int64_t*)addr; + break; + + default: + return; // something invalid + } + ar(key, val); + } +} + +//========================================================================== +// +// PInt :: ReadValue +// +//========================================================================== + +bool PInt::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + NumericValue val; + + ar(key, val); + if (val.type == NumericValue::NM_invalid) return false; // not found or usable + if (val.type == NumericValue::NM_float) val.signedval = (int64_t)val.floatval; + + // No need to check the unsigned state here. Downcasting to smaller types will yield the same result for both. + switch (Size) + { + case 1: + *(uint8_t*)addr = (uint8_t)val.signedval; + break; + + case 2: + *(uint16_t*)addr = (uint16_t)val.signedval; + break; + + case 4: + *(uint32_t*)addr = (uint32_t)val.signedval; + break; + + case 8: + *(uint64_t*)addr = (uint64_t)val.signedval; + break; + + default: + return false; // something invalid + } + + return true; +} + +//========================================================================== +// +// PInt :: SetValue +// +//========================================================================== + +void PInt::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + *(int *)addr = val; + } + else if (Size == 1) + { + *(uint8_t *)addr = val; + } + else if (Size == 2) + { + *(uint16_t *)addr = val; + } + else if (Size == 8) + { + *(uint64_t *)addr = val; + } + else + { + assert(0 && "Unhandled integer size"); + } +} + +void PInt::SetValue(void *addr, double val) +{ + SetValue(addr, (int)val); +} + +//========================================================================== +// +// PInt :: GetValueInt +// +//========================================================================== + +int PInt::GetValueInt(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + return *(int *)addr; + } + else if (Size == 1) + { + return Unsigned ? *(uint8_t *)addr : *(int8_t *)addr; + } + else if (Size == 2) + { + return Unsigned ? *(uint16_t *)addr : *(int16_t *)addr; + } + else if (Size == 8) + { // truncated output + return (int)*(uint64_t *)addr; + } + else + { + assert(0 && "Unhandled integer size"); + return 0; + } +} + +//========================================================================== +// +// PInt :: GetValueFloat +// +//========================================================================== + +double PInt::GetValueFloat(void *addr) const +{ + return GetValueInt(addr); +} + +//========================================================================== +// +// PInt :: GetStoreOp +// +//========================================================================== + +/* PBool ******************************************************************/ + +//========================================================================== +// +// PInt :: SetValue +// +//========================================================================== + +void PBool::SetValue(void *addr, int val) +{ + *(bool*)addr = !!val; +} + +void PBool::SetValue(void *addr, double val) +{ + *(bool*)addr = val != 0.; +} + +int PBool::GetValueInt(void *addr) const +{ + return *(bool *)addr; +} + +double PBool::GetValueFloat(void *addr) const +{ + return *(bool *)addr; +} + +//========================================================================== +// +// PBool Default Constructor +// +//========================================================================== + +PBool::PBool() +: PInt(sizeof(bool), true) +{ + mDescriptiveName = "Bool"; + MemberOnly = false; + Flags |= TYPE_IntNotInt; +} + +/* PFloat *****************************************************************/ + +//========================================================================== +// +// PFloat Parameterized Constructor +// +//========================================================================== + +PFloat::PFloat(unsigned int size) +: PBasicType(size, size) +{ + mDescriptiveName.Format("Float%d", size); + Flags |= TYPE_Float; + if (size == 8) + { + if (sizeof(void*) == 4) + { + // Some ABIs for 32-bit platforms define alignment of double type as 4 bytes + // Intel POSIX (System V ABI) and PowerPC Macs are examples of those + struct AlignmentCheck { uint8_t i; double d; }; + Align = static_cast(offsetof(AlignmentCheck, d)); + } + + SetDoubleSymbols(); + } + else + { + assert(size == 4); + MemberOnly = true; + SetSingleSymbols(); + } + SetOps(); +} + +//========================================================================== +// +// PFloat :: SetDoubleSymbols +// +// Setup constant values for 64-bit floats. +// +//========================================================================== + +void PFloat::SetDoubleSymbols() +{ + static const SymbolInitF symf[] = + { + { NAME_Min_Normal, DBL_MIN }, + { NAME_Max, DBL_MAX }, + { NAME_Epsilon, DBL_EPSILON }, + { NAME_Equal_Epsilon, EQUAL_EPSILON }, + { NAME_NaN, std::numeric_limits::quiet_NaN() }, + { NAME_Infinity, std::numeric_limits::infinity() }, + { NAME_Min_Denormal, std::numeric_limits::denorm_min() } + }; + static const SymbolInitI symi[] = + { + { NAME_Dig, DBL_DIG }, + { NAME_Min_Exp, DBL_MIN_EXP }, + { NAME_Max_Exp, DBL_MAX_EXP }, + { NAME_Mant_Dig, DBL_MANT_DIG }, + { NAME_Min_10_Exp, DBL_MIN_10_EXP }, + { NAME_Max_10_Exp, DBL_MAX_10_EXP } + }; + SetSymbols(symf, countof(symf)); + SetSymbols(symi, countof(symi)); +} + +//========================================================================== +// +// PFloat :: SetSingleSymbols +// +// Setup constant values for 32-bit floats. +// +//========================================================================== + +void PFloat::SetSingleSymbols() +{ + static const SymbolInitF symf[] = + { + { NAME_Min_Normal, FLT_MIN }, + { NAME_Max, FLT_MAX }, + { NAME_Epsilon, FLT_EPSILON }, + { NAME_Equal_Epsilon, (float)EQUAL_EPSILON }, + { NAME_NaN, std::numeric_limits::quiet_NaN() }, + { NAME_Infinity, std::numeric_limits::infinity() }, + { NAME_Min_Denormal, std::numeric_limits::denorm_min() } + }; + static const SymbolInitI symi[] = + { + { NAME_Dig, FLT_DIG }, + { NAME_Min_Exp, FLT_MIN_EXP }, + { NAME_Max_Exp, FLT_MAX_EXP }, + { NAME_Mant_Dig, FLT_MANT_DIG }, + { NAME_Min_10_Exp, FLT_MIN_10_EXP }, + { NAME_Max_10_Exp, FLT_MAX_10_EXP } + }; + SetSymbols(symf, countof(symf)); + SetSymbols(symi, countof(symi)); +} + +//========================================================================== +// +// PFloat :: SetSymbols +// +//========================================================================== + +void PFloat::SetSymbols(const PFloat::SymbolInitF *sym, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Symbols.AddSymbol(Create(sym[i].Name, this, sym[i].Value)); + } +} + +void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Symbols.AddSymbol(Create(sym[i].Name, this, sym[i].Value)); + } +} + +//========================================================================== +// +// PFloat :: WriteValue +// +//========================================================================== + +void PFloat::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (Size == 8) + { + ar(key, *(double*)addr); + } + else + { + ar(key, *(float*)addr); + } +} + +//========================================================================== +// +// PFloat :: ReadValue +// +//========================================================================== + +bool PFloat::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + NumericValue val; + + ar(key, val); + if (val.type == NumericValue::NM_invalid) return false; // not found or usable + else if (val.type == NumericValue::NM_signed) val.floatval = (double)val.signedval; + else if (val.type == NumericValue::NM_unsigned) val.floatval = (double)val.unsignedval; + + if (Size == 8) + { + *(double*)addr = val.floatval; + } + else + { + *(float*)addr = (float)val.floatval; + } + return true; +} + +//========================================================================== +// +// PFloat :: SetValue +// +//========================================================================== + +void PFloat::SetValue(void *addr, int val) +{ + return SetValue(addr, (double)val); +} + +void PFloat::SetValue(void *addr, double val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + *(float *)addr = (float)val; + } + else + { + assert(Size == 8); + *(double *)addr = val; + } +} + +//========================================================================== +// +// PFloat :: GetValueInt +// +//========================================================================== + +int PFloat::GetValueInt(void *addr) const +{ + return int(GetValueFloat(addr)); +} + +//========================================================================== +// +// PFloat :: GetValueFloat +// +//========================================================================== + +double PFloat::GetValueFloat(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + return *(float *)addr; + } + else + { + assert(Size == 8); + return *(double *)addr; + } +} + +//========================================================================== +// +// PFloat :: GetStoreOp +// +//========================================================================== + +void PFloat::SetOps() +{ + if (Size == 4) + { + storeOp = OP_SSP; + loadOp = OP_LSP; + } + else + { + assert(Size == 8); + storeOp = OP_SDP; + loadOp = OP_LDP; + } + moveOp = OP_MOVEF; + RegType = REGT_FLOAT; +} + +/* PString ****************************************************************/ + +//========================================================================== +// +// PString Default Constructor +// +//========================================================================== + +PString::PString() +: PBasicType(sizeof(FString), alignof(FString)) +{ + mDescriptiveName = "String"; + storeOp = OP_SS; + loadOp = OP_LS; + moveOp = OP_MOVES; + RegType = REGT_STRING; + +} + +//========================================================================== +// +// PString :: WriteValue +// +//========================================================================== + +void PString::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + ar(key, *(FString*)addr); +} + +//========================================================================== +// +// PString :: ReadValue +// +//========================================================================== + +bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) + { + return false; + } + else + { + *(FString*)addr = cptr; + return true; + } +} + +//========================================================================== +// +// PString :: SetDefaultValue +// +//========================================================================== + +void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + if (base != nullptr) new((uint8_t *)base + offset) FString; + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } +} + +//========================================================================== +// +// PString :: InitializeValue +// +//========================================================================== + +void PString::InitializeValue(void *addr, const void *def) const +{ + if (def != nullptr) + { + new(addr) FString(*(FString *)def); + } + else + { + new(addr) FString; + } +} + +//========================================================================== +// +// PString :: DestroyValue +// +//========================================================================== + +void PString::DestroyValue(void *addr) const +{ + ((FString *)addr)->~FString(); +} + +/* PName ******************************************************************/ + +//========================================================================== +// +// PName Default Constructor +// +//========================================================================== + +PName::PName() +: PInt(sizeof(FName), true, false) +{ + mDescriptiveName = "Name"; + Flags |= TYPE_IntNotInt; + static_assert(sizeof(FName) == alignof(FName), "Name not properly aligned"); +} + +//========================================================================== +// +// PName :: WriteValue +// +//========================================================================== + +void PName::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + const char *cptr = ((const FName*)addr)->GetChars(); + ar.StringPtr(key, cptr); +} + +//========================================================================== +// +// PName :: ReadValue +// +//========================================================================== + +bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) + { + return false; + } + else + { + *(FName*)addr = FName(cptr); + return true; + } +} + +/* PStatePointer **********************************************************/ + +//========================================================================== +// +// PStatePointer Default Constructor +// +//========================================================================== + +PStatePointer::PStatePointer() +{ + mDescriptiveName = "Pointer"; + PointedType = NewStruct(NAME_State, nullptr, true); + IsConst = true; +} + +//========================================================================== +// +// PStatePointer :: WriteValue +// +//========================================================================== + +void PStatePointer::WriteValue(FSerializer& ar, const char* key, const void* addr) const +{ + ar.StatePointer(key, const_cast(addr), nullptr); +} + +//========================================================================== +// +// PStatePointer :: ReadValue +// +//========================================================================== + +bool PStatePointer::ReadValue(FSerializer& ar, const char* key, void* addr) const +{ + bool res = false; + ar.StatePointer(key, addr, &res); + return res; +} + + +/* PSpriteID ******************************************************************/ + +//========================================================================== +// +// PName Default Constructor +// +//========================================================================== + +PSpriteID::PSpriteID() + : PInt(sizeof(int), true, true) +{ + Flags |= TYPE_IntNotInt; + mDescriptiveName = "SpriteID"; +} + +//========================================================================== +// +// PName :: WriteValue +// +//========================================================================== + +void PSpriteID::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + int32_t val = *(int*)addr; + ar.Sprite(key, val, nullptr); +} + +//========================================================================== +// +// PName :: ReadValue +// +//========================================================================== + +bool PSpriteID::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + int32_t val = 0; + ar.Sprite(key, val, nullptr); + *(int*)addr = val; + return true; +} + +/* PTextureID ******************************************************************/ + +//========================================================================== +// +// PTextureID Default Constructor +// +//========================================================================== + +PTextureID::PTextureID() + : PInt(sizeof(FTextureID), true, false) +{ + mDescriptiveName = "TextureID"; + Flags |= TYPE_IntNotInt; + static_assert(sizeof(FTextureID) == alignof(FTextureID), "TextureID not properly aligned"); +} + +//========================================================================== +// +// PTextureID :: WriteValue +// +//========================================================================== + +void PTextureID::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + FTextureID val = *(FTextureID*)addr; + ar(key, val); +} + +//========================================================================== +// +// PTextureID :: ReadValue +// +//========================================================================== + +bool PTextureID::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FTextureID val; + ar(key, val); + *(FTextureID*)addr = val; + return true; +} + +/* PTranslationID ******************************************************************/ + +//========================================================================== +// +// PTranslationID Default Constructor +// +//========================================================================== + +PTranslationID::PTranslationID() + : PInt(sizeof(FTranslationID), true, false) +{ + mDescriptiveName = "TranslationID"; + Flags |= TYPE_IntNotInt; + static_assert(sizeof(FTranslationID) == alignof(FTranslationID), "TranslationID not properly aligned"); +} + +//========================================================================== +// +// PTranslationID :: WriteValue +// +//========================================================================== + +void PTranslationID::WriteValue(FSerializer& ar, const char* key, const void* addr) const +{ + FTranslationID val = *(FTranslationID*)addr; + ar(key, val); +} + +//========================================================================== +// +// PTranslationID :: ReadValue +// +//========================================================================== + +bool PTranslationID::ReadValue(FSerializer& ar, const char* key, void* addr) const +{ + FTranslationID val; + ar(key, val); + *(FTranslationID*)addr = val; + return true; +} + +/* PSound *****************************************************************/ + +//========================================================================== +// +// PSound Default Constructor +// +//========================================================================== + +PSound::PSound() +: PInt(sizeof(FSoundID), true) +{ + mDescriptiveName = "Sound"; + Flags |= TYPE_IntNotInt; + static_assert(sizeof(FSoundID) == alignof(FSoundID), "SoundID not properly aligned"); +} + +//========================================================================== +// +// PSound :: WriteValue +// +//========================================================================== + +void PSound::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + const char *cptr = soundEngine->GetSoundName(*(const FSoundID *)addr); + ar.StringPtr(key, cptr); +} + +//========================================================================== +// +// PSound :: ReadValue +// +//========================================================================== + +bool PSound::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) + { + return false; + } + else + { + *(FSoundID *)addr = S_FindSound(cptr); + return true; + } +} + +/* PColor *****************************************************************/ + +//========================================================================== +// +// PColor Default Constructor +// +//========================================================================== + +PColor::PColor() +: PInt(sizeof(PalEntry), true) +{ + mDescriptiveName = "Color"; + Flags |= TYPE_IntNotInt; + static_assert(sizeof(PalEntry) == alignof(PalEntry), "PalEntry not properly aligned"); +} + +/* PStateLabel *****************************************************************/ + +//========================================================================== +// +// PStateLabel Default Constructor +// +//========================================================================== + +PStateLabel::PStateLabel() + : PInt(sizeof(int), false, false) +{ + Flags |= TYPE_IntNotInt; + mDescriptiveName = "StateLabel"; +} + +/* PPointer ***************************************************************/ + +//========================================================================== +// +// PPointer - Default Constructor +// +//========================================================================== + +PPointer::PPointer() +: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) +{ + mDescriptiveName = "NullPointer"; + loadOp = OP_LP; + storeOp = OP_SP; + moveOp = OP_MOVEA; + RegType = REGT_POINTER; + Flags |= TYPE_Pointer; +} + +//========================================================================== +// +// PPointer - Parameterized Constructor +// +//========================================================================== + +PPointer::PPointer(PType *pointsat, bool isconst) +: PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) +{ + if (pointsat != nullptr) + { + mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst ? "readonly " : ""); + mVersion = pointsat->mVersion; + } + else + { + mDescriptiveName = "Pointer"; + mVersion = 0; + } + loadOp = OP_LP; + storeOp = OP_SP; + moveOp = OP_MOVEA; + RegType = REGT_POINTER; + Flags |= TYPE_Pointer; +} + +//========================================================================== +// +// PPointer :: IsMatch +// +//========================================================================== + +bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const +{ + assert(id2 == 0 || id2 == 1); + PType *pointat = (PType *)id1; + + return pointat == PointedType && (!!id2) == IsConst; +} + +//========================================================================== +// +// PPointer :: GetTypeIDs +// +//========================================================================== + +void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)PointedType; + id2 = 0; +} + +//========================================================================== +// +// PPointer :: WriteValue +// +//========================================================================== + +void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (writer != nullptr) + { + writer(ar, key, addr); + } + else + { + I_Error("Attempt to save pointer to unhandled type %s", PointedType->DescriptiveName()); + } +} + +//========================================================================== +// +// PPointer :: ReadValue +// +//========================================================================== + +bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + if (reader != nullptr) + { + return reader(ar, key, addr); + } + return false; +} + +/* PObjectPointer **********************************************************/ + +//========================================================================== +// +// PPointer :: GetStoreOp +// +//========================================================================== + +PObjectPointer::PObjectPointer(PClass *cls, bool isconst) + : PPointer(cls->VMType, isconst) +{ + loadOp = OP_LO; + Flags |= TYPE_ObjectPointer; + // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. + if (cls && !cls->IsDescendantOf(NAME_Thinker)) storeOp = OP_SO; +} + +//========================================================================== +// +// PPointer :: SetPointer +// +//========================================================================== + +void PObjectPointer::SetPointer(void *base, unsigned offset, TArray> *special) +{ + // Add to the list of pointers for this class. + special->Push({offset, this}); +} + +//========================================================================== +// +// PPointer :: WriteValue +// +//========================================================================== + +void PObjectPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(DObject **)addr); +} + +//========================================================================== +// +// PPointer :: ReadValue +// +//========================================================================== + +bool PObjectPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + bool res; + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + return res; +} + +//========================================================================== +// +// NewPointer +// +// Returns a PPointer to an object of the specified type +// +//========================================================================== + +PPointer *NewPointer(PType *type, bool isconst) +{ + auto cp = PType::toClass(type); + if (cp) return NewPointer(cp->Descriptor, isconst); + + size_t bucket; + PType *ptype = TypeTable.FindType(NAME_Pointer, (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) + { + ptype = new PPointer(type, isconst); + TypeTable.AddType(ptype, NAME_Pointer, (intptr_t)type, isconst ? 1 : 0, bucket); + } + return static_cast(ptype); +} + +PPointer *NewPointer(PClass *cls, bool isconst) +{ + assert(cls->VMType != nullptr); + + auto type = cls->VMType; + size_t bucket; + PType *ptype = TypeTable.FindType(NAME_Pointer, (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) + { + ptype = new PObjectPointer(cls, isconst); + TypeTable.AddType(ptype, NAME_Pointer, (intptr_t)type, isconst ? 1 : 0, bucket); + } + return static_cast(ptype); +} + + + +/* PClassPointer **********************************************************/ + +//========================================================================== +// +// PClassPointer - Parameterized Constructor +// +//========================================================================== + +PClassPointer::PClassPointer(PClass *restrict) +: PPointer(restrict->VMType), ClassRestriction(restrict) +{ + if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); + else mDescriptiveName = "ClassPointer"; + loadOp = OP_LP; + storeOp = OP_SP; + Flags |= TYPE_ClassPointer; + if (restrict) mVersion = restrict->VMType->mVersion; + else mVersion = 0; +} + +//========================================================================== +// +// PPointer :: WriteValue +// +//========================================================================== + +void PClassPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(PClass **)addr); +} + +//========================================================================== +// +// PPointer :: ReadValue +// +//========================================================================== + +bool PClassPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); + return false; +} + +//========================================================================== +// +// PClassPointer - isCompatible +// +//========================================================================== + +bool PClassPointer::isCompatible(PType *type) +{ + auto other = PType::toClassPointer(type); + return (other != nullptr && other->ClassRestriction->IsDescendantOf(ClassRestriction)); +} + +//========================================================================== +// +// PClassPointer :: SetPointer +// +//========================================================================== + +void PClassPointer::SetPointer(void *base, unsigned offset, TArray> *special) +{ +} + +//========================================================================== +// +// PClassPointer :: IsMatch +// +//========================================================================== + +bool PClassPointer::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PClass *classat = (const PClass *)id2; + return classat == ClassRestriction; +} + +//========================================================================== +// +// PClassPointer :: GetTypeIDs +// +//========================================================================== + +void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = 0; + id2 = (intptr_t)ClassRestriction; +} + +//========================================================================== +// +// NewClassPointer +// +// Returns a PClassPointer for the restricted type. +// +//========================================================================== + +PClassPointer *NewClassPointer(PClass *restrict) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(NAME_Class, 0, (intptr_t)restrict, &bucket); + if (ptype == nullptr) + { + ptype = new PClassPointer(restrict); + TypeTable.AddType(ptype, NAME_Class, 0, (intptr_t)restrict, bucket); + } + return static_cast(ptype); +} + +/* PEnum ******************************************************************/ + +//========================================================================== +// +// PEnum - Parameterized Constructor +// +//========================================================================== + +PEnum::PEnum(FName name, PTypeBase *outer) +: PInt(4, false), Outer(outer), EnumName(name) +{ + Flags |= TYPE_IntNotInt; + mDescriptiveName.Format("Enum<%s>", name.GetChars()); +} + +//========================================================================== +// +// NewEnum +// +// Returns a PEnum for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PEnum *NewEnum(FName name, PTypeBase *outer) +{ + size_t bucket; + if (outer == nullptr) outer = Namespaces.GlobalNamespace; + PType *etype = TypeTable.FindType(NAME_Enum, (intptr_t)outer, name.GetIndex(), &bucket); + if (etype == nullptr) + { + etype = new PEnum(name, outer); + TypeTable.AddType(etype, NAME_Enum, (intptr_t)outer, name.GetIndex(), bucket); + } + return static_cast(etype); +} + +/* PArray *****************************************************************/ + +//========================================================================== +// +// PArray - Parameterized Constructor +// +//========================================================================== + +PArray::PArray(PType *etype, unsigned int ecount) +: ElementType(etype), ElementCount(ecount) +{ + mDescriptiveName.Format("Array<%s>[%d]", etype->DescriptiveName(), ecount); + + Align = etype->Align; + // Since we are concatenating elements together, the element size should + // also be padded to the nearest alignment. + ElementSize = (etype->Size + (etype->Align - 1)) & ~(etype->Align - 1); + Size = ElementSize * ecount; + Flags |= TYPE_Array; +} + +//========================================================================== +// +// PArray :: IsMatch +// +//========================================================================== + +bool PArray::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *elemtype = (const PType *)id1; + unsigned int count = (unsigned int)(intptr_t)id2; + + return elemtype == ElementType && count == ElementCount; +} + +//========================================================================== +// +// PArray :: GetTypeIDs +// +//========================================================================== + +void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)ElementType; + id2 = ElementCount; +} + +//========================================================================== +// +// PArray :: WriteValue +// +//========================================================================== + +void PArray::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (ar.BeginArray(key)) + { + const uint8_t *addrb = (const uint8_t *)addr; + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->WriteValue(ar, nullptr, addrb); + addrb += ElementSize; + } + ar.EndArray(); + } +} + +//========================================================================== +// +// PArray :: ReadValue +// +//========================================================================== + +bool PArray::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + if (ar.BeginArray(key)) + { + bool readsomething = false; + unsigned count = ar.ArraySize(); + unsigned loop = min(count, ElementCount); + uint8_t *addrb = (uint8_t *)addr; + for(unsigned i=0;iReadValue(ar, nullptr, addrb); + addrb += ElementSize; + } + if (loop < count) + { + DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n", + count, ElementCount); + } + ar.EndArray(); + return readsomething; + } + return false; +} + +//========================================================================== +// +// PArray :: SetDefaultValue +// +//========================================================================== + +void PArray::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->SetDefaultValue(base, offset + i*ElementSize, special); + } +} + +//========================================================================== +// +// PArray :: SetDefaultValue +// +//========================================================================== + +void PArray::SetPointer(void *base, unsigned offset, TArray> *special) +{ + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->SetPointer(base, offset + i*ElementSize, special); + } +} + +//========================================================================== +// +// PArray :: SetPointerArray +// +//========================================================================== + +void PArray::SetPointerArray(void *base, unsigned offset, TArray> *special) +{ + if (ElementType->isStruct() || ElementType->isDynArray()) + { + for (unsigned int i = 0; i < ElementCount; ++i) + { + ElementType->SetPointerArray(base, offset + ElementSize * i, special); + } + } +} + +//========================================================================== +// +// PArray :: SetPointerMap +// +//========================================================================== + +void PArray::SetPointerMap(void *base, unsigned offset, TArray> *special) +{ + if(ElementType->isStruct() || ElementType->isMap()) + { + for (unsigned int i = 0; i < ElementCount; ++i) + { + ElementType->SetPointerMap(base, offset + ElementSize * i, special); + } + } +} + +//========================================================================== +// +// NewArray +// +// Returns a PArray for the given type and size, making sure not to create +// duplicates. +// +//========================================================================== + +PArray *NewArray(PType *type, unsigned int count) +{ + size_t bucket; + PType *atype = TypeTable.FindType(NAME_Array, (intptr_t)type, count, &bucket); + if (atype == nullptr) + { + atype = new PArray(type, count); + TypeTable.AddType(atype, NAME_Array, (intptr_t)type, count, bucket); + } + return (PArray *)atype; +} + +/* PArray *****************************************************************/ + +//========================================================================== +// +// PArray - Parameterized Constructor +// +//========================================================================== + +PStaticArray::PStaticArray(PType *etype) + : PArray(etype, 0) +{ + mDescriptiveName.Format("ResizableArray<%s>", etype->DescriptiveName()); +} + +//========================================================================== +// +// PArray :: IsMatch +// +//========================================================================== + +bool PStaticArray::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *elemtype = (const PType *)id1; + unsigned int count = (unsigned int)(intptr_t)id2; + + return elemtype == ElementType && count == 0; +} + +//========================================================================== +// +// PArray :: GetTypeIDs +// +//========================================================================== + +void PStaticArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)ElementType; + id2 = 0; +} + +//========================================================================== +// +// NewStaticArray +// +// Returns a PArray for the given type and size, making sure not to create +// duplicates. +// +//========================================================================== + +PStaticArray *NewStaticArray(PType *type) +{ + size_t bucket; + PType *atype = TypeTable.FindType(NAME_StaticArray, (intptr_t)type, 0, &bucket); + if (atype == nullptr) + { + atype = new PStaticArray(type); + TypeTable.AddType(atype, NAME_StaticArray, (intptr_t)type, 0, bucket); + } + return (PStaticArray *)atype; +} + +/* PDynArray **************************************************************/ + +//========================================================================== +// +// PDynArray - Parameterized Constructor +// +//========================================================================== + +enum OverrideFunctionRetType { + OFN_RET_VOID, + OFN_RET_VAL, + OFN_RET_KEY, + OFN_RET_BOOL, + OFN_RET_VAL_BOOL, + OFN_RET_INT, +}; +enum OverrideFunctionArgType { + OFN_ARG_VOID, + OFN_ARG_KEY, + OFN_ARG_VAL, + OFN_ARG_KEY_VAL, + OFN_ARG_ELEM, + OFN_ARG_INT_ELEM, +}; + +template +void CreateOverrideFunction(MT *self, FName name) +{ + auto Fn = Create(self->BackingType, name); + auto NativeFn = FindFunction(self->BackingType, name.GetChars()); + + assert(NativeFn); + assert(NativeFn->VMPointer); + + TArray ret; + TArray args; + TArray argflags; + TArray argnames; + + if constexpr(RetType == OFN_RET_VAL) + { + ret.Push(self->ValueType); + } + else if constexpr(RetType == OFN_RET_KEY) + { + ret.Push(self->KeyType); + } + else if constexpr(RetType == OFN_RET_BOOL) + { + ret.Push(TypeBool); + } + else if constexpr(RetType == OFN_RET_VAL_BOOL) + { + ret.Push(self->ValueType); + ret.Push(TypeBool); + } + else if constexpr(RetType == OFN_RET_INT) + { + ret.Push(TypeSInt32); + } + + args.Push(NewPointer(self->BackingType)); + argnames.Push(NAME_self); + argflags.Push(VARF_Implicit | VARF_ReadOnly); + + if constexpr(ArgType == OFN_ARG_KEY) + { + args.Push(self->KeyType); + argflags.Push(0); + argnames.Push(NAME_Key); + } + else if constexpr(ArgType == OFN_ARG_VAL) + { + + args.Push(self->ValueType); + argflags.Push(0); + argnames.Push(NAME_Value); + } + else if constexpr(ArgType == OFN_ARG_KEY_VAL) + { + args.Push(self->KeyType); + args.Push(self->ValueType); + argflags.Push(0); + argflags.Push(0); + argnames.Push(NAME_Key); + argnames.Push(NAME_Value); + } + else if constexpr(ArgType == OFN_ARG_ELEM) + { + args.Push(self->ElementType); + argflags.Push(0); + argnames.Push(NAME_Item); + } + else if constexpr(ArgType == OFN_ARG_INT_ELEM) + { + args.Push(TypeSInt32); + args.Push(self->ElementType); + argflags.Push(0); + argflags.Push(0); + argnames.Push(NAME_Index); + argnames.Push(NAME_Item); + } + + Fn->AddVariant(NewPrototype(ret, args), argflags, argnames, *NativeFn->VMPointer, VARF_Method | VARF_Native | ExtraFlags, SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM); + self->FnOverrides.Insert(name, Fn); +} + +PDynArray::PDynArray(PType *etype,PStruct *backing) +: ElementType(etype), BackingType(backing) +{ + mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); + Size = sizeof(FArray); + Align = alignof(FArray); + CreateOverrideFunction (this, NAME_Find); + CreateOverrideFunction (this, NAME_Push); + CreateOverrideFunction (this, NAME_Insert); +} + +//========================================================================== +// +// PDynArray :: IsMatch +// +//========================================================================== + +bool PDynArray::IsMatch(intptr_t id1, intptr_t id2) const +{ + assert(id2 == 0); + const PType *elemtype = (const PType *)id1; + + return elemtype == ElementType; +} + +//========================================================================== +// +// PDynArray :: GetTypeIDs +// +//========================================================================== + +void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)ElementType; + id2 = 0; +} + +//========================================================================== +// +// PDynArray :: InitializeValue +// +//========================================================================== + +void PDynArray::InitializeValue(void *addr, const void *deff) const +{ + const FArray *def = (const FArray*)deff; + FArray *aray = (FArray*)addr; + + if (def == nullptr || def->Count == 0) + { + // Empty arrays do not need construction. + *aray = { nullptr, 0, 0 }; + } + else if (ElementType->GetRegType() != REGT_STRING) + { + // These are just integral values which can be done without any constructor hackery. + size_t blocksize = ElementType->Size * def->Count; + aray->Array = M_Malloc(blocksize); + memcpy(aray->Array, def->Array, blocksize); + aray->Most = aray->Count = def->Count; + } + else + { + // non-empty string arrays require explicit construction. + new(addr) TArray(*(TArray*)def); + } +} + +//========================================================================== +// +// PDynArray :: DestroyValue +// +//========================================================================== + +void PDynArray::DestroyValue(void *addr) const +{ + FArray *aray = (FArray*)addr; + + if (aray->Array != nullptr) + { + if (ElementType->GetRegType() != REGT_STRING) + { + M_Free(aray->Array); + } + else + { + // Damn those cursed strings again. :( + ((TArray*)addr)->~TArray(); + } + } + aray->Count = aray->Most = 0; + aray->Array = nullptr; +} + +//========================================================================== +// +// PDynArray :: SetDefaultValue +// +//========================================================================== + +void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + if (base != nullptr) memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array. + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } +} + +//========================================================================== +// +// PDynArray :: SetPointer +// +//========================================================================== + +void PDynArray::SetPointerArray(void *base, unsigned offset, TArray> *special) +{ + if (ElementType->isObjectPointer()) + { + // Add to the list of pointer arrays for this class. + special->Push({offset, this}); + } +} + +//========================================================================== +// +// PDynArray :: WriteValue +// +//========================================================================== + +void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + FArray *aray = (FArray*)addr; + // We may skip an empty array only if it gets stored under a named key. + // If no name is given, i.e. it's part of an outer array's element list, even empty arrays must be stored, + // because otherwise the array would lose its entry. + if (aray->Count > 0 || key == nullptr) + { + if (ar.BeginArray(key)) + { + const uint8_t *addrb = (const uint8_t *)aray->Array; + for (unsigned i = 0; i < aray->Count; ++i) + { + ElementType->WriteValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + } + } +} + +//========================================================================== +// +// PDynArray :: ReadValue +// +//========================================================================== + +bool PDynArray::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FArray *aray = (FArray*)addr; + DestroyValue(addr); // note that even after calling this we still got a validly constructed empty array. + + if (ar.BeginArray(key)) + { + bool readsomething = false; + unsigned count = ar.ArraySize(); + + size_t blocksize = ElementType->Size * count; + aray->Array = M_Malloc(blocksize); + memset(aray->Array, 0, blocksize); + aray->Most = aray->Count = count; + + uint8_t *addrb = (uint8_t *)aray->Array; + for (unsigned i = 0; iGetRegType() == REGT_STRING) new(addrb) FString; + readsomething |= ElementType->ReadValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + return readsomething; + } + return false; +} + +//========================================================================== +// +// NewDynArray +// +// Creates a new DynArray of the given type, making sure not to create a +// duplicate. +// +//========================================================================== + +PDynArray *NewDynArray(PType *type) +{ + size_t bucket; + PType *atype = TypeTable.FindType(NAME_DynArray, (intptr_t)type, 0, &bucket); + if (atype == nullptr) + { + FString backingname; + + switch (type->GetRegType()) + { + case REGT_INT: + backingname.Format("DynArray_I%d", type->Size * 8); + break; + + case REGT_FLOAT: + backingname.Format("DynArray_F%d", type->Size * 8); + break; + + case REGT_STRING: + backingname = "DynArray_String"; + break; + + case REGT_POINTER: + if (type->isObjectPointer()) + backingname = "DynArray_Obj"; + else + backingname = "DynArray_Ptr"; + break; + + default: + I_Error("Unsupported dynamic array requested"); + break; + } + + auto backing = NewStruct(backingname, nullptr, true); + atype = new PDynArray(type, backing); + TypeTable.AddType(atype, NAME_DynArray, (intptr_t)type, 0, bucket); + } + return (PDynArray *)atype; +} + +/* PMap *******************************************************************/ + +//========================================================================== +// +// PMap - Parameterized Constructor +// +//========================================================================== + +PMap::PMap(PType *keytype, PType *valtype, PStruct *backing, int backing_class) +: KeyType(keytype), ValueType(valtype), BackingType(backing), BackingClass((decltype(BackingClass)) backing_class) +{ + mDescriptiveName.Format("Map<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName()); + Size = sizeof(ZSFMap); + Align = alignof(ZSFMap); + CreateOverrideFunction< OFN_RET_VAL , OFN_ARG_KEY > (this, NAME_Get); + CreateOverrideFunction< OFN_RET_VAL , OFN_ARG_KEY , VARF_ReadOnly> (this, NAME_GetIfExists); + CreateOverrideFunction< OFN_RET_BOOL , OFN_ARG_KEY , VARF_ReadOnly> (this, NAME_CheckKey); + CreateOverrideFunction< OFN_RET_VAL_BOOL , OFN_ARG_KEY , VARF_ReadOnly> (this, NAME_CheckValue); + CreateOverrideFunction< OFN_RET_VOID , OFN_ARG_KEY_VAL > (this, NAME_Insert); + CreateOverrideFunction< OFN_RET_VOID , OFN_ARG_KEY > (this, NAME_InsertNew); + CreateOverrideFunction< OFN_RET_VOID , OFN_ARG_KEY > (this, NAME_Remove); +} + +//========================================================================== +// +// PMap :: IsMatch +// +//========================================================================== + +bool PMap::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *keyty = (const PType *)id1; + const PType *valty = (const PType *)id2; + + return keyty == KeyType && valty == ValueType; +} + +//========================================================================== +// +// PMap :: GetTypeIDs +// +//========================================================================== + +void PMap::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)KeyType; + id2 = (intptr_t)ValueType; +} + +//========================================================================== +// +// PMap :: InitializeValue +// +//========================================================================== + +#define FOR_EACH_MAP_TYPE(FN) \ + case PMap::MAP_I32_I8: \ + FN( uint32_t , uint8_t ) \ + case PMap::MAP_I32_I16: \ + FN( uint32_t , uint16_t ) \ + case PMap::MAP_I32_I32: \ + FN( uint32_t , uint32_t ) \ + case PMap::MAP_I32_F32: \ + FN( uint32_t , float ) \ + case PMap::MAP_I32_F64: \ + FN( uint32_t , double ) \ + case PMap::MAP_I32_OBJ: \ + FN( uint32_t , DObject* ) \ + case PMap::MAP_I32_PTR: \ + FN( uint32_t , void* ) \ + case PMap::MAP_I32_STR: \ + FN( uint32_t , FString ) \ + case PMap::MAP_STR_I8: \ + FN( FString , uint8_t ) \ + case PMap::MAP_STR_I16: \ + FN( FString , uint16_t ) \ + case PMap::MAP_STR_I32: \ + FN( FString , uint32_t ) \ + case PMap::MAP_STR_F32: \ + FN( FString , float ) \ + case PMap::MAP_STR_F64: \ + FN( FString , double ) \ + case PMap::MAP_STR_OBJ: \ + FN( FString , DObject* ) \ + case PMap::MAP_STR_PTR: \ + FN( FString , void* ) \ + case PMap::MAP_STR_STR: \ + FN( FString , FString ) + +void PMap::Construct(void * addr) const { + switch(BackingClass) + { + #define MAP_CONSTRUCT(KT, VT) new(addr) ZSMap< KT, VT >(); break; + FOR_EACH_MAP_TYPE(MAP_CONSTRUCT) + #undef MAP_CONSTRUCT + }; +} + + +void PMap::InitializeValue(void *addr, const void *def) const +{ + Construct(addr); +} + +//========================================================================== +// +// PMap :: DestroyValue +// +//========================================================================== + +void PMap::DestroyValue(void *addr) const +{ + switch(BackingClass) + { + #define MAP_DESTRUCT(KT, VT) static_cast*>(addr)->~ZSMap(); break; + FOR_EACH_MAP_TYPE(MAP_DESTRUCT) + #undef MAP_DESTRUCT + } +} + +//========================================================================== +// +// PMap :: SetDefaultValue +// +//========================================================================== + +void PMap::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + if (base != nullptr) + { + Construct(((uint8_t*)base)+offset); // is this needed? string/dynarray do this initialization if base != nullptr, but their initialization doesn't need to allocate + // it might lead to double allocations (and memory leakage) for Map if both base and special != nullptr + } + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } + else + { + I_Error("null special"); + } +} + +//========================================================================== +// +// PMap :: SetPointer +// +//========================================================================== + +void PMap::SetPointerMap(void *base, unsigned offset, TArray> *special) +{ + if (ValueType->isObjectPointer()) + { + // Add to the list of pointer arrays for this class. + special->Push(std::make_pair(offset, this)); + } +} + +//========================================================================== +// +// PMap :: WriteValue +// +//========================================================================== + +template +static void PMapValueWriter(FSerializer &ar, const M *map, const PMap *m) +{ + TMapConstIterator it(*map); + const typename M::Pair * p; + while(it.NextPair(p)) + { + if constexpr(std::is_same_v) + { + m->ValueType->WriteValue(ar,p->Key.GetChars(),static_cast(&p->Value)); + } + else if constexpr(std::is_same_v) + { + if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/) + { + if(m->KeyType == TypeName) + { + m->ValueType->WriteValue(ar,FName(ENamedName(p->Key)).GetChars(),static_cast(&p->Value)); + } + else if(m->KeyType == TypeSound) + { + m->ValueType->WriteValue(ar,soundEngine->GetSoundName(FSoundID::fromInt(p->Key)),static_cast(&p->Value)); + } + else if(m->KeyType == TypeTextureID) + { + if(!!(p->Key & 0x8000000)) + { // invalid + m->ValueType->WriteValue(ar,"invalid",static_cast(&p->Value)); + } + else if(p->Key == 0 || p->Key >= (unsigned)TexMan.NumTextures()) + { // null + m->ValueType->WriteValue(ar,"null",static_cast(&p->Value)); + } + else + { + FTextureID tid; + tid.SetIndex(p->Key); + FGameTexture *tex = TexMan.GetGameTexture(tid); + int lump = tex->GetSourceLump(); + unsigned useType = static_cast(tex->GetUseType()); + + FString name; + + if (TexMan.GetLinkedTexture(lump) == tex) + { + name = fileSystem.GetFileFullName(lump); + } + else + { + name = tex->GetName().GetChars(); + } + + name.AppendFormat(":%u",useType); + + m->ValueType->WriteValue(ar,name.GetChars(),static_cast(&p->Value)); + } + } + else + { // bool/color/enum/sprite/translationID + FString key; + key.Format("%u",p->Key); + m->ValueType->WriteValue(ar,key.GetChars(),static_cast(&p->Value)); + } + } + else + { + FString key; + key.Format("%u",p->Key); + m->ValueType->WriteValue(ar,key.GetChars(),static_cast(&p->Value)); + } + } + //else unknown key type + } +} + +void PMap::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + if(ar.BeginObject(key)) + { + switch(BackingClass) + { + #define MAP_WRITE(KT, VT) PMapValueWriter(ar, static_cast*>(addr), this); break; + FOR_EACH_MAP_TYPE(MAP_WRITE) + #undef MAP_WRITE + } + ar.EndObject(); + } +} + +//========================================================================== +// +// PMap :: ReadValue +// +//========================================================================== + + +template +static bool PMapValueReader(FSerializer &ar, M *map, const PMap *m) +{ + const char * k; + while((k = ar.GetKey())) + { + typename M::ValueType * val = nullptr; + if constexpr(std::is_same_v) + { + val = &map->InsertNew(k); + } + else if constexpr(std::is_same_v) + { + if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/) + { + if(m->KeyType == TypeName) + { + val = &map->InsertNew(FName(k).GetIndex()); + } + else if(m->KeyType == TypeSound) + { + val = &map->InsertNew(S_FindSound(k).index()); + } + else if(m->KeyType == TypeTextureID) + { + FString s(k); + FTextureID tex; + if(s.Compare("invalid") == 0) + { + tex.SetInvalid(); + } + else if(s.Compare("null") == 0) + { + tex.SetNull(); + } + else + { + ptrdiff_t sep = s.LastIndexOf(":"); + if(sep < 0) + { + ar.EndObject(); + return false; + } + FString texName = s.Left(sep); + FString useType = s.Mid(sep + 1); + + tex = TexMan.GetTextureID(texName.GetChars(), (ETextureType) useType.ToULong()); + } + val = &map->InsertNew(tex.GetIndex()); + } + else if(m->KeyType == TypeTranslationID) + { + FString s(k); + if(!s.IsInt()) + { + ar.EndObject(); + return false; + } + int v = (int)s.ToULong(); + + if (sysCallbacks.RemapTranslation) v = sysCallbacks.RemapTranslation(FTranslationID::fromInt(v)).index(); + + val = &map->InsertNew(v); + } + else + { // bool/color/enum/sprite + FString s(k); + if(!s.IsInt()) + { + ar.EndObject(); + return false; + } + val = &map->InsertNew(static_cast(s.ToULong())); + } + } + else + { + FString s(k); + if(!s.IsInt()) + { + ar.EndObject(); + return false; + } + val = &map->InsertNew(static_cast(s.ToULong())); + } + } + if (!m->ValueType->ReadValue(ar,nullptr,static_cast(val))) + { + ar.EndObject(); + return false; + } + } + ar.EndObject(); + return true; +} + + +bool PMap::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + DestroyValue(addr); + InitializeValue(addr, nullptr); + if(ar.BeginObject(key)) + { + switch(BackingClass) + { + #define MAP_READ(KT, VT) return PMapValueReader(ar, static_cast*>(addr), this); + FOR_EACH_MAP_TYPE(MAP_READ) + #undef MAP_READ + } + } + return false; +} + +//========================================================================== +// +// NewMap +// +// Returns a PMap for the given key and value types, ensuring not to create +// duplicates. +// +//========================================================================== + +int PMapBackingClass(PType *keytype, PType *valuetype, FString &backingName) { + int backingClass; + auto key_rtype = keytype->GetRegType(); + auto value_rtype = valuetype->GetRegType(); + if (key_rtype == REGT_INT) + { + if(keytype->Size != 4) + { + I_Error("Unsupported map requested"); + } + else + { + backingName += "I32_"; + backingClass = PMap::MAP_I32_I8; + } + } + else if (key_rtype == REGT_STRING) + { + backingName += "Str_"; + backingClass = PMap::MAP_STR_I8; + } + else + { + I_Error("Unsupported map requested"); + } + switch (valuetype->GetRegType()) + { + case REGT_INT: + backingName.AppendFormat("I%d", valuetype->Size * 8); + backingClass += (valuetype->Size >> 1); + break; + case REGT_FLOAT: + backingName.AppendFormat("F%d", valuetype->Size * 8); + backingClass += PMap::MAP_I32_F32 + (valuetype->Size == 8); + break; + case REGT_STRING: + backingName += "Str"; + backingClass += PMap::MAP_I32_STR; + break; + + case REGT_POINTER: + if (valuetype->isObjectPointer()) + { + backingName += "Obj"; + backingClass += PMap::MAP_I32_OBJ; + } + else + { + backingName += "Ptr"; + backingClass += PMap::MAP_I32_PTR; + } + break; + default: + I_Error("Unsupported map requested"); + break; + } + return backingClass; +} + +PMap *NewMap(PType *keyType, PType *valueType) +{ + size_t bucket; + PType *mapType = TypeTable.FindType(NAME_Map, (intptr_t)keyType, (intptr_t)valueType, &bucket); + if (mapType == nullptr) + { + FString backingName = "Map_"; + int backingClass = PMapBackingClass(keyType, valueType, backingName); + + auto backing = NewStruct(backingName, nullptr, true); + mapType = new PMap(keyType, valueType, backing, backingClass); + TypeTable.AddType(mapType, NAME_Map, (intptr_t)keyType, (intptr_t)valueType, bucket); + + } + return (PMap *)mapType; +} + +/* PMapIterator ***********************************************************/ + +//========================================================================== +// +// PMapIterator - Parameterized Constructor +// +//========================================================================== + +PMapIterator::PMapIterator(PType *keytype, PType *valtype, PStruct *backing, int backing_class) + : KeyType(keytype), ValueType(valtype), BackingType(backing), BackingClass((decltype(BackingClass)) backing_class) +{ + mDescriptiveName.Format("MapIterator<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName()); + Size = sizeof(ZSFMap); + Align = alignof(ZSFMap); + CreateOverrideFunction(this, NAME_GetKey); + CreateOverrideFunction(this, NAME_GetValue); + CreateOverrideFunction(this, NAME_SetValue); +} + +//========================================================================== +// +// PMapIterator :: IsMatch +// +//========================================================================== + +bool PMapIterator::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *keyty = (const PType *)id1; + const PType *valty = (const PType *)id2; + + return keyty == KeyType && valty == ValueType; +} + +//========================================================================== +// +// PMapIterator :: GetTypeIDs +// +//========================================================================== + +void PMapIterator::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)KeyType; + id2 = (intptr_t)ValueType; +} + +//========================================================================== +// +// PMapIterator :: InitializeValue +// +//========================================================================== + +void PMapIterator::Construct(void * addr) const { + switch(BackingClass) + { + #define MAP_IT_CONSTRUCT(KT, VT) new(addr) ZSMapIterator< KT, VT >(); break; + FOR_EACH_MAP_TYPE(MAP_IT_CONSTRUCT) + #undef MAP_IT_CONSTRUCT + }; +} + +void PMapIterator::InitializeValue(void *addr, const void *def) const +{ + Construct(addr); +} + +//========================================================================== +// +// PMapIterator :: DestroyValue +// +//========================================================================== + +void PMapIterator::DestroyValue(void *addr) const +{ + switch(BackingClass) + { + #define MAP_IT_DESTROY(KT, VT) static_cast*>(addr)->~ZSMapIterator(); break; + FOR_EACH_MAP_TYPE(MAP_IT_DESTROY) + #undef MAP_IT_DESTROY + } +} + +//========================================================================== +// +// PMapIterator :: SetDefaultValue +// +//========================================================================== + +void PMapIterator::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + if (base != nullptr) + { + Construct(((uint8_t*)base)+offset); + } + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } + else + { + I_Error("null special"); + } +} + +//========================================================================== +// +// PMapIterator :: WriteValue +// +//========================================================================== + +void PMapIterator::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar.BeginObject(key); + ar.EndObject(); +} + +//========================================================================== +// +// PMapIterator :: ReadValue +// +//========================================================================== + +bool PMapIterator::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + DestroyValue(addr); + InitializeValue(addr, nullptr); + ar.BeginObject(key); + ar.EndObject(); + return true; +} + +//========================================================================== +// +// NewMapIterator +// +// Returns a PMapIterator for the given key and value types, ensuring not to create +// duplicates. +// +//========================================================================== + +PMapIterator *NewMapIterator(PType *keyType, PType *valueType) +{ + size_t bucket; + PType *mapIteratorType = TypeTable.FindType(NAME_MapIterator, (intptr_t)keyType, (intptr_t)valueType, &bucket); + if (mapIteratorType == nullptr) + { + FString backingName = "MapIterator_"; + int backingClass = PMapBackingClass(keyType, valueType, backingName); + + auto backing = NewStruct(backingName, nullptr, true); + mapIteratorType = new PMapIterator(keyType, valueType, backing, backingClass); + TypeTable.AddType(mapIteratorType, NAME_MapIterator, (intptr_t)keyType, (intptr_t)valueType, bucket); + } + return (PMapIterator *)mapIteratorType; +} + +/* PFunctionPointer *******************************************************/ + +//========================================================================== +// +// PFunctionPointer - Parameterized Constructor +// +//========================================================================== + +static FString MakeFunctionPointerDescriptiveName(PPrototype * proto,const TArray &ArgFlags, int scope) +{ + FString mDescriptiveName; + + mDescriptiveName = "Function<"; + switch(scope) + { + case FScopeBarrier::Side_PlainData: + mDescriptiveName += "clearscope "; + break; + case FScopeBarrier::Side_Play: + mDescriptiveName += "play "; + break; + case FScopeBarrier::Side_UI: + mDescriptiveName += "ui "; + break; + } + if(proto->ReturnTypes.Size() > 0) + { + mDescriptiveName += proto->ReturnTypes[0]->DescriptiveName(); + + const unsigned n = proto->ReturnTypes.Size(); + for(unsigned i = 1; i < n; i++) + { + mDescriptiveName += ", "; + mDescriptiveName += proto->ReturnTypes[i]->DescriptiveName(); + } + mDescriptiveName += " ("; + } + else + { + mDescriptiveName += "void ("; + } + if(proto->ArgumentTypes.Size() > 0) + { + if(ArgFlags[0] == VARF_Out) mDescriptiveName += "out "; + mDescriptiveName += proto->ArgumentTypes[0]->DescriptiveName(); + const unsigned n = proto->ArgumentTypes.Size(); + for(unsigned i = 1; i < n; i++) + { + mDescriptiveName += ", "; + if(ArgFlags[i] == VARF_Out) mDescriptiveName += "out "; + mDescriptiveName += proto->ArgumentTypes[i]->DescriptiveName(); + } + mDescriptiveName += ")>"; + } + else + { + mDescriptiveName += "void)>"; + } + + return mDescriptiveName; +} + + +FString PFunctionPointer::GenerateNameForError(const PFunction * from) +{ + return MakeFunctionPointerDescriptiveName(from->Variants[0].Proto, from->Variants[0].ArgFlags, FScopeBarrier::SideFromFlags(from->Variants[0].Flags)); +} + +PFunctionPointer::PFunctionPointer(PPrototype * proto, TArray && argflags, int scope) + : PPointer(proto ? (PType*) proto : TypeVoid, false), ArgFlags(std::move(argflags)), Scope(scope) +{ + if(!proto) + { + mDescriptiveName = "Function"; + } + else + { + mDescriptiveName = MakeFunctionPointerDescriptiveName(proto, ArgFlags, scope); + } + + Flags |= TYPE_FunctionPointer; + + if(proto) + { + assert(Scope != -1); // for now, a scope is always required + + TArray ArgNames; + TArray ArgFlags2(ArgFlags); // AddVariant calls std::move on this, so it needs to be a copy, + // but it takes it as a regular reference, so it needs to be a full variable instead of a temporary + ArgNames.Resize(ArgFlags.Size()); + FakeFunction = Create(); + FakeFunction->AddVariant(proto, ArgFlags2, ArgNames, nullptr, FScopeBarrier::FlagsFromSide(Scope), 0); + } + else + { + FakeFunction = nullptr; + } +} + +void PFunctionPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + auto p = *(const PFunction**)(addr); + if(p) + { + FunctionPointerValue val; + FunctionPointerValue *fpv = &val; + val.ClassName = FString((p->OwningClass ? p->OwningClass->TypeName : NAME_None).GetChars()); + val.FunctionName = FString(p->SymbolName.GetChars()); + SerializeFunctionPointer(ar, key, fpv); + } + else + { + FunctionPointerValue *fpv = nullptr; + SerializeFunctionPointer(ar, key, fpv); + } +} + +PFunction *NativeFunctionPointerCast(PFunction *from, const PFunctionPointer *to); + +bool PFunctionPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FunctionPointerValue val; + FunctionPointerValue *fpv = &val; + SerializeFunctionPointer(ar, key, fpv); + + PFunction ** fn = (PFunction**)(addr); + + if(fpv) + { + auto cls = PClass::FindClass(val.ClassName); + if(!cls) + { + *fn = nullptr; + Printf(TEXTCOLOR_RED "Function Pointer ('%s::%s'): '%s' is not a valid class\n", + val.ClassName.GetChars(), + val.FunctionName.GetChars(), + val.ClassName.GetChars() + ); + ar.mErrors++; + return false; + } + auto sym = cls->FindSymbol(FName(val.FunctionName), true); + if(!sym) + { + *fn = nullptr; + Printf(TEXTCOLOR_RED "Function Pointer ('%s::%s'): symbol '%s' does not exist in class '%s'\n", + val.ClassName.GetChars(), + val.FunctionName.GetChars(), + val.FunctionName.GetChars(), + val.ClassName.GetChars() + ); + ar.mErrors++; + return false; + } + PFunction* p = dyn_cast(sym); + if(!p) + { + *fn = nullptr; + Printf(TEXTCOLOR_RED "Function Pointer (%s::%s): '%s' in class '%s' is a variable, not a function\n", + val.ClassName.GetChars(), + val.FunctionName.GetChars(), + val.FunctionName.GetChars(), + val.ClassName.GetChars() + ); + ar.mErrors++; + return false; + } + *fn = NativeFunctionPointerCast(p, this); + if(!*fn) + { + if((p->Variants[0].Flags & (VARF_Action | VARF_Virtual)) != 0) + { + *fn = nullptr; + Printf(TEXTCOLOR_RED "Function Pointer (%s::%s): function '%s' in class '%s' is %s, not a static function\n", + val.ClassName.GetChars(), + val.FunctionName.GetChars(), + val.FunctionName.GetChars(), + val.ClassName.GetChars(), + (p->GetImplicitArgs() == 1 ? "a virtual function" : "an action function") + ); + } + else + { + FString fn_name = MakeFunctionPointerDescriptiveName(p->Variants[0].Proto,p->Variants[0].ArgFlags, FScopeBarrier::SideFromFlags(p->Variants[0].Flags)); + Printf(TEXTCOLOR_RED "Function Pointer (%s::%s) has incompatible type (Pointer is '%s', Function is '%s')\n", + val.ClassName.GetChars(), + val.FunctionName.GetChars(), + fn_name.GetChars(), + mDescriptiveName.GetChars() + ); + } + ar.mErrors++; + return false; + } + return true; + } + else + { + *fn = nullptr; + } + return true; +} + +bool PFunctionPointer::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PPrototype * proto = (const PPrototype*) id1; + const PFunctionPointer::FlagsAndScope * flags_and_scope = (const PFunctionPointer::FlagsAndScope *) id2; + return (proto == (PointedType == TypeVoid ? nullptr : PointedType)) + && (Scope == flags_and_scope->Scope) + && (ArgFlags == *flags_and_scope->ArgFlags); +} + +void PFunctionPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ //NOT SUPPORTED + assert(0 && "GetTypeIDs not supported for PFunctionPointer"); +} + +PFunctionPointer * NewFunctionPointer(PPrototype * proto, TArray && argflags, int scope) +{ + size_t bucket; + + PFunctionPointer::FlagsAndScope flags_and_scope { &argflags, scope }; + + PType *fn = TypeTable.FindType(NAME_Function, (intptr_t)proto, (intptr_t)&flags_and_scope, &bucket); + if (fn == nullptr) + { + fn = new PFunctionPointer(proto, std::move(argflags), scope); + flags_and_scope.ArgFlags = &static_cast(fn)->ArgFlags; + TypeTable.AddType(fn, NAME_Function, (intptr_t)proto, (intptr_t)&flags_and_scope, bucket); + } + return (PFunctionPointer *)fn; +} + +/* PStruct ****************************************************************/ + +//========================================================================== +// +// PStruct - Parameterized Constructor +// +//========================================================================== + +PStruct::PStruct(FName name, PTypeBase *outer, bool isnative, int fileno) +: PContainerType(name, outer) +{ + mDescriptiveName.Format("%sStruct<%s>", isnative? "Native" : "", name.GetChars()); + Size = 0; + isNative = isnative; + mDefFileNo = fileno; +} + +//========================================================================== +// +// PStruct :: SetDefaultValue +// +//========================================================================== + +void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + auto field = dyn_cast(pair->Value); + if (field && !(field->Flags & VARF_Transient)) + { + field->Type->SetDefaultValue(base, unsigned(offset + field->Offset), special); + } + } +} + +//========================================================================== +// +// PStruct :: SetPointer +// +//========================================================================== + +void PStruct::SetPointer(void *base, unsigned offset, TArray> *special) +{ + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + auto field = dyn_cast(pair->Value); + if (field && !(field->Flags & VARF_Transient)) + { + field->Type->SetPointer(base, unsigned(offset + field->Offset), special); + } + } +} + +//========================================================================== +// +// PStruct :: SetPointerArray +// +//========================================================================== + +void PStruct::SetPointerArray(void *base, unsigned offset, TArray> *special) +{ + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + auto field = dyn_cast(pair->Value); + if (field && !(field->Flags & VARF_Transient)) + { + field->Type->SetPointerArray(base, unsigned(offset + field->Offset), special); + } + } +} + +//========================================================================== +// +// PStruct :: SetPointerMap +// +//========================================================================== + +void PStruct::SetPointerMap(void *base, unsigned offset, TArray> *special) +{ + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + auto field = dyn_cast(pair->Value); + if (field && !(field->Flags & VARF_Transient)) + { + field->Type->SetPointerMap(base, unsigned(offset + field->Offset), special); + } + } +} + +//========================================================================== +// +// PStruct :: WriteValue +// +//========================================================================== + +void PStruct::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (ar.BeginObject(key)) + { + Symbols.WriteFields(ar, addr); + ar.EndObject(); + } +} + +//========================================================================== +// +// PStruct :: ReadValue +// +//========================================================================== + +bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + if (ar.BeginObject(key)) + { + bool ret = Symbols.ReadFields(ar, addr, DescriptiveName()); + ar.EndObject(); + return ret; + } + return false; +} + +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new field to the end of a struct. Returns either the new field +// or nullptr if a symbol by that name already exists. +// +//========================================================================== + +PField *PStruct::AddField(FName name, PType *type, uint32_t flags) +{ + assert(type->Size > 0); + return Symbols.AddField(name, type, flags, Size, &Align, mDefFileNo); +} + +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new native field to the struct. Returns either the new field +// or nullptr if a symbol by that name already exists. +// +//========================================================================== + +PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + return Symbols.AddNativeField(name, type, address, flags, bitvalue, mDefFileNo); +} + +//========================================================================== +// +// NewStruct +// Returns a PStruct for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PStruct *NewStruct(FName name, PTypeBase *outer, bool native, int fileno) +{ + size_t bucket; + if (outer == nullptr) outer = Namespaces.GlobalNamespace; + PType *stype = TypeTable.FindType(NAME_Struct, (intptr_t)outer, name.GetIndex(), &bucket); + if (stype == nullptr) + { + stype = new PStruct(name, outer, native, fileno); + TypeTable.AddType(stype, NAME_Struct, (intptr_t)outer, name.GetIndex(), bucket); + } + return static_cast(stype); +} + + +/* PPrototype *************************************************************/ + +//========================================================================== +// +// PPrototype - Parameterized Constructor +// +//========================================================================== + +PPrototype::PPrototype(const TArray &rettypes, const TArray &argtypes) +: ArgumentTypes(argtypes), ReturnTypes(rettypes) +{ + for (auto& type: ArgumentTypes) + { + if (type == TypeFVector2) + { + type = TypeVector2; + } + else if (type == TypeFVector3) + { + type = TypeVector3; + } + } + + for (auto& type : ReturnTypes) + { + if (type == TypeFVector2) + { + type = TypeVector2; + } + else if (type == TypeFVector3) + { + type = TypeVector3; + } + } +} + +//========================================================================== +// +// PPrototype :: IsMatch +// +//========================================================================== + +bool PPrototype::IsMatch(intptr_t id1, intptr_t id2) const +{ + const TArray *args = (const TArray *)id1; + const TArray *rets = (const TArray *)id2; + + return *args == ArgumentTypes && *rets == ReturnTypes; +} + +//========================================================================== +// +// PPrototype :: GetTypeIDs +// +//========================================================================== + +void PPrototype::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)&ArgumentTypes; + id2 = (intptr_t)&ReturnTypes; +} + +//========================================================================== +// +// NewPrototype +// +// Returns a PPrototype for the given return and argument types, making sure +// not to create duplicates. +// +//========================================================================== + +PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes) +{ + size_t bucket; + PType *proto = TypeTable.FindType(NAME_Prototype, (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); + if (proto == nullptr) + { + proto = new PPrototype(rettypes, argtypes); + TypeTable.AddType(proto, NAME_Prototype, (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); + } + return static_cast(proto); +} + +/* PClass *****************************************************************/ + +//========================================================================== +// +// +// +//========================================================================== + +PClassType::PClassType(PClass *cls, int fileno) +{ + assert(cls->VMType == nullptr); + Descriptor = cls; + TypeName = cls->TypeName; + if (cls->ParentClass != nullptr) + { + ParentType = cls->ParentClass->VMType; + assert(ParentType != nullptr); + Symbols.SetParentTable(&ParentType->Symbols); + ScopeFlags = ParentType->ScopeFlags; + } + cls->VMType = this; + mDefFileNo = fileno; + mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); +} + +//========================================================================== +// +// PClass :: AddField +// +//========================================================================== + +PField *PClassType::AddField(FName name, PType *type, uint32_t flags) +{ + return Descriptor->AddField(name, type, flags, mDefFileNo); +} + +//========================================================================== +// +// PClass :: AddNativeField +// +//========================================================================== + +PField *PClassType::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue, mDefFileNo); + if (field != nullptr) Descriptor->Fields.Push(field); + return field; +} + +//========================================================================== +// +// +// +//========================================================================== + +PClassType *NewClassType(PClass *cls, int fileno) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(NAME_Object, 0, cls->TypeName.GetIndex(), &bucket); + if (ptype == nullptr) + { + ptype = new PClassType(cls, fileno); + TypeTable.AddType(ptype, NAME_Object, 0, cls->TypeName.GetIndex(), bucket); + } + return static_cast(ptype); +} + + +/* FTypeTable **************************************************************/ + +//========================================================================== +// +// FTypeTable :: FindType +// +//========================================================================== + +PType *FTypeTable::FindType(FName type_name, intptr_t parm1, intptr_t parm2, size_t *bucketnum) +{ + size_t bucket = Hash(type_name, parm1, parm2) % HASH_SIZE; + if (bucketnum != nullptr) + { + *bucketnum = bucket; + } + for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) + { + if (type->TypeTableType == type_name && type->IsMatch(parm1, parm2)) + { + return type; + } + } + return nullptr; +} + +//========================================================================== +// +// FTypeTable :: AddType - Fully Parameterized Version +// +//========================================================================== + +void FTypeTable::AddType(PType *type, FName type_name, intptr_t parm1, intptr_t parm2, size_t bucket) +{ +#ifdef _DEBUG + size_t bucketcheck; + assert(FindType(type_name, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once"); + assert(bucketcheck == bucket && "Passed bucket was wrong"); +#endif + type->TypeTableType = type_name; + type->HashNext = TypeHash[bucket]; + TypeHash[bucket] = type; +} + +//========================================================================== +// +// FTypeTable :: AddType - Simple Version +// +//========================================================================== + +void FTypeTable::AddType(PType *type, FName type_name) +{ + intptr_t parm1, parm2; + size_t bucket; + + // Type table stuff id only needed to let all classes hash to the same group. For all other types this is pointless. + type->TypeTableType = type_name; + type->GetTypeIDs(parm1, parm2); + bucket = Hash(type_name, parm1, parm2) % HASH_SIZE; + assert(FindType(type_name, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once"); + + type->HashNext = TypeHash[bucket]; + TypeHash[bucket] = type; +} + +//========================================================================== +// +// FTypeTable :: Hash STATIC +// +//========================================================================== + +size_t FTypeTable::Hash(FName p1, intptr_t p2, intptr_t p3) +{ + size_t i1 = (size_t)p1.GetIndex(); + + // Swap the high and low halves of i1. The compiler should be smart enough + // to transform this into a ROR or ROL. + i1 = (i1 >> (sizeof(size_t)*4)) | (i1 << (sizeof(size_t)*4)); + + if (p1 != NAME_Prototype && p1 != NAME_Function) + { + size_t i2 = (size_t)p2; + size_t i3 = (size_t)p3; + return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime + } + else if(p1 == NAME_Prototype) + { // Prototypes need to hash the TArrays at p2 and p3 + const TArray *a2 = (const TArray *)p2; + const TArray *a3 = (const TArray *)p3; + for (unsigned i = 0; i < a2->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a2)[i]); + } + for (unsigned i = 0; i < a3->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a3)[i]); + } + return i1; + } + else // if(p1 == NAME_Function) + { // functions need custom hashing as well + size_t i2 = (size_t)p2; + const PFunctionPointer::FlagsAndScope * flags_and_scope = (const PFunctionPointer::FlagsAndScope *) p3; + const TArray * a3 = flags_and_scope->ArgFlags; + i1 = (~i1 ^ i2); + for (unsigned i = 0; i < a3->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a3)[i]); + } + return (i1 * 961748927) + (size_t)flags_and_scope->Scope; + } +} + +//========================================================================== +// +// FTypeTable :: Clear +// +//========================================================================== + +void FTypeTable::Clear() +{ + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr;) + { + auto next = ty->HashNext; + delete ty; + ty = next; + } + } + memset(TypeHash, 0, sizeof(TypeHash)); +} + +#include "c_dispatch.h" +CCMD(typetable) +{ + DumpTypeTable(); +} + diff --git a/src/common/scripting/core/types.h b/src/common/scripting/core/types.h new file mode 100644 index 00000000000..a092247dea3 --- /dev/null +++ b/src/common/scripting/core/types.h @@ -0,0 +1,772 @@ +#pragma once + +#include "dobject.h" +#include "serializer.h" +#include "symbols.h" +#include "scopebarrier.h" + +// Variable/parameter/field flags ------------------------------------------- + +// Making all these different storage types use a common set of flags seems +// like the simplest thing to do. + +enum +{ + VARF_Optional = (1<<0), // func param is optional + VARF_Method = (1<<1), // func has an implied self parameter + VARF_Action = (1<<2), // func has implied owner and state parameters + VARF_Native = (1<<3), // func is native code, field is natively defined + VARF_ReadOnly = (1<<4), // field is read only, do not write to it + VARF_Private = (1<<5), // field is private to containing class + VARF_Protected = (1<<6), // field is only accessible by containing class and children. + VARF_Deprecated = (1<<7), // Deprecated fields should output warnings when used. + VARF_Virtual = (1<<8), // function is virtual + VARF_Final = (1<<9), // Function may not be overridden in subclasses + VARF_In = (1<<10), + VARF_Out = (1<<11), + VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures) + VARF_Static = (1<<13), + VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. + VARF_Override = (1<<15), // overrides a virtual function from the parent class. + VARF_Ref = (1<<16), // argument is passed by reference. + VARF_Transient = (1<<17), // don't auto serialize field. + VARF_Meta = (1<<18), // static class data (by necessity read only.) + VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature + VARF_UI = (1<<20), // [ZZ] ui: object is ui-scope only (can't modify playsim) + VARF_Play = (1<<21), // [ZZ] play: object is playsim-scope only (can't access ui) + VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only) + VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data. + VARF_Abstract = (1<<24), // [Player701] Function does not have a body and must be overridden in subclasses +}; + +// Basic information shared by all types ------------------------------------ + +// Only one copy of a type is ever instantiated at one time. +// - Enums, classes, and structs are defined by their names and outer classes. +// - Pointers are uniquely defined by the type they point at. +// - ClassPointers are also defined by their class restriction. +// - Arrays are defined by their element type and count. +// - DynArrays are defined by their element type. +// - Maps are defined by their key and value types. +// - Prototypes are defined by the argument and return types. +// - Functions are defined by their names and outer objects. +// In table form: +// Outer Name Type Type2 Count +// Enum * * +// Class * * +// Struct * * +// Function * * +// Pointer * +// ClassPointer + * +// Array * * +// DynArray * +// Map * * +// Prototype *+ *+ + +class PContainerType; +class PPointer; +class PClassPointer; +class PFunctionPointer; +class PArray; +class PDynArray; +class PMap; +class PStruct; +class PClassType; +class PObjectPointer; + +struct ZCC_ExprConstant; +class PType : public PTypeBase +{ +protected: + + enum ETypeFlags + { + TYPE_Scalar = 1, + TYPE_Container = 2, + TYPE_Int = 4, + TYPE_IntNotInt = 8, // catch-all for subtypes that are not being checked by type directly. + TYPE_Float = 16, + TYPE_Pointer = 32, + TYPE_ObjectPointer = 64, + TYPE_ClassPointer = 128, + TYPE_Array = 256, + TYPE_FunctionPointer = 512, + + TYPE_IntCompatible = TYPE_Int | TYPE_IntNotInt, // must be the combination of all flags that are subtypes of int and can be cast to an int. + }; + +public: + FName TypeTableType; // The type to use for hashing into the type table + unsigned int Size; // this type's size + unsigned int Align; // this type's preferred alignment + unsigned int Flags = 0; // What is this type? + PType *HashNext; // next type in this type table + PSymbolTable Symbols; + bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument. + FString mDescriptiveName; + VersionInfo mVersion = { 0,0,0 }; + uint8_t loadOp, storeOp, moveOp, RegType, RegCount; + EScopeFlags ScopeFlags = (EScopeFlags)0; + bool SizeKnown = true; + + PType(unsigned int size = 1, unsigned int align = 1); + virtual ~PType(); + virtual bool isNumeric() { return false; } + + // Writes the value of a variable of this type at (addr) to an archive, preceded by + // a tag indicating its type. The tag is there so that variable types can be changed + // without completely breaking savegames, provided that the change isn't between + // totally unrelated types. + virtual void WriteValue(FSerializer &ar, const char *key,const void *addr) const; + + // Returns true if the stored value was compatible. False otherwise. + // If the value was incompatible, then the memory at *addr is unchanged. + virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const; + + // Sets the default value for this type at (base + offset) + // If the default value is binary 0, then this function doesn't need + // to do anything, because PClass::Extend() takes care of that. + // + // The stroffs array is so that types that need special initialization + // and destruction (e.g. strings) can add their offsets to it for special + // initialization when the object is created and destruction when the + // object is destroyed. + virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL); + virtual void SetPointer(void *base, unsigned offset, TArray> *ptrofs = NULL); + virtual void SetPointerArray(void *base, unsigned offset, TArray> *ptrofs = NULL); + virtual void SetPointerMap(void *base, unsigned offset, TArray> *ptrofs = NULL); + + // Initialize the value, if needed (e.g. strings) + virtual void InitializeValue(void *addr, const void *def) const; + + // Destroy the value, if needed (e.g. strings) + virtual void DestroyValue(void *addr) const; + + // Sets the value of a variable of this type at (addr) + virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); + + // Gets the value of a variable of this type at (addr) + virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; + + // Gets the opcode to store from a register to memory + int GetStoreOp() const + { + return storeOp; + } + + // Gets the opcode to load from memory to a register + int GetLoadOp() const + { + return loadOp; + } + + // Gets the opcode to move from register to another register + int GetMoveOp() const + { + return moveOp; + } + + // Gets the register type for this type + int GetRegType() const + { + return RegType; + } + + int GetRegCount() const + { + return RegCount; + } + // Returns true if this type matches the two identifiers. Referring to the + // above table, any type is identified by at most two characteristics. Each + // type that implements this function will cast these to the appropriate type. + // It is up to the caller to make sure they are the correct types. There is + // only one prototype for this function in order to simplify type table + // management. + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + + // Get the type IDs used by IsMatch + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + const char *DescriptiveName() const; + + static void StaticInit(); + + bool isScalar() const { return !!(Flags & TYPE_Scalar); } + bool isContainer() const { return !!(Flags & TYPE_Container); } + bool isInt() const { return (Flags & TYPE_IntCompatible) == TYPE_Int; } + bool isIntCompatible() const { return !!(Flags & TYPE_IntCompatible); } + bool isFloat() const { return !!(Flags & TYPE_Float); } + bool isPointer() const { return !!(Flags & TYPE_Pointer); } + bool isRealPointer() const { return (Flags & (TYPE_Pointer | TYPE_ClassPointer | TYPE_FunctionPointer)) == TYPE_Pointer; } // This excludes class and function pointers which use their PointedType differently + bool isObjectPointer() const { return !!(Flags & TYPE_ObjectPointer); } + bool isClassPointer() const { return !!(Flags & TYPE_ClassPointer); } + bool isFunctionPointer() const { return !!(Flags & TYPE_FunctionPointer); } + bool isEnum() const { return TypeTableType == NAME_Enum; } + bool isArray() const { return !!(Flags & TYPE_Array); } + bool isStaticArray() const { return TypeTableType == NAME_StaticArray; } + bool isDynArray() const { return TypeTableType == NAME_DynArray; } + bool isMap() const { return TypeTableType == NAME_Map; } + bool isMapIterator() const { return TypeTableType == NAME_MapIterator; } + bool isStruct() const { return TypeTableType == NAME_Struct; } + bool isClass() const { return TypeTableType == NAME_Object; } + bool isPrototype() const { return TypeTableType == NAME_Prototype; } + + PContainerType *toContainer() { return isContainer() ? (PContainerType*)this : nullptr; } + PPointer *toPointer() { return isPointer() ? (PPointer*)this : nullptr; } + static PClassPointer *toClassPointer(PType *t) { return t && t->isClassPointer() ? (PClassPointer*)t : nullptr; } + static PFunctionPointer *toFunctionPointer(PType *t) { return t && t->isFunctionPointer() ? (PFunctionPointer*)t : nullptr; } + static PClassType *toClass(PType *t) { return t && t->isClass() ? (PClassType*)t : nullptr; } +}; + +// Not-really-a-type types -------------------------------------------------- + +class PErrorType : public PType +{ +public: + PErrorType(int which = 1) : PType(0, which) {} +}; + +class PVoidType : public PType +{ +public: + PVoidType() : PType(0, 1) {} +}; + +// Some categorization typing ----------------------------------------------- + +class PBasicType : public PType +{ +protected: + PBasicType(unsigned int size = 1, unsigned int align = 1); +}; + +class PCompoundType : public PType +{ +protected: + PCompoundType(unsigned int size = 1, unsigned int align = 1); +}; + +class PContainerType : public PCompoundType +{ +public: + PTypeBase *Outer = nullptr; // object this type is contained within + FName TypeName = NAME_None; // this type's name + + PContainerType() + { + mDescriptiveName = "ContainerType"; + Flags |= TYPE_Container; + } + PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) + { + mDescriptiveName = name.GetChars(); + Flags |= TYPE_Container; + } + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + virtual PField *AddField(FName name, PType *type, uint32_t flags = 0) = 0; + virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) = 0; +}; + +// Basic types -------------------------------------------------------------- + +class PInt : public PBasicType +{ +public: + PInt(unsigned int size, bool unsign, bool compatible = true); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + + virtual void SetValue(void *addr, int val) override; + virtual void SetValue(void *addr, double val) override; + virtual int GetValueInt(void *addr) const override; + virtual double GetValueFloat(void *addr) const override; + virtual bool isNumeric() override { return IntCompatible; } + + bool Unsigned; + bool IntCompatible; +protected: + void SetOps(); +}; + +class PBool : public PInt +{ +public: + PBool(); + virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); + virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; +}; + +class PFloat : public PBasicType +{ +public: + PFloat(unsigned int size = 8); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + + virtual void SetValue(void *addr, int val) override; + virtual void SetValue(void *addr, double val) override; + virtual int GetValueInt(void *addr) const override; + virtual double GetValueFloat(void *addr) const override; + virtual bool isNumeric() override { return true; } +protected: + void SetOps(); +private: + struct SymbolInitF + { + ENamedName Name; + double Value; + }; + struct SymbolInitI + { + ENamedName Name; + int Value; + }; + + void SetSingleSymbols(); + void SetDoubleSymbols(); + void SetSymbols(const SymbolInitF *syminit, size_t count); + void SetSymbols(const SymbolInitI *syminit, size_t count); +}; + +class PString : public PBasicType +{ +public: + PString(); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; +}; + +// Variations of integer types ---------------------------------------------- + +class PName : public PInt +{ +public: + PName(); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; +}; + +class PSound : public PInt +{ +public: + PSound(); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; +}; + +class PSpriteID : public PInt +{ +public: + PSpriteID(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + +class PTextureID : public PInt +{ +public: + PTextureID(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + +class PTranslationID : public PInt +{ +public: + PTranslationID(); + + void WriteValue(FSerializer& ar, const char* key, const void* addr) const override; + bool ReadValue(FSerializer& ar, const char* key, void* addr) const override; +}; + +class PColor : public PInt +{ +public: + PColor(); +}; + +class PStateLabel : public PInt +{ +public: + PStateLabel(); +}; + +// Pointers ----------------------------------------------------------------- + +class PPointer : public PBasicType +{ + +public: + typedef void(*WriteHandler)(FSerializer &ar, const char *key, const void *addr); + typedef bool(*ReadHandler)(FSerializer &ar, const char *key, void *addr); + + PPointer(); + PPointer(PType *pointsat, bool isconst = false); + + PType *PointedType; + bool IsConst; + + WriteHandler writer = nullptr; + ReadHandler reader = nullptr; + + void InstallHandlers(WriteHandler w, ReadHandler r) + { + writer = w; + reader = r; + } + + bool IsMatch(intptr_t id1, intptr_t id2) const override; + void GetTypeIDs(intptr_t &id1, intptr_t &id2) const override; + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + +protected: + void SetOps(); +}; + +class PStatePointer : public PPointer +{ +public: + PStatePointer(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + + +class PObjectPointer : public PPointer +{ +public: + PObjectPointer(PClass *pointedtype = nullptr, bool isconst = false); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetPointer(void *base, unsigned offset, TArray> *special = NULL) override; + PClass *PointedClass() const; +}; + + +class PClassPointer : public PPointer +{ +public: + PClassPointer(class PClass *restrict = nullptr); + + class PClass *ClassRestriction; + + bool isCompatible(PType *type); + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + + void SetPointer(void *base, unsigned offset, TArray> *special = NULL) override; + bool IsMatch(intptr_t id1, intptr_t id2) const override; + void GetTypeIDs(intptr_t &id1, intptr_t &id2) const override; +}; + +// Compound types ----------------------------------------------------------- + +class PEnum : public PInt +{ +public: + PEnum(FName name, PTypeBase *outer); + + PTypeBase *Outer; + FName EnumName; +}; + +class PArray : public PCompoundType +{ +public: + PArray(PType *etype, unsigned int ecount); + + PType *ElementType; + unsigned int ElementCount; + unsigned int ElementSize; + + bool IsMatch(intptr_t id1, intptr_t id2) const override; + void GetTypeIDs(intptr_t &id1, intptr_t &id2) const override; + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + + void SetDefaultValue(void *base, unsigned offset, TArray *special) override; + void SetPointer(void *base, unsigned offset, TArray> *special) override; + void SetPointerArray(void *base, unsigned offset, TArray> *ptrofs = NULL) override; + void SetPointerMap(void *base, unsigned offset, TArray> *ptrofs = NULL) override; +}; + +class PStaticArray : public PArray +{ +public: + PStaticArray(PType *etype); + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +}; + +class PDynArray : public PCompoundType +{ +public: + PDynArray(PType *etype, PStruct *backing); + + PType *ElementType; + PStruct *BackingType; + + TMap FnOverrides; + + bool IsMatch(intptr_t id1, intptr_t id2) const override; + void GetTypeIDs(intptr_t &id1, intptr_t &id2) const override; + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + void SetPointerArray(void *base, unsigned offset, TArray> *ptrofs = NULL) override; +}; + +class PMap : public PCompoundType +{ + void Construct(void * addr) const; +public: + PMap(PType *keytype, PType *valtype, PStruct *backing, int backing_class); + + PType *KeyType; + PType *ValueType; + + TMap FnOverrides; + + PStruct *BackingType; + + enum EBackingClass { + MAP_I32_I8, + MAP_I32_I16, + MAP_I32_I32, + MAP_I32_F32, + MAP_I32_F64, + MAP_I32_OBJ, + MAP_I32_PTR, + MAP_I32_STR, + + MAP_STR_I8, + MAP_STR_I16, + MAP_STR_I32, + MAP_STR_F32, + MAP_STR_F64, + MAP_STR_OBJ, + MAP_STR_PTR, + MAP_STR_STR, + } BackingClass; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + void SetPointerMap(void *base, unsigned offset, TArray> *ptrofs) override; +}; + + +class PMapIterator : public PCompoundType +{ + void Construct(void * addr) const; +public: + PMapIterator(PType *keytype, PType *valtype, PStruct *backing, int backing_class); + + PType *KeyType; + PType *ValueType; + + TMap FnOverrides; + + PStruct *BackingType; + + PMap::EBackingClass BackingClass; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; +}; + +class PFunctionPointer : public PPointer +{ +public: + //PointedType = PPrototype or TypeVoid + PFunctionPointer(PPrototype * proto, TArray &&argflags, int scope); + + static FString GenerateNameForError(const PFunction * from); + + TArray ArgFlags; + int Scope; + + PFunction *FakeFunction; // used for type checking in FxFunctionCall + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + + + struct FlagsAndScope + { // used for IsMatch's id2 + TArray * ArgFlags; + int Scope; + }; + + bool IsMatch(intptr_t id1, intptr_t id2) const override; + void GetTypeIDs(intptr_t &id1, intptr_t &id2) const override; //NOT SUPPORTED +}; + +class PStruct : public PContainerType +{ +public: + PStruct(FName name, PTypeBase *outer, bool isnative = false, int fileno = 0); + + bool isNative; + bool isOrdered = false; + // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it. + VMFunction *mConstructor = nullptr; + VMFunction *mDestructor = nullptr; + int mDefFileNo; + + PField *AddField(FName name, PType *type, uint32_t flags=0) override; + PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; + void SetPointer(void *base, unsigned offset, TArray> *specials) override; + void SetPointerArray(void *base, unsigned offset, TArray> *special) override; + void SetPointerMap(void *base, unsigned offset, TArray> *ptrofs) override; +}; + +class PPrototype : public PCompoundType +{ +public: + PPrototype(const TArray &rettypes, const TArray &argtypes); + + TArray ArgumentTypes; + TArray ReturnTypes; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +}; + + +// Meta-info for every class derived from DObject --------------------------- + +class PClassType : public PContainerType +{ +public: + PClass *Descriptor; + PClassType *ParentType; + int mDefFileNo; + + PClassType(PClass *cls = nullptr, int fileno = 0); + PField *AddField(FName name, PType *type, uint32_t flags = 0) override; + PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; +}; + + +inline PClass *PObjectPointer::PointedClass() const +{ + return static_cast(PointedType)->Descriptor; +} + +// Returns a type from the TypeTable. Will create one if it isn't present. +PMap *NewMap(PType *keytype, PType *valuetype); +PMapIterator *NewMapIterator(PType *keytype, PType *valuetype); +PArray *NewArray(PType *type, unsigned int count); +PStaticArray *NewStaticArray(PType *type); +PDynArray *NewDynArray(PType *type); +PFunctionPointer *NewFunctionPointer(PPrototype * proto, TArray && argflags, int scope); +PPointer *NewPointer(PType *type, bool isconst = false); +PPointer *NewPointer(PClass *type, bool isconst = false); +PClassPointer *NewClassPointer(PClass *restrict); +PEnum *NewEnum(FName name, PTypeBase *outer); +PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false, int fileno = 0); +PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); +PClassType *NewClassType(PClass *cls, int fileno); + +// Built-in types ----------------------------------------------------------- + +extern PErrorType *TypeError; +extern PErrorType *TypeAuto; +extern PVoidType *TypeVoid; +extern PInt *TypeSInt8, *TypeUInt8; +extern PInt *TypeSInt16, *TypeUInt16; +extern PInt *TypeSInt32, *TypeUInt32; +extern PBool *TypeBool; +extern PFloat *TypeFloat32, *TypeFloat64; +extern PString *TypeString; +extern PName *TypeName; +extern PSound *TypeSound; +extern PColor *TypeColor; +extern PTextureID *TypeTextureID; +extern PTranslationID* TypeTranslationID; +extern PSpriteID *TypeSpriteID; +extern PStruct* TypeVector2; +extern PStruct* TypeVector3; +extern PStruct* TypeVector4; +extern PStruct* TypeFVector2; +extern PStruct* TypeFVector3; +extern PStruct* TypeFVector4; +extern PStruct* TypeQuaternion; +extern PStruct* TypeFQuaternion; +extern PStruct *TypeColorStruct; +extern PStruct *TypeStringStruct; +extern PStruct* TypeQuaternionStruct; +extern PStatePointer *TypeState; +extern PPointer *TypeFont; +extern PStateLabel *TypeStateLabel; +extern PPointer *TypeNullPtr; +extern PPointer *TypeVoidPtr; +extern PPointer* TypeRawFunction; +extern PPointer* TypeVMFunction; + + +inline FString &DObject::StringVar(FName field) +{ + return *(FString*)ScriptVar(field, TypeString); +} + +// Type tables -------------------------------------------------------------- + +struct FTypeTable +{ + enum { HASH_SIZE = 1021 }; + + PType *TypeHash[HASH_SIZE]; + + PType *FindType(FName type_name, intptr_t parm1, intptr_t parm2, size_t *bucketnum); + void AddType(PType *type, FName type_name, intptr_t parm1, intptr_t parm2, size_t bucket); + void AddType(PType *type, FName type_name); + void Clear(); + + static size_t Hash(FName p1, intptr_t p2, intptr_t p3); +}; + + +extern FTypeTable TypeTable; + diff --git a/src/scripting/backend/vmdisasm.cpp b/src/common/scripting/core/vmdisasm.cpp similarity index 97% rename from src/scripting/backend/vmdisasm.cpp rename to src/common/scripting/core/vmdisasm.cpp index 0046bd7273c..09524d3b58d 100644 --- a/src/scripting/backend/vmdisasm.cpp +++ b/src/common/scripting/core/vmdisasm.cpp @@ -33,8 +33,9 @@ #include "dobject.h" #include "c_console.h" -#include "templates.h" + #include "vmintern.h" +#include "printf.h" #define NOP MODE_AUNUSED | MODE_BUNUSED | MODE_CUNUSED @@ -45,6 +46,9 @@ #define LKP MODE_AP | MODE_BCJOINT | MODE_BCKP #define LFP MODE_AP | MODE_BUNUSED | MODE_CUNUSED + +#define RP MODE_AP | MODE_BUNUSED | MODE_CUNUSED + #define RIRPKI MODE_AI | MODE_BP | MODE_CKI #define RIRPRI MODE_AI | MODE_BP | MODE_CI #define RFRPKI MODE_AF | MODE_BP | MODE_CKI @@ -264,7 +268,7 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func) { - VMFunction *callfunc; + VMFunction *callfunc = nullptr; const char *name; int col; int mode; @@ -525,9 +529,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction { printf_wrapper(out, ",%d\n", code[++i].i24); } - else if (code[i].op == OP_CALL_K) + else if (code[i].op == OP_CALL_K && callfunc) { - printf_wrapper(out, " [%s]\n", callfunc->PrintableName.GetChars()); + printf_wrapper(out, " [%s]\n", callfunc->PrintableName); } else { @@ -638,6 +642,8 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const return col+printf_wrapper(out, "v%d.2", regnum); case REGT_FLOAT | REGT_MULTIREG3: return col+printf_wrapper(out, "v%d.3", regnum); + case REGT_FLOAT | REGT_MULTIREG4: + return col+printf_wrapper(out, "v%d.4", regnum); case REGT_INT | REGT_KONST: return col+print_reg(out, 0, regnum, MODE_KI, 0, func); case REGT_FLOAT | REGT_KONST: @@ -664,7 +670,6 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const default: return col+printf_wrapper(out, "$%d", arg); } - return col; } //========================================================================== @@ -676,7 +681,7 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen) { const char *marks = "======================================================="; - fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + fprintf(dump, "\n%.*s %s %.*s", max(3, 38 - labellen / 2), marks, label, max(3, 38 - labellen / 2), marks); fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); VMDumpConstants(dump, sfunc); diff --git a/src/common/scripting/frontend/ast.cpp b/src/common/scripting/frontend/ast.cpp new file mode 100644 index 00000000000..ba91077af05 --- /dev/null +++ b/src/common/scripting/frontend/ast.cpp @@ -0,0 +1,1125 @@ +/* +** ast.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "dobject.h" +#include "vmintern.h" +#include "types.h" +#include "zcc_parser.h" +#include "zcc-parse.h" +#include "printf.h" + +class FLispString; +using NodePrinterFunc = void (*)(FLispString &, const ZCC_TreeNode *); + +static const char *BuiltInTypeNames[] = +{ + "sint8", "uint8", + "sint16", "uint16", + "sint32", "uint32_t", + "intauto", + + "bool", + "float64", "floatauto", + "string", + "vector2", + "vector3", + "vector4", + "name", + + "color", + "state", + "sound", + + "usertype", + "nativetype", + "let", +}; + +class FLispString +{ +public: + operator FString &() { return Str; } + + FLispString() + { + NestDepth = Column = 0; + WrapWidth = 200; + NeedSpace = false; + ConsecOpens = 0; + } + + void Open(const char *label) + { + size_t labellen = label != NULL ? strlen(label) : 0; + CheckWrap(labellen + 1 + NeedSpace); + if (NeedSpace) + { + Str << ' '; + ConsecOpens = 0; + } + Str << '('; + ConsecOpens++; + if (label != NULL) + { + Str.AppendCStrPart(label, labellen); + } + Column += labellen + 1 + NeedSpace; + NestDepth++; + NeedSpace = (label != NULL); + } + void Close() + { + assert(NestDepth != 0); + Str << ')'; + Column++; + NestDepth--; + NeedSpace = true; + } + void Break() + { + // Don't break if not needed. + if (Column != NestDepth) + { + if (NeedSpace) + { + ConsecOpens = 0; + } + else + { // Move hanging ( characters to the new line + Str.Truncate(Str.Len() - ConsecOpens); + NestDepth -= ConsecOpens; + } + Str << '\n'; + Column = NestDepth; + NeedSpace = false; + if (NestDepth > 0) + { + Str.AppendFormat("%*s", (int)NestDepth, ""); + } + if (ConsecOpens > 0) + { + for (size_t i = 0; i < ConsecOpens; ++i) + { + Str << '('; + } + NestDepth += ConsecOpens; + } + } + } + bool CheckWrap(size_t len) + { + if (len + Column > WrapWidth) + { + Break(); + return true; + } + return false; + } + void Add(const char *str, size_t len) + { + CheckWrap(len + NeedSpace); + if (NeedSpace) + { + Str << ' '; + } + Str.AppendCStrPart(str, len); + Column += len + NeedSpace; + NeedSpace = true; + } + void Add(const char *str) + { + Add(str, strlen(str)); + } + void Add(FString &str) + { + Add(str.GetChars(), str.Len()); + } + void AddName(FName name) + { + size_t namelen = strlen(name.GetChars()); + CheckWrap(namelen + 2 + NeedSpace); + if (NeedSpace) + { + NeedSpace = false; + Str << ' '; + } + Str << '\'' << name.GetChars() << '\''; + Column += namelen + 2 + NeedSpace; + NeedSpace = true; + } + void AddChar(char c) + { + Add(&c, 1); + } + void AddInt(int i, bool un=false) + { + char buf[16]; + size_t len; + if (!un) + { + len = mysnprintf(buf, countof(buf), "%d", i); + } + else + { + len = mysnprintf(buf, countof(buf), "%uu", i); + } + Add(buf, len); + } + void AddHex(unsigned x) + { + char buf[10]; + size_t len = mysnprintf(buf, countof(buf), "%08x", x); + Add(buf, len); + } + void AddFloat(double f, bool single) + { + char buf[32]; + size_t len = mysnprintf(buf, countof(buf), "%.4f", f); + if (single) + { + buf[len++] = 'f'; + buf[len] = '\0'; + } + Add(buf, len); + } +private: + FString Str; + size_t NestDepth; + size_t Column; + size_t WrapWidth; + size_t ConsecOpens; + bool NeedSpace; +}; + +static void PrintNode(FLispString &out, const ZCC_TreeNode *node); + +static void PrintNodes(FLispString &out, const ZCC_TreeNode *node, bool newlist=true, bool addbreaks=false) +{ + const ZCC_TreeNode *p; + + if (node == NULL) + { + out.Add("nil", 3); + } + else + { + if (newlist) + { + out.Open(NULL); + } + p = node; + do + { + if (addbreaks) + { + out.Break(); + } + PrintNode(out, p); + p = p->SiblingNext; + } while (p != node); + if (newlist) + { + out.Close(); + } + } +} + +static void PrintBuiltInType(FLispString &out, EZCCBuiltinType type) +{ + static_assert(ZCC_NUM_BUILT_IN_TYPES == countof(BuiltInTypeNames)); + if (unsigned(type) >= unsigned(ZCC_NUM_BUILT_IN_TYPES)) + { + char buf[30]; + size_t len = mysnprintf(buf, countof(buf), "bad-type-%u", type); + out.Add(buf, len); + } + else + { + out.Add(BuiltInTypeNames[type]); + } +} + +static void PrintIdentifier(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Identifier *inode = (ZCC_Identifier *)node; + out.Open("identifier"); + out.AddName(inode->Id); + out.Close(); +} + +static void PrintStringConst(FLispString &out, FString str) +{ + FString outstr; + outstr << '"'; + for (size_t i = 0; i < str.Len(); ++i) + { + if (str[i] == '"') + { + outstr << "\""; + } + else if (str[i] == '\\') + { + outstr << "\\\\"; + } + else if (str[i] >= 32) + { + outstr << str[i]; + } + else + { + outstr.AppendFormat("\\x%02X", str[i]); + } + } + outstr << '"'; + out.Add(outstr); +} + +static void PrintClass(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Class *cnode = (ZCC_Class *)node; + out.Break(); + out.Open("class"); + out.AddName(cnode->NodeName); + PrintNodes(out, cnode->ParentName); + PrintNodes(out, cnode->Replaces); + out.AddHex(cnode->Flags); + PrintNodes(out, cnode->Body, false, true); + out.Close(); +} + +static void PrintStruct(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Struct *snode = (ZCC_Struct *)node; + out.Break(); + out.Open("struct"); + out.AddName(snode->NodeName); + PrintNodes(out, snode->Body, false, true); + out.Close(); +} + +static void PrintProperty(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Property *snode = (ZCC_Property *)node; + out.Break(); + out.Open("property"); + out.AddName(snode->NodeName); + PrintNodes(out, snode->Body, false, true); + out.Close(); +} + +static void PrintFlagDef(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_FlagDef *snode = (ZCC_FlagDef *)node; + out.Break(); + out.Open("flagdef"); + out.AddName(snode->NodeName); + out.AddName(snode->RefName); + out.AddInt(snode->BitValue); + out.Close(); +} + +static void PrintStaticArrayState(FLispString &out, const ZCC_TreeNode *node) +{ + auto *snode = (ZCC_StaticArrayStatement *)node; + out.Break(); + out.Open("static-array"); + out.AddName(snode->Id); + PrintNodes(out, snode->Values, false, true); + out.Close(); +} + +static void PrintEnum(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Enum *enode = (ZCC_Enum *)node; + out.Break(); + out.Open("enum"); + out.AddName(enode->NodeName); + PrintBuiltInType(out, enode->EnumType); + out.Add(enode->Elements == NULL ? "nil" : "...", 3); + out.Close(); +} + +static void PrintEnumTerminator(FLispString &out, const ZCC_TreeNode *node) +{ + out.Open("enum-term"); + out.Close(); +} + +static void PrintStates(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_States *snode = (ZCC_States *)node; + out.Break(); + out.Open("states"); + PrintNodes(out, snode->Flags, false, true); + PrintNodes(out, snode->Body, false, true); + out.Close(); +} + +static void PrintStatePart(FLispString &out, const ZCC_TreeNode *node) +{ + out.Open("state-part"); + out.Close(); +} + +static void PrintStateLabel(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_StateLabel *snode = (ZCC_StateLabel *)node; + out.Open("state-label"); + out.AddName(snode->Label); + out.Close(); +} + +static void PrintStateStop(FLispString &out, const ZCC_TreeNode *node) +{ + out.Open("state-stop"); + out.Close(); +} + +static void PrintStateWait(FLispString &out, const ZCC_TreeNode *node) +{ + out.Open("state-wait"); + out.Close(); +} + +static void PrintStateFail(FLispString &out, const ZCC_TreeNode *node) +{ + out.Open("state-fail"); + out.Close(); +} + +static void PrintStateLoop(FLispString &out, const ZCC_TreeNode *node) +{ + out.Open("state-loop"); + out.Close(); +} + +static void PrintStateGoto(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_StateGoto *snode = (ZCC_StateGoto *)node; + out.Open("state-goto"); + PrintNodes(out, snode->Qualifier); + PrintNodes(out, snode->Label); + PrintNodes(out, snode->Offset); + out.Close(); +} + +static void PrintStateLine(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_StateLine *snode = (ZCC_StateLine *)node; + out.Open("state-line"); + out.Add(*(snode->Sprite)); + PrintNodes(out, snode->Duration); + if (snode->bNoDelay) out.Add("nodelay", 7); + if (snode->bBright) out.Add("bright", 6); + if (snode->bFast) out.Add("fast", 4); + if (snode->bSlow) out.Add("slow", 4); + if (snode->bCanRaise) out.Add("canraise", 8); + out.Add(*(snode->Frames)); + PrintNodes(out, snode->Offset); + PrintNodes(out, snode->Action, false); + out.Close(); +} + +static void PrintVarName(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_VarName *vnode = (ZCC_VarName *)node; + out.Open("var-name"); + PrintNodes(out, vnode->ArraySize); + out.AddName(vnode->Name); + out.Close(); +} + +static void PrintVarInit(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_VarInit *vnode = (ZCC_VarInit *)node; + out.Open("var-init"); + PrintNodes(out, vnode->ArraySize); + PrintNodes(out, vnode->Init); + if (vnode->InitIsArray) out.Add("array", 5); + out.AddName(vnode->Name); + out.Close(); +} + +static void PrintType(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Type *tnode = (ZCC_Type *)node; + out.Open("bad-type"); + PrintNodes(out, tnode->ArraySize); + out.Close(); +} + +static void PrintBasicType(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_BasicType *tnode = (ZCC_BasicType *)node; + out.Open("basic-type"); + PrintNodes(out, tnode->ArraySize); + PrintBuiltInType(out, tnode->Type); + if (tnode->Type == ZCC_UserType || tnode->Type == ZCC_NativeType) + { + if (tnode->Type == ZCC_NativeType) out.Add("@", 1); + PrintNodes(out, tnode->UserType, false); + } + out.Close(); +} + +static void PrintMapType(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_MapType *tnode = (ZCC_MapType *)node; + out.Open("map-type"); + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->KeyType); + PrintNodes(out, tnode->ValueType); + out.Close(); +} + +static void PrintMapIteratorType(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_MapIteratorType *tnode = (ZCC_MapIteratorType *)node; + out.Open("map-iterator-type"); + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->KeyType); + PrintNodes(out, tnode->ValueType); + out.Close(); +} + +static void PrintDynArrayType(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_DynArrayType *tnode = (ZCC_DynArrayType *)node; + out.Open("dyn-array-type"); + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->ElementType); + out.Close(); +} + +static void PrintFuncPtrParamDecl(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_FuncPtrParamDecl *dnode = (ZCC_FuncPtrParamDecl *)node; + out.Break(); + out.Open("func-ptr-param-decl"); + PrintNodes(out, dnode->Type); + out.AddHex(dnode->Flags); + out.Close(); +} + +static void PrintFuncPtrType(FLispString &out, const ZCC_TreeNode *node){ + ZCC_FuncPtrType *dnode = (ZCC_FuncPtrType *)node; + out.Break(); + out.Open("func-ptr-type"); + PrintNodes(out, dnode->RetType); + PrintNodes(out, dnode->Params); + out.AddHex(dnode->Scope); + out.Close(); +} + +static void PrintClassType(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ClassType *tnode = (ZCC_ClassType *)node; + out.Open("class-type"); + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->Restriction); + out.Close(); +} + +static void OpenExprType(FLispString &out, EZCCExprType type) +{ + char buf[32]; + + if (unsigned(type) < PEX_COUNT_OF) + { + mysnprintf(buf, countof(buf), "expr %d", type); + } + else + { + mysnprintf(buf, countof(buf), "bad-pex-%u", type); + } + out.Open(buf); +} + +static void PrintExpression(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Expression *enode = (ZCC_Expression *)node; + OpenExprType(out, enode->Operation); + out.Close(); +} + +static void PrintExprID(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExprID *enode = (ZCC_ExprID *)node; + assert(enode->Operation == PEX_ID); + out.Open("expr-id"); + out.AddName(enode->Identifier); + out.Close(); +} + +static void PrintExprTypeRef(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExprTypeRef *enode = (ZCC_ExprTypeRef *)node; + assert(enode->Operation == PEX_TypeRef); + out.Open("expr-type-ref"); + if (enode->RefType == TypeSInt8) { out.Add("sint8"); } + else if (enode->RefType == TypeUInt8) { out.Add("uint8"); } + else if (enode->RefType == TypeSInt16) { out.Add("sint16"); } + else if (enode->RefType == TypeSInt32) { out.Add("sint32"); } + else if (enode->RefType == TypeFloat32) { out.Add("float32"); } + else if (enode->RefType == TypeFloat64) { out.Add("float64"); } + else if (enode->RefType == TypeString) { out.Add("string"); } + else if (enode->RefType == TypeName) { out.Add("name"); } + else if (enode->RefType == TypeColor) { out.Add("color"); } + else if (enode->RefType == TypeSound) { out.Add("sound"); } + else { out.Add("other"); } + out.Close(); +} + +static void PrintExprConstant(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExprConstant *enode = (ZCC_ExprConstant *)node; + assert(enode->Operation == PEX_ConstValue); + out.Open("expr-const"); + if (enode->Type == TypeString) + { + PrintStringConst(out, *enode->StringVal); + } + else if (enode->Type == TypeFloat64) + { + out.AddFloat(enode->DoubleVal, false); + } + else if (enode->Type == TypeFloat32) + { + out.AddFloat(enode->DoubleVal, true); + } + else if (enode->Type == TypeName) + { + out.AddName(ENamedName(enode->IntVal)); + } + else if (enode->Type->isIntCompatible()) + { + out.AddInt(enode->IntVal, static_cast(enode->Type)->Unsigned); + } + out.Close(); +} + +static void PrintExprFuncCall(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExprFuncCall *enode = (ZCC_ExprFuncCall *)node; + assert(enode->Operation == PEX_FuncCall); + out.Open("expr-func-call"); + PrintNodes(out, enode->Function); + PrintNodes(out, enode->Parameters, false); + out.Close(); +} + +static void PrintExprClassCast(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ClassCast *enode = (ZCC_ClassCast *)node; + assert(enode->Operation == PEX_ClassCast); + out.Open("expr-class-cast"); + out.AddName(enode->ClassName); + PrintNodes(out, enode->Parameters, false); + out.Close(); +} + +static void PrintExprFunctionPtrCast(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_FunctionPtrCast *enode = (ZCC_FunctionPtrCast *)node; + assert(enode->Operation == PEX_FunctionPtrCast); + out.Open("expr-func-ptr-cast"); + PrintNodes(out, enode->PtrType, false); + PrintNodes(out, enode->Expr, false); + out.Close(); +} + +static void PrintStaticArray(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_StaticArrayStatement *enode = (ZCC_StaticArrayStatement *)node; + out.Open("static-array-stmt"); + PrintNodes(out, enode->Type, false); + out.AddName(enode->Id); + PrintNodes(out, enode->Values, false); + out.Close(); +} + +static void PrintExprMemberAccess(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; + assert(enode->Operation == PEX_MemberAccess); + out.Open("expr-member-access"); + PrintNodes(out, enode->Left); + out.AddName(enode->Right); + out.Close(); +} + +static void PrintExprUnary(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExprUnary *enode = (ZCC_ExprUnary *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->Operand, false); + out.Close(); +} + +static void PrintExprBinary(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExprBinary *enode = (ZCC_ExprBinary *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->Left); + PrintNodes(out, enode->Right); + out.Close(); +} + +static void PrintExprTrinary(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExprTrinary *enode = (ZCC_ExprTrinary *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->Test); + PrintNodes(out, enode->Left); + PrintNodes(out, enode->Right); + out.Close(); +} + +static void PrintVectorInitializer(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_VectorValue *enode = (ZCC_VectorValue *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->X); + PrintNodes(out, enode->Y); + PrintNodes(out, enode->Z); + PrintNodes(out, enode->W); + out.Close(); +} + +static void PrintFuncParam(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_FuncParm *pnode = (ZCC_FuncParm *)node; + out.Break(); + out.Open("func-parm"); + out.AddName(pnode->Label); + PrintNodes(out, pnode->Value, false); + out.Close(); +} + +static void PrintStatement(FLispString &out, const ZCC_TreeNode *node) +{ + out.Open("statement"); + out.Close(); +} + +static void PrintCompoundStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node; + out.Break(); + out.Open("compound-stmt"); + PrintNodes(out, snode->Content, false, true); + out.Close(); +} + +static void PrintDefault(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Default *snode = (ZCC_Default *)node; + out.Break(); + out.Open("default"); + PrintNodes(out, snode->Content, false, true); + out.Close(); +} + +static void PrintContinueStmt(FLispString &out, const ZCC_TreeNode *node) +{ + out.Break(); + out.Open("continue-stmt"); + out.Close(); +} + +static void PrintBreakStmt(FLispString &out, const ZCC_TreeNode *node) +{ + out.Break(); + out.Open("break-stmt"); + out.Close(); +} + +static void PrintReturnStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node; + out.Break(); + out.Open("return-stmt"); + PrintNodes(out, snode->Values, false); + out.Close(); +} + +static void PrintExpressionStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node; + out.Break(); + out.Open("expression-stmt"); + PrintNodes(out, snode->Expression, false); + out.Close(); +} + +static void PrintIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_IterationStmt *snode = (ZCC_IterationStmt *)node; + out.Break(); + out.Open("iteration-stmt"); + out.Add((snode->CheckAt == ZCC_IterationStmt::Start) ? "start" : "end"); + out.Break(); + PrintNodes(out, snode->LoopCondition); + out.Break(); + PrintNodes(out, snode->LoopBumper); + out.Break(); + PrintNodes(out, snode->LoopStatement); + out.Close(); +} + +static void PrintIfStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_IfStmt *snode = (ZCC_IfStmt *)node; + out.Break(); + out.Open("if-stmt"); + PrintNodes(out, snode->Condition); + out.Break(); + PrintNodes(out, snode->TruePath); + out.Break(); + PrintNodes(out, snode->FalsePath); + out.Close(); +} + +static void PrintSwitchStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_SwitchStmt *snode = (ZCC_SwitchStmt *)node; + out.Break(); + out.Open("switch-stmt"); + PrintNodes(out, snode->Condition); + out.Break(); + PrintNodes(out, snode->Content, false); + out.Close(); +} + +static void PrintCaseStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node; + out.Break(); + out.Open("case-stmt"); + PrintNodes(out, snode->Condition, false); + out.Close(); +} + +static void BadAssignOp(FLispString &out, int op) +{ + char buf[32]; + size_t len = mysnprintf(buf, countof(buf), "assign-op-%d", op); + out.Add(buf, len); +} + +static void PrintAssignStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_AssignStmt *snode = (ZCC_AssignStmt *)node; + out.Open("assign-stmt"); + PrintNodes(out, snode->Dests); + PrintNodes(out, snode->Sources); + out.Close(); +} + +static void PrintAssignDeclStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_AssignDeclStmt *snode = (ZCC_AssignDeclStmt *)node; + out.Open("assign-stmt-decl"); + PrintNodes(out, snode->Dests); + PrintNodes(out, snode->Sources); + out.Close(); +} + +static void PrintLocalVarStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node; + out.Open("local-var-stmt"); + PrintNodes(out, snode->Type); + PrintNodes(out, snode->Vars); + out.Close(); +} + +static void PrintFuncParamDecl(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_FuncParamDecl *dnode = (ZCC_FuncParamDecl *)node; + out.Break(); + out.Open("func-param-decl"); + PrintNodes(out, dnode->Type); + out.AddName(dnode->Name); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Default); + out.Close(); +} + +static void PrintConstantDef(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node; + out.Break(); + out.Open("constant-def"); + out.AddName(dnode->NodeName); + PrintNodes(out, dnode->Value, false); + out.Close(); +} + +static void PrintDeclarator(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_Declarator *dnode = (ZCC_Declarator *)node; + out.Break(); + out.Open("declarator"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Type); + out.Close(); +} + +static void PrintVarDeclarator(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node; + out.Break(); + out.Open("var-declarator"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Type); + PrintNodes(out, dnode->Names); + out.Close(); +} + +static void PrintFuncDeclarator(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node; + out.Break(); + out.Open("func-declarator"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->UseFlags); + PrintNodes(out, dnode->Type); + out.AddName(dnode->Name); + PrintNodes(out, dnode->Params); + PrintNodes(out, dnode->Body, false); + out.Close(); +} + +static void PrintDeclFlags(FLispString &out, const ZCC_TreeNode *node) +{ + auto dnode = (ZCC_DeclFlags *)node; + out.Break(); + out.Open("decl-flags"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Id); + out.Close(); +} + +static void PrintFlagStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto dnode = (ZCC_FlagStmt *)node; + out.Break(); + out.Open("flag-stmt"); + PrintNodes(out, dnode->name, false); + out.AddInt(dnode->set); + out.Close(); +} + +static void PrintPropertyStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto dnode = (ZCC_PropertyStmt *)node; + out.Break(); + out.Open("property-stmt"); + PrintNodes(out, dnode->Prop, false); + PrintNodes(out, dnode->Values, false); + out.Close(); +} + +static void PrintMixinDef(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_MixinDef *mdnode = (ZCC_MixinDef *)node; + out.Break(); + out.Open("mixin-def"); + out.AddName(mdnode->NodeName); + PrintNodes(out, mdnode->Body); + out.Close(); +} + +static void PrintMixinStmt(FLispString &out, const ZCC_TreeNode *node) +{ + ZCC_MixinStmt *msnode = (ZCC_MixinStmt *)node; + out.Break(); + out.Open("mixin-stmt"); + out.AddName(msnode->MixinName); + out.Close(); +} + +static void PrintArrayIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto inode = (ZCC_ArrayIterationStmt *)node; + out.Break(); + out.Open("array-iteration-stmt"); + PrintVarName(out, inode->ItName); + out.Break(); + PrintNodes(out, inode->ItArray); + out.Break(); + PrintNodes(out, inode->LoopStatement); + out.Close(); +} + +static void PrintTwoArgIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto inode = (ZCC_TwoArgIterationStmt *)node; + out.Break(); + out.Open("map-iteration-stmt"); + PrintVarName(out, inode->ItKey); + out.Break(); + PrintVarName(out, inode->ItValue); + out.Break(); + PrintNodes(out, inode->ItMap); + out.Break(); + PrintNodes(out, inode->LoopStatement); + out.Close(); +} + +static void PrintThreeArgIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto inode = (ZCC_ThreeArgIterationStmt *)node; + out.Break(); + out.Open("block-iteration-stmt"); + PrintVarName(out, inode->ItVar); + out.Break(); + PrintVarName(out, inode->ItPos); + out.Break(); + PrintVarName(out, inode->ItFlags); + out.Break(); + PrintNodes(out, inode->ItBlock); + out.Break(); + PrintNodes(out, inode->LoopStatement); + out.Close(); +} + +static void PrintTypedIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto inode = (ZCC_TypedIterationStmt *)node; + out.Break(); + out.Open("cast-iteration-stmt"); + PrintVarName(out, inode->ItType); + out.Break(); + PrintVarName(out, inode->ItVar); + out.Break(); + PrintNodes(out, inode->ItExpr); + out.Break(); + PrintNodes(out, inode->LoopStatement); + out.Close(); +} + +static const NodePrinterFunc TreeNodePrinter[] = +{ + PrintIdentifier, + PrintClass, + PrintStruct, + PrintEnum, + PrintEnumTerminator, + PrintStates, + PrintStatePart, + PrintStateLabel, + PrintStateStop, + PrintStateWait, + PrintStateFail, + PrintStateLoop, + PrintStateGoto, + PrintStateLine, + PrintVarName, + PrintVarInit, + PrintType, + PrintBasicType, + PrintMapType, + PrintMapIteratorType, + PrintDynArrayType, + PrintFuncPtrParamDecl, + PrintFuncPtrType, + PrintClassType, + PrintExpression, + PrintExprID, + PrintExprTypeRef, + PrintExprConstant, + PrintExprFuncCall, + PrintExprMemberAccess, + PrintExprUnary, + PrintExprBinary, + PrintExprTrinary, + PrintFuncParam, + PrintStatement, + PrintCompoundStmt, + PrintContinueStmt, + PrintBreakStmt, + PrintReturnStmt, + PrintExpressionStmt, + PrintIterationStmt, + PrintIfStmt, + PrintSwitchStmt, + PrintCaseStmt, + PrintAssignStmt, + PrintAssignDeclStmt, + PrintLocalVarStmt, + PrintFuncParamDecl, + PrintConstantDef, + PrintDeclarator, + PrintVarDeclarator, + PrintFuncDeclarator, + PrintDefault, + PrintFlagStmt, + PrintPropertyStmt, + PrintVectorInitializer, + PrintDeclFlags, + PrintExprClassCast, + PrintExprFunctionPtrCast, + PrintStaticArrayState, + PrintProperty, + PrintFlagDef, + PrintMixinDef, + PrintMixinStmt, + PrintArrayIterationStmt, + PrintTwoArgIterationStmt, + PrintThreeArgIterationStmt, + PrintTypedIterationStmt, +}; + +FString ZCC_PrintAST(const ZCC_TreeNode *root) +{ + FLispString out; + PrintNodes(out, root); + return out; +} + +static void PrintNode(FLispString &out, const ZCC_TreeNode *node) +{ + static_assert(countof(TreeNodePrinter) == NUM_AST_NODE_TYPES, "All AST node types should have printers defined for them"); + if (node->NodeType >= 0 && node->NodeType < NUM_AST_NODE_TYPES) + { + TreeNodePrinter[node->NodeType](out, node); + } + else + { + out.Open("unknown-node-type"); + out.AddInt(node->NodeType); + out.Close(); + } +} diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/common/scripting/frontend/zcc-parse.lemon similarity index 88% rename from src/scripting/zscript/zcc-parse.lemon rename to src/common/scripting/frontend/zcc-parse.lemon index 9bf5932cf68..199771949d3 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/common/scripting/frontend/zcc-parse.lemon @@ -78,6 +78,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) struct ClassFlagsBlock { VM_UWORD Flags; ZCC_Identifier *Replaces; + ZCC_Identifier *Sealed; VersionInfo Version; }; @@ -234,6 +235,7 @@ class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A). X = head; } + class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). { NEW_AST_NODE(Class,head,T); @@ -241,6 +243,7 @@ class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). head->ParentName = B; head->Flags = C.Flags; head->Replaces = C.Replaces; + head->Sealed = C.Sealed; head->Version = C.Version; head->Type = nullptr; head->Symbol = nullptr; @@ -252,13 +255,15 @@ class_ancestry(X) ::= . { X = NULL; } class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ } %type class_flags{ClassFlagsBlock} -class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; X.Version = {0,0}; } -class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; } -class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; } -class_flags(X) ::= class_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; X.Replaces = A.Replaces; } -class_flags(X) ::= class_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; X.Replaces = A.Replaces; } -class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; } -class_flags(X) ::= class_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Replaces = A.Replaces; X.Version = C.String->GetChars(); } +class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; X.Version = {0,0}; X.Sealed = NULL; } +class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed; } +class_flags(X) ::= class_flags(A) FINAL. { X.Flags = A.Flags | ZCC_Final; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed;} +class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed; } +class_flags(X) ::= class_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed; } +class_flags(X) ::= class_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = A.Sealed; } +class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; X.Version = A.Version; X.Sealed = A.Sealed; } +class_flags(X) ::= class_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Replaces = A.Replaces; X.Version = C.String->GetChars(); X.Sealed = A.Sealed; } +class_flags(X) ::= class_flags(A) SEALED LPAREN states_opt(B) RPAREN. { X.Flags = A.Flags | ZCC_Sealed; X.Replaces = A.Replaces; X.Version = A.Version; X.Sealed = B; } /*----- Dottable Identifier -----*/ // This can be either a single identifier or two identifiers connected by a . @@ -271,6 +276,13 @@ dottable_id(X) ::= IDENTIFIER(A). id->Id = A.Name(); X = id; } +// this is needed for defining properties named 'action'. +dottable_id(X) ::= ACTION(A). +{ + NEW_AST_NODE(Identifier,id,A); + id->Id = NAME_Action; + X = id; +} dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). { NEW_AST_NODE(Identifier,id2,A); @@ -366,6 +378,15 @@ flag_def(X) ::= FLAGDEF(T) IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) S X = def; } +flag_def(X) ::= FLAGDEF(T) INTERNAL IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) SEMICOLON. +{ + NEW_AST_NODE(FlagDef,def,T); + def->NodeName = A.Name(); + def->RefName = B.Name(); + def->BitValue = C.Int | 0x10000; + X = def; +} + identifier_list(X) ::= IDENTIFIER(A). { @@ -394,6 +415,17 @@ struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body X = def; } +struct_def(X) ::= EXTEND STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. +{ + NEW_AST_NODE(Struct,def,T); + def->NodeName = A.Name(); + def->Body = B; + def->Type = nullptr; + def->Symbol = nullptr; + def->Flags = ZCC_Extension; + X = def; +} + %type struct_flags{ClassFlagsBlock} struct_flags(X) ::= . { X.Flags = 0; X.Version = {0, 0}; } struct_flags(X) ::= struct_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; } @@ -414,6 +446,7 @@ struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ } +struct_member(X) ::= flag_def(A). { X = A; /*X-overwrites-A*/ } /*----- Constant Definition ------*/ /* Like UnrealScript, a constant's type is implied by its value's type. */ @@ -849,6 +882,7 @@ type_name1(X) ::= DOUBLE(T). { X.Int = ZCC_Float64; X.SourceLoc = T.SourceLoc //type_name1(X) ::= STRING(T). { X.Int = ZCC_String; X.SourceLoc = T.SourceLoc; } // [ZZ] it's handled elsewhere. this particular line only causes troubles in the form of String.Format being invalid. type_name1(X) ::= VECTOR2(T). { X.Int = ZCC_Vector2; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= VECTOR3(T). { X.Int = ZCC_Vector3; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= VECTOR4(T). { X.Int = ZCC_Vector4; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= NAME(T). { X.Int = ZCC_Name; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= SOUND(T). { X.Int = ZCC_Sound; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= STATE(T). { X.Int = ZCC_State; X.SourceLoc = T.SourceLoc; } @@ -919,7 +953,7 @@ type_name(X) ::= DOT dottable_id(A). /* Type names can also be used as identifiers in contexts where type names * are not normally allowed. */ %fallback IDENTIFIER - SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16 PROPERTY. + SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 VECTOR4 NAME MAP MAPITERATOR ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16 PROPERTY. /* Aggregate types */ %type aggregate_type {ZCC_Type *} @@ -931,7 +965,7 @@ type_name(X) ::= DOT dottable_id(A). %type array_size{ZCC_Expression *} %type array_size_expr{ZCC_Expression *} -aggregate_type(X) ::= MAP(T) LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash table */ +aggregate_type(X) ::= MAP(T) LT type_or_array(A) COMMA type_or_array(B) GT. /* ZSMap */ { NEW_AST_NODE(MapType,map,T); map->KeyType = A; @@ -939,6 +973,14 @@ aggregate_type(X) ::= MAP(T) LT type_or_array(A) COMMA type_or_array(B) GT. /* H X = map; } +aggregate_type(X) ::= MAPITERATOR(T) LT type_or_array(A) COMMA type_or_array(B) GT. /* ZSMapIterator */ +{ + NEW_AST_NODE(MapIteratorType,map_it,T); + map_it->KeyType = A; + map_it->ValueType = B; + X = map_it; +} + aggregate_type(X) ::= ARRAY(T) LT type_or_array(A) GT. /* TArray */ { NEW_AST_NODE(DynArrayType,arr,T); @@ -946,6 +988,71 @@ aggregate_type(X) ::= ARRAY(T) LT type_or_array(A) GT. /* TArray */ X = arr; } +aggregate_type(X) ::= func_ptr_type(A). { X = A; /*X-overwrites-A*/ } + +%type func_ptr_type {ZCC_FuncPtrType *} +%type func_ptr_params {ZCC_FuncPtrParamDecl *} +%type func_ptr_param_list {ZCC_FuncPtrParamDecl *} +%type func_ptr_param {ZCC_FuncPtrParamDecl *} + +//fn_ptr_flag(X) ::= . { X.Int = 0; } //implicit scope not allowed +fn_ptr_flag(X) ::= UI. { X.Int = ZCC_UIFlag; } +fn_ptr_flag(X) ::= PLAY. { X.Int = ZCC_Play; } +fn_ptr_flag(X) ::= CLEARSCOPE. { X.Int = ZCC_ClearScope; } +//fn_ptr_flag(X) ::= VIRTUALSCOPE. { X.Int = ZCC_VirtualScope; } //virtual scope not allowed + + +func_ptr_type(X) ::= FNTYPE(T) LT fn_ptr_flag(F) type_list_or_void(A) LPAREN func_ptr_params(B) RPAREN GT. /* Function<...(...)> */ +{ + NEW_AST_NODE(FuncPtrType,fn_ptr,T); + fn_ptr->RetType = A; + fn_ptr->Params = B; + fn_ptr->Scope = F.Int; + X = fn_ptr; +} + +func_ptr_type(X) ::= FNTYPE(T) LT VOID GT. /* Function */ +{ + NEW_AST_NODE(FuncPtrType,fn_ptr,T); + fn_ptr->RetType = nullptr; + fn_ptr->Params = nullptr; + fn_ptr->Scope = -1; + X = fn_ptr; +} + +func_ptr_params(X) ::= . /* empty */ { X = NULL; } +func_ptr_params(X) ::= VOID. { X = NULL; } +func_ptr_params(X) ::= func_ptr_param_list(X). + +// varargs function pointers not currently supported +//func_ptr_params(X) ::= func_ptr_param_list(A) COMMA ELLIPSIS. +//{ +// NEW_AST_NODE(FuncPtrParamDecl,parm,stat->sc->GetMessageLine()); +// parm->Type = nullptr; +// parm->Flags = 0; +// X = A; /*X-overwrites-A*/ +// AppendTreeNodeSibling(X, parm); +//} + +func_ptr_param_list(X) ::= func_ptr_param(X). +func_ptr_param_list(X) ::= func_ptr_param_list(A) COMMA func_ptr_param(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } + +func_ptr_param(X) ::= func_param_flags(A) type(B). +{ + NEW_AST_NODE(FuncPtrParamDecl,parm,A.SourceLoc ? A.SourceLoc : B->SourceLoc); + parm->Type = B; + parm->Flags = A.Int; + X = parm; +} + +func_ptr_param(X) ::= func_param_flags(A) type(B) AND. +{ + NEW_AST_NODE(FuncPtrParamDecl,parm,A.SourceLoc ? A.SourceLoc : B->SourceLoc); + parm->Type = B; + parm->Flags = A.Int | ZCC_Out; + X = parm; +} + aggregate_type(X) ::= CLASS(T) class_restrictor(A). /* class */ { NEW_AST_NODE(ClassType,cls,T); @@ -1202,6 +1309,7 @@ decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc decl_flag(X) ::= INTERNAL(T). { X.Int = ZCC_Internal; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= OVERRIDE(T). { X.Int = ZCC_Override; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= ABSTRACT(T). { X.Int = ZCC_Abstract; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= VARARG(T). { X.Int = ZCC_VarArg; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= UI(T). { X.Int = ZCC_UIFlag; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= PLAY(T). { X.Int = ZCC_Play; X.SourceLoc = T.SourceLoc; } @@ -1256,6 +1364,26 @@ func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C) EQ expr(D). X = parm; } +func_param(X) ::= func_param_flags(A) type(B) AND IDENTIFIER(C). +{ + NEW_AST_NODE(FuncParamDecl,parm,A.SourceLoc ? A.SourceLoc : B->SourceLoc); + parm->Type = B; + parm->Name = C.Name(); + parm->Flags = A.Int | ZCC_Out; + parm->Default = nullptr; + X = parm; +} + +func_param(X) ::= func_param_flags(A) type(B) AND IDENTIFIER(C) EQ expr(D). +{ + NEW_AST_NODE(FuncParamDecl,parm,A.SourceLoc ? A.SourceLoc : B->SourceLoc); + parm->Type = B; + parm->Name = C.Name(); + parm->Flags = A.Int | ZCC_Out; + parm->Default = D; + X = parm; +} + func_param_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; } func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X.SourceLoc = T.SourceLoc; } func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = T.SourceLoc; } @@ -1290,6 +1418,17 @@ primary(X) ::= SUPER(T). X = expr; } primary(X) ::= constant(A). { X = A; /*X-overwrites-A*/ } +primary(XX) ::= LPAREN expr(A) COMMA expr(B) COMMA expr(C) COMMA expr(D) RPAREN. [DOT] +{ + NEW_AST_NODE(VectorValue, expr, A); + expr->Operation = PEX_Vector; + expr->Type = TypeVector4; + expr->X = A; + expr->Y = B; + expr->Z = C; + expr->W = D; + XX = expr; +} primary(XX) ::= LPAREN expr(A) COMMA expr(B) COMMA expr(C) RPAREN. [DOT] { NEW_AST_NODE(VectorValue, expr, A); @@ -1298,6 +1437,7 @@ primary(XX) ::= LPAREN expr(A) COMMA expr(B) COMMA expr(C) RPAREN. [DOT] expr->X = A; expr->Y = B; expr->Z = C; + expr->W = nullptr; XX = expr; } primary(XX) ::= LPAREN expr(A) COMMA expr(B) RPAREN. [DOT] @@ -1308,6 +1448,7 @@ primary(XX) ::= LPAREN expr(A) COMMA expr(B) RPAREN. [DOT] expr->X = A; expr->Y = B; expr->Z = nullptr; + expr->W = nullptr; XX = expr; } primary(X) ::= LPAREN expr(A) RPAREN. @@ -1332,6 +1473,17 @@ primary(X) ::= LPAREN CLASS LT IDENTIFIER(A) GT RPAREN LPAREN func_expr_list(B) expr->Parameters = B; X = expr; } + +primary(X) ::= LPAREN func_ptr_type(A) RPAREN LPAREN expr(B) RPAREN. [DOT] // function pointer type cast +{ + NEW_AST_NODE(FunctionPtrCast, expr, A); + expr->Operation = PEX_FunctionPtrCast; + A->ArraySize = NULL; + expr->PtrType = A; + expr->Expr = B; + X = expr; +} + primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access { NEW_AST_NODE(ExprBinary, expr, B); @@ -1341,6 +1493,7 @@ primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access expr->Right = B; X = expr; } + primary(X) ::= primary(A) DOT IDENTIFIER(B). // Member access { NEW_AST_NODE(ExprMemberAccess, expr, B); @@ -1802,8 +1955,13 @@ statement(X) ::= compound_statement(A). { X = A; /*X-overwrites-A*/ } statement(X) ::= expression_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= selection_statement(X). statement(X) ::= iteration_statement(X). +statement(X) ::= array_iteration_statement(X). +statement(X) ::= two_arg_iteration_statement(X). +statement(X) ::= three_arg_iteration_statement(X). +statement(X) ::= typed_iteration_statement(X). statement(X) ::= jump_statement(X). statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } +statement(X) ::= assign_decl_statement(A) SEMICOLON.{ X = A; /*X-overwrites-A*/ } statement(X) ::= local_var(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= error SEMICOLON. { X = NULL; } statement(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ } @@ -1959,6 +2117,54 @@ iteration_statement(X) ::= FOR(T) LPAREN for_init(IN) SEMICOLON opt_expr(EX) SEM X = wrap; } +%type array_iteration_statement{ZCC_Statement *} + +array_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(IN) COLON expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(ArrayIterationStmt, iter, T); + iter->ItName = IN; + iter->ItArray = EX; + iter->LoopStatement = ST; + X = iter; +} + +%type two_arg_iteration_statement{ZCC_Statement *} + +two_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variable_name(VAL) COLON expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(TwoArgIterationStmt, iter, T); + iter->ItKey = KEY; + iter->ItValue = VAL; + iter->ItMap = EX; + iter->LoopStatement = ST; + X = iter; +} + +%type three_arg_iteration_statement{ZCC_Statement *} + +three_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA variable_name(POS) COMMA variable_name(FLAGS) COLON expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(ThreeArgIterationStmt, iter, T); + iter->ItVar = VAR; + iter->ItPos = POS; + iter->ItFlags = FLAGS; + iter->ItBlock = EX; + iter->LoopStatement = ST; + X = iter; +} + +%type typed_iteration_statement{ZCC_Statement *} + +typed_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(TYPE) variable_name(VAR) COLON expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(TypedIterationStmt, iter, T); + iter->ItType = TYPE; + iter->ItVar = VAR; + iter->ItExpr = EX; + iter->LoopStatement = ST; + X = iter; +} + while_or_until(X) ::= WHILE(T). { X.Int = ZCC_WHILE; @@ -2051,6 +2257,17 @@ assign_statement(X) ::= LBRACKET expr_list(A) RBRACKET EQ expr(B). [EQ] X = stmt; } +%type assign_decl_statement{ZCC_AssignDeclStmt *} + +assign_decl_statement(X) ::= LET LBRACKET identifier_list(A) RBRACKET EQ expr(B). [EQ] +{ + NEW_AST_NODE(AssignDeclStmt,stmt,A); + stmt->AssignOp = ZCC_EQ; + stmt->Dests = A; + stmt->Sources = B; + X = stmt; +} + /*----- Local Variable Definition "Statements" -----*/ %type local_var{ZCC_LocalVarStmt *} diff --git a/src/common/scripting/frontend/zcc_compile.cpp b/src/common/scripting/frontend/zcc_compile.cpp new file mode 100644 index 00000000000..d109717a32f --- /dev/null +++ b/src/common/scripting/frontend/zcc_compile.cpp @@ -0,0 +1,3608 @@ +/* +** zcc_compile.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_console.h" +#include "filesystem.h" +#include "zcc_parser.h" +#include "zcc-parse.h" +#include "zcc_compile.h" +#include "printf.h" +#include "symbols.h" + +FSharedStringArena VMStringConstants; + + +static bool ShouldWrapPointer(PType * type) +{ + return ((type->isStruct() && type != TypeVector2 && type != TypeVector3 && type != TypeVector4 && type != TypeQuaternion && type != TypeFVector2 && type != TypeFVector3 && type != TypeFVector4 && type != TypeFQuaternion) || type->isDynArray() || type->isMap() || type->isMapIterator()); +} + +int GetIntConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxIntCast(ex, false); + ex = ex->Resolve(ctx); + return ex ? static_cast(ex)->GetValue().GetInt() : 0; +} + +double GetFloatConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxFloatCast(ex); + ex = ex->Resolve(ctx); + return ex ? static_cast(ex)->GetValue().GetFloat() : 0; +} + +VMFunction* GetFuncConst(FxExpression* ex, FCompileContext& ctx) +{ + ex = new FxTypeCast(ex, TypeVMFunction, false); + ex = ex->Resolve(ctx); + return static_cast(ex ? static_cast(ex)->GetValue().GetPointer() : nullptr); +} + +const char * ZCCCompiler::GetStringConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxStringCast(ex); + ex = ex->Resolve(ctx); + if (!ex) return ""; + // The string here must be stored in a persistent place that lasts long enough to have it processed. + return AST.Strings.Alloc(static_cast(ex)->GetValue().GetString())->GetChars(); +} + +int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls) +{ + FCompileContext ctx(OutNamespace, cls, false, mVersion); + FxExpression *ex = new FxIntCast(ConvertNode(node), false); + ex = ex->Resolve(ctx); + if (ex == nullptr) return 0; + if (!ex->isConstant()) + { + ex->ScriptPosition.Message(MSG_ERROR, "Expression is not constant"); + return 0; + } + return static_cast(ex)->GetValue().GetInt(); +} + +FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls) +{ + FCompileContext ctx(OutNamespace, cls, false, mVersion); + FxExpression *ex = new FxStringCast(ConvertNode(node)); + ex = ex->Resolve(ctx); + if (ex == nullptr) return ""; + if (!ex->isConstant()) + { + ex->ScriptPosition.Message(MSG_ERROR, "Expression is not constant"); + return ""; + } + return static_cast(ex)->GetValue().GetString(); +} + +ZCC_MixinDef *ZCCCompiler::ResolveMixinStmt(ZCC_MixinStmt *mixinStmt, EZCCMixinType type) +{ + for (auto mx : Mixins) + { + if (mx->mixin->NodeName == mixinStmt->MixinName) + { + if (mx->mixin->MixinType != type) + { + Error(mixinStmt, "Mixin %s is a %s mixin cannot be used here.", FName(mixinStmt->MixinName).GetChars(), GetMixinTypeString(type)); + return nullptr; + } + + return mx->mixin; + } + } + + Error(mixinStmt, "Mixin %s does not exist.", FName(mixinStmt->MixinName).GetChars()); + + return nullptr; +} + + +//========================================================================== +// +// ZCCCompiler :: ProcessClass +// +//========================================================================== + +void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) +{ + ZCC_ClassWork *cls = nullptr; + // If this is a class extension, put the new node directly into the existing class. + if (cnode->Flags == ZCC_Extension) + { + for (auto clss : Classes) + { + if (clss->NodeName() == cnode->NodeName) + { + cls = clss; + break; + } + } + if (cls == nullptr) + { + Error(cnode, "Class %s cannot be found in the current translation unit.", FName(cnode->NodeName).GetChars()); + return; + } + } + else + { + Classes.Push(new ZCC_ClassWork(static_cast(cnode), treenode)); + cls = Classes.Last(); + } + + auto node = cnode->Body; + PSymbolTreeNode *childnode; + ZCC_Enum *enumType = nullptr; + + // [pbeta] Handle mixins here for the sake of simplifying things. + if (node != nullptr) + { + bool mixinError = false; + TArray mixinStmts; + mixinStmts.Clear(); + + // Gather all mixin statement nodes. + do + { + if (node->NodeType == AST_MixinStmt) + { + mixinStmts.Push(static_cast(node)); + } + + node = node->SiblingNext; + } + while (node != cnode->Body); + + for (auto mixinStmt : mixinStmts) + { + ZCC_MixinDef *mixinDef = ResolveMixinStmt(mixinStmt, ZCC_Mixin_Class); + + if (mixinDef == nullptr) + { + mixinError = true; + continue; + } + + // Insert the mixin if there's a body. If not, just remove this node. + if (mixinDef->Body != nullptr) + { + auto newNode = TreeNodeDeepCopy(&AST, mixinDef->Body, true); + + if (mixinStmt->SiblingNext != mixinStmt && mixinStmt->SiblingPrev != mixinStmt) + { + auto prevSibling = mixinStmt->SiblingPrev; + auto nextSibling = mixinStmt->SiblingNext; + + auto newFirst = newNode; + auto newLast = newNode->SiblingPrev; + + newFirst->SiblingPrev = prevSibling; + newLast->SiblingNext = nextSibling; + + prevSibling->SiblingNext = newFirst; + nextSibling->SiblingPrev = newLast; + } + + if (cnode->Body == mixinStmt) + { + cnode->Body = newNode; + } + } + else + { + if (mixinStmt->SiblingNext != mixinStmt && mixinStmt->SiblingPrev != mixinStmt) + { + auto prevSibling = mixinStmt->SiblingPrev; + auto nextSibling = mixinStmt->SiblingNext; + + prevSibling->SiblingNext = nextSibling; + nextSibling->SiblingPrev = prevSibling; + + if (cnode->Body == mixinStmt) + { + cnode->Body = nextSibling; + } + } + else if (cnode->Body == mixinStmt) + { + cnode->Body = nullptr; + } + } + } + + mixinStmts.Clear(); + + if (mixinError) + { + return; + } + } + + node = cnode->Body; + + // Need to check if the class actually has a body. + if (node != nullptr) do + { + switch (node->NodeType) + { + case AST_MixinStmt: + assert(0 && "Unhandled mixin statement in class parsing loop. If this has been reached, something is seriously wrong"); + Error(node, "Internal mixin error."); + break; + + case AST_Struct: + case AST_ConstantDef: + case AST_Enum: + if ((childnode = AddTreeNode(static_cast(node)->NodeName, node, &cls->TreeNodes))) + { + switch (node->NodeType) + { + case AST_Enum: + enumType = static_cast(node); + cls->Enums.Push(enumType); + break; + + case AST_Struct: + if (static_cast(node)->Flags & VARF_Native) + { + Error(node, "Cannot define native structs inside classes"); + static_cast(node)->Flags &= ~VARF_Native; + } + ProcessStruct(static_cast(node), childnode, cls->cls); + break; + + case AST_ConstantDef: + cls->Constants.Push(static_cast(node)); + cls->Constants.Last()->Type = enumType; + break; + + default: + assert(0 && "Default case is just here to make GCC happy. It should never be reached"); + } + } + break; + + case AST_Property: + cls->Properties.Push(static_cast(node)); + break; + + case AST_FlagDef: + cls->FlagDefs.Push(static_cast(node)); + break; + + case AST_VarDeclarator: + cls->Fields.Push(static_cast(node)); + break; + + case AST_EnumTerminator: + enumType = nullptr; + break; + + case AST_States: + cls->States.Push(static_cast(node)); + break; + + case AST_FuncDeclarator: + cls->Functions.Push(static_cast(node)); + break; + + case AST_Default: + cls->Defaults.Push(static_cast(node)); + break; + + case AST_StaticArrayStatement: + if (AddTreeNode(static_cast(node)->Id, node, &cls->TreeNodes)) + { + cls->Arrays.Push(static_cast(node)); + } + break; + + default: + assert(0 && "Unhandled AST node type"); + break; + } + + node = node->SiblingNext; + } + while (node != cnode->Body); +} + +//========================================================================== +// +// ZCCCompiler :: ProcessMixin +// +//========================================================================== + +void ZCCCompiler::ProcessMixin(ZCC_MixinDef *cnode, PSymbolTreeNode *treenode) +{ + ZCC_MixinWork *cls = new ZCC_MixinWork(cnode, treenode); + + auto node = cnode->Body; + + // Need to check if the mixin actually has a body. + if (node != nullptr) do + { + if (cnode->MixinType == ZCC_Mixin_Class) + { + switch (node->NodeType) + { + case AST_Struct: + case AST_ConstantDef: + case AST_Enum: + case AST_Property: + case AST_FlagDef: + case AST_VarDeclarator: + case AST_EnumTerminator: + case AST_States: + case AST_FuncDeclarator: + case AST_Default: + case AST_StaticArrayStatement: + break; + + default: + assert(0 && "Unhandled AST node type"); + break; + } + } + + node = node->SiblingNext; + } while (node != cnode->Body); + + Mixins.Push(cls); +} + +//========================================================================== +// +// ZCCCompiler :: ProcessStruct +// +//========================================================================== + +void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZCC_Class *outer) +{ + ZCC_StructWork* cls = nullptr; + + // If this is a struct extension, put the new node directly into the existing class. + if (cnode->Flags == ZCC_Extension) + { + for (auto strct : Structs) + { + if (strct->NodeName() == cnode->NodeName) + { + cls = strct; + break; + } + } + if (cls == nullptr) + { + Error(cnode, "Struct %s cannot be found in the current translation unit.", FName(cnode->NodeName).GetChars()); + return; + } + } + else + { + Structs.Push(new ZCC_StructWork(static_cast(cnode), treenode, outer)); + cls = Structs.Last(); + } + + auto node = cnode->Body; + PSymbolTreeNode *childnode; + ZCC_Enum *enumType = nullptr; + + // Need to check if the struct actually has a body. + if (node != nullptr) do + { + switch (node->NodeType) + { + case AST_ConstantDef: + case AST_Enum: + if ((childnode = AddTreeNode(static_cast(node)->NodeName, node, &cls->TreeNodes))) + { + switch (node->NodeType) + { + case AST_Enum: + enumType = static_cast(node); + cls->Enums.Push(enumType); + break; + + case AST_ConstantDef: + cls->Constants.Push(static_cast(node)); + cls->Constants.Last()->Type = enumType; + break; + + default: + assert(0 && "Default case is just here to make GCC happy. It should never be reached"); + } + } + break; + + case AST_VarDeclarator: + cls->Fields.Push(static_cast(node)); + break; + + case AST_FuncDeclarator: + cls->Functions.Push(static_cast(node)); + break; + + case AST_EnumTerminator: + enumType = nullptr; + break; + + case AST_StaticArrayStatement: + if (AddTreeNode(static_cast(node)->Id, node, &cls->TreeNodes)) + { + cls->Arrays.Push(static_cast(node)); + } + break; + + case AST_FlagDef: + cls->FlagDefs.Push(static_cast(node)); + break; + + + default: + assert(0 && "Unhandled AST node type"); + break; + } + node = node->SiblingNext; + } + while (node != cnode->Body); +} + +//========================================================================== +// +// ZCCCompiler Constructor +// +//========================================================================== + +ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PNamespace *_outnamespc, int lumpnum, const VersionInfo &ver) + : mVersion(ver), Outer(_outer), ConvertClass(nullptr), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), Lump(lumpnum) +{ + FScriptPosition::ResetErrorCounter(); + // Group top-level nodes by type + if (ast.TopNode != NULL) + { + ZCC_TreeNode *node = ast.TopNode; + PSymbolTreeNode *tnode = nullptr; + + // [pbeta] Anything that must be processed before classes, structs, etc. should go here. + do + { + switch (node->NodeType) + { + // [pbeta] Mixins must be processed before everything else. + case AST_MixinDef: + if ((tnode = AddTreeNode(static_cast(node)->NodeName, node, GlobalTreeNodes))) + { + ProcessMixin(static_cast(node), tnode); + break; + } + break; + + default: + break; // Shut GCC up. + } + node = node->SiblingNext; + } while (node != ast.TopNode); + + node = ast.TopNode; + PType *enumType = nullptr; + ZCC_Enum *zenumType = nullptr; + + do + { + switch (node->NodeType) + { + case AST_MixinDef: + // [pbeta] We already processed mixins, ignore them here. + break; + + case AST_Class: + // a class extension should not check the tree node symbols. + if (static_cast(node)->Flags == ZCC_Extension) + { + ProcessClass(static_cast(node), tnode); + break; + } + goto common; + case AST_Struct: + if (static_cast(node)->Flags == ZCC_Extension) + { + ProcessStruct(static_cast(node), tnode, nullptr); + break; + } + goto common; + + common: + case AST_ConstantDef: + case AST_Enum: + if ((tnode = AddTreeNode(static_cast(node)->NodeName, node, GlobalTreeNodes))) + { + switch (node->NodeType) + { + case AST_Enum: + zenumType = static_cast(node); + enumType = NewEnum(zenumType->NodeName, OutNamespace); + OutNamespace->Symbols.AddSymbol(Create(zenumType->NodeName, enumType)); + break; + + case AST_Class: + ProcessClass(static_cast(node), tnode); + break; + + case AST_Struct: + ProcessStruct(static_cast(node), tnode, nullptr); + break; + + case AST_ConstantDef: + Constants.Push(static_cast(node)); + Constants.Last()->Type = zenumType; + break; + + default: + assert(0 && "Default case is just here to make GCC happy. It should never be reached"); + } + } + break; + + case AST_EnumTerminator: + zenumType = nullptr; + break; + + default: + assert(0 && "Unhandled AST node type"); + break; + } + node = node->SiblingNext; + } while (node != ast.TopNode); + } +} + +ZCCCompiler::~ZCCCompiler() +{ + for (auto s : Structs) + { + delete s; + } + for (auto c : Classes) + { + delete c; + } + Structs.Clear(); + Classes.Clear(); +} + +//========================================================================== +// +// ZCCCompiler :: AddTreeNode +// +// Keeps track of definition nodes by their names. Ensures that all names +// in this scope are unique. +// +//========================================================================== + +PSymbolTreeNode *ZCCCompiler::AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents) +{ + PSymbol *check = treenodes->FindSymbol(name, searchparents); + if (check != NULL) + { + assert(check->IsA(RUNTIME_CLASS(PSymbolTreeNode))); + Error(node, "Attempt to redefine '%s'", name.GetChars()); + Error(static_cast(check)->Node, " Original definition is here"); + return nullptr; + } + else + { + auto sy = Create(name, node); + treenodes->AddSymbol(sy); + return sy; + } +} + +//========================================================================== +// +// ZCCCompiler :: Warn +// +// Prints a warning message, and increments WarnCount. +// +//========================================================================== + +void ZCCCompiler::Warn(ZCC_TreeNode *node, const char *msg, ...) +{ + va_list argptr; + va_start(argptr, msg); + MessageV(node, TEXTCOLOR_ORANGE, msg, argptr); + va_end(argptr); + + FScriptPosition::WarnCounter++; +} + +//========================================================================== +// +// ZCCCompiler :: Error +// +// Prints an error message, and increments ErrorCount. +// +//========================================================================== + +void ZCCCompiler::Error(ZCC_TreeNode *node, const char *msg, ...) +{ + va_list argptr; + va_start(argptr, msg); + MessageV(node, TEXTCOLOR_RED, msg, argptr); + va_end(argptr); + + FScriptPosition::ErrorCounter++; +} + +//========================================================================== +// +// ZCCCompiler :: MessageV +// +// Prints a message, annotated with the source location for the tree node. +// +//========================================================================== + +void ZCCCompiler::MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr) +{ + FString composed; + + composed.Format("%s%s, line %d: ", txtcolor, node->SourceName->GetChars(), node->SourceLoc); + composed.VAppendFormat(msg, argptr); + composed += '\n'; + PrintString(PRINT_HIGH, composed.GetChars()); +} + +//========================================================================== +// +// ZCCCompiler :: Compile +// +// Compile everything defined at this level. +// This can be overridden to add custom content. +// +//========================================================================== + +int ZCCCompiler::Compile() +{ + CreateClassTypes(); + CreateStructTypes(); + CompileAllConstants(); + CompileAllFields(); + InitDefaults(); + InitFunctions(); + return FScriptPosition::ErrorCounter; +} + +//========================================================================== +// +// ZCCCompiler :: CreateStructTypes +// +// Creates a PStruct for every struct. +// +//========================================================================== + +void ZCCCompiler::CreateStructTypes() +{ + for(auto s : Structs) + { + PTypeBase *outer; + PSymbolTable *syms; + + s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); + if (s->Outer) + { + outer = s->Outer->VMType; + syms = &s->Outer->VMType->Symbols; + } + else + { + outer = OutNamespace; + syms = &OutNamespace->Symbols; + } + + if (s->NodeName() == NAME__ && fileSystem.GetFileContainer(Lump) == 0) + { + // This is just a container for syntactic purposes. + s->strct->Type = nullptr; + continue; + } + else if (s->strct->Flags & ZCC_Native) + { + s->strct->Type = NewStruct(s->NodeName(), outer, true, AST.FileNo); + } + else + { + s->strct->Type = NewStruct(s->NodeName(), outer, false, AST.FileNo); + } + if (s->strct->Flags & ZCC_Version) + { + s->strct->Type->mVersion = s->strct->Version; + } + + auto &sf = s->Type()->ScopeFlags; + if (mVersion >= MakeVersion(2, 4, 0)) + { + if ((s->strct->Flags & (ZCC_UIFlag | ZCC_Play)) == (ZCC_UIFlag | ZCC_Play)) + { + Error(s->strct, "Struct %s has incompatible flags", s->NodeName().GetChars()); + } + + if (outer != OutNamespace) sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::SideFromObjectFlags(static_cast(outer)->ScopeFlags)); + else if (s->strct->Flags & ZCC_ClearScope) Warn(s->strct, "Useless 'ClearScope' on struct %s not inside a class", s->NodeName().GetChars()); + if (s->strct->Flags & ZCC_UIFlag) + sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::Side_UI); + if (s->strct->Flags & ZCC_Play) + sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::Side_Play); + if (s->strct->Flags & ZCC_ClearScope) + sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::Side_PlainData); // don't inherit the scope from the outer class + } + else + { + // old versions force 'play'. + sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::Side_Play); + } + s->strct->Symbol = Create(s->NodeName(), s->Type()); + syms->AddSymbol(s->strct->Symbol); + + for (auto e : s->Enums) + { + auto etype = NewEnum(e->NodeName, s->Type()); + s->Type()->Symbols.AddSymbol(Create(e->NodeName, etype)); + } + } +} + +//========================================================================== +// +// ZCCCompiler :: CreateClassTypes +// +// Creates a PClass for every class so that we get access to the symbol table +// These will be created with unknown size because for that we need to +// process all fields first, but to do that we need the PClass and some +// other info depending on the PClass. +// +//========================================================================== + +void ZCCCompiler::CreateClassTypes() +{ + // we are going to sort the classes array so that entries are sorted in order of inheritance. + + auto OrigClasses = std::move(Classes); + Classes.Clear(); + bool donesomething = true; + while (donesomething) + { + donesomething = false; + for (unsigned i = 0; icls->ParentName; + + if (ParentName != nullptr && ParentName->SiblingNext == ParentName) + { + parent = PClass::FindClass(ParentName->Id); + } + else if (ParentName == nullptr) + { + parent = RUNTIME_CLASS(DObject); + } + else + { + // The parent is a dotted name which the type system currently does not handle. + // Once it does this needs to be implemented here. + auto p = ParentName; + FString build; + + do + { + if (build.IsNotEmpty()) build += '.'; + build += FName(p->Id).GetChars(); + p = static_cast(p->SiblingNext); + } while (p != ParentName); + Error(c->cls, "Qualified name '%s' for base class not supported in '%s'", build.GetChars(), FName(c->NodeName()).GetChars()); + parent = RUNTIME_CLASS(DObject); + } + + if (parent != nullptr && (parent->VMType != nullptr || c->NodeName() == NAME_Object)) + { + if(parent->bFinal) + { + Error(c->cls, "Class '%s' cannot extend final class '%s'", FName(c->NodeName()).GetChars(), parent->TypeName.GetChars()); + } + else if(parent->bSealed && !parent->SealedRestriction.Contains(c->NodeName())) + { + Error(c->cls, "Class '%s' cannot extend sealed class '%s'", FName(c->NodeName()).GetChars(), parent->TypeName.GetChars()); + } + + // The parent exists, we may create a type for this class + if (c->cls->Flags & ZCC_Native) + { + // If this is a native class, its own type must also already exist and not be a runtime class. + auto me = PClass::FindClass(c->NodeName()); + if (me == nullptr) + { + Error(c->cls, "Unknown native class %s", c->NodeName().GetChars()); + // Create a placeholder so that the compiler can continue looking for errors. + me = parent->FindClassTentative(c->NodeName()); + } + else if (me->bRuntimeClass) + { + Error(c->cls, "%s is not a native class", c->NodeName().GetChars()); + } + else + { + DPrintf(DMSG_SPAMMY, "Registered %s as native with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars()); + } + c->cls->Type = NewClassType(me, AST.FileNo); + me->SourceLumpName = *c->cls->SourceName; + } + else + { + // We will never get here if the name is a duplicate, so we can just do the assignment. + try + { + if (parent->VMType->mVersion > mVersion) + { + Error(c->cls, "Parent class %s of %s not accessible to ZScript version %d.%d.%d", parent->TypeName.GetChars(), c->NodeName().GetChars(), mVersion.major, mVersion.minor, mVersion.revision); + } + auto newclass = parent->CreateDerivedClass(c->NodeName(), TentativeClass, nullptr, AST.FileNo); + if (newclass == nullptr) + { + Error(c->cls, "Class name %s already exists", c->NodeName().GetChars()); + } + else + { + c->cls->Type = NewClassType(newclass, AST.FileNo); + DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->ClassType()->ParentClass->TypeName.GetChars()); + } + } + catch (CRecoverableError &err) + { + Error(c->cls, "%s", err.GetMessage()); + c->cls->Type = nullptr; + } + } + if (c->Type() == nullptr) + { + // create a placeholder so that the compiler can continue looking for errors. + c->cls->Type = NewClassType(parent->FindClassTentative(c->NodeName()), AST.FileNo); + } + + if (c->cls->Flags & ZCC_Abstract) + c->ClassType()->bAbstract = true; + + if (c->cls->Flags & ZCC_Version) + { + c->Type()->mVersion = c->cls->Version; + } + + + if (c->cls->Flags & ZCC_Final) + { + c->ClassType()->bFinal = true; + } + + if (c->cls->Flags & ZCC_Sealed) + { + PClass * ccls = c->ClassType(); + ccls->bSealed = true; + ZCC_Identifier * it = c->cls->Sealed; + if(it) do + { + ccls->SealedRestriction.Push(FName(it->Id)); + it = (ZCC_Identifier*) it->SiblingNext; + } + while(it != c->cls->Sealed); + } + // + if (mVersion >= MakeVersion(2, 4, 0)) + { + static int incompatible[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope }; + int incompatiblecnt = 0; + for (size_t k = 0; k < countof(incompatible); k++) + if (incompatible[k] & c->cls->Flags) incompatiblecnt++; + + if (incompatiblecnt > 1) + { + Error(c->cls, "Class %s has incompatible flags", c->NodeName().GetChars()); + } + + if (c->cls->Flags & ZCC_UIFlag) + c->Type()->ScopeFlags = EScopeFlags((c->Type()->ScopeFlags&~Scope_Play) | Scope_UI); + if (c->cls->Flags & ZCC_Play) + c->Type()->ScopeFlags = EScopeFlags((c->Type()->ScopeFlags&~Scope_UI) | Scope_Play); + if (parent->VMType->ScopeFlags & (Scope_UI | Scope_Play)) // parent is either ui or play + { + if (c->cls->Flags & (ZCC_UIFlag | ZCC_Play)) + { + Error(c->cls, "Can't change class scope in class %s", c->NodeName().GetChars()); + } + c->Type()->ScopeFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ScopeFlags, FScopeBarrier::SideFromObjectFlags(parent->VMType->ScopeFlags)); + } + } + else + { + c->Type()->ScopeFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ScopeFlags, FScopeBarrier::Side_Play); + } + + c->cls->Symbol = Create(c->NodeName(), c->Type()); + OutNamespace->Symbols.AddSymbol(c->cls->Symbol); + Classes.Push(c); + OrigClasses.Delete(i--); + donesomething = true; + } + else if (c->cls->ParentName != nullptr) + { + // No base class found. Now check if something in the unprocessed classes matches. + // If not, print an error. If something is found let's retry again in the next iteration. + bool found = false; + for (auto d : OrigClasses) + { + if (d->NodeName() == c->cls->ParentName->Id) + { + found = true; + break; + } + } + if (!found) + { + Error(c->cls, "Class %s has unknown base class %s", c->NodeName().GetChars(), FName(c->cls->ParentName->Id).GetChars()); + // create a placeholder so that the compiler can continue looking for errors. + c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()), AST.FileNo); + c->cls->Symbol = Create(c->NodeName(), c->Type()); + OutNamespace->Symbols.AddSymbol(c->cls->Symbol); + Classes.Push(c); + OrigClasses.Delete(i--); + donesomething = true; + } + } + } + } + + // What's left refers to some other class in the list but could not be resolved. + // This normally means a circular reference. + for (auto c : OrigClasses) + { + Error(c->cls, "Class %s has circular inheritance", FName(c->NodeName()).GetChars()); + c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()), AST.FileNo); + c->cls->Symbol = Create(c->NodeName(), c->Type()); + OutNamespace->Symbols.AddSymbol(c->cls->Symbol); + Classes.Push(c); + } + + // Last but not least: Now that all classes have been created, we can create the symbols for the internal enums and link the treenode symbol tables. + for (auto cd : Classes) + { + for (auto e : cd->Enums) + { + auto etype = NewEnum(e->NodeName, cd->Type()); + cd->Type()->Symbols.AddSymbol(Create(e->NodeName, etype)); + } + // Link the tree node tables. We only can do this after we know the class relations. + for (auto cc : Classes) + { + if (cc->ClassType() == cd->ClassType()->ParentClass) + { + cd->TreeNodes.SetParentTable(&cc->TreeNodes); + break; + } + } + } +} + +//========================================================================== +// +// ZCCCompiler :: AddConstants +// +// Helper for CompileAllConstants +// +//========================================================================== + +void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PContainerType *cls, PSymbolTable *ot) +{ + for (auto c : Constants) + { + dest.Push({ c, cls, ot }); + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileAllConstants +// +// Make symbols from every constant defined at all levels. +// Since constants may only depend on other constants this can be done +// without any more involved processing of the AST as a first step. +// +//========================================================================== + +void ZCCCompiler::CompileAllConstants() +{ + // put all constants in one list to make resolving this easier. + TArray constantwork; + + CopyConstants(constantwork, Constants, nullptr, &OutNamespace->Symbols); + for (auto c : Classes) + { + CopyConstants(constantwork, c->Constants, c->Type(), &c->Type()->Symbols); + } + for (auto s : Structs) + { + if (s->Type() != nullptr) + CopyConstants(constantwork, s->Constants, s->Type(), &s->Type()->Symbols); + } + + // Before starting to resolve the list, let's create symbols for all already resolved ones first (i.e. all literal constants), to reduce work. + for (unsigned i = 0; iValue->NodeType == AST_ExprConstant) + { + AddConstant(constantwork[i]); + // Remove the constant from the list + constantwork.Delete(i); + i--; + } + } + bool donesomething = true; + // Now go through this list until no more constants can be resolved. The remaining ones will be non-constant values. + while (donesomething && constantwork.Size() > 0) + { + donesomething = false; + for (unsigned i = 0; i < constantwork.Size(); i++) + { + if (CompileConstant(&constantwork[i])) + { + AddConstant(constantwork[i]); + // Remove the constant from the list + constantwork.Delete(i); + i--; + donesomething = true; + } + } + } + for (unsigned i = 0; i < constantwork.Size(); i++) + { + Error(constantwork[i].node, "%s is not a constant", FName(constantwork[i].node->NodeName).GetChars()); + } + + + for (auto s : Structs) + { + CompileArrays(s); + } + for (auto c : Classes) + { + CompileArrays(c); + } +} + +//========================================================================== +// +// ZCCCompiler :: AddConstant +// +// Adds a constant to its assigned symbol table +// +//========================================================================== + +void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) +{ + auto def = constant.node; + auto val = def->Value; + ExpVal &c = constant.constval; + + // This is for literal constants. + if (val->NodeType == AST_ExprConstant) + { + ZCC_ExprConstant *cval = static_cast(val); + if (cval->Type == TypeString) + { + def->Symbol = Create(def->NodeName, *(cval->StringVal)); + } + else if (cval->Type->isInt()) + { + // How do we get an Enum type in here without screwing everything up??? + //auto type = def->Type != nullptr ? def->Type : cval->Type; + def->Symbol = Create(def->NodeName, cval->Type, cval->IntVal); + } + else if (cval->Type->isFloat()) + { + if (def->Type != nullptr) + { + Error(def, "Enum members must be integer values"); + } + def->Symbol = Create(def->NodeName, cval->Type, cval->DoubleVal); + } + else + { + Error(def->Value, "Bad type for constant definiton"); + def->Symbol = nullptr; + } + } + else + { + if (c.Type == TypeString) + { + def->Symbol = Create(def->NodeName, c.GetString()); + } + else if (c.Type->isInt()) + { + // How do we get an Enum type in here without screwing everything up??? + //auto type = def->Type != nullptr ? def->Type : cval->Type; + def->Symbol = Create(def->NodeName, c.Type, c.GetInt()); + } + else if (c.Type->isFloat()) + { + if (def->Type != nullptr) + { + Error(def, "Enum members must be integer values"); + } + def->Symbol = Create(def->NodeName, c.Type, c.GetFloat()); + } + else + { + Error(def->Value, "Bad type for constant definiton"); + def->Symbol = nullptr; + } + } + + if (def->Symbol == nullptr) + { + // Create a dummy constant so we don't make any undefined value warnings. + def->Symbol = Create(def->NodeName, TypeError, 0); + } + constant.Outputtable->ReplaceSymbol(def->Symbol); +} + +//========================================================================== +// +// ZCCCompiler :: CompileConstant +// +// For every constant definition, evaluate its value (which should result +// in a constant), and create a symbol for it. +// +//========================================================================== + +bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work) +{ + FCompileContext ctx(OutNamespace, work->cls, false, mVersion); + FxExpression *exp = ConvertNode(work->node->Value); + try + { + FScriptPosition::errorout = true; + exp = exp->Resolve(ctx); + if (exp == nullptr) return false; + FScriptPosition::errorout = false; + if (!exp->isConstant()) + { + delete exp; + return false; + } + work->constval = static_cast(exp)->GetValue(); + delete exp; + return true; + } + catch (...) + { + // eat the reported error and treat this as a temorary failure. All unresolved contants will be reported at the end. + FScriptPosition::errorout = false; + return false; + } +} + + +void ZCCCompiler::CompileArrays(ZCC_StructWork *work) +{ + for(auto sas : work->Arrays) + { + PType *ztype = DetermineType(work->Type(), sas, sas->Id, sas->Type, false, true); + PType *ctype = ztype; + FArgumentList values; + + // Don't use narrow typea for casting. + if (ctype->isInt()) ctype = static_cast(ztype)->Unsigned ? TypeUInt32 : TypeSInt32; + else if (ctype == TypeFloat32) ctype = TypeFloat64; + + ConvertNodeList(values, sas->Values); + + bool fail = false; + FCompileContext ctx(OutNamespace, work->Type(), false, mVersion); + + char *destmem = (char *)ClassDataAllocator.Alloc(values.Size() * ztype->Align); + memset(destmem, 0, values.Size() * ztype->Align); + char *copyp = destmem; + for (unsigned i = 0; i < values.Size(); i++) + { + values[i] = new FxTypeCast(values[i], ctype, false); + values[i] = values[i]->Resolve(ctx); + if (values[i] == nullptr) fail = true; + else if (!values[i]->isConstant()) + { + Error(sas, "Initializer must be constant"); + fail = true; + } + else + { + ExpVal val = static_cast(values[i])->GetValue(); + switch (ztype->GetRegType()) + { + default: + // should never happen + Error(sas, "Non-integral type in constant array"); + return; + + case REGT_INT: + ztype->SetValue(copyp, val.GetInt()); + break; + + case REGT_FLOAT: + ztype->SetValue(copyp, val.GetFloat()); + break; + + case REGT_POINTER: + *(void**)copyp = val.GetPointer(); + break; + + case REGT_STRING: + ::new(copyp) FString(val.GetString()); + break; + } + copyp += ztype->Align; + } + } + work->Type()->Symbols.AddSymbol(Create(sas->Id, NewArray(ztype, values.Size()), VARF_Static | VARF_ReadOnly, (size_t)destmem)); + } +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbol +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table) +{ + assert(sym != nullptr); + + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + return NodeFromSymbolConst(static_cast(sym), source); + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) + { + return NodeFromSymbolType(static_cast(sym), source); + } + return NULL; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbolConst +// +// Returns a new AST constant node with the symbol's content. +// +//========================================================================== + +ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode) +{ + ZCC_ExprConstant *val = static_cast(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); + val->Operation = PEX_ConstValue; + if (sym == NULL) + { + val->Type = TypeError; + val->IntVal = 0; + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) + { + val->StringVal = AST.Strings.Alloc(static_cast(sym)->Str); + val->Type = TypeString; + } + else + { + val->Type = sym->ValueType; + if (val->Type != TypeError) + { + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + if (sym->ValueType->isIntCompatible()) + { + val->IntVal = static_cast(sym)->Value; + } + else + { + assert(sym->ValueType->isFloat()); + val->DoubleVal = static_cast(sym)->Float; + } + } + } + return val; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbolType +// +// Returns a new AST type ref node with the symbol's content. +// +//========================================================================== + +ZCC_ExprTypeRef *ZCCCompiler::NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode) +{ + ZCC_ExprTypeRef *ref = static_cast(AST.InitNode(sizeof(*ref), AST_ExprTypeRef, idnode)); + ref->Operation = PEX_TypeRef; + ref->RefType = sym->Type; + ref->Type = NewClassPointer(RUNTIME_CLASS(DObject)); + return ref; +} + +//========================================================================== +// +// ZCCCompiler :: CompileAllFields +// +// builds the internal structure of all classes and structs +// +//========================================================================== + +void ZCCCompiler::CompileAllFields() +{ + // Create copies of the arrays which can be altered + auto Classes = this->Classes; + auto Structs = OrderStructs(); + TMap HasNativeChildren; + + // first step: Look for native classes with native children. + // These may not have any variables added to them because it'd clash with the native definitions. + for (unsigned i = 0; i < Classes.Size(); i++) + { + auto c = Classes[i]; + + if (c->Type()->Size != TentativeClass && c->Fields.Size() > 0) + { + // We need to search the global class table here because not all children may have a scripted definition attached. + for (auto ac : PClass::AllClasses) + { + if (ac->ParentClass != nullptr && ac->ParentClass->VMType == c->Type() && ac->Size != TentativeClass) + { + // Only set a marker here, so that we can print a better message when the actual fields get added. + HasNativeChildren.Insert(c->Type()->TypeName, true); + break; + } + } + } + } + bool donesomething = true; + while (donesomething && (Structs.Size() > 0 || Classes.Size() > 0)) + { + donesomething = false; + for (unsigned i = 0; i < Structs.Size(); i++) + { + if (CompileFields(Structs[i]->Type(), Structs[i]->Fields, Structs[i]->Outer, Structs[i]->Type() == 0? GlobalTreeNodes : &Structs[i]->TreeNodes, true)) + { + // Remove from the list if all fields got compiled. + Structs.Delete(i--); + donesomething = true; + } + } + for (unsigned i = 0; i < Classes.Size(); i++) + { + auto type = Classes[i]->ClassType(); + + if (type->Size == TentativeClass) + { + if (type->ParentClass->Size == TentativeClass) + { + // we do not know the parent class's size yet, so skip this class for now. + continue; + } + else + { + // Inherit the size of the parent class + type->Size = Classes[i]->ClassType()->ParentClass->Size; + } + } + if (!PrepareMetaData(type)) + { + if (Classes[i]->ClassType()->ParentClass) + type->MetaSize = Classes[i]->ClassType()->ParentClass->MetaSize; + else + type->MetaSize = 0; + } + + if (CompileFields(type->VMType, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type->TypeName))) + { + // Remove from the list if all fields got compiled. + Classes.Delete(i--); + donesomething = true; + } + } + } + // This really should never happen, but if it does, let's better print an error. + for (auto s : Structs) + { + Error(s->strct, "Unable to resolve all fields for struct %s", FName(s->NodeName()).GetChars()); + } + for (auto s : Classes) + { + Error(s->cls, "Unable to resolve all fields for class %s", FName(s->NodeName()).GetChars()); + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileFields +// +// builds the internal structure of a single class or struct +// +//========================================================================== + +bool ZCCCompiler::CompileFields(PContainerType *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) +{ + while (Fields.Size() > 0) + { + auto field = Fields[0]; + FieldDesc *fd = nullptr; + + PType *fieldtype = DetermineType(type, field, field->Names->Name, field->Type, true, true); + + // For structs only allow 'deprecated', for classes exclude function qualifiers. + int notallowed = forstruct? + ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Meta | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope : + ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope; + + // Some internal fields need to be set to clearscope. + if (fileSystem.GetFileContainer(Lump) == 0) notallowed &= ~ZCC_ClearScope; + + if (field->Flags & notallowed) + { + Error(field, "Invalid qualifiers for %s (%s not allowed)", FName(field->Names->Name).GetChars(), FlagsToString(field->Flags & notallowed).GetChars()); + field->Flags &= notallowed; + } + uint32_t varflags = 0; + + // These map directly to implementation flags. + if (field->Flags & ZCC_Private) varflags |= VARF_Private; + if (field->Flags & ZCC_Protected) varflags |= VARF_Protected; + if (field->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; + if (field->Flags & ZCC_ReadOnly) varflags |= VARF_ReadOnly; + if (field->Flags & ZCC_Internal) varflags |= VARF_InternalAccess; + if (field->Flags & ZCC_Transient) varflags |= VARF_Transient; + if (mVersion >= MakeVersion(2, 4, 0)) + { + if (type != nullptr) + { + if (type->ScopeFlags & Scope_UI) + varflags |= VARF_UI; + if (type->ScopeFlags & Scope_Play) + varflags |= VARF_Play; + } + if (field->Flags & ZCC_UIFlag) + varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI); + if (field->Flags & ZCC_Play) + varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play); + if (field->Flags & ZCC_ClearScope) + varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData); + } + else + { + varflags |= VARF_Play; + } + + if (field->Flags & ZCC_Native) + { + varflags |= VARF_Native | VARF_Transient; + } + + static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope }; + int excludeflags = 0; + int fc = 0; + for (size_t i = 0; i < countof(excludescope); i++) + { + if (field->Flags & excludescope[i]) + { + fc++; + excludeflags |= excludescope[i]; + } + } + if (fc > 1) + { + Error(field, "Invalid combination of scope qualifiers %s on field %s", FlagsToString(excludeflags).GetChars(), FName(field->Names->Name).GetChars()); + varflags &= ~(VARF_UI | VARF_Play); // make plain data + } + + if (field->Flags & ZCC_Meta) + { + varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly + } + + if (field->Type->ArraySize != nullptr) + { + bool nosize; + fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, type, &nosize); + + if (nosize) + { + Error(field, "Must specify array size"); + } + } + + auto name = field->Names; + do + { + if ((fieldtype->Size == 0 || !fieldtype->SizeKnown) && !(varflags & VARF_Native)) // Size not known yet. + { + if (type != nullptr) + { + type->SizeKnown = false; + } + return false; + } + + if (AddTreeNode(name->Name, name, TreeNodes, !forstruct)) + { + auto thisfieldtype = fieldtype; + if (name->ArraySize != nullptr) + { + bool nosize; + thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, type, &nosize); + + if (nosize) + { + Error(field, "Must specify array size"); + } + } + + PField *f = nullptr; + + if (varflags & VARF_Native) + { + if (varflags & VARF_Meta) + { + Error(field, "Native meta variable %s not allowed", FName(name->Name).GetChars()); + } + else + { + fd = FindField(type, FName(name->Name).GetChars()); + if (fd == nullptr) + { + Error(field, "The member variable '%s.%s' has not been exported from the executable.", type == nullptr? "" : type->TypeName.GetChars(), FName(name->Name).GetChars()); + } + // For native structs a size check cannot be done because they normally have no size. But for a native reference they are still fine. + else if (thisfieldtype->Size != ~0u && fd->FieldSize != ~0u && thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0 && + (!thisfieldtype->isStruct() || !static_cast(thisfieldtype)->isNative)) + { + Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type == nullptr ? "" : type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); + } + // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. + else if (type != nullptr) + { + // for bit fields the type must point to the source variable. + if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; + f = type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); + } + else + { + + // This is a global variable. + if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; + f = Create(name->Name, thisfieldtype, varflags | VARF_Native | VARF_Static, fd->FieldOffset, fd->BitValue); + + if (OutNamespace->Symbols.AddSymbol(f) == nullptr) + { // name is already in use + if (type != nullptr) + { + type->SizeKnown = false; + } + f->Destroy(); + return false; + } + } + } + } + else if (hasnativechildren && !(varflags & VARF_Meta)) + { + Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change", FName(name->Name).GetChars(), type->TypeName.GetChars(), type->TypeName.GetChars()); + } + else if (type != nullptr) + { + f = type->AddField(name->Name, thisfieldtype, varflags); + } + else + { + Error(field, "Cannot declare non-native global variables. Tried to declare %s", FName(name->Name).GetChars()); + } + + if ((field->Flags & (ZCC_Version | ZCC_Deprecated)) && f != nullptr) + { + f->mVersion = field->Version; + + if (field->DeprecationMessage != nullptr) + { + f->DeprecationMessage = *field->DeprecationMessage; + } + } + } + name = static_cast(name->SiblingNext); + } while (name != field->Names); + Fields.Delete(0); + } + + if (type != nullptr) + { + type->SizeKnown = Fields.Size() == 0; + } + + return Fields.Size() == 0; +} + +//========================================================================== +// +// ZCCCompiler :: OrderStructs +// +// Order the Structs array so that the least-dependant structs come first +// +//========================================================================== + +TArray ZCCCompiler::OrderStructs() +{ + TArray new_order; + + for (auto struct_def : Structs) + { + if (std::find(new_order.begin(), new_order.end(), struct_def) != new_order.end()) + { + continue; + } + AddStruct(new_order, struct_def); + } + return new_order; +} + +//========================================================================== +// +// ZCCCompiler :: AddStruct +// +// Adds a struct to the Structs array, preceded by all its dependant structs +// +//========================================================================== + +void ZCCCompiler::AddStruct(TArray &new_order, ZCC_StructWork *my_def) +{ + PStruct *my_type = static_cast(my_def->Type()); + if (my_type) + { + if (my_type->isOrdered) + { + return; + } + my_type->isOrdered = true; + } + + // Find all struct fields and add them before this one + for (const auto field : my_def->Fields) + { + PType *fieldtype = DetermineType(my_type, field, field->Names->Name, field->Type, true, true); + if (fieldtype->isStruct() && !static_cast(fieldtype)->isOrdered) + { + AddStruct(new_order, StructTypeToWork(static_cast(fieldtype))); + } + } + new_order.Push(my_def); +} + +//========================================================================== +// +// ZCCCompiler :: StructTypeToWork +// +// Find the ZCC_StructWork that corresponds to a PStruct +// +//========================================================================== + +ZCC_StructWork *ZCCCompiler::StructTypeToWork(const PStruct *type) const +{ + assert(type->isStruct()); + for (auto &def : Structs) + { + if (def->Type() == type) + { + return def; + } + } + assert(false && "Struct not found"); + return nullptr; +} + +//========================================================================== +// +// ZCCCompiler :: FieldFlagsToString +// +// creates a string for a field's flags +// +//========================================================================== + +FString ZCCCompiler::FlagsToString(uint32_t flags) +{ + + const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "const", "abstract", "extend", "virtual", "override", "transient", "vararg", "ui", "play", "clearscope", "virtualscope" }; + FString build; + + for (size_t i = 0; i < countof(flagnames); i++) + { + if (flags & (1 << i)) + { + if (build.IsNotEmpty()) build += ", "; + build += flagnames[i]; + } + } + return build; +} + +//========================================================================== +// +// ZCCCompiler :: DetermineType +// +// retrieves the type for this field, for arrays the type of a single entry. +// +//========================================================================== + +PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember) +{ + PType *retval = TypeError; + if (!allowarraytypes && ztype->ArraySize != nullptr) + { + Error(field, "%s: Array type not allowed", name.GetChars()); + return TypeError; + } + switch (ztype->NodeType) + { + case AST_BasicType: + { + auto btype = static_cast(ztype); + switch (btype->Type) + { + case ZCC_SInt8: + retval = formember? TypeSInt8 : (PType*)TypeError; + break; + + case ZCC_UInt8: + retval = formember ? TypeUInt8 : (PType*)TypeError; + break; + + case ZCC_SInt16: + retval = formember ? TypeSInt16 : (PType*)TypeError; + break; + + case ZCC_UInt16: + retval = formember ? TypeUInt16 : (PType*)TypeError; + break; + + case ZCC_SInt32: + case ZCC_IntAuto: // todo: for enums, autoselect appropriately sized int + retval = TypeSInt32; + break; + + case ZCC_UInt32: + retval = TypeUInt32; + break; + + case ZCC_Bool: + retval = TypeBool; + break; + + case ZCC_FloatAuto: + retval = formember ? TypeFloat32 : TypeFloat64; + break; + + case ZCC_Float64: + retval = TypeFloat64; + break; + + case ZCC_String: + retval = TypeString; + break; + + case ZCC_Name: + retval = TypeName; + break; + + case ZCC_Vector2: + retval = TypeVector2; + break; + + case ZCC_Vector3: + retval = TypeVector3; + break; + + case ZCC_Vector4: + retval = TypeVector4; + break; + + case ZCC_State: + retval = TypeState; + break; + + case ZCC_Color: + retval = TypeColor; + break; + + case ZCC_Sound: + retval = TypeSound; + break; + + case ZCC_Let: + retval = TypeAuto; + break; + + case ZCC_NativeType: + + // Creating an instance of a native struct is only allowed for internal definitions of native variables. + if (fileSystem.GetFileContainer(Lump) != 0 || !formember) + { + Error(field, "%s: @ not allowed for user scripts", name.GetChars()); + } + retval = ResolveUserType(btype, btype->UserType, outertype? &outertype->Symbols : nullptr, true); + break; + + case ZCC_UserType: + // statelabel et.al. are not tokens - there really is no need to, it works just as well as an identifier. Maybe the same should be done for some other types, too? + switch (btype->UserType->Id) + { + case NAME_Voidptr: + retval = TypeVoidPtr; + break; + + case NAME_StateLabel: + retval = TypeStateLabel; + break; + + case NAME_SpriteID: + retval = TypeSpriteID; + break; + + case NAME_TextureID: + retval = TypeTextureID; + break; + + case NAME_TranslationID: + retval = TypeTranslationID; + break; + + + + default: + retval = ResolveUserType(btype, btype->UserType, outertype ? &outertype->Symbols : nullptr, false); + break; + } + break; + + default: + break; + } + break; + } + + case AST_MapType: + { + if(AST.ParseVersion < MakeVersion(4, 10, 0)) + { + Error(field, "Map not accessible to ZScript version %d.%d.%d", AST.ParseVersion.major, AST.ParseVersion.minor, AST.ParseVersion.revision); + break; + } + + // Todo: Decide what we allow here and if it makes sense to allow more complex constructs. + auto mtype = static_cast(ztype); + + auto keytype = DetermineType(outertype, field, name, mtype->KeyType, false, false); + auto valuetype = DetermineType(outertype, field, name, mtype->ValueType, false, false); + + if (keytype->GetRegType() != REGT_STRING && !(keytype->GetRegType() == REGT_INT && keytype->Size == 4)) + { + if(name != NAME_None) + { + Error(field, "%s : Map<%s , ...> not implemented yet", name.GetChars(), keytype->DescriptiveName()); + } + else + { + Error(field, "Map<%s , ...> not implemented yet", keytype->DescriptiveName()); + } + } + + switch(valuetype->GetRegType()) + { + case REGT_FLOAT: + case REGT_INT: + case REGT_STRING: + case REGT_POINTER: + if (valuetype->GetRegCount() > 1) + { + default: + if(name != NAME_None) + { + Error(field, "%s : Base type for map value types must be integral, but got %s", name.GetChars(), valuetype->DescriptiveName()); + } + else + { + Error(field, "Base type for map value types must be integral, but got %s", valuetype->DescriptiveName()); + } + break; + } + + retval = NewMap(keytype, valuetype); + break; + } + + break; + } + case AST_MapIteratorType: + { + if(AST.ParseVersion < MakeVersion(4, 10, 0)) + { + Error(field, "MapIterator not accessible to ZScript version %d.%d.%d", AST.ParseVersion.major, AST.ParseVersion.minor, AST.ParseVersion.revision); + break; + } + // Todo: Decide what we allow here and if it makes sense to allow more complex constructs. + auto mtype = static_cast(ztype); + + auto keytype = DetermineType(outertype, field, name, mtype->KeyType, false, false); + auto valuetype = DetermineType(outertype, field, name, mtype->ValueType, false, false); + + if (keytype->GetRegType() != REGT_STRING && !(keytype->GetRegType() == REGT_INT && keytype->Size == 4)) + { + if(name != NAME_None) + { + Error(field, "%s : MapIterator<%s , ...> not implemented yet", name.GetChars(), keytype->DescriptiveName()); + } + else + { + Error(field, "MapIterator<%s , ...> not implemented yet", keytype->DescriptiveName()); + } + } + + switch(valuetype->GetRegType()) + { + case REGT_FLOAT: + case REGT_INT: + case REGT_STRING: + case REGT_POINTER: + if (valuetype->GetRegCount() > 1) + { + default: + if(name != NAME_None) + { + Error(field, "%s : Base type for map value types must be integral, but got %s", name.GetChars(), valuetype->DescriptiveName()); + } + else + { + Error(field, "Base type for map value types must be integral, but got %s", valuetype->DescriptiveName()); + } + break; + } + retval = NewMapIterator(keytype, valuetype); + break; + } + break; + } + case AST_DynArrayType: + { + auto atype = static_cast(ztype); + auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true); + if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1) + { + if (field->NodeType == AST_VarDeclarator && (static_cast(field)->Flags & ZCC_Native) && fileSystem.GetFileContainer(Lump) == 0) + { + // the internal definitions may declare native arrays to complex types. + // As long as they can be mapped to a static array type the VM can handle them, in a limited but sufficient fashion. + retval = NewPointer(NewStaticArray(ftype), false); + retval->Size = ~0u; // don't check for a size match, it's likely to fail anyway. + retval->Align = ~0u; + } + else + { + Error(field, "%s: Base type for dynamic array types must be integral, but got %s", name.GetChars(), ftype->DescriptiveName()); + } + } + else + { + retval = NewDynArray(ftype); + } + break; + } + case AST_FuncPtrType: + { + auto fn = static_cast(ztype); + + if(fn->Scope == -1) + { // Function + retval = NewFunctionPointer(nullptr, {}, -1); + } + else + { + TArray returns; + TArray args; + TArray argflags; + + if(auto *t = fn->RetType; t != nullptr) do { + returns.Push(DetermineType(outertype, field, name, t, false, false)); + } while( (t = (ZCC_Type *)t->SiblingNext) != fn->RetType); + + if(auto *t = fn->Params; t != nullptr) do { + PType * tt = DetermineType(outertype, field, name, t->Type, false, false); + int flags = 0; + + if (ShouldWrapPointer(tt)) + { + tt = NewPointer(tt); + flags = VARF_Ref; + } + + args.Push(tt); + argflags.Push(t->Flags == ZCC_Out ? VARF_Out|flags : flags); + } while( (t = (ZCC_FuncPtrParamDecl *) t->SiblingNext) != fn->Params); + + auto proto = NewPrototype(returns,args); + switch(fn->Scope) + { // only play/ui/clearscope functions are allowed, no data or virtual scope functions + case ZCC_Play: + fn->Scope = FScopeBarrier::Side_Play; + break; + case ZCC_UIFlag: + fn->Scope = FScopeBarrier::Side_UI; + break; + case ZCC_ClearScope: + fn->Scope = FScopeBarrier::Side_PlainData; + break; + case 0: + fn->Scope = -1; + break; + default: + Error(field, "Invalid Scope for Function Pointer"); + break; + } + retval = NewFunctionPointer(proto, std::move(argflags), fn->Scope); + } + break; + } + case AST_ClassType: + { + auto ctype = static_cast(ztype); + if (ctype->Restriction == nullptr) + { + retval = NewClassPointer(RUNTIME_CLASS(DObject)); + } + else + { + // This doesn't check the class list directly but the current symbol table to ensure that + // this does not reference a type that got shadowed by a more local definition. + // We first look in the current class and its parents, and then in the current namespace and its parents. + auto sym = outertype ? outertype->Symbols.FindSymbol(ctype->Restriction->Id, true) : nullptr; + if (sym == nullptr) sym = OutNamespace->Symbols.FindSymbol(ctype->Restriction->Id, true); + if (sym == nullptr) + { + // A symbol with a given name cannot be reached from this definition point, so + // even if a class with the given name exists, it is not accessible. + Error(field, "%s: Unknown identifier", FName(ctype->Restriction->Id).GetChars()); + return TypeError; + } + auto typesym = dyn_cast(sym); + if (typesym == nullptr || !typesym->Type->isClass()) + { + Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars()); + return TypeError; + } + if (typesym->Type->mVersion > mVersion) + { + Error(field, "Class %s not accessible to ZScript version %d.%d.%d", FName(ctype->Restriction->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); + return TypeError; + } + retval = NewClassPointer(static_cast(typesym->Type)->Descriptor); + } + break; + } + + default: + break; + } + if (retval != TypeError && retval->MemberOnly && !formember) + { + Error(field, "Invalid type %s", retval->DescriptiveName()); + return TypeError; + } + return retval; +} + +//========================================================================== +// +// ZCCCompiler :: ResolveUserType +// +//========================================================================== + +/** +* Resolves a user type and returns a matching PType. +* +* @param type The tree node with the identifiers to look for. +* @param type The current identifier being looked for. This must be in type's UserType list. +* @param symt The symbol table to search in. If id is the first identifier and not found in symt, then OutNamespace will also be searched. +* @param nativetype Distinguishes between searching for a native type or a user type. +* @returns the PType found for this user type +*/ +PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, ZCC_Identifier *id, PSymbolTable *symt, bool nativetype) +{ + // Check the symbol table for the identifier. + PSymbol *sym = nullptr; + + // We first look in the current class and its parents, and then in the current namespace and its parents. + if (symt != nullptr) sym = symt->FindSymbol(id->Id, true); + if (sym == nullptr && type->UserType == id) sym = OutNamespace->Symbols.FindSymbol(id->Id, true); + if (sym != nullptr && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) + { + auto ptype = static_cast(sym)->Type; + if (ptype->mVersion > mVersion) + { + Error(type, "Type %s not accessible to ZScript version %d.%d.%d", FName(type->UserType->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); + return TypeError; + } + + if (id->SiblingNext != type->UserType) + { + assert(id->SiblingNext->NodeType == AST_Identifier); + ptype = ResolveUserType( + type, + static_cast(id->SiblingNext), + &ptype->Symbols, + nativetype + ); + if (ptype == TypeError) + { + return ptype; + } + } + + if (ptype->isEnum()) + { + if (!nativetype) return TypeSInt32; // hack this to an integer until we can resolve the enum mess. + } + else if (ptype->isClass()) // classes cannot be instantiated at all, they always get used as references. + { + return NewPointer(ptype, type->isconst); + } + else if (ptype->isStruct() && static_cast(ptype)->isNative) // native structs and classes cannot be instantiated, they always get used as reference. + { + if (!nativetype) return NewPointer(ptype, type->isconst); + return ptype; // instantiation of native structs. Only for internal use. + } + if (!nativetype) return ptype; + } + Error(type, "Unable to resolve %s%s as a type.", nativetype? "@" : "", UserTypeName(type).GetChars()); + return TypeError; +} + + +//========================================================================== +// +// ZCCCompiler :: UserTypeName STATIC +// +// Returns the full name for a UserType node. +// +//========================================================================== + +FString ZCCCompiler::UserTypeName(ZCC_BasicType *type) +{ + FString out; + ZCC_Identifier *id = type->UserType; + + do + { + assert(id->NodeType == AST_Identifier); + if (out.Len() > 0) + { + out += '.'; + } + out += FName(id->Id).GetChars(); + } while ((id = static_cast(id->SiblingNext)) != type->UserType); + return out; +} + +//========================================================================== +// +// ZCCCompiler :: ResolveArraySize +// +// resolves the array size and returns a matching type. +// +//========================================================================== + +PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls, bool *nosize) +{ + TArray indices; + + // Simplify is too broken to resolve this inside the ring list so unravel the list into an array before starting to simplify its components. + auto node = arraysize; + do + { + indices.Push(node); + node = static_cast(node->SiblingNext); + } while (node != arraysize); + + if (indices.Size() == 1 && indices [0]->Operation == PEX_Nil) + { + *nosize = true; + return baseType; + } + + if (mVersion >= MakeVersion(3, 7, 2)) + { + TArray fixedIndices; + for (auto index : indices) + { + fixedIndices.Insert (0, index); + } + + indices = std::move(fixedIndices); + } + + FCompileContext ctx(OutNamespace, cls, false, mVersion); + for (auto index : indices) + { + // There is no float->int casting here. + FxExpression *ex = ConvertNode(index); + ex = ex->Resolve(ctx); + + if (ex == nullptr) return TypeError; + if (!ex->isConstant() || !ex->ValueType->isInt()) + { + Error(arraysize, "Array index must be an integer constant"); + return TypeError; + } + int size = static_cast(ex)->GetValue().GetInt(); + if (size < 1) + { + Error(arraysize, "Array size must be positive"); + return TypeError; + } + baseType = NewArray(baseType, size); + } + + *nosize = false; + return baseType; +} + +//========================================================================== +// +// SetImplicitArgs +// +// Adds the parameters implied by the function flags. +// +//========================================================================== + +void ZCCCompiler::SetImplicitArgs(TArray* args, TArray* argflags, TArray* argnames, PContainerType* cls, uint32_t funcflags, int useflags) +{ + // Must be called before adding any other arguments. + assert(args == nullptr || args->Size() == 0); + assert(argflags == nullptr || argflags->Size() == 0); + + if (funcflags & VARF_Method) + { + // implied self pointer + if (args != nullptr) args->Push(NewPointer(cls, !!(funcflags & VARF_ReadOnly))); + if (argflags != nullptr) argflags->Push(VARF_Implicit | VARF_ReadOnly); + if (argnames != nullptr) argnames->Push(NAME_self); + } +} + + +void ZCCCompiler::InitDefaults() +{ + for (auto c : Classes) + { + if (c->ClassType()->ParentClass) + { + auto ti = c->ClassType(); + ti->InitializeDefaults(); + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass) +{ + TArray rets(1); + TArray args; + TArray argflags; + TArray argdefaults; + TArray argnames; + + rets.Clear(); + args.Clear(); + argflags.Clear(); + bool hasdefault = false; + // For the time being, let's not allow overloading. This may be reconsidered later but really just adds an unnecessary amount of complexity here. + if (AddTreeNode(f->Name, f, &c->TreeNodes, false)) + { + auto t = f->Type; + if (t != nullptr) + { + do + { + auto type = DetermineType(c->Type(), f, f->Name, t, false, false); + if (type->isContainer() && type != TypeVector2 && type != TypeVector3 && type != TypeVector4 && type != TypeQuaternion && type != TypeFVector2 && type != TypeFVector3 && type != TypeFVector4 && type != TypeFQuaternion) + { + // structs and classes only get passed by pointer. + type = NewPointer(type); + } + else if (type->isDynArray()) + { + Error(f, "The return type of a function cannot be a dynamic array"); + break; + } + else if (type->isMap()) + { + Error(f, "The return type of a function cannot be a map"); + break; + } + else if (type == TypeFVector2) + { + type = TypeVector2; + } + else if (type == TypeFVector3) + { + type = TypeVector3; + } + else if (type == TypeFVector4) + { + type = TypeVector4; + } + else if (type == TypeFQuaternion) + { + type = TypeQuaternion; + } + // TBD: disallow certain types? For now, let everything pass that isn't an array. + rets.Push(type); + t = static_cast(t->SiblingNext); + } while (t != f->Type); + } + + int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_Internal; + + if (f->Flags & notallowed) + { + Error(f, "Invalid qualifiers for %s (%s not allowed)", FName(f->Name).GetChars(), FlagsToString(f->Flags & notallowed).GetChars()); + f->Flags &= notallowed; + } + uint32_t varflags = VARF_Method; + int implicitargs = 1; + AFuncDesc *afd = nullptr; + int useflags = SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM; + if (f->UseFlags != nullptr) + { + useflags = 0; + auto p = f->UseFlags; + do + { + switch (p->Id) + { + case NAME_Actor: + useflags |= SUF_ACTOR; + break; + case NAME_Overlay: + useflags |= SUF_OVERLAY; + break; + case NAME_Weapon: + useflags |= SUF_WEAPON; + break; + case NAME_Item: + useflags |= SUF_ITEM; + break; + default: + Error(p, "Unknown Action qualifier %s", FName(p->Id).GetChars()); + break; + } + + p = static_cast(p->SiblingNext); + } while (p != f->UseFlags); + } + + // map to implementation flags. + if (f->Flags & ZCC_Private) varflags |= VARF_Private; + if (f->Flags & ZCC_Protected) varflags |= VARF_Protected; + if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; + if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual; + if (f->Flags & ZCC_Override) varflags |= VARF_Override; + if (f->Flags & ZCC_Abstract) varflags |= VARF_Abstract; + if (f->Flags & ZCC_VarArg) varflags |= VARF_VarArg; + if (f->Flags & ZCC_FuncConst) varflags |= VARF_ReadOnly; // FuncConst method is internally marked as VARF_ReadOnly + if (mVersion >= MakeVersion(2, 4, 0)) + { + if (c->Type()->ScopeFlags & Scope_UI) + varflags |= VARF_UI; + if (c->Type()->ScopeFlags & Scope_Play) + varflags |= VARF_Play; + //if (f->Flags & ZCC_FuncConst) + // varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData); // const implies clearscope. this is checked a bit later to also not have ZCC_Play/ZCC_UIFlag. + if (f->Flags & ZCC_UIFlag) + varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI); + if (f->Flags & ZCC_Play) + varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play); + if (f->Flags & ZCC_ClearScope) + varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Clear); + if (f->Flags & ZCC_VirtualScope) + varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Virtual); + } + else + { + varflags |= VARF_Play; + } + + if ((f->Flags & ZCC_VarArg) && !(f->Flags & ZCC_Native)) + { + Error(f, "'VarArg' can only be used with native methods"); + } + if (f->Flags & ZCC_Action) + { + implicitargs = CheckActionKeyword(f,varflags, useflags, c); + if (implicitargs < 0) + { + Error(f, "'Action' not allowed as a function qualifier"); + // Set state to allow continued compilation to find more errors. + varflags &= ~VARF_ReadOnly; + implicitargs = 1; + } + } + if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final. + + if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'. + // Only one of these flags may be used. + static int exclude[] = { ZCC_Abstract, ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static }; + int excludeflags = 0; + int fc = 0; + for (size_t i = 0; i < countof(exclude); i++) + { + if (f->Flags & exclude[i]) + { + fc++; + excludeflags |= exclude[i]; + } + } + if (fc > 1) + { + Error(f, "Invalid combination of qualifiers %s on function %s", FlagsToString(excludeflags).GetChars(), FName(f->Name).GetChars()); + varflags |= VARF_Method; + } + if (varflags & (VARF_Override | VARF_Abstract)) varflags |= VARF_Virtual; // Now that the flags are checked, make all override and abstract functions virtual as well. + + // [ZZ] this doesn't make sense either. + if ((varflags&(VARF_ReadOnly | VARF_Method)) == VARF_ReadOnly) // non-method const function + { + Error(f, "'Const' on a static method is not supported"); + } + + // [ZZ] neither this + if ((varflags&(VARF_VirtualScope | VARF_Method)) == VARF_VirtualScope) // non-method virtualscope function + { + Error(f, "'VirtualScope' on a static method is not supported"); + } + + static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope, ZCC_VirtualScope }; + excludeflags = 0; + fc = 0; + for (size_t i = 0; i < countof(excludescope); i++) + { + if (f->Flags & excludescope[i]) + { + fc++; + excludeflags |= excludescope[i]; + } + } + if (fc > 1) + { + Error(f, "Invalid combination of scope qualifiers %s on function %s", FlagsToString(excludeflags).GetChars(), FName(f->Name).GetChars()); + varflags &= ~(VARF_UI | VARF_Play); // make plain data + } + + if (f->Flags & ZCC_Native) + { + if (varflags & VARF_Abstract) + { + Error(f, "Native functions cannot be abstract"); + return; + } + + varflags |= VARF_Native; + afd = FindFunction(c->Type(), FName(f->Name).GetChars()); + if (afd == nullptr) + { + Error(f, "The function '%s.%s' has not been exported from the executable", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); + } + else + { + (*afd->VMPointer)->ImplicitArgs = uint8_t(implicitargs); + } + } + SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, useflags); + argdefaults.Resize(argnames.Size()); + auto p = f->Params; + bool hasoptionals = false; + if (p != nullptr) + { + bool overridemsg = false; + do + { + int elementcount = 1; + TypedVMValue vmval[4]; // default is REGT_NIL which means 'no default value' here. + if (p->Type != nullptr) + { + auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); + int flags = 0; + if (ShouldWrapPointer(type)) + { + // Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly. + type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/); + flags |= VARF_Ref; + } + else if (type->GetRegType() != REGT_NIL) + { + if (p->Flags & ZCC_Out) flags |= VARF_Out; + if (type == TypeVector2 || type == TypeFVector2) + { + elementcount = 2; + } + else if (type == TypeVector3 || type == TypeFVector3) + { + elementcount = 3; + } + else if (type == TypeVector4 || type == TypeFVector4 || type == TypeQuaternion || type == TypeFQuaternion) + { + elementcount = 4; + } + } + if (type->GetRegType() == REGT_NIL && type != TypeVector2 && type != TypeVector3 && type != TypeVector4 && type != TypeQuaternion && type != TypeFVector2 && type != TypeFVector3 && type != TypeFVector4 && type != TypeFQuaternion) + { + // If it's TypeError, then an error was already given + if (type != TypeError) + { + Error(p, "Invalid type %s for function parameter", type->DescriptiveName()); + } + } + else if (p->Default != nullptr) + { + if (flags & VARF_Out) + { + Error(p, "Out parameters cannot have default values"); + } + + flags |= VARF_Optional; + hasoptionals = true; + + if ((varflags & VARF_Override) && !overridemsg) + { + // This is illegal, but in older compilers wasn't checked, so there it has to be demoted to a warning. + // Virtual calls always need to get their defaults from the base virtual method. + if (mVersion >= MakeVersion(3, 3)) + { + Error(p, "Default values for parameter of virtual override not allowed"); + } + else + { + Warn(p, "Default values for parameter of virtual override will be ignored!"); + } + overridemsg = true; + } + + + FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false); + FCompileContext ctx(OutNamespace, c->Type(), false, mVersion); + x = x->Resolve(ctx); + + if (x != nullptr) + { + // Vectors need special treatment because they use more than one entry in the Defaults and do not report as actual constants + if ((type == TypeVector2 || type == TypeFVector2) && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(2)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyzw[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyzw[1])->GetValue().GetFloat(); + } + else if ((type == TypeVector3 || type == TypeFVector3) && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(3)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyzw[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyzw[1])->GetValue().GetFloat(); + vmval[2] = static_cast(vx->xyzw[2])->GetValue().GetFloat(); + } + else if ((type == TypeVector4 || type == TypeFVector4) && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(4)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyzw[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyzw[1])->GetValue().GetFloat(); + vmval[2] = static_cast(vx->xyzw[2])->GetValue().GetFloat(); + vmval[3] = static_cast(vx->xyzw[3])->GetValue().GetFloat(); + } + else if ((type == TypeQuaternion || type == TypeFQuaternion) && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(4)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyzw[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyzw[1])->GetValue().GetFloat(); + vmval[2] = static_cast(vx->xyzw[2])->GetValue().GetFloat(); + vmval[3] = static_cast(vx->xyzw[3])->GetValue().GetFloat(); + } + else if (!x->isConstant()) + { + Error(p, "Default parameter %s is not constant in %s", FName(p->Name).GetChars(), FName(f->Name).GetChars()); + } + else if (x->ValueType != type) + { + Error(p, "Default parameter %s could not be converted to target type %s", FName(p->Name).GetChars(), c->Type()->TypeName.GetChars()); + } + else + { + auto cnst = static_cast(x); + switch (type->GetRegType()) + { + case REGT_INT: + vmval[0] = cnst->GetValue().GetInt(); + break; + + case REGT_FLOAT: + vmval[0] = cnst->GetValue().GetFloat(); + break; + + case REGT_POINTER: + if (type->isClassPointer()) + vmval[0] = (DObject*)cnst->GetValue().GetPointer(); + else + vmval[0] = cnst->GetValue().GetPointer(); + break; + + case REGT_STRING: + // We need a reference to something permanently stored here. + vmval[0] = VMStringConstants.Alloc(cnst->GetValue().GetString()); + break; + + default: + assert(0 && "no valid type for constant"); + break; + } + } + + hasdefault = true; + } + if (x != nullptr) delete x; + } + else if (hasoptionals) + { + Error(p, "All arguments after the first optional one need also be optional"); + } + // TBD: disallow certain types? For now, let everything pass that isn't an array. + args.Push(type); + argflags.Push(flags); + argnames.Push(p->Name); + + } + else + { + args.Push(nullptr); + argflags.Push(0); + argnames.Push(NAME_None); + } + for (int i = 0; i(p->SiblingNext); + } while (p != f->Params); + } + + PFunction *sym = Create(c->Type(), f->Name); + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags); + c->Type()->Symbols.ReplaceSymbol(sym); + + if (f->DeprecationMessage != nullptr) + { + sym->Variants[0].DeprecationMessage = *f->DeprecationMessage; + } + + auto vcls = PType::toClass(c->Type()); + auto cls = vcls ? vcls->Descriptor : nullptr; + PFunction *virtsym = nullptr; + if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->VMType->Symbols.FindSymbol(FName(f->Name), true)); + unsigned vindex = ~0u; + if (virtsym != nullptr) + { + auto imp = virtsym->Variants[0].Implementation; + if (imp != nullptr) vindex = imp->VirtualIndex; + else Error(f, "Virtual base function %s not found in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars()); + } + if (f->Flags & (ZCC_Version | ZCC_Deprecated)) + { + sym->mVersion = f->Version; + if (varflags & VARF_Override) + { + Error(f, "Overridden function %s may not alter version restriction in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars()); + } + } + + VMFunction *newfunc = nullptr; + + if (!(f->Flags & ZCC_Native)) + { + if (f->Body != nullptr && (varflags & VARF_Abstract)) + { + Error(f, "Abstract function %s cannot have a body", FName(f->Name).GetChars()); + return; + } + + if (f->Body == nullptr && !(varflags & VARF_Abstract)) + { + Error(f, "Empty function %s", FName(f->Name).GetChars()); + return; + } + + FxExpression* code = f->Body != nullptr ? ConvertAST(c->Type(), f->Body) : nullptr; + newfunc = FunctionBuildList.AddFunction(OutNamespace, mVersion, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); + } + if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time. + { + sym->Variants[0].Implementation->DefaultArgs = std::move(argdefaults); + } + + if (sym->Variants[0].Implementation != nullptr) + { + // [ZZ] unspecified virtual function inherits old scope. virtual function scope can't be changed. + sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags; + } + + bool exactReturnType = mVersion < MakeVersion(4, 4); + PClass *clstype = forclass? static_cast(c->Type())->Descriptor : nullptr; + if (varflags & VARF_Virtual) + { + if (sym->Variants[0].Implementation == nullptr) + { + Error(f, "Virtual function %s.%s not present", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); + return; + } + + if (forclass) + { + if ((varflags & VARF_Abstract) && !clstype->bAbstract) + { + Error(f, "Abstract functions can only be defined in abstract classes"); + return; + } + + auto parentfunc = clstype->ParentClass? dyn_cast(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)) : nullptr; + + int virtindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], parentfunc, exactReturnType, sym->SymbolName == FName("SpecialBounceHit") && mVersion < MakeVersion(4, 12)); + // specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types. + if (varflags & VARF_Override) + { + if (virtindex == -1) + { + Error(f, "Attempt to override non-existent virtual function %s", FName(f->Name).GetChars()); + } + else + { + auto oldfunc = clstype->Virtuals[virtindex]; + if (parentfunc && parentfunc->mVersion > mVersion) + { + Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); + } + if (oldfunc->VarFlags & VARF_Final) + { + Error(f, "Attempt to override final function %s", FName(f->Name).GetChars()); + } + // you can't change ui/play/clearscope for a virtual method. + if (f->Flags & (ZCC_UIFlag|ZCC_Play|ZCC_ClearScope|ZCC_VirtualScope)) + { + Error(f, "Attempt to change scope for virtual function %s", FName(f->Name).GetChars()); + } + // you can't change const qualifier for a virtual method + if ((sym->Variants[0].Implementation->VarFlags & VARF_ReadOnly) && !(oldfunc->VarFlags & VARF_ReadOnly)) + { + Error(f, "Attempt to add const qualifier to virtual function %s", FName(f->Name).GetChars()); + } + // you can't change protected qualifier for a virtual method (i.e. putting private), because this cannot be reliably checked without runtime stuff + if (f->Flags & (ZCC_Private | ZCC_Protected)) + { + Error(f, "Attempt to change private/protected qualifiers for virtual function %s", FName(f->Name).GetChars()); + } + // inherit scope of original function if override not specified + sym->Variants[0].Flags = FScopeBarrier::ChangeSideInFlags(sym->Variants[0].Flags, FScopeBarrier::SideFromFlags(oldfunc->VarFlags)); + // inherit const from original function + if (oldfunc->VarFlags & VARF_ReadOnly) + sym->Variants[0].Flags |= VARF_ReadOnly; + if (oldfunc->VarFlags & VARF_Protected) + sym->Variants[0].Flags |= VARF_Protected; + + clstype->Virtuals[virtindex] = sym->Variants[0].Implementation; + sym->Variants[0].Implementation->VirtualIndex = virtindex; + sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags; + + // Defaults must be identical to parent class + if (parentfunc->Variants[0].Implementation->DefaultArgs.Size() > 0) + { + sym->Variants[0].Implementation->DefaultArgs = parentfunc->Variants[0].Implementation->DefaultArgs; + sym->Variants[0].ArgFlags = parentfunc->Variants[0].ArgFlags; + } + + // Update argument flags for VM function if needed as their list could be incomplete + // At the moment of function creation, arguments with default values were not copied yet from the parent function + if (newfunc != nullptr && sym->Variants[0].ArgFlags.Size() != newfunc->ArgFlags.Size()) + { + for (unsigned i = newfunc->ArgFlags.Size(), count = sym->Variants[0].ArgFlags.Size(); i < count; ++i) + { + newfunc->ArgFlags.Push(sym->Variants[0].ArgFlags[i]); + } + + newfunc->Proto = sym->Variants[0].Proto; + } + } + } + else + { + if (virtindex != -1) + { + Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); + } + sym->Variants[0].Implementation->VirtualIndex = clstype->Virtuals.Push(sym->Variants[0].Implementation); + } + } + else + { + Error(p, "Virtual functions can only be defined for classes"); + } + } + else if (forclass) + { + int virtindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], nullptr, exactReturnType, sym->SymbolName == FName("SpecialBounceHit") && mVersion < MakeVersion(4, 12)); + if (virtindex != -1) + { + Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); + } + } + } +} + +//========================================================================== +// +// Parses the functions list +// +//========================================================================== + +void ZCCCompiler::InitFunctions() +{ + for (auto s : Structs) + { + for (auto f : s->Functions) + { + CompileFunction(s, f, false); + } + } + + for (auto c : Classes) + { + // cannot be done earlier because it requires the parent class to be processed by this code, too. + if (c->ClassType()->ParentClass != nullptr) + { + c->ClassType()->Virtuals = c->ClassType()->ParentClass->Virtuals; + } + for (auto f : c->Functions) + { + CompileFunction(c, f, true); + } + + // [Player701] Make sure all abstract functions are overridden + if (!c->ClassType()->bAbstract) + { + for (auto v : c->ClassType()->Virtuals) + { + if (v->VarFlags & VARF_Abstract) + { + Error(c->cls, "Non-abstract class %s must override abstract function %s", c->Type()->TypeName.GetChars(), v->PrintableName); + } + } + } + } +} + +//========================================================================== +// +// Convert the AST data for the code generator. +// +//========================================================================== + +FxExpression *ZCCCompiler::ConvertAST(PContainerType *cls, ZCC_TreeNode *ast) +{ + ConvertClass = cls; + // there are two possibilities here: either a single function call or a compound statement. For a compound statement we also need to check if the last thing added was a return. + if (ast->NodeType == AST_ExprFuncCall) + { + auto cp = new FxCompoundStatement(*ast); + cp->Add(new FxReturnStatement(ConvertNode(ast), *ast)); + return cp; + } + else + { + // This must be done here so that we can check for a trailing return statement. + auto x = new FxCompoundStatement(*ast); + auto compound = static_cast(ast); + //bool isreturn = false; + auto node = compound->Content; + if (node != nullptr) do + { + x->Add(ConvertNode(node)); + //isreturn = node->NodeType == AST_ReturnStmt; + node = static_cast(node->SiblingNext); + } while (node != compound->Content); + //if (!isreturn) x->Add(new FxReturnStatement(nullptr, *ast)); + return x; + } +} + + +#define xx(a,z) z, +static int Pex2Tok[] = { +#include "zcc_exprlist.h" +}; + +//========================================================================== +// +// Helper for modify/assign operators +// +//========================================================================== + +static FxExpression *ModifyAssign(FxBinary *operation, FxExpression *left) +{ + auto assignself = static_cast(operation->left); + auto assignment = new FxAssign(left, operation, true); + assignself->Assignment = assignment; + return assignment; +} + + +//========================================================================== +// +// Convert an AST node and its children +// +//========================================================================== + +FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute) +{ + if (ast == nullptr) return nullptr; + + switch (ast->NodeType) + { + case AST_ExprFuncCall: + { + auto fcall = static_cast(ast); + + // function names can either be + // - plain identifiers + // - class members + // - array syntax for random() calls. + // Everything else coming here is a syntax error. + FArgumentList args; + switch (fcall->Function->NodeType) + { + case AST_ExprID: + // The function name is a simple identifier. + return new FxFunctionCall(static_cast(fcall->Function)->Identifier, NAME_None, std::move(ConvertNodeList(args, fcall->Parameters)), *ast); + + case AST_ExprMemberAccess: + { + auto ema = static_cast(fcall->Function); + return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, std::move(ConvertNodeList(args, fcall->Parameters)), *ast); + } + + case AST_ExprBinary: + // Array syntax for randoms. They are internally stored as ExprBinary with both an identifier on the left and right side. + if (fcall->Function->Operation == PEX_ArrayAccess) + { + auto binary = static_cast(fcall->Function); + if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID) + { + return new FxFunctionCall(static_cast(binary->Left)->Identifier, static_cast(binary->Right)->Identifier, std::move(ConvertNodeList(args, fcall->Parameters)), *ast); + } + } + // fall through if this isn't an array access node. + [[fallthrough]]; + + default: + Error(fcall, "Invalid function identifier"); + return new FxNop(*ast); // return something so that the compiler can continue. + } + break; + } + + case AST_ClassCast: + { + auto cc = static_cast(ast); + if (cc->Parameters == nullptr || cc->Parameters->SiblingNext != cc->Parameters) + { + Error(cc, "Class type cast requires exactly one parameter"); + return new FxNop(*ast); // return something so that the compiler can continue. + } + auto cls = PClass::FindClass(cc->ClassName); + if (cls == nullptr || cls->VMType == nullptr) + { + Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars()); + return new FxNop(*ast); // return something so that the compiler can continue. + } + return new FxClassPtrCast(cls, ConvertNode(cc->Parameters)); + } + + case AST_FunctionPtrCast: + { + auto cast = static_cast(ast); + + auto type = DetermineType(ConvertClass, cast, NAME_None, cast->PtrType, false, false); + assert(type->isFunctionPointer()); + auto ptrType = static_cast(type); + + return new FxFunctionPtrCast(ptrType, ConvertNode(cast->Expr)); + } + + case AST_StaticArrayStatement: + { + auto sas = static_cast(ast); + PType *ztype = DetermineType(ConvertClass, sas, sas->Id, sas->Type, false, false); + FArgumentList args; + ConvertNodeList(args, sas->Values); + // This has to let the code generator resolve the constants, not the Simplifier, which lacks all the necessary type info. + return new FxStaticArray(ztype, sas->Id, args, *ast); + } + + case AST_ExprMemberAccess: + { + auto memaccess = static_cast(ast); + return new FxMemberIdentifier(ConvertNode(memaccess->Left), memaccess->Right, *ast); + } + + case AST_FuncParm: + { + auto fparm = static_cast(ast); + auto node = ConvertNode(fparm->Value); + if (fparm->Label != NAME_None) node = new FxNamedNode(fparm->Label, node, *ast); + return node; + } + + case AST_ExprID: + { + auto id = static_cast(ast)->Identifier; + if (id == NAME_LevelLocals && substitute) id = NAME_Level; // All static methods of FLevelLocals are now non-static so remap the name right here before passing it to the backend. + return new FxIdentifier(id, *ast); + } + + case AST_ExprConstant: + { + auto cnst = static_cast(ast); + if (cnst->Type == TypeName) + { + return new FxConstant(FName(ENamedName(cnst->IntVal)), *ast); + } + else if (cnst->Type->isInt()) + { + if (cnst->Type == TypeUInt32) + { + return new FxConstant((unsigned)cnst->IntVal, *ast); + } + else + { + return new FxConstant(cnst->IntVal, *ast); + } + } + else if (cnst->Type == TypeBool) + { + return new FxConstant(!!cnst->IntVal, *ast); + } + else if (cnst->Type->isFloat()) + { + return new FxConstant(cnst->DoubleVal, *ast); + } + else if (cnst->Type == TypeString) + { + return new FxConstant(*cnst->StringVal, *ast); + } + else if (cnst->Type == TypeNullPtr) + { + return new FxConstant(*ast); + } + else + { + // can there be other types? + Error(cnst, "Unknown constant type %s", cnst->Type->DescriptiveName()); + return new FxConstant(0, *ast); + } + } + + case AST_ExprUnary: + { + auto unary = static_cast(ast); + auto operand = ConvertNode(unary->Operand); + auto op = unary->Operation; + switch (op) + { + case PEX_PostDec: + case PEX_PostInc: + return new FxPostIncrDecr(operand, Pex2Tok[op]); + + case PEX_PreDec: + case PEX_PreInc: + return new FxPreIncrDecr(operand, Pex2Tok[op]); + + case PEX_Negate: + return new FxMinusSign(operand); + + case PEX_AntiNegate: + return new FxPlusSign(operand); + + case PEX_BitNot: + return new FxUnaryNotBitwise(operand); + + case PEX_BoolNot: + return new FxUnaryNotBoolean(operand); + + case PEX_SizeOf: + case PEX_AlignOf: + return new FxSizeAlign(operand, Pex2Tok[op]); + + default: + assert(0 && "Unknown unary operator."); // should never happen + Error(unary, "Unknown unary operator ID #%d", op); + return new FxNop(*ast); + } + break; + } + + + case AST_ExprBinary: + { + auto binary = static_cast(ast); + auto left = ConvertNode(binary->Left); + auto right = ConvertNode(binary->Right); + auto op = binary->Operation; + auto tok = Pex2Tok[op]; + switch (op) + { + case PEX_Add: + case PEX_Sub: + return new FxAddSub(tok, left, right); + + case PEX_Mul: + case PEX_Div: + case PEX_Mod: + return new FxMulDiv(tok, left, right); + + case PEX_Pow: + return new FxPow(left, right); + + case PEX_LeftShift: + case PEX_RightShift: + case PEX_URightShift: + return new FxShift(tok, left, right); + + case PEX_BitAnd: + case PEX_BitOr: + case PEX_BitXor: + return new FxBitOp(tok, left, right); + + case PEX_BoolOr: + case PEX_BoolAnd: + return new FxBinaryLogical(tok, left, right); + + case PEX_LT: + case PEX_LTEQ: + case PEX_GT: + case PEX_GTEQ: + return new FxCompareRel(tok, left, right); + + case PEX_EQEQ: + case PEX_NEQ: + case PEX_APREQ: + return new FxCompareEq(tok, left, right); + + case PEX_Assign: + return new FxAssign(left, right); + + case PEX_AddAssign: + case PEX_SubAssign: + return ModifyAssign(new FxAddSub(tok, new FxAssignSelf(*ast), right), left); + + case PEX_MulAssign: + case PEX_DivAssign: + case PEX_ModAssign: + return ModifyAssign(new FxMulDiv(tok, new FxAssignSelf(*ast), right), left); + + case PEX_LshAssign: + case PEX_RshAssign: + case PEX_URshAssign: + return ModifyAssign(new FxShift(tok, new FxAssignSelf(*ast), right), left); + + case PEX_AndAssign: + case PEX_OrAssign: + case PEX_XorAssign: + return ModifyAssign(new FxBitOp(tok, new FxAssignSelf(*ast), right), left); + + case PEX_LTGTEQ: + return new FxLtGtEq(left, right); + + case PEX_ArrayAccess: + return new FxArrayElement(left, right); + + case PEX_CrossProduct: + case PEX_DotProduct: + return new FxDotCross(tok, left, right); + + case PEX_Is: + return new FxTypeCheck(left, right); + + case PEX_Concat: + return new FxConcat(left, right); + + default: + I_Error("Binary operator %d not implemented yet", op); + } + break; + } + + case AST_ExprTrinary: + { + auto trinary = static_cast(ast); + auto condition = ConvertNode(trinary->Test); + auto left = ConvertNode(trinary->Left); + auto right = ConvertNode(trinary->Right); + + return new FxConditional(condition, left, right); + } + + case AST_VectorValue: + { + auto vecini = static_cast(ast); + auto xx = ConvertNode(vecini->X); + auto yy = ConvertNode(vecini->Y); + auto zz = ConvertNode(vecini->Z); + auto ww = ConvertNode(vecini->W); + return new FxVectorValue(xx, yy, zz, ww, *ast); + } + + case AST_LocalVarStmt: + { + auto loc = static_cast(ast); + auto node = loc->Vars; + FxSequence *list = new FxSequence(*ast); + + PType *ztype = DetermineType(ConvertClass, node, node->Name, loc->Type, true, false); + + if (loc->Type->ArraySize != nullptr) + { + bool nosize; + ztype = ResolveArraySize(ztype, loc->Type->ArraySize, ConvertClass, &nosize); + + if (nosize) + { + Error(node, "Must specify array size"); + } + } + + do + { + PType *type; + + bool nosize = false; + if (node->ArraySize != nullptr) + { + type = ResolveArraySize(ztype, node->ArraySize, ConvertClass, &nosize); + + if (nosize && !node->InitIsArray) + { + Error(node, "Must specify array size for non-initialized arrays"); + } + } + else + { + type = ztype; + } + + if (node->InitIsArray && (type->isArray() || type->isDynArray() || nosize)) + { + auto arrtype = static_cast(type); + if (!nosize && (arrtype->ElementType->isArray() || arrtype->ElementType->isDynArray())) + { + Error(node, "Compound initializer not implemented yet for multi-dimensional arrays"); + } + FArgumentList args; + ConvertNodeList(args, node->Init); + + if (nosize) + { + type = NewArray(type, args.Size()); + } + list->Add(new FxLocalArrayDeclaration(type, node->Name, args, 0, *node)); + } + else + { + FxExpression *val = node->Init ? ConvertNode(node->Init) : nullptr; + list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar. + } + + node = static_cast(node->SiblingNext); + } while (node != loc->Vars); + return list; + } + + case AST_Expression: + { + auto ret = static_cast(ast); + if (ret->Operation == PEX_Super) + { + return new FxSuper(*ast); + } + break; + } + + case AST_ExpressionStmt: + return ConvertNode(static_cast(ast)->Expression); + + case AST_ReturnStmt: + { + auto ret = static_cast(ast); + FArgumentList args; + ConvertNodeList(args, ret->Values); + if (args.Size() == 0) + { + return new FxReturnStatement(nullptr, *ast); + } + else + { + return new FxReturnStatement(args, *ast); + } + } + + case AST_BreakStmt: + case AST_ContinueStmt: + return new FxJumpStatement(ast->NodeType == AST_BreakStmt ? TK_Break : TK_Continue, *ast); + + case AST_IfStmt: + { + auto iff = static_cast(ast); + FxExpression *const truePath = ConvertImplicitScopeNode(ast, iff->TruePath); + FxExpression *const falsePath = ConvertImplicitScopeNode(ast, iff->FalsePath); + return new FxIfStatement(ConvertNode(iff->Condition), truePath, falsePath, *ast); + } + + case AST_ArrayIterationStmt: + { + auto iter = static_cast(ast); + auto var = iter->ItName->Name; + FxExpression* const itArray = ConvertNode(iter->ItArray); + FxExpression* const itArray2 = ConvertNode(iter->ItArray); + FxExpression* const itArray3 = ConvertNode(iter->ItArray); + FxExpression* const itArray4 = ConvertNode(iter->ItArray); // the handler needs copies of this - here's the easiest place to create them. + FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, itArray3, itArray4, body, *ast); + } + + case AST_TwoArgIterationStmt: + { + auto iter = static_cast(ast); + auto key = iter->ItKey->Name; + auto var = iter->ItValue->Name; + FxExpression* const itMap = ConvertNode(iter->ItMap); + FxExpression* const itMap2 = ConvertNode(iter->ItMap); + FxExpression* const itMap3 = ConvertNode(iter->ItMap); + FxExpression* const itMap4 = ConvertNode(iter->ItMap); + FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxTwoArgForEachLoop(key, var, itMap, itMap2, itMap3, itMap4, body, *ast); + } + + case AST_ThreeArgIterationStmt: + { + auto iter = static_cast(ast); + auto var = iter->ItVar->Name; + auto pos = iter->ItPos->Name; + auto flags = iter->ItFlags->Name; + FxExpression* const itBlock = ConvertNode(iter->ItBlock); + FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxThreeArgForEachLoop(var, pos, flags, itBlock, body, *ast); + } + + case AST_TypedIterationStmt: + { + auto iter = static_cast(ast); + auto cls = iter->ItType->Name; + auto var = iter->ItVar->Name; + FxExpression* const itExpr = ConvertNode(iter->ItExpr); + FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxTypedForEachLoop(cls, var, itExpr, body, *ast); + } + + case AST_IterationStmt: + { + auto iter = static_cast(ast); + if (iter->CheckAt == ZCC_IterationStmt::End) + { + assert(iter->LoopBumper == nullptr); + FxExpression *const loop = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), loop, *ast); + } + else if (iter->LoopBumper != nullptr) + { + FArgumentList bumper; + ConvertNodeList(bumper, iter->LoopBumper); + FxCompoundStatement *bumps = new FxCompoundStatement(*ast); + for (auto &ex : bumper) + { + bumps->Add(ex); + ex = nullptr; + } + return new FxForLoop(nullptr, ConvertNode(iter->LoopCondition), bumps, ConvertNode(iter->LoopStatement), *ast); + } + else + { + FxExpression *const loop = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxWhileLoop(ConvertNode(iter->LoopCondition), loop, *ast); + } + } + + // not yet done + case AST_SwitchStmt: + { + auto swtch = static_cast(ast); + if (swtch->Content->NodeType != AST_CompoundStmt) + { + Error(ast, "Expecting { after 'switch'"); + return new FxNop(*ast); // allow compiler to continue looking for errors. + } + else + { + // The switch content is wrapped into a compound statement which needs to be unraveled here. + auto cmpnd = static_cast(swtch->Content); + FArgumentList args; + return new FxSwitchStatement(ConvertNode(swtch->Condition), ConvertNodeList(args, cmpnd->Content), *ast); + } + } + + case AST_CaseStmt: + { + auto cases = static_cast(ast); + return new FxCaseStatement(ConvertNode(cases->Condition), *ast); + } + + case AST_CompoundStmt: + { + auto x = new FxCompoundStatement(*ast); + auto compound = static_cast(ast); + auto node = compound->Content; + if (node != nullptr) do + { + x->Add(ConvertNode(node)); + node = static_cast(node->SiblingNext); + } while (node != compound->Content); + return x; + } + + case AST_AssignStmt: + { + auto ass = static_cast(ast); + FArgumentList args; + ConvertNodeList(args, ass->Dests); + assert(ass->Sources->SiblingNext == ass->Sources); // right side should be a single function call - nothing else + if (ass->Sources->NodeType != AST_ExprFuncCall) + { + // don't let this through to the code generator. This node is only used to assign multiple returns of a function to more than one variable. + Error(ass, "Right side of multi-assignment must be a function call"); + return new FxNop(*ast); // allow compiler to continue looking for errors. + } + return new FxMultiAssign(args, ConvertNode(ass->Sources), *ast); + } + + case AST_AssignDeclStmt: + { + auto ass = static_cast(ast); + FArgumentList args; + { + ZCC_TreeNode *n = ass->Dests; + if(n) do + { + args.Push(new FxIdentifier(static_cast(n)->Id,*n)); + n = n->SiblingNext; + } while(n != ass->Dests); + } + assert(ass->Sources->SiblingNext == ass->Sources); // right side should be a single function call - nothing else + if (ass->Sources->NodeType != AST_ExprFuncCall) + { + // don't let this through to the code generator. This node is only used to assign multiple returns of a function to more than one variable. + Error(ass, "Right side of multi-assignment must be a function call"); + return new FxNop(*ast); // allow compiler to continue looking for errors. + } + return new FxMultiAssignDecl(args, ConvertNode(ass->Sources), *ast); + } + + default: + break; + } + // only for development. I_Error is more convenient here than a normal error. + I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType); + return nullptr; +} + +//========================================================================== +// +// Wrapper around ConvertNode() that adds a scope (a compound statement) +// when needed to avoid leaking of variable or contant to an outer scope: +// +// if (true) int i; else bool b[1]; +// while (false) readonly a; +// do static const float f[] = {0}; while (false); +// +// Accessing such variables outside of their statements is now an error +// +//========================================================================== + +FxExpression *ZCCCompiler::ConvertImplicitScopeNode(ZCC_TreeNode *node, ZCC_Statement *nested) +{ + assert(nullptr != node); + + if (nullptr == nested) + { + return nullptr; + } + + FxExpression *nestedExpr = ConvertNode(nested); + assert(nullptr != nestedExpr); + + const EZCCTreeNodeType nestedType = nested->NodeType; + const bool needScope = AST_LocalVarStmt == nestedType || AST_StaticArrayStatement == nestedType; + + if (needScope) + { + FxCompoundStatement *implicitCompound = new FxCompoundStatement(*node); + implicitCompound->Add(nestedExpr); + + nestedExpr = implicitCompound; + } + + return nestedExpr; +} + + +FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *head) +{ + if (head != nullptr) + { + auto node = head; + do + { + args.Push(ConvertNode(node)); + node = node->SiblingNext; + } while (node != head); + } + return args; +} diff --git a/src/scripting/zscript/zcc_compile.h b/src/common/scripting/frontend/zcc_compile.h similarity index 83% rename from src/scripting/zscript/zcc_compile.h rename to src/common/scripting/frontend/zcc_compile.h index 040d28bd308..19e9f8ff078 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/common/scripting/frontend/zcc_compile.h @@ -2,11 +2,10 @@ #define ZCC_COMPILE_H #include -#include "backend/codegen.h" +#include "codegen.h" struct Baggage; struct FPropertyInfo; -class AActor; class FxExpression; typedef TDeletingArray FArgumentList; @@ -23,6 +22,7 @@ struct ZCC_StructWork TArray Fields; TArray Functions; TArray Arrays; + TArray FlagDefs; ZCC_StructWork() { @@ -106,11 +106,14 @@ class ZCCCompiler { public: ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PNamespace *outnamespace, int lumpnum, const VersionInfo & ver); - ~ZCCCompiler(); - int Compile(); + virtual ~ZCCCompiler(); + virtual int Compile(); -private: +protected: const char * GetStringConst(FxExpression *ex, FCompileContext &ctx); + virtual int CheckActionKeyword(ZCC_FuncDeclarator* f, uint32_t &varflags, int useflags, ZCC_StructWork *c) { return -1; } // stock implementation does not support this. + virtual bool PrepareMetaData(PClass *type) { return false; } + virtual void SetImplicitArgs(TArray* args, TArray* argflags, TArray* argnames, PContainerType* cls, uint32_t funcflags, int useflags); int IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls); FString StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls); @@ -128,24 +131,19 @@ class ZCCCompiler void CompileAllFields(); bool CompileFields(PContainerType *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); - void CompileAllProperties(); - bool CompileProperties(PClass *type, TArray &Properties, FName prefix); - bool CompileFlagDefs(PClass *type, TArray &FlagDefs, FName prefix); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls, bool *nosize); - PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym, bool nativetype); + PType *ResolveUserType(ZCC_BasicType *type, ZCC_Identifier *id, PSymbolTable *sym, bool nativetype); + static FString UserTypeName(ZCC_BasicType *type); + TArray OrderStructs(); + void AddStruct(TArray &new_order, ZCC_StructWork *struct_def); + ZCC_StructWork *StructTypeToWork(const PStruct *type) const; - void InitDefaults(); - void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg); - void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag); - void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); - void DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); void CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass); void InitFunctions(); - void CompileStates(); - FxExpression *SetupActionFunction(PClass *cls, ZCC_TreeNode *sl, int stateflags); + virtual void InitDefaults(); TArray Constants; TArray Structs; diff --git a/src/scripting/zscript/zcc_exprlist.h b/src/common/scripting/frontend/zcc_exprlist.h similarity index 97% rename from src/scripting/zscript/zcc_exprlist.h rename to src/common/scripting/frontend/zcc_exprlist.h index faf6af6a43d..f05758379a2 100644 --- a/src/scripting/zscript/zcc_exprlist.h +++ b/src/common/scripting/frontend/zcc_exprlist.h @@ -9,6 +9,7 @@ xx(FuncCall, '(') xx(ArrayAccess, TK_Array) xx(MemberAccess, '.') xx(ClassCast, TK_Class) +xx(FunctionPtrCast, TK_FunctionType) xx(TypeRef, TK_Class) xx(Vector, TK_Vector2) diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/common/scripting/frontend/zcc_parser.cpp similarity index 83% rename from src/scripting/zscript/zcc_parser.cpp rename to src/common/scripting/frontend/zcc_parser.cpp index 0f9a06f422e..6ea3c316e6b 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/common/scripting/frontend/zcc_parser.cpp @@ -33,7 +33,7 @@ #include "dobject.h" #include "sc_man.h" -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" #include "m_argv.h" #include "v_text.h" @@ -41,17 +41,72 @@ #include "zcc_parser.h" #include "zcc_compile.h" + TArray Includes; TArray IncludeLocs; +static FString ResolveIncludePath(const FString &path,const FString &lumpname){ + if (path.IndexOf("./") == 0 || path.IndexOf("../") == 0) // relative path resolving + { + auto start = lumpname.LastIndexOf(":"); // find find separator between wad and path + + auto end = lumpname.LastIndexOf("/"); // find last '/' + + // it's a top-level file, if it's a folder being loaded ( /xxx/yyy/:whatever.zs ) end is before than start, or if it's a zip ( xxx.zip:whatever.zs ) end would be -1 + bool topLevelFile = start > end ; + + FString fullPath = topLevelFile ? FString {} : lumpname.Mid(start + 1, end - start - 1); // get path from lumpname (format 'wad:filepath/filename') + + if (start != -1) + { + FString relativePath = path; + if (relativePath.IndexOf("./") == 0) // strip initial marker + { + relativePath = relativePath.Mid(2); + } + + bool pathOk = true; + + while (relativePath.IndexOf("../") == 0) // go back one folder for each '..' + { + relativePath = relativePath.Mid(3); + auto slash_index = fullPath.LastIndexOf("/"); + if (slash_index != -1) + { + fullPath = fullPath.Mid(0, slash_index); + } + else if (fullPath.IsNotEmpty()) + { + fullPath = ""; + } + else + { + pathOk = false; + break; + } + } + if (pathOk) // if '..' parsing was successful + { + return topLevelFile ? relativePath : fullPath + "/" + relativePath; + } + } + } + return path; +} + static FString ZCCTokenName(int terminal); void AddInclude(ZCC_ExprConstant *node) { assert(node->Type == TypeString); - if (Includes.Find(*node->StringVal) >= Includes.Size()) + + FScriptPosition pos(*node); + + FString path = ResolveIncludePath(*node->StringVal, pos.FileName.GetChars()); + + if (Includes.Find(path) >= Includes.Size()) { - Includes.Push(*node->StringVal); - IncludeLocs.Push(*node); + Includes.Push(path); + IncludeLocs.Push(pos); } } @@ -172,7 +227,9 @@ static void InitTokenMap() TOKENDEF2(TK_Vector3, ZCC_VECTOR3, NAME_Vector3); TOKENDEF2(TK_Name, ZCC_NAME, NAME_Name); TOKENDEF2(TK_Map, ZCC_MAP, NAME_Map); + TOKENDEF2(TK_MapIterator, ZCC_MAPITERATOR,NAME_MapIterator); TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_Array); + TOKENDEF2(TK_FunctionType, ZCC_FNTYPE, NAME_Function); TOKENDEF2(TK_Include, ZCC_INCLUDE, NAME_Include); TOKENDEF (TK_Void, ZCC_VOID); TOKENDEF (TK_True, ZCC_TRUE); @@ -183,6 +240,7 @@ static void InitTokenMap() TOKENDEF (TK_Out, ZCC_OUT); TOKENDEF (TK_Super, ZCC_SUPER); TOKENDEF (TK_Null, ZCC_NULLPTR); + TOKENDEF (TK_Sealed, ZCC_SEALED); TOKENDEF ('~', ZCC_TILDE); TOKENDEF ('!', ZCC_BANG); TOKENDEF (TK_SizeOf, ZCC_SIZEOF); @@ -192,6 +250,7 @@ static void InitTokenMap() TOKENDEF (TK_Return, ZCC_RETURN); TOKENDEF (TK_Do, ZCC_DO); TOKENDEF (TK_For, ZCC_FOR); + TOKENDEF (TK_ForEach, ZCC_FOREACH); TOKENDEF (TK_While, ZCC_WHILE); TOKENDEF (TK_Until, ZCC_UNTIL); TOKENDEF (TK_If, ZCC_IF); @@ -245,7 +304,7 @@ static void ParseSingleFile(FScanner *pSC, const char *filename, int lump, void { if (filename != nullptr) { - lump = Wads.CheckNumForFullName(filename, true); + lump = fileSystem.CheckNumForFullName(filename, true); if (lump >= 0) { lsc.OpenLumpNum(lump); @@ -297,12 +356,12 @@ static void ParseSingleFile(FScanner *pSC, const char *filename, int lump, void case TK_None: // 'NONE' is a token for SBARINFO but not here. case TK_Identifier: - value.Int = FName(sc.String); + value.Int = FName(sc.String).GetIndex(); tokentype = ZCC_IDENTIFIER; break; case TK_NonWhitespace: - value.Int = FName(sc.String); + value.Int = FName(sc.String).GetIndex(); tokentype = ZCC_NWS; break; @@ -349,16 +408,22 @@ static void ParseSingleFile(FScanner *pSC, const char *filename, int lump, void //**-------------------------------------------------------------------------- -static void DoParse(int lumpnum) +PNamespace *ParseOneScript(const int baselump, ZCCParseState &state) { FScanner sc; void *parser; ZCCToken value; - auto baselump = lumpnum; - auto fileno = Wads.GetLumpFile(lumpnum); + int lumpnum = baselump; + auto fileno = fileSystem.GetFileContainer(lumpnum); + + state.FileNo = fileno; + + if (TokenMap.CountUsed() == 0) + { + InitTokenMap(); + } parser = ZCCParseAlloc(malloc); - ZCCParseState state; #ifndef NDEBUG FILE *f = nullptr; @@ -415,18 +480,18 @@ static void DoParse(int lumpnum) ParseSingleFile(&sc, nullptr, lumpnum, parser, state); for (unsigned i = 0; i < Includes.Size(); i++) { - lumpnum = Wads.CheckNumForFullName(Includes[i], true); + lumpnum = fileSystem.CheckNumForFullName(Includes[i].GetChars(), true); if (lumpnum == -1) { IncludeLocs[i].Message(MSG_ERROR, "Include script lump %s not found", Includes[i].GetChars()); } else { - auto fileno2 = Wads.GetLumpFile(lumpnum); + auto fileno2 = fileSystem.GetFileContainer(lumpnum); if (fileno == 0 && fileno2 != 0) { I_FatalError("File %s is overriding core lump %s.", - Wads.GetWadFullName(Wads.GetLumpFile(lumpnum)), Includes[i].GetChars()); + fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(lumpnum)), Includes[i].GetChars()); } ParseSingleFile(nullptr, nullptr, lumpnum, parser, state); @@ -445,7 +510,7 @@ static void DoParse(int lumpnum) // If the parser fails, there is no point starting the compiler, because it'd only flood the output with endless errors. if (FScriptPosition::ErrorCounter > 0) { - I_Error("%d errors while parsing %s", FScriptPosition::ErrorCounter, Wads.GetLumpFullPath(baselump).GetChars()); + I_Error("%d errors while parsing %s", FScriptPosition::ErrorCounter, fileSystem.GetFileFullPath(baselump).c_str()); } #ifndef NDEBUG @@ -459,10 +524,10 @@ static void DoParse(int lumpnum) if (Args->CheckParm("-dumpast")) { FString ast = ZCC_PrintAST(state.TopNode); - FString filename = Wads.GetLumpFullPath(baselump); + FString filename = fileSystem.GetFileFullPath(baselump).c_str(); filename.ReplaceChars(":\\/?|", '.'); filename << ".ast"; - FileWriter *ff = FileWriter::Open(filename); + FileWriter *ff = FileWriter::Open(filename.GetChars()); if (ff != NULL) { ff->Write(ast.GetChars(), ast.Len()); @@ -470,37 +535,8 @@ static void DoParse(int lumpnum) } } - PSymbolTable symtable; - auto newns = Wads.GetLumpFile(baselump) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(Wads.GetLumpFile(baselump)); - ZCCCompiler cc(state, NULL, symtable, newns, baselump, state.ParseVersion); - cc.Compile(); - - if (FScriptPosition::ErrorCounter > 0) - { - // Abort if the compiler produced any errors. Also do not compile further lumps, because they very likely miss some stuff. - I_Error("%d errors, %d warnings while compiling %s", FScriptPosition::ErrorCounter, FScriptPosition::WarnCounter, Wads.GetLumpFullPath(baselump).GetChars()); - } - else if (FScriptPosition::WarnCounter > 0) - { - // If we got warnings, but no errors, print the information but continue. - Printf(TEXTCOLOR_ORANGE "%d warnings while compiling %s\n", FScriptPosition::WarnCounter, Wads.GetLumpFullPath(baselump).GetChars()); - } - -} - -void ParseScripts() -{ - if (TokenMap.CountUsed() == 0) - { - InitTokenMap(); - } - int lump, lastlump = 0; - FScriptPosition::ResetErrorCounter(); - - while ((lump = Wads.FindLump("ZSCRIPT", &lastlump)) != -1) - { - DoParse(lump); - } + auto newns = fileSystem.GetFileContainer(baselump) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(fileSystem.GetFileContainer(baselump)); + return newns; } static FString ZCCTokenName(int terminal) @@ -872,6 +908,19 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c break; } + case AST_MapIteratorType: + { + TreeNodeDeepCopy_Start(MapIteratorType); + + // ZCC_Type + copy->ArraySize = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ArraySize, true, copiedNodesList)); + // AST_MapIteratorType + copy->KeyType = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->KeyType, true, copiedNodesList)); + copy->ValueType = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ValueType, true, copiedNodesList)); + + break; + } + case AST_DynArrayType: { TreeNodeDeepCopy_Start(DynArrayType); @@ -884,6 +933,29 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c break; } + case AST_FuncPtrParamDecl: + { + TreeNodeDeepCopy_Start(FuncPtrParamDecl); + + // ZCC_FuncPtrParamDecl + copy->Type = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->Type, true, copiedNodesList)); + copy->Flags = origCasted->Flags; + + break; + } + + case AST_FuncPtrType: + { + TreeNodeDeepCopy_Start(FuncPtrType); + + // ZCC_FuncPtrType + copy->RetType = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->RetType, true, copiedNodesList)); + copy->Params = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->Params, true, copiedNodesList)); + copy->Scope = origCasted->Scope; + + break; + } + case AST_ClassType: { TreeNodeDeepCopy_Start(ClassType); @@ -1100,6 +1172,58 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c break; } + case AST_ArrayIterationStmt: + { + TreeNodeDeepCopy_Start(ArrayIterationStmt); + + // ZCC_ArrayIterationStmt + copy->ItName = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItName, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItArray = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItArray, true, copiedNodesList)); + + break; + } + + case AST_TwoArgIterationStmt: + { + TreeNodeDeepCopy_Start(TwoArgIterationStmt); + + // ZCC_TwoArgIterationStmt + copy->ItKey = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItKey, true, copiedNodesList)); + copy->ItValue = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItValue, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItMap = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItMap, true, copiedNodesList)); + + break; + } + + case AST_ThreeArgIterationStmt: + { + TreeNodeDeepCopy_Start(ThreeArgIterationStmt); + + // ZCC_TwoArgIterationStmt + copy->ItVar = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList)); + copy->ItPos = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItPos, true, copiedNodesList)); + copy->ItFlags = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItFlags, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItBlock = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItBlock, true, copiedNodesList)); + + break; + } + + case AST_TypedIterationStmt: + { + TreeNodeDeepCopy_Start(TypedIterationStmt); + + // ZCC_TwoArgIterationStmt + copy->ItType = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItType, true, copiedNodesList)); + copy->ItVar = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItExpr = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItExpr, true, copiedNodesList)); + + break; + } + case AST_IfStmt: { TreeNodeDeepCopy_Start(IfStmt); @@ -1145,6 +1269,18 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c break; } + case AST_AssignDeclStmt: + { + TreeNodeDeepCopy_Start(AssignDeclStmt); + + // ZCC_AssignDeclStmt + copy->Dests = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->Dests, true, copiedNodesList)); + copy->Sources = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->Sources, true, copiedNodesList)); + copy->AssignOp = origCasted->AssignOp; + + break; + } + case AST_LocalVarStmt: { TreeNodeDeepCopy_Start(LocalVarStmt); @@ -1274,7 +1410,8 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c // ZCC_VectorValue copy->X = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->X, true, copiedNodesList)); copy->Y = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->Y, true, copiedNodesList)); - copy->Z = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->Z, true, copiedNodesList)); + copy->Z = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->Z, true, copiedNodesList)); + copy->W = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->W, true, copiedNodesList)); break; } @@ -1291,7 +1428,7 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c break; } - + case AST_ClassCast: { TreeNodeDeepCopy_Start(ClassCast); @@ -1305,7 +1442,21 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c break; } + + case AST_FunctionPtrCast: + { + TreeNodeDeepCopy_Start(FunctionPtrCast); + // ZCC_Expression + copy->Operation = origCasted->Operation; + copy->Type = origCasted->Type; + // ZCC_FunctionPtrCast + copy->PtrType = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->PtrType, true, copiedNodesList)); + copy->Expr = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->Expr, true, copiedNodesList)); + + break; + } + case AST_StaticArrayStatement: { TreeNodeDeepCopy_Start(StaticArrayStatement); diff --git a/src/scripting/zscript/zcc_parser.h b/src/common/scripting/frontend/zcc_parser.h similarity index 86% rename from src/scripting/zscript/zcc_parser.h rename to src/common/scripting/frontend/zcc_parser.h index 3b0e9eb193f..d0b6264da5d 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/common/scripting/frontend/zcc_parser.h @@ -64,6 +64,7 @@ enum ZCC_VirtualScope = 1 << 20, ZCC_Version = 1 << 21, ZCC_Internal = 1 << 22, + ZCC_Sealed = 1 << 23, }; // Function parameter modifiers @@ -98,7 +99,10 @@ enum EZCCTreeNodeType AST_Type, AST_BasicType, AST_MapType, + AST_MapIteratorType, AST_DynArrayType, + AST_FuncPtrParamDecl, + AST_FuncPtrType, AST_ClassType, AST_Expression, AST_ExprID, @@ -121,6 +125,7 @@ enum EZCCTreeNodeType AST_SwitchStmt, AST_CaseStmt, AST_AssignStmt, + AST_AssignDeclStmt, AST_LocalVarStmt, AST_FuncParamDecl, AST_ConstantDef, @@ -133,11 +138,16 @@ enum EZCCTreeNodeType AST_VectorValue, AST_DeclFlags, AST_ClassCast, + AST_FunctionPtrCast, AST_StaticArrayStatement, AST_Property, AST_FlagDef, AST_MixinDef, AST_MixinStmt, + AST_ArrayIterationStmt, + AST_TwoArgIterationStmt, + AST_ThreeArgIterationStmt, + AST_TypedIterationStmt, NUM_AST_NODE_TYPES }; @@ -158,6 +168,7 @@ enum EZCCBuiltinType ZCC_String, ZCC_Vector2, ZCC_Vector3, + ZCC_Vector4, ZCC_Name, ZCC_Color, // special types for ZDoom. @@ -247,6 +258,7 @@ struct ZCC_Class : ZCC_Struct { ZCC_Identifier *ParentName; ZCC_Identifier *Replaces; + ZCC_Identifier *Sealed; PClass *CType() { return static_cast(Type)->Descriptor; } }; @@ -365,11 +377,30 @@ struct ZCC_MapType : ZCC_Type ZCC_Type *ValueType; }; +struct ZCC_MapIteratorType : ZCC_Type +{ + ZCC_Type *KeyType; + ZCC_Type *ValueType; +}; + struct ZCC_DynArrayType : ZCC_Type { ZCC_Type *ElementType; }; +struct ZCC_FuncPtrParamDecl : ZCC_TreeNode +{ + ZCC_Type *Type; + int Flags; +}; + +struct ZCC_FuncPtrType : ZCC_Type +{ + ZCC_Type *RetType; + ZCC_FuncPtrParamDecl *Params; + int Scope; +}; + struct ZCC_ClassType : ZCC_Type { ZCC_Identifier *Restriction; @@ -416,6 +447,12 @@ struct ZCC_ClassCast : ZCC_Expression ZCC_FuncParm *Parameters; }; +struct ZCC_FunctionPtrCast : ZCC_Expression +{ + ZCC_FuncPtrType *PtrType; + ZCC_Expression *Expr; +}; + struct ZCC_ExprMemberAccess : ZCC_Expression { ZCC_Expression *Left; @@ -442,7 +479,7 @@ struct ZCC_ExprTrinary : ZCC_Expression struct ZCC_VectorValue : ZCC_Expression { - ZCC_Expression *X, *Y, *Z; + ZCC_Expression *X, *Y, *Z, *W; }; struct ZCC_Statement : ZCC_TreeNode @@ -491,6 +528,38 @@ struct ZCC_IterationStmt : ZCC_Statement enum { Start, End } CheckAt; }; +struct ZCC_ArrayIterationStmt : ZCC_Statement +{ + ZCC_VarName* ItName; + ZCC_Expression* ItArray; + ZCC_Statement* LoopStatement; +}; + +struct ZCC_TwoArgIterationStmt : ZCC_Statement +{ + ZCC_VarName* ItKey; + ZCC_VarName* ItValue; + ZCC_Expression* ItMap; + ZCC_Statement* LoopStatement; +}; + +struct ZCC_ThreeArgIterationStmt : ZCC_Statement +{ + ZCC_VarName* ItVar; + ZCC_VarName* ItPos; + ZCC_VarName* ItFlags; + ZCC_Expression* ItBlock; + ZCC_Statement* LoopStatement; +}; + +struct ZCC_TypedIterationStmt : ZCC_Statement +{ + ZCC_VarName* ItType; + ZCC_VarName* ItVar; + ZCC_Expression* ItExpr; + ZCC_Statement* LoopStatement; +}; + struct ZCC_IfStmt : ZCC_Statement { ZCC_Expression *Condition; @@ -517,6 +586,13 @@ struct ZCC_AssignStmt : ZCC_Statement int AssignOp; }; +struct ZCC_AssignDeclStmt : ZCC_Statement +{ + ZCC_Identifier *Dests; + ZCC_Expression *Sources; + int AssignOp; +}; + struct ZCC_LocalVarStmt : ZCC_Statement { ZCC_Type *Type; @@ -592,7 +668,7 @@ struct ZCC_MixinStmt : ZCC_Statement ENamedName MixinName; }; -FString ZCC_PrintAST(ZCC_TreeNode *root); +FString ZCC_PrintAST(const ZCC_TreeNode *root); struct ZCC_AST @@ -604,6 +680,7 @@ struct ZCC_AST FMemArena SyntaxArena; struct ZCC_TreeNode *TopNode; VersionInfo ParseVersion; + int FileNo; }; struct ZCCParseState : public ZCC_AST @@ -618,4 +695,7 @@ const char *GetMixinTypeString(EZCCMixinType type); ZCC_TreeNode *TreeNodeDeepCopy(ZCC_AST *ast, ZCC_TreeNode *orig, bool copySiblings); +// Main entry point for the parser. Returns some data needed by the compiler. +PNamespace* ParseOneScript(const int baselump, ZCCParseState& state); + #endif diff --git a/src/common/scripting/interface/stringformat.cpp b/src/common/scripting/interface/stringformat.cpp new file mode 100644 index 00000000000..3d7a3c428e7 --- /dev/null +++ b/src/common/scripting/interface/stringformat.cpp @@ -0,0 +1,651 @@ +/* +** thingdef_data.cpp +** +** DECORATE data tables +** +**--------------------------------------------------------------------------- +** Copyright 2002-2008 Christoph Oelckers +** Copyright 2004-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "zstring.h" +#include "vm.h" +#include "gstrings.h" +#include "v_font.h" +#include "types.h" +#include "utf8.h" + + + +FString FStringFormat(VM_ARGS, int offset) +{ + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + assert(va_reginfo[offset] == REGT_STRING); + + FString fmtstring = param[offset].s().GetChars(); + + param += offset; + numparam -= offset; + va_reginfo += offset; + + // note: we don't need a real printf format parser. + // enough to simply find the subtitution tokens and feed them to the real printf after checking types. + // https://en.wikipedia.org/wiki/Printf_format_string#Format_placeholder_specification + FString output; + bool in_fmt = false; + FString fmt_current; + int argnum = 1; + int argauto = 1; + // % = starts + // [0-9], -, +, \s, 0, #, . continue + // %, s, d, i, u, fF, eE, gG, xX, o, c, p, aA terminate + // various type flags are not supported. not like stuff like 'hh' modifier is to be used in the VM. + // the only combination that is parsed locally is %n$... + bool haveargnums = false; + for (size_t i = 0; i < fmtstring.Len(); i++) + { + char c = fmtstring[i]; + if (in_fmt) + { + if (c == '*' && (fmt_current.Len() == 1 || (fmt_current.Len() == 2 && fmt_current[1] == '0'))) + { + fmt_current += c; + } + else if ((c >= '0' && c <= '9') || + c == '-' || c == '+' || (c == ' ' && fmt_current.Back() != ' ') || c == '#' || c == '.') + { + fmt_current += c; + } + else if (c == '$') // %number$format + { + if (!haveargnums && argauto > 1) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + FString argnumstr = fmt_current.Mid(1); + if (!argnumstr.IsInt()) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for argument number, got '%s'.", argnumstr.GetChars()); + auto argnum64 = argnumstr.ToLong(); + if (argnum64 < 1 || argnum64 >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format (tried to access argument %d, %d total).", argnum64, numparam); + fmt_current = "%"; + haveargnums = true; + argnum = int(argnum64); + } + else + { + fmt_current += c; + + switch (c) + { + // string + case 's': + { + if (argnum < 0 && haveargnums) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + in_fmt = false; + // fail if something was found, but it's not a string + if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (va_reginfo[argnum] != REGT_STRING) ThrowAbortException(X_FORMAT_ERROR, "Expected a string for format %s.", fmt_current.GetChars()); + // append + output.AppendFormat(fmt_current.GetChars(), param[argnum].s().GetChars()); + if (!haveargnums) argnum = ++argauto; + else argnum = -1; + break; + } + + // pointer + case 'p': + { + if (argnum < 0 && haveargnums) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + in_fmt = false; + // fail if something was found, but it's not a string + if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (va_reginfo[argnum] != REGT_POINTER) ThrowAbortException(X_FORMAT_ERROR, "Expected a pointer for format %s.", fmt_current.GetChars()); + // append + output.AppendFormat(fmt_current.GetChars(), param[argnum].a); + if (!haveargnums) argnum = ++argauto; + else argnum = -1; + break; + } + + // int formats (including char) + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'c': + case 'B': + { + if (argnum < 0 && haveargnums) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + in_fmt = false; + // append + if (fmt_current[1] == '*' || fmt_current[2] == '*') + { + // fail if something was found, but it's not an int + if (argnum+1 >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (va_reginfo[argnum] != REGT_INT && + va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + if (va_reginfo[argnum+1] != REGT_INT && + va_reginfo[argnum+1] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + + output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt(va_reginfo[argnum]), param[argnum + 1].ToInt(va_reginfo[argnum + 1])); + argauto++; + } + else + { + // fail if something was found, but it's not an int + if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (va_reginfo[argnum] != REGT_INT && + va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt(va_reginfo[argnum])); + } + if (!haveargnums) argnum = ++argauto; + else argnum = -1; + break; + } + + // double formats + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + { + if (argnum < 0 && haveargnums) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + in_fmt = false; + if (fmt_current[1] == '*' || fmt_current[2] == '*') + { + // fail if something was found, but it's not an int + if (argnum + 1 >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (va_reginfo[argnum] != REGT_INT && + va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + if (va_reginfo[argnum + 1] != REGT_INT && + va_reginfo[argnum + 1] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + + output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt(va_reginfo[argnum]), param[argnum + 1].ToDouble(va_reginfo[argnum + 1])); + argauto++; + } + else + { + // fail if something was found, but it's not a float + if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (va_reginfo[argnum] != REGT_INT && + va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + // append + output.AppendFormat(fmt_current.GetChars(), param[argnum].ToDouble(va_reginfo[argnum])); + } + if (!haveargnums) argnum = ++argauto; + else argnum = -1; + break; + } + + default: + // invalid character + output += fmt_current; + in_fmt = false; + break; + } + } + } + else + { + if (c == '%') + { + if (i + 1 < fmtstring.Len() && fmtstring[i + 1] == '%') + { + output += '%'; + i++; + } + else + { + in_fmt = true; + fmt_current = "%"; + } + } + else + { + output += c; + } + } + } + + return output; +} + +DEFINE_ACTION_FUNCTION(FStringStruct, Format) +{ + PARAM_PROLOGUE; + FString s = FStringFormat(VM_ARGS_NAMES); + ACTION_RETURN_STRING(s); +} + +DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + // first parameter is the self pointer + FString s = FStringFormat(VM_ARGS_NAMES, 1); + (*self) += s; + return 0; +} + +DEFINE_ACTION_FUNCTION(FStringStruct, AppendCharacter) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(c); + self->AppendCharacter(c); + return 0; +} + +DEFINE_ACTION_FUNCTION(FStringStruct, DeleteLastCharacter) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + self->DeleteLastCharacter(); + return 0; +} + +//===================================================================================== +// +// FString exports +// +//===================================================================================== + +static void LocalizeString(const FString &label, bool prefixed, FString *result) +{ + if (!prefixed) *result = GStrings.GetString(label); + else if (label[0] != '$') *result = label; + else *result = GStrings.GetString(&label[1]); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringTable, Localize, LocalizeString) +{ + PARAM_PROLOGUE; + PARAM_STRING(label); + PARAM_BOOL(prefixed); + FString result; + LocalizeString(label, prefixed, &result); + ACTION_RETURN_STRING(result); +} + +static void StringReplace(FString *self, const FString &s1, const FString &s2) +{ + self->Substitute(s1, s2); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Replace, StringReplace) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(s1); + PARAM_STRING(s2); + self->Substitute(s1, s2); + return 0; +} + +static void StringMid(FString *self, unsigned pos, unsigned len, FString *result) +{ + *result = self->Mid(pos, len); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Mid, StringMid) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_UINT(pos); + PARAM_UINT(len); + FString s = self->Mid(pos, len); + ACTION_RETURN_STRING(s); +} + +static void StringLeft(FString *self, unsigned len, FString *result) +{ + *result = self->Left(len); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Left, StringLeft) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_UINT(len); + FString s = self->Left(len); + ACTION_RETURN_STRING(s); +} + +static void StringTruncate(FString *self, unsigned len) +{ + self->Truncate(len); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Truncate, StringTruncate) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_UINT(len); + self->Truncate(len); + return 0; +} + +static void StringRemove(FString *self, unsigned index, unsigned remlen) +{ + self->Remove(index, remlen); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Remove, StringRemove) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_UINT(index); + PARAM_UINT(remlen); + self->Remove(index, remlen); + return 0; +} + +static void StringCharAt(FString *self, int pos, FString *result) +{ + if ((unsigned)pos >= self->Len()) *result = ""; + else *result = FString((*self)[pos]); +} +// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CharAt, StringCharAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + FString result; + StringCharAt(self, pos, &result); + ACTION_RETURN_STRING(result); +} + +static int StringCharCodeAt(FString *self, int pos) +{ + if ((unsigned)pos >= self->Len()) return 0; + else return (*self)[pos]; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CharCodeAt, StringCharCodeAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + ACTION_RETURN_INT(StringCharCodeAt(self, pos)); +} + +static int StringByteAt(FString *self, int pos) +{ + if ((unsigned)pos >= self->Len()) return 0; + else return (uint8_t)((*self)[pos]); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ByteAt, StringByteAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + ACTION_RETURN_INT(StringByteAt(self, pos)); +} + +static void StringFilter(FString *self, FString *result) +{ + *result = strbin1(self->GetChars()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Filter, StringFilter) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_STRING(strbin1(self->GetChars())); +} + +static int StringIndexOf(FString *self, const FString &substr, int startIndex) +{ + return (int)self->IndexOf(substr, startIndex); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, IndexOf, StringIndexOf) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(substr); + PARAM_INT(startIndex); + ACTION_RETURN_INT(StringIndexOf(self, substr, startIndex)); +} + +static int StringLastIndexOf(FString *self, const FString &substr, int endIndex) +{ + return (int)self->LastIndexOfBroken(substr, endIndex); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, LastIndexOf, StringLastIndexOf) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(substr); + PARAM_INT(endIndex); + ACTION_RETURN_INT(StringLastIndexOf(self, substr, endIndex)); +} + +static int StringRightIndexOf(FString *self, const FString &substr, int endIndex) +{ + return (int)self->LastIndexOf(substr, endIndex); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, RightIndexOf, StringRightIndexOf) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(substr); + PARAM_INT(endIndex); + ACTION_RETURN_INT(StringRightIndexOf(self, substr, endIndex)); +} + +static void StringToUpper(FString *self) +{ + self->ToUpper(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToUpper, StringToUpper) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + self->ToUpper(); + return 0; +} + +static void StringToLower(FString *self) +{ + self->ToLower(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToLower, StringToLower) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + self->ToLower(); + return 0; +} + +static void StringMakeUpper(FString *self, FString *out) +{ + *out = self->MakeUpper(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, MakeUpper, StringMakeUpper) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_STRING(self->MakeUpper()); +} + +static void StringMakeLower(FString *self, FString *out) +{ + *out = self->MakeLower(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, MakeLower, StringMakeLower) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_STRING(self->MakeLower()); +} + +static int StringCharUpper(int ch) +{ + return ch >= 0 && ch < 65536 ? upperforlower[ch] : ch; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CharUpper, StringCharUpper) +{ + PARAM_PROLOGUE; + PARAM_INT(ch); + ACTION_RETURN_INT(StringCharUpper(ch)); +} + +static int StringCharLower(int ch) +{ + return ch >= 0 && ch < 65536 ? lowerforupper[ch] : ch; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CharLower, StringCharLower) +{ + PARAM_PROLOGUE; + PARAM_INT(ch); + ACTION_RETURN_INT(StringCharLower(ch)); +} + + +static int StringToInt(FString *self, int base) +{ + return (int)self->ToLong(base); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToInt, StringToInt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(base); + ACTION_RETURN_INT((int)self->ToLong(base)); +} + +static double StringToDbl(FString *self) +{ + return self->ToDouble(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToDouble, StringToDbl) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_FLOAT(self->ToDouble()); +} + +static void StringSubst(FString *self, const FString &substr, const FString& replc) +{ + self->Substitute(substr, replc); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Substitute, StringSubst) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(substr); + PARAM_STRING(replc); + StringSubst(self, substr, replc); + return 0; +} + +static void StringStripRight(FString* self, const FString& junk) +{ + if (junk.IsNotEmpty()) self->StripRight(junk); + else self->StripRight(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, StripRight, StringStripRight) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(junk); + StringStripRight(self, junk); + return 0; +} + +static void StringStripLeft(FString* self, const FString& junk) +{ + if (junk.IsNotEmpty()) self->StripLeft(junk); + else self->StripLeft(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, StripLeft, StringStripLeft) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(junk); + StringStripLeft(self, junk); + return 0; +} + +static void StringStripLeftRight(FString* self, const FString& junk) +{ + if (junk.IsNotEmpty()) self->StripLeftRight(junk); + else self->StripLeftRight(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, StripLeftRight, StringStripLeftRight) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(junk); + StringStripLeftRight(self, junk); + return 0; +} + +static void StringSplit(FString* self, TArray* tokens, const FString& delimiter, int keepEmpty) +{ + self->Split(*tokens, delimiter, static_cast(keepEmpty)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Split, StringSplit) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_POINTER(tokens, TArray); + PARAM_STRING(delimiter); + PARAM_INT(keepEmpty); + StringSplit(self, tokens, delimiter, keepEmpty); + return 0; +} + +static int StringCodePointCount(FString *self) +{ + return (int)self->CharacterCount(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CodePointCount, StringCodePointCount) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_INT(StringCodePointCount(self)); +} + +static int StringNextCodePoint(FString *self, int inposition, int *position) +{ + int codepoint = self->GetNextCharacter(inposition); + if (position) *position = inposition; + return codepoint; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, GetNextCodePoint, StringNextCodePoint) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_INT(pos); + if (numret > 0) ret[0].SetInt(self->GetNextCharacter(pos)); + if (numret > 1) ret[1].SetInt(pos); + return numret; +} + + diff --git a/src/common/scripting/interface/vmnatives.cpp b/src/common/scripting/interface/vmnatives.cpp new file mode 100644 index 00000000000..730465a34eb --- /dev/null +++ b/src/common/scripting/interface/vmnatives.cpp @@ -0,0 +1,1767 @@ +/* +** vmnatives.cpp +** +** VM exports for engine backend classes +** +**--------------------------------------------------------------------------- +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + + +#include "texturemanager.h" +#include "filesystem.h" +#include "c_console.h" +#include "c_cvars.h" +#include "c_bind.h" +#include "c_dispatch.h" + +#include "menu.h" +#include "vm.h" +#include "gstrings.h" +#include "printf.h" +#include "s_music.h" +#include "i_interface.h" +#include "base_sbar.h" +#include "image.h" +#include "s_soundinternal.h" +#include "i_time.h" + +#include "maps.h" +#include "types.h" + +static ZSMap AllServices; + +static void MarkServices() +{ + ZSMap::Iterator it(AllServices); + ZSMap::Pair* pair; + while (it.NextPair(pair)) + { + GC::Mark(pair->Value); + } +} + +void InitServices() +{ + PClass* cls = PClass::FindClass("Service"); + for (PClass* clss : PClass::AllClasses) + { + if (clss != cls && cls->IsAncestorOf(clss)) + { + DObject* obj = clss->CreateNew(); + obj->ObjectFlags |= OF_Transient; + AllServices.Insert(clss->TypeName, obj); + } + } + GC::AddMarkerFunc(&MarkServices); +} + +void ClearServices() +{ + AllServices.Clear(); +} + + + +//========================================================================== +// +// status bar exports +// +//========================================================================== + +static double StatusbarToRealCoords(DStatusBarCore* self, double x, double y, double w, double h, double* py, double* pw, double* ph) +{ + self->StatusbarToRealCoords(x, y, w, h); + *py = y; + *pw = w; + *ph = h; + return x; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, StatusbarToRealCoords, StatusbarToRealCoords) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + self->StatusbarToRealCoords(x, y, w, h); + if (numret > 0) ret[0].SetFloat(x); + if (numret > 1) ret[1].SetFloat(y); + if (numret > 2) ret[2].SetFloat(w); + if (numret > 3) ret[3].SetFloat(h); + return min(4, numret); +} + +void SBar_DrawTexture(DStatusBarCore* self, int texid, double x, double y, int flags, double alpha, double w, double h, double scaleX, double scaleY, int style, int color, int translation, double clipwidth) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->DrawGraphic(FSetTextureID(texid), x, y, flags, alpha, w, h, scaleX, scaleY, ERenderStyle(style), color, translation, clipwidth); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawTexture, SBar_DrawTexture) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_INT(texid); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(flags); + PARAM_FLOAT(alpha); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + PARAM_FLOAT(scaleX); + PARAM_FLOAT(scaleY); + PARAM_INT(style); + PARAM_INT(col); + PARAM_INT(trans); + PARAM_FLOAT(clipwidth); + SBar_DrawTexture(self, texid, x, y, flags, alpha, w, h, scaleX, scaleY, style, col, trans, clipwidth); + return 0; +} + +void SBar_DrawImage(DStatusBarCore* self, const FString& texid, double x, double y, int flags, double alpha, double w, double h, double scaleX, double scaleY, int style, int color, int translation, double clipwidth) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->DrawGraphic(TexMan.CheckForTexture(texid.GetChars(), ETextureType::Any), x, y, flags, alpha, w, h, scaleX, scaleY, ERenderStyle(style), color, translation, clipwidth); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawImage, SBar_DrawImage) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_STRING(texid); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(flags); + PARAM_FLOAT(alpha); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + PARAM_FLOAT(scaleX); + PARAM_FLOAT(scaleY); + PARAM_INT(style); + PARAM_INT(col); + PARAM_INT(trans); + PARAM_FLOAT(clipwidth); + SBar_DrawImage(self, texid, x, y, flags, alpha, w, h, scaleX, scaleY, style, col, trans, clipwidth); + return 0; +} + +void SBar_DrawImageRotated(DStatusBarCore* self, const FString& texid, double x, double y, int flags, double angle, double alpha, double scaleX, double scaleY, int style, int color, int translation) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->DrawRotated(TexMan.CheckForTexture(texid.GetChars(), ETextureType::Any), x, y, flags, angle, alpha, scaleX, scaleY, color, translation, (ERenderStyle)style); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawImageRotated, SBar_DrawImageRotated) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_STRING(texid); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(flags); + PARAM_FLOAT(angle); + PARAM_FLOAT(alpha); + PARAM_FLOAT(scaleX); + PARAM_FLOAT(scaleY); + PARAM_INT(style); + PARAM_INT(col); + PARAM_INT(trans); + SBar_DrawImageRotated(self, texid, x, y, flags, angle, alpha, scaleX, scaleY, style, col, trans); + return 0; +} + +void SBar_DrawTextureRotated(DStatusBarCore* self, int texid, double x, double y, int flags, double angle, double alpha, double scaleX, double scaleY, int style, int color, int translation) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->DrawRotated(FSetTextureID(texid), x, y, flags, angle, alpha, scaleX, scaleY, color, translation, (ERenderStyle)style); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawTextureRotated, SBar_DrawTextureRotated) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_INT(texid); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(flags); + PARAM_FLOAT(angle); + PARAM_FLOAT(alpha); + PARAM_FLOAT(scaleX); + PARAM_FLOAT(scaleY); + PARAM_INT(style); + PARAM_INT(col); + PARAM_INT(trans); + SBar_DrawTextureRotated(self, texid, x, y, flags, angle, alpha, scaleX, scaleY, style, col, trans); + return 0; +} + + +void SBar_DrawString(DStatusBarCore* self, DHUDFont* font, const FString& string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY, int translation, int style); + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawString, SBar_DrawString) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_POINTER_NOT_NULL(font, DHUDFont); + PARAM_STRING(string); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(flags); + PARAM_INT(trans); + PARAM_FLOAT(alpha); + PARAM_INT(wrapwidth); + PARAM_INT(linespacing); + PARAM_FLOAT(scaleX); + PARAM_FLOAT(scaleY); + PARAM_INT(pt); + PARAM_INT(style); + SBar_DrawString(self, font, string, x, y, flags, trans, alpha, wrapwidth, linespacing, scaleX, scaleY, pt, style); + return 0; +} + +static double SBar_TransformRect(DStatusBarCore* self, double x, double y, double w, double h, int flags, double* py, double* pw, double* ph) +{ + self->TransformRect(x, y, w, h, flags); + *py = y; + *pw = w; + *ph = h; + return x; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, TransformRect, SBar_TransformRect) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + PARAM_INT(flags); + self->TransformRect(x, y, w, h, flags); + if (numret > 0) ret[0].SetFloat(x); + if (numret > 1) ret[1].SetFloat(y); + if (numret > 2) ret[2].SetFloat(w); + if (numret > 3) ret[3].SetFloat(h); + return min(4, numret); +} + +static void SBar_Fill(DStatusBarCore* self, int color, double x, double y, double w, double h, int flags) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->Fill(color, x, y, w, h, flags); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, Fill, SBar_Fill) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_COLOR(color); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + PARAM_INT(flags); + SBar_Fill(self, color, x, y, w, h, flags); + return 0; +} + +static void SBar_SetClipRect(DStatusBarCore* self, double x, double y, double w, double h, int flags) +{ + self->SetClipRect(x, y, w, h, flags); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, SetClipRect, SBar_SetClipRect) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + PARAM_INT(flags); + self->SetClipRect(x, y, w, h, flags); + return 0; +} + +void FormatNumber(int number, int minsize, int maxsize, int flags, const FString& prefix, FString* result); + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, FormatNumber, FormatNumber) +{ + PARAM_PROLOGUE; + PARAM_INT(number); + PARAM_INT(minsize); + PARAM_INT(maxsize); + PARAM_INT(flags); + PARAM_STRING(prefix); + FString fmt; + FormatNumber(number, minsize, maxsize, flags, prefix, &fmt); + ACTION_RETURN_STRING(fmt); +} + +static void SBar_SetSize(DStatusBarCore* self, int rt, int vw, int vh, int hvw, int hvh) +{ + self->SetSize(rt, vw, vh, hvw, hvh); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, SetSize, SBar_SetSize) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_INT(rt); + PARAM_INT(vw); + PARAM_INT(vh); + PARAM_INT(hvw); + PARAM_INT(hvh); + self->SetSize(rt, vw, vh, hvw, hvh); + return 0; +} + +static void SBar_GetHUDScale(DStatusBarCore* self, DVector2* result) +{ + *result = self->GetHUDScale(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, GetHUDScale, SBar_GetHUDScale) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + ACTION_RETURN_VEC2(self->GetHUDScale()); +} + +static void BeginStatusBar(DStatusBarCore* self, bool fs, int w, int h, int r) +{ + self->BeginStatusBar(w, h, r, fs); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, BeginStatusBar, BeginStatusBar) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_BOOL(fs); + PARAM_INT(w); + PARAM_INT(h); + PARAM_INT(r); + self->BeginStatusBar(w, h, r, fs); + return 0; +} + +static void BeginHUD(DStatusBarCore* self, double a, bool fs, int w, int h) +{ + self->BeginHUD(w, h, a, fs); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, BeginHUD, BeginHUD) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_FLOAT(a); + PARAM_BOOL(fs); + PARAM_INT(w); + PARAM_INT(h); + self->BeginHUD(w, h, a, fs); + return 0; +} + + +//===================================================================================== +// +// +// +//===================================================================================== + +DHUDFont* CreateHudFont(FFont* fnt, int spac, int mono, int sx, int sy) +{ + return Create(fnt, spac, EMonospacing(mono), sy, sy); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DHUDFont, Create, CreateHudFont) +{ + PARAM_PROLOGUE; + PARAM_POINTER(fnt, FFont); + PARAM_INT(spac); + PARAM_INT(mono); + PARAM_INT(sx); + PARAM_INT(sy); + ACTION_RETURN_POINTER(CreateHudFont(fnt, spac, mono, sy, sy)); +} + + + + +//========================================================================== +// +// texture manager exports +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(_TexMan, GetName) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + auto tex = TexMan.GameByIndex(texid); + FString retval; + + if (tex != nullptr) + { + if (tex->GetName().IsNotEmpty()) retval = tex->GetName(); + else + { + // Textures for full path names do not have their own name, they merely link to the source lump. + auto lump = tex->GetSourceLump(); + if (TexMan.GetLinkedTexture(lump) == tex) + retval = fileSystem.GetFileFullName(lump); + } + } + ACTION_RETURN_STRING(retval); +} + +static int CheckForTexture(const FString& name, int type, int flags) +{ + return TexMan.CheckForTexture(name.GetChars(), static_cast(type), flags).GetIndex(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, CheckForTexture, CheckForTexture) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + PARAM_INT(type); + PARAM_INT(flags); + ACTION_RETURN_INT(CheckForTexture(name, type, flags)); +} + +//========================================================================== +// +// +// +//========================================================================== + +static int GetTextureSize(int texid, int* py) +{ + auto tex = TexMan.GameByIndex(texid); + int x, y; + if (tex != nullptr) + { + x = int(0.5 + tex->GetDisplayWidth()); + y = int(0.5 + tex->GetDisplayHeight()); + } + else x = y = -1; + if (py) *py = y; + return x; +} + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, GetSize, GetTextureSize) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + int x, y; + x = GetTextureSize(texid, &y); + if (numret > 0) ret[0].SetInt(x); + if (numret > 1) ret[1].SetInt(y); + return min(numret, 2); +} + +//========================================================================== +// +// +// +//========================================================================== +static void GetScaledSize(int texid, DVector2* pvec) +{ + auto tex = TexMan.GameByIndex(texid); + double x, y; + if (tex != nullptr) + { + x = tex->GetDisplayWidth(); + y = tex->GetDisplayHeight(); + } + else x = y = -1; + if (pvec) + { + pvec->X = x; + pvec->Y = y; + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, GetScaledSize, GetScaledSize) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + DVector2 vec; + GetScaledSize(texid, &vec); + ACTION_RETURN_VEC2(vec); +} + +//========================================================================== +// +// +// +//========================================================================== +static void GetScaledOffset(int texid, DVector2* pvec) +{ + auto tex = TexMan.GameByIndex(texid); + double x, y; + if (tex != nullptr) + { + x = tex->GetDisplayLeftOffset(); + y = tex->GetDisplayTopOffset(); + } + else x = y = -1; + if (pvec) + { + pvec->X = x; + pvec->Y = y; + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, GetScaledOffset, GetScaledOffset) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + DVector2 vec; + GetScaledOffset(texid, &vec); + ACTION_RETURN_VEC2(vec); +} + +//========================================================================== +// +// +// +//========================================================================== + +static int CheckRealHeight(int texid) +{ + auto tex = TexMan.GameByIndex(texid); + if (tex != nullptr) return tex->CheckRealHeight(); + else return -1; +} + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, CheckRealHeight, CheckRealHeight) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + ACTION_RETURN_INT(CheckRealHeight(texid)); +} + +static int OkForLocalization_(int index, const FString& substitute) +{ + return sysCallbacks.OkForLocalization? sysCallbacks.OkForLocalization(FSetTextureID(index), substitute.GetChars()) : false; +} + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, OkForLocalization, OkForLocalization_) +{ + PARAM_PROLOGUE; + PARAM_INT(name); + PARAM_STRING(subst) + ACTION_RETURN_INT(OkForLocalization_(name, subst)); +} + +static int UseGamePalette(int index) +{ + auto tex = TexMan.GameByIndex(index, false); + if (!tex) return false; + auto image = tex->GetTexture()->GetImage(); + return image ? image->UseGamePalette() : false; +} + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, UseGamePalette, UseGamePalette) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + ACTION_RETURN_INT(UseGamePalette(texid)); +} + +FCanvas* GetTextureCanvas(const FString& texturename); + +DEFINE_ACTION_FUNCTION(_TexMan, GetCanvas) +{ + PARAM_PROLOGUE; + PARAM_STRING(texturename); + ACTION_RETURN_POINTER(GetTextureCanvas(texturename)); +} + +//===================================================================================== +// +// FFont exports +// +//===================================================================================== + +static FFont *GetFont(int name) +{ + return V_GetFont(FName(ENamedName(name)).GetChars()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetFont, GetFont) +{ + PARAM_PROLOGUE; + PARAM_INT(name); + ACTION_RETURN_POINTER(GetFont(name)); +} + +static FFont *FindFont(int name) +{ + return FFont::FindFont(FName(ENamedName(name))); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, FindFont, FindFont) +{ + PARAM_PROLOGUE; + PARAM_NAME(name); + ACTION_RETURN_POINTER(FFont::FindFont(name)); +} + +static int GetCharWidth(FFont *font, int code) +{ + return font->GetCharWidth(code); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetCharWidth, GetCharWidth) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_INT(code); + ACTION_RETURN_INT(self->GetCharWidth(code)); +} + +static int GetHeight(FFont *font) +{ + return font->GetHeight(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetHeight, GetHeight) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + ACTION_RETURN_INT(self->GetHeight()); +} + +static int GetDisplacement(FFont* font) +{ + return font->GetDisplacement(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetDisplacement, GetDisplacement) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + ACTION_RETURN_INT(self->GetDisplacement()); +} + +double GetBottomAlignOffset(FFont *font, int c); +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetBottomAlignOffset, GetBottomAlignOffset) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_INT(code); + ACTION_RETURN_FLOAT(GetBottomAlignOffset(self, code)); +} + +static int StringWidth(FFont *font, const FString &str, int localize) +{ + const char *txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars(); + return font->StringWidth(txt); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, StringWidth, StringWidth) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(str); + PARAM_BOOL(localize); + ACTION_RETURN_INT(StringWidth(self, str, localize)); +} + +static int GetMaxAscender(FFont* font, const FString& str, int localize) +{ + const char* txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars(); + return font->GetMaxAscender(txt); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetMaxAscender, GetMaxAscender) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(str); + PARAM_BOOL(localize); + ACTION_RETURN_INT(GetMaxAscender(self, str, localize)); +} + +static int CanPrint(FFont *font, const FString &str, int localize) +{ + const char *txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars(); + return font->CanPrint(txt); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, CanPrint, CanPrint) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(str); + PARAM_BOOL(localize); + ACTION_RETURN_INT(CanPrint(self, str, localize)); +} + +static int FindFontColor(int name) +{ + return V_FindFontColor(ENamedName(name)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, FindFontColor, FindFontColor) +{ + PARAM_PROLOGUE; + PARAM_NAME(code); + ACTION_RETURN_INT((int)V_FindFontColor(code)); +} + +static void GetCursor(FFont *font, FString *result) +{ + *result = font->GetCursor(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetCursor, GetCursor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + ACTION_RETURN_STRING(FString(self->GetCursor())); +} + +static int GetGlyphHeight(FFont* fnt, int code) +{ + auto glyph = fnt->GetChar(code, CR_UNTRANSLATED, nullptr); + return glyph ? (int)glyph->GetDisplayHeight() : 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetGlyphHeight, GetGlyphHeight) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_INT(code); + ACTION_RETURN_INT(GetGlyphHeight(self, code)); +} + +static int GetDefaultKerning(FFont* font) +{ + return font->GetDefaultKerning(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetDefaultKerning, GetDefaultKerning) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + ACTION_RETURN_INT(self->GetDefaultKerning()); +} + +static double GetDisplayTopOffset(FFont* font, int c) +{ + auto texc = font->GetChar(c, CR_UNDEFINED, nullptr); + return texc ? texc->GetDisplayTopOffset() : 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetDisplayTopOffset, GetDisplayTopOffset) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_INT(code); + ACTION_RETURN_FLOAT(GetDisplayTopOffset(self, code)); +} + +//========================================================================== +// +// file system +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(_Wads, GetNumLumps) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(fileSystem.GetNumEntries()); +} + +DEFINE_ACTION_FUNCTION(_Wads, CheckNumForName) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + PARAM_INT(ns); + PARAM_INT(wadnum); + PARAM_BOOL(exact); + ACTION_RETURN_INT(fileSystem.CheckNumForName(name.GetChars(), ns, wadnum, exact)); +} + +DEFINE_ACTION_FUNCTION(_Wads, CheckNumForFullName) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + ACTION_RETURN_INT(fileSystem.CheckNumForFullName(name.GetChars())); +} + +DEFINE_ACTION_FUNCTION(_Wads, FindLump) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + PARAM_INT(startlump); + PARAM_INT(ns); + const bool isLumpValid = startlump >= 0 && startlump < fileSystem.GetNumEntries(); + ACTION_RETURN_INT(isLumpValid ? fileSystem.FindLump(name.GetChars(), &startlump, 0 != ns) : -1); +} + +DEFINE_ACTION_FUNCTION(_Wads, FindLumpFullName) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + PARAM_INT(startlump); + PARAM_BOOL(noext); + const bool isLumpValid = startlump >= 0 && startlump < fileSystem.GetNumEntries(); + ACTION_RETURN_INT(isLumpValid ? fileSystem.FindLumpFullName(name.GetChars(), &startlump, noext) : -1); +} + +DEFINE_ACTION_FUNCTION(_Wads, GetLumpName) +{ + PARAM_PROLOGUE; + PARAM_INT(lump); + ACTION_RETURN_STRING(fileSystem.GetFileShortName(lump)); +} + +DEFINE_ACTION_FUNCTION(_Wads, GetLumpFullName) +{ + PARAM_PROLOGUE; + PARAM_INT(lump); + ACTION_RETURN_STRING(fileSystem.GetFileFullName(lump)); +} + +DEFINE_ACTION_FUNCTION(_Wads, GetLumpNamespace) +{ + PARAM_PROLOGUE; + PARAM_INT(lump); + ACTION_RETURN_INT(fileSystem.GetFileNamespace(lump)); +} + +DEFINE_ACTION_FUNCTION(_Wads, ReadLump) +{ + PARAM_PROLOGUE; + PARAM_INT(lump); + const bool isLumpValid = lump >= 0 && lump < fileSystem.GetNumEntries(); + ACTION_RETURN_STRING(isLumpValid ? GetStringFromLump(lump, false) : FString()); +} + +DEFINE_ACTION_FUNCTION(_Wads, GetLumpLength) +{ + PARAM_PROLOGUE; + PARAM_INT(lump); + ACTION_RETURN_INT((int)fileSystem.FileLength(lump)); +} + +//========================================================================== +// +// CVARs +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(_CVar, GetInt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); + auto v = self->GetGenericRep(CVAR_Int); + ACTION_RETURN_INT(v.Int); +} + +DEFINE_ACTION_FUNCTION(_CVar, GetFloat) +{ + PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); + auto v = self->GetGenericRep(CVAR_Float); + ACTION_RETURN_FLOAT(v.Float); +} + +DEFINE_ACTION_FUNCTION(_CVar, GetString) +{ + PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); + auto v = self->GetGenericRep(CVAR_String); + ACTION_RETURN_STRING(v.String); +} + +DEFINE_ACTION_FUNCTION(_CVar, SetInt) +{ + // Only menus are allowed to change CVARs. + PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); + if (!(self->GetFlags() & CVAR_MOD)) + { + // Only menus are allowed to change non-mod CVARs. + if (DMenu::InMenu == 0) + { + ThrowAbortException(X_OTHER, "Attempt to change CVAR '%s' outside of menu code", self->GetName()); + } + } + PARAM_INT(val); + UCVarValue v; + v.Int = val; + + if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE) + { + auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer()); + assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM); + + v = realCVar->GenericZSCVarCallback(v, CVAR_Int); + self->SetGenericRep(v, realCVar->GetRealType()); + + if(realCVar->GetRealType() == CVAR_String) delete[] v.String; + } + else + { + self->SetGenericRep(v, CVAR_Int); + } + + return 0; +} + +DEFINE_ACTION_FUNCTION(_CVar, SetFloat) +{ + PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); + if (!(self->GetFlags() & CVAR_MOD)) + { + // Only menus are allowed to change non-mod CVARs. + if (DMenu::InMenu == 0) + { + ThrowAbortException(X_OTHER, "Attempt to change CVAR '%s' outside of menu code", self->GetName()); + } + } + PARAM_FLOAT(val); + UCVarValue v; + v.Float = (float)val; + + if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE) + { + auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer()); + assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM); + + v = realCVar->GenericZSCVarCallback(v, CVAR_Float); + self->SetGenericRep(v, realCVar->GetRealType()); + + if(realCVar->GetRealType() == CVAR_String) delete[] v.String; + } + else + { + self->SetGenericRep(v, CVAR_Float); + } + + return 0; +} + +DEFINE_ACTION_FUNCTION(_CVar, SetString) +{ + // Only menus are allowed to change CVARs. + PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); + if (!(self->GetFlags() & CVAR_MOD)) + { + // Only menus are allowed to change non-mod CVARs. + if (DMenu::InMenu == 0) + { + ThrowAbortException(X_OTHER, "Attempt to change CVAR '%s' outside of menu code", self->GetName()); + } + } + PARAM_STRING(val); + UCVarValue v; + v.String = val.GetChars(); + + if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE) + { + auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer()); + assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM); + + v = realCVar->GenericZSCVarCallback(v, CVAR_String); + self->SetGenericRep(v, realCVar->GetRealType()); + + if(realCVar->GetRealType() == CVAR_String) delete[] v.String; + } + else + { + self->SetGenericRep(v, CVAR_String); + } + + return 0; +} + +DEFINE_ACTION_FUNCTION(_CVar, GetRealType) +{ + PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); + ACTION_RETURN_INT(self->GetRealType()); +} + +DEFINE_ACTION_FUNCTION(_CVar, ResetToDefault) +{ + PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); + if (!(self->GetFlags() & CVAR_MOD)) + { + // Only menus are allowed to change non-mod CVARs. + if (DMenu::InMenu == 0) + { + ThrowAbortException(X_OTHER, "Attempt to change CVAR '%s' outside of menu code", self->GetName()); + } + } + + self->ResetToDefault(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_CVar, FindCVar) +{ + PARAM_PROLOGUE; + PARAM_NAME(name); + ACTION_RETURN_POINTER(FindCVar(name.GetChars(), nullptr)); +} + +//============================================================================= +// +// +// +//============================================================================= + +DEFINE_ACTION_FUNCTION(FKeyBindings, SetBind) +{ + PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); + PARAM_INT(k); + PARAM_STRING(cmd); + + // Only menus are allowed to change bindings. + if (DMenu::InMenu == 0) + { + I_FatalError("Attempt to change key bindings outside of menu code to '%s'", cmd.GetChars()); + } + + + self->SetBind(k, cmd.GetChars()); + return 0; +} + +DEFINE_ACTION_FUNCTION(FKeyBindings, NameKeys) +{ + PARAM_PROLOGUE; + PARAM_INT(k1); + PARAM_INT(k2); + char buffer[120]; + C_NameKeys(buffer, k1, k2); + ACTION_RETURN_STRING(buffer); +} + +DEFINE_ACTION_FUNCTION(FKeyBindings, NameAllKeys) +{ + PARAM_PROLOGUE; + PARAM_POINTER(array, TArray); + PARAM_BOOL(color); + auto buffer = C_NameKeys(array->Data(), array->Size(), color); + ACTION_RETURN_STRING(buffer); +} + +DEFINE_ACTION_FUNCTION(FKeyBindings, GetKeysForCommand) +{ + PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); + PARAM_STRING(cmd); + int k1, k2; + self->GetKeysForCommand(cmd.GetChars(), &k1, &k2); + if (numret > 0) ret[0].SetInt(k1); + if (numret > 1) ret[1].SetInt(k2); + return min(numret, 2); +} + +DEFINE_ACTION_FUNCTION(FKeyBindings, GetAllKeysForCommand) +{ + PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); + PARAM_POINTER(array, TArray); + PARAM_STRING(cmd); + *array = self->GetKeysForCommand(cmd.GetChars()); + return 0; +} + +DEFINE_ACTION_FUNCTION(FKeyBindings, GetBinding) +{ + PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); + PARAM_INT(key); + ACTION_RETURN_STRING(self->GetBinding(key)); +} + +DEFINE_ACTION_FUNCTION(FKeyBindings, UnbindACommand) +{ + PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); + PARAM_STRING(cmd); + + // Only menus are allowed to change bindings. + if (DMenu::InMenu == 0) + { + I_FatalError("Attempt to unbind key bindings for '%s' outside of menu code", cmd.GetChars()); + } + + self->UnbindACommand(cmd.GetChars()); + return 0; +} + +// This is only accessible to the special menu item to run CCMDs. +DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand) +{ + PARAM_PROLOGUE; + PARAM_STRING(cmd); + PARAM_BOOL(unsafe); + + // Only menus are allowed to execute CCMDs. + if (DMenu::InMenu == 0) + { + I_FatalError("Attempt to execute CCMD '%s' outside of menu code", cmd.GetChars()); + } + + UnsafeExecutionScope scope(unsafe); + AddCommandString(cmd.GetChars()); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Console, HideConsole) +{ + C_HideConsole(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Console, Printf) +{ + PARAM_PROLOGUE; + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + FString s = FStringFormat(VM_ARGS_NAMES); + Printf("%s\n", s.GetChars()); + return 0; +} + +DEFINE_ACTION_FUNCTION(_Console, PrintfEx) +{ + PARAM_PROLOGUE; + PARAM_INT(printlevel); + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + FString s = FStringFormat(VM_ARGS_NAMES,1); + + Printf(printlevel,"%s\n", s.GetChars()); + return 0; +} + +static void StopAllSounds() +{ + soundEngine->StopAllChannels(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_System, StopAllSounds, StopAllSounds) +{ + StopAllSounds(); + return 0; +} + +static int PlayMusic(const FString& musname, int order, int looped) +{ + return S_ChangeMusic(musname.GetChars(), order, !!looped, true); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_System, PlayMusic, PlayMusic) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + PARAM_INT(order); + PARAM_BOOL(looped); + ACTION_RETURN_BOOL(PlayMusic(name, order, looped)); +} + +static void Mus_Stop() +{ + S_StopMusic(true); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_System, StopMusic, Mus_Stop) +{ + Mus_Stop(); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(_System, SoundEnabled, SoundEnabled) +{ + ACTION_RETURN_INT(SoundEnabled()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_System, MusicEnabled, MusicEnabled) +{ + ACTION_RETURN_INT(MusicEnabled()); +} + +static double Jit_GetTimeFrac() // cannot use I_GetTimwfrac directly due to default arguments. +{ + return I_GetTimeFrac(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_System, GetTimeFrac, Jit_GetTimeFrac) +{ + ACTION_RETURN_FLOAT(I_GetTimeFrac()); +} + + +DEFINE_GLOBAL_NAMED(mus_playing, musplaying); +DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, name); +DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, baseorder); +DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, loop); +DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, handle); + +DEFINE_GLOBAL_NAMED(PClass::AllClasses, AllClasses) + +DEFINE_GLOBAL(AllServices) + +DEFINE_GLOBAL(Bindings) +DEFINE_GLOBAL(AutomapBindings) +DEFINE_GLOBAL(generic_ui) + +DEFINE_FIELD(DStatusBarCore, RelTop); +DEFINE_FIELD(DStatusBarCore, HorizontalResolution); +DEFINE_FIELD(DStatusBarCore, VerticalResolution); +DEFINE_FIELD(DStatusBarCore, CompleteBorder); +DEFINE_FIELD(DStatusBarCore, Alpha); +DEFINE_FIELD(DStatusBarCore, drawOffset); +DEFINE_FIELD(DStatusBarCore, drawClip); +DEFINE_FIELD(DStatusBarCore, fullscreenOffsets); +DEFINE_FIELD(DStatusBarCore, defaultScale); +DEFINE_FIELD(DHUDFont, mFont); + +// +// Quaternion +void QuatFromAngles(double yaw, double pitch, double roll, DQuaternion* pquat) +{ + *pquat = DQuaternion::FromAngles(DAngle::fromDeg(yaw), DAngle::fromDeg(pitch), DAngle::fromDeg(roll)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_QuatStruct, FromAngles, QuatFromAngles) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(yaw); + PARAM_FLOAT(pitch); + PARAM_FLOAT(roll); + + DQuaternion quat; + QuatFromAngles(yaw, pitch, roll, &quat); + ACTION_RETURN_QUAT(quat); +} + +void QuatAxisAngle(double x, double y, double z, double angleDeg, DQuaternion* pquat) +{ + auto axis = DVector3(x, y, z); + auto angle = DAngle::fromDeg(angleDeg); + *pquat = DQuaternion::AxisAngle(axis, angle); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_QuatStruct, AxisAngle, QuatAxisAngle) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_FLOAT(angle); + + DQuaternion quat; + QuatAxisAngle(x, y, z, angle, &quat); + ACTION_RETURN_QUAT(quat); +} + +void QuatNLerp( + double ax, double ay, double az, double aw, + double bx, double by, double bz, double bw, + double t, + DQuaternion* pquat +) +{ + auto from = DQuaternion { ax, ay, az, aw }; + auto to = DQuaternion { bx, by, bz, bw }; + *pquat = DQuaternion::NLerp(from, to, t); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_QuatStruct, NLerp, QuatNLerp) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(ax); + PARAM_FLOAT(ay); + PARAM_FLOAT(az); + PARAM_FLOAT(aw); + PARAM_FLOAT(bx); + PARAM_FLOAT(by); + PARAM_FLOAT(bz); + PARAM_FLOAT(bw); + PARAM_FLOAT(t); + + DQuaternion quat; + QuatNLerp(ax, ay, az, aw, bx, by, bz, bw, t, &quat); + ACTION_RETURN_QUAT(quat); +} + +void QuatSLerp( + double ax, double ay, double az, double aw, + double bx, double by, double bz, double bw, + double t, + DQuaternion* pquat +) +{ + auto from = DQuaternion { ax, ay, az, aw }; + auto to = DQuaternion { bx, by, bz, bw }; + *pquat = DQuaternion::SLerp(from, to, t); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_QuatStruct, SLerp, QuatSLerp) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(ax); + PARAM_FLOAT(ay); + PARAM_FLOAT(az); + PARAM_FLOAT(aw); + PARAM_FLOAT(bx); + PARAM_FLOAT(by); + PARAM_FLOAT(bz); + PARAM_FLOAT(bw); + PARAM_FLOAT(t); + + DQuaternion quat; + QuatSLerp(ax, ay, az, aw, bx, by, bz, bw, t, &quat); + ACTION_RETURN_QUAT(quat); +} + +void QuatConjugate( + double x, double y, double z, double w, + DQuaternion* pquat +) +{ + *pquat = DQuaternion(x, y, z, w).Conjugate(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_QuatStruct, Conjugate, QuatConjugate) +{ + PARAM_SELF_STRUCT_PROLOGUE(DQuaternion); + + DQuaternion quat; + QuatConjugate(self->X, self->Y, self->Z, self->W, &quat); + ACTION_RETURN_QUAT(quat); +} + +void QuatInverse( + double x, double y, double z, double w, + DQuaternion* pquat +) +{ + *pquat = DQuaternion(x, y, z, w).Inverse(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_QuatStruct, Inverse, QuatInverse) +{ + PARAM_SELF_STRUCT_PROLOGUE(DQuaternion); + + DQuaternion quat; + QuatInverse(self->X, self->Y, self->Z, self->W, &quat); + ACTION_RETURN_QUAT(quat); +} + +PFunction * FindFunctionPointer(PClass * cls, int fn_name) +{ + auto fn = dyn_cast(cls->FindSymbol(ENamedName(fn_name), true)); + return (fn && (fn->Variants[0].Flags & (VARF_Action | VARF_Virtual)) == 0 ) ? fn : nullptr; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, FindFunction, FindFunctionPointer) +{ + PARAM_PROLOGUE; + PARAM_CLASS(cls, DObject); + PARAM_NAME(fn); + + ACTION_RETURN_POINTER(FindFunctionPointer(cls, fn.GetIndex())); +} + +FTranslationID R_FindCustomTranslation(FName name); + +static int ZFindTranslation(int intname) +{ + return R_FindCustomTranslation(ENamedName(intname)).index(); +} + +static int MakeTransID(int g, int s) +{ + return TRANSLATION(g, s).index(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_Translation, GetID, ZFindTranslation) +{ + PARAM_PROLOGUE; + PARAM_INT(t); + ACTION_RETURN_INT(ZFindTranslation(t)); +} + +// same as above for the compiler which needs a class to look this up. +DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinFindTranslation, ZFindTranslation) +{ + PARAM_PROLOGUE; + PARAM_INT(t); + ACTION_RETURN_INT(ZFindTranslation(t)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_Translation, MakeID, MakeTransID) +{ + PARAM_PROLOGUE; + PARAM_INT(g); + PARAM_INT(t); + ACTION_RETURN_INT(MakeTransID(g, t)); +} + +// DObject-based wrapper around FScanner, for ZScript. +class DScriptScanner : public DObject +{ + DECLARE_CLASS(DScriptScanner, DObject) +public: + FScanner wrapped; + +}; + +IMPLEMENT_CLASS(DScriptScanner, false, false); + +static void OpenLumpNum(DScriptScanner* self, int lump) { return self->wrapped.OpenLumpNum(lump); } +static void OpenString(DScriptScanner* self, const FString* name, FString* script) { return self->wrapped.OpenString(name->GetChars(), *script); } +static void SavePos(DScriptScanner* self, FScanner::SavedPos *pos) { *pos = self->wrapped.SavePos(); } +static void RestorePos(DScriptScanner* self, const FScanner::SavedPos* pos) { return self->wrapped.RestorePos(*pos); } +static void GetStringContents(DScriptScanner* self, FString* str) { *str = self->wrapped.String; } +static void UnGet(DScriptScanner* self) { return self->wrapped.UnGet(); } +static int isText(DScriptScanner* self) { return self->wrapped.isText(); } +static int GetMessageLine(DScriptScanner* self) { return self->wrapped.GetMessageLine(); } +static void Close(DScriptScanner* self) { return self->wrapped.Close(); } +static void SetCMode(DScriptScanner* self, int cmode) { return self->wrapped.SetCMode(cmode); } +static void SetNoOctals(DScriptScanner* self, int cmode) { return self->wrapped.SetNoOctals(cmode); } +static void SetEscape(DScriptScanner* self, int esc) { return self->wrapped.SetNoOctals(esc); } +static void SetNoFatalErrors(DScriptScanner* self, int cmode) { return self->wrapped.SetNoFatalErrors(cmode); } +static void AddSymbolUint(DScriptScanner* self, const FString* name, uint32_t value) { return self->wrapped.AddSymbol(name->GetChars(), value); } +static void AddSymbolInt(DScriptScanner* self, const FString* name, int32_t value) { return self->wrapped.AddSymbol(name->GetChars(), value); } +static void AddSymbolDouble(DScriptScanner* self, const FString* name, double value) { return self->wrapped.AddSymbol(name->GetChars(), value); } +static int GetString(DScriptScanner* self) { return self->wrapped.GetString(); } +static int GetNumber(DScriptScanner* self, int evaluate) { return self->wrapped.GetNumber(evaluate); } +static int GetFloat(DScriptScanner* self, int evaluate) { return self->wrapped.GetFloat(evaluate); } +static int CheckValue(DScriptScanner* self, int allowfloat, int evaluate) { return self->wrapped.CheckValue(allowfloat, evaluate); } +static int CheckNumber(DScriptScanner* self, int evaluate) { return self->wrapped.CheckNumber(evaluate); } +static int CheckBoolToken(DScriptScanner* self) { return self->wrapped.CheckBoolToken(); } +static int CheckString(DScriptScanner* self, const FString* name) { return self->wrapped.CheckString(name->GetChars()); } +static int CheckFloat(DScriptScanner* self, int evaluate) { return self->wrapped.CheckFloat(evaluate); } +static void SetPrependMessage(DScriptScanner* self, const FString* message) { return self->wrapped.SetPrependMessage(*message); } +static void SkipToEndOfBlock(DScriptScanner* self) { return self->wrapped.SkipToEndOfBlock(); } +static int StartBraces(DScriptScanner* self, FScanner::SavedPos* braceend) { return self->wrapped.StartBraces(braceend); } +static int FoundEndBrace(DScriptScanner* self, FScanner::SavedPos* braceend) { return self->wrapped.FoundEndBrace(*braceend); } +static void MustGetValue(DScriptScanner* self, int allowfloat, int evaluate) { return self->wrapped.MustGetValue(allowfloat, evaluate); } +static void MustGetFloat(DScriptScanner* self, int evaluate) { return self->wrapped.MustGetFloat(evaluate); } +static void MustGetNumber(DScriptScanner* self, int evaluate) { return self->wrapped.MustGetNumber(evaluate); } +static void MustGetString(DScriptScanner* self) { return self->wrapped.MustGetString(); } +static void MustGetStringName(DScriptScanner* self, const FString* name) { return self->wrapped.MustGetStringName(name->GetChars()); } +static void MustGetBoolToken(DScriptScanner* self) { return self->wrapped.MustGetBoolToken(); } + + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, OpenLumpNum, OpenLumpNum) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_INT(lump); + + OpenLumpNum(self, lump); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, OpenString, OpenString) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + PARAM_STRING_VAL(script); + + OpenString(self, &name, &script); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SavePos, SavePos) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_POINTER(pos, FScanner::SavedPos); + + SavePos(self, pos); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, RestorePos, RestorePos) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_POINTER(pos, FScanner::SavedPos); + + RestorePos(self, pos); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetStringContents, GetStringContents) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + ACTION_RETURN_STRING(self->wrapped.String); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, UnGet, UnGet) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + UnGet(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, isText, isText) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + ACTION_RETURN_BOOL(isText(self)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetMessageLine, GetMessageLine) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + ACTION_RETURN_INT(GetMessageLine(self)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, AddSymbol, AddSymbolInt) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + PARAM_INT(value); + + AddSymbolInt(self, &name, value); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, AddSymbolUnsigned, AddSymbolUint) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + PARAM_UINT(value); + + AddSymbolUint(self, &name, value); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, AddSymbolFloat, AddSymbolDouble) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + PARAM_FLOAT(value); + + AddSymbolDouble(self, &name, value); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetString, GetString) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + ACTION_RETURN_BOOL(GetString(self)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetNumber, GetNumber) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(GetNumber(self, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetFloat, GetFloat) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(GetFloat(self, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckValue, CheckValue) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(allowfloat); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(CheckValue(self, allowfloat, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckBoolToken, CheckBoolToken) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + ACTION_RETURN_BOOL(CheckBoolToken(self)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckNumber, CheckNumber) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(CheckNumber(self, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckString, CheckString) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + + ACTION_RETURN_BOOL(CheckString(self, &name)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckFloat, CheckFloat) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(CheckFloat(self, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetPrependMessage, SetPrependMessage) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(message); + + SetPrependMessage(self, &message); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetCMode, SetCMode) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(cmode); + + SetCMode(self, cmode); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetNoOctals, SetNoOctals) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(cmode); + + SetNoOctals(self, cmode); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetEscape, SetEscape) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(esc); + + SetEscape(self, esc); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SkipToEndOfBlock, SkipToEndOfBlock) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + SkipToEndOfBlock(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, StartBraces, StartBraces) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_POINTER(braceend, FScanner::SavedPos); + + StartBraces(self, braceend); // the return value of this is useless. + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, FoundEndBrace, FoundEndBrace) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_POINTER(braceend, FScanner::SavedPos); + + ACTION_RETURN_BOOL(FoundEndBrace(self, braceend)); +} + +DEFINE_ACTION_FUNCTION(DScriptScanner, ScriptError) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + FString s = FStringFormat(VM_ARGS_NAMES); + self->wrapped.ScriptError("%s", s.GetChars()); + return 0; +} + +DEFINE_ACTION_FUNCTION(DScriptScanner, ScriptMessage) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + FString s = FStringFormat(VM_ARGS_NAMES); + self->wrapped.ScriptMessage("%s", s.GetChars()); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetValue, MustGetValue) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(allowfloat); + PARAM_BOOL(evaluate); + + MustGetValue(self, allowfloat, evaluate); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetNumber, MustGetNumber) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + MustGetNumber(self, evaluate); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetFloat, MustGetFloat) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + MustGetFloat(self, evaluate); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetString, MustGetString) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + MustGetString(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetStringName, MustGetStringName) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + + MustGetStringName(self, &name); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetBoolToken, MustGetBoolToken) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + MustGetBoolToken(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, Close, Close) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + Close(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetNoFatalErrors, SetNoFatalErrors) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(cmode); + + SetNoFatalErrors(self, cmode); + return 0; +} + +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.Line, Line); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.Float, Float); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.Number, Number); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.End, End); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.Crossed, Crossed); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.ParseError, ParseError); diff --git a/src/scripting/vm/jit.cpp b/src/common/scripting/jit/jit.cpp similarity index 85% rename from src/scripting/vm/jit.cpp rename to src/common/scripting/jit/jit.cpp index 1813d19caac..7ccd1a733af 100644 --- a/src/scripting/vm/jit.cpp +++ b/src/common/scripting/jit/jit.cpp @@ -1,17 +1,21 @@ #include "jit.h" #include "jitintern.h" +#include "printf.h" extern PString *TypeString; extern PStruct *TypeVector2; extern PStruct *TypeVector3; +extern PStruct* TypeVector4; +extern PStruct* TypeQuaternion; +extern PStruct* TypeFQuaternion; static void OutputJitLog(const asmjit::StringLogger &logger); JitFuncPtr JitCompile(VMScriptFunction *sfunc) { #if 0 - if (strcmp(sfunc->PrintableName.GetChars(), "StatusScreen.drawNum") != 0) + if (strcmp(sfunc->PrintableName, "StatusScreen.drawNum") != 0) return nullptr; #endif @@ -31,7 +35,7 @@ JitFuncPtr JitCompile(VMScriptFunction *sfunc) catch (const CRecoverableError &e) { OutputJitLog(logger); - Printf("%s: Unexpected JIT error: %s\n",sfunc->PrintableName.GetChars(), e.what()); + Printf("%s: Unexpected JIT error: %s\n",sfunc->PrintableName, e.what()); return nullptr; } } @@ -40,6 +44,13 @@ void JitDumpLog(FILE *file, VMScriptFunction *sfunc) { using namespace asmjit; StringLogger logger; + + if(sfunc->VarFlags & VARF_Abstract) + { + // Printf(TEXTCOLOR_ORANGE "Skipping abstract function during JIT dump: %s\n", sfunc->PrintableName.GetChars()); + return; + } + try { ThrowingErrorHandler errorHandler; @@ -233,7 +244,7 @@ void JitCompiler::Setup() cc.comment(marks, 56); FString funcname; - funcname.Format("Function: %s", sfunc->PrintableName.GetChars()); + funcname.Format("Function: %s", sfunc->PrintableName); cc.comment(funcname.GetChars(), funcname.Len()); cc.comment(marks, 56); @@ -276,7 +287,7 @@ void JitCompiler::SetupFrame() offsetD = offsetA + (int)(sfunc->NumRegA * sizeof(void*)); offsetExtra = (offsetD + (int)(sfunc->NumRegD * sizeof(int32_t)) + 15) & ~15; - if (sfunc->SpecialInits.Size() == 0 && sfunc->NumRegS == 0) + if (sfunc->SpecialInits.Size() == 0 && sfunc->NumRegS == 0 && sfunc->ExtraSpace == 0) { SetupSimpleFrame(); } @@ -303,17 +314,24 @@ void JitCompiler::SetupSimpleFrame() { cc.mov(regA[rega++], x86::ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, a))); } - else if (type == TypeVector2) + else if (type == TypeVector2 || type == TypeFVector2) { cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); } - else if (type == TypeVector3) + else if (type == TypeVector3 || type == TypeFVector3) { cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); } + else if (type == TypeVector4 || type == TypeFVector4 || type == TypeQuaternion || type == TypeFQuaternion) + { + cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); + cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); + cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); + cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); + } else if (type == TypeFloat64) { cc.movsd(regF[regf++], x86::qword_ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, f))); @@ -332,8 +350,29 @@ void JitCompiler::SetupSimpleFrame() } } - if (sfunc->NumArgs != argsPos || regd > sfunc->NumRegD || regf > sfunc->NumRegF || rega > sfunc->NumRegA) - I_FatalError("JIT: sfunc->NumArgs != argsPos || regd > sfunc->NumRegD || regf > sfunc->NumRegF || rega > sfunc->NumRegA"); + const char *errorDetails = nullptr; + + if (sfunc->NumArgs != argsPos) + { + errorDetails = "arguments"; + } + else if (regd > sfunc->NumRegD) + { + errorDetails = "integer registers"; + } + else if (regf > sfunc->NumRegF) + { + errorDetails = "floating point registers"; + } + else if (rega > sfunc->NumRegA) + { + errorDetails = "address registers"; + } + + if (errorDetails) + { + I_FatalError("JIT: inconsistent number of %s for function %s", errorDetails, sfunc->PrintableName); + } for (int i = regd; i < sfunc->NumRegD; i++) cc.xor_(regD[i], regD[i]); @@ -389,7 +428,7 @@ static void PopFullVMFrame(VMFrameStack *stack) void JitCompiler::EmitPopFrame() { - if (sfunc->SpecialInits.Size() != 0 || sfunc->NumRegS != 0) + if (sfunc->SpecialInits.Size() != 0 || sfunc->NumRegS != 0 || sfunc->ExtraSpace != 0) { auto popFrame = CreateCall(PopFullVMFrame); popFrame->setArg(0, stack); @@ -529,6 +568,20 @@ asmjit::X86Xmm JitCompiler::CheckRegF(int r0, int r1, int r2, int r3) } } +asmjit::X86Xmm JitCompiler::CheckRegF(int r0, int r1, int r2, int r3, int r4) +{ + if (r0 != r1 && r0 != r2 && r0 != r3 && r0 != r4) + { + return regF[r0]; + } + else + { + auto copy = newTempXmmSd(); + cc.movsd(copy, regF[r0]); + return copy; + } +} + asmjit::X86Gp JitCompiler::CheckRegS(int r0, int r1) { if (r0 != r1) diff --git a/src/scripting/vm/jit.h b/src/common/scripting/jit/jit.h similarity index 87% rename from src/scripting/vm/jit.h rename to src/common/scripting/jit/jit.h index faaf6511281..c4aa1fb270b 100644 --- a/src/scripting/vm/jit.h +++ b/src/common/scripting/jit/jit.h @@ -5,4 +5,4 @@ JitFuncPtr JitCompile(VMScriptFunction *func); void JitDumpLog(FILE *file, VMScriptFunction *func); -FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames); +FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames = -1); diff --git a/src/scripting/vm/jit_call.cpp b/src/common/scripting/jit/jit_call.cpp similarity index 92% rename from src/scripting/vm/jit_call.cpp rename to src/common/scripting/jit/jit_call.cpp index ee35fc13994..7154d9e2713 100644 --- a/src/scripting/vm/jit_call.cpp +++ b/src/common/scripting/jit/jit_call.cpp @@ -97,7 +97,7 @@ void JitCompiler::EmitVMCall(asmjit::X86Gp vmfunc, VMFunction *target) call->setArg(2, Imm(B)); call->setArg(3, GetCallReturns()); call->setArg(4, Imm(C)); - call->setInlineComment(target ? target->PrintableName.GetChars() : "VMCall"); + call->setInlineComment(target ? target->PrintableName : "VMCall"); LoadInOuts(); LoadReturns(pc + 1, C); @@ -182,6 +182,13 @@ int JitCompiler::StoreCallParams() } numparams += 2; break; + case REGT_FLOAT | REGT_MULTIREG4: + for (int j = 0; j < 4; j++) + { + cc.movsd(x86::qword_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc + j]); + } + numparams += 3; + break; case REGT_FLOAT | REGT_ADDROF: cc.lea(stackPtr, x86::ptr(vmframe, offsetF + (int)(bc * sizeof(double)))); // When passing the address to a float we don't know if the receiving function will treat it as float, vec2 or vec3. @@ -256,6 +263,12 @@ void JitCompiler::LoadCallResult(int type, int regnum, bool addrof) cc.movsd(regF[regnum + 1], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 1) * sizeof(double))); cc.movsd(regF[regnum + 2], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 2) * sizeof(double))); } + else if (type & REGT_MULTIREG4) + { + cc.movsd(regF[regnum + 1], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 1) * sizeof(double))); + cc.movsd(regF[regnum + 2], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 2) * sizeof(double))); + cc.movsd(regF[regnum + 3], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 3) * sizeof(double))); + } break; case REGT_STRING: // We don't have to do anything in this case. String values are never moved to virtual registers. @@ -340,14 +353,14 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target) I_Error("Unexpected register type for self pointer\n"); break; } - + cc.test(*reg, *reg); cc.jz(label); } asmjit::CBNode *cursorBefore = cc.getCursor(); auto call = cc.call(imm_ptr(target->DirectNativeCall), CreateFuncSignature()); - call->setInlineComment(target->PrintableName.GetChars()); + call->setInlineComment(target->PrintableName); asmjit::CBNode *cursorAfter = cc.getCursor(); cc.setCursor(cursorBefore); @@ -408,6 +421,11 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target) call->setArg(slot + j, regF[bc + j]); numparams += 2; break; + case REGT_FLOAT | REGT_MULTIREG4: + for (int j = 0; j < 4; j++) + call->setArg(slot + j, regF[bc + j]); + numparams += 3; + break; case REGT_FLOAT | REGT_KONST: tmp = newTempIntPtr(); tmp2 = newTempXmmSd(); @@ -550,6 +568,12 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target) cc.movsd(regF[regnum + 1], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 1) * sizeof(double))); cc.movsd(regF[regnum + 2], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 2) * sizeof(double))); break; + case REGT_FLOAT | REGT_MULTIREG4: + cc.movsd(regF[regnum], asmjit::x86::qword_ptr(vmframe, offsetF + regnum * sizeof(double))); + cc.movsd(regF[regnum + 1], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 1) * sizeof(double))); + cc.movsd(regF[regnum + 2], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 2) * sizeof(double))); + cc.movsd(regF[regnum + 3], asmjit::x86::qword_ptr(vmframe, offsetF + (regnum + 3) * sizeof(double))); + break; case REGT_STRING: // We don't have to do anything in this case. String values are never moved to virtual registers. break; @@ -624,6 +648,13 @@ asmjit::FuncSignature JitCompiler::CreateFuncSignature() args.Push(TypeIdOf::kTypeId); key += "fff"; break; + case REGT_FLOAT | REGT_MULTIREG4: + args.Push(TypeIdOf::kTypeId); + args.Push(TypeIdOf::kTypeId); + args.Push(TypeIdOf::kTypeId); + args.Push(TypeIdOf::kTypeId); + key += "ffff"; + break; default: I_Error("Unknown REGT value passed to EmitPARAM\n"); @@ -688,3 +719,8 @@ asmjit::FuncSignature JitCompiler::CreateFuncSignature() signature.init(CallConv::kIdHost, rettype, cachedArgs->Data(), cachedArgs->Size()); return signature; } + +void JitCompiler::EmitNULLCHECK() +{ + EmitNullPointerThrow(A, X_READ_NIL); +} \ No newline at end of file diff --git a/src/scripting/vm/jit_flow.cpp b/src/common/scripting/jit/jit_flow.cpp similarity index 88% rename from src/scripting/vm/jit_flow.cpp rename to src/common/scripting/jit/jit_flow.cpp index 5db91818a10..3b5acd1ab85 100644 --- a/src/scripting/vm/jit_flow.cpp +++ b/src/common/scripting/jit/jit_flow.cpp @@ -7,7 +7,7 @@ void JitCompiler::EmitTEST() cc.cmp(regD[A], BC); cc.jne(GetLabel(i + 2)); } - + void JitCompiler::EmitTESTN() { int bc = BC; @@ -110,7 +110,21 @@ void JitCompiler::EmitRET() if (regtype & REGT_KONST) { auto tmp = newTempInt64(); - if (regtype & REGT_MULTIREG3) + if (regtype & REGT_MULTIREG4) + { + cc.mov(tmp, (((int64_t*)konstf)[regnum])); + cc.mov(x86::qword_ptr(location), tmp); + + cc.mov(tmp, (((int64_t*)konstf)[regnum + 1])); + cc.mov(x86::qword_ptr(location, 8), tmp); + + cc.mov(tmp, (((int64_t*)konstf)[regnum + 2])); + cc.mov(x86::qword_ptr(location, 16), tmp); + + cc.mov(tmp, (((int64_t*)konstf)[regnum + 3])); + cc.mov(x86::qword_ptr(location, 24), tmp); + } + else if (regtype & REGT_MULTIREG3) { cc.mov(tmp, (((int64_t *)konstf)[regnum])); cc.mov(x86::qword_ptr(location), tmp); @@ -137,7 +151,14 @@ void JitCompiler::EmitRET() } else { - if (regtype & REGT_MULTIREG3) + if (regtype & REGT_MULTIREG4) + { + cc.movsd(x86::qword_ptr(location), regF[regnum]); + cc.movsd(x86::qword_ptr(location, 8), regF[regnum + 1]); + cc.movsd(x86::qword_ptr(location, 16), regF[regnum + 2]); + cc.movsd(x86::qword_ptr(location, 24), regF[regnum + 3]); + } + else if (regtype & REGT_MULTIREG3) { cc.movsd(x86::qword_ptr(location), regF[regnum]); cc.movsd(x86::qword_ptr(location, 8), regF[regnum + 1]); @@ -310,7 +331,7 @@ void JitCompiler::ThrowArrayOutOfBounds(int index, int size) { if (index >= size) { - ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", size, index); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Size = %u, current index = %u\n", size, index); } else { diff --git a/src/common/scripting/jit/jit_load.cpp b/src/common/scripting/jit/jit_load.cpp new file mode 100644 index 00000000000..60947084dde --- /dev/null +++ b/src/common/scripting/jit/jit_load.cpp @@ -0,0 +1,460 @@ + +#include "jitintern.h" + +///////////////////////////////////////////////////////////////////////////// +// Load constants. + +void JitCompiler::EmitLI() +{ + cc.mov(regD[A], BCs); +} + +void JitCompiler::EmitLK() +{ + cc.mov(regD[A], konstd[BC]); +} + +void JitCompiler::EmitLKF() +{ + auto base = newTempIntPtr(); + cc.mov(base, asmjit::imm_ptr(konstf + BC)); + cc.movsd(regF[A], asmjit::x86::qword_ptr(base)); +} + +void JitCompiler::EmitLKS() +{ + auto call = CreateCall(&JitCompiler::CallAssignString); + call->setArg(0, regS[A]); + call->setArg(1, asmjit::imm_ptr(konsts + BC)); +} + +void JitCompiler::EmitLKP() +{ + cc.mov(regA[A], (int64_t)konsta[BC].v); +} + +void JitCompiler::EmitLK_R() +{ + auto base = newTempIntPtr(); + cc.mov(base, asmjit::imm_ptr(konstd + C)); + cc.mov(regD[A], asmjit::x86::ptr(base, regD[B], 2)); +} + +void JitCompiler::EmitLKF_R() +{ + auto base = newTempIntPtr(); + cc.mov(base, asmjit::imm_ptr(konstf + C)); + cc.movsd(regF[A], asmjit::x86::qword_ptr(base, regD[B], 3)); +} + +void JitCompiler::EmitLKS_R() +{ + auto base = newTempIntPtr(); + cc.mov(base, asmjit::imm_ptr(konsts + C)); + auto ptr = newTempIntPtr(); + if (cc.is64Bit()) + cc.lea(ptr, asmjit::x86::ptr(base, regD[B], 3)); + else + cc.lea(ptr, asmjit::x86::ptr(base, regD[B], 2)); + auto call = CreateCall(&JitCompiler::CallAssignString); + call->setArg(0, regS[A]); + call->setArg(1, ptr); +} + +void JitCompiler::EmitLKP_R() +{ + auto base = newTempIntPtr(); + cc.mov(base, asmjit::imm_ptr(konsta + C)); + if (cc.is64Bit()) + cc.mov(regA[A], asmjit::x86::ptr(base, regD[B], 3)); + else + cc.mov(regA[A], asmjit::x86::ptr(base, regD[B], 2)); +} + +void JitCompiler::EmitLFP() +{ + CheckVMFrame(); + cc.lea(regA[A], asmjit::x86::ptr(vmframe, offsetExtra)); +} + +void JitCompiler::EmitMETA() +{ + auto label = EmitThrowExceptionLabel(X_READ_NIL); + cc.test(regA[B], regA[B]); + cc.je(label); + + cc.mov(regA[A], asmjit::x86::qword_ptr(regA[B], myoffsetof(DObject, Class))); + cc.mov(regA[A], asmjit::x86::qword_ptr(regA[A], myoffsetof(PClass, Meta))); +} + +void JitCompiler::EmitCLSS() +{ + auto label = EmitThrowExceptionLabel(X_READ_NIL); + cc.test(regA[B], regA[B]); + cc.je(label); + cc.mov(regA[A], asmjit::x86::qword_ptr(regA[B], myoffsetof(DObject, Class))); +} + +///////////////////////////////////////////////////////////////////////////// +// Load from memory. rA = *(rB + rkC) + +void JitCompiler::EmitLB() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B], konstd[C])); +} + +void JitCompiler::EmitLB_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B], regD[C])); +} + +void JitCompiler::EmitLH() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movsx(regD[A], asmjit::x86::word_ptr(regA[B], konstd[C])); +} + +void JitCompiler::EmitLH_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movsx(regD[A], asmjit::x86::word_ptr(regA[B], regD[C])); +} + +void JitCompiler::EmitLW() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.mov(regD[A], asmjit::x86::dword_ptr(regA[B], konstd[C])); +} + +void JitCompiler::EmitLW_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.mov(regD[A], asmjit::x86::dword_ptr(regA[B], regD[C])); +} + +void JitCompiler::EmitLBU() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movzx(regD[A], asmjit::x86::byte_ptr(regA[B], konstd[C])); +} + +void JitCompiler::EmitLBU_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movzx(regD[A].r8Lo(), asmjit::x86::byte_ptr(regA[B], regD[C])); +} + +void JitCompiler::EmitLHU() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movzx(regD[A].r16(), asmjit::x86::word_ptr(regA[B], konstd[C])); +} + +void JitCompiler::EmitLHU_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movzx(regD[A].r16(), asmjit::x86::word_ptr(regA[B], regD[C])); +} + +void JitCompiler::EmitLSP() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.xorpd(regF[A], regF[A]); + cc.cvtss2sd(regF[A], asmjit::x86::dword_ptr(regA[B], konstd[C])); +} + +void JitCompiler::EmitLSP_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.xorpd(regF[A], regF[A]); + cc.cvtss2sd(regF[A], asmjit::x86::dword_ptr(regA[B], regD[C])); +} + +void JitCompiler::EmitLDP() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movsd(regF[A], asmjit::x86::qword_ptr(regA[B], konstd[C])); +} + +void JitCompiler::EmitLDP_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movsd(regF[A], asmjit::x86::qword_ptr(regA[B], regD[C])); +} + +void JitCompiler::EmitLS() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto ptr = newTempIntPtr(); + cc.lea(ptr, asmjit::x86::ptr(regA[B], konstd[C])); + auto call = CreateCall(&JitCompiler::CallAssignString); + call->setArg(0, regS[A]); + call->setArg(1, ptr); +} + +void JitCompiler::EmitLS_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto ptr = newTempIntPtr(); + cc.lea(ptr, asmjit::x86::ptr(regA[B], regD[C])); + auto call = CreateCall(&JitCompiler::CallAssignString); + call->setArg(0, regS[A]); + call->setArg(1, ptr); +} + +#if 1 // Inline read barrier impl + +void JitCompiler::EmitReadBarrier() +{ + auto isnull = cc.newLabel(); + cc.test(regA[A], regA[A]); + cc.je(isnull); + + auto mask = newTempIntPtr(); + cc.mov(mask.r32(), asmjit::x86::dword_ptr(regA[A], myoffsetof(DObject, ObjectFlags))); + cc.shl(mask, 63 - 5); // put OF_EuthanizeMe (1 << 5) in the highest bit + cc.sar(mask, 63); // sign extend so all bits are set if OF_EuthanizeMe was set + cc.not_(mask); + cc.and_(regA[A], mask); + + cc.bind(isnull); +} + +void JitCompiler::EmitLO() +{ + EmitNullPointerThrow(B, X_READ_NIL); + + cc.mov(regA[A], asmjit::x86::ptr(regA[B], konstd[C])); + EmitReadBarrier(); +} + +void JitCompiler::EmitLO_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + + cc.mov(regA[A], asmjit::x86::ptr(regA[B], regD[C])); + EmitReadBarrier(); +} + +#else + +static DObject *ReadBarrier(DObject *p) +{ + return GC::ReadBarrier(p); +} + +void JitCompiler::EmitLO() +{ + EmitNullPointerThrow(B, X_READ_NIL); + + auto ptr = newTempIntPtr(); + cc.mov(ptr, asmjit::x86::ptr(regA[B], konstd[C])); + + auto result = newResultIntPtr(); + auto call = CreateCall(ReadBarrier); + call->setRet(0, result); + call->setArg(0, ptr); + cc.mov(regA[A], result); +} + +void JitCompiler::EmitLO_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + + auto ptr = newTempIntPtr(); + cc.mov(ptr, asmjit::x86::ptr(regA[B], regD[C])); + + auto result = newResultIntPtr(); + auto call = CreateCall(ReadBarrier); + call->setRet(0, result); + call->setArg(0, ptr); + cc.mov(regA[A], result); +} + +#endif + +void JitCompiler::EmitLP() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.mov(regA[A], asmjit::x86::ptr(regA[B], konstd[C])); +} + +void JitCompiler::EmitLP_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.mov(regA[A], asmjit::x86::ptr(regA[B], regD[C])); +} + +void JitCompiler::EmitLV2() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], konstd[C])); + cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); +} + +void JitCompiler::EmitLV2_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], regD[C])); + cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); +} + +void JitCompiler::EmitLV3() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], konstd[C])); + cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); + cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); +} + +void JitCompiler::EmitLV3_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], regD[C])); + cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); + cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); +} + +void JitCompiler::EmitLV4() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], konstd[C])); + cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); + cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); + cc.movsd(regF[A + 3], asmjit::x86::qword_ptr(tmp, 24)); +} + +void JitCompiler::EmitLV4_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], regD[C])); + cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); + cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); + cc.movsd(regF[A + 3], asmjit::x86::qword_ptr(tmp, 24)); +} + +void JitCompiler::EmitLFV2() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], konstd[C])); + cc.movss(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movss(regF[A + 1], asmjit::x86::qword_ptr(tmp, 4)); + cc.cvtss2sd(regF[A], regF[A]); + cc.cvtss2sd(regF[A + 1], regF[A + 1]); +} + +void JitCompiler::EmitLFV2_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], regD[C])); + cc.movss(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movss(regF[A + 1], asmjit::x86::qword_ptr(tmp, 4)); + cc.cvtss2sd(regF[A], regF[A]); + cc.cvtss2sd(regF[A + 1], regF[A + 1]); +} + +void JitCompiler::EmitLFV3() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], konstd[C])); + cc.movss(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movss(regF[A + 1], asmjit::x86::qword_ptr(tmp, 4)); + cc.movss(regF[A + 2], asmjit::x86::qword_ptr(tmp, 8)); + cc.cvtss2sd(regF[A], regF[A]); + cc.cvtss2sd(regF[A + 1], regF[A + 1]); + cc.cvtss2sd(regF[A + 2], regF[A + 2]); +} + +void JitCompiler::EmitLFV3_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], regD[C])); + cc.movss(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movss(regF[A + 1], asmjit::x86::qword_ptr(tmp, 4)); + cc.movss(regF[A + 2], asmjit::x86::qword_ptr(tmp, 8)); + cc.cvtss2sd(regF[A], regF[A]); + cc.cvtss2sd(regF[A + 1], regF[A + 1]); + cc.cvtss2sd(regF[A + 2], regF[A + 2]); +} + +void JitCompiler::EmitLFV4() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], konstd[C])); + cc.movss(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movss(regF[A + 1], asmjit::x86::qword_ptr(tmp, 4)); + cc.movss(regF[A + 2], asmjit::x86::qword_ptr(tmp, 8)); + cc.movss(regF[A + 3], asmjit::x86::qword_ptr(tmp, 12)); + cc.cvtss2sd(regF[A], regF[A]); + cc.cvtss2sd(regF[A + 1], regF[A + 1]); + cc.cvtss2sd(regF[A + 2], regF[A + 2]); + cc.cvtss2sd(regF[A + 3], regF[A + 3]); +} + +void JitCompiler::EmitLFV4_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto tmp = newTempIntPtr(); + cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], regD[C])); + cc.movss(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.movss(regF[A + 1], asmjit::x86::qword_ptr(tmp, 4)); + cc.movss(regF[A + 2], asmjit::x86::qword_ptr(tmp, 8)); + cc.movss(regF[A + 3], asmjit::x86::qword_ptr(tmp, 12)); + cc.cvtss2sd(regF[A], regF[A]); + cc.cvtss2sd(regF[A + 1], regF[A + 1]); + cc.cvtss2sd(regF[A + 2], regF[A + 2]); + cc.cvtss2sd(regF[A + 3], regF[A + 3]); +} + +static void SetString(FString *to, char **from) +{ + *to = *from; +} + +void JitCompiler::EmitLCS() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto ptr = newTempIntPtr(); + cc.lea(ptr, asmjit::x86::ptr(regA[B], konstd[C])); + auto call = CreateCall(SetString); + call->setArg(0, regS[A]); + call->setArg(1, ptr); +} + +void JitCompiler::EmitLCS_R() +{ + EmitNullPointerThrow(B, X_READ_NIL); + auto ptr = newTempIntPtr(); + cc.lea(ptr, asmjit::x86::ptr(regA[B], regD[C])); + auto call = CreateCall(SetString); + call->setArg(0, regS[A]); + call->setArg(1, ptr); +} + +void JitCompiler::EmitLBIT() +{ + EmitNullPointerThrow(B, X_READ_NIL); + cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B])); + cc.and_(regD[A], C); + cc.cmp(regD[A], 0); + cc.setne(regD[A]); +} diff --git a/src/scripting/vm/jit_math.cpp b/src/common/scripting/jit/jit_math.cpp similarity index 84% rename from src/scripting/vm/jit_math.cpp rename to src/common/scripting/jit/jit_math.cpp index 4210fa6ff7d..24328b9d314 100644 --- a/src/scripting/vm/jit_math.cpp +++ b/src/common/scripting/jit/jit_math.cpp @@ -1,5 +1,6 @@ #include "jitintern.h" +#include "basics.h" ///////////////////////////////////////////////////////////////////////////// // String instructions. @@ -901,7 +902,7 @@ void JitCompiler::EmitMINF_RK() cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); cc.minpd(regF[A], rb); // minsd requires SSE 4.1 } - + void JitCompiler::EmitMAXF_RR() { auto rc = CheckRegF(C, A); @@ -918,7 +919,7 @@ void JitCompiler::EmitMAXF_RK() cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); cc.maxpd(regF[A], rb); // maxsd requires SSE 4.1 } - + void JitCompiler::EmitATAN2() { auto result = newResultXmmSd(); @@ -962,7 +963,7 @@ void JitCompiler::EmitFLOP() FuncPtr func = nullptr; switch (C) { - default: I_Error("Unknown OP_FLOP subfunction"); + default: I_Error("Unknown OP_FLOP subfunction"); break; case FLOP_ABS: func = fabs; break; case FLOP_EXP: func = g_exp; break; case FLOP_LOG: func = g_log; break; @@ -1440,12 +1441,227 @@ void JitCompiler::EmitEQV3_R() EmitVectorComparison<3> (check, fail, success); }); } - + void JitCompiler::EmitEQV3_K() { I_Error("EQV3_K is not used."); } +///////////////////////////////////////////////////////////////////////////// +// Vector math. (4D/Quaternion) + +void JitCompiler::EmitNEGV4() +{ + auto mask = cc.newDoubleConst(asmjit::kConstScopeLocal, -0.0); + auto maskXmm = newTempXmmSd(); + cc.movsd(maskXmm, mask); + cc.movsd(regF[A], regF[B]); + cc.xorpd(regF[A], maskXmm); + cc.movsd(regF[A + 1], regF[B + 1]); + cc.xorpd(regF[A + 1], maskXmm); + cc.movsd(regF[A + 2], regF[B + 2]); + cc.xorpd(regF[A + 2], maskXmm); + cc.movsd(regF[A + 3], regF[B + 3]); + cc.xorpd(regF[A + 3], maskXmm); +} + +void JitCompiler::EmitADDV4_RR() +{ + auto rc0 = CheckRegF(C, A); + auto rc1 = CheckRegF(C + 1, A + 1); + auto rc2 = CheckRegF(C + 2, A + 2); + auto rc3 = CheckRegF(C + 3, A + 3); + cc.movsd(regF[A], regF[B]); + cc.addsd(regF[A], rc0); + cc.movsd(regF[A + 1], regF[B + 1]); + cc.addsd(regF[A + 1], rc1); + cc.movsd(regF[A + 2], regF[B + 2]); + cc.addsd(regF[A + 2], rc2); + cc.movsd(regF[A + 3], regF[B + 3]); + cc.addsd(regF[A + 3], rc3); +} + +void JitCompiler::EmitSUBV4_RR() +{ + auto rc0 = CheckRegF(C, A); + auto rc1 = CheckRegF(C + 1, A + 1); + auto rc2 = CheckRegF(C + 2, A + 2); + auto rc3 = CheckRegF(C + 3, A + 3); + cc.movsd(regF[A], regF[B]); + cc.subsd(regF[A], rc0); + cc.movsd(regF[A + 1], regF[B + 1]); + cc.subsd(regF[A + 1], rc1); + cc.movsd(regF[A + 2], regF[B + 2]); + cc.subsd(regF[A + 2], rc2); + cc.movsd(regF[A + 3], regF[B + 3]); + cc.subsd(regF[A + 3], rc3); +} + +void JitCompiler::EmitDOTV4_RR() +{ + auto rb1 = CheckRegF(B + 1, A); + auto rb2 = CheckRegF(B + 2, A); + auto rb3 = CheckRegF(B + 3, A); + auto rc0 = CheckRegF(C, A); + auto rc1 = CheckRegF(C + 1, A); + auto rc2 = CheckRegF(C + 2, A); + auto rc3 = CheckRegF(C + 3, A); + auto tmp = newTempXmmSd(); + cc.movsd(regF[A], regF[B]); + cc.mulsd(regF[A], rc0); + cc.movsd(tmp, rb1); + cc.mulsd(tmp, rc1); + cc.addsd(regF[A], tmp); + cc.movsd(tmp, rb2); + cc.mulsd(tmp, rc2); + cc.addsd(regF[A], tmp); + cc.movsd(tmp, rb3); + cc.mulsd(tmp, rc3); + cc.addsd(regF[A], tmp); +} + +void JitCompiler::EmitMULVF4_RR() +{ + auto rc = CheckRegF(C, A, A + 1, A + 2, A + 3); + cc.movsd(regF[A], regF[B]); + cc.movsd(regF[A + 1], regF[B + 1]); + cc.movsd(regF[A + 2], regF[B + 2]); + cc.movsd(regF[A + 3], regF[B + 3]); + cc.mulsd(regF[A], rc); + cc.mulsd(regF[A + 1], rc); + cc.mulsd(regF[A + 2], rc); + cc.mulsd(regF[A + 3], rc); +} + +void JitCompiler::EmitMULVF4_RK() +{ + auto tmp = newTempIntPtr(); + cc.movsd(regF[A], regF[B]); + cc.movsd(regF[A + 1], regF[B + 1]); + cc.movsd(regF[A + 2], regF[B + 2]); + cc.movsd(regF[A + 3], regF[B + 3]); + cc.mov(tmp, asmjit::imm_ptr(&konstf[C])); + cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.mulsd(regF[A + 1], asmjit::x86::qword_ptr(tmp)); + cc.mulsd(regF[A + 2], asmjit::x86::qword_ptr(tmp)); + cc.mulsd(regF[A + 3], asmjit::x86::qword_ptr(tmp)); +} + +void JitCompiler::EmitDIVVF4_RR() +{ + auto rc = CheckRegF(C, A, A + 1, A + 2, A + 3); + cc.movsd(regF[A], regF[B]); + cc.movsd(regF[A + 1], regF[B + 1]); + cc.movsd(regF[A + 2], regF[B + 2]); + cc.movsd(regF[A + 3], regF[B + 3]); + cc.divsd(regF[A], rc); + cc.divsd(regF[A + 1], rc); + cc.divsd(regF[A + 2], rc); + cc.divsd(regF[A + 3], rc); +} + +void JitCompiler::EmitDIVVF4_RK() +{ + auto tmp = newTempIntPtr(); + cc.movsd(regF[A], regF[B]); + cc.movsd(regF[A + 1], regF[B + 1]); + cc.movsd(regF[A + 2], regF[B + 2]); + cc.movsd(regF[A + 3], regF[B + 3]); + cc.mov(tmp, asmjit::imm_ptr(&konstf[C])); + cc.divsd(regF[A], asmjit::x86::qword_ptr(tmp)); + cc.divsd(regF[A + 1], asmjit::x86::qword_ptr(tmp)); + cc.divsd(regF[A + 2], asmjit::x86::qword_ptr(tmp)); + cc.divsd(regF[A + 3], asmjit::x86::qword_ptr(tmp)); +} + +void JitCompiler::EmitLENV4() +{ + auto rb1 = CheckRegF(B + 1, A); + auto rb2 = CheckRegF(B + 2, A); + auto rb3 = CheckRegF(B + 3, A); + auto tmp = newTempXmmSd(); + cc.movsd(regF[A], regF[B]); + cc.mulsd(regF[A], regF[B]); + cc.movsd(tmp, rb1); + cc.mulsd(tmp, rb1); + cc.addsd(regF[A], tmp); + cc.movsd(tmp, rb2); + cc.mulsd(tmp, rb2); + cc.addsd(regF[A], tmp); + cc.movsd(tmp, rb3); + cc.mulsd(tmp, rb3); + cc.addsd(regF[A], tmp); + CallSqrt(regF[A], regF[A]); +} + +void JitCompiler::EmitEQV4_R() +{ + EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) { + EmitVectorComparison<4> (check, fail, success); + }); +} + +void JitCompiler::EmitEQV4_K() +{ + I_Error("EQV4_K is not used."); +} + +// Quaternion ops +void FuncMULQQ(void *result, double ax, double ay, double az, double aw, double bx, double by, double bz, double bw) +{ + *reinterpret_cast(result) = DQuaternion(ax, ay, az, aw) * DQuaternion(bx, by, bz, bw); +} + +void FuncMULQV3(void *result, double ax, double ay, double az, double aw, double bx, double by, double bz) +{ + *reinterpret_cast(result) = DQuaternion(ax, ay, az, aw) * DVector3(bx, by, bz); +} + +void JitCompiler::EmitMULQQ_RR() +{ + auto stack = GetTemporaryVectorStackStorage(); + auto tmp = newTempIntPtr(); + cc.lea(tmp, stack); + + auto call = CreateCall(FuncMULQQ); + call->setArg(0, tmp); + call->setArg(1, regF[B + 0]); + call->setArg(2, regF[B + 1]); + call->setArg(3, regF[B + 2]); + call->setArg(4, regF[B + 3]); + call->setArg(5, regF[C + 0]); + call->setArg(6, regF[C + 1]); + call->setArg(7, regF[C + 2]); + call->setArg(8, regF[C + 3]); + + cc.movsd(regF[A + 0], asmjit::x86::qword_ptr(tmp, 0)); + cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); + cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); + cc.movsd(regF[A + 3], asmjit::x86::qword_ptr(tmp, 24)); +} + +void JitCompiler::EmitMULQV3_RR() +{ + auto stack = GetTemporaryVectorStackStorage(); + auto tmp = newTempIntPtr(); + cc.lea(tmp, stack); + + auto call = CreateCall(FuncMULQV3); + call->setArg(0, tmp); + call->setArg(1, regF[B + 0]); + call->setArg(2, regF[B + 1]); + call->setArg(3, regF[B + 2]); + call->setArg(4, regF[B + 3]); + call->setArg(5, regF[C + 0]); + call->setArg(6, regF[C + 1]); + call->setArg(7, regF[C + 2]); + + cc.movsd(regF[A + 0], asmjit::x86::qword_ptr(tmp, 0)); + cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); + cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); +} + + ///////////////////////////////////////////////////////////////////////////// // Pointer math. diff --git a/src/scripting/vm/jit_move.cpp b/src/common/scripting/jit/jit_move.cpp similarity index 85% rename from src/scripting/vm/jit_move.cpp rename to src/common/scripting/jit/jit_move.cpp index f9383eababe..edff1763c41 100644 --- a/src/scripting/vm/jit_move.cpp +++ b/src/common/scripting/jit/jit_move.cpp @@ -1,8 +1,9 @@ #include "jitintern.h" #include "v_video.h" -#include "s_sound.h" -#include "r_state.h" +#include "s_soundinternal.h" +#include "texturemanager.h" +#include "palutil.h" void JitCompiler::EmitMOVE() { @@ -38,22 +39,31 @@ void JitCompiler::EmitMOVEV3() cc.movsd(regF[A + 2], regF[B + 2]); } +void JitCompiler::EmitMOVEV4() +{ + cc.movsd(regF[A], regF[B]); + cc.movsd(regF[A + 1], regF[B + 1]); + cc.movsd(regF[A + 2], regF[B + 2]); + cc.movsd(regF[A + 3], regF[B + 3]); +} + static void CastI2S(FString *a, int b) { a->Format("%d", b); } static void CastU2S(FString *a, int b) { a->Format("%u", b); } static void CastF2S(FString *a, double b) { a->Format("%.5f", b); } static void CastV22S(FString *a, double b, double b1) { a->Format("(%.5f, %.5f)", b, b1); } static void CastV32S(FString *a, double b, double b1, double b2) { a->Format("(%.5f, %.5f, %.5f)", b, b1, b2); } +static void CastV42S(FString *a, double b, double b1, double b2, double b3) { a->Format("(%.5f, %.5f, %.5f, %.5f)", b, b1, b2, b3); } static void CastP2S(FString *a, void *b) { if (b == nullptr) *a = "null"; else a->Format("%p", b); } static int CastS2I(FString *b) { return (int)b->ToLong(); } static double CastS2F(FString *b) { return b->ToDouble(); } -static int CastS2N(FString *b) { return b->Len() == 0 ? FName(NAME_None) : FName(*b); } +static int CastS2N(FString *b) { return b->Len() == 0 ? NAME_None : FName(*b).GetIndex(); } static void CastN2S(FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; } -static int CastS2Co(FString *b) { return V_GetColor(nullptr, *b); } +static int CastS2Co(FString *b) { return V_GetColor(b->GetChars()); } static void CastCo2S(FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); } -static int CastS2So(FString *b) { return FSoundID(*b); } -static void CastSo2S(FString* a, int b) { *a = S_GetSoundName(b); } -static void CastSID2S(FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; } -static void CastTID2S(FString *a, int b) { auto tex = TexMan.GetTexture(*(FTextureID*)&b); *a = (tex == nullptr) ? "(null)" : tex->GetName().GetChars(); } +static int CastS2So(FString *b) { return S_FindSound(*b).index(); } +static void CastSo2S(FString* a, int b) { *a = soundEngine->GetSoundName(FSoundID::fromInt(b)); } +static void CastSID2S(FString* a, unsigned int b) { VM_CastSpriteIDToString(a, b); } +static void CastTID2S(FString *a, int b) { auto tex = TexMan.GetGameTexture(*(FTextureID*)&b); *a = (tex == nullptr) ? "(null)" : tex->GetName().GetChars(); } void JitCompiler::EmitCAST() { @@ -108,6 +118,14 @@ void JitCompiler::EmitCAST() call->setArg(2, regF[B + 1]); call->setArg(3, regF[B + 2]); break; + case CAST_V42S: + call = CreateCall(CastV42S); + call->setArg(0, regS[A]); + call->setArg(1, regF[B]); + call->setArg(2, regF[B + 1]); + call->setArg(3, regF[B + 2]); + call->setArg(4, regF[B + 3]); + break; case CAST_P2S: call = CreateCall(CastP2S); call->setArg(0, regS[A]); diff --git a/src/scripting/vm/jit_runtime.cpp b/src/common/scripting/jit/jit_runtime.cpp similarity index 95% rename from src/scripting/vm/jit_runtime.cpp rename to src/common/scripting/jit/jit_runtime.cpp index 5e922be6f24..cdfbedb674f 100644 --- a/src/scripting/vm/jit_runtime.cpp +++ b/src/common/scripting/jit/jit_runtime.cpp @@ -5,6 +5,7 @@ #ifdef WIN32 #include +#include #else #include #include @@ -56,7 +57,7 @@ static void *AllocJitMemory(size_t size) } else { - const size_t bytesToAllocate = MAX(size_t(1024 * 1024), size); + const size_t bytesToAllocate = max(size_t(1024 * 1024), size); size_t allocatedSize = 0; void *p = OSUtils::allocVirtualMemory(bytesToAllocate, &allocatedSize, OSUtils::kVMWritable | OSUtils::kVMExecutable); if (!p) @@ -305,7 +306,7 @@ void *AddJitFunction(asmjit::CodeHolder* code, JitCompiler *compiler) if (result == 0) I_Error("RtlAddFunctionTable failed"); - JitDebugInfo.Push({ compiler->GetScriptFunction()->PrintableName, compiler->GetScriptFunction()->SourceFileName, compiler->LineInfo, startaddr, endaddr }); + JitDebugInfo.Push({ FString(compiler->GetScriptFunction()->PrintableName), compiler->GetScriptFunction()->SourceFileName, compiler->LineInfo, startaddr, endaddr }); #endif return p; @@ -403,7 +404,7 @@ static void WriteCIE(TArray &stream, const TArray &cieInstruct unsigned int lengthPos = stream.Size(); WriteUInt32(stream, 0); // Length WriteUInt32(stream, 0); // CIE ID - + WriteUInt8(stream, 1); // CIE Version WriteUInt8(stream, 'z'); WriteUInt8(stream, 'R'); // fde encoding @@ -428,7 +429,7 @@ static void WriteFDE(TArray &stream, const TArray &fdeInstruct WriteUInt32(stream, 0); // Length uint32_t offsetToCIE = stream.Size() - cieLocation; WriteUInt32(stream, offsetToCIE); - + functionStart = stream.Size(); WriteUInt64(stream, 0); // func start WriteUInt64(stream, 0); // func size @@ -499,7 +500,7 @@ static TArray CreateUnwindInfoUnix(asmjit::CCFunc *func, unsigned int & // // The CFI_Parser::decodeFDE parser on the other side.. // https://github.com/llvm-mirror/libunwind/blob/master/src/DwarfParser.hpp - + // Asmjit -> DWARF register id int dwarfRegId[16]; dwarfRegId[X86Gp::kIdAx] = 0; @@ -520,7 +521,7 @@ static TArray CreateUnwindInfoUnix(asmjit::CCFunc *func, unsigned int & dwarfRegId[X86Gp::kIdR15] = 15; int dwarfRegRAId = 16; int dwarfRegXmmId = 17; - + TArray cieInstructions; TArray fdeInstructions; @@ -529,7 +530,7 @@ static TArray CreateUnwindInfoUnix(asmjit::CCFunc *func, unsigned int & WriteDefineCFA(cieInstructions, dwarfRegId[X86Gp::kIdSp], stackOffset); WriteRegisterStackLocation(cieInstructions, returnAddressReg, stackOffset); - + FuncFrameLayout layout; Error error = layout.init(func->getDetail(), func->getFrameInfo()); if (error != kErrorOk) @@ -702,7 +703,7 @@ void *AddJitFunction(asmjit::CodeHolder* code, JitCompiler *compiler) uint64_t length64 = *((uint64_t *)(entry + 4)); if (length64 == 0) break; - + uint64_t offset = *((uint64_t *)(entry + 12)); if (offset != 0) { @@ -803,7 +804,7 @@ static int CaptureStackTrace(int max_frames, void **out_frames) #elif defined(WIN32) // JIT isn't supported here, so just do nothing. - return 0;//return RtlCaptureStackBackTrace(0, MIN(max_frames, 32), out_frames, nullptr); + return 0;//return RtlCaptureStackBackTrace(0, min(max_frames, 32), out_frames, nullptr); #else return backtrace(out_frames, max_frames); #endif @@ -813,8 +814,16 @@ static int CaptureStackTrace(int max_frames, void **out_frames) class NativeSymbolResolver { public: - NativeSymbolResolver() { SymInitialize(GetCurrentProcess(), nullptr, TRUE); } - ~NativeSymbolResolver() { SymCleanup(GetCurrentProcess()); } + NativeSymbolResolver() + { + SymInitialize(GetCurrentProcess(), nullptr, TRUE); + GetModuleInformation(GetCurrentProcess(), GetModuleHandle(0), &moduleInfo, sizeof(MODULEINFO)); + } + + ~NativeSymbolResolver() + { + SymCleanup(GetCurrentProcess()); + } FString GetName(void *frame) { @@ -830,11 +839,14 @@ class NativeSymbolResolver BOOL result = SymGetSymFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, symbol64); if (result) { + if ((DWORD64)frame < (DWORD64)moduleInfo.lpBaseOfDll || (DWORD64)frame >= ((DWORD64)moduleInfo.lpBaseOfDll + moduleInfo.SizeOfImage)) + return s; // Ignore anything not from the exe itself + IMAGEHLP_LINE64 line64; - DWORD displacement = 0; + DWORD displacement1 = 0; memset(&line64, 0, sizeof(IMAGEHLP_LINE64)); line64.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - result = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, &line64); + result = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement1, &line64); if (result) { s.Format("Called from %s at %s, line %d\n", symbol64->Name, line64.FileName, (int)line64.LineNumber); @@ -847,6 +859,8 @@ class NativeSymbolResolver return s; } + + MODULEINFO moduleInfo = {}; }; #else class NativeSymbolResolver @@ -952,7 +966,7 @@ FString JitGetStackFrameName(NativeSymbolResolver *nativeSymbols, void *pc) return nativeSymbols ? nativeSymbols->GetName(pc) : FString(); } -FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames) +FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames) { void *frames[32]; int numframes = CaptureStackTrace(32, frames); @@ -961,10 +975,18 @@ FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames) if (includeNativeFrames) nativeSymbols.reset(new NativeSymbolResolver()); + int total = 0; FString s; for (int i = framesToSkip + 1; i < numframes; i++) { - s += JitGetStackFrameName(nativeSymbols.get(), frames[i]); + FString name = JitGetStackFrameName(nativeSymbols.get(), frames[i]); + if (!name.IsEmpty()) + { + s += name; + total++; + if (maxFrames != -1 && maxFrames == total) + break; + } } return s; } diff --git a/src/common/scripting/jit/jit_store.cpp b/src/common/scripting/jit/jit_store.cpp new file mode 100644 index 00000000000..49464691e63 --- /dev/null +++ b/src/common/scripting/jit/jit_store.cpp @@ -0,0 +1,292 @@ + +#include "jitintern.h" + +void JitCompiler::EmitSB() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::byte_ptr(regA[A], konstd[C]), regD[B].r8Lo()); +} + +void JitCompiler::EmitSB_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::byte_ptr(regA[A], regD[C]), regD[B].r8Lo()); +} + +void JitCompiler::EmitSH() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::word_ptr(regA[A], konstd[C]), regD[B].r16()); +} + +void JitCompiler::EmitSH_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::word_ptr(regA[A], regD[C]), regD[B].r16()); +} + +void JitCompiler::EmitSW() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::dword_ptr(regA[A], konstd[C]), regD[B]); +} + +void JitCompiler::EmitSW_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::dword_ptr(regA[A], regD[C]), regD[B]); +} + +void JitCompiler::EmitSSP() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempXmmSd(); + cc.xorpd(tmp, tmp); + cc.cvtsd2ss(tmp, regF[B]); + cc.movss(asmjit::x86::dword_ptr(regA[A], konstd[C]), tmp); +} + +void JitCompiler::EmitSSP_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempXmmSd(); + cc.xorpd(tmp, tmp); + cc.cvtsd2ss(tmp, regF[B]); + cc.movss(asmjit::x86::dword_ptr(regA[A], regD[C]), tmp); +} + +void JitCompiler::EmitSDP() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.movsd(asmjit::x86::qword_ptr(regA[A], konstd[C]), regF[B]); +} + +void JitCompiler::EmitSDP_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.movsd(asmjit::x86::qword_ptr(regA[A], regD[C]), regF[B]); +} + +void JitCompiler::EmitSS() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto ptr = newTempIntPtr(); + cc.lea(ptr, asmjit::x86::ptr(regA[A], konstd[C])); + auto call = CreateCall(&JitCompiler::CallAssignString); + call->setArg(0, ptr); + call->setArg(1, regS[B]); +} + +void JitCompiler::EmitSS_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto ptr = newTempIntPtr(); + cc.lea(ptr, asmjit::x86::ptr(regA[A], regD[C])); + auto call = CreateCall(&JitCompiler::CallAssignString); + call->setArg(0, ptr); + call->setArg(1, regS[B]); +} + +void JitCompiler::EmitSO() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::ptr(regA[A], konstd[C]), regA[B]); + + typedef void(*FuncPtr)(DObject*); + auto call = CreateCall(static_cast(GC::WriteBarrier)); + call->setArg(0, regA[B]); +} + +void JitCompiler::EmitSO_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::ptr(regA[A], regD[C]), regA[B]); + + typedef void(*FuncPtr)(DObject*); + auto call = CreateCall(static_cast(GC::WriteBarrier)); + call->setArg(0, regA[B]); +} + +void JitCompiler::EmitSP() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::ptr(regA[A], konstd[C]), regA[B]); +} + +void JitCompiler::EmitSP_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + cc.mov(asmjit::x86::ptr(regA[A], regD[C]), regA[B]); +} + +void JitCompiler::EmitSV2() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, konstd[C]); + cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); +} + +void JitCompiler::EmitSV2_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, regD[C]); + cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); +} + +void JitCompiler::EmitSV3() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, konstd[C]); + cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 16), regF[B + 2]); +} + +void JitCompiler::EmitSV3_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, regD[C]); + cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 16), regF[B + 2]); +} + +void JitCompiler::EmitSV4() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, konstd[C]); + cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 16), regF[B + 2]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 24), regF[B + 3]); +} + +void JitCompiler::EmitSV4_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, regD[C]); + cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 16), regF[B + 2]); + cc.movsd(asmjit::x86::qword_ptr(tmp, 24), regF[B + 3]); +} + +void JitCompiler::EmitSFV2() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, konstd[C]); + + auto tmpF = newTempXmmSs(); + cc.cvtsd2ss(tmpF, regF[B]); + cc.movss(asmjit::x86::qword_ptr(tmp), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 1]); + cc.movss(asmjit::x86::qword_ptr(tmp, 4), tmpF); +} + +void JitCompiler::EmitSFV2_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, regD[C]); + + auto tmpF = newTempXmmSs(); + cc.cvtsd2ss(tmpF, regF[B]); + cc.movss(asmjit::x86::qword_ptr(tmp), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 1]); + cc.movss(asmjit::x86::qword_ptr(tmp, 4), tmpF); +} + +void JitCompiler::EmitSFV3() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, konstd[C]); + auto tmpF = newTempXmmSs(); + cc.cvtsd2ss(tmpF, regF[B]); + cc.movss(asmjit::x86::qword_ptr(tmp), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 1]); + cc.movss(asmjit::x86::qword_ptr(tmp, 4), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 2]); + cc.movss(asmjit::x86::qword_ptr(tmp, 8), tmpF); +} + +void JitCompiler::EmitSFV3_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, regD[C]); + auto tmpF = newTempXmmSs(); + cc.cvtsd2ss(tmpF, regF[B]); + cc.movss(asmjit::x86::qword_ptr(tmp), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 1]); + cc.movss(asmjit::x86::qword_ptr(tmp, 4), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 2]); + cc.movss(asmjit::x86::qword_ptr(tmp, 8), tmpF); +} + +void JitCompiler::EmitSFV4() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, konstd[C]); + auto tmpF = newTempXmmSs(); + cc.cvtsd2ss(tmpF, regF[B]); + cc.movss(asmjit::x86::qword_ptr(tmp), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 1]); + cc.movss(asmjit::x86::qword_ptr(tmp, 4), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 2]); + cc.movss(asmjit::x86::qword_ptr(tmp, 8), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 3]); + cc.movss(asmjit::x86::qword_ptr(tmp, 12), tmpF); +} + +void JitCompiler::EmitSFV4_R() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp = newTempIntPtr(); + cc.mov(tmp, regA[A]); + cc.add(tmp, regD[C]); + auto tmpF = newTempXmmSs(); + cc.cvtsd2ss(tmpF, regF[B]); + cc.movss(asmjit::x86::qword_ptr(tmp), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 1]); + cc.movss(asmjit::x86::qword_ptr(tmp, 4), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 2]); + cc.movss(asmjit::x86::qword_ptr(tmp, 8), tmpF); + cc.cvtsd2ss(tmpF, regF[B + 3]); + cc.movss(asmjit::x86::qword_ptr(tmp, 12), tmpF); +} + +void JitCompiler::EmitSBIT() +{ + EmitNullPointerThrow(A, X_WRITE_NIL); + auto tmp1 = newTempInt32(); + auto tmp2 = newTempInt32(); + cc.mov(tmp1, asmjit::x86::byte_ptr(regA[A])); + cc.mov(tmp2, tmp1); + cc.or_(tmp1, (int)C); + cc.and_(tmp2, ~(int)C); + cc.test(regD[B], regD[B]); + cc.cmove(tmp1, tmp2); + cc.mov(asmjit::x86::byte_ptr(regA[A]), tmp1); +} diff --git a/src/scripting/vm/jitintern.h b/src/common/scripting/jit/jitintern.h similarity index 87% rename from src/scripting/vm/jitintern.h rename to src/common/scripting/jit/jitintern.h index ac3d8acf567..05dfd62dfcc 100644 --- a/src/scripting/vm/jitintern.h +++ b/src/common/scripting/jit/jitintern.h @@ -1,4 +1,4 @@ - +#pragma once #include "jit.h" #include "types.h" @@ -186,7 +186,13 @@ class JitCompiler asmjit::CCFuncCall *CreateCall(RetType(*func)(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)) { return cc.call(asmjit::imm_ptr(reinterpret_cast(static_cast(func))), asmjit::FuncSignature6()); } template - asmjit::CCFuncCall *CreateCall(RetType(*func)(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7)) { return cc.call(asmjit::imm_ptr(reinterpret_cast(static_cast(func))), asmjit::FuncSignature7()); } + asmjit::CCFuncCall* CreateCall(RetType(*func)(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7)) { return cc.call(asmjit::imm_ptr(reinterpret_cast(static_cast(func))), asmjit::FuncSignature7()); } + + template + asmjit::CCFuncCall* CreateCall(RetType(*func)(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)) { return cc.call(asmjit::imm_ptr(reinterpret_cast(static_cast(func))), asmjit::FuncSignature8()); } + + template + asmjit::CCFuncCall* CreateCall(RetType(*func)(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9)) { return cc.call(asmjit::imm_ptr(reinterpret_cast(static_cast(func))), asmjit::FuncSignature9()); } FString regname; size_t tmpPosInt32, tmpPosInt64, tmpPosIntPtr, tmpPosXmmSd, tmpPosXmmSs, tmpPosXmmPd, resultPosInt32, resultPosIntPtr, resultPosXmmSd; @@ -241,6 +247,7 @@ class JitCompiler asmjit::X86Xmm CheckRegF(int r0, int r1); asmjit::X86Xmm CheckRegF(int r0, int r1, int r2); asmjit::X86Xmm CheckRegF(int r0, int r1, int r2, int r3); + asmjit::X86Xmm CheckRegF(int r0, int r1, int r2, int r3, int r4); asmjit::X86Gp CheckRegS(int r0, int r1); asmjit::X86Gp CheckRegA(int r0, int r1); @@ -304,6 +311,19 @@ class JitCompiler TArray labels; + // Get temporary storage enough for DVector4 which is required by operation such as MULQQ and MULQV3 + bool vectorStackAllocated = false; + asmjit::X86Mem vectorStack; + asmjit::X86Mem GetTemporaryVectorStackStorage() + { + if (!vectorStackAllocated) + { + vectorStack = cc.newStack(sizeof(DVector4), alignof(DVector4), "tmpDVector4"); + vectorStackAllocated = true; + } + return vectorStack; + } + const VMOP *pc; VM_UBYTE op; }; diff --git a/src/scripting/vm/vm.h b/src/common/scripting/vm/vm.h similarity index 85% rename from src/scripting/vm/vm.h rename to src/common/scripting/vm/vm.h index db55dce43c9..2b7344d5dc1 100644 --- a/src/scripting/vm/vm.h +++ b/src/common/scripting/vm/vm.h @@ -39,10 +39,13 @@ #include "autosegs.h" #include "zstring.h" #include "vectors.h" +#include "quaternion.h" #include "cmdlib.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "memarena.h" -#include "scripting/backend/scopebarrier.h" +#include "name.h" +#include "scopebarrier.h" +#include class DObject; union VMOP; @@ -55,6 +58,8 @@ extern FMemArena ClassDataAllocator; void JitRelease(); +extern void (*VM_CastSpriteIDToString)(FString* a, unsigned int b); + typedef unsigned char VM_UBYTE; typedef signed char VM_SBYTE; @@ -77,8 +82,9 @@ enum REGT_KONST = 4, REGT_MULTIREG2 = 8, REGT_MULTIREG3 = 16, // (e.g. a vector) - REGT_MULTIREG = 24, + REGT_MULTIREG = 8 | 16 | 64, REGT_ADDROF = 32, // used with PARAM: pass address of this register + REGT_MULTIREG4 = 64, REGT_NIL = 128 // parameter was omitted }; @@ -98,7 +104,7 @@ enum EVMAbortException X_FORMAT_ERROR }; -class CVMAbortException : public CDoomError +class CVMAbortException : public CEngineError { public: static FString stacktrace; @@ -107,8 +113,8 @@ class CVMAbortException : public CDoomError }; // This must be a separate function because the VC compiler would otherwise allocate memory on the stack for every separate instance of the exception object that may get thrown. -void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...); -void ThrowAbortException(VMScriptFunction *sfunc, VMOP *line, EVMAbortException reason, const char *moreinfo, ...); +[[noreturn]] void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...); +[[noreturn]] void ThrowAbortException(VMScriptFunction *sfunc, VMOP *line, EVMAbortException reason, const char *moreinfo, ...); void ClearGlobalVMStack(); @@ -127,8 +133,32 @@ struct VMReturn assert(RegType == REGT_FLOAT); *(double *)Location = val; } + void SetVector4(const double val[4]) + { + assert(RegType == (REGT_FLOAT|REGT_MULTIREG4)); + ((double *)Location)[0] = val[0]; + ((double *)Location)[1] = val[1]; + ((double *)Location)[2] = val[2]; + ((double *)Location)[3] = val[3]; + } + void SetVector4(const DVector4 &val) + { + assert(RegType == (REGT_FLOAT | REGT_MULTIREG4)); + ((double *)Location)[0] = val[0]; + ((double *)Location)[1] = val[1]; + ((double *)Location)[2] = val[2]; + ((double *)Location)[3] = val[3]; + } + void SetQuaternion(const DQuaternion &val) + { + assert(RegType == (REGT_FLOAT | REGT_MULTIREG4)); + ((double *)Location)[0] = val[0]; + ((double *)Location)[1] = val[1]; + ((double *)Location)[2] = val[2]; + ((double *)Location)[3] = val[3]; + } void SetVector(const double val[3]) - { + { assert(RegType == (REGT_FLOAT|REGT_MULTIREG3)); ((double *)Location)[0] = val[0]; ((double *)Location)[1] = val[1]; @@ -165,6 +195,12 @@ struct VMReturn *(void **)Location = val; } + void SetConstPointer(const void *val) + { + assert(RegType == REGT_POINTER); + *(const void **)Location = val; + } + void SetObject(DObject *val) { assert(RegType == REGT_POINTER); @@ -186,6 +222,11 @@ struct VMReturn Location = loc; RegType = REGT_FLOAT | REGT_MULTIREG2; } + void Vec3At(DVector3 *loc) + { + Location = loc; + RegType = REGT_FLOAT | REGT_MULTIREG3; + } void StringAt(FString *loc) { Location = loc; @@ -200,6 +241,7 @@ struct VMReturn VMReturn(int *loc) { IntAt(loc); } VMReturn(double *loc) { FloatAt(loc); } VMReturn(DVector2 *loc) { Vec2At(loc); } + VMReturn(DVector3 *loc) { Vec3At(loc); } VMReturn(FString *loc) { StringAt(loc); } VMReturn(void **loc) { PointerAt(loc); } }; @@ -312,6 +354,10 @@ struct VMValue { i = v; } + VMValue(unsigned int v) + { + i = v; + } VMValue(double v) { f = v; @@ -405,7 +451,8 @@ class VMFunction FName Name; const uint8_t *RegTypes = nullptr; TArray DefaultArgs; - FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. + const char* QualifiedName = nullptr; + const char* PrintableName = nullptr; // same as QualifiedName, but can have additional annotations. class PPrototype *Proto; TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes @@ -489,6 +536,7 @@ inline int VMCallAction(VMFunction *func, VMValue *params, int numparams, VMRetu // Use these to collect the parameters in a native function. // variable name at position

+[[noreturn]] void NullParam(const char *varname); #ifndef NDEBUG @@ -505,10 +553,11 @@ bool AssertObject(void * ob); #define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); unsigned x = param[p].i; #define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); bool x = !!param[p].i; #define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FName x = ENamedName(param[p].i); -#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FSoundID x = param[p].i; -#define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); PalEntry x; x.d = param[p].i; +#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FSoundID x = FSoundID::fromInt(param[p].i); +#define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); PalEntry x = param[p].i; #define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_FLOAT); double x = param[p].f; -#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_FLOAT); DAngle x = param[p].f; +#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_FLOAT); DAngle x = DAngle::fromDeg(param[p].f); +#define PARAM_FANGLE_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_FLOAT); FAngle x = FAngle::fromDeg(param[p].f); #define PARAM_STRING_VAL_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_STRING); FString x = param[p].s(); #define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_STRING); const FString &x = param[p].s(); #define PARAM_STATELABEL_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); int x = param[p].i; @@ -535,6 +584,7 @@ bool AssertObject(void * ob); #define PARAM_COLOR(x) ++paramnum; PARAM_COLOR_AT(paramnum,x) #define PARAM_FLOAT(x) ++paramnum; PARAM_FLOAT_AT(paramnum,x) #define PARAM_ANGLE(x) ++paramnum; PARAM_ANGLE_AT(paramnum,x) +#define PARAM_FANGLE(x) ++paramnum; PARAM_FANGLE_AT(paramnum,x) #define PARAM_STRING(x) ++paramnum; PARAM_STRING_AT(paramnum,x) #define PARAM_STRING_VAL(x) ++paramnum; PARAM_STRING_VAL_AT(paramnum,x) #define PARAM_STATELABEL(x) ++paramnum; PARAM_STATELABEL_AT(paramnum,x) @@ -569,6 +619,8 @@ namespace template struct native_is_valid { static const bool value = true; static const bool retval = true; }; template<> struct native_is_valid { static const bool value = true; static const bool retval = true; }; template<> struct native_is_valid { static const bool value = true; static const bool retval = true; }; + // [RL0] this is disabled for now due to graf's concerns + // template<> struct native_is_valid { static const bool value = true; static const bool retval = true; static_assert(sizeof(FName) == sizeof(int)); static_assert(std::is_pod_v);}; template<> struct native_is_valid { static const bool value = true; static const bool retval = true; }; template<> struct native_is_valid { static const bool value = true; static const bool retval = true; }; template<> struct native_is_valid { static const bool value = true; static const bool retval = false;}; // Bool as return does not work! @@ -579,25 +631,7 @@ struct DirectNativeDesc { DirectNativeDesc() = default; - #define TP(n) typename P##n - #define VP(n) ValidateType() - template DirectNativeDesc(Ret(*func)()) : Ptr(reinterpret_cast(func)) { ValidateRet(); } - template DirectNativeDesc(Ret(*func)(P1)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); } - template DirectNativeDesc(Ret(*func)(P1,P2)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); } - template DirectNativeDesc(Ret(*func)(P1,P2,P3)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); VP(13); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); VP(13), VP(14); } - #undef TP - #undef VP + template DirectNativeDesc(Ret(*func)(Params...)) : Ptr(reinterpret_cast(func)) { ValidateRet(); (ValidateType(), ...); } template void ValidateType() { static_assert(native_is_valid::value, "Argument type is not valid as a direct native parameter or return type"); } template void ValidateRet() { static_assert(native_is_valid::retval, "Return type is not valid as a direct native parameter or return type"); } @@ -617,11 +651,11 @@ struct AFuncDesc }; #if defined(_MSC_VER) -#pragma section(".areg$u",read) -#pragma section(".freg$u",read) +#pragma section(SECTION_AREG,read) +#pragma section(SECTION_FREG,read) -#define MSVC_ASEG __declspec(allocate(".areg$u")) -#define MSVC_FSEG __declspec(allocate(".freg$u")) +#define MSVC_ASEG __declspec(allocate(SECTION_AREG)) +#define MSVC_FSEG __declspec(allocate(SECTION_FREG)) #define GCC_ASEG #define GCC_FSEG #else @@ -690,6 +724,11 @@ struct AFuncDesc extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; +#define DEFINE_FIELD_NAMED_UNSIZED(cls, name, scriptname) \ + static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), ~0u, 0 }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; + #define DEFINE_FIELD_BIT(cls, name, scriptname, bitval) \ static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), bitval }; \ extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ @@ -705,15 +744,25 @@ struct AFuncDesc extern FieldDesc const *const VMGlobal_##name##_HookPtr; \ MSVC_FSEG FieldDesc const *const VMGlobal_##name##_HookPtr GCC_FSEG = &VMGlobal_##name; +#define DEFINE_GLOBAL_UNSIZED(name) \ + static const FieldDesc VMGlobal_##name = { "", #name, (size_t)&name, ~0u, 0 }; \ + extern FieldDesc const *const VMGlobal_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMGlobal_##name##_HookPtr GCC_FSEG = &VMGlobal_##name; + + + class AActor; #define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state); return 1; } return 0; } while(0) +#define ACTION_RETURN_CONST_POINTER(v) do { const void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetConstPointer(state); return 1; } return 0; } while(0) #define ACTION_RETURN_POINTER(v) do { void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state); return 1; } return 0; } while(0) #define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetObject(state); return 1; } return 0; } while(0) #define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) #define ACTION_RETURN_VEC2(v) do { DVector2 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector2(u); return 1; } return 0; } while(0) #define ACTION_RETURN_VEC3(v) do { DVector3 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector(u); return 1; } return 0; } while(0) +#define ACTION_RETURN_VEC4(v) do { DVector4 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector4(u); return 1; } return 0; } while(0) +#define ACTION_RETURN_QUAT(v) do { DQuaternion u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetQuaternion(u); return 1; } return 0; } while(0) #define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0) #define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v) #define ACTION_RETURN_STRING(v) do { FString u = v; if (numret > 0) { assert(ret != NULL); ret->SetString(u); return 1; } return 0; } while(0) @@ -748,6 +797,7 @@ class AActor; class PFunction; VMFunction *FindVMFunction(PClass *cls, const char *name); +VMFunction* FindVMFunction(const char* name); #define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name); FString FStringFormat(VM_ARGS, int offset = 0); @@ -786,4 +836,16 @@ unsigned GetVirtualIndex(PClass *cls, const char *funcname); VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ if (func != nullptr) +#define IFOVERRIDENVIRTUALPTRNAME(self, clsname, funcname) \ + static VMFunction *orig_func = nullptr; \ + static unsigned VIndex = ~0u; \ + if (VIndex == ~0u) { \ + PClass *cls = PClass::FindClass(clsname); \ + VIndex = GetVirtualIndex(cls, #funcname); \ + orig_func = cls->Virtuals.Size() > VIndex? cls->Virtuals[VIndex] : nullptr; \ + assert(VIndex != ~0u); \ + } \ + auto *clss = self->GetClass(); \ + VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ + if (func && func != orig_func ) #endif diff --git a/src/scripting/vm/vmexec.cpp b/src/common/scripting/vm/vmexec.cpp similarity index 93% rename from src/scripting/vm/vmexec.cpp rename to src/common/scripting/vm/vmexec.cpp index 0d0e2125f90..7180cb1034e 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/common/scripting/vm/vmexec.cpp @@ -32,16 +32,24 @@ */ #include -#include -#include -#include "r_state.h" +#include +#include "v_video.h" +#include "s_soundinternal.h" +#include "basics.h" +//#include "r_state.h" #include "stats.h" #include "vmintern.h" #include "types.h" +#include "basics.h" +#include "texturemanager.h" +#include "palutil.h" extern cycle_t VMCycles[10]; extern int VMCalls[10]; +// THe sprite ID to string cast is game specific so let's do it with a callback to remove the dependency and allow easier reuse. +void (*VM_CastSpriteIDToString)(FString* a, unsigned int b) = [](FString* a, unsigned int b) { a->Format("%d", b); }; + // intentionally implemented in a different source file to prevent inlining. #if 0 void ThrowVMException(VMException *x); diff --git a/src/scripting/vm/vmexec.h b/src/common/scripting/vm/vmexec.h similarity index 83% rename from src/scripting/vm/vmexec.h rename to src/common/scripting/vm/vmexec.h index 08a398f9e91..0d5737d256e 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/common/scripting/vm/vmexec.h @@ -40,7 +40,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) { #if COMPGOTO - static const void * const ops[256] = + static void * const ops[256] = { #define xx(op,sym,mode,alt,kreg,ktype) &&op, #include "vmops.h" @@ -263,42 +263,124 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) GETADDR(PB,RC,X_READ_NIL); reg.a[a] = *(void **)ptr; NEXTOP; - OP(LV2): + OP(LV2) : + ASSERTF(a + 1); ASSERTA(B); ASSERTKD(C); + GETADDR(PB, KC, X_READ_NIL); + { + auto v = (double*)ptr; + reg.f[a] = v[0]; + reg.f[a + 1] = v[1]; + } + NEXTOP; + OP(LV2_R) : + ASSERTF(a + 1); ASSERTA(B); ASSERTD(C); + GETADDR(PB, RC, X_READ_NIL); + { + auto v = (double*)ptr; + reg.f[a] = v[0]; + reg.f[a + 1] = v[1]; + } + NEXTOP; + OP(LV3) : + ASSERTF(a + 2); ASSERTA(B); ASSERTKD(C); + GETADDR(PB, KC, X_READ_NIL); + { + auto v = (double*)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + reg.f[a+2] = v[2]; + } + NEXTOP; + OP(LV3_R) : + ASSERTF(a + 2); ASSERTA(B); ASSERTD(C); + GETADDR(PB, RC, X_READ_NIL); + { + auto v = (double*)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + reg.f[a+2] = v[2]; + } + NEXTOP; + OP(LV4) : + ASSERTF(a + 3); ASSERTA(B); ASSERTKD(C); + GETADDR(PB, KC, X_READ_NIL); + { + auto v = (double*)ptr; + reg.f[a] = v[0]; + reg.f[a + 1] = v[1]; + reg.f[a + 2] = v[2]; + reg.f[a + 3] = v[3]; + } + NEXTOP; + OP(LV4_R) : + ASSERTF(a + 3); ASSERTA(B); ASSERTD(C); + GETADDR(PB, RC, X_READ_NIL); + { + auto v = (double*)ptr; + reg.f[a] = v[0]; + reg.f[a + 1] = v[1]; + reg.f[a + 2] = v[2]; + reg.f[a + 3] = v[3]; + } + NEXTOP; + OP(LFV2): ASSERTF(a+1); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); { - auto v = (double *)ptr; + auto v = (float *)ptr; reg.f[a] = v[0]; reg.f[a+1] = v[1]; } NEXTOP; - OP(LV2_R): + OP(LFV2_R): ASSERTF(a+1); ASSERTA(B); ASSERTD(C); GETADDR(PB,RC,X_READ_NIL); { - auto v = (double *)ptr; + auto v = (float *)ptr; reg.f[a] = v[0]; reg.f[a+1] = v[1]; } NEXTOP; - OP(LV3): + OP(LFV3): ASSERTF(a+2); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); { - auto v = (double *)ptr; + auto v = (float *)ptr; reg.f[a] = v[0]; reg.f[a+1] = v[1]; reg.f[a+2] = v[2]; } NEXTOP; - OP(LV3_R): + OP(LFV3_R): ASSERTF(a+2); ASSERTA(B); ASSERTD(C); GETADDR(PB,RC,X_READ_NIL); { - auto v = (double *)ptr; + auto v = (float *)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + reg.f[a+2] = v[2]; + } + NEXTOP; + OP(LFV4) : + ASSERTF(a + 3); ASSERTA(B); ASSERTKD(C); + GETADDR(PB, KC, X_READ_NIL); + { + auto v = (float*)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + reg.f[a+2] = v[2]; + reg.f[a+3] = v[3]; + } + NEXTOP; + OP(LFV4_R) : + ASSERTF(a + 3); ASSERTA(B); ASSERTD(C); + GETADDR(PB, RC, X_READ_NIL); + { + auto v = (float*)ptr; reg.f[a] = v[0]; reg.f[a+1] = v[1]; reg.f[a+2] = v[2]; + reg.f[a+3] = v[3]; } NEXTOP; OP(LBIT): @@ -360,6 +442,10 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) OP(SS): ASSERTA(a); ASSERTS(B); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); +#ifdef _DEBUG + // Should never happen, if it does it indicates a compiler side problem. + if (((FString*)ptr)->GetChars() == nullptr) ThrowAbortException(X_OTHER, "Uninitialized string"); +#endif *(FString *)ptr = reg.s[B]; NEXTOP; OP(SS_R): @@ -426,6 +512,88 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) v[2] = reg.f[B+2]; } NEXTOP; + OP(SV4): + ASSERTA(a); ASSERTF(B+3); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + { + auto v = (double *)ptr; + v[0] = reg.f[B]; + v[1] = reg.f[B+1]; + v[2] = reg.f[B+2]; + v[3] = reg.f[B+3]; + } + NEXTOP; + OP(SV4_R): + ASSERTA(a); ASSERTF(B+3); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + { + auto v = (double *)ptr; + v[0] = reg.f[B]; + v[1] = reg.f[B+1]; + v[2] = reg.f[B+2]; + v[3] = reg.f[B+3]; + } + NEXTOP; + OP(SFV2): + ASSERTA(a); ASSERTF(B+1); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + { + auto v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + } + NEXTOP; + OP(SFV2_R): + ASSERTA(a); ASSERTF(B+1); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + { + auto v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + } + NEXTOP; + OP(SFV3): + ASSERTA(a); ASSERTF(B+2); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + { + auto v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + v[2] = (float)reg.f[B+2]; + } + NEXTOP; + OP(SFV3_R): + ASSERTA(a); ASSERTF(B+2); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + { + auto v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + v[2] = (float)reg.f[B+2]; + } + NEXTOP; + OP(SFV4): + ASSERTA(a); ASSERTF(B+3); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + { + auto v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + v[2] = (float)reg.f[B+2]; + v[3] = (float)reg.f[B+3]; + } + NEXTOP; + OP(SFV4_R): + ASSERTA(a); ASSERTF(B+3); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + { + auto v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + v[2] = (float)reg.f[B+2]; + v[3] = (float)reg.f[B+3]; + } + NEXTOP; OP(SBIT): ASSERTA(a); ASSERTD(B); GETADDR(PA,0,X_WRITE_NIL); @@ -475,6 +643,16 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) reg.f[a + 2] = reg.f[b + 2]; NEXTOP; } + OP(MOVEV4) : + { + ASSERTF(a); ASSERTF(B); + b = B; + reg.f[a] = reg.f[b]; + reg.f[a + 1] = reg.f[b + 1]; + reg.f[a + 2] = reg.f[b + 2]; + reg.f[a + 3] = reg.f[b + 3]; + NEXTOP; + } OP(DYNCAST_R) : ASSERTA(a); ASSERTA(B); ASSERTA(C); b = B; @@ -511,7 +689,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) DoCast(reg, f, a, B, C); } NEXTOP; - + OP(CASTB): if (C == CASTB_I) { @@ -534,7 +712,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) reg.d[a] = reg.s[B].Len() > 0; } NEXTOP; - + OP(TEST): ASSERTD(a); if (reg.d[a] != BC) @@ -633,10 +811,23 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) ::new(param + 2) VMValue(reg.f[b + 2]); f->NumParam += 2; break; + case REGT_FLOAT | REGT_MULTIREG4: + assert(b < f->NumRegF - 3); + assert(f->NumParam < sfunc->MaxParam - 2); + ::new(param) VMValue(reg.f[b]); + ::new(param + 1) VMValue(reg.f[b + 1]); + ::new(param + 2) VMValue(reg.f[b + 2]); + ::new(param + 3) VMValue(reg.f[b + 3]); + f->NumParam += 3; + break; case REGT_FLOAT | REGT_ADDROF: assert(b < f->NumRegF); ::new(param) VMValue(®.f[b]); break; + case REGT_FLOAT | REGT_MULTIREG2 | REGT_ADDROF: + case REGT_FLOAT | REGT_MULTIREG3 | REGT_ADDROF: + case REGT_FLOAT | REGT_MULTIREG4 | REGT_ADDROF: + I_Error("REGT_ADDROF not implemented for vectors\n"); case REGT_FLOAT | REGT_KONST: assert(b < sfunc->NumKonstF); ::new(param) VMValue(konstf[b]); @@ -658,6 +849,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) return 0; } auto p = o->GetClass(); + if(p->Virtuals.Size() <= 0) ThrowAbortException(X_OTHER,"Attempted to call an invalid virtual function in class %s",p->TypeName.GetChars()); assert(C < p->Virtuals.Size()); reg.a[a] = p->Virtuals[C]; } @@ -688,7 +880,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) { VMFunction *call = (VMFunction *)ptr; VMReturn returns[MAX_RETURNS]; - int numret; + int numret1; b = B; FillReturns(reg, f, returns, pc+1, C); @@ -697,23 +889,23 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) try { VMCycles[0].Unclock(); - numret = static_cast(call)->NativeCall(VM_INVOKE(reg.param + f->NumParam - b, b, returns, C, call->RegTypes)); + numret1 = static_cast(call)->NativeCall(VM_INVOKE(reg.param + f->NumParam - b, b, returns, C, call->RegTypes)); VMCycles[0].Clock(); } catch (CVMAbortException &err) { err.MaybePrintMessage(); - err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars()); + err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName); // PrintParameters(reg.param + f->NumParam - B, B); throw; } } else { - auto sfunc = static_cast(call); - numret = sfunc->ScriptCall(sfunc, reg.param + f->NumParam - b, b, returns, C); + auto sfunc1 = static_cast(call); + numret1 = sfunc1->ScriptCall(sfunc1, reg.param + f->NumParam - b, b, returns, C); } - assert(numret == C && "Number of parameters returned differs from what was expected by the caller"); + assert(numret1 == C && "Number of parameters returned differs from what was expected by the caller"); f->NumParam -= B; pc += C; // Skip RESULTs } @@ -802,7 +994,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) OP(BOUND): if (reg.d[a] >= BC) { - ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", BC, reg.d[a]); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Size = %u, current index = %u\n", BC, reg.d[a]); return 0; } else if (reg.d[a] < 0) @@ -816,7 +1008,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) ASSERTKD(BC); if (reg.d[a] >= konstd[BC]) { - ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", konstd[BC], reg.d[a]); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Size = %u, current index = %u\n", konstd[BC], reg.d[a]); return 0; } else if (reg.d[a] < 0) @@ -830,7 +1022,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) ASSERTD(B); if (reg.d[a] >= reg.d[B]) { - ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", reg.d[B], reg.d[a]); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Size = %u, current index = %u\n", reg.d[B], reg.d[a]); return 0; } else if (reg.d[a] < 0) @@ -848,37 +1040,37 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) ASSERTD(a); ASSERTS(B); reg.d[a] = (int)reg.s[B].Len(); NEXTOP; - + OP(CMPS): // String comparison is a fairly expensive operation, so I've // chosen to conserve a few opcodes by condensing all the // string comparisons into a single one. { - const FString *b, *c; + const FString *b1, *c1; int test, method; bool cmp; if (a & CMP_BK) { ASSERTKS(B); - b = &konsts[B]; + b1 = &konsts[B]; } else { ASSERTS(B); - b = ®.s[B]; + b1 = ®.s[B]; } if (a & CMP_CK) { ASSERTKS(C); - c = &konsts[C]; + c1 = &konsts[C]; } else { ASSERTS(C); - c = ®.s[C]; + c1 = ®.s[C]; } - test = (a & CMP_APPROX) ? b->CompareNoCase(*c) : b->Compare(*c); + test = (a & CMP_APPROX) ? b1->CompareNoCase(*c1) : b1->Compare(*c1); method = a & CMP_METHOD_MASK; if (method == CMP_EQ) { @@ -1298,12 +1490,10 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) ASSERTF(a); ASSERTF(B); ASSERTKF(C); fb = reg.f[B]; fc = konstf[C]; goto Do_MODF; - NEXTOP; OP(MODF_KR): ASSERTF(a); ASSERTKF(B); ASSERTF(C); fb = konstf[B]; fc = reg.f[C]; goto Do_MODF; - NEXTOP; OP(POWF_RR): ASSERTF(a); ASSERTF(B); ASSERTF(C); @@ -1345,7 +1535,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) fb = reg.f[B]; reg.f[a] = (C == FLOP_ABS) ? fabs(fb) : (C == FLOP_NEG) ? -fb : DoFLOP(C, fb); NEXTOP; - + OP(EQF_R): ASSERTF(B); ASSERTF(C); if (a & CMP_APPROX) @@ -1612,6 +1802,112 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) fcp = &konstf[C]; goto Do_EQV3; + OP(NEGV4): + ASSERTF(a+3); ASSERTF(B+3); + reg.f[a] = -reg.f[B]; + reg.f[a+1] = -reg.f[B+1]; + reg.f[a+2] = -reg.f[B+2]; + reg.f[a+3] = -reg.f[B+3]; + NEXTOP; + + OP(ADDV4_RR): + ASSERTF(a+3); ASSERTF(B+3); ASSERTF(C+3); + fcp = ®.f[C]; + fbp = ®.f[B]; + reg.f[a] = fbp[0] + fcp[0]; + reg.f[a+1] = fbp[1] + fcp[1]; + reg.f[a+2] = fbp[2] + fcp[2]; + reg.f[a+3] = fbp[3] + fcp[3]; + NEXTOP; + + OP(SUBV4_RR): + ASSERTF(a+3); ASSERTF(B+3); ASSERTF(C+3); + fbp = ®.f[B]; + fcp = ®.f[C]; + reg.f[a] = fbp[0] - fcp[0]; + reg.f[a+1] = fbp[1] - fcp[1]; + reg.f[a+2] = fbp[2] - fcp[2]; + reg.f[a+3] = fbp[3] - fcp[3]; + NEXTOP; + + OP(DOTV4_RR): + ASSERTF(a); ASSERTF(B+3); ASSERTF(C+3); + reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1] + reg.f[B+2] * reg.f[C+2] + reg.f[B+3] * reg.f[C+3]; + NEXTOP; + + OP(MULVF4_RR): + ASSERTF(a+3); ASSERTF(B+3); ASSERTF(C); + fc = reg.f[C]; + fbp = ®.f[B]; + Do_MULV4: + reg.f[a] = fbp[0] * fc; + reg.f[a+1] = fbp[1] * fc; + reg.f[a+2] = fbp[2] * fc; + reg.f[a+3] = fbp[3] * fc; + NEXTOP; + OP(MULVF4_RK): + ASSERTF(a+3); ASSERTF(B+3); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_MULV4; + + OP(DIVVF4_RR): + ASSERTF(a+3); ASSERTF(B+3); ASSERTF(C); + fc = reg.f[C]; + fbp = ®.f[B]; + Do_DIVV4: + reg.f[a] = fbp[0] / fc; + reg.f[a+1] = fbp[1] / fc; + reg.f[a+2] = fbp[2] / fc; + reg.f[a+3] = fbp[3] / fc; + NEXTOP; + OP(DIVVF4_RK): + ASSERTF(a+3); ASSERTF(B+3); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_DIVV4; + + OP(LENV4): + ASSERTF(a); ASSERTF(B+3); + reg.f[a] = g_sqrt(reg.f[B] * reg.f[B] + reg.f[B+1] * reg.f[B+1] + reg.f[B+2] * reg.f[B+2]+ reg.f[B+3] * reg.f[B+3]); + NEXTOP; + + OP(EQV4_R): + ASSERTF(B+3); ASSERTF(C+3); + fcp = ®.f[C]; + Do_EQV4: + if (a & CMP_APPROX) + { + CMPJMP(fabs(reg.f[B ] - fcp[0]) < VM_EPSILON && + fabs(reg.f[B+1] - fcp[1]) < VM_EPSILON && + fabs(reg.f[B+2] - fcp[2]) < VM_EPSILON && + fabs(reg.f[B+3] - fcp[3]) < VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] == fcp[0] && reg.f[B+1] == fcp[1] && reg.f[B+2] == fcp[2] && reg.f[B+3] == fcp[3]); + } + NEXTOP; + OP(EQV4_K): + ASSERTF(B+3); ASSERTKF(C+3); + fcp = &konstf[C]; + goto Do_EQV4; + OP(MULQV3_RR): + ASSERTF(a + 2); ASSERTF(B + 3); ASSERTF(C + 2); + { + const DQuaternion& q = reinterpret_cast(reg.f[B]); + const DVector3& v = reinterpret_cast(reg.f[C]); + reinterpret_cast(reg.f[A]) = q * v; + } + NEXTOP; + OP(MULQQ_RR): + ASSERTF(a + 3); ASSERTF(B + 3); ASSERTF(C + 3); + { + const DQuaternion& q1 = reinterpret_cast(reg.f[B]); + const DQuaternion& q2 = reinterpret_cast(reg.f[C]); + reinterpret_cast(reg.f[A]) = q1 * q2; + } + NEXTOP; OP(ADDA_RR): ASSERTA(a); ASSERTA(B); ASSERTD(C); c = reg.d[C]; @@ -1641,6 +1937,15 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) CMPJMP(reg.a[B] == konsta[C].v); NEXTOP; + OP(NULLCHECK): + ASSERTA(a); + if (PA == nullptr) + { + ThrowAbortException(X_WRITE_NIL, nullptr); + return 0; + } + NEXTOP; + OP(NOP): NEXTOP; } @@ -1704,11 +2009,10 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) catch (CVMAbortException &err) { err.MaybePrintMessage(); - err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(pc)); + err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName, sfunc->SourceFileName.GetChars(), sfunc->PCToLine(pc)); // PrintParameters(reg.param + f->NumParam - B, B); throw; } - return 0; } static double DoFLOP(int flop, double v) @@ -1809,7 +2113,7 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c case CAST_S2N: ASSERTD(a); ASSERTS(b); - reg.d[a] = reg.s[b].Len() == 0? FName(NAME_None) : FName(reg.s[b]); + reg.d[a] = reg.s[b].Len() == 0? NAME_None : FName(reg.s[b]).GetIndex(); break; case CAST_N2S: @@ -1822,7 +2126,7 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c case CAST_S2Co: ASSERTD(a); ASSERTS(b); - reg.d[a] = V_GetColor(NULL, reg.s[b]); + reg.d[a] = V_GetColor(reg.s[b].GetChars()); break; case CAST_Co2S: @@ -1832,23 +2136,23 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c case CAST_S2So: ASSERTD(a); ASSERTS(b); - reg.d[a] = FSoundID(reg.s[b]); + reg.d[a] = S_FindSound(reg.s[b]).index(); break; case CAST_So2S: ASSERTS(a); ASSERTD(b); - reg.s[a] = S_GetSoundName(reg.d[b]); + reg.s[a] = soundEngine->GetSoundName(FSoundID::fromInt(reg.d[b])); break; case CAST_SID2S: ASSERTS(a); ASSERTD(b); - reg.s[a] = unsigned(reg.d[b]) >= sprites.Size() ? "TNT1" : sprites[reg.d[b]].name; + VM_CastSpriteIDToString(®.s[a], reg.d[b]); break; case CAST_TID2S: { ASSERTS(a); ASSERTD(b); - auto tex = TexMan.GetTexture(*(FTextureID*)&(reg.d[b])); + auto tex = TexMan.GetGameTexture(*(FTextureID*)&(reg.d[b])); reg.s[a] = tex == nullptr ? "(null)" : tex->GetName().GetChars(); break; } @@ -1951,7 +2255,11 @@ static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_ assert(regnum < frame->NumRegF); src = ®.f[regnum]; } - if (regtype & REGT_MULTIREG3) + if (regtype & REGT_MULTIREG4) + { + ret->SetVector4((double*)src); + } + else if (regtype & REGT_MULTIREG3) { ret->SetVector((double *)src); } diff --git a/src/scripting/vm/vmframe.cpp b/src/common/scripting/vm/vmframe.cpp similarity index 90% rename from src/scripting/vm/vmframe.cpp rename to src/common/scripting/vm/vmframe.cpp index 7c2a63b1f71..f69b8ea6160 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/common/scripting/vm/vmframe.cpp @@ -37,7 +37,7 @@ #include "v_text.h" #include "stats.h" #include "c_dispatch.h" -#include "templates.h" + #include "vmintern.h" #include "types.h" #include "jit.h" @@ -45,14 +45,24 @@ #include "version.h" #ifdef HAVE_VM_JIT +#ifdef __DragonFly__ +CUSTOM_CVAR(Bool, vm_jit, false, CVAR_NOINITCALL) +#else CUSTOM_CVAR(Bool, vm_jit, true, CVAR_NOINITCALL) +#endif +{ + Printf("You must restart " GAMENAME " for this change to take effect.\n"); + Printf("This cvar is currently not saved. You must specify it on the command line."); +} +CUSTOM_CVAR(Bool, vm_jit_aot, true, CVAR_NOINITCALL) { Printf("You must restart " GAMENAME " for this change to take effect.\n"); Printf("This cvar is currently not saved. You must specify it on the command line."); } #else CVAR(Bool, vm_jit, false, CVAR_NOINITCALL|CVAR_NOSET) -FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames) { return FString(); } +CVAR(Bool, vm_jit_aot, false, CVAR_NOINITCALL|CVAR_NOSET) +FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames) { return FString(); } void JitRelease() {} #endif @@ -75,8 +85,8 @@ void VMFunction::CreateRegUse() int count = 0; if (!Proto) { - if (RegTypes) return; - Printf(TEXTCOLOR_ORANGE "Function without prototype needs register info manually set: %s\n", PrintableName.GetChars()); + //if (RegTypes) return; + //Printf(TEXTCOLOR_ORANGE "Function without prototype needs register info manually set: %s\n", PrintableName); return; } assert(Proto->isPrototype()); @@ -269,29 +279,47 @@ static bool CanJit(VMScriptFunction *func) // Asmjit has a 256 register limit. Stay safely away from it as the jit compiler uses a few for temporaries as well. // Any function exceeding the limit will use the VM - a fair punishment to someone for writing a function so bloated ;) + if(func->blockJit) return false; + int maxregs = 200; if (func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS < maxregs) return true; - Printf(TEXTCOLOR_ORANGE "%s is using too many registers (%d of max %d)! Function will not use native code.\n", func->PrintableName.GetChars(), func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS, maxregs); + Printf(TEXTCOLOR_ORANGE "%s is using too many registers (%d of max %d)! Function will not use native code.\n", func->PrintableName, func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS, maxregs); return false; } -int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) +void VMScriptFunction::JitCompile() { -#ifdef HAVE_VM_JIT - if (vm_jit && CanJit(static_cast(func))) + if(!(VarFlags & VARF_Abstract)) { - func->ScriptCall = JitCompile(static_cast(func)); - if (!func->ScriptCall) - func->ScriptCall = VMExec; + #ifdef HAVE_VM_JIT + if (vm_jit && CanJit(this)) + { + ScriptCall = ::JitCompile(this); + if (!ScriptCall) + ScriptCall = VMExec; + } + else + #endif // HAVE_VM_JIT + { + ScriptCall = VMExec; + } } - else -#endif // HAVE_VM_JIT +} + +int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) +{ + // [Player701] Check that we aren't trying to call an abstract function. + // This shouldn't happen normally, but if it does, let's catch this explicitly + // rather than let GZDoom crash. + if (func->VarFlags & VARF_Abstract) { - func->ScriptCall = VMExec; + ThrowAbortException(X_OTHER, "attempt to call abstract function %s.", func->PrintableName); } + + static_cast(func)->JitCompile(); return func->ScriptCall(func, params, numparams, ret, numret); } @@ -309,7 +337,7 @@ int VMNativeFunction::NativeScriptCall(VMFunction *func, VMValue *params, int nu catch (CVMAbortException &err) { err.MaybePrintMessage(); - err.stacktrace.AppendFormat("Called from %s\n", func->PrintableName.GetChars()); + err.stacktrace.AppendFormat("Called from %s\n", func->PrintableName); throw; } } @@ -650,7 +678,11 @@ CVMAbortException::CVMAbortException(EVMAbortException reason, const char *morei } if (moreinfo != nullptr) { - AppendMessage(" "); + // [Player701] avoid double space + if (reason != X_OTHER) + { + AppendMessage(" "); + } size_t len = strlen(m_Message); myvsnprintf(m_Message + len, MAX_ERRORTEXT - len, moreinfo, ap); } @@ -667,31 +699,28 @@ void CVMAbortException::MaybePrintMessage() auto m = GetMessage(); if (m != nullptr) { - Printf(TEXTCOLOR_RED); - Printf("%s\n", m); + Printf(PRINT_NONOTIFY | PRINT_BOLD, TEXTCOLOR_RED "%s\n", m); SetMessage(""); } } -void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...) +[[noreturn]] void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...) { va_list ap; va_start(ap, moreinfo); throw CVMAbortException(reason, moreinfo, ap); - va_end(ap); } -void ThrowAbortException(VMScriptFunction *sfunc, VMOP *line, EVMAbortException reason, const char *moreinfo, ...) +[[noreturn]] void ThrowAbortException(VMScriptFunction *sfunc, VMOP *line, EVMAbortException reason, const char *moreinfo, ...) { va_list ap; va_start(ap, moreinfo); CVMAbortException err(reason, moreinfo, ap); - err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(line)); + err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName, sfunc->SourceFileName.GetChars(), sfunc->PCToLine(line)); throw err; - va_end(ap); } DEFINE_ACTION_FUNCTION(DObject, ThrowAbortException) @@ -699,10 +728,9 @@ DEFINE_ACTION_FUNCTION(DObject, ThrowAbortException) PARAM_PROLOGUE; FString s = FStringFormat(VM_ARGS_NAMES); ThrowAbortException(X_OTHER, s.GetChars()); - return 0; } -void NullParam(const char *varname) +[[noreturn]] void NullParam(const char *varname) { ThrowAbortException(X_READ_NIL, "In function parameter %s", varname); } @@ -731,7 +759,7 @@ ADD_STAT(VM) for (auto d : VMCycles) { added += d.TimeMS(); - peak = MAX(peak, d.TimeMS()); + peak = max(peak, d.TimeMS()); } for (auto d : VMCalls) addedc += d; memmove(&VMCycles[1], &VMCycles[0], 9 * sizeof(cycle_t)); diff --git a/src/scripting/vm/vmintern.h b/src/common/scripting/vm/vmintern.h similarity index 98% rename from src/scripting/vm/vmintern.h rename to src/common/scripting/vm/vmintern.h index b93f3e6ef5d..b35eefc1e34 100644 --- a/src/scripting/vm/vmintern.h +++ b/src/common/scripting/vm/vmintern.h @@ -126,6 +126,7 @@ enum CAST_So2S, CAST_V22S, CAST_V32S, + CAST_V42S, CAST_SID2S, CAST_TID2S, @@ -473,6 +474,8 @@ class VMScriptFunction : public VMFunction VM_UBYTE NumArgs; // Number of arguments this function takes TArray SpecialInits; // list of all contents on the extra stack which require construction and destruction + bool blockJit = false; // function triggers Jit bugs, block compilation until bugs are fixed + void InitExtra(void *addr); void DestroyExtra(void *addr); int AllocExtraStack(PType *type); @@ -480,4 +483,6 @@ class VMScriptFunction : public VMFunction private: static int FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret); + void JitCompile(); + friend class FFunctionBuildList; }; diff --git a/src/scripting/vm/vmops.h b/src/common/scripting/vm/vmops.h similarity index 88% rename from src/scripting/vm/vmops.h rename to src/common/scripting/vm/vmops.h index 82b3cabc48b..9280b746c5d 100644 --- a/src/scripting/vm/vmops.h +++ b/src/common/scripting/vm/vmops.h @@ -51,8 +51,16 @@ xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT) // load vector2 xx(LV2_R, lv2, RVRPRI, NOP, 0, 0) xx(LV3, lv3, RVRPKI, LV3_R, 4, REGT_INT) // load vector3 xx(LV3_R, lv3, RVRPRI, NOP, 0, 0) +xx(LV4, lv4, RVRPKI, LV4_R, 4, REGT_INT) // load vector4 +xx(LV4_R, lv4, RVRPRI, NOP, 0, 0) xx(LCS, lcs, RSRPKI, LCS_R, 4, REGT_INT) // load string from char ptr. xx(LCS_R, lcs, RSRPRI, NOP, 0, 0) +xx(LFV2, lfv2, RVRPKI, LFV2_R, 4, REGT_INT) // load fvector2 +xx(LFV2_R, lfv2, RVRPRI, NOP, 0, 0) +xx(LFV3, lfv3, RVRPKI, LFV3_R, 4, REGT_INT) // load fvector3 +xx(LFV3_R, lfv3, RVRPRI, NOP, 0, 0) +xx(LFV4, lfv4, RVRPKI, LFV4_R, 4, REGT_INT) // load fvector4 +xx(LFV4_R, lfv4, RVRPRI, NOP, 0, 0) xx(LBIT, lbit, RIRPI8, NOP, 0, 0) // rA = !!(*rB & C) -- *rB is a byte @@ -77,6 +85,14 @@ xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT) // store vector2 xx(SV2_R, sv2, RPRVRI, NOP, 0, 0) xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT) // store vector3 xx(SV3_R, sv3, RPRVRI, NOP, 0, 0) +xx(SV4, sv4, RPRVKI, SV4_R, 4, REGT_INT) // store vector4 +xx(SV4_R, sv4, RPRVRI, NOP, 0, 0) +xx(SFV2, sfv2, RPRVKI, SFV2_R, 4, REGT_INT) // store fvector2 +xx(SFV2_R, sfv2, RPRVRI, NOP, 0, 0) +xx(SFV3, sfv3, RPRVKI, SFV3_R, 4, REGT_INT) // store fvector3 +xx(SFV3_R, sfv3, RPRVRI, NOP, 0, 0) +xx(SFV4, sfv4, RPRVKI, SFV4_R, 4, REGT_INT) // store fvector4 +xx(SFV4_R, sfv4, RPRVRI, NOP, 0, 0) xx(SBIT, sbit, RPRII8, NOP, 0, 0) // *rA |= C if rB is true, *rA &= ~C otherwise @@ -87,6 +103,7 @@ xx(MOVES, mov, RSRS, NOP, 0, 0) // sA = sB xx(MOVEA, mov, RPRP, NOP, 0, 0) // aA = aB xx(MOVEV2, mov2, RFRF, NOP, 0, 0) // fA = fB (2 elements) xx(MOVEV3, mov3, RFRF, NOP, 0, 0) // fA = fB (3 elements) +xx(MOVEV4, mov4, RFRF, NOP, 0, 0) // fA = fB (4 elements) xx(CAST, cast, CAST, NOP, 0, 0) // xA = xB, conversion specified by C xx(CASTB, castb, CAST, NOP, 0, 0) // xA = !!xB, type specified by C xx(DYNCAST_R, dyncast, RPRPRP, NOP, 0, 0) // aA = dyn_cast(aB); @@ -248,6 +265,23 @@ xx(LENV3, lenv3, RFRV, NOP, 0, 0) // fA = vB.Length xx(EQV3_R, beqv3, CVRR, NOP, 0, 0) // if ((vB == vkC) != A) then pc++ (inexact if A & 33) xx(EQV3_K, beqv3, CVRK, NOP, 0, 0) // this will never be used. +// Vector math (4D) +xx(NEGV4, negv4, RVRV, NOP, 0, 0) // vA = -vB +xx(ADDV4_RR, addv4, RVRVRV, NOP, 0, 0) // vA = vB + vkC +xx(SUBV4_RR, subv4, RVRVRV, NOP, 0, 0) // vA = vkB - vkC +xx(DOTV4_RR, dotv4, RVRVRV, NOP, 0, 0) // va = vB dot vkC +xx(MULVF4_RR, mulv4, RVRVRF, NOP, 0, 0) // vA = vkB * fkC +xx(MULVF4_RK, mulv4, RVRVKF, MULVF4_RR, 4, REGT_FLOAT) +xx(DIVVF4_RR, divv4, RVRVRF, NOP, 0, 0) // vA = vkB / fkC +xx(DIVVF4_RK, divv4, RVRVKF, DIVVF4_RR, 4, REGT_FLOAT) +xx(LENV4, lenv4, RFRV, NOP, 0, 0) // fA = vB.Length +xx(EQV4_R, beqv4, CVRR, NOP, 0, 0) // if ((vB == vkC) != A) then pc++ (inexact if A & 33) +xx(EQV4_K, beqv4, CVRK, NOP, 0, 0) // this will never be used. + +// Quaternion math +xx(MULQQ_RR, mulqq, RVRVRV, NOP, 0, 0) // qA = qB * qC +xx(MULQV3_RR, mulqv3, RVRVRV, NOP, 0, 0) // qA = qB * vC + // Pointer math. xx(ADDA_RR, add, RPRPRI, NOP, 0, 0) // pA = pB + dkC xx(ADDA_RK, add, RPRPKI, ADDA_RR,4, REGT_INT) @@ -255,4 +289,7 @@ xx(SUBA, sub, RIRPRP, NOP, 0, 0) // dA = pB - pC xx(EQA_R, beq, CPRR, NOP, 0, 0) // if ((pB == pkC) != A) then pc++ xx(EQA_K, beq, CPRK, EQA_R, 4, REGT_POINTER) +// Null check +xx(NULLCHECK, nullcheck, RP, NOP, 0, 0) // EmitNullPointerThrow(pA) + #undef xx diff --git a/src/common/startscreen/endoom.cpp b/src/common/startscreen/endoom.cpp new file mode 100644 index 00000000000..6e8e7af353d --- /dev/null +++ b/src/common/startscreen/endoom.cpp @@ -0,0 +1,200 @@ + +/* +** endoom.cpp +** Handles the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** Copyright 2006-2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include "startscreen.h" +#include "cmdlib.h" + +#include "i_system.h" +#include "gstrings.h" +#include "filesystem.h" +#include "m_argv.h" +#include "engineerrors.h" +#include "s_music.h" +#include "printf.h" +#include "startupinfo.h" +#include "i_interface.h" +#include "texturemanager.h" +#include "c_cvars.h" +#include "i_time.h" +#include "g_input.h" +#include "d_eventbase.h" + +// MACROS ------------------------------------------------------------------ + +// How many ms elapse between blinking text flips. On a standard VGA +// adapter, the characters are on for 16 frames and then off for another 16. +// The number here therefore corresponds roughly to the blink rate on a +// 60 Hz display. +#define BLINK_PERIOD 267 + + +// TYPES ------------------------------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CUSTOM_CVAR(Int, showendoom, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) self = 0; + else if (self > 2) self=2; +} + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// CODE -------------------------------------------------------------------- + +class FEndoomScreen : public FStartScreen +{ + uint64_t lastUpdateTime; + bool blinkstate = false; + bool blinking = true; + uint8_t endoom_screen[4000]; + +public: + FEndoomScreen(int); + void Update(); +}; + + +//========================================================================== +// +// FHereticStartScreen Constructor +// +// Shows the Heretic startup screen. If the screen doesn't appear to be +// valid, it returns a failure code in hr. +// +// The loading screen is an 80x25 text screen with character data and +// attributes intermixed, which means it must be exactly 4000 bytes long. +// +//========================================================================== + +FEndoomScreen::FEndoomScreen(int loading_lump) + : FStartScreen(0) +{ + fileSystem.ReadFile(loading_lump, endoom_screen); + + // Draw the loading screen to a bitmap. + StartupBitmap.Create(80 * 8, 26 * 16); // line 26 is for our own 'press any key to quit' message. + DrawTextScreen(StartupBitmap, endoom_screen); + ClearBlock(StartupBitmap, {0, 0, 0, 255}, 0, 25*16, 640, 16); + DrawString(StartupBitmap, 0, 25, GStrings.GetString("TXT_QUITENDOOM"), { 128, 128, 128 ,255}, { 0, 0, 0, 255}); + lastUpdateTime = I_msTime(); + + // Does this screen need blinking? + for (int i = 0; i < 80*25; ++i) + { + if (endoom_screen[1+i*2] & 0x80) + { + blinking = true; + break; + } + } +} + +void FEndoomScreen::Update() +{ + if (blinking && I_msTime() > lastUpdateTime + BLINK_PERIOD) + { + lastUpdateTime = I_msTime(); + UpdateTextBlink (StartupBitmap, endoom_screen, blinkstate); + blinkstate = !blinkstate; + StartupTexture->CleanHardwareData(); + Render(true); + } +} + + +//========================================================================== +// +// ST_Endoom +// +// Shows an ENDOOM text screen +// +//========================================================================== + +int RunEndoom() +{ + if (showendoom == 0 || endoomName.Len() == 0) + { + return 0; + } + + int endoom_lump = fileSystem.CheckNumForFullName (endoomName.GetChars(), true); + + if (endoom_lump < 0 || fileSystem.FileLength (endoom_lump) != 4000) + { + return 0; + } + + if (fileSystem.GetFileContainer(endoom_lump) == fileSystem.GetMaxIwadNum() && showendoom == 2) + { + // showendoom==2 means to show only lumps from PWADs. + return 0; + } + + S_StopMusic(true); + auto endoom = new FEndoomScreen(endoom_lump); + endoom->Render(true); + + while(true) + { + I_GetEvent(); + endoom->Update(); + while (eventtail != eventhead) + { + event_t *ev = &events[eventtail]; + eventtail = (eventtail + 1) & (MAXEVENTS - 1); + + if (ev->type == EV_KeyDown || ev->type == EV_KeyUp) + { + return 0; + } + if (ev->type == EV_GUI_Event && (ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_LButtonDown || ev->subtype == EV_GUI_RButtonDown || ev->subtype == EV_GUI_MButtonDown)) + { + return 0; + } + } + } + return 0; +} + +[[noreturn]] +void ST_Endoom() +{ + int code = RunEndoom(); + throw CExitEvent(code); +} diff --git a/src/common/startscreen/startscreen.cpp b/src/common/startscreen/startscreen.cpp new file mode 100644 index 00000000000..b71949f469a --- /dev/null +++ b/src/common/startscreen/startscreen.cpp @@ -0,0 +1,720 @@ +/* +** st_start.cpp +** Handles the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** Copyright 2006-2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "startscreen.h" +#include "filesystem.h" +#include "palutil.h" +#include "v_font.h" +#include "i_interface.h" +#include "startupinfo.h" +#include "m_argv.h" +#include "engineerrors.h" +#include "utf8.h" +#include "gstrings.h" +#include "printf.h" +#include "i_time.h" +#include "v_video.h" +#include "v_draw.h" +#include "g_input.h" +#include "texturemanager.h" + +// Text mode color values +enum{ + LO = 85, + MD = 170, + HI = 255, +}; + +const RgbQuad TextModePalette[16] = +{ + { 0, 0, 0, 255 }, // 0 black + { MD, 0, 0, 255 }, // 1 blue + { 0, MD, 0, 255 }, // 2 green + { MD, MD, 0, 255 }, // 3 cyan + { 0, 0, MD, 255 }, // 4 red + { MD, 0, MD, 255 }, // 5 magenta + { 0, LO, MD, 255 }, // 6 brown + { MD, MD, MD, 255 }, // 7 light gray + + { LO, LO, LO, 255 }, // 8 dark gray + { HI, LO, LO, 255 }, // 9 light blue + { LO, HI, LO, 255 }, // A light green + { HI, HI, LO, 255 }, // B light cyan + { LO, LO, HI, 255 }, // C light red + { HI, LO, HI, 255 }, // D light magenta + { LO, HI, HI, 255 }, // E yellow + { HI, HI, HI, 255 }, // F white +}; + +static const uint16_t IBM437ToUnicode[] = { + 0x0000, //#NULL + 0x263a, //#START OF HEADING + 0x263B, //#START OF TEXT + 0x2665, //#END OF TEXT + 0x2666, //#END OF TRANSMISSION + 0x2663, //#ENQUIRY + 0x2660, //#ACKNOWLEDGE + 0x2022, //#BELL + 0x25d8, //#BACKSPACE + 0x25cb, //#HORIZONTAL TABULATION + 0x25d9, //#LINE FEED + 0x2642, //#VERTICAL TABULATION + 0x2640, //#FORM FEED + 0x266a, //#CARRIAGE RETURN + 0x266b, //#SHIFT OUT + 0x263c, //#SHIFT IN + 0x25ba, //#DATA LINK ESCAPE + 0x25c4, //#DEVICE CONTROL ONE + 0x2195, //#DEVICE CONTROL TWO + 0x203c, //#DEVICE CONTROL THREE + 0x00b6, //#DEVICE CONTROL FOUR + 0x00a7, //#NEGATIVE ACKNOWLEDGE + 0x25ac, //#SYNCHRONOUS IDLE + 0x21ab, //#END OF TRANSMISSION BLOCK + 0x2191, //#CANCEL + 0x2193, //#END OF MEDIUM + 0x2192, //#SUBSTITUTE + 0x2190, //#ESCAPE + 0x221f, //#FILE SEPARATOR + 0x2194, //#GROUP SEPARATOR + 0x25b2, //#RECORD SEPARATOR + 0x25bc, //#UNIT SEPARATOR + 0x0020, //#SPACE + 0x0021, //#EXCLAMATION MARK + 0x0022, //#QUOTATION MARK + 0x0023, //#NUMBER SIGN + 0x0024, //#DOLLAR SIGN + 0x0025, //#PERCENT SIGN + 0x0026, //#AMPERSAND + 0x0027, //#APOSTROPHE + 0x0028, //#LEFT PARENTHESIS + 0x0029, //#RIGHT PARENTHESIS + 0x002a, //#ASTERISK + 0x002b, //#PLUS SIGN + 0x002c, //#COMMA + 0x002d, //#HYPHEN-MINUS + 0x002e, //#FULL STOP + 0x002f, //#SOLIDUS + 0x0030, //#DIGIT ZERO + 0x0031, //#DIGIT ONE + 0x0032, //#DIGIT TWO + 0x0033, //#DIGIT THREE + 0x0034, //#DIGIT FOUR + 0x0035, //#DIGIT FIVE + 0x0036, //#DIGIT SIX + 0x0037, //#DIGIT SEVEN + 0x0038, //#DIGIT EIGHT + 0x0039, //#DIGIT NINE + 0x003a, //#COLON + 0x003b, //#SEMICOLON + 0x003c, //#LESS-THAN SIGN + 0x003d, //#EQUALS SIGN + 0x003e, //#GREATER-THAN SIGN + 0x003f, //#QUESTION MARK + 0x0040, //#COMMERCIAL AT + 0x0041, //#LATIN CAPITAL LETTER A + 0x0042, //#LATIN CAPITAL LETTER B + 0x0043, //#LATIN CAPITAL LETTER C + 0x0044, //#LATIN CAPITAL LETTER D + 0x0045, //#LATIN CAPITAL LETTER E + 0x0046, //#LATIN CAPITAL LETTER F + 0x0047, //#LATIN CAPITAL LETTER G + 0x0048, //#LATIN CAPITAL LETTER H + 0x0049, //#LATIN CAPITAL LETTER I + 0x004a, //#LATIN CAPITAL LETTER J + 0x004b, //#LATIN CAPITAL LETTER K + 0x004c, //#LATIN CAPITAL LETTER L + 0x004d, //#LATIN CAPITAL LETTER M + 0x004e, //#LATIN CAPITAL LETTER N + 0x004f, //#LATIN CAPITAL LETTER O + 0x0050, //#LATIN CAPITAL LETTER P + 0x0051, //#LATIN CAPITAL LETTER Q + 0x0052, //#LATIN CAPITAL LETTER R + 0x0053, //#LATIN CAPITAL LETTER S + 0x0054, //#LATIN CAPITAL LETTER T + 0x0055, //#LATIN CAPITAL LETTER U + 0x0056, //#LATIN CAPITAL LETTER V + 0x0057, //#LATIN CAPITAL LETTER W + 0x0058, //#LATIN CAPITAL LETTER X + 0x0059, //#LATIN CAPITAL LETTER Y + 0x005a, //#LATIN CAPITAL LETTER Z + 0x005b, //#LEFT SQUARE BRACKET + 0x005c, //#REVERSE SOLIDUS + 0x005d, //#RIGHT SQUARE BRACKET + 0x005e, //#CIRCUMFLEX ACCENT + 0x005f, //#LOW LINE + 0x0060, //#GRAVE ACCENT + 0x0061, //#LATIN SMALL LETTER A + 0x0062, //#LATIN SMALL LETTER B + 0x0063, //#LATIN SMALL LETTER C + 0x0064, //#LATIN SMALL LETTER D + 0x0065, //#LATIN SMALL LETTER E + 0x0066, //#LATIN SMALL LETTER F + 0x0067, //#LATIN SMALL LETTER G + 0x0068, //#LATIN SMALL LETTER H + 0x0069, //#LATIN SMALL LETTER I + 0x006a, //#LATIN SMALL LETTER J + 0x006b, //#LATIN SMALL LETTER K + 0x006c, //#LATIN SMALL LETTER L + 0x006d, //#LATIN SMALL LETTER M + 0x006e, //#LATIN SMALL LETTER N + 0x006f, //#LATIN SMALL LETTER O + 0x0070, //#LATIN SMALL LETTER P + 0x0071, //#LATIN SMALL LETTER Q + 0x0072, //#LATIN SMALL LETTER R + 0x0073, //#LATIN SMALL LETTER S + 0x0074, //#LATIN SMALL LETTER T + 0x0075, //#LATIN SMALL LETTER U + 0x0076, //#LATIN SMALL LETTER V + 0x0077, //#LATIN SMALL LETTER W + 0x0078, //#LATIN SMALL LETTER X + 0x0079, //#LATIN SMALL LETTER Y + 0x007a, //#LATIN SMALL LETTER Z + 0x007b, //#LEFT CURLY BRACKET + 0x007c, //#VERTICAL LINE + 0x007d, //#RIGHT CURLY BRACKET + 0x007e, //#TILDE + 0x2302, //#DELETE + 0x00c7, //#LATIN CAPITAL LETTER C WITH CEDILLA + 0x00fc, //#LATIN SMALL LETTER U WITH DIAERESIS + 0x00e9, //#LATIN SMALL LETTER E WITH ACUTE + 0x00e2, //#LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e4, //#LATIN SMALL LETTER A WITH DIAERESIS + 0x00e0, //#LATIN SMALL LETTER A WITH GRAVE + 0x00e5, //#LATIN SMALL LETTER A WITH RING ABOVE + 0x00e7, //#LATIN SMALL LETTER C WITH CEDILLA + 0x00ea, //#LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb, //#LATIN SMALL LETTER E WITH DIAERESIS + 0x00e8, //#LATIN SMALL LETTER E WITH GRAVE + 0x00ef, //#LATIN SMALL LETTER I WITH DIAERESIS + 0x00ee, //#LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ec, //#LATIN SMALL LETTER I WITH GRAVE + 0x00c4, //#LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5, //#LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c9, //#LATIN CAPITAL LETTER E WITH ACUTE + 0x00e6, //#LATIN SMALL LIGATURE AE + 0x00c6, //#LATIN CAPITAL LIGATURE AE + 0x00f4, //#LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f6, //#LATIN SMALL LETTER O WITH DIAERESIS + 0x00f2, //#LATIN SMALL LETTER O WITH GRAVE + 0x00fb, //#LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00f9, //#LATIN SMALL LETTER U WITH GRAVE + 0x00ff, //#LATIN SMALL LETTER Y WITH DIAERESIS + 0x00d6, //#LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00dc, //#LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00a2, //#CENT SIGN + 0x00a3, //#POUND SIGN + 0x00a5, //#YEN SIGN + 0x20a7, //#PESETA SIGN + 0x0192, //#LATIN SMALL LETTER F WITH HOOK + 0x00e1, //#LATIN SMALL LETTER A WITH ACUTE + 0x00ed, //#LATIN SMALL LETTER I WITH ACUTE + 0x00f3, //#LATIN SMALL LETTER O WITH ACUTE + 0x00fa, //#LATIN SMALL LETTER U WITH ACUTE + 0x00f1, //#LATIN SMALL LETTER N WITH TILDE + 0x00d1, //#LATIN CAPITAL LETTER N WITH TILDE + 0x00aa, //#FEMININE ORDINAL INDICATOR + 0x00ba, //#MASCULINE ORDINAL INDICATOR + 0x00bf, //#INVERTED QUESTION MARK + 0x2310, //#REVERSED NOT SIGN + 0x00ac, //#NOT SIGN + 0x00bd, //#VULGAR FRACTION ONE HALF + 0x00bc, //#VULGAR FRACTION ONE QUARTER + 0x00a1, //#INVERTED EXCLAMATION MARK + 0x00ab, //#LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bb, //#RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x2591, //#LIGHT SHADE + 0x2592, //#MEDIUM SHADE + 0x2593, //#DARK SHADE + 0x2502, //#BOX DRAWINGS LIGHT VERTICAL + 0x2524, //#BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x2561, //#BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0x2562, //#BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0x2556, //#BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0x2555, //#BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0x2563, //#BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0x2551, //#BOX DRAWINGS DOUBLE VERTICAL + 0x2557, //#BOX DRAWINGS DOUBLE DOWN AND LEFT + 0x255d, //#BOX DRAWINGS DOUBLE UP AND LEFT + 0x255c, //#BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0x255b, //#BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0x2510, //#BOX DRAWINGS LIGHT DOWN AND LEFT + 0x2514, //#BOX DRAWINGS LIGHT UP AND RIGHT + 0x2534, //#BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x252c, //#BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x251c, //#BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x2500, //#BOX DRAWINGS LIGHT HORIZONTAL + 0x253c, //#BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x255e, //#BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0x255f, //#BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0x255a, //#BOX DRAWINGS DOUBLE UP AND RIGHT + 0x2554, //#BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0x2569, //#BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0x2566, //#BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0x2560, //#BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0x2550, //#BOX DRAWINGS DOUBLE HORIZONTAL + 0x256c, //#BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0x2567, //#BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0x2568, //#BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0x2564, //#BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0x2565, //#BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0x2559, //#BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0x2558, //#BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0x2552, //#BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0x2553, //#BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0x256b, //#BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0x256a, //#BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0x2518, //#BOX DRAWINGS LIGHT UP AND LEFT + 0x250c, //#BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x2588, //#FULL BLOCK + 0x2584, //#LOWER HALF BLOCK + 0x258c, //#LEFT HALF BLOCK + 0x2590, //#RIGHT HALF BLOCK + 0x2580, //#UPPER HALF BLOCK + 0x03b1, //#GREEK SMALL LETTER ALPHA + 0x00df, //#LATIN SMALL LETTER SHARP S + 0x0393, //#GREEK CAPITAL LETTER GAMMA + 0x03c0, //#GREEK SMALL LETTER PI + 0x03a3, //#GREEK CAPITAL LETTER SIGMA + 0x03c3, //#GREEK SMALL LETTER SIGMA + 0x00b5, //#MICRO SIGN + 0x03c4, //#GREEK SMALL LETTER TAU + 0x03a6, //#GREEK CAPITAL LETTER PHI + 0x0398, //#GREEK CAPITAL LETTER THETA + 0x03a9, //#GREEK CAPITAL LETTER OMEGA + 0x03b4, //#GREEK SMALL LETTER DELTA + 0x221e, //#INFINITY + 0x03c6, //#GREEK SMALL LETTER PHI + 0x03b5, //#GREEK SMALL LETTER EPSILON + 0x2229, //#INTERSECTION + 0x2261, //#IDENTICAL TO + 0x00b1, //#PLUS-MINUS SIGN + 0x2265, //#GREATER-THAN OR EQUAL TO + 0x2264, //#LESS-THAN OR EQUAL TO + 0x2320, //#TOP HALF INTEGRAL + 0x2321, //#BOTTOM HALF INTEGRAL + 0x00f7, //#DIVISION SIGN + 0x2248, //#ALMOST EQUAL TO + 0x00b0, //#DEGREE SIGN + 0x2219, //#BULLET OPERATOR + 0x00b7, //#MIDDLE DOT + 0x221a, //#SQUARE ROOT + 0x207f, //#SUPERSCRIPT LATIN SMALL LETTER N + 0x00b2, //#SUPERSCRIPT TWO + 0x25a0, //#BLACK SQUARE + 0x00a0, //#NO-BREAK SPACE +}; + +FStartScreen* CreateHexenStartScreen(int max_progress); +FStartScreen* CreateHereticStartScreen(int max_progress); +FStartScreen* CreateStrifeStartScreen(int max_progress); +FStartScreen* CreateGenericStartScreen(int max_progress); + + +FStartScreen* GetGameStartScreen(int max_progress) +{ + if (!Args->CheckParm("-nostartup")) + { + try + { + if (GameStartupInfo.Type == FStartupInfo::HexenStartup) + { + return CreateHexenStartScreen(max_progress); + } + else if (GameStartupInfo.Type == FStartupInfo::HereticStartup) + { + return CreateHereticStartScreen(max_progress); + } + else if (GameStartupInfo.Type == FStartupInfo::StrifeStartup) + { + return CreateStrifeStartScreen(max_progress); + } + } + catch(const CRecoverableError& err) + { + Printf("Error creating start screen: %s\n", err.what()); + // fall through to the generic startup screen + } + return CreateGenericStartScreen(max_progress); + } + return nullptr; +} + +//========================================================================== +// +// ST_Util_ClearBlock +// +//========================================================================== + +void FStartScreen::ClearBlock(FBitmap& bitmap_info, RgbQuad fill, int x, int y, int bytewidth, int height) +{ + int destpitch = bitmap_info.GetWidth(); + auto dest = (RgbQuad*)(bitmap_info.GetPixels()) + x + y * destpitch; + + while (height > 0) + { + for(int i = 0; i < bytewidth; i++) + { + dest[i] = fill; + } + dest += destpitch; + height--; + } +} + +//========================================================================== +// +// ST_Util_DrawTextScreen +// +// Draws the text screen to the bitmap. The bitmap must be the proper size +// for the font. +// +//========================================================================== + +void FStartScreen::DrawTextScreen(FBitmap& bitmap_info, const uint8_t* text_screen) +{ + int x, y; + + for (y = 0; y < 25; ++y) + { + for (x = 0; x < 80; ++x) + { + DrawChar(bitmap_info, x, y, IBM437ToUnicode[text_screen[0]], text_screen[1]); + text_screen += 2; + } + } +} + +//========================================================================== +// +// ST_Util_DrawChar +// +// Draws a character on the bitmap. X and Y specify the character cell, +// and fg and bg are 4-bit colors. +// +//========================================================================== +uint8_t* GetHexChar(int codepoint); + +int FStartScreen::DrawChar(FBitmap& screen, double x, double y, unsigned charnum, RgbQuad fg, RgbQuad bg) +{ + if (x < 0 || y < 0 || y >= screen.GetHeight() - 16) return 1; + static const uint8_t space[17] = { 16 }; + const RgbQuad color_array[4] = { bg, fg }; + const uint8_t* src = GetHexChar(charnum); + if (!src) src = space; + int size = (*src++) == 32? 2 : 1; + if (x > (screen.GetWidth() >> 3) - size) return size; + int pitch = screen.GetWidth(); + RgbQuad* dest = (RgbQuad*)screen.GetPixels() + int(x * 8) + int(y * 16) * pitch; + + for (y = 0; y <16; ++y) + { + uint8_t srcbyte = *src++; + + dest[0] = color_array[(srcbyte >> 7) & 1]; + dest[1] = color_array[(srcbyte >> 6) & 1]; + dest[2] = color_array[(srcbyte >> 5) & 1]; + dest[3] = color_array[(srcbyte >> 4) & 1]; + dest[4] = color_array[(srcbyte >> 3) & 1]; + dest[5] = color_array[(srcbyte >> 2) & 1]; + dest[6] = color_array[(srcbyte >> 1) & 1]; + dest[7] = color_array[(srcbyte) & 1]; + if (size == 16) + { + srcbyte = *src++; + + dest[8] = color_array[(srcbyte >> 7) & 1]; + dest[9] = color_array[(srcbyte >> 6) & 1]; + dest[10] = color_array[(srcbyte >> 5) & 1]; + dest[11] = color_array[(srcbyte >> 4) & 1]; + dest[12] = color_array[(srcbyte >> 3) & 1]; + dest[13] = color_array[(srcbyte >> 2) & 1]; + dest[14] = color_array[(srcbyte >> 1) & 1]; + dest[15] = color_array[(srcbyte) & 1]; + } + dest += pitch; + } + return size; +} + +int FStartScreen::DrawChar(FBitmap& screen, double x, double y, unsigned charnum, uint8_t attrib) +{ + const uint8_t bg = (attrib & 0x70) >> 4; + const uint8_t fg = attrib & 0x0F; + auto bgc = TextModePalette[bg], fgc = TextModePalette[fg]; + return DrawChar(screen, x, y, charnum, fgc, bgc); +} + +int FStartScreen::DrawString(FBitmap& screen, double x, double y, const char* text, RgbQuad fg, RgbQuad bg) +{ + double oldx = x; + auto str = (const uint8_t*)text; + while (auto chr = GetCharFromString(str)) + { + x += DrawChar(screen, x, y, chr, fg, bg); + } + return int(x - oldx); +} + +//========================================================================== +// +// SizeOfText +// +// returns width in pixels +// +//========================================================================== + +int FStartScreen::SizeOfText(const char* text) +{ + int len = 0; + const uint8_t* utext = (uint8_t*)text; + while(auto code = GetCharFromString(utext)) + { + const uint8_t* src = GetHexChar(code); + if (src && *src == 32) len += 2; + else len ++; + } + return len; +} + +//========================================================================== +// +// ST_Util_UpdateTextBlink +// +// Draws the parts of the text screen that blink to the bitmap. The bitmap +// must be the proper size for the font. +// +//========================================================================== + +void FStartScreen::UpdateTextBlink(FBitmap& bitmap_info, const uint8_t* text_screen, bool on) +{ + int x, y; + + for (y = 0; y < 25; ++y) + { + for (x = 0; x < 80; ++x) + { + if (text_screen[1] & 0x80) + { + DrawChar(bitmap_info, x, y, on ? IBM437ToUnicode[text_screen[0]] : ' ', text_screen[1]); + } + text_screen += 2; + } + } +} + +//========================================================================== +// +// ST_Sound +// +// plays a sound on the start screen +// +//========================================================================== + +void FStartScreen::ST_Sound(const char* sndname) +{ + if (sysCallbacks.PlayStartupSound) + sysCallbacks.PlayStartupSound(sndname); +} + +//========================================================================== +// +// CreateHeader +// +// creates a bitmap for the title header +// +//========================================================================== + +void FStartScreen::CreateHeader() +{ + HeaderBitmap.Create(StartupBitmap.GetWidth() * Scale, 2 * 16); + RgbQuad bcolor, fcolor; + bcolor.rgbRed = RPART(GameStartupInfo.BkColor); + bcolor.rgbGreen = GPART(GameStartupInfo.BkColor); + bcolor.rgbBlue = BPART(GameStartupInfo.BkColor); + bcolor.rgbReserved = 255; + fcolor.rgbRed = RPART(GameStartupInfo.FgColor); + fcolor.rgbGreen = GPART(GameStartupInfo.FgColor); + fcolor.rgbBlue = BPART(GameStartupInfo.FgColor); + fcolor.rgbReserved = 255; + ClearBlock(HeaderBitmap, bcolor, 0, 0, HeaderBitmap.GetWidth(), HeaderBitmap.GetHeight()); + int textlen = SizeOfText(GameStartupInfo.Name.GetChars()); + DrawString(HeaderBitmap, (HeaderBitmap.GetWidth() >> 4) - (textlen >> 1), 0.5, GameStartupInfo.Name.GetChars(), fcolor, bcolor); + NetBitmap.Create(StartupBitmap.GetWidth() * Scale, 16); +} + +//========================================================================== +// +// DrawNetStatus +// +// Draws network status into the last line of the startup screen. +// +//========================================================================== + +void FStartScreen::DrawNetStatus(int found, int total) +{ + RgbQuad black = { 0, 0, 0, 255 }; + RgbQuad gray = { 100, 100, 100, 255 }; + ClearBlock(NetBitmap, black, 0, NetBitmap.GetHeight() - 16, NetBitmap.GetWidth(), 16); + DrawString(NetBitmap, 0, 0, NetMessageString.GetChars(), gray, black); + char of[10]; + mysnprintf(of, 10, "%d/%d", found, total); + int siz = SizeOfText(of); + DrawString(NetBitmap, (NetBitmap.GetWidth() >> 3) - siz, 0, of, gray, black); +} + +//========================================================================== +// +// NetInit +// +// sets network status message +// +//========================================================================== + +bool FStartScreen::NetInit(const char* message, int numplayers) +{ + NetMaxPos = numplayers; + NetCurPos = 0; + NetMessageString.Format("%s %s", message, GStrings.GetString("TXT_NET_PRESSESC")); + NetProgress(1); // You always know about yourself + return true; +} + +//========================================================================== +// +// Progress +// +// advances the progress bar +// +//========================================================================== + +bool FStartScreen::DoProgress(int advance) +{ + CurPos = min(CurPos + advance, MaxPos); + return true; +} + +void FStartScreen::DoNetProgress(int count) +{ + if (count == 0) + { + NetCurPos++; + } + else if (count > 0) + { + NetCurPos = count; + } + NetTexture->CleanHardwareData(); +} + +bool FStartScreen::Progress(int advance) +{ + bool done = DoProgress(advance); + Render(); + return done; +} + +void FStartScreen::NetProgress(int count) +{ + DoNetProgress(count); + Render(); +} + +void FStartScreen::Render(bool force) +{ + static uint64_t minwaittime = 30; + + auto nowtime = I_msTime(); + // Do not refresh too often. This function gets called a lot more frequently than the screen can update. + if (nowtime - screen->FrameTime > minwaittime || force) + { + screen->FrameTime = nowtime; + screen->BeginFrame(); + twod->ClearClipRect(); + I_GetEvent(); + ValidateTexture(); + float displaywidth; + float displayheight; + twod->Begin(screen->GetWidth(), screen->GetHeight()); + + // At this point the shader for untextured rendering has not been loaded yet, so we got to clear the screen by rendering a texture with black color. + DrawTexture(twod, StartupTexture, 0, 0, DTA_VirtualWidthF, StartupTexture->GetDisplayWidth(), DTA_VirtualHeightF, StartupTexture->GetDisplayHeight(), DTA_KeepRatio, true, DTA_Color, PalEntry(255,0,0,0), TAG_END); + + if (HeaderTexture) + { + displaywidth = HeaderTexture->GetDisplayWidth(); + displayheight = HeaderTexture->GetDisplayHeight() + StartupTexture->GetDisplayHeight(); + DrawTexture(twod, HeaderTexture, 0, 0, DTA_VirtualWidthF, displaywidth, DTA_VirtualHeightF, displayheight, TAG_END); + DrawTexture(twod, StartupTexture, 0, 32, DTA_VirtualWidthF, displaywidth, DTA_VirtualHeightF, displayheight, TAG_END); + if (NetMaxPos >= 0) DrawTexture(twod, NetTexture, 0, displayheight - 16, DTA_VirtualWidthF, displaywidth, DTA_VirtualHeightF, displayheight, TAG_END); + } + else + { + displaywidth = StartupTexture->GetDisplayWidth(); + displayheight = StartupTexture->GetDisplayHeight(); + DrawTexture(twod, StartupTexture, 0, 0, DTA_VirtualWidthF, displaywidth, DTA_VirtualHeightF, displayheight, TAG_END); + } + + twod->End(); + screen->Update(); + twod->OnFrameDone(); + } + auto newtime = I_msTime(); + if ((newtime - nowtime) * 2.0 > minwaittime) // slow down drawing the start screen if we're on a slow GPU! + minwaittime = (newtime - nowtime) * 2.0; +} + +FImageSource* CreateStartScreenTexture(FBitmap& srcdata); + +void FStartScreen::ValidateTexture() +{ + if (StartupTexture == nullptr) + { + auto imgsource = CreateStartScreenTexture(StartupBitmap); + StartupTexture = MakeGameTexture(new FImageTexture(imgsource), nullptr, ETextureType::Override); + StartupTexture->SetScale(1.f / Scale, 1.f / Scale); + } + if (HeaderTexture == nullptr && HeaderBitmap.GetWidth() > 0) + { + auto imgsource = CreateStartScreenTexture(HeaderBitmap); + HeaderTexture = MakeGameTexture(new FImageTexture(imgsource), nullptr, ETextureType::Override); + } + if (NetTexture == nullptr && NetBitmap.GetWidth() > 0) + { + auto imgsource = CreateStartScreenTexture(NetBitmap); + NetTexture = MakeGameTexture(new FImageTexture(imgsource), nullptr, ETextureType::Override); + } +} + diff --git a/src/common/startscreen/startscreen.h b/src/common/startscreen/startscreen.h new file mode 100644 index 00000000000..afac6c7594e --- /dev/null +++ b/src/common/startscreen/startscreen.h @@ -0,0 +1,106 @@ +#pragma once +/* +** st_start.h +** Interface for the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +#pragma once +** The startup screen interface is based on a mix of Heretic and Hexen. +** Actual implementation is system-specific. +*/ +#include +#include +#include "bitmap.h" +#include "zstring.h" + +class FGameTexture; + +struct RgbQuad +{ + uint8_t rgbBlue; + uint8_t rgbGreen; + uint8_t rgbRed; + uint8_t rgbReserved; +}; + + +extern const RgbQuad TextModePalette[16]; + +class FStartScreen +{ +protected: + int CurPos = 0; + int MaxPos; + int Scale = 1; + int NetMaxPos = -1; + int NetCurPos = 0; + FBitmap StartupBitmap; + FBitmap HeaderBitmap; + FBitmap NetBitmap; + FString NetMessageString; + FGameTexture* StartupTexture = nullptr; + FGameTexture* HeaderTexture = nullptr; + FGameTexture* NetTexture = nullptr; +public: + FStartScreen(int maxp) { MaxPos = maxp; } + virtual ~FStartScreen() = default; + void Render(bool force = false); + bool Progress(int); + void NetProgress(int count); + virtual void LoadingStatus(const char *message, int colors) {} + virtual void AppendStatusLine(const char *status) {} + virtual bool NetInit(const char* message, int numplayers); + virtual void NetDone() {} + virtual void NetTick() {} + FBitmap& GetBitmap() { return StartupBitmap; } + int GetScale() const { return Scale; } + + +protected: + void ClearBlock(FBitmap& bitmap_info, RgbQuad fill, int x, int y, int bytewidth, int height); + FBitmap AllocTextBitmap(); + void DrawTextScreen(FBitmap& bitmap_info, const uint8_t* text_screen); + int DrawChar(FBitmap& screen, double x, double y, unsigned charnum, uint8_t attrib); + int DrawChar(FBitmap& screen, double x, double y, unsigned charnum, RgbQuad fg, RgbQuad bg); + int DrawString(FBitmap& screen, double x, double y, const char* text, RgbQuad fg, RgbQuad bg); + void UpdateTextBlink(FBitmap& bitmap_info, const uint8_t* text_screen, bool on); + void ST_Sound(const char* sndname); + int SizeOfText(const char* text); + void CreateHeader(); + void DrawNetStatus(int found, int total); + void ValidateTexture(); + virtual bool DoProgress(int); + virtual void DoNetProgress(int count); +}; + +FStartScreen* GetGameStartScreen(int max_progress); + +[[noreturn]] +void ST_Endoom(); diff --git a/src/common/startscreen/startscreen_generic.cpp b/src/common/startscreen/startscreen_generic.cpp new file mode 100644 index 00000000000..b76cbd3e250 --- /dev/null +++ b/src/common/startscreen/startscreen_generic.cpp @@ -0,0 +1,127 @@ +/* +** st_start.cpp +** Generic startup screen +** +**--------------------------------------------------------------------------- +** Copyright 2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "startscreen.h" +#include "filesystem.h" +#include "printf.h" +#include "startupinfo.h" +#include "image.h" +#include "texturemanager.h" + +// Hexen startup screen +#define ST_PROGRESS_X 64 // Start of notches x screen pos. +#define ST_PROGRESS_Y 441 // Start of notches y screen pos. + + +class FGenericStartScreen : public FStartScreen +{ + FBitmap Background; + int NotchPos = 0; + +public: + FGenericStartScreen(int max_progress); + + bool DoProgress(int) override; +}; + + +//========================================================================== +// +// FGenericStartScreen Constructor +// +// Shows the Hexen startup screen. If the screen doesn't appear to be +// valid, it sets hr for a failure. +// +// The startup graphic is a planar, 4-bit 640x480 graphic preceded by a +// 16 entry (48 byte) VGA palette. +// +//========================================================================== + +FGenericStartScreen::FGenericStartScreen(int max_progress) + : FStartScreen(max_progress) +{ + // at this point we do not have a working texture manager yet, so we have to do the lookup via the file system + int startup_lump = fileSystem.CheckNumForName("BOOTLOGO", FileSys::ns_graphics); + + StartupBitmap.Create(640 * 2, 480 * 2); + ClearBlock(StartupBitmap, { 0, 0, 0, 255 }, 0, 0, 640 * 2, 480 * 2); + // This also needs to work if the lump turns out to be unusable. + if (startup_lump != -1) + { + auto iBackground = FImageSource::GetImage(startup_lump, false); + if (iBackground) + { + Background = iBackground->GetCachedBitmap(nullptr, FImageSource::normal); + if (Background.GetWidth() < 640 * 2 || Background.GetHeight() < 480 * 2) + StartupBitmap.Blit(320 * 2 - Background.GetWidth()/2, 220 * 2 - Background.GetHeight() / 2, Background); + else + StartupBitmap.Blit(0, 0, Background, 640 * 2, 480 * 2); + + } + } +} + +//========================================================================== +// +// FGenericStartScreen :: Progress +// +// Bumps the progress meter one notch. +// +//========================================================================== + +bool FGenericStartScreen::DoProgress(int advance) +{ + int notch_pos; + + if (CurPos < MaxPos) + { + RgbQuad bcolor = { 2, 25, 87, 255 }; // todo: make configurable + int numnotches = 200 * 2; + notch_pos = ((CurPos + 1) * numnotches) / MaxPos; + if (notch_pos != NotchPos) + { // Time to draw another notch. + ClearBlock(StartupBitmap, bcolor, (320 - 100) * 2, 480 * 2 - 30, notch_pos, 4 * 2); + NotchPos = notch_pos; + if (StartupTexture) + StartupTexture->CleanHardwareData(true); + } + } + return FStartScreen::DoProgress(advance); +} + + +FStartScreen* CreateGenericStartScreen(int max_progress) +{ + return new FGenericStartScreen(max_progress); +} diff --git a/src/common/startscreen/startscreen_heretic.cpp b/src/common/startscreen/startscreen_heretic.cpp new file mode 100644 index 00000000000..6829436f9b8 --- /dev/null +++ b/src/common/startscreen/startscreen_heretic.cpp @@ -0,0 +1,181 @@ +/* +** st_start.cpp +** Handles the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** Copyright 2006-2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "startscreen.h" +#include "filesystem.h" +#include "printf.h" +#include "texturemanager.h" + + +// Heretic startup screen +#define HERETIC_MINOR_VERSION '3' // Since we're based on Heretic 1.3 +#define THERM_X 14 +#define THERM_Y 14 +#define THERM_LEN 51 +#define THERM_COLOR 0xA // light green + + +class FHereticStartScreen : public FStartScreen +{ + int NotchPos; + int ThermX, ThermY, ThermWidth, ThermHeight; + int HMsgY, SMsgX; +public: + FHereticStartScreen(int max_progress); + + bool DoProgress(int) override; + void LoadingStatus(const char *message, int colors) override; + void AppendStatusLine(const char *status) override; +}; + + +//========================================================================== +// +// FHereticStartScreen Constructor +// +// Shows the Heretic startup screen. If the screen doesn't appear to be +// valid, it returns a failure code in hr. +// +// The loading screen is an 80x25 text screen with character data and +// attributes intermixed, which means it must be exactly 4000 bytes long. +// +//========================================================================== + +FHereticStartScreen::FHereticStartScreen(int max_progress) + : FStartScreen(max_progress) +{ + int loading_lump = fileSystem.CheckNumForName("LOADING"); + uint8_t loading_screen[4000]; + + if (loading_lump < 0 || fileSystem.FileLength(loading_lump) != 4000) + { + I_Error("'LOADING' not found"); + } + + fileSystem.ReadFile(loading_lump, loading_screen); + + // Slap the Heretic minor version on the loading screen. Heretic + // did this inside the executable rather than coming with modified + // LOADING screens, so we need to do the same. + loading_screen[2 * 160 + 49 * 2] = HERETIC_MINOR_VERSION; + + // Draw the loading screen to a bitmap. + StartupBitmap.Create(80 * 8, 25 * 16); + DrawTextScreen(StartupBitmap, loading_screen); + + ThermX = THERM_X * 8; + ThermY = THERM_Y * 16; + ThermWidth = THERM_LEN * 8 - 4; + ThermHeight = 16; + HMsgY = 7; + SMsgX = 1; + NotchPos = 0; + CreateHeader(); +} + +//========================================================================== +// +// FHereticStartScreen::Progress +// +// Bumps the progress meter one notch. +// +//========================================================================== + +bool FHereticStartScreen::DoProgress(int advance) +{ + if (CurPos < MaxPos) + { + int notch_pos = ((CurPos + 1) * ThermWidth) / MaxPos; + if (notch_pos != NotchPos && !(notch_pos & 3)) + { // Time to draw another notch. + int left = NotchPos + ThermX; + int top = ThermY; + int right = notch_pos + ThermX; + int bottom = top + ThermHeight; + ClearBlock(StartupBitmap, TextModePalette[THERM_COLOR], left, top, right - left, bottom - top); + NotchPos = notch_pos; + StartupTexture->CleanHardwareData(true); + } + } + return FStartScreen::DoProgress(advance); +} + +//========================================================================== +// +// FHereticStartScreen :: LoadingStatus +// +// Prints text in the center box of the startup screen. +// +//========================================================================== + +void FHereticStartScreen::LoadingStatus(const char* message, int colors) +{ + int x; + + for (x = 0; message[x] != '\0'; ++x) + { + DrawChar(StartupBitmap, 17 + x, HMsgY, message[x], colors); + } + HMsgY++; + StartupTexture->CleanHardwareData(true); + Render(); +} + +//========================================================================== +// +// FHereticStartScreen :: AppendStatusLine +// +// Appends text to Heretic's status line. +// +//========================================================================== + +void FHereticStartScreen::AppendStatusLine(const char* status) +{ + int x; + + for (x = 0; status[x] != '\0'; ++x) + { + DrawChar(StartupBitmap, SMsgX + x, 24, status[x], 0x1f); + } + SMsgX += x; + StartupTexture->CleanHardwareData(true); + Render(); +} + + +FStartScreen* CreateHereticStartScreen(int max_progress) +{ + return new FHereticStartScreen(max_progress); +} diff --git a/src/common/startscreen/startscreen_hexen.cpp b/src/common/startscreen/startscreen_hexen.cpp new file mode 100644 index 00000000000..a82e21b3518 --- /dev/null +++ b/src/common/startscreen/startscreen_hexen.cpp @@ -0,0 +1,212 @@ +/* +** st_start.cpp +** Handles the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** Copyright 2006-2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "startscreen.h" +#include "filesystem.h" +#include "printf.h" +#include "startupinfo.h" +#include "s_music.h" +#include "image.h" +#include "texturemanager.h" + +// Hexen startup screen +#define ST_PROGRESS_X 64 // Start of notches x screen pos. +#define ST_PROGRESS_Y 441 // Start of notches y screen pos. + +#define ST_NETPROGRESS_X 288 +#define ST_NETPROGRESS_Y 32 + +class FHexenStartScreen : public FStartScreen +{ + // Hexen's notch graphics, converted to chunky pixels. + FBitmap Background; + FBitmap NotchBits; + FBitmap NetNotchBits; + int NotchPos = 0; + +public: + FHexenStartScreen(int max_progress); + + bool DoProgress(int) override; + void DoNetProgress(int count) override; + void NetDone() override; +}; + + +//========================================================================== +// +// FHexenStartScreen Constructor +// +// Shows the Hexen startup screen. If the screen doesn't appear to be +// valid, it sets hr for a failure. +// +// The startup graphic is a planar, 4-bit 640x480 graphic preceded by a +// 16 entry (48 byte) VGA palette. +// +//========================================================================== + +FHexenStartScreen::FHexenStartScreen(int max_progress) + : FStartScreen(max_progress) +{ + // at this point we do not have a working texture manager yet, so we have to do the lookup via the file system + int startup_lump = fileSystem.CheckNumForName("STARTUP", FileSys::ns_graphics); + int netnotch_lump = fileSystem.CheckNumForName("NETNOTCH", FileSys::ns_graphics); + int notch_lump = fileSystem.CheckNumForName("NOTCH", FileSys::ns_graphics); + + // For backwards compatibility we also need to look in the default namespace, because these were previously not handled as graphics. + if (startup_lump == -1) startup_lump = fileSystem.CheckNumForName("STARTUP"); + if (netnotch_lump == -1)netnotch_lump = fileSystem.CheckNumForName("NETNOTCH"); + if (notch_lump == -1)notch_lump = fileSystem.CheckNumForName("NOTCH"); + + + if (startup_lump < 0 || netnotch_lump < 0 || notch_lump < 0) + { + I_Error("Start screen assets missing"); + } + + auto iBackground = FImageSource::GetImage(startup_lump, false); + auto iNetNotchBits = FImageSource::GetImage(netnotch_lump, false); + auto iNotchBits = FImageSource::GetImage(notch_lump, false); + if (!iBackground || !iNetNotchBits || !iNotchBits || iBackground->GetWidth() != 640 || iBackground->GetHeight() != 480) + { + I_Error("Start screen assets missing"); + } + NetNotchBits = iNetNotchBits->GetCachedBitmap(nullptr, FImageSource::normal); + NotchBits = iNotchBits->GetCachedBitmap(nullptr, FImageSource::normal); + Background = iBackground->GetCachedBitmap(nullptr, FImageSource::normal); + + StartupBitmap.Create(640, 480); + StartupBitmap.Blit(0, 0, Background, 640, 480); + + // Fill in the bitmap data. Convert to chunky, because I can't figure out + // if Windows actually supports planar images or not, despite the presence + // of biPlanes in the BITMAPINFOHEADER. + + + if (!batchrun) + { + if (GameStartupInfo.Song.IsNotEmpty()) + { + S_ChangeMusic(GameStartupInfo.Song.GetChars(), true, true); + } + else + { + S_ChangeMusic("orb", true, true); + } + } + CreateHeader(); +} + +//========================================================================== +// +// FHexenStartScreen :: Progress +// +// Bumps the progress meter one notch. +// +//========================================================================== + +bool FHexenStartScreen::DoProgress(int advance) +{ + int notch_pos, x, y; + + if (CurPos <= MaxPos) + { + int numnotches = (16 * 32) / NotchBits.GetWidth(); + notch_pos = ((CurPos + 1) * numnotches) / MaxPos; + if (notch_pos != NotchPos) + { // Time to draw another notch. + for (; NotchPos < notch_pos; NotchPos++) + { + x = ST_PROGRESS_X + NotchBits.GetWidth() * NotchPos; + y = ST_PROGRESS_Y; + StartupBitmap.Blit(x, y, NotchBits); + } + StartupTexture->CleanHardwareData(true); + ST_Sound("StartupTick"); + } + } + return FStartScreen::DoProgress(advance); +} + +//========================================================================== +// +// FHexenStartScreen :: NetProgress +// +// Draws the red net noches in addition to the normal progress bar. +// +//========================================================================== + +void FHexenStartScreen::DoNetProgress(int count) +{ + int oldpos = NetCurPos; + int x, y; + + FStartScreen::NetProgress(count); + + if (NetMaxPos != 0 && NetCurPos > oldpos) + { + int numnotches = (4 * 8) / NetNotchBits.GetWidth(); + int notch_pos = (NetCurPos * numnotches) / NetMaxPos; + + for (; oldpos < NetCurPos && oldpos < numnotches; ++oldpos) + { + x = ST_NETPROGRESS_X + NetNotchBits.GetWidth() * oldpos; + y = ST_NETPROGRESS_Y; + StartupBitmap.Blit(x, y, NetNotchBits); + } + ST_Sound("misc/netnotch"); + StartupTexture->CleanHardwareData(true); + } +} + +//========================================================================== +// +// FHexenStartScreen :: NetDone +// +// Aside from the standard processing, also plays a sound. +// +//========================================================================== + +void FHexenStartScreen::NetDone() +{ + ST_Sound("PickupWeapon"); + FStartScreen::NetDone(); +} + + +FStartScreen* CreateHexenStartScreen(int max_progress) +{ + return new FHexenStartScreen(max_progress); +} diff --git a/src/common/startscreen/startscreen_strife.cpp b/src/common/startscreen/startscreen_strife.cpp new file mode 100644 index 00000000000..df5467f9660 --- /dev/null +++ b/src/common/startscreen/startscreen_strife.cpp @@ -0,0 +1,195 @@ +/* +** st_start.cpp +** Handles the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** Copyright 2006-2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "startscreen.h" +#include "filesystem.h" +#include "printf.h" +#include "image.h" +#include "textures.h" +#include "palettecontainer.h" +#include "cmdlib.h" + +// Strife startup screen +#define PEASANT_INDEX 0 +#define LASER_INDEX 4 +#define BOT_INDEX 6 + +#define ST_LASERSPACE_X 60 +#define ST_LASERSPACE_Y 156 +#define ST_LASERSPACE_WIDTH 200 +#define ST_LASER_WIDTH 16 +#define ST_LASER_HEIGHT 16 + +#define ST_BOT_X 14 +#define ST_BOT_Y 138 +#define ST_BOT_WIDTH 48 +#define ST_BOT_HEIGHT 48 + +#define ST_PEASANT_X 262 +#define ST_PEASANT_Y 136 +#define ST_PEASANT_WIDTH 32 +#define ST_PEASANT_HEIGHT 64 + +static const char* StrifeStartupPicNames[] = +{ + "STRTPA1", "STRTPB1", "STRTPC1", "STRTPD1", + "STRTLZ1", "STRTLZ2", + "STRTBOT", + "STARTUP0" +}; + + + +class FStrifeStartScreen : public FStartScreen +{ +public: + FStrifeStartScreen(int max_progress); + + bool DoProgress(int) override; +protected: + void DrawStuff(int old_laser, int new_laser); + + FBitmap StartupPics[4+2+1+1]; + int NotchPos = 0; +}; + + +//========================================================================== +// +// FStrifeStartScreen Constructor +// +// Shows the Strife startup screen. If the screen doesn't appear to be +// valid, it returns a failure code in hr. +// +// The startup background is a raw 320x200 image, however Strife only +// actually uses 95 rows from it, starting at row 57. The rest of the image +// is discarded. (What a shame.) +// +// The peasants are raw 32x64 images. The laser dots are raw 16x16 images. +// The bot is a raw 48x48 image. All use the standard PLAYPAL. +// +//========================================================================== + +FStrifeStartScreen::FStrifeStartScreen(int max_progress) + : FStartScreen(max_progress) +{ + StartupBitmap.Create(320, 200); + + // at this point we do not have a working texture manager yet, so we have to do the lookup via the file system + // Load the background and animated overlays. + for (size_t i = 0; i < countof(StrifeStartupPicNames); ++i) + { + int lumpnum = fileSystem.CheckNumForName(StrifeStartupPicNames[i], FileSys::ns_graphics); + if (lumpnum < 0) lumpnum = fileSystem.CheckNumForName(StrifeStartupPicNames[i]); + + if (lumpnum >= 0) + { + auto lumpr1 = FImageSource::GetImage(lumpnum, false); + if (lumpr1) StartupPics[i] = lumpr1->GetCachedBitmap(nullptr, FImageSource::normal); + } + } + if (StartupPics[7].GetWidth() != 320 || StartupPics[7].GetHeight() != 200) + { + I_Error("bad startscreen assets"); + } + + // Make the startup image appear. + DrawStuff(0, 0); + Scale = 2; + CreateHeader(); +} + +//========================================================================== +// +// FStrifeStartScreen :: Progress +// +// Bumps the progress meter one notch. +// +//========================================================================== + +bool FStrifeStartScreen::DoProgress(int advance) +{ + int notch_pos; + + if (CurPos < MaxPos) + { + notch_pos = ((CurPos + 1) * (ST_LASERSPACE_WIDTH - ST_LASER_WIDTH)) / MaxPos; + if (notch_pos != NotchPos && !(notch_pos & 1)) + { // Time to update. + DrawStuff(NotchPos, notch_pos); + NotchPos = notch_pos; + StartupTexture->CleanHardwareData(true); + } + } + return FStartScreen::DoProgress(advance); +} + +//========================================================================== +// +// FStrifeStartScreen :: DrawStuff +// +// Draws all the moving parts of Strife's startup screen. If you're +// running off a slow drive, it can look kind of good. Otherwise, it +// borders on crazy insane fast. +// +//========================================================================== + +void FStrifeStartScreen::DrawStuff(int old_laser, int new_laser) +{ + int y; + + // Clear old laser + StartupBitmap.Blit(0, 0, StartupPics[7]); + + // Draw new laser + auto& lp = StartupPics[LASER_INDEX + (new_laser & 1)]; + StartupBitmap.Blit(ST_LASERSPACE_X + new_laser, ST_LASERSPACE_Y, lp); + + // The bot jumps up and down like crazy. + y = max(0, (new_laser >> 1) % 5 - 2); + + StartupBitmap.Blit(ST_BOT_X, ST_BOT_Y + y, StartupPics[BOT_INDEX]); + + // The peasant desperately runs in place, trying to get away from the laser. + // Yet, despite all his limb flailing, he never manages to get anywhere. + auto& pp = StartupPics[PEASANT_INDEX + ((new_laser >> 1) & 3)]; + StartupBitmap.Blit(ST_PEASANT_X, ST_PEASANT_Y, pp); +} + + +FStartScreen* CreateStrifeStartScreen(int max_progress) +{ + return new FStrifeStartScreen(max_progress); +} diff --git a/src/common/statusbar/base_sbar.cpp b/src/common/statusbar/base_sbar.cpp new file mode 100644 index 00000000000..51950e8b29b --- /dev/null +++ b/src/common/statusbar/base_sbar.cpp @@ -0,0 +1,966 @@ +/* +** base_sbar.cpp +** Base status bar implementation +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2017-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include + + +#include "base_sbar.h" +#include "printf.h" +#include "v_draw.h" +#include "cmdlib.h" +#include "texturemanager.h" +#include "c_cvars.h" +#include "v_font.h" +#include "utf8.h" +#include "v_text.h" +#include "vm.h" +#include "i_interface.h" +#include "r_videoscale.h" + +FGameTexture* CrosshairImage; +static int CrosshairNum; + + +IMPLEMENT_CLASS(DStatusBarCore, false, false) +IMPLEMENT_CLASS(DHUDFont, false, false); + + +CVAR(Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE); +CVAR(Int, crosshairhealth, 2, CVAR_ARCHIVE); +CVARD(Float, crosshairscale, 0.5, CVAR_ARCHIVE, "changes the size of the crosshair"); +CVAR(Bool, crosshairgrow, false, CVAR_ARCHIVE); + +CUSTOM_CVARD(Float, hud_scalefactor, 1.f, CVAR_ARCHIVE, "changes the hud scale") +{ + if (self < 0.36f) self = 0.36f; + else if (self > 1) self = 1; + else if (sysCallbacks.HudScaleChanged) sysCallbacks.HudScaleChanged(); +} + +CUSTOM_CVARD(Bool, hud_aspectscale, true, CVAR_ARCHIVE, "enables aspect ratio correction for the status bar") +{ + if (sysCallbacks.HudScaleChanged) sysCallbacks.HudScaleChanged(); +} + + +void ST_LoadCrosshair(int num, bool alwaysload) +{ + char name[16]; + char size; + + if (!alwaysload && CrosshairNum == num && CrosshairImage != NULL) + { // No change. + return; + } + + if (num == 0) + { + CrosshairNum = 0; + CrosshairImage = NULL; + return; + } + if (num < 0) + { + num = -num; + } + size = (twod->GetWidth() < 640) ? 'S' : 'B'; + + mysnprintf(name, countof(name), "XHAIR%c%d", size, num); + FTextureID texid = TexMan.CheckForTexture(name, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly); + if (!texid.isValid()) + { + mysnprintf(name, countof(name), "XHAIR%c1", size); + texid = TexMan.CheckForTexture(name, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly); + if (!texid.isValid()) + { + texid = TexMan.CheckForTexture("XHAIRS1", ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly); + } + } + CrosshairNum = num; + CrosshairImage = TexMan.GetGameTexture(texid); +} + +void ST_UnloadCrosshair() +{ + CrosshairImage = NULL; + CrosshairNum = 0; +} + + +//--------------------------------------------------------------------------- +// +// DrawCrosshair +// +//--------------------------------------------------------------------------- + +void ST_DrawCrosshair(int phealth, double xpos, double ypos, double scale, DAngle angle) +{ + uint32_t color; + double size; + int w, h; + + // Don't draw the crosshair if there is none + if (CrosshairImage == NULL) + { + return; + } + + if (crosshairscale > 0.0f) + { + size = twod->GetHeight() * crosshairscale * 0.005; + } + else + { + size = 1.; + } + + if (crosshairgrow) + { + size *= scale; + } + + w = int(CrosshairImage->GetDisplayWidth() * size); + h = int(CrosshairImage->GetDisplayHeight() * size); + + if (crosshairhealth == 1) + { + // "Standard" crosshair health (green-red) + int health = phealth; + + if (health >= 85) + { + color = 0x00ff00; + } + else + { + int red, green; + health -= 25; + if (health < 0) + { + health = 0; + } + if (health < 30) + { + red = 255; + green = health * 255 / 30; + } + else + { + red = (60 - health) * 255 / 30; + green = 255; + } + color = (red << 16) | (green << 8); + } + } + else if (crosshairhealth == 2) + { + // "Enhanced" crosshair health (blue-green-yellow-red) + int health = clamp(phealth, 0, 200); + float rr, gg, bb; + + float saturation = health < 150 ? 1.f : 1.f - (health - 150) / 100.f; + + HSVtoRGB(&rr, &gg, &bb, health * 1.2f, saturation, 1); + int red = int(rr * 255); + int green = int(gg * 255); + int blue = int(bb * 255); + + color = (red << 16) | (green << 8) | blue; + } + else + { + color = crosshaircolor; + } + + DrawTexture(twod, CrosshairImage, + xpos, ypos, + DTA_DestWidth, w, + DTA_DestHeight, h, + DTA_Rotate, angle.Degrees(), + DTA_AlphaChannel, true, + DTA_FillColor, color & 0xFFFFFF, + TAG_DONE); +} + + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +enum ENumFlags +{ + FNF_WHENNOTZERO = 0x1, + FNF_FILLZEROS = 0x2, +}; + +void FormatNumber(int number, int minsize, int maxsize, int flags, const FString& prefix, FString* result) +{ + static int maxvals[] = { 1, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999 }; + + if (number == 0 && (flags & FNF_WHENNOTZERO)) + { + *result = ""; + return; + } + if (maxsize > 0 && maxsize < 10) + { + number = clamp(number, -maxvals[maxsize - 1], maxvals[maxsize]); + } + FString& fmt = *result; + if (minsize <= 1) fmt.Format("%s%d", prefix.GetChars(), number); + else if (flags & FNF_FILLZEROS) fmt.Format("%s%0*d", prefix.GetChars(), minsize, number); + else fmt.Format("%s%*d", prefix.GetChars(), minsize, number); +} + +void DStatusBarCore::ValidateResolution(int& hres, int& vres) const +{ + if (hres == 0) + { + static const int HORIZONTAL_RESOLUTION_DEFAULT = 320; + hres = HORIZONTAL_RESOLUTION_DEFAULT; + } + + if (vres == 0) + { + static const int VERTICAL_RESOLUTION_DEFAULT = 200; + vres = VERTICAL_RESOLUTION_DEFAULT; + } +} + + +//============================================================================ +// +// +// +//============================================================================ + +void DStatusBarCore::SetSize(int reltop, int hres, int vres, int hhres, int hvres) +{ + ValidateResolution(hres, vres); + + BaseRelTop = reltop; + BaseSBarHorizontalResolution = hres; + BaseSBarVerticalResolution = vres; + BaseHUDHorizontalResolution = hhres < 0 ? hres : hhres; + BaseHUDVerticalResolution = hvres < 0 ? vres : hvres; + SetDrawSize(reltop, hres, vres); +} + +//============================================================================ +// +// calculates a clean scale for the status bar +// +//============================================================================ + +static void ST_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realheight, int* cleanx, int* cleany) +{ + float ratio; + int cwidth; + int cheight; + int cx1, cy1, cx2, cy2; + + ratio = ActiveRatio(realwidth, realheight); + if (AspectTallerThanWide(ratio)) + { + cwidth = realwidth; + cheight = realheight * AspectMultiplier(ratio) / 48; + } + else + { + cwidth = realwidth * AspectMultiplier(ratio) / 48; + cheight = realheight; + } + // Use whichever pair of cwidth/cheight or width/height that produces less difference + // between CleanXfac and CleanYfac. + cx1 = max(cwidth / designwidth, 1); + cy1 = max(cheight / designheight, 1); + cx2 = max(realwidth / designwidth, 1); + cy2 = max(realheight / designheight, 1); + if (abs(cx1 - cy1) <= abs(cx2 - cy2) || max(cx1, cx2) >= 4) + { // e.g. 640x360 looks better with this. + *cleanx = cx1; + *cleany = cy1; + } + else + { // e.g. 720x480 looks better with this. + *cleanx = cx2; + *cleany = cy2; + } + + if (*cleanx < *cleany) + *cleany = *cleanx; + else + *cleanx = *cleany; +} + +//============================================================================ +// +// +// +//============================================================================ + +void DStatusBarCore::SetDrawSize(int reltop, int hres, int vres) +{ + ValidateResolution(hres, vres); + + RelTop = reltop; + HorizontalResolution = hres; + VerticalResolution = vres; + + int x, y; + ST_CalcCleanFacs(hres, vres, twod->GetWidth(), twod->GetHeight(), &x, &y); + defaultScale = { (double)x, (double)y }; + + SetScale(); // recalculate positioning info. +} + +//--------------------------------------------------------------------------- +// +// PROC SetScaled +// +//--------------------------------------------------------------------------- + +void DStatusBarCore::SetScale() +{ + ValidateResolution(HorizontalResolution, VerticalResolution); + + int w = twod->GetWidth(); + int h = twod->GetHeight(); + double refw, refh; + + int horz = HorizontalResolution; + int vert = VerticalResolution; + double refaspect = horz / double(vert); + double screenaspect = w / double(h); + double aspectscale = 1.0; + + const double ViewportAspect = 1. / ViewportPixelAspect(); + + if ((horz == 320 && vert == 200) || (horz == 640 && vert == 400)) + { + refaspect = (4. / 3.); + if (!hud_aspectscale) aspectscale = 1 / 1.2; + } + + if (screenaspect < refaspect) + { + refw = w; + refh = w / refaspect; + } + else + { + refh = h; + refw = h * refaspect; + } + refw *= hud_scalefactor; + refh *= hud_scalefactor * aspectscale * ViewportAspect; + + int sby = vert - int(RelTop * hud_scalefactor * aspectscale * ViewportAspect); + // Use full pixels for destination size. + + ST_X = xs_CRoundToInt((w - refw) / 2); + ST_Y = xs_CRoundToInt(h - refh); + SBarTop = Scale(sby, h, vert); + SBarScale.X = refw / horz; + SBarScale.Y = refh / vert; +} + +//--------------------------------------------------------------------------- +// +// PROC GetHUDScale +// +//--------------------------------------------------------------------------- + +DVector2 DStatusBarCore::GetHUDScale() const +{ + return SBarScale; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void DStatusBarCore::BeginStatusBar(int resW, int resH, int relTop, bool forceScaled) +{ + SetDrawSize(relTop < 0 ? BaseRelTop : relTop, resW < 0 ? BaseSBarHorizontalResolution : resW, resH < 0 ? BaseSBarVerticalResolution : resH); + ForcedScale = forceScaled; + fullscreenOffsets = false; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void DStatusBarCore::BeginHUD(int resW, int resH, double Alpha, bool forcescaled) +{ + SetDrawSize(RelTop, resW < 0 ? BaseHUDHorizontalResolution : resW, resH < 0 ? BaseHUDVerticalResolution : resH); + this->Alpha = Alpha; + ForcedScale = forcescaled; + CompleteBorder = false; + fullscreenOffsets = true; +} + +//============================================================================ +// +// draw stuff +// +//============================================================================ + +void DStatusBarCore::StatusbarToRealCoords(double& x, double& y, double& w, double& h) const +{ + if (SBarScale.X == -1 || ForcedScale) + { + int hres = HorizontalResolution; + int vres = VerticalResolution; + ValidateResolution(hres, vres); + + VirtualToRealCoords(twod, x, y, w, h, hres, vres, true, true); + } + else + { + x = ST_X + x * SBarScale.X; + y = ST_Y + y * SBarScale.Y; + w *= SBarScale.X; + h *= SBarScale.Y; + } +} + +//============================================================================ +// +// draw stuff +// +//============================================================================ + +void DStatusBarCore::DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, ERenderStyle style, PalEntry color, int translation, double clipwidth) +{ + if (!texture.isValid()) + return; + + FGameTexture* tex = TexMan.GetGameTexture(texture, !(flags & DI_DONTANIMATE)); + DrawGraphic(tex, x, y, flags, Alpha, boxwidth, boxheight, scaleX, scaleY, style, color, translation, clipwidth); +} + +void DStatusBarCore::DrawGraphic(FGameTexture* tex, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, ERenderStyle style, PalEntry color, int translation, double clipwidth) +{ + double texwidth = tex->GetDisplayWidth() * scaleX; + double texheight = tex->GetDisplayHeight() * scaleY; + double texleftoffs = tex->GetDisplayLeftOffset() * scaleY; + double textopoffs = tex->GetDisplayTopOffset() * scaleY; + double boxleftoffs = 0, boxtopoffs = 0; + + if (boxwidth > 0 || boxheight > 0) + { + if (!(flags & DI_FORCEFILL)) + { + double scale1 = 1., scale2 = 1.; + + if (boxwidth > 0 && (boxwidth < texwidth || (flags & DI_FORCESCALE))) + { + scale1 = boxwidth / texwidth; + } + if (boxheight != -1 && (boxheight < texheight || (flags & DI_FORCESCALE))) + { + scale2 = boxheight / texheight; + } + + if (flags & DI_FORCESCALE) + { + if (boxwidth <= 0 || (boxheight > 0 && scale2 < scale1)) + scale1 = scale2; + } + else scale1 = min(scale1, scale2); + + boxwidth = texwidth * scale1; + boxheight = texheight * scale1; + boxleftoffs = texleftoffs * scale1; + boxtopoffs = textopoffs * scale1; + } + } + else + { + boxwidth = texwidth; + boxheight = texheight; + boxleftoffs = texleftoffs; + boxtopoffs = textopoffs; + } + + // resolve auto-alignment before making any adjustments to the position values. + if (!(flags & DI_SCREEN_MANUAL_ALIGN)) + { + if (x < 0) flags |= DI_SCREEN_RIGHT; + else flags |= DI_SCREEN_LEFT; + if (y < 0) flags |= DI_SCREEN_BOTTOM; + else flags |= DI_SCREEN_TOP; + } + + Alpha *= this->Alpha; + if (Alpha <= 0) return; + x += drawOffset.X; + y += drawOffset.Y; + + if (flags & DI_ITEM_RELCENTER) + { + if (flags & DI_MIRROR) boxleftoffs = -boxleftoffs; + if (flags & DI_MIRRORY) boxtopoffs = -boxtopoffs; + x -= boxwidth / 2 + boxleftoffs; + y -= boxheight / 2 + boxtopoffs; + } + else + { + switch (flags & DI_ITEM_HMASK) + { + case DI_ITEM_HCENTER: x -= boxwidth / 2; break; + case DI_ITEM_RIGHT: x -= boxwidth; break; + case DI_ITEM_HOFFSET: x -= boxleftoffs; break; + } + + switch (flags & DI_ITEM_VMASK) + { + case DI_ITEM_VCENTER: y -= boxheight / 2; break; + case DI_ITEM_BOTTOM: y -= boxheight; break; + case DI_ITEM_VOFFSET: y -= boxtopoffs; break; + } + } + + if (!fullscreenOffsets) + { + StatusbarToRealCoords(x, y, boxwidth, boxheight); + } + else + { + double orgx, orgy; + + switch (flags & DI_SCREEN_HMASK) + { + default: orgx = 0; break; + case DI_SCREEN_HCENTER: orgx = twod->GetWidth() / 2; break; + case DI_SCREEN_RIGHT: orgx = twod->GetWidth(); break; + } + + switch (flags & DI_SCREEN_VMASK) + { + default: orgy = 0; break; + case DI_SCREEN_VCENTER: orgy = twod->GetHeight() / 2; break; + case DI_SCREEN_BOTTOM: orgy = twod->GetHeight(); break; + } + + DVector2 Scale = GetHUDScale(); + + x *= Scale.X; + y *= Scale.Y; + boxwidth *= Scale.X; + boxheight *= Scale.Y; + x += orgx; + y += orgy; + } + DrawTexture(twod, tex, x, y, + DTA_TopOffset, 0, + DTA_LeftOffset, 0, + DTA_DestWidthF, boxwidth, + DTA_DestHeightF, boxheight, + DTA_ClipLeft, 0, + DTA_ClipTop, 0, + DTA_ClipBottom, twod->GetHeight(), + DTA_ClipRight, clipwidth < 0? twod->GetWidth() : int(x + boxwidth * clipwidth), + DTA_Color, color, + DTA_TranslationIndex, translation? translation : (flags & DI_TRANSLATABLE) ? GetTranslation().index() : 0, + DTA_ColorOverlay, (flags & DI_DIM) ? MAKEARGB(170, 0, 0, 0) : 0, + DTA_Alpha, Alpha, + DTA_AlphaChannel, !!(flags & DI_ALPHAMAPPED), + DTA_FillColor, (flags & DI_ALPHAMAPPED) ? 0 : -1, + DTA_FlipX, !!(flags & DI_MIRROR), + DTA_FlipY, !!(flags& DI_MIRRORY), + DTA_LegacyRenderStyle, (flags & DI_ALPHAMAPPED) ? STYLE_Shaded : style, + TAG_DONE); +} + + +//============================================================================ +// +// draw stuff +// +//============================================================================ + +void DStatusBarCore::DrawRotated(FTextureID texture, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style) +{ + if (!texture.isValid()) + return; + + FGameTexture* tex = TexMan.GetGameTexture(texture, !(flags & DI_DONTANIMATE)); + DrawRotated(tex, x, y, flags, angle, Alpha, scaleX, scaleY, color, translation, style); +} + +void DStatusBarCore::DrawRotated(FGameTexture* tex, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style) +{ + double texwidth = tex->GetDisplayWidth() * scaleX; + double texheight = tex->GetDisplayHeight() * scaleY; + + // resolve auto-alignment before making any adjustments to the position values. + if (!(flags & DI_SCREEN_MANUAL_ALIGN)) + { + if (x < 0) flags |= DI_SCREEN_RIGHT; + else flags |= DI_SCREEN_LEFT; + if (y < 0) flags |= DI_SCREEN_BOTTOM; + else flags |= DI_SCREEN_TOP; + } + + Alpha *= this->Alpha; + if (Alpha <= 0) return; + x += drawOffset.X; + y += drawOffset.Y; + DVector2 Scale = GetHUDScale(); + + scaleX = 1 / scaleX; + scaleY = 1 / scaleY; + + if (!fullscreenOffsets) + { + StatusbarToRealCoords(x, y, texwidth, texheight); + } + else + { + double orgx, orgy; + + switch (flags & DI_SCREEN_HMASK) + { + default: orgx = 0; break; + case DI_SCREEN_HCENTER: orgx = twod->GetWidth() / 2; break; + case DI_SCREEN_RIGHT: orgx = twod->GetWidth(); break; + } + + switch (flags & DI_SCREEN_VMASK) + { + default: orgy = 0; break; + case DI_SCREEN_VCENTER: orgy = twod->GetHeight() / 2; break; + case DI_SCREEN_BOTTOM: orgy = twod->GetHeight(); break; + } + + x *= Scale.X; + y *= Scale.Y; + scaleX *= Scale.X; + scaleY *= Scale.Y; + x += orgx; + y += orgy; + } + DrawTexture(twod, tex, x, y, + DTA_ScaleX, scaleX, + DTA_ScaleY, scaleY, + DTA_Color, color, + DTA_CenterOffsetRel, !!(flags & DI_ITEM_RELCENTER), + DTA_Rotate, angle, + DTA_TranslationIndex, translation ? translation : (flags & DI_TRANSLATABLE) ? GetTranslation().index() : 0, + DTA_ColorOverlay, (flags & DI_DIM) ? MAKEARGB(170, 0, 0, 0) : 0, + DTA_Alpha, Alpha, + DTA_AlphaChannel, !!(flags & DI_ALPHAMAPPED), + DTA_FillColor, (flags & DI_ALPHAMAPPED) ? 0 : -1, + DTA_FlipX, !!(flags & DI_MIRROR), + DTA_FlipY, !!(flags & DI_MIRRORY), + DTA_LegacyRenderStyle, style, + TAG_DONE); +} + + +//============================================================================ +// +// draw a string +// +//============================================================================ + +void DStatusBarCore::DrawString(FFont* font, const FString& cstring, double x, double y, int flags, double Alpha, int translation, int spacing, EMonospacing monospacing, int shadowX, int shadowY, double scaleX, double scaleY, FTranslationID pt, int style) +{ + bool monospaced = monospacing != EMonospacing::Off; + double dx = 0; + int spacingparm = monospaced ? -spacing : spacing; + + switch (flags & DI_TEXT_ALIGN) + { + default: + break; + case DI_TEXT_ALIGN_RIGHT: + dx = font->StringWidth(cstring, spacingparm); + break; + case DI_TEXT_ALIGN_CENTER: + dx = font->StringWidth(cstring, spacingparm) / 2; + break; + } + + // Take text scale into account + x -= dx * scaleX; + + const uint8_t* str = (const uint8_t*)cstring.GetChars(); + const EColorRange boldTranslation = EColorRange(translation ? translation - 1 : NumTextColors - 1); + int fontcolor = translation; + double orgx = 0, orgy = 0; + DVector2 Scale; + + if (fullscreenOffsets) + { + Scale = GetHUDScale(); + shadowX *= (int)Scale.X; + shadowY *= (int)Scale.Y; + + switch (flags & DI_SCREEN_HMASK) + { + default: orgx = 0; break; + case DI_SCREEN_HCENTER: orgx = twod->GetWidth() / 2; break; + case DI_SCREEN_RIGHT: orgx = twod->GetWidth(); break; + } + + switch (flags & DI_SCREEN_VMASK) + { + default: orgy = 0; break; + case DI_SCREEN_VCENTER: orgy = twod->GetHeight() / 2; break; + case DI_SCREEN_BOTTOM: orgy = twod->GetHeight(); break; + } + } + else + { + Scale = { 1.,1. }; + } + int ch; + while (ch = GetCharFromString(str), ch != '\0') + { + if (ch == ' ') + { + x += (monospaced ? spacing : font->GetSpaceWidth() + spacing) * scaleX; + continue; + } + else if (ch == TEXTCOLOR_ESCAPE) + { + EColorRange newColor = V_ParseFontColor(str, translation, boldTranslation); + if (newColor != CR_UNDEFINED) + fontcolor = newColor; + continue; + } + + int width; + FGameTexture* c = font->GetChar(ch, fontcolor, &width); + if (c == NULL) //missing character. + { + continue; + } + width += font->GetDefaultKerning(); + + if (!monospaced) //If we are monospaced lets use the offset + x += (c->GetDisplayLeftOffset() * scaleX + 1); //ignore x offsets since we adapt to character size + + double rx, ry, rw, rh; + rx = x + drawOffset.X; + ry = y + drawOffset.Y; + rw = c->GetDisplayWidth(); + rh = c->GetDisplayHeight(); + + if (monospacing == EMonospacing::CellCenter) + rx += (spacing - rw) / 2; + else if (monospacing == EMonospacing::CellRight) + rx += (spacing - rw); + + if (!fullscreenOffsets) + { + StatusbarToRealCoords(rx, ry, rw, rh); + } + else + { + rx *= Scale.X; + ry *= Scale.Y; + rw *= Scale.X; + rh *= Scale.Y; + + rx += orgx; + ry += orgy; + } + + // Apply text scale + rw *= scaleX; + rh *= scaleY; + + // This is not really such a great way to draw shadows because they can overlap with previously drawn characters. + // This may have to be changed to draw the shadow text up front separately. + if ((shadowX != 0 || shadowY != 0) && !(flags & DI_NOSHADOW)) + { + DrawChar(twod, font, CR_UNTRANSLATED, rx + shadowX, ry + shadowY, ch, + DTA_DestWidthF, rw, + DTA_DestHeightF, rh, + DTA_Alpha, (Alpha * 0.4), + DTA_FillColor, 0, + TAG_DONE); + } + DrawChar(twod, font, pt == NO_TRANSLATION? fontcolor : CR_NATIVEPAL, rx, ry, ch, + DTA_DestWidthF, rw, + DTA_DestHeightF, rh, + DTA_Alpha, Alpha, + DTA_TranslationIndex, pt.index(), + DTA_LegacyRenderStyle, ERenderStyle(style), + TAG_DONE); + + // Take text scale into account + dx = monospaced + ? spacing * scaleX + : (double(width) + spacing - c->GetDisplayLeftOffset()) * scaleX - 1; + + x += dx; + } +} + +void SBar_DrawString(DStatusBarCore* self, DHUDFont* font, const FString& string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY, int pt_, int style) +{ + if (font == nullptr || font->mFont == nullptr) ThrowAbortException(X_READ_NIL, nullptr); + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + auto pt = FTranslationID::fromInt(pt_); + + // resolve auto-alignment before making any adjustments to the position values. + if (!(flags & DI_SCREEN_MANUAL_ALIGN)) + { + if (x < 0) flags |= DI_SCREEN_RIGHT; + else flags |= DI_SCREEN_LEFT; + if (y < 0) flags |= DI_SCREEN_BOTTOM; + else flags |= DI_SCREEN_TOP; + } + + if (wrapwidth > 0) + { + auto brk = V_BreakLines(font->mFont, int(wrapwidth * scaleX), string, true); + for (auto& line : brk) + { + self->DrawString(font->mFont, line.Text, x, y, flags, alpha, trans, font->mSpacing, font->mMonospacing, font->mShadowX, font->mShadowY, scaleX, scaleY, pt, style); + y += (font->mFont->GetHeight() + linespacing) * scaleY; + } + } + else + { + self->DrawString(font->mFont, string, x, y, flags, alpha, trans, font->mSpacing, font->mMonospacing, font->mShadowX, font->mShadowY, scaleX, scaleY, pt, style); + } +} + + +//============================================================================ +// +// draw stuff +// +//============================================================================ + +void DStatusBarCore::TransformRect(double& x, double& y, double& w, double& h, int flags) +{ + // resolve auto-alignment before making any adjustments to the position values. + if (!(flags & DI_SCREEN_MANUAL_ALIGN)) + { + if (x < 0) flags |= DI_SCREEN_RIGHT; + else flags |= DI_SCREEN_LEFT; + if (y < 0) flags |= DI_SCREEN_BOTTOM; + else flags |= DI_SCREEN_TOP; + } + + x += drawOffset.X; + y += drawOffset.Y; + + if (!fullscreenOffsets) + { + StatusbarToRealCoords(x, y, w, h); + } + else + { + double orgx, orgy; + + switch (flags & DI_SCREEN_HMASK) + { + default: orgx = 0; break; + case DI_SCREEN_HCENTER: orgx = twod->GetWidth() / 2; break; + case DI_SCREEN_RIGHT: orgx = twod->GetWidth(); break; + } + + switch (flags & DI_SCREEN_VMASK) + { + default: orgy = 0; break; + case DI_SCREEN_VCENTER: orgy = twod->GetHeight() / 2; break; + case DI_SCREEN_BOTTOM: orgy = twod->GetHeight(); break; + } + + DVector2 Scale = GetHUDScale(); + + x *= Scale.X; + y *= Scale.Y; + w *= Scale.X; + h *= Scale.Y; + x += orgx; + y += orgy; + } +} + + +//============================================================================ +// +// draw stuff +// +//============================================================================ + +void DStatusBarCore::Fill(PalEntry color, double x, double y, double w, double h, int flags) +{ + double Alpha = color.a * this->Alpha / 255; + if (Alpha <= 0) return; + + TransformRect(x, y, w, h, flags); + + int x1 = int(x); + int y1 = int(y); + int ww = int(x + w - x1); // account for scaling to non-integers. Truncating the values separately would fail for cases like + int hh = int(y + h - y1); // y=3.5, height = 5.5 where adding both values gives a larger integer than adding the two integers. + + Dim(twod, color, float(Alpha), x1, y1, ww, hh); +} + + +//============================================================================ +// +// draw stuff +// +//============================================================================ + +void DStatusBarCore::SetClipRect(double x, double y, double w, double h, int flags) +{ + TransformRect(x, y, w, h, flags); + int x1 = int(x); + int y1 = int(y); + int ww = int(x + w - x1); // account for scaling to non-integers. Truncating the values separately would fail for cases like + int hh = int(y + h - y1); // y=3.5, height = 5.5 where adding both values gives a larger integer than adding the two integers. + twod->SetClipRect(x1, y1, ww, hh); +} + + diff --git a/src/common/statusbar/base_sbar.h b/src/common/statusbar/base_sbar.h new file mode 100644 index 00000000000..444e5257a1e --- /dev/null +++ b/src/common/statusbar/base_sbar.h @@ -0,0 +1,196 @@ +#pragma once + +#include "dobject.h" +#include "textureid.h" +#include "zstring.h" +#include "v_draw.h" + +class FGameTexture; +class FFont; +extern FGameTexture* CrosshairImage; +void ST_LoadCrosshair(int num, bool alwaysload); +void ST_UnloadCrosshair(); +void ST_DrawCrosshair(int phealth, double xpos, double ypos, double scale, DAngle angle = nullAngle); + + +enum DI_Flags +{ + DI_SKIPICON = 0x1, + DI_SKIPALTICON = 0x2, + DI_SKIPSPAWN = 0x4, + DI_SKIPREADY = 0x8, + DI_ALTICONFIRST = 0x10, + + + DI_TRANSLATABLE = 0x20, + DI_FORCESCALE = 0x40, + DI_DIM = 0x80, + DI_DRAWCURSORFIRST = 0x100, // only for DrawInventoryBar. + DI_ALWAYSSHOWCOUNT = 0x200, // only for DrawInventoryBar. + DI_DIMDEPLETED = 0x400, + DI_DONTANIMATE = 0x800, // do not animate the texture + DI_MIRROR = 0x1000, // flip the texture horizontally, like a mirror + DI_ITEM_RELCENTER = 0x2000, + DI_MIRRORY = 0x40000000, + + DI_SCREEN_AUTO = 0, // decide based on given offsets. + DI_SCREEN_MANUAL_ALIGN = 0x4000, // If this is on, the following flags will have an effect + + DI_SCREEN_TOP = DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VCENTER = 0x8000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_BOTTOM = 0x10000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VOFFSET = 0x18000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VMASK = 0x18000 | DI_SCREEN_MANUAL_ALIGN, + + DI_SCREEN_LEFT = DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HCENTER = 0x20000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_RIGHT = 0x40000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HOFFSET = 0x60000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HMASK = 0x60000 | DI_SCREEN_MANUAL_ALIGN, + + DI_SCREEN_LEFT_TOP = DI_SCREEN_TOP | DI_SCREEN_LEFT, + DI_SCREEN_RIGHT_TOP = DI_SCREEN_TOP | DI_SCREEN_RIGHT, + DI_SCREEN_LEFT_BOTTOM = DI_SCREEN_BOTTOM | DI_SCREEN_LEFT, + DI_SCREEN_LEFT_CENTER = DI_SCREEN_VCENTER | DI_SCREEN_LEFT, + DI_SCREEN_RIGHT_BOTTOM = DI_SCREEN_BOTTOM | DI_SCREEN_RIGHT, + DI_SCREEN_RIGHT_CENTER = DI_SCREEN_VCENTER | DI_SCREEN_RIGHT, + DI_SCREEN_CENTER = DI_SCREEN_VCENTER | DI_SCREEN_HCENTER, + DI_SCREEN_CENTER_TOP = DI_SCREEN_TOP | DI_SCREEN_HCENTER, + DI_SCREEN_CENTER_BOTTOM = DI_SCREEN_BOTTOM | DI_SCREEN_HCENTER, + DI_SCREEN_OFFSETS = DI_SCREEN_HOFFSET | DI_SCREEN_VOFFSET, + + DI_ITEM_AUTO = 0, // equivalent with bottom center, which is the default alignment. + + DI_ITEM_TOP = 0x80000, + DI_ITEM_VCENTER = 0x100000, + DI_ITEM_BOTTOM = 0, // this is the default vertical alignment + DI_ITEM_VOFFSET = 0x180000, + DI_ITEM_VMASK = 0x180000, + + DI_ITEM_LEFT = 0x200000, + DI_ITEM_HCENTER = 0, // this is the deafault horizontal alignment + DI_ITEM_RIGHT = 0x400000, + DI_ITEM_HOFFSET = 0x600000, + DI_ITEM_HMASK = 0x600000, + + DI_ITEM_LEFT_TOP = DI_ITEM_TOP | DI_ITEM_LEFT, + DI_ITEM_RIGHT_TOP = DI_ITEM_TOP | DI_ITEM_RIGHT, + DI_ITEM_LEFT_BOTTOM = DI_ITEM_BOTTOM | DI_ITEM_LEFT, + DI_ITEM_RIGHT_BOTTOM = DI_ITEM_BOTTOM | DI_ITEM_RIGHT, + DI_ITEM_CENTER = DI_ITEM_VCENTER | DI_ITEM_HCENTER, + DI_ITEM_CENTER_BOTTOM = DI_ITEM_BOTTOM | DI_ITEM_HCENTER, + DI_ITEM_OFFSETS = DI_ITEM_HOFFSET | DI_ITEM_VOFFSET, + + DI_TEXT_ALIGN_LEFT = 0, + DI_TEXT_ALIGN_RIGHT = 0x800000, + DI_TEXT_ALIGN_CENTER = 0x1000000, + DI_TEXT_ALIGN = 0x1800000, + + DI_ALPHAMAPPED = 0x2000000, + DI_NOSHADOW = 0x4000000, + DI_ALWAYSSHOWCOUNTERS = 0x8000000, + DI_ARTIFLASH = 0x10000000, + DI_FORCEFILL = 0x20000000, + + // These 2 flags are only used by SBARINFO so these duplicate other flags not used by SBARINFO + DI_DRAWINBOX = DI_TEXT_ALIGN_RIGHT, + DI_ALTERNATEONFAIL = DI_TEXT_ALIGN_CENTER, + +}; + +//============================================================================ +// +// encapsulates all settings a HUD font may need +// +//============================================================================ + +class DHUDFont : public DObject +{ + // this blocks CreateNew on this class which is the intent here. + DECLARE_CLASS(DHUDFont, DObject); + +public: + FFont* mFont; + int mSpacing; + EMonospacing mMonospacing; + int mShadowX; + int mShadowY; + + DHUDFont() = default; + + DHUDFont(FFont* f, int sp, EMonospacing ms, int sx, int sy) + : mFont(f), mSpacing(sp), mMonospacing(ms), mShadowX(sx), mShadowY(sy) + {} +}; + + + + +class DStatusBarCore : public DObject +{ + DECLARE_CLASS(DStatusBarCore, DObject) + +protected: + + + +public: + + enum EAlign + { + TOP = 0, + VCENTER = 1, + BOTTOM = 2, + VOFFSET = 3, + VMASK = 3, + + LEFT = 0, + HCENTER = 4, + RIGHT = 8, + HOFFSET = 12, + HMASK = 12, + + CENTER = VCENTER | HCENTER, + CENTER_BOTTOM = BOTTOM | HCENTER + }; + + int ST_X; + int ST_Y; + int SBarTop; + int RelTop; + int HorizontalResolution, VerticalResolution; + double Alpha = 1.; + DVector2 SBarScale; + DVector2 drawOffset = { 0,0 }; // can be set by subclasses to offset drawing operations + DVector2 defaultScale; // factor for clean fully scaled display. + double drawClip[4] = { 0,0,0,0 }; // defines a clipping rectangle (not used yet) + bool fullscreenOffsets = false; // current screen is displayed with fullscreen behavior. + bool ForcedScale = false; + bool CompleteBorder = false; + + int BaseRelTop; + int BaseSBarHorizontalResolution; + int BaseSBarVerticalResolution; + int BaseHUDHorizontalResolution; + int BaseHUDVerticalResolution; + + + void BeginStatusBar(int resW, int resH, int relTop, bool forceScaled = false); + void BeginHUD(int resW, int resH, double Alpha, bool forceScaled = false); + void SetSize(int reltop = 32, int hres = 320, int vres = 200, int hhres = -1, int hvres = -1); + virtual DVector2 GetHUDScale() const; + virtual FTranslationID GetTranslation() const { return NO_TRANSLATION; } + void SetDrawSize(int reltop, int hres, int vres); + virtual void SetScale(); + void ValidateResolution(int& hres, int& vres) const; + void StatusbarToRealCoords(double& x, double& y, double& w, double& h) const; + void DrawGraphic(FGameTexture* texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, ERenderStyle style = STYLE_Translucent, PalEntry color = 0xffffffff, int translation = 0, double clipwidth = -1.0); + void DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, ERenderStyle style = STYLE_Translucent, PalEntry color = 0xffffffff, int translation = 0, double clipwidth = -1.0); + void DrawRotated(FTextureID texture, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent); + void DrawRotated(FGameTexture* tex, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent); + void DrawString(FFont* font, const FString& cstring, double x, double y, int flags, double Alpha, int translation, int spacing, EMonospacing monospacing, int shadowX, int shadowY, double scaleX, double scaleY, FTranslationID pt, int style); + void TransformRect(double& x, double& y, double& w, double& h, int flags = 0); + void Fill(PalEntry color, double x, double y, double w, double h, int flags = 0); + void SetClipRect(double x, double y, double w, double h, int flags = 0); + +}; \ No newline at end of file diff --git a/src/common/textures/animtexture.cpp b/src/common/textures/animtexture.cpp new file mode 100644 index 00000000000..1e9ee6d8095 --- /dev/null +++ b/src/common/textures/animtexture.cpp @@ -0,0 +1,251 @@ +/* +** animtexture.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ +#include "animtexture.h" +#include "bitmap.h" +#include "texturemanager.h" + +#include "vpx/vpx_image.h" + + +//========================================================================== +// +// +// +//========================================================================== + +void AnimTexture::SetFrameSize(int format, int width, int height) +{ + pixelformat = format; + FTexture::SetSize(width, height); + Image.Resize(width * height * 4); + memset(Image.Data(), 0, Image.Size()); +} + +//TODO optimize +static inline void YUVtoRGB(uint8_t yi, uint8_t ui, uint8_t vi, uint8_t * rgb) +{ + float Y = yi * (1 / 255.f); + float U = ui * (1 / 255.f) - 0.5f; + float V = vi * (1 / 255.f) - 0.5f; + Y = 1.1643f * (Y - 0.0625f); + float r = Y + 1.5958f * V; + float g = Y - 0.39173f * U - 0.81290f * V; + float b = Y + 2.017f * U; + (rgb)[2] = (uint8_t)(clamp(r, 0.f, 1.f) * 255); + (rgb)[1] = (uint8_t)(clamp(g, 0.f, 1.f) * 255); + (rgb)[0] = (uint8_t)(clamp(b, 0.f, 1.f) * 255); + (rgb)[3] = 255; +} + +void AnimTexture::SetFrame(const uint8_t* Palette, const void* data_) +{ + if (data_) + { + auto dpix = Image.Data(); + + if (pixelformat == YUV) + { + const uint8_t * spix = reinterpret_cast(data_); + + for (int i = 0; i < Width * Height; i++) + { + YUVtoRGB(spix[0], spix[1], spix[2], dpix); + + spix += 4; + dpix += 4; + } + } + else if(pixelformat == VPX) + { + const vpx_image_t *img = reinterpret_cast(data_); + + uint8_t const* const yplane = img->planes[VPX_PLANE_Y]; + uint8_t const* const uplane = img->planes[VPX_PLANE_U]; + uint8_t const* const vplane = img->planes[VPX_PLANE_V]; + + const int ystride = img->stride[VPX_PLANE_Y]; + const int ustride = img->stride[VPX_PLANE_U]; + const int vstride = img->stride[VPX_PLANE_V]; + + if(img->fmt == VPX_IMG_FMT_I420) + { + for (unsigned int y = 0; y < Height; y++) + { + for (unsigned int x = 0; x < Width; x++) + { + YUVtoRGB( + yplane[ystride * y + x], + uplane[ustride * (y >> 1) + (x >> 1)], + vplane[vstride * (y >> 1) + (x >> 1)], + dpix + ); + + dpix += 4; + } + } + } + else if(img->fmt == VPX_IMG_FMT_I444) + { + for (unsigned int y = 0; y < Height; y++) + { + for (unsigned int x = 0; x < Width; x++) + { + YUVtoRGB( + yplane[ystride * y + x], + uplane[ustride * y + x], + vplane[vstride * y + x], + dpix + ); + dpix += 4; + } + } + } + else if(img->fmt == VPX_IMG_FMT_I422) + { // 422 and 440 untested + for (unsigned int y = 0; y < Height; y++) + { + for (unsigned int x = 0; x < Width; x++) + { + YUVtoRGB( + yplane[ystride * y + x], + uplane[ustride * y + (x >> 1)], + vplane[vstride * y + (x >> 1)], + dpix + ); + dpix += 4; + } + } + } + else if(img->fmt == VPX_IMG_FMT_I440) + { + for (unsigned int y = 0; y < Height; y++) + { + for (unsigned int x = 0; x < Width; x++) + { + YUVtoRGB( + yplane[ystride * y + x], + uplane[ustride * (y >> 1) + x], + vplane[vstride * (y >> 1) + x], + dpix + ); + dpix += 4; + } + } + } + } + else if(pixelformat == RGB) + { + const uint8_t *img = reinterpret_cast(data_); + + for (int i = 0; i < Width * Height; i++) + { + dpix[0] = img[2]; + dpix[1] = img[1]; + dpix[2] = img[0]; + dpix[3] = 255; + + dpix += 4; + } + } + else if (pixelformat == Paletted) + { + assert(Palette); + const uint8_t *img = reinterpret_cast(data_); + + for (int i = 0; i < Width * Height; i++) + { + int index = img[i]; + dpix[0] = Palette[index * 3 + 2]; + dpix[1] = Palette[index * 3 + 1]; + dpix[2] = Palette[index * 3]; + dpix[3] = 255; + + dpix += 4; + } + } + } +} + +//=========================================================================== +// +// FPNGTexture::CopyPixels +// +//=========================================================================== + +FBitmap AnimTexture::GetBgraBitmap(const PalEntry* remap, int* trans) +{ + return FBitmap(Image.Data(), Width * 4, Width, Height); +} + +//========================================================================== +// +// +// +//========================================================================== + +AnimTextures::AnimTextures() +{ + active = 1; + tex[0] = TexMan.FindGameTexture("AnimTextureFrame1", ETextureType::Override); + tex[1] = TexMan.FindGameTexture("AnimTextureFrame2", ETextureType::Override); +} + +AnimTextures::~AnimTextures() +{ + Clean(); +} + +void AnimTextures::Clean() +{ + if (tex[0]) tex[0]->CleanHardwareData(true); + if (tex[1]) tex[1]->CleanHardwareData(true); + tex[0] = tex[1] = nullptr; +} + +void AnimTextures::SetSize(int format, int width, int height) +{ + static_cast(tex[0]->GetTexture())->SetFrameSize(format, width, height); + static_cast(tex[1]->GetTexture())->SetFrameSize(format, width, height); + tex[0]->SetSize(width, height); + tex[1]->SetSize(width, height); + tex[0]->CleanHardwareData(); + tex[1]->CleanHardwareData(); +} + +void AnimTextures::SetFrame(const uint8_t* palette, const void* data) +{ + active ^= 1; + static_cast(tex[active]->GetTexture())->SetFrame(palette, data); + tex[active]->CleanHardwareData(); +} diff --git a/src/common/textures/animtexture.h b/src/common/textures/animtexture.h new file mode 100644 index 00000000000..dafa5e6334a --- /dev/null +++ b/src/common/textures/animtexture.h @@ -0,0 +1,44 @@ +#pragma once + +#include "textures.h" + + +class AnimTexture : public FTexture +{ + TArray Image; + int pixelformat; +public: + enum + { + Paletted = 0, + RGB = 1, + YUV = 2, + VPX = 3 + }; + AnimTexture() = default; + void SetFrameSize(int format, int width, int height); + void SetFrame(const uint8_t* palette, const void* data); + virtual FBitmap GetBgraBitmap(const PalEntry* remap, int* trans) override; +}; + +class AnimTextures +{ + int active; + FGameTexture* tex[2]; + +public: + AnimTextures(); + ~AnimTextures(); + void Clean(); + void SetSize(int format, int width, int height); + void SetFrame(const uint8_t* palette, const void* data); + FGameTexture* GetFrame() + { + return tex[active]; + } + + FTextureID GetFrameID() + { + return tex[active]->GetID(); + } +}; diff --git a/src/gamedata/textures/bitmap.cpp b/src/common/textures/bitmap.cpp similarity index 92% rename from src/gamedata/textures/bitmap.cpp rename to src/common/textures/bitmap.cpp index aee21372a26..b97b969d70e 100644 --- a/src/gamedata/textures/bitmap.cpp +++ b/src/common/textures/bitmap.cpp @@ -33,9 +33,27 @@ */ #include "bitmap.h" -#include "r_data/r_translate.h" -#include "r_data/colormaps.h" +#include "palutil.h" +uint8_t IcePalette[16][3] = +{ + { 10, 8, 18 }, + { 15, 15, 26 }, + { 20, 16, 36 }, + { 30, 26, 46 }, + { 40, 36, 57 }, + { 50, 46, 67 }, + { 59, 57, 78 }, + { 69, 67, 88 }, + { 79, 77, 99 }, + { 89, 87,109 }, + { 99, 97,120 }, + { 109,107,130 }, + { 118,118,141 }, + { 128,128,151 }, + { 138,138,162 }, + { 148,148,172 } +}; //=========================================================================== // @@ -50,7 +68,6 @@ void iCopyColors(uint8_t *pout, const uint8_t *pin, int count, int step, FCopyIn int i; int fac; uint8_t r,g,b; - int gray; int a; switch(inf? inf->blend : BLEND_NONE) @@ -80,7 +97,7 @@ void iCopyColors(uint8_t *pout, const uint8_t *pin, int count, int step, FCopyIn if (TBlend::ProcessAlpha0() || a) { int gray = TSrc::Gray(pin)>>4; - + TBlend::OpC(pout[TDest::RED], IcePalette[gray][0], a, inf); TBlend::OpC(pout[TDest::GREEN], IcePalette[gray][1], a, inf); TBlend::OpC(pout[TDest::BLUE], IcePalette[gray][2], a, inf); @@ -101,7 +118,7 @@ void iCopyColors(uint8_t *pout, const uint8_t *pin, int count, int step, FCopyIn a = TSrc::A(pin, tr, tg, tb); if (TBlend::ProcessAlpha0() || a) { - gray = clamp(TSrc::Gray(pin),0,255); + int gray = std::clamp(TSrc::Gray(pin),0,255); PalEntry pe = cm->GrayscaleToColor[gray]; TBlend::OpC(pout[TDest::RED], pe.r , a, inf); @@ -122,7 +139,7 @@ void iCopyColors(uint8_t *pout, const uint8_t *pin, int count, int step, FCopyIn a = TSrc::A(pin, tr, tg, tb); if (TBlend::ProcessAlpha0() || a) { - gray = TSrc::Gray(pin); + int gray = TSrc::Gray(pin); r = (TSrc::R(pin)*(31-fac) + gray*fac)/31; g = (TSrc::G(pin)*(31-fac) + gray*fac)/31; b = (TSrc::B(pin)*(31-fac) + gray*fac)/31; @@ -192,13 +209,14 @@ typedef void (*CopyFunc)(uint8_t *pout, const uint8_t *pin, int count, int step, iCopyColors, \ iCopyColors, \ iCopyColors, \ + iCopyColors, \ iCopyColors, \ iCopyColors, \ iCopyColors, \ iCopyColors, \ iCopyColors \ } -static const CopyFunc copyfuncs[][11]={ +static const CopyFunc copyfuncs[][12]={ COPY_FUNCS(bCopy), COPY_FUNCS(bBlend), COPY_FUNCS(bAdd), @@ -239,21 +257,21 @@ bool ClipCopyPixelRect(const FClipRect *cr, int &originx, int &originy, step_y = pstep_y; break; - case 1: // rotate 90� right + case 1: // rotate 90° right pixxoffset = 0; pixyoffset = srcheight - 1; step_x = -pstep_y; step_y = pstep_x; break; - case 2: // rotate 180� + case 2: // rotate 180° pixxoffset = srcwidth - 1; pixyoffset = srcheight - 1; step_x = -pstep_x; step_y = -pstep_y; break; - case 3: // rotate 90� left + case 3: // rotate 90° left pixxoffset = srcwidth - 1; pixyoffset = 0; step_x = pstep_y; @@ -267,7 +285,7 @@ bool ClipCopyPixelRect(const FClipRect *cr, int &originx, int &originy, step_y = pstep_y; break; - case 5: // flip horizontally and rotate 90� right + case 5: // flip horizontally and rotate 90° right pixxoffset = srcwidth - 1; pixyoffset = srcheight - 1; step_x = -pstep_y; @@ -281,7 +299,7 @@ bool ClipCopyPixelRect(const FClipRect *cr, int &originx, int &originy, step_y = -pstep_y; break; - case 7: // flip horizontally and rotate 90� left + case 7: // flip horizontally and rotate 90° left pixxoffset = 0; pixyoffset = 0; step_x = pstep_y; @@ -314,7 +332,7 @@ bool ClipCopyPixelRect(const FClipRect *cr, int &originx, int &originy, srcwidth = cr->x + cr->width - originx; if (srcwidth<=0) return false; } - + if (originy < cr->y) { int skip = cr->y - originy; @@ -385,10 +403,9 @@ void FBitmap::CopyPixelDataRGB(int originx, int originy, const uint8_t *patch, i } } - template void iCopyPaletted(uint8_t *buffer, const uint8_t * patch, int srcwidth, int srcheight, int Pitch, - int step_x, int step_y, int rotate, PalEntry * palette, FCopyInfo *inf) + int step_x, int step_y, int rotate, const PalEntry * palette, FCopyInfo *inf) { int x,y,pos; @@ -412,7 +429,7 @@ void iCopyPaletted(uint8_t *buffer, const uint8_t * patch, int srcwidth, int src } typedef void (*CopyPalettedFunc)(uint8_t *buffer, const uint8_t * patch, int srcwidth, int srcheight, int Pitch, - int step_x, int step_y, int rotate, PalEntry * palette, FCopyInfo *inf); + int step_x, int step_y, int rotate, const PalEntry * palette, FCopyInfo *inf); static const CopyPalettedFunc copypalettedfuncs[]= @@ -435,7 +452,7 @@ static const CopyPalettedFunc copypalettedfuncs[]= // //=========================================================================== void FBitmap::CopyPixelData(int originx, int originy, const uint8_t * patch, int srcwidth, int srcheight, - int step_x, int step_y, int rotate, PalEntry * palette, FCopyInfo *inf) + int step_x, int step_y, int rotate, const PalEntry * palette, FCopyInfo *inf) { if (ClipCopyPixelRect(&ClipRect, originx, originy, patch, srcwidth, srcheight, step_x, step_y, rotate)) { diff --git a/src/gamedata/textures/bitmap.h b/src/common/textures/bitmap.h similarity index 91% rename from src/gamedata/textures/bitmap.h rename to src/common/textures/bitmap.h index 7b09fb21b09..7f52bc5c025 100644 --- a/src/gamedata/textures/bitmap.h +++ b/src/common/textures/bitmap.h @@ -36,8 +36,8 @@ #ifndef __BITMAP_H__ #define __BITMAP_H__ -#include "doomtype.h" -#include "templates.h" +#include +#include "palentry.h" struct FCopyInfo; @@ -64,6 +64,7 @@ enum ColorType CF_IA, CF_CMYK, CF_YCbCr, + CF_YCCK, CF_BGR, CF_BGRA, CF_I16, @@ -108,7 +109,7 @@ class FBitmap FBitmap(const FBitmap &other) = delete; // disallow because in nearly all cases this creates an unwanted copy. - FBitmap(FBitmap &&other) + FBitmap(FBitmap &&other) noexcept { data = other.data; Pitch = other.Pitch; @@ -122,7 +123,7 @@ class FBitmap FBitmap &operator=(const FBitmap &other) = delete; // disallow because in nearly all cases this creates an unwanted copy. Use Copy instead. - FBitmap &operator=(FBitmap &&other) + FBitmap &operator=(FBitmap &&other) noexcept { if (data != nullptr && FreeBuffer) delete[] data; data = other.data; @@ -155,7 +156,7 @@ class FBitmap } } - + ~FBitmap() { Destroy(); @@ -197,6 +198,11 @@ class FBitmap return Pitch; } + int GetBufferSize() const + { + return Pitch * Height; + } + const uint8_t *GetPixels() const { return data; @@ -234,7 +240,7 @@ class FBitmap int srcheight, int step_x, int step_y, int rotate, int ct, FCopyInfo *inf = NULL, /* for PNG tRNS */ int r=0, int g=0, int b=0); void CopyPixelData(int originx, int originy, const uint8_t * patch, int srcwidth, int srcheight, - int step_x, int step_y, int rotate, PalEntry * palette, FCopyInfo *inf = NULL); + int step_x, int step_y, int rotate, const PalEntry * palette, FCopyInfo *inf = NULL); void Blit(int originx, int originy, const FBitmap &src, int width, int height, int rotate = 0, FCopyInfo *inf = NULL) @@ -247,6 +253,8 @@ class FBitmap CopyPixelDataRGB(originx, originy, src.GetPixels(), src.GetWidth(), src.GetHeight(), 4, src.GetWidth()*4, 0, CF_BGRA, inf); } + + friend class FTexture; }; bool ClipCopyPixelRect(const FClipRect *cr, int &originx, int &originy, @@ -313,13 +321,22 @@ struct cCMYK struct cYCbCr { - static __forceinline unsigned char R(const unsigned char * p) { return clamp((int)(p[0] + 1.40200 * (int(p[2]) - 0x80)), 0, 255); } - static __forceinline unsigned char G(const unsigned char * p) { return clamp((int)(p[0] - 0.34414 * (int(p[1] - 0x80)) - 0.71414 * (int(p[2]) - 0x80)), 0, 255); } - static __forceinline unsigned char B(const unsigned char * p) { return clamp((int)(p[0] + 1.77200 * (int(p[1]) - 0x80)), 0, 255); } + static __forceinline unsigned char R(const unsigned char * p) { return std::clamp((int)(p[0] + 1.40200 * (int(p[2]) - 0x80)), 0, 255); } + static __forceinline unsigned char G(const unsigned char * p) { return std::clamp((int)(p[0] - 0.34414 * (int(p[1] - 0x80)) - 0.71414 * (int(p[2]) - 0x80)), 0, 255); } + static __forceinline unsigned char B(const unsigned char * p) { return std::clamp((int)(p[0] + 1.77200 * (int(p[1]) - 0x80)), 0, 255); } static __forceinline unsigned char A(const unsigned char * p, uint8_t x, uint8_t y, uint8_t z) { return 255; } static __forceinline int Gray(const unsigned char * p) { return (R(p) * 77 + G(p) * 143 + B(p) * 36) >> 8; } }; +struct cYCCK +{ + static __forceinline unsigned char R(const unsigned char* p) { auto myR = cYCbCr::R(p); return p[3] - ((myR * p[3]) >> 8); } + static __forceinline unsigned char G(const unsigned char* p) { auto myG = cYCbCr::G(p); return p[3] - ((myG * p[3]) >> 8); } + static __forceinline unsigned char B(const unsigned char* p) { auto myB = cYCbCr::B(p); return p[3] - ((myB * p[3]) >> 8); } + static __forceinline unsigned char A(const unsigned char* p, uint8_t x, uint8_t y, uint8_t z) { return 255; } + static __forceinline int Gray(const unsigned char* p) { return (R(p) * 77 + G(p) * 143 + B(p) * 36) >> 8; } +}; + struct cBGR { static __forceinline unsigned char R(const unsigned char * p) { return p[2]; } @@ -454,7 +471,7 @@ struct bCopyAlpha struct bOverlay { static __forceinline void OpC(uint8_t &d, uint8_t s, uint8_t a, FCopyInfo *i) { d = (s*a + d*(255-a))/255; } - static __forceinline void OpA(uint8_t &d, uint8_t s, FCopyInfo *i) { d = MAX(s,d); } + static __forceinline void OpA(uint8_t &d, uint8_t s, FCopyInfo *i) { d = std::max(s,d); } static __forceinline bool ProcessAlpha0() { return false; } }; @@ -467,21 +484,21 @@ struct bBlend struct bAdd { - static __forceinline void OpC(uint8_t &d, uint8_t s, uint8_t a, FCopyInfo *i) { d = MIN((d*BLENDUNIT + s*i->alpha) >> BLENDBITS, 255); } + static __forceinline void OpC(uint8_t &d, uint8_t s, uint8_t a, FCopyInfo *i) { d = std::min((d*BLENDUNIT + s*i->alpha) >> BLENDBITS, 255); } static __forceinline void OpA(uint8_t &d, uint8_t s, FCopyInfo *i) { d = s; } static __forceinline bool ProcessAlpha0() { return false; } }; struct bSubtract { - static __forceinline void OpC(uint8_t &d, uint8_t s, uint8_t a, FCopyInfo *i) { d = MAX((d*BLENDUNIT - s*i->alpha) >> BLENDBITS, 0); } + static __forceinline void OpC(uint8_t &d, uint8_t s, uint8_t a, FCopyInfo *i) { d = std::max((d*BLENDUNIT - s*i->alpha) >> BLENDBITS, 0); } static __forceinline void OpA(uint8_t &d, uint8_t s, FCopyInfo *i) { d = s; } static __forceinline bool ProcessAlpha0() { return false; } }; struct bReverseSubtract { - static __forceinline void OpC(uint8_t &d, uint8_t s, uint8_t a, FCopyInfo *i) { d = MAX((-d*BLENDUNIT + s*i->alpha) >> BLENDBITS, 0); } + static __forceinline void OpC(uint8_t &d, uint8_t s, uint8_t a, FCopyInfo *i) { d = std::max((-d*BLENDUNIT + s*i->alpha) >> BLENDBITS, 0); } static __forceinline void OpA(uint8_t &d, uint8_t s, FCopyInfo *i) { d = s; } static __forceinline bool ProcessAlpha0() { return false; } }; diff --git a/src/common/textures/formats/anmtexture.cpp b/src/common/textures/formats/anmtexture.cpp new file mode 100644 index 00000000000..1eb7f494920 --- /dev/null +++ b/src/common/textures/formats/anmtexture.cpp @@ -0,0 +1,178 @@ +/* +** anmtexture.cpp +** Texture class for reading the first frame of Build ANM files +** +**--------------------------------------------------------------------------- +** Copyright 2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" +#include "animlib.h" + +//========================================================================== +// +// +//========================================================================== + +class FAnmTexture : public FImageSource +{ + +public: + FAnmTexture (int lumpnum, int w, int h); + void ReadFrame(uint8_t *buffer, uint8_t *palette); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; +}; + + +//========================================================================== +// +// +// +//========================================================================== + +FImageSource *AnmImage_TryCreate(FileReader & file, int lumpnum) +{ + file.Seek(0, FileReader::SeekSet); + char check[4]; + auto num = file.Read(check, 4); + if (num < 4) return nullptr; + if (memcmp(check, "LPF ", 4)) return nullptr; + file.Seek(0, FileReader::SeekSet); + auto buffer = file.ReadPadded(1); + if (buffer.size() < 4) return nullptr; + + std::unique_ptr anim = std::make_unique(); // note that this struct is very large and should not go onto the stack! + if (ANIM_LoadAnim(anim.get(), buffer.bytes(), buffer.size() - 1) < 0) + { + return nullptr; + } + int numframes = ANIM_NumFrames(anim.get()); + if (numframes >= 1) + { + return new FAnmTexture(lumpnum, 320, 200); + } + + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +FAnmTexture::FAnmTexture (int lumpnum, int w, int h) + : FImageSource(lumpnum) +{ + Width = w; + Height = h; + LeftOffset = 0; + TopOffset = 0; +} + +void FAnmTexture::ReadFrame(uint8_t *pixels, uint8_t *palette) +{ + auto lump = fileSystem.ReadFile (SourceLump); + auto source = lump.bytes(); + + std::unique_ptr anim = std::make_unique(); // note that this struct is very large and should not go onto the stack! + if (ANIM_LoadAnim(anim.get(), source, (int)lump.size()) >= 0) + { + int numframes = ANIM_NumFrames(anim.get()); + if (numframes >= 1) + { + memcpy(palette, ANIM_GetPalette(anim.get()), 768); + memcpy(pixels, ANIM_DrawFrame(anim.get(), 1), Width * Height); + return; + } + } + memset(pixels, 0, Width*Height); + memset(palette, 0, 768); +} + +struct workbuf +{ + uint8_t buffer[64000]; + uint8_t palette[768]; +}; + +//========================================================================== +// +// +// +//========================================================================== + +PalettedPixels FAnmTexture::CreatePalettedPixels(int conversion, int frame) +{ + PalettedPixels pixels(Width*Height); + uint8_t remap[256]; + std::unique_ptr w = std::make_unique(); + + ReadFrame(w->buffer, w->palette); + for(int i=0;i<256;i++) + { + remap[i] = ColorMatcher.Pick(w->palette[i*3], w->palette[i*3+1], w->palette[i*3+2]); + } + ImageHelpers::FlipNonSquareBlockRemap (pixels.Data(), w->buffer, Width, Height, Width, remap); + return pixels; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FAnmTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) +{ + std::unique_ptr w = std::make_unique(); + ReadFrame(w->buffer, w->palette); + + auto dpix = bmp->GetPixels(); + for (int i = 0; i < Width * Height; i++) + { + int p = i * 4; + int index = w->buffer[i]; + dpix[p + 0] = w->palette[index * 3 + 2]; + dpix[p + 1] = w->palette[index * 3 + 1]; + dpix[p + 2] = w->palette[index * 3]; + dpix[p + 3] = 255; + } + + return -1; +} + + \ No newline at end of file diff --git a/src/gamedata/textures/formats/automaptexture.cpp b/src/common/textures/formats/automaptexture.cpp similarity index 87% rename from src/gamedata/textures/formats/automaptexture.cpp rename to src/common/textures/formats/automaptexture.cpp index 81205291bba..2ebdc4d5361 100644 --- a/src/gamedata/textures/formats/automaptexture.cpp +++ b/src/common/textures/formats/automaptexture.cpp @@ -35,10 +35,8 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" -#include "textures/textures.h" +#include "filesystem.h" #include "imagehelpers.h" #include "image.h" @@ -52,7 +50,7 @@ class FAutomapTexture : public FImageSource { public: FAutomapTexture(int lumpnum); - TArray CreatePalettedPixels(int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; }; @@ -67,7 +65,7 @@ class FAutomapTexture : public FImageSource FImageSource *AutomapImage_TryCreate(FileReader &data, int lumpnum) { if (data.GetLength() < 320) return nullptr; - if (!Wads.CheckLumpName(lumpnum, "AUTOPAGE")) return nullptr; + if (!fileSystem.CheckFileName(lumpnum, "AUTOPAGE")) return nullptr; return new FAutomapTexture(lumpnum); } @@ -81,7 +79,7 @@ FAutomapTexture::FAutomapTexture (int lumpnum) : FImageSource(lumpnum) { Width = 320; - Height = uint16_t(Wads.LumpLength(lumpnum) / 320); + Height = uint16_t(fileSystem.FileLength(lumpnum) / 320); bUseGamePalette = true; } @@ -91,13 +89,13 @@ FAutomapTexture::FAutomapTexture (int lumpnum) // //========================================================================== -TArray FAutomapTexture::CreatePalettedPixels(int conversion) +PalettedPixels FAutomapTexture::CreatePalettedPixels(int conversion, int frame) { int x, y; - FMemLump data = Wads.ReadLump (SourceLump); - const uint8_t *indata = (const uint8_t *)data.GetMem(); + auto data = fileSystem.ReadFile (SourceLump); + auto indata = data.bytes(); - TArray Pixels(Width * Height, true); + PalettedPixels Pixels(Width * Height); const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); for (x = 0; x < Width; ++x) diff --git a/src/gamedata/textures/formats/brightmaptexture.cpp b/src/common/textures/formats/brightmaptexture.cpp similarity index 87% rename from src/gamedata/textures/formats/brightmaptexture.cpp rename to src/common/textures/formats/brightmaptexture.cpp index b9baf23839b..262a520f6f7 100644 --- a/src/gamedata/textures/formats/brightmaptexture.cpp +++ b/src/common/textures/formats/brightmaptexture.cpp @@ -33,12 +33,9 @@ ** */ -#include "doomtype.h" -#include "w_wad.h" - -#include "r_data/r_translate.h" +#include "filesystem.h" +#include "palettecontainer.h" #include "bitmap.h" -#include "v_video.h" #include "image.h" class FBrightmapTexture : public FImageSource @@ -46,7 +43,7 @@ class FBrightmapTexture : public FImageSource public: FBrightmapTexture (FImageSource *source); - int CopyPixels(FBitmap *bmp, int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; protected: FImageSource *SourcePic; @@ -68,13 +65,13 @@ FBrightmapTexture::FBrightmapTexture (FImageSource *source) bMasked = false; } -int FBrightmapTexture::CopyPixels(FBitmap *bmp, int conversion) +int FBrightmapTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { - SourcePic->CopyTranslatedPixels(bmp, TexMan.GlobalBrightmap.Palette); + SourcePic->CopyTranslatedPixels(bmp, GPalette.GlobalBrightmap.Palette, frame); return 0; } FTexture *CreateBrightmapTexture(FImageSource *tex) { - return new FImageTexture(new FBrightmapTexture(tex)); + return CreateImageTexture(new FBrightmapTexture(tex)); } diff --git a/src/common/textures/formats/buildtexture.cpp b/src/common/textures/formats/buildtexture.cpp new file mode 100644 index 00000000000..fec41227bfc --- /dev/null +++ b/src/common/textures/formats/buildtexture.cpp @@ -0,0 +1,77 @@ +/* +** buildtexture.cpp +** Handling Build textures (now as a usable editing feature!) +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "bitmap.h" +#include "image.h" +#include "palettecontainer.h" + + +//========================================================================== +// +// +// +//========================================================================== + +FBuildTexture::FBuildTexture(const FString &pathprefix, int tilenum, const uint8_t *pixels, FRemapTable *translation, int width, int height, int left, int top) +: RawPixels (pixels), Translation(translation) +{ + Width = width; + Height = height; + LeftOffset = left; + TopOffset = top; +} + +PalettedPixels FBuildTexture::CreatePalettedPixels(int conversion, int frame) +{ + PalettedPixels Pixels(Width * Height); + FRemapTable *Remap = Translation; + for (int i = 0; i < Width*Height; i++) + { + auto c = RawPixels[i]; + Pixels[i] = conversion == luminance ? Remap->Palette[c].Luminance() : Remap->Remap[c]; + } + return Pixels; +} + +int FBuildTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) +{ + PalEntry *Remap = Translation->Palette; + bmp->CopyPixelData(0, 0, RawPixels, Width, Height, Height, 1, 0, Remap); + return -1; + +} + diff --git a/src/gamedata/textures/formats/ddstexture.cpp b/src/common/textures/formats/ddstexture.cpp similarity index 97% rename from src/gamedata/textures/formats/ddstexture.cpp rename to src/common/textures/formats/ddstexture.cpp index f5ae1f05627..6105ea99be8 100644 --- a/src/gamedata/textures/formats/ddstexture.cpp +++ b/src/common/textures/formats/ddstexture.cpp @@ -1,9 +1,10 @@ /* -** pngtexture.cpp +** ddstexture.cpp ** Texture class for DDS images ** **--------------------------------------------------------------------------- -** Copyright 2006-2007 Randy Heit +** Copyright 2006-2016 Randy Heit +** Copyright 2006-2019 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -48,13 +49,12 @@ ** the pixel data, it is fairly inefficient to process. */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" +#include "filesystem.h" #include "bitmap.h" -#include "v_video.h" #include "imagehelpers.h" #include "image.h" +#include "m_swap.h" // Since we want this to compile under Linux too, we need to define this // stuff ourselves instead of including a DirectX header. @@ -164,7 +164,7 @@ class FDDSTexture : public FImageSource public: FDDSTexture (FileReader &lump, int lumpnum, void *surfdesc); - TArray CreatePalettedPixels(int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; protected: uint32_t Format; @@ -183,7 +183,7 @@ class FDDSTexture : public FImageSource void DecompressDXT3 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode); void DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode); - int CopyPixels(FBitmap *bmp, int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; friend class FTexture; }; @@ -372,11 +372,11 @@ void FDDSTexture::CalcBitShift (uint32_t mask, uint8_t *lshiftp, uint8_t *rshift // //========================================================================== -TArray FDDSTexture::CreatePalettedPixels(int conversion) +PalettedPixels FDDSTexture::CreatePalettedPixels(int conversion, int frame) { - auto lump = Wads.OpenLumpReader (SourceLump); + auto lump = fileSystem.OpenFileReader (SourceLump); - TArray Pixels(Width*Height, true); + PalettedPixels Pixels(Width*Height); lump.Seek (sizeof(DDSURFACEDESC2) + 4, FileReader::SeekSet); @@ -665,7 +665,7 @@ void FDDSTexture::DecompressDXT3 (FileReader &lump, bool premultiplied, uint8_t void FDDSTexture::DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode) { - const long blocklinelen = ((Width + 3) >> 2) << 4; + const size_t blocklinelen = ((Width + 3) >> 2) << 4; uint8_t *blockbuff = new uint8_t[blocklinelen]; uint8_t *block; PalEntry color[4]; @@ -781,9 +781,9 @@ void FDDSTexture::DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t // //=========================================================================== -int FDDSTexture::CopyPixels(FBitmap *bmp, int conversion) +int FDDSTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { - auto lump = Wads.OpenLumpReader (SourceLump); + auto lump = fileSystem.OpenFileReader (SourceLump); uint8_t *TexBuffer = bmp->GetPixels(); diff --git a/src/gamedata/textures/formats/emptytexture.cpp b/src/common/textures/formats/emptytexture.cpp similarity index 91% rename from src/gamedata/textures/formats/emptytexture.cpp rename to src/common/textures/formats/emptytexture.cpp index 1073de660cc..cd53b996a35 100644 --- a/src/gamedata/textures/formats/emptytexture.cpp +++ b/src/common/textures/formats/emptytexture.cpp @@ -35,10 +35,8 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" -#include "textures/textures.h" +#include "filesystem.h" #include "image.h" //========================================================================== @@ -51,7 +49,7 @@ class FEmptyTexture : public FImageSource { public: FEmptyTexture (int lumpnum); - TArray CreatePalettedPixels(int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; }; //========================================================================== @@ -71,6 +69,11 @@ FImageSource *EmptyImage_TryCreate(FileReader & file, int lumpnum) return new FEmptyTexture(lumpnum); } +FImageSource* CreateEmptyTexture() +{ + return new FEmptyTexture(0); +} + //========================================================================== // // @@ -91,10 +94,10 @@ FEmptyTexture::FEmptyTexture (int lumpnum) // //========================================================================== -TArray FEmptyTexture::CreatePalettedPixels(int conversion) +PalettedPixels FEmptyTexture::CreatePalettedPixels(int conversion, int frame) { - TArray Pixel(1, true); - Pixel[0] = 0; + static uint8_t p; + PalettedPixels Pixel(&p, 1); return Pixel; } diff --git a/src/gamedata/textures/formats/flattexture.cpp b/src/common/textures/formats/flattexture.cpp similarity index 91% rename from src/gamedata/textures/formats/flattexture.cpp rename to src/common/textures/formats/flattexture.cpp index 7654b2b350f..533b484b36d 100644 --- a/src/gamedata/textures/formats/flattexture.cpp +++ b/src/common/textures/formats/flattexture.cpp @@ -33,10 +33,8 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" -#include "textures/textures.h" +#include "filesystem.h" #include "imagehelpers.h" #include "image.h" @@ -50,7 +48,7 @@ class FFlatTexture : public FImageSource { public: FFlatTexture (int lumpnum); - TArray CreatePalettedPixels(int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; }; @@ -76,10 +74,9 @@ FImageSource *FlatImage_TryCreate(FileReader & file, int lumpnum) FFlatTexture::FFlatTexture (int lumpnum) : FImageSource(lumpnum) { - int area; int bits; - area = Wads.LumpLength (lumpnum); + auto area = fileSystem.FileLength (lumpnum); switch (area) { @@ -104,10 +101,10 @@ FFlatTexture::FFlatTexture (int lumpnum) // //========================================================================== -TArray FFlatTexture::CreatePalettedPixels(int conversion) +PalettedPixels FFlatTexture::CreatePalettedPixels(int conversion, int frame) { - auto lump = Wads.OpenLumpReader (SourceLump); - TArray Pixels(Width*Height, true); + auto lump = fileSystem.OpenFileReader (SourceLump); + PalettedPixels Pixels(Width*Height); auto numread = lump.Read (Pixels.Data(), Width*Height); if (numread < Width*Height) { diff --git a/src/common/textures/formats/fontchars.cpp b/src/common/textures/formats/fontchars.cpp new file mode 100644 index 00000000000..2d09cf58dec --- /dev/null +++ b/src/common/textures/formats/fontchars.cpp @@ -0,0 +1,179 @@ +/* +** fontchars.cpp +** Texture class for font characters +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "filesystem.h" +#include "bitmap.h" +#include "image.h" +#include "imagehelpers.h" +#include "fontchars.h" +#include "engineerrors.h" + +//========================================================================== +// +// FFontChar2 :: FFontChar2 +// +// Used by FON1 and FON2 fonts. +// +//========================================================================== + +FFontChar2::FFontChar2(int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs) + : SourceLump(sourcelump), SourcePos(sourcepos) +{ + Width = width; + Height = height; + LeftOffset = leftofs; + TopOffset = topofs; +} + +//========================================================================== +// +// FFontChar2 :: Get8BitPixels +// +// Like for FontChar1, the render style has no relevance here as well. +// +//========================================================================== + +PalettedPixels FFontChar2::CreatePalettedPixels(int, int) +{ + auto lump = fileSystem.OpenFileReader(SourceLump); + int destSize = Width * Height; + uint8_t max = 255; + bool rle = true; + + // This is to "fix" bad fonts + { + uint8_t buff[16]; + lump.Read(buff, 4); + if (buff[3] == '2') + { + lump.Read(buff, 7); + max = buff[6]; + lump.Seek(SourcePos - 11, FileReader::SeekCur); + } + else if (buff[3] == 0x1A) + { + lump.Read(buff, 13); + max = buff[12] - 1; + lump.Seek(SourcePos - 17, FileReader::SeekCur); + rle = false; + } + else + { + lump.Seek(SourcePos - 4, FileReader::SeekCur); + } + } + + PalettedPixels Pixels(destSize); + + int runlen = 0, setlen = 0; + uint8_t setval = 0; // Shut up, GCC! + uint8_t* dest_p = Pixels.Data(); + int dest_adv = Height; + int dest_rew = destSize - 1; + + if (rle) + { + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; ) + { + if (runlen != 0) + { + uint8_t color = lump.ReadUInt8(); + color = min(color, max); + *dest_p = color; + dest_p += dest_adv; + x--; + runlen--; + } + else if (setlen != 0) + { + *dest_p = setval; + dest_p += dest_adv; + x--; + setlen--; + } + else + { + int8_t code = lump.ReadInt8(); + if (code >= 0) + { + runlen = code + 1; + } + else if (code != -128) + { + uint8_t color = lump.ReadUInt8(); + setlen = (-code) + 1; + setval = min(color, max); + } + } + } + dest_p -= dest_rew; + } + } + else + { + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + uint8_t color = lump.ReadUInt8(); + if (color > max) + { + color = max; + } + *dest_p = color; + dest_p += dest_adv; + } + dest_p -= dest_rew; + } + } + + if (destSize < 0) + { + auto name = fileSystem.GetFileShortName(SourceLump); + I_FatalError("The font %s is corrupt", name); + } + return Pixels; +} + +int FFontChar2::CopyPixels(FBitmap* bmp, int conversion, int frame) +{ + if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source. + auto ppix = CreatePalettedPixels(conversion); + bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, SourceRemap, nullptr); + return 0; +} diff --git a/src/common/textures/formats/fontchars.h b/src/common/textures/formats/fontchars.h new file mode 100644 index 00000000000..089043969ee --- /dev/null +++ b/src/common/textures/formats/fontchars.h @@ -0,0 +1,21 @@ + + +// This is a font character that reads RLE compressed data. +class FFontChar2 : public FImageSource +{ +public: + FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0); + + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap* bmp, int conversion, int frame = 0); + + void SetSourceRemap(const PalEntry* sourceremap) + { + SourceRemap = sourceremap; + } + +protected: + int SourceLump; + int SourcePos; + const PalEntry *SourceRemap; +}; diff --git a/src/gamedata/textures/formats/imgztexture.cpp b/src/common/textures/formats/imgztexture.cpp similarity index 88% rename from src/gamedata/textures/formats/imgztexture.cpp rename to src/common/textures/formats/imgztexture.cpp index 2f466c5e2b0..9419c64a66f 100644 --- a/src/gamedata/textures/formats/imgztexture.cpp +++ b/src/common/textures/formats/imgztexture.cpp @@ -33,10 +33,8 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" -#include "v_video.h" +#include "filesystem.h" #include "bitmap.h" #include "imagehelpers.h" #include "image.h" @@ -68,8 +66,8 @@ class FIMGZTexture : public FImageSource public: FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int16_t t, bool isalpha); - TArray CreatePalettedPixels(int conversion) override; - int CopyPixels(FBitmap *bmp, int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; }; @@ -120,17 +118,17 @@ FIMGZTexture::FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int1 // //========================================================================== -TArray FIMGZTexture::CreatePalettedPixels(int conversion) +PalettedPixels FIMGZTexture::CreatePalettedPixels(int conversion, int frame) { - FMemLump lump = Wads.ReadLump (SourceLump); - const ImageHeader *imgz = (const ImageHeader *)lump.GetMem(); + auto lump = fileSystem.ReadFile (SourceLump); + auto imgz = (const ImageHeader *)lump.data(); const uint8_t *data = (const uint8_t *)&imgz[1]; uint8_t *dest_p; int dest_adv = Height; int dest_rew = Width * Height - 1; - TArray Pixels(Width*Height, true); + PalettedPixels Pixels(Width*Height); dest_p = Pixels.Data(); const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance, isalpha); @@ -200,9 +198,9 @@ TArray FIMGZTexture::CreatePalettedPixels(int conversion) // //========================================================================== -int FIMGZTexture::CopyPixels(FBitmap *bmp, int conversion) +int FIMGZTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { - if (!isalpha) return FImageSource::CopyPixels(bmp, conversion); - else return CopyTranslatedPixels(bmp, translationtables[TRANSLATION_Standard][STD_Grayscale]->Palette); + if (!isalpha) return FImageSource::CopyPixels(bmp, conversion, frame); + else return CopyTranslatedPixels(bmp, GPalette.GrayscaleMap.Palette, frame); } diff --git a/src/gamedata/textures/formats/md5check.cpp b/src/common/textures/formats/md5check.cpp similarity index 99% rename from src/gamedata/textures/formats/md5check.cpp rename to src/common/textures/formats/md5check.cpp index eb0a188d056..120371a8e59 100644 --- a/src/gamedata/textures/formats/md5check.cpp +++ b/src/common/textures/formats/md5check.cpp @@ -37,7 +37,7 @@ #include #include "files.h" #include "md5.h" -#include "doomtype.h" +#include "printf.h" struct MD5Check { @@ -219,10 +219,10 @@ void makeMD5(const void *buffer, unsigned length, char *md5out) bool checkPatchForAlpha(const void *buffer, uint32_t length) { if (length > 10164) return false; // shortcut for anything too large - + char md5[33]; bool done = false; - + for(int i=0; alphapatches[i].length > 0; i++) { if (alphapatches[i].length == (int)length) // length check diff --git a/src/gamedata/textures/formats/multipatchtexture.cpp b/src/common/textures/formats/multipatchtexture.cpp similarity index 89% rename from src/gamedata/textures/formats/multipatchtexture.cpp rename to src/common/textures/formats/multipatchtexture.cpp index 8166db6459c..3a8e8ae7b09 100644 --- a/src/gamedata/textures/formats/multipatchtexture.cpp +++ b/src/common/textures/formats/multipatchtexture.cpp @@ -34,25 +34,11 @@ */ #include -#include "doomtype.h" #include "files.h" -#include "w_wad.h" - -#include "gi.h" -#include "st_start.h" -#include "sc_man.h" -#include "templates.h" -#include "r_data/r_translate.h" -#include "bitmap.h" -#include "colormatcher.h" -#include "v_palette.h" -#include "v_video.h" -#include "v_text.h" -#include "cmdlib.h" -#include "imagehelpers.h" +#include "filesystem.h" #include "image.h" #include "multipatchtexture.h" - +#include "imagehelpers.h" //========================================================================== // @@ -60,15 +46,19 @@ // //========================================================================== -FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual) +FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual) { Width = w; Height = h; bComplex = complex; - bTextual = textual; + bTextual = textual; Parts = (TexPart*)ImageArena.Alloc(sizeof(TexPart) * parts.Size()); NumParts = parts.Size(); memcpy(Parts, parts.Data(), sizeof(TexPart) * parts.Size()); + for (unsigned i = 0; i < parts.Size(); i++) + { + Parts[i].Image = parts[i].TexImage->GetImage(); + } bUseGamePalette = false; if (!bComplex) @@ -81,6 +71,27 @@ FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray &part } } +//========================================================================== +// +// sky remapping will only happen if +// - the texture was defined through a TEXTUREx lump (this implies only trivial copies) +// - all patches use the base palette. +// - all patches are in a format that allows the remap. +// All other cases would not be able to properly deal with this special case. +// For textual definitions this hack isn't necessary. +// +//========================================================================== + +bool FMultiPatchTexture::SupportRemap0() +{ + if (bTextual || UseGamePalette()) return false; + for (int i = 0; i < NumParts; i++) + { + if (!Parts[i].Image->SupportRemap0()) return false; + } + return true; +} + //========================================================================== // // GetBlendMap @@ -92,7 +103,7 @@ static uint8_t *GetBlendMap(PalEntry blend, uint8_t *blendwork) switch (blend.a==0 ? int(blend) : -1) { case BLEND_ICEMAP: - return TranslationToTable(TRANSLATION(TRANSLATION_Standard, 7))->Remap; + return GPalette.IceMap.Remap; default: if (blend >= BLEND_SPECIALCOLORMAP1 && blend < BLEND_SPECIALCOLORMAP1 + SpecialColormaps.Size()) @@ -190,13 +201,13 @@ void FMultiPatchTexture::CopyToBlock(uint8_t *dest, int dwidth, int dheight, FIm // //========================================================================== -TArray FMultiPatchTexture::CreatePalettedPixels(int conversion) +PalettedPixels FMultiPatchTexture::CreatePalettedPixels(int conversion, int frame) { int numpix = Width * Height; uint8_t blendwork[256]; bool buildrgb = bComplex; - TArray Pixels(numpix, true); + PalettedPixels Pixels(numpix); memset (Pixels.Data(), 0, numpix); if (conversion == luminance) @@ -217,11 +228,6 @@ TArray FMultiPatchTexture::CreatePalettedPixels(int conversion) } if (conversion == noremap0) { - // sky remapping will only happen if - // - the texture was defined through a TEXTUREx lump (this implies only trivial copies) - // - all patches use the base palette. - // All other cases would not be able to properly deal with this special case. - // For textual definitions this hack isn't necessary. if (bTextual || !UseGamePalette()) conversion = normal; } @@ -272,7 +278,7 @@ TArray FMultiPatchTexture::CreatePalettedPixels(int conversion) // //=========================================================================== -int FMultiPatchTexture::CopyPixels(FBitmap *bmp, int conversion) +int FMultiPatchTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { int retv = -1; diff --git a/src/common/textures/formats/multipatchtexture.h b/src/common/textures/formats/multipatchtexture.h new file mode 100644 index 00000000000..ce1f5d932f3 --- /dev/null +++ b/src/common/textures/formats/multipatchtexture.h @@ -0,0 +1,176 @@ +#pragma once +#include "sc_man.h" +#include "palettecontainer.h" +#include "textureid.h" +#include "vectors.h" +#include "bitmap.h" +#include "image.h" +#include "textures.h" + +class FImageTexture; +class FTextureManager; + +//========================================================================== +// +// TexPart is the data that will get passed to the final texture. +// +//========================================================================== + +struct TexPart +{ + FRemapTable *Translation = nullptr; + FImageSource *Image = nullptr; + PalEntry Blend = 0; + blend_t Alpha = FRACUNIT; + int16_t OriginX = 0; + int16_t OriginY = 0; + uint8_t Rotate = 0; + uint8_t op = OP_COPY; +}; + +struct TexPartBuild +{ + FRemapTable* Translation = nullptr; + FImageTexture *TexImage = nullptr; + PalEntry Blend = 0; + blend_t Alpha = FRACUNIT; + int16_t OriginX = 0; + int16_t OriginY = 0; + uint8_t Rotate = 0; + uint8_t op = OP_COPY; +}; + + + +//========================================================================== +// +// A texture defined in a TEXTURE1 or TEXTURE2 lump +// +//========================================================================== + +class FMultiPatchTexture : public FImageSource +{ + friend class FTexture; + friend class FGameTexture; +public: + FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual); + int GetNumParts() const { return NumParts; } + // Query some needed info for texture hack support. + bool SupportRemap0() override; + bool IsRawCompatible() override + { + return NumParts != 1 || Parts[0].OriginY == 0 || bTextual; + } + FImageSource* GetImageForPart(int num) + { + if (num >= 0 && num < NumParts) return Parts[num].Image; + return nullptr; + } + +protected: + int NumParts; + bool bComplex; + bool bTextual; + TexPart *Parts; + + // The getters must optionally redirect if it's a simple one-patch texture. + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + void CopyToBlock(uint8_t *dest, int dwidth, int dheight, FImageSource *source, int xpos, int ypos, int rotate, const uint8_t *translation, int style); + void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor) override; + +}; + + +//========================================================================== +// +// Additional data per patch which is needed for initialization +// +//========================================================================== + +struct TexInit +{ + FString TexName; + ETextureType UseType = ETextureType::Null; + FGameTexture *GameTexture = nullptr; + bool Silent = false; + bool HasLine = false; + bool UseOffsets = false; + FScriptPosition sc; +}; + +//========================================================================== +// +// All build info only needed to construct the multipatch textures +// +//========================================================================== + +struct FPatchLookup; + +struct BuildInfo +{ + FString Name; + TArray Parts; + TArray Inits; + int Width = 0; + int Height = 0; + DVector2 Scale = { 1, 1 }; + bool bWorldPanning = false; // This sucks! + int DefinitionLump = 0; + bool bComplex = false; + bool textual = false; + bool bNoDecals = false; + bool bNoTrim = false; + int LeftOffset[2] = {}; + int TopOffset[2] = {}; + FGameTexture *texture = nullptr; + + void swap(BuildInfo &other) + { + Name.Swap(other.Name); + Parts.Swap(other.Parts); + Inits.Swap(other.Inits); + std::swap(Width, other.Width); + std::swap(Height, other.Height); + std::swap(Scale, other.Scale); + std::swap(bWorldPanning, other.bWorldPanning); + std::swap(DefinitionLump, other.DefinitionLump); + std::swap(bComplex, other.bComplex); + std::swap(textual, other.textual); + std::swap(bNoDecals, other.bNoDecals); + std::swap(LeftOffset[0], other.LeftOffset[0]); + std::swap(LeftOffset[1], other.LeftOffset[1]); + std::swap(TopOffset[0], other.TopOffset[0]); + std::swap(TopOffset[1], other.TopOffset[1]); + std::swap(texture, other.texture); + } +}; + + + +class FMultipatchTextureBuilder +{ + FTextureManager &TexMan; + TArray BuiltTextures; + TMap complex; + void(*progressFunc)(); + void(*checkForHacks)(BuildInfo&); + + void MakeTexture(BuildInfo &buildinfo, ETextureType usetype); + void AddImageToTexture(FImageTexture* tex, BuildInfo& buildinfo); + + void BuildTexture(const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum, ETextureType usetyoe); + void AddTexturesLump(const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup, bool texture1); + + void ParsePatch(FScanner &sc, BuildInfo &info, TexPartBuild &part, TexInit &init); + void ResolvePatches(BuildInfo &buildinfo); + +public: + FMultipatchTextureBuilder(FTextureManager &texMan, void(*progressFunc_)(), void(*checkForHacks_)(BuildInfo &)) : TexMan(texMan), progressFunc(progressFunc_), checkForHacks(checkForHacks_) + { + } + + void AddTexturesLumps(int lump1, int lump2, int patcheslump); + void ParseTexture(FScanner &sc, ETextureType usetype, int deflump); + void ResolveAllPatches(); +}; diff --git a/src/gamedata/textures/formats/patchtexture.cpp b/src/common/textures/formats/patchtexture.cpp similarity index 77% rename from src/gamedata/textures/formats/patchtexture.cpp rename to src/common/textures/formats/patchtexture.cpp index 705da984a0c..d7e8f3fca6b 100644 --- a/src/gamedata/textures/formats/patchtexture.cpp +++ b/src/common/textures/formats/patchtexture.cpp @@ -33,14 +33,23 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" -#include "v_palette.h" -#include "v_video.h" +#include "filesystem.h" #include "bitmap.h" #include "image.h" #include "imagehelpers.h" +#include "m_swap.h" + + +// Doom patch format header +struct patch_t +{ + int16_t width; // bounding box size + int16_t height; + int16_t leftoffset; // pixels to the left of origin + int16_t topoffset; // pixels below the origin + uint32_t columnofs[1]; // only [width] used +}; // posts are runs of non masked source pixels @@ -63,9 +72,10 @@ class FPatchTexture : public FImageSource bool badflag = false; bool isalpha = false; public: - FPatchTexture (int lumpnum, patch_t *header, bool isalphatex); - TArray CreatePalettedPixels(int conversion) override; - int CopyPixels(FBitmap *bmp, int conversion) override; + FPatchTexture (int lumpnum, int w, int h, int lo, int to, bool isalphatex); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; + bool SupportRemap0() override { return !badflag; } void DetectBadPatches(); }; @@ -78,15 +88,15 @@ class FPatchTexture : public FImageSource static bool CheckIfPatch(FileReader & file, bool &isalpha) { if (file.GetLength() < 13) return false; // minimum length of a valid Doom patch - + file.Seek(0, FileReader::SeekSet); auto data = file.Read(file.GetLength()); - - const patch_t *foo = (const patch_t *)data.Data(); - + + const patch_t *foo = (const patch_t *)data.data(); + int height = LittleShort(foo->height); int width = LittleShort(foo->width); - + if (height > 0 && height <= 2048 && width > 0 && width <= 2048 && width < file.GetLength()/4) { // The dimensions seem like they might be valid for a patch, so @@ -95,7 +105,7 @@ static bool CheckIfPatch(FileReader & file, bool &isalpha) // and none of them must point past the end of the patch. bool gapAtStart = true; int x; - + for (x = 0; x < width; ++x) { uint32_t ofs = LittleLong(foo->columnofs[x]); @@ -112,7 +122,7 @@ static bool CheckIfPatch(FileReader & file, bool &isalpha) { // only check this if the texture passed validation. // Here is a good point because we already have a valid buffer of the lump's data. - isalpha = checkPatchForAlpha(data.Data(), (uint32_t)file.GetLength()); + isalpha = checkPatchForAlpha(data.data(), (uint32_t)file.GetLength()); } return !gapAtStart; } @@ -127,16 +137,21 @@ static bool CheckIfPatch(FileReader & file, bool &isalpha) FImageSource *PatchImage_TryCreate(FileReader & file, int lumpnum) { - patch_t header; bool isalpha; - if (!CheckIfPatch(file, isalpha)) return NULL; file.Seek(0, FileReader::SeekSet); - header.width = file.ReadUInt16(); - header.height = file.ReadUInt16(); - header.leftoffset = file.ReadInt16(); - header.topoffset = file.ReadInt16(); - return new FPatchTexture(lumpnum, &header, isalpha); + int width = file.ReadUInt16(); + int height = file.ReadUInt16(); + int leftoffset = file.ReadInt16(); + int topoffset = file.ReadInt16(); + // quickly reject any lump which cannot be a texture without reading in all the data. + if (height > 0 && height <= 2048 && width > 0 && width <= 2048 && width < file.GetLength() / 4 && abs(leftoffset) < 4096 && abs(topoffset) < 4096) + { + if (!CheckIfPatch(file, isalpha)) return NULL; + file.Seek(8, FileReader::SeekSet); + return new FPatchTexture(lumpnum, width, height, leftoffset, topoffset, isalpha); + } + return nullptr; } //========================================================================== @@ -145,15 +160,15 @@ FImageSource *PatchImage_TryCreate(FileReader & file, int lumpnum) // //========================================================================== -FPatchTexture::FPatchTexture (int lumpnum, patch_t * header, bool isalphatex) +FPatchTexture::FPatchTexture (int lumpnum, int w, int h, int lo, int to, bool isalphatex) : FImageSource(lumpnum) { bUseGamePalette = !isalphatex; isalpha = isalphatex; - Width = header->width; - Height = header->height; - LeftOffset = header->leftoffset; - TopOffset = header->topoffset; + Width = w; + Height = h; + LeftOffset = lo; + TopOffset = to; DetectBadPatches(); } @@ -163,17 +178,17 @@ FPatchTexture::FPatchTexture (int lumpnum, patch_t * header, bool isalphatex) // //========================================================================== -TArray FPatchTexture::CreatePalettedPixels(int conversion) +PalettedPixels FPatchTexture::CreatePalettedPixels(int conversion, int frame) { uint8_t *remap, remaptable[256]; int numspans; const column_t *maxcol; int x; - FMemLump lump = Wads.ReadLump (SourceLump); - const patch_t *patch = (const patch_t *)lump.GetMem(); + auto lump = fileSystem.ReadFile (SourceLump); + const patch_t *patch = (const patch_t *)lump.data(); - maxcol = (const column_t *)((const uint8_t *)patch + Wads.LumpLength (SourceLump) - 3); + maxcol = (const column_t *)((const uint8_t *)patch + fileSystem.FileLength (SourceLump) - 3); remap = ImageHelpers::GetRemap(conversion == luminance, isalpha); // Special case for skies @@ -186,7 +201,7 @@ TArray FPatchTexture::CreatePalettedPixels(int conversion) if (badflag) { - TArray Pixels(Width * Height, true); + PalettedPixels Pixels(Width * Height); uint8_t *out; // Draw the image to the buffer @@ -207,7 +222,7 @@ TArray FPatchTexture::CreatePalettedPixels(int conversion) numspans = Width; - TArray Pixels(numpix, true); + PalettedPixels Pixels(numpix); memset (Pixels.Data(), 0, numpix); // Draw the image to the buffer @@ -260,10 +275,10 @@ TArray FPatchTexture::CreatePalettedPixels(int conversion) // //========================================================================== -int FPatchTexture::CopyPixels(FBitmap *bmp, int conversion) +int FPatchTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { - if (!isalpha) return FImageSource::CopyPixels(bmp, conversion); - else return CopyTranslatedPixels(bmp, translationtables[TRANSLATION_Standard][STD_Grayscale]->Palette); + if (!isalpha) return FImageSource::CopyPixels(bmp, conversion, frame); + else return CopyTranslatedPixels(bmp, GPalette.GrayscaleMap.Palette, frame); } //========================================================================== @@ -275,13 +290,13 @@ int FPatchTexture::CopyPixels(FBitmap *bmp, int conversion) void FPatchTexture::DetectBadPatches () { // The patch must look like it is large enough for the rules to apply to avoid using this on truly empty patches. - if (Wads.LumpLength(SourceLump) < Width * Height / 2) return; + if (fileSystem.FileLength(SourceLump) < Width * Height / 2) return; // Check if this patch is likely to be a problem. // It must be 256 pixels tall, and all its columns must have exactly // one post, where each post has a supposed length of 0. - FMemLump lump = Wads.ReadLump (SourceLump); - const patch_t *realpatch = (patch_t *)lump.GetMem(); + auto lump = fileSystem.ReadFile (SourceLump); + const patch_t *realpatch = (patch_t *)lump.data(); const uint32_t *cofs = realpatch->columnofs; int x, x2 = LittleShort(realpatch->width); diff --git a/src/gamedata/textures/formats/pcxtexture.cpp b/src/common/textures/formats/pcxtexture.cpp similarity index 92% rename from src/gamedata/textures/formats/pcxtexture.cpp rename to src/common/textures/formats/pcxtexture.cpp index 70cb7e2e789..6981f91e03b 100644 --- a/src/gamedata/textures/formats/pcxtexture.cpp +++ b/src/common/textures/formats/pcxtexture.cpp @@ -4,7 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2005 David HENRY -** Copyright 2006 Christoph Oelckers +** Copyright 2006-2019 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -34,13 +34,12 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" +#include "filesystem.h" #include "bitmap.h" -#include "v_video.h" #include "imagehelpers.h" #include "image.h" +#include "m_swap.h" //========================================================================== // @@ -85,7 +84,7 @@ class FPCXTexture : public FImageSource public: FPCXTexture (int lumpnum, PCXHeader &); - int CopyPixels(FBitmap *bmp, int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; protected: void ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr); @@ -93,7 +92,7 @@ class FPCXTexture : public FImageSource void ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr); void ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr, int planes); - TArray CreatePalettedPixels(int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; }; @@ -161,8 +160,8 @@ void FPCXTexture::ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr) int rle_count = 0; uint8_t rle_value = 0; - TArray srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp.Data(); + auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); + const uint8_t * src = srcp.bytes(); for (y = 0; y < Height; ++y) { @@ -211,8 +210,8 @@ void FPCXTexture::ReadPCX4bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) TArray line(hdr->bytesPerScanLine, true); TArray colorIndex(Width, true); - TArray srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp.Data(); + auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); + const uint8_t * src = srcp.bytes(); for (y = 0; y < Height; ++y) { @@ -266,7 +265,7 @@ void FPCXTexture::ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) int y, bytes; auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp.Data(); + const uint8_t * src = srcp.bytes(); for (y = 0; y < Height; ++y) { @@ -307,7 +306,7 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr int bytes; auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp.Data(); + const uint8_t * src = srcp.bytes(); for (y = 0; y < Height; ++y) { @@ -346,18 +345,18 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr // //========================================================================== -TArray FPCXTexture::CreatePalettedPixels(int conversion) +PalettedPixels FPCXTexture::CreatePalettedPixels(int conversion, int frame) { uint8_t PaletteMap[256]; PCXHeader header; int bitcount; - auto lump = Wads.OpenLumpReader(SourceLump); + auto lump = fileSystem.OpenFileReader(SourceLump); lump.Read(&header, sizeof(header)); bitcount = header.bitsPerPixel * header.numColorPlanes; - TArray Pixels(Width*Height, true); + PalettedPixels Pixels(Width*Height); bool alphatex = conversion == luminance; if (bitcount < 24) @@ -368,8 +367,8 @@ TArray FPCXTexture::CreatePalettedPixels(int conversion) { default: case 1: - PaletteMap[0] = alphatex? 0 : ImageHelpers::GrayMap[0]; - PaletteMap[1] = alphatex? 255 : ImageHelpers::GrayMap[255]; + PaletteMap[0] = alphatex? 0 : GPalette.GrayMap[0]; + PaletteMap[1] = alphatex? 255 : GPalette.GrayMap[255]; ReadPCX1bit (Pixels.Data(), lump, &header); break; @@ -385,7 +384,7 @@ TArray FPCXTexture::CreatePalettedPixels(int conversion) else if (bitcount == 8) { lump.Seek(-769, FileReader::SeekEnd); - uint8_t c = lump.ReadUInt8(); + lump.ReadUInt8(); //if (c !=0x0c) memcpy(PaletteMap, GrayMap, 256); // Fallback for files without palette //else for(int i=0;i<256;i++) @@ -404,7 +403,7 @@ TArray FPCXTexture::CreatePalettedPixels(int conversion) } else { - TArray newpix(Width*Height, true); + PalettedPixels newpix(Width*Height); ImageHelpers::FlipNonSquareBlockRemap (newpix.Data(), Pixels.Data(), Width, Height, Width, PaletteMap); return newpix; } @@ -434,14 +433,14 @@ TArray FPCXTexture::CreatePalettedPixels(int conversion) // //=========================================================================== -int FPCXTexture::CopyPixels(FBitmap *bmp, int conversion) +int FPCXTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { PalEntry pe[256]; PCXHeader header; int bitcount; TArray Pixels; - auto lump = Wads.OpenLumpReader(SourceLump); + auto lump = fileSystem.OpenFileReader(SourceLump); lump.Read(&header, sizeof(header)); diff --git a/src/gamedata/textures/formats/pngtexture.cpp b/src/common/textures/formats/pngtexture.cpp similarity index 77% rename from src/gamedata/textures/formats/pngtexture.cpp rename to src/common/textures/formats/pngtexture.cpp index ccf13d0daad..01f210a1c5b 100644 --- a/src/gamedata/textures/formats/pngtexture.cpp +++ b/src/common/textures/formats/pngtexture.cpp @@ -4,6 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2004-2007 Randy Heit +** Copyright 2005-2019 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -33,14 +34,16 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" -#include "templates.h" + #include "m_png.h" #include "bitmap.h" #include "imagehelpers.h" #include "image.h" +#include "printf.h" +#include "texturemanager.h" +#include "filesystem.h" +#include "m_swap.h" //========================================================================== // @@ -53,11 +56,12 @@ class FPNGTexture : public FImageSource public: FPNGTexture (FileReader &lump, int lumpnum, int width, int height, uint8_t bitdepth, uint8_t colortype, uint8_t interlace); - int CopyPixels(FBitmap *bmp, int conversion) override; - TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; protected: void ReadAlphaRemap(FileReader *lump, uint8_t *alpharemap); + void SetupPalette(FileReader &lump); uint8_t BitDepth; uint8_t ColorType; @@ -71,6 +75,7 @@ class FPNGTexture : public FImageSource uint32_t StartOfPalette = 0; }; +FImageSource* StbImage_TryCreate(FileReader& file, int lumpnum); //========================================================================== // @@ -114,14 +119,57 @@ FImageSource *PNGImage_TryCreate(FileReader & data, int lumpnum) if (compression != 0 || filter != 0 || interlace > 1) { + Printf(TEXTCOLOR_YELLOW"WARNING: failed to load PNG %s: the compression, filter, or interlace is not supported!\n", fileSystem.GetFileFullName(lumpnum)); return NULL; } if (!((1 << colortype) & 0x5D)) { + Printf(TEXTCOLOR_YELLOW"WARNING: failed to load PNG %s: the colortype (%u) is not supported!\n", fileSystem.GetFileFullName(lumpnum), colortype); return NULL; } if (!((1 << bitdepth) & 0x116)) { + // Try STBImage for 16 bit PNGs. + auto tex = StbImage_TryCreate(data, lumpnum); + if (tex) + { + // STBImage does not handle grAb, so do that here and insert the data into the texture. + data.Seek(33, FileReader::SeekSet); + + int len = data.ReadInt32BE(); + int id = data.ReadInt32(); + while (id != MAKE_ID('I', 'D', 'A', 'T') && id != MAKE_ID('I', 'E', 'N', 'D')) + { + if (id != MAKE_ID('g', 'r', 'A', 'b')) + { + data.Seek(len, FileReader::SeekCur); + } + else + { + int ihotx = data.ReadInt32BE(); + int ihoty = data.ReadInt32BE(); + if (ihotx < -32768 || ihotx > 32767) + { + Printf("X-Offset for PNG texture %s is bad: %d (0x%08x)\n", fileSystem.GetFileFullName(lumpnum), ihotx, ihotx); + ihotx = 0; + } + if (ihoty < -32768 || ihoty > 32767) + { + Printf("Y-Offset for PNG texture %s is bad: %d (0x%08x)\n", fileSystem.GetFileFullName(lumpnum), ihoty, ihoty); + ihoty = 0; + } + tex->SetOffsets(ihotx, ihoty); + } + + data.Seek(4, FileReader::SeekCur); // Skip CRC + len = data.ReadInt32BE(); + id = MAKE_ID('I', 'E', 'N', 'D'); + id = data.ReadInt32(); + } + return tex; + } + + Printf(TEXTCOLOR_YELLOW"WARNING: failed to load PNG %s: the bit-depth (%u) is not supported!\n", fileSystem.GetFileFullName(lumpnum), bitdepth); return NULL; } @@ -130,9 +178,9 @@ FImageSource *PNGImage_TryCreate(FileReader & data, int lumpnum) data.Read (first4bytes.b, 4); if (first4bytes.dw == 0) { - data.Read (first4bytes.b, 4); - if (first4bytes.dw == MAKE_ID('I','E','N','D')) + if (data.Read(first4bytes.b, 4) != 4 || first4bytes.dw == MAKE_ID('I','E','N','D')) { + Printf(TEXTCOLOR_YELLOW"WARNING: failed to load PNG %s: the file ends immediately after the IHDR.\n", fileSystem.GetFileFullName(lumpnum)); return NULL; } } @@ -151,11 +199,6 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, int width, int height, : FImageSource(lumpnum), BitDepth(depth), ColorType(colortype), Interlace(interlace), HaveTrans(false) { - union - { - uint32_t palette[256]; - uint8_t pngpal[256][3]; - } p; uint8_t trans[256]; uint32_t len, id; int i; @@ -184,21 +227,16 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, int width, int height, case MAKE_ID('g','r','A','b'): // This is like GRAB found in an ILBM, except coordinates use 4 bytes { - uint32_t hotx, hoty; - int ihotx, ihoty; - - lump.Read(&hotx, 4); - lump.Read(&hoty, 4); - ihotx = BigLong((int)hotx); - ihoty = BigLong((int)hoty); + int ihotx = lump.ReadInt32BE(); + int ihoty = lump.ReadInt32BE(); if (ihotx < -32768 || ihotx > 32767) { - Printf ("X-Offset for PNG texture %s is bad: %d (0x%08x)\n", Wads.GetLumpFullName (lumpnum), ihotx, ihotx); + Printf ("X-Offset for PNG texture %s is bad: %d (0x%08x)\n", fileSystem.GetFileFullName (lumpnum), ihotx, ihotx); ihotx = 0; } if (ihoty < -32768 || ihoty > 32767) { - Printf ("Y-Offset for PNG texture %s is bad: %d (0x%08x)\n", Wads.GetLumpFullName (lumpnum), ihoty, ihoty); + Printf ("Y-Offset for PNG texture %s is bad: %d (0x%08x)\n", fileSystem.GetFileFullName (lumpnum), ihoty, ihoty); ihoty = 0; } LeftOffset = ihotx; @@ -207,17 +245,9 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, int width, int height, break; case MAKE_ID('P','L','T','E'): - PaletteSize = MIN (len / 3, 256); + PaletteSize = min (len / 3, 256); StartOfPalette = (uint32_t)lump.Tell(); - lump.Read (p.pngpal, PaletteSize * 3); - if (PaletteSize * 3 != (int)len) - { - lump.Seek (len - PaletteSize * 3, FileReader::SeekCur); - } - for (i = PaletteSize - 1; i >= 0; --i) - { - p.palette[i] = MAKERGB(p.pngpal[i][0], p.pngpal[i][1], p.pngpal[i][2]); - } + lump.Seek(len, FileReader::SeekCur); break; case MAKE_ID('t','R','N','S'): @@ -247,25 +277,19 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, int width, int height, { bMasked = true; PaletteSize = 256; - PaletteMap = (uint8_t*)ImageArena.Alloc(PaletteSize); - memcpy (PaletteMap, ImageHelpers::GrayMap, 256); - PaletteMap[NonPaletteTrans[0]] = 0; } else { - PaletteMap = ImageHelpers::GrayMap; + PaletteMap = GPalette.GrayMap; } break; case 3: // Paletted - PaletteMap = (uint8_t*)ImageArena.Alloc(PaletteSize); - GPalette.MakeRemap (p.palette, PaletteMap, trans, PaletteSize); for (i = 0; i < PaletteSize; ++i) { if (trans[i] == 0) { bMasked = true; - PaletteMap[i] = 0; } } break; @@ -280,6 +304,87 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, int width, int height, } } +void FPNGTexture::SetupPalette(FileReader &lump) +{ + union + { + uint32_t palette[256]; + uint8_t pngpal[256][3]; + } p; + uint8_t trans[256]; + uint32_t len, id; + int i; + + auto pos = lump.Tell(); + + memset(trans, 255, 256); + + // Parse pre-IDAT chunks. I skip the CRCs. Is that bad? + lump.Seek(33, FileReader::SeekSet); + + lump.Read(&len, 4); + lump.Read(&id, 4); + while (id != MAKE_ID('I', 'D', 'A', 'T') && id != MAKE_ID('I', 'E', 'N', 'D')) + { + len = BigLong((unsigned int)len); + switch (id) + { + default: + lump.Seek(len, FileReader::SeekCur); + break; + + case MAKE_ID('P', 'L', 'T', 'E'): + lump.Read(p.pngpal, PaletteSize * 3); + if (PaletteSize * 3 != (int)len) + { + lump.Seek(len - PaletteSize * 3, FileReader::SeekCur); + } + for (i = PaletteSize - 1; i >= 0; --i) + { + p.palette[i] = MAKERGB(p.pngpal[i][0], p.pngpal[i][1], p.pngpal[i][2]); + } + break; + + case MAKE_ID('t', 'R', 'N', 'S'): + lump.Read(trans, len); + break; + } + lump.Seek(4, FileReader::SeekCur); // Skip CRC + lump.Read(&len, 4); + id = MAKE_ID('I', 'E', 'N', 'D'); + lump.Read(&id, 4); + } + StartOfIDAT = (uint32_t)lump.Tell() - 8; + + switch (ColorType) + { + case 0: // Grayscale + if (HaveTrans && NonPaletteTrans[0] < 256) + { + PaletteMap = (uint8_t*)ImageArena.Alloc(PaletteSize); + memcpy(PaletteMap, GPalette.GrayMap, 256); + PaletteMap[NonPaletteTrans[0]] = 0; + } + break; + + case 3: // Paletted + PaletteMap = (uint8_t*)ImageArena.Alloc(PaletteSize); + MakeRemap((uint32_t*)GPalette.BaseColors, p.palette, PaletteMap, trans, PaletteSize); + for (i = 0; i < PaletteSize; ++i) + { + if (trans[i] == 0) + { + PaletteMap[i] = 0; + } + } + break; + + default: + break; + } + lump.Seek(pos, FileReader::SeekSet); +} + //========================================================================== // // @@ -295,7 +400,8 @@ void FPNGTexture::ReadAlphaRemap(FileReader *lump, uint8_t *alpharemap) uint8_t r = lump->ReadUInt8(); uint8_t g = lump->ReadUInt8(); uint8_t b = lump->ReadUInt8(); - alpharemap[i] = PaletteMap[i] == 0 ? 0 : Luminance(r, g, b); + int palmap = PaletteMap ? PaletteMap[i] : i; + alpharemap[i] = palmap == 0 ? 0 : Luminance(r, g, b); } lump->Seek(p, FileReader::SeekSet); } @@ -306,15 +412,15 @@ void FPNGTexture::ReadAlphaRemap(FileReader *lump, uint8_t *alpharemap) // //========================================================================== -TArray FPNGTexture::CreatePalettedPixels(int conversion) +PalettedPixels FPNGTexture::CreatePalettedPixels(int conversion, int frame) { FileReader *lump; FileReader lfr; - lfr = Wads.OpenLumpReader(SourceLump); + lfr = fileSystem.OpenFileReader(SourceLump); lump = 𝔩 - TArray Pixels(Width*Height, true); + PalettedPixels Pixels(Width*Height); if (StartOfIDAT == 0) { memset (Pixels.Data(), 0x99, Width*Height); @@ -335,6 +441,7 @@ TArray FPNGTexture::CreatePalettedPixels(int conversion) { if (conversion != luminance) { + if (!PaletteMap) SetupPalette(lfr); ImageHelpers::FlipSquareBlockRemap (Pixels.Data(), Width, PaletteMap); } else if (ColorType == 0) @@ -350,9 +457,10 @@ TArray FPNGTexture::CreatePalettedPixels(int conversion) } else { - TArray newpix(Width*Height, true); + PalettedPixels newpix(Width*Height); if (conversion != luminance) { + if (!PaletteMap) SetupPalette(lfr); ImageHelpers::FlipNonSquareBlockRemap (newpix.Data(), Pixels.Data(), Width, Height, Width, PaletteMap); } else if (ColorType == 0) @@ -407,6 +515,7 @@ TArray FPNGTexture::CreatePalettedPixels(int conversion) case 4: // Grayscale + Alpha pitch = Width * 2; backstep = Height * pitch - 2; + if (!PaletteMap) SetupPalette(lfr); for (x = Width; x > 0; --x) { for (y = Height; y > 0; --y) @@ -444,7 +553,7 @@ TArray FPNGTexture::CreatePalettedPixels(int conversion) // //=========================================================================== -int FPNGTexture::CopyPixels(FBitmap *bmp, int conversion) +int FPNGTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { // Parse pre-IDAT chunks. I skip the CRCs. Is that bad? PalEntry pe[256]; @@ -456,7 +565,7 @@ int FPNGTexture::CopyPixels(FBitmap *bmp, int conversion) FileReader *lump; FileReader lfr; - lfr = Wads.OpenLumpReader(SourceLump); + lfr = fileSystem.OpenFileReader(SourceLump); lump = 𝔩 lump->Seek(33, FileReader::SeekSet); @@ -557,6 +666,7 @@ int FPNGTexture::CopyPixels(FBitmap *bmp, int conversion) } +#include "textures.h" //========================================================================== // @@ -572,10 +682,10 @@ class FPNGFileTexture : public FTexture { public: FPNGFileTexture (FileReader &lump, int width, int height, uint8_t colortype); - virtual FBitmap GetBgraBitmap(PalEntry *remap, int *trans); + virtual FBitmap GetBgraBitmap(const PalEntry *remap, int *trans) override; protected: - + FileReader fr; uint8_t ColorType; int PaletteSize; @@ -588,13 +698,13 @@ class FPNGFileTexture : public FTexture // //========================================================================== -FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename) +FGameTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename) { if (M_FindPNGChunk(png, MAKE_ID('I','H','D','R')) == 0) { return nullptr; } - + // Savegame images can only be either 8 bit paletted or 24 bit RGB auto &data = png->File; int width = data.ReadInt32BE(); @@ -604,10 +714,10 @@ FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename) uint8_t compression = data.ReadUInt8(); uint8_t filter = data.ReadUInt8(); uint8_t interlace = data.ReadUInt8(); - + // Reject anything that cannot be put into a savegame picture by GZDoom itself. if (compression != 0 || filter != 0 || interlace > 0 || bitdepth != 8 || (colortype != 2 && colortype != 3)) return nullptr; - else return new FPNGFileTexture (png->File, width, height, colortype); + else return MakeGameTexture(new FPNGFileTexture (png->File, width, height, colortype), nullptr, ETextureType::Override); } //========================================================================== @@ -621,6 +731,8 @@ FPNGFileTexture::FPNGFileTexture (FileReader &lump, int width, int height, uint8 { Width = width; Height = height; + Masked = false; + bTranslucent = false; fr = std::move(lump); } @@ -630,16 +742,16 @@ FPNGFileTexture::FPNGFileTexture (FileReader &lump, int width, int height, uint8 // //=========================================================================== -FBitmap FPNGFileTexture::GetBgraBitmap(PalEntry *remap, int *trans) +FBitmap FPNGFileTexture::GetBgraBitmap(const PalEntry *remap, int *trans) { FBitmap bmp; // Parse pre-IDAT chunks. I skip the CRCs. Is that bad? PalEntry pe[256]; uint32_t len, id; int pixwidth = Width * (ColorType == 2? 3:1); - + FileReader *lump = &fr; - + bmp.Create(Width, Height); lump->Seek(33, FileReader::SeekSet); lump->Read(&len, 4); @@ -651,7 +763,7 @@ FBitmap FPNGFileTexture::GetBgraBitmap(PalEntry *remap, int *trans) lump->Seek (len, FileReader::SeekCur); else { - PaletteSize = MIN (len / 3, 256); + PaletteSize = min (len / 3, 256); for(int i = 0; i < PaletteSize; i++) { pe[i].r = lump->ReadUInt8(); @@ -668,12 +780,12 @@ FBitmap FPNGFileTexture::GetBgraBitmap(PalEntry *remap, int *trans) auto StartOfIDAT = (uint32_t)lump->Tell() - 8; TArray Pixels(pixwidth * Height); - + lump->Seek (StartOfIDAT, FileReader::SeekSet); lump->Read(&len, 4); lump->Read(&id, 4); M_ReadIDAT (*lump, Pixels.Data(), Width, Height, pixwidth, 8, ColorType, 0, BigLong((unsigned int)len)); - + if (ColorType == 3) { bmp.CopyPixelData(0, 0, Pixels.Data(), Width, Height, 1, Width, 0, pe); @@ -683,4 +795,4 @@ FBitmap FPNGFileTexture::GetBgraBitmap(PalEntry *remap, int *trans) bmp.CopyPixelDataRGB(0, 0, Pixels.Data(), Width, Height, 3, pixwidth, 0, CF_RGB); } return bmp; -} +} \ No newline at end of file diff --git a/src/common/textures/formats/qoitexture.cpp b/src/common/textures/formats/qoitexture.cpp new file mode 100644 index 00000000000..07511aaf9ae --- /dev/null +++ b/src/common/textures/formats/qoitexture.cpp @@ -0,0 +1,213 @@ +/* +** qoitexture.cpp +** Texture class for QOI (Quite OK Image Format) images +** +**--------------------------------------------------------------------------- +** Copyright 2023 Cacodemon345 +** Copyright 2022 Dominic Szablewski +** All rights reserved. +** +** 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" + +#pragma pack(1) + +struct QOIHeader +{ + char magic[4]; + uint32_t width; + uint32_t height; + uint8_t channels; + uint8_t colorspace; +}; +#pragma pack() + +class FQOITexture : public FImageSource +{ +public: + FQOITexture(int lumpnum, QOIHeader& header); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; +}; + +FImageSource *QOIImage_TryCreate(FileReader &file, int lumpnum) +{ + QOIHeader header; + + if ((size_t)file.GetLength() < (sizeof(header) + 8)) + { + return nullptr; + } + + file.Seek(0, FileReader::SeekSet); + file.Read((void *)&header, sizeof(header)); + + if (header.magic[0] != 'q' || header.magic[1] != 'o' || header.magic[2] != 'i' || header.magic[3] != 'f') + { + return nullptr; + } + + if (header.width == 0 || header.height == 0 || header.channels < 3 || header.channels > 4 || header.colorspace > 1) + { + return nullptr; + } + + return new FQOITexture(lumpnum, header); +} + +FQOITexture::FQOITexture(int lumpnum, QOIHeader& header) + : FImageSource(lumpnum) +{ + LeftOffset = TopOffset = 0; + Width = header.width; + Height = header.height; + if (header.channels == 3) bMasked = (bTranslucent = false); +} + +PalettedPixels FQOITexture::CreatePalettedPixels(int conversion, int frame) +{ + FBitmap bitmap; + bitmap.Create(Width, Height); + CopyPixels(&bitmap, conversion); + const uint8_t *data = bitmap.GetPixels(); + + uint8_t *dest_p; + int dest_adv = Height; + int dest_rew = Width * Height - 1; + + PalettedPixels Pixels(Width * Height); + dest_p = Pixels.Data(); + + bool doalpha = conversion == luminance; + // Convert the source image from row-major to column-major format and remap it + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + int b = *data++; + int g = *data++; + int r = *data++; + int a = *data++; + if (a < 128) + *dest_p = 0; + else + *dest_p = ImageHelpers::RGBToPalette(doalpha, r, g, b); + dest_p += dest_adv; + } + dest_p -= dest_rew; + } + return Pixels; +} + +int FQOITexture::CopyPixels(FBitmap *bmp, int conversion, int frame) +{ + enum + { + QOI_OP_INDEX = 0x00, /* 00xxxxxx */ + QOI_OP_DIFF = 0x40, /* 01xxxxxx */ + QOI_OP_LUMA = 0x80, /* 10xxxxxx */ + QOI_OP_RUN = 0xc0, /* 11xxxxxx */ + QOI_OP_RGB = 0xfe, /* 11111110 */ + QOI_OP_RGBA = 0xff, /* 11111111 */ + + QOI_MASK_2 = 0xc0, /* 11000000 */ + }; + + constexpr auto QOI_COLOR_HASH = [](PalEntry C) { return (C.r * 3 + C.g * 5 + C.b * 7 + C.a * 11); }; + + auto lump = fileSystem.ReadFile(SourceLump); + if (lump.size() < 22) return 0; // error + PalEntry index[64] = {}; + PalEntry pe = 0xff000000; + + size_t p = 14, run = 0; + + size_t chunks_len = lump.size() - 8; + auto bytes = lump.bytes(); + + for (int h = 0; h < Height; h++) + { + auto pixels = bmp->GetPixels() + h * bmp->GetPitch(); + for (int w = 0; w < Width; w++) + { + if (run > 0) + { + run--; + } + else if (p < chunks_len) + { + int b1 = bytes[p++]; + + if (b1 == QOI_OP_RGB) + { + pe.r = bytes[p++]; + pe.g = bytes[p++]; + pe.b = bytes[p++]; + } + else if (b1 == QOI_OP_RGBA) + { + pe.r = bytes[p++]; + pe.g = bytes[p++]; + pe.b = bytes[p++]; + pe.a = bytes[p++]; + } + else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) + { + pe = index[b1]; + } + else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) + { + pe.r += ((b1 >> 4) & 0x03) - 2; + pe.g += ((b1 >> 2) & 0x03) - 2; + pe.b += (b1 & 0x03) - 2; + } + else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) + { + int b2 = bytes[p++]; + int vg = (b1 & 0x3f) - 32; + pe.r += vg - 8 + ((b2 >> 4) & 0x0f); + pe.g += vg; + pe.b += vg - 8 + (b2 & 0x0f); + } + else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) + { + run = (b1 & 0x3f); + } + + index[QOI_COLOR_HASH(pe) % 64] = pe; + } + } + + pixels[0] = pe.b; + pixels[1] = pe.g; + pixels[2] = pe.r; + pixels[3] = pe.a; + pixels += 4; + } + return bMasked? -1 : 0; +} diff --git a/src/gamedata/textures/formats/rawpagetexture.cpp b/src/common/textures/formats/rawpagetexture.cpp similarity index 79% rename from src/gamedata/textures/formats/rawpagetexture.cpp rename to src/common/textures/formats/rawpagetexture.cpp index 3cc136dfce7..52b3f3c5355 100644 --- a/src/gamedata/textures/formats/rawpagetexture.cpp +++ b/src/common/textures/formats/rawpagetexture.cpp @@ -33,14 +33,22 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" -#include "gi.h" +#include "filesystem.h" #include "bitmap.h" -#include "textures/textures.h" #include "imagehelpers.h" #include "image.h" +#include "m_swap.h" + +// Doom patch format header +struct patch_t +{ + int16_t width; // bounding box size + int16_t height; + int16_t leftoffset; // pixels to the left of origin + int16_t topoffset; // pixels below the origin + uint32_t columnofs[1]; // only [width] used +}; //========================================================================== @@ -54,8 +62,8 @@ class FRawPageTexture : public FImageSource int mPaletteLump = -1; public: FRawPageTexture (int lumpnum); - TArray CreatePalettedPixels(int conversion) override; - int CopyPixels(FBitmap *bmp, int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; }; //========================================================================== @@ -65,9 +73,9 @@ class FRawPageTexture : public FImageSource // //========================================================================== -static bool CheckIfRaw(FileReader & data) +bool CheckIfRaw(FileReader & data, unsigned desiredsize) { - if (data.GetLength() != 64000) return false; + if (data.GetLength() != desiredsize) return false; // This is probably a raw page graphic, but do some checking to be sure patch_t *foo; @@ -76,7 +84,7 @@ static bool CheckIfRaw(FileReader & data) data.Seek(0, FileReader::SeekSet); auto bits = data.Read(data.GetLength()); - foo = (patch_t *)bits.Data();; + foo = (patch_t *)bits.data(); height = LittleShort(foo->height); width = LittleShort(foo->width); @@ -97,7 +105,7 @@ static bool CheckIfRaw(FileReader & data) { gapAtStart = false; } - else if (ofs >= 64000-1) // Need one byte for an empty column + else if (ofs >= desiredsize-1) // Need one byte for an empty column { return true; } @@ -105,7 +113,7 @@ static bool CheckIfRaw(FileReader & data) { // Ensure this column does not extend beyond the end of the patch const uint8_t *foo2 = (const uint8_t *)foo; - while (ofs < 64000) + while (ofs < desiredsize) { if (foo2[ofs] == 255) { @@ -113,7 +121,7 @@ static bool CheckIfRaw(FileReader & data) } ofs += foo2[ofs+1] + 4; } - if (ofs >= 64000) + if (ofs >= desiredsize) { return true; } @@ -139,7 +147,7 @@ static bool CheckIfRaw(FileReader & data) FImageSource *RawPageImage_TryCreate(FileReader & file, int lumpnum) { - if (!CheckIfRaw(file)) return nullptr; + if (!CheckIfRaw(file, 64000)) return nullptr; return new FRawPageTexture(lumpnum); } @@ -157,12 +165,11 @@ FRawPageTexture::FRawPageTexture (int lumpnum) Height = 200; // Special case hack for Heretic's E2 end pic. This is not going to be exposed as an editing feature because the implications would be horrible. - FString Name; - Wads.GetLumpName(Name, lumpnum); - if (Name.CompareNoCase("E2END") == 0 && gameinfo.gametype == GAME_Heretic) + auto Name = fileSystem.GetFileShortName(lumpnum); + if (stricmp(Name, "E2END") == 0) { - mPaletteLump = Wads.CheckNumForName("E2PAL"); - if (Wads.LumpLength(mPaletteLump) < 768) mPaletteLump = -1; + mPaletteLump = fileSystem.CheckNumForName("E2PAL"); + if (fileSystem.FileLength(mPaletteLump) < 768) mPaletteLump = -1; } else bUseGamePalette = true; } @@ -173,14 +180,14 @@ FRawPageTexture::FRawPageTexture (int lumpnum) // //========================================================================== -TArray FRawPageTexture::CreatePalettedPixels(int conversion) +PalettedPixels FRawPageTexture::CreatePalettedPixels(int conversion, int frame) { - FMemLump lump = Wads.ReadLump (SourceLump); - const uint8_t *source = (const uint8_t *)lump.GetMem(); + auto lump = fileSystem.ReadFile (SourceLump); + auto source = lump.bytes(); const uint8_t *source_p = source; uint8_t *dest_p; - TArray Pixels(Width*Height, true); + PalettedPixels Pixels(Width*Height); dest_p = Pixels.Data(); const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); @@ -202,15 +209,15 @@ TArray FRawPageTexture::CreatePalettedPixels(int conversion) return Pixels; } -int FRawPageTexture::CopyPixels(FBitmap *bmp, int conversion) +int FRawPageTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { - if (mPaletteLump < 0) return FImageSource::CopyPixels(bmp, conversion); + if (mPaletteLump < 0) return FImageSource::CopyPixels(bmp, conversion, frame); else { - FMemLump lump = Wads.ReadLump(SourceLump); - FMemLump plump = Wads.ReadLump(mPaletteLump); - const uint8_t *source = (const uint8_t *)lump.GetMem(); - const uint8_t *psource = (const uint8_t *)plump.GetMem(); + auto lump = fileSystem.ReadFile(SourceLump); + auto plump = fileSystem.ReadFile(mPaletteLump); + auto source = lump.bytes(); + auto psource = plump.bytes(); PalEntry paldata[256]; for (auto & pe : paldata) { diff --git a/src/gamedata/textures/formats/shadertexture.cpp b/src/common/textures/formats/shadertexture.cpp similarity index 87% rename from src/gamedata/textures/formats/shadertexture.cpp rename to src/common/textures/formats/shadertexture.cpp index 8f817d9bc62..0b69e8acb2a 100644 --- a/src/gamedata/textures/formats/shadertexture.cpp +++ b/src/common/textures/formats/shadertexture.cpp @@ -34,13 +34,11 @@ ** */ -#include "doomtype.h" -#include "d_player.h" -#include "menu/menu.h" -#include "w_wad.h" +#include "filesystem.h" #include "bitmap.h" #include "imagehelpers.h" #include "image.h" +#include "textures.h" class FBarShader : public FImageSource @@ -100,9 +98,9 @@ class FBarShader : public FImageSource } } - TArray CreatePalettedPixels(int conversion) override + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override { - TArray Pix(512, true); + PalettedPixels Pix(512); if (conversion == luminance) { memcpy(Pix.Data(), Pixels, 512); @@ -114,15 +112,15 @@ class FBarShader : public FImageSource // even if it makes little sense. for (int i = 0; i < 512; i++) { - Pix[i] = ImageHelpers::GrayMap[Pixels[i]]; + Pix[i] = GPalette.GrayMap[Pixels[i]]; } } return Pix; } - int CopyPixels(FBitmap *bmp, int conversion) override + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override { - bmp->CopyPixelData(0, 0, Pixels, Width, Height, Height, 1, 0, translationtables[TRANSLATION_Standard][8]->Palette); + bmp->CopyPixelData(0, 0, Pixels, Width, Height, Height, 1, 0, GPalette.GrayRamp.Palette); return 0; } @@ -131,9 +129,9 @@ class FBarShader : public FImageSource }; -FTexture *CreateShaderTexture(bool vertical, bool reverse) +FGameTexture *CreateShaderTexture(bool vertical, bool reverse) { FStringf name("BarShader%c%c", vertical ? 'v' : 'h', reverse ? 'r' : 'f'); - return new FImageTexture(new FBarShader(vertical, reverse), name.GetChars()); + return MakeGameTexture(CreateImageTexture(new FBarShader(vertical, reverse)), name.GetChars(), ETextureType::Override); } diff --git a/src/common/textures/formats/startscreentexture.cpp b/src/common/textures/formats/startscreentexture.cpp new file mode 100644 index 00000000000..155bae19b1d --- /dev/null +++ b/src/common/textures/formats/startscreentexture.cpp @@ -0,0 +1,81 @@ +/* +** startscreentexture.cpp +** Texture class to create a texture from the start screen's imagé +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "bitmap.h" +#include "textures.h" +#include "imagehelpers.h" +#include "image.h" +#include "startscreen.h" + + +//========================================================================== +// +// +// +//========================================================================== + +class FStartScreenTexture : public FImageSource +{ + FBitmap& info; // This must remain constant for the lifetime of this texture + +public: + FStartScreenTexture(FBitmap& srcdata) + : FImageSource(-1), info(srcdata) + { + Width = srcdata.GetWidth(); + Height = srcdata.GetHeight(); + bUseGamePalette = false; + } + int CopyPixels(FBitmap* bmp, int conversion, int frame = 0) override + { + bmp->Blit(0, 0, info); + return 0; + } +}; + +//========================================================================== +// +// +// +//========================================================================== + +FImageSource *CreateStartScreenTexture(FBitmap& srcdata) +{ + return new FStartScreenTexture(srcdata); +} + + diff --git a/src/common/textures/formats/startuptexture.cpp b/src/common/textures/formats/startuptexture.cpp new file mode 100644 index 00000000000..c062251d8cf --- /dev/null +++ b/src/common/textures/formats/startuptexture.cpp @@ -0,0 +1,381 @@ + +/* +** startuptexture.cpp +** Texture class for Hexen's startup screen +** +**--------------------------------------------------------------------------- +** Copyright 2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" + +#define ST_NOTCH_WIDTH 16 +#define ST_NOTCH_HEIGHT 23 + +#define ST_NETNOTCH_WIDTH 4 +#define ST_NETNOTCH_HEIGHT 16 + +struct StrifeStartupInfo +{ + char name[9]; + uint8_t width, height; +}; + +static StrifeStartupInfo StrifeRawPics[] = +{ + { "STRTPA1", 32, 64}, + { "STRTPB1", 32, 64}, + { "STRTPC1", 32, 64}, + { "STRTPD1", 32, 64}, + { "STRTLZ1", 16, 16}, + { "STRTLZ2", 16, 16}, + { "STRTBOT", 48, 48} +}; + +// there is only one palette for all these images. +static uint8_t startuppalette8[16]; +static uint32_t startuppalette32[16]; + +//========================================================================== +// +// +// +//========================================================================== + +class FStartupTexture : public FImageSource +{ +public: + FStartupTexture (int lumpnum); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame) override; +}; + +class FNotchTexture : public FImageSource +{ +public: + FNotchTexture (int lumpnum, int width, int height); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame) override; +}; + +class FStrifeStartupTexture : public FImageSource +{ +public: + FStrifeStartupTexture (int lumpnum, int w, int h); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; +}; + +class FStrifeStartupBackground : public FImageSource +{ +public: + FStrifeStartupBackground (int lumpnum); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; +}; + +//========================================================================== +// +// Use the same function as raw textures to eliminate Doom patches +// +//========================================================================== + +bool CheckIfRaw(FileReader & data, unsigned desiredsize); + +//========================================================================== +// +// loads all raw images for Hexen's and Strife's startup screens +// +//========================================================================== + +FImageSource *StartupPageImage_TryCreate(FileReader & file, int lumpnum) +{ + if (fileSystem.CheckFileName(lumpnum, "STARTUP")) + { + if (!CheckIfRaw(file, 153648)) return nullptr; + return new FStartupTexture(lumpnum); + } + if (fileSystem.CheckFileName(lumpnum, "NOTCH")) + { + if (!CheckIfRaw(file, ST_NOTCH_WIDTH * ST_NOTCH_HEIGHT / 2)) return nullptr; + return new FNotchTexture(lumpnum, ST_NOTCH_WIDTH, ST_NOTCH_HEIGHT); + } + if (fileSystem.CheckFileName(lumpnum, "NETNOTCH")) + { + if (!CheckIfRaw(file, ST_NETNOTCH_WIDTH * ST_NETNOTCH_HEIGHT / 2)) return nullptr; + return new FNotchTexture(lumpnum, ST_NETNOTCH_WIDTH, ST_NETNOTCH_HEIGHT); + } + if (fileSystem.CheckFileName(lumpnum, "STARTUP0")) + { + if (!CheckIfRaw(file, 64000)) return nullptr; + return new FStrifeStartupBackground(lumpnum); + } + for(auto& sst : StrifeRawPics) + { + if (fileSystem.CheckFileName(lumpnum, sst.name)) + { + if (!CheckIfRaw(file, sst.width * sst.height)) return nullptr; + return new FStrifeStartupTexture(lumpnum, sst.width, sst.height); + } + } + return nullptr; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FStartupTexture::FStartupTexture (int lumpnum) +: FImageSource(lumpnum) +{ + Width = 640; + Height = 480; + bUseGamePalette = false; + + auto lump = fileSystem.ReadFile (SourceLump); + auto source = lump.bytes(); + + // Initialize the bitmap palette. + // the palette is static so that the notches can share it. + // Note that if the STARTUP image gets replaced, the notches will be all black unless they get replaced as well! + for (int i = 0; i < 16; ++i) + { + PalEntry pe; + pe.r = source[i * 3 + 0]; + pe.g = source[i * 3 + 1]; + pe.b = source[i * 3 + 2]; + pe.a = 63; + // Convert from 6-bit per component to 8-bit per component. + pe.d= (pe.d << 2) | ((pe.d >> 4) & 0x03030303); + startuppalette8[i] = ColorMatcher.Pick(pe); + startuppalette32[i] = pe; + } +} + +//========================================================================== +// +// PlanarToChunky +// +// Convert a 4-bpp planar image to chunky pixels. +// +//========================================================================== + +template +void PlanarToChunky(T* dest, const uint8_t* src, const T* remap, int width, int height) +{ + int y, x; + const uint8_t* src1, * src2, * src3, * src4; + size_t plane_size = width / 8 * height; + + src1 = src; + src2 = src1 + plane_size; + src3 = src2 + plane_size; + src4 = src3 + plane_size; + + for (y = height; y > 0; --y) + { + for (x = width; x > 0; x -= 8) + { + dest[0] = remap[((*src4 & 0x80) | ((*src3 & 0x80) >> 1) | ((*src2 & 0x80) >> 2) | ((*src1 & 0x80) >> 3)) >> 4]; + dest[1] = remap[((*src4 & 0x40) >> 3) | ((*src3 & 0x40) >> 4) | ((*src2 & 0x40) >> 5) | ((*src1 & 0x40) >> 6)]; + dest[2] = remap[(((*src4 & 0x20) << 2) | ((*src3 & 0x20) << 1) | ((*src2 & 0x20)) | ((*src1 & 0x20) >> 1)) >> 4]; + dest[3] = remap[((*src4 & 0x10) >> 1) | ((*src3 & 0x10) >> 2) | ((*src2 & 0x10) >> 3) | ((*src1 & 0x10) >> 4)]; + dest[4] = remap[(((*src4 & 0x08) << 4) | ((*src3 & 0x08) << 3) | ((*src2 & 0x08) << 2) | ((*src1 & 0x08) << 1)) >> 4]; + dest[5] = remap[((*src4 & 0x04) << 1) | ((*src3 & 0x04)) | ((*src2 & 0x04) >> 1) | ((*src1 & 0x04) >> 2)]; + dest[6] = remap[(((*src4 & 0x02) << 6) | ((*src3 & 0x02) << 5) | ((*src2 & 0x02) << 4) | ((*src1 & 0x02) << 3)) >> 4]; + dest[7] = remap[((*src4 & 0x01) << 3) | ((*src3 & 0x01) << 2) | ((*src2 & 0x01) << 1) | ((*src1 & 0x01))]; + dest += 8; + src1 += 1; + src2 += 1; + src3 += 1; + src4 += 1; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +PalettedPixels FStartupTexture::CreatePalettedPixels(int conversion, int frame) +{ + auto lump = fileSystem.ReadFile (SourceLump); + auto source = lump.bytes(); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); + + + TArray Work(Width*Height, true); + PalettedPixels Pixels(Width*Height); + PlanarToChunky(Work.Data(), source + 48, startuppalette8, Width, Height); + ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), Work.Data(), Width, Height, Width, remap); + return Pixels; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FStartupTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) +{ + auto lump = fileSystem.ReadFile (SourceLump); + auto source = lump.bytes(); + PlanarToChunky((uint32_t*)bmp->GetPixels(), source + 48, startuppalette32, Width, Height); + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +FNotchTexture::FNotchTexture (int lumpnum, int width, int height) +: FImageSource(lumpnum) +{ + Width = width; + Height = height; + bUseGamePalette = false; +} + +//========================================================================== +// +// +// +//========================================================================== + +PalettedPixels FNotchTexture::CreatePalettedPixels(int conversion, int frame) +{ + auto lump = fileSystem.ReadFile (SourceLump); + auto source = lump.bytes(); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); + + TArray Work(Width*Height, true); + PalettedPixels Pixels(Width*Height); + for(int i=0; i * Width * Height / 2; i++) + { + Work[i * 2] = startuppalette8[source[i] >> 4]; + Work[i * 2 + 1] = startuppalette8[source[i] & 15]; + } + ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), Work.Data(), Width, Height, Width, remap); + return Pixels; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FNotchTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) +{ + auto lump = fileSystem.ReadFile (SourceLump); + auto source = lump.bytes(); + + auto Work = (uint32_t*)bmp->GetPixels(); + for(int i = 0; i < Width * Height / 2; i++) + { + Work[i * 2] = startuppalette32[source[i] >> 4]; + Work[i * 2 + 1] = startuppalette32[source[i] & 15]; + } + return 0; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FStrifeStartupTexture::FStrifeStartupTexture (int lumpnum, int w, int h) +: FImageSource(lumpnum) +{ + Width = w; + Height = h; +} + +//========================================================================== +// +// +// +//========================================================================== + +PalettedPixels FStrifeStartupTexture::CreatePalettedPixels(int conversion, int frame) +{ + auto lump = fileSystem.ReadFile (SourceLump); + auto source = lump.bytes(); + PalettedPixels Pixels(Width*Height); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); + ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), source, Width, Height, Width, remap); + return Pixels; +} + +//========================================================================== +// +// +// +//========================================================================== + +FStrifeStartupBackground::FStrifeStartupBackground (int lumpnum) +: FImageSource(lumpnum) +{ + Width = 320; + Height = 200; +} + +//========================================================================== +// +// this image is very messy but let's prepare it just like Strife does +// so that the screen can be replaced with a whole image. +// +//========================================================================== + +PalettedPixels FStrifeStartupBackground::CreatePalettedPixels(int conversion, int frame) +{ + TArray source(64000, true); + memset(source.Data(), 0xF0, 64000); + auto lumpr = fileSystem.OpenFileReader(SourceLump); + lumpr.Seek(57 * 320, FileReader::SeekSet); + lumpr.Read(source.Data() + 41 * 320, 95 * 320); + + PalettedPixels Pixels(Width*Height); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); + ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), source.Data(), Width, Height, Width, remap); + return Pixels; +} diff --git a/src/gamedata/textures/formats/stbtexture.cpp b/src/common/textures/formats/stbtexture.cpp similarity index 89% rename from src/gamedata/textures/formats/stbtexture.cpp rename to src/common/textures/formats/stbtexture.cpp index e8ffbd93443..827013a5832 100644 --- a/src/gamedata/textures/formats/stbtexture.cpp +++ b/src/common/textures/formats/stbtexture.cpp @@ -36,19 +36,16 @@ #define STB_IMAGE_IMPLEMENTATION #define STBI_NO_STDIO // Undefine formats we do not want to support here. -#define STBI_NO_JPEG -#define STBI_NO_PNG -#define STBI_NO_TGA +//#define STBI_NO_PNG we need PNG for 16 bit channel images. Regular ones still use our own, more flexible decoder. +#define STBI_NO_TGA // we could use that but our own loader has better palette support. #define STBI_NO_PSD #define STBI_NO_HDR #define STBI_NO_PNM #include "stb_image.h" - -#include "doomtype.h" + #include "files.h" -#include "w_wad.h" -#include "v_video.h" +#include "filesystem.h" #include "bitmap.h" #include "imagehelpers.h" #include "image.h" @@ -69,8 +66,8 @@ class FStbTexture : public FImageSource public: FStbTexture (int lumpnum, int w, int h); - TArray CreatePalettedPixels(int conversion) override; - int CopyPixels(FBitmap *bmp, int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; }; @@ -94,7 +91,7 @@ FImageSource *StbImage_TryCreate(FileReader & file, int lumpnum) { return new FStbTexture(lumpnum, x, y); } - + return nullptr; } @@ -119,7 +116,7 @@ FStbTexture::FStbTexture (int lumpnum, int w, int h) // //========================================================================== -TArray FStbTexture::CreatePalettedPixels(int conversion) +PalettedPixels FStbTexture::CreatePalettedPixels(int conversion, int frame) { FBitmap bitmap; bitmap.Create(Width, Height); @@ -130,7 +127,7 @@ TArray FStbTexture::CreatePalettedPixels(int conversion) int dest_adv = Height; int dest_rew = Width * Height - 1; - TArray Pixels(Width*Height, true); + PalettedPixels Pixels(Width*Height); dest_p = Pixels.Data(); bool doalpha = conversion == luminance; @@ -158,9 +155,9 @@ TArray FStbTexture::CreatePalettedPixels(int conversion) // //========================================================================== -int FStbTexture::CopyPixels(FBitmap *bmp, int conversion) +int FStbTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { - auto lump = Wads.OpenLumpReader (SourceLump); + auto lump = fileSystem.OpenFileReader (SourceLump); int x, y, chan; auto image = stbi_load_from_callbacks(&callbacks, &lump, &x, &y, &chan, STBI_rgb_alpha); if (image) diff --git a/src/gamedata/textures/formats/tgatexture.cpp b/src/common/textures/formats/tgatexture.cpp similarity index 93% rename from src/gamedata/textures/formats/tgatexture.cpp rename to src/common/textures/formats/tgatexture.cpp index 927bf9b50dc..7577f79ff40 100644 --- a/src/gamedata/textures/formats/tgatexture.cpp +++ b/src/common/textures/formats/tgatexture.cpp @@ -3,7 +3,7 @@ ** Texture class for TGA images ** **--------------------------------------------------------------------------- -** Copyright 2006 Christoph Oelckers +** Copyright 2006-2019 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -33,14 +33,13 @@ ** */ -#include "doomtype.h" #include "files.h" -#include "w_wad.h" -#include "templates.h" +#include "filesystem.h" + #include "bitmap.h" -#include "v_video.h" #include "imagehelpers.h" #include "image.h" +#include "m_swap.h" //========================================================================== @@ -59,7 +58,7 @@ struct TGAHeader int16_t cm_first; int16_t cm_length; uint8_t cm_size; - + int16_t x_origin; int16_t y_origin; int16_t width; @@ -81,11 +80,11 @@ class FTGATexture : public FImageSource public: FTGATexture (int lumpnum, TGAHeader *); - int CopyPixels(FBitmap *bmp, int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; protected: void ReadCompressed(FileReader &lump, uint8_t * buffer, int bytesperpixel); - TArray CreatePalettedPixels(int conversion) override; + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; }; //========================================================================== @@ -98,13 +97,13 @@ FImageSource *TGAImage_TryCreate(FileReader & file, int lumpnum) { TGAHeader hdr; - if (file.GetLength() < (long)sizeof(hdr)) return NULL; - + if (file.GetLength() < (ptrdiff_t)sizeof(hdr)) return NULL; + file.Seek(0, FileReader::SeekSet); file.Read(&hdr, sizeof(hdr)); hdr.width = LittleShort(hdr.width); hdr.height = LittleShort(hdr.height); - + // Not much that can be done here because TGA does not have a proper // header to be identified with. if (hdr.has_cm != 0 && hdr.has_cm != 1) return NULL; @@ -147,7 +146,7 @@ void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytespe { uint8_t data[4]; int Size = Width * Height; - + while (Size > 0) { uint8_t b = lump.ReadUInt8(); @@ -155,7 +154,7 @@ void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytespe { b&=~128; lump.Read(data, bytesperpixel); - for (int i=MIN(Size, (b+1)); i>0; i--) + for (int i=min(Size, (b+1)); i>0; i--) { buffer[0] = data[0]; if (bytesperpixel>=2) buffer[1] = data[1]; @@ -166,7 +165,7 @@ void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytespe } else { - lump.Read(buffer, MIN(Size, (b+1))*bytesperpixel); + lump.Read(buffer, min(Size, (b+1))*bytesperpixel); buffer += (b+1)*bytesperpixel; } Size -= b+1; @@ -179,18 +178,18 @@ void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytespe // //========================================================================== -TArray FTGATexture::CreatePalettedPixels(int conversion) +PalettedPixels FTGATexture::CreatePalettedPixels(int conversion, int frame) { uint8_t PaletteMap[256]; - auto lump = Wads.OpenLumpReader (SourceLump); + auto lump = fileSystem.OpenFileReader (SourceLump); TGAHeader hdr; uint16_t w; uint8_t r,g,b,a; - TArray Pixels(Width*Height, true); + PalettedPixels Pixels(Width*Height); lump.Read(&hdr, sizeof(hdr)); lump.Seek(hdr.id_len, FileReader::SeekCur); - + hdr.width = LittleShort(hdr.width); hdr.height = LittleShort(hdr.height); hdr.cm_first = LittleShort(hdr.cm_first); @@ -211,14 +210,14 @@ TArray FTGATexture::CreatePalettedPixels(int conversion) b = (w & 0x7C00) >> 7; a = 255; break; - + case 24: b = lump.ReadUInt8(); g = lump.ReadUInt8(); r = lump.ReadUInt8(); a=255; break; - + case 32: b = lump.ReadUInt8(); g = lump.ReadUInt8(); @@ -226,7 +225,7 @@ TArray FTGATexture::CreatePalettedPixels(int conversion) a = lump.ReadUInt8(); if ((hdr.img_desc&15)!=8) a=255; break; - + default: // should never happen r=g=b=a=0; break; @@ -234,10 +233,10 @@ TArray FTGATexture::CreatePalettedPixels(int conversion) PaletteMap[i] = ImageHelpers::RGBToPalettePrecise(conversion == luminance, r, g, b, a); } } - + int Size = Width * Height * (hdr.bpp>>3); TArray buffer(Size, true); - + if (hdr.img_type < 4) // uncompressed { lump.Read(buffer.Data(), Size); @@ -246,7 +245,7 @@ TArray FTGATexture::CreatePalettedPixels(int conversion) { ReadCompressed(lump, buffer.Data(), hdr.bpp>>3); } - + uint8_t * ptr = buffer.Data(); int step_x = (hdr.bpp>>3); int Pitch = Width * step_x; @@ -295,7 +294,7 @@ TArray FTGATexture::CreatePalettedPixels(int conversion) } } break; - + case 24: for(int y=0;y FTGATexture::CreatePalettedPixels(int conversion) } } break; - + case 32: if ((hdr.img_desc&15)!=8) // 32 bits without a valid alpha channel { @@ -334,12 +333,12 @@ TArray FTGATexture::CreatePalettedPixels(int conversion) } } break; - + default: break; } break; - + case 3: // Grayscale { auto remap = ImageHelpers::GetRemap(conversion == luminance, true); @@ -386,10 +385,10 @@ TArray FTGATexture::CreatePalettedPixels(int conversion) // //=========================================================================== -int FTGATexture::CopyPixels(FBitmap *bmp, int conversion) +int FTGATexture::CopyPixels(FBitmap *bmp, int conversion, int frame) { PalEntry pe[256]; - auto lump = Wads.OpenLumpReader (SourceLump); + auto lump = fileSystem.OpenFileReader (SourceLump); TGAHeader hdr; uint16_t w; uint8_t r,g,b,a; @@ -397,7 +396,7 @@ int FTGATexture::CopyPixels(FBitmap *bmp, int conversion) lump.Read(&hdr, sizeof(hdr)); lump.Seek(hdr.id_len, FileReader::SeekCur); - + hdr.width = LittleShort(hdr.width); hdr.height = LittleShort(hdr.height); hdr.cm_first = LittleShort(hdr.cm_first); @@ -442,10 +441,10 @@ int FTGATexture::CopyPixels(FBitmap *bmp, int conversion) pe[i] = PalEntry(a, r, g, b); } } - + int Size = Width * Height * (hdr.bpp>>3); TArray sbuffer(Size); - + if (hdr.img_type < 4) // uncompressed { lump.Read(sbuffer.Data(), Size); @@ -454,7 +453,7 @@ int FTGATexture::CopyPixels(FBitmap *bmp, int conversion) { ReadCompressed(lump, sbuffer.Data(), hdr.bpp>>3); } - + uint8_t * ptr = sbuffer.Data(); int step_x = (hdr.bpp>>3); int Pitch = Width * step_x; @@ -485,11 +484,11 @@ int FTGATexture::CopyPixels(FBitmap *bmp, int conversion) case 16: bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_RGB555); break; - + case 24: bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_BGR); break; - + case 32: if ((hdr.img_desc&15)!=8) // 32 bits without a valid alpha channel { @@ -501,12 +500,12 @@ int FTGATexture::CopyPixels(FBitmap *bmp, int conversion) transval = -1; } break; - + default: break; } break; - + case 3: // Grayscale switch (hdr.bpp) { @@ -514,11 +513,11 @@ int FTGATexture::CopyPixels(FBitmap *bmp, int conversion) for(int i=0;i<256;i++) pe[i]=PalEntry(255,i,i,i); // gray map bmp->CopyPixelData(0, 0, ptr, Width, Height, step_x, Pitch, 0, pe); break; - + case 16: bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_I16); break; - + default: break; } diff --git a/src/common/textures/formats/webptexture.cpp b/src/common/textures/formats/webptexture.cpp new file mode 100644 index 00000000000..2df75964514 --- /dev/null +++ b/src/common/textures/formats/webptexture.cpp @@ -0,0 +1,148 @@ +/* +** webptexture.cpp +** Texture class for WebP images. +** +**--------------------------------------------------------------------------- +** Copyright 2023 Cacodemon345 +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ +#include "webp/decode.h" +#include "webp/mux.h" + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" +#include "printf.h" + +class FWebPTexture : public FImageSource +{ + +public: + FWebPTexture(int lumpnum, int w, int h, int xoff, int yoff); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override; +}; + + +FImageSource *WebPImage_TryCreate(FileReader &file, int lumpnum) +{ + int width = 0, height = 0; + int xoff = 0, yoff = 0; + file.Seek(0, FileReader::SeekSet); + + uint8_t header[12]; + if (file.Read(header, 12) != 12) return nullptr; + if (memcmp(header, "RIFF", 4) || memcmp(header + 8, "WEBP", 4)) return nullptr; + + file.Seek(0, FileReader::SeekSet); + auto bytes = file.Read(); + + if (WebPGetInfo(bytes.bytes(), bytes.size(), &width, &height)) + { + WebPData data{ bytes.bytes(), bytes.size() }; + WebPData chunk_data; + auto mux = WebPMuxCreate(&data, 0); + if (mux) + { + const char fourcc[4] = { 'g', 'r', 'A', 'b' }; + if (WebPMuxGetChunk(mux, fourcc, &chunk_data) == WEBP_MUX_OK && chunk_data.size >= 4) + { + xoff = chunk_data.bytes[0] | (chunk_data.bytes[1] << 8); + yoff = chunk_data.bytes[2] | (chunk_data.bytes[3] << 8); + } + WebPMuxDelete(mux); + } + return new FWebPTexture(lumpnum, width, height, xoff, yoff); + } + return nullptr; +} + +FWebPTexture::FWebPTexture(int lumpnum, int w, int h, int xoff, int yoff) + : FImageSource(lumpnum) +{ + Width = w; + Height = h; + LeftOffset = xoff; + TopOffset = yoff; +} + +PalettedPixels FWebPTexture::CreatePalettedPixels(int conversion, int frame) +{ + FBitmap bitmap; + bitmap.Create(Width, Height); + CopyPixels(&bitmap, conversion); + const uint8_t *data = bitmap.GetPixels(); + + uint8_t *dest_p; + int dest_adv = Height; + int dest_rew = Width * Height - 1; + + PalettedPixels Pixels(Width*Height); + dest_p = Pixels.Data(); + + bool doalpha = conversion == luminance; + // Convert the source image from row-major to column-major format and remap it + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + int b = *data++; + int g = *data++; + int r = *data++; + int a = *data++; + if (a < 128) *dest_p = 0; + else *dest_p = ImageHelpers::RGBToPalette(doalpha, r, g, b); + dest_p += dest_adv; + } + dest_p -= dest_rew; + } + return Pixels; +} + +int FWebPTexture::CopyPixels(FBitmap *bmp, int conversion, int frame) +{ + WebPDecoderConfig config; + auto bytes = fileSystem.ReadFile(SourceLump); + + if (WebPInitDecoderConfig(&config) == false) + return 0; + + config.options.no_fancy_upsampling = 0; + config.output.colorspace = MODE_BGRA; + config.output.u.RGBA.rgba = (uint8_t*)bmp->GetPixels(); + config.output.u.RGBA.size = bmp->GetBufferSize(); + config.output.u.RGBA.stride = bmp->GetPitch(); + config.output.is_external_memory = 1; + + (void)WebPDecode(bytes.bytes(), bytes.size(), &config); + + return 0; +} diff --git a/src/common/textures/gametexture.cpp b/src/common/textures/gametexture.cpp new file mode 100644 index 00000000000..755f48b49e3 --- /dev/null +++ b/src/common/textures/gametexture.cpp @@ -0,0 +1,547 @@ +/* +** gametexture.cpp +** The game-facing texture class. +** +**--------------------------------------------------------------------------- +** Copyright 2004-2007 Randy Heit +** Copyright 2006-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "printf.h" +#include "files.h" +#include "filesystem.h" + +#include "textures.h" +#include "bitmap.h" +#include "colormatcher.h" +#include "c_dispatch.h" +#include "m_fixed.h" +#include "imagehelpers.h" +#include "image.h" +#include "formats/multipatchtexture.h" +#include "texturemanager.h" +#include "c_cvars.h" +#include "hw_material.h" +#include "cmdlib.h" + +FTexture *CreateBrightmapTexture(FImageSource*); + + +FGameTexture::FGameTexture(FTexture* wrap, const char* name) : Name(name) +{ + if (wrap) Setup(wrap); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGameTexture::Setup(FTexture *wrap) +{ + Base = wrap; + id.SetInvalid(); + TexelWidth = Base->GetWidth(); + DisplayWidth = (float)TexelWidth; + TexelHeight = Base->GetHeight(); + DisplayHeight = (float)TexelHeight; + auto img = Base->GetImage(); + if (img) + { + auto ofs = img->GetOffsets(); + LeftOffset[0] = LeftOffset[1] = ofs.first; + TopOffset[0] = TopOffset[1] = ofs.second; + } + else + { + LeftOffset[0] = LeftOffset[1] = + TopOffset[0] = TopOffset[1] = 0; + + } + ScaleX = ScaleY = 1.f; +} + +//========================================================================== +// +// +// +//========================================================================== + +FGameTexture::~FGameTexture() +{ + if (Base != nullptr) + { + FGameTexture* link = TexMan.GetLinkedTexture(GetSourceLump()); + if (link == this) TexMan.SetLinkedTexture(GetSourceLump(), nullptr); + } + if (SoftwareTexture != nullptr) + { + delete SoftwareTexture; + SoftwareTexture = nullptr; + } + for (auto &mat : Material) + { + if (mat != nullptr) delete mat; + mat = nullptr; + } + +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FGameTexture::isUserContent() const +{ + int filenum = fileSystem.GetFileContainer(Base->GetSourceLump()); + return (filenum > fileSystem.GetMaxIwadNum()); +} + + +//========================================================================== +// +// Search auto paths for extra material textures +// +//========================================================================== + +void FGameTexture::AddAutoMaterials() +{ + struct AutoTextureSearchPath + { + const char* path; + RefCountedPtr FGameTexture::* pointer; + }; + struct AutoTextureSearchPath2 + { + const char* path; + RefCountedPtr FMaterialLayers::* pointer; + }; + + static AutoTextureSearchPath autosearchpaths[] = + { + { "brightmaps/", &FGameTexture::Brightmap }, // For backwards compatibility, only for short names + { "materials/brightmaps/", &FGameTexture::Brightmap }, + }; + + static AutoTextureSearchPath2 autosearchpaths2[] = + { + { "materials/detailmaps/", &FMaterialLayers::Detailmap }, + { "materials/glowmaps/", &FMaterialLayers::Glowmap }, + { "materials/normalmaps/", &FMaterialLayers::Normal }, + { "materials/specular/", &FMaterialLayers::Specular }, + { "materials/metallic/", &FMaterialLayers::Metallic }, + { "materials/roughness/", &FMaterialLayers::Roughness }, + { "materials/ao/", &FMaterialLayers::AmbientOcclusion } + }; + + if (flags & GTexf_AutoMaterialsAdded) return; // do this only once + + bool fullname = !!(flags & GTexf_FullNameTexture); + FString searchname = GetName(); + + if (fullname) + { + auto dot = searchname.LastIndexOf('.'); + auto slash = searchname.LastIndexOf('/'); + if (dot > slash) searchname.Truncate(dot); + } + + for (size_t i = 0; i < countof(autosearchpaths); i++) + { + auto& layer = autosearchpaths[i]; + if (this->*(layer.pointer) == nullptr) // only if no explicit assignment had been done. + { + FStringf lookup("%s%s%s", layer.path, fullname ? "" : "auto/", searchname.GetChars()); + auto lump = fileSystem.CheckNumForFullName(lookup.GetChars(), false, FileSys::ns_global, true); + if (lump != -1) + { + auto bmtex = TexMan.FindGameTexture(fileSystem.GetFileFullName(lump), ETextureType::Any, FTextureManager::TEXMAN_TryAny); + if (bmtex != nullptr) + { + this->*(layer.pointer) = bmtex->GetTexture(); + } + } + } + } + for (size_t i = 0; i < countof(autosearchpaths2); i++) + { + auto& layer = autosearchpaths2[i]; + if (!this->Layers || this->Layers.get()->*(layer.pointer) == nullptr) // only if no explicit assignment had been done. + { + FStringf lookup("%s%s%s", layer.path, fullname ? "" : "auto/", searchname.GetChars()); + auto lump = fileSystem.CheckNumForFullName(lookup.GetChars(), false, FileSys::ns_global, true); + if (lump != -1) + { + auto bmtex = TexMan.FindGameTexture(fileSystem.GetFileFullName(lump), ETextureType::Any, FTextureManager::TEXMAN_TryAny); + if (bmtex != nullptr) + { + if (this->Layers == nullptr) this->Layers = std::make_unique(); + this->Layers.get()->* (layer.pointer) = bmtex->GetTexture(); + } + } + } + } + flags |= GTexf_AutoMaterialsAdded; +} + +//=========================================================================== +// +// Checks if the texture has a default brightmap and creates it if so +// +//=========================================================================== +void FGameTexture::CreateDefaultBrightmap() +{ + auto tex = GetTexture(); + if (!(flags & GTexf_BrightmapChecked)) + { + flags |= GTexf_BrightmapChecked; + // Check for brightmaps + if (tex->GetImage() && tex->GetImage()->UseGamePalette() && GPalette.HasGlobalBrightmap && + GetUseType() != ETextureType::Decal && GetUseType() != ETextureType::MiscPatch && GetUseType() != ETextureType::FontChar && + Brightmap == nullptr) + { + // May have one - let's check when we use this texture + auto texbuf = tex->Get8BitPixels(false); + const int white = ColorMatcher.Pick(255, 255, 255); + + int size = tex->GetWidth() * tex->GetHeight(); + for (int i = 0; i < size; i++) + { + if (GPalette.GlobalBrightmap.Remap[texbuf[i]] == white) + { + // Create a brightmap + DPrintf(DMSG_NOTIFY, "brightmap created for texture '%s'\n", GetName().GetChars()); + Brightmap = CreateBrightmapTexture(tex->GetImage()); + return; + } + } + // No bright pixels found + DPrintf(DMSG_SPAMMY, "No bright pixels found in texture '%s'\n", GetName().GetChars()); + } + } +} + + +//========================================================================== +// +// Calculates glow color for a texture +// +//========================================================================== + +void FGameTexture::GetGlowColor(float* data) +{ + if (isGlowing() && GlowColor == 0) + { + auto buffer = Base->GetBgraBitmap(nullptr); + GlowColor = averageColor((uint32_t*)buffer.GetPixels(), buffer.GetWidth() * buffer.GetHeight(), 153); + + // Black glow equals nothing so switch glowing off + if (GlowColor == 0) flags &= ~GTexf_Glowing; + } + data[0] = GlowColor.r * (1 / 255.0f); + data[1] = GlowColor.g * (1 / 255.0f); + data[2] = GlowColor.b * (1 / 255.0f); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +int FGameTexture::GetAreas(FloatRect** pAreas) const +{ + if (shaderindex == SHADER_Default) // texture splitting can only be done if there's no attached effects + { + *pAreas = Base->areas; + return Base->areacount; + } + else + { + return 0; + } +} + +//=========================================================================== +// +// Checks if a sprite may be expanded with an empty frame +// +//=========================================================================== + +bool FGameTexture::ShouldExpandSprite() +{ + if (expandSprite != -1) return expandSprite; + // Only applicable to image textures with no shader effect. + if (GetShaderIndex() != SHADER_Default || !dynamic_cast(Base.get())) + { + expandSprite = false; + return false; + } + if (Brightmap != NULL && (Base->GetWidth() != Brightmap->GetWidth() || Base->GetHeight() != Brightmap->GetHeight())) + { + // do not expand if the brightmap's physical size differs from the base. + expandSprite = false; + return false; + } + if (Layers && Layers->Glowmap != NULL && (Base->GetWidth() != Layers->Glowmap->GetWidth() || Base->GetHeight() != Layers->Glowmap->GetHeight())) + { + // same restriction for the glow map + expandSprite = false; + return false; + } + expandSprite = true; + return true; +} + +//=========================================================================== +// +// Sets up the sprite positioning data for this texture +// +//=========================================================================== + +void FGameTexture::SetupSpriteData() +{ + // Since this is only needed for real sprites it gets allocated on demand. + // It also allocates from the image memory arena because it has the same lifetime and to reduce maintenance. + if (spi == nullptr) spi = (SpritePositioningInfo*)ImageArena.Alloc(2 * sizeof(SpritePositioningInfo)); + for (int i = 0; i < 2; i++) + { + auto& spi = this->spi[i]; + spi.mSpriteU[0] = spi.mSpriteV[0] = 0.f; + spi.mSpriteU[1] = spi.mSpriteV[1] = 1.f; + spi.spriteWidth = GetTexelWidth(); + spi.spriteHeight = GetTexelHeight(); + + if (i == 1 && ShouldExpandSprite()) + { + spi.mTrimResult = Base->TrimBorders(spi.trim) && !GetNoTrimming(); // get the trim size before adding the empty frame + spi.spriteWidth += 2; + spi.spriteHeight += 2; + } + } + SetSpriteRect(); +} + +//=========================================================================== +// +// Set the sprite rectangle. This is separate because it may be called by a CVAR, too. +// +//=========================================================================== + +void FGameTexture::SetSpriteRect() +{ + + if (!spi) return; + auto leftOffset = GetTexelLeftOffset(r_spriteadjustHW); + auto topOffset = GetTexelTopOffset(r_spriteadjustHW); + + float fxScale = GetScaleX(); + float fyScale = GetScaleY(); + + for (int i = 0; i < 2; i++) + { + auto& spi = this->spi[i]; + + // mSpriteRect is for positioning the sprite in the scene. + spi.mSpriteRect.left = -leftOffset / fxScale; + spi.mSpriteRect.top = -topOffset / fyScale; + spi.mSpriteRect.width = spi.spriteWidth / fxScale; + spi.mSpriteRect.height = spi.spriteHeight / fyScale; + + if (i == 1 && ShouldExpandSprite()) + { + // a little adjustment to make sprites look better with texture filtering: + // create a 1 pixel wide empty frame around them. + + int oldwidth = spi.spriteWidth - 2; + int oldheight = spi.spriteHeight - 2; + + leftOffset += 1; + topOffset += 1; + + // Reposition the sprite with the frame considered + spi.mSpriteRect.left = -(float)leftOffset / fxScale; + spi.mSpriteRect.top = -(float)topOffset / fyScale; + spi.mSpriteRect.width = (float)spi.spriteWidth / fxScale; + spi.mSpriteRect.height = (float)spi.spriteHeight / fyScale; + + if (spi.mTrimResult > 0) + { + spi.mSpriteRect.left += (float)spi.trim[0] / fxScale; + spi.mSpriteRect.top += (float)spi.trim[1] / fyScale; + + spi.mSpriteRect.width -= float(oldwidth - spi.trim[2]) / fxScale; + spi.mSpriteRect.height -= float(oldheight - spi.trim[3]) / fyScale; + + spi.mSpriteU[0] = (float)spi.trim[0] / (float)spi.spriteWidth; + spi.mSpriteV[0] = (float)spi.trim[1] / (float)spi.spriteHeight; + spi.mSpriteU[1] -= float(oldwidth - spi.trim[0] - spi.trim[2]) / (float)spi.spriteWidth; + spi.mSpriteV[1] -= float(oldheight - spi.trim[1] - spi.trim[3]) / (float)spi.spriteHeight; + } + } + } +} + +//=========================================================================== +// +// Cleans the attached hardware resources. +// This should only be used on textures which alter their content at run time +//or when the engine shuts down. +// +//=========================================================================== + +void FGameTexture::CleanHardwareData(bool full) +{ + if (full) Base->CleanHardwareTextures(); + for (auto mat : Material) if (mat) mat->DeleteDescriptors(); +} + + +//----------------------------------------------------------------------------- +// +// Make sprite offset adjustment user-configurable per renderer. +// +//----------------------------------------------------------------------------- + +CUSTOM_CVAR(Int, r_spriteadjust, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + r_spriteadjustHW = !!(self & 2); + r_spriteadjustSW = !!(self & 1); + for (int i = 0; i < TexMan.NumTextures(); i++) + { + auto tex = TexMan.GetGameTexture(FSetTextureID(i)); + if (tex->GetTexelLeftOffset(0) != tex->GetTexelLeftOffset(1) || tex->GetTexelTopOffset(0) != tex->GetTexelTopOffset(1)) + { + tex->SetSpriteRect(); + } + } +} + +//=========================================================================== +// +// Coordinate helper. +// The only reason this is even needed is that many years ago someone +// was convinced that having per-texel panning on walls was a good idea. +// If it wasn't for this relatively useless feature the entire positioning +// code for wall textures could be a lot simpler. +// +//=========================================================================== + +//=========================================================================== +// +// +// +//=========================================================================== + +float FTexCoordInfo::RowOffset(float rowoffset) const +{ + float scale = fabsf(mScale.Y); + if (scale == 1.f || mWorldPanning) return rowoffset; + else return rowoffset / scale; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +float FTexCoordInfo::TextureOffset(float textureoffset) const +{ + float scale = fabsf(mScale.X); + if (scale == 1.f || mWorldPanning) return textureoffset; + else return textureoffset / scale; +} + +//=========================================================================== +// +// Returns the size for which texture offset coordinates are used. +// +//=========================================================================== + +float FTexCoordInfo::TextureAdjustWidth() const +{ + if (mWorldPanning) + { + float tscale = fabsf(mTempScale.X); + if (tscale == 1.f) return (float)mRenderWidth; + else return mWidth / fabsf(tscale); + } + else return (float)mWidth; +} + + +//=========================================================================== +// +// Retrieve texture coordinate info for per-wall scaling +// +//=========================================================================== + +void FTexCoordInfo::GetFromTexture(FGameTexture *tex, float x, float y, bool forceworldpanning) +{ + if (x == 1.f) + { + mRenderWidth = xs_RoundToInt(tex->GetDisplayWidth()); + mScale.X = tex->GetScaleX(); + mTempScale.X = 1.f; + } + else + { + float scale_x = x * tex->GetScaleX(); + mRenderWidth = xs_CeilToInt(tex->GetTexelWidth() / scale_x); + mScale.X = scale_x; + mTempScale.X = x; + } + + if (y == 1.f) + { + mRenderHeight = xs_RoundToInt(tex->GetDisplayHeight()); + mScale.Y = tex->GetScaleY(); + mTempScale.Y = 1.f; + } + else + { + float scale_y = y * tex->GetScaleY(); + mRenderHeight = xs_CeilToInt(tex->GetTexelHeight() / scale_y); + mScale.Y = scale_y; + mTempScale.Y = y; + } + if (tex->isHardwareCanvas()) + { + mScale.Y = -mScale.Y; + mRenderHeight = -mRenderHeight; + } + mWorldPanning = tex->useWorldPanning() || forceworldpanning; + mWidth = tex->GetTexelWidth(); +} + diff --git a/src/common/textures/gametexture.h b/src/common/textures/gametexture.h new file mode 100644 index 00000000000..3eb3740a952 --- /dev/null +++ b/src/common/textures/gametexture.h @@ -0,0 +1,470 @@ +#pragma once +#include +#include +#include "vectors.h" +#include "floatrect.h" +#include "refcounted.h" +#include "xs_Float.h" +#include "palentry.h" +#include "zstring.h" +#include "textureid.h" + +// 15 because 0th texture is our texture +#define MAX_CUSTOM_HW_SHADER_TEXTURES 15 +class FTexture; +class ISoftwareTexture; +class FMaterial; + +struct SpritePositioningInfo +{ + uint16_t trim[4]; + int spriteWidth, spriteHeight; + float mSpriteU[2], mSpriteV[2]; + FloatRect mSpriteRect; + uint8_t mTrimResult; + + float GetSpriteUL() const { return mSpriteU[0]; } + float GetSpriteVT() const { return mSpriteV[0]; } + float GetSpriteUR() const { return mSpriteU[1]; } + float GetSpriteVB() const { return mSpriteV[1]; } + + const FloatRect &GetSpriteRect() const + { + return mSpriteRect; + } + +}; + +struct MaterialLayers +{ + float Glossiness; + float SpecularLevel; + FGameTexture* Brightmap; + FGameTexture* Normal; + FGameTexture* Specular; + FGameTexture* Metallic; + FGameTexture* Roughness; + FGameTexture* AmbientOcclusion; + FGameTexture* CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; +}; + +enum EGameTexFlags +{ + GTexf_NoDecals = 1, // Decals should not stick to texture + GTexf_WorldPanning = 2, // Texture is panned in world units rather than texels + GTexf_FullNameTexture = 4, // Name is taken from the file system. + GTexf_Glowing = 8, // Texture emits a glow + GTexf_AutoGlowing = 16, // Glow info is determined from texture image. + GTexf_RenderFullbright = 32, // always draw fullbright + GTexf_DisableFullbrightSprites = 64, // This texture will not be displayed as fullbright sprite + GTexf_BrightmapChecked = 128, // Check for a colormap-based brightmap was already done. + GTexf_AutoMaterialsAdded = 256, // AddAutoMaterials has been called on this texture. + GTexf_OffsetsNotForFont = 512, // The offsets must be ignored when using this texture in a font. + GTexf_NoTrim = 1024, // Don't perform trimming on this texture. + GTexf_Seen = 2048, // Set to true when the texture is being used for rendering. Must be cleared manually if the check is needed. +}; + +struct FMaterialLayers +{ + RefCountedPtr Detailmap; + RefCountedPtr Glowmap; + RefCountedPtr Normal; // Normal map texture + RefCountedPtr Specular; // Specular light texture for the diffuse+normal+specular light model + RefCountedPtr Metallic; // Metalness texture for the physically based rendering (PBR) light model + RefCountedPtr Roughness; // Roughness texture for PBR + RefCountedPtr AmbientOcclusion; // Ambient occlusion texture for PBR + RefCountedPtr CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; // Custom texture maps for custom hardware shaders +}; + +// Refactoring helper to allow piece by piece adjustment of the API +class FGameTexture +{ + friend class FMaterial; + friend class GLDefsParser; // this needs access to set up the texture properly + + // Material layers. These are shared so reference counting is used. + RefCountedPtr Base; + RefCountedPtr Brightmap; + std::unique_ptr Layers; + + FString Name; + FTextureID id; + + uint16_t TexelWidth, TexelHeight; + int16_t LeftOffset[2], TopOffset[2]; + float DisplayWidth, DisplayHeight; + float ScaleX, ScaleY; + + int8_t shouldUpscaleFlag = 1; + ETextureType UseType = ETextureType::Wall; // This texture's primary purpose + SpritePositioningInfo* spi = nullptr; + + ISoftwareTexture* SoftwareTexture = nullptr; + FMaterial* Material[5] = { }; + + // Material properties + FVector2 detailScale = { 1.f, 1.f }; + float Glossiness = 10.f; + float SpecularLevel = 0.1f; + float shaderspeed = 1.f; + int shaderindex = 0; + + int flags = 0; + uint8_t warped = 0; + int8_t expandSprite = -1; + uint16_t GlowHeight = 128; + PalEntry GlowColor = 0; + + int16_t SkyOffset = 0; + uint16_t Rotations = 0xffff; + + +public: + float alphaThreshold = 0.5f; + + FGameTexture(FTexture* wrap, const char *name); + ~FGameTexture(); + void Setup(FTexture* wrap); + FTextureID GetID() const { return id; } + void SetID(FTextureID newid) { id = newid; } // should only be called by the texture manager + const FString& GetName() const { return Name; } + void SetName(const char* name) { Name = name; } // should only be called by setup code. + + float GetScaleX() { return ScaleX; } + float GetScaleY() { return ScaleY; } + float GetDisplayWidth() const { return DisplayWidth; } + float GetDisplayHeight() const { return DisplayHeight; } + int GetTexelWidth() const { return TexelWidth; } + int GetTexelHeight() const { return TexelHeight; } + + void CreateDefaultBrightmap(); + void AddAutoMaterials(); + bool ShouldExpandSprite(); + void SetupSpriteData(); + void SetSpriteRect(); + + ETextureType GetUseType() const { return UseType; } + void SetUpscaleFlag(int what, bool manual = false) + { + if ((shouldUpscaleFlag & 2) && !manual) return; // if set manually this may not be reset. + shouldUpscaleFlag = what | (manual? 2 : 0); + } + int GetUpscaleFlag() { return shouldUpscaleFlag & 1; } + + FTexture* GetTexture() { return Base.get(); } + int GetSourceLump() const { return Base->GetSourceLump(); } + void SetBrightmap(FGameTexture* tex) { Brightmap = tex->GetTexture(); } + + int GetTexelLeftOffset(int adjusted = 0) const { return LeftOffset[adjusted]; } + int GetTexelTopOffset(int adjusted = 0) const { return TopOffset[adjusted]; } + float GetDisplayLeftOffset(int adjusted = 0) const { return LeftOffset[adjusted] / ScaleX; } + float GetDisplayTopOffset(int adjusted = 0) const { return TopOffset[adjusted] / ScaleY; } + + bool isMiscPatch() const { return GetUseType() == ETextureType::MiscPatch; } // only used by the intermission screen to decide whether to tile the background image or not. + bool isFullbrightDisabled() const { return !!(flags & GTexf_DisableFullbrightSprites); } + bool isFullbright() const { return !!(flags & GTexf_RenderFullbright); } + bool isFullNameTexture() const { return !!(flags & GTexf_FullNameTexture); } + bool expandSprites() { return expandSprite == -1? ShouldExpandSprite() : !!expandSprite; } + bool useWorldPanning() const { return !!(flags & GTexf_WorldPanning); } + void SetWorldPanning(bool on) { if (on) flags |= GTexf_WorldPanning; else flags &= ~GTexf_WorldPanning; } + void SetNoTrimming(bool on) { if (on) flags |= GTexf_NoTrim; else flags &= ~GTexf_NoTrim; } + bool GetNoTrimming() { return !!(flags & GTexf_NoTrim); } + bool allowNoDecals() const { return !!(flags & GTexf_NoDecals); } + void SetNoDecals(bool on) { if (on) flags |= GTexf_NoDecals; else flags &= ~GTexf_NoDecals; } + void SetOffsetsNotForFont() { flags |= GTexf_OffsetsNotForFont; } + + bool isValid() const { return UseType != ETextureType::Null; } + int isWarped() { return warped; } + void SetWarpStyle(int style) { warped = style; } + bool isMasked() { return Base->Masked; } + bool isHardwareCanvas() const { return Base->isHardwareCanvas(); } // There's two here so that this can deal with software canvases in the hardware renderer later. + bool isSoftwareCanvas() const { return Base->isCanvas(); } + + void SetTranslucent(bool on) { Base->bTranslucent = on; } + void SetUseType(ETextureType type) { UseType = type; } + int GetRotations() const { return Rotations; } + void SetRotations(int rot) { Rotations = int16_t(rot); } + void SetSkyOffset(int offs) { SkyOffset = offs; } + int GetSkyOffset() const { return SkyOffset; } + void setSeen() { flags |= GTexf_Seen; } + bool isSeen(bool reset) + { + int v = flags & GTexf_Seen; + if (reset) flags &= ~GTexf_Seen; + return v; + } + + ISoftwareTexture* GetSoftwareTexture() + { + return SoftwareTexture; + } + void SetSoftwareTexture(ISoftwareTexture* swtex) + { + SoftwareTexture = swtex; + } + + FMaterial* GetMaterial(int num) + { + return Material[num]; + } + + int GetShaderIndex() const { return shaderindex; } + float GetShaderSpeed() const { return shaderspeed; } + void SetShaderSpeed(float speed) { shaderspeed = speed; } + void SetShaderIndex(int index) { shaderindex = index; } + void SetShaderLayers(MaterialLayers& lay) + { + // Only update layers that have something defind. + if (lay.Glossiness > -1000) Glossiness = lay.Glossiness; + if (lay.SpecularLevel > -1000) SpecularLevel = lay.SpecularLevel; + if (lay.Brightmap) Brightmap = lay.Brightmap->GetTexture(); + + bool needlayers = (lay.Normal || lay.Specular || lay.Metallic || lay.Roughness || lay.AmbientOcclusion); + for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES && !needlayers; i++) + { + if (lay.CustomShaderTextures[i]) needlayers = true; + } + if (needlayers) + { + Layers = std::make_unique(); + + if (lay.Normal) Layers->Normal = lay.Normal->GetTexture(); + if (lay.Specular) Layers->Specular = lay.Specular->GetTexture(); + if (lay.Metallic) Layers->Metallic = lay.Metallic->GetTexture(); + if (lay.Roughness) Layers->Roughness = lay.Roughness->GetTexture(); + if (lay.AmbientOcclusion) Layers->AmbientOcclusion = lay.AmbientOcclusion->GetTexture(); + for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++) + { + if (lay.CustomShaderTextures[i]) Layers->CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture(); + } + } + } + float GetGlossiness() const { return Glossiness; } + float GetSpecularLevel() const { return SpecularLevel; } + + void CopySize(FGameTexture* BaseTexture, bool forfont = false) + { + Base->CopySize(BaseTexture->Base.get()); + SetDisplaySize(BaseTexture->GetDisplayWidth(), BaseTexture->GetDisplayHeight()); + if (!forfont || !(BaseTexture->flags & GTexf_OffsetsNotForFont)) + { + SetOffsets(0, BaseTexture->GetTexelLeftOffset(0), BaseTexture->GetTexelTopOffset(0)); + SetOffsets(1, BaseTexture->GetTexelLeftOffset(1), BaseTexture->GetTexelTopOffset(1)); + } + } + + // Glowing is a pure material property that should not filter down to the actual texture objects. + void GetGlowColor(float* data); + bool isGlowing() const { return !!(flags & GTexf_Glowing); } + bool isAutoGlowing() const { return !!(flags & GTexf_AutoGlowing); } + int GetGlowHeight() const { return GlowHeight; } + void SetAutoGlowing() { flags |= (GTexf_AutoGlowing | GTexf_Glowing | GTexf_RenderFullbright); } + void SetGlowHeight(int v) { GlowHeight = v; } + void SetFullbright() { flags |= GTexf_RenderFullbright; } + void SetDisableFullbright(bool on) { if (on) flags |= GTexf_DisableFullbrightSprites; else flags &= ~GTexf_DisableFullbrightSprites; } + void SetGlowing(PalEntry color) { flags = (flags & ~GTexf_AutoGlowing) | GTexf_Glowing; GlowColor = color; } + void SetDisableBrightmap() { flags |= GTexf_BrightmapChecked; Brightmap = nullptr; } + + bool isUserContent() const; + int CheckRealHeight() { return xs_RoundToInt(Base->CheckRealHeight() / ScaleY); } + void SetSize(int x, int y) + { + TexelWidth = x; + TexelHeight = y; + SetDisplaySize(float(x), float(y)); + if (GetTexture()) GetTexture()->SetSize(x, y); + } + void SetDisplaySize(float w, float h) + { + DisplayWidth = w; + DisplayHeight = h; + ScaleX = TexelWidth / w; + ScaleY = TexelHeight / h; + + // compensate for roundoff errors + if (int(ScaleX * w) != TexelWidth) ScaleX += (1 / 65536.); + if (int(ScaleY * h) != TexelHeight) ScaleY += (1 / 65536.); + + } + void SetBase(FTexture* Tex) + { + Base = Tex; + } + void SetOffsets(int which, int x, int y) + { + LeftOffset[which] = x; + TopOffset[which] = y; + } + void SetOffsets(int x, int y) + { + LeftOffset[0] = x; + TopOffset[0] = y; + LeftOffset[1] = x; + TopOffset[1] = y; + } + void SetScale(float x, float y) + { + ScaleX = x; + ScaleY = y; + DisplayWidth = TexelWidth / x; + DisplayHeight = TexelHeight / y; + } + + const SpritePositioningInfo& GetSpritePositioning(int which) { if (spi == nullptr) SetupSpriteData(); return spi[which]; } + int GetAreas(FloatRect** pAreas) const; + + bool GetTranslucency() + { + return Base->GetTranslucency(); + } + + int GetClampMode(int clampmode) + { + if (GetUseType() == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; + else if (isHardwareCanvas()) clampmode = CLAMP_CAMTEX; + else if ((isWarped() || shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; + return clampmode; + } + + void CleanHardwareData(bool full = true); + + void GetLayers(TArray& layers) + { + layers.Clear(); + for (auto tex : { Base.get(), Brightmap.get() }) + { + if (tex != nullptr) layers.Push(tex); + } + if (Layers) + { + for (auto tex : { Layers->Detailmap.get(), Layers->Glowmap.get(), Layers->Normal.get(), Layers->Specular.get(), Layers->Metallic.get(), Layers->Roughness.get(), Layers->AmbientOcclusion.get() }) + { + if (tex != nullptr) layers.Push(tex); + } + for (auto& tex : Layers->CustomShaderTextures) + { + if (tex != nullptr) layers.Push(tex.get()); + } + } + } + + FVector2 GetDetailScale() const + { + return detailScale; + } + + void SetDetailScale(float x, float y) + { + detailScale.X = x; + detailScale.Y = y; + } + + FTexture* GetBrightmap() + { + if (Brightmap.get() || (flags & GTexf_BrightmapChecked)) return Brightmap.get(); + CreateDefaultBrightmap(); + return Brightmap.get(); + } + FTexture* GetGlowmap() + { + if (!Layers) return nullptr; + return Layers->Glowmap.get(); + } + FTexture* GetDetailmap() + { + if (!Layers) return nullptr; + return Layers->Detailmap.get(); + } + FTexture* GetNormalmap() + { + if (!Layers) return nullptr; + return Layers->Normal.get(); + } + FTexture* GetSpecularmap() + { + if (!Layers) return nullptr; + return Layers->Specular.get(); + } + FTexture* GetMetallic() + { + if (!Layers) return nullptr; + return Layers->Metallic.get(); + } + FTexture* GetRoughness() + { + if (!Layers) return nullptr; + return Layers->Roughness.get(); + } + FTexture* GetAmbientOcclusion() + { + if (!Layers) return nullptr; + return Layers->AmbientOcclusion.get(); + } + + void SetGlowmap(FTexture *T) + { + if (!Layers) Layers = std::make_unique(); + Layers->Glowmap = T; + } + void SetDetailmap(FTexture* T) + { + if (!Layers) Layers = std::make_unique(); + Layers->Detailmap = T; + } + void SetNormalmap(FTexture* T) + { + if (!Layers) Layers = std::make_unique(); + Layers->Normal = T; + } + void SetSpecularmap(FTexture* T) + { + if (!Layers) Layers = std::make_unique(); + Layers->Specular = T; + } + +}; + +inline FGameTexture* MakeGameTexture(FTexture* tex, const char *name, ETextureType useType) +{ + if (!tex) return nullptr; + auto t = new FGameTexture(tex, name); + t->SetUseType(useType); + return t; +} + +enum EUpscaleFlags : int +{ + UF_None = 0, + UF_Texture = 1, + UF_Sprite = 2, + UF_Font = 4, + UF_Skin = 8 +}; + +extern int upscalemask; +void UpdateUpscaleMask(); + +void calcShouldUpscale(FGameTexture* tex); +inline int shouldUpscale(FGameTexture* tex, EUpscaleFlags UseType) +{ + // This only checks the global scale mask and the texture's validation for upscaling. Everything else has been done up front elsewhere. + if (!(upscalemask & UseType)) return 0; + return tex->GetUpscaleFlag(); +} + +struct FTexCoordInfo +{ + int mRenderWidth; + int mRenderHeight; + int mWidth; + FVector2 mScale; + FVector2 mTempScale; + bool mWorldPanning; + + float FloatToTexU(float v) const { return v / mRenderWidth; } + float FloatToTexV(float v) const { return v / mRenderHeight; } + float RowOffset(float ofs) const; + float TextureOffset(float ofs) const; + float TextureAdjustWidth() const; + void GetFromTexture(FGameTexture* tex, float x, float y, bool forceworldpanning); +}; diff --git a/src/gamedata/textures/hires/hqnx/common.h b/src/common/textures/hires/hqnx/common.h similarity index 100% rename from src/gamedata/textures/hires/hqnx/common.h rename to src/common/textures/hires/hqnx/common.h diff --git a/src/gamedata/textures/hires/hqnx/hq2x.cpp b/src/common/textures/hires/hqnx/hq2x.cpp similarity index 100% rename from src/gamedata/textures/hires/hqnx/hq2x.cpp rename to src/common/textures/hires/hqnx/hq2x.cpp diff --git a/src/gamedata/textures/hires/hqnx/hq3x.cpp b/src/common/textures/hires/hqnx/hq3x.cpp similarity index 100% rename from src/gamedata/textures/hires/hqnx/hq3x.cpp rename to src/common/textures/hires/hqnx/hq3x.cpp diff --git a/src/gamedata/textures/hires/hqnx/hq4x.cpp b/src/common/textures/hires/hqnx/hq4x.cpp similarity index 100% rename from src/gamedata/textures/hires/hqnx/hq4x.cpp rename to src/common/textures/hires/hqnx/hq4x.cpp diff --git a/src/gamedata/textures/hires/hqnx/hqx.h b/src/common/textures/hires/hqnx/hqx.h similarity index 100% rename from src/gamedata/textures/hires/hqnx/hqx.h rename to src/common/textures/hires/hqnx/hqx.h diff --git a/src/gamedata/textures/hires/hqnx/init.cpp b/src/common/textures/hires/hqnx/init.cpp similarity index 100% rename from src/gamedata/textures/hires/hqnx/init.cpp rename to src/common/textures/hires/hqnx/init.cpp diff --git a/src/gamedata/textures/hires/hqnx_asm/hq2x_asm.cpp b/src/common/textures/hires/hqnx_asm/hq2x_asm.cpp similarity index 100% rename from src/gamedata/textures/hires/hqnx_asm/hq2x_asm.cpp rename to src/common/textures/hires/hqnx_asm/hq2x_asm.cpp diff --git a/src/gamedata/textures/hires/hqnx_asm/hq3x_asm.cpp b/src/common/textures/hires/hqnx_asm/hq3x_asm.cpp similarity index 100% rename from src/gamedata/textures/hires/hqnx_asm/hq3x_asm.cpp rename to src/common/textures/hires/hqnx_asm/hq3x_asm.cpp diff --git a/src/gamedata/textures/hires/hqnx_asm/hq4x_asm.cpp b/src/common/textures/hires/hqnx_asm/hq4x_asm.cpp similarity index 99% rename from src/gamedata/textures/hires/hqnx_asm/hq4x_asm.cpp rename to src/common/textures/hires/hqnx_asm/hq4x_asm.cpp index 7ce8a162123..5d22e134858 100644 --- a/src/gamedata/textures/hires/hqnx_asm/hq4x_asm.cpp +++ b/src/common/textures/hires/hqnx_asm/hq4x_asm.cpp @@ -272,9 +272,9 @@ bool Diff(const unsigned int rgb1, const unsigned int rgb2) { return false; } - + static const hq_vec THRESHOLD = 0x00300706; - + const hq_vec yuv1 = RGBtoYUV[rgb1]; const hq_vec yuv2 = RGBtoYUV[rgb2]; diff --git a/src/gamedata/textures/hires/hqnx_asm/hqnx_asm.h b/src/common/textures/hires/hqnx_asm/hqnx_asm.h similarity index 100% rename from src/gamedata/textures/hires/hqnx_asm/hqnx_asm.h rename to src/common/textures/hires/hqnx_asm/hqnx_asm.h diff --git a/src/gamedata/textures/hires/hqnx_asm/hqnx_asm_Image.cpp b/src/common/textures/hires/hqnx_asm/hqnx_asm_Image.cpp similarity index 100% rename from src/gamedata/textures/hires/hqnx_asm/hqnx_asm_Image.cpp rename to src/common/textures/hires/hqnx_asm/hqnx_asm_Image.cpp diff --git a/src/gamedata/textures/hires/hqnx_asm/hqnx_asm_Image.h b/src/common/textures/hires/hqnx_asm/hqnx_asm_Image.h similarity index 99% rename from src/gamedata/textures/hires/hqnx_asm/hqnx_asm_Image.h rename to src/common/textures/hires/hqnx_asm/hqnx_asm_Image.h index 918b904fe26..6e2a9310812 100644 --- a/src/gamedata/textures/hires/hqnx_asm/hqnx_asm_Image.h +++ b/src/common/textures/hires/hqnx_asm/hqnx_asm_Image.h @@ -19,6 +19,7 @@ //#ifdef WIN32 //#define DLL __declspec(dllexport) //#else +#pragma once #define DLL //#endif diff --git a/src/gamedata/textures/hires/hqresize.cpp b/src/common/textures/hires/hqresize.cpp similarity index 93% rename from src/gamedata/textures/hires/hqresize.cpp rename to src/common/textures/hires/hqresize.cpp index 8a63dd06f46..fc3f13a1624 100644 --- a/src/gamedata/textures/hires/hqresize.cpp +++ b/src/common/textures/hires/hqresize.cpp @@ -35,15 +35,19 @@ */ #include "c_cvars.h" -#include "v_video.h" #include "hqnx/hqx.h" #ifdef HAVE_MMX #include "hqnx_asm/hqnx_asm.h" #endif +#include #include "xbr/xbrz.h" #include "xbr/xbrz_old.h" #include "parallel_for.h" -#include "hwrenderer/textures/hw_material.h" +#include "textures.h" +#include "texturemanager.h" +#include "printf.h" + +int upscalemask; EXTERN_CVAR(Int, gl_texture_hqresizemult) CUSTOM_CVAR(Int, gl_texture_hqresizemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) @@ -53,6 +57,7 @@ CUSTOM_CVAR(Int, gl_texture_hqresizemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | if ((gl_texture_hqresizemult > 4) && (self < 4) && (self > 0)) gl_texture_hqresizemult = 4; TexMan.FlushAll(); + UpdateUpscaleMask(); } CUSTOM_CVAR(Int, gl_texture_hqresizemult, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) @@ -62,6 +67,7 @@ CUSTOM_CVAR(Int, gl_texture_hqresizemult, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | if ((self > 4) && (gl_texture_hqresizemode < 4) && (gl_texture_hqresizemode > 0)) self = 4; TexMan.FlushAll(); + UpdateUpscaleMask(); } CUSTOM_CVAR(Int, gl_texture_hqresize_maxinputsize, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) @@ -70,14 +76,16 @@ CUSTOM_CVAR(Int, gl_texture_hqresize_maxinputsize, 512, CVAR_ARCHIVE | CVAR_GLOB TexMan.FlushAll(); } -CUSTOM_CVAR(Int, gl_texture_hqresize_targets, 7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +CUSTOM_CVAR(Int, gl_texture_hqresize_targets, 15, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { TexMan.FlushAll(); + UpdateUpscaleMask(); } CVAR (Flag, gl_texture_hqresize_textures, gl_texture_hqresize_targets, 1); CVAR (Flag, gl_texture_hqresize_sprites, gl_texture_hqresize_targets, 2); CVAR (Flag, gl_texture_hqresize_fonts, gl_texture_hqresize_targets, 4); +CVAR (Flag, gl_texture_hqresize_skins, gl_texture_hqresize_targets, 8); CVAR(Bool, gl_texture_hqresize_multithread, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); @@ -95,6 +103,13 @@ CUSTOM_CVAR(Int, gl_texture_hqresize_mt_height, 4, CVAR_ARCHIVE | CVAR_GLOBALCON CVAR(Int, xbrz_colorformat, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +void UpdateUpscaleMask() +{ + if (!gl_texture_hqresizemode || gl_texture_hqresizemult == 1) upscalemask = 0; + else upscalemask = gl_texture_hqresize_targets; +} + + static void xbrzApplyOptions() { if (gl_texture_hqresizemult != 0 && (gl_texture_hqresizemode == 4 || gl_texture_hqresizemode == 5)) @@ -290,7 +305,8 @@ static unsigned char *hqNxAsmHelper( void (*hqNxFunction) ( int*, unsigned char* initdone = true; } - HQnX_asm::CImage cImageIn; + auto pImageIn = std::make_unique(); + auto& cImageIn = *pImageIn; cImageIn.SetImage(inputBuffer, inWidth, inHeight, 32); cImageIn.Convert32To17(); @@ -361,7 +377,7 @@ static unsigned char *xbrzHelper( void (*xbrzFunction) ( size_t, const uint32_t* outHeight = N *inHeight; unsigned char * newBuffer = new unsigned char[outWidth*outHeight*4]; - + const int thresholdWidth = gl_texture_hqresize_mt_width; const int thresholdHeight = gl_texture_hqresize_mt_height; @@ -404,42 +420,15 @@ static void xbrzOldScale(size_t factor, const uint32_t* src, uint32_t* trg, int // the upsampled buffer. // //=========================================================================== + void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly) { // [BB] Make sure that inWidth and inHeight denote the size of // the returned buffer even if we don't upsample the input buffer. + int inWidth = texbuffer.mWidth; int inHeight = texbuffer.mHeight; - // [BB] Don't resample if width * height of the input texture is bigger than gl_texture_hqresize_maxinputsize squared. - const int maxInputSize = gl_texture_hqresize_maxinputsize; - if (inWidth * inHeight > maxInputSize * maxInputSize) - return; - - // [BB] Don't try to upsample textures based off FCanvasTexture. (This should never get here in the first place!) - if (bHasCanvas) - return; - - // already scaled? - if (Scale.X >= 2 && Scale.Y >= 2) - return; - - switch (UseType) - { - case ETextureType::Sprite: - case ETextureType::SkinSprite: - if (!(gl_texture_hqresize_targets & 2)) return; - break; - - case ETextureType::FontChar: - if (!(gl_texture_hqresize_targets & 4)) return; - break; - - default: - if (!(gl_texture_hqresize_targets & 1)) return; - break; - } - int type = gl_texture_hqresizemode; int mult = gl_texture_hqresizemult; #ifdef HAVE_MMX @@ -508,3 +497,29 @@ void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasA contentId.scalefactor = mult; texbuffer.mContentId = contentId.id; } + +//=========================================================================== +// +// This was pulled out of the above function to allow running these +// checks before the texture is passed to the render state. +// +//=========================================================================== + +void calcShouldUpscale(FGameTexture *tex) +{ + tex->SetUpscaleFlag(0); + // [BB] Don't resample if width * height of the input texture is bigger than gl_texture_hqresize_maxinputsize squared. + const int maxInputSize = gl_texture_hqresize_maxinputsize; + if (tex->GetTexelWidth() * tex->GetTexelHeight() > maxInputSize * maxInputSize) + return; + + // [BB] Don't try to upsample textures based off FCanvasTexture. (This should never get here in the first place!) + if (tex->isHardwareCanvas()) + return; + + // already scaled? + if (tex->GetScaleX() >= 2.f || tex->GetScaleY() > 2.f) + return; + + tex->SetUpscaleFlag(1); +} \ No newline at end of file diff --git a/src/gamedata/textures/hires/xbr/xbrz.cpp b/src/common/textures/hires/xbr/xbrz.cpp similarity index 99% rename from src/gamedata/textures/hires/xbr/xbrz.cpp rename to src/common/textures/hires/xbr/xbrz.cpp index cd0b7b030d3..855205af253 100644 --- a/src/gamedata/textures/hires/xbr/xbrz.cpp +++ b/src/common/textures/hires/xbr/xbrz.cpp @@ -420,7 +420,7 @@ void blendPixel(const Kernel_3x3& ker, return true; //make sure there is no second blending in an adjacent rotation for this pixel: handles insular pixels, mario eyes - if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90� corners + if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90° corners return false; if (getBottomL(blend) != BLEND_NONE && !eq(e, c)) return false; diff --git a/src/gamedata/textures/hires/xbr/xbrz.h b/src/common/textures/hires/xbr/xbrz.h similarity index 100% rename from src/gamedata/textures/hires/xbr/xbrz.h rename to src/common/textures/hires/xbr/xbrz.h diff --git a/src/gamedata/textures/hires/xbr/xbrz_config.h b/src/common/textures/hires/xbr/xbrz_config.h similarity index 100% rename from src/gamedata/textures/hires/xbr/xbrz_config.h rename to src/common/textures/hires/xbr/xbrz_config.h diff --git a/src/gamedata/textures/hires/xbr/xbrz_config_old.h b/src/common/textures/hires/xbr/xbrz_config_old.h similarity index 100% rename from src/gamedata/textures/hires/xbr/xbrz_config_old.h rename to src/common/textures/hires/xbr/xbrz_config_old.h diff --git a/src/gamedata/textures/hires/xbr/xbrz_old.cpp b/src/common/textures/hires/xbr/xbrz_old.cpp similarity index 100% rename from src/gamedata/textures/hires/xbr/xbrz_old.cpp rename to src/common/textures/hires/xbr/xbrz_old.cpp diff --git a/src/gamedata/textures/hires/xbr/xbrz_old.h b/src/common/textures/hires/xbr/xbrz_old.h similarity index 99% rename from src/gamedata/textures/hires/xbr/xbrz_old.h rename to src/common/textures/hires/xbr/xbrz_old.h index 9a46f2a9786..10e60dcfc2e 100644 --- a/src/gamedata/textures/hires/xbr/xbrz_old.h +++ b/src/common/textures/hires/xbr/xbrz_old.h @@ -47,7 +47,7 @@ using a modified approach of xBR: THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap! - there is a minor inefficiency for the first row of a slice, so avoid processing single rows only - + */ void scale(size_t factor, //valid range: 2 - 5 const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, diff --git a/src/gamedata/textures/hires/xbr/xbrz_tools.h b/src/common/textures/hires/xbr/xbrz_tools.h similarity index 100% rename from src/gamedata/textures/hires/xbr/xbrz_tools.h rename to src/common/textures/hires/xbr/xbrz_tools.h diff --git a/src/common/textures/hw_ihwtexture.cpp b/src/common/textures/hw_ihwtexture.cpp new file mode 100644 index 00000000000..296bfd40dae --- /dev/null +++ b/src/common/textures/hw_ihwtexture.cpp @@ -0,0 +1,137 @@ +/* +** ihwtexture.cpp +** Interface for hardware textures +** +**--------------------------------------------------------------------------- +** Copyright 2006-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "hw_ihwtexture.h" +#include "basics.h" +#include "tarray.h" +#include "xs_Float.h" + +//=========================================================================== +// +// Quick'n dirty image rescaling. +// +// This will only be used when the source texture is larger than +// what the hardware can manage (extremely rare in Doom) +// +// Code taken from wxWidgets +// +//=========================================================================== + +struct BoxPrecalc +{ + int boxStart; + int boxEnd; +}; + +static void ResampleBoxPrecalc(TArray& boxes, int oldDim) +{ + int newDim = boxes.Size(); + const double scale_factor_1 = double(oldDim) / newDim; + const int scale_factor_2 = (int)(scale_factor_1 / 2); + + for (int dst = 0; dst < newDim; ++dst) + { + // Source pixel in the Y direction + const int src_p = int(dst * scale_factor_1); + + BoxPrecalc& precalc = boxes[dst]; + precalc.boxStart = std::clamp(int(src_p - scale_factor_1 / 2.0 + 1), 0, oldDim - 1); + precalc.boxEnd = std::clamp(std::max(precalc.boxStart + 1, int(src_p + scale_factor_2)), 0, oldDim - 1); + } +} + +void IHardwareTexture::Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data) +{ + + // This function implements a simple pre-blur/box averaging method for + // downsampling that gives reasonably smooth results To scale the image + // down we will need to gather a grid of pixels of the size of the scale + // factor in each direction and then do an averaging of the pixels. + + TArray vPrecalcs(height, true); + TArray hPrecalcs(width, true); + + ResampleBoxPrecalc(vPrecalcs, sheight); + ResampleBoxPrecalc(hPrecalcs, swidth); + + int averaged_pixels, averaged_alpha, src_pixel_index; + double sum_r, sum_g, sum_b, sum_a; + + for (int y = 0; y < height; y++) // Destination image - Y direction + { + // Source pixel in the Y direction + const BoxPrecalc& vPrecalc = vPrecalcs[y]; + + for (int x = 0; x < width; x++) // Destination image - X direction + { + // Source pixel in the X direction + const BoxPrecalc& hPrecalc = hPrecalcs[x]; + + // Box of pixels to average + averaged_pixels = 0; + averaged_alpha = 0; + sum_r = sum_g = sum_b = sum_a = 0.0; + + for (int j = vPrecalc.boxStart; j <= vPrecalc.boxEnd; ++j) + { + for (int i = hPrecalc.boxStart; i <= hPrecalc.boxEnd; ++i) + { + // Calculate the actual index in our source pixels + src_pixel_index = j * swidth + i; + + int a = src_data[src_pixel_index * 4 + 3]; + if (a > 0) // do not use color from fully transparent pixels + { + sum_r += src_data[src_pixel_index * 4 + 0]; + sum_g += src_data[src_pixel_index * 4 + 1]; + sum_b += src_data[src_pixel_index * 4 + 2]; + sum_a += a; + averaged_pixels++; + } + averaged_alpha++; + + } + } + + // Calculate the average from the sum and number of averaged pixels + dst_data[0] = (unsigned char)xs_CRoundToInt(sum_r / averaged_pixels); + dst_data[1] = (unsigned char)xs_CRoundToInt(sum_g / averaged_pixels); + dst_data[2] = (unsigned char)xs_CRoundToInt(sum_b / averaged_pixels); + dst_data[3] = (unsigned char)xs_CRoundToInt(sum_a / averaged_alpha); + dst_data += 4; + } + } +} + diff --git a/src/rendering/hwrenderer/textures/hw_ihwtexture.h b/src/common/textures/hw_ihwtexture.h similarity index 76% rename from src/rendering/hwrenderer/textures/hw_ihwtexture.h rename to src/common/textures/hw_ihwtexture.h index 741bfd1bc27..b207dceb4b5 100644 --- a/src/rendering/hwrenderer/textures/hw_ihwtexture.h +++ b/src/common/textures/hw_ihwtexture.h @@ -14,14 +14,12 @@ class IHardwareTexture MAX_TEXTURES = 16 }; - IHardwareTexture() {} - virtual ~IHardwareTexture() {} - - virtual void DeleteDescriptors() { } + IHardwareTexture() = default; + virtual ~IHardwareTexture() = default; virtual void AllocateBuffer(int w, int h, int texelsize) = 0; virtual uint8_t *MapBuffer() = 0; - virtual unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) = 0; + virtual unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) = 0; void Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data); diff --git a/src/common/textures/hw_material.cpp b/src/common/textures/hw_material.cpp new file mode 100644 index 00000000000..2517c098edc --- /dev/null +++ b/src/common/textures/hw_material.cpp @@ -0,0 +1,226 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2004-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include "filesystem.h" +#include "m_png.h" +#include "c_dispatch.h" +#include "hw_ihwtexture.h" +#include "hw_material.h" +#include "texturemanager.h" +#include "c_cvars.h" +#include "v_video.h" + + +CVAR(Bool, gl_customshader, true, 0); + + +static IHardwareTexture* (*layercallback)(int layer, int translation); +TArray usershaders; + +void FMaterial::SetLayerCallback(IHardwareTexture* (*cb)(int layer, int translation)) +{ + layercallback = cb; +} + +//=========================================================================== +// +// Constructor +// +//=========================================================================== + +FMaterial::FMaterial(FGameTexture * tx, int scaleflags) +{ + mShaderIndex = SHADER_Default; + sourcetex = tx; + auto imgtex = tx->GetTexture(); + mTextureLayers.Push({ imgtex, scaleflags, -1 }); + + if (tx->GetUseType() == ETextureType::SWCanvas && static_cast(imgtex)->GetColorFormat() == 0) + { + mShaderIndex = SHADER_Paletted; + } + else if (scaleflags & CTF_Indexed) + { + mTextureLayers[0].scaleFlags |= CTF_Indexed; + mShaderIndex = SHADER_Paletted; + } + else if (tx->isHardwareCanvas()) + { + if (tx->GetShaderIndex() >= FIRST_USER_SHADER) + { + mShaderIndex = tx->GetShaderIndex(); + } + mTextureLayers.Last().clampflags = CLAMP_CAMTEX; + // no additional layers for cameratexture + } + else + { + if (tx->isWarped()) + { + mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2 + } + // Note that the material takes no ownership of the texture! + else if (tx->Layers && tx->Layers->Normal.get() && tx->Layers->Specular.get()) + { + for (auto &texture : { tx->Layers->Normal.get(), tx->Layers->Specular.get() }) + { + mTextureLayers.Push({ texture, 0, -1 }); + } + mShaderIndex = SHADER_Specular; + } + else if (tx->Layers && tx->Layers->Normal.get() && tx->Layers->Metallic.get() && tx->Layers->Roughness.get() && tx->Layers->AmbientOcclusion.get()) + { + for (auto &texture : { tx->Layers->Normal.get(), tx->Layers->Metallic.get(), tx->Layers->Roughness.get(), tx->Layers->AmbientOcclusion.get() }) + { + mTextureLayers.Push({ texture, 0, -1 }); + } + mShaderIndex = SHADER_PBR; + } + + // Note that these layers must present a valid texture even if not used, because empty TMUs in the shader are an undefined condition. + tx->CreateDefaultBrightmap(); + auto placeholder = TexMan.GameByIndex(1); + if (tx->Brightmap.get()) + { + mTextureLayers.Push({ tx->Brightmap.get(), scaleflags, -1 }); + mLayerFlags |= TEXF_Brightmap; + } + else + { + mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 }); + } + if (tx->Layers && tx->Layers->Detailmap.get()) + { + mTextureLayers.Push({ tx->Layers->Detailmap.get(), 0, CLAMP_NONE }); + mLayerFlags |= TEXF_Detailmap; + } + else + { + mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 }); + } + if (tx->Layers && tx->Layers->Glowmap.get()) + { + mTextureLayers.Push({ tx->Layers->Glowmap.get(), scaleflags, -1 }); + mLayerFlags |= TEXF_Glowmap; + } + else + { + mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 }); + } + + auto index = tx->GetShaderIndex(); + if (gl_customshader) + { + if (index >= FIRST_USER_SHADER) + { + const UserShaderDesc& usershader = usershaders[index - FIRST_USER_SHADER]; + if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material + { + if (tx->Layers) + { + for (auto& texture : tx->Layers->CustomShaderTextures) + { + if (texture == nullptr) continue; + mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable. + } + } + mShaderIndex = index; + } + } + } + } + mScaleFlags = scaleflags; + + mTextureLayers.ShrinkToFit(); + tx->Material[scaleflags] = this; + if (tx->isHardwareCanvas()) tx->SetTranslucent(false); +} + +//=========================================================================== +// +// Destructor +// +//=========================================================================== + +FMaterial::~FMaterial() +{ +} + + +//=========================================================================== +// +// +// +//=========================================================================== + +IHardwareTexture* FMaterial::GetLayer(int i, int translation, MaterialLayerInfo** pLayer) const +{ + if ((mScaleFlags & CTF_Indexed) && i > 0 && layercallback) + { + static MaterialLayerInfo deflayer = { nullptr, 0, CLAMP_XY }; + if (i == 1 || i == 2) + { + if (pLayer) *pLayer = &deflayer; + //This must be done with a user supplied callback because we cannot set up the rules for palette data selection here + return layercallback(i, translation); + } + } + else + { + auto& layer = mTextureLayers[i]; + if (pLayer) *pLayer = &layer; + if (mScaleFlags & CTF_Indexed) translation = -1; + if (layer.layerTexture) return layer.layerTexture->GetHardwareTexture(translation, layer.scaleFlags); + } + return nullptr; +} + +//========================================================================== +// +// Gets a texture from the texture manager and checks its validity for +// GL rendering. +// +//========================================================================== + +FMaterial * FMaterial::ValidateTexture(FGameTexture * gtex, int scaleflags, bool create) +{ + if (gtex && gtex->isValid()) + { + if (scaleflags & CTF_Indexed) scaleflags = CTF_Indexed; + if (!gtex->expandSprites()) scaleflags &= ~CTF_Expand; + + FMaterial *hwtex = gtex->Material[scaleflags]; + if (hwtex == NULL && create) + { + hwtex = screen->CreateMaterial(gtex, scaleflags); + } + return hwtex; + } + return NULL; +} + +void DeleteMaterial(FMaterial* mat) +{ + delete mat; +} + + diff --git a/src/common/textures/hw_material.h b/src/common/textures/hw_material.h new file mode 100644 index 00000000000..20c38b33269 --- /dev/null +++ b/src/common/textures/hw_material.h @@ -0,0 +1,80 @@ + +#ifndef __GL_MATERIAL_H +#define __GL_MATERIAL_H + +#include "m_fixed.h" +#include "textures.h" + +struct FRemapTable; +class IHardwareTexture; + +struct MaterialLayerInfo +{ + FTexture* layerTexture; + int scaleFlags; + int clampflags; +}; + +//=========================================================================== +// +// this is the material class for OpenGL. +// +//=========================================================================== + +class FMaterial +{ + private: + TArray mTextureLayers; // the only layers allowed to scale are the brightmap and the glowmap. + int mShaderIndex; + int mLayerFlags = 0; + int mScaleFlags; + +public: + static void SetLayerCallback(IHardwareTexture* (*layercallback)(int layer, int translation)); + + FGameTexture *sourcetex; // the owning texture. + + FMaterial(FGameTexture *tex, int scaleflags); + virtual ~FMaterial(); + int GetLayerFlags() const { return mLayerFlags; } + int GetShaderIndex() const { return mShaderIndex; } + int GetScaleFlags() const { return mScaleFlags; } + virtual void DeleteDescriptors() { } + FVector2 GetDetailScale() const + { + return sourcetex->GetDetailScale(); + } + + FGameTexture* Source() const + { + return sourcetex; + } + + void ClearLayers() + { + mTextureLayers.Resize(1); + } + + void AddTextureLayer(FTexture *tex, bool allowscale) + { + mTextureLayers.Push({ tex, allowscale }); + } + + int NumLayers() const + { + return mTextureLayers.Size(); + } + + IHardwareTexture *GetLayer(int i, int translation, MaterialLayerInfo **pLayer = nullptr) const; + + + static FMaterial *ValidateTexture(FGameTexture * tex, int scaleflags, bool create = true); + const TArray &GetLayerArray() const + { + return mTextureLayers; + } +}; + +#endif + + diff --git a/src/common/textures/hw_texcontainer.h b/src/common/textures/hw_texcontainer.h new file mode 100644 index 00000000000..e8777b00e1a --- /dev/null +++ b/src/common/textures/hw_texcontainer.h @@ -0,0 +1,175 @@ +#pragma once + +#include "tarray.h" +#include "hw_ihwtexture.h" +#include "palettecontainer.h" +#include "hw_ihwtexture.h" // Note: this cannot be a forward declaration due to the inlined delete statement below. + +struct FTextureBuffer; + +enum ECreateTexBufferFlags +{ + CTF_Expand = 1, // create buffer with a one-pixel wide border + CTF_Upscale = 2, // Upscale the texture + CTF_CreateMask = 3, // Flags that are relevant for hardware texture creation. + CTF_Indexed = 4, // Tell the backend to create an indexed texture. + CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures. + CTF_ProcessData = 16, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture. +}; + +class FHardwareTextureContainer +{ +public: + enum + { + MAX_TEXTURES = 16 + }; + +private: + struct TranslatedTexture + { + IHardwareTexture *hwTexture = nullptr; + int translation = 0; + bool precacheMarker; // This is used to check whether a texture has been hit by the precacher, so that the cleanup code can delete the unneeded ones. + + void Delete() + { + delete hwTexture; + hwTexture = nullptr; + } + + ~TranslatedTexture() + { + Delete(); + } + + void MarkForPrecache(bool on) + { + precacheMarker = on; + } + + bool isMarkedForPreache() const + { + return precacheMarker; + } + }; + +private: + + TranslatedTexture hwDefTex[4]; + TArray hwTex_Translated; + + TranslatedTexture * GetTexID(int translation, int scaleflags) + { + // Allow negative indices to pass through unchanged. + // This is needed for allowing the client to allocate slots that aren't matched to a palette, e.g. Build's indexed variants. + if (translation >= 0) + { + if (!IsLuminosityTranslation(translation)) + { + auto remap = GPalette.TranslationToTable(translation); + translation = remap == nullptr ? 0 : remap->Index; + } + else + { + // only needs to preserve the color range plus an identifier for marking this a luminosity translation. + translation = ((translation >> 16) & 0x3fff) | 0xff0000; + } + } + else translation &= ~0x7fffffff; + + if (translation == 0 && !(scaleflags & CTF_Upscale)) + { + return &hwDefTex[scaleflags]; + } + + translation |= (scaleflags << 24); + // normally there aren't more than very few different + // translations here so this isn't performance critical. + unsigned index = hwTex_Translated.FindEx([=](auto &element) + { + return element.translation == translation; + }); + if (index < hwTex_Translated.Size()) + { + return &hwTex_Translated[index]; + } + + int add = hwTex_Translated.Reserve(1); + auto item = &hwTex_Translated[add]; + item->translation = translation; + return item; + } + +public: + void Clean() + { + hwDefTex[0].Delete(); + hwDefTex[1].Delete(); + hwTex_Translated.Clear(); + } + + IHardwareTexture * GetHardwareTexture(int translation, int scaleflags) + { + auto tt = GetTexID(translation, scaleflags); + return tt->hwTexture; + } + + void AddHardwareTexture(int translation, int scaleflags, IHardwareTexture *tex) + { + auto tt = GetTexID(translation, scaleflags); + tt->Delete(); + tt->hwTexture =tex; + } + + //=========================================================================== + // + // Deletes all allocated resources and considers translations + // + //=========================================================================== + + void CleanUnused() + { + for (auto& tt : hwDefTex) + { + if (!tt.isMarkedForPreache()) tt.Delete(); + } + for (int i = hwTex_Translated.Size()-1; i>= 0; i--) + { + auto& tt = hwTex_Translated[i]; + if (!tt.isMarkedForPreache()) + { + hwTex_Translated.Delete(i); + } + } + } + + void UnmarkAll() + { + for (auto& tt : hwDefTex) + { + tt.MarkForPrecache(false); + } + for (auto& tt : hwTex_Translated) + { + tt.MarkForPrecache(false); + } + } + + void MarkForPrecache(int translation, int scaleflags) + { + auto tt = GetTexID(translation, scaleflags); + tt->MarkForPrecache(true); + } + + + template + void Iterate(T callback) + { + for (auto & t : hwDefTex) if (t.hwTexture) callback(t.hwTexture); + for (auto & t : hwTex_Translated) if (t.hwTexture) callback(t.hwTexture); + } + + +}; + diff --git a/src/common/textures/image.cpp b/src/common/textures/image.cpp new file mode 100644 index 00000000000..83f7450ebec --- /dev/null +++ b/src/common/textures/image.cpp @@ -0,0 +1,394 @@ +/* +** texture.cpp +** The base texture class +** +**--------------------------------------------------------------------------- +** Copyright 2004-2007 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "bitmap.h" +#include "image.h" +#include "filesystem.h" +#include "files.h" +#include "cmdlib.h" +#include "palettecontainer.h" + +FMemArena ImageArena(32768); +TArrayFImageSource::ImageForLump; +int FImageSource::NextID; +static PrecacheInfo precacheInfo; + +struct PrecacheDataPaletted +{ + PalettedPixels Pixels; + int RefCount; + int ImageID; + int Frame; +}; + +struct PrecacheDataRgba +{ + FBitmap Pixels; + int TransInfo; + int RefCount; + int ImageID; + int Frame; +}; + +// TMap doesn't handle this kind of data well. std::map neither. The linear search is still faster, even for a few 100 entries because it doesn't have to access the heap as often.. +TArray precacheDataPaletted; +TArray precacheDataRgba; + +//=========================================================================== +// +// the default just returns an empty texture. +// +//=========================================================================== + +PalettedPixels FImageSource::CreatePalettedPixels(int conversion, int frame) +{ + PalettedPixels Pixels(Width * Height); + memset(Pixels.Data(), 0, Width * Height); + return Pixels; +} + +PalettedPixels FImageSource::GetCachedPalettedPixels(int conversion, int frame) +{ + PalettedPixels ret; + + auto imageID = ImageID; + + // Do we have this image in the cache? + unsigned index = conversion != normal? UINT_MAX : precacheDataPaletted.FindEx([=](PrecacheDataPaletted &entry) { return entry.ImageID == imageID && entry.Frame == frame; }); + if (index < precacheDataPaletted.Size()) + { + auto cache = &precacheDataPaletted[index]; + + if (cache->RefCount > 1) + { + //Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret.Pixels.Set(cache->Pixels.Data(), cache->Pixels.Size()); + cache->RefCount--; + } + else if (cache->Pixels.Size() > 0) + { + //Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret = std::move(cache->Pixels); + precacheDataPaletted.Delete(index); + } + else + { + //Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount); + } + } + else + { + // The image wasn't cached. Now there's two possibilities: + auto info = precacheInfo.CheckKey(ImageID); + if (!info || info->second <= 1 || conversion != normal) + { + // This is either the only copy needed or some access outside the caching block. In these cases create a new one and directly return it. + //Printf("returning fresh copy of %s\n", name.GetChars()); + return CreatePalettedPixels(conversion, frame); + } + else + { + //Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->second); + // This is the first time it gets accessed and needs to be placed in the cache. + PrecacheDataPaletted *pdp = &precacheDataPaletted[precacheDataPaletted.Reserve(1)]; + + pdp->ImageID = imageID; + pdp->RefCount = info->second - 1; + info->second = 0; + pdp->Pixels = CreatePalettedPixels(normal, frame); + ret.Pixels.Set(pdp->Pixels.Data(), pdp->Pixels.Size()); + } + } + return ret; +} + +TArray FImageSource::GetPalettedPixels(int conversion, int frame) +{ + auto pix = GetCachedPalettedPixels(conversion, frame); + if (pix.ownsPixels()) + { + // return the pixel store of the returned data directly if this was the last reference. + auto array = std::move(pix.PixelStore); + return array; + } + else + { + // If there are pending references, make a copy. + TArray array(pix.Pixels.Size(), true); + memcpy(array.Data(), pix.Pixels.Data(), array.Size()); + return array; + } +} + + + +//=========================================================================== +// +// FImageSource::CopyPixels +// +// this is the generic case that can handle +// any properly implemented texture for software rendering. +// Its drawback is that it is limited to the base palette which is +// why all classes that handle different palettes should subclass this +// method +// +//=========================================================================== + +int FImageSource::CopyPixels(FBitmap *bmp, int conversion, int frame) +{ + if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source. + PalEntry *palette = GPalette.BaseColors; + + auto ppix = CreatePalettedPixels(conversion, frame); + bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr); + return 0; +} + +int FImageSource::CopyTranslatedPixels(FBitmap *bmp, const PalEntry *remap, int frame) +{ + auto ppix = CreatePalettedPixels(normal, frame); + bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, remap, nullptr); + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +FBitmap FImageSource::GetCachedBitmap(const PalEntry *remap, int conversion, int *ptrans, int frame) +{ + FBitmap ret; + + int trans = -1; + auto imageID = ImageID; + + if (NumOfFrames == 1 && frame == 1) + { + frame = 0; + } + + if (remap != nullptr) + { + // Remapped images are never run through the cache because they would complicate matters too much for very little gain. + // Translated images are normally sprites which normally just consist of a single image and use no composition. + // Additionally, since translation requires the base palette, the really time consuming stuff will never be subjected to it. + ret.Create(Width, Height); + trans = CopyTranslatedPixels(&ret, remap, frame); + } + else + { + if (conversion == luminance) conversion = normal; // luminance has no meaning for true color. + // Do we have this image in the cache? + unsigned index = conversion != normal? UINT_MAX : precacheDataRgba.FindEx([=](PrecacheDataRgba &entry) { return entry.ImageID == imageID && entry.Frame == frame; }); + if (index < precacheDataRgba.Size()) + { + auto cache = &precacheDataRgba[index]; + + trans = cache->TransInfo; + if (cache->RefCount > 1) + { + //Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret.Copy(cache->Pixels, false); + cache->RefCount--; + } + else if (cache->Pixels.GetPixels()) + { + //Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret = std::move(cache->Pixels); + precacheDataRgba.Delete(index); + } + else + { + // This should never happen if the function is implemented correctly + //Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret.Create(Width, Height); + trans = CopyPixels(&ret, normal, frame); + } + } + else + { + // The image wasn't cached. Now there's two possibilities: + auto info = precacheInfo.CheckKey(ImageID); + if (!info || info->first <= 1 || conversion != normal) + { + // This is either the only copy needed or some access outside the caching block. In these cases create a new one and directly return it. + //Printf("returning fresh copy of %s\n", name.GetChars()); + ret.Create(Width, Height); + trans = CopyPixels(&ret, conversion, frame); + } + else + { + //Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->first); + // This is the first time it gets accessed and needs to be placed in the cache. + PrecacheDataRgba *pdr = &precacheDataRgba[precacheDataRgba.Reserve(1)]; + + pdr->ImageID = imageID; + pdr->Frame = frame; + pdr->RefCount = info->first - 1; + info->first = 0; + pdr->Pixels.Create(Width, Height); + trans = pdr->TransInfo = CopyPixels(&pdr->Pixels, normal, frame); + ret.Copy(pdr->Pixels, false); + } + } + } + if (ptrans) *ptrans = trans; + return ret; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FImageSource::CollectForPrecache(PrecacheInfo &info, bool requiretruecolor) +{ + auto val = info.CheckKey(ImageID); + bool tc = requiretruecolor; + if (val) + { + val->first += tc; + val->second += !tc; + } + else + { + auto pair = std::make_pair(tc, !tc); + info.Insert(ImageID, pair); + } +} + +void FImageSource::BeginPrecaching() +{ + precacheInfo.Clear(); +} + +void FImageSource::EndPrecaching() +{ + precacheDataPaletted.Clear(); + precacheDataRgba.Clear(); +} + +void FImageSource::RegisterForPrecache(FImageSource *img, bool requiretruecolor) +{ + img->CollectForPrecache(precacheInfo, requiretruecolor); +} + +//========================================================================== +// +// +// +//========================================================================== + +typedef FImageSource * (*CreateFunc)(FileReader & file, int lumpnum); + +struct TexCreateInfo +{ + CreateFunc TryCreate; + bool checkflat; +}; + +FImageSource *IMGZImage_TryCreate(FileReader &, int lumpnum); +FImageSource *PNGImage_TryCreate(FileReader &, int lumpnum); +FImageSource *DDSImage_TryCreate(FileReader &, int lumpnum); +FImageSource *PCXImage_TryCreate(FileReader &, int lumpnum); +FImageSource *TGAImage_TryCreate(FileReader &, int lumpnum); +FImageSource *StbImage_TryCreate(FileReader &, int lumpnum); +FImageSource *QOIImage_TryCreate(FileReader &, int lumpnum); +FImageSource *WebPImage_TryCreate(FileReader &, int lumpnum); +FImageSource *AnmImage_TryCreate(FileReader &, int lumpnum); +FImageSource *RawPageImage_TryCreate(FileReader &, int lumpnum); +FImageSource *FlatImage_TryCreate(FileReader &, int lumpnum); +FImageSource *PatchImage_TryCreate(FileReader &, int lumpnum); +FImageSource *EmptyImage_TryCreate(FileReader &, int lumpnum); +FImageSource *AutomapImage_TryCreate(FileReader &, int lumpnum); +FImageSource *StartupPageImage_TryCreate(FileReader &, int lumpnum); + + +// Examines the lump contents to decide what type of texture to create, +// and creates the texture. +FImageSource * FImageSource::GetImage(int lumpnum, bool isflat) +{ + static TexCreateInfo CreateInfo[] = { + { IMGZImage_TryCreate, false }, + { PNGImage_TryCreate, false }, + { DDSImage_TryCreate, false }, + { PCXImage_TryCreate, false }, + { StbImage_TryCreate, false }, + { QOIImage_TryCreate, false }, + { WebPImage_TryCreate, false }, + { TGAImage_TryCreate, false }, + { AnmImage_TryCreate, false }, + { StartupPageImage_TryCreate, false }, + { RawPageImage_TryCreate, false }, + { FlatImage_TryCreate, true }, // flat detection is not reliable, so only consider this for real flats. + { PatchImage_TryCreate, false }, + { EmptyImage_TryCreate, false }, + { AutomapImage_TryCreate, false }, + }; + + if (lumpnum == -1) return nullptr; + + unsigned size = ImageForLump.Size(); + if (size <= (unsigned)lumpnum) + { + // Hires textures can be added dynamically to the end of the lump array, so this must be checked each time. + ImageForLump.Resize(lumpnum + 1); + for (; size < ImageForLump.Size(); size++) ImageForLump[size] = nullptr; + } + // An image for this lump already exists. We do not need another one. + if (ImageForLump[lumpnum] != nullptr) return ImageForLump[lumpnum]; + + auto data = fileSystem.OpenFileReader(lumpnum); + if (!data.isOpen()) + return nullptr; + + for (size_t i = 0; i < countof(CreateInfo); i++) + { + if (!CreateInfo[i].checkflat || isflat) + { + auto image = CreateInfo[i].TryCreate(data, lumpnum); + if (image != nullptr) + { + ImageForLump[lumpnum] = image; + return image; + } + } + } + return nullptr; +} diff --git a/src/common/textures/image.h b/src/common/textures/image.h new file mode 100644 index 00000000000..72b5ca9df5a --- /dev/null +++ b/src/common/textures/image.h @@ -0,0 +1,205 @@ +#pragma once + +#include +#include "tarray.h" +#include "bitmap.h" +#include "memarena.h" + +#ifndef MAKE_ID +#ifndef __BIG_ENDIAN__ +#define MAKE_ID(a,b,c,d) ((uint32_t)((a)|((b)<<8)|((c)<<16)|((d)<<24))) +#else +#define MAKE_ID(a,b,c,d) ((uint32_t)((d)|((c)<<8)|((b)<<16)|((a)<<24))) +#endif +#endif + +using std::min; +using std::max; +using std::clamp; + + +class FImageSource; +using PrecacheInfo = TMap>; +extern FMemArena ImageArena; + +// Pixel store wrapper that can either own the pixels itself or refer to an external store. +struct PalettedPixels +{ + friend class FImageSource; + TArrayView Pixels; +private: + TArray PixelStore; + +public: + PalettedPixels() = default; + PalettedPixels(unsigned size) + { + PixelStore.Resize(size); + Pixels.Set(PixelStore.Data(), PixelStore.Size()); + } + PalettedPixels(uint8_t* data, unsigned size) + { + Pixels.Set(data, size); + } + bool ownsPixels() const + { + return Pixels.Data() == PixelStore.Data(); + } + uint8_t* Data() const { return Pixels.Data(); } + unsigned Size() const { return Pixels.Size(); } + + uint8_t& operator[] (size_t index) const + { + assert(index < Size()); + return Pixels[index]; + } + +}; + +// This represents a naked image. It has no high level logic attached to it. +// All it can do is provide raw image data to its users. +class FImageSource +{ + friend class FBrightmapTexture; +protected: + + static TArrayImageForLump; + static int NextID; + + int SourceLump; + int Width = 0, Height = 0; + int LeftOffset = 0, TopOffset = 0; // Offsets stored in the image. + bool bUseGamePalette = false; // true if this is an image without its own color set. + int ImageID = -1; + int NumOfFrames = 1; + + // Internal image creation functions. All external access should go through the cache interface, + // so that all code can benefit from future improvements to that. + + virtual PalettedPixels CreatePalettedPixels(int conversion, int frame = 0); + int CopyTranslatedPixels(FBitmap *bmp, const PalEntry *remap, int frame = 0); + + +public: + virtual bool SupportRemap0() { return false; } // Unfortunate hackery that's needed for Hexen's skies. Only the image can know about the needed parameters + virtual bool IsRawCompatible() { return true; } // Same thing for mid texture compatibility handling. Can only be determined by looking at the composition data which is private to the image. + + void CopySize(FImageSource &other) noexcept + { + Width = other.Width; + Height = other.Height; + LeftOffset = other.LeftOffset; + TopOffset = other.TopOffset; + SourceLump = other.SourceLump; + } + + // Images are statically allocated and freed in bulk. None of the subclasses may hold any destructible data. + void *operator new(size_t block) { return ImageArena.Alloc(block); } + void* operator new(size_t block, void* mem) { return mem; } + void operator delete(void *block) {} + + bool bMasked = true; // Image (might) have holes (Assume true unless proven otherwise!) + int8_t bTranslucent = -1; // Image has pixels with a non-0/1 value. (-1 means the user needs to do a real check) + + int GetId() const { return ImageID; } + + // 'noremap0' will only be looked at by FPatchTexture and forwarded by FMultipatchTexture. + + // Either returns a reference to the cache, or a newly created item. The return of this has to be considered transient. If you need to store the result, use GetPalettedPixels + PalettedPixels GetCachedPalettedPixels(int conversion, int frame = 0); + + // tries to get a buffer from the cache. If not available, create a new one. If further references are pending, create a copy. + TArray GetPalettedPixels(int conversion, int frame = 0); + + virtual int CopyPixels(FBitmap* bmp, int conversion, int frame = 0); + + FBitmap GetCachedBitmap(const PalEntry *remap, int conversion, int *trans = nullptr, int frame = 0); + + static void ClearImages() { ImageArena.FreeAll(); ImageForLump.Clear(); NextID = 0; } + static FImageSource * GetImage(int lumpnum, bool checkflat); + + // Frame functions + + // Gets number of frames. + int GetNumOfFrames() { return NumOfFrames; } + + // Gets duration of frame in miliseconds. + virtual int GetDurationOfFrame(int frame) { return 1000; } + + // Conversion option + enum EType + { + normal = 0, + luminance = 1, + noremap0 = 2 + }; + + FImageSource(int sourcelump = -1) noexcept : SourceLump(sourcelump) { ImageID = ++NextID; } + virtual ~FImageSource() = default; + + int GetWidth() const + { + return Width; + } + + int GetHeight() const + { + return Height; + } + + std::pair GetSize() const + { + return std::make_pair(Width, Height); + } + + std::pair GetOffsets() const + { + return std::make_pair(LeftOffset, TopOffset); + } + + void SetOffsets(int x, int y) + { + LeftOffset = x; + TopOffset = y; + } + + int LumpNum() const + { + return SourceLump; + } + + bool UseGamePalette() const + { + return bUseGamePalette; + } + + virtual void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor); + static void BeginPrecaching(); + static void EndPrecaching(); + static void RegisterForPrecache(FImageSource *img, bool requiretruecolor); +}; + + +//========================================================================== +// +// A texture defined in a Build TILESxxx.ART file +// +//========================================================================== +struct FRemapTable; + +class FBuildTexture : public FImageSource +{ +public: + FBuildTexture(const FString& pathprefix, int tilenum, const uint8_t* pixels, FRemapTable* translation, int width, int height, int left, int top); + PalettedPixels CreatePalettedPixels(int conversion, int frame = 0) override; + int CopyPixels(FBitmap* bmp, int conversion, int frame = 0) override; + +protected: + const uint8_t* RawPixels; + FRemapTable* Translation; +}; + + +class FTexture; + +FTexture* CreateImageTexture(FImageSource* img, int frame = 0) noexcept; diff --git a/src/gamedata/textures/imagehelpers.h b/src/common/textures/imagehelpers.h similarity index 92% rename from src/gamedata/textures/imagehelpers.h rename to src/common/textures/imagehelpers.h index 39cd83e67c7..a25187ef2c0 100644 --- a/src/gamedata/textures/imagehelpers.h +++ b/src/common/textures/imagehelpers.h @@ -40,28 +40,25 @@ #include #include "tarray.h" #include "colormatcher.h" -#include "v_palette.h" -#include "textures/bitmap.h" -#include "r_data/renderstyle.h" -#include "r_data/r_translate.h" +#include "bitmap.h" +#include "palettecontainer.h" +#include "v_colortables.h" namespace ImageHelpers { - extern uint8_t GrayMap[256]; - // Helpers for creating paletted images. inline uint8_t *GetRemap(bool wantluminance, bool srcisgrayscale = false) { if (wantluminance) { - return translationtables[TRANSLATION_Standard][srcisgrayscale ? STD_Gray : STD_Grayscale]->Remap; + return srcisgrayscale ? GPalette.GrayRamp.Remap : GPalette.GrayscaleMap.Remap; } else { - return srcisgrayscale ? GrayMap : GPalette.Remap; + return srcisgrayscale ? GPalette.GrayMap : GPalette.Remap; } } - + inline uint8_t RGBToPalettePrecise(bool wantluminance, int r, int g, int b, int a = 255) { if (wantluminance) @@ -73,7 +70,7 @@ namespace ImageHelpers return ColorMatcher.Pick(r, g, b); } } - + inline uint8_t RGBToPalette(bool wantluminance, int r, int g, int b, int a = 255) { if (wantluminance) @@ -86,19 +83,19 @@ namespace ImageHelpers return a < 128? 0 : RGB256k.RGB[r >> 2][g >> 2][b >> 2]; } } - + inline uint8_t RGBToPalette(bool wantluminance, PalEntry pe, bool hasalpha = true) { return RGBToPalette(wantluminance, pe.r, pe.g, pe.b, hasalpha? pe.a : 255); } - + //========================================================================== // // Converts a texture between row-major and column-major format // by flipping it about the X=Y axis. // //========================================================================== - + template void FlipSquareBlock (T *block, int x) { @@ -112,7 +109,7 @@ namespace ImageHelpers } } } - + inline void FlipSquareBlockRemap (uint8_t *block, int x, const uint8_t *remap) { for (int i = 0; i < x; ++i) @@ -127,7 +124,7 @@ namespace ImageHelpers } } } - + template void FlipNonSquareBlock (T *dst, const T *src, int x, int y, int srcpitch) { @@ -139,7 +136,7 @@ namespace ImageHelpers } } } - + inline void FlipNonSquareBlockRemap (uint8_t *dst, const uint8_t *src, int x, int y, int srcpitch, const uint8_t *remap) { for (int i = 0; i < x; ++i) @@ -150,5 +147,4 @@ namespace ImageHelpers } } } - } diff --git a/src/common/textures/imagetexture.cpp b/src/common/textures/imagetexture.cpp new file mode 100644 index 00000000000..233cf4b098f --- /dev/null +++ b/src/common/textures/imagetexture.cpp @@ -0,0 +1,121 @@ +/* +** imagetexture.cpp +** Texture class based on FImageSource +** +**--------------------------------------------------------------------------- +** Copyright 2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" + +#include "bitmap.h" +#include "image.h" +#include "textures.h" + + +//========================================================================== +// +// +// +//========================================================================== + +FImageTexture::FImageTexture(FImageSource *img, int frame) noexcept +: FTexture(img? img->LumpNum() : 0) +{ + mImage = img; + TexFrame = frame; + if (img != nullptr) + { + SetFromImage(); + } +} + +FImageTexture::~FImageTexture() +{ + delete mImage; +} + +void FImageTexture::SetFromImage() +{ + auto img = mImage; + Width = img->GetWidth(); + Height = img->GetHeight(); + + Masked = img->bMasked; + bTranslucent = img->bTranslucent; +} +//=========================================================================== +// +// +// +//=========================================================================== + +FBitmap FImageTexture::GetBgraBitmap(const PalEntry *p, int *trans) +{ + return mImage->GetCachedBitmap(p, bNoRemap0? FImageSource::noremap0 : FImageSource::normal, trans, TexFrame); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +TArray FImageTexture::Get8BitPixels(bool alpha) +{ + return mImage->GetPalettedPixels(alpha? FImageSource::luminance : bNoRemap0 ? FImageSource::noremap0 : FImageSource::normal, TexFrame); +} + +//=========================================================================== +// +// use the already known state of the underlying image to save time. +// +//=========================================================================== + +bool FImageTexture::DetermineTranslucency() +{ + if (mImage->bTranslucent != -1) + { + bTranslucent = mImage->bTranslucent; + return !!bTranslucent; + } + else + { + return FTexture::DetermineTranslucency(); + } +} + + +FTexture* CreateImageTexture(FImageSource* img, int frame) noexcept +{ + return new FImageTexture(img, frame); +} + diff --git a/src/utility/m_png.cpp b/src/common/textures/m_png.cpp similarity index 98% rename from src/utility/m_png.cpp rename to src/common/textures/m_png.cpp index 52d46f3e46e..331b35e200e 100644 --- a/src/utility/m_png.cpp +++ b/src/common/textures/m_png.cpp @@ -34,17 +34,22 @@ // HEADER FILES ------------------------------------------------------------ +#include #include -#include +#include +#include #ifdef _MSC_VER #include // for alloca() #endif #include "m_crc32.h" #include "m_swap.h" +#if __has_include("c_cvars.h") #include "c_cvars.h" -#include "r_defs.h" +#endif #include "m_png.h" +#include "basics.h" + // MACROS ------------------------------------------------------------------ @@ -100,6 +105,8 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const uint8_ // PUBLIC DATA DEFINITIONS ------------------------------------------------- +// allow this to compile without CVARs. +#if __has_include("c_cvars.h") CUSTOM_CVAR(Int, png_level, 5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) @@ -108,6 +115,10 @@ CUSTOM_CVAR(Int, png_level, 5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) self = 9; } CVAR(Float, png_gamma, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#else +const int png_level = 5; +const float png_gamma = 0; +#endif // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -243,7 +254,7 @@ bool M_AppendPNGText (FileWriter *file, const char *keyword, const char *text) { struct { uint32_t len, id; char key[80]; } head; int len = (int)strlen (text); - int keylen = MIN ((int)strlen (keyword), 79); + int keylen = min ((int)strlen (keyword), 79); uint32_t crc; head.len = BigLong(len + keylen + 1); @@ -326,7 +337,7 @@ char *M_GetPNGText (PNGHandle *png, const char *keyword) if (strncmp (keyword, png->TextChunks[i], 80) == 0) { // Woo! A match was found! - keylen = MIN (80, strlen (keyword) + 1); + keylen = min (80, strlen (keyword) + 1); textlen = strlen (png->TextChunks[i] + keylen) + 1; char *str = new char[textlen]; strcpy (str, png->TextChunks[i] + keylen); @@ -348,7 +359,7 @@ bool M_GetPNGText (PNGHandle *png, const char *keyword, char *buffer, size_t buf if (strncmp (keyword, png->TextChunks[i], 80) == 0) { // Woo! A match was found! - keylen = MIN (80, strlen (keyword) + 1); + keylen = min (80, strlen (keyword) + 1); strncpy (buffer, png->TextChunks[i] + keylen, buffsize); return true; } @@ -499,7 +510,8 @@ bool M_ReadIDAT (FileReader &file, uint8_t *buffer, int width, int height, int p { i += bytesPerRowOut * 2; } - inputLine = (Byte *)alloca (i); + TArray inputArray(i, true); + inputLine = inputArray.data(); adam7buff[0] = inputLine + 4 + bytesPerRowOut; adam7buff[1] = adam7buff[0] + bytesPerRowOut; adam7buff[2] = adam7buff[1] + bytesPerRowOut; @@ -563,7 +575,7 @@ bool M_ReadIDAT (FileReader &file, uint8_t *buffer, int width, int height, int p if (stream.avail_in == 0 && chunklen > 0) { stream.next_in = chunkbuffer; - stream.avail_in = (uInt)file.Read (chunkbuffer, MIN(chunklen,sizeof(chunkbuffer))); + stream.avail_in = (uInt)file.Read (chunkbuffer, min(chunklen,sizeof(chunkbuffer))); chunklen -= stream.avail_in; } @@ -914,7 +926,8 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height temprow[i] = &temprow_storage[temprow_size * i]; } - Byte buffer[PNG_WRITE_SIZE]; + TArray array(PNG_WRITE_SIZE, true); + auto buffer = array.data(); z_stream stream; int err; int y; diff --git a/src/utility/m_png.h b/src/common/textures/m_png.h similarity index 90% rename from src/utility/m_png.h rename to src/common/textures/m_png.h index 10fd4c8e6b2..426e4d9828b 100644 --- a/src/utility/m_png.h +++ b/src/common/textures/m_png.h @@ -34,11 +34,18 @@ */ #include -#include "doomtype.h" -#include "v_video.h" +#include "zstring.h" #include "files.h" +#include "palentry.h" + +// Screenshot buffer image data types +enum ESSType +{ + SS_PAL, + SS_RGB, + SS_BGRA +}; -class FileWriter; // PNG Writing -------------------------------------------------------------- // Start writing an 8-bit palettized PNG file. @@ -73,13 +80,13 @@ struct PNGHandle uint32_t Size; }; - FileReader File; + FileSys::FileReader File; bool bDeleteFilePtr; TArray Chunks; TArray TextChunks; unsigned int ChunkPt; - PNGHandle(FileReader &file); + PNGHandle(FileSys::FileReader &file); ~PNGHandle(); }; @@ -87,7 +94,7 @@ struct PNGHandle // the signature, but also checking for the IEND chunk. CRC checking of // each chunk is not done. If it is valid, you get a PNGHandle to pass to // the following functions. -PNGHandle *M_VerifyPNG (FileReader &file); +PNGHandle *M_VerifyPNG (FileSys::FileReader &file); // Finds a chunk in a PNG file. The file pointer will be positioned at the // beginning of the chunk data, and its length will be returned. A return @@ -106,12 +113,12 @@ bool M_GetPNGText (PNGHandle *png, const char *keyword, char *buffer, size_t buf // The file must be positioned at the start of the first IDAT. It reads // image data into the provided buffer. Returns true on success. -bool M_ReadIDAT (FileReader &file, uint8_t *buffer, int width, int height, int pitch, +bool M_ReadIDAT (FileSys::FileReader &file, uint8_t *buffer, int width, int height, int pitch, uint8_t bitdepth, uint8_t colortype, uint8_t interlace, unsigned int idatlen); -class FTexture; +class FGameTexture; -FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename); +FGameTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename); #endif diff --git a/src/gamedata/textures/multipatchtexturebuilder.cpp b/src/common/textures/multipatchtexturebuilder.cpp similarity index 80% rename from src/gamedata/textures/multipatchtexturebuilder.cpp rename to src/common/textures/multipatchtexturebuilder.cpp index 1f9ea1db2fc..25ea5bbefa8 100644 --- a/src/gamedata/textures/multipatchtexturebuilder.cpp +++ b/src/common/textures/multipatchtexturebuilder.cpp @@ -35,25 +35,17 @@ */ #include -#include "doomtype.h" #include "files.h" -#include "w_wad.h" - -#include "gi.h" -#include "st_start.h" -#include "sc_man.h" -#include "templates.h" -#include "r_data/r_translate.h" +#include "printf.h" +#include "filesystem.h" +#include "engineerrors.h" #include "bitmap.h" -#include "colormatcher.h" -#include "v_palette.h" -#include "v_video.h" -#include "v_text.h" -#include "cmdlib.h" -#include "imagehelpers.h" +#include "textures.h" #include "image.h" #include "formats/multipatchtexture.h" -#include "doomerrors.h" +#include "texturemanager.h" +#include "m_swap.h" + // On the Alpha, accessing the shorts directly if they aren't aligned on a // 4-byte boundary causes unaligned access warnings. Why it does this at @@ -66,7 +58,6 @@ #endif - //-------------------------------------------------------------------------- // // Data structures for the TEXTUREx lumps @@ -94,7 +85,7 @@ struct mappatch_t struct maptexture_t { uint8_t name[8]; - uint16_t Flags; // [RH] Was unused + uint16_t Flags; // [RH] Was unused uint8_t ScaleX; // [RH] Scaling (8 is normal) uint8_t ScaleY; // [RH] Same as above int16_t width; @@ -122,7 +113,7 @@ struct strifemappatch_t struct strifemaptexture_t { uint8_t name[8]; - uint16_t Flags; // [RH] Was unused + uint16_t Flags; // [RH] Was unused uint8_t ScaleX; // [RH] Scaling (8 is normal) uint8_t ScaleY; // [RH] Same as above int16_t width; @@ -146,25 +137,25 @@ struct FPatchLookup void FMultipatchTextureBuilder::MakeTexture(BuildInfo &buildinfo, ETextureType usetype) { - FImageTexture *tex = new FImageTexture(nullptr, buildinfo.Name); - tex->SetUseType(usetype); - tex->bMultiPatch = true; - tex->Width = buildinfo.Width; - tex->Height = buildinfo.Height; - tex->_LeftOffset[0] = buildinfo.LeftOffset[0]; - tex->_LeftOffset[1] = buildinfo.LeftOffset[1]; - tex->_TopOffset[0] = buildinfo.TopOffset[0]; - tex->_TopOffset[1] = buildinfo.TopOffset[1]; - tex->Scale = buildinfo.Scale; - tex->bMasked = true; // we do not really know yet. - tex->bTranslucent = -1; - tex->bWorldPanning = buildinfo.bWorldPanning; - tex->bNoDecals = buildinfo.bNoDecals; - tex->SourceLump = buildinfo.DefinitionLump; - buildinfo.tex = tex; - TexMan.AddTexture(tex); + buildinfo.texture = new FGameTexture(nullptr, buildinfo.Name.GetChars()); + buildinfo.texture->SetUseType(usetype); + buildinfo.texture->SetSize(buildinfo.Width, buildinfo.Height); + buildinfo.texture->SetOffsets(0, buildinfo.LeftOffset[0], buildinfo.TopOffset[0]); // These are needed for construction of other multipatch textures. + buildinfo.texture->SetOffsets(1, buildinfo.LeftOffset[1], buildinfo.TopOffset[1]); + buildinfo.texture->SetScale((float)buildinfo.Scale.X, (float)buildinfo.Scale.Y); + buildinfo.texture->SetWorldPanning(buildinfo.bWorldPanning); + buildinfo.texture->SetNoDecals(buildinfo.bNoDecals); + buildinfo.texture->SetNoTrimming(buildinfo.bNoTrim); + TexMan.AddGameTexture(buildinfo.texture); } +void FMultipatchTextureBuilder::AddImageToTexture(FImageTexture *tex, BuildInfo& buildinfo) +{ + buildinfo.texture->SetBase(tex); + calcShouldUpscale(buildinfo.texture); // calculate this once at insertion +} + + //========================================================================== // // The reader for TEXTUREx @@ -247,7 +238,7 @@ void FMultipatchTextureBuilder::BuildTexture(const void *texdef, FPatchLookup *p } buildinfo.Parts[i].OriginX = LittleShort(mpatch.d->originx); buildinfo.Parts[i].OriginY = LittleShort(mpatch.d->originy); - buildinfo.Parts[i].Image = nullptr; + buildinfo.Parts[i].TexImage = nullptr; buildinfo.Inits[i].TexName = patchlookup[LittleShort(mpatch.d->patch)].Name; buildinfo.Inits[i].UseType = ETextureType::WallPatch; if (strife) @@ -283,7 +274,7 @@ void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsi } { - auto pnames = Wads.OpenLumpReader(patcheslump); + auto pnames = fileSystem.OpenFileReader(patcheslump); numpatches = pnames.ReadUInt32(); // Check whether the amount of names reported is correct. @@ -294,7 +285,7 @@ void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsi } // Check whether the amount of names reported is correct. - int lumplength = Wads.LumpLength(patcheslump); + uint32_t lumplength = (uint32_t)fileSystem.FileLength(patcheslump); if (numpatches > uint32_t((lumplength - 4) / 8)) { Printf("PNAMES lump is shorter than required (%u entries reported but only %d bytes (%d entries) long\n", @@ -306,12 +297,12 @@ void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsi // Catalog the patches these textures use so we know which // textures they represent. patchlookup.Resize(numpatches); - for (uint32_t i = 0; i < numpatches; ++i) + for (uint32_t ii = 0; ii < numpatches; ++ii) { char pname[9]; pnames.Read(pname, 8); pname[8] = '\0'; - patchlookup[i].Name = pname; + patchlookup[ii].Name = pname; } } @@ -365,7 +356,7 @@ void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsi // It still needs to be created in case someone uses it by name. offset = LittleLong(directory[1]); const maptexture_t *tex = (const maptexture_t *)((const uint8_t *)maptex + offset); - FTexture *tex0 = TexMan.ByIndex(0); + auto tex0 = TexMan.GameByIndex(0); tex0->SetSize(SAFESHORT(tex->width), SAFESHORT(tex->height)); } @@ -382,13 +373,13 @@ void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsi int j; for (j = (int)TexMan.NumTextures() - 1; j >= firstdup; --j) { - if (strnicmp(TexMan.ByIndex(j)->GetName(), (const char *)maptex + offset, 8) == 0) + if (strnicmp(TexMan.GameByIndex(j)->GetName().GetChars(), (const char *)maptex + offset, 8) == 0) break; } if (j + 1 == firstdup) { BuildTexture((const uint8_t *)maptex + offset, patchlookup.Data(), numpatches, isStrife, deflumpnum, (i == 1 && texture1) ? ETextureType::FirstDefined : ETextureType::Wall); - StartScreen->Progress(); + progressFunc(); } } } @@ -406,13 +397,13 @@ void FMultipatchTextureBuilder::AddTexturesLumps(int lump1, int lump2, int patch if (lump1 >= 0) { - FMemLump texdir = Wads.ReadLump(lump1); - AddTexturesLump(texdir.GetMem(), Wads.LumpLength(lump1), lump1, patcheslump, firstdup, true); + auto texdir = fileSystem.ReadFile(lump1); + AddTexturesLump(texdir.data(), (int)fileSystem.FileLength(lump1), lump1, patcheslump, firstdup, true); } if (lump2 >= 0) { - FMemLump texdir = Wads.ReadLump(lump2); - AddTexturesLump(texdir.GetMem(), Wads.LumpLength(lump2), lump2, patcheslump, firstdup, false); + auto texdir = fileSystem.ReadFile(lump2); + AddTexturesLump(texdir.data(), (int)fileSystem.FileLength(lump2), lump2, patcheslump, firstdup, false); } } @@ -429,7 +420,7 @@ void FMultipatchTextureBuilder::AddTexturesLumps(int lump1, int lump2, int patch // //========================================================================== -void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPart & part, TexInit &init) +void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPartBuild & part, TexInit &init) { FString patchname; int Mirror = 0; @@ -474,13 +465,13 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar if (part.Translation != NULL) delete part.Translation; part.Translation = NULL; part.Blend = 0; - static const char *maps[] = { "inverse", "gold", "red", "green", "blue", NULL }; + static const char *maps[] = { "gold", "red", "green", "blue", "inverse", NULL }; sc.MustGetString(); match = sc.MatchString(maps); if (match >= 0) { - part.Blend = BLEND_SPECIALCOLORMAP1 + match; + part.Blend = BLEND_SPECIALCOLORMAP1 + match + 1; } else if (sc.Compare("ICE")) { @@ -528,7 +519,7 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar b1 = (float)sc.Float; if (!sc.CheckString(",")) { - part.Blend = AddSpecialColormap(0, 0, 0, r1, g1, b1); + part.Blend = AddSpecialColormap(GPalette.BaseColors, 0, 0, 0, r1, g1, b1); } else { @@ -540,7 +531,7 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar sc.MustGetStringName(","); sc.MustGetFloat(); b2 = (float)sc.Float; - part.Blend = AddSpecialColormap(r1, g1, b1, r2, g2, b2); + part.Blend = AddSpecialColormap(GPalette.BaseColors, r1, g1, b1, r2, g2, b2); } } else if (sc.Compare("Blend")) @@ -553,7 +544,7 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar if (!sc.CheckNumber()) { sc.MustGetString(); - part.Blend = V_GetColor(NULL, sc); + part.Blend = V_GetColor(sc); } else { @@ -583,7 +574,7 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar else if (sc.Compare("alpha")) { sc.MustGetFloat(); - part.Alpha = clamp(int(sc.Float * BLENDUNIT), 0, BLENDUNIT); + part.Alpha = clamp(int(sc.Float * +BLENDUNIT), 0, BLENDUNIT); // bComplex is not set because it is only needed when the style is not OP_COPY. } else if (sc.Compare("style")) @@ -617,12 +608,12 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar // //========================================================================== -void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) +void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType, int deflump) { BuildInfo &buildinfo = BuiltTextures[BuiltTextures.Reserve(1)]; bool bSilent = false; - + buildinfo.textual = true; sc.SetCMode(true); sc.MustGetString(); @@ -648,6 +639,7 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) sc.MustGetStringName(","); sc.MustGetNumber(); buildinfo.Height = sc.Number; + buildinfo.DefinitionLump = deflump; bool offset2set = false; if (sc.CheckString("{")) @@ -679,9 +671,13 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) { buildinfo.bNoDecals = true; } + else if (sc.Compare("NoTrim")) + { + buildinfo.bNoTrim = true; + } else if (sc.Compare("Patch")) { - TexPart part; + TexPartBuild part; TexInit init; ParsePatch(sc, buildinfo, part, init); if (init.TexName.IsNotEmpty()) @@ -693,12 +689,12 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) init.sc = sc; buildinfo.Inits.Push(init); } - part.Image = nullptr; + part.TexImage = nullptr; part.Translation = nullptr; } else if (sc.Compare("Sprite")) { - TexPart part; + TexPartBuild part; TexInit init; ParsePatch(sc, buildinfo, part, init); if (init.TexName.IsNotEmpty()) @@ -710,12 +706,12 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) init.sc = sc; buildinfo.Inits.Push(init); } - part.Image = nullptr; + part.TexImage = nullptr; part.Translation = nullptr; } else if (sc.Compare("Graphic")) { - TexPart part; + TexPartBuild part; TexInit init; ParsePatch(sc, buildinfo, part, init); if (init.TexName.IsNotEmpty()) @@ -727,7 +723,7 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) init.sc = sc; buildinfo.Inits.Push(init); } - part.Image = nullptr; + part.TexImage = nullptr; part.Translation = nullptr; } else if (sc.Compare("Offset")) @@ -772,66 +768,6 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) -//========================================================================== -// -// FMultiPatchTexture :: CheckForHacks -// -//========================================================================== - -void FMultipatchTextureBuilder::CheckForHacks(BuildInfo &buildinfo) -{ - if (buildinfo.Parts.Size() == 0) - { - return; - } - - // Heretic sky textures are marked as only 128 pixels tall, - // even though they are really 200 pixels tall. - if (gameinfo.gametype == GAME_Heretic && - buildinfo.Name.Len() == 4 && - buildinfo.Name[0] == 'S' && - buildinfo.Name[1] == 'K' && - buildinfo.Name[2] == 'Y' && - buildinfo.Name[3] >= '1' && - buildinfo.Name[3] <= '3' && - buildinfo.Height == 128) - { - buildinfo.Height = 200; - buildinfo.tex->SetSize(buildinfo.tex->Width, 200); - return; - } - - // The Doom E1 sky has its patch's y offset at -8 instead of 0. - if (gameinfo.gametype == GAME_Doom && - !(gameinfo.flags & GI_MAPxx) && - buildinfo.Name.Len() == 4 && - buildinfo.Parts.Size() == 1 && - buildinfo.Height == 128 && - buildinfo.Parts[0].OriginY == -8 && - buildinfo.Name[0] == 'S' && - buildinfo.Name[1] == 'K' && - buildinfo.Name[2] == 'Y' && - buildinfo.Name[3] == '1') - { - buildinfo.Parts[0].OriginY = 0; - return; - } - - // BIGDOOR7 in Doom also has patches at y offset -4 instead of 0. - if (gameinfo.gametype == GAME_Doom && - !(gameinfo.flags & GI_MAPxx) && - buildinfo.Name.CompareNoCase("BIGDOOR7") == 0 && - buildinfo.Parts.Size() == 2 && - buildinfo.Height == 128 && - buildinfo.Parts[0].OriginY == -4 && - buildinfo.Parts[1].OriginY == -4) - { - buildinfo.Parts[0].OriginY = 0; - buildinfo.Parts[1].OriginY = 0; - return; - } -} - //========================================================================== // // @@ -842,20 +778,21 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo) { for (unsigned i = 0; i < buildinfo.Inits.Size(); i++) { - FTextureID texno = TexMan.CheckForTexture(buildinfo.Inits[i].TexName, buildinfo.Inits[i].UseType); - if (texno == buildinfo.tex->id) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. + FTextureID texno = TexMan.CheckForTexture(buildinfo.Inits[i].TexName.GetChars(), buildinfo.Inits[i].UseType); + if (texno == buildinfo.texture->GetID()) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. { TArray list; - TexMan.ListTextures(buildinfo.Inits[i].TexName, list, true); - for (int i = list.Size() - 1; i >= 0; i--) + TexMan.ListTextures(buildinfo.Inits[i].TexName.GetChars(), list, true); + for (int ii = list.Size() - 1; ii >= 0; ii--) { - if (list[i] != buildinfo.tex->id && !TexMan.GetTexture(list[i])->bMultiPatch) + auto gtex = TexMan.GetGameTexture(list[ii]); + if (gtex && gtex != buildinfo.texture && gtex->GetTexture() && gtex->GetTexture()->GetImage() && !dynamic_cast(gtex->GetTexture()->GetImage())) { - texno = list[i]; + texno = list[ii]; break; } } - if (texno == buildinfo.tex->id) + if (texno == buildinfo.texture->GetID()) { if (buildinfo.Inits[i].HasLine) buildinfo.Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", buildinfo.Inits[i].TexName.GetChars()); else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", buildinfo.Inits[i].TexName.GetChars()); @@ -878,18 +815,19 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo) } else { - FTexture *tex = TexMan.GetTexture(texno); + FGameTexture *tex = TexMan.GetGameTexture(texno); - if (tex != nullptr && tex->isValid()) + if (tex != nullptr && tex->isValid() && (tex->GetTexture() == nullptr || dynamic_cast(tex->GetTexture()))) { - //We cannot set the image source yet. First all textures need to be resolved. - buildinfo.Inits[i].Texture = tex; - buildinfo.tex->bComplex |= tex->bComplex; - buildinfo.bComplex |= tex->bComplex; + //We cannot set the image texture yet. First all textures need to be resolved. + buildinfo.Inits[i].GameTexture = tex; + bool iscomplex = !!complex.CheckKey(tex); + if (iscomplex) complex.Insert(buildinfo.texture, true); + buildinfo.bComplex |= iscomplex; if (buildinfo.Inits[i].UseOffsets) { - buildinfo.Parts[i].OriginX -= tex->GetLeftOffset(0); - buildinfo.Parts[i].OriginY -= tex->GetTopOffset(0); + buildinfo.Parts[i].OriginX -= tex->GetTexelLeftOffset(0); + buildinfo.Parts[i].OriginY -= tex->GetTexelTopOffset(0); } } else @@ -897,21 +835,21 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo) // The patch is bogus. Remove it. if (buildinfo.Inits[i].HasLine) buildinfo.Inits[i].sc.Message(MSG_WARNING, "Invalid patch '%s' in texture '%s'\n", buildinfo.Inits[i].TexName.GetChars(), buildinfo.Name.GetChars()); else Printf(TEXTCOLOR_YELLOW "Invalid patch '%s' in texture '%s'\n", buildinfo.Inits[i].TexName.GetChars(), buildinfo.Name.GetChars()); + buildinfo.Inits.Delete(i); + buildinfo.Parts.Delete(i); i--; } } } for (unsigned i = 0; i < buildinfo.Inits.Size(); i++) { - if (buildinfo.Inits[i].Texture == nullptr) + if (buildinfo.Inits[i].GameTexture == nullptr) { buildinfo.Inits.Delete(i); buildinfo.Parts.Delete(i); i--; } } - - CheckForHacks(buildinfo); } void FMultipatchTextureBuilder::ResolveAllPatches() @@ -921,7 +859,6 @@ void FMultipatchTextureBuilder::ResolveAllPatches() ResolvePatches(bi); } // Now try to resolve the images. We only can do this at the end when all multipatch textures are set up. - int i = 0; // reverse the list so that the Delete operation in the loop below deletes at the end. // For normal sized lists this is of no real concern, but Total Chaos has over 250000 textures where this becomes a performance issue. @@ -943,12 +880,12 @@ void FMultipatchTextureBuilder::ResolveAllPatches() for (unsigned j = 0; j < buildinfo.Inits.Size(); j++) { - if (buildinfo.Parts[j].Image == nullptr) + if (buildinfo.Parts[j].TexImage == nullptr) { - auto image = buildinfo.Inits[j].Texture->GetImage(); - if (image != nullptr) + auto image = buildinfo.Inits[j].GameTexture->GetTexture(); + if (image && image->GetImage() != nullptr) { - buildinfo.Parts[j].Image = image; + buildinfo.Parts[j].TexImage = static_cast(image); donesomething = true; } else hasEmpty = true; @@ -958,26 +895,28 @@ void FMultipatchTextureBuilder::ResolveAllPatches() { // If this texture is just a wrapper around a single patch, we can simply // use that patch's image directly here. + checkForHacks(buildinfo); bool done = false; if (buildinfo.Parts.Size() == 1) { if (buildinfo.Parts[0].OriginX == 0 && buildinfo.Parts[0].OriginY == 0 && - buildinfo.Parts[0].Image->GetWidth() == buildinfo.Width && - buildinfo.Parts[0].Image->GetHeight() == buildinfo.Height && + buildinfo.Parts[0].TexImage->GetWidth() == buildinfo.Width && + buildinfo.Parts[0].TexImage->GetHeight() == buildinfo.Height && buildinfo.Parts[0].Rotate == 0 && !buildinfo.bComplex) { - buildinfo.tex->SetImage(buildinfo.Parts[0].Image); + AddImageToTexture(buildinfo.Parts[0].TexImage, buildinfo); done = true; } } if (!done) { auto img = new FMultiPatchTexture(buildinfo.Width, buildinfo.Height, buildinfo.Parts, buildinfo.bComplex, buildinfo.textual); - buildinfo.tex->SetImage(img); + auto itex = new FImageTexture(img); + itex->SetSourceLump(buildinfo.DefinitionLump); + AddImageToTexture(itex, buildinfo); } - BuiltTextures.Delete(i); donesomething = true; } @@ -988,7 +927,10 @@ void FMultipatchTextureBuilder::ResolveAllPatches() for (auto &b : BuiltTextures) { Printf("%s\n", b.Name.GetChars()); - b.tex->SetUseType(ETextureType::Null); + // make it hard to find but also ensure that it references valid backing data. + b.texture->SetUseType(ETextureType::Null); + b.texture->SetBase(TexMan.GameByIndex(0)->GetTexture()); + b.texture->SetName(""); } break; } diff --git a/src/common/textures/skyboxtexture.cpp b/src/common/textures/skyboxtexture.cpp new file mode 100644 index 00000000000..2ca476a20e7 --- /dev/null +++ b/src/common/textures/skyboxtexture.cpp @@ -0,0 +1,74 @@ +/* +** skyboxtexture.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2004-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "filesystem.h" +#include "textures.h" +#include "skyboxtexture.h" +#include "bitmap.h" +#include "texturemanager.h" + + + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +FSkyBox::FSkyBox(const char *name) + : FImageTexture(nullptr) +{ + FTextureID texid = TexMan.CheckForTexture(name, ETextureType::Wall); + if (texid.isValid()) + { + previous = TexMan.GetGameTexture(texid); + } + else previous = nullptr; + faces[0]=faces[1]=faces[2]=faces[3]=faces[4]=faces[5] = nullptr; + fliptop = false; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyBox::SetSize() +{ + if (!previous && faces[0]) previous = faces[0]; + if (previous && previous->GetTexture()->GetImage()) + { + SetImage(previous->GetTexture()->GetImage()); + } +} diff --git a/src/common/textures/skyboxtexture.h b/src/common/textures/skyboxtexture.h new file mode 100644 index 00000000000..645e54b9343 --- /dev/null +++ b/src/common/textures/skyboxtexture.h @@ -0,0 +1,42 @@ +#pragma once + +#include "textures.h" + +//----------------------------------------------------------------------------- +// +// Todo: Get rid of this +// The faces can easily be stored in the material layer array +// +//----------------------------------------------------------------------------- + +class FSkyBox : public FImageTexture +{ +public: + + FGameTexture* previous; + FGameTexture* faces[6]; // the faces need to be full materials as they can have all supported effects. + bool fliptop; + + FSkyBox(const char* name); + void SetSize(); + + bool Is3Face() const + { + return faces[5] == nullptr; + } + + bool IsFlipped() const + { + return fliptop; + } + + FGameTexture* GetSkyFace(int num) const + { + return faces[num]; + } + + bool GetSkyFlip() const + { + return fliptop; + } +}; diff --git a/src/common/textures/texmanip.h b/src/common/textures/texmanip.h new file mode 100644 index 00000000000..c5e3a368a43 --- /dev/null +++ b/src/common/textures/texmanip.h @@ -0,0 +1,75 @@ +#pragma once + +#include "palentry.h" + +struct TextureManipulation +{ + enum + { + BlendNone = 0, + BlendAlpha = 1, + BlendScreen = 2, + BlendOverlay = 3, + BlendHardLight = 4, + BlendMask = 7, + InvertBit = 8, + ActiveBit = 16, // Must be set for the shader to do something + }; + PalEntry AddColor; // Alpha contains the blend flags + PalEntry ModulateColor; // Alpha may contain a multiplier to get higher values than 1.0 without promoting this to 4 full floats. + PalEntry BlendColor; + float DesaturationFactor; + + bool CheckIfEnabled() // check if this manipulation is doing something. NoOps do not need to be preserved, unless they override older setttings. + { + if (AddColor != 0 || // this includes a check for the blend mode without which BlendColor is not active + ModulateColor != 0x01ffffff || // 1 in alpha must be the default for a no-op. + DesaturationFactor != 0) + { + AddColor.a |= ActiveBit; // mark as active for the shader's benefit. + return true; + } + return false; + } + + void SetTextureModulateColor(int slot, PalEntry rgb) + { + rgb.a = ModulateColor.a; + ModulateColor = rgb; + } + + void SetTextureModulateScaleFactor(int slot, int fac) + { + ModulateColor.a = (uint8_t)fac; + } + + void SetTextureAdditiveColor(int slot, PalEntry rgb) + { + rgb.a = AddColor.a; + AddColor = rgb; + } + + void SetTextureBlendColor(int slot, PalEntry rgb) + { + BlendColor = rgb; + } + + void SetTextureDesaturationFactor(int slot, double fac) + { + DesaturationFactor = (float)fac; + } + + void SetTextureBlendMode(int slot, int mode) + { + AddColor.a = (AddColor.a & ~TextureManipulation::BlendMask) | (mode & TextureManipulation::BlendMask); + } + + void SetTextureInvert(bool on) + { + AddColor.a |= TextureManipulation::InvertBit; + AddColor.a &= ~TextureManipulation::InvertBit; + } + +}; + + diff --git a/src/common/textures/texture.cpp b/src/common/textures/texture.cpp new file mode 100644 index 00000000000..af335ca31e6 --- /dev/null +++ b/src/common/textures/texture.cpp @@ -0,0 +1,576 @@ +/* +** texture.cpp +** The base texture class +** +**--------------------------------------------------------------------------- +** Copyright 2004-2007 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "printf.h" +#include "files.h" +#include "filesystem.h" + +#include "textures.h" +#include "bitmap.h" +#include "colormatcher.h" +#include "c_dispatch.h" +#include "m_fixed.h" +#include "imagehelpers.h" +#include "image.h" +#include "formats/multipatchtexture.h" +#include "texturemanager.h" +#include "c_cvars.h" +#include "imagehelpers.h" +#include "v_video.h" +#include "v_font.h" + +// Wrappers to keep the definitions of these classes out of here. +IHardwareTexture* CreateHardwareTexture(int numchannels); + +// Make sprite offset adjustment user-configurable per renderer. +int r_spriteadjustSW, r_spriteadjustHW; + +//========================================================================== +// +// +// +//========================================================================== + +FTexture::FTexture (int lumpnum) + : SourceLump(lumpnum), bHasCanvas(false) +{ + bTranslucent = -1; +} + +//=========================================================================== +// +// FTexture::GetBgraBitmap +// +// Default returns just an empty bitmap. This needs to be overridden by +// any subclass that actually does return a software pixel buffer. +// +//=========================================================================== + +FBitmap FTexture::GetBgraBitmap(const PalEntry* remap, int* ptrans) +{ + FBitmap bmp; + bmp.Create(Width, Height); + return bmp; +} + +//==================================================================== +// +// CheckRealHeight +// +// Checks the posts in a texture and returns the lowest row (plus one) +// of the texture that is actually used. +// +//==================================================================== + +int FTexture::CheckRealHeight() +{ + auto pixels = Get8BitPixels(false); + + for(int h = GetHeight()-1; h>= 0; h--) + { + for(int w = 0; w < GetWidth(); w++) + { + if (pixels[h + w * GetHeight()] != 0) + { + return h; + } + } + } + return 0; +} + +//=========================================================================== +// +// Finds gaps in the texture which can be skipped by the renderer +// This was mainly added to speed up one area in E4M6 of 007LTSD +// +//=========================================================================== + +bool FTexture::FindHoles(const unsigned char* buffer, int w, int h) +{ + const unsigned char* li; + int y, x; + int startdraw, lendraw; + int gaps[5][2]; + int gapc = 0; + + + // already done! + if (areacount) return false; + areacount = -1; //whatever happens next, it shouldn't be done twice! + + // large textures and non-images are excluded for performance reasons + if (h>512 || !GetImage()) return false; + + startdraw = -1; + lendraw = 0; + for (y = 0; y < h; y++) + { + li = buffer + w * y * 4 + 3; + + for (x = 0; x < w; x++, li += 4) + { + if (*li != 0) break; + } + + if (x != w) + { + // non - transparent + if (startdraw == -1) + { + startdraw = y; + // merge transparent gaps of less than 16 pixels into the last drawing block + if (gapc && y <= gaps[gapc - 1][0] + gaps[gapc - 1][1] + 16) + { + gapc--; + startdraw = gaps[gapc][0]; + lendraw = y - startdraw; + } + if (gapc == 4) return false; // too many splits - this isn't worth it + } + lendraw++; + } + else if (startdraw != -1) + { + if (lendraw == 1) lendraw = 2; + gaps[gapc][0] = startdraw; + gaps[gapc][1] = lendraw; + gapc++; + + startdraw = -1; + lendraw = 0; + } + } + if (startdraw != -1) + { + gaps[gapc][0] = startdraw; + gaps[gapc][1] = lendraw; + gapc++; + } + if (startdraw == 0 && lendraw == h) return false; // nothing saved so don't create a split list + + if (gapc > 0) + { + FloatRect* rcs = (FloatRect*)ImageArena.Alloc(gapc * sizeof(FloatRect)); // allocate this on the image arena + + for (x = 0; x < gapc; x++) + { + // gaps are stored as texture (u/v) coordinates + rcs[x].width = rcs[x].left = -1.0f; + rcs[x].top = (float)gaps[x][0] / (float)h; + rcs[x].height = (float)gaps[x][1] / (float)h; + } + areas = rcs; + } + else areas = nullptr; + areacount = gapc; + + return true; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void FTexture::CheckTrans(unsigned char* buffer, int size, int trans) +{ + if (bTranslucent == -1) + { + bTranslucent = trans; + if (trans == -1) + { + uint32_t* dwbuf = (uint32_t*)buffer; + for (int i = 0; i < size; i++) + { + uint32_t alpha = dwbuf[i] >> 24; + + if (alpha != 0xff && alpha != 0) + { + bTranslucent = 1; + return; + } + } + bTranslucent = 0; + } + } +} + + +//=========================================================================== +// +// smooth the edges of transparent fields in the texture +// +//=========================================================================== + +#ifdef WORDS_BIGENDIAN +#define MSB 0 +#define SOME_MASK 0xffffff00 +#else +#define MSB 3 +#define SOME_MASK 0x00ffffff +#endif + +#define CHKPIX(ofs) (l1[(ofs)*4+MSB]==255 ? (( ((uint32_t*)l1)[0] = ((uint32_t*)l1)[ofs]&SOME_MASK), trans=true ) : false) + +bool FTexture::SmoothEdges(unsigned char* buffer, int w, int h) +{ + int x, y; + bool trans = buffer[MSB] == 0; // If I set this to false here the code won't detect textures + // that only contain transparent pixels. + bool semitrans = false; + unsigned char* l1; + + if (h <= 1 || w <= 1) return false; // makes (a) no sense and (b) doesn't work with this code! + + l1 = buffer; + + + if (l1[MSB] == 0 && !CHKPIX(1)) CHKPIX(w); + else if (l1[MSB] < 255) semitrans = true; + l1 += 4; + for (x = 1; x < w - 1; x++, l1 += 4) + { + if (l1[MSB] == 0 && !CHKPIX(-1) && !CHKPIX(1)) CHKPIX(w); + else if (l1[MSB] < 255) semitrans = true; + } + if (l1[MSB] == 0 && !CHKPIX(-1)) CHKPIX(w); + else if (l1[MSB] < 255) semitrans = true; + l1 += 4; + + for (y = 1; y < h - 1; y++) + { + if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(1)) CHKPIX(w); + else if (l1[MSB] < 255) semitrans = true; + l1 += 4; + for (x = 1; x < w - 1; x++, l1 += 4) + { + if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(-1) && !CHKPIX(1) && !CHKPIX(-w - 1) && !CHKPIX(-w + 1) && !CHKPIX(w - 1) && !CHKPIX(w + 1)) CHKPIX(w); + else if (l1[MSB] < 255) semitrans = true; + } + if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(-1)) CHKPIX(w); + else if (l1[MSB] < 255) semitrans = true; + l1 += 4; + } + + if (l1[MSB] == 0 && !CHKPIX(-w)) CHKPIX(1); + else if (l1[MSB] < 255) semitrans = true; + l1 += 4; + for (x = 1; x < w - 1; x++, l1 += 4) + { + if (l1[MSB] == 0 && !CHKPIX(-w) && !CHKPIX(-1)) CHKPIX(1); + else if (l1[MSB] < 255) semitrans = true; + } + if (l1[MSB] == 0 && !CHKPIX(-w)) CHKPIX(-1); + else if (l1[MSB] < 255) semitrans = true; + + return trans || semitrans; +} + +//=========================================================================== +// +// Post-process the texture data after the buffer has been created +// +//=========================================================================== + +bool FTexture::ProcessData(unsigned char* buffer, int w, int h, bool ispatch) +{ + if (Masked) + { + Masked = SmoothEdges(buffer, w, h); + if (Masked && !ispatch) FindHoles(buffer, w, h); + } + return true; +} + +//=========================================================================== +// +// Initializes the buffer for the texture data +// +//=========================================================================== + +FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) +{ + FTextureBuffer result; + if (flags & CTF_Indexed) + { + // Indexed textures will never be translated and never be scaled. + int w = GetWidth(), h = GetHeight(); + + auto store = Get8BitPixels(false); + const uint8_t* p = store.Data(); + + result.mBuffer = new uint8_t[w * h]; + result.mWidth = w; + result.mHeight = h; + result.mContentId = 0; + ImageHelpers::FlipNonSquareBlock(result.mBuffer, p, h, w, h); + } + else + { + unsigned char* buffer = nullptr; + int W, H; + int isTransparent = -1; + bool checkonly = !!(flags & CTF_CheckOnly); + + int exx = !!(flags & CTF_Expand); + + W = GetWidth() + 2 * exx; + H = GetHeight() + 2 * exx; + + if (!checkonly) + { + auto remap = translation <= 0 || IsLuminosityTranslation(translation) ? nullptr : GPalette.TranslationToTable(translation); + if (remap && remap->Inactive) remap = nullptr; + if (remap) translation = remap->Index; + + int trans; + auto Pixels = GetBgraBitmap(remap ? remap->Palette : nullptr, &trans); + + if(!exx && Pixels.ClipRect.x == 0 && Pixels.ClipRect.y == 0 && Pixels.ClipRect.width == Pixels.Width && Pixels.ClipRect.height == Pixels.Height && (Pixels.FreeBuffer || !IsLuminosityTranslation(translation))) + { + buffer = Pixels.data; + result.mFreeBuffer = Pixels.FreeBuffer; + Pixels.FreeBuffer = false; + } + else + { + buffer = new unsigned char[W * (H + 1) * 4]; + memset(buffer, 0, W * (H + 1) * 4); + + FBitmap bmp(buffer, W * 4, W, H); + + bmp.Blit(exx, exx, Pixels); + } + + if (IsLuminosityTranslation(translation)) + { + V_ApplyLuminosityTranslation(LuminosityTranslationDesc::fromInt(translation), buffer, W * H); + } + + if (remap == nullptr) + { + CheckTrans(buffer, W * H, trans); + isTransparent = bTranslucent; + } + else + { + isTransparent = 0; + // A translated image is not conclusive for setting the texture's transparency info. + } + } + + if (GetImage()) + { + FContentIdBuilder builder; + builder.id = 0; + builder.imageID = GetImage()->GetId(); + builder.translation = max(0, translation); + builder.expand = exx; + result.mContentId = builder.id; + } + else result.mContentId = 0; // for non-image backed textures this has no meaning so leave it at 0. + + result.mBuffer = buffer; + result.mWidth = W; + result.mHeight = H; + + // Only do postprocessing for image-backed textures. (i.e. not for the burn texture which can also pass through here.) + if (GetImage() && flags & CTF_ProcessData) + { + if (flags & CTF_Upscale) CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly); + + if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false); + } + } + return result; + +} + +//=========================================================================== +// +// Dummy texture for the 0-entry. +// +//=========================================================================== + +bool FTexture::DetermineTranslucency() +{ + // This will calculate all we need, so just discard the result. + CreateTexBuffer(0); + return !!bTranslucent; +} + +//=========================================================================== +// +// the default just returns an empty texture. +// +//=========================================================================== + +TArray FTexture::Get8BitPixels(bool alphatex) +{ + TArray Pixels(Width * Height, true); + memset(Pixels.Data(), 0, Width * Height); + return Pixels; +} + +//=========================================================================== +// +// Finds empty space around the texture. +// Used for sprites that got placed into a huge empty frame. +// +//=========================================================================== + +bool FTexture::TrimBorders(uint16_t* rect) +{ + + auto texbuffer = CreateTexBuffer(0); + int w = texbuffer.mWidth; + int h = texbuffer.mHeight; + auto Buffer = texbuffer.mBuffer; + + if (texbuffer.mBuffer == nullptr) + { + return false; + } + if (w != Width || h != Height) + { + // external Hires replacements cannot be trimmed. + return false; + } + + int size = w * h; + if (size == 1) + { + // nothing to be done here. + rect[0] = 0; + rect[1] = 0; + rect[2] = 1; + rect[3] = 1; + return true; + } + int first, last; + + for (first = 0; first < size; first++) + { + if (Buffer[first * 4 + 3] != 0) break; + } + if (first >= size) + { + // completely empty + rect[0] = 0; + rect[1] = 0; + rect[2] = 1; + rect[3] = 1; + return true; + } + + for (last = size - 1; last >= first; last--) + { + if (Buffer[last * 4 + 3] != 0) break; + } + + rect[1] = first / w; + rect[3] = 1 + last / w - rect[1]; + + rect[0] = 0; + rect[2] = w; + + unsigned char* bufferoff = Buffer + (rect[1] * w * 4); + h = rect[3]; + + for (int x = 0; x < w; x++) + { + for (int y = 0; y < h; y++) + { + if (bufferoff[(x + y * w) * 4 + 3] != 0) goto outl; + } + rect[0]++; + } +outl: + rect[2] -= rect[0]; + + for (int x = w - 1; rect[2] > 1; x--) + { + for (int y = 0; y < h; y++) + { + if (bufferoff[(x + y * w) * 4 + 3] != 0) + { + return true; + } + } + rect[2]--; + } + return true; +} + +//=========================================================================== +// +// Create a hardware texture for this texture image. +// +//=========================================================================== + +IHardwareTexture* FTexture::GetHardwareTexture(int translation, int scaleflags) +{ + int indexed = scaleflags & CTF_Indexed; + if (indexed) translation = -1; + IHardwareTexture* hwtex = SystemTextures.GetHardwareTexture(translation, scaleflags); + if (hwtex == nullptr) + { + hwtex = screen->CreateHardwareTexture(indexed? 1 : 4); + SystemTextures.AddHardwareTexture(translation, scaleflags, hwtex); + } + return hwtex; +} + + +//========================================================================== +// +// this must be copied back to textures.cpp later. +// +//========================================================================== + +FWrapperTexture::FWrapperTexture(int w, int h, int bits) +{ + Width = w; + Height = h; + Format = bits; + //bNoCompress = true; + auto hwtex = screen->CreateHardwareTexture(4); + // todo: Initialize here. + SystemTextures.AddHardwareTexture(0, false, hwtex); +} + diff --git a/src/common/textures/textureid.h b/src/common/textures/textureid.h new file mode 100644 index 00000000000..2d3a226f526 --- /dev/null +++ b/src/common/textures/textureid.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include "tarray.h" + +enum class ETextureType : uint8_t +{ + Any, + Wall, + Flat, + Sprite, + WallPatch, + Build, // no longer used but needs to remain for ZScript + SkinSprite, + Decal, + MiscPatch, + FontChar, + Override, // For patches between TX_START/TX_END + Autopage, // Automap background - used to enable the use of FAutomapTexture + SkinGraphic, + Null, + FirstDefined, + Special, + SWCanvas, +}; + +class FTextureID +{ + friend class FTextureManager; + friend void R_InitSpriteDefs(); + +public: + FTextureID() = default; + FTextureID(std::nullptr_t) : texnum(0) {} + bool isNull() const { return texnum == 0; } + bool isValid() const { return texnum > 0; } + bool Exists() const { return texnum >= 0; } + void SetInvalid() { texnum = -1; } + void SetNull() { texnum = 0; } + bool operator ==(const FTextureID &other) const { return texnum == other.texnum; } + bool operator !=(const FTextureID &other) const { return texnum != other.texnum; } + FTextureID operator +(int offset) const noexcept(true); + int GetIndex() const { return texnum; } // Use this only if you absolutely need the index! + void SetIndex(int index) { texnum = index; } // Use this only if you absolutely need the index! + + // The switch list needs these to sort the switches by texture index + int operator -(FTextureID other) const { return texnum - other.texnum; } + bool operator < (FTextureID other) const { return texnum < other.texnum; } + bool operator > (FTextureID other) const { return texnum > other.texnum; } + +protected: + constexpr FTextureID(int num) : texnum(num) { } +private: + int texnum; +}; + +class FNullTextureID : public FTextureID +{ +public: + constexpr FNullTextureID() : FTextureID(0) {} +}; + +// This is for the script interface which needs to do casts from int to texture. +class FSetTextureID : public FTextureID +{ +public: + constexpr FSetTextureID(int v) : FTextureID(v) {} +}; + +template<> struct THashTraits +{ + + hash_t Hash(const FTextureID key) { return (hash_t)key.GetIndex(); } + + // Compares two keys, returning zero if they are the same. + int Compare(const FTextureID left, const FTextureID right) { return left != right; } +}; diff --git a/src/common/textures/texturemanager.cpp b/src/common/textures/texturemanager.cpp new file mode 100644 index 00000000000..1173f61be05 --- /dev/null +++ b/src/common/textures/texturemanager.cpp @@ -0,0 +1,1680 @@ +/* +** texturemanager.cpp +** The texture manager class +** +**--------------------------------------------------------------------------- +** Copyright 2004-2008 Randy Heit +** Copyright 2006-2008 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "filesystem.h" +#include "printf.h" +#include "c_cvars.h" + +#include "gstrings.h" +#include "textures.h" +#include "texturemanager.h" +#include "c_dispatch.h" +#include "sc_man.h" +#include "image.h" +#include "vectors.h" +#include "animtexture.h" +#include "formats/multipatchtexture.h" +#include "basics.h" +#include "cmdlib.h" + +using namespace FileSys; +FTextureManager TexMan; + + +//========================================================================== +// +// FTextureManager :: FTextureManager +// +//========================================================================== + +FTextureManager::FTextureManager () +{ + memset (HashFirst, -1, sizeof(HashFirst)); + + for (int i = 0; i < 2048; ++i) + { + sintable[i] = short(sin(i*(pi::pi() / 1024)) * 16384); + } +} + +//========================================================================== +// +// FTextureManager :: ~FTextureManager +// +//========================================================================== + +FTextureManager::~FTextureManager () +{ + DeleteAll(); +} + +//========================================================================== +// +// FTextureManager :: DeleteAll +// +//========================================================================== + +void FTextureManager::DeleteAll() +{ + for (unsigned int i = 0; i < Textures.Size(); ++i) + { + delete Textures[i].Texture; + } + FImageSource::ClearImages(); + Textures.Clear(); + Translation.Clear(); + FirstTextureForFile.Clear(); + memset (HashFirst, -1, sizeof(HashFirst)); + DefaultTexture.SetInvalid(); + + BuildTileData.Clear(); + tmanips.Clear(); +} + +//========================================================================== +// +// Flushes all hardware dependent data. +// This must not, under any circumstances, delete the wipe textures, because +// all CCMDs triggering a flush can be executed while a wipe is in progress +// +// This now also deletes the software textures because the software +// renderer can also use the texture scalers and that is the +// main reason to call this outside of the destruction code. +// +//========================================================================== + +void FTextureManager::FlushAll() +{ + for (int i = TexMan.NumTextures() - 1; i >= 0; i--) + { + for (int j = 0; j < 2; j++) + { + Textures[i].Texture->CleanHardwareData(); + delete Textures[i].Texture->GetSoftwareTexture(); + calcShouldUpscale(Textures[i].Texture); + Textures[i].Texture->SetSoftwareTexture(nullptr); + } + } +} + +//========================================================================== +// +// Examines the lump contents to decide what type of texture to create, +// and creates the texture. +// +//========================================================================== + +static FTexture* CreateTextureFromLump(int lumpnum, bool allowflats = false) +{ + if (lumpnum == -1) return nullptr; + + auto image = FImageSource::GetImage(lumpnum, allowflats); + if (image != nullptr) + { + return new FImageTexture(image); + } + return nullptr; +} + +//========================================================================== +// +// FTextureManager :: CheckForTexture +// +//========================================================================== + +FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType usetype, BITFIELD flags) +{ + int i; + int firstfound = -1; + auto firsttype = ETextureType::Null; + + if (name == NULL || name[0] == '\0') + { + return FTextureID(-1); + } + // [RH] Doom counted anything beginning with '-' as "no texture". + // Hopefully nobody made use of that and had textures like "-EMPTY", + // because -NOFLAT- is a valid graphic for ZDoom. + if (name[0] == '-' && name[1] == '\0') + { + return FTextureID(0); + } + + for(i = HashFirst[MakeKey(name) % HASH_SIZE]; i != HASH_END; i = Textures[i].HashNext) + { + auto tex = Textures[i].Texture; + + + if (tex->GetName().CompareNoCase(name) == 0 ) + { + // If we look for short names, we must ignore any long name texture. + if ((flags & TEXMAN_ShortNameOnly) && tex->isFullNameTexture()) + { + continue; + } + auto texUseType = tex->GetUseType(); + // The name matches, so check the texture type + if (usetype == ETextureType::Any) + { + if (flags & TEXMAN_ReturnAll) return FTextureID(i); // user asked to skip all checks, including null textures. + // All NULL textures should actually return 0 + if (texUseType == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0; + if (texUseType == ETextureType::SkinGraphic && !(flags & TEXMAN_AllowSkins)) return 0; + return FTextureID(texUseType==ETextureType::Null ? 0 : i); + } + else if ((flags & TEXMAN_Overridable) && texUseType == ETextureType::Override) + { + return FTextureID(i); + } + else if (texUseType == usetype) + { + return FTextureID(i); + } + else if (texUseType == ETextureType::FirstDefined && usetype == ETextureType::Wall) + { + if (!(flags & TEXMAN_ReturnFirst)) return FTextureID(0); + else return FTextureID(i); + } + else if (texUseType == ETextureType::Null && usetype == ETextureType::Wall) + { + // We found a NULL texture on a wall -> return 0 + return FTextureID(0); + } + else + { + if (firsttype == ETextureType::Null || + (firsttype == ETextureType::MiscPatch && + texUseType != firsttype && + texUseType != ETextureType::Null) + ) + { + firstfound = i; + firsttype = texUseType; + } + } + } + } + + if ((flags & TEXMAN_TryAny) && usetype != ETextureType::Any) + { + // Never return the index of NULL textures. + if (firstfound != -1) + { + if (flags & TEXMAN_ReturnAll) return FTextureID(i); // user asked to skip all checks, including null textures. + if (firsttype == ETextureType::Null) return FTextureID(0); + if (firsttype == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return FTextureID(0); + return FTextureID(firstfound); + } + } + + + if (!(flags & TEXMAN_ShortNameOnly)) + { + // We intentionally only look for textures in subdirectories. + // Any graphic being placed in the zip's root directory can not be found by this. + if (strchr(name, '/') || (flags & TEXMAN_ForceLookup)) + { + FGameTexture *const NO_TEXTURE = (FGameTexture*)-1; // marker for lumps we already checked that do not map to a texture. + int lump = fileSystem.CheckNumForFullName(name); + if (lump >= 0) + { + FGameTexture *tex = GetLinkedTexture(lump); + if (tex == NO_TEXTURE) return FTextureID(-1); + if (tex != NULL) return tex->GetID(); + if (flags & TEXMAN_DontCreate) return FTextureID(-1); // we only want to check, there's no need to create a texture if we don't have one yet. + tex = MakeGameTexture(CreateTextureFromLump(lump), nullptr, ETextureType::Override); + if (tex != NULL) + { + tex->AddAutoMaterials(); + SetLinkedTexture(lump, tex); + return AddGameTexture(tex); + } + else + { + // mark this lump as having no valid texture so that we don't have to retry creating one later. + SetLinkedTexture(lump, NO_TEXTURE); + } + } + } + } + if (!(flags & TEXMAN_NoAlias)) + { + int* alias = aliases.CheckKey(name); + if (alias) return FTextureID(*alias); + } + + return FTextureID(-1); +} + +//========================================================================== +// +// FTextureManager :: ListTextures +// +//========================================================================== + +int FTextureManager::ListTextures (const char *name, TArray &list, bool listall) +{ + int i; + + if (name == NULL || name[0] == '\0') + { + return 0; + } + // [RH] Doom counted anything beginning with '-' as "no texture". + // Hopefully nobody made use of that and had textures like "-EMPTY", + // because -NOFLAT- is a valid graphic for ZDoom. + if (name[0] == '-' && name[1] == '\0') + { + return 0; + } + i = HashFirst[MakeKey (name) % HASH_SIZE]; + + while (i != HASH_END) + { + auto tex = Textures[i].Texture; + + if (tex->GetName().CompareNoCase(name) == 0) + { + auto texUseType = tex->GetUseType(); + // NULL textures must be ignored. + if (texUseType!=ETextureType::Null) + { + unsigned int j = list.Size(); + if (!listall) + { + for (j = 0; j < list.Size(); j++) + { + // Check for overriding definitions from newer WADs + if (Textures[list[j].GetIndex()].Texture->GetUseType() == texUseType) break; + } + } + if (j==list.Size()) list.Push(FTextureID(i)); + } + } + i = Textures[i].HashNext; + } + return list.Size(); +} + +//========================================================================== +// +// FTextureManager :: GetTextures +// +//========================================================================== + +FTextureID FTextureManager::GetTextureID (const char *name, ETextureType usetype, BITFIELD flags) +{ + FTextureID i; + + if (name == NULL || name[0] == 0) + { + return FTextureID(0); + } + else + { + i = CheckForTexture (name, usetype, flags | TEXMAN_TryAny); + } + + if (!i.Exists()) + { + // Use a default texture instead of aborting like Doom did + Printf ("Unknown texture: \"%s\"\n", name); + i = DefaultTexture; + } + return FTextureID(i); +} + +//========================================================================== +// +// FTextureManager :: FindTexture +// +//========================================================================== + +FGameTexture *FTextureManager::FindGameTexture(const char *texname, ETextureType usetype, BITFIELD flags) +{ + FTextureID texnum = CheckForTexture (texname, usetype, flags); + return GetGameTexture(texnum.GetIndex()); +} + +//========================================================================== +// +// FTextureManager :: OkForLocalization +// +//========================================================================== + +bool FTextureManager::OkForLocalization(FTextureID texnum, const char *substitute, int locmode) +{ + uint32_t langtable = 0; + if (*substitute == '$') substitute = GStrings.CheckString(substitute+1, &langtable); + else return true; // String literals from the source data should never override graphics from the same definition. + if (substitute == nullptr) return true; // The text does not exist. + + // Modes 2, 3 and 4 must not replace localized textures. + int localizedTex = ResolveLocalizedTexture(texnum.GetIndex()); + if (localizedTex != texnum.GetIndex()) return true; // Do not substitute a localized variant of the graphics patch. + + // For mode 4 we are done now. + if (locmode == 4) return false; + + // Mode 2 and 3 must reject any text replacement from the default language tables. + if ((langtable & MAKE_ID(255,0,0,0)) == MAKE_ID('*', 0, 0, 0)) return true; // Do not substitute if the string comes from the default table. + if (locmode == 2) return false; + + // Mode 3 must also reject substitutions for non-IWAD content. + int file = fileSystem.GetFileContainer(Textures[texnum.GetIndex()].Texture->GetSourceLump()); + if (file > fileSystem.GetMaxIwadNum()) return true; + + return false; +} + +//========================================================================== +// +// FTextureManager :: AddTexture +// +//========================================================================== + +FTextureID FTextureManager::AddGameTexture (FGameTexture *texture, bool addtohash) +{ + int bucket; + int hash; + + if (texture == NULL) return FTextureID(-1); + + if (texture->GetTexture()) + { + // Later textures take precedence over earlier ones + calcShouldUpscale(texture); // calculate this once at insertion + } + + // Textures without name can't be looked for + if (addtohash && texture->GetName().IsNotEmpty()) + { + bucket = int(MakeKey (texture->GetName().GetChars()) % HASH_SIZE); + hash = HashFirst[bucket]; + } + else + { + bucket = -1; + hash = -1; + } + + TextureDescriptor hasher = { texture, -1, -1, -1, hash }; + int trans = Textures.Push (hasher); + Translation.Push (trans); + if (bucket >= 0) HashFirst[bucket] = trans; + auto id = FTextureID(trans); + texture->SetID(id); + return id; +} + +//========================================================================== +// +// FTextureManager :: CreateTexture +// +// Calls FTexture::CreateTexture and adds the texture to the manager. +// +//========================================================================== + +FTextureID FTextureManager::CreateTexture (int lumpnum, ETextureType usetype) +{ + if (lumpnum != -1) + { + FString str; + if (!usefullnames) + str = fileSystem.GetFileShortName(lumpnum); + else + { + auto fn = fileSystem.GetFileFullName(lumpnum); + str = ExtractFileBase(fn); + } + auto out = MakeGameTexture(CreateTextureFromLump(lumpnum, usetype == ETextureType::Flat), str.GetChars(), usetype); + + if (out != NULL) + { + if (usetype == ETextureType::Flat) + { + int w = out->GetTexelWidth(); + int h = out->GetTexelHeight(); + + // Auto-scale flats with dimensions 128x128 and 256x256. + // In hindsight, a bad idea, but RandomLag made it sound better than it really is. + // Now we're stuck with this stupid behaviour. + if (w == 128 && h == 128) + { + out->SetScale(2, 2); + out->SetWorldPanning(true); + } + else if (w == 256 && h == 256) + { + out->SetScale(4, 4); + out->SetWorldPanning(true); + } + } + + return AddGameTexture(out); + } + else + { + Printf (TEXTCOLOR_ORANGE "Invalid data encountered for texture %s\n", fileSystem.GetFileFullPath(lumpnum).c_str()); + return FTextureID(-1); + } + } + return FTextureID(-1); +} + +//========================================================================== +// +// FTextureManager :: ReplaceTexture +// +//========================================================================== + +void FTextureManager::ReplaceTexture (FTextureID texid, FGameTexture *newtexture, bool free) +{ + int index = texid.GetIndex(); + if (unsigned(index) >= Textures.Size()) + return; + + if (newtexture->GetTexture()) + { + calcShouldUpscale(newtexture); // calculate this once at insertion + } + + auto oldtexture = Textures[index].Texture; + + newtexture->SetName(oldtexture->GetName().GetChars()); + newtexture->SetUseType(oldtexture->GetUseType()); + Textures[index].Texture = newtexture; + newtexture->SetID(oldtexture->GetID()); + oldtexture->SetName(""); + AddGameTexture(oldtexture); +} + +//========================================================================== +// +// FTextureManager :: AreTexturesCompatible +// +// Checks if 2 textures are compatible for a ranged animation +// +//========================================================================== + +bool FTextureManager::AreTexturesCompatible (FTextureID picnum1, FTextureID picnum2) +{ + int index1 = picnum1.GetIndex(); + int index2 = picnum2.GetIndex(); + if (unsigned(index1) >= Textures.Size() || unsigned(index2) >= Textures.Size()) + return false; + + auto texture1 = Textures[index1].Texture; + auto texture2 = Textures[index2].Texture; + + // both textures must be the same type. + if (texture1 == NULL || texture2 == NULL || texture1->GetUseType() != texture2->GetUseType()) + return false; + + // both textures must be from the same file + for(unsigned i = 0; i < FirstTextureForFile.Size() - 1; i++) + { + if (index1 >= FirstTextureForFile[i] && index1 < FirstTextureForFile[i+1]) + { + return (index2 >= FirstTextureForFile[i] && index2 < FirstTextureForFile[i+1]); + } + } + return false; +} + + +//========================================================================== +// +// FTextureManager :: AddGroup +// +//========================================================================== + +void FTextureManager::AddGroup(int wadnum, int ns, ETextureType usetype) +{ + int firsttx = fileSystem.GetFirstEntry(wadnum); + int lasttx = fileSystem.GetLastEntry(wadnum); + + if (!usefullnames) + { + // Go from first to last so that ANIMDEFS work as expected. However, + // to avoid duplicates (and to keep earlier entries from overriding + // later ones), the texture is only inserted if it is the one returned + // by doing a check by name in the list of wads. + + for (; firsttx <= lasttx; ++firsttx) + { + auto Name = fileSystem.GetFileShortName(firsttx); + if (fileSystem.GetFileNamespace(firsttx) == ns) + { + if (fileSystem.CheckNumForName(Name, ns) == firsttx) + { + CreateTexture(firsttx, usetype); + } + progressFunc(); + } + else if (ns == ns_flats && fileSystem.GetFileFlags(firsttx) & RESFF_MAYBEFLAT) + { + if (fileSystem.CheckNumForName(Name, ns) < firsttx) + { + CreateTexture(firsttx, usetype); + } + progressFunc(); + } + } + } + else + { + // The duplicate check does not work with this (yet.) + for (; firsttx <= lasttx; ++firsttx) + { + if (fileSystem.GetFileNamespace(firsttx) == ns) + { + CreateTexture(firsttx, usetype); + } + } + } +} + +//========================================================================== +// +// Adds all hires texture definitions. +// +//========================================================================== + +void FTextureManager::AddHiresTextures (int wadnum) +{ + int firsttx = fileSystem.GetFirstEntry(wadnum); + int lasttx = fileSystem.GetLastEntry(wadnum); + + TArray tlist; + + if (firsttx == -1 || lasttx == -1) + { + return; + } + + for (;firsttx <= lasttx; ++firsttx) + { + if (fileSystem.GetFileNamespace(firsttx) == ns_hires) + { + auto Name = fileSystem.GetFileShortName(firsttx); + + if (fileSystem.CheckNumForName (Name, ns_hires) == firsttx) + { + tlist.Clear(); + int amount = ListTextures(Name, tlist); + if (amount == 0) + { + // A texture with this name does not yet exist + auto newtex = MakeGameTexture(CreateTextureFromLump(firsttx), Name, ETextureType::Override); + if (newtex != NULL) + { + AddGameTexture(newtex); + } + } + else + { + for(unsigned int i = 0; i < tlist.Size(); i++) + { + FTexture * newtex = CreateTextureFromLump(firsttx); + if (newtex != NULL) + { + auto oldtex = Textures[tlist[i].GetIndex()].Texture; + + // Replace the entire texture and adjust the scaling and offset factors. + auto gtex = MakeGameTexture(newtex, nullptr, ETextureType::Override); + gtex->SetWorldPanning(true); + gtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight()); + double xscale1 = oldtex->GetTexelLeftOffset(0) * gtex->GetScaleX() / oldtex->GetScaleX(); + double xscale2 = oldtex->GetTexelLeftOffset(1) * gtex->GetScaleX() / oldtex->GetScaleX(); + double yscale1 = oldtex->GetTexelTopOffset(0) * gtex->GetScaleY() / oldtex->GetScaleY(); + double yscale2 = oldtex->GetTexelTopOffset(1) * gtex->GetScaleY() / oldtex->GetScaleY(); + gtex->SetOffsets(0, xs_RoundToInt(xscale1), xs_RoundToInt(yscale1)); + gtex->SetOffsets(1, xs_RoundToInt(xscale2), xs_RoundToInt(yscale2)); + ReplaceTexture(tlist[i], gtex, true); + } + } + } + progressFunc(); + } + } + } +} + +//========================================================================== +// +// Loads the HIRESTEX lumps +// +//========================================================================== + +void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname, FMultipatchTextureBuilder &build) +{ + int texLump, lastLump; + + lastLump = 0; + + while ((texLump = fileSystem.FindLump(lumpname, &lastLump)) != -1) + { + if (fileSystem.GetFileContainer(texLump) == wadnum) + { + ParseTextureDef(texLump, build); + } + } +} + +void FTextureManager::ParseTextureDef(int lump, FMultipatchTextureBuilder &build) +{ + TArray tlist; + + FScanner sc(lump); + while (sc.GetString()) + { + if (sc.Compare("remap")) // remap an existing texture + { + sc.MustGetString(); + + // allow selection by type + int mode; + ETextureType type; + if (sc.Compare("wall")) type=ETextureType::Wall, mode=FTextureManager::TEXMAN_Overridable; + else if (sc.Compare("flat")) type=ETextureType::Flat, mode=FTextureManager::TEXMAN_Overridable; + else if (sc.Compare("sprite")) type=ETextureType::Sprite, mode=0; + else type = ETextureType::Any, mode = 0; + + if (type != ETextureType::Any) sc.MustGetString(); + + sc.String[8]=0; + + tlist.Clear(); + ListTextures(sc.String, tlist); + FName texname = sc.String; + + sc.MustGetString(); + int lumpnum = fileSystem.CheckNumForFullName(sc.String, true, ns_patches); + if (lumpnum == -1) lumpnum = fileSystem.CheckNumForFullName(sc.String, true, ns_graphics); + + if (tlist.Size() == 0) + { + Printf("Attempting to remap non-existent texture %s to %s\n", + texname.GetChars(), sc.String); + } + else if (lumpnum == -1) + { + Printf("Attempting to remap texture %s to non-existent lump %s\n", + texname.GetChars(), sc.String); + } + else + { + for(unsigned int i = 0; i < tlist.Size(); i++) + { + auto oldtex = Textures[tlist[i].GetIndex()].Texture; + int sl; + + // only replace matching types. For sprites also replace any MiscPatches + // based on the same lump. These can be created for icons. + if (oldtex->GetUseType() == type || type == ETextureType::Any || + (mode == TEXMAN_Overridable && oldtex->GetUseType() == ETextureType::Override) || + (type == ETextureType::Sprite && oldtex->GetUseType() == ETextureType::MiscPatch && + (sl=oldtex->GetSourceLump()) >= 0 && fileSystem.GetFileNamespace(sl) == ns_sprites) + ) + { + FTexture * newtex = CreateTextureFromLump(lumpnum); + if (newtex != NULL) + { + // Replace the entire texture and adjust the scaling and offset factors. + auto gtex = MakeGameTexture(newtex, nullptr, ETextureType::Override); + gtex->SetWorldPanning(true); + gtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight()); + double xscale1 = oldtex->GetTexelLeftOffset(0) * gtex->GetScaleX() / oldtex->GetScaleX(); + double xscale2 = oldtex->GetTexelLeftOffset(1) * gtex->GetScaleX() / oldtex->GetScaleX(); + double yscale1 = oldtex->GetTexelTopOffset(0) * gtex->GetScaleY() / oldtex->GetScaleY(); + double yscale2 = oldtex->GetTexelTopOffset(1) * gtex->GetScaleY() / oldtex->GetScaleY(); + gtex->SetOffsets(0, xs_RoundToInt(xscale1), xs_RoundToInt(yscale1)); + gtex->SetOffsets(1, xs_RoundToInt(xscale2), xs_RoundToInt(yscale2)); + ReplaceTexture(tlist[i], gtex, true); + } + } + } + } + } + else if (sc.Compare("define")) // define a new "fake" texture + { + sc.GetString(); + + FString base = ExtractFileBase(sc.String, false); + if (!base.IsEmpty()) + { + FString src = base.Left(8); + + int lumpnum = fileSystem.CheckNumForFullName(sc.String, true, ns_patches); + if (lumpnum == -1) lumpnum = fileSystem.CheckNumForFullName(sc.String, true, ns_graphics); + + sc.GetString(); + bool is32bit = !!sc.Compare("force32bit"); + if (!is32bit) sc.UnGet(); + + sc.MustGetNumber(); + int width = sc.Number; + sc.MustGetNumber(); + int height = sc.Number; + + if (lumpnum>=0) + { + auto newtex = MakeGameTexture(CreateTextureFromLump(lumpnum), src.GetChars(), ETextureType::Override); + + if (newtex != NULL) + { + // Replace the entire texture and adjust the scaling and offset factors. + newtex->SetWorldPanning(true); + newtex->SetDisplaySize((float)width, (float)height); + + FTextureID oldtex = TexMan.CheckForTexture(src.GetChars(), ETextureType::MiscPatch); + if (oldtex.isValid()) + { + ReplaceTexture(oldtex, newtex, true); + newtex->SetUseType(ETextureType::Override); + } + else AddGameTexture(newtex); + } + } + } + //else Printf("Unable to define hires texture '%s'\n", tex->Name); + } + else if (sc.Compare("notrim")) + { + sc.MustGetString(); + + FTextureID id = TexMan.CheckForTexture(sc.String, ETextureType::Sprite); + if (id.isValid()) + { + FGameTexture *tex = TexMan.GetGameTexture(id); + + if (tex) tex->SetNoTrimming(true); + else sc.ScriptError("NoTrim: %s not found", sc.String); + } + else + sc.ScriptError("NoTrim: %s is not a sprite", sc.String); + + } + else if (sc.Compare("texture")) + { + build.ParseTexture(sc, ETextureType::Override, lump); + } + else if (sc.Compare("sprite")) + { + build.ParseTexture(sc, ETextureType::Sprite, lump); + } + else if (sc.Compare("walltexture")) + { + build.ParseTexture(sc, ETextureType::Wall, lump); + } + else if (sc.Compare("flat")) + { + build.ParseTexture(sc, ETextureType::Flat, lump); + } + else if (sc.Compare("graphic")) + { + build.ParseTexture(sc, ETextureType::MiscPatch, lump); + } + else if (sc.Compare("#include")) + { + sc.MustGetString(); + + // This is not using sc.Open because it can print a more useful error message when done here + int includelump = fileSystem.CheckNumForFullName(sc.String, true); + if (includelump == -1) + { + sc.ScriptError("Lump '%s' not found", sc.String); + } + else + { + ParseTextureDef(includelump, build); + } + } + else + { + sc.ScriptError("Texture definition expected, found '%s'", sc.String); + } + } +} + +//========================================================================== +// +// FTextureManager :: AddPatches +// +//========================================================================== + +void FTextureManager::AddPatches (int lumpnum) +{ + auto file = fileSystem.ReopenFileReader (lumpnum, true); + uint32_t numpatches, i; + char name[9]; + + numpatches = file.ReadUInt32(); + name[8] = '\0'; + + for (i = 0; i < numpatches; ++i) + { + file.Read (name, 8); + + if (CheckForTexture (name, ETextureType::WallPatch, 0) == -1) + { + CreateTexture (fileSystem.CheckNumForName (name, ns_patches), ETextureType::WallPatch); + } + progressFunc(); + } +} + + +//========================================================================== +// +// FTextureManager :: LoadTexturesX +// +// Initializes the texture list with the textures from the world map. +// +//========================================================================== + +void FTextureManager::LoadTextureX(int wadnum, FMultipatchTextureBuilder &build) +{ + // Use the most recent PNAMES for this WAD. + // Multiple PNAMES in a WAD will be ignored. + int pnames = fileSystem.CheckNumForName("PNAMES", ns_global, wadnum, false); + + if (pnames < 0) + { + // should never happen except for zdoom.pk3 + return; + } + + // Only add the patches if the PNAMES come from the current file + // Otherwise they have already been processed. + if (fileSystem.GetFileContainer(pnames) == wadnum) TexMan.AddPatches (pnames); + + int texlump1 = fileSystem.CheckNumForName ("TEXTURE1", ns_global, wadnum); + int texlump2 = fileSystem.CheckNumForName ("TEXTURE2", ns_global, wadnum); + build.AddTexturesLumps (texlump1, texlump2, pnames); +} + +//========================================================================== +// +// FTextureManager :: AddTexturesForWad +// +//========================================================================== + +void FTextureManager::AddTexturesForWad(int wadnum, FMultipatchTextureBuilder &build) +{ + int firsttexture = Textures.Size(); + bool iwad = wadnum >= fileSystem.GetIwadNum() && wadnum <= fileSystem.GetMaxIwadNum(); + + FirstTextureForFile.Push(firsttexture); + + // First step: Load sprites + AddGroup(wadnum, ns_sprites, ETextureType::Sprite); + + // When loading a Zip, all graphics in the patches/ directory should be + // added as well. + AddGroup(wadnum, ns_patches, ETextureType::WallPatch); + + // Second step: TEXTUREx lumps + LoadTextureX(wadnum, build); + + // Third step: Flats + AddGroup(wadnum, ns_flats, ETextureType::Flat); + + // Fourth step: Textures (TX_) + AddGroup(wadnum, ns_newtextures, ETextureType::Override); + + // Sixth step: Try to find any lump in the WAD that may be a texture and load as a TEX_MiscPatch + int firsttx = fileSystem.GetFirstEntry(wadnum); + int lasttx = fileSystem.GetLastEntry(wadnum); + + for (int i= firsttx; i <= lasttx; i++) + { + bool skin = false; + auto Name = fileSystem.GetFileShortName(i); + + // Ignore anything not in the global namespace + int ns = fileSystem.GetFileNamespace(i); + if (ns == ns_global) + { + // In Zips all graphics must be in a separate namespace. + if (fileSystem.GetFileFlags(i) & RESFF_FULLPATH) continue; + + // Ignore lumps with empty names. + if (fileSystem.CheckFileName(i, "")) continue; + + // Ignore anything belonging to a map + if (fileSystem.CheckFileName(i, "THINGS")) continue; + if (fileSystem.CheckFileName(i, "LINEDEFS")) continue; + if (fileSystem.CheckFileName(i, "SIDEDEFS")) continue; + if (fileSystem.CheckFileName(i, "VERTEXES")) continue; + if (fileSystem.CheckFileName(i, "SEGS")) continue; + if (fileSystem.CheckFileName(i, "SSECTORS")) continue; + if (fileSystem.CheckFileName(i, "NODES")) continue; + if (fileSystem.CheckFileName(i, "SECTORS")) continue; + if (fileSystem.CheckFileName(i, "REJECT")) continue; + if (fileSystem.CheckFileName(i, "BLOCKMAP")) continue; + if (fileSystem.CheckFileName(i, "BEHAVIOR")) continue; + + bool force = false; + // Don't bother looking at this lump if something later overrides it. + if (fileSystem.CheckNumForName(Name, ns_graphics) != i) + { + if (iwad) + { + // We need to make an exception for font characters of the SmallFont coming from the IWAD to be able to construct the original font. + if (strncmp(Name, "STCFN", 5) != 0 && strncmp(Name, "FONTA", 5) != 0) continue; + force = true; + } + else continue; + } + + // skip this if it has already been added as a wall patch. + if (!force && CheckForTexture(Name, ETextureType::WallPatch, 0).Exists()) continue; + } + else if (ns == ns_graphics) + { + if (fileSystem.CheckNumForName(Name, ns_graphics) != i) + { + if (iwad) + { + // We need to make an exception for font characters of the SmallFont coming from the IWAD to be able to construct the original font. + if (strncmp(Name, "STCFN", 5) != 0 && strncmp(Name, "FONTA", 5) != 0) continue; + } + else continue; + } + } + else if (ns >= ns_firstskin) + { + // Don't bother looking this lump if something later overrides it. + if (fileSystem.CheckNumForName(Name, ns) != i) continue; + skin = true; + } + else continue; + + // Try to create a texture from this lump and add it. + // Unfortunately we have to look at everything that comes through here... + auto out = MakeGameTexture(CreateTextureFromLump(i), Name, skin ? ETextureType::SkinGraphic : ETextureType::MiscPatch); + + if (out != NULL) + { + AddGameTexture (out); + } + } + + // Check for text based texture definitions + LoadTextureDefs(wadnum, "TEXTURES", build); + LoadTextureDefs(wadnum, "HIRESTEX", build); + + // Seventh step: Check for hires replacements. + AddHiresTextures(wadnum); + + SortTexturesByType(firsttexture, Textures.Size()); +} + +//========================================================================== +// +// FTextureManager :: SortTexturesByType +// sorts newly added textures by UseType so that anything defined +// in TEXTURES and HIRESTEX gets in its proper place. +// +//========================================================================== + +void FTextureManager::SortTexturesByType(int start, int end) +{ + TArray newtextures; + + // First unlink all newly added textures from the hash chain + for (int i = 0; i < HASH_SIZE; i++) + { + while (HashFirst[i] >= start && HashFirst[i] != HASH_END) + { + HashFirst[i] = Textures[HashFirst[i]].HashNext; + } + } + newtextures.Resize(end-start); + for(int i=start; iGetUseType() == texturetypes[i]) + { + AddGameTexture(newtextures[j]); + newtextures[j] = NULL; + } + } + } + // This should never happen. All other UseTypes are only used outside + for(unsigned j = 0; jGetName().GetChars()); + AddGameTexture(newtextures[j]); + } + } +} + +//========================================================================== +// +// FTextureManager :: AddLocalizedVariants +// +//========================================================================== + +void FTextureManager::AddLocalizedVariants() +{ + std::vector content; + fileSystem.GetFilesInFolder("localized/textures/", content, false); + for (auto &entry : content) + { + FString name = entry.name; + auto tokens = name.Split(".", FString::TOK_SKIPEMPTY); + if (tokens.Size() == 2) + { + auto ext = tokens[1]; + // Do not interpret common extensions for images as language IDs. + if (ext.CompareNoCase("png") == 0 || ext.CompareNoCase("jpg") == 0 || ext.CompareNoCase("gfx") == 0 || ext.CompareNoCase("tga") == 0 || ext.CompareNoCase("lmp") == 0) + { + Printf("%s contains no language IDs and will be ignored\n", entry.name); + continue; + } + } + if (tokens.Size() >= 2) + { + FString base = ExtractFileBase(tokens[0].GetChars()); + FTextureID origTex = CheckForTexture(base.GetChars(), ETextureType::MiscPatch); + if (origTex.isValid()) + { + FTextureID tex = CheckForTexture(entry.name, ETextureType::MiscPatch); + if (tex.isValid()) + { + auto otex = GetGameTexture(origTex); + auto ntex = GetGameTexture(tex); + if (otex->GetDisplayWidth() != ntex->GetDisplayWidth() || otex->GetDisplayHeight() != ntex->GetDisplayHeight()) + { + Printf("Localized texture %s must be the same size as the one it replaces\n", entry.name); + } + else + { + tokens[1].ToLower(); + auto langids = tokens[1].Split("-", FString::TOK_SKIPEMPTY); + for (auto &lang : langids) + { + if (lang.Len() == 2 || lang.Len() == 3) + { + uint32_t langid = MAKE_ID(lang[0], lang[1], lang[2], 0); + uint64_t comboid = (uint64_t(langid) << 32) | origTex.GetIndex(); + LocalizedTextures.Insert(comboid, tex.GetIndex()); + Textures[origTex.GetIndex()].Flags |= TEXFLAG_HASLOCALIZATION; + } + else + { + Printf("Invalid language ID in texture %s\n", entry.name); + } + } + } + } + else + { + Printf("%s is not a texture\n", entry.name); + } + } + else + { + Printf("Unknown texture %s for localized variant %s\n", tokens[0].GetChars(), entry.name); + } + } + else + { + Printf("%s contains no language IDs and will be ignored\n", entry.name); + } + + } +} + +//========================================================================== +// +// FTextureManager :: Init +// +//========================================================================== +FGameTexture *CreateShaderTexture(bool, bool); +FImageSource* CreateEmptyTexture(); + +void FTextureManager::Init() +{ + DeleteAll(); + + // Add all the static content + auto nulltex = MakeGameTexture(new FImageTexture(CreateEmptyTexture()), nullptr, ETextureType::Null); + AddGameTexture(nulltex); + + // This is for binding to unused texture units, because accessing an unbound texture unit is undefined. It's a one pixel empty texture. + auto emptytex = MakeGameTexture(new FImageTexture(CreateEmptyTexture()), nullptr, ETextureType::Override); + emptytex->SetSize(1, 1); + AddGameTexture(emptytex); + + // some special textures used in the game. + AddGameTexture(CreateShaderTexture(false, false)); + AddGameTexture(CreateShaderTexture(false, true)); + AddGameTexture(CreateShaderTexture(true, false)); + AddGameTexture(CreateShaderTexture(true, true)); + // Add two animtexture entries so that movie playback can call functions using texture IDs. + auto mt = MakeGameTexture(new AnimTexture(), "AnimTextureFrame1", ETextureType::Override); + mt->SetUpscaleFlag(false, true); + AddGameTexture(mt); + mt = MakeGameTexture(new AnimTexture(), "AnimTextureFrame2", ETextureType::Override); + mt->SetUpscaleFlag(false, true); + AddGameTexture(mt); +} + +void FTextureManager::AddTextures(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo&), void (*customtexturehandler)()) +{ + progressFunc = progressFunc_; + //if (BuildTileFiles.Size() == 0) CountBuildTiles (); + + int wadcnt = fileSystem.GetNumWads(); + + FMultipatchTextureBuilder build(*this, progressFunc_, checkForHacks); + + for(int i = 0; i< wadcnt; i++) + { + AddTexturesForWad(i, build); + } + build.ResolveAllPatches(); + + // Add one marker so that the last WAD is easier to handle and treat + // custom textures as a completely separate block. + FirstTextureForFile.Push(Textures.Size()); + if (customtexturehandler) customtexturehandler(); + FirstTextureForFile.Push(Textures.Size()); + + DefaultTexture = CheckForTexture ("-NOFLAT-", ETextureType::Override, 0); + + InitPalettedVersions(); + AdjustSpriteOffsets(); + // Add auto materials to each texture after everything has been set up. + // Textures array can be reallocated in process, so ranged for loop is not suitable. + // There is no need to process discovered material textures here, + // CheckForTexture() did this already. + for (unsigned int i = 0, count = Textures.Size(); i < count; ++i) + { + Textures[i].Texture->AddAutoMaterials(); + } + + glPart2 = TexMan.CheckForTexture("glstuff/glpart2.png", ETextureType::MiscPatch); + glPart = TexMan.CheckForTexture("glstuff/glpart.png", ETextureType::MiscPatch); + mirrorTexture = TexMan.CheckForTexture("glstuff/mirror.png", ETextureType::MiscPatch); + AddLocalizedVariants(); + + // Make sure all ID's are correct by resetting them here to the proper index. + for (unsigned int i = 0, count = Textures.Size(); i < count; ++i) + { + Textures[i].Texture->SetID(i); + } + +} + +//========================================================================== +// +// FTextureManager :: InitPalettedVersions +// +//========================================================================== + +void FTextureManager::InitPalettedVersions() +{ + int lump, lastlump = 0; + + while ((lump = fileSystem.FindLump("PALVERS", &lastlump)) != -1) + { + FScanner sc(lump); + + while (sc.GetString()) + { + FTextureID pic1 = CheckForTexture(sc.String, ETextureType::Any); + if (!pic1.isValid()) + { + sc.ScriptMessage("Unknown texture %s to replace", sc.String); + } + sc.MustGetString(); + FTextureID pic2 = CheckForTexture(sc.String, ETextureType::Any); + if (!pic2.isValid()) + { + sc.ScriptMessage("Unknown texture %s to use as paletted replacement", sc.String); + } + if (pic1.isValid() && pic2.isValid()) + { + Textures[pic1.GetIndex()].Paletted = pic2.GetIndex(); + } + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FTextureID FTextureManager::GetRawTexture(FTextureID texid, bool dontlookup) +{ + int texidx = texid.GetIndex(); + if ((unsigned)texidx >= Textures.Size()) return texid; + if (Textures[texidx].RawTexture != -1) return FSetTextureID(Textures[texidx].RawTexture); + if (dontlookup) return texid; + + // Reject anything that cannot have been a front layer for the sky in original Hexen, i.e. it needs to be an unscaled wall texture only using Doom patches. + auto tex = Textures[texidx].Texture; + auto ttex = tex->GetTexture(); + auto image = ttex->GetImage(); + // Reject anything that cannot have been a single-patch multipatch texture in vanilla. + if (image == nullptr || image->IsRawCompatible() || tex->GetUseType() != ETextureType::Wall || ttex->GetWidth() != tex->GetDisplayWidth() || + ttex->GetHeight() != tex->GetDisplayHeight()) + { + Textures[texidx].RawTexture = texidx; + return texid; + } + + // Let the hackery begin + auto mptimage = static_cast(image); + auto source = mptimage->GetImageForPart(0); + + // Size must match for this to work as intended + if (source->GetWidth() != ttex->GetWidth() || source->GetHeight() != ttex->GetHeight()) + { + Textures[texidx].RawTexture = texidx; + return texid; + } + + // Todo: later this can just link to the already existing texture for this source graphic, once it can be retrieved through the image's SourceLump index + auto RawTexture = MakeGameTexture(new FImageTexture(source), nullptr, ETextureType::Wall); + texid = TexMan.AddGameTexture(RawTexture); + Textures[texidx].RawTexture = texid.GetIndex(); + Textures[texid.GetIndex()].RawTexture = texid.GetIndex(); + return texid; +} + + +//========================================================================== +// +// Same shit for a different hack, this time Hexen's front sky layers. +// +//========================================================================== + +FTextureID FTextureManager::GetFrontSkyLayer(FTextureID texid) +{ + int texidx = texid.GetIndex(); + if ((unsigned)texidx >= Textures.Size()) return texid; + if (Textures[texidx].FrontSkyLayer != -1) return FSetTextureID(Textures[texidx].FrontSkyLayer); + + // Reject anything that cannot have been a front layer for the sky in original Hexen, i.e. it needs to be an unscaled wall texture only using Doom patches. + auto tex = Textures[texidx].Texture; + auto ttex = tex->GetTexture(); + auto image = ttex->GetImage(); + if (image == nullptr || !image->SupportRemap0() || tex->GetUseType() != ETextureType::Wall || tex->useWorldPanning() || tex->GetTexelTopOffset() != 0 || + ttex->GetWidth() != tex->GetDisplayWidth() || ttex->GetHeight() != tex->GetDisplayHeight()) + { + Textures[texidx].FrontSkyLayer = texidx; + return texid; + } + + // Set this up so that it serializes to the same info as the base texture - this is needed to restore it on load. + // But do not link the new texture into the hash chain! + auto itex = new FImageTexture(image); + itex->SetNoRemap0(); + auto FrontSkyLayer = MakeGameTexture(itex, tex->GetName().GetChars(), ETextureType::Wall); + FrontSkyLayer->SetUseType(tex->GetUseType()); + texid = TexMan.AddGameTexture(FrontSkyLayer, false); + Textures[texidx].FrontSkyLayer = texid.GetIndex(); + Textures[texid.GetIndex()].FrontSkyLayer = texid.GetIndex(); // also let it refer to itself as its front sky layer, in case for repeated InitSkyMap calls. + return texid; +} + +//========================================================================== +// +// +// +//========================================================================== +EXTERN_CVAR(String, language) + +int FTextureManager::ResolveLocalizedTexture(int tex) +{ + size_t langlen = strlen(language); + int lang = (langlen < 2 || langlen > 3) ? + MAKE_ID('e', 'n', 'u', '\0') : + MAKE_ID(language[0], language[1], language[2], '\0'); + + uint64_t index = (uint64_t(lang) << 32) + tex; + if (auto pTex = LocalizedTextures.CheckKey(index)) return *pTex; + index = (uint64_t(lang & MAKE_ID(255, 255, 0, 0)) << 32) + tex; + if (auto pTex = LocalizedTextures.CheckKey(index)) return *pTex; + + return tex; +} + +//=========================================================================== +// +// R_GuesstimateNumTextures +// +// Returns an estimate of the number of textures R_InitData will have to +// process. Used by D_DoomMain() when it calls ST_Init(). +// +//=========================================================================== + +int FTextureManager::GuesstimateNumTextures () +{ + int numtex = 0; + + for(int i = fileSystem.GetNumEntries()-1; i>=0; i--) + { + int space = fileSystem.GetFileNamespace(i); + switch(space) + { + case ns_flats: + case ns_sprites: + case ns_newtextures: + case ns_hires: + case ns_patches: + case ns_graphics: + numtex++; + break; + + default: + if (fileSystem.GetFileFlags(i) & RESFF_MAYBEFLAT) numtex++; + + break; + } + } + + //numtex += CountBuildTiles (); // this cannot be done with a lot of overhead so just leave it out. + numtex += CountTexturesX (); + return numtex; +} + +//=========================================================================== +// +// R_CountTexturesX +// +// See R_InitTextures() for the logic in deciding what lumps to check. +// +//=========================================================================== + +int FTextureManager::CountTexturesX () +{ + int count = 0; + int wadcount = fileSystem.GetNumWads(); + for (int wadnum = 0; wadnum < wadcount; wadnum++) + { + // Use the most recent PNAMES for this WAD. + // Multiple PNAMES in a WAD will be ignored. + int pnames = fileSystem.CheckNumForName("PNAMES", ns_global, wadnum, false); + + // should never happen except for zdoom.pk3 + if (pnames < 0) continue; + + // Only count the patches if the PNAMES come from the current file + // Otherwise they have already been counted. + if (fileSystem.GetFileContainer(pnames) == wadnum) + { + count += CountLumpTextures (pnames); + } + + int texlump1 = fileSystem.CheckNumForName ("TEXTURE1", ns_global, wadnum); + int texlump2 = fileSystem.CheckNumForName ("TEXTURE2", ns_global, wadnum); + + count += CountLumpTextures (texlump1) - 1; + count += CountLumpTextures (texlump2) - 1; + } + return count; +} + +//=========================================================================== +// +// R_CountLumpTextures +// +// Returns the number of patches in a PNAMES/TEXTURE1/TEXTURE2 lump. +// +//=========================================================================== + +int FTextureManager::CountLumpTextures (int lumpnum) +{ + if (lumpnum >= 0) + { + auto file = fileSystem.OpenFileReader (lumpnum); + uint32_t numtex = file.ReadUInt32(); + + return int(numtex) >= 0 ? numtex : 0; + } + return 0; +} + +//----------------------------------------------------------------------------- +// +// Adjust sprite offsets for GL rendering (IWAD resources only) +// +//----------------------------------------------------------------------------- + +void FTextureManager::AdjustSpriteOffsets() +{ + int lump, lastlump = 0; + int sprid; + TMap donotprocess; + + int numtex = fileSystem.GetNumEntries(); + + for (int i = 0; i < numtex; i++) + { + if (fileSystem.GetFileContainer(i) > fileSystem.GetMaxIwadNum()) break; // we are past the IWAD + if (fileSystem.GetFileNamespace(i) == ns_sprites && fileSystem.GetFileContainer(i) >= fileSystem.GetIwadNum() && fileSystem.GetFileContainer(i) <= fileSystem.GetMaxIwadNum()) + { + const char *str = fileSystem.GetFileShortName(i); + FTextureID texid = TexMan.CheckForTexture(str, ETextureType::Sprite, 0); + if (texid.isValid() && fileSystem.GetFileContainer(GetGameTexture(texid)->GetSourceLump()) > fileSystem.GetMaxIwadNum()) + { + // This texture has been replaced by some PWAD. + memcpy(&sprid, str, 4); + donotprocess[sprid] = true; + } + } + } + + while ((lump = fileSystem.FindLump("SPROFS", &lastlump, false)) != -1) + { + FScanner sc; + sc.OpenLumpNum(lump); + sc.SetCMode(true); + int ofslumpno = fileSystem.GetFileContainer(lump); + while (sc.GetString()) + { + int x, y; + bool iwadonly = false; + bool forced = false; + FTextureID texno = TexMan.CheckForTexture(sc.String, ETextureType::Sprite); + sc.MustGetStringName(","); + sc.MustGetNumber(); + x = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + y = sc.Number; + if (sc.CheckString(",")) + { + sc.MustGetString(); + if (sc.Compare("iwad")) iwadonly = true; + if (sc.Compare("iwadforced")) forced = iwadonly = true; + } + if (texno.isValid()) + { + auto tex = GetGameTexture(texno); + + int lumpnum = tex->GetSourceLump(); + // We only want to change texture offsets for sprites in the IWAD or the file this lump originated from. + if (lumpnum >= 0 && lumpnum < fileSystem.GetNumEntries()) + { + int wadno = fileSystem.GetFileContainer(lumpnum); + if ((iwadonly && wadno >= fileSystem.GetIwadNum() && wadno <= fileSystem.GetMaxIwadNum()) || (!iwadonly && wadno == ofslumpno)) + { + if (wadno >= fileSystem.GetIwadNum() && wadno <= fileSystem.GetMaxIwadNum() && !forced && iwadonly) + { + memcpy(&sprid, tex->GetName().GetChars(), 4); + if (donotprocess.CheckKey(sprid)) continue; // do not alter sprites that only get partially replaced. + } + tex->SetOffsets(1, x, y); + } + } + } + } + } +} + + +//========================================================================== +// +// FTextureAnimator :: SetTranslation +// +// Sets animation translation for a texture +// +//========================================================================== + +void FTextureManager::SetTranslation(FTextureID fromtexnum, FTextureID totexnum) +{ + if ((size_t)fromtexnum.texnum < Translation.Size()) + { + if ((size_t)totexnum.texnum >= Textures.Size()) + { + totexnum.texnum = fromtexnum.texnum; + } + Translation[fromtexnum.texnum] = totexnum.texnum; + } +} + + +//----------------------------------------------------------------------------- +// +// Adds an alias name to the texture manager. +// Aliases are only checked if no real texture with the given name exists. +// +//----------------------------------------------------------------------------- + +void FTextureManager::AddAlias(const char* name, int texindex) +{ + if (texindex < 0 || texindex >= NumTextures()) return; // Whatever got passed in here was not valid, so ignore the alias. + aliases.Insert(name, texindex); +} + +void FTextureManager::Listaliases() +{ + decltype(aliases)::Iterator it(aliases); + decltype(aliases)::Pair* pair; + + TArray list; + while (it.NextPair(pair)) + { + auto tex = GetGameTexture(pair->Value); + list.Push(FStringf("%s -> %s%s", pair->Key.GetChars(), tex ? tex->GetName().GetChars() : "(null)", ((tex && tex->GetUseType() == ETextureType::Null) ? ", null" : ""))); + } + std::sort(list.begin(), list.end(), [](const FString& l, const FString& r) { return l.CompareNoCase(r) < 0; }); + for (auto& s : list) + { + Printf("%s\n", s.GetChars()); + } +} + +//========================================================================== +// +// link a texture with a given lump +// +//========================================================================== + +void FTextureManager::SetLinkedTexture(int lump, FGameTexture* tex) +{ + if (lump < fileSystem.GetNumEntries()) + { + linkedMap.Insert(lump, tex); + } +} + +//========================================================================== +// +// retrieve linked texture +// +//========================================================================== + +FGameTexture* FTextureManager::GetLinkedTexture(int lump) +{ + if (lump < fileSystem.GetNumEntries()) + { + auto check = linkedMap.CheckKey(lump); + if (check) return *check; + } + return nullptr; +} + + +//========================================================================== +// +// FTextureID::operator+ +// Does not return invalid texture IDs +// +//========================================================================== + +FTextureID FTextureID::operator +(int offset) const noexcept(true) +{ + if (!isValid()) return *this; + if (texnum + offset >= TexMan.NumTextures()) return FTextureID(-1); + return FTextureID(texnum + offset); +} + +CCMD(flushtextures) +{ + TexMan.FlushAll(); +} + +CCMD(listtexturealiases) +{ + TexMan.Listaliases(); +} diff --git a/src/common/textures/texturemanager.h b/src/common/textures/texturemanager.h new file mode 100644 index 00000000000..cf799153f6a --- /dev/null +++ b/src/common/textures/texturemanager.h @@ -0,0 +1,251 @@ +#pragma once + +#include +#include "tarray.h" +#include "textureid.h" +#include "textures.h" +#include "basics.h" +#include "texmanip.h" +#include "name.h" + +class FxAddSub; +struct BuildInfo; +class FMultipatchTextureBuilder; +class FScanner; + +// Texture manager +class FTextureManager +{ + void (*progressFunc)(); + friend class FxAddSub; // needs access to do a bounds check on the texture ID. +public: + FTextureManager (); + ~FTextureManager (); + +private: + int ResolveLocalizedTexture(int texnum); + + int ResolveTextureIndex(int texnum, bool animate) const + { + if ((unsigned)texnum >= Textures.Size()) return -1; + if (animate) texnum = Translation[texnum]; + //if (localize && Textures[texnum].Flags & TEXFLAG_HASLOCALIZATION) texnum = ResolveLocalizedTexture(texnum); + return texnum; + } + + FGameTexture *InternalGetTexture(int texnum, bool animate) const + { + texnum = ResolveTextureIndex(texnum, animate); + if (texnum == -1) return nullptr; + return Textures[texnum].Texture; + } + + FTextureID ResolveTextureIndex(FTextureID texid, bool animate) const + { + return FSetTextureID(ResolveTextureIndex(texid.GetIndex(), animate)); + } + +public: + // This only gets used in UI code so we do not need PALVERS handling. + FGameTexture* GetGameTextureByName(const char *name, bool animate = false, int flags = 0) + { + FTextureID texnum = GetTextureID(name, ETextureType::MiscPatch, flags); + return InternalGetTexture(texnum.GetIndex(), animate); + } + + FGameTexture* GetGameTexture(FTextureID texnum, bool animate = false) const + { + return InternalGetTexture(texnum.GetIndex(), animate); + } + + FGameTexture* GetPalettedTexture(FTextureID texnum, bool animate = false, bool allowsubstitute = true) const + { + auto texid = ResolveTextureIndex(texnum.GetIndex(), animate); + if (texid == -1) return nullptr; + if (allowsubstitute && Textures[texid].Paletted > 0) texid = Textures[texid].Paletted; + return Textures[texid].Texture; + } + + FGameTexture* GameByIndex(int i, bool animate = false) const + { + return InternalGetTexture(i, animate); + } + + FGameTexture* FindGameTexture(const char* texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny); + + bool OkForLocalization(FTextureID texnum, const char *substitute, int locnum); + + void FlushAll(); + void Listaliases(); + FTextureID GetFrontSkyLayer(FTextureID); + FTextureID GetRawTexture(FTextureID tex, bool dontlookup = false); + void SetRawTexture(FTextureID texid) + { + int texidx = texid.GetIndex(); + if ((unsigned)texidx < Textures.Size()) + { + Textures[texidx].RawTexture = texidx; + } + } + + //========================================================================== + // + // link a texture with a given lump + // + //========================================================================== + + TMap linkedMap; + void SetLinkedTexture(int lump, FGameTexture* tex); + FGameTexture* GetLinkedTexture(int lump); + + enum + { + TEXMAN_TryAny = 1, + TEXMAN_Overridable = 2, + TEXMAN_ReturnFirst = 4, + TEXMAN_AllowSkins = 8, + TEXMAN_ShortNameOnly = 16, + TEXMAN_DontCreate = 32, + TEXMAN_Localize = 64, + TEXMAN_ForceLookup = 128, + TEXMAN_NoAlias = 256, + TEXMAN_ReturnAll = 512, + }; + + enum + { + HIT_Wall = 1, + HIT_Flat = 2, + HIT_Sky = 4, + HIT_Sprite = 8, + + HIT_Columnmode = HIT_Wall|HIT_Sky|HIT_Sprite + }; + + FTextureID CheckForTexture (const char *name, ETextureType usetype, BITFIELD flags=TEXMAN_TryAny); + FTextureID GetTextureID (const char *name, ETextureType usetype, BITFIELD flags=0); + int ListTextures (const char *name, TArray &list, bool listall = false); + + void AddGroup(int wadnum, int ns, ETextureType usetype); + void AddPatches (int lumpnum); + void AddHiresTextures (int wadnum); + void LoadTextureDefs(int wadnum, const char *lumpname, FMultipatchTextureBuilder &build); + void ParseColorization(FScanner& sc); + void ParseTextureDef(int remapLump, FMultipatchTextureBuilder &build); + void SortTexturesByType(int start, int end); + bool AreTexturesCompatible (FTextureID picnum1, FTextureID picnum2); + void AddLocalizedVariants(); + + FTextureID CreateTexture (int lumpnum, ETextureType usetype=ETextureType::Any); // Also calls AddTexture + FTextureID AddGameTexture(FGameTexture* texture, bool addtohash = true); + FTextureID GetDefaultTexture() const { return DefaultTexture; } + + void LoadTextureX(int wadnum, FMultipatchTextureBuilder &build); + void AddTexturesForWad(int wadnum, FMultipatchTextureBuilder &build); + void Init(); + void AddTextures(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo&), void (*customtexturehandler)() = nullptr); + void DeleteAll(); + + void ReplaceTexture (FTextureID texid, FGameTexture *newtexture, bool free); + + int NumTextures () const { return (int)Textures.Size(); } + + int GuesstimateNumTextures (); + + TextureManipulation* GetTextureManipulation(FName name) + { + return tmanips.CheckKey(name); + } + void InsertTextureManipulation(FName cname, TextureManipulation tm) + { + tmanips.Insert(cname, tm); + } + void RemoveTextureManipulation(FName cname) + { + tmanips.Remove(cname); + } + + void AddAlias(const char* name, int texindex); + void AddAlias(const char* name, FTextureID texindex) + { + AddAlias(name, texindex.GetIndex()); + } + +private: + + // texture counting + int CountTexturesX (); + int CountLumpTextures (int lumpnum); + void AdjustSpriteOffsets(); + + // Build tiles + //int CountBuildTiles (); + +public: + + TArray& GetNewBuildTileData() + { + BuildTileData.Reserve(1); + return BuildTileData.Last(); + } + TArray>& GetBuildTileDataStore() + { + return BuildTileData; + } + + FGameTexture* GameTexture(FTextureID id) { return Textures[id.GetIndex()].Texture; } + void SetTranslation(FTextureID fromtexnum, FTextureID totexnum); + +private: + + void InitPalettedVersions(); + + // Switches + + struct TextureDescriptor + { + FGameTexture* Texture; + int Paletted; // redirection to paletted variant + int FrontSkyLayer; // and front sky layer, + int RawTexture; + int HashNext; + uint64_t Flags; + }; + + enum : uint64_t + { + TEXFLAG_HASLOCALIZATION = 1, + }; +public: + constexpr static int TEXFLAG_FIRSTUSER = 65536; // this leaves 16 flags to the texture manager and 48 flags to the user +private: + + enum { HASH_END = -1, HASH_SIZE = 1027 }; + TArray Textures; + TMap LocalizedTextures; + int HashFirst[HASH_SIZE]; + FTextureID DefaultTexture; + TArray FirstTextureForFile; + TArray > BuildTileData; + TArray Translation; + + TMap tmanips; + TMap aliases; + +public: + + short sintable[2048]; // for texture warping + enum + { + SINMASK = 2047 + }; + + FTextureID glPart2; + FTextureID glPart; + FTextureID mirrorTexture; + bool usefullnames; + +}; + +extern FTextureManager TexMan; + diff --git a/src/common/textures/textures.h b/src/common/textures/textures.h new file mode 100644 index 00000000000..8fcdd3b2392 --- /dev/null +++ b/src/common/textures/textures.h @@ -0,0 +1,409 @@ +/* +** textures.h +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __TEXTURES_H +#define __TEXTURES_H + +#include "basics.h" +#include "vectors.h" +#include "colormatcher.h" +#include "renderstyle.h" +#include "textureid.h" +#include +#include "hw_texcontainer.h" +#include "floatrect.h" +#include "refcounted.h" + +class FImageSource; +class FGameTexture; +class IHardwareTexture; + + +enum +{ + CLAMP_NONE = 0, + CLAMP_X, + CLAMP_Y, + CLAMP_XY, + CLAMP_XY_NOMIP, + CLAMP_NOFILTER, + CLAMP_NOFILTER_X, + CLAMP_NOFILTER_Y, + CLAMP_NOFILTER_XY, + CLAMP_CAMTEX, + NUMSAMPLERS +}; + +enum MaterialShaderIndex +{ + SHADER_Default, + SHADER_Warp1, + SHADER_Warp2, + SHADER_Specular, + SHADER_PBR, + SHADER_Paletted, + SHADER_NoTexture, + SHADER_BasicFuzz, + SHADER_SmoothFuzz, + SHADER_SwirlyFuzz, + SHADER_TranslucentFuzz, + SHADER_JaggedFuzz, + SHADER_NoiseFuzz, + SHADER_SmoothNoiseFuzz, + SHADER_SoftwareFuzz, + FIRST_USER_SHADER +}; + +enum texflags +{ + // These get Or'ed into uTextureMode because it only uses its 3 lowermost bits. + TEXF_Brightmap = 0x10000, + TEXF_Detailmap = 0x20000, + TEXF_Glowmap = 0x40000, + TEXF_ClampY = 0x80000, +}; + + + +enum +{ + SFlag_Brightmap = 1, + SFlag_Detailmap = 2, + SFlag_Glowmap = 4, +}; + +struct UserShaderDesc +{ + FString shader; + MaterialShaderIndex shaderType; + FString defines; + bool disablealphatest = false; + uint8_t shaderFlags = 0; +}; + +extern TArray usershaders; + +class FBitmap; +struct FRemapTable; +struct FCopyInfo; +class FScanner; + +// Texture IDs +class FTextureManager; +class FTerrainTypeArray; +class IHardwareTexture; +class FMaterial; +class FMultipatchTextureBuilder; + +extern int r_spriteadjustSW, r_spriteadjustHW; + +enum FTextureFormat : uint32_t +{ + TEX_Pal, + TEX_Gray, + TEX_RGB, // Actually ARGB + + TEX_Count +}; + +class ISoftwareTexture +{ +public: + virtual ~ISoftwareTexture() = default; +}; + +class FGLRenderState; + +struct spriteframewithrotate; +class FSerializer; +namespace OpenGLRenderer +{ + class FGLRenderState; + class FHardwareTexture; +} + +union FContentIdBuilder +{ + uint64_t id; + struct + { + unsigned imageID : 24; + unsigned translation : 16; + unsigned expand : 1; + unsigned scaler : 4; + unsigned scalefactor : 4; + }; +}; + +struct FTextureBuffer +{ + uint8_t *mBuffer = nullptr; + bool mFreeBuffer = true; + int mWidth = 0; + int mHeight = 0; + uint64_t mContentId = 0; // unique content identifier. (Two images created from the same image source with the same settings will return the same value.) + + FTextureBuffer() = default; + + ~FTextureBuffer() + { + if (mBuffer && mFreeBuffer) delete[] mBuffer; + } + + FTextureBuffer(const FTextureBuffer &other) = delete; + FTextureBuffer(FTextureBuffer &&other) noexcept + { + mBuffer = other.mBuffer; + mWidth = other.mWidth; + mHeight = other.mHeight; + mContentId = other.mContentId; + mFreeBuffer = other.mFreeBuffer; + other.mBuffer = nullptr; + } + + FTextureBuffer& operator=(FTextureBuffer &&other) noexcept + { + mBuffer = other.mBuffer; + mWidth = other.mWidth; + mHeight = other.mHeight; + mContentId = other.mContentId; + mFreeBuffer = other.mFreeBuffer; + other.mBuffer = nullptr; + return *this; + } + +}; + +// Base texture class +class FTexture : public RefCountedBase +{ + friend class FGameTexture; // only for the porting work + +public: + FHardwareTextureContainer SystemTextures; +protected: + FloatRect* areas = nullptr; + int SourceLump; + uint16_t Width = 0, Height = 0; + + bool Masked = false; // Texture (might) have holes + bool bHasCanvas = false; + bool bHdr = false; // only canvas textures for now. + int8_t bTranslucent = -1; + int8_t areacount = 0; // this is capped at 4 sections. + + +public: + + IHardwareTexture* GetHardwareTexture(int translation, int scaleflags); + virtual FImageSource *GetImage() const { return nullptr; } + void CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly); + + void CleanHardwareTextures() + { + SystemTextures.Clean(); + } + + void CleanPrecacheMarker() + { + SystemTextures.UnmarkAll(); + } + + void MarkForPrecache(int translation, int scaleflags) + { + SystemTextures.MarkForPrecache(translation, scaleflags); + } + + void CleanUnused() + { + SystemTextures.CleanUnused(); + } + + int GetWidth() { return Width; } + int GetHeight() { return Height; } + + bool isHardwareCanvas() const { return bHasCanvas; } // There's two here so that this can deal with software canvases in the hardware renderer later. + bool isCanvas() const { return bHasCanvas; } + + bool IsHDR() const { return bHdr; } + + int GetSourceLump() { return SourceLump; } // needed by the scripted GetName method. + void SetSourceLump(int sl) { SourceLump = sl; } + bool FindHoles(const unsigned char * buffer, int w, int h); + + void CopySize(FTexture* BaseTexture) + { + Width = BaseTexture->GetWidth(); + Height = BaseTexture->GetHeight(); + } + + // This is only used for the null texture and for Heretic's skies. + void SetSize(int w, int h) + { + Width = w; + Height = h; + } + + bool TrimBorders(uint16_t* rect); + int GetAreas(FloatRect** pAreas) const; + + // Returns the whole texture, stored in column-major order + virtual TArray Get8BitPixels(bool alphatex); + virtual FBitmap GetBgraBitmap(const PalEntry *remap, int *trans = nullptr); + + static bool SmoothEdges(unsigned char * buffer,int w, int h); + + + virtual void ResolvePatches() {} + + + FTexture (int lumpnum = -1); + +public: + FTextureBuffer CreateTexBuffer(int translation, int flags = 0); + virtual bool DetermineTranslucency(); + bool GetTranslucency() + { + return bTranslucent != -1 ? bTranslucent : DetermineTranslucency(); + } + +public: + + void CheckTrans(unsigned char * buffer, int size, int trans); + bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch); + int CheckRealHeight(); + + friend class FTextureManager; +}; + +class FCanvas; +extern TArray AllCanvases; + +// A texture that can be drawn to. + +class FCanvasTexture : public FTexture +{ +public: + FCanvasTexture(int width, int height) + { + Width = width; + Height = height; + + bHasCanvas = true; + aspectRatio = (float)width / height; + } + + ~FCanvasTexture() + { + if (Canvas) + { + AllCanvases.Delete(AllCanvases.Find(Canvas)); + Canvas = nullptr; + } + } + + void NeedUpdate() { bNeedsUpdate = true; } + void SetUpdated(bool rendertype) { bNeedsUpdate = false; bFirstUpdate = false; bLastUpdateType = rendertype; } + bool CheckNeedsUpdate() const { return bNeedsUpdate; } + + void SetAspectRatio(double aspectScale, bool useTextureRatio) { aspectRatio = (float)aspectScale * (useTextureRatio? ((float)Width / Height) : 1); } + + FCanvas* Canvas = nullptr; + +protected: + + bool bLastUpdateType = false; + bool bNeedsUpdate = true; +public: + bool bFirstUpdate = true; + float aspectRatio; + + friend struct FCanvasTextureInfo; + friend class FTextureAnimator; + +private: + void SetHDR(bool hdr) { + bHdr = hdr; + } +}; + + +// A wrapper around a hardware texture, to allow using it in the 2D drawing interface. +class FWrapperTexture : public FTexture +{ + int Format; +public: + FWrapperTexture(int w, int h, int bits = 1); + IHardwareTexture *GetSystemTexture() + { + return SystemTextures.GetHardwareTexture(0, 0); + } + + int GetColorFormat() const + { + return Format; + } +}; + + +class FImageTexture : public FTexture +{ + FImageSource* mImage; + bool bNoRemap0 = false; + int TexFrame = 0; +protected: + void SetFromImage(); +public: + FImageTexture(FImageSource* image, int frame = 0) noexcept; + ~FImageTexture(); + TArray Get8BitPixels(bool alphatex) override; + + void SetImage(FImageSource* img) + { + mImage = img; + SetFromImage(); + } + void SetNoRemap0() { bNoRemap0 = true; } + + FImageSource* GetImage() const override { return mImage; } + FBitmap GetBgraBitmap(const PalEntry* p, int* trans) override; + bool DetermineTranslucency() override; + +}; + + +#include "gametexture.h" +#endif + + diff --git a/src/utility/v_collection.cpp b/src/common/textures/v_collection.cpp similarity index 89% rename from src/utility/v_collection.cpp rename to src/common/textures/v_collection.cpp index 053eeec45d0..975287680a9 100644 --- a/src/utility/v_collection.cpp +++ b/src/common/textures/v_collection.cpp @@ -35,7 +35,8 @@ #include "v_collection.h" #include "v_font.h" #include "v_video.h" -#include "w_wad.h" +#include "filesystem.h" +#include "texturemanager.h" FImageCollection::FImageCollection () { @@ -61,8 +62,8 @@ void FImageCollection::Add (const char **patchNames, int numPatches, ETextureTyp for (int i = 0; i < numPatches; ++i) { - FTextureID picnum = TexMan.CheckForTexture(patchNames[i], namespc); - ImageMap[OldCount + i] = picnum; + FTextureID texid = TexMan.CheckForTexture(patchNames[i], namespc); + ImageMap[OldCount + i] = texid; } } @@ -71,11 +72,11 @@ void FImageCollection::Uninit () ImageMap.Clear(); } -FTexture *FImageCollection::operator[] (int index) const +FGameTexture *FImageCollection::operator[] (int index) const { if ((unsigned int)index >= ImageMap.Size()) { return NULL; } - return ImageMap[index].Exists()? TexMan.GetPalettedTexture(ImageMap[index], true) : NULL; + return ImageMap[index].Exists()? TexMan.GetGameTexture(ImageMap[index], true) : NULL; } diff --git a/src/utility/v_collection.h b/src/common/textures/v_collection.h similarity index 95% rename from src/utility/v_collection.h rename to src/common/textures/v_collection.h index 697e6bb0787..8574e580274 100644 --- a/src/utility/v_collection.h +++ b/src/common/textures/v_collection.h @@ -34,10 +34,10 @@ #ifndef __V_COLLECTION_H__ #define __V_COLLECTION_H__ -#include "doomtype.h" -#include "r_defs.h" +#include "tarray.h" +#include "textureid.h" -class FTexture; +class FGameTexture; class FImageCollection { @@ -49,7 +49,7 @@ class FImageCollection void Add(const char **patchnames, int numPatches, ETextureType namespc = ETextureType::Any); void Uninit(); - FTexture *operator[] (int index) const; + FGameTexture *operator[] (int index) const; protected: TArray ImageMap; diff --git a/src/common/thirdparty/animlib.cpp b/src/common/thirdparty/animlib.cpp new file mode 100644 index 00000000000..4791a131322 --- /dev/null +++ b/src/common/thirdparty/animlib.cpp @@ -0,0 +1,290 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) +*/ +//------------------------------------------------------------------------- + +#include +#include "animlib.h" +#include "m_swap.h" + +//**************************************************************************** +// +// LOCALS +// +//**************************************************************************** + +//**************************************************************************** +// +// findpage () +// - return the large page number a given frame resides in +// +//**************************************************************************** + +static inline uint16_t findpage(anim_t *anim, uint16_t framenumber) +{ + // curlpnum is initialized to 0xffff, obviously + size_t i = anim->curlpnum & ~0xffff; + size_t const nLps = anim->lpheader->nLps; + bool j = true; + + if (framenumber < anim->currentframe) + i = 0, j = false; + + // this scans the last used page and higher first and then scans the + // previously accessed pages afterwards if it doesn't find anything + do + { + for (; i < nLps; ++i) + { + lp_descriptor & lp = anim->LpArray[i]; + if (lp.baseRecord <= framenumber && framenumber < lp.baseRecord + lp.nRecords) + return (uint16_t)i; + } + + if (j && i == nLps) + { + // handle out of order pages... I don't think any Duke .ANM files + // have them, but they're part of the file spec + i = 0, j = false; + continue; + } + + break; + } + while (1); + + return (uint16_t)i; +} + + +//**************************************************************************** +// +// loadpage () +// - seek out and set pointers to the large page specified +// +//**************************************************************************** + +static inline void loadpage(anim_t *anim, uint16_t pagenumber, uint16_t **pagepointer) +{ + if (anim->curlpnum == pagenumber) + return; + + anim->curlpnum = pagenumber; + anim->curlp = &anim->LpArray[pagenumber]; + *pagepointer = (uint16_t *)(anim->buffer + 0xb00 + (pagenumber*IMAGEBUFFERSIZE) + + sizeof(lp_descriptor) + sizeof(uint16_t)); +} + + +//**************************************************************************** +// +// decodeframe () +// - I found this less obfuscated version of the .ANM "decompressor", +// (c) 1998 "Jari Komppa aka Sol/Trauma". This code is public domain +// but has been mostly rewritten by me. +// +// - As a side note, it looks like this format came about in 1989 and +// never went anywhere after that, and appears to have been the format +// used by Electronic Arts' DeluxePaint Animation, which never made it +// past version 1.0. +// +//**************************************************************************** + +static void decodeframe(uint8_t * srcP, uint8_t * dstP) +{ + do + { + { + /* short op */ + uint8_t count = *srcP++; + + if (!count) /* short RLE */ + { + uint8_t color = *(srcP+1); + count = *(uint8_t *)srcP; + srcP += sizeof(int16_t); + memset(dstP, color, count); + dstP += count; + continue; + } + else if ((count & 0x80) == 0) /* short copy */ + { + memcpy(dstP, srcP, count); + dstP += count; + srcP += count; + continue; + } + else if ((count &= ~0x80) > 0) /* short skip */ + { + dstP += count; + continue; + } + } + + { + /* long op */ + uint16_t count = LittleShort((uint16_t)GetShort(srcP)); + srcP += sizeof(int16_t); + + if (!count) /* stop sign */ + return; + else if ((count & 0x8000) == 0) /* long skip */ + { + dstP += count; + continue; + } + else if ((count &= ~0x8000) & 0x4000) /* long RLE */ + { + uint8_t color = *srcP++; + count &= ~0x4000; + memset(dstP, color, count); + dstP += count; + continue; + } + + /* long copy */ + memcpy(dstP, srcP, count); + dstP += count; + srcP += count; + } + } + while (1); +} + + +//**************************************************************************** +// +// renderframe () +// - draw the frame sepcified from the large page in the buffer pointed to +// +//**************************************************************************** + +static void renderframe(anim_t *anim, uint16_t framenumber, uint16_t *pagepointer) +{ + uint16_t offset = 0; + uint16_t frame = framenumber - anim->curlp->baseRecord; + + while (frame--) offset += LittleShort(pagepointer[frame]); + + if (offset >= anim->curlp->nBytes) + return; + + uint8_t *ppointer = (uint8_t *)(pagepointer) + anim->curlp->nRecords*2 + offset + 4; + + if ((ppointer-4)[1]) + { + uint16_t const temp = LittleShort(((uint16_t *)(ppointer-4))[1]); + ppointer += temp + (temp & 1); + } + + decodeframe((uint8_t *)ppointer, (uint8_t *)anim->imagebuffer); +} + + +//**************************************************************************** +// +// drawframe () +// - high level frame draw routine +// +//**************************************************************************** + +static inline void drawframe(anim_t *anim, uint16_t framenumber) +{ + loadpage(anim, findpage(anim, framenumber), &anim->thepage); + renderframe(anim, framenumber, anim->thepage); +} + +// is the file size, for consistency checking. +int32_t ANIM_LoadAnim(anim_t *anim, const uint8_t *buffer, size_t length) +{ + if (memcmp(buffer, "LPF ", 4)) return -1; + + length -= sizeof(lpfileheader)+128+768; + if ((signed)length < 0) + return -1; + + anim->curlpnum = 0xffff; + anim->currentframe = -1; + + // this just modifies the data in-place instead of copying it elsewhere now + lpfileheader & lpheader = *(anim->lpheader = (lpfileheader *)(anim->buffer = buffer)); + + lpheader.id = LittleLong(lpheader.id); + lpheader.maxLps = LittleShort(lpheader.maxLps); + lpheader.nLps = LittleShort(lpheader.nLps); + lpheader.nRecords = LittleLong(lpheader.nRecords); + lpheader.maxRecsPerLp = LittleShort(lpheader.maxRecsPerLp); + lpheader.lpfTableOffset = LittleShort(lpheader.lpfTableOffset); + lpheader.contentType = LittleLong(lpheader.contentType); + lpheader.width = LittleShort(lpheader.width); + lpheader.height = LittleShort(lpheader.height); + lpheader.nFrames = LittleLong(lpheader.nFrames); + lpheader.framesPerSecond = LittleShort(lpheader.framesPerSecond); + + length -= lpheader.nLps * sizeof(lp_descriptor); + if ((signed)length < 0) + return -2; + + buffer += sizeof(lpfileheader)+128; + + // load the color palette + for (uint8_t * pal = anim->pal, * pal_end = pal+768; pal < pal_end; pal += 3, buffer += 4) + { + pal[2] = buffer[0]; + pal[1] = buffer[1]; + pal[0] = buffer[2]; + } + + // set up large page descriptors + anim->LpArray = (lp_descriptor *)buffer; + + // theoretically we should be able to play files with more than 256 frames now + // assuming the utilities to create them can make them that way + for (lp_descriptor * lp = anim->LpArray, * lp_end = lp+lpheader.nLps; lp < lp_end; ++lp) + { + lp->baseRecord = LittleShort(lp->baseRecord); + lp->nRecords = LittleShort(lp->nRecords); + lp->nBytes = LittleShort(lp->nBytes); + } + return ANIM_NumFrames(anim) <= 0 ? -1 : 0; +} + + +uint8_t * ANIM_DrawFrame(anim_t *anim, int32_t framenumber) +{ + uint32_t cnt = anim->currentframe; + + // handle first play and looping or rewinding + if (cnt > (uint32_t)framenumber) + cnt = 0; + + do drawframe(anim, cnt++); + while (cnt < (uint32_t)framenumber); + + anim->currentframe = framenumber; + return anim->imagebuffer; +} + + diff --git a/src/common/thirdparty/animlib.h b/src/common/thirdparty/animlib.h new file mode 100644 index 00000000000..26fa124f408 --- /dev/null +++ b/src/common/thirdparty/animlib.h @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) +*/ +//------------------------------------------------------------------------- +#pragma once + +#include +///////////////////////////////////////////////////////////////////////////// +// +// ANIMLIB.H +// +///////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifndef animlib_public_h_ +#define animlib_public_h_ + +# pragma pack(push,1) + +/* structure declarations for deluxe animate large page files, doesn't + need to be in the header because there are no exposed functions + that use any of this directly */ + +struct lpfileheader +{ + uint32_t id; /* 4 uint8_tacter ID == "LPF " */ + uint16_t maxLps; /* max # largePages allowed. 256 FOR NOW. */ + uint16_t nLps; /* # largePages in this file. */ + uint32_t nRecords; /* # records in this file. 65534 is current limit + ring */ + uint16_t maxRecsPerLp; /* # records permitted in an lp. 256 FOR NOW. */ + uint16_t lpfTableOffset; /* Absolute Seek position of lpfTable. 1280 FOR NOW. */ + uint32_t contentType; /* 4 character ID == "ANIM" */ + uint16_t width; /* Width of screen in pixels. */ + uint16_t height; /* Height of screen in pixels. */ + uint8_t variant; /* 0==ANIM. */ + uint8_t version; /* 0==frame rate in 18/sec, 1= 70/sec */ + uint8_t hasLastDelta; /* 1==Last record is a delta from last-to-first frame. */ + uint8_t lastDeltaValid; /* 0==Ignore ring frame. */ + uint8_t pixelType; /* 0==256 color. */ + uint8_t CompressionType; /* 1==(RunSkipDump) Only one used FOR NOW. */ + uint8_t otherRecsPerFrm; /* 0 FOR NOW. */ + uint8_t bitmaptype; /* 1==320x200, 256-color. Only one implemented so far. */ + uint8_t recordTypes[32]; /* Not yet implemented. */ + uint32_t nFrames; /* Number of actual frames in the file, includes ring frame. */ + uint16_t framesPerSecond; /* Number of frames to play per second. */ + uint16_t pad2[29]; /* 58 bytes of filler to round up to 128 bytes total. */ +}; + +// this is the format of a large page structure +struct lp_descriptor +{ + uint16_t baseRecord; // Number of first record in this large page. + uint16_t nRecords; // Number of records in lp. + // bit 15 of "nRecords" == "has continuation from previous lp". + // bit 14 of "nRecords" == "final record continues on next lp". + uint16_t nBytes; // Total number of bytes of contents, excluding header. +}; + +#pragma pack(pop) + +#define IMAGEBUFFERSIZE 0x10000 + +struct anim_t +{ + uint16_t framecount; // current frame of anim + lpfileheader * lpheader; // file header will be loaded into this structure + lp_descriptor * LpArray; // arrays of large page structs used to find frames + uint16_t curlpnum; // initialize to an invalid Large page number + lp_descriptor * curlp; // header of large page currently in memory + uint16_t * thepage; // buffer where current large page is loaded + uint8_t imagebuffer[IMAGEBUFFERSIZE]; // buffer where anim frame is decoded + const uint8_t * buffer; + uint8_t pal[768]; + int32_t currentframe; +}; + +//**************************************************************************** +// +// ANIM_LoadAnim () +// +// Setup internal anim data structure +// +//**************************************************************************** + +int32_t ANIM_LoadAnim(anim_t *anim, const uint8_t *buffer, size_t length); + +//**************************************************************************** +// +// ANIM_NumFrames () +// +// returns the number of frames in the current anim +// +//**************************************************************************** + +inline int32_t ANIM_NumFrames(anim_t* anim) +{ + return anim->lpheader->nRecords; +} + +//**************************************************************************** +// +// ANIM_DrawFrame () +// +// Draw the frame to a returned buffer +// +//**************************************************************************** + +uint8_t * ANIM_DrawFrame(anim_t* anim, int32_t framenumber); + +//**************************************************************************** +// +// ANIM_GetPalette () +// +// return the palette of the anim +//**************************************************************************** + +inline uint8_t* ANIM_GetPalette(anim_t* anim) +{ + return anim->pal; +} + +#endif diff --git a/src/common/thirdparty/base64.cpp b/src/common/thirdparty/base64.cpp new file mode 100644 index 00000000000..fcd0ae4147a --- /dev/null +++ b/src/common/thirdparty/base64.cpp @@ -0,0 +1,139 @@ +/* + base64.cpp and base64.h + + base64 encoding and decoding with C++. + + Version: 1.01.00 + + Copyright (C) 2004-2017 René Nyffenegger + Copyright (C) 2020 Christoph Oelckers + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + + Addapted by Christoph Oelckers to FSerializer's needs where std::string is not a good container. + +*/ +#include +#include "base64.h" + +static const char *base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +inline int base64toindex(int c) +{ + if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 'a' + 26; + if (c >= '0' && c <= '9') return c - '0' + 52; + if (c == '+') return 62; + if (c == '/') return 63; + return -1; +} + +static inline bool is_base64(unsigned char c) { + return base64toindex(c) >= 0; +} + +TArray base64_encode(unsigned char const* bytes_to_encode, size_t in_len) { + TArray reta((in_len+5)/6 + 6); + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + reta.Push(base64_chars[char_array_4[i]]); + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = ( char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + + for (j = 0; (j < i + 1); j++) + reta.Push(base64_chars[char_array_4[j]]); + + while((i++ < 3)) + reta.Push('='); + + } + reta.Push(0); + + return reta; + +} + +void base64_decode(void *memory, size_t maxlen, const char *encoded_string) { + size_t in_len = strlen(encoded_string); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + uint8_t* dest = (uint8_t*)memory; + uint8_t* end = dest + maxlen; + + while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i == 4) { + for (i = 0; i < 4; i++) + char_array_4[i] = base64toindex(char_array_4[i]) & 0xff; + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + *dest++ = char_array_3[i]; + if (dest >= end) return; + i = 0; + } + } + + if (i) { + for (j = 0; j < i; j++) + char_array_4[j] = base64toindex(char_array_4[j]) & 0xff; + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + + for (j = 0; (j < i - 1); j++) + { + *dest++ = char_array_3[j]; + if (dest >= end) return; + } + } + while (dest < end) *dest++ = 0; +} diff --git a/src/common/thirdparty/base64.h b/src/common/thirdparty/base64.h new file mode 100644 index 00000000000..1f1bde61cdf --- /dev/null +++ b/src/common/thirdparty/base64.h @@ -0,0 +1,14 @@ +// +// base64 encoding and decoding with C++. +// Version: 1.01.00 +// + +#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A +#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A + +#include "tarray.h" + +TArray base64_encode(unsigned char const* bytes_to_encode, size_t in_len); +void base64_decode(void* memory, size_t len, const char* encoded_string); + +#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */ diff --git a/src/utility/ctpl.h b/src/common/thirdparty/ctpl.h similarity index 100% rename from src/utility/ctpl.h rename to src/common/thirdparty/ctpl.h diff --git a/src/utility/earcut.hpp b/src/common/thirdparty/earcut.hpp similarity index 88% rename from src/utility/earcut.hpp rename to src/common/thirdparty/earcut.hpp index d6a2c979880..2c83e33bfda 100644 --- a/src/utility/earcut.hpp +++ b/src/common/thirdparty/earcut.hpp @@ -82,6 +82,7 @@ class Earcut { template Node* eliminateHoles(const Polygon& points, Node* outerNode); void eliminateHole(Node* hole, Node* outerNode); Node* findHoleBridge(Node* hole, Node* outerNode); + bool sectorContainsSector(const Node* m, const Node* p); void indexCurve(Node* start); Node* sortLinked(Node* list); int32_t zOrder(const double x_, const double y_); @@ -91,6 +92,8 @@ class Earcut { double area(const Node* p, const Node* q, const Node* r) const; bool equals(const Node* p1, const Node* p2); bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2); + bool onSegment(const Node* p, const Node* q, const Node* r); + int sign(double val); bool intersectsPolygon(const Node* a, const Node* b); bool locallyInside(const Node* a, const Node* b); bool middleInside(const Node* a, const Node* b); @@ -116,16 +119,18 @@ class Earcut { template T* construct(Args&&... args) { if (currentIndex >= blockSize) { - currentBlock = alloc.allocate(blockSize); + currentBlock = alloc_traits::allocate(alloc, blockSize); allocations.emplace_back(currentBlock); currentIndex = 0; } T* object = ¤tBlock[currentIndex++]; - alloc.construct(object, std::forward(args)...); + alloc_traits::construct(alloc, object, std::forward(args)...); return object; } void reset(std::size_t newBlockSize) { - for (auto allocation : allocations) alloc.deallocate(allocation, blockSize); + for (auto allocation : allocations) { + alloc_traits::deallocate(alloc, allocation, blockSize); + } allocations.clear(); blockSize = std::max(1, newBlockSize); currentBlock = nullptr; @@ -138,6 +143,7 @@ class Earcut { std::size_t blockSize = 1; std::vector allocations; Alloc alloc; + typedef typename std::allocator_traits alloc_traits; }; ObjectPool nodes; }; @@ -165,7 +171,7 @@ void Earcut::operator()(const Polygon& points) { indices.reserve(len + points[0].size()); Node* outerNode = linkedList(points[0], true); - if (!outerNode) return; + if (!outerNode || outerNode->prev == outerNode->next) return; if (points.size() > 1) outerNode = eliminateHoles(points, outerNode); @@ -244,8 +250,7 @@ Earcut::filterPoints(Node* start, Node* end) { do { again = false; - if (!p->steiner && (equals(p, p->next) /*|| area(p->prev, p, p->next) == 0*/)) - { + if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) { removeNode(p); p = end = p->prev; @@ -304,7 +309,7 @@ void Earcut::earcutLinked(Node* ear, int pass) { // if this didn't work, try curing all small self-intersections locally else if (pass == 1) { - ear = cureLocalIntersections(ear); + ear = cureLocalIntersections(filterPoints(ear)); earcutLinked(ear, 2); // as a last resort, try splitting the remaining polygon into two @@ -401,7 +406,7 @@ Earcut::cureLocalIntersections(Node* start) { p = p->next; } while (p != start); - return p; + return filterPoints(p); } // try splitting polygon into two and triangulate them independently @@ -464,6 +469,9 @@ void Earcut::eliminateHole(Node* hole, Node* outerNode) { outerNode = findHoleBridge(hole, outerNode); if (outerNode) { Node* b = splitPolygon(outerNode, hole); + + // filter out colinear points around cuts + filterPoints(outerNode, outerNode->next); filterPoints(b, b->next); } } @@ -497,7 +505,7 @@ Earcut::findHoleBridge(Node* hole, Node* outerNode) { if (!m) return 0; - if (hx == qx) return m->prev; + if (hx == qx) return m; // hole touches outer segment; pick leftmost endpoint // look for points inside the triangle of hole Vertex, segment intersection and endpoint; // if there are no points found, we have a valid connection; @@ -507,28 +515,35 @@ Earcut::findHoleBridge(Node* hole, Node* outerNode) { double tanMin = std::numeric_limits::infinity(); double tanCur = 0; - p = m->next; + p = m; double mx = m->x; double my = m->y; - while (p != stop) { + do { if (hx >= p->x && p->x >= mx && hx != p->x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) { tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential - if ((tanCur < tanMin || (tanCur == tanMin && p->x > m->x)) && locallyInside(p, hole)) { + if (locallyInside(p, hole) && + (tanCur < tanMin || (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) { m = p; tanMin = tanCur; } } p = p->next; - } + } while (p != stop); return m; } +// whether sector in vertex m contains sector in vertex p in the same coordinates +template +bool Earcut::sectorContainsSector(const Node* m, const Node* p) { + return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0; +} + // interlink polygon nodes in z-order template void Earcut::indexCurve(Node* start) { @@ -644,7 +659,8 @@ Earcut::getLeftmost(Node* start) { Node* p = start; Node* leftmost = start; do { - if (p->x < leftmost->x) leftmost = p; + if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) + leftmost = p; p = p->next; } while (p != start); @@ -662,8 +678,10 @@ bool Earcut::pointInTriangle(double ax, double ay, double bx, double by, doub // check if a diagonal between two polygon nodes is valid (lies in polygon interior) template bool Earcut::isValidDiagonal(Node* a, Node* b) { - return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && - locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b); + return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges + ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible + (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors + (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case } // signed area of a triangle @@ -681,10 +699,33 @@ bool Earcut::equals(const Node* p1, const Node* p2) { // check if two segments intersect template bool Earcut::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) { - if ((equals(p1, q1) && equals(p2, q2)) || - (equals(p1, q2) && equals(p2, q1))) return true; - return (area(p1, q1, p2) > 0) != (area(p1, q1, q2) > 0) && - (area(p2, q2, p1) > 0) != (area(p2, q2, q1) > 0); + int o1 = sign(area(p1, q1, p2)); + int o2 = sign(area(p1, q1, q2)); + int o3 = sign(area(p2, q2, p1)); + int o4 = sign(area(p2, q2, q1)); + + if (o1 != o2 && o3 != o4) return true; // general case + + if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 + if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 + if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 + if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 + + return false; +} + +// for collinear points p, q, r, check if point q lies on segment pr +template +bool Earcut::onSegment(const Node* p, const Node* q, const Node* r) { + return q->x <= std::max(p->x, r->x) && + q->x >= std::min(p->x, r->x) && + q->y <= std::max(p->y, r->y) && + q->y >= std::min(p->y, r->y); +} + +template +int Earcut::sign(double val) { + return (0.0 < val) - (val < 0.0); } // check if a polygon diagonal intersects any polygon segments diff --git a/src/common/thirdparty/gain_analysis.cpp b/src/common/thirdparty/gain_analysis.cpp new file mode 100644 index 00000000000..a31538f40a0 --- /dev/null +++ b/src/common/thirdparty/gain_analysis.cpp @@ -0,0 +1,487 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001-2009 David Robinson and Glen Sawyer + * Improvements and optimizations added by Frank Klemm, and by Marcel M�ller + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * original coding by Glen Sawyer (mp3gain@hotmail.com) + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ ) + * -- credit him for all the _good_ programming ;) + * + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +/* + * Here's the deal. Call + * + * InitGainAnalysis ( long samplefreq ); + * + * to initialize everything. Call + * + * AnalyzeSamples ( const Float_t* left_samples, + * const Float_t* right_samples, + * size_t num_samples, + * int num_channels ); + * + * as many times as you want, with as many or as few samples as you want. + * If mono, pass the sample buffer in through left_samples, leave + * right_samples NULL, and make sure num_channels = 1. + * + * GetTitleGain() + * + * will return the recommended dB level change for all samples analyzed + * SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis(). + * + * GetAlbumGain() + * + * will return the recommended dB level change for all samples analyzed + * since InitGainAnalysis() was called and finalized with GetTitleGain(). + * + * Pseudo-code to process an album: + * + * Float_t l_samples [4096]; + * Float_t r_samples [4096]; + * size_t num_samples; + * unsigned int num_songs; + * unsigned int i; + * + * InitGainAnalysis ( 44100 ); + * for ( i = 1; i <= num_songs; i++ ) { + * while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 ) + * AnalyzeSamples ( left_samples, right_samples, num_samples, 2 ); + * fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() ); + * } + * fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() ); + */ + +/* + * So here's the main source of potential code confusion: + * + * The filters applied to the incoming samples are IIR filters, + * meaning they rely on up to number of previous samples + * AND up to number of previous filtered samples. + * + * I set up the AnalyzeSamples routine to minimize memory usage and interface + * complexity. The speed isn't compromised too much (I don't think), but the + * internal complexity is higher than it should be for such a relatively + * simple routine. + * + * Optimization/clarity suggestions are welcome. + */ + +#include +#include +#include +#include + +#include "gain_analysis.h" + +#define RMS_PERCENTILE 0.95 // percentile which is louder than the proposed level + +#define PINK_REF 64.82 //298640883795 // calibration value + + +// for each filter: +// [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz + +#ifdef WIN32 +#ifndef __GNUC__ +#pragma warning ( disable : 4305 ) +#pragma warning ( disable : 4244 ) +#endif +#endif + +static const Float_t ABYule[][2 * YULE_ORDER + 1] = { + {(Float_t) 0.006471345933032, (Float_t) -7.22103125152679, (Float_t) -0.02567678242161, (Float_t) 24.7034187975904, (Float_t) 0.049805860704367, (Float_t) -52.6825833623896, (Float_t) -0.05823001743528, (Float_t) 77.4825736677539, (Float_t) 0.040611847441914, (Float_t) -82.0074753444205, (Float_t) -0.010912036887501, (Float_t) 63.1566097101925, (Float_t) -0.00901635868667, (Float_t) -34.889569769245, (Float_t) 0.012448886238123, (Float_t) 13.2126852760198, (Float_t) -0.007206683749426, (Float_t) -3.09445623301669, (Float_t) 0.002167156433951, (Float_t) 0.340344741393305, (Float_t) -0.000261819276949}, + {(Float_t) 0.015415414474287, (Float_t) -7.19001570087017, (Float_t) -0.07691359399407, (Float_t) 24.4109412087159, (Float_t) 0.196677418516518, (Float_t) -51.6306373580801, (Float_t) -0.338855114128061, (Float_t) 75.3978476863163, (Float_t) 0.430094579594561, (Float_t) -79.4164552507386, (Float_t) -0.415015413747894, (Float_t) 61.0373661948115, (Float_t) 0.304942508151101, (Float_t) -33.7446462547014, (Float_t) -0.166191795926663, (Float_t) 12.8168791146274, (Float_t) 0.063198189938739, (Float_t) -3.01332198541437, (Float_t) -0.015003978694525, (Float_t) 0.223619893831468, (Float_t) 0.001748085184539}, + {(Float_t) 0.021776466467053, (Float_t) -5.74819833657784, (Float_t) -0.062376961003801, (Float_t) 16.246507961894, (Float_t) 0.107731165328514, (Float_t) -29.9691822642542, (Float_t) -0.150994515142316, (Float_t) 40.027597579378, (Float_t) 0.170334807313632, (Float_t) -40.3209196052655, (Float_t) -0.157984942890531, (Float_t) 30.8542077487718, (Float_t) 0.121639833268721, (Float_t) -17.5965138737281, (Float_t) -0.074094040816409, (Float_t) 7.10690214103873, (Float_t) 0.031282852041061, (Float_t) -1.82175564515191, (Float_t) -0.00755421235941, (Float_t) 0.223619893831468, (Float_t) 0.00117925454213}, + {(Float_t) 0.03857599435200, (Float_t) -3.84664617118067, (Float_t) -0.02160367184185, (Float_t) 7.81501653005538, (Float_t) -0.00123395316851, (Float_t) -11.34170355132042, (Float_t) -0.00009291677959, (Float_t) 13.05504219327545, (Float_t) -0.01655260341619, (Float_t) -12.28759895145294, (Float_t) 0.02161526843274, (Float_t) 9.48293806319790, (Float_t) -0.02074045215285, (Float_t) -5.87257861775999, (Float_t) 0.00594298065125, (Float_t) 2.75465861874613, (Float_t) 0.00306428023191, (Float_t) -0.86984376593551, (Float_t) 0.00012025322027, (Float_t) 0.13919314567432, (Float_t) 0.00288463683916}, + {(Float_t) 0.05418656406430, (Float_t) -3.47845948550071, (Float_t) -0.02911007808948, (Float_t) 6.36317777566148, (Float_t) -0.00848709379851, (Float_t) -8.54751527471874, (Float_t) -0.00851165645469, (Float_t) 9.47693607801280, (Float_t) -0.00834990904936, (Float_t) -8.81498681370155, (Float_t) 0.02245293253339, (Float_t) 6.85401540936998, (Float_t) -0.02596338512915, (Float_t) -4.39470996079559, (Float_t) 0.01624864962975, (Float_t) 2.19611684890774, (Float_t) -0.00240879051584, (Float_t) -0.75104302451432, (Float_t) 0.00674613682247, (Float_t) 0.13149317958808, (Float_t) -0.00187763777362}, + {(Float_t) 0.15457299681924, (Float_t) -2.37898834973084, (Float_t) -0.09331049056315, (Float_t) 2.84868151156327, (Float_t) -0.06247880153653, (Float_t) -2.64577170229825, (Float_t) 0.02163541888798, (Float_t) 2.23697657451713, (Float_t) -0.05588393329856, (Float_t) -1.67148153367602, (Float_t) 0.04781476674921, (Float_t) 1.00595954808547, (Float_t) 0.00222312597743, (Float_t) -0.45953458054983, (Float_t) 0.03174092540049, (Float_t) 0.16378164858596, (Float_t) -0.01390589421898, (Float_t) -0.05032077717131, (Float_t) 0.00651420667831, (Float_t) 0.02347897407020, (Float_t) -0.00881362733839}, + {(Float_t) 0.30296907319327, (Float_t) -1.61273165137247, (Float_t) -0.22613988682123, (Float_t) 1.07977492259970, (Float_t) -0.08587323730772, (Float_t) -0.25656257754070, (Float_t) 0.03282930172664, (Float_t) -0.16276719120440, (Float_t) -0.00915702933434, (Float_t) -0.22638893773906, (Float_t) -0.02364141202522, (Float_t) 0.39120800788284, (Float_t) -0.00584456039913, (Float_t) -0.22138138954925, (Float_t) 0.06276101321749, (Float_t) 0.04500235387352, (Float_t) -0.00000828086748, (Float_t) 0.02005851806501, (Float_t) 0.00205861885564, (Float_t) 0.00302439095741, (Float_t) -0.02950134983287}, + {(Float_t) 0.33642304856132, (Float_t) -1.49858979367799, (Float_t) -0.25572241425570, (Float_t) 0.87350271418188, (Float_t) -0.11828570177555, (Float_t) 0.12205022308084, (Float_t) 0.11921148675203, (Float_t) -0.80774944671438, (Float_t) -0.07834489609479, (Float_t) 0.47854794562326, (Float_t) -0.00469977914380, (Float_t) -0.12453458140019, (Float_t) -0.00589500224440, (Float_t) -0.04067510197014, (Float_t) 0.05724228140351, (Float_t) 0.08333755284107, (Float_t) 0.00832043980773, (Float_t) -0.04237348025746, (Float_t) -0.01635381384540, (Float_t) 0.02977207319925, (Float_t) -0.01760176568150}, + {(Float_t) 0.44915256608450, (Float_t) -0.62820619233671, (Float_t) -0.14351757464547, (Float_t) 0.29661783706366, (Float_t) -0.22784394429749, (Float_t) -0.37256372942400, (Float_t) -0.01419140100551, (Float_t) 0.00213767857124, (Float_t) 0.04078262797139, (Float_t) -0.42029820170918, (Float_t) -0.12398163381748, (Float_t) 0.22199650564824, (Float_t) 0.04097565135648, (Float_t) 0.00613424350682, (Float_t) 0.10478503600251, (Float_t) 0.06747620744683, (Float_t) -0.01863887810927, (Float_t) 0.05784820375801, (Float_t) -0.03193428438915, (Float_t) 0.03222754072173, (Float_t) 0.00541907748707}, + {(Float_t) 0.56619470757641, (Float_t) -1.04800335126349, (Float_t) -0.75464456939302, (Float_t) 0.29156311971249, (Float_t) 0.16242137742230, (Float_t) -0.26806001042947, (Float_t) 0.16744243493672, (Float_t) 0.00819999645858, (Float_t) -0.18901604199609, (Float_t) 0.45054734505008, (Float_t) 0.30931782841830, (Float_t) -0.33032403314006, (Float_t) -0.27562961986224, (Float_t) 0.06739368333110, (Float_t) 0.00647310677246, (Float_t) -0.04784254229033, (Float_t) 0.08647503780351, (Float_t) 0.01639907836189, (Float_t) -0.03788984554840, (Float_t) 0.01807364323573, (Float_t) -0.00588215443421}, + {(Float_t) 0.58100494960553, (Float_t) -0.51035327095184, (Float_t) -0.53174909058578, (Float_t) -0.31863563325245, (Float_t) -0.14289799034253, (Float_t) -0.20256413484477, (Float_t) 0.17520704835522, (Float_t) 0.14728154134330, (Float_t) 0.02377945217615, (Float_t) 0.38952639978999, (Float_t) 0.15558449135573, (Float_t) -0.23313271880868, (Float_t) -0.25344790059353, (Float_t) -0.05246019024463, (Float_t) 0.01628462406333, (Float_t) -0.02505961724053, (Float_t) 0.06920467763959, (Float_t) 0.02442357316099, (Float_t) -0.03721611395801, (Float_t) 0.01818801111503, (Float_t) -0.00749618797172}, + {(Float_t) 0.53648789255105, (Float_t) -0.25049871956020, (Float_t) -0.42163034350696, (Float_t) -0.43193942311114, (Float_t) -0.00275953611929, (Float_t) -0.03424681017675, (Float_t) 0.04267842219415, (Float_t) -0.04678328784242, (Float_t) -0.10214864179676, (Float_t) 0.26408300200955, (Float_t) 0.14590772289388, (Float_t) 0.15113130533216, (Float_t) -0.02459864859345, (Float_t) -0.17556493366449, (Float_t) -0.11202315195388, (Float_t) -0.18823009262115, (Float_t) -0.04060034127000, (Float_t) 0.05477720428674, (Float_t) 0.04788665548180, (Float_t) 0.04704409688120, (Float_t) -0.02217936801134}, + + {(Float_t) 0.38524531015142, (Float_t) -1.29708918404534, (Float_t) -0.27682212062067, (Float_t) 0.90399339674203, (Float_t)-0.09980181488805, (Float_t) -0.29613799017877, (Float_t) 0.09951486755646, (Float_t)-0.42326645916207, (Float_t) -0.08934020156622, (Float_t) 0.37934887402200, (Float_t) -0.00322369330199, (Float_t) -0.37919795944938, (Float_t) -0.00110329090689, (Float_t) 0.23410283284785, (Float_t) 0.03784509844682, (Float_t) -0.03892971758879, (Float_t) 0.01683906213303, (Float_t) 0.00403009552351, (Float_t) -0.01147039862572, (Float_t) 0.03640166626278, (Float_t) -0.01941767987192 }, + {(Float_t)0.08717879977844, (Float_t)-2.62816311472146, (Float_t)-0.01000374016172, (Float_t)3.53734535817992, (Float_t)-0.06265852122368, (Float_t)-3.81003448678921, (Float_t)-0.01119328800950, (Float_t)3.91291636730132, (Float_t)-0.00114279372960, (Float_t)-3.53518605896288, (Float_t)0.02081333954769, (Float_t)2.71356866157873, (Float_t)-0.01603261863207, (Float_t)-1.86723311846592, (Float_t)0.01936763028546, (Float_t)1.12075382367659, (Float_t)0.00760044736442, (Float_t)-0.48574086886890, (Float_t)-0.00303979112271, (Float_t)0.11330544663849, (Float_t)-0.00075088605788 }, + +}; + + +static const Float_t ABButter[][2 * BUTTER_ORDER + 1] = { + {(Float_t) 0.99308203517541, (Float_t) -1.98611621154089, (Float_t) -1.98616407035082, (Float_t) 0.986211929160751, (Float_t) 0.99308203517541}, + {(Float_t) 0.992472550461293, (Float_t) -1.98488843762334, (Float_t) -1.98494510092258, (Float_t) 0.979389350028798, (Float_t) 0.992472550461293}, + {(Float_t) 0.989641019334721, (Float_t) -1.97917472731008, (Float_t) -1.97928203866944, (Float_t) 0.979389350028798, (Float_t) 0.989641019334721}, + {(Float_t) 0.98621192462708, (Float_t) -1.97223372919527, (Float_t) -1.97242384925416, (Float_t) 0.97261396931306, (Float_t) 0.98621192462708}, + {(Float_t) 0.98500175787242, (Float_t) -1.96977855582618, (Float_t) -1.97000351574484, (Float_t) 0.97022847566350, (Float_t) 0.98500175787242}, + {(Float_t) 0.97938932735214, (Float_t) -1.95835380975398, (Float_t) -1.95877865470428, (Float_t) 0.95920349965459, (Float_t) 0.97938932735214}, + {(Float_t) 0.97531843204928, (Float_t) -1.95002759149878, (Float_t) -1.95063686409857, (Float_t) 0.95124613669835, (Float_t) 0.97531843204928}, + {(Float_t) 0.97316523498161, (Float_t) -1.94561023566527, (Float_t) -1.94633046996323, (Float_t) 0.94705070426118, (Float_t) 0.97316523498161}, + {(Float_t) 0.96454515552826, (Float_t) -1.92783286977036, (Float_t) -1.92909031105652, (Float_t) 0.93034775234268, (Float_t) 0.96454515552826}, + {(Float_t) 0.96009142950541, (Float_t) -1.91858953033784, (Float_t) -1.92018285901082, (Float_t) 0.92177618768381, (Float_t) 0.96009142950541}, + {(Float_t) 0.95856916599601, (Float_t) -1.91542108074780, (Float_t) -1.91713833199203, (Float_t) 0.91885558323625, (Float_t) 0.95856916599601}, + {(Float_t) 0.94597685600279, (Float_t) -1.88903307939452, (Float_t) -1.89195371200558, (Float_t) 0.89487434461664, (Float_t) 0.94597685600279}, + + {(Float_t)0.96535326815829, (Float_t)-1.92950577983524, (Float_t)-1.93070653631658, (Float_t)0.93190729279793, (Float_t)0.96535326815829 }, + {(Float_t)0.98252400815195, (Float_t)-1.96474258269041, (Float_t)-1.96504801630391, (Float_t)0.96535344991740, (Float_t)0.98252400815195 }, + +}; + +#ifdef WIN32 +#ifndef __GNUC__ +#pragma warning ( default : 4305 ) +#endif +#endif + +// When calling these filter procedures, make sure that ip[-order] and op[-order] point to real data! + +// If your compiler complains that "'operation on 'output' may be undefined", you can +// either ignore the warnings or uncomment the three "y" lines (and comment out the indicated line) + +void +GainAnalyzer::filterYule(const Float_t *input, Float_t *output, size_t nSamples, const Float_t *kernel) +{ + + while (nSamples--) { + *output = 1e-10f /* 1e-10 is a hack to avoid slowdown because of denormals */ + + input[0] * kernel[0] + - output[-1] * kernel[1] + + input[-1] * kernel[2] + - output[-2] * kernel[3] + + input[-2] * kernel[4] + - output[-3] * kernel[5] + + input[-3] * kernel[6] + - output[-4] * kernel[7] + + input[-4] * kernel[8] + - output[-5] * kernel[9] + + input[-5] * kernel[10] + - output[-6] * kernel[11] + + input[-6] * kernel[12] + - output[-7] * kernel[13] + + input[-7] * kernel[14] + - output[-8] * kernel[15] + + input[-8] * kernel[16] + - output[-9] * kernel[17] + + input[-9] * kernel[18] + - output[-10] * kernel[19] + + input[-10] * kernel[20]; + ++output; + ++input; + } +} + +void +GainAnalyzer::filterButter(const Float_t *input, Float_t *output, size_t nSamples, const Float_t *kernel) { + + while (nSamples--) { + *output = + input[0] * kernel[0] + - output[-1] * kernel[1] + + input[-1] * kernel[2] + - output[-2] * kernel[3] + + input[-2] * kernel[4]; + ++output; + ++input; + } +} + + +// returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not + +int +GainAnalyzer::ResetSampleFrequency(int samplefreq) { + int i; + + // zero out initial values + for (i = 0; i < MAX_ORDER; i++) + linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = (Float_t) 0.; + + switch ((int) (samplefreq)) { + case 96000: + freqindex = 0; + break; + case 88200: + freqindex = 1; + break; + case 64000: + freqindex = 2; + break; + case 49716: // I could not find a table for this but we need to be able to handle this frequency for OPL, even if this means not getting the proper level. + case 48000: + freqindex = 3; + break; + case 44100: + freqindex = 4; + break; + case 32000: + freqindex = 5; + break; + case 24000: + freqindex = 6; + break; + case 22050: + freqindex = 7; + break; + case 16000: + freqindex = 8; + break; + case 12000: + freqindex = 9; + break; + case 11025: + case 11111: // SW shareware tries to play a VOC with this frequency as music. This is close enough to 11025 to use the same table. + freqindex = 10; + break; + case 8000: + freqindex = 11; + break; + + // These two were added for XA support. + case 18900: + freqindex = 12; + break; + case 37800: + freqindex = 13; + break; + default: + return INIT_GAIN_ANALYSIS_ERROR; + } + + sampleWindow = (int) ceil(samplefreq * RMS_WINDOW_TIME); + + lsum = 0.; + rsum = 0.; + totsamp = 0; + + memset(A, 0, sizeof(A)); + + return INIT_GAIN_ANALYSIS_OK; +} + +int +GainAnalyzer::InitGainAnalysis(int samplefreq) { + memset(this, 0, sizeof(*this)); + if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) { + return INIT_GAIN_ANALYSIS_ERROR; + } + + linpre = linprebuf + MAX_ORDER; + rinpre = rinprebuf + MAX_ORDER; + lstep = lstepbuf + MAX_ORDER; + rstep = rstepbuf + MAX_ORDER; + lout = loutbuf + MAX_ORDER; + rout = routbuf + MAX_ORDER; + + memset(B, 0, sizeof(B)); + + return INIT_GAIN_ANALYSIS_OK; +} + +// returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not + +static __inline double fsqr(const double d) { + return d * d; +} + +int +GainAnalyzer::AnalyzeSamples(const Float_t *left_samples, const Float_t *right_samples, size_t num_samples, int num_channels) { + const Float_t *curleft; + const Float_t *curright; + int64_t batchsamples; + int64_t cursamples; + int64_t cursamplepos; + int i; + + if (num_samples == 0) + return GAIN_ANALYSIS_OK; + + cursamplepos = 0; + batchsamples = (int64_t) num_samples; + + switch (num_channels) { + case 1: + right_samples = left_samples; + case 2: + break; + default: + return GAIN_ANALYSIS_ERROR; + } + + if (num_samples < MAX_ORDER) { + memcpy(linprebuf + MAX_ORDER, left_samples, num_samples * sizeof(Float_t)); + memcpy(rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t)); + } else { + memcpy(linprebuf + MAX_ORDER, left_samples, MAX_ORDER * sizeof(Float_t)); + memcpy(rinprebuf + MAX_ORDER, right_samples, MAX_ORDER * sizeof(Float_t)); + } + + while (batchsamples > 0) { + cursamples = batchsamples > sampleWindow - totsamp ? sampleWindow - totsamp : batchsamples; + if (cursamplepos < MAX_ORDER) { + curleft = linpre + cursamplepos; + curright = rinpre + cursamplepos; + if (cursamples > MAX_ORDER - cursamplepos) + cursamples = MAX_ORDER - cursamplepos; + } else { + curleft = left_samples + cursamplepos; + curright = right_samples + cursamplepos; + } + + filterYule(curleft, lstep + totsamp, cursamples, ABYule[freqindex]); + filterYule(curright, rstep + totsamp, cursamples, ABYule[freqindex]); + + filterButter(lstep + totsamp, lout + totsamp, cursamples, ABButter[freqindex]); + filterButter(rstep + totsamp, rout + totsamp, cursamples, ABButter[freqindex]); + + curleft = lout + totsamp; // Get the squared values + curright = rout + totsamp; + + i = cursamples % 16; + while (i--) { + lsum += fsqr(*curleft++); + rsum += fsqr(*curright++); + } + i = cursamples / 16; + while (i--) { + lsum += fsqr(curleft[0]) + + fsqr(curleft[1]) + + fsqr(curleft[2]) + + fsqr(curleft[3]) + + fsqr(curleft[4]) + + fsqr(curleft[5]) + + fsqr(curleft[6]) + + fsqr(curleft[7]) + + fsqr(curleft[8]) + + fsqr(curleft[9]) + + fsqr(curleft[10]) + + fsqr(curleft[11]) + + fsqr(curleft[12]) + + fsqr(curleft[13]) + + fsqr(curleft[14]) + + fsqr(curleft[15]); + curleft += 16; + rsum += fsqr(curright[0]) + + fsqr(curright[1]) + + fsqr(curright[2]) + + fsqr(curright[3]) + + fsqr(curright[4]) + + fsqr(curright[5]) + + fsqr(curright[6]) + + fsqr(curright[7]) + + fsqr(curright[8]) + + fsqr(curright[9]) + + fsqr(curright[10]) + + fsqr(curright[11]) + + fsqr(curright[12]) + + fsqr(curright[13]) + + fsqr(curright[14]) + + fsqr(curright[15]); + curright += 16; + } + + batchsamples -= cursamples; + cursamplepos += cursamples; + totsamp += cursamples; + if (totsamp == sampleWindow) { // Get the Root Mean Square (RMS) for this set of samples + double val = STEPS_per_dB * 10. * log10((lsum + rsum) / totsamp * 0.5 + 1.e-37); + int ival = (int) val; + if (ival < 0) ival = 0; + if (ival >= (int) (sizeof(A) / sizeof(*A))) ival = sizeof(A) / sizeof(*A) - 1; + A[ival]++; + lsum = rsum = 0.; + memmove(loutbuf, loutbuf + totsamp, MAX_ORDER * sizeof(Float_t)); + memmove(routbuf, routbuf + totsamp, MAX_ORDER * sizeof(Float_t)); + memmove(lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(Float_t)); + memmove(rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(Float_t)); + totsamp = 0; + } + if (totsamp > + sampleWindow) // somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow + return GAIN_ANALYSIS_ERROR; + } + if (num_samples < MAX_ORDER) { + memmove(linprebuf, linprebuf + num_samples, (MAX_ORDER - num_samples) * sizeof(Float_t)); + memmove(rinprebuf, rinprebuf + num_samples, (MAX_ORDER - num_samples) * sizeof(Float_t)); + memcpy(linprebuf + MAX_ORDER - num_samples, left_samples, num_samples * sizeof(Float_t)); + memcpy(rinprebuf + MAX_ORDER - num_samples, right_samples, num_samples * sizeof(Float_t)); + } else { + memcpy(linprebuf, left_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t)); + memcpy(rinprebuf, right_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t)); + } + + return GAIN_ANALYSIS_OK; +} + + +Float_t +GainAnalyzer::analyzeResult(const unsigned int *Array, size_t len) { + unsigned int elems; + signed int upper; + size_t i; + + elems = 0; + for (i = 0; i < len; i++) + elems += Array[i]; + if (elems == 0) + return GAIN_NOT_ENOUGH_SAMPLES; + + upper = (signed int) ceil(elems * (1. - RMS_PERCENTILE)); + for (i = len; i-- > 0;) { + if ((upper -= Array[i]) <= 0) + break; + } + + return (Float_t) ((Float_t) PINK_REF - (Float_t) i / (Float_t) STEPS_per_dB); +} + + +Float_t +GainAnalyzer::GetTitleGain(void) { + Float_t retval; + int i; + + retval = analyzeResult(A, sizeof(A) / sizeof(*A)); + + for (i = 0; i < (int) (sizeof(A) / sizeof(*A)); i++) { + B[i] += A[i]; + A[i] = 0; + } + + for (i = 0; i < MAX_ORDER; i++) + linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f; + + totsamp = 0; + lsum = rsum = 0.; + return retval; +} + + +Float_t +GainAnalyzer::GetAlbumGain(void) { + return analyzeResult(B, sizeof(B) / sizeof(*B)); +} + + +/* end of gain_analysis.c */ diff --git a/src/common/thirdparty/gain_analysis.h b/src/common/thirdparty/gain_analysis.h new file mode 100644 index 00000000000..076da30d4ef --- /dev/null +++ b/src/common/thirdparty/gain_analysis.h @@ -0,0 +1,92 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001-2009 David Robinson and Glen Sawyer + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * coding by Glen Sawyer (mp3gain@hotmail.com) 735 W 255 N, Orem, UT 84057-4505 USA + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +#ifndef GAIN_ANALYSIS_H +#define GAIN_ANALYSIS_H + +#include +#include + +#define GAIN_NOT_ENOUGH_SAMPLES (-24601) +#define GAIN_ANALYSIS_ERROR 0 +#define GAIN_ANALYSIS_OK 1 + +#define INIT_GAIN_ANALYSIS_ERROR 0 +#define INIT_GAIN_ANALYSIS_OK 1 + +#define STEPS_per_dB 100. // Table entries per dB +#define MAX_dB 120. // Table entries for 0...MAX_dB (normal max. values are 70...80 dB) +#define MAX_SAMP_FREQ 96000. // maximum allowed sample frequency [Hz] +#define RMS_WINDOW_TIME 0.050 // Time slice size [s] + +#define YULE_ORDER 10 +#define BUTTER_ORDER 2 +#define MAX_ORDER (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER) +#define MAX_SAMPLES_PER_WINDOW (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1) // max. Samples per Time slice + +typedef float Float_t; // Type used for filtering + +struct GainAnalyzer +{ + int InitGainAnalysis(int samplefreq); + + int AnalyzeSamples(const Float_t *left_samples, const Float_t *right_samples, size_t num_samples, int num_channels); + + int ResetSampleFrequency(int samplefreq); + + Float_t GetTitleGain(void); + + Float_t GetAlbumGain(void); + +private: + Float_t linprebuf[MAX_ORDER * 2]; + Float_t *linpre; // left input samples, with pre-buffer + Float_t lstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *lstep; // left "first step" (i.e. post first filter) samples + Float_t loutbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *lout; // left "out" (i.e. post second filter) samples + Float_t rinprebuf[MAX_ORDER * 2]; + Float_t *rinpre; // right input samples ... + Float_t rstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *rstep; + Float_t routbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *rout; + long sampleWindow; // number of samples required to reach number of milliseconds required for RMS window + long totsamp; + double lsum; + double rsum; + int freqindex; + unsigned int A[(size_t) (STEPS_per_dB * MAX_dB)]; + unsigned int B[(size_t) (STEPS_per_dB * MAX_dB)]; + + void filterYule(const Float_t* input, Float_t* output, size_t nSamples, const Float_t* kernel); + void filterButter(const Float_t* input, Float_t* output, size_t nSamples, const Float_t* kernel); + Float_t analyzeResult(const unsigned int* Array, size_t len); + +}; + +#endif /* GAIN_ANALYSIS_H */ diff --git a/src/common/thirdparty/libsmackerdec/COPYING b/src/common/thirdparty/libsmackerdec/COPYING new file mode 100644 index 00000000000..00b4fedfe7e --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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; either + version 2.1 of the License, or (at your option) any later version. + + 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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/src/common/thirdparty/libsmackerdec/include/BitReader.h b/src/common/thirdparty/libsmackerdec/include/BitReader.h new file mode 100644 index 00000000000..1bf12b2ca6b --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/include/BitReader.h @@ -0,0 +1,50 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef _SmackerBitReader_h_ +#define _SmackerBitReader_h_ + +#include +#include "FileStream.h" +#include "tarray.h" + +namespace SmackerCommon { + +class BitReader +{ + public: + BitReader(const uint8_t *data, uint32_t size) : bitData(data), totalSize(size) { } + ~BitReader() = default; + uint32_t GetBit(); + uint32_t GetBits(uint32_t n); + void SkipBits(uint32_t n); + + uint32_t GetSize(); + uint32_t GetPosition(); + + private: + const uint8_t *bitData = nullptr; + uint32_t totalSize = 0; + uint32_t currentOffset = 0; + uint32_t bytesRead = 0; +}; + +} // close namespace SmackerCommon + +#endif diff --git a/src/common/thirdparty/libsmackerdec/include/FileStream.h b/src/common/thirdparty/libsmackerdec/include/FileStream.h new file mode 100644 index 00000000000..034ccb7336a --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/include/FileStream.h @@ -0,0 +1,63 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef _SmackerFileStream_h_ +#define _SmackerFileStream_h_ + +#include +#include "files.h" + +namespace SmackerCommon { + +class FileStream +{ + public: + + bool Open(const char *fileName); + bool Is_Open() { return file.isOpen(); } + void Close() { file.Close(); } + + int32_t ReadBytes(uint8_t *data, uint32_t nBytes) + { + return (uint32_t)file.Read(data, static_cast(nBytes)); + } + + uint64_t ReadUint64LE() { return file.ReadUInt64(); } + uint32_t ReadUint32LE() { return file.ReadUInt32(); } + uint16_t ReadUint16LE() { return file.ReadUInt16(); } + uint8_t ReadByte() { return file.ReadInt8(); } + + + enum SeekDirection{ + kSeekCurrent = SEEK_CUR, + kSeekStart = SEEK_SET, + kSeekEnd = SEEK_END + }; + + int32_t Seek(int32_t offset, SeekDirection dir = kSeekStart) { return (int)file.Seek(offset, (FileReader::ESeek) dir); } + int32_t Skip(int32_t offset) { return (int)Seek(offset, kSeekCurrent); } + int32_t GetPosition() { return (int)file.Tell(); } + + private: + FileReader file; +}; + +} // close namespace SmackerCommon + +#endif diff --git a/src/common/thirdparty/libsmackerdec/include/HuffmanVLC.h b/src/common/thirdparty/libsmackerdec/include/HuffmanVLC.h new file mode 100644 index 00000000000..668249317fa --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/include/HuffmanVLC.h @@ -0,0 +1,43 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef _SmackerHuffmanVLC_h_ +#define _SmackerHuffmanVLC_h_ + +#include +#include "BitReader.h" +#include + +namespace SmackerCommon { + +struct VLC +{ + uint32_t symbol; + uint32_t code; +}; + +typedef std::vector< std::vector > VLCtable; + +uint16_t VLC_GetCodeBits(BitReader &bits, VLCtable &table); +void VLC_InitTable (VLCtable &table, uint32_t maxLength, uint32_t size, int *lengths, uint32_t *bits); +uint32_t VLC_GetSize (VLCtable &table); + +} // close namespace SmackerCommon + +#endif diff --git a/src/common/thirdparty/libsmackerdec/include/LogError.h b/src/common/thirdparty/libsmackerdec/include/LogError.h new file mode 100644 index 00000000000..b5b8b5f36c8 --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/include/LogError.h @@ -0,0 +1,31 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#ifndef _SmackerLogError_h_ +#define _SmackerLogError_h_ + +//#include + +namespace SmackerCommon { + +//void LogError(const std::string &error); + +} // close namespace SmackerCommon + +#endif \ No newline at end of file diff --git a/src/common/thirdparty/libsmackerdec/include/SmackerDecoder.h b/src/common/thirdparty/libsmackerdec/include/SmackerDecoder.h new file mode 100644 index 00000000000..e9a8b1e27b1 --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/include/SmackerDecoder.h @@ -0,0 +1,185 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +/* This code is based on smacker.c from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * below is the license from smacker.c + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Smacker decoder + * Copyright (c) 2006 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SmackerDecoder_h_ +#define _SmackerDecoder_h_ + +#include +#include "FileStream.h" +#include "BitReader.h" +#include +#include +#include +#include + +// exportable interface +struct SmackerHandle +{ + bool isValid; + int instanceIndex; +}; + +struct SmackerAudioInfo +{ + uint32_t sampleRate; + uint8_t nChannels; + + uint32_t idealBufferSize; +}; + +SmackerHandle Smacker_Open (const char *fileName); +void Smacker_Close (SmackerHandle &handle); +uint32_t Smacker_GetNumAudioTracks (SmackerHandle &handle); +SmackerAudioInfo Smacker_GetAudioTrackDetails (SmackerHandle &handle, uint32_t trackIndex); +uint32_t Smacker_GetAudioData (SmackerHandle &handle, uint32_t trackIndex, int16_t *data); +void Smacker_DisableAudioTrack (SmackerHandle &handle, uint32_t trackIndex); +uint32_t Smacker_GetNumFrames (SmackerHandle &handle); +void Smacker_GetFrameSize (SmackerHandle &handle, uint32_t &width, uint32_t &height); +uint32_t Smacker_GetCurrentFrameNum (SmackerHandle &handle); +uint32_t Smacker_GetNextFrame (SmackerHandle &handle); +float Smacker_GetFrameRate (SmackerHandle &handle); +void Smacker_GetPalette (SmackerHandle &handle, uint8_t *palette); +void Smacker_GetFrame (SmackerHandle &handle, uint8_t *frame); +void Smacker_GotoFrame (SmackerHandle &handle, uint32_t frameNum); + +const int kMaxAudioTracks = 7; + +// forward declare +struct HuffContext; +struct DBCtx; + +struct SmackerPacket +{ + size_t size = 0; + std::unique_ptr data; +}; + +struct SmackerAudioTrack +{ + uint32_t sizeInBytes; + uint32_t flags; + uint32_t sampleRate; + uint8_t nChannels; + uint8_t bitsPerSample; +// int compressionType; + + uint8_t *buffer; + uint32_t bufferSize; + + uint32_t bytesReadThisFrame; + std::deque packetData; +}; + +class SmackerDecoder +{ + public: + uint32_t frameWidth; + uint32_t frameHeight; + + SmackerDecoder(); + ~SmackerDecoder(); + + bool Open(const char *fileName); + void GetPalette(uint8_t *palette); + void GetFrame(uint8_t *frame); + + uint32_t GetNumAudioTracks(); + SmackerAudioInfo GetAudioTrackDetails(uint32_t trackIndex); + uint32_t GetAudioData(uint32_t trackIndex, int16_t *audioBuffer); + void DisableAudioTrack(uint32_t trackIndex); + uint32_t GetNumFrames(); + uint32_t GetCurrentFrameNum(); + float GetFrameRate(); + void GetNextFrame(); + void GotoFrame(uint32_t frameNum); + + private: + SmackerCommon::FileStream file; + char signature[4]; + std::mutex fileMutex; + + // video related members + uint32_t nFrames; + uint32_t fps; // frames per second + + uint8_t palette[768]; + uint8_t *picture; + + bool isVer4; + + uint32_t currentReadFrame; + std::vector packetData; + + std::deque framePacketData; + SmackerAudioTrack audioTracks[kMaxAudioTracks]; + + uint32_t treeSize; + uint32_t mMapSize, MClrSize, fullSize, typeSize; + + std::vector mmap_tbl; + std::vector mclr_tbl; + std::vector full_tbl; + std::vector type_tbl; + + int mmap_last[3], mclr_last[3], full_last[3], type_last[3]; + + std::vector frameSizes; + std::vector frameFlags; + + uint32_t currentFrame; + int32_t nextPos; + int32_t firstFrameFilePos; + + bool DecodeHeaderTrees(); + int DecodeHeaderTree(SmackerCommon::BitReader &bits, std::vector &recodes, int *last, int size); + int DecodeTree(SmackerCommon::BitReader &bits, HuffContext *hc, uint32_t prefix, int length); + int DecodeBigTree(SmackerCommon::BitReader &bits, HuffContext *hc, DBCtx *ctx); + int GetCode(SmackerCommon::BitReader &bits, std::vector &recode, int *last); + int ReadPacket(); + int DecodeFrame(const uint8_t *dataPtr, uint32_t frameSize); + void GetFrameSize(uint32_t &width, uint32_t &height); + int DecodeAudio(const uint8_t *dataPtr, uint32_t size, SmackerAudioTrack &track); +}; + +#endif diff --git a/src/common/thirdparty/libsmackerdec/src/BitReader.cpp b/src/common/thirdparty/libsmackerdec/src/BitReader.cpp new file mode 100644 index 00000000000..604848ec6ed --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/src/BitReader.cpp @@ -0,0 +1,71 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#include "BitReader.h" +#include + +namespace SmackerCommon { + +uint32_t BitReader::GetSize() +{ + return totalSize * 8; +} + +uint32_t BitReader::GetPosition() +{ + return currentOffset; +} + +uint32_t BitReader::GetBit() +{ + uint32_t ret = (bitData[currentOffset>>3]>>(currentOffset&7))&1; + currentOffset++; + return ret; +} + +uint32_t BitReader::GetBits(uint32_t n) +{ + uint32_t ret = 0; + + int bitsTodo = n; + + uint32_t theShift = 0; + + while (bitsTodo) + { + uint32_t bit = GetBit(); + bit <<= theShift; + + theShift++; + + ret |= bit; + + bitsTodo--; + } + + return ret; +} + +void BitReader::SkipBits(uint32_t n) +{ + GetBits(n); +} + +} // close namespace SmackerCommon + diff --git a/src/common/thirdparty/libsmackerdec/src/FileStream.cpp b/src/common/thirdparty/libsmackerdec/src/FileStream.cpp new file mode 100644 index 00000000000..f7845136b51 --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/src/FileStream.cpp @@ -0,0 +1,40 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#include "FileStream.h" +#include "filesystem.h" +#include +#include "cmdlib.h" + +namespace SmackerCommon { + +bool FileStream::Open(const char *fileName) +{ + FString fixedname = fileName; + FixPathSeperator(fixedname); + file = fileSystem.OpenFileReader(fixedname.GetChars()); + if (!file.isOpen()) + { + // log error + return false; + } + return true; +} + +} // close namespace SmackerCommon diff --git a/src/common/thirdparty/libsmackerdec/src/HuffmanVLC.cpp b/src/common/thirdparty/libsmackerdec/src/HuffmanVLC.cpp new file mode 100644 index 00000000000..400e622f8fd --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/src/HuffmanVLC.cpp @@ -0,0 +1,71 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#include + +namespace SmackerCommon { + +uint16_t VLC_GetCodeBits(BitReader &bits, VLCtable &table) +{ + uint32_t codeBits = 0; + + // search each length array + for (uint32_t i = 0; i < table.size(); i++) + { + // get and add a new bit to codeBits + uint32_t theBit = bits.GetBit() << i; + codeBits |= theBit; + + // search for a code match + for (uint32_t j = 0; j < table[i].size(); j++) + { + if (codeBits == table[i][j].code) + { + return table[i][j].symbol; + } + } + } + + // shouldn't get here.. + return 0; +} + +void VLC_InitTable(VLCtable &table, uint32_t maxLength, uint32_t size, int *lengths, uint32_t *bits) +{ + table.resize(maxLength); + + for (uint32_t i = 0; i < size; i++) + { + VLC newCode; + newCode.symbol = i; + newCode.code = bits[i]; + + uint32_t codeLength = lengths[i]; + + if (codeLength) + table[codeLength - 1].push_back(newCode); + } +} + +uint32_t VLC_GetSize(VLCtable &table) +{ + return uint32_t(table.size()); +} + +} // close namespace SmackerCommon diff --git a/src/common/thirdparty/libsmackerdec/src/LogError.cpp b/src/common/thirdparty/libsmackerdec/src/LogError.cpp new file mode 100644 index 00000000000..46a45bb0a64 --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/src/LogError.cpp @@ -0,0 +1,33 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +#include "LogError.h" + +namespace SmackerCommon { + +#if 0 +static std::string LastError; + +void LogError(const std::string &error) +{ + LastError = error; +} +#endif + +} // close namespace SmackerCommon diff --git a/src/common/thirdparty/libsmackerdec/src/SmackerDecoder.cpp b/src/common/thirdparty/libsmackerdec/src/SmackerDecoder.cpp new file mode 100644 index 00000000000..ff69f3b2c20 --- /dev/null +++ b/src/common/thirdparty/libsmackerdec/src/SmackerDecoder.cpp @@ -0,0 +1,1255 @@ +/* + * libsmackerdec - Smacker video decoder + * Copyright (C) 2011 Barry Duncan + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + */ + +/* This code is heavily based on smacker.c from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * below is the license from smacker.c + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Smacker decoder + * Copyright (c) 2006 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "SmackerDecoder.h" +#include "HuffmanVLC.h" +#include "LogError.h" +#include "printf.h" +#include "limits.h" +#include +#include +#include + +std::vector classInstances; + +SmackerHandle Smacker_Open(const char* fileName) +{ + SmackerHandle newHandle; + newHandle.isValid = false; + newHandle.instanceIndex = -1; + + SmackerDecoder *newDecoder = new SmackerDecoder(); + if (!newDecoder->Open(fileName)) + { + delete newDecoder; + return newHandle; + } + + // add instance to global instance vector + classInstances.push_back(newDecoder); + + // get a handle ID + newHandle.instanceIndex = int(classInstances.size()) - 1; + + // loaded ok, make handle valid + newHandle.isValid = true; + + return newHandle; +} + +void Smacker_Close(SmackerHandle &handle) +{ + if (!classInstances.at(handle.instanceIndex)) + { + // invalid handle + return; + } + + // close bink decoder + delete classInstances[handle.instanceIndex]; + classInstances[handle.instanceIndex] = 0; + + handle.instanceIndex = -1; + handle.isValid = false; +} + +uint32_t Smacker_GetNumAudioTracks(SmackerHandle &handle) +{ + return classInstances[handle.instanceIndex]->GetNumAudioTracks(); +} + +SmackerAudioInfo Smacker_GetAudioTrackDetails(SmackerHandle &handle, uint32_t trackIndex) +{ + return classInstances[handle.instanceIndex]->GetAudioTrackDetails(trackIndex); +} + +/* Get a frame's worth of audio data. + * + * 'data' needs to be a pointer to allocated memory that this function will fill. + * You can find the size (in bytes) to make this buffer by calling Bink_GetAudioTrackDetails() + * and checking the 'idealBufferSize' member in the returned AudioInfo struct + */ +uint32_t Smacker_GetAudioData(SmackerHandle &handle, uint32_t trackIndex, int16_t *data) +{ + return classInstances[handle.instanceIndex]->GetAudioData(trackIndex, data); +} + +/* Disables an audio track if it's enabled. + * + * When getting video or audio data, encoded data is stored for other tracks so + * they can be read and decoded later. This function prevents a build-up of + * encoded audio data for the specified track if such data isn't going to be + * decoded and read by the caller. + */ +void Smacker_DisableAudioTrack(SmackerHandle &handle, uint32_t trackIndex) +{ + classInstances[handle.instanceIndex]->DisableAudioTrack(trackIndex); +} + +uint32_t Smacker_GetNumFrames(SmackerHandle &handle) +{ + return classInstances[handle.instanceIndex]->GetNumFrames(); +} + +void Smacker_GetFrameSize(SmackerHandle &handle, uint32_t &width, uint32_t &height) +{ + width = classInstances[handle.instanceIndex]->frameWidth; + height = classInstances[handle.instanceIndex]->frameHeight; +} + +uint32_t Smacker_GetCurrentFrameNum(SmackerHandle &handle) +{ + return classInstances[handle.instanceIndex]->GetCurrentFrameNum(); +} + +uint32_t Smacker_GetNextFrame(SmackerHandle &handle) +{ + SmackerDecoder *decoder = classInstances[handle.instanceIndex]; + + uint32_t frameIndex = decoder->GetCurrentFrameNum(); + + decoder->GetNextFrame(); + + return frameIndex; +} + +float Smacker_GetFrameRate(SmackerHandle &handle) +{ + return classInstances[handle.instanceIndex]->GetFrameRate(); +} + +void Smacker_GetPalette(SmackerHandle &handle, uint8_t *palette) +{ + classInstances[handle.instanceIndex]->GetPalette(palette); +} + +void Smacker_GetFrame(SmackerHandle &handle, uint8_t *frame) +{ + classInstances[handle.instanceIndex]->GetFrame(frame); +} + +void Smacker_GotoFrame(SmackerHandle &handle, uint32_t frameNum) +{ + classInstances[handle.instanceIndex]->GotoFrame(frameNum); +} + +SmackerDecoder::SmackerDecoder() +{ + isVer4 = false; + currentReadFrame = 0; + currentFrame = 0; + picture = 0; + nextPos = 0; + + for (int i = 0; i < kMaxAudioTracks; i++) + { + audioTracks[i].buffer = 0; + } +} + +SmackerDecoder::~SmackerDecoder() +{ + for (int i = 0; i < kMaxAudioTracks; i++) + { + delete[] audioTracks[i].buffer; + } + + delete[] picture; +} + +// from bswap.h +static /*av_always_inline av_const*/ uint16_t av_bswap16(uint16_t x) +{ + x= (x>>8) | (x<<8); + return x; +} + +/* possible runs of blocks */ +static const int block_runs[64] = { + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 128, 256, 512, 1024, 2048 }; + +enum SmkBlockTypes { + SMK_BLK_MONO = 0, + SMK_BLK_FULL = 1, + SMK_BLK_SKIP = 2, + SMK_BLK_FILL = 3 }; + +/* palette used in Smacker */ +static const uint8_t smk_pal[64] = { + 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, + 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, + 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, + 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, + 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, + 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, + 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF, + 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF +}; + +enum SAudFlags { + SMK_AUD_PACKED = 0x80000000, + SMK_AUD_PRESENT = 0x40000000, + SMK_AUD_16BITS = 0x20000000, + SMK_AUD_STEREO = 0x10000000, + SMK_AUD_BINKAUD = 0x08000000, + SMK_AUD_USEDCT = 0x04000000 +}; + +const int kSMKpal = 0x01; +const int kFlagRingFrame = 0x01; + +const int kTreeBits = 9; +const int kSMKnode = 0x80000000; + +const char *kSMK2iD = "SMK2"; +const char *kSMK4iD = "SMK4"; + + +/** + * Context used for code reconstructing + */ +typedef struct HuffContext { + int length = 0; + int maxlength = 0; + int current = 0; + + std::vector bits; + std::vector lengths; + std::vector values; + +} HuffContext; + +/* common parameters used for decode_bigtree */ +typedef struct DBCtx { + SmackerCommon::VLCtable v1; + SmackerCommon::VLCtable v2; + std::vector recode1, recode2; + int escapes[3]; + int *last; + int lcur; +} DBCtx; + + +static void last_reset(std::vector &recode, int *last) { + recode[last[0]] = recode[last[1]] = recode[last[2]] = 0; +} + +/* get code and update history */ +int SmackerDecoder::GetCode(SmackerCommon::BitReader &bits, std::vector &recode, int *last) +{ + int *table = &recode[0]; + + int v, b; + + b = bits.GetPosition(); + + while (*table & kSMKnode) + { + if (bits.GetBit()) + table += (*table) & (~kSMKnode); + table++; + } + v = *table; + b = bits.GetPosition() - b; + + if (v != recode[last[0]]) { + recode[last[2]] = recode[last[1]]; + recode[last[1]] = recode[last[0]]; + recode[last[0]] = v; + } + return v; +} + +bool SmackerDecoder::Open(const char *fileName) +{ + // open the file (read only) + file.Open(fileName); + if (!file.Is_Open()) + { + Printf("SmackerDecoder::Open() - Can't open file %s\n", fileName); + return false; + } + + // check the file signature + file.ReadBytes((uint8_t*)signature, 4); + if (memcmp(signature, kSMK2iD, 4) != 0 + && memcmp(signature, kSMK4iD, 4) != 0) + { + Printf("SmackerDecoder::Open() - Unknown Smacker signature\n"); + return false; + } + + if (!memcmp(signature, kSMK4iD, 4)) { + isVer4 = true; + } + + frameWidth = file.ReadUint32LE(); + frameHeight = file.ReadUint32LE(); + nFrames = file.ReadUint32LE(); + + picture = new uint8_t[frameWidth * frameHeight]; + + int32_t frameRate = file.ReadUint32LE(); + + if (frameRate > 0) + fps = 1000 / frameRate; + else if (frameRate < 0) + fps = 100000 / (-frameRate); + else + fps = 10; + + uint32_t flags = file.ReadUint32LE(); + + if (flags & kFlagRingFrame) { + nFrames++; + } + + for (int i = 0; i < kMaxAudioTracks; i++) { + audioTracks[i].sizeInBytes = file.ReadUint32LE(); + } + + treeSize = file.ReadUint32LE(); + mMapSize = file.ReadUint32LE(); + MClrSize = file.ReadUint32LE(); + fullSize = file.ReadUint32LE(); + typeSize = file.ReadUint32LE(); + + for (int i = 0; i < kMaxAudioTracks; i++) { + audioTracks[i].flags = file.ReadUint32LE(); + } + + // skip pad + file.Skip(4); + + if (nFrames > 0xFFFFFF) + { + Printf("SmackerDecoder::Open() - Too many frames\n"); + return false; + } + + frameSizes.resize(nFrames); + frameFlags.resize(nFrames); + + // read frame info + for (uint32_t i = 0; i < nFrames; i++) { + frameSizes[i] = file.ReadUint32LE(); + } + for (uint32_t i = 0; i < nFrames; i++) { + frameFlags[i] = file.ReadByte(); + } + + auto maxFrameSize = std::max_element(frameSizes.begin(), frameSizes.end()); + if (maxFrameSize != frameSizes.end()) + packetData.reserve(*maxFrameSize); + + // handle possible audio streams + for (int i = 0; i < kMaxAudioTracks; i++) + { + audioTracks[i].buffer = 0; + audioTracks[i].bufferSize = 0; + audioTracks[i].bytesReadThisFrame = 0; + + // Disable non-consecutive enabled tracks. Not sure how to otherwise report + // them properly for Smacker_GetNumAudioTracks. + if (i > 0 && !(audioTracks[i-1].flags & SMK_AUD_PRESENT)) + audioTracks[i].flags &= ~SMK_AUD_PRESENT; + + if (audioTracks[i].flags & 0xFFFFFF) + { +/* + if (audioTracks[i].flags & SMK_AUD_BINKAUD) { + audioTracks[i].compressionType = SMK_AUD_BINKAUD; + } else if (audioTracks[i].flags & SMK_AUD_USEDCT) { + audioTracks[i].compressionType = SMK_AUD_USEDCT; + } else if (audioTracks[i].flags & SMK_AUD_PACKED){ + ast[i]->codec->codec_id = CODEC_ID_SMACKAUDIO; + ast[i]->codec->codec_tag = MKTAG('S', 'M', 'K', 'A'); + } else { + ast[i]->codec->codec_id = CODEC_ID_PCM_U8; + } +*/ + audioTracks[i].nChannels = (audioTracks[i].flags & SMK_AUD_STEREO) ? 2 : 1; + audioTracks[i].sampleRate = audioTracks[i].flags & 0xFFFFFF; + audioTracks[i].bitsPerSample = (audioTracks[i].flags & SMK_AUD_16BITS) ? 16 : 8; + } + } + + memset(palette, 0, 768); + + DecodeHeaderTrees(); + + // set nextPos to where we are now, as next data is frame 1 + nextPos = file.GetPosition(); + firstFrameFilePos = nextPos; + + // determine max buffer sizes for audio tracks +// file.Seek(nextPos, SmackerCommon::FileStream::kSeekStart); + + uint8_t frameFlag = frameFlags[0]; + + // skip over palette + if (frameFlag & kSMKpal) + { + uint32_t size = file.ReadByte(); + size = size * 4 - 1; + file.Skip(size); + } + + frameFlag >>= 1; + + for (int i = 0; i < kMaxAudioTracks; i++) + { + if (frameFlag & 1) + { + uint32_t size = file.ReadUint32LE(); + uint32_t unpackedSize = file.ReadUint32LE(); + + // If the track isn't 16-bit, double the buffer size for converting 8-bit to 16-bit. + if (!(audioTracks[i].flags & SMK_AUD_16BITS)) + unpackedSize *= 2; + + audioTracks[i].bufferSize = unpackedSize; + audioTracks[i].buffer = new uint8_t[unpackedSize]; + + // skip size + file.Skip(size - 8); + } + frameFlag >>= 1; + } + + return true; +} + +// static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length) +int SmackerDecoder::DecodeTree(SmackerCommon::BitReader &bits, HuffContext *hc, uint32_t prefix, int length) +{ + if (!bits.GetBit()) // Leaf + { + if (hc->current >= 256){ + Printf("SmackerDecoder::DecodeTree() - Tree size exceeded\n"); + return -1; + } + if (length){ + hc->bits[hc->current] = prefix; + hc->lengths[hc->current] = length; + } else { + hc->bits[hc->current] = 0; + hc->lengths[hc->current] = 0; + } + hc->values[hc->current] = bits.GetBits(8); + + hc->current++; + if (hc->maxlength < length) + hc->maxlength = length; + return 0; + } else { //Node + int r; + length++; + r = DecodeTree(bits, hc, prefix, length); + if (r) + return r; + return DecodeTree(bits, hc, prefix | (1 << (length - 1)), length); + } +} + +/** + * Decode header tree + */ +int SmackerDecoder::DecodeBigTree(SmackerCommon::BitReader &bits, HuffContext *hc, DBCtx *ctx) +{ + if (!bits.GetBit()) // Leaf + { + int val, i1, i2, b1, b2; + + i1 = 0; + i2 = 0; + + if (hc->current >= hc->length){ + Printf("SmackerDecoder::DecodeBigTree() - Tree size exceeded"); + return -1; + } + + b1 = bits.GetPosition(); + + if (VLC_GetSize(ctx->v1)) + { + i1 = VLC_GetCodeBits(bits, ctx->v1); + } + + b1 = bits.GetPosition() - b1; + b2 = bits.GetPosition(); + + if (VLC_GetSize(ctx->v2)) + { + i2 = VLC_GetCodeBits(bits, ctx->v2); + } + + b2 = bits.GetPosition() - b2; + if (i1 < 0 || i2 < 0) + return -1; + val = ctx->recode1[i1] | (ctx->recode2[i2] << 8); + if (val == ctx->escapes[0]) { + ctx->last[0] = hc->current; + val = 0; + } else if (val == ctx->escapes[1]) { + ctx->last[1] = hc->current; + val = 0; + } else if (val == ctx->escapes[2]) { + ctx->last[2] = hc->current; + val = 0; + } + + hc->values[hc->current++] = val; + return 1; + } else { //Node + int r = 0, t; + + t = hc->current++; + r = DecodeBigTree(bits, hc, ctx); + if (r < 0) + return r; + hc->values[t] = kSMKnode | r; + r++; + r += DecodeBigTree(bits, hc, ctx); + return r; + } +} + +/** + * Store large tree as Libav's vlc codes + */ +int SmackerDecoder::DecodeHeaderTree(SmackerCommon::BitReader &bits, std::vector &recodes, int *last, int size) +{ + HuffContext huff; + HuffContext tmp1, tmp2; + int escapes[3]; + DBCtx ctx; + + if ((uint32_t)size >= UINT_MAX>>4) + { + Printf("SmackerDecoder::DecodeHeaderTree() - Size too large\n"); + return -1; + } + + tmp1.length = 256; + tmp1.maxlength = 0; + tmp1.current = 0; + + tmp1.bits.resize(256); + tmp1.lengths.resize(256); + tmp1.values.resize(256); + + tmp2.length = 256; + tmp2.maxlength = 0; + tmp2.current = 0; + + tmp2.bits.resize(256); + tmp2.lengths.resize(256); + tmp2.values.resize(256); + + // low byte tree + if (bits.GetBit()) // 1: Read Tag + { + DecodeTree(bits, &tmp1, 0, 0); + + bits.SkipBits(1); + + VLC_InitTable(ctx.v1, tmp1.maxlength, tmp1.current, &tmp1.lengths[0], &tmp1.bits[0]); + } + else + { + // Skipping low bytes tree + } + + // high byte tree + if (bits.GetBit()) + { + DecodeTree(bits, &tmp2, 0, 0); + + bits.SkipBits(1); + + VLC_InitTable(ctx.v2, tmp2.maxlength, tmp2.current, &tmp2.lengths[0], &tmp2.bits[0]); + } + else + { + // Skipping high bytes tree + } + + escapes[0] = bits.GetBits(8); + escapes[0] |= bits.GetBits(8) << 8; + escapes[1] = bits.GetBits(8); + escapes[1] |= bits.GetBits(8) << 8; + escapes[2] = bits.GetBits(8); + escapes[2] |= bits.GetBits(8) << 8; + + last[0] = last[1] = last[2] = -1; + + ctx.escapes[0] = escapes[0]; + ctx.escapes[1] = escapes[1]; + ctx.escapes[2] = escapes[2]; + + ctx.recode1 = tmp1.values; + ctx.recode2 = tmp2.values; + ctx.last = last; + + huff.length = ((size + 3) >> 2) + 3; + huff.maxlength = 0; + huff.current = 0; + huff.values.resize(huff.length); + + DecodeBigTree(bits, &huff, &ctx); + + bits.SkipBits(1); + + if (ctx.last[0] == -1) ctx.last[0] = huff.current++; + if (ctx.last[1] == -1) ctx.last[1] = huff.current++; + if (ctx.last[2] == -1) ctx.last[2] = huff.current++; + + recodes = huff.values; + + return 0; +} + +// static int decode_header_trees(SmackVContext *smk) { +bool SmackerDecoder::DecodeHeaderTrees() +{ + auto treeData = std::make_unique(treeSize); + file.ReadBytes(treeData.get(), treeSize); + + SmackerCommon::BitReader bits(treeData.get(), treeSize); + + if (!bits.GetBit()) + { + // Skipping MMAP tree + mmap_tbl.resize(2); + mmap_tbl[0] = 0; + mmap_last[0] = mmap_last[1] = mmap_last[2] = 1; + } + else + { + DecodeHeaderTree(bits, mmap_tbl, mmap_last, mMapSize); + } + + if (!bits.GetBit()) + { + // Skipping MCLR tree + mclr_tbl.resize(2); + mclr_tbl[0] = 0; + mclr_last[0] = mclr_last[1] = mclr_last[2] = 1; + } + else + { + DecodeHeaderTree(bits, mclr_tbl, mclr_last, MClrSize); + } + + if (!bits.GetBit()) + { + // Skipping FULL tree + full_tbl.resize(2); + full_tbl[0] = 0; + full_last[0] = full_last[1] = full_last[2] = 1; + } + else + { + DecodeHeaderTree(bits, full_tbl, full_last, fullSize); + } + + if (!bits.GetBit()) + { + // Skipping TYPE tree + type_tbl.resize(2); + type_tbl[0] = 0; + type_last[0] = type_last[1] = type_last[2] = 1; + } + else + { + DecodeHeaderTree(bits, type_tbl, type_last, typeSize); + } + + return true; +} + +void SmackerDecoder::GetNextFrame() +{ + if (currentFrame >= nFrames) + return; + + std::unique_lock flock(fileMutex); + while (framePacketData.empty()) + { + if (ReadPacket() > 0) + return; + } + SmackerPacket pkt = std::move(framePacketData.front()); + framePacketData.pop_front(); + flock.unlock(); + + uint32_t frameSize = (uint32_t)pkt.size; + uint8_t frameFlag = frameFlags[currentFrame]; + + const uint8_t *packetDataPtr = pkt.data.get(); + + // handle palette change + if (frameFlag & kSMKpal) + { + int size, sz, t, off, j; + uint8_t *pal = palette; + uint8_t oldpal[768]; + const uint8_t *dataEnd; + + memcpy(oldpal, pal, 768); + size = *(packetDataPtr++); + size = size * 4 - 1; + frameSize -= size; + frameSize--; + sz = 0; + dataEnd = packetDataPtr + size; + + while (sz < 256) + { + t = *(packetDataPtr++); + if (t & 0x80){ /* skip palette entries */ + sz += (t & 0x7F) + 1; + pal += ((t & 0x7F) + 1) * 3; + } else if (t & 0x40){ /* copy with offset */ + off = *(packetDataPtr++) * 3; + j = (t & 0x3F) + 1; + while (j-- && sz < 256) { + *pal++ = oldpal[off + 0]; + *pal++ = oldpal[off + 1]; + *pal++ = oldpal[off + 2]; + sz++; + off += 3; + } + } else { /* new entries */ + *pal++ = smk_pal[t]; + *pal++ = smk_pal[*(packetDataPtr++) & 0x3F]; + *pal++ = smk_pal[*(packetDataPtr++) & 0x3F]; + sz++; + } + } + + packetDataPtr = dataEnd; + } + + if (frameSize > 0) + DecodeFrame(packetDataPtr, frameSize); + + currentFrame++; +} + +int SmackerDecoder::ReadPacket() +{ + // test-remove + if (currentReadFrame >= nFrames) + return 1; + + // seek to next frame position + file.Seek(nextPos, SmackerCommon::FileStream::kSeekStart); + + uint32_t frameSize = frameSizes[currentReadFrame] & (~3); + uint8_t frameFlag = frameFlags[currentReadFrame]; + + packetData.resize(frameSize); + file.ReadBytes(packetData.data(), frameSize); + + const uint8_t *packetDataPtr = packetData.data(); + + // skip pal data for later, after getting audio data + if (frameFlag & kSMKpal) + { + int size = (*packetDataPtr * 4); + packetDataPtr += size; + frameSize -= size; + } + + frameFlag >>= 1; + for (int i = 0; i < kMaxAudioTracks; i++) + { + if (frameFlag & 1) + { + uint32_t size = *(packetDataPtr++); + size |= *(packetDataPtr++) << 8; + size |= *(packetDataPtr++) << 16; + size |= *(packetDataPtr++) << 24; + frameSize -= size; + size -= 4; + + if (audioTracks[i].flags & SMK_AUD_PRESENT) + { + SmackerPacket pkt; + pkt.size = size; + pkt.data = std::make_unique(size); + memcpy(pkt.data.get(), packetDataPtr, size); + audioTracks[i].packetData.emplace_back(std::move(pkt)); + } + packetDataPtr += size; + } + frameFlag >>= 1; + } + + SmackerPacket pkt; + frameFlag = frameFlags[currentReadFrame]; + if (frameSize != 0 || (frameFlag & kSMKpal)) + { + int palsize = (frameFlag & kSMKpal) ? packetData[0] * 4 : 0; + int totalSize = frameSize + palsize; + pkt.size = totalSize; + pkt.data = std::make_unique(totalSize); + memcpy(pkt.data.get(), packetData.data(), palsize); + memcpy(pkt.data.get()+palsize, packetDataPtr, frameSize); + } + framePacketData.emplace_back(std::move(pkt)); + + ++currentReadFrame; + + nextPos = file.GetPosition(); + + return 0; +} + +int SmackerDecoder::DecodeFrame(const uint8_t *dataPtr, uint32_t frameSize) +{ + last_reset(mmap_tbl, mmap_last); + last_reset(mclr_tbl, mclr_last); + last_reset(full_tbl, full_last); + last_reset(type_tbl, type_last); + + int blocks, blk, bw, bh; + int i; + int stride; + + uint8_t *out = picture; // set to output image + + blk = 0; + bw = frameWidth >> 2; + bh = frameHeight >> 2; + blocks = bw * bh; + + stride = frameWidth; + + SmackerCommon::BitReader bits(dataPtr, frameSize); + dataPtr += frameSize; + + while (blk < blocks) + { + int type, run, mode; + uint16_t pix; + + type = GetCode(bits, type_tbl, type_last); + run = block_runs[(type >> 2) & 0x3F]; + switch (type & 3) + { + case SMK_BLK_MONO: + while (run-- && blk < blocks) + { + int clr, map; + int hi, lo; + clr = GetCode(bits, mclr_tbl, mclr_last); + map = GetCode(bits, mmap_tbl, mmap_last); + + out = picture + (blk / bw) * (stride * 4) + (blk % bw) * 4; + + hi = clr >> 8; + lo = clr & 0xFF; + for (i = 0; i < 4; i++) + { + if (map & 1) out[0] = hi; else out[0] = lo; + if (map & 2) out[1] = hi; else out[1] = lo; + if (map & 4) out[2] = hi; else out[2] = lo; + if (map & 8) out[3] = hi; else out[3] = lo; + map >>= 4; + out += stride; + } + blk++; + } + break; + case SMK_BLK_FULL: + mode = 0; + if (isVer4) // In case of Smacker v4 we have three modes + { + if (bits.GetBit()) mode = 1; + else if (bits.GetBit()) mode = 2; + } + + while (run-- && blk < blocks) + { + out = picture + (blk / bw) * (stride * 4) + (blk % bw) * 4; + switch (mode) + { + case 0: + for (i = 0; i < 4; i++) + { + pix = GetCode(bits, full_tbl, full_last); +// FIX AV_WL16(out+2, pix); + out[2] = pix & 0xff; + out[3] = pix >> 8; + + pix = GetCode(bits, full_tbl, full_last); +// FIX AV_WL16(out, pix); + out[0] = pix & 0xff; + out[1] = pix >> 8; + out += stride; + } + break; + case 1: + pix = GetCode(bits, full_tbl, full_last); + out[0] = out[1] = pix & 0xFF; + out[2] = out[3] = pix >> 8; + out += stride; + out[0] = out[1] = pix & 0xFF; + out[2] = out[3] = pix >> 8; + out += stride; + pix = GetCode(bits, full_tbl, full_last); + out[0] = out[1] = pix & 0xFF; + out[2] = out[3] = pix >> 8; + out += stride; + out[0] = out[1] = pix & 0xFF; + out[2] = out[3] = pix >> 8; + out += stride; + break; + case 2: + for (i = 0; i < 2; i++) + { + uint16_t pix1, pix2; + pix2 = GetCode(bits, full_tbl, full_last); + pix1 = GetCode(bits, full_tbl, full_last); + +// FIX AV_WL16(out, pix1); +// FIX AV_WL16(out+2, pix2); + out[0] = pix1 & 0xff; + out[1] = pix1 >> 8; + out[2] = pix2 & 0xff; + out[3] = pix2 >> 8; + + out += stride; + +// FIX AV_WL16(out, pix1); +// FIX AV_WL16(out+2, pix2); + out[0] = pix1 & 0xff; + out[1] = pix1 >> 8; + out[2] = pix2 & 0xff; + out[3] = pix2 >> 8; + + out += stride; + } + break; + } + blk++; + } + break; + case SMK_BLK_SKIP: + while (run-- && blk < blocks) + blk++; + break; + case SMK_BLK_FILL: + mode = type >> 8; + while (run-- && blk < blocks) + { + uint32_t col; + out = picture + (blk / bw) * (stride * 4) + (blk % bw) * 4; + col = mode * 0x01010101; + for (i = 0; i < 4; i++) { + *((uint32_t*)out) = col; + out += stride; + } + blk++; + } + break; + } + } + + return 0; +} + +/** + * Decode Smacker audio data + */ +int SmackerDecoder::DecodeAudio(const uint8_t *dataPtr, uint32_t size, SmackerAudioTrack &track) +{ + SmackerCommon::VLCtable vlc[4]; + int val; + int i, res; + int unpackedSize; + int sampleBits, stereo; + int pred[2] = {0, 0}; + + int16_t *samples = reinterpret_cast(track.buffer); + + SmackerCommon::BitReader bits(dataPtr, size); + + unpackedSize = bits.GetBits(32); + if (unpackedSize <= 4) { + Printf("SmackerDecoder::DecodeAudio() - Packet is too small\n"); + return -1; + } + + if (!bits.GetBit()) { + // no sound data + return 1; + } + + stereo = bits.GetBit(); + sampleBits = bits.GetBit(); + + if (stereo ^ (track.nChannels != 1)) { + Printf("SmackerDecoder::DecodeAudio() - Channels mismatch\n"); + return -1; + } + + HuffContext h[4]; + + // Initialize + for (i = 0; i < (1 << (sampleBits + stereo)); i++) { + h[i].length = 256; + h[i].maxlength = 0; + h[i].current = 0; + h[i].bits.resize(256); + h[i].lengths.resize(256); + h[i].values.resize(256); + + bits.SkipBits(1); + DecodeTree(bits, &h[i], 0, 0); + bits.SkipBits(1); + + if (h[i].current > 1) { + VLC_InitTable(vlc[i], h[i].maxlength, h[i].current, &h[i].lengths[0], &h[i].bits[0]); + } + } + if (sampleBits) { //decode 16-bit data + for (i = stereo; i >= 0; i--) + pred[i] = av_bswap16(bits.GetBits(16)); + for (i = 0; i <= stereo; i++) + *samples++ = pred[i]; + for (; i < unpackedSize / 2; i++) { + if (i & stereo) { + if (VLC_GetSize(vlc[2])) + res = VLC_GetCodeBits(bits, vlc[2]); + else + res = 0; + val = h[2].values[res]; + if (VLC_GetSize(vlc[3])) + res = VLC_GetCodeBits(bits, vlc[3]); + else + res = 0; + val |= h[3].values[res] << 8; + pred[1] += (int16_t)val; + *samples++ = pred[1]; + } else { + if (VLC_GetSize(vlc[0])) + res = VLC_GetCodeBits(bits, vlc[0]); + else + res = 0; + val = h[0].values[res]; + if (VLC_GetSize(vlc[1])) + res = VLC_GetCodeBits(bits, vlc[1]); + else + res = 0; + val |= h[1].values[res] << 8; + pred[0] += val; + *samples++ = pred[0]; + } + } + } + else { //8-bit data + for (i = stereo; i >= 0; i--) + pred[i] = bits.GetBits(8); + for (i = 0; i <= stereo; i++) + *samples++ = (pred[i]-128) << 8; + for (; i < unpackedSize; i++) { + if (i & stereo){ + if (VLC_GetSize(vlc[1])) + res = VLC_GetCodeBits(bits, vlc[1]); + else + res = 0; + pred[1] += (int8_t)h[1].values[res]; + *samples++ = (pred[1]-128) << 8; + } else { + if (VLC_GetSize(vlc[0])) + res = VLC_GetCodeBits(bits, vlc[0]); + else + res = 0; + pred[0] += (int8_t)h[0].values[res]; + *samples++ = (pred[0]-128) << 8; + } + } + unpackedSize *= 2; + } + + track.bytesReadThisFrame = unpackedSize; + + return 0; +} + +void SmackerDecoder::GetPalette(uint8_t *palette) +{ + memcpy(palette, this->palette, 768); +} + +void SmackerDecoder::GetFrame(uint8_t *frame) +{ + memcpy(frame, this->picture, frameWidth * frameHeight); +} + +void SmackerDecoder::GetFrameSize(uint32_t &width, uint32_t &height) +{ + width = this->frameWidth; + height = this->frameHeight; +} + +uint32_t SmackerDecoder::GetNumFrames() +{ + return nFrames; +} + +uint32_t SmackerDecoder::GetCurrentFrameNum() +{ + return currentFrame; +} + +float SmackerDecoder::GetFrameRate() +{ + return (float)fps; +} + +void SmackerDecoder::GotoFrame(uint32_t frameNum) +{ + if (frameNum > nFrames) { + Printf("SmackerDecoder::GotoFrame() - Invalid frame number\n"); + return; + } + +// file.Seek(firstFrameFilePos, SmackerCommon::FileStream::kSeekStart); + + currentReadFrame = 0; + currentFrame = 0; + nextPos = firstFrameFilePos; + + framePacketData.clear(); + for (unsigned j = 0; j < kMaxAudioTracks; j++) + audioTracks[j].packetData.clear(); + + for (unsigned i = 0; i < frameNum; i++) + { + GetNextFrame(); + for (unsigned j = 0; j < kMaxAudioTracks; j++) + audioTracks[j].packetData.clear(); + } + + GetNextFrame(); +} + +uint32_t SmackerDecoder::GetNumAudioTracks() +{ + for(uint32_t i = 0;i < kMaxAudioTracks;++i) + { + if (!(audioTracks[i].flags & SMK_AUD_PRESENT)) + return i; + } + return kMaxAudioTracks; +} + +SmackerAudioInfo SmackerDecoder::GetAudioTrackDetails(uint32_t trackIndex) +{ + SmackerAudioInfo info; + SmackerAudioTrack *track = &audioTracks[trackIndex]; + + info.sampleRate = track->sampleRate; + info.nChannels = track->nChannels; + + // audio buffer size in bytes + info.idealBufferSize = track->bufferSize; + + return info; +} + +uint32_t SmackerDecoder::GetAudioData(uint32_t trackIndex, int16_t *audioBuffer) +{ + if (!audioBuffer) { + return 0; + } + + SmackerAudioTrack *track = &audioTracks[trackIndex]; + + std::unique_lock flock(fileMutex); + if (!(track->flags & SMK_AUD_PRESENT)) + return 0; + + while (track->packetData.empty()) + { + if (ReadPacket() > 0) + return 0; + } + SmackerPacket pkt = std::move(track->packetData.front()); + track->packetData.pop_front(); + flock.unlock(); + + track->bytesReadThisFrame = 0; + + const uint8_t *packetDataPtr = pkt.data.get(); + uint32_t size = (uint32_t)pkt.size; + + DecodeAudio(packetDataPtr, size, *track); + + if (track->bytesReadThisFrame) { + memcpy(audioBuffer, track->buffer, std::min(track->bufferSize, track->bytesReadThisFrame)); + } + + return track->bytesReadThisFrame; +} + +void SmackerDecoder::DisableAudioTrack(uint32_t trackIndex) +{ + SmackerAudioTrack *track = &audioTracks[trackIndex]; + std::unique_lock flock(fileMutex); + track->flags &= ~SMK_AUD_PRESENT; + track->packetData.clear(); +} diff --git a/src/utility/m_crc32.h b/src/common/thirdparty/m_crc32.h similarity index 90% rename from src/utility/m_crc32.h rename to src/common/thirdparty/m_crc32.h index 0d6a439db84..d2de074fc06 100644 --- a/src/utility/m_crc32.h +++ b/src/common/thirdparty/m_crc32.h @@ -31,13 +31,12 @@ **--------------------------------------------------------------------------- ** */ +#pragma once +#include +#include -#include -#include "basictypes.h" +// miniz includes some CRC32 stuff, so just use that -// zlib includes some CRC32 stuff, so just use that - -inline const uint32_t *GetCRCTable () { return (const uint32_t *)get_crc_table(); } inline uint32_t CalcCRC32 (const uint8_t *buf, unsigned int len) { return crc32 (0, buf, len); @@ -50,3 +49,8 @@ inline uint32_t CRC1 (uint32_t crc, const uint8_t c, const uint32_t *crcTable) { return crcTable[(crc & 0xff) ^ c] ^ (crc >> 8); } + +inline uint32_t Bcrc32(const void* data, int length, uint32_t crc) +{ + return crc32(crc, (const Bytef*)data, length); +} diff --git a/src/utility/math/asin.c b/src/common/thirdparty/math/asin.c similarity index 99% rename from src/utility/math/asin.c rename to src/common/thirdparty/math/asin.c index 8bc342dd12f..72dc9b3e95e 100644 --- a/src/utility/math/asin.c +++ b/src/common/thirdparty/math/asin.c @@ -276,8 +276,7 @@ double c_asin(); #endif extern double PIO2, PIO4, NAN; -double c_asin(x) -double x; +double c_asin(double x) { double a, p, z, zz; short sign; @@ -327,8 +326,7 @@ return(z); -double c_acos(x) -double x; +double c_acos(double x) { if( (x < -1.0) || (x > 1.0) ) { diff --git a/src/utility/math/atan.c b/src/common/thirdparty/math/atan.c similarity index 98% rename from src/utility/math/atan.c rename to src/common/thirdparty/math/atan.c index d73ed1ee443..68e10310af4 100644 --- a/src/utility/math/atan.c +++ b/src/common/thirdparty/math/atan.c @@ -212,8 +212,7 @@ extern double PI, PIO2, PIO4, INFINITY, NEGZERO, MAXNUM; #endif -double c_atan(x) -double x; +double c_atan(double x) { double y, z; short sign, flag; @@ -269,11 +268,10 @@ return(y); /* atan2 */ #ifdef ANSIC -double c_atan2( y, x ) +double c_atan2(double y, double x) #else -double c_atan2( x, y ) +double c_atan2(double x, double y) #endif -double x, y; { double z, w; short code; diff --git a/src/utility/math/cmath.h b/src/common/thirdparty/math/cmath.h similarity index 93% rename from src/utility/math/cmath.h rename to src/common/thirdparty/math/cmath.h index 5c02c4e87e5..4da0afcb6df 100644 --- a/src/utility/math/cmath.h +++ b/src/common/thirdparty/math/cmath.h @@ -54,6 +54,16 @@ extern FFastTrig fasttrig; #define RAD2BAM(f) ((unsigned)xs_CRoundToInt((f) * (0x80000000/3.14159265358979323846))) +inline double fastcosbam(unsigned int v) +{ + return fasttrig.cos(v); +} + +inline double fastsinbam(unsigned int v) +{ + return fasttrig.sin(v); +} + inline double fastcosdeg(double v) { return fasttrig.cos(DEG2BAM(v)); @@ -129,6 +139,8 @@ inline double cosdeg(double v) #else #define g_sindeg fastsindeg #define g_cosdeg fastcosdeg +#define g_sinbam fastsinbam +#define g_cosbam fastcosbam #define g_sin fastsin #define g_cos fastcos #endif diff --git a/src/utility/math/const.c b/src/common/thirdparty/math/const.c similarity index 100% rename from src/utility/math/const.c rename to src/common/thirdparty/math/const.c diff --git a/src/utility/math/cosh.c b/src/common/thirdparty/math/cosh.c similarity index 99% rename from src/utility/math/cosh.c rename to src/common/thirdparty/math/cosh.c index 778ccd9514b..bd4df2f391e 100644 --- a/src/utility/math/cosh.c +++ b/src/common/thirdparty/math/cosh.c @@ -79,8 +79,7 @@ int isnan(), isfinite(); #endif extern double MAXLOG, INFINITY, LOGE2; -double c_cosh(x) -double x; +double c_cosh(double x) { double y; diff --git a/src/utility/math/exp.c b/src/common/thirdparty/math/exp.c similarity index 98% rename from src/utility/math/exp.c rename to src/common/thirdparty/math/exp.c index 29ec8d5da81..46cd0f55961 100644 --- a/src/utility/math/exp.c +++ b/src/common/thirdparty/math/exp.c @@ -164,12 +164,11 @@ static short sc2[] = {0x3eb7,0xf7d1,0xcf79,0xabca}; extern double LOGE2, LOG2E, MAXLOG, MINLOG, MAXNUM; -double c_exp(x) -double x; +double c_exp(double x) { double px, xx; int n; -double polevl(), floor(), ldexp(); +double polevl(double, void *, int), floor(double), ldexp(double, int); if( x > MAXLOG) { diff --git a/src/utility/math/fastsin.cpp b/src/common/thirdparty/math/fastsin.cpp similarity index 99% rename from src/utility/math/fastsin.cpp rename to src/common/thirdparty/math/fastsin.cpp index 36f59dbb44a..41bc473ca88 100644 --- a/src/utility/math/fastsin.cpp +++ b/src/common/thirdparty/math/fastsin.cpp @@ -57,7 +57,7 @@ __forceinline double FFastTrig::sinq1(unsigned bangle) { unsigned int index = bangle >> BITSHIFT; - if ((bangle &= (REMAINDER)) == 0) // This is to avoid precision problems at 180� + if ((bangle &= (REMAINDER)) == 0) // This is to avoid precision problems at 180° { return double(sinetable[index]); } diff --git a/src/utility/math/isnan.c b/src/common/thirdparty/math/isnan.c similarity index 98% rename from src/utility/math/isnan.c rename to src/common/thirdparty/math/isnan.c index 6c421441f57..b09ce01a354 100644 --- a/src/utility/math/isnan.c +++ b/src/common/thirdparty/math/isnan.c @@ -99,8 +99,7 @@ POSSIBILITY OF SUCH DAMAGE. /* Return 1 if the sign bit of x is 1, else 0. */ -int signbit(x) -double x; +int signbit(double x) { union { @@ -140,8 +139,7 @@ else /* Return 1 if x is a number that is Not a Number, else return 0. */ -int isnan(x) -double x; +int isnan(double x) { #ifdef NANS union @@ -209,8 +207,7 @@ return(0); /* Return 1 if x is not infinite and is not a NaN. */ -int isfinite(x) -double x; +int isfinite(double x) { #ifdef INFINITIES union diff --git a/src/utility/math/log.c b/src/common/thirdparty/math/log.c similarity index 99% rename from src/utility/math/log.c rename to src/common/thirdparty/math/log.c index 81595120cc2..8ad060c7ee9 100644 --- a/src/utility/math/log.c +++ b/src/common/thirdparty/math/log.c @@ -230,8 +230,7 @@ int isnan(), isfinite(); #define SQRTH 0.70710678118654752440 extern double INFINITY, NAN; -double c_log(x) -double x; +double c_log(double x) { int e; #ifdef DEC diff --git a/src/utility/math/log10.c b/src/common/thirdparty/math/log10.c similarity index 99% rename from src/utility/math/log10.c rename to src/common/thirdparty/math/log10.c index 037741c60e7..b7662dc0ece 100644 --- a/src/utility/math/log10.c +++ b/src/common/thirdparty/math/log10.c @@ -178,8 +178,7 @@ int isnan(), isfinite(); #endif extern double LOGE2, SQRT2, INFINITY, NAN; -double c_log10(x) -double x; +double c_log10(double x) { VOLATILE double z; double y; diff --git a/src/utility/math/mconf.h b/src/common/thirdparty/math/mconf.h similarity index 100% rename from src/utility/math/mconf.h rename to src/common/thirdparty/math/mconf.h diff --git a/src/utility/math/mtherr.c b/src/common/thirdparty/math/mtherr.c similarity index 98% rename from src/utility/math/mtherr.c rename to src/common/thirdparty/math/mtherr.c index 5650e07ed65..3f24da2b7ce 100644 --- a/src/utility/math/mtherr.c +++ b/src/common/thirdparty/math/mtherr.c @@ -99,9 +99,7 @@ static char *ermsg[7] = { }; -int mtherr( name, code ) -char *name; -int code; +int mtherr(char* name, int code) { /* Display string passed by calling program, diff --git a/src/utility/math/polevl.c b/src/common/thirdparty/math/polevl.c similarity index 96% rename from src/utility/math/polevl.c rename to src/common/thirdparty/math/polevl.c index bc17a1210cb..dde27daff66 100644 --- a/src/utility/math/polevl.c +++ b/src/common/thirdparty/math/polevl.c @@ -75,10 +75,7 @@ Direct inquiries to 30 Frost Street, Cambridge, MA 02140 */ -double polevl( x, coef, N ) -double x; -double coef[]; -int N; +double polevl(double x, double coef[], int N) { double ans; int i; @@ -101,10 +98,7 @@ return( ans ); * Otherwise same as polevl. */ -double p1evl( x, coef, N ) -double x; -double coef[]; -int N; +double p1evl(double x, double coef[], int N) { double ans; double *p; diff --git a/src/utility/math/pow.c b/src/common/thirdparty/math/pow.c similarity index 99% rename from src/utility/math/pow.c rename to src/common/thirdparty/math/pow.c index 49d09144585..3631c4c78c6 100644 --- a/src/utility/math/pow.c +++ b/src/common/thirdparty/math/pow.c @@ -387,8 +387,7 @@ extern double NAN; extern double NEGZERO; #endif -double c_pow( x, y ) -double x, y; +double c_pow(double x, double y) { double w, z, W, Wa, Wb, ya, yb, u; /* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */ @@ -768,8 +767,7 @@ return( z ); /* Find a multiple of 1/16 that is within 1/16 of x. */ -static double reduc(x) -double x; +static double reduc(double x) { double t; diff --git a/src/utility/math/powi.c b/src/common/thirdparty/math/powi.c similarity index 99% rename from src/utility/math/powi.c rename to src/common/thirdparty/math/powi.c index d4d5a07f69d..75a22f8f1a2 100644 --- a/src/utility/math/powi.c +++ b/src/common/thirdparty/math/powi.c @@ -78,9 +78,7 @@ int signbit(); #endif extern double NEGZERO, INFINITY, MAXNUM, MAXLOG, MINLOG, LOGE2; -double c_powi( x, nn ) -double x; -int nn; +double c_powi(double x, int nn) { int n, e, sign, asign, lx; double w, y, s; diff --git a/src/utility/math/sin.c b/src/common/thirdparty/math/sin.c similarity index 99% rename from src/utility/math/sin.c rename to src/common/thirdparty/math/sin.c index 76c6a1938a6..4b4275f2ed8 100644 --- a/src/utility/math/sin.c +++ b/src/common/thirdparty/math/sin.c @@ -238,8 +238,7 @@ extern double INFINITY; #endif -double c_sin(x) -double x; +double c_sin(double x) { double y, z, zz; int j, sign; @@ -318,8 +317,7 @@ return(y); -double c_cos(x) -double x; +double c_cos(double x) { double y, z, zz; int i; @@ -403,8 +401,7 @@ static unsigned short P648[] = {034513,054170,0176773,0116043,}; static double P64800 = 4.8481368110953599358991410e-5; #endif -double radian(d,m,s) -double d,m,s; +double radian(double d, double m, double s) { return( ((d*60.0 + m)*60.0 + s)*P64800 ); diff --git a/src/utility/math/sinh.c b/src/common/thirdparty/math/sinh.c similarity index 99% rename from src/utility/math/sinh.c rename to src/common/thirdparty/math/sinh.c index eb868b76508..3b54760c462 100644 --- a/src/utility/math/sinh.c +++ b/src/common/thirdparty/math/sinh.c @@ -132,8 +132,7 @@ double fabs(), c_exp(), polevl(), p1evl(); #endif extern double INFINITY, MINLOG, MAXLOG, LOGE2; -double c_sinh(x) -double x; +double c_sinh(double x) { double a; diff --git a/src/utility/math/sqrt.c b/src/common/thirdparty/math/sqrt.c similarity index 99% rename from src/utility/math/sqrt.c rename to src/common/thirdparty/math/sqrt.c index de214aff04a..67f7376f171 100644 --- a/src/utility/math/sqrt.c +++ b/src/common/thirdparty/math/sqrt.c @@ -78,8 +78,7 @@ double frexp(), ldexp(); #endif extern double SQRT2; /* _sqrt2 = 1.41421356237309504880 */ -double c_sqrt(x) -double x; +double c_sqrt(double x) { int e; #ifndef UNK diff --git a/src/utility/math/tan.c b/src/common/thirdparty/math/tan.c similarity index 98% rename from src/utility/math/tan.c rename to src/common/thirdparty/math/tan.c index 0b5fecc9c61..adeade460ec 100644 --- a/src/utility/math/tan.c +++ b/src/common/thirdparty/math/tan.c @@ -220,8 +220,7 @@ extern double PIO4; extern double INFINITY; extern double NAN; -double c_tan(x) -double x; +double c_tan(double x) { #ifdef MINUSZERO if( x == 0.0 ) @@ -240,8 +239,7 @@ return( tancot(x,0) ); } -double c_cot(x) -double x; +double c_cot(double x) { if( x == 0.0 ) @@ -253,9 +251,7 @@ return( tancot(x,1) ); } -static double tancot( xx, cotflg ) -double xx; -int cotflg; +static double tancot(double xx, int cotflg) { double x, y, z, zz; int j, sign; diff --git a/src/utility/math/tanh.c b/src/common/thirdparty/math/tanh.c similarity index 99% rename from src/utility/math/tanh.c rename to src/common/thirdparty/math/tanh.c index 1836d35cce5..92452c10fbb 100644 --- a/src/utility/math/tanh.c +++ b/src/common/thirdparty/math/tanh.c @@ -128,8 +128,7 @@ double fabs(), c_exp(), polevl(), p1evl(); #endif extern double MAXLOG; -double c_tanh(x) -double x; +double c_tanh(double x) { double s, z; diff --git a/src/utility/md5.cpp b/src/common/thirdparty/md5.cpp similarity index 86% rename from src/utility/md5.cpp rename to src/common/thirdparty/md5.cpp index 1e0f724404f..c2f90cdbc16 100644 --- a/src/utility/md5.cpp +++ b/src/common/thirdparty/md5.cpp @@ -16,11 +16,9 @@ */ #include /* for memcpy() */ +#include -#include "doomtype.h" #include "md5.h" -#include "templates.h" -#include "files.h" #ifdef __BIG_ENDIAN__ void byteSwap(uint32_t *buf, unsigned words) @@ -95,20 +93,6 @@ void MD5Context::Update(const uint8_t *buf, unsigned len) memcpy(in, buf, len); } -void MD5Context::Update(FileReader &file, unsigned len) -{ - uint8_t readbuf[8192]; - long t; - - while (len > 0) - { - t = MIN(len, sizeof(readbuf)); - len -= t; - t = (long)file.Read(readbuf, t); - Update(readbuf, t); - } -} - /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) @@ -250,46 +234,3 @@ MD5Transform(uint32_t buf[4], const uint32_t in[16]) #endif -//========================================================================== -// -// CCMD md5sum -// -// Like the command-line tool, because I wanted to make sure I had it right. -// -//========================================================================== - -#include "c_dispatch.h" -#include - -CCMD (md5sum) -{ - if (argv.argc() < 2) - { - Printf("Usage: md5sum ...\n"); - } - for (int i = 1; i < argv.argc(); ++i) - { - FileReader fr; - if (!fr.OpenFile(argv[i])) - { - Printf("%s: %s\n", argv[i], strerror(errno)); - } - else - { - MD5Context md5; - uint8_t readbuf[8192]; - size_t len; - - while ((len = fr.Read(readbuf, sizeof(readbuf))) > 0) - { - md5.Update(readbuf, (unsigned int)len); - } - md5.Final(readbuf); - for(int j = 0; j < 16; ++j) - { - Printf("%02x", readbuf[j]); - } - Printf(" *%s\n", argv[i]); - } - } -} diff --git a/src/utility/md5.h b/src/common/thirdparty/md5.h similarity index 94% rename from src/utility/md5.h rename to src/common/thirdparty/md5.h index 82d4f32dc13..95ac9a50d8c 100644 --- a/src/utility/md5.h +++ b/src/common/thirdparty/md5.h @@ -18,7 +18,7 @@ #ifndef MD5_H #define MD5_H -class FileReader; +#include struct MD5Context { @@ -26,7 +26,6 @@ struct MD5Context void Init(); void Update(const uint8_t *buf, unsigned len); - void Update(FileReader &file, unsigned len); void Final(uint8_t digest[16]); private: diff --git a/src/common/thirdparty/rapidjson/allocators.h b/src/common/thirdparty/rapidjson/allocators.h new file mode 100644 index 00000000000..ddcf4781bea --- /dev/null +++ b/src/common/thirdparty/rapidjson/allocators.h @@ -0,0 +1,693 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ALLOCATORS_H_ +#define RAPIDJSON_ALLOCATORS_H_ + +#include "rapidjson.h" +#include "internal/meta.h" + +#include +#include + +#if RAPIDJSON_HAS_CXX11 +#include +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Allocator + +/*! \class rapidjson::Allocator + \brief Concept for allocating, resizing and freeing memory block. + + Note that Malloc() and Realloc() are non-static but Free() is static. + + So if an allocator need to support Free(), it needs to put its pointer in + the header of memory block. + +\code +concept Allocator { + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). + + // Allocate a memory block. + // \param size of the memory block in bytes. + // \returns pointer to the memory block. + void* Malloc(size_t size); + + // Resize a memory block. + // \param originalPtr The pointer to current memory block. Null pointer is permitted. + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) + // \param newSize the new size in bytes. + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); + + // Free a memory block. + // \param pointer to the memory block. Null pointer is permitted. + static void Free(void *ptr); +}; +\endcode +*/ + + +/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User-defined kDefaultChunkCapacity definition. + + User can define this as any \c size that is a power of 2. +*/ + +#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY +#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// CrtAllocator + +//! C-runtime library allocator. +/*! This class is just wrapper for standard C library memory routines. + \note implements Allocator concept +*/ +class CrtAllocator { +public: + static const bool kNeedFree = true; + void* Malloc(size_t size) { + if (size) // behavior of malloc(0) is implementation defined. + return RAPIDJSON_MALLOC(size); + else + return NULL; // standardize to returning NULL. + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + (void)originalSize; + if (newSize == 0) { + RAPIDJSON_FREE(originalPtr); + return NULL; + } + return RAPIDJSON_REALLOC(originalPtr, newSize); + } + static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); } + + bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { + return true; + } + bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { + return false; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// MemoryPoolAllocator + +//! Default memory allocator used by the parser and DOM. +/*! This allocator allocate memory blocks from pre-allocated memory chunks. + + It does not free memory blocks. And Realloc() only allocate new memory. + + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. + + User may also supply a buffer as the first chunk. + + If the user-buffer is full then additional chunks are allocated by BaseAllocator. + + The user-buffer is not deallocated by this allocator. + + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. + \note implements Allocator concept +*/ +template +class MemoryPoolAllocator { + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; + + struct SharedData { + ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + BaseAllocator* ownBaseAllocator; //!< base allocator created by this object. + size_t refcount; + bool ownBuffer; + }; + + static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData)); + static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader)); + + static inline ChunkHeader *GetChunkHead(SharedData *shared) + { + return reinterpret_cast(reinterpret_cast(shared) + SIZEOF_SHARED_DATA); + } + static inline uint8_t *GetChunkBuffer(SharedData *shared) + { + return reinterpret_cast(shared->chunkHead) + SIZEOF_CHUNK_HEADER; + } + + static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. + +public: + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy + + //! Constructor with chunkSize. + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + explicit + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunk_capacity_(chunkSize), + baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()), + shared_(static_cast(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0)) + { + RAPIDJSON_ASSERT(baseAllocator_ != 0); + RAPIDJSON_ASSERT(shared_ != 0); + if (baseAllocator) { + shared_->ownBaseAllocator = 0; + } + else { + shared_->ownBaseAllocator = baseAllocator_; + } + shared_->chunkHead = GetChunkHead(shared_); + shared_->chunkHead->capacity = 0; + shared_->chunkHead->size = 0; + shared_->chunkHead->next = 0; + shared_->ownBuffer = true; + shared_->refcount = 1; + } + + //! Constructor with user-supplied buffer. + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. + + The user buffer will not be deallocated when this allocator is destructed. + + \param buffer User supplied buffer. + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunk_capacity_(chunkSize), + baseAllocator_(baseAllocator), + shared_(static_cast(AlignBuffer(buffer, size))) + { + RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER); + shared_->chunkHead = GetChunkHead(shared_); + shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER; + shared_->chunkHead->size = 0; + shared_->chunkHead->next = 0; + shared_->ownBaseAllocator = 0; + shared_->ownBuffer = false; + shared_->refcount = 1; + } + + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT : + chunk_capacity_(rhs.chunk_capacity_), + baseAllocator_(rhs.baseAllocator_), + shared_(rhs.shared_) + { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + ++shared_->refcount; + } + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + ++rhs.shared_->refcount; + this->~MemoryPoolAllocator(); + baseAllocator_ = rhs.baseAllocator_; + chunk_capacity_ = rhs.chunk_capacity_; + shared_ = rhs.shared_; + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT : + chunk_capacity_(rhs.chunk_capacity_), + baseAllocator_(rhs.baseAllocator_), + shared_(rhs.shared_) + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + rhs.shared_ = 0; + } + MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + this->~MemoryPoolAllocator(); + baseAllocator_ = rhs.baseAllocator_; + chunk_capacity_ = rhs.chunk_capacity_; + shared_ = rhs.shared_; + rhs.shared_ = 0; + return *this; + } +#endif + + //! Destructor. + /*! This deallocates all memory chunks, excluding the user-supplied buffer. + */ + ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT { + if (!shared_) { + // do nothing if moved + return; + } + if (shared_->refcount > 1) { + --shared_->refcount; + return; + } + Clear(); + BaseAllocator *a = shared_->ownBaseAllocator; + if (shared_->ownBuffer) { + baseAllocator_->Free(shared_); + } + RAPIDJSON_DELETE(a); + } + + //! Deallocates all memory chunks, excluding the first/user one. + void Clear() RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + for (;;) { + ChunkHeader* c = shared_->chunkHead; + if (!c->next) { + break; + } + shared_->chunkHead = c->next; + baseAllocator_->Free(c); + } + shared_->chunkHead->size = 0; + } + + //! Computes the total capacity of allocated memory chunks. + /*! \return total capacity in bytes. + */ + size_t Capacity() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + size_t capacity = 0; + for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) + capacity += c->capacity; + return capacity; + } + + //! Computes the memory blocks allocated. + /*! \return total used bytes. + */ + size_t Size() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + size_t size = 0; + for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) + size += c->size; + return size; + } + + //! Whether the allocator is shared. + /*! \return true or false. + */ + bool Shared() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + return shared_->refcount > 1; + } + + //! Allocates a memory block. (concept Allocator) + void* Malloc(size_t size) { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + if (!size) + return NULL; + + size = RAPIDJSON_ALIGN(size); + if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity)) + if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) + return NULL; + + void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size; + shared_->chunkHead->size += size; + return buffer; + } + + //! Resizes a memory block (concept Allocator) + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + if (originalPtr == 0) + return Malloc(newSize); + + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + if (newSize == 0) + return NULL; + + originalSize = RAPIDJSON_ALIGN(originalSize); + newSize = RAPIDJSON_ALIGN(newSize); + + // Do not shrink if new size is smaller than original + if (originalSize >= newSize) + return originalPtr; + + // Simply expand it if it is the last allocation and there is sufficient space + if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) { + size_t increment = static_cast(newSize - originalSize); + if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) { + shared_->chunkHead->size += increment; + return originalPtr; + } + } + + // Realloc process: allocate and copy memory, do not free original buffer. + if (void* newBuffer = Malloc(newSize)) { + if (originalSize) + std::memcpy(newBuffer, originalPtr, originalSize); + return newBuffer; + } + else + return NULL; + } + + //! Frees a memory block (concept Allocator) + static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing + + //! Compare (equality) with another MemoryPoolAllocator + bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + return shared_ == rhs.shared_; + } + //! Compare (inequality) with another MemoryPoolAllocator + bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { + return !operator==(rhs); + } + +private: + //! Creates a new chunk. + /*! \param capacity Capacity of the chunk in bytes. + \return true if success. + */ + bool AddChunk(size_t capacity) { + if (!baseAllocator_) + shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); + if (ChunkHeader* chunk = static_cast(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) { + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = shared_->chunkHead; + shared_->chunkHead = chunk; + return true; + } + else + return false; + } + + static inline void* AlignBuffer(void* buf, size_t &size) + { + RAPIDJSON_NOEXCEPT_ASSERT(buf != 0); + const uintptr_t mask = sizeof(void*) - 1; + const uintptr_t ubuf = reinterpret_cast(buf); + if (RAPIDJSON_UNLIKELY(ubuf & mask)) { + const uintptr_t abuf = (ubuf + mask) & ~mask; + RAPIDJSON_ASSERT(size >= abuf - ubuf); + buf = reinterpret_cast(abuf); + size -= abuf - ubuf; + } + return buf; + } + + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. + SharedData *shared_; //!< The shared data of the allocator +}; + +namespace internal { + template + struct IsRefCounted : + public FalseType + { }; + template + struct IsRefCounted::Type> : + public TrueType + { }; +} + +template +inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n) +{ + RAPIDJSON_NOEXCEPT_ASSERT(old_n <= std::numeric_limits::max() / sizeof(T) && new_n <= std::numeric_limits::max() / sizeof(T)); + return static_cast(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T))); +} + +template +inline T *Malloc(A& a, size_t n = 1) +{ + return Realloc(a, NULL, 0, n); +} + +template +inline void Free(A& a, T *p, size_t n = 1) +{ + static_cast(Realloc(a, p, n, 0)); +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited +#endif + +template +class StdAllocator : + public std::allocator +{ + typedef std::allocator allocator_type; +#if RAPIDJSON_HAS_CXX11 + typedef std::allocator_traits traits_type; +#else + typedef allocator_type traits_type; +#endif + +public: + typedef BaseAllocator BaseAllocatorType; + + StdAllocator() RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_() + { } + + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + template + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(std::move(rhs)), + baseAllocator_(std::move(rhs.baseAllocator_)) + { } +#endif +#if RAPIDJSON_HAS_CXX11 + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_swap = std::true_type; +#endif + + /* implicit */ + StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_(allocator) + { } + + ~StdAllocator() RAPIDJSON_NOEXCEPT + { } + + template + struct rebind { + typedef StdAllocator other; + }; + + typedef typename traits_type::size_type size_type; + typedef typename traits_type::difference_type difference_type; + + typedef typename traits_type::value_type value_type; + typedef typename traits_type::pointer pointer; + typedef typename traits_type::const_pointer const_pointer; + +#if RAPIDJSON_HAS_CXX11 + + typedef typename std::add_lvalue_reference::type &reference; + typedef typename std::add_lvalue_reference::type>::type &const_reference; + + pointer address(reference r) const RAPIDJSON_NOEXCEPT + { + return std::addressof(r); + } + const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT + { + return std::addressof(r); + } + + size_type max_size() const RAPIDJSON_NOEXCEPT + { + return traits_type::max_size(*this); + } + + template + void construct(pointer p, Args&&... args) + { + traits_type::construct(*this, p, std::forward(args)...); + } + void destroy(pointer p) + { + traits_type::destroy(*this, p); + } + +#else // !RAPIDJSON_HAS_CXX11 + + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + + pointer address(reference r) const RAPIDJSON_NOEXCEPT + { + return allocator_type::address(r); + } + const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT + { + return allocator_type::address(r); + } + + size_type max_size() const RAPIDJSON_NOEXCEPT + { + return allocator_type::max_size(); + } + + void construct(pointer p, const_reference r) + { + allocator_type::construct(p, r); + } + void destroy(pointer p) + { + allocator_type::destroy(p); + } + +#endif // !RAPIDJSON_HAS_CXX11 + + template + U* allocate(size_type n = 1, const void* = 0) + { + return RAPIDJSON_NAMESPACE::Malloc(baseAllocator_, n); + } + template + void deallocate(U* p, size_type n = 1) + { + RAPIDJSON_NAMESPACE::Free(baseAllocator_, p, n); + } + + pointer allocate(size_type n = 1, const void* = 0) + { + return allocate(n); + } + void deallocate(pointer p, size_type n = 1) + { + deallocate(p, n); + } + +#if RAPIDJSON_HAS_CXX11 + using is_always_equal = std::is_empty; +#endif + + template + bool operator==(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT + { + return baseAllocator_ == rhs.baseAllocator_; + } + template + bool operator!=(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT + { + return !operator==(rhs); + } + + //! rapidjson Allocator concept + static const bool kNeedFree = BaseAllocator::kNeedFree; + static const bool kRefCounted = internal::IsRefCounted::Value; + void* Malloc(size_t size) + { + return baseAllocator_.Malloc(size); + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) + { + return baseAllocator_.Realloc(originalPtr, originalSize, newSize); + } + static void Free(void *ptr) RAPIDJSON_NOEXCEPT + { + BaseAllocator::Free(ptr); + } + +private: + template + friend class StdAllocator; // access to StdAllocator.* + + BaseAllocator baseAllocator_; +}; + +#if !RAPIDJSON_HAS_CXX17 // std::allocator deprecated in C++17 +template +class StdAllocator : + public std::allocator +{ + typedef std::allocator allocator_type; + +public: + typedef BaseAllocator BaseAllocatorType; + + StdAllocator() RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_() + { } + + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + template + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + /* implicit */ + StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_(baseAllocator) + { } + + ~StdAllocator() RAPIDJSON_NOEXCEPT + { } + + template + struct rebind { + typedef StdAllocator other; + }; + + typedef typename allocator_type::value_type value_type; + +private: + template + friend class StdAllocator; // access to StdAllocator.* + + BaseAllocator baseAllocator_; +}; +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/src/common/thirdparty/rapidjson/cursorstreamwrapper.h b/src/common/thirdparty/rapidjson/cursorstreamwrapper.h new file mode 100644 index 00000000000..fd6513db14a --- /dev/null +++ b/src/common/thirdparty/rapidjson/cursorstreamwrapper.h @@ -0,0 +1,78 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ +#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ + +#include "stream.h" + +#if defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + + +//! Cursor stream wrapper for counting line and column number if error exists. +/*! + \tparam InputStream Any stream that implements Stream Concept +*/ +template > +class CursorStreamWrapper : public GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + + CursorStreamWrapper(InputStream& is): + GenericStreamWrapper(is), line_(1), col_(0) {} + + // counting line and column number + Ch Take() { + Ch ch = this->is_.Take(); + if(ch == '\n') { + line_ ++; + col_ = 0; + } else { + col_ ++; + } + return ch; + } + + //! Get the error line number, if error exists. + size_t GetLine() const { return line_; } + //! Get the error column number, if error exists. + size_t GetColumn() const { return col_; } + +private: + size_t line_; //!< Current Line + size_t col_; //!< Current Column +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +#if defined(__GNUC__) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/src/utility/rapidjson/document.h b/src/common/thirdparty/rapidjson/document.h similarity index 79% rename from src/utility/rapidjson/document.h rename to src/common/thirdparty/rapidjson/document.h index 19f5a6a5ff9..2cd9a70a600 100644 --- a/src/utility/rapidjson/document.h +++ b/src/common/thirdparty/rapidjson/document.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -24,32 +24,39 @@ #include "encodedstream.h" #include // placement new #include - -RAPIDJSON_DIAG_PUSH -#ifdef _MSC_VER -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data +#ifdef __cpp_lib_three_way_comparison +#include #endif +RAPIDJSON_DIAG_PUSH #ifdef __clang__ RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data #endif #ifdef __GNUC__ RAPIDJSON_DIAG_OFF(effc++) -#if __GNUC__ >= 6 -RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions -#endif #endif // __GNUC__ +#ifdef GetObject +// see https://github.com/Tencent/rapidjson/issues/1448 +// a former included windows.h might have defined a macro called GetObject, which affects +// GetObject defined here. This ensures the macro does not get applied +#pragma push_macro("GetObject") +#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#undef GetObject +#endif + #ifndef RAPIDJSON_NOMEMBERITERATORCLASS -#include // std::iterator, std::random_access_iterator_tag +#include // std::random_access_iterator_tag #endif -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move +#if RAPIDJSON_USE_MEMBERSMAP +#include // std::multimap #endif RAPIDJSON_NAMESPACE_BEGIN @@ -61,6 +68,48 @@ class GenericValue; template class GenericDocument; +/*! \def RAPIDJSON_DEFAULT_ALLOCATOR + \ingroup RAPIDJSON_CONFIG + \brief Allows to choose default allocator. + + User can define this to use CrtAllocator or MemoryPoolAllocator. +*/ +#ifndef RAPIDJSON_DEFAULT_ALLOCATOR +#define RAPIDJSON_DEFAULT_ALLOCATOR ::RAPIDJSON_NAMESPACE::MemoryPoolAllocator<::RAPIDJSON_NAMESPACE::CrtAllocator> +#endif + +/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR + \ingroup RAPIDJSON_CONFIG + \brief Allows to choose default stack allocator for Document. + + User can define this to use CrtAllocator or MemoryPoolAllocator. +*/ +#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR +#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR ::RAPIDJSON_NAMESPACE::CrtAllocator +#endif + +/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User defined kDefaultObjectCapacity value. + + User can define this as any natural number. +*/ +#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY +// number of objects that rapidjson::Value allocates memory for by default +#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16 +#endif + +/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User defined kDefaultArrayCapacity value. + + User can define this as any natural number. +*/ +#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY +// number of array elements that rapidjson::Value allocates memory for by default +#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16 +#endif + //! Name-value pair in a JSON object value. /*! This class was internal to GenericValue. It used to be a inner struct. @@ -68,9 +117,45 @@ class GenericDocument; https://code.google.com/p/rapidjson/issues/detail?id=64 */ template -struct GenericMember { +class GenericMember { +public: GenericValue name; //!< name of member (must be a string) GenericValue value; //!< value of member. + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT + : name(std::move(rhs.name)), + value(std::move(rhs.value)) + { + } + + //! Move assignment in C++11 + GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT { + return *this = static_cast(rhs); + } +#endif + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. Its name and value will become a null value after assignment. + */ + GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT { + if (RAPIDJSON_LIKELY(this != &rhs)) { + name = rhs.name; + value = rhs.value; + } + return *this; + } + + // swap() for std::sort() and other potential use in STL. + friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT { + a.name.Swap(b.name); + a.value.Swap(b.value); + } + +private: + //! Copy constructor is not permitted. + GenericMember(const GenericMember& rhs); }; /////////////////////////////////////////////////////////////////////////////// @@ -98,16 +183,13 @@ struct GenericMember { \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template -class GenericMemberIterator - : public std::iterator >::Type> { +class GenericMemberIterator { friend class GenericValue; template friend class GenericMemberIterator; typedef GenericMember PlainType; typedef typename internal::MaybeAddConst::Type ValueType; - typedef std::iterator BaseType; public: //! Iterator type itself @@ -117,12 +199,21 @@ class GenericMemberIterator //! Non-constant iterator type typedef GenericMemberIterator NonConstIterator; + /** \name std::iterator_traits support */ + //@{ + typedef ValueType value_type; + typedef ValueType * pointer; + typedef ValueType & reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + //@} + //! Pointer to (const) GenericMember - typedef typename BaseType::pointer Pointer; + typedef pointer Pointer; //! Reference to (const) GenericMember - typedef typename BaseType::reference Reference; + typedef reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) - typedef typename BaseType::difference_type DifferenceType; + typedef difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. @@ -168,12 +259,16 @@ class GenericMemberIterator //! @name relations //@{ - bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } - bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } - bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } - bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } - bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } - bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } + template bool operator==(const GenericMemberIterator& that) const { return ptr_ == that.ptr_; } + template bool operator!=(const GenericMemberIterator& that) const { return ptr_ != that.ptr_; } + template bool operator<=(const GenericMemberIterator& that) const { return ptr_ <= that.ptr_; } + template bool operator>=(const GenericMemberIterator& that) const { return ptr_ >= that.ptr_; } + template bool operator< (const GenericMemberIterator& that) const { return ptr_ < that.ptr_; } + template bool operator> (const GenericMemberIterator& that) const { return ptr_ > that.ptr_; } + +#ifdef __cpp_lib_three_way_comparison + template std::strong_ordering operator<=>(const GenericMemberIterator& that) const { return ptr_ <=> that.ptr_; } +#endif //@} //! @name dereference @@ -198,17 +293,19 @@ class GenericMemberIterator // class-based member iterator implementation disabled, use plain pointers template -struct GenericMemberIterator; +class GenericMemberIterator; //! non-const GenericMemberIterator template -struct GenericMemberIterator { +class GenericMemberIterator { +public: //! use plain pointer as iterator type typedef GenericMember* Iterator; }; //! const GenericMemberIterator template -struct GenericMemberIterator { +class GenericMemberIterator { +public: //! use plain const pointer as iterator type typedef const GenericMember* Iterator; }; @@ -300,7 +397,7 @@ struct GenericStringRef { */ #endif explicit GenericStringRef(const CharType* str) - : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); } + : s(str), length(NotNullStrLen(str)) {} //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation @@ -312,7 +409,7 @@ struct GenericStringRef { */ #endif GenericStringRef(const CharType* str, SizeType len) - : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); } + : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} @@ -323,6 +420,14 @@ struct GenericStringRef { const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: + SizeType NotNullStrLen(const CharType* str) { + RAPIDJSON_ASSERT(str != 0); + return internal::StrLen(str); + } + + /// Empty string - used when passing in a NULL pointer + static const Ch emptyString[]; + //! Disallow construction from non-const array template GenericStringRef(CharType (&str)[N]) /* = delete */; @@ -330,6 +435,9 @@ struct GenericStringRef { GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; }; +template +const CharType GenericStringRef::emptyString[] = { CharType() }; + //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a @@ -344,7 +452,7 @@ struct GenericStringRef { */ template inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str, internal::StrLen(str)); + return GenericStringRef(str); } //! Mark a character pointer as constant string @@ -434,6 +542,26 @@ struct TypeHelper { static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } }; +#ifdef _MSC_VER +RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static long Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned long Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; +#endif + template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsInt64(); } @@ -507,7 +635,7 @@ struct TypeHelper { static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(ValueType& v) { return v.GetObject(); } static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } - static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } }; template @@ -536,7 +664,7 @@ template class GenericObject; \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. */ -template > +template class GenericValue { public: //! Name-value pair in an object. @@ -590,11 +718,11 @@ class GenericValue { \note Default content for number is zero. */ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { - static const uint16_t defaultFlags[7] = { + static const uint16_t defaultFlags[] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; - RAPIDJSON_ASSERT(type <= kNumberType); + RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. @@ -607,10 +735,40 @@ class GenericValue { \tparam SourceAllocator allocator of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) \see CopyFrom() */ - template< typename SourceAllocator > - GenericValue(const GenericValue& rhs, Allocator & allocator); + template + GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + switch (rhs.GetType()) { + case kObjectType: + DoCopyMembers(rhs, allocator, copyConstStrings); + break; + case kArrayType: { + SizeType count = rhs.data_.a.size; + GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); + const GenericValue* re = rhs.GetElementsPointer(); + for (SizeType i = 0; i < count; i++) + new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); + data_.f.flags = kArrayFlag; + data_.a.size = data_.a.capacity = count; + SetElementsPointer(le); + } + break; + case kStringType: + if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + } + else + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); + break; + default: + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + break; + } + } //! Constructor for boolean value. /*! \param b Boolean value @@ -672,6 +830,9 @@ class GenericValue { //! Constructor for double value. explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } + //! Constructor for float value. + explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } + //! Constructor for constant string (i.e. do not make a copy of string) GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } @@ -717,25 +878,30 @@ class GenericValue { /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release + // their Allocator if it's refcounted (e.g. MemoryPoolAllocator). + if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 && + internal::IsRefCounted::Value)) { switch(data_.f.flags) { case kArrayFlag: { GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); - Allocator::Free(e); + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Allocator::Free(e); + } } break; case kObjectFlag: - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - Allocator::Free(GetMembersPointer()); + DoFreeMembers(); break; case kCopyStringFlag: - Allocator::Free(const_cast(GetStringPointer())); + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Allocator::Free(const_cast(GetStringPointer())); + } break; default: @@ -753,9 +919,15 @@ class GenericValue { /*! \param rhs Source of the assignment. It will become a null value after assignment. */ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { - RAPIDJSON_ASSERT(this != &rhs); - this->~GenericValue(); - RawAssign(rhs); + if (RAPIDJSON_LIKELY(this != &rhs)) { + // Can't destroy "this" before assigning "rhs", otherwise "rhs" + // could be used after free if it's an sub-Value of "this", + // hence the temporary danse. + GenericValue temp; + temp.RawAssign(rhs); + this->~GenericValue(); + RawAssign(temp); + } return *this; } @@ -800,12 +972,13 @@ class GenericValue { \tparam SourceAllocator Allocator type of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator to use for copying + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) */ template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); this->~GenericValue(); - new (this) GenericValue(rhs, allocator); + new (this) GenericValue(rhs, allocator, copyConstStrings); return *this; } @@ -846,7 +1019,7 @@ class GenericValue { //! Equal-to operator /*! \note If an object contains duplicated named member, comparing equality with any object is always \c false. - \note Linear time complexity (number of all values in the subtree and total lengths of all strings). + \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings). */ template bool operator==(const GenericValue& rhs) const { @@ -905,6 +1078,7 @@ class GenericValue { */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } +#ifndef __cpp_impl_three_way_comparison //! Not-equal-to operator /*! \return !(*this == rhs) */ @@ -929,6 +1103,7 @@ class GenericValue { */ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} +#endif //!@name Type //@{ @@ -955,14 +1130,14 @@ class GenericValue { uint64_t u = GetUint64(); volatile double d = static_cast(u); return (d >= 0.0) - && (d < static_cast(std::numeric_limits::max())) + && (d < static_cast((std::numeric_limits::max)())) && (u == static_cast(d)); } if (IsInt64()) { int64_t i = GetInt64(); volatile double d = static_cast(i); - return (d >= static_cast(std::numeric_limits::min())) - && (d < static_cast(std::numeric_limits::max())) + return (d >= static_cast((std::numeric_limits::min)())) + && (d < static_cast((std::numeric_limits::max)())) && (i == static_cast(d)); } return true; // double, int, uint are always lossless @@ -979,8 +1154,8 @@ class GenericValue { bool IsLosslessFloat() const { if (!IsNumber()) return false; double a = GetDouble(); - if (a < static_cast(-std::numeric_limits::max()) - || a > static_cast(std::numeric_limits::max())) + if (a < static_cast(-(std::numeric_limits::max)()) + || a > static_cast((std::numeric_limits::max)())) return false; double b = static_cast(static_cast(a)); return a >= b && a <= b; // Prevent -Wfloat-equal @@ -1015,6 +1190,9 @@ class GenericValue { //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + //! Get the capacity of object. + SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } + //! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } @@ -1052,13 +1230,28 @@ class GenericValue { else { RAPIDJSON_ASSERT(false); // see above note - // This will generate -Wexit-time-destructors in clang - // static GenericValue NullValue; - // return NullValue; - - // Use static buffer and placement-new to prevent destruction - static char buffer[sizeof(GenericValue)]; +#if RAPIDJSON_HAS_CXX11 + // Use thread-local storage to prevent races between threads. + // Use static buffer and placement-new to prevent destruction, with + // alignas() to ensure proper alignment. + alignas(GenericValue) thread_local static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); +#elif defined(_MSC_VER) && _MSC_VER < 1900 + // There's no way to solve both thread locality and proper alignment + // simultaneously. + __declspec(thread) static char buffer[sizeof(GenericValue)]; return *new (buffer) GenericValue(); +#elif defined(__GNUC__) || defined(__clang__) + // This will generate -Wexit-time-destructors in clang, but that's + // better than having under-alignment. + __thread static GenericValue buffer; + return buffer; +#else + // Don't know what compiler this is, so don't know how to ensure + // thread-locality. + static GenericValue buffer; + return buffer; +#endif } } template @@ -1083,6 +1276,18 @@ class GenericValue { /*! \pre IsObject() == true */ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + //! Request the object to have enough capacity to store members. + /*! \param newCapacity The capacity that the object at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsObject()); + DoReserveMembers(newCapacity, allocator); + return *this; + } + //! Check whether a member exists in the object. /*! \param name Member name to be searched. @@ -1153,11 +1358,7 @@ class GenericValue { MemberIterator FindMember(const GenericValue& name) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); - MemberIterator member = MemberBegin(); - for ( ; member != MemberEnd(); ++member) - if (name.StringEqual(member->name)) - break; - return member; + return DoFindMember(name); } template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } @@ -1186,23 +1387,7 @@ class GenericValue { GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); - - ObjectData& o = data_.o; - if (o.size >= o.capacity) { - if (o.capacity == 0) { - o.capacity = kDefaultObjectCapacity; - SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); - } - else { - SizeType oldCapacity = o.capacity; - o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); - } - } - Member* members = GetMembersPointer(); - members[o.size].name.RawAssign(name); - members[o.size].value.RawAssign(value); - o.size++; + DoAddMember(name, value, allocator); return *this; } @@ -1336,9 +1521,7 @@ class GenericValue { */ void RemoveAllMembers() { RAPIDJSON_ASSERT(IsObject()); - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - data_.o.size = 0; + DoClearMembers(); } //! Remove a member in object by its name. @@ -1382,14 +1565,7 @@ class GenericValue { RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - - MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); - if (data_.o.size > 1 && m != last) - *m = *last; // Move the last one to this place - else - m->~Member(); // Only one left, just destroy - --data_.o.size; - return m; + return DoRemoveMember(m); } //! Remove a member from an object by iterator. @@ -1421,13 +1597,7 @@ class GenericValue { RAPIDJSON_ASSERT(first >= MemberBegin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= MemberEnd()); - - MemberIterator pos = MemberBegin() + (first - MemberBegin()); - for (MemberIterator itr = pos; itr != last; ++itr) - itr->~Member(); - std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); - data_.o.size -= static_cast(last - first); - return pos; + return DoEraseMembers(first, last); } //! Erase a member in object by its name. @@ -1456,7 +1626,9 @@ class GenericValue { } Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } //@} @@ -1628,8 +1800,8 @@ class GenericValue { RAPIDJSON_ASSERT(last <= End()); ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr) - itr->~GenericValue(); - std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); + itr->~GenericValue(); + std::memmove(static_cast(pos), last, static_cast(End() - last) * sizeof(GenericValue)); data_.a.size -= static_cast(last - first); return pos; } @@ -1671,19 +1843,19 @@ class GenericValue { GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } - GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; } + GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } //@} //!@name String //@{ - const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); } //! Get the length of string. /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). */ - SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); } //! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. @@ -1710,7 +1882,7 @@ class GenericValue { \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } //! Set this value as a string by copying from source string. /*! \param s source string. @@ -1718,7 +1890,15 @@ class GenericValue { \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } + + //! Set this value as a string by copying from source string. + /*! \param s source string reference + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. @@ -1728,7 +1908,7 @@ class GenericValue { \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } #endif //@} @@ -1786,7 +1966,7 @@ class GenericValue { case kArrayType: if (RAPIDJSON_UNLIKELY(!handler.StartArray())) return false; - for (const GenericValue* v = Begin(); v != End(); ++v) + for (ConstValueIterator v = Begin(); v != End(); ++v) if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) return false; return handler.EndArray(data_.a.size); @@ -1822,25 +2002,26 @@ class GenericValue { // Initial flags of different types. kNullFlag = kNullType, - kTrueFlag = kTrueType | kBoolFlag, - kFalseFlag = kFalseType | kBoolFlag, - kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, - kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, - kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, - kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, - kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, - kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, - kConstStringFlag = kStringType | kStringFlag, - kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, - kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, + // These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types. + kTrueFlag = static_cast(kTrueType) | static_cast(kBoolFlag), + kFalseFlag = static_cast(kFalseType) | static_cast(kBoolFlag), + kNumberIntFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kIntFlag | kInt64Flag), + kNumberUintFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag), + kNumberInt64Flag = static_cast(kNumberType) | static_cast(kNumberFlag | kInt64Flag), + kNumberUint64Flag = static_cast(kNumberType) | static_cast(kNumberFlag | kUint64Flag), + kNumberDoubleFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kDoubleFlag), + kNumberAnyFlag = static_cast(kNumberType) | static_cast(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag), + kConstStringFlag = static_cast(kStringType) | static_cast(kStringFlag), + kCopyStringFlag = static_cast(kStringType) | static_cast(kStringFlag | kCopyFlag), + kShortStringFlag = static_cast(kStringType) | static_cast(kStringFlag | kCopyFlag | kInlineStrFlag), kObjectFlag = kObjectType, kArrayFlag = kArrayType, kTypeMask = 0x07 }; - static const SizeType kDefaultArrayCapacity = 16; - static const SizeType kDefaultObjectCapacity = 16; + static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY; + static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY; struct Flag { #if RAPIDJSON_48BITPOINTER_OPTIMIZATION @@ -1923,6 +2104,13 @@ class GenericValue { Flag f; }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION + static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) { + return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str); + } + static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) { + return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length; + } + RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } @@ -1930,13 +2118,293 @@ class GenericValue { RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } +#if RAPIDJSON_USE_MEMBERSMAP + + struct MapTraits { + struct Less { + bool operator()(const Data& s1, const Data& s2) const { + SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2); + int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2)); + return cmp < 0 || (cmp == 0 && n1 < n2); + } + }; + typedef std::pair Pair; + typedef std::multimap > Map; + typedef typename Map::iterator Iterator; + }; + typedef typename MapTraits::Map Map; + typedef typename MapTraits::Less MapLess; + typedef typename MapTraits::Pair MapPair; + typedef typename MapTraits::Iterator MapIterator; + + // + // Layout of the members' map/array, re(al)located according to the needed capacity: + // + // {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]} + // + // (where <> stands for the RAPIDJSON_ALIGN-ment, if needed) + // + + static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) { + return RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType)) + + RAPIDJSON_ALIGN(capacity * sizeof(Member)) + + capacity * sizeof(MapIterator); + } + + static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) { + return *reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*))); + } + + static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) { + return reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType))); + } + + static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) { + return reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType)) + + RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member))); + } + + static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) { + RAPIDJSON_ASSERT(members != 0); + return *reinterpret_cast(reinterpret_cast(members) - + RAPIDJSON_ALIGN(sizeof(SizeType)) - + RAPIDJSON_ALIGN(sizeof(Map*))); + } + + // Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting.. + RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) { +#if RAPIDJSON_HAS_CXX11 + MapIterator ret = std::move(rhs); +#else + MapIterator ret = rhs; +#endif + rhs.~MapIterator(); + return ret; + } + + Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) { + Map **newMap = static_cast(allocator.Malloc(GetMapLayoutSize(newCapacity))); + GetMapCapacity(*newMap) = newCapacity; + if (!oldMap) { + *newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator); + } + else { + *newMap = *oldMap; + size_t count = (*oldMap)->size(); + std::memcpy(static_cast(GetMapMembers(*newMap)), + static_cast(GetMapMembers(*oldMap)), + count * sizeof(Member)); + MapIterator *oldIt = GetMapIterators(*oldMap), + *newIt = GetMapIterators(*newMap); + while (count--) { + new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count])); + } + Allocator::Free(oldMap); + } + return *newMap; + } + + RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { + return GetMapMembers(DoReallocMap(0, capacity, allocator)); + } + + void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { + ObjectData& o = data_.o; + if (newCapacity > o.capacity) { + Member* oldMembers = GetMembersPointer(); + Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0, + *&newMap = DoReallocMap(oldMap, newCapacity, allocator); + RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap)); + o.capacity = newCapacity; + } + } + + template + MemberIterator DoFindMember(const GenericValue& name) { + if (Member* members = GetMembersPointer()) { + Map* &map = GetMap(members); + MapIterator mit = map->find(reinterpret_cast(name.data_)); + if (mit != map->end()) { + return MemberIterator(&members[mit->second]); + } + } + return MemberEnd(); + } + + void DoClearMembers() { + if (Member* members = GetMembersPointer()) { + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + for (SizeType i = 0; i < data_.o.size; i++) { + map->erase(DropMapIterator(mit[i])); + members[i].~Member(); + } + data_.o.size = 0; + } + } + + void DoFreeMembers() { + if (Member* members = GetMembersPointer()) { + GetMap(members)->~Map(); + for (SizeType i = 0; i < data_.o.size; i++) { + members[i].~Member(); + } + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Map** map = &GetMap(members); + Allocator::Free(*map); + Allocator::Free(map); + } + } + } + +#else // !RAPIDJSON_USE_MEMBERSMAP + + RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { + return Malloc(allocator, capacity); + } + + void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { + ObjectData& o = data_.o; + if (newCapacity > o.capacity) { + Member* newMembers = Realloc(allocator, GetMembersPointer(), o.capacity, newCapacity); + RAPIDJSON_SETPOINTER(Member, o.members, newMembers); + o.capacity = newCapacity; + } + } + + template + MemberIterator DoFindMember(const GenericValue& name) { + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + + void DoClearMembers() { + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + data_.o.size = 0; + } + + void DoFreeMembers() { + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + Allocator::Free(GetMembersPointer()); + } + +#endif // !RAPIDJSON_USE_MEMBERSMAP + + void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + ObjectData& o = data_.o; + if (o.size >= o.capacity) + DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator); + Member* members = GetMembersPointer(); + Member* m = members + o.size; + m->name.RawAssign(name); + m->value.RawAssign(value); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size))); +#endif + ++o.size; + } + + MemberIterator DoRemoveMember(MemberIterator m) { + ObjectData& o = data_.o; + Member* members = GetMembersPointer(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + SizeType mpos = static_cast(&*m - members); + map->erase(DropMapIterator(mit[mpos])); +#endif + MemberIterator last(members + (o.size - 1)); + if (o.size > 1 && m != last) { +#if RAPIDJSON_USE_MEMBERSMAP + new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members])); + mit[mpos]->second = mpos; +#endif + *m = *last; // Move the last one to this place + } + else { + m->~Member(); // Only one left, just destroy + } + --o.size; + return m; + } + + MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) { + ObjectData& o = data_.o; + MemberIterator beg = MemberBegin(), + pos = beg + (first - beg), + end = MemberEnd(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(GetMembersPointer()); + MapIterator* mit = GetMapIterators(map); +#endif + for (MemberIterator itr = pos; itr != last; ++itr) { +#if RAPIDJSON_USE_MEMBERSMAP + map->erase(DropMapIterator(mit[itr - beg])); +#endif + itr->~Member(); + } +#if RAPIDJSON_USE_MEMBERSMAP + if (first != last) { + // Move remaining members/iterators + MemberIterator next = pos + (last - first); + for (MemberIterator itr = pos; next != end; ++itr, ++next) { + std::memcpy(static_cast(&*itr), &*next, sizeof(Member)); + SizeType mpos = static_cast(itr - beg); + new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg])); + mit[mpos]->second = mpos; + } + } +#else + std::memmove(static_cast(&*pos), &*last, + static_cast(end - last) * sizeof(Member)); +#endif + o.size -= static_cast(last - first); + return pos; + } + + template + void DoCopyMembers(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings) { + RAPIDJSON_ASSERT(rhs.GetType() == kObjectType); + + data_.f.flags = kObjectFlag; + SizeType count = rhs.data_.o.size; + Member* lm = DoAllocMembers(count, allocator); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(lm); + MapIterator* mit = GetMapIterators(map); +#endif + for (SizeType i = 0; i < count; i++) { + new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); +#if RAPIDJSON_USE_MEMBERSMAP + new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i))); +#endif + } + data_.o.size = data_.o.capacity = count; + SetMembersPointer(lm); + } + // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { data_.f.flags = kArrayFlag; if (count) { GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); SetElementsPointer(e); - std::memcpy(e, values, count * sizeof(GenericValue)); + std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); } else SetElementsPointer(0); @@ -1947,9 +2415,16 @@ class GenericValue { void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { data_.f.flags = kObjectFlag; if (count) { - Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + Member* m = DoAllocMembers(count, allocator); SetMembersPointer(m); - std::memcpy(m, members, count * sizeof(Member)); + std::memcpy(static_cast(m), members, count * sizeof(Member)); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(m); + MapIterator* mit = GetMapIterators(map); + for (SizeType i = 0; i < count; i++) { + new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i))); + } +#endif } else SetMembersPointer(0); @@ -2020,12 +2495,13 @@ typedef GenericValue > Value; \tparam StackAllocator Allocator for allocating memory for stack during parsing. \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. */ -template , typename StackAllocator = CrtAllocator> +template class GenericDocument : public GenericValue { public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericValue ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef StackAllocator StackAllocatorType; //!< StackAllocator type from template parameter. //! Constructor /*! Creates an empty document of specified type. @@ -2038,7 +2514,7 @@ class GenericDocument : public GenericValue { GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } //! Constructor @@ -2051,7 +2527,7 @@ class GenericDocument : public GenericValue { allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS @@ -2070,6 +2546,13 @@ class GenericDocument : public GenericValue { #endif ~GenericDocument() { + // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType() + // runs last and may access its elements or members which would be freed + // with an allocator like MemoryPoolAllocator (CrtAllocator does not + // free its data when destroyed, but MemoryPoolAllocator does). + if (ownAllocator_) { + ValueType::SetNull(); + } Destroy(); } @@ -2112,6 +2595,10 @@ class GenericDocument : public GenericValue { return *this; } + // Allow Swap with ValueType. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + using ValueType::Swap; + //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: @@ -2243,7 +2730,7 @@ class GenericDocument : public GenericValue { template GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - MemoryStream ms(static_cast(str), length * sizeof(typename SourceEncoding::Ch)); + MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); EncodedInputStream is(ms); ParseStream(is); return *this; @@ -2280,7 +2767,7 @@ class GenericDocument : public GenericValue { //!@name Handling parse errors //!@{ - //! Whether a parse error has occured in the last parsing. + //! Whether a parse error has occurred in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. @@ -2401,34 +2888,6 @@ class GenericDocument : public GenericValue { //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; -// defined here due to the dependency on GenericDocument -template -template -inline -GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) -{ - switch (rhs.GetType()) { - case kObjectType: - case kArrayType: { // perform deep copy via SAX Handler - GenericDocument d(&allocator); - rhs.Accept(d); - RawAssign(*d.stack_.template Pop(1)); - } - break; - case kStringType: - if (rhs.data_.f.flags == kConstStringFlag) { - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - } else { - SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); - } - break; - default: - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - break; - } -} //! Helper class for accessing Value of array type. /*! @@ -2454,6 +2913,7 @@ class GenericArray { GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } ~GenericArray() {} + operator ValueType&() const { return value_; } SizeType Size() const { return value_.Size(); } SizeType Capacity() const { return value_.Capacity(); } bool Empty() const { return value_.Empty(); } @@ -2509,7 +2969,9 @@ class GenericObject { GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } ~GenericObject() {} + operator ValueType&() const { return value_; } SizeType MemberCount() const { return value_.MemberCount(); } + SizeType MemberCapacity() const { return value_.MemberCapacity(); } bool ObjectEmpty() const { return value_.ObjectEmpty(); } template ValueType& operator[](T* name) const { return value_[name]; } template ValueType& operator[](const GenericValue& name) const { return value_[name]; } @@ -2518,6 +2980,7 @@ class GenericObject { #endif MemberIterator MemberBegin() const { return value_.MemberBegin(); } MemberIterator MemberEnd() const { return value_.MemberEnd(); } + GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if RAPIDJSON_HAS_STDSTRING bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } @@ -2543,7 +3006,7 @@ class GenericObject { GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - void RemoveAllMembers() { return value_.RemoveAllMembers(); } + void RemoveAllMembers() { value_.RemoveAllMembers(); } bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } @@ -2572,4 +3035,9 @@ class GenericObject { RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP +#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#pragma pop_macro("GetObject") +#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#endif + #endif // RAPIDJSON_DOCUMENT_H_ diff --git a/src/utility/rapidjson/encodedstream.h b/src/common/thirdparty/rapidjson/encodedstream.h similarity index 98% rename from src/utility/rapidjson/encodedstream.h rename to src/common/thirdparty/rapidjson/encodedstream.h index 145068386a0..cf046b89235 100644 --- a/src/utility/rapidjson/encodedstream.h +++ b/src/common/thirdparty/rapidjson/encodedstream.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -200,7 +200,7 @@ class AutoUTFInputStream { // xx xx xx xx UTF-8 if (!hasBOM_) { - unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); switch (pattern) { case 0x08: type_ = kUTF32BE; break; case 0x0A: type_ = kUTF16BE; break; diff --git a/src/utility/rapidjson/encodings.h b/src/common/thirdparty/rapidjson/encodings.h similarity index 90% rename from src/utility/rapidjson/encodings.h rename to src/common/thirdparty/rapidjson/encodings.h index baa7c2b17f8..50ad18bdc08 100644 --- a/src/utility/rapidjson/encodings.h +++ b/src/common/thirdparty/rapidjson/encodings.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -17,7 +17,7 @@ #include "rapidjson.h" -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data RAPIDJSON_DIAG_OFF(4702) // unreachable code @@ -144,9 +144,9 @@ struct UTF8 { template static bool Decode(InputStream& is, unsigned* codepoint) { -#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) -#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define TAIL() COPY(); TRANS(0x70) +#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) +#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) typename InputStream::Ch c = is.Take(); if (!(c & 0x80)) { *codepoint = static_cast(c); @@ -157,48 +157,48 @@ struct UTF8 { if (type >= 32) { *codepoint = 0; } else { - *codepoint = (0xFF >> type) & static_cast(c); + *codepoint = (0xFFu >> type) & static_cast(c); } bool result = true; switch (type) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + case 2: RAPIDJSON_TAIL(); return result; + case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; + case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; + case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; default: return false; } -#undef COPY -#undef TRANS -#undef TAIL +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL } template static bool Validate(InputStream& is, OutputStream& os) { -#define COPY() os.Put(c = is.Take()) -#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define TAIL() COPY(); TRANS(0x70) +#define RAPIDJSON_COPY() os.Put(c = is.Take()) +#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) Ch c; - COPY(); + RAPIDJSON_COPY(); if (!(c & 0x80)) return true; bool result = true; switch (GetRange(static_cast(c))) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + case 2: RAPIDJSON_TAIL(); return result; + case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; + case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; + case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; default: return false; } -#undef COPY -#undef TRANS -#undef TAIL +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL } static unsigned char GetRange(unsigned char c) { @@ -283,7 +283,7 @@ struct UTF16 { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; os.Put(static_cast((v >> 10) | 0xD800)); - os.Put((v & 0x3FF) | 0xDC00); + os.Put(static_cast((v & 0x3FF) | 0xDC00)); } } @@ -299,7 +299,7 @@ struct UTF16 { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; PutUnsafe(os, static_cast((v >> 10) | 0xD800)); - PutUnsafe(os, (v & 0x3FF) | 0xDC00); + PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); } } @@ -384,7 +384,7 @@ struct UTF16BE : UTF16 { static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 8; - c |= static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())); return static_cast(c); } @@ -620,28 +620,28 @@ struct AutoUTF { #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x template - RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } template - RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; (*f[os.GetType()])(os, codepoint); } template - RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { + static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); @@ -658,7 +658,7 @@ template struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -667,7 +667,7 @@ struct Transcoder { } template - RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -677,7 +677,7 @@ struct Transcoder { //! Validate one Unicode codepoint from an encoded stream. template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; @@ -690,26 +690,26 @@ inline void PutUnsafe(Stream& stream, typename Stream::Ch c); template struct Transcoder { template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template - RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; RAPIDJSON_NAMESPACE_END -#if defined(__GNUC__) || defined(_MSC_VER) +#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) RAPIDJSON_DIAG_POP #endif diff --git a/src/common/thirdparty/rapidjson/error/en.h b/src/common/thirdparty/rapidjson/error/en.h new file mode 100644 index 00000000000..c87b04eb133 --- /dev/null +++ b/src/common/thirdparty/rapidjson/error/en.h @@ -0,0 +1,176 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_EN_H_ +#define RAPIDJSON_ERROR_EN_H_ + +#include "error.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(covered-switch-default) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Maps error code of parsing into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param parseErrorCode Error code obtained in parsing. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { + switch (parseErrorCode) { + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); + + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); + + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); + case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); + case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); + + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); + + case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); + case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); + case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); + case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); + + case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); + case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); + case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); + + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +//! Maps error code of validation into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param validateErrorCode Error code obtained from validator. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) { + switch (validateErrorCode) { + case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred"); + case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'."); + case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'."); + case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'."); + case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'."); + case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'."); + + case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'."); + case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'."); + case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression."); + + case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'."); + case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'."); + case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true."); + case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema."); + + case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'."); + case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'."); + case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'."); + case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema."); + case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema."); + case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors."); + + case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values."); + case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); + + case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); + case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf', indices '%matches'."); + case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); + case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); + case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); + + case kValidateErrorReadOnly: return RAPIDJSON_ERROR_STRING("Property is read-only but has been provided when validation is for writing."); + case kValidateErrorWriteOnly: return RAPIDJSON_ERROR_STRING("Property is write-only but has been provided when validation is for reading."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +//! Maps error code of schema document compilation into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param schemaErrorCode Error code obtained from compiling the schema document. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ + inline const RAPIDJSON_ERROR_CHARTYPE* GetSchemaError_En(SchemaErrorCode schemaErrorCode) { + switch (schemaErrorCode) { + case kSchemaErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kSchemaErrorStartUnknown: return RAPIDJSON_ERROR_STRING("Pointer '%value' to start of schema does not resolve to a location in the document."); + case kSchemaErrorRefPlainName: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' must be a JSON pointer."); + case kSchemaErrorRefInvalid: return RAPIDJSON_ERROR_STRING("$ref must not be an empty string."); + case kSchemaErrorRefPointerInvalid: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' is not a valid JSON pointer at offset '%offset'."); + case kSchemaErrorRefUnknown: return RAPIDJSON_ERROR_STRING("$ref '%value' does not resolve to a location in the target document."); + case kSchemaErrorRefCyclical: return RAPIDJSON_ERROR_STRING("$ref '%value' is cyclical."); + case kSchemaErrorRefNoRemoteProvider: return RAPIDJSON_ERROR_STRING("$ref is remote but there is no remote provider."); + case kSchemaErrorRefNoRemoteSchema: return RAPIDJSON_ERROR_STRING("$ref '%value' is remote but the remote provider did not return a schema."); + case kSchemaErrorRegexInvalid: return RAPIDJSON_ERROR_STRING("Invalid regular expression '%value' in 'pattern' or 'patternProperties'."); + case kSchemaErrorSpecUnknown: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not recognized."); + case kSchemaErrorSpecUnsupported: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not supported."); + case kSchemaErrorSpecIllegal: return RAPIDJSON_ERROR_STRING("Both JSON schema draft and OpenAPI version found in document."); + case kSchemaErrorReadOnlyAndWriteOnly: return RAPIDJSON_ERROR_STRING("Property must not be both 'readOnly' and 'writeOnly'."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } + } + +//! Maps error code of pointer parse into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param pointerParseErrorCode Error code obtained from pointer parse. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE* GetPointerParseError_En(PointerParseErrorCode pointerParseErrorCode) { + switch (pointerParseErrorCode) { + case kPointerParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kPointerParseErrorTokenMustBeginWithSolidus: return RAPIDJSON_ERROR_STRING("A token must begin with a '/'."); + case kPointerParseErrorInvalidEscape: return RAPIDJSON_ERROR_STRING("Invalid escape."); + case kPointerParseErrorInvalidPercentEncoding: return RAPIDJSON_ERROR_STRING("Invalid percent encoding in URI fragment."); + case kPointerParseErrorCharacterMustPercentEncode: return RAPIDJSON_ERROR_STRING("A character must be percent encoded in a URI fragment."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/src/common/thirdparty/rapidjson/error/error.h b/src/common/thirdparty/rapidjson/error/error.h new file mode 100644 index 00000000000..cae345db36d --- /dev/null +++ b/src/common/thirdparty/rapidjson/error/error.h @@ -0,0 +1,285 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_ERROR_H_ +#define RAPIDJSON_ERROR_ERROR_H_ + +#include "../rapidjson.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +/*! \file error.h */ + +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_CHARTYPE + +//! Character type of error messages. +/*! \ingroup RAPIDJSON_ERRORS + The default character type is \c char. + On Windows, user can define this macro as \c TCHAR for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_CHARTYPE +#define RAPIDJSON_ERROR_CHARTYPE char +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_STRING + +//! Macro for converting string literal to \ref RAPIDJSON_ERROR_CHARTYPE[]. +/*! \ingroup RAPIDJSON_ERRORS + By default this conversion macro does nothing. + On Windows, user can define this macro as \c _T(x) for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_STRING +#define RAPIDJSON_ERROR_STRING(x) x +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseErrorCode + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericReader::Parse, GenericReader::GetParseErrorCode +*/ +enum ParseErrorCode { + kParseErrorNone = 0, //!< No error. + + kParseErrorDocumentEmpty, //!< The document is empty. + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. + + kParseErrorValueInvalid, //!< Invalid value. + + kParseErrorObjectMissName, //!< Missing a name for object member. + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. + + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. + + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. + + kParseErrorNumberTooBig, //!< Number too big to be stored in double. + kParseErrorNumberMissFraction, //!< Miss fraction part in number. + kParseErrorNumberMissExponent, //!< Miss exponent in number. + + kParseErrorTermination, //!< Parsing was terminated. + kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. +}; + +//! Result of parsing (wraps ParseErrorCode) +/*! + \ingroup RAPIDJSON_ERRORS + \code + Document doc; + ParseResult ok = doc.Parse("[42]"); + if (!ok) { + fprintf(stderr, "JSON parse error: %s (%u)", + GetParseError_En(ok.Code()), ok.Offset()); + exit(EXIT_FAILURE); + } + \endcode + \see GenericReader::Parse, GenericDocument::Parse +*/ +struct ParseResult { + //!! Unspecified boolean type + typedef bool (ParseResult::*BooleanType)() const; +public: + //! Default constructor, no error. + ParseResult() : code_(kParseErrorNone), offset_(0) {} + //! Constructor to set an error. + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + + //! Get the error code. + ParseErrorCode Code() const { return code_; } + //! Get the error offset, if \ref IsError(), 0 otherwise. + size_t Offset() const { return offset_; } + + //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). + operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } + //! Whether the result is an error. + bool IsError() const { return code_ != kParseErrorNone; } + + bool operator==(const ParseResult& that) const { return code_ == that.code_; } + bool operator==(ParseErrorCode code) const { return code_ == code; } + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + + bool operator!=(const ParseResult& that) const { return !(*this == that); } + bool operator!=(ParseErrorCode code) const { return !(*this == code); } + friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } + + //! Reset error code. + void Clear() { Set(kParseErrorNone); } + //! Update error code and offset. + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + +private: + ParseErrorCode code_; + size_t offset_; +}; + +//! Function pointer type of GetParseError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetParseError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); + +/////////////////////////////////////////////////////////////////////////////// +// ValidateErrorCode + +//! Error codes when validating. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericSchemaValidator +*/ +enum ValidateErrorCode { + kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set. + kValidateErrorNone = 0, //!< No error. + + kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value. + kValidateErrorMaximum, //!< Number is greater than the 'maximum' value. + kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value. + kValidateErrorMinimum, //!< Number is less than the 'minimum' value. + kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value. + + kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value. + kValidateErrorMinLength, //!< String is longer than the 'maxLength' value. + kValidateErrorPattern, //!< String does not match the 'pattern' regular expression. + + kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value. + kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value. + kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true. + kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema. + + kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value. + kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value. + kValidateErrorRequired, //!< Object is missing one or more members required by the schema. + kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema. + kValidateErrorPatternProperties, //!< See other errors. + kValidateErrorDependencies, //!< Object has missing property or schema dependencies. + + kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values. + kValidateErrorType, //!< Property has a type that is not allowed by the schema. + + kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'. + kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'. + kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'. + kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'. + kValidateErrorNot, //!< Property matched the sub-schema specified by 'not'. + + kValidateErrorReadOnly, //!< Property is read-only but has been provided when validation is for writing + kValidateErrorWriteOnly //!< Property is write-only but has been provided when validation is for reading +}; + +//! Function pointer type of GetValidateError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetValidateError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode); + +/////////////////////////////////////////////////////////////////////////////// +// SchemaErrorCode + +//! Error codes when validating. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericSchemaValidator +*/ +enum SchemaErrorCode { + kSchemaErrorNone = 0, //!< No error. + + kSchemaErrorStartUnknown, //!< Pointer to start of schema does not resolve to a location in the document + kSchemaErrorRefPlainName, //!< $ref fragment must be a JSON pointer + kSchemaErrorRefInvalid, //!< $ref must not be an empty string + kSchemaErrorRefPointerInvalid, //!< $ref fragment is not a valid JSON pointer at offset + kSchemaErrorRefUnknown, //!< $ref does not resolve to a location in the target document + kSchemaErrorRefCyclical, //!< $ref is cyclical + kSchemaErrorRefNoRemoteProvider, //!< $ref is remote but there is no remote provider + kSchemaErrorRefNoRemoteSchema, //!< $ref is remote but the remote provider did not return a schema + kSchemaErrorRegexInvalid, //!< Invalid regular expression in 'pattern' or 'patternProperties' + kSchemaErrorSpecUnknown, //!< JSON schema draft or OpenAPI version is not recognized + kSchemaErrorSpecUnsupported, //!< JSON schema draft or OpenAPI version is not supported + kSchemaErrorSpecIllegal, //!< Both JSON schema draft and OpenAPI version found in document + kSchemaErrorReadOnlyAndWriteOnly //!< Property must not be both 'readOnly' and 'writeOnly' +}; + +//! Function pointer type of GetSchemaError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetSchemaError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetSchemaErrorFunc GetSchemaError = GetSchemaError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetSchemaError(validator.GetInvalidSchemaCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetSchemaErrorFunc)(SchemaErrorCode); + +/////////////////////////////////////////////////////////////////////////////// +// PointerParseErrorCode + +//! Error code of JSON pointer parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode +*/ +enum PointerParseErrorCode { + kPointerParseErrorNone = 0, //!< The parse is successful + + kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' + kPointerParseErrorInvalidEscape, //!< Invalid escape + kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment + kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment +}; + +//! Function pointer type of GetPointerParseError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetPointerParseError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetPointerParseErrorFunc GetPointerParseError = GetPointerParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetPointerParseError(pointer.GetParseErrorCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetPointerParseErrorFunc)(PointerParseErrorCode); + + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/src/utility/rapidjson/filereadstream.h b/src/common/thirdparty/rapidjson/filereadstream.h similarity index 94% rename from src/utility/rapidjson/filereadstream.h rename to src/common/thirdparty/rapidjson/filereadstream.h index b56ea13b342..f8bb43cb0cf 100644 --- a/src/utility/rapidjson/filereadstream.h +++ b/src/common/thirdparty/rapidjson/filereadstream.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -59,7 +59,7 @@ class FileReadStream { // For encoding detection only. const Ch* Peek4() const { - return (current_ + 4 <= bufferLast_) ? current_ : 0; + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; } private: @@ -68,7 +68,7 @@ class FileReadStream { ++current_; else if (!eof_) { count_ += readCount_; - readCount_ = fread(buffer_, 1, bufferSize_, fp_); + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; diff --git a/src/utility/rapidjson/filewritestream.h b/src/common/thirdparty/rapidjson/filewritestream.h similarity index 94% rename from src/utility/rapidjson/filewritestream.h rename to src/common/thirdparty/rapidjson/filewritestream.h index 6378dd60ed4..5d89588c218 100644 --- a/src/utility/rapidjson/filewritestream.h +++ b/src/common/thirdparty/rapidjson/filewritestream.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -25,7 +25,7 @@ RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_NAMESPACE_BEGIN -//! Wrapper of C file stream for input using fread(). +//! Wrapper of C file stream for output using fwrite(). /*! \note implements Stream concept */ @@ -62,7 +62,7 @@ class FileWriteStream { void Flush() { if (current_ != buffer_) { - size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); if (result < static_cast(current_ - buffer_)) { // failure deliberately ignored at this time // added to avoid warn_unused_result build errors diff --git a/src/utility/rapidjson/fwd.h b/src/common/thirdparty/rapidjson/fwd.h similarity index 98% rename from src/utility/rapidjson/fwd.h rename to src/common/thirdparty/rapidjson/fwd.h index e8104e841bc..d62f77f0ecf 100644 --- a/src/utility/rapidjson/fwd.h +++ b/src/common/thirdparty/rapidjson/fwd.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -102,7 +102,7 @@ class PrettyWriter; // document.h template -struct GenericMember; +class GenericMember; template class GenericMemberIterator; diff --git a/src/utility/rapidjson/internal/biginteger.h b/src/common/thirdparty/rapidjson/internal/biginteger.h similarity index 92% rename from src/utility/rapidjson/internal/biginteger.h rename to src/common/thirdparty/rapidjson/internal/biginteger.h index 9d3e88c9981..af487380389 100644 --- a/src/utility/rapidjson/internal/biginteger.h +++ b/src/common/thirdparty/rapidjson/internal/biginteger.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -17,9 +17,13 @@ #include "../rapidjson.h" -#if defined(_MSC_VER) && defined(_M_AMD64) +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) #include // for _umul128 +#if !defined(_ARM64EC_) #pragma intrinsic(_umul128) +#else +#pragma comment(lib,"softintrin") +#endif #endif RAPIDJSON_NAMESPACE_BEGIN @@ -37,7 +41,8 @@ class BigInteger { digits_[0] = u; } - BigInteger(const char* decimals, size_t length) : count_(1) { + template + BigInteger(const Ch* decimals, size_t length) : count_(1) { RAPIDJSON_ASSERT(length > 0); digits_[0] = 0; size_t i = 0; @@ -133,7 +138,7 @@ class BigInteger { RAPIDJSON_ASSERT(count_ + offset <= kCapacity); if (interShift == 0) { - std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); + std::memmove(digits_ + offset, digits_, count_ * sizeof(Type)); count_ += offset; } else { @@ -221,7 +226,8 @@ class BigInteger { bool IsZero() const { return count_ == 1 && digits_[0] == 0; } private: - void AppendDecimal64(const char* begin, const char* end) { + template + void AppendDecimal64(const Ch* begin, const Ch* end) { uint64_t u = ParseUint64(begin, end); if (IsZero()) *this = u; @@ -236,11 +242,12 @@ class BigInteger { digits_[count_++] = digit; } - static uint64_t ParseUint64(const char* begin, const char* end) { + template + static uint64_t ParseUint64(const Ch* begin, const Ch* end) { uint64_t r = 0; - for (const char* p = begin; p != end; ++p) { - RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); - r = r * 10u + static_cast(*p - '0'); + for (const Ch* p = begin; p != end; ++p) { + RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9')); + r = r * 10u + static_cast(*p - Ch('0')); } return r; } diff --git a/src/common/thirdparty/rapidjson/internal/clzll.h b/src/common/thirdparty/rapidjson/internal/clzll.h new file mode 100644 index 00000000000..8fc5118aa47 --- /dev/null +++ b/src/common/thirdparty/rapidjson/internal/clzll.h @@ -0,0 +1,71 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CLZLL_H_ +#define RAPIDJSON_CLZLL_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && !defined(UNDER_CE) +#include +#if defined(_WIN64) +#pragma intrinsic(_BitScanReverse64) +#else +#pragma intrinsic(_BitScanReverse) +#endif +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline uint32_t clzll(uint64_t x) { + // Passing 0 to __builtin_clzll is UB in GCC and results in an + // infinite loop in the software implementation. + RAPIDJSON_ASSERT(x != 0); + +#if defined(_MSC_VER) && !defined(UNDER_CE) + unsigned long r = 0; +#if defined(_WIN64) + _BitScanReverse64(&r, x); +#else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); +#endif // _WIN64 + + return 63 - r; +#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) + // __builtin_clzll wrapper + return static_cast(__builtin_clzll(x)); +#else + // naive version + uint32_t r = 0; + while (!(x & (static_cast(1) << 63))) { + x <<= 1; + ++r; + } + + return r; +#endif // _MSC_VER +} + +#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CLZLL_H_ diff --git a/src/utility/rapidjson/internal/diyfp.h b/src/common/thirdparty/rapidjson/internal/diyfp.h similarity index 92% rename from src/utility/rapidjson/internal/diyfp.h rename to src/common/thirdparty/rapidjson/internal/diyfp.h index c9fefdc6139..f7d46539a90 100644 --- a/src/utility/rapidjson/internal/diyfp.h +++ b/src/common/thirdparty/rapidjson/internal/diyfp.h @@ -1,15 +1,15 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: @@ -20,11 +20,16 @@ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" +#include "clzll.h" +#include -#if defined(_MSC_VER) && defined(_M_AMD64) +#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include -#pragma intrinsic(_BitScanReverse64) +#if !defined(_ARM64EC_) #pragma intrinsic(_umul128) +#else +#pragma comment(lib,"softintrin") +#endif #endif RAPIDJSON_NAMESPACE_BEGIN @@ -56,7 +61,7 @@ struct DiyFp { if (biased_e != 0) { f = significand + kDpHiddenBit; e = biased_e - kDpExponentBias; - } + } else { f = significand; e = kDpMinExponent + 1; @@ -99,21 +104,8 @@ struct DiyFp { } DiyFp Normalize() const { -#if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp(f << (63 - index), e - (63 - index)); -#elif defined(__GNUC__) && __GNUC__ >= 4 - int s = __builtin_clzll(f); + int s = static_cast(clzll(f)); return DiyFp(f << s, e - s); -#else - DiyFp res = *this; - while (!(res.f & (static_cast(1) << 63))) { - res.f <<= 1; - res.e--; - } - return res; -#endif } DiyFp NormalizeBoundary() const { @@ -141,7 +133,16 @@ struct DiyFp { double d; uint64_t u64; }u; - const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); + if (e < kDpDenormalExponent) { + // Underflow. + return 0.0; + } + if (e >= kDpMaxExponent) { + // Overflow. + return std::numeric_limits::infinity(); + } + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : static_cast(e + kDpExponentBias); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); return u.d; @@ -220,9 +221,10 @@ inline DiyFp GetCachedPowerByIndex(size_t index) { 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 }; + RAPIDJSON_ASSERT(index < 87); return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); } - + inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; @@ -238,10 +240,11 @@ inline DiyFp GetCachedPower(int e, int* K) { } inline DiyFp GetCachedPower10(int exp, int *outExp) { - unsigned index = (static_cast(exp) + 348u) / 8u; - *outExp = -348 + static_cast(index) * 8; - return GetCachedPowerByIndex(index); - } + RAPIDJSON_ASSERT(exp >= -348); + unsigned index = static_cast(exp + 348) / 8u; + *outExp = -348 + static_cast(index) * 8; + return GetCachedPowerByIndex(index); +} #ifdef __GNUC__ RAPIDJSON_DIAG_POP diff --git a/src/utility/rapidjson/internal/dtoa.h b/src/common/thirdparty/rapidjson/internal/dtoa.h similarity index 90% rename from src/utility/rapidjson/internal/dtoa.h rename to src/common/thirdparty/rapidjson/internal/dtoa.h index 8d6350e626d..cd456721a71 100644 --- a/src/utility/rapidjson/internal/dtoa.h +++ b/src/common/thirdparty/rapidjson/internal/dtoa.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -41,7 +41,7 @@ inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin } } -inline unsigned CountDecimalDigit32(uint32_t n) { +inline int CountDecimalDigit32(uint32_t n) { // Simple pure C++ implementation was faster than __builtin_clz version in this situation. if (n < 10) return 1; if (n < 100) return 2; @@ -58,12 +58,16 @@ inline unsigned CountDecimalDigit32(uint32_t n) { } inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { - static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + static const uint64_t kPow10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL, + 1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL, + 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, + 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, + 10000000000000000000ULL }; const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp wp_w = Mp - W; uint32_t p1 = static_cast(Mp.f >> -one.e); uint64_t p2 = Mp.f & (one.f - 1); - unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] *len = 0; while (kappa > 0) { @@ -86,7 +90,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff uint64_t tmp = (static_cast(p1) << -one.e) + p2; if (tmp <= delta) { *K += kappa; - GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + GrisuRound(buffer, *len, delta, tmp, kPow10[kappa] << -one.e, wp_w.f); return; } } @@ -102,8 +106,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff kappa--; if (p2 < delta) { *K += kappa; - int index = -static_cast(kappa); - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast(kappa)] : 0)); + int index = -kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 20 ? kPow10[index] : 0)); return; } } diff --git a/src/utility/rapidjson/internal/ieee754.h b/src/common/thirdparty/rapidjson/internal/ieee754.h similarity index 95% rename from src/utility/rapidjson/internal/ieee754.h rename to src/common/thirdparty/rapidjson/internal/ieee754.h index 82bb0b99e5c..68c9e96649b 100644 --- a/src/utility/rapidjson/internal/ieee754.h +++ b/src/common/thirdparty/rapidjson/internal/ieee754.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -48,13 +48,13 @@ class Double { int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } - static unsigned EffectiveSignificandSize(int order) { + static int EffectiveSignificandSize(int order) { if (order >= -1021) return 53; else if (order <= -1074) return 0; else - return static_cast(order) + 1074; + return order + 1074; } private: diff --git a/src/utility/rapidjson/internal/itoa.h b/src/common/thirdparty/rapidjson/internal/itoa.h similarity index 95% rename from src/utility/rapidjson/internal/itoa.h rename to src/common/thirdparty/rapidjson/internal/itoa.h index 01a4e7e72d7..9fe8c932ffa 100644 --- a/src/utility/rapidjson/internal/itoa.h +++ b/src/common/thirdparty/rapidjson/internal/itoa.h @@ -1,15 +1,15 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ITOA_ @@ -37,12 +37,14 @@ inline const char* GetDigitsLut() { } inline char* u32toa(uint32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + const char* cDigitsLut = GetDigitsLut(); if (value < 10000) { const uint32_t d1 = (value / 100) << 1; const uint32_t d2 = (value % 100) << 1; - + if (value >= 1000) *buffer++ = cDigitsLut[d1]; if (value >= 100) @@ -55,13 +57,13 @@ inline char* u32toa(uint32_t value, char* buffer) { // value = bbbbcccc const uint32_t b = value / 10000; const uint32_t c = value % 10000; - + const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; - + const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; - + if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) @@ -69,7 +71,7 @@ inline char* u32toa(uint32_t value, char* buffer) { if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; - + *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; @@ -77,10 +79,10 @@ inline char* u32toa(uint32_t value, char* buffer) { } else { // value = aabbbbcccc in decimal - + const uint32_t a = value / 100000000; // 1 to 42 value %= 100000000; - + if (a >= 10) { const unsigned i = a << 1; *buffer++ = cDigitsLut[i]; @@ -91,13 +93,13 @@ inline char* u32toa(uint32_t value, char* buffer) { const uint32_t b = value / 10000; // 0 to 9999 const uint32_t c = value % 10000; // 0 to 9999 - + const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; - + const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; - + *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; @@ -111,6 +113,7 @@ inline char* u32toa(uint32_t value, char* buffer) { } inline char* i32toa(int32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); uint32_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; @@ -121,6 +124,7 @@ inline char* i32toa(int32_t value, char* buffer) { } inline char* u64toa(uint64_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); const char* cDigitsLut = GetDigitsLut(); const uint64_t kTen8 = 100000000; const uint64_t kTen9 = kTen8 * 10; @@ -131,13 +135,13 @@ inline char* u64toa(uint64_t value, char* buffer) { const uint64_t kTen14 = kTen8 * 1000000; const uint64_t kTen15 = kTen8 * 10000000; const uint64_t kTen16 = kTen8 * kTen8; - + if (value < kTen8) { uint32_t v = static_cast(value); if (v < 10000) { const uint32_t d1 = (v / 100) << 1; const uint32_t d2 = (v % 100) << 1; - + if (v >= 1000) *buffer++ = cDigitsLut[d1]; if (v >= 100) @@ -150,13 +154,13 @@ inline char* u64toa(uint64_t value, char* buffer) { // value = bbbbcccc const uint32_t b = v / 10000; const uint32_t c = v % 10000; - + const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; - + const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; - + if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) @@ -164,7 +168,7 @@ inline char* u64toa(uint64_t value, char* buffer) { if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; - + *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; @@ -174,22 +178,22 @@ inline char* u64toa(uint64_t value, char* buffer) { else if (value < kTen16) { const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); - + const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; - + const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; - + const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; - + const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; - + const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; @@ -207,9 +211,8 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[d3 + 1]; if (value >= kTen9) *buffer++ = cDigitsLut[d4]; - if (value >= kTen8) - *buffer++ = cDigitsLut[d4 + 1]; - + + *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; @@ -222,7 +225,7 @@ inline char* u64toa(uint64_t value, char* buffer) { else { const uint32_t a = static_cast(value / kTen16); // 1 to 1844 value %= kTen16; - + if (a < 10) *buffer++ = static_cast('0' + static_cast(a)); else if (a < 100) { @@ -232,7 +235,7 @@ inline char* u64toa(uint64_t value, char* buffer) { } else if (a < 1000) { *buffer++ = static_cast('0' + static_cast(a / 100)); - + const uint32_t i = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; @@ -245,28 +248,28 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[j]; *buffer++ = cDigitsLut[j + 1]; } - + const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); - + const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; - + const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; - + const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; - + const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; - + const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; - + const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; - + *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; @@ -284,11 +287,12 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } - + return buffer; } inline char* i64toa(int64_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); uint64_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; diff --git a/src/utility/rapidjson/internal/meta.h b/src/common/thirdparty/rapidjson/internal/meta.h similarity index 97% rename from src/utility/rapidjson/internal/meta.h rename to src/common/thirdparty/rapidjson/internal/meta.h index 5a9aaa42866..27092dc0d69 100644 --- a/src/utility/rapidjson/internal/meta.h +++ b/src/common/thirdparty/rapidjson/internal/meta.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -21,7 +21,8 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif -#if defined(_MSC_VER) + +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(6334) #endif @@ -174,7 +175,11 @@ template struct RemoveSfinaeTag { typedef T Type; RAPIDJSON_NAMESPACE_END //@endcond -#if defined(__GNUC__) || defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/src/utility/rapidjson/internal/pow10.h b/src/common/thirdparty/rapidjson/internal/pow10.h similarity index 99% rename from src/utility/rapidjson/internal/pow10.h rename to src/common/thirdparty/rapidjson/internal/pow10.h index 02f475d705f..eae1a43ed1a 100644 --- a/src/utility/rapidjson/internal/pow10.h +++ b/src/common/thirdparty/rapidjson/internal/pow10.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at diff --git a/src/utility/rapidjson/internal/regex.h b/src/common/thirdparty/rapidjson/internal/regex.h similarity index 82% rename from src/utility/rapidjson/internal/regex.h rename to src/common/thirdparty/rapidjson/internal/regex.h index 422a5240bf5..6446c403af9 100644 --- a/src/utility/rapidjson/internal/regex.h +++ b/src/common/thirdparty/rapidjson/internal/regex.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -23,7 +23,9 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif #ifdef __GNUC__ @@ -31,11 +33,6 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - #ifndef RAPIDJSON_REGEX_VERBOSE #define RAPIDJSON_REGEX_VERBOSE 0 #endif @@ -43,12 +40,40 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated RAPIDJSON_NAMESPACE_BEGIN namespace internal { +/////////////////////////////////////////////////////////////////////////////// +// DecodedStream + +template +class DecodedStream { +public: + DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } + unsigned Peek() { return codepoint_; } + unsigned Take() { + unsigned c = codepoint_; + if (c) // No further decoding when '\0' + Decode(); + return c; + } + +private: + void Decode() { + if (!Encoding::Decode(ss_, &codepoint_)) + codepoint_ = 0; + } + + SourceStream& ss_; + unsigned codepoint_; +}; + /////////////////////////////////////////////////////////////////////////////// // GenericRegex static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 static const SizeType kRegexInvalidRange = ~SizeType(0); +template +class GenericRegexSearch; + //! Regular expression engine with subset of ECMAscript grammar. /*! Supported regular expression syntax: @@ -84,45 +109,29 @@ static const SizeType kRegexInvalidRange = ~SizeType(0); template class GenericRegex { public: + typedef Encoding EncodingType; typedef typename Encoding::Ch Ch; + template friend class GenericRegexSearch; GenericRegex(const Ch* source, Allocator* allocator = 0) : - states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), - stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() + ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), + states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), + anchorBegin_(), anchorEnd_() { GenericStringStream ss(source); - DecodedStream > ds(ss); + DecodedStream, Encoding> ds(ss); Parse(ds); } - ~GenericRegex() { - Allocator::Free(stateSet_); + ~GenericRegex() + { + RAPIDJSON_DELETE(ownAllocator_); } bool IsValid() const { return root_ != kRegexInvalidState; } - template - bool Match(InputStream& is) const { - return SearchWithAnchoring(is, true, true); - } - - bool Match(const Ch* s) const { - GenericStringStream is(s); - return Match(is); - } - - template - bool Search(InputStream& is) const { - return SearchWithAnchoring(is, anchorBegin_, anchorEnd_); - } - - bool Search(const Ch* s) const { - GenericStringStream is(s); - return Search(is); - } - private: enum Operator { kZeroOrOne, @@ -157,28 +166,6 @@ class GenericRegex { SizeType minIndex; }; - template - class DecodedStream { - public: - DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } - unsigned Peek() { return codepoint_; } - unsigned Take() { - unsigned c = codepoint_; - if (c) // No further decoding when '\0' - Decode(); - return c; - } - - private: - void Decode() { - if (!Encoding::Decode(ss_, &codepoint_)) - codepoint_ = 0; - } - - SourceStream& ss_; - unsigned codepoint_; - }; - State& GetState(SizeType index) { RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom()[index]; @@ -200,11 +187,10 @@ class GenericRegex { } template - void Parse(DecodedStream& ds) { - Allocator allocator; - Stack operandStack(&allocator, 256); // Frag - Stack operatorStack(&allocator, 256); // Operator - Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) + void Parse(DecodedStream& ds) { + Stack operandStack(allocator_, 256); // Frag + Stack operatorStack(allocator_, 256); // Operator + Stack atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis) *atomCountStack.template Push() = 0; @@ -301,6 +287,7 @@ class GenericRegex { if (!CharacterEscape(ds, &codepoint)) return; // Unsupported escape character // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; default: // Pattern character PushOperand(operandStack, codepoint); @@ -327,14 +314,6 @@ class GenericRegex { printf("\n"); #endif } - - // Preallocate buffer for SearchWithAnchoring() - RAPIDJSON_ASSERT(stateSet_ == 0); - if (stateCount_ > 0) { - stateSet_ = static_cast(states_.GetAllocator().Malloc(GetStateSetSize())); - state0_.template Reserve(stateCount_); - state1_.template Reserve(stateCount_); - } } SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { @@ -413,8 +392,7 @@ class GenericRegex { } return false; - default: - RAPIDJSON_ASSERT(op == kOneOrMore); + case kOneOrMore: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); @@ -423,6 +401,10 @@ class GenericRegex { return true; } return false; + + default: + // syntax error (e.g. unclosed kLeftParenthesis) + return false; } } @@ -483,7 +465,7 @@ class GenericRegex { } template - bool ParseUnsigned(DecodedStream& ds, unsigned* u) { + bool ParseUnsigned(DecodedStream& ds, unsigned* u) { unsigned r = 0; if (ds.Peek() < '0' || ds.Peek() > '9') return false; @@ -497,7 +479,7 @@ class GenericRegex { } template - bool ParseRange(DecodedStream& ds, SizeType* range) { + bool ParseRange(DecodedStream& ds, SizeType* range) { bool isBegin = true; bool negate = false; int step = 0; @@ -535,6 +517,7 @@ class GenericRegex { else if (!CharacterEscape(ds, &codepoint)) return false; // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; default: switch (step) { @@ -544,6 +527,7 @@ class GenericRegex { break; } // fall through to step 0 for other characters + RAPIDJSON_DELIBERATE_FALLTHROUGH; case 0: { @@ -575,7 +559,7 @@ class GenericRegex { } template - bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { + bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { unsigned codepoint; switch (codepoint = ds.Take()) { case '^': @@ -603,34 +587,95 @@ class GenericRegex { } } + Allocator* ownAllocator_; + Allocator* allocator_; + Stack states_; + Stack ranges_; + SizeType root_; + SizeType stateCount_; + SizeType rangeCount_; + + static const unsigned kInfinityQuantifier = ~0u; + + // For SearchWithAnchoring() + bool anchorBegin_; + bool anchorEnd_; +}; + +template +class GenericRegexSearch { +public: + typedef typename RegexType::EncodingType Encoding; + typedef typename Encoding::Ch Ch; + + GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : + regex_(regex), allocator_(allocator), ownAllocator_(0), + state0_(allocator, 0), state1_(allocator, 0), stateSet_() + { + RAPIDJSON_ASSERT(regex_.IsValid()); + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); + state0_.template Reserve(regex_.stateCount_); + state1_.template Reserve(regex_.stateCount_); + } + + ~GenericRegexSearch() { + Allocator::Free(stateSet_); + RAPIDJSON_DELETE(ownAllocator_); + } + template - bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { - RAPIDJSON_ASSERT(IsValid()); - DecodedStream ds(is); + bool Match(InputStream& is) { + return SearchWithAnchoring(is, true, true); + } + + bool Match(const Ch* s) { + GenericStringStream is(s); + return Match(is); + } + + template + bool Search(InputStream& is) { + return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); + } + + bool Search(const Ch* s) { + GenericStringStream is(s); + return Search(is); + } + +private: + typedef typename RegexType::State State; + typedef typename RegexType::Range Range; + + template + bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { + DecodedStream ds(is); state0_.Clear(); Stack *current = &state0_, *next = &state1_; const size_t stateSetSize = GetStateSetSize(); std::memset(stateSet_, 0, stateSetSize); - bool matched = AddState(*current, root_); + bool matched = AddState(*current, regex_.root_); unsigned codepoint; while (!current->Empty() && (codepoint = ds.Take()) != 0) { std::memset(stateSet_, 0, stateSetSize); next->Clear(); matched = false; for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { - const State& sr = GetState(*s); + const State& sr = regex_.GetState(*s); if (sr.codepoint == codepoint || - sr.codepoint == kAnyCharacterClass || - (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) + sr.codepoint == RegexType::kAnyCharacterClass || + (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) { matched = AddState(*next, sr.out) || matched; if (!anchorEnd && matched) return true; } if (!anchorBegin) - AddState(*next, root_); + AddState(*next, regex_.root_); } internal::Swap(current, next); } @@ -639,62 +684,55 @@ class GenericRegex { } size_t GetStateSetSize() const { - return (stateCount_ + 31) / 32 * 4; + return (regex_.stateCount_ + 31) / 32 * 4; } // Return whether the added states is a match state - bool AddState(Stack& l, SizeType index) const { + bool AddState(Stack& l, SizeType index) { RAPIDJSON_ASSERT(index != kRegexInvalidState); - const State& s = GetState(index); + const State& s = regex_.GetState(index); if (s.out1 != kRegexInvalidState) { // Split bool matched = AddState(l, s.out); return AddState(l, s.out1) || matched; } - else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) { - stateSet_[index >> 5] |= (1 << (index & 31)); + else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { + stateSet_[index >> 5] |= (1u << (index & 31)); *l.template PushUnsafe() = index; } return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. } bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { - bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; + bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; while (rangeIndex != kRegexInvalidRange) { - const Range& r = GetRange(rangeIndex); - if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) + const Range& r = regex_.GetRange(rangeIndex); + if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) return yes; rangeIndex = r.next; } return !yes; } - Stack states_; - Stack ranges_; - SizeType root_; - SizeType stateCount_; - SizeType rangeCount_; - - static const unsigned kInfinityQuantifier = ~0u; - - // For SearchWithAnchoring() - uint32_t* stateSet_; // allocated by states_.GetAllocator() - mutable Stack state0_; - mutable Stack state1_; - bool anchorBegin_; - bool anchorEnd_; + const RegexType& regex_; + Allocator* allocator_; + Allocator* ownAllocator_; + Stack state0_; + Stack state1_; + uint32_t* stateSet_; }; typedef GenericRegex > Regex; +typedef GenericRegexSearch RegexSearch; } // namespace internal RAPIDJSON_NAMESPACE_END -#ifdef __clang__ +#ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER +#if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif diff --git a/src/utility/rapidjson/internal/stack.h b/src/common/thirdparty/rapidjson/internal/stack.h similarity index 95% rename from src/utility/rapidjson/internal/stack.h rename to src/common/thirdparty/rapidjson/internal/stack.h index 022c9aab411..73abd706e97 100644 --- a/src/utility/rapidjson/internal/stack.h +++ b/src/common/thirdparty/rapidjson/internal/stack.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -17,6 +17,7 @@ #include "../allocators.h" #include "swap.h" +#include #if defined(__clang__) RAPIDJSON_DIAG_PUSH @@ -100,7 +101,7 @@ class Stack { void ShrinkToFit() { if (Empty()) { // If the stack is empty, completely deallocate the memory. - Allocator::Free(stack_); + Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) stack_ = 0; stackTop_ = 0; stackEnd_ = 0; @@ -114,7 +115,7 @@ class Stack { template RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed - if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) + if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) Expand(count); } @@ -126,7 +127,8 @@ class Stack { template RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { - RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); + RAPIDJSON_ASSERT(stackTop_); + RAPIDJSON_ASSERT(static_cast(sizeof(T) * count) <= (stackEnd_ - stackTop_)); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; @@ -183,7 +185,7 @@ class Stack { size_t newCapacity; if (stack_ == 0) { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); newCapacity = initialCapacity_; } else { newCapacity = GetCapacity(); diff --git a/src/common/thirdparty/rapidjson/internal/strfunc.h b/src/common/thirdparty/rapidjson/internal/strfunc.h new file mode 100644 index 00000000000..b698a8f43fa --- /dev/null +++ b/src/common/thirdparty/rapidjson/internal/strfunc.h @@ -0,0 +1,83 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ +#define RAPIDJSON_INTERNAL_STRFUNC_H_ + +#include "../stream.h" +#include + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom strlen() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s Null-terminated input string. + \return Number of characters in the string. + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. +*/ +template +inline SizeType StrLen(const Ch* s) { + RAPIDJSON_ASSERT(s != 0); + const Ch* p = s; + while (*p) ++p; + return SizeType(p - s); +} + +template <> +inline SizeType StrLen(const char* s) { + return SizeType(std::strlen(s)); +} + +template <> +inline SizeType StrLen(const wchar_t* s) { + return SizeType(std::wcslen(s)); +} + +//! Custom strcmpn() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s1 Null-terminated input string. + \param s2 Null-terminated input string. + \return 0 if equal +*/ +template +inline int StrCmp(const Ch* s1, const Ch* s2) { + RAPIDJSON_ASSERT(s1 != 0); + RAPIDJSON_ASSERT(s2 != 0); + while(*s1 && (*s1 == *s2)) { s1++; s2++; } + return static_cast(*s1) < static_cast(*s2) ? -1 : static_cast(*s1) > static_cast(*s2); +} + +//! Returns number of code points in a encoded string. +template +bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { + RAPIDJSON_ASSERT(s != 0); + RAPIDJSON_ASSERT(outCount != 0); + GenericStringStream is(s); + const typename Encoding::Ch* end = s + length; + SizeType count = 0; + while (is.src_ < end) { + unsigned codepoint; + if (!Encoding::Decode(is, &codepoint)) + return false; + count++; + } + *outCount = count; + return true; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/src/common/thirdparty/rapidjson/internal/strtod.h b/src/common/thirdparty/rapidjson/internal/strtod.h new file mode 100644 index 00000000000..55f0e380bfa --- /dev/null +++ b/src/common/thirdparty/rapidjson/internal/strtod.h @@ -0,0 +1,293 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRTOD_ +#define RAPIDJSON_STRTOD_ + +#include "ieee754.h" +#include "biginteger.h" +#include "diyfp.h" +#include "pow10.h" +#include +#include + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline double FastPath(double significand, int exp) { + if (exp < -308) + return 0.0; + else if (exp >= 0) + return significand * internal::Pow10(exp); + else + return significand / internal::Pow10(-exp); +} + +inline double StrtodNormalPrecision(double d, int p) { + if (p < -308) { + // Prevent expSum < -308, making Pow10(p) = 0 + d = FastPath(d, -308); + d = FastPath(d, p + 308); + } + else + d = FastPath(d, p); + return d; +} + +template +inline T Min3(T a, T b, T c) { + T m = a; + if (m > b) m = b; + if (m > c) m = c; + return m; +} + +inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { + const Double db(b); + const uint64_t bInt = db.IntegerSignificand(); + const int bExp = db.IntegerExponent(); + const int hExp = bExp - 1; + + int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; + + // Adjust for decimal exponent + if (dExp >= 0) { + dS_Exp2 += dExp; + dS_Exp5 += dExp; + } + else { + bS_Exp2 -= dExp; + bS_Exp5 -= dExp; + hS_Exp2 -= dExp; + hS_Exp5 -= dExp; + } + + // Adjust for binary exponent + if (bExp >= 0) + bS_Exp2 += bExp; + else { + dS_Exp2 -= bExp; + hS_Exp2 -= bExp; + } + + // Adjust for half ulp exponent + if (hExp >= 0) + hS_Exp2 += hExp; + else { + dS_Exp2 -= hExp; + bS_Exp2 -= hExp; + } + + // Remove common power of two factor from all three scaled values + int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); + dS_Exp2 -= common_Exp2; + bS_Exp2 -= common_Exp2; + hS_Exp2 -= common_Exp2; + + BigInteger dS = d; + dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); + + BigInteger bS(bInt); + bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); + + BigInteger hS(1); + hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); + + BigInteger delta(0); + dS.Difference(bS, &delta); + + return delta.Compare(hS); +} + +inline bool StrtodFast(double d, int p, double* result) { + // Use fast path for string-to-double conversion if possible + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + if (p > 22 && p < 22 + 16) { + // Fast Path Cases In Disguise + d *= internal::Pow10(p - 22); + p = 22; + } + + if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 + *result = FastPath(d, p); + return true; + } + else + return false; +} + +// Compute an approximation and see if it is within 1/2 ULP +template +inline bool StrtodDiyFp(const Ch* decimals, int dLen, int dExp, double* result) { + uint64_t significand = 0; + int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 + for (; i < dLen; i++) { + if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || + (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > Ch('5'))) + break; + significand = significand * 10u + static_cast(decimals[i] - Ch('0')); + } + + if (i < dLen && decimals[i] >= Ch('5')) // Rounding + significand++; + + int remaining = dLen - i; + const int kUlpShift = 3; + const int kUlp = 1 << kUlpShift; + int64_t error = (remaining == 0) ? 0 : kUlp / 2; + + DiyFp v(significand, 0); + v = v.Normalize(); + error <<= -v.e; + + dExp += remaining; + + int actualExp; + DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); + if (actualExp != dExp) { + static const DiyFp kPow10[] = { + DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1 + DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2 + DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3 + DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4 + DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5 + DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6 + DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7 + }; + int adjustment = dExp - actualExp; + RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8); + v = v * kPow10[adjustment - 1]; + if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit + error += kUlp / 2; + } + + v = v * cachedPower; + + error += kUlp + (error == 0 ? 0 : 1); + + const int oldExp = v.e; + v = v.Normalize(); + error <<= oldExp - v.e; + + const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + int precisionSize = 64 - effectiveSignificandSize; + if (precisionSize + kUlpShift >= 64) { + int scaleExp = (precisionSize + kUlpShift) - 63; + v.f >>= scaleExp; + v.e += scaleExp; + error = (error >> scaleExp) + 1 + kUlp; + precisionSize -= scaleExp; + } + + DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); + const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; + const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; + if (precisionBits >= halfWay + static_cast(error)) { + rounded.f++; + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) + rounded.f >>= 1; + rounded.e++; + } + } + + *result = rounded.ToDouble(); + + return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); +} + +template +inline double StrtodBigInteger(double approx, const Ch* decimals, int dLen, int dExp) { + RAPIDJSON_ASSERT(dLen >= 0); + const BigInteger dInt(decimals, static_cast(dLen)); + Double a(approx); + int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); + if (cmp < 0) + return a.Value(); // within half ULP + else if (cmp == 0) { + // Round towards even + if (a.Significand() & 1) + return a.NextPositiveDouble(); + else + return a.Value(); + } + else // adjustment + return a.NextPositiveDouble(); +} + +template +inline double StrtodFullPrecision(double d, int p, const Ch* decimals, size_t length, size_t decimalPosition, int exp) { + RAPIDJSON_ASSERT(d >= 0.0); + RAPIDJSON_ASSERT(length >= 1); + + double result = 0.0; + if (StrtodFast(d, p, &result)) + return result; + + RAPIDJSON_ASSERT(length <= INT_MAX); + int dLen = static_cast(length); + + RAPIDJSON_ASSERT(length >= decimalPosition); + RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX); + int dExpAdjust = static_cast(length - decimalPosition); + + RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust); + int dExp = exp - dExpAdjust; + + // Make sure length+dExp does not overflow + RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen); + + // Trim leading zeros + while (dLen > 0 && *decimals == '0') { + dLen--; + decimals++; + } + + // Trim trailing zeros + while (dLen > 0 && decimals[dLen - 1] == '0') { + dLen--; + dExp++; + } + + if (dLen == 0) { // Buffer only contains zeros. + return 0.0; + } + + // Trim right-most digits + const int kMaxDecimalDigit = 767 + 1; + if (dLen > kMaxDecimalDigit) { + dExp += dLen - kMaxDecimalDigit; + dLen = kMaxDecimalDigit; + } + + // If too small, underflow to zero. + // Any x <= 10^-324 is interpreted as zero. + if (dLen + dExp <= -324) + return 0.0; + + // If too large, overflow to infinity. + // Any x >= 10^309 is interpreted as +infinity. + if (dLen + dExp > 309) + return std::numeric_limits::infinity(); + + if (StrtodDiyFp(decimals, dLen, dExp, &result)) + return result; + + // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison + return StrtodBigInteger(result, decimals, dLen, dExp); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STRTOD_ diff --git a/src/utility/rapidjson/internal/swap.h b/src/common/thirdparty/rapidjson/internal/swap.h similarity index 97% rename from src/utility/rapidjson/internal/swap.h rename to src/common/thirdparty/rapidjson/internal/swap.h index 666e49f97b6..2cf92f93a1d 100644 --- a/src/utility/rapidjson/internal/swap.h +++ b/src/common/thirdparty/rapidjson/internal/swap.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at diff --git a/src/common/thirdparty/rapidjson/istreamwrapper.h b/src/common/thirdparty/rapidjson/istreamwrapper.h new file mode 100644 index 00000000000..01437ec0127 --- /dev/null +++ b/src/common/thirdparty/rapidjson/istreamwrapper.h @@ -0,0 +1,128 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ +#define RAPIDJSON_ISTREAMWRAPPER_H_ + +#include "stream.h" +#include +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::istringstream + - \c std::stringstream + - \c std::wistringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wifstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_istream. +*/ + +template +class BasicIStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + + //! Constructor. + /*! + \param stream stream opened for read. + */ + BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + Read(); + } + + //! Constructor. + /*! + \param stream stream opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); + } + + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; + } + +private: + BasicIStreamWrapper(); + BasicIStreamWrapper(const BasicIStreamWrapper&); + BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); + + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = bufferSize_; + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (!stream_.read(buffer_, static_cast(bufferSize_))) { + readCount_ = static_cast(stream_.gcount()); + *(bufferLast_ = buffer_ + readCount_) = '\0'; + eof_ = true; + } + } + } + + StreamType &stream_; + Ch peekBuffer_[4], *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; +}; + +typedef BasicIStreamWrapper IStreamWrapper; +typedef BasicIStreamWrapper WIStreamWrapper; + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/src/utility/rapidjson/memorybuffer.h b/src/common/thirdparty/rapidjson/memorybuffer.h similarity index 98% rename from src/utility/rapidjson/memorybuffer.h rename to src/common/thirdparty/rapidjson/memorybuffer.h index 39bee1dec1c..ffbc41ed1f7 100644 --- a/src/utility/rapidjson/memorybuffer.h +++ b/src/common/thirdparty/rapidjson/memorybuffer.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at diff --git a/src/utility/rapidjson/memorystream.h b/src/common/thirdparty/rapidjson/memorystream.h similarity index 98% rename from src/utility/rapidjson/memorystream.h rename to src/common/thirdparty/rapidjson/memorystream.h index 1d71d8a4f0e..77af6c999e9 100644 --- a/src/utility/rapidjson/memorystream.h +++ b/src/common/thirdparty/rapidjson/memorystream.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at diff --git a/src/utility/rapidjson/msinttypes/inttypes.h b/src/common/thirdparty/rapidjson/msinttypes/inttypes.h similarity index 100% rename from src/utility/rapidjson/msinttypes/inttypes.h rename to src/common/thirdparty/rapidjson/msinttypes/inttypes.h diff --git a/src/utility/rapidjson/msinttypes/stdint.h b/src/common/thirdparty/rapidjson/msinttypes/stdint.h similarity index 100% rename from src/utility/rapidjson/msinttypes/stdint.h rename to src/common/thirdparty/rapidjson/msinttypes/stdint.h diff --git a/src/utility/rapidjson/ostreamwrapper.h b/src/common/thirdparty/rapidjson/ostreamwrapper.h similarity index 98% rename from src/utility/rapidjson/ostreamwrapper.h rename to src/common/thirdparty/rapidjson/ostreamwrapper.h index 6f4667c08ad..11ed4d33f92 100644 --- a/src/utility/rapidjson/ostreamwrapper.h +++ b/src/common/thirdparty/rapidjson/ostreamwrapper.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at diff --git a/src/utility/rapidjson/pointer.h b/src/common/thirdparty/rapidjson/pointer.h similarity index 90% rename from src/utility/rapidjson/pointer.h rename to src/common/thirdparty/rapidjson/pointer.h index 0206ac1c8b6..05b1704dd45 100644 --- a/src/utility/rapidjson/pointer.h +++ b/src/common/thirdparty/rapidjson/pointer.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -16,14 +16,14 @@ #define RAPIDJSON_POINTER_H_ #include "document.h" +#include "uri.h" #include "internal/itoa.h" +#include "error/error.h" // PointerParseErrorCode #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(switch-enum) -#endif - -#ifdef _MSC_VER +#elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif @@ -32,19 +32,6 @@ RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token -//! Error code of parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode -*/ -enum PointerParseErrorCode { - kPointerParseErrorNone = 0, //!< The parse is successful - - kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' - kPointerParseErrorInvalidEscape, //!< Invalid escape - kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment - kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment -}; - /////////////////////////////////////////////////////////////////////////////// // GenericPointer @@ -70,10 +57,10 @@ enum PointerParseErrorCode { supplied tokens eliminates these. GenericPointer depends on GenericDocument and GenericValue. - + \tparam ValueType The value type of the DOM tree. E.g. GenericValue > \tparam Allocator The allocator type for allocating memory for internal representation. - + \note GenericPointer uses same encoding of ValueType. However, Allocator of GenericPointer is independent of Allocator of Value. */ @@ -82,8 +69,10 @@ class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value typedef typename ValueType::Ch Ch; //!< Character type from Value + typedef GenericUri UriType; - //! A token is the basic units of internal representation. + + //! A token is the basic units of internal representation. /*! A JSON pointer string representation "/foo/123" is parsed to two tokens: "foo" and 123. 123 will be represented in both numeric form and string form. @@ -165,7 +154,12 @@ class GenericPointer { GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Copy constructor. - GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + *this = rhs; + } + + //! Copy constructor. + GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } @@ -197,6 +191,36 @@ class GenericPointer { return *this; } + //! Swap the content of this pointer with an other. + /*! + \param other The pointer to swap with. + \note Constant complexity. + */ + GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT { + internal::Swap(allocator_, other.allocator_); + internal::Swap(ownAllocator_, other.ownAllocator_); + internal::Swap(nameBuffer_, other.nameBuffer_); + internal::Swap(tokens_, other.tokens_); + internal::Swap(tokenCount_, other.tokenCount_); + internal::Swap(parseErrorOffset_, other.parseErrorOffset_); + internal::Swap(parseErrorCode_, other.parseErrorCode_); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.pointer, b.pointer); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + //@} //!@name Append token @@ -240,7 +264,7 @@ class GenericPointer { template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { - return Append(name, StrLen(name), allocator); + return Append(name, internal::StrLen(name), allocator); } #if RAPIDJSON_HAS_STDSTRING @@ -274,7 +298,7 @@ class GenericPointer { else { Ch name[21]; for (size_t i = 0; i <= length; i++) - name[i] = buffer[i]; + name[i] = static_cast(buffer[i]); Token token = { name, length, index }; return Append(token, allocator); } @@ -353,6 +377,33 @@ class GenericPointer { */ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } + //! Less than operator. + /*! + \note Invalid pointers are always greater than valid ones. + */ + bool operator<(const GenericPointer& rhs) const { + if (!IsValid()) + return false; + if (!rhs.IsValid()) + return true; + + if (tokenCount_ != rhs.tokenCount_) + return tokenCount_ < rhs.tokenCount_; + + for (size_t i = 0; i < tokenCount_; i++) { + if (tokens_[i].index != rhs.tokens_[i].index) + return tokens_[i].index < rhs.tokens_[i].index; + + if (tokens_[i].length != rhs.tokens_[i].length) + return tokens_[i].length < rhs.tokens_[i].length; + + if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length)) + return cmp < 0; + } + + return false; + } + //@} //!@name Stringify @@ -428,10 +479,11 @@ class GenericPointer { v = &((*v)[t->index]); } else { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); if (m == v->MemberEnd()) { v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); - v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end + m = v->MemberEnd(); + v = &(--m)->value; // Assumes AddMember() appends at the end exist = false; } else @@ -459,6 +511,70 @@ class GenericPointer { //@} + //!@name Compute URI + //@{ + + //! Compute the in-scope URI for a subtree. + // For use with JSON pointers into JSON schema documents. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param rootUri Root URI + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. + \param allocator Allocator for Uris + \return Uri if it can be resolved. Otherwise null. + + \note + There are only 3 situations when a URI cannot be resolved: + 1. A value in the path is not an array nor object. + 2. An object value does not contain the token. + 3. A token is out of range of an array value. + + Use unresolvedTokenIndex to retrieve the token index. + */ + UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { + static const Ch kIdString[] = { 'i', 'd', '\0' }; + static const ValueType kIdValue(kIdString, 2); + UriType base = UriType(rootUri, allocator); + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + switch (v->GetType()) { + case kObjectType: + { + // See if we have an id, and if so resolve with the current base + typename ValueType::MemberIterator m = v->FindMember(kIdValue); + if (m != v->MemberEnd() && (m->value).IsString()) { + UriType here = UriType(m->value, allocator).Resolve(base, allocator); + base = here; + } + m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); + if (m == v->MemberEnd()) + break; + v = &m->value; + } + continue; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + break; + v = &((*v)[t->index]); + continue; + default: + break; + } + + // Error: unresolved token + if (unresolvedTokenIndex) + *unresolvedTokenIndex = static_cast(t - tokens_); + return UriType(allocator); + } + return base; + } + + UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { + return GetUri(const_cast(root), rootUri, unresolvedTokenIndex, allocator); + } + + //!@name Query value //@{ @@ -483,7 +599,7 @@ class GenericPointer { switch (v->GetType()) { case kObjectType: { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); if (m == v->MemberEnd()) break; v = &m->value; @@ -532,14 +648,14 @@ class GenericPointer { */ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); + ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); } //! Query a value in a subtree with default null-terminated string. ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); + ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } @@ -547,7 +663,7 @@ class GenericPointer { //! Query a value in a subtree with default std::basic_string. ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); + ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #endif @@ -573,7 +689,7 @@ class GenericPointer { ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } - + #if RAPIDJSON_HAS_STDSTRING //! Query a value in a document with default std::basic_string. template @@ -719,7 +835,7 @@ class GenericPointer { switch (v->GetType()) { case kObjectType: { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); if (m == v->MemberEnd()) return false; v = &m->value; @@ -758,7 +874,7 @@ class GenericPointer { */ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { if (!allocator_) // allocator is independently owned. - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) @@ -806,7 +922,7 @@ class GenericPointer { // Create own allocator if user did not supply. if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); // Count number of '/' as tokenCount tokenCount_ = 0; @@ -867,7 +983,7 @@ class GenericPointer { } i++; - + // Escaping "~0" -> '~', "~1" -> '/' if (c == '~') { if (i < length) { @@ -1029,8 +1145,8 @@ class GenericPointer { unsigned char u = static_cast(c); static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; os_.Put('%'); - os_.Put(hexDigits[u >> 4]); - os_.Put(hexDigits[u & 15]); + os_.Put(static_cast(hexDigits[u >> 4])); + os_.Put(static_cast(hexDigits[u & 15])); } private: OutputStream& os_; @@ -1347,11 +1463,7 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) { RAPIDJSON_NAMESPACE_END -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef _MSC_VER +#if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif diff --git a/src/utility/rapidjson/prettywriter.h b/src/common/thirdparty/rapidjson/prettywriter.h similarity index 85% rename from src/utility/rapidjson/prettywriter.h rename to src/common/thirdparty/rapidjson/prettywriter.h index c6f0216e984..fe45df1d10f 100644 --- a/src/utility/rapidjson/prettywriter.h +++ b/src/common/thirdparty/rapidjson/prettywriter.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -22,6 +22,11 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Combination of PrettyWriter format flags. @@ -34,7 +39,7 @@ enum PrettyFormatOptions { //! Writer with indentation and spacing. /*! - \tparam OutputStream Type of ouptut os. + \tparam OutputStream Type of output os. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. @@ -42,7 +47,7 @@ enum PrettyFormatOptions { template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class PrettyWriter : public Writer { public: - typedef Writer Base; + typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor @@ -55,7 +60,12 @@ class PrettyWriter : public Writer(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} +#endif //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). @@ -82,26 +92,26 @@ class PrettyWriter : public Writer= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::os_->Put('\n'); WriteIndent(); } - bool ret = Base::WriteEndObject(); + bool ret = Base::EndValue(Base::WriteEndObject()); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); + Base::Flush(); return true; } @@ -158,11 +170,11 @@ class PrettyWriter : public WriterPut('\n'); WriteIndent(); } - bool ret = Base::WriteEndArray(); + bool ret = Base::EndValue(Base::WriteEndArray()); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); + Base::Flush(); return true; } @@ -189,7 +201,7 @@ class PrettyWriter : public Writer(indentChar_), count); + PutN(*Base::os_, static_cast(indentChar_), count); } Ch indentChar_; @@ -254,6 +266,10 @@ class PrettyWriter : public Writer #endif // RAPIDJSON_HAS_STDSTRING +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_USE_MEMBERSMAP + +/*! \def RAPIDJSON_USE_MEMBERSMAP + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for object members handling in a \c std::multimap + + By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object + members are stored in a \c std::multimap for faster lookup and deletion times, a + trade off with a slightly slower insertion time and a small object allocat(or)ed + memory overhead. + + \hideinitializer +*/ +#ifndef RAPIDJSON_USE_MEMBERSMAP +#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default +#endif + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE @@ -159,7 +195,7 @@ */ #ifndef RAPIDJSON_NO_INT64DEFINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 +#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 #include "msinttypes/stdint.h" #include "msinttypes/inttypes.h" #else @@ -214,7 +250,7 @@ # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif // __BYTE_ORDER__ // Detect with GLIBC's endian.h # elif defined(__GLIBC__) @@ -224,7 +260,7 @@ # elif (__BYTE_ORDER == __BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif // __GLIBC__ // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro # elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) @@ -236,12 +272,12 @@ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_MSC_VER) && defined(_M_ARM) +# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif #endif // RAPIDJSON_ENDIAN @@ -264,16 +300,11 @@ /*! \ingroup RAPIDJSON_CONFIG \param x pointer to align - Some machines require strict data alignment. Currently the default uses 4 bytes - alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. + Some machines require strict data alignment. The default is 8 bytes. User can customize by defining the RAPIDJSON_ALIGN function macro. */ #ifndef RAPIDJSON_ALIGN -#if RAPIDJSON_64BIT == 1 -#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) -#else -#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) -#endif +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) #endif /////////////////////////////////////////////////////////////////////////////// @@ -320,17 +351,17 @@ #endif /////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD /*! \def RAPIDJSON_SIMD \ingroup RAPIDJSON_CONFIG - \brief Enable SSE2/SSE4.2 optimization. + \brief Enable SSE2/SSE4.2/Neon optimization. RapidJSON supports optimized implementations for some parsing operations - based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible - processors. + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel + or ARM compatible processors. - To enable these optimizations, two different symbols can be defined; + To enable these optimizations, three different symbols can be defined; \code // Enable SSE2 optimization. #define RAPIDJSON_SSE2 @@ -339,13 +370,17 @@ #define RAPIDJSON_SSE42 \endcode - \c RAPIDJSON_SSE42 takes precedence, if both are defined. + // Enable ARM Neon optimization. + #define RAPIDJSON_NEON + \endcode + + \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. If any of these symbols is defined, RapidJSON defines the macro \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ - || defined(RAPIDJSON_DOXYGEN_RUNNING) + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) #define RAPIDJSON_SIMD #endif @@ -405,7 +440,15 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_STATIC_ASSERT -// Adopt from boost +// Prefer C++11 static_assert, if available +#ifndef RAPIDJSON_STATIC_ASSERT +#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) +#define RAPIDJSON_STATIC_ASSERT(x) \ + static_assert(x, RAPIDJSON_STRINGIFY(x)) +#endif // C++11 +#endif // RAPIDJSON_STATIC_ASSERT + +// Adopt C++03 implementation from boost #ifndef RAPIDJSON_STATIC_ASSERT #ifndef __clang__ //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN @@ -413,14 +456,10 @@ RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; -template struct StaticAssertTest {}; +template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END -#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) -#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) -#define RAPIDJSON_DO_JOIN2(X, Y) X##Y - -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE @@ -438,7 +477,7 @@ RAPIDJSON_NAMESPACE_END typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif +#endif // RAPIDJSON_STATIC_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY @@ -474,7 +513,7 @@ RAPIDJSON_NAMESPACE_END //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define RAPIDJSON_MULTILINEMACRO_BEGIN do { +#define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_END \ } while((void)0, 0) @@ -482,6 +521,12 @@ RAPIDJSON_NAMESPACE_END #define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) +#if defined(__has_builtin) +#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) +#else +#define RAPIDJSON_HAS_BUILTIN(x) 0 +#endif + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF @@ -527,16 +572,23 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // C++11 features +#ifndef RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L) +#endif + #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS -#if defined(__clang__) +#if RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#elif defined(__clang__) #if __has_feature(cxx_rvalue_references) && \ - (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) + (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1600) + (defined(_MSC_VER) && _MSC_VER >= 1600) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else @@ -544,46 +596,120 @@ RAPIDJSON_NAMESPACE_END #endif #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT -#if defined(__clang__) +#if RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#elif defined(__clang__) #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) -// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 #else #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 #endif #endif +#ifndef RAPIDJSON_NOEXCEPT #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT noexcept #else -#define RAPIDJSON_NOEXCEPT /* noexcept */ +#define RAPIDJSON_NOEXCEPT throw() #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT +#endif // no automatic detection, yet #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS +#if (defined(_MSC_VER) && _MSC_VER >= 1700) +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 +#else #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #endif +#endif #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1700) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1700) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 #else #define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 #endif #endif // RAPIDJSON_HAS_CXX11_RANGE_FOR +/////////////////////////////////////////////////////////////////////////////// +// C++17 features + +#ifndef RAPIDJSON_HAS_CXX17 +#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L) +#endif + +#if RAPIDJSON_HAS_CXX17 +# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] +#elif defined(__has_cpp_attribute) +# if __has_cpp_attribute(clang::fallthrough) +# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]] +# elif __has_cpp_attribute(fallthrough) +# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough)) +# else +# define RAPIDJSON_DELIBERATE_FALLTHROUGH +# endif +#else +# define RAPIDJSON_DELIBERATE_FALLTHROUGH +#endif + //!@endcond +//! Assertion (in non-throwing contexts). + /*! \ingroup RAPIDJSON_CONFIG + Some functions provide a \c noexcept guarantee, if the compiler supports it. + In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to + throw an exception. This macro adds a separate customization point for + such cases. + + Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is + supported, and to \ref RAPIDJSON_ASSERT otherwise. + */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NOEXCEPT_ASSERT + +#ifndef RAPIDJSON_NOEXCEPT_ASSERT +#ifdef RAPIDJSON_ASSERT_THROWS +#include +#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) +#else +#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) +#endif // RAPIDJSON_ASSERT_THROWS +#endif // RAPIDJSON_NOEXCEPT_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// malloc/realloc/free + +#ifndef RAPIDJSON_MALLOC +///! customization point for global \c malloc +#define RAPIDJSON_MALLOC(size) std::malloc(size) +#endif +#ifndef RAPIDJSON_REALLOC +///! customization point for global \c realloc +#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size) +#endif +#ifndef RAPIDJSON_FREE +///! customization point for global \c free +#define RAPIDJSON_FREE(ptr) std::free(ptr) +#endif + /////////////////////////////////////////////////////////////////////////////// // new/delete #ifndef RAPIDJSON_NEW ///! customization point for global \c new -#define RAPIDJSON_NEW(x) new x +#define RAPIDJSON_NEW(TypeName) new TypeName #endif #ifndef RAPIDJSON_DELETE ///! customization point for global \c delete @@ -605,7 +731,7 @@ enum Type { kFalseType = 1, //!< false kTrueType = 2, //!< true kObjectType = 3, //!< object - kArrayType = 4, //!< array + kArrayType = 4, //!< array kStringType = 5, //!< string kNumberType = 6 //!< number }; diff --git a/src/utility/rapidjson/reader.h b/src/common/thirdparty/rapidjson/reader.h similarity index 78% rename from src/utility/rapidjson/reader.h rename to src/common/thirdparty/rapidjson/reader.h index 19f8849b14c..55546601e29 100644 --- a/src/utility/rapidjson/reader.h +++ b/src/common/thirdparty/rapidjson/reader.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -20,6 +20,7 @@ #include "allocators.h" #include "stream.h" #include "encodedstream.h" +#include "internal/clzll.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strtod.h" @@ -33,12 +34,8 @@ #include #elif defined(RAPIDJSON_SSE2) #include -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4702) // unreachable code +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef __clang__ @@ -46,6 +43,10 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(old-style-cast) RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif #ifdef __GNUC__ @@ -153,6 +154,7 @@ enum ParseFlag { kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. + kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings. kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; @@ -299,16 +301,9 @@ inline const char *SkipWhitespace_SIMD(const char* p) { for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; } } @@ -325,16 +320,9 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; } return SkipWhitespace(p, end); @@ -425,7 +413,92 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { return SkipWhitespace(p, end); } -#endif // RAPIDJSON_SSE2 +#elif defined(RAPIDJSON_NEON) + +//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + return p + 8 + (lz >> 3); + } + } else { + uint32_t lz = internal::clzll(low); + return p + (lz >> 3); + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (; p <= end - 16; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + return p + 8 + (lz >> 3); + } + } else { + uint32_t lz = internal::clzll(low); + return p + (lz >> 3); + } + } + + return SkipWhitespace(p, end); +} + +#endif // RAPIDJSON_NEON #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream @@ -471,7 +544,8 @@ class GenericReader { /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ - GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : + stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. @@ -527,7 +601,84 @@ class GenericReader { return Parse(is, handler); } - //! Whether a parse error has occured in the last parsing. + //! Initialize JSON text token-by-token parsing + /*! + */ + void IterativeParseInit() { + parseResult_.Clear(); + state_ = IterativeParsingStartState; + } + + //! Parse one token from JSON text + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + bool IterativeParseNext(InputStream& is, Handler& handler) { + while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { + SkipWhitespaceAndComments(is); + + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state_, t); + IterativeParsingState d = Transit(state_, t, n, is, handler); + + // If we've finished or hit an error... + if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { + // Report errors. + if (d == IterativeParsingErrorState) { + HandleError(state_, is); + return false; + } + + // Transition to the finish state. + RAPIDJSON_ASSERT(d == IterativeParsingFinishState); + state_ = d; + + // If StopWhenDone is not set... + if (!(parseFlags & kParseStopWhenDoneFlag)) { + // ... and extra non-whitespace data is found... + SkipWhitespaceAndComments(is); + if (is.Peek() != '\0') { + // ... this is considered an error. + HandleError(state_, is); + return false; + } + } + + // Success! We are done! + return true; + } + + // Transition to the new state. + state_ = d; + + // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. + if (!IsIterativeParsingDelimiterState(n)) + return true; + } + + // We reached the end of file. + stack_.Clear(); + + if (state_ != IterativeParsingFinishState) { + HandleError(state_, is); + return false; + } + + return true; + } + + //! Check if token-by-token parsing JSON text is complete + /*! \return Whether the JSON has been fully decoded. + */ + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const { + return IsIterativeParsingCompleteState(state_); + } + + //! Whether a parse error has occurred in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. @@ -575,7 +726,7 @@ class GenericReader { } } else if (RAPIDJSON_LIKELY(Consume(is, '/'))) - while (is.Peek() != '\0' && is.Take() != '\n'); + while (is.Peek() != '\0' && is.Take() != '\n') {} else RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); @@ -750,7 +901,7 @@ class GenericReader { return false; } - // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). + // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is, size_t escapeOffset) { unsigned codepoint = 0; @@ -841,7 +992,7 @@ class GenericReader { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { - Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -857,26 +1008,38 @@ class GenericReader { Ch c = is.Peek(); if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape - size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset + size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset is.Take(); Ch e = is.Peek(); if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { is.Take(); os.Put(static_cast(escape[static_cast(e)])); } + else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe + is.Take(); + os.Put('\''); + } else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode is.Take(); unsigned codepoint = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { - // Handle UTF-16 surrogate pair - if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - unsigned codepoint2 = ParseHex4(is, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) { + // high surrogate, check if followed by valid low surrogate + if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) { + // Handle UTF-16 surrogate pair + if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + unsigned codepoint2 = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + // single low surrogate + else + { RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } } TEncoding::Encode(os, codepoint); } @@ -892,7 +1055,7 @@ class GenericReader { if (c == '\0') RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } else { size_t offset = is.Tell(); @@ -927,7 +1090,7 @@ class GenericReader { // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -936,7 +1099,7 @@ class GenericReader { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -948,11 +1111,13 @@ class GenericReader { #else length = static_cast(__builtin_ffs(r) - 1); #endif - char* q = reinterpret_cast(os.Push(length)); - for (size_t i = 0; i < length; i++) - q[i] = p[i]; + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; - p += length; + p += length; + } break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); @@ -988,7 +1153,7 @@ class GenericReader { // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -997,7 +1162,7 @@ class GenericReader { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -1036,7 +1201,7 @@ class GenericReader { // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -1045,7 +1210,7 @@ class GenericReader { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -1064,27 +1229,199 @@ class GenericReader { is.src_ = is.dst_ = p; } -#endif +#elif defined(RAPIDJSON_NEON) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); - template + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } else { + uint32_t lz = internal::clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + vst1q_u8(reinterpret_cast(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16, q += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } else { + uint32_t lz = internal::clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + for (const char* pend = p + length; p != pend; ) { + *q++ = *p++; + } + break; + } + vst1q_u8(reinterpret_cast(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + p += 8 + (lz >> 3); + break; + } + } else { + uint32_t lz = internal::clzll(low); + p += lz >> 3; + break; + } + } + + is.src_ = is.dst_ = p; + } +#endif // RAPIDJSON_NEON + + template class NumberStream; - template - class NumberStream { + template + class NumberStream { public: typedef typename InputStream::Ch Ch; NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } - ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char) {} + RAPIDJSON_FORCEINLINE void Push(char) {} size_t Tell() { return is.Tell(); } size_t Length() { return 0; } - const char* Pop() { return 0; } + const StackCharacter* Pop() { return 0; } protected: NumberStream& operator=(const NumberStream&); @@ -1092,47 +1429,47 @@ class GenericReader { InputStream& is; }; - template - class NumberStream : public NumberStream { - typedef NumberStream Base; + template + class NumberStream : public NumberStream { + typedef NumberStream Base; public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} - ~NumberStream() {} + NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {} RAPIDJSON_FORCEINLINE Ch TakePush() { - stackStream.Put(static_cast(Base::is.Peek())); + stackStream.Put(static_cast(Base::is.Peek())); return Base::is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char c) { + RAPIDJSON_FORCEINLINE void Push(StackCharacter c) { stackStream.Put(c); } size_t Length() { return stackStream.Length(); } - const char* Pop() { + const StackCharacter* Pop() { stackStream.Put('\0'); return stackStream.Pop(); } private: - StackStream stackStream; + StackStream stackStream; }; - template - class NumberStream : public NumberStream { - typedef NumberStream Base; + template + class NumberStream : public NumberStream { + typedef NumberStream Base; public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} - ~NumberStream() {} + NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s) {} RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } }; template void ParseNumber(InputStream& is, Handler& handler) { + typedef typename internal::SelectIf, typename TargetEncoding::Ch, char>::Type NumberCharacter; + internal::StreamLocalCopy copy(is); - NumberStream::quiet_NaN(); + if (Consume(s, 'N')) { + if (Consume(s, 'a') && Consume(s, 'N')) { + d = std::numeric_limits::quiet_NaN(); + useNanOrInf = true; + } } - else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { - d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') - && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { + if (Consume(s, 'n') && Consume(s, 'f')) { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + useNanOrInf = true; + + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } } - else + + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); @@ -1231,8 +1577,6 @@ class GenericReader { // Force double for big integer if (useDouble) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); d = d * 10 + (s.TakePush() - '0'); } } @@ -1302,9 +1646,18 @@ class GenericReader { if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = static_cast(s.Take() - '0'); if (expMinus) { + // (exp + expFrac) must not underflow int => we're detecting when -exp gets + // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into + // underflow territory): + // + // -(exp * 10 + 9) + expFrac >= INT_MIN + // <=> exp <= (expFrac - INT_MIN - 9) / 10 + RAPIDJSON_ASSERT(expFrac <= 0); + int maxExp = (expFrac + 2147483639) / 10; + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); - if (exp >= 214748364) { // Issue #313: prevent overflow exponent + if (RAPIDJSON_UNLIKELY(exp > maxExp)) { while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent s.Take(); } @@ -1341,10 +1694,10 @@ class GenericReader { } else { SizeType numCharsToCopy = static_cast(s.Length()); - StringStream srcStream(s.Pop()); + GenericStringStream > srcStream(s.Pop()); StackStream dstStream(stack_); while (numCharsToCopy--) { - Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); } dstStream.Put('\0'); const typename TargetEncoding::Ch* str = dstStream.Pop(); @@ -1354,7 +1707,7 @@ class GenericReader { } else { size_t length = s.Length(); - const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. + const NumberCharacter* decimal = s.Pop(); // Pop stack no matter if it will be used or not. if (useDouble) { int p = exp + expFrac; @@ -1363,6 +1716,13 @@ class GenericReader { else d = internal::StrtodNormalPrecision(d, p); + // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal + if (d > (std::numeric_limits::max)()) { + // Overflow + // TODO: internal::StrtodX should report overflow (or underflow) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + } + cont = handler.Double(minus ? -d : d); } else if (useNanOrInf) { @@ -1408,29 +1768,31 @@ class GenericReader { // States enum IterativeParsingState { - IterativeParsingStartState = 0, - IterativeParsingFinishState, - IterativeParsingErrorState, + IterativeParsingFinishState = 0, // sink states at top + IterativeParsingErrorState, // sink states at top + IterativeParsingStartState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, - IterativeParsingKeyValueDelimiterState, IterativeParsingMemberValueState, - IterativeParsingMemberDelimiterState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, - IterativeParsingElementDelimiterState, IterativeParsingArrayFinishState, // Single value state - IterativeParsingValueState - }; + IterativeParsingValueState, + + // Delimiter states (at bottom) + IterativeParsingElementDelimiterState, + IterativeParsingMemberDelimiterState, + IterativeParsingKeyValueDelimiterState, - enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 }; + cIterativeParsingStateCount + }; // Tokens enum Token { @@ -1452,7 +1814,7 @@ class GenericReader { kTokenCount }; - RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define N NumberToken @@ -1479,9 +1841,21 @@ class GenericReader { return NumberToken; } - RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, // Start { IterativeParsingArrayInitialState, // Left bracket @@ -1496,18 +1870,6 @@ class GenericReader { IterativeParsingValueState, // Null IterativeParsingValueState // Number }, - // Finish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Error(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, // ObjectInitial { IterativeParsingErrorState, // Left bracket @@ -1536,20 +1898,6 @@ class GenericReader { IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // KeyValueDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberValueState, // String - IterativeParsingMemberValueState, // False - IterativeParsingMemberValueState, // True - IterativeParsingMemberValueState, // Null - IterativeParsingMemberValueState // Number - }, // MemberValue { IterativeParsingErrorState, // Left bracket @@ -1564,20 +1912,6 @@ class GenericReader { IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // MemberDelimiter - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, @@ -1612,6 +1946,18 @@ class GenericReader { IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Single Value (sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, // ElementDelimiter { IterativeParsingArrayInitialState, // Left bracket(push Element state) @@ -1626,18 +1972,34 @@ class GenericReader { IterativeParsingElementState, // Null IterativeParsingElementState // Number }, - // ArrayFinish(sink state) + // MemberDelimiter { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number }, - // Single Value (sink state) + // KeyValueDelimiter { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - } + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, }; // End of G return static_cast(G[state][token]); @@ -1818,6 +2180,14 @@ class GenericReader { } } + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const { + return s >= IterativeParsingElementDelimiterState; + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const { + return s <= IterativeParsingErrorState; + } + template ParseResult IterativeParse(InputStream& is, Handler& handler) { parseResult_.Clear(); @@ -1856,6 +2226,7 @@ class GenericReader { static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; + IterativeParsingState state_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. @@ -1863,7 +2234,7 @@ typedef GenericReader, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END -#ifdef __clang__ +#if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif @@ -1872,8 +2243,4 @@ RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif - #endif // RAPIDJSON_READER_H_ diff --git a/src/common/thirdparty/rapidjson/schema.h b/src/common/thirdparty/rapidjson/schema.h new file mode 100644 index 00000000000..439133fa674 --- /dev/null +++ b/src/common/thirdparty/rapidjson/schema.h @@ -0,0 +1,3262 @@ +// Tencent is pleased to support the open source community by making RapidJSON available-> +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License-> You may obtain a copy of the License at +// +// http://opensource->org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied-> See the License for the +// specific language governing permissions and limitations under the License-> + +#ifndef RAPIDJSON_SCHEMA_H_ +#define RAPIDJSON_SCHEMA_H_ + +#include "document.h" +#include "pointer.h" +#include "stringbuffer.h" +#include "error/en.h" +#include "uri.h" +#include // abs, floor + +#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 +#endif + +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) +#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX +#include "internal/regex.h" +#elif RAPIDJSON_SCHEMA_USE_STDREGEX +#include +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX +#define RAPIDJSON_SCHEMA_HAS_REGEX 1 +#else +#define RAPIDJSON_SCHEMA_HAS_REGEX 0 +#endif + +#ifndef RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_VERBOSE 0 +#endif + +RAPIDJSON_DIAG_PUSH + +#if defined(__GNUC__) +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(weak-vtables) +RAPIDJSON_DIAG_OFF(exit-time-destructors) +RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) +RAPIDJSON_DIAG_OFF(variadic-macros) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Verbose Utilities + +#if RAPIDJSON_SCHEMA_VERBOSE + +namespace internal { + +inline void PrintInvalidKeywordData(const char* keyword) { + printf(" Fail keyword: '%s'\n", keyword); +} + +inline void PrintInvalidKeywordData(const wchar_t* keyword) { + wprintf(L" Fail keyword: '%ls'\n", keyword); +} + +inline void PrintInvalidDocumentData(const char* document) { + printf(" Fail document: '%s'\n", document); +} + +inline void PrintInvalidDocumentData(const wchar_t* document) { + wprintf(L" Fail document: '%ls'\n", document); +} + +inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth) { + printf(" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d); +} + +inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth) { + wprintf(L" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d); +} + +inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved) { + printf(" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved); +} + +inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved) { + wprintf(L" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved); +} + +inline void PrintMethodData(const char* method) { + printf("%s\n", method); +} + +inline void PrintMethodData(const char* method, bool b) { + printf("%s, Data: '%s'\n", method, b ? "true" : "false"); +} + +inline void PrintMethodData(const char* method, int64_t i) { + printf("%s, Data: '%" PRId64 "'\n", method, i); +} + +inline void PrintMethodData(const char* method, uint64_t u) { + printf("%s, Data: '%" PRIu64 "'\n", method, u); +} + +inline void PrintMethodData(const char* method, double d) { + printf("%s, Data: '%lf'\n", method, d); +} + +inline void PrintMethodData(const char* method, const char* s) { + printf("%s, Data: '%s'\n", method, s); +} + +inline void PrintMethodData(const char* method, const wchar_t* s) { + wprintf(L"%hs, Data: '%ls'\n", method, s); +} + +inline void PrintMethodData(const char* method, const char* s1, const char* s2) { + printf("%s, Data: '%s', '%s'\n", method, s1, s2); +} + +inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2) { + wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2); +} + +} // namespace internal + +#endif // RAPIDJSON_SCHEMA_VERBOSE + +#ifndef RAPIDJSON_SCHEMA_PRINT +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__) +#else +#define RAPIDJSON_SCHEMA_PRINT(name, ...) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_INVALID_KEYWORD_RETURN + +#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + context.invalidCode = code;\ + context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\ + RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\ + return false;\ +RAPIDJSON_MULTILINEMACRO_END + +/////////////////////////////////////////////////////////////////////////////// +// ValidateFlag + +/*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kValidateDefaultFlags definition. + + User can define this as any \c ValidateFlag combinations. +*/ +#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS +#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags +#endif + +//! Combination of validate flags +/*! \see + */ +enum ValidateFlag { + kValidateNoFlags = 0, //!< No flags are set. + kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error. + kValidateReadFlag = 2, //!< Validation is for a read semantic. + kValidateWriteFlag = 4, //!< Validation is for a write semantic. + kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS +}; + +/////////////////////////////////////////////////////////////////////////////// +// Specification +enum SchemaDraft { + kDraftUnknown = -1, + kDraftNone = 0, + kDraft03 = 3, + kDraftMin = 4, //!< Current minimum supported draft + kDraft04 = 4, + kDraft05 = 5, + kDraftMax = 5, //!< Current maximum supported draft + kDraft06 = 6, + kDraft07 = 7, + kDraft2019_09 = 8, + kDraft2020_12 = 9 +}; + +enum OpenApiVersion { + kVersionUnknown = -1, + kVersionNone = 0, + kVersionMin = 2, //!< Current minimum supported version + kVersion20 = 2, + kVersion30 = 3, + kVersionMax = 3, //!< Current maximum supported version + kVersion31 = 4, +}; + +struct Specification { + Specification(SchemaDraft d) : draft(d), oapi(kVersionNone) {} + Specification(OpenApiVersion o) : oapi(o) { + if (oapi == kVersion20) draft = kDraft04; + else if (oapi == kVersion30) draft = kDraft05; + else if (oapi == kVersion31) draft = kDraft2020_12; + else draft = kDraft04; + } + ~Specification() {} + bool IsSupported() const { + return ((draft >= kDraftMin && draft <= kDraftMax) && ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax))); + } + SchemaDraft draft; + OpenApiVersion oapi; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Forward declarations + +template +class GenericSchemaDocument; + +namespace internal { + +template +class Schema; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaValidator + +class ISchemaValidator { +public: + virtual ~ISchemaValidator() {} + virtual bool IsValid() const = 0; + virtual void SetValidateFlags(unsigned flags) = 0; + virtual unsigned GetValidateFlags() const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaStateFactory + +template +class ISchemaStateFactory { +public: + virtual ~ISchemaStateFactory() {} + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0; + virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; + virtual void* CreateHasher() = 0; + virtual uint64_t GetHashCode(void* hasher) = 0; + virtual void DestroryHasher(void* hasher) = 0; + virtual void* MallocState(size_t size) = 0; + virtual void FreeState(void* p) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// IValidationErrorHandler + +template +class IValidationErrorHandler { +public: + typedef typename SchemaType::Ch Ch; + typedef typename SchemaType::SValue SValue; + + virtual ~IValidationErrorHandler() {} + + virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0; + virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0; + virtual void NotMultipleOf(double actual, const SValue& expected) = 0; + virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0; + + virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0; + virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0; + virtual void DoesNotMatch(const Ch* str, SizeType length) = 0; + + virtual void DisallowedItem(SizeType index) = 0; + virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void DuplicateItems(SizeType index1, SizeType index2) = 0; + + virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void StartMissingProperties() = 0; + virtual void AddMissingProperty(const SValue& name) = 0; + virtual bool EndMissingProperties() = 0; + virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void DisallowedProperty(const Ch* name, SizeType length) = 0; + + virtual void StartDependencyErrors() = 0; + virtual void StartMissingDependentProperties() = 0; + virtual void AddMissingDependentProperty(const SValue& targetName) = 0; + virtual void EndMissingDependentProperties(const SValue& sourceName) = 0; + virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0; + virtual bool EndDependencyErrors() = 0; + + virtual void DisallowedValue(const ValidateErrorCode code) = 0; + virtual void StartDisallowedType() = 0; + virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0; + virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0; + virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0; + virtual void Disallowed() = 0; + virtual void DisallowedWhenWriting() = 0; + virtual void DisallowedWhenReading() = 0; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Hasher + +// For comparison of compound value +template +class Hasher { +public: + typedef typename Encoding::Ch Ch; + + Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} + + bool Null() { return WriteType(kNullType); } + bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } + bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Double(double d) { + Number n; + if (d < 0) n.u.i = static_cast(d); + else n.u.u = static_cast(d); + n.d = d; + return WriteNumber(n); + } + + bool RawNumber(const Ch* str, SizeType len, bool) { + WriteBuffer(kNumberType, str, len * sizeof(Ch)); + return true; + } + + bool String(const Ch* str, SizeType len, bool) { + WriteBuffer(kStringType, str, len * sizeof(Ch)); + return true; + } + + bool StartObject() { return true; } + bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } + bool EndObject(SizeType memberCount) { + uint64_t h = Hash(0, kObjectType); + uint64_t* kv = stack_.template Pop(memberCount * 2); + for (SizeType i = 0; i < memberCount; i++) + h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive + *stack_.template Push() = h; + return true; + } + + bool StartArray() { return true; } + bool EndArray(SizeType elementCount) { + uint64_t h = Hash(0, kArrayType); + uint64_t* e = stack_.template Pop(elementCount); + for (SizeType i = 0; i < elementCount; i++) + h = Hash(h, e[i]); // Use hash to achieve element order sensitive + *stack_.template Push() = h; + return true; + } + + bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } + + uint64_t GetHashCode() const { + RAPIDJSON_ASSERT(IsValid()); + return *stack_.template Top(); + } + +private: + static const size_t kDefaultSize = 256; + struct Number { + union U { + uint64_t u; + int64_t i; + }u; + double d; + }; + + bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } + + bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } + + bool WriteBuffer(Type type, const void* data, size_t len) { + // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ + uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); + const unsigned char* d = static_cast(data); + for (size_t i = 0; i < len; i++) + h = Hash(h, d[i]); + *stack_.template Push() = h; + return true; + } + + static uint64_t Hash(uint64_t h, uint64_t d) { + static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); + h ^= d; + h *= kPrime; + return h; + } + + Stack stack_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidationContext + +template +struct SchemaValidationContext { + typedef Schema SchemaType; + typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef IValidationErrorHandler ErrorHandlerType; + typedef typename SchemaType::ValueType ValueType; + typedef typename ValueType::Ch Ch; + + enum PatternValidatorType { + kPatternValidatorOnly, + kPatternValidatorWithProperty, + kPatternValidatorWithAdditionalProperty + }; + + SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s, unsigned fl = 0) : + factory(f), + error_handler(eh), + schema(s), + flags(fl), + valueSchema(), + invalidKeyword(), + invalidCode(), + hasher(), + arrayElementHashCodes(), + validators(), + validatorCount(), + patternPropertiesValidators(), + patternPropertiesValidatorCount(), + patternPropertiesSchemas(), + patternPropertiesSchemaCount(), + valuePatternValidatorType(kPatternValidatorOnly), + propertyExist(), + inArray(false), + valueUniqueness(false), + arrayUniqueness(false) + { + } + + ~SchemaValidationContext() { + if (hasher) + factory.DestroryHasher(hasher); + if (validators) { + for (SizeType i = 0; i < validatorCount; i++) { + if (validators[i]) { + factory.DestroySchemaValidator(validators[i]); + } + } + factory.FreeState(validators); + } + if (patternPropertiesValidators) { + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) { + if (patternPropertiesValidators[i]) { + factory.DestroySchemaValidator(patternPropertiesValidators[i]); + } + } + factory.FreeState(patternPropertiesValidators); + } + if (patternPropertiesSchemas) + factory.FreeState(patternPropertiesSchemas); + if (propertyExist) + factory.FreeState(propertyExist); + } + + SchemaValidatorFactoryType& factory; + ErrorHandlerType& error_handler; + const SchemaType* schema; + unsigned flags; + const SchemaType* valueSchema; + const Ch* invalidKeyword; + ValidateErrorCode invalidCode; + void* hasher; // Only validator access + void* arrayElementHashCodes; // Only validator access this + ISchemaValidator** validators; + SizeType validatorCount; + ISchemaValidator** patternPropertiesValidators; + SizeType patternPropertiesValidatorCount; + const SchemaType** patternPropertiesSchemas; + SizeType patternPropertiesSchemaCount; + PatternValidatorType valuePatternValidatorType; + PatternValidatorType objectPatternValidatorType; + SizeType arrayElementIndex; + bool* propertyExist; + bool inArray; + bool valueUniqueness; + bool arrayUniqueness; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Schema + +template +class Schema { +public: + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef SchemaValidationContext Context; + typedef Schema SchemaType; + typedef GenericValue SValue; + typedef IValidationErrorHandler ErrorHandler; + typedef GenericUri UriType; + friend class GenericSchemaDocument; + + Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) : + allocator_(allocator), + uri_(schemaDocument->GetURI(), *allocator), + id_(id, allocator), + spec_(schemaDocument->GetSpecification()), + pointer_(p, allocator), + typeless_(schemaDocument->GetTypeless()), + enum_(), + enumCount_(), + not_(), + type_((1 << kTotalSchemaType) - 1), // typeless + validatorCount_(), + notValidatorIndex_(), + properties_(), + additionalPropertiesSchema_(), + patternProperties_(), + patternPropertyCount_(), + propertyCount_(), + minProperties_(), + maxProperties_(SizeType(~0)), + additionalProperties_(true), + hasDependencies_(), + hasRequired_(), + hasSchemaDependencies_(), + additionalItemsSchema_(), + itemsList_(), + itemsTuple_(), + itemsTupleCount_(), + minItems_(), + maxItems_(SizeType(~0)), + additionalItems_(true), + uniqueItems_(false), + pattern_(), + minLength_(0), + maxLength_(~SizeType(0)), + exclusiveMinimum_(false), + exclusiveMaximum_(false), + defaultValueLength_(0), + readOnly_(false), + writeOnly_(false), + nullable_(false) + { + GenericStringBuffer sb; + p.StringifyUriFragment(sb); + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString()); + + typedef typename ValueType::ConstValueIterator ConstValueIterator; + typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + + // PR #1393 + // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite + // recursion (with recursive schemas), since schemaDocument->getSchema() is always + // checked before creating a new one. Don't cache typeless_, though. + if (this != typeless_) { + typedef typename SchemaDocumentType::SchemaEntry SchemaEntry; + SchemaEntry *entry = schemaDocument->schemaMap_.template Push(); + new (entry) SchemaEntry(pointer_, this, true, allocator_); + schemaDocument->AddSchemaRefs(this); + } + + if (!value.IsObject()) + return; + + // If we have an id property, resolve it with the in-scope id + // Not supported for open api 2.0 or 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) + if (const ValueType* v = GetMember(value, GetIdString())) { + if (v->IsString()) { + UriType local(*v, allocator); + id_ = local.Resolve(id_, allocator); + RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), v->GetString(), id_.GetString()); + } + } + + if (const ValueType* v = GetMember(value, GetTypeString())) { + type_ = 0; + if (v->IsString()) + AddType(*v); + else if (v->IsArray()) + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) + AddType(*itr); + } + + if (const ValueType* v = GetMember(value, GetEnumString())) { + if (v->IsArray() && v->Size() > 0) { + enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { + typedef Hasher > EnumHasherType; + char buffer[256u + 24]; + MemoryPoolAllocator hasherAllocator(buffer, sizeof(buffer)); + EnumHasherType h(&hasherAllocator, 256); + itr->Accept(h); + enum_[enumCount_++] = h.GetHashCode(); + } + } + } + + if (schemaDocument) + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + + // AnyOf, OneOf, Not not supported for open api 2.0 + if (schemaDocument && spec_.oapi != kVersion20) { + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + + if (const ValueType* v = GetMember(value, GetNotString())) { + schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_); + notValidatorIndex_ = validatorCount_; + validatorCount_++; + } + } + + // Object + + const ValueType* properties = GetMember(value, GetPropertiesString()); + const ValueType* required = GetMember(value, GetRequiredString()); + const ValueType* dependencies = GetMember(value, GetDependenciesString()); + { + // Gather properties from properties/required/dependencies + SValue allProperties(kArrayType); + + if (properties && properties->IsObject()) + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) + AddUniqueElement(allProperties, itr->name); + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) + AddUniqueElement(allProperties, *itr); + + // Dependencies not supported for open api 2.0 and 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) + if (dependencies && dependencies->IsObject()) + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + AddUniqueElement(allProperties, itr->name); + if (itr->value.IsArray()) + for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) + if (i->IsString()) + AddUniqueElement(allProperties, *i); + } + + if (allProperties.Size() > 0) { + propertyCount_ = allProperties.Size(); + properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); + for (SizeType i = 0; i < propertyCount_; i++) { + new (&properties_[i]) Property(); + properties_[i].name = allProperties[i]; + properties_[i].schema = typeless_; + } + } + } + + if (properties && properties->IsObject()) { + PointerType q = p.Append(GetPropertiesString(), allocator_); + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { + SizeType index; + if (FindPropertyIndex(itr->name, &index)) + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_); + } + } + + // PatternProperties not supported for open api 2.0 and 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) + if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { + PointerType q = p.Append(GetPatternPropertiesString(), allocator_); + patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); + patternPropertyCount_ = 0; + + for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { + new (&patternProperties_[patternPropertyCount_]) PatternProperty(); + PointerType r = q.Append(itr->name, allocator_); + patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r); + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_); + patternPropertyCount_++; + } + } + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) { + SizeType index; + if (FindPropertyIndex(*itr, &index)) { + properties_[index].required = true; + hasRequired_ = true; + } + } + + // Dependencies not supported for open api 2.0 and 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) + if (dependencies && dependencies->IsObject()) { + PointerType q = p.Append(GetDependenciesString(), allocator_); + hasDependencies_ = true; + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + SizeType sourceIndex; + if (FindPropertyIndex(itr->name, &sourceIndex)) { + if (itr->value.IsArray()) { + properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); + std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); + for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { + SizeType targetIndex; + if (FindPropertyIndex(*targetItr, &targetIndex)) + properties_[sourceIndex].dependencies[targetIndex] = true; + } + } + else if (itr->value.IsObject()) { + hasSchemaDependencies_ = true; + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_); + properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; + validatorCount_++; + } + } + } + } + + if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { + if (v->IsBool()) + additionalProperties_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_); + } + + AssignIfExist(minProperties_, value, GetMinPropertiesString()); + AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); + + // Array + if (const ValueType* v = GetMember(value, GetItemsString())) { + PointerType q = p.Append(GetItemsString(), allocator_); + if (v->IsObject()) // List validation + schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_); + else if (v->IsArray()) { // Tuple validation + itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); + SizeType index = 0; + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_); + } + } + + AssignIfExist(minItems_, value, GetMinItemsString()); + AssignIfExist(maxItems_, value, GetMaxItemsString()); + + // AdditionalItems not supported for openapi 2.0 and 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) + if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { + if (v->IsBool()) + additionalItems_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_); + } + + AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); + + // String + AssignIfExist(minLength_, value, GetMinLengthString()); + AssignIfExist(maxLength_, value, GetMaxLengthString()); + + if (const ValueType* v = GetMember(value, GetPatternString())) + pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_)); + + // Number + if (const ValueType* v = GetMember(value, GetMinimumString())) + if (v->IsNumber()) + minimum_.CopyFrom(*v, *allocator_); + + if (const ValueType* v = GetMember(value, GetMaximumString())) + if (v->IsNumber()) + maximum_.CopyFrom(*v, *allocator_); + + AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); + AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); + + if (const ValueType* v = GetMember(value, GetMultipleOfString())) + if (v->IsNumber() && v->GetDouble() > 0.0) + multipleOf_.CopyFrom(*v, *allocator_); + + // Default + if (const ValueType* v = GetMember(value, GetDefaultValueString())) + if (v->IsString()) + defaultValueLength_ = v->GetStringLength(); + + // ReadOnly - open api only (until draft 7 supported) + // WriteOnly - open api 3 only (until draft 7 supported) + // Both can't be true + if (spec_.oapi != kVersionNone) + AssignIfExist(readOnly_, value, GetReadOnlyString()); + if (spec_.oapi >= kVersion30) + AssignIfExist(writeOnly_, value, GetWriteOnlyString()); + if (readOnly_ && writeOnly_) + schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p); + + // Nullable - open api 3 only + // If true add 'null' as allowable type + if (spec_.oapi >= kVersion30) { + AssignIfExist(nullable_, value, GetNullableString()); + if (nullable_) + AddType(GetNullString()); + } + } + + ~Schema() { + AllocatorType::Free(enum_); + if (properties_) { + for (SizeType i = 0; i < propertyCount_; i++) + properties_[i].~Property(); + AllocatorType::Free(properties_); + } + if (patternProperties_) { + for (SizeType i = 0; i < patternPropertyCount_; i++) + patternProperties_[i].~PatternProperty(); + AllocatorType::Free(patternProperties_); + } + AllocatorType::Free(itemsTuple_); +#if RAPIDJSON_SCHEMA_HAS_REGEX + if (pattern_) { + pattern_->~RegexType(); + AllocatorType::Free(pattern_); + } +#endif + } + + const SValue& GetURI() const { + return uri_; + } + + const UriType& GetId() const { + return id_; + } + + const Specification& GetSpecification() const { + return spec_; + } + + const PointerType& GetPointer() const { + return pointer_; + } + + bool BeginValue(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue"); + if (context.inArray) { + if (uniqueItems_) + context.valueUniqueness = true; + + if (itemsList_) + context.valueSchema = itemsList_; + else if (itemsTuple_) { + if (context.arrayElementIndex < itemsTupleCount_) + context.valueSchema = itemsTuple_[context.arrayElementIndex]; + else if (additionalItemsSchema_) + context.valueSchema = additionalItemsSchema_; + else if (additionalItems_) + context.valueSchema = typeless_; + else { + context.error_handler.DisallowedItem(context.arrayElementIndex); + // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error + context.valueSchema = typeless_; + // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set + context.arrayElementIndex++; + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems); + } + } + else + context.valueSchema = typeless_; + + context.arrayElementIndex++; + } + return true; + } + + RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue"); + // Only check pattern properties if we have validators + if (context.patternPropertiesValidatorCount > 0) { + bool otherValid = false; + SizeType count = context.patternPropertiesValidatorCount; + if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) + otherValid = context.patternPropertiesValidators[--count]->IsValid(); + + bool patternValid = true; + for (SizeType i = 0; i < count; i++) + if (!context.patternPropertiesValidators[i]->IsValid()) { + patternValid = false; + break; + } + + if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { + if (!patternValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); + } + } + else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { + if (!patternValid || !otherValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); + } + } + else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); + } + } + + // For enums only check if we have a hasher + if (enum_ && context.hasher) { + const uint64_t h = context.factory.GetHashCode(context.hasher); + for (SizeType i = 0; i < enumCount_; i++) + if (enum_[i] == h) + goto foundEnum; + context.error_handler.DisallowedValue(kValidateErrorEnum); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum); + foundEnum:; + } + + // Only check allOf etc if we have validators + if (context.validatorCount > 0) { + if (allOf_.schemas) + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) + if (!context.validators[i]->IsValid()) { + context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf); + } + + if (anyOf_.schemas) { + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) + if (context.validators[i]->IsValid()) + goto foundAny; + context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf); + foundAny:; + } + + if (oneOf_.schemas) { + bool oneValid = false; + SizeType firstMatch = 0; + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) + if (context.validators[i]->IsValid()) { + if (oneValid) { + context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); + } else { + oneValid = true; + firstMatch = i - oneOf_.begin; + } + } + if (!oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); + } + } + + if (not_ && context.validators[notValidatorIndex_]->IsValid()) { + context.error_handler.Disallowed(); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); + } + } + + return true; + } + + bool Null(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null"); + if (!(type_ & (1 << kNullSchemaType))) { + DisallowedType(context, GetNullString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + return CreateParallelValidator(context); + } + + bool Bool(Context& context, bool b) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Bool", b); + if (!CheckBool(context, b)) + return false; + return CreateParallelValidator(context); + } + + bool Int(Context& context, int i) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int", (int64_t)i); + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint(Context& context, unsigned u) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint", (uint64_t)u); + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Int64(Context& context, int64_t i) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int64", i); + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint64(Context& context, uint64_t u) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint64", u); + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Double(Context& context, double d) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Double", d); + if (!(type_ & (1 << kNumberSchemaType))) { + DisallowedType(context, GetNumberString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) + return false; + + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) + return false; + + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) + return false; + + return CreateParallelValidator(context); + } + + bool String(Context& context, const Ch* str, SizeType length, bool) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::String", str); + if (!(type_ & (1 << kStringSchemaType))) { + DisallowedType(context, GetStringString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + + if (minLength_ != 0 || maxLength_ != SizeType(~0)) { + SizeType count; + if (internal::CountStringCodePoint(str, length, &count)) { + if (count < minLength_) { + context.error_handler.TooShort(str, length, minLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength); + } + if (count > maxLength_) { + context.error_handler.TooLong(str, length, maxLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength); + } + } + } + + if (pattern_ && !IsPatternMatch(pattern_, str, length)) { + context.error_handler.DoesNotMatch(str, length); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern); + } + + return CreateParallelValidator(context); + } + + bool StartObject(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartObject"); + if (!(type_ & (1 << kObjectSchemaType))) { + DisallowedType(context, GetObjectString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + + if (hasDependencies_ || hasRequired_) { + context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); + std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); + } + + if (patternProperties_) { // pre-allocate schema array + SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType + context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); + context.patternPropertiesSchemaCount = 0; + std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); + } + + return CreateParallelValidator(context); + } + + bool Key(Context& context, const Ch* str, SizeType len, bool) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str); + + if (patternProperties_) { + context.patternPropertiesSchemaCount = 0; + for (SizeType i = 0; i < patternPropertyCount_; i++) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + context.valueSchema = typeless_; + } + } + + SizeType index = 0; + if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { + if (context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; + } + else + context.valueSchema = properties_[index].schema; + + if (context.propertyExist) + context.propertyExist[index] = true; + + return true; + } + + if (additionalPropertiesSchema_) { + if (context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; + } + else + context.valueSchema = additionalPropertiesSchema_; + return true; + } + else if (additionalProperties_) { + context.valueSchema = typeless_; + return true; + } + + if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties + // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error + context.valueSchema = typeless_; + context.error_handler.DisallowedProperty(str, len); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties); + } + + return true; + } + + bool EndObject(Context& context, SizeType memberCount) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject"); + if (hasRequired_) { + context.error_handler.StartMissingProperties(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].required && !context.propertyExist[index]) + if (properties_[index].schema->defaultValueLength_ == 0 ) + context.error_handler.AddMissingProperty(properties_[index].name); + if (context.error_handler.EndMissingProperties()) + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired); + } + + if (memberCount < minProperties_) { + context.error_handler.TooFewProperties(memberCount, minProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties); + } + + if (memberCount > maxProperties_) { + context.error_handler.TooManyProperties(memberCount, maxProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties); + } + + if (hasDependencies_) { + context.error_handler.StartDependencyErrors(); + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { + const Property& source = properties_[sourceIndex]; + if (context.propertyExist[sourceIndex]) { + if (source.dependencies) { + context.error_handler.StartMissingDependentProperties(); + for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) + if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) + context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name); + context.error_handler.EndMissingDependentProperties(source.name); + } + else if (source.dependenciesSchema) { + ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; + if (!dependenciesValidator->IsValid()) + context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); + } + } + } + if (context.error_handler.EndDependencyErrors()) + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies); + } + + return true; + } + + bool StartArray(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray"); + context.arrayElementIndex = 0; + context.inArray = true; // Ensure we note that we are in an array + + if (!(type_ & (1 << kArraySchemaType))) { + DisallowedType(context, GetArrayString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + + return CreateParallelValidator(context); + } + + bool EndArray(Context& context, SizeType elementCount) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndArray"); + context.inArray = false; + + if (elementCount < minItems_) { + context.error_handler.TooFewItems(elementCount, minItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems); + } + + if (elementCount > maxItems_) { + context.error_handler.TooManyItems(elementCount, maxItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems); + } + + return true; + } + + static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) { + switch (validateErrorCode) { + case kValidateErrorMultipleOf: return GetMultipleOfString(); + case kValidateErrorMaximum: return GetMaximumString(); + case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same + case kValidateErrorMinimum: return GetMinimumString(); + case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same + + case kValidateErrorMaxLength: return GetMaxLengthString(); + case kValidateErrorMinLength: return GetMinLengthString(); + case kValidateErrorPattern: return GetPatternString(); + + case kValidateErrorMaxItems: return GetMaxItemsString(); + case kValidateErrorMinItems: return GetMinItemsString(); + case kValidateErrorUniqueItems: return GetUniqueItemsString(); + case kValidateErrorAdditionalItems: return GetAdditionalItemsString(); + + case kValidateErrorMaxProperties: return GetMaxPropertiesString(); + case kValidateErrorMinProperties: return GetMinPropertiesString(); + case kValidateErrorRequired: return GetRequiredString(); + case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString(); + case kValidateErrorPatternProperties: return GetPatternPropertiesString(); + case kValidateErrorDependencies: return GetDependenciesString(); + + case kValidateErrorEnum: return GetEnumString(); + case kValidateErrorType: return GetTypeString(); + + case kValidateErrorOneOf: return GetOneOfString(); + case kValidateErrorOneOfMatch: return GetOneOfString(); // Same + case kValidateErrorAllOf: return GetAllOfString(); + case kValidateErrorAnyOf: return GetAnyOfString(); + case kValidateErrorNot: return GetNotString(); + + case kValidateErrorReadOnly: return GetReadOnlyString(); + case kValidateErrorWriteOnly: return GetWriteOnlyString(); + + default: return GetNullString(); + } + } + + + // Generate functions for string literal according to Ch +#define RAPIDJSON_STRING_(name, ...) \ + static const ValueType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ + return v;\ + } + + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') + RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') + RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') + RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') + RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') + RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') + RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') + RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') + RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') + RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') + RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') + RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') + RAPIDJSON_STRING_(Not, 'n', 'o', 't') + RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') + RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') + RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') + RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') + RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't') + RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a') + RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f') + RAPIDJSON_STRING_(Id, 'i', 'd') + RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r') + RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i') + RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y') + RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y') + RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e') + +#undef RAPIDJSON_STRING_ + +private: + enum SchemaValueType { + kNullSchemaType, + kBooleanSchemaType, + kObjectSchemaType, + kArraySchemaType, + kStringSchemaType, + kNumberSchemaType, + kIntegerSchemaType, + kTotalSchemaType + }; + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + typedef internal::GenericRegex RegexType; +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + typedef std::basic_regex RegexType; +#else + typedef char RegexType; +#endif + + struct SchemaArray { + SchemaArray() : schemas(), count() {} + ~SchemaArray() { AllocatorType::Free(schemas); } + const SchemaType** schemas; + SizeType begin; // begin index of context.validators + SizeType count; + }; + + template + void AddUniqueElement(V1& a, const V2& v) { + for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) + if (*itr == v) + return; + V1 c(v, *allocator_); + a.PushBack(c, *allocator_); + } + + static const ValueType* GetMember(const ValueType& value, const ValueType& name) { + typename ValueType::ConstMemberIterator itr = value.FindMember(name); + return itr != value.MemberEnd() ? &(itr->value) : 0; + } + + static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsBool()) + out = v->GetBool(); + } + + static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) + out = static_cast(v->GetUint64()); + } + + void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { + if (const ValueType* v = GetMember(value, name)) { + if (v->IsArray() && v->Size() > 0) { + PointerType q = p.Append(name, allocator_); + out.count = v->Size(); + out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); + memset(out.schemas, 0, sizeof(Schema*)* out.count); + for (SizeType i = 0; i < out.count; i++) + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_); + out.begin = validatorCount_; + validatorCount_ += out.count; + } + } + } + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + template + RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) { + if (value.IsString()) { + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); + if (!r->IsValid()) { + sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength()); + r->~RegexType(); + AllocatorType::Free(r); + r = 0; + } + return r; + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { + GenericRegexSearch rs(*pattern); + return rs.Search(str); + } +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + template + RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) { + if (value.IsString()) { + RegexType *r = static_cast(allocator_->Malloc(sizeof(RegexType))); + try { + return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); + } + catch (const std::regex_error& e) { + sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength()); + AllocatorType::Free(r); + } + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { + std::match_results r; + return std::regex_search(str, str + length, r, *pattern); + } +#else + template + RegexType* CreatePattern(const ValueType&) { + return 0; + } + + static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } +#endif // RAPIDJSON_SCHEMA_USE_STDREGEX + + void AddType(const ValueType& type) { + if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; + else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; + else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; + else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; + else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; + else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; + else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); + } + + // Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if required. + // Also creates a hasher for enums and array uniqueness, if required. + // Also a useful place to add type-independent error checks. + bool CreateParallelValidator(Context& context) const { + if (enum_ || context.arrayUniqueness) + context.hasher = context.factory.CreateHasher(); + + if (validatorCount_) { + RAPIDJSON_ASSERT(context.validators == 0); + context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); + std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_); + context.validatorCount = validatorCount_; + + // Always return after first failure for these sub-validators + if (allOf_.schemas) + CreateSchemaValidators(context, allOf_, false); + + if (anyOf_.schemas) + CreateSchemaValidators(context, anyOf_, false); + + if (oneOf_.schemas) + CreateSchemaValidators(context, oneOf_, false); + + if (not_) + context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false); + + if (hasSchemaDependencies_) { + for (SizeType i = 0; i < propertyCount_; i++) + if (properties_[i].dependenciesSchema) + context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false); + } + } + + // Add any other type-independent checks here + if (readOnly_ && (context.flags & kValidateWriteFlag)) { + context.error_handler.DisallowedWhenWriting(); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorReadOnly); + } + if (writeOnly_ && (context.flags & kValidateReadFlag)) { + context.error_handler.DisallowedWhenReading(); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorWriteOnly); + } + + return true; + } + + void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const { + for (SizeType i = 0; i < schemas.count; i++) + context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors); + } + + // O(n) + bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { + SizeType len = name.GetStringLength(); + const Ch* str = name.GetString(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].name.GetStringLength() == len && + (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) + { + *outIndex = index; + return true; + } + return false; + } + + bool CheckBool(Context& context, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) { + DisallowedType(context, GetBooleanString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + return true; + } + + bool CheckInt(Context& context, int64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + + if (!minimum_.IsNull()) { + if (minimum_.IsInt64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); + } + } + else if (minimum_.IsUint64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64() + } + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsInt64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); + } + } + else if (maximum_.IsUint64()) { } + /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); + } + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckUint(Context& context, uint64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + + if (!minimum_.IsNull()) { + if (minimum_.IsUint64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); + } + } + else if (minimum_.IsInt64()) + /* do nothing */; // i >= 0 > minimum.Getint64() + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsUint64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); + } + } + else if (maximum_.IsInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_ + } + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (i % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); + } + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckDoubleMinimum(Context& context, double d) const { + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { + context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); + } + return true; + } + + bool CheckDoubleMaximum(Context& context, double d) const { + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { + context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); + } + return true; + } + + bool CheckDoubleMultipleOf(Context& context, double d) const { + double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); + double q = std::floor(a / b); + double r = a - q * b; + if (r > 0.0) { + context.error_handler.NotMultipleOf(d, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); + } + return true; + } + + void DisallowedType(Context& context, const ValueType& actualType) const { + ErrorHandler& eh = context.error_handler; + eh.StartDisallowedType(); + + if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); + if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString()); + if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString()); + if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString()); + if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString()); + + if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString()); + else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString()); + + eh.EndDisallowedType(actualType); + } + + struct Property { + Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} + ~Property() { AllocatorType::Free(dependencies); } + SValue name; + const SchemaType* schema; + const SchemaType* dependenciesSchema; + SizeType dependenciesValidatorIndex; + bool* dependencies; + bool required; + }; + + struct PatternProperty { + PatternProperty() : schema(), pattern() {} + ~PatternProperty() { + if (pattern) { + pattern->~RegexType(); + AllocatorType::Free(pattern); + } + } + const SchemaType* schema; + RegexType* pattern; + }; + + AllocatorType* allocator_; + SValue uri_; + UriType id_; + Specification spec_; + PointerType pointer_; + const SchemaType* typeless_; + uint64_t* enum_; + SizeType enumCount_; + SchemaArray allOf_; + SchemaArray anyOf_; + SchemaArray oneOf_; + const SchemaType* not_; + unsigned type_; // bitmask of kSchemaType + SizeType validatorCount_; + SizeType notValidatorIndex_; + + Property* properties_; + const SchemaType* additionalPropertiesSchema_; + PatternProperty* patternProperties_; + SizeType patternPropertyCount_; + SizeType propertyCount_; + SizeType minProperties_; + SizeType maxProperties_; + bool additionalProperties_; + bool hasDependencies_; + bool hasRequired_; + bool hasSchemaDependencies_; + + const SchemaType* additionalItemsSchema_; + const SchemaType* itemsList_; + const SchemaType** itemsTuple_; + SizeType itemsTupleCount_; + SizeType minItems_; + SizeType maxItems_; + bool additionalItems_; + bool uniqueItems_; + + RegexType* pattern_; + SizeType minLength_; + SizeType maxLength_; + + SValue minimum_; + SValue maximum_; + SValue multipleOf_; + bool exclusiveMinimum_; + bool exclusiveMaximum_; + + SizeType defaultValueLength_; + + bool readOnly_; + bool writeOnly_; + bool nullable_; +}; + +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + *documentStack.template Push() = '/'; + char buffer[21]; + size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); + for (size_t i = 0; i < length; i++) + *documentStack.template Push() = static_cast(buffer[i]); + } +}; + +// Partial specialized version for char to prevent buffer copying. +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + if (sizeof(SizeType) == 4) { + char *buffer = documentStack.template Push(1 + 10); // '/' + uint + *buffer++ = '/'; + const char* end = internal::u32toa(index, buffer); + documentStack.template Pop(static_cast(10 - (end - buffer))); + } + else { + char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 + *buffer++ = '/'; + const char* end = internal::u64toa(index, buffer); + documentStack.template Pop(static_cast(20 - (end - buffer))); + } + } +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// IGenericRemoteSchemaDocumentProvider + +template +class IGenericRemoteSchemaDocumentProvider { +public: + typedef typename SchemaDocumentType::Ch Ch; + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; + + virtual ~IGenericRemoteSchemaDocumentProvider() {} + virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; + virtual const SchemaDocumentType* GetRemoteDocument(const GenericUri uri, Specification& spec) { + // Default implementation just calls through for compatibility + // Following line suppresses unused parameter warning + (void)spec; + // printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi); + return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength()); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaDocument + +//! JSON schema document. +/*! + A JSON schema document is a compiled version of a JSON schema. + It is basically a tree of internal::Schema. + + \note This is an immutable class (i.e. its instance cannot be modified after construction). + \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. + \tparam Allocator Allocator type for allocating memory of this document. +*/ +template +class GenericSchemaDocument { +public: + typedef ValueT ValueType; + typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; + typedef Allocator AllocatorType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef internal::Schema SchemaType; + typedef GenericPointer PointerType; + typedef GenericValue GValue; + typedef GenericUri UriType; + typedef GenericStringRef StringRefType; + friend class internal::Schema; + template + friend class GenericSchemaValidator; + + //! Constructor. + /*! + Compile a JSON document into schema document. + + \param document A JSON document as source. + \param uri The base URI of this schema document for purposes of violation reporting. + \param uriLength Length of \c name, in code points. + \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. + \param allocator An optional allocator instance for allocating memory. Can be null. + \param pointer An optional JSON pointer to the start of the schema document + \param spec Optional schema draft or OpenAPI version. Used if no specification in document. Defaults to draft-04. + */ + explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, + IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0, + const PointerType& pointer = PointerType(), // PR #1393 + const Specification& spec = Specification(kDraft04)) : + remoteProvider_(remoteProvider), + allocator_(allocator), + ownAllocator_(), + root_(), + typeless_(), + schemaMap_(allocator, kInitialSchemaMapSize), + schemaRef_(allocator, kInitialSchemaRefSize), + spec_(spec), + error_(kObjectType), + currentError_() + { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument"); + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + Ch noUri[1] = {0}; + uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); + docId_ = UriType(uri_, allocator_); + + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_); + + // Establish the schema draft or open api version. + // We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document. + SetSchemaSpecification(document); + + // Generate root schema, it will call CreateSchema() to create sub-schemas, + // And call HandleRefSchema() if there are $ref. + // PR #1393 use input pointer if supplied + root_ = typeless_; + if (pointer.GetTokenCount() == 0) { + CreateSchemaRecursive(&root_, pointer, document, document, docId_); + } + else if (const ValueType* v = pointer.Get(document)) { + CreateSchema(&root_, pointer, *v, document, docId_); + } + else { + GenericStringBuffer sb; + pointer.StringifyUriFragment(sb); + SchemaErrorValue(kSchemaErrorStartUnknown, PointerType(), sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch))); + } + + RAPIDJSON_ASSERT(root_ != 0); + + schemaRef_.ShrinkToFit(); // Deallocate all memory for ref + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : + remoteProvider_(rhs.remoteProvider_), + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + root_(rhs.root_), + typeless_(rhs.typeless_), + schemaMap_(std::move(rhs.schemaMap_)), + schemaRef_(std::move(rhs.schemaRef_)), + uri_(std::move(rhs.uri_)), + docId_(std::move(rhs.docId_)), + spec_(rhs.spec_), + error_(std::move(rhs.error_)), + currentError_(std::move(rhs.currentError_)) + { + rhs.remoteProvider_ = 0; + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.typeless_ = 0; + } +#endif + + //! Destructor + ~GenericSchemaDocument() { + while (!schemaMap_.Empty()) + schemaMap_.template Pop(1)->~SchemaEntry(); + + if (typeless_) { + typeless_->~SchemaType(); + Allocator::Free(typeless_); + } + + // these may contain some allocator data so clear before deleting ownAllocator_ + uri_.SetNull(); + error_.SetNull(); + currentError_.SetNull(); + + RAPIDJSON_DELETE(ownAllocator_); + } + + const GValue& GetURI() const { return uri_; } + + const Specification& GetSpecification() const { return spec_; } + bool IsSupportedSpecification() const { return spec_.IsSupported(); } + + //! Static method to get the specification of any schema document + // Returns kDraftNone if document is silent + static const Specification GetSpecification(const ValueType& document) { + SchemaDraft draft = GetSchemaDraft(document); + if (draft != kDraftNone) + return Specification(draft); + else { + OpenApiVersion oapi = GetOpenApiVersion(document); + if (oapi != kVersionNone) + return Specification(oapi); + } + return Specification(kDraftNone); + } + + //! Get the root schema. + const SchemaType& GetRoot() const { return *root_; } + + //! Gets the error object. + GValue& GetError() { return error_; } + const GValue& GetError() const { return error_; } + + static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode) { + switch (schemaErrorCode) { + case kSchemaErrorStartUnknown: return GetStartUnknownString(); + case kSchemaErrorRefPlainName: return GetRefPlainNameString(); + case kSchemaErrorRefInvalid: return GetRefInvalidString(); + case kSchemaErrorRefPointerInvalid: return GetRefPointerInvalidString(); + case kSchemaErrorRefUnknown: return GetRefUnknownString(); + case kSchemaErrorRefCyclical: return GetRefCyclicalString(); + case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString(); + case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString(); + case kSchemaErrorRegexInvalid: return GetRegexInvalidString(); + case kSchemaErrorSpecUnknown: return GetSpecUnknownString(); + case kSchemaErrorSpecUnsupported: return GetSpecUnsupportedString(); + case kSchemaErrorSpecIllegal: return GetSpecIllegalString(); + case kSchemaErrorReadOnlyAndWriteOnly: return GetReadOnlyAndWriteOnlyString(); + default: return GetNullString(); + } + } + + //! Default error method + void SchemaError(const SchemaErrorCode code, const PointerType& location) { + currentError_ = GValue(kObjectType); + AddCurrentError(code, location); + } + + //! Method for error with single string value insert + void SchemaErrorValue(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length) { + currentError_ = GValue(kObjectType); + currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_); + AddCurrentError(code, location); + } + + //! Method for error with invalid pointer + void SchemaErrorPointer(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length, const PointerType& pointer) { + currentError_ = GValue(kObjectType); + currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_); + currentError_.AddMember(GetOffsetString(), static_cast(pointer.GetParseErrorOffset() / sizeof(Ch)), *allocator_); + AddCurrentError(code, location); + } + + private: + //! Prohibit copying + GenericSchemaDocument(const GenericSchemaDocument&); + //! Prohibit assignment + GenericSchemaDocument& operator=(const GenericSchemaDocument&); + + typedef const PointerType* SchemaRefPtr; // PR #1393 + + struct SchemaEntry { + SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} + ~SchemaEntry() { + if (owned) { + schema->~SchemaType(); + Allocator::Free(schema); + } + } + PointerType pointer; + SchemaType* schema; + bool owned; + }; + + void AddErrorInstanceLocation(GValue& result, const PointerType& location) { + GenericStringBuffer sb; + location.StringifyUriFragment(sb); + GValue instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), *allocator_); + result.AddMember(GetInstanceRefString(), instanceRef, *allocator_); + } + + void AddError(GValue& keyword, GValue& error) { + typename GValue::MemberIterator member = error_.FindMember(keyword); + if (member == error_.MemberEnd()) + error_.AddMember(keyword, error, *allocator_); + else { + if (member->value.IsObject()) { + GValue errors(kArrayType); + errors.PushBack(member->value, *allocator_); + member->value = errors; + } + member->value.PushBack(error, *allocator_); + } + } + + void AddCurrentError(const SchemaErrorCode code, const PointerType& location) { + RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code)); + currentError_.AddMember(GetErrorCodeString(), code, *allocator_); + AddErrorInstanceLocation(currentError_, location); + AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_); + } + +#define RAPIDJSON_STRING_(name, ...) \ + static const StringRefType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ + return v;\ + } + + RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') + RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') + RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e') + RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't') + + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') + RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n') + RAPIDJSON_STRING_(SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd') + RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l') + RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n') + RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e') + RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd') + RAPIDJSON_STRING_(RefPointerInvalid, 'R', 'e', 'f', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'I', 'n', 'v', 'a', 'l', 'i', 'd') + RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n') + RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l') + RAPIDJSON_STRING_(RefNoRemoteProvider, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r') + RAPIDJSON_STRING_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a') + RAPIDJSON_STRING_(ReadOnlyAndWriteOnly, 'R', 'e', 'a', 'd', 'O', 'n', 'l', 'y', 'A', 'n', 'd', 'W', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y') + RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd') + +#undef RAPIDJSON_STRING_ + + // Static method to get schema draft of any schema document + static SchemaDraft GetSchemaDraft(const ValueType& document) { + static const Ch kDraft03String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '3', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft04String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '4', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft05String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '5', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft06String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '6', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft07String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '7', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft2019_09String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '1', '9', '-', '0', '9', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' }; + static const Ch kDraft2020_12String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '2', '0', '-', '1', '2', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' }; + + if (!document.IsObject()) { + return kDraftNone; + } + + // Get the schema draft from the $schema keyword at the supplied location + typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString()); + if (itr != document.MemberEnd()) { + if (!itr->value.IsString()) return kDraftUnknown; + const UriType draftUri(itr->value); + // Check base uri for match + if (draftUri.Match(UriType(kDraft04String), false)) return kDraft04; + if (draftUri.Match(UriType(kDraft05String), false)) return kDraft05; + if (draftUri.Match(UriType(kDraft06String), false)) return kDraft06; + if (draftUri.Match(UriType(kDraft07String), false)) return kDraft07; + if (draftUri.Match(UriType(kDraft03String), false)) return kDraft03; + if (draftUri.Match(UriType(kDraft2019_09String), false)) return kDraft2019_09; + if (draftUri.Match(UriType(kDraft2020_12String), false)) return kDraft2020_12; + return kDraftUnknown; + } + // $schema not found + return kDraftNone; + } + + + // Get open api version of any schema document + static OpenApiVersion GetOpenApiVersion(const ValueType& document) { + static const Ch kVersion20String[] = { '2', '.', '0', '\0' }; + static const Ch kVersion30String[] = { '3', '.', '0', '.', '\0' }; // ignore patch level + static const Ch kVersion31String[] = { '3', '.', '1', '.', '\0' }; // ignore patch level + static SizeType len = internal::StrLen(kVersion30String); + + if (!document.IsObject()) { + return kVersionNone; + } + + // Get the open api version from the swagger / openapi keyword at the supplied location + typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString()); + if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString()); + if (itr != document.MemberEnd()) { + if (!itr->value.IsString()) return kVersionUnknown; + const ValueType kVersion20Value(kVersion20String); + if (kVersion20Value == itr->value) return kVersion20; // must match 2.0 exactly + const ValueType kVersion30Value(kVersion30String); + if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len)) return kVersion30; // must match 3.0.x + const ValueType kVersion31Value(kVersion31String); + if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len)) return kVersion31; // must match 3.1.x + return kVersionUnknown; + } + // swagger or openapi not found + return kVersionNone; + } + + // Get the draft of the schema or the open api version (which implies the draft). + // Report an error if schema draft or open api version not supported or not recognized, or both in document, and carry on. + void SetSchemaSpecification(const ValueType& document) { + // Look for '$schema', 'swagger' or 'openapi' keyword at document root + SchemaDraft docDraft = GetSchemaDraft(document); + OpenApiVersion docOapi = GetOpenApiVersion(document); + // Error if both in document + if (docDraft != kDraftNone && docOapi != kVersionNone) + SchemaError(kSchemaErrorSpecIllegal, PointerType()); + // Use document draft or open api version if present or use spec from constructor + if (docDraft != kDraftNone) + spec_ = Specification(docDraft); + else if (docOapi != kVersionNone) + spec_ = Specification(docOapi); + // Error if draft or version unknown + if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown) + SchemaError(kSchemaErrorSpecUnknown, PointerType()); + else if (!spec_.IsSupported()) + SchemaError(kSchemaErrorSpecUnsupported, PointerType()); + } + + // Changed by PR #1393 + void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { + if (v.GetType() == kObjectType) { + UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_); + + for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid); + } + else if (v.GetType() == kArrayType) + for (SizeType i = 0; i < v.Size(); i++) + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id); + } + + // Changed by PR #1393 + const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { + RAPIDJSON_ASSERT(pointer.IsValid()); + GenericStringBuffer sb; + pointer.StringifyUriFragment(sb); + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString()); + if (v.IsObject()) { + if (const SchemaType* sc = GetSchema(pointer)) { + if (schema) + *schema = sc; + AddSchemaRefs(const_cast(sc)); + } + else if (!HandleRefSchema(pointer, schema, v, document, id)) { + // The new schema constructor adds itself and its $ref(s) to schemaMap_ + SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id); + if (schema) + *schema = s; + return s->GetId(); + } + } + else { + if (schema) + *schema = typeless_; + AddSchemaRefs(typeless_); + } + return id; + } + + // Changed by PR #1393 + // TODO should this return a UriType& ? + bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) { + typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString()); + if (itr == v.MemberEnd()) + return false; + + GenericStringBuffer sb; + source.StringifyUriFragment(sb); + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString()); + // Resolve the source pointer to the $ref'ed schema (finally) + new (schemaRef_.template Push()) SchemaRefPtr(&source); + + if (itr->value.IsString()) { + SizeType len = itr->value.GetStringLength(); + if (len == 0) + SchemaError(kSchemaErrorRefInvalid, source); + else { + // First resolve $ref against the in-scope id + UriType scopeId = UriType(id, allocator_); + UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_); + RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString()); + // See if the resolved $ref minus the fragment matches a resolved id in this document + // Search from the root. Returns the subschema in the document and its absolute JSON pointer. + PointerType basePointer = PointerType(); + const ValueType *base = FindId(document, ref, basePointer, docId_, false); + if (!base) { + // Remote reference - call the remote document provider + if (!remoteProvider_) + SchemaError(kSchemaErrorRefNoRemoteProvider, source); + else { + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) { + const Ch* s = ref.GetFragString(); + len = ref.GetFragStringLength(); + if (len <= 1 || s[1] == '/') { + // JSON pointer fragment, absolute in the remote schema + const PointerType pointer(s, len, allocator_); + if (!pointer.IsValid()) + SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, pointer); + else { + // Get the subschema + if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) { + if (schema) + *schema = sc; + AddSchemaRefs(const_cast(sc)); + return true; + } else + SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); + } + } else + // Plain name fragment, not allowed in remote schema + SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len); + } else + SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength()); + } + } + else { // Local reference + const Ch* s = ref.GetFragString(); + len = ref.GetFragStringLength(); + if (len <= 1 || s[1] == '/') { + // JSON pointer fragment, relative to the resolved URI + const PointerType relPointer(s, len, allocator_); + if (!relPointer.IsValid()) + SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, relPointer); + else { + // Get the subschema + if (const ValueType *pv = relPointer.Get(*base)) { + // Now get the absolute JSON pointer by adding relative to base + PointerType pointer(basePointer, allocator_); + for (SizeType i = 0; i < relPointer.GetTokenCount(); i++) + pointer = pointer.Append(relPointer.GetTokens()[i], allocator_); + if (IsCyclicRef(pointer)) + SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength()); + else { + // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there + // TODO: cache pointer <-> id mapping + size_t unresolvedTokenIndex; + scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); + CreateSchema(schema, pointer, *pv, document, scopeId); + return true; + } + } else + SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); + } + } else { + // Plain name fragment, relative to the resolved URI + // Not supported in open api 2.0 and 3.0 + PointerType pointer(allocator_); + if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30) + SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len); + // See if the fragment matches an id in this document. + // Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer. + else if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) { + if (IsCyclicRef(pointer)) + SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength()); + else { + // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there + // TODO: cache pointer <-> id mapping + size_t unresolvedTokenIndex; + scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); + CreateSchema(schema, pointer, *pv, document, scopeId); + return true; + } + } else + SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); + } + } + } + } + + // Invalid/Unknown $ref + if (schema) + *schema = typeless_; + AddSchemaRefs(typeless_); + return true; + } + + //! Find the first subschema with a resolved 'id' that matches the specified URI. + // If full specified use all URI else ignore fragment. + // If found, return a pointer to the subschema and its JSON pointer. + // TODO cache pointer <-> id mapping + ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const { + SizeType i = 0; + ValueType* resval = 0; + UriType tempuri = UriType(finduri, allocator_); + UriType localuri = UriType(baseuri, allocator_); + if (doc.GetType() == kObjectType) { + // Establish the base URI of this object + typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString()); + if (m != doc.MemberEnd() && m->value.GetType() == kStringType) { + localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_); + } + // See if it matches + if (localuri.Match(finduri, full)) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString()); + resval = const_cast(&doc); + resptr = here; + return resval; + } + // No match, continue looking + for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) { + if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) { + resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_)); + } + if (resval) break; + } + } else if (doc.GetType() == kArrayType) { + // Continue looking + for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) { + if (v->GetType() == kObjectType || v->GetType() == kArrayType) { + resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_)); + } + if (resval) break; + i++; + } + } + return resval; + } + + // Added by PR #1393 + void AddSchemaRefs(SchemaType* schema) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs"); + while (!schemaRef_.Empty()) { + SchemaRefPtr *ref = schemaRef_.template Pop(1); + SchemaEntry *entry = schemaMap_.template Push(); + new (entry) SchemaEntry(**ref, schema, false, allocator_); + } + } + + // Added by PR #1393 + bool IsCyclicRef(const PointerType& pointer) const { + for (const SchemaRefPtr* ref = schemaRef_.template Bottom(); ref != schemaRef_.template End(); ++ref) + if (pointer == **ref) + return true; + return false; + } + + const SchemaType* GetSchema(const PointerType& pointer) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (pointer == target->pointer) + return target->schema; + return 0; + } + + PointerType GetPointer(const SchemaType* schema) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (schema == target->schema) + return target->pointer; + return PointerType(); + } + + const SchemaType* GetTypeless() const { return typeless_; } + + static const size_t kInitialSchemaMapSize = 64; + static const size_t kInitialSchemaRefSize = 64; + + IRemoteSchemaDocumentProviderType* remoteProvider_; + Allocator *allocator_; + Allocator *ownAllocator_; + const SchemaType* root_; //!< Root schema. + SchemaType* typeless_; + internal::Stack schemaMap_; // Stores created Pointer -> Schemas + internal::Stack schemaRef_; // Stores Pointer(s) from $ref(s) until resolved + GValue uri_; // Schema document URI + UriType docId_; + Specification spec_; + GValue error_; + GValue currentError_; +}; + +//! GenericSchemaDocument using Value type. +typedef GenericSchemaDocument SchemaDocument; +//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaValidator + +//! JSON Schema Validator. +/*! + A SAX style JSON schema validator. + It uses a \c GenericSchemaDocument to validate SAX events. + It delegates the incoming SAX events to an output handler. + The default output handler does nothing. + It can be reused multiple times by calling \c Reset(). + + \tparam SchemaDocumentType Type of schema document. + \tparam OutputHandler Type of output handler. Default handler does nothing. + \tparam StateAllocator Allocator for storing the internal validation states. +*/ +template < + typename SchemaDocumentType, + typename OutputHandler = BaseReaderHandler, + typename StateAllocator = CrtAllocator> +class GenericSchemaValidator : + public internal::ISchemaStateFactory, + public internal::ISchemaValidator, + public internal::IValidationErrorHandler { +public: + typedef typename SchemaDocumentType::SchemaType SchemaType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename SchemaType::EncodingType EncodingType; + typedef typename SchemaType::SValue SValue; + typedef typename EncodingType::Ch Ch; + typedef GenericStringRef StringRefType; + typedef GenericValue ValueType; + + //! Constructor without output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true), + flags_(kValidateDefaultFlags), + depth_(0) + { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator"); + } + + //! Constructor with output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + OutputHandler& outputHandler, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(&outputHandler), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true), + flags_(kValidateDefaultFlags), + depth_(0) + { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (output handler)"); + } + + //! Destructor. + ~GenericSchemaValidator() { + Reset(); + RAPIDJSON_DELETE(ownStateAllocator_); + } + + //! Reset the internal states. + void Reset() { + while (!schemaStack_.Empty()) + PopSchema(); + documentStack_.Clear(); + ResetError(); + } + + //! Reset the error state. + void ResetError() { + error_.SetObject(); + currentError_.SetNull(); + missingDependents_.SetNull(); + valid_ = true; + } + + //! Implementation of ISchemaValidator + void SetValidateFlags(unsigned flags) { + flags_ = flags; + } + virtual unsigned GetValidateFlags() const { + return flags_; + } + + virtual bool IsValid() const { + if (!valid_) return false; + if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false; + return true; + } + //! End of Implementation of ISchemaValidator + + //! Gets the error object. + ValueType& GetError() { return error_; } + const ValueType& GetError() const { return error_; } + + //! Gets the JSON pointer pointed to the invalid schema. + // If reporting all errors, the stack will be empty. + PointerType GetInvalidSchemaPointer() const { + return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); + } + + //! Gets the keyword of invalid schema. + // If reporting all errors, the stack will be empty, so return "errors". + const Ch* GetInvalidSchemaKeyword() const { + if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword; + if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString(); + return 0; + } + + //! Gets the error code of invalid schema. + // If reporting all errors, the stack will be empty, so return kValidateErrors. + ValidateErrorCode GetInvalidSchemaCode() const { + if (!schemaStack_.Empty()) return CurrentContext().invalidCode; + if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors; + return kValidateErrorNone; + } + + //! Gets the JSON pointer pointed to the invalid value. + // If reporting all errors, the stack will be empty. + PointerType GetInvalidDocumentPointer() const { + if (documentStack_.Empty()) { + return PointerType(); + } + else { + return PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + } + } + + void NotMultipleOf(int64_t actual, const SValue& expected) { + AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); + } + void NotMultipleOf(uint64_t actual, const SValue& expected) { + AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); + } + void NotMultipleOf(double actual, const SValue& expected) { + AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); + } + void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + + void TooLong(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(kValidateErrorMaxLength, + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void TooShort(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(kValidateErrorMinLength, + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void DoesNotMatch(const Ch* str, SizeType length) { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(kValidateErrorPattern); + } + + void DisallowedItem(SizeType index) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); + AddCurrentError(kValidateErrorAdditionalItems, true); + } + void TooFewItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(kValidateErrorMinItems, + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooManyItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(kValidateErrorMaxItems, + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void DuplicateItems(SizeType index1, SizeType index2) { + ValueType duplicates(kArrayType); + duplicates.PushBack(index1, GetStateAllocator()); + duplicates.PushBack(index2, GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator()); + AddCurrentError(kValidateErrorUniqueItems, true); + } + + void TooManyProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(kValidateErrorMaxProperties, + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooFewProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(kValidateErrorMinProperties, + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void StartMissingProperties() { + currentError_.SetArray(); + } + void AddMissingProperty(const SValue& name) { + currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator()); + } + bool EndMissingProperties() { + if (currentError_.Empty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetMissingString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(kValidateErrorRequired); + return true; + } + void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) { + for (SizeType i = 0; i < count; ++i) + MergeError(static_cast(subvalidators[i])->GetError()); + } + void DisallowedProperty(const Ch* name, SizeType length) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(kValidateErrorAdditionalProperties, true); + } + + void StartDependencyErrors() { + currentError_.SetObject(); + } + void StartMissingDependentProperties() { + missingDependents_.SetArray(); + } + void AddMissingDependentProperty(const SValue& targetName) { + missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndMissingDependentProperties(const SValue& sourceName) { + if (!missingDependents_.Empty()) { + // Create equivalent 'required' error + ValueType error(kObjectType); + ValidateErrorCode code = kValidateErrorRequired; + error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator()); + AddErrorCode(error, code); + AddErrorInstanceLocation(error, false); + // When appending to a pointer ensure its allocator is used + PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator()); + AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator())); + ValueType wrapper(kObjectType); + wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator()); + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator()); + } + } + void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) { + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + static_cast(subvalidator)->GetError(), GetStateAllocator()); + } + bool EndDependencyErrors() { + if (currentError_.ObjectEmpty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetErrorsString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(kValidateErrorDependencies); + return true; + } + + void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) { + currentError_.SetObject(); + AddCurrentError(code); + } + void StartDisallowedType() { + currentError_.SetArray(); + } + void AddExpectedType(const typename SchemaType::ValueType& expectedType) { + currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndDisallowedType(const typename SchemaType::ValueType& actualType) { + ValueType error(kObjectType); + error.AddMember(GetExpectedString(), currentError_, GetStateAllocator()); + error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator()); + currentError_ = error; + AddCurrentError(kValidateErrorType); + } + void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { + // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf + AddErrorArray(kValidateErrorAllOf, subvalidators, count); + //for (SizeType i = 0; i < count; ++i) { + // MergeError(static_cast(subvalidators[i])->GetError()); + //} + } + void NoneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(kValidateErrorAnyOf, subvalidators, count); + } + void NotOneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(kValidateErrorOneOf, subvalidators, count); + } + void MultipleOneOf(SizeType index1, SizeType index2) { + ValueType matches(kArrayType); + matches.PushBack(index1, GetStateAllocator()); + matches.PushBack(index2, GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator()); + AddCurrentError(kValidateErrorOneOfMatch); + } + void Disallowed() { + currentError_.SetObject(); + AddCurrentError(kValidateErrorNot); + } + void DisallowedWhenWriting() { + currentError_.SetObject(); + AddCurrentError(kValidateErrorReadOnly); + } + void DisallowedWhenReading() { + currentError_.SetObject(); + AddCurrentError(kValidateErrorWriteOnly); + } + +#define RAPIDJSON_STRING_(name, ...) \ + static const StringRefType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ + return v;\ + } + + RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') + RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f') + RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd') + RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l') + RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd') + RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g') + RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's') + RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') + RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e') + RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') + RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's') + +#undef RAPIDJSON_STRING_ + +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ + if (!valid_) return false; \ + if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\ + *documentStack_.template Push() = '\0';\ + documentStack_.template Pop(1);\ + RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom());\ + valid_ = false;\ + return valid_;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ + for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ + if (context->hasher)\ + static_cast(context->hasher)->method arg2;\ + if (context->validators)\ + for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ + static_cast(context->validators[i_])->method arg2;\ + if (context->patternPropertiesValidators)\ + for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ + static_cast(context->patternPropertiesValidators[i_])->method arg2;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ + valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\ + return valid_; + +#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ + RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) + + bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); } + bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } + bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } + bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } + bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } + bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } + bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } + bool RawNumber(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + bool String(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + + bool StartObject() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject"); + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); + valid_ = !outputHandler_ || outputHandler_->StartObject(); + return valid_; + } + + bool Key(const Ch* str, SizeType len, bool copy) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str); + if (!valid_) return false; + AppendToken(str, len); + if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); + valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); + return valid_; + } + + bool EndObject(SizeType memberCount) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject"); + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); + if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } + RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); + } + + bool StartArray() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray"); + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); + valid_ = !outputHandler_ || outputHandler_->StartArray(); + return valid_; + } + + bool EndArray(SizeType elementCount) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray"); + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); + if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } + RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); + } + +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ +#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ +#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ + + // Implementation of ISchemaStateFactory + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) { + *documentStack_.template Push() = '\0'; + documentStack_.template Pop(1); + ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), + depth_ + 1, + &GetStateAllocator()); + sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag); + return sv; + } + + virtual void DestroySchemaValidator(ISchemaValidator* validator) { + GenericSchemaValidator* v = static_cast(validator); + v->~GenericSchemaValidator(); + StateAllocator::Free(v); + } + + virtual void* CreateHasher() { + return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); + } + + virtual uint64_t GetHashCode(void* hasher) { + return static_cast(hasher)->GetHashCode(); + } + + virtual void DestroryHasher(void* hasher) { + HasherType* h = static_cast(hasher); + h->~HasherType(); + StateAllocator::Free(h); + } + + virtual void* MallocState(size_t size) { + return GetStateAllocator().Malloc(size); + } + + virtual void FreeState(void* p) { + StateAllocator::Free(p); + } + // End of implementation of ISchemaStateFactory + +private: + typedef typename SchemaType::Context Context; + typedef GenericValue, StateAllocator> HashCodeArray; + typedef internal::Hasher HasherType; + + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + const SchemaType& root, + const char* basePath, size_t basePathSize, + unsigned depth, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(root), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true), + flags_(kValidateDefaultFlags), + depth_(depth) + { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath : ""); + if (basePath && basePathSize) + memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); + } + + StateAllocator& GetStateAllocator() { + if (!stateAllocator_) + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); + return *stateAllocator_; + } + + bool GetContinueOnErrors() const { + return flags_ & kValidateContinueOnErrorFlag; + } + + bool BeginValue() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue"); + if (schemaStack_.Empty()) + PushSchema(root_); + else { + if (CurrentContext().inArray) + internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); + + if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors()) + return false; + + SizeType count = CurrentContext().patternPropertiesSchemaCount; + const SchemaType** sa = CurrentContext().patternPropertiesSchemas; + typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; + bool valueUniqueness = CurrentContext().valueUniqueness; + RAPIDJSON_ASSERT(CurrentContext().valueSchema); + PushSchema(*CurrentContext().valueSchema); + + if (count > 0) { + CurrentContext().objectPatternValidatorType = patternValidatorType; + ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; + SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; + va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); + std::memset(va, 0, sizeof(ISchemaValidator*) * count); + for (SizeType i = 0; i < count; i++) + va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError + } + + CurrentContext().arrayUniqueness = valueUniqueness; + } + return true; + } + + bool EndValue() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue"); + if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors()) + return false; + + GenericStringBuffer sb; + schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb); + *documentStack_.template Push() = '\0'; + documentStack_.template Pop(1); + RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom(), depth_); + void* hasher = CurrentContext().hasher; + uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast(hasher)->GetHashCode() : 0; + + PopSchema(); + + if (!schemaStack_.Empty()) { + Context& context = CurrentContext(); + // Only check uniqueness if there is a hasher + if (hasher && context.valueUniqueness) { + HashCodeArray* a = static_cast(context.arrayElementHashCodes); + if (!a) + CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); + for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) + if (itr->GetUint64() == h) { + DuplicateItems(static_cast(itr - a->Begin()), a->Size()); + // Cleanup before returning if continuing + if (GetContinueOnErrors()) { + a->PushBack(h, GetStateAllocator()); + while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/'); + } + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems); + } + a->PushBack(h, GetStateAllocator()); + } + } + + // Remove the last token of document pointer + while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') + ; + + return true; + } + + void AppendToken(const Ch* str, SizeType len) { + documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters + *documentStack_.template PushUnsafe() = '/'; + for (SizeType i = 0; i < len; i++) { + if (str[i] == '~') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '0'; + } + else if (str[i] == '/') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '1'; + } + else + *documentStack_.template PushUnsafe() = str[i]; + } + } + + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema, flags_); } + + RAPIDJSON_FORCEINLINE void PopSchema() { + Context* c = schemaStack_.template Pop(1); + if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { + a->~HashCodeArray(); + StateAllocator::Free(a); + } + c->~Context(); + } + + void AddErrorInstanceLocation(ValueType& result, bool parent) { + GenericStringBuffer sb; + PointerType instancePointer = GetInvalidDocumentPointer(); + ((parent && instancePointer.GetTokenCount() > 0) + ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1) + : instancePointer).StringifyUriFragment(sb); + ValueType instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator()); + } + + void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) { + GenericStringBuffer sb; + SizeType len = CurrentSchema().GetURI().GetStringLength(); + if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch)); + if (schema.GetTokenCount()) schema.StringifyUriFragment(sb); + else GetInvalidSchemaPointer().StringifyUriFragment(sb); + ValueType schemaRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); + } + + void AddErrorCode(ValueType& result, const ValidateErrorCode code) { + result.AddMember(GetErrorCodeString(), code, GetStateAllocator()); + } + + void AddError(ValueType& keyword, ValueType& error) { + typename ValueType::MemberIterator member = error_.FindMember(keyword); + if (member == error_.MemberEnd()) + error_.AddMember(keyword, error, GetStateAllocator()); + else { + if (member->value.IsObject()) { + ValueType errors(kArrayType); + errors.PushBack(member->value, GetStateAllocator()); + member->value = errors; + } + member->value.PushBack(error, GetStateAllocator()); + } + } + + void AddCurrentError(const ValidateErrorCode code, bool parent = false) { + AddErrorCode(currentError_, code); + AddErrorInstanceLocation(currentError_, parent); + AddErrorSchemaLocation(currentError_); + AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_); + } + + void MergeError(ValueType& other) { + for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) { + AddError(it->name, it->value); + } + } + + void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected, + const typename SchemaType::ValueType& (*exclusive)() = 0) { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), actual, GetStateAllocator()); + currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator()); + if (exclusive) + currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator()); + AddCurrentError(code); + } + + void AddErrorArray(const ValidateErrorCode code, + ISchemaValidator** subvalidators, SizeType count) { + ValueType errors(kArrayType); + for (SizeType i = 0; i < count; ++i) + errors.PushBack(static_cast(subvalidators[i])->GetError(), GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator()); + AddCurrentError(code); + } + + const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } + Context& CurrentContext() { return *schemaStack_.template Top(); } + const Context& CurrentContext() const { return *schemaStack_.template Top(); } + + static const size_t kDefaultSchemaStackCapacity = 1024; + static const size_t kDefaultDocumentStackCapacity = 256; + const SchemaDocumentType* schemaDocument_; + const SchemaType& root_; + StateAllocator* stateAllocator_; + StateAllocator* ownStateAllocator_; + internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) + internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) + OutputHandler* outputHandler_; + ValueType error_; + ValueType currentError_; + ValueType missingDependents_; + bool valid_; + unsigned flags_; + unsigned depth_; +}; + +typedef GenericSchemaValidator SchemaValidator; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidatingReader + +//! A helper class for parsing with validation. +/*! + This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). + + \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam SourceEncoding Encoding of the input stream. + \tparam SchemaDocumentType Type of schema document. + \tparam StackAllocator Allocator type for stack. +*/ +template < + unsigned parseFlags, + typename InputStream, + typename SourceEncoding, + typename SchemaDocumentType = SchemaDocument, + typename StackAllocator = CrtAllocator> +class SchemaValidatingReader { +public: + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename InputStream::Ch Ch; + typedef GenericValue ValueType; + + //! Constructor + /*! + \param is Input stream. + \param sd Schema document. + */ + SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {} + + template + bool operator()(Handler& handler) { + GenericReader reader; + GenericSchemaValidator validator(sd_, handler); + parseResult_ = reader.template Parse(is_, validator); + + isValid_ = validator.IsValid(); + if (isValid_) { + invalidSchemaPointer_ = PointerType(); + invalidSchemaKeyword_ = 0; + invalidDocumentPointer_ = PointerType(); + error_.SetObject(); + } + else { + invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); + invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); + invalidSchemaCode_ = validator.GetInvalidSchemaCode(); + invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); + error_.CopyFrom(validator.GetError(), allocator_); + } + + return parseResult_; + } + + const ParseResult& GetParseResult() const { return parseResult_; } + bool IsValid() const { return isValid_; } + const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } + const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } + const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } + const ValueType& GetError() const { return error_; } + ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; } + +private: + InputStream& is_; + const SchemaDocumentType& sd_; + + ParseResult parseResult_; + PointerType invalidSchemaPointer_; + const Ch* invalidSchemaKeyword_; + PointerType invalidDocumentPointer_; + ValidateErrorCode invalidSchemaCode_; + StackAllocator allocator_; + ValueType error_; + bool isValid_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_SCHEMA_H_ diff --git a/src/utility/rapidjson/stream.h b/src/common/thirdparty/rapidjson/stream.h similarity index 79% rename from src/utility/rapidjson/stream.h rename to src/common/thirdparty/rapidjson/stream.h index fef82c252ff..1fd70915c54 100644 --- a/src/utility/rapidjson/stream.h +++ b/src/common/thirdparty/rapidjson/stream.h @@ -1,15 +1,15 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "rapidjson.h" @@ -100,6 +100,50 @@ inline void PutN(Stream& stream, Ch c, size_t n) { PutUnsafe(stream, c); } +/////////////////////////////////////////////////////////////////////////////// +// GenericStreamWrapper + +//! A Stream Wrapper +/*! \tThis string stream is a wrapper for any stream by just forwarding any + \treceived message to the origin stream. + \note implements Stream concept +*/ + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +template > +class GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + GenericStreamWrapper(InputStream& is): is_(is) {} + + Ch Peek() const { return is_.Peek(); } + Ch Take() { return is_.Take(); } + size_t Tell() { return is_.Tell(); } + Ch* PutBegin() { return is_.PutBegin(); } + void Put(Ch ch) { is_.Put(ch); } + void Flush() { is_.Flush(); } + size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } + + // wrapper for MemoryStream + const Ch* Peek4() const { return is_.Peek4(); } + + // wrapper for AutoUTFInputStream + UTFType GetType() const { return is_.GetType(); } + bool HasBOM() const { return is_.HasBOM(); } + +protected: + InputStream& is_; +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + /////////////////////////////////////////////////////////////////////////////// // StringStream diff --git a/src/utility/rapidjson/stringbuffer.h b/src/common/thirdparty/rapidjson/stringbuffer.h similarity index 94% rename from src/utility/rapidjson/stringbuffer.h rename to src/common/thirdparty/rapidjson/stringbuffer.h index 78f34d2098e..82ad3ca6bbf 100644 --- a/src/utility/rapidjson/stringbuffer.h +++ b/src/common/thirdparty/rapidjson/stringbuffer.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -78,8 +78,12 @@ class GenericStringBuffer { return stack_.template Bottom(); } + //! Get the size of string in bytes in the string buffer. size_t GetSize() const { return stack_.GetSize(); } + //! Get the length of string in Ch in the string buffer. + size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } + static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; diff --git a/src/common/thirdparty/rapidjson/uri.h b/src/common/thirdparty/rapidjson/uri.h new file mode 100644 index 00000000000..f93e508a4f4 --- /dev/null +++ b/src/common/thirdparty/rapidjson/uri.h @@ -0,0 +1,481 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// (C) Copyright IBM Corporation 2021 +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_URI_H_ +#define RAPIDJSON_URI_H_ + +#include "internal/strfunc.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// GenericUri + +template +class GenericUri { +public: + typedef typename ValueType::Ch Ch; +#if RAPIDJSON_HAS_STDSTRING + typedef std::basic_string String; +#endif + + //! Constructors + GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + } + + GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri, len); + } + + GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri, internal::StrLen(uri)); + } + + // Use with specializations of GenericValue + template GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + const Ch* u = uri.template Get(); // TypeHelper from document.h + Parse(u, internal::StrLen(u)); + } + +#if RAPIDJSON_HAS_STDSTRING + GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri.c_str(), internal::StrLen(uri.c_str())); + } +#endif + + //! Copy constructor + GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() { + *this = rhs; + } + + //! Copy constructor + GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + *this = rhs; + } + + //! Destructor. + ~GenericUri() { + Free(); + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Assignment operator + GenericUri& operator=(const GenericUri& rhs) { + if (this != &rhs) { + // Do not delete ownAllocator + Free(); + Allocate(rhs.GetStringLength()); + auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength()); + path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength()); + query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength()); + frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength()); + base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength()); + uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength()); + CopyPart(uri_, rhs.uri_, rhs.GetStringLength()); + } + return *this; + } + + //! Getters + // Use with specializations of GenericValue + template void Get(T& uri, Allocator& allocator) { + uri.template Set(this->GetString(), allocator); // TypeHelper from document.h + } + + const Ch* GetString() const { return uri_; } + SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen(uri_); } + const Ch* GetBaseString() const { return base_; } + SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen(base_); } + const Ch* GetSchemeString() const { return scheme_; } + SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen(scheme_); } + const Ch* GetAuthString() const { return auth_; } + SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen(auth_); } + const Ch* GetPathString() const { return path_; } + SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen(path_); } + const Ch* GetQueryString() const { return query_; } + SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen(query_); } + const Ch* GetFragString() const { return frag_; } + SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen(frag_); } + +#if RAPIDJSON_HAS_STDSTRING + static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); } + static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); } + static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); } + static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); } + static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); } + static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); } + static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); } +#endif + + //! Equality operators + bool operator==(const GenericUri& rhs) const { + return Match(rhs, true); + } + + bool operator!=(const GenericUri& rhs) const { + return !Match(rhs, true); + } + + bool Match(const GenericUri& uri, bool full = true) const { + Ch* s1; + Ch* s2; + if (full) { + s1 = uri_; + s2 = uri.uri_; + } else { + s1 = base_; + s2 = uri.base_; + } + if (s1 == s2) return true; + if (s1 == 0 || s2 == 0) return false; + return internal::StrCmp(s1, s2) == 0; + } + + //! Resolve this URI against another (base) URI in accordance with URI resolution rules. + // See https://tools.ietf.org/html/rfc3986 + // Use for resolving an id or $ref with an in-scope id. + // Returns a new GenericUri for the resolved URI. + GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) { + GenericUri resuri; + resuri.allocator_ = allocator; + // Ensure enough space for combining paths + resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash + + if (!(GetSchemeStringLength() == 0)) { + // Use all of this URI + resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength()); + resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + resuri.RemoveDotSegments(); + } else { + // Use the base scheme + resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength()); + if (!(GetAuthStringLength() == 0)) { + // Use this auth, path, query + resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + resuri.RemoveDotSegments(); + } else { + // Use the base auth + resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength()); + if (GetPathStringLength() == 0) { + // Use the base path + resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength()); + if (GetQueryStringLength() == 0) { + // Use the base query + resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength()); + } else { + // Use this query + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + } + } else { + if (path_[0] == '/') { + // Absolute path - use all of this path + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.RemoveDotSegments(); + } else { + // Relative path - append this path to base path after base path's last slash + size_t pos = 0; + if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) { + resuri.path_[pos] = '/'; + pos++; + } + size_t lastslashpos = baseuri.GetPathStringLength(); + while (lastslashpos > 0) { + if (baseuri.path_[lastslashpos - 1] == '/') break; + lastslashpos--; + } + std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch)); + pos += lastslashpos; + resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength()); + resuri.RemoveDotSegments(); + } + // Use this query + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + } + } + } + // Always use this frag + resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength()); + + // Re-constitute base_ and uri_ + resuri.SetBase(); + resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1; + resuri.SetUri(); + return resuri; + } + + //! Get the allocator of this GenericUri. + Allocator& GetAllocator() { return *allocator_; } + +private: + // Allocate memory for a URI + // Returns total amount allocated + std::size_t Allocate(std::size_t len) { + // Create own allocator if user did not supply. + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + // Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated. + // Order: scheme, auth, path, query, frag, base, uri + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + size_t total = (3 * len + 7) * sizeof(Ch); + scheme_ = static_cast(allocator_->Malloc(total)); + *scheme_ = '\0'; + auth_ = scheme_; + auth_++; + *auth_ = '\0'; + path_ = auth_; + path_++; + *path_ = '\0'; + query_ = path_; + query_++; + *query_ = '\0'; + frag_ = query_; + frag_++; + *frag_ = '\0'; + base_ = frag_; + base_++; + *base_ = '\0'; + uri_ = base_; + uri_++; + *uri_ = '\0'; + return total; + } + + // Free memory for a URI + void Free() { + if (scheme_) { + Allocator::Free(scheme_); + scheme_ = 0; + } + } + + // Parse a URI into constituent scheme, authority, path, query, & fragment parts + // Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per + // https://tools.ietf.org/html/rfc3986 + void Parse(const Ch* uri, std::size_t len) { + std::size_t start = 0, pos1 = 0, pos2 = 0; + Allocate(len); + + // Look for scheme ([^:/?#]+):)? + if (start < len) { + while (pos1 < len) { + if (uri[pos1] == ':') break; + pos1++; + } + if (pos1 != len) { + while (pos2 < len) { + if (uri[pos2] == '/') break; + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + if (pos1 < pos2) { + pos1++; + std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch)); + scheme_[pos1] = '\0'; + start = pos1; + } + } + } + // Look for auth (//([^/?#]*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + auth_ = scheme_ + GetSchemeStringLength(); + auth_++; + *auth_ = '\0'; + if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') { + pos2 = start + 2; + while (pos2 < len) { + if (uri[pos2] == '/') break; + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch)); + auth_[pos2 - start] = '\0'; + start = pos2; + } + // Look for path ([^?#]*) + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + path_ = auth_ + GetAuthStringLength(); + path_++; + *path_ = '\0'; + if (start < len) { + pos2 = start; + while (pos2 < len) { + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + if (start != pos2) { + std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch)); + path_[pos2 - start] = '\0'; + if (path_[0] == '/') + RemoveDotSegments(); // absolute path - normalize + start = pos2; + } + } + // Look for query (\?([^#]*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + query_ = path_ + GetPathStringLength(); + query_++; + *query_ = '\0'; + if (start < len && uri[start] == '?') { + pos2 = start + 1; + while (pos2 < len) { + if (uri[pos2] == '#') break; + pos2++; + } + if (start != pos2) { + std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch)); + query_[pos2 - start] = '\0'; + start = pos2; + } + } + // Look for fragment (#(.*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + frag_ = query_ + GetQueryStringLength(); + frag_++; + *frag_ = '\0'; + if (start < len && uri[start] == '#') { + std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch)); + frag_[len - start] = '\0'; + } + + // Re-constitute base_ and uri_ + base_ = frag_ + GetFragStringLength() + 1; + SetBase(); + uri_ = base_ + GetBaseStringLength() + 1; + SetUri(); + } + + // Reconstitute base + void SetBase() { + Ch* next = base_; + std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch)); + next+= GetSchemeStringLength(); + std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch)); + next+= GetAuthStringLength(); + std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch)); + next+= GetPathStringLength(); + std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch)); + next+= GetQueryStringLength(); + *next = '\0'; + } + + // Reconstitute uri + void SetUri() { + Ch* next = uri_; + std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch)); + next+= GetBaseStringLength(); + std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch)); + next+= GetFragStringLength(); + *next = '\0'; + } + + // Copy a part from one GenericUri to another + // Return the pointer to the next part to be copied to + Ch* CopyPart(Ch* to, Ch* from, std::size_t len) { + RAPIDJSON_ASSERT(to != 0); + RAPIDJSON_ASSERT(from != 0); + std::memcpy(to, from, len * sizeof(Ch)); + to[len] = '\0'; + Ch* next = to + len + 1; + return next; + } + + // Remove . and .. segments from the path_ member. + // https://tools.ietf.org/html/rfc3986 + // This is done in place as we are only removing segments. + void RemoveDotSegments() { + std::size_t pathlen = GetPathStringLength(); + std::size_t pathpos = 0; // Position in path_ + std::size_t newpos = 0; // Position in new path_ + + // Loop through each segment in original path_ + while (pathpos < pathlen) { + // Get next segment, bounded by '/' or end + size_t slashpos = 0; + while ((pathpos + slashpos) < pathlen) { + if (path_[pathpos + slashpos] == '/') break; + slashpos++; + } + // Check for .. and . segments + if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') { + // Backup a .. segment in the new path_ + // We expect to find a previously added slash at the end or nothing + RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/'); + size_t lastslashpos = newpos; + // Make sure we don't go beyond the start segment + if (lastslashpos > 1) { + // Find the next to last slash and back up to it + lastslashpos--; + while (lastslashpos > 0) { + if (path_[lastslashpos - 1] == '/') break; + lastslashpos--; + } + // Set the new path_ position + newpos = lastslashpos; + } + } else if (slashpos == 1 && path_[pathpos] == '.') { + // Discard . segment, leaves new path_ unchanged + } else { + // Move any other kind of segment to the new path_ + RAPIDJSON_ASSERT(newpos <= pathpos); + std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch)); + newpos += slashpos; + // Add slash if not at end + if ((pathpos + slashpos) < pathlen) { + path_[newpos] = '/'; + newpos++; + } + } + // Move to next segment + pathpos += slashpos + 1; + } + path_[newpos] = '\0'; + } + + Ch* uri_; // Everything + Ch* base_; // Everything except fragment + Ch* scheme_; // Includes the : + Ch* auth_; // Includes the // + Ch* path_; // Absolute if starts with / + Ch* query_; // Includes the ? + Ch* frag_; // Includes the # + + Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. + Allocator* ownAllocator_; //!< Allocator owned by this Uri. +}; + +//! GenericUri for Value (UTF-8, default allocator). +typedef GenericUri Uri; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_URI_H_ diff --git a/src/utility/rapidjson/writer.h b/src/common/thirdparty/rapidjson/writer.h similarity index 79% rename from src/utility/rapidjson/writer.h rename to src/common/thirdparty/rapidjson/writer.h index 200abadaeb2..bbc94497966 100644 --- a/src/utility/rapidjson/writer.h +++ b/src/common/thirdparty/rapidjson/writer.h @@ -1,6 +1,6 @@ // Tencent is pleased to support the open source community by making RapidJSON available. // -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at @@ -16,6 +16,8 @@ #define RAPIDJSON_WRITER_H_ #include "stream.h" +#include "internal/clzll.h" +#include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" #include "internal/dtoa.h" @@ -31,17 +33,18 @@ #include #elif defined(RAPIDJSON_SSE2) #include -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif RAPIDJSON_NAMESPACE_BEGIN @@ -103,6 +106,13 @@ class Writer { Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Writer(Writer&& rhs) : + os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { + rhs.os_ = 0; + } +#endif + //! Reset the writer with a new stream. /*! This function reset the writer with a new stream and default settings, @@ -211,10 +221,18 @@ class Writer { bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + bool EndObject(SizeType memberCount = 0) { (void)memberCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value level_stack_.template Pop(1); return EndValue(WriteEndObject()); } @@ -238,9 +256,9 @@ class Writer { //@{ //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } - + bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } + //@} //! Write a raw JSON value. @@ -257,6 +275,16 @@ class Writer { return EndValue(WriteRawValue(json, length)); } + //! Flush the output stream. + /*! + Allows the user to flush the output stream immediately. + */ + void Flush() { + os_->Flush(); + } + + static const size_t kDefaultLevelDepth = 32; + protected: //! Information for each nested level struct Level { @@ -265,8 +293,6 @@ class Writer { bool inArray; //!< true if in array, otherwise in object }; - static const size_t kDefaultLevelDepth = 32; - bool WriteNull() { PutReserve(*os_, 4); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; @@ -289,7 +315,7 @@ class Writer { const char* end = internal::i32toa(i, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -298,7 +324,7 @@ class Writer { const char* end = internal::u32toa(u, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -307,7 +333,7 @@ class Writer { const char* end = internal::i64toa(i64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -316,7 +342,7 @@ class Writer { char* end = internal::u64toa(u64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -352,12 +378,12 @@ class Writer { char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return ret; } bool WriteString(const Ch* str, SizeType length) { - static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F @@ -413,7 +439,7 @@ class Writer { else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { is.Take(); PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, static_cast(escape[static_cast(c)])); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); if (escape[static_cast(c)] == 'u') { PutUnsafe(*os_, '0'); PutUnsafe(*os_, '0'); @@ -441,9 +467,13 @@ class Writer { bool WriteRawValue(const Ch* json, size_t length) { PutReserve(*os_, length); - for (size_t i = 0; i < length; i++) { - RAPIDJSON_ASSERT(json[i] != '\0'); - PutUnsafe(*os_, json[i]); + GenericStringStream is(json); + while (RAPIDJSON_LIKELY(is.Tell() < length)) { + RAPIDJSON_ASSERT(is.Peek() != '\0'); + if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; } return true; } @@ -471,7 +501,7 @@ class Writer { // Flush the value if it is the top level one. bool EndValue(bool ret) { if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text - os_->Flush(); + Flush(); return ret; } @@ -522,37 +552,38 @@ inline bool Writer::WriteUint64(uint64_t u) { template<> inline bool Writer::WriteDouble(double d) { + bool ret = true; if (internal::Double(d).IsNanOrInf()) { // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). - if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) - { - // At least ensure that the output does not get broken. - PutReserve(*os_, 3); - PutUnsafe(*os_, '0'); - PutUnsafe(*os_, '.'); - PutUnsafe(*os_, '0'); - return false; - } - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); + if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) + { + // if we abort here, the writer is left in a broken state, unable to recover, so better write a 0 in addition to returning an error. + ret = false; + d = 0; } else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; + { + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } } char *buffer = os_->Push(25); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); os_->Pop(static_cast(25 - (end - buffer))); - return true; + return ret; } #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) @@ -582,7 +613,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -591,7 +622,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -616,15 +647,79 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } -#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +#elif defined(RAPIDJSON_NEON) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); -RAPIDJSON_NAMESPACE_END + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; -#ifdef __clang__ + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (; p != endAligned; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract + + SizeType len = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + uint32_t lz = internal::clzll(high); + len = 8 + (lz >> 3); + escaped = true; + } + } else { + uint32_t lz = internal::clzll(low); + len = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#endif // RAPIDJSON_NEON + +RAPIDJSON_NAMESPACE_END + +#if defined(_MSC_VER) || defined(__clang__) RAPIDJSON_DIAG_POP #endif diff --git a/src/common/thirdparty/richpresence.cpp b/src/common/thirdparty/richpresence.cpp new file mode 100644 index 00000000000..a8d8e81158c --- /dev/null +++ b/src/common/thirdparty/richpresence.cpp @@ -0,0 +1,129 @@ +/* +** richpresence.cpp +** +** handles rich presence for Discord. does nothing but transmit the appid, +** game, and current level. +** +**--------------------------------------------------------------------------- +** Copyright 2022 Rachael Alexanderson +** Copyright 2017 Discord +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include + +#include "common/engine/printf.h" +#include "discord_rpc.h" +#include "version.h" + +static int64_t StartTime = 0; +static bool didInit = false; + +static void handleDiscordReady(const DiscordUser* connectedUser) +{ + Printf("\nDiscord: connected to user %s#%s - %s\n", + connectedUser->username, + connectedUser->discriminator, + connectedUser->userId); +} + +static void handleDiscordDisconnected(int errcode, const char* message) +{ + Printf("\nDiscord: disconnected (%d: %s)\n", errcode, message); +} + +static void handleDiscordError(int errcode, const char* message) +{ + Printf("\nDiscord: error (%d: %s)\n", errcode, message); +} + +static void handleDiscordSpectate(const char* secret) +{ + Printf("\nDiscord: spectate (%s)\n", secret); +} + +static void handleDiscordJoin(const char* secret) +{ + Printf("\nDiscord: join (%s)\n", secret); +} + +static void handleDiscordJoinRequest(const DiscordUser* request) +{ + // we can't join in-game + int response = DISCORD_REPLY_NO; + Discord_Respond(request->userId, response); + Printf("\nDiscord: join request from %s#%s - %s\n", + request->username, + request->discriminator, + request->userId); +} + +void I_UpdateDiscordPresence(bool SendPresence, const char* curstatus, const char* appid, const char* steamappid) +{ + const char* curappid = DEFAULT_DISCORD_APP_ID; + + if (appid && appid[0] != '\0') + curappid = appid; + + if (!didInit && !SendPresence) + return; // we haven't initted, there's nothing to do here, just exit + + if (!didInit) + { + didInit = true; + DiscordEventHandlers handlers; + memset(&handlers, 0, sizeof(handlers)); + handlers.ready = handleDiscordReady; + handlers.disconnected = handleDiscordDisconnected; + handlers.errored = handleDiscordError; + handlers.joinGame = handleDiscordJoin; + handlers.spectateGame = handleDiscordSpectate; + handlers.joinRequest = handleDiscordJoinRequest; + Discord_Initialize(curappid, &handlers, 1, steamappid); + } + + if (SendPresence) + { + DiscordRichPresence discordPresence; + memset(&discordPresence, 0, sizeof(discordPresence)); + discordPresence.state = "Playing"; + if (!StartTime) + StartTime = time(0); + discordPresence.startTimestamp = StartTime; + discordPresence.details = curstatus; + discordPresence.largeImageKey = "game-image"; + discordPresence.instance = 0; + Discord_UpdatePresence(&discordPresence); + } + else + { + Discord_ClearPresence(); + } +} + diff --git a/src/utility/sfmt/LICENSE.txt b/src/common/thirdparty/sfmt/LICENSE.txt similarity index 100% rename from src/utility/sfmt/LICENSE.txt rename to src/common/thirdparty/sfmt/LICENSE.txt diff --git a/src/utility/sfmt/SFMT-alti.h b/src/common/thirdparty/sfmt/SFMT-alti.h similarity index 100% rename from src/utility/sfmt/SFMT-alti.h rename to src/common/thirdparty/sfmt/SFMT-alti.h diff --git a/src/utility/sfmt/SFMT-params.h b/src/common/thirdparty/sfmt/SFMT-params.h similarity index 100% rename from src/utility/sfmt/SFMT-params.h rename to src/common/thirdparty/sfmt/SFMT-params.h diff --git a/src/utility/sfmt/SFMT-params11213.h b/src/common/thirdparty/sfmt/SFMT-params11213.h similarity index 100% rename from src/utility/sfmt/SFMT-params11213.h rename to src/common/thirdparty/sfmt/SFMT-params11213.h diff --git a/src/utility/sfmt/SFMT-params1279.h b/src/common/thirdparty/sfmt/SFMT-params1279.h similarity index 100% rename from src/utility/sfmt/SFMT-params1279.h rename to src/common/thirdparty/sfmt/SFMT-params1279.h diff --git a/src/utility/sfmt/SFMT-params132049.h b/src/common/thirdparty/sfmt/SFMT-params132049.h similarity index 100% rename from src/utility/sfmt/SFMT-params132049.h rename to src/common/thirdparty/sfmt/SFMT-params132049.h diff --git a/src/utility/sfmt/SFMT-params19937.h b/src/common/thirdparty/sfmt/SFMT-params19937.h similarity index 100% rename from src/utility/sfmt/SFMT-params19937.h rename to src/common/thirdparty/sfmt/SFMT-params19937.h diff --git a/src/utility/sfmt/SFMT-params216091.h b/src/common/thirdparty/sfmt/SFMT-params216091.h similarity index 100% rename from src/utility/sfmt/SFMT-params216091.h rename to src/common/thirdparty/sfmt/SFMT-params216091.h diff --git a/src/utility/sfmt/SFMT-params2281.h b/src/common/thirdparty/sfmt/SFMT-params2281.h similarity index 100% rename from src/utility/sfmt/SFMT-params2281.h rename to src/common/thirdparty/sfmt/SFMT-params2281.h diff --git a/src/utility/sfmt/SFMT-params4253.h b/src/common/thirdparty/sfmt/SFMT-params4253.h similarity index 100% rename from src/utility/sfmt/SFMT-params4253.h rename to src/common/thirdparty/sfmt/SFMT-params4253.h diff --git a/src/utility/sfmt/SFMT-params44497.h b/src/common/thirdparty/sfmt/SFMT-params44497.h similarity index 100% rename from src/utility/sfmt/SFMT-params44497.h rename to src/common/thirdparty/sfmt/SFMT-params44497.h diff --git a/src/utility/sfmt/SFMT-params607.h b/src/common/thirdparty/sfmt/SFMT-params607.h similarity index 100% rename from src/utility/sfmt/SFMT-params607.h rename to src/common/thirdparty/sfmt/SFMT-params607.h diff --git a/src/utility/sfmt/SFMT-params86243.h b/src/common/thirdparty/sfmt/SFMT-params86243.h similarity index 100% rename from src/utility/sfmt/SFMT-params86243.h rename to src/common/thirdparty/sfmt/SFMT-params86243.h diff --git a/src/utility/sfmt/SFMT-sse2.h b/src/common/thirdparty/sfmt/SFMT-sse2.h similarity index 100% rename from src/utility/sfmt/SFMT-sse2.h rename to src/common/thirdparty/sfmt/SFMT-sse2.h diff --git a/src/utility/sfmt/SFMT.cpp b/src/common/thirdparty/sfmt/SFMT.cpp similarity index 97% rename from src/utility/sfmt/SFMT.cpp rename to src/common/thirdparty/sfmt/SFMT.cpp index 102497a8c04..ccfd61a2921 100644 --- a/src/utility/sfmt/SFMT.cpp +++ b/src/common/thirdparty/sfmt/SFMT.cpp @@ -12,7 +12,7 @@ */ #include #include -#include "m_random.h" +#include "SFMTObj.h" #include "SFMT-params.h" #if defined(__BIG_ENDIAN__) && !defined(__amd64) && !defined(BIG_ENDIAN64) @@ -201,7 +201,7 @@ inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c, * This function fills the internal state array with pseudorandom * integers. */ -void FRandom::GenRandAll() +void SFMTObj::GenRandAll() { int i; w128_t *r1, *r2; @@ -227,7 +227,7 @@ void FRandom::GenRandAll() * @param array an 128-bit array to be filled by pseudorandom numbers. * @param size number of 128-bit pseudorandom numbers to be generated. */ -void FRandom::GenRandArray(w128_t *array, int size) +void SFMTObj::GenRandArray(w128_t *array, int size) { int i, j; w128_t *r1, *r2; @@ -301,7 +301,7 @@ static uint32_t func2(uint32_t x) /** * This function certificate the period of 2^{MEXP} */ -void FRandom::PeriodCertification() +void SFMTObj::PeriodCertification() { int inner = 0; int i, j; @@ -337,7 +337,7 @@ PUBLIC FUNCTIONS * fill_array32() function. * @return minimum size of array used for FillArray32() function. */ -int FRandom::GetMinArraySize32() +int SFMTObj::GetMinArraySize32() { return SFMT::N32; } @@ -347,7 +347,7 @@ int FRandom::GetMinArraySize32() * fill_array64() function. * @return minimum size of array used for FillArray64() function. */ -int FRandom::GetMinArraySize64() +int SFMTObj::GetMinArraySize64() { return SFMT::N64; } @@ -358,7 +358,7 @@ int FRandom::GetMinArraySize64() * init_gen_rand or init_by_array must be called before this function. * @return 32-bit pseudorandom number */ -unsigned int FRandom::GenRand32() +unsigned int SFMTObj::GenRand32() { uint32_t r; @@ -379,7 +379,7 @@ unsigned int FRandom::GenRand32() * unless an initialization is again executed. * @return 64-bit pseudorandom number */ -uint64_t FRandom::GenRand64() +uint64_t SFMTObj::GenRand64() { #if defined(BIG_ENDIAN64) && !defined(ONLY64) uint32_t r1, r2; @@ -433,7 +433,7 @@ uint64_t FRandom::GenRand64() * memory. Mac OSX doesn't have these functions, but \b malloc of OSX * returns the pointer to the aligned memory block. */ -void FRandom::FillArray32(uint32_t *array, int size) +void SFMTObj::FillArray32(uint32_t *array, int size) { assert(initialized); assert(idx == SFMT::N32); @@ -470,7 +470,7 @@ void FRandom::FillArray32(uint32_t *array, int size) * memory. Mac OSX doesn't have these functions, but \b malloc of OSX * returns the pointer to the aligned memory block. */ -void FRandom::FillArray64(uint64_t *array, int size) +void SFMTObj::FillArray64(uint64_t *array, int size) { assert(initialized); assert(idx == SFMT::N32); @@ -491,7 +491,7 @@ void FRandom::FillArray64(uint64_t *array, int size) * * @param seed a 32-bit integer used as the seed. */ -void FRandom::InitGenRand(uint32_t seed) +void SFMTObj::InitGenRand(uint32_t seed) { int i; @@ -515,7 +515,7 @@ void FRandom::InitGenRand(uint32_t seed) * @param init_key the array of 32-bit integers, used as a seed. * @param key_length the length of init_key. */ -void FRandom::InitByArray(uint32_t *init_key, int key_length) +void SFMTObj::InitByArray(uint32_t *init_key, int key_length) { int i, j, count; uint32_t r; diff --git a/src/utility/sfmt/SFMT.h b/src/common/thirdparty/sfmt/SFMT.h similarity index 99% rename from src/utility/sfmt/SFMT.h rename to src/common/thirdparty/sfmt/SFMT.h index ddaabf2461f..b7d3c42f371 100644 --- a/src/utility/sfmt/SFMT.h +++ b/src/common/thirdparty/sfmt/SFMT.h @@ -28,6 +28,8 @@ * unsigned int and 64-bit unsigned int in hexadecimal format. */ +#include + #ifndef SFMT_H #define SFMT_H diff --git a/src/common/thirdparty/sfmt/SFMTObj.h b/src/common/thirdparty/sfmt/SFMTObj.h new file mode 100644 index 00000000000..3b85ab939d0 --- /dev/null +++ b/src/common/thirdparty/sfmt/SFMTObj.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include "SFMT.h" + +struct SFMTObj +{ + void Init(uint32_t seed1, uint32_t seed2) + { + uint32_t seeds[2] = { seed1, seed2 }; + InitByArray(seeds, 2); + } + void GenRandAll(); + void GenRandArray(w128_t *array, int size); + void PeriodCertification(); + int GetMinArraySize32(); + int GetMinArraySize64(); + unsigned int GenRand32(); + uint64_t GenRand64(); + void FillArray32(uint32_t *array, int size); + void FillArray64(uint64_t *array, int size); + void InitGenRand(uint32_t seed); + void InitByArray(uint32_t *init_key, int key_length); + +protected: + + /** index counter to the 32-bit internal state array */ + int idx; + + /** the 128-bit internal state array */ + union + { + w128_t w128[SFMT::N]; + unsigned int u[SFMT::N32]; + uint64_t u64[SFMT::N64]; + } sfmt; + + /** a flag: it is 0 if and only if the internal state is not yet + * initialized. */ +#ifndef NDEBUG + bool initialized = false; +#endif + +}; \ No newline at end of file diff --git a/src/gamedata/textures/formats/stb_image.h b/src/common/thirdparty/stb/stb_image.h similarity index 89% rename from src/gamedata/textures/formats/stb_image.h rename to src/common/thirdparty/stb/stb_image.h index 196dfd5cc6e..5e807a0a6e7 100644 --- a/src/gamedata/textures/formats/stb_image.h +++ b/src/common/thirdparty/stb/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.23 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,10 +48,15 @@ LICENSE RECENT REVISION HISTORY: + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically 2.23 (2019-08-11) fix clang static analysis warning 2.22 (2019-03-04) gif fixes, fix warnings 2.21 (2019-02-25) fix typo in comment - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings @@ -86,26 +91,37 @@ RECENT REVISION HISTORY: Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine + Arseny Kapoulkine Simon Breuss (16-bit PNM) John-Mark Allen Carmelo J Fdez-Aguera Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan - Dave Moore Roy Eltham Hayaki Saito Nathan Reed - Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar - Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex - Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 - Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw - Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus - Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo - Christian Floisand Kevin Schmidt JR Smith github:darealshinji - Blazej Dariusz Roszkowski github:Michaelangel007 + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -125,7 +141,7 @@ RECENT REVISION HISTORY: // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) +// stbi_image_free(data); // // Standard parameters: // int *x -- outputs image width in pixels @@ -164,6 +180,32 @@ RECENT REVISION HISTORY: // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// // =========================================================================== // // UNICODE: @@ -269,11 +311,10 @@ RECENT REVISION HISTORY: // // iPhone PNG support: // -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). // // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // pixel to remove any premultiplied alpha *only* if the image file explicitly @@ -315,7 +356,14 @@ RECENT REVISION HISTORY: // - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still // want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB // - +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. #ifndef STBI_NO_STDIO #include @@ -434,7 +482,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f); // get a VERY brief reason for failure -// NOT THREADSAFE +// on most compilers (and ALL modern mainstream compilers) this is threadsafe STBIDEF const char *stbi_failure_reason (void); // free the loaded image -- this is just free() @@ -467,6 +515,13 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); // flip the image vertically, so the first pixel in the output array is the bottom left STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + // ZLIB client - used by PNG, available for other purposes STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); @@ -563,8 +618,25 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define stbi_inline __forceinline #endif +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif -#ifdef _MSC_VER + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if defined(_MSC_VER) || defined(__SYMBIAN32__) typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; @@ -593,7 +665,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef STBI_HAS_LROTL #define stbi_lrot(x,y) _lrotl(x,y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -707,14 +779,21 @@ static int stbi__sse2_available(void) #ifdef STBI_NEON #include -// assume GCC or Clang on ARM targets +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #endif +#endif #ifndef STBI_SIMD_ALIGN #define STBI_SIMD_ALIGN(type, name) type name #endif +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + /////////////////////////////////////////////// // // stbi__context struct and start_xxx functions @@ -732,6 +811,7 @@ typedef struct int read_from_callbacks; int buflen; stbi_uc buffer_start[128]; + int callback_already_read; stbi_uc *img_buffer, *img_buffer_end; stbi_uc *img_buffer_original, *img_buffer_original_end; @@ -745,6 +825,7 @@ static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) { s->io.read = NULL; s->read_from_callbacks = 0; + s->callback_already_read = 0; s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; } @@ -756,7 +837,8 @@ static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void * s->io_user_data = user; s->buflen = sizeof(s->buffer_start); s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; stbi__refill_buffer(s); s->img_buffer_original_end = s->img_buffer_end; } @@ -770,12 +852,17 @@ static int stbi__stdio_read(void *user, char *data, int size) static void stbi__stdio_skip(void *user, int n) { + int ch; fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } } static int stbi__stdio_eof(void *user) { - return feof((FILE*) user); + return feof((FILE*) user) || ferror((FILE *) user); } static stbi_io_callbacks stbi__stdio_callbacks = @@ -871,21 +958,27 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__pnm_test(stbi__context *s); static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); #endif -// this is not threadsafe -static const char *stbi__g_failure_reason; +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } +#ifndef STBI_NO_FAILURE_STRINGS static int stbi__err(const char *str) { stbi__g_failure_reason = str; return 0; } +#endif static void *stbi__malloc(size_t size) { @@ -924,11 +1017,13 @@ static int stbi__mul2sizes_valid(int a, int b) return a <= INT_MAX/b; } +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow static int stbi__mad2sizes_valid(int a, int b, int add) { return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); } +#endif // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow static int stbi__mad3sizes_valid(int a, int b, int c, int add) @@ -938,7 +1033,7 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add) } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && @@ -946,12 +1041,14 @@ static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) } #endif +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // mallocs with size overflow checking static void *stbi__malloc_mad2(int a, int b, int add) { if (!stbi__mad2sizes_valid(a, b, add)) return NULL; return stbi__malloc(a*b + add); } +#endif static void *stbi__malloc_mad3(int a, int b, int c, int add) { @@ -959,7 +1056,7 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add) return stbi__malloc(a*b*c + add); } -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; @@ -967,6 +1064,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) } #endif +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two signed shorts is valid, 0 on overflow. +static int stbi__mul2shorts_valid(short a, short b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -995,13 +1109,29 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif -static int stbi__vertically_flip_on_load = 0; +static int stbi__vertically_flip_on_load_global = 0; STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { - stbi__vertically_flip_on_load = flag_true_if_should_flip; + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; } +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields @@ -1009,9 +1139,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order ri->num_channels = 0; - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) #ifndef STBI_NO_PNG if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif @@ -1023,10 +1152,19 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #endif #ifndef STBI_NO_PSD if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); #endif #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif #ifndef STBI_NO_PNM if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif @@ -1111,8 +1249,8 @@ static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int byt stbi_uc *bytes = (stbi_uc *)image; for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; } } #endif @@ -1125,8 +1263,10 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, if (result == NULL) return NULL; + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + if (ri.bits_per_channel != 8) { - STBI_ASSERT(ri.bits_per_channel == 16); result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 8; } @@ -1149,8 +1289,10 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, if (result == NULL) return NULL; + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + if (ri.bits_per_channel != 16) { - STBI_ASSERT(ri.bits_per_channel == 8); result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 16; } @@ -1178,12 +1320,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in #ifndef STBI_NO_STDIO -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); #endif -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); @@ -1193,16 +1335,16 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; - - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; -#if _MSC_VER >= 1400 +#if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else @@ -1300,15 +1442,15 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); - + stbi__context s; + stbi__start_mem(&s,buffer,len); + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); } - return result; + return result; } #endif @@ -1453,6 +1595,7 @@ enum static void stbi__refill_buffer(stbi__context *s) { int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); if (n == 0) { // at end of file, treat same as if from memory, but need to handle case // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file @@ -1477,6 +1620,9 @@ stbi_inline static stbi_uc stbi__get8(stbi__context *s) return 0; } +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else stbi_inline static int stbi__at_eof(stbi__context *s) { if (s->io.read) { @@ -1488,9 +1634,14 @@ stbi_inline static int stbi__at_eof(stbi__context *s) return s->img_buffer >= s->img_buffer_end; } +#endif +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else static void stbi__skip(stbi__context *s, int n) { + if (n == 0) return; // already there! if (n < 0) { s->img_buffer = s->img_buffer_end; return; @@ -1505,7 +1656,11 @@ static void stbi__skip(stbi__context *s, int n) } s->img_buffer += n; } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { if (s->io.read) { @@ -1529,18 +1684,27 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) } else return 0; } +#endif +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else static int stbi__get16be(stbi__context *s) { int z = stbi__get8(s); return (z << 8) + stbi__get8(s); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else static stbi__uint32 stbi__get32be(stbi__context *s) { stbi__uint32 z = stbi__get16be(s); return (z << 16) + stbi__get16be(s); } +#endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing @@ -1556,13 +1720,16 @@ static int stbi__get16le(stbi__context *s) static stbi__uint32 stbi__get32le(stbi__context *s) { stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; } #endif #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else ////////////////////////////////////////////////////////////////////////////// // // generic converter from built-in img_n to req_comp @@ -1578,7 +1745,11 @@ static stbi_uc stbi__compute_y(int r, int g, int b) { return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1614,7 +1785,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } @@ -1622,12 +1793,20 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r STBI_FREE(data); return good; } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1663,7 +1842,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } @@ -1671,6 +1850,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r STBI_FREE(data); return good; } +#endif #ifndef STBI_NO_LINEAR static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) @@ -1823,9 +2003,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) int i,j,k=0; unsigned int code; // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } h->size[k] = 0; // compute actual symbols (from jpeg spec) @@ -1950,6 +2133,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol @@ -1968,14 +2153,14 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) unsigned int k; int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); - STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); + return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits @@ -1983,6 +2168,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { unsigned int k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; @@ -1994,6 +2180,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { unsigned int k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing k = j->code_buffer; j->code_buffer <<= 1; --j->code_bits; @@ -2025,14 +2212,16 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); // 0 all the ac values now so we can do it 32-bits at a time memset(data,0,64*sizeof(data[0])); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * dequant[0]); // decode AC components, see JPEG spec @@ -2046,6 +2235,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; // decode into unzigzag'd location @@ -2082,11 +2272,14 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ // first scan for DC coefficient, must be first memset(data,0,64*sizeof(data[0])); // 0 all the ac values now t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient if (stbi__jpeg_get_bit(j)) @@ -2120,10 +2313,11 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); + data[zig] = (short) ((r >> 8) * (1 << shift)); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); @@ -2141,7 +2335,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ } else { k += r; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); } } } while (k <= j->spec_end); @@ -2940,6 +3134,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m) sizes[i] = stbi__get8(z->s); n += sizes[i]; } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! L -= 17; if (tc == 0) { if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; @@ -3072,6 +3267,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); c = stbi__get8(s); if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); s->img_n = c; @@ -3103,6 +3300,13 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; } + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + // compute interleaved mcu info z->img_h_max = h_max; z->img_v_max = v_max; @@ -3180,6 +3384,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) return 1; } +static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + while (x == 255) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + // decode image to YCbCr format static int stbi__decode_jpeg_image(stbi__jpeg *j) { @@ -3196,25 +3422,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (!stbi__process_scan_header(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0; if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } + j->marker = stbi__skip_jpeg_junk_at_end(j); // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); } else if (stbi__DNL(m)) { int Ld = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); } else { - if (!stbi__process_marker(j, m)) return 0; + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); } - m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); @@ -3658,6 +3881,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp else decode_n = z->s->img_n; + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + // resample and color-convert { int k; @@ -3800,6 +4027,8 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -3812,6 +4041,8 @@ static int stbi__jpeg_test(stbi__context *s) { int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -3836,6 +4067,8 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -3855,6 +4088,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) // fast-way is faster to check than jpeg huffman, but slow way is slower #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) @@ -3864,8 +4098,8 @@ typedef struct stbi__uint16 firstcode[16]; int maxcode[17]; stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) @@ -3952,16 +4186,23 @@ typedef struct stbi__zhuffman z_length, z_distance; } stbi__zbuf; +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) { - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; + return stbi__zeof(z) ? 0 : *z->zbuffer++; } static void stbi__fill_bits(stbi__zbuf *z) { do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); @@ -3986,10 +4227,11 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) for (s=STBI__ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; - if (s == 16) return -1; // invalid code! + if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. a->code_buffer >>= s; a->num_bits -= s; return z->value[b]; @@ -3998,7 +4240,12 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) { int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { s = b >> 9; @@ -4012,13 +4259,16 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { char *q; - int cur, limit, old_limit; + unsigned int cur, limit, old_limit; z->zout = zout; if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = old_limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); limit *= 2; + } q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); STBI_NOTUSED(old_limit); if (q == NULL) return stbi__err("outofmem", "Out of memory"); @@ -4061,11 +4311,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) a->zout = zout; return 1; } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); @@ -4116,11 +4367,12 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) c = stbi__zreceive(a,2)+3; if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); fill = lencodes[n-1]; - } else if (c == 17) + } else if (c == 17) { c = stbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); + } else if (c == 18) { c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); } if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); memset(lencodes+n, fill, c); @@ -4146,7 +4398,7 @@ static int stbi__parse_uncompressed_block(stbi__zbuf *a) a->code_buffer >>= 8; a->num_bits -= 8; } - STBI_ASSERT(a->num_bits == 0); + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); // now fill header the normal way while (k < 4) header[k++] = stbi__zget8(a); @@ -4168,6 +4420,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) int cm = cmf & 15; /* int cinfo = cmf >> 4; */ int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png @@ -4175,7 +4428,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) return 1; } -static const stbi_uc stbi__zdefault_length[288] = +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, @@ -4221,7 +4474,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) } else { if (type == 1) { // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { if (!stbi__compute_huffman_codes(a)) return 0; @@ -4429,7 +4682,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r return stbi__err("invalid filter","Corrupt PNG"); if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place filter_bytes = 1; width = img_width_bytes; @@ -4617,6 +4870,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 // de-interlacing final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4737,19 +4991,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { - stbi__de_iphone_flag = flag_true_if_should_convert; + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; } +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + static void stbi__de_iphone(stbi__png *z) { stbi__context *s = z->s; @@ -4824,8 +5105,10 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); first = 0; if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); @@ -4837,14 +5120,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS } + // even with SCAN_header, have to scan to see if we have a tRNS break; } @@ -4876,6 +5158,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } if (z->depth == 16) { for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { @@ -4888,7 +5172,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; @@ -4942,6 +5232,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); return 1; } @@ -4972,10 +5264,12 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st void *result=NULL; if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) + if (p->depth <= 8) ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; else - ri->bits_per_channel = p->depth; + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { @@ -5111,7 +5405,7 @@ static int stbi__shiftsigned(unsigned int v, int shift, int bits) v <<= -shift; else v >>= shift; - STBI_ASSERT(v >= 0 && v < 256); + STBI_ASSERT(v < 256); v >>= (8-bits); STBI_ASSERT(bits >= 0 && bits <= 8); return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; @@ -5121,8 +5415,35 @@ typedef struct { int bpp, offset, hsz; unsigned int mr,mg,mb,ma, all_a; + int extra_read; } stbi__bmp_data; +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { int hsz; @@ -5133,6 +5454,9 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->offset = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s); info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz == 12) { @@ -5147,6 +5471,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard hres stbi__get32le(s); // discard vres @@ -5161,21 +5487,12 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (info->bpp == 16 || info->bpp == 32) { if (compress == 0) { - if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } + stbi__bmp_set_mask_defaults(info, compress); } else if (compress == 3) { info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); + info->extra_read += 12; // not documented, but generated by photoshop and handled by mspaint if (info->mr == info->mg && info->mg == info->mb) { // ?!?!? @@ -5185,6 +5502,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) return stbi__errpuc("bad BMP", "bad BMP"); } } else { + // V4/V5 header int i; if (hsz != 108 && hsz != 124) return stbi__errpuc("bad BMP", "bad BMP"); @@ -5192,6 +5510,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); stbi__get32le(s); // discard color space for (i=0; i < 12; ++i) stbi__get32le(s); // discard color space parameters @@ -5224,6 +5544,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req flip_vertically = ((int) s->img_y) > 0; s->img_y = abs((int) s->img_y); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + mr = info.mr; mg = info.mg; mb = info.mb; @@ -5232,10 +5555,29 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz == 12) { if (info.bpp < 24) - psize = (info.offset - 14 - 24) / 3; + psize = (info.offset - info.extra_read - 24) / 3; } else { if (info.bpp < 16) - psize = (info.offset - 14 - info.hsz) >> 2; + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } } if (info.bpp == 24 && ma == 0xff000000) @@ -5263,7 +5605,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz != 12) stbi__get8(s); pal[i][3] = 255; } - stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); if (info.bpp == 1) width = (s->img_x + 7) >> 3; else if (info.bpp == 4) width = (s->img_x + 1) >> 1; else if (info.bpp == 8) width = s->img_x; @@ -5312,7 +5654,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int z = 0; int easy=0; - stbi__skip(s, info.offset - 14 - info.hsz); + stbi__skip(s, info.offset - info.extra_read - info.hsz); if (info.bpp == 24) width = 3 * s->img_x; else if (info.bpp == 16) width = 2*s->img_x; else /* bpp = 32 and pad = 0 */ width=0; @@ -5330,6 +5672,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } } for (j=0; j < (int) s->img_y; ++j) { if (easy) { @@ -5554,6 +5897,9 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req STBI_NOTUSED(tga_x_origin); // @TODO STBI_NOTUSED(tga_y_origin); // @TODO + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + // do a tiny bit of precessing if ( tga_image_type >= 8 ) { @@ -5593,6 +5939,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // do I need to load a palette? if ( tga_indexed) { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + // any data to skip? (offset usually = 0) stbi__skip(s, tga_palette_start ); // load the palette @@ -5801,6 +6152,9 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req h = stbi__get32be(s); w = stbi__get32be(s); + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + // Make sure the depth is 8 bits. bitdepth = stbi__get16be(s); if (bitdepth != 8 && bitdepth != 16) @@ -6155,6 +6509,10 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c x = stbi__get16be(s); y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); @@ -6164,6 +6522,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c // intermediate buffer is RGBA result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -6202,7 +6561,7 @@ typedef struct int w,h; stbi_uc *out; // output buffer (always 4 components) stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; + stbi_uc *history; int flags, bgindex, ratio, transparent, eflags; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; @@ -6263,6 +6622,9 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in g->ratio = stbi__get8(s); g->transparent = -1; + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments if (is_info) return 1; @@ -6276,6 +6638,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); if (!stbi__gif_header(s, g, comp, 1)) { STBI_FREE(g); stbi__rewind( s ); @@ -6290,7 +6653,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; - int idx; + int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty @@ -6299,12 +6662,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) if (g->cur_y >= g->max_y) return; - idx = g->cur_x + g->cur_y; + idx = g->cur_x + g->cur_y; p = &g->out[idx]; - g->history[idx / 4] = 1; + g->history[idx / 4] = 1; c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; + if (c[3] > 128) { // don't render transparent pixels; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; @@ -6413,14 +6776,14 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) // two back is the image from two frames ago, used for a very specific disposal format static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { - int dispose; - int first_frame; - int pi; - int pcount; + int dispose; + int first_frame; + int pi; + int pcount; STBI_NOTUSED(req_comp); // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; + first_frame = 0; if (g->out == 0) { if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) @@ -6432,17 +6795,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (!g->out || !g->background || !g->history) return stbi__errpuc("outofmem", "Out of memory"); - // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to the color that was there the previous frame. + // color refers to the color that was there the previous frame. memset(g->out, 0x00, 4 * pcount); memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) memset(g->history, 0x00, pcount); // pixels that were affected previous frame - first_frame = 1; + first_frame = 1; } else { - // second frame - how do we dispoase of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; if ((dispose == 3) && (two_back == 0)) { dispose = 2; // if I don't have an image to revert back to, default to the old background @@ -6451,32 +6814,32 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (dispose == 3) { // use previous graphic for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); } } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); } } } else { - // This is a non-disposal case eithe way, so just + // This is a non-disposal case eithe way, so just // leave the pixels as is, and they will become the new background // 1: do not dispose // 0: not specified. } - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); } - // clear my history; + // clear my history; memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame for (;;) { - int tag = stbi__get8(s); + int tag = stbi__get8(s); switch (tag) { case 0x2C: /* Image Descriptor */ { @@ -6521,19 +6884,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } else if (g->flags & 0x80) { g->color_table = (stbi_uc *) g->pal; } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - + return stbi__errpuc("missing color table", "Corrupt GIF"); + o = stbi__process_gif_raster(s, g); if (!o) return NULL; - // if this was the first frame, - pcount = g->w * g->h; + // if this was the first frame, + pcount = g->w * g->h; if (first_frame && (g->bgindex > 0)) { // if first frame, any pixel not drawn to gets the background color for (pi = 0; pi < pcount; ++pi) { if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); } } } @@ -6544,7 +6907,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i case 0x21: // Comment Extension. { int len; - int ext = stbi__get8(s); + int ext = stbi__get8(s); if (ext == 0xF9) { // Graphic Control Extension. len = stbi__get8(s); if (len == 4) { @@ -6553,23 +6916,23 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i // unset old transparent if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } + g->pal[g->transparent][3] = 255; + } if (g->eflags & 0x01) { g->transparent = stbi__get8(s); if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; + g->pal[g->transparent][3] = 0; } } else { // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; + stbi__skip(s, 1); + g->transparent = -1; } } else { stbi__skip(s, len); break; } - } + } while ((len = stbi__get8(s)) != 0) { stbi__skip(s, len); } @@ -6585,18 +6948,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } } +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { - int layers = 0; + int layers = 0; stbi_uc *u = 0; stbi_uc *out = 0; - stbi_uc *two_back = 0; + stbi_uc *two_back = 0; stbi__gif g; - int stride; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + memset(&g, 0, sizeof(g)); if (delays) { - *delays = 0; + *delays = 0; } do { @@ -6606,44 +6986,61 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, if (u) { *x = g.w; *y = g.h; - ++layers; - stride = g.w * g.h * 4; - + ++layers; + stride = g.w * g.h * 4; + if (out) { - out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); } } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); } } - memcpy( out + ((layers - 1) * stride), u, stride ); + memcpy( out + ((layers - 1) * stride), u, stride ); if (layers >= 2) { - two_back = out - 2 * stride; + two_back = out - 2 * stride; } if (delays) { - (*delays)[layers - 1U] = g.delay; + (*delays)[layers - 1U] = g.delay; } } - } while (u != 0); + } while (u != 0); - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); - // do the final conversion after loading everything; + // do the final conversion after loading everything; if (req_comp && req_comp != 4) out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - *z = layers; + *z = layers; return out; } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); + return stbi__errpuc("not GIF", "Image was not as a gif type."); } } @@ -6661,7 +7058,7 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req *y = g.h; // moved conversion to after successful load so that the same - // can be done for multiple frames. + // can be done for multiple frames. if (req_comp && req_comp != 4) u = stbi__convert_format(u, 4, req_comp, g.w, g.h); } else if (g.out) { @@ -6669,9 +7066,9 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req STBI_FREE(g.out); } - // free buffers needed for multiple frame loading; + // free buffers needed for multiple frame loading; STBI_FREE(g.history); - STBI_FREE(g.background); + STBI_FREE(g.background); return u; } @@ -6796,6 +7193,9 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re token += 3; width = (int) strtol(token, NULL, 10); + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + *x = width; *y = height; @@ -6864,12 +7264,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re // Run value = stbi__get8(s); count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -6938,9 +7338,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) info.all_a = 255; p = stbi__bmp_parse_header(s, &info); - stbi__rewind( s ); - if (p == NULL) + if (p == NULL) { + stbi__rewind( s ); return 0; + } if (x) *x = s->img_x; if (y) *y = s->img_y; if (comp) { @@ -7006,8 +7407,8 @@ static int stbi__psd_is16(stbi__context *s) stbi__rewind( s ); return 0; } - (void) stbi__get32be(s); - (void) stbi__get32be(s); + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); depth = stbi__get16be(s); if (depth != 16) { stbi__rewind( s ); @@ -7086,7 +7487,6 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) // Known limitations: // Does not support comments in the header section // Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel #ifndef STBI_NO_PNM @@ -7107,22 +7507,33 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *out; STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) return 0; + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + *x = s->img_x; *y = s->img_y; if (comp) *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; @@ -7159,6 +7570,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); } return value; @@ -7189,17 +7602,29 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; else - return 1; + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; } #endif @@ -7255,6 +7680,9 @@ static int stbi__is_16_main(stbi__context *s) if (stbi__psd_is16(s)) return 1; #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif return 0; } @@ -7334,7 +7762,7 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user /* revision history: - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug diff --git a/src/common/thirdparty/stb/stb_sprintf.c b/src/common/thirdparty/stb/stb_sprintf.c new file mode 100644 index 00000000000..948362c3b8e --- /dev/null +++ b/src/common/thirdparty/stb/stb_sprintf.c @@ -0,0 +1,21 @@ +#define STB_SPRINTF_IMPLEMENTATION +#define STB_SPRINTF_UTF8_CHARS +#include "stb_sprintf.h" + +// We still need our own wrappers because they use a size_t for count, not an int. +int mysnprintf(char* buf, size_t count, char const* fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + + result = stbsp_vsnprintf(buf, (int)count, fmt, va); + va_end(va); + + return result; +} + +int myvsnprintf(char* buf, size_t count, const char* fmt, va_list va) +{ + return stbsp_vsnprintf(buf, (int)count, fmt, va); +} diff --git a/src/common/thirdparty/stb/stb_sprintf.h b/src/common/thirdparty/stb/stb_sprintf.h new file mode 100644 index 00000000000..ee4a601f88a --- /dev/null +++ b/src/common/thirdparty/stb/stb_sprintf.h @@ -0,0 +1,1947 @@ +// stb_sprintf - v1.10 - public domain snprintf() implementation +// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 +// http://github.com/nothings/stb +// +// allowed types: sc uidBboXx p AaGgEef n +// lengths : hh h ll j z t I64 I32 I +// +// Contributors: +// Fabian "ryg" Giesen (reformatting) +// github:aganm (attribute format) +// +// Contributors (bugfixes): +// github:d26435 +// github:trex78 +// github:account-login +// Jari Komppa (SI suffixes) +// Rohit Nirmal +// Marcin Wojdyr +// Leonard Ritter +// Stefano Zanotti +// Adam Allison +// Arvid Gerstmann +// Markus Kolb +// +// LICENSE: +// +// See end of file for license information. + +#ifndef STB_SPRINTF_H_INCLUDE +#define STB_SPRINTF_H_INCLUDE + +/* +Single file sprintf replacement. + +Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. +Hereby placed in public domain. + +This is a full sprintf replacement that supports everything that +the C runtime sprintfs support, including float/double, 64-bit integers, +hex floats, field parameters (%*.*d stuff), length reads backs, etc. + +Why would you need this if sprintf already exists? Well, first off, +it's *much* faster (see below). It's also much smaller than the CRT +versions code-space-wise. We've also added some simple improvements +that are super handy (commas in thousands, callbacks at buffer full, +for example). Finally, the format strings for MSVC and GCC differ +for 64-bit integers (among other small things), so this lets you use +the same format strings in cross platform code. + +It uses the standard single file trick of being both the header file +and the source itself. If you just include it normally, you just get +the header file function definitions. To get the code, you include +it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. + +It only uses va_args macros from the C runtime to do it's work. It +does cast doubles to S64s and shifts and divides U64s, which does +drag in CRT code on most platforms. + +It compiles to roughly 8K with float support, and 4K without. +As a comparison, when using MSVC static libs, calling sprintf drags +in 16K. + +API: +==== +int stbsp_sprintf( char * buf, char const * fmt, ... ) +int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) + Convert an arg list into a buffer. stbsp_snprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) +int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) + Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) + typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); + Convert into a buffer, calling back every STB_SPRINTF_MIN chars. + Your callback can then copy the chars out, print them or whatever. + This function is actually the workhorse for everything else. + The buffer you pass in must hold at least STB_SPRINTF_MIN characters. + // you return the next buffer to use or 0 to stop converting + +void stbsp_set_separators( char comma, char period ) + Set the comma and period characters to use. + +FLOATS/DOUBLES: +=============== +This code uses a internal float->ascii conversion method that uses +doubles with error correction (double-doubles, for ~105 bits of +precision). This conversion is round-trip perfect - that is, an atof +of the values output here will give you the bit-exact double back. + +One difference is that our insignificant digits will be different than +with MSVC or GCC (but they don't match each other either). We also +don't attempt to find the minimum length matching float (pre-MSVC15 +doesn't either). + +If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT +and you'll save 4K of code space. + +64-BIT INTS: +============ +This library also supports 64-bit integers and you can use MSVC style or +GCC style indicators (%I64d or %lld). It supports the C99 specifiers +for size_t and ptr_diff_t (%jd %zd) as well. + +EXTRAS: +======= +Like some GCCs, for integers and floats, you can use a ' (single quote) +specifier and commas will be inserted on the thousands: "%'d" on 12345 +would print 12,345. + +For integers and floats, you can use a "$" specifier and the number +will be converted to float and then divided to get kilo, mega, giga or +tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is +"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn +2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three +$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the +suffix, add "_" specifier: "%_$d" -> "2.53M". + +In addition to octal and hexadecimal conversions, you can print +integers in binary: "%b" for 256 would print 100. + +PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): +=================================================================== +"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) +"%24d" across all 32-bit ints (4.5x/4.2x faster) +"%x" across all 32-bit ints (4.5x/3.8x faster) +"%08x" across all 32-bit ints (4.3x/3.8x faster) +"%f" across e-10 to e+10 floats (7.3x/6.0x faster) +"%e" across e-10 to e+10 floats (8.1x/6.0x faster) +"%g" across e-10 to e+10 floats (10.0x/7.1x faster) +"%f" for values near e-300 (7.9x/6.5x faster) +"%f" for values near e+300 (10.0x/9.1x faster) +"%e" for values near e-300 (10.1x/7.0x faster) +"%e" for values near e+300 (9.2x/6.0x faster) +"%.320f" for values near e-300 (12.6x/11.2x faster) +"%a" for random values (8.6x/4.3x faster) +"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) +"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) +"%s%s%s" for 64 char strings (7.1x/7.3x faster) +"...512 char string..." ( 35.0x/32.5x faster!) +*/ + +#if defined(__clang__) + #if defined(__has_feature) && defined(__has_attribute) + #if __has_feature(address_sanitizer) + #if __has_attribute(__no_sanitize__) + #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) + #elif __has_attribute(__no_sanitize_address__) + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #elif __has_attribute(__no_address_safety_analysis__) + #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) + #endif + #endif + #endif +#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #endif +#endif + +#ifndef STBSP__ASAN +#define STBSP__ASAN +#endif + +#ifdef STB_SPRINTF_STATIC +#define STBSP__PUBLICDEC static +#define STBSP__PUBLICDEF static STBSP__ASAN +#else +#ifdef __cplusplus +#define STBSP__PUBLICDEC extern "C" +#define STBSP__PUBLICDEF extern "C" STBSP__ASAN +#else +#define STBSP__PUBLICDEC extern +#define STBSP__PUBLICDEF STBSP__ASAN +#endif +#endif + +#if defined(__has_attribute) + #if __has_attribute(format) + #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) + #endif +#endif + +#ifndef STBSP__ATTRIBUTE_FORMAT +#define STBSP__ATTRIBUTE_FORMAT(fmt,va) +#endif + +#ifdef _MSC_VER +#define STBSP__NOTUSED(v) (void)(v) +#else +#define STBSP__NOTUSED(v) (void)sizeof(v) +#endif + +#include // for va_arg(), va_list() +#include // size_t, ptrdiff_t + +#ifndef STB_SPRINTF_MIN +#define STB_SPRINTF_MIN 512 // how many characters per callback +#endif +typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); + +#ifndef STB_SPRINTF_DECORATE +#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names +#endif + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); + +#endif // STB_SPRINTF_H_INCLUDE + +#ifdef STB_SPRINTF_IMPLEMENTATION + +#define stbsp__uint32 unsigned int +#define stbsp__int32 signed int + +#ifdef _MSC_VER +#define stbsp__uint64 unsigned __int64 +#define stbsp__int64 signed __int64 +#else +#define stbsp__uint64 unsigned long long +#define stbsp__int64 signed long long +#endif +#define stbsp__uint16 unsigned short + +#ifndef stbsp__uintptr +#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) +#define stbsp__uintptr stbsp__uint64 +#else +#define stbsp__uintptr stbsp__uint32 +#endif +#endif + +#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define STB_SPRINTF_MSVC_MODE +#endif +#endif + +#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses +#define STBSP__UNALIGNED(code) +#else +#define STBSP__UNALIGNED(code) code +#endif + +#ifndef STB_SPRINTF_NOFLOAT +// internal float utility functions +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); +#define STBSP__SPECIAL 0x7000 +#endif + +static char stbsp__period = '.'; +static char stbsp__comma = ','; +static struct +{ + short temp; // force next field to be 2-byte aligned + char pair[201]; +} stbsp__digitpair = +{ + 0, + "00010203040506070809101112131415161718192021222324" + "25262728293031323334353637383940414243444546474849" + "50515253545556575859606162636465666768697071727374" + "75767778798081828384858687888990919293949596979899" +}; + +#ifdef STB_SPRINTF_UTF8_CHARS +static int stbsp_utf8_encode(int codepoint, char* buffer) +{ + if (codepoint < -0x80 || codepoint > 0x10FFFF) + { + codepoint = 0xfffd; + } + if (codepoint < 0x80) + { + buffer[0] = (char)codepoint; + return 1; + } + else if (codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + return 2; + } + else if (codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + return 3; + } + else + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + return 4; + } +} +#endif + +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) +{ + stbsp__period = pperiod; + stbsp__comma = pcomma; +} + +#define STBSP__LEFTJUST 1 +#define STBSP__LEADINGPLUS 2 +#define STBSP__LEADINGSPACE 4 +#define STBSP__LEADING_0X 8 +#define STBSP__LEADINGZERO 16 +#define STBSP__INTMAX 32 +#define STBSP__TRIPLET_COMMA 64 +#define STBSP__NEGATIVE 128 +#define STBSP__METRIC_SUFFIX 256 +#define STBSP__HALFWIDTH 512 +#define STBSP__METRIC_NOSPACE 1024 +#define STBSP__METRIC_1024 2048 +#define STBSP__METRIC_JEDEC 4096 + +static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) +{ + sign[0] = 0; + if (fl & STBSP__NEGATIVE) { + sign[0] = 1; + sign[1] = '-'; + } else if (fl & STBSP__LEADINGSPACE) { + sign[0] = 1; + sign[1] = ' '; + } else if (fl & STBSP__LEADINGPLUS) { + sign[0] = 1; + sign[1] = '+'; + } +} + +static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) +{ + char const * sn = s; + + // get up to 4-byte alignment + for (;;) { + if (((stbsp__uintptr)sn & 3) == 0) + break; + + if (!limit || *sn == 0) + return (stbsp__uint32)(sn - s); + + ++sn; + --limit; + } + + // scan over 4 bytes at a time to find terminating 0 + // this will intentionally scan up to 3 bytes past the end of buffers, + // but becase it works 4B aligned, it will never cross page boundaries + // (hence the STBSP__ASAN markup; the over-read here is intentional + // and harmless) + while (limit >= 4) { + stbsp__uint32 v = *(stbsp__uint32 *)sn; + // bit hack to find if there's a 0 byte in there + if ((v - 0x01010101) & (~v) & 0x80808080UL) + break; + + sn += 4; + limit -= 4; + } + + // handle the last few characters to find actual size + while (limit && *sn) { + ++sn; + --limit; + } + + return (stbsp__uint32)(sn - s); +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) +{ + static char hex[] = "0123456789abcdefxp"; + static char hexu[] = "0123456789ABCDEFXP"; + char *bf; + char const *f; + int tlen = 0; + + bf = buf; + f = fmt; + for (;;) { + stbsp__int32 fw, pr, tz; + stbsp__uint32 fl; + + // macros for the callback buffer stuff + #define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } + #define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } + #define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer + #define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } + + // fast copy everything up to the next % (or end of string) + for (;;) { + while (((stbsp__uintptr)f) & 3) { + schk1: + if (f[0] == '%') + goto scandd; + schk2: + if (f[0] == 0) + goto endfmt; + stbsp__chk_cb_buf(1); + *bf++ = f[0]; + ++f; + } + for (;;) { + // Check if the next 4 bytes contain %(0x25) or end of string. + // Using the 'hasless' trick: + // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + stbsp__uint32 v, c; + v = *(stbsp__uint32 *)f; + c = (~v) & 0x80808080; + if (((v ^ 0x25252525) - 0x01010101) & c) + goto schk1; + if ((v - 0x01010101) & c) + goto schk2; + if (callback) + if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) + goto schk1; + #ifdef STB_SPRINTF_NOUNALIGNED + if(((stbsp__uintptr)bf) & 3) { + bf[0] = f[0]; + bf[1] = f[1]; + bf[2] = f[2]; + bf[3] = f[3]; + } else + #endif + { + *(stbsp__uint32 *)bf = v; + } + bf += 4; + f += 4; + } + } + scandd: + + ++f; + + // ok, we have a percent, read the modifiers first + fw = 0; + pr = -1; + fl = 0; + tz = 0; + + // flags + for (;;) { + switch (f[0]) { + // if we have left justify + case '-': + fl |= STBSP__LEFTJUST; + ++f; + continue; + // if we have leading plus + case '+': + fl |= STBSP__LEADINGPLUS; + ++f; + continue; + // if we have leading space + case ' ': + fl |= STBSP__LEADINGSPACE; + ++f; + continue; + // if we have leading 0x + case '#': + fl |= STBSP__LEADING_0X; + ++f; + continue; + // if we have thousand commas + case '\'': + fl |= STBSP__TRIPLET_COMMA; + ++f; + continue; + // if we have kilo marker (none->kilo->kibi->jedec) + case '$': + if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_1024) { + fl |= STBSP__METRIC_JEDEC; + } else { + fl |= STBSP__METRIC_1024; + } + } else { + fl |= STBSP__METRIC_SUFFIX; + } + ++f; + continue; + // if we don't want space between metric suffix and number + case '_': + fl |= STBSP__METRIC_NOSPACE; + ++f; + continue; + // if we have leading zero + case '0': + fl |= STBSP__LEADINGZERO; + ++f; + goto flags_done; + default: goto flags_done; + } + } + flags_done: + + // get the field width + if (f[0] == '*') { + fw = va_arg(va, stbsp__uint32); + ++f; + } else { + while ((f[0] >= '0') && (f[0] <= '9')) { + fw = fw * 10 + f[0] - '0'; + f++; + } + } + // get the precision + if (f[0] == '.') { + ++f; + if (f[0] == '*') { + pr = va_arg(va, stbsp__uint32); + ++f; + } else { + pr = 0; + while ((f[0] >= '0') && (f[0] <= '9')) { + pr = pr * 10 + f[0] - '0'; + f++; + } + } + } + + // handle integer size overrides + switch (f[0]) { + // are we halfwidth? + case 'h': + fl |= STBSP__HALFWIDTH; + ++f; + if (f[0] == 'h') + ++f; // QUARTERWIDTH + break; + // are we 64-bit (unix style) + case 'l': + fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); + ++f; + if (f[0] == 'l') { + fl |= STBSP__INTMAX; + ++f; + } + break; + // are we 64-bit on intmax? (c99) + case 'j': + fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit on size_t or ptrdiff_t? (c99) + case 'z': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + case 't': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit (msft style) + case 'I': + if ((f[1] == '6') && (f[2] == '4')) { + fl |= STBSP__INTMAX; + f += 3; + } else if ((f[1] == '3') && (f[2] == '2')) { + f += 3; + } else { + fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); + ++f; + } + break; + default: break; + } + + // handle each replacement + switch (f[0]) { + #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + char num[STBSP__NUMSZ]; + char lead[8]; + char tail[8]; + char *s; + char const *h; + stbsp__uint32 l, n, cs; + stbsp__uint64 n64; +#ifndef STB_SPRINTF_NOFLOAT + double fv; +#endif + stbsp__int32 dp; + char const *sn; + + case 's': + // get the string + s = va_arg(va, char *); + if (s == 0) + s = (char *)"null"; + // get the length, limited to desired precision + // always limit to ~0u chars since our counts are 32b + l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + // copy the string in + goto scopy; + + case 'c': // char + // get the character +#ifndef STB_SPRINTF_UTF8_CHARS + s = num + STBSP__NUMSZ - 1; + *s = (char)va_arg(va, int); + l = 1; +#else + s = num + STBSP__NUMSZ - 4; // UTF-8 needs 4 bytes at most. + l = stbsp_utf8_encode(va_arg(va, int), s); +#endif + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + + case 'n': // weird write-bytes specifier + { + int *d = va_arg(va, int *); + *d = tlen + (int)(bf - buf); + } break; + +#ifdef STB_SPRINTF_NOFLOAT + case 'A': // float + case 'a': // hex float + case 'G': // float + case 'g': // float + case 'E': // float + case 'e': // float + case 'f': // float + va_arg(va, double); // eat it + s = (char *)"No float"; + l = 8; + lead[0] = 0; + tail[0] = 0; + pr = 0; + cs = 0; + STBSP__NOTUSED(dp); + goto scopy; +#else + case 'A': // hex float + case 'a': // hex float + h = (f[0] == 'A') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) + fl |= STBSP__NEGATIVE; + + s = num + 64; + + stbsp__lead_sign(fl, lead); + + if (dp == -1023) + dp = (n64) ? -1022 : 0; + else + n64 |= (((stbsp__uint64)1) << 52); + n64 <<= (64 - 56); + if (pr < 15) + n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); +// add leading chars + +#ifdef STB_SPRINTF_MSVC_MODE + *s++ = '0'; + *s++ = 'x'; +#else + lead[1 + lead[0]] = '0'; + lead[2 + lead[0]] = 'x'; + lead[0] += 2; +#endif + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + if (pr) + *s++ = stbsp__period; + sn = s; + + // print the bits + n = pr; + if (n > 13) + n = 13; + if (pr > (stbsp__int32)n) + tz = pr - n; + pr = 0; + while (n--) { + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + } + + // print the expo + tail[1] = h[17]; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; + n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + + dp = (int)(s - sn); + l = (int)(s - (num + 64)); + s = num + 64; + cs = 1 + (3 << 24); + goto scopy; + + case 'G': // float + case 'g': // float + h = (f[0] == 'G') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; + else if (pr == 0) + pr = 1; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) + fl |= STBSP__NEGATIVE; + + // clamp the precision and delete extra zeros after clamp + n = pr; + if (l > (stbsp__uint32)pr) + l = pr; + while ((l > 1) && (pr) && (sn[l - 1] == '0')) { + --pr; + --l; + } + + // should we use %e + if ((dp <= -4) || (dp > (stbsp__int32)n)) { + if (pr > (stbsp__int32)l) + pr = l - 1; + else if (pr) + --pr; // when using %e, there is one digit before the decimal + goto doexpfromg; + } + // this is the insane action to get the pr to match %g semantics for %f + if (dp > 0) { + pr = (dp < (stbsp__int32)l) ? l - dp : 0; + } else { + pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); + } + goto dofloatfromg; + + case 'E': // float + case 'e': // float + h = (f[0] == 'E') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) + fl |= STBSP__NEGATIVE; + doexpfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + // handle leading chars + *s++ = sn[0]; + + if (pr) + *s++ = stbsp__period; + + // handle after decimal + if ((l - 1) > (stbsp__uint32)pr) + l = pr + 1; + for (n = 1; n < l; n++) + *s++ = sn[n]; + // trailing zeros + tz = pr - (l - 1); + pr = 0; + // dump expo + tail[1] = h[0xe]; + dp -= 1; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; +#ifdef STB_SPRINTF_MSVC_MODE + n = 5; +#else + n = (dp >= 100) ? 5 : 4; +#endif + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + cs = 1 + (3 << 24); // how many tens + goto flt_lead; + + case 'f': // float + fv = va_arg(va, double); + doafloat: + // do kilos + if (fl & STBSP__METRIC_SUFFIX) { + double divisor; + divisor = 1000.0f; + if (fl & STBSP__METRIC_1024) + divisor = 1024.0; + while (fl < 0x4000000) { + if ((fv < divisor) && (fv > -divisor)) + break; + fv /= divisor; + fl += 0x1000000; + } + } + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) + fl |= STBSP__NEGATIVE; + dofloatfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + + // handle the three decimal varieties + if (dp <= 0) { + stbsp__int32 i; + // handle 0.000*000xxxx + *s++ = '0'; + if (pr) + *s++ = stbsp__period; + n = -dp; + if ((stbsp__int32)n > pr) + n = pr; + i = n; + while (i) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + i -= 4; + } + while (i) { + *s++ = '0'; + --i; + } + if ((stbsp__int32)(l + n) > pr) + l = pr - n; + i = l; + while (i) { + *s++ = *sn++; + --i; + } + tz = pr - (n + l); + cs = 1 + (3 << 24); // how many tens did we write (for commas below) + } else { + cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; + if ((stbsp__uint32)dp >= l) { + // handle xxxx000*000.0 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= l) + break; + } + } + if (n < (stbsp__uint32)dp) { + n = dp - n; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --n; + } + while (n >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + n -= 4; + } + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = '0'; + --n; + } + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) { + *s++ = stbsp__period; + tz = pr; + } + } else { + // handle xxxxx.xxxx000*000 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= (stbsp__uint32)dp) + break; + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) + *s++ = stbsp__period; + if ((l - dp) > (stbsp__uint32)pr) + l = pr + dp; + while (n < l) { + *s++ = sn[n]; + ++n; + } + tz = pr - (l - dp); + } + } + pr = 0; + + // handle k,m,g,t + if (fl & STBSP__METRIC_SUFFIX) { + char idx; + idx = 1; + if (fl & STBSP__METRIC_NOSPACE) + idx = 0; + tail[0] = idx; + tail[1] = ' '; + { + if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl & STBSP__METRIC_1024) + tail[idx + 1] = "_KMGT"[fl >> 24]; + else + tail[idx + 1] = "_kMGT"[fl >> 24]; + idx++; + // If printing kibits and not in jedec, add the 'i'. + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { + tail[idx + 1] = 'i'; + idx++; + } + tail[0] = idx; + } + } + }; + + flt_lead: + // get the length that we copied + l = (stbsp__uint32)(s - (num + 64)); + s = num + 64; + goto scopy; +#endif + + case 'B': // upper binary + case 'b': // lower binary + h = (f[0] == 'B') ? hexu : hex; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[0xb]; + } + l = (8 << 4) | (1 << 8); + goto radixnum; + + case 'o': // octal + h = hexu; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 1; + lead[1] = '0'; + } + l = (3 << 4) | (3 << 8); + goto radixnum; + + case 'p': // pointer + fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; + pr = sizeof(void *) * 2; + fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros + // fall through - to X + + case 'X': // upper hex + case 'x': // lower hex + h = (f[0] == 'X') ? hexu : hex; + l = (4 << 4) | (4 << 8); + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[16]; + } + radixnum: + // get the number + if (fl & STBSP__INTMAX) + n64 = va_arg(va, stbsp__uint64); + else + n64 = va_arg(va, stbsp__uint32); + + s = num + STBSP__NUMSZ; + dp = 0; + // clear tail, and clear leading if value is zero + tail[0] = 0; + if (n64 == 0) { + lead[0] = 0; + if (pr == 0) { + l = 0; + cs = 0; + goto scopy; + } + } + // convert to string + for (;;) { + *--s = h[n64 & ((1 << (l >> 8)) - 1)]; + n64 >>= (l >> 8); + if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) + break; + if (fl & STBSP__TRIPLET_COMMA) { + ++l; + if ((l & 15) == ((l >> 4) & 15)) { + l &= ~15; + *--s = stbsp__comma; + } + } + }; + // get the tens and the comma pos + cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + // copy it + goto scopy; + + case 'u': // unsigned + case 'i': + case 'd': // integer + // get the integer and abs it + if (fl & STBSP__INTMAX) { + stbsp__int64 i64 = va_arg(va, stbsp__int64); + n64 = (stbsp__uint64)i64; + if ((f[0] != 'u') && (i64 < 0)) { + n64 = (stbsp__uint64)-i64; + fl |= STBSP__NEGATIVE; + } + } else { + stbsp__int32 i = va_arg(va, stbsp__int32); + n64 = (stbsp__uint32)i; + if ((f[0] != 'u') && (i < 0)) { + n64 = (stbsp__uint32)-i; + fl |= STBSP__NEGATIVE; + } + } + +#ifndef STB_SPRINTF_NOFLOAT + if (fl & STBSP__METRIC_SUFFIX) { + if (n64 < 1024) + pr = 0; + else if (pr == -1) + pr = 1; + fv = (double)(stbsp__int64)n64; + goto doafloat; + } +#endif + + // convert to string + s = num + STBSP__NUMSZ; + l = 0; + + for (;;) { + // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) + char *o = s - 8; + if (n64 >= 100000000) { + n = (stbsp__uint32)(n64 % 100000000); + n64 /= 100000000; + } else { + n = (stbsp__uint32)n64; + n64 = 0; + } + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + do { + s -= 2; + *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + } while (n); + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = (char)(n % 10) + '0'; + n /= 10; + } + } + if (n64 == 0) { + if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) + ++s; + break; + } + while (s != o) + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = '0'; + } + } + + tail[0] = 0; + stbsp__lead_sign(fl, lead); + + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + if (l == 0) { + *--s = '0'; + l = 1; + } + cs = l + (3 << 24); + if (pr < 0) + pr = 0; + + scopy: + // get fw=leading/trailing space, pr=leading zeros + if (pr < (stbsp__int32)l) + pr = l; + n = pr + lead[0] + tail[0] + tz; + if (fw < (stbsp__int32)n) + fw = n; + fw -= n; + pr -= l; + + // handle right justify and leading zeros + if ((fl & STBSP__LEFTJUST) == 0) { + if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr + { + pr = (fw > pr) ? fw : pr; + fw = 0; + } else { + fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas + } + } + + // copy the spaces and/or zeros + if (fw + pr) { + stbsp__int32 i; + stbsp__uint32 c; + + // copy leading spaces (or when doing %8.4d stuff) + if ((fl & STBSP__LEFTJUST) == 0) + while (fw > 0) { + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = ' '; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leader + sn = lead + 1; + while (lead[0]) { + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leading zeros + c = cs >> 24; + cs &= 0xffffff; + cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; + while (pr > 0) { + stbsp__cb_buf_clamp(i, pr); + pr -= i; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + } + while (i) { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { + cs = 0; + *bf++ = stbsp__comma; + } else + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + } + + // copy leader if there is still one + sn = lead + 1; + while (lead[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy the string + n = l; + while (n) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, n); + n -= i; + STBSP__UNALIGNED(while (i >= 4) { + *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; + bf += 4; + s += 4; + i -= 4; + }) + while (i) { + *bf++ = *s++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy trailing zeros + while (tz) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tz); + tz -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy tail if there is one + sn = tail + 1; + while (tail[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tail[0]); + tail[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // handle the left justify + if (fl & STBSP__LEFTJUST) + if (fw > 0) { + while (fw) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i--) + *bf++ = ' '; + stbsp__chk_cb_buf(1); + } + } + break; + + default: // unknown, just copy code + s = num + STBSP__NUMSZ - 1; + *s = f[0]; + l = 1; + fw = fl = 0; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + } + ++f; + } +endfmt: + + if (!callback) + *bf = 0; + else + stbsp__flush_cb(); + +done: + return tlen + (int)(bf - buf); +} + +// cleanup +#undef STBSP__LEFTJUST +#undef STBSP__LEADINGPLUS +#undef STBSP__LEADINGSPACE +#undef STBSP__LEADING_0X +#undef STBSP__LEADINGZERO +#undef STBSP__INTMAX +#undef STBSP__TRIPLET_COMMA +#undef STBSP__NEGATIVE +#undef STBSP__METRIC_SUFFIX +#undef STBSP__NUMSZ +#undef stbsp__chk_cb_bufL +#undef stbsp__chk_cb_buf +#undef stbsp__flush_cb +#undef stbsp__cb_buf_clamp + +// ============================================================================ +// wrapper functions + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); + va_end(va); + return result; +} + +typedef struct stbsp__context { + char *buf; + int count; + int length; + char tmp[STB_SPRINTF_MIN]; +} stbsp__context; + +static char *stbsp__clamp_callback(const char *buf, void *user, int len) +{ + stbsp__context *c = (stbsp__context *)user; + c->length += len; + + if (len > c->count) + len = c->count; + + if (len) { + if (buf != c->buf) { + const char *s, *se; + char *d; + d = c->buf; + s = buf; + se = buf + len; + do { + *d++ = *s++; + } while (s < se); + } + c->buf += len; + c->count -= len; + } + + if (c->count <= 0) + return c->tmp; + return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can +} + +static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) +{ + stbsp__context * c = (stbsp__context*)user; + (void) sizeof(buf); + + c->length += len; + return c->tmp; // go direct into buffer if you can +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) +{ + stbsp__context c; + + if ( (count == 0) && !buf ) + { + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); + } + else + { + int l; + + c.buf = buf; + c.count = count; + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); + + // zero-terminate + l = (int)( c.buf - buf ); + if ( l >= count ) // should never be greater, only equal (or less) than count + l = count - 1; + buf[l] = 0; + } + + return c.length; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + + result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); + va_end(va); + + return result; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) +{ + return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); +} + +// ======================================================================= +// low level float utility functions + +#ifndef STB_SPRINTF_NOFLOAT + +// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) +#define STBSP__COPYFP(dest, src) \ + { \ + int cn; \ + for (cn = 0; cn < 8; cn++) \ + ((char *)&dest)[cn] = ((char *)&src)[cn]; \ + } + +// get float info +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) +{ + double d; + stbsp__int64 b = 0; + + // load value and round at the frac_digits + d = value; + + STBSP__COPYFP(b, d); + + *bits = b & ((((stbsp__uint64)1) << 52) - 1); + *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); + + return (stbsp__int32)((stbsp__uint64) b >> 63); +} + +static double const stbsp__bot[23] = { + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 +}; +static double const stbsp__negbot[22] = { + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 +}; +static double const stbsp__negboterr[22] = { + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 +}; +static double const stbsp__top[13] = { + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 +}; +static double const stbsp__negtop[13] = { + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 +}; +static double const stbsp__toperr[13] = { + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282 +}; +static double const stbsp__negtoperr[13] = { + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317 +}; + +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U +}; +#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) +#else +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; +#define stbsp__tento19th (1000000000000000000ULL) +#endif + +#define stbsp__ddmulthi(oh, ol, xh, yh) \ + { \ + double ahi = 0, alo, bhi = 0, blo; \ + stbsp__int64 bt; \ + oh = xh * yh; \ + STBSP__COPYFP(bt, xh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(ahi, bt); \ + alo = xh - ahi; \ + STBSP__COPYFP(bt, yh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(bhi, bt); \ + blo = yh - bhi; \ + ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ + } + +#define stbsp__ddtoS64(ob, xh, xl) \ + { \ + double ahi = 0, alo, vh, t; \ + ob = (stbsp__int64)xh; \ + vh = (double)ob; \ + ahi = (xh - vh); \ + t = (ahi - xh); \ + alo = (xh - (ahi - t)) - (vh + t); \ + ob += (stbsp__int64)(ahi + alo + xl); \ + } + +#define stbsp__ddrenorm(oh, ol) \ + { \ + double s; \ + s = oh + ol; \ + ol = ol - (s - oh); \ + oh = s; \ + } + +#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); + +#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); + +static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 +{ + double ph, pl; + if ((power >= 0) && (power <= 22)) { + stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); + } else { + stbsp__int32 e, et, eb; + double p2h, p2l; + + e = power; + if (power < 0) + e = -e; + et = (e * 0x2c9) >> 14; /* %23 */ + if (et > 13) + et = 13; + eb = e - (et * 23); + + ph = d; + pl = 0.0; + if (power < 0) { + if (eb) { + --eb; + stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); + stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); + ph = p2h; + pl = p2l; + } + } else { + if (eb) { + e = eb; + if (eb > 22) + eb = 22; + e -= eb; + stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); + if (e) { + stbsp__ddrenorm(ph, pl); + stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); + stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); + ph = p2h; + pl = p2l; + } + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); + ph = p2h; + pl = p2l; + } + } + } + stbsp__ddrenorm(ph, pl); + *ohi = ph; + *olo = pl; +} + +// given a float value, returns the significant bits in bits, and the position of the +// decimal point in decimal_pos. +/-INF and NAN are specified by special values +// returned in the decimal_pos parameter. +// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) +{ + double d; + stbsp__int64 bits = 0; + stbsp__int32 expo, e, ng, tens; + + d = value; + STBSP__COPYFP(bits, d); + expo = (stbsp__int32)((bits >> 52) & 2047); + ng = (stbsp__int32)((stbsp__uint64) bits >> 63); + if (ng) + d = -d; + + if (expo == 2047) // is nan or inf? + { + *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; + *decimal_pos = STBSP__SPECIAL; + *len = 3; + return ng; + } + + if (expo == 0) // is zero or denormal + { + if (((stbsp__uint64) bits << 1) == 0) // do zero + { + *decimal_pos = 1; + *start = out; + out[0] = '0'; + *len = 1; + return ng; + } + // find the right expo for denormals + { + stbsp__int64 v = ((stbsp__uint64)1) << 51; + while ((bits & v) == 0) { + --expo; + v >>= 1; + } + } + } + + // find the decimal exponent as well as the decimal bits of the value + { + double ph, pl; + + // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 + tens = expo - 1023; + tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); + + // move the significant bits into position and stick them into an int + stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); + + // get full as much precision from double-double as possible + stbsp__ddtoS64(bits, ph, pl); + + // check if we undershot + if (((stbsp__uint64)bits) >= stbsp__tento19th) + ++tens; + } + + // now do the rounding in integer land + frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); + if ((frac_digits < 24)) { + stbsp__uint32 dg = 1; + if ((stbsp__uint64)bits >= stbsp__powten[9]) + dg = 10; + while ((stbsp__uint64)bits >= stbsp__powten[dg]) { + ++dg; + if (dg == 20) + goto noround; + } + if (frac_digits < dg) { + stbsp__uint64 r; + // add 0.5 at the right position and round + e = dg - frac_digits; + if ((stbsp__uint32)e >= 24) + goto noround; + r = stbsp__powten[e]; + bits = bits + (r / 2); + if ((stbsp__uint64)bits >= stbsp__powten[dg]) + ++tens; + bits /= r; + } + noround:; + } + + // kill long trailing runs of zeros + if (bits) { + stbsp__uint32 n; + for (;;) { + if (bits <= 0xffffffff) + break; + if (bits % 1000) + goto donez; + bits /= 1000; + } + n = (stbsp__uint32)bits; + while ((n % 1000) == 0) + n /= 1000; + bits = n; + donez:; + } + + // convert to string + out += 64; + e = 0; + for (;;) { + stbsp__uint32 n; + char *o = out - 8; + // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) + if (bits >= 100000000) { + n = (stbsp__uint32)(bits % 100000000); + bits /= 100000000; + } else { + n = (stbsp__uint32)bits; + bits = 0; + } + while (n) { + out -= 2; + *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + e += 2; + } + if (bits == 0) { + if ((e) && (out[0] == '0')) { + ++out; + --e; + } + break; + } + while (out != o) { + *--out = '0'; + ++e; + } + } + + *decimal_pos = tens; + *start = out; + *len = e; + return ng; +} + +#undef stbsp__ddmulthi +#undef stbsp__ddrenorm +#undef stbsp__ddmultlo +#undef stbsp__ddmultlos +#undef STBSP__SPECIAL +#undef STBSP__COPYFP + +#endif // STB_SPRINTF_NOFLOAT + +// clean up +#undef stbsp__uint16 +#undef stbsp__uint32 +#undef stbsp__int32 +#undef stbsp__uint64 +#undef stbsp__int64 +#undef STBSP__UNALIGNED + +#endif // STB_SPRINTF_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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/src/utility/strnatcmp.c b/src/common/thirdparty/strnatcmp.c similarity index 99% rename from src/utility/strnatcmp.c rename to src/common/thirdparty/strnatcmp.c index 58fa5571ab0..8caadfbd7f9 100644 --- a/src/utility/strnatcmp.c +++ b/src/common/thirdparty/strnatcmp.c @@ -85,8 +85,6 @@ compare_right(nat_char const *a, nat_char const *b) } else if (!*a && !*b) return bias; } - - return 0; } @@ -107,8 +105,6 @@ compare_left(nat_char const *a, nat_char const *b) else if (*a > *b) return +1; } - - return 0; } diff --git a/src/utility/strnatcmp.h b/src/common/thirdparty/strnatcmp.h similarity index 100% rename from src/utility/strnatcmp.h rename to src/common/thirdparty/strnatcmp.h diff --git a/src/common/thirdparty/superfasthash.cpp b/src/common/thirdparty/superfasthash.cpp new file mode 100644 index 00000000000..a443809f06d --- /dev/null +++ b/src/common/thirdparty/superfasthash.cpp @@ -0,0 +1,127 @@ +#include +#include +#include + +/* ======================================================================== */ + +/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh derivative + license. See: + http://www.azillionmonkeys.com/qed/weblicense.html for license details. + + http://www.azillionmonkeys.com/qed/hash.html */ + +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif + +uint32_t SuperFastHash (const char *data, size_t len) +{ + uint32_t hash = 0, tmp; + size_t rem; + + if (len == 0 || data == NULL) return 0; + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (;len > 0; len--) + { + hash += get16bits (data); + tmp = (get16bits (data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof (uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) + { + case 3: hash += get16bits (data); + hash ^= hash << 16; + hash ^= data[sizeof (uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: hash += get16bits (data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +/* A modified version to do a case-insensitive hash */ + +#undef get16bits +#define get16bits(d) ((((uint32_t)tolower(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)tolower(((const uint8_t *)(d))[0]) ) + +uint32_t SuperFastHashI (const char *data, size_t len) +{ + uint32_t hash = 0, tmp; + size_t rem; + + if (len <= 0 || data == NULL) return 0; + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (;len > 0; len--) + { + hash += get16bits (data); + tmp = (get16bits (data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof (uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) + { + case 3: hash += get16bits (data); + hash ^= hash << 16; + hash ^= tolower(data[sizeof (uint16_t)]) << 18; + hash += hash >> 11; + break; + case 2: hash += get16bits (data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += tolower(*data); + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +/* ======================================================================== */ + diff --git a/src/common/thirdparty/superfasthash.h b/src/common/thirdparty/superfasthash.h new file mode 100644 index 00000000000..97202520289 --- /dev/null +++ b/src/common/thirdparty/superfasthash.h @@ -0,0 +1,20 @@ +#pragma once +#include + +uint32_t SuperFastHash (const char *data, size_t len); +uint32_t SuperFastHashI (const char *data, size_t len); + +inline unsigned int MakeKey(const char* s) +{ + if (s == NULL) + { + return 0; + } + return SuperFastHashI(s, strlen(s)); +} + +inline unsigned int MakeKey(const char* s, size_t len) +{ + return SuperFastHashI(s, len); +} + diff --git a/src/common/thirdparty/utf8proc/LICENSE.md b/src/common/thirdparty/utf8proc/LICENSE.md new file mode 100644 index 00000000000..f18b1f3abdc --- /dev/null +++ b/src/common/thirdparty/utf8proc/LICENSE.md @@ -0,0 +1,93 @@ +## utf8proc license ## + +**utf8proc** is a software package originally developed +by Jan Behrens and the rest of the Public Software Group, who +deserve nearly all of the credit for this library, that is now maintained by the Julia-language developers. Like the original utf8proc, +whose copyright and license statements are reproduced below, all new +work on the utf8proc library is licensed under the [MIT "expat" +license](http://opensource.org/licenses/MIT): + +*Copyright © 2014-2021 by Steven G. Johnson, Jiahao Chen, Tony Kelman, Jonas Fonseca, and other contributors listed in the git history.* + +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. + +## Original utf8proc license ## + +*Copyright (c) 2009, 2013 Public Software Group e. V., Berlin, Germany* + +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. + +## Unicode data license ## + +This software contains data (`utf8proc_data.c`) derived from processing +the Unicode data files. The following license applies to that data: + +**COPYRIGHT AND PERMISSION NOTICE** + +*Copyright (c) 1991-2007 Unicode, Inc. All rights reserved. Distributed +under the Terms of Use in http://www.unicode.org/copyright.html.* + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Unicode data files and any associated documentation (the "Data +Files") or Unicode software and any associated documentation (the +"Software") to deal in the Data Files or Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, and/or sell copies of the Data Files or Software, and +to permit persons to whom the Data Files or Software are furnished to do +so, provided that (a) the above copyright notice(s) and this permission +notice appear with all copies of the Data Files or Software, (b) both the +above copyright notice(s) and this permission notice appear in associated +documentation, and (c) there is clear notice in each modified Data File or +in the Software as well as in the documentation associated with the Data +File(s) or Software that the data or software has been modified. + +THE DATA FILES AND SOFTWARE ARE 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 OF +THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS +INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR +CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. + +Unicode and the Unicode logo are trademarks of Unicode, Inc., and may be +registered in some jurisdictions. All other trademarks and registered +trademarks mentioned herein are the property of their respective owners. diff --git a/src/common/thirdparty/utf8proc/utf8proc.c b/src/common/thirdparty/utf8proc/utf8proc.c new file mode 100644 index 00000000000..a7644247b44 --- /dev/null +++ b/src/common/thirdparty/utf8proc/utf8proc.c @@ -0,0 +1,815 @@ +/* -*- mode: c; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*- */ +/* + * Copyright (c) 2014-2021 Steven G. Johnson, Jiahao Chen, Peter Colberg, Tony Kelman, Scott P. Jones, and other contributors. + * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany + * + * 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. + */ + +/* + * This library contains derived data from a modified version of the + * Unicode data files. + * + * The original data files are available at + * https://www.unicode.org/Public/UNIDATA/ + * + * Please notice the copyright statement in the file "utf8proc_data.c". + */ + + +/* + * File name: utf8proc.c + * + * Description: + * Implementation of libutf8proc. + */ + + +#include "utf8proc.h" + +#ifndef SSIZE_MAX +#define SSIZE_MAX ((size_t)SIZE_MAX/2) +#endif +#ifndef UINT16_MAX +# define UINT16_MAX 65535U +#endif + +#include "utf8proc_data.c" + + +UTF8PROC_DLLEXPORT const utf8proc_int8_t utf8proc_utf8class[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0 }; + +#define UTF8PROC_HANGUL_SBASE 0xAC00 +#define UTF8PROC_HANGUL_LBASE 0x1100 +#define UTF8PROC_HANGUL_VBASE 0x1161 +#define UTF8PROC_HANGUL_TBASE 0x11A7 +#define UTF8PROC_HANGUL_LCOUNT 19 +#define UTF8PROC_HANGUL_VCOUNT 21 +#define UTF8PROC_HANGUL_TCOUNT 28 +#define UTF8PROC_HANGUL_NCOUNT 588 +#define UTF8PROC_HANGUL_SCOUNT 11172 +/* END is exclusive */ +#define UTF8PROC_HANGUL_L_START 0x1100 +#define UTF8PROC_HANGUL_L_END 0x115A +#define UTF8PROC_HANGUL_L_FILLER 0x115F +#define UTF8PROC_HANGUL_V_START 0x1160 +#define UTF8PROC_HANGUL_V_END 0x11A3 +#define UTF8PROC_HANGUL_T_START 0x11A8 +#define UTF8PROC_HANGUL_T_END 0x11FA +#define UTF8PROC_HANGUL_S_START 0xAC00 +#define UTF8PROC_HANGUL_S_END 0xD7A4 + +/* Should follow semantic-versioning rules (semver.org) based on API + compatibility. (Note that the shared-library version number will + be different, being based on ABI compatibility.): */ +#define STRINGIZEx(x) #x +#define STRINGIZE(x) STRINGIZEx(x) +UTF8PROC_DLLEXPORT const char *utf8proc_version(void) { + return STRINGIZE(UTF8PROC_VERSION_MAJOR) "." STRINGIZE(UTF8PROC_VERSION_MINOR) "." STRINGIZE(UTF8PROC_VERSION_PATCH) ""; +} + +UTF8PROC_DLLEXPORT const char *utf8proc_unicode_version(void) { + return "15.1.0"; +} + +UTF8PROC_DLLEXPORT const char *utf8proc_errmsg(utf8proc_ssize_t errcode) { + switch (errcode) { + case UTF8PROC_ERROR_NOMEM: + return "Memory for processing UTF-8 data could not be allocated."; + case UTF8PROC_ERROR_OVERFLOW: + return "UTF-8 string is too long to be processed."; + case UTF8PROC_ERROR_INVALIDUTF8: + return "Invalid UTF-8 string"; + case UTF8PROC_ERROR_NOTASSIGNED: + return "Unassigned Unicode code point found in UTF-8 string."; + case UTF8PROC_ERROR_INVALIDOPTS: + return "Invalid options for UTF-8 processing chosen."; + default: + return "An unknown error occurred while processing UTF-8 data."; + } +} + +#define utf_cont(ch) (((ch) & 0xc0) == 0x80) +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_iterate( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *dst +) { + utf8proc_int32_t uc; + const utf8proc_uint8_t *end; + + *dst = -1; + if (!strlen) return 0; + end = str + ((strlen < 0) ? 4 : strlen); + uc = *str++; + if (uc < 0x80) { + *dst = uc; + return 1; + } + // Must be between 0xc2 and 0xf4 inclusive to be valid + if ((utf8proc_uint32_t)(uc - 0xc2) > (0xf4-0xc2)) return UTF8PROC_ERROR_INVALIDUTF8; + if (uc < 0xe0) { // 2-byte sequence + // Must have valid continuation character + if (str >= end || !utf_cont(*str)) return UTF8PROC_ERROR_INVALIDUTF8; + *dst = ((uc & 0x1f)<<6) | (*str & 0x3f); + return 2; + } + if (uc < 0xf0) { // 3-byte sequence + if ((str + 1 >= end) || !utf_cont(*str) || !utf_cont(str[1])) + return UTF8PROC_ERROR_INVALIDUTF8; + // Check for surrogate chars + if (uc == 0xed && *str > 0x9f) + return UTF8PROC_ERROR_INVALIDUTF8; + uc = ((uc & 0xf)<<12) | ((*str & 0x3f)<<6) | (str[1] & 0x3f); + if (uc < 0x800) + return UTF8PROC_ERROR_INVALIDUTF8; + *dst = uc; + return 3; + } + // 4-byte sequence + // Must have 3 valid continuation characters + if ((str + 2 >= end) || !utf_cont(*str) || !utf_cont(str[1]) || !utf_cont(str[2])) + return UTF8PROC_ERROR_INVALIDUTF8; + // Make sure in correct range (0x10000 - 0x10ffff) + if (uc == 0xf0) { + if (*str < 0x90) return UTF8PROC_ERROR_INVALIDUTF8; + } else if (uc == 0xf4) { + if (*str > 0x8f) return UTF8PROC_ERROR_INVALIDUTF8; + } + *dst = ((uc & 7)<<18) | ((*str & 0x3f)<<12) | ((str[1] & 0x3f)<<6) | (str[2] & 0x3f); + return 4; +} + +UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_codepoint_valid(utf8proc_int32_t uc) { + return (((utf8proc_uint32_t)uc)-0xd800 > 0x07ff) && ((utf8proc_uint32_t)uc < 0x110000); +} + +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t *dst) { + if (uc < 0x00) { + return 0; + } else if (uc < 0x80) { + dst[0] = (utf8proc_uint8_t) uc; + return 1; + } else if (uc < 0x800) { + dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6)); + dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); + return 2; + // Note: we allow encoding 0xd800-0xdfff here, so as not to change + // the API, however, these are actually invalid in UTF-8 + } else if (uc < 0x10000) { + dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12)); + dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F)); + dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); + return 3; + } else if (uc < 0x110000) { + dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18)); + dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F)); + dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F)); + dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); + return 4; + } else return 0; +} + +/* internal version used for inserting 0xff bytes between graphemes */ +static utf8proc_ssize_t charbound_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t *dst) { + if (uc < 0x00) { + if (uc == -1) { /* internal value used for grapheme breaks */ + dst[0] = (utf8proc_uint8_t)0xFF; + return 1; + } + return 0; + } else if (uc < 0x80) { + dst[0] = (utf8proc_uint8_t)uc; + return 1; + } else if (uc < 0x800) { + dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6)); + dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); + return 2; + } else if (uc < 0x10000) { + dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12)); + dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F)); + dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); + return 3; + } else if (uc < 0x110000) { + dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18)); + dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F)); + dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F)); + dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); + return 4; + } else return 0; +} + +/* internal "unsafe" version that does not check whether uc is in range */ +static const utf8proc_property_t *unsafe_get_property(utf8proc_int32_t uc) { + /* ASSERT: uc >= 0 && uc < 0x110000 */ + return utf8proc_properties + ( + utf8proc_stage2table[ + utf8proc_stage1table[uc >> 8] + (uc & 0xFF) + ] + ); +} + +UTF8PROC_DLLEXPORT const utf8proc_property_t *utf8proc_get_property(utf8proc_int32_t uc) { + return uc < 0 || uc >= 0x110000 ? utf8proc_properties : unsafe_get_property(uc); +} + +/* return whether there is a grapheme break between boundclasses lbc and tbc + (according to the definition of extended grapheme clusters) + + Rule numbering refers to TR29 Version 29 (Unicode 9.0.0): + http://www.unicode.org/reports/tr29/tr29-29.html + + CAVEATS: + Please note that evaluation of GB10 (grapheme breaks between emoji zwj sequences) + and GB 12/13 (regional indicator code points) require knowledge of previous characters + and are thus not handled by this function. This may result in an incorrect break before + an E_Modifier class codepoint and an incorrectly missing break between two + REGIONAL_INDICATOR class code points if such support does not exist in the caller. + + See the special support in grapheme_break_extended, for required bookkeeping by the caller. +*/ +static utf8proc_bool grapheme_break_simple(int lbc, int tbc) { + return + (lbc == UTF8PROC_BOUNDCLASS_START) ? true : // GB1 + (lbc == UTF8PROC_BOUNDCLASS_CR && // GB3 + tbc == UTF8PROC_BOUNDCLASS_LF) ? false : // --- + (lbc >= UTF8PROC_BOUNDCLASS_CR && lbc <= UTF8PROC_BOUNDCLASS_CONTROL) ? true : // GB4 + (tbc >= UTF8PROC_BOUNDCLASS_CR && tbc <= UTF8PROC_BOUNDCLASS_CONTROL) ? true : // GB5 + (lbc == UTF8PROC_BOUNDCLASS_L && // GB6 + (tbc == UTF8PROC_BOUNDCLASS_L || // --- + tbc == UTF8PROC_BOUNDCLASS_V || // --- + tbc == UTF8PROC_BOUNDCLASS_LV || // --- + tbc == UTF8PROC_BOUNDCLASS_LVT)) ? false : // --- + ((lbc == UTF8PROC_BOUNDCLASS_LV || // GB7 + lbc == UTF8PROC_BOUNDCLASS_V) && // --- + (tbc == UTF8PROC_BOUNDCLASS_V || // --- + tbc == UTF8PROC_BOUNDCLASS_T)) ? false : // --- + ((lbc == UTF8PROC_BOUNDCLASS_LVT || // GB8 + lbc == UTF8PROC_BOUNDCLASS_T) && // --- + tbc == UTF8PROC_BOUNDCLASS_T) ? false : // --- + (tbc == UTF8PROC_BOUNDCLASS_EXTEND || // GB9 + tbc == UTF8PROC_BOUNDCLASS_ZWJ || // --- + tbc == UTF8PROC_BOUNDCLASS_SPACINGMARK || // GB9a + lbc == UTF8PROC_BOUNDCLASS_PREPEND) ? false : // GB9b + (lbc == UTF8PROC_BOUNDCLASS_E_ZWG && // GB11 (requires additional handling below) + tbc == UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC) ? false : // ---- + (lbc == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR && // GB12/13 (requires additional handling below) + tbc == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR) ? false : // ---- + true; // GB999 +} + +static utf8proc_bool grapheme_break_extended(int lbc, int tbc, int licb, int ticb, utf8proc_int32_t *state) +{ + if (state) { + int state_bc, state_icb; /* boundclass and indic_conjunct_break state */ + if (*state == 0) { /* state initialization */ + state_bc = lbc; + state_icb = licb == UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT ? licb : UTF8PROC_INDIC_CONJUNCT_BREAK_NONE; + } + else { /* lbc and licb are already encoded in *state */ + state_bc = *state & 0xff; // 1st byte of state is bound class + state_icb = *state >> 8; // 2nd byte of state is indic conjunct break + } + + utf8proc_bool break_permitted = grapheme_break_simple(state_bc, tbc) && + !(state_icb == UTF8PROC_INDIC_CONJUNCT_BREAK_LINKER + && ticb == UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT); // GB9c + + // Special support for GB9c. Don't break between two consonants + // separated 1+ linker characters and 0+ extend characters in any order. + // After a consonant, we enter LINKER state after at least one linker. + if (ticb == UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT + || state_icb == UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT + || state_icb == UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND) + state_icb = ticb; + else if (state_icb == UTF8PROC_INDIC_CONJUNCT_BREAK_LINKER) + state_icb = ticb == UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND ? + UTF8PROC_INDIC_CONJUNCT_BREAK_LINKER : ticb; + + // Special support for GB 12/13 made possible by GB999. After two RI + // class codepoints we want to force a break. Do this by resetting the + // second RI's bound class to UTF8PROC_BOUNDCLASS_OTHER, to force a break + // after that character according to GB999 (unless of course such a break is + // forbidden by a different rule such as GB9). + if (state_bc == tbc && tbc == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR) + state_bc = UTF8PROC_BOUNDCLASS_OTHER; + // Special support for GB11 (emoji extend* zwj / emoji) + else if (state_bc == UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC) { + if (tbc == UTF8PROC_BOUNDCLASS_EXTEND) // fold EXTEND codepoints into emoji + state_bc = UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC; + else if (tbc == UTF8PROC_BOUNDCLASS_ZWJ) + state_bc = UTF8PROC_BOUNDCLASS_E_ZWG; // state to record emoji+zwg combo + else + state_bc = tbc; + } + else + state_bc = tbc; + + *state = state_bc + (state_icb << 8); + return break_permitted; + } + else + return grapheme_break_simple(lbc, tbc); +} + +UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break_stateful( + utf8proc_int32_t c1, utf8proc_int32_t c2, utf8proc_int32_t *state) { + + const utf8proc_property_t *p1 = utf8proc_get_property(c1); + const utf8proc_property_t *p2 = utf8proc_get_property(c2); + return grapheme_break_extended(p1->boundclass, + p2->boundclass, + p1->indic_conjunct_break, + p2->indic_conjunct_break, + state); +} + + +UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break( + utf8proc_int32_t c1, utf8proc_int32_t c2) { + return utf8proc_grapheme_break_stateful(c1, c2, NULL); +} + +static utf8proc_int32_t seqindex_decode_entry(const utf8proc_uint16_t **entry) +{ + utf8proc_int32_t entry_cp = **entry; + if ((entry_cp & 0xF800) == 0xD800) { + *entry = *entry + 1; + entry_cp = ((entry_cp & 0x03FF) << 10) | (**entry & 0x03FF); + entry_cp += 0x10000; + } + return entry_cp; +} + +static utf8proc_int32_t seqindex_decode_index(const utf8proc_uint32_t seqindex) +{ + const utf8proc_uint16_t *entry = &utf8proc_sequences[seqindex]; + return seqindex_decode_entry(&entry); +} + +static utf8proc_ssize_t seqindex_write_char_decomposed(utf8proc_uint16_t seqindex, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) { + utf8proc_ssize_t written = 0; + const utf8proc_uint16_t *entry = &utf8proc_sequences[seqindex & 0x3FFF]; + int len = seqindex >> 14; + if (len >= 3) { + len = *entry; + entry++; + } + for (; len >= 0; entry++, len--) { + utf8proc_int32_t entry_cp = seqindex_decode_entry(&entry); + + written += utf8proc_decompose_char(entry_cp, dst+written, + (bufsize > written) ? (bufsize - written) : 0, options, + last_boundclass); + if (written < 0) return UTF8PROC_ERROR_OVERFLOW; + } + return written; +} + +UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_tolower(utf8proc_int32_t c) +{ + utf8proc_int32_t cl = utf8proc_get_property(c)->lowercase_seqindex; + return cl != UINT16_MAX ? seqindex_decode_index((utf8proc_uint32_t)cl) : c; +} + +UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_toupper(utf8proc_int32_t c) +{ + utf8proc_int32_t cu = utf8proc_get_property(c)->uppercase_seqindex; + return cu != UINT16_MAX ? seqindex_decode_index((utf8proc_uint32_t)cu) : c; +} + +UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_totitle(utf8proc_int32_t c) +{ + utf8proc_int32_t cu = utf8proc_get_property(c)->titlecase_seqindex; + return cu != UINT16_MAX ? seqindex_decode_index((utf8proc_uint32_t)cu) : c; +} + +UTF8PROC_DLLEXPORT int utf8proc_islower(utf8proc_int32_t c) +{ + const utf8proc_property_t *p = utf8proc_get_property(c); + return p->lowercase_seqindex != p->uppercase_seqindex && p->lowercase_seqindex == UINT16_MAX; +} + +UTF8PROC_DLLEXPORT int utf8proc_isupper(utf8proc_int32_t c) +{ + const utf8proc_property_t *p = utf8proc_get_property(c); + return p->lowercase_seqindex != p->uppercase_seqindex && p->uppercase_seqindex == UINT16_MAX && p->category != UTF8PROC_CATEGORY_LT; +} + +/* return a character width analogous to wcwidth (except portable and + hopefully less buggy than most system wcwidth functions). */ +UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) { + return utf8proc_get_property(c)->charwidth; +} + +UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) { + return (utf8proc_category_t) utf8proc_get_property(c)->category; +} + +UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) { + static const char s[][3] = {"Cn","Lu","Ll","Lt","Lm","Lo","Mn","Mc","Me","Nd","Nl","No","Pc","Pd","Ps","Pe","Pi","Pf","Po","Sm","Sc","Sk","So","Zs","Zl","Zp","Cc","Cf","Cs","Co"}; + return s[utf8proc_category(c)]; +} + +#define utf8proc_decompose_lump(replacement_uc) \ + return utf8proc_decompose_char((replacement_uc), dst, bufsize, \ + options & ~(unsigned int)UTF8PROC_LUMP, last_boundclass) + +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) { + const utf8proc_property_t *property; + utf8proc_propval_t category; + utf8proc_int32_t hangul_sindex; + if (uc < 0 || uc >= 0x110000) return UTF8PROC_ERROR_NOTASSIGNED; + property = unsafe_get_property(uc); + category = property->category; + hangul_sindex = uc - UTF8PROC_HANGUL_SBASE; + if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { + if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) { + utf8proc_int32_t hangul_tindex; + if (bufsize >= 1) { + dst[0] = UTF8PROC_HANGUL_LBASE + + hangul_sindex / UTF8PROC_HANGUL_NCOUNT; + if (bufsize >= 2) dst[1] = UTF8PROC_HANGUL_VBASE + + (hangul_sindex % UTF8PROC_HANGUL_NCOUNT) / UTF8PROC_HANGUL_TCOUNT; + } + hangul_tindex = hangul_sindex % UTF8PROC_HANGUL_TCOUNT; + if (!hangul_tindex) return 2; + if (bufsize >= 3) dst[2] = UTF8PROC_HANGUL_TBASE + hangul_tindex; + return 3; + } + } + if (options & UTF8PROC_REJECTNA) { + if (!category) return UTF8PROC_ERROR_NOTASSIGNED; + } + if (options & UTF8PROC_IGNORE) { + if (property->ignorable) return 0; + } + if (options & UTF8PROC_STRIPNA) { + if (!category) return 0; + } + if (options & UTF8PROC_LUMP) { + if (category == UTF8PROC_CATEGORY_ZS) utf8proc_decompose_lump(0x0020); + if (uc == 0x2018 || uc == 0x2019 || uc == 0x02BC || uc == 0x02C8) + utf8proc_decompose_lump(0x0027); + if (category == UTF8PROC_CATEGORY_PD || uc == 0x2212) + utf8proc_decompose_lump(0x002D); + if (uc == 0x2044 || uc == 0x2215) utf8proc_decompose_lump(0x002F); + if (uc == 0x2236) utf8proc_decompose_lump(0x003A); + if (uc == 0x2039 || uc == 0x2329 || uc == 0x3008) + utf8proc_decompose_lump(0x003C); + if (uc == 0x203A || uc == 0x232A || uc == 0x3009) + utf8proc_decompose_lump(0x003E); + if (uc == 0x2216) utf8proc_decompose_lump(0x005C); + if (uc == 0x02C4 || uc == 0x02C6 || uc == 0x2038 || uc == 0x2303) + utf8proc_decompose_lump(0x005E); + if (category == UTF8PROC_CATEGORY_PC || uc == 0x02CD) + utf8proc_decompose_lump(0x005F); + if (uc == 0x02CB) utf8proc_decompose_lump(0x0060); + if (uc == 0x2223) utf8proc_decompose_lump(0x007C); + if (uc == 0x223C) utf8proc_decompose_lump(0x007E); + if ((options & UTF8PROC_NLF2LS) && (options & UTF8PROC_NLF2PS)) { + if (category == UTF8PROC_CATEGORY_ZL || + category == UTF8PROC_CATEGORY_ZP) + utf8proc_decompose_lump(0x000A); + } + } + if (options & UTF8PROC_STRIPMARK) { + if (category == UTF8PROC_CATEGORY_MN || + category == UTF8PROC_CATEGORY_MC || + category == UTF8PROC_CATEGORY_ME) return 0; + } + if (options & UTF8PROC_CASEFOLD) { + if (property->casefold_seqindex != UINT16_MAX) { + return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass); + } + } + if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { + if (property->decomp_seqindex != UINT16_MAX && + (!property->decomp_type || (options & UTF8PROC_COMPAT))) { + return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass); + } + } + if (options & UTF8PROC_CHARBOUND) { + utf8proc_bool boundary; + boundary = grapheme_break_extended(0, property->boundclass, 0, property->indic_conjunct_break, + last_boundclass); + if (boundary) { + if (bufsize >= 1) dst[0] = -1; /* sentinel value for grapheme break */ + if (bufsize >= 2) dst[1] = uc; + return 2; + } + } + if (bufsize >= 1) *dst = uc; + return 1; +} + +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, + utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options +) { + return utf8proc_decompose_custom(str, strlen, buffer, bufsize, options, NULL, NULL); +} + +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, + utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options, + utf8proc_custom_func custom_func, void *custom_data +) { + /* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */ + utf8proc_ssize_t wpos = 0; + if ((options & UTF8PROC_COMPOSE) && (options & UTF8PROC_DECOMPOSE)) + return UTF8PROC_ERROR_INVALIDOPTS; + if ((options & UTF8PROC_STRIPMARK) && + !(options & UTF8PROC_COMPOSE) && !(options & UTF8PROC_DECOMPOSE)) + return UTF8PROC_ERROR_INVALIDOPTS; + { + utf8proc_int32_t uc; + utf8proc_ssize_t rpos = 0; + utf8proc_ssize_t decomp_result; + int boundclass = UTF8PROC_BOUNDCLASS_START; + while (1) { + if (options & UTF8PROC_NULLTERM) { + rpos += utf8proc_iterate(str + rpos, -1, &uc); + /* checking of return value is not necessary, + as 'uc' is < 0 in case of error */ + if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; + if (rpos < 0) return UTF8PROC_ERROR_OVERFLOW; + if (uc == 0) break; + } else { + if (rpos >= strlen) break; + rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc); + if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; + } + if (custom_func != NULL) { + uc = custom_func(uc, custom_data); /* user-specified custom mapping */ + } + decomp_result = utf8proc_decompose_char( + uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options, + &boundclass + ); + if (decomp_result < 0) return decomp_result; + wpos += decomp_result; + /* prohibiting integer overflows due to too long strings: */ + if (wpos < 0 || + wpos > (utf8proc_ssize_t)(SSIZE_MAX/sizeof(utf8proc_int32_t)/2)) + return UTF8PROC_ERROR_OVERFLOW; + } + } + if ((options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) && bufsize >= wpos) { + utf8proc_ssize_t pos = 0; + while (pos < wpos-1) { + utf8proc_int32_t uc1, uc2; + const utf8proc_property_t *property1, *property2; + uc1 = buffer[pos]; + uc2 = buffer[pos+1]; + property1 = unsafe_get_property(uc1); + property2 = unsafe_get_property(uc2); + if (property1->combining_class > property2->combining_class && + property2->combining_class > 0) { + buffer[pos] = uc2; + buffer[pos+1] = uc1; + if (pos > 0) pos--; else pos++; + } else { + pos++; + } + } + } + return wpos; +} + +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) { + /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored */ + if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) { + utf8proc_ssize_t rpos; + utf8proc_ssize_t wpos = 0; + utf8proc_int32_t uc; + for (rpos = 0; rpos < length; rpos++) { + uc = buffer[rpos]; + if (uc == 0x000D && rpos < length-1 && buffer[rpos+1] == 0x000A) rpos++; + if (uc == 0x000A || uc == 0x000D || uc == 0x0085 || + ((options & UTF8PROC_STRIPCC) && (uc == 0x000B || uc == 0x000C))) { + if (options & UTF8PROC_NLF2LS) { + if (options & UTF8PROC_NLF2PS) { + buffer[wpos++] = 0x000A; + } else { + buffer[wpos++] = 0x2028; + } + } else { + if (options & UTF8PROC_NLF2PS) { + buffer[wpos++] = 0x2029; + } else { + buffer[wpos++] = 0x0020; + } + } + } else if ((options & UTF8PROC_STRIPCC) && + (uc < 0x0020 || (uc >= 0x007F && uc < 0x00A0))) { + if (uc == 0x0009) buffer[wpos++] = 0x0020; + } else { + buffer[wpos++] = uc; + } + } + length = wpos; + } + if (options & UTF8PROC_COMPOSE) { + utf8proc_int32_t *starter = NULL; + utf8proc_int32_t current_char; + const utf8proc_property_t *starter_property = NULL, *current_property; + utf8proc_propval_t max_combining_class = -1; + utf8proc_ssize_t rpos; + utf8proc_ssize_t wpos = 0; + utf8proc_int32_t composition; + for (rpos = 0; rpos < length; rpos++) { + current_char = buffer[rpos]; + current_property = unsafe_get_property(current_char); + if (starter && current_property->combining_class > max_combining_class) { + /* combination perhaps possible */ + utf8proc_int32_t hangul_lindex; + utf8proc_int32_t hangul_sindex; + hangul_lindex = *starter - UTF8PROC_HANGUL_LBASE; + if (hangul_lindex >= 0 && hangul_lindex < UTF8PROC_HANGUL_LCOUNT) { + utf8proc_int32_t hangul_vindex; + hangul_vindex = current_char - UTF8PROC_HANGUL_VBASE; + if (hangul_vindex >= 0 && hangul_vindex < UTF8PROC_HANGUL_VCOUNT) { + *starter = UTF8PROC_HANGUL_SBASE + + (hangul_lindex * UTF8PROC_HANGUL_VCOUNT + hangul_vindex) * + UTF8PROC_HANGUL_TCOUNT; + starter_property = NULL; + continue; + } + } + hangul_sindex = *starter - UTF8PROC_HANGUL_SBASE; + if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT && + (hangul_sindex % UTF8PROC_HANGUL_TCOUNT) == 0) { + utf8proc_int32_t hangul_tindex; + hangul_tindex = current_char - UTF8PROC_HANGUL_TBASE; + if (hangul_tindex >= 0 && hangul_tindex < UTF8PROC_HANGUL_TCOUNT) { + *starter += hangul_tindex; + starter_property = NULL; + continue; + } + } + if (!starter_property) { + starter_property = unsafe_get_property(*starter); + } + if (starter_property->comb_index < 0x8000 && + current_property->comb_index != UINT16_MAX && + current_property->comb_index >= 0x8000) { + int sidx = starter_property->comb_index; + int idx = current_property->comb_index & 0x3FFF; + if (idx >= utf8proc_combinations[sidx] && idx <= utf8proc_combinations[sidx + 1] ) { + idx += sidx + 2 - utf8proc_combinations[sidx]; + if (current_property->comb_index & 0x4000) { + composition = (utf8proc_combinations[idx] << 16) | utf8proc_combinations[idx+1]; + } else + composition = utf8proc_combinations[idx]; + + if (composition > 0 && (!(options & UTF8PROC_STABLE) || + !(unsafe_get_property(composition)->comp_exclusion))) { + *starter = composition; + starter_property = NULL; + continue; + } + } + } + } + buffer[wpos] = current_char; + if (current_property->combining_class) { + if (current_property->combining_class > max_combining_class) { + max_combining_class = current_property->combining_class; + } + } else { + starter = buffer + wpos; + starter_property = NULL; + max_combining_class = -1; + } + wpos++; + } + length = wpos; + } + return length; +} + +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) { + /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored + ASSERT: 'buffer' has one spare byte of free space at the end! */ + length = utf8proc_normalize_utf32(buffer, length, options); + if (length < 0) return length; + { + utf8proc_ssize_t rpos, wpos = 0; + utf8proc_int32_t uc; + if (options & UTF8PROC_CHARBOUND) { + for (rpos = 0; rpos < length; rpos++) { + uc = buffer[rpos]; + wpos += charbound_encode_char(uc, ((utf8proc_uint8_t *)buffer) + wpos); + } + } else { + for (rpos = 0; rpos < length; rpos++) { + uc = buffer[rpos]; + wpos += utf8proc_encode_char(uc, ((utf8proc_uint8_t *)buffer) + wpos); + } + } + ((utf8proc_uint8_t *)buffer)[wpos] = 0; + return wpos; + } +} + +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options +) { + return utf8proc_map_custom(str, strlen, dstptr, options, NULL, NULL); +} + +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options, + utf8proc_custom_func custom_func, void *custom_data +) { + utf8proc_int32_t *buffer; + utf8proc_ssize_t result; + *dstptr = NULL; + result = utf8proc_decompose_custom(str, strlen, NULL, 0, options, custom_func, custom_data); + if (result < 0) return result; + buffer = (utf8proc_int32_t *) malloc(((utf8proc_size_t)result) * sizeof(utf8proc_int32_t) + 1); + if (!buffer) return UTF8PROC_ERROR_NOMEM; + result = utf8proc_decompose_custom(str, strlen, buffer, result, options, custom_func, custom_data); + if (result < 0) { + free(buffer); + return result; + } + result = utf8proc_reencode(buffer, result, options); + if (result < 0) { + free(buffer); + return result; + } + { + utf8proc_int32_t *newptr; + newptr = (utf8proc_int32_t *) realloc(buffer, (size_t)result+1); + if (newptr) buffer = newptr; + } + *dstptr = (utf8proc_uint8_t *)buffer; + return result; +} + +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) { + utf8proc_uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_DECOMPOSE); + return retval; +} + +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) { + utf8proc_uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_COMPOSE); + return retval; +} + +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) { + utf8proc_uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT); + return retval; +} + +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) { + utf8proc_uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_COMPOSE | UTF8PROC_COMPAT); + return retval; +} + +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC_Casefold(const utf8proc_uint8_t *str) { + utf8proc_uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_COMPOSE | UTF8PROC_COMPAT | UTF8PROC_CASEFOLD | UTF8PROC_IGNORE); + return retval; +} diff --git a/src/common/thirdparty/utf8proc/utf8proc.h b/src/common/thirdparty/utf8proc/utf8proc.h new file mode 100644 index 00000000000..0bd44524828 --- /dev/null +++ b/src/common/thirdparty/utf8proc/utf8proc.h @@ -0,0 +1,745 @@ +/* + * Copyright (c) 2014-2021 Steven G. Johnson, Jiahao Chen, Peter Colberg, Tony Kelman, Scott P. Jones, and other contributors. + * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany + * + * 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. + */ + + +/** + * @mainpage + * + * utf8proc is a free/open-source (MIT/expat licensed) C library + * providing Unicode normalization, case-folding, and other operations + * for strings in the UTF-8 encoding, supporting up-to-date Unicode versions. + * See the utf8proc home page (http://julialang.org/utf8proc/) + * for downloads and other information, or the source code on github + * (https://github.com/JuliaLang/utf8proc). + * + * For the utf8proc API documentation, see: @ref utf8proc.h + * + * The features of utf8proc include: + * + * - Transformation of strings (utf8proc_map()) to: + * - decompose (@ref UTF8PROC_DECOMPOSE) or compose (@ref UTF8PROC_COMPOSE) Unicode combining characters (http://en.wikipedia.org/wiki/Combining_character) + * - canonicalize Unicode compatibility characters (@ref UTF8PROC_COMPAT) + * - strip "ignorable" (@ref UTF8PROC_IGNORE) characters, control characters (@ref UTF8PROC_STRIPCC), or combining characters such as accents (@ref UTF8PROC_STRIPMARK) + * - case-folding (@ref UTF8PROC_CASEFOLD) + * - Unicode normalization: utf8proc_NFD(), utf8proc_NFC(), utf8proc_NFKD(), utf8proc_NFKC() + * - Detecting grapheme boundaries (utf8proc_grapheme_break() and @ref UTF8PROC_CHARBOUND) + * - Character-width computation: utf8proc_charwidth() + * - Classification of characters by Unicode category: utf8proc_category() and utf8proc_category_string() + * - Encode (utf8proc_encode_char()) and decode (utf8proc_iterate()) Unicode codepoints to/from UTF-8. + */ + +/** @file */ + +#ifndef UTF8PROC_H +#define UTF8PROC_H + +#define UTF8PROC_STATIC + +/** @name API version + * + * The utf8proc API version MAJOR.MINOR.PATCH, following + * semantic-versioning rules (http://semver.org) based on API + * compatibility. + * + * This is also returned at runtime by utf8proc_version(); however, the + * runtime version may append a string like "-dev" to the version number + * for prerelease versions. + * + * @note The shared-library version number in the Makefile + * (and CMakeLists.txt, and MANIFEST) may be different, + * being based on ABI compatibility rather than API compatibility. + */ +/** @{ */ +/** The MAJOR version number (increased when backwards API compatibility is broken). */ +#define UTF8PROC_VERSION_MAJOR 2 +/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */ +#define UTF8PROC_VERSION_MINOR 9 +/** The PATCH version (increased for fixes that do not change the API). */ +#define UTF8PROC_VERSION_PATCH 0 +/** @} */ + +#include + +#if defined(_MSC_VER) && _MSC_VER < 1800 +// MSVC prior to 2013 lacked stdbool.h and inttypes.h +typedef signed char utf8proc_int8_t; +typedef unsigned char utf8proc_uint8_t; +typedef short utf8proc_int16_t; +typedef unsigned short utf8proc_uint16_t; +typedef int utf8proc_int32_t; +typedef unsigned int utf8proc_uint32_t; +# ifdef _WIN64 +typedef __int64 utf8proc_ssize_t; +typedef unsigned __int64 utf8proc_size_t; +# else +typedef int utf8proc_ssize_t; +typedef unsigned int utf8proc_size_t; +# endif +# ifndef __cplusplus +// emulate C99 bool +typedef unsigned char utf8proc_bool; +# ifndef __bool_true_false_are_defined +# define false 0 +# define true 1 +# define __bool_true_false_are_defined 1 +# endif +# else +typedef bool utf8proc_bool; +# endif +#else +# include +# include +# include +typedef int8_t utf8proc_int8_t; +typedef uint8_t utf8proc_uint8_t; +typedef int16_t utf8proc_int16_t; +typedef uint16_t utf8proc_uint16_t; +typedef int32_t utf8proc_int32_t; +typedef uint32_t utf8proc_uint32_t; +typedef size_t utf8proc_size_t; +typedef ptrdiff_t utf8proc_ssize_t; +typedef bool utf8proc_bool; +#endif +#include + +#ifdef UTF8PROC_STATIC +# define UTF8PROC_DLLEXPORT +#else +# ifdef _WIN32 +# ifdef UTF8PROC_EXPORTS +# define UTF8PROC_DLLEXPORT __declspec(dllexport) +# else +# define UTF8PROC_DLLEXPORT __declspec(dllimport) +# endif +# elif __GNUC__ >= 4 +# define UTF8PROC_DLLEXPORT __attribute__ ((visibility("default"))) +# else +# define UTF8PROC_DLLEXPORT +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Option flags used by several functions in the library. + */ +typedef enum { + /** The given UTF-8 input is NULL terminated. */ + UTF8PROC_NULLTERM = (1<<0), + /** Unicode Versioning Stability has to be respected. */ + UTF8PROC_STABLE = (1<<1), + /** Compatibility decomposition (i.e. formatting information is lost). */ + UTF8PROC_COMPAT = (1<<2), + /** Return a result with decomposed characters. */ + UTF8PROC_COMPOSE = (1<<3), + /** Return a result with decomposed characters. */ + UTF8PROC_DECOMPOSE = (1<<4), + /** Strip "default ignorable characters" such as SOFT-HYPHEN or ZERO-WIDTH-SPACE. */ + UTF8PROC_IGNORE = (1<<5), + /** Return an error, if the input contains unassigned codepoints. */ + UTF8PROC_REJECTNA = (1<<6), + /** + * Indicating that NLF-sequences (LF, CRLF, CR, NEL) are representing a + * line break, and should be converted to the codepoint for line + * separation (LS). + */ + UTF8PROC_NLF2LS = (1<<7), + /** + * Indicating that NLF-sequences are representing a paragraph break, and + * should be converted to the codepoint for paragraph separation + * (PS). + */ + UTF8PROC_NLF2PS = (1<<8), + /** Indicating that the meaning of NLF-sequences is unknown. */ + UTF8PROC_NLF2LF = (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS), + /** Strips and/or convers control characters. + * + * NLF-sequences are transformed into space, except if one of the + * NLF2LS/PS/LF options is given. HorizontalTab (HT) and FormFeed (FF) + * are treated as a NLF-sequence in this case. All other control + * characters are simply removed. + */ + UTF8PROC_STRIPCC = (1<<9), + /** + * Performs unicode case folding, to be able to do a case-insensitive + * string comparison. + */ + UTF8PROC_CASEFOLD = (1<<10), + /** + * Inserts 0xFF bytes at the beginning of each sequence which is + * representing a single grapheme cluster (see UAX#29). + */ + UTF8PROC_CHARBOUND = (1<<11), + /** Lumps certain characters together. + * + * E.g. HYPHEN U+2010 and MINUS U+2212 to ASCII "-". See lump.md for details. + * + * If NLF2LF is set, this includes a transformation of paragraph and + * line separators to ASCII line-feed (LF). + */ + UTF8PROC_LUMP = (1<<12), + /** Strips all character markings. + * + * This includes non-spacing, spacing and enclosing (i.e. accents). + * @note This option works only with @ref UTF8PROC_COMPOSE or + * @ref UTF8PROC_DECOMPOSE + */ + UTF8PROC_STRIPMARK = (1<<13), + /** + * Strip unassigned codepoints. + */ + UTF8PROC_STRIPNA = (1<<14), +} utf8proc_option_t; + +/** @name Error codes + * Error codes being returned by almost all functions. + */ +/** @{ */ +/** Memory could not be allocated. */ +#define UTF8PROC_ERROR_NOMEM -1 +/** The given string is too long to be processed. */ +#define UTF8PROC_ERROR_OVERFLOW -2 +/** The given string is not a legal UTF-8 string. */ +#define UTF8PROC_ERROR_INVALIDUTF8 -3 +/** The @ref UTF8PROC_REJECTNA flag was set and an unassigned codepoint was found. */ +#define UTF8PROC_ERROR_NOTASSIGNED -4 +/** Invalid options have been used. */ +#define UTF8PROC_ERROR_INVALIDOPTS -5 +/** @} */ + +/* @name Types */ + +/** Holds the value of a property. */ +typedef utf8proc_int16_t utf8proc_propval_t; + +/** Struct containing information about a codepoint. */ +typedef struct utf8proc_property_struct { + /** + * Unicode category. + * @see utf8proc_category_t. + */ + utf8proc_propval_t category; + utf8proc_propval_t combining_class; + /** + * Bidirectional class. + * @see utf8proc_bidi_class_t. + */ + utf8proc_propval_t bidi_class; + /** + * @anchor Decomposition type. + * @see utf8proc_decomp_type_t. + */ + utf8proc_propval_t decomp_type; + utf8proc_uint16_t decomp_seqindex; + utf8proc_uint16_t casefold_seqindex; + utf8proc_uint16_t uppercase_seqindex; + utf8proc_uint16_t lowercase_seqindex; + utf8proc_uint16_t titlecase_seqindex; + utf8proc_uint16_t comb_index; + unsigned bidi_mirrored:1; + unsigned comp_exclusion:1; + /** + * Can this codepoint be ignored? + * + * Used by utf8proc_decompose_char() when @ref UTF8PROC_IGNORE is + * passed as an option. + */ + unsigned ignorable:1; + unsigned control_boundary:1; + /** The width of the codepoint. */ + unsigned charwidth:2; + unsigned pad:2; + /** + * Boundclass. + * @see utf8proc_boundclass_t. + */ + unsigned boundclass:6; + unsigned indic_conjunct_break:2; +} utf8proc_property_t; + +/** Unicode categories. */ +typedef enum { + UTF8PROC_CATEGORY_CN = 0, /**< Other, not assigned */ + UTF8PROC_CATEGORY_LU = 1, /**< Letter, uppercase */ + UTF8PROC_CATEGORY_LL = 2, /**< Letter, lowercase */ + UTF8PROC_CATEGORY_LT = 3, /**< Letter, titlecase */ + UTF8PROC_CATEGORY_LM = 4, /**< Letter, modifier */ + UTF8PROC_CATEGORY_LO = 5, /**< Letter, other */ + UTF8PROC_CATEGORY_MN = 6, /**< Mark, nonspacing */ + UTF8PROC_CATEGORY_MC = 7, /**< Mark, spacing combining */ + UTF8PROC_CATEGORY_ME = 8, /**< Mark, enclosing */ + UTF8PROC_CATEGORY_ND = 9, /**< Number, decimal digit */ + UTF8PROC_CATEGORY_NL = 10, /**< Number, letter */ + UTF8PROC_CATEGORY_NO = 11, /**< Number, other */ + UTF8PROC_CATEGORY_PC = 12, /**< Punctuation, connector */ + UTF8PROC_CATEGORY_PD = 13, /**< Punctuation, dash */ + UTF8PROC_CATEGORY_PS = 14, /**< Punctuation, open */ + UTF8PROC_CATEGORY_PE = 15, /**< Punctuation, close */ + UTF8PROC_CATEGORY_PI = 16, /**< Punctuation, initial quote */ + UTF8PROC_CATEGORY_PF = 17, /**< Punctuation, final quote */ + UTF8PROC_CATEGORY_PO = 18, /**< Punctuation, other */ + UTF8PROC_CATEGORY_SM = 19, /**< Symbol, math */ + UTF8PROC_CATEGORY_SC = 20, /**< Symbol, currency */ + UTF8PROC_CATEGORY_SK = 21, /**< Symbol, modifier */ + UTF8PROC_CATEGORY_SO = 22, /**< Symbol, other */ + UTF8PROC_CATEGORY_ZS = 23, /**< Separator, space */ + UTF8PROC_CATEGORY_ZL = 24, /**< Separator, line */ + UTF8PROC_CATEGORY_ZP = 25, /**< Separator, paragraph */ + UTF8PROC_CATEGORY_CC = 26, /**< Other, control */ + UTF8PROC_CATEGORY_CF = 27, /**< Other, format */ + UTF8PROC_CATEGORY_CS = 28, /**< Other, surrogate */ + UTF8PROC_CATEGORY_CO = 29, /**< Other, private use */ +} utf8proc_category_t; + +/** Bidirectional character classes. */ +typedef enum { + UTF8PROC_BIDI_CLASS_L = 1, /**< Left-to-Right */ + UTF8PROC_BIDI_CLASS_LRE = 2, /**< Left-to-Right Embedding */ + UTF8PROC_BIDI_CLASS_LRO = 3, /**< Left-to-Right Override */ + UTF8PROC_BIDI_CLASS_R = 4, /**< Right-to-Left */ + UTF8PROC_BIDI_CLASS_AL = 5, /**< Right-to-Left Arabic */ + UTF8PROC_BIDI_CLASS_RLE = 6, /**< Right-to-Left Embedding */ + UTF8PROC_BIDI_CLASS_RLO = 7, /**< Right-to-Left Override */ + UTF8PROC_BIDI_CLASS_PDF = 8, /**< Pop Directional Format */ + UTF8PROC_BIDI_CLASS_EN = 9, /**< European Number */ + UTF8PROC_BIDI_CLASS_ES = 10, /**< European Separator */ + UTF8PROC_BIDI_CLASS_ET = 11, /**< European Number Terminator */ + UTF8PROC_BIDI_CLASS_AN = 12, /**< Arabic Number */ + UTF8PROC_BIDI_CLASS_CS = 13, /**< Common Number Separator */ + UTF8PROC_BIDI_CLASS_NSM = 14, /**< Nonspacing Mark */ + UTF8PROC_BIDI_CLASS_BN = 15, /**< Boundary Neutral */ + UTF8PROC_BIDI_CLASS_B = 16, /**< Paragraph Separator */ + UTF8PROC_BIDI_CLASS_S = 17, /**< Segment Separator */ + UTF8PROC_BIDI_CLASS_WS = 18, /**< Whitespace */ + UTF8PROC_BIDI_CLASS_ON = 19, /**< Other Neutrals */ + UTF8PROC_BIDI_CLASS_LRI = 20, /**< Left-to-Right Isolate */ + UTF8PROC_BIDI_CLASS_RLI = 21, /**< Right-to-Left Isolate */ + UTF8PROC_BIDI_CLASS_FSI = 22, /**< First Strong Isolate */ + UTF8PROC_BIDI_CLASS_PDI = 23, /**< Pop Directional Isolate */ +} utf8proc_bidi_class_t; + +/** Decomposition type. */ +typedef enum { + UTF8PROC_DECOMP_TYPE_FONT = 1, /**< Font */ + UTF8PROC_DECOMP_TYPE_NOBREAK = 2, /**< Nobreak */ + UTF8PROC_DECOMP_TYPE_INITIAL = 3, /**< Initial */ + UTF8PROC_DECOMP_TYPE_MEDIAL = 4, /**< Medial */ + UTF8PROC_DECOMP_TYPE_FINAL = 5, /**< Final */ + UTF8PROC_DECOMP_TYPE_ISOLATED = 6, /**< Isolated */ + UTF8PROC_DECOMP_TYPE_CIRCLE = 7, /**< Circle */ + UTF8PROC_DECOMP_TYPE_SUPER = 8, /**< Super */ + UTF8PROC_DECOMP_TYPE_SUB = 9, /**< Sub */ + UTF8PROC_DECOMP_TYPE_VERTICAL = 10, /**< Vertical */ + UTF8PROC_DECOMP_TYPE_WIDE = 11, /**< Wide */ + UTF8PROC_DECOMP_TYPE_NARROW = 12, /**< Narrow */ + UTF8PROC_DECOMP_TYPE_SMALL = 13, /**< Small */ + UTF8PROC_DECOMP_TYPE_SQUARE = 14, /**< Square */ + UTF8PROC_DECOMP_TYPE_FRACTION = 15, /**< Fraction */ + UTF8PROC_DECOMP_TYPE_COMPAT = 16, /**< Compat */ +} utf8proc_decomp_type_t; + +/** Boundclass property. (TR29) */ +typedef enum { + UTF8PROC_BOUNDCLASS_START = 0, /**< Start */ + UTF8PROC_BOUNDCLASS_OTHER = 1, /**< Other */ + UTF8PROC_BOUNDCLASS_CR = 2, /**< Cr */ + UTF8PROC_BOUNDCLASS_LF = 3, /**< Lf */ + UTF8PROC_BOUNDCLASS_CONTROL = 4, /**< Control */ + UTF8PROC_BOUNDCLASS_EXTEND = 5, /**< Extend */ + UTF8PROC_BOUNDCLASS_L = 6, /**< L */ + UTF8PROC_BOUNDCLASS_V = 7, /**< V */ + UTF8PROC_BOUNDCLASS_T = 8, /**< T */ + UTF8PROC_BOUNDCLASS_LV = 9, /**< Lv */ + UTF8PROC_BOUNDCLASS_LVT = 10, /**< Lvt */ + UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR = 11, /**< Regional indicator */ + UTF8PROC_BOUNDCLASS_SPACINGMARK = 12, /**< Spacingmark */ + UTF8PROC_BOUNDCLASS_PREPEND = 13, /**< Prepend */ + UTF8PROC_BOUNDCLASS_ZWJ = 14, /**< Zero Width Joiner */ + + /* the following are no longer used in Unicode 11, but we keep + the constants here for backward compatibility */ + UTF8PROC_BOUNDCLASS_E_BASE = 15, /**< Emoji Base */ + UTF8PROC_BOUNDCLASS_E_MODIFIER = 16, /**< Emoji Modifier */ + UTF8PROC_BOUNDCLASS_GLUE_AFTER_ZWJ = 17, /**< Glue_After_ZWJ */ + UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */ + + /* the Extended_Pictographic property is used in the Unicode 11 + grapheme-boundary rules, so we store it in the boundclass field */ + UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC = 19, + UTF8PROC_BOUNDCLASS_E_ZWG = 20, /* UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC + ZWJ */ +} utf8proc_boundclass_t; + +/** Indic_Conjunct_Break property. (TR44) */ +typedef enum { + UTF8PROC_INDIC_CONJUNCT_BREAK_NONE = 0, + UTF8PROC_INDIC_CONJUNCT_BREAK_LINKER = 1, + UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT = 2, + UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND = 3, +} utf8proc_indic_conjunct_break_t; + +/** + * Function pointer type passed to utf8proc_map_custom() and + * utf8proc_decompose_custom(), which is used to specify a user-defined + * mapping of codepoints to be applied in conjunction with other mappings. + */ +typedef utf8proc_int32_t (*utf8proc_custom_func)(utf8proc_int32_t codepoint, void *data); + +/** + * Array containing the byte lengths of a UTF-8 encoded codepoint based + * on the first byte. + */ +UTF8PROC_DLLEXPORT extern const utf8proc_int8_t utf8proc_utf8class[256]; + +/** + * Returns the utf8proc API version as a string MAJOR.MINOR.PATCH + * (http://semver.org format), possibly with a "-dev" suffix for + * development versions. + */ +UTF8PROC_DLLEXPORT const char *utf8proc_version(void); + +/** + * Returns the utf8proc supported Unicode version as a string MAJOR.MINOR.PATCH. + */ +UTF8PROC_DLLEXPORT const char *utf8proc_unicode_version(void); + +/** + * Returns an informative error string for the given utf8proc error code + * (e.g. the error codes returned by utf8proc_map()). + */ +UTF8PROC_DLLEXPORT const char *utf8proc_errmsg(utf8proc_ssize_t errcode); + +/** + * Reads a single codepoint from the UTF-8 sequence being pointed to by `str`. + * The maximum number of bytes read is `strlen`, unless `strlen` is + * negative (in which case up to 4 bytes are read). + * + * If a valid codepoint could be read, it is stored in the variable + * pointed to by `codepoint_ref`, otherwise that variable will be set to -1. + * In case of success, the number of bytes read is returned; otherwise, a + * negative error code is returned. + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_iterate(const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *codepoint_ref); + +/** + * Check if a codepoint is valid (regardless of whether it has been + * assigned a value by the current Unicode standard). + * + * @return 1 if the given `codepoint` is valid and otherwise return 0. + */ +UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_codepoint_valid(utf8proc_int32_t codepoint); + +/** + * Encodes the codepoint as an UTF-8 string in the byte array pointed + * to by `dst`. This array must be at least 4 bytes long. + * + * In case of success the number of bytes written is returned, and + * otherwise 0 is returned. + * + * This function does not check whether `codepoint` is valid Unicode. + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t codepoint, utf8proc_uint8_t *dst); + +/** + * Look up the properties for a given codepoint. + * + * @param codepoint The Unicode codepoint. + * + * @returns + * A pointer to a (constant) struct containing information about + * the codepoint. + * @par + * If the codepoint is unassigned or invalid, a pointer to a special struct is + * returned in which `category` is 0 (@ref UTF8PROC_CATEGORY_CN). + */ +UTF8PROC_DLLEXPORT const utf8proc_property_t *utf8proc_get_property(utf8proc_int32_t codepoint); + +/** Decompose a codepoint into an array of codepoints. + * + * @param codepoint the codepoint. + * @param dst the destination buffer. + * @param bufsize the size of the destination buffer. + * @param options one or more of the following flags: + * - @ref UTF8PROC_REJECTNA - return an error `codepoint` is unassigned + * - @ref UTF8PROC_IGNORE - strip "default ignorable" codepoints + * - @ref UTF8PROC_CASEFOLD - apply Unicode casefolding + * - @ref UTF8PROC_COMPAT - replace certain codepoints with their + * compatibility decomposition + * - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster + * - @ref UTF8PROC_LUMP - lump certain different codepoints together + * - @ref UTF8PROC_STRIPMARK - remove all character marks + * - @ref UTF8PROC_STRIPNA - remove unassigned codepoints + * @param last_boundclass + * Pointer to an integer variable containing + * the previous codepoint's (boundclass + indic_conjunct_break << 1) if the @ref UTF8PROC_CHARBOUND + * option is used. If the string is being processed in order, this can be initialized to 0 for + * the beginning of the string, and is thereafter updated automatically. Otherwise, this parameter is ignored. + * + * @return + * In case of success, the number of codepoints written is returned; in case + * of an error, a negative error code is returned (utf8proc_errmsg()). + * @par + * If the number of written codepoints would be bigger than `bufsize`, the + * required buffer size is returned, while the buffer will be overwritten with + * undefined data. + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char( + utf8proc_int32_t codepoint, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, + utf8proc_option_t options, int *last_boundclass +); + +/** + * The same as utf8proc_decompose_char(), but acts on a whole UTF-8 + * string and orders the decomposed sequences correctly. + * + * If the @ref UTF8PROC_NULLTERM flag in `options` is set, processing + * will be stopped, when a NULL byte is encountered, otherwise `strlen` + * bytes are processed. The result (in the form of 32-bit unicode + * codepoints) is written into the buffer being pointed to by + * `buffer` (which must contain at least `bufsize` entries). In case of + * success, the number of codepoints written is returned; in case of an + * error, a negative error code is returned (utf8proc_errmsg()). + * See utf8proc_decompose_custom() to supply additional transformations. + * + * If the number of written codepoints would be bigger than `bufsize`, the + * required buffer size is returned, while the buffer will be overwritten with + * undefined data. + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, + utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options +); + +/** + * The same as utf8proc_decompose(), but also takes a `custom_func` mapping function + * that is called on each codepoint in `str` before any other transformations + * (along with a `custom_data` pointer that is passed through to `custom_func`). + * The `custom_func` argument is ignored if it is `NULL`. See also utf8proc_map_custom(). + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, + utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options, + utf8proc_custom_func custom_func, void *custom_data +); + +/** + * Normalizes the sequence of `length` codepoints pointed to by `buffer` + * in-place (i.e., the result is also stored in `buffer`). + * + * @param buffer the (native-endian UTF-32) unicode codepoints to re-encode. + * @param length the length (in codepoints) of the buffer. + * @param options a bitwise or (`|`) of one or more of the following flags: + * - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS + * - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS + * - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF + * - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters + * - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite + * codepoints + * - @ref UTF8PROC_STABLE - prohibit combining characters that would violate + * the unicode versioning stability + * + * @return + * In case of success, the length (in codepoints) of the normalized UTF-32 string is + * returned; otherwise, a negative error code is returned (utf8proc_errmsg()). + * + * @warning The entries of the array pointed to by `str` have to be in the + * range `0x0000` to `0x10FFFF`. Otherwise, the program might crash! + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options); + +/** + * Reencodes the sequence of `length` codepoints pointed to by `buffer` + * UTF-8 data in-place (i.e., the result is also stored in `buffer`). + * Can optionally normalize the UTF-32 sequence prior to UTF-8 conversion. + * + * @param buffer the (native-endian UTF-32) unicode codepoints to re-encode. + * @param length the length (in codepoints) of the buffer. + * @param options a bitwise or (`|`) of one or more of the following flags: + * - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS + * - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS + * - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF + * - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters + * - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite + * codepoints + * - @ref UTF8PROC_STABLE - prohibit combining characters that would violate + * the unicode versioning stability + * - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster + * + * @return + * In case of success, the length (in bytes) of the resulting nul-terminated + * UTF-8 string is returned; otherwise, a negative error code is returned + * (utf8proc_errmsg()). + * + * @warning The amount of free space pointed to by `buffer` must + * exceed the amount of the input data by one byte, and the + * entries of the array pointed to by `str` have to be in the + * range `0x0000` to `0x10FFFF`. Otherwise, the program might crash! + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options); + +/** + * Given a pair of consecutive codepoints, return whether a grapheme break is + * permitted between them (as defined by the extended grapheme clusters in UAX#29). + * + * @param codepoint1 The first codepoint. + * @param codepoint2 The second codepoint, occurring consecutively after `codepoint1`. + * @param state Beginning with Version 29 (Unicode 9.0.0), this algorithm requires + * state to break graphemes. This state can be passed in as a pointer + * in the `state` argument and should initially be set to 0. If the + * state is not passed in (i.e. a null pointer is passed), UAX#29 rules + * GB10/12/13 which require this state will not be applied, essentially + * matching the rules in Unicode 8.0.0. + * + * @warning If the state parameter is used, `utf8proc_grapheme_break_stateful` must + * be called IN ORDER on ALL potential breaks in a string. However, it + * is safe to reset the state to zero after a grapheme break. + */ +UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break_stateful( + utf8proc_int32_t codepoint1, utf8proc_int32_t codepoint2, utf8proc_int32_t *state); + +/** + * Same as utf8proc_grapheme_break_stateful(), except without support for the + * Unicode 9 additions to the algorithm. Supported for legacy reasons. + */ +UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break( + utf8proc_int32_t codepoint1, utf8proc_int32_t codepoint2); + + +/** + * Given a codepoint `c`, return the codepoint of the corresponding + * lower-case character, if any; otherwise (if there is no lower-case + * variant, or if `c` is not a valid codepoint) return `c`. + */ +UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_tolower(utf8proc_int32_t c); + +/** + * Given a codepoint `c`, return the codepoint of the corresponding + * upper-case character, if any; otherwise (if there is no upper-case + * variant, or if `c` is not a valid codepoint) return `c`. + */ +UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_toupper(utf8proc_int32_t c); + +/** + * Given a codepoint `c`, return the codepoint of the corresponding + * title-case character, if any; otherwise (if there is no title-case + * variant, or if `c` is not a valid codepoint) return `c`. + */ +UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_totitle(utf8proc_int32_t c); + +/** + * Given a codepoint `c`, return `1` if the codepoint corresponds to a lower-case character + * and `0` otherwise. + */ +UTF8PROC_DLLEXPORT int utf8proc_islower(utf8proc_int32_t c); + +/** + * Given a codepoint `c`, return `1` if the codepoint corresponds to an upper-case character + * and `0` otherwise. + */ +UTF8PROC_DLLEXPORT int utf8proc_isupper(utf8proc_int32_t c); + +/** + * Given a codepoint, return a character width analogous to `wcwidth(codepoint)`, + * except that a width of 0 is returned for non-printable codepoints + * instead of -1 as in `wcwidth`. + * + * @note + * If you want to check for particular types of non-printable characters, + * (analogous to `isprint` or `iscntrl`), use utf8proc_category(). */ +UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t codepoint); + +/** + * Return the Unicode category for the codepoint (one of the + * @ref utf8proc_category_t constants.) + */ +UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t codepoint); + +/** + * Return the two-letter (nul-terminated) Unicode category string for + * the codepoint (e.g. `"Lu"` or `"Co"`). + */ +UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t codepoint); + +/** + * Maps the given UTF-8 string pointed to by `str` to a new UTF-8 + * string, allocated dynamically by `malloc` and returned via `dstptr`. + * + * If the @ref UTF8PROC_NULLTERM flag in the `options` field is set, + * the length is determined by a NULL terminator, otherwise the + * parameter `strlen` is evaluated to determine the string length, but + * in any case the result will be NULL terminated (though it might + * contain NULL characters with the string if `str` contained NULL + * characters). Other flags in the `options` field are passed to the + * functions defined above, and regarded as described. See also + * utf8proc_map_custom() to supply a custom codepoint transformation. + * + * In case of success the length of the new string is returned, + * otherwise a negative error code is returned. + * + * @note The memory of the new UTF-8 string will have been allocated + * with `malloc`, and should therefore be deallocated with `free`. + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options +); + +/** + * Like utf8proc_map(), but also takes a `custom_func` mapping function + * that is called on each codepoint in `str` before any other transformations + * (along with a `custom_data` pointer that is passed through to `custom_func`). + * The `custom_func` argument is ignored if it is `NULL`. + */ +UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom( + const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options, + utf8proc_custom_func custom_func, void *custom_data +); + +/** @name Unicode normalization + * + * Returns a pointer to newly allocated memory of a NFD, NFC, NFKD, NFKC or + * NFKC_Casefold normalized version of the null-terminated string `str`. These + * are shortcuts to calling utf8proc_map() with @ref UTF8PROC_NULLTERM + * combined with @ref UTF8PROC_STABLE and flags indicating the normalization. + */ +/** @{ */ +/** NFD normalization (@ref UTF8PROC_DECOMPOSE). */ +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str); +/** NFC normalization (@ref UTF8PROC_COMPOSE). */ +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str); +/** NFKD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */ +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str); +/** NFKC normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */ +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str); +/** + * NFKC_Casefold normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT + * and @ref UTF8PROC_CASEFOLD and @ref UTF8PROC_IGNORE). + **/ +UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC_Casefold(const utf8proc_uint8_t *str); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/thirdparty/utf8proc/utf8proc_data.c b/src/common/thirdparty/utf8proc/utf8proc_data.c new file mode 100644 index 00000000000..b26bcb3b6fc --- /dev/null +++ b/src/common/thirdparty/utf8proc/utf8proc_data.c @@ -0,0 +1,16960 @@ +static const utf8proc_uint16_t utf8proc_sequences[] = { + 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 32, 32, 776, 32, 772, + 50, 51, 32, 769, 956, 32, 807, 49, + 49, 8260, 52, 49, 8260, 50, 51, 8260, + 52, 65, 768, 224, 65, 769, 225, 65, + 770, 226, 65, 771, 227, 65, 776, 228, + 65, 778, 229, 230, 67, 807, 231, 69, + 768, 232, 69, 769, 233, 69, 770, 234, + 69, 776, 235, 73, 768, 236, 73, 769, + 237, 73, 770, 238, 73, 776, 239, 240, + 78, 771, 241, 79, 768, 242, 79, 769, + 243, 79, 770, 244, 79, 771, 245, 79, + 776, 246, 248, 85, 768, 249, 85, 769, + 250, 85, 770, 251, 85, 776, 252, 89, + 769, 253, 254, 115, 115, 97, 768, 97, + 769, 97, 770, 97, 771, 97, 776, 97, + 778, 99, 807, 101, 768, 101, 769, 101, + 770, 101, 776, 105, 768, 105, 769, 105, + 770, 105, 776, 110, 771, 111, 768, 111, + 769, 111, 770, 111, 771, 111, 776, 117, + 768, 117, 769, 117, 770, 117, 776, 121, + 769, 121, 776, 65, 772, 257, 97, 772, + 65, 774, 259, 97, 774, 65, 808, 261, + 97, 808, 67, 769, 263, 99, 769, 67, + 770, 265, 99, 770, 67, 775, 267, 99, + 775, 67, 780, 269, 99, 780, 68, 780, + 271, 100, 780, 273, 69, 772, 275, 101, + 772, 69, 774, 277, 101, 774, 69, 775, + 279, 101, 775, 69, 808, 281, 101, 808, + 69, 780, 283, 101, 780, 71, 770, 285, + 103, 770, 71, 774, 287, 103, 774, 71, + 775, 289, 103, 775, 71, 807, 291, 103, + 807, 72, 770, 293, 104, 770, 295, 73, + 771, 297, 105, 771, 73, 772, 299, 105, + 772, 73, 774, 301, 105, 774, 73, 808, + 303, 105, 808, 73, 775, 105, 775, 73, + 74, 307, 105, 106, 74, 770, 309, 106, + 770, 75, 807, 311, 107, 807, 76, 769, + 314, 108, 769, 76, 807, 316, 108, 807, + 76, 780, 318, 108, 780, 76, 183, 320, + 108, 183, 322, 78, 769, 324, 110, 769, + 78, 807, 326, 110, 807, 78, 780, 328, + 110, 780, 700, 110, 331, 79, 772, 333, + 111, 772, 79, 774, 335, 111, 774, 79, + 779, 337, 111, 779, 339, 82, 769, 341, + 114, 769, 82, 807, 343, 114, 807, 82, + 780, 345, 114, 780, 83, 769, 347, 115, + 769, 83, 770, 349, 115, 770, 83, 807, + 351, 115, 807, 83, 780, 353, 115, 780, + 84, 807, 355, 116, 807, 84, 780, 357, + 116, 780, 359, 85, 771, 361, 117, 771, + 85, 772, 363, 117, 772, 85, 774, 365, + 117, 774, 85, 778, 367, 117, 778, 85, + 779, 369, 117, 779, 85, 808, 371, 117, + 808, 87, 770, 373, 119, 770, 89, 770, + 375, 121, 770, 89, 776, 255, 90, 769, + 378, 122, 769, 90, 775, 380, 122, 775, + 90, 780, 382, 122, 780, 595, 387, 389, + 596, 392, 598, 599, 396, 477, 601, 603, + 402, 608, 611, 617, 616, 409, 623, 626, + 629, 79, 795, 417, 111, 795, 419, 421, + 640, 424, 643, 429, 648, 85, 795, 432, + 117, 795, 650, 651, 436, 438, 658, 441, + 445, 68, 381, 454, 68, 382, 100, 382, + 76, 74, 457, 76, 106, 108, 106, 78, + 74, 460, 78, 106, 110, 106, 65, 780, + 462, 97, 780, 73, 780, 464, 105, 780, + 79, 780, 466, 111, 780, 85, 780, 468, + 117, 780, 220, 772, 470, 252, 772, 220, + 769, 472, 252, 769, 220, 780, 474, 252, + 780, 220, 768, 476, 252, 768, 196, 772, + 479, 228, 772, 550, 772, 481, 551, 772, + 198, 772, 483, 230, 772, 485, 71, 780, + 487, 103, 780, 75, 780, 489, 107, 780, + 79, 808, 491, 111, 808, 490, 772, 493, + 491, 772, 439, 780, 495, 658, 780, 106, + 780, 68, 90, 499, 68, 122, 100, 122, + 71, 769, 501, 103, 769, 405, 447, 78, + 768, 505, 110, 768, 197, 769, 507, 229, + 769, 198, 769, 509, 230, 769, 216, 769, + 511, 248, 769, 65, 783, 513, 97, 783, + 65, 785, 515, 97, 785, 69, 783, 517, + 101, 783, 69, 785, 519, 101, 785, 73, + 783, 521, 105, 783, 73, 785, 523, 105, + 785, 79, 783, 525, 111, 783, 79, 785, + 527, 111, 785, 82, 783, 529, 114, 783, + 82, 785, 531, 114, 785, 85, 783, 533, + 117, 783, 85, 785, 535, 117, 785, 83, + 806, 537, 115, 806, 84, 806, 539, 116, + 806, 541, 72, 780, 543, 104, 780, 414, + 547, 549, 65, 775, 551, 97, 775, 69, + 807, 553, 101, 807, 214, 772, 555, 246, + 772, 213, 772, 557, 245, 772, 79, 775, + 559, 111, 775, 558, 772, 561, 559, 772, + 89, 772, 563, 121, 772, 11365, 572, 410, + 11366, 578, 384, 649, 652, 583, 585, 587, + 589, 591, 614, 633, 635, 641, 32, 774, + 32, 775, 32, 778, 32, 808, 32, 771, + 32, 779, 661, 768, 769, 787, 776, 769, + 953, 881, 883, 697, 887, 32, 837, 59, + 1011, 168, 769, 913, 769, 940, 183, 917, + 769, 941, 919, 769, 942, 921, 769, 943, + 927, 769, 972, 933, 769, 973, 937, 769, + 974, 970, 769, 953, 776, 769, 945, 946, + 947, 948, 949, 950, 951, 952, 954, 955, + 957, 958, 959, 960, 961, 963, 964, 965, + 966, 967, 968, 969, 921, 776, 970, 933, + 776, 971, 945, 769, 949, 769, 951, 769, + 953, 769, 971, 769, 965, 776, 769, 953, + 776, 965, 776, 959, 769, 965, 769, 969, + 769, 983, 933, 978, 769, 978, 776, 985, + 987, 989, 991, 993, 995, 997, 999, 1001, + 1003, 1005, 1007, 962, 920, 1016, 931, 1010, + 1019, 891, 892, 893, 1045, 768, 1104, 1045, + 776, 1105, 1106, 1043, 769, 1107, 1108, 1109, + 1110, 1030, 776, 1111, 1112, 1113, 1114, 1115, + 1050, 769, 1116, 1048, 768, 1117, 1059, 774, + 1118, 1119, 1072, 1073, 1074, 1075, 1076, 1077, + 1078, 1079, 1080, 1048, 774, 1081, 1082, 1083, + 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, + 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, + 1100, 1101, 1102, 1103, 1080, 774, 1077, 768, + 1077, 776, 1075, 769, 1110, 776, 1082, 769, + 1080, 768, 1091, 774, 1121, 1123, 1125, 1127, + 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1140, + 783, 1143, 1141, 783, 1145, 1147, 1149, 1151, + 1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, + 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, + 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, + 1209, 1211, 1213, 1215, 1231, 1046, 774, 1218, + 1078, 774, 1220, 1222, 1224, 1226, 1228, 1230, + 1040, 774, 1233, 1072, 774, 1040, 776, 1235, + 1072, 776, 1237, 1045, 774, 1239, 1077, 774, + 1241, 1240, 776, 1243, 1241, 776, 1046, 776, + 1245, 1078, 776, 1047, 776, 1247, 1079, 776, + 1249, 1048, 772, 1251, 1080, 772, 1048, 776, + 1253, 1080, 776, 1054, 776, 1255, 1086, 776, + 1257, 1256, 776, 1259, 1257, 776, 1069, 776, + 1261, 1101, 776, 1059, 772, 1263, 1091, 772, + 1059, 776, 1265, 1091, 776, 1059, 779, 1267, + 1091, 779, 1063, 776, 1269, 1095, 776, 1271, + 1067, 776, 1273, 1099, 776, 1275, 1277, 1279, + 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, + 1297, 1299, 1301, 1303, 1305, 1307, 1309, 1311, + 1313, 1315, 1317, 1319, 1321, 1323, 1325, 1327, + 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, + 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, + 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, + 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, + 1409, 1410, 1411, 1412, 1413, 1414, 1381, 1410, + 1575, 1619, 1575, 1620, 1608, 1620, 1575, 1621, + 1610, 1620, 1575, 1652, 1608, 1652, 1735, 1652, + 1610, 1652, 1749, 1620, 1729, 1620, 1746, 1620, + 2344, 2364, 2352, 2364, 2355, 2364, 2325, 2364, + 2326, 2364, 2327, 2364, 2332, 2364, 2337, 2364, + 2338, 2364, 2347, 2364, 2351, 2364, 2503, 2494, + 2503, 2519, 2465, 2492, 2466, 2492, 2479, 2492, + 2610, 2620, 2616, 2620, 2582, 2620, 2583, 2620, + 2588, 2620, 2603, 2620, 2887, 2902, 2887, 2878, + 2887, 2903, 2849, 2876, 2850, 2876, 2962, 3031, + 3014, 3006, 3015, 3006, 3014, 3031, 3142, 3158, + 3263, 3285, 3270, 3285, 3270, 3286, 3270, 3266, + 3274, 3285, 3398, 3390, 3399, 3390, 3398, 3415, + 3545, 3530, 3545, 3535, 3548, 3530, 3545, 3551, + 3661, 3634, 3789, 3762, 3755, 3737, 3755, 3745, + 3851, 3906, 4023, 3916, 4023, 3921, 4023, 3926, + 4023, 3931, 4023, 3904, 4021, 3953, 3954, 3953, + 3956, 4018, 3968, 4018, 3969, 4019, 3968, 4019, + 3969, 3953, 3968, 3986, 4023, 3996, 4023, 4001, + 4023, 4006, 4023, 4011, 4023, 3984, 4021, 4133, + 4142, 11520, 11521, 11522, 11523, 11524, 11525, 11526, + 11527, 11528, 11529, 11530, 11531, 11532, 11533, 11534, + 11535, 11536, 11537, 11538, 11539, 11540, 11541, 11542, + 11543, 11544, 11545, 11546, 11547, 11548, 11549, 11550, + 11551, 11552, 11553, 11554, 11555, 11556, 11557, 11559, + 11565, 4316, 5104, 5105, 5106, 5107, 5108, 5109, + 6917, 6965, 6919, 6965, 6921, 6965, 6923, 6965, + 6925, 6965, 6929, 6965, 6970, 6965, 6972, 6965, + 6974, 6965, 6975, 6965, 6978, 6965, 42571, 4304, + 4305, 4306, 4307, 4308, 4309, 4310, 4311, 4312, + 4313, 4314, 4315, 4317, 4318, 4319, 4320, 4321, + 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, + 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, + 4338, 4339, 4340, 4341, 4342, 4343, 4344, 4345, + 4346, 4349, 4350, 4351, 65, 198, 66, 68, + 69, 398, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 546, 80, 82, 84, 85, + 87, 592, 593, 7426, 604, 7446, 7447, 7453, + 7461, 594, 597, 607, 609, 613, 618, 7547, + 669, 621, 7557, 671, 625, 624, 627, 628, + 632, 642, 427, 7452, 656, 657, 65, 805, + 7681, 97, 805, 66, 775, 7683, 98, 775, + 66, 803, 7685, 98, 803, 66, 817, 7687, + 98, 817, 199, 769, 7689, 231, 769, 68, + 775, 7691, 100, 775, 68, 803, 7693, 100, + 803, 68, 817, 7695, 100, 817, 68, 807, + 7697, 100, 807, 68, 813, 7699, 100, 813, + 274, 768, 7701, 275, 768, 274, 769, 7703, + 275, 769, 69, 813, 7705, 101, 813, 69, + 816, 7707, 101, 816, 552, 774, 7709, 553, + 774, 70, 775, 7711, 102, 775, 71, 772, + 7713, 103, 772, 72, 775, 7715, 104, 775, + 72, 803, 7717, 104, 803, 72, 776, 7719, + 104, 776, 72, 807, 7721, 104, 807, 72, + 814, 7723, 104, 814, 73, 816, 7725, 105, + 816, 207, 769, 7727, 239, 769, 75, 769, + 7729, 107, 769, 75, 803, 7731, 107, 803, + 75, 817, 7733, 107, 817, 76, 803, 7735, + 108, 803, 7734, 772, 7737, 7735, 772, 76, + 817, 7739, 108, 817, 76, 813, 7741, 108, + 813, 77, 769, 7743, 109, 769, 77, 775, + 7745, 109, 775, 77, 803, 7747, 109, 803, + 78, 775, 7749, 110, 775, 78, 803, 7751, + 110, 803, 78, 817, 7753, 110, 817, 78, + 813, 7755, 110, 813, 213, 769, 7757, 245, + 769, 213, 776, 7759, 245, 776, 332, 768, + 7761, 333, 768, 332, 769, 7763, 333, 769, + 80, 769, 7765, 112, 769, 80, 775, 7767, + 112, 775, 82, 775, 7769, 114, 775, 82, + 803, 7771, 114, 803, 7770, 772, 7773, 7771, + 772, 82, 817, 7775, 114, 817, 83, 775, + 7777, 115, 775, 83, 803, 7779, 115, 803, + 346, 775, 7781, 347, 775, 352, 775, 7783, + 353, 775, 7778, 775, 7785, 7779, 775, 84, + 775, 7787, 116, 775, 84, 803, 7789, 116, + 803, 84, 817, 7791, 116, 817, 84, 813, + 7793, 116, 813, 85, 804, 7795, 117, 804, + 85, 816, 7797, 117, 816, 85, 813, 7799, + 117, 813, 360, 769, 7801, 361, 769, 362, + 776, 7803, 363, 776, 86, 771, 7805, 118, + 771, 86, 803, 7807, 118, 803, 87, 768, + 7809, 119, 768, 87, 769, 7811, 119, 769, + 87, 776, 7813, 119, 776, 87, 775, 7815, + 119, 775, 87, 803, 7817, 119, 803, 88, + 775, 7819, 120, 775, 88, 776, 7821, 120, + 776, 89, 775, 7823, 121, 775, 90, 770, + 7825, 122, 770, 90, 803, 7827, 122, 803, + 90, 817, 7829, 122, 817, 104, 817, 116, + 776, 119, 778, 121, 778, 97, 702, 383, + 775, 65, 803, 7841, 97, 803, 65, 777, + 7843, 97, 777, 194, 769, 7845, 226, 769, + 194, 768, 7847, 226, 768, 194, 777, 7849, + 226, 777, 194, 771, 7851, 226, 771, 7840, + 770, 7853, 7841, 770, 258, 769, 7855, 259, + 769, 258, 768, 7857, 259, 768, 258, 777, + 7859, 259, 777, 258, 771, 7861, 259, 771, + 7840, 774, 7863, 7841, 774, 69, 803, 7865, + 101, 803, 69, 777, 7867, 101, 777, 69, + 771, 7869, 101, 771, 202, 769, 7871, 234, + 769, 202, 768, 7873, 234, 768, 202, 777, + 7875, 234, 777, 202, 771, 7877, 234, 771, + 7864, 770, 7879, 7865, 770, 73, 777, 7881, + 105, 777, 73, 803, 7883, 105, 803, 79, + 803, 7885, 111, 803, 79, 777, 7887, 111, + 777, 212, 769, 7889, 244, 769, 212, 768, + 7891, 244, 768, 212, 777, 7893, 244, 777, + 212, 771, 7895, 244, 771, 7884, 770, 7897, + 7885, 770, 416, 769, 7899, 417, 769, 416, + 768, 7901, 417, 768, 416, 777, 7903, 417, + 777, 416, 771, 7905, 417, 771, 416, 803, + 7907, 417, 803, 85, 803, 7909, 117, 803, + 85, 777, 7911, 117, 777, 431, 769, 7913, + 432, 769, 431, 768, 7915, 432, 768, 431, + 777, 7917, 432, 777, 431, 771, 7919, 432, + 771, 431, 803, 7921, 432, 803, 89, 768, + 7923, 121, 768, 89, 803, 7925, 121, 803, + 89, 777, 7927, 121, 777, 89, 771, 7929, + 121, 771, 7931, 7933, 7935, 945, 787, 945, + 788, 7936, 768, 7937, 768, 7936, 769, 7937, + 769, 7936, 834, 7937, 834, 913, 787, 7936, + 913, 788, 7937, 7944, 768, 7938, 7945, 768, + 7939, 7944, 769, 7940, 7945, 769, 7941, 7944, + 834, 7942, 7945, 834, 7943, 949, 787, 949, + 788, 7952, 768, 7953, 768, 7952, 769, 7953, + 769, 917, 787, 7952, 917, 788, 7953, 7960, + 768, 7954, 7961, 768, 7955, 7960, 769, 7956, + 7961, 769, 7957, 951, 787, 951, 788, 7968, + 768, 7969, 768, 7968, 769, 7969, 769, 7968, + 834, 7969, 834, 919, 787, 7968, 919, 788, + 7969, 7976, 768, 7970, 7977, 768, 7971, 7976, + 769, 7972, 7977, 769, 7973, 7976, 834, 7974, + 7977, 834, 7975, 953, 787, 953, 788, 7984, + 768, 7985, 768, 7984, 769, 7985, 769, 7984, + 834, 7985, 834, 921, 787, 7984, 921, 788, + 7985, 7992, 768, 7986, 7993, 768, 7987, 7992, + 769, 7988, 7993, 769, 7989, 7992, 834, 7990, + 7993, 834, 7991, 959, 787, 959, 788, 8000, + 768, 8001, 768, 8000, 769, 8001, 769, 927, + 787, 8000, 927, 788, 8001, 8008, 768, 8002, + 8009, 768, 8003, 8008, 769, 8004, 8009, 769, + 8005, 965, 787, 965, 788, 8016, 768, 965, + 787, 768, 8017, 768, 8016, 769, 965, 787, + 769, 8017, 769, 8016, 834, 965, 787, 834, + 8017, 834, 933, 788, 8017, 8025, 768, 8019, + 8025, 769, 8021, 8025, 834, 8023, 969, 787, + 969, 788, 8032, 768, 8033, 768, 8032, 769, + 8033, 769, 8032, 834, 8033, 834, 937, 787, + 8032, 937, 788, 8033, 8040, 768, 8034, 8041, + 768, 8035, 8040, 769, 8036, 8041, 769, 8037, + 8040, 834, 8038, 8041, 834, 8039, 945, 768, + 949, 768, 951, 768, 953, 768, 959, 768, + 965, 768, 969, 768, 7936, 837, 7936, 953, + 7937, 837, 7937, 953, 7938, 837, 7938, 953, + 7939, 837, 7939, 953, 7940, 837, 7940, 953, + 7941, 837, 7941, 953, 7942, 837, 7942, 953, + 7943, 837, 7943, 953, 7944, 837, 7945, 837, + 7946, 837, 7947, 837, 7948, 837, 7949, 837, + 7950, 837, 7951, 837, 7968, 837, 7968, 953, + 7969, 837, 7969, 953, 7970, 837, 7970, 953, + 7971, 837, 7971, 953, 7972, 837, 7972, 953, + 7973, 837, 7973, 953, 7974, 837, 7974, 953, + 7975, 837, 7975, 953, 7976, 837, 7977, 837, + 7978, 837, 7979, 837, 7980, 837, 7981, 837, + 7982, 837, 7983, 837, 8032, 837, 8032, 953, + 8033, 837, 8033, 953, 8034, 837, 8034, 953, + 8035, 837, 8035, 953, 8036, 837, 8036, 953, + 8037, 837, 8037, 953, 8038, 837, 8038, 953, + 8039, 837, 8039, 953, 8040, 837, 8041, 837, + 8042, 837, 8043, 837, 8044, 837, 8045, 837, + 8046, 837, 8047, 837, 945, 774, 945, 772, + 8048, 837, 8048, 953, 945, 837, 945, 953, + 940, 837, 940, 953, 945, 834, 8118, 837, + 945, 834, 953, 913, 774, 8112, 913, 772, + 8113, 913, 768, 8048, 902, 8049, 913, 837, + 32, 787, 32, 834, 168, 834, 8052, 837, + 8052, 953, 951, 837, 951, 953, 942, 837, + 942, 953, 951, 834, 8134, 837, 951, 834, + 953, 917, 768, 8050, 904, 8051, 919, 768, + 8052, 905, 8053, 919, 837, 8127, 768, 8127, + 769, 8127, 834, 953, 774, 953, 772, 970, + 768, 953, 776, 768, 912, 953, 834, 970, + 834, 953, 776, 834, 921, 774, 8144, 921, + 772, 8145, 921, 768, 8054, 906, 8055, 8190, + 768, 8190, 769, 8190, 834, 965, 774, 965, + 772, 971, 768, 965, 776, 768, 944, 961, + 787, 961, 788, 965, 834, 971, 834, 965, + 776, 834, 933, 774, 8160, 933, 772, 8161, + 933, 768, 8058, 910, 8059, 929, 788, 8165, + 168, 768, 901, 96, 8060, 837, 8060, 953, + 969, 837, 969, 953, 974, 837, 974, 953, + 969, 834, 8182, 837, 969, 834, 953, 927, + 768, 8056, 908, 8057, 937, 768, 8060, 911, + 8061, 937, 837, 180, 32, 788, 8194, 8195, + 8208, 32, 819, 46, 46, 46, 46, 46, + 46, 8242, 8242, 8242, 8242, 8242, 8245, 8245, + 8245, 8245, 8245, 33, 33, 32, 773, 63, + 63, 63, 33, 33, 63, 3, 8242, 8242, + 8242, 8242, 48, 52, 53, 54, 55, 56, + 57, 43, 8722, 61, 40, 41, 82, 115, + 97, 47, 99, 97, 47, 115, 67, 176, + 67, 99, 47, 111, 99, 47, 117, 400, + 176, 70, 78, 111, 81, 83, 77, 84, + 69, 76, 84, 77, 90, 937, 197, 70, + 8526, 1488, 1489, 1490, 1491, 70, 65, 88, + 915, 928, 8721, 49, 8260, 55, 49, 8260, + 57, 3, 49, 8260, 49, 48, 49, 8260, + 51, 50, 8260, 51, 49, 8260, 53, 50, + 8260, 53, 51, 8260, 53, 52, 8260, 53, + 49, 8260, 54, 53, 8260, 54, 49, 8260, + 56, 51, 8260, 56, 53, 8260, 56, 55, + 8260, 56, 49, 8260, 8560, 73, 73, 8561, + 73, 73, 73, 8562, 73, 86, 8563, 86, + 8564, 86, 73, 8565, 86, 73, 73, 8566, + 3, 86, 73, 73, 73, 8567, 73, 88, + 8568, 88, 8569, 88, 73, 8570, 88, 73, + 73, 8571, 8572, 8573, 8574, 8575, 105, 105, + 105, 105, 105, 105, 118, 118, 105, 118, + 105, 105, 3, 118, 105, 105, 105, 105, + 120, 120, 105, 120, 105, 105, 8580, 48, + 8260, 51, 8592, 824, 8594, 824, 8596, 824, + 8656, 824, 8660, 824, 8658, 824, 8707, 824, + 8712, 824, 8715, 824, 8739, 824, 8741, 824, + 8747, 8747, 8747, 8747, 8747, 8750, 8750, 8750, + 8750, 8750, 8764, 824, 8771, 824, 8773, 824, + 8776, 824, 61, 824, 8801, 824, 8781, 824, + 60, 824, 62, 824, 8804, 824, 8805, 824, + 8818, 824, 8819, 824, 8822, 824, 8823, 824, + 8826, 824, 8827, 824, 8834, 824, 8835, 824, + 8838, 824, 8839, 824, 8866, 824, 8872, 824, + 8873, 824, 8875, 824, 8828, 824, 8829, 824, + 8849, 824, 8850, 824, 8882, 824, 8883, 824, + 8884, 824, 8885, 824, 12296, 12297, 49, 48, + 49, 49, 49, 50, 49, 51, 49, 52, + 49, 53, 49, 54, 49, 55, 49, 56, + 49, 57, 50, 48, 40, 49, 41, 40, + 50, 41, 40, 51, 41, 40, 52, 41, + 40, 53, 41, 40, 54, 41, 40, 55, + 41, 40, 56, 41, 40, 57, 41, 3, + 40, 49, 48, 41, 3, 40, 49, 49, + 41, 3, 40, 49, 50, 41, 3, 40, + 49, 51, 41, 3, 40, 49, 52, 41, + 3, 40, 49, 53, 41, 3, 40, 49, + 54, 41, 3, 40, 49, 55, 41, 3, + 40, 49, 56, 41, 3, 40, 49, 57, + 41, 3, 40, 50, 48, 41, 49, 46, + 50, 46, 51, 46, 52, 46, 53, 46, + 54, 46, 55, 46, 56, 46, 57, 46, + 49, 48, 46, 49, 49, 46, 49, 50, + 46, 49, 51, 46, 49, 52, 46, 49, + 53, 46, 49, 54, 46, 49, 55, 46, + 49, 56, 46, 49, 57, 46, 50, 48, + 46, 40, 97, 41, 40, 98, 41, 40, + 99, 41, 40, 100, 41, 40, 101, 41, + 40, 102, 41, 40, 103, 41, 40, 104, + 41, 40, 105, 41, 40, 106, 41, 40, + 107, 41, 40, 108, 41, 40, 109, 41, + 40, 110, 41, 40, 111, 41, 40, 112, + 41, 40, 113, 41, 40, 114, 41, 40, + 115, 41, 40, 116, 41, 40, 117, 41, + 40, 118, 41, 40, 119, 41, 40, 120, + 41, 40, 121, 41, 40, 122, 41, 9424, + 9425, 9426, 9427, 9428, 9429, 9430, 9431, 9432, + 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, + 9441, 83, 9442, 9443, 9444, 9445, 9446, 9447, + 89, 9448, 9449, 3, 8747, 8747, 8747, 8747, + 58, 58, 61, 61, 61, 61, 61, 61, + 10973, 824, 11312, 11313, 11314, 11315, 11316, 11317, + 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325, + 11326, 11327, 11328, 11329, 11330, 11331, 11332, 11333, + 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, + 11342, 11343, 11344, 11345, 11346, 11347, 11348, 11349, + 11350, 11351, 11352, 11353, 11354, 11355, 11356, 11357, + 11358, 11359, 11361, 619, 7549, 637, 11368, 11370, + 11372, 11379, 11382, 575, 576, 11393, 11395, 11397, + 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, + 11415, 11417, 11419, 11421, 11423, 11425, 11427, 11429, + 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, + 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, + 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, + 11479, 11481, 11483, 11485, 11487, 11489, 11491, 11500, + 11502, 11507, 11617, 27597, 40863, 19968, 20008, 20022, + 20031, 20057, 20101, 20108, 20128, 20154, 20799, 20837, + 20843, 20866, 20886, 20907, 20960, 20981, 20992, 21147, + 21241, 21269, 21274, 21304, 21313, 21340, 21353, 21378, + 21430, 21448, 21475, 22231, 22303, 22763, 22786, 22794, + 22805, 22823, 22899, 23376, 23424, 23544, 23567, 23586, + 23608, 23662, 23665, 24027, 24037, 24049, 24062, 24178, + 24186, 24191, 24308, 24318, 24331, 24339, 24400, 24417, + 24435, 24515, 25096, 25142, 25163, 25903, 25908, 25991, + 26007, 26020, 26041, 26080, 26085, 26352, 26376, 26408, + 27424, 27490, 27513, 27571, 27595, 27604, 27611, 27663, + 27668, 27700, 28779, 29226, 29238, 29243, 29247, 29255, + 29273, 29275, 29356, 29572, 29577, 29916, 29926, 29976, + 29983, 29992, 30000, 30091, 30098, 30326, 30333, 30382, + 30399, 30446, 30683, 30690, 30707, 31034, 31160, 31166, + 31348, 31435, 31481, 31859, 31992, 32566, 32593, 32650, + 32701, 32769, 32780, 32786, 32819, 32895, 32905, 33251, + 33258, 33267, 33276, 33292, 33307, 33311, 33390, 33394, + 33400, 34381, 34411, 34880, 34892, 34915, 35198, 35211, + 35282, 35328, 35895, 35910, 35925, 35960, 35997, 36196, + 36208, 36275, 36523, 36554, 36763, 36784, 36789, 37009, + 37193, 37318, 37324, 37329, 38263, 38272, 38428, 38582, + 38585, 38632, 38737, 38750, 38754, 38761, 38859, 38893, + 38899, 38913, 39080, 39131, 39135, 39318, 39321, 39340, + 39592, 39640, 39647, 39717, 39727, 39730, 39740, 39770, + 40165, 40565, 40575, 40613, 40635, 40643, 40653, 40657, + 40697, 40701, 40718, 40723, 40736, 40763, 40778, 40786, + 40845, 40860, 40864, 12306, 21316, 21317, 12363, 12441, + 12365, 12441, 12367, 12441, 12369, 12441, 12371, 12441, + 12373, 12441, 12375, 12441, 12377, 12441, 12379, 12441, + 12381, 12441, 12383, 12441, 12385, 12441, 12388, 12441, + 12390, 12441, 12392, 12441, 12399, 12441, 12399, 12442, + 12402, 12441, 12402, 12442, 12405, 12441, 12405, 12442, + 12408, 12441, 12408, 12442, 12411, 12441, 12411, 12442, + 12358, 12441, 32, 12441, 32, 12442, 12445, 12441, + 12424, 12426, 12459, 12441, 12461, 12441, 12463, 12441, + 12465, 12441, 12467, 12441, 12469, 12441, 12471, 12441, + 12473, 12441, 12475, 12441, 12477, 12441, 12479, 12441, + 12481, 12441, 12484, 12441, 12486, 12441, 12488, 12441, + 12495, 12441, 12495, 12442, 12498, 12441, 12498, 12442, + 12501, 12441, 12501, 12442, 12504, 12441, 12504, 12442, + 12507, 12441, 12507, 12442, 12454, 12441, 12527, 12441, + 12528, 12441, 12529, 12441, 12530, 12441, 12541, 12441, + 12467, 12488, 4352, 4353, 4522, 4354, 4524, 4525, + 4355, 4356, 4357, 4528, 4529, 4530, 4531, 4532, + 4533, 4378, 4358, 4359, 4360, 4385, 4361, 4362, + 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, + 4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, + 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, + 4465, 4466, 4467, 4468, 4469, 4448, 4372, 4373, + 4551, 4552, 4556, 4558, 4563, 4567, 4569, 4380, + 4573, 4575, 4381, 4382, 4384, 4386, 4387, 4391, + 4393, 4395, 4396, 4397, 4398, 4399, 4402, 4406, + 4416, 4423, 4428, 4593, 4594, 4439, 4440, 4441, + 4484, 4485, 4488, 4497, 4498, 4500, 4510, 4513, + 19977, 22235, 19978, 20013, 19979, 30002, 19993, 19969, + 22825, 22320, 40, 4352, 41, 40, 4354, 41, + 40, 4355, 41, 40, 4357, 41, 40, 4358, + 41, 40, 4359, 41, 40, 4361, 41, 40, + 4363, 41, 40, 4364, 41, 40, 4366, 41, + 40, 4367, 41, 40, 4368, 41, 40, 4369, + 41, 40, 4370, 41, 3, 40, 4352, 4449, + 41, 3, 40, 4354, 4449, 41, 3, 40, + 4355, 4449, 41, 3, 40, 4357, 4449, 41, + 3, 40, 4358, 4449, 41, 3, 40, 4359, + 4449, 41, 3, 40, 4361, 4449, 41, 3, + 40, 4363, 4449, 41, 3, 40, 4364, 4449, + 41, 3, 40, 4366, 4449, 41, 3, 40, + 4367, 4449, 41, 3, 40, 4368, 4449, 41, + 3, 40, 4369, 4449, 41, 3, 40, 4370, + 4449, 41, 3, 40, 4364, 4462, 41, 6, + 40, 4363, 4457, 4364, 4453, 4523, 41, 5, + 40, 4363, 4457, 4370, 4462, 41, 40, 19968, + 41, 40, 20108, 41, 40, 19977, 41, 40, + 22235, 41, 40, 20116, 41, 40, 20845, 41, + 40, 19971, 41, 40, 20843, 41, 40, 20061, + 41, 40, 21313, 41, 40, 26376, 41, 40, + 28779, 41, 40, 27700, 41, 40, 26408, 41, + 40, 37329, 41, 40, 22303, 41, 40, 26085, + 41, 40, 26666, 41, 40, 26377, 41, 40, + 31038, 41, 40, 21517, 41, 40, 29305, 41, + 40, 36001, 41, 40, 31069, 41, 40, 21172, + 41, 40, 20195, 41, 40, 21628, 41, 40, + 23398, 41, 40, 30435, 41, 40, 20225, 41, + 40, 36039, 41, 40, 21332, 41, 40, 31085, + 41, 40, 20241, 41, 40, 33258, 41, 40, + 33267, 41, 21839, 24188, 31631, 80, 84, 69, + 50, 49, 50, 50, 50, 51, 50, 52, + 50, 53, 50, 54, 50, 55, 50, 56, + 50, 57, 51, 48, 51, 49, 51, 50, + 51, 51, 51, 52, 51, 53, 4352, 4449, + 4354, 4449, 4355, 4449, 4357, 4449, 4358, 4449, + 4359, 4449, 4361, 4449, 4363, 4449, 4364, 4449, + 4366, 4449, 4367, 4449, 4368, 4449, 4369, 4449, + 4370, 4449, 4, 4366, 4449, 4535, 4352, 4457, + 3, 4364, 4462, 4363, 4468, 4363, 4462, 20116, + 20845, 19971, 20061, 26666, 26377, 31038, 21517, 29305, + 36001, 31069, 21172, 31192, 30007, 36969, 20778, 21360, + 27880, 38917, 20241, 20889, 27491, 24038, 21491, 21307, + 23447, 23398, 30435, 20225, 36039, 21332, 22812, 51, + 54, 51, 55, 51, 56, 51, 57, 52, + 48, 52, 49, 52, 50, 52, 51, 52, + 52, 52, 53, 52, 54, 52, 55, 52, + 56, 52, 57, 53, 48, 49, 26376, 50, + 26376, 51, 26376, 52, 26376, 53, 26376, 54, + 26376, 55, 26376, 56, 26376, 57, 26376, 49, + 48, 26376, 49, 49, 26376, 49, 50, 26376, + 72, 103, 101, 114, 103, 101, 86, 76, + 84, 68, 12450, 12452, 12454, 12456, 12458, 12459, + 12461, 12463, 12465, 12467, 12469, 12471, 12473, 12475, + 12477, 12479, 12481, 12484, 12486, 12488, 12490, 12491, + 12492, 12493, 12494, 12495, 12498, 12501, 12504, 12507, + 12510, 12511, 12512, 12513, 12514, 12516, 12518, 12520, + 12521, 12522, 12523, 12524, 12525, 12527, 12528, 12529, + 12530, 20196, 21644, 3, 12450, 12497, 12540, 12488, + 3, 12450, 12523, 12501, 12449, 3, 12450, 12531, + 12506, 12450, 12450, 12540, 12523, 3, 12452, 12491, + 12531, 12464, 12452, 12531, 12481, 12454, 12457, 12531, + 4, 12456, 12473, 12463, 12540, 12489, 3, 12456, + 12540, 12459, 12540, 12458, 12531, 12473, 12458, 12540, + 12512, 12459, 12452, 12522, 3, 12459, 12521, 12483, + 12488, 3, 12459, 12525, 12522, 12540, 12460, 12525, + 12531, 12460, 12531, 12510, 12462, 12460, 12462, 12491, + 12540, 3, 12461, 12517, 12522, 12540, 3, 12462, + 12523, 12480, 12540, 12461, 12525, 4, 12461, 12525, + 12464, 12521, 12512, 5, 12461, 12525, 12513, 12540, + 12488, 12523, 4, 12461, 12525, 12527, 12483, 12488, + 12464, 12521, 12512, 4, 12464, 12521, 12512, 12488, + 12531, 4, 12463, 12523, 12476, 12452, 12525, 3, + 12463, 12525, 12540, 12493, 12465, 12540, 12473, 12467, + 12523, 12490, 12467, 12540, 12509, 3, 12469, 12452, + 12463, 12523, 4, 12469, 12531, 12481, 12540, 12512, + 3, 12471, 12522, 12531, 12464, 12475, 12531, 12481, + 12475, 12531, 12488, 12480, 12540, 12473, 12487, 12471, + 12489, 12523, 12488, 12531, 12490, 12494, 12494, 12483, + 12488, 12495, 12452, 12484, 4, 12497, 12540, 12475, + 12531, 12488, 12497, 12540, 12484, 3, 12496, 12540, + 12524, 12523, 4, 12500, 12450, 12473, 12488, 12523, + 12500, 12463, 12523, 12500, 12467, 12499, 12523, 4, + 12501, 12449, 12521, 12483, 12489, 3, 12501, 12451, + 12540, 12488, 4, 12502, 12483, 12471, 12455, 12523, + 12501, 12521, 12531, 4, 12504, 12463, 12479, 12540, + 12523, 12506, 12477, 12506, 12491, 12498, 12504, 12523, + 12484, 12506, 12531, 12473, 12506, 12540, 12472, 12505, + 12540, 12479, 3, 12509, 12452, 12531, 12488, 12508, + 12523, 12488, 12507, 12531, 12509, 12531, 12489, 12507, + 12540, 12523, 12507, 12540, 12531, 3, 12510, 12452, + 12463, 12525, 12510, 12452, 12523, 12510, 12483, 12495, + 12510, 12523, 12463, 4, 12510, 12531, 12471, 12519, + 12531, 3, 12511, 12463, 12525, 12531, 12511, 12522, + 4, 12511, 12522, 12496, 12540, 12523, 12513, 12460, + 3, 12513, 12460, 12488, 12531, 3, 12513, 12540, + 12488, 12523, 12516, 12540, 12489, 12516, 12540, 12523, + 12518, 12450, 12531, 3, 12522, 12483, 12488, 12523, + 12522, 12521, 12523, 12500, 12540, 3, 12523, 12540, + 12502, 12523, 12524, 12512, 4, 12524, 12531, 12488, + 12466, 12531, 12527, 12483, 12488, 48, 28857, 49, + 28857, 50, 28857, 51, 28857, 52, 28857, 53, + 28857, 54, 28857, 55, 28857, 56, 28857, 57, + 28857, 49, 48, 28857, 49, 49, 28857, 49, + 50, 28857, 49, 51, 28857, 49, 52, 28857, + 49, 53, 28857, 49, 54, 28857, 49, 55, + 28857, 49, 56, 28857, 49, 57, 28857, 50, + 48, 28857, 50, 49, 28857, 50, 50, 28857, + 50, 51, 28857, 50, 52, 28857, 104, 80, + 97, 100, 97, 65, 85, 98, 97, 114, + 111, 86, 112, 99, 100, 109, 100, 109, + 178, 100, 109, 179, 73, 85, 24179, 25104, + 26157, 21644, 22823, 27491, 26126, 27835, 3, 26666, + 24335, 20250, 31038, 112, 65, 110, 65, 956, + 65, 109, 65, 107, 65, 75, 66, 77, + 66, 71, 66, 99, 97, 108, 3, 107, + 99, 97, 108, 112, 70, 110, 70, 956, + 70, 956, 103, 109, 103, 107, 103, 72, + 122, 107, 72, 122, 77, 72, 122, 71, + 72, 122, 84, 72, 122, 956, 8467, 109, + 8467, 100, 8467, 107, 8467, 102, 109, 110, + 109, 956, 109, 109, 109, 99, 109, 107, + 109, 109, 109, 178, 99, 109, 178, 109, + 178, 107, 109, 178, 109, 109, 179, 99, + 109, 179, 109, 179, 107, 109, 179, 109, + 8725, 115, 3, 109, 8725, 115, 178, 80, + 97, 107, 80, 97, 77, 80, 97, 71, + 80, 97, 114, 97, 100, 4, 114, 97, + 100, 8725, 115, 5, 114, 97, 100, 8725, + 115, 178, 112, 115, 110, 115, 956, 115, + 109, 115, 112, 86, 110, 86, 956, 86, + 109, 86, 107, 86, 77, 86, 112, 87, + 110, 87, 956, 87, 109, 87, 107, 87, + 77, 87, 107, 937, 77, 937, 3, 97, + 46, 109, 46, 66, 113, 99, 99, 99, + 100, 3, 67, 8725, 107, 103, 67, 111, + 46, 100, 66, 71, 121, 104, 97, 72, + 80, 105, 110, 75, 75, 75, 77, 107, + 116, 108, 109, 108, 110, 108, 111, 103, + 108, 120, 109, 98, 109, 105, 108, 109, + 111, 108, 80, 72, 3, 112, 46, 109, + 46, 80, 80, 77, 80, 82, 115, 114, + 83, 118, 87, 98, 86, 8725, 109, 65, + 8725, 109, 49, 26085, 50, 26085, 51, 26085, + 52, 26085, 53, 26085, 54, 26085, 55, 26085, + 56, 26085, 57, 26085, 49, 48, 26085, 49, + 49, 26085, 49, 50, 26085, 49, 51, 26085, + 49, 52, 26085, 49, 53, 26085, 49, 54, + 26085, 49, 55, 26085, 49, 56, 26085, 49, + 57, 26085, 50, 48, 26085, 50, 49, 26085, + 50, 50, 26085, 50, 51, 26085, 50, 52, + 26085, 50, 53, 26085, 50, 54, 26085, 50, + 55, 26085, 50, 56, 26085, 50, 57, 26085, + 51, 48, 26085, 51, 49, 26085, 103, 97, + 108, 42561, 42563, 42565, 42567, 42569, 42573, 42575, + 42577, 42579, 42581, 42583, 42585, 42587, 42589, 42591, + 42593, 42595, 42597, 42599, 42601, 42603, 42605, 42625, + 42627, 42629, 42631, 42633, 42635, 42637, 42639, 42641, + 42643, 42645, 42647, 42649, 42651, 42787, 42789, 42791, + 42793, 42795, 42797, 42799, 42803, 42805, 42807, 42809, + 42811, 42813, 42815, 42817, 42819, 42821, 42823, 42825, + 42827, 42829, 42831, 42833, 42835, 42837, 42839, 42841, + 42843, 42845, 42847, 42849, 42851, 42853, 42855, 42857, + 42859, 42861, 42863, 42874, 42876, 7545, 42879, 42881, + 42883, 42885, 42887, 42892, 42897, 42899, 42903, 42905, + 42907, 42909, 42911, 42913, 42915, 42917, 42919, 42921, + 620, 670, 647, 43859, 42933, 42935, 42937, 42939, + 42941, 42943, 42945, 42947, 42900, 7566, 42952, 42954, + 42961, 42967, 42969, 42998, 294, 43831, 43858, 653, + 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, + 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, + 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, + 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055, + 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, + 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, + 5072, 5073, 5074, 5075, 5076, 5077, 5078, 5079, + 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, + 5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, + 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, + 35912, 26356, 36040, 28369, 20018, 21477, 22865, 21895, + 22856, 25078, 30313, 32645, 34367, 34746, 35064, 37007, + 27138, 27931, 28889, 29662, 33853, 37226, 39409, 20098, + 21365, 27396, 29211, 34349, 40478, 23888, 28651, 34253, + 35172, 25289, 33240, 34847, 24266, 26391, 28010, 29436, + 37070, 20358, 20919, 21214, 25796, 27347, 29200, 30439, + 34310, 34396, 36335, 38706, 39791, 40442, 30860, 31103, + 32160, 33737, 37636, 35542, 22751, 24324, 31840, 32894, + 29282, 30922, 36034, 38647, 22744, 23650, 27155, 28122, + 28431, 32047, 32311, 38475, 21202, 32907, 20956, 20940, + 31260, 32190, 33777, 38517, 35712, 25295, 35582, 20025, + 23527, 24594, 29575, 30064, 21271, 30971, 20415, 24489, + 19981, 27852, 25976, 32034, 21443, 22622, 30465, 33865, + 35498, 27578, 27784, 25342, 33509, 25504, 30053, 20142, + 20841, 20937, 26753, 31975, 33391, 35538, 37327, 21237, + 21570, 24300, 26053, 28670, 31018, 38317, 39530, 40599, + 40654, 26310, 27511, 36706, 24180, 24976, 25088, 25754, + 28451, 29001, 29833, 31178, 32244, 32879, 36646, 34030, + 36899, 37706, 21015, 21155, 21693, 28872, 35010, 24265, + 24565, 25467, 27566, 31806, 29557, 20196, 22265, 23994, + 24604, 29618, 29801, 32666, 32838, 37428, 38646, 38728, + 38936, 20363, 31150, 37300, 38584, 24801, 20102, 20698, + 23534, 23615, 26009, 29134, 30274, 34044, 36988, 26248, + 38446, 21129, 26491, 26611, 27969, 28316, 29705, 30041, + 30827, 32016, 39006, 25134, 38520, 20523, 23833, 28138, + 36650, 24459, 24900, 26647, 38534, 21033, 21519, 23653, + 26131, 26446, 26792, 27877, 29702, 30178, 32633, 35023, + 35041, 38626, 21311, 28346, 21533, 29136, 29848, 34298, + 38563, 40023, 40607, 26519, 28107, 33256, 31520, 31890, + 29376, 28825, 35672, 20160, 33590, 21050, 20999, 24230, + 25299, 31958, 23429, 27934, 26292, 36667, 38477, 24275, + 20800, 21952, 22618, 26228, 20958, 29482, 30410, 31036, + 31070, 31077, 31119, 38742, 31934, 34322, 35576, 36920, + 37117, 39151, 39164, 39208, 40372, 37086, 38583, 20398, + 20711, 20813, 21193, 21220, 21329, 21917, 22022, 22120, + 22592, 22696, 23652, 24724, 24936, 24974, 25074, 25935, + 26082, 26257, 26757, 28023, 28186, 28450, 29038, 29227, + 29730, 30865, 31049, 31048, 31056, 31062, 31117, 31118, + 31296, 31361, 31680, 32265, 32321, 32626, 32773, 33261, + 33401, 33879, 35088, 35222, 35585, 35641, 36051, 36104, + 36790, 38627, 38911, 38971, 24693, 55376, 57070, 33304, + 20006, 20917, 20840, 20352, 20805, 20864, 21191, 21242, + 21845, 21913, 21986, 22707, 22852, 22868, 23138, 23336, + 24274, 24281, 24425, 24493, 24792, 24910, 24840, 24928, + 25140, 25540, 25628, 25682, 25942, 26395, 26454, 28379, + 28363, 28702, 30631, 29237, 29359, 29809, 29958, 30011, + 30237, 30239, 30427, 30452, 30538, 30528, 30924, 31409, + 31867, 32091, 32574, 33618, 33775, 34681, 35137, 35206, + 35519, 35531, 35565, 35722, 36664, 36978, 37273, 37494, + 38524, 38875, 38923, 39698, 55370, 56394, 55370, 56388, + 55372, 57301, 15261, 16408, 16441, 55380, 56905, 55383, + 56528, 55391, 57043, 40771, 40846, 102, 102, 102, + 105, 102, 108, 102, 102, 105, 102, 102, + 108, 383, 116, 115, 116, 1396, 1398, 1396, + 1381, 1396, 1387, 1406, 1398, 1396, 1389, 1497, + 1460, 1522, 1463, 1506, 1492, 1499, 1500, 1501, + 1512, 1514, 1513, 1473, 1513, 1474, 64329, 1473, + 64329, 1474, 1488, 1463, 1488, 1464, 1488, 1468, + 1489, 1468, 1490, 1468, 1491, 1468, 1492, 1468, + 1493, 1468, 1494, 1468, 1496, 1468, 1497, 1468, + 1498, 1468, 1499, 1468, 1500, 1468, 1502, 1468, + 1504, 1468, 1505, 1468, 1507, 1468, 1508, 1468, + 1510, 1468, 1511, 1468, 1512, 1468, 1513, 1468, + 1514, 1468, 1493, 1465, 1489, 1471, 1499, 1471, + 1508, 1471, 1488, 1500, 1649, 1659, 1662, 1664, + 1658, 1663, 1657, 1700, 1702, 1668, 1667, 1670, + 1671, 1677, 1676, 1678, 1672, 1688, 1681, 1705, + 1711, 1715, 1713, 1722, 1723, 1728, 1729, 1726, + 1746, 1747, 1709, 1735, 1734, 1736, 1655, 1739, + 1733, 1737, 1744, 1609, 1574, 1575, 1574, 1749, + 1574, 1608, 1574, 1735, 1574, 1734, 1574, 1736, + 1574, 1744, 1574, 1609, 1740, 1574, 1580, 1574, + 1581, 1574, 1605, 1574, 1610, 1576, 1580, 1576, + 1581, 1576, 1582, 1576, 1605, 1576, 1609, 1576, + 1610, 1578, 1580, 1578, 1581, 1578, 1582, 1578, + 1605, 1578, 1609, 1578, 1610, 1579, 1580, 1579, + 1605, 1579, 1609, 1579, 1610, 1580, 1581, 1580, + 1605, 1581, 1580, 1581, 1605, 1582, 1580, 1582, + 1581, 1582, 1605, 1587, 1580, 1587, 1581, 1587, + 1582, 1587, 1605, 1589, 1581, 1589, 1605, 1590, + 1580, 1590, 1581, 1590, 1582, 1590, 1605, 1591, + 1581, 1591, 1605, 1592, 1605, 1593, 1580, 1593, + 1605, 1594, 1580, 1594, 1605, 1601, 1580, 1601, + 1581, 1601, 1582, 1601, 1605, 1601, 1609, 1601, + 1610, 1602, 1581, 1602, 1605, 1602, 1609, 1602, + 1610, 1603, 1575, 1603, 1580, 1603, 1581, 1603, + 1582, 1603, 1604, 1603, 1605, 1603, 1609, 1603, + 1610, 1604, 1580, 1604, 1581, 1604, 1582, 1604, + 1605, 1604, 1609, 1604, 1610, 1605, 1580, 1605, + 1581, 1605, 1582, 1605, 1605, 1605, 1609, 1605, + 1610, 1606, 1580, 1606, 1581, 1606, 1582, 1606, + 1605, 1606, 1609, 1606, 1610, 1607, 1580, 1607, + 1605, 1607, 1609, 1607, 1610, 1610, 1580, 1610, + 1581, 1610, 1582, 1610, 1605, 1610, 1609, 1610, + 1610, 1584, 1648, 1585, 1648, 1609, 1648, 32, + 1612, 1617, 32, 1613, 1617, 32, 1614, 1617, + 32, 1615, 1617, 32, 1616, 1617, 32, 1617, + 1648, 1574, 1585, 1574, 1586, 1574, 1606, 1576, + 1585, 1576, 1586, 1576, 1606, 1578, 1585, 1578, + 1586, 1578, 1606, 1579, 1585, 1579, 1586, 1579, + 1606, 1605, 1575, 1606, 1585, 1606, 1586, 1606, + 1606, 1610, 1585, 1610, 1586, 1610, 1606, 1574, + 1582, 1574, 1607, 1576, 1607, 1578, 1607, 1589, + 1582, 1604, 1607, 1606, 1607, 1607, 1648, 1610, + 1607, 1579, 1607, 1587, 1607, 1588, 1605, 1588, + 1607, 1600, 1614, 1617, 1600, 1615, 1617, 1600, + 1616, 1617, 1591, 1609, 1591, 1610, 1593, 1609, + 1593, 1610, 1594, 1609, 1594, 1610, 1587, 1609, + 1587, 1610, 1588, 1609, 1588, 1610, 1581, 1609, + 1581, 1610, 1580, 1609, 1580, 1610, 1582, 1609, + 1582, 1610, 1589, 1609, 1589, 1610, 1590, 1609, + 1590, 1610, 1588, 1580, 1588, 1581, 1588, 1582, + 1588, 1585, 1587, 1585, 1589, 1585, 1590, 1585, + 1575, 1611, 1578, 1580, 1605, 1578, 1581, 1580, + 1578, 1581, 1605, 1578, 1582, 1605, 1578, 1605, + 1580, 1578, 1605, 1581, 1578, 1605, 1582, 1580, + 1605, 1581, 1581, 1605, 1610, 1581, 1605, 1609, + 1587, 1581, 1580, 1587, 1580, 1581, 1587, 1580, + 1609, 1587, 1605, 1581, 1587, 1605, 1580, 1587, + 1605, 1605, 1589, 1581, 1581, 1589, 1605, 1605, + 1588, 1581, 1605, 1588, 1580, 1610, 1588, 1605, + 1582, 1588, 1605, 1605, 1590, 1581, 1609, 1590, + 1582, 1605, 1591, 1605, 1581, 1591, 1605, 1605, + 1591, 1605, 1610, 1593, 1580, 1605, 1593, 1605, + 1605, 1593, 1605, 1609, 1594, 1605, 1605, 1594, + 1605, 1610, 1594, 1605, 1609, 1601, 1582, 1605, + 1602, 1605, 1581, 1602, 1605, 1605, 1604, 1581, + 1605, 1604, 1581, 1610, 1604, 1581, 1609, 1604, + 1580, 1580, 1604, 1582, 1605, 1604, 1605, 1581, + 1605, 1581, 1580, 1605, 1581, 1605, 1605, 1581, + 1610, 1605, 1580, 1581, 1605, 1580, 1605, 1605, + 1582, 1580, 1605, 1582, 1605, 1605, 1580, 1582, + 1607, 1605, 1580, 1607, 1605, 1605, 1606, 1581, + 1605, 1606, 1581, 1609, 1606, 1580, 1605, 1606, + 1580, 1609, 1606, 1605, 1610, 1606, 1605, 1609, + 1610, 1605, 1605, 1576, 1582, 1610, 1578, 1580, + 1610, 1578, 1580, 1609, 1578, 1582, 1610, 1578, + 1582, 1609, 1578, 1605, 1610, 1578, 1605, 1609, + 1580, 1605, 1610, 1580, 1581, 1609, 1580, 1605, + 1609, 1587, 1582, 1609, 1589, 1581, 1610, 1588, + 1581, 1610, 1590, 1581, 1610, 1604, 1580, 1610, + 1604, 1605, 1610, 1610, 1581, 1610, 1610, 1580, + 1610, 1610, 1605, 1610, 1605, 1605, 1610, 1602, + 1605, 1610, 1606, 1581, 1610, 1593, 1605, 1610, + 1603, 1605, 1610, 1606, 1580, 1581, 1605, 1582, + 1610, 1604, 1580, 1605, 1603, 1605, 1605, 1580, + 1581, 1610, 1581, 1580, 1610, 1605, 1580, 1610, + 1601, 1605, 1610, 1576, 1581, 1610, 1587, 1582, + 1610, 1606, 1580, 1610, 1589, 1604, 1746, 1602, + 1604, 1746, 3, 1575, 1604, 1604, 1607, 3, + 1575, 1603, 1576, 1585, 3, 1605, 1581, 1605, + 1583, 3, 1589, 1604, 1593, 1605, 3, 1585, + 1587, 1608, 1604, 3, 1593, 1604, 1610, 1607, + 3, 1608, 1587, 1604, 1605, 1589, 1604, 1609, + 17, 1589, 1604, 1609, 32, 1575, 1604, 1604, + 1607, 32, 1593, 1604, 1610, 1607, 32, 1608, + 1587, 1604, 1605, 7, 1580, 1604, 32, 1580, + 1604, 1575, 1604, 1607, 3, 1585, 1740, 1575, + 1604, 44, 12289, 12290, 58, 33, 63, 12310, + 12311, 8230, 8229, 8212, 8211, 95, 123, 125, + 12308, 12309, 12304, 12305, 12298, 12299, 12300, 12301, + 12302, 12303, 91, 93, 8254, 35, 38, 42, + 45, 60, 62, 92, 36, 37, 64, 32, + 1611, 1600, 1611, 32, 1612, 32, 1613, 32, + 1614, 1600, 1614, 32, 1615, 1600, 1615, 32, + 1616, 1600, 1616, 32, 1617, 1600, 1617, 32, + 1618, 1600, 1618, 1569, 1570, 1571, 1572, 1573, + 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, + 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, + 1590, 1591, 1592, 1593, 1594, 1601, 1602, 1603, + 1604, 1605, 1606, 1607, 1608, 1610, 1604, 1570, + 1604, 1571, 1604, 1573, 1604, 1575, 34, 39, + 47, 65345, 65346, 65347, 65348, 65349, 65350, 65351, + 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359, + 65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, + 65368, 65369, 65370, 94, 124, 126, 10629, 10630, + 12539, 12449, 12451, 12453, 12455, 12457, 12515, 12517, + 12519, 12483, 12540, 12531, 12441, 12442, 12644, 12593, + 12594, 12595, 12596, 12597, 12598, 12599, 12600, 12601, + 12602, 12603, 12604, 12605, 12606, 12607, 12608, 12609, + 12610, 12611, 12612, 12613, 12614, 12615, 12616, 12617, + 12618, 12619, 12620, 12621, 12622, 12623, 12624, 12625, + 12626, 12627, 12628, 12629, 12630, 12631, 12632, 12633, + 12634, 12635, 12636, 12637, 12638, 12639, 12640, 12641, + 12642, 12643, 162, 163, 172, 175, 166, 165, + 8361, 9474, 8592, 8593, 8594, 8595, 9632, 9675, + 55297, 56360, 55297, 56361, 55297, 56362, 55297, 56363, + 55297, 56364, 55297, 56365, 55297, 56366, 55297, 56367, + 55297, 56368, 55297, 56369, 55297, 56370, 55297, 56371, + 55297, 56372, 55297, 56373, 55297, 56374, 55297, 56375, + 55297, 56376, 55297, 56377, 55297, 56378, 55297, 56379, + 55297, 56380, 55297, 56381, 55297, 56382, 55297, 56383, + 55297, 56384, 55297, 56385, 55297, 56386, 55297, 56387, + 55297, 56388, 55297, 56389, 55297, 56390, 55297, 56391, + 55297, 56392, 55297, 56393, 55297, 56394, 55297, 56395, + 55297, 56396, 55297, 56397, 55297, 56398, 55297, 56399, + 55297, 56536, 55297, 56537, 55297, 56538, 55297, 56539, + 55297, 56540, 55297, 56541, 55297, 56542, 55297, 56543, + 55297, 56544, 55297, 56545, 55297, 56546, 55297, 56547, + 55297, 56548, 55297, 56549, 55297, 56550, 55297, 56551, + 55297, 56552, 55297, 56553, 55297, 56554, 55297, 56555, + 55297, 56556, 55297, 56557, 55297, 56558, 55297, 56559, + 55297, 56560, 55297, 56561, 55297, 56562, 55297, 56563, + 55297, 56564, 55297, 56565, 55297, 56566, 55297, 56567, + 55297, 56568, 55297, 56569, 55297, 56570, 55297, 56571, + 55297, 56727, 55297, 56728, 55297, 56729, 55297, 56730, + 55297, 56731, 55297, 56732, 55297, 56733, 55297, 56734, + 55297, 56735, 55297, 56736, 55297, 56737, 55297, 56739, + 55297, 56740, 55297, 56741, 55297, 56742, 55297, 56743, + 55297, 56744, 55297, 56745, 55297, 56746, 55297, 56747, + 55297, 56748, 55297, 56749, 55297, 56750, 55297, 56751, + 55297, 56752, 55297, 56753, 55297, 56755, 55297, 56756, + 55297, 56757, 55297, 56758, 55297, 56759, 55297, 56760, + 55297, 56761, 55297, 56763, 55297, 56764, 720, 721, + 665, 675, 43878, 677, 676, 7569, 600, 606, + 681, 612, 610, 667, 668, 615, 644, 682, + 683, 55351, 57092, 42894, 622, 55351, 57093, 654, + 55351, 57094, 630, 631, 634, 55351, 57096, 638, + 680, 678, 43879, 679, 11377, 655, 673, 674, + 664, 448, 449, 450, 55351, 57098, 55351, 57118, + 55299, 56512, 55299, 56513, 55299, 56514, 55299, 56515, + 55299, 56516, 55299, 56517, 55299, 56518, 55299, 56519, + 55299, 56520, 55299, 56521, 55299, 56522, 55299, 56523, + 55299, 56524, 55299, 56525, 55299, 56526, 55299, 56527, + 55299, 56528, 55299, 56529, 55299, 56530, 55299, 56531, + 55299, 56532, 55299, 56533, 55299, 56534, 55299, 56535, + 55299, 56536, 55299, 56537, 55299, 56538, 55299, 56539, + 55299, 56540, 55299, 56541, 55299, 56542, 55299, 56543, + 55299, 56544, 55299, 56545, 55299, 56546, 55299, 56547, + 55299, 56548, 55299, 56549, 55299, 56550, 55299, 56551, + 55299, 56552, 55299, 56553, 55299, 56554, 55299, 56555, + 55299, 56556, 55299, 56557, 55299, 56558, 55299, 56559, + 55299, 56560, 55299, 56561, 55299, 56562, 55300, 56473, + 55300, 56506, 55300, 56475, 55300, 56506, 55300, 56485, + 55300, 56506, 55300, 56625, 55300, 56615, 55300, 56626, + 55300, 56615, 55300, 57159, 55300, 57150, 55300, 57159, + 55300, 57175, 55301, 56505, 55301, 56506, 55301, 56505, + 55301, 56496, 55301, 56505, 55301, 56509, 55301, 56760, + 55301, 56751, 55301, 56761, 55301, 56751, 55302, 56512, + 55302, 56513, 55302, 56514, 55302, 56515, 55302, 56516, + 55302, 56517, 55302, 56518, 55302, 56519, 55302, 56520, + 55302, 56521, 55302, 56522, 55302, 56523, 55302, 56524, + 55302, 56525, 55302, 56526, 55302, 56527, 55302, 56528, + 55302, 56529, 55302, 56530, 55302, 56531, 55302, 56532, + 55302, 56533, 55302, 56534, 55302, 56535, 55302, 56536, + 55302, 56537, 55302, 56538, 55302, 56539, 55302, 56540, + 55302, 56541, 55302, 56542, 55302, 56543, 55302, 56629, + 55302, 56624, 55323, 56928, 55323, 56929, 55323, 56930, + 55323, 56931, 55323, 56932, 55323, 56933, 55323, 56934, + 55323, 56935, 55323, 56936, 55323, 56937, 55323, 56938, + 55323, 56939, 55323, 56940, 55323, 56941, 55323, 56942, + 55323, 56943, 55323, 56944, 55323, 56945, 55323, 56946, + 55323, 56947, 55323, 56948, 55323, 56949, 55323, 56950, + 55323, 56951, 55323, 56952, 55323, 56953, 55323, 56954, + 55323, 56955, 55323, 56956, 55323, 56957, 55323, 56958, + 55323, 56959, 55348, 56663, 55348, 56677, 55348, 56664, + 55348, 56677, 55348, 56671, 55348, 56686, 55348, 56671, + 55348, 56687, 55348, 56671, 55348, 56688, 55348, 56671, + 55348, 56689, 55348, 56671, 55348, 56690, 55348, 56761, + 55348, 56677, 55348, 56762, 55348, 56677, 55348, 56763, + 55348, 56686, 55348, 56764, 55348, 56686, 55348, 56763, + 55348, 56687, 55348, 56764, 55348, 56687, 305, 567, + 913, 914, 916, 917, 918, 919, 921, 922, + 923, 924, 925, 926, 927, 929, 1012, 932, + 934, 935, 936, 8711, 8706, 1013, 977, 1008, + 981, 1009, 982, 988, 55354, 56610, 55354, 56611, + 55354, 56612, 55354, 56613, 55354, 56614, 55354, 56615, + 55354, 56616, 55354, 56617, 55354, 56618, 55354, 56619, + 55354, 56620, 55354, 56621, 55354, 56622, 55354, 56623, + 55354, 56624, 55354, 56625, 55354, 56626, 55354, 56627, + 55354, 56628, 55354, 56629, 55354, 56630, 55354, 56631, + 55354, 56632, 55354, 56633, 55354, 56634, 55354, 56635, + 55354, 56636, 55354, 56637, 55354, 56638, 55354, 56639, + 55354, 56640, 55354, 56641, 55354, 56642, 55354, 56643, + 1646, 1697, 1647, 48, 46, 48, 44, 49, + 44, 50, 44, 51, 44, 52, 44, 53, + 44, 54, 44, 55, 44, 56, 44, 57, + 44, 40, 65, 41, 40, 66, 41, 40, + 67, 41, 40, 68, 41, 40, 69, 41, + 40, 70, 41, 40, 71, 41, 40, 72, + 41, 40, 73, 41, 40, 74, 41, 40, + 75, 41, 40, 76, 41, 40, 77, 41, + 40, 78, 41, 40, 79, 41, 40, 80, + 41, 40, 81, 41, 40, 82, 41, 40, + 83, 41, 40, 84, 41, 40, 85, 41, + 40, 86, 41, 40, 87, 41, 40, 88, + 41, 40, 89, 41, 40, 90, 41, 12308, + 83, 12309, 67, 68, 87, 90, 72, 86, + 83, 68, 83, 83, 80, 80, 86, 87, + 67, 77, 67, 77, 68, 77, 82, 68, + 74, 12411, 12363, 12467, 12467, 23383, 21452, 12487, + 22810, 35299, 20132, 26144, 28961, 21069, 24460, 20877, + 26032, 21021, 32066, 36009, 22768, 21561, 28436, 25237, + 25429, 36938, 25351, 25171, 31105, 31354, 21512, 28288, + 30003, 21106, 21942, 37197, 12308, 26412, 12309, 12308, + 19977, 12309, 12308, 20108, 12309, 12308, 23433, 12309, + 12308, 28857, 12309, 12308, 25171, 12309, 12308, 30423, + 12309, 12308, 21213, 12309, 12308, 25943, 12309, 24471, + 21487, 20029, 20024, 20033, 55360, 56610, 20320, 20411, + 20482, 20602, 20633, 20687, 13470, 55361, 56890, 20820, + 20836, 20855, 55361, 56604, 13497, 20839, 55361, 56651, + 20887, 20900, 20172, 20908, 55396, 56799, 20995, 13535, + 21051, 21062, 21111, 13589, 21253, 21254, 21321, 21338, + 21363, 21373, 21375, 55362, 56876, 28784, 21450, 21471, + 55362, 57187, 21483, 21489, 21510, 21662, 21560, 21576, + 21608, 21666, 21750, 21776, 21843, 21859, 21892, 21931, + 21939, 21954, 22294, 22295, 22097, 22132, 22766, 22478, + 22516, 22541, 22411, 22578, 22577, 22700, 55365, 56548, + 22770, 22775, 22790, 22818, 22882, 55365, 57000, 55365, + 57066, 23020, 23067, 23079, 23000, 23142, 14062, 14076, + 23304, 23358, 55366, 56776, 23491, 23512, 23539, 55366, + 57112, 23551, 23558, 24403, 14209, 23648, 23744, 23693, + 55367, 56804, 23875, 55367, 56806, 23918, 23915, 23932, + 24033, 24034, 14383, 24061, 24104, 24125, 24169, 14434, + 55368, 56707, 14460, 24240, 24243, 24246, 55400, 57234, + 55368, 57137, 33281, 24354, 14535, 55372, 57016, 55384, + 56794, 24418, 24427, 14563, 24474, 24525, 24535, 24569, + 24705, 14650, 14620, 55369, 57044, 24775, 24904, 24908, + 24954, 25010, 24996, 25007, 25054, 25104, 25115, 25181, + 25265, 25300, 25424, 55370, 57100, 25405, 25340, 25448, + 25475, 25572, 55370, 57329, 25634, 25541, 25513, 14894, + 25705, 25726, 25757, 25719, 14956, 25964, 55372, 56330, + 26083, 26360, 26185, 15129, 15112, 15076, 20882, 20885, + 26368, 26268, 32941, 17369, 26401, 26462, 26451, 55372, + 57283, 15177, 26618, 26501, 26706, 55373, 56429, 26766, + 26655, 26900, 26946, 27043, 27114, 27304, 55373, 56995, + 27355, 15384, 27425, 55374, 56487, 27476, 15438, 27506, + 27551, 27579, 55374, 56973, 55367, 56587, 55374, 57082, + 27726, 55375, 56508, 27839, 27853, 27751, 27926, 27966, + 28009, 28024, 28037, 55375, 56606, 27956, 28207, 28270, + 15667, 28359, 55375, 57041, 28153, 28526, 55375, 57182, + 55375, 57230, 28614, 28729, 28699, 15766, 28746, 28797, + 28791, 28845, 55361, 56613, 28997, 55376, 56931, 29084, + 55376, 57259, 29224, 29264, 55377, 56840, 29312, 29333, + 55377, 57141, 55378, 56340, 29562, 29579, 16044, 29605, + 16056, 29767, 29788, 29829, 29898, 16155, 29988, 55379, + 56374, 30014, 55379, 56466, 55368, 56735, 30224, 55379, + 57249, 55379, 57272, 55380, 56388, 16380, 16392, 55380, + 56563, 55380, 56562, 55380, 56601, 55380, 56627, 30494, + 30495, 30603, 16454, 16534, 55381, 56349, 30798, 16611, + 55381, 56870, 55381, 56986, 55381, 57029, 31211, 16687, + 31306, 31311, 55382, 56700, 55382, 56999, 31470, 16898, + 55382, 57259, 31686, 31689, 16935, 55383, 56448, 31954, + 17056, 31976, 31971, 32000, 55383, 57222, 32099, 17153, + 32199, 32258, 32325, 17204, 55384, 56872, 55384, 56903, + 17241, 55384, 57049, 32634, 55384, 57150, 32661, 32762, + 55385, 56538, 55385, 56611, 32864, 55385, 56744, 32880, + 55372, 57183, 17365, 32946, 33027, 17419, 33086, 23221, + 55385, 57255, 55385, 57269, 55372, 57235, 55372, 57244, + 33284, 36766, 17515, 33425, 33419, 33437, 21171, 33457, + 33459, 33469, 33510, 55386, 57148, 33565, 33635, 33709, + 33571, 33725, 33767, 33619, 33738, 33740, 33756, 55387, + 56374, 55387, 56683, 55387, 56533, 17707, 34033, 34035, + 34070, 55388, 57290, 34148, 55387, 57132, 17757, 17761, + 55387, 57265, 55388, 56530, 17771, 34384, 34407, 34409, + 34473, 34440, 34574, 34530, 34600, 34667, 34694, 17879, + 34785, 34817, 17913, 34912, 55389, 56935, 35031, 35038, + 17973, 35066, 13499, 55390, 56494, 55390, 56678, 18110, + 18119, 35488, 55391, 56488, 36011, 36033, 36123, 36215, + 55391, 57135, 55362, 56324, 36299, 36284, 36336, 55362, + 56542, 36564, 55393, 56786, 55393, 56813, 37012, 37105, + 37137, 55393, 57134, 37147, 37432, 37591, 37592, 37500, + 37881, 37909, 55394, 57338, 38283, 18837, 38327, 55395, + 56695, 18918, 38595, 23986, 38691, 55396, 56645, 55396, + 56858, 19054, 19062, 38880, 55397, 56330, 19122, 55397, + 56470, 38953, 55397, 56758, 39138, 19251, 39209, 39335, + 39362, 39422, 19406, 55398, 57136, 40000, 40189, 19662, + 19693, 40295, 55400, 56526, 19704, 55400, 56581, 55400, + 56846, 55400, 56977, 19798, 40702, 40709, 40719, 40726, + 55401, 56832, 170, 186, 7838, 192, 193, 194, + 195, 196, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 216, 217, 218, 219, 220, 221, + 222, 376, 256, 258, 260, 262, 264, 266, + 268, 270, 272, 274, 276, 278, 280, 282, + 284, 286, 288, 290, 292, 296, 298, 300, + 302, 306, 308, 310, 312, 313, 315, 317, + 319, 321, 323, 325, 327, 329, 330, 332, + 334, 336, 338, 340, 342, 344, 346, 348, + 350, 352, 354, 356, 358, 360, 362, 364, + 366, 368, 370, 372, 374, 377, 379, 381, + 579, 386, 388, 391, 395, 397, 401, 502, + 408, 573, 411, 544, 416, 418, 420, 423, + 426, 428, 431, 435, 437, 440, 442, 444, + 446, 503, 453, 452, 456, 455, 459, 458, + 461, 463, 465, 467, 469, 471, 473, 475, + 478, 480, 482, 484, 486, 488, 490, 492, + 494, 496, 498, 497, 500, 504, 506, 508, + 510, 512, 514, 516, 518, 520, 522, 524, + 526, 528, 530, 532, 534, 536, 538, 540, + 542, 545, 548, 550, 552, 554, 556, 558, + 560, 562, 564, 565, 566, 568, 569, 571, + 11390, 11391, 577, 582, 584, 586, 588, 590, + 11375, 11373, 11376, 385, 390, 393, 394, 399, + 602, 42923, 605, 403, 42924, 404, 42893, 42922, + 407, 406, 42926, 11362, 42925, 412, 11374, 413, + 415, 636, 11364, 639, 422, 42949, 425, 645, + 646, 42929, 430, 580, 433, 434, 581, 439, + 659, 662, 663, 666, 42930, 42928, 672, 684, + 685, 686, 687, 688, 689, 690, 691, 692, + 693, 694, 695, 696, 704, 705, 736, 737, + 738, 739, 740, 880, 882, 886, 890, 1021, + 1022, 1023, 938, 939, 978, 979, 980, 975, + 984, 986, 990, 992, 994, 996, 998, 1000, + 1002, 1004, 1006, 1017, 895, 1015, 1018, 1020, + 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, + 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, + 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, + 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, + 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, + 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, + 1120, 1122, 1124, 1126, 1128, 1130, 1132, 1134, + 1136, 1138, 1140, 1142, 1144, 1146, 1148, 1150, + 1152, 1162, 1164, 1166, 1168, 1170, 1172, 1174, + 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, + 1192, 1194, 1196, 1198, 1200, 1202, 1204, 1206, + 1208, 1210, 1212, 1214, 1217, 1219, 1221, 1223, + 1225, 1227, 1229, 1216, 1232, 1234, 1236, 1238, + 1240, 1242, 1244, 1246, 1248, 1250, 1252, 1254, + 1256, 1258, 1260, 1262, 1264, 1266, 1268, 1270, + 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, + 1288, 1290, 1292, 1294, 1296, 1298, 1300, 1302, + 1304, 1306, 1308, 1310, 1312, 1314, 1316, 1318, + 1320, 1322, 1324, 1326, 1376, 1329, 1330, 1331, + 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, + 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, + 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, + 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, + 1364, 1365, 1366, 1415, 1416, 7312, 7313, 7314, + 7315, 7316, 7317, 7318, 7319, 7320, 7321, 7322, + 7323, 7324, 7325, 7326, 7327, 7328, 7329, 7330, + 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, + 7339, 7340, 7341, 7342, 7343, 7344, 7345, 7346, + 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, + 4348, 7357, 7358, 7359, 43888, 43889, 43890, 43891, + 43892, 43893, 43894, 43895, 43896, 43897, 43898, 43899, + 43900, 43901, 43902, 43903, 43904, 43905, 43906, 43907, + 43908, 43909, 43910, 43911, 43912, 43913, 43914, 43915, + 43916, 43917, 43918, 43919, 43920, 43921, 43922, 43923, + 43924, 43925, 43926, 43927, 43928, 43929, 43930, 43931, + 43932, 43933, 43934, 43935, 43936, 43937, 43938, 43939, + 43940, 43941, 43942, 43943, 43944, 43945, 43946, 43947, + 43948, 43949, 43950, 43951, 43952, 43953, 43954, 43955, + 43956, 43957, 43958, 43959, 43960, 43961, 43962, 43963, + 43964, 43965, 43966, 43967, 5112, 5113, 5114, 5115, + 5116, 5117, 42570, 7424, 7425, 7427, 7428, 7429, + 7430, 7431, 7432, 7433, 7434, 7435, 7436, 7437, + 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, + 7448, 7449, 7450, 7451, 7454, 7455, 7456, 7457, + 7458, 7459, 7460, 7462, 7463, 7464, 7465, 7466, + 7467, 7468, 7469, 7470, 7471, 7472, 7473, 7474, + 7475, 7476, 7477, 7478, 7479, 7480, 7481, 7482, + 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, + 7491, 7492, 7493, 7494, 7495, 7496, 7497, 7498, + 7499, 7500, 7501, 7502, 7503, 7504, 7505, 7506, + 7507, 7508, 7509, 7510, 7511, 7512, 7513, 7514, + 7515, 7516, 7517, 7518, 7519, 7520, 7521, 7522, + 7523, 7524, 7525, 7526, 7527, 7528, 7529, 7530, + 7531, 7532, 7533, 7534, 7535, 7536, 7537, 7538, + 7539, 7540, 7541, 7542, 7543, 7544, 42877, 7546, + 7548, 11363, 7550, 7551, 7552, 7553, 7554, 7555, + 7556, 7558, 7559, 7560, 7561, 7562, 7563, 7564, + 7565, 42950, 7567, 7568, 7570, 7571, 7572, 7573, + 7574, 7575, 7576, 7577, 7578, 7579, 7580, 7581, + 7582, 7583, 7584, 7585, 7586, 7587, 7588, 7589, + 7590, 7591, 7592, 7593, 7594, 7595, 7596, 7597, + 7598, 7599, 7600, 7601, 7602, 7603, 7604, 7605, + 7606, 7607, 7608, 7609, 7610, 7611, 7612, 7613, + 7614, 7615, 7680, 7682, 7684, 7686, 7688, 7690, + 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, + 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, + 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, + 7740, 7742, 7744, 7746, 7748, 7750, 7752, 7754, + 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, + 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, + 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, + 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, + 7820, 7822, 7824, 7826, 7828, 7830, 7831, 7832, + 7833, 7834, 7836, 7837, 223, 7839, 7840, 7842, + 7844, 7846, 7848, 7850, 7852, 7854, 7856, 7858, + 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, + 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, + 7892, 7894, 7896, 7898, 7900, 7902, 7904, 7906, + 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, + 7924, 7926, 7928, 7930, 7932, 7934, 7944, 7945, + 7946, 7947, 7948, 7949, 7950, 7951, 7960, 7961, + 7962, 7963, 7964, 7965, 7976, 7977, 7978, 7979, + 7980, 7981, 7982, 7983, 7992, 7993, 7994, 7995, + 7996, 7997, 7998, 7999, 8008, 8009, 8010, 8011, + 8012, 8013, 8016, 8025, 8018, 8027, 8020, 8029, + 8022, 8031, 8040, 8041, 8042, 8043, 8044, 8045, + 8046, 8047, 8122, 8123, 8136, 8137, 8138, 8139, + 8154, 8155, 8184, 8185, 8170, 8171, 8186, 8187, + 8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079, + 8064, 8065, 8066, 8067, 8068, 8069, 8070, 8071, + 8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095, + 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, + 8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111, + 8096, 8097, 8098, 8099, 8100, 8101, 8102, 8103, + 8120, 8121, 8114, 8124, 8116, 8118, 8119, 8115, + 8130, 8140, 8132, 8134, 8135, 8131, 8152, 8153, + 8146, 8147, 8150, 8151, 8168, 8169, 8162, 8163, + 8164, 8172, 8166, 8167, 8178, 8188, 8180, 8182, + 8183, 8179, 8305, 8319, 8336, 8337, 8338, 8339, + 8340, 8341, 8342, 8343, 8344, 8345, 8346, 8347, + 8348, 8450, 8455, 8458, 8459, 8460, 8461, 8462, + 8463, 8464, 8465, 8466, 8467, 8469, 8473, 8474, + 8475, 8476, 8477, 8484, 8488, 8492, 8493, 8495, + 8496, 8497, 8499, 8500, 8505, 8508, 8509, 8510, + 8511, 8517, 8518, 8519, 8520, 8521, 8498, 8544, + 8545, 8546, 8547, 8548, 8549, 8550, 8551, 8552, + 8553, 8554, 8555, 8556, 8557, 8558, 8559, 8579, + 9398, 9399, 9400, 9401, 9402, 9403, 9404, 9405, + 9406, 9407, 9408, 9409, 9410, 9411, 9412, 9413, + 9414, 9415, 9416, 9417, 9418, 9419, 9420, 9421, + 9422, 9423, 11264, 11265, 11266, 11267, 11268, 11269, + 11270, 11271, 11272, 11273, 11274, 11275, 11276, 11277, + 11278, 11279, 11280, 11281, 11282, 11283, 11284, 11285, + 11286, 11287, 11288, 11289, 11290, 11291, 11292, 11293, + 11294, 11295, 11296, 11297, 11298, 11299, 11300, 11301, + 11302, 11303, 11304, 11305, 11306, 11307, 11308, 11309, + 11310, 11311, 11360, 570, 574, 11367, 11369, 11371, + 11378, 11380, 11381, 11383, 11384, 11385, 11386, 11387, + 11388, 11389, 11392, 11394, 11396, 11398, 11400, 11402, + 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, + 11420, 11422, 11424, 11426, 11428, 11430, 11432, 11434, + 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450, + 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, + 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, + 11484, 11486, 11488, 11490, 11492, 11499, 11501, 11506, + 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, + 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, + 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, + 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, + 4288, 4289, 4290, 4291, 4292, 4293, 4295, 4301, + 42560, 42562, 42564, 42566, 42568, 42572, 42574, 42576, + 42578, 42580, 42582, 42584, 42586, 42588, 42590, 42592, + 42594, 42596, 42598, 42600, 42602, 42604, 42624, 42626, + 42628, 42630, 42632, 42634, 42636, 42638, 42640, 42642, + 42644, 42646, 42648, 42650, 42652, 42653, 42786, 42788, + 42790, 42792, 42794, 42796, 42798, 42800, 42801, 42802, + 42804, 42806, 42808, 42810, 42812, 42814, 42816, 42818, + 42820, 42822, 42824, 42826, 42828, 42830, 42832, 42834, + 42836, 42838, 42840, 42842, 42844, 42846, 42848, 42850, + 42852, 42854, 42856, 42858, 42860, 42862, 42864, 42865, + 42866, 42867, 42868, 42869, 42870, 42871, 42872, 42873, + 42875, 42878, 42880, 42882, 42884, 42886, 42891, 42896, + 42898, 42948, 42901, 42902, 42904, 42906, 42908, 42910, + 42912, 42914, 42916, 42918, 42920, 42927, 42932, 42934, + 42936, 42938, 42940, 42942, 42944, 42946, 42951, 42953, + 42960, 42963, 42965, 42966, 42968, 42994, 42995, 42996, + 42997, 43000, 43001, 43002, 43824, 43825, 43826, 43827, + 43828, 43829, 43830, 43832, 43833, 43834, 43835, 43836, + 43837, 43838, 43839, 43840, 43841, 43842, 43843, 43844, + 43845, 43846, 43847, 43848, 43849, 43850, 43851, 43852, + 43853, 43854, 43855, 43856, 43857, 42931, 43860, 43861, + 43862, 43863, 43864, 43865, 43866, 43868, 43869, 43870, + 43871, 43872, 43873, 43874, 43875, 43876, 43877, 43880, + 43881, 64256, 64257, 64258, 64259, 64260, 64261, 64262, + 64275, 64276, 64277, 64278, 64279, 65313, 65314, 65315, + 65316, 65317, 65318, 65319, 65320, 65321, 65322, 65323, + 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, + 65332, 65333, 65334, 65335, 65336, 65337, 65338, 55297, + 56320, 55297, 56321, 55297, 56322, 55297, 56323, 55297, + 56324, 55297, 56325, 55297, 56326, 55297, 56327, 55297, + 56328, 55297, 56329, 55297, 56330, 55297, 56331, 55297, + 56332, 55297, 56333, 55297, 56334, 55297, 56335, 55297, + 56336, 55297, 56337, 55297, 56338, 55297, 56339, 55297, + 56340, 55297, 56341, 55297, 56342, 55297, 56343, 55297, + 56344, 55297, 56345, 55297, 56346, 55297, 56347, 55297, + 56348, 55297, 56349, 55297, 56350, 55297, 56351, 55297, + 56352, 55297, 56353, 55297, 56354, 55297, 56355, 55297, + 56356, 55297, 56357, 55297, 56358, 55297, 56359, 55297, + 56496, 55297, 56497, 55297, 56498, 55297, 56499, 55297, + 56500, 55297, 56501, 55297, 56502, 55297, 56503, 55297, + 56504, 55297, 56505, 55297, 56506, 55297, 56507, 55297, + 56508, 55297, 56509, 55297, 56510, 55297, 56511, 55297, + 56512, 55297, 56513, 55297, 56514, 55297, 56515, 55297, + 56516, 55297, 56517, 55297, 56518, 55297, 56519, 55297, + 56520, 55297, 56521, 55297, 56522, 55297, 56523, 55297, + 56524, 55297, 56525, 55297, 56526, 55297, 56527, 55297, + 56528, 55297, 56529, 55297, 56530, 55297, 56531, 55297, + 56688, 55297, 56689, 55297, 56690, 55297, 56691, 55297, + 56692, 55297, 56693, 55297, 56694, 55297, 56695, 55297, + 56696, 55297, 56697, 55297, 56698, 55297, 56700, 55297, + 56701, 55297, 56702, 55297, 56703, 55297, 56704, 55297, + 56705, 55297, 56706, 55297, 56707, 55297, 56708, 55297, + 56709, 55297, 56710, 55297, 56711, 55297, 56712, 55297, + 56713, 55297, 56714, 55297, 56716, 55297, 56717, 55297, + 56718, 55297, 56719, 55297, 56720, 55297, 56721, 55297, + 56722, 55297, 56724, 55297, 56725, 55297, 57216, 55297, + 57219, 55297, 57220, 55297, 57221, 55297, 57223, 55297, + 57224, 55297, 57225, 55297, 57226, 55297, 57227, 55297, + 57228, 55297, 57229, 55297, 57230, 55297, 57231, 55297, + 57232, 55297, 57233, 55297, 57234, 55297, 57235, 55297, + 57236, 55297, 57237, 55297, 57238, 55297, 57239, 55297, + 57240, 55297, 57241, 55297, 57242, 55297, 57243, 55297, + 57244, 55297, 57245, 55297, 57246, 55297, 57247, 55297, + 57248, 55297, 57249, 55297, 57250, 55297, 57251, 55297, + 57252, 55297, 57253, 55297, 57254, 55297, 57255, 55297, + 57256, 55297, 57257, 55297, 57258, 55297, 57259, 55297, + 57260, 55297, 57261, 55297, 57262, 55297, 57263, 55297, + 57264, 55297, 57266, 55297, 57267, 55297, 57268, 55297, + 57269, 55297, 57270, 55297, 57271, 55297, 57272, 55297, + 57273, 55297, 57274, 55299, 56448, 55299, 56449, 55299, + 56450, 55299, 56451, 55299, 56452, 55299, 56453, 55299, + 56454, 55299, 56455, 55299, 56456, 55299, 56457, 55299, + 56458, 55299, 56459, 55299, 56460, 55299, 56461, 55299, + 56462, 55299, 56463, 55299, 56464, 55299, 56465, 55299, + 56466, 55299, 56467, 55299, 56468, 55299, 56469, 55299, + 56470, 55299, 56471, 55299, 56472, 55299, 56473, 55299, + 56474, 55299, 56475, 55299, 56476, 55299, 56477, 55299, + 56478, 55299, 56479, 55299, 56480, 55299, 56481, 55299, + 56482, 55299, 56483, 55299, 56484, 55299, 56485, 55299, + 56486, 55299, 56487, 55299, 56488, 55299, 56489, 55299, + 56490, 55299, 56491, 55299, 56492, 55299, 56493, 55299, + 56494, 55299, 56495, 55299, 56496, 55299, 56497, 55299, + 56498, 55302, 56480, 55302, 56481, 55302, 56482, 55302, + 56483, 55302, 56484, 55302, 56485, 55302, 56486, 55302, + 56487, 55302, 56488, 55302, 56489, 55302, 56490, 55302, + 56491, 55302, 56492, 55302, 56493, 55302, 56494, 55302, + 56495, 55302, 56496, 55302, 56497, 55302, 56498, 55302, + 56499, 55302, 56500, 55302, 56501, 55302, 56502, 55302, + 56503, 55302, 56504, 55302, 56505, 55302, 56506, 55302, + 56507, 55302, 56508, 55302, 56509, 55302, 56510, 55302, + 56511, 55323, 56896, 55323, 56897, 55323, 56898, 55323, + 56899, 55323, 56900, 55323, 56901, 55323, 56902, 55323, + 56903, 55323, 56904, 55323, 56905, 55323, 56906, 55323, + 56907, 55323, 56908, 55323, 56909, 55323, 56910, 55323, + 56911, 55323, 56912, 55323, 56913, 55323, 56914, 55323, + 56915, 55323, 56916, 55323, 56917, 55323, 56918, 55323, + 56919, 55323, 56920, 55323, 56921, 55323, 56922, 55323, + 56923, 55323, 56924, 55323, 56925, 55323, 56926, 55323, + 56927, 55349, 56320, 55349, 56321, 55349, 56322, 55349, + 56323, 55349, 56324, 55349, 56325, 55349, 56326, 55349, + 56327, 55349, 56328, 55349, 56329, 55349, 56330, 55349, + 56331, 55349, 56332, 55349, 56333, 55349, 56334, 55349, + 56335, 55349, 56336, 55349, 56337, 55349, 56338, 55349, + 56339, 55349, 56340, 55349, 56341, 55349, 56342, 55349, + 56343, 55349, 56344, 55349, 56345, 55349, 56346, 55349, + 56347, 55349, 56348, 55349, 56349, 55349, 56350, 55349, + 56351, 55349, 56352, 55349, 56353, 55349, 56354, 55349, + 56355, 55349, 56356, 55349, 56357, 55349, 56358, 55349, + 56359, 55349, 56360, 55349, 56361, 55349, 56362, 55349, + 56363, 55349, 56364, 55349, 56365, 55349, 56366, 55349, + 56367, 55349, 56368, 55349, 56369, 55349, 56370, 55349, + 56371, 55349, 56372, 55349, 56373, 55349, 56374, 55349, + 56375, 55349, 56376, 55349, 56377, 55349, 56378, 55349, + 56379, 55349, 56380, 55349, 56381, 55349, 56382, 55349, + 56383, 55349, 56384, 55349, 56385, 55349, 56386, 55349, + 56387, 55349, 56388, 55349, 56389, 55349, 56390, 55349, + 56391, 55349, 56392, 55349, 56393, 55349, 56394, 55349, + 56395, 55349, 56396, 55349, 56397, 55349, 56398, 55349, + 56399, 55349, 56400, 55349, 56401, 55349, 56402, 55349, + 56403, 55349, 56404, 55349, 56406, 55349, 56407, 55349, + 56408, 55349, 56409, 55349, 56410, 55349, 56411, 55349, + 56412, 55349, 56413, 55349, 56414, 55349, 56415, 55349, + 56416, 55349, 56417, 55349, 56418, 55349, 56419, 55349, + 56420, 55349, 56421, 55349, 56422, 55349, 56423, 55349, + 56424, 55349, 56425, 55349, 56426, 55349, 56427, 55349, + 56428, 55349, 56429, 55349, 56430, 55349, 56431, 55349, + 56432, 55349, 56433, 55349, 56434, 55349, 56435, 55349, + 56436, 55349, 56437, 55349, 56438, 55349, 56439, 55349, + 56440, 55349, 56441, 55349, 56442, 55349, 56443, 55349, + 56444, 55349, 56445, 55349, 56446, 55349, 56447, 55349, + 56448, 55349, 56449, 55349, 56450, 55349, 56451, 55349, + 56452, 55349, 56453, 55349, 56454, 55349, 56455, 55349, + 56456, 55349, 56457, 55349, 56458, 55349, 56459, 55349, + 56460, 55349, 56461, 55349, 56462, 55349, 56463, 55349, + 56464, 55349, 56465, 55349, 56466, 55349, 56467, 55349, + 56468, 55349, 56469, 55349, 56470, 55349, 56471, 55349, + 56472, 55349, 56473, 55349, 56474, 55349, 56475, 55349, + 56476, 55349, 56478, 55349, 56479, 55349, 56482, 55349, + 56485, 55349, 56486, 55349, 56489, 55349, 56490, 55349, + 56491, 55349, 56492, 55349, 56494, 55349, 56495, 55349, + 56496, 55349, 56497, 55349, 56498, 55349, 56499, 55349, + 56500, 55349, 56501, 55349, 56502, 55349, 56503, 55349, + 56504, 55349, 56505, 55349, 56507, 55349, 56509, 55349, + 56510, 55349, 56511, 55349, 56512, 55349, 56513, 55349, + 56514, 55349, 56515, 55349, 56517, 55349, 56518, 55349, + 56519, 55349, 56520, 55349, 56521, 55349, 56522, 55349, + 56523, 55349, 56524, 55349, 56525, 55349, 56526, 55349, + 56527, 55349, 56528, 55349, 56529, 55349, 56530, 55349, + 56531, 55349, 56532, 55349, 56533, 55349, 56534, 55349, + 56535, 55349, 56536, 55349, 56537, 55349, 56538, 55349, + 56539, 55349, 56540, 55349, 56541, 55349, 56542, 55349, + 56543, 55349, 56544, 55349, 56545, 55349, 56546, 55349, + 56547, 55349, 56548, 55349, 56549, 55349, 56550, 55349, + 56551, 55349, 56552, 55349, 56553, 55349, 56554, 55349, + 56555, 55349, 56556, 55349, 56557, 55349, 56558, 55349, + 56559, 55349, 56560, 55349, 56561, 55349, 56562, 55349, + 56563, 55349, 56564, 55349, 56565, 55349, 56566, 55349, + 56567, 55349, 56568, 55349, 56569, 55349, 56570, 55349, + 56571, 55349, 56572, 55349, 56573, 55349, 56574, 55349, + 56575, 55349, 56576, 55349, 56577, 55349, 56578, 55349, + 56579, 55349, 56580, 55349, 56581, 55349, 56583, 55349, + 56584, 55349, 56585, 55349, 56586, 55349, 56589, 55349, + 56590, 55349, 56591, 55349, 56592, 55349, 56593, 55349, + 56594, 55349, 56595, 55349, 56596, 55349, 56598, 55349, + 56599, 55349, 56600, 55349, 56601, 55349, 56602, 55349, + 56603, 55349, 56604, 55349, 56606, 55349, 56607, 55349, + 56608, 55349, 56609, 55349, 56610, 55349, 56611, 55349, + 56612, 55349, 56613, 55349, 56614, 55349, 56615, 55349, + 56616, 55349, 56617, 55349, 56618, 55349, 56619, 55349, + 56620, 55349, 56621, 55349, 56622, 55349, 56623, 55349, + 56624, 55349, 56625, 55349, 56626, 55349, 56627, 55349, + 56628, 55349, 56629, 55349, 56630, 55349, 56631, 55349, + 56632, 55349, 56633, 55349, 56635, 55349, 56636, 55349, + 56637, 55349, 56638, 55349, 56640, 55349, 56641, 55349, + 56642, 55349, 56643, 55349, 56644, 55349, 56646, 55349, + 56650, 55349, 56651, 55349, 56652, 55349, 56653, 55349, + 56654, 55349, 56655, 55349, 56656, 55349, 56658, 55349, + 56659, 55349, 56660, 55349, 56661, 55349, 56662, 55349, + 56663, 55349, 56664, 55349, 56665, 55349, 56666, 55349, + 56667, 55349, 56668, 55349, 56669, 55349, 56670, 55349, + 56671, 55349, 56672, 55349, 56673, 55349, 56674, 55349, + 56675, 55349, 56676, 55349, 56677, 55349, 56678, 55349, + 56679, 55349, 56680, 55349, 56681, 55349, 56682, 55349, + 56683, 55349, 56684, 55349, 56685, 55349, 56686, 55349, + 56687, 55349, 56688, 55349, 56689, 55349, 56690, 55349, + 56691, 55349, 56692, 55349, 56693, 55349, 56694, 55349, + 56695, 55349, 56696, 55349, 56697, 55349, 56698, 55349, + 56699, 55349, 56700, 55349, 56701, 55349, 56702, 55349, + 56703, 55349, 56704, 55349, 56705, 55349, 56706, 55349, + 56707, 55349, 56708, 55349, 56709, 55349, 56710, 55349, + 56711, 55349, 56712, 55349, 56713, 55349, 56714, 55349, + 56715, 55349, 56716, 55349, 56717, 55349, 56718, 55349, + 56719, 55349, 56720, 55349, 56721, 55349, 56722, 55349, + 56723, 55349, 56724, 55349, 56725, 55349, 56726, 55349, + 56727, 55349, 56728, 55349, 56729, 55349, 56730, 55349, + 56731, 55349, 56732, 55349, 56733, 55349, 56734, 55349, + 56735, 55349, 56736, 55349, 56737, 55349, 56738, 55349, + 56739, 55349, 56740, 55349, 56741, 55349, 56742, 55349, + 56743, 55349, 56744, 55349, 56745, 55349, 56746, 55349, + 56747, 55349, 56748, 55349, 56749, 55349, 56750, 55349, + 56751, 55349, 56752, 55349, 56753, 55349, 56754, 55349, + 56755, 55349, 56756, 55349, 56757, 55349, 56758, 55349, + 56759, 55349, 56760, 55349, 56761, 55349, 56762, 55349, + 56763, 55349, 56764, 55349, 56765, 55349, 56766, 55349, + 56767, 55349, 56768, 55349, 56769, 55349, 56770, 55349, + 56771, 55349, 56772, 55349, 56773, 55349, 56774, 55349, + 56775, 55349, 56776, 55349, 56777, 55349, 56778, 55349, + 56779, 55349, 56780, 55349, 56781, 55349, 56782, 55349, + 56783, 55349, 56784, 55349, 56785, 55349, 56786, 55349, + 56787, 55349, 56788, 55349, 56789, 55349, 56790, 55349, + 56791, 55349, 56792, 55349, 56793, 55349, 56794, 55349, + 56795, 55349, 56796, 55349, 56797, 55349, 56798, 55349, + 56799, 55349, 56800, 55349, 56801, 55349, 56802, 55349, + 56803, 55349, 56804, 55349, 56805, 55349, 56806, 55349, + 56807, 55349, 56808, 55349, 56809, 55349, 56810, 55349, + 56811, 55349, 56812, 55349, 56813, 55349, 56814, 55349, + 56815, 55349, 56816, 55349, 56817, 55349, 56818, 55349, + 56819, 55349, 56820, 55349, 56821, 55349, 56822, 55349, + 56823, 55349, 56824, 55349, 56825, 55349, 56826, 55349, + 56827, 55349, 56828, 55349, 56829, 55349, 56830, 55349, + 56831, 55349, 56832, 55349, 56833, 55349, 56834, 55349, + 56835, 55349, 56836, 55349, 56837, 55349, 56838, 55349, + 56839, 55349, 56840, 55349, 56841, 55349, 56842, 55349, + 56843, 55349, 56844, 55349, 56845, 55349, 56846, 55349, + 56847, 55349, 56848, 55349, 56849, 55349, 56850, 55349, + 56851, 55349, 56852, 55349, 56853, 55349, 56854, 55349, + 56855, 55349, 56856, 55349, 56857, 55349, 56858, 55349, + 56859, 55349, 56860, 55349, 56861, 55349, 56862, 55349, + 56863, 55349, 56864, 55349, 56865, 55349, 56866, 55349, + 56867, 55349, 56868, 55349, 56869, 55349, 56870, 55349, + 56871, 55349, 56872, 55349, 56873, 55349, 56874, 55349, + 56875, 55349, 56876, 55349, 56877, 55349, 56878, 55349, + 56879, 55349, 56880, 55349, 56881, 55349, 56882, 55349, + 56883, 55349, 56884, 55349, 56885, 55349, 56886, 55349, + 56887, 55349, 56888, 55349, 56889, 55349, 56890, 55349, + 56891, 55349, 56892, 55349, 56893, 55349, 56894, 55349, + 56895, 55349, 56896, 55349, 56897, 55349, 56898, 55349, + 56899, 55349, 56900, 55349, 56901, 55349, 56902, 55349, + 56903, 55349, 56904, 55349, 56905, 55349, 56906, 55349, + 56907, 55349, 56908, 55349, 56909, 55349, 56910, 55349, + 56911, 55349, 56912, 55349, 56913, 55349, 56914, 55349, + 56915, 55349, 56916, 55349, 56917, 55349, 56918, 55349, + 56919, 55349, 56920, 55349, 56921, 55349, 56922, 55349, + 56923, 55349, 56924, 55349, 56925, 55349, 56926, 55349, + 56927, 55349, 56928, 55349, 56929, 55349, 56930, 55349, + 56931, 55349, 56932, 55349, 56933, 55349, 56934, 55349, + 56935, 55349, 56936, 55349, 56937, 55349, 56938, 55349, + 56939, 55349, 56940, 55349, 56941, 55349, 56942, 55349, + 56943, 55349, 56944, 55349, 56945, 55349, 56946, 55349, + 56947, 55349, 56948, 55349, 56949, 55349, 56950, 55349, + 56951, 55349, 56952, 55349, 56953, 55349, 56954, 55349, + 56955, 55349, 56956, 55349, 56957, 55349, 56958, 55349, + 56959, 55349, 56960, 55349, 56961, 55349, 56962, 55349, + 56963, 55349, 56964, 55349, 56965, 55349, 56966, 55349, + 56967, 55349, 56968, 55349, 56969, 55349, 56970, 55349, + 56971, 55349, 56972, 55349, 56973, 55349, 56974, 55349, + 56975, 55349, 56976, 55349, 56977, 55349, 56978, 55349, + 56979, 55349, 56980, 55349, 56981, 55349, 56982, 55349, + 56983, 55349, 56984, 55349, 56985, 55349, 56986, 55349, + 56987, 55349, 56988, 55349, 56989, 55349, 56990, 55349, + 56991, 55349, 56992, 55349, 56993, 55349, 56994, 55349, + 56995, 55349, 56996, 55349, 56997, 55349, 57000, 55349, + 57001, 55349, 57002, 55349, 57003, 55349, 57004, 55349, + 57005, 55349, 57006, 55349, 57007, 55349, 57008, 55349, + 57009, 55349, 57010, 55349, 57011, 55349, 57012, 55349, + 57013, 55349, 57014, 55349, 57015, 55349, 57016, 55349, + 57017, 55349, 57018, 55349, 57019, 55349, 57020, 55349, + 57021, 55349, 57022, 55349, 57023, 55349, 57024, 55349, + 57026, 55349, 57027, 55349, 57028, 55349, 57029, 55349, + 57030, 55349, 57031, 55349, 57032, 55349, 57033, 55349, + 57034, 55349, 57035, 55349, 57036, 55349, 57037, 55349, + 57038, 55349, 57039, 55349, 57040, 55349, 57041, 55349, + 57042, 55349, 57043, 55349, 57044, 55349, 57045, 55349, + 57046, 55349, 57047, 55349, 57048, 55349, 57049, 55349, + 57050, 55349, 57052, 55349, 57053, 55349, 57054, 55349, + 57055, 55349, 57056, 55349, 57057, 55349, 57058, 55349, + 57059, 55349, 57060, 55349, 57061, 55349, 57062, 55349, + 57063, 55349, 57064, 55349, 57065, 55349, 57066, 55349, + 57067, 55349, 57068, 55349, 57069, 55349, 57070, 55349, + 57071, 55349, 57072, 55349, 57073, 55349, 57074, 55349, + 57075, 55349, 57076, 55349, 57077, 55349, 57078, 55349, + 57079, 55349, 57080, 55349, 57081, 55349, 57082, 55349, + 57084, 55349, 57085, 55349, 57086, 55349, 57087, 55349, + 57088, 55349, 57089, 55349, 57090, 55349, 57091, 55349, + 57092, 55349, 57093, 55349, 57094, 55349, 57095, 55349, + 57096, 55349, 57097, 55349, 57098, 55349, 57099, 55349, + 57100, 55349, 57101, 55349, 57102, 55349, 57103, 55349, + 57104, 55349, 57105, 55349, 57106, 55349, 57107, 55349, + 57108, 55349, 57110, 55349, 57111, 55349, 57112, 55349, + 57113, 55349, 57114, 55349, 57115, 55349, 57116, 55349, + 57117, 55349, 57118, 55349, 57119, 55349, 57120, 55349, + 57121, 55349, 57122, 55349, 57123, 55349, 57124, 55349, + 57125, 55349, 57126, 55349, 57127, 55349, 57128, 55349, + 57129, 55349, 57130, 55349, 57131, 55349, 57132, 55349, + 57133, 55349, 57134, 55349, 57135, 55349, 57136, 55349, + 57137, 55349, 57138, 55349, 57139, 55349, 57140, 55349, + 57142, 55349, 57143, 55349, 57144, 55349, 57145, 55349, + 57146, 55349, 57147, 55349, 57148, 55349, 57149, 55349, + 57150, 55349, 57151, 55349, 57152, 55349, 57153, 55349, + 57154, 55349, 57155, 55349, 57156, 55349, 57157, 55349, + 57158, 55349, 57159, 55349, 57160, 55349, 57161, 55349, + 57162, 55349, 57163, 55349, 57164, 55349, 57165, 55349, + 57166, 55349, 57168, 55349, 57169, 55349, 57170, 55349, + 57171, 55349, 57172, 55349, 57173, 55349, 57174, 55349, + 57175, 55349, 57176, 55349, 57177, 55349, 57178, 55349, + 57179, 55349, 57180, 55349, 57181, 55349, 57182, 55349, + 57183, 55349, 57184, 55349, 57185, 55349, 57186, 55349, + 57187, 55349, 57188, 55349, 57189, 55349, 57190, 55349, + 57191, 55349, 57192, 55349, 57193, 55349, 57194, 55349, + 57195, 55349, 57196, 55349, 57197, 55349, 57198, 55349, + 57200, 55349, 57201, 55349, 57202, 55349, 57203, 55349, + 57204, 55349, 57205, 55349, 57206, 55349, 57207, 55349, + 57208, 55349, 57209, 55349, 57210, 55349, 57211, 55349, + 57212, 55349, 57213, 55349, 57214, 55349, 57215, 55349, + 57216, 55349, 57217, 55349, 57218, 55349, 57219, 55349, + 57220, 55349, 57221, 55349, 57222, 55349, 57223, 55349, + 57224, 55349, 57226, 55349, 57227, 55349, 57228, 55349, + 57229, 55349, 57230, 55349, 57231, 55349, 57232, 55349, + 57233, 55349, 57234, 55349, 57235, 55349, 57236, 55349, + 57237, 55349, 57238, 55349, 57239, 55349, 57240, 55349, + 57241, 55349, 57242, 55349, 57243, 55349, 57244, 55349, + 57245, 55349, 57246, 55349, 57247, 55349, 57248, 55349, + 57249, 55349, 57250, 55349, 57251, 55349, 57252, 55349, + 57253, 55349, 57254, 55349, 57255, 55349, 57256, 55349, + 57258, 55349, 57259, 55349, 57260, 55349, 57261, 55349, + 57262, 55349, 57263, 55349, 57264, 55349, 57265, 55349, + 57266, 55349, 57267, 55349, 57268, 55349, 57269, 55349, + 57270, 55349, 57271, 55349, 57272, 55349, 57273, 55349, + 57274, 55349, 57275, 55349, 57276, 55349, 57277, 55349, + 57278, 55349, 57279, 55349, 57280, 55349, 57281, 55349, + 57282, 55349, 57284, 55349, 57285, 55349, 57286, 55349, + 57287, 55349, 57288, 55349, 57289, 55349, 57290, 55349, + 57291, 55351, 57088, 55351, 57089, 55351, 57090, 55351, + 57091, 55351, 57095, 55351, 57097, 55351, 57099, 55351, + 57100, 55351, 57101, 55351, 57102, 55351, 57103, 55351, + 57104, 55351, 57105, 55351, 57106, 55351, 57107, 55351, + 57108, 55351, 57109, 55351, 57110, 55351, 57111, 55351, + 57112, 55351, 57113, 55351, 57114, 55351, 57115, 55351, + 57116, 55351, 57117, 55351, 57125, 55351, 57126, 55351, + 57127, 55351, 57128, 55351, 57129, 55351, 57130, 55352, + 56368, 55352, 56369, 55352, 56370, 55352, 56371, 55352, + 56372, 55352, 56373, 55352, 56374, 55352, 56375, 55352, + 56376, 55352, 56377, 55352, 56378, 55352, 56379, 55352, + 56380, 55352, 56381, 55352, 56382, 55352, 56383, 55352, + 56384, 55352, 56385, 55352, 56386, 55352, 56387, 55352, + 56388, 55352, 56389, 55352, 56390, 55352, 56391, 55352, + 56392, 55352, 56393, 55352, 56394, 55352, 56395, 55352, + 56396, 55352, 56397, 55352, 56398, 55352, 56399, 55352, + 56400, 55352, 56401, 55352, 56402, 55352, 56403, 55352, + 56404, 55352, 56405, 55352, 56406, 55352, 56407, 55352, + 56408, 55352, 56409, 55352, 56410, 55352, 56411, 55352, + 56412, 55352, 56413, 55352, 56414, 55352, 56415, 55352, + 56416, 55352, 56417, 55352, 56418, 55352, 56419, 55352, + 56420, 55352, 56421, 55352, 56422, 55352, 56423, 55352, + 56424, 55352, 56425, 55352, 56426, 55352, 56427, 55352, + 56428, 55352, 56429, 55354, 56576, 55354, 56577, 55354, + 56578, 55354, 56579, 55354, 56580, 55354, 56581, 55354, + 56582, 55354, 56583, 55354, 56584, 55354, 56585, 55354, + 56586, 55354, 56587, 55354, 56588, 55354, 56589, 55354, + 56590, 55354, 56591, 55354, 56592, 55354, 56593, 55354, + 56594, 55354, 56595, 55354, 56596, 55354, 56597, 55354, + 56598, 55354, 56599, 55354, 56600, 55354, 56601, 55354, + 56602, 55354, 56603, 55354, 56604, 55354, 56605, 55354, + 56606, 55354, 56607, 55354, 56608, 55354, 56609, 55356, + 56624, 55356, 56625, 55356, 56626, 55356, 56627, 55356, + 56628, 55356, 56629, 55356, 56630, 55356, 56631, 55356, + 56632, 55356, 56633, 55356, 56634, 55356, 56635, 55356, + 56636, 55356, 56637, 55356, 56638, 55356, 56639, 55356, + 56640, 55356, 56641, 55356, 56642, 55356, 56643, 55356, + 56644, 55356, 56645, 55356, 56646, 55356, 56647, 55356, + 56648, 55356, 56649, 55356, 56656, 55356, 56657, 55356, + 56658, 55356, 56659, 55356, 56660, 55356, 56661, 55356, + 56662, 55356, 56663, 55356, 56664, 55356, 56665, 55356, + 56666, 55356, 56667, 55356, 56668, 55356, 56669, 55356, + 56670, 55356, 56671, 55356, 56672, 55356, 56673, 55356, + 56674, 55356, 56675, 55356, 56676, 55356, 56677, 55356, + 56678, 55356, 56679, 55356, 56680, 55356, 56681, 55356, + 56688, 55356, 56689, 55356, 56690, 55356, 56691, 55356, + 56692, 55356, 56693, 55356, 56694, 55356, 56695, 55356, + 56696, 55356, 56697, 55356, 56698, 55356, 56699, 55356, + 56700, 55356, 56701, 55356, 56702, 55356, 56703, 55356, + 56704, 55356, 56705, 55356, 56706, 55356, 56707, 55356, + 56708, 55356, 56709, 55356, 56710, 55356, 56711, 55356, + 56712, 55356, 56713, }; + +static const utf8proc_uint16_t utf8proc_stage1table[] = { + 0, 256, 512, 768, 1024, 1280, 1536, + 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, + 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632, + 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680, + 7936, 8192, 8448, 8704, 8960, 9216, 9472, 9728, + 9984, 10240, 10496, 10752, 11008, 11264, 11520, 11776, + 12032, 12288, 12544, 12800, 13056, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13568, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13824, 13312, 13312, 13312, 14080, 5376, 14336, + 14592, 14848, 15104, 15360, 15616, 15872, 16128, 16384, + 16640, 16896, 17152, 17408, 15872, 16128, 16384, 16640, + 16896, 17152, 17408, 15872, 16128, 16384, 16640, 16896, + 17152, 17408, 15872, 16128, 16384, 16640, 16896, 17152, + 17408, 15872, 16128, 16384, 16640, 16896, 17152, 17408, + 15872, 16128, 16384, 16640, 16896, 17152, 17408, 15872, + 17664, 17920, 17920, 17920, 17920, 17920, 17920, 17920, + 17920, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18432, 18688, 18944, 19200, 19456, 19712, + 19968, 20224, 20480, 20736, 20992, 21248, 21504, 5376, + 21760, 22016, 22272, 22528, 22784, 23040, 23296, 23552, + 23808, 24064, 24320, 24576, 24832, 25088, 25344, 25600, + 25856, 26112, 26368, 26624, 26880, 27136, 27392, 27648, + 27904, 5376, 5376, 5376, 28160, 28416, 28672, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 29184, 5376, 5376, 5376, 5376, 29440, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 5376, 5376, 29696, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 5376, 5376, 29952, 30208, 28928, 28928, 30464, + 30720, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 30976, 13312, 13312, 13312, 13312, 31232, 31488, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 31744, 13312, 32000, 32256, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 32512, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 32768, 33024, 33280, 33536, 33792, 34048, 34304, 34560, + 34816, 10240, 10240, 35072, 28928, 28928, 28928, 28928, + 35328, 35584, 35840, 36096, 28928, 36352, 28928, 28928, + 36608, 36864, 37120, 28928, 28928, 37376, 37632, 37888, + 28928, 38144, 38400, 38656, 38912, 39168, 39424, 39680, + 39936, 40192, 40448, 40704, 40960, 28928, 28928, 28928, + 28928, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 41216, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 41472, 41728, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 41984, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 42240, 13312, 13312, 42496, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 42752, 43008, 43264, 28928, 28928, 28928, 28928, + 28928, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 43520, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, + 13312, 13312, 13312, 13312, 43776, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 44032, 44288, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, + 28928, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 44544, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, + 44544, }; + +static const utf8proc_uint16_t utf8proc_stage2table[] = { + 1, 2, 2, 2, 2, 2, 2, + 2, 2, 3, 4, 3, 5, 6, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 7, 7, 7, + 3, 8, 9, 9, 10, 11, 10, 9, + 9, 12, 13, 9, 14, 15, 16, 15, + 15, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 15, 9, 18, 19, 20, + 9, 9, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 12, 9, 13, 47, + 48, 47, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 12, 75, 13, 75, + 2, 2, 2, 2, 2, 2, 7, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 76, 9, 11, 11, 11, 11, 77, + 9, 78, 79, 80, 81, 75, 82, 79, + 83, 84, 85, 86, 87, 88, 89, 9, + 9, 90, 91, 92, 93, 94, 95, 96, + 9, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 75, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, + 75, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, + 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, + 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, 329, 330, 331, 332, 333, + 334, 335, 336, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, 347, 348, 349, + 350, 346, 346, 346, 346, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 431, 432, 433, + 434, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 447, 448, 449, + 450, 451, 452, 453, 454, 455, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 465, + 466, 467, 468, 469, 470, 471, 472, 473, + 474, 475, 476, 477, 478, 479, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 521, + 522, 523, 524, 525, 526, 527, 528, 529, + 530, 531, 532, 533, 534, 535, 536, 537, + 538, 539, 540, 541, 542, 543, 544, 545, + 546, 547, 548, 549, 550, 551, 552, 553, + 554, 555, 556, 557, 558, 346, 559, 560, + 561, 562, 563, 564, 565, 566, 567, 568, + 569, 570, 571, 572, 573, 574, 575, 576, + 577, 578, 579, 580, 581, 582, 583, 584, + 585, 586, 587, 588, 589, 590, 591, 592, + 593, 594, 595, 595, 596, 596, 596, 596, + 596, 597, 598, 47, 47, 47, 47, 595, + 595, 595, 595, 595, 595, 595, 595, 595, + 595, 596, 596, 47, 47, 47, 47, 47, + 47, 599, 600, 601, 602, 603, 604, 47, + 47, 605, 606, 607, 608, 609, 47, 47, + 47, 47, 47, 47, 47, 595, 47, 596, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 610, 611, 612, 613, 614, 615, 616, + 617, 618, 619, 620, 621, 622, 615, 615, + 623, 615, 624, 615, 625, 626, 627, 628, + 628, 628, 628, 627, 629, 628, 628, 628, + 628, 628, 630, 630, 631, 632, 633, 634, + 635, 636, 628, 628, 628, 628, 637, 638, + 628, 639, 640, 628, 628, 641, 641, 641, + 641, 642, 628, 628, 628, 628, 615, 615, + 615, 643, 644, 645, 646, 647, 648, 615, + 628, 628, 628, 615, 615, 615, 628, 628, + 649, 615, 615, 615, 628, 628, 628, 628, + 615, 627, 628, 628, 615, 650, 651, 651, + 650, 651, 651, 650, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 652, 653, 654, 655, 656, 47, 657, + 658, 0, 0, 659, 660, 661, 662, 663, + 664, 0, 0, 0, 0, 88, 665, 666, + 667, 668, 669, 670, 0, 671, 0, 672, + 673, 674, 675, 676, 677, 678, 679, 680, + 681, 682, 683, 684, 685, 686, 687, 688, + 689, 690, 691, 0, 692, 693, 694, 695, + 696, 697, 698, 699, 700, 701, 702, 703, + 704, 705, 706, 707, 708, 709, 710, 711, + 712, 713, 714, 715, 716, 717, 718, 719, + 720, 721, 722, 723, 724, 725, 726, 727, + 728, 729, 730, 731, 732, 733, 734, 735, + 736, 737, 738, 739, 740, 741, 742, 743, + 744, 745, 746, 747, 748, 749, 750, 751, + 752, 753, 754, 755, 756, 757, 758, 759, + 760, 761, 762, 763, 764, 765, 766, 767, + 768, 769, 770, 771, 772, 773, 774, 75, + 775, 776, 777, 778, 779, 780, 781, 782, + 783, 784, 785, 786, 787, 788, 789, 790, + 791, 792, 793, 794, 795, 796, 797, 798, + 799, 800, 801, 802, 803, 804, 805, 806, + 807, 808, 809, 810, 811, 812, 813, 814, + 815, 816, 817, 818, 819, 820, 821, 822, + 823, 824, 825, 826, 827, 828, 829, 830, + 831, 832, 833, 834, 835, 836, 837, 838, + 839, 840, 841, 842, 843, 844, 845, 846, + 847, 848, 849, 850, 851, 852, 853, 854, + 855, 856, 857, 858, 859, 860, 861, 862, + 863, 864, 865, 866, 867, 868, 869, 870, + 871, 872, 873, 874, 875, 876, 877, 878, + 879, 880, 881, 882, 883, 884, 885, 886, + 887, 888, 889, 890, 891, 892, 893, 894, + 895, 896, 897, 898, 899, 900, 901, 902, + 903, 904, 905, 906, 907, 908, 909, 910, + 911, 912, 913, 914, 615, 615, 615, 615, + 615, 915, 915, 916, 917, 918, 919, 920, + 921, 922, 923, 924, 925, 926, 927, 928, + 929, 930, 931, 932, 933, 934, 935, 936, + 937, 938, 939, 940, 941, 942, 943, 944, + 945, 946, 947, 948, 949, 950, 951, 952, + 953, 954, 955, 956, 957, 958, 959, 960, + 961, 962, 963, 964, 965, 966, 967, 968, + 969, 970, 971, 972, 973, 974, 975, 976, + 977, 978, 979, 980, 981, 982, 983, 984, + 985, 986, 987, 988, 989, 990, 991, 992, + 993, 994, 995, 996, 997, 998, 999, 1000, + 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, + 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, + 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, + 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, + 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, + 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, + 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, + 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, + 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, + 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, + 1081, 0, 1082, 1083, 1084, 1085, 1086, 1087, + 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, + 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, + 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, + 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, + 0, 0, 596, 1120, 1120, 1120, 1120, 1120, + 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, + 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, + 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, + 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, + 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, + 1160, 1161, 1120, 1162, 0, 0, 77, 77, + 11, 0, 628, 615, 615, 615, 615, 628, + 615, 615, 615, 1163, 628, 615, 615, 615, + 615, 615, 615, 628, 628, 628, 628, 628, + 628, 615, 615, 628, 615, 615, 1163, 1164, + 615, 1165, 1166, 1167, 1168, 1169, 1170, 1171, + 1172, 1173, 1174, 1174, 1175, 1176, 1177, 1178, + 1179, 1180, 1181, 1182, 1180, 615, 628, 1180, + 1173, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 0, 0, 0, 0, + 1183, 1183, 1183, 1183, 1180, 1180, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1184, 1184, 1184, 1184, 1184, 1184, 75, + 75, 1185, 10, 10, 1186, 15, 1187, 77, + 77, 615, 615, 615, 615, 615, 615, 615, + 615, 1188, 1189, 1190, 1187, 1191, 1187, 1187, + 1187, 1192, 1192, 1193, 1194, 1195, 1196, 1197, + 1198, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1199, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1200, 1192, 1201, 1202, 1203, 1204, 1188, + 1189, 1190, 1205, 1206, 1207, 1208, 1209, 628, + 615, 615, 615, 615, 615, 628, 615, 615, + 628, 1210, 1210, 1210, 1210, 1210, 1210, 1210, + 1210, 1210, 1210, 10, 1211, 1211, 1187, 1192, + 1192, 1212, 1192, 1192, 1192, 1192, 1213, 1214, + 1215, 1216, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1217, 1218, 1219, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1220, 1221, 1187, 1222, 615, + 615, 615, 615, 615, 615, 615, 1184, 77, + 615, 615, 615, 615, 628, 615, 1199, 1199, + 615, 615, 77, 628, 615, 615, 628, 1192, + 1192, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 1192, 1192, 1192, 1223, 1223, + 1192, 1187, 1187, 1187, 1187, 1187, 1187, 1187, + 1187, 1187, 1187, 1187, 1187, 1187, 1187, 0, + 1224, 1192, 1225, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 615, 628, 615, 615, 628, 615, 615, + 628, 628, 628, 615, 628, 628, 615, 628, + 615, 615, 615, 628, 615, 628, 615, 628, + 615, 628, 615, 615, 0, 0, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1192, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1227, 1227, 1227, 1227, 1227, 1227, 1227, + 1227, 1227, 1227, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 615, 615, 615, 615, + 615, 615, 615, 628, 615, 1228, 1228, 77, + 9, 9, 9, 1228, 0, 0, 628, 1229, + 1229, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 615, + 615, 615, 615, 1228, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 1228, 615, 615, + 615, 1228, 615, 615, 615, 615, 615, 0, + 0, 1180, 1180, 1180, 1180, 1180, 1180, 1180, + 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 628, 628, 628, 0, 0, 1180, + 0, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 0, 0, 0, 0, + 0, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1230, 1192, 1192, 1192, 1192, 1192, 1192, + 0, 1184, 1184, 0, 0, 0, 0, 0, + 0, 615, 628, 628, 628, 615, 615, 615, + 615, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1199, 615, 615, 615, 615, 615, + 628, 628, 628, 628, 628, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 1184, 628, 615, 615, 628, + 615, 615, 628, 615, 615, 615, 628, 628, + 628, 1202, 1203, 1204, 615, 615, 615, 628, + 615, 615, 628, 628, 615, 615, 615, 615, + 615, 1226, 1226, 1226, 1231, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1233, 1234, 1232, 1232, 1232, 1232, 1232, + 1232, 1235, 1236, 1232, 1237, 1238, 1232, 1232, + 1232, 1232, 1232, 1226, 1231, 1239, 346, 1231, + 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1231, 1231, 1231, 1231, 1240, 1231, + 1231, 346, 615, 628, 615, 615, 1226, 1226, + 1226, 1241, 1242, 1243, 1244, 1245, 1246, 1247, + 1248, 346, 346, 1226, 1226, 1120, 1120, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1120, 596, 346, 346, 346, 346, 346, + 346, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 346, 1226, 1231, 1231, 0, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 0, + 346, 346, 0, 0, 346, 346, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 0, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 0, 1232, 0, 0, 0, 1232, + 1232, 1232, 1232, 0, 0, 1250, 346, 1251, + 1231, 1231, 1226, 1226, 1226, 1226, 0, 0, + 1252, 1231, 0, 0, 1253, 1254, 1240, 346, + 0, 0, 0, 0, 0, 0, 0, 0, + 1255, 0, 0, 0, 0, 1256, 1257, 0, + 1258, 346, 346, 1226, 1226, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1232, 1232, 11, 11, 1259, 1259, 1259, + 1259, 1259, 1259, 914, 11, 346, 1120, 615, + 0, 0, 1226, 1226, 1231, 0, 346, 346, + 346, 346, 346, 346, 0, 0, 0, 0, + 346, 346, 0, 0, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 1260, 0, 346, 1261, + 0, 346, 346, 0, 0, 1250, 0, 1231, + 1231, 1231, 1226, 1226, 0, 0, 0, 0, + 1226, 1226, 0, 0, 1226, 1226, 1262, 0, + 0, 0, 1226, 0, 0, 0, 0, 0, + 0, 0, 1263, 1264, 1265, 346, 0, 1266, + 0, 0, 0, 0, 0, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1226, 1226, 346, 346, 346, 1226, 1120, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1226, 1226, 1231, 0, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 346, 346, 346, 0, 346, 346, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 0, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 0, 1232, 1232, 0, 1232, 1232, + 1232, 1232, 1232, 0, 0, 1250, 346, 1231, + 1231, 1231, 1226, 1226, 1226, 1226, 1226, 0, + 1226, 1226, 1231, 0, 1231, 1231, 1240, 0, + 0, 346, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 1226, 1226, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1120, 11, 0, 0, 0, 0, 0, + 0, 0, 1232, 1226, 1226, 1226, 1226, 1226, + 1226, 0, 1226, 1231, 1231, 0, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 0, + 346, 346, 0, 0, 346, 346, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 0, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 0, 1232, 1232, 0, 1232, 1232, + 1232, 1232, 1232, 0, 0, 1250, 346, 1267, + 1226, 1231, 1226, 1226, 1226, 1226, 0, 0, + 1268, 1269, 0, 0, 1270, 1271, 1240, 0, + 0, 0, 0, 0, 0, 0, 1226, 1272, + 1273, 0, 0, 0, 0, 1274, 1275, 0, + 1232, 346, 346, 1226, 1226, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 914, 1232, 1259, 1259, 1259, 1259, 1259, + 1259, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1226, 346, 0, 346, 346, + 346, 346, 346, 346, 0, 0, 0, 346, + 346, 346, 0, 1276, 346, 1277, 346, 0, + 0, 0, 346, 346, 0, 346, 0, 346, + 346, 0, 0, 0, 346, 346, 0, 0, + 0, 346, 346, 346, 0, 0, 0, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 0, 0, 0, 0, 1278, + 1231, 1226, 1231, 1231, 0, 0, 0, 1279, + 1280, 1231, 0, 1281, 1282, 1283, 1262, 0, + 0, 346, 0, 0, 0, 0, 0, 0, + 1284, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1259, 1259, 1259, 77, 77, 77, 77, + 77, 77, 11, 77, 0, 0, 0, 0, + 0, 1226, 1231, 1231, 1231, 1226, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 346, + 346, 346, 0, 346, 346, 346, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 0, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 0, 0, 1250, 346, 1226, + 1226, 1226, 1231, 1231, 1231, 1231, 0, 1285, + 1226, 1286, 0, 1226, 1226, 1226, 1240, 0, + 0, 0, 0, 0, 0, 0, 1287, 1288, + 0, 1232, 1232, 1232, 0, 0, 346, 0, + 0, 346, 346, 1226, 1226, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 0, 0, 0, 0, 0, 0, 0, + 1120, 1289, 1289, 1289, 1289, 1289, 1289, 1289, + 914, 346, 1226, 1231, 1231, 1120, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 346, + 346, 346, 0, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 346, 346, + 346, 346, 346, 0, 0, 1250, 346, 1231, + 1290, 1291, 1231, 1292, 1231, 1231, 0, 1293, + 1294, 1295, 0, 1296, 1297, 1226, 1262, 0, + 0, 0, 0, 0, 0, 0, 1298, 1299, + 0, 0, 0, 0, 0, 0, 346, 346, + 0, 346, 346, 1226, 1226, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 0, 346, 346, 1231, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1226, 1226, 1231, 1231, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 346, + 346, 346, 0, 346, 346, 346, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, + 1232, 1232, 1232, 1232, 1300, 1300, 346, 1301, + 1231, 1231, 1226, 1226, 1226, 1226, 0, 1302, + 1303, 1231, 0, 1304, 1305, 1306, 1240, 1307, + 914, 0, 0, 0, 0, 346, 346, 346, + 1308, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 346, 346, 346, 1226, 1226, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 914, 346, 346, 346, 346, 346, + 346, 0, 1226, 1231, 1231, 0, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 0, 0, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 0, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 346, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 0, 0, 1309, 0, 0, 0, 0, + 1310, 1231, 1231, 1226, 1226, 1226, 0, 1226, + 0, 1231, 1311, 1312, 1231, 1313, 1314, 1315, + 1316, 0, 0, 0, 0, 0, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 0, 0, 1231, 1231, 1120, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1226, 346, 1317, 1226, 1226, 1226, + 1226, 1318, 1318, 1300, 0, 0, 0, 0, + 11, 346, 346, 346, 346, 346, 346, 596, + 1226, 1319, 1319, 1319, 1319, 1226, 1226, 1226, + 1120, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1120, 1120, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 346, 346, 0, 346, 0, 346, + 346, 346, 346, 346, 0, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 346, 0, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1226, 346, 1320, 1226, 1226, 1226, + 1226, 1321, 1321, 1300, 1226, 1226, 346, 0, + 0, 346, 346, 346, 346, 346, 0, 596, + 0, 1322, 1322, 1322, 1322, 1226, 1226, 1226, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 1323, 1324, 346, + 346, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 914, 914, 914, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1325, 1120, 1120, + 1120, 1120, 1120, 1120, 914, 1120, 914, 914, + 914, 628, 628, 914, 914, 914, 914, 914, + 914, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 914, 628, 914, + 628, 914, 1326, 12, 13, 12, 13, 1231, + 1231, 346, 346, 346, 1327, 346, 346, 346, + 346, 0, 346, 346, 346, 346, 1328, 346, + 346, 346, 346, 1329, 346, 346, 346, 346, + 1330, 346, 346, 346, 346, 1331, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1332, 346, 346, 346, 0, 0, + 0, 0, 1333, 1334, 1335, 1336, 1337, 1338, + 1339, 1340, 1341, 1334, 1334, 1334, 1334, 1226, + 1231, 1334, 1342, 615, 615, 1300, 1120, 615, + 615, 346, 346, 346, 346, 346, 1226, 1226, + 1226, 1226, 1226, 1226, 1343, 1226, 1226, 1226, + 1226, 0, 1226, 1226, 1226, 1226, 1344, 1226, + 1226, 1226, 1226, 1345, 1226, 1226, 1226, 1226, + 1346, 1226, 1226, 1226, 1226, 1347, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1348, 1226, 1226, 1226, 0, 914, + 914, 914, 914, 914, 914, 914, 914, 628, + 914, 914, 914, 914, 914, 914, 0, 914, + 914, 1120, 1120, 1120, 1120, 1120, 914, 914, + 914, 914, 1120, 1120, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 1349, 1350, + 346, 346, 346, 346, 1351, 1351, 1226, 1352, + 1226, 1226, 1231, 1226, 1226, 1226, 1226, 1226, + 1250, 1351, 1300, 1300, 1231, 1231, 1226, 1226, + 346, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1120, 1120, 1120, 1120, 1120, + 1120, 346, 346, 346, 346, 346, 346, 1231, + 1231, 1226, 1226, 346, 346, 346, 346, 1226, + 1226, 1226, 346, 1351, 1351, 1351, 346, 346, + 1351, 1351, 1351, 1351, 1351, 1351, 1351, 346, + 346, 346, 1226, 1226, 1226, 1226, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 1226, 1351, 1231, 1226, 1226, + 1351, 1351, 1351, 1351, 1351, 1351, 628, 346, + 1351, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1351, 1351, 1351, 1226, 914, + 914, 1353, 1354, 1355, 1356, 1357, 1358, 1359, + 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, + 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, + 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, + 1384, 1385, 1386, 1387, 1388, 1389, 1390, 0, + 1391, 0, 0, 0, 0, 0, 1392, 0, + 0, 1393, 1394, 1395, 1396, 1397, 1398, 1399, + 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, + 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, + 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, + 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, + 1432, 1433, 1434, 1435, 1120, 1436, 1437, 1438, + 1439, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1441, 1442, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 0, 346, 346, 346, 346, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 0, 346, 346, 346, 346, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 0, 0, 615, 615, + 615, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 0, 0, 0, 0, 0, + 0, 1445, 1446, 1447, 1448, 1449, 1450, 1451, + 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, + 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, + 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, + 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, + 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, + 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, + 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, + 1508, 1509, 1510, 1511, 1512, 1513, 1514, 1515, + 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, + 1524, 1525, 1526, 1527, 1528, 1529, 1530, 0, + 0, 1531, 1532, 1533, 1534, 1535, 1536, 0, + 0, 1162, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 914, 1120, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 8, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 12, 13, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1120, 1120, 1120, 1537, + 1537, 1537, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 1226, 1226, 1300, 1538, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 1226, 1226, 1538, 1120, 1120, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 1226, 1226, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 346, + 346, 346, 0, 1226, 1226, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 649, 649, 1231, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1226, + 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1300, 1226, 1120, 1120, 1120, + 596, 1120, 1120, 1120, 11, 346, 615, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 1289, 1289, 1289, 1289, 1289, 1289, 1289, + 1289, 1289, 1289, 0, 0, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 1162, + 9, 9, 9, 9, 649, 649, 649, 1539, + 649, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 596, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 1226, 1226, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1164, 346, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 1226, 1226, 1226, 1231, 1231, 1231, 1231, + 1226, 1226, 1231, 1231, 1231, 0, 0, 0, + 0, 1231, 1231, 1226, 1231, 1231, 1231, 1231, + 1231, 1231, 1163, 615, 628, 0, 0, 0, + 0, 77, 0, 0, 0, 9, 9, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 0, 346, 346, 346, 346, 346, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1259, 0, 0, 0, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 615, 628, 1231, 1231, 1226, 0, 0, 1120, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 1231, 1226, + 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 0, 1300, 1351, 1226, 1351, 1351, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, + 1231, 1231, 1231, 1231, 1226, 1226, 615, 615, + 615, 615, 615, 615, 615, 615, 0, 0, + 628, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 596, 1120, 1120, 1120, 1120, 1120, 1120, 0, + 0, 615, 615, 615, 615, 615, 628, 628, + 628, 628, 628, 628, 615, 615, 628, 915, + 628, 628, 615, 615, 628, 628, 615, 615, + 615, 615, 615, 628, 615, 615, 615, 615, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1226, 1226, 1226, 1226, 1231, 1540, 1541, + 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1549, + 346, 346, 1550, 1551, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 1250, 1552, 1226, + 1226, 1226, 1226, 1553, 1554, 1555, 1556, 1557, + 1558, 1559, 1560, 1561, 1562, 1538, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 615, 628, 615, 615, + 615, 615, 615, 615, 615, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 1120, 1120, + 0, 1226, 1226, 1231, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1231, 1226, 1226, 1226, 1226, 1231, + 1231, 1226, 1226, 1538, 1300, 1226, 1226, 346, + 346, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 1250, + 1231, 1226, 1226, 1231, 1231, 1231, 1226, 1231, + 1226, 1226, 1226, 1538, 1538, 0, 0, 0, + 0, 0, 0, 0, 0, 1120, 1120, 1120, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1226, + 1250, 0, 0, 0, 1120, 1120, 1120, 1120, + 1120, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 346, 346, + 346, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 596, 596, 596, 596, 596, 596, 1120, + 1120, 1563, 1564, 1565, 1566, 1567, 1567, 1568, + 1569, 1570, 0, 0, 0, 0, 0, 0, + 0, 1571, 1572, 1573, 1574, 1575, 1576, 1577, + 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, + 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, + 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, + 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, + 1610, 1611, 1612, 1613, 0, 0, 1614, 1615, + 1616, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 0, 0, 0, 0, 0, 0, 0, + 0, 615, 615, 615, 1120, 641, 628, 628, + 628, 628, 628, 615, 615, 628, 628, 628, + 628, 615, 1231, 641, 641, 641, 641, 641, + 641, 641, 346, 346, 346, 346, 628, 346, + 346, 346, 346, 346, 346, 615, 346, 346, + 1231, 615, 615, 346, 0, 0, 0, 0, + 0, 1617, 1618, 1619, 1620, 1621, 1622, 1623, + 1624, 1625, 1626, 1627, 1628, 1629, 1630, 1631, + 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, + 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1647, + 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, + 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, + 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, + 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, + 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, + 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, + 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1703, + 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, + 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, + 1720, 1721, 1722, 1723, 1724, 1725, 1726, 1727, + 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, + 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, + 1744, 1745, 1746, 1747, 1748, 1749, 1750, 1751, + 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, + 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, + 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1775, + 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, + 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1791, + 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, + 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807, + 1808, 615, 615, 628, 615, 615, 615, 615, + 615, 615, 615, 628, 615, 615, 651, 1809, + 628, 630, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 627, + 1164, 1164, 628, 1810, 615, 650, 628, 615, + 628, 1811, 1812, 1813, 1814, 1815, 1816, 1817, + 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1825, + 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, + 1834, 1835, 1836, 1837, 1838, 1839, 1840, 1841, + 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, + 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, + 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, + 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, + 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, + 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889, + 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, + 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905, + 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, + 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, + 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, + 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, + 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, + 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, + 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, + 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, + 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, + 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, + 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, + 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, + 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, + 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, + 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, + 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, + 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, + 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, + 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, + 2082, 2083, 2084, 2085, 2086, 2087, 2088, 0, + 0, 2089, 2090, 2091, 2092, 2093, 2094, 0, + 0, 2095, 2096, 2097, 2098, 2099, 2100, 2101, + 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, + 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, + 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, + 2126, 2127, 2128, 2129, 2130, 2131, 2132, 0, + 0, 2133, 2134, 2135, 2136, 2137, 2138, 0, + 0, 2139, 2140, 2141, 2142, 2143, 2144, 2145, + 2146, 0, 2147, 0, 2148, 0, 2149, 0, + 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, + 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, + 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, + 2174, 2175, 2176, 2177, 2178, 2179, 2180, 0, + 0, 2181, 2182, 2183, 2184, 2185, 2186, 2187, + 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, + 2196, 2197, 2198, 2199, 2200, 2201, 2202, 2203, + 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, + 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, + 2220, 2221, 2222, 2223, 2224, 2225, 2226, 2227, + 2228, 2229, 2230, 2231, 2232, 2233, 0, 2234, + 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2242, + 2243, 2244, 2245, 2246, 2247, 2248, 0, 2249, + 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, + 2258, 2259, 2260, 2261, 2262, 0, 0, 2263, + 2264, 2265, 2266, 2267, 2268, 0, 2269, 2270, + 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, + 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, + 2287, 0, 0, 2288, 2289, 2290, 0, 2291, + 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299, + 0, 2300, 2301, 2302, 2302, 2302, 2302, 2302, + 2303, 2302, 2302, 2302, 1539, 2304, 2305, 2306, + 2307, 1162, 2308, 1162, 1162, 1162, 1162, 9, + 2309, 2310, 2311, 2312, 2310, 2310, 2311, 2312, + 2310, 9, 9, 9, 9, 2313, 2314, 2315, + 9, 2316, 2317, 2318, 2319, 2320, 2321, 2322, + 76, 10, 10, 10, 2323, 2324, 9, 2325, + 2326, 9, 81, 93, 9, 2327, 9, 2328, + 48, 48, 9, 9, 9, 2329, 12, 13, + 2330, 2331, 2332, 9, 9, 9, 9, 9, + 9, 9, 9, 75, 9, 48, 9, 9, + 2333, 9, 9, 9, 9, 9, 9, 9, + 2302, 1539, 1539, 1539, 1539, 1539, 0, 2334, + 2335, 2336, 2337, 1539, 1539, 1539, 1539, 1539, + 1539, 2338, 2339, 0, 0, 2340, 2341, 2342, + 2343, 2344, 2345, 2346, 2347, 2348, 2349, 2350, + 2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, + 2359, 2360, 2361, 2362, 2363, 2364, 2365, 2366, + 0, 2367, 2368, 2369, 2370, 2371, 2372, 2373, + 2374, 2375, 2376, 2377, 2378, 2379, 0, 0, + 0, 11, 11, 11, 11, 11, 11, 11, + 11, 2380, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 615, 615, 641, 641, 615, 615, 615, + 615, 641, 641, 641, 615, 615, 915, 915, + 915, 915, 615, 915, 915, 915, 641, 641, + 615, 628, 615, 641, 641, 628, 628, 628, + 628, 615, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2381, 2382, 2383, 2384, 77, 2385, 2386, + 2387, 77, 2388, 2389, 2390, 2391, 2392, 2393, + 2394, 2395, 2396, 2397, 2398, 77, 2399, 2400, + 77, 75, 2401, 2402, 2403, 2404, 2405, 77, + 77, 2406, 2407, 2408, 77, 2409, 77, 2410, + 77, 2411, 77, 2412, 2413, 2414, 2415, 84, + 2416, 2417, 2418, 2419, 2420, 2421, 2422, 2423, + 2424, 2425, 2426, 77, 2427, 2428, 2429, 2430, + 2431, 2432, 75, 75, 75, 75, 2433, 2434, + 2435, 2436, 2437, 77, 75, 77, 77, 2438, + 914, 2439, 2440, 2441, 2442, 2443, 2444, 2445, + 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453, + 2454, 2455, 2456, 2457, 2458, 2459, 2460, 2461, + 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, + 2470, 2471, 2472, 2473, 2474, 2475, 2476, 2477, + 2478, 2479, 2480, 2481, 2482, 2483, 2484, 2485, + 2486, 1537, 1537, 1537, 2487, 2488, 1537, 1537, + 1537, 1537, 2489, 77, 77, 0, 0, 0, + 0, 2490, 75, 2491, 75, 2492, 79, 79, + 79, 79, 79, 2493, 2494, 77, 77, 77, + 77, 75, 77, 77, 75, 77, 77, 75, + 77, 77, 79, 79, 77, 77, 77, 2495, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 2496, 2497, + 2498, 2499, 77, 2500, 77, 2501, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 2502, 2502, 2503, 2504, 75, 75, + 75, 2505, 2506, 2502, 2507, 2508, 2502, 75, + 75, 75, 2502, 14, 85, 75, 2502, 2502, + 75, 75, 75, 2502, 2502, 2502, 2502, 75, + 2502, 2502, 2502, 2502, 2509, 2510, 2511, 2512, + 75, 75, 75, 75, 2502, 2513, 2514, 2502, + 2515, 2516, 2502, 2502, 2502, 75, 75, 75, + 75, 75, 2502, 75, 2502, 2517, 2502, 2502, + 2502, 2502, 2518, 2502, 2519, 2520, 2521, 2502, + 2522, 2523, 2524, 2502, 2502, 2502, 2525, 75, + 75, 75, 75, 2502, 2502, 2502, 2502, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 2502, 2526, 2527, 2528, 75, 2529, 2530, 2502, + 2502, 2502, 2502, 2502, 2502, 75, 2531, 2532, + 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, + 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2502, + 2502, 2548, 2549, 2550, 2551, 2552, 2553, 2554, + 2555, 2556, 2557, 2502, 2502, 2502, 75, 75, + 2502, 2502, 2558, 2559, 75, 75, 75, 75, + 75, 2502, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 2560, 2502, 75, 75, 2502, + 2502, 2561, 2562, 2502, 2563, 2564, 2565, 2566, + 2567, 2502, 2502, 2568, 2569, 2570, 2571, 2502, + 2502, 2502, 75, 75, 75, 75, 75, 2502, + 2502, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 2502, 2502, 2502, 2502, 2502, 75, + 75, 2502, 2502, 75, 75, 75, 75, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2572, 2573, 2574, 2575, 2502, 2502, 2502, + 2502, 2502, 2502, 2576, 2577, 2578, 2579, 75, + 75, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 77, 77, 77, 77, 77, 77, 77, + 77, 12, 13, 12, 13, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 2580, 2580, 77, 77, 77, + 77, 2502, 2502, 77, 77, 77, 77, 77, + 77, 79, 2581, 2582, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 77, 75, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 79, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 914, 77, + 77, 77, 77, 77, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 79, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 75, 75, 75, + 75, 75, 75, 77, 77, 77, 77, 77, + 77, 77, 2580, 2580, 2580, 2580, 79, 79, + 79, 2580, 79, 79, 2580, 77, 77, 77, + 77, 79, 79, 79, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2583, 2584, 2585, 2586, 2587, 2588, 2589, + 2590, 2591, 2592, 2593, 2594, 2595, 2596, 2597, + 2598, 2599, 2600, 2601, 2602, 2603, 2604, 2605, + 2606, 2607, 2608, 2609, 2610, 2611, 2612, 2613, + 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, + 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, + 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, + 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, + 2646, 2647, 2648, 2649, 2650, 2651, 2652, 2653, + 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, + 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, + 2670, 2671, 2672, 2673, 2674, 2675, 2676, 2677, + 2678, 2679, 2680, 2681, 2682, 2683, 2684, 2685, + 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, + 2694, 2695, 2696, 2697, 2698, 2699, 2700, 2701, + 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, + 2710, 2711, 2712, 2713, 2714, 2715, 2716, 2717, + 2718, 2719, 2720, 2721, 1289, 1289, 1289, 1289, + 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, + 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, + 1289, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 79, 79, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 79, + 75, 77, 77, 77, 77, 77, 77, 77, + 77, 79, 75, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 75, 75, 75, 2722, 2722, 2723, 2723, + 75, 79, 79, 79, 79, 79, 79, 77, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 77, 2580, 2580, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 2722, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 2580, 79, 79, 79, 79, 79, 79, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 79, 79, 79, 2580, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 2580, 79, 79, 79, 79, 79, + 79, 79, 79, 2580, 2580, 2724, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 2580, 2580, + 79, 79, 79, 79, 79, 2580, 2580, 79, + 79, 79, 79, 79, 79, 79, 79, 2580, + 79, 79, 79, 79, 79, 2580, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 2580, 79, 79, 79, 79, + 79, 79, 79, 2580, 2580, 79, 2580, 79, + 79, 79, 79, 2580, 79, 79, 2580, 79, + 79, 79, 79, 79, 79, 79, 2580, 77, + 77, 79, 79, 2580, 2580, 79, 79, 79, + 79, 79, 79, 79, 77, 79, 77, 79, + 77, 77, 77, 77, 77, 77, 79, 77, + 77, 77, 79, 77, 77, 77, 77, 77, + 77, 2580, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 79, 79, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 79, 77, 77, + 79, 77, 77, 77, 77, 2580, 77, 2580, + 77, 77, 77, 77, 2580, 2580, 2580, 77, + 2580, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 79, 79, 79, 79, + 79, 12, 13, 12, 13, 12, 13, 12, + 13, 12, 13, 12, 13, 12, 13, 1289, + 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, + 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, + 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, + 1289, 1289, 1289, 1289, 1289, 77, 2580, 2580, + 2580, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 79, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 2580, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 2580, 2502, 75, 75, 2502, 2502, 12, 13, + 75, 2502, 2502, 75, 2502, 2502, 2502, 75, + 75, 75, 75, 75, 2502, 2502, 2502, 2502, + 75, 75, 75, 75, 75, 2502, 2502, 2502, + 75, 75, 75, 2502, 2502, 2502, 2502, 12, + 13, 12, 13, 12, 13, 12, 13, 12, + 13, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 2722, 2722, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 75, 75, 2502, 2502, 2502, 2502, + 2502, 2502, 75, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 75, 75, 75, 75, 75, 75, 75, + 75, 2502, 75, 75, 75, 75, 75, 75, + 75, 2502, 2502, 2502, 2502, 2502, 2502, 75, + 75, 75, 2502, 75, 75, 75, 75, 2502, + 2502, 2502, 2502, 2502, 75, 2502, 2502, 75, + 75, 12, 13, 12, 13, 2502, 75, 75, + 75, 75, 2502, 75, 2502, 2502, 2502, 75, + 75, 2502, 2502, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 2502, 2502, 2502, + 2502, 2502, 2502, 75, 75, 12, 13, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 2502, 2502, 2725, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 75, 2502, + 2502, 2502, 2502, 75, 75, 2502, 75, 2502, + 75, 75, 2502, 75, 2502, 2502, 2502, 2502, + 75, 75, 75, 75, 75, 2502, 2502, 75, + 75, 75, 75, 75, 75, 2502, 2502, 2502, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 2502, 2502, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 2502, 2502, 75, + 75, 75, 75, 2502, 2502, 2502, 2502, 75, + 2502, 2502, 75, 75, 2502, 2726, 2727, 2728, + 75, 75, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 75, 75, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 75, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 2502, 2502, 2502, 2502, 2502, 2502, 2502, 2502, + 75, 75, 75, 75, 75, 2729, 2730, 2502, + 75, 75, 75, 2502, 2502, 2502, 2502, 2502, + 75, 75, 75, 75, 75, 2502, 2502, 2502, + 75, 75, 75, 75, 2502, 75, 75, 75, + 2502, 2502, 2502, 2502, 2502, 75, 2502, 75, + 75, 77, 77, 77, 77, 77, 79, 79, + 79, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 2580, 2580, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 77, 77, + 75, 75, 75, 75, 75, 75, 77, 77, + 77, 2580, 77, 77, 77, 77, 2580, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 0, 0, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 0, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 2731, + 77, 2732, 2733, 2734, 2735, 2736, 2737, 2738, + 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2746, + 2747, 2748, 2749, 2750, 2751, 2752, 2753, 2754, + 2755, 2756, 2757, 2758, 2759, 2760, 2761, 2762, + 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, + 2771, 2772, 2773, 2774, 2775, 2776, 2777, 2778, + 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, + 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, + 2795, 2796, 2797, 2798, 2799, 2800, 2801, 2802, + 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, + 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, + 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826, + 2827, 2828, 2829, 2830, 2831, 2832, 2833, 2834, + 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, + 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850, + 2851, 2852, 2853, 2854, 2855, 2856, 2857, 2858, + 2859, 2860, 2861, 2862, 2863, 2864, 2865, 2866, + 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, + 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, + 2883, 2884, 2885, 2886, 2887, 2888, 2889, 2890, + 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, + 2899, 2900, 2901, 2902, 2903, 2904, 2905, 2906, + 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, + 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, + 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, + 2931, 2932, 2933, 2934, 2935, 2936, 2937, 2938, + 2939, 2940, 2941, 2942, 2943, 2944, 2945, 2946, + 2947, 2948, 2949, 2950, 2951, 2952, 2953, 2954, + 2955, 2956, 2957, 2958, 2959, 2960, 77, 77, + 77, 77, 77, 77, 2961, 2962, 2963, 2964, + 615, 615, 615, 2965, 2966, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 1289, 9, + 9, 2967, 2968, 2969, 2970, 2971, 2972, 2973, + 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, + 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, + 2990, 2991, 2992, 2993, 2994, 2995, 2996, 2997, + 2998, 2999, 3000, 3001, 3002, 3003, 3004, 0, + 3005, 0, 0, 0, 0, 0, 3006, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 0, 0, 0, 0, 0, 0, 0, + 3007, 1120, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1300, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 9, 9, 81, 93, 81, 93, 9, + 9, 9, 81, 93, 9, 81, 93, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 1162, 9, 9, 1162, 9, 81, 93, 9, + 9, 81, 93, 12, 13, 12, 13, 12, + 13, 12, 13, 9, 9, 9, 9, 9, + 595, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 1162, 1162, 9, 9, 9, + 9, 1162, 9, 2312, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 77, 77, 9, 9, 9, 12, 13, + 12, 13, 12, 13, 12, 13, 1162, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 0, 3008, 3008, 3008, 3008, + 3009, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3010, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3011, 3012, 3013, 3014, 3015, 3016, 3017, + 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, + 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, + 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, + 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, + 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, + 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, + 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, + 3074, 3075, 3076, 3077, 3078, 3079, 3080, 3081, + 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, + 3090, 3091, 3092, 3093, 3094, 3095, 3096, 3097, + 3098, 3099, 3100, 3101, 3102, 3103, 3104, 3105, + 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, + 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, + 3122, 3123, 3124, 3125, 3126, 3127, 3128, 3129, + 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, + 3138, 3139, 3140, 3141, 3142, 3143, 3144, 3145, + 3146, 3147, 3148, 3149, 3150, 3151, 3152, 3153, + 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, + 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, + 3170, 3171, 3172, 3173, 3174, 3175, 3176, 3177, + 3178, 3179, 3180, 3181, 3182, 3183, 3184, 3185, + 3186, 3187, 3188, 3189, 3190, 3191, 3192, 3193, + 3194, 3195, 3196, 3197, 3198, 3199, 3200, 3201, + 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, + 3210, 3211, 3212, 3213, 3214, 3215, 3216, 3217, + 3218, 3219, 3220, 3221, 3222, 3223, 3224, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3225, 3226, 3226, 3226, 3008, 3227, 3228, + 3229, 3230, 3231, 3230, 3231, 3230, 3231, 3230, + 3231, 3230, 3231, 3008, 3008, 3230, 3231, 3230, + 3231, 3230, 3231, 3230, 3231, 3232, 3233, 3234, + 3234, 3008, 3229, 3229, 3229, 3229, 3229, 3229, + 3229, 3229, 3229, 1810, 1164, 627, 1163, 3235, + 3235, 3236, 3227, 3227, 3227, 3227, 3227, 3237, + 3008, 3238, 3239, 3240, 3227, 3228, 3241, 3008, + 77, 0, 3228, 3228, 3228, 3228, 3228, 3242, + 3228, 3228, 3228, 3228, 3243, 3244, 3245, 3246, + 3247, 3248, 3249, 3250, 3251, 3252, 3253, 3254, + 3255, 3256, 3257, 3258, 3259, 3260, 3261, 3262, + 3263, 3264, 3265, 3266, 3228, 3267, 3268, 3269, + 3270, 3271, 3272, 3228, 3228, 3228, 3228, 3228, + 3273, 3274, 3275, 3276, 3277, 3278, 3279, 3280, + 3281, 3282, 3283, 3284, 3285, 3286, 3287, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3288, 3228, 3228, + 0, 0, 3289, 3290, 3291, 3292, 3293, 3294, + 3295, 3232, 3228, 3228, 3228, 3228, 3228, 3296, + 3228, 3228, 3228, 3228, 3297, 3298, 3299, 3300, + 3301, 3302, 3303, 3304, 3305, 3306, 3307, 3308, + 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, + 3317, 3318, 3319, 3320, 3228, 3321, 3322, 3323, + 3324, 3325, 3326, 3228, 3228, 3228, 3228, 3228, + 3327, 3328, 3329, 3330, 3331, 3332, 3333, 3334, + 3335, 3336, 3337, 3338, 3339, 3340, 3341, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3342, 3343, 3344, 3345, 3228, 3346, 3228, 3228, + 3347, 3348, 3349, 3350, 3226, 3227, 3351, 3352, + 3353, 0, 0, 0, 0, 0, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 0, 3354, 3355, 3356, 3357, 3358, 3359, + 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, + 3368, 3369, 3370, 3371, 3372, 3373, 3374, 3375, + 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, + 3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, + 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, + 3400, 3401, 3402, 3403, 3404, 3405, 3406, 3407, + 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, + 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, + 3424, 3425, 3426, 3427, 3428, 3429, 3430, 3431, + 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, + 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, + 0, 3448, 3448, 3449, 3450, 3451, 3452, 3453, + 3454, 3455, 3456, 3457, 3458, 3459, 3460, 3461, + 3462, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3008, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3463, 3464, 3465, 3466, 3467, 3468, 3469, + 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, + 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, + 3486, 3487, 3488, 3489, 3490, 3491, 3492, 3493, + 0, 3494, 3495, 3496, 3497, 3498, 3499, 3500, + 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, + 3509, 3510, 3511, 3512, 3513, 3514, 3515, 3516, + 3517, 3518, 3519, 3520, 3521, 3522, 3523, 3524, + 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, + 3533, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 3534, 3535, 3536, 3537, 3538, 3539, 3540, + 3541, 3542, 3543, 3544, 3545, 3546, 3547, 3548, + 3549, 3550, 3551, 3552, 3553, 3554, 3555, 3556, + 3557, 3558, 3559, 3560, 3561, 3562, 3563, 3564, + 3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, + 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3580, + 3448, 3581, 3582, 3583, 3584, 3585, 3586, 3587, + 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, + 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, + 3604, 3605, 3606, 3607, 3608, 3609, 3610, 3611, + 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, + 3620, 3621, 3622, 3623, 3624, 3625, 3626, 3627, + 3628, 3629, 3630, 3631, 3632, 3633, 3634, 3635, + 3636, 3637, 3638, 3639, 3640, 3641, 3642, 3643, + 3644, 3645, 3646, 3647, 3648, 3649, 3650, 3651, + 3652, 3653, 3654, 3655, 3656, 3657, 3658, 3659, + 3660, 3661, 3662, 3663, 3664, 3665, 3666, 3667, + 3668, 3669, 3670, 3671, 3672, 3673, 3674, 3675, + 3676, 3677, 3678, 3679, 3680, 3681, 3682, 3683, + 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, + 3692, 3693, 3694, 3695, 3696, 3697, 3698, 3699, + 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, + 3708, 3709, 3710, 3711, 3712, 3713, 3714, 3715, + 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, + 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, + 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, + 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, + 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, + 3756, 3757, 3758, 3759, 3760, 3761, 3762, 3763, + 3764, 3765, 3766, 3767, 3768, 3769, 3770, 3771, + 3772, 3773, 3774, 3775, 3776, 3777, 3778, 3779, + 3780, 3781, 3782, 3783, 3784, 3785, 3786, 3787, + 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, + 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, + 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, + 3812, 3813, 3814, 3815, 3816, 3817, 3818, 3819, + 3820, 3821, 3822, 3823, 3824, 3825, 3826, 3827, + 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, + 3836, 3837, 3838, 3839, 3840, 3841, 3842, 3843, + 3844, 3845, 3846, 3847, 3848, 3849, 3850, 3851, + 3852, 3853, 3854, 3855, 3856, 3857, 3858, 3859, + 3860, 3861, 3862, 3863, 3864, 3865, 3866, 3867, + 3868, 3869, 3870, 3871, 3872, 3873, 3874, 3875, + 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, + 3884, 3885, 3886, 3887, 3888, 3889, 3890, 3891, + 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, + 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3907, + 3908, 3909, 3910, 3911, 3912, 3913, 3914, 3915, + 3916, 3917, 3918, 3919, 3920, 3921, 3922, 3923, + 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, + 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939, + 3940, 3941, 3942, 3943, 3944, 3945, 3946, 3947, + 3948, 3949, 3950, 3951, 3952, 3953, 3954, 3955, + 3956, 3957, 3958, 3959, 3960, 3961, 3962, 3963, + 3964, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3227, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 0, 0, + 0, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 596, 596, 596, 596, 596, 596, 1120, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 596, 9, 9, + 9, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 346, 346, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3965, 3966, 3967, 3968, 3969, 3970, 3971, + 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, + 3980, 3981, 3982, 3983, 3984, 3985, 3986, 3987, + 3988, 3989, 3990, 3991, 3992, 3993, 3994, 3995, + 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, + 4004, 4005, 4006, 4007, 4008, 4009, 4010, 346, + 615, 915, 915, 915, 9, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 9, + 595, 4011, 4012, 4013, 4014, 4015, 4016, 4017, + 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, + 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, + 4034, 4035, 4036, 4037, 4038, 4039, 4040, 615, + 615, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 615, 615, 1120, 1120, 1120, 1120, 1120, + 1120, 0, 0, 0, 0, 0, 0, 0, + 0, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 595, 595, 595, 595, 595, 595, 595, 595, + 595, 47, 47, 4041, 4042, 4043, 4044, 4045, + 4046, 4047, 4048, 4049, 4050, 4051, 4052, 4053, + 4054, 4055, 4056, 4057, 4058, 4059, 4060, 4061, + 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, + 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077, + 4078, 4079, 4080, 4081, 4082, 4083, 4084, 4085, + 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, + 4094, 4095, 4096, 4097, 4098, 4099, 4100, 4101, + 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, + 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, + 4118, 4119, 4120, 4121, 4122, 4123, 4124, 4125, + 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, + 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, + 4142, 595, 4143, 4143, 4144, 4145, 4146, 4147, + 346, 4148, 4149, 4150, 4151, 4152, 4153, 4154, + 4155, 4156, 4157, 4158, 4159, 4160, 4161, 4162, + 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, + 4171, 4172, 4173, 4174, 4175, 4176, 4177, 4178, + 4179, 4180, 4181, 4182, 4183, 4184, 4185, 4186, + 4187, 4188, 4189, 4190, 4191, 4192, 4193, 4194, + 4195, 4196, 4197, 4198, 4199, 4200, 4201, 4202, + 4203, 4204, 4205, 4206, 0, 0, 0, 0, + 0, 4207, 4208, 0, 4209, 0, 4210, 4211, + 4212, 4213, 4214, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4215, 4216, 4217, 4218, 4219, + 346, 4220, 4221, 4222, 346, 346, 346, 346, + 346, 346, 346, 1226, 346, 346, 346, 1262, + 346, 346, 346, 346, 1226, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1231, 1231, 1226, 1226, + 1231, 77, 77, 77, 77, 1300, 0, 0, + 0, 1259, 1259, 1259, 1259, 1259, 1259, 914, + 914, 11, 84, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 9, 9, 9, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 1231, 1231, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1262, 1226, 0, + 0, 0, 0, 0, 0, 0, 0, 1120, + 1120, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 346, 346, 346, 346, 346, + 346, 1120, 1120, 1120, 346, 1120, 346, 346, + 1226, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 1226, + 1226, 1226, 1226, 1226, 628, 628, 628, 1120, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1231, 1538, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1120, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 0, 0, + 0, 1226, 1226, 1226, 1231, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1250, 1231, 1231, 1226, + 1226, 1226, 1226, 1231, 1231, 1226, 1226, 1231, + 1231, 1538, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 0, + 596, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 1120, + 1120, 346, 346, 346, 346, 346, 1226, 596, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1226, 1226, 1226, 1226, 1226, 1226, + 1231, 1231, 1226, 1226, 1231, 1231, 1226, 1226, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 1226, 346, 346, 346, + 346, 346, 346, 346, 346, 1226, 1231, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 1120, 1120, 1120, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 596, 346, 346, 346, 346, 346, 346, + 914, 914, 914, 346, 1351, 1226, 1351, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 615, 346, 615, 615, 628, 346, 346, + 615, 615, 346, 346, 346, 346, 346, 615, + 615, 346, 615, 346, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 346, 346, 596, 1120, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1231, 1226, 1226, 1231, + 1231, 1120, 1120, 346, 596, 596, 1231, 1300, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 346, 346, 346, 346, 346, 346, + 0, 0, 346, 346, 346, 346, 346, 346, + 0, 0, 346, 346, 346, 346, 346, 346, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 4223, 4224, 4225, 4226, 4227, 4228, 4229, + 4230, 4231, 4232, 4233, 4234, 4235, 4236, 4237, + 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4245, + 4246, 4247, 4248, 4249, 4250, 4251, 4252, 4253, + 4254, 4255, 4256, 4257, 4258, 4259, 4260, 4261, + 4262, 4263, 4264, 4265, 4143, 4266, 4267, 4268, + 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, + 4277, 4278, 4279, 47, 47, 0, 0, 0, + 0, 4280, 4281, 4282, 4283, 4284, 4285, 4286, + 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, + 4295, 4296, 4297, 4298, 4299, 4300, 4301, 4302, + 4303, 4304, 4305, 4306, 4307, 4308, 4309, 4310, + 4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, + 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4326, + 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, + 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, + 4343, 4344, 4345, 4346, 4347, 4348, 4349, 4350, + 4351, 4352, 4353, 4354, 4355, 4356, 4357, 4358, + 4359, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1231, 1231, 1226, 1231, + 1231, 1226, 1231, 1231, 1120, 1231, 1300, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4360, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4360, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 4361, 4361, 4361, + 4361, 4361, 4361, 4361, 4361, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, + 0, 0, 0, 0, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 1444, 1444, 1444, 1444, 0, 0, 0, + 0, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4362, 4362, 4362, 4362, 4362, 4362, 4362, + 4362, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, + 4371, 4371, 4372, 4373, 4374, 4375, 4376, 4377, + 4378, 4379, 4380, 4381, 4382, 4383, 4384, 4385, + 4386, 4387, 4388, 4389, 4390, 4391, 4392, 4393, + 4394, 4395, 4396, 4397, 4398, 4399, 4400, 4401, + 4402, 4403, 4404, 4405, 4406, 4407, 4408, 4409, + 4410, 4411, 4412, 4413, 4414, 4415, 4416, 4417, + 4418, 4419, 4420, 4421, 4422, 4423, 4424, 4425, + 4426, 4427, 4428, 4429, 4430, 4431, 4432, 4433, + 4434, 4435, 4436, 4437, 4438, 4439, 4440, 4441, + 4442, 4443, 4444, 4445, 4446, 4447, 4448, 4449, + 4450, 4451, 4452, 4453, 4454, 4383, 4455, 4456, + 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, + 4465, 4466, 4467, 4468, 4469, 4470, 4471, 4472, + 4473, 4474, 4475, 4476, 4477, 4478, 4479, 4480, + 4481, 4482, 4483, 4484, 4485, 4486, 4487, 4488, + 4489, 4490, 4491, 4492, 4493, 4494, 4495, 4496, + 4497, 4498, 4499, 4500, 4501, 4502, 4503, 4504, + 4505, 4506, 4507, 4508, 4509, 4510, 4511, 4512, + 4513, 4514, 4515, 4516, 4517, 4518, 4519, 4520, + 4521, 4522, 4473, 4523, 4524, 4525, 4526, 4527, + 4528, 4529, 4530, 4457, 4531, 4532, 4533, 4534, + 4535, 4536, 4537, 4538, 4539, 4540, 4541, 4542, + 4543, 4544, 4545, 4546, 4547, 4548, 4549, 4550, + 4383, 4551, 4552, 4553, 4554, 4555, 4556, 4557, + 4558, 4559, 4560, 4561, 4562, 4563, 4564, 4565, + 4566, 4567, 4568, 4569, 4570, 4571, 4572, 4573, + 4574, 4575, 4576, 4577, 4459, 4578, 4579, 4580, + 4581, 4582, 4583, 4584, 4585, 4586, 4587, 4588, + 4589, 4590, 4591, 4592, 4593, 4594, 4595, 4596, + 4597, 4598, 4599, 4600, 4601, 4602, 4603, 4604, + 4605, 4606, 4607, 4608, 4609, 4610, 4611, 4612, + 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4620, + 4621, 4622, 4623, 4624, 4625, 4626, 4627, 3228, + 3228, 4628, 3228, 4629, 3228, 3228, 4630, 4631, + 4632, 4633, 4634, 4635, 4636, 4637, 4638, 4639, + 3228, 4640, 3228, 4641, 3228, 3228, 4642, 4643, + 3228, 3228, 3228, 4644, 4645, 4646, 4647, 4648, + 4649, 4650, 4651, 4652, 4653, 4654, 4655, 4656, + 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4664, + 4665, 4666, 4667, 4668, 4669, 4670, 4671, 4672, + 4673, 4674, 4675, 4676, 4677, 4678, 4679, 4680, + 4681, 4682, 4683, 4684, 4685, 4686, 4687, 4688, + 4512, 4689, 4690, 4691, 4692, 4693, 4694, 4694, + 4695, 4696, 4697, 4698, 4699, 4700, 4701, 4702, + 4642, 4703, 4704, 4705, 4706, 4707, 4708, 0, + 0, 4709, 4710, 4711, 4712, 4713, 4714, 4715, + 4716, 4656, 4717, 4718, 4719, 4628, 4720, 4721, + 4722, 4723, 4724, 4725, 4726, 4727, 4728, 4729, + 4730, 4731, 4665, 4732, 4666, 4733, 4734, 4735, + 4736, 4737, 4629, 4404, 4738, 4739, 4740, 4474, + 4561, 4741, 4742, 4673, 4743, 4674, 4744, 4745, + 4746, 4631, 4747, 4748, 4749, 4750, 4751, 4632, + 4752, 4753, 4754, 4755, 4756, 4757, 4688, 4758, + 4759, 4512, 4760, 4692, 4761, 4762, 4763, 4764, + 4765, 4697, 4766, 4641, 4767, 4698, 4455, 4768, + 4699, 4769, 4701, 4770, 4771, 4772, 4773, 4774, + 4703, 4637, 4775, 4704, 4776, 4705, 4777, 4371, + 4778, 4779, 4780, 4781, 4782, 4783, 4784, 4785, + 4786, 4787, 4788, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4789, 4790, 4791, 4792, 4793, 4794, 4795, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4796, 4797, 4798, 4799, + 4800, 0, 0, 0, 0, 0, 4801, 4802, + 4803, 4804, 4805, 4806, 4807, 4808, 4809, 4810, + 4811, 4812, 4813, 4814, 4815, 4816, 4817, 4818, + 4819, 4820, 4821, 4822, 4823, 4824, 4825, 4826, + 0, 4827, 4828, 4829, 4830, 4831, 0, 4832, + 0, 4833, 4834, 0, 4835, 4836, 0, 4837, + 4838, 4839, 4840, 4841, 4842, 4843, 4844, 4845, + 4846, 4847, 4848, 4849, 4850, 4851, 4852, 4853, + 4854, 4855, 4856, 4857, 4858, 4859, 4860, 4861, + 4862, 4863, 4864, 4865, 4866, 4867, 4868, 4869, + 4870, 4871, 4872, 4873, 4874, 4875, 4876, 4877, + 4878, 4879, 4880, 4881, 4882, 4883, 4884, 4885, + 4886, 4887, 4888, 4889, 4890, 4891, 4892, 4893, + 4894, 4895, 4896, 4897, 4898, 4899, 4900, 4901, + 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, + 4910, 4911, 4912, 4913, 4914, 4915, 4916, 4917, + 4918, 4919, 4920, 4921, 4922, 4923, 4924, 4925, + 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, + 4934, 4935, 4936, 4937, 4938, 4939, 4940, 4941, + 4942, 4943, 4944, 1230, 1230, 1230, 1230, 1230, + 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, + 1230, 1230, 1230, 1230, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4945, 4946, 4947, 4948, + 4949, 4950, 4951, 4952, 4953, 4954, 4955, 4956, + 4957, 4958, 4959, 4960, 4961, 4962, 4963, 4964, + 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, + 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, + 4981, 4982, 4983, 4984, 4985, 4986, 4987, 4988, + 4989, 4990, 4991, 4992, 4983, 4993, 4994, 4995, + 4996, 4997, 4998, 4999, 5000, 5001, 5002, 5003, + 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, + 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, + 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, + 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, + 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, + 5044, 5045, 5046, 5047, 5048, 5049, 5050, 5051, + 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, + 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, + 5068, 5069, 5070, 5071, 5072, 5073, 5074, 5075, + 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, + 5084, 5085, 5086, 5087, 5088, 5089, 5090, 5091, + 5092, 4984, 5093, 5094, 5095, 5096, 5097, 5098, + 5099, 5100, 5101, 5102, 5103, 5104, 5105, 5106, + 5107, 5108, 5109, 5110, 5111, 5112, 5113, 5114, + 5115, 5116, 5117, 5118, 5119, 5120, 5121, 5122, + 5123, 5124, 5125, 5126, 5127, 5128, 5129, 5130, + 5131, 5132, 5133, 5134, 5135, 5136, 5137, 5138, + 5139, 5140, 5141, 5142, 5143, 5144, 5145, 5146, + 5147, 5148, 5149, 5150, 5151, 5152, 5153, 5154, + 5155, 5156, 5157, 5158, 5159, 5160, 5161, 5162, + 5163, 5164, 5165, 5166, 5167, 5168, 5169, 5170, + 5171, 5172, 5173, 5174, 5175, 5176, 5177, 5178, + 5179, 5180, 5181, 5182, 5183, 5184, 5185, 5186, + 5187, 5188, 5189, 5190, 5191, 5192, 5193, 5194, + 5195, 5196, 5197, 5198, 5199, 5200, 5201, 5202, + 5203, 5204, 5205, 5206, 5207, 5208, 5209, 5210, + 5211, 5212, 5213, 5214, 5215, 5216, 5217, 5218, + 5219, 5220, 5221, 5222, 5223, 5224, 5225, 5226, + 5227, 5228, 5229, 5230, 5231, 5232, 5233, 5234, + 5235, 5236, 5237, 5238, 5239, 5240, 5241, 5242, + 5243, 5244, 5245, 5246, 5247, 5248, 5249, 5250, + 5251, 5252, 5253, 5254, 5255, 5256, 5257, 5258, + 5259, 5260, 5261, 5262, 5263, 5264, 5265, 5266, + 5267, 5268, 5269, 5270, 5271, 5272, 5273, 5274, + 5275, 5276, 5277, 5278, 5279, 5280, 5281, 5282, + 5283, 5284, 5285, 5286, 5287, 5288, 5289, 5290, + 5291, 5292, 5293, 5294, 5295, 5296, 5297, 5298, + 5299, 5300, 5301, 5302, 5303, 5304, 5305, 5306, + 2312, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 5307, 5308, 5309, 5310, 5311, 5312, 5313, + 5314, 5315, 5316, 5317, 5318, 5319, 5320, 5321, + 5322, 5323, 5324, 5325, 5326, 5327, 5328, 5329, + 5330, 5331, 5332, 5333, 5334, 5335, 5336, 5337, + 5338, 5339, 5340, 5341, 5342, 5343, 5344, 5345, + 5346, 5347, 5348, 5349, 5350, 5351, 5352, 5353, + 5354, 5355, 5356, 5357, 5358, 5359, 5360, 5361, + 5362, 5363, 5364, 5365, 5366, 5367, 5368, 5369, + 5370, 0, 0, 5371, 5372, 5373, 5374, 5375, + 5376, 5377, 5378, 5379, 5380, 5381, 5382, 5383, + 5384, 5385, 5386, 5387, 5388, 5389, 5390, 5391, + 5392, 5393, 5394, 5395, 5396, 5397, 5398, 5399, + 5400, 5401, 5402, 5403, 5404, 5405, 5406, 5407, + 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, + 5416, 5417, 5418, 5419, 5420, 5421, 5422, 5423, + 5424, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5425, 5426, 5427, 5428, 5429, 5430, 5431, + 5432, 5433, 5434, 5435, 5436, 5437, 77, 77, + 77, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 5438, 5439, 5440, 5441, 5442, 5443, 5444, + 5445, 5446, 5447, 0, 0, 0, 0, 0, + 0, 615, 615, 615, 615, 615, 615, 615, + 628, 628, 628, 628, 628, 628, 628, 615, + 615, 5448, 5449, 5450, 5451, 5451, 5452, 5453, + 5454, 5455, 5456, 5457, 5458, 5459, 5460, 5461, + 5462, 5463, 5464, 5465, 5466, 5467, 3226, 3226, + 5468, 5469, 5470, 5470, 5470, 5470, 5471, 5471, + 5471, 5472, 5473, 5474, 0, 5475, 5476, 5477, + 5478, 5479, 5480, 5481, 5482, 5483, 5484, 5485, + 5486, 5487, 5488, 5489, 5490, 5491, 5492, 5493, + 0, 5494, 5495, 5496, 5497, 0, 0, 0, + 0, 5498, 5499, 5500, 1192, 5501, 0, 5502, + 5503, 5504, 5505, 5506, 5507, 5508, 5509, 5510, + 5511, 5512, 5513, 5514, 5515, 5516, 5517, 5518, + 5519, 5520, 5521, 5522, 5523, 5524, 5525, 5526, + 5527, 5528, 5529, 5530, 5531, 5532, 5533, 5534, + 5535, 5536, 5537, 5538, 5539, 5540, 5541, 5542, + 5543, 5544, 5545, 5546, 5547, 5548, 5549, 5550, + 5551, 5552, 5553, 5554, 5555, 5556, 5557, 5558, + 5559, 5560, 5561, 5562, 5563, 5564, 5565, 5566, + 5567, 5568, 5569, 5570, 5571, 5572, 5573, 5574, + 5575, 5576, 5577, 5578, 5579, 5580, 5581, 5582, + 5583, 5584, 5585, 5586, 5587, 5588, 5589, 5590, + 5591, 5592, 5593, 5594, 5595, 5596, 5597, 5598, + 5599, 5600, 5601, 5602, 5603, 5604, 5605, 5606, + 5607, 5608, 5609, 5610, 5611, 5612, 5613, 5614, + 5615, 5616, 5617, 5618, 5619, 5620, 5621, 5622, + 5623, 5624, 5625, 5626, 5627, 5628, 5629, 5630, + 5631, 5632, 5633, 5634, 5635, 5636, 0, 0, + 1539, 0, 5637, 5638, 5639, 5640, 5641, 5642, + 5643, 5644, 5645, 5646, 5647, 5648, 5649, 5650, + 5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, + 5659, 5660, 5661, 5662, 5663, 5664, 5665, 5666, + 5667, 5668, 5669, 5670, 5671, 5672, 5673, 5674, + 5675, 5676, 5677, 5678, 5679, 5680, 5681, 5682, + 5683, 5684, 5685, 5686, 5687, 5688, 5689, 5690, + 5691, 5692, 5693, 5694, 5695, 5696, 5697, 5698, + 5699, 5700, 5701, 5702, 5703, 5704, 5705, 5706, + 5707, 5708, 5709, 5710, 5711, 5712, 5713, 5714, + 5715, 5716, 5717, 5718, 5719, 5720, 5721, 5722, + 5723, 5724, 5725, 5726, 5727, 5728, 5729, 5730, + 5731, 5732, 5733, 5734, 5735, 5736, 5737, 5738, + 5739, 5740, 5741, 5742, 5743, 5744, 5745, 5746, + 5747, 5748, 5749, 5750, 5751, 5752, 5753, 5754, + 5755, 5756, 5757, 5758, 5759, 5760, 5761, 5762, + 5763, 5764, 5765, 5766, 5767, 5768, 5769, 5770, + 5771, 5772, 5773, 5774, 5775, 5776, 5777, 5778, + 5779, 5780, 5781, 5782, 5783, 5784, 5785, 5786, + 5787, 5788, 5789, 5790, 5791, 5792, 5793, 5794, + 5795, 5796, 5797, 5798, 5799, 5800, 5801, 5802, + 5803, 5804, 5805, 5806, 5807, 5808, 5809, 5810, + 5811, 5812, 5813, 5814, 5815, 5816, 5817, 5818, + 5819, 5820, 5821, 5822, 5823, 5824, 5825, 5826, + 0, 0, 0, 5827, 5828, 5829, 5830, 5831, + 5832, 0, 0, 5833, 5834, 5835, 5836, 5837, + 5838, 0, 0, 5839, 5840, 5841, 5842, 5843, + 5844, 0, 0, 5845, 5846, 5847, 0, 0, + 0, 5848, 5849, 5850, 5851, 5852, 5853, 5854, + 0, 5855, 5856, 5857, 5858, 5859, 5860, 5861, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5862, 5862, 5862, 77, 77, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 0, 346, 346, 0, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 0, 0, 0, 0, + 0, 1120, 9, 1120, 0, 0, 0, 0, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 0, 0, 0, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 5863, 5863, 5863, 5863, 5863, 5863, 5863, + 5863, 5863, 5863, 5863, 5863, 5863, 5863, 5863, + 5863, 5863, 5863, 5863, 5863, 5863, 5863, 5863, + 5863, 5863, 5863, 5863, 5863, 5863, 5863, 5863, + 5863, 5863, 5863, 5863, 5863, 5863, 5863, 5863, + 5863, 5863, 5863, 5863, 5863, 5863, 5863, 5863, + 5863, 5863, 5863, 5863, 5863, 5863, 1289, 1289, + 1289, 1289, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 1289, 1289, 77, 914, 914, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 0, 0, + 0, 77, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 628, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 628, 5864, 5864, 5864, 5864, 5864, 5864, + 5864, 5864, 5864, 5864, 5864, 5864, 5864, 5864, + 5864, 5864, 5864, 5864, 5864, 5864, 5864, 5864, + 5864, 5864, 5864, 5864, 5864, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 1259, 1259, 1259, 1259, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1537, 346, 346, 346, 346, 346, + 346, 346, 346, 1537, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 615, + 615, 615, 615, 615, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 1120, 1537, 1537, 1537, 1537, 1537, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5865, 5866, 5867, 5868, 5869, 5870, 5871, + 5872, 5873, 5874, 5875, 5876, 5877, 5878, 5879, + 5880, 5881, 5882, 5883, 5884, 5885, 5886, 5887, + 5888, 5889, 5890, 5891, 5892, 5893, 5894, 5895, + 5896, 5897, 5898, 5899, 5900, 5901, 5902, 5903, + 5904, 5905, 5906, 5907, 5908, 5909, 5910, 5911, + 5912, 5913, 5914, 5915, 5916, 5917, 5918, 5919, + 5920, 5921, 5922, 5923, 5924, 5925, 5926, 5927, + 5928, 5929, 5930, 5931, 5932, 5933, 5934, 5935, + 5936, 5937, 5938, 5939, 5940, 5941, 5942, 5943, + 5944, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 5945, 5946, 5947, 5948, 5949, 5950, 5951, + 5952, 5953, 5954, 5955, 5956, 5957, 5958, 5959, + 5960, 5961, 5962, 5963, 5964, 5965, 5966, 5967, + 5968, 5969, 5970, 5971, 5972, 5973, 5974, 5975, + 5976, 5977, 5978, 5979, 5980, 0, 0, 0, + 0, 5981, 5982, 5983, 5984, 5985, 5986, 5987, + 5988, 5989, 5990, 5991, 5992, 5993, 5994, 5995, + 5996, 5997, 5998, 5999, 6000, 6001, 6002, 6003, + 6004, 6005, 6006, 6007, 6008, 6009, 6010, 6011, + 6012, 6013, 6014, 6015, 6016, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1120, 6017, 6018, 6019, 6020, 6021, 6022, 6023, + 6024, 6025, 6026, 6027, 0, 6028, 6029, 6030, + 6031, 6032, 6033, 6034, 6035, 6036, 6037, 6038, + 6039, 6040, 6041, 6042, 0, 6043, 6044, 6045, + 6046, 6047, 6048, 6049, 0, 6050, 6051, 0, + 6052, 6053, 6054, 6055, 6056, 6057, 6058, 6059, + 6060, 6061, 6062, 0, 6063, 6064, 6065, 6066, + 6067, 6068, 6069, 6070, 6071, 6072, 6073, 6074, + 6075, 6076, 6077, 0, 6078, 6079, 6080, 6081, + 6082, 6083, 6084, 0, 6085, 6086, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6087, 6088, 6089, 6090, 6091, 6092, 0, + 6093, 6094, 6095, 6096, 6097, 6098, 6099, 6100, + 6101, 6102, 6103, 6104, 6105, 6106, 6107, 6108, + 6109, 6110, 6111, 6112, 6113, 6114, 6115, 6116, + 6117, 6118, 6119, 6120, 6121, 6122, 6123, 6124, + 6125, 6126, 6127, 6128, 6129, 6130, 6131, 6132, + 6133, 6134, 0, 6135, 6136, 6137, 6138, 6139, + 6140, 6141, 6142, 6143, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 0, + 0, 1183, 0, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, + 1183, 1183, 0, 0, 0, 1183, 0, 0, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, + 1180, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 6145, 6145, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 0, 0, 0, 0, 0, 0, 0, 0, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 0, 1183, 1183, 0, + 0, 0, 0, 0, 6144, 6144, 6144, 6144, + 6144, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 6144, + 6144, 6144, 6144, 6144, 6144, 0, 0, 0, + 9, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 0, 0, 0, 0, 0, + 1180, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 0, 0, 0, 0, 6144, 6144, 1183, + 1183, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 0, 0, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 1183, 1226, 1226, 1226, 0, 1226, 1226, + 0, 0, 0, 0, 0, 1226, 628, 1226, + 615, 1183, 1183, 1183, 1183, 0, 1183, 1183, + 1183, 0, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, + 0, 615, 641, 628, 0, 0, 0, 0, + 1300, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 0, 0, 0, 0, 0, 0, + 0, 1180, 1180, 1180, 1180, 1180, 1180, 1180, + 1180, 1180, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 6144, 6144, + 1180, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 6144, 6144, + 6144, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 6145, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 615, 628, + 0, 0, 0, 0, 6144, 6144, 6144, 6144, + 6144, 1180, 1180, 1180, 1180, 1180, 1180, 1180, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, + 0, 0, 9, 9, 9, 9, 9, 9, + 9, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, + 0, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 0, 0, 0, 0, + 0, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 0, 0, 0, 0, 0, + 0, 0, 1180, 1180, 1180, 1180, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6146, 6147, 6148, 6149, 6150, 6151, 6152, + 6153, 6154, 6155, 6156, 6157, 6158, 6159, 6160, + 6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, + 6169, 6170, 6171, 6172, 6173, 6174, 6175, 6176, + 6177, 6178, 6179, 6180, 6181, 6182, 6183, 6184, + 6185, 6186, 6187, 6188, 6189, 6190, 6191, 6192, + 6193, 6194, 6195, 6196, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6197, 6198, 6199, 6200, 6201, 6202, 6203, + 6204, 6205, 6206, 6207, 6208, 6209, 6210, 6211, + 6212, 6213, 6214, 6215, 6216, 6217, 6218, 6219, + 6220, 6221, 6222, 6223, 6224, 6225, 6226, 6227, + 6228, 6229, 6230, 6231, 6232, 6233, 6234, 6235, + 6236, 6237, 6238, 6239, 6240, 6241, 6242, 6243, + 6244, 6245, 6246, 6247, 0, 0, 0, 0, + 0, 0, 0, 6144, 6144, 6144, 6144, 6144, + 6144, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 615, 615, 615, + 615, 0, 0, 0, 0, 0, 0, 0, + 0, 1210, 1210, 1210, 1210, 1210, 1210, 1210, + 1210, 1210, 1210, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6248, 6248, 6248, 6248, 6248, 6248, 6248, + 6248, 6248, 6248, 6248, 6248, 6248, 6248, 6248, + 6248, 6248, 6248, 6248, 6248, 6248, 6248, 6248, + 6248, 6248, 6248, 6248, 6248, 6248, 6248, 6248, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 0, 615, 615, 1178, 0, + 0, 1183, 1183, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 628, 628, + 628, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 1183, 0, 0, 0, 0, 0, 0, 0, + 0, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 628, + 628, 615, 615, 615, 628, 615, 628, 628, + 628, 628, 6249, 6249, 6249, 6249, 1187, 1187, + 1187, 1187, 1187, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 615, 628, 615, 628, 1180, + 1180, 1180, 1180, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1231, 1226, 1231, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1262, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 0, + 0, 0, 0, 1289, 1289, 1289, 1289, 1289, + 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, + 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1300, 346, 346, 1226, 1226, 346, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1300, 1226, 1226, 1231, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 6250, 6251, 6252, 6253, 346, 346, + 346, 346, 346, 346, 346, 346, 6254, 346, + 346, 346, 346, 346, 6255, 346, 346, 346, + 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, + 1231, 1231, 1262, 6256, 1120, 1120, 6257, 1120, + 1120, 1120, 1120, 1226, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6257, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 615, 615, 615, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 6258, 1226, 1226, 1226, 1226, 1231, 1226, 6259, + 6260, 1226, 6261, 6262, 1300, 1300, 0, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1120, 1120, 1120, 1120, 346, 1231, 1231, + 346, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1250, 1120, 1120, 346, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1226, 1226, 1231, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1231, 1231, 1231, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1231, 1538, 346, 1307, 1307, 346, 1120, 1120, + 1120, 1120, 1226, 1250, 1226, 1226, 1120, 1231, + 1226, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 346, 1120, 346, 1120, 1120, + 1120, 0, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 0, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 1231, 1231, 1231, + 1226, 1226, 1226, 1231, 1231, 1226, 1538, 1250, + 1226, 1120, 1120, 1120, 1120, 1120, 1120, 1226, + 346, 346, 1226, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 0, 346, 346, 346, 346, 0, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1120, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 1226, 1231, 1231, 1231, 1226, 1226, 1226, 1226, + 1226, 1226, 1250, 1300, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 1226, 1226, 1231, 1231, 0, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 0, + 346, 346, 0, 0, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 0, 346, 346, + 346, 346, 346, 0, 1250, 1250, 346, 6263, + 1231, 1226, 1231, 1231, 1231, 1231, 0, 0, + 6264, 1231, 0, 0, 6265, 6266, 1538, 0, + 0, 346, 0, 0, 0, 0, 0, 0, + 6267, 0, 0, 0, 0, 0, 346, 346, + 346, 346, 346, 1231, 1231, 0, 0, 615, + 615, 615, 615, 615, 615, 615, 0, 0, + 0, 615, 615, 615, 615, 615, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 1231, 1231, + 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1231, 1231, 1262, 1226, 1226, 1231, 1250, + 346, 346, 346, 346, 1120, 1120, 1120, 1120, + 1120, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1120, 1120, 0, 1120, 615, + 346, 346, 346, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 6268, 1231, 1231, 1226, 1226, 1226, 1226, + 1226, 1226, 6269, 6270, 6271, 6272, 6273, 6274, + 1226, 1226, 1231, 1262, 1250, 346, 346, 1120, + 346, 0, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 6275, 1231, 1231, 1226, 1226, 1226, 1226, 0, + 0, 6276, 6277, 6278, 6279, 1226, 1226, 1231, + 1262, 1250, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 346, 346, 346, 346, 1226, 1226, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1231, 1231, 1226, 1231, + 1262, 1226, 1120, 1120, 1120, 346, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1226, 1231, 1226, 1231, + 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1538, + 1250, 346, 1120, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 0, 0, 1226, 1226, + 1226, 1351, 1351, 1226, 1226, 1226, 1226, 1231, + 1226, 1226, 1226, 1226, 1300, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1259, 1259, 1120, 1120, 1120, + 914, 346, 346, 346, 346, 346, 346, 346, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 1231, 1231, 1231, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1231, 1262, 1250, 1120, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6280, 6281, 6282, 6283, 6284, 6285, 6286, + 6287, 6288, 6289, 6290, 6291, 6292, 6293, 6294, + 6295, 6296, 6297, 6298, 6299, 6300, 6301, 6302, + 6303, 6304, 6305, 6306, 6307, 6308, 6309, 6310, + 6311, 6312, 6313, 6314, 6315, 6316, 6317, 6318, + 6319, 6320, 6321, 6322, 6323, 6324, 6325, 6326, + 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, + 6335, 6336, 6337, 6338, 6339, 6340, 6341, 6342, + 6343, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 0, 346, 0, 0, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 6344, 1231, 1231, 1231, 1231, 6345, 0, + 1231, 6346, 0, 0, 1226, 1226, 1538, 1300, + 1307, 1231, 1307, 1231, 1250, 1120, 1120, 1120, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 0, 0, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1231, 1231, 1231, 1226, 1226, 1226, + 1226, 0, 0, 1226, 1226, 1231, 1231, 1231, + 1231, 1262, 346, 1120, 346, 1231, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 1226, 1226, 1226, 1226, 1226, 1226, + 6347, 6347, 1226, 1226, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1226, 1300, 1226, 1226, + 1226, 1226, 1231, 1307, 1226, 1226, 1226, 1226, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1300, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 1226, 1226, 1226, 1226, 1226, 1226, + 1231, 1231, 1226, 1226, 1226, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 1307, 1307, 1307, + 1307, 1307, 1307, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1231, 1226, 1300, 1120, 1120, 1120, 346, 1120, + 1120, 1120, 1120, 1120, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 0, 0, 0, 0, 0, + 0, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 0, 1226, 1226, 1226, 1226, 1226, 1226, 1231, + 6348, 346, 1120, 1120, 1120, 1120, 1120, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 0, 0, + 0, 1120, 1120, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 0, 0, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 0, 1231, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1231, 1226, 1226, 1231, 1226, 1226, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 0, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1226, 1226, 1226, 1226, 1226, 1226, + 0, 0, 0, 1226, 0, 1226, 1226, 0, + 1226, 1226, 1226, 1250, 1226, 1300, 1300, 1307, + 1226, 0, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 0, + 346, 346, 0, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 1231, 1231, 1231, 1231, 1231, + 0, 1226, 1226, 0, 1231, 1231, 1226, 1231, + 1300, 346, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 1226, 1226, 1231, 1231, + 1120, 1120, 0, 0, 0, 0, 0, 0, + 0, 1226, 1226, 1307, 1231, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 1231, 1231, 1226, + 1226, 1226, 1226, 1226, 0, 0, 0, 1231, + 1231, 1226, 1538, 1300, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 77, 77, + 77, 77, 77, 77, 77, 77, 11, 11, + 11, 11, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, + 0, 1120, 1120, 1120, 1120, 1120, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 1120, 1120, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 6349, 6349, 6349, 6349, 6349, 6349, 6349, + 6349, 6349, 6349, 6349, 6349, 6349, 6349, 6349, + 6349, 1226, 346, 346, 346, 346, 346, 346, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 1120, + 1120, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 0, + 0, 641, 641, 641, 641, 641, 1120, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 615, 615, 615, 615, 615, 615, 615, + 1120, 1120, 1120, 1120, 1120, 914, 914, 914, + 914, 596, 596, 596, 596, 1120, 914, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 0, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 0, 0, 0, 0, 0, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6350, 6351, 6352, 6353, 6354, 6355, 6356, + 6357, 6358, 6359, 6360, 6361, 6362, 6363, 6364, + 6365, 6366, 6367, 6368, 6369, 6370, 6371, 6372, + 6373, 6374, 6375, 6376, 6377, 6378, 6379, 6380, + 6381, 6382, 6383, 6384, 6385, 6386, 6387, 6388, + 6389, 6390, 6391, 6392, 6393, 6394, 6395, 6396, + 6397, 6398, 6399, 6400, 6401, 6402, 6403, 6404, + 6405, 6406, 6407, 6408, 6409, 6410, 6411, 6412, + 6413, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1120, 1120, 1120, 1120, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 0, 0, 0, 0, + 1226, 346, 1231, 1231, 1231, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, + 1231, 0, 0, 0, 0, 0, 0, 0, + 1226, 1226, 1226, 1226, 596, 596, 596, 596, + 596, 596, 596, 596, 596, 596, 596, 596, + 596, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3227, 3227, 3226, 3227, 1226, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6414, 6414, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3227, 3227, 3227, 3227, 0, 3227, 3227, + 3227, 3227, 3227, 3227, 3227, 0, 3227, 3227, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3228, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 0, 0, 3228, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3228, 3228, 3228, + 3228, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 0, 0, 914, 1226, 641, + 1120, 1539, 1539, 1539, 1539, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, + 0, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 0, 0, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 6415, 6416, 914, 914, 914, 914, 914, 6417, + 6418, 6419, 6420, 6421, 6422, 6423, 6424, 6425, + 641, 641, 641, 914, 914, 914, 6426, 6427, + 6428, 6429, 6430, 6431, 1539, 1539, 1539, 1539, + 1539, 1539, 1539, 1539, 628, 628, 628, 628, + 628, 628, 628, 628, 914, 914, 615, 615, + 615, 615, 615, 628, 628, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 615, 615, 615, 615, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 6432, 6433, 6434, 6435, 6436, 6437, + 6438, 6439, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 77, 77, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 615, 615, 615, 77, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6440, 6441, 6442, 6443, 6444, 6445, 6446, + 6447, 6448, 6449, 6450, 6451, 6452, 6453, 6454, + 6455, 6456, 6457, 6458, 6459, 6460, 6461, 6462, + 6463, 6464, 6465, 6466, 6467, 6468, 6469, 6470, + 6471, 6472, 6473, 6474, 6475, 6476, 6477, 6478, + 6479, 6480, 6481, 6482, 6483, 6484, 6485, 6486, + 6487, 6488, 6489, 6490, 6491, 6492, 6493, 6494, + 6495, 6496, 6497, 6498, 6499, 6500, 6501, 6502, + 6503, 6504, 6505, 6506, 6507, 6508, 6509, 6510, + 6511, 6512, 6513, 6514, 6515, 6516, 6517, 6518, + 6519, 6520, 6521, 6522, 6523, 6524, 0, 6525, + 6526, 6527, 6528, 6529, 6530, 6531, 6532, 6533, + 6534, 6535, 6536, 6537, 6538, 6539, 6540, 6541, + 6542, 6543, 6544, 6545, 6546, 6547, 6548, 6549, + 6550, 6551, 6552, 6553, 6554, 6555, 6556, 6557, + 6558, 6559, 6560, 6561, 6562, 6563, 6564, 6565, + 6566, 6567, 6568, 6569, 6570, 6571, 6572, 6573, + 6574, 6575, 6576, 6577, 6578, 6579, 6580, 6581, + 6582, 6583, 6584, 6585, 6586, 6587, 6588, 6589, + 6590, 6591, 6592, 6593, 6594, 6595, 0, 6596, + 6597, 0, 0, 6598, 0, 0, 6599, 6600, + 0, 0, 6601, 6602, 6603, 6604, 0, 6605, + 6606, 6607, 6608, 6609, 6610, 6611, 6612, 6613, + 6614, 6615, 6616, 0, 6617, 0, 6618, 6619, + 6620, 6621, 6622, 6623, 6624, 0, 6625, 6626, + 6627, 6628, 6629, 6630, 6631, 6632, 6633, 6634, + 6635, 6636, 6637, 6638, 6639, 6640, 6641, 6642, + 6643, 6644, 6645, 6646, 6647, 6648, 6649, 6650, + 6651, 6652, 6653, 6654, 6655, 6656, 6657, 6658, + 6659, 6660, 6661, 6662, 6663, 6664, 6665, 6666, + 6667, 6668, 6669, 6670, 6671, 6672, 6673, 6674, + 6675, 6676, 6677, 6678, 6679, 6680, 6681, 6682, + 6683, 6684, 6685, 6686, 6687, 6688, 6689, 0, + 6690, 6691, 6692, 6693, 0, 0, 6694, 6695, + 6696, 6697, 6698, 6699, 6700, 6701, 0, 6702, + 6703, 6704, 6705, 6706, 6707, 6708, 0, 6709, + 6710, 6711, 6712, 6713, 6714, 6715, 6716, 6717, + 6718, 6719, 6720, 6721, 6722, 6723, 6724, 6725, + 6726, 6727, 6728, 6729, 6730, 6731, 6732, 6733, + 6734, 6735, 6736, 0, 6737, 6738, 6739, 6740, + 0, 6741, 6742, 6743, 6744, 6745, 0, 6746, + 0, 0, 0, 6747, 6748, 6749, 6750, 6751, + 6752, 6753, 0, 6754, 6755, 6756, 6757, 6758, + 6759, 6760, 6761, 6762, 6763, 6764, 6765, 6766, + 6767, 6768, 6769, 6770, 6771, 6772, 6773, 6774, + 6775, 6776, 6777, 6778, 6779, 6780, 6781, 6782, + 6783, 6784, 6785, 6786, 6787, 6788, 6789, 6790, + 6791, 6792, 6793, 6794, 6795, 6796, 6797, 6798, + 6799, 6800, 6801, 6802, 6803, 6804, 6805, 6806, + 6807, 6808, 6809, 6810, 6811, 6812, 6813, 6814, + 6815, 6816, 6817, 6818, 6819, 6820, 6821, 6822, + 6823, 6824, 6825, 6826, 6827, 6828, 6829, 6830, + 6831, 6832, 6833, 6834, 6835, 6836, 6837, 6838, + 6839, 6840, 6841, 6842, 6843, 6844, 6845, 6846, + 6847, 6848, 6849, 6850, 6851, 6852, 6853, 6854, + 6855, 6856, 6857, 6858, 6859, 6860, 6861, 6862, + 6863, 6864, 6865, 6866, 6867, 6868, 6869, 6870, + 6871, 6872, 6873, 6874, 6875, 6876, 6877, 6878, + 6879, 6880, 6881, 6882, 6883, 6884, 6885, 6886, + 6887, 6888, 6889, 6890, 6891, 6892, 6893, 6894, + 6895, 6896, 6897, 6898, 6899, 6900, 6901, 6902, + 6903, 6904, 6905, 6906, 6907, 6908, 6909, 6910, + 6911, 6912, 6913, 6914, 6915, 6916, 6917, 6918, + 6919, 6920, 6921, 6922, 6923, 6924, 6925, 6926, + 6927, 6928, 6929, 6930, 6931, 6932, 6933, 6934, + 6935, 6936, 6937, 6938, 6939, 6940, 6941, 6942, + 6943, 6944, 6945, 6946, 6947, 6948, 6949, 6950, + 6951, 6952, 6953, 6954, 6955, 6956, 6957, 6958, + 6959, 6960, 6961, 6962, 6963, 6964, 6965, 6966, + 6967, 6968, 6969, 6970, 6971, 6972, 6973, 6974, + 6975, 6976, 6977, 6978, 6979, 6980, 6981, 6982, + 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, + 6991, 6992, 6993, 6994, 6995, 6996, 6997, 6998, + 6999, 7000, 7001, 7002, 7003, 7004, 7005, 7006, + 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, + 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, + 7023, 7024, 7025, 7026, 7027, 7028, 7029, 7030, + 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, + 7039, 7040, 7041, 7042, 7043, 7044, 7045, 7046, + 7047, 7048, 7049, 7050, 7051, 7052, 7053, 7054, + 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, + 7063, 7064, 7065, 7066, 7067, 7068, 7069, 7070, + 7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, + 7079, 7080, 7081, 7082, 7083, 7084, 7085, 7086, + 7087, 7088, 7089, 7090, 7091, 7092, 7093, 0, + 0, 7094, 7095, 7096, 7097, 7098, 7099, 7100, + 7101, 7102, 7103, 7104, 7105, 7106, 7107, 7108, + 7109, 7110, 7111, 7112, 7113, 7114, 7115, 7116, + 7117, 7118, 7119, 7120, 7121, 7122, 7123, 7124, + 7125, 7126, 7127, 7128, 7129, 7130, 7131, 7132, + 7133, 7134, 7135, 7136, 7137, 7138, 7139, 7140, + 7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, + 7149, 7150, 7151, 7152, 7153, 7154, 7155, 7156, + 7157, 7158, 7159, 7160, 7161, 7162, 7163, 7164, + 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, + 7173, 7174, 7175, 7176, 7119, 7177, 7178, 7179, + 7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, + 7188, 7189, 7190, 7191, 7192, 7193, 7194, 7195, + 7196, 7197, 7198, 7199, 7200, 7201, 7145, 7202, + 7203, 7204, 7205, 7206, 7207, 7208, 7209, 7210, + 7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, + 7219, 7220, 7221, 7222, 7223, 7224, 7225, 7226, + 7227, 7228, 7229, 7230, 7231, 7232, 7119, 7233, + 7234, 7235, 7236, 7237, 7238, 7239, 7240, 7241, + 7242, 7243, 7244, 7245, 7246, 7247, 7248, 7249, + 7250, 7251, 7252, 7253, 7254, 7255, 7256, 7257, + 7145, 7258, 7259, 7260, 7261, 7262, 7263, 7264, + 7265, 7266, 7267, 7268, 7269, 7270, 7271, 7272, + 7273, 7274, 7275, 7276, 7277, 7278, 7279, 7280, + 7281, 7282, 7283, 7284, 7285, 7286, 7287, 7288, + 7119, 7289, 7290, 7291, 7292, 7293, 7294, 7295, + 7296, 7297, 7298, 7299, 7300, 7301, 7302, 7303, + 7304, 7305, 7306, 7307, 7308, 7309, 7310, 7311, + 7312, 7313, 7145, 7314, 7315, 7316, 7317, 7318, + 7319, 7320, 7321, 7322, 7323, 7324, 7325, 7326, + 7327, 7328, 7329, 7330, 7331, 7332, 7333, 7334, + 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7342, + 7343, 7344, 7119, 7345, 7346, 7347, 7348, 7349, + 7350, 7351, 7352, 7353, 7354, 7355, 7356, 7357, + 7358, 7359, 7360, 7361, 7362, 7363, 7364, 7365, + 7366, 7367, 7368, 7369, 7145, 7370, 7371, 7372, + 7373, 7374, 7375, 7376, 7377, 0, 0, 7378, + 7379, 7380, 7381, 7382, 7383, 7384, 7385, 7386, + 7387, 7378, 7379, 7380, 7381, 7382, 7383, 7384, + 7385, 7386, 7387, 7378, 7379, 7380, 7381, 7382, + 7383, 7384, 7385, 7386, 7387, 7378, 7379, 7380, + 7381, 7382, 7383, 7384, 7385, 7386, 7387, 7378, + 7379, 7380, 7381, 7382, 7383, 7384, 7385, 7386, + 7387, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 914, 914, 914, 914, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 914, 914, + 914, 914, 914, 914, 914, 914, 1226, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 1226, 914, 914, + 1120, 1120, 1120, 1120, 1120, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1226, 1226, 1226, 1226, + 1226, 0, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, + 1226, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7388, 7389, 7390, 7391, 7392, 7393, 7394, + 7395, 7396, 7397, 346, 7398, 7399, 7400, 7401, + 7402, 7403, 7404, 7405, 7406, 7407, 7408, 7409, + 7410, 7411, 7412, 7413, 7414, 7415, 7416, 7417, + 0, 0, 0, 0, 0, 0, 7418, 7419, + 7420, 7421, 7422, 7423, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 615, 615, 615, 615, 615, 615, 615, + 0, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 615, 615, 615, 615, 615, 615, + 615, 615, 0, 0, 615, 615, 615, 615, + 615, 615, 615, 0, 615, 615, 0, 615, + 615, 615, 615, 615, 0, 0, 0, 0, + 0, 7424, 7425, 7426, 7427, 7428, 7429, 7430, + 7431, 7432, 7433, 7434, 7435, 7436, 7437, 7438, + 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7446, + 7447, 7448, 7449, 7450, 7451, 7452, 7453, 7454, + 7455, 7456, 7457, 7458, 7459, 7460, 7461, 7462, + 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, + 7471, 7472, 7473, 7474, 7475, 7476, 7477, 7478, + 7479, 7480, 7481, 7482, 7483, 7484, 7485, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 615, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 0, 0, + 0, 615, 615, 615, 615, 615, 615, 615, + 596, 596, 596, 596, 596, 596, 596, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 346, + 914, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 615, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 615, 615, 615, + 615, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 596, 627, 627, 628, + 615, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 346, 346, 346, 346, 346, 346, 346, + 0, 346, 346, 346, 346, 0, 346, 346, + 0, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, + 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, + 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 628, 628, 628, 628, 628, 628, 628, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7486, 7487, 7488, 7489, 7490, 7491, 7492, + 7493, 7494, 7495, 7496, 7497, 7498, 7499, 7500, + 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, + 7509, 7510, 7511, 7512, 7513, 7514, 7515, 7516, + 7517, 7518, 7519, 7520, 7521, 7522, 7523, 7524, + 7525, 7526, 7527, 7528, 7529, 7530, 7531, 7532, + 7533, 7534, 7535, 7536, 7537, 7538, 7539, 7540, + 7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, + 7549, 7550, 7551, 7552, 7553, 615, 615, 615, + 615, 615, 615, 1250, 1228, 0, 0, 0, + 0, 1227, 1227, 1227, 1227, 1227, 1227, 1227, + 1227, 1227, 1227, 0, 0, 0, 0, 1180, + 1180, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 1223, 6249, 6249, + 6249, 1186, 6249, 6249, 6249, 6249, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 1223, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 6249, + 6249, 6249, 6249, 6249, 6249, 6249, 6249, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7554, 7555, 7556, 7557, 0, 7558, 7559, + 7560, 7561, 7562, 7563, 7564, 7565, 7566, 7567, + 7568, 7569, 7570, 7571, 7572, 7573, 7574, 7575, + 7576, 7577, 7578, 7579, 7580, 7581, 7582, 7583, + 7584, 0, 7555, 7556, 0, 7585, 0, 0, + 7560, 0, 7562, 7563, 7564, 7565, 7566, 7567, + 7568, 7569, 7570, 7571, 0, 7573, 7574, 7575, + 7576, 0, 7578, 0, 7580, 0, 0, 0, + 0, 0, 0, 7556, 0, 0, 0, 0, + 7560, 0, 7562, 0, 7564, 0, 7566, 7567, + 7568, 0, 7570, 7571, 0, 7573, 0, 0, + 7576, 0, 7578, 0, 7580, 0, 7582, 0, + 7584, 0, 7555, 7556, 0, 7585, 0, 0, + 7560, 7561, 7562, 7563, 0, 7565, 7566, 7567, + 7568, 7569, 7570, 7571, 0, 7573, 7574, 7575, + 7576, 0, 7578, 7579, 7580, 7581, 0, 7583, + 0, 7554, 7555, 7556, 7557, 7585, 7558, 7559, + 7560, 7561, 7562, 0, 7564, 7565, 7566, 7567, + 7568, 7569, 7570, 7571, 7572, 7573, 7574, 7575, + 7576, 7577, 7578, 7579, 7580, 0, 0, 0, + 0, 0, 7555, 7556, 7557, 0, 7558, 7559, + 7560, 7561, 7562, 0, 7564, 7565, 7566, 7567, + 7568, 7569, 7570, 7571, 7572, 7573, 7574, 7575, + 7576, 7577, 7578, 7579, 7580, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 75, 75, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 79, 79, 79, 79, 2580, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 0, 0, 0, + 0, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 0, 0, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 0, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 2580, 0, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7586, 7587, 7588, 7589, 7590, 7591, 7592, + 7593, 7594, 7595, 7596, 1289, 1289, 79, 79, + 79, 7597, 7598, 7599, 7600, 7601, 7602, 7603, + 7604, 7605, 7606, 7607, 7608, 7609, 7610, 7611, + 7612, 7613, 7614, 7615, 7616, 7617, 7618, 7619, + 7620, 7621, 7622, 7623, 7624, 7625, 7626, 7627, + 79, 7628, 7629, 7630, 7631, 7632, 7633, 7634, + 7635, 7636, 7637, 7638, 7639, 7640, 7641, 7642, + 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, + 7651, 7652, 7653, 7654, 7655, 7656, 7657, 7658, + 7659, 7660, 7661, 7662, 7663, 7664, 7665, 7666, + 7667, 7668, 7669, 7670, 7671, 7672, 7673, 7674, + 7675, 7676, 7677, 7678, 7679, 7680, 7681, 7682, + 7683, 7684, 7685, 7686, 7687, 7688, 79, 79, + 79, 7689, 7690, 7691, 7692, 7693, 7694, 7695, + 7696, 7697, 7698, 7699, 7700, 7701, 7702, 7703, + 7704, 7705, 7706, 7707, 7708, 7709, 7710, 7711, + 7712, 7713, 7714, 914, 914, 914, 914, 7715, + 914, 7716, 7715, 7715, 7715, 7715, 7715, 7715, + 7715, 7715, 7715, 7715, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 914, 914, 914, 79, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7717, + 7717, 7717, 7717, 7717, 7717, 7717, 7717, 7717, + 7717, 7717, 7717, 7717, 7717, 7717, 7717, 7717, + 7717, 7717, 7717, 7717, 7717, 7717, 7717, 7717, + 7717, 7718, 7719, 7720, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7721, 7722, 7723, 7724, 7725, 7726, 7727, + 7728, 7729, 7730, 7731, 7732, 7733, 7734, 7735, + 7736, 7737, 7738, 7739, 7740, 7741, 7742, 7743, + 7744, 7745, 7746, 7747, 7748, 7749, 7750, 7751, + 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, + 7760, 7761, 7762, 7763, 7764, 0, 0, 0, + 0, 7765, 7766, 7767, 7768, 7769, 7770, 7771, + 7772, 7773, 0, 0, 0, 0, 0, 0, + 0, 7774, 7775, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2580, 2580, 2580, 2580, 2580, 2580, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 79, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 79, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 79, 79, 79, 79, + 2580, 2580, 2580, 2580, 2580, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 79, 79, 79, 2580, 79, 79, + 79, 2580, 2580, 2580, 7776, 7776, 7776, 7776, + 7776, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 79, 2580, 79, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 79, 79, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 77, + 77, 77, 77, 77, 77, 77, 77, 79, + 79, 79, 79, 79, 2580, 2580, 2580, 2580, + 79, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 2580, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 2580, 2580, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 2580, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 79, + 79, 79, 79, 79, 79, 2580, 79, 79, + 79, 2580, 2580, 2580, 79, 79, 2580, 2580, + 2580, 0, 0, 0, 0, 2580, 2580, 2580, + 2580, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 2580, 2580, 0, 0, + 0, 79, 79, 79, 79, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 79, 79, 79, + 0, 0, 0, 0, 79, 79, 79, 79, + 79, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 79, 79, + 79, 79, 79, 0, 0, 0, 0, 0, + 0, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 0, 0, 0, + 0, 2580, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 0, 0, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 0, 0, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 0, + 0, 79, 79, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 77, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 77, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 0, + 0, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 0, 0, + 0, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 0, 0, 0, 0, 0, 0, + 0, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 0, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 0, + 0, 0, 0, 0, 0, 0, 0, 2580, + 2580, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 2580, 2580, 2580, 0, 0, 0, + 0, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 0, 0, 0, 0, 0, 0, + 0, 2580, 2580, 2580, 2580, 2580, 2580, 2580, + 2580, 2580, 0, 0, 0, 0, 0, 0, + 0, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 0, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7378, 7379, 7380, 7381, 7382, 7383, 7384, + 7385, 7386, 7387, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7777, 7778, 7779, 7780, 7781, 4650, 7782, + 7783, 7784, 7785, 4651, 7786, 7787, 7788, 4652, + 7789, 7790, 7791, 7792, 7793, 7794, 7795, 7796, + 7797, 7798, 7799, 7800, 4710, 7801, 7802, 7803, + 7804, 7805, 7806, 7807, 7808, 7809, 4715, 4653, + 4654, 4716, 7810, 7811, 4461, 7812, 4655, 7813, + 7814, 7815, 7816, 7816, 7816, 7817, 7818, 7819, + 7820, 7821, 7822, 7823, 7824, 7825, 7826, 7827, + 7828, 7829, 7830, 7831, 7832, 7833, 7834, 7834, + 4718, 7835, 7836, 7837, 7838, 4657, 7839, 7840, + 7841, 4614, 7842, 7843, 7844, 7845, 7846, 7847, + 7848, 7849, 7850, 7851, 7852, 7853, 7854, 7855, + 7856, 7857, 7858, 7859, 7860, 7861, 7862, 7863, + 7864, 7865, 7866, 7867, 7867, 7868, 7869, 7870, + 4457, 7871, 7872, 7873, 7874, 7875, 7876, 7877, + 7878, 4662, 7879, 7880, 7881, 7882, 7883, 7884, + 7885, 7886, 7887, 7888, 7889, 7890, 7891, 7892, + 7893, 7894, 7895, 7896, 7897, 7898, 7899, 4403, + 7900, 7901, 7902, 7902, 7903, 7904, 7904, 7905, + 7906, 7907, 7908, 7909, 7910, 7911, 7912, 7913, + 7914, 7915, 7916, 7917, 4663, 7918, 7919, 7920, + 7921, 4730, 7921, 7922, 4665, 7923, 7924, 7925, + 7926, 4666, 4376, 7927, 7928, 7929, 7930, 7931, + 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, + 7940, 7941, 7942, 7943, 7944, 7945, 7946, 7947, + 7948, 4667, 7949, 7950, 7951, 7952, 7953, 7954, + 4669, 7955, 7956, 7957, 7958, 7959, 7960, 7961, + 7962, 4404, 4738, 7963, 7964, 7965, 7966, 7967, + 7968, 7969, 7970, 4670, 7971, 7972, 7973, 7974, + 4781, 7975, 7976, 7977, 7978, 7979, 7980, 7981, + 7982, 7983, 7984, 7985, 7986, 7987, 4474, 7988, + 7989, 7990, 7991, 7992, 7993, 7994, 7995, 7996, + 7997, 7998, 4671, 4561, 7999, 8000, 8001, 8002, + 8003, 8004, 8005, 8006, 4742, 8007, 8008, 8009, + 8010, 8011, 8012, 8013, 8014, 4743, 8015, 8016, + 8017, 8018, 8019, 8020, 8021, 8022, 8023, 8024, + 8025, 8026, 4745, 8027, 8028, 8029, 8030, 8031, + 8032, 8033, 8034, 8035, 8036, 8037, 8037, 8038, + 8039, 4747, 8040, 8041, 8042, 8043, 8044, 8045, + 8046, 4460, 8047, 8048, 8049, 8050, 8051, 8052, + 8053, 4753, 8054, 8055, 8056, 8057, 8058, 8059, + 8059, 4754, 4783, 8060, 8061, 8062, 8063, 8064, + 4422, 4756, 8065, 8066, 4682, 8067, 8068, 4636, + 8069, 8070, 4686, 8071, 8072, 8073, 8074, 8074, + 8075, 8076, 8077, 8078, 8079, 8080, 8081, 8082, + 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090, + 8091, 8092, 8093, 8094, 8095, 8096, 8097, 8098, + 8099, 8100, 8101, 4692, 8102, 8103, 8104, 8105, + 8106, 8107, 8108, 8109, 8110, 8111, 8112, 8113, + 8114, 8115, 8116, 8117, 7903, 8118, 8119, 8120, + 8121, 8122, 8123, 8124, 8125, 8126, 8127, 8128, + 8129, 4478, 8130, 8131, 8132, 8133, 8134, 8135, + 4695, 8136, 8137, 8138, 8139, 8140, 8141, 8142, + 8143, 8144, 8145, 8146, 8147, 8148, 8149, 8150, + 8151, 8152, 8153, 8154, 8155, 4417, 8156, 8157, + 8158, 8159, 8160, 8161, 4763, 8162, 8163, 8164, + 8165, 8166, 8167, 8168, 8169, 8170, 8171, 8172, + 8173, 8174, 8175, 8176, 8177, 8178, 8179, 8180, + 8181, 4768, 4769, 8182, 8183, 8184, 8185, 8186, + 8187, 8188, 8189, 8190, 8191, 8192, 8193, 8194, + 4770, 8195, 8196, 8197, 8198, 8199, 8200, 8201, + 8202, 8203, 8204, 8205, 8206, 8207, 8208, 8209, + 8210, 8211, 8212, 8213, 8214, 8215, 8216, 8217, + 8218, 8219, 8220, 8221, 8222, 8223, 8224, 4776, + 4776, 8225, 8226, 8227, 8228, 8229, 8230, 8231, + 8232, 8233, 8234, 4777, 8235, 8236, 8237, 8238, + 8239, 8240, 8241, 8242, 8243, 8244, 8245, 8246, + 8247, 8248, 8249, 8250, 8251, 8252, 8253, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 0, 0, 0, 0, + 0, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228, + 3228, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1539, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 649, 649, 649, 649, 649, 649, 649, + 649, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 4363, + 4363, 4363, 4363, 4363, 4363, 4363, 4363, 0, + 0, }; + +static const utf8proc_property_t utf8proc_properties[] = { + {0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_S, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_B, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_LF, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_WS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_B, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CR, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_B, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5093, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5084, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5096, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 0, UINT16_MAX, 0, UINT16_MAX, 0, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1, UINT16_MAX, 1, UINT16_MAX, 2784, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2, UINT16_MAX, 2, UINT16_MAX, 49, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3, UINT16_MAX, 3, UINT16_MAX, 704, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 4, UINT16_MAX, 4, UINT16_MAX, 62, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5, UINT16_MAX, 5, UINT16_MAX, 2872, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6, UINT16_MAX, 6, UINT16_MAX, 782, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7, UINT16_MAX, 7, UINT16_MAX, 808, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 8, UINT16_MAX, 8, UINT16_MAX, 111, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 9, UINT16_MAX, 9, UINT16_MAX, 898, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 10, UINT16_MAX, 10, UINT16_MAX, 913, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 11, UINT16_MAX, 11, UINT16_MAX, 999, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 12, UINT16_MAX, 12, UINT16_MAX, 2890, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 13, UINT16_MAX, 13, UINT16_MAX, 160, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 14, UINT16_MAX, 14, UINT16_MAX, 205, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 15, UINT16_MAX, 15, UINT16_MAX, 2982, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 16, UINT16_MAX, 16, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 17, UINT16_MAX, 17, UINT16_MAX, 1087, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 18, UINT16_MAX, 18, UINT16_MAX, 1173, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 19, UINT16_MAX, 19, UINT16_MAX, 1257, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 20, UINT16_MAX, 20, UINT16_MAX, 254, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 21, UINT16_MAX, 21, UINT16_MAX, 3042, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 22, UINT16_MAX, 22, UINT16_MAX, 1337, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 23, UINT16_MAX, 23, UINT16_MAX, 3122, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 24, UINT16_MAX, 24, UINT16_MAX, 303, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 25, UINT16_MAX, 25, UINT16_MAX, 1423, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1491, UINT16_MAX, 1491, 352, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1493, UINT16_MAX, 1493, 2818, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2813, UINT16_MAX, 2813, 401, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1494, UINT16_MAX, 1494, 743, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1495, UINT16_MAX, 1495, 414, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2838, UINT16_MAX, 2838, 2875, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1497, UINT16_MAX, 1497, 795, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1498, UINT16_MAX, 1498, 853, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1499, UINT16_MAX, 1499, 463, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1500, UINT16_MAX, 1500, 901, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1501, UINT16_MAX, 1501, 956, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1502, UINT16_MAX, 1502, 1043, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1503, UINT16_MAX, 1503, 2932, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1504, UINT16_MAX, 1504, 512, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1505, UINT16_MAX, 1505, 557, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1507, UINT16_MAX, 1507, 2994, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2827, UINT16_MAX, 2827, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1508, UINT16_MAX, 1508, 1130, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 3320, UINT16_MAX, 3320, 1215, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1509, UINT16_MAX, 1509, 1296, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1510, UINT16_MAX, 1510, 606, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2910, UINT16_MAX, 2910, 3082, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1511, UINT16_MAX, 1511, 1380, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2928, UINT16_MAX, 2928, 3131, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 3327, UINT16_MAX, 3327, 655, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2835, UINT16_MAX, 2835, 1466, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_NOBREAK, 26, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 16411, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 1621, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 0, UINT16_MAX, 8289, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PI, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 1, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 16413, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ET, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ET, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 16417, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35, 35, 7440, UINT16_MAX, 7440, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 16420, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 14, UINT16_MAX, 8290, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PF, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 32807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 32810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 32813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16432, 50, UINT16_MAX, 50, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16435, 53, UINT16_MAX, 53, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16438, 56, UINT16_MAX, 56, UINT16_MAX, 3143, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16441, 59, UINT16_MAX, 59, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16444, 62, UINT16_MAX, 62, UINT16_MAX, 1537, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16447, 65, UINT16_MAX, 65, UINT16_MAX, 1579, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 66, UINT16_MAX, 66, UINT16_MAX, 1549, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16451, 69, UINT16_MAX, 69, UINT16_MAX, 2852, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16454, 72, UINT16_MAX, 72, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16457, 75, UINT16_MAX, 75, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16460, 78, UINT16_MAX, 78, UINT16_MAX, 3357, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16463, 81, UINT16_MAX, 81, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16466, 84, UINT16_MAX, 84, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16469, 87, UINT16_MAX, 87, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16472, 90, UINT16_MAX, 90, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16475, 93, UINT16_MAX, 93, UINT16_MAX, 2878, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 94, UINT16_MAX, 94, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16479, 97, UINT16_MAX, 97, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16482, 100, UINT16_MAX, 100, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16485, 103, UINT16_MAX, 103, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16488, 106, UINT16_MAX, 106, UINT16_MAX, 3461, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16491, 109, UINT16_MAX, 109, UINT16_MAX, 1597, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16494, 112, UINT16_MAX, 112, UINT16_MAX, 1591, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 113, UINT16_MAX, 113, UINT16_MAX, 1585, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16498, 116, UINT16_MAX, 116, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16501, 119, UINT16_MAX, 119, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16504, 122, UINT16_MAX, 122, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16507, 125, UINT16_MAX, 125, UINT16_MAX, 1509, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16510, 128, UINT16_MAX, 128, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 129, UINT16_MAX, 129, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 16514, 8291, UINT16_MAX, 8291, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16516, UINT16_MAX, 8292, UINT16_MAX, 8292, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16518, UINT16_MAX, 8293, UINT16_MAX, 8293, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16520, UINT16_MAX, 8294, UINT16_MAX, 8294, 3192, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16522, UINT16_MAX, 8295, UINT16_MAX, 8295, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16524, UINT16_MAX, 8296, UINT16_MAX, 8296, 1540, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16526, UINT16_MAX, 2837, UINT16_MAX, 2837, 1582, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1492, UINT16_MAX, 1492, 1558, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16528, UINT16_MAX, 8297, UINT16_MAX, 8297, 2855, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16530, UINT16_MAX, 8298, UINT16_MAX, 8298, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16532, UINT16_MAX, 8299, UINT16_MAX, 8299, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16534, UINT16_MAX, 8300, UINT16_MAX, 8300, 3406, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16536, UINT16_MAX, 8301, UINT16_MAX, 8301, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16538, UINT16_MAX, 8302, UINT16_MAX, 8302, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16540, UINT16_MAX, 8303, UINT16_MAX, 8303, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16542, UINT16_MAX, 8304, UINT16_MAX, 8304, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16544, UINT16_MAX, 8305, UINT16_MAX, 8305, 2881, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8306, UINT16_MAX, 8306, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16546, UINT16_MAX, 8307, UINT16_MAX, 8307, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16548, UINT16_MAX, 8308, UINT16_MAX, 8308, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16550, UINT16_MAX, 8309, UINT16_MAX, 8309, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16552, UINT16_MAX, 8310, UINT16_MAX, 8310, 3510, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16554, UINT16_MAX, 8311, UINT16_MAX, 8311, 1606, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16556, UINT16_MAX, 8312, UINT16_MAX, 8312, 1594, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8313, UINT16_MAX, 8313, 1588, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16558, UINT16_MAX, 8314, UINT16_MAX, 8314, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16560, UINT16_MAX, 8315, UINT16_MAX, 8315, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16562, UINT16_MAX, 8316, UINT16_MAX, 8316, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16564, UINT16_MAX, 8317, UINT16_MAX, 8317, 1523, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16566, UINT16_MAX, 8318, UINT16_MAX, 8318, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8319, UINT16_MAX, 8319, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16568, UINT16_MAX, 8320, UINT16_MAX, 8320, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16570, 188, UINT16_MAX, 188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16573, UINT16_MAX, 8321, UINT16_MAX, 8321, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16575, 193, UINT16_MAX, 193, UINT16_MAX, 3259, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16578, UINT16_MAX, 8322, UINT16_MAX, 8322, 3308, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16580, 198, UINT16_MAX, 198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16583, UINT16_MAX, 8323, UINT16_MAX, 8323, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16585, 203, UINT16_MAX, 203, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16588, UINT16_MAX, 8324, UINT16_MAX, 8324, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16590, 208, UINT16_MAX, 208, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16593, UINT16_MAX, 8325, UINT16_MAX, 8325, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16595, 213, UINT16_MAX, 213, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16598, UINT16_MAX, 8326, UINT16_MAX, 8326, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16600, 218, UINT16_MAX, 218, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16603, UINT16_MAX, 8327, UINT16_MAX, 8327, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16605, 223, UINT16_MAX, 223, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16608, UINT16_MAX, 8328, UINT16_MAX, 8328, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 226, UINT16_MAX, 226, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8329, UINT16_MAX, 8329, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16611, 229, UINT16_MAX, 229, UINT16_MAX, 2858, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16614, UINT16_MAX, 8330, UINT16_MAX, 8330, 2862, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16616, 234, UINT16_MAX, 234, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16619, UINT16_MAX, 8331, UINT16_MAX, 8331, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16621, 239, UINT16_MAX, 239, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16624, UINT16_MAX, 8332, UINT16_MAX, 8332, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16626, 244, UINT16_MAX, 244, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16629, UINT16_MAX, 8333, UINT16_MAX, 8333, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16631, 249, UINT16_MAX, 249, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16634, UINT16_MAX, 8334, UINT16_MAX, 8334, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16636, 254, UINT16_MAX, 254, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16639, UINT16_MAX, 8335, UINT16_MAX, 8335, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16641, 259, UINT16_MAX, 259, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16644, UINT16_MAX, 8336, UINT16_MAX, 8336, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16646, 264, UINT16_MAX, 264, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16649, UINT16_MAX, 8337, UINT16_MAX, 8337, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16651, 269, UINT16_MAX, 269, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16654, UINT16_MAX, 8338, UINT16_MAX, 8338, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16656, 274, UINT16_MAX, 274, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16659, UINT16_MAX, 8339, UINT16_MAX, 8339, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 277, UINT16_MAX, 277, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 5251, UINT16_MAX, 5251, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16662, 280, UINT16_MAX, 280, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16665, UINT16_MAX, 8340, UINT16_MAX, 8340, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16667, 285, UINT16_MAX, 285, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16670, UINT16_MAX, 8341, UINT16_MAX, 8341, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16672, 290, UINT16_MAX, 290, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16675, UINT16_MAX, 8342, UINT16_MAX, 8342, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16677, 295, UINT16_MAX, 295, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16680, UINT16_MAX, 8343, UINT16_MAX, 8343, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16682, 16684, UINT16_MAX, 8, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1499, UINT16_MAX, 1499, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16686, 304, UINT16_MAX, 304, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16689, UINT16_MAX, 8344, UINT16_MAX, 8344, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16691, 309, UINT16_MAX, 309, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16694, UINT16_MAX, 8345, UINT16_MAX, 8345, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16696, 314, UINT16_MAX, 314, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16699, UINT16_MAX, 8346, UINT16_MAX, 8346, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8347, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16701, 319, UINT16_MAX, 319, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16704, UINT16_MAX, 8348, UINT16_MAX, 8348, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16706, 324, UINT16_MAX, 324, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16709, UINT16_MAX, 8349, UINT16_MAX, 8349, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16711, 329, UINT16_MAX, 329, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16714, UINT16_MAX, 8350, UINT16_MAX, 8350, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16716, 334, UINT16_MAX, 334, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16719, UINT16_MAX, 8351, UINT16_MAX, 8351, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 337, UINT16_MAX, 337, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8352, UINT16_MAX, 8352, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16722, 340, UINT16_MAX, 340, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16725, UINT16_MAX, 8353, UINT16_MAX, 8353, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16727, 345, UINT16_MAX, 345, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16730, UINT16_MAX, 8354, UINT16_MAX, 8354, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16732, 350, UINT16_MAX, 350, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16735, UINT16_MAX, 8355, UINT16_MAX, 8355, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16737, 16737, 8356, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 355, UINT16_MAX, 355, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8357, UINT16_MAX, 8357, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16740, 358, UINT16_MAX, 358, UINT16_MAX, 2974, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16743, UINT16_MAX, 8358, UINT16_MAX, 8358, 2978, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16745, 363, UINT16_MAX, 363, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16748, UINT16_MAX, 8359, UINT16_MAX, 8359, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16750, 368, UINT16_MAX, 368, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16753, UINT16_MAX, 8360, UINT16_MAX, 8360, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 371, UINT16_MAX, 371, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8361, UINT16_MAX, 8361, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16756, 374, UINT16_MAX, 374, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16759, UINT16_MAX, 8362, UINT16_MAX, 8362, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16761, 379, UINT16_MAX, 379, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16764, UINT16_MAX, 8363, UINT16_MAX, 8363, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16766, 384, UINT16_MAX, 384, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16769, UINT16_MAX, 8364, UINT16_MAX, 8364, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16771, 389, UINT16_MAX, 389, UINT16_MAX, 3012, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16774, UINT16_MAX, 8365, UINT16_MAX, 8365, 3015, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16776, 394, UINT16_MAX, 394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16779, UINT16_MAX, 8366, UINT16_MAX, 8366, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16781, 399, UINT16_MAX, 399, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16784, UINT16_MAX, 8367, UINT16_MAX, 8367, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16786, 404, UINT16_MAX, 404, UINT16_MAX, 3018, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16789, UINT16_MAX, 8368, UINT16_MAX, 8368, 3021, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16791, 409, UINT16_MAX, 409, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16794, UINT16_MAX, 8369, UINT16_MAX, 8369, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16796, 414, UINT16_MAX, 414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16799, UINT16_MAX, 8370, UINT16_MAX, 8370, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 417, UINT16_MAX, 417, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8371, UINT16_MAX, 8371, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16802, 420, UINT16_MAX, 420, UINT16_MAX, 3030, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16805, UINT16_MAX, 8372, UINT16_MAX, 8372, 3033, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16807, 425, UINT16_MAX, 425, UINT16_MAX, 3036, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16810, UINT16_MAX, 8373, UINT16_MAX, 8373, 3039, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16812, 430, UINT16_MAX, 430, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16815, UINT16_MAX, 8374, UINT16_MAX, 8374, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16817, 435, UINT16_MAX, 435, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16820, UINT16_MAX, 8375, UINT16_MAX, 8375, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16822, 440, UINT16_MAX, 440, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16825, UINT16_MAX, 8376, UINT16_MAX, 8376, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16827, 445, UINT16_MAX, 445, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16830, UINT16_MAX, 8377, UINT16_MAX, 8377, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16832, 450, UINT16_MAX, 450, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16835, UINT16_MAX, 8378, UINT16_MAX, 8378, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16837, 455, UINT16_MAX, 455, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16840, UINT16_MAX, 8379, UINT16_MAX, 8379, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16842, 460, UINT16_MAX, 460, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16845, 463, UINT16_MAX, 463, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16848, UINT16_MAX, 8380, UINT16_MAX, 8380, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16850, 468, UINT16_MAX, 468, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16853, UINT16_MAX, 8381, UINT16_MAX, 8381, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16855, 473, UINT16_MAX, 473, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16858, UINT16_MAX, 8382, UINT16_MAX, 8382, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 18, 18, 3320, UINT16_MAX, 3320, 3140, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8383, UINT16_MAX, 8383, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 476, UINT16_MAX, 476, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 477, UINT16_MAX, 477, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8384, UINT16_MAX, 8384, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 478, UINT16_MAX, 478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8385, UINT16_MAX, 8385, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 479, UINT16_MAX, 479, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 480, UINT16_MAX, 480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8386, UINT16_MAX, 8386, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 481, UINT16_MAX, 481, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 482, UINT16_MAX, 482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 483, UINT16_MAX, 483, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8387, UINT16_MAX, 8387, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8388, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 484, UINT16_MAX, 484, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 485, UINT16_MAX, 485, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 486, UINT16_MAX, 486, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 487, UINT16_MAX, 487, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8389, UINT16_MAX, 8389, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 488, UINT16_MAX, 488, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 489, UINT16_MAX, 489, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8390, UINT16_MAX, 8390, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 490, UINT16_MAX, 490, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 491, UINT16_MAX, 491, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 492, UINT16_MAX, 492, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8391, UINT16_MAX, 8391, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8392, UINT16_MAX, 8392, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8393, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 493, UINT16_MAX, 493, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 494, UINT16_MAX, 494, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8394, UINT16_MAX, 8394, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 495, UINT16_MAX, 495, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16880, 498, UINT16_MAX, 498, UINT16_MAX, 3565, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16883, UINT16_MAX, 8395, UINT16_MAX, 8395, 3614, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 501, UINT16_MAX, 501, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8396, UINT16_MAX, 8396, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 502, UINT16_MAX, 502, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8397, UINT16_MAX, 8397, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 503, UINT16_MAX, 503, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 504, UINT16_MAX, 504, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8398, UINT16_MAX, 8398, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 505, UINT16_MAX, 505, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8399, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1537, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 506, UINT16_MAX, 506, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8400, UINT16_MAX, 8400, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 507, UINT16_MAX, 507, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16892, 510, UINT16_MAX, 510, UINT16_MAX, 3663, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16895, UINT16_MAX, 8401, UINT16_MAX, 8401, 3712, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 513, UINT16_MAX, 513, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 514, UINT16_MAX, 514, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 515, UINT16_MAX, 515, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8402, UINT16_MAX, 8402, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 516, UINT16_MAX, 516, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8403, UINT16_MAX, 8403, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 517, UINT16_MAX, 517, UINT16_MAX, 1573, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 518, UINT16_MAX, 518, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8404, UINT16_MAX, 8404, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8405, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 519, UINT16_MAX, 519, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8406, UINT16_MAX, 8406, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8407, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8408, UINT16_MAX, 8408, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16904, 522, UINT16_MAX, 522, 8409, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16907, 522, 8410, 522, 8409, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16909, UINT16_MAX, 8410, UINT16_MAX, 8409, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16911, 529, UINT16_MAX, 529, 8411, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16914, 529, 8412, 529, 8411, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16916, UINT16_MAX, 8412, UINT16_MAX, 8411, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16918, 536, UINT16_MAX, 536, 8413, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16921, 536, 8414, 536, 8413, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16923, UINT16_MAX, 8414, UINT16_MAX, 8413, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16925, 543, UINT16_MAX, 543, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16928, UINT16_MAX, 8415, UINT16_MAX, 8415, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16930, 548, UINT16_MAX, 548, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16933, UINT16_MAX, 8416, UINT16_MAX, 8416, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16935, 553, UINT16_MAX, 553, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16938, UINT16_MAX, 8417, UINT16_MAX, 8417, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16940, 558, UINT16_MAX, 558, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16943, UINT16_MAX, 8418, UINT16_MAX, 8418, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16945, 563, UINT16_MAX, 563, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16948, UINT16_MAX, 8419, UINT16_MAX, 8419, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16950, 568, UINT16_MAX, 568, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16953, UINT16_MAX, 8420, UINT16_MAX, 8420, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16955, 573, UINT16_MAX, 573, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16958, UINT16_MAX, 8421, UINT16_MAX, 8421, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16960, 578, UINT16_MAX, 578, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16963, UINT16_MAX, 8422, UINT16_MAX, 8422, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1496, UINT16_MAX, 1496, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16965, 583, UINT16_MAX, 583, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16968, UINT16_MAX, 8423, UINT16_MAX, 8423, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16970, 588, UINT16_MAX, 588, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16973, UINT16_MAX, 8424, UINT16_MAX, 8424, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16975, 593, UINT16_MAX, 593, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16978, UINT16_MAX, 8425, UINT16_MAX, 8425, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 596, UINT16_MAX, 596, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8426, UINT16_MAX, 8426, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16981, 599, UINT16_MAX, 599, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16984, UINT16_MAX, 8427, UINT16_MAX, 8427, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16986, 604, UINT16_MAX, 604, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16989, UINT16_MAX, 8428, UINT16_MAX, 8428, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16991, 609, UINT16_MAX, 609, UINT16_MAX, 1567, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16994, UINT16_MAX, 8429, UINT16_MAX, 8429, 1570, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16996, 614, UINT16_MAX, 614, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16999, UINT16_MAX, 8430, UINT16_MAX, 8430, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17001, 619, UINT16_MAX, 619, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17004, UINT16_MAX, 8431, UINT16_MAX, 8431, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17006, 17006, 8432, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17008, 626, UINT16_MAX, 626, 8433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17011, 626, 8434, 626, 8433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17013, UINT16_MAX, 8434, UINT16_MAX, 8433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17015, 633, UINT16_MAX, 633, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17018, UINT16_MAX, 8435, UINT16_MAX, 8435, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 636, UINT16_MAX, 636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 637, UINT16_MAX, 637, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17022, 640, UINT16_MAX, 640, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17025, UINT16_MAX, 8436, UINT16_MAX, 8436, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17027, 645, UINT16_MAX, 645, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17030, UINT16_MAX, 8437, UINT16_MAX, 8437, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17032, 650, UINT16_MAX, 650, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17035, UINT16_MAX, 8438, UINT16_MAX, 8438, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17037, 655, UINT16_MAX, 655, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17040, UINT16_MAX, 8439, UINT16_MAX, 8439, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17042, 660, UINT16_MAX, 660, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17045, UINT16_MAX, 8440, UINT16_MAX, 8440, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17047, 665, UINT16_MAX, 665, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17050, UINT16_MAX, 8441, UINT16_MAX, 8441, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17052, 670, UINT16_MAX, 670, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17055, UINT16_MAX, 8442, UINT16_MAX, 8442, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17057, 675, UINT16_MAX, 675, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17060, UINT16_MAX, 8443, UINT16_MAX, 8443, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17062, 680, UINT16_MAX, 680, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17065, UINT16_MAX, 8444, UINT16_MAX, 8444, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17067, 685, UINT16_MAX, 685, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17070, UINT16_MAX, 8445, UINT16_MAX, 8445, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17072, 690, UINT16_MAX, 690, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17075, UINT16_MAX, 8446, UINT16_MAX, 8446, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17077, 695, UINT16_MAX, 695, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17080, UINT16_MAX, 8447, UINT16_MAX, 8447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17082, 700, UINT16_MAX, 700, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17085, UINT16_MAX, 8448, UINT16_MAX, 8448, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17087, 705, UINT16_MAX, 705, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17090, UINT16_MAX, 8449, UINT16_MAX, 8449, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17092, 710, UINT16_MAX, 710, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17095, UINT16_MAX, 8450, UINT16_MAX, 8450, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17097, 715, UINT16_MAX, 715, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17100, UINT16_MAX, 8451, UINT16_MAX, 8451, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17102, 720, UINT16_MAX, 720, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17105, UINT16_MAX, 8452, UINT16_MAX, 8452, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17107, 725, UINT16_MAX, 725, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17110, UINT16_MAX, 8453, UINT16_MAX, 8453, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 728, UINT16_MAX, 728, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8454, UINT16_MAX, 8454, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17113, 731, UINT16_MAX, 731, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17116, UINT16_MAX, 8455, UINT16_MAX, 8455, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 734, UINT16_MAX, 734, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8456, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 735, UINT16_MAX, 735, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1506, UINT16_MAX, 1506, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 736, UINT16_MAX, 736, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8457, UINT16_MAX, 8457, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17121, 739, UINT16_MAX, 739, UINT16_MAX, 1543, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17124, UINT16_MAX, 8458, UINT16_MAX, 8458, 1546, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17126, 744, UINT16_MAX, 744, UINT16_MAX, 2866, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17129, UINT16_MAX, 8459, UINT16_MAX, 8459, 2869, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17131, 749, UINT16_MAX, 749, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17134, UINT16_MAX, 8460, UINT16_MAX, 8460, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17136, 754, UINT16_MAX, 754, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17139, UINT16_MAX, 8461, UINT16_MAX, 8461, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17141, 759, UINT16_MAX, 759, UINT16_MAX, 1615, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17144, UINT16_MAX, 8462, UINT16_MAX, 8462, 1618, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17146, 764, UINT16_MAX, 764, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17149, UINT16_MAX, 8463, UINT16_MAX, 8463, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17151, 769, UINT16_MAX, 769, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17154, UINT16_MAX, 8464, UINT16_MAX, 8464, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8465, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8466, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8467, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7430, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8468, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8469, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 772, UINT16_MAX, 772, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 773, UINT16_MAX, 773, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8470, UINT16_MAX, 8470, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 774, UINT16_MAX, 774, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 775, UINT16_MAX, 775, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8471, UINT16_MAX, 8471, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8472, UINT16_MAX, 8472, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 776, UINT16_MAX, 776, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8473, UINT16_MAX, 8473, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 777, UINT16_MAX, 777, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 778, UINT16_MAX, 778, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 779, UINT16_MAX, 779, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 780, UINT16_MAX, 780, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8474, UINT16_MAX, 8474, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 781, UINT16_MAX, 781, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8475, UINT16_MAX, 8475, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 782, UINT16_MAX, 782, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8476, UINT16_MAX, 8476, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 783, UINT16_MAX, 783, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8477, UINT16_MAX, 8477, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 784, UINT16_MAX, 784, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8478, UINT16_MAX, 8478, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8479, UINT16_MAX, 8479, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8480, UINT16_MAX, 8480, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8481, UINT16_MAX, 8481, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8482, UINT16_MAX, 8482, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8483, UINT16_MAX, 8483, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1521, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8484, UINT16_MAX, 8484, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8485, UINT16_MAX, 8485, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7053, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8486, UINT16_MAX, 8486, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8487, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2822, UINT16_MAX, 2822, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8488, UINT16_MAX, 8488, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8489, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7054, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1522, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8490, UINT16_MAX, 8490, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8491, UINT16_MAX, 8491, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7057, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8492, UINT16_MAX, 8492, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7056, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8493, UINT16_MAX, 8493, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8494, UINT16_MAX, 8494, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7060, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8495, UINT16_MAX, 8495, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8496, UINT16_MAX, 8496, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8497, UINT16_MAX, 8497, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8498, UINT16_MAX, 8498, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8499, UINT16_MAX, 8499, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1528, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7067, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8500, UINT16_MAX, 8500, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1532, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8501, UINT16_MAX, 8501, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8502, UINT16_MAX, 8502, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1533, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1534, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8503, UINT16_MAX, 8503, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7073, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7074, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1535, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 786, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7075, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 787, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8504, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8505, UINT16_MAX, 8505, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7078, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8506, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8507, UINT16_MAX, 8507, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 788, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8508, UINT16_MAX, 8508, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8509, UINT16_MAX, 8509, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7061, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8510, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8511, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8512, UINT16_MAX, 8512, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8513, UINT16_MAX, 8513, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8514, UINT16_MAX, 8514, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8515, UINT16_MAX, 8515, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8516, UINT16_MAX, 8516, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8517, UINT16_MAX, 8517, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 5254, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7070, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7084, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1539, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1540, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8518, UINT16_MAX, 8518, 1576, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8519, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 801, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8520, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8521, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7087, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7047, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8522, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7058, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7059, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8523, UINT16_MAX, 8523, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8524, UINT16_MAX, 8524, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1530, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8525, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7085, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7086, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7048, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7051, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7050, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7080, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7082, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7079, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7055, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7062, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7063, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8526, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8527, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8528, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8529, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7, UINT16_MAX, 8530, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 785, UINT16_MAX, 8531, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 9, UINT16_MAX, 8532, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 17, UINT16_MAX, 8533, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 786, UINT16_MAX, 8534, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 787, UINT16_MAX, 8535, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 788, UINT16_MAX, 8536, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 22, UINT16_MAX, 8537, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 24, UINT16_MAX, 8538, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8539, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8540, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17173, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17175, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 489, UINT16_MAX, 8541, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 11, UINT16_MAX, 8542, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 18, UINT16_MAX, 8543, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 23, UINT16_MAX, 8544, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 801, UINT16_MAX, 8545, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32768, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32769, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32770, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32771, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32775, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32776, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32778, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32772, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32814, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32773, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32780, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32779, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32782, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32783, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32815, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32816, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 232, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32781, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32808, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32813, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32807, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32784, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32774, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32777, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32810, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32812, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32811, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32809, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 1, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 1, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32819, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, 802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, 803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32817, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, 804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, 17189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 240, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, 807, 7437, UINT16_MAX, 7437, 32818, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 233, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 234, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 808, UINT16_MAX, 808, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8546, UINT16_MAX, 8546, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 809, UINT16_MAX, 809, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8547, UINT16_MAX, 8547, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 811, UINT16_MAX, 811, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8548, UINT16_MAX, 8548, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17196, UINT16_MAX, 8549, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8550, UINT16_MAX, 8550, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8551, UINT16_MAX, 8551, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8552, UINT16_MAX, 8552, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, 814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 815, UINT16_MAX, 815, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 17200, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17202, 820, UINT16_MAX, 820, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, 821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17206, 824, UINT16_MAX, 824, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17209, 827, UINT16_MAX, 827, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17212, 830, UINT16_MAX, 830, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17215, 833, UINT16_MAX, 833, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17218, 836, UINT16_MAX, 836, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17221, 839, UINT16_MAX, 839, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17224, 33610, 2659, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 845, UINT16_MAX, 845, UINT16_MAX, 1673, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 846, UINT16_MAX, 846, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 847, UINT16_MAX, 847, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 848, UINT16_MAX, 848, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 849, UINT16_MAX, 849, UINT16_MAX, 1726, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 850, UINT16_MAX, 850, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 851, UINT16_MAX, 851, UINT16_MAX, 1777, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 852, UINT16_MAX, 852, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 807, UINT16_MAX, 807, UINT16_MAX, 1830, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 853, UINT16_MAX, 853, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 854, UINT16_MAX, 854, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 35, UINT16_MAX, 35, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 855, UINT16_MAX, 855, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 856, UINT16_MAX, 856, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 857, UINT16_MAX, 857, UINT16_MAX, 1881, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 858, UINT16_MAX, 858, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 859, UINT16_MAX, 859, UINT16_MAX, 5027, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 860, UINT16_MAX, 860, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 861, UINT16_MAX, 861, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 862, UINT16_MAX, 862, UINT16_MAX, 1932, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 863, UINT16_MAX, 863, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 864, UINT16_MAX, 864, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 865, UINT16_MAX, 865, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 866, UINT16_MAX, 866, UINT16_MAX, 1983, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17251, 869, UINT16_MAX, 869, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17254, 872, UINT16_MAX, 872, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17257, UINT16_MAX, 2603, UINT16_MAX, 2603, 4904, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17259, UINT16_MAX, 2635, UINT16_MAX, 2635, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17261, UINT16_MAX, 2640, UINT16_MAX, 2640, 4913, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17263, UINT16_MAX, 2676, UINT16_MAX, 2676, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17265, 33651, 2693, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7431, UINT16_MAX, 7431, 2088, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7432, UINT16_MAX, 7432, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2847, UINT16_MAX, 2847, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7433, UINT16_MAX, 7433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7434, UINT16_MAX, 7434, 2141, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7435, UINT16_MAX, 7435, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7436, UINT16_MAX, 7436, 2192, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 915, UINT16_MAX, 915, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7437, UINT16_MAX, 7437, 2245, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7438, UINT16_MAX, 7438, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7439, UINT16_MAX, 7439, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7440, UINT16_MAX, 7440, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7441, UINT16_MAX, 7441, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7442, UINT16_MAX, 7442, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7443, UINT16_MAX, 7443, 2401, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2848, UINT16_MAX, 2848, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7444, UINT16_MAX, 7444, 5023, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 860, 917, UINT16_MAX, 917, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 917, UINT16_MAX, 917, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7446, UINT16_MAX, 7446, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 897, UINT16_MAX, 897, 2349, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7447, UINT16_MAX, 7447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7448, UINT16_MAX, 7448, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7449, UINT16_MAX, 7449, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2836, UINT16_MAX, 2836, 2452, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17270, UINT16_MAX, 8553, UINT16_MAX, 8553, 2036, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17272, UINT16_MAX, 8554, UINT16_MAX, 8554, 2297, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17274, UINT16_MAX, 2745, UINT16_MAX, 2745, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17276, UINT16_MAX, 2714, UINT16_MAX, 2714, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17278, UINT16_MAX, 2750, UINT16_MAX, 2750, 5033, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 896, UINT16_MAX, 896, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 846, 846, 7432, UINT16_MAX, 7432, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 852, 852, 915, UINT16_MAX, 915, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 897, UINT16_MAX, UINT16_MAX, 8555, UINT16_MAX, 2505, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17282, UINT16_MAX, UINT16_MAX, 8556, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17284, UINT16_MAX, UINT16_MAX, 8557, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 863, 863, 7447, UINT16_MAX, 7447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 858, 858, 2848, UINT16_MAX, 2848, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8558, UINT16_MAX, 8558, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 902, UINT16_MAX, 902, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8559, UINT16_MAX, 8559, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 903, UINT16_MAX, 903, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8560, UINT16_MAX, 8560, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 904, UINT16_MAX, 904, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7458, UINT16_MAX, 7458, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 905, UINT16_MAX, 905, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8561, UINT16_MAX, 8561, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 906, UINT16_MAX, 906, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8562, UINT16_MAX, 8562, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 907, UINT16_MAX, 907, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8563, UINT16_MAX, 8563, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 908, UINT16_MAX, 908, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8564, UINT16_MAX, 8564, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 909, UINT16_MAX, 909, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8565, UINT16_MAX, 8565, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 910, UINT16_MAX, 910, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8566, UINT16_MAX, 8566, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 911, UINT16_MAX, 911, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8567, UINT16_MAX, 8567, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 912, UINT16_MAX, 912, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8568, UINT16_MAX, 8568, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 913, UINT16_MAX, 913, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8569, UINT16_MAX, 8569, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 853, 853, 7438, UINT16_MAX, 7438, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 859, 859, 7444, UINT16_MAX, 7444, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 914, UINT16_MAX, 8570, UINT16_MAX, 8570, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8571, UINT16_MAX, 8571, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 915, 852, UINT16_MAX, 852, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 849, 849, 7434, UINT16_MAX, 7434, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 916, UINT16_MAX, 916, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8572, UINT16_MAX, 8572, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 917, 918, UINT16_MAX, 918, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 919, UINT16_MAX, 919, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8573, UINT16_MAX, 8573, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8574, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 920, UINT16_MAX, 920, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 921, UINT16_MAX, 921, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 922, UINT16_MAX, 922, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17307, 925, UINT16_MAX, 925, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17310, 928, UINT16_MAX, 928, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 929, UINT16_MAX, 929, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17314, 932, UINT16_MAX, 932, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 933, UINT16_MAX, 933, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 934, UINT16_MAX, 934, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 935, UINT16_MAX, 935, UINT16_MAX, 2525, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17320, 938, UINT16_MAX, 938, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 939, UINT16_MAX, 939, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 940, UINT16_MAX, 940, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 941, UINT16_MAX, 941, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 942, UINT16_MAX, 942, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17327, 945, UINT16_MAX, 945, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17330, 948, UINT16_MAX, 948, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17333, 951, UINT16_MAX, 951, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 952, UINT16_MAX, 952, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 953, UINT16_MAX, 953, UINT16_MAX, 2615, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 954, UINT16_MAX, 954, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 955, UINT16_MAX, 955, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 956, UINT16_MAX, 956, UINT16_MAX, 2522, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 957, UINT16_MAX, 957, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 958, UINT16_MAX, 958, UINT16_MAX, 2511, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 959, UINT16_MAX, 959, UINT16_MAX, 2601, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 960, UINT16_MAX, 960, UINT16_MAX, 2635, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 961, UINT16_MAX, 961, UINT16_MAX, 2531, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17346, 964, UINT16_MAX, 964, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 965, UINT16_MAX, 965, UINT16_MAX, 2528, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 966, UINT16_MAX, 966, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 967, UINT16_MAX, 967, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 968, UINT16_MAX, 968, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 969, UINT16_MAX, 969, UINT16_MAX, 2641, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 970, UINT16_MAX, 970, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 971, UINT16_MAX, 971, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 972, UINT16_MAX, 972, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 973, UINT16_MAX, 973, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 974, UINT16_MAX, 974, UINT16_MAX, 2542, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 975, UINT16_MAX, 975, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 976, UINT16_MAX, 976, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 977, UINT16_MAX, 977, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 978, UINT16_MAX, 978, UINT16_MAX, 2659, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 979, UINT16_MAX, 979, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 980, UINT16_MAX, 980, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 981, UINT16_MAX, 981, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 982, UINT16_MAX, 982, UINT16_MAX, 2665, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 983, UINT16_MAX, 983, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 984, UINT16_MAX, 984, UINT16_MAX, 2653, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 985, UINT16_MAX, 985, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 986, UINT16_MAX, 986, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8575, UINT16_MAX, 8575, 2622, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8576, UINT16_MAX, 8576, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8577, UINT16_MAX, 8577, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8578, UINT16_MAX, 8578, 2575, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8579, UINT16_MAX, 8579, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8580, UINT16_MAX, 8580, 2564, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8581, UINT16_MAX, 8581, 2608, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8582, UINT16_MAX, 8582, 2638, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8583, UINT16_MAX, 8583, 2553, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17371, UINT16_MAX, 8584, UINT16_MAX, 8584, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8585, UINT16_MAX, 8585, 2581, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8586, UINT16_MAX, 8586, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8587, UINT16_MAX, 8587, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8588, UINT16_MAX, 8588, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8589, UINT16_MAX, 8589, 2644, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8590, UINT16_MAX, 8590, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8591, UINT16_MAX, 8591, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8592, UINT16_MAX, 8592, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8593, UINT16_MAX, 8593, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8594, UINT16_MAX, 8594, 2584, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8595, UINT16_MAX, 8595, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8596, UINT16_MAX, 8596, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8597, UINT16_MAX, 8597, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8598, UINT16_MAX, 8598, 2662, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8599, UINT16_MAX, 8599, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8600, UINT16_MAX, 8600, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8601, UINT16_MAX, 8601, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8602, UINT16_MAX, 8602, 2668, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8603, UINT16_MAX, 8603, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8604, UINT16_MAX, 8604, 2656, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8605, UINT16_MAX, 8605, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8606, UINT16_MAX, 8606, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17373, UINT16_MAX, 8607, UINT16_MAX, 8607, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17375, UINT16_MAX, 8608, UINT16_MAX, 8608, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8609, UINT16_MAX, 8609, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17377, UINT16_MAX, 8610, UINT16_MAX, 8610, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8611, UINT16_MAX, 8611, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8612, UINT16_MAX, 8612, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8613, UINT16_MAX, 8613, 2578, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17379, UINT16_MAX, 8614, UINT16_MAX, 8614, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8615, UINT16_MAX, 8615, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8616, UINT16_MAX, 8616, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8617, UINT16_MAX, 8617, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8618, UINT16_MAX, 8618, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17381, UINT16_MAX, 8619, UINT16_MAX, 8619, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17383, UINT16_MAX, 8620, UINT16_MAX, 8620, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17385, UINT16_MAX, 8621, UINT16_MAX, 8621, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8622, UINT16_MAX, 8622, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1003, UINT16_MAX, 1003, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8623, UINT16_MAX, 8623, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1004, UINT16_MAX, 1004, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8624, UINT16_MAX, 8624, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1005, UINT16_MAX, 1005, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8625, UINT16_MAX, 8625, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1006, UINT16_MAX, 1006, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8626, UINT16_MAX, 8626, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1007, UINT16_MAX, 1007, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8627, UINT16_MAX, 8627, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1008, UINT16_MAX, 1008, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8628, UINT16_MAX, 8628, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1009, UINT16_MAX, 1009, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8629, UINT16_MAX, 8629, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1010, UINT16_MAX, 1010, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8630, UINT16_MAX, 8630, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1011, UINT16_MAX, 1011, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8631, UINT16_MAX, 8631, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1012, UINT16_MAX, 1012, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8632, UINT16_MAX, 8632, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1013, UINT16_MAX, 1013, UINT16_MAX, 2595, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8633, UINT16_MAX, 8633, 2598, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17398, 1016, UINT16_MAX, 1016, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17401, UINT16_MAX, 8634, UINT16_MAX, 8634, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1019, UINT16_MAX, 1019, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8635, UINT16_MAX, 8635, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1020, UINT16_MAX, 1020, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8636, UINT16_MAX, 8636, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1021, UINT16_MAX, 1021, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8637, UINT16_MAX, 8637, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1022, UINT16_MAX, 1022, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8638, UINT16_MAX, 8638, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1023, UINT16_MAX, 1023, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8639, UINT16_MAX, 8639, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ME, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1024, UINT16_MAX, 1024, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8640, UINT16_MAX, 8640, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1025, UINT16_MAX, 1025, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8641, UINT16_MAX, 8641, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1026, UINT16_MAX, 1026, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8642, UINT16_MAX, 8642, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1027, UINT16_MAX, 1027, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8643, UINT16_MAX, 8643, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1028, UINT16_MAX, 1028, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8644, UINT16_MAX, 8644, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1029, UINT16_MAX, 1029, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8645, UINT16_MAX, 8645, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1030, UINT16_MAX, 1030, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8646, UINT16_MAX, 8646, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1031, UINT16_MAX, 1031, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8647, UINT16_MAX, 8647, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1032, UINT16_MAX, 1032, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8648, UINT16_MAX, 8648, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1033, UINT16_MAX, 1033, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8649, UINT16_MAX, 8649, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1034, UINT16_MAX, 1034, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8650, UINT16_MAX, 8650, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1035, UINT16_MAX, 1035, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8651, UINT16_MAX, 8651, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1036, UINT16_MAX, 1036, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8652, UINT16_MAX, 8652, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1037, UINT16_MAX, 1037, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8653, UINT16_MAX, 8653, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1038, UINT16_MAX, 1038, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8654, UINT16_MAX, 8654, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1039, UINT16_MAX, 1039, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8655, UINT16_MAX, 8655, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1040, UINT16_MAX, 1040, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8656, UINT16_MAX, 8656, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1041, UINT16_MAX, 1041, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8657, UINT16_MAX, 8657, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1042, UINT16_MAX, 1042, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8658, UINT16_MAX, 8658, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1043, UINT16_MAX, 1043, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8659, UINT16_MAX, 8659, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1044, UINT16_MAX, 1044, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8660, UINT16_MAX, 8660, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1045, UINT16_MAX, 1045, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8661, UINT16_MAX, 8661, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1046, UINT16_MAX, 1046, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8662, UINT16_MAX, 8662, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1047, UINT16_MAX, 1047, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8663, UINT16_MAX, 8663, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1048, UINT16_MAX, 1048, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8664, UINT16_MAX, 8664, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1049, UINT16_MAX, 1049, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8665, UINT16_MAX, 8665, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1050, UINT16_MAX, 1050, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8666, UINT16_MAX, 8666, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1051, UINT16_MAX, 1051, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17436, 1054, UINT16_MAX, 1054, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17439, UINT16_MAX, 8667, UINT16_MAX, 8667, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1057, UINT16_MAX, 1057, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8668, UINT16_MAX, 8668, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1058, UINT16_MAX, 1058, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8669, UINT16_MAX, 8669, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1059, UINT16_MAX, 1059, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8670, UINT16_MAX, 8670, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1060, UINT16_MAX, 1060, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8671, UINT16_MAX, 8671, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1061, UINT16_MAX, 1061, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8672, UINT16_MAX, 8672, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1062, UINT16_MAX, 1062, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8673, UINT16_MAX, 8673, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8674, UINT16_MAX, 8674, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17447, 1065, UINT16_MAX, 1065, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17450, UINT16_MAX, 8675, UINT16_MAX, 8675, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17452, 1070, UINT16_MAX, 1070, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17455, UINT16_MAX, 8676, UINT16_MAX, 8676, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1073, UINT16_MAX, 1073, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8677, UINT16_MAX, 8677, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17458, 1076, UINT16_MAX, 1076, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17461, UINT16_MAX, 8678, UINT16_MAX, 8678, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1079, UINT16_MAX, 1079, UINT16_MAX, 2629, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8679, UINT16_MAX, 8679, 2632, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17464, 1082, UINT16_MAX, 1082, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17467, UINT16_MAX, 8680, UINT16_MAX, 8680, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17469, 1087, UINT16_MAX, 1087, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17472, UINT16_MAX, 8681, UINT16_MAX, 8681, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17474, 1092, UINT16_MAX, 1092, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17477, UINT16_MAX, 8682, UINT16_MAX, 8682, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1095, UINT16_MAX, 1095, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8683, UINT16_MAX, 8683, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17480, 1098, UINT16_MAX, 1098, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17483, UINT16_MAX, 8684, UINT16_MAX, 8684, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17485, 1103, UINT16_MAX, 1103, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17488, UINT16_MAX, 8685, UINT16_MAX, 8685, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17490, 1108, UINT16_MAX, 1108, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17493, UINT16_MAX, 8686, UINT16_MAX, 8686, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1111, UINT16_MAX, 1111, UINT16_MAX, 2647, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8687, UINT16_MAX, 8687, 2650, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17496, 1114, UINT16_MAX, 1114, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17499, UINT16_MAX, 8688, UINT16_MAX, 8688, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17501, 1119, UINT16_MAX, 1119, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17504, UINT16_MAX, 8689, UINT16_MAX, 8689, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17506, 1124, UINT16_MAX, 1124, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17509, UINT16_MAX, 8690, UINT16_MAX, 8690, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17511, 1129, UINT16_MAX, 1129, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17514, UINT16_MAX, 8691, UINT16_MAX, 8691, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17516, 1134, UINT16_MAX, 1134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17519, UINT16_MAX, 8692, UINT16_MAX, 8692, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17521, 1139, UINT16_MAX, 1139, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17524, UINT16_MAX, 8693, UINT16_MAX, 8693, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1142, UINT16_MAX, 1142, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8694, UINT16_MAX, 8694, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17527, 1145, UINT16_MAX, 1145, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17530, UINT16_MAX, 8695, UINT16_MAX, 8695, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1148, UINT16_MAX, 1148, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8696, UINT16_MAX, 8696, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1149, UINT16_MAX, 1149, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8697, UINT16_MAX, 8697, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1150, UINT16_MAX, 1150, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8698, UINT16_MAX, 8698, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1151, UINT16_MAX, 1151, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8699, UINT16_MAX, 8699, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1152, UINT16_MAX, 1152, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8700, UINT16_MAX, 8700, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1153, UINT16_MAX, 1153, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8701, UINT16_MAX, 8701, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1154, UINT16_MAX, 1154, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8702, UINT16_MAX, 8702, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1155, UINT16_MAX, 1155, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8703, UINT16_MAX, 8703, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1156, UINT16_MAX, 1156, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8704, UINT16_MAX, 8704, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1157, UINT16_MAX, 1157, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8705, UINT16_MAX, 8705, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1158, UINT16_MAX, 1158, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8706, UINT16_MAX, 8706, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1159, UINT16_MAX, 1159, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8707, UINT16_MAX, 8707, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1160, UINT16_MAX, 1160, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8708, UINT16_MAX, 8708, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1161, UINT16_MAX, 1161, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8709, UINT16_MAX, 8709, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1162, UINT16_MAX, 1162, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8710, UINT16_MAX, 8710, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1163, UINT16_MAX, 1163, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8711, UINT16_MAX, 8711, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1164, UINT16_MAX, 1164, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8712, UINT16_MAX, 8712, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1165, UINT16_MAX, 1165, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8713, UINT16_MAX, 8713, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1166, UINT16_MAX, 1166, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8714, UINT16_MAX, 8714, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1167, UINT16_MAX, 1167, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8715, UINT16_MAX, 8715, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1168, UINT16_MAX, 1168, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8716, UINT16_MAX, 8716, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1169, UINT16_MAX, 1169, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8717, UINT16_MAX, 8717, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1170, UINT16_MAX, 1170, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8718, UINT16_MAX, 8718, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1171, UINT16_MAX, 1171, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8719, UINT16_MAX, 8719, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1172, UINT16_MAX, 1172, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8720, UINT16_MAX, 8720, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1173, UINT16_MAX, 1173, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8721, UINT16_MAX, 8721, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1174, UINT16_MAX, 1174, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8722, UINT16_MAX, 8722, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1175, UINT16_MAX, 1175, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1176, UINT16_MAX, 1176, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1177, UINT16_MAX, 1177, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1178, UINT16_MAX, 1178, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1179, UINT16_MAX, 1179, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1180, UINT16_MAX, 1180, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1181, UINT16_MAX, 1181, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1182, UINT16_MAX, 1182, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1183, UINT16_MAX, 1183, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1184, UINT16_MAX, 1184, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1185, UINT16_MAX, 1185, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1186, UINT16_MAX, 1186, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1187, UINT16_MAX, 1187, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1188, UINT16_MAX, 1188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1189, UINT16_MAX, 1189, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1190, UINT16_MAX, 1190, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1191, UINT16_MAX, 1191, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1192, UINT16_MAX, 1192, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1193, UINT16_MAX, 1193, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1194, UINT16_MAX, 1194, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1195, UINT16_MAX, 1195, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1196, UINT16_MAX, 1196, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1197, UINT16_MAX, 1197, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1198, UINT16_MAX, 1198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1199, UINT16_MAX, 1199, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1200, UINT16_MAX, 1200, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1201, UINT16_MAX, 1201, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1202, UINT16_MAX, 1202, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1203, UINT16_MAX, 1203, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1204, UINT16_MAX, 1204, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1205, UINT16_MAX, 1205, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1206, UINT16_MAX, 1206, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1207, UINT16_MAX, 1207, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1208, UINT16_MAX, 1208, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1209, UINT16_MAX, 1209, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1210, UINT16_MAX, 1210, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1211, UINT16_MAX, 1211, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1212, UINT16_MAX, 1212, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8723, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8724, UINT16_MAX, 8724, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8725, UINT16_MAX, 8725, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8726, UINT16_MAX, 8726, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8727, UINT16_MAX, 8727, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8728, UINT16_MAX, 8728, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8729, UINT16_MAX, 8729, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8730, UINT16_MAX, 8730, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8731, UINT16_MAX, 8731, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8732, UINT16_MAX, 8732, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8733, UINT16_MAX, 8733, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8734, UINT16_MAX, 8734, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8735, UINT16_MAX, 8735, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8736, UINT16_MAX, 8736, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8737, UINT16_MAX, 8737, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8738, UINT16_MAX, 8738, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8739, UINT16_MAX, 8739, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8740, UINT16_MAX, 8740, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8741, UINT16_MAX, 8741, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8742, UINT16_MAX, 8742, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8743, UINT16_MAX, 8743, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8744, UINT16_MAX, 8744, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8745, UINT16_MAX, 8745, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8746, UINT16_MAX, 8746, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8747, UINT16_MAX, 8747, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8748, UINT16_MAX, 8748, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8749, UINT16_MAX, 8749, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8750, UINT16_MAX, 8750, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8751, UINT16_MAX, 8751, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8752, UINT16_MAX, 8752, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8753, UINT16_MAX, 8753, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8754, UINT16_MAX, 8754, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8755, UINT16_MAX, 8755, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8756, UINT16_MAX, 8756, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8757, UINT16_MAX, 8757, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8758, UINT16_MAX, 8758, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8759, UINT16_MAX, 8759, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8760, UINT16_MAX, 8760, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8761, UINT16_MAX, 8761, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17597, 17597, 8762, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8763, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 222, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 228, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 10, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 11, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 12, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 13, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 14, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 15, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 16, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 17, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 18, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 19, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 20, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 21, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 22, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 23, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 24, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 25, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_AN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_PREPEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 30, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 31, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 32, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2671, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2676, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2679, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 27, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 28, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 29, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 33, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 34, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32785, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32786, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32787, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_AN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_AN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 35, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, 17609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, 17611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, 17613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, 17615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2685, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2688, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2682, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_PREPEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 36, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2691, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2694, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2697, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17627, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_MN, 7, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32788, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_LINKER}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17639, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17641, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17643, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 7, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32789, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2700, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17645, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17647, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32790, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17649, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17651, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17653, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17655, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17661, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17665, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32792, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2704, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32791, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32793, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_CONSONANT}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2709, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32795, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2712, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2716, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32794, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2719, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 84, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 91, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32796, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2722, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32799, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2725, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2730, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32797, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32798, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32800, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2733, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2737, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17701, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_PREPEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32801, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32802, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32803, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2740, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17703, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17705, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2745, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17707, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17709, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32804, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17711, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 103, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 107, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17713, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 118, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17715, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17717, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17720, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17724, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17726, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17728, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17730, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 129, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 130, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17732, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 132, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17734, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17736, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, UTF8PROC_DECOMP_TYPE_COMPAT, 17738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17740, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, UTF8PROC_DECOMP_TYPE_COMPAT, 17742, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17744, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17746, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17748, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17750, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17752, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17754, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17756, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2748, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17758, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32805, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1376, UINT16_MAX, 1376, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1377, UINT16_MAX, 1377, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1378, UINT16_MAX, 1378, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1379, UINT16_MAX, 1379, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1380, UINT16_MAX, 1380, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1381, UINT16_MAX, 1381, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1382, UINT16_MAX, 1382, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1383, UINT16_MAX, 1383, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1384, UINT16_MAX, 1384, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1385, UINT16_MAX, 1385, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1386, UINT16_MAX, 1386, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1387, UINT16_MAX, 1387, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1388, UINT16_MAX, 1388, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1389, UINT16_MAX, 1389, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1390, UINT16_MAX, 1390, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1391, UINT16_MAX, 1391, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1392, UINT16_MAX, 1392, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1393, UINT16_MAX, 1393, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1394, UINT16_MAX, 1394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1395, UINT16_MAX, 1395, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1396, UINT16_MAX, 1396, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1397, UINT16_MAX, 1397, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1398, UINT16_MAX, 1398, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1399, UINT16_MAX, 1399, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1400, UINT16_MAX, 1400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1401, UINT16_MAX, 1401, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1402, UINT16_MAX, 1402, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1403, UINT16_MAX, 1403, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1404, UINT16_MAX, 1404, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1405, UINT16_MAX, 1405, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1406, UINT16_MAX, 1406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1407, UINT16_MAX, 1407, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1408, UINT16_MAX, 1408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1409, UINT16_MAX, 1409, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1410, UINT16_MAX, 1410, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1411, UINT16_MAX, 1411, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1412, UINT16_MAX, 1412, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1413, UINT16_MAX, 1413, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1414, UINT16_MAX, 1414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1415, UINT16_MAX, 1415, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8764, UINT16_MAX, 1446, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8765, UINT16_MAX, 1447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8766, UINT16_MAX, 1448, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8767, UINT16_MAX, 1449, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8768, UINT16_MAX, 1450, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8769, UINT16_MAX, 1451, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8770, UINT16_MAX, 1452, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8771, UINT16_MAX, 1453, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8772, UINT16_MAX, 1454, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8773, UINT16_MAX, 1455, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8774, UINT16_MAX, 1456, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8775, UINT16_MAX, 1457, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8776, UINT16_MAX, 1416, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8777, UINT16_MAX, 1458, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8778, UINT16_MAX, 1459, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8779, UINT16_MAX, 1460, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8780, UINT16_MAX, 1461, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8781, UINT16_MAX, 1462, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8782, UINT16_MAX, 1463, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8783, UINT16_MAX, 1464, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8784, UINT16_MAX, 1465, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8785, UINT16_MAX, 1466, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8786, UINT16_MAX, 1467, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8787, UINT16_MAX, 1468, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8788, UINT16_MAX, 1469, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8789, UINT16_MAX, 1470, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8790, UINT16_MAX, 1471, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8791, UINT16_MAX, 1472, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8792, UINT16_MAX, 1473, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8793, UINT16_MAX, 1474, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8794, UINT16_MAX, 1475, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8795, UINT16_MAX, 1476, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8796, UINT16_MAX, 1477, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8797, UINT16_MAX, 1478, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8798, UINT16_MAX, 1479, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8799, UINT16_MAX, 1480, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8800, UINT16_MAX, 1481, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8801, UINT16_MAX, 1482, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8802, UINT16_MAX, 1483, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8803, UINT16_MAX, 1484, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8804, UINT16_MAX, 1485, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8805, UINT16_MAX, 1486, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8806, UINT16_MAX, 1487, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1416, UINT16_MAX, 8807, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8808, UINT16_MAX, 1488, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8809, UINT16_MAX, 1489, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8810, UINT16_MAX, 1490, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_L, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 2, 0, UTF8PROC_BOUNDCLASS_L, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 1, 0, UTF8PROC_BOUNDCLASS_V, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_V, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_T, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8811, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8812, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8813, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8814, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8815, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8816, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8817, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8818, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8819, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8820, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8821, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8822, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8823, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8824, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8825, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8826, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8827, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8828, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8829, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8830, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8831, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8832, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8833, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8834, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8835, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8836, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8837, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8838, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8839, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8840, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8841, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8842, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8843, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8844, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8845, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8846, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8847, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8848, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8849, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8850, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8851, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8852, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8853, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8854, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8855, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8856, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8857, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8858, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8859, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8860, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8861, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8862, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8863, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8864, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8865, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8866, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8867, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8868, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8869, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8870, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8871, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8872, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8873, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8874, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8875, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8876, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8877, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8878, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8879, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8880, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8881, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8882, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8883, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8884, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8885, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8886, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8887, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8888, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8889, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8890, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8891, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8892, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8893, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8894, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8895, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8896, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1417, 1417, UINT16_MAX, 1417, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1418, 1418, UINT16_MAX, 1418, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1419, 1419, UINT16_MAX, 1419, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1420, 1420, UINT16_MAX, 1420, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1421, 1421, UINT16_MAX, 1421, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1422, 1422, UINT16_MAX, 1422, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 9, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2751, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2754, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2757, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2760, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2763, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2766, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32806, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2769, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2772, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2775, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2778, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17823, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17825, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2781, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17827, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 955, 8577, UINT16_MAX, 8577, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 957, 8579, UINT16_MAX, 8579, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 969, 8589, UINT16_MAX, 8589, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 972, 8592, UINT16_MAX, 8592, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 973, 8593, UINT16_MAX, 8593, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 981, 8601, UINT16_MAX, 8601, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1004, 8624, UINT16_MAX, 8624, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1445, 8897, UINT16_MAX, 8897, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1446, UINT16_MAX, 1446, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1447, UINT16_MAX, 1447, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1448, UINT16_MAX, 1448, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1449, UINT16_MAX, 1449, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1450, UINT16_MAX, 1450, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1451, UINT16_MAX, 1451, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1452, UINT16_MAX, 1452, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1453, UINT16_MAX, 1453, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1454, UINT16_MAX, 1454, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1455, UINT16_MAX, 1455, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1456, UINT16_MAX, 1456, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1457, UINT16_MAX, 1457, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1416, UINT16_MAX, 1416, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1458, UINT16_MAX, 1458, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1459, UINT16_MAX, 1459, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1460, UINT16_MAX, 1460, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1461, UINT16_MAX, 1461, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1462, UINT16_MAX, 1462, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1463, UINT16_MAX, 1463, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1464, UINT16_MAX, 1464, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1465, UINT16_MAX, 1465, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1466, UINT16_MAX, 1466, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1467, UINT16_MAX, 1467, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1468, UINT16_MAX, 1468, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1469, UINT16_MAX, 1469, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1471, UINT16_MAX, 1471, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1472, UINT16_MAX, 1472, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1473, UINT16_MAX, 1473, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1474, UINT16_MAX, 1474, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1475, UINT16_MAX, 1475, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1476, UINT16_MAX, 1476, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1477, UINT16_MAX, 1477, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1479, UINT16_MAX, 1479, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1481, UINT16_MAX, 1481, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1483, UINT16_MAX, 1483, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1484, UINT16_MAX, 1484, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1485, UINT16_MAX, 1485, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1486, UINT16_MAX, 1486, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1487, UINT16_MAX, 1487, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1488, UINT16_MAX, 1488, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1489, UINT16_MAX, 1489, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1490, UINT16_MAX, 1490, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8898, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8899, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1514, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8900, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8901, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8902, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8903, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8904, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8905, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8906, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8907, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8908, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8909, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8910, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8911, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8912, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8913, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8914, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8915, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8916, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8917, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8918, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1516, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1517, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8919, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8920, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8921, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8922, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1538, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1518, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8923, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8924, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8925, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8926, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8927, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8928, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8929, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1519, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8930, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8931, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8932, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8933, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8934, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8935, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1491, UINT16_MAX, 8936, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1492, UINT16_MAX, 8937, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1493, UINT16_MAX, 8938, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8939, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1494, UINT16_MAX, 8940, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1495, UINT16_MAX, 8941, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1496, UINT16_MAX, 8942, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1497, UINT16_MAX, 8943, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1498, UINT16_MAX, 8944, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1499, UINT16_MAX, 8945, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1500, UINT16_MAX, 8946, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1501, UINT16_MAX, 8947, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1502, UINT16_MAX, 8948, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1503, UINT16_MAX, 8949, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1504, UINT16_MAX, 8950, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8951, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1505, UINT16_MAX, 8952, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1506, UINT16_MAX, 8953, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1507, UINT16_MAX, 8954, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1508, UINT16_MAX, 8955, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1509, UINT16_MAX, 8956, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1510, UINT16_MAX, 8957, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1511, UINT16_MAX, 8958, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 0, UINT16_MAX, 8959, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1512, UINT16_MAX, 8960, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1513, UINT16_MAX, 8961, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1514, UINT16_MAX, 8962, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1, UINT16_MAX, 8963, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3, UINT16_MAX, 8964, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 4, UINT16_MAX, 8965, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 485, UINT16_MAX, 8966, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 486, UINT16_MAX, 8967, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1515, UINT16_MAX, 8968, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 6, UINT16_MAX, 8969, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8970, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 10, UINT16_MAX, 8971, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 12, UINT16_MAX, 8972, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 355, UINT16_MAX, 8973, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 14, UINT16_MAX, 8974, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 479, UINT16_MAX, 8975, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1516, UINT16_MAX, 8976, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1517, UINT16_MAX, 8977, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 15, UINT16_MAX, 8978, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 19, UINT16_MAX, 8979, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 20, UINT16_MAX, 8980, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1518, UINT16_MAX, 8981, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 493, UINT16_MAX, 8982, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 21, UINT16_MAX, 8983, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1519, UINT16_MAX, 8984, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 846, UINT16_MAX, 8985, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 847, UINT16_MAX, 8986, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 848, UINT16_MAX, 8987, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 863, UINT16_MAX, 8988, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 864, UINT16_MAX, 8989, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 8, UINT16_MAX, 8990, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 17, UINT16_MAX, 8991, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 20, UINT16_MAX, 8992, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 21, UINT16_MAX, 8993, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 846, UINT16_MAX, 8994, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 847, UINT16_MAX, 8995, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 859, UINT16_MAX, 8996, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 863, UINT16_MAX, 8997, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 864, UINT16_MAX, 8998, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8999, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9000, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9001, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9002, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9003, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9004, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9005, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9006, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9007, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9008, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9009, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9010, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9011, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 968, UINT16_MAX, 9012, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9013, UINT16_MAX, 9013, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9014, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1526, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9015, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9016, UINT16_MAX, 9016, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9017, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9018, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9019, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9020, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9021, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9022, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9023, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1529, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9024, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9025, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9026, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9027, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9028, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9029, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9030, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9031, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9032, UINT16_MAX, 9032, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9033, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9034, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7052, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9035, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9036, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9037, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9038, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9039, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9040, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9041, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9042, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9043, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1520, UINT16_MAX, 9044, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2, UINT16_MAX, 9045, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1521, UINT16_MAX, 9046, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 94, UINT16_MAX, 9047, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1515, UINT16_MAX, 9048, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5, UINT16_MAX, 9049, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1522, UINT16_MAX, 9050, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1523, UINT16_MAX, 9051, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1524, UINT16_MAX, 9052, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 491, UINT16_MAX, 9053, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 490, UINT16_MAX, 9054, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1525, UINT16_MAX, 9055, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1526, UINT16_MAX, 9056, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1527, UINT16_MAX, 9057, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1528, UINT16_MAX, 9058, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1529, UINT16_MAX, 9059, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1530, UINT16_MAX, 9060, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1531, UINT16_MAX, 9061, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1532, UINT16_MAX, 9062, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 494, UINT16_MAX, 9063, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1533, UINT16_MAX, 9064, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1534, UINT16_MAX, 9065, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 495, UINT16_MAX, 9066, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1535, UINT16_MAX, 9067, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1536, UINT16_MAX, 9068, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 505, UINT16_MAX, 9069, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1537, UINT16_MAX, 9070, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 778, UINT16_MAX, 9071, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 513, UINT16_MAX, 9072, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1538, UINT16_MAX, 9073, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 514, UINT16_MAX, 9074, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 779, UINT16_MAX, 9075, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 25, UINT16_MAX, 9076, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1539, UINT16_MAX, 9077, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1540, UINT16_MAX, 9078, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 517, UINT16_MAX, 9079, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 852, UINT16_MAX, 9080, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 214, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 218, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17925, 1543, UINT16_MAX, 1543, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17928, UINT16_MAX, 9081, UINT16_MAX, 9081, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17930, 1548, UINT16_MAX, 1548, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17933, UINT16_MAX, 9082, UINT16_MAX, 9082, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17935, 1553, UINT16_MAX, 1553, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17938, UINT16_MAX, 9083, UINT16_MAX, 9083, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17940, 1558, UINT16_MAX, 1558, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17943, UINT16_MAX, 9084, UINT16_MAX, 9084, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17945, 1563, UINT16_MAX, 1563, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17948, UINT16_MAX, 9085, UINT16_MAX, 9085, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17950, 1568, UINT16_MAX, 1568, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17953, UINT16_MAX, 9086, UINT16_MAX, 9086, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17955, 1573, UINT16_MAX, 1573, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17958, UINT16_MAX, 9087, UINT16_MAX, 9087, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17960, 1578, UINT16_MAX, 1578, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17963, UINT16_MAX, 9088, UINT16_MAX, 9088, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17965, 1583, UINT16_MAX, 1583, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17968, UINT16_MAX, 9089, UINT16_MAX, 9089, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17970, 1588, UINT16_MAX, 1588, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17973, UINT16_MAX, 9090, UINT16_MAX, 9090, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17975, 1593, UINT16_MAX, 1593, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17978, UINT16_MAX, 9091, UINT16_MAX, 9091, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17980, 1598, UINT16_MAX, 1598, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17983, UINT16_MAX, 9092, UINT16_MAX, 9092, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17985, 1603, UINT16_MAX, 1603, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17988, UINT16_MAX, 9093, UINT16_MAX, 9093, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17990, 1608, UINT16_MAX, 1608, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17993, UINT16_MAX, 9094, UINT16_MAX, 9094, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17995, 1613, UINT16_MAX, 1613, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17998, UINT16_MAX, 9095, UINT16_MAX, 9095, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18000, 1618, UINT16_MAX, 1618, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18003, UINT16_MAX, 9096, UINT16_MAX, 9096, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18005, 1623, UINT16_MAX, 1623, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18008, UINT16_MAX, 9097, UINT16_MAX, 9097, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18010, 1628, UINT16_MAX, 1628, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18013, UINT16_MAX, 9098, UINT16_MAX, 9098, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18015, 1633, UINT16_MAX, 1633, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18018, UINT16_MAX, 9099, UINT16_MAX, 9099, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18020, 1638, UINT16_MAX, 1638, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18023, UINT16_MAX, 9100, UINT16_MAX, 9100, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18025, 1643, UINT16_MAX, 1643, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18028, UINT16_MAX, 9101, UINT16_MAX, 9101, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18030, 1648, UINT16_MAX, 1648, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18033, UINT16_MAX, 9102, UINT16_MAX, 9102, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18035, 1653, UINT16_MAX, 1653, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18038, UINT16_MAX, 9103, UINT16_MAX, 9103, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18040, 1658, UINT16_MAX, 1658, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18043, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18045, 1663, UINT16_MAX, 1663, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18048, UINT16_MAX, 9105, UINT16_MAX, 9105, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18050, 1668, UINT16_MAX, 1668, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18053, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18055, 1673, UINT16_MAX, 1673, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18058, UINT16_MAX, 9107, UINT16_MAX, 9107, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18060, 1678, UINT16_MAX, 1678, UINT16_MAX, 2884, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18063, UINT16_MAX, 9108, UINT16_MAX, 9108, 2887, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18065, 1683, UINT16_MAX, 1683, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18068, UINT16_MAX, 9109, UINT16_MAX, 9109, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18070, 1688, UINT16_MAX, 1688, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18073, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18075, 1693, UINT16_MAX, 1693, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18078, UINT16_MAX, 9111, UINT16_MAX, 9111, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18080, 1698, UINT16_MAX, 1698, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18083, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18085, 1703, UINT16_MAX, 1703, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18088, UINT16_MAX, 9113, UINT16_MAX, 9113, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18090, 1708, UINT16_MAX, 1708, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18093, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18095, 1713, UINT16_MAX, 1713, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18098, UINT16_MAX, 9115, UINT16_MAX, 9115, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18100, 1718, UINT16_MAX, 1718, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18103, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18105, 1723, UINT16_MAX, 1723, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18108, UINT16_MAX, 9117, UINT16_MAX, 9117, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18110, 1728, UINT16_MAX, 1728, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18113, UINT16_MAX, 9118, UINT16_MAX, 9118, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18115, 1733, UINT16_MAX, 1733, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18118, UINT16_MAX, 9119, UINT16_MAX, 9119, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18120, 1738, UINT16_MAX, 1738, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18123, UINT16_MAX, 9120, UINT16_MAX, 9120, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18125, 1743, UINT16_MAX, 1743, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18128, UINT16_MAX, 9121, UINT16_MAX, 9121, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18130, 1748, UINT16_MAX, 1748, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18133, UINT16_MAX, 9122, UINT16_MAX, 9122, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18135, 1753, UINT16_MAX, 1753, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18138, UINT16_MAX, 9123, UINT16_MAX, 9123, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18140, 1758, UINT16_MAX, 1758, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18143, UINT16_MAX, 9124, UINT16_MAX, 9124, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18145, 1763, UINT16_MAX, 1763, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18148, UINT16_MAX, 9125, UINT16_MAX, 9125, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18150, 1768, UINT16_MAX, 1768, UINT16_MAX, 3006, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18153, UINT16_MAX, 9126, UINT16_MAX, 9126, 3009, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18155, 1773, UINT16_MAX, 1773, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18158, UINT16_MAX, 9127, UINT16_MAX, 9127, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18160, 1778, UINT16_MAX, 1778, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18163, UINT16_MAX, 9128, UINT16_MAX, 9128, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18165, 1783, UINT16_MAX, 1783, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18168, UINT16_MAX, 9129, UINT16_MAX, 9129, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18170, 1788, UINT16_MAX, 1788, UINT16_MAX, 3024, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18173, UINT16_MAX, 9130, UINT16_MAX, 9130, 3027, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18175, 1793, UINT16_MAX, 1793, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18178, UINT16_MAX, 9131, UINT16_MAX, 9131, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18180, 1798, UINT16_MAX, 1798, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18183, UINT16_MAX, 9132, UINT16_MAX, 9132, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18185, 1803, UINT16_MAX, 1803, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18188, UINT16_MAX, 9133, UINT16_MAX, 9133, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18190, 1808, UINT16_MAX, 1808, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18193, UINT16_MAX, 9134, UINT16_MAX, 9134, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18195, 1813, UINT16_MAX, 1813, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18198, UINT16_MAX, 9135, UINT16_MAX, 9135, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18200, 1818, UINT16_MAX, 1818, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18203, UINT16_MAX, 9136, UINT16_MAX, 9136, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18205, 1823, UINT16_MAX, 1823, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18208, UINT16_MAX, 9137, UINT16_MAX, 9137, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18210, 1828, UINT16_MAX, 1828, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18213, UINT16_MAX, 9138, UINT16_MAX, 9138, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18215, 1833, UINT16_MAX, 1833, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18218, UINT16_MAX, 9139, UINT16_MAX, 9139, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18220, 1838, UINT16_MAX, 1838, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18223, UINT16_MAX, 9140, UINT16_MAX, 9140, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18225, 1843, UINT16_MAX, 1843, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18228, UINT16_MAX, 9141, UINT16_MAX, 9141, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18230, 1848, UINT16_MAX, 1848, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18233, UINT16_MAX, 9142, UINT16_MAX, 9142, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18235, 1853, UINT16_MAX, 1853, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18238, UINT16_MAX, 9143, UINT16_MAX, 9143, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18240, 1858, UINT16_MAX, 1858, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18243, UINT16_MAX, 9144, UINT16_MAX, 9144, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18245, 1863, UINT16_MAX, 1863, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18248, UINT16_MAX, 9145, UINT16_MAX, 9145, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18250, 1868, UINT16_MAX, 1868, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18253, UINT16_MAX, 9146, UINT16_MAX, 9146, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18255, 1873, UINT16_MAX, 1873, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18258, UINT16_MAX, 9147, UINT16_MAX, 9147, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18260, 1878, UINT16_MAX, 1878, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18263, UINT16_MAX, 9148, UINT16_MAX, 9148, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18265, 1883, UINT16_MAX, 1883, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18268, UINT16_MAX, 9149, UINT16_MAX, 9149, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18270, 1888, UINT16_MAX, 1888, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18273, UINT16_MAX, 9150, UINT16_MAX, 9150, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18275, 1893, UINT16_MAX, 1893, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18278, UINT16_MAX, 9151, UINT16_MAX, 9151, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18280, 1898, UINT16_MAX, 1898, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18283, UINT16_MAX, 9152, UINT16_MAX, 9152, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18285, 1903, UINT16_MAX, 1903, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18288, UINT16_MAX, 9153, UINT16_MAX, 9153, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18290, 1908, UINT16_MAX, 1908, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18293, UINT16_MAX, 9154, UINT16_MAX, 9154, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18295, 1913, UINT16_MAX, 1913, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18298, UINT16_MAX, 9155, UINT16_MAX, 9155, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18300, 18300, 9156, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18302, 18302, 9157, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18304, 18304, 9158, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18306, 18306, 9159, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 18308, 18308, 9160, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18310, 1783, 9129, UINT16_MAX, 9129, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9161, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9162, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 16514, UINT16_MAX, 9163, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9164, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18312, 1930, UINT16_MAX, 1930, UINT16_MAX, 3241, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18315, UINT16_MAX, 9165, UINT16_MAX, 9165, 3250, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18317, 1935, UINT16_MAX, 1935, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18320, UINT16_MAX, 9166, UINT16_MAX, 9166, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18322, 1940, UINT16_MAX, 1940, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18325, UINT16_MAX, 9167, UINT16_MAX, 9167, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18327, 1945, UINT16_MAX, 1945, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18330, UINT16_MAX, 9168, UINT16_MAX, 9168, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18332, 1950, UINT16_MAX, 1950, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18335, UINT16_MAX, 9169, UINT16_MAX, 9169, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18337, 1955, UINT16_MAX, 1955, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18340, UINT16_MAX, 9170, UINT16_MAX, 9170, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18342, 1960, UINT16_MAX, 1960, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18345, UINT16_MAX, 9171, UINT16_MAX, 9171, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18347, 1965, UINT16_MAX, 1965, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18350, UINT16_MAX, 9172, UINT16_MAX, 9172, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18352, 1970, UINT16_MAX, 1970, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18355, UINT16_MAX, 9173, UINT16_MAX, 9173, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18357, 1975, UINT16_MAX, 1975, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18360, UINT16_MAX, 9174, UINT16_MAX, 9174, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18362, 1980, UINT16_MAX, 1980, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18365, UINT16_MAX, 9175, UINT16_MAX, 9175, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18367, 1985, UINT16_MAX, 1985, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18370, UINT16_MAX, 9176, UINT16_MAX, 9176, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18372, 1990, UINT16_MAX, 1990, UINT16_MAX, 3455, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18375, UINT16_MAX, 9177, UINT16_MAX, 9177, 3458, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18377, 1995, UINT16_MAX, 1995, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18380, UINT16_MAX, 9178, UINT16_MAX, 9178, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18382, 2000, UINT16_MAX, 2000, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18385, UINT16_MAX, 9179, UINT16_MAX, 9179, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18387, 2005, UINT16_MAX, 2005, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18390, UINT16_MAX, 9180, UINT16_MAX, 9180, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18392, 2010, UINT16_MAX, 2010, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18395, UINT16_MAX, 9181, UINT16_MAX, 9181, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18397, 2015, UINT16_MAX, 2015, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18400, UINT16_MAX, 9182, UINT16_MAX, 9182, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18402, 2020, UINT16_MAX, 2020, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18405, UINT16_MAX, 9183, UINT16_MAX, 9183, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18407, 2025, UINT16_MAX, 2025, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18410, UINT16_MAX, 9184, UINT16_MAX, 9184, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18412, 2030, UINT16_MAX, 2030, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18415, UINT16_MAX, 9185, UINT16_MAX, 9185, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18417, 2035, UINT16_MAX, 2035, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18420, UINT16_MAX, 9186, UINT16_MAX, 9186, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18422, 2040, UINT16_MAX, 2040, UINT16_MAX, 3559, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18425, UINT16_MAX, 9187, UINT16_MAX, 9187, 3562, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18427, 2045, UINT16_MAX, 2045, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18430, UINT16_MAX, 9188, UINT16_MAX, 9188, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18432, 2050, UINT16_MAX, 2050, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18435, UINT16_MAX, 9189, UINT16_MAX, 9189, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18437, 2055, UINT16_MAX, 2055, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18440, UINT16_MAX, 9190, UINT16_MAX, 9190, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18442, 2060, UINT16_MAX, 2060, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18445, UINT16_MAX, 9191, UINT16_MAX, 9191, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18447, 2065, UINT16_MAX, 2065, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18450, UINT16_MAX, 9192, UINT16_MAX, 9192, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18452, 2070, UINT16_MAX, 2070, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18455, UINT16_MAX, 9193, UINT16_MAX, 9193, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18457, 2075, UINT16_MAX, 2075, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18460, UINT16_MAX, 9194, UINT16_MAX, 9194, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18462, 2080, UINT16_MAX, 2080, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18465, UINT16_MAX, 9195, UINT16_MAX, 9195, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18467, 2085, UINT16_MAX, 2085, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18470, UINT16_MAX, 9196, UINT16_MAX, 9196, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18472, 2090, UINT16_MAX, 2090, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18475, UINT16_MAX, 9197, UINT16_MAX, 9197, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18477, 2095, UINT16_MAX, 2095, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18480, UINT16_MAX, 9198, UINT16_MAX, 9198, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18482, 2100, UINT16_MAX, 2100, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18485, UINT16_MAX, 9199, UINT16_MAX, 9199, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18487, 2105, UINT16_MAX, 2105, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18490, UINT16_MAX, 9200, UINT16_MAX, 9200, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18492, 2110, UINT16_MAX, 2110, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18495, UINT16_MAX, 9201, UINT16_MAX, 9201, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18497, 2115, UINT16_MAX, 2115, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18500, UINT16_MAX, 9202, UINT16_MAX, 9202, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18502, 2120, UINT16_MAX, 2120, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18505, UINT16_MAX, 9203, UINT16_MAX, 9203, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18507, 2125, UINT16_MAX, 2125, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18510, UINT16_MAX, 9204, UINT16_MAX, 9204, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18512, 2130, UINT16_MAX, 2130, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18515, UINT16_MAX, 9205, UINT16_MAX, 9205, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18517, 2135, UINT16_MAX, 2135, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18520, UINT16_MAX, 9206, UINT16_MAX, 9206, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18522, 2140, UINT16_MAX, 2140, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18525, UINT16_MAX, 9207, UINT16_MAX, 9207, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18527, 2145, UINT16_MAX, 2145, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18530, UINT16_MAX, 9208, UINT16_MAX, 9208, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18532, 2150, UINT16_MAX, 2150, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18535, UINT16_MAX, 9209, UINT16_MAX, 9209, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2153, UINT16_MAX, 2153, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9210, UINT16_MAX, 9210, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2154, UINT16_MAX, 2154, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9211, UINT16_MAX, 9211, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2155, UINT16_MAX, 2155, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9212, UINT16_MAX, 9212, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18540, UINT16_MAX, 9213, UINT16_MAX, 9213, 3761, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18542, UINT16_MAX, 9214, UINT16_MAX, 9214, 3814, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18544, UINT16_MAX, 9215, UINT16_MAX, 9215, 4793, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18546, UINT16_MAX, 9216, UINT16_MAX, 9216, 4796, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18548, UINT16_MAX, 9217, UINT16_MAX, 9217, 4799, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18550, UINT16_MAX, 9218, UINT16_MAX, 9218, 4802, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18552, UINT16_MAX, 9219, UINT16_MAX, 9219, 4805, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18554, UINT16_MAX, 9220, UINT16_MAX, 9220, 4808, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18556, 2174, UINT16_MAX, 2174, UINT16_MAX, 3867, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18559, 2177, UINT16_MAX, 2177, UINT16_MAX, 3920, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18562, 2180, UINT16_MAX, 2180, UINT16_MAX, 4811, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18565, 2183, UINT16_MAX, 2183, UINT16_MAX, 4814, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18568, 2186, UINT16_MAX, 2186, UINT16_MAX, 4817, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18571, 2189, UINT16_MAX, 2189, UINT16_MAX, 4820, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18574, 2192, UINT16_MAX, 2192, UINT16_MAX, 4823, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18577, 2195, UINT16_MAX, 2195, UINT16_MAX, 4826, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18580, UINT16_MAX, 9221, UINT16_MAX, 9221, 3973, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18582, UINT16_MAX, 9222, UINT16_MAX, 9222, 3977, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18584, UINT16_MAX, 9223, UINT16_MAX, 9223, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18586, UINT16_MAX, 9224, UINT16_MAX, 9224, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18588, UINT16_MAX, 9225, UINT16_MAX, 9225, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18590, UINT16_MAX, 9226, UINT16_MAX, 9226, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18592, 2210, UINT16_MAX, 2210, UINT16_MAX, 3981, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18595, 2213, UINT16_MAX, 2213, UINT16_MAX, 3985, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18598, 2216, UINT16_MAX, 2216, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18601, 2219, UINT16_MAX, 2219, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18604, 2222, UINT16_MAX, 2222, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18607, 2225, UINT16_MAX, 2225, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18610, UINT16_MAX, 9227, UINT16_MAX, 9227, 3989, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18612, UINT16_MAX, 9228, UINT16_MAX, 9228, 4042, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18614, UINT16_MAX, 9229, UINT16_MAX, 9229, 4829, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18616, UINT16_MAX, 9230, UINT16_MAX, 9230, 4832, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18618, UINT16_MAX, 9231, UINT16_MAX, 9231, 4835, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18620, UINT16_MAX, 9232, UINT16_MAX, 9232, 4838, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18622, UINT16_MAX, 9233, UINT16_MAX, 9233, 4841, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18624, UINT16_MAX, 9234, UINT16_MAX, 9234, 4844, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18626, 2244, UINT16_MAX, 2244, UINT16_MAX, 4095, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18629, 2247, UINT16_MAX, 2247, UINT16_MAX, 4148, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18632, 2250, UINT16_MAX, 2250, UINT16_MAX, 4847, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18635, 2253, UINT16_MAX, 2253, UINT16_MAX, 4850, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18638, 2256, UINT16_MAX, 2256, UINT16_MAX, 4853, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18641, 2259, UINT16_MAX, 2259, UINT16_MAX, 4856, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18644, 2262, UINT16_MAX, 2262, UINT16_MAX, 4859, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18647, 2265, UINT16_MAX, 2265, UINT16_MAX, 4862, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18650, UINT16_MAX, 9235, UINT16_MAX, 9235, 4201, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18652, UINT16_MAX, 9236, UINT16_MAX, 9236, 4253, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18654, UINT16_MAX, 9237, UINT16_MAX, 9237, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18656, UINT16_MAX, 9238, UINT16_MAX, 9238, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18658, UINT16_MAX, 9239, UINT16_MAX, 9239, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18660, UINT16_MAX, 9240, UINT16_MAX, 9240, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18662, UINT16_MAX, 9241, UINT16_MAX, 9241, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18664, UINT16_MAX, 9242, UINT16_MAX, 9242, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18666, 2284, UINT16_MAX, 2284, UINT16_MAX, 4305, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18669, 2287, UINT16_MAX, 2287, UINT16_MAX, 4357, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18672, 2290, UINT16_MAX, 2290, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18675, 2293, UINT16_MAX, 2293, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18678, 2296, UINT16_MAX, 2296, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18681, 2299, UINT16_MAX, 2299, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18684, 2302, UINT16_MAX, 2302, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18687, 2305, UINT16_MAX, 2305, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18690, UINT16_MAX, 9243, UINT16_MAX, 9243, 4409, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18692, UINT16_MAX, 9244, UINT16_MAX, 9244, 4413, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18694, UINT16_MAX, 9245, UINT16_MAX, 9245, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18696, UINT16_MAX, 9246, UINT16_MAX, 9246, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18698, UINT16_MAX, 9247, UINT16_MAX, 9247, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18700, UINT16_MAX, 9248, UINT16_MAX, 9248, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18702, 2320, UINT16_MAX, 2320, UINT16_MAX, 4417, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18705, 2323, UINT16_MAX, 2323, UINT16_MAX, 4421, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18708, 2326, UINT16_MAX, 2326, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18711, 2329, UINT16_MAX, 2329, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18714, 2332, UINT16_MAX, 2332, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18717, 2335, UINT16_MAX, 2335, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18720, 18720, 9249, UINT16_MAX, UINT16_MAX, 4425, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18722, UINT16_MAX, 9250, UINT16_MAX, 9250, 4477, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18724, 35110, 9251, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18729, UINT16_MAX, 9252, UINT16_MAX, 9252, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18731, 35117, 9253, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18736, UINT16_MAX, 9254, UINT16_MAX, 9254, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18738, 35124, 9255, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18743, UINT16_MAX, 9256, UINT16_MAX, 9256, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18745, 2363, UINT16_MAX, 2363, UINT16_MAX, 4529, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18748, 2366, UINT16_MAX, 2366, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18751, 2369, UINT16_MAX, 2369, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18754, 2372, UINT16_MAX, 2372, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18757, UINT16_MAX, 9257, UINT16_MAX, 9257, 4581, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18759, UINT16_MAX, 9258, UINT16_MAX, 9258, 4634, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18761, UINT16_MAX, 9259, UINT16_MAX, 9259, 4865, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18763, UINT16_MAX, 9260, UINT16_MAX, 9260, 4868, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18765, UINT16_MAX, 9261, UINT16_MAX, 9261, 4871, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18767, UINT16_MAX, 9262, UINT16_MAX, 9262, 4874, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18769, UINT16_MAX, 9263, UINT16_MAX, 9263, 4877, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18771, UINT16_MAX, 9264, UINT16_MAX, 9264, 4880, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18773, 2391, UINT16_MAX, 2391, UINT16_MAX, 4687, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18776, 2394, UINT16_MAX, 2394, UINT16_MAX, 4740, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18779, 2397, UINT16_MAX, 2397, UINT16_MAX, 4883, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18782, 2400, UINT16_MAX, 2400, UINT16_MAX, 4886, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18785, 2403, UINT16_MAX, 2403, UINT16_MAX, 4889, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18788, 2406, UINT16_MAX, 2406, UINT16_MAX, 4892, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18791, 2409, UINT16_MAX, 2409, UINT16_MAX, 4895, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18794, 2412, UINT16_MAX, 2412, UINT16_MAX, 4898, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18797, UINT16_MAX, 9265, UINT16_MAX, 9265, 4901, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 820, UINT16_MAX, 9266, UINT16_MAX, 9266, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18799, UINT16_MAX, 9267, UINT16_MAX, 9267, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 824, UINT16_MAX, 9268, UINT16_MAX, 9268, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18801, UINT16_MAX, 9269, UINT16_MAX, 9269, 4910, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 827, UINT16_MAX, 9270, UINT16_MAX, 9270, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18803, UINT16_MAX, 9271, UINT16_MAX, 9271, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 830, UINT16_MAX, 9272, UINT16_MAX, 9272, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18805, UINT16_MAX, 9273, UINT16_MAX, 9273, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 833, UINT16_MAX, 9274, UINT16_MAX, 9274, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18807, UINT16_MAX, 9275, UINT16_MAX, 9275, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 836, UINT16_MAX, 9276, UINT16_MAX, 9276, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18809, UINT16_MAX, 9277, UINT16_MAX, 9277, 5030, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 839, UINT16_MAX, 9278, UINT16_MAX, 9278, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18811, 18813, 9279, UINT16_MAX, 9279, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18815, 18817, 9280, UINT16_MAX, 9280, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18819, 18821, 9281, UINT16_MAX, 9281, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18823, 18825, 9282, UINT16_MAX, 9282, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18827, 18829, 9283, UINT16_MAX, 9283, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18831, 18833, 9284, UINT16_MAX, 9284, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18835, 18837, 9285, UINT16_MAX, 9285, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18839, 18841, 9286, UINT16_MAX, 9286, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18843, 18813, UINT16_MAX, 9287, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18845, 18817, UINT16_MAX, 9288, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18847, 18821, UINT16_MAX, 9289, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18849, 18825, UINT16_MAX, 9290, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18851, 18829, UINT16_MAX, 9291, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18853, 18833, UINT16_MAX, 9292, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18855, 18837, UINT16_MAX, 9293, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18857, 18841, UINT16_MAX, 9294, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18859, 18861, 9295, UINT16_MAX, 9295, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18863, 18865, 9296, UINT16_MAX, 9296, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18867, 18869, 9297, UINT16_MAX, 9297, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18871, 18873, 9298, UINT16_MAX, 9298, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18875, 18877, 9299, UINT16_MAX, 9299, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18879, 18881, 9300, UINT16_MAX, 9300, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18883, 18885, 9301, UINT16_MAX, 9301, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18887, 18889, 9302, UINT16_MAX, 9302, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18891, 18861, UINT16_MAX, 9303, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18893, 18865, UINT16_MAX, 9304, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18895, 18869, UINT16_MAX, 9305, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18897, 18873, UINT16_MAX, 9306, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18899, 18877, UINT16_MAX, 9307, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18901, 18881, UINT16_MAX, 9308, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18903, 18885, UINT16_MAX, 9309, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18905, 18889, UINT16_MAX, 9310, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18907, 18909, 9311, UINT16_MAX, 9311, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18911, 18913, 9312, UINT16_MAX, 9312, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18915, 18917, 9313, UINT16_MAX, 9313, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18919, 18921, 9314, UINT16_MAX, 9314, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18923, 18925, 9315, UINT16_MAX, 9315, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18927, 18929, 9316, UINT16_MAX, 9316, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18931, 18933, 9317, UINT16_MAX, 9317, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18935, 18937, 9318, UINT16_MAX, 9318, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18939, 18909, UINT16_MAX, 9319, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18941, 18913, UINT16_MAX, 9320, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18943, 18917, UINT16_MAX, 9321, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18945, 18921, UINT16_MAX, 9322, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18947, 18925, UINT16_MAX, 9323, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18949, 18929, UINT16_MAX, 9324, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18951, 18933, UINT16_MAX, 9325, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18953, 18937, UINT16_MAX, 9326, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18955, UINT16_MAX, 9327, UINT16_MAX, 9327, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18957, UINT16_MAX, 9328, UINT16_MAX, 9328, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18959, 18961, 9329, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18963, 18965, 9330, UINT16_MAX, 9330, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18967, 18969, 9331, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18971, 18971, 9332, UINT16_MAX, UINT16_MAX, 4907, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18973, 35359, 9333, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18978, 2596, UINT16_MAX, 2596, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18981, 2599, UINT16_MAX, 2599, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18984, 2602, UINT16_MAX, 2602, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2603, 2604, UINT16_MAX, 2604, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18989, 18965, UINT16_MAX, 9334, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 18991, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 807, 807, 7437, UINT16_MAX, 7437, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 18991, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 4919, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 18993, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 18995, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18997, 18999, 9335, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19001, 19003, 9336, UINT16_MAX, 9336, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19005, 19007, 9337, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19009, 19009, 9338, UINT16_MAX, UINT16_MAX, 4916, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19011, 35397, 9339, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19016, 2634, UINT16_MAX, 2634, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2635, 2636, UINT16_MAX, 2636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19021, 2639, UINT16_MAX, 2639, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2640, 2641, UINT16_MAX, 2641, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 19026, 19003, UINT16_MAX, 9340, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19028, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19032, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19034, UINT16_MAX, 9341, UINT16_MAX, 9341, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19036, UINT16_MAX, 9342, UINT16_MAX, 9342, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19038, 35424, 9343, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 2659, 33610, 9344, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19044, 19044, 9345, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19046, 35432, 9346, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19051, 2669, UINT16_MAX, 2669, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19054, 2672, UINT16_MAX, 2672, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19057, 2675, UINT16_MAX, 2675, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2676, 2677, UINT16_MAX, 2677, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19062, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19064, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19066, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19068, UINT16_MAX, 9347, UINT16_MAX, 9347, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19070, UINT16_MAX, 9348, UINT16_MAX, 9348, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19072, 35458, 9349, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 2693, 33651, 9350, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19078, 19078, 9351, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19080, UINT16_MAX, 9352, UINT16_MAX, 9352, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19082, 19082, 9353, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19084, 35470, 9354, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19089, 2707, UINT16_MAX, 2707, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19092, 2710, UINT16_MAX, 2710, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19095, 2713, UINT16_MAX, 2713, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2714, 2715, UINT16_MAX, 2715, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19100, 2718, UINT16_MAX, 2718, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19103, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 2721, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 2722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19107, 19109, 9355, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19111, 19113, 9356, UINT16_MAX, 9356, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19115, 19117, 9357, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19119, 19119, 9358, UINT16_MAX, UINT16_MAX, 5036, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19121, 35507, 9359, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19126, 2744, UINT16_MAX, 2744, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2745, 2746, UINT16_MAX, 2746, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19131, 2749, UINT16_MAX, 2749, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2750, 2751, UINT16_MAX, 2751, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 19136, 19113, UINT16_MAX, 9360, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 2754, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19139, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 4971, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, 2757, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, 2758, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_COMPAT, 26, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_NOBREAK, 26, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_ZWJ, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NOBREAK, 2759, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19144, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PI, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PF, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 2762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZL, 0, UTF8PROC_BIDI_CLASS_WS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZP, 0, UTF8PROC_BIDI_CLASS_B, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_LRE, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_RLE, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_PDF, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_LRO, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_RLO, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, 19152, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, 35538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19157, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35543, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19162, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19164, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_CS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19166, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19168, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19170, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 51940, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_LRI, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_RLI, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_FSI, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_PDI, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 8, UINT16_MAX, 9361, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUPER, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUPER, 2801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 2802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 13, UINT16_MAX, 9362, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUB, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUB, 2801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, 2802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 0, UINT16_MAX, 9363, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 4, UINT16_MAX, 9364, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 14, UINT16_MAX, 9365, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 23, UINT16_MAX, 9366, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 485, UINT16_MAX, 9367, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 7, UINT16_MAX, 9368, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 10, UINT16_MAX, 9369, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 11, UINT16_MAX, 9370, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 12, UINT16_MAX, 9371, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 13, UINT16_MAX, 9372, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 15, UINT16_MAX, 9373, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 18, UINT16_MAX, 9374, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 19, UINT16_MAX, 9375, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, 19189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35578, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 9376, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19198, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35584, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2822, UINT16_MAX, UINT16_MAX, 9377, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19207, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 9378, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 9379, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 9380, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 9381, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 9382, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 277, UINT16_MAX, 9383, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 9384, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 9385, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 9386, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 9387, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 9388, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19209, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 9389, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 9390, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 9391, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 9392, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 9393, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 19212, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35598, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 19217, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 9394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2836, 866, UINT16_MAX, 866, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 9395, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 1501, 10, UINT16_MAX, 10, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2837, 65, UINT16_MAX, 65, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 9396, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 9397, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 9398, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 9399, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 9400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2839, UINT16_MAX, 2839, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 9401, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 9402, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2840, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2842, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2843, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 9403, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 9404, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 9405, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 9406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 9407, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FONT, 2849, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 9408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 9409, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 9410, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 9411, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 9412, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9413, UINT16_MAX, 9413, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 52008, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35641, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35644, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35647, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35650, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35653, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 19281, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 1499, 2899, UINT16_MAX, 2899, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19284, 2902, UINT16_MAX, 2902, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35671, 2906, UINT16_MAX, 2906, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19291, 2909, UINT16_MAX, 2909, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2910, 2911, UINT16_MAX, 2911, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19296, 2914, UINT16_MAX, 2914, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35683, 2918, UINT16_MAX, 2918, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 52071, 2924, UINT16_MAX, 2924, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19309, 2927, UINT16_MAX, 2927, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2928, 2929, UINT16_MAX, 2929, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19314, 2932, UINT16_MAX, 2932, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35701, 2936, UINT16_MAX, 2936, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 1502, 2937, UINT16_MAX, 2937, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2813, 2938, UINT16_MAX, 2938, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 1494, 2939, UINT16_MAX, 2939, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 1503, 2940, UINT16_MAX, 2940, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 8, UINT16_MAX, 9414, UINT16_MAX, 9414, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19325, UINT16_MAX, 9415, UINT16_MAX, 9415, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35711, UINT16_MAX, 9416, UINT16_MAX, 9416, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19330, UINT16_MAX, 9417, UINT16_MAX, 9417, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21, UINT16_MAX, 9418, UINT16_MAX, 9418, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19332, UINT16_MAX, 9419, UINT16_MAX, 9419, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35718, UINT16_MAX, 9420, UINT16_MAX, 9420, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 52105, UINT16_MAX, 9421, UINT16_MAX, 9421, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19342, UINT16_MAX, 9422, UINT16_MAX, 9422, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 23, UINT16_MAX, 9423, UINT16_MAX, 9423, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19344, UINT16_MAX, 9424, UINT16_MAX, 9424, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35730, UINT16_MAX, 9425, UINT16_MAX, 9425, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 11, UINT16_MAX, 9426, UINT16_MAX, 9426, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2, UINT16_MAX, 9427, UINT16_MAX, 9427, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3, UINT16_MAX, 9428, UINT16_MAX, 9428, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 12, UINT16_MAX, 9429, UINT16_MAX, 9429, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2965, UINT16_MAX, 2965, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9430, UINT16_MAX, 9430, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35734, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5039, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5042, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5045, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19357, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19363, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5048, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5054, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5051, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5057, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5060, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5063, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19369, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5066, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19371, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5069, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19373, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19375, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35766, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5072, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19385, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5075, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19387, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5078, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19389, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5081, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19391, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5090, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19393, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5087, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19395, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5099, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5102, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19397, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19399, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19401, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19403, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19405, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5105, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5108, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19407, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19409, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5111, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5114, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19411, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19413, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5117, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5120, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5147, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5150, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19415, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19417, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5123, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5126, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19419, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19421, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5129, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5132, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19423, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19425, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5153, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5156, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5135, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5138, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5141, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5144, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19427, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19429, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19431, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19433, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5159, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5162, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5165, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5168, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19435, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19437, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19439, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19441, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19443, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19445, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19447, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19449, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, 3067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, 3068, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19453, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19455, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19457, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19459, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19461, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19463, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19465, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19467, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19469, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19473, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52270, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52275, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52280, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52290, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52295, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52300, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52305, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52310, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52315, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52320, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19561, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19563, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19565, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19567, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35959, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35962, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35965, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35968, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35971, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35974, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35977, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35980, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35983, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35986, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35989, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35992, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35995, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35998, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36001, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36004, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36007, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36010, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36013, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36016, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36019, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36022, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36025, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36028, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36031, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36034, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36037, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36040, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36043, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36046, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36049, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36052, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36055, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36058, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36061, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36064, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1491, 3302, UINT16_MAX, 3302, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1493, 3303, UINT16_MAX, 3303, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2813, 3304, UINT16_MAX, 3304, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1494, 3305, UINT16_MAX, 3305, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1495, 3306, UINT16_MAX, 3306, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2838, 3307, UINT16_MAX, 3307, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1497, 3308, UINT16_MAX, 3308, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1498, 3309, UINT16_MAX, 3309, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1499, 3310, UINT16_MAX, 3310, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1500, 3311, UINT16_MAX, 3311, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1501, 3312, UINT16_MAX, 3312, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1502, 3313, UINT16_MAX, 3313, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1503, 3314, UINT16_MAX, 3314, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1504, 3315, UINT16_MAX, 3315, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1505, 3316, UINT16_MAX, 3316, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1507, 3317, UINT16_MAX, 3317, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2827, 3318, UINT16_MAX, 3318, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1508, 3319, UINT16_MAX, 3319, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3320, 3321, UINT16_MAX, 3321, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1509, 3322, UINT16_MAX, 3322, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1510, 3323, UINT16_MAX, 3323, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2910, 3324, UINT16_MAX, 3324, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1511, 3325, UINT16_MAX, 3325, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2928, 3326, UINT16_MAX, 3326, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3327, 3328, UINT16_MAX, 3328, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2835, 3329, UINT16_MAX, 3329, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 0, UINT16_MAX, 9431, UINT16_MAX, 9431, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1, UINT16_MAX, 9432, UINT16_MAX, 9432, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2, UINT16_MAX, 9433, UINT16_MAX, 9433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3, UINT16_MAX, 9434, UINT16_MAX, 9434, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4, UINT16_MAX, 9435, UINT16_MAX, 9435, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 5, UINT16_MAX, 9436, UINT16_MAX, 9436, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 6, UINT16_MAX, 9437, UINT16_MAX, 9437, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 7, UINT16_MAX, 9438, UINT16_MAX, 9438, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 8, UINT16_MAX, 9439, UINT16_MAX, 9439, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 9, UINT16_MAX, 9440, UINT16_MAX, 9440, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 10, UINT16_MAX, 9441, UINT16_MAX, 9441, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 11, UINT16_MAX, 9442, UINT16_MAX, 9442, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 12, UINT16_MAX, 9443, UINT16_MAX, 9443, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 13, UINT16_MAX, 9444, UINT16_MAX, 9444, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 14, UINT16_MAX, 9445, UINT16_MAX, 9445, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 15, UINT16_MAX, 9446, UINT16_MAX, 9446, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 16, UINT16_MAX, 9447, UINT16_MAX, 9447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 17, UINT16_MAX, 9448, UINT16_MAX, 9448, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 18, UINT16_MAX, 9449, UINT16_MAX, 9449, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 19, UINT16_MAX, 9450, UINT16_MAX, 9450, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20, UINT16_MAX, 9451, UINT16_MAX, 9451, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 21, UINT16_MAX, 9452, UINT16_MAX, 9452, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 22, UINT16_MAX, 9453, UINT16_MAX, 9453, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 23, UINT16_MAX, 9454, UINT16_MAX, 9454, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 24, UINT16_MAX, 9455, UINT16_MAX, 9455, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 25, UINT16_MAX, 9456, UINT16_MAX, 9456, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52482, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 36103, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 36108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19727, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5171, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3345, UINT16_MAX, 3345, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3346, UINT16_MAX, 3346, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3347, UINT16_MAX, 3347, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3348, UINT16_MAX, 3348, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3349, UINT16_MAX, 3349, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3350, UINT16_MAX, 3350, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3351, UINT16_MAX, 3351, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3352, UINT16_MAX, 3352, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3353, UINT16_MAX, 3353, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3354, UINT16_MAX, 3354, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3355, UINT16_MAX, 3355, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3356, UINT16_MAX, 3356, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3357, UINT16_MAX, 3357, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3358, UINT16_MAX, 3358, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3359, UINT16_MAX, 3359, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3360, UINT16_MAX, 3360, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3361, UINT16_MAX, 3361, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3362, UINT16_MAX, 3362, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3363, UINT16_MAX, 3363, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3364, UINT16_MAX, 3364, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3365, UINT16_MAX, 3365, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3366, UINT16_MAX, 3366, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3367, UINT16_MAX, 3367, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3368, UINT16_MAX, 3368, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3369, UINT16_MAX, 3369, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3370, UINT16_MAX, 3370, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3371, UINT16_MAX, 3371, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3372, UINT16_MAX, 3372, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3373, UINT16_MAX, 3373, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3374, UINT16_MAX, 3374, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3375, UINT16_MAX, 3375, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3376, UINT16_MAX, 3376, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3377, UINT16_MAX, 3377, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3378, UINT16_MAX, 3378, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3379, UINT16_MAX, 3379, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3380, UINT16_MAX, 3380, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3381, UINT16_MAX, 3381, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3382, UINT16_MAX, 3382, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3383, UINT16_MAX, 3383, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3384, UINT16_MAX, 3384, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3385, UINT16_MAX, 3385, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3386, UINT16_MAX, 3386, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3387, UINT16_MAX, 3387, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3388, UINT16_MAX, 3388, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3389, UINT16_MAX, 3389, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3390, UINT16_MAX, 3390, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3391, UINT16_MAX, 3391, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3392, UINT16_MAX, 3392, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9457, UINT16_MAX, 9457, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9458, UINT16_MAX, 9458, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9459, UINT16_MAX, 9459, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9460, UINT16_MAX, 9460, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9461, UINT16_MAX, 9461, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9462, UINT16_MAX, 9462, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9463, UINT16_MAX, 9463, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9464, UINT16_MAX, 9464, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9465, UINT16_MAX, 9465, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9466, UINT16_MAX, 9466, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9467, UINT16_MAX, 9467, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9468, UINT16_MAX, 9468, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9469, UINT16_MAX, 9469, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9470, UINT16_MAX, 9470, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9471, UINT16_MAX, 9471, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9472, UINT16_MAX, 9472, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9473, UINT16_MAX, 9473, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9474, UINT16_MAX, 9474, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9475, UINT16_MAX, 9475, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9476, UINT16_MAX, 9476, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9477, UINT16_MAX, 9477, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9478, UINT16_MAX, 9478, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9479, UINT16_MAX, 9479, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9480, UINT16_MAX, 9480, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9481, UINT16_MAX, 9481, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9482, UINT16_MAX, 9482, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9483, UINT16_MAX, 9483, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9484, UINT16_MAX, 9484, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9485, UINT16_MAX, 9485, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9486, UINT16_MAX, 9486, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9487, UINT16_MAX, 9487, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9488, UINT16_MAX, 9488, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9489, UINT16_MAX, 9489, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9490, UINT16_MAX, 9490, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9491, UINT16_MAX, 9491, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9492, UINT16_MAX, 9492, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9493, UINT16_MAX, 9493, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9494, UINT16_MAX, 9494, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9495, UINT16_MAX, 9495, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9496, UINT16_MAX, 9496, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9497, UINT16_MAX, 9497, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9498, UINT16_MAX, 9498, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9499, UINT16_MAX, 9499, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9500, UINT16_MAX, 9500, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9501, UINT16_MAX, 9501, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9502, UINT16_MAX, 9502, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9503, UINT16_MAX, 9503, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9504, UINT16_MAX, 9504, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3393, UINT16_MAX, 3393, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9505, UINT16_MAX, 9505, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3394, UINT16_MAX, 3394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3395, UINT16_MAX, 3395, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3396, UINT16_MAX, 3396, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9506, UINT16_MAX, 9506, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9507, UINT16_MAX, 9507, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3397, UINT16_MAX, 3397, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9508, UINT16_MAX, 9508, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3398, UINT16_MAX, 3398, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9509, UINT16_MAX, 9509, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3399, UINT16_MAX, 3399, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9510, UINT16_MAX, 9510, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1513, UINT16_MAX, 1513, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1531, UINT16_MAX, 1531, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1512, UINT16_MAX, 1512, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1520, UINT16_MAX, 1520, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7083, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3400, UINT16_MAX, 3400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9511, UINT16_MAX, 9511, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9512, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3401, UINT16_MAX, 3401, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9513, UINT16_MAX, 9513, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9514, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9515, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9516, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9517, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9518, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 9, UINT16_MAX, 9519, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2910, UINT16_MAX, 9520, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3402, UINT16_MAX, 3402, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3403, UINT16_MAX, 3403, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3404, UINT16_MAX, 3404, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9521, UINT16_MAX, 9521, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3405, UINT16_MAX, 3405, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9522, UINT16_MAX, 9522, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3406, UINT16_MAX, 3406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9523, UINT16_MAX, 9523, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3407, UINT16_MAX, 3407, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9524, UINT16_MAX, 9524, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3408, UINT16_MAX, 3408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9525, UINT16_MAX, 9525, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3409, UINT16_MAX, 3409, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9526, UINT16_MAX, 9526, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3410, UINT16_MAX, 3410, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9527, UINT16_MAX, 9527, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3411, UINT16_MAX, 3411, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9528, UINT16_MAX, 9528, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3412, UINT16_MAX, 3412, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9529, UINT16_MAX, 9529, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3413, UINT16_MAX, 3413, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9530, UINT16_MAX, 9530, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3414, UINT16_MAX, 3414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9531, UINT16_MAX, 9531, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3415, UINT16_MAX, 3415, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9532, UINT16_MAX, 9532, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3416, UINT16_MAX, 3416, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9533, UINT16_MAX, 9533, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3417, UINT16_MAX, 3417, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9534, UINT16_MAX, 9534, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3418, UINT16_MAX, 3418, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9535, UINT16_MAX, 9535, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3419, UINT16_MAX, 3419, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9536, UINT16_MAX, 9536, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3420, UINT16_MAX, 3420, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9537, UINT16_MAX, 9537, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3421, UINT16_MAX, 3421, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9538, UINT16_MAX, 9538, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3422, UINT16_MAX, 3422, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9539, UINT16_MAX, 9539, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3423, UINT16_MAX, 3423, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9540, UINT16_MAX, 9540, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3424, UINT16_MAX, 3424, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9541, UINT16_MAX, 9541, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3425, UINT16_MAX, 3425, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9542, UINT16_MAX, 9542, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3426, UINT16_MAX, 3426, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9543, UINT16_MAX, 9543, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3427, UINT16_MAX, 3427, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9544, UINT16_MAX, 9544, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3428, UINT16_MAX, 3428, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9545, UINT16_MAX, 9545, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3429, UINT16_MAX, 3429, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9546, UINT16_MAX, 9546, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3430, UINT16_MAX, 3430, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9547, UINT16_MAX, 9547, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3431, UINT16_MAX, 3431, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9548, UINT16_MAX, 9548, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3432, UINT16_MAX, 3432, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9549, UINT16_MAX, 9549, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3433, UINT16_MAX, 3433, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9550, UINT16_MAX, 9550, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3434, UINT16_MAX, 3434, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9551, UINT16_MAX, 9551, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3435, UINT16_MAX, 3435, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9552, UINT16_MAX, 9552, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3436, UINT16_MAX, 3436, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9553, UINT16_MAX, 9553, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3437, UINT16_MAX, 3437, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9554, UINT16_MAX, 9554, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3438, UINT16_MAX, 3438, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9555, UINT16_MAX, 9555, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3439, UINT16_MAX, 3439, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9556, UINT16_MAX, 9556, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3440, UINT16_MAX, 3440, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9557, UINT16_MAX, 9557, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3441, UINT16_MAX, 3441, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9558, UINT16_MAX, 9558, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3442, UINT16_MAX, 3442, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9559, UINT16_MAX, 9559, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3443, UINT16_MAX, 3443, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9560, UINT16_MAX, 9560, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3444, UINT16_MAX, 3444, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9561, UINT16_MAX, 9561, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3445, UINT16_MAX, 3445, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9562, UINT16_MAX, 9562, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3446, UINT16_MAX, 3446, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9563, UINT16_MAX, 9563, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3447, UINT16_MAX, 3447, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9564, UINT16_MAX, 9564, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3448, UINT16_MAX, 3448, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9565, UINT16_MAX, 9565, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3449, UINT16_MAX, 3449, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9566, UINT16_MAX, 9566, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3450, UINT16_MAX, 3450, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9567, UINT16_MAX, 9567, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3451, UINT16_MAX, 3451, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9568, UINT16_MAX, 9568, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3452, UINT16_MAX, 3452, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9569, UINT16_MAX, 9569, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3453, UINT16_MAX, 3453, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9570, UINT16_MAX, 9570, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9571, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3454, UINT16_MAX, 3454, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9572, UINT16_MAX, 9572, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3455, UINT16_MAX, 3455, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9573, UINT16_MAX, 9573, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3456, UINT16_MAX, 3456, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9574, UINT16_MAX, 9574, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9575, UINT16_MAX, 9575, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9576, UINT16_MAX, 9576, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9577, UINT16_MAX, 9577, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9578, UINT16_MAX, 9578, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9579, UINT16_MAX, 9579, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9580, UINT16_MAX, 9580, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9581, UINT16_MAX, 9581, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9582, UINT16_MAX, 9582, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9583, UINT16_MAX, 9583, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9584, UINT16_MAX, 9584, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9585, UINT16_MAX, 9585, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9586, UINT16_MAX, 9586, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9587, UINT16_MAX, 9587, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9588, UINT16_MAX, 9588, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9589, UINT16_MAX, 9589, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9590, UINT16_MAX, 9590, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9591, UINT16_MAX, 9591, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9592, UINT16_MAX, 9592, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9593, UINT16_MAX, 9593, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9594, UINT16_MAX, 9594, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9595, UINT16_MAX, 9595, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9596, UINT16_MAX, 9596, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9597, UINT16_MAX, 9597, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9598, UINT16_MAX, 9598, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9599, UINT16_MAX, 9599, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9600, UINT16_MAX, 9600, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9601, UINT16_MAX, 9601, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9602, UINT16_MAX, 9602, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9603, UINT16_MAX, 9603, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9604, UINT16_MAX, 9604, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9605, UINT16_MAX, 9605, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9606, UINT16_MAX, 9606, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9607, UINT16_MAX, 9607, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9608, UINT16_MAX, 9608, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9609, UINT16_MAX, 9609, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9610, UINT16_MAX, 9610, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9611, UINT16_MAX, 9611, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9612, UINT16_MAX, 9612, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9613, UINT16_MAX, 9613, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9614, UINT16_MAX, 9614, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3457, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3458, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3459, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3461, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3463, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3465, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3467, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3469, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3470, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3472, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3473, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3474, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3475, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3477, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3478, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3479, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3480, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3481, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3482, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3484, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3485, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3486, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3487, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3488, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3489, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3490, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3491, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3492, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3493, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3494, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3495, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3496, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3497, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3498, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3499, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3500, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3501, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3503, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3504, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3505, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3506, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3507, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3509, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3510, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3511, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3512, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3513, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3515, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3516, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3517, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3518, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3519, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3520, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3521, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3522, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3524, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3527, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3528, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3529, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3530, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3531, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3534, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3535, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3536, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3537, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3539, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3541, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3542, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3543, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3544, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3545, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3546, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3547, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3548, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3549, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3550, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3551, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3552, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3553, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3554, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3555, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3558, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3560, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3561, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3562, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3563, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3564, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3565, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3566, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3567, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3568, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3570, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3572, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3574, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3576, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3578, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3580, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3582, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3584, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3586, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3588, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3590, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3592, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3594, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3595, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3596, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3598, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3602, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3606, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3608, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3620, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3624, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3627, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3628, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3630, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3634, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3636, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3639, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3640, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3641, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3642, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3643, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3644, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3645, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3646, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3647, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3648, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3649, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3650, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3651, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3652, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3653, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3654, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3655, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3658, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3660, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3661, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3664, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3665, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_WIDE, 26, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 224, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5239, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5174, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20061, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5177, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20063, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5180, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20065, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5183, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5186, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20069, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5189, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20071, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5192, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20073, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5195, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20075, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5198, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20077, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5201, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20079, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5204, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5207, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20083, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5210, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20085, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5213, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5216, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20089, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5219, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20091, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20093, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5223, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20095, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20097, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5227, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20099, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20101, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5231, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20103, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20105, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5235, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20107, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20109, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20111, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 8, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32820, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MN, 8, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32821, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 20113, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 20115, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5242, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, 20117, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_VERTICAL, 20119, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5310, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5245, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20121, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5248, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20123, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5251, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20125, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5254, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20127, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5257, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5260, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20131, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5263, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20133, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5266, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20135, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5269, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20137, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5272, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20139, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5275, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20141, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5278, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20143, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5281, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20145, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5284, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5287, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20149, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5290, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20151, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20153, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5294, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20155, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20157, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5298, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20159, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20161, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5302, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20163, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20165, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5306, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20167, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5313, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5316, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5319, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5322, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20173, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20175, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5325, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, 20181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_VERTICAL, 20183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3805, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3806, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3808, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3812, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3816, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3818, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3822, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3823, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3824, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3825, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3826, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3827, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3828, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3829, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3830, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3831, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3832, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3833, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3834, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3835, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3836, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3837, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3838, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3839, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3840, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3842, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3843, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3845, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3846, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3847, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3848, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3849, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3850, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3864, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3866, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3867, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3869, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3876, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3879, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3882, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3884, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3885, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3887, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3888, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3891, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3892, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3893, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3894, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3896, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3897, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3899, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3900, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3901, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3902, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3903, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3904, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36703, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36706, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36709, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36712, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53099, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53104, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53109, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53114, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53119, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53124, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53134, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53139, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53144, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53149, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53154, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53159, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53164, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 53174, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 53182, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36805, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36808, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36823, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36826, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36829, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36832, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36835, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36838, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36847, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36850, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36892, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36901, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36904, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36910, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4145, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4146, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 36916, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20535, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20537, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20539, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20541, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20543, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20545, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20547, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20549, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20551, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20553, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20555, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20561, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20563, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3818, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3823, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3824, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3826, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3827, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3828, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3829, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3830, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20565, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20567, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 53361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 53367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3896, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4222, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4223, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4224, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4225, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3545, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3544, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3534, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3491, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3531, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4226, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4227, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4229, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4230, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4231, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4232, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4233, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4234, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4235, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3497, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4236, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4237, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4238, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4239, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4240, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4241, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4242, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4243, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3897, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3899, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4244, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4245, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4246, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4247, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4248, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4249, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4250, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4251, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4252, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4253, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20640, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20642, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20644, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20646, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20648, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20650, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20652, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20654, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20658, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20660, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20664, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37070, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37073, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37076, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 20695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 20700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37086, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4321, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4322, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4323, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4324, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4325, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4327, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4328, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4329, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4330, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4331, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4333, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4334, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4337, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4342, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4343, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4345, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4349, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4357, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4363, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20752, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53522, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53527, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37153, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37161, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37164, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53551, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37178, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37184, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53576, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37197, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37200, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37205, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53592, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20834, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37239, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37259, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37262, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37265, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53652, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37284, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37290, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20909, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20911, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20913, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20915, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37301, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37304, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37313, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53705, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37327, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20946, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20948, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53718, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53724, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53729, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20976, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37371, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21001, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37387, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37393, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37401, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37404, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37407, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21037, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21045, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37441, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37444, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37447, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53834, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21071, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37457, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37473, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21092, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21094, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21096, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21098, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21100, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21102, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21104, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21106, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21110, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37496, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37499, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37505, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37511, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37517, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37520, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37529, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37535, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37541, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21160, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21162, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37548, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21167, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 21171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37560, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 21179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21185, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21187, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53957, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21194, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21196, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21198, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21200, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21202, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21204, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21206, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21208, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37594, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53981, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21218, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21220, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21222, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21224, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21226, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21230, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21244, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21246, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21248, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21250, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21252, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21254, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21256, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21258, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21260, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21262, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37648, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37651, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21270, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21281, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54057, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21294, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54076, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54082, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21321, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21323, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21325, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21327, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21329, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21331, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21333, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21337, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21343, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21345, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21349, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54125, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54136, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37757, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21376, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21378, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21384, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21388, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21394, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21399, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21401, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37787, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37790, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21409, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21419, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21421, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21423, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21425, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21433, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21435, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21437, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21439, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21441, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21443, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21445, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21447, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21449, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37835, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37838, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37847, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37850, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37892, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37901, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5136, UINT16_MAX, 5136, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9615, UINT16_MAX, 9615, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5137, UINT16_MAX, 5137, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9616, UINT16_MAX, 9616, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5138, UINT16_MAX, 5138, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9617, UINT16_MAX, 9617, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5139, UINT16_MAX, 5139, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9618, UINT16_MAX, 9618, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5140, UINT16_MAX, 5140, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9619, UINT16_MAX, 9619, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1445, UINT16_MAX, 1445, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8897, UINT16_MAX, 8897, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5141, UINT16_MAX, 5141, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9620, UINT16_MAX, 9620, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5142, UINT16_MAX, 5142, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9621, UINT16_MAX, 9621, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5143, UINT16_MAX, 5143, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9622, UINT16_MAX, 9622, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5144, UINT16_MAX, 5144, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9623, UINT16_MAX, 9623, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5145, UINT16_MAX, 5145, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9624, UINT16_MAX, 9624, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5146, UINT16_MAX, 5146, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9625, UINT16_MAX, 9625, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5147, UINT16_MAX, 5147, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9626, UINT16_MAX, 9626, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5148, UINT16_MAX, 5148, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9627, UINT16_MAX, 9627, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5149, UINT16_MAX, 5149, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9628, UINT16_MAX, 9628, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5150, UINT16_MAX, 5150, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9629, UINT16_MAX, 9629, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5151, UINT16_MAX, 5151, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9630, UINT16_MAX, 9630, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5152, UINT16_MAX, 5152, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9631, UINT16_MAX, 9631, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5153, UINT16_MAX, 5153, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9632, UINT16_MAX, 9632, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5154, UINT16_MAX, 5154, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9633, UINT16_MAX, 9633, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5155, UINT16_MAX, 5155, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9634, UINT16_MAX, 9634, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5156, UINT16_MAX, 5156, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9635, UINT16_MAX, 9635, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5157, UINT16_MAX, 5157, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9636, UINT16_MAX, 9636, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5158, UINT16_MAX, 5158, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9637, UINT16_MAX, 9637, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5159, UINT16_MAX, 5159, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9638, UINT16_MAX, 9638, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5160, UINT16_MAX, 5160, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9639, UINT16_MAX, 9639, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5161, UINT16_MAX, 5161, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9640, UINT16_MAX, 9640, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5162, UINT16_MAX, 5162, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9641, UINT16_MAX, 9641, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5163, UINT16_MAX, 5163, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9642, UINT16_MAX, 9642, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5164, UINT16_MAX, 5164, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9643, UINT16_MAX, 9643, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5165, UINT16_MAX, 5165, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9644, UINT16_MAX, 9644, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5166, UINT16_MAX, 5166, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9645, UINT16_MAX, 9645, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5167, UINT16_MAX, 5167, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9646, UINT16_MAX, 9646, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5168, UINT16_MAX, 5168, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9647, UINT16_MAX, 9647, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5169, UINT16_MAX, 5169, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9648, UINT16_MAX, 9648, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5170, UINT16_MAX, 5170, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9649, UINT16_MAX, 9649, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5171, UINT16_MAX, 5171, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9650, UINT16_MAX, 9650, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 981, UINT16_MAX, 9651, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 983, UINT16_MAX, 9652, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5172, UINT16_MAX, 5172, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9653, UINT16_MAX, 9653, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5173, UINT16_MAX, 5173, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9654, UINT16_MAX, 9654, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5174, UINT16_MAX, 5174, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9655, UINT16_MAX, 9655, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5175, UINT16_MAX, 5175, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9656, UINT16_MAX, 9656, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5176, UINT16_MAX, 5176, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9657, UINT16_MAX, 9657, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5177, UINT16_MAX, 5177, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9658, UINT16_MAX, 9658, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5178, UINT16_MAX, 5178, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9659, UINT16_MAX, 9659, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9660, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9661, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5179, UINT16_MAX, 5179, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9662, UINT16_MAX, 9662, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5180, UINT16_MAX, 5180, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9663, UINT16_MAX, 9663, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5181, UINT16_MAX, 5181, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9664, UINT16_MAX, 9664, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5182, UINT16_MAX, 5182, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9665, UINT16_MAX, 9665, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5183, UINT16_MAX, 5183, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9666, UINT16_MAX, 9666, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5184, UINT16_MAX, 5184, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9667, UINT16_MAX, 9667, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5185, UINT16_MAX, 5185, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9668, UINT16_MAX, 9668, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5186, UINT16_MAX, 5186, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9669, UINT16_MAX, 9669, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5187, UINT16_MAX, 5187, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9670, UINT16_MAX, 9670, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5188, UINT16_MAX, 5188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9671, UINT16_MAX, 9671, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5189, UINT16_MAX, 5189, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9672, UINT16_MAX, 9672, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5190, UINT16_MAX, 5190, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9673, UINT16_MAX, 9673, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5191, UINT16_MAX, 5191, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9674, UINT16_MAX, 9674, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5192, UINT16_MAX, 5192, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9675, UINT16_MAX, 9675, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5193, UINT16_MAX, 5193, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9676, UINT16_MAX, 9676, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5194, UINT16_MAX, 5194, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9677, UINT16_MAX, 9677, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5195, UINT16_MAX, 5195, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9678, UINT16_MAX, 9678, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5196, UINT16_MAX, 5196, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9679, UINT16_MAX, 9679, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5197, UINT16_MAX, 5197, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9680, UINT16_MAX, 9680, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5198, UINT16_MAX, 5198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9681, UINT16_MAX, 9681, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5199, UINT16_MAX, 5199, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9682, UINT16_MAX, 9682, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5200, UINT16_MAX, 5200, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9683, UINT16_MAX, 9683, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5201, UINT16_MAX, 5201, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9684, UINT16_MAX, 9684, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5202, UINT16_MAX, 5202, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9685, UINT16_MAX, 9685, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5203, UINT16_MAX, 5203, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9686, UINT16_MAX, 9686, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5204, UINT16_MAX, 5204, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9687, UINT16_MAX, 9687, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5205, UINT16_MAX, 5205, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9688, UINT16_MAX, 9688, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5206, UINT16_MAX, 5206, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9689, UINT16_MAX, 9689, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5207, UINT16_MAX, 5207, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9690, UINT16_MAX, 9690, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5208, UINT16_MAX, 5208, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9691, UINT16_MAX, 9691, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5209, UINT16_MAX, 5209, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9692, UINT16_MAX, 9692, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5209, UINT16_MAX, 9693, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9694, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9695, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9696, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9697, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9698, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9699, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9700, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9701, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5210, UINT16_MAX, 5210, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9702, UINT16_MAX, 9702, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5211, UINT16_MAX, 5211, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9703, UINT16_MAX, 9703, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5212, UINT16_MAX, 5212, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5213, UINT16_MAX, 5213, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9704, UINT16_MAX, 9704, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5214, UINT16_MAX, 5214, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9705, UINT16_MAX, 9705, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5215, UINT16_MAX, 5215, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9706, UINT16_MAX, 9706, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5216, UINT16_MAX, 5216, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9707, UINT16_MAX, 9707, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5217, UINT16_MAX, 5217, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9708, UINT16_MAX, 9708, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5218, UINT16_MAX, 5218, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9709, UINT16_MAX, 9709, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1524, UINT16_MAX, 1524, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7066, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5219, UINT16_MAX, 5219, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9710, UINT16_MAX, 9710, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5220, UINT16_MAX, 5220, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9711, UINT16_MAX, 9711, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9712, UINT16_MAX, 9712, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9713, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5221, UINT16_MAX, 5221, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9714, UINT16_MAX, 9714, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5222, UINT16_MAX, 5222, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9715, UINT16_MAX, 9715, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5223, UINT16_MAX, 5223, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9716, UINT16_MAX, 9716, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5224, UINT16_MAX, 5224, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9717, UINT16_MAX, 9717, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5225, UINT16_MAX, 5225, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9718, UINT16_MAX, 9718, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5226, UINT16_MAX, 5226, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9719, UINT16_MAX, 9719, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5227, UINT16_MAX, 5227, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9720, UINT16_MAX, 9720, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5228, UINT16_MAX, 5228, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9721, UINT16_MAX, 9721, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5229, UINT16_MAX, 5229, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9722, UINT16_MAX, 9722, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5230, UINT16_MAX, 5230, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9723, UINT16_MAX, 9723, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 785, UINT16_MAX, 785, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1515, UINT16_MAX, 1515, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1523, UINT16_MAX, 1523, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5231, UINT16_MAX, 5231, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1525, UINT16_MAX, 1525, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9724, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5232, UINT16_MAX, 5232, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5233, UINT16_MAX, 5233, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1527, UINT16_MAX, 1527, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5234, UINT16_MAX, 5234, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5235, UINT16_MAX, 5235, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9725, UINT16_MAX, 9725, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5236, UINT16_MAX, 5236, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9726, UINT16_MAX, 9726, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5237, UINT16_MAX, 5237, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9727, UINT16_MAX, 9727, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5238, UINT16_MAX, 5238, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9728, UINT16_MAX, 9728, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5239, UINT16_MAX, 5239, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9729, UINT16_MAX, 9729, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5240, UINT16_MAX, 5240, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9730, UINT16_MAX, 9730, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5241, UINT16_MAX, 5241, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9731, UINT16_MAX, 9731, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5242, UINT16_MAX, 5242, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9732, UINT16_MAX, 9732, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5243, UINT16_MAX, 5243, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1536, UINT16_MAX, 1536, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5244, UINT16_MAX, 5244, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5245, UINT16_MAX, 5245, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9733, UINT16_MAX, 9733, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5246, UINT16_MAX, 5246, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9734, UINT16_MAX, 9734, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5247, UINT16_MAX, 5247, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9735, UINT16_MAX, 9735, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9736, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9737, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5248, UINT16_MAX, 5248, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9738, UINT16_MAX, 9738, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5249, UINT16_MAX, 5249, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9739, UINT16_MAX, 9739, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2813, UINT16_MAX, 9740, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2838, UINT16_MAX, 9741, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2827, UINT16_MAX, 9742, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5250, UINT16_MAX, 5250, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9743, UINT16_MAX, 9743, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5251, UINT16_MAX, 9744, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 371, UINT16_MAX, 9745, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9746, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9747, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9748, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9749, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9750, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9751, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9752, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9753, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 5252, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9754, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9755, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9756, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9757, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9758, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9759, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9760, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9761, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9762, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9763, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9764, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9765, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9766, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9767, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9768, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9769, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9770, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9771, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9772, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9773, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9774, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9775, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9776, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9777, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9778, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9779, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 5253, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9780, UINT16_MAX, 9780, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9781, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9782, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9783, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9784, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9785, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9786, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9787, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5174, UINT16_MAX, 9788, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5252, UINT16_MAX, 9789, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3394, UINT16_MAX, 9790, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5253, UINT16_MAX, 9791, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9792, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9793, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9794, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9795, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9796, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9797, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7049, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7081, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9798, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5254, UINT16_MAX, 9799, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5255, 5255, UINT16_MAX, 5255, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5256, 5256, UINT16_MAX, 5256, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5257, 5257, UINT16_MAX, 5257, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5258, 5258, UINT16_MAX, 5258, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5259, 5259, UINT16_MAX, 5259, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5260, 5260, UINT16_MAX, 5260, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5261, 5261, UINT16_MAX, 5261, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5262, 5262, UINT16_MAX, 5262, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5263, 5263, UINT16_MAX, 5263, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5264, 5264, UINT16_MAX, 5264, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5265, 5265, UINT16_MAX, 5265, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5266, 5266, UINT16_MAX, 5266, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5267, 5267, UINT16_MAX, 5267, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5268, 5268, UINT16_MAX, 5268, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5269, 5269, UINT16_MAX, 5269, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5270, 5270, UINT16_MAX, 5270, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5271, 5271, UINT16_MAX, 5271, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5272, 5272, UINT16_MAX, 5272, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5273, 5273, UINT16_MAX, 5273, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5274, 5274, UINT16_MAX, 5274, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5275, 5275, UINT16_MAX, 5275, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5276, 5276, UINT16_MAX, 5276, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5277, 5277, UINT16_MAX, 5277, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5278, 5278, UINT16_MAX, 5278, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5279, 5279, UINT16_MAX, 5279, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5280, 5280, UINT16_MAX, 5280, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5281, 5281, UINT16_MAX, 5281, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5282, 5282, UINT16_MAX, 5282, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5283, 5283, UINT16_MAX, 5283, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5284, 5284, UINT16_MAX, 5284, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5285, 5285, UINT16_MAX, 5285, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5286, 5286, UINT16_MAX, 5286, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5287, 5287, UINT16_MAX, 5287, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5288, 5288, UINT16_MAX, 5288, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5289, 5289, UINT16_MAX, 5289, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5290, 5290, UINT16_MAX, 5290, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5291, 5291, UINT16_MAX, 5291, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5292, 5292, UINT16_MAX, 5292, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5293, 5293, UINT16_MAX, 5293, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5294, 5294, UINT16_MAX, 5294, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5295, 5295, UINT16_MAX, 5295, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5296, 5296, UINT16_MAX, 5296, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5297, 5297, UINT16_MAX, 5297, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5298, 5298, UINT16_MAX, 5298, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5299, 5299, UINT16_MAX, 5299, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5300, 5300, UINT16_MAX, 5300, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5301, 5301, UINT16_MAX, 5301, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5302, 5302, UINT16_MAX, 5302, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5303, 5303, UINT16_MAX, 5303, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5304, 5304, UINT16_MAX, 5304, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5305, 5305, UINT16_MAX, 5305, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5306, 5306, UINT16_MAX, 5306, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5307, 5307, UINT16_MAX, 5307, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5308, 5308, UINT16_MAX, 5308, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5309, 5309, UINT16_MAX, 5309, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5310, 5310, UINT16_MAX, 5310, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5311, 5311, UINT16_MAX, 5311, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5312, 5312, UINT16_MAX, 5312, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5313, 5313, UINT16_MAX, 5313, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5314, 5314, UINT16_MAX, 5314, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5315, 5315, UINT16_MAX, 5315, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5316, 5316, UINT16_MAX, 5316, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5317, 5317, UINT16_MAX, 5317, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5318, 5318, UINT16_MAX, 5318, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5319, 5319, UINT16_MAX, 5319, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5320, 5320, UINT16_MAX, 5320, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5321, 5321, UINT16_MAX, 5321, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5322, 5322, UINT16_MAX, 5322, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5323, 5323, UINT16_MAX, 5323, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5324, 5324, UINT16_MAX, 5324, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5325, 5325, UINT16_MAX, 5325, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5326, 5326, UINT16_MAX, 5326, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5327, 5327, UINT16_MAX, 5327, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5328, 5328, UINT16_MAX, 5328, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5329, 5329, UINT16_MAX, 5329, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5330, 5330, UINT16_MAX, 5330, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5331, 5331, UINT16_MAX, 5331, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5332, 5332, UINT16_MAX, 5332, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5333, 5333, UINT16_MAX, 5333, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5334, 5334, UINT16_MAX, 5334, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_LV, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_LVT, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CS, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5337, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5342, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5343, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5345, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5349, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5357, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5363, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5369, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5370, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5371, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5372, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5373, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5375, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5376, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5377, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5378, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5379, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5381, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3584, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5383, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5384, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5385, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5387, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5388, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5389, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5391, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5393, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5394, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5395, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5396, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5397, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5398, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5399, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5400, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5401, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5402, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5403, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5404, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5405, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5406, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5407, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5409, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5411, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5412, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5413, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5414, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5415, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5416, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5417, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5418, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5419, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5420, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5421, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5423, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5424, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5425, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5426, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5427, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5428, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5429, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5430, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5431, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5432, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5433, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5434, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5435, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5436, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5437, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5438, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5439, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5440, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3620, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5441, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5442, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5443, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5444, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5445, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5447, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5448, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5449, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5450, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5451, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5452, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5453, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5454, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5455, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3497, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5456, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5457, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5458, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5459, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5461, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5463, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3478, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5465, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5467, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5469, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5470, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5472, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5473, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5474, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5475, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5477, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5478, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5479, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5480, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5481, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5482, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5484, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5485, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5486, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5487, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5488, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5489, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5490, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5491, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5492, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5493, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5494, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5495, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5496, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5497, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5498, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5499, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5500, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5501, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5503, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5504, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5505, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5506, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5507, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5509, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5510, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5511, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5512, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5513, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5515, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5516, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5517, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5518, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5519, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5520, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5521, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5522, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5524, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5527, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5528, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5529, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 4223, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5530, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5531, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5534, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5535, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5536, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5537, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5539, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5541, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5542, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5543, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5544, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5545, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5546, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5547, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5548, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5549, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5550, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5551, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5552, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5553, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5554, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5555, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5558, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5560, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5561, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5562, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5563, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5564, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3576, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5565, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5566, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5567, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5568, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5570, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5572, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5574, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5576, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5578, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5580, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3606, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5582, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5584, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5586, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5588, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5590, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5592, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5594, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5595, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5596, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5598, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5602, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5606, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5608, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3504, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5620, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5624, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5627, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5628, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5630, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 4228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5634, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5636, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 4232, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5639, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5640, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5641, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5642, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5643, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5644, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5645, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5646, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5647, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5648, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5649, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5650, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5651, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5652, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5653, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5654, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5655, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5658, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5660, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5664, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5665, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3537, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5701, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5702, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5703, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5704, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5705, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5706, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5707, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5708, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5709, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5710, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5711, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5712, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5713, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5714, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5715, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5716, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5717, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5718, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5719, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5720, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5721, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5723, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5724, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5725, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5726, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5727, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5728, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5729, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5730, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5731, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5733, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5735, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5737, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5739, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5740, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5742, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5744, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5746, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5747, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22132, 22132, 9800, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22134, 22134, 9801, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22136, 22136, 9802, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 38522, 38522, 9803, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 38525, 38525, 9804, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22144, 22146, 9805, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22146, 22146, 9806, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22148, 22148, 9807, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22150, 22150, 9808, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22152, 22152, 9809, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22154, 22154, 9810, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22156, 22156, 9811, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22158, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 26, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22160, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5778, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 2840, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 2843, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5779, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5781, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5782, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5783, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5784, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_FONT, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22173, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22175, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22185, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22187, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22191, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22193, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22195, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22197, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22199, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22201, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22203, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22205, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22207, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22209, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22211, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22213, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22215, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22217, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22219, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22221, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22223, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22225, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22227, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22229, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22231, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_COMPAT, 22233, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5864, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5864, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5866, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5866, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5867, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5867, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5869, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5869, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5876, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5876, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5879, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5879, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5882, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5882, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5884, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5884, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5885, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5887, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5887, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5888, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5888, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22275, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22275, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22277, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22277, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22279, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22279, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22281, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22281, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22283, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22283, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22289, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22289, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22289, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22292, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22294, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22296, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22298, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22300, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22302, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22304, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22306, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22308, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22310, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22312, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22314, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22316, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22318, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22320, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22322, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22324, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22328, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22330, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22334, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22342, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22370, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22372, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22376, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22378, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22384, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22388, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22394, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22396, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22398, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22400, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22402, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22404, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22406, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22412, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22414, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22416, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22418, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22420, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22424, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22426, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22428, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22430, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22432, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22434, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22436, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22438, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22440, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22442, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22444, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22448, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22450, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22452, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22454, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22456, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22458, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22470, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22472, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22474, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22496, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22498, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22296, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22500, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22298, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22504, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22306, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22506, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22308, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22310, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22510, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22318, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22512, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22320, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22322, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22516, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22518, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22328, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22330, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22388, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22396, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22398, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22400, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22412, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22414, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22424, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22426, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22520, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22434, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22522, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22524, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22448, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22450, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22528, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22530, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22470, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22292, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22294, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22534, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22296, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22536, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22300, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22302, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22304, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22306, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22312, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22314, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22316, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22318, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22334, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22542, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22370, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22372, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22376, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22378, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22384, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22394, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22402, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22404, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22406, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22416, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22418, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22420, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22544, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22428, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22430, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22432, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22434, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22440, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22442, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22444, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22546, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22452, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22454, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22548, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22550, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22296, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22536, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22306, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22318, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22552, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22554, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22558, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22546, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22550, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 38944, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 38947, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 38950, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22595, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22595, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22554, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22558, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22370, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39009, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39012, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39012, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39015, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39018, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39021, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39024, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39027, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39033, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39036, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39039, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39042, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39045, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39048, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39048, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39051, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39054, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39054, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39057, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39057, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39060, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39063, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39063, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39066, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39069, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39069, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39072, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39072, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39075, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39078, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39078, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39084, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39090, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39093, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39093, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39096, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39099, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39102, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39105, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39111, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39114, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39117, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39120, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39123, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39126, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39126, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39132, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39132, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39135, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39138, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39141, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39144, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39150, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39153, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39156, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39159, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39162, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39165, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39168, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39174, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39180, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39186, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39192, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39195, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39198, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39201, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39204, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39207, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39210, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39213, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39216, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39219, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39222, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39225, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39231, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39234, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39237, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39240, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39243, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39246, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39249, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39111, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39117, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39252, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39255, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39258, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39261, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39264, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39267, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39264, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39258, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39270, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39273, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39276, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39279, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39282, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39267, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39090, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39060, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39288, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 39291, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 39294, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55701, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55706, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55711, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 39332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55719, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55747, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6602, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6606, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6608, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6620, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 3067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 3068, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6624, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 6627, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 6612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, 6600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, 2762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, 6603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, 6628, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6630, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SMALL, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SMALL, 6631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 2802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6634, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, 6635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, 6636, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23022, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23024, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23026, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23028, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23032, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23034, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23036, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23038, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23040, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23042, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23044, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23046, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23048, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23085, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 23085, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 23087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23089, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 23089, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23091, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 23091, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6709, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6628, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6636, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6710, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6630, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_WIDE, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, 6600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_WIDE, 6631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, 2762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, 6711, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, 6603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 2802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1491, 6712, UINT16_MAX, 6712, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1493, 6713, UINT16_MAX, 6713, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2813, 6714, UINT16_MAX, 6714, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1494, 6715, UINT16_MAX, 6715, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1495, 6716, UINT16_MAX, 6716, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2838, 6717, UINT16_MAX, 6717, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1497, 6718, UINT16_MAX, 6718, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1498, 6719, UINT16_MAX, 6719, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1499, 6720, UINT16_MAX, 6720, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1500, 6721, UINT16_MAX, 6721, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1501, 6722, UINT16_MAX, 6722, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1502, 6723, UINT16_MAX, 6723, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1503, 6724, UINT16_MAX, 6724, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1504, 6725, UINT16_MAX, 6725, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1505, 6726, UINT16_MAX, 6726, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1507, 6727, UINT16_MAX, 6727, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2827, 6728, UINT16_MAX, 6728, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1508, 6729, UINT16_MAX, 6729, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 3320, 6730, UINT16_MAX, 6730, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1509, 6731, UINT16_MAX, 6731, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1510, 6732, UINT16_MAX, 6732, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2910, 6733, UINT16_MAX, 6733, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1511, 6734, UINT16_MAX, 6734, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2928, 6735, UINT16_MAX, 6735, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 3327, 6736, UINT16_MAX, 6736, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2835, 6737, UINT16_MAX, 6737, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6634, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 2722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 0, UINT16_MAX, 9812, UINT16_MAX, 9812, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1, UINT16_MAX, 9813, UINT16_MAX, 9813, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2, UINT16_MAX, 9814, UINT16_MAX, 9814, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 3, UINT16_MAX, 9815, UINT16_MAX, 9815, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 4, UINT16_MAX, 9816, UINT16_MAX, 9816, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 5, UINT16_MAX, 9817, UINT16_MAX, 9817, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 6, UINT16_MAX, 9818, UINT16_MAX, 9818, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 7, UINT16_MAX, 9819, UINT16_MAX, 9819, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 8, UINT16_MAX, 9820, UINT16_MAX, 9820, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 9, UINT16_MAX, 9821, UINT16_MAX, 9821, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 10, UINT16_MAX, 9822, UINT16_MAX, 9822, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 11, UINT16_MAX, 9823, UINT16_MAX, 9823, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 12, UINT16_MAX, 9824, UINT16_MAX, 9824, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 13, UINT16_MAX, 9825, UINT16_MAX, 9825, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 14, UINT16_MAX, 9826, UINT16_MAX, 9826, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 15, UINT16_MAX, 9827, UINT16_MAX, 9827, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 16, UINT16_MAX, 9828, UINT16_MAX, 9828, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 17, UINT16_MAX, 9829, UINT16_MAX, 9829, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 18, UINT16_MAX, 9830, UINT16_MAX, 9830, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 19, UINT16_MAX, 9831, UINT16_MAX, 9831, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 20, UINT16_MAX, 9832, UINT16_MAX, 9832, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 21, UINT16_MAX, 9833, UINT16_MAX, 9833, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 22, UINT16_MAX, 9834, UINT16_MAX, 9834, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 23, UINT16_MAX, 9835, UINT16_MAX, 9835, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 24, UINT16_MAX, 9836, UINT16_MAX, 9836, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 25, UINT16_MAX, 9837, UINT16_MAX, 9837, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6739, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6740, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6741, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6742, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6602, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6743, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6744, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6745, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6746, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6747, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6748, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6749, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6750, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6751, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6752, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6753, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4321, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4322, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4323, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4324, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4325, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4327, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4328, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4329, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4330, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4331, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4333, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4334, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4337, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4342, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4343, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4345, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4349, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4357, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4363, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6754, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6755, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6756, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6757, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6758, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6759, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6760, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6763, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6764, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6765, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6766, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6767, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6768, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6769, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6770, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6771, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6772, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6773, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6774, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6775, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6776, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6777, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6778, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6779, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6781, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6782, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6783, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6784, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6785, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6786, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6787, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6788, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6789, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6790, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6791, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6792, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6805, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6806, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6808, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6812, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6816, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6818, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6822, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6823, UINT16_MAX, 6823, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6825, UINT16_MAX, 6825, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6827, UINT16_MAX, 6827, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6829, UINT16_MAX, 6829, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6831, UINT16_MAX, 6831, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6833, UINT16_MAX, 6833, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6835, UINT16_MAX, 6835, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6837, UINT16_MAX, 6837, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6839, UINT16_MAX, 6839, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6841, UINT16_MAX, 6841, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6843, UINT16_MAX, 6843, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6845, UINT16_MAX, 6845, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6847, UINT16_MAX, 6847, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6849, UINT16_MAX, 6849, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6851, UINT16_MAX, 6851, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6853, UINT16_MAX, 6853, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6855, UINT16_MAX, 6855, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6857, UINT16_MAX, 6857, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6859, UINT16_MAX, 6859, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6861, UINT16_MAX, 6861, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6863, UINT16_MAX, 6863, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6865, UINT16_MAX, 6865, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6867, UINT16_MAX, 6867, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6869, UINT16_MAX, 6869, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6871, UINT16_MAX, 6871, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6873, UINT16_MAX, 6873, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6875, UINT16_MAX, 6875, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6877, UINT16_MAX, 6877, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6879, UINT16_MAX, 6879, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6881, UINT16_MAX, 6881, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6883, UINT16_MAX, 6883, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6885, UINT16_MAX, 6885, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6887, UINT16_MAX, 6887, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6889, UINT16_MAX, 6889, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6891, UINT16_MAX, 6891, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6893, UINT16_MAX, 6893, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6895, UINT16_MAX, 6895, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6897, UINT16_MAX, 6897, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6899, UINT16_MAX, 6899, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6901, UINT16_MAX, 6901, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9838, UINT16_MAX, 9838, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9840, UINT16_MAX, 9840, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9842, UINT16_MAX, 9842, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9844, UINT16_MAX, 9844, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9846, UINT16_MAX, 9846, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9848, UINT16_MAX, 9848, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9850, UINT16_MAX, 9850, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9852, UINT16_MAX, 9852, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9854, UINT16_MAX, 9854, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9856, UINT16_MAX, 9856, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9858, UINT16_MAX, 9858, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9860, UINT16_MAX, 9860, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9862, UINT16_MAX, 9862, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9864, UINT16_MAX, 9864, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9866, UINT16_MAX, 9866, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9868, UINT16_MAX, 9868, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9870, UINT16_MAX, 9870, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9872, UINT16_MAX, 9872, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9874, UINT16_MAX, 9874, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9876, UINT16_MAX, 9876, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9878, UINT16_MAX, 9878, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9880, UINT16_MAX, 9880, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9882, UINT16_MAX, 9882, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9884, UINT16_MAX, 9884, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9886, UINT16_MAX, 9886, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9888, UINT16_MAX, 9888, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9890, UINT16_MAX, 9890, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9892, UINT16_MAX, 9892, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9894, UINT16_MAX, 9894, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9896, UINT16_MAX, 9896, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9898, UINT16_MAX, 9898, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9900, UINT16_MAX, 9900, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9902, UINT16_MAX, 9902, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9904, UINT16_MAX, 9904, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9906, UINT16_MAX, 9906, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9908, UINT16_MAX, 9908, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9910, UINT16_MAX, 9910, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9912, UINT16_MAX, 9912, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9914, UINT16_MAX, 9914, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9916, UINT16_MAX, 9916, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6903, UINT16_MAX, 6903, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6905, UINT16_MAX, 6905, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6907, UINT16_MAX, 6907, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6909, UINT16_MAX, 6909, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6911, UINT16_MAX, 6911, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6913, UINT16_MAX, 6913, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6915, UINT16_MAX, 6915, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6917, UINT16_MAX, 6917, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6919, UINT16_MAX, 6919, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6921, UINT16_MAX, 6921, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6923, UINT16_MAX, 6923, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6925, UINT16_MAX, 6925, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6927, UINT16_MAX, 6927, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6929, UINT16_MAX, 6929, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6931, UINT16_MAX, 6931, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6933, UINT16_MAX, 6933, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6935, UINT16_MAX, 6935, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6937, UINT16_MAX, 6937, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6939, UINT16_MAX, 6939, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6941, UINT16_MAX, 6941, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6943, UINT16_MAX, 6943, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6945, UINT16_MAX, 6945, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6947, UINT16_MAX, 6947, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6949, UINT16_MAX, 6949, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6951, UINT16_MAX, 6951, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6953, UINT16_MAX, 6953, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6955, UINT16_MAX, 6955, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6957, UINT16_MAX, 6957, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6959, UINT16_MAX, 6959, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6961, UINT16_MAX, 6961, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6963, UINT16_MAX, 6963, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6965, UINT16_MAX, 6965, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6967, UINT16_MAX, 6967, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6969, UINT16_MAX, 6969, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6971, UINT16_MAX, 6971, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6973, UINT16_MAX, 6973, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9918, UINT16_MAX, 9918, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9920, UINT16_MAX, 9920, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9922, UINT16_MAX, 9922, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9924, UINT16_MAX, 9924, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9926, UINT16_MAX, 9926, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9928, UINT16_MAX, 9928, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9930, UINT16_MAX, 9930, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9932, UINT16_MAX, 9932, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9934, UINT16_MAX, 9934, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9936, UINT16_MAX, 9936, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9938, UINT16_MAX, 9938, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9940, UINT16_MAX, 9940, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9942, UINT16_MAX, 9942, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9944, UINT16_MAX, 9944, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9946, UINT16_MAX, 9946, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9948, UINT16_MAX, 9948, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9950, UINT16_MAX, 9950, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9952, UINT16_MAX, 9952, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9954, UINT16_MAX, 9954, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9956, UINT16_MAX, 9956, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9958, UINT16_MAX, 9958, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9960, UINT16_MAX, 9960, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9962, UINT16_MAX, 9962, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9964, UINT16_MAX, 9964, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9966, UINT16_MAX, 9966, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9968, UINT16_MAX, 9968, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9970, UINT16_MAX, 9970, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9972, UINT16_MAX, 9972, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9974, UINT16_MAX, 9974, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9976, UINT16_MAX, 9976, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9978, UINT16_MAX, 9978, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9980, UINT16_MAX, 9980, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9982, UINT16_MAX, 9982, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9984, UINT16_MAX, 9984, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9986, UINT16_MAX, 9986, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9988, UINT16_MAX, 9988, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6975, UINT16_MAX, 6975, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6977, UINT16_MAX, 6977, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6979, UINT16_MAX, 6979, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6981, UINT16_MAX, 6981, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6983, UINT16_MAX, 6983, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6985, UINT16_MAX, 6985, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6987, UINT16_MAX, 6987, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6989, UINT16_MAX, 6989, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6991, UINT16_MAX, 6991, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6993, UINT16_MAX, 6993, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6995, UINT16_MAX, 6995, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6997, UINT16_MAX, 6997, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6999, UINT16_MAX, 6999, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7001, UINT16_MAX, 7001, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7003, UINT16_MAX, 7003, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7005, UINT16_MAX, 7005, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7007, UINT16_MAX, 7007, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7009, UINT16_MAX, 7009, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7011, UINT16_MAX, 7011, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7013, UINT16_MAX, 7013, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7015, UINT16_MAX, 7015, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7017, UINT16_MAX, 7017, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7019, UINT16_MAX, 7019, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7021, UINT16_MAX, 7021, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7023, UINT16_MAX, 7023, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7025, UINT16_MAX, 7025, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7027, UINT16_MAX, 7027, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7029, UINT16_MAX, 7029, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7031, UINT16_MAX, 7031, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7033, UINT16_MAX, 7033, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7035, UINT16_MAX, 7035, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7037, UINT16_MAX, 7037, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7039, UINT16_MAX, 7039, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7041, UINT16_MAX, 7041, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7043, UINT16_MAX, 7043, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9990, UINT16_MAX, 9990, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9992, UINT16_MAX, 9992, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9994, UINT16_MAX, 9994, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9996, UINT16_MAX, 9996, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9998, UINT16_MAX, 9998, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10000, UINT16_MAX, 10000, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10002, UINT16_MAX, 10002, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10004, UINT16_MAX, 10004, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10006, UINT16_MAX, 10006, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10008, UINT16_MAX, 10008, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10010, UINT16_MAX, 10010, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10012, UINT16_MAX, 10012, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10014, UINT16_MAX, 10014, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10016, UINT16_MAX, 10016, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10018, UINT16_MAX, 10018, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10020, UINT16_MAX, 10020, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10022, UINT16_MAX, 10022, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10024, UINT16_MAX, 10024, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10026, UINT16_MAX, 10026, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10028, UINT16_MAX, 10028, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10030, UINT16_MAX, 10030, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10032, UINT16_MAX, 10032, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10034, UINT16_MAX, 10034, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10036, UINT16_MAX, 10036, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10038, UINT16_MAX, 10038, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10040, UINT16_MAX, 10040, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10042, UINT16_MAX, 10042, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10044, UINT16_MAX, 10044, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10046, UINT16_MAX, 10046, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10048, UINT16_MAX, 10048, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10050, UINT16_MAX, 10050, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10052, UINT16_MAX, 10052, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10054, UINT16_MAX, 10054, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10056, UINT16_MAX, 10056, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10058, UINT16_MAX, 10058, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10060, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7045, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7046, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 66, UINT16_MAX, 10062, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7047, UINT16_MAX, 10064, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 476, UINT16_MAX, 10066, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7048, UINT16_MAX, 10068, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7049, UINT16_MAX, 10070, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7050, UINT16_MAX, 10072, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7051, UINT16_MAX, 10074, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 481, UINT16_MAX, 10076, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 482, UINT16_MAX, 10078, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7052, UINT16_MAX, 10080, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7053, UINT16_MAX, 10082, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7054, UINT16_MAX, 10084, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7055, UINT16_MAX, 10086, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7056, UINT16_MAX, 10088, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7057, UINT16_MAX, 10090, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 488, UINT16_MAX, 10092, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7058, UINT16_MAX, 10094, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 277, UINT16_MAX, 10096, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7059, UINT16_MAX, 10098, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7060, UINT16_MAX, 10100, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7061, UINT16_MAX, 10102, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7062, UINT16_MAX, 10104, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7063, UINT16_MAX, 10106, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5231, UINT16_MAX, 10108, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7064, UINT16_MAX, 10110, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7066, UINT16_MAX, 10112, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7067, UINT16_MAX, 10114, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7068, UINT16_MAX, 10116, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7070, UINT16_MAX, 10118, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7071, UINT16_MAX, 10120, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 113, UINT16_MAX, 10122, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7073, UINT16_MAX, 10124, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7074, UINT16_MAX, 10126, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 16, UINT16_MAX, 10128, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7075, UINT16_MAX, 10130, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7076, UINT16_MAX, 10132, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3396, UINT16_MAX, 10134, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7078, UINT16_MAX, 10136, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 503, UINT16_MAX, 10138, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7079, UINT16_MAX, 10140, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7080, UINT16_MAX, 10142, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7081, UINT16_MAX, 10144, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7082, UINT16_MAX, 10146, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 507, UINT16_MAX, 10148, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7083, UINT16_MAX, 10150, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7084, UINT16_MAX, 10152, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7085, UINT16_MAX, 10154, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7086, UINT16_MAX, 10156, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7087, UINT16_MAX, 10158, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7088, UINT16_MAX, 10160, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7089, UINT16_MAX, 10162, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7090, UINT16_MAX, 10164, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7091, UINT16_MAX, 10166, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7093, UINT16_MAX, 10168, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7095, UINT16_MAX, 7095, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7097, UINT16_MAX, 7097, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7099, UINT16_MAX, 7099, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7101, UINT16_MAX, 7101, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7103, UINT16_MAX, 7103, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7105, UINT16_MAX, 7105, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7107, UINT16_MAX, 7107, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7109, UINT16_MAX, 7109, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7111, UINT16_MAX, 7111, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7113, UINT16_MAX, 7113, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7115, UINT16_MAX, 7115, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7117, UINT16_MAX, 7117, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7119, UINT16_MAX, 7119, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7121, UINT16_MAX, 7121, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7123, UINT16_MAX, 7123, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7125, UINT16_MAX, 7125, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7127, UINT16_MAX, 7127, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7129, UINT16_MAX, 7129, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7131, UINT16_MAX, 7131, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7133, UINT16_MAX, 7133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7135, UINT16_MAX, 7135, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7137, UINT16_MAX, 7137, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7139, UINT16_MAX, 7139, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7141, UINT16_MAX, 7141, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7143, UINT16_MAX, 7143, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7145, UINT16_MAX, 7145, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7147, UINT16_MAX, 7147, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7149, UINT16_MAX, 7149, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7151, UINT16_MAX, 7151, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7153, UINT16_MAX, 7153, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7155, UINT16_MAX, 7155, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7157, UINT16_MAX, 7157, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7159, UINT16_MAX, 7159, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7161, UINT16_MAX, 7161, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7163, UINT16_MAX, 7163, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7165, UINT16_MAX, 7165, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7167, UINT16_MAX, 7167, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7169, UINT16_MAX, 7169, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7171, UINT16_MAX, 7171, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7173, UINT16_MAX, 7173, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7175, UINT16_MAX, 7175, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7177, UINT16_MAX, 7177, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7179, UINT16_MAX, 7179, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7181, UINT16_MAX, 7181, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7183, UINT16_MAX, 7183, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7185, UINT16_MAX, 7185, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7187, UINT16_MAX, 7187, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7189, UINT16_MAX, 7189, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7191, UINT16_MAX, 7191, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7193, UINT16_MAX, 7193, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7195, UINT16_MAX, 7195, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10170, UINT16_MAX, 10170, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10172, UINT16_MAX, 10172, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10174, UINT16_MAX, 10174, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10176, UINT16_MAX, 10176, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10178, UINT16_MAX, 10178, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10180, UINT16_MAX, 10180, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10182, UINT16_MAX, 10182, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10184, UINT16_MAX, 10184, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10186, UINT16_MAX, 10186, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10188, UINT16_MAX, 10188, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10190, UINT16_MAX, 10190, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10192, UINT16_MAX, 10192, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10194, UINT16_MAX, 10194, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10196, UINT16_MAX, 10196, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10198, UINT16_MAX, 10198, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10200, UINT16_MAX, 10200, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10202, UINT16_MAX, 10202, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10204, UINT16_MAX, 10204, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10206, UINT16_MAX, 10206, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10208, UINT16_MAX, 10208, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10210, UINT16_MAX, 10210, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10212, UINT16_MAX, 10212, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10214, UINT16_MAX, 10214, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10216, UINT16_MAX, 10216, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10218, UINT16_MAX, 10218, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10220, UINT16_MAX, 10220, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10222, UINT16_MAX, 10222, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10224, UINT16_MAX, 10224, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10226, UINT16_MAX, 10226, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10228, UINT16_MAX, 10228, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10230, UINT16_MAX, 10230, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10232, UINT16_MAX, 10232, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10234, UINT16_MAX, 10234, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10236, UINT16_MAX, 10236, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10238, UINT16_MAX, 10238, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10240, UINT16_MAX, 10240, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10242, UINT16_MAX, 10242, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10244, UINT16_MAX, 10244, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10246, UINT16_MAX, 10246, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10248, UINT16_MAX, 10248, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10250, UINT16_MAX, 10250, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10252, UINT16_MAX, 10252, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10254, UINT16_MAX, 10254, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10256, UINT16_MAX, 10256, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10258, UINT16_MAX, 10258, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10260, UINT16_MAX, 10260, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10262, UINT16_MAX, 10262, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10264, UINT16_MAX, 10264, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10266, UINT16_MAX, 10266, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10268, UINT16_MAX, 10268, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10270, UINT16_MAX, 10270, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_AN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5328, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5332, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5336, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 7, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49206, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_PREPEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49208, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 23593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 23597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5340, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5344, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49210, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5348, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49212, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49216, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5354, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49214, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49218, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49220, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5362, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5366, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7245, UINT16_MAX, 7245, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7247, UINT16_MAX, 7247, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7249, UINT16_MAX, 7249, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7251, UINT16_MAX, 7251, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7253, UINT16_MAX, 7253, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7255, UINT16_MAX, 7255, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7257, UINT16_MAX, 7257, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7259, UINT16_MAX, 7259, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7261, UINT16_MAX, 7261, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7263, UINT16_MAX, 7263, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7265, UINT16_MAX, 7265, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7267, UINT16_MAX, 7267, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7269, UINT16_MAX, 7269, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7271, UINT16_MAX, 7271, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7273, UINT16_MAX, 7273, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7275, UINT16_MAX, 7275, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7277, UINT16_MAX, 7277, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7279, UINT16_MAX, 7279, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7281, UINT16_MAX, 7281, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7283, UINT16_MAX, 7283, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7285, UINT16_MAX, 7285, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7287, UINT16_MAX, 7287, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7289, UINT16_MAX, 7289, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7291, UINT16_MAX, 7291, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7293, UINT16_MAX, 7293, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7295, UINT16_MAX, 7295, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7297, UINT16_MAX, 7297, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7299, UINT16_MAX, 7299, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7301, UINT16_MAX, 7301, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7303, UINT16_MAX, 7303, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7305, UINT16_MAX, 7305, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7307, UINT16_MAX, 7307, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10272, UINT16_MAX, 10272, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10274, UINT16_MAX, 10274, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10276, UINT16_MAX, 10276, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10278, UINT16_MAX, 10278, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10280, UINT16_MAX, 10280, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10282, UINT16_MAX, 10282, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10284, UINT16_MAX, 10284, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10286, UINT16_MAX, 10286, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10288, UINT16_MAX, 10288, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10290, UINT16_MAX, 10290, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10292, UINT16_MAX, 10292, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10294, UINT16_MAX, 10294, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10296, UINT16_MAX, 10296, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10298, UINT16_MAX, 10298, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10300, UINT16_MAX, 10300, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10302, UINT16_MAX, 10302, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10304, UINT16_MAX, 10304, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10306, UINT16_MAX, 10306, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10308, UINT16_MAX, 10308, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10310, UINT16_MAX, 10310, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10312, UINT16_MAX, 10312, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10314, UINT16_MAX, 10314, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10316, UINT16_MAX, 10316, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10318, UINT16_MAX, 10318, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10320, UINT16_MAX, 10320, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10322, UINT16_MAX, 10322, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10324, UINT16_MAX, 10324, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10326, UINT16_MAX, 10326, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10328, UINT16_MAX, 10328, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10330, UINT16_MAX, 10330, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10332, UINT16_MAX, 10332, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10334, UINT16_MAX, 10334, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49222, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5370, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7313, UINT16_MAX, 7313, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7315, UINT16_MAX, 7315, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7317, UINT16_MAX, 7317, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7319, UINT16_MAX, 7319, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7321, UINT16_MAX, 7321, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7323, UINT16_MAX, 7323, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7325, UINT16_MAX, 7325, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7327, UINT16_MAX, 7327, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7329, UINT16_MAX, 7329, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7331, UINT16_MAX, 7331, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7333, UINT16_MAX, 7333, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7335, UINT16_MAX, 7335, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7337, UINT16_MAX, 7337, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7339, UINT16_MAX, 7339, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7341, UINT16_MAX, 7341, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7343, UINT16_MAX, 7343, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7345, UINT16_MAX, 7345, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7347, UINT16_MAX, 7347, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7349, UINT16_MAX, 7349, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7351, UINT16_MAX, 7351, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7353, UINT16_MAX, 7353, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7355, UINT16_MAX, 7355, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7357, UINT16_MAX, 7357, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7359, UINT16_MAX, 7359, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7361, UINT16_MAX, 7361, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7363, UINT16_MAX, 7363, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7365, UINT16_MAX, 7365, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7367, UINT16_MAX, 7367, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7369, UINT16_MAX, 7369, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7371, UINT16_MAX, 7371, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7373, UINT16_MAX, 7373, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7375, UINT16_MAX, 7375, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10336, UINT16_MAX, 10336, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10338, UINT16_MAX, 10338, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10340, UINT16_MAX, 10340, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10342, UINT16_MAX, 10342, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10344, UINT16_MAX, 10344, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10346, UINT16_MAX, 10346, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10348, UINT16_MAX, 10348, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10350, UINT16_MAX, 10350, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10352, UINT16_MAX, 10352, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10354, UINT16_MAX, 10354, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10356, UINT16_MAX, 10356, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10358, UINT16_MAX, 10358, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10360, UINT16_MAX, 10360, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10362, UINT16_MAX, 10362, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10364, UINT16_MAX, 10364, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10366, UINT16_MAX, 10366, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10368, UINT16_MAX, 10368, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10370, UINT16_MAX, 10370, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10372, UINT16_MAX, 10372, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10374, UINT16_MAX, 10374, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10376, UINT16_MAX, 10376, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10378, UINT16_MAX, 10378, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10380, UINT16_MAX, 10380, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10382, UINT16_MAX, 10382, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10384, UINT16_MAX, 10384, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10386, UINT16_MAX, 10386, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10388, UINT16_MAX, 10388, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10390, UINT16_MAX, 10390, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10392, UINT16_MAX, 10392, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10394, UINT16_MAX, 10394, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10396, UINT16_MAX, 10396, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10398, UINT16_MAX, 10398, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 6, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5374, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5378, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23765, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5382, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23769, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23773, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23777, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23781, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23785, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49224, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 226, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49226, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49228, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49230, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49232, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49234, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_EXTEND}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5394, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5398, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23789, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5402, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5408, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23805, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10402, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10404, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10410, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10412, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 10414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 10416, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10418, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10420, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10422, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10424, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10426, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10428, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10430, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10432, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 10434, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10436, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10438, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10440, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10442, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10444, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10446, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10448, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10450, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10452, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10454, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10456, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10458, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10460, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10462, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10464, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10466, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10468, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10470, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10472, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10474, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10476, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10478, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10480, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10482, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10484, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10486, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10488, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10490, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10492, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10494, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10496, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10498, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10500, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10502, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10504, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10506, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10508, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10510, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10512, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10514, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10516, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 10518, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 10520, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10522, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10524, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10526, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10528, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10530, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10532, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10534, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10536, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 10538, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10540, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10542, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10544, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10546, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10548, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10550, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10552, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10554, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10556, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10558, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10560, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10562, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10564, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10566, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10568, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10570, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10572, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10574, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10576, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10578, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10580, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10582, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10584, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10586, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10588, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10590, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10592, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10594, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10596, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10598, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10600, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10602, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10604, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10606, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10608, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10610, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10612, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10614, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10616, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10618, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 10620, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 10622, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10624, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10626, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10628, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10630, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10632, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10634, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10638, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 10640, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10642, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10644, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10646, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10648, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10650, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10652, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10654, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10656, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10658, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10660, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10662, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10664, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10666, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10668, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10670, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10672, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10674, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10676, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10678, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10680, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10682, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10684, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10686, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10688, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10690, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10692, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10694, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10696, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10698, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10700, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10702, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10704, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10706, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10708, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10710, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10712, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10714, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10716, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10718, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10720, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10722, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10724, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10726, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10728, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10730, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10732, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10734, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10736, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10738, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10740, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10742, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10744, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10746, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10748, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10750, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10752, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10754, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10756, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10758, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10760, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10762, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10764, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10766, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10768, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10770, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10772, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10774, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10776, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10778, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10780, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10782, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10784, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10786, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10788, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10790, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10792, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10794, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10796, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10798, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10800, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10802, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10804, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 10806, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 10808, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10810, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10812, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10814, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10816, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10818, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10820, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10822, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10824, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 10826, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10828, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10830, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10832, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10834, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10836, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10838, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10840, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10842, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10844, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10846, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10848, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10850, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10852, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10854, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10856, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10858, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10860, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10862, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10864, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10866, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10868, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10870, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10872, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10874, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10876, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10878, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10880, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10882, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10884, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10886, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10888, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10890, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10892, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10894, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10896, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10898, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10900, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10902, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10904, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10906, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10908, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10910, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10912, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10914, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10916, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10918, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10920, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10922, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10924, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10926, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10928, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10930, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10932, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10934, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10936, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10938, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10940, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10942, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10944, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10946, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10948, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10950, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10952, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10954, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10956, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10958, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10960, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10962, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10964, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10966, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10968, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10970, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10972, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10974, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10976, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10978, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10980, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10982, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10984, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10986, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10988, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10990, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10992, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10994, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10996, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10998, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11000, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11002, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11004, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11006, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11008, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11010, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11012, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11014, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11016, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11018, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11020, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11022, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11024, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11026, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11028, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11030, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11032, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11034, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11036, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11038, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11040, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11042, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11044, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11046, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11048, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11050, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11052, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11054, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11056, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11058, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11060, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11062, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11064, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11066, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11068, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11070, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11072, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11074, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11076, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11078, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11080, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11082, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11084, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11086, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11088, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11090, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11092, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11094, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11096, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11098, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11100, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11102, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11104, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11106, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11108, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11110, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11112, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11114, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11116, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11118, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11120, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11122, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11124, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11126, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11128, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11130, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11132, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11134, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11136, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11138, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11140, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11142, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11144, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11146, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11148, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11150, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11152, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11154, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11156, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11158, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11160, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11162, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11164, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11166, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11168, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11170, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11172, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11174, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11176, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11178, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11180, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11182, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11184, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11186, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11190, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11192, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11194, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11196, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11200, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11202, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11204, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11206, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11208, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11210, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11212, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11214, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11216, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11218, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11220, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11222, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11224, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11226, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11228, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11230, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11232, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11234, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11236, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11238, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11240, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11242, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11244, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11246, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11248, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11250, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11252, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11254, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11256, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11258, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11260, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11262, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11264, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11266, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11268, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11270, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11272, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11274, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11276, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11278, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11280, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11282, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11284, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11286, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11288, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11290, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11292, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11294, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11296, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11298, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11300, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11302, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11304, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11306, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11308, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11310, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11312, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11314, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11316, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11318, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11320, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11322, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11324, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11326, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11328, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11330, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11332, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11334, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11336, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11338, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11340, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11342, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11344, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11346, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11348, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11350, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11352, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11354, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11356, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11358, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11360, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11362, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11364, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11366, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11368, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11370, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11372, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11374, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11376, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11378, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11380, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11382, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11384, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11386, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11388, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11390, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11392, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11396, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11398, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11402, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11404, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11410, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11412, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11416, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11418, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11420, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11422, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11424, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11426, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11428, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11430, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11432, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11434, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11436, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11438, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11440, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11442, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11444, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11446, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11448, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11450, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11452, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11454, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11456, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11458, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11460, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11462, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11464, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11466, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11468, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11470, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11472, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11474, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11476, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11478, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11480, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11482, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11484, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11486, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11488, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11490, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11492, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11494, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11496, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11498, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11500, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11502, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11504, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11506, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11508, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11510, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11512, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11514, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11516, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11518, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11520, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11522, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11524, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11526, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11528, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11530, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11532, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11534, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11536, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11538, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11540, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11542, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11544, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11546, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11548, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11550, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11552, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11554, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11556, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11558, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11560, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11562, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11564, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11566, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11568, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11570, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11572, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11574, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11576, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11578, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11580, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11582, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11584, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11586, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11588, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11590, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11592, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11594, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11596, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11598, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11600, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11602, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11604, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11606, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11608, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11610, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11612, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11614, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11616, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11618, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11620, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11622, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11624, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11626, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11628, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11630, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11632, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11634, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11638, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11640, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11642, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11644, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11646, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11648, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11650, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11652, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11654, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11656, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11658, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11660, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11662, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11664, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11666, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11668, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11670, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11672, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11674, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11676, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11678, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11680, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11682, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11684, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11686, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11688, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11690, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11692, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11694, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11696, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11698, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11700, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11702, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7429, UINT16_MAX, 11704, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7430, UINT16_MAX, 11706, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 11708, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 11710, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 11712, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 11714, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 11716, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 11718, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 11720, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 11722, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 11724, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 11726, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 11728, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 11730, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 11732, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 11734, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 11736, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 11738, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 11740, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 11742, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 11744, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 11746, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 11748, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 11750, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 11752, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 11754, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 11756, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7450, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 11758, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 11760, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 11762, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 11764, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 11766, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 11768, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 11770, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 11772, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 11774, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 11776, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 11778, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 11780, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 11782, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 11784, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 11786, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 11788, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 11790, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 11792, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 11794, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 11796, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 11798, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 11800, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 11802, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 11804, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 11806, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FONT, 7451, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 11808, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 11810, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 11812, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 11814, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 11816, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 11818, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 11820, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 11822, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 11824, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 11826, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 11828, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 11830, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 11832, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 11834, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 11836, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 11838, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 11840, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 11842, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 11844, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 11846, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 11848, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 11850, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 11852, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 11854, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 11856, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 11858, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 11860, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 11862, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 11864, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 11866, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 11868, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 11870, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 11872, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 11874, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 11876, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 11878, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 11880, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 11882, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 11884, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 11886, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 11888, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 11890, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 11892, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 11894, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 11896, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 11898, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 11900, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 11902, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 11904, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 11906, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 11908, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 11910, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 11912, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 11914, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 11916, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 11918, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 11920, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 11922, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 11924, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 11926, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 11928, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 11930, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 11932, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 11934, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 11936, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 11938, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 11940, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 11942, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 11944, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 11946, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 11948, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 11950, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 11952, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 11954, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 11956, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 11958, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 11960, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 11962, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 11964, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 11966, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 11968, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 11970, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 11972, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 11974, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 11976, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 11978, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 11980, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 11982, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 11984, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 11986, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 11988, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 11990, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 11992, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 11994, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 11996, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 11998, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 12000, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 12002, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 12004, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 12006, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 12008, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 12010, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 12012, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 12014, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 12016, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 12018, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 12020, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 12022, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 12024, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 12026, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 12028, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 12030, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 12032, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 12034, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 12036, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 12038, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 12040, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 12042, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 12044, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 12046, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 12048, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 12050, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 12052, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 12054, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 12056, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 12058, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 12060, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 12062, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 12064, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 12066, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 12068, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 12070, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 12072, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 12074, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 12076, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 12078, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 12080, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 12082, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 12084, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 12086, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 12088, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 12090, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 12092, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 12094, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 12096, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 12098, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 12100, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 12102, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 12104, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 12106, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 12108, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 12110, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 12112, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 12114, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 12116, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 12118, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 12120, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 12122, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 12124, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 12126, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 12128, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 12130, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 12132, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 12134, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 12136, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 12138, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 12140, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 12142, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 12144, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 12146, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 12148, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 12150, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 12152, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 12154, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 12156, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 12158, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 12160, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 12162, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 12164, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 12166, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 12168, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 12170, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 12172, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 12174, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 12176, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 12178, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 12180, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 12182, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 12184, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 12186, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 12188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 12190, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 12192, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 12194, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 12196, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 12198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 12200, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 12202, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 12204, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 12206, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 12208, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 12210, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 12212, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 12214, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 12216, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 12218, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 12220, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 12222, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 12224, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 12226, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 12228, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 12230, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 12232, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 12234, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 12236, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 12238, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 12240, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 12242, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 12244, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 12246, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 12248, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 12250, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 12252, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 12254, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 12256, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 12258, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 12260, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 12262, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 12264, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 12266, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7458, UINT16_MAX, UINT16_MAX, 12268, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 904, UINT16_MAX, 12270, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12272, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12274, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12276, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12278, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7064, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7068, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7071, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12280, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7076, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12282, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12284, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12286, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12288, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12290, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12292, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12294, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12296, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12298, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12300, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12302, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12304, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12306, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12308, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12310, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12312, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12314, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12316, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12318, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12320, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7093, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12322, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12324, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12326, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12328, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12330, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12332, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 953, UINT16_MAX, 12334, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 954, UINT16_MAX, 12336, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 955, UINT16_MAX, 12338, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 956, UINT16_MAX, 12340, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 957, UINT16_MAX, 12342, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 958, UINT16_MAX, 12344, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 959, UINT16_MAX, 12346, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 960, UINT16_MAX, 12348, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 961, UINT16_MAX, 12350, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 965, UINT16_MAX, 12352, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 966, UINT16_MAX, 12354, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 967, UINT16_MAX, 12356, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 969, UINT16_MAX, 12358, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 970, UINT16_MAX, 12360, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 971, UINT16_MAX, 12362, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 972, UINT16_MAX, 12364, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 973, UINT16_MAX, 12366, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 974, UINT16_MAX, 12368, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 975, UINT16_MAX, 12370, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 976, UINT16_MAX, 12372, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 977, UINT16_MAX, 12374, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 978, UINT16_MAX, 12376, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 979, UINT16_MAX, 12378, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 982, UINT16_MAX, 12380, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 984, UINT16_MAX, 12382, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 985, UINT16_MAX, 12384, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5162, UINT16_MAX, 12386, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1079, UINT16_MAX, 12388, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 935, UINT16_MAX, 12390, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 939, UINT16_MAX, 12392, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1111, UINT16_MAX, 12394, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1042, UINT16_MAX, 12396, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1051, UINT16_MAX, 12398, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 953, UINT16_MAX, 12400, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 954, UINT16_MAX, 12402, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 955, UINT16_MAX, 12404, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 956, UINT16_MAX, 12406, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 957, UINT16_MAX, 12408, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 958, UINT16_MAX, 12410, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 959, UINT16_MAX, 12412, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 960, UINT16_MAX, 12414, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 961, UINT16_MAX, 12416, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 965, UINT16_MAX, 12418, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 966, UINT16_MAX, 12420, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 969, UINT16_MAX, 12422, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 970, UINT16_MAX, 12424, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 972, UINT16_MAX, 12426, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 974, UINT16_MAX, 12428, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 975, UINT16_MAX, 12430, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 976, UINT16_MAX, 12432, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 977, UINT16_MAX, 12434, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 978, UINT16_MAX, 12436, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 979, UINT16_MAX, 12438, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 981, UINT16_MAX, 12440, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 982, UINT16_MAX, 12442, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 1027, UINT16_MAX, 12444, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 935, UINT16_MAX, 12446, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 934, UINT16_MAX, 12448, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 952, UINT16_MAX, 12450, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1040, UINT16_MAX, 12452, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5143, UINT16_MAX, 12454, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1043, UINT16_MAX, 12456, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7459, UINT16_MAX, 7459, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7461, UINT16_MAX, 7461, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7463, UINT16_MAX, 7463, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7465, UINT16_MAX, 7465, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7467, UINT16_MAX, 7467, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7469, UINT16_MAX, 7469, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7471, UINT16_MAX, 7471, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7473, UINT16_MAX, 7473, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7475, UINT16_MAX, 7475, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7477, UINT16_MAX, 7477, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7479, UINT16_MAX, 7479, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7481, UINT16_MAX, 7481, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7483, UINT16_MAX, 7483, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7485, UINT16_MAX, 7485, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7487, UINT16_MAX, 7487, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7489, UINT16_MAX, 7489, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7491, UINT16_MAX, 7491, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7493, UINT16_MAX, 7493, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7495, UINT16_MAX, 7495, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7497, UINT16_MAX, 7497, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7499, UINT16_MAX, 7499, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7501, UINT16_MAX, 7501, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7503, UINT16_MAX, 7503, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7505, UINT16_MAX, 7505, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7507, UINT16_MAX, 7507, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7509, UINT16_MAX, 7509, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7511, UINT16_MAX, 7511, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7513, UINT16_MAX, 7513, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7515, UINT16_MAX, 7515, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7517, UINT16_MAX, 7517, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7519, UINT16_MAX, 7519, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7521, UINT16_MAX, 7521, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7523, UINT16_MAX, 7523, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7525, UINT16_MAX, 7525, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12458, UINT16_MAX, 12458, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12460, UINT16_MAX, 12460, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12462, UINT16_MAX, 12462, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12464, UINT16_MAX, 12464, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12466, UINT16_MAX, 12466, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12468, UINT16_MAX, 12468, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12470, UINT16_MAX, 12470, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12472, UINT16_MAX, 12472, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12474, UINT16_MAX, 12474, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12476, UINT16_MAX, 12476, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12478, UINT16_MAX, 12478, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12480, UINT16_MAX, 12480, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12482, UINT16_MAX, 12482, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12484, UINT16_MAX, 12484, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12486, UINT16_MAX, 12486, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12488, UINT16_MAX, 12488, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12490, UINT16_MAX, 12490, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12492, UINT16_MAX, 12492, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12494, UINT16_MAX, 12494, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12496, UINT16_MAX, 12496, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12498, UINT16_MAX, 12498, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12500, UINT16_MAX, 12500, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12502, UINT16_MAX, 12502, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12504, UINT16_MAX, 12504, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12506, UINT16_MAX, 12506, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12508, UINT16_MAX, 12508, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12510, UINT16_MAX, 12510, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12512, UINT16_MAX, 12512, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12514, UINT16_MAX, 12514, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12516, UINT16_MAX, 12516, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12518, UINT16_MAX, 12518, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12520, UINT16_MAX, 12520, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12522, UINT16_MAX, 12522, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12524, UINT16_MAX, 12524, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 7527, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 5874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 7528, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 7529, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23914, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23916, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23918, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23920, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23922, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23924, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23926, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23928, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23930, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23932, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23934, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40320, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40323, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40329, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40371, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40377, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40383, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40389, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40395, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40398, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 24017, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 24019, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1491, UINT16_MAX, UINT16_MAX, 12526, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1493, UINT16_MAX, UINT16_MAX, 12528, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2813, UINT16_MAX, UINT16_MAX, 12530, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1494, UINT16_MAX, UINT16_MAX, 12532, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1495, UINT16_MAX, UINT16_MAX, 12534, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2838, UINT16_MAX, UINT16_MAX, 12536, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1497, UINT16_MAX, UINT16_MAX, 12538, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1498, UINT16_MAX, UINT16_MAX, 12540, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1499, UINT16_MAX, UINT16_MAX, 12542, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1500, UINT16_MAX, UINT16_MAX, 12544, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1501, UINT16_MAX, UINT16_MAX, 12546, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1502, UINT16_MAX, UINT16_MAX, 12548, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1503, UINT16_MAX, UINT16_MAX, 12550, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1504, UINT16_MAX, UINT16_MAX, 12552, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1505, UINT16_MAX, UINT16_MAX, 12554, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1507, UINT16_MAX, UINT16_MAX, 12556, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2827, UINT16_MAX, UINT16_MAX, 12558, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1508, UINT16_MAX, UINT16_MAX, 12560, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3320, UINT16_MAX, UINT16_MAX, 12562, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1509, UINT16_MAX, UINT16_MAX, 12564, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1510, UINT16_MAX, UINT16_MAX, 12566, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2910, UINT16_MAX, UINT16_MAX, 12568, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1511, UINT16_MAX, UINT16_MAX, 12570, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2928, UINT16_MAX, UINT16_MAX, 12572, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3327, UINT16_MAX, UINT16_MAX, 12574, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2835, UINT16_MAX, UINT16_MAX, 12576, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24021, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24023, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24025, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 40411, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12578, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12580, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12582, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12584, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12586, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12588, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12590, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12592, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12594, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12596, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12598, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12600, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12602, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12604, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12606, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12608, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12610, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12612, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12614, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12616, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12618, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12620, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12622, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12624, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12626, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12628, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 24032, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 24034, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 24036, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12630, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12632, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12634, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12638, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12640, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12642, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12644, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12646, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12648, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12650, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12652, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12654, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12656, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12658, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12660, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12662, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12664, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12666, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12668, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12670, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12672, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12674, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12676, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12678, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12680, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24038, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24040, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24042, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 4331, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7660, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7661, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7664, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3903, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7665, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 5513, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 4244, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 4245, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 4227, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40459, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40465, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40474, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40477, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40480, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 7718, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 7719, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTEND, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7720, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7721, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7723, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7725, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7726, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7727, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7728, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7729, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7730, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7731, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7732, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7734, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7735, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7736, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7737, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7739, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7740, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7741, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7743, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7744, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7745, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7746, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7747, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7749, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7750, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7751, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7752, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7753, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7754, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7755, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7756, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7757, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7758, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7759, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7760, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7764, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7765, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7766, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7767, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7769, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7770, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7771, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7772, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7773, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7774, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7775, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7776, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7777, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7778, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7779, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7781, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7782, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7783, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7784, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7785, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7786, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7787, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7788, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7789, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7790, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7791, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7792, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7806, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7808, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7812, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7816, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7822, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7824, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7825, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7826, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7827, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7828, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7829, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7830, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7831, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7833, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7834, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7836, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7837, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7838, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7839, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7840, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7842, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7843, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7845, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7846, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7847, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7849, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7850, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7864, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7866, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7867, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7869, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7876, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7879, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7882, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7884, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7885, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7887, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7888, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7892, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7893, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7894, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7896, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7897, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7899, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7900, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7901, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7902, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7903, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7904, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7905, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7906, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7908, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7909, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7911, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7912, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7913, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7914, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7915, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7916, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7917, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7918, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7919, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7920, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7921, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7922, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7923, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7924, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7925, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7926, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7928, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7929, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7930, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7931, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7932, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7934, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7935, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7936, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7937, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7938, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7939, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7940, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7941, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7943, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7944, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7945, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7946, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7948, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7949, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7950, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7951, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7952, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7953, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7955, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7957, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7959, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7960, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7962, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7963, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7964, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7965, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7966, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7967, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7968, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7969, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7970, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7972, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7973, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7974, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7976, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7977, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7979, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7980, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7981, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7983, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7985, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7986, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7987, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7988, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7989, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7990, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7991, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7992, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7993, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7995, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7996, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7998, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7999, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8001, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8002, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8003, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8005, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8006, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8007, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8009, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8011, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8012, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8013, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8014, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8015, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8016, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8017, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8018, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8019, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8020, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8021, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8022, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8024, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8025, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8027, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8029, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8032, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8034, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8036, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8037, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8038, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8040, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8042, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8044, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8046, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8047, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8048, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8049, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8050, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8051, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8053, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8054, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8055, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8057, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8059, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8061, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8062, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8063, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8064, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8065, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8069, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8070, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8071, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8073, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8074, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8075, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8076, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8078, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8079, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8080, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8082, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8083, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8085, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8086, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8088, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8089, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8090, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8091, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8093, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8095, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8096, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8098, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8099, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8101, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8102, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8103, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8105, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8107, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8110, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8111, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8113, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8114, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8115, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8116, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8117, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8118, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8119, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8121, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8123, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8125, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8127, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8128, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8130, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8131, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8132, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8133, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8134, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8135, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8136, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8137, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8138, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8140, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8141, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8142, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8143, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8144, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8145, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8146, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8148, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8149, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8150, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8152, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8154, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8156, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8157, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8158, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8159, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8160, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8162, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8163, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8165, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8166, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8167, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8172, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8173, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8174, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8175, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8176, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8178, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8180, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8182, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8184, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8185, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8186, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8187, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8190, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8191, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8192, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8193, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8194, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8196, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8198, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8199, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8200, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8201, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8203, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8204, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8205, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8206, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8207, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8209, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8211, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8212, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8213, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8214, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8216, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8217, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8219, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8221, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8222, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8223, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8224, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8226, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8227, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8229, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8230, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8231, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8232, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8233, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8235, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8236, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8237, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8238, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8240, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8241, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8242, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8243, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8244, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8246, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8248, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8249, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8250, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8251, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8253, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8254, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8256, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8257, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8259, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8260, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8261, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8262, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8263, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8264, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8265, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8266, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8268, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8269, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8270, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8271, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8272, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8273, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8275, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8276, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8278, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8280, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8282, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8283, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8284, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8286, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER, UTF8PROC_INDIC_CONJUNCT_BREAK_NONE}, +}; + +static const utf8proc_uint16_t utf8proc_combinations[] = { + 0, 46, 192, 193, 194, 195, 196, 197, 0, + 256, 258, 260, 550, 461, 0, 0, 512, + 514, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7680, 7840, 0, 0, 0, 0, 0, 7842, +1, 11, + 262, 264, 0, 0, 0, 199, 0, 0, + 0, 266, 268, +0, 46, 200, 201, 202, 7868, 203, + 0, 552, 274, 276, 280, 278, 282, 0, + 0, 516, 518, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7864, 0, 7704, 7706, 0, + 0, 7866, +0, 46, 204, 205, 206, 296, 207, 0, + 0, 298, 300, 302, 304, 463, 0, 0, + 520, 522, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7882, 0, 0, 7724, 0, 0, + 7880, +0, 42, 504, 323, 0, 209, 0, 0, 325, + 0, 0, 0, 7748, 327, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7750, 7752, 7754, +0, 46, 210, 211, 212, 213, + 214, 0, 0, 332, 334, 490, 558, 465, + 336, 416, 524, 526, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7884, 0, 0, 0, + 0, 0, 7886, +0, 46, 217, 218, 219, 360, 220, + 366, 0, 362, 364, 370, 0, 467, 368, + 431, 532, 534, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7908, 0, 7798, 7796, 0, + 7794, 7910, +0, 46, 7922, 221, 374, 7928, 376, 0, + 0, 562, 0, 0, 7822, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7924, 0, 0, 0, 0, 0, + 7926, +0, 46, 224, 225, 226, 227, 228, 229, 0, + 257, 259, 261, 551, 462, 0, 0, 513, + 515, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7681, 7841, 0, 0, 0, 0, 0, 7843, +1, 11, + 263, 265, 0, 0, 0, 231, 0, 0, + 0, 267, 269, +0, 46, 232, 233, 234, 7869, 235, + 0, 553, 275, 277, 281, 279, 283, 0, + 0, 517, 519, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7865, 0, 7705, 7707, 0, + 0, 7867, +0, 46, 236, 237, 238, 297, 239, 0, + 0, 299, 301, 303, 0, 464, 0, 0, + 521, 523, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7883, 0, 0, 7725, 0, 0, + 7881, +0, 42, 505, 324, 0, 241, 0, 0, 326, + 0, 0, 0, 7749, 328, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7751, 7753, 7755, +0, 46, 242, 243, 244, 245, + 246, 0, 0, 333, 335, 491, 559, 466, + 337, 417, 525, 527, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7885, 0, 0, 0, + 0, 0, 7887, +0, 46, 249, 250, 251, 361, 252, + 367, 0, 363, 365, 371, 0, 468, 369, + 432, 533, 535, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7909, 0, 7799, 7797, 0, + 7795, 7911, +0, 46, 7923, 253, 375, 7929, 255, 7833, + 0, 563, 0, 0, 7823, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7925, 0, 0, 0, 0, 0, + 7927, +6, 42, 7696, 0, 0, 0, 7690, 270, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7692, 7694, 7698, +6, 42, 7697, 0, + 0, 0, 7691, 271, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7693, 7695, 7699, +1, 11, 500, 284, 0, 0, 0, + 290, 7712, 286, 0, 288, 486, +1, 11, 501, 285, + 0, 0, 0, 291, 7713, 287, 0, 289, + 487, +2, 44, 292, 0, 7718, 0, 7720, 0, 0, + 0, 7714, 542, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7716, + 0, 0, 0, 7722, +2, 44, 293, 0, 7719, 0, + 7721, 0, 0, 0, 7715, 543, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7717, 7830, 0, 0, 7723, +2, 2, 308, +2, 11, + 309, 0, 0, 0, 0, 0, 0, 0, + 0, 496, +1, 41, 7728, 0, 0, 0, 0, 310, + 0, 0, 0, 0, 488, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7730, 7732, +1, 41, 7729, 0, 0, 0, 0, + 311, 0, 0, 0, 0, 489, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7731, 7733, +1, 42, 313, 0, 0, 0, + 0, 315, 0, 0, 0, 0, 317, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7734, 7738, 7740, +1, 42, 314, 0, + 0, 0, 0, 316, 0, 0, 0, 0, + 318, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7735, 7739, 7741, +1, 41, + 340, 0, 0, 0, 0, 342, 0, 0, + 0, 7768, 344, 0, 0, 528, 530, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7770, + 7774, +1, 41, 341, 0, 0, 0, 0, 343, 0, + 0, 0, 7769, 345, 0, 0, 529, 531, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7771, 7775, +1, 40, 346, 348, 0, 0, 0, 350, + 0, 0, 0, 7776, 352, 0, 0, 0, + 0, 536, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7778, +1, 40, 347, 349, 0, 0, 0, 351, + 0, 0, 0, 7777, 353, 0, 0, 0, + 0, 537, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7779, +6, 42, 354, 0, 0, 0, 7786, 356, + 0, 0, 0, 0, 538, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7788, 7790, 7792, +4, 42, 7831, + 0, 355, 0, 0, 0, 7787, 357, 0, + 0, 0, 0, 539, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7789, 7791, 7793, +0, 40, 7808, 7810, + 372, 0, 7812, 0, 0, 0, 0, 0, + 7814, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7816, +0, 40, 7809, + 7811, 373, 0, 7813, 7832, 0, 0, 0, + 0, 7815, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7817, +1, 41, + 377, 7824, 0, 0, 0, 0, 0, 0, + 0, 379, 381, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7826, + 7828, +1, 41, 378, 7825, 0, 0, 0, 0, 0, + 0, 0, 380, 382, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7827, 7829, +0, 11, 475, 471, 0, 0, 0, 0, + 0, 469, 0, 0, 0, 473, +0, 11, 476, 472, + 0, 0, 0, 0, 0, 470, 0, 0, + 0, 474, +7, 7, 478, +7, 7, 479, +7, 7, 480, +7, 7, 481, +1, 7, 508, 0, + 0, 0, 0, 0, 482, +1, 7, 509, 0, 0, + 0, 0, 0, 483, +7, 7, 492, +7, 7, 493, +11, 11, 494, +11, 11, 495, +1, 1, + 506, +1, 1, 507, +1, 1, 510, +1, 1, 511, +7, 7, 554, +7, 7, 555, +1, 7, 7756, 0, + 0, 7758, 0, 0, 556, +1, 7, 7757, 0, 0, + 7759, 0, 0, 557, +7, 7, 560, +7, 7, 561, +0, 49, 8173, 901, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 8129, +0, 50, + 8122, 902, 0, 0, 0, 0, 0, 8121, + 8120, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7944, + 7945, 0, 8124, +0, 48, 8136, 904, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7960, 7961, +0, 50, 8138, 905, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7976, 7977, 0, 8140, +0, 48, 8154, + 906, 0, 0, 938, 0, 0, 8153, 8152, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7992, 7993, +0, 48, + 8184, 908, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 8008, + 8009, +0, 48, 8170, 910, 0, 0, 939, 0, 0, + 8169, 8168, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8025, +0, 50, 8186, 911, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8040, 8041, 0, 8188, +0, 49, 8146, 912, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 8151, +0, 50, 8048, + 940, 0, 0, 0, 0, 0, 8113, 8112, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7936, 7937, + 8118, 8115, +0, 48, 8050, 941, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7952, 7953, +0, 50, 8052, 942, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7968, 7969, 8134, 8131, +0, 49, 8054, 943, + 0, 0, 970, 0, 0, 8145, 8144, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7984, 7985, 8150, +0, 49, + 8162, 944, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8167, +0, 49, 8058, 973, 0, 0, 971, 0, + 0, 8161, 8160, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8016, 8017, 8166, +0, 48, 8056, 972, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8000, 8001, +0, 50, 8060, 974, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8032, 8033, 8182, 8179, +1, 4, + 979, 0, 0, 980, +0, 8, 1024, 0, 0, 0, + 1025, 0, 0, 0, 1238, +1, 1, 1027, +4, 4, 1031, +1, 1, 1036, +0, 8, + 1037, 0, 0, 0, 1252, 0, 0, 1250, + 1049, +4, 12, 1264, 0, 0, 1262, 1038, 0, 0, + 0, 1266, +0, 8, 1117, 0, 0, 0, 1253, 0, + 0, 1251, 1081, +0, 8, 1104, 0, 0, 0, 1105, + 0, 0, 0, 1239, +1, 1, 1107, +4, 4, 1111, +1, 1, 1116, +4, 12, 1265, + 0, 0, 1263, 1118, 0, 0, 0, 1267, +14, 14, + 1142, +14, 14, 1143, +4, 8, 1244, 0, 0, 0, 1217, +4, 8, 1245, + 0, 0, 0, 1218, +4, 8, 1234, 0, 0, 0, + 1232, +4, 8, 1235, 0, 0, 0, 1233, +4, 4, 1242, +4, 4, 1243, +4, 4, + 1246, +4, 4, 1247, +4, 4, 1254, +4, 4, 1255, +4, 4, 1258, +4, 4, 1259, +4, 4, 1260, +4, 4, 1261, +4, 4, + 1268, +4, 4, 1269, +4, 4, 1272, +4, 4, 1273, +17, 19, 1570, 1571, 1573, +18, 18, 1572, +18, 18, + 1574, +18, 18, 1728, +18, 18, 1730, +18, 18, 1747, +20, 20, 2345, +20, 20, 2353, +20, 20, 2356, +21, 22, 2507, + 2508, +23, 25, 2888, 2891, 2892, +26, 26, 2964, +26, 27, 3020, 3018, +27, 27, 3019, +28, 28, + 3144, +29, 29, 3264, +29, 31, 3271, 3272, 3274, +29, 29, 3275, +32, 33, 3402, 3404, +32, 32, + 3403, +34, 36, 3546, 3548, 3550, +34, 34, 3549, +37, 37, 4134, +38, 38, 6918, +38, 38, 6920, +38, 38, + 6922, +38, 38, 6924, +38, 38, 6926, +38, 38, 6930, +38, 38, 6971, +38, 38, 6973, +38, 38, 6976, +38, 38, 6977, +38, 38, + 6979, +10, 41, 7682, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7684, + 7686, +10, 41, 7683, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7685, + 7687, +1, 1, 7688, +1, 1, 7689, +0, 1, 7700, 7702, +0, 1, 7701, 7703, +8, 8, 7708, +8, 8, + 7709, +10, 10, 7710, +10, 10, 7711, +1, 1, 7726, +1, 1, 7727, +7, 7, 7736, +7, 7, 7737, +1, 40, 7742, + 0, 0, 0, 0, 0, 0, 0, 0, + 7744, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7746, +1, 40, 7743, + 0, 0, 0, 0, 0, 0, 0, 0, + 7745, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7747, +0, 1, 7760, + 7762, +0, 1, 7761, 7763, +1, 10, 7764, 0, 0, 0, 0, + 0, 0, 0, 0, 7766, +1, 10, 7765, 0, 0, + 0, 0, 0, 0, 0, 0, 7767, +7, 7, 7772, +7, 7, + 7773, +10, 10, 7780, +10, 10, 7781, +10, 10, 7782, +10, 10, 7783, +10, 10, 7784, +10, 10, 7785, +1, 1, 7800, +1, 1, + 7801, +4, 4, 7802, +4, 4, 7803, +3, 40, 7804, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7806, +3, 40, 7805, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7807, +4, 10, 7820, + 0, 0, 0, 0, 0, 7818, +4, 10, 7821, 0, + 0, 0, 0, 0, 7819, +10, 10, 7835, +0, 46, 7846, 7844, + 0, 7850, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7848, +0, 46, 7847, 7845, 0, + 7851, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7849, +2, 8, 7852, 0, 0, 0, + 0, 0, 7862, +2, 8, 7853, 0, 0, 0, 0, + 0, 7863, +0, 46, 7856, 7854, 0, 7860, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7858, +0, 46, 7857, 7855, 0, 7861, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7859, +0, 46, + 7872, 7870, 0, 7876, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7874, +0, 46, 7873, + 7871, 0, 7877, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7875, +2, 2, 7878, +2, 2, 7879, +0, 46, + 7890, 7888, 0, 7894, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7892, +0, 46, 7891, + 7889, 0, 7895, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7893, +2, 2, 7896, +2, 2, 7897, +0, 46, + 7900, 7898, 0, 7904, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7906, 0, 0, 0, 0, 0, 7902, +0, 46, 7901, + 7899, 0, 7905, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7907, + 0, 0, 0, 0, 0, 7903, +0, 46, 7914, 7912, + 0, 7918, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7920, 0, + 0, 0, 0, 0, 7916, +0, 46, 7915, 7913, 0, + 7919, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7921, 0, 0, + 0, 0, 0, 7917, +0, 50, 7938, 7940, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7942, 8064, +0, 50, 7939, + 7941, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7943, 8065, +0, 50, 7946, 7948, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7950, 8072, +0, 50, 7947, 7949, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7951, 8073, +0, 1, + 7954, 7956, +0, 1, 7955, 7957, +0, 1, 7962, 7964, +0, 1, 7963, 7965, +0, 50, + 7970, 7972, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7974, 8080, +0, 50, 7971, 7973, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7975, 8081, +0, 50, 7978, 7980, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7982, + 8088, +0, 50, 7979, 7981, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7983, 8089, +0, 49, 7986, 7988, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7990, +0, 49, 7987, 7989, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7991, +0, 49, + 7994, 7996, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7998, +0, 49, 7995, 7997, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7999, +0, 1, 8002, 8004, +0, 1, 8003, 8005, +0, 1, + 8010, 8012, +0, 1, 8011, 8013, +0, 49, 8018, 8020, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8022, +0, 49, 8019, 8021, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 8023, +0, 49, + 8027, 8029, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8031, +0, 50, 8034, 8036, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8038, 8096, +0, 50, 8035, 8037, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 8039, 8097, +0, 50, + 8042, 8044, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8046, 8104, +0, 50, 8043, 8045, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8047, 8105, +50, 50, 8066, +50, 50, 8067, +50, 50, + 8068, +50, 50, 8069, +50, 50, 8070, +50, 50, 8071, +50, 50, 8074, +50, 50, 8075, +50, 50, 8076, +50, 50, 8077, +50, 50, + 8078, +50, 50, 8079, +50, 50, 8082, +50, 50, 8083, +50, 50, 8084, +50, 50, 8085, +50, 50, 8086, +50, 50, 8087, +50, 50, + 8090, +50, 50, 8091, +50, 50, 8092, +50, 50, 8093, +50, 50, 8094, +50, 50, 8095, +50, 50, 8098, +50, 50, 8099, +50, 50, + 8100, +50, 50, 8101, +50, 50, 8102, +50, 50, 8103, +50, 50, 8106, +50, 50, 8107, +50, 50, 8108, +50, 50, 8109, +50, 50, + 8110, +50, 50, 8111, +50, 50, 8114, +50, 50, 8116, +50, 50, 8119, +50, 50, 8130, +50, 50, 8132, +50, 50, 8135, +0, 49, + 8141, 8142, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8143, +0, 49, 8157, 8158, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8159, +47, 48, 8164, 8165, +48, 48, 8172, +50, 50, 8178, +50, 50, + 8180, +50, 50, 8183, +51, 51, 8602, +51, 51, 8603, +51, 51, 8622, +51, 51, 8653, +51, 51, 8654, +51, 51, 8655, +51, 51, + 8708, +51, 51, 8713, +51, 51, 8716, +51, 51, 8740, +51, 51, 8742, +51, 51, 8769, +51, 51, 8772, +51, 51, 8775, +51, 51, + 8777, +51, 51, 8800, +51, 51, 8802, +51, 51, 8813, +51, 51, 8814, +51, 51, 8815, +51, 51, 8816, +51, 51, 8817, +51, 51, + 8820, +51, 51, 8821, +51, 51, 8824, +51, 51, 8825, +51, 51, 8832, +51, 51, 8833, +51, 51, 8836, +51, 51, 8837, +51, 51, + 8840, +51, 51, 8841, +51, 51, 8876, +51, 51, 8877, +51, 51, 8878, +51, 51, 8879, +51, 51, 8928, +51, 51, 8929, +51, 51, + 8930, +51, 51, 8931, +51, 51, 8938, +51, 51, 8939, +51, 51, 8940, +51, 51, 8941, +51, 51, 10972, +52, 52, 12364, +52, 52, + 12366, +52, 52, 12368, +52, 52, 12370, +52, 52, 12372, +52, 52, 12374, +52, 52, 12376, +52, 52, 12378, +52, 52, 12380, +52, 52, + 12382, +52, 52, 12384, +52, 52, 12386, +52, 52, 12389, +52, 52, 12391, +52, 52, 12393, +52, 53, 12400, 12401, +52, 53, + 12403, 12404, +52, 53, 12406, 12407, +52, 53, 12409, 12410, +52, 53, 12412, 12413, +52, 52, + 12436, +52, 52, 12446, +52, 52, 12460, +52, 52, 12462, +52, 52, 12464, +52, 52, 12466, +52, 52, 12468, +52, 52, 12470, +52, 52, + 12472, +52, 52, 12474, +52, 52, 12476, +52, 52, 12478, +52, 52, 12480, +52, 52, 12482, +52, 52, 12485, +52, 52, 12487, +52, 52, + 12489, +52, 53, 12496, 12497, +52, 53, 12499, 12500, +52, 53, 12502, 12503, +52, 53, 12505, + 12506, +52, 53, 12508, 12509, +52, 52, 12532, +52, 52, 12535, +52, 52, 12536, +52, 52, 12537, +52, 52, 12538, +52, 52, + 12542, +54, 55, 1, 4250, +54, 55, 1, 4252, +54, 55, 1, 4267, +56, 57, 1, 4398, +56, 57, 1, 4399, +58, 61, 1, 4939, 1, 4940, +62, 67, + 1, 5307, 1, 5308, 1, 5310, +68, 69, 1, 5562, +68, 69, 1, 5563, +70, 71, 1, 6456, +72, 73, 1, 53598, +72, 73, 1, 53599, +74, 83, + 1, 53600, 1, 53601, 1, 53602, 1, 53603, 1, 53604, +72, 73, 1, 53691, +72, 73, 1, 53692, +74, 77, 1, 53693, + 1, 53695, +74, 77, 1, 53694, 1, 53696, +}; + diff --git a/src/utility/xs_Float.h b/src/common/thirdparty/xs_Float.h similarity index 100% rename from src/utility/xs_Float.h rename to src/common/thirdparty/xs_Float.h diff --git a/src/common/utility/TRS.h b/src/common/utility/TRS.h new file mode 100644 index 00000000000..c39a870ad34 --- /dev/null +++ b/src/common/utility/TRS.h @@ -0,0 +1,56 @@ +/* +** TRS +** +**--------------------------------------------------------------------------- +** Copyright 2022 Andrew Clarke +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#pragma once +#include "vectors.h" + +class TRS +{ +public: + FVector3 translation; + FVector4 rotation; + FVector3 scaling; + + TRS() + { + translation = FVector3(0,0,0); + rotation = FVector4(0,0,0,1); + scaling = FVector3(0,0,0); + } + + bool Equals(TRS& compare) + { + return compare.translation == this->translation && compare.rotation == this->rotation && compare.scaling == this->scaling; + } +}; + diff --git a/src/common/utility/basics.h b/src/common/utility/basics.h new file mode 100644 index 00000000000..0dbb47c67b2 --- /dev/null +++ b/src/common/utility/basics.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include + +#define MAXWIDTH 12000 +#define MAXHEIGHT 5000 + +// +// fixed point, 32bit as 16.16. +// +#define FRACBITS 16 +#define FRACUNIT (1< +#include +#include + +#ifndef _WIN32 +#include +#include +#endif + +/* +progdir will hold the path up to the game directory, including the slash + + f:\quake\ + /raid/quake/ + +gamedir will hold progdir + the game directory (id1, id2, etc) + + */ + +FString progdir; + +//========================================================================== +// +// IsSeperator +// +// Returns true if the character is a path seperator. +// +//========================================================================== + +static inline bool IsSeperator (int c, bool forcebackslash = false) +{ + if (c == '/') + return true; +#ifdef _WIN32 + if (c == '\\') + return true; +#else + if (forcebackslash && c == '\\') + return true; +#endif + return false; +} + +//========================================================================== +// +// FixPathSeperator +// +// Convert backslashes to forward slashes. +// +//========================================================================== + +void FixPathSeperator (char *path) +{ + while (*path) + { + if (*path == '\\') + *path = '/'; + path++; + } +} + +//========================================================================== +// +// copystring +// +// Replacement for strdup that uses new instead of malloc. +// +//========================================================================== + +char *copystring (const char *s) +{ + char *b; + if (s) + { + size_t len = strlen (s) + 1; + b = new char[len]; + memcpy (b, s, len); + } + else + { + b = new char[1]; + b[0] = '\0'; + } + return b; +} + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +//========================================================================== +// +// FileExists +// +// Returns true if the given path exists and is a readable file. +// +//========================================================================== + +bool FileExists (const char *filename) +{ + bool isdir; + bool res = DirEntryExists(filename, &isdir); + return res && !isdir; +} + +//========================================================================== +// +// FileReadable +// +// Returns true if the file can be read. +// +//========================================================================== + +bool FileReadable(const char *filename) +{ +#ifndef _WIN32 + return access (filename, R_OK) == 0; +#else + auto wstr = WideString(filename); + return _waccess (wstr.c_str(), 4) == 0; +#endif +} + +//========================================================================== +// +// DirExists +// +// Returns true if the given path exists and is a directory. +// +//========================================================================== + +bool DirExists(const char *filename) +{ + bool isdir; + bool res = DirEntryExists(filename, &isdir); + return res && isdir; +} + +//========================================================================== +// +// DirEntryExists +// +// Returns true if the given path exists, be it a directory or a file. +// +//========================================================================== + +bool DirEntryExists(const char *pathname, bool *isdir) +{ + if (isdir) *isdir = false; + if (pathname == NULL || *pathname == 0) + return false; + +#ifndef _WIN32 + struct stat info; + bool res = stat(pathname, &info) == 0; +#else + // Windows must use the wide version of stat to preserve non-standard paths. + auto wstr = WideString(pathname); + struct _stat64 info; + bool res = _wstat64(wstr.c_str(), &info) == 0; +#endif + if (isdir) *isdir = !!(info.st_mode & S_IFDIR); + return res; +} + +//========================================================================== +// +// DirEntryExists +// +// Returns true if the given path exists, be it a directory or a file. +// +//========================================================================== + +bool GetFileInfo(const char* pathname, size_t *size, time_t *time) +{ + if (pathname == NULL || *pathname == 0) + return false; + +#ifndef _WIN32 + struct stat info; + bool res = stat(pathname, &info) == 0; +#else + // Windows must use the wide version of stat to preserve non-standard paths. + auto wstr = WideString(pathname); + struct _stat64 info; + bool res = _wstat64(wstr.c_str(), &info) == 0; +#endif + if (!res || (info.st_mode & S_IFDIR)) return false; + if (size) *size = (size_t)info.st_size; + if (time) *time = info.st_mtime; + return res; +} + +//========================================================================== +// +// DefaultExtension -- FString version +// +// Appends the extension to a pathname if it does not already have one. +// +//========================================================================== + +void DefaultExtension (FString &path, const char *extension, bool forcebackslash) +{ + const char *src = &path[int(path.Len())-1]; + + while (src != &path[0] && !IsSeperator(*src, forcebackslash)) + { + if (*src == '.') + return; // it has an extension + src--; + } + + path += extension; +} + + +//========================================================================== +// +// ExtractFilePath +// +// Returns the directory part of a pathname. +// +// FIXME: should include the slash, otherwise +// backing to an empty path will be wrong when appending a slash +// +//========================================================================== + +FString ExtractFilePath (const char *path, bool forcebackslash) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && !IsSeperator(*(src-1), forcebackslash)) + src--; + + return FString(path, src - path); +} + +//========================================================================== +// +// ExtractFileBase +// +// Returns the file part of a pathname, optionally including the extension. +// +//========================================================================== + +FString ExtractFileBase (const char *path, bool include_extension, bool forcebackslash) +{ + const char *src, *dot; + + src = path + strlen(path) - 1; + + if (src >= path) + { + // back up until a / or the start + while (src != path && !IsSeperator(*(src-1), forcebackslash)) + src--; + + // Check for files with drive specification but no path +#if defined(_WIN32) + if (src == path && src[0] != 0) + { + if (src[1] == ':') + src += 2; + } +#endif + + if (!include_extension && (dot = strrchr(src, '.'))) + { + return FString(src, dot - src); + } + else + { + return FString(src); + } + } + return FString(); +} + +//========================================================================== +// +// SplitPath +// +// splits a path into directory, base name and extension +// +//========================================================================== + + void SplitPath(const char* path, FString& directory, FString& base, FString& ext, bool forcebackslash) +{ + directory = ExtractFilePath(path, forcebackslash); + base = ExtractFileBase(path, forcebackslash); + auto dot = base.LastIndexOf('.'); + if (dot > -1) + { + ext = base.Mid(dot + 1); + base.Truncate(dot); + } + else + ext = ""; +} + + +//========================================================================== +// +// StripExtension +// +// Returns the path with the extension removed +// +//========================================================================== + +FString StripExtension(const char* path) +{ + const char* src; + if (*path == 0) return ""; + + src = path + strlen(path) - 1; + + // + // back up until a . and abort on a '/' + // + while (src != path && !IsSeperator(*(src - 1))) + { + if (*src == '.') return FString(path, src - path); + src--; + } + + return path; + +} + +//========================================================================== +// +// IsNum +// +// [RH] Returns true if the specified string is a valid decimal number +// +//========================================================================== + +bool IsNum (const char *str) +{ + while (*str) + { + if (((*str < '0') || (*str > '9')) && (*str != '-')) + { + return false; + } + str++; + } + return true; +} + +//========================================================================== +// +// CheckWildcards +// +// [RH] Checks if text matches the wildcard pattern using ? or * +// +//========================================================================== + +bool CheckWildcards (const char *pattern, const char *text) +{ + if (pattern == NULL || text == NULL) + return true; + + while (*pattern) + { + if (*pattern == '*') + { + char stop = tolower (*++pattern); + while (*text && tolower(*text) != stop) + { + text++; + } + if (*text && tolower(*text) == stop) + { + if (CheckWildcards (pattern, text++)) + { + return true; + } + pattern--; + } + } + else if (*pattern == '?' || tolower(*pattern) == tolower(*text)) + { + pattern++; + text++; + } + else + { + return false; + } + } + return (*pattern | *text) == 0; +} + +//========================================================================== +// +// FormatGUID +// +// [RH] Print a GUID to a text buffer using the standard format. +// +//========================================================================== + +void FormatGUID (char *buffer, size_t buffsize, const GUID &guid) +{ + snprintf (buffer, buffsize, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + (uint32_t)guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], + guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], + guid.Data4[6], guid.Data4[7]); +} + +//========================================================================== +// +// myasctime +// +// [RH] Returns the current local time as ASCII, even if it's too early +// +//========================================================================== + +const char *myasctime () +{ + static char readabletime[50]; + time_t clock; + struct tm *lt; + + time (&clock); + lt = localtime (&clock); + if (lt != NULL) + { + strftime(readabletime, 50, "%F %T", lt); + return readabletime; + } + else + { + return "Unknown\n"; + } +} + +//========================================================================== +// +// CreatePath +// +// Creates a directory including all levels necessary +// +//========================================================================== +#ifdef _WIN32 +void DoCreatePath(const char *fn) +{ + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + _splitpath_s(fn, drive, sizeof drive, dir, sizeof dir, nullptr, 0, nullptr, 0); + + if ('\0' == *dir) + { + // Root/current/parent directory always exists + return; + } + + char path[_MAX_PATH]; + _makepath_s(path, sizeof path, drive, dir, nullptr, nullptr); + + if ('\0' == *path) + { + // No need to process empty relative path + return; + } + + // Remove trailing path separator(s) + for (size_t i = strlen(path); 0 != i; --i) + { + char& lastchar = path[i - 1]; + + if ('/' == lastchar || '\\' == lastchar) + { + lastchar = '\0'; + } + else + { + break; + } + } + + // Create all directories for given path + if ('\0' != *path) + { + DoCreatePath(path); +#ifdef _WIN32 + auto wpath = WideString(path); + _wmkdir(wpath.c_str()); +#else + _mkdir(path); +#endif + } +} + +void CreatePath(const char *fn) +{ + char c = fn[strlen(fn)-1]; + + if (c != '\\' && c != '/') + { + FString name(fn); + name += '/'; + DoCreatePath(name.GetChars()); + } + else + { + DoCreatePath(fn); + } +} +#else +void CreatePath(const char *fn) +{ + char *copy, *p; + + if (fn[0] == '/' && fn[1] == '\0') + { + return; + } + p = copy = strdup(fn); + do + { + p = strchr(p + 1, '/'); + if (p != NULL) + { + *p = '\0'; + } + if (!DirEntryExists(copy) && mkdir(copy, 0755) == -1) + { + // failed + free(copy); + return; + } + if (p != NULL) + { + *p = '/'; + } + } while (p); + free(copy); +} +#endif + +void RemoveFile(const char* file) +{ +#ifndef _WIN32 + remove(file); +#else + auto wpath = WideString(file); + _wremove(wpath.c_str()); +#endif +} + +int RemoveDir(const char* file) +{ +#ifndef _WIN32 + return rmdir(file); +#else + auto wpath = WideString(file); + return _wrmdir(wpath.c_str()); +#endif +} + +//========================================================================== +// +// strbin -- In-place version +// +// [RH] Replaces the escape sequences in a string with actual escaped characters. +// This operation is done in-place. The result is the new length of the string. +// +//========================================================================== + +int strbin (char *str) +{ + char *start = str; + char *p = str, c; + int i; + + while ( (c = *p++) ) { + if (c != '\\') { + *str++ = c; + } else if (*p != 0) { + switch (*p) { + case 'a': + *str++ = '\a'; + break; + case 'b': + *str++ = '\b'; + break; + case 'c': + *str++ = '\034'; // TEXTCOLOR_ESCAPE + break; + case 'f': + *str++ = '\f'; + break; + case 'n': + *str++ = '\n'; + break; + case 't': + *str++ = '\t'; + break; + case 'r': + *str++ = '\r'; + break; + case 'v': + *str++ = '\v'; + break; + case '?': + *str++ = '\?'; + break; + case '\n': + break; + case 'x': + case 'X': + c = 0; + for (i = 0; i < 2; i++) + { + p++; + if (*p >= '0' && *p <= '9') + c = (c << 4) + *p-'0'; + else if (*p >= 'a' && *p <= 'f') + c = (c << 4) + 10 + *p-'a'; + else if (*p >= 'A' && *p <= 'F') + c = (c << 4) + 10 + *p-'A'; + else + { + p--; + break; + } + } + *str++ = c; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + c = *p - '0'; + for (i = 0; i < 2; i++) + { + p++; + if (*p >= '0' && *p <= '7') + c = (c << 3) + *p - '0'; + else + { + p--; + break; + } + } + *str++ = c; + break; + default: + *str++ = *p; + break; + } + p++; + } + } + *str = 0; + return int(str - start); +} + +//========================================================================== +// +// strbin1 -- String-creating version +// +// [RH] Replaces the escape sequences in a string with actual escaped characters. +// The result is a new string. +// +//========================================================================== + +FString strbin1 (const char *start) +{ + FString result; + const char *p = start; + char c; + int i; + + while ( (c = *p++) ) { + if (c != '\\') { + result << c; + } else if (*p) { + switch (*p) { + case 'a': + result << '\a'; + break; + case 'b': + result << '\b'; + break; + case 'c': + result << '\034'; // TEXTCOLOR_ESCAPE + break; + case 'f': + result << '\f'; + break; + case 'n': + result << '\n'; + break; + case 't': + result << '\t'; + break; + case 'r': + result << '\r'; + break; + case 'v': + result << '\v'; + break; + case '?': + result << '\?'; + break; + case '\n': + break; + case 'x': + case 'X': + c = 0; + for (i = 0; i < 2; i++) + { + p++; + if (*p >= '0' && *p <= '9') + c = (c << 4) + *p-'0'; + else if (*p >= 'a' && *p <= 'f') + c = (c << 4) + 10 + *p-'a'; + else if (*p >= 'A' && *p <= 'F') + c = (c << 4) + 10 + *p-'A'; + else + { + p--; + break; + } + } + result << c; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + c = *p - '0'; + for (i = 0; i < 2; i++) + { + p++; + if (*p >= '0' && *p <= '7') + c = (c << 3) + *p - '0'; + else + { + p--; + break; + } + } + result << c; + break; + default: + result << *p; + break; + } + p++; + } + } + return result; +} + +//========================================================================== +// +// ExpandEnvVars +// +// Expands environment variable references in a string. Intended primarily +// for use with IWAD search paths in config files. +// +//========================================================================== + +FString ExpandEnvVars(const char *searchpathstring) +{ + static const char envvarnamechars[] = + "01234567890" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "_" + "abcdefghijklmnopqrstuvwxyz"; + + if (searchpathstring == NULL) + return FString(""); + + const char *dollar = strchr(searchpathstring, '$'); + if (dollar == NULL) + { + return FString(searchpathstring); + } + + const char *nextchars = searchpathstring; + FString out = FString(searchpathstring, dollar - searchpathstring); + while ( (dollar != NULL) && (*nextchars != 0) ) + { + size_t length = strspn(dollar + 1, envvarnamechars); + if (length != 0) + { + FString varname = FString(dollar + 1, length); + if (varname.CompareNoCase("progdir") == 0) + { + out += progdir; + } + else + { + char *varvalue = getenv(varname.GetChars()); + if ( (varvalue != NULL) && (strlen(varvalue) != 0) ) + { + out += varvalue; + } + } + } + else + { + out += '$'; + } + nextchars = dollar + length + 1; + dollar = strchr(nextchars, '$'); + if (dollar != NULL) + { + out += FString(nextchars, dollar - nextchars); + } + } + if (*nextchars != 0) + { + out += nextchars; + } + return out; +} + +//========================================================================== +// +// NicePath +// +// Handles paths with leading ~ characters on Unix as well as environment +// variable substitution. On Windows, this is identical to ExpandEnvVars. +// +//========================================================================== + +FString NicePath(const char *path) +{ +#ifdef _WIN32 + if (*path == '\0') + { + return FString("."); + } + return ExpandEnvVars(path); +#else + if (path == NULL || *path == '\0') + { + return FString(""); + } + if (*path != '~') + { + return ExpandEnvVars(path); + } + + passwd *pwstruct; + const char *slash; + + if (path[1] == '/' || path[1] == '\0') + { // Get my home directory + pwstruct = getpwuid(getuid()); + slash = path + 1; + } + else + { // Get somebody else's home directory + slash = strchr(path, '/'); + if (slash == NULL) + { + slash = path + strlen(path); + } + FString who(path, slash - path); + pwstruct = getpwnam(who.GetChars()); + } + if (pwstruct == NULL) + { + return ExpandEnvVars(path); + } + FString where(pwstruct->pw_dir); + if (*slash != '\0') + { + where += ExpandEnvVars(slash); + } + return where; +#endif +} + + +//========================================================================== +// +// +// +//========================================================================== + +bool IsAbsPath(const char *name) +{ + if (IsSeperator(name[0])) return true; +#ifdef _WIN32 + /* [A-Za-z]: (for Windows) */ + if (isalpha((uint8_t)name[0]) && name[1] == ':') return true; +#endif /* _WIN32 */ + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +void NormalizeFileName(FString& str) +{ + FixPathSeperator(str); + auto splits = str.Split("/"); + for (unsigned i = 1; i < splits.Size(); i++) + { + if (splits[i].Compare(".") == 0) + { + splits.Delete(i); + i--; + } + + if (splits[i].Compare("..") == 0 && splits[i - 1].Compare("..") != 0) + { + splits.Delete(i); + splits.Delete(i - 1); + i -= 2; + if (i < 1) i = 1; + } + } + str = splits[0]; + for (unsigned i = 1; i < splits.Size(); i++) + { + str << "/" << splits[i]; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FString M_ZLibError(int zerr) +{ + if (zerr >= 0) + { + return "OK"; + } + else if (zerr < -6) + { + FString out; + out.Format("%d", zerr); + return out; + } + else + { + static const char* errs[6] = + { + "Errno", + "Stream Error", + "Data Error", + "Memory Error", + "Buffer Error", + "Version Error" + }; + return errs[-zerr - 1]; + } +} + +void md5Update(FileReader& file, MD5Context& md5, unsigned len) +{ + uint8_t readbuf[8192]; + unsigned t; + + while (len > 0) + { + t = std::min(len, sizeof(readbuf)); + len -= t; + t = (unsigned)file.Read(readbuf, t); + md5.Update(readbuf, t); + } +} + + +//========================================================================== +// +// uppercoppy +// +// [RH] Copy up to 8 chars, upper-casing them in the process +//========================================================================== + +void uppercopy(char* to, const char* from) +{ + int i; + + for (i = 0; i < 8 && from[i]; i++) + to[i] = toupper(from[i]); + for (; i < 8; i++) + to[i] = 0; +} + +//========================================================================== +// +// GetStringFromLump +// +// Loads a zero terminated string from a lump in the file system +//========================================================================== + +FString GetStringFromLump(int lump, bool zerotruncate) +{ + auto fd = fileSystem.ReadFile(lump); + FString ScriptBuffer(fd.string(), fd.size()); + if (zerotruncate) ScriptBuffer.Truncate(strlen(ScriptBuffer.GetChars())); // this is necessary to properly truncate the generated string to not contain 0 bytes. + return ScriptBuffer; +} diff --git a/src/common/utility/cmdlib.h b/src/common/utility/cmdlib.h new file mode 100644 index 00000000000..88027c1565a --- /dev/null +++ b/src/common/utility/cmdlib.h @@ -0,0 +1,121 @@ +// cmdlib.h + +#ifndef __CMDLIB__ +#define __CMDLIB__ + + +#include +#include +#include +#include +#include +#include +#include +#include "zstring.h" +#include "files.h" + +#if !defined(GUID_DEFINED) +#define GUID_DEFINED +typedef struct _GUID +{ + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} GUID; +#endif + +template +char(&_ArraySizeHelper(T(&array)[N]))[N]; + +#define countof( array ) (sizeof( _ArraySizeHelper( array ) )) + +// the dec offsetof macro doesnt work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)alignof(type))->identifier - alignof(type)) + +bool FileExists (const char *filename); +inline bool FileExists(const FString& filename) +{ + return FileExists(filename.GetChars()); +} +bool FileReadable (const char *filename); +bool DirExists(const char *filename); +bool DirEntryExists (const char *pathname, bool *isdir = nullptr); +bool GetFileInfo(const char* pathname, size_t* size, time_t* time); + +extern FString progdir; + +void FixPathSeperator (char *path); +static void inline FixPathSeperator (FString &path) { path.ReplaceChars('\\', '/'); } + +void DefaultExtension (FString &path, const char *extension, bool forcebackslash = false); +void NormalizeFileName(FString &str); + +FString ExtractFilePath (const char *path, bool forcebackslash = false); +FString ExtractFileBase (const char *path, bool keep_extension=false, bool forcebackslash = false); +FString StripExtension(const char* path); +void SplitPath(const char* path, FString& directory, FString& base, FString& ext, bool forcebackslash = false); + +struct FScriptPosition; +bool IsNum (const char *str); // [RH] added + +char *copystring(const char *s); + +bool CheckWildcards (const char *pattern, const char *text); + +void FormatGUID (char *buffer, size_t buffsize, const GUID &guid); + +const char *myasctime (); + +int strbin (char *str); +FString strbin1 (const char *start); + +void CreatePath(const char * fn); +void RemoveFile(const char* file); +int RemoveDir(const char* file); + +FString ExpandEnvVars(const char *searchpathstring); +FString NicePath(const char *path); + +bool IsAbsPath(const char*); +FString M_ZLibError(int zerrnum); + +inline constexpr int32_t Scale(int32_t a, int32_t b, int32_t c) +{ + return (int32_t)(((int64_t)a * b) / c); +} + +inline constexpr double Scale(double a, double b, double c) +{ + return (a * b) / c; +} + +struct MD5Context; + +void md5Update(FileReader& file, MD5Context& md5, unsigned len); +void uppercopy(char* to, const char* from); +FString GetStringFromLump(int lump, bool zerotruncate = true); + +inline void fillshort(void* buff, size_t count, uint16_t clear) +{ + int16_t* b2 = (int16_t*)buff; + for (size_t i = 0; i < count; ++i) + { + b2[i] = clear; + } +} + +template inline constexpr int Sgn(const T& val) { return (val > 0) - (val < 0); } + + +inline int sizeToBits(int w) +{ + int j = 15; + + while ((j > 1) && ((1 << j) > w)) + j--; + return j; +} + + +#endif diff --git a/src/utility/colormatcher.h b/src/common/utility/colormatcher.h similarity index 86% rename from src/utility/colormatcher.h rename to src/common/utility/colormatcher.h index c9623c66495..277505e8143 100644 --- a/src/utility/colormatcher.h +++ b/src/common/utility/colormatcher.h @@ -40,35 +40,34 @@ #ifndef __COLORMATCHER_H__ #define __COLORMATCHER_H__ -#include "palette.h" +#include "palutil.h" -int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num); +int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num, const uint8_t* indexmap); class FColorMatcher { public: - FColorMatcher () = default; - FColorMatcher (const uint32_t *palette) { Pal = reinterpret_cast(palette); } - FColorMatcher (const FColorMatcher &other) = default; + void SetPalette(PalEntry* palette) { Pal = palette; } void SetPalette (const uint32_t *palette) { Pal = reinterpret_cast(palette); } + void SetIndexMap(const uint8_t* index) { indexmap = index; startindex = index ? 0 : 1; } uint8_t Pick (int r, int g, int b) { if (Pal == nullptr) return 1; - return (uint8_t)BestColor ((uint32_t *)Pal, r, g, b, 1, 255); + return (uint8_t)BestColor ((uint32_t *)Pal, r, g, b, startindex, 255, indexmap); } - + uint8_t Pick (PalEntry pe) { return Pick(pe.r, pe.g, pe.b); } - FColorMatcher &operator= (const FColorMatcher &other) = default; - private: - const PalEntry *Pal; + const PalEntry *Pal = nullptr; + const uint8_t* indexmap = nullptr; + int startindex = 1; }; extern FColorMatcher ColorMatcher; diff --git a/src/utility/configfile.cpp b/src/common/utility/configfile.cpp similarity index 91% rename from src/utility/configfile.cpp rename to src/common/utility/configfile.cpp index 2dc016e9e46..cdd4e951973 100644 --- a/src/utility/configfile.cpp +++ b/src/common/utility/configfile.cpp @@ -36,15 +36,11 @@ #include #include -#include "doomtype.h" #include "configfile.h" #include "files.h" -#include "m_random.h" #define READBUFFERSIZE 256 -static FRandom pr_endtag; - //==================================================================== // // FConfigFile Constructor @@ -89,7 +85,7 @@ FConfigFile::FConfigFile (const FConfigFile &other) Sections = CurrentSection = NULL; LastSectionPtr = &Sections; CurrentEntry = NULL; - ChangePathName (other.PathName); + ChangePathName (other.PathName.GetChars()); *this = other; OkayToWrite = other.OkayToWrite; FileExisted = other.FileExisted; @@ -138,7 +134,7 @@ FConfigFile &FConfigFile::operator = (const FConfigFile &other) while (fromsection != NULL) { fromentry = fromsection->RootEntry; - tosection = NewConfigSection (fromsection->SectionName); + tosection = NewConfigSection (fromsection->SectionName.GetChars()); while (fromentry != NULL) { NewConfigEntry (tosection, fromentry->Key, fromentry->Value); @@ -606,7 +602,7 @@ void FConfigFile::LoadConfigFile () bool succ; FileExisted = false; - if (!file.OpenFile (PathName)) + if (!file.OpenFile (PathName.GetChars())) { return; } @@ -621,15 +617,15 @@ void FConfigFile::LoadConfigFile () // //==================================================================== -bool FConfigFile::ReadConfig (void *file) +bool FConfigFile::ReadConfig (FileReader *file) { - uint8_t readbuf[READBUFFERSIZE]; + TArray readbuf; FConfigSection *section = NULL; ClearConfig (); - while (ReadLine ((char*)readbuf, READBUFFERSIZE, file) != NULL) + while (ReadLine (readbuf, file) != NULL) { - uint8_t *start = readbuf; + uint8_t *start = readbuf.Data(); uint8_t *equalpt; uint8_t *endpt; @@ -643,25 +639,17 @@ bool FConfigFile::ReadConfig (void *file) { continue; } - // Do not process tail of long line - const bool longline = (READBUFFERSIZE - 1) == strlen((char*)readbuf) && '\n' != readbuf[READBUFFERSIZE - 2]; - if (longline) + + // Remove white space at end of line + endpt = start + strlen ((char*)start) - 1; + while (endpt > start && *endpt <= ' ') { - endpt = start + READBUFFERSIZE - 2; - } - else - { - // Remove white space at end of line - endpt = start + strlen ((char*)start) - 1; - while (endpt > start && *endpt <= ' ') - { - endpt--; - } - // Remove line feed '\n' character - endpt[1] = 0; - if (endpt <= start) - continue; // Nothing here + endpt--; } + // Remove line feed '\n' character + endpt[1] = 0; + if (endpt <= start) + continue; // Nothing here if (*start == '[') { // Section header @@ -697,31 +685,6 @@ bool FConfigFile::ReadConfig (void *file) { ReadMultiLineValue (file, section, (char*)start, (char*)whiteprobe + 3); } - else if (longline) - { - const FString key = (char*)start; - FString value = (char*)whiteprobe; - - while (ReadLine ((char*)readbuf, READBUFFERSIZE, file) != NULL) - { - const size_t endpos = (0 == readbuf[0]) ? 0 : (strlen((char*)readbuf) - 1); - const bool endofline = '\n' == readbuf[endpos]; - - if (endofline) - { - readbuf[endpos] = 0; - } - - value += (char*)readbuf; - - if (endofline) - { - break; - } - } - - NewConfigEntry (section, key.GetChars(), value.GetChars()); - } else { NewConfigEntry (section, (char*)start, (char*)whiteprobe); @@ -746,18 +709,18 @@ bool FConfigFile::ReadConfig (void *file) // //==================================================================== -FConfigFile::FConfigEntry *FConfigFile::ReadMultiLineValue(void *file, FConfigSection *section, const char *key, const char *endtag) +FConfigFile::FConfigEntry *FConfigFile::ReadMultiLineValue(FileReader *file, FConfigSection *section, const char *key, const char *endtag) { - char readbuf[READBUFFERSIZE]; + TArray readbuf; FString value; size_t endlen = strlen(endtag); // Keep on reading lines until we reach a line that matches >>>endtag - while (ReadLine(readbuf, READBUFFERSIZE, file) != NULL) + while (ReadLine(readbuf, file) != NULL) { // Does the start of this line match the endtag? if (readbuf[0] == '>' && readbuf[1] == '>' && readbuf[2] == '>' && - strncmp(readbuf + 3, endtag, endlen) == 0) + strncmp((char*)readbuf.Data() + 3, endtag, endlen) == 0) { // Is there nothing but line break characters after the match? size_t i; for (i = endlen + 3; readbuf[i] != '\0'; ++i) @@ -776,7 +739,7 @@ FConfigFile::FConfigEntry *FConfigFile::ReadMultiLineValue(void *file, FConfigSe // Append this line to the value. value << readbuf; } - return NewConfigEntry(section, key, value); + return NewConfigEntry(section, key, value.GetChars()); } //==================================================================== @@ -785,9 +748,28 @@ FConfigFile::FConfigEntry *FConfigFile::ReadMultiLineValue(void *file, FConfigSe // //==================================================================== -char *FConfigFile::ReadLine (char *string, int n, void *file) const +uint8_t *FConfigFile::ReadLine(TArray& string, FileReader* file) const { - return ((FileReader *)file)->Gets (string, n); + uint8_t byte; + string.Clear(); + while (file->Read(&byte, 1)) + { + if (byte == 0) + { + break; + } + if (byte != '\r') + { + string.Push(byte); + if (byte == '\n') + { + break; + } + } + } + if (string.Size() == 0) return nullptr; + string.Push(0); + return string.Data(); } //==================================================================== @@ -805,7 +787,7 @@ bool FConfigFile::WriteConfigFile () const return true; } - FileWriter *file = FileWriter::Open (PathName); + FileWriter *file = FileWriter::Open (PathName.GetChars()); FConfigSection *section; FConfigEntry *entry; @@ -863,11 +845,10 @@ const char *FConfigFile::GenerateEndTag(const char *value) // isn't in the value. We create the sequences by generating two // 64-bit random numbers and Base64 encoding the first 15 bytes // from them. - union { uint64_t rand_num[2]; uint8_t rand_bytes[16]; }; + union { uint16_t rand_num[8]; uint8_t rand_bytes[16]; }; do { - rand_num[0] = pr_endtag.GenRand64(); - rand_num[1] = pr_endtag.GenRand64(); + for (auto &r : rand_num) r = (uint16_t)rand(); for (int i = 0; i < 5; ++i) { diff --git a/src/utility/configfile.h b/src/common/utility/configfile.h similarity index 90% rename from src/utility/configfile.h rename to src/common/utility/configfile.h index ab686643065..f1a5ab87d61 100644 --- a/src/utility/configfile.h +++ b/src/common/utility/configfile.h @@ -66,6 +66,10 @@ class FConfigFile bool NextInSection (const char *&key, const char *&value); const char *GetValueForKey (const char *key) const; void SetValueForKey (const char *key, const char *value, bool duplicates=false); + void SetValueForKey(const char* key, const FString& value, bool duplicates = false) + { + SetValueForKey(key, value.GetChars(), duplicates); + } const char *GetPathName () const { return PathName.GetChars(); } void ChangePathName (const char *path); @@ -76,8 +80,8 @@ class FConfigFile protected: virtual void WriteCommentHeader (FileWriter *file) const; - virtual char *ReadLine (char *string, int n, void *file) const; - bool ReadConfig (void *file); + uint8_t *ReadLine (TArray &string, FileReader *file) const; + bool ReadConfig (FileReader *file); static const char *GenerateEndTag(const char *value); void RenameSection(const char *oldname, const char *newname) const; @@ -103,7 +107,7 @@ class FConfigFile //char Name[1]; // + length of name }; - FConfigSection *Sections; + FConfigSection* Sections = nullptr; FConfigSection **LastSectionPtr; FConfigSection *CurrentSection; FConfigEntry *CurrentEntry; @@ -113,7 +117,7 @@ class FConfigFile FConfigEntry *FindEntry (FConfigSection *section, const char *key) const; FConfigSection *NewConfigSection (const char *name); FConfigEntry *NewConfigEntry (FConfigSection *section, const char *key, const char *value); - FConfigEntry *ReadMultiLineValue (void *file, FConfigSection *section, const char *key, const char *terminator); + FConfigEntry *ReadMultiLineValue (FileReader *file, FConfigSection *section, const char *key, const char *terminator); void SetSectionNote (FConfigSection *section, const char *note); public: diff --git a/src/common/utility/engineerrors.cpp b/src/common/utility/engineerrors.cpp new file mode 100644 index 00000000000..05897b78626 --- /dev/null +++ b/src/common/utility/engineerrors.cpp @@ -0,0 +1,137 @@ +/* +** engineerrors.cpp +** Contains error classes that can be thrown around +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +bool gameisdead; + +#include + +#ifdef _WIN32 +#include +#include "zstring.h" +void I_DebugPrint(const char *cp) +{ + if (IsDebuggerPresent()) + { + auto wstr = WideString(cp); + OutputDebugStringW(wstr.c_str()); + } +} + +void I_DebugPrintf(const char *fmt,...) +{ + if (IsDebuggerPresent()) + { + va_list args; + va_start(args, fmt); + + FString s; + s.VFormat(fmt, args); + + va_end(args); + + auto wstr = WideString(s.GetChars()); + OutputDebugStringW(wstr.c_str()); + } +} +#else +void I_DebugPrint(const char *cp) +{ +} + +void I_DebugPrintf(const char *fmt,...) +{ +} +#endif + +#include "engineerrors.h" + +//========================================================================== +// +// I_Error +// +// Throw an error that will send us to the console if we are far enough +// along in the startup process. +// +//========================================================================== + +[[noreturn]] void I_Error(const char *error, ...) +{ + va_list argptr; + char errortext[MAX_ERRORTEXT]; + + va_start(argptr, error); + vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + I_DebugPrint(errortext); + + throw CRecoverableError(errortext); +} + +//========================================================================== +// +// I_FatalError +// +// Throw an error that will end the game. +// +//========================================================================== +extern FILE *Logfile; + +[[noreturn]] void I_FatalError(const char *error, ...) +{ + static bool alreadyThrown = false; + gameisdead = true; + + if (!alreadyThrown) // ignore all but the first message -- killough + { + alreadyThrown = true; + char errortext[MAX_ERRORTEXT]; + va_list argptr; + va_start(argptr, error); + vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + I_DebugPrint(errortext); + + // Record error to log (if logging) + if (Logfile) + { + fprintf(Logfile, "\n**** DIED WITH FATAL ERROR:\n%s\n", errortext); + fflush(Logfile); + } + + throw CFatalError(errortext); + } + std::terminate(); // recursive I_FatalErrors must immediately terminate. +} + diff --git a/src/common/utility/engineerrors.h b/src/common/utility/engineerrors.h new file mode 100644 index 00000000000..a8d439f7a78 --- /dev/null +++ b/src/common/utility/engineerrors.h @@ -0,0 +1,116 @@ +/* +** doomerrors.h +** Contains error classes that can be thrown around +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __ERRORS_H__ +#define __ERRORS_H__ + +#include +#include +#include +#include +#include "basics.h" + +#define MAX_ERRORTEXT 1024 + +class CEngineError : public std::exception +{ +public: + CEngineError () + { + m_Message[0] = '\0'; + } + CEngineError (const char *message) + { + SetMessage (message); + } + void SetMessage (const char *message) + { + strncpy (m_Message, message, MAX_ERRORTEXT-1); + m_Message[MAX_ERRORTEXT-1] = '\0'; + } + void AppendMessage(const char *message) noexcept + { + size_t len = strlen(m_Message); + strncpy(m_Message + len, message, MAX_ERRORTEXT - 1 - len); + m_Message[MAX_ERRORTEXT - 1] = '\0'; + } + const char *GetMessage (void) const noexcept + { + if (m_Message[0] != '\0') + return (const char *)m_Message; + else + return NULL; + } + char const *what() const noexcept override + { + return m_Message; + } + + +protected: + char m_Message[MAX_ERRORTEXT]; +}; + + +class CRecoverableError : public CEngineError +{ +public: + CRecoverableError() : CEngineError() {} + CRecoverableError(const char *message) : CEngineError(message) {} +}; + +class CFatalError : public CEngineError +{ +public: + CFatalError() : CEngineError() {} + CFatalError(const char *message) : CEngineError(message) {} +}; + +class CExitEvent : public std::exception +{ + int m_reason; +public: + CExitEvent(int reason) { m_reason = reason; } + char const *what() const noexcept override + { + return "The game wants to exit"; + } + int Reason() const { return m_reason; } +}; + +void I_ShowFatalError(const char *message); +[[noreturn]] void I_Error (const char *error, ...) GCCPRINTF(1,2); +[[noreturn]] void I_FatalError (const char *error, ...) GCCPRINTF(1,2); + +#endif //__ERRORS_H__ diff --git a/src/common/utility/filereadermusicinterface.h b/src/common/utility/filereadermusicinterface.h new file mode 100644 index 00000000000..c30ac6c55ec --- /dev/null +++ b/src/common/utility/filereadermusicinterface.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include "files.h" + + +inline ZMusicCustomReader *GetMusicReader(FileReader& fr) +{ + using FileSys::FileReaderInterface; + auto zcr = new ZMusicCustomReader; + + zcr->handle = fr.GetInterface(); + zcr->gets = [](ZMusicCustomReader* zr, char* buff, int n) { return reinterpret_cast(zr->handle)->Gets(buff, n); }; + zcr->read = [](ZMusicCustomReader* zr, void* buff, int32_t size) -> long { return (long)reinterpret_cast(zr->handle)->Read(buff, size); }; + zcr->seek = [](ZMusicCustomReader* zr, long offset, int whence) -> long { return (long)reinterpret_cast(zr->handle)->Seek(offset, whence); }; + zcr->tell = [](ZMusicCustomReader* zr) -> long { return (long)reinterpret_cast(zr->handle)->Tell(); }; + zcr->close = [](ZMusicCustomReader* zr) + { + delete reinterpret_cast(zr->handle); + delete zr; + }; + return zcr; +} + diff --git a/src/common/utility/findfile.cpp b/src/common/utility/findfile.cpp new file mode 100644 index 00000000000..65090cc9037 --- /dev/null +++ b/src/common/utility/findfile.cpp @@ -0,0 +1,278 @@ +/* +** findfile.cpp +** Warpper around the native directory scanning API +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2020 Christoph Oelckers +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "findfile.h" +#include "zstring.h" +#include "cmdlib.h" +#include "printf.h" +#include "configfile.h" +#include "i_system.h" +#include "fs_findfile.h" + +#ifdef __unix__ +#include +#endif // __unix__ + +//========================================================================== +// +// D_AddFile +// +//========================================================================== + +bool D_AddFile(std::vector& wadfiles, const char* file, bool check, int position, FConfigFile* config) +{ + if (file == nullptr || *file == '\0') + { + return false; + } +#ifdef __unix__ + // Confirm file exists in filesystem. + struct stat info; + bool found = stat(file, &info) == 0; + FString fullpath = file; + if (!found) + { + // File not found, so split file into path and filename so we can enumerate the path for the file. + auto lastindex = fullpath.LastIndexOf("/"); + FString basepath = fullpath.Left(lastindex); + FString filename = fullpath.Right(fullpath.Len() - lastindex - 1); + + // Proceed only if locating a file (i.e. `file` isn't a path to just a directory.) + if (filename.IsNotEmpty()) + { + DIR *d; + struct dirent *dir; + d = opendir(basepath.GetChars()); + if (d) + { + while ((dir = readdir(d)) != NULL) + { + if (filename.CompareNoCase(dir->d_name) == 0) + { + found = true; + filename = dir->d_name; + fullpath = basepath << "/" << filename; + file = fullpath.GetChars(); + break; + } + } + closedir(d); + if (!found) + { + //Printf("Can't find file '%s' in '%s'\n", filename.GetChars(), basepath.GetChars()); + return false; + } + } + else + { + Printf("Can't open directory '%s'\n", basepath.GetChars()); + return false; + } + } + } +#endif + + if (check && !DirEntryExists(file)) + { + const char* f = BaseFileSearch(file, ".wad", false, config); + if (f == nullptr) + { + Printf("Can't find '%s'\n", file); + return false; + } + file = f; + } + + std::string f = file; + for (auto& c : f) if (c == '\\') c = '/'; + if (position == -1) wadfiles.push_back(f); + else wadfiles.insert(wadfiles.begin() + position, f); + return true; +} + +//========================================================================== +// +// D_AddWildFile +// +//========================================================================== + +void D_AddWildFile(std::vector& wadfiles, const char* value, const char *extension, FConfigFile* config) +{ + if (value == nullptr || *value == '\0') + { + return; + } + const char* wadfile = BaseFileSearch(value, extension, false, config); + + if (wadfile != nullptr) + { + D_AddFile(wadfiles, wadfile, true, -1, config); + } + else + { + // Try pattern matching + FileSys::FileList list; + auto path = ExtractFilePath(value); + auto name = ExtractFileBase(value, true); + if (path.IsEmpty()) path = "."; + if (FileSys::ScanDirectory(list, path.GetChars(), name.GetChars(), true)) + { + for(auto& entry : list) + { + D_AddFile(wadfiles, entry.FilePath.c_str(), true, -1, config); + } + } + } +} + +//========================================================================== +// +// D_AddConfigWads +// +// Adds all files in the specified config file section. +// +//========================================================================== + +void D_AddConfigFiles(std::vector& wadfiles, const char* section, const char* extension, FConfigFile *config) +{ + if (config && config->SetSection(section)) + { + const char* key; + const char* value; + FConfigFile::Position pos; + + while (config->NextInSection(key, value)) + { + if (stricmp(key, "Path") == 0) + { + // D_AddWildFile resets config's position, so remember it + config->GetPosition(pos); + D_AddWildFile(wadfiles, ExpandEnvVars(value).GetChars(), extension, config); + // Reset config's position to get next wad + config->SetPosition(pos); + } + } + } +} + +//========================================================================== +// +// D_AddDirectory +// +// Add all .wad files in a directory. Does not descend into subdirectories. +// +//========================================================================== + +void D_AddDirectory(std::vector& wadfiles, const char* dir, const char *filespec, FConfigFile* config) +{ + FileSys::FileList list; + if (FileSys::ScanDirectory(list, dir, "*.wad", true)) + { + for (auto& entry : list) + { + if (!entry.isDirectory) + { + D_AddFile(wadfiles, entry.FilePath.c_str(), true, -1, config); + } + } + } +} + +//========================================================================== +// +// BaseFileSearch +// +// If a file does not exist at , looks for it in the directories +// specified in the config file. Returns the path to the file, if found, +// or nullptr if it could not be found. +// +//========================================================================== + +static FString BFSwad; // outside the function to evade C++'s insane rules for constructing static variables inside functions. + +const char* BaseFileSearch(const char* file, const char* ext, bool lookfirstinprogdir, FConfigFile* config) +{ + if (file == nullptr || *file == '\0') + { + return nullptr; + } + if (lookfirstinprogdir) + { + BFSwad.Format("%s%s%s", progdir.GetChars(), progdir.Back() == '/' ? "" : "/", file); + if (DirEntryExists(BFSwad.GetChars())) + { + return BFSwad.GetChars(); + } + } + + if (DirEntryExists(file)) + { + BFSwad.Format("%s", file); + return BFSwad.GetChars(); + } + + if (config != nullptr && config->SetSection("FileSearch.Directories")) + { + const char* key; + const char* value; + + while (config->NextInSection(key, value)) + { + if (stricmp(key, "Path") == 0) + { + FString dir; + + dir = NicePath(value); + if (dir.IsNotEmpty()) + { + BFSwad.Format("%s%s%s", dir.GetChars(), dir.Back() == '/' ? "" : "/", file); + if (DirEntryExists(BFSwad.GetChars())) + { + return BFSwad.GetChars(); + } + } + } + } + } + + // Retry, this time with a default extension + if (ext != nullptr) + { + FString tmp = file; + DefaultExtension(tmp, ext); + return BaseFileSearch(tmp.GetChars(), nullptr, lookfirstinprogdir, config); + } + return nullptr; +} + diff --git a/src/common/utility/findfile.h b/src/common/utility/findfile.h new file mode 100644 index 00000000000..fd58ecde5ee --- /dev/null +++ b/src/common/utility/findfile.h @@ -0,0 +1,14 @@ +#pragma once +// Directory searching routines + +#include +#include +#include + +class FConfigFile; + +bool D_AddFile(std::vector& wadfiles, const char* file, bool check, int position, FConfigFile* config); +void D_AddWildFile(std::vector& wadfiles, const char* value, const char *extension, FConfigFile* config); +void D_AddConfigFiles(std::vector& wadfiles, const char* section, const char* extension, FConfigFile* config); +void D_AddDirectory(std::vector& wadfiles, const char* dir, const char *filespec, FConfigFile* config); +const char* BaseFileSearch(const char* file, const char* ext, bool lookfirstinprogdir, FConfigFile* config); diff --git a/src/common/utility/floatrect.h b/src/common/utility/floatrect.h new file mode 100644 index 00000000000..34eedabe631 --- /dev/null +++ b/src/common/utility/floatrect.h @@ -0,0 +1,41 @@ +#pragma once + +struct FloatRect +{ + float left,top; + float width,height; + + + void Offset(float xofs,float yofs) + { + left+=xofs; + top+=yofs; + } + void Scale(float xfac,float yfac) + { + left*=xfac; + width*=xfac; + top*=yfac; + height*=yfac; + } +}; + +struct DoubleRect +{ + double left, top; + double width, height; + + + void Offset(double xofs, double yofs) + { + left += xofs; + top += yofs; + } + void Scale(double xfac, double yfac) + { + left *= xfac; + width *= xfac; + top *= yfac; + height *= yfac; + } +}; diff --git a/src/common/utility/geometry.h b/src/common/utility/geometry.h new file mode 100644 index 00000000000..3a7bb8d9c8a --- /dev/null +++ b/src/common/utility/geometry.h @@ -0,0 +1,234 @@ +#pragma once + +/* +** geometry.h +** basic geometry math routines +** +**--------------------------------------------------------------------------- +** Copyright 2005-2022 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +*/ + +#include "vectors.h" + +inline DVector2 rotatepoint(const DVector2& pivot, const DVector2& point, DAngle angle) +{ + return (point - pivot).Rotated(angle) + pivot; +} + +//========================================================================== +// +// +// +//========================================================================== + +inline double PointOnLineSide(double x, double y, double linex, double liney, double deltax, double deltay) +{ + return (x - linex) * deltay - (y - liney) * deltax; +} + +//========================================================================== +// +// +// +//========================================================================== + +inline double SquareDist(double lx1, double ly1, double lx2, double ly2) +{ + double dx = lx2 - lx1; + double dy = ly2 - ly1; + return dx * dx + dy * dy; +} + +// This is for cases where only the factor is needed, and pre-validation was performed. +inline double NearestPointOnLineFast(double px, double py, double lx1, double ly1, double lx2, double ly2) +{ + double wall_length = SquareDist(lx1, ly1, lx2, ly2); + assert(wall_length > 0); + return ((px - lx1) * (lx2 - lx1) + (py - ly1) * (ly2 - ly1)) / wall_length; +} + + +inline DVector2 NearestPointOnLine(double px, double py, double lx1, double ly1, double lx2, double ly2, bool clamp = true) +{ + double wall_length = SquareDist(lx1, ly1, lx2, ly2); + + if (wall_length == 0) + { + return { lx1, ly1 }; + } + + double t = ((px - lx1) * (lx2 - lx1) + (py - ly1) * (ly2 - ly1)) / wall_length; + if (clamp) + { + if (t <= 0) return { lx1, ly1 }; + if (t >= 1) return { lx2, ly2 }; + } + double xx = lx1 + t * (lx2 - lx1); + double yy = ly1 + t * (ly2 - ly1); + return { xx, yy }; +} + +//========================================================================== +// +// +// +//========================================================================== + +inline double SquareDistToLine(double px, double py, double lx1, double ly1, double lx2, double ly2) +{ + double wall_length = SquareDist(lx1, ly1, lx2, ly2); + + if (wall_length == 0) return SquareDist(px, py, lx1, ly1); + + double t = ((px - lx1) * (lx2 - lx1) + (py - ly1) * (ly2 - ly1)) / wall_length; + t = clamp(t, 0., 1.); + double xx = lx1 + t * (lx2 - lx1); + double yy = ly1 + t * (ly2 - ly1); + return SquareDist(px, py, xx, yy); +} + +//========================================================================== +// +// taken from GZDoom with the divline_t parameters removed +// +//========================================================================== + +inline double InterceptVector(double v2x, double v2y, double v2dx, double v2dy, double v1x, double v1y, double v1dx, double v1dy) +{ + double den = v1dy * v2dx - v1dx * v2dy; + + if (den == 0) + return 0; // parallel + + double num = (v1x - v2x) * v1dy + (v2y - v1y) * v1dx; + return num / den; +} + +//========================================================================== +// +// Essentially two InterceptVector calls. We can reduce the calculations +// because the denominators for both calculations only differ by their sign. +// +//========================================================================== + +inline double InterceptLineSegments(double v2x, double v2y, double v2dx, double v2dy, double v1x, double v1y, double v1dx, double v1dy, double* pfactor1 = nullptr, bool forcansee = false) +{ + double den = v1dy * v2dx - v1dx * v2dy; + + if (den == 0) + return -2 * (double)FLT_MAX; // parallel (return a magic value different from everything else, just in case it needs to be handled) + + if (forcansee && den < 0) // cansee does this added check here, aside from that its logic is virtually the same. + return -1; // hitting the backside + + // perform the division first for better parallelization. + den = 1 / den; + + double factor1 = ((v2x - v1x) * v2dy + (v1y - v2y) * v2dx) * -den; + if (factor1 < 0 || factor1 >= 1) return -FLT_MAX; // no intersection + if (pfactor1) *pfactor1 = factor1; + + return ((v1x - v2x) * v1dy + (v2y - v1y) * v1dx) * den; // this one's for the line segment where we want to get the intercept factor for so it needs to be last. +} + +//========================================================================== +// +// calculates intersection between a plane and line in 3D +// +//========================================================================== + +inline double LinePlaneIntersect(const DVector3& start, const DVector3& trace, const DVector3& ppoint, const DVector3& pvec1, const DVector3& pvec2) +{ + auto normal = pvec1 ^ pvec2; // we do not need a unit vector here. + double dist = normal.dot(ppoint); + double dotStart = normal.dot(start); + double dotTrace = normal.dot(trace); + if (dotTrace == 0) return -FLT_MAX; + return (dist - dotStart) / dotTrace; // we are only interested in the factor +} + +//========================================================================== +// +// BoxOnLineSide +// +// Based on Doom's, but rewritten to be standalone +// +//========================================================================== + +inline int BoxOnLineSide(const DVector2& boxtl, const DVector2& boxbr, const DVector2& start, const DVector2& delta) +{ + int p1; + int p2; + + if (delta.X == 0) + { + p1 = boxbr.X < start.X; + p2 = boxtl.X < start.X; + if (delta.Y < 0) + { + p1 ^= 1; + p2 ^= 1; + } + } + else if (delta.Y == 0) + { + p1 = boxtl.Y > start.Y; + p2 = boxbr.Y > start.Y; + if (delta.X < 0) + { + p1 ^= 1; + p2 ^= 1; + } + } + else if (delta.X * delta.Y <= 0) + { + p1 = PointOnLineSide(boxtl.X, boxtl.Y, start.X, start.Y, delta.X, delta.Y) > 0; + p2 = PointOnLineSide(boxbr.X, boxbr.Y, start.X, start.Y, delta.X, delta.Y) > 0; + } + else + { + p1 = PointOnLineSide(boxbr.X, boxtl.Y, start.X, start.Y, delta.X, delta.Y) > 0; + p2 = PointOnLineSide(boxtl.X, boxbr.Y, start.X, start.Y, delta.X, delta.Y) > 0; + } + + return (p1 == p2) ? p1 : -1; +} + +//========================================================================== +// +// BoxInRange +// +//========================================================================== + +inline bool BoxInRange(const DVector2& boxtl, const DVector2& boxbr, const DVector2& start, const DVector2& end) +{ + return boxtl.X < max(start.X, end.X) && + boxbr.X > min(start.X, end.X) && + boxtl.Y < max(start.Y, end.Y) && + boxbr.Y > min(start.Y, end.Y); +} diff --git a/src/gitinfo.cpp b/src/common/utility/gitinfo.cpp similarity index 100% rename from src/gitinfo.cpp rename to src/common/utility/gitinfo.cpp diff --git a/src/utility/i_module.cpp b/src/common/utility/i_module.cpp similarity index 100% rename from src/utility/i_module.cpp rename to src/common/utility/i_module.cpp diff --git a/src/utility/i_module.h b/src/common/utility/i_module.h similarity index 100% rename from src/utility/i_module.h rename to src/common/utility/i_module.h diff --git a/src/common/utility/i_time.cpp b/src/common/utility/i_time.cpp new file mode 100644 index 00000000000..b3312b89f5c --- /dev/null +++ b/src/common/utility/i_time.cpp @@ -0,0 +1,225 @@ +/* +** i_time.cpp +** Implements the timer +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2017 Magnus Norddahl +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include "i_time.h" + +//========================================================================== +// +// Tick time functions +// +//========================================================================== + +static uint64_t StartupTimeNS; +static uint64_t FirstFrameStartTime; +static uint64_t CurrentFrameStartTime; +static uint64_t FreezeTime; +static double lastinputtime; +int GameTicRate = 35; // make sure it is not 0, even if the client doesn't set it. + +double TimeScale = 1.0; + +static uint64_t GetTimePoint() +{ + using namespace std::chrono; + return (uint64_t)(duration_cast(steady_clock::now().time_since_epoch()).count()); +} + +void I_InitTime() +{ + StartupTimeNS = GetTimePoint(); +} + +static uint64_t GetClockTimeNS() +{ + auto tp = GetTimePoint() - StartupTimeNS; + if (TimeScale == 1.0) return tp; + else return uint64_t(tp / 1000 * TimeScale * 1000); +} + +static uint64_t MSToNS(unsigned int ms) +{ + return static_cast(ms) * 1'000'000; +} + +static uint64_t NSToMS(uint64_t ns) +{ + return static_cast(ns / 1'000'000); +} + +static int NSToTic(uint64_t ns, double const ticrate) +{ + return static_cast(ns * ticrate / 1'000'000'000); +} + +static uint64_t TicToNS(double tic, double const ticrate) +{ + return static_cast(tic * 1'000'000'000 / ticrate); +} + +void I_SetFrameTime() +{ + // Must only be called once per frame/swapbuffers. + // + // Caches all timing information for the current rendered frame so that any + // calls to I_GetTime or I_GetTimeFrac will return + // the same time. + + if (FreezeTime == 0) + { + CurrentFrameStartTime = GetClockTimeNS(); + if (FirstFrameStartTime == 0) + FirstFrameStartTime = CurrentFrameStartTime; + } +} + +void I_WaitVBL(int count) +{ + // I_WaitVBL is never used to actually synchronize to the vertical blank. + // Instead, it's used for delay purposes. Doom used a 70 Hz display mode, + // so that's what we use to determine how long to wait for. + + std::this_thread::sleep_for(std::chrono::milliseconds(1000 * count / 70)); + I_SetFrameTime(); +} + +int I_WaitForTic(int prevtic, double const ticrate) +{ + // Waits until the current tic is greater than prevtic. Time must not be frozen. + + int time; + while ((time = I_GetTime(ticrate)) <= prevtic) + { + // Windows-specific note: + // The minimum amount of time a thread can sleep is controlled by timeBeginPeriod. + // We set this to 1 ms in DoMain. + + const uint64_t next = FirstFrameStartTime + TicToNS(prevtic + 1, ticrate); + const uint64_t now = I_nsTime(); + + if (next > now) + { + const uint64_t sleepTime = NSToMS(next - now); + + if (sleepTime > 2) + { + std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime - 2)); + } + } + + I_SetFrameTime(); + } + + return time; +} + +uint64_t I_nsTime() +{ + return GetClockTimeNS(); +} + +uint64_t I_msTime() +{ + return NSToMS(I_nsTime()); +} + +double I_msTimeF(void) +{ + return I_nsTime() / 1'000'000.; +} + +uint64_t I_msTimeFS() // from "start" +{ + return (FirstFrameStartTime == 0) ? 0 : NSToMS(I_nsTime() - FirstFrameStartTime); +} + +uint64_t I_GetTimeNS() +{ + return CurrentFrameStartTime - FirstFrameStartTime; +} + +int I_GetTime(double const ticrate) +{ + return NSToTic(CurrentFrameStartTime - FirstFrameStartTime, ticrate); +} + +double I_GetTimeFrac(double const ticrate) +{ + int currentTic = NSToTic(CurrentFrameStartTime - FirstFrameStartTime, ticrate); + uint64_t ticStartTime = FirstFrameStartTime + TicToNS(currentTic, ticrate); + uint64_t ticNextTime = FirstFrameStartTime + TicToNS(currentTic + 1, ticrate); + + return (CurrentFrameStartTime - ticStartTime) / (double)(ticNextTime - ticStartTime); +} + +void I_FreezeTime(bool frozen) +{ + if (frozen) + { + assert(FreezeTime == 0); + FreezeTime = GetClockTimeNS(); + } + else + { + assert(FreezeTime != 0); + if (FirstFrameStartTime != 0) FirstFrameStartTime += GetClockTimeNS() - FreezeTime; + FreezeTime = 0; + I_SetFrameTime(); + } +} + +void I_ResetFrameTime() +{ + // Reset the starting point of the current frame to now. For use after lengthy operations that should not result in tic accumulation. + auto ft = CurrentFrameStartTime; + I_SetFrameTime(); + FirstFrameStartTime += (CurrentFrameStartTime - ft); +} + +double I_GetInputFrac() +{ + const double now = I_msTimeF(); + const double result = (now - lastinputtime) * GameTicRate * (1. / 1000.); + lastinputtime = now; + return result; +} + +void I_ResetInputTime() +{ + // Reset lastinputtime to current time. + lastinputtime = I_msTimeF(); +} diff --git a/src/common/utility/i_time.h b/src/common/utility/i_time.h new file mode 100644 index 00000000000..a77640fb5d6 --- /dev/null +++ b/src/common/utility/i_time.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +extern int GameTicRate; +extern double TimeScale; + +void I_InitTime(); + +// Called by D_DoomLoop, sets the time for the current frame +void I_SetFrameTime(); + +// Called by D_DoomLoop, returns current time in tics. +int I_GetTime(double const ticrate = GameTicRate); +// same, but using nanoseconds +uint64_t I_GetTimeNS(); + +double I_GetTimeFrac(double const ticrate = GameTicRate); + +// like I_GetTime, except it waits for a new tic before returning +int I_WaitForTic(int prevtic, double const ticrate = GameTicRate); + +// Freezes tic counting temporarily. While frozen, calls to I_GetTime() +// will always return the same value. +// You must also not call I_WaitForTic() while freezing time, since the +// tic will never arrive (unless it's the current one). +void I_FreezeTime(bool frozen); + +// [RH] Returns millisecond-accurate time +uint64_t I_msTime(); + +// [RH] Returns nanosecond-accurate time in milliseconds +double I_msTimeF(void); + +// [SP] Returns millisecond-accurate time from start +uint64_t I_msTimeFS(); + +// Nanosecond-accurate time +uint64_t I_nsTime(); + +// Reset the timer after a lengthy operation +void I_ResetFrameTime(); + +// Return a decimal fraction to scale input operations at framerate +double I_GetInputFrac(); + +// Reset the last input check to after a lengthy operation +void I_ResetInputTime(); + +// Pause a bit. +// [RH] Despite the name, it apparently never waited for the VBL, even in +// the original DOS version (if the Heretic/Hexen source is any indicator). +void I_WaitVBL(int count); diff --git a/src/common/utility/intrect.h b/src/common/utility/intrect.h new file mode 100644 index 00000000000..1de15df29c9 --- /dev/null +++ b/src/common/utility/intrect.h @@ -0,0 +1,61 @@ +#pragma once + + +struct IntRect +{ + int left, top; + int width, height; + + void Offset(int xofs, int yofs) + { + left += xofs; + top += yofs; + } + + void AddToRect(int x, int y) + { + if (x < left) + left = x; + if (x > left + width) + width = x - left; + + if (y < top) + top = y; + if (y > top + height) + height = y - top; + } + + int Left() const + { + return left; + } + + int Top() const + { + return top; + } + + + int Right() const + { + return left + width; + } + + int Bottom() const + { + return top + height; + } + + int Width() const + { + return width; + } + + int Height() const + { + return height; + } + + +}; + diff --git a/src/common/utility/m_alloc.cpp b/src/common/utility/m_alloc.cpp new file mode 100644 index 00000000000..5884b48e819 --- /dev/null +++ b/src/common/utility/m_alloc.cpp @@ -0,0 +1,204 @@ +/* +** m_alloc.cpp +** Wrappers for the malloc family of functions that count used bytes. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Marisa Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 defined(__FreeBSD__) +#include +#include +#elif defined(__APPLE__) +#include +#include +#elif defined(__OpenBSD__) || defined(__DragonFly__) +#include +#else +#include +#endif + +#include "engineerrors.h" +#include "dobjgc.h" + +#ifndef _MSC_VER +#define _NORMAL_BLOCK 0 +#define _malloc_dbg(s,b,f,l) malloc(s) +#define _realloc_dbg(p,s,b,f,l) realloc(p,s) +#endif + +#ifndef _DEBUG +#if !defined(__solaris__) && !defined(__OpenBSD__) && !defined(__DragonFly__) +void *M_Malloc(size_t size) +{ + void *block = malloc(size); + + if (block == nullptr) + I_FatalError("Could not malloc %zu bytes", size); + + GC::ReportAlloc(_msize(block)); + return block; +} + +void *M_Realloc(void *memblock, size_t size) +{ + size_t oldsize = memblock ? _msize(memblock) : 0; + void *block = realloc(memblock, size); + if (block == nullptr) + { + I_FatalError("Could not realloc %zu bytes", size); + } + GC::ReportRealloc(oldsize, _msize(block)); + return block; +} + +#else +void *M_Malloc(size_t size) +{ + void *block = malloc(size+sizeof(size_t)); + + if (block == nullptr) + I_FatalError("Could not malloc %zu bytes", size); + + size_t *sizeStore = (size_t *) block; + *sizeStore = size; + block = sizeStore+1; + + GC::ReportAlloc(_msize(block)); + return block; +} + +void *M_Realloc(void *memblock, size_t size) +{ + if (memblock == nullptr) + return M_Malloc(size); + + size_t oldsize = _msize(memblock); + void *block = realloc(((size_t*) memblock)-1, size+sizeof(size_t)); + if (block == nullptr) + { + I_FatalError("Could not realloc %zu bytes", size); + } + + size_t *sizeStore = (size_t *) block; + *sizeStore = size; + block = sizeStore+1; + + GC::ReportRealloc(oldsize, _msize(block)); + return block; +} +#endif + +void* M_Calloc(size_t v1, size_t v2) +{ + auto p = M_Malloc(v1 * v2); + memset(p, 0, v1 * v2); + return p; +} + +#else +#ifdef _MSC_VER +#include +#endif + +#if !defined(__solaris__) && !defined(__OpenBSD__) && !defined(__DragonFly__) +void *M_Malloc_Dbg(size_t size, const char *file, int lineno) +{ + void *block = _malloc_dbg(size, _NORMAL_BLOCK, file, lineno); + + if (block == nullptr) + I_FatalError("Could not malloc %zu bytes in %s, line %d", size, file, lineno); + + GC::ReportAlloc(_msize(block)); + return block; +} + +void *M_Realloc_Dbg(void *memblock, size_t size, const char *file, int lineno) +{ + size_t oldsize = memblock ? _msize(memblock) : 0; + void *block = _realloc_dbg(memblock, size, _NORMAL_BLOCK, file, lineno); + if (block == nullptr) + { + I_FatalError("Could not realloc %zu bytes in %s, line %d", size, file, lineno); + } + GC::ReportRealloc(oldsize, _msize(block)); + return block; +} +#else +void *M_Malloc_Dbg(size_t size, const char *file, int lineno) +{ + void *block = _malloc_dbg(size+sizeof(size_t), _NORMAL_BLOCK, file, lineno); + + if (block == nullptr) + I_FatalError("Could not malloc %zu bytes in %s, line %d", size, file, lineno); + + size_t *sizeStore = (size_t *) block; + *sizeStore = size; + block = sizeStore+1; + + GC::ReportAlloc(_msize(block)); + return block; +} + +void *M_Realloc_Dbg(void *memblock, size_t size, const char *file, int lineno) +{ + if (memblock == nullptr) + return M_Malloc_Dbg(size, file, lineno); + + size_t oldsize = _msize(memblock); + void *block = _realloc_dbg(((size_t*) memblock)-1, size+sizeof(size_t), _NORMAL_BLOCK, file, lineno); + + if (block == nullptr) + { + I_FatalError("Could not realloc %zu bytes in %s, line %d", size, file, lineno); + } + + size_t *sizeStore = (size_t *) block; + *sizeStore = size; + block = sizeStore+1; + + GC::ReportRealloc(oldsize, _msize(block)); + return block; +} +#endif +#endif + +void M_Free (void *block) +{ + if (block != nullptr) + { + GC::ReportDealloc(_msize(block)); +#if !defined(__solaris__) && !defined(__OpenBSD__) && !defined(__DragonFly__) + free(block); +#else + free(((size_t*) block)-1); +#endif + } +} + diff --git a/src/utility/m_alloc.h b/src/common/utility/m_alloc.h similarity index 77% rename from src/utility/m_alloc.h rename to src/common/utility/m_alloc.h index c91983aaf11..5f80584d6d1 100644 --- a/src/utility/m_alloc.h +++ b/src/common/utility/m_alloc.h @@ -35,22 +35,48 @@ #define __M_ALLOC_H__ #include +#include + +#if defined(__APPLE__) +#include +#define _msize(p) malloc_size(p) +#elif defined(__solaris__) || defined(__OpenBSD__) || defined(__DragonFly__) +#define _msize(p) (*((size_t*)(p)-1)) +#elif !defined(_WIN32) +#ifdef __FreeBSD__ +#include +#else +#include +#endif +#define _msize(p) malloc_usable_size(p) // from glibc/FreeBSD +#endif // These are the same as the same stdlib functions, // except they bomb out with a fatal error // when they can't get the memory. #if defined(_DEBUG) +#define M_Calloc(s,t) M_Calloc_Dbg(s, t, __FILE__, __LINE__) #define M_Malloc(s) M_Malloc_Dbg(s, __FILE__, __LINE__) #define M_Realloc(p,s) M_Realloc_Dbg(p, s, __FILE__, __LINE__) void *M_Malloc_Dbg (size_t size, const char *file, int lineno); void *M_Realloc_Dbg (void *memblock, size_t size, const char *file, int lineno); +inline void* M_Calloc_Dbg(size_t v1, size_t v2, const char* file, int lineno) +{ + auto p = M_Malloc_Dbg(v1 * v2, file, lineno); + memset(p, 0, v1 * v2); + return p; +} + #else void *M_Malloc (size_t size); void *M_Realloc (void *memblock, size_t size); +void* M_Calloc(size_t v1, size_t v2); + #endif + void M_Free (void *memblock); #endif //__M_ALLOC_H__ diff --git a/src/common/utility/m_argv.cpp b/src/common/utility/m_argv.cpp new file mode 100644 index 00000000000..0e8946058dc --- /dev/null +++ b/src/common/utility/m_argv.cpp @@ -0,0 +1,562 @@ +/* +** m_argv.cpp +** Manages command line arguments +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "m_argv.h" +#include "zstring.h" + +//=========================================================================== +// +// FArgs Default Constructor +// +//=========================================================================== + +FArgs::FArgs() +{ +} + +//=========================================================================== +// +// FArgs Copy Constructor +// +//=========================================================================== + +FArgs::FArgs(const FArgs &other) +: Argv(other.Argv) +{ +} + +//=========================================================================== +// +// FArgs Argv Constructor +// +//=========================================================================== + +FArgs::FArgs(int argc, char **argv) +{ + SetArgs(argc, argv); +} + +//=========================================================================== +// +// FArgs Argv Constructor +// +//=========================================================================== + +FArgs::FArgs(int argc, const char** argv) +{ + SetArgs(argc, const_cast(argv)); // Thanks, C++, for the inflexible const casting rules... +} + +//=========================================================================== +// +// FArgs String Argv Constructor +// +//=========================================================================== + +FArgs::FArgs(int argc, FString *argv) +{ + AppendArgs(argc, argv); +} + + + +//=========================================================================== +// +// FArgs Copy Operator +// +//=========================================================================== + +FArgs &FArgs::operator=(const FArgs &other) +{ + Argv = other.Argv; + return *this; +} + +//=========================================================================== +// +// FArgs :: SetArgs +// +//=========================================================================== + +void FArgs::SetArgs(int argc, char **argv) +{ + Argv.Resize(argc); + for (int i = 0; i < argc; ++i) + { + Argv[i] = argv[i]; + } +} + +//=========================================================================== +// +// FArgs :: FlushArgs +// +//=========================================================================== + +void FArgs::FlushArgs() +{ + Argv.Clear(); +} + +//=========================================================================== +// +// FArgs :: CheckParm +// +// Checks for the given parameter in the program's command line arguments. +// Returns the argument number (1 to argc-1) or 0 if not present +// +//=========================================================================== + +int stricmp(const char** check, const char* str) +{ + for (int i = 0; check[i]; i++) + { + if (!stricmp(check[i], str)) return 0; + } + return 1; // we do not care about order here. +} + +int FArgs::CheckParm(const char* check, int start) const +{ + const char* array[] = { check, nullptr }; + return CheckParm(array, start); +} + +int FArgs::CheckParm(const char** check, int start) const +{ + for (unsigned i = start; i < Argv.Size(); ++i) + { + if (0 == stricmp(check, Argv[i].GetChars())) + { + return i; + } + } + return 0; +} + +//=========================================================================== +// +// FArgs :: CheckParmList +// +// Returns the number of arguments after the parameter (if found) and also +// returns a pointer to the first argument. +// +//=========================================================================== + +int FArgs::CheckParmList(const char *check, FString **strings, int start) const +{ + unsigned int i, parmat = CheckParm(check, start); + + if (parmat == 0) + { + if (strings != nullptr) + { + *strings = nullptr; + } + return 0; + } + for (i = ++parmat; i < Argv.Size(); ++i) + { + if (Argv[i][0] == '-' || Argv[i][0] == '+') + { + break; + } + } + if (strings != nullptr) + { + *strings = &Argv[parmat]; + } + return i - parmat; +} + +//=========================================================================== +// +// FArgs :: CheckValue +// +// Like CheckParm, but it also checks that the parameter has a value after +// it and returns that or nullptr if not present. +// +//=========================================================================== + +const char *FArgs::CheckValue(const char *check) const +{ + int i = CheckParm(check); + + if (i > 0 && i < (int)Argv.Size() - 1) + { + i++; + return Argv[i][0] != '+' && Argv[i][0] != '-' ? Argv[i].GetChars() : nullptr; + } + else + { + return nullptr; + } +} + +//=========================================================================== +// +// FArgs :: TakeValue +// +// Like CheckValue, except it also removes the parameter and its argument +// (if present) from argv. +// +//=========================================================================== + +FString FArgs::TakeValue(const char *check) +{ + int i = CheckParm(check); + FString out; + + if (i > 0 && i < (int)Argv.Size()) + { + if (i < (int)Argv.Size() - 1 && Argv[i+1][0] != '+' && Argv[i+1][0] != '-') + { + out = Argv[i+1]; + Argv.Delete(i, 2); // Delete the parm and its value. + } + else + { + Argv.Delete(i); // Just delete the parm, since it has no value. + } + } + return out; +} + +//=========================================================================== +// +// FArgs :: RemoveArg +// +//=========================================================================== + +void FArgs::RemoveArgs(const char *check) +{ + int i = CheckParm(check); + + if (i > 0 && i < (int)Argv.Size() - 1) + { + do + { + RemoveArg(i); + } + while (Argv[i][0] != '+' && Argv[i][0] != '-' && i < (int)Argv.Size() - 1); + } +} + +//=========================================================================== +// +// FArgs :: GetArg +// +// Gets the argument at a particular position. +// +//=========================================================================== + +const char *FArgs::GetArg(int arg) const +{ + return ((unsigned)arg < Argv.Size()) ? Argv[arg].GetChars() : nullptr; +} + +//=========================================================================== +// +// FArgs :: GetArgList +// +// Returns a pointer to the FString at a particular position. +// +//=========================================================================== + +FString *FArgs::GetArgList(int arg) const +{ + return ((unsigned)arg < Argv.Size()) ? &Argv[arg] : nullptr; +} + +//=========================================================================== +// +// FArgs :: NumArgs +// +//=========================================================================== + +int FArgs::NumArgs() const +{ + return (int)Argv.Size(); +} + +//=========================================================================== +// +// FArgs :: AppendArg +// +// Adds another argument to argv. Invalidates any previous results from +// GetArgList(). +// +//=========================================================================== + +void FArgs::AppendArg(FString arg) +{ + Argv.Push(arg); +} + +//=========================================================================== +// +// FArgs :: AppendArgs +// +// Adds an array of FStrings to argv. +// +//=========================================================================== + +void FArgs::AppendArgs(int argc, const FString *argv) +{ + if (argv != NULL && argc > 0) + { + Argv.Grow(argc); + for (int i = 0; i < argc; ++i) + { + Argv.Push(argv[i]); + } + } +} + +//=========================================================================== +// +// FArgs :: AppendArgsString +// +// Adds extra args as a space-separated string, supporting simple quoting, and inserting -file args into the right place +// +//=========================================================================== + + +void FArgs::AppendArgsString(FString argv) +{ + auto file_index = Argv.Find("-file"); + auto files_end = file_index + 1; + + for (; files_end < Argv.Size() && Argv[files_end][0] != '-' && Argv[files_end][0] != '+'; ++files_end); + + if(file_index == Argv.Size()) + { + Argv.Push("-file"); + } + + bool inserting_file = true; + + argv.StripLeftRight(); + + size_t i = 0; + size_t lastSection = 0; + size_t lastStart = 0; + char lastQuoteType = 0; + + FString tmp; + bool has_tmp = false; + + for(i = 0; i < argv.Len(); i++) + { + if(argv[i] == ' ') + { + FString arg = tmp + argv.Mid(lastSection, i - lastSection); + + if(arg[0] == '-' || arg[0] == '+') inserting_file = false; + + if(inserting_file) + { + Argv.Insert(files_end++, arg); + } + else if(arg.Compare("-file") == 0) + { + inserting_file = true; + } + else + { + files_end++; + Argv.Insert(file_index++, arg); + } + + lastSection = i + 1; + tmp = ""; + has_tmp = false; + for(;(i + 1) < argv.Len() && argv[i + 1] == ' '; i++, lastSection++); + lastStart = i + 1; + } + else if(argv[i] == '\'' || argv[i] == '"') + { + lastQuoteType = argv[i]; + tmp += argv.Mid(lastSection, i - lastSection); + has_tmp = true; + bool wasSlash = false; + + for(i++; (argv[i] != lastQuoteType || wasSlash) && i < argv.Len(); i++) + { + if(i == '\\' && !wasSlash) + { + wasSlash = true; + } + else + { + tmp += argv[i]; + wasSlash = false; + } + } + lastSection = i + 1; + } + } + + if(lastSection != i) + { // ended on an unquoted section + FString arg = tmp + argv.Mid(lastSection); + if(inserting_file) + { + Argv.Insert(files_end, arg); + } + else if(arg.Compare("-file") != 0) + { + Argv.Insert(file_index, arg); + } + } + else if(has_tmp) + { // ended on a quote + if(inserting_file) + { + Argv.Insert(files_end, tmp); + } + else if(tmp.Compare("-file") != 0) + { + Argv.Insert(file_index, tmp); + } + } +} +//=========================================================================== +// +// FArgs :: RemoveArg +// +// Removes a single argument from argv. +// +//=========================================================================== + +void FArgs::RemoveArg(int argindex) +{ + Argv.Delete(argindex); +} + +//=========================================================================== +// +// FArgs :: CollectFiles +// +// Takes all arguments after any instance of -param and any arguments before +// all switches that end in .extension and combines them into a single +// -switch block at the end of the arguments. If extension is nullptr, then +// every parameter before the first switch is added after this -param. +// +//=========================================================================== + +void FArgs::CollectFiles(const char* param, const char* extension) +{ + const char* array[] = { param, nullptr }; + CollectFiles(param, array, extension); +} + +void FArgs::CollectFiles(const char *finalname, const char **param, const char *extension) +{ + TArray work; + unsigned int i; + size_t extlen = extension == nullptr ? 0 : strlen(extension); + + // Step 1: Find suitable arguments before the first switch. + i = 1; + while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+') + { + bool useit; + + if (extlen > 0) + { // Argument's extension must match. + size_t len = Argv[i].Len(); + useit = (len >= extlen && stricmp(&Argv[i][len - extlen], extension) == 0); + } + else + { // Anything will do so long as it's before the first switch. + useit = true; + } + if (useit) + { + work.Push(Argv[i]); + Argv.Delete(i); + } + else + { + i++; + } + } + + // Step 2: Find each occurence of -param and add its arguments to work. + while ((i = CheckParm(param, i)) > 0) + { + Argv.Delete(i); + while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+') + { + work.Push(Argv[i]); + Argv.Delete(i); + } + } + + // Optional: Replace short path names with long path names +#if 0 //def _WIN32 + for (i = 0; i < work.Size(); ++i) + { + work[i] = I_GetLongPathName(work[i]); + } +#endif + + // Step 3: Add work back to Argv, as long as it's non-empty. + if (work.Size() > 0) + { + Argv.Push(finalname); + AppendArgs(work.Size(), &work[0]); + } +} + +//=========================================================================== +// +// FArgs :: GatherFiles +// +// Returns all the arguments after the first instance of -param. If you want +// to combine more than one or get switchless stuff included, you need to +// call CollectFiles first. +// +//=========================================================================== + +FArgs *FArgs::GatherFiles(const char *param) const +{ + FString *files; + int filecount; + + filecount = CheckParmList(param, &files); + return new FArgs(filecount, files); +} diff --git a/src/common/utility/m_argv.h b/src/common/utility/m_argv.h new file mode 100644 index 00000000000..d12da9a5fc8 --- /dev/null +++ b/src/common/utility/m_argv.h @@ -0,0 +1,114 @@ +/* +** m_argv.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __M_ARGV_H__ +#define __M_ARGV_H__ + +#include "tarray.h" +#include "zstring.h" + +// +// MISC +// +class FArgs +{ +public: + + typedef TIterator iterator; + typedef TIterator const_iterator; + typedef FString value_type; + + iterator begin() + { + return Argv.begin(); + } + const_iterator begin() const + { + return Argv.begin(); + } + const_iterator cbegin() const + { + return Argv.begin(); + } + + iterator end() + { + return Argv.end(); + } + const_iterator end() const + { + return Argv.end(); + } + const_iterator cend() const + { + return Argv.end(); + } + + FArgs(); + FArgs(const FArgs &args); + FArgs(int argc, char **argv); + FArgs(int argc, const char** argv); + FArgs(int argc, FString *argv); + + FArgs &operator=(const FArgs &other); + const FString& operator[](size_t index) { return Argv[index]; } + + void AppendArg(FString arg); + void AppendArgs(int argc, const FString *argv); + void AppendArgsString(FString argv); + void RemoveArg(int argindex); + void RemoveArgs(const char *check); + void SetArgs(int argc, char **argv); + void CollectFiles(const char *finalname, const char** param, const char* extension); + void CollectFiles(const char *param, const char *extension); + FArgs *GatherFiles(const char *param) const; + void SetArg(int argnum, const char *arg); + + int CheckParm(const char *check, int start=1) const; // Returns the position of the given parameter in the arg list (0 if not found). + int CheckParm(const char** check, int start = 1) const; // Returns the position of the given parameter in the arg list (0 if not found). Allows checking for multiple switches + int CheckParmList(const char *check, FString **strings, int start=1) const; + const char *CheckValue(const char *check) const; + const char *GetArg(int arg) const; + FString *GetArgList(int arg) const; + FString TakeValue(const char *check); + int NumArgs() const; + void FlushArgs(); + TArray& Array() { return Argv; } + +private: + TArray Argv; +}; + +extern FArgs *Args; + +#endif //__M_ARGV_H__ diff --git a/src/common/utility/m_bbox.h b/src/common/utility/m_bbox.h new file mode 100644 index 00000000000..7f622a6ba9f --- /dev/null +++ b/src/common/utility/m_bbox.h @@ -0,0 +1,94 @@ + +#ifndef __M_BBOX_H__ +#define __M_BBOX_H__ + +#include +#include "vectors.h" + +enum +{ + BOXTOP, + BOXBOTTOM, + BOXLEFT, + BOXRIGHT +}; // bbox coordinates + + +class FBoundingBox +{ +public: + FBoundingBox() + { + ClearBox(); + } + + FBoundingBox(double left, double bottom, double right, double top) + { + m_Box[BOXTOP] = top; + m_Box[BOXLEFT] = left; + m_Box[BOXRIGHT] = right; + m_Box[BOXBOTTOM] = bottom; + } + + FBoundingBox(double x, double y, double radius) + { + setBox(x, y, radius); + } + + + void setBox(double x, double y, double radius) + { + m_Box[BOXTOP] = y + radius; + m_Box[BOXLEFT] = x - radius; + m_Box[BOXRIGHT] = x + radius; + m_Box[BOXBOTTOM] = y - radius; + } + + void ClearBox () + { + m_Box[BOXTOP] = m_Box[BOXRIGHT] = -FLT_MAX; + m_Box[BOXBOTTOM] = m_Box[BOXLEFT] = FLT_MAX; + } + + // Returns a bounding box that encloses both bounding boxes + FBoundingBox operator | (const FBoundingBox &box2) const + { + return FBoundingBox(m_Box[BOXLEFT] < box2.m_Box[BOXLEFT] ? m_Box[BOXLEFT] : box2.m_Box[BOXLEFT], + m_Box[BOXBOTTOM] < box2.m_Box[BOXBOTTOM] ? m_Box[BOXBOTTOM] : box2.m_Box[BOXBOTTOM], + m_Box[BOXRIGHT] > box2.m_Box[BOXRIGHT] ? m_Box[BOXRIGHT] : box2.m_Box[BOXRIGHT], + m_Box[BOXTOP] > box2.m_Box[BOXTOP] ? m_Box[BOXTOP] : box2.m_Box[BOXTOP]); + } + + void AddToBox(const DVector2 &pos) + { + if (pos.X < m_Box[BOXLEFT]) + m_Box[BOXLEFT] = pos.X; + if (pos.X > m_Box[BOXRIGHT]) + m_Box[BOXRIGHT] = pos.X; + + if (pos.Y < m_Box[BOXBOTTOM]) + m_Box[BOXBOTTOM] = pos.Y; + if (pos.Y > m_Box[BOXTOP]) + m_Box[BOXTOP] = pos.Y; + } + + bool CheckOverlap(const FBoundingBox &box2) + { + bool hori = (Left() > box2.Right()) || (Right() < box2.Left()); + bool vert = (Bottom() > box2.Top()) || (Top() < box2.Bottom()); + return !(hori || vert); // [DVR] For alternative space partition + } + + inline double Top () const { return m_Box[BOXTOP]; } + inline double Bottom () const { return m_Box[BOXBOTTOM]; } + inline double Left () const { return m_Box[BOXLEFT]; } + inline double Right () const { return m_Box[BOXRIGHT]; } + + void Set(int index, double value) {m_Box[index] = value;} + +protected: + double m_Box[4]; +}; + + +#endif //__M_BBOX_H__ diff --git a/src/common/utility/m_fixed.h b/src/common/utility/m_fixed.h new file mode 100644 index 00000000000..09d29769348 --- /dev/null +++ b/src/common/utility/m_fixed.h @@ -0,0 +1,60 @@ +#ifndef __M_FIXED__ +#define __M_FIXED__ + +#include +#include +#include "basics.h" + + +__forceinline constexpr int32_t MulScale(int32_t a, int32_t b, int32_t shift) { return (int32_t)(((int64_t)a * b) >> shift); } +__forceinline constexpr int32_t DMulScale(int32_t a, int32_t b, int32_t c, int32_t d, int32_t shift) { return (int32_t)(((int64_t)a * b + (int64_t)c * d) >> shift); } +__forceinline constexpr int32_t DivScale(int32_t a, int32_t b, int shift) { return (int32_t)(((int64_t)a << shift) / b); } +__forceinline constexpr int64_t DivScaleL(int64_t a, int64_t b, int shift) { return ((a << shift) / b); } + +#include "xs_Float.h" + +template +constexpr fixed_t FloatToFixed(double f) +{ + return int(f * (1 << b)); +} + +constexpr fixed_t FloatToFixed(double f, int b) +{ + return int(f * (1 << b)); +} + +template +inline constexpr fixed_t IntToFixed(int32_t f) +{ + return f << b; +} + +template +inline constexpr double FixedToFloat(fixed_t f) +{ + return f * (1. / (1 << b)); +} + +inline constexpr double FixedToFloat(fixed_t f, int b) +{ + return f * (1. / (1 << b)); +} + +template +inline constexpr int32_t FixedToInt(fixed_t f) +{ + return (f + (1 << (b-1))) >> b; +} + +inline unsigned FloatToAngle(double f) +{ + return xs_CRoundToInt((f)* (0x40000000 / 90.)); +} + +#define FLOAT2FIXED(f) FloatToFixed(f) +#define FIXED2FLOAT(f) float(FixedToFloat(f)) +#define FIXED2DBL(f) FixedToFloat(f) + + +#endif diff --git a/src/utility/m_swap.h b/src/common/utility/m_swap.h similarity index 100% rename from src/utility/m_swap.h rename to src/common/utility/m_swap.h diff --git a/src/utility/matrix.cpp b/src/common/utility/matrix.cpp similarity index 91% rename from src/utility/matrix.cpp rename to src/common/utility/matrix.cpp index 6b7e64df1e8..3d84d48e70a 100644 --- a/src/utility/matrix.cpp +++ b/src/common/utility/matrix.cpp @@ -21,7 +21,7 @@ This is a simplified version of VSMatrix that has been adjusted for GZDoom's nee static inline FLOATTYPE DegToRad(FLOATTYPE degrees) { - return (FLOATTYPE)(degrees * (M_PI / 180.0f)); + return (FLOATTYPE)(degrees * (pi::pif() / 180.0f)); }; // sets the square matrix mat to the identity matrix, @@ -58,7 +58,7 @@ VSMatrix::loadIdentity() void VSMatrix::multMatrix(const FLOATTYPE *aMatrix) { - + FLOATTYPE res[16]; for (int i = 0; i < 4; ++i) @@ -98,6 +98,21 @@ VSMatrix::multMatrix(const float *aMatrix) } #endif +void VSMatrix::multQuaternion(const TVector4& q) +{ + FLOATTYPE m[16] = { FLOATTYPE(0.0) }; + m[0 * 4 + 0] = FLOATTYPE(1.0) - FLOATTYPE(2.0) * q.Y * q.Y - FLOATTYPE(2.0) * q.Z * q.Z; + m[1 * 4 + 0] = FLOATTYPE(2.0) * q.X * q.Y - FLOATTYPE(2.0) * q.W * q.Z; + m[2 * 4 + 0] = FLOATTYPE(2.0) * q.X * q.Z + FLOATTYPE(2.0) * q.W * q.Y; + m[0 * 4 + 1] = FLOATTYPE(2.0) * q.X * q.Y + FLOATTYPE(2.0) * q.W * q.Z; + m[1 * 4 + 1] = FLOATTYPE(1.0) - FLOATTYPE(2.0) * q.X * q.X - FLOATTYPE(2.0) * q.Z * q.Z; + m[2 * 4 + 1] = FLOATTYPE(2.0) * q.Y * q.Z - FLOATTYPE(2.0) * q.W * q.X; + m[0 * 4 + 2] = FLOATTYPE(2.0) * q.X * q.Z - FLOATTYPE(2.0) * q.W * q.Y; + m[1 * 4 + 2] = FLOATTYPE(2.0) * q.Y * q.Z + FLOATTYPE(2.0) * q.W * q.X; + m[2 * 4 + 2] = FLOATTYPE(1.0) - FLOATTYPE(2.0) * q.X * q.X - FLOATTYPE(2.0) * q.Y * q.Y; + m[3 * 4 + 3] = FLOATTYPE(1.0); + multMatrix(m); +} // gl LoadMatrix implementation @@ -129,6 +144,29 @@ VSMatrix::translate(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z) mMatrix[14] = mMatrix[2] * x + mMatrix[6] * y + mMatrix[10] * z + mMatrix[14]; } +void VSMatrix::transpose() +{ + FLOATTYPE original[16]; + for (int cnt = 0; cnt < 16; cnt++) + original[cnt] = mMatrix[cnt]; + + mMatrix[0] = original[0]; + mMatrix[1] = original[4]; + mMatrix[2] = original[8]; + mMatrix[3] = original[12]; + mMatrix[4] = original[1]; + mMatrix[5] = original[5]; + mMatrix[6] = original[9]; + mMatrix[7] = original[13]; + mMatrix[8] = original[2]; + mMatrix[9] = original[6]; + mMatrix[10] = original[10]; + mMatrix[11] = original[14]; + mMatrix[12] = original[3]; + mMatrix[13] = original[7]; + mMatrix[14] = original[11]; + mMatrix[15] = original[15]; +} // gl Scale implementation void @@ -164,19 +202,19 @@ VSMatrix::rotate(FLOATTYPE angle, FLOATTYPE x, FLOATTYPE y, FLOATTYPE z) mat[4] = v[0] * v[1] * (1 - co) - v[2] * si; mat[8] = v[0] * v[2] * (1 - co) + v[1] * si; mat[12]= 0.0f; - + mat[1] = v[0] * v[1] * (1 - co) + v[2] * si; // mat[5] = y2 + (x2 + z2) * co; mat[5] = co + y2 * (1 - co); mat[9] = v[1] * v[2] * (1 - co) - v[0] * si; mat[13]= 0.0f; - + mat[2] = v[0] * v[2] * (1 - co) - v[1] * si; mat[6] = v[1] * v[2] * (1 - co) + v[0] * si; // mat[10]= z2 + (x2 + y2) * co; mat[10]= co + z2 * (1 - co); mat[14]= 0.0f; - + mat[3] = 0.0f; mat[7] = 0.0f; mat[11]= 0.0f; @@ -243,7 +281,7 @@ VSMatrix::lookAt(FLOATTYPE xPos, FLOATTYPE yPos, FLOATTYPE zPos, void VSMatrix::perspective(FLOATTYPE fov, FLOATTYPE ratio, FLOATTYPE nearp, FLOATTYPE farp) { - FLOATTYPE f = 1.0f / tan (fov * (M_PI / 360.0f)); + FLOATTYPE f = 1.0f / tan (fov * (pi::pif() / 360.0f)); loadIdentity(); mMatrix[0] = f / ratio; @@ -323,9 +361,9 @@ VSMatrix::multMatrixPoint(const FLOATTYPE *point, FLOATTYPE *res) { res[i] = 0.0f; - + for (int j = 0; j < 4; j++) { - + res[i] += point[j] * mMatrix[j*4 + i]; } } @@ -392,13 +430,6 @@ VSMatrix::length(const FLOATTYPE *a) { } -static inline int -M3(int i, int j) -{ - return (i*3+j); -}; - - // computes the derived normal matrix for the view matrix void @@ -451,7 +482,7 @@ VSMatrix::computeNormalMatrix(const FLOATTYPE *aMatrix) void VSMatrix::multMatrix(FLOATTYPE *resMat, const FLOATTYPE *aMatrix) { - + FLOATTYPE res[16]; for (int i = 0; i < 4; ++i) diff --git a/src/utility/matrix.h b/src/common/utility/matrix.h similarity index 97% rename from src/utility/matrix.h rename to src/common/utility/matrix.h index 22774845aaa..265981e1bca 100644 --- a/src/utility/matrix.h +++ b/src/common/utility/matrix.h @@ -22,7 +22,6 @@ #include #include "vectors.h" -#include "doomtype.h" #ifdef USE_DOUBLE typedef double FLOATTYPE; @@ -34,10 +33,8 @@ class VSMatrix { public: - VSMatrix() - { - } - + VSMatrix() = default; + VSMatrix(int) { loadIdentity(); @@ -56,6 +53,7 @@ class VSMatrix { { multMatrix(aMatrix.mMatrix); } + void multQuaternion(const TVector4& q); void loadMatrix(const FLOATTYPE *aMatrix); #ifdef USE_DOUBLE void loadMatrix(const float *aMatrix); @@ -138,11 +136,11 @@ class Matrix3x4 // used like a 4x4 matrix with the last row always being (0,0,0, m[0][0] *=x; m[1][0] *=x; m[2][0] *=x; - + m[0][1] *=y; m[1][1] *=y; m[2][1] *=y; - + m[0][2] *=z; m[1][2] *=z; m[2][2] *=z; @@ -154,7 +152,7 @@ class Matrix3x4 // used like a 4x4 matrix with the last row always being (0,0,0, FVector3 axis(ax, ay, az); axis.MakeUnit(); - double c = cos(angle * M_PI/180.), s = sin(angle * M_PI/180.), t = 1 - c; + double c = cos(angle * pi::pi()/180.), s = sin(angle * pi::pi()/180.), t = 1 - c; double sx = s*axis.X, sy = s*axis.Y, sz = s*axis.Z; double tx, ty, txx, tyy, u, v; diff --git a/src/utility/memarena.cpp b/src/common/utility/memarena.cpp similarity index 94% rename from src/utility/memarena.cpp rename to src/common/utility/memarena.cpp index f5544708d6c..83621df47ad 100644 --- a/src/utility/memarena.cpp +++ b/src/common/utility/memarena.cpp @@ -37,9 +37,17 @@ ** with destructors). */ -#include "doomtype.h" +#include "basics.h" #include "memarena.h" -#include "c_dispatch.h" +#include "cmdlib.h" + +#if __has_include("m_alloc.h") + #include "m_alloc.h" +#else + #define M_Malloc malloc + #define M_Realloc realloc + #define M_Free free +#endif struct FMemArena::Block { @@ -116,6 +124,21 @@ void *FMemArena::Alloc(size_t size) return iAlloc((size + 15) & ~15); } +void* FMemArena::Calloc(size_t size) +{ + size = (size + 15) & ~15; + auto mem = iAlloc(size); + memset(mem, 0, size); + return mem; +} + +const char* FMemArena::Strdup(const char* str) +{ + char* p = (char*)Alloc(strlen(str) + 1); + strcpy(p, str); + return p; +} + //========================================================================== // // FMemArena :: FreeAll @@ -158,7 +181,7 @@ void FMemArena::FreeAllBlocks() // //========================================================================== -void FMemArena::DumpInfo() +FString FMemArena::DumpInfo() { size_t allocated = 0; size_t used = 0; @@ -167,7 +190,7 @@ void FMemArena::DumpInfo() allocated += BlockSize; used += BlockSize - ((char*)block->Limit - (char*)block->Avail); } - Printf("%zu bytes allocated, %zu bytes in use\n", allocated, used); + return FStringf("%zu bytes allocated, %zu bytes in use\n", allocated, used); } //========================================================================== @@ -319,7 +342,7 @@ FString *FSharedStringArena::Alloc(const FString &source) unsigned int hash; Node *strnode; - strnode = FindString(source, source.Len(), hash); + strnode = FindString(source.GetChars(), source.Len(), hash); if (strnode == NULL) { strnode = (Node *)iAlloc(sizeof(Node)); diff --git a/src/utility/memarena.h b/src/common/utility/memarena.h similarity index 97% rename from src/utility/memarena.h rename to src/common/utility/memarena.h index f8a15aefab6..8c1def64dca 100644 --- a/src/utility/memarena.h +++ b/src/common/utility/memarena.h @@ -44,9 +44,11 @@ class FMemArena ~FMemArena(); void *Alloc(size_t size); + void* Calloc(size_t size); + const char* Strdup(const char*); void FreeAll(); void FreeAllBlocks(); - void DumpInfo(); + FString DumpInfo(); void DumpData(FILE *f); protected: diff --git a/src/utility/name.cpp b/src/common/utility/name.cpp similarity index 97% rename from src/utility/name.cpp rename to src/common/utility/name.cpp index ecedcf0f313..c9960ca934a 100644 --- a/src/utility/name.cpp +++ b/src/common/utility/name.cpp @@ -34,8 +34,9 @@ #include #include "name.h" -#include "c_dispatch.h" -#include "c_console.h" +#include "superfasthash.h" +#include "cmdlib.h" +#include "m_alloc.h" // MACROS ------------------------------------------------------------------ @@ -72,8 +73,13 @@ bool FName::NameManager::Inited; static const char *PredefinedNames[] = { #define xx(n) #n, +#define xy(n, s) s, #include "namedef.h" +#if __has_include("namedef_custom.h") + #include "namedef_custom.h" +#endif #undef xx +#undef xy }; // CODE -------------------------------------------------------------------- @@ -269,7 +275,7 @@ FName::NameManager::~NameManager() { NameBlock *block, *next; - C_ClearTabCommands(); + //C_ClearTabCommands(); for (block = Blocks; block != NULL; block = next) { diff --git a/src/utility/name.h b/src/common/utility/name.h similarity index 87% rename from src/utility/name.h rename to src/common/utility/name.h index 76324fe7c36..fe2424f45f0 100644 --- a/src/utility/name.h +++ b/src/common/utility/name.h @@ -34,11 +34,19 @@ #ifndef NAME_H #define NAME_H +#include "tarray.h" +#include "zstring.h" + enum ENamedName { #define xx(n) NAME_##n, +#define xy(n, s) NAME_##n, #include "namedef.h" +#if __has_include("namedef_custom.h") + #include "namedef_custom.h" +#endif #undef xx +#undef xy }; class FString; @@ -50,19 +58,17 @@ class FName FName (const char *text) { Index = NameData.FindName (text, false); } FName (const char *text, bool noCreate) { Index = NameData.FindName (text, noCreate); } FName (const char *text, size_t textlen, bool noCreate) { Index = NameData.FindName (text, textlen, noCreate); } - FName (const FString &text); - FName (const FString &text, bool noCreate); + FName(const FString& text) { Index = NameData.FindName(text.GetChars(), text.Len(), false); } + FName(const FString& text, bool noCreate) { Index = NameData.FindName(text.GetChars(), text.Len(), noCreate); } FName (const FName &other) = default; FName (ENamedName index) { Index = index; } // ~FName () {} // Names can be added but never removed. int GetIndex() const { return Index; } - operator int() const { return Index; } const char *GetChars() const { return NameData.NameArray[Index].Text; } - operator const char *() const { return NameData.NameArray[Index].Text; } FName &operator = (const char *text) { Index = NameData.FindName (text, false); return *this; } - FName &operator = (const FString &text); + FName& operator = (const FString& text) { Index = NameData.FindName(text.GetChars(), text.Len(), false); return *this; } FName &operator = (const FName &other) = default; FName &operator = (ENamedName index) { Index = index; return *this; } @@ -122,4 +128,13 @@ class FName static NameManager NameData; }; + +template<> struct THashTraits +{ + hash_t Hash(FName key) + { + return key.GetIndex(); + } + int Compare(FName left, FName right) { return left != right; } +}; #endif diff --git a/src/common/utility/palentry.h b/src/common/utility/palentry.h new file mode 100644 index 00000000000..4acbbfff888 --- /dev/null +++ b/src/common/utility/palentry.h @@ -0,0 +1,101 @@ +#pragma once + +#include +#include + +// Beware of windows.h :( +#ifdef max +#undef min +#undef max +#endif + +struct PalEntry +{ + PalEntry() = default; + PalEntry(const PalEntry&) = default; + constexpr PalEntry (uint32_t argb) : d(argb) { } + operator uint32_t () const { return d; } + void SetRGB(PalEntry other) + { + d = other.d & 0xffffff; + } + PalEntry Modulate(PalEntry other) const + { + if (isWhite()) + { + return other; + } + else if (other.isWhite()) + { + return *this; + } + else + { + other.r = (r * other.r) / 255; + other.g = (g * other.g) / 255; + other.b = (b * other.b) / 255; + return other; + } + } + constexpr int Luminance() const + { + return (r * 77 + g * 143 + b * 37) >> 8; + } + + constexpr int Amplitude() const + { + return std::max(r, std::max(g, b)); + } + + constexpr void Decolorize() // this for 'nocoloredspritelighting' and not the same as desaturation. The normal formula results in a value that's too dark. + { + int v = (r + g + b); + r = g = b = ((255*3) + v + v) / 9; + } + constexpr bool isBlack() const + { + return (d & 0xffffff) == 0; + } + constexpr bool isWhite() const + { + return (d & 0xffffff) == 0xffffff; + } + PalEntry &operator= (const PalEntry &other) = default; + constexpr PalEntry &operator= (uint32_t other) { d = other; return *this; } + constexpr PalEntry InverseColor() const { PalEntry nc(a, 255 - r, 255 - g, 255 - b); return nc; } +#ifdef __BIG_ENDIAN__ + constexpr PalEntry (uint8_t ir, uint8_t ig, uint8_t ib) : a(0), r(ir), g(ig), b(ib) {} + constexpr PalEntry (uint8_t ia, uint8_t ir, uint8_t ig, uint8_t ib) : a(ia), r(ir), g(ig), b(ib) {} + union + { + struct + { + uint8_t a,r,g,b; + }; + uint32_t d; + }; +#else + constexpr PalEntry (uint8_t ir, uint8_t ig, uint8_t ib) : b(ib), g(ig), r(ir), a(0) {} + constexpr PalEntry (uint8_t ia, uint8_t ir, uint8_t ig, uint8_t ib) : b(ib), g(ig), r(ir), a(ia) {} + union + { + struct + { + uint8_t b,g,r,a; + }; + uint32_t d; + }; +#endif +}; + +constexpr inline int Luminance(int r, int g, int b) +{ + return (r * 77 + g * 143 + b * 37) >> 8; +} + +#define APART(c) (((c)>>24)&0xff) +#define RPART(c) (((c)>>16)&0xff) +#define GPART(c) (((c)>>8)&0xff) +#define BPART(c) ((c)&0xff) +#define MAKERGB(r,g,b) uint32_t(((r)<<16)|((g)<<8)|(b)) +#define MAKEARGB(a,r,g,b) uint32_t(((a)<<24)|((r)<<16)|((g)<<8)|(b)) diff --git a/src/common/utility/palette.cpp b/src/common/utility/palette.cpp new file mode 100644 index 00000000000..03517c1ba55 --- /dev/null +++ b/src/common/utility/palette.cpp @@ -0,0 +1,991 @@ +/* +** palette.cpp +** Palette and color utility functions +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include "palutil.h" +#include "palentry.h" +#include "sc_man.h" +#include "files.h" +#include "filesystem.h" +#include "printf.h" +#include "m_swap.h" +#include "cmdlib.h" + +#include "m_png.h" + +/****************************/ +/* Palette management stuff */ +/****************************/ + +int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num, const uint8_t* indexmap) +{ + const PalEntry *pal = (const PalEntry *)pal_in; + int bestcolor = first; + int bestdist = 257 * 257 + 257 * 257 + 257 * 257; + + for (int color = first; color < num; color++) + { + int co = indexmap ? indexmap[color] : color; + int x = r - pal[co].r; + int y = g - pal[co].g; + int z = b - pal[co].b; + int dist = x*x + y*y + z*z; + if (dist < bestdist) + { + if (dist == 0) + return co; + + bestdist = dist; + bestcolor = co; + } + } + return bestcolor; +} + + +// [SP] Re-implemented BestColor for more precision rather than speed. This function is only ever called once until the game palette is changed. + +int PTM_BestColor (const uint32_t *pal_in, int r, int g, int b, bool reverselookup, float powtable_val, int first, int num) +{ + const PalEntry *pal = (const PalEntry *)pal_in; + static double powtable[256]; + static bool firstTime = true; + static float trackpowtable = 0.; + + double fbestdist = DBL_MAX, fdist; + int bestcolor = 0; + + if (firstTime || trackpowtable != powtable_val) + { + auto pt = powtable_val; + trackpowtable = pt; + firstTime = false; + for (int x = 0; x < 256; x++) powtable[x] = pow((double)x/255, (double)pt); + } + + for (int color = first; color < num; color++) + { + double x = powtable[abs(r-pal[color].r)]; + double y = powtable[abs(g-pal[color].g)]; + double z = powtable[abs(b-pal[color].b)]; + fdist = x + y + z; + if (color == first || (reverselookup?(fdist <= fbestdist):(fdist < fbestdist))) + { + if (fdist == 0 && !reverselookup) + return color; + + fbestdist = fdist; + bestcolor = color; + } + } + return bestcolor; +} + +#if defined(_M_X64) || defined(_M_IX86) || defined(__i386__) || defined(__amd64__) + +#ifdef _MSC_VER +#include +#endif +#include + +static void DoBlending_SSE2(const PalEntry *from, PalEntry *to, int count, int r, int g, int b, int a) +{ + __m128i blendcolor; + __m128i blendalpha; + __m128i zero; + __m128i blending256; + __m128i color1; + __m128i color2; + size_t unaligned; + + unaligned = ((size_t)from | (size_t)to) & 0xF; + +#if defined(__amd64__) || defined(_M_X64) + int64_t color; + + blending256 = _mm_set_epi64x(0x10001000100ll, 0x10001000100ll); + + color = ((int64_t)r << 32) | (g << 16) | b; + blendcolor = _mm_set_epi64x(color, color); + + color = ((int64_t)a << 32) | (a << 16) | a; + blendalpha = _mm_set_epi64x(color, color); +#else + int color; + + blending256 = _mm_set_epi32(0x100, 0x1000100, 0x100, 0x1000100); + + color = (g << 16) | b; + blendcolor = _mm_set_epi32(r, color, r, color); + + color = (a << 16) | a; + blendalpha = _mm_set_epi32(a, color, a, color); +#endif + + blendcolor = _mm_mullo_epi16(blendcolor, blendalpha); // premultiply blend by alpha + blendalpha = _mm_subs_epu16(blending256, blendalpha); // one minus alpha + + zero = _mm_setzero_si128(); + + if (unaligned) + { + for (count >>= 2; count > 0; --count) + { + color1 = _mm_loadu_si128((__m128i *)from); + from += 4; + color2 = _mm_unpackhi_epi8(color1, zero); + color1 = _mm_unpacklo_epi8(color1, zero); + color1 = _mm_mullo_epi16(blendalpha, color1); + color2 = _mm_mullo_epi16(blendalpha, color2); + color1 = _mm_adds_epu16(blendcolor, color1); + color2 = _mm_adds_epu16(blendcolor, color2); + color1 = _mm_srli_epi16(color1, 8); + color2 = _mm_srli_epi16(color2, 8); + _mm_storeu_si128((__m128i *)to, _mm_packus_epi16(color1, color2)); + to += 4; + } + } + else + { + for (count >>= 2; count > 0; --count) + { + color1 = _mm_load_si128((__m128i *)from); + from += 4; + color2 = _mm_unpackhi_epi8(color1, zero); + color1 = _mm_unpacklo_epi8(color1, zero); + color1 = _mm_mullo_epi16(blendalpha, color1); + color2 = _mm_mullo_epi16(blendalpha, color2); + color1 = _mm_adds_epu16(blendcolor, color1); + color2 = _mm_adds_epu16(blendcolor, color2); + color1 = _mm_srli_epi16(color1, 8); + color2 = _mm_srli_epi16(color2, 8); + _mm_store_si128((__m128i *)to, _mm_packus_epi16(color1, color2)); + to += 4; + } + } +} +#endif + +void DoBlending (const PalEntry *from, PalEntry *to, int count, int r, int g, int b, int a) +{ + if (a == 0) + { + if (from != to) + { + memcpy (to, from, count * sizeof(uint32_t)); + } + return; + } + else if (a == 256) + { + uint32_t t = MAKERGB(r,g,b); + int i; + + for (i = 0; i < count; i++) + { + to[i] = t; + } + return; + } +#if defined(_M_X64) || defined(_M_IX86) || defined(__i386__) || defined(__amd64__) + else if (count >= 4) + { + int not3count = count & ~3; + DoBlending_SSE2 (from, to, not3count, r, g, b, a); + count &= 3; + if (count <= 0) + { + return; + } + from += not3count; + to += not3count; + } +#endif + int i, ia; + + ia = 256 - a; + r *= a; + g *= a; + b *= a; + + for (i = count; i > 0; i--, to++, from++) + { + to->r = (r + from->r * ia) >> 8; + to->g = (g + from->g * ia) >> 8; + to->b = (b + from->b * ia) >> 8; + } +} + +/****** Colorspace Conversion Functions ******/ + +// Code from http://www.cs.rit.edu/~yxv4997/t_convert.html + +// r,g,b values are from 0 to 1 +// h = [0,360], s = [0,1], v = [0,1] +// if s == 0, then h = -1 (undefined) + +// Green Doom guy colors: +// RGB - 0: { .46 1 .429 } 7: { .254 .571 .206 } 15: { .0317 .0794 .0159 } +// HSV - 0: { 116.743 .571 1 } 7: { 112.110 .639 .571 } 15: { 105.071 .800 .0794 } +void RGBtoHSV (float r, float g, float b, float *h, float *s, float *v) +{ + float min, max, delta, foo; + + if (r == g && g == b) + { + *h = 0; + *s = 0; + *v = r; + return; + } + + foo = r < g ? r : g; + min = (foo < b) ? foo : b; + foo = r > g ? r : g; + max = (foo > b) ? foo : b; + + *v = max; // v + + delta = max - min; + + *s = delta / max; // s + + if (r == max) + *h = (g - b) / delta; // between yellow & magenta + else if (g == max) + *h = 2 + (b - r) / delta; // between cyan & yellow + else + *h = 4 + (r - g) / delta; // between magenta & cyan + + *h *= 60; // degrees + if (*h < 0) + *h += 360; +} + +void HSVtoRGB (float *r, float *g, float *b, float h, float s, float v) +{ + int i; + float f, p, q, t; + + if (s == 0) + { // achromatic (grey) + *r = *g = *b = v; + return; + } + + h /= 60; // sector 0 to 5 + i = (int)floor (h); + f = h - i; // factorial part of h + p = v * (1 - s); + q = v * (1 - s * f); + t = v * (1 - s * (1 - f)); + + switch (i) + { + case 0: *r = v; *g = t; *b = p; break; + case 1: *r = q; *g = v; *b = p; break; + case 2: *r = p; *g = v; *b = t; break; + case 3: *r = p; *g = q; *b = v; break; + case 4: *r = t; *g = p; *b = v; break; + default: *r = v; *g = p; *b = q; break; + } +} + +struct RemappingWork +{ + uint32_t Color; + uint8_t Foreign; // 0 = local palette, 1 = foreign palette + uint8_t PalEntry; // Entry # in the palette + uint8_t Pad[2]; +}; + +static int sortforremap(const void* a, const void* b) +{ + return (*(const uint32_t*)a & 0xFFFFFF) - (*(const uint32_t*)b & 0xFFFFFF); +} + +static int sortforremap2(const void* a, const void* b) +{ + const RemappingWork* ap = (const RemappingWork*)a; + const RemappingWork* bp = (const RemappingWork*)b; + + if (ap->Color == bp->Color) + { + return bp->Foreign - ap->Foreign; + } + else + { + return ap->Color - bp->Color; + } +} + + +void MakeRemap(uint32_t* BaseColors, const uint32_t* colors, uint8_t* remap, const uint8_t* useful, int numcolors) +{ + RemappingWork workspace[255 + 256]; + int i, j, k; + + // Fill in workspace with the colors from the passed palette and this palette. + // By sorting this array, we can quickly find exact matches so that we can + // minimize the time spent calling BestColor for near matches. + + for (i = 1; i < 256; ++i) + { + workspace[i - 1].Color = uint32_t(BaseColors[i]) & 0xFFFFFF; + workspace[i - 1].Foreign = 0; + workspace[i - 1].PalEntry = i; + } + for (i = k = 0, j = 255; i < numcolors; ++i) + { + if (useful == NULL || useful[i] != 0) + { + workspace[j].Color = colors[i] & 0xFFFFFF; + workspace[j].Foreign = 1; + workspace[j].PalEntry = i; + ++j; + ++k; + } + else + { + remap[i] = 0; + } + } + qsort(workspace, j, sizeof(RemappingWork), sortforremap2); + + // Find exact matches + --j; + for (i = 0; i < j; ++i) + { + if (workspace[i].Foreign) + { + if (!workspace[i + 1].Foreign && workspace[i].Color == workspace[i + 1].Color) + { + remap[workspace[i].PalEntry] = workspace[i + 1].PalEntry; + workspace[i].Foreign = 2; + ++i; + --k; + } + } + } + + // Find near matches + if (k > 0) + { + for (i = 0; i <= j; ++i) + { + if (workspace[i].Foreign == 1) + { + remap[workspace[i].PalEntry] = BestColor((uint32_t*)BaseColors, + RPART(workspace[i].Color), GPART(workspace[i].Color), BPART(workspace[i].Color), + 1, 255); + } + } + } +} + +// In ZDoom's new texture system, color 0 is used as the transparent color. +// But color 0 is also a valid color for Doom engine graphics. What to do? +// Simple. The default palette for every game has at least one duplicate +// color, so find a duplicate pair of palette entries, make one of them a +// duplicate of color 0, and remap every graphic so that it uses that entry +// instead of entry 0. +void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap, const uint8_t* lastcolormap) +{ + for (int i = 0; i < 256; i++) Remap[i] = i; + PalEntry color0 = BaseColors[0]; + int i; + + + // First try for an exact match of color 0. Only Hexen does not have one. + if (!lastcolormap) + { + for (i = 1; i < 256; ++i) + { + if (BaseColors[i] == color0) + { + Remap[0] = i; + break; + } + } + } + else + { + for (i = 1; i < 256; ++i) + { + if ((BaseColors[i] == color0) && (lastcolormap[i] == lastcolormap[0])) + { + Remap[0] = i; + break; + } + } + } + + // If there is no duplicate of color 0, find the first set of duplicate + // colors and make one of them a duplicate of color 0. In Hexen's PLAYPAL + // colors 209 and 229 are the only duplicates, but we cannot assume + // anything because the player might be using a custom PLAYPAL where those + // entries are not duplicates. + if (Remap[0] == 0) + { + PalEntry sortcopy[256]; + + for (i = 0; i < 256; ++i) + { + sortcopy[i] = (BaseColors[i] & 0xffffff) | (i << 24); + } + qsort(sortcopy, 256, 4, sortforremap); + if (!lastcolormap) + { + for (i = 255; i > 0; --i) + { + if ((sortcopy[i] & 0xFFFFFF) == (sortcopy[i - 1] & 0xFFFFFF)) + { + int new0 = sortcopy[i].a; + int dup = sortcopy[i - 1].a; + if (new0 > dup) + { + // Make the lower-numbered entry a copy of color 0. (Just because.) + std::swap(new0, dup); + } + Remap[0] = new0; + Remap[new0] = dup; + BaseColors[new0] = color0; + break; + } + } + } + else + { + for (i = 255; i > 0; --i) + { + if (((sortcopy[i] & 0xFFFFFF) == (sortcopy[i - 1] & 0xFFFFFF)) && (lastcolormap[sortcopy[i].a] == lastcolormap[sortcopy[i - 1].a])) + { + int new0 = sortcopy[i].a; + int dup = sortcopy[i - 1].a; + if (new0 > dup) + { + // Make the lower-numbered entry a copy of color 0. (Just because.) + std::swap(new0, dup); + } + Remap[0] = new0; + Remap[new0] = dup; + BaseColors[new0] = color0; + break; + } + } + } + } + + // If there were no duplicates, InitPalette() will remap color 0 to the + // closest matching color. Hopefully nobody will use a palette where all + // 256 entries are different. :-) +} + +//=========================================================================== +// +// Gets the average color of a texture for use as a sky cap color +// +//=========================================================================== + +PalEntry averageColor(const uint32_t* data, int size, int maxout) +{ + int i; + unsigned int r, g, b; + + // First clear them. + r = g = b = 0; + if (size == 0) + { + return PalEntry(255, 255, 255); + } + for (i = 0; i < size; i++) + { + b += BPART(data[i]); + g += GPART(data[i]); + r += RPART(data[i]); + } + + r = r / size; + g = g / size; + b = b / size; + + int maxv = max(max(r, g), b); + + if (maxv && maxout) + { + r = ::Scale(r, maxout, maxv); + g = ::Scale(g, maxout, maxv); + b = ::Scale(b, maxout, maxv); + } + return PalEntry(255, r, g, b); +} + + + +//========================================================================== +// +// V_GetColorFromString +// +// Passed a string of the form "#RGB", "#RRGGBB", "R G B", or "RR GG BB", +// returns a number representing that color. If palette is non-NULL, the +// index of the best match in the palette is returned, otherwise the +// RRGGBB value is returned directly. +// +//========================================================================== + +int V_GetColorFromString(const char* cstr, FScriptPosition* sc) +{ + int c[3], i, p; + char val[3]; + + val[2] = '\0'; + + // Check for HTML-style #RRGGBB or #RGB color string + if (cstr[0] == '#') + { + size_t len = strlen(cstr); + + if (len == 7) + { + // Extract each eight-bit component into c[]. + for (i = 0; i < 3; ++i) + { + val[0] = cstr[1 + i * 2]; + val[1] = cstr[2 + i * 2]; + c[i] = ParseHex(val, sc); + } + } + else if (len == 4) + { + // Extract each four-bit component into c[], expanding to eight bits. + for (i = 0; i < 3; ++i) + { + val[1] = val[0] = cstr[1 + i]; + c[i] = ParseHex(val, sc); + } + } + else + { + // Bad HTML-style; pretend it's black. + c[2] = c[1] = c[0] = 0; + } + } + else + { + if (strlen(cstr) == 6) + { + char* endp; + int color = strtol(cstr, &endp, 16); + if (*endp == 0) + { + // RRGGBB string + c[0] = (color & 0xff0000) >> 16; + c[1] = (color & 0xff00) >> 8; + c[2] = (color & 0xff); + } + else goto normal; + } + else + { + normal: + // Treat it as a space-delimited hexadecimal string + for (i = 0; i < 3; ++i) + { + // Skip leading whitespace + while (*cstr <= ' ' && *cstr != '\0') + { + cstr++; + } + // Extract a component and convert it to eight-bit + for (p = 0; *cstr > ' '; ++p, ++cstr) + { + if (p < 2) + { + val[p] = *cstr; + } + } + if (p == 0) + { + c[i] = 0; + } + else + { + if (p == 1) + { + val[1] = val[0]; + } + c[i] = ParseHex(val, sc); + } + } + } + } + return MAKERGB(c[0], c[1], c[2]); +} + +//========================================================================== +// +// V_GetColorStringByName +// +// Searches for the given color name in x11r6rgb.txt and returns an +// HTML-ish "#RRGGBB" string for it if found or the empty string if not. +// +//========================================================================== + +FString V_GetColorStringByName(const char* name, FScriptPosition* sc) +{ + const char* rgbEnd; + const char* rgb, * endp; + int rgblump; + int c[3], step; + size_t namelen; + + if (fileSystem.GetNumEntries() == 0) return FString(); + + rgblump = fileSystem.CheckNumForName("X11R6RGB"); + if (rgblump == -1) + { + if (!sc) Printf("X11R6RGB lump not found\n"); + else sc->Message(MSG_WARNING, "X11R6RGB lump not found"); + return FString(); + } + + auto rgbNames = fileSystem.ReadFile(rgblump); + rgb = rgbNames.string(); + rgbEnd = rgb + rgbNames.size(); + step = 0; + namelen = strlen(name); + + while (rgb < rgbEnd) + { + // Skip white space + if (*rgb <= ' ') + { + do + { + rgb++; + } while (rgb < rgbEnd && *rgb <= ' '); + } + else if (step == 0 && *rgb == '!') + { // skip comment lines + do + { + rgb++; + } while (rgb < rgbEnd && *rgb != '\n'); + } + else if (step < 3) + { // collect RGB values + c[step++] = strtoul(rgb, (char**)&endp, 10); + if (endp == rgb) + { + break; + } + rgb = endp; + } + else + { // Check color name + endp = rgb; + // Find the end of the line + while (endp < rgbEnd && *endp != '\n') + endp++; + // Back up over any whitespace + while (endp > rgb && *endp <= ' ') + endp--; + if (endp == rgb) + { + break; + } + size_t checklen = ++endp - rgb; + if (checklen == namelen && strnicmp(rgb, name, checklen) == 0) + { + FString descr; + descr.Format("#%02x%02x%02x", c[0], c[1], c[2]); + return descr; + } + rgb = endp; + step = 0; + } + } + if (rgb < rgbEnd) + { + if (!sc) Printf("X11R6RGB lump is corrupt\n"); + else sc->Message(MSG_WARNING, "X11R6RGB lump is corrupt"); + } + return FString(); +} + +//========================================================================== +// +// V_GetColor +// +// Works like V_GetColorFromString(), but also understands X11 color names. +// +//========================================================================== + +int V_GetColor(const char* str, FScriptPosition* sc) +{ + FString string = V_GetColorStringByName(str, sc); + int res; + + if (!string.IsEmpty()) + { + res = V_GetColorFromString(string.GetChars(), sc); + } + else + { + res = V_GetColorFromString(str, sc); + } + return res; +} + +int V_GetColor(FScanner& sc) +{ + FScriptPosition scc = sc; + return V_GetColor(sc.String, &scc); +} + +//========================================================================== +// +// Special colormaps +// +//========================================================================== + + +TArray SpecialColormaps; +uint8_t DesaturateColormap[31][256]; + +// These default tables are needed for texture composition. +static FSpecialColormapParameters SpecialColormapParms[] = +{ + // Doom invulnerability is an inverted grayscale. + // Strife uses it when firing the Sigil + { { 1, 1, 1 }, { 0, 0, 0 } }, + + // Heretic invulnerability is a golden shade. + { { 0, 0, 0 }, { 1.5, 0.75, 0 }, }, + + // [BC] Build the Doomsphere colormap. It is red! + { { 0, 0, 0 }, { 1.5, 0, 0 } }, + + // [BC] Build the Guardsphere colormap. It's a greenish-white kind of thing. + { { 0, 0, 0 }, { 1.25, 1.5, 1 } }, + + // Build a blue colormap. + { { 0, 0, 0 }, { 0, 0, 1.5 } }, + + // Repeated to get around the overridability of the other one + { { 1, 1, 1 }, { 0, 0, 0 } }, + +}; + +//========================================================================== +// +// +// +//========================================================================== + +void UpdateSpecialColormap(PalEntry* BaseColors, unsigned int index, float r1, float g1, float b1, float r2, float g2, float b2) +{ + assert(index < SpecialColormaps.Size()); + + FSpecialColormap* cm = &SpecialColormaps[index]; + cm->ColorizeStart[0] = float(r1); + cm->ColorizeStart[1] = float(g1); + cm->ColorizeStart[2] = float(b1); + cm->ColorizeEnd[0] = float(r2); + cm->ColorizeEnd[1] = float(g2); + cm->ColorizeEnd[2] = float(b2); + + r2 -= r1; + g2 -= g1; + b2 -= b1; + r1 *= 255; + g1 *= 255; + b1 *= 255; + + if (BaseColors) // only create this table if needed + { + for (int c = 0; c < 256; c++) + { + double intensity = (BaseColors[c].r * 77 + + BaseColors[c].g * 143 + + BaseColors[c].b * 37) / 256.0; + + PalEntry pe = PalEntry(min(255, int(r1 + intensity * r2)), + min(255, int(g1 + intensity * g2)), + min(255, int(b1 + intensity * b2))); + + cm->Colormap[c] = BestColor((uint32_t*)BaseColors, pe.r, pe.g, pe.b); + } + } + + // This table is used by the texture composition code + for (int i = 0; i < 256; i++) + { + cm->GrayscaleToColor[i] = PalEntry(min(255, int(r1 + i * r2)), + min(255, int(g1 + i * g2)), + min(255, int(b1 + i * b2))); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +int AddSpecialColormap(PalEntry *BaseColors, float r1, float g1, float b1, float r2, float g2, float b2) +{ + // Clamp these in range for the hardware shader. + r1 = clamp(r1, 0.0f, 2.0f); + g1 = clamp(g1, 0.0f, 2.0f); + b1 = clamp(b1, 0.0f, 2.0f); + r2 = clamp(r2, 0.0f, 2.0f); + g2 = clamp(g2, 0.0f, 2.0f); + b2 = clamp(b2, 0.0f, 2.0f); + + for (unsigned i = 1; i < SpecialColormaps.Size(); i++) + { + // Avoid precision issues here when trying to find a proper match. + if (fabs(SpecialColormaps[i].ColorizeStart[0] - r1) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeStart[1] - g1) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeStart[2] - b1) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeEnd[0] - r2) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeEnd[1] - g2) < FLT_EPSILON && + fabs(SpecialColormaps[i].ColorizeEnd[2] - b2) < FLT_EPSILON) + { + return i; // The map already exists + } + } + + UpdateSpecialColormap(BaseColors, SpecialColormaps.Reserve(1), r1, g1, b1, r2, g2, b2); + return SpecialColormaps.Size() - 1; +} + +void InitSpecialColormaps(PalEntry *pe) +{ + for (unsigned i = 0; i < countof(SpecialColormapParms); ++i) + { + AddSpecialColormap(pe, SpecialColormapParms[i].Start[0], SpecialColormapParms[i].Start[1], + SpecialColormapParms[i].Start[2], SpecialColormapParms[i].End[0], + SpecialColormapParms[i].End[1], SpecialColormapParms[i].End[2]); + } + + // desaturated colormaps. These are used for texture composition + for (int m = 0; m < 31; m++) + { + uint8_t* shade = DesaturateColormap[m]; + for (int c = 0; c < 256; c++) + { + int intensity = pe[c].Luminance(); + + int r = (pe[c].r * (31 - m) + intensity * m) / 31; + int g = (pe[c].g * (31 - m) + intensity * m) / 31; + int b = (pe[c].b * (31 - m) + intensity * m) / 31; + shade[c] = BestColor((uint32_t*)pe, r, g, b); + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +int ReadPalette(int lumpnum, uint8_t* buffer) +{ + if (lumpnum < 0) + { + return 0; + } + auto lump = fileSystem.ReadFile(lumpnum); + auto lumpmem = lump.bytes(); + memset(buffer, 0, 768); + + FileReader fr; + fr.OpenMemory(lumpmem, lump.size()); + auto png = M_VerifyPNG(fr); + if (png) + { + uint32_t id, len; + fr.Seek(33, FileReader::SeekSet); + fr.Read(&len, 4); + fr.Read(&id, 4); + while (id != MAKE_ID('I', 'D', 'A', 'T') && id != MAKE_ID('I', 'E', 'N', 'D')) + { + len = BigLong((unsigned int)len); + if (id != MAKE_ID('P', 'L', 'T', 'E')) + fr.Seek(len, FileReader::SeekCur); + else + { + int PaletteSize = min(len, 768); + fr.Read(buffer, PaletteSize); + return PaletteSize / 3; + } + fr.Seek(4, FileReader::SeekCur); // Skip CRC + fr.Read(&len, 4); + id = MAKE_ID('I', 'E', 'N', 'D'); + fr.Read(&id, 4); + } + I_Error("%s contains no palette", fileSystem.GetFileFullName(lumpnum)); + } + if (memcmp(lumpmem, "JASC-PAL", 8) == 0) + { + FScanner sc; + + sc.OpenMem(fileSystem.GetFileFullName(lumpnum), (char*)lumpmem, int(lump.size())); + sc.MustGetString(); + sc.MustGetNumber(); // version - ignore + sc.MustGetNumber(); + int colors = min(256, sc.Number) * 3; + for (int i = 0; i < colors; i++) + { + sc.MustGetNumber(); + if (sc.Number < 0 || sc.Number > 255) + { + sc.ScriptError("Color %d value out of range.", sc.Number); + } + buffer[i] = sc.Number; + } + return colors / 3; + } + else + { + memcpy(buffer, lumpmem, min(768, lump.size())); + return 256; + } +} + diff --git a/src/common/utility/palutil.h b/src/common/utility/palutil.h new file mode 100644 index 00000000000..6faa7b5df3c --- /dev/null +++ b/src/common/utility/palutil.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include "zstring.h" +#include "palentry.h" + +struct FScriptPosition; +class FScanner; + +int BestColor(const uint32_t* pal, int r, int g, int b, int first = 1, int num = 255, const uint8_t* indexmap = nullptr); +int PTM_BestColor(const uint32_t* pal_in, int r, int g, int b, bool reverselookup, float powtable, int first = 1, int num = 255); +void DoBlending(const PalEntry* from, PalEntry* to, int count, int r, int g, int b, int a); + +// Given an array of colors, fills in remap with values to remap the +// passed array of colors to BaseColors. Used for loading palette downconversions of PNGs. +void MakeRemap(uint32_t* BaseColors, const uint32_t* colors, uint8_t* remap, const uint8_t* useful, int numcolors); +void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap, const uint8_t* cmapdata = nullptr); + +// Colorspace conversion RGB <-> HSV +void RGBtoHSV (float r, float g, float b, float *h, float *s, float *v); +void HSVtoRGB (float *r, float *g, float *b, float h, float s, float v); + +// Returns the closest color to the one desired. String +// should be of the form "rr gg bb". +int V_GetColorFromString(const char* colorstring, FScriptPosition* sc = nullptr); +// Scans through the X11R6RGB lump for a matching color +// and returns a color string suitable for V_GetColorFromString. +FString V_GetColorStringByName(const char* name, FScriptPosition* sc = nullptr); + +// Tries to get color by name, then by string +int V_GetColor(const char* str, FScriptPosition* sc = nullptr); +int V_GetColor(FScanner& sc); +PalEntry averageColor(const uint32_t* data, int size, int maxout); + +enum +{ + NOFIXEDCOLORMAP = -1, + INVERSECOLORMAP, // the inverse map is used explicitly in a few places. + GOLDCOLORMAP, + REDCOLORMAP, + GREENCOLORMAP, + BLUECOLORMAP, + REALINVERSECOLORMAP, +}; + +struct FSpecialColormapParameters +{ + float Start[3], End[3]; +}; + +struct FSpecialColormap +{ + float ColorizeStart[3]; + float ColorizeEnd[3]; + uint8_t Colormap[256]; + PalEntry GrayscaleToColor[256]; +}; + +extern TArray SpecialColormaps; +extern uint8_t DesaturateColormap[31][256]; + +int AddSpecialColormap(PalEntry *pe, float r1, float g1, float b1, float r2, float g2, float b2); +void InitSpecialColormaps(PalEntry* pe); +void UpdateSpecialColormap(PalEntry* BaseColors, unsigned int index, float r1, float g1, float b1, float r2, float g2, float b2); +int ReadPalette(int lumpnum, uint8_t* buffer); + +enum EColorManipulation +{ + CM_PLAIN2D = -2, // regular 2D drawing. + CM_INVALID = -1, + CM_DEFAULT = 0, // untranslated + CM_FIRSTSPECIALCOLORMAP, // first special fixed colormap +}; + +#define CM_MAXCOLORMAP int(CM_FIRSTSPECIALCOLORMAP + SpecialColormaps.Size()) diff --git a/src/utility/parallel_for.h b/src/common/utility/parallel_for.h similarity index 97% rename from src/utility/parallel_for.h rename to src/common/utility/parallel_for.h index d3e0e5de0bb..7f7ee5b6ca0 100644 --- a/src/utility/parallel_for.h +++ b/src/common/utility/parallel_for.h @@ -6,7 +6,7 @@ // // This program 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, either version 3 of the License, or +// the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, diff --git a/src/common/utility/quaternion.h b/src/common/utility/quaternion.h new file mode 100644 index 00000000000..1437b56be5f --- /dev/null +++ b/src/common/utility/quaternion.h @@ -0,0 +1,352 @@ +#pragma once + +#include "vectors.h" + +template +class TQuaternion +{ +public: + typedef TVector2 Vector2; + typedef TVector3 Vector3; + + vec_t X, Y, Z, W; + + TQuaternion() = default; + + TQuaternion(vec_t x, vec_t y, vec_t z, vec_t w) + : X(x), Y(y), Z(z), W(w) + { + } + + TQuaternion(vec_t *o) + : X(o[0]), Y(o[1]), Z(o[2]), W(o[3]) + { + } + + TQuaternion(const TQuaternion &other) = default; + + TQuaternion(const Vector3 &v, vec_t s) + : X(v.X), Y(v.Y), Z(v.Z), W(s) + { + } + + TQuaternion(const vec_t v[4]) + : TQuaternion(v[0], v[1], v[2], v[3]) + { + } + + void Zero() + { + Z = Y = X = W = 0; + } + + bool isZero() const + { + return X == 0 && Y == 0 && Z == 0 && W == 0; + } + + TQuaternion &operator= (const TQuaternion &other) = default; + + // Access X and Y and Z as an array + vec_t &operator[] (int index) + { + return (&X)[index]; + } + + const vec_t &operator[] (int index) const + { + return (&X)[index]; + } + + // Test for equality + bool operator== (const TQuaternion &other) const + { + return X == other.X && Y == other.Y && Z == other.Z && W == other.W; + } + + // Test for inequality + bool operator!= (const TQuaternion &other) const + { + return X != other.X || Y != other.Y || Z != other.Z || W != other.W; + } + + // returns the XY fields as a 2D-vector. + const Vector2& XY() const + { + return *reinterpret_cast(this); + } + + Vector2& XY() + { + return *reinterpret_cast(this); + } + + // returns the XY fields as a 2D-vector. + const Vector3& XYZ() const + { + return *reinterpret_cast(this); + } + + Vector3& XYZ() + { + return *reinterpret_cast(this); + } + + + // Test for approximate equality + bool ApproximatelyEquals(const TQuaternion &other) const + { + return fabs(X - other.X) < EQUAL_EPSILON && fabs(Y - other.Y) < EQUAL_EPSILON && fabs(Z - other.Z) < EQUAL_EPSILON && fabs(W - other.W) < EQUAL_EPSILON; + } + + // Test for approximate inequality + bool DoesNotApproximatelyEqual(const TQuaternion &other) const + { + return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON || fabs(Z - other.Z) >= EQUAL_EPSILON || fabs(W - other.W) >= EQUAL_EPSILON; + } + + // Unary negation + TQuaternion operator- () const + { + return TQuaternion(-X, -Y, -Z, -W); + } + + // Scalar addition + TQuaternion &operator+= (vec_t scalar) + { + X += scalar, Y += scalar, Z += scalar; W += scalar; + return *this; + } + + friend TQuaternion operator+ (const TQuaternion &v, vec_t scalar) + { + return TQuaternion(v.X + scalar, v.Y + scalar, v.Z + scalar, v.W + scalar); + } + + friend TQuaternion operator+ (vec_t scalar, const TQuaternion &v) + { + return TQuaternion(v.X + scalar, v.Y + scalar, v.Z + scalar, v.W + scalar); + } + + // Scalar subtraction + TQuaternion &operator-= (vec_t scalar) + { + X -= scalar, Y -= scalar, Z -= scalar, W -= scalar; + return *this; + } + + TQuaternion operator- (vec_t scalar) const + { + return TQuaternion(X - scalar, Y - scalar, Z - scalar, W - scalar); + } + + // Scalar multiplication + TQuaternion &operator*= (vec_t scalar) + { + X = vec_t(X *scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar), W = vec_t(W * scalar); + return *this; + } + + friend TQuaternion operator* (const TQuaternion &v, vec_t scalar) + { + return TQuaternion(v.X * scalar, v.Y * scalar, v.Z * scalar, v.W * scalar); + } + + friend TQuaternion operator* (vec_t scalar, const TQuaternion &v) + { + return TQuaternion(v.X * scalar, v.Y * scalar, v.Z * scalar, v.W * scalar); + } + + // Scalar division + TQuaternion &operator/= (vec_t scalar) + { + scalar = 1 / scalar, X = vec_t(X * scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar), W = vec_t(W * scalar); + return *this; + } + + TQuaternion operator/ (vec_t scalar) const + { + scalar = 1 / scalar; + return TQuaternion(X * scalar, Y * scalar, Z * scalar, W * scalar); + } + + // Vector addition + TQuaternion &operator+= (const TQuaternion &other) + { + X += other.X, Y += other.Y, Z += other.Z, W += other.W; + return *this; + } + + TQuaternion operator+ (const TQuaternion &other) const + { + return TQuaternion(X + other.X, Y + other.Y, Z + other.Z, W + other.W); + } + + // Vector subtraction + TQuaternion &operator-= (const TQuaternion &other) + { + X -= other.X, Y -= other.Y, Z -= other.Z, W -= other.W; + return *this; + } + + TQuaternion operator- (const TQuaternion &other) const + { + return TQuaternion(X - other.X, Y - other.Y, Z - other.Z, W - other.W); + } + + // Quaternion length + double Length() const + { + return g_sqrt(X*X + Y*Y + Z*Z + W*W); + } + + double LengthSquared() const + { + return X*X + Y*Y + Z*Z + W*W; + } + + double Sum() const + { + return abs(X) + abs(Y) + abs(Z) + abs(W); + } + + + // Return a unit vector facing the same direction as this one + TQuaternion Unit() const + { + double len = Length(); + if (len != 0) len = 1 / len; + return *this * (vec_t)len; + } + + // Scales this vector into a unit vector + void MakeUnit() + { + double len = Length(); + if (len != 0) len = 1 / len; + *this *= (vec_t)len; + } + + // Resizes this vector to be the specified length (if it is not 0) + TQuaternion &MakeResize(double len) + { + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + X = vec_t(X * scale); + Y = vec_t(Y * scale); + Z = vec_t(Z * scale); + W = vec_t(W * scale); + } + return *this; + } + + TQuaternion Resized(double len) const + { + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + return{ vec_t(X * scale), vec_t(Y * scale), vec_t(Z * scale), vec_t(W * scale) }; + } + else + { + return *this; + } + } + + // Dot product + vec_t operator | (const TQuaternion &other) const + { + return X*other.X + Y*other.Y + Z*other.Z + W*other.W; + } + + vec_t dot(const TQuaternion &other) const + { + return X*other.X + Y*other.Y + Z*other.Z + W*other.W; + } + + TQuaternion& operator*= (const TQuaternion& q) + { + *this = *this * q; + return *this; + } + + friend TQuaternion operator* (const TQuaternion& q1, const TQuaternion& q2) + { + return TQuaternion( + q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y, + q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X, + q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W, + q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z + ); + } + + // Rotate Vector3 by Quaternion q + friend TVector3 operator* (const TQuaternion& q, const TVector3& v) + { + auto r = TQuaternion({ v.X, v.Y, v.Z, 0 }) * TQuaternion({ -q.X, -q.Y, -q.Z, q.W }); + r = q * r; + return TVector3(r.X, r.Y, r.Z); + } + + TQuaternion Conjugate() + { + return TQuaternion(-X, -Y, -Z, +W); + } + TQuaternion Inverse() + { + return Conjugate() / LengthSquared(); + } + + static TQuaternion AxisAngle(TVector3 axis, TAngle angle) + { + auto lengthSquared = axis.LengthSquared(); + auto halfAngle = angle * 0.5; + auto sinTheta = halfAngle.Sin(); + auto cosTheta = halfAngle.Cos(); + auto factor = sinTheta / g_sqrt(lengthSquared); + TQuaternion ret; + ret.W = cosTheta; + ret.XYZ() = factor * axis; + return ret; + } + static TQuaternion FromAngles(TAngle yaw, TAngle pitch, TAngle roll) + { + auto zRotation = TQuaternion::AxisAngle(Vector3(vec_t{0.0}, vec_t{0.0}, vec_t{1.0}), yaw); + auto yRotation = TQuaternion::AxisAngle(Vector3(vec_t{0.0}, vec_t{1.0}, vec_t{0.0}), pitch); + auto xRotation = TQuaternion::AxisAngle(Vector3(vec_t{1.0}, vec_t{0.0}, vec_t{0.0}), roll); + return zRotation * yRotation * xRotation; + } + + static TQuaternion NLerp(TQuaternion from, TQuaternion to, vec_t t) + { + return (from * (vec_t{1.0} - t) + to * t).Unit(); + } + static TQuaternion SLerp(TQuaternion from, TQuaternion to, vec_t t) + { + auto dot = from.dot(to); + const auto dotThreshold = vec_t{0.9995}; + if (dot < vec_t{0.0}) + { + to = -to; + dot = -dot; + } + if (dot > dotThreshold) + { + return NLerp(from, to, t); + } + else + { + auto robustDot = clamp(dot, vec_t{-1.0}, vec_t{1.0}); + auto theta = TAngle::fromRad(g_acos(robustDot)); + auto scale0 = (theta * (vec_t{1.0} - t)).Sin(); + auto scale1 = (theta * t).Sin(); + return (from * scale0 + to * scale1).Unit(); + } + } +}; + +typedef TQuaternion FQuaternion; +typedef TQuaternion DQuaternion; diff --git a/src/common/utility/r_memory.cpp b/src/common/utility/r_memory.cpp new file mode 100644 index 00000000000..8ff821c38eb --- /dev/null +++ b/src/common/utility/r_memory.cpp @@ -0,0 +1,101 @@ +/* +** Render memory allocation +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include + +#include "r_memory.h" +#include + +void *RenderMemory::AllocBytes(int size) +{ + size = (size + 15) / 16 * 16; // 16-byte align + + if (UsedBlocks.empty() || UsedBlocks.back()->Position + size > BlockSize) + { + if (!FreeBlocks.empty()) + { + auto block = std::move(FreeBlocks.back()); + block->Position = 0; + FreeBlocks.pop_back(); + UsedBlocks.push_back(std::move(block)); + } + else + { + UsedBlocks.push_back(std::unique_ptr(new MemoryBlock())); + } + } + + auto &block = UsedBlocks.back(); + void *data = block->Data + block->Position; + block->Position += size; + + return data; +} + +void RenderMemory::Clear() +{ + while (!UsedBlocks.empty()) + { + auto block = std::move(UsedBlocks.back()); + UsedBlocks.pop_back(); + FreeBlocks.push_back(std::move(block)); + } +} + +static void* Aligned_Alloc(size_t alignment, size_t size) +{ + void* ptr; +#if defined (_MSC_VER) || defined (__MINGW32__) + ptr = _aligned_malloc(size, alignment); + if (!ptr) + throw std::bad_alloc(); +#else + // posix_memalign required alignment to be a min of sizeof(void *) + if (alignment < sizeof(void*)) + alignment = sizeof(void*); + + if (posix_memalign((void**)&ptr, alignment, size)) + throw std::bad_alloc(); +#endif + return ptr; +} + +static void Aligned_Free(void* ptr) +{ + if (ptr) + { +#if defined _MSC_VER + _aligned_free(ptr); +#else + free(ptr); +#endif + } +} + +RenderMemory::MemoryBlock::MemoryBlock() : Data(static_cast(Aligned_Alloc(16, BlockSize))), Position(0) +{ +} + +RenderMemory::MemoryBlock::~MemoryBlock() +{ + Aligned_Free(Data); +} diff --git a/src/rendering/swrenderer/r_memory.h b/src/common/utility/r_memory.h similarity index 97% rename from src/rendering/swrenderer/r_memory.h rename to src/common/utility/r_memory.h index 8007b6cc182..d9db538ca4b 100644 --- a/src/rendering/swrenderer/r_memory.h +++ b/src/common/utility/r_memory.h @@ -8,33 +8,33 @@ class RenderMemory { public: void Clear(); - + template T *AllocMemory(int size = 1) { return (T*)AllocBytes(sizeof(T) * size); } - + template T *NewObject(Types &&... args) { void *ptr = AllocBytes(sizeof(T)); return new (ptr)T(std::forward(args)...); } - + private: void *AllocBytes(int size); - + enum { BlockSize = 1024 * 1024 }; - + struct MemoryBlock { MemoryBlock(); ~MemoryBlock(); - + MemoryBlock(const MemoryBlock &) = delete; MemoryBlock &operator=(const MemoryBlock &) = delete; - + uint8_t *Data; uint32_t Position; }; diff --git a/src/common/utility/refcounted.h b/src/common/utility/refcounted.h new file mode 100644 index 00000000000..f8643f0800b --- /dev/null +++ b/src/common/utility/refcounted.h @@ -0,0 +1,116 @@ +#pragma once + +// Simple lightweight reference counting pointer alternative for std::shared_ptr which stores the reference counter in the handled object itself. + +// Base class for handled objects +class RefCountedBase +{ +public: + void IncRef() { refCount++; } + void DecRef() { if (--refCount <= 0) delete this; } +private: + int refCount = 0; +protected: + virtual ~RefCountedBase() = default; +}; + +// The actual pointer object +template +class RefCountedPtr +{ +public: + ~RefCountedPtr() + { + if (ptr) ptr->DecRef(); + } + + RefCountedPtr() : ptr(nullptr) + {} + + explicit RefCountedPtr(T* p) : ptr(p) + { + if (ptr) ptr->IncRef(); + } + + RefCountedPtr(const RefCountedPtr& r) : ptr(r.ptr) + { + if (ptr) ptr->IncRef(); + } + + RefCountedPtr(RefCountedPtr&& r) : ptr(r.ptr) + { + r.ptr = nullptr; + } + + RefCountedPtr & operator=(const RefCountedPtr& r) + { + if (this != &r) + { + if (ptr) ptr->DecRef(); + ptr = r.ptr; + if (ptr) ptr->IncRef(); + } + return *this; + } + + RefCountedPtr& operator=(T* r) + { + if (ptr != r) + { + if (ptr) ptr->DecRef(); + ptr = r; + if (ptr) ptr->IncRef(); + } + return *this; + } + + RefCountedPtr & operator=(RefCountedPtr&& r) + { + if (this != &r) + { + if (ptr) ptr->DecRef(); + ptr = r.ptr; + r.ptr = nullptr; + } + return *this; + } + + bool operator==(T* p) const + { + return ptr == p; + } + + bool operator!=(T* p) const + { + return ptr != p; + } + + bool operator==(const RefCountedPtr &p) const + { + return ptr == p.ptr; + } + + bool operator!=(const RefCountedPtr& p) const + { + return ptr != p.ptr; + } + + T& operator* () const + { + return *ptr; + } + + T* operator-> () const + { + return ptr; + } + + T* get() const + { + return ptr; + } + +private: + + T * ptr; +}; \ No newline at end of file diff --git a/src/utility/s_playlist.cpp b/src/common/utility/s_playlist.cpp similarity index 89% rename from src/utility/s_playlist.cpp rename to src/common/utility/s_playlist.cpp index 8b8be5f760c..694329b58bb 100644 --- a/src/utility/s_playlist.cpp +++ b/src/common/utility/s_playlist.cpp @@ -37,7 +37,7 @@ #include "cmdlib.h" #include "s_playlist.h" -#include "templates.h" + #include "v_text.h" #include "files.h" @@ -54,14 +54,12 @@ bool FPlayList::ChangeList (const char *path) bool pls; int i; - Songs.Clear(); - Position = 0; - if (!fr.OpenFile(path)) { - Printf ("Could not open " TEXTCOLOR_BOLD "%s" TEXTCOLOR_NORMAL ": %s\n", path, strerror(errno)); return false; } + Songs.Clear(); + Position = 0; first = true; pls = false; @@ -82,7 +80,7 @@ bool FPlayList::ChangeList (const char *path) // For a .PLS file, skip anything that doesn't start with File[0-9]+= if (pls) { - if (strncmp(song, "File", 4) != 0) + if (strncmp(song.GetChars(), "File", 4) != 0) { continue; } @@ -97,7 +95,7 @@ bool FPlayList::ChangeList (const char *path) } // Check for relative paths. - long slashpos = song.IndexOf('/'); + auto slashpos = song.IndexOf('/'); if (slashpos == 0) { @@ -156,7 +154,7 @@ void FPlayList::Shuffle () for (i = 0; i < numsongs; ++i) { - swapvalues (Songs[i], Songs[(rand() % (numsongs - i)) + i]); + std::swap (Songs[i], Songs[(rand() % (numsongs - i)) + i]); } Position = 0; } @@ -176,7 +174,6 @@ int FPlayList::SetPosition (int position) { Position = position; } - DPrintf (DMSG_NOTIFY, "Playlist position set to %d\n", Position); return Position; } @@ -191,7 +188,6 @@ int FPlayList::Advance () { Position = 0; } - DPrintf (DMSG_NOTIFY, "Playlist advanced to song %d\n", Position); return Position; } @@ -201,7 +197,6 @@ int FPlayList::Backup () { Position = Songs.Size() - 1; } - DPrintf (DMSG_NOTIFY, "Playlist backed up to song %d\n", Position); return Position; } @@ -210,5 +205,5 @@ const char *FPlayList::GetSong (int position) const if ((unsigned)position >= Songs.Size()) return NULL; - return Songs[position]; + return Songs[position].GetChars(); } diff --git a/src/utility/s_playlist.h b/src/common/utility/s_playlist.h similarity index 99% rename from src/utility/s_playlist.h rename to src/common/utility/s_playlist.h index 5bd5fd55ef6..84d2040b039 100644 --- a/src/utility/s_playlist.h +++ b/src/common/utility/s_playlist.h @@ -34,7 +34,7 @@ #ifndef __S_PLAYLIST_H__ #define __S_PLAYLIST_H__ -class FileReader; +#include "files.h" class FPlayList { diff --git a/src/common/utility/tarray.h b/src/common/utility/tarray.h new file mode 100644 index 00000000000..3445bd48409 --- /dev/null +++ b/src/common/utility/tarray.h @@ -0,0 +1,2204 @@ +#pragma once +/* +** tarray.h +** Templated, automatically resizing array +** +**--------------------------------------------------------------------------- +** Copyright 1998-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** NOTE: TArray takes advantage of the assumption that the contained type is +** able to be trivially moved. The definition of trivially movable by the C++ +** standard is more strict than the actual set of types that can be moved with +** memmove. For example, FString uses non-trivial constructors/destructor in +** order to maintain the reference count, but can be "safely" by passed if the +** opaque destructor call is avoided. Similarly types like TArray itself which +** only null the owning pointers when moving which can be skipped if the +** destructor is not called. +** +** It is possible that with LTO TArray could be made safe for non-trivial types, +** but we don't wish to rely on LTO to reach expected performance. The set of +** types which can not be contained by TArray as a result of this choice is +** actually extremely small. +** +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_WIN32) +#include // for intptr_t +#else +#include // for mingw +#endif + +#if __has_include("m_alloc.h") + #include "m_alloc.h" +#else + #define M_Malloc malloc + #define M_Realloc realloc + #define M_Free free +#endif + +template class TIterator +{ +public: + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + TIterator(T* ptr = nullptr) { m_ptr = ptr; } + + // Comparison operators + bool operator==(const TIterator &other) const { return m_ptr == other.m_ptr; } + bool operator!=(const TIterator &other) const { return m_ptr != other.m_ptr; } + bool operator< (const TIterator &other) const { return m_ptr < other.m_ptr; } + bool operator<=(const TIterator &other) const { return m_ptr <= other.m_ptr; } + bool operator> (const TIterator &other) const { return m_ptr > other.m_ptr; } + bool operator>=(const TIterator &other) const { return m_ptr >= other.m_ptr; } + + // Arithmetic operators + TIterator &operator++() { ++m_ptr; return *this; } + TIterator operator++(int) { pointer tmp = m_ptr; ++*this; return TIterator(tmp); } + TIterator &operator--() { --m_ptr; return *this; } + TIterator operator--(int) { pointer tmp = m_ptr; --*this; return TIterator(tmp); } + TIterator &operator+=(difference_type offset) { m_ptr += offset; return *this; } + TIterator operator+(difference_type offset) const { return TIterator(m_ptr + offset); } + friend TIterator operator+(difference_type offset, const TIterator &other) { return TIterator(offset + other.m_ptr); } + TIterator &operator-=(difference_type offset) { m_ptr -= offset; return *this; } + TIterator operator-(difference_type offset) const { return TIterator(m_ptr - offset); } + difference_type operator-(const TIterator &other) const { return m_ptr - other.m_ptr; } + + // Random access operators + T& operator[](difference_type i) { return m_ptr[i]; } + const T& operator[](difference_type i) const { return m_ptr[i]; } + + T &operator*() const { return *m_ptr; } + T* operator->() { return m_ptr; } + +protected: + T* m_ptr; +}; + +// magic little helper. :) +template +class backwards +{ + T& _obj; +public: + backwards(T &obj) : _obj(obj) {} + auto begin() {return _obj.rbegin();} + auto end() {return _obj.rend();} +}; + + +// TArray ------------------------------------------------------------------- + +// Must match TArray's layout. +struct FArray +{ + void *Array; + unsigned int Count; + unsigned int Most; +}; + +// T is the type stored in the array. +// TT is the type returned by operator(). +template +class TArray +{ +public: + + typedef TIterator iterator; + typedef TIterator const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + typedef T value_type; + + iterator begin() + { + return &Array[0]; + } + const_iterator begin() const + { + return &Array[0]; + } + const_iterator cbegin() const + { + return &Array[0]; + } + + iterator end() + { + return &Array[Count]; + } + const_iterator end() const + { + return &Array[Count]; + } + const_iterator cend() const + { + return &Array[Count]; + } + + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + + //////// + // This is a dummy constructor that does nothing. The purpose of this + // is so you can create a global TArray in the data segment that gets + // used by code before startup without worrying about the constructor + // resetting it after it's already been used. You MUST NOT use it for + // heap- or stack-allocated TArrays. + enum ENoInit + { + NoInit + }; + TArray (ENoInit dummy) + { + } + //////// + constexpr TArray () + { + Most = 0; + Count = 0; + Array = NULL; + } + explicit TArray (size_t max, bool reserve = false) + { + Most = (unsigned)max; + Count = (unsigned)(reserve ? max : 0); + Array = max > 0 ? (T *)M_Malloc (sizeof(T)*max) : nullptr; + if (Count > 0) + { + ConstructEmpty(0, Count - 1); + } + } + TArray (const TArray &other) + { + DoCopy (other); + } + TArray (TArray &&other) noexcept + { + Array = other.Array; other.Array = NULL; + Most = other.Most; other.Most = 0; + Count = other.Count; other.Count = 0; + } + TArray &operator= (const TArray &other) + { + if (&other != this) + { + if (Array != NULL) + { + if (Count > 0) + { + DoDelete (0, Count-1); + } + M_Free (Array); + } + DoCopy (other); + } + return *this; + } + TArray &operator= (TArray &&other) noexcept + { + if (Array) + { + if (Count > 0) + { + DoDelete (0, Count-1); + } + M_Free (Array); + } + Array = other.Array; other.Array = NULL; + Most = other.Most; other.Most = 0; + Count = other.Count; other.Count = 0; + return *this; + } + ~TArray () + { + if (Array) + { + if (Count > 0) + { + DoDelete (0, Count-1); + } + M_Free (Array); + Array = NULL; + Count = 0; + Most = 0; + } + } + // Check equality of two arrays + bool operator==(const TArray &other) const + { + if (Count != other.Count) + { + return false; + } + for (unsigned int i = 0; i < Count; ++i) + { + if (Array[i] != other.Array[i]) + { + return false; + } + } + return true; + } + // Return a reference to an element. + // Note that the asserts must let the element after the end pass because this gets frequently used as a sentinel pointer. + T &operator[] (size_t index) const + { + assert(index <= Count); + return Array[index]; + } + // Returns the value of an element + TT operator() (size_t index) const + { + assert(index <= Count); + return Array[index]; + } + // Returns a reference to the last element + T &Last() const + { + assert(Count > 0); + return Array[Count-1]; + } + + T SafeGet (size_t index, const T& defaultval) const + { + if (index <= Count) return Array[index]; + else return defaultval; + } + + // returns address of first element + T *Data(size_t index = 0) const + { + assert(index <= Count); + return &Array[index]; + } + + unsigned IndexOf(const T& elem) const + { + return &elem - Array; + } + + unsigned IndexOf(const T* elem) const + { + return unsigned(elem - Array); + } + + unsigned int Find(const T& item) const + { + unsigned int i; + for(i = 0;i < Count;++i) + { + if(Array[i] == item) + break; + } + return i; + } + + // !!! THIS REQUIRES AN ELEMENT TYPE THAT'S COMPARABLE WITH THE LT OPERATOR !!! + bool IsSorted() + { + for(unsigned i = 1; i < Count; i++) + { + if(Array[i] < Array[i-1]) return false; + } + return true; + } + + template + bool IsSorted(Func &<) + { + for(unsigned i = 1; i < Count; i++) + { + if(std::invoke(lt, Array[i], Array[i-1])) return false; + } + return true; + } + + // !!! THIS REQUIRES A SORTED OR EMPTY ARRAY !!! + // !!! AND AN ELEMENT TYPE THAT'S COMPARABLE WITH THE LT OPERATOR !!! + // + // exact = false returns the closest match, to be used for, ex., insertions, exact = true returns Size() when no match, like Find does + unsigned int SortedFind(const T& item, bool exact = true) const + { + if(Count == 0) return 0; + if(Count == 1) return (item < Array[0]) ? 0 : 1; + + unsigned int lo = 0; + unsigned int hi = Count - 1; + + while(lo <= hi) + { + int mid = lo + ((hi - lo) / 2); + + if(Array[mid] < item) + { + lo = mid + 1; + } + else if(item < Array[mid]) + { + hi = mid - 1; + } + else + { + return mid; + } + } + if(exact) + { + return Count; + } + else + { + return (lo == Count || (item < Array[lo])) ? lo : lo + 1; + } + } + + // !!! THIS REQUIRES A SORTED OR EMPTY ARRAY !!! + // + // exact = false returns the closest match, to be used for, ex., insertions, exact = true returns Size() when no match, like Find does + template + unsigned int SortedFind(const T& item, Func &<, bool exact = true) const + { + if(Count == 0) return 0; + if(Count == 1) return lt(item, Array[0]) ? 0 : 1; + + unsigned int lo = 0; + unsigned int hi = Count - 1; + + while(lo <= hi) + { + int mid = lo + ((hi - lo) / 2); + + if(std::invoke(lt, Array[mid], item)) + { + lo = mid + 1; + } + else if(std::invoke(lt, item, Array[mid])) + { + if(mid == 0) break; // prevent negative overflow due to unsigned numbers + hi = mid - 1; + } + else + { + return mid; + } + } + if(exact) + { + return Count; + } + else + { + return (lo == Count || std::invoke(lt, item, Array[lo])) ? lo : lo + 1; + } + } + + bool Contains(const T& item) const + { + unsigned int i; + for(i = 0;i < Count;++i) + { + if(Array[i] == item) + return true; + } + return false; + } + + template + bool Contains(const T& item, Func &&compare) const + { + unsigned int i; + for(i = 0;i < Count;++i) + { + if(std::invoke(compare, Array[i], item)) + return true; + } + return false; + } + + template + unsigned int FindEx(Func &&compare) const + { + unsigned int i; + for (i = 0; i < Count; ++i) + { + if (std::invoke(compare, Array[i])) + break; + } + return i; + } + + unsigned int Push (const T &item) + { + Grow (1); + ::new((void*)&Array[Count]) T(item); + return Count++; + } + + unsigned int Push(T &&item) + { + Grow(1); + ::new((void*)&Array[Count]) T(std::move(item)); + return Count++; + } + + unsigned Append(const TArray &item) + { + unsigned start = Count; + + Grow(item.Size()); + Count += item.Size(); + + if constexpr (std::is_trivially_copyable::value) + { + memcpy(Array + start,item.Array,item.Size() * sizeof(T)); + } + else + { + for (unsigned i = 0; i < item.Size(); i++) + { + new(&Array[start + i]) T(item[i]); + } + } + return start; + } + + unsigned Append(TArray &&item) + { + unsigned start = Count; + + Grow(item.Size()); + Count += item.Size(); + + if constexpr (std::is_trivially_copyable::value) + { + memcpy(Array + start,item.Array,item.Size() * sizeof(T)); + } + else + { + for (unsigned i = 0; i < item.Size(); i++) + { + new(&Array[start + i]) T(std::move(item[i])); + } + } + item.Clear(); + return start; + } + + unsigned AppendFill(const T& val, unsigned append_count) + { + unsigned start = Count; + + Grow(append_count); + Count += append_count; + if constexpr (std::is_trivially_copyable::value) + { + std::fill(Array + start, Array + Count, val); + } + else + { + for (unsigned i = 0; i < append_count; i++) + { + new(&Array[start + i]) T(val); + } + } + return start; + } + + unsigned AddUnique(const T& obj) + { + auto f = Find(obj); + if (f == Size()) Push(obj); + return f; + } + + unsigned SortedAddUnique(const T& obj) + { + auto f = SortedFind(obj, true); + if (f == Size()) Push(obj); + return f; + } + + template + unsigned SortedAddUnique(const T& obj, Func &<) + { + auto f = SortedFind(obj, std::forward(lt), true); + if (f == Size()) Push(obj); + return f; + } + + bool SortedDelete(const T& obj) + { + auto f = SortedFind(obj, true); + if (f == Size()) + { + Delete(f); + return true; + } + else + { + return false; + } + } + + template + bool SortedDelete(const T& obj, Func &<) + { + auto f = SortedFind(obj, std::forward(lt), true); + if (f == Size()) + { + Delete(f); + return true; + } + else + { + return false; + } + } + + bool Pop () + { + if (Count > 0) + { + Array[--Count].~T(); + return true; + } + return false; + } + bool Pop (T &item) + { + if (Count > 0) + { + item = Array[--Count]; + Array[Count].~T(); + return true; + } + return false; + } + void Delete (unsigned int index) + { + if (index < Count) + { + Array[index].~T(); + if (index < --Count) + { + // Cast to void to assume trivial move + memmove ((void*)&Array[index], (const void*)&Array[index+1], sizeof(T)*(Count - index)); + } + } + } + + void Delete (unsigned int index, int deletecount) + { + if(index >= Count) return; + + if (index + deletecount > Count) + { + deletecount = Count - index; + } + if (deletecount > 0) + { + for (int i = 0; i < deletecount; i++) + { + Array[index + i].~T(); + } + Count -= deletecount; + if (index < Count) + { + // Cast to void to assume trivial move + memmove ((void*)&Array[index], (const void*)&Array[index+deletecount], sizeof(T)*(Count - index)); + } + } + } + + // Inserts an item into the array, shifting elements as needed + void Insert (unsigned int index, const T &item) + { + if (index >= Count) + { + // Inserting somewhere past the end of the array, so we can + // just add it without moving things. + Resize (index + 1); + ::new ((void *)&Array[index]) T(item); + } + else + { + // Inserting somewhere in the middle of the array, + // so make room for it + Resize (Count + 1); + + // Now move items from the index and onward out of the way + // Cast to void to assume trivial move + memmove ((void*)&Array[index+1], (const void*)&Array[index], sizeof(T)*(Count - index - 1)); + + // And put the new element in + ::new ((void *)&Array[index]) T(item); + } + } + + void SortedInsert (const T &item) + { + Insert (SortedFind (item, false), item); + } + + template + void SortedInsert (const T &item, Func &<) + { + Insert (SortedFind (item, std::forward(lt), false), item); + } + + void ShrinkToFit () + { + if (Most > Count) + { + Most = Count; + if (Most == 0) + { + if (Array != NULL) + { + M_Free (Array); + Array = NULL; + } + } + else + { + DoResize (); + } + } + } + // Grow Array to be large enough to hold amount more entries without + // further growing. + void Grow (unsigned int amount) + { + if (Count + amount > Most) + { + const unsigned int choicea = Count + amount; + const unsigned int choiceb = Most = (Most >= 16) ? Most + Most / 2 : 16; + Most = (choicea > choiceb ? choicea : choiceb); + DoResize (); + } + } + // Resize Array so that it has exactly amount entries in use. + void Resize (unsigned int amount) + { + if (Count < amount) + { + // Adding new entries + Grow (amount - Count); + ConstructEmpty(Count, amount - 1); + } + else if (Count != amount) + { + // Deleting old entries + DoDelete (amount, Count - 1); + } + Count = amount; + } + // Ensures that the array has at most amount entries. + // Useful in cases where the initial allocation may be larger than the final result. + // Resize would create a lot of unneeded code in those cases. + void Clamp(unsigned int amount) + { + if (Count > amount) + { + // Deleting old entries + DoDelete(amount, Count - 1); + Count = amount; + } + } + void Alloc(unsigned int amount) + { + // first destroys all content and then rebuilds the array. + if (Count > 0) DoDelete(0, Count - 1); + Count = 0; + Resize(amount); + ShrinkToFit(); + } + // Reserves amount entries at the end of the array, but does nothing + // with them. + unsigned int Reserve (size_t amount) + { + Grow ((unsigned)amount); + unsigned int place = Count; + Count += (unsigned)amount; + if (Count > 0) ConstructEmpty(place, Count - 1); + return place; + } + unsigned int Size () const + { + return Count; + } + int SSize() const + { + return (int)Count; + } + unsigned int Max () const + { + return Most; + } + void Clear () + { + if (Count > 0) + { + DoDelete (0, Count-1); + Count = 0; + } + } + void Reset() + { + Clear(); + Most = 0; + if (Array != nullptr) + { + M_Free(Array); + Array = nullptr; + } + } + + void Swap(TArray &other) + { + std::swap(Array, other.Array); + std::swap(Count, other.Count); + std::swap(Most, other.Most); + } + + // aliases with STL compliant names to allow using TArrays with templates designed for STL containers + + size_t size() const + { + return Count; + } + + T* data() const + { + return Data(); + } + + T& front() const + { + return *Data(); + } + + T& back() const + { + return Last(); + } + + void resize(size_t i) + { + Resize(i); + } + + void push_back(const T& elem) + { + Push(elem); + } + + void clear() + { + Clear(); + } + + +private: + T *Array; + unsigned int Count; + unsigned int Most; + + void DoCopy (const TArray &other) + { + Most = Count = other.Count; + if (Count != 0) + { + Array = (T *)M_Malloc (sizeof(T)*Most); + for (unsigned int i = 0; i < Count; ++i) + { + ::new(&Array[i]) T(other.Array[i]); + } + } + else + { + Array = NULL; + } + } + + void DoResize () + { + size_t allocsize = sizeof(T)*Most; + Array = (T *)M_Realloc (Array, allocsize); + } + + void DoDelete (unsigned int first, unsigned int last) + { + assert (last != ~0u); + for (unsigned int i = first; i <= last; ++i) + { + Array[i].~T(); + } + } + + void ConstructEmpty(unsigned int first, unsigned int last) + { + assert(last != ~0u); + for (unsigned int i = first; i <= last; ++i) + { + ::new(&Array[i]) T; + } + } +}; + +// TDeletingArray ----------------------------------------------------------- +// An array that deletes its elements when it gets deleted. +template +class TDeletingArray : public TArray +{ +public: + TDeletingArray() : TArray() {} + TDeletingArray(TDeletingArray &&other) : TArray(std::move(other)) {} + TDeletingArray &operator=(TDeletingArray &&other) + { + DeleteAndClear(); + TArray::operator=(std::move(other)); + return *this; + } + + ~TDeletingArray () + { + for (unsigned int i = 0; i < TArray::Size(); ++i) + { + if ((*this)[i] != NULL) + delete (*this)[i]; + } + } + void DeleteAndClear() + { + for (unsigned int i = 0; i < TArray::Size(); ++i) + { + if ((*this)[i] != NULL) + delete (*this)[i]; + } + this->Clear(); + } +}; + +// This is only used for exposing the sector's Lines array to ZScript. +// Unlike TArrayView, its members are public as needed by the map loader. + +template +class TStaticPointedArray +{ +public: + + typedef TIterator iterator; + typedef TIterator const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + typedef T value_type; + + iterator begin() + { + return &Array[0]; + } + const_iterator begin() const + { + return &Array[0]; + } + const_iterator cbegin() const + { + return &Array[0]; + } + + iterator end() + { + return &Array[Count]; + } + const_iterator end() const + { + return &Array[Count]; + } + const_iterator cend() const + { + return &Array[Count]; + } + + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + void Init(T *ptr, unsigned cnt) + { + Array = ptr; + Count = cnt; + } + // Return a reference to an element + T &operator[] (size_t index) const + { + return Array[index]; + } + T &At(size_t index) const + { + return Array[index]; + } + unsigned int Size() const + { + return Count; + } + // Some code needs to access these directly so they cannot be private. + T *Array; + unsigned int Count; +}; + +// TAutoGrowArray ----------------------------------------------------------- +// An array with accessors that automatically grow the array as needed. +// It can still be used as a normal TArray if needed. ACS uses this for +// world and global arrays. + +template +class TAutoGrowArray : public TArray +{ +public: + T GetVal (unsigned int index) + { + if (index >= this->Size()) + { + return 0; + } + return (*this)[index]; + } + void SetVal (unsigned int index, T val) + { + if ((int)index < 0) return; // These always result in an out of memory condition. + + if (index >= this->Size()) + { + this->Resize (index + 1); + } + (*this)[index] = val; + } +}; + +// TMap --------------------------------------------------------------------- +// An associative array, similar in concept to the STL extension +// class hash_map. It is implemented using Lua's table algorithm: +/* +** Hash uses a mix of chained scatter table with Brent's variation. +** A main invariant of these tables is that, if an element is not +** in its main position (i.e. the `original' position that its hash gives +** to it), then the colliding element is in its own main position. +** Hence even when the load factor reaches 100%, performance remains good. +*/ +/****************************************************************************** +* Copyright (C) 1994-2006 Lua.org, PUC-Rio. All rights reserved. +* +* 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. +******************************************************************************/ + +typedef unsigned int hash_t; + +template struct THashTraits +{ + // Returns the hash value for a key. + hash_t Hash(const KT key) { return (hash_t)(intptr_t)key; } + hash_t Hash(double key) + { + hash_t keyhash[2]; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash[0] ^ keyhash[1]; + } + + // Compares two keys, returning zero if they are the same. + int Compare(const KT left, const KT right) { return left != right; } +}; + +template<> struct THashTraits +{ + // Use all bits when hashing singles instead of converting them to ints. + hash_t Hash(float key) + { + hash_t keyhash; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash; + } + int Compare(float left, float right) { return left != right; } +}; + +template<> struct THashTraits +{ + // Use all bits when hashing doubles instead of converting them to ints. + hash_t Hash(double key) + { + hash_t keyhash[2]; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash[0] ^ keyhash[1]; + } + int Compare(double left, double right) { return left != right; } +}; + +template struct TValueTraits +{ + // Initializes a value for TMap. If a regular constructor isn't + // good enough, you can override it. + void Init(VT &value) + { + ::new(&value) VT; + } +}; + +// Must match layout of TMap +struct FMap +{ + void *Nodes; + void *LastFree; + hash_t Size; + hash_t NumUsed; +}; + + +template class TMapIterator; +template class TMapConstIterator; + +template, class ValueTraits=TValueTraits > +class TMap +{ + template friend class TMapIterator; + template friend class TMapConstIterator; + +public: + typedef class TMap MyType; + typedef class TMapIterator Iterator; + typedef class TMapConstIterator ConstIterator; + typedef struct { const KT Key; VT Value; } Pair; + typedef const Pair ConstPair; + + typedef KT KeyType; + typedef VT ValueType; + + TMap() { NumUsed = 0; SetNodeVector(1); } + TMap(hash_t size) { NumUsed = 0; SetNodeVector(size); } + ~TMap() { ClearNodeVector(); } + + TMap(const TMap &o) + { + NumUsed = 0; + SetNodeVector(o.CountUsed()); + CopyNodes(o.Nodes, o.Size); + } + + TMap(TMap &&o) + { + Nodes = o.Nodes; + LastFree = o.LastFree; /* any free position is before this position */ + Size = o.Size; /* must be a power of 2 */ + NumUsed = o.NumUsed; + + o.Size = 0; + o.NumUsed = 0; + o.SetNodeVector(1); + } + + TMap &operator= (const TMap &o) + { + NumUsed = 0; + ClearNodeVector(); + SetNodeVector(o.CountUsed()); + CopyNodes(o.Nodes, o.Size); + return *this; + } + + TMap &operator= (TMap &&o) + { + TransferFrom(o); + return *this; + } + + //======================================================================= + // + // TransferFrom + // + // Moves the contents from one TMap to another, leaving the TMap moved + // from empty. + // + //======================================================================= + + void TransferFrom(TMap &o) + { + // Clear all our nodes. + NumUsed = 0; + ClearNodeVector(); + + // Copy all of o's nodes. + Nodes = o.Nodes; + LastFree = o.LastFree; + Size = o.Size; + NumUsed = o.NumUsed; + + // Tell o it doesn't have any nodes. + o.Nodes = NULL; + o.Size = 0; + o.LastFree = NULL; + o.NumUsed = 0; + + // Leave o functional with one empty node. + o.SetNodeVector(1); + } + + //======================================================================= + // + // Clear + // + // Empties out the table and resizes it with room for count entries. + // + //======================================================================= + + void Clear(hash_t count=1) + { + ClearNodeVector(); + SetNodeVector(count); + } + + //======================================================================= + // + // CountUsed + // + // Returns the number of entries in use in the table. + // + //======================================================================= + + hash_t CountUsed() const + { +#ifdef _DEBUG + hash_t used = 0; + hash_t ct = Size; + for (Node *n = Nodes; ct-- > 0; ++n) + { + if (!n->IsNil()) + { + ++used; + } + } + assert (used == NumUsed); +#endif + return NumUsed; + } + + //======================================================================= + // + // operator[] + // + // Returns a reference to the value associated with a particular key, + // creating the pair if the key isn't already in the table. + // + //======================================================================= + + VT &operator[] (const KT key) + { + return GetNode(key)->Pair.Value; + } + + const VT &operator[] (const KT key) const + { + return GetNode(key)->Pair.Value; + } + + //======================================================================= + // + // CheckKey + // + // Returns a pointer to the value associated with a particular key, or + // NULL if the key isn't in the table. + // + //======================================================================= + + VT *CheckKey (const KT key) + { + Node *n = FindKey(key); + return n != NULL ? &n->Pair.Value : NULL; + } + + const VT *CheckKey (const KT key) const + { + const Node *n = FindKey(key); + return n != NULL ? &n->Pair.Value : NULL; + } + + //======================================================================= + // + // Insert + // + // Adds a key/value pair to the table if key isn't in the table, or + // replaces the value for the existing pair if the key is in the table. + // + // This is functionally equivalent to (*this)[key] = value; but can be + // slightly faster if the pair needs to be created because it doesn't run + // the constructor on the value part twice. + // + //======================================================================= + + VT &Insert(const KT key, const VT &value) + { + Node *n = FindKey(key); + if (n != NULL) + { + n->Pair.Value = value; + } + else + { + n = NewKey(key); + ::new(&n->Pair.Value) VT(value); + } + return n->Pair.Value; + } + + VT &Insert(const KT key, VT &&value) + { + Node *n = FindKey(key); + if (n != NULL) + { + n->Pair.Value = value; + } + else + { + n = NewKey(key); + ::new(&n->Pair.Value) VT(value); + } + return n->Pair.Value; + } + + VT &InsertNew(const KT key) + { + Node *n = FindKey(key); + if (n != NULL) + { + n->Pair.Value.~VT(); + } + else + { + n = NewKey(key); + } + ::new(&n->Pair.Value) VT; + return n->Pair.Value; + } + + //======================================================================= + // + // Remove + // + // Removes the key/value pair for a particular key if it is in the table. + // + //======================================================================= + + void Remove(const KT key) + { + DelKey(key); + } + + void Swap(MyType &other) + { + std::swap(Nodes, other.Nodes); + std::swap(LastFree, other.LastFree); + std::swap(Size, other.Size); + std::swap(NumUsed, other.NumUsed); + } + +protected: + struct IPair // This must be the same as Pair above, but with a + { // non-const Key. + KT Key; + VT Value; + }; + struct Node + { + Node *Next; + IPair Pair; + void SetNil() + { + Next = (Node *)1; + } + bool IsNil() const + { + return Next == (Node *)1; + } + }; + + /* This is used instead of memcpy, because Node is likely to be small, + * such that the time spent calling a function would eclipse the time + * spent copying. */ + struct NodeSizedStruct { unsigned char Pads[sizeof(Node)]; }; + + Node *Nodes; + Node *LastFree; /* any free position is before this position */ + hash_t Size; /* must be a power of 2 */ + hash_t NumUsed; + + const Node *MainPosition(const KT k) const + { + HashTraits Traits; + return &Nodes[Traits.Hash(k) & (Size - 1)]; + } + + Node *MainPosition(const KT k) + { + HashTraits Traits; + return &Nodes[Traits.Hash(k) & (Size - 1)]; + } + + void SetNodeVector(hash_t size) + { + // Round size up to nearest power of 2 + for (Size = 1; Size < size; Size <<= 1) + { } + Nodes = (Node *)M_Malloc(Size * sizeof(Node)); + LastFree = &Nodes[Size]; /* all positions are free */ + for (hash_t i = 0; i < Size; ++i) + { + Nodes[i].SetNil(); + } + } + + void ClearNodeVector() + { + for (hash_t i = 0; i < Size; ++i) + { + if (!Nodes[i].IsNil()) + { + Nodes[i].~Node(); + } + } + M_Free(Nodes); + Nodes = NULL; + Size = 0; + LastFree = NULL; + NumUsed = 0; + } + + void Resize(hash_t nhsize) + { + hash_t i, oldhsize = Size; + Node *nold = Nodes; + /* create new hash part with appropriate size */ + SetNodeVector(nhsize); + /* re-insert elements from hash part */ + NumUsed = 0; + for (i = 0; i < oldhsize; ++i) + { + if (!nold[i].IsNil()) + { + Node *n = NewKey(nold[i].Pair.Key); + ::new(&n->Pair.Value) VT(std::move(nold[i].Pair.Value)); + nold[i].~Node(); + } + } + M_Free(nold); + } + + void Rehash() + { + Resize (Size << 1); + } + + Node *GetFreePos() + { + while (LastFree-- > Nodes) + { + if (LastFree->IsNil()) + { + return LastFree; + } + } + return NULL; /* could not find a free place */ + } + + /* + ** Inserts a new key into a hash table; first, check whether key's main + ** position is free. If not, check whether colliding node is in its main + ** position or not: if it is not, move colliding node to an empty place and + ** put new key in its main position; otherwise (colliding node is in its main + ** position), new key goes to an empty position. + ** + ** The Value field is left unconstructed. + */ + Node *NewKey(const KT key) + { + Node *mp = MainPosition(key); + if (!mp->IsNil()) + { + Node *othern; + Node *n = GetFreePos(); /* get a free place */ + if (n == NULL) /* cannot find a free place? */ + { + Rehash(); /* grow table */ + return NewKey(key); /* re-insert key into grown table */ + } + othern = MainPosition(mp->Pair.Key); + if (othern != mp) /* is colliding node out of its main position? */ + { /* yes; move colliding node into free position */ + while (othern->Next != mp) /* find previous */ + { + othern = othern->Next; + } + othern->Next = n; /* redo the chain with 'n' in place of 'mp' */ + CopyNode(n, mp); /* copy colliding node into free pos. (mp->Next also goes) */ + mp->Next = NULL; /* now 'mp' is free */ + } + else /* colliding node is in its own main position */ + { /* new node will go into free position */ + n->Next = mp->Next; /* chain new position */ + mp->Next = n; + mp = n; + } + } + else + { + mp->Next = NULL; + } + ++NumUsed; + ::new(&mp->Pair.Key) KT(key); + return mp; + } + + void DelKey(const KT key) + { + Node *mp = MainPosition(key), **mpp; + HashTraits Traits; + + if (mp->IsNil()) + { + /* the key is definitely not present, because there is nothing at its main position */ + } + else if (!Traits.Compare(mp->Pair.Key, key)) /* the key is in its main position */ + { + if (mp->Next != NULL) /* move next node to its main position */ + { + Node *n = mp->Next; + mp->~Node(); /* deconstruct old node */ + CopyNode(mp, n); /* copy next node */ + n->SetNil(); /* next node is now nil */ + } + else + { + mp->~Node(); + mp->SetNil(); /* there is no chain, so main position is nil */ + } + --NumUsed; + } + else /* the key is either not present or not in its main position */ + { + for (mpp = &mp->Next, mp = *mpp; mp != NULL && Traits.Compare(mp->Pair.Key, key); mpp = &mp->Next, mp = *mpp) + { } /* look for the key */ + if (mp != NULL) /* found it */ + { + *mpp = mp->Next; /* rechain so this node is skipped */ + mp->~Node(); + mp->SetNil(); /* because this node is now nil */ + --NumUsed; + } + } + } + + Node *FindKey(const KT key) + { + HashTraits Traits; + Node *n = MainPosition(key); + while (n != NULL && !n->IsNil() && Traits.Compare(n->Pair.Key, key)) + { + n = n->Next; + } + return n == NULL || n->IsNil() ? NULL : n; + } + + const Node *FindKey(const KT key) const + { + HashTraits Traits; + const Node *n = MainPosition(key); + while (n != NULL && !n->IsNil() && Traits.Compare(n->Pair.Key, key)) + { + n = n->Next; + } + return n == NULL || n->IsNil() ? NULL : n; + } + + Node *GetNode(const KT key) + { + Node *n = FindKey(key); + if (n != NULL) + { + return n; + } + n = NewKey(key); + ValueTraits traits; + traits.Init(n->Pair.Value); + return n; + } + + /* Perform a bit-wise copy of the node. Used when relocating a node in the table. */ + void CopyNode(Node *dst, const Node *src) + { + *(NodeSizedStruct *)dst = *(const NodeSizedStruct *)src; + } + + /* Copy all nodes in the node vector to this table. */ + void CopyNodes(const Node *nodes, hash_t numnodes) + { + for (; numnodes-- > 0; ++nodes) + { + if (!nodes->IsNil()) + { + Node *n = NewKey(nodes->Pair.Key); + ::new(&n->Pair.Value) VT(nodes->Pair.Value); + } + } + } +}; + +// TMapIterator ------------------------------------------------------------- +// A class to iterate over all the pairs in a TMap. + +template > +class TMapIterator +{ +public: + TMapIterator(MapType &map) + : Map(map), Position(0) + { + } + + //======================================================================= + // + // NextPair + // + // Returns false if there are no more entries in the table. Otherwise, it + // returns true, and pair is filled with a pointer to the pair in the + // table. + // + //======================================================================= + + bool NextPair(typename MapType::Pair *&pair) + { + if (Position >= Map.Size) + { + return false; + } + do + { + if (!Map.Nodes[Position].IsNil()) + { + pair = reinterpret_cast(&Map.Nodes[Position].Pair); + Position += 1; + return true; + } + } while (++Position < Map.Size); + return false; + } + + //======================================================================= + // + // Reset + // + // Restarts the iteration so you can do it all over again. + // + //======================================================================= + + void Reset() + { + Position = 0; + } + +protected: + MapType ⤅ + hash_t Position; +}; + +// TMapConstIterator -------------------------------------------------------- +// Exactly the same as TMapIterator, but it works with a const TMap. + +template > +class TMapConstIterator +{ +public: + TMapConstIterator(const MapType &map) + : Map(map), Position(0) + { + } + + bool NextPair(typename MapType::ConstPair *&pair) + { + if (Position >= Map.Size) + { + return false; + } + do + { + if (!Map.Nodes[Position].IsNil()) + { + pair = reinterpret_cast(&Map.Nodes[Position].Pair); + Position += 1; + return true; + } + } while (++Position < Map.Size); + return false; + } + +protected: + const MapType ⤅ + hash_t Position; +}; + + +// Pointer wrapper without the unpleasant side effects of std::unique_ptr, mainly the inability to copy it. +// This class owns the object with no means to release it, and copying the pointer copies the object. +template +class TPointer +{ +public: + + //////// + TPointer() + { + Ptr = nullptr; + } + TPointer(const T& other) = delete; + /* + { + Alloc(); + *Ptr = other; + } + */ + TPointer(T&& other) + { + Alloc(); + *Ptr = other; + } + TPointer(const TPointer& other) = delete; + /* + { + DoCopy(other); + } + */ + TPointer(TPointer&& other) + { + Ptr = other.Ptr; + other.Ptr = nullptr; + } + TPointer& operator= (const T& other) + { + if (&other != this) + { + Alloc(); + *Ptr = other; + } + return *this; + } + TPointer& operator= (const TPointer& other) + { + if (&other != this) + { + DoCopy(other); + } + return *this; + } + TPointer& operator= (TPointer&& other) + { + if (&other != this) + { + if (Ptr) delete Ptr; + Ptr = other.Ptr; + other.Ptr = nullptr; + } + return *this; + } + ~TPointer() + { + if (Ptr) delete Ptr; + Ptr = nullptr; + } + // Check equality of two pointers + bool operator==(const TPointer& other) const + { + return *Ptr == *other.Ptr; + } + + T& operator* () const + { + assert(Ptr); + return *Ptr; + } + + T* operator->() { return Ptr; } + + // returns raw pointer + T* Data() const + { + return Ptr; + } + +#if 0 // this is too dangerous. + operator T* () const + { + return Ptr; + } +#endif + + void Alloc() + { + if (!Ptr) Ptr = new T; + } + + void Clear() + { + if (Ptr) delete Ptr; + Ptr = nullptr; + } + + void Swap(TPointer& other) + { + std::swap(Ptr, other.Ptr); + } + +private: + T* Ptr; + + void DoCopy(const TPointer& other) + { + if (other.Ptr == nullptr) + { + Clear(); + } + else + { + Alloc(); + *Ptr = *other.Ptr; + } + } +}; + + + +//========================================================================== +// +// an array to hold a small number of unique entries +// +//========================================================================== + +template class UniqueList +{ + TArray Array; + +public: + + T * Get(T * t) + { + for (unsigned i = 0; i bytes; + unsigned size; + +public: + void Resize(unsigned elem) + { + bytes.Resize((elem + 7) / 8); + size = elem; + } + + BitArray() : size(0) + { + } + + BitArray(unsigned elem) + : bytes((elem + 7) / 8, true), size(elem) + { + + } + + BitArray(const BitArray & arr) + : bytes(arr.bytes) + { + size = arr.size; + } + + BitArray &operator=(const BitArray & arr) + { + bytes = arr.bytes; + size = arr.size; + return *this; + } + + BitArray(BitArray && arr) noexcept + : bytes(std::move(arr.bytes)) + { + size = arr.size; + arr.size = 0; + } + + BitArray &operator=(BitArray && arr) noexcept + { + bytes = std::move(arr.bytes); + size = arr.size; + arr.size = 0; + return *this; + } + + bool operator[](size_t index) const + { + return !!(bytes[index >> 3] & (1 << (index & 7))); + } + + // for when array syntax cannot be used. + bool Check(size_t index) const + { + return !!(bytes[index >> 3] & (1 << (index & 7))); + } + + void Set(size_t index, bool set = true) + { + if (!set) Clear(index); + else bytes[index >> 3] |= (1 << (index & 7)); + } + + void Clear(size_t index) + { + bytes[index >> 3] &= ~(1 << (index & 7)); + } + + unsigned Size() const + { + return size; + } + + void Zero() + { + memset(&bytes[0], 0, bytes.Size()); + } + + TArray &Storage() + { + return bytes; + } +}; + + +template +class FixedBitArray +{ + uint8_t bytes[(size + 7) / 8]; + +public: + + FixedBitArray() = default; + FixedBitArray(bool set) + { + memset(bytes, set ? -1 : 0, sizeof(bytes)); + } + + bool operator[](size_t index) const + { + return !!(bytes[index >> 3] & (1 << (index & 7))); + } + + void Set(size_t index, bool set = true) + { + if (!set) Clear(index); + else bytes[index >> 3] |= (1 << (index & 7)); + } + + void Clear(size_t index) + { + bytes[index >> 3] &= ~(1 << (index & 7)); + } + + constexpr unsigned Size() const + { + return size; + } + + void Zero() + { + memset(&bytes[0], 0, sizeof(bytes)); + } + + void SetAll(bool on) + { + memset(&bytes[0], on ? -1 : 0, sizeof(bytes)); + } + + // These are for utilities that need access to the raw storage. The serializer needs this to do its work, for example. + uint8_t* Storage() + { + return bytes; + } + unsigned StorageSize() const + { + return sizeof(bytes); + } +}; + +// A wrapper to externally stored data. +// I would have expected something for this in the stl, but std::span is only in C++20. +template +class TArrayView +{ +public: + + typedef TIterator iterator; + typedef TIterator const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + typedef T value_type; + + iterator begin() + { + return &Array[0]; + } + const_iterator begin() const + { + return &Array[0]; + } + const_iterator cbegin() const + { + return &Array[0]; + } + + iterator end() + { + return &Array[Count]; + } + const_iterator end() const + { + return &Array[Count]; + } + const_iterator cend() const + { + return &Array[Count]; + } + + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + + //////// + TArrayView() = default; // intended to keep this type trivial. + TArrayView(T *data, unsigned count = 0) + { + Count = count; + Array = data; + } + TArrayView(const TArrayView &other) = default; + TArrayView &operator= (const TArrayView &other) = default; + + // Check equality of two arrays + bool operator==(const TArrayView &other) const + { + if (Count != other.Count) + { + return false; + } + for (unsigned int i = 0; i < Count; ++i) + { + if (Array[i] != other.Array[i]) + { + return false; + } + } + return true; + } + // Return a reference to an element + T &operator[] (size_t index) const + { + assert(index < Count); + return Array[index]; + } + // Returns a reference to the last element + T &Last() const + { + assert(Count > 0); + return Array[Count - 1]; + } + + // returns address of first element + T *Data() const + { + return Array; + } + + unsigned Size() const + { + return Count; + } + + unsigned int Find(const T& item) const + { + unsigned int i; + for (i = 0; i < Count; ++i) + { + if (Array[i] == item) + break; + } + return i; + } + + void Set(T *data, unsigned count) + { + Array = data; + Count = count; + } + + void Clear() + { + Count = 0; + Array = nullptr; + } +private: + T *Array; + unsigned int Count; +}; + +#if !__has_include("m_alloc.h") + #undef M_Malloc + #undef M_Realloc + #undef M_Free +#endif diff --git a/src/common/utility/templates.h b/src/common/utility/templates.h new file mode 100644 index 00000000000..22b9f3d3f29 --- /dev/null +++ b/src/common/utility/templates.h @@ -0,0 +1,97 @@ +/* +** templates.h +** Some useful template functions +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __TEMPLATES_H__ +#define __TEMPLATES_H__ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +//========================================================================== +// +// BinarySearch +// +// Searches an array sorted in ascending order for an element matching +// the desired key. +// +// Template parameters: +// ClassType - The class to be searched +// KeyType - The type of the key contained in the class +// +// Function parameters: +// first - Pointer to the first element in the array +// max - The number of elements in the array +// keyptr - Pointer to the key member of ClassType +// key - The key value to look for +// +// Returns: +// A pointer to the element with a matching key or NULL if none found. +//========================================================================== + +template +inline +const ClassType *BinarySearch (const ClassType *first, int max, + const KeyType ClassType::*keyptr, const KeyType key) +{ + int min = 0; + --max; + + while (min <= max) + { + int mid = (min + max) / 2; + const ClassType *probe = &first[mid]; + const KeyType &seekey = probe->*keyptr; + if (seekey == key) + { + return probe; + } + else if (seekey < key) + { + min = mid + 1; + } + else + { + max = mid - 1; + } + } + return NULL; +} + + +#endif //__TEMPLATES_H__ diff --git a/src/common/utility/tflags.h b/src/common/utility/tflags.h new file mode 100644 index 00000000000..f872d4574c3 --- /dev/null +++ b/src/common/utility/tflags.h @@ -0,0 +1,108 @@ +/* +** tflags.h +** +**--------------------------------------------------------------------------- +** Copyright 2015 Teemu Piippo +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#pragma once + +/* + * TFlags + * + * A Qt-inspired type-safe flagset type. + * + * T is the enum type of individual flags, + * TT is the underlying integer type used (defaults to uint32_t) + */ +template +class TFlags +{ + struct ZeroDummy {}; + +public: + typedef TFlags Self; + typedef T EnumType; + typedef TT IntType; + + TFlags() = default; + TFlags(const Self& other) = default; + constexpr TFlags (T value) : Value (static_cast (value)) {} + + // This allows initializing the flagset with 0, as 0 implicitly converts into a null pointer. + constexpr TFlags (ZeroDummy*) : Value (0) {} + + // Relation operators + constexpr Self operator| (const Self& other) const { return Self::FromInt (Value | other.GetValue()); } + constexpr Self operator& (const Self& other) const { return Self::FromInt (Value & other.GetValue()); } + constexpr Self operator^ (const Self& other) const { return Self::FromInt (Value ^ other.GetValue()); } + constexpr Self operator| (T value) const { return Self::FromInt (Value | value); } + constexpr Self operator& (T value) const { return Self::FromInt (Value & value); } + constexpr Self operator^ (T value) const { return Self::FromInt (Value ^ value); } + constexpr Self operator~() const { return Self::FromInt (~Value); } + + // Assignment operators + constexpr Self& operator= (const Self& other) = default; + constexpr Self& operator|= (const Self& other) { Value |= other.GetValue(); return *this; } + constexpr Self& operator&= (const Self& other) { Value &= other.GetValue(); return *this; } + constexpr Self& operator^= (const Self& other) { Value ^= other.GetValue(); return *this; } + constexpr Self& operator= (T value) { Value = value; return *this; } + constexpr Self& operator|= (T value) { Value |= value; return *this; } + constexpr Self& operator&= (T value) { Value &= value; return *this; } + constexpr Self& operator^= (T value) { Value ^= value; return *this; } + + // Access the value of the flagset + constexpr TT GetValue() const { return Value; } + constexpr operator TT() const { return Value; } + + // Set the value of the flagset manually with an integer. + // Please think twice before using this. + static constexpr Self FromInt (TT value) { return Self (static_cast (value)); } + +private: + template constexpr Self operator| (X value) const { return Self::FromInt (Value | value); } + template constexpr Self operator& (X value) const { return Self::FromInt (Value & value); } + template constexpr Self operator^ (X value) const { return Self::FromInt (Value ^ value); } + +public: // to be removed. + TT Value; +}; + +/* + * Additional operators for TFlags types. + */ +#define DEFINE_TFLAGS_OPERATORS(T) \ +constexpr inline T operator| (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) | T::IntType (b)); } \ +constexpr inline T operator& (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) & T::IntType (b)); } \ +constexpr inline T operator^ (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) ^ T::IntType (b)); } \ +constexpr inline T operator| (T::EnumType a, T b) { return T::FromInt (T::IntType (a) | T::IntType (b)); } \ +constexpr inline T operator& (T::EnumType a, T b) { return T::FromInt (T::IntType (a) & T::IntType (b)); } \ +constexpr inline T operator^ (T::EnumType a, T b) { return T::FromInt (T::IntType (a) ^ T::IntType (b)); } \ +constexpr inline T operator~ (T::EnumType a) { return T::FromInt (~T::IntType (a)); } + diff --git a/src/common/utility/utf8.cpp b/src/common/utility/utf8.cpp new file mode 100644 index 00000000000..5ac7fc9f15b --- /dev/null +++ b/src/common/utility/utf8.cpp @@ -0,0 +1,1221 @@ +/* +** utf8.cpp +** UTF-8 utilities +** +**--------------------------------------------------------------------------- +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ +#include +#include "tarray.h" +#include "utf8.h" + + +//========================================================================== +// +// +// +//========================================================================== + +int utf8_encode(int32_t codepoint, uint8_t *buffer, int *size) +{ + if (codepoint < 0) + return -1; + else if (codepoint < 0x80) + { + buffer[0] = (char)codepoint; + *size = 1; + } + else if (codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } + else if (codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } + else if (codepoint <= 0x10FFFF) + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } + else + return -1; + + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +int utf8_decode(const uint8_t *src, int *size) +{ + int c = src[0]; + int r; + + *size = 1; + if ((c & 0x80) == 0) + { + return c; + } + + int c1 = src[1]; + if (c1 < 0x80 || c1 >= 0xc0) return -1; + c1 &= 0x3f; + + if ((c & 0xE0) == 0xC0) + { + r = ((c & 0x1F) << 6) | c1; + if (r >= 128) + { + *size = 2; + return r; + } + return -1; + } + + int c2 = src[2]; + if (c2 < 0x80 || c2 >= 0xc0) return -1; + c2 &= 0x3f; + + if ((c & 0xF0) == 0xE0) + { + r = ((c & 0x0F) << 12) | (c1 << 6) | c2; + if (r >= 2048 && (r < 55296 || r > 57343)) + { + *size = 3; + return r; + } + return -1; + } + + int c3 = src[3]; + if (c3 < 0x80 || c1 >= 0xc0) return -1; + c3 &= 0x3f; + + if ((c & 0xF8) == 0xF0) + { + r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; + if (r >= 65536 && r <= 1114111) + { + *size = 4; + return r; + } + } + return -1; +} + +//========================================================================== +// +// Unicode mapping for the 0x80-0x9f range of the Windows 1252 code page +// +//========================================================================== + +uint16_t win1252map[] = { + 0x20AC, + 0x81 , + 0x201A, + 0x0192, + 0x201E, + 0x2026, + 0x2020, + 0x2021, + 0x02C6, + 0x2030, + 0x0160, + 0x2039, + 0x0152, + 0x8d , + 0x017D, + 0x8f , + 0x90 , + 0x2018, + 0x2019, + 0x201C, + 0x201D, + 0x2022, + 0x2013, + 0x2014, + 0x02DC, + 0x2122, + 0x0161, + 0x203A, + 0x0153, + 0x9d , + 0x017E, + 0x0178, +}; + +//========================================================================== +// +// reads one character from the string. +// This can handle both ISO 8859-1/Windows-1252 and UTF-8, as well as mixed strings +// between both encodings, which may happen if inconsistent encoding is +// used between different files in a mod. +// +//========================================================================== + +int GetCharFromString(const uint8_t *&string) +{ + int z; + + z = *string; + + if (z < 192) + { + string++; + + // Handle Windows 1252 characters + if (z >= 128 && z < 160) + { + return win1252map[z - 128]; + } + return z; + } + else + { + int size = 0; + auto chr = utf8_decode(string, &size); + if (chr >= 0) + { + string += size; + return chr; + } + string++; + return z; + } +} + +//========================================================================== +// +// convert a potentially mixed-encoded string to pure UTF-8 +// this returns a pointer to a static buffer, +// assuming that its caller will immediately process the result. +// +//========================================================================== + +static TArray UTF8String; + +const char *MakeUTF8(const char *outline, int *numchars) +{ + UTF8String.Clear(); + const uint8_t *in = (const uint8_t*)outline; + + if (numchars) *numchars = 0; + while (int chr = GetCharFromString(in)) + { + int size = 0; + uint8_t encode[4]; + if (!utf8_encode(chr, encode, &size)) + { + for (int i = 0; i < size; i++) + { + UTF8String.Push(encode[i]); + } + } + if (numchars) (*numchars)++; + } + UTF8String.Push(0); + return UTF8String.Data(); +} + +const char *MakeUTF8(int codepoint, int *psize) +{ + int size = 0; + UTF8String.Resize(5); + utf8_encode(codepoint, (uint8_t*)UTF8String.Data(), &size); + UTF8String[size] = 0; + if (psize) *psize = size; + return UTF8String.Data(); +} + + +//========================================================================== +// +// Returns a character without an accent mark (or one with a similar looking accent in some cases where direct support is unlikely.) +// +//========================================================================== + +int stripaccent(int code) +{ + if (code < 0x8a) + return code; + if (code < 0x100) + { + if (code == 0x8a) // Latin capital letter S with caron + return 'S'; + if (code == 0x8e) // Latin capital letter Z with caron + return 'Z'; + if (code == 0x9a) // Latin small letter S with caron + return 's'; + if (code == 0x9e) // Latin small letter Z with caron + return 'z'; + if (code == 0x9f) // Latin capital letter Y with diaeresis + return 'Y'; + if (code == 0xab || code == 0xbb) return '"'; // typographic quotation marks. + if (code == 0xff) // Latin small letter Y with diaeresis + return 'y'; + // Every other accented character has the high two bits set. + if ((code & 0xC0) == 0) + return code; + // Make lowercase characters uppercase so there are half as many tests. + int acode = code & 0xDF; + if (acode >= 0xC0 && acode <= 0xC5) // A with accents + return 'A' + (code & 0x20); + if (acode == 0xC7) // Cedilla + return 'C' + (acode & 0x20); + if (acode >= 0xC8 && acode <= 0xCB) // E with accents + return 'E' + (code & 0x20); + if (acode >= 0xCC && acode <= 0xCF) // I with accents + return 'I' + (code & 0x20); + if (acode == 0xD0) // Eth + return 'D' + (code & 0x20); + if (acode == 0xD1) // N with tilde + return 'N' + (code & 0x20); + if ((acode >= 0xD2 && acode <= 0xD6) || // O with accents + acode == 0xD8) // O with stroke + return 'O' + (code & 0x20); + if (acode >= 0xD9 && acode <= 0xDC) // U with accents + return 'U' + (code & 0x20); + if (acode == 0xDD) // Y with accute + return 'Y' + (code & 0x20); + if (acode == 0xDE) // Thorn + return 'P' + (code & 0x20); // well, it sort of looks like a 'P' + } + else if (code >= 0x100 && code < 0x180) + { + // For the double-accented Hungarian letters it makes more sense to first map them to the very similar looking Umlauts. + // (And screw the crappy specs that do not allow UTF-8 multibyte character literals here.) + if (code == 0x150) code = 0xd6; + else if (code == 0x151) code = 0xf6; + else if (code == 0x170) code = 0xdc; + else if (code == 0x171) code = 0xfc; + else + { + static const char accentless[] = "AaAaAaCcCcCcCcDdDdEeEeEeEeEeGgGgGgGgHhHhIiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnnNnOoOoOoOoRrRrRrSsSsSsSsTtTtTtUuUuUuUuUuUuWwYyYZzZzZzs"; + return accentless[code - 0x100]; + } + } + else if (code >= 0x1fc && code < 0x218) + { + // 0x200-0x217 are irrelevant but easy to map to other characters more likely to exist. + static const uint16_t u200map[] = {0xc6, 0xe6, 0xd8, 0xf8, 0xc4, 0xe4, 0xc2, 0xe2, 0xcb, 0xeb, 0xca, 0xea, 0xcf, 0xef, 0xce, 0xee, 0xd6, 0xf6, 0xd4, 0xe4, 'R', 'r', 'R', 'r', 0xdc, 0xfc, 0xdb, 0xfb}; + return u200map[code - 0x1fc]; + } + return getAlternative(code); +} + +//========================================================================== +// +// Return replacement characters that should not make font completeness tests fail. +// +//========================================================================== + +int getAlternative(int code) +{ + switch (code) + { + default: + return code; + + case '{': return '('; + case '}': return ')'; + case 0x17f: return 's'; // The 'long s' can be safely remapped to the regular variant, not that this gets used in any real text... + case 0x218: return 0x15e; // Romanian S with comma below may get remapped to S with cedilla. + case 0x219: return 0x15f; + case 0x21a: return 0x162; // Romanian T with comma below may get remapped to T with cedilla. + case 0x21b: return 0x163; + case 0x386: return 0x391; // Greek characters with accents must map to their base form due to the "no accents in allcaps " rule. + case 0x388: return 0x395; + case 0x389: return 0x397; + case 0x38a: return 0x399; + case 0x38c: return 0x39f; + case 0x3a0: return 0x41f; + case 0x38e: return 0x3a5; + case 0x38f: return 0x3a9; + case 0x391: return 'A';// Greek characters with equivalents in either Latin or Cyrillic. This is only suitable for uppercase fonts! + case 0x392: return 'B'; + case 0x393: return 0x413; + case 0x395: return 'E'; + case 0x396: return 'Z'; + case 0x397: return 'H'; + case 0x399: return 'I'; + case 0x39a: return 'K'; + case 0x39c: return 'M'; + case 0x39d: return 'N'; + case 0x39f: return 'O'; + case 0x3a1: return 'P'; + case 0x3a4: return 'T'; + case 0x3a5: return 'Y'; + case 0x3a6: return 0x424; + case 0x3a7: return 'X'; + case 0x3aa: return 0xcf; + case 0x3ab: return 0x178; + case 0x3bf: return 'o'; // the Omicron is the only small Greek character that's easily mappable to a Latin equivalent. :( + case 0x3c2: return 0x3c3; // Lowercase Sigma character in Greek, which changes depending on its positioning in a word; if the font is uppercase only or features a smallcaps style, the second variant of the letter will remain unused + case 0x390: return 0x3ca; // For smallcaps fonts the small accented Greek characters remap to the unaccented versions. + case 0x3ac: return 0x3b1; + case 0x3ad: return 0x3b5; + case 0x3ae: return 0x3b7; + case 0x3af: return 0x3b9; + case 0x3b0: return 0x3cb; + case 0x3cc: return 0x3bf; + case 0x3cd: return 0x3c5; + case 0x3ce: return 0x3c9; + case 0x400: return 0xc8; // Cyrillic characters with equivalents in the Latin alphabet. + case 0x401: return 0xcb; + case 0x405: return 'S'; + case 0x406: return 'I'; + case 0x407: return 0xcf; + case 0x408: return 'J'; + case 0x410: return 'A'; + case 0x412: return 'B'; + case 0x415: return 'E'; + case 0x41a: return 'K'; + case 0x41c: return 'M'; + case 0x41d: return 'H'; + case 0x41e: return 'O'; + case 0x420: return 'P'; + case 0x421: return 'C'; + case 0x422: return 'T'; + case 0x425: return 'X'; + case 0x430: return 'a'; + case 0x435: return 'e'; + case 0x43e: return 'o'; + case 0x440: return 'p'; + case 0x441: return 'c'; + case 0x445: return 'x'; + case 0x450: return 0xe8; + case 0x451: return 0xeb; + case 0x455: return 's'; + case 0x456: return 'i'; + case 0x457: return 0xef; + case 0x458: return 'j'; + } +} + +//========================================================================== +// +// Unicode-aware upper/lowercase conversion +// The only characters not being handled by this are the Turkish I's +// because those are language specific. +// +//========================================================================== + +uint16_t lowerforupper[65536]; +uint16_t upperforlower[65536]; +bool islowermap[65536]; +bool isuppermap[65536]; + +// This is a supposedly complete mapping of all lower <-> upper pairs. Most will most likely never be needed by Doom but this way there won't be any future surprises +static const uint16_t loweruppercase[] = { +0x0061,0x0041, +0x0062,0x0042, +0x0063,0x0043, +0x0064,0x0044, +0x0065,0x0045, +0x0066,0x0046, +0x0067,0x0047, +0x0068,0x0048, +0x0069,0x0049, +0x006A,0x004A, +0x006B,0x004B, +0x006C,0x004C, +0x006D,0x004D, +0x006E,0x004E, +0x006F,0x004F, +0x0070,0x0050, +0x0071,0x0051, +0x0072,0x0052, +0x0073,0x0053, +0x0074,0x0054, +0x0075,0x0055, +0x0076,0x0056, +0x0077,0x0057, +0x0078,0x0058, +0x0079,0x0059, +0x007A,0x005A, +0x00DF,0x1E9E, +0x00E0,0x00C0, +0x00E1,0x00C1, +0x00E2,0x00C2, +0x00E3,0x00C3, +0x00E4,0x00C4, +0x00E5,0x00C5, +0x00E6,0x00C6, +0x00E7,0x00C7, +0x00E8,0x00C8, +0x00E9,0x00C9, +0x00EA,0x00CA, +0x00EB,0x00CB, +0x00EC,0x00CC, +0x00ED,0x00CD, +0x00EE,0x00CE, +0x00EF,0x00CF, +0x00F0,0x00D0, +0x00F1,0x00D1, +0x00F2,0x00D2, +0x00F3,0x00D3, +0x00F4,0x00D4, +0x00F5,0x00D5, +0x00F6,0x00D6, +0x00F8,0x00D8, +0x00F9,0x00D9, +0x00FA,0x00DA, +0x00FB,0x00DB, +0x00FC,0x00DC, +0x00FD,0x00DD, +0x00FE,0x00DE, +0x00FF,0x0178, +0x0101,0x0100, +0x0103,0x0102, +0x0105,0x0104, +0x0107,0x0106, +0x0109,0x0108, +0x010B,0x010A, +0x010D,0x010C, +0x010F,0x010E, +0x0111,0x0110, +0x0113,0x0112, +0x0115,0x0114, +0x0117,0x0116, +0x0119,0x0118, +0x011B,0x011A, +0x011D,0x011C, +0x011F,0x011E, +0x0121,0x0120, +0x0123,0x0122, +0x0125,0x0124, +0x0127,0x0126, +0x0129,0x0128, +0x012B,0x012A, +0x012D,0x012C, +0x012F,0x012E, +0x0133,0x0132, +0x0135,0x0134, +0x0137,0x0136, +0x013A,0x0139, +0x013C,0x013B, +0x013E,0x013D, +0x0140,0x013F, +0x0142,0x0141, +0x0144,0x0143, +0x0146,0x0145, +0x0148,0x0147, +0x014B,0x014A, +0x014D,0x014C, +0x014F,0x014E, +0x0151,0x0150, +0x0153,0x0152, +0x0155,0x0154, +0x0157,0x0156, +0x0159,0x0158, +0x015B,0x015A, +0x015D,0x015C, +0x015F,0x015E, +0x0161,0x0160, +0x0163,0x0162, +0x0165,0x0164, +0x0167,0x0166, +0x0169,0x0168, +0x016B,0x016A, +0x016D,0x016C, +0x016F,0x016E, +0x0171,0x0170, +0x0173,0x0172, +0x0175,0x0174, +0x0177,0x0176, +0x017A,0x0179, +0x017C,0x017B, +0x017E,0x017D, +0x0183,0x0182, +0x0185,0x0184, +0x0188,0x0187, +0x018C,0x018B, +0x0192,0x0191, +0x0199,0x0198, +0x01A1,0x01A0, +0x01A3,0x01A2, +0x01A5,0x01A4, +0x01A8,0x01A7, +0x01AD,0x01AC, +0x01B0,0x01AF, +0x01B4,0x01B3, +0x01B6,0x01B5, +0x01B9,0x01B8, +0x01BD,0x01BC, +0x01C6,0x01C4, +0x01C9,0x01C7, +0x01CC,0x01CA, +0x01CE,0x01CD, +0x01D0,0x01CF, +0x01D2,0x01D1, +0x01D4,0x01D3, +0x01D6,0x01D5, +0x01D8,0x01D7, +0x01DA,0x01D9, +0x01DC,0x01DB, +0x01DF,0x01DE, +0x01E1,0x01E0, +0x01E3,0x01E2, +0x01E5,0x01E4, +0x01E7,0x01E6, +0x01E9,0x01E8, +0x01EB,0x01EA, +0x01ED,0x01EC, +0x01EF,0x01EE, +0x01F3,0x01F1, +0x01F5,0x01F4, +0x01FB,0x01FA, +0x01FD,0x01FC, +0x01FF,0x01FE, +0x0201,0x0200, +0x0203,0x0202, +0x0205,0x0204, +0x0207,0x0206, +0x0209,0x0208, +0x020B,0x020A, +0x020D,0x020C, +0x020F,0x020E, +0x0211,0x0210, +0x0213,0x0212, +0x0215,0x0214, +0x0217,0x0216, +0x0253,0x0181, +0x0254,0x0186, +0x0257,0x018A, +0x0258,0x018E, +0x0259,0x018F, +0x025B,0x0190, +0x0260,0x0193, +0x0263,0x0194, +0x0268,0x0197, +0x0269,0x0196, +0x026F,0x019C, +0x0272,0x019D, +0x0275,0x019F, +0x0283,0x01A9, +0x0288,0x01AE, +0x028A,0x01B1, +0x028B,0x01B2, +0x0292,0x01B7, +0x03AC,0x0386, +0x03AD,0x0388, +0x03AE,0x0389, +0x03AF,0x038A, +0x03B1,0x0391, +0x03B2,0x0392, +0x03B3,0x0393, +0x03B4,0x0394, +0x03B5,0x0395, +0x03B6,0x0396, +0x03B7,0x0397, +0x03B8,0x0398, +0x03B9,0x0399, +0x03BA,0x039A, +0x03BB,0x039B, +0x03BC,0x039C, +0x03BD,0x039D, +0x03BE,0x039E, +0x03BF,0x039F, +0x03C0,0x03A0, +0x03C1,0x03A1, +0x03C3,0x03A3, +0x03C4,0x03A4, +0x03C5,0x03A5, +0x03C6,0x03A6, +0x03C7,0x03A7, +0x03C8,0x03A8, +0x03C9,0x03A9, +0x03CA,0x03AA, +0x03CB,0x03AB, +0x03CC,0x038C, +0x03CD,0x038E, +0x03CE,0x038F, +0x03E3,0x03E2, +0x03E5,0x03E4, +0x03E7,0x03E6, +0x03E9,0x03E8, +0x03EB,0x03EA, +0x03ED,0x03EC, +0x03EF,0x03EE, +0x0430,0x0410, +0x0431,0x0411, +0x0432,0x0412, +0x0433,0x0413, +0x0434,0x0414, +0x0435,0x0415, +0x0436,0x0416, +0x0437,0x0417, +0x0438,0x0418, +0x0439,0x0419, +0x043A,0x041A, +0x043B,0x041B, +0x043C,0x041C, +0x043D,0x041D, +0x043E,0x041E, +0x043F,0x041F, +0x0440,0x0420, +0x0441,0x0421, +0x0442,0x0422, +0x0443,0x0423, +0x0444,0x0424, +0x0445,0x0425, +0x0446,0x0426, +0x0447,0x0427, +0x0448,0x0428, +0x0449,0x0429, +0x044A,0x042A, +0x044B,0x042B, +0x044C,0x042C, +0x044D,0x042D, +0x044E,0x042E, +0x044F,0x042F, +0x0451,0x0401, +0x0452,0x0402, +0x0453,0x0403, +0x0454,0x0404, +0x0455,0x0405, +0x0456,0x0406, +0x0457,0x0407, +0x0458,0x0408, +0x0459,0x0409, +0x045A,0x040A, +0x045B,0x040B, +0x045C,0x040C, +0x045E,0x040E, +0x045F,0x040F, +0x0461,0x0460, +0x0463,0x0462, +0x0465,0x0464, +0x0467,0x0466, +0x0469,0x0468, +0x046B,0x046A, +0x046D,0x046C, +0x046F,0x046E, +0x0471,0x0470, +0x0473,0x0472, +0x0475,0x0474, +0x0477,0x0476, +0x0479,0x0478, +0x047B,0x047A, +0x047D,0x047C, +0x047F,0x047E, +0x0481,0x0480, +0x0491,0x0490, +0x0493,0x0492, +0x0495,0x0494, +0x0497,0x0496, +0x0499,0x0498, +0x049B,0x049A, +0x049D,0x049C, +0x049F,0x049E, +0x04A1,0x04A0, +0x04A3,0x04A2, +0x04A5,0x04A4, +0x04A7,0x04A6, +0x04A9,0x04A8, +0x04AB,0x04AA, +0x04AD,0x04AC, +0x04AF,0x04AE, +0x04B1,0x04B0, +0x04B3,0x04B2, +0x04B5,0x04B4, +0x04B7,0x04B6, +0x04B9,0x04B8, +0x04BB,0x04BA, +0x04BD,0x04BC, +0x04BF,0x04BE, +0x04C2,0x04C1, +0x04C4,0x04C3, +0x04C8,0x04C7, +0x04CC,0x04CB, +0x04D1,0x04D0, +0x04D3,0x04D2, +0x04D5,0x04D4, +0x04D7,0x04D6, +0x04D9,0x04D8, +0x04DB,0x04DA, +0x04DD,0x04DC, +0x04DF,0x04DE, +0x04E1,0x04E0, +0x04E3,0x04E2, +0x04E5,0x04E4, +0x04E7,0x04E6, +0x04E9,0x04E8, +0x04EB,0x04EA, +0x04EF,0x04EE, +0x04F1,0x04F0, +0x04F3,0x04F2, +0x04F5,0x04F4, +0x04F9,0x04F8, +0x0561,0x0531, +0x0562,0x0532, +0x0563,0x0533, +0x0564,0x0534, +0x0565,0x0535, +0x0566,0x0536, +0x0567,0x0537, +0x0568,0x0538, +0x0569,0x0539, +0x056A,0x053A, +0x056B,0x053B, +0x056C,0x053C, +0x056D,0x053D, +0x056E,0x053E, +0x056F,0x053F, +0x0570,0x0540, +0x0571,0x0541, +0x0572,0x0542, +0x0573,0x0543, +0x0574,0x0544, +0x0575,0x0545, +0x0576,0x0546, +0x0577,0x0547, +0x0578,0x0548, +0x0579,0x0549, +0x057A,0x054A, +0x057B,0x054B, +0x057C,0x054C, +0x057D,0x054D, +0x057E,0x054E, +0x057F,0x054F, +0x0580,0x0550, +0x0581,0x0551, +0x0582,0x0552, +0x0583,0x0553, +0x0584,0x0554, +0x0585,0x0555, +0x0586,0x0556, +0x10D0,0x1C90, +0x10D1,0x1C91, +0x10D2,0x1C92, +0x10D3,0x1C93, +0x10D4,0x1C94, +0x10D5,0x1C95, +0x10D6,0x1C96, +0x10D7,0x1C97, +0x10D8,0x1C98, +0x10D9,0x1C99, +0x10DA,0x1C9A, +0x10DB,0x1C9B, +0x10DC,0x1C9C, +0x10DD,0x1C9D, +0x10DE,0x1C9E, +0x10DF,0x1C9F, +0x10E0,0x1CA0, +0x10E1,0x1CA1, +0x10E2,0x1CA2, +0x10E3,0x1CA3, +0x10E4,0x1CA4, +0x10E5,0x1CA5, +0x10E6,0x1CA6, +0x10E7,0x1CA7, +0x10E8,0x1CA8, +0x10E9,0x1CA9, +0x10EA,0x1CAA, +0x10EB,0x1CAB, +0x10EC,0x1CAC, +0x10ED,0x1CAD, +0x10EE,0x1CAE, +0x10EF,0x1CAF, +0x10F0,0x1CB0, +0x10F1,0x1CB1, +0x10F2,0x1CB2, +0x10F3,0x1CB3, +0x10F4,0x1CB4, +0x10F5,0x1CB5, +0x10F6,0x1CB6, +0x10F7,0x1CB7, +0x10F8,0x1CB8, +0x10F9,0x1CB9, +0x10FA,0x1CBA, +0x10FD,0x1CBD, +0x10FE,0x1CBE, +0x10FF,0x1CBF, +0x1E01,0x1E00, +0x1E03,0x1E02, +0x1E05,0x1E04, +0x1E07,0x1E06, +0x1E09,0x1E08, +0x1E0B,0x1E0A, +0x1E0D,0x1E0C, +0x1E0F,0x1E0E, +0x1E11,0x1E10, +0x1E13,0x1E12, +0x1E15,0x1E14, +0x1E17,0x1E16, +0x1E19,0x1E18, +0x1E1B,0x1E1A, +0x1E1D,0x1E1C, +0x1E1F,0x1E1E, +0x1E21,0x1E20, +0x1E23,0x1E22, +0x1E25,0x1E24, +0x1E27,0x1E26, +0x1E29,0x1E28, +0x1E2B,0x1E2A, +0x1E2D,0x1E2C, +0x1E2F,0x1E2E, +0x1E31,0x1E30, +0x1E33,0x1E32, +0x1E35,0x1E34, +0x1E37,0x1E36, +0x1E39,0x1E38, +0x1E3B,0x1E3A, +0x1E3D,0x1E3C, +0x1E3F,0x1E3E, +0x1E41,0x1E40, +0x1E43,0x1E42, +0x1E45,0x1E44, +0x1E47,0x1E46, +0x1E49,0x1E48, +0x1E4B,0x1E4A, +0x1E4D,0x1E4C, +0x1E4F,0x1E4E, +0x1E51,0x1E50, +0x1E53,0x1E52, +0x1E55,0x1E54, +0x1E57,0x1E56, +0x1E59,0x1E58, +0x1E5B,0x1E5A, +0x1E5D,0x1E5C, +0x1E5F,0x1E5E, +0x1E61,0x1E60, +0x1E63,0x1E62, +0x1E65,0x1E64, +0x1E67,0x1E66, +0x1E69,0x1E68, +0x1E6B,0x1E6A, +0x1E6D,0x1E6C, +0x1E6F,0x1E6E, +0x1E71,0x1E70, +0x1E73,0x1E72, +0x1E75,0x1E74, +0x1E77,0x1E76, +0x1E79,0x1E78, +0x1E7B,0x1E7A, +0x1E7D,0x1E7C, +0x1E7F,0x1E7E, +0x1E81,0x1E80, +0x1E83,0x1E82, +0x1E85,0x1E84, +0x1E87,0x1E86, +0x1E89,0x1E88, +0x1E8B,0x1E8A, +0x1E8D,0x1E8C, +0x1E8F,0x1E8E, +0x1E91,0x1E90, +0x1E93,0x1E92, +0x1E95,0x1E94, +0x1EA1,0x1EA0, +0x1EA3,0x1EA2, +0x1EA5,0x1EA4, +0x1EA7,0x1EA6, +0x1EA9,0x1EA8, +0x1EAB,0x1EAA, +0x1EAD,0x1EAC, +0x1EAF,0x1EAE, +0x1EB1,0x1EB0, +0x1EB3,0x1EB2, +0x1EB5,0x1EB4, +0x1EB7,0x1EB6, +0x1EB9,0x1EB8, +0x1EBB,0x1EBA, +0x1EBD,0x1EBC, +0x1EBF,0x1EBE, +0x1EC1,0x1EC0, +0x1EC3,0x1EC2, +0x1EC5,0x1EC4, +0x1EC7,0x1EC6, +0x1EC9,0x1EC8, +0x1ECB,0x1ECA, +0x1ECD,0x1ECC, +0x1ECF,0x1ECE, +0x1ED1,0x1ED0, +0x1ED3,0x1ED2, +0x1ED5,0x1ED4, +0x1ED7,0x1ED6, +0x1ED9,0x1ED8, +0x1EDB,0x1EDA, +0x1EDD,0x1EDC, +0x1EDF,0x1EDE, +0x1EE1,0x1EE0, +0x1EE3,0x1EE2, +0x1EE5,0x1EE4, +0x1EE7,0x1EE6, +0x1EE9,0x1EE8, +0x1EEB,0x1EEA, +0x1EED,0x1EEC, +0x1EEF,0x1EEE, +0x1EF1,0x1EF0, +0x1EF3,0x1EF2, +0x1EF5,0x1EF4, +0x1EF7,0x1EF6, +0x1EF9,0x1EF8, +0x1F00,0x1F08, +0x1F01,0x1F09, +0x1F02,0x1F0A, +0x1F03,0x1F0B, +0x1F04,0x1F0C, +0x1F05,0x1F0D, +0x1F06,0x1F0E, +0x1F07,0x1F0F, +0x1F10,0x1F18, +0x1F11,0x1F19, +0x1F12,0x1F1A, +0x1F13,0x1F1B, +0x1F14,0x1F1C, +0x1F15,0x1F1D, +0x1F20,0x1F28, +0x1F21,0x1F29, +0x1F22,0x1F2A, +0x1F23,0x1F2B, +0x1F24,0x1F2C, +0x1F25,0x1F2D, +0x1F26,0x1F2E, +0x1F27,0x1F2F, +0x1F30,0x1F38, +0x1F31,0x1F39, +0x1F32,0x1F3A, +0x1F33,0x1F3B, +0x1F34,0x1F3C, +0x1F35,0x1F3D, +0x1F36,0x1F3E, +0x1F37,0x1F3F, +0x1F40,0x1F48, +0x1F41,0x1F49, +0x1F42,0x1F4A, +0x1F43,0x1F4B, +0x1F44,0x1F4C, +0x1F45,0x1F4D, +0x1F51,0x1F59, +0x1F53,0x1F5B, +0x1F55,0x1F5D, +0x1F57,0x1F5F, +0x1F60,0x1F68, +0x1F61, 0x1F69, +0x1F62, 0x1F6A, +0x1F63, 0x1F6B, +0x1F64, 0x1F6C, +0x1F65, 0x1F6D, +0x1F66, 0x1F6E, +0x1F67, 0x1F6F, +0x1F80, 0x1F88, +0x1F81, 0x1F89, +0x1F82, 0x1F8A, +0x1F83, 0x1F8B, +0x1F84, 0x1F8C, +0x1F85, 0x1F8D, +0x1F86, 0x1F8E, +0x1F87, 0x1F8F, +0x1F90, 0x1F98, +0x1F91, 0x1F99, +0x1F92, 0x1F9A, +0x1F93, 0x1F9B, +0x1F94, 0x1F9C, +0x1F95, 0x1F9D, +0x1F96, 0x1F9E, +0x1F97, 0x1F9F, +0x1FA0, 0x1FA8, +0x1FA1, 0x1FA9, +0x1FA2, 0x1FAA, +0x1FA3, 0x1FAB, +0x1FA4, 0x1FAC, +0x1FA5, 0x1FAD, +0x1FA6, 0x1FAE, +0x1FA7, 0x1FAF, +0x1FB0, 0x1FB8, +0x1FB1, 0x1FB9, +0x1FD0, 0x1FD8, +0x1FD1, 0x1FD9, +0x1FE0, 0x1FE8, +0x1FE1, 0x1FE9, +0x24D0, 0x24B6, +0x24D1, 0x24B7, +0x24D2, 0x24B8, +0x24D3, 0x24B9, +0x24D4, 0x24BA, +0x24D5, 0x24BB, +0x24D6, 0x24BC, +0x24D7, 0x24BD, +0x24D8, 0x24BE, +0x24D9, 0x24BF, +0x24DA, 0x24C0, +0x24DB, 0x24C1, +0x24DC, 0x24C2, +0x24DD, 0x24C3, +0x24DE, 0x24C4, +0x24DF, 0x24C5, +0x24E0, 0x24C6, +0x24E1, 0x24C7, +0x24E2, 0x24C8, +0x24E3, 0x24C9, +0x24E4, 0x24CA, +0x24E5, 0x24CB, +0x24E6, 0x24CC, +0x24E7, 0x24CD, +0x24E8, 0x24CE, +0x24E9, 0x24CF, +0x2D00, 0x10A0, +0x2D01, 0x10A1, +0x2D02, 0x10A2, +0x2D03, 0x10A3, +0x2D04, 0x10A4, +0x2D05, 0x10A5, +0x2D06, 0x10A6, +0x2D07, 0x10A7, +0x2D08, 0x10A8, +0x2D09, 0x10A9, +0x2D0A, 0x10AA, +0x2D0B, 0x10AB, +0x2D0C, 0x10AC, +0x2D0D, 0x10AD, +0x2D0E, 0x10AE, +0x2D0F, 0x10AF, +0x2D10, 0x10B0, +0x2D11, 0x10B1, +0x2D12, 0x10B2, +0x2D13, 0x10B3, +0x2D14, 0x10B4, +0x2D15, 0x10B5, +0x2D16, 0x10B6, +0x2D17, 0x10B7, +0x2D18, 0x10B8, +0x2D19, 0x10B9, +0x2D1A, 0x10BA, +0x2D1B, 0x10BB, +0x2D1C, 0x10BC, +0x2D1D, 0x10BD, +0x2D1E, 0x10BE, +0x2D1F, 0x10BF, +0x2D20, 0x10C0, +0x2D21, 0x10C1, +0x2D22, 0x10C2, +0x2D23, 0x10C3, +0x2D24, 0x10C4, +0x2D25, 0x10C5, +0x2D27, 0x10C7, +0x2D2D, 0x10CD, +0xFF41, 0xFF21, +0xFF42, 0xFF22, +0xFF43, 0xFF23, +0xFF44, 0xFF24, +0xFF45, 0xFF25, +0xFF46, 0xFF26, +0xFF47, 0xFF27, +0xFF48, 0xFF28, +0xFF49, 0xFF29, +0xFF4A, 0xFF2A, +0xFF4B, 0xFF2B, +0xFF4C, 0xFF2C, +0xFF4D, 0xFF2D, +0xFF4E, 0xFF2E, +0xFF4F, 0xFF2F, +0xFF50, 0xFF30, +0xFF51, 0xFF31, +0xFF52, 0xFF32, +0xFF53, 0xFF33, +0xFF54, 0xFF34, +0xFF55, 0xFF35, +0xFF56, 0xFF36, +0xFF57, 0xFF37, +0xFF58, 0xFF38, +0xFF59, 0xFF39, +0xFF5A, 0xFF3A, + +0, 0 +}; + +struct InitLowerUpper +{ + InitLowerUpper() + { + for (int i = 0; i < 65536; i++) + { + lowerforupper[i] = i; + upperforlower[i] = i; + } + for (int i = 0; loweruppercase[i]; i += 2) + { + auto lower = loweruppercase[i]; + auto upper = loweruppercase[i + 1]; + if (lowerforupper[upper] == upper) lowerforupper[upper] = lower; // This mapping is ambiguous so only pick the first match. + if (upperforlower[lower] == lower) upperforlower[lower] = upper; + isuppermap[upper] = islowermap[lower] = true; + } + // Special treatment for the two variants of the small sigma in Greek. + islowermap[0x3c2] = true; + upperforlower[0x3c2] = 0x3a3; + // Turkish 'I's. + upperforlower[0x131] = 'I'; + lowerforupper[0x130] = 'i'; + islowermap[0x131] = true; + isuppermap[0x130] = true; + } +}; + +static InitLowerUpper initer; + +bool myislower(int code) +{ + if (code >= 0 && code < 65536) return islowermap[code]; + return false; +} + +bool myisupper(int code) +{ + if (code >= 0 && code < 65536) return isuppermap[code]; + return false; +} + +std::wstring WideString(const char* cin) +{ + std::wstring buildbuffer; + if (cin) + { + // This is a bit tricky because we need to support both UTF-8 and legacy content in ISO-8859-1 / Windows 1252 + // and thanks to user-side string manipulation it can be that a text mixes both. + // To convert the string this uses the same function as all text printing in the engine. + const uint8_t* in = (const uint8_t*)cin; + while (*in) buildbuffer.push_back((wchar_t)GetCharFromString(in)); + } + return buildbuffer; +} + diff --git a/src/common/utility/utf8.h b/src/common/utility/utf8.h new file mode 100644 index 00000000000..0b5e4ae0ac6 --- /dev/null +++ b/src/common/utility/utf8.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +int utf8_encode(int32_t codepoint, uint8_t *buffer, int *size); +int utf8_decode(const uint8_t *src, int *size); +int GetCharFromString(const uint8_t *&string); +inline int GetCharFromString(const char32_t *&string) +{ + return *string++; +} +const char *MakeUTF8(const char *outline, int *numchars = nullptr); // returns a pointer to a static buffer, assuming that its caller will immediately process the result. +const char *MakeUTF8(int codepoint, int *psize = nullptr); + +bool myislower(int code); +bool myisupper(int code); +int stripaccent(int code); +int getAlternative(int code); + +extern uint16_t win1252map[]; +extern uint16_t lowerforupper[65536]; +extern uint16_t upperforlower[65536]; + +// make this only visible on Windows, on other platforms this should not be called. +#ifdef _WIN32 +std::wstring WideString(const char*); +#endif diff --git a/src/common/utility/vectors.h b/src/common/utility/vectors.h new file mode 100644 index 00000000000..47eb597938f --- /dev/null +++ b/src/common/utility/vectors.h @@ -0,0 +1,1878 @@ +/* +** vectors.h +** Vector math routines. +** +**--------------------------------------------------------------------------- +** Copyright 2005-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** Since C++ doesn't let me add completely new operators, the following two +** are overloaded for vectors: +** +** | dot product +** ^ cross product +*/ + +#ifndef VECTORS_H +#define VECTORS_H + +#include +#include +#include +#include +#include + +// this is needed to properly normalize angles. We cannot do that with compiler provided conversions because they differ too much +#include "xs_Float.h" + +// make this a local inline function to avoid any dependencies on other headers and not pollute the global namespace +namespace pi +{ + inline constexpr double pi() { return 3.14159265358979323846; } + inline constexpr float pif() { return 3.14159265358979323846f; } +} + +// optionally use reliable math routines if reproducability across hardware is important, but let this still compile without them. +#if __has_include("math/cmath.h") +#include "math/cmath.h" +#else +inline double g_cosdeg(double v) { return cos(v * (pi::pi() / 180.)); } +inline double g_sindeg(double v) { return sin(v * (pi::pi() / 180.)); } +inline double g_cos(double v) { return cos(v); } +inline double g_sin(double v) { return sin(v); } +inline double g_sqrt(double v) { return sqrt(v); } +inline double g_atan2(double v, double w) { return atan2(v, w); } +#endif + + +#define EQUAL_EPSILON (1/65536.) + +template struct TVector3; +template struct TRotator; +template struct TAngle; + +template +struct TVector2 +{ + vec_t X, Y; + + constexpr TVector2() = default; + + constexpr TVector2 (vec_t a, vec_t b) + : X(a), Y(b) + { + } + + constexpr TVector2(const TVector2 &other) = default; + + constexpr TVector2(vec_t *o) + : X(o[0]), Y(o[1]) + { + } + + template + constexpr explicit operator TVector2 () const noexcept { + return TVector2(static_cast(X), static_cast(Y)); + } + + constexpr void Zero() + { + Y = X = 0; + } + + constexpr bool isZero() const + { + return X == 0 && Y == 0; + } + + constexpr TVector2 &operator= (const TVector2 &other) = default; + + // Access X and Y as an array + constexpr vec_t &operator[] (int index) + { + return index == 0 ? X : Y; + } + + constexpr const vec_t &operator[] (int index) const + { + return index == 0 ? X : Y; + } + + // Test for equality + constexpr bool operator== (const TVector2 &other) const + { + return X == other.X && Y == other.Y; + } + + // Test for inequality + constexpr bool operator!= (const TVector2 &other) const + { + return X != other.X || Y != other.Y; + } + + // Test for approximate equality + bool ApproximatelyEquals (const TVector2 &other) const + { + return fabs(X - other.X) < EQUAL_EPSILON && fabs(Y - other.Y) < EQUAL_EPSILON; + } + + // Test for approximate inequality + bool DoesNotApproximatelyEqual (const TVector2 &other) const + { + return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON; + } + + // Unary negation + constexpr TVector2 operator- () const + { + return TVector2(-X, -Y); + } + + // Scalar addition +#if 0 + constexpr TVector2 &operator+= (double scalar) + { + X += scalar, Y += scalar; + return *this; + } +#endif + + constexpr friend TVector2 operator+ (const TVector2 &v, vec_t scalar) + { + return TVector2(v.X + scalar, v.Y + scalar); + } + + constexpr friend TVector2 operator+ (vec_t scalar, const TVector2 &v) + { + return TVector2(v.X + scalar, v.Y + scalar); + } + + // Scalar subtraction + constexpr TVector2 &operator-= (vec_t scalar) + { + X -= scalar, Y -= scalar; + return *this; + } + + constexpr TVector2 operator- (vec_t scalar) const + { + return TVector2(X - scalar, Y - scalar); + } + + // Scalar multiplication + constexpr TVector2 &operator*= (vec_t scalar) + { + X *= scalar, Y *= scalar; + return *this; + } + + constexpr friend TVector2 operator* (const TVector2 &v, vec_t scalar) + { + return TVector2(v.X * scalar, v.Y * scalar); + } + + constexpr friend TVector2 operator* (vec_t scalar, const TVector2 &v) + { + return TVector2(v.X * scalar, v.Y * scalar); + } + + // Scalar division + constexpr TVector2 &operator/= (vec_t scalar) + { + scalar = 1 / scalar, X *= scalar, Y *= scalar; + return *this; + } + + constexpr TVector2 operator/ (vec_t scalar) const + { + scalar = 1 / scalar; + return TVector2(X * scalar, Y * scalar); + } + + // Vector addition + constexpr TVector2 &operator+= (const TVector2 &other) + { + X += other.X, Y += other.Y; + return *this; + } + + constexpr TVector2 operator+ (const TVector2 &other) const + { + return TVector2(X + other.X, Y + other.Y); + } + + // Vector subtraction + constexpr TVector2 &operator-= (const TVector2 &other) + { + X -= other.X, Y -= other.Y; + return *this; + } + + constexpr TVector2 operator- (const TVector2 &other) const + { + return TVector2(X - other.X, Y - other.Y); + } + + // Vector length + vec_t Length() const + { + return (vec_t)g_sqrt (LengthSquared()); + } + + constexpr vec_t LengthSquared() const + { + return X*X + Y*Y; + } + + double Sum() const + { + return abs(X) + abs(Y); + } + + + // Return a unit vector facing the same direction as this one + TVector2 Unit() const + { + vec_t len = Length(); + if (len != 0) len = 1 / len; + return *this * len; + } + + // Scales this vector into a unit vector. Returns the old length + vec_t MakeUnit() + { + vec_t len, ilen; + len = ilen = Length(); + if (ilen != 0) ilen = 1 / ilen; + *this *= ilen; + return len; + } + + // Resizes this vector to be the specified length (if it is not 0) + TVector2 &MakeResize(double len) + { + double scale = len / Length(); + X = vec_t(X * scale); + Y = vec_t(Y * scale); + return *this; + } + + TVector2 Resized(double len) const + { + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + return{ vec_t(X * scale), vec_t(Y * scale) }; + } + else + { + return *this; + } + } + + // Dot product + constexpr vec_t operator | (const TVector2 &other) const + { + return X*other.X + Y*other.Y; + } + + constexpr vec_t dot(const TVector2 &other) const + { + return X*other.X + Y*other.Y; + } + + // Returns the angle that the ray (0,0)-(X,Y) faces + TAngle Angle() const; + + // Returns a rotated vector. angle is in degrees. + TVector2 Rotated (double angle) const + { + double cosval = g_cosdeg (angle); + double sinval = g_sindeg (angle); + return TVector2(X*cosval - Y*sinval, Y*cosval + X*sinval); + } + + // Returns a rotated vector. angle is in degrees. + template + TVector2 Rotated(TAngle angle) const + { + double cosval = angle.Cos(); + double sinval = angle.Sin(); + return TVector2(X*cosval - Y*sinval, Y*cosval + X*sinval); + } + + // Returns a rotated vector. angle is in degrees. + constexpr TVector2 Rotated(const double cosval, const double sinval) const + { + return TVector2(X*cosval - Y*sinval, Y*cosval + X*sinval); + } + + // Returns a vector rotated 90 degrees clockwise. + constexpr TVector2 Rotated90CW() const + { + return TVector2(Y, -X); + } + + // Returns a vector rotated 90 degrees counterclockwise. + constexpr TVector2 Rotated90CCW() const + { + return TVector2(-Y, X); + } +}; + +template +struct TVector3 +{ + typedef TVector2 Vector2; + // this does not compile - should be true on all relevant hardware. + //static_assert(myoffsetof(TVector3, X) == myoffsetof(Vector2, X) && myoffsetof(TVector3, Y) == myoffsetof(Vector2, Y), "TVector2 and TVector3 are not aligned"); + + vec_t X, Y, Z; + + constexpr TVector3() = default; + + constexpr TVector3 (vec_t a, vec_t b, vec_t c) + : X(a), Y(b), Z(c) + { + } + + constexpr TVector3(vec_t *o) + : X(o[0]), Y(o[1]), Z(o[2]) + { + } + + constexpr TVector3(std::nullptr_t nul) = delete; + + constexpr TVector3(const TVector3 &other) = default; + + constexpr TVector3 (const Vector2 &xy, vec_t z) + : X(xy.X), Y(xy.Y), Z(z) + { + } + + TVector3 (const TRotator &rot); + + template + constexpr explicit operator TVector3 () const noexcept { + return TVector3(static_cast(X), static_cast(Y), static_cast(Z)); + } + + constexpr void Zero() + { + Z = Y = X = 0; + } + + constexpr bool isZero() const + { + return X == 0 && Y == 0 && Z == 0; + } + + constexpr TVector3 plusZ(double z) const + { + return { X, Y, Z + z }; + } + + constexpr TVector3 &operator= (const TVector3 &other) = default; + + // Access X and Y and Z as an array + constexpr vec_t &operator[] (int index) + { + return index == 0 ? X : index == 1 ? Y : Z; + } + + constexpr const vec_t &operator[] (int index) const + { + return index == 0 ? X : index == 1 ? Y : Z; + } + + // Test for equality + constexpr bool operator== (const TVector3 &other) const + { + return X == other.X && Y == other.Y && Z == other.Z; + } + + // Test for inequality + constexpr bool operator!= (const TVector3 &other) const + { + return X != other.X || Y != other.Y || Z != other.Z; + } + + // Test for approximate equality + bool ApproximatelyEquals (const TVector3 &other) const + { + return fabs(X - other.X) < EQUAL_EPSILON && fabs(Y - other.Y) < EQUAL_EPSILON && fabs(Z - other.Z) < EQUAL_EPSILON; + } + + // Test for approximate inequality + bool DoesNotApproximatelyEqual (const TVector3 &other) const + { + return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON || fabs(Z - other.Z) >= EQUAL_EPSILON; + } + + // Unary negation + constexpr TVector3 operator- () const + { + return TVector3(-X, -Y, -Z); + } + + // Scalar addition +#if 0 + constexpr TVector3 &operator+= (vec_t scalar) + { + X += scalar, Y += scalar, Z += scalar; + return *this; + } +#endif + + constexpr friend TVector3 operator+ (const TVector3 &v, vec_t scalar) + { + return TVector3(v.X + scalar, v.Y + scalar, v.Z + scalar); + } + + constexpr friend TVector3 operator+ (vec_t scalar, const TVector3 &v) + { + return TVector3(v.X + scalar, v.Y + scalar, v.Z + scalar); + } + + // Scalar subtraction + constexpr TVector3 &operator-= (vec_t scalar) + { + X -= scalar, Y -= scalar, Z -= scalar; + return *this; + } + + constexpr TVector3 operator- (vec_t scalar) const + { + return TVector3(X - scalar, Y - scalar, Z - scalar); + } + + // Scalar multiplication + constexpr TVector3 &operator*= (vec_t scalar) + { + X = vec_t(X *scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar); + return *this; + } + + constexpr friend TVector3 operator* (const TVector3 &v, vec_t scalar) + { + return TVector3(v.X * scalar, v.Y * scalar, v.Z * scalar); + } + + constexpr friend TVector3 operator* (vec_t scalar, const TVector3 &v) + { + return TVector3(v.X * scalar, v.Y * scalar, v.Z * scalar); + } + + // Scalar division + constexpr TVector3 &operator/= (vec_t scalar) + { + scalar = 1 / scalar, X = vec_t(X * scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar); + return *this; + } + + constexpr TVector3 operator/ (vec_t scalar) const + { + scalar = 1 / scalar; + return TVector3(X * scalar, Y * scalar, Z * scalar); + } + + // Vector addition + constexpr TVector3 &operator+= (const TVector3 &other) + { + X += other.X, Y += other.Y, Z += other.Z; + return *this; + } + + constexpr TVector3 operator+ (const TVector3 &other) const + { + return TVector3(X + other.X, Y + other.Y, Z + other.Z); + } + + // Vector subtraction + constexpr TVector3 &operator-= (const TVector3 &other) + { + X -= other.X, Y -= other.Y, Z -= other.Z; + return *this; + } + + constexpr TVector3 operator- (const TVector3 &other) const + { + return TVector3(X - other.X, Y - other.Y, Z - other.Z); + } + + // Add a 2D vector to this 3D vector, leaving Z unchanged. + constexpr TVector3 &operator+= (const Vector2 &other) + { + X += other.X, Y += other.Y; + return *this; + } + + // Subtract a 2D vector from this 3D vector, leaving Z unchanged. + constexpr TVector3 &operator-= (const Vector2 &other) + { + X -= other.X, Y -= other.Y; + return *this; + } + + // returns the XY fields as a 2D-vector. + constexpr const Vector2& XY() const + { + return *reinterpret_cast(this); + } + + constexpr Vector2& XY() + { + return *reinterpret_cast(this); + } + + // Add a 3D vector and a 2D vector. + constexpr friend TVector3 operator+ (const TVector3 &v3, const Vector2 &v2) + { + return TVector3(v3.X + v2.X, v3.Y + v2.Y, v3.Z); + } + + constexpr friend TVector3 operator- (const TVector3 &v3, const Vector2 &v2) + { + return TVector3(v3.X - v2.X, v3.Y - v2.Y, v3.Z); + } + + constexpr friend Vector2 operator+ (const Vector2 &v2, const TVector3 &v3) + { + return Vector2(v2.X + v3.X, v2.Y + v3.Y); + } + + // Subtract a 3D vector and a 2D vector. + // Discards the Z component of the 3D vector and returns a 2D vector. + constexpr friend Vector2 operator- (const TVector2 &v2, const TVector3 &v3) + { + return Vector2(v2.X - v3.X, v2.Y - v3.Y); + } + + void GetRightUp(TVector3 &right, TVector3 &up) + { + TVector3 n(X, Y, Z); + TVector3 fn((vec_t)fabs(n.X), (vec_t)fabs(n.Y), (vec_t)fabs(n.Z)); + int major = 0; + + if (fn[1] > fn[major]) major = 1; + if (fn[2] > fn[major]) major = 2; + + // build right vector by hand + if (fabs(fn[0] - 1.0f) < FLT_EPSILON || fabs(fn[1] - 1.0f) < FLT_EPSILON || fabs(fn[2] - 1.0f) < FLT_EPSILON) + { + if (major == 0 && n[0] > 0.f) + { + right = { 0.f, 0.f, -1.f }; + } + else if (major == 0) + { + right = { 0.f, 0.f, 1.f }; + } + else if (major == 1 || (major == 2 && n[2] > 0.f)) + { + right = { 1.f, 0.f, 0.f }; + } + // Unconditional to ease static analysis + else // major == 2 && n[2] <= 0.0f + { + right = { -1.f, 0.f, 0.f }; + } + } + else + { + static TVector3 axis[3] = + { + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f } + }; + + right = axis[major] ^ n; + } + + up = n ^right; + right.MakeUnit(); + up.MakeUnit(); + } + + + // Returns the angle (in radians) that the ray (0,0)-(X,Y) faces + TAngle Angle() const; + TAngle Pitch() const; + + // Vector length + double Length() const + { + return g_sqrt (LengthSquared()); + } + + constexpr double LengthSquared() const + { + return X*X + Y*Y + Z*Z; + } + + double Sum() const + { + return abs(X) + abs(Y) + abs(Z); + } + + + // Return a unit vector facing the same direction as this one + TVector3 Unit() const + { + double len = Length(); + if (len != 0) len = 1 / len; + return *this * (vec_t)len; + } + + // Scales this vector into a unit vector + void MakeUnit() + { + double len = Length(); + if (len != 0) len = 1 / len; + *this *= (vec_t)len; + } + + // Resizes this vector to be the specified length (if it is not 0) + TVector3 &MakeResize(double len) + { + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + X = vec_t(X * scale); + Y = vec_t(Y * scale); + Z = vec_t(Z * scale); + } + return *this; + } + + TVector3 Resized(double len) const + { + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + return{ vec_t(X * scale), vec_t(Y * scale), vec_t(Z * scale) }; + } + else + { + return *this; + } + } + + // Dot product + constexpr vec_t operator | (const TVector3 &other) const + { + return X*other.X + Y*other.Y + Z*other.Z; + } + + constexpr vec_t dot (const TVector3& other) const + { + return X * other.X + Y * other.Y + Z * other.Z; + } + + // Cross product + constexpr TVector3 operator ^ (const TVector3 &other) const + { + return TVector3(Y*other.Z - Z*other.Y, + Z*other.X - X*other.Z, + X*other.Y - Y*other.X); + } + + constexpr TVector3 &operator ^= (const TVector3 &other) + { + *this = *this ^ other; + return *this; + } +}; + +template +struct TVector4 +{ + typedef TVector2 Vector2; + typedef TVector3 Vector3; + + vec_t X, Y, Z, W; + + constexpr TVector4() = default; + + constexpr TVector4(vec_t a, vec_t b, vec_t c, vec_t d) + : X(a), Y(b), Z(c), W(d) + { + } + + constexpr TVector4(vec_t *o) + : X(o[0]), Y(o[1]), Z(o[2]), W(o[3]) + { + } + + constexpr TVector4(const TVector4 &other) = default; + + constexpr TVector4(const Vector3 &xyz, vec_t w) + : X(xyz.X), Y(xyz.Y), Z(xyz.Z), W(w) + { + } + + constexpr TVector4(const vec_t v[4]) + : TVector4(v[0], v[1], v[2], v[3]) + { + } + + template + constexpr explicit operator TVector4 () const noexcept { + return TVector4(static_cast(X), static_cast(Y), static_cast(Z), static_cast(W)); + } + + constexpr void Zero() + { + Z = Y = X = W = 0; + } + + constexpr bool isZero() const + { + return X == 0 && Y == 0 && Z == 0 && W == 0; + } + + constexpr TVector4 &operator= (const TVector4 &other) = default; + + // Access X and Y and Z as an array + constexpr vec_t &operator[] (int index) + { + return (&X)[index]; + } + + constexpr const vec_t &operator[] (int index) const + { + return (&X)[index]; + } + + // Test for equality + constexpr bool operator== (const TVector4 &other) const + { + return X == other.X && Y == other.Y && Z == other.Z && W == other.W; + } + + // Test for inequality + constexpr bool operator!= (const TVector4 &other) const + { + return X != other.X || Y != other.Y || Z != other.Z || W != other.W; + } + + // returns the XY fields as a 2D-vector. + constexpr const Vector2& XY() const + { + return *reinterpret_cast(this); + } + + constexpr Vector2& XY() + { + return *reinterpret_cast(this); + } + + // returns the XY fields as a 2D-vector. + constexpr const Vector3& XYZ() const + { + return *reinterpret_cast(this); + } + + constexpr Vector3& XYZ() + { + return *reinterpret_cast(this); + } + + + // Test for approximate equality + bool ApproximatelyEquals(const TVector4 &other) const + { + return fabs(X - other.X) < EQUAL_EPSILON && fabs(Y - other.Y) < EQUAL_EPSILON && fabs(Z - other.Z) < EQUAL_EPSILON && fabs(W - other.W) < EQUAL_EPSILON; + } + + // Test for approximate inequality + bool DoesNotApproximatelyEqual(const TVector4 &other) const + { + return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON || fabs(Z - other.Z) >= EQUAL_EPSILON || fabs(W - other.W) >= EQUAL_EPSILON; + } + + // Unary negation + constexpr TVector4 operator- () const + { + return TVector4(-X, -Y, -Z, -W); + } + + // Scalar addition + constexpr TVector4 &operator+= (vec_t scalar) + { + X += scalar, Y += scalar, Z += scalar; W += scalar; + return *this; + } + + constexpr friend TVector4 operator+ (const TVector4 &v, vec_t scalar) + { + return TVector4(v.X + scalar, v.Y + scalar, v.Z + scalar, v.W + scalar); + } + + constexpr friend TVector4 operator+ (vec_t scalar, const TVector4 &v) + { + return TVector4(v.X + scalar, v.Y + scalar, v.Z + scalar, v.W + scalar); + } + + // Scalar subtraction + constexpr TVector4 &operator-= (vec_t scalar) + { + X -= scalar, Y -= scalar, Z -= scalar, W -= scalar; + return *this; + } + + constexpr TVector4 operator- (vec_t scalar) const + { + return TVector4(X - scalar, Y - scalar, Z - scalar, W - scalar); + } + + // Scalar multiplication + constexpr TVector4 &operator*= (vec_t scalar) + { + X = vec_t(X *scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar), W = vec_t(W * scalar); + return *this; + } + + constexpr friend TVector4 operator* (const TVector4 &v, vec_t scalar) + { + return TVector4(v.X * scalar, v.Y * scalar, v.Z * scalar, v.W * scalar); + } + + constexpr friend TVector4 operator* (vec_t scalar, const TVector4 &v) + { + return TVector4(v.X * scalar, v.Y * scalar, v.Z * scalar, v.W * scalar); + } + + // Scalar division + constexpr TVector4 &operator/= (vec_t scalar) + { + scalar = 1 / scalar, X = vec_t(X * scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar), W = vec_t(W * scalar); + return *this; + } + + constexpr TVector4 operator/ (vec_t scalar) const + { + scalar = 1 / scalar; + return TVector4(X * scalar, Y * scalar, Z * scalar, W * scalar); + } + + // Vector addition + constexpr TVector4 &operator+= (const TVector4 &other) + { + X += other.X, Y += other.Y, Z += other.Z, W += other.W; + return *this; + } + + constexpr TVector4 operator+ (const TVector4 &other) const + { + return TVector4(X + other.X, Y + other.Y, Z + other.Z, W + other.W); + } + + // Vector subtraction + constexpr TVector4 &operator-= (const TVector4 &other) + { + X -= other.X, Y -= other.Y, Z -= other.Z, W -= other.W; + return *this; + } + + constexpr TVector4 operator- (const TVector4 &other) const + { + return TVector4(X - other.X, Y - other.Y, Z - other.Z, W - other.W); + } + + // Add a 3D vector to this 4D vector, leaving W unchanged. + constexpr TVector4 &operator+= (const Vector3 &other) + { + X += other.X, Y += other.Y, Z += other.Z; + return *this; + } + + // Subtract a 3D vector from this 4D vector, leaving W unchanged. + constexpr TVector4 &operator-= (const Vector3 &other) + { + X -= other.X, Y -= other.Y, Z -= other.Z; + return *this; + } + + // Add a 4D vector and a 3D vector. + constexpr friend TVector4 operator+ (const TVector4 &v4, const Vector3 &v3) + { + return TVector4(v4.X + v3.X, v4.Y + v3.Y, v4.Z + v3.Z, v4.W); + } + + constexpr friend TVector4 operator- (const TVector4 &v4, const Vector3 &v3) + { + return TVector4(v4.X - v3.X, v4.Y - v3.Y, v4.Z - v3.Z, v4.W); + } + + constexpr friend Vector3 operator+ (const Vector3 &v3, const TVector4 &v4) + { + return Vector3(v3.X + v4.X, v3.Y + v4.Y, v3.Z + v4.Z); + } + + // Subtract a 4D vector and a 3D vector. + // Discards the W component of the 4D vector and returns a 3D vector. + constexpr friend Vector3 operator- (const TVector3 &v3, const TVector4 &v4) + { + return Vector3(v3.X - v4.X, v3.Y - v4.Y, v3.Z - v4.Z); + } + + // Vector length + double Length() const + { + return g_sqrt(LengthSquared()); + } + + constexpr double LengthSquared() const + { + return X*X + Y*Y + Z*Z + W*W; + } + + double Sum() const + { + return abs(X) + abs(Y) + abs(Z) + abs(W); + } + + + // Return a unit vector facing the same direction as this one + TVector4 Unit() const + { + double len = Length(); + if (len != 0) len = 1 / len; + return *this * (vec_t)len; + } + + // Scales this vector into a unit vector + void MakeUnit() + { + double len = Length(); + if (len != 0) len = 1 / len; + *this *= (vec_t)len; + } + + // Resizes this vector to be the specified length (if it is not 0) + TVector4 &MakeResize(double len) + { + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + X = vec_t(X * scale); + Y = vec_t(Y * scale); + Z = vec_t(Z * scale); + W = vec_t(W * scale); + } + return *this; + } + + TVector4 Resized(double len) const + { + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + return{ vec_t(X * scale), vec_t(Y * scale), vec_t(Z * scale), vec_t(W * scale) }; + } + else + { + return *this; + } + } + + // Dot product + constexpr vec_t operator | (const TVector4 &other) const + { + return X*other.X + Y*other.Y + Z*other.Z + W*other.W; + } + + constexpr vec_t dot(const TVector4 &other) const + { + return X*other.X + Y*other.Y + Z*other.Z + W*other.W; + } +}; + +inline void ZeroSubnormalsF(double& num) +{ + if (fabs(num) < FLT_MIN) num = 0; +} + +inline void ZeroSubnormals(double& num) +{ + if (fabs(num) < DBL_MIN) num = 0; +} + +inline void ZeroSubnormals(float& num) +{ + if (fabsf(num) < FLT_MIN) num = 0; +} + +template +inline void ZeroSubnormals(TVector2& vec) +{ + ZeroSubnormals(vec.X); + ZeroSubnormals(vec.Y); +} + +template +inline void ZeroSubnormals(TVector3& vec) +{ + ZeroSubnormals(vec.X); + ZeroSubnormals(vec.Y); + ZeroSubnormals(vec.Z); +} + +template +inline void ZeroSubnormals(TVector4& vec) +{ + ZeroSubnormals(vec.X); + ZeroSubnormals(vec.Y); + ZeroSubnormals(vec.Z); + ZeroSubnormals(vec.W); +} + +template +struct TMatrix3x3 +{ + typedef TVector3 Vector3; + + vec_t Cells[3][3]; + + constexpr TMatrix3x3() = default; + constexpr TMatrix3x3(const TMatrix3x3 &other) = default; + constexpr TMatrix3x3& operator=(const TMatrix3x3& other) = default; + + constexpr TMatrix3x3(const Vector3 &row1, const Vector3 &row2, const Vector3 &row3) + { + (*this)[0] = row1; + (*this)[1] = row2; + (*this)[2] = row3; + } + + // Construct a rotation matrix about an arbitrary axis. + // (The axis vector must be normalized.) + constexpr TMatrix3x3(const Vector3 &axis, double degrees) + : TMatrix3x3(axis, g_sindeg(degrees), g_cosdeg(degrees)) + { + } + + constexpr TMatrix3x3(const Vector3 &axis, double c/*cosine*/, double s/*sine*/) + { + double t = 1 - c; + double sx = s*axis.X, sy = s*axis.Y, sz = s*axis.Z; + double tx = 0, ty = 0, txx = 0, tyy = 0, u = 0, v = 0; + + tx = t*axis.X; + Cells[0][0] = vec_t( (txx=tx*axis.X) + c ); + Cells[0][1] = vec_t( (u=tx*axis.Y) - sz); + Cells[0][2] = vec_t( (v=tx*axis.Z) + sy); + + ty = t*axis.Y; + Cells[1][0] = vec_t( u + sz); + Cells[1][1] = vec_t( (tyy=ty*axis.Y) + c ); + Cells[1][2] = vec_t( (u=ty*axis.Z) - sx); + + Cells[2][0] = vec_t( v - sy); + Cells[2][1] = vec_t( u + sx); + Cells[2][2] = vec_t( (t-txx-tyy) + c ); + } + + TMatrix3x3(const Vector3 &axis, TAngle degrees); + + static TMatrix3x3 Rotate2D(double degrees) + { + double c = g_cosdeg(degrees); + double s = g_sindeg(degrees); + TMatrix3x3 ret; + ret.Cells[0][0] = c; ret.Cells[0][1] = -s; ret.Cells[0][2] = 0; + ret.Cells[1][0] = s; ret.Cells[1][1] = c; ret.Cells[1][2] = 0; + ret.Cells[2][0] = 0; ret.Cells[2][1] = 0; ret.Cells[2][2] = 1; + return ret; + } + + constexpr static TMatrix3x3 Scale2D(TVector2 scaleVec) + { + TMatrix3x3 ret; + ret.Cells[0][0] = scaleVec.X; ret.Cells[0][1] = 0; ret.Cells[0][2] = 0; + ret.Cells[1][0] = 0; ret.Cells[1][1] = scaleVec.Y; ret.Cells[1][2] = 0; + ret.Cells[2][0] = 0; ret.Cells[2][1] = 0; ret.Cells[2][2] = 1; + return ret; + } + + constexpr static TMatrix3x3 Translate2D(TVector2 translateVec) + { + TMatrix3x3 ret; + ret.Cells[0][0] = 1; ret.Cells[0][1] = 0; ret.Cells[0][2] = translateVec.X; + ret.Cells[1][0] = 0; ret.Cells[1][1] = 1; ret.Cells[1][2] = translateVec.Y; + ret.Cells[2][0] = 0; ret.Cells[2][1] = 0; ret.Cells[2][2] = 1; + return ret; + } + + constexpr void Zero() + { + memset (this, 0, sizeof *this); + } + + constexpr void Identity() + { + Cells[0][0] = 1; Cells[0][1] = 0; Cells[0][2] = 0; + Cells[1][0] = 0; Cells[1][1] = 1; Cells[1][2] = 0; + Cells[2][0] = 0; Cells[2][1] = 0; Cells[2][2] = 1; + } + + constexpr Vector3 &operator[] (int index) + { + return *((Vector3 *)&Cells[index]); + } + + constexpr const Vector3 &operator[] (int index) const + { + return *((Vector3 *)&Cells[index]); + } + + // Multiply a scalar + constexpr TMatrix3x3 &operator*= (double scalar) + { + (*this)[0] *= scalar; + (*this)[1] *= scalar; + (*this)[2] *= scalar; + return *this; + } + + constexpr friend TMatrix3x3 operator* (double s, const TMatrix3x3 &m) + { + return TMatrix3x3(m[0]*s, m[1]*s, m[2]*s); + } + + constexpr TMatrix3x3 operator* (double s) const + { + return TMatrix3x3((*this)[0]*s, (*this)[1]*s, (*this)[2]*s); + } + + // Divide a scalar + constexpr TMatrix3x3 &operator/= (double scalar) + { + return *this *= 1 / scalar; + } + + constexpr TMatrix3x3 operator/ (double s) const + { + return *this * (1 / s); + } + + // Add two 3x3 matrices together + constexpr TMatrix3x3 &operator+= (const TMatrix3x3 &o) + { + (*this)[0] += o[0]; + (*this)[1] += o[1]; + (*this)[2] += o[2]; + return *this; + } + + constexpr TMatrix3x3 operator+ (const TMatrix3x3 &o) const + { + return TMatrix3x3((*this)[0] + o[0], (*this)[1] + o[1], (*this)[2] + o[2]); + } + + // Subtract two 3x3 matrices + constexpr TMatrix3x3 &operator-= (const TMatrix3x3 &o) + { + (*this)[0] -= o[0]; + (*this)[1] -= o[1]; + (*this)[2] -= o[2]; + return *this; + } + + constexpr TMatrix3x3 operator- (const TMatrix3x3 &o) const + { + return TMatrix3x3((*this)[0] - o[0], (*this)[1] - o[1], (*this)[2] - o[2]); + } + + // Concatenate two 3x3 matrices + constexpr TMatrix3x3 &operator*= (const TMatrix3x3 &o) + { + return *this = *this * o; + } + + constexpr TMatrix3x3 operator* (const TMatrix3x3 &o) const + { + return TMatrix3x3( + Vector3(Cells[0][0]*o[0][0] + Cells[0][1]*o[1][0] + Cells[0][2]*o[2][0], + Cells[0][0]*o[0][1] + Cells[0][1]*o[1][1] + Cells[0][2]*o[2][1], + Cells[0][0]*o[0][2] + Cells[0][1]*o[1][2] + Cells[0][2]*o[2][2]), + Vector3(Cells[1][0]*o[0][0] + Cells[1][1]*o[1][0] + Cells[1][2]*o[2][0], + Cells[1][0]*o[0][1] + Cells[1][1]*o[1][1] + Cells[1][2]*o[2][1], + Cells[1][0]*o[0][2] + Cells[1][1]*o[1][2] + Cells[1][2]*o[2][2]), + Vector3(Cells[2][0]*o[0][0] + Cells[2][1]*o[1][0] + Cells[2][2]*o[2][0], + Cells[2][0]*o[0][1] + Cells[2][1]*o[1][1] + Cells[2][2]*o[2][1], + Cells[2][0]*o[0][2] + Cells[2][1]*o[1][2] + Cells[2][2]*o[2][2])); + } + + // Multiply a 3D vector by a rotation matrix + constexpr friend Vector3 operator* (const Vector3 &v, const TMatrix3x3 &m) + { + return Vector3(m[0] | v, m[1] | v, m[2] | v); + } + + constexpr friend Vector3 operator* (const TMatrix3x3 &m, const Vector3 &v) + { + return Vector3(m[0] | v, m[1] | v, m[2] | v); + } +}; + +#define BAM_FACTOR (90. / 0x40000000) + +template +struct TAngle +{ + vec_t Degrees_; + + // This is to catch any accidental attempt to assign an angle_t to this type. Any explicit exception will require a type cast. + TAngle(int) = delete; + TAngle(unsigned int) = delete; + TAngle(long) = delete; + TAngle(unsigned long) = delete; + TAngle &operator= (int other) = delete; + TAngle &operator= (unsigned other) = delete; + TAngle &operator= (long other) = delete; + TAngle &operator= (unsigned long other) = delete; + + TAngle() = default; + +private: + // Both constructors are needed to avoid unnecessary conversions when assigning to FAngle. + constexpr TAngle (float amt) + : Degrees_((vec_t)amt) + { + } + constexpr TAngle (double amt) + : Degrees_((vec_t)amt) + { + } +public: + + constexpr vec_t& Degrees__() { return Degrees_; } + + static constexpr TAngle fromDeg(float deg) + { + return TAngle(deg); + } + static constexpr TAngle fromDeg(double deg) + { + return TAngle(deg); + } + static constexpr TAngle fromDeg(int deg) + { + return TAngle((vec_t)deg); + } + static constexpr TAngle fromDeg(unsigned deg) + { + return TAngle((vec_t)deg); + } + + static constexpr TAngle fromRad(float rad) + { + return TAngle(float(rad * (180.0f / pi::pif()))); + } + static constexpr TAngle fromRad(double rad) + { + return TAngle(double(rad * (180.0 / pi::pi()))); + } + + static constexpr TAngle fromBam(int f) + { + return TAngle(f * (90. / 0x40000000)); + } + static constexpr TAngle fromBam(unsigned f) + { + return TAngle(f * (90. / 0x40000000)); + } + + static constexpr TAngle fromBuild(double bang) + { + return TAngle(bang * (90. / 512)); + } + + static constexpr TAngle fromQ16(int bang) + { + return TAngle(bang * (90. / 16384)); + } + + constexpr TAngle(const TAngle &other) = default; + constexpr TAngle &operator= (const TAngle &other) = default; + + constexpr TAngle operator- () const + { + return TAngle(-Degrees_); + } + + constexpr TAngle &operator+= (TAngle other) + { + Degrees_ += other.Degrees_; + return *this; + } + + constexpr TAngle &operator-= (TAngle other) + { + Degrees_ -= other.Degrees_; + return *this; + } + + constexpr TAngle operator+ (TAngle other) const + { + return Degrees_ + other.Degrees_; + } + + constexpr TAngle operator- (TAngle other) const + { + return Degrees_ - other.Degrees_; + } + + constexpr TAngle &operator*= (vec_t other) + { + Degrees_ = Degrees_ * other; + return *this; + } + + constexpr TAngle &operator/= (vec_t other) + { + Degrees_ = Degrees_ / other; + return *this; + } + + constexpr TAngle operator* (vec_t other) const + { + return Degrees_ * other; + } + + constexpr TAngle operator* (TAngle other) const + { + return Degrees_ * other.Degrees_; + } + + constexpr TAngle operator/ (vec_t other) const + { + return Degrees_ / other; + } + + constexpr double operator/ (TAngle other) const + { + return Degrees_ / other.Degrees_; + } + + // Should the comparisons consider an epsilon value? + constexpr bool operator< (TAngle other) const + { + return Degrees_ < other.Degrees_; + } + + constexpr bool operator> (TAngle other) const + { + return Degrees_ > other.Degrees_; + } + + constexpr bool operator<= (TAngle other) const + { + return Degrees_ <= other.Degrees_; + } + + constexpr bool operator>= (TAngle other) const + { + return Degrees_ >= other.Degrees_; + } + + constexpr bool operator== (TAngle other) const + { + return Degrees_ == other.Degrees_; + } + + constexpr bool operator!= (TAngle other) const + { + return Degrees_ != other.Degrees_; + } + + // Ensure the angle is between [0.0,360.0) degrees + TAngle Normalized360() const + { + // Normalizing the angle converts it to a BAM, which masks it, and converts it back to a float. + // Note: We MUST use xs_Float here because it is the only method that guarantees reliable wraparound. + return (vec_t)(BAM_FACTOR * BAMs()); + } + + // Ensures the angle is between (-180.0,180.0] degrees + TAngle Normalized180() const + { + return (vec_t)(BAM_FACTOR * (signed int)BAMs()); + } + + constexpr vec_t Radians() const + { + return vec_t(Degrees_ * (pi::pi() / 180.0)); + } + + unsigned BAMs() const + { + return xs_CRoundToInt(Degrees_ * (0x40000000 / 90.)); + } + + constexpr vec_t Degrees() const + { + return Degrees_; + } + + constexpr int Buildang() const + { + return int(Degrees_ * (512 / 90.0)); + } + + constexpr int Q16() const + { + return int(Degrees_ * (16384 / 90.0)); + } + + TVector2 ToVector(vec_t length = 1) const + { + return TVector2(length * Cos(), length * Sin()); + } + + vec_t Cos() const + { + return vec_t(g_cosdeg(Degrees_)); + } + + vec_t Sin() const + { + return vec_t(g_sindeg(Degrees_)); + } + + double Tan() const + { + // use an optimized approach if we have a sine table. If not just call the CRT's tan function. +#if __has_include("math/cmath.h") + const auto bam = BAMs(); + return g_sinbam(bam) / g_cosbam(bam); +#else + return vec_t(tan(Radians())); +#endif + } + + // This is for calculating vertical velocity. For high pitches the tangent will become too large to be useful. + double TanClamped(double max = 5.) const + { + return clamp(Tan(), -max, max); + } + + // returns sign of the NORMALIZED angle. + int Sgn() const + { + auto val = int(BAMs()); + return (val > 0) - (val < 0); + } +}; + +typedef TAngle FAngle; +typedef TAngle DAngle; + +constexpr DAngle nullAngle = DAngle::fromDeg(0.); +constexpr FAngle nullFAngle = FAngle::fromDeg(0.); +constexpr DAngle minAngle = DAngle::fromDeg(1. / 65536.); +constexpr FAngle minFAngle = FAngle::fromDeg(1. / 65536.); + +constexpr DAngle DAngle1 = DAngle::fromDeg(1); +constexpr DAngle DAngle15 = DAngle::fromDeg(15); +constexpr DAngle DAngle22_5 = DAngle::fromDeg(22.5); +constexpr DAngle DAngle45 = DAngle::fromDeg(45); +constexpr DAngle DAngle60 = DAngle::fromDeg(60); +constexpr DAngle DAngle90 = DAngle::fromDeg(90); +constexpr DAngle DAngle180 = DAngle::fromDeg(180); +constexpr DAngle DAngle270 = DAngle::fromDeg(270); +constexpr DAngle DAngle360 = DAngle::fromDeg(360); + +template +inline TAngle fabs (const TAngle °) +{ + return TAngle::fromDeg(fabs(deg.Degrees())); +} + +template +inline TAngle abs (const TAngle °) +{ + return TAngle::fromDeg(fabs(deg.Degrees())); +} + +template +inline TAngle deltaangle(const TAngle &a1, const TAngle &a2) +{ + return (a2 - a1).Normalized180(); +} + +template +inline TAngle absangle(const TAngle &a1, const TAngle &a2) +{ + return fabs(deltaangle(a2, a1)); +} + +inline TAngle VecToAngle(double x, double y) +{ + return TAngle::fromRad(g_atan2(y, x)); +} + +template +inline TAngle VecToAngle (const TVector2 &vec) +{ + return TAngle::fromRad(g_atan2(vec.Y, vec.X)); +} + +template +inline TAngle VecToAngle (const TVector3 &vec) +{ + return TAngle::fromRad(g_atan2(vec.Y, vec.X)); +} + +template +TAngle TVector2::Angle() const +{ + return VecToAngle(X, Y); +} + +template +TAngle TVector3::Angle() const +{ + return VecToAngle(X, Y); +} + +template +TAngle TVector3::Pitch() const +{ + return -VecToAngle(XY().Length(), Z); +} + +template +constexpr inline TVector2 clamp(const TVector2 &vec, const TVector2 &min, const TVector2 &max) +{ + return TVector2(clamp(vec.X, min.X, max.X), clamp(vec.Y, min.Y, max.Y)); +} + +template +constexpr inline TVector3 clamp(const TVector3 &vec, const TVector3 &min, const TVector3 &max) +{ + return TVector3(std::clamp(vec.X, min.X, max.X), std::clamp(vec.Y, min.Y, max.Y), std::clamp(vec.Z, min.Z, max.Z)); +} + +template +constexpr inline TRotator clamp(const TRotator &rot, const TRotator &min, const TRotator &max) +{ + return TRotator(clamp(rot.Pitch, min.Pitch, max.Pitch), clamp(rot.Yaw, min.Yaw, max.Yaw), clamp(rot.Roll, min.Roll, max.Roll)); +} + +template +inline TAngle interpolatedvalue(const TAngle &oang, const TAngle &ang, const double interpfrac) +{ + return oang + (deltaangle(oang, ang) * interpfrac); +} + +template +inline TRotator interpolatedvalue(const TRotator &oang, const TRotator &ang, const double interpfrac) +{ + return TRotator( + interpolatedvalue(oang.Pitch, ang.Pitch, interpfrac), + interpolatedvalue(oang.Yaw, ang.Yaw, interpfrac), + interpolatedvalue(oang.Roll, ang.Roll, interpfrac) + ); +} + +template +constexpr inline T interpolatedvalue(const T& oval, const T& val, const double interpfrac) +{ + return T(oval + (val - oval) * interpfrac); +} + +// Much of this is copied from TVector3. Is all that functionality really appropriate? +template +struct TRotator +{ + typedef TAngle Angle; + + Angle Pitch; // up/down + Angle Yaw; // left/right + Angle Roll; // rotation about the forward axis. + + constexpr TRotator() = default; + + constexpr TRotator (const Angle &p, const Angle &y, const Angle &r) + : Pitch(p), Yaw(y), Roll(r) + { + } + + constexpr TRotator(const TRotator &other) = default; + constexpr TRotator &operator= (const TRotator &other) = default; + + constexpr void Zero() + { + Roll = Yaw = Pitch = nullAngle; + } + + constexpr bool isZero() const + { + return Pitch == nullAngle && Yaw == nullAngle && Roll == nullAngle; + } + + // Access angles as an array + constexpr Angle &operator[] (int index) + { + return *(&Pitch + index); + } + + constexpr const Angle &operator[] (int index) const + { + return *(&Pitch + index); + } + + // Test for equality + constexpr bool operator== (const TRotator &other) const + { + return Pitch == other.Pitch && Yaw == other.Yaw && Roll == other.Roll; + } + + // Test for inequality + constexpr bool operator!= (const TRotator &other) const + { + return Pitch != other.Pitch || Yaw != other.Yaw || Roll != other.Roll; + } + + // Test for approximate equality + bool ApproximatelyEquals (const TRotator &other) const + { + constexpr auto epsilon = Angle(EQUAL_EPSILON); + return fabs(Pitch - other.Pitch) < epsilon && fabs(Yaw - other.Yaw) < epsilon && fabs(Roll - other.Roll) < epsilon; + } + + // Test for approximate inequality + bool DoesNotApproximatelyEqual (const TRotator &other) const + { + constexpr auto epsilon = Angle(EQUAL_EPSILON); + return fabs(Pitch - other.Pitch) >= epsilon && fabs(Yaw - other.Yaw) >= epsilon && fabs(Roll - other.Roll) >= epsilon; + } + + // Unary negation + constexpr TRotator operator- () const + { + return TRotator(-Pitch, -Yaw, -Roll); + } + + // Scalar addition + constexpr TRotator &operator+= (const Angle &scalar) + { + Pitch += scalar, Yaw += scalar, Roll += scalar; + return *this; + } + + constexpr friend TRotator operator+ (const TRotator &v, const Angle &scalar) + { + return TRotator(v.Pitch + scalar, v.Yaw + scalar, v.Roll + scalar); + } + + constexpr friend TRotator operator+ (const Angle &scalar, const TRotator &v) + { + return TRotator(v.Pitch + scalar, v.Yaw + scalar, v.Roll + scalar); + } + + // Scalar subtraction + constexpr TRotator &operator-= (const Angle &scalar) + { + Pitch -= scalar, Yaw -= scalar, Roll -= scalar; + return *this; + } + + constexpr TRotator operator- (const Angle &scalar) const + { + return TRotator(Pitch - scalar, Yaw - scalar, Roll - scalar); + } + + // Scalar multiplication + constexpr TRotator &operator*= (const Angle &scalar) + { + Pitch *= scalar, Yaw *= scalar, Roll *= scalar; + return *this; + } + + constexpr friend TRotator operator* (const TRotator &v, const Angle &scalar) + { + return TRotator(v.Pitch * scalar, v.Yaw * scalar, v.Roll * scalar); + } + + constexpr friend TRotator operator* (const Angle &scalar, const TRotator &v) + { + return TRotator(v.Pitch * scalar, v.Yaw * scalar, v.Roll * scalar); + } + + // Scalar division + constexpr TRotator &operator/= (const Angle &scalar) + { + Angle mul(1 / scalar.Degrees_); + Pitch *= mul, Yaw *= mul, Roll *= mul; + return *this; + } + + constexpr TRotator &operator/= (const vec_t &scalar) + { + const auto mul = 1. / scalar; + Pitch *= mul, Yaw *= mul, Roll *= mul; + return *this; + } + + constexpr TRotator operator/ (const Angle &scalar) const + { + Angle mul(1 / scalar.Degrees_); + return TRotator(Pitch * mul, Yaw * mul, Roll * mul); + } + + constexpr TRotator operator/ (const vec_t &scalar) const + { + const auto mul = 1. / scalar; + return TRotator(Pitch * mul, Yaw * mul, Roll * mul); + } + + // Vector addition + constexpr TRotator &operator+= (const TRotator &other) + { + Pitch += other.Pitch, Yaw += other.Yaw, Roll += other.Roll; + return *this; + } + + constexpr TRotator operator+ (const TRotator &other) const + { + return TRotator(Pitch + other.Pitch, Yaw + other.Yaw, Roll + other.Roll); + } + + // Vector subtraction + constexpr TRotator &operator-= (const TRotator &other) + { + Pitch -= other.Pitch, Yaw -= other.Yaw, Roll -= other.Roll; + return *this; + } + + constexpr TRotator operator- (const TRotator &other) const + { + return TRotator(Pitch - other.Pitch, Yaw - other.Yaw, Roll - other.Roll); + } +}; + +// Create a forward vector from a rotation (ignoring roll) +template +inline TVector3::TVector3 (const TRotator &rot) +{ + XY() = rot.Pitch.Cos() * rot.Yaw.ToVector(); + Z = rot.Pitch.Sin(); +} + +template +inline TMatrix3x3::TMatrix3x3(const TVector3 &axis, TAngle degrees) +{ + double c = degrees.Cos(), s = degrees.Sin(), t = 1 - c; + double sx = s*axis.X, sy = s*axis.Y, sz = s*axis.Z; + double tx, ty, txx, tyy, u, v; + + tx = t*axis.X; + Cells[0][0] = T( (txx=tx*axis.X) + c ); + Cells[0][1] = T( (u=tx*axis.Y) - sz ); + Cells[0][2] = T( (v=tx*axis.Z) + sy ); + + ty = t*axis.Y; + Cells[1][0] = T( u + sz ); + Cells[1][1] = T( (tyy=ty*axis.Y) + c ); + Cells[1][2] = T( (u=ty*axis.Z) - sx ); + + Cells[2][0] = T( v - sy ); + Cells[2][1] = T( u + sx ); + Cells[2][2] = T( (t-txx-tyy) + c ); +} + +typedef TVector2 FVector2; +typedef TVector3 FVector3; +typedef TVector4 FVector4; +typedef TRotator FRotator; +typedef TMatrix3x3 FMatrix3x3; + +typedef TVector2 DVector2; +typedef TVector3 DVector3; +typedef TVector4 DVector4; +typedef TRotator DRotator; +typedef TMatrix3x3 DMatrix3x3; + +class Plane +{ +public: + void Set(FVector3 normal, float d) + { + m_normal = normal; + m_d = d; + } + + void Init(const FVector3& p1, const FVector3& p2, const FVector3& p3) + { + m_normal = ((p2 - p1) ^ (p3 - p1)).Unit(); + m_d = -(p3 |m_normal); + } + + // same for a play-vector. Note that y and z are inversed. + void Set(DVector3 normal, double d) + { + m_normal = { (float)normal.X, (float)normal.Z, (float)normal.Y }; + m_d = (float)d; + } + + float DistToPoint(float x, float y, float z) + { + FVector3 p(x, y, z); + + return (m_normal | p) + m_d; + } + + + bool PointOnSide(float x, float y, float z) + { + return DistToPoint(x, y, z) < 0.f; + } + + bool PointOnSide(const FVector3 &v) { return PointOnSide(v.X, v.Y, v.Z); } + + float A() { return m_normal.X; } + float B() { return m_normal.Y; } + float C() { return m_normal.Z; } + float D() { return m_d; } + + const FVector3 &Normal() const { return m_normal; } +protected: + FVector3 m_normal; + float m_d; +}; + +#endif diff --git a/src/utility/weightedlist.h b/src/common/utility/weightedlist.h similarity index 99% rename from src/utility/weightedlist.h rename to src/common/utility/weightedlist.h index 4582f6e0f7b..fb956a4625d 100644 --- a/src/utility/weightedlist.h +++ b/src/common/utility/weightedlist.h @@ -31,10 +31,10 @@ **--------------------------------------------------------------------------- ** */ +#pragma once #include - -#include "doomtype.h" +#include class FRandom; diff --git a/src/common/utility/writezip.cpp b/src/common/utility/writezip.cpp new file mode 100644 index 00000000000..de89779c074 --- /dev/null +++ b/src/common/utility/writezip.cpp @@ -0,0 +1,241 @@ +/* +** writezip.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2023 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include +#include "tarray.h" +#include "files.h" +#include "m_swap.h" +#include "w_zip.h" +#include "fs_decompress.h" +#include "cmdlib.h" + +using FileSys::FCompressedBuffer; + + + +//========================================================================== +// +// time_to_dos +// +// Converts time from struct tm to the DOS format used by zip files. +// +//========================================================================== + +static std::pair time_to_dos(struct tm *time) +{ + std::pair val; + if (time == NULL || time->tm_year < 80) + { + val.first = val.second = 0; + } + else + { + val.first = time->tm_hour * 2048 + time->tm_min * 32 + time->tm_sec / 2; + val.second = (time->tm_year - 80) * 512 + (time->tm_mon + 1) * 32 + time->tm_mday; + } + return val; +} + +//========================================================================== +// +// append_to_zip +// +// Write a given file to the zipFile. +// +// zipfile: zip object to be written to +// +// returns: position = success, -1 = error +// +//========================================================================== + +static int AppendToZip(FileWriter *zip_file, const FCompressedBuffer &content, std::pair &dostime) +{ + FZipLocalFileHeader local; + int position; + + int flags = 0; + int method = content.mMethod; + if (method >= FileSys::METHOD_IMPLODE_MIN && method <= FileSys::METHOD_IMPLODE_MAX) + { + flags = method - FileSys::METHOD_IMPLODE_MIN; + method = FileSys::METHOD_IMPLODE; + } + else if (method == FileSys::METHOD_DEFLATE) + { + flags = 2; + } + else if (method >= 1337) + return -1; + + local.Magic = ZIP_LOCALFILE; + local.VersionToExtract[0] = 20; + local.VersionToExtract[1] = 0; + local.Flags = LittleShort((uint16_t)flags); + local.Method = LittleShort((uint16_t)method); + local.ModDate = LittleShort(dostime.first); + local.ModTime = LittleShort(dostime.second); + local.CRC32 = content.mCRC32; + local.UncompressedSize = LittleLong((unsigned)content.mSize); + local.CompressedSize = LittleLong((unsigned)content.mCompressedSize); + local.NameLength = LittleShort((unsigned short)strlen(content.filename)); + local.ExtraLength = 0; + + // Fill in local directory header. + + position = (int)zip_file->Tell(); + + // Write out the header, file name, and file data. + if (zip_file->Write(&local, sizeof(local)) != sizeof(local) || + zip_file->Write(content.filename, strlen(content.filename)) != strlen(content.filename) || + zip_file->Write(content.mBuffer, content.mCompressedSize) != content.mCompressedSize) + { + return -1; + } + return position; +} + + +//========================================================================== +// +// write_central_dir +// +// Writes the central directory entry for a file. +// +//========================================================================== + +int AppendCentralDirectory(FileWriter *zip_file, const FCompressedBuffer &content, std::pair &dostime, int position) +{ + FZipCentralDirectoryInfo dir; + + int flags = 0; + int method = content.mMethod; + if (method >= FileSys::METHOD_IMPLODE_MIN && method <= FileSys::METHOD_IMPLODE_MAX) + { + flags = method - FileSys::METHOD_IMPLODE_MIN; + method = FileSys::METHOD_IMPLODE; + } + else if (method == FileSys::METHOD_DEFLATE) + { + flags = 2; + } + else if (method >= 1337) + return -1; + + dir.Magic = ZIP_CENTRALFILE; + dir.VersionMadeBy[0] = 20; + dir.VersionMadeBy[1] = 0; + dir.VersionToExtract[0] = 20; + dir.VersionToExtract[1] = 0; + dir.Flags = LittleShort((uint16_t)flags); + dir.Method = LittleShort((uint16_t)method); + dir.ModTime = LittleShort(dostime.first); + dir.ModDate = LittleShort(dostime.second); + dir.CRC32 = content.mCRC32; + dir.CompressedSize32 = LittleLong((unsigned)content.mCompressedSize); + dir.UncompressedSize32 = LittleLong((unsigned)content.mSize); + dir.NameLength = LittleShort((unsigned short)strlen(content.filename)); + dir.ExtraLength = 0; + dir.CommentLength = 0; + dir.StartingDiskNumber = 0; + dir.InternalAttributes = 0; + dir.ExternalAttributes = 0; + dir.LocalHeaderOffset32 = LittleLong((unsigned)position); + + if (zip_file->Write(&dir, sizeof(dir)) != sizeof(dir) || + zip_file->Write(content.filename, strlen(content.filename)) != strlen(content.filename)) + { + return -1; + } + return 0; +} + +bool WriteZip(const char* filename, const FCompressedBuffer* content, size_t contentcount) +{ + // try to determine local time + struct tm *ltime; + time_t ttime; + ttime = time(nullptr); + ltime = localtime(&ttime); + auto dostime = time_to_dos(ltime); + + TArray positions; + + auto f = FileWriter::Open(filename); + if (f != nullptr) + { + for (size_t i = 0; i < contentcount; i++) + { + int pos = AppendToZip(f, content[i], dostime); + if (pos == -1) + { + delete f; + RemoveFile(filename); + return false; + } + positions.Push(pos); + } + + int dirofs = (int)f->Tell(); + for (size_t i = 0; i < contentcount; i++) + { + if (AppendCentralDirectory(f, content[i], dostime, positions[i]) < 0) + { + delete f; + RemoveFile(filename); + return false; + } + } + + // Write the directory terminator. + FZipEndOfCentralDirectory dirend; + dirend.Magic = ZIP_ENDOFDIR; + dirend.DiskNumber = 0; + dirend.FirstDisk = 0; + dirend.NumEntriesOnAllDisks = dirend.NumEntries = LittleShort((uint16_t)contentcount); + dirend.DirectoryOffset = LittleLong((unsigned)dirofs); + dirend.DirectorySize = LittleLong((uint32_t)(f->Tell() - dirofs)); + dirend.ZipCommentLength = 0; + if (f->Write(&dirend, sizeof(dirend)) != sizeof(dirend)) + { + delete f; + RemoveFile(filename); + return false; + } + delete f; + return true; + } + return false; +} diff --git a/src/common/utility/x86.cpp b/src/common/utility/x86.cpp new file mode 100644 index 00000000000..5707c6572cb --- /dev/null +++ b/src/common/utility/x86.cpp @@ -0,0 +1,228 @@ +/* +** +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Randy Heit +** Copyright 2005-2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include "x86.h" + +CPUInfo CPU; + +#if !defined(__amd64__) && !defined(__i386__) && !defined(_M_IX86) && !defined(_M_X64) +void CheckCPUID(CPUInfo *cpu) +{ + memset(cpu, 0, sizeof(*cpu)); + cpu->DataL1LineSize = 32; // Assume a 32-byte cache line +} + +FString DumpCPUInfo(const CPUInfo *cpu, bool brief) +{ + return FString(); +} +#else + +#ifdef _MSC_VER +#include +#endif +#include + + +#ifdef __GNUC__ +#define __cpuidex(output, func, subfunc) \ + __asm__ __volatile__("cpuid" \ + : "=a" ((output)[0]), "=b" ((output)[1]), "=c" ((output)[2]), "=d" ((output)[3]) \ + : "a" (func), "c" (subfunc)); +#define __cpuid(output, func) __cpuidex(output, func, 0) +#endif + +void CheckCPUID(CPUInfo *cpu) +{ + int foo[4]; + unsigned int maxext; + + memset(cpu, 0, sizeof(*cpu)); + + cpu->DataL1LineSize = 32; // Assume a 32-byte cache line + + // Get vendor ID + __cpuid(foo, 0); + const int maxid = foo[0]; + cpu->dwVendorID[0] = foo[1]; + cpu->dwVendorID[1] = foo[3]; + cpu->dwVendorID[2] = foo[2]; + if (foo[1] == MAKE_ID('A','u','t','h') && + foo[3] == MAKE_ID('e','n','t','i') && + foo[2] == MAKE_ID('c','A','M','D')) + { + cpu->bIsAMD = true; + } + + // Get features flags and other info + __cpuid(foo, 1); + cpu->FeatureFlags[0] = foo[1]; // Store brand index and other stuff + cpu->FeatureFlags[1] = foo[2]; // Store extended feature flags + cpu->FeatureFlags[2] = foo[3]; // Store feature flags + + cpu->HyperThreading = (foo[3] & (1 << 28)) > 0; + + // If CLFLUSH instruction is supported, get the real cache line size. + if (foo[3] & (1 << 19)) + { + cpu->DataL1LineSize = (foo[1] & 0xFF00) >> (8 - 3); + } + + cpu->Stepping = foo[0] & 0x0F; + cpu->Type = (foo[0] & 0x3000) >> 12; // valid on Intel only + cpu->Model = (foo[0] & 0xF0) >> 4; + cpu->Family = (foo[0] & 0xF00) >> 8; + + if (cpu->Family == 15) + { // Add extended family. + cpu->Family += (foo[0] >> 20) & 0xFF; + } + if (cpu->Family == 6 || cpu->Family == 15) + { // Add extended model ID. + cpu->Model |= (foo[0] >> 12) & 0xF0; + } + + // Check for extended functions. + __cpuid(foo, 0x80000000); + maxext = (unsigned int)foo[0]; + + if (maxext >= 0x80000004) + { // Get processor brand string. + __cpuid((int *)&cpu->dwCPUString[0], 0x80000002); + __cpuid((int *)&cpu->dwCPUString[4], 0x80000003); + __cpuid((int *)&cpu->dwCPUString[8], 0x80000004); + } + + if (cpu->bIsAMD) + { + if (maxext >= 0x80000005) + { // Get data L1 cache info. + __cpuid(foo, 0x80000005); + cpu->AMD_DataL1Info = foo[2]; + } + if (maxext >= 0x80000001) + { // Get AMD-specific feature flags. + __cpuid(foo, 0x80000001); + cpu->AMDStepping = foo[0] & 0x0F; + cpu->AMDModel = (foo[0] & 0xF0) >> 4; + cpu->AMDFamily = (foo[0] & 0xF00) >> 8; + + if (cpu->AMDFamily == 15) + { // Add extended model and family. + cpu->AMDFamily += (foo[0] >> 20) & 0xFF; + cpu->AMDModel |= (foo[0] >> 12) & 0xF0; + } + cpu->FeatureFlags[3] = foo[3]; // AMD feature flags + } + } + + if (maxid >= 7) + { + __cpuidex(foo, 7, 0); + cpu->FeatureFlags[4] = foo[1]; + cpu->FeatureFlags[5] = foo[2]; + cpu->FeatureFlags[6] = foo[3]; + + __cpuidex(foo, 7, 1); + cpu->FeatureFlags[7] = foo[0]; + } +} + +FString DumpCPUInfo(const CPUInfo *cpu, bool brief) +{ + char cpustring[4*4*3+1]; + + // Why does Intel right-justify this string (on P4s) + // or add extra spaces (on Cores)? + const char *f = cpu->CPUString; + char *t; + + // Skip extra whitespace at the beginning. + while (*f == ' ') + { + ++f; + } + + // Copy string to temp buffer, but condense consecutive + // spaces to a single space character. + for (t = cpustring; *f != '\0'; ++f) + { + if (*f == ' ' && *(f - 1) == ' ') + { + continue; + } + *t++ = *f; + } + *t = '\0'; + + FString out; + if (cpu->VendorID[0]) + { + out.Format("CPU Vendor ID: %s\n", cpu->VendorID); + if (cpustring[0]) + { + out.AppendFormat(" Name: %s\n", cpustring); + } + if (cpu->bIsAMD) + { + out.AppendFormat(" Family %d (%d), Model %d, Stepping %d\n", + cpu->Family, cpu->AMDFamily, cpu->AMDModel, cpu->AMDStepping); + } + else + { + out.AppendFormat(" Family %d, Model %d, Stepping %d\n", + cpu->Family, cpu->Model, cpu->Stepping); + } + out.AppendFormat(" Features:"); + if (cpu->bSSE2) out += (" SSE2"); + if (cpu->bSSE3) out += (" SSE3"); + if (cpu->bSSSE3) out += (" SSSE3"); + if (cpu->bSSE41) out += (" SSE4.1"); + if (cpu->bSSE42) out += (" SSE4.2"); + if (cpu->bAVX) out += (" AVX"); + if (cpu->bAVX2) out += (" AVX2"); + if (cpu->bAVX512_F) out += (" AVX512"); + if (cpu->bF16C) out += (" F16C"); + if (cpu->bFMA3) out += (" FMA3"); + if (cpu->bBMI1) out += (" BMI1"); + if (cpu->bBMI2) out += (" BMI2"); + if (cpu->HyperThreading) out += (" HyperThreading"); + out += ("\n"); + } + return out; +} + +#endif diff --git a/src/common/utility/x86.h b/src/common/utility/x86.h new file mode 100644 index 00000000000..8a009efa0e0 --- /dev/null +++ b/src/common/utility/x86.h @@ -0,0 +1,235 @@ +#ifndef X86_H +#define X86_H + +#include "basics.h" +#include "zstring.h" + +struct CPUInfo // 92 bytes +{ + union + { + char VendorID[16]; + uint32_t dwVendorID[4]; + }; + union + { + char CPUString[48]; + uint32_t dwCPUString[12]; + }; + + uint8_t Stepping; + uint8_t Model; + uint8_t Family; + uint8_t Type; + uint8_t HyperThreading; + + union + { + struct + { + uint8_t BrandIndex; + uint8_t CLFlush; + uint8_t CPUCount; + uint8_t APICID; + + uint32_t bSSE3:1; + uint32_t bPCLMULQDQ:1; + uint32_t bDTES64:1; + uint32_t bMONITOR:1; + uint32_t bDSCPL:1; + uint32_t bVMX:1; + uint32_t bSMX:1; + uint32_t bEST:1; + uint32_t bTM2:1; + uint32_t bSSSE3:1; + uint32_t bCNXTID:1; + uint32_t bSDBG:1; + uint32_t bFMA3:1; + uint32_t bCX16:1; + uint32_t bXTPR:1; + uint32_t bPDCM:1; + uint32_t bReverved1:1; + uint32_t bPCID:1; + uint32_t bDCA:1; + uint32_t bSSE41:1; + uint32_t bSSE42:1; + uint32_t bX2APIC:1; + uint32_t bMOVBE:1; + uint32_t bPOPCNT:1; + uint32_t bTSCDL:1; + uint32_t bAES:1; + uint32_t bXSAVE:1; + uint32_t bOSXSAVE:1; + uint32_t bAVX:1; + uint32_t bF16C:1; + uint32_t bRDRND:1; + uint32_t bHypervisor:1; + + uint32_t bFPU:1; + uint32_t bVME:1; + uint32_t bDE:1; + uint32_t bPSE:1; + uint32_t bRDTSC:1; + uint32_t bMSR:1; + uint32_t bPAE:1; + uint32_t bMCE:1; + uint32_t bCX8:1; + uint32_t bAPIC:1; + uint32_t bReserved2:1; + uint32_t bSEP:1; + uint32_t bMTRR:1; + uint32_t bPGE:1; + uint32_t bMCA:1; + uint32_t bCMOV:1; + uint32_t bPAT:1; + uint32_t bPSE36:1; + uint32_t bPSN:1; + uint32_t bCFLUSH:1; + uint32_t bReserved3:1; + uint32_t bDS:1; + uint32_t bACPI:1; + uint32_t bMMX:1; + uint32_t bFXSR:1; + uint32_t bSSE:1; + uint32_t bSSE2:1; + uint32_t bSS:1; + uint32_t bHTT:1; + uint32_t bTM:1; + uint32_t bReserved4:1; + uint32_t bPBE:1; + + uint32_t DontCare2:22; + uint32_t bMMXPlus:1; // AMD's MMX extensions + uint32_t bMMXAgain:1; // Just a copy of bMMX above + uint32_t DontCare3:6; + uint32_t b3DNowPlus:1; + uint32_t b3DNow:1; + + uint32_t bFSGSBASE:1; + uint32_t bIA32_TSC_ADJUST:1; + uint32_t bSGX:1; + uint32_t bBMI1:1; + uint32_t bHLE:1; + uint32_t bAVX2:1; + uint32_t bFDP_EXCPTN_ONLY:1; + uint32_t bSMEP:1; + uint32_t bBMI2:1; + uint32_t bERMS:1; + uint32_t bINVPCID:1; + uint32_t bRTM:1; + uint32_t bPQM:1; + uint32_t bFPU_CS_DS:1; + uint32_t bMPX:1; + uint32_t bPQE:1; + uint32_t bAVX512_F:1; + uint32_t bAVX512_DQ:1; + uint32_t bRDSEED:1; + uint32_t bADX:1; + uint32_t bSMAP:1; + uint32_t bAVX512_IFMA:1; + uint32_t bPCOMMIT:1; + uint32_t bCLFLUSHOPT:1; + uint32_t bCLWB:1; + uint32_t bINTEL_PT:1; + uint32_t bAVX512_PF:1; + uint32_t bAVX512_ER:1; + uint32_t bAVX512_CD:1; + uint32_t bSHA:1; + uint32_t bAVX512_BW:1; + uint32_t bAVX512_VL:1; + + uint32_t bPREFETCHWT1:1; + uint32_t bAVX512_VBMI:1; + uint32_t bUMIP:1; + uint32_t bPKU:1; + uint32_t bOSPKE:1; + uint32_t bWAITPKG:1; + uint32_t bAVX512_VBMI2:1; + uint32_t bCET_SS:1; + uint32_t bGFNI:1; + uint32_t bVAES:1; + uint32_t bVPCLMULQDQ:1; + uint32_t bAVX512_VNNI:1; + uint32_t bAVX512_BITALG:1; + uint32_t bReserved5:1; + uint32_t bAVX512_VPOPCNTDQ:1; + uint32_t bReserved6:1; + uint32_t b5L_PAGING:1; + uint32_t MAWAU:5; + uint32_t bRDPID:1; + uint32_t bReserved7:1; + uint32_t bReserved8:1; + uint32_t bCLDEMOTE:1; + uint32_t bReserved9:1; + uint32_t bMOVDIRI:1; + uint32_t bMOVDIR64B:1; + uint32_t bENQCMD:1; + uint32_t bSGX_LC:1; + uint32_t bPKS:1; + + uint32_t bReserved10:1; + uint32_t bReserved11:1; + uint32_t bAVX512_4VNNIW:1; + uint32_t bAVX512_4FMAPS:1; + uint32_t bFSRM:1; + uint32_t bReserved12:1; + uint32_t bReserved13:1; + uint32_t bReserved14:1; + uint32_t bAVX512_VP2INTERSECT:1; + uint32_t bSRBDS_CTRL:1; + uint32_t bMD_CLEAR:1; + uint32_t bReserved15:1; + uint32_t bReserved16:1; + uint32_t bTSX_FORCE_ABORT:1; + uint32_t bSERIALIZE:1; + uint32_t bHYBRID:1; + uint32_t bTSXLDTRK:1; + uint32_t bReserved17:1; + uint32_t bPCONFIG:1; + uint32_t bLBR:1; + uint32_t bCET_IBT:1; + uint32_t bReserved18:1; + uint32_t bAMX_BF16:1; + uint32_t bReserved19:1; + uint32_t bAMX_TILE:1; + uint32_t bAMX_INT8:1; + uint32_t bIBRS_IBPB:1; + uint32_t bSTIBP:1; + uint32_t bL1D_FLUSH:1; + uint32_t bIA32_ARCH_CAPABILITIES:1; + uint32_t bIA32_CORE_CAPABILITIES:1; + uint32_t bSSBD:1; + + uint32_t DontCare4:5; + uint32_t bAVX512_BF16:1; + uint32_t DontCare5:26; + }; + uint32_t FeatureFlags[8]; + }; + + uint8_t AMDStepping; + uint8_t AMDModel; + uint8_t AMDFamily; + uint8_t bIsAMD; + + union + { + struct + { + uint8_t DataL1LineSize; + uint8_t DataL1LinesPerTag; + uint8_t DataL1Associativity; + uint8_t DataL1SizeKB; + }; + uint32_t AMD_DataL1Info; + }; +}; + + +extern CPUInfo CPU; + +void CheckCPUID (CPUInfo *cpu); +FString DumpCPUInfo (const CPUInfo *cpu, bool brief = false); + +#endif + diff --git a/src/utility/zstring.cpp b/src/common/utility/zstring.cpp similarity index 90% rename from src/utility/zstring.cpp rename to src/common/utility/zstring.cpp index 0f7a0bd1031..488c09eb6e8 100644 --- a/src/utility/zstring.cpp +++ b/src/common/utility/zstring.cpp @@ -38,9 +38,11 @@ #include // for bad_alloc #include "zstring.h" -#include "v_text.h" #include "utf8.h" -#include "fontinternals.h" +#include "stb_sprintf.h" + +extern uint16_t lowerforupper[65536]; +extern uint16_t upperforlower[65536]; FNullStringData FString::NullString = { @@ -215,7 +217,7 @@ FString &FString::operator = (const FString &other) return *this; } -FString &FString::operator = (FString &&other) +FString &FString::operator = (FString &&other) noexcept { assert (Chars != NULL); @@ -273,25 +275,28 @@ void FString::Format (const char *fmt, ...) void FString::AppendFormat (const char *fmt, ...) { + char workbuf[STB_SPRINTF_MIN]; va_list arglist; va_start (arglist, fmt); - StringFormat::VWorker (FormatHelper, this, fmt, arglist); + stbsp_vsprintfcb(FormatHelper, this, workbuf, fmt, arglist); va_end (arglist); } void FString::VFormat (const char *fmt, va_list arglist) { + char workbuf[STB_SPRINTF_MIN]; Data()->Release(); Chars = (char *)(FStringData::Alloc(128) + 1); - StringFormat::VWorker (FormatHelper, this, fmt, arglist); + stbsp_vsprintfcb(FormatHelper, this, workbuf, fmt, arglist); } void FString::VAppendFormat (const char *fmt, va_list arglist) { - StringFormat::VWorker (FormatHelper, this, fmt, arglist); + char workbuf[STB_SPRINTF_MIN]; + stbsp_vsprintfcb(FormatHelper, this, workbuf, fmt, arglist); } -int FString::FormatHelper (void *data, const char *cstr, int len) +char* FString::FormatHelper (const char *cstr, void* data, int len) { FString *str = (FString *)data; size_t len1 = str->Len(); @@ -301,7 +306,7 @@ int FString::FormatHelper (void *data, const char *cstr, int len) } StrCopy (str->Chars + len1, cstr, len); str->Data()->Len = (unsigned int)(len1 + len); - return len; + return (char*)cstr; } FString FString::operator + (const FString &tail) const @@ -421,7 +426,7 @@ void FString::Remove(size_t index, size_t remlen) { if (index + remlen >= Len()) { - Truncate((long)index); + Truncate(index); } else { @@ -499,12 +504,12 @@ void FString::DeleteLastCharacter() } -long FString::IndexOf (const FString &substr, long startIndex) const +ptrdiff_t FString::IndexOf (const FString &substr, ptrdiff_t startIndex) const { return IndexOf (substr.Chars, startIndex); } -long FString::IndexOf (const char *substr, long startIndex) const +ptrdiff_t FString::IndexOf (const char *substr, ptrdiff_t startIndex) const { if (startIndex > 0 && Len() <= (size_t)startIndex) { @@ -515,10 +520,10 @@ long FString::IndexOf (const char *substr, long startIndex) const { return -1; } - return long(str - Chars); + return str - Chars; } -long FString::IndexOf (char subchar, long startIndex) const +ptrdiff_t FString::IndexOf (char subchar, ptrdiff_t startIndex) const { if (startIndex > 0 && Len() <= (size_t)startIndex) { @@ -529,15 +534,15 @@ long FString::IndexOf (char subchar, long startIndex) const { return -1; } - return long(str - Chars); + return str - Chars; } -long FString::IndexOfAny (const FString &charset, long startIndex) const +ptrdiff_t FString::IndexOfAny (const FString &charset, ptrdiff_t startIndex) const { return IndexOfAny (charset.Chars, startIndex); } -long FString::IndexOfAny (const char *charset, long startIndex) const +ptrdiff_t FString::IndexOfAny (const char *charset, ptrdiff_t startIndex) const { if (startIndex > 0 && Len() <= (size_t)startIndex) { @@ -548,19 +553,19 @@ long FString::IndexOfAny (const char *charset, long startIndex) const { return -1; } - return long(brk - Chars); + return brk - Chars; } -long FString::LastIndexOf (char subchar) const +ptrdiff_t FString::LastIndexOf (char subchar) const { - return LastIndexOf (subchar, long(Len())); + return LastIndexOf (subchar, Len()); } -long FString::LastIndexOf (char subchar, long endIndex) const +ptrdiff_t FString::LastIndexOf (char subchar, ptrdiff_t endIndex) const { if ((size_t)endIndex > Len()) { - endIndex = long(Len()); + endIndex = Len(); } while (--endIndex >= 0) { @@ -572,16 +577,16 @@ long FString::LastIndexOf (char subchar, long endIndex) const return -1; } -long FString::LastIndexOfBroken (const FString &_substr, long endIndex) const +ptrdiff_t FString::LastIndexOfBroken (const FString &_substr, ptrdiff_t endIndex) const { const char *substr = _substr.GetChars(); size_t substrlen = _substr.Len(); if ((size_t)endIndex > Len()) { - endIndex = long(Len()); + endIndex = Len(); } substrlen--; - while (--endIndex >= long(substrlen)) + while (--endIndex >= ptrdiff_t(substrlen)) { if (strncmp (substr, Chars + endIndex - substrlen, substrlen + 1) == 0) { @@ -591,26 +596,26 @@ long FString::LastIndexOfBroken (const FString &_substr, long endIndex) const return -1; } -long FString::LastIndexOfAny (const FString &charset) const +ptrdiff_t FString::LastIndexOfAny (const FString &charset) const { - return LastIndexOfAny (charset.Chars, long(Len())); + return LastIndexOfAny (charset.Chars, Len()); } -long FString::LastIndexOfAny (const char *charset) const +ptrdiff_t FString::LastIndexOfAny (const char *charset) const { - return LastIndexOfAny (charset, long(Len())); + return LastIndexOfAny (charset, ptrdiff_t(Len())); } -long FString::LastIndexOfAny (const FString &charset, long endIndex) const +ptrdiff_t FString::LastIndexOfAny (const FString &charset, ptrdiff_t endIndex) const { return LastIndexOfAny (charset.Chars, endIndex); } -long FString::LastIndexOfAny (const char *charset, long endIndex) const +ptrdiff_t FString::LastIndexOfAny (const char *charset, ptrdiff_t endIndex) const { if ((size_t)endIndex > Len()) { - endIndex = long(Len()); + endIndex = Len(); } while (--endIndex >= 0) { @@ -622,31 +627,31 @@ long FString::LastIndexOfAny (const char *charset, long endIndex) const return -1; } -long FString::LastIndexOf (const FString &substr) const +ptrdiff_t FString::LastIndexOf (const FString &substr) const { - return LastIndexOf(substr.Chars, long(Len() - substr.Len()), substr.Len()); + return LastIndexOf(substr.Chars, Len() - substr.Len(), substr.Len()); } -long FString::LastIndexOf (const FString &substr, long endIndex) const +ptrdiff_t FString::LastIndexOf (const FString &substr, ptrdiff_t endIndex) const { return LastIndexOf(substr.Chars, endIndex, substr.Len()); } -long FString::LastIndexOf (const char *substr) const +ptrdiff_t FString::LastIndexOf (const char *substr) const { - return LastIndexOf(substr, long(Len() - strlen(substr)), strlen(substr)); + return LastIndexOf(substr, Len() - strlen(substr), strlen(substr)); } -long FString::LastIndexOf (const char *substr, long endIndex) const +ptrdiff_t FString::LastIndexOf (const char *substr, ptrdiff_t endIndex) const { return LastIndexOf(substr, endIndex, strlen(substr)); } -long FString::LastIndexOf (const char *substr, long endIndex, size_t substrlen) const +ptrdiff_t FString::LastIndexOf (const char *substr, ptrdiff_t endIndex, size_t substrlen) const { if ((size_t)endIndex + substrlen > Len()) { - endIndex = long(Len() - substrlen); + endIndex = Len() - substrlen; } while (endIndex >= 0) { @@ -837,12 +842,12 @@ void FString::StripLeftRight () if (max == 0) return; for (i = 0; i < max; ++i) { - if (Chars[i] < 0 || !isspace((unsigned char)Chars[i])) + if ((signed char)Chars[i] < 0 || !isspace((unsigned char)Chars[i])) break; } for (j = max - 1; j >= i; --j) { - if (Chars[i] < 0 || !isspace((unsigned char)Chars[j])) + if ((signed char)Chars[j] < 0 || !isspace((unsigned char)Chars[j])) break; } if (i == 0 && j == max - 1) @@ -862,7 +867,7 @@ void FString::StripLeftRight () { FStringData *old = Data(); AllocBuffer(j - i + 1); - StrCopy(Chars, old->Chars(), j - i + 1); + StrCopy(Chars, old->Chars() + i, j - i + 1); old->Release(); } } @@ -898,8 +903,8 @@ void FString::StripLeftRight (const char *charset) else { FStringData *old = Data(); - AllocBuffer (j - i); - StrCopy (Chars, old->Chars(), j - i); + AllocBuffer (j - i + 1); + StrCopy (Chars, old->Chars() + i, j - i + 1); old->Release(); } } @@ -1084,6 +1089,12 @@ octdigits = [0-7]; ("0" octdigits+ | "0" [xX] hexdigits+ | (digits \ '0') digits*) { return true; } [\000-\377] { return false; }*/ + + //FIX for "0" returning false, doesn't fix 0 with whitespace, but that isn't necessary for savegame loading, so it'll need to be fixed later + if(Len() == 1 && Chars[0] == '0') return true; + + + const char *YYCURSOR = Chars; char yych; @@ -1255,15 +1266,15 @@ void FString::Split(TArray& tokens, const char *delimiter, EmptyTokenTy { assert(nullptr != delimiter); - const long selfLen = static_cast(Len()); - const long delimLen = static_cast(strlen(delimiter)); - long lastPos = 0; + const auto selfLen = static_cast(Len()); + const auto delimLen = static_cast(strlen(delimiter)); + ptrdiff_t lastPos = 0; if (selfLen == 0) return; // Empty strings do not contain tokens, even with TOK_KEEPEMPTY. while (lastPos <= selfLen) { - long pos = IndexOf(delimiter, lastPos); + auto pos = IndexOf(delimiter, lastPos); if (-1 == pos) { @@ -1321,19 +1332,6 @@ FString &FString::operator=(const wchar_t *copyStr) return *this; } -std::wstring WideString(const char *cin) -{ - if (!cin) return L""; - const uint8_t *in = (const uint8_t*)cin; - // This is a bit tricky because we need to support both UTF-8 and legacy content in ISO-8859-1 - // and thanks to user-side string manipulation it can be that a text mixes both. - // To convert the string this uses the same function as all text printing in the engine. - TArray buildbuffer; - while (*in) buildbuffer.Push((wchar_t)GetCharFromString(in)); - buildbuffer.Push(0); - return std::wstring(buildbuffer.Data()); -} - static HANDLE StringHeap; const SIZE_T STRING_HEAP_SIZE = 64*1024; #endif diff --git a/src/utility/zstring.h b/src/common/utility/zstring.h similarity index 80% rename from src/utility/zstring.h rename to src/common/utility/zstring.h index d7a9417ef16..28402771233 100644 --- a/src/utility/zstring.h +++ b/src/common/utility/zstring.h @@ -37,8 +37,10 @@ #include #include #include +#include #include "tarray.h" -#include "name.h" +#include "utf8.h" +#include "filesystem.h" #ifdef __GNUC__ #define PRINTFISH(x) __attribute__((format(printf, 2, x))) @@ -57,10 +59,6 @@ #define IGNORE_FORMAT_POST #endif -#ifdef _WIN32 -std::wstring WideString(const char *); -#endif - struct FStringData { unsigned int Len; // Length of string, excluding terminating null @@ -127,9 +125,10 @@ class FString // Copy constructors FString (const FString &other) { AttachToOther (other); } - FString (FString &&other) : Chars(other.Chars) { other.ResetToNull(); } + FString (FString &&other) noexcept : Chars(other.Chars) { other.ResetToNull(); } FString (const char *copyStr); FString (const char *copyStr, size_t copyLen); + FString (const std::string &s) : FString(s.c_str(), s.length()) {} FString (char oneChar); FString(const TArray & source) : FString(source.Data(), source.Size()) {} FString(const TArray & source) : FString((char*)source.Data(), source.Size()) {} @@ -148,9 +147,6 @@ class FString FString (const char *head, const char *tail); FString (char head, const FString &tail); - // Other constructors - FString (ELumpNum); // Create from a lump - ~FString (); // Discard string's contents, create a new buffer, and lock it. @@ -164,7 +160,9 @@ class FString std::swap(Chars, other.Chars); } - operator const char *() const { return Chars; } + // We do not want any implicit conversions from FString in conditionals. + explicit operator bool() = delete; // this is needed to render the operator const char * ineffective when used in boolean constructs. + bool operator !() = delete; const char *GetChars() const { return Chars; } @@ -182,7 +180,7 @@ class FString const char &operator[] (unsigned long long index) const { return Chars[index]; } FString &operator = (const FString &other); - FString &operator = (FString &&other); + FString &operator = (FString &&other) noexcept; FString &operator = (const char *copyStr); FString operator + (const FString &tail) const; @@ -194,14 +192,12 @@ class FString FString &operator += (const FString &tail); FString &operator += (const char *tail); FString &operator += (char tail); - FString &operator += (const FName &name) { return *this += name.GetChars(); } FString &AppendCStrPart (const char *tail, size_t tailLen); FString &CopyCStrPart(const char *tail, size_t tailLen); FString &operator << (const FString &tail) { return *this += tail; } FString &operator << (const char *tail) { return *this += tail; } FString &operator << (char tail) { return *this += tail; } - FString &operator << (const FName &name) { return *this += name.GetChars(); } const char &Front() const { assert(IsNotEmpty()); return Chars[0]; } const char &Back() const { assert(IsNotEmpty()); return Chars[Len() - 1]; } @@ -213,28 +209,28 @@ class FString void AppendCharacter(int codepoint); void DeleteLastCharacter(); - long IndexOf (const FString &substr, long startIndex=0) const; - long IndexOf (const char *substr, long startIndex=0) const; - long IndexOf (char subchar, long startIndex=0) const; + ptrdiff_t IndexOf (const FString &substr, ptrdiff_t startIndex=0) const; + ptrdiff_t IndexOf (const char *substr, ptrdiff_t startIndex=0) const; + ptrdiff_t IndexOf (char subchar, ptrdiff_t startIndex=0) const; - long IndexOfAny (const FString &charset, long startIndex=0) const; - long IndexOfAny (const char *charset, long startIndex=0) const; + ptrdiff_t IndexOfAny (const FString &charset, ptrdiff_t startIndex=0) const; + ptrdiff_t IndexOfAny (const char *charset, ptrdiff_t startIndex=0) const; // This is only kept for backwards compatibility with old ZScript versions that used this function and depend on its bug. - long LastIndexOf (char subchar) const; - long LastIndexOfBroken (const FString &substr, long endIndex) const; - long LastIndexOf (char subchar, long endIndex) const; + ptrdiff_t LastIndexOf (char subchar) const; + ptrdiff_t LastIndexOfBroken (const FString &substr, ptrdiff_t endIndex) const; + ptrdiff_t LastIndexOf (char subchar, ptrdiff_t endIndex) const; - long LastIndexOfAny (const FString &charset) const; - long LastIndexOfAny (const char *charset) const; - long LastIndexOfAny (const FString &charset, long endIndex) const; - long LastIndexOfAny (const char *charset, long endIndex) const; + ptrdiff_t LastIndexOfAny (const FString &charset) const; + ptrdiff_t LastIndexOfAny (const char *charset) const; + ptrdiff_t LastIndexOfAny (const FString &charset, ptrdiff_t endIndex) const; + ptrdiff_t LastIndexOfAny (const char *charset, ptrdiff_t endIndex) const; - long LastIndexOf (const FString &substr) const; - long LastIndexOf (const FString &substr, long endIndex) const; - long LastIndexOf (const char *substr) const; - long LastIndexOf (const char *substr, long endIndex) const; - long LastIndexOf (const char *substr, long endIndex, size_t substrlen) const; + ptrdiff_t LastIndexOf (const FString &substr) const; + ptrdiff_t LastIndexOf (const FString &substr, ptrdiff_t endIndex) const; + ptrdiff_t LastIndexOf (const char *substr) const; + ptrdiff_t LastIndexOf (const char *substr, ptrdiff_t endIndex) const; + ptrdiff_t LastIndexOf (const char *substr, ptrdiff_t endIndex, size_t substrlen) const; void ToUpper (); void ToLower (); @@ -329,13 +325,13 @@ class FString int Compare (const FString &other) const { return strcmp (Chars, other.Chars); } int Compare (const char *other) const { return strcmp (Chars, other); } - int Compare(const FString &other, int len) const { return strncmp(Chars, other.Chars, len); } - int Compare(const char *other, int len) const { return strncmp(Chars, other, len); } + int Compare(const FString &other, size_t len) const { return strncmp(Chars, other.Chars, len); } + int Compare(const char *other, size_t len) const { return strncmp(Chars, other, len); } int CompareNoCase (const FString &other) const { return stricmp (Chars, other.Chars); } int CompareNoCase (const char *other) const { return stricmp (Chars, other); } - int CompareNoCase(const FString &other, int len) const { return strnicmp(Chars, other.Chars, len); } - int CompareNoCase(const char *other, int len) const { return strnicmp(Chars, other, len); } + int CompareNoCase(const FString &other, size_t len) const { return strnicmp(Chars, other.Chars, len); } + int CompareNoCase(const char *other, size_t len) const { return strnicmp(Chars, other, len); } enum EmptyTokenType { @@ -362,7 +358,7 @@ class FString void AllocBuffer (size_t len); void ReallocBuffer (size_t newlen); - static int FormatHelper (void *data, const char *str, int len); + static char* FormatHelper (const char *str, void* data, int len); static void StrCopy (char *to, const char *from, size_t len); static void StrCopy (char *to, const FString &from); @@ -403,6 +399,7 @@ class FString return Compare(other) >= 0; } + // These are needed to block the default char * conversion operator from making a mess. bool operator == (const char *) const = delete; bool operator != (const char *) const = delete; bool operator < (const char *) const = delete; @@ -410,16 +407,10 @@ class FString bool operator <= (const char *) const = delete; bool operator >= (const char *) const = delete; - bool operator == (FName) const = delete; - bool operator != (FName) const = delete; - bool operator < (FName) const = delete; - bool operator > (FName) const = delete; - bool operator <= (FName) const = delete; - bool operator >= (FName) const = delete; - private: }; +// These are also needed to block the default char * conversion operator from making a mess. bool operator == (const char *, const FString &) = delete; bool operator != (const char *, const FString &) = delete; bool operator < (const char *, const FString &) = delete; @@ -427,13 +418,6 @@ bool operator > (const char *, const FString &) = delete; bool operator <= (const char *, const FString &) = delete; bool operator >= (const char *, const FString &) = delete; -bool operator == (FName, const FString &) = delete; -bool operator != (FName, const FString &) = delete; -bool operator < (FName, const FString &) = delete; -bool operator > (FName, const FString &) = delete; -bool operator <= (FName, const FString &) = delete; -bool operator >= (FName, const FString &) = delete; - class FStringf : public FString { public: @@ -441,6 +425,7 @@ class FStringf : public FString }; +/* namespace StringFormat { enum @@ -471,20 +456,24 @@ namespace StringFormat int VWorker (OutputFunc output, void *outputData, const char *fmt, va_list arglist); int Worker (OutputFunc output, void *outputData, const char *fmt, ...); }; +*/ #undef PRINTFISH -// FName inline implementations that take FString parameters - -inline FName::FName(const FString &text) { Index = NameData.FindName (text.GetChars(), text.Len(), false); } -inline FName::FName(const FString &text, bool noCreate) { Index = NameData.FindName (text.GetChars(), text.Len(), noCreate); } -inline FName &FName::operator = (const FString &text) { Index = NameData.FindName (text.GetChars(), text.Len(), false); return *this; } - // Hash FStrings on their contents. (used by TMap) -extern unsigned int SuperFastHash (const char *data, size_t len); +#include "superfasthash.h" + template<> struct THashTraits { hash_t Hash(const FString &key) { return (hash_t)SuperFastHash(key.GetChars(), key.Len()); } // Compares two keys, returning zero if they are the same. int Compare(const FString &left, const FString &right) { return left.Compare(right); } }; + +struct StringNoCaseHashTraits +{ + hash_t Hash(const FString& key) { return (hash_t)SuperFastHashI(key.GetChars(), key.Len()); } + // Compares two keys, returning zero if they are the same. + int Compare(const FString& left, const FString& right) { return left.CompareNoCase(right); } +}; + diff --git a/src/common/widgets/errorwindow.cpp b/src/common/widgets/errorwindow.cpp new file mode 100644 index 00000000000..e0af0730b7d --- /dev/null +++ b/src/common/widgets/errorwindow.cpp @@ -0,0 +1,281 @@ + +#include "errorwindow.h" +#include "version.h" +#include "v_font.h" +#include "printf.h" +#include +#include +#include + +bool ErrorWindow::ExecModal(const std::string& text, const std::string& log) +{ + Size screenSize = GetScreenSize(); + double windowWidth = 1200.0; + double windowHeight = 700.0; + + auto window = std::make_unique(); + window->SetText(text, log); + window->SetFrameGeometry((screenSize.width - windowWidth) * 0.5, (screenSize.height - windowHeight) * 0.5, windowWidth, windowHeight); + window->Show(); + + DisplayWindow::RunLoop(); + + return window->Restart; +} + +ErrorWindow::ErrorWindow() : Widget(nullptr, WidgetType::Window) +{ + FStringf caption("Fatal Error - " GAMENAME " %s (%s)", GetVersionString(), GetGitTime()); + SetWindowTitle(caption.GetChars()); + SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); + SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51)); + SetWindowCaptionColor(Colorf::fromRgba8(33, 33, 33)); + SetWindowCaptionTextColor(Colorf::fromRgba8(226, 223, 219)); + + LogView = new LogViewer(this); + ClipboardButton = new PushButton(this); + RestartButton = new PushButton(this); + + ClipboardButton->OnClick = [=]() { OnClipboardButtonClicked(); }; + RestartButton->OnClick = [=]() { OnRestartButtonClicked(); }; + + ClipboardButton->SetText("Copy to clipboard"); + RestartButton->SetText("Restart"); + + LogView->SetFocus(); +} + +void ErrorWindow::SetText(const std::string& text, const std::string& log) +{ + LogView->SetText(text, log); + + clipboardtext.clear(); + clipboardtext.reserve(log.size() + text.size() + 100); + + // Strip the color escapes from the log + const uint8_t* cptr = (const uint8_t*)log.data(); + while (int chr = GetCharFromString(cptr)) + { + if (chr != TEXTCOLOR_ESCAPE) + { + // The bar characters, most commonly used to indicate map changes + if (chr >= 0x1D && chr <= 0x1F) + { + chr = 0x2550; // Box Drawings Double Horizontal + } + clipboardtext += MakeUTF8(chr); + } + } + + clipboardtext += "\nExecution could not continue.\n"; + clipboardtext += text; + clipboardtext += "\n"; +} + +void ErrorWindow::OnClipboardButtonClicked() +{ + SetClipboardText(clipboardtext); +} + +void ErrorWindow::OnRestartButtonClicked() +{ + Restart = true; + DisplayWindow::ExitLoop(); +} + +void ErrorWindow::OnClose() +{ + Restart = false; + DisplayWindow::ExitLoop(); +} + +void ErrorWindow::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + + double y = GetHeight() - 15.0 - ClipboardButton->GetPreferredHeight(); + ClipboardButton->SetFrameGeometry(20.0, y, 170.0, ClipboardButton->GetPreferredHeight()); + RestartButton->SetFrameGeometry(GetWidth() - 20.0 - 100.0, y, 100.0, RestartButton->GetPreferredHeight()); + y -= 20.0; + + LogView->SetFrameGeometry(Rect::xywh(0.0, 0.0, w, y)); +} + +///////////////////////////////////////////////////////////////////////////// + +LogViewer::LogViewer(Widget* parent) : Widget(parent) +{ + SetNoncontentSizes(8.0, 8.0, 3.0, 8.0); + + scrollbar = new Scrollbar(this); + scrollbar->FuncScroll = [=]() { OnScrollbarScroll(); }; +} + +void LogViewer::SetText(const std::string& text, const std::string& log) +{ + lines.clear(); + + std::string::size_type start = 0; + std::string::size_type end = log.find('\n'); + while (end != std::string::npos) + { + lines.push_back(CreateLineLayout(log.substr(start, end - start))); + start = end + 1; + end = log.find('\n', start); + } + + lines.push_back(CreateLineLayout(log.substr(start))); + + // Add an empty line as a bit of spacing + lines.push_back(CreateLineLayout({})); + + SpanLayout layout; + //layout.AddImage(Image::LoadResource("widgets/erroricon.svg"), -8.0); + layout.AddText("Execution could not continue.", largefont, Colorf::fromRgba8(255, 170, 170)); + lines.push_back(layout); + + layout.Clear(); + layout.AddText(text, largefont, Colorf::fromRgba8(255, 255, 170)); + lines.push_back(layout); + + scrollbar->SetRanges(0.0, (double)lines.size(), 1.0, 100.0); + scrollbar->SetPosition((double)lines.size() - 1.0); + + Update(); +} + +SpanLayout LogViewer::CreateLineLayout(const std::string& text) +{ + SpanLayout layout; + + Colorf curcolor = Colorf::fromRgba8(255, 255, 255); + std::string curtext; + + const uint8_t* cptr = (const uint8_t*)text.data(); + while (int chr = GetCharFromString(cptr)) + { + if (chr != TEXTCOLOR_ESCAPE) + { + // The bar characters, most commonly used to indicate map changes + if (chr >= 0x1D && chr <= 0x1F) + { + chr = 0x2550; // Box Drawings Double Horizontal + } + curtext += MakeUTF8(chr); + } + else + { + EColorRange range = V_ParseFontColor(cptr, CR_UNTRANSLATED, CR_YELLOW); + if (range != CR_UNDEFINED) + { + if (!curtext.empty()) + layout.AddText(curtext, font, curcolor); + curtext.clear(); + + PalEntry color = V_LogColorFromColorRange(range); + curcolor = Colorf::fromRgba8(color.r, color.g, color.b); + } + } + } + + curtext.push_back(' '); + layout.AddText(curtext, font, curcolor); + + return layout; +} + +void LogViewer::OnPaintFrame(Canvas* canvas) +{ + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + Colorf bordercolor = Colorf::fromRgba8(100, 100, 100); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); + //canvas->fillRect(Rect::xywh(0.0, 0.0, w, 1.0), bordercolor); + //canvas->fillRect(Rect::xywh(0.0, h - 1.0, w, 1.0), bordercolor); + //canvas->fillRect(Rect::xywh(0.0, 0.0, 1.0, h - 0.0), bordercolor); + //canvas->fillRect(Rect::xywh(w - 1.0, 0.0, 1.0, h - 0.0), bordercolor); +} + +void LogViewer::OnPaint(Canvas* canvas) +{ + double width = GetWidth() - scrollbar->GetFrameGeometry().width; + double y = GetHeight(); + size_t start = std::min((size_t)std::round(scrollbar->GetPosition() + 1.0), lines.size()); + for (size_t i = start; i > 0 && y > 0.0; i--) + { + SpanLayout& layout = lines[i - 1]; + layout.Layout(canvas, width); + layout.SetPosition(Point(0.0, y - layout.GetSize().height)); + layout.DrawLayout(canvas); + y -= layout.GetSize().height; + } +} + +bool LogViewer::OnMouseWheel(const Point& pos, EInputKey key) +{ + if (key == IK_MouseWheelUp) + { + ScrollUp(4); + } + else if (key == IK_MouseWheelDown) + { + ScrollDown(4); + } + return true; +} + +void LogViewer::OnKeyDown(EInputKey key) +{ + if (key == IK_Home) + { + scrollbar->SetPosition(0.0f); + Update(); + } + if (key == IK_End) + { + scrollbar->SetPosition(scrollbar->GetMax()); + Update(); + } + else if (key == IK_PageUp) + { + ScrollUp(20); + } + else if (key == IK_PageDown) + { + ScrollDown(20); + } + else if (key == IK_Up) + { + ScrollUp(4); + } + else if (key == IK_Down) + { + ScrollDown(4); + } +} + +void LogViewer::OnScrollbarScroll() +{ + Update(); +} + +void LogViewer::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + double sw = scrollbar->GetPreferredWidth(); + scrollbar->SetFrameGeometry(Rect::xywh(w - sw, 0.0, sw, h)); +} + +void LogViewer::ScrollUp(int lines) +{ + scrollbar->SetPosition(std::max(scrollbar->GetPosition() - (double)lines, 0.0)); + Update(); +} + +void LogViewer::ScrollDown(int lines) +{ + scrollbar->SetPosition(std::min(scrollbar->GetPosition() + (double)lines, scrollbar->GetMax())); + Update(); +} diff --git a/src/common/widgets/errorwindow.h b/src/common/widgets/errorwindow.h new file mode 100644 index 00000000000..f38eb676cb6 --- /dev/null +++ b/src/common/widgets/errorwindow.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include + +class LogViewer; +class PushButton; +class Scrollbar; + +class ErrorWindow : public Widget +{ +public: + static bool ExecModal(const std::string& text, const std::string& log); + + ErrorWindow(); + + bool Restart = false; + +protected: + void OnClose() override; + void OnGeometryChanged() override; + +private: + void SetText(const std::string& text, const std::string& log); + + void OnClipboardButtonClicked(); + void OnRestartButtonClicked(); + + LogViewer* LogView = nullptr; + PushButton* ClipboardButton = nullptr; + PushButton* RestartButton = nullptr; + + std::string clipboardtext; +}; + +class LogViewer : public Widget +{ +public: + LogViewer(Widget* parent); + + void SetText(const std::string& text, const std::string& log); + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnPaint(Canvas* canvas) override; + bool OnMouseWheel(const Point& pos, EInputKey key) override; + void OnKeyDown(EInputKey key) override; + void OnGeometryChanged() override; + +private: + void OnScrollbarScroll(); + void ScrollUp(int lines); + void ScrollDown(int lines); + + SpanLayout CreateLineLayout(const std::string& text); + + Scrollbar* scrollbar = nullptr; + + std::shared_ptr largefont = Font::Create("Poppins", 16.0); + std::shared_ptr font = Font::Create("Poppins", 12.0); + std::vector lines; +}; diff --git a/src/common/widgets/netstartwindow.cpp b/src/common/widgets/netstartwindow.cpp new file mode 100644 index 00000000000..69c83e56542 --- /dev/null +++ b/src/common/widgets/netstartwindow.cpp @@ -0,0 +1,152 @@ + +#include "netstartwindow.h" +#include "version.h" +#include "engineerrors.h" +#include "gstrings.h" +#include +#include +#include + +NetStartWindow* NetStartWindow::Instance = nullptr; + +void NetStartWindow::ShowNetStartPane(const char* message, int maxpos) +{ + Size screenSize = GetScreenSize(); + double windowWidth = 300.0; + double windowHeight = 150.0; + + if (!Instance) + { + Instance = new NetStartWindow(); + Instance->SetFrameGeometry((screenSize.width - windowWidth) * 0.5, (screenSize.height - windowHeight) * 0.5, windowWidth, windowHeight); + Instance->Show(); + } + + Instance->SetMessage(message, maxpos); +} + +void NetStartWindow::HideNetStartPane() +{ + delete Instance; + Instance = nullptr; +} + +void NetStartWindow::SetNetStartProgress(int pos) +{ + if (Instance) + Instance->SetProgress(pos); +} + +bool NetStartWindow::RunMessageLoop(bool (*newtimer_callback)(void*), void* newuserdata) +{ + if (!Instance) + return false; + + Instance->timer_callback = newtimer_callback; + Instance->userdata = newuserdata; + Instance->CallbackException = {}; + + DisplayWindow::RunLoop(); + + Instance->timer_callback = nullptr; + Instance->userdata = nullptr; + + if (Instance->CallbackException) + std::rethrow_exception(Instance->CallbackException); + + // Even though the comment in FBasicStartupScreen::NetLoop says we should return false, the old code actually throws an exception! + // This effectively also means the function always returns true... + if (!Instance->exitreason) + { + throw CExitEvent(0); + } + + return Instance->exitreason; +} + +NetStartWindow::NetStartWindow() : Widget(nullptr, WidgetType::Window) +{ + SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); + SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51)); + SetWindowCaptionColor(Colorf::fromRgba8(33, 33, 33)); + SetWindowCaptionTextColor(Colorf::fromRgba8(226, 223, 219)); + SetWindowTitle(GAMENAME); + + MessageLabel = new TextLabel(this); + ProgressLabel = new TextLabel(this); + AbortButton = new PushButton(this); + + MessageLabel->SetTextAlignment(TextLabelAlignment::Center); + ProgressLabel->SetTextAlignment(TextLabelAlignment::Center); + + AbortButton->OnClick = [=]() { OnClose(); }; + + AbortButton->SetText("Abort Network Game"); + + CallbackTimer = new Timer(this); + CallbackTimer->FuncExpired = [=]() { OnCallbackTimerExpired(); }; + CallbackTimer->Start(500); +} + +void NetStartWindow::SetMessage(const std::string& message, int newmaxpos) +{ + MessageLabel->SetText(message); + maxpos = newmaxpos; +} + +void NetStartWindow::SetProgress(int newpos) +{ + if (pos != newpos && maxpos > 1) + { + pos = newpos; + FString message; + message.Format("%d/%d", pos, maxpos); + ProgressLabel->SetText(message.GetChars()); + } +} + +void NetStartWindow::OnClose() +{ + exitreason = false; + DisplayWindow::ExitLoop(); +} + +void NetStartWindow::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + + double y = 15.0; + double labelheight = MessageLabel->GetPreferredHeight(); + MessageLabel->SetFrameGeometry(Rect::xywh(5.0, y, w - 10.0, labelheight)); + y += labelheight; + + labelheight = ProgressLabel->GetPreferredHeight(); + ProgressLabel->SetFrameGeometry(Rect::xywh(5.0, y, w - 10.0, labelheight)); + y += labelheight; + + y = GetHeight() - 15.0 - AbortButton->GetPreferredHeight(); + AbortButton->SetFrameGeometry((w - 200.0) * 0.5, y, 200.0, AbortButton->GetPreferredHeight()); +} + +void NetStartWindow::OnCallbackTimerExpired() +{ + if (timer_callback) + { + bool result = false; + try + { + result = timer_callback(userdata); + } + catch (...) + { + CallbackException = std::current_exception(); + } + + if (result) + { + exitreason = true; + DisplayWindow::ExitLoop(); + } + } +} diff --git a/src/common/widgets/netstartwindow.h b/src/common/widgets/netstartwindow.h new file mode 100644 index 00000000000..5d27b8ebfc7 --- /dev/null +++ b/src/common/widgets/netstartwindow.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +class TextLabel; +class PushButton; +class Timer; + +class NetStartWindow : public Widget +{ +public: + static void ShowNetStartPane(const char* message, int maxpos); + static void HideNetStartPane(); + static void SetNetStartProgress(int pos); + static bool RunMessageLoop(bool (*timer_callback)(void*), void* userdata); + +private: + NetStartWindow(); + + void SetMessage(const std::string& message, int maxpos); + void SetProgress(int pos); + +protected: + void OnClose() override; + void OnGeometryChanged() override; + +private: + void OnCallbackTimerExpired(); + + TextLabel* MessageLabel = nullptr; + TextLabel* ProgressLabel = nullptr; + PushButton* AbortButton = nullptr; + + Timer* CallbackTimer = nullptr; + + int pos = 0; + int maxpos = 1; + bool (*timer_callback)(void*) = nullptr; + void* userdata = nullptr; + + bool exitreason = false; + + std::exception_ptr CallbackException; + + static NetStartWindow* Instance; +}; diff --git a/src/common/widgets/widgetresourcedata.cpp b/src/common/widgets/widgetresourcedata.cpp new file mode 100644 index 00000000000..85ee3e2498e --- /dev/null +++ b/src/common/widgets/widgetresourcedata.cpp @@ -0,0 +1,88 @@ + +#include +#include "filesystem.h" +#include "printf.h" +#include "zstring.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +FResourceFile* WidgetResources; + +void InitWidgetResources(const char* filename) +{ + WidgetResources = FResourceFile::OpenResourceFile(filename); + if (!WidgetResources) + I_FatalError("Unable to open %s", filename); +} + +void CloseWidgetResources() +{ + if (WidgetResources) delete WidgetResources; +} + +static std::vector LoadFile(const char* name) +{ + auto lump = WidgetResources->FindEntry(name); + if (lump == -1) + I_FatalError("Unable to find %s", name); + + auto reader = WidgetResources->GetEntryReader(lump, FileSys::READER_SHARED); + std::vector buffer(reader.GetLength()); + reader.Read(buffer.data(), buffer.size()); + return buffer; +} + +// this must be allowed to fail without throwing. +static std::vector LoadDiskFile(const char* name) +{ + std::vector buffer; + FileSys::FileReader lump; + if (lump.OpenFile(name)) + { + buffer.resize(lump.GetLength()); + lump.Read(buffer.data(), buffer.size()); + } + return buffer; +} + +// This interface will later require some significant redesign. +std::vector LoadWidgetFontData(const std::string& name) +{ + std::vector returnv; + if (!stricmp(name.c_str(), "notosans")) + { + returnv.resize(3); + returnv[0].fontdata = LoadFile("widgets/noto/notosans-regular.ttf"); + returnv[1].fontdata = LoadFile("widgets/noto/notosansarmenian-regular.ttf"); + returnv[2].fontdata = LoadFile("widgets/noto/notosansgeorgian-regular.ttf"); +#ifdef _WIN32 + wchar_t wbuffer[256]; + if (GetWindowsDirectoryW(wbuffer, 256)) + { + returnv.resize(5); + FString windir(wbuffer); + returnv[3].fontdata = LoadDiskFile((windir + "/fonts/yugothm.ttc").GetChars()); + returnv[3].language = "ja"; + returnv[4].fontdata = LoadDiskFile((windir + "/fonts/malgun.ttf").GetChars()); + returnv[4].language = "ko"; + // Don't fail if these cannot be found + if (returnv[4].fontdata.size() == 0) returnv.erase(returnv.begin() + 4); + if (returnv[3].fontdata.size() == 0) returnv.erase(returnv.begin() + 3); + } +#endif + return returnv; + + } + returnv.resize(1); + std::string fn = "widgets/font/" +name + ".ttf"; + returnv[0].fontdata = LoadFile(fn.c_str()); + return returnv; +} + +std::vector LoadWidgetData(const std::string& name) +{ + return LoadFile(name.c_str()); +} diff --git a/src/console/c_bind.cpp b/src/console/c_bind.cpp deleted file mode 100644 index 14e2f5e054e..00000000000 --- a/src/console/c_bind.cpp +++ /dev/null @@ -1,811 +0,0 @@ -/* -** c_bind.cpp -** Functions for using and maintaining key bindings -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "doomtype.h" -#include "doomdef.h" -#include "c_dispatch.h" -#include "c_bind.h" -#include "g_level.h" -#include "hu_stuff.h" -#include "configfile.h" -#include "d_event.h" -#include "w_wad.h" -#include "templates.h" -#include "dobject.h" -#include "vm.h" -#include "i_time.h" -#include "menu/menu.h" -#include "v_text.h" - -const char *KeyNames[NUM_KEYS] = -{ - // This array is dependant on the particular keyboard input - // codes generated in i_input.c. If they change there, they - // also need to change here. In this case, we use the - // DirectInput codes and assume a qwerty keyboard layout. - // See for the DIK_* codes - - NULL, "Escape", "1", "2", "3", "4", "5", "6", //00 - "7", "8", "9", "0", "-", "=", "Backspace","Tab", //08 - "Q", "W", "E", "R", "T", "Y", "U", "I", //10 - "O", "P", "[", "]", "Enter", "Ctrl", "A", "S", //18 - "D", "F", "G", "H", "J", "K", "L", ";", //20 - "'", "`", "Shift", "\\", "Z", "X", "C", "V", //28 - "B", "N", "M", ",", ".", "/", "RShift", "KP*", //30 - "Alt", "Space", "CapsLock", "F1", "F2", "F3", "F4", "F5", //38 - "F6", "F7", "F8", "F9", "F10", "NumLock", "Scroll", "KP7", //40 - "KP8", "KP9", "KP-", "KP4", "KP5", "KP6", "KP+", "KP1", //48 - "KP2", "KP3", "KP0", "KP.", NULL, NULL, "OEM102", "F11", //50 - "F12", NULL, NULL, NULL, NULL, NULL, NULL, NULL, //58 - NULL, NULL, NULL, NULL, "F13", "F14", "F15", "F16", //60 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //68 - "Kana", NULL, NULL, "Abnt_C1", NULL, NULL, NULL, NULL, //70 - NULL, "Convert", NULL, "NoConvert",NULL, "Yen", "Abnt_C2", NULL, //78 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //80 - NULL, NULL, NULL, NULL, NULL, "KP=", NULL, NULL, //88 - "Circumflex","@", ":", "_", "Kanji", "Stop", "Ax", "Unlabeled",//90 - NULL, "PrevTrack",NULL, NULL, "KP-Enter", "RCtrl", NULL, NULL, //98 - "Mute", "Calculator","Play", NULL, "Stop", NULL, NULL, NULL, //A0 - NULL, NULL, NULL, NULL, NULL, NULL, "VolDown", NULL, //A8 - "VolUp", NULL, "WebHome", "KP,", NULL, "KP/", NULL, "SysRq", //B0 - "RAlt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, //B8 - NULL, NULL, NULL, NULL, NULL, "Pause", NULL, "Home", //C0 - "UpArrow", "PgUp", NULL, "LeftArrow",NULL, "RightArrow",NULL, "End", //C8 - "DownArrow","PgDn", "Ins", "Del", NULL, NULL, NULL, NULL, //D0 -#ifdef __APPLE__ - NULL, NULL, NULL, "Command", NULL, "Apps", "Power", "Sleep", //D8 -#else // !__APPLE__ - NULL, NULL, NULL, "LWin", "RWin", "Apps", "Power", "Sleep", //D8 -#endif // __APPLE__ - NULL, NULL, NULL, "Wake", NULL, "Search", "Favorites","Refresh", //E0 - "WebStop", "WebForward","WebBack", "MyComputer","Mail", "MediaSelect",NULL, NULL, //E8 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //F0 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //F8 - - // non-keyboard buttons that can be bound - "Mouse1", "Mouse2", "Mouse3", "Mouse4", // 8 mouse buttons - "Mouse5", "Mouse6", "Mouse7", "Mouse8", - - "Joy1", "Joy2", "Joy3", "Joy4", // 128 joystick buttons! - "Joy5", "Joy6", "Joy7", "Joy8", - "Joy9", "Joy10", "Joy11", "Joy12", - "Joy13", "Joy14", "Joy15", "Joy16", - "Joy17", "Joy18", "Joy19", "Joy20", - "Joy21", "Joy22", "Joy23", "Joy24", - "Joy25", "Joy26", "Joy27", "Joy28", - "Joy29", "Joy30", "Joy31", "Joy32", - "Joy33", "Joy34", "Joy35", "Joy36", - "Joy37", "Joy38", "Joy39", "Joy40", - "Joy41", "Joy42", "Joy43", "Joy44", - "Joy45", "Joy46", "Joy47", "Joy48", - "Joy49", "Joy50", "Joy51", "Joy52", - "Joy53", "Joy54", "Joy55", "Joy56", - "Joy57", "Joy58", "Joy59", "Joy60", - "Joy61", "Joy62", "Joy63", "Joy64", - "Joy65", "Joy66", "Joy67", "Joy68", - "Joy69", "Joy70", "Joy71", "Joy72", - "Joy73", "Joy74", "Joy75", "Joy76", - "Joy77", "Joy78", "Joy79", "Joy80", - "Joy81", "Joy82", "Joy83", "Joy84", - "Joy85", "Joy86", "Joy87", "Joy88", - "Joy89", "Joy90", "Joy91", "Joy92", - "Joy93", "Joy94", "Joy95", "Joy96", - "Joy97", "Joy98", "Joy99", "Joy100", - "Joy101", "Joy102", "Joy103", "Joy104", - "Joy105", "Joy106", "Joy107", "Joy108", - "Joy109", "Joy110", "Joy111", "Joy112", - "Joy113", "Joy114", "Joy115", "Joy116", - "Joy117", "Joy118", "Joy119", "Joy120", - "Joy121", "Joy122", "Joy123", "Joy124", - "Joy125", "Joy126", "Joy127", "Joy128", - - "POV1Up", "POV1Right","POV1Down", "POV1Left", // First POV hat - "POV2Up", "POV2Right","POV2Down", "POV2Left", // Second POV hat - "POV3Up", "POV3Right","POV3Down", "POV3Left", // Third POV hat - "POV4Up", "POV4Right","POV4Down", "POV4Left", // Fourth POV hat - - "MWheelUp", "MWheelDown", // the mouse wheel - "MWheelRight", "MWheelLeft", - - "Axis1Plus","Axis1Minus","Axis2Plus","Axis2Minus", // joystick axes as buttons - "Axis3Plus","Axis3Minus","Axis4Plus","Axis4Minus", - "Axis5Plus","Axis5Minus","Axis6Plus","Axis6Minus", - "Axis7Plus","Axis7Minus","Axis8Plus","Axis8Minus", - - "LStickRight","LStickLeft","LStickDown","LStickUp", // Gamepad axis-based buttons - "RStickRight","RStickLeft","RStickDown","RStickUp", - - "DPadUp","DPadDown","DPadLeft","DPadRight", // Gamepad buttons - "Pad_Start","Pad_Back","LThumb","RThumb", - "LShoulder","RShoulder","LTrigger","RTrigger", - "Pad_A", "Pad_B", "Pad_X", "Pad_Y" -}; - -FKeyBindings Bindings; -FKeyBindings DoubleBindings; -FKeyBindings AutomapBindings; - -DEFINE_GLOBAL(Bindings) -DEFINE_GLOBAL(AutomapBindings) - -static unsigned int DClickTime[NUM_KEYS]; -static uint8_t DClicked[(NUM_KEYS+7)/8]; - -//============================================================================= -// -// -// -//============================================================================= - -static int GetKeyFromName (const char *name) -{ - int i; - - // Names of the form #xxx are translated to key xxx automatically - if (name[0] == '#' && name[1] != 0) - { - return atoi (name + 1); - } - - // Otherwise, we scan the KeyNames[] array for a matching name - for (i = 0; i < NUM_KEYS; i++) - { - if (KeyNames[i] && !stricmp (KeyNames[i], name)) - return i; - } - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -static int GetConfigKeyFromName (const char *key) -{ - int keynum = GetKeyFromName(key); - if (keynum == 0) - { - if (stricmp (key, "LeftBracket") == 0) - { - keynum = GetKeyFromName ("["); - } - else if (stricmp (key, "RightBracket") == 0) - { - keynum = GetKeyFromName ("]"); - } - else if (stricmp (key, "Equals") == 0) - { - keynum = GetKeyFromName ("="); - } - else if (stricmp (key, "KP-Equals") == 0) - { - keynum = GetKeyFromName ("kp="); - } - } - return keynum; -} - -//============================================================================= -// -// -// -//============================================================================= - -static const char *KeyName (int key) -{ - static char name[5]; - - if (KeyNames[key]) - return KeyNames[key]; - - mysnprintf (name, countof(name), "Key_%d", key); - return name; -} - -//============================================================================= -// -// -// -//============================================================================= - -static const char *ConfigKeyName(int keynum) -{ - const char *name = KeyName(keynum); - if (name[1] == 0) // Make sure given name is config-safe - { - if (name[0] == '[') - return "LeftBracket"; - else if (name[0] == ']') - return "RightBracket"; - else if (name[0] == '=') - return "Equals"; - else if (strcmp (name, "kp=") == 0) - return "KP-Equals"; - } - return name; -} - -//============================================================================= -// -// -// -//============================================================================= - -DEFINE_ACTION_FUNCTION(FKeyBindings, SetBind) -{ - PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); - PARAM_INT(k); - PARAM_STRING(cmd); - - // Only menus are allowed to change bindings. - if (DMenu::InMenu == 0) - { - I_FatalError("Attempt to change key bindings outside of menu code to '%s'", cmd.GetChars()); - } - - - self->SetBind(k, cmd); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -void C_NameKeys (char *str, int first, int second) -{ - int c = 0; - - *str = 0; - if (second == first) second = 0; - if (first) - { - c++; - strcpy (str, KeyName (first)); - if (second) - strcat (str, TEXTCOLOR_BLACK ", " TEXTCOLOR_NORMAL); - } - - if (second) - { - c++; - strcat (str, KeyName (second)); - } - - if (!c) - *str = '\0'; -} - -DEFINE_ACTION_FUNCTION(FKeyBindings, NameKeys) -{ - PARAM_PROLOGUE; - PARAM_INT(k1); - PARAM_INT(k2); - char buffer[120]; - C_NameKeys(buffer, k1, k2); - ACTION_RETURN_STRING(buffer); -} - -//============================================================================= -// -// -// -//============================================================================= - -void FKeyBindings::DoBind (const char *key, const char *bind) -{ - int keynum = GetConfigKeyFromName (key); - if (keynum != 0) - { - Binds[keynum] = bind; - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void FKeyBindings::UnbindAll () -{ - for (int i = 0; i < NUM_KEYS; ++i) - { - Binds[i] = ""; - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void FKeyBindings::UnbindKey(const char *key) -{ - int i; - - if ( (i = GetKeyFromName (key)) ) - { - Binds[i] = ""; - } - else - { - Printf ("Unknown key \"%s\"\n", key); - return; - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void FKeyBindings::PerformBind(FCommandLine &argv, const char *msg) -{ - int i; - - if (argv.argc() > 1) - { - i = GetKeyFromName (argv[1]); - if (!i) - { - Printf ("Unknown key \"%s\"\n", argv[1]); - return; - } - if (argv.argc() == 2) - { - Printf ("\"%s\" = \"%s\"\n", argv[1], Binds[i].GetChars()); - } - else - { - Binds[i] = argv[2]; - } - } - else - { - Printf ("%s:\n", msg); - - for (i = 0; i < NUM_KEYS; i++) - { - if (!Binds[i].IsEmpty()) - Printf ("%s \"%s\"\n", KeyName (i), Binds[i].GetChars()); - } - } -} - - -//============================================================================= -// -// This function is first called for functions in custom key sections. -// In this case, matchcmd is non-NULL, and only keys bound to that command -// are stored. If a match is found, its binding is set to "\1". -// After all custom key sections are saved, it is called one more for the -// normal Bindings and DoubleBindings sections for this game. In this case -// matchcmd is NULL and all keys will be stored. The config section was not -// previously cleared, so all old bindings are still in place. If the binding -// for a key is empty, the corresponding key in the config is removed as well. -// If a binding is "\1", then the binding itself is cleared, but nothing -// happens to the entry in the config. -// -//============================================================================= - -void FKeyBindings::ArchiveBindings(FConfigFile *f, const char *matchcmd) -{ - int i; - - for (i = 0; i < NUM_KEYS; i++) - { - if (Binds[i].IsEmpty()) - { - if (matchcmd == NULL) - { - f->ClearKey(ConfigKeyName(i)); - } - } - else if (matchcmd == NULL || stricmp(Binds[i], matchcmd) == 0) - { - if (Binds[i][0] == '\1') - { - Binds[i] = ""; - continue; - } - f->SetValueForKey(ConfigKeyName(i), Binds[i]); - if (matchcmd != NULL) - { // If saving a specific command, set a marker so that - // it does not get saved in the general binding list. - Binds[i] = "\1"; - } - } - } -} - -//============================================================================= -// -// -// -//============================================================================= - -int FKeyBindings::GetKeysForCommand (const char *cmd, int *first, int *second) -{ - int c, i; - - *first = *second = c = i = 0; - - while (i < NUM_KEYS && c < 2) - { - if (stricmp (cmd, Binds[i]) == 0) - { - if (c++ == 0) - *first = i; - else - *second = i; - } - i++; - } - return c; -} - -DEFINE_ACTION_FUNCTION(FKeyBindings, GetKeysForCommand) -{ - PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); - PARAM_STRING(cmd); - int k1, k2; - self->GetKeysForCommand(cmd.GetChars(), &k1, &k2); - if (numret > 0) ret[0].SetInt(k1); - if (numret > 1) ret[1].SetInt(k2); - return MIN(numret, 2); -} - -//============================================================================= -// -// -// -//============================================================================= - -void FKeyBindings::UnbindACommand (const char *str) -{ - int i; - - for (i = 0; i < NUM_KEYS; i++) - { - if (!stricmp (str, Binds[i])) - { - Binds[i] = ""; - } - } -} - -DEFINE_ACTION_FUNCTION(FKeyBindings, UnbindACommand) -{ - PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); - PARAM_STRING(cmd); - - // Only menus are allowed to change bindings. - if (DMenu::InMenu == 0) - { - I_FatalError("Attempt to unbind key bindings for '%s' outside of menu code", cmd.GetChars()); - } - - self->UnbindACommand(cmd); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -void FKeyBindings::DefaultBind(const char *keyname, const char *cmd) -{ - int key = GetKeyFromName (keyname); - if (key == 0) - { - Printf ("Unknown key \"%s\"\n", keyname); - return; - } - if (!Binds[key].IsEmpty()) - { // This key is already bound. - return; - } - for (int i = 0; i < NUM_KEYS; ++i) - { - if (!Binds[i].IsEmpty() && stricmp (Binds[i], cmd) == 0) - { // This command is already bound to a key. - return; - } - } - // It is safe to do the bind, so do it. - Binds[key] = cmd; -} - -//============================================================================= -// -// -// -//============================================================================= - -void C_UnbindAll () -{ - Bindings.UnbindAll(); - DoubleBindings.UnbindAll(); - AutomapBindings.UnbindAll(); -} - -UNSAFE_CCMD (unbindall) -{ - C_UnbindAll (); -} - -//============================================================================= -// -// -// -//============================================================================= - -CCMD (unbind) -{ - if (argv.argc() > 1) - { - Bindings.UnbindKey(argv[1]); - } -} - -CCMD (undoublebind) -{ - if (argv.argc() > 1) - { - DoubleBindings.UnbindKey(argv[1]); - } -} - -CCMD (unmapbind) -{ - if (argv.argc() > 1) - { - AutomapBindings.UnbindKey(argv[1]); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -CCMD (bind) -{ - Bindings.PerformBind(argv, "Current key bindings"); -} - -CCMD (doublebind) -{ - DoubleBindings.PerformBind(argv, "Current key doublebindings"); -} - -CCMD (mapbind) -{ - AutomapBindings.PerformBind(argv, "Current automap key bindings"); -} - -//========================================================================== -// -// CCMD defaultbind -// -// Binds a command to a key if that key is not already bound and if -// that command is not already bound to another key. -// -//========================================================================== - -CCMD (defaultbind) -{ - if (argv.argc() < 3) - { - Printf ("Usage: defaultbind \n"); - } - else - { - Bindings.DefaultBind(argv[1], argv[2]); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -CCMD (rebind) -{ - FKeyBindings *bindings; - - if (key == 0) - { - Printf ("Rebind cannot be used from the console\n"); - return; - } - - if (key & KEY_DBLCLICKED) - { - bindings = &DoubleBindings; - key &= KEY_DBLCLICKED-1; - } - else - { - bindings = &Bindings; - } - - if (argv.argc() > 1) - { - bindings->SetBind(key, argv[1]); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void C_BindDefaults () -{ - int lump, lastlump = 0; - - while ((lump = Wads.FindLump("DEFBINDS", &lastlump)) != -1) - { - FScanner sc(lump); - - while (sc.GetString()) - { - FKeyBindings *dest = &Bindings; - int key; - - // bind destination is optional and is the same as the console command - if (sc.Compare("bind")) - { - sc.MustGetString(); - } - else if (sc.Compare("doublebind")) - { - dest = &DoubleBindings; - sc.MustGetString(); - } - else if (sc.Compare("mapbind")) - { - dest = &AutomapBindings; - sc.MustGetString(); - } - key = GetConfigKeyFromName(sc.String); - sc.MustGetString(); - dest->SetBind(key, sc.String); - } - } -} - -CCMD(binddefaults) -{ - C_BindDefaults (); -} - -void C_SetDefaultBindings () -{ - C_UnbindAll (); - C_BindDefaults (); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds) -{ - FString binding; - bool dclick; - int dclickspot; - uint8_t dclickmask; - unsigned int nowtime; - - if (ev->type != EV_KeyDown && ev->type != EV_KeyUp) - return false; - - if ((unsigned int)ev->data1 >= NUM_KEYS) - return false; - - dclickspot = ev->data1 >> 3; - dclickmask = 1 << (ev->data1 & 7); - dclick = false; - - nowtime = (unsigned)I_msTime(); - if (doublebinds != NULL && int(DClickTime[ev->data1] - nowtime) > 0 && ev->type == EV_KeyDown) - { - // Key pressed for a double click - binding = doublebinds->GetBinding(ev->data1); - DClicked[dclickspot] |= dclickmask; - dclick = true; - } - else - { - if (ev->type == EV_KeyDown) - { // Key pressed for a normal press - binding = binds->GetBinding(ev->data1); - DClickTime[ev->data1] = nowtime + 571; - } - else if (doublebinds != NULL && DClicked[dclickspot] & dclickmask) - { // Key released from a double click - binding = doublebinds->GetBinding(ev->data1); - DClicked[dclickspot] &= ~dclickmask; - DClickTime[ev->data1] = 0; - dclick = true; - } - else - { // Key released from a normal press - binding = binds->GetBinding(ev->data1); - } - } - - - if (binding.IsEmpty()) - { - binding = binds->GetBinding(ev->data1); - dclick = false; - } - - if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256)) - { - if (ev->type == EV_KeyUp && binding[0] != '+') - { - return false; - } - - char *copy = binding.LockBuffer(); - - if (ev->type == EV_KeyUp) - { - copy[0] = '-'; - } - - AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1); - return true; - } - return false; -} - diff --git a/src/console/c_cmds.cpp b/src/console/c_cmds.cpp index 8d030eceda5..19c5c9d5098 100644 --- a/src/console/c_cmds.cpp +++ b/src/console/c_cmds.cpp @@ -35,25 +35,20 @@ #include #include #include - -#ifdef _WIN32 -#include -#else -#include -#endif +#include #include "version.h" #include "c_console.h" #include "c_dispatch.h" #include "i_system.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "doomstat.h" #include "gstrings.h" #include "s_sound.h" #include "g_game.h" #include "g_level.h" -#include "w_wad.h" +#include "filesystem.h" #include "gi.h" #include "r_defs.h" #include "d_player.h" @@ -68,21 +63,33 @@ #include "c_functions.h" #include "g_levellocals.h" #include "v_video.h" +#include "md5.h" +#include "findfile.h" +#include "i_music.h" +#include "s_music.h" +#include "texturemanager.h" +#include "v_draw.h" +#include "d_main.h" +#include "savegamemanager.h" extern FILE *Logfile; extern bool insave; -CVAR (Bool, sv_cheats, false, CVAR_SERVERINFO | CVAR_LATCH) +CVAR (Bool, sv_cheats, false, CVAR_SERVERINFO) CVAR (Bool, sv_unlimited_pickup, false, CVAR_SERVERINFO) CVAR (Int, cl_blockcheats, 0, 0) -CCMD (toggleconsole) -{ - C_ToggleConsole(); -} +CVARD(Bool, show_messages, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable showing messages") +CVAR(Bool, show_obituaries, true, CVAR_ARCHIVE) -bool CheckCheatmode (bool printmsg) + +bool CheckCheatmode (bool printmsg, bool sponly) { + if (sponly && netgame) + { + if (printmsg) Printf("Not in a singleplayer game.\n"); + return true; + } if ((G_SkillProperty(SKILLP_DisableCheats) || netgame || deathmatch) && (!sv_cheats)) { if (printmsg) Printf ("sv_cheats must be true to enable this command.\n"); @@ -99,16 +106,6 @@ bool CheckCheatmode (bool printmsg) } } -CCMD (quit) -{ - if (!insave) throw CExitEvent(0); -} - -CCMD (exit) -{ - if (!insave) throw CExitEvent(0); -} - /* ================== Cmd_God @@ -123,8 +120,8 @@ CCMD (god) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_GOD); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_GOD); } CCMD(god2) @@ -132,8 +129,8 @@ CCMD(god2) if (CheckCheatmode()) return; - Net_WriteByte(DEM_GENERICCHEAT); - Net_WriteByte(CHT_GOD2); + Net_WriteInt8(DEM_GENERICCHEAT); + Net_WriteInt8(CHT_GOD2); } CCMD (iddqd) @@ -141,8 +138,8 @@ CCMD (iddqd) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_IDDQD); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_IDDQD); } CCMD (buddha) @@ -150,8 +147,8 @@ CCMD (buddha) if (CheckCheatmode()) return; - Net_WriteByte(DEM_GENERICCHEAT); - Net_WriteByte(CHT_BUDDHA); + Net_WriteInt8(DEM_GENERICCHEAT); + Net_WriteInt8(CHT_BUDDHA); } CCMD(buddha2) @@ -159,8 +156,8 @@ CCMD(buddha2) if (CheckCheatmode()) return; - Net_WriteByte(DEM_GENERICCHEAT); - Net_WriteByte(CHT_BUDDHA2); + Net_WriteInt8(DEM_GENERICCHEAT); + Net_WriteInt8(CHT_BUDDHA2); } CCMD (notarget) @@ -168,8 +165,8 @@ CCMD (notarget) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_NOTARGET); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_NOTARGET); } CCMD (fly) @@ -177,8 +174,8 @@ CCMD (fly) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_FLY); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_FLY); } /* @@ -193,8 +190,8 @@ CCMD (noclip) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_NOCLIP); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_NOCLIP); } CCMD (noclip2) @@ -202,8 +199,8 @@ CCMD (noclip2) if (CheckCheatmode()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_NOCLIP2); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_NOCLIP2); } CCMD (powerup) @@ -211,8 +208,8 @@ CCMD (powerup) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_POWER); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_POWER); } CCMD (morphme) @@ -222,12 +219,12 @@ CCMD (morphme) if (argv.argc() == 1) { - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_MORPH); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_MORPH); } else { - Net_WriteByte (DEM_MORPHEX); + Net_WriteInt8 (DEM_MORPHEX); Net_WriteString (argv[1]); } } @@ -237,8 +234,8 @@ CCMD (anubis) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_ANUBIS); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_ANUBIS); } // [GRB] @@ -247,8 +244,8 @@ CCMD (resurrect) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_RESSURECT); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_RESSURECT); } EXTERN_CVAR (Bool, chasedemo) @@ -279,8 +276,8 @@ CCMD (chase) if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && deathmatch && CheckCheatmode ())) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_CHASECAM); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_CHASECAM); } } @@ -312,12 +309,12 @@ CCMD (idclev) // Catch invalid maps. mapname = CalcMapName (epsd, map); - if (!P_CheckMapData(mapname)) + if (!P_CheckMapData(mapname.GetChars())) return; // So be it. - Printf ("%s\n", GStrings("STSTR_CLEV")); - G_DeferedInitNew (mapname); + Printf ("%s\n", GStrings.GetString("STSTR_CLEV")); + G_DeferedInitNew (mapname.GetChars()); //players[0].health = 0; // Force reset } } @@ -337,11 +334,11 @@ CCMD (hxvisit) { // Just because it's in MAPINFO doesn't mean it's in the wad. - if (P_CheckMapData(mapname)) + if (P_CheckMapData(mapname.GetChars())) { // So be it. - Printf ("%s\n", GStrings("STSTR_CLEV")); - G_DeferedInitNew (mapname); + Printf ("%s\n", GStrings.GetString("STSTR_CLEV")); + G_DeferedInitNew (mapname.GetChars()); return; } } @@ -351,13 +348,13 @@ CCMD (hxvisit) CCMD (changemap) { - if (who == NULL || !usergame) + if (!players[consoleplayer].mo || !usergame) { Printf ("Use the map command when not in a game.\n"); return; } - if (!players[who->player - players].settings_controller && netgame) + if (!players[consoleplayer].settings_controller && netgame) { Printf ("Only setting controllers can change the map.\n"); return; @@ -366,7 +363,18 @@ CCMD (changemap) if (argv.argc() > 1) { const char *mapname = argv[1]; - if (!strcmp(mapname, "*")) mapname = primaryLevel->MapName.GetChars(); + if (!strcmp(mapname, "*")) + { + mapname = primaryLevel->MapName.GetChars(); + } + else if (!strcmp(mapname, "+") && primaryLevel->NextMap.Len() > 0 && primaryLevel->NextMap.Compare("enDSeQ", 6)) + { + mapname = primaryLevel->NextMap.GetChars(); + } + else if (!strcmp(mapname, "+$") && primaryLevel->NextSecretMap.Len() > 0 && primaryLevel->NextSecretMap.Compare("enDSeQ", 6)) + { + mapname = primaryLevel->NextSecretMap.GetChars(); + } try { @@ -378,12 +386,12 @@ CCMD (changemap) { if (argv.argc() > 2) { - Net_WriteByte (DEM_CHANGEMAP2); - Net_WriteByte (atoi(argv[2])); + Net_WriteInt8 (DEM_CHANGEMAP2); + Net_WriteInt8 (atoi(argv[2])); } else { - Net_WriteByte (DEM_CHANGEMAP); + Net_WriteInt8 (DEM_CHANGEMAP); } Net_WriteString (mapname); } @@ -400,17 +408,51 @@ CCMD (changemap) } } +CCMD (changeskill) +{ + if (!players[consoleplayer].mo || !usergame) + { + Printf ("Cannot change skills while not in a game.\n"); + return; + } + + if (!players[consoleplayer].settings_controller && netgame) + { + Printf ("Only setting controllers can change the skill.\n"); + return; + } + + if (argv.argc() == 2) + { + int skill = atoi(argv[1]); + if ((unsigned)skill >= AllSkills.Size()) + { + Printf ("Skill %d is out of range.\n", skill); + } + else + { + Net_WriteInt8(DEM_CHANGESKILL); + Net_WriteInt32(skill); + Printf ("Skill %d will take effect on the next map.\n", skill); + } + } + else + { + Printf ("Usage: changeskill \n"); + } +} + CCMD (give) { if (CheckCheatmode () || argv.argc() < 2) return; - Net_WriteByte (DEM_GIVECHEAT); + Net_WriteInt8 (DEM_GIVECHEAT); Net_WriteString (argv[1]); if (argv.argc() > 2) - Net_WriteLong(atoi(argv[2])); + Net_WriteInt32(atoi(argv[2])); else - Net_WriteLong(0); + Net_WriteInt32(0); } CCMD (take) @@ -418,12 +460,12 @@ CCMD (take) if (CheckCheatmode () || argv.argc() < 2) return; - Net_WriteByte (DEM_TAKECHEAT); + Net_WriteInt8 (DEM_TAKECHEAT); Net_WriteString (argv[1]); if (argv.argc() > 2) - Net_WriteLong(atoi (argv[2])); + Net_WriteInt32(atoi (argv[2])); else - Net_WriteLong (0); + Net_WriteInt32 (0); } CCMD(setinv) @@ -431,87 +473,20 @@ CCMD(setinv) if (CheckCheatmode() || argv.argc() < 2) return; - Net_WriteByte(DEM_SETINV); + Net_WriteInt8(DEM_SETINV); Net_WriteString(argv[1]); if (argv.argc() > 2) - Net_WriteLong(atoi(argv[2])); + Net_WriteInt32(atoi(argv[2])); else - Net_WriteLong(0); + Net_WriteInt32(0); if (argv.argc() > 3) - Net_WriteByte(!!atoi(argv[3])); + Net_WriteInt8(!!atoi(argv[3])); else - Net_WriteByte(0); + Net_WriteInt8(0); } -CCMD (gameversion) -{ - Printf ("%s @ %s\nCommit %s\n", GetVersionString(), GetGitTime(), GetGitHash()); -} - -CCMD (print) -{ - if (argv.argc() != 2) - { - Printf ("print : Print a string from the string table\n"); - return; - } - const char *str = GStrings[argv[1]]; - if (str == NULL) - { - Printf ("%s unknown\n", argv[1]); - } - else - { - Printf ("%s\n", str); - } -} - -UNSAFE_CCMD (exec) -{ - if (argv.argc() < 2) - return; - - for (int i = 1; i < argv.argc(); ++i) - { - if (!C_ExecFile(argv[i])) - { - Printf ("Could not exec \"%s\"\n", argv[i]); - break; - } - } -} - -void execLogfile(const char *fn, bool append) -{ - if ((Logfile = fopen(fn, append? "a" : "w"))) - { - const char *timestr = myasctime(); - Printf("Log started: %s\n", timestr); - } - else - { - Printf("Could not start log\n"); - } -} - -UNSAFE_CCMD (logfile) -{ - - if (Logfile) - { - const char *timestr = myasctime(); - Printf("Log stopped: %s\n", timestr); - fclose (Logfile); - Logfile = NULL; - } - - if (argv.argc() >= 2) - { - execLogfile(argv[1], argv.argc() >=3? !!argv[2]:false); - } -} CCMD (puke) { @@ -530,7 +505,7 @@ CCMD (puke) return; } int arg[4] = { 0, 0, 0, 0 }; - int argn = MIN(argc - 2, countof(arg)), i; + int argn = min(argc - 2, countof(arg)), i; for (i = 0; i < argn; ++i) { @@ -539,18 +514,18 @@ CCMD (puke) if (script > 0) { - Net_WriteByte (DEM_RUNSCRIPT); - Net_WriteWord (script); + Net_WriteInt8 (DEM_RUNSCRIPT); + Net_WriteInt16 (script); } else { - Net_WriteByte (DEM_RUNSCRIPT2); - Net_WriteWord (-script); + Net_WriteInt8 (DEM_RUNSCRIPT2); + Net_WriteInt16 (-script); } - Net_WriteByte (argn); + Net_WriteInt8 (argn); for (i = 0; i < argn; ++i) { - Net_WriteLong (arg[i]); + Net_WriteInt32 (arg[i]); } } } @@ -577,18 +552,18 @@ CCMD (pukename) always = true; argstart = 3; } - argn = MIN(argc - argstart, countof(arg)); + argn = min(argc - argstart, countof(arg)); for (i = 0; i < argn; ++i) { arg[i] = atoi(argv[argstart + i]); } } - Net_WriteByte(DEM_RUNNAMEDSCRIPT); + Net_WriteInt8(DEM_RUNNAMEDSCRIPT); Net_WriteString(argv[1]); - Net_WriteByte(argn | (always << 7)); + Net_WriteInt8(argn | (always << 7)); for (i = 0; i < argn; ++i) { - Net_WriteLong(arg[i]); + Net_WriteInt32(arg[i]); } } } @@ -629,131 +604,16 @@ CCMD (special) return; } } - Net_WriteByte(DEM_RUNSPECIAL); - Net_WriteWord(specnum); - Net_WriteByte(argc - 2); + Net_WriteInt8(DEM_RUNSPECIAL); + Net_WriteInt16(specnum); + Net_WriteInt8(argc - 2); for (int i = 2; i < argc; ++i) { - Net_WriteLong(atoi(argv[i])); + Net_WriteInt32(atoi(argv[i])); } } } -CCMD (error) -{ - if (argv.argc() > 1) - { - char *textcopy = copystring (argv[1]); - I_Error ("%s", textcopy); - } - else - { - Printf ("Usage: error \n"); - } -} - -UNSAFE_CCMD (error_fatal) -{ - if (argv.argc() > 1) - { - char *textcopy = copystring (argv[1]); - I_FatalError ("%s", textcopy); - } - else - { - Printf ("Usage: error_fatal \n"); - } -} - -//========================================================================== -// -// CCMD crashout -// -// Debugging routine for testing the crash logger. -// Useless in a win32 debug build, because that doesn't enable the crash logger. -// -//========================================================================== - -#if !defined(_WIN32) || !defined(_DEBUG) -UNSAFE_CCMD (crashout) -{ - *(volatile int *)0 = 0; -} -#endif - - -UNSAFE_CCMD (dir) -{ - FString dir, path; - char curdir[256]; - const char *match; - findstate_t c_file; - void *file; - - if (!getcwd (curdir, countof(curdir))) - { - Printf ("Current path too long\n"); - return; - } - - if (argv.argc() > 1) - { - path = NicePath(argv[1]); - if (chdir(path)) - { - match = path; - dir = ExtractFilePath(path); - if (dir[0] != '\0') - { - match += dir.Len(); - } - else - { - dir = "./"; - } - if (match[0] == '\0') - { - match = "*"; - } - if (chdir (dir)) - { - Printf ("%s not found\n", dir.GetChars()); - return; - } - } - else - { - match = "*"; - dir = path; - } - } - else - { - match = "*"; - dir = curdir; - } - if (dir[dir.Len()-1] != '/') - { - dir += '/'; - } - - if ( (file = I_FindFirst (match, &c_file)) == ((void *)(-1))) - Printf ("Nothing matching %s%s\n", dir.GetChars(), match); - else - { - Printf ("Listing of %s%s:\n", dir.GetChars(), match); - do - { - if (I_FindAttr (&c_file) & FA_DIREC) - Printf (PRINT_BOLD, "%s

\n", I_FindName (&c_file)); - else - Printf ("%s\n", I_FindName (&c_file)); - } while (I_FindNext (file, &c_file) == 0); - I_FindClose (file); - } - - chdir (curdir); -} //========================================================================== // @@ -780,10 +640,10 @@ CCMD (warp) } else { - Net_WriteByte (DEM_WARPCHEAT); - Net_WriteWord (atoi (argv[1])); - Net_WriteWord (atoi (argv[2])); - Net_WriteWord (argv.argc() == 3 ? ONFLOORZ/65536 : atoi (argv[3])); + Net_WriteInt8 (DEM_WARPCHEAT); + Net_WriteInt16 (atoi (argv[1])); + Net_WriteInt16 (atoi (argv[2])); + Net_WriteInt16 (argv.argc() == 3 ? ONFLOORZ/65536 : atoi (argv[3])); } } @@ -808,8 +668,27 @@ UNSAFE_CCMD (load) return; } FString fname = argv[1]; - DefaultExtension (fname, "." SAVEGAME_EXT); - G_LoadGame (fname); + FixPathSeperator(fname); + if (fname[0] == '/') + { + Printf("saving to an absolute path is not allowed\n"); + return; + } + if (fname.IndexOf("..") > 0) + { + Printf("'..' not allowed in file names\n"); + return; + } +#ifdef _WIN32 + // block all invalid characters for Windows file names + if (fname.IndexOfAny(":?*<>|") >= 0) + { + Printf("file name contains invalid characters\n"); + return; + } +#endif + fname = G_BuildSaveName(fname.GetChars()); + G_LoadGame (fname.GetChars()); } //========================================================================== @@ -820,48 +699,38 @@ UNSAFE_CCMD (load) // //========================================================================== -UNSAFE_CCMD (save) +UNSAFE_CCMD(save) { - if (argv.argc() < 2 || argv.argc() > 3) + if (argv.argc() < 2 || argv.argc() > 3 || argv[1][0] == 0) { Printf ("usage: save [description]\n"); return; } - FString fname = argv[1]; - DefaultExtension (fname, "." SAVEGAME_EXT); - G_SaveGame (fname, argv.argc() > 2 ? argv[2] : argv[1]); -} - -//========================================================================== -// -// CCMD wdir -// -// Lists the contents of a loaded wad file. -// -//========================================================================== - -CCMD (wdir) -{ - if (argv.argc() != 2) + FString fname = argv[1]; + FixPathSeperator(fname); + if (fname[0] == '/') { - Printf ("usage: wdir \n"); + Printf("saving to an absolute path is not allowed\n"); return; } - int wadnum = Wads.CheckIfWadLoaded (argv[1]); - if (wadnum < 0) + if (fname.IndexOf("..") > 0) { - Printf ("%s must be loaded to view its directory.\n", argv[1]); + Printf("'..' not allowed in file names\n"); return; } - for (int i = 0; i < Wads.GetNumLumps(); ++i) +#ifdef _WIN32 + // block all invalid characters for Windows file names + if (fname.IndexOfAny(":?*<>|") >= 0) { - if (Wads.GetLumpFile(i) == wadnum) - { - Printf ("%s\n", Wads.GetLumpFullName(i)); - } + Printf("file name contains invalid characters\n"); + return; } +#endif + fname = G_BuildSaveName(fname.GetChars()); + G_SaveGame (fname.GetChars(), argv.argc() > 2 ? argv[2] : argv[1]); } + //----------------------------------------------------------------------------- // // @@ -1083,8 +952,8 @@ CCMD(thaw) if (CheckCheatmode()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_CLEARFROZENPROPS); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_CLEARFROZENPROPS); } //----------------------------------------------------------------------------- @@ -1103,7 +972,7 @@ CCMD(nextmap) if (primaryLevel->NextMap.Len() > 0 && primaryLevel->NextMap.Compare("enDSeQ", 6)) { - G_DeferedInitNew(primaryLevel->NextMap); + G_DeferedInitNew(primaryLevel->NextMap.GetChars()); } else { @@ -1127,7 +996,7 @@ CCMD(nextsecret) if (primaryLevel->NextSecretMap.Len() > 0 && primaryLevel->NextSecretMap.Compare("enDSeQ", 6)) { - G_DeferedInitNew(primaryLevel->NextSecretMap); + G_DeferedInitNew(primaryLevel->NextSecretMap.GetChars()); } else { @@ -1146,8 +1015,8 @@ CCMD(currentpos) AActor *mo = players[consoleplayer].mo; if(mo) { - Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, lightlevel: %d\n", - mo->X(), mo->Y(), mo->Z(), mo->Angles.Yaw.Normalized360().Degrees, mo->floorz, mo->Sector->sectornum, mo->Sector->lightlevel); + Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, sector lightlevel: %d, actor lightlevel: %d\n", + mo->X(), mo->Y(), mo->Z(), mo->Angles.Yaw.Normalized360().Degrees(), mo->floorz, mo->Sector->sectornum, mo->Sector->lightlevel, mo->LightLevel); } else { @@ -1181,7 +1050,7 @@ static void PrintSecretString(const char *string, bool thislevel) } else if (string[1] == 'T' || string[1] == 't') { - long tid = (long)strtoll(string+2, (char**)&string, 10); + int tid = (int)strtoll(string+2, (char**)&string, 10); if (*string == ';') string++; auto it = primaryLevel->GetActorIterator(tid); AActor *actor; @@ -1199,7 +1068,7 @@ static void PrintSecretString(const char *string, bool thislevel) else colstr = TEXTCOLOR_GREEN; } } - auto brok = V_BreakLines(CurrentConsoleFont, screen->GetWidth()*95/100, string); + auto brok = V_BreakLines(CurrentConsoleFont, twod->GetWidth()*95/100, *string == '$' ? GStrings.GetString(++string) : string); for (auto &line : brok) { @@ -1217,33 +1086,33 @@ static void PrintSecretString(const char *string, bool thislevel) CCMD(secret) { const char *mapname = argv.argc() < 2? primaryLevel->MapName.GetChars() : argv[1]; - bool thislevel = !stricmp(mapname, primaryLevel->MapName); + bool thislevel = !stricmp(mapname, primaryLevel->MapName.GetChars()); bool foundsome = false; - int lumpno=Wads.CheckNumForName("SECRETS"); + int lumpno=fileSystem.CheckNumForName("SECRETS"); if (lumpno < 0) return; - auto lump = Wads.OpenLumpReader(lumpno); + auto lump = fileSystem.OpenFileReader(lumpno); FString maphdr; maphdr.Format("[%s]", mapname); FString linebuild; - char readbuffer[1024]; + char readbuffer[10240]; bool inlevel = false; - while (lump.Gets(readbuffer, 1024)) + while (lump.Gets(readbuffer, 10240)) { if (!inlevel) { if (readbuffer[0] == '[') { - inlevel = !strnicmp(readbuffer, maphdr, maphdr.Len()); + inlevel = !strnicmp(readbuffer, maphdr.GetChars(), maphdr.Len()); if (!foundsome) { FString levelname; level_info_t *info = FindLevelInfo(mapname); - const char *ln = !(info->flags & LEVEL_LOOKUPLEVELNAME)? info->LevelName.GetChars() : GStrings[info->LevelName.GetChars()]; - levelname.Format("%s - %s", mapname, ln); + FString ln = info->LookupLevelName(); + levelname.Format("%s - %s", mapname, ln.GetChars()); Printf(TEXTCOLOR_YELLOW "%s\n", levelname.GetChars()); size_t llen = levelname.Len(); levelname = ""; @@ -1264,7 +1133,7 @@ CCMD(secret) // line complete so print it. linebuild.Substitute("\r", ""); linebuild.StripRight(" \t\n"); - PrintSecretString(linebuild, thislevel); + PrintSecretString(linebuild.GetChars(), thislevel); linebuild = ""; } } @@ -1278,7 +1147,7 @@ CCMD(angleconvtest) Printf("Testing degrees to angle conversion:\n"); for (double ang = -5 * 180.; ang < 5 * 180.; ang += 45.) { - unsigned ang1 = DAngle(ang).BAMs(); + unsigned ang1 = DAngle::fromDeg(ang).BAMs(); unsigned ang2 = (unsigned)(ang * (0x40000000 / 90.)); unsigned ang3 = (unsigned)(int)(ang * (0x40000000 / 90.)); Printf("Angle = %.5f: xs_RoundToInt = %08x, unsigned cast = %08x, signed cast = %08x\n", @@ -1305,3 +1174,182 @@ CCMD(r_showcaps) PRINT_CAP("Truecolor Enabled", RFF_TRUECOLOR) PRINT_CAP("Voxels", RFF_VOXELS) } + + +//========================================================================== +// +// CCMD idmus +// +//========================================================================== + +CCMD(idmus) +{ + level_info_t* info; + FString map; + int l; + + if (MusicEnabled()) + { + if (argv.argc() > 1) + { + if (gameinfo.flags & GI_MAPxx) + { + l = atoi(argv[1]); + if (l <= 99) + { + map = CalcMapName(0, l); + } + else + { + Printf("%s\n", GStrings.GetString("STSTR_NOMUS")); + return; + } + } + else + { + map = CalcMapName(argv[1][0] - '0', argv[1][1] - '0'); + } + + if ((info = FindLevelInfo(map.GetChars()))) + { + if (info->Music.IsNotEmpty()) + { + S_ChangeMusic(info->Music.GetChars(), info->musicorder); + Printf("%s\n", GStrings.GetString("STSTR_MUS")); + } + } + else + { + Printf("%s\n", GStrings.GetString("STSTR_NOMUS")); + } + } + } + else + { + Printf("Music is disabled\n"); + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +CCMD(dumpactors) +{ + const char* const filters[32] = + { + "0:All", "1:Doom", "2:Heretic", "3:DoomHeretic", "4:Hexen", "5:DoomHexen", "6:Raven", "7:IdRaven", + "8:Strife", "9:DoomStrife", "10:HereticStrife", "11:DoomHereticStrife", "12:HexenStrife", + "13:DoomHexenStrife", "14:RavenStrife", "15:NotChex", "16:Chex", "17:DoomChex", "18:HereticChex", + "19:DoomHereticChex", "20:HexenChex", "21:DoomHexenChex", "22:RavenChex", "23:NotStrife", "24:StrifeChex", + "25:DoomStrifeChex", "26:HereticStrifeChex", "27:NotHexen", "28:HexenStrifeChex", "29:NotHeretic", + "30:NotDoom", "31:All", + }; + Printf("%u object class types total\nActor\tEd Num\tSpawnID\tFilter\tSource\n", PClass::AllClasses.Size()); + for (unsigned int i = 0; i < PClass::AllClasses.Size(); i++) + { + PClass* cls = PClass::AllClasses[i]; + PClassActor* acls = ValidateActor(cls); + if (acls != NULL) + { + auto ainfo = acls->ActorInfo(); + Printf("%s\t%i\t%i\t%s\t%s\n", + acls->TypeName.GetChars(), ainfo->DoomEdNum, + ainfo->SpawnID, filters[ainfo->GameFilter & 31], + acls->SourceLumpName.GetChars()); + } + else if (cls != NULL) + { + Printf("%s\tn/a\tn/a\tn/a\tEngine (not an actor type)\tSource: %s\n", cls->TypeName.GetChars(), cls->SourceLumpName.GetChars()); + } + else + { + Printf("Type %i is not an object class\n", i); + } + } +} + +const char* testlocalised(const char* in) +{ + const char *out = GStrings.GetLanguageString(in, FStringTable::default_table); + if (in[0] == '$') + out = GStrings.GetLanguageString(in + 1, FStringTable::default_table); + if (out) + return out; + return in; +} + +CCMD (mapinfo) +{ + level_info_t *myLevel = nullptr; + if (players[consoleplayer].mo && players[consoleplayer].mo->Level) + myLevel = players[consoleplayer].mo->Level->info; + + if (argv.argc() > 1) + { + if (P_CheckMapData(argv[1])) + myLevel = FindLevelInfo(argv[1]); + else + { + Printf("Mapname '%s' not found\n", argv[1]); + return; + } + } + + if (!myLevel) + { + Printf("Not in a level\n"); + return; + } + + Printf("[ Map Info For: '%s' ]\n\n", myLevel->MapName.GetChars()); + + if (myLevel->LevelName.IsNotEmpty()) + Printf(" LevelName: %s\n", myLevel->LookupLevelName().GetChars()); + + if (myLevel->AuthorName.IsNotEmpty()) + Printf(" AuthorName: %s\n", testlocalised(myLevel->AuthorName.GetChars())); + + if (myLevel->levelnum) + Printf(" LevelNum: %i\n", myLevel->levelnum); + + if (myLevel->NextMap.IsNotEmpty()) + Printf(" Next: %s\n", myLevel->NextMap.GetChars()); + + if (myLevel->NextSecretMap.IsNotEmpty()) + Printf(" SecretNext: %s\n", myLevel->NextSecretMap.GetChars()); + + if (myLevel->Music.IsNotEmpty()) + Printf(" Music: %s%s\n", myLevel->Music[0] == '$'? "D_" : "", testlocalised(myLevel->Music.GetChars())); + + Printf(" PixelStretch: %f\n", myLevel->pixelstretch); + + if (myLevel->RedirectType != NAME_None) + Printf(" Redirect (Item): %s\n", myLevel->RedirectType.GetChars()); + + if (myLevel->RedirectMapName.IsNotEmpty()) + Printf(" Redirect (Map): %s\n", myLevel->RedirectMapName.GetChars()); + + if (myLevel->RedirectCVAR != NAME_None) + Printf("CVAR_Redirect (CVAR): %s\n", myLevel->RedirectCVAR.GetChars()); + + if (myLevel->RedirectCVARMapName.IsNotEmpty()) + Printf(" CVAR_Redirect (Map): %s\n", myLevel->RedirectCVARMapName.GetChars()); + + Printf(" LightMode: %i\n", (int8_t)myLevel->lightmode); + + if (players[consoleplayer].mo && players[consoleplayer].mo->Level) + { + level_info_t *check = myLevel->CheckLevelRedirect(); + if (check) + Printf("Level IS currently being redirected to '%s'!\n", check->MapName.GetChars()); + else + Printf("Level is currently NOT being redirected!\n"); + } + else + Printf("Level redirection is currently not being tested - not in game!\n"); +} + diff --git a/src/console/c_console.cpp b/src/console/c_console.cpp deleted file mode 100644 index 38cf1a82ad8..00000000000 --- a/src/console/c_console.cpp +++ /dev/null @@ -1,2079 +0,0 @@ -/* -** c_console.cpp -** Implements the console itself -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include - -#include "templates.h" -#include "p_setup.h" -#include "i_system.h" -#include "version.h" -#include "g_game.h" -#include "c_bind.h" -#include "c_console.h" -#include "c_cvars.h" -#include "c_dispatch.h" -#include "hu_stuff.h" -#include "i_system.h" -#include "i_video.h" -#include "g_input.h" -#include "v_palette.h" -#include "v_video.h" -#include "v_text.h" -#include "w_wad.h" -#include "sbar.h" -#include "s_sound.h" -#include "doomstat.h" -#include "d_gui.h" -#include "cmdlib.h" -#include "d_net.h" -#include "d_event.h" -#include "d_player.h" -#include "gstrings.h" -#include "c_consolebuffer.h" -#include "g_levellocals.h" -#include "vm.h" -#include "utf8.h" -#include "s_music.h" - - -#include "gi.h" - -#define LEFTMARGIN 8 -#define RIGHTMARGIN 8 -#define BOTTOMARGIN 12 - -extern bool hud_toggled; -void D_ToggleHud(); - - -CUSTOM_CVAR(Int, con_buffersize, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - // ensure a minimum size - if (self >= 0 && self < 128) self = 128; -} - -FConsoleBuffer *conbuffer; - -static void C_TabComplete (bool goForward); -static bool C_TabCompleteList (); -static bool TabbedLast; // True if last key pressed was tab -static bool TabbedList; // True if tab list was shown -CVAR(Bool, con_notablist, false, CVAR_ARCHIVE) - - -static FTextureID conback; -static uint32_t conshade; -static bool conline; - -extern int gametic; -extern bool automapactive; // in AM_map.c -extern bool advancedemo; - -extern FBaseCVar *CVars; -extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE]; - -unsigned ConCols; -int ConWidth; -bool vidactive = false; -bool cursoron = false; -int ConBottom, ConScroll, RowAdjust; -int CursorTicker; -constate_e ConsoleState = c_up; - - -static int TopLine, InsertLine; - -static void ClearConsole (); - -struct GameAtExit -{ - GameAtExit(FString str) : Command(str) {} - - GameAtExit *Next; - FString Command; -}; - -static GameAtExit *ExitCmdList; - -#define SCROLLUP 1 -#define SCROLLDN 2 -#define SCROLLNO 0 - -EXTERN_CVAR (Bool, show_messages) - -// Buffer for AddToConsole() -static char *work = NULL; -static int worklen = 0; - -CVAR(Float, con_notifytime, 3.f, CVAR_ARCHIVE) -CVAR(Bool, con_centernotify, false, CVAR_ARCHIVE) -CUSTOM_CVAR(Int, con_scaletext, 0, CVAR_ARCHIVE) // Scale notify text at high resolutions? -{ - if (self < 0) self = 0; -} - -CUSTOM_CVAR(Int, con_scale, 0, CVAR_ARCHIVE) -{ - if (self < 0) self = 0; -} - -CUSTOM_CVAR(Float, con_alpha, 0.75f, CVAR_ARCHIVE) -{ - if (self < 0.f) self = 0.f; - if (self > 1.f) self = 1.f; -} - -// Command to run when Ctrl-D is pressed at start of line -CVAR(String, con_ctrl_d, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - - -struct History -{ - struct History *Older; - struct History *Newer; - FString String; -}; - -struct FCommandBuffer -{ -private: - std::u32string Text; - unsigned CursorPos = 0; - unsigned StartPos = 0; // First character to display - unsigned CursorPosCells = 0; - unsigned StartPosCells = 0; - - std::u32string YankBuffer; // Deleted text buffer - -public: - bool AppendToYankBuffer = false; // Append consecutive deletes to buffer - - FCommandBuffer() = default; - - FCommandBuffer(const FCommandBuffer &o) - { - Text = o.Text; - CursorPos = o.CursorPos; - StartPos = o.StartPos; - } - - FString GetText() const - { - FString build; - for (auto chr : Text) build.AppendCharacter(chr); - return build; - } - - size_t TextLength() const - { - return Text.length(); - } - - void Draw(int x, int y, int scale, bool cursor) - { - if (scale == 1) - { - screen->DrawChar(CurrentConsoleFont, CR_ORANGE, x, y, '\x1c', TAG_DONE); - screen->DrawText(CurrentConsoleFont, CR_ORANGE, x + CurrentConsoleFont->GetCharWidth(0x1c), y, - &Text[StartPos], TAG_DONE); - - if (cursor) - { - screen->DrawChar(CurrentConsoleFont, CR_YELLOW, - x + CurrentConsoleFont->GetCharWidth(0x1c) + (CursorPosCells - StartPosCells) * CurrentConsoleFont->GetCharWidth(0xb), - y, '\xb', TAG_DONE); - } - } - else - { - screen->DrawChar(CurrentConsoleFont, CR_ORANGE, x, y, '\x1c', - DTA_VirtualWidth, screen->GetWidth() / scale, - DTA_VirtualHeight, screen->GetHeight() / scale, - DTA_KeepRatio, true, TAG_DONE); - - screen->DrawText(CurrentConsoleFont, CR_ORANGE, x + CurrentConsoleFont->GetCharWidth(0x1c), y, - &Text[StartPos], - DTA_VirtualWidth, screen->GetWidth() / scale, - DTA_VirtualHeight, screen->GetHeight() / scale, - DTA_KeepRatio, true, TAG_DONE); - - if (cursor) - { - screen->DrawChar(CurrentConsoleFont, CR_YELLOW, - x + CurrentConsoleFont->GetCharWidth(0x1c) + (CursorPosCells - StartPosCells) * CurrentConsoleFont->GetCharWidth(0xb), - y, '\xb', - DTA_VirtualWidth, screen->GetWidth() / scale, - DTA_VirtualHeight, screen->GetHeight() / scale, - DTA_KeepRatio, true, TAG_DONE); - } - } - } - - unsigned CalcCellSize(unsigned length) - { - unsigned cellcount = 0; - for (unsigned i = 0; i < length; i++) - { - int w; - NewConsoleFont->GetChar(Text[i], CR_UNTRANSLATED, &w); - cellcount += w / 9; - } - return cellcount; - - } - - unsigned CharsForCells(unsigned cellin, bool *overflow) - { - unsigned chars = 0; - int cells = cellin; - while (cells > 0) - { - int w; - NewConsoleFont->GetChar(Text[chars++], CR_UNTRANSLATED, &w); - cells -= w / 9; - } - *overflow = (cells < 0); - return chars; - } - - - void MakeStartPosGood() - { - // Make sure both values point to something valid. - if (CursorPos > Text.length()) CursorPos = (unsigned)Text.length(); - if (StartPos > Text.length()) StartPos = (unsigned)Text.length(); - - CursorPosCells = CalcCellSize(CursorPos); - StartPosCells = CalcCellSize(StartPos); - unsigned LengthCells = CalcCellSize((unsigned)Text.length()); - - int n = StartPosCells; - unsigned cols = ConCols / active_con_scale(); - - if (StartPosCells >= LengthCells) - { // Start of visible line is beyond end of line - n = CursorPosCells - cols + 2; - } - if ((CursorPosCells - StartPosCells) >= cols - 2) - { // The cursor is beyond the visible part of the line - n = CursorPosCells - cols + 2; - } - if (StartPosCells > CursorPosCells) - { // The cursor is in front of the visible part of the line - n = CursorPosCells; - } - StartPosCells = MAX(0, n); - bool overflow; - StartPos = CharsForCells(StartPosCells, &overflow); - if (overflow) - { - // We ended up in the middle of a double cell character, so set the start to the following character. - StartPosCells++; - StartPos = CharsForCells(StartPosCells, &overflow); - } - } - - void CursorStart() - { - CursorPos = 0; - StartPos = 0; - CursorPosCells = 0; - StartPosCells = 0; - } - - void CursorEnd() - { - CursorPos = (unsigned)Text.length(); - MakeStartPosGood(); - } - -private: - void MoveCursorLeft() - { - CursorPos--; - } - - void MoveCursorRight() - { - CursorPos++; - } - -public: - void CursorLeft() - { - if (CursorPos > 0) - { - MoveCursorLeft(); - MakeStartPosGood(); - } - } - - void CursorRight() - { - if (CursorPos < Text.length()) - { - MoveCursorRight(); - MakeStartPosGood(); - } - } - - void CursorWordLeft() - { - if (CursorPos > 0) - { - do MoveCursorLeft(); - while (CursorPos > 0 && Text[CursorPos - 1] != ' '); - MakeStartPosGood(); - } - } - - void CursorWordRight() - { - if (CursorPos < Text.length()) - { - do MoveCursorRight(); - while (CursorPos < Text.length() && Text[CursorPos] != ' '); - MakeStartPosGood(); - } - } - - void DeleteLeft() - { - if (CursorPos > 0) - { - MoveCursorLeft(); - Text.erase(CursorPos, 1); - MakeStartPosGood(); - } - } - - void DeleteRight() - { - if (CursorPos < Text.length()) - { - Text.erase(CursorPos, 1); - MakeStartPosGood(); - } - } - - void DeleteWordLeft() - { - if (CursorPos > 0) - { - auto now = CursorPos; - - CursorWordLeft(); - - if (AppendToYankBuffer) { - YankBuffer = Text.substr(CursorPos, now - CursorPos) + YankBuffer; - } else { - YankBuffer = Text.substr(CursorPos, now - CursorPos); - } - Text.erase(CursorPos, now - CursorPos); - MakeStartPosGood(); - } - } - - void DeleteLineLeft() - { - if (CursorPos > 0) - { - if (AppendToYankBuffer) { - YankBuffer = Text.substr(0, CursorPos) + YankBuffer; - } else { - YankBuffer = Text.substr(0, CursorPos); - } - Text.erase(0, CursorPos); - CursorStart(); - } - } - - void DeleteLineRight() - { - if (CursorPos < Text.length()) - { - if (AppendToYankBuffer) { - YankBuffer += Text.substr(CursorPos, Text.length() - CursorPos); - } else { - YankBuffer = Text.substr(CursorPos, Text.length() - CursorPos); - } - Text.resize(CursorPos); - CursorEnd(); - } - } - - void AddChar(int character) - { - if (Text.length() == 0) - { - Text += character; - } - else - { - Text.insert(CursorPos, 1, character); - } - CursorPos++; - MakeStartPosGood(); - } - - void AddString(FString clip) - { - if (clip.IsNotEmpty()) - { - // Only paste the first line. - long brk = clip.IndexOfAny("\r\n\b"); - std::u32string build; - if (brk >= 0) - { - clip.Truncate(brk); - } - auto strp = (const uint8_t*)clip.GetChars(); - while (auto chr = GetCharFromString(strp)) build += chr; - - if (Text.length() == 0) - { - Text = build; - } - else - { - Text.insert(CursorPos, build); - } - CursorPos += (unsigned)build.length(); - MakeStartPosGood(); - } - } - - void SetString(const FString &str) - { - Text.clear(); - auto strp = (const uint8_t*)str.GetChars(); - while (auto chr = GetCharFromString(strp)) Text += chr; - - CursorEnd(); - MakeStartPosGood(); - } - - void AddYankBuffer() - { - if (YankBuffer.length() > 0) - { - if (Text.length() == 0) - { - Text = YankBuffer; - } - else - { - Text.insert(CursorPos, YankBuffer); - } - CursorPos += (unsigned)YankBuffer.length(); - MakeStartPosGood(); - } - } -}; -static FCommandBuffer CmdLine; - -#define MAXHISTSIZE 50 -static struct History *HistHead = NULL, *HistTail = NULL, *HistPos = NULL; -static int HistSize; - -#define NUMNOTIFIES 4 -#define NOTIFYFADETIME 6 - -struct FNotifyText -{ - int TimeOut; - int PrintLevel; - FString Text; -}; - -struct FNotifyBuffer -{ -public: - FNotifyBuffer(); - void AddString(int printlevel, FString source); - void Shift(int maxlines); - void Clear() { Text.Clear(); } - void Tick(); - void Draw(); - -private: - TArray Text; - int Top; - int TopGoal; - enum { NEWLINE, APPENDLINE, REPLACELINE } AddType; -}; -static FNotifyBuffer NotifyStrings; - -CUSTOM_CVAR(Int, con_notifylines, NUMNOTIFIES, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) -{ - NotifyStrings.Shift(self); -} - - -int PrintColors[PRINTLEVELS+2] = { CR_RED, CR_GOLD, CR_GRAY, CR_GREEN, CR_GREEN, CR_GOLD }; - -static void setmsgcolor (int index, int color); - -FILE *Logfile = NULL; - - -FIntCVar msglevel ("msg", 0, CVAR_ARCHIVE); - -CUSTOM_CVAR (Int, msg0color, 6, CVAR_ARCHIVE) -{ - setmsgcolor (0, self); -} - -CUSTOM_CVAR (Int, msg1color, 5, CVAR_ARCHIVE) -{ - setmsgcolor (1, self); -} - -CUSTOM_CVAR (Int, msg2color, 2, CVAR_ARCHIVE) -{ - setmsgcolor (2, self); -} - -CUSTOM_CVAR (Int, msg3color, 3, CVAR_ARCHIVE) -{ - setmsgcolor (3, self); -} - -CUSTOM_CVAR (Int, msg4color, 3, CVAR_ARCHIVE) -{ - setmsgcolor (4, self); -} - -CUSTOM_CVAR (Int, msgmidcolor, 5, CVAR_ARCHIVE) -{ - setmsgcolor (PRINTLEVELS, self); -} - -CUSTOM_CVAR (Int, msgmidcolor2, 4, CVAR_ARCHIVE) -{ - setmsgcolor (PRINTLEVELS+1, self); -} - -void C_InitConback() -{ - conback = TexMan.CheckForTexture ("CONBACK", ETextureType::MiscPatch); - - if (!conback.isValid()) - { - conback = TexMan.GetTextureID (gameinfo.TitlePage, ETextureType::MiscPatch); - conshade = MAKEARGB(175,0,0,0); - conline = true; - } - else - { - conshade = 0; - conline = false; - } -} - -void C_InitConsole (int width, int height, bool ingame) -{ - int cwidth, cheight; - - vidactive = ingame; - if (CurrentConsoleFont != NULL) - { - cwidth = CurrentConsoleFont->GetCharWidth ('M'); - cheight = CurrentConsoleFont->GetHeight(); - } - else - { - cwidth = cheight = 8; - } - ConWidth = (width - LEFTMARGIN - RIGHTMARGIN); - ConCols = ConWidth / cwidth; - - if (conbuffer == NULL) conbuffer = new FConsoleBuffer; -} - -//========================================================================== -// -// CCMD atexit -// -//========================================================================== - -UNSAFE_CCMD (atexit) -{ - if (argv.argc() == 1) - { - Printf ("Registered atexit commands:\n"); - GameAtExit *record = ExitCmdList; - while (record != NULL) - { - Printf ("%s\n", record->Command.GetChars()); - record = record->Next; - } - return; - } - for (int i = 1; i < argv.argc(); ++i) - { - GameAtExit *record = new GameAtExit(argv[i]); - record->Next = ExitCmdList; - ExitCmdList = record; - } -} - -//========================================================================== -// -// C_DeinitConsole -// -// Executes the contents of the atexit cvar, if any, at quit time. -// Then releases all of the console's memory. -// -//========================================================================== - -void C_DeinitConsole () -{ - GameAtExit *cmd = ExitCmdList; - - while (cmd != NULL) - { - GameAtExit *next = cmd->Next; - AddCommandString (cmd->Command); - delete cmd; - cmd = next; - } - - // Free command history - History *hist = HistTail; - - while (hist != NULL) - { - History *next = hist->Newer; - delete hist; - hist = next; - } - HistTail = HistHead = HistPos = NULL; - - // Free cvars allocated at runtime - FBaseCVar *var, *next, **nextp; - for (var = CVars, nextp = &CVars; var != NULL; var = next) - { - next = var->m_Next; - if (var->GetFlags() & CVAR_UNSETTABLE) - { - delete var; - *nextp = next; - } - else - { - nextp = &var->m_Next; - } - } - - // Free alias commands. (i.e. The "commands" that can be allocated - // at runtime.) - for (size_t i = 0; i < countof(Commands); ++i) - { - FConsoleCommand *cmd = Commands[i]; - - while (cmd != NULL) - { - FConsoleCommand *next = cmd->m_Next; - if (cmd->IsAlias()) - { - delete cmd; - } - cmd = next; - } - } - - // Make sure all tab commands are cleared before the memory for - // their names is deallocated. - C_ClearTabCommands (); - - // Free AddToConsole()'s work buffer - if (work != NULL) - { - free (work); - work = NULL; - worklen = 0; - } - - if (conbuffer != NULL) - { - delete conbuffer; - conbuffer = NULL; - } -} - -static void ClearConsole () -{ - if (conbuffer != NULL) - { - conbuffer->Clear(); - } - TopLine = InsertLine = 0; -} - -static void setmsgcolor (int index, int color) -{ - if ((unsigned)color >= (unsigned)NUM_TEXT_COLORS) - color = 0; - PrintColors[index] = color; -} - -extern int DisplayWidth; - -FNotifyBuffer::FNotifyBuffer() -{ - Top = TopGoal = 0; - AddType = NEWLINE; -} - -void FNotifyBuffer::Shift(int maxlines) -{ - if (maxlines >= 0 && Text.Size() > (unsigned)maxlines) - { - Text.Delete(0, Text.Size() - maxlines); - } -} - -void FNotifyBuffer::AddString(int printlevel, FString source) -{ - TArray lines; - int width; - - if ((printlevel != 128 && !show_messages) || - source.IsEmpty() || - gamestate == GS_FULLCONSOLE || - gamestate == GS_DEMOSCREEN || - con_notifylines == 0) - return; - - // [MK] allow the status bar to take over notify printing - if (StatusBar != nullptr) - { - IFVIRTUALPTR(StatusBar, DBaseStatusBar, ProcessNotify) - { - VMValue params[] = { (DObject*)StatusBar, printlevel, &source }; - int rv; - VMReturn ret(&rv); - VMCall(func, params, countof(params), &ret, 1); - if (!!rv) return; - } - } - - width = DisplayWidth / active_con_scaletext(generic_ui); - - FFont *font = generic_ui ? NewSmallFont : AlternativeSmallFont; - if (font == nullptr) return; // Without an initialized font we cannot handle the message (this is for those which come here before the font system is ready.) - - if (AddType == APPENDLINE && Text.Size() > 0 && Text[Text.Size() - 1].PrintLevel == printlevel) - { - FString str = Text[Text.Size() - 1].Text + source; - lines = V_BreakLines (font, width, str); - } - else - { - lines = V_BreakLines (font, width, source); - if (AddType == APPENDLINE) - { - AddType = NEWLINE; - } - } - - if (lines.Size() == 0) - return; - - for (auto &line : lines) - { - FNotifyText newline; - - newline.Text = line.Text; - newline.TimeOut = gametic + int(con_notifytime * TICRATE); - newline.PrintLevel = printlevel; - if (AddType == NEWLINE || Text.Size() == 0) - { - if (con_notifylines > 0) - { - Shift(con_notifylines - 1); - } - Text.Push(newline); - } - else - { - Text[Text.Size() - 1] = newline; - } - AddType = NEWLINE; - } - - switch (source[source.Len()-1]) - { - case '\r': AddType = REPLACELINE; break; - case '\n': AddType = NEWLINE; break; - default: AddType = APPENDLINE; break; - } - - TopGoal = 0; -} - -void AddToConsole (int printlevel, const char *text) -{ - conbuffer->AddText(printlevel, MakeUTF8(text)); -} - -//========================================================================== -// -// -// -//========================================================================== - -void WriteLineToLog(FILE *LogFile, const char *outline) -{ - // Strip out any color escape sequences before writing to the log file - TArray copy(strlen(outline) + 1); - const char * srcp = outline; - char * dstp = copy.Data(); - - while (*srcp != 0) - { - - if (*srcp != TEXTCOLOR_ESCAPE) - { - *dstp++ = *srcp++; - } - else if (srcp[1] == '[') - { - srcp += 2; - while (*srcp != ']' && *srcp != 0) srcp++; - if (*srcp == ']') srcp++; - } - else - { - if (srcp[1] != 0) srcp += 2; - else break; - } - } - *dstp = 0; - - fputs(copy.Data(), LogFile); - fflush(LogFile); -} - - -int PrintString (int iprintlevel, const char *outline) -{ - int printlevel = iprintlevel & PRINT_TYPES; - if (printlevel < msglevel || *outline == '\0') - { - return 0; - } - if (printlevel != PRINT_LOG || Logfile != nullptr) - { - // Convert everything coming through here to UTF-8 so that all console text is in a consistent format - int count; - outline = MakeUTF8(outline, &count); - - if (printlevel != PRINT_LOG) - { - I_PrintStr(outline); - - conbuffer->AddText(printlevel, outline); - if (vidactive && screen && !(iprintlevel & PRINT_NONOTIFY)) - { - NotifyStrings.AddString(printlevel, outline); - } - } - if (Logfile != nullptr && !(iprintlevel & PRINT_NOLOG)) - { - WriteLineToLog(Logfile, outline); - } - return count; - } - return 0; // Don't waste time on calculating this if nothing at all was printed... -} - -bool gameisdead; - -int VPrintf (int printlevel, const char *format, va_list parms) -{ - if (gameisdead) - return 0; - - FString outline; - outline.VFormat (format, parms); - return PrintString (printlevel, outline.GetChars()); -} - -int Printf (int printlevel, const char *format, ...) -{ - va_list argptr; - int count; - - va_start (argptr, format); - count = VPrintf (printlevel, format, argptr); - va_end (argptr); - - return count; -} - -int Printf (const char *format, ...) -{ - va_list argptr; - int count; - - va_start (argptr, format); - count = VPrintf (PRINT_HIGH, format, argptr); - va_end (argptr); - - return count; -} - -int DPrintf (int level, const char *format, ...) -{ - va_list argptr; - int count; - - if (developer >= level) - { - va_start (argptr, format); - count = VPrintf (PRINT_HIGH, format, argptr); - va_end (argptr); - return count; - } - else - { - return 0; - } -} - -void C_FlushDisplay () -{ - NotifyStrings.Clear(); - if (StatusBar == nullptr) return; - IFVIRTUALPTR(StatusBar, DBaseStatusBar, FlushNotify) - { - VMValue params[] = { (DObject*)StatusBar }; - VMCall(func, params, countof(params), nullptr, 1); - } -} - -void C_AdjustBottom () -{ - if (gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) - ConBottom = SCREENHEIGHT; - else if (ConBottom > SCREENHEIGHT / 2 || ConsoleState == c_down) - ConBottom = SCREENHEIGHT / 2; -} - -void C_NewModeAdjust () -{ - C_InitConsole (SCREENWIDTH, SCREENHEIGHT, true); - C_FlushDisplay (); - C_AdjustBottom (); -} - -int consoletic = 0; -void C_Ticker() -{ - static int lasttic = 0; - consoletic++; - - if (lasttic == 0) - lasttic = consoletic - 1; - - if (con_buffersize > 0) - { - conbuffer->ResizeBuffer(con_buffersize); - } - - if (ConsoleState != c_up) - { - if (ConsoleState == c_falling) - { - ConBottom += (consoletic - lasttic) * (SCREENHEIGHT * 2 / 25); - if (ConBottom >= SCREENHEIGHT / 2) - { - ConBottom = SCREENHEIGHT / 2; - ConsoleState = c_down; - } - } - else if (ConsoleState == c_rising) - { - ConBottom -= (consoletic - lasttic) * (SCREENHEIGHT * 2 / 25); - if (ConBottom <= 0) - { - ConsoleState = c_up; - ConBottom = 0; - } - } - } - - if (--CursorTicker <= 0) - { - cursoron ^= 1; - CursorTicker = C_BLINKRATE; - } - - lasttic = consoletic; - NotifyStrings.Tick(); -} - -void FNotifyBuffer::Tick() -{ - if (TopGoal > Top) - { - Top++; - } - else if (TopGoal < Top) - { - Top--; - } - - // Remove lines from the beginning that have expired. - unsigned i; - for (i = 0; i < Text.Size(); ++i) - { - if (Text[i].TimeOut != 0 && Text[i].TimeOut > gametic) - break; - } - if (i > 0) - { - Text.Delete(0, i); - } -} - -void FNotifyBuffer::Draw() -{ - bool center = (con_centernotify != 0.f); - int line, lineadv, color, j; - bool canskip; - - if (gamestate == GS_FULLCONSOLE || gamestate == GS_DEMOSCREEN/* || menuactive != MENU_Off*/) - return; - - FFont* font = generic_ui ? NewSmallFont : AlternativeSmallFont; - - line = Top + font->GetDisplacement(); - canskip = true; - - lineadv = font->GetHeight (); - - for (unsigned i = 0; i < Text.Size(); ++ i) - { - FNotifyText ¬ify = Text[i]; - - if (notify.TimeOut == 0) - continue; - - j = notify.TimeOut - gametic; - if (j > 0) - { - if (!show_messages && notify.PrintLevel != 128) - continue; - - double alpha = (j < NOTIFYFADETIME) ? 1. * j / NOTIFYFADETIME : 1; - - if (notify.PrintLevel >= PRINTLEVELS) - color = CR_UNTRANSLATED; - else - color = PrintColors[notify.PrintLevel]; - - int scale = active_con_scaletext(generic_ui); - if (!center) - screen->DrawText (font, color, 0, line, notify.Text, - DTA_VirtualWidth, screen->GetWidth() / scale, - DTA_VirtualHeight, screen->GetHeight() / scale, - DTA_KeepRatio, true, - DTA_Alpha, alpha, TAG_DONE); - else - screen->DrawText (font, color, (screen->GetWidth() - - font->StringWidth (notify.Text) * scale) / 2 / scale, - line, notify.Text, - DTA_VirtualWidth, screen->GetWidth() / scale, - DTA_VirtualHeight, screen->GetHeight() / scale, - DTA_KeepRatio, true, - DTA_Alpha, alpha, TAG_DONE); - line += lineadv; - canskip = false; - } - else - { - if (canskip) - { - Top += lineadv; - line += lineadv; - } - notify.TimeOut = 0; - } - } - if (canskip) - { - Top = TopGoal; - } -} - -void C_DrawConsole () -{ - static int oldbottom = 0; - int lines, left, offset; - - int textScale = active_con_scale(); - - left = LEFTMARGIN; - lines = (ConBottom/textScale-CurrentConsoleFont->GetHeight()*2)/CurrentConsoleFont->GetHeight(); - if (-CurrentConsoleFont->GetHeight() + lines*CurrentConsoleFont->GetHeight() > ConBottom/textScale - CurrentConsoleFont->GetHeight()*7/2) - { - offset = -CurrentConsoleFont->GetHeight()/2; - lines--; - } - else - { - offset = -CurrentConsoleFont->GetHeight(); - } - - oldbottom = ConBottom; - - if (ConsoleState == c_up) - { - NotifyStrings.Draw(); - return; - } - else if (ConBottom) - { - int visheight; - FTexture *conpic = TexMan.GetTexture(conback); - - visheight = ConBottom; - - screen->DrawTexture (conpic, 0, visheight - screen->GetHeight(), - DTA_DestWidth, screen->GetWidth(), - DTA_DestHeight, screen->GetHeight(), - DTA_ColorOverlay, conshade, - DTA_Alpha, (gamestate != GS_FULLCONSOLE) ? (double)con_alpha : 1., - DTA_Masked, false, - TAG_DONE); - if (conline && visheight < screen->GetHeight()) - { - screen->Clear (0, visheight, screen->GetWidth(), visheight+1, 0, 0); - } - - if (ConBottom >= 12) - { - if (textScale == 1) - screen->DrawText (CurrentConsoleFont, CR_ORANGE, SCREENWIDTH - 8 - - CurrentConsoleFont->StringWidth (GetVersionString()), - ConBottom / textScale - CurrentConsoleFont->GetHeight() - 4, - GetVersionString(), TAG_DONE); - else - screen->DrawText(CurrentConsoleFont, CR_ORANGE, SCREENWIDTH / textScale - 8 - - CurrentConsoleFont->StringWidth(GetVersionString()), - ConBottom / textScale - CurrentConsoleFont->GetHeight() - 4, - GetVersionString(), - DTA_VirtualWidth, screen->GetWidth() / textScale, - DTA_VirtualHeight, screen->GetHeight() / textScale, - DTA_KeepRatio, true, TAG_DONE); - - } - - } - - if (menuactive != MENU_Off) - { - return; - } - - if (lines > 0) - { - // No more enqueuing because adding new text to the console won't touch the actual print data. - conbuffer->FormatText(CurrentConsoleFont, ConWidth / textScale); - unsigned int consolelines = conbuffer->GetFormattedLineCount(); - FBrokenLines *blines = conbuffer->GetLines(); - FBrokenLines *printline = blines + consolelines - 1 - RowAdjust; - - int bottomline = ConBottom / textScale - CurrentConsoleFont->GetHeight()*2 - 4; - - for(FBrokenLines *p = printline; p >= blines && lines > 0; p--, lines--) - { - if (textScale == 1) - { - screen->DrawText(CurrentConsoleFont, CR_TAN, LEFTMARGIN, offset + lines * CurrentConsoleFont->GetHeight(), p->Text, TAG_DONE); - } - else - { - screen->DrawText(CurrentConsoleFont, CR_TAN, LEFTMARGIN, offset + lines * CurrentConsoleFont->GetHeight(), p->Text, - DTA_VirtualWidth, screen->GetWidth() / textScale, - DTA_VirtualHeight, screen->GetHeight() / textScale, - DTA_KeepRatio, true, TAG_DONE); - } - } - - if (ConBottom >= 20) - { - if (gamestate != GS_STARTUP) - { - CmdLine.Draw(left, bottomline, textScale, cursoron); - } - if (RowAdjust && ConBottom >= CurrentConsoleFont->GetHeight()*7/2) - { - // Indicate that the view has been scrolled up (10) - // and if we can scroll no further (12) - if (textScale == 1) - screen->DrawChar (CurrentConsoleFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, TAG_DONE); - else - screen->DrawChar(CurrentConsoleFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, - DTA_VirtualWidth, screen->GetWidth() / textScale, - DTA_VirtualHeight, screen->GetHeight() / textScale, - DTA_KeepRatio, true, TAG_DONE); - } - } - } -} - -void C_FullConsole () -{ - if (hud_toggled) - D_ToggleHud(); - if (demoplayback) - G_CheckDemoStatus (); - D_QuitNetGame (); - advancedemo = false; - ConsoleState = c_down; - HistPos = NULL; - TabbedLast = false; - TabbedList = false; - if (gamestate != GS_STARTUP) - { - gamestate = GS_FULLCONSOLE; - primaryLevel->Music = ""; - S_Start (); - S_StartMusic(); - P_FreeLevelData (); - } - else - { - C_AdjustBottom (); - } -} - -void C_ToggleConsole () -{ - if (gamestate == GS_DEMOSCREEN || demoplayback) - { - gameaction = ga_fullconsole; - } - else if (!chatmodeon && (ConsoleState == c_up || ConsoleState == c_rising) && menuactive == MENU_Off) - { - ConsoleState = c_falling; - HistPos = NULL; - TabbedLast = false; - TabbedList = false; - if (hud_toggled) - D_ToggleHud(); - } - else if (gamestate != GS_FULLCONSOLE && gamestate != GS_STARTUP) - { - ConsoleState = c_rising; - C_FlushDisplay (); - } -} - -void C_HideConsole () -{ - if (gamestate != GS_FULLCONSOLE) - { - ConsoleState = c_up; - ConBottom = 0; - HistPos = NULL; - } -} - -DEFINE_ACTION_FUNCTION(_Console, HideConsole) -{ - C_HideConsole(); - return 0; -} - -DEFINE_ACTION_FUNCTION(_Console, Printf) -{ - PARAM_PROLOGUE; - PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array - - FString s = FStringFormat(VM_ARGS_NAMES); - Printf("%s\n", s.GetChars()); - return 0; -} - -static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) -{ - int data1 = ev->data1; - bool keepappending = false; - - switch (ev->subtype) - { - default: - return false; - - case EV_GUI_Char: - if (ev->data2) - { - // Bash-style shortcuts - if (data1 == 'b') - { - buffer.CursorWordLeft(); - break; - } - else if (data1 == 'f') - { - buffer.CursorWordRight(); - break; - } - } - // Add keypress to command line - buffer.AddChar(data1); - HistPos = NULL; - TabbedLast = false; - TabbedList = false; - break; - - case EV_GUI_WheelUp: - case EV_GUI_WheelDown: - if (!(ev->data3 & GKM_SHIFT)) - { - data1 = GK_PGDN + EV_GUI_WheelDown - ev->subtype; - } - else - { - data1 = GK_DOWN + EV_GUI_WheelDown - ev->subtype; - } - // Intentional fallthrough - - case EV_GUI_KeyDown: - case EV_GUI_KeyRepeat: - switch (data1) - { - case '\t': - // Try to do tab-completion - C_TabComplete ((ev->data3 & GKM_SHIFT) ? false : true); - break; - - case GK_PGUP: - if (ev->data3 & (GKM_SHIFT|GKM_CTRL)) - { // Scroll console buffer up one page - RowAdjust += (SCREENHEIGHT-4)/active_con_scale() / - ((gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) ? CurrentConsoleFont->GetHeight() : CurrentConsoleFont->GetHeight()*2) - 3; - } - else if (RowAdjust < conbuffer->GetFormattedLineCount()) - { // Scroll console buffer up - if (ev->subtype == EV_GUI_WheelUp) - { - RowAdjust += 3; - } - else - { - RowAdjust++; - } - if (RowAdjust > conbuffer->GetFormattedLineCount()) - { - RowAdjust = conbuffer->GetFormattedLineCount(); - } - } - break; - - case GK_PGDN: - if (ev->data3 & (GKM_SHIFT|GKM_CTRL)) - { // Scroll console buffer down one page - const int scrollamt = (SCREENHEIGHT-4)/active_con_scale() / - ((gamestate == GS_FULLCONSOLE || gamestate == GS_STARTUP) ? CurrentConsoleFont->GetHeight() : CurrentConsoleFont->GetHeight()*2) - 3; - if (RowAdjust < scrollamt) - { - RowAdjust = 0; - } - else - { - RowAdjust -= scrollamt; - } - } - else if (RowAdjust > 0) - { // Scroll console buffer down - if (ev->subtype == EV_GUI_WheelDown) - { - RowAdjust = MAX (0, RowAdjust - 3); - } - else - { - RowAdjust--; - } - } - break; - - case GK_HOME: - if (ev->data3 & GKM_CTRL) - { // Move to top of console buffer - RowAdjust = conbuffer->GetFormattedLineCount(); - } - else - { // Move cursor to start of line - buffer.CursorStart(); - } - break; - - case GK_END: - if (ev->data3 & GKM_CTRL) - { // Move to bottom of console buffer - RowAdjust = 0; - } - else - { // Move cursor to end of line - buffer.CursorEnd(); - } - break; - - case GK_LEFT: - // Move cursor left one character - buffer.CursorLeft(); - break; - - case GK_RIGHT: - // Move cursor right one character - buffer.CursorRight(); - break; - - case '\b': - // Erase character to left of cursor - buffer.DeleteLeft(); - TabbedLast = false; - TabbedList = false; - break; - - case GK_DEL: - // Erase character under cursor - buffer.DeleteRight(); - TabbedLast = false; - TabbedList = false; - break; - - case GK_UP: - // Move to previous entry in the command history - if (HistPos == NULL) - { - HistPos = HistHead; - } - else if (HistPos->Older) - { - HistPos = HistPos->Older; - } - - if (HistPos) - { - buffer.SetString(HistPos->String); - } - - TabbedLast = false; - TabbedList = false; - break; - - case GK_DOWN: - // Move to next entry in the command history - if (HistPos && HistPos->Newer) - { - HistPos = HistPos->Newer; - buffer.SetString(HistPos->String); - } - else - { - HistPos = NULL; - buffer.SetString(""); - } - TabbedLast = false; - TabbedList = false; - break; - - case 'X': - if (ev->data3 & GKM_CTRL) - { - buffer.SetString(""); - TabbedLast = TabbedList = false; - } - break; - - case 'D': - if (ev->data3 & GKM_CTRL && buffer.TextLength() == 0) - { // Control-D pressed on an empty line - if (strlen(con_ctrl_d) == 0) - { - break; // Replacement is empty, so do nothing - } - buffer.SetString(*con_ctrl_d); - } - else - { - break; - } - // Intentional fall-through for command(s) added with Ctrl-D - - case '\r': - { - // Execute command line (ENTER) - FString bufferText = buffer.GetText(); - - bufferText.StripLeftRight(); - Printf(127, TEXTCOLOR_WHITE "]%s\n", bufferText.GetChars()); - - if (bufferText.Len() == 0) - { - // Command line is empty, so do nothing to the history - } - else if (HistHead && HistHead->String.CompareNoCase(bufferText) == 0) - { - // Command line was the same as the previous one, - // so leave the history list alone - } - else - { - // Command line is different from last command line, - // or there is nothing in the history list, - // so add it to the history list. - - History *temp = new History; - temp->String = bufferText; - temp->Older = HistHead; - if (HistHead) - { - HistHead->Newer = temp; - } - temp->Newer = NULL; - HistHead = temp; - - if (!HistTail) - { - HistTail = temp; - } - - if (HistSize == MAXHISTSIZE) - { - HistTail = HistTail->Newer; - delete HistTail->Older; - HistTail->Older = NULL; - } - else - { - HistSize++; - } - } - HistPos = NULL; - buffer.SetString(""); - AddCommandString(bufferText); - TabbedLast = false; - TabbedList = false; - break; - } - - case '`': - // Check to see if we have ` bound to the console before accepting - // it as a way to close the console. - if (Bindings.GetBinding(KEY_GRAVE).CompareNoCase("toggleconsole")) - { - break; - } - case GK_ESCAPE: - // Close console and clear command line. But if we're in the - // fullscreen console mode, there's nothing to fall back on - // if it's closed, so open the main menu instead. - if (gamestate == GS_STARTUP) - { - return false; - } - else if (gamestate == GS_FULLCONSOLE) - { - C_DoCommand ("menu_main"); - } - else - { - buffer.SetString(""); - HistPos = NULL; - C_ToggleConsole (); - } - break; - - case 'C': - case 'V': - TabbedLast = false; - TabbedList = false; -#ifdef __APPLE__ - if (ev->data3 & GKM_META) -#else // !__APPLE__ - if (ev->data3 & GKM_CTRL) -#endif // __APPLE__ - { - if (data1 == 'C') - { // copy to clipboard - if (buffer.TextLength() > 0) - { - I_PutInClipboard(buffer.GetText()); - } - } - else - { // paste from clipboard - buffer.AddString(I_GetFromClipboard(false)); - HistPos = NULL; - } - break; - } - break; - - // Bash-style shortcuts - case 'A': - if (ev->data3 & GKM_CTRL) - { - buffer.CursorStart(); - } - break; - case 'E': - if (ev->data3 & GKM_CTRL) - { - buffer.CursorEnd(); - } - break; - case 'W': - if (ev->data3 & GKM_CTRL) - { - buffer.DeleteWordLeft(); - keepappending = true; - TabbedLast = false; - TabbedList = false; - } - break; - case 'U': - if (ev->data3 & GKM_CTRL) - { - buffer.DeleteLineLeft(); - keepappending = true; - TabbedLast = false; - TabbedList = false; - } - break; - case 'K': - if (ev->data3 & GKM_CTRL) - { - buffer.DeleteLineRight(); - keepappending = true; - TabbedLast = false; - TabbedList = false; - } - break; - case 'Y': - if (ev->data3 & GKM_CTRL) - { - buffer.AddYankBuffer(); - TabbedLast = false; - TabbedList = false; - HistPos = NULL; - } - break; - } - break; - -#ifdef __unix__ - case EV_GUI_MButtonDown: - buffer.AddString(I_GetFromClipboard(true)); - HistPos = NULL; - break; -#endif - } - - buffer.AppendToYankBuffer = keepappending; - - // Ensure that the cursor is always visible while typing - CursorTicker = C_BLINKRATE; - cursoron = 1; - return true; -} - -bool C_Responder (event_t *ev) -{ - if (ev->type != EV_GUI_Event || - ConsoleState == c_up || - ConsoleState == c_rising || - menuactive != MENU_Off) - { - return false; - } - - return C_HandleKey(ev, CmdLine); -} - -CCMD (history) -{ - struct History *hist = HistTail; - - while (hist) - { - Printf (" %s\n", hist->String.GetChars()); - hist = hist->Newer; - } -} - -CCMD (clear) -{ - C_FlushDisplay (); - ClearConsole (); -} - -CCMD (echo) -{ - int last = argv.argc()-1; - for (int i = 1; i <= last; ++i) - { - FString formatted = strbin1 (argv[i]); - Printf ("%s%s", formatted.GetChars(), i!=last ? " " : "\n"); - } -} - -/* Printing in the middle of the screen */ - -CVAR(Float, con_midtime, 3.f, CVAR_ARCHIVE) - -const char *console_bar = "----------------------------------------"; - -void C_MidPrint (FFont *font, const char *msg, bool bold) -{ - if (StatusBar == nullptr || screen == nullptr) - return; - - // [MK] allow the status bar to take over MidPrint - IFVIRTUALPTR(StatusBar, DBaseStatusBar, ProcessMidPrint) - { - FString msgstr = msg; - VMValue params[] = { (DObject*)StatusBar, font, &msgstr, bold }; - int rv; - VMReturn ret(&rv); - VMCall(func, params, countof(params), &ret, 1); - if (!!rv) return; - } - - if (msg != nullptr) - { - auto color = (EColorRange)PrintColors[bold? PRINTLEVELS+1 : PRINTLEVELS]; - Printf(PRINT_HIGH|PRINT_NONOTIFY, TEXTCOLOR_ESCAPESTR "%c%s\n%s\n%s\n", color, console_bar, msg, console_bar); - - StatusBar->AttachMessage (Create(font, msg, 1.5f, 0.375f, 0, 0, color, con_midtime), MAKE_ID('C','N','T','R')); - } - else - { - StatusBar->DetachMessage (MAKE_ID('C','N','T','R')); - } -} - -DEFINE_ACTION_FUNCTION(_Console, MidPrint) -{ - PARAM_PROLOGUE; - PARAM_POINTER(fnt, FFont); - PARAM_STRING(text); - PARAM_BOOL(bold); - - const char *txt = text[0] == '$'? GStrings(&text[1]) : text.GetChars(); - C_MidPrint(fnt, txt, bold); - return 0; -} - -/****** Tab completion code ******/ - -struct TabData -{ - int UseCount; - FName TabName; - - TabData() - : UseCount(0), TabName(NAME_None) - { - } - - TabData(const char *name) - : UseCount(1), TabName(name) - { - } - - TabData(const TabData &other) = default; -}; - -static TArray TabCommands (TArray::NoInit); -static int TabPos; // Last TabCommand tabbed to -static int TabStart; // First char in CmdLine to use for tab completion -static int TabSize; // Size of tab string - -static bool FindTabCommand (const char *name, int *stoppos, int len) -{ - FName aname(name); - unsigned int i; - int cval = 1; - - for (i = 0; i < TabCommands.Size(); i++) - { - if (TabCommands[i].TabName == aname) - { - *stoppos = i; - return true; - } - cval = strnicmp (TabCommands[i].TabName.GetChars(), name, len); - if (cval >= 0) - break; - } - - *stoppos = i; - - return (cval == 0); -} - -void C_AddTabCommand (const char *name) -{ - int pos; - - if (FindTabCommand (name, &pos, INT_MAX)) - { - TabCommands[pos].UseCount++; - } - else - { - TabData tab(name); - TabCommands.Insert (pos, tab); - } -} - -void C_RemoveTabCommand (const char *name) -{ - if (TabCommands.Size() == 0) - { - // There are no tab commands that can be removed. - // This is important to skip construction of aname - // in case the NameManager has already been destroyed. - return; - } - - FName aname(name, true); - - if (aname == NAME_None) - { - return; - } - for (unsigned int i = 0; i < TabCommands.Size(); ++i) - { - if (TabCommands[i].TabName == aname) - { - if (--TabCommands[i].UseCount == 0) - { - TabCommands.Delete(i); - } - break; - } - } -} - -void C_ClearTabCommands () -{ - TabCommands.Clear(); -} - -static int FindDiffPoint (FName name1, const char *str2) -{ - const char *str1 = name1.GetChars(); - int i; - - for (i = 0; tolower(str1[i]) == tolower(str2[i]); i++) - if (str1[i] == 0 || str2[i] == 0) - break; - - return i; -} - -static void C_TabComplete (bool goForward) -{ - unsigned i; - int diffpoint; - - auto CmdLineText = CmdLine.GetText(); - if (!TabbedLast) - { - bool cancomplete; - - - // Skip any spaces at beginning of command line - for (i = 0; i < CmdLineText.Len(); ++i) - { - if (CmdLineText[i] != ' ') - break; - } - if (i == CmdLineText.Len()) - { // Line was nothing but spaces - return; - } - TabStart = i; - - TabSize = (int)CmdLineText.Len() - TabStart; - - if (!FindTabCommand(&CmdLineText[TabStart], &TabPos, TabSize)) - return; // No initial matches - - // Show a list of possible completions, if more than one. - if (TabbedList || con_notablist) - { - cancomplete = true; - } - else - { - cancomplete = C_TabCompleteList (); - TabbedList = true; - } - - if (goForward) - { // Position just before the list of completions so that when TabPos - // gets advanced below, it will be at the first one. - --TabPos; - } - else - { // Find the last matching tab, then go one past it. - while (++TabPos < (int)TabCommands.Size()) - { - if (FindDiffPoint(TabCommands[TabPos].TabName, &CmdLineText[TabStart]) < TabSize) - { - break; - } - } - } - TabbedLast = true; - if (!cancomplete) - { - return; - } - } - - if ((goForward && ++TabPos == (int)TabCommands.Size()) || - (!goForward && --TabPos < 0)) - { - TabbedLast = false; - CmdLineText.Truncate(TabSize); - } - else - { - diffpoint = FindDiffPoint(TabCommands[TabPos].TabName, &CmdLineText[TabStart]); - - if (diffpoint < TabSize) - { - // No more matches - TabbedLast = false; - CmdLineText.Truncate(TabSize - TabStart); - } - else - { - CmdLineText.Truncate(TabStart); - CmdLineText << TabCommands[TabPos].TabName << ' '; - } - } - CmdLine.SetString(CmdLineText); - CmdLine.MakeStartPosGood(); -} - -static bool C_TabCompleteList () -{ - int nummatches, i; - size_t maxwidth; - int commonsize = INT_MAX; - - nummatches = 0; - maxwidth = 0; - - auto CmdLineText = CmdLine.GetText(); - for (i = TabPos; i < (int)TabCommands.Size(); ++i) - { - if (FindDiffPoint (TabCommands[i].TabName, &CmdLineText[TabStart]) < TabSize) - { - break; - } - else - { - if (i > TabPos) - { - // This keeps track of the longest common prefix for all the possible - // completions, so we can fill in part of the command for the user if - // the longest common prefix is longer than what the user already typed. - int diffpt = FindDiffPoint (TabCommands[i-1].TabName, TabCommands[i].TabName.GetChars()); - if (diffpt < commonsize) - { - commonsize = diffpt; - } - } - nummatches++; - maxwidth = MAX (maxwidth, strlen (TabCommands[i].TabName.GetChars())); - } - } - if (nummatches > 1) - { - size_t x = 0; - maxwidth += 3; - Printf (TEXTCOLOR_BLUE "Completions for %s:\n", CmdLineText.GetChars()); - for (i = TabPos; nummatches > 0; ++i, --nummatches) - { - // [Dusk] Print console commands blue, CVars green, aliases red. - const char* colorcode = ""; - FConsoleCommand* ccmd; - if (FindCVar (TabCommands[i].TabName, NULL)) - colorcode = TEXTCOLOR_GREEN; - else if ((ccmd = FConsoleCommand::FindByName (TabCommands[i].TabName)) != NULL) - { - if (ccmd->IsAlias()) - colorcode = TEXTCOLOR_RED; - else - colorcode = TEXTCOLOR_LIGHTBLUE; - } - - Printf ("%s%-*s", colorcode, int(maxwidth), TabCommands[i].TabName.GetChars()); - x += maxwidth; - if (x > ConCols / active_con_scale() - maxwidth) - { - x = 0; - Printf ("\n"); - } - } - if (x != 0) - { - Printf ("\n"); - } - // Fill in the longest common prefix, if it's longer than what was typed. - if (TabSize != commonsize) - { - TabSize = commonsize; - CmdLineText.Truncate(TabStart); - CmdLineText.AppendCStrPart(TabCommands[TabPos].TabName.GetChars(), commonsize); - CmdLine.SetString(CmdLineText); - } - return false; - } - return true; -} diff --git a/src/console/c_cvars.cpp b/src/console/c_cvars.cpp deleted file mode 100644 index d13e0baa347..00000000000 --- a/src/console/c_cvars.cpp +++ /dev/null @@ -1,1847 +0,0 @@ -/* -** c_cvars.cpp -** Defines all the different console variable types -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include - -#include "cmdlib.h" -#include "configfile.h" -#include "c_console.h" -#include "c_dispatch.h" - -#include "g_game.h" -#include "d_player.h" -#include "v_video.h" -#include "d_netinf.h" -#include "serializer.h" - -#include "menu/menu.h" -#include "vm.h" - -#include "version.h" - -struct FLatchedValue -{ - FBaseCVar *Variable; - UCVarValue Value; - ECVarType Type; - bool UnsafeContext; -}; - -static TArray LatchedValues; - -bool FBaseCVar::m_DoNoSet = false; -bool FBaseCVar::m_UseCallback = false; - -FBaseCVar *CVars = NULL; - -int cvar_defflags; - -FBaseCVar::FBaseCVar (const char *var_name, uint32_t flags, void (*callback)(FBaseCVar &)) -{ - if (var_name != nullptr && (flags & CVAR_SERVERINFO)) - { - // This limitation is imposed by network protocol which uses only 6 bits - // for name's length with terminating null character - static const size_t NAME_LENGHT_MAX = 63; - - if (strlen(var_name) > NAME_LENGHT_MAX) - { - I_FatalError("Name of the server console variable \"%s\" is too long.\n" - "Its length should not exceed %zu characters.\n", var_name, NAME_LENGHT_MAX); - } - } - - FBaseCVar *var; - - var = FindCVar (var_name, NULL); - - m_Callback = callback; - Flags = 0; - Name = NULL; - inCallback = false; - - if (var_name) - { - C_AddTabCommand (var_name); - Name = copystring (var_name); - m_Next = CVars; - CVars = this; - } - - if (var) - { - ECVarType type; - UCVarValue value; - - value = var->GetFavoriteRep (&type); - ForceSet (value, type); - - if (var->Flags & CVAR_AUTO) - delete var; - else - var->~FBaseCVar(); - - Flags = flags; - } - else - { - Flags = flags | CVAR_ISDEFAULT; - } -} - -FBaseCVar::~FBaseCVar () -{ - if (Name) - { - FBaseCVar *var, *prev; - - var = FindCVar (Name, &prev); - - if (var == this) - { - if (prev) - prev->m_Next = m_Next; - else - CVars = m_Next; - } - C_RemoveTabCommand(Name); - delete[] Name; - } -} - -const char *FBaseCVar::GetHumanString(int precision) const -{ - return GetGenericRep(CVAR_String).String; -} - -void FBaseCVar::ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend) -{ - DoSet (value, type); - if ((Flags & CVAR_USERINFO) && !nouserinfosend && !(Flags & CVAR_IGNORE)) - D_UserInfoChanged (this); - if (m_UseCallback) - Callback (); - - if ((Flags & CVAR_ARCHIVE) && !(Flags & CVAR_UNSAFECONTEXT)) - { - SafeValue = GetGenericRep(CVAR_String).String; - } - - Flags &= ~(CVAR_ISDEFAULT | CVAR_UNSAFECONTEXT); -} - -void FBaseCVar::SetGenericRep (UCVarValue value, ECVarType type) -{ - if ((Flags & CVAR_NOSET) && m_DoNoSet) - { - return; - } - else if ((Flags & CVAR_LATCH) && gamestate != GS_FULLCONSOLE && gamestate != GS_STARTUP) - { - FLatchedValue latch; - - latch.Variable = this; - latch.Type = type; - if (type != CVAR_String) - latch.Value = value; - else - latch.Value.String = copystring(value.String); - latch.UnsafeContext = !!(Flags & CVAR_UNSAFECONTEXT); - LatchedValues.Push (latch); - - Flags &= ~CVAR_UNSAFECONTEXT; - } - else if ((Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) - { - if (netgame && !players[consoleplayer].settings_controller) - { - Printf ("Only setting controllers can change %s\n", Name); - Flags &= ~CVAR_UNSAFECONTEXT; - return; - } - D_SendServerInfoChange (this, value, type); - } - else - { - ForceSet (value, type); - } -} - -DEFINE_ACTION_FUNCTION(_CVar, GetInt) -{ - PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - auto v = self->GetGenericRep(CVAR_Int); - ACTION_RETURN_INT(v.Int); -} - -DEFINE_ACTION_FUNCTION(_CVar, GetFloat) -{ - PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - auto v = self->GetGenericRep(CVAR_Float); - ACTION_RETURN_FLOAT(v.Float); -} - -DEFINE_ACTION_FUNCTION(_CVar, GetString) -{ - PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - auto v = self->GetGenericRep(CVAR_String); - ACTION_RETURN_STRING(v.String); -} - -DEFINE_ACTION_FUNCTION(_CVar, SetInt) -{ - // Only menus are allowed to change CVARs. - PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - if (!(self->GetFlags() & CVAR_MOD)) - { - // Only menus are allowed to change non-mod CVARs. - if (DMenu::InMenu == 0) - { - ThrowAbortException(X_OTHER, "Attempt to change CVAR '%s' outside of menu code", self->GetName()); - } - } - PARAM_INT(val); - UCVarValue v; - v.Int = val; - self->SetGenericRep(v, CVAR_Int); - return 0; -} - -DEFINE_ACTION_FUNCTION(_CVar, SetFloat) -{ - PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - if (!(self->GetFlags() & CVAR_MOD)) - { - // Only menus are allowed to change non-mod CVARs. - if (DMenu::InMenu == 0) - { - ThrowAbortException(X_OTHER, "Attempt to change CVAR '%s' outside of menu code", self->GetName()); - } - } - PARAM_FLOAT(val); - UCVarValue v; - v.Float = (float)val; - self->SetGenericRep(v, CVAR_Float); - return 0; -} - -DEFINE_ACTION_FUNCTION(_CVar, SetString) -{ - // Only menus are allowed to change CVARs. - PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - if (!(self->GetFlags() & CVAR_MOD)) - { - // Only menus are allowed to change non-mod CVARs. - if (DMenu::InMenu == 0) - { - ThrowAbortException(X_OTHER, "Attempt to change CVAR '%s' outside of menu code", self->GetName()); - } - } - PARAM_STRING(val); - UCVarValue v; - v.String = val.GetChars(); - self->SetGenericRep(v, CVAR_String); - return 0; -} - -bool FBaseCVar::ToBool (UCVarValue value, ECVarType type) -{ - switch (type) - { - case CVAR_Bool: - return value.Bool; - - case CVAR_Int: - return !!value.Int; - - case CVAR_Float: - return value.Float != 0.f; - - case CVAR_String: - if (stricmp (value.String, "true") == 0) - return true; - else if (stricmp (value.String, "false") == 0) - return false; - else - return !!strtoll (value.String, NULL, 0); - - default: - return false; - } -} - -int FBaseCVar::ToInt (UCVarValue value, ECVarType type) -{ - int res; -#if __GNUC__ <= 2 - float tmp; -#endif - - switch (type) - { - case CVAR_Bool: res = (int)value.Bool; break; - case CVAR_Int: res = value.Int; break; -#if __GNUC__ <= 2 - case CVAR_Float: tmp = value.Float; res = (int)tmp; break; -#else - case CVAR_Float: res = (int)value.Float; break; -#endif - case CVAR_String: - { - if (stricmp (value.String, "true") == 0) - res = 1; - else if (stricmp (value.String, "false") == 0) - res = 0; - else - res = (int)strtoll (value.String, NULL, 0); - break; - } - default: res = 0; break; - } - return res; -} - -float FBaseCVar::ToFloat (UCVarValue value, ECVarType type) -{ - switch (type) - { - case CVAR_Bool: - return (float)value.Bool; - - case CVAR_Int: - return (float)value.Int; - - case CVAR_Float: - return value.Float; - - case CVAR_String: - return (float)strtod (value.String, NULL); - - default: - return 0.f; - } -} - -static char cstrbuf[40]; -static GUID cGUID; -static char truestr[] = "true"; -static char falsestr[] = "false"; - -const char *FBaseCVar::ToString (UCVarValue value, ECVarType type) -{ - switch (type) - { - case CVAR_Bool: - return value.Bool ? truestr : falsestr; - - case CVAR_String: - return value.String; - - case CVAR_Int: - mysnprintf (cstrbuf, countof(cstrbuf), "%i", value.Int); - break; - - case CVAR_Float: - IGNORE_FORMAT_PRE - mysnprintf (cstrbuf, countof(cstrbuf), "%H", value.Float); - IGNORE_FORMAT_POST - break; - - default: - strcpy (cstrbuf, ""); - break; - } - return cstrbuf; -} - -UCVarValue FBaseCVar::FromBool (bool value, ECVarType type) -{ - UCVarValue ret; - - switch (type) - { - case CVAR_Bool: - ret.Bool = value; - break; - - case CVAR_Int: - ret.Int = value; - break; - - case CVAR_Float: - ret.Float = value; - break; - - case CVAR_String: - ret.String = value ? truestr : falsestr; - break; - - default: - break; - } - - return ret; -} - -UCVarValue FBaseCVar::FromInt (int value, ECVarType type) -{ - UCVarValue ret; - - switch (type) - { - case CVAR_Bool: - ret.Bool = value != 0; - break; - - case CVAR_Int: - ret.Int = value; - break; - - case CVAR_Float: - ret.Float = (float)value; - break; - - case CVAR_String: - mysnprintf (cstrbuf, countof(cstrbuf), "%i", value); - ret.String = cstrbuf; - break; - - default: - break; - } - - return ret; -} - -UCVarValue FBaseCVar::FromFloat (float value, ECVarType type) -{ - UCVarValue ret; - - switch (type) - { - case CVAR_Bool: - ret.Bool = value != 0.f; - break; - - case CVAR_Int: - ret.Int = (int)value; - break; - - case CVAR_Float: - ret.Float = value; - break; - - case CVAR_String: - IGNORE_FORMAT_PRE - mysnprintf (cstrbuf, countof(cstrbuf), "%H", value); - IGNORE_FORMAT_POST - ret.String = cstrbuf; - break; - - default: - break; - } - - return ret; -} - -static uint8_t HexToByte (const char *hex) -{ - uint8_t v = 0; - for (int i = 0; i < 2; ++i) - { - v <<= 4; - if (hex[i] >= '0' && hex[i] <= '9') - { - v += hex[i] - '0'; - } - else if (hex[i] >= 'A' && hex[i] <= 'F') - { - v += hex[i] - 'A'; - } - else // The string is already verified to contain valid hexits - { - v += hex[i] - 'a'; - } - } - return v; -} - -UCVarValue FBaseCVar::FromString (const char *value, ECVarType type) -{ - UCVarValue ret; - - switch (type) - { - case CVAR_Bool: - if (stricmp (value, "true") == 0) - ret.Bool = true; - else if (stricmp (value, "false") == 0) - ret.Bool = false; - else - ret.Bool = strtoll (value, NULL, 0) != 0; - break; - - case CVAR_Int: - if (stricmp (value, "true") == 0) - ret.Int = 1; - else if (stricmp (value, "false") == 0) - ret.Int = 0; - else - ret.Int = (int)strtoll (value, NULL, 0); - break; - - case CVAR_Float: - ret.Float = (float)strtod (value, NULL); - break; - - case CVAR_String: - ret.String = const_cast(value); - break; - - default: - break; - } - - return ret; -} - -FBaseCVar *cvar_set (const char *var_name, const char *val) -{ - FBaseCVar *var; - - if ( (var = FindCVar (var_name, NULL)) ) - { - UCVarValue value; - value.String = const_cast(val); - var->SetGenericRep (value, CVAR_String); - } - - return var; -} - -FBaseCVar *cvar_forceset (const char *var_name, const char *val) -{ - FBaseCVar *var; - UCVarValue vval; - - if ( (var = FindCVar (var_name, NULL)) ) - { - vval.String = const_cast(val); - var->ForceSet (vval, CVAR_String); - } - - return var; -} - -void FBaseCVar::EnableNoSet () -{ - m_DoNoSet = true; -} - -void FBaseCVar::EnableCallbacks () -{ - m_UseCallback = true; - FBaseCVar *cvar = CVars; - - while (cvar) - { - if (!(cvar->Flags & CVAR_NOINITCALL)) - { - cvar->Callback (); - } - cvar = cvar->m_Next; - } -} - -void FBaseCVar::DisableCallbacks () -{ - m_UseCallback = false; -} - -DEFINE_ACTION_FUNCTION(_CVar, GetRealType) -{ - PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - ACTION_RETURN_INT(self->GetRealType()); -} - -// -// Boolean cvar implementation -// - -FBoolCVar::FBoolCVar (const char *name, bool def, uint32_t flags, void (*callback)(FBoolCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - DefaultValue = def; - if (Flags & CVAR_ISDEFAULT) - Value = def; -} - -ECVarType FBoolCVar::GetRealType () const -{ - return CVAR_Bool; -} - -UCVarValue FBoolCVar::GetGenericRep (ECVarType type) const -{ - return FromBool (Value, type); -} - -UCVarValue FBoolCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Bool; - ret.Bool = Value; - return ret; -} - -UCVarValue FBoolCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromBool (DefaultValue, type); -} - -UCVarValue FBoolCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Bool; - ret.Bool = DefaultValue; - return ret; -} - -void FBoolCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - DefaultValue = ToBool (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FBoolCVar::DoSet (UCVarValue value, ECVarType type) -{ - Value = ToBool (value, type); -} - -// -// Integer cvar implementation -// - -FIntCVar::FIntCVar (const char *name, int def, uint32_t flags, void (*callback)(FIntCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - DefaultValue = def; - if (Flags & CVAR_ISDEFAULT) - Value = def; -} - -ECVarType FIntCVar::GetRealType () const -{ - return CVAR_Int; -} - -UCVarValue FIntCVar::GetGenericRep (ECVarType type) const -{ - return FromInt (Value, type); -} - -UCVarValue FIntCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Int; - ret.Int = Value; - return ret; -} - -UCVarValue FIntCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromInt (DefaultValue, type); -} - -UCVarValue FIntCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Int; - ret.Int = DefaultValue; - return ret; -} - -void FIntCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - DefaultValue = ToInt (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FIntCVar::DoSet (UCVarValue value, ECVarType type) -{ - Value = ToInt (value, type); -} - -// -// Floating point cvar implementation -// - -FFloatCVar::FFloatCVar (const char *name, float def, uint32_t flags, void (*callback)(FFloatCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - DefaultValue = def; - if (Flags & CVAR_ISDEFAULT) - Value = def; -} - -ECVarType FFloatCVar::GetRealType () const -{ - return CVAR_Float; -} - -const char *FFloatCVar::GetHumanString(int precision) const -{ - if (precision < 0) - { - precision = 6; - } - mysnprintf(cstrbuf, countof(cstrbuf), "%.*g", precision, Value); - return cstrbuf; -} - -UCVarValue FFloatCVar::GetGenericRep (ECVarType type) const -{ - return FromFloat (Value, type); -} - -UCVarValue FFloatCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Float; - ret.Float = Value; - return ret; -} - -UCVarValue FFloatCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromFloat (DefaultValue, type); -} - -UCVarValue FFloatCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Float; - ret.Float = DefaultValue; - return ret; -} - -void FFloatCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - DefaultValue = ToFloat (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FFloatCVar::DoSet (UCVarValue value, ECVarType type) -{ - Value = ToFloat (value, type); -} - -// -// String cvar implementation -// - -FStringCVar::FStringCVar (const char *name, const char *def, uint32_t flags, void (*callback)(FStringCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - DefaultValue = copystring (def); - if (Flags & CVAR_ISDEFAULT) - Value = copystring (def); - else - Value = NULL; -} - -FStringCVar::~FStringCVar () -{ - if (Value != NULL) - { - delete[] Value; - } - delete[] DefaultValue; -} - -ECVarType FStringCVar::GetRealType () const -{ - return CVAR_String; -} - -UCVarValue FStringCVar::GetGenericRep (ECVarType type) const -{ - return FromString (Value, type); -} - -UCVarValue FStringCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_String; - ret.String = Value; - return ret; -} - -UCVarValue FStringCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromString (DefaultValue, type); -} - -UCVarValue FStringCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_String; - ret.String = DefaultValue; - return ret; -} - -void FStringCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - ReplaceString(&DefaultValue, ToString(value, type)); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FStringCVar::DoSet (UCVarValue value, ECVarType type) -{ - ReplaceString (&Value, ToString (value, type)); -} - -// -// Color cvar implementation -// - -FColorCVar::FColorCVar (const char *name, int def, uint32_t flags, void (*callback)(FColorCVar &)) -: FIntCVar (name, def, flags, reinterpret_cast(callback)) -{ -} - -ECVarType FColorCVar::GetRealType () const -{ - return CVAR_Color; -} - -UCVarValue FColorCVar::GetGenericRep (ECVarType type) const -{ - return FromInt2 (Value, type); -} - -UCVarValue FColorCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromInt2 (DefaultValue, type); -} - -void FColorCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - DefaultValue = ToInt2 (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FColorCVar::DoSet (UCVarValue value, ECVarType type) -{ - Value = ToInt2 (value, type); - if (screen) - Index = ColorMatcher.Pick (RPART(Value), GPART(Value), BPART(Value)); -} - -UCVarValue FColorCVar::FromInt2 (int value, ECVarType type) -{ - if (type == CVAR_String) - { - UCVarValue ret; - mysnprintf (cstrbuf, countof(cstrbuf), "%02x %02x %02x", - RPART(value), GPART(value), BPART(value)); - ret.String = cstrbuf; - return ret; - } - return FromInt (value, type); -} - -int FColorCVar::ToInt2 (UCVarValue value, ECVarType type) -{ - int ret; - - if (type == CVAR_String) - { - FString string; - // Only allow named colors after the screen exists (i.e. after - // we've got some lumps loaded, so X11R6RGB can be read). Since - // the only time this might be called before that is when loading - // zdoom.ini, this shouldn't be a problem. - if (screen && !(string = V_GetColorStringByName (value.String)).IsEmpty() ) - { - ret = V_GetColorFromString (NULL, string); - } - else - { - ret = V_GetColorFromString (NULL, value.String); - } - } - else - { - ret = ToInt (value, type); - } - return ret; -} - -// -// More base cvar stuff -// - -void FBaseCVar::ResetColors () -{ - FBaseCVar *var = CVars; - - while (var) - { - if (var->GetRealType () == CVAR_Color) - { - var->DoSet (var->GetGenericRep (CVAR_Int), CVAR_Int); - } - var = var->m_Next; - } -} - -void FBaseCVar::ResetToDefault () -{ - if (!(Flags & CVAR_ISDEFAULT)) - { - UCVarValue val; - ECVarType type; - - val = GetFavoriteRepDefault (&type); - SetGenericRep (val, type); - Flags |= CVAR_ISDEFAULT; - } -} - -DEFINE_ACTION_FUNCTION(_CVar, ResetToDefault) -{ - PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - if (!(self->GetFlags() & CVAR_MOD)) - { - // Only menus are allowed to change non-mod CVARs. - if (DMenu::InMenu == 0) - { - ThrowAbortException(X_OTHER, "Attempt to change CVAR '%s' outside of menu code", self->GetName()); - } - } - - self->ResetToDefault(); - return 0; -} - -void FBaseCVar::MarkUnsafe() -{ - if (!(Flags & CVAR_MOD) && UnsafeExecutionContext) - { - Flags |= CVAR_UNSAFECONTEXT; - } -} - -// -// Flag cvar implementation -// -// This type of cvar is not a "real" cvar. Instead, it gets and sets -// the value of a FIntCVar, modifying it bit-by-bit. As such, it has -// no default, and is not written to the .cfg or transferred around -// the network. The "host" cvar is responsible for that. -// - -FFlagCVar::FFlagCVar (const char *name, FIntCVar &realvar, uint32_t bitval) -: FBaseCVar (name, 0, NULL), -ValueVar (realvar), -BitVal (bitval) -{ - int bit; - - Flags &= ~CVAR_ISDEFAULT; - - assert (bitval != 0); - - bit = 0; - while ((bitval >>= 1) != 0) - { - ++bit; - } - BitNum = bit; - - assert ((1u << BitNum) == BitVal); -} - -ECVarType FFlagCVar::GetRealType () const -{ - return CVAR_DummyBool; -} - -UCVarValue FFlagCVar::GetGenericRep (ECVarType type) const -{ - return FromBool ((ValueVar & BitVal) != 0, type); -} - -UCVarValue FFlagCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Bool; - ret.Bool = (ValueVar & BitVal) != 0; - return ret; -} - -UCVarValue FFlagCVar::GetGenericRepDefault (ECVarType type) const -{ - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - return FromBool ((def.Int & BitVal) != 0, type); -} - -UCVarValue FFlagCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - def.Bool = (def.Int & BitVal) != 0; - *type = CVAR_Bool; - return def; -} - -void FFlagCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - bool newdef = ToBool (value, type); - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - if (newdef) - def.Int |= BitVal; - else - def.Int &= ~BitVal; - ValueVar.SetGenericRepDefault (def, CVAR_Int); -} - -void FFlagCVar::DoSet (UCVarValue value, ECVarType type) -{ - bool newval = ToBool (value, type); - - // Server cvars that get changed by this need to use a special message, because - // changes are not processed until the next net update. This is a problem with - // exec scripts because all flags will base their changes off of the value of - // the "master" cvar at the time the script was run, overriding any changes - // another flag might have made to the same cvar earlier in the script. - if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) - { - if (netgame && !players[consoleplayer].settings_controller) - { - Printf ("Only setting controllers can change %s\n", Name); - return; - } - D_SendServerFlagChange (&ValueVar, BitNum, newval); - } - else - { - int val = *ValueVar; - if (newval) - val |= BitVal; - else - val &= ~BitVal; - ValueVar = val; - } -} - -// -// Mask cvar implementation -// -// Similar to FFlagCVar but can have multiple bits -// - -FMaskCVar::FMaskCVar (const char *name, FIntCVar &realvar, uint32_t bitval) -: FBaseCVar (name, 0, NULL), -ValueVar (realvar), -BitVal (bitval) -{ - int bit; - - Flags &= ~CVAR_ISDEFAULT; - - assert (bitval != 0); - - bit = 0; - while ((bitval & 1) == 0) - { - ++bit; - bitval >>= 1; - } - BitNum = bit; -} - -ECVarType FMaskCVar::GetRealType () const -{ - return CVAR_DummyInt; -} - -UCVarValue FMaskCVar::GetGenericRep (ECVarType type) const -{ - return FromInt ((ValueVar & BitVal) >> BitNum, type); -} - -UCVarValue FMaskCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Int; - ret.Int = (ValueVar & BitVal) >> BitNum; - return ret; -} - -UCVarValue FMaskCVar::GetGenericRepDefault (ECVarType type) const -{ - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - return FromInt ((def.Int & BitVal) >> BitNum, type); -} - -UCVarValue FMaskCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - def.Int = (def.Int & BitVal) >> BitNum; - *type = CVAR_Int; - return def; -} - -void FMaskCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - int val = ToInt(value, type) << BitNum; - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - def.Int &= ~BitVal; - def.Int |= val; - ValueVar.SetGenericRepDefault (def, CVAR_Int); -} - -void FMaskCVar::DoSet (UCVarValue value, ECVarType type) -{ - int val = ToInt(value, type) << BitNum; - - // Server cvars that get changed by this need to use a special message, because - // changes are not processed until the next net update. This is a problem with - // exec scripts because all flags will base their changes off of the value of - // the "master" cvar at the time the script was run, overriding any changes - // another flag might have made to the same cvar earlier in the script. - if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) - { - if (netgame && !players[consoleplayer].settings_controller) - { - Printf ("Only setting controllers can change %s\n", Name); - return; - } - // Ugh... - for(int i = 0; i < 32; i++) - { - if (BitVal & (1<GetName(), ((*(FBaseCVar **)b))->GetName()); -} - -void FilterCompactCVars (TArray &cvars, uint32_t filter) -{ - // Accumulate all cvars that match the filter flags. - for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next) - { - if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_IGNORE)) - cvars.Push(cvar); - } - // Now sort them, so they're in a deterministic order and not whatever - // order the linker put them in. - if (cvars.Size() > 0) - { - qsort(&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars); - } -} - -void C_WriteCVars (uint8_t **demo_p, uint32_t filter, bool compact) -{ - FString dump = C_GetMassCVarString(filter, compact); - size_t dumplen = dump.Len() + 1; // include terminating \0 - memcpy(*demo_p, dump.GetChars(), dumplen); - *demo_p += dumplen; -} - -FString C_GetMassCVarString (uint32_t filter, bool compact) -{ - FBaseCVar *cvar; - FString dump; - - if (compact) - { - TArray cvars; - dump.AppendFormat("\\\\%ux", filter); - FilterCompactCVars(cvars, filter); - while (cvars.Pop (cvar)) - { - UCVarValue val = cvar->GetGenericRep(CVAR_String); - dump << '\\' << val.String; - } - } - else - { - for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next) - { - if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_IGNORE))) - { - UCVarValue val = cvar->GetGenericRep(CVAR_String); - dump << '\\' << cvar->GetName() << '\\' << val.String; - } - } - } - return dump; -} - -void C_SerializeCVars(FSerializer &arc, const char *label, uint32_t filter) -{ - FBaseCVar* cvar; - FString dump; - - if (arc.BeginObject(label)) - { - if (arc.isWriting()) - { - for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next) - { - if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE | CVAR_IGNORE | CVAR_CONFIG_ONLY))) - { - UCVarValue val = cvar->GetGenericRep(CVAR_String); - char* c = const_cast(val.String); - arc(cvar->GetName(), c); - } - } - } - else - { - for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next) - { - if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE | CVAR_IGNORE | CVAR_CONFIG_ONLY))) - { - UCVarValue val; - char *c = nullptr; - arc(cvar->GetName(), c); - if (c != nullptr) - { - val.String = c; - cvar->SetGenericRep(val, CVAR_String); - delete[] c; - } - } - } - } - arc.EndObject(); - } -} - -void C_ReadCVars (uint8_t **demo_p) -{ - char *ptr = *((char **)demo_p); - char *breakpt; - - if (*ptr++ != '\\') - return; - - if (*ptr == '\\') - { // compact mode - TArray cvars; - FBaseCVar *cvar; - uint32_t filter; - - ptr++; - breakpt = strchr (ptr, '\\'); - *breakpt = 0; - filter = strtoul (ptr, NULL, 16); - *breakpt = '\\'; - ptr = breakpt + 1; - - FilterCompactCVars (cvars, filter); - - while (cvars.Pop (cvar)) - { - UCVarValue val; - breakpt = strchr (ptr, '\\'); - if (breakpt) - *breakpt = 0; - val.String = ptr; - cvar->ForceSet (val, CVAR_String); - if (breakpt) - { - *breakpt = '\\'; - ptr = breakpt + 1; - } - else - break; - } - } - else - { - char *value; - - while ( (breakpt = strchr (ptr, '\\')) ) - { - *breakpt = 0; - value = breakpt + 1; - if ( (breakpt = strchr (value, '\\')) ) - *breakpt = 0; - - cvar_set (ptr, value); - - *(value - 1) = '\\'; - if (breakpt) - { - *breakpt = '\\'; - ptr = breakpt + 1; - } - else - { - break; - } - } - } - *demo_p += strlen (*((char **)demo_p)) + 1; -} - -struct FCVarBackup -{ - FString Name, String; -}; -static TArray CVarBackups; - -void C_BackupCVars (void) -{ - assert(CVarBackups.Size() == 0); - CVarBackups.Clear(); - - FCVarBackup backup; - - for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next) - { - if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE)) && !(cvar->Flags & CVAR_LATCH)) - { - backup.Name = cvar->GetName(); - backup.String = cvar->GetGenericRep(CVAR_String).String; - CVarBackups.Push(backup); - } - } -} - -void C_RestoreCVars (void) -{ - for (unsigned int i = 0; i < CVarBackups.Size(); ++i) - { - cvar_set(CVarBackups[i].Name, CVarBackups[i].String); - } - C_ForgetCVars(); -} - -void C_ForgetCVars (void) -{ - CVarBackups.Clear(); -} - -FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev) -{ - FBaseCVar *var; - FBaseCVar *dummy; - - if (var_name == NULL) - return NULL; - - if (prev == NULL) - prev = &dummy; - - var = CVars; - *prev = NULL; - while (var) - { - if (stricmp (var->GetName (), var_name) == 0) - break; - *prev = var; - var = var->m_Next; - } - return var; -} - -DEFINE_ACTION_FUNCTION(_CVar, FindCVar) -{ - PARAM_PROLOGUE; - PARAM_NAME(name); - ACTION_RETURN_POINTER(FindCVar(name, nullptr)); -} - -DEFINE_ACTION_FUNCTION(_CVar, GetCVar) -{ - PARAM_PROLOGUE; - PARAM_NAME(name); - PARAM_POINTER(plyr, player_t); - ACTION_RETURN_POINTER(GetCVar(plyr ? int(plyr - players) : -1, name)); -} - -FBaseCVar *FindCVarSub (const char *var_name, int namelen) -{ - FBaseCVar *var; - - if (var_name == NULL) - return NULL; - - var = CVars; - while (var) - { - const char *probename = var->GetName (); - - if (strnicmp (probename, var_name, namelen) == 0 && - probename[namelen] == 0) - { - break; - } - var = var->m_Next; - } - return var; -} - -FBaseCVar *GetCVar(int playernum, const char *cvarname) -{ - FBaseCVar *cvar = FindCVar(cvarname, nullptr); - // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return nullptr. - if (cvar == nullptr || (cvar->GetFlags() & CVAR_IGNORE)) - { - return nullptr; - } - else - { - // For userinfo cvars, redirect to GetUserCVar - if (cvar->GetFlags() & CVAR_USERINFO) - { - return GetUserCVar(playernum, cvarname); - } - return cvar; - } -} - -FBaseCVar *GetUserCVar(int playernum, const char *cvarname) -{ - if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) - { - return nullptr; - } - FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true)); - FBaseCVar *cvar; - if (cvar_p == nullptr || (cvar = *cvar_p) == nullptr || (cvar->GetFlags() & CVAR_IGNORE)) - { - return nullptr; - } - return cvar; -} - -//=========================================================================== -// -// C_CreateCVar -// -// Create a new cvar with the specified name and type. It should not already -// exist. -// -//=========================================================================== - -FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, uint32_t flags) -{ - assert(FindCVar(var_name, NULL) == NULL); - flags |= CVAR_AUTO; - switch (var_type) - { - case CVAR_Bool: return new FBoolCVar(var_name, 0, flags); - case CVAR_Int: return new FIntCVar(var_name, 0, flags); - case CVAR_Float: return new FFloatCVar(var_name, 0, flags); - case CVAR_String: return new FStringCVar(var_name, NULL, flags); - case CVAR_Color: return new FColorCVar(var_name, 0, flags); - default: return NULL; - } -} - -void UnlatchCVars (void) -{ - for (const FLatchedValue& var : LatchedValues) - { - uint32_t oldflags = var.Variable->Flags; - var.Variable->Flags &= ~(CVAR_LATCH | CVAR_SERVERINFO); - if (var.UnsafeContext) - var.Variable->Flags |= CVAR_UNSAFECONTEXT; - var.Variable->SetGenericRep (var.Value, var.Type); - if (var.Type == CVAR_String) - delete[] var.Value.String; - var.Variable->Flags = oldflags; - } - - LatchedValues.Clear(); -} - -void DestroyCVarsFlagged (uint32_t flags) -{ - FBaseCVar *cvar = CVars; - FBaseCVar *next = cvar; - - while(cvar) - { - next = cvar->m_Next; - - if(cvar->Flags & flags) - delete cvar; - - cvar = next; - } -} - -void C_SetCVarsToDefaults (void) -{ - FBaseCVar *cvar = CVars; - - while (cvar) - { - // Only default save-able cvars - if (cvar->Flags & CVAR_ARCHIVE) - { - UCVarValue val; - ECVarType type; - val = cvar->GetFavoriteRepDefault (&type); - cvar->SetGenericRep (val, type); - } - cvar = cvar->m_Next; - } -} - -static int cvarcmp(const void* a, const void* b) -{ - FBaseCVar** A = (FBaseCVar**)a; - FBaseCVar** B = (FBaseCVar**)b; - return strcmp((*A)->GetName(), (*B)->GetName()); -} - -void C_ArchiveCVars (FConfigFile *f, uint32_t filter) -{ - FBaseCVar *cvar = CVars; - TArray cvarlist; - - while (cvar) - { - if ((cvar->Flags & - (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MOD|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE|CVAR_CONFIG_ONLY)) - == filter) - { - cvarlist.Push(cvar); - } - cvar = cvar->m_Next; - } - qsort(cvarlist.Data(), cvarlist.Size(), sizeof(FBaseCVar*), cvarcmp); - for (auto cvar : cvarlist) - { - const char* const value = (cvar->Flags & CVAR_ISDEFAULT) - ? cvar->GetGenericRep(CVAR_String).String - : cvar->SafeValue.GetChars(); - f->SetValueForKey(cvar->GetName(), value); - } -} - -EXTERN_CVAR(Bool, sv_cheats); - -void FBaseCVar::CmdSet (const char *newval) -{ - if ((GetFlags() & CVAR_CHEAT) && CheckCheatmode ()) - return; - - MarkUnsafe(); - - UCVarValue val; - - // Casting away the const is safe in this case. - val.String = const_cast(newval); - SetGenericRep (val, CVAR_String); - - if (GetFlags() & CVAR_NOSET) - Printf ("%s is write protected.\n", GetName()); - else if (GetFlags() & CVAR_LATCH) - Printf ("%s will be changed for next game.\n", GetName()); -} - -CCMD (set) -{ - if (argv.argc() != 3) - { - Printf ("usage: set \n"); - } - else - { - FBaseCVar *var; - - var = FindCVar (argv[1], NULL); - if (var == NULL) - var = new FStringCVar (argv[1], NULL, CVAR_AUTO | CVAR_UNSETTABLE | cvar_defflags); - - var->CmdSet (argv[2]); - } -} - -CCMD (unset) -{ - if (argv.argc() != 2) - { - Printf ("usage: unset \n"); - } - else - { - FBaseCVar *var = FindCVar (argv[1], NULL); - if (var != NULL) - { - if (var->GetFlags() & CVAR_UNSETTABLE) - { - delete var; - } - else - { - Printf ("Cannot unset %s\n", argv[1]); - } - } - } -} - -CCMD (get) -{ - FBaseCVar *var, *prev; - - if (argv.argc() >= 2) - { - if ( (var = FindCVar (argv[1], &prev)) ) - { - UCVarValue val; - val = var->GetGenericRep (CVAR_String); - Printf ("\"%s\" is \"%s\"\n", var->GetName(), val.String); - } - else - { - Printf ("\"%s\" is unset\n", argv[1]); - } - } - else - { - Printf ("get: need variable name\n"); - } -} - -CCMD (toggle) -{ - FBaseCVar *var, *prev; - UCVarValue val; - - if (argv.argc() > 1) - { - if ( (var = FindCVar (argv[1], &prev)) ) - { - var->MarkUnsafe(); - - val = var->GetGenericRep (CVAR_Bool); - val.Bool = !val.Bool; - var->SetGenericRep (val, CVAR_Bool); - Printf ("\"%s\" = \"%s\"\n", var->GetName(), - val.Bool ? "true" : "false"); - } - } -} - -void FBaseCVar::ListVars (const char *filter, bool plain) -{ - FBaseCVar *var = CVars; - int count = 0; - - while (var) - { - if (CheckWildcards (filter, var->GetName())) - { - uint32_t flags = var->GetFlags(); - if (plain) - { // plain formatting does not include user-defined cvars - if (!(flags & CVAR_UNSETTABLE)) - { - ++count; - Printf ("%s : %s\n", var->GetName(), var->GetHumanString()); - } - } - else - { - ++count; - Printf ("%c%c%c%c%c %s = %s\n", - flags & CVAR_ARCHIVE ? 'A' : ' ', - flags & CVAR_USERINFO ? 'U' : - flags & CVAR_SERVERINFO ? 'S' : - flags & CVAR_AUTO ? 'C' : ' ', - flags & CVAR_NOSET ? '-' : - flags & CVAR_LATCH ? 'L' : - flags & CVAR_UNSETTABLE ? '*' : ' ', - flags & CVAR_MOD ? 'M' : ' ', - flags & CVAR_IGNORE ? 'X' : ' ', - var->GetName(), - var->GetHumanString()); - } - } - var = var->m_Next; - } - Printf ("%d cvars\n", count); -} - -CCMD (cvarlist) -{ - if (argv.argc() == 1) - { - FBaseCVar::ListVars (NULL, false); - } - else - { - FBaseCVar::ListVars (argv[1], false); - } -} - -CCMD (cvarlistplain) -{ - FBaseCVar::ListVars (NULL, true); -} - -CCMD (archivecvar) -{ - - if (argv.argc() == 1) - { - Printf ("Usage: archivecvar \n"); - } - else - { - FBaseCVar *var = FindCVar (argv[1], NULL); - - if (var != NULL && (var->GetFlags() & CVAR_AUTO)) - { - var->SetArchiveBit (); - } - } -} - -void C_GrabCVarDefaults () -{ - int lump, lastlump = 0; - int lumpversion, gamelastrunversion; - gamelastrunversion = atoi(LASTRUNVERSION); - - while ((lump = Wads.FindLump("DEFCVARS", &lastlump)) != -1) - { - // don't parse from wads - if (lastlump > Wads.GetLastLump(Wads.GetMaxIwadNum())) - I_FatalError("Cannot load DEFCVARS from a wadfile!\n"); - - FScanner sc(lump); - - sc.MustGetString(); - if (!sc.Compare("version")) - sc.ScriptError("Must declare version for defcvars! (currently: %i)", gamelastrunversion); - sc.MustGetNumber(); - lumpversion = sc.Number; - if (lumpversion > gamelastrunversion) - sc.ScriptError("Unsupported version %i (%i supported)", lumpversion, gamelastrunversion); - if (lumpversion < 219) - sc.ScriptError("Version must be at least 219 (current version %i)", gamelastrunversion); - - FBaseCVar *var; - - while (sc.GetString()) - { - if (sc.Compare("set")) - { - sc.MustGetString(); - } - var = FindCVar (sc.String, NULL); - if (var != NULL) - { - if (var->GetFlags() & CVAR_ARCHIVE) - { - UCVarValue val; - - sc.MustGetString(); - val.String = const_cast(sc.String); - var->SetGenericRepDefault(val, CVAR_String); - } - else - { - sc.ScriptError("Cannot set cvar default for non-config cvar '%s'", sc.String); - } - } - else - { - sc.ScriptError("Unknown cvar '%s'", sc.String); - } - } - } -} diff --git a/src/console/c_cvars.h b/src/console/c_cvars.h deleted file mode 100644 index 1e2f75c89be..00000000000 --- a/src/console/c_cvars.h +++ /dev/null @@ -1,448 +0,0 @@ -/* -** c_cvars.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __C_CVARS_H__ -#define __C_CVARS_H__ - -#include "zstring.h" -#include "tarray.h" - -class FSerializer; -/* -========================================================== - -CVARS (console variables) - -========================================================== -*/ - -enum -{ - CVAR_ARCHIVE = 1, // set to cause it to be saved to config. - CVAR_USERINFO = 1 << 1, // added to userinfo when changed. - CVAR_SERVERINFO = 1 << 2, // added to serverinfo when changed. - CVAR_NOSET = 1 << 3, // don't allow change from console at all, - // but can be set from the command line. - CVAR_LATCH = 1 << 4, // save changes until server restart. - CVAR_UNSETTABLE = 1 << 5, // can unset this var from console. - CVAR_DEMOSAVE = 1 << 6, // save the value of this cvar in a demo. - CVAR_ISDEFAULT = 1 << 7, // is cvar unchanged since creation? - CVAR_AUTO = 1 << 8, // allocated; needs to be freed when destroyed. - CVAR_NOINITCALL = 1 << 9, // don't call callback at game start. - CVAR_GLOBALCONFIG = 1 << 10, // cvar is saved to global config section. - CVAR_VIDEOCONFIG = 1 << 11, // cvar is saved to video config section (not implemented). - CVAR_NOSAVE = 1 << 12, // when used with CVAR_SERVERINFO, do not save var to savegame - // and config. - CVAR_MOD = 1 << 13, // cvar was defined by a mod. - CVAR_IGNORE = 1 << 14, // do not send cvar across the network/inaccesible from ACS - // (dummy mod cvar). - CVAR_CHEAT = 1 << 15, // can be set only when sv_cheats is enabled. - CVAR_UNSAFECONTEXT = 1 << 16, // cvar value came from unsafe context. - CVAR_VIRTUAL = 1 << 17, // do not invoke the callback recursively so it can be used to - // mirror an external variable. - CVAR_CONFIG_ONLY = 1 << 18, // do not save var to savegame and do not send it across network. -}; - -union UCVarValue -{ - bool Bool; - int Int; - float Float; - const char *String; -}; - -enum ECVarType -{ - CVAR_Bool, - CVAR_Int, - CVAR_Float, - CVAR_String, - CVAR_Color, // stored as CVAR_Int - CVAR_DummyBool, // just redirects to another cvar - CVAR_DummyInt, // just redirects to another cvar - CVAR_Dummy // Unknown -}; - -class FConfigFile; - -class FxCVar; - -class FBaseCVar -{ -public: - FBaseCVar (const char *name, uint32_t flags, void (*callback)(FBaseCVar &)); - virtual ~FBaseCVar (); - - inline void Callback () - { - if (m_Callback && !inCallback) - { - inCallback = !!(Flags & CVAR_VIRTUAL); // Virtual CVARs never invoke the callback recursively, giving it a chance to manipulate the value without side effects. - m_Callback(*this); - inCallback = false; - } - } - - inline const char *GetName () const { return Name; } - inline uint32_t GetFlags () const { return Flags; } - inline FBaseCVar *GetNext() const { return m_Next; } - - void CmdSet (const char *newval); - void ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend=false); - void SetGenericRep (UCVarValue value, ECVarType type); - void ResetToDefault (); - void SetArchiveBit () { Flags |= CVAR_ARCHIVE; } - void MarkUnsafe(); - - virtual ECVarType GetRealType () const = 0; - - virtual const char *GetHumanString(int precision=-1) const; - virtual UCVarValue GetGenericRep (ECVarType type) const = 0; - virtual UCVarValue GetFavoriteRep (ECVarType *type) const = 0; - - virtual UCVarValue GetGenericRepDefault (ECVarType type) const = 0; - virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const = 0; - virtual void SetGenericRepDefault (UCVarValue value, ECVarType type) = 0; - - FBaseCVar &operator= (const FBaseCVar &var) - { UCVarValue val; ECVarType type; val = var.GetFavoriteRep (&type); SetGenericRep (val, type); return *this; } - - static void EnableNoSet (); // enable the honoring of CVAR_NOSET - static void EnableCallbacks (); - static void DisableCallbacks (); - static void ResetColors (); // recalc color cvars' indices after screen change - - static void ListVars (const char *filter, bool plain); - -protected: - virtual void DoSet (UCVarValue value, ECVarType type) = 0; - - static bool ToBool (UCVarValue value, ECVarType type); - static int ToInt (UCVarValue value, ECVarType type); - static float ToFloat (UCVarValue value, ECVarType type); - static const char *ToString (UCVarValue value, ECVarType type); - static UCVarValue FromBool (bool value, ECVarType type); - static UCVarValue FromInt (int value, ECVarType type); - static UCVarValue FromFloat (float value, ECVarType type); - static UCVarValue FromString (const char *value, ECVarType type); - - char *Name; - FString SafeValue; - uint32_t Flags; - bool inCallback; - -private: - FBaseCVar (const FBaseCVar &var) = delete; - FBaseCVar (const char *name, uint32_t flags); - - void (*m_Callback)(FBaseCVar &); - FBaseCVar *m_Next; - - static bool m_UseCallback; - static bool m_DoNoSet; - - friend FString C_GetMassCVarString (uint32_t filter, bool compact); - friend void C_SerializeCVars(FSerializer& arc, const char* label, uint32_t filter); - friend void C_ReadCVars (uint8_t **demo_p); - friend void C_BackupCVars (void); - friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); - friend FBaseCVar *FindCVarSub (const char *var_name, int namelen); - friend void UnlatchCVars (void); - friend void DestroyCVarsFlagged (uint32_t flags); - friend void C_ArchiveCVars (FConfigFile *f, uint32_t filter); - friend void C_SetCVarsToDefaults (void); - friend void FilterCompactCVars (TArray &cvars, uint32_t filter); - friend void C_DeinitConsole(); -}; - -// Returns a string with all cvars whose flags match filter. In compact mode, -// the cvar names are omitted to save space. -FString C_GetMassCVarString (uint32_t filter, bool compact=false); - -// Writes all cvars that could effect demo sync to *demo_p. These are -// cvars that have either CVAR_SERVERINFO or CVAR_DEMOSAVE set. -void C_WriteCVars (uint8_t **demo_p, uint32_t filter, bool compact=false); - -// Read all cvars from *demo_p and set them appropriately. -void C_ReadCVars (uint8_t **demo_p); - -void C_SerializeCVars(FSerializer& arc, const char* label, uint32_t filter); - -// Backup demo cvars. Called before a demo starts playing to save all -// cvars the demo might change. -void C_BackupCVars (void); - -// Finds a named cvar -FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); -FBaseCVar *FindCVarSub (const char *var_name, int namelen); - -// Used for ACS and DECORATE. -FBaseCVar *GetCVar(int playernum, const char *cvarname); -FBaseCVar *GetUserCVar(int playernum, const char *cvarname); - -// Create a new cvar with the specified name and type -FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, uint32_t flags); - -// Called from G_InitNew() -void UnlatchCVars (void); - -// Destroy CVars with the matching flags; called from CCMD(restart) -void DestroyCVarsFlagged (uint32_t flags); - -// archive cvars to FILE f -void C_ArchiveCVars (FConfigFile *f, uint32_t filter); - -// initialize cvars to default values after they are created -void C_SetCVarsToDefaults (void); - -void FilterCompactCVars (TArray &cvars, uint32_t filter); - -void C_DeinitConsole(); - -class FBoolCVar : public FBaseCVar -{ - friend class FxCVar; -public: - FBoolCVar (const char *name, bool def, uint32_t flags, void (*callback)(FBoolCVar &)=NULL); - - virtual ECVarType GetRealType () const; - - virtual UCVarValue GetGenericRep (ECVarType type) const; - virtual UCVarValue GetFavoriteRep (ECVarType *type) const; - virtual UCVarValue GetGenericRepDefault (ECVarType type) const; - virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; - virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); - - inline bool operator= (bool boolval) - { UCVarValue val; val.Bool = boolval; SetGenericRep (val, CVAR_Bool); return boolval; } - inline operator bool () const { return Value; } - inline bool operator *() const { return Value; } - -protected: - virtual void DoSet (UCVarValue value, ECVarType type); - - bool Value; - bool DefaultValue; -}; - -class FIntCVar : public FBaseCVar -{ - friend class FxCVar; -public: - FIntCVar (const char *name, int def, uint32_t flags, void (*callback)(FIntCVar &)=NULL); - - virtual ECVarType GetRealType () const; - - virtual UCVarValue GetGenericRep (ECVarType type) const; - virtual UCVarValue GetFavoriteRep (ECVarType *type) const; - virtual UCVarValue GetGenericRepDefault (ECVarType type) const; - virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; - virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); - - int operator= (int intval) - { UCVarValue val; val.Int = intval; SetGenericRep (val, CVAR_Int); return intval; } - inline operator int () const { return Value; } - inline int operator *() const { return Value; } - -protected: - virtual void DoSet (UCVarValue value, ECVarType type); - - int Value; - int DefaultValue; - - friend class FFlagCVar; -}; - -class FFloatCVar : public FBaseCVar -{ - friend class FxCVar; -public: - FFloatCVar (const char *name, float def, uint32_t flags, void (*callback)(FFloatCVar &)=NULL); - - virtual ECVarType GetRealType () const; - - virtual UCVarValue GetGenericRep (ECVarType type) const; - virtual UCVarValue GetFavoriteRep (ECVarType *type) const; - virtual UCVarValue GetGenericRepDefault (ECVarType type) const; - virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; - virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); - const char *GetHumanString(int precision) const override; - - float operator= (float floatval) - { UCVarValue val; val.Float = floatval; SetGenericRep (val, CVAR_Float); return floatval; } - inline operator float () const { return Value; } - inline float operator *() const { return Value; } - -protected: - virtual void DoSet (UCVarValue value, ECVarType type); - - float Value; - float DefaultValue; -}; - -class FStringCVar : public FBaseCVar -{ - friend class FxCVar; -public: - FStringCVar (const char *name, const char *def, uint32_t flags, void (*callback)(FStringCVar &)=NULL); - ~FStringCVar (); - - virtual ECVarType GetRealType () const; - - virtual UCVarValue GetGenericRep (ECVarType type) const; - virtual UCVarValue GetFavoriteRep (ECVarType *type) const; - virtual UCVarValue GetGenericRepDefault (ECVarType type) const; - virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; - virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); - - const char *operator= (const char *stringrep) - { UCVarValue val; val.String = const_cast(stringrep); SetGenericRep (val, CVAR_String); return stringrep; } - inline operator const char * () const { return Value; } - inline const char *operator *() const { return Value; } - -protected: - virtual void DoSet (UCVarValue value, ECVarType type); - - char *Value; - char *DefaultValue; -}; - -class FColorCVar : public FIntCVar -{ - friend class FxCVar; -public: - FColorCVar (const char *name, int def, uint32_t flags, void (*callback)(FColorCVar &)=NULL); - - virtual ECVarType GetRealType () const; - - virtual UCVarValue GetGenericRep (ECVarType type) const; - virtual UCVarValue GetGenericRepDefault (ECVarType type) const; - virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); - - inline operator uint32_t () const { return Value; } - inline uint32_t operator *() const { return Value; } - inline int GetIndex () const { return Index; } - -protected: - virtual void DoSet (UCVarValue value, ECVarType type); - - static UCVarValue FromInt2 (int value, ECVarType type); - static int ToInt2 (UCVarValue value, ECVarType type); - - int Index; -}; - -class FFlagCVar : public FBaseCVar -{ - friend class FxCVar; -public: - FFlagCVar (const char *name, FIntCVar &realvar, uint32_t bitval); - - virtual ECVarType GetRealType () const; - - virtual UCVarValue GetGenericRep (ECVarType type) const; - virtual UCVarValue GetFavoriteRep (ECVarType *type) const; - virtual UCVarValue GetGenericRepDefault (ECVarType type) const; - virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; - virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); - - bool operator= (bool boolval) - { UCVarValue val; val.Bool = boolval; SetGenericRep (val, CVAR_Bool); return boolval; } - bool operator= (FFlagCVar &flag) - { UCVarValue val; val.Bool = !!flag; SetGenericRep (val, CVAR_Bool); return val.Bool; } - inline operator int () const { return (ValueVar & BitVal); } - inline int operator *() const { return (ValueVar & BitVal); } - -protected: - virtual void DoSet (UCVarValue value, ECVarType type); - - FIntCVar &ValueVar; - uint32_t BitVal; - int BitNum; -}; - -class FMaskCVar : public FBaseCVar -{ - friend class FxCVar; -public: - FMaskCVar (const char *name, FIntCVar &realvar, uint32_t bitval); - - virtual ECVarType GetRealType () const; - - virtual UCVarValue GetGenericRep (ECVarType type) const; - virtual UCVarValue GetFavoriteRep (ECVarType *type) const; - virtual UCVarValue GetGenericRepDefault (ECVarType type) const; - virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const; - virtual void SetGenericRepDefault (UCVarValue value, ECVarType type); - - inline operator int () const { return (ValueVar & BitVal) >> BitNum; } - inline int operator *() const { return (ValueVar & BitVal) >> BitNum; } - -protected: - virtual void DoSet (UCVarValue value, ECVarType type); - - FIntCVar &ValueVar; - uint32_t BitVal; - int BitNum; -}; - -extern int cvar_defflags; - -FBaseCVar *cvar_set (const char *var_name, const char *value); -FBaseCVar *cvar_forceset (const char *var_name, const char *value); - -inline FBaseCVar *cvar_set (const char *var_name, const uint8_t *value) { return cvar_set (var_name, (const char *)value); } -inline FBaseCVar *cvar_forceset (const char *var_name, const uint8_t *value) { return cvar_forceset (var_name, (const char *)value); } - - - -// Restore demo cvars. Called after demo playback to restore all cvars -// that might possibly have been changed during the course of demo playback. -void C_RestoreCVars (void); - -void C_ForgetCVars (void); - - -#define CUSTOM_CVAR(type,name,def,flags) \ - static void cvarfunc_##name(F##type##CVar &); \ - F##type##CVar name (#name, def, flags, cvarfunc_##name); \ - static void cvarfunc_##name(F##type##CVar &self) - -#define CVAR(type,name,def,flags) \ - F##type##CVar name (#name, def, flags); - -#define EXTERN_CVAR(type,name) extern F##type##CVar name; - -extern FBaseCVar *CVars; - -#endif //__C_CVARS_H__ diff --git a/src/console/c_dispatch.cpp b/src/console/c_dispatch.cpp deleted file mode 100644 index 1921e2be334..00000000000 --- a/src/console/c_dispatch.cpp +++ /dev/null @@ -1,1683 +0,0 @@ -/* -** c_dispatch.cpp -** Functions for executing console commands and aliases -** -**--------------------------------------------------------------------------- -** Copyright 1998-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include - -#include "templates.h" -#include "doomtype.h" -#include "cmdlib.h" -#include "c_console.h" -#include "c_dispatch.h" -#include "m_argv.h" -#include "g_game.h" -#include "d_player.h" -#include "configfile.h" -#include "v_text.h" -#include "d_net.h" -#include "d_main.h" -#include "serializer.h" -#include "menu/menu.h" -#include "vm.h" -#include "g_levellocals.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -class UnsafeExecutionScope -{ - const bool wasEnabled; - -public: - explicit UnsafeExecutionScope(const bool enable = true) - : wasEnabled(UnsafeExecutionContext) - { - UnsafeExecutionContext = enable; - } - - ~UnsafeExecutionScope() - { - UnsafeExecutionContext = wasEnabled; - } -}; - -class FDelayedCommand -{ -public: - virtual ~FDelayedCommand() {} - -protected: - virtual bool Tick() = 0; - - friend class FDelayedCommandQueue; -}; - -class FWaitingCommand : public FDelayedCommand -{ -public: - FWaitingCommand(const char *cmd, int tics, bool unsafe) - : Command(cmd), TicsLeft(tics+1), IsUnsafe(unsafe) - {} - - bool Tick() override - { - if (--TicsLeft == 0) - { - UnsafeExecutionScope scope(IsUnsafe); - AddCommandString(Command); - return true; - } - return false; - } - - FString Command; - int TicsLeft; - bool IsUnsafe; -}; - -class FStoredCommand : public FDelayedCommand -{ -public: - FStoredCommand(FConsoleCommand *com, const char *cmd) - : Command(com), Text(cmd) - {} - - bool Tick() override - { - if (Text.IsNotEmpty() && Command != nullptr) - { - FCommandLine args(Text); - Command->Run(args, players[consoleplayer].mo, 0); - } - return true; - } - -private: - - FConsoleCommand *Command; - FString Text; -}; - -class FDelayedCommandQueue -{ - TDeletingArray delayedCommands; -public: - void Run() - { - for (unsigned i = 0; i < delayedCommands.Size(); i++) - { - if (delayedCommands[i]->Tick()) - { - delete delayedCommands[i]; - delayedCommands.Delete(i); - i--; - } - } - } - - void Clear() - { - delayedCommands.DeleteAndClear(); - } - - void AddCommand(FDelayedCommand * cmd) - { - delayedCommands.Push(cmd); - } -}; - -static FDelayedCommandQueue delayedCommandQueue; - -void C_RunDelayedCommands() -{ - delayedCommandQueue.Run(); -} - -void C_ClearDelayedCommands() -{ - delayedCommandQueue.Clear(); -} - - - -struct FActionMap -{ - FButtonStatus *Button; - unsigned int Key; // value from passing Name to MakeKey() - char Name[12]; -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static long ParseCommandLine (const char *args, int *argc, char **argv, bool no_escapes); -static FConsoleCommand *FindNameInHashTable (FConsoleCommand **table, const char *name, size_t namelen); -static FConsoleCommand *ScanChainForName (FConsoleCommand *start, const char *name, size_t namelen, FConsoleCommand **prev); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -CVAR (Bool, lookspring, true, CVAR_ARCHIVE); // Generate centerview when -mlook encountered? - -FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE]; -FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack, - Button_Attack, Button_Speed, Button_MoveRight, Button_MoveLeft, - Button_Strafe, Button_LookDown, Button_LookUp, Button_Back, - Button_Forward, Button_Right, Button_Left, Button_MoveDown, - Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch, - Button_Zoom, Button_Reload, - Button_User1, Button_User2, Button_User3, Button_User4, - Button_AM_PanLeft, Button_AM_PanRight, Button_AM_PanDown, Button_AM_PanUp, - Button_AM_ZoomIn, Button_AM_ZoomOut; - -bool ParsingKeyConf, UnsafeExecutionContext; - - -// To add new actions, go to the console and type "key ". -// This will give you the key value to use in the first column. Then -// insert your new action into this list so that the keys remain sorted -// in ascending order. No two keys can be identical. If yours matches -// an existing key, change the name of your action. - -FActionMap ActionMaps[] = -{ - { &Button_AM_PanLeft, 0x0d52d67b, "am_panleft"}, - { &Button_User2, 0x125f5226, "user2" }, - { &Button_Jump, 0x1eefa611, "jump" }, - { &Button_Right, 0x201f1c55, "right" }, - { &Button_Zoom, 0x20ccc4d5, "zoom" }, - { &Button_Back, 0x23a99cd7, "back" }, - { &Button_AM_ZoomIn, 0x41df90c2, "am_zoomin"}, - { &Button_Reload, 0x426b69e7, "reload" }, - { &Button_LookDown, 0x4463f43a, "lookdown" }, - { &Button_AM_ZoomOut, 0x51f7a334, "am_zoomout"}, - { &Button_User4, 0x534c30ee, "user4" }, - { &Button_Attack, 0x5622bf42, "attack" }, - { &Button_User1, 0x577712d0, "user1" }, - { &Button_Klook, 0x57c25cb2, "klook" }, - { &Button_Forward, 0x59f3e907, "forward" }, - { &Button_MoveDown, 0x6167ce99, "movedown" }, - { &Button_AltAttack, 0x676885b8, "altattack" }, - { &Button_MoveLeft, 0x6fa41b84, "moveleft" }, - { &Button_MoveRight, 0x818f08e6, "moveright" }, - { &Button_AM_PanRight, 0x8197097b, "am_panright"}, - { &Button_AM_PanUp, 0x8d89955e, "am_panup"} , - { &Button_Mlook, 0xa2b62d8b, "mlook" }, - { &Button_Crouch, 0xab2c3e71, "crouch" }, - { &Button_Left, 0xb000b483, "left" }, - { &Button_LookUp, 0xb62b1e49, "lookup" }, - { &Button_User3, 0xb6f8fe92, "user3" }, - { &Button_Strafe, 0xb7e6a54b, "strafe" }, - { &Button_AM_PanDown, 0xce301c81, "am_pandown"}, - { &Button_ShowScores, 0xd5897c73, "showscores" }, - { &Button_Speed, 0xe0ccb317, "speed" }, - { &Button_Use, 0xe0cfc260, "use" }, - { &Button_MoveUp, 0xfdd701c7, "moveup" }, -}; -#define NUM_ACTIONS countof(ActionMaps) - - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static const char *KeyConfCommands[] = -{ - "alias", - "defaultbind", - "addkeysection", - "addmenukey", - "addslotdefault", - "weaponsection", - "setslot", - "addplayerclass", - "clearplayerclasses" -}; - -// CODE -------------------------------------------------------------------- - - -static int ListActionCommands (const char *pattern) -{ - char matcher[16]; - unsigned int i; - int count = 0; - - for (i = 0; i < NUM_ACTIONS; ++i) - { - if (pattern == NULL || CheckWildcards (pattern, - (mysnprintf (matcher, countof(matcher), "+%s", ActionMaps[i].Name), matcher))) - { - Printf ("+%s\n", ActionMaps[i].Name); - count++; - } - if (pattern == NULL || CheckWildcards (pattern, - (mysnprintf (matcher, countof(matcher), "-%s", ActionMaps[i].Name), matcher))) - { - Printf ("-%s\n", ActionMaps[i].Name); - count++; - } - } - return count; -} - -/* ======================================================================== */ - -/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh derivative - license. See: - http://www.azillionmonkeys.com/qed/weblicense.html for license details. - - http://www.azillionmonkeys.com/qed/hash.html */ - -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) -#endif - -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif - -uint32_t SuperFastHash (const char *data, size_t len) -{ - uint32_t hash = 0, tmp; - size_t rem; - - if (len == 0 || data == NULL) return 0; - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (;len > 0; len--) - { - hash += get16bits (data); - tmp = (get16bits (data+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2*sizeof (uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) - { - case 3: hash += get16bits (data); - hash ^= hash << 16; - hash ^= data[sizeof (uint16_t)] << 18; - hash += hash >> 11; - break; - case 2: hash += get16bits (data); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += *data; - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -/* A modified version to do a case-insensitive hash */ - -#undef get16bits -#define get16bits(d) ((((uint32_t)tolower(((const uint8_t *)(d))[1])) << 8)\ - +(uint32_t)tolower(((const uint8_t *)(d))[0]) ) - -uint32_t SuperFastHashI (const char *data, size_t len) -{ - uint32_t hash = 0, tmp; - size_t rem; - - if (len <= 0 || data == NULL) return 0; - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (;len > 0; len--) - { - hash += get16bits (data); - tmp = (get16bits (data+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2*sizeof (uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) - { - case 3: hash += get16bits (data); - hash ^= hash << 16; - hash ^= tolower(data[sizeof (uint16_t)]) << 18; - hash += hash >> 11; - break; - case 2: hash += get16bits (data); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += tolower(*data); - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -/* ======================================================================== */ - -unsigned int MakeKey (const char *s) -{ - if (s == NULL) - { - return 0; - } - return SuperFastHashI (s, strlen (s)); -} - -unsigned int MakeKey (const char *s, size_t len) -{ - return SuperFastHashI (s, len); -} - -// FindButton scans through the actionbits[] array -// for a matching key and returns an index or -1 if -// the key could not be found. This uses binary search, -// so actionbits[] must be sorted in ascending order. - -FButtonStatus *FindButton (unsigned int key) -{ - const FActionMap *bit; - - bit = BinarySearch - (ActionMaps, NUM_ACTIONS, &FActionMap::Key, key); - return bit ? bit->Button : NULL; -} - -bool FButtonStatus::PressKey (int keynum) -{ - int i, open; - - keynum &= KEY_DBLCLICKED-1; - - if (keynum == 0) - { // Issued from console instead of a key, so force on - Keys[0] = 0xffff; - for (i = MAX_KEYS-1; i > 0; --i) - { - Keys[i] = 0; - } - } - else - { - for (i = MAX_KEYS-1, open = -1; i >= 0; --i) - { - if (Keys[i] == 0) - { - open = i; - } - else if (Keys[i] == keynum) - { // Key is already down; do nothing - return false; - } - } - if (open < 0) - { // No free key slots, so do nothing - Printf ("More than %u keys pressed for a single action!\n", MAX_KEYS); - return false; - } - Keys[open] = keynum; - } - uint8_t wasdown = bDown; - bDown = bWentDown = true; - // Returns true if this key caused the button to go down. - return !wasdown; -} - -bool FButtonStatus::ReleaseKey (int keynum) -{ - int i, numdown, match; - uint8_t wasdown = bDown; - - keynum &= KEY_DBLCLICKED-1; - - if (keynum == 0) - { // Issued from console instead of a key, so force off - for (i = MAX_KEYS-1; i >= 0; --i) - { - Keys[i] = 0; - } - bWentUp = true; - bDown = false; - } - else - { - for (i = MAX_KEYS-1, numdown = 0, match = -1; i >= 0; --i) - { - if (Keys[i] != 0) - { - ++numdown; - if (Keys[i] == keynum) - { - match = i; - } - } - } - if (match < 0) - { // Key was not down; do nothing - return false; - } - Keys[match] = 0; - bWentUp = true; - if (--numdown == 0) - { - bDown = false; - } - } - // Returns true if releasing this key caused the button to go up. - return wasdown && !bDown; -} - -void ResetButtonTriggers () -{ - for (int i = NUM_ACTIONS-1; i >= 0; --i) - { - ActionMaps[i].Button->ResetTriggers (); - } -} - -void ResetButtonStates () -{ - for (int i = NUM_ACTIONS-1; i >= 0; --i) - { - FButtonStatus *button = ActionMaps[i].Button; - - if (button != &Button_Mlook && button != &Button_Klook) - { - button->ReleaseKey (0); - } - button->ResetTriggers (); - } -} - -void C_DoCommand (const char *cmd, int keynum) -{ - FConsoleCommand *com; - const char *end; - const char *beg; - - // Skip any beginning whitespace - while (*cmd > 0 && *cmd <= ' ') - cmd++; - - // Find end of the command name - if (*cmd == '\"') - { - for (end = beg = cmd+1; *end && *end != '\"'; ++end) - ; - } - else - { - beg = cmd; - for (end = cmd+1; *end > ' ' || *end < 0; ++end) - ; - } - - const size_t len = end - beg; - - if (ParsingKeyConf) - { - int i; - - for (i = countof(KeyConfCommands)-1; i >= 0; --i) - { - if (strnicmp (beg, KeyConfCommands[i], len) == 0 && - KeyConfCommands[i][len] == 0) - { - break; - } - } - if (i < 0) - { - Printf ("Invalid command for KEYCONF: %s\n", beg); - return; - } - } - - // Check if this is an action - if (*beg == '+' || *beg == '-') - { - FButtonStatus *button; - - button = FindButton (MakeKey (beg + 1, end - beg - 1)); - if (button != NULL) - { - if (*beg == '+') - { - button->PressKey (keynum); - } - else - { - button->ReleaseKey (keynum); - if (button == &Button_Mlook && lookspring) - { - Net_WriteByte (DEM_CENTERVIEW); - } - } - return; - } - } - - // Parse it as a normal command - // Checking for matching commands follows this search order: - // 1. Check the Commands[] hash table - // 2. Check the CVars list - - if ( (com = FindNameInHashTable (Commands, beg, len)) ) - { - if (gamestate != GS_STARTUP || ParsingKeyConf || - (len == 3 && strnicmp (beg, "set", 3) == 0) || - (len == 7 && strnicmp (beg, "logfile", 7) == 0) || - (len == 9 && strnicmp (beg, "unbindall", 9) == 0) || - (len == 4 && strnicmp (beg, "bind", 4) == 0) || - (len == 4 && strnicmp (beg, "exec", 4) == 0) || - (len ==10 && strnicmp (beg, "doublebind", 10) == 0) || - (len == 6 && strnicmp (beg, "pullin", 6) == 0) - ) - { - FCommandLine args (beg); - com->Run (args, players[consoleplayer].mo, keynum); - } - else - { - if (len == 4 && strnicmp(beg, "warp", 4) == 0) - { - StoredWarp = beg; - } - else - { - auto cmd = new FStoredCommand(com, beg); - delayedCommandQueue.AddCommand(cmd); - } - } - } - else - { // Check for any console vars that match the command - FBaseCVar *var = FindCVarSub (beg, int(len)); - - if (var != NULL) - { - FCommandLine args (beg); - - if (args.argc() >= 2) - { // Set the variable - var->CmdSet (args[1]); - } - else - { // Get the variable's value - Printf ("\"%s\" is \"%s\"\n", var->GetName(), var->GetHumanString()); - } - } - else - { // We don't know how to handle this command - Printf ("Unknown command \"%.*s\"\n", (int)len, beg); - } - } -} - -// This is only accessible to the special menu item to run CCMDs. -DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand) -{ - if (CurrentMenu == nullptr) return 0; - PARAM_PROLOGUE; - PARAM_STRING(cmd); - PARAM_BOOL(unsafe); - UnsafeExecutionScope scope(unsafe); - C_DoCommand(cmd); - return 0; -} - -void AddCommandString (const char *text, int keynum) -{ - // Operate on a local copy instead of messing around with the data that's being passed in here. - TArray buffer(strlen(text) + 1, true); - memcpy(buffer.Data(), text, buffer.Size()); - char *cmd = buffer.Data(); - char *brkpt; - int more; - - if (cmd) - { - while (*cmd) - { - brkpt = cmd; - while (*brkpt != ';' && *brkpt != '\0') - { - if (*brkpt == '\"') - { - brkpt++; - while (*brkpt != '\0' && (*brkpt != '\"' || *(brkpt-1) == '\\')) - brkpt++; - } - if (*brkpt != '\0') - brkpt++; - } - if (*brkpt == ';') - { - *brkpt = '\0'; - more = 1; - } - else - { - more = 0; - } - // Intercept wait commands here. Note: wait must be lowercase - while (*cmd > 0 && *cmd <= ' ') - cmd++; - if (*cmd) - { - if (!ParsingKeyConf && - cmd[0] == 'w' && cmd[1] == 'a' && cmd[2] == 'i' && cmd[3] == 't' && - (cmd[4] == 0 || cmd[4] == ' ')) - { - int tics; - - if (cmd[4] == ' ') - { - tics = (int)strtoll (cmd + 5, NULL, 0); - } - else - { - tics = 1; - } - if (tics > 0) - { - if (more) - { // The remainder of the command will be executed later - // Note that deferred commands lose track of which key - // (if any) they were pressed from. - *brkpt = ';'; - auto cmd = new FWaitingCommand(brkpt, tics, UnsafeExecutionContext); - delayedCommandQueue.AddCommand(cmd); - } - return; - } - } - else - { - C_DoCommand (cmd, keynum); - } - } - if (more) - { - *brkpt = ';'; - } - cmd = brkpt + more; - } - } -} - -// ParseCommandLine -// -// Parse a command line (passed in args). If argc is non-NULL, it will -// be set to the number of arguments. If argv is non-NULL, it will be -// filled with pointers to each argument; argv[0] should be initialized -// to point to a buffer large enough to hold all the arguments. The -// return value is the necessary size of this buffer. -// -// Special processing: -// Inside quoted strings, \" becomes just " -// \\ becomes just a single backslash -// \c becomes just TEXTCOLOR_ESCAPE -// $ is replaced by the contents of - -static long ParseCommandLine (const char *args, int *argc, char **argv, bool no_escapes) -{ - int count; - char *buffplace; - - count = 0; - buffplace = NULL; - if (argv != NULL) - { - buffplace = argv[0]; - } - - for (;;) - { - while (*args <= ' ' && *args) - { // skip white space - args++; - } - if (*args == 0) - { - break; - } - else if (*args == '\"') - { // read quoted string - char stuff; - if (argv != NULL) - { - argv[count] = buffplace; - } - count++; - args++; - do - { - stuff = *args++; - if (!no_escapes && stuff == '\\' && *args == '\"') - { - stuff = '\"', args++; - } - else if (!no_escapes && stuff == '\\' && *args == '\\') - { - args++; - } - else if (!no_escapes && stuff == '\\' && *args == 'c') - { - stuff = TEXTCOLOR_ESCAPE, args++; - } - else if (stuff == '\"') - { - stuff = 0; - } - else if (stuff == 0) - { - args--; - } - if (argv != NULL) - { - *buffplace = stuff; - } - buffplace++; - } while (stuff); - } - else - { // read unquoted string - const char *start = args++, *end; - FBaseCVar *var; - UCVarValue val; - - while (*args && *args > ' ' && *args != '\"') - args++; - if (*start == '$' && (var = FindCVarSub (start+1, int(args-start-1)))) - { - val = var->GetGenericRep (CVAR_String); - start = val.String; - end = start + strlen (start); - } - else - { - end = args; - } - if (argv != NULL) - { - argv[count] = buffplace; - while (start < end) - *buffplace++ = *start++; - *buffplace++ = 0; - } - else - { - buffplace += end - start + 1; - } - count++; - } - } - if (argc != NULL) - { - *argc = count; - } - return (long)(buffplace - (char *)0); -} - -FCommandLine::FCommandLine (const char *commandline, bool no_escapes) -{ - cmd = commandline; - _argc = -1; - _argv = NULL; - noescapes = no_escapes; -} - -FCommandLine::~FCommandLine () -{ - if (_argv != NULL) - { - delete[] _argv; - } -} - -void FCommandLine::Shift() -{ - // Only valid after _argv has been filled. - for (int i = 1; i < _argc; ++i) - { - _argv[i - 1] = _argv[i]; - } -} - -int FCommandLine::argc () -{ - if (_argc == -1) - { - argsize = ParseCommandLine (cmd, &_argc, NULL, noescapes); - } - return _argc; -} - -char *FCommandLine::operator[] (int i) -{ - if (_argv == NULL) - { - int count = argc(); - _argv = new char *[count + (argsize+sizeof(char*)-1)/sizeof(char*)]; - _argv[0] = (char *)_argv + count*sizeof(char *); - ParseCommandLine (cmd, NULL, _argv, noescapes); - } - return _argv[i]; -} - -static FConsoleCommand *ScanChainForName (FConsoleCommand *start, const char *name, size_t namelen, FConsoleCommand **prev) -{ - int comp; - - *prev = NULL; - while (start) - { - comp = strnicmp (start->m_Name, name, namelen); - if (comp > 0) - return NULL; - else if (comp == 0 && start->m_Name[namelen] == 0) - return start; - - *prev = start; - start = start->m_Next; - } - return NULL; -} - -static FConsoleCommand *FindNameInHashTable (FConsoleCommand **table, const char *name, size_t namelen) -{ - FConsoleCommand *dummy; - - return ScanChainForName (table[MakeKey (name, namelen) % FConsoleCommand::HASH_SIZE], name, namelen, &dummy); -} - -bool FConsoleCommand::AddToHash (FConsoleCommand **table) -{ - unsigned int key; - FConsoleCommand *insert, **bucket; - - key = MakeKey (m_Name); - bucket = &table[key % HASH_SIZE]; - - if (ScanChainForName (*bucket, m_Name, strlen (m_Name), &insert)) - { - return false; - } - else - { - if (insert) - { - m_Next = insert->m_Next; - if (m_Next) - m_Next->m_Prev = &m_Next; - insert->m_Next = this; - m_Prev = &insert->m_Next; - } - else - { - m_Next = *bucket; - *bucket = this; - m_Prev = bucket; - if (m_Next) - m_Next->m_Prev = &m_Next; - } - } - return true; -} - -FConsoleCommand* FConsoleCommand::FindByName (const char* name) -{ - return FindNameInHashTable (Commands, name, strlen (name)); -} - -FConsoleCommand::FConsoleCommand (const char *name, CCmdRun runFunc) - : m_RunFunc (runFunc) -{ - static bool firstTime = true; - - if (firstTime) - { - char tname[16]; - unsigned int i; - - firstTime = false; - - // Add all the action commands for tab completion - for (i = 0; i < NUM_ACTIONS; i++) - { - strcpy (&tname[1], ActionMaps[i].Name); - tname[0] = '+'; - C_AddTabCommand (tname); - tname[0] = '-'; - C_AddTabCommand (tname); - } - } - - int ag = strcmp (name, "kill"); - if (ag == 0) - ag=0; - m_Name = copystring (name); - - if (!AddToHash (Commands)) - Printf ("FConsoleCommand c'tor: %s exists\n", name); - else - C_AddTabCommand (name); -} - -FConsoleCommand::~FConsoleCommand () -{ - *m_Prev = m_Next; - if (m_Next) - m_Next->m_Prev = m_Prev; - C_RemoveTabCommand (m_Name); - delete[] m_Name; -} - -void FConsoleCommand::Run (FCommandLine &argv, AActor *who, int key) -{ - m_RunFunc (argv, who, key); -} - -void FUnsafeConsoleCommand::Run (FCommandLine &args, AActor *instigator, int key) -{ - if (UnsafeExecutionContext) - { - Printf(TEXTCOLOR_RED "Cannot execute unsafe command " TEXTCOLOR_GOLD "%s\n", m_Name); - return; - } - - FConsoleCommand::Run (args, instigator, key); -} - -FConsoleAlias::FConsoleAlias (const char *name, const char *command, bool noSave) - : FConsoleCommand (name, NULL), - bRunning(false), bKill(false) -{ - m_Command[noSave] = command; - m_Command[!noSave] = FString(); - // If the command contains % characters, assume they are parameter markers - // for substitution when the command is executed. - bDoSubstitution = (strchr (command, '%') != NULL); -} - -FConsoleAlias::~FConsoleAlias () -{ - m_Command[1] = m_Command[0] = FString(); -} - -// Given an argument vector, reconstitute the command line it could have been produced from. -FString BuildString (int argc, FString *argv) -{ - if (argc == 1) - { - return *argv; - } - else - { - FString buf; - int arg; - - for (arg = 0; arg < argc; arg++) - { - if (argv[arg][0] == '\0') - { // It's an empty argument, we need to convert it to '""' - buf << "\"\" "; - } - else if (strchr(argv[arg], '"')) - { // If it contains one or more quotes, we need to escape them. - buf << '"'; - long substr_start = 0, quotepos; - while ((quotepos = argv[arg].IndexOf('"', substr_start)) >= 0) - { - if (substr_start < quotepos) - { - buf << argv[arg].Mid(substr_start, quotepos - substr_start); - } - buf << "\\\""; - substr_start = quotepos + 1; - } - buf << argv[arg].Mid(substr_start) << "\" "; - } - else if (strchr(argv[arg], ' ')) - { // If it contains a space, it needs to be quoted. - buf << '"' << argv[arg] << "\" "; - } - else - { - buf << argv[arg] << ' '; - } - } - return buf; - } -} - -//=========================================================================== -// -// SubstituteAliasParams -// -// Given an command line and a set of arguments, replace instances of -// %x or %{x} in the command line with argument x. If argument x does not -// exist, then the empty string is substituted in its place. -// -// Substitution is not done inside of quoted strings, unless that string is -// prepended with a % character. -// -// To avoid a substitution, use %%. The %% will be replaced by a single %. -// -//=========================================================================== - -void FConsoleCommand::PrintCommand() -{ - Printf("%s\n", m_Name); -} - -FString SubstituteAliasParams (FString &command, FCommandLine &args) -{ - // Do substitution by replacing %x with the argument x. - // If there is no argument x, then %x is simply removed. - - // For some reason, strtoul's stop parameter is non-const. - char *p = command.LockBuffer(), *start = p; - unsigned long argnum; - FString buf; - bool inquote = false; - - while (*p != '\0') - { - if (p[0] == '%' && ((p[1] >= '0' && p[1] <= '9') || p[1] == '{')) - { - // Do a substitution. Output what came before this. - buf.AppendCStrPart (start, p - start); - - // Extract the argument number and substitute the corresponding argument. - argnum = strtoul (p + 1 + (p[1] == '{'), &start, 10); - if ((p[1] != '{' || *start == '}') && argnum < (unsigned long)args.argc()) - { - buf += args[argnum]; - } - p = (start += (p[1] == '{' && *start == '}')); - } - else if (p[0] == '%' && p[1] == '%') - { - // Do not substitute. Just collapse to a single %. - buf.AppendCStrPart (start, p - start + 1); - start = p = p + 2; - continue; - } - else if (p[0] == '%' && p[1] == '"') - { - // Collapse %" to " and remember that we're in a quote so when we - // see a " character again, we don't start skipping below. - if (!inquote) - { - inquote = true; - buf.AppendCStrPart(start, p - start); - start = p + 1; - } - else - { - inquote = false; - } - p += 2; - } - else if (p[0] == '\\' && p[1] == '"') - { - p += 2; - } - else if (p[0] == '"') - { - // Don't substitute inside quoted strings if it didn't start - // with a %" - if (!inquote) - { - p++; - while (*p != '\0' && (*p != '"' || *(p-1) == '\\')) - p++; - if (*p != '\0') - p++; - } - else - { - inquote = false; - p++; - } - } - else - { - p++; - } - } - // Return whatever was after the final substitution. - if (p > start) - { - buf.AppendCStrPart (start, p - start); - } - command.UnlockBuffer(); - - return buf; -} - -static int DumpHash (FConsoleCommand **table, bool aliases, const char *pattern=NULL) -{ - int bucket, count; - FConsoleCommand *cmd; - - for (bucket = count = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++) - { - cmd = table[bucket]; - while (cmd) - { - if (CheckWildcards (pattern, cmd->m_Name)) - { - if (cmd->IsAlias()) - { - if (aliases) - { - ++count; - static_cast(cmd)->PrintAlias (); - } - } - else if (!aliases) - { - ++count; - cmd->PrintCommand (); - } - } - cmd = cmd->m_Next; - } - } - return count; -} - -void FConsoleAlias::PrintAlias () -{ - if (m_Command[0].IsNotEmpty()) - { - Printf (TEXTCOLOR_YELLOW "%s : %s\n", m_Name, m_Command[0].GetChars()); - } - if (m_Command[1].IsNotEmpty()) - { - Printf (TEXTCOLOR_ORANGE "%s : %s\n", m_Name, m_Command[1].GetChars()); - } -} - -void FConsoleAlias::Archive (FConfigFile *f) -{ - if (f != NULL && !m_Command[0].IsEmpty()) - { - f->SetValueForKey ("Name", m_Name, true); - f->SetValueForKey ("Command", m_Command[0], true); - } -} - -void C_ArchiveAliases (FConfigFile *f) -{ - int bucket; - FConsoleCommand *alias; - - for (bucket = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++) - { - alias = Commands[bucket]; - while (alias) - { - if (alias->IsAlias()) - static_cast(alias)->Archive (f); - alias = alias->m_Next; - } - } -} - -void C_ClearAliases () -{ - int bucket; - FConsoleCommand *alias; - - for (bucket = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++) - { - alias = Commands[bucket]; - while (alias) - { - FConsoleCommand *next = alias->m_Next; - if (alias->IsAlias()) - static_cast(alias)->SafeDelete(); - alias = next; - } - } -} - -CCMD(clearaliases) -{ - C_ClearAliases(); -} - - -// This is called only by the ini parser. -void C_SetAlias (const char *name, const char *cmd) -{ - FConsoleCommand *prev, *alias, **chain; - - chain = &Commands[MakeKey (name) % FConsoleCommand::HASH_SIZE]; - alias = ScanChainForName (*chain, name, strlen (name), &prev); - if (alias != NULL) - { - if (!alias->IsAlias ()) - { - //Printf (PRINT_BOLD, "%s is a command and cannot be an alias.\n", name); - return; - } - delete alias; - } - new FConsoleAlias (name, cmd, false); -} - -CCMD (alias) -{ - FConsoleCommand *prev, *alias, **chain; - - if (argv.argc() == 1) - { - Printf ("Current alias commands:\n"); - DumpHash (Commands, true); - } - else - { - chain = &Commands[MakeKey (argv[1]) % FConsoleCommand::HASH_SIZE]; - - if (argv.argc() == 2) - { // Remove the alias - - if ( (alias = ScanChainForName (*chain, argv[1], strlen (argv[1]), &prev))) - { - if (alias->IsAlias ()) - { - static_cast (alias)->SafeDelete (); - } - else - { - Printf ("%s is a normal command\n", alias->m_Name); - } - } - } - else - { // Add/change the alias - - alias = ScanChainForName (*chain, argv[1], strlen (argv[1]), &prev); - if (alias != NULL) - { - if (alias->IsAlias ()) - { - static_cast (alias)->Realias (argv[2], ParsingKeyConf); - } - else - { - Printf ("%s is a normal command\n", alias->m_Name); - alias = NULL; - } - } - else if (ParsingKeyConf) - { - new FUnsafeConsoleAlias (argv[1], argv[2]); - } - else - { - new FConsoleAlias (argv[1], argv[2], false); - } - } - } -} - -CCMD (cmdlist) -{ - int count; - const char *filter = (argv.argc() == 1 ? NULL : argv[1]); - - count = ListActionCommands (filter); - count += DumpHash (Commands, false, filter); - Printf ("%d commands\n", count); -} - -CCMD (key) -{ - if (argv.argc() > 1) - { - int i; - - for (i = 1; i < argv.argc(); ++i) - { - unsigned int key = MakeKey (argv[i]); - Printf (" 0x%08x\n", key); - } - } -} - -// Execute any console commands specified on the command line. -// These all begin with '+' as opposed to '-'. -FExecList *C_ParseCmdLineParams(FExecList *exec) -{ - for (int currArg = 1; currArg < Args->NumArgs(); ) - { - if (*Args->GetArg (currArg++) == '+') - { - FString cmdString; - int cmdlen = 1; - int argstart = currArg - 1; - - while (currArg < Args->NumArgs()) - { - if (*Args->GetArg (currArg) == '-' || *Args->GetArg (currArg) == '+') - break; - currArg++; - cmdlen++; - } - - cmdString = BuildString (cmdlen, Args->GetArgList (argstart)); - if (!cmdString.IsEmpty()) - { - if (exec == NULL) - { - exec = new FExecList; - } - exec->AddCommand(&cmdString[1]); - } - } - } - return exec; -} - -bool FConsoleCommand::IsAlias () -{ - return false; -} - -bool FConsoleAlias::IsAlias () -{ - return true; -} - -void FConsoleAlias::Run (FCommandLine &args, AActor *who, int key) -{ - if (bRunning) - { - Printf ("Alias %s tried to recurse.\n", m_Name); - return; - } - - int index = !m_Command[1].IsEmpty(); - FString savedcommand = m_Command[index], mycommand; - m_Command[index] = FString(); - - if (bDoSubstitution) - { - mycommand = SubstituteAliasParams (savedcommand, args); - } - else - { - mycommand = savedcommand; - } - - bRunning = true; - AddCommandString (mycommand, key); - bRunning = false; - if (m_Command[index].IsEmpty()) - { // The alias is unchanged, so put the command back so it can be used again. - // If the command had been non-empty, then that means that executing this - // alias caused it to realias itself, so the old command will be forgotten - // once this function returns. - m_Command[index] = savedcommand; - } - if (bKill) - { // The alias wants to remove itself - delete this; - } -} - -void FConsoleAlias::Realias (const char *command, bool noSave) -{ - if (!noSave && !m_Command[1].IsEmpty()) - { - noSave = true; - } - m_Command[noSave] = command; - - // If the command contains % characters, assume they are parameter markers - // for substitution when the command is executed. - bDoSubstitution = (strchr (command, '%') != NULL); - bKill = false; -} - -void FConsoleAlias::SafeDelete () -{ - if (!bRunning) - { - delete this; - } - else - { - bKill = true; - } -} - -void FUnsafeConsoleAlias::Run (FCommandLine &args, AActor *instigator, int key) -{ - UnsafeExecutionScope scope; - FConsoleAlias::Run(args, instigator, key); -} - -void FExecList::AddCommand(const char *cmd, const char *file) -{ - // Pullins are special and need to be separated from general commands. - // They also turned out to be a really bad idea, since they make things - // more complicated. :( - if (file != NULL && strnicmp(cmd, "pullin", 6) == 0 && isspace(cmd[6])) - { - FCommandLine line(cmd); - C_SearchForPullins(this, file, line); - } - // Recursive exec: Parse this file now. - else if (strnicmp(cmd, "exec", 4) == 0 && isspace(cmd[4])) - { - FCommandLine argv(cmd); - for (int i = 1; i < argv.argc(); ++i) - { - C_ParseExecFile(argv[i], this); - } - } - else - { - Commands.Push(cmd); - } -} - -void FExecList::ExecCommands() const -{ - for (unsigned i = 0; i < Commands.Size(); ++i) - { - AddCommandString(Commands[i]); - } -} - -void FExecList::AddPullins(TArray &wads) const -{ - for (unsigned i = 0; i < Pullins.Size(); ++i) - { - D_AddFile(wads, Pullins[i]); - } -} - -FExecList *C_ParseExecFile(const char *file, FExecList *exec) -{ - char cmd[4096]; - int retval = 0; - - FileReader fr; - - if ( (fr.OpenFile(file)) ) - { - while (fr.Gets(cmd, countof(cmd)-1)) - { - // Comments begin with // - char *stop = cmd + strlen(cmd) - 1; - char *comment = cmd; - int inQuote = 0; - - if (*stop == '\n') - *stop-- = 0; - - while (comment < stop) - { - if (*comment == '\"') - { - inQuote ^= 1; - } - else if (!inQuote && *comment == '/' && *(comment + 1) == '/') - { - break; - } - comment++; - } - if (comment == cmd) - { // Comment at line beginning - continue; - } - else if (comment < stop) - { // Comment in middle of line - *comment = 0; - } - if (exec == NULL) - { - exec = new FExecList; - } - exec->AddCommand(cmd, file); - } - } - else - { - Printf ("Could not open \"%s\"\n", file); - } - return exec; -} - -bool C_ExecFile (const char *file) -{ - FExecList *exec = C_ParseExecFile(file, NULL); - if (exec != NULL) - { - exec->ExecCommands(); - if (exec->Pullins.Size() > 0) - { - Printf(TEXTCOLOR_BOLD "Notice: Pullin files were ignored.\n"); - } - delete exec; - } - return exec != NULL; -} - -void C_SearchForPullins(FExecList *exec, const char *file, FCommandLine &argv) -{ - const char *lastSlash; - - assert(exec != NULL); - assert(file != NULL); -#ifdef __unix__ - lastSlash = strrchr(file, '/'); -#else - const char *lastSlash1, *lastSlash2; - - lastSlash1 = strrchr(file, '/'); - lastSlash2 = strrchr(file, '\\'); - lastSlash = MAX(lastSlash1, lastSlash2); -#endif - - for (int i = 1; i < argv.argc(); ++i) - { - // Try looking for the wad in the same directory as the .cfg - // before looking for it in the current directory. - if (lastSlash != NULL) - { - FString path(file, (lastSlash - file) + 1); - path += argv[i]; - if (FileExists(path)) - { - exec->Pullins.Push(path); - continue; - } - } - exec->Pullins.Push(argv[i]); - } -} - -CCMD (pullin) -{ - // Actual handling for pullin is now completely special-cased above - Printf (TEXTCOLOR_BOLD "Pullin" TEXTCOLOR_NORMAL " is only valid from .cfg\n" - "files and only when used at startup.\n"); -} - diff --git a/src/console/c_dispatch.h b/src/console/c_dispatch.h deleted file mode 100644 index 88976d95f5a..00000000000 --- a/src/console/c_dispatch.h +++ /dev/null @@ -1,217 +0,0 @@ -/* -** c_dispatch.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __C_DISPATCH_H__ -#define __C_DISPATCH_H__ - -#include -#include "tarray.h" -#include "zstring.h" - -class FConfigFile; - -// Class that can parse command lines -class FCommandLine -{ -public: - FCommandLine (const char *commandline, bool no_escapes = false); - ~FCommandLine (); - int argc (); - char *operator[] (int i); - const char *args () { return cmd; } - void Shift(); - -private: - const char *cmd; - int _argc; - char **_argv; - long argsize; - bool noescapes; -}; - -// Contains the contents of an exec'ed file -struct FExecList -{ - TArray Commands; - TArray Pullins; - - void AddCommand(const char *cmd, const char *file = nullptr); - void ExecCommands() const; - void AddPullins(TArray &wads) const; -}; - - -extern bool CheckCheatmode (bool printmsg = true); - -FExecList *C_ParseCmdLineParams(FExecList *exec); - -// Add commands to the console as if they were typed in. Can handle wait -// and semicolon-separated commands. This function may modify the source -// string, but the string will be restored to its original state before -// returning. Therefore, commands passed must not be in read-only memory. -void AddCommandString (const char *text, int keynum=0); - -void C_RunDelayedCommands(); -void C_ClearDelayedCommands(); - -// Process a single console command. Does not handle wait. -void C_DoCommand (const char *cmd, int keynum=0); - -FExecList *C_ParseExecFile(const char *file, FExecList *source); -void C_SearchForPullins(FExecList *exec, const char *file, class FCommandLine &args); -bool C_ExecFile(const char *file); - -// Write out alias commands to a file for all current aliases. -void C_ArchiveAliases (FConfigFile *f); - -void C_SetAlias (const char *name, const char *cmd); -void C_ClearAliases (); - -// build a single string out of multiple strings -FString BuildString (int argc, FString *argv); - -class AActor; -typedef void (*CCmdRun) (FCommandLine &argv, AActor *instigator, int key); - -class FConsoleCommand -{ -public: - FConsoleCommand (const char *name, CCmdRun RunFunc); - virtual ~FConsoleCommand (); - virtual bool IsAlias (); - void PrintCommand(); - - virtual void Run (FCommandLine &args, AActor *instigator, int key); - static FConsoleCommand* FindByName (const char* name); - - FConsoleCommand *m_Next, **m_Prev; - char *m_Name; - - enum { HASH_SIZE = 251 }; // Is this prime? - -protected: - FConsoleCommand (); - bool AddToHash (FConsoleCommand **table); - - CCmdRun m_RunFunc; - -}; - -#define CCMD(n) \ - void Cmd_##n (FCommandLine &, AActor *, int key); \ - FConsoleCommand Cmd_##n##_Ref (#n, Cmd_##n); \ - void Cmd_##n (FCommandLine &argv, AActor *who, int key) - -class FUnsafeConsoleCommand : public FConsoleCommand -{ -public: - FUnsafeConsoleCommand (const char *name, CCmdRun RunFunc) - : FConsoleCommand (name, RunFunc) - { - } - - virtual void Run (FCommandLine &args, AActor *instigator, int key) override; -}; - -#define UNSAFE_CCMD(n) \ - static void Cmd_##n (FCommandLine &, AActor *, int key); \ - static FUnsafeConsoleCommand Cmd_##n##_Ref (#n, Cmd_##n); \ - void Cmd_##n (FCommandLine &argv, AActor *who, int key) - -const int KEY_DBLCLICKED = 0x8000; - -class FConsoleAlias : public FConsoleCommand -{ -public: - FConsoleAlias (const char *name, const char *command, bool noSave); - ~FConsoleAlias (); - void Run (FCommandLine &args, AActor *instigator, int key); - bool IsAlias (); - void PrintAlias (); - void Archive (FConfigFile *f); - void Realias (const char *command, bool noSave); - void SafeDelete (); -protected: - FString m_Command[2]; // Slot 0 is saved to the ini, slot 1 is not. - bool bDoSubstitution; - bool bRunning; - bool bKill; -}; - -class FUnsafeConsoleAlias : public FConsoleAlias -{ -public: - FUnsafeConsoleAlias (const char *name, const char *command) - : FConsoleAlias (name, command, true) - { - } - - virtual void Run (FCommandLine &args, AActor *instigator, int key) override; -}; - -// Actions -struct FButtonStatus -{ - enum { MAX_KEYS = 6 }; // Maximum number of keys that can press this button - - uint16_t Keys[MAX_KEYS]; - uint8_t bDown; // Button is down right now - uint8_t bWentDown; // Button went down this tic - uint8_t bWentUp; // Button went up this tic - uint8_t padTo16Bytes; - - bool PressKey (int keynum); // Returns true if this key caused the button to be pressed. - bool ReleaseKey (int keynum); // Returns true if this key is no longer pressed. - void ResetTriggers () { bWentDown = bWentUp = false; } - void Reset () { bDown = bWentDown = bWentUp = false; } -}; - -extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack, - Button_Attack, Button_Speed, Button_MoveRight, Button_MoveLeft, - Button_Strafe, Button_LookDown, Button_LookUp, Button_Back, - Button_Forward, Button_Right, Button_Left, Button_MoveDown, - Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch, - Button_Zoom, Button_Reload, - Button_User1, Button_User2, Button_User3, Button_User4, - Button_AM_PanLeft, Button_AM_PanRight, Button_AM_PanDown, Button_AM_PanUp, - Button_AM_ZoomIn, Button_AM_ZoomOut; -extern bool ParsingKeyConf, UnsafeExecutionContext; - -void ResetButtonTriggers (); // Call ResetTriggers for all buttons -void ResetButtonStates (); // Same as above, but also clear bDown - -#include "superfasthash.h" - -void execLogfile(const char *fn, bool append = false); - -#endif //__C_DISPATCH_H__ diff --git a/src/console/c_functions.cpp b/src/console/c_functions.cpp index 7bbf314cc51..b99c9a5d085 100644 --- a/src/console/c_functions.cpp +++ b/src/console/c_functions.cpp @@ -52,8 +52,8 @@ void C_PrintInfo(AActor *target, bool verbose) void C_AimLine(FTranslatedLineTarget *t, bool nonshootable) { - P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->Angles.Yaw, MISSILERANGE, t, 0., - (nonshootable) ? ALF_CHECKNONSHOOTABLE|ALF_FORCENOSMART : 0); + P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->Angles.Yaw, MISSILERANGE, t, nullAngle, + (nonshootable) ? ALF_CHECKNONSHOOTABLE|ALF_FORCENOSMART|ALF_IGNORENOAUTOAIM : ALF_IGNORENOAUTOAIM); } void C_PrintInv(AActor *target) diff --git a/src/console/c_notifybuffer.cpp b/src/console/c_notifybuffer.cpp new file mode 100644 index 00000000000..4c394c376a7 --- /dev/null +++ b/src/console/c_notifybuffer.cpp @@ -0,0 +1,179 @@ +/* +** c_notifybuffer.cpp +** Implements the buffer for the notification message +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** Copyright 2005-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_console.h" +#include "vm.h" +#include "gamestate.h" +#include "c_cvars.h" +#include "sbar.h" +#include "v_video.h" +#include "i_time.h" +#include "c_notifybufferbase.h" + +struct FNotifyBuffer : public FNotifyBufferBase +{ +public: + void AddString(int printlevel, FString source) override; + void Clear() override; + void Draw() override; + +}; + +static FNotifyBuffer NotifyStrings; + +EXTERN_CVAR(Bool, show_messages) +extern bool generic_ui; +CVAR(Float, con_notifytime, 3.f, CVAR_ARCHIVE) +CVAR(Bool, con_centernotify, false, CVAR_ARCHIVE) +CVAR(Bool, con_pulsetext, false, CVAR_ARCHIVE) + +CUSTOM_CVAR(Int, con_scaletext, 0, CVAR_ARCHIVE) // Scale notify text at high resolutions? +{ + if (self < 0) self = 0; +} + +constexpr int NOTIFYFADETIME = 6; + +CUSTOM_CVAR(Int, con_notifylines, 4, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +{ + NotifyStrings.Shift(self); +} + +void FNotifyBuffer::Clear() +{ + FNotifyBufferBase::Clear(); + if (StatusBar == nullptr) return; + IFVIRTUALPTR(StatusBar, DBaseStatusBar, FlushNotify) + { + VMValue params[] = { (DObject*)StatusBar }; + VMCall(func, params, countof(params), nullptr, 1); + } + +} + +void FNotifyBuffer::AddString(int printlevel, FString source) +{ + if (!show_messages || + source.IsEmpty() || + gamestate == GS_FULLCONSOLE || + gamestate == GS_DEMOSCREEN || + con_notifylines == 0) + return; + + // [MK] allow the status bar to take over notify printing + if (StatusBar != nullptr) + { + IFVIRTUALPTR(StatusBar, DBaseStatusBar, ProcessNotify) + { + VMValue params[] = { (DObject*)StatusBar, printlevel, &source }; + int rv; + VMReturn ret(&rv); + VMCall(func, params, countof(params), &ret, 1); + if (!!rv) return; + } + } + + int width = DisplayWidth / active_con_scaletext(twod, generic_ui); + FFont *font = generic_ui ? NewSmallFont : AlternativeSmallFont; + FNotifyBufferBase::AddString(printlevel & PRINT_TYPES, font, source, width, con_notifytime, con_notifylines); +} + +void FNotifyBuffer::Draw() +{ + bool center = (con_centernotify != 0.f); + int line, lineadv, color, j; + bool canskip; + + FFont* font = generic_ui ? NewSmallFont : AlternativeSmallFont; + + line = Top + font->GetDisplacement(); + canskip = true; + + lineadv = font->GetHeight (); + + for (unsigned i = 0; i < Text.Size(); ++ i) + { + FNotifyText ¬ify = Text[i]; + + if (notify.TimeOut == 0) + continue; + + j = notify.TimeOut - notify.Ticker; + if (j > 0) + { + double alpha = (j < NOTIFYFADETIME) ? 1. * j / NOTIFYFADETIME : 1; + if (con_pulsetext) + { + alpha *= 0.7 + 0.3 * sin(I_msTime() / 100.); + } + + if (notify.PrintLevel >= PRINTLEVELS) + color = CR_UNTRANSLATED; + else + color = PrintColors[notify.PrintLevel]; + + int scale = active_con_scaletext(twod, generic_ui); + if (!center) + DrawText(twod, font, color, 0, line, notify.Text.GetChars(), + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, + DTA_KeepRatio, true, + DTA_Alpha, alpha, TAG_DONE); + else + DrawText(twod, font, color, (twod->GetWidth() - + font->StringWidth (notify.Text) * scale) / 2 / scale, + line, notify.Text.GetChars(), + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, + DTA_KeepRatio, true, + DTA_Alpha, alpha, TAG_DONE); + line += lineadv; + canskip = false; + } + else + { + notify.TimeOut = 0; + } + } + if (canskip) + { + Top = TopGoal; + } +} + +void SetConsoleNotifyBuffer() +{ + C_SetNotifyBuffer(&NotifyStrings); +} diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index ea80df71fec..a12bb9f205a 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -36,12 +36,15 @@ #include "d_gui.h" #include "g_input.h" #include "d_net.h" -#include "d_event.h" +#include "d_eventbase.h" #include "sbar.h" #include "v_video.h" #include "utf8.h" #include "gstrings.h" #include "vm.h" +#include "c_buttons.h" +#include "d_buttons.h" +#include "v_draw.h" enum { @@ -49,8 +52,6 @@ enum }; -EXTERN_CVAR (Int, con_scaletext) - EXTERN_CVAR (Bool, sb_cooperative_enable) EXTERN_CVAR (Bool, sb_deathmatch_enable) EXTERN_CVAR (Bool, sb_teamdeathmatch_enable) @@ -64,8 +65,6 @@ void CT_Drawer (); bool CT_Responder (event_t *ev); void CT_PasteChat(const char *clip); -int chatmodeon; - // Private data static void CT_ClearChatMessage (); @@ -87,7 +86,7 @@ CVAR (String, chatmacro8, "I'll take care of it.", CVAR_ARCHIVE) CVAR (String, chatmacro9, "Yes", CVAR_ARCHIVE) CVAR (String, chatmacro0, "No", CVAR_ARCHIVE) -FStringCVar *chat_macros[10] = +FStringCVarRef *chat_macros[10] = { &chatmacro0, &chatmacro1, @@ -174,7 +173,7 @@ bool CT_Responder (event_t *ev) else if (ev->data1 == 'V' && (ev->data3 & GKM_CTRL)) #endif // __APPLE__ { - CT_PasteChat(I_GetFromClipboard(false)); + CT_PasteChat(I_GetFromClipboard(false).GetChars()); } } else if (ev->subtype == EV_GUI_Char) @@ -194,7 +193,7 @@ bool CT_Responder (event_t *ev) #ifdef __unix__ else if (ev->subtype == EV_GUI_MButtonDown) { - CT_PasteChat(I_GetFromClipboard(true)); + CT_PasteChat(I_GetFromClipboard(true).GetChars()); } #endif } @@ -233,16 +232,20 @@ void CT_PasteChat(const char *clip) void CT_Drawer (void) { + auto drawer = twod; FFont *displayfont = NewConsoleFont; if (players[consoleplayer].camera != NULL && - (Button_ShowScores.bDown || + (buttonMap.ButtonDown(Button_ShowScores) || players[consoleplayer].camera->health <= 0 || - SB_ForceActive) && - // Don't draw during intermission, since it has its own scoreboard in wi_stuff.cpp. - gamestate != GS_INTERMISSION) + SB_ForceActive)) { - HU_DrawScores (&players[consoleplayer]); + bool skipit = false; + if (gamestate == GS_CUTSCENE) + { + // todo: check for summary screen + } + if (!skipit) HU_DrawScores (&players[consoleplayer]); } if (chatmodeon) { @@ -258,18 +261,18 @@ void CT_Drawer (void) if (!!rv) return; } - FStringf prompt("%s ", GStrings("TXT_SAY")); + FStringf prompt("%s ", GStrings.GetString("TXT_SAY")); int x, scalex, y, promptwidth; y = (viewactive || gamestate != GS_LEVEL) ? -displayfont->GetHeight()-2 : -displayfont->GetHeight() - 22; scalex = 1; - int scale = active_con_scaletext(true); - int screen_width = SCREENWIDTH / scale; - int screen_height= SCREENHEIGHT / scale; + int scale = active_con_scale(drawer); + int screen_width = twod->GetWidth() / scale; + int screen_height= twod->GetHeight() / scale; int st_y = StatusBar->GetTopOfStatusbar() / scale; - y += ((SCREENHEIGHT == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y; + y += ((twod->GetHeight() == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y; promptwidth = displayfont->StringWidth (prompt) * scalex; x = displayfont->GetCharWidth (displayfont->GetCursor()) * scalex * 2 + promptwidth; @@ -286,9 +289,9 @@ void CT_Drawer (void) } printstr += displayfont->GetCursor(); - screen->DrawText (displayfont, CR_GREEN, 0, y, prompt.GetChars(), + DrawText(drawer, displayfont, CR_GREEN, 0, y, prompt.GetChars(), DTA_VirtualWidth, screen_width, DTA_VirtualHeight, screen_height, DTA_KeepRatio, true, TAG_DONE); - screen->DrawText (displayfont, CR_GREY, promptwidth, y, printstr, + DrawText(drawer, displayfont, CR_GREY, promptwidth, y, printstr.GetChars(), DTA_VirtualWidth, screen_width, DTA_VirtualHeight, screen_height, DTA_KeepRatio, true, TAG_DONE); } } @@ -368,17 +371,16 @@ static void ShoveChatStr (const char *str, uint8_t who) who |= 2; } - Net_WriteByte (DEM_SAY); - Net_WriteByte (who); + Net_WriteInt8 (DEM_SAY); + Net_WriteInt8 (who); - if (!chat_substitution || !DoSubstitution (substBuff, str)) + if (chat_substitution && DoSubstitution (substBuff, str)) { - Net_WriteString(MakeUTF8(str)); - } - else - { - Net_WriteString(MakeUTF8(substBuff)); + str = substBuff.GetChars(); } + + Net_WriteString(CleanseString(const_cast(MakeUTF8(str)))); + } //=========================================================================== @@ -426,7 +428,7 @@ static bool DoSubstitution (FString &out, const char *in) } else { - out += weapon->GetClass()->TypeName; + out += weapon->GetClass()->TypeName.GetChars(); } } } @@ -434,7 +436,7 @@ static bool DoSubstitution (FString &out, const char *in) { if (strnicmp(a, "armor", 5) == 0) { - auto armor = player->mo->FindInventory(NAME_BasicArmor); + auto armor = player->mo->FindInventory(NAME_BasicArmor, true); out.AppendFormat("%d", armor != NULL ? armor->IntVar(NAME_Amount) : 0); } } @@ -504,6 +506,7 @@ CCMD (messagemode) { if (menuactive == MENU_Off) { + buttonMap.ResetButtonStates(); chatmodeon = 1; C_HideConsole (); CT_ClearChatMessage (); @@ -526,6 +529,7 @@ CCMD (messagemode2) { if (menuactive == MENU_Off) { + buttonMap.ResetButtonStates(); chatmodeon = 2; C_HideConsole (); CT_ClearChatMessage (); diff --git a/src/d_anonstats.cpp b/src/d_anonstats.cpp index 92846b0c11a..b302ad189f3 100644 --- a/src/d_anonstats.cpp +++ b/src/d_anonstats.cpp @@ -12,11 +12,13 @@ void D_ConfirmSendStats() #else // !NO_SEND_STATS #if defined(_WIN32) +#include "i_mainwindow.h" #define WIN32_LEAN_AND_MEAN #include #include -extern int sys_ostype; +extern const char* sys_ostype; #else +extern FString sys_ostype; #ifdef __APPLE__ #include #else // !__APPLE__ @@ -34,18 +36,19 @@ extern int sys_ostype; #include "x86.h" #include "version.h" #include "v_video.h" -#include "gl_load/gl_interface.h" +#include "gl_interface.h" +#include "printf.h" -CVAR(Int, sys_statsenabled, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOSET) -CVAR(String, sys_statshost, "gzstats.drdteam.org", CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOSET) -CVAR(Int, sys_statsport, 80, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOSET) +CVAR(Int, anonstats_enabled411, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOSET) +CVAR(String, anonstats_host, "gzstats.drdteam.org", CVAR_NOSET) +CVAR(Int, anonstats_port, 80, CVAR_NOSET) -// Each machine will only send two reports, one when started with hardware rendering and one when started with software rendering. -#define CHECKVERSION 350 -#define CHECKVERSIONSTR "350" +#define CHECKVERSION 490 +#define CHECKVERSIONSTR "490" CVAR(Int, sentstats_hwr_done, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOSET) std::pair gl_getInfo(); +extern int vkversion; @@ -68,13 +71,16 @@ FString URLencode(const char *s) return out; } +// accept FString inputs too +FString URLencode(FString s) +{ + return URLencode(s.GetChars()); +} + #ifdef _WIN32 bool I_HTTPRequest(const char* request) { - if (sys_statshost.GetHumanString() == NULL) - return false; // no host, disable - WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { @@ -83,20 +89,20 @@ bool I_HTTPRequest(const char* request) } SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); struct hostent *host; - host = gethostbyname(sys_statshost.GetHumanString()); + host = gethostbyname(anonstats_host); if (host == nullptr) { DPrintf(DMSG_ERROR, "Error looking up hostname.\n"); return false; } SOCKADDR_IN SockAddr; - SockAddr.sin_port = htons(sys_statsport); + SockAddr.sin_port = htons(anonstats_port); SockAddr.sin_family = AF_INET; SockAddr.sin_addr.s_addr = *((uint32_t*)host->h_addr); - DPrintf(DMSG_NOTIFY, "Connecting to host %s\n", sys_statshost.GetHumanString()); + DPrintf(DMSG_NOTIFY, "Connecting to host %s\n", *anonstats_host); if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0) { - DPrintf(DMSG_ERROR, "Connection to host %s failed!\n", sys_statshost.GetHumanString()); + DPrintf(DMSG_ERROR, "Connection to host %s failed!\n", *anonstats_host); return false; } send(Socket, request, (int)strlen(request), 0); @@ -118,14 +124,14 @@ bool I_HTTPRequest(const char* request) #else bool I_HTTPRequest(const char* request) { - if (sys_statshost.GetHumanString() == NULL || sys_statshost.GetHumanString()[0] == 0) + if ((*anonstats_host)[0] == 0) return false; // no host, disable int sockfd, portno, n; struct sockaddr_in serv_addr; struct hostent *server; - portno = sys_statsport; + portno = anonstats_port; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) @@ -134,7 +140,7 @@ bool I_HTTPRequest(const char* request) return false; } - server = gethostbyname(sys_statshost.GetHumanString()); + server = gethostbyname(anonstats_host); if (server == NULL) { DPrintf(DMSG_ERROR, "Error looking up hostname.\n"); @@ -147,10 +153,10 @@ bool I_HTTPRequest(const char* request) server->h_length); serv_addr.sin_port = htons(portno); - DPrintf(DMSG_NOTIFY, "Connecting to host %s\n", sys_statshost.GetHumanString()); + DPrintf(DMSG_NOTIFY, "Connecting to host %s\n", *anonstats_host); if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { - DPrintf(DMSG_ERROR, "Connection to host %s failed!\n", sys_statshost.GetHumanString()); + DPrintf(DMSG_ERROR, "Connection to host %s failed!\n", *anonstats_host); return false; } @@ -170,44 +176,28 @@ bool I_HTTPRequest(const char* request) } #endif -static int GetOSVersion() +static FString GetOSVersion() { #ifdef _WIN32 - if (sizeof(void*) == 4) // 32 bit - { - BOOL res; - if (IsWow64Process(GetCurrentProcess(), &res) && res) - { - return 2; - } - return 1; - } - else - { - if (sys_ostype == 2) return 3; - else return 4; - } +#ifndef _M_ARM64 + return FStringf("Windows %s", sys_ostype); +#else + return FStringf("Windows %s ARM", sys_ostype); +#endif #elif defined __APPLE__ - return 5; - +#if defined(__aarch64__) + return sys_ostype + " ARM"; #else + return sys_ostype + " x64"; +#endif -// fall-through linux stuff here +#else // fall-through linux stuff here #ifdef __arm__ - return 8; -#elif __ppc__ - return 9; + return sys_ostype + " ARM"; #else - if (sizeof(void*) == 4) // 32 bit - { - return 6; - } - else - { - return 7; - } + return sys_ostype; #endif @@ -260,19 +250,19 @@ static int GetCoreInfo() static int GetRenderInfo() { + if (screen->Backend() == 2) return 1; if (screen->Backend() == 1) return 4; auto info = gl_getInfo(); if (!info.second) { - if ((screen->hwcaps & (RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE)) == (RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE)) return 2; - return 1; + return 2; } return 3; } static int GetGLVersion() { - if (screen->Backend() == 1) return 50; + if (screen->Backend() == 1) return vkversion; auto info = gl_getInfo(); return int(info.first * 10); } @@ -285,11 +275,57 @@ static void D_DoHTTPRequest(const char *request) } } + +static FString GetDeviceName() +{ + FString device = screen->DeviceName(); + if (device.Compare("AMD Radeon(TM) Graphics") == 0 || + device.Compare("Intel(R) UHD Graphics") == 0 || + //device.Compare("Intel(R) HD Graphics") == 0 || these are not that interesting so leave them alone + device.Compare("Intel(R) Iris(R) Plus Graphics") == 0 || + device.Compare("Intel(R) Iris(R) Xe Graphics") == 0 || + device.Compare("Radeon RX Vega") == 0 || + device.Compare("AMD Radeon Series") == 0) + { + // for these anonymous series names add the CPU name to get an idea what GPU we really have + auto ci = DumpCPUInfo(&CPU, true); + device.AppendFormat(" * %s", ci.GetChars()); + } + // cleanse the GPU info string to allow better searches on the database. + device.Substitute("/SSE2", ""); + device.Substitute("/PCIe", ""); + device.Substitute("/PCI", ""); + device.Substitute("(TM) ", ""); + device.Substitute("Mesa ", ""); + device.Substitute("DRI ", ""); + auto pos = device.IndexOf("Intel(R)"); + if (pos >= 0) + { + device.Substitute("(R) ", ""); + auto pos = device.IndexOf("("); + if (pos >= 0) device.Truncate(pos); + } + + pos = device.IndexOf("(LLVM"); + if (pos >= 0) device.Truncate(pos); + pos = device.IndexOf("(DRM"); + if (pos >= 0) device.Truncate(pos); + pos = device.IndexOf("(RADV"); + if (pos >= 0) device.Truncate(pos); + pos = device.IndexOf(", LLVM"); + if (pos >= 0) + { + device.Truncate(pos); + device << ')'; + } + device.StripLeftRight(); + return device; +} void D_DoAnonStats() { #ifndef _DEBUG // Do not repeat if already sent. - if (sys_statsenabled != 1 || sentstats_hwr_done >= CHECKVERSION) + if (anonstats_enabled411 != 1 || sentstats_hwr_done >= CHECKVERSION) { return; } @@ -301,10 +337,10 @@ void D_DoAnonStats() static char requeststring[1024]; - mysnprintf(requeststring, sizeof requeststring, "GET /stats_201903.py?render=%i&cores=%i&os=%i&glversion=%i&vendor=%s&model=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\nUser-Agent: %s %s\r\n\r\n", - GetRenderInfo(), GetCoreInfo(), GetOSVersion(), GetGLVersion(), URLencode(screen->vendorstring).GetChars(), URLencode(screen->DeviceName()).GetChars(), sys_statshost.GetHumanString(), GAMENAME, VERSIONSTR); + mysnprintf(requeststring, sizeof requeststring, "GET /stats_202309.py?render=%i&cores=%i&os=%s&glversion=%i&vendor=%s&model=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\nUser-Agent: %s %s\r\n\r\n", + GetRenderInfo(), GetCoreInfo(), URLencode(GetOSVersion()).GetChars(), GetGLVersion(), URLencode(screen->vendorstring).GetChars(), URLencode(GetDeviceName()).GetChars(), *anonstats_host, GAMENAME, VERSIONSTR); DPrintf(DMSG_NOTIFY, "Sending %s", requeststring); -#ifndef _DEBUG +#if 1//ndef _DEBUG // Don't send info in debug builds std::thread t1(D_DoHTTPRequest, requeststring); t1.detach(); @@ -315,7 +351,7 @@ void D_DoAnonStats() void D_ConfirmSendStats() { - if (sys_statsenabled >= 0) + if (anonstats_enabled411 >= 0) { return; } @@ -327,7 +363,7 @@ void D_ConfirmSendStats() "- Operating system\n" \ "- Number of processor cores\n" \ "- OpenGL version and your graphics card's name\n\n" \ - "All information sent will be anonymously. We will NOT be sending this information to any third party.\n" \ + "All information sent will be collected anonymously. We will NOT be sending this information to any third party.\n" \ "It will merely be used for decision-making about GZDoom's future development.\n" \ "Data will only be sent once per system.\n" \ "If you are getting this notice more than once, please let us know on the forums. Thanks!\n\n" \ @@ -338,8 +374,7 @@ void D_ConfirmSendStats() UCVarValue enabled = { 0 }; #ifdef _WIN32 - extern HWND Window; - enabled.Int = MessageBoxA(Window, MESSAGE_TEXT, TITLE_TEXT, MB_ICONQUESTION | MB_YESNO) == IDYES; + enabled.Int = MessageBoxA(mainwindow.GetHandle(), MESSAGE_TEXT, TITLE_TEXT, MB_ICONQUESTION | MB_YESNO) == IDYES; #elif defined __APPLE__ const CFStringRef messageString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, MESSAGE_TEXT, kCFStringEncodingASCII, kCFAllocatorNull); const CFStringRef titleString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, TITLE_TEXT, kCFStringEncodingASCII, kCFAllocatorNull); @@ -372,7 +407,7 @@ void D_ConfirmSendStats() enabled.Int = SDL_ShowMessageBox(&messageboxdata, &buttonid) == 0 && buttonid == 0; #endif // _WIN32 - sys_statsenabled.ForceSet(enabled, CVAR_Int); + anonstats_enabled411->ForceSet(enabled, CVAR_Int); } #endif // NO_SEND_STATS diff --git a/src/d_buttons.h b/src/d_buttons.h new file mode 100644 index 00000000000..341ead790cc --- /dev/null +++ b/src/d_buttons.h @@ -0,0 +1,39 @@ +#pragma once + +enum +{ + Button_AM_PanLeft, + Button_User2, + Button_Jump, + Button_Right, + Button_Zoom, + Button_Back, + Button_AM_ZoomIn, + Button_Reload, + Button_LookDown, + Button_AM_ZoomOut, + Button_User4, + Button_Attack, + Button_User1, + Button_Klook, + Button_Forward, + Button_MoveDown, + Button_AltAttack, + Button_MoveLeft, + Button_MoveRight, + Button_AM_PanRight, + Button_AM_PanUp, + Button_Mlook, + Button_Crouch, + Button_Left, + Button_LookUp, + Button_User3, + Button_Strafe, + Button_AM_PanDown, + Button_ShowScores, + Button_Speed, + Button_Use, + Button_MoveUp, + NUM_ACTIONS +}; + diff --git a/src/d_defcvars.cpp b/src/d_defcvars.cpp new file mode 100644 index 00000000000..bcd8ad19403 --- /dev/null +++ b/src/d_defcvars.cpp @@ -0,0 +1,167 @@ +//----------------------------------------------------------------------------- +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// Copyright 2019-2021 Rachael Alexanderson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +// +// DESCRIPTION: +// defcvars loader split from d_main.cpp +// +//----------------------------------------------------------------------------- + +// HEADER FILES ------------------------------------------------------------ + +#include "doomdef.h" +#include "doomstat.h" +#include "gstrings.h" +#include "filesystem.h" +#include "menu.h" +#include "doommenu.h" +#include "c_console.h" +#include "d_main.h" +#include "version.h" +#include "d_defcvars.h" + + +void D_GrabCVarDefaults() +{ + int lump, lastlump = 0; + int lumpversion, gamelastrunversion; + gamelastrunversion = atoi(LASTRUNVERSION); + + while ((lump = fileSystem.FindLump("DEFCVARS", &lastlump)) != -1) + { + // don't parse from wads + if (lastlump > fileSystem.GetLastEntry(fileSystem.GetMaxIwadNum())) + { + // would rather put this in a modal of some sort, but this will have to do. + Printf(TEXTCOLOR_RED "Cannot load DEFCVARS from a wadfile!\n"); + break; + } + + FScanner sc(lump); + + sc.MustGetString(); + if (!sc.Compare("version")) + sc.ScriptError("Must declare version for defcvars! (currently: %i)", gamelastrunversion); + sc.MustGetNumber(); + lumpversion = sc.Number; + if (lumpversion > gamelastrunversion) + sc.ScriptError("Unsupported version %i (%i supported)", lumpversion, gamelastrunversion); + if (lumpversion < 219) + sc.ScriptError("Version must be at least 219 (current version %i)", gamelastrunversion); + + FBaseCVar* var; + FString CurrentFindCVar; + + while (sc.GetString()) + { + if (sc.Compare("set")) + { + sc.MustGetString(); + } + + CurrentFindCVar = sc.String; + if (lumpversion < 220) + { + CurrentFindCVar.ToLower(); + + // these two got renamed + if (CurrentFindCVar.Compare("gamma") == 0) + { + CurrentFindCVar = "vid_gamma"; + } + if (CurrentFindCVar.Compare("fullscreen") == 0) + { + CurrentFindCVar = "vid_fullscreen"; + } + + // this was removed + if (CurrentFindCVar.Compare("cd_drive") == 0) + break; + } + if (lumpversion < 221) + { + // removed cvar + // this one doesn't matter as much, since it depended on platform-specific values, + // and is something the user should change anyhow, so, let's just throw this value + // out. + if (CurrentFindCVar.Compare("mouse_sensitivity") == 0) + break; + if (CurrentFindCVar.Compare("m_noprescale") == 0) + break; + } + + bool blacklisted = false; + SHOULD_BLACKLIST(disablecrashlog) + SHOULD_BLACKLIST(gl_control_tear) + SHOULD_BLACKLIST(in_mouse) + SHOULD_BLACKLIST(joy_dinput) + SHOULD_BLACKLIST(joy_ps2raw) + SHOULD_BLACKLIST(joy_xinput) + SHOULD_BLACKLIST(k_allowfullscreentoggle) + SHOULD_BLACKLIST(k_mergekeys) + SHOULD_BLACKLIST(m_swapbuttons) + SHOULD_BLACKLIST(queryiwad_key) + SHOULD_BLACKLIST(vid_gpuswitch) + SHOULD_BLACKLIST(vr_enable_quadbuffered) + SHOULD_BLACKLIST(m_filter) + SHOULD_BLACKLIST(gl_debug) + SHOULD_BLACKLIST(vid_adapter) + SHOULD_BLACKLIST(sys_statsenabled47) + SHOULD_BLACKLIST(sys_statsenabled49) + SHOULD_BLACKLIST(anonstats_statsenabled411) + SHOULD_BLACKLIST(save_dir) + SHOULD_BLACKLIST(sys_statsport) + SHOULD_BLACKLIST(sys_statshost) + SHOULD_BLACKLIST(anonstats_port) + SHOULD_BLACKLIST(anonstats_host) + SHOULD_BLACKLIST(sentstats_hwr_done) + + var = FindCVar(CurrentFindCVar.GetChars(), NULL); + + if (blacklisted) + { + sc.ScriptMessage("Cannot set cvar default for blacklisted cvar '%s'", sc.String); + sc.MustGetString(); // to ignore the value of the cvar + } + else if (var != NULL) + { + + if (var->GetFlags() & CVAR_ARCHIVE) + { + UCVarValue val; + + sc.MustGetString(); + val.String = const_cast(sc.String); + var->SetGenericRepDefault(val, CVAR_String); + } + else + { + sc.ScriptMessage("Cannot set cvar default for non-config cvar '%s'", sc.String); + sc.MustGetString(); // to ignore the value of the cvar + } + } + else + { + sc.ScriptMessage("Unknown cvar '%s' in defcvars", sc.String); + sc.MustGetString(); // to ignore the value of the cvar + } + } + } +} + diff --git a/src/d_defcvars.h b/src/d_defcvars.h new file mode 100644 index 00000000000..caaca508ba0 --- /dev/null +++ b/src/d_defcvars.h @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------------- +// Copyright 2021 Rachael Alexanderson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +// +// DESCRIPTION: +// defcvars loader split from d_main.cpp +// +//----------------------------------------------------------------------------- +#pragma once + +#define SHOULD_BLACKLIST(name) \ + if (#name[0]==CurrentFindCVar[0]) \ + if (CurrentFindCVar.Compare(#name) == 0) \ + blacklisted = true; + diff --git a/src/d_event.h b/src/d_event.h index ef54c3a0ffe..409dcb62b78 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -24,60 +24,12 @@ #define __D_EVENT_H__ -#include "basictypes.h" +#include "basics.h" #include - - -// -// Event handling. -// - -// Input event types. -enum EGenericEvent -{ - EV_None, - EV_KeyDown, // data1: scan code, data2: Qwerty ASCII code - EV_KeyUp, // same - EV_Mouse, // x, y: mouse movement deltas - EV_GUI_Event, // subtype specifies actual event - EV_DeviceChange,// a device has been connected or removed -}; - -// Event structure. -struct event_t -{ - uint8_t type; - uint8_t subtype; - int16_t data1; // keys / mouse/joystick buttons - int16_t data2; - int16_t data3; - int x; // mouse/joystick x move - int y; // mouse/joystick y move -}; +#include "d_eventbase.h" +#include "gamestate.h" -enum gameaction_t : int -{ - ga_nothing, - ga_loadlevel, // not used. - ga_newgame, - ga_newgame2, - ga_recordgame, - ga_loadgame, - ga_loadgamehidecon, - ga_loadgameplaydemo, - ga_autoloadgame, - ga_savegame, - ga_autosave, - ga_playdemo, - ga_completed, - ga_slideshow, - ga_worlddone, - ga_screenshot, - ga_togglemap, - ga_fullconsole, - ga_resumeconversation, -}; @@ -116,20 +68,38 @@ typedef enum BT_USER2 = 1<<22, BT_USER3 = 1<<23, BT_USER4 = 1<<24, + + BT_RUN = 1<<25, } buttoncode_t; // Called by IO functions when input is detected. -void D_PostEvent (const event_t* ev); -void D_RemoveNextCharEvent(); void D_Render(std::function action, bool interpolate); - -// -// GLOBAL VARIABLES -// -#define MAXEVENTS 128 - -extern event_t events[MAXEVENTS]; +enum gameaction_t : int +{ + ga_nothing, + ga_loadlevel, // not used. + ga_newgame, + ga_newgame2, + ga_recordgame, + ga_loadgame, + ga_loadgamehidecon, + ga_loadgameplaydemo, + ga_autoloadgame, + ga_savegame, + ga_autosave, + ga_playdemo, + ga_completed, + ga_slideshow, + ga_worlddone, + ga_screenshot, + ga_togglemap, + ga_fullconsole, + ga_resumeconversation, + ga_intro, + ga_intermission, + ga_titleloop, +}; extern gameaction_t gameaction; diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index bb957b73e4b..7f9bc60fedf 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -4,7 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 1998-2009 Randy Heit -** Copyright 2009 CHristoph Oelckers +** Copyright 2009 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -37,21 +37,27 @@ #include "cmdlib.h" #include "doomstat.h" #include "i_system.h" -#include "w_wad.h" +#include "filesystem.h" #include "m_argv.h" #include "m_misc.h" #include "sc_man.h" #include "v_video.h" #include "gameconfigfile.h" -#include "resourcefiles/resourcefile.h" #include "version.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "v_text.h" - -CVAR (Bool, queryiwad, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -CVAR (String, defaultiwad, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); - -const char* BaseFileSearch(const char* file, const char* ext, bool lookfirstinprogdir); +#include "fs_findfile.h" +#include "findfile.h" +#include "i_interface.h" +#include "gstrings.h" + +EXTERN_CVAR(Bool, queryiwad); +EXTERN_CVAR(String, defaultiwad); +EXTERN_CVAR(Bool, disableautoload) +EXTERN_CVAR(Bool, autoloadlights) +EXTERN_CVAR(Bool, autoloadbrightmaps) +EXTERN_CVAR(Bool, autoloadwidescreen) +EXTERN_CVAR(String, language) //========================================================================== // @@ -132,6 +138,10 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, { iwad->nokeyboardcheats = true; } + else if (sc.Compare("SkipBexStringsIfLanguage")) + { + iwad->SkipBexStringsIfLanguage = true; + } else if (sc.Compare("Compatibility")) { sc.MustGetStringName("="); @@ -145,6 +155,7 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, else if(sc.Compare("Extended")) iwad->flags |= GI_MENUHACK_EXTENDED; else if(sc.Compare("Shorttex")) iwad->flags |= GI_COMPATSHORTTEX; else if(sc.Compare("Stairs")) iwad->flags |= GI_COMPATSTAIRS; + else if (sc.Compare("nosectionmerge")) iwad->flags |= GI_NOSECTIONMERGE; else sc.ScriptError(NULL); } while (sc.CheckString(",")); @@ -173,10 +184,10 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, { sc.MustGetStringName("="); sc.MustGetString(); - iwad->FgColor = V_GetColor(NULL, sc); + iwad->FgColor = V_GetColor(sc); sc.MustGetStringName(","); sc.MustGetString(); - iwad->BkColor = V_GetColor(NULL, sc); + iwad->BkColor = V_GetColor(sc); } else if (sc.Compare("IgnoreTitlePatches")) { @@ -222,6 +233,36 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, sc.MustGetString(); iwad->Song = sc.String; } + else if (sc.Compare("LoadLights")) + { + sc.MustGetStringName("="); + sc.MustGetNumber(); + iwad->LoadLights = sc.Number; + } + else if (sc.Compare("LoadBrightmaps")) + { + sc.MustGetStringName("="); + sc.MustGetNumber(); + iwad->LoadBrightmaps = sc.Number; + } + else if (sc.Compare("LoadWidescreen")) + { + sc.MustGetStringName("="); + sc.MustGetNumber(); + iwad->LoadWidescreen = sc.Number; + } + else if (sc.Compare("DiscordAppId")) + { + sc.MustGetStringName("="); + sc.MustGetString(); + iwad->DiscordAppId = sc.String; + } + else if (sc.Compare("SteamAppId")) + { + sc.MustGetStringName("="); + sc.MustGetString(); + iwad->SteamAppId = sc.String; + } else { sc.ScriptError("Unknown keyword '%s'", sc.String); @@ -265,29 +306,28 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, // Look for IWAD definition lump // //========================================================================== +void GetReserved(FileSys::LumpFilterInfo& lfi); -FIWadManager::FIWadManager(const char *fn, const char *optfn) +FIWadManager::FIWadManager(const char *firstfn, const char *optfn) { - FResourceFile *resfile = FResourceFile::OpenResourceFile(optfn, true); - if (resfile != NULL) + FileSystem check; + std::vector fns; + fns.push_back(firstfn); + if (optfn) fns.push_back(optfn); + FileSys::LumpFilterInfo lfi; + GetReserved(lfi); + + if (check.InitMultipleFiles(fns, &lfi, nullptr)) { - uint32_t cnt = resfile->LumpCount(); - for(int i=cnt-1; i>=0; i--) + // this is for the IWAD picker. As we have a filesystem open here that contains the base files, it is the easiest place to load the strings early. + GStrings.LoadStrings(check, language); + int num = check.CheckNumForName("IWADINFO"); + if (num >= 0) { - FResourceLump *lmp = resfile->GetLump(i); - - if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "IWADINFO")) - { - // Found one! - ParseIWadInfo(resfile->FileName, (const char*)lmp->CacheLump(), lmp->LumpSize); - break; - } - } - delete resfile; - if (mIWadNames.Size() == 0 || mIWadInfos.Size() == 0) - { - I_FatalError("No IWAD definitions found"); + auto data = check.ReadFile(num); + ParseIWadInfo("IWADINFO", data.string(), (int)data.size()); } + } } @@ -301,11 +341,12 @@ FIWadManager::FIWadManager(const char *fn, const char *optfn) int FIWadManager::ScanIWAD (const char *iwad) { - FResourceFile *iwadfile = FResourceFile::OpenResourceFile(iwad, true); + FileSystem check; + check.InitSingleFile(iwad, nullptr); mLumpsFound.Resize(mIWadInfos.Size()); - auto CheckLumpName = [=](const char *name) + auto CheckFileName = [=](const char *name) { for (unsigned i = 0; i< mIWadInfos.Size(); i++) { @@ -319,24 +360,20 @@ int FIWadManager::ScanIWAD (const char *iwad) } }; - if (iwadfile != NULL) + if (check.GetNumEntries() > 0) { memset(&mLumpsFound[0], 0, mLumpsFound.Size() * sizeof(mLumpsFound[0])); - for(uint32_t ii = 0; ii < iwadfile->LumpCount(); ii++) + for(int ii = 0; ii < check.GetNumEntries(); ii++) { - FResourceLump *lump = iwadfile->GetLump(ii); - CheckLumpName(lump->Name); - if (lump->FullName.IsNotEmpty()) + CheckFileName(check.GetFileShortName(ii)); + auto full = check.GetFileFullName(ii, false); + if (full && strnicmp(full, "maps/", 5) == 0) { - if (strnicmp(lump->FullName, "maps/", 5) == 0) - { - FString mapname(&lump->FullName[5], strcspn(&lump->FullName[5], ".")); - CheckLumpName(mapname); - } + FString mapname(&full[5], strcspn(&full[5], ".")); + CheckFileName(mapname.GetChars()); } } - delete iwadfile; } for (unsigned i = 0; i< mIWadInfos.Size(); i++) { @@ -355,46 +392,43 @@ int FIWadManager::ScanIWAD (const char *iwad) // //========================================================================== -int FIWadManager::CheckIWADInfo(const char *fn) +int FIWadManager::CheckIWADInfo(const char* fn) { - FResourceFile *resfile = FResourceFile::OpenResourceFile(fn, true); - if (resfile != NULL) + FileSystem check; + + FileSys::LumpFilterInfo lfi; + GetReserved(lfi); + + std::vector filenames = { fn }; + if (check.InitMultipleFiles(filenames, &lfi, nullptr)) { - uint32_t cnt = resfile->LumpCount(); - for (int i = cnt - 1; i >= 0; i--) + int num = check.CheckNumForName("IWADINFO"); + if (num >= 0) { - FResourceLump *lmp = resfile->GetLump(i); - - if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "IWADINFO")) + try { - // Found one! - try - { - FIWADInfo result; - ParseIWadInfo(resfile->FileName, (const char*)lmp->CacheLump(), lmp->LumpSize, &result); - delete resfile; - for (unsigned i = 0, count = mIWadInfos.Size(); i < count; ++i) - { - if (mIWadInfos[i].Name == result.Name) - { - return i; - } - } + FIWADInfo result; + auto data = check.ReadFile(num); + ParseIWadInfo(fn, data.string(), (int)data.size(), &result); - mOrderNames.Push(result.Name); - return mIWadInfos.Push(result); - } - catch (CRecoverableError &err) + for (unsigned i = 0, count = mIWadInfos.Size(); i < count; ++i) { - delete resfile; - Printf(TEXTCOLOR_RED "%s: %s\nFile has been removed from the list of IWADs\n", fn, err.GetMessage()); - return -1; + if (mIWadInfos[i].Name == result.Name) + { + return i; + } } - break; + + mOrderNames.Push(result.Name); + return mIWadInfos.Push(result); + } + catch (CRecoverableError & err) + { + Printf(TEXTCOLOR_RED "%s: %s\nFile has been removed from the list of IWADs\n", fn, err.what()); + return -1; } } - delete resfile; Printf(TEXTCOLOR_RED "%s: Unable to find IWADINFO\nFile has been removed from the list of IWADs\n", fn); return -1; } @@ -428,6 +462,7 @@ void FIWadManager::CollectSearchPaths() } mSearchPaths.Append(I_GetGogPaths()); mSearchPaths.Append(I_GetSteamPath()); + mSearchPaths.Append(I_GetBethesdaPath()); // Unify and remove trailing slashes for (auto &str : mSearchPaths) @@ -447,36 +482,32 @@ void FIWadManager::CollectSearchPaths() void FIWadManager::AddIWADCandidates(const char *dir) { - void *handle; - findstate_t findstate; - FStringf slasheddir("%s/", dir); - FString findmask = slasheddir + "*.*"; - if ((handle = I_FindFirst(findmask, &findstate)) != (void *)-1) + FileSys::FileList list; + + if (FileSys::ScanDirectory(list, dir, "*", true)) { - do + for(auto& entry : list) { - if (!(I_FindAttr(&findstate) & FA_DIREC)) + if (!entry.isDirectory) { - auto FindName = I_FindName(&findstate); - auto p = strrchr(FindName, '.'); + auto p = strrchr(entry.FileName.c_str(), '.'); if (p != nullptr) { // special IWAD extension. if (!stricmp(p, ".iwad") || !stricmp(p, ".ipk3") || !stricmp(p, ".ipk7")) { - mFoundWads.Push(FFoundWadInfo{ slasheddir + FindName, "", -1 }); + mFoundWads.Push(FFoundWadInfo{ entry.FilePath.c_str(), "", -1 }); } } for (auto &name : mIWadNames) { - if (!stricmp(name, FindName)) + if (!name.CompareNoCase(entry.FileName.c_str())) { - mFoundWads.Push(FFoundWadInfo{ slasheddir + FindName, "", -1 }); + mFoundWads.Push(FFoundWadInfo{ entry.FilePath.c_str(), "", -1 }); } } } - } while (I_FindNext(handle, &findstate) == 0); - I_FindClose(handle); + } } } @@ -495,14 +526,14 @@ void FIWadManager::ValidateIWADs() for (auto &p : mFoundWads) { int index; - auto x = strrchr(p.mFullPath, '.'); + auto x = strrchr(p.mFullPath.GetChars(), '.'); if (x != nullptr && (!stricmp(x, ".iwad") || !stricmp(x, ".ipk3") || !stricmp(x, ".ipk7"))) { - index = CheckIWADInfo(p.mFullPath); + index = CheckIWADInfo(p.mFullPath.GetChars()); } else { - index = ScanIWAD(p.mFullPath); + index = ScanIWAD(p.mFullPath.GetChars()); } p.mInfoIndex = index; } @@ -531,7 +562,7 @@ void FIWadManager::ValidateIWADs() static bool havepicked = false; -int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, const char *zdoom_wad, const char *optional_wad) +int FIWadManager::IdentifyVersion (std::vector&wadfiles, const char *iwad, const char *zdoom_wad, const char *optional_wad) { const char *iwadparm = Args->CheckValue ("-iwad"); FString custwad; @@ -541,7 +572,7 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, // Collect all IWADs in the search path for (auto &dir : mSearchPaths) { - AddIWADCandidates(dir); + AddIWADCandidates(dir.GetChars()); } unsigned numFoundWads = mFoundWads.Size(); @@ -585,6 +616,12 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, // -iwad not found or not specified. Revert back to standard behavior. if (mFoundWads.Size() == numFoundWads) iwadparm = nullptr; + // Check for symbolic links leading to non-existent files and for files that are unreadable. + for (unsigned int i = 0; i < mFoundWads.Size(); i++) + { + if (!FileExists(mFoundWads[i].mFullPath) || !FileReadable(mFoundWads[i].mFullPath.GetChars())) mFoundWads.Delete(i--); + } + // Now check if what got collected actually is an IWAD. ValidateIWADs(); @@ -694,8 +731,10 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, } int pick = 0; - // We got more than one so present the IWAD selection box. - if (picks.Size() > 1) + // Present the IWAD selection box. + bool alwaysshow = (queryiwad && !Args->CheckParm("-iwad")); + + if (alwaysshow || picks.Size() > 1) { // Locate the user's prefered IWAD, if it was found. if (defaultiwad[0] != '\0') @@ -703,14 +742,14 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, for (unsigned i = 0; i < picks.Size(); ++i) { FString &basename = mIWadInfos[picks[i].mInfoIndex].Name; - if (stricmp(basename, defaultiwad) == 0) + if (basename.CompareNoCase(defaultiwad) == 0) { pick = i; break; } } } - if (picks.Size() > 1) + if (alwaysshow || picks.Size() > 1) { if (!havepicked) { @@ -719,14 +758,35 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, { WadStuff stuff; stuff.Name = mIWadInfos[found.mInfoIndex].Name; - stuff.Path = ExtractFileBase(found.mFullPath); + stuff.Path = ExtractFileBase(found.mFullPath.GetChars()); wads.Push(stuff); } - pick = I_PickIWad(&wads[0], (int)wads.Size(), queryiwad, pick); + int flags = 0;; + + if (disableautoload) flags |= 1; + if (autoloadlights) flags |= 2; + if (autoloadbrightmaps) flags |= 4; + if (autoloadwidescreen) flags |= 8; + + FString extraArgs; + + pick = I_PickIWad(&wads[0], (int)wads.Size(), queryiwad, pick, flags, extraArgs); if (pick >= 0) { + extraArgs.StripLeftRight(); + + if(extraArgs.Len() > 0) + { + Args->AppendArgsString(extraArgs); + } + + disableautoload = !!(flags & 1); + autoloadlights = !!(flags & 2); + autoloadbrightmaps = !!(flags & 4); + autoloadwidescreen = !!(flags & 8); + // The newly selected IWAD becomes the new default - defaultiwad = mIWadInfos[picks[pick].mInfoIndex].Name; + defaultiwad = mIWadInfos[picks[pick].mInfoIndex].Name.GetChars(); } else { @@ -738,24 +798,24 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, } // zdoom.pk3 must always be the first file loaded and the IWAD second. - wadfiles.Clear(); - D_AddFile (wadfiles, zdoom_wad); + wadfiles.clear(); + D_AddFile (wadfiles, zdoom_wad, true, -1, GameConfig); // [SP] Load non-free assets if available. This must be done before the IWAD. int iwadnum; - if (D_AddFile(wadfiles, optional_wad)) + if (D_AddFile(wadfiles, optional_wad, true, -1, GameConfig)) iwadnum = 2; else iwadnum = 1; - Wads.SetIwadNum(iwadnum); + fileSystem.SetIwadNum(iwadnum); if (picks[pick].mRequiredPath.IsNotEmpty()) { - D_AddFile (wadfiles, picks[pick].mRequiredPath); + D_AddFile (wadfiles, picks[pick].mRequiredPath.GetChars(), true, -1, GameConfig); iwadnum++; } - D_AddFile (wadfiles, picks[pick].mFullPath); - Wads.SetMaxIwadNum(iwadnum); + D_AddFile (wadfiles, picks[pick].mFullPath.GetChars(), true, -1, GameConfig); + fileSystem.SetMaxIwadNum(iwadnum); auto info = mIWadInfos[picks[pick].mInfoIndex]; // Load additional resources from the same directory as the IWAD itself. @@ -764,7 +824,7 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, FString path; if (info.Load[i][0] != ':') { - long lastslash = picks[pick].mFullPath.LastIndexOf('/'); + auto lastslash = picks[pick].mFullPath.LastIndexOf('/'); if (lastslash == -1) { @@ -775,12 +835,12 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, path = FString(picks[pick].mFullPath.GetChars(), lastslash + 1); } path += info.Load[i]; - D_AddFile(wadfiles, path); + D_AddFile(wadfiles, path.GetChars(), true, -1, GameConfig); } else { - auto wad = BaseFileSearch(info.Load[i].GetChars() + 1, NULL, true); - if (wad) D_AddFile(wadfiles, wad); + auto wad = BaseFileSearch(info.Load[i].GetChars() + 1, NULL, true, GameConfig); + if (wad) D_AddFile(wadfiles, wad, true, -1, GameConfig); } } @@ -794,20 +854,28 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, // //========================================================================== -const FIWADInfo *FIWadManager::FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad, const char *optionalwad) +const FIWADInfo *FIWadManager::FindIWAD(std::vector& wadfiles, const char *iwad, const char *basewad, const char *optionalwad) { int iwadType = IdentifyVersion(wadfiles, iwad, basewad, optionalwad); if (iwadType == -1) return nullptr; //gameiwad = iwadType; const FIWADInfo *iwad_info = &mIWadInfos[iwadType]; - if (DoomStartupInfo.Name.IsEmpty()) DoomStartupInfo.Name = iwad_info->Name; - if (DoomStartupInfo.BkColor == 0 && DoomStartupInfo.FgColor == 0) + if (GameStartupInfo.Name.IsEmpty()) GameStartupInfo.Name = iwad_info->Name; + if (GameStartupInfo.BkColor == 0 && GameStartupInfo.FgColor == 0) { - DoomStartupInfo.BkColor = iwad_info->BkColor; - DoomStartupInfo.FgColor = iwad_info->FgColor; + GameStartupInfo.BkColor = iwad_info->BkColor; + GameStartupInfo.FgColor = iwad_info->FgColor; } - if (DoomStartupInfo.Type == 0) DoomStartupInfo.Type = iwad_info->StartupType; - if (DoomStartupInfo.Song.IsEmpty()) DoomStartupInfo.Song = iwad_info->Song; + if (GameStartupInfo.LoadWidescreen == -1) + GameStartupInfo.LoadWidescreen = iwad_info->LoadWidescreen; + if (GameStartupInfo.LoadLights == -1) + GameStartupInfo.LoadLights = iwad_info->LoadLights; + if (GameStartupInfo.LoadBrightmaps == -1) + GameStartupInfo.LoadBrightmaps = iwad_info->LoadBrightmaps; + if (GameStartupInfo.Type == 0) GameStartupInfo.Type = iwad_info->StartupType; + if (GameStartupInfo.Song.IsEmpty()) GameStartupInfo.Song = iwad_info->Song; + if (GameStartupInfo.DiscordAppId.IsEmpty()) GameStartupInfo.DiscordAppId = iwad_info->DiscordAppId; + if (GameStartupInfo.SteamAppId.IsEmpty()) GameStartupInfo.SteamAppId = iwad_info->SteamAppId; I_SetIWADInfo(); return iwad_info; } diff --git a/src/d_main.cpp b/src/d_main.cpp index 98042bcd8e1..c14149196a4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1,4 +1,5 @@ //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Copyright 1993-1996 id Software // Copyright 1999-2016 Randy Heit // Copyright 2002-2016 Christoph Oelckers @@ -31,10 +32,6 @@ #include #endif -#ifdef HAVE_FPU_CONTROL -#include -#endif - #if defined(__unix__) || defined(__APPLE__) #include #endif @@ -42,7 +39,7 @@ #include #include -#include "doomerrors.h" +#include "engineerrors.h" #include "i_time.h" #include "d_gui.h" @@ -50,14 +47,15 @@ #include "doomdef.h" #include "doomstat.h" #include "gstrings.h" -#include "w_wad.h" +#include "filesystem.h" #include "s_sound.h" #include "v_video.h" #include "intermission/intermission.h" -#include "f_wipe.h" +#include "wipe.h" #include "m_argv.h" #include "m_misc.h" -#include "menu/menu.h" +#include "menu.h" +#include "doommenu.h" #include "c_console.h" #include "c_dispatch.h" #include "i_sound.h" @@ -89,6 +87,7 @@ #include "d_netinf.h" #include "m_cheat.h" #include "m_joy.h" +#include "v_draw.h" #include "po_man.h" #include "p_local.h" #include "autosegs.h" @@ -102,14 +101,42 @@ #include "r_data/r_vanillatrans.h" #include "s_music.h" #include "swrenderer/r_swcolormaps.h" +#include "findfile.h" +#include "md5.h" +#include "c_buttons.h" +#include "d_buttons.h" +#include "i_interface.h" +#include "animations.h" +#include "texturemanager.h" +#include "formats/multipatchtexture.h" +#include "scriptutil.h" +#include "v_palette.h" +#include "texturemanager.h" +#include "hw_clock.h" +#include "hwrenderer/scene/hw_drawinfo.h" +#include "doomfont.h" +#include "screenjob.h" +#include "startscreen.h" +#include "shiftstate.h" + +#ifdef __unix__ +#include "i_system.h" // for SHARE_DIR +#endif // __unix__ + +using namespace FileSys; EXTERN_CVAR(Bool, hud_althud) EXTERN_CVAR(Int, vr_mode) EXTERN_CVAR(Bool, cl_customizeinvulmap) +EXTERN_CVAR(Bool, log_vgafont) +EXTERN_CVAR(Bool, dlg_vgafont) +CVAR(Int, vid_renderer, 1, 0) // for some stupid mods which threw caution out of the window... + void DrawHUD(); void D_DoAnonStats(); void I_DetectOS(); - +void UpdateGenericUI(bool cvar); +void Local_Job_Init(); // MACROS ------------------------------------------------------------------ @@ -128,8 +155,12 @@ void P_Shutdown(); void M_SaveDefaultsFinal(); void R_Shutdown(); void I_ShutdownInput(); +void SetConsoleNotifyBuffer(); +void I_UpdateDiscordPresence(bool SendPresence, const char* curstatus, const char* appid, const char* steamappid); +bool M_SetSpecialMenu(FName& menu, int param); // game specific checks const FIWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad); +void InitWidgetResources(const char* basewad); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -137,19 +168,21 @@ bool D_CheckNetGame (); void D_ProcessEvents (); void G_BuildTiccmd (ticcmd_t* cmd); void D_DoAdvanceDemo (); -void D_AddWildFile (TArray &wadfiles, const char *pattern); void D_LoadWadSettings (); void ParseGLDefs(); -void DrawFullscreenSubtitle(const char *text); +void DrawFullscreenSubtitle(FFont* font, const char *text); void D_Cleanup(); void FreeSBarInfoScript(); void I_UpdateWindowTitle(); -void C_GrabCVarDefaults (); +void S_ParseMusInfo(); +void D_GrabCVarDefaults(); +void LoadHexFont(const char* filename); +void InitBuildTiles(); +bool OkForLocalization(FTextureID texnum, const char* substitute); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- void D_DoomLoop (); -const char *BaseFileSearch (const char *file, const char *ext, bool lookfirstinprogdir=false); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- @@ -157,23 +190,23 @@ EXTERN_CVAR (Float, turbo) EXTERN_CVAR (Bool, freelook) EXTERN_CVAR (Float, m_pitch) EXTERN_CVAR (Float, m_yaw) -EXTERN_CVAR (Bool, invertmouse) EXTERN_CVAR (Bool, lookstrafe) EXTERN_CVAR (Int, screenblocks) EXTERN_CVAR (Bool, sv_cheats) EXTERN_CVAR (Bool, sv_unlimited_pickup) EXTERN_CVAR (Bool, r_drawplayersprites) EXTERN_CVAR (Bool, show_messages) +EXTERN_CVAR(Bool, ticker) +EXTERN_CVAR(Bool, vid_fps) extern bool setmodeneeded; -extern bool gameisdead; extern bool demorecording; -extern bool M_DemoNoPlay; // [RH] if true, then skip any demos in the loop +bool M_DemoNoPlay; // [RH] if true, then skip any demos in the loop extern bool insave; extern TDeletingArray LightDefaults; +extern FName MessageBoxClass; - -CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL) +CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL | CVAR_VIRTUAL) { if (netgame) { @@ -195,6 +228,29 @@ CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL) // PUBLIC DATA DEFINITIONS ------------------------------------------------- +#ifndef NO_SWRENDERER +CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (self < 0 || self > 4) + { + self = 4; + } + else if (self == 2 || self == 3) + { + self = self - 2; // softpoly to software + } + + if (usergame) + { + // [SP] Update pitch limits to the netgame/gamesim. + players[consoleplayer].SendPitchLimits(); + } + screen->SetTextureFilterMode(); + + // No further checks needed. All this changes now is which scene drawer the render backend calls. +} +#endif + CUSTOM_CVAR (Int, fraglimit, 0, CVAR_SERVERINFO) { // Check for the fraglimit being hit because the fraglimit is being @@ -205,7 +261,7 @@ CUSTOM_CVAR (Int, fraglimit, 0, CVAR_SERVERINFO) { if (playeringame[i] && self <= D_GetFragCount(&players[i])) { - Printf ("%s\n", GStrings("TXT_FRAGLIMIT")); + Printf ("%s\n", GStrings.GetString("TXT_FRAGLIMIT")); primaryLevel->ExitLevel (0, false); break; } @@ -223,52 +279,60 @@ CUSTOM_CVAR (String, vid_cursor, "None", CVAR_ARCHIVE | CVAR_NOINITCALL) if (!stricmp(self, "None" ) && gameinfo.CursorPic.IsNotEmpty()) { - res = I_SetCursor(TexMan.GetTextureByName(gameinfo.CursorPic)); + res = I_SetCursor(TexMan.GetGameTextureByName(gameinfo.CursorPic.GetChars())); } else { - res = I_SetCursor(TexMan.GetTextureByName(self)); + res = I_SetCursor(TexMan.GetGameTextureByName(self)); } if (!res) { - I_SetCursor(TexMan.GetTextureByName("cursor")); + I_SetCursor(TexMan.GetGameTextureByName("cursor")); } } // Controlled by startup dialog -CVAR (Bool, disableautoload, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) -CVAR (Bool, autoloadbrightmaps, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) -CVAR (Bool, autoloadlights, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) -CVAR (Bool, r_debug_disable_vis_filter, false, 0) +CVAR(Bool, disableautoload, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) +CVAR(Bool, autoloadbrightmaps, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) +CVAR(Bool, autoloadlights, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) +CVAR(Bool, autoloadwidescreen, true, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) +CVAR(Bool, r_debug_disable_vis_filter, false, 0) +CVAR(Int, vid_showpalette, 0, 0) + +CUSTOM_CVAR (Bool, i_discordrpc, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + I_UpdateWindowTitle(); +} +CUSTOM_CVAR(Int, I_FriendlyWindowTitle, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL) +{ + I_UpdateWindowTitle(); +} +CVAR(Bool, cl_nointros, false, CVAR_ARCHIVE) + bool hud_toggled = false; bool wantToRestart; bool DrawFSHUD; // [RH] Draw fullscreen HUD? -TArray allwads; bool devparm; // started game with -devparm const char *D_DrawIcon; // [RH] Patch name of icon to draw on next refresh int NoWipe; // [RH] Allow wipe? (Needs to be set each time) bool singletics = false; // debug flag to cancel adaptiveness FString startmap; bool autostart; -FString StoredWarp; bool advancedemo; FILE *debugfile; -FILE *hashfile; -event_t events[MAXEVENTS]; -int eventhead; -int eventtail; gamestate_t wipegamestate = GS_DEMOSCREEN; // can be -1 to force a wipe bool PageBlank; -FTexture *Advisory; +FTextureID Advisory; FTextureID Page; const char *Subtitle; bool nospriterename; -FStartupInfo DoomStartupInfo; FString lastIWAD; int restart = 0; -bool batchrun; // just run the startup and collect all error messages in a logfile, then quit without any interaction -bool AppActive = true; +extern bool AppActive; +bool playedtitlemusic; + +FStartScreen* StartScreen; cycle_t FrameCycles; @@ -319,111 +383,8 @@ CCMD(togglehud) D_ToggleHud(); } -//========================================================================== -// -// D_ProcessEvents -// -// Send all the events of the given timestamp down the responder chain. -// Events are asynchronous inputs generally generated by the game user. -// Events can be discarded if no responder claims them -// -//========================================================================== - -void D_ProcessEvents (void) -{ - event_t *ev; - - for (; eventtail != eventhead ; eventtail = (eventtail+1)&(MAXEVENTS-1)) - { - ev = &events[eventtail]; - if (ev->type == EV_None) - continue; - if (ev->type == EV_DeviceChange) - UpdateJoystickMenu(I_UpdateDeviceList()); - if (C_Responder (ev)) - continue; // console ate the event - if (M_Responder (ev)) - continue; // menu ate the event - // check events - if (ev->type != EV_Mouse && primaryLevel->localEventManager->Responder(ev)) // [ZZ] ZScript ate the event // update 07.03.17: mouse events are handled directly - continue; - G_Responder (ev); - } -} - -//========================================================================== -// -// D_PostEvent -// -// Called by the I/O functions when input is detected. -// -//========================================================================== - -void D_PostEvent (const event_t *ev) -{ - // Do not post duplicate consecutive EV_DeviceChange events. - if (ev->type == EV_DeviceChange && events[eventhead].type == EV_DeviceChange) - { - return; - } - events[eventhead] = *ev; - if (ev->type == EV_Mouse && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !primaryLevel->localEventManager->Responder(ev) && !paused) - { - if (Button_Mlook.bDown || freelook) - { - int look = int(ev->y * m_pitch * mouse_sensitivity * 16.0); - if (invertmouse) - look = -look; - G_AddViewPitch (look, true); - events[eventhead].y = 0; - } - if (!Button_Strafe.bDown && !lookstrafe) - { - G_AddViewAngle (int(ev->x * m_yaw * mouse_sensitivity * 8.0), true); - events[eventhead].x = 0; - } - if ((events[eventhead].x | events[eventhead].y) == 0) - { - return; - } - } - eventhead = (eventhead+1)&(MAXEVENTS-1); -} - -//========================================================================== -// -// D_RemoveNextCharEvent -// -// Removes the next EV_GUI_Char event in the input queue. Used by the menu, -// since it (generally) consumes EV_GUI_KeyDown events and not EV_GUI_Char -// events, and it needs to ensure that there is no left over input when it's -// done. If there are multiple EV_GUI_KeyDowns before the EV_GUI_Char, then -// there are dead chars involved, so those should be removed, too. We do -// this by changing the message type to EV_None rather than by actually -// removing the event from the queue. -// -//========================================================================== - -void D_RemoveNextCharEvent() -{ - assert(events[eventtail].type == EV_GUI_Event && events[eventtail].subtype == EV_GUI_KeyDown); - for (int evnum = eventtail; evnum != eventhead; evnum = (evnum+1) & (MAXEVENTS-1)) - { - event_t *ev = &events[evnum]; - if (ev->type != EV_GUI_Event) - break; - if (ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_Char) - { - ev->type = EV_None; - if (ev->subtype == EV_GUI_Char) - break; - } - else - { - break; - } - } -} +CVAR(Float, m_pitch, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) // Mouse speeds +CVAR(Float, m_yaw, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) //========================================================================== // @@ -437,9 +398,9 @@ void D_Render(std::function action, bool interpolate) for (auto Level : AllLevels()) { // Check for the presence of dynamic lights at the start of the frame once. - if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4)) + if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4) || Level->LightProbes.Size() > 0) { - Level->HasDynamicLights = !!Level->lights; + Level->HasDynamicLights = Level->lights || Level->LightProbes.Size() > 0; } else Level->HasDynamicLights = false; // lights are off so effectively we have none. if (interpolate) Level->interpolator.DoInterpolations(I_GetTimeFrac()); @@ -468,14 +429,14 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO | CVAR_NOINITCALL) if (self & DF_NO_FREELOOK) { - Net_WriteByte (DEM_CENTERVIEW); + Net_WriteInt8 (DEM_CENTERVIEW); } // If nofov is set, force everybody to the arbitrator's FOV. if ((self & DF_NO_FOV) && consoleplayer == Net_Arbitrator) { float fov; - Net_WriteByte (DEM_FOV); + Net_WriteInt8 (DEM_FOV); // If the game is started with DF_NO_FOV set, the arbitrator's // DesiredFOV will not be set when this callback is run, so @@ -519,6 +480,7 @@ CVAR (Flag, sv_cooplosearmor, dmflags, DF_COOP_LOSE_ARMOR); CVAR (Flag, sv_cooplosepowerups, dmflags, DF_COOP_LOSE_POWERUPS); CVAR (Flag, sv_cooploseammo, dmflags, DF_COOP_LOSE_AMMO); CVAR (Flag, sv_coophalveammo, dmflags, DF_COOP_HALVE_AMMO); +CVAR (Flag, sv_instantreaction, dmflags, DF_INSTANT_REACTION); // Some (hopefully cleaner) interface to these settings. CVAR (Mask, sv_crouch, dmflags, DF_NO_CROUCH|DF_YES_CROUCH); @@ -597,6 +559,29 @@ CVAR (Flag, sv_dontcheckammo, dmflags2, DF2_DONTCHECKAMMO); CVAR (Flag, sv_killbossmonst, dmflags2, DF2_KILLBOSSMONST); CVAR (Flag, sv_nocountendmonst, dmflags2, DF2_NOCOUNTENDMONST); CVAR (Flag, sv_respawnsuper, dmflags2, DF2_RESPAWN_SUPER); +CVAR (Flag, sv_nothingspawn, dmflags2, DF2_NO_COOP_THING_SPAWN); +CVAR (Flag, sv_alwaysspawnmulti, dmflags2, DF2_ALWAYS_SPAWN_MULTI); +CVAR (Flag, sv_novertspread, dmflags2, DF2_NOVERTSPREAD); +CVAR (Flag, sv_noextraammo, dmflags2, DF2_NO_EXTRA_AMMO); + +//========================================================================== +// +// CVAR dmflags3 +// +//========================================================================== + +CUSTOM_CVAR(Int, dmflags3, 0, CVAR_SERVERINFO | CVAR_NOINITCALL) +{ +} + +CVAR(Flag, sv_noplayerclip, dmflags3, DF3_NO_PLAYER_CLIP); +CVAR(Flag, sv_coopsharekeys, dmflags3, DF3_COOP_SHARE_KEYS); +CVAR(Flag, sv_localitems, dmflags3, DF3_LOCAL_ITEMS); +CVAR(Flag, sv_nolocaldrops, dmflags3, DF3_NO_LOCAL_DROPS); +CVAR(Flag, sv_nocoopitems, dmflags3, DF3_NO_COOP_ONLY_ITEMS); +CVAR(Flag, sv_nocoopthings, dmflags3, DF3_NO_COOP_ONLY_THINGS); +CVAR(Flag, sv_rememberlastweapon, dmflags3, DF3_REMEMBER_LAST_WEAP); +CVAR(Flag, sv_pistolstart, dmflags3, DF3_PISTOL_START); //========================================================================== // @@ -638,44 +623,57 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) v = COMPATF_SHORTTEX | COMPATF_STAIRINDEX | COMPATF_USEBLOCKING | COMPATF_NODOORLIGHT | COMPATF_SPRITESORT | COMPATF_TRACE | COMPATF_MISSILECLIP | COMPATF_SOUNDTARGET | COMPATF_DEHHEALTH | COMPATF_CROSSDROPOFF | COMPATF_LIGHT | COMPATF_MASKEDMIDTEX; - w = COMPATF2_FLOORMOVE | COMPATF2_EXPLODE1; + w = COMPATF2_FLOORMOVE | COMPATF2_EXPLODE1 | COMPATF2_NOMBF21; break; case 2: // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set) v = COMPATF_SHORTTEX | COMPATF_STAIRINDEX | COMPATF_USEBLOCKING | COMPATF_NODOORLIGHT | COMPATF_SPRITESORT | COMPATF_TRACE | COMPATF_MISSILECLIP | COMPATF_SOUNDTARGET | COMPATF_NO_PASSMOBJ | COMPATF_LIMITPAIN | - COMPATF_DEHHEALTH | COMPATF_INVISIBILITY | COMPATF_CROSSDROPOFF | COMPATF_CORPSEGIBS | COMPATF_HITSCAN | + COMPATF_DEHHEALTH | COMPATF_INVISIBILITY | COMPATF_CROSSDROPOFF | COMPATF_VILEGHOSTS | COMPATF_HITSCAN | COMPATF_WALLRUN | COMPATF_NOTOSSDROPS | COMPATF_LIGHT | COMPATF_MASKEDMIDTEX; - w = COMPATF2_BADANGLES | COMPATF2_FLOORMOVE | COMPATF2_POINTONLINE | COMPATF2_EXPLODE2; + w = COMPATF2_BADANGLES | COMPATF2_FLOORMOVE | COMPATF2_POINTONLINE | COMPATF2_EXPLODE2 | COMPATF2_NOMBF21 | COMPATF2_VOODOO_ZOMBIES; break; case 3: // Boom compat mode v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_MASKEDMIDTEX; - w = COMPATF2_EXPLODE1; + w = COMPATF2_EXPLODE1 | COMPATF2_NOMBF21; break; case 4: // Old ZDoom compat mode v = COMPATF_SOUNDTARGET | COMPATF_LIGHT; - w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT | COMPATF2_PUSHWINDOW | COMPATF2_CHECKSWITCHRANGE; + w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT | COMPATF2_PUSHWINDOW | COMPATF2_CHECKSWITCHRANGE | COMPATF2_NOMBF21; break; case 5: // MBF compat mode v = COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_MUSHROOM | COMPATF_MBFMONSTERMOVE | COMPATF_NOBLOCKFRIENDS | COMPATF_MASKEDMIDTEX; - w = COMPATF2_EXPLODE1; + w = COMPATF2_EXPLODE1 | COMPATF2_AVOID_HAZARDS | COMPATF2_STAYONLIFT | COMPATF2_NOMBF21; break; case 6: // Boom with some added settings to reenable some 'broken' behavior v = COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_NO_PASSMOBJ | - COMPATF_INVISIBILITY | COMPATF_CORPSEGIBS | COMPATF_HITSCAN | COMPATF_WALLRUN | COMPATF_NOTOSSDROPS | COMPATF_MASKEDMIDTEX; - w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE2; + COMPATF_INVISIBILITY | COMPATF_HITSCAN | COMPATF_WALLRUN | COMPATF_NOTOSSDROPS | COMPATF_MASKEDMIDTEX; + w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE2 | COMPATF2_NOMBF21; break; case 7: // Stricter MBF compatibility - v = COMPATF_CORPSEGIBS | COMPATF_NOBLOCKFRIENDS | COMPATF_MBFMONSTERMOVE | COMPATF_INVISIBILITY | + v = COMPATF_NOBLOCKFRIENDS | COMPATF_MBFMONSTERMOVE | COMPATF_INVISIBILITY | COMPATF_NOTOSSDROPS | COMPATF_MUSHROOM | COMPATF_NO_PASSMOBJ | COMPATF_BOOMSCROLL | COMPATF_WALLRUN | COMPATF_TRACE | COMPATF_HITSCAN | COMPATF_MISSILECLIP | COMPATF_MASKEDMIDTEX | COMPATF_SOUNDTARGET; - w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE1 | COMPATF2_EXPLODE2; + w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE1 | COMPATF2_EXPLODE2 | COMPATF2_AVOID_HAZARDS | COMPATF2_STAYONLIFT | COMPATF2_NOMBF21; + break; + + case 8: // MBF21 compat mode + v = COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_CROSSDROPOFF | + COMPATF_MUSHROOM | COMPATF_MBFMONSTERMOVE | COMPATF_NOBLOCKFRIENDS | COMPATF_MASKEDMIDTEX; + w = COMPATF2_EXPLODE1 | COMPATF2_AVOID_HAZARDS | COMPATF2_STAYONLIFT; + break; + + case 9: // Stricter MBF21 compatibility + v = COMPATF_NOBLOCKFRIENDS | COMPATF_MBFMONSTERMOVE | COMPATF_INVISIBILITY | + COMPATF_NOTOSSDROPS | COMPATF_MUSHROOM | COMPATF_NO_PASSMOBJ | COMPATF_BOOMSCROLL | COMPATF_WALLRUN | + COMPATF_TRACE | COMPATF_HITSCAN | COMPATF_MISSILECLIP | COMPATF_CROSSDROPOFF | COMPATF_MASKEDMIDTEX | COMPATF_SOUNDTARGET; + w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE1 | COMPATF2_EXPLODE2 | COMPATF2_AVOID_HAZARDS | COMPATF2_STAYONLIFT; break; } compatflags = v; @@ -707,7 +705,7 @@ CVAR (Flag, compat_anybossdeath, compatflags, COMPATF_ANYBOSSDEATH); CVAR (Flag, compat_minotaur, compatflags, COMPATF_MINOTAUR); CVAR (Flag, compat_mushroom, compatflags, COMPATF_MUSHROOM); CVAR (Flag, compat_mbfmonstermove, compatflags, COMPATF_MBFMONSTERMOVE); -CVAR (Flag, compat_corpsegibs, compatflags, COMPATF_CORPSEGIBS); +CVAR (Flag, compat_vileghosts, compatflags, COMPATF_VILEGHOSTS); CVAR (Flag, compat_noblockfriends, compatflags, COMPATF_NOBLOCKFRIENDS); CVAR (Flag, compat_spritesort, compatflags, COMPATF_SPRITESORT); CVAR (Flag, compat_hitscan, compatflags, COMPATF_HITSCAN); @@ -725,9 +723,172 @@ CVAR (Flag, compat_checkswitchrange, compatflags2, COMPATF2_CHECKSWITCHRANGE); CVAR (Flag, compat_explode1, compatflags2, COMPATF2_EXPLODE1); CVAR (Flag, compat_explode2, compatflags2, COMPATF2_EXPLODE2); CVAR (Flag, compat_railing, compatflags2, COMPATF2_RAILING); +CVAR (Flag, compat_avoidhazard, compatflags2, COMPATF2_AVOID_HAZARDS); +CVAR (Flag, compat_stayonlift, compatflags2, COMPATF2_STAYONLIFT); +CVAR (Flag, compat_nombf21, compatflags2, COMPATF2_NOMBF21); +CVAR (Flag, compat_voodoozombies, compatflags2, COMPATF2_VOODOO_ZOMBIES); +CVAR (Flag, compat_fdteleport, compatflags2, COMPATF2_FDTELEPORT); CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +EXTERN_CVAR(Bool, r_drawvoxels) +EXTERN_CVAR(Int, gl_tonemap) +static uint32_t GetCaps() +{ + ActorRenderFeatureFlags FlagSet; + if (!V_IsHardwareRenderer()) + { + FlagSet = RFF_UNCLIPPEDTEX; + + if (V_IsTrueColor()) + FlagSet |= RFF_TRUECOLOR; + else + FlagSet |= RFF_COLORMAP; + + } + else + { + // describe our basic feature set + FlagSet = RFF_FLATSPRITES | RFF_MODELS | RFF_SLOPE3DFLOORS | + RFF_TILTPITCH | RFF_ROLLSPRITES | RFF_POLYGONAL | RFF_MATSHADER | RFF_POSTSHADER | RFF_BRIGHTMAP; + + if (gl_tonemap != 5) // not running palette tonemap shader + FlagSet |= RFF_TRUECOLOR; + } + + if (r_drawvoxels) + FlagSet |= RFF_VOXELS; + return (uint32_t)FlagSet; +} + +//========================================================================== +// +// +// +//========================================================================== + +static void DrawPaletteTester(int paletteno) +{ + int blocksize = screen->GetHeight() / 50; + + int t = paletteno; + int k = 0; + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 16; ++j) + { + PalEntry pe; + if (t > 1) + { + auto palette = GPalette.GetTranslation(TRANSLATION_Standard, t - 2)->Palette; + pe = palette[k]; + } + else GPalette.BaseColors[k]; + k++; + Dim(twod, pe, 1.f, j * blocksize, i * blocksize, blocksize, blocksize); + } + } +} + +//========================================================================== +// +// DFrameBuffer :: DrawRateStuff +// +// Draws the fps counter, dot ticker, and palette debug. +// +//========================================================================== +uint64_t LastFPS, LastMSCount; + +void CalcFps() +{ + static uint64_t LastMS = 0, LastSec = 0, FrameCount = 0, LastTic = 0; + + uint64_t ms = screen->FrameTime; + uint64_t howlong = ms - LastMS; + if ((signed)howlong > 0) // do this only once per frame. + { + uint32_t thisSec = (uint32_t)(ms / 1000); + if (LastSec < thisSec) + { + LastFPS = FrameCount / (thisSec - LastSec); + LastSec = thisSec; + FrameCount = 0; + } + FrameCount++; + LastMS = ms; + LastMSCount = howlong; + } +} + +ADD_STAT(fps) +{ + CalcFps(); + return FStringf("%2llu ms (%3llu fps)", (unsigned long long)LastMSCount , (unsigned long long)LastFPS); +} + +static void DrawRateStuff() +{ + static uint64_t LastMS = 0, LastSec = 0, FrameCount = 0, LastTic = 0; + + // Draws frame time and cumulative fps + if (vid_fps) + { + CalcFps(); + char fpsbuff[40]; + int chars; + int rate_x; + int textScale = active_con_scale(twod); + + chars = mysnprintf(fpsbuff, countof(fpsbuff), "%2llu ms (%3llu fps)", (unsigned long long)LastMSCount, (unsigned long long)LastFPS); + rate_x = screen->GetWidth() / textScale - NewConsoleFont->StringWidth(&fpsbuff[0]); + ClearRect(twod, rate_x * textScale, 0, screen->GetWidth(), NewConsoleFont->GetHeight() * textScale, GPalette.BlackIndex, 0); + DrawText(twod, NewConsoleFont, CR_WHITE, rate_x, 0, (char*)&fpsbuff[0], + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); + } + + int Height = screen->GetHeight(); + + // draws little dots on the bottom of the screen + if (ticker) + { + int64_t t = I_GetTime(); + int64_t tics = t - LastTic; + + LastTic = t; + if (tics > 20) tics = 20; + + int i; + for (i = 0; i < tics * 2; i += 2) ClearRect(twod, i, Height - 1, i + 1, Height, 255, 0); + for (; i < 20 * 2; i += 2) ClearRect(twod, i, Height - 1, i + 1, Height, 0, 0); + } + + // draws the palette for debugging + if (vid_showpalette) + { + DrawPaletteTester(vid_showpalette); + } +} + +static void DrawOverlays() +{ + NetUpdate (); + C_DrawConsole (); + M_Drawer (); + DrawRateStuff(); + if (!hud_toggled) + FStat::PrintStat (twod); +} + +static void End2DAndUpdate() +{ + twod->End(); + CheckBench(); + screen->Update(); + twod->OnFrameDone(); +} + //========================================================================== // // D_Display @@ -738,7 +899,7 @@ CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) void D_Display () { - FTexture *wipe = nullptr; + FTexture *wipestart = nullptr; int wipe_type; sector_t *viewsec; @@ -756,7 +917,7 @@ void D_Display () cycles.Clock(); r_UseVanillaTransparency = UseVanillaTransparency(); // [SP] Cache UseVanillaTransparency() call - r_renderercaps = screen->GetCaps(); // [SP] Get the current capabilities of the renderer + r_renderercaps = GetCaps(); // [SP] Get the current capabilities of the renderer if (players[consoleplayer].camera == NULL) { @@ -766,14 +927,11 @@ void D_Display () auto &vp = r_viewpoint; if (viewactive) { - DAngle fov = 90.f; + DAngle fov = DAngle::fromDeg(90.); AActor *cam = players[consoleplayer].camera; if (cam) - { - if (cam->player) - fov = cam->player->FOV; - else fov = cam->CameraFOV; - } + fov = DAngle::fromDeg(cam->GetFOV(I_GetTimeFrac())); + R_SetFOV(vp, fov); } @@ -781,7 +939,7 @@ void D_Display () if (setmodeneeded) { setmodeneeded = false; - screen->ToggleFullscreen(fullscreen); + screen->ToggleFullscreen(vid_fullscreen); V_OutputResized(screen->GetWidth(), screen->GetHeight()); } @@ -801,10 +959,10 @@ void D_Display () } // [RH] Allow temporarily disabling wipes - if (NoWipe) + if (NoWipe || !CanWipe()) { - NoWipe--; - wipe = nullptr; + if (NoWipe > 0) NoWipe--; + wipestart = nullptr; wipegamestate = gamestate; } // No wipes when in a stereo3D VR mode @@ -813,7 +971,7 @@ void D_Display () if (vr_mode == 0 || vid_rendermode != 4) { // save the current screen if about to wipe - wipe = screen->WipeStartScreen (); + wipestart = screen->WipeStartScreen(); switch (wipegamestate) { @@ -839,14 +997,14 @@ void D_Display () } else { - wipe = nullptr; + wipestart = nullptr; } screen->FrameTime = I_msTimeFS(); - TexMan.UpdateAnimations(screen->FrameTime); + TexAnim.UpdateAnimations(screen->FrameTime); R_UpdateSky(screen->FrameTime); screen->BeginFrame(); - screen->ClearClipRect(); + twod->ClearClipRect(); if ((gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL) && gametic != 0) { // [ZZ] execute event hook that we just started the frame @@ -855,13 +1013,13 @@ void D_Display () D_Render([&]() { - viewsec = screen->RenderView(&players[consoleplayer]); + viewsec = RenderView(&players[consoleplayer]); }, true); - screen->Begin2D(); + twod->Begin(screen->GetWidth(), screen->GetHeight()); if (!hud_toggled) { - screen->DrawBlend(viewsec); + V_DrawBlend(viewsec); if (automapactive) { primaryLevel->automap->Drawer ((hud_althud && viewheight == SCREENHEIGHT) ? viewheight : StatusBar->GetTopOfStatusbar()); @@ -905,28 +1063,26 @@ void D_Display () } else { - screen->Begin2D(); + twod->Begin(screen->GetWidth(), screen->GetHeight()); switch (gamestate) { case GS_FULLCONSOLE: - screen->Begin2D(); + D_PageDrawer(); C_DrawConsole (); M_Drawer (); - screen->End2DAndUpdate (); + End2DAndUpdate (); return; - case GS_INTERMISSION: - WI_Drawer (); - break; - - case GS_FINALE: - F_Drawer (); - break; - case GS_DEMOSCREEN: D_PageDrawer (); break; + case GS_CUTSCENE: + case GS_INTRO: + ScreenJobDraw(); + break; + + default: break; } @@ -936,23 +1092,33 @@ void D_Display () CT_Drawer (); // draw pause pic - if ((paused || pauseext) && menuactive == MENU_Off) + if ((paused || pauseext) && menuactive == MENU_Off && StatusBar != nullptr) { - FTexture *tex; - int x; - - tex = TexMan.GetTextureByName(gameinfo.PauseSign, true); - x = (SCREENWIDTH - tex->GetDisplayWidth() * CleanXfac)/2 + - tex->GetDisplayLeftOffset() * CleanXfac; - screen->DrawTexture (tex, x, 4, DTA_CleanNoMove, true, TAG_DONE); - if (paused && multiplayer) + // [MK] optionally let the status bar handle this + bool skip = false; + IFVIRTUALPTR(StatusBar, DBaseStatusBar, DrawPaused) + { + VMValue params[] { (DObject*)StatusBar, paused-1 }; + int rv; + VMReturn ret(&rv); + VMCall(func, params, countof(params), &ret, 1); + skip = !!rv; + } + if ( !skip ) { - FFont *font = generic_ui? NewSmallFont : SmallFont; - FString pstring = GStrings("TXT_BY"); - pstring.Substitute("%s", players[paused - 1].userinfo.GetName()); - screen->DrawText(font, CR_RED, - (screen->GetWidth() - font->StringWidth(pstring)*CleanXfac) / 2, - (tex->GetDisplayHeight() * CleanYfac) + 4, pstring, DTA_CleanNoMove, true, TAG_DONE); + auto tex = TexMan.GetGameTextureByName(gameinfo.PauseSign.GetChars(), true); + double x = (SCREENWIDTH - tex->GetDisplayWidth() * CleanXfac)/2 + + tex->GetDisplayLeftOffset() * CleanXfac; + DrawTexture(twod, tex, x, 4, DTA_CleanNoMove, true, TAG_DONE); + if (paused && multiplayer) + { + FFont *font = generic_ui? NewSmallFont : SmallFont; + FString pstring = GStrings.GetString("TXT_BY"); + pstring.Substitute("%s", players[paused - 1].userinfo.GetName()); + DrawText(twod, font, CR_RED, + (twod->GetWidth() - font->StringWidth(pstring)*CleanXfac) / 2, + (tex->GetDisplayHeight() * CleanYfac) + 4, pstring.GetChars(), DTA_CleanNoMove, true, TAG_DONE); + } } } @@ -964,8 +1130,8 @@ void D_Display () D_DrawIcon = NULL; if (picnum.isValid()) { - FTexture *tex = TexMan.GetTexture(picnum); - screen->DrawTexture (tex, 160 - tex->GetDisplayWidth()/2, 100 - tex->GetDisplayHeight()/2, + auto tex = TexMan.GetGameTexture(picnum); + DrawTexture(twod, tex, 160 - tex->GetDisplayWidth()/2, 100 - tex->GetDisplayHeight()/2, DTA_320x200, true, TAG_DONE); } NoWipe = 10; @@ -977,54 +1143,17 @@ void D_Display () } } - if (!wipe || NoWipe < 0 || wipe_type == wipe_None || hud_toggled) + if (!wipestart || NoWipe < 0 || wipe_type == wipe_None || hud_toggled) { - if (wipe != nullptr) delete wipe; - wipe = nullptr; - NetUpdate (); // send out any new accumulation - // normal update - // draw ZScript UI stuff - C_DrawConsole (); // draw console - M_Drawer (); // menu is drawn even on top of everything - if (!hud_toggled) - FStat::PrintStat (); - screen->End2DAndUpdate (); + if (wipestart != nullptr) wipestart->DecRef(); + wipestart = nullptr; + DrawOverlays(); + End2DAndUpdate (); } else { - // wipe update - uint64_t wipestart, nowtime, diff; - bool done; - - GSnd->SetSfxPaused(true, 1); - I_FreezeTime(true); - screen->End2D(); - auto wipend = screen->WipeEndScreen (); - auto wiper = Wiper::Create(wipe_type); - wiper->SetTextures(wipe, wipend); - - wipestart = I_msTime(); NetUpdate(); // send out any new accumulation - - do - { - do - { - I_WaitVBL(2); - nowtime = I_msTime(); - diff = (nowtime - wipestart) * 40 / 1000; // Using 35 here feels too slow. - } while (diff < 1); - wipestart = nowtime; - screen->Begin2D(); - done = wiper->Run(1); - C_DrawConsole (); // console and - M_Drawer (); // menu are drawn even on top of wipes - screen->End2DAndUpdate (); - NetUpdate (); // [RH] not sure this is needed anymore - } while (!done); - delete wiper; - I_FreezeTime(false); - GSnd->SetSfxPaused(false, 1); + PerformWipe(wipestart, screen->WipeEndScreen(), wipe_type, false, DrawOverlays); } cycles.Unclock(); FrameCycles = cycles; @@ -1055,7 +1184,6 @@ void D_ErrorCleanup () { menuactive = MENU_Off; } - if (gamestate == GS_INTERMISSION) gamestate = GS_DEMOSCREEN; insave = false; ClearGlobalVMStack(); } @@ -1077,14 +1205,16 @@ void D_DoomLoop () r_NoInterpolate = true; Page.SetInvalid(); Subtitle = nullptr; - Advisory = nullptr; + Advisory.SetInvalid(); - vid_cursor.Callback(); + vid_cursor->Callback(); for (;;) { try { + GStrings.SetDefaultGender(players[consoleplayer].userinfo.GetGender()); // cannot be done when the CVAR changes because we don't know if it's for the consoleplayer. + // frame syncronous IO operations if (gametic > lasttic) { @@ -1117,6 +1247,7 @@ void D_DoomLoop () } // Update display, next frame, with current state. I_StartTic (); + D_ProcessEvents(); D_Display (); S_UpdateMusic(); if (wantToRestart) @@ -1125,18 +1256,26 @@ void D_DoomLoop () return; } } - catch (CRecoverableError &error) + catch (const CRecoverableError &error) { if (error.GetMessage ()) { - Printf (PRINT_BOLD, "\n%s\n", error.GetMessage()); + Printf (PRINT_NONOTIFY | PRINT_BOLD, "\n%s\n", error.GetMessage()); } D_ErrorCleanup (); } + catch (const FileSystemException& error) // in case this propagates up to here it should be treated as a recoverable error. + { + if (error.what()) + { + Printf(PRINT_NONOTIFY | PRINT_BOLD, "\n%s\n", error.what()); + } + D_ErrorCleanup(); + } catch (CVMAbortException &error) { error.MaybePrintMessage(); - Printf("%s", error.stacktrace.GetChars()); + Printf(PRINT_NONOTIFY | PRINT_BOLD, "%s", error.stacktrace.GetChars()); D_ErrorCleanup(); } } @@ -1162,10 +1301,10 @@ void D_PageTicker (void) void D_PageDrawer (void) { - screen->Clear(0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0); + ClearRect(twod, 0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0); if (Page.Exists()) { - screen->DrawTexture (TexMan.GetTexture(Page, true), 0, 0, + DrawTexture(twod, Page, true, 0, 0, DTA_Fullscreen, true, DTA_Masked, false, DTA_BilinearFilter, true, @@ -1173,11 +1312,12 @@ void D_PageDrawer (void) } if (Subtitle != nullptr) { - DrawFullscreenSubtitle(GStrings[Subtitle]); + FFont* font = generic_ui ? NewSmallFont : SmallFont; + DrawFullscreenSubtitle(font, GStrings.CheckString(Subtitle)); } - if (Advisory != nullptr) + if (Advisory.isValid()) { - screen->DrawTexture (Advisory, 4, 160, DTA_320x200, true, TAG_DONE); + DrawTexture(twod, Advisory, true, 4, 160, DTA_320x200, true, TAG_DONE); } } @@ -1223,7 +1363,7 @@ void D_DoStrifeAdvanceDemo () case 0: pagetic = 6 * TICRATE; pagename = "TITLEPIC"; - if (Wads.CheckNumForName ("d_logo", ns_music) < 0) + if (fileSystem.CheckNumForName ("d_logo", ns_music) < 0) { // strife0.wad does not have d_logo S_StartMusic (""); } @@ -1251,7 +1391,7 @@ void D_DoStrifeAdvanceDemo () case 3: pagetic = 7 * TICRATE; pagename = "PANEL1"; - subtitle = "TXT_SUB_INTRO1"; + subtitle = "$TXT_SUB_INTRO1"; S_Sound (CHAN_VOICE, CHANF_UI, voices[0], 1, ATTN_NORM); // The new Strife teaser has D_FMINTR. // The full retail Strife has D_INTRO. @@ -1262,35 +1402,35 @@ void D_DoStrifeAdvanceDemo () case 4: pagetic = 9 * TICRATE; pagename = "PANEL2"; - subtitle = "TXT_SUB_INTRO2"; + subtitle = "$TXT_SUB_INTRO2"; S_Sound (CHAN_VOICE, CHANF_UI, voices[1], 1, ATTN_NORM); break; case 5: pagetic = 12 * TICRATE; pagename = "PANEL3"; - subtitle = "TXT_SUB_INTRO3"; + subtitle = "$TXT_SUB_INTRO3"; S_Sound (CHAN_VOICE, CHANF_UI, voices[2], 1, ATTN_NORM); break; case 6: pagetic = 11 * TICRATE; pagename = "PANEL4"; - subtitle = "TXT_SUB_INTRO4"; + subtitle = "$TXT_SUB_INTRO4"; S_Sound (CHAN_VOICE, CHANF_UI, voices[3], 1, ATTN_NORM); break; case 7: pagetic = 10 * TICRATE; pagename = "PANEL5"; - subtitle = "TXT_SUB_INTRO5"; + subtitle = "$TXT_SUB_INTRO5"; S_Sound (CHAN_VOICE, CHANF_UI, voices[4], 1, ATTN_NORM); break; case 8: pagetic = 16 * TICRATE; pagename = "PANEL6"; - subtitle = "TXT_SUB_INTRO6"; + subtitle = "$TXT_SUB_INTRO6"; S_Sound (CHAN_VOICE, CHANF_UI, voices[5], 1, ATTN_NORM); break; @@ -1366,20 +1506,21 @@ void D_DoAdvanceDemo (void) case 3: if (gameinfo.advisoryTime) { - Advisory = TexMan.GetTextureByName("ADVISOR"); + Advisory = TexMan.GetTextureID("ADVISOR", ETextureType::MiscPatch); demosequence = 1; pagetic = (int)(gameinfo.advisoryTime * TICRATE); break; } // fall through to case 1 if no advisory notice + [[fallthrough]]; case 1: - Advisory = NULL; + Advisory.SetInvalid(); if (!M_DemoNoPlay) { democount++; mysnprintf (demoname + 4, countof(demoname) - 4, "%d", democount); - if (Wads.CheckNumForName (demoname) < 0) + if (fileSystem.CheckNumForName (demoname) < 0) { demosequence = 0; democount = 0; @@ -1393,13 +1534,15 @@ void D_DoAdvanceDemo (void) break; } } + [[fallthrough]]; default: case 0: gamestate = GS_DEMOSCREEN; pagename = gameinfo.TitlePage; pagetic = (int)(gameinfo.titleTime * TICRATE); - S_ChangeMusic (gameinfo.titleMusic, gameinfo.titleOrder, false); + if (!playedtitlemusic) S_ChangeMusic (gameinfo.titleMusic.GetChars(), gameinfo.titleOrder, false); + playedtitlemusic = true; demosequence = 3; pagecount = 0; C_HideConsole (); @@ -1410,7 +1553,7 @@ void D_DoAdvanceDemo (void) gamestate = GS_DEMOSCREEN; if (gameinfo.creditPages.Size() > 0) { - pagename = gameinfo.creditPages[pagecount]; + pagename = gameinfo.creditPages[pagecount].GetChars(); pagecount = (pagecount+1) % gameinfo.creditPages.Size(); } demosequence = 1; @@ -1420,7 +1563,7 @@ void D_DoAdvanceDemo (void) if (pagename.IsNotEmpty()) { - Page = TexMan.CheckForTexture(pagename, ETextureType::MiscPatch); + Page = TexMan.CheckForTexture(pagename.GetChars(), ETextureType::MiscPatch); } } @@ -1432,6 +1575,7 @@ void D_DoAdvanceDemo (void) void D_StartTitle (void) { + playedtitlemusic = false; gameaction = ga_nothing; demosequence = -1; D_AdvanceDemo (); @@ -1466,7 +1610,7 @@ void ParseCVarInfo() int lump, lastlump = 0; bool addedcvars = false; - while ((lump = Wads.FindLump("CVARINFO", &lastlump)) != -1) + while ((lump = fileSystem.FindLump("CVARINFO", &lastlump)) != -1) { FScanner sc(lump); sc.SetCMode(true); @@ -1478,6 +1622,8 @@ void ParseCVarInfo() ECVarType cvartype = CVAR_Dummy; int cvarflags = CVAR_MOD|CVAR_ARCHIVE; FBaseCVar *cvar; + bool customCVar = false; + FName customCVarClassName; // Check for flag tokens. while (sc.TokenType == TK_Identifier) @@ -1506,6 +1652,14 @@ void ParseCVarInfo() { cvarflags |= CVAR_CONFIG_ONLY; } + else if (stricmp(sc.String, "handlerClass") == 0) + { + sc.MustGetStringName("("); + sc.MustGetString(); + customCVar = true; + customCVarClassName = sc.String; + sc.MustGetStringName(")"); + } else { sc.ScriptError("Unknown cvar attribute '%s'", sc.String); @@ -1588,7 +1742,7 @@ void ParseCVarInfo() } } // Now create the cvar. - cvar = C_CreateCVar(cvarname, cvartype, cvarflags); + cvar = customCVar ? C_CreateZSCustomCVar(cvarname.GetChars(), cvartype, cvarflags, customCVarClassName) : C_CreateCVar(cvarname.GetChars(), cvartype, cvarflags); if (cvardefault != NULL) { UCVarValue val; @@ -1604,329 +1758,89 @@ void ParseCVarInfo() // clutter up the cvar space when not playing mods with custom cvars. if (addedcvars) { - GameConfig->DoModSetup (gameinfo.ConfigName); + GameConfig->DoModSetup (gameinfo.ConfigName.GetChars()); } } //========================================================================== // -// D_AddFile +// ConsiderPatches +// +// Tries to add any deh/bex patches from the command line. // //========================================================================== -bool D_AddFile (TArray &wadfiles, const char *file, bool check, int position) +bool ConsiderPatches (const char *arg) { - if (file == NULL || *file == '\0') - { - return false; - } + int i, argc; + FString *args; + const char *f; - if (check && !DirEntryExists (file)) + argc = Args->CheckParmList(arg, &args); + for (i = 0; i < argc; ++i) { - const char *f = BaseFileSearch (file, ".wad"); - if (f == NULL) + if ( (f = BaseFileSearch(args[i].GetChars(), ".deh", false, GameConfig)) || + (f = BaseFileSearch(args[i].GetChars(), ".bex", false, GameConfig)) ) { - Printf ("Can't find '%s'\n", file); - return false; + D_LoadDehFile(f, 0); } - file = f; } - - FString f = file; - FixPathSeperator(f); - if (position == -1) wadfiles.Push(f); - else wadfiles.Insert(position, f); - return true; + return argc > 0; } //========================================================================== // -// D_AddWildFile +// D_MultiExec // //========================================================================== -void D_AddWildFile (TArray &wadfiles, const char *value) +FExecList *D_MultiExec (FArgs *list, FExecList *exec) { - if (value == NULL || *value == '\0') + for (int i = 0; i < list->NumArgs(); ++i) { - return; + exec = C_ParseExecFile(list->GetArg(i), exec); } - const char *wadfile = BaseFileSearch (value, ".wad"); + return exec; +} + +static void GetCmdLineFiles(std::vector& wadfiles) +{ + FString *args; + int i, argc; + + argc = Args->CheckParmList("-file", &args); - if (wadfile != NULL) + // [RL0] Check for array size to only add new wads + for (i = wadfiles.size(); i < argc; ++i) { - D_AddFile (wadfiles, wadfile); + D_AddWildFile(wadfiles, args[i].GetChars(), ".wad", GameConfig); } - else - { // Try pattern matching - findstate_t findstate; - char path[PATH_MAX]; - char *sep; - void *handle = I_FindFirst (value, &findstate); +} + + +static FString ParseGameInfo(std::vector &pwads, const char *fn, const char *data, int size) +{ + FScanner sc; + FString iwad; + int pos = 0; + bool isDir; + + const char *lastSlash = strrchr (fn, '/'); + if (lastSlash == NULL) + lastSlash = strrchr (fn, ':'); - strcpy (path, value); - sep = strrchr (path, '/'); - if (sep == NULL) + sc.OpenMem("GAMEINFO", data, size); + while(sc.GetToken()) + { + sc.TokenMustBe(TK_Identifier); + FString nextKey = sc.String; + sc.MustGetToken('='); + if (!nextKey.CompareNoCase("IWAD")) { - sep = strrchr (path, '\\'); -#ifdef _WIN32 - if (sep == NULL && path[1] == ':') - { - sep = path + 1; - } -#endif + sc.MustGetString(); + iwad = sc.String; } - - if (handle != ((void *)-1)) - { - do - { - if (!(I_FindAttr(&findstate) & FA_DIREC)) - { - if (sep == NULL) - { - D_AddFile (wadfiles, I_FindName (&findstate)); - } - else - { - strcpy (sep+1, I_FindName (&findstate)); - D_AddFile (wadfiles, path); - } - } - } while (I_FindNext (handle, &findstate) == 0); - } - I_FindClose (handle); - } -} - -//========================================================================== -// -// D_AddConfigWads -// -// Adds all files in the specified config file section. -// -//========================================================================== - -void D_AddConfigWads (TArray &wadfiles, const char *section) -{ - if (GameConfig->SetSection (section)) - { - const char *key; - const char *value; - FConfigFile::Position pos; - - while (GameConfig->NextInSection (key, value)) - { - if (stricmp (key, "Path") == 0) - { - // D_AddWildFile resets GameConfig's position, so remember it - GameConfig->GetPosition (pos); - D_AddWildFile (wadfiles, ExpandEnvVars(value)); - // Reset GameConfig's position to get next wad - GameConfig->SetPosition (pos); - } - } - } -} - -//========================================================================== -// -// D_AddDirectory -// -// Add all .wad files in a directory. Does not descend into subdirectories. -// -//========================================================================== - -static void D_AddDirectory (TArray &wadfiles, const char *dir) -{ - char curdir[PATH_MAX]; - - if (getcwd (curdir, PATH_MAX)) - { - char skindir[PATH_MAX]; - findstate_t findstate; - void *handle; - size_t stuffstart; - - stuffstart = strlen (dir); - memcpy (skindir, dir, stuffstart*sizeof(*dir)); - skindir[stuffstart] = 0; - - if (skindir[stuffstart-1] == '/') - { - skindir[--stuffstart] = 0; - } - - if (!chdir (skindir)) - { - skindir[stuffstart++] = '/'; - if ((handle = I_FindFirst ("*.wad", &findstate)) != (void *)-1) - { - do - { - if (!(I_FindAttr (&findstate) & FA_DIREC)) - { - strcpy (skindir + stuffstart, I_FindName (&findstate)); - D_AddFile (wadfiles, skindir); - } - } while (I_FindNext (handle, &findstate) == 0); - I_FindClose (handle); - } - } - chdir (curdir); - } -} - - -//========================================================================== -// -// BaseFileSearch -// -// If a file does not exist at , looks for it in the directories -// specified in the config file. Returns the path to the file, if found, -// or NULL if it could not be found. -// -//========================================================================== - -const char *BaseFileSearch (const char *file, const char *ext, bool lookfirstinprogdir) -{ - static char wad[PATH_MAX]; - - if (file == NULL || *file == '\0') - { - return NULL; - } - if (lookfirstinprogdir) - { - mysnprintf (wad, countof(wad), "%s%s%s", progdir.GetChars(), progdir.Back() == '/' ? "" : "/", file); - if (DirEntryExists (wad)) - { - return wad; - } - } - - if (DirEntryExists (file)) - { - mysnprintf (wad, countof(wad), "%s", file); - return wad; - } - - if (GameConfig != NULL && GameConfig->SetSection ("FileSearch.Directories")) - { - const char *key; - const char *value; - - while (GameConfig->NextInSection (key, value)) - { - if (stricmp (key, "Path") == 0) - { - FString dir; - - dir = NicePath(value); - if (dir.IsNotEmpty()) - { - mysnprintf (wad, countof(wad), "%s%s%s", dir.GetChars(), dir.Back() == '/' ? "" : "/", file); - if (DirEntryExists (wad)) - { - return wad; - } - } - } - } - } - - // Retry, this time with a default extension - if (ext != NULL) - { - FString tmp = file; - DefaultExtension (tmp, ext); - return BaseFileSearch (tmp, NULL); - } - return NULL; -} - -//========================================================================== -// -// ConsiderPatches -// -// Tries to add any deh/bex patches from the command line. -// -//========================================================================== - -bool ConsiderPatches (const char *arg) -{ - int i, argc; - FString *args; - const char *f; - - argc = Args->CheckParmList(arg, &args); - for (i = 0; i < argc; ++i) - { - if ( (f = BaseFileSearch(args[i], ".deh")) || - (f = BaseFileSearch(args[i], ".bex")) ) - { - D_LoadDehFile(f); - } - } - return argc > 0; -} - -//========================================================================== -// -// D_MultiExec -// -//========================================================================== - -FExecList *D_MultiExec (FArgs *list, FExecList *exec) -{ - for (int i = 0; i < list->NumArgs(); ++i) - { - exec = C_ParseExecFile(list->GetArg(i), exec); - } - return exec; -} - -static void GetCmdLineFiles(TArray &wadfiles) -{ - FString *args; - int i, argc; - - argc = Args->CheckParmList("-file", &args); - for (i = 0; i < argc; ++i) - { - D_AddWildFile(wadfiles, args[i]); - } -} - -static void CopyFiles(TArray &to, TArray &from) -{ - unsigned int ndx = to.Reserve(from.Size()); - for(unsigned i=0;i &pwads, const char *fn, const char *data, int size) -{ - FScanner sc; - FString iwad; - int pos = 0; - - const char *lastSlash = strrchr (fn, '/'); - - sc.OpenMem("GAMEINFO", data, size); - while(sc.GetToken()) - { - sc.TokenMustBe(TK_Identifier); - FString nextKey = sc.String; - sc.MustGetToken('='); - if (!nextKey.CompareNoCase("IWAD")) - { - sc.MustGetString(); - iwad = sc.String; - } - else if (!nextKey.CompareNoCase("LOAD")) + else if (!nextKey.CompareNoCase("LOAD")) { do { @@ -1938,20 +1852,19 @@ static FString ParseGameInfo(TArray &pwads, const char *fn, const char FString checkpath; if (lastSlash != NULL) { - checkpath = FString(fn, (lastSlash - fn) + 1); - checkpath += sc.String; + checkpath = FString(fn, lastSlash - fn) + '/' + sc.String; } else { checkpath = sc.String; } - if (!FileExists(checkpath)) + if (!DirEntryExists(checkpath.GetChars(), &isDir)) { - pos += D_AddFile(pwads, sc.String, true, pos); + pos += D_AddFile(pwads, sc.String, true, pos, GameConfig); } else { - pos += D_AddFile(pwads, checkpath, true, pos); + pos += D_AddFile(pwads, checkpath.GetChars(), true, pos, GameConfig); } } while (sc.CheckToken(',')); @@ -1964,44 +1877,59 @@ static FString ParseGameInfo(TArray &pwads, const char *fn, const char else if (!nextKey.CompareNoCase("STARTUPTITLE")) { sc.MustGetString(); - DoomStartupInfo.Name = sc.String; + GameStartupInfo.Name = sc.String; } else if (!nextKey.CompareNoCase("STARTUPCOLORS")) { sc.MustGetString(); - DoomStartupInfo.FgColor = V_GetColor(NULL, sc); + GameStartupInfo.FgColor = V_GetColor(sc); sc.MustGetStringName(","); sc.MustGetString(); - DoomStartupInfo.BkColor = V_GetColor(NULL, sc); + GameStartupInfo.BkColor = V_GetColor(sc); } else if (!nextKey.CompareNoCase("STARTUPTYPE")) { sc.MustGetString(); FString sttype = sc.String; if (!sttype.CompareNoCase("DOOM")) - DoomStartupInfo.Type = FStartupInfo::DoomStartup; + GameStartupInfo.Type = FStartupInfo::DoomStartup; else if (!sttype.CompareNoCase("HERETIC")) - DoomStartupInfo.Type = FStartupInfo::HereticStartup; + GameStartupInfo.Type = FStartupInfo::HereticStartup; else if (!sttype.CompareNoCase("HEXEN")) - DoomStartupInfo.Type = FStartupInfo::HexenStartup; + GameStartupInfo.Type = FStartupInfo::HexenStartup; else if (!sttype.CompareNoCase("STRIFE")) - DoomStartupInfo.Type = FStartupInfo::StrifeStartup; - else DoomStartupInfo.Type = FStartupInfo::DefaultStartup; + GameStartupInfo.Type = FStartupInfo::StrifeStartup; + else GameStartupInfo.Type = FStartupInfo::DefaultStartup; } else if (!nextKey.CompareNoCase("STARTUPSONG")) { sc.MustGetString(); - DoomStartupInfo.Song = sc.String; + GameStartupInfo.Song = sc.String; } else if (!nextKey.CompareNoCase("LOADLIGHTS")) { sc.MustGetNumber(); - DoomStartupInfo.LoadLights = !!sc.Number; + GameStartupInfo.LoadLights = !!sc.Number; } else if (!nextKey.CompareNoCase("LOADBRIGHTMAPS")) { sc.MustGetNumber(); - DoomStartupInfo.LoadBrightmaps = !!sc.Number; + GameStartupInfo.LoadBrightmaps = !!sc.Number; + } + else if (!nextKey.CompareNoCase("LOADWIDESCREEN")) + { + sc.MustGetNumber(); + GameStartupInfo.LoadWidescreen = !!sc.Number; + } + else if (!nextKey.CompareNoCase("DISCORDAPPID")) + { + sc.MustGetString(); + GameStartupInfo.DiscordAppId = sc.String; + } + else if (!nextKey.CompareNoCase("STEAMAPPID")) + { + sc.MustGetString(); + GameStartupInfo.SteamAppId = sc.String; } else { @@ -2016,51 +1944,31 @@ static FString ParseGameInfo(TArray &pwads, const char *fn, const char return iwad; } -static FString CheckGameInfo(TArray & pwads) +void GetReserved(LumpFilterInfo& lfi) { - // scan the list of WADs backwards to find the last one that contains a GAMEINFO lump - for(int i=pwads.Size()-1; i>=0; i--) - { - bool isdir = false; - FResourceFile *resfile; - const char *filename = pwads[i]; + lfi.reservedFolders = { "flats/", "textures/", "hires/", "sprites/", "voxels/", "colormaps/", "acs/", "maps/", "voices/", "patches/", "graphics/", "sounds/", "music/", + "materials/", "models/", "fonts/", "brightmaps/" }; + lfi.requiredPrefixes = { "mapinfo", "zmapinfo", "umapinfo", "gameinfo", "sndinfo", "sndseq", "sbarinfo", "menudef", "gldefs", "animdefs", "decorate", "zscript", "iwadinfo", "complvl", "terrain", "maps/" }; + lfi.blockednames = { "*.bat", "*.exe", "__macosx/*", "*/__macosx/*" }; +} - // Does this exist? If so, is it a directory? - if (!DirEntryExists(pwads[i], &isdir)) - { - Printf(TEXTCOLOR_RED "Could not stat %s\n", filename); - continue; - } +static FString CheckGameInfo(std::vector & pwads) +{ + FileSystem check; - if (!isdir) - { - FileReader fr; - if (!fr.OpenFile(filename)) - { - // Didn't find file - continue; - } - resfile = FResourceFile::OpenResourceFile(filename, fr, true); - } - else - resfile = FResourceFile::OpenDirectory(filename, true); + LumpFilterInfo lfi; + GetReserved(lfi); - if (resfile != NULL) + // Open the entire list as a temporary file system and look for a GAMEINFO lump. The last one will automatically win. + if (check.InitMultipleFiles(pwads, &lfi, nullptr)) + { + int num = check.CheckNumForName("GAMEINFO"); + if (num >= 0) { - uint32_t cnt = resfile->LumpCount(); - for(int i=cnt-1; i>=0; i--) - { - FResourceLump *lmp = resfile->GetLump(i); - - if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "GAMEINFO")) - { - // Found one! - FString iwad = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->CacheLump(), lmp->LumpSize); - delete resfile; - return iwad; - } - } - delete resfile; + // Found one! + auto data = check.ReadFile(num); + auto wadname = check.GetResourceFileName(check.GetFileContainer(num)); + return ParseGameInfo(pwads, wadname, data.string(), (int)data.size()); } } return ""; @@ -2074,9 +1982,9 @@ static FString CheckGameInfo(TArray & pwads) static void SetMapxxFlag() { - int lump_name = Wads.CheckNumForName("MAP01", ns_global, Wads.GetIwadNum()); - int lump_wad = Wads.CheckNumForFullName("maps/map01.wad", Wads.GetIwadNum()); - int lump_map = Wads.CheckNumForFullName("maps/map01.map", Wads.GetIwadNum()); + int lump_name = fileSystem.CheckNumForName("MAP01", ns_global, fileSystem.GetIwadNum()); + int lump_wad = fileSystem.CheckNumForFullName("maps/map01.wad", fileSystem.GetIwadNum()); + int lump_map = fileSystem.CheckNumForFullName("maps/map01.map", fileSystem.GetIwadNum()); if (lump_name >= 0 || lump_wad >= 0 || lump_map >= 0) gameinfo.flags |= GI_MAPxx; } @@ -2089,23 +1997,6 @@ static void SetMapxxFlag() static void D_DoomInit() { - // Set the FPU precision to 53 significant bits. This is the default - // for Visual C++, but not for GCC, so some slight math variances - // might crop up if we leave it alone. -#if defined(_FPU_GETCW) && defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE) - { - int cw; - _FPU_GETCW(cw); - cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE; - _FPU_SETCW(cw); - } -#elif defined(_PC_53) -// On the x64 architecture, changing the floating point precision is not supported. -#ifndef _WIN64 - int cfp = _control87(_PC_53, _MCW_PC); -#endif -#endif - // Check response files before coalescing file parameters. M_FindResponseFile (); @@ -2118,22 +2009,6 @@ static void D_DoomInit() gamestate = GS_STARTUP; - const char *v = Args->CheckValue("-rngseed"); - if (v) - { - rngseed = staticrngseed = atoi(v); - use_staticrng = true; - if (!batchrun) Printf("D_DoomInit: Static RNGseed %d set.\n", rngseed); - } - else - { - rngseed = I_MakeRNGSeed(); - use_staticrng = false; - } - srand(rngseed); - - FRandom::StaticClearRandom (); - if (!batchrun) Printf ("M_LoadDefaults: Load system defaults.\n"); M_LoadDefaults (); // load before initing other systems } @@ -2144,24 +2019,30 @@ static void D_DoomInit() // //========================================================================== -static void AddAutoloadFiles(const char *autoname) +static void AddAutoloadFiles(const char *autoname, std::vector& allwads) { LumpFilterIWAD.Format("%s.", autoname); // The '.' is appened to simplify parsing the string // [SP] Dialog reaction - load lights.pk3 and brightmaps.pk3 based on user choices - if (!(gameinfo.flags & GI_SHAREWARE)) + if (!(gameinfo.flags & GI_SHAREWARE) && !(Args->CheckParm("-noextras"))) { - if (DoomStartupInfo.LoadLights == 1 || (DoomStartupInfo.LoadLights != 0 && autoloadlights)) + if ((GameStartupInfo.LoadLights == 1 || (GameStartupInfo.LoadLights != 0 && autoloadlights)) && !(Args->CheckParm("-nolights"))) { - const char *lightswad = BaseFileSearch ("lights.pk3", NULL); + const char *lightswad = BaseFileSearch ("lights.pk3", NULL, true, GameConfig); if (lightswad) - D_AddFile (allwads, lightswad); + D_AddFile (allwads, lightswad, true, -1, GameConfig); } - if (DoomStartupInfo.LoadBrightmaps == 1 || (DoomStartupInfo.LoadBrightmaps != 0 && autoloadbrightmaps)) + if ((GameStartupInfo.LoadBrightmaps == 1 || (GameStartupInfo.LoadBrightmaps != 0 && autoloadbrightmaps)) && !(Args->CheckParm("-nobrightmaps"))) { - const char *bmwad = BaseFileSearch ("brightmaps.pk3", NULL); + const char *bmwad = BaseFileSearch ("brightmaps.pk3", NULL, true, GameConfig); if (bmwad) - D_AddFile (allwads, bmwad); + D_AddFile (allwads, bmwad, true, -1, GameConfig); + } + if ((GameStartupInfo.LoadWidescreen == 1 || (GameStartupInfo.LoadWidescreen != 0 && autoloadwidescreen)) && !(Args->CheckParm("-nowidescreen"))) + { + const char *wswad = BaseFileSearch ("game_widescreen_gfx.pk3", NULL, true, GameConfig); + if (wswad) + D_AddFile (allwads, wswad, true, -1, GameConfig); } } @@ -2174,9 +2055,9 @@ static void AddAutoloadFiles(const char *autoname) // voices. I never got around to writing the utility to do it, though. // And I probably never will now. But I know at least one person uses // it for something else, so this gets to stay here. - const char *wad = BaseFileSearch ("zvox.wad", NULL); + const char *wad = BaseFileSearch ("zvox.wad", NULL, false, GameConfig); if (wad) - D_AddFile (allwads, wad); + D_AddFile (allwads, wad, true, -1, GameConfig); // [RH] Add any .wad files in the skins directory #ifdef __unix__ @@ -2185,23 +2066,23 @@ static void AddAutoloadFiles(const char *autoname) file = progdir; #endif file += "skins"; - D_AddDirectory (allwads, file); + D_AddDirectory (allwads, file.GetChars(), "*.wad", GameConfig); #ifdef __unix__ file = NicePath("$HOME/" GAME_DIR "/skins"); - D_AddDirectory (allwads, file); + D_AddDirectory (allwads, file.GetChars(), "*.wad", GameConfig); #endif // Add common (global) wads - D_AddConfigWads (allwads, "Global.Autoload"); + D_AddConfigFiles(allwads, "Global.Autoload", "*.wad", GameConfig); - long len; - int lastpos = -1; + ptrdiff_t len; + ptrdiff_t lastpos = -1; while ((len = LumpFilterIWAD.IndexOf('.', lastpos+1)) > 0) { file = LumpFilterIWAD.Left(len) + ".Autoload"; - D_AddConfigWads(allwads, file); + D_AddConfigFiles(allwads, file.GetChars(), "*.wad", GameConfig); lastpos = len; } } @@ -2288,7 +2169,7 @@ static void CheckCmdLine() FString mapvalue = Args->TakeValue("+map"); if (mapvalue.IsNotEmpty()) { - if (!P_CheckMapData(mapvalue)) + if (!P_CheckMapData(mapvalue.GetChars())) { Printf ("Can't find map %s\n", mapvalue.GetChars()); } @@ -2301,7 +2182,7 @@ static void CheckCmdLine() if (devparm) { - Printf ("%s", GStrings("D_DEVSTR")); + Printf ("%s", GStrings.GetString("D_DEVSTR")); } // turbo option // [RH] (now a cvar) @@ -2328,6 +2209,7 @@ static void CheckCmdLine() timelimit = 20.f; } + if (!StartScreen) return; // // Build status bar line! // @@ -2339,560 +2221,1572 @@ static void CheckCmdLine() StartScreen->AppendStatusLine("Respawning..."); if (autostart) { - FString temp; - temp.Format ("Warp to map %s, Skill %d ", startmap.GetChars(), gameskill + 1); - StartScreen->AppendStatusLine(temp); + FStringf temp("Warp to map %s, Skill %d ", startmap.GetChars(), gameskill + 1); + StartScreen->AppendStatusLine(temp.GetChars()); } } +static void NewFailure () +{ + I_FatalError ("Failed to allocate memory from system heap"); +} + + //========================================================================== // -// I_Error +// RenameSprites // -// Throw an error that will send us to the console if we are far enough -// along in the startup process. +// Renames sprites in IWADs so that unique actors can have unique sprites, +// making it possible to import any actor from any game into any other +// game without jumping through hoops to resolve duplicate sprite names. +// You just need to know what the sprite's new name is. // //========================================================================== -void I_Error(const char *error, ...) +static void RenameSprites(FileSystem &fileSystem, const TArray& deletelumps) { - va_list argptr; - char errortext[MAX_ERRORTEXT]; + bool renameAll; + bool MNTRZfound = false; + const char* altbigfont = gameinfo.gametype == GAME_Strife ? "SBIGFONT" : (gameinfo.gametype & GAME_Raven) ? "HBIGFONT" : "DBIGFONT"; - va_start(argptr, error); - myvsnprintf(errortext, MAX_ERRORTEXT, error, argptr); - va_end(argptr); - I_DebugPrint(errortext); + static const uint32_t HereticRenames[] = + { MAKE_ID('H','E','A','D'), MAKE_ID('L','I','C','H'), // Ironlich + }; - throw CRecoverableError(errortext); -} + static const uint32_t HexenRenames[] = + { MAKE_ID('B','A','R','L'), MAKE_ID('Z','B','A','R'), // ZBarrel + MAKE_ID('A','R','M','1'), MAKE_ID('A','R','_','1'), // MeshArmor + MAKE_ID('A','R','M','2'), MAKE_ID('A','R','_','2'), // FalconShield + MAKE_ID('A','R','M','3'), MAKE_ID('A','R','_','3'), // PlatinumHelm + MAKE_ID('A','R','M','4'), MAKE_ID('A','R','_','4'), // AmuletOfWarding + MAKE_ID('S','U','I','T'), MAKE_ID('Z','S','U','I'), // ZSuitOfArmor and ZArmorChunk + MAKE_ID('T','R','E','1'), MAKE_ID('Z','T','R','E'), // ZTree and ZTreeDead + MAKE_ID('T','R','E','2'), MAKE_ID('T','R','E','S'), // ZTreeSwamp150 + MAKE_ID('C','A','N','D'), MAKE_ID('B','C','A','N'), // ZBlueCandle + MAKE_ID('R','O','C','K'), MAKE_ID('R','O','K','K'), // rocks and dirt in a_debris.cpp + MAKE_ID('W','A','T','R'), MAKE_ID('H','W','A','T'), // Strife also has WATR + MAKE_ID('G','I','B','S'), MAKE_ID('P','O','L','5'), // RealGibs + MAKE_ID('E','G','G','M'), MAKE_ID('P','R','K','M'), // PorkFX + MAKE_ID('I','N','V','U'), MAKE_ID('D','E','F','N'), // Icon of the Defender + }; -//========================================================================== -// -// I_FatalError -// -// Throw an error that will end the game. -// -//========================================================================== -extern FILE *Logfile; + static const uint32_t StrifeRenames[] = + { MAKE_ID('M','I','S','L'), MAKE_ID('S','M','I','S'), // lots of places + MAKE_ID('A','R','M','1'), MAKE_ID('A','R','M','3'), // MetalArmor + MAKE_ID('A','R','M','2'), MAKE_ID('A','R','M','4'), // LeatherArmor + MAKE_ID('P','M','A','P'), MAKE_ID('S','M','A','P'), // StrifeMap + MAKE_ID('T','L','M','P'), MAKE_ID('T','E','C','H'), // TechLampSilver and TechLampBrass + MAKE_ID('T','R','E','1'), MAKE_ID('T','R','E','T'), // TreeStub + MAKE_ID('B','A','R','1'), MAKE_ID('B','A','R','C'), // BarricadeColumn + MAKE_ID('S','H','T','2'), MAKE_ID('M','P','U','F'), // MaulerPuff + MAKE_ID('B','A','R','L'), MAKE_ID('B','B','A','R'), // StrifeBurningBarrel + MAKE_ID('T','R','C','H'), MAKE_ID('T','R','H','L'), // SmallTorchLit + MAKE_ID('S','H','R','D'), MAKE_ID('S','H','A','R'), // glass shards + MAKE_ID('B','L','S','T'), MAKE_ID('M','A','U','L'), // Mauler + MAKE_ID('L','O','G','G'), MAKE_ID('L','O','G','W'), // StickInWater + MAKE_ID('V','A','S','E'), MAKE_ID('V','A','Z','E'), // Pot and Pitcher + MAKE_ID('C','N','D','L'), MAKE_ID('K','N','D','L'), // Candle + MAKE_ID('P','O','T','1'), MAKE_ID('M','P','O','T'), // MetalPot + MAKE_ID('S','P','I','D'), MAKE_ID('S','T','L','K'), // Stalker + }; -void I_FatalError(const char *error, ...) -{ - static bool alreadyThrown = false; - gameisdead = true; + const uint32_t* renames; + int numrenames; - if (!alreadyThrown) // ignore all but the first message -- killough + switch (gameinfo.gametype) { - alreadyThrown = true; - char errortext[MAX_ERRORTEXT]; - va_list argptr; - va_start(argptr, error); - myvsnprintf(errortext, MAX_ERRORTEXT, error, argptr); - va_end(argptr); - I_DebugPrint(errortext); + case GAME_Doom: + default: + // Doom's sprites don't get renamed. + renames = nullptr; + numrenames = 0; + break; - // Record error to log (if logging) - if (Logfile) - { - fprintf(Logfile, "\n**** DIED WITH FATAL ERROR:\n%s\n", errortext); - fflush(Logfile); - } + case GAME_Heretic: + renames = HereticRenames; + numrenames = sizeof(HereticRenames) / 8; + break; + + case GAME_Hexen: + renames = HexenRenames; + numrenames = sizeof(HexenRenames) / 8; + break; - throw CFatalError(errortext); + case GAME_Strife: + renames = StrifeRenames; + numrenames = sizeof(StrifeRenames) / 8; + break; } - std::terminate(); // recursive I_FatalErrors must immediately terminate. -} -static void NewFailure () -{ - I_FatalError ("Failed to allocate memory from system heap"); -} + unsigned NumFiles = fileSystem.GetNumEntries(); -//========================================================================== -// -// D_DoomMain -// -//========================================================================== + for (uint32_t i = 0; i < NumFiles; i++) + { + // check for full Minotaur animations. If this is not found + // some frames need to be renamed. + if (fileSystem.GetFileNamespace(i) == ns_sprites) + { + auto& shortName = fileSystem.GetShortName(i); + if (shortName.dword == MAKE_ID('M', 'N', 'T', 'R') && shortName.String[4] == 'Z') + { + MNTRZfound = true; + break; + } + } + } -static int D_DoomMain_Internal (void) -{ - int p; - const char *v; - const char *wad; - TArray pwads; - FString *args; - int argcount; - FIWadManager *iwad_man; - - std::set_new_handler(NewFailure); - const char *batchout = Args->CheckValue("-errorlog"); - - C_InitConsole(80*8, 25*8, false); - I_DetectOS(); + renameAll = !!Args->CheckParm("-oldsprites") || nospriterename; - // +logfile gets checked too late to catch the full startup log in the logfile so do some extra check for it here. - FString logfile = Args->TakeValue("+logfile"); - if (logfile.IsNotEmpty()) + for (uint32_t i = 0; i < NumFiles; i++) { - execLogfile(logfile); + auto& shortName = fileSystem.GetShortName(i); + if (fileSystem.GetFileNamespace(i) == ns_sprites) + { + // Only sprites in the IWAD normally get renamed + if (renameAll || fileSystem.GetFileContainer(i) == fileSystem.GetIwadNum()) + { + for (int j = 0; j < numrenames; ++j) + { + if (shortName.dword == renames[j * 2]) + { + shortName.dword = renames[j * 2 + 1]; + } + } + if (gameinfo.gametype == GAME_Hexen) + { + if (fileSystem.CheckFileName(i, "ARTIINVU")) + { + shortName.String[4] = 'D'; shortName.String[5] = 'E'; + shortName.String[6] = 'F'; shortName.String[7] = 'N'; + } + } + } + + if (!MNTRZfound) + { + if (shortName.dword == MAKE_ID('M', 'N', 'T', 'R')) + { + for (size_t fi : {4, 6}) + { + if (shortName.String[fi] >= 'F' && shortName.String[fi] <= 'K') + { + shortName.String[fi] += 'U' - 'F'; + } + } + } + } + + // When not playing Doom rename all BLOD sprites to BLUD so that + // the same blood states can be used everywhere + if (!(gameinfo.gametype & GAME_DoomChex)) + { + if (shortName.dword == MAKE_ID('B', 'L', 'O', 'D')) + { + shortName.dword = MAKE_ID('B', 'L', 'U', 'D'); + } + } + } + else if (fileSystem.GetFileNamespace(i) == ns_global) + { + int fn = fileSystem.GetFileContainer(i); + if (fn >= fileSystem.GetIwadNum() && fn <= fileSystem.GetMaxIwadNum() && deletelumps.Find(shortName.String) < deletelumps.Size()) + { + shortName.String[0] = 0; // Lump must be deleted from directory. + } + // Rename the game specific big font lumps so that the font manager does not have to do problematic special checks for them. + else if (!strcmp(shortName.String, altbigfont)) + { + strcpy(shortName.String, "BIGFONT"); + } + } } - else if (batchout != NULL && *batchout != 0) +} + +//========================================================================== +// +// RenameNerve +// +// Renames map headers and map name pictures in nerve.wad so as to load it +// alongside Doom II and offer both episodes without causing conflicts. +// MD5 checksum for NERVE.WAD: 967d5ae23daf45196212ae1b605da3b0 (3,819,855) +// MD5 checksum for Unity version of NERVE.WAD: 4214c47651b63ee2257b1c2490a518c9 (3,821,966) +// +//========================================================================== +void RenameNerve(FileSystem& fileSystem) +{ + if (gameinfo.gametype != GAME_Doom) + return; + + const int numnerveversions = 4; + + bool found = false; + uint8_t cksum[16]; + static const uint8_t nerve[numnerveversions][16] = { + { 0x96, 0x7d, 0x5a, 0xe2, 0x3d, 0xaf, 0x45, 0x19, + 0x62, 0x12, 0xae, 0x1b, 0x60, 0x5d, 0xa3, 0xb0 }, + { 0x42, 0x14, 0xc4, 0x76, 0x51, 0xb6, 0x3e, 0xe2, + 0x25, 0x7b, 0x1c, 0x24, 0x90, 0xa5, 0x18, 0xc9 }, + { 0x35, 0x44, 0xe1, 0x90, 0x30, 0x91, 0xc5, 0x0b, + 0xa5, 0x00, 0x49, 0xdb, 0x74, 0xcd, 0x7d, 0x25 }, + { 0x91, 0x43, 0xb3, 0x92, 0x39, 0x2a, 0x7a, 0xc8, + 0x70, 0xc2, 0xca, 0x36, 0xac, 0x65, 0xaf, 0x45 } + }; + size_t nervesize[numnerveversions] = { 3819855, 3821966, 3821885, 4003409 }; // NERVE.WAD's file size + int w = fileSystem.GetIwadNum(); + while (++w < fileSystem.GetNumWads()) { - batchrun = true; - execLogfile(batchout, true); - Printf("Command line: "); - for (int i = 0; i < Args->NumArgs(); i++) + auto fr = fileSystem.GetFileReader(w); + int isizecheck = -1; + if (fr == NULL) { - Printf("%s ", Args->GetArg(i)); + continue; + } + for (int icheck = 0; icheck < numnerveversions; icheck++) + if (fr->GetLength() == (ptrdiff_t)nervesize[icheck]) + isizecheck = icheck; + if (isizecheck == -1) + { + // Skip MD5 computation when there is a + // cheaper way to know this is not the file + continue; + } + fr->Seek(0, FileReader::SeekSet); + MD5Context md5; + md5Update(*fr, md5, (unsigned)fr->GetLength()); + md5.Final(cksum); + if (memcmp(nerve[isizecheck], cksum, 16) == 0) + { + found = true; + break; } - Printf("\n"); } - if (Args->CheckParm("-hashfiles")) + if (!found) + return; + + for (int i = fileSystem.GetFirstEntry(w); i <= fileSystem.GetLastEntry(w); i++) { - const char *filename = "fileinfo.txt"; - Printf("Hashing loaded content to: %s\n", filename); - hashfile = fopen(filename, "w"); - if (hashfile) + auto& shortName = fileSystem.GetShortName(i); + // Only rename the maps from NERVE.WAD + if (shortName.dword == MAKE_ID('C', 'W', 'I', 'L')) { - fprintf(hashfile, "%s version %s (%s)\n", GAMENAME, GetVersionString(), GetGitHash()); -#ifdef __VERSION__ - fprintf(hashfile, "Compiler version: %s\n", __VERSION__); -#endif - fprintf(hashfile, "Command line:"); - for (int i = 0; i < Args->NumArgs(); ++i) - { - fprintf(hashfile, " %s", Args->GetArg(i)); - } - fprintf(hashfile, "\n"); + shortName.String[0] = 'N'; + } + else if (shortName.dword == MAKE_ID('M', 'A', 'P', '0')) + { + shortName.String[6] = shortName.String[4]; + shortName.String[5] = '0'; + shortName.String[4] = 'L'; + shortName.dword = MAKE_ID('L', 'E', 'V', 'E'); } } +} - if (!batchrun) Printf(PRINT_LOG, "%s version %s\n", GAMENAME, GetVersionString()); +//========================================================================== +// +// FixMacHexen +// +// Discard all extra lumps in Mac version of Hexen IWAD (demo or full) +// to avoid any issues caused by names of these lumps, including: +// * Wrong height of small font +// * Broken life bar of mage class +// +//========================================================================== - D_DoomInit(); +void FixMacHexen(FileSystem& fileSystem) +{ + if (GAME_Hexen != gameinfo.gametype) + { + return; + } - extern void D_ConfirmSendStats(); - D_ConfirmSendStats(); + FileReader* reader = fileSystem.GetFileReader(fileSystem.GetIwadNum()); + auto iwadSize = reader->GetLength(); - // [RH] Make sure zdoom.pk3 is always loaded, - // as it contains magic stuff we need. - wad = BaseFileSearch (BASEWAD, NULL, true); - if (wad == NULL) + static const ptrdiff_t DEMO_SIZE = 13596228; + static const ptrdiff_t BETA_SIZE = 13749984; + static const ptrdiff_t FULL_SIZE = 21078584; + + if (DEMO_SIZE != iwadSize + && BETA_SIZE != iwadSize + && FULL_SIZE != iwadSize) { - I_FatalError ("Cannot find " BASEWAD); + return; } - FString basewad = wad; - FString optionalwad = BaseFileSearch(OPTIONALWAD, NULL, true); + reader->Seek(0, FileReader::SeekSet); - iwad_man = new FIWadManager(basewad, optionalwad); + uint8_t checksum[16]; + MD5Context md5; - // Now that we have the IWADINFO, initialize the autoload ini sections. - GameConfig->DoAutoloadSetup(iwad_man); + md5Update(*reader, md5, (unsigned)iwadSize); + md5.Final(checksum); - // reinit from here + static const uint8_t HEXEN_DEMO_MD5[16] = + { + 0x92, 0x5f, 0x9f, 0x50, 0x00, 0xe1, 0x7d, 0xc8, + 0x4b, 0x0a, 0x6a, 0x3b, 0xed, 0x3a, 0x6f, 0x31 + }; - do + static const uint8_t HEXEN_BETA_MD5[16] = { - PClass::StaticInit(); - PType::StaticInit(); + 0x2a, 0xf1, 0xb2, 0x7c, 0xd1, 0x1f, 0xb1, 0x59, + 0xe6, 0x08, 0x47, 0x2a, 0x1b, 0x53, 0xe4, 0x0e + }; - if (restart) + static const uint8_t HEXEN_FULL_MD5[16] = + { + 0xb6, 0x81, 0x40, 0xa7, 0x96, 0xf6, 0xfd, 0x7f, + 0x3a, 0x5d, 0x32, 0x26, 0xa3, 0x2b, 0x93, 0xbe + }; + + const bool isBeta = 0 == memcmp(HEXEN_BETA_MD5, checksum, sizeof checksum); + + if (!isBeta + && 0 != memcmp(HEXEN_DEMO_MD5, checksum, sizeof checksum) + && 0 != memcmp(HEXEN_FULL_MD5, checksum, sizeof checksum)) + { + return; + } + + static const int EXTRA_LUMPS = 299; + + // Hexen Beta is very similar to Demo but it has MAP41: Maze at the end of the WAD + // So keep this map if it's present but discard all extra lumps + + const int lastLump = fileSystem.GetLastEntry(fileSystem.GetIwadNum()) - (isBeta ? 12 : 0); + assert(fileSystem.GetFirstEntry(fileSystem.GetIwadNum()) + 299 < lastLump); + + for (int i = lastLump - EXTRA_LUMPS + 1; i <= lastLump; ++i) + { + auto& shortName = fileSystem.GetShortName(i); + shortName.String[0] = '\0'; + } +} + +static void FindStrifeTeaserVoices(FileSystem& fileSystem) +{ + if (gameinfo.gametype == GAME_Strife && gameinfo.flags & GI_SHAREWARE) + { + unsigned NumFiles = fileSystem.GetNumEntries(); + for (uint32_t i = 0; i < NumFiles; i++) { - C_InitConsole(SCREENWIDTH, SCREENHEIGHT, false); + auto& shortName = fileSystem.GetShortName(i); + if (fileSystem.GetFileNamespace(i) == ns_global) + { + // Only sprites in the IWAD normally get renamed + if (fileSystem.GetFileContainer(i) == fileSystem.GetIwadNum()) + { + if (shortName.String[0] == 'V' && + shortName.String[1] == 'O' && + shortName.String[2] == 'C') + { + int j; + + for (j = 3; j < 8; ++j) + { + if (shortName.String[j] != 0 && !isdigit(shortName.String[j])) + break; + } + if (j == 8) + { + fileSystem.SetFileNamespace(i, ns_strifevoices); + } + } + } + } } - nospriterename = false; + } +} - // Load zdoom.pk3 alone so that we can get access to the internal gameinfos before - // the IWAD is known. - GetCmdLineFiles(pwads); - FString iwad = CheckGameInfo(pwads); +static const char *DoomButtons[] = +{ + "am_panleft", + "user2" , + "jump" , + "right" , + "zoom" , + "back" , + "am_zoomin", + "reload" , + "lookdown" , + "am_zoomout", + "user4" , + "attack" , + "user1" , + "klook" , + "forward" , + "movedown" , + "altattack" , + "moveleft" , + "moveright" , + "am_panright", + "am_panup" , + "mlook" , + "crouch" , + "left" , + "lookup" , + "user3" , + "strafe" , + "am_pandown", + "showscores" , + "speed" , + "use" , + "moveup" }; + +CVAR(Bool, lookspring, true, CVAR_ARCHIVE); // Generate centerview when -mlook encountered? +EXTERN_CVAR(String, language) + +CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +{ + if (self < 0) + { + self = 0; + } + else if (self > 2) + { + self = 2; + } +} - // The IWAD selection dialogue does not show in fullscreen so if the - // restart is initiated without a defined IWAD assume for now that it's not going to change. - if (iwad.IsEmpty()) iwad = lastIWAD; - if (iwad_man == NULL) +void Mlook_ReleaseHandler() +{ + if (lookspring) + { + Net_WriteInt8(DEM_CENTERVIEW); + } +} + +bool StrTable_ValidFilter(const char* str) +{ + if (gameinfo.gametype == GAME_Strife && (gameinfo.flags & GI_SHAREWARE) && !stricmp(str, "strifeteaser")) return true; + return gameinfo.gametype == 0 || stricmp(str, GameNames[gameinfo.gametype]) == 0; +} + +bool System_WantGuiCapture() +{ + bool wantCapt; + + if (menuactive == MENU_Off) + { + wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon; + } + else + { + wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause); + } + + // [ZZ] check active event handlers that want the UI processing + if (!wantCapt && primaryLevel->localEventManager->CheckUiProcessors()) + wantCapt = true; + + return wantCapt; +} + +bool System_WantLeftButton() +{ + return (gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL); +} + +static bool System_DispatchEvent(event_t* ev) +{ + shiftState.AddEvent(ev); + + if (ev->type == EV_Mouse && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !primaryLevel->localEventManager->Responder(ev) && !paused) + { + if (buttonMap.ButtonDown(Button_Mlook) || freelook) { - iwad_man = new FIWadManager(basewad, optionalwad); + int look = int(ev->y * m_pitch * 16.0); + G_AddViewPitch(look, true); + ev->y = 0; } - const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad, optionalwad); - if (!iwad_info) return 0; // user exited the selection popup via cancel button. - gameinfo.gametype = iwad_info->gametype; - gameinfo.flags = iwad_info->flags; - gameinfo.nokeyboardcheats = iwad_info->nokeyboardcheats; - gameinfo.ConfigName = iwad_info->Configname; - lastIWAD = iwad; - - if ((gameinfo.flags & GI_SHAREWARE) && pwads.Size() > 0) + if (!buttonMap.ButtonDown(Button_Strafe) && !lookstrafe) { - I_FatalError ("You cannot -file with the shareware version. Register!"); + int turn = int(ev->x * m_yaw * 16.0); + G_AddViewAngle(turn, true); + ev->x = 0; + } + if (ev->x == 0 && ev->y == 0) + { + return true; } + } + return false; +} - FBaseCVar::DisableCallbacks(); - GameConfig->DoGameSetup (gameinfo.ConfigName); +bool System_NetGame() +{ + return netgame; +} + +bool System_WantNativeMouse() +{ + return primaryLevel->localEventManager->CheckRequireMouse(); +} - AddAutoloadFiles(iwad_info->Autoname); +static bool System_CaptureModeInGame() +{ + if (demoplayback || paused) return false; + switch (mouse_capturemode) + { + default: + case 0: + return gamestate == GS_LEVEL; + case 1: + return gamestate == GS_LEVEL || gamestate == GS_CUTSCENE; + case 2: + return true; + } +} - // Process automatically executed files - FExecList *exec; - FArgs *execFiles = new FArgs; - GameConfig->AddAutoexec(execFiles, gameinfo.ConfigName); - exec = D_MultiExec(execFiles, NULL); - delete execFiles; +static void System_PlayStartupSound(const char* sndname) +{ + S_Sound(CHAN_BODY, 0, sndname, 1, ATTN_NONE); +} - // Process .cfg files at the start of the command line. - execFiles = Args->GatherFiles ("-exec"); - exec = D_MultiExec(execFiles, exec); - delete execFiles; +static bool System_IsSpecialUI() +{ + return (generic_ui || !!log_vgafont || !!dlg_vgafont || ConsoleState != c_up || multiplayer || + (menuactive == MENU_On && CurrentMenu && !CurrentMenu->IsKindOf("ConversationMenu"))); - // [RH] process all + commands on the command line - exec = C_ParseCmdLineParams(exec); +} - CopyFiles(allwads, pwads); - if (exec != NULL) - { - exec->AddPullins(allwads); - } +static bool System_DisableTextureFilter() +{ + return !V_IsHardwareRenderer(); +} - // Since this function will never leave we must delete this array here manually. - pwads.Clear(); - pwads.ShrinkToFit(); +static void System_OnScreenSizeChanged() +{ + if (StatusBar != NULL) + { + StatusBar->CallScreenSizeChanged(); + } + // Reload crosshair if transitioned to a different size + ST_LoadCrosshair(true); + if (primaryLevel && primaryLevel->automap) + primaryLevel->automap->NewResolution(); +} - if (hashfile) - { - Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer than usual.\n"); - } +IntRect System_GetSceneRect() +{ + IntRect mSceneViewport; + // Special handling so the view with a visible status bar displays properly + int height, width; + if (screenblocks >= 10) + { + height = screen->GetHeight(); + width = screen->GetWidth(); + } + else + { + height = (screenblocks * screen->GetHeight() / 10) & ~7; + width = (screenblocks * screen->GetWidth() / 10); + } - if (!batchrun) Printf ("W_Init: Init WADfiles.\n"); - Wads.InitMultipleFiles (allwads, iwad_info->DeleteLumps); - allwads.Clear(); - allwads.ShrinkToFit(); - SetMapxxFlag(); + mSceneViewport.left = viewwindowx; + mSceneViewport.top = screen->GetHeight() - (height + viewwindowy - ((height - viewheight) / 2)); + mSceneViewport.width = viewwidth; + mSceneViewport.height = height; + return mSceneViewport; +} - C_GrabCVarDefaults(); //parse DEFCVARS +FString System_GetLocationDescription() +{ + auto& vp = r_viewpoint; + auto Level = vp.ViewLevel; + return Level == nullptr ? FString() : FStringf("Map %s: \"%s\",\nx = %1.4f, y = %1.4f, z = %1.4f, angle = %1.4f, pitch = %1.4f\n%llu fps\n\n", + Level->MapName.GetChars(), Level->LevelName.GetChars(), vp.Pos.X, vp.Pos.Y, vp.Pos.Z, vp.Angles.Yaw.Degrees(), vp.Angles.Pitch.Degrees(), (unsigned long long)LastFPS); - GameConfig->DoKeySetup(gameinfo.ConfigName); +} - // Now that wads are loaded, define mod-specific cvars. - ParseCVarInfo(); +FString System_GetPlayerName(int node) +{ + return players[node].userinfo.GetName(); +} - // Actually exec command line commands and exec files. - if (exec != NULL) - { - exec->ExecCommands(); - delete exec; - exec = NULL; - } +void System_ConsoleToggled(int state) +{ + if (state == c_falling && hud_toggled) + D_ToggleHud(); +} + +void System_LanguageChanged(const char* lang) +{ + for (auto Level : AllLevels()) + { + // does this even make sense on secondary levels...? + if (Level->info != nullptr) Level->LevelName = Level->info->LookupLevelName(); + } + I_UpdateWindowTitle(); +} - // [RH] Initialize localizable strings. - GStrings.LoadStrings (); +//========================================================================== +// +// DoomSpecificInfo +// +// Called by the crash logger to get application-specific information. +// +//========================================================================== - V_InitFontColors (); +void System_CrashInfo(char* buffer, size_t bufflen, const char *lfstr) +{ + const char* arg; + char* const buffend = buffer + bufflen - 2; // -2 for CRLF at end + int i; - // [RH] Moved these up here so that we can do most of our - // startup output in a fullscreen console. + buffer += mysnprintf(buffer, buffend - buffer, GAMENAME " version %s (%s)", GetVersionString(), GetGitHash()); - CT_Init (); + buffer += snprintf(buffer, buffend - buffer, "%sCommand line:", lfstr); + for (i = 0; i < Args->NumArgs(); ++i) + { + buffer += snprintf(buffer, buffend - buffer, " %s", Args->GetArg(i)); + } - if (!restart) - { - if (!batchrun) Printf ("I_Init: Setting up machine state.\n"); - I_Init (); - } + for (i = 0; (arg = fileSystem.GetResourceFileName(i)) != NULL; ++i) + { + buffer += mysnprintf(buffer, buffend - buffer, "%sWad %d: %s", lfstr, i, arg); + } - // [RH] Initialize palette management - InitPalette (); - - if (!batchrun) Printf ("V_Init: allocate screen.\n"); - if (!restart) + if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) + { + buffer += mysnprintf(buffer, buffend - buffer, "%s%sNot in a level.", lfstr, lfstr); + } + else + { + buffer += mysnprintf(buffer, buffend - buffer, "%s%sCurrent map: %s", lfstr, lfstr, primaryLevel->MapName.GetChars()); + + if (!viewactive) { - V_InitScreenSize(); + buffer += mysnprintf(buffer, buffend - buffer, "%s%sView not active.", lfstr, lfstr); } - - if (!restart) + else { - // This allocates a dummy framebuffer as a stand-in until V_Init2 is called. - V_InitScreen (); + auto& vp = r_viewpoint; + buffer += mysnprintf(buffer, buffend - buffer, "%s%sviewx = %f", lfstr, lfstr, vp.Pos.X); + buffer += mysnprintf(buffer, buffend - buffer, "%sviewy = %f", lfstr, vp.Pos.Y); + buffer += mysnprintf(buffer, buffend - buffer, "%sviewz = %f", lfstr, vp.Pos.Z); + buffer += mysnprintf(buffer, buffend - buffer, "%sviewangle = %f", lfstr, vp.Angles.Yaw.Degrees()); } - - if (restart) + } + buffer += mysnprintf(buffer, buffend - buffer, "%s", lfstr); + *buffer = 0; +} + +void System_M_Dim(); + + +static void PatchTextures() +{ + // The Hexen scripts use BLANK as a blank texture, even though it's really not. + // I guess the Doom renderer must have clipped away the line at the bottom of + // the texture so it wasn't visible. Change its use type to a blank null texture to really make it blank. + if (gameinfo.gametype == GAME_Hexen) + { + FTextureID tex = TexMan.CheckForTexture("BLANK", ETextureType::Wall, false); + if (tex.Exists()) { - // Update screen palette when restarting - screen->UpdatePalette(); + auto texture = TexMan.GetGameTexture(tex, false); + texture->SetUseType(ETextureType::Null); } + } +} + +//========================================================================== +// +// this gets called during texture creation to fix known problems +// +//========================================================================== - // Base systems have been inited; enable cvar callbacks - FBaseCVar::EnableCallbacks (); +static void CheckForHacks(BuildInfo& buildinfo) +{ + if (buildinfo.Parts.Size() == 0) + { + return; + } - if (!batchrun) Printf ("S_Init: Setting up sound.\n"); - S_Init (); + // Heretic sky textures are marked as only 128 pixels tall, + // even though they are really 200 pixels tall. + if (gameinfo.gametype == GAME_Heretic && + buildinfo.Name.Len() == 4 && + buildinfo.Name[0] == 'S' && + buildinfo.Name[1] == 'K' && + buildinfo.Name[2] == 'Y' && + buildinfo.Name[3] >= '1' && + buildinfo.Name[3] <= '3' && + buildinfo.Height == 128 && + buildinfo.Parts.Size() == 1) + { + // This must alter the size of both the texture image and the game texture. + buildinfo.Height = buildinfo.Parts[0].TexImage->GetImage()->GetHeight(); + buildinfo.texture->SetSize(buildinfo.Width, buildinfo.Height); + return; + } + + // The Doom E1 sky has its patch's y offset at -8 instead of 0. + if (gameinfo.gametype == GAME_Doom && + !(gameinfo.flags & GI_MAPxx) && + buildinfo.Name.Len() == 4 && + buildinfo.Parts.Size() == 1 && + buildinfo.Height == 128 && + buildinfo.Parts[0].OriginY == -8 && + buildinfo.Name[0] == 'S' && + buildinfo.Name[1] == 'K' && + buildinfo.Name[2] == 'Y' && + buildinfo.Name[3] == '1') + { + buildinfo.Parts[0].OriginY = 0; + return; + } + + // BIGDOOR7 in Doom also has patches at y offset -4 instead of 0. + if (gameinfo.gametype == GAME_Doom && + !(gameinfo.flags & GI_MAPxx) && + buildinfo.Name.CompareNoCase("BIGDOOR7") == 0 && + buildinfo.Parts.Size() == 2 && + buildinfo.Height == 128 && + buildinfo.Parts[0].OriginY == -4 && + buildinfo.Parts[1].OriginY == -4) + { + buildinfo.Parts[0].OriginY = 0; + buildinfo.Parts[1].OriginY = 0; + return; + } +} + +static void FixWideStatusBar() +{ + FGameTexture* sbartex = TexMan.FindGameTexture("stbar", ETextureType::MiscPatch); + + // only adjust offsets if none already exist and if the texture is not scaled. For scaled textures a proper offset is needed. + if (sbartex && sbartex->GetTexelWidth() > 320 && sbartex->GetScaleX() == 1 && + !sbartex->GetTexelLeftOffset(0) && !sbartex->GetTexelTopOffset(0)) + { + sbartex->SetOffsets(0, (sbartex->GetTexelWidth() - 320) / 2, 0); + sbartex->SetOffsets(1, (sbartex->GetTexelWidth() - 320) / 2, 0); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +static void Doom_CastSpriteIDToString(FString* a, unsigned int b) +{ + *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; +} + + +extern DThinker* NextToThink; + +static void GC_MarkGameRoots() +{ + GC::Mark(staticEventManager.FirstEventHandler); + GC::Mark(staticEventManager.LastEventHandler); + for (auto Level : AllLevels()) + Level->Mark(); + + // Mark players. + for (int i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + players[i].PropagateMark(); + } + + // NextToThink must not be freed while thinkers are ticking. + GC::Mark(NextToThink); +} + +static void System_ToggleFullConsole() +{ + gameaction = ga_fullconsole; +} + +static void System_StartCutscene(bool blockui) +{ + gameaction = blockui ? ga_intro : ga_intermission; +} + +static void System_SetTransition(int type) +{ + if (type != wipe_None) wipegamestate = type == wipe_Burn? GS_FORCEWIPEBURN : type == wipe_Fade? GS_FORCEWIPEFADE : GS_FORCEWIPEMELT; +} + +static void System_HudScaleChanged() +{ + if (StatusBar) + { + StatusBar->SetScale(); + setsizeneeded = true; + } +} + +bool CheckSkipGameOptionBlock(const char* str); + +//========================================================================== +// +// +// +//========================================================================== + +static FILE* D_GetHashFile() +{ + FILE *hashfile = nullptr; - if (!batchrun) Printf ("ST_Init: Init startup screen.\n"); - if (!restart) + if (Args->CheckParm("-hashfiles")) + { + const char *filename = "fileinfo.txt"; + Printf("Hashing loaded content to: %s\n", filename); + hashfile = fopen(filename, "w"); + if (hashfile) { - StartScreen = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5); + Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer than usual.\n"); + fprintf(hashfile, "%s version %s (%s)\n", GAMENAME, GetVersionString(), GetGitHash()); +#ifdef __VERSION__ + fprintf(hashfile, "Compiler version: %s\n", __VERSION__); +#endif + fprintf(hashfile, "Command line:"); + for (int i = 0; i < Args->NumArgs(); ++i) + { + fprintf(hashfile, " %s", Args->GetArg(i)); + } + fprintf(hashfile, "\n"); } - else + } + return hashfile; +} + +// checks if a file within a directory is allowed to be added to the file system. +static bool FileNameCheck(const char* base, const char* path) +{ + // This one is courtesy of EDuke32. :( + // Putting cache files in the application directory is very bad style. + // Unfortunately, having a garbage file named "textures" present will cause serious problems down the line. + if (!strnicmp(base, "textures", 8)) + { + // do not use fopen. The path may contain non-ASCII characters. + FileReader f; + if (f.OpenFile(path)) { - StartScreen = new FStartupScreen(0); + char check[3]{}; + f.Read(check, 3); + if (!memcmp(check, "LZ4", 3)) return false; } + } + return true; +} + +static int FileSystemPrintf(FSMessageLevel level, const char* fmt, ...) +{ + va_list arg; + va_start(arg, fmt); + FString text; + text.VFormat(fmt, arg); + switch (level) + { + case FSMessageLevel::Error: + return Printf(TEXTCOLOR_RED "%s", text.GetChars()); + break; + case FSMessageLevel::Warning: + Printf(TEXTCOLOR_YELLOW "%s", text.GetChars()); + break; + case FSMessageLevel::Attention: + Printf(TEXTCOLOR_BLUE "%s", text.GetChars()); + break; + case FSMessageLevel::Message: + Printf("%s", text.GetChars()); + break; + case FSMessageLevel::DebugWarn: + DPrintf(DMSG_WARNING, "%s", text.GetChars()); + break; + case FSMessageLevel::DebugNotify: + DPrintf(DMSG_NOTIFY, "%s", text.GetChars()); + break; + } + return (int)text.Len(); +} +//========================================================================== +// +// D_InitGame +// +//========================================================================== + +static int D_InitGame(const FIWADInfo* iwad_info, std::vector& allwads, std::vector& pwads) +{ + NetworkEntityManager::InitializeNetworkEntities(); + + if (!restart) + { + V_InitScreenSize(); + // This allocates a dummy framebuffer as a stand-in until V_Init2 is called. + V_InitScreen(); + } + SavegameFolder = iwad_info->Autoname; + gameinfo.gametype = iwad_info->gametype; + gameinfo.flags = iwad_info->flags; + gameinfo.nokeyboardcheats = iwad_info->nokeyboardcheats; + gameinfo.ConfigName = iwad_info->Configname; + + const char *v = Args->CheckValue("-rngseed"); + if (v) + { + rngseed = staticrngseed = atoi(v); + use_staticrng = true; + if (!batchrun) Printf("D_DoomInit: Static RNGseed %d set.\n", rngseed); + } + else + { + rngseed = I_MakeRNGSeed(); + use_staticrng = false; + } + srand(rngseed); + + FRandom::StaticClearRandom (); + + FBaseCVar::DisableCallbacks(); + GameConfig->DoGameSetup (gameinfo.ConfigName.GetChars()); + + AddAutoloadFiles(iwad_info->Autoname.GetChars(), allwads); + + // Process automatically executed files + FExecList *exec; + FArgs *execFiles = new FArgs; + if (!(Args->CheckParm("-noautoexec"))) + GameConfig->AddAutoexec(execFiles, gameinfo.ConfigName.GetChars()); + exec = D_MultiExec(execFiles, NULL); + delete execFiles; + + // Process .cfg files at the start of the command line. + execFiles = Args->GatherFiles ("-exec"); + exec = D_MultiExec(execFiles, exec); + delete execFiles; + + // [RH] process all + commands on the command line + exec = C_ParseCmdLineParams(exec); + + if (exec != NULL) + { + exec->AddPullins(allwads, GameConfig); + } + + if (!batchrun) Printf ("W_Init: Init WADfiles.\n"); + + LumpFilterInfo lfi; + + static const struct { int match; const char* name; } blanket[] = + { + { GAME_Raven, "game-Raven" }, + { GAME_DoomStrifeChex, "game-DoomStrifeChex" }, + { GAME_DoomChex, "game-DoomChex" }, + { GAME_Any, NULL } + }; + + for (auto& inf : blanket) + { + if (gameinfo.gametype & inf.match) lfi.gameTypeFilter.push_back(inf.name); + } + lfi.gameTypeFilter.push_back(FStringf("game-%s", GameTypeName()).GetChars()); + + lfi.gameTypeFilter.push_back(LumpFilterIWAD.GetChars()); + // Workaround for old Doom filter names. + if (LumpFilterIWAD.Compare("doom.id.doom") == 0) + { + lfi.gameTypeFilter.push_back("doom.doom"); + } + + + + GetReserved(lfi); + + lfi.postprocessFunc = [&]() + { + RenameNerve(fileSystem); + RenameSprites(fileSystem, iwad_info->DeleteLumps); + FixMacHexen(fileSystem); + FindStrifeTeaserVoices(fileSystem); + }; + allwads.insert( + allwads.end(), + std::make_move_iterator(pwads.begin()), + std::make_move_iterator(pwads.end()) + ); + + bool allowduplicates = Args->CheckParm("-allowduplicates"); + auto hashfile = D_GetHashFile(); + if (!fileSystem.InitMultipleFiles(allwads, &lfi, FileSystemPrintf, allowduplicates, hashfile)) + { + I_FatalError("FileSystem: no files found"); + } + allwads.clear(); + allwads.shrink_to_fit(); + SetMapxxFlag(); - CheckCmdLine(); + D_GrabCVarDefaults(); //parse DEFCVARS + InitPalette(); - // [RH] Load sound environments - S_ParseReverbDef (); + if (!batchrun) Printf("S_Init: Setting up sound.\n"); + S_Init(); - // [RH] Parse any SNDINFO lumps - if (!batchrun) Printf ("S_InitData: Load sound definitions.\n"); - S_InitData (); + int max_progress = TexMan.GuesstimateNumTextures(); + int per_shader_progress = 0;//screen->GetShaderCount()? (max_progress / 10 / screen->GetShaderCount()) : 0; + bool nostartscreen = batchrun || restart || Args->CheckParm("-join") || Args->CheckParm("-host") || Args->CheckParm("-norun"); + + if (GameStartupInfo.Type == FStartupInfo::DefaultStartup) + { + if (gameinfo.gametype == GAME_Hexen) + GameStartupInfo.Type = FStartupInfo::HexenStartup; + else if (gameinfo.gametype == GAME_Heretic) + GameStartupInfo.Type = FStartupInfo::HereticStartup; + else if (gameinfo.gametype == GAME_Strife) + GameStartupInfo.Type = FStartupInfo::StrifeStartup; + } - // [RH] Parse through all loaded mapinfo lumps - if (!batchrun) Printf ("G_ParseMapInfo: Load map definitions.\n"); - G_ParseMapInfo (iwad_info->MapInfo); - ReadStatistics(); + StartScreen = nostartscreen? nullptr : GetGameStartScreen(per_shader_progress > 0 ? max_progress * 10 / 9 : max_progress + 3); + + GameConfig->DoKeySetup(gameinfo.ConfigName.GetChars()); - // MUSINFO must be parsed after MAPINFO - S_ParseMusInfo(); + // Now that wads are loaded, define mod-specific cvars. + ParseCVarInfo(); - if (!batchrun) Printf ("Texman.Init: Init texture manager.\n"); - TexMan.Init(); - C_InitConback(); + // Actually exec command line commands and exec files. + if (exec != NULL) + { + exec->ExecCommands(); + delete exec; + exec = NULL; + } - StartScreen->Progress(); - V_InitFonts(); + if (!restart) + V_Init2(); + + // [RH] Initialize localizable strings. + GStrings.LoadStrings(fileSystem, language); + + V_InitFontColors (); + + // [RH] Moved these up here so that we can do most of our + // startup output in a fullscreen console. + + CT_Init (); + + if (!restart) + { + if (!batchrun) Printf ("I_Init: Setting up machine state.\n"); + CheckCPUID(&CPU); + CalculateCPUSpeed(); + auto ci = DumpCPUInfo(&CPU); + Printf("%s", ci.GetChars()); + } + + TexMan.Init(); + + if (!batchrun) Printf ("V_Init: allocate screen.\n"); + if (!restart) + { + screen->CompileNextShader(); + if (StartScreen != nullptr) StartScreen->Render(); + } + else + { + // Update screen palette when restarting + screen->UpdatePalette(); + } + + // Base systems have been inited; enable cvar callbacks + FBaseCVar::EnableCallbacks (); + + // +compatmode cannot be used on the command line, so use this as a substitute + auto compatmodeval = Args->CheckValue("-compatmode"); + if (compatmodeval) + { + compatmode = (int)strtoll(compatmodeval, nullptr, 10); + } + + if (!batchrun) Printf ("ST_Init: Init startup screen.\n"); + if (!restart) + { + StartWindow = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5); + } + else + { + StartWindow = new FStartupScreen(0); + } + + CheckCmdLine(); + + // [RH] Load sound environments + S_ParseReverbDef (); + + // [RH] Parse any SNDINFO lumps + if (!batchrun) Printf ("S_InitData: Load sound definitions.\n"); + S_InitData (); + + // [RH] Parse through all loaded mapinfo lumps + if (!batchrun) Printf ("G_ParseMapInfo: Load map definitions.\n"); + G_ParseMapInfo (iwad_info->MapInfo); + MessageBoxClass = gameinfo.MessageBoxClass; + endoomName = gameinfo.Endoom; + menuBlurAmount = gameinfo.bluramount; + ReadStatistics(); + + // MUSINFO must be parsed after MAPINFO + S_ParseMusInfo(); + + if (!batchrun) Printf ("Texman.Init: Init texture manager.\n"); + UpdateUpscaleMask(); + SpriteFrames.Clear(); + TexMan.AddTextures([]() + { + StartWindow->Progress(); + if (StartScreen) StartScreen->Progress(1); + }, CheckForHacks, InitBuildTiles); + PatchTextures(); + TexAnim.Init(); + C_InitConback(TexMan.CheckForTexture(gameinfo.BorderFlat.GetChars(), ETextureType::Flat), true, 0.25); + + FixWideStatusBar(); + + StartWindow->Progress(); + if (StartScreen) StartScreen->Progress(1); + V_InitFonts(); + InitDoomFonts(); + V_LoadTranslations(); + UpdateGenericUI(false); + + // [CW] Parse any TEAMINFO lumps. + if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n"); + FTeam::ParseTeamInfo (); + + R_ParseTrnslate(); + PClassActor::StaticInit (); + FBaseCVar::InitZSCallbacks (); + + Job_Init(); - // [CW] Parse any TEAMINFO lumps. - if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n"); - TeamLibrary.ParseTeamInfo (); + // [GRB] Initialize player class list + SetupPlayerClasses (); - R_ParseTrnslate(); - PClassActor::StaticInit (); + // [RH] Load custom key and weapon settings from WADs + D_LoadWadSettings (); - // [GRB] Initialize player class list - SetupPlayerClasses (); + // [GRB] Check if someone used clearplayerclasses but not addplayerclass + if (PlayerClasses.Size () == 0) + { + I_FatalError ("No player classes defined"); + } - // [RH] Load custom key and weapon settings from WADs - D_LoadWadSettings (); + StartWindow->Progress(); + if (StartScreen) StartScreen->Progress (1); - // [GRB] Check if someone used clearplayerclasses but not addplayerclass - if (PlayerClasses.Size () == 0) - { - I_FatalError ("No player classes defined"); - } + ParseGLDefs(); - StartScreen->Progress (); + if (!batchrun) Printf ("R_Init: Init %s refresh subsystem.\n", gameinfo.ConfigName.GetChars()); + if (StartScreen) StartScreen->LoadingStatus ("Loading graphics", 0x3f); + if (StartScreen) StartScreen->Progress(1); + StartWindow->Progress(); + R_Init (); - ParseGLDefs(); + if (!batchrun) Printf ("DecalLibrary: Load decals.\n"); + DecalLibrary.ReadAllDecals (); - if (!batchrun) Printf ("R_Init: Init %s refresh subsystem.\n", gameinfo.ConfigName.GetChars()); - StartScreen->LoadingStatus ("Loading graphics", 0x3f); - R_Init (); + auto numbasesounds = soundEngine->GetNumSounds(); - if (!batchrun) Printf ("DecalLibrary: Load decals.\n"); - DecalLibrary.ReadAllDecals (); + // Load embedded Dehacked patches + D_LoadDehLumps(FromIWAD, iwad_info->SkipBexStringsIfLanguage ? DEH_SKIP_BEX_STRINGS_IF_LANGUAGE : 0); - // Load embedded Dehacked patches - D_LoadDehLumps(FromIWAD); + // [RH] Add any .deh and .bex files on the command line. + // If there are none, try adding any in the config file. + // Note that the command line overrides defaults from the config. - // [RH] Add any .deh and .bex files on the command line. - // If there are none, try adding any in the config file. - // Note that the command line overrides defaults from the config. + if ((ConsiderPatches("-deh") | ConsiderPatches("-bex")) == 0 && + gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked")) + { + const char *key; + const char *value; - if ((ConsiderPatches("-deh") | ConsiderPatches("-bex")) == 0 && - gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked")) + while (GameConfig->NextInSection (key, value)) { - const char *key; - const char *value; - - while (GameConfig->NextInSection (key, value)) + if (stricmp (key, "Path") == 0 && FileExists (value)) { - if (stricmp (key, "Path") == 0 && FileExists (value)) - { - if (!batchrun) Printf ("Applying patch %s\n", value); - D_LoadDehFile(value); - } + if (!batchrun) Printf ("Applying patch %s\n", value); + D_LoadDehFile(value, 0); } } + } - // Load embedded Dehacked patches - D_LoadDehLumps(FromPWADs); + // Load embedded Dehacked patches + D_LoadDehLumps(FromPWADs, 0); - // Create replacements for dehacked pickups - FinishDehPatch(); + // Create replacements for dehacked pickups + FinishDehPatch(); - if (!batchrun) Printf("M_Init: Init menus.\n"); - M_Init(); + auto numdehsounds = soundEngine->GetNumSounds(); + if (numbasesounds < numdehsounds) S_LockLocalSndinfo(); // DSDHacked sounds are not compatible with map-local SNDINFOs. - // clean up the compiler symbols which are not needed any longer. - RemoveUnusedSymbols(); + if (!batchrun) Printf("M_Init: Init menus.\n"); + SetDefaultMenuColors(); + M_Init(); + M_CreateGameMenus(); - InitActorNumsFromMapinfo(); - InitSpawnablesFromMapinfo(); - PClassActor::StaticSetActorNums(); - //Added by MC: - primaryLevel->BotInfo.getspawned.Clear(); - argcount = Args->CheckParmList("-bots", &args); - for (p = 0; p < argcount; ++p) - { - primaryLevel->BotInfo.getspawned.Push(args[p]); - } - primaryLevel->BotInfo.spawn_tries = 0; - primaryLevel->BotInfo.wanted_botnum = primaryLevel->BotInfo.getspawned.Size(); + // clean up the compiler symbols which are not needed any longer. + RemoveUnusedSymbols(); + + InitActorNumsFromMapinfo(); + InitSpawnablesFromMapinfo(); + PClassActor::StaticSetActorNums(); + + //Added by MC: + primaryLevel->BotInfo.getspawned.Clear(); + + FString *args; + int argcount = Args->CheckParmList("-bots", &args); + for (int p = 0; p < argcount; ++p) + { + primaryLevel->BotInfo.getspawned.Push(args[p]); + } + primaryLevel->BotInfo.spawn_tries = 0; + primaryLevel->BotInfo.wanted_botnum = primaryLevel->BotInfo.getspawned.Size(); - if (!batchrun) Printf ("P_Init: Init Playloop state.\n"); - StartScreen->LoadingStatus ("Init game engine", 0x3f); - AM_StaticInit(); - P_Init (); + if (!batchrun) Printf ("P_Init: Init Playloop state.\n"); + if (StartScreen) StartScreen->LoadingStatus ("Init game engine", 0x3f); + AM_StaticInit(); + P_Init (); - P_SetupWeapons_ntohton(); + P_SetupWeapons_ntohton(); - //SBarInfo support. Note that the first SBARINFO lump contains the mugshot definition so it even needs to be read when a regular status bar is being used. - SBarInfo::Load(); + //SBarInfo support. Note that the first SBARINFO lump contains the mugshot definition so it even needs to be read when a regular status bar is being used. + SBarInfo::Load(); - if (!batchrun) + if (!batchrun) + { + // [RH] User-configurable startup strings. Because BOOM does. + static const char *startupString[5] = { + "STARTUP1", "STARTUP2", "STARTUP3", "STARTUP4", "STARTUP5" + }; + for (int p = 0; p < 5; ++p) { - // [RH] User-configurable startup strings. Because BOOM does. - static const char *startupString[5] = { - "STARTUP1", "STARTUP2", "STARTUP3", "STARTUP4", "STARTUP5" - }; - for (p = 0; p < 5; ++p) + // At this point we cannot use the player's gender info yet so force 'male' here. + const char *str = GStrings.CheckString(startupString[p], nullptr, 0); + if (str != NULL && str[0] != '\0') { - // At this point we cannot use the player's gender info yet so force 'male' here. - const char *str = GStrings.GetString(startupString[p], nullptr, 0); - if (str != NULL && str[0] != '\0') - { - Printf("%s\n", str); - } + Printf("%s\n", str); } } + } - if (!restart) + if (!restart) + { + if (!batchrun) Printf ("D_CheckNetGame: Checking network game status.\n"); + if (StartScreen) StartScreen->LoadingStatus ("Checking network game status.", 0x3f); + if (!D_CheckNetGame ()) { - if (!batchrun) Printf ("D_CheckNetGame: Checking network game status.\n"); - StartScreen->LoadingStatus ("Checking network game status.", 0x3f); - if (!D_CheckNetGame ()) - { - return 0; - } + return 0; } + } - // [SP] Force vanilla transparency auto-detection to re-detect our game lumps now - UpdateVanillaTransparency(); + // [SP] Force vanilla transparency auto-detection to re-detect our game lumps now + UpdateVanillaTransparency(); - // [RH] Lock any cvars that should be locked now that we're - // about to begin the game. - FBaseCVar::EnableNoSet (); + // [RH] Lock any cvars that should be locked now that we're + // about to begin the game. + FBaseCVar::EnableNoSet (); - delete iwad_man; // now we won't need this anymore - iwad_man = NULL; + // [RH] Run any saved commands from the command line or autoexec.cfg now. + gamestate = GS_FULLCONSOLE; + Net_NewMakeTic (); + C_RunDelayedCommands(); + gamestate = GS_STARTUP; - // [RH] Run any saved commands from the command line or autoexec.cfg now. - gamestate = GS_FULLCONSOLE; - Net_NewMakeTic (); - C_RunDelayedCommands(); - gamestate = GS_STARTUP; + // enable custom invulnerability map here + if (cl_customizeinvulmap) + R_UpdateInvulnerabilityColormap(); - // enable custom invulnerability map here - if (cl_customizeinvulmap) - R_UpdateInvulnerabilityColormap(); + if (!restart) + { + // start the apropriate game based on parms + auto v = Args->CheckValue ("-record"); - if (!restart) + if (v) { - // start the apropriate game based on parms - v = Args->CheckValue ("-record"); + G_RecordDemo (v); + autostart = true; + } - if (v) - { - G_RecordDemo (v); - autostart = true; - } + S_Sound (CHAN_BODY, 0, "misc/startupdone", 1, ATTN_NONE); + + if (Args->CheckParm("-norun") || batchrun) + { + return 1337; // special exit + } + if (StartScreen) + { + StartScreen->Progress(max_progress); // advance progress bar to the end. + StartScreen->Render(true); + StartScreen->Progress(max_progress); // do this again because Progress advances the counter after redrawing. + StartScreen->Render(true); delete StartScreen; StartScreen = NULL; - S_Sound (CHAN_BODY, 0, "misc/startupdone", 1, ATTN_NONE); - - if (Args->CheckParm("-norun") || batchrun) - { - return 1337; // special exit - } + } - V_Init2(); - UpdateJoystickMenu(NULL); - UpdateVRModes(); + while(!screen->CompileNextShader()) + { + // here we can do some visual updates later + } + twod->fullscreenautoaspect = gameinfo.fullscreenautoaspect; + // Initialize the size of the 2D drawer so that an attempt to access it outside the draw code won't crash. + twod->Begin(screen->GetWidth(), screen->GetHeight()); + twod->End(); + UpdateJoystickMenu(NULL); + UpdateVRModes(); + Local_Job_Init(); - v = Args->CheckValue ("-loadgame"); - if (v) + v = Args->CheckValue ("-loadgame"); + if (v) + { + FString file = G_BuildSaveName(v); + if (!FileExists(file)) { - FString file(v); - FixPathSeperator (file); - DefaultExtension (file, "." SAVEGAME_EXT); - G_LoadGame (file); + I_FatalError("Cannot find savegame %s", file.GetChars()); } + G_LoadGame(file.GetChars()); + } - v = Args->CheckValue("-playdemo"); - if (v != NULL) + v = Args->CheckValue("-playdemo"); + if (v != NULL) + { + singledemo = true; // quit after one demo + G_DeferedPlayDemo (v); + } + else + { + v = Args->CheckValue("-timedemo"); + if (v) { - singledemo = true; // quit after one demo - G_DeferedPlayDemo (v); - D_DoomLoop (); // never returns + G_TimeDemo(v); } else { - v = Args->CheckValue("-timedemo"); - if (v) - { - G_TimeDemo(v); - D_DoomLoop(); // never returns - } - else + if (gameaction != ga_loadgame && gameaction != ga_loadgamehidecon) { - if (gameaction != ga_loadgame && gameaction != ga_loadgamehidecon) + if (autostart || netgame) { - if (autostart || netgame) + // Do not do any screenwipes when autostarting a game. + if (!Args->CheckParm("-warpwipe")) { - // Do not do any screenwipes when autostarting a game. - if (!Args->CheckParm("-warpwipe")) - { - NoWipe = TICRATE; - } - CheckWarpTransMap(startmap, true); - if (demorecording) - G_BeginRecording(startmap); - G_InitNew(startmap, false); - if (StoredWarp.IsNotEmpty()) - { - AddCommandString(StoredWarp); - StoredWarp = ""; - } + NoWipe = TICRATE; } - else + CheckWarpTransMap(startmap, true); + if (demorecording) + G_BeginRecording(startmap.GetChars()); + G_InitNew(startmap.GetChars(), false); + if (StoredWarp.IsNotEmpty()) { - D_StartTitle(); // start up intro loop + AddCommandString(StoredWarp.GetChars()); + StoredWarp = ""; } } - else if (demorecording) + else { - G_BeginRecording(NULL); + if (multiplayer || cl_nointros || Args->CheckParm("-nointro")) + { + D_StartTitle(); + } + else + { + I_SetFrameTime(); + if (!StartCutscene(gameinfo.IntroScene, SJ_BLOCKUI, [=](bool) { + gameaction = ga_titleloop; + })) D_StartTitle(); + } } } + else if (demorecording) + { + G_BeginRecording(NULL); + } } } - else + } + else + { + // These calls from inside V_Init2 are still necessary + C_NewModeAdjust(); + D_StartTitle (); // start up intro loop + setmodeneeded = false; // This may be set to true here, but isn't needed for a restart + } + + staticEventManager.OnEngineInitialize(); + return 0; +} +//========================================================================== +// +// D_DoomMain +// +//========================================================================== + +static int D_DoomMain_Internal (void) +{ + const char *wad; + FIWadManager *iwad_man; + + NetworkEntityManager::NetIDStart = MAXPLAYERS + 1; + GC::AddMarkerFunc(GC_MarkGameRoots); + VM_CastSpriteIDToString = Doom_CastSpriteIDToString; + + // Set up the button list. Mlook and Klook need a bit of extra treatment. + buttonMap.SetButtons(DoomButtons, countof(DoomButtons)); + buttonMap.GetButton(Button_Mlook)->ReleaseHandler = Mlook_ReleaseHandler; + buttonMap.GetButton(Button_Mlook)->bReleaseLock = true; + buttonMap.GetButton(Button_Klook)->bReleaseLock = true; + + sysCallbacks = { + G_Responder, + System_WantGuiCapture, + System_WantLeftButton, + System_NetGame, + System_WantNativeMouse, + System_CaptureModeInGame, + System_CrashInfo, + System_PlayStartupSound, + System_IsSpecialUI, + System_DisableTextureFilter, + System_OnScreenSizeChanged, + System_GetSceneRect, + System_GetLocationDescription, + System_M_Dim, + System_GetPlayerName, + System_DispatchEvent, + StrTable_ValidFilter, + nullptr, + CheckSkipGameOptionBlock, + System_ConsoleToggled, + nullptr, + nullptr, + System_ToggleFullConsole, + System_StartCutscene, + System_SetTransition, + CheckCheatmode, + System_HudScaleChanged, + M_SetSpecialMenu, + OnMenuOpen, + System_LanguageChanged, + OkForLocalization, + []() ->FConfigFile* { return GameConfig; }, + nullptr, + RemapUserTranslation + }; + + + std::set_new_handler(NewFailure); + const char *batchout = Args->CheckValue("-errorlog"); + + D_DoomInit(); + + // [RH] Make sure zdoom.pk3 is always loaded, + // as it contains magic stuff we need. + wad = BaseFileSearch(BASEWAD, NULL, true, GameConfig); + if (wad == NULL) + { + I_FatalError("Cannot find " BASEWAD); + } + LoadHexFont(wad); // load hex font early so we have it during startup. + InitWidgetResources(wad); + + C_InitConsole(80*8, 25*8, false); + I_DetectOS(); + + // +logfile gets checked too late to catch the full startup log in the logfile so do some extra check for it here. + FString logfile = Args->TakeValue("+logfile"); + if (logfile.IsNotEmpty()) + { + execLogfile(logfile.GetChars()); + } + else if (batchout != NULL && *batchout != 0) + { + batchrun = true; + nosound = true; + execLogfile(batchout, true); + Printf("Command line: "); + for (int i = 0; i < Args->NumArgs(); i++) { - // These calls from inside V_Init2 are still necessary - C_NewModeAdjust(); - D_StartTitle (); // start up intro loop - setmodeneeded = false; // This may be set to true here, but isn't needed for a restart + Printf("%s ", Args->GetArg(i)); } + Printf("\n"); + } - D_DoAnonStats(); + Printf("%s version %s\n", GAMENAME, GetVersionString()); - I_UpdateWindowTitle(); + extern void D_ConfirmSendStats(); + D_ConfirmSendStats(); + + FString basewad = wad; + + FString optionalwad = BaseFileSearch(OPTIONALWAD, NULL, true, GameConfig); + + iwad_man = new FIWadManager(basewad.GetChars(), optionalwad.GetChars()); + // Now that we have the IWADINFO, initialize the autoload ini sections. + GameConfig->DoAutoloadSetup(iwad_man); + + // reinit from here + + do + { + PClass::StaticInit(); + PType::StaticInit(); + + if (restart) + { + C_InitConsole(SCREENWIDTH, SCREENHEIGHT, false); + } + nospriterename = false; + + if (iwad_man == NULL) + { + iwad_man = new FIWadManager(basewad.GetChars(), optionalwad.GetChars()); + } + + // Load zdoom.pk3 alone so that we can get access to the internal gameinfos before + // the IWAD is known. + + std::vector pwads; + GetCmdLineFiles(pwads); + FString iwad = CheckGameInfo(pwads); + + // The IWAD selection dialogue does not show in fullscreen so if the + // restart is initiated without a defined IWAD assume for now that it's not going to change. + if (iwad.IsEmpty()) iwad = lastIWAD; + + std::vector allwads; + + const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad.GetChars(), basewad.GetChars(), optionalwad.GetChars()); + + GetCmdLineFiles(pwads); // [RL0] Update with files passed on the launcher extra args + + if (!iwad_info) return 0; // user exited the selection popup via cancel button. + if ((iwad_info->flags & GI_SHAREWARE) && pwads.size() > 0) + { + I_FatalError ("You cannot -file with the shareware version. Register!"); + } + lastIWAD = iwad; + + int ret = D_InitGame(iwad_info, allwads, pwads); + pwads.clear(); + pwads.shrink_to_fit(); + allwads.clear(); + allwads.shrink_to_fit(); + delete iwad_man; // now we won't need this anymore + iwad_man = NULL; + if (ret != 0) return ret; + + D_DoAnonStats(); + I_UpdateWindowTitle(); D_DoomLoop (); // this only returns if a 'restart' CCMD is given. // // Clean up after a restart @@ -2905,10 +3799,23 @@ static int D_DoomMain_Internal (void) while (1); } -int D_DoomMain() +int GameMain() { int ret = 0; GameTicRate = TICRATE; + I_InitTime(); + + ConsoleCallbacks cb = { + D_UserInfoChanged, + D_SendServerInfoChange, + D_SendServerFlagChange, + G_GetUserCVar, + []() { return gamestate != GS_FULLCONSOLE && gamestate != GS_STARTUP; } + }; + C_InitCVars(0); + C_InstallHandlers(&cb); + SetConsoleNotifyBuffer(); + try { ret = D_DoomMain_Internal(); @@ -2924,7 +3831,6 @@ int D_DoomMain() } // Unless something really bad happened, the game should only exit through this single point in the code. // No more 'exit', please. - // Todo: Move all engine cleanup here instead of using exit handlers and replace the scattered 'exit' calls with a special exception. D_Cleanup(); CloseNetwork(); GC::FinalGC = true; @@ -2937,6 +3843,7 @@ int D_DoomMain() I_ShutdownInput(); M_SaveDefaultsFinal(); DeleteStartupScreen(); + C_UninitCVars(); // must come last so that nothing will access the CVARs anymore after deletion. delete Args; Args = nullptr; return ret; @@ -2962,49 +3869,56 @@ void D_Cleanup() G_ClearMapinfo(); M_ClearMenus(); // close menu if open - F_EndFinale(); // If an intermission is active, end it now AM_ClearColorsets(); DeinitSWColorMaps(); FreeSBarInfoScript(); - + DeleteScreenJob(); + // clean up game state - ST_Clear(); D_ErrorCleanup (); P_Shutdown(); M_SaveDefaults(NULL); // save config before the restart // delete all data that cannot be left until reinitialization - if (screen) screen->CleanForRestart(); + CleanSWDrawer(); V_ClearFonts(); // must clear global font pointers ColorSets.Clear(); PainFlashes.Clear(); - R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. gameinfo.~gameinfo_t(); new (&gameinfo) gameinfo_t; // Reset gameinfo S_Shutdown(); // free all channels and delete playlist C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods DeinitMenus(); + savegameManager.ClearSaveGames(); LightDefaults.DeleteAndClear(); // this can leak heap memory if it isn't cleared. + TexAnim.DeleteAll(); + TexMan.DeleteAll(); - // delete DoomStartupInfo data - DoomStartupInfo.Name = ""; - DoomStartupInfo.BkColor = DoomStartupInfo.FgColor = DoomStartupInfo.Type = 0; - DoomStartupInfo.LoadLights = DoomStartupInfo.LoadBrightmaps = -1; - + // delete GameStartupInfo data + GameStartupInfo.Name = ""; + GameStartupInfo.BkColor = GameStartupInfo.FgColor = GameStartupInfo.Type = 0; + GameStartupInfo.LoadWidescreen = GameStartupInfo.LoadLights = GameStartupInfo.LoadBrightmaps = -1; + GameStartupInfo.DiscordAppId = ""; + GameStartupInfo.SteamAppId = ""; + GC::FullGC(); // clean up before taking down the object list. // Delete the reference to the VM functions here which were deleted and will be recreated after the restart. - FAutoSegIterator probe(ARegHead, ARegTail); - while (*++probe != NULL) + AutoSegs::ActionFunctons.ForEach([](AFuncDesc *afunc) { - AFuncDesc *afunc = (AFuncDesc *)*probe; *(afunc->VMPointer) = NULL; - } + }); GC::DelSoftRootHead(); + for (auto& p : players) + { + p.PendingWeapon = nullptr; + } + PClassActor::AllActorClasses.Clear(); + ScriptUtil::Clear(); PClass::StaticShutdown(); GC::FullGC(); // perform one final garbage collection after shutdown @@ -3048,79 +3962,6 @@ UNSAFE_CCMD(restart) wantToRestart = true; } -//========================================================================== -// -// FStartupScreen Constructor -// -//========================================================================== - -FStartupScreen::FStartupScreen(int max_progress) -{ - MaxPos = max_progress; - CurPos = 0; - NotchPos = 0; -} - -//========================================================================== -// -// FStartupScreen Destructor -// -//========================================================================== - -FStartupScreen::~FStartupScreen() -{ -} - -//========================================================================== -// -// FStartupScreen :: LoadingStatus -// -// Used by Heretic for the Loading Status "window." -// -//========================================================================== - -void FStartupScreen::LoadingStatus(const char *message, int colors) -{ -} - -//========================================================================== -// -// FStartupScreen :: AppendStatusLine -// -// Used by Heretic for the "status line" at the bottom of the screen. -// -//========================================================================== - -void FStartupScreen::AppendStatusLine(const char *status) -{ -} - -//=========================================================================== -// -// DeleteStartupScreen -// -// Makes sure the startup screen has been deleted before quitting. -// -//=========================================================================== - -void DeleteStartupScreen() -{ - if (StartScreen != nullptr) - { - delete StartScreen; - StartScreen = nullptr; - } -} - - - -void FStartupScreen::Progress(void) {} -void FStartupScreen::NetInit(char const *,int) {} -void FStartupScreen::NetProgress(int) {} -void FStartupScreen::NetMessage(char const *,...) {} -void FStartupScreen::NetDone(void) {} -bool FStartupScreen::NetLoop(bool (*)(void *),void *) { return false; } - DEFINE_FIELD_X(InputEventData, event_t, type) DEFINE_FIELD_X(InputEventData, event_t, subtype) DEFINE_FIELD_X(InputEventData, event_t, data1) @@ -3129,27 +3970,82 @@ DEFINE_FIELD_X(InputEventData, event_t, data3) DEFINE_FIELD_X(InputEventData, event_t, x) DEFINE_FIELD_X(InputEventData, event_t, y) -CUSTOM_CVAR(Int, I_FriendlyWindowTitle, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL) -{ - I_UpdateWindowTitle(); -} - void I_UpdateWindowTitle() { + FString titlestr; switch (I_FriendlyWindowTitle) { case 1: - if (level.LevelName && level.LevelName.GetChars()[0]) + if (level.LevelName.IsNotEmpty()) { - FString titlestr; - titlestr.Format("%s - %s", level.LevelName.GetChars(), DoomStartupInfo.Name.GetChars()); - I_SetWindowTitle(titlestr.GetChars()); + titlestr.Format("%s - %s", level.LevelName.GetChars(), GameStartupInfo.Name.GetChars()); break; } + [[fallthrough]]; case 2: - I_SetWindowTitle(DoomStartupInfo.Name.GetChars()); + titlestr = GameStartupInfo.Name; break; default: + I_UpdateDiscordPresence(false, NULL, GameStartupInfo.DiscordAppId.GetChars(), GameStartupInfo.SteamAppId.GetChars()); I_SetWindowTitle(NULL); + return; + } + + // Strip out any color escape sequences before setting a window title + TArray copy(titlestr.Len() + 1); + const char* srcp = titlestr.GetChars(); + char* dstp = copy.Data(); + + while (*srcp != 0) + { + + if (*srcp != TEXTCOLOR_ESCAPE) + { + *dstp++ = *srcp++; + } + else if (srcp[1] == '[') + { + srcp += 2; + while (*srcp != ']' && *srcp != 0) srcp++; + if (*srcp == ']') srcp++; + } + else + { + if (srcp[1] != 0) srcp += 2; + else break; + } + } + *dstp = 0; + if (i_discordrpc) + I_UpdateDiscordPresence(true, copy.Data(), GameStartupInfo.DiscordAppId.GetChars(), GameStartupInfo.SteamAppId.GetChars()); + else + I_UpdateDiscordPresence(false, nullptr, nullptr, nullptr); + I_SetWindowTitle(copy.Data()); +} + +CCMD(fs_dir) +{ + int numfiles = fileSystem.GetNumEntries(); + + for (int i = 0; i < numfiles; i++) + { + auto container = fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(i)); + auto fn1 = fileSystem.GetFileFullName(i); + auto fns = fileSystem.GetFileShortName(i); + auto fnid = fileSystem.GetResourceId(i); + auto length = fileSystem.FileLength(i); + bool hidden = fileSystem.FindFile(fn1) != i; + Printf(PRINT_HIGH | PRINT_NONOTIFY, "%s%-64s %-15s (%5d) %10d %s %s\n", hidden ? TEXTCOLOR_RED : TEXTCOLOR_UNTRANSLATED, fn1, fns, fnid, length, container, hidden ? "(h)" : ""); } } + +CCMD(type) +{ + if (argv.argc() < 2) return; + int lump = fileSystem.CheckNumForFullName(argv[1]); + if (lump >= 0) + { + auto data = fileSystem.ReadFile(lump); + Printf("%.*s\n", data.size(), data.string()); + } +} \ No newline at end of file diff --git a/src/d_main.h b/src/d_main.h index 5fea9f034b8..49e9846be1a 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -30,6 +30,12 @@ #include "doomtype.h" #include "gametype.h" +#include "startupinfo.h" +#include "c_cvars.h" + +extern bool advancedemo; +extern bool hud_toggled; +void D_ToggleHud(); struct event_t; @@ -45,8 +51,6 @@ struct CRestartException char dummy; }; -int D_DoomMain (void); - void D_Display (); @@ -58,7 +62,6 @@ void D_PageTicker (void); void D_PageDrawer (void); void D_AdvanceDemo (void); void D_StartTitle (void); -bool D_AddFile (TArray &wadfiles, const char *file, bool check = true, int position = -1); // [RH] Set this to something to draw an icon during the next screen refresh. @@ -68,31 +71,6 @@ extern const char *D_DrawIcon; extern uint32_t r_renderercaps; -struct WadStuff -{ - FString Path; - FString Name; -}; - -struct FStartupInfo -{ - FString Name; - uint32_t FgColor; // Foreground color for title banner - uint32_t BkColor; // Background color for title banner - FString Song; - int Type; - int LoadLights = -1; - int LoadBrightmaps = -1; - enum - { - DefaultStartup, - DoomStartup, - HereticStartup, - HexenStartup, - StrifeStartup, - }; -}; - struct FIWADInfo { FString Name; // Title banner text for this IWAD @@ -108,10 +86,16 @@ struct FIWADInfo int StartupType = FStartupInfo::DefaultStartup; // alternate startup type FString MapInfo; // Base mapinfo to load bool nokeyboardcheats = false; // disable keyboard cheats + bool SkipBexStringsIfLanguage = false; TArray Load; // Wads to be loaded with this one. TArray Lumps; // Lump names for identification TArray DeleteLumps; // Lumps which must be deleted from the directory. int flags = 0; + int LoadWidescreen = -1; + int LoadBrightmaps = -1; + int LoadLights = -1; + FString DiscordAppId = nullptr; + FString SteamAppId = nullptr; }; struct FFoundWadInfo @@ -127,8 +111,6 @@ struct FFoundWadInfo } }; -extern FStartupInfo DoomStartupInfo; - //========================================================================== // // IWAD identifier class @@ -147,13 +129,13 @@ class FIWadManager void ParseIWadInfo(const char *fn, const char *data, int datasize, FIWADInfo *result = nullptr); int ScanIWAD (const char *iwad); int CheckIWADInfo(const char *iwad); - int IdentifyVersion (TArray &wadfiles, const char *iwad, const char *zdoom_wad, const char *optional_wad); + int IdentifyVersion (std::vector& wadfiles, const char *iwad, const char *zdoom_wad, const char *optional_wad); void CollectSearchPaths(); void AddIWADCandidates(const char *dir); void ValidateIWADs(); public: FIWadManager(const char *fn, const char *fnopt); - const FIWADInfo *FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad, const char *optionalwad); + const FIWADInfo *FindIWAD(std::vector& wadfiles, const char *iwad, const char *basewad, const char *optionalwad); const FString *GetAutoname(unsigned int num) const { if (num < mIWadInfos.Size()) return &mIWadInfos[num].Autoname; @@ -165,6 +147,25 @@ class FIWadManager else return 0; } + }; +#ifndef NO_SWRENDERER +EXTERN_CVAR(Int, vid_rendermode) +#else +constexpr int vid_rendermode = 4; +#endif + +inline bool V_IsHardwareRenderer() +{ + return vid_rendermode == 4; +} + +inline bool V_IsTrueColor() +{ + return vid_rendermode == 1 || vid_rendermode == 4; +} + +bool CheckCheatmode(bool printmsg = true, bool sponly = false); + #endif diff --git a/src/d_net.cpp b/src/d_net.cpp index 3b8222b3cc3..b785b52e2b9 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -30,7 +30,7 @@ #include #include "version.h" -#include "menu/menu.h" +#include "menu.h" #include "i_video.h" #include "i_net.h" #include "g_game.h" @@ -51,7 +51,7 @@ #include "st_start.h" #include "teaminfo.h" #include "p_conversation.h" -#include "d_event.h" +#include "d_eventbase.h" #include "p_enemy.h" #include "m_argv.h" #include "p_lnspec.h" @@ -68,9 +68,14 @@ #include "vm.h" #include "gstrings.h" #include "s_music.h" +#include "screenjob.h" +#include "d_main.h" +#include "i_interface.h" +#include "savegamemanager.h" EXTERN_CVAR (Int, disableautosave) EXTERN_CVAR (Int, autosavecount) +EXTERN_CVAR(Bool, cl_capfps) //#define SIMULATEERRORS (RAND_MAX/3) #define SIMULATEERRORS 0 @@ -81,7 +86,6 @@ extern FString savegamefile; extern short consistancy[MAXPLAYERS][BACKUPTICS]; -doomcom_t doomcom; #define netbuffer (doomcom.data) enum { NET_PeerToPeer, NET_PacketServer }; @@ -124,7 +128,7 @@ int playerfornode[MAXNETNODES]; int maketic; int skiptics; -int ticdup; +int ticdup = 1; void D_ProcessEvents (void); void G_BuildTiccmd (ticcmd_t *cmd); @@ -146,8 +150,6 @@ static int oldentertics; extern bool advancedemo; -CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - CVAR(Bool, net_ticbalance, false, CVAR_SERVERINFO | CVAR_NOSAVE) CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO | CVAR_NOSAVE) { @@ -224,7 +226,7 @@ static struct TicSpecial { int i; - specialsize = MAX(specialsize * 2, needed + 30); + specialsize = max(specialsize * 2, needed + 30); DPrintf (DMSG_NOTIFY, "Expanding special size to %zu\n", specialsize); @@ -262,27 +264,37 @@ static struct TicSpecial if (streamptr) { CheckSpace (1); - WriteByte (it, &streamptr); + WriteInt8 (it, &streamptr); } return *this; } - TicSpecial &operator << (short it) + TicSpecial &operator << (int16_t it) { if (streamptr) { CheckSpace (2); - WriteWord (it, &streamptr); + WriteInt16 (it, &streamptr); } return *this; } - TicSpecial &operator << (int it) + TicSpecial &operator << (int32_t it) { if (streamptr) { CheckSpace (4); - WriteLong (it, &streamptr); + WriteInt32 (it, &streamptr); + } + return *this; + } + + TicSpecial& operator << (int64_t it) + { + if (streamptr) + { + CheckSpace(8); + WriteInt64(it, &streamptr); } return *this; } @@ -297,6 +309,16 @@ static struct TicSpecial return *this; } + TicSpecial& operator << (double it) + { + if (streamptr) + { + CheckSpace(8); + WriteDouble(it, &streamptr); + } + return *this; + } + TicSpecial &operator << (const char *it) { if (streamptr) @@ -789,7 +811,7 @@ void GetPackets (void) { if (playeringame[i]) { - int resend = ReadLong (&foo); + int resend = ReadInt32 (&foo); if (i != consoleplayer) { resendto[nodeforplayer[i]] = resend; @@ -1153,7 +1175,7 @@ void NetUpdate (void) netbuffer[k++] = lowtic; } - numtics = MAX(0, lowtic - realstart); + numtics = max(0, lowtic - realstart); if (numtics > BACKUPTICS) I_Error ("NetUpdate: Node %d missed too many tics", i); @@ -1162,7 +1184,7 @@ void NetUpdate (void) case 0: default: resendto[i] = lowtic; break; - case 1: resendto[i] = MAX(0, lowtic - 1); break; + case 1: resendto[i] = max(0, lowtic - 1); break; case 2: resendto[i] = nettics[i]; break; } @@ -1244,7 +1266,7 @@ void NetUpdate (void) // the other players. if (l == 0) { - WriteWord (localcmds[localstart].consistancy, &cmddata); + WriteInt16 (localcmds[localstart].consistancy, &cmddata); // [RH] Write out special "ticcmds" before real ticcmd if (specials.used[start]) { @@ -1259,7 +1281,7 @@ void NetUpdate (void) int len; uint8_t *spec; - WriteWord (netcmds[playerbytes[l]][start].consistancy, &cmddata); + WriteInt16 (netcmds[playerbytes[l]][start].consistancy, &cmddata); spec = NetSpecs[playerbytes[l]][start].GetData (&len); if (spec != NULL) { @@ -1404,7 +1426,6 @@ struct ArbitrateData bool DoArbitrate (void *userdata) { ArbitrateData *data = (ArbitrateData *)userdata; - char *s; uint8_t *stream; int version; int node; @@ -1453,7 +1474,7 @@ bool DoArbitrate (void *userdata) data->playersdetected[0] |= 1 << netbuffer[1]; - StartScreen->NetMessage ("Found %s (node %d, player %d)", + I_NetMessage ("Found %s (node %d, player %d)", players[netbuffer[1]].userinfo.GetName(), node, netbuffer[1]+1); } @@ -1462,14 +1483,12 @@ bool DoArbitrate (void *userdata) { data->gotsetup[0] = 0x80; - ticdup = doomcom.ticdup = netbuffer[1]; + ticdup = doomcom.ticdup = clamp(netbuffer[1], 1, MAXTICDUP); NetMode = netbuffer[2]; stream = &netbuffer[3]; - s = ReadString (&stream); - startmap = s; - delete[] s; - rngseed = ReadLong (&stream); + startmap = ReadStringConst(&stream); + rngseed = ReadInt32 (&stream); C_ReadCVars (&stream); } else if (netbuffer[0] == NCMD_SETUP+3) @@ -1503,7 +1522,9 @@ bool DoArbitrate (void *userdata) netbuffer[1] = consoleplayer; netbuffer[9] = data->gotsetup[0]; stream = &netbuffer[10]; - D_WriteUserInfoStrings (consoleplayer, &stream, true); + auto str = D_GetUserInfoStrings (consoleplayer, true); + memcpy(stream, str.GetChars(), str.Len() + 1); + stream += str.Len(); SendSetup (data->playersdetected, data->gotsetup, int(stream - netbuffer)); } else @@ -1518,7 +1539,9 @@ bool DoArbitrate (void *userdata) { netbuffer[1] = j; stream = &netbuffer[9]; - D_WriteUserInfoStrings (j, &stream, true); + auto str = D_GetUserInfoStrings(j, true); + memcpy(stream, str.GetChars(), str.Len() + 1); + stream += str.Len(); HSendPacket (i, int(stream - netbuffer)); } } @@ -1532,8 +1555,8 @@ bool DoArbitrate (void *userdata) netbuffer[1] = (uint8_t)doomcom.ticdup; netbuffer[2] = NetMode; stream = &netbuffer[3]; - WriteString (startmap, &stream); - WriteLong (rngseed, &stream); + WriteString (startmap.GetChars(), &stream); + WriteInt32 (rngseed, &stream); C_WriteCVars (&stream, CVAR_SERVERINFO, true); SendSetup (data->playersdetected, data->gotsetup, int(stream - netbuffer)); @@ -1601,8 +1624,8 @@ bool D_ArbitrateNetStart (void) data.gotsetup[0] = 0x80; } - StartScreen->NetInit ("Exchanging game information", 1); - if (!StartScreen->NetLoop (DoArbitrate, &data)) + I_NetInit ("Exchanging game information", 1); + if (!I_NetLoop (DoArbitrate, &data)) { return false; } @@ -1620,7 +1643,7 @@ bool D_ArbitrateNetStart (void) fprintf (debugfile, "player %d is on node %d\n", i, nodeforplayer[i]); } } - StartScreen->NetDone(); + I_NetDone(); return true; } @@ -1776,7 +1799,7 @@ void D_QuitNetGame (void) for (i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i] && i != consoleplayer) - WriteLong (resendto[nodeforplayer[i]], &foo); + WriteInt32 (resendto[nodeforplayer[i]], &foo); } k = int(foo - netbuffer); } @@ -1838,7 +1861,7 @@ static void TicStabilityEnd() { using namespace std::chrono; uint64_t stabilityendtime = duration_cast(steady_clock::now().time_since_epoch()).count(); - stabilityticduration = std::min(stabilityendtime - stabilitystarttime, (uint64_t)1'000'000); + stabilityticduration = min(stabilityendtime - stabilitystarttime, (uint64_t)1'000'000); } // @@ -1853,11 +1876,7 @@ void TryRunTics (void) int counts; int numplaying; - // If paused, do not eat more CPU time than we need, because it - // will all be wasted anyway. - if (pauseext) - r_NoInterpolate = true; - bool doWait = cl_capfps || r_NoInterpolate /*|| netgame*/; + bool doWait = (cl_capfps || pauseext || (r_NoInterpolate && !M_IsAnimated())); // get real tics if (doWait) @@ -1889,7 +1908,7 @@ void TryRunTics (void) } } - if (ticdup == 1) + if (ticdup <= 1) { availabletics = lowtic - gametic; } @@ -2048,17 +2067,22 @@ void Net_NewMakeTic (void) specials.NewMakeTic (); } -void Net_WriteByte (uint8_t it) +void Net_WriteInt8 (uint8_t it) { specials << it; } -void Net_WriteWord (short it) +void Net_WriteInt16 (int16_t it) { specials << it; } -void Net_WriteLong (int it) +void Net_WriteInt32 (int32_t it) +{ + specials << it; +} + +void Net_WriteInt64(int64_t it) { specials << it; } @@ -2068,6 +2092,11 @@ void Net_WriteFloat (float it) specials << it; } +void Net_WriteDouble(double it) +{ + specials << it; +} + void Net_WriteString (const char *it) { specials << it; @@ -2164,7 +2193,7 @@ static int RemoveClass(FLevelLocals *Level, const PClass *cls) void Net_DoCommand (int type, uint8_t **stream, int player) { uint8_t pos = 0; - char *s = NULL; + const char* s = nullptr; int i; switch (type) @@ -2172,10 +2201,9 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_SAY: { const char *name = players[player].userinfo.GetName(); - uint8_t who = ReadByte (stream); + uint8_t who = ReadInt8 (stream); - s = ReadString (stream); - CleanseString (s); + s = ReadStringConst(stream); if (((who & 1) == 0) || players[player].userinfo.GetTeam() == TEAM_NONE) { // Said to everyone if (who & 2) @@ -2204,18 +2232,15 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_MUSICCHANGE: - s = ReadString (stream); - S_ChangeMusic (s); + S_ChangeMusic(ReadStringConst(stream)); break; case DEM_PRINT: - s = ReadString (stream); - Printf ("%s", s); + Printf("%s", ReadStringConst(stream)); break; case DEM_CENTERPRINT: - s = ReadString (stream); - C_MidPrint (nullptr, s); + C_MidPrint(nullptr, ReadStringConst(stream)); break; case DEM_UINFCHANGED: @@ -2231,11 +2256,11 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_GIVECHEAT: - s = ReadString (stream); - cht_Give (&players[player], s, ReadLong (stream)); + s = ReadStringConst(stream); + cht_Give (&players[player], s, ReadInt32 (stream)); if (player != consoleplayer) { - FString message = GStrings("TXT_X_CHEATS"); + FString message = GStrings.GetString("TXT_X_CHEATS"); message.Substitute("%s", players[player].userinfo.GetName()); Printf("%s: give %s\n", message.GetChars(), s); } @@ -2243,36 +2268,36 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_TAKECHEAT: - s = ReadString (stream); - cht_Take (&players[player], s, ReadLong (stream)); + s = ReadStringConst(stream); + cht_Take (&players[player], s, ReadInt32 (stream)); break; case DEM_SETINV: - s = ReadString(stream); - i = ReadLong(stream); - cht_SetInv(&players[player], s, i, !!ReadByte(stream)); + s = ReadStringConst(stream); + i = ReadInt32(stream); + cht_SetInv(&players[player], s, i, !!ReadInt8(stream)); break; case DEM_WARPCHEAT: { int x, y, z; - x = ReadWord (stream); - y = ReadWord (stream); - z = ReadWord (stream); + x = ReadInt16 (stream); + y = ReadInt16 (stream); + z = ReadInt16 (stream); P_TeleportMove (players[player].mo, DVector3(x, y, z), true); } break; case DEM_GENERICCHEAT: - cht_DoCheat (&players[player], ReadByte (stream)); + cht_DoCheat (&players[player], ReadInt8 (stream)); break; case DEM_CHANGEMAP2: - pos = ReadByte (stream); + pos = ReadInt8 (stream); /* intentional fall-through */ case DEM_CHANGEMAP: // Change to another map without disconnecting other players - s = ReadString (stream); + s = ReadStringConst(stream); // Using LEVEL_NOINTERMISSION tends to throw the game out of sync. // That was a long time ago. Maybe it works now? primaryLevel->flags |= LEVEL_CHANGEMAPCHEAT; @@ -2317,10 +2342,10 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_INVUSE: case DEM_INVDROP: { - uint32_t which = ReadLong (stream); + uint32_t which = ReadInt32 (stream); int amt = -1; - if (type == DEM_INVDROP) amt = ReadLong(stream); + if (type == DEM_INVDROP) amt = ReadInt32(stream); if (gamestate == GS_LEVEL && !paused && players[player].playerstate != PST_DEAD) @@ -2359,13 +2384,13 @@ void Net_DoCommand (int type, uint8_t **stream, int player) uint8_t special = 0; int args[5]; - s = ReadString (stream); + s = ReadStringConst(stream); if (type >= DEM_SUMMON2 && type <= DEM_SUMMONFOE2) { - angle = ReadWord(stream); - tid = ReadWord(stream); - special = ReadByte(stream); - for(i = 0; i < 5; i++) args[i] = ReadLong(stream); + angle = ReadInt16(stream); + tid = ReadInt16(stream); + special = ReadInt8(stream); + for(i = 0; i < 5; i++) args[i] = ReadInt32(stream); } typeinfo = PClass::FindActor(s); @@ -2408,7 +2433,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) if (type >= DEM_SUMMON2 && type <= DEM_SUMMONFOE2) { - spawned->Angles.Yaw = source->Angles.Yaw - angle; + spawned->Angles.Yaw = source->Angles.Yaw - DAngle::fromDeg(angle); spawned->special = special; for(i = 0; i < 5; i++) { spawned->args[i] = args[i]; @@ -2423,12 +2448,12 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_SPRAY: - s = ReadString(stream); + s = ReadStringConst(stream); SprayDecal(players[player].mo, s); break; case DEM_MDK: - s = ReadString(stream); + s = ReadStringConst(stream); cht_DoMDK(&players[player], s); break; @@ -2451,30 +2476,14 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_SAVEGAME: if (gamestate == GS_LEVEL) { - s = ReadString (stream); - savegamefile = s; - delete[] s; - s = ReadString (stream); - savedescription = s; + savegamefile = ReadStringConst(stream); + savedescription = ReadStringConst(stream); if (player != consoleplayer) { // Paths sent over the network will be valid for the system that sent // the save command. For other systems, the path needs to be changed. - const char *fileonly = savegamefile.GetChars(); - const char *slash = strrchr (fileonly, '\\'); - if (slash != NULL) - { - fileonly = slash + 1; - } - slash = strrchr (fileonly, '/'); - if (slash != NULL) - { - fileonly = slash + 1; - } - if (fileonly != savegamefile.GetChars()) - { - savegamefile = G_BuildSaveName (fileonly, -1); - } + FString basename = ExtractFileBase(savegamefile.GetChars(), true); + savegamefile = G_BuildSaveName (basename.GetChars()); } } gameaction = ga_savegame; @@ -2492,7 +2501,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) { break; } - Net_WriteByte (DEM_DOAUTOSAVE); + Net_WriteInt8 (DEM_DOAUTOSAVE); break; case DEM_DOAUTOSAVE: @@ -2527,8 +2536,8 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_RUNSCRIPT: case DEM_RUNSCRIPT2: { - int snum = ReadWord (stream); - int argn = ReadByte (stream); + int snum = ReadInt16 (stream); + int argn = ReadInt8 (stream); RunScript(stream, players[player].mo, snum, argn, (type == DEM_RUNSCRIPT2) ? ACS_ALWAYS : 0); } @@ -2536,22 +2545,22 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_RUNNAMEDSCRIPT: { - s = ReadString(stream); - int argn = ReadByte(stream); + s = ReadStringConst(stream); + int argn = ReadInt8(stream); - RunScript(stream, players[player].mo, -FName(s), argn & 127, (argn & 128) ? ACS_ALWAYS : 0); + RunScript(stream, players[player].mo, -FName(s).GetIndex(), argn & 127, (argn & 128) ? ACS_ALWAYS : 0); } break; case DEM_RUNSPECIAL: { - int snum = ReadWord(stream); - int argn = ReadByte(stream); + int snum = ReadInt16(stream); + int argn = ReadInt8(stream); int arg[5] = { 0, 0, 0, 0, 0 }; for (i = 0; i < argn; ++i) { - int argval = ReadLong(stream); + int argval = ReadInt32(stream); if ((unsigned)i < countof(arg)) { arg[i] = argval; @@ -2575,8 +2584,8 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_MORPHEX: { - s = ReadString (stream); - FString msg = cht_Morph (players + player, PClass::FindActor (s), false); + s = ReadStringConst(stream); + FString msg = cht_Morph (players + player, PClass::FindActor(s), false); if (player == consoleplayer) { Printf ("%s\n", msg[0] != '\0' ? msg.GetChars() : "Morph failed."); @@ -2586,7 +2595,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_ADDCONTROLLER: { - uint8_t playernum = ReadByte (stream); + uint8_t playernum = ReadInt8 (stream); players[playernum].settings_controller = true; if (consoleplayer == playernum || consoleplayer == Net_Arbitrator) @@ -2596,7 +2605,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_DELCONTROLLER: { - uint8_t playernum = ReadByte (stream); + uint8_t playernum = ReadInt8 (stream); players[playernum].settings_controller = false; if (consoleplayer == playernum || consoleplayer == Net_Arbitrator) @@ -2606,7 +2615,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_KILLCLASSCHEAT: { - s = ReadString (stream); + s = ReadStringConst(stream); int killcount = 0; PClassActor *cls = PClass::FindActor(s); @@ -2629,7 +2638,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_REMOVE: { - s = ReadString(stream); + s = ReadStringConst(stream); int removecount = 0; PClassActor *cls = PClass::FindActor(s); if (cls != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AActor))) @@ -2661,14 +2670,14 @@ void Net_DoCommand (int type, uint8_t **stream, int player) int pnum; if (type == DEM_SETSLOTPNUM) { - pnum = ReadByte(stream); + pnum = ReadInt8(stream); } else { pnum = player; } - unsigned int slot = ReadByte(stream); - int count = ReadByte(stream); + unsigned int slot = ReadInt8(stream); + int count = ReadInt8(stream); if (slot < NUM_WEAPON_SLOTS) { players[pnum].weapons.ClearSlot(slot); @@ -2683,7 +2692,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_ADDSLOT: { - int slot = ReadByte(stream); + int slot = ReadInt8(stream); PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } @@ -2691,19 +2700,15 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_ADDSLOTDEFAULT: { - int slot = ReadByte(stream); + int slot = ReadInt8(stream); PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer); } break; case DEM_SETPITCHLIMIT: - players[player].MinPitch = -(double)ReadByte(stream); // up - players[player].MaxPitch = (double)ReadByte(stream); // down - break; - - case DEM_ADVANCEINTER: - F_AdvanceIntermission(); + players[player].MinPitch = DAngle::fromDeg(-ReadInt8(stream)); // up + players[player].MaxPitch = DAngle::fromDeg(ReadInt8(stream)); // down break; case DEM_REVERTCAMERA: @@ -2717,23 +2722,46 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_NETEVENT: { - s = ReadString(stream); - int argn = ReadByte(stream); + s = ReadStringConst(stream); + int argn = ReadInt8(stream); int arg[3] = { 0, 0, 0 }; for (int i = 0; i < 3; i++) - arg[i] = ReadLong(stream); - bool manual = !!ReadByte(stream); - primaryLevel->localEventManager->Console(player, s, arg[0], arg[1], arg[2], manual); + arg[i] = ReadInt32(stream); + bool manual = !!ReadInt8(stream); + primaryLevel->localEventManager->Console(player, s, arg[0], arg[1], arg[2], manual, false); } break; + case DEM_ENDSCREENJOB: + EndScreenJob(); + break; + + case DEM_ZSC_CMD: + { + FName cmd = ReadStringConst(stream); + unsigned int size = ReadInt16(stream); + + TArray buffer = {}; + if (size) + { + buffer.Grow(size); + for (unsigned int i = 0u; i < size; ++i) + buffer.Push(ReadInt8(stream)); + } + + FNetworkCommand netCmd = { player, cmd, buffer }; + primaryLevel->localEventManager->NetCommand(netCmd); + } + break; + + case DEM_CHANGESKILL: + NextSkill = ReadInt32(stream); + break; + default: I_Error ("Unknown net command: %d", type); break; } - - if (s) - delete[] s; } // Used by DEM_RUNSCRIPT, DEM_RUNSCRIPT2, and DEM_RUNNAMEDSCRIPT @@ -2750,13 +2778,13 @@ static void RunScript(uint8_t **stream, AActor *pawn, int snum, int argn, int al for (i = 0; i < argn; ++i) { - int argval = ReadLong(stream); + int argval = ReadInt32(stream); if ((unsigned)i < countof(arg)) { arg[i] = argval; } } - P_StartScript(pawn->Level, pawn, NULL, snum, primaryLevel->MapName, arg, MIN(countof(arg), argn), ACS_NET | always); + P_StartScript(pawn->Level, pawn, NULL, snum, primaryLevel->MapName.GetChars(), arg, min(countof(arg), argn), ACS_NET | always); } void Net_SkipCommand (int type, uint8_t **stream) @@ -2787,6 +2815,11 @@ void Net_SkipCommand (int type, uint8_t **stream) skip = strlen((char *)(*stream)) + 15; break; + case DEM_ZSC_CMD: + skip = strlen((char*)(*stream)) + 1; + skip += (((*stream)[skip] << 8) | (*stream)[skip + 1]) + 2; + break; + case DEM_SUMMON2: case DEM_SUMMONFRIEND2: case DEM_SUMMONFOE2: @@ -2819,6 +2852,7 @@ void Net_SkipCommand (int type, uint8_t **stream) case DEM_INVUSE: case DEM_FOV: case DEM_MYFOV: + case DEM_CHANGESKILL: skip = 4; break; @@ -2919,15 +2953,15 @@ int Net_GetLatency(int *ld, int *ad) localdelay = ((localdelay / BACKUPTICS) * ticdup) * (1000 / TICRATE); int severity = 0; - if (MAX(localdelay, arbitratordelay) > 200) + if (max(localdelay, arbitratordelay) > 200) { severity = 1; } - if (MAX(localdelay, arbitratordelay) > 400) + if (max(localdelay, arbitratordelay) > 400) { severity = 2; } - if (MAX(localdelay, arbitratordelay) >= ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE)) + if (max(localdelay, arbitratordelay) >= ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE)) { severity = 3; } @@ -2936,6 +2970,12 @@ int Net_GetLatency(int *ld, int *ad) return severity; } +//========================================================================== +// +// +// +//========================================================================== + // [RH] List "ping" times CCMD (pings) { @@ -2994,11 +3034,11 @@ static void Network_Controller (int playernum, bool add) } if (add) - Net_WriteByte (DEM_ADDCONTROLLER); + Net_WriteInt8 (DEM_ADDCONTROLLER); else - Net_WriteByte (DEM_DELCONTROLLER); + Net_WriteInt8 (DEM_DELCONTROLLER); - Net_WriteByte (playernum); + Net_WriteInt8 (playernum); } //========================================================================== diff --git a/src/d_net.h b/src/d_net.h index 352a01eb28f..e6a6a32b9fd 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -31,67 +31,7 @@ #include "doomtype.h" #include "doomdef.h" #include "d_protocol.h" - - -// -// Network play related stuff. -// There is a data struct that stores network -// communication related stuff, and another -// one that defines the actual packets to -// be transmitted. -// - -#define DOOMCOM_ID 0x12345678l -#define MAXNETNODES 8 // max computers in a game -#define BACKUPTICS 36 // number of tics to remember -#define MAXTICDUP 5 -#define LOCALCMDTICS (BACKUPTICS*MAXTICDUP) - - -#ifdef DJGPP -// The DOS drivers provide a pretty skimpy buffer. -// Probably not enough. -#define MAX_MSGLEN (BACKUPTICS*10) -#else -#define MAX_MSGLEN 14000 -#endif - -#define CMD_SEND 1 -#define CMD_GET 2 - -// -// Network packet data. -// -struct doomcom_t -{ - uint32_t id; // should be DOOMCOM_ID - int16_t intnum; // DOOM executes an int to execute commands - -// communication between DOOM and the driver - int16_t command; // CMD_SEND or CMD_GET - int16_t remotenode; // dest for send, set by get (-1 = no packet). - int16_t datalength; // bytes in doomdata to be sent - -// info common to all nodes - int16_t numnodes; // console is always node 0. - int16_t ticdup; // 1 = no duplication, 2-5 = dup for slow nets -#ifdef DJGPP - int16_t pad[5]; // keep things aligned for DOS drivers -#endif - -// info specific to this node - int16_t consoleplayer; - int16_t numplayers; -#ifdef DJGPP - int16_t angleoffset; // does not work, but needed to preserve - int16_t drone; // alignment for DOS drivers -#endif - -// packet data to be sent - uint8_t data[MAX_MSGLEN]; - -}; - +#include "i_net.h" class FDynamicBuffer { @@ -124,10 +64,12 @@ void Net_CheckLastReceived(int); // [RH] Functions for making and using special "ticcmds" void Net_NewMakeTic (); -void Net_WriteByte (uint8_t); -void Net_WriteWord (short); -void Net_WriteLong (int); +void Net_WriteInt8 (uint8_t); +void Net_WriteInt16 (int16_t); +void Net_WriteInt32 (int32_t); +void Net_WriteInt64(int64_t); void Net_WriteFloat (float); +void Net_WriteDouble(double); void Net_WriteString (const char *); void Net_WriteBytes (const uint8_t *, int len); @@ -153,6 +95,10 @@ extern int nodeforplayer[MAXPLAYERS]; extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; extern int ticdup; +class player_t; +class DObject; + + // [RH] // New generic packet structure: // diff --git a/src/d_netinf.h b/src/d_netinf.h index 34df4bcea71..56f955e0645 100644 --- a/src/d_netinf.h +++ b/src/d_netinf.h @@ -54,11 +54,11 @@ void D_SetupUserInfo (void); void D_UserInfoChanged (FBaseCVar *info); -void D_SendServerInfoChange (const FBaseCVar *cvar, UCVarValue value, ECVarType type); -void D_SendServerFlagChange (const FBaseCVar *cvar, int bitnum, bool set); +bool D_SendServerInfoChange (FBaseCVar *cvar, UCVarValue value, ECVarType type); +bool D_SendServerFlagChange (FBaseCVar *cvar, int bitnum, bool set, bool silent); void D_DoServerInfoChange (uint8_t **stream, bool singlebit); -void D_WriteUserInfoStrings (int player, uint8_t **stream, bool compact=false); +FString D_GetUserInfoStrings(int pnum, bool compact = false); void D_ReadUserInfoStrings (int player, uint8_t **stream, bool update); struct FPlayerColorSet; diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index e631c4e994f..bac6eddfe87 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -50,6 +50,7 @@ #include "serializer.h" #include "vm.h" #include "gstrings.h" +#include "g_game.h" static FRandom pr_pickteam ("PickRandomTeam"); @@ -62,10 +63,13 @@ CVAR (Int, team, TEAM_NONE, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, gender, "male", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Bool, neverswitchonpickup, false, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Float, movebob, 0.25f, CVAR_USERINFO | CVAR_ARCHIVE); +CVAR (Bool, fviewbob, true, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Float, stillbob, 0.f, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Float, wbobspeed, 1.f, CVAR_USERINFO | CVAR_ARCHIVE); +CVAR (Float, wbobfire, 0.f, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, playerclass, "Fighter", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Bool, classicflight, false, CVAR_USERINFO | CVAR_ARCHIVE); +CVAR (Bool, vertspread, false, CVAR_USERINFO | CVAR_ARCHIVE); enum { @@ -77,11 +81,14 @@ enum INFO_Gender, INFO_NeverSwitchOnPickup, INFO_MoveBob, + INFO_FViewBob, INFO_StillBob, INFO_WBobSpeed, + INFO_WBobFire, INFO_PlayerClass, INFO_ColorSet, INFO_ClassicFlight, + INFO_VertSpread, }; const char *GenderNames[GENDER_MAX] = { "male", "female", "neutral", "other" }; @@ -154,7 +161,7 @@ int D_PlayerClassToInt (const char *classname) { auto type = PlayerClasses[i].Type; - if (type->GetDisplayName().IsNotEmpty() && stricmp(type->GetDisplayName(), classname) == 0) + if (type->GetDisplayName().IsNotEmpty() && type->GetDisplayName().CompareNoCase(classname) == 0) { return i; } @@ -190,7 +197,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f, h, s, v); - if (teamplay && TeamLibrary.IsValidTeam((team = info->GetTeam())) && !Teams[team].GetAllowCustomPlayerColor()) + if (teamplay && FTeam::IsValid((team = info->GetTeam())) && !Teams[team].GetAllowCustomPlayerColor()) { // In team play, force the player to use the team's hue // and adjust the saturation and value so that the team @@ -257,7 +264,7 @@ int D_PickRandomTeam () if (playeringame[i]) { team = players[i].userinfo.GetTeam(); - if (TeamLibrary.IsValidTeam(team)) + if (FTeam::IsValid(team)) { if (Teams[team].m_iPresent++ == 0) { @@ -312,15 +319,15 @@ static void UpdateTeam (int pnum, int team, bool update) { userinfo_t *info = &players[pnum].userinfo; - if ((dmflags2 & DF2_NO_TEAM_SWITCH) && (alwaysapplydmflags || deathmatch) && TeamLibrary.IsValidTeam (info->GetTeam())) + if ((dmflags2 & DF2_NO_TEAM_SWITCH) && (alwaysapplydmflags || deathmatch) && FTeam::IsValid (info->GetTeam())) { - Printf ("%s\n", GStrings("TXT_NO_TEAM_CHANGE")); + Printf ("%s\n", GStrings.GetString("TXT_NO_TEAM_CHANGE")); return; } int oldteam; - if (!TeamLibrary.IsValidTeam (team)) + if (!FTeam::IsValid (team)) { team = TEAM_NONE; } @@ -330,14 +337,14 @@ static void UpdateTeam (int pnum, int team, bool update) if (update && oldteam != team) { FString message; - if (TeamLibrary.IsValidTeam (team)) + if (FTeam::IsValid (team)) { - message = GStrings("TXT_JOINED_TEAM"); + message = GStrings.GetString("TXT_JOINED_TEAM"); message.Substitute("%t", Teams[team].GetName()); } else { - message = GStrings("TXT_LONER"); + message = GStrings.GetString("TXT_LONER"); } message.Substitute("%s", info->GetName()); Printf("%s\n", message.GetChars()); @@ -349,7 +356,7 @@ static void UpdateTeam (int pnum, int team, bool update) StatusBar->AttachToPlayer (&players[pnum]); } // Double-check - if (!TeamLibrary.IsValidTeam (team)) + if (!FTeam::IsValid (team)) { *static_cast((*info)[NAME_Team]) = TEAM_NONE; } @@ -358,7 +365,7 @@ static void UpdateTeam (int pnum, int team, bool update) int D_GetFragCount (player_t *player) { const int team = player->userinfo.GetTeam(); - if (!teamplay || !TeamLibrary.IsValidTeam(team)) + if (!teamplay || !FTeam::IsValid(team)) { return player->fragcount; } @@ -386,13 +393,16 @@ void D_SetupUserInfo () // Reset everybody's userinfo to a default state. for (i = 0; i < MAXPLAYERS; i++) { - players[i].userinfo.Reset(); + players[i].userinfo.Reset(i); } // Initialize the console player's user info coninfo = &players[consoleplayer].userinfo; - for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) { + auto cvar = pair->Value; if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO) { FBaseCVar **newcvar; @@ -416,7 +426,7 @@ void D_SetupUserInfo () R_BuildPlayerTranslation(consoleplayer); } -void userinfo_t::Reset() +void userinfo_t::Reset(int pnum) { // Clear this player's userinfo. TMapIterator it(*this); @@ -429,8 +439,11 @@ void userinfo_t::Reset() Clear(); // Create userinfo vars for this player, initialized to their defaults. - for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) + decltype(cvarMap)::Iterator it2(cvarMap); + decltype(cvarMap)::Pair *pair2; + while (it2.NextPair(pair2)) { + auto cvar = pair2->Value; if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO) { ECVarType type; @@ -445,8 +458,20 @@ void userinfo_t::Reset() case NAME_PlayerClass: type = CVAR_Int; break; default: type = cvar->GetRealType(); break; } - newcvar = C_CreateCVar(NULL, type, cvar->GetFlags() & CVAR_MOD); + + int flags = cvar->GetFlags(); + + newcvar = C_CreateCVar(NULL, type, (flags & CVAR_MOD) | ((flags & CVAR_ZS_CUSTOM) << 1) ); newcvar->SetGenericRepDefault(cvar->GetGenericRepDefault(CVAR_String), CVAR_String); + + if(flags & CVAR_ZS_CUSTOM) + { + newcvar->SetExtraDataPointer(cvar); // store backing cvar + } + + newcvar->pnum = pnum; + newcvar->userinfoName = cvarname; + Insert(cvarname, newcvar); } } @@ -454,7 +479,7 @@ void userinfo_t::Reset() int userinfo_t::TeamChanged(int team) { - if (teamplay && !TeamLibrary.IsValidTeam(team)) + if (teamplay && !FTeam::IsValid(team)) { // Force players onto teams in teamplay mode team = D_PickRandomTeam(); } @@ -523,7 +548,8 @@ void D_UserInfoChanged (FBaseCVar *cvar) FString escaped_val; char foo[256]; - if (cvar == &autoaim) +#if 0 + if (cvar == autoaim->get()) { if (autoaim < 0.0f) { @@ -536,6 +562,7 @@ void D_UserInfoChanged (FBaseCVar *cvar) return; } } +#endif val = cvar->GetGenericRep (CVAR_String); escaped_val = D_EscapeUserInfo(val.String); @@ -544,7 +571,7 @@ void D_UserInfoChanged (FBaseCVar *cvar) mysnprintf (foo, countof(foo), "\\%s\\%s", cvar->GetName(), escaped_val.GetChars()); - Net_WriteByte (DEM_UINFCHANGED); + Net_WriteInt8 (DEM_UINFCHANGED); Net_WriteString (foo); } @@ -565,7 +592,7 @@ static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, b { return NULL; } - bitdata = ReadByte (stream); + bitdata = ReadInt8 (stream); mask = 1 << (bitdata & 31); if (bitdata & 32) { @@ -581,8 +608,8 @@ static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, b { switch (type) { - case CVAR_Bool: value.Bool = ReadByte (stream) ? 1 : 0; break; - case CVAR_Int: value.Int = ReadLong (stream); break; + case CVAR_Bool: value.Bool = ReadInt8 (stream) ? 1 : 0; break; + case CVAR_Int: value.Int = ReadInt32 (stream); break; case CVAR_Float: value.Float = ReadFloat (stream); break; case CVAR_String: value.String = ReadString (stream); break; default: break; // Silence GCC @@ -599,7 +626,8 @@ static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, b delete[] value.String; } - if (var == &teamplay) +#if 0 + if (var == teamplay->get()) { // Put players on teams if teamplay turned on for (int i = 0; i < MAXPLAYERS; ++i) @@ -610,6 +638,7 @@ static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, b } } } +#endif if (var) { @@ -622,35 +651,58 @@ static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, b EXTERN_CVAR (Float, sv_gravity) -void D_SendServerInfoChange (const FBaseCVar *cvar, UCVarValue value, ECVarType type) +bool D_SendServerInfoChange (FBaseCVar *cvar, UCVarValue value, ECVarType type) { - size_t namelen; + if (gamestate != GS_STARTUP && !demoplayback && !savegamerestore) + { + if (netgame && !players[consoleplayer].settings_controller) + { + Printf("Only setting controllers can change server CVAR %s\n", cvar->GetName()); + cvar->MarkSafe(); + return true; + } + size_t namelen; - namelen = strlen (cvar->GetName ()); + namelen = strlen(cvar->GetName()); - Net_WriteByte (DEM_SINFCHANGED); - Net_WriteByte ((uint8_t)(namelen | (type << 6))); - Net_WriteBytes ((uint8_t *)cvar->GetName (), (int)namelen); - switch (type) - { - case CVAR_Bool: Net_WriteByte (value.Bool); break; - case CVAR_Int: Net_WriteLong (value.Int); break; - case CVAR_Float: Net_WriteFloat (value.Float); break; - case CVAR_String: Net_WriteString (value.String); break; - default: break; // Silence GCC + Net_WriteInt8(DEM_SINFCHANGED); + Net_WriteInt8((uint8_t)(namelen | (type << 6))); + Net_WriteBytes((uint8_t*)cvar->GetName(), (int)namelen); + switch (type) + { + case CVAR_Bool: Net_WriteInt8(value.Bool); break; + case CVAR_Int: Net_WriteInt32(value.Int); break; + case CVAR_Float: Net_WriteFloat(value.Float); break; + case CVAR_String: Net_WriteString(value.String); break; + default: break; // Silence GCC + } + return true; } + return false; } -void D_SendServerFlagChange (const FBaseCVar *cvar, int bitnum, bool set) +bool D_SendServerFlagChange (FBaseCVar *cvar, int bitnum, bool set, bool silent) { - int namelen; + if (gamestate != GS_STARTUP && !demoplayback && !savegamerestore) + { + if (netgame && !players[consoleplayer].settings_controller) + { + if (!silent) + { + Printf("Only setting controllers can change server CVAR %s\n", cvar->GetName()); + } + return true; + } - namelen = (int)strlen (cvar->GetName ()); + int namelen = (int)strlen(cvar->GetName()); - Net_WriteByte (DEM_SINFCHANGEDXOR); - Net_WriteByte ((uint8_t)namelen); - Net_WriteBytes ((uint8_t *)cvar->GetName (), namelen); - Net_WriteByte (uint8_t(bitnum | (set << 5))); + Net_WriteInt8(DEM_SINFCHANGEDXOR); + Net_WriteInt8((uint8_t)namelen); + Net_WriteBytes((uint8_t*)cvar->GetName(), namelen); + Net_WriteInt8(uint8_t(bitnum | (set << 5))); + return true; + } + return false; } void D_DoServerInfoChange (uint8_t **stream, bool singlebit) @@ -660,7 +712,7 @@ void D_DoServerInfoChange (uint8_t **stream, bool singlebit) int len; int type; - len = ReadByte (stream); + len = ReadInt8 (stream); type = len >> 6; len &= 0x3f; if (len == 0) @@ -689,67 +741,65 @@ static int namesortfunc(const void *a, const void *b) return stricmp(name1->GetChars(), name2->GetChars()); } -void D_WriteUserInfoStrings (int pnum, uint8_t **stream, bool compact) +FString D_GetUserInfoStrings(int pnum, bool compact) { - if (pnum >= MAXPLAYERS) - { - WriteByte (0, stream); - return; - } - - userinfo_t *info = &players[pnum].userinfo; - TArray::Pair *> userinfo_pairs(info->CountUsed()); - TMap::Iterator it(*info); - TMap::Pair *pair; - UCVarValue cval; - - // Create a simple array of all userinfo cvars - while (it.NextPair(pair)) - { - userinfo_pairs.Push(pair); - } - // For compact mode, these need to be sorted. Verbose mode doesn't matter. - if (compact) - { - qsort(&userinfo_pairs[0], userinfo_pairs.Size(), sizeof(pair), userinfosortfunc); - // Compact mode is signified by starting the string with two backslash characters. - // We output one now. The second will be output as part of the first value. - *(*stream)++ = '\\'; - } - for (unsigned int i = 0; i < userinfo_pairs.Size(); ++i) + FString result; + if (pnum >= 0 && pnum < MAXPLAYERS) { - pair = userinfo_pairs[i]; + userinfo_t* info = &players[pnum].userinfo; + TArray::Pair*> userinfo_pairs(info->CountUsed()); + TMap::Iterator it(*info); + TMap::Pair* pair; + UCVarValue cval; - if (!compact) - { // In verbose mode, prepend the cvar's name - *stream += sprintf(*((char **)stream), "\\%s", pair->Key.GetChars()); + // Create a simple array of all userinfo cvars + while (it.NextPair(pair)) + { + userinfo_pairs.Push(pair); + } + // For compact mode, these need to be sorted. Verbose mode doesn't matter. + if (compact) + { + qsort(&userinfo_pairs[0], userinfo_pairs.Size(), sizeof(pair), userinfosortfunc); + // Compact mode is signified by starting the string with two backslash characters. + // We output one now. The second will be output as part of the first value. + result += '\\'; } - // A few of these need special handling for compatibility reasons. - switch (pair->Key.GetIndex()) + for (unsigned int i = 0; i < userinfo_pairs.Size(); ++i) { - case NAME_Gender: - *stream += sprintf(*((char **)stream), "\\%s", - *static_cast(pair->Value) == GENDER_FEMALE ? "female" : - *static_cast(pair->Value) == GENDER_NEUTER ? "neutral" : - *static_cast(pair->Value) == GENDER_OBJECT ? "other" : "male"); - break; - - case NAME_PlayerClass: - *stream += sprintf(*((char **)stream), "\\%s", info->GetPlayerClassNum() == -1 ? "Random" : - D_EscapeUserInfo(info->GetPlayerClassType()->GetDisplayName().GetChars()).GetChars()); - break; - - case NAME_Skin: - *stream += sprintf(*((char **)stream), "\\%s", D_EscapeUserInfo(Skins[info->GetSkin()].Name).GetChars()); - break; - - default: - cval = pair->Value->GetGenericRep(CVAR_String); - *stream += sprintf(*((char **)stream), "\\%s", cval.String); - break; + pair = userinfo_pairs[i]; + + if (!compact) + { // In verbose mode, prepend the cvar's name + result.AppendFormat("\\%s", pair->Key.GetChars()); + } + // A few of these need special handling for compatibility reasons. + switch (pair->Key.GetIndex()) + { + case NAME_Gender: + result.AppendFormat("\\%s", + *static_cast(pair->Value) == GENDER_FEMALE ? "female" : + *static_cast(pair->Value) == GENDER_NEUTER ? "neutral" : + *static_cast(pair->Value) == GENDER_OBJECT ? "other" : "male"); + break; + + case NAME_PlayerClass: + result.AppendFormat("\\%s", info->GetPlayerClassNum() == -1 ? "Random" : + D_EscapeUserInfo(info->GetPlayerClassType()->GetDisplayName().GetChars()).GetChars()); + break; + + case NAME_Skin: + result.AppendFormat("\\%s", D_EscapeUserInfo(Skins[info->GetSkin()].Name.GetChars()).GetChars()); + break; + + default: + cval = pair->Value->GetGenericRep(CVAR_String); + result.AppendFormat("\\%s", cval.String); + break; + } } } - *(*stream)++ = '\0'; + return result; } void D_ReadUserInfoStrings (int pnum, uint8_t **stream, bool update) @@ -820,18 +870,18 @@ void D_ReadUserInfoStrings (int pnum, uint8_t **stream, bool update) } // A few of these need special handling. - switch (keyname) + switch (keyname.GetIndex()) { case NAME_Gender: - info->GenderChanged(value); + info->GenderChanged(value.GetChars()); break; case NAME_PlayerClass: - info->PlayerClassChanged(value); + info->PlayerClassChanged(value.GetChars()); break; case NAME_Skin: - info->SkinChanged(value, players[pnum].CurrentPlayerClass); + info->SkinChanged(value.GetChars(), players[pnum].CurrentPlayerClass); if (players[pnum].mo != NULL) { if (players[pnum].cls != NULL && @@ -848,11 +898,11 @@ void D_ReadUserInfoStrings (int pnum, uint8_t **stream, bool update) break; case NAME_Team: - UpdateTeam(pnum, atoi(value), update); + UpdateTeam(pnum, atoi(value.GetChars()), update); break; case NAME_Color: - info->ColorChanged(value); + info->ColorChanged(value.GetChars()); break; default: @@ -904,12 +954,12 @@ void WriteUserInfo(FSerializer &arc, userinfo_t &info) while (it.NextPair(pair)) { - name = pair->Key; + name = pair->Key.GetChars(); name.ToLower(); switch (pair->Key.GetIndex()) { case NAME_Skin: - string = Skins[info.GetSkin()].Name; + string = Skins[info.GetSkin()].Name.GetChars(); break; case NAME_PlayerClass: @@ -922,7 +972,7 @@ void WriteUserInfo(FSerializer &arc, userinfo_t &info) string = val.String; break; } - arc.StringPtr(name, string); + arc.StringPtr(name.GetChars(), string); } arc.EndObject(); } @@ -934,7 +984,6 @@ void ReadUserInfo(FSerializer &arc, userinfo_t &info, FString &skin) const char *key; const char *str; - info.Reset(); skin = ""; if (arc.BeginObject("userinfo")) { @@ -945,7 +994,7 @@ void ReadUserInfo(FSerializer &arc, userinfo_t &info, FString &skin) FBaseCVar **cvar = info.CheckKey(name); if (cvar != NULL && *cvar != NULL) { - switch (name) + switch (name.GetIndex()) { case NAME_Team: info.TeamChanged(atoi(str)); break; case NAME_Skin: skin = str; break; // Caller must call SkinChanged() once current calss is known diff --git a/src/d_protocol.cpp b/src/d_protocol.cpp index 10794197682..ec1750a12e4 100644 --- a/src/d_protocol.cpp +++ b/src/d_protocol.cpp @@ -55,35 +55,54 @@ const char *ReadStringConst(uint8_t **stream) return string; } -int ReadByte (uint8_t **stream) +uint8_t ReadInt8 (uint8_t **stream) { uint8_t v = **stream; *stream += 1; return v; } -int ReadWord (uint8_t **stream) +int16_t ReadInt16 (uint8_t **stream) { - short v = (((*stream)[0]) << 8) | (((*stream)[1])); + int16_t v = (((*stream)[0]) << 8) | (((*stream)[1])); *stream += 2; return v; } -int ReadLong (uint8_t **stream) +int32_t ReadInt32 (uint8_t **stream) { - int v = (((*stream)[0]) << 24) | (((*stream)[1]) << 16) | (((*stream)[2]) << 8) | (((*stream)[3])); + int32_t v = (((*stream)[0]) << 24) | (((*stream)[1]) << 16) | (((*stream)[2]) << 8) | (((*stream)[3])); *stream += 4; return v; } +int64_t ReadInt64(uint8_t** stream) +{ + int64_t v = (int64_t((*stream)[0]) << 56) | (int64_t((*stream)[1]) << 48) | (int64_t((*stream)[2]) << 40) | (int64_t((*stream)[3]) << 32) + | (int64_t((*stream)[4]) << 24) | (int64_t((*stream)[5]) << 16) | (int64_t((*stream)[6]) << 8) | (int64_t((*stream)[7])); + *stream += 8; + return v; +} + float ReadFloat (uint8_t **stream) { union { - int i; + int32_t i; float f; } fakeint; - fakeint.i = ReadLong (stream); + fakeint.i = ReadInt32 (stream); + return fakeint.f; +} + +double ReadDouble(uint8_t** stream) +{ + union + { + int64_t i; + double f; + } fakeint; + fakeint.i = ReadInt64(stream); return fakeint.f; } @@ -100,20 +119,20 @@ void WriteString (const char *string, uint8_t **stream) } -void WriteByte (uint8_t v, uint8_t **stream) +void WriteInt8 (uint8_t v, uint8_t **stream) { **stream = v; *stream += 1; } -void WriteWord (short v, uint8_t **stream) +void WriteInt16 (int16_t v, uint8_t **stream) { (*stream)[0] = v >> 8; (*stream)[1] = v & 255; *stream += 2; } -void WriteLong (int v, uint8_t **stream) +void WriteInt32 (int32_t v, uint8_t **stream) { (*stream)[0] = v >> 24; (*stream)[1] = (v >> 16) & 255; @@ -122,15 +141,39 @@ void WriteLong (int v, uint8_t **stream) *stream += 4; } +void WriteInt64(int64_t v, uint8_t** stream) +{ + (*stream)[0] = v >> 56; + (*stream)[1] = (v >> 48) & 255; + (*stream)[2] = (v >> 40) & 255; + (*stream)[3] = (v >> 32) & 255; + (*stream)[4] = (v >> 24) & 255; + (*stream)[5] = (v >> 16) & 255; + (*stream)[6] = (v >> 8) & 255; + (*stream)[7] = v & 255; + *stream += 8; +} + void WriteFloat (float v, uint8_t **stream) { union { - int i; + int32_t i; float f; } fakeint; fakeint.f = v; - WriteLong (fakeint.i, stream); + WriteInt32 (fakeint.i, stream); +} + +void WriteDouble(double v, uint8_t** stream) +{ + union + { + int64_t i; + double f; + } fakeint; + fakeint.f = v; + WriteInt64(fakeint.i, stream); } // Returns the number of bytes read @@ -151,7 +194,7 @@ int UnpackUserCmd (usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stream) memset (ucmd, 0, sizeof(usercmd_t)); } - flags = ReadByte (stream); + flags = ReadInt8 (stream); if (flags) { @@ -159,20 +202,20 @@ int UnpackUserCmd (usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stream) if (flags & UCMDF_BUTTONS) { uint32_t buttons = ucmd->buttons; - uint8_t in = ReadByte(stream); + uint8_t in = ReadInt8(stream); buttons = (buttons & ~0x7F) | (in & 0x7F); if (in & 0x80) { - in = ReadByte(stream); + in = ReadInt8(stream); buttons = (buttons & ~(0x7F << 7)) | ((in & 0x7F) << 7); if (in & 0x80) { - in = ReadByte(stream); + in = ReadInt8(stream); buttons = (buttons & ~(0x7F << 14)) | ((in & 0x7F) << 14); if (in & 0x80) { - in = ReadByte(stream); + in = ReadInt8(stream); buttons = (buttons & ~(0xFF << 21)) | (in << 21); } } @@ -180,17 +223,17 @@ int UnpackUserCmd (usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stream) ucmd->buttons = buttons; } if (flags & UCMDF_PITCH) - ucmd->pitch = ReadWord (stream); + ucmd->pitch = ReadInt16 (stream); if (flags & UCMDF_YAW) - ucmd->yaw = ReadWord (stream); + ucmd->yaw = ReadInt16 (stream); if (flags & UCMDF_FORWARDMOVE) - ucmd->forwardmove = ReadWord (stream); + ucmd->forwardmove = ReadInt16 (stream); if (flags & UCMDF_SIDEMOVE) - ucmd->sidemove = ReadWord (stream); + ucmd->sidemove = ReadInt16 (stream); if (flags & UCMDF_UPMOVE) - ucmd->upmove = ReadWord (stream); + ucmd->upmove = ReadInt16 (stream); if (flags & UCMDF_ROLL) - ucmd->roll = ReadWord (stream); + ucmd->roll = ReadInt16 (stream); } return int(*stream - start); @@ -211,7 +254,7 @@ int PackUserCmd (const usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stream basis = ␣ } - WriteByte (0, stream); // Make room for the packing bits + WriteInt8 (0, stream); // Make room for the packing bits buttons_changed = ucmd->buttons ^ basis->buttons; if (buttons_changed != 0) @@ -235,16 +278,16 @@ int PackUserCmd (const usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stream } } } - WriteByte (bytes[0], stream); + WriteInt8 (bytes[0], stream); if (bytes[0] & 0x80) { - WriteByte (bytes[1], stream); + WriteInt8 (bytes[1], stream); if (bytes[1] & 0x80) { - WriteByte (bytes[2], stream); + WriteInt8 (bytes[2], stream); if (bytes[2] & 0x80) { - WriteByte (bytes[3], stream); + WriteInt8 (bytes[3], stream); } } } @@ -252,36 +295,36 @@ int PackUserCmd (const usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stream if (ucmd->pitch != basis->pitch) { flags |= UCMDF_PITCH; - WriteWord (ucmd->pitch, stream); + WriteInt16 (ucmd->pitch, stream); } if (ucmd->yaw != basis->yaw) { flags |= UCMDF_YAW; - WriteWord (ucmd->yaw, stream); + WriteInt16 (ucmd->yaw, stream); } if (ucmd->forwardmove != basis->forwardmove) { flags |= UCMDF_FORWARDMOVE; - WriteWord (ucmd->forwardmove, stream); + WriteInt16 (ucmd->forwardmove, stream); } if (ucmd->sidemove != basis->sidemove) { flags |= UCMDF_SIDEMOVE; - WriteWord (ucmd->sidemove, stream); + WriteInt16 (ucmd->sidemove, stream); } if (ucmd->upmove != basis->upmove) { flags |= UCMDF_UPMOVE; - WriteWord (ucmd->upmove, stream); + WriteInt16 (ucmd->upmove, stream); } if (ucmd->roll != basis->roll) { flags |= UCMDF_ROLL; - WriteWord (ucmd->roll, stream); + WriteInt16 (ucmd->roll, stream); } // Write the packing bits - WriteByte (flags, &temp); + WriteInt8 (flags, &temp); return int(*stream - start); } @@ -329,7 +372,7 @@ int WriteUserCmdMessage (usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stre ucmd->upmove != 0 || ucmd->roll != 0) { - WriteByte (DEM_USERCMD, stream); + WriteInt8 (DEM_USERCMD, stream); return PackUserCmd (ucmd, basis, stream) + 1; } } @@ -342,11 +385,11 @@ int WriteUserCmdMessage (usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stre ucmd->upmove != basis->upmove || ucmd->roll != basis->roll) { - WriteByte (DEM_USERCMD, stream); + WriteInt8 (DEM_USERCMD, stream); return PackUserCmd (ucmd, basis, stream) + 1; } - WriteByte (DEM_EMPTYUSERCMD, stream); + WriteInt8 (DEM_EMPTYUSERCMD, stream); return 1; } @@ -417,11 +460,11 @@ void ReadTicCmd (uint8_t **stream, int player, int tic) int ticmod = tic % BACKUPTICS; tcmd = &netcmds[player][ticmod]; - tcmd->consistancy = ReadWord (stream); + tcmd->consistancy = ReadInt16 (stream); start = *stream; - while ((type = ReadByte (stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD) + while ((type = ReadInt8 (stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD) Net_SkipCommand (type, stream); NetSpecs[player][ticmod].SetData (start, int(*stream - start - 1)); @@ -460,7 +503,7 @@ void RunNetSpecs (int player, int buf) uint8_t *end = stream + len; while (stream < end) { - int type = ReadByte (&stream); + int type = ReadInt8 (&stream); Net_DoCommand (type, &stream, player); } if (!demorecording) @@ -475,7 +518,7 @@ uint8_t *lenspot; // for the length field. void StartChunk (int id, uint8_t **stream) { - WriteLong (id, stream); + WriteInt32 (id, stream); lenspot = *stream; *stream += 4; } @@ -490,9 +533,9 @@ void FinishChunk (uint8_t **stream) return; len = int(*stream - lenspot - 4); - WriteLong (len, &lenspot); + WriteInt32 (len, &lenspot); if (len & 1) - WriteByte (0, stream); + WriteInt8 (0, stream); lenspot = NULL; } @@ -503,6 +546,6 @@ void SkipChunk (uint8_t **stream) { int len; - len = ReadLong (stream); + len = ReadInt32 (stream); *stream += len + (len & 1); } diff --git a/src/d_protocol.h b/src/d_protocol.h index ddae331a609..f726a6ef2f8 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -162,6 +162,9 @@ enum EDemoCommand DEM_NETEVENT, // 70 String: Event name, Byte: Arg count; each arg is a 4-byte int DEM_MDK, // 71 String: Damage type DEM_SETINV, // 72 SetInventory + DEM_ENDSCREENJOB, + DEM_ZSC_CMD, // 74 String: Command, Word: Byte size of command + DEM_CHANGESKILL, // 75 Int: Skill }; // The following are implemented by cht_DoCheat in m_cheat.cpp @@ -245,16 +248,20 @@ int SkipTicCmd (uint8_t **stream, int count); void ReadTicCmd (uint8_t **stream, int player, int tic); void RunNetSpecs (int player, int buf); -int ReadByte (uint8_t **stream); -int ReadWord (uint8_t **stream); -int ReadLong (uint8_t **stream); +uint8_t ReadInt8 (uint8_t **stream); +int16_t ReadInt16 (uint8_t **stream); +int32_t ReadInt32 (uint8_t **stream); +int64_t ReadInt64(uint8_t** stream); float ReadFloat (uint8_t **stream); +double ReadDouble(uint8_t** stream); char *ReadString (uint8_t **stream); const char *ReadStringConst(uint8_t **stream); -void WriteByte (uint8_t val, uint8_t **stream); -void WriteWord (short val, uint8_t **stream); -void WriteLong (int val, uint8_t **stream); +void WriteInt8 (uint8_t val, uint8_t **stream); +void WriteInt16 (int16_t val, uint8_t **stream); +void WriteInt32 (int32_t val, uint8_t **stream); +void WriteInt64(int64_t val, uint8_t** stream); void WriteFloat (float val, uint8_t **stream); +void WriteDouble(double val, uint8_t** stream); void WriteString (const char *string, uint8_t **stream); #endif //__D_PROTOCOL_H__ diff --git a/src/dobject.cpp b/src/dobject.cpp deleted file mode 100644 index e1ebc654b41..00000000000 --- a/src/dobject.cpp +++ /dev/null @@ -1,611 +0,0 @@ -/* -** dobject.cpp -** Implements the base class DObject, which most other classes derive from -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include - -#include "cmdlib.h" -#include "actor.h" -#include "doomstat.h" // Ideally, DObjects can be used independant of Doom. -#include "d_player.h" // See p_user.cpp to find out why this doesn't work. -#include "c_dispatch.h" -#include "dsectoreffect.h" -#include "serializer.h" -#include "vm.h" -#include "g_levellocals.h" -#include "types.h" -#include "i_time.h" - -//========================================================================== -// -// -// -//========================================================================== - -ClassReg DObject::RegistrationInfo = -{ - nullptr, // MyClass - "DObject", // Name - nullptr, // ParentType - nullptr, - nullptr, // Pointers - &DObject::InPlaceConstructor, // ConstructNative - nullptr, - sizeof(DObject), // SizeOf -}; -_DECLARE_TI(DObject) - -// This bit is needed in the playsim - but give it a less crappy name. -DEFINE_FIELD_BIT(DObject,ObjectFlags, bDestroyed, OF_EuthanizeMe) - -//========================================================================== -// -// -// -//========================================================================== - -CCMD (dumpactors) -{ - const char *const filters[32] = - { - "0:All", "1:Doom", "2:Heretic", "3:DoomHeretic", "4:Hexen", "5:DoomHexen", "6:Raven", "7:IdRaven", - "8:Strife", "9:DoomStrife", "10:HereticStrife", "11:DoomHereticStrife", "12:HexenStrife", - "13:DoomHexenStrife", "14:RavenStrife", "15:NotChex", "16:Chex", "17:DoomChex", "18:HereticChex", - "19:DoomHereticChex", "20:HexenChex", "21:DoomHexenChex", "22:RavenChex", "23:NotStrife", "24:StrifeChex", - "25:DoomStrifeChex", "26:HereticStrifeChex", "27:NotHexen", "28:HexenStrifeChex", "29:NotHeretic", - "30:NotDoom", "31:All", - }; - Printf("%u object class types total\nActor\tEd Num\tSpawnID\tFilter\tSource\n", PClass::AllClasses.Size()); - for (unsigned int i = 0; i < PClass::AllClasses.Size(); i++) - { - PClass *cls = PClass::AllClasses[i]; - PClassActor *acls = ValidateActor(cls); - if (acls != NULL) - { - auto ainfo = acls->ActorInfo(); - Printf("%s\t%i\t%i\t%s\t%s\n", - acls->TypeName.GetChars(), ainfo->DoomEdNum, - ainfo->SpawnID, filters[ainfo->GameFilter & 31], - acls->SourceLumpName.GetChars()); - } - else if (cls != NULL) - { - Printf("%s\tn/a\tn/a\tn/a\tEngine (not an actor type)\tSource: %s\n", cls->TypeName.GetChars(), cls->SourceLumpName.GetChars()); - } - else - { - Printf("Type %i is not an object class\n", i); - } - } -} - -//========================================================================== -// -// -// -//========================================================================== - -CCMD (dumpclasses) -{ - // This is by no means speed-optimized. But it's an informational console - // command that will be executed infrequently, so I don't mind. - struct DumpInfo - { - const PClass *Type; - DumpInfo *Next; - DumpInfo *Children; - - static DumpInfo *FindType (DumpInfo *root, const PClass *type) - { - if (root == NULL) - { - return root; - } - if (root->Type == type) - { - return root; - } - if (root->Next != NULL) - { - return FindType (root->Next, type); - } - if (root->Children != NULL) - { - return FindType (root->Children, type); - } - return NULL; - } - - static DumpInfo *AddType (DumpInfo **root, const PClass *type) - { - DumpInfo *info, *parentInfo; - - if (*root == NULL) - { - info = new DumpInfo; - info->Type = type; - info->Next = NULL; - info->Children = *root; - *root = info; - return info; - } - if (type->ParentClass == (*root)->Type) - { - parentInfo = *root; - } - else if (type == (*root)->Type) - { - return *root; - } - else - { - parentInfo = FindType (*root, type->ParentClass); - if (parentInfo == NULL) - { - parentInfo = AddType (root, type->ParentClass); - } - } - // Has this type already been added? - for (info = parentInfo->Children; info != NULL; info = info->Next) - { - if (info->Type == type) - { - return info; - } - } - info = new DumpInfo; - info->Type = type; - info->Next = parentInfo->Children; - info->Children = NULL; - parentInfo->Children = info; - return info; - } - - static void PrintTree (DumpInfo *root, int level) - { - Printf ("%*c%s\n", level, ' ', root->Type->TypeName.GetChars()); - if (root->Children != NULL) - { - PrintTree (root->Children, level + 2); - } - if (root->Next != NULL) - { - PrintTree (root->Next, level); - } - } - - static void FreeTree (DumpInfo *root) - { - if (root->Children != NULL) - { - FreeTree (root->Children); - } - if (root->Next != NULL) - { - FreeTree (root->Next); - } - delete root; - } - }; - - unsigned int i; - int shown, omitted; - DumpInfo *tree = NULL; - const PClass *root = NULL; - - if (argv.argc() > 1) - { - root = PClass::FindClass (argv[1]); - if (root == NULL) - { - Printf ("Class '%s' not found\n", argv[1]); - return; - } - } - - shown = omitted = 0; - DumpInfo::AddType (&tree, root != NULL ? root : RUNTIME_CLASS(DObject)); - for (i = 0; i < PClass::AllClasses.Size(); i++) - { - PClass *cls = PClass::AllClasses[i]; - if (root == NULL || cls == root || cls->IsDescendantOf(root)) - { - DumpInfo::AddType (&tree, cls); -// Printf (" %s\n", PClass::m_Types[i]->Name + 1); - shown++; - } - else - { - omitted++; - } - } - DumpInfo::PrintTree (tree, 2); - DumpInfo::FreeTree (tree); - Printf ("%d classes shown, %d omitted\n", shown, omitted); -} - -//========================================================================== -// -// -// -//========================================================================== - -void DObject::InPlaceConstructor (void *mem) -{ - new ((EInPlace *)mem) DObject; -} - -DObject::DObject () -: Class(0), ObjectFlags(0) -{ - ObjectFlags = GC::CurrentWhite & OF_WhiteBits; - ObjNext = GC::Root; - GCNext = nullptr; - GC::Root = this; -} - -DObject::DObject (PClass *inClass) -: Class(inClass), ObjectFlags(0) -{ - ObjectFlags = GC::CurrentWhite & OF_WhiteBits; - ObjNext = GC::Root; - GCNext = nullptr; - GC::Root = this; -} - -//========================================================================== -// -// -// -//========================================================================== - -DObject::~DObject () -{ - if (!PClass::bShutdown) - { - PClass *type = GetClass(); - if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) - { - if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released))) - { - Printf("Warning: '%s' is freed outside the GC process.\n", - type != NULL ? type->TypeName.GetChars() : "==some object=="); - } - - if (!(ObjectFlags & OF_Released)) - { - // Find all pointers that reference this object and NULL them. - Release(); - } - } - - if (nullptr != type) - { - type->DestroySpecials(this); - } - } -} - -void DObject::Release() -{ - DObject **probe; - - // Unlink this object from the GC list. - for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) - { - if (*probe == this) - { - *probe = ObjNext; - if (&ObjNext == GC::SweepPos) - { - GC::SweepPos = probe; - } - break; - } - } - - // If it's gray, also unlink it from the gray list. - if (this->IsGray()) - { - for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) - { - if (*probe == this) - { - *probe = GCNext; - break; - } - } - } - ObjNext = nullptr; - GCNext = nullptr; - ObjectFlags |= OF_Released; -} - -//========================================================================== -// -// -// -//========================================================================== - -void DObject:: Destroy () -{ - // We cannot call the VM during shutdown because all the needed data has been or is in the process of being deleted. - if (PClass::bVMOperational) - { - IFVIRTUAL(DObject, OnDestroy) - { - VMValue params[1] = { (DObject*)this }; - VMCall(func, params, 1, nullptr, 0); - } - } - OnDestroy(); - ObjectFlags = (ObjectFlags & ~OF_Fixed) | OF_EuthanizeMe; -} - -DEFINE_ACTION_FUNCTION(DObject, Destroy) -{ - PARAM_SELF_PROLOGUE(DObject); - self->Destroy(); - return 0; -} - -//========================================================================== -// -// -// -//========================================================================== - -size_t DObject::PropagateMark() -{ - const PClass *info = GetClass(); - if (!PClass::bShutdown) - { - const size_t *offsets = info->FlatPointers; - if (offsets == NULL) - { - const_cast(info)->BuildFlatPointers(); - offsets = info->FlatPointers; - } - while (*offsets != ~(size_t)0) - { - GC::Mark((DObject **)((uint8_t *)this + *offsets)); - offsets++; - } - - offsets = info->ArrayPointers; - if (offsets == NULL) - { - const_cast(info)->BuildArrayPointers(); - offsets = info->ArrayPointers; - } - while (*offsets != ~(size_t)0) - { - auto aray = (TArray*)((uint8_t *)this + *offsets); - for (auto &p : *aray) - { - GC::Mark(&p); - } - offsets++; - } - - return info->Size; - } - return 0; -} - -//========================================================================== -// -// -// -//========================================================================== - -size_t DObject::PointerSubstitution (DObject *old, DObject *notOld) -{ - const PClass *info = GetClass(); - const size_t *offsets = info->FlatPointers; - size_t changed = 0; - if (offsets == NULL) - { - const_cast(info)->BuildFlatPointers(); - offsets = info->FlatPointers; - } - while (*offsets != ~(size_t)0) - { - if (*(DObject **)((uint8_t *)this + *offsets) == old) - { - *(DObject **)((uint8_t *)this + *offsets) = notOld; - changed++; - } - offsets++; - } - - offsets = info->ArrayPointers; - if (offsets == NULL) - { - const_cast(info)->BuildArrayPointers(); - offsets = info->ArrayPointers; - } - while (*offsets != ~(size_t)0) - { - auto aray = (TArray*)((uint8_t *)this + *offsets); - for (auto &p : *aray) - { - if (p == old) - { - p = notOld; - changed++; - } - } - offsets++; - } - - - return changed; -} - -//========================================================================== -// -// This once was the main method for pointer cleanup, but -// nowadays its only use is swapping out PlayerPawns. -// This requires pointer fixing throughout all objects and a few -// global variables, but it only needs to look at pointers that -// can point to a player. -// -//========================================================================== - -void DObject::StaticPointerSubstitution (AActor *old, AActor *notOld) -{ - DObject *probe; - size_t changed = 0; - int i; - - if (old == nullptr) return; - - // This is only allowed to replace players. For everything else the results are undefined. - if (!old->IsKindOf(NAME_PlayerPawn) || (notOld != nullptr && !notOld->IsKindOf(NAME_PlayerPawn))) return; - - // Go through all objects. - i = 0;DObject *last=0; - for (probe = GC::Root; probe != NULL; probe = probe->ObjNext) - { - i++; - changed += probe->PointerSubstitution(old, notOld); - last = probe; - } - - // Go through players. - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - { - AActor *replacement = notOld; - auto &p = players[i]; - - if (p.mo == old) p.mo = replacement, changed++; - if (p.poisoner.pp == old) p.poisoner = replacement, changed++; - if (p.attacker.pp == old) p.attacker = replacement, changed++; - if (p.camera.pp == old) p.camera = replacement, changed++; - if (p.ConversationNPC.pp == old) p.ConversationNPC = replacement, changed++; - if (p.ConversationPC == old) p.ConversationPC = replacement, changed++; - } - } - - // Go through sectors. Only the level this actor belongs to is relevant. - for (auto &sec : old->Level->sectors) - { - if (sec.SoundTarget == old) sec.SoundTarget = notOld; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void DObject::SerializeUserVars(FSerializer &arc) -{ - if (arc.isWriting()) - { - // Write all fields that aren't serialized by native code. - GetClass()->WriteAllFields(arc, this); - } - else - { - GetClass()->ReadAllFields(arc, this); - } -} - - -//========================================================================== -// -// -// -//========================================================================== - -void DObject::Serialize(FSerializer &arc) -{ - const auto SerializeFlag = [&](const char *const name, const EObjectFlags flag) - { - int value = ObjectFlags & flag; - int defaultvalue = 0; - arc(name, value, defaultvalue); - if (arc.isReading()) - { - ObjectFlags |= value; - } - }; - - SerializeFlag("justspawned", OF_JustSpawned); - SerializeFlag("spawned", OF_Spawned); - - ObjectFlags |= OF_SerialSuccess; -} - -void DObject::CheckIfSerialized () const -{ - if (!(ObjectFlags & OF_SerialSuccess)) - { - I_Error ( - "BUG: %s::Serialize\n" - "(or one of its superclasses) needs to call\n" - "Super::Serialize\n", - StaticType()->TypeName.GetChars()); - } -} - - -DEFINE_ACTION_FUNCTION(DObject, MSTime) -{ - ACTION_RETURN_INT((uint32_t)I_msTime()); -} - -void *DObject::ScriptVar(FName field, PType *type) -{ - auto cls = GetClass(); - auto sym = dyn_cast(cls->FindSymbol(field, true)); - if (sym && (sym->Type == type || type == nullptr)) - { - if (!(sym->Flags & VARF_Meta)) - { - return (((char*)this) + sym->Offset); - } - else - { - return (cls->Meta + sym->Offset); - } - } - // This is only for internal use so I_Error is fine. - I_Error("Variable %s not found in %s\n", field.GetChars(), cls->TypeName.GetChars()); - return nullptr; -} diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp deleted file mode 100644 index bed2caa08f6..00000000000 --- a/src/dobjgc.cpp +++ /dev/null @@ -1,669 +0,0 @@ -/* -** dobjgc.cpp -** The garbage collector. Based largely on Lua's. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ -/****************************************************************************** -* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. -* -* 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. -******************************************************************************/ - -// HEADER FILES ------------------------------------------------------------ - -#include "dobject.h" -#include "templates.h" -#include "b_bot.h" -#include "p_local.h" -#include "g_game.h" -#include "a_sharedglobal.h" -#include "sbar.h" -#include "c_dispatch.h" -#include "s_sndseq.h" -#include "r_data/r_interpolate.h" -#include "doomstat.h" -#include "po_man.h" -#include "r_utility.h" -#include "menu/menu.h" -#include "intermission/intermission.h" -#include "g_levellocals.h" -#include "events.h" - -// MACROS ------------------------------------------------------------------ - -/* -@@ DEFAULT_GCPAUSE defines the default pause between garbage-collector cycles -@* as a percentage. -** CHANGE it if you want the GC to run faster or slower (higher values -** mean larger pauses which mean slower collection.) You can also change -** this value dynamically. -*/ -#define DEFAULT_GCPAUSE 150 // 150% (wait for memory to increase by half before next GC) - -/* -@@ DEFAULT_GCMUL defines the default speed of garbage collection relative to -@* memory allocation as a percentage. -** CHANGE it if you want to change the granularity of the garbage -** collection. (Higher values mean coarser collections. 0 represents -** infinity, where each step performs a full collection.) You can also -** change this value dynamically. -*/ -#define DEFAULT_GCMUL 400 // GC runs 'quadruple the speed' of memory allocation - -// Number of sectors to mark for each step. - -#define GCSTEPSIZE 1024u -#define GCSWEEPMAX 40 -#define GCSWEEPCOST 10 -#define GCFINALIZECOST 100 - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern DThinker *NextToThink; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -namespace GC -{ -size_t AllocBytes; -size_t Threshold; -size_t Estimate; -DObject *Gray; -DObject *Root; -DObject *SoftRoots; -DObject **SweepPos; -uint32_t CurrentWhite = OF_White0 | OF_Fixed; -EGCState State = GCS_Pause; -int Pause = DEFAULT_GCPAUSE; -int StepMul = DEFAULT_GCMUL; -int StepCount; -size_t Dept; -bool FinalGC; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// SetThreshold -// -// Sets the new threshold after a collection is finished. -// -//========================================================================== - -void SetThreshold() -{ - Threshold = (Estimate / 100) * Pause; -} - -//========================================================================== -// -// PropagateMark -// -// Marks the top-most gray object black and marks all objects it points to -// gray. -// -//========================================================================== - -size_t PropagateMark() -{ - DObject *obj = Gray; - assert(obj->IsGray()); - obj->Gray2Black(); - Gray = obj->GCNext; - return !(obj->ObjectFlags & OF_EuthanizeMe) ? obj->PropagateMark() : - obj->GetClass()->Size; -} - -//========================================================================== -// -// SweepList -// -// Runs a limited sweep on a list, returning the location where to resume -// the sweep at next time. (FIXME: Horrible Engrish in this description.) -// -//========================================================================== - -static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count) -{ - DObject *curr; - int deadmask = OtherWhite(); - size_t finalized = 0; - - while ((curr = *p) != NULL && count-- > 0) - { - if ((curr->ObjectFlags ^ OF_WhiteBits) & deadmask) // not dead? - { - assert(!curr->IsDead() || (curr->ObjectFlags & OF_Fixed)); - curr->MakeWhite(); // make it white (for next cycle) - p = &curr->ObjNext; - } - else // must erase 'curr' - { - assert(curr->IsDead()); - *p = curr->ObjNext; - if (!(curr->ObjectFlags & OF_EuthanizeMe)) - { // The object must be destroyed before it can be finalized. - // Note that thinkers must already have been destroyed. If they get here without - // having been destroyed first, it means they somehow became unattached from the - // thinker lists. If I don't maintain the invariant that all live thinkers must - // be in a thinker list, then I need to add write barriers for every time a - // thinker pointer is changed. This seems easier and perfectly reasonable, since - // a live thinker that isn't on a thinker list isn't much of a thinker. - - // However, this can happen during deletion of the thinker list while cleaning up - // from a savegame error so we can't assume that any thinker that gets here is an error. - - curr->Destroy(); - } - curr->ObjectFlags |= OF_Cleanup; - delete curr; - finalized++; - } - } - if (finalize_count != NULL) - { - *finalize_count = finalized; - } - return p; -} - -//========================================================================== -// -// Mark -// -// Mark a single object gray. -// -//========================================================================== - -void Mark(DObject **obj) -{ - DObject *lobj = *obj; - - //assert(lobj == nullptr || !(lobj->ObjectFlags & OF_Released)); - if (lobj != nullptr && !(lobj->ObjectFlags & OF_Released)) - { - if (lobj->ObjectFlags & OF_EuthanizeMe) - { - *obj = (DObject *)NULL; - } - else if (lobj->IsWhite()) - { - lobj->White2Gray(); - lobj->GCNext = Gray; - Gray = lobj; - } - } -} - -//========================================================================== -// -// MarkArray -// -// Mark an array of objects gray. -// -//========================================================================== - -void MarkArray(DObject **obj, size_t count) -{ - for (size_t i = 0; i < count; ++i) - { - Mark(obj[i]); - } -} - -//========================================================================== -// -// MarkRoot -// -// Mark the root set of objects. -// -//========================================================================== - -static void MarkRoot() -{ - int i; - - Gray = NULL; - Mark(StatusBar); - M_MarkMenus(); - Mark(DIntermissionController::CurrentIntermission); - Mark(staticEventManager.FirstEventHandler); - Mark(staticEventManager.LastEventHandler); - for (auto Level : AllLevels()) - Level->Mark(); - - // Mark players. - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - players[i].PropagateMark(); - } - // Mark sectors. - - for (auto Level : AllLevels()) - { - Level->Mark(); - } - // NextToThink must not be freed while thinkers are ticking. - Mark(NextToThink); - // Mark soft roots. - if (SoftRoots != NULL) - { - DObject **probe = &SoftRoots->ObjNext; - while (*probe != NULL) - { - DObject *soft = *probe; - probe = &soft->ObjNext; - if ((soft->ObjectFlags & (OF_Rooted | OF_EuthanizeMe)) == OF_Rooted) - { - Mark(soft); - } - } - } - // Time to propagate the marks. - State = GCS_Propagate; - StepCount = 0; -} - -//========================================================================== -// -// Atomic -// -// If there were any propagations that needed to be done atomicly, they -// would go here. It also sets things up for the sweep state. -// -//========================================================================== - -static void Atomic() -{ - // Flip current white - CurrentWhite = OtherWhite(); - SweepPos = &Root; - State = GCS_Sweep; - Estimate = AllocBytes; -} - -//========================================================================== -// -// SingleStep -// -// Performs one step of the collector. -// -//========================================================================== - -static size_t SingleStep() -{ - switch (State) - { - case GCS_Pause: - MarkRoot(); // Start a new collection - return 0; - - case GCS_Propagate: - if (Gray != NULL) - { - return PropagateMark(); - } - else - { // no more gray objects - Atomic(); // finish mark phase - return 0; - } - - case GCS_Sweep: { - size_t old = AllocBytes; - size_t finalize_count; - SweepPos = SweepList(SweepPos, GCSWEEPMAX, &finalize_count); - if (*SweepPos == NULL) - { // Nothing more to sweep? - State = GCS_Finalize; - } - //assert(old >= AllocBytes); - Estimate -= MAX(0, old - AllocBytes); - return (GCSWEEPMAX - finalize_count) * GCSWEEPCOST + finalize_count * GCFINALIZECOST; - } - - case GCS_Finalize: - State = GCS_Pause; // end collection - Dept = 0; - return 0; - - default: - assert(0); - return 0; - } -} - -//========================================================================== -// -// Step -// -// Performs enough single steps to cover GCSTEPSIZE * StepMul% bytes of -// memory. -// -//========================================================================== - -void Step() -{ - size_t lim = (GCSTEPSIZE/100) * StepMul; - size_t olim; - if (lim == 0) - { - lim = (~(size_t)0) / 2; // no limit - } - Dept += AllocBytes - Threshold; - do - { - olim = lim; - lim -= SingleStep(); - } while (olim > lim && State != GCS_Pause); - if (State != GCS_Pause) - { - if (Dept < GCSTEPSIZE) - { - Threshold = AllocBytes + GCSTEPSIZE; // - lim/StepMul - } - else - { - Dept -= GCSTEPSIZE; - Threshold = AllocBytes; - } - } - else - { - assert(AllocBytes >= Estimate); - SetThreshold(); - } - StepCount++; -} - -//========================================================================== -// -// FullGC -// -// Collects everything in one fell swoop. -// -//========================================================================== - -void FullGC() -{ - if (State <= GCS_Propagate) - { - // Reset sweep mark to sweep all elements (returning them to white) - SweepPos = &Root; - // Reset other collector lists - Gray = NULL; - State = GCS_Sweep; - } - // Finish any pending sweep phase - while (State != GCS_Finalize) - { - SingleStep(); - } - MarkRoot(); - while (State != GCS_Pause) - { - SingleStep(); - } - SetThreshold(); -} - -//========================================================================== -// -// Barrier -// -// Implements a write barrier to maintain the invariant that a black node -// never points to a white node by making the node pointed at gray. -// -//========================================================================== - -void Barrier(DObject *pointing, DObject *pointed) -{ - assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); - assert(pointed->IsWhite() && !pointed->IsDead()); - assert(State != GCS_Finalize && State != GCS_Pause); - assert(!(pointed->ObjectFlags & OF_Released)); // if a released object gets here, something must be wrong. - if (pointed->ObjectFlags & OF_Released) return; // don't do anything with non-GC'd objects. - // The invariant only needs to be maintained in the propagate state. - if (State == GCS_Propagate) - { - pointed->White2Gray(); - pointed->GCNext = Gray; - Gray = pointed; - } - // In other states, we can mark the pointing object white so this - // barrier won't be triggered again, saving a few cycles in the future. - else if (pointing != NULL) - { - pointing->MakeWhite(); - } -} - -void DelSoftRootHead() -{ - if (SoftRoots != NULL) - { - // Don't let the destructor print a warning message - SoftRoots->ObjectFlags |= OF_YesReallyDelete; - delete SoftRoots; - } - SoftRoots = NULL; -} - -//========================================================================== -// -// AddSoftRoot -// -// Marks an object as a soft root. A soft root behaves exactly like a root -// in MarkRoot, except it can be added at run-time. -// -//========================================================================== - -void AddSoftRoot(DObject *obj) -{ - DObject **probe; - - // Are there any soft roots yet? - if (SoftRoots == NULL) - { - // Create a new object to root the soft roots off of, and stick - // it at the end of the object list, so we know that anything - // before it is not a soft root. - SoftRoots = Create(); - SoftRoots->ObjectFlags |= OF_Fixed; - probe = &Root; - while (*probe != NULL) - { - probe = &(*probe)->ObjNext; - } - Root = SoftRoots->ObjNext; - SoftRoots->ObjNext = NULL; - *probe = SoftRoots; - } - // Mark this object as rooted and move it after the SoftRoots marker. - probe = &Root; - while (*probe != NULL && *probe != obj) - { - probe = &(*probe)->ObjNext; - } - *probe = (*probe)->ObjNext; - obj->ObjNext = SoftRoots->ObjNext; - SoftRoots->ObjNext = obj; - obj->ObjectFlags |= OF_Rooted; - WriteBarrier(obj); -} - -//========================================================================== -// -// DelSoftRoot -// -// Unroots an object so that it must be reachable or it will get collected. -// -//========================================================================== - -void DelSoftRoot(DObject *obj) -{ - DObject **probe; - - if (!(obj->ObjectFlags & OF_Rooted)) - { // Not rooted, so nothing to do. - return; - } - obj->ObjectFlags &= ~OF_Rooted; - // Move object out of the soft roots part of the list. - probe = &SoftRoots; - while (*probe != NULL && *probe != obj) - { - probe = &(*probe)->ObjNext; - } - if (*probe == obj) - { - *probe = obj->ObjNext; - obj->ObjNext = Root; - Root = obj; - } -} - -} - -//========================================================================== -// -// STAT gc -// -// Provides information about the current garbage collector state. -// -//========================================================================== - -ADD_STAT(gc) -{ - static const char *StateStrings[] = { - " Pause ", - "Propagate", - " Sweep ", - "Finalize " }; - FString out; - out.Format("[%s] Alloc:%6zuK Thresh:%6zuK Est:%6zuK Steps: %d", - StateStrings[GC::State], - (GC::AllocBytes + 1023) >> 10, - (GC::Threshold + 1023) >> 10, - (GC::Estimate + 1023) >> 10, - GC::StepCount); - if (GC::State != GC::GCS_Pause) - { - out.AppendFormat(" %zuK", (GC::Dept + 1023) >> 10); - } - return out; -} - -//========================================================================== -// -// CCMD gc -// -// Controls various aspects of the collector. -// -//========================================================================== - -CCMD(gc) -{ - if (argv.argc() == 1) - { - Printf ("Usage: gc stop|now|full|count|pause [size]|stepmul [size]\n"); - return; - } - if (stricmp(argv[1], "stop") == 0) - { - GC::Threshold = ~(size_t)0 - 2; - } - else if (stricmp(argv[1], "now") == 0) - { - GC::Threshold = GC::AllocBytes; - } - else if (stricmp(argv[1], "full") == 0) - { - GC::FullGC(); - } - else if (stricmp(argv[1], "count") == 0) - { - int cnt = 0; - for (DObject *obj = GC::Root; obj; obj = obj->ObjNext, cnt++); - Printf("%d active objects counted\n", cnt); - } - else if (stricmp(argv[1], "pause") == 0) - { - if (argv.argc() == 2) - { - Printf ("Current GC pause is %d\n", GC::Pause); - } - else - { - GC::Pause = MAX(1,atoi(argv[2])); - } - } - else if (stricmp(argv[1], "stepmul") == 0) - { - if (argv.argc() == 2) - { - Printf ("Current GC stepmul is %d\n", GC::StepMul); - } - else - { - GC::StepMul = MAX(100, atoi(argv[2])); - } - } -} - diff --git a/src/dobjgc.h b/src/dobjgc.h deleted file mode 100644 index 79316da0d17..00000000000 --- a/src/dobjgc.h +++ /dev/null @@ -1,253 +0,0 @@ -#pragma once -#include -class DObject; -class FSerializer; - -enum EObjectFlags -{ - // GC flags - OF_White0 = 1 << 0, // Object is white (type 0) - OF_White1 = 1 << 1, // Object is white (type 1) - OF_Black = 1 << 2, // Object is black - OF_Fixed = 1 << 3, // Object is fixed (should not be collected) - OF_Rooted = 1 << 4, // Object is soft-rooted - OF_EuthanizeMe = 1 << 5, // Object wants to die - OF_Cleanup = 1 << 6, // Object is now being deleted by the collector - OF_YesReallyDelete = 1 << 7, // Object is being deleted outside the collector, and this is okay, so don't print a warning - - OF_WhiteBits = OF_White0 | OF_White1, - OF_MarkBits = OF_WhiteBits | OF_Black, - - // Other flags - OF_JustSpawned = 1 << 8, // Thinker was spawned this tic - OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls - OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list - OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk) - OF_Spawned = 1 << 12, // Thinker was spawned at all (some thinkers get deleted before spawning) - OF_Released = 1 << 13, // Object was released from the GC system and should not be processed by GC function -}; - -template class TObjPtr; - -namespace GC -{ - enum EGCState - { - GCS_Pause, - GCS_Propagate, - GCS_Sweep, - GCS_Finalize - }; - - // Number of bytes currently allocated through M_Malloc/M_Realloc. - extern size_t AllocBytes; - - // Amount of memory to allocate before triggering a collection. - extern size_t Threshold; - - // List of gray objects. - extern DObject *Gray; - - // List of every object. - extern DObject *Root; - - // Current white value for potentially-live objects. - extern uint32_t CurrentWhite; - - // Current collector state. - extern EGCState State; - - // Position of GC sweep in the list of objects. - extern DObject **SweepPos; - - // Size of GC pause. - extern int Pause; - - // Size of GC steps. - extern int StepMul; - - // Is this the final collection just before exit? - extern bool FinalGC; - - // Current white value for known-dead objects. - static inline uint32_t OtherWhite() - { - return CurrentWhite ^ OF_WhiteBits; - } - - // Frees all objects, whether they're dead or not. - void FreeAll(); - - // Does one collection step. - void Step(); - - // Does a complete collection. - void FullGC(); - - // Handles the grunt work for a write barrier. - void Barrier(DObject *pointing, DObject *pointed); - - // Handles a write barrier. - static inline void WriteBarrier(DObject *pointing, DObject *pointed); - - // Handles a write barrier for a pointer that isn't inside an object. - static inline void WriteBarrier(DObject *pointed); - - // Handles a read barrier. - template inline T *ReadBarrier(T *&obj) - { - if (obj == NULL || !(obj->ObjectFlags & OF_EuthanizeMe)) - { - return obj; - } - return obj = NULL; - } - - // Check if it's time to collect, and do a collection step if it is. - static inline void CheckGC() - { - if (AllocBytes >= Threshold) - Step(); - } - - // Forces a collection to start now. - static inline void StartCollection() - { - Threshold = AllocBytes; - } - - // Marks a white object gray. If the object wants to die, the pointer - // is NULLed instead. - void Mark(DObject **obj); - - // Marks an array of objects. - void MarkArray(DObject **objs, size_t count); - - // For cleanup - void DelSoftRootHead(); - - // Soft-roots an object. - void AddSoftRoot(DObject *obj); - - // Unroots an object. - void DelSoftRoot(DObject *obj); - - template void Mark(T *&obj) - { - union - { - T *t; - DObject *o; - }; - o = obj; - Mark(&o); - obj = t; - } - template void Mark(TObjPtr &obj); - - template void MarkArray(T **obj, size_t count) - { - MarkArray((DObject **)(obj), count); - } - template void MarkArray(TArray &arr) - { - MarkArray(&arr[0], arr.Size()); - } -} - -// A template class to help with handling read barriers. It does not -// handle write barriers, because those can be handled more efficiently -// with knowledge of the object that holds the pointer. -template -class TObjPtr -{ - union - { - T pp; - DObject *o; - }; -public: - TObjPtr() = default; - TObjPtr(const TObjPtr &q) = default; - - TObjPtr(T q) throw() - : pp(q) - { - } - T operator=(T q) - { - pp = q; - return *this; - } - - T operator=(std::nullptr_t nul) - { - o = nullptr; - return *this; - } - - // To allow NULL, too. - T operator=(const int val) - { - assert(val == 0); - o = nullptr; - return *this; - } - - // To allow NULL, too. In Clang NULL is a long. - T operator=(const long val) - { - assert(val == 0); - o = nullptr; - return *this; - } - - T Get() throw() - { - return GC::ReadBarrier(pp); - } - - operator T() throw() - { - return GC::ReadBarrier(pp); - } - T &operator*() - { - T q = GC::ReadBarrier(pp); - assert(q != NULL); - return *q; - } - T operator->() throw() - { - return GC::ReadBarrier(pp); - } - bool operator!=(T u) throw() - { - return GC::ReadBarrier(o) != u; - } - bool operator==(T u) throw() - { - return GC::ReadBarrier(o) == u; - } - - template friend inline void GC::Mark(TObjPtr &obj); - template friend FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, TObjPtr *); - template friend FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, U *); - - friend class DObject; -}; - -// Use barrier_cast instead of static_cast when you need to cast -// the contents of a TObjPtr to a related type. -template inline T barrier_cast(TObjPtr &o) -{ - return static_cast(static_cast(o)); -} - -namespace GC -{ - template inline void Mark(TObjPtr &obj) - { - GC::Mark(&obj.o); - } -} diff --git a/src/doomdata.h b/src/doomdata.h index 572ebb61eb4..12a2869219d 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -62,6 +62,7 @@ enum ML_BEHAVIOR, // [RH] Hexen-style scripts. If present, THINGS // and LINEDEFS are also Hexen-style. ML_CONVERSATION, // Strife dialog (only for TEXTMAP format) + ML_LIGHTMAP, // ZDRay generated lightmap ML_MAX, // [RH] These are compressed (and extended) nodes. They combine the data from @@ -128,7 +129,7 @@ struct maplinedef2_t // LineDef attributes. // -enum ELineFlags : unsigned +enum ELineFlags : uint32_t { ML_BLOCKING =0x00000001, // solid, is an obstacle ML_BLOCKMONSTERS =0x00000002, // blocks monsters only @@ -176,6 +177,8 @@ enum ELineFlags : unsigned ML_REVEALED = 0x20000000, // set if revealed in automap ML_DRAWFULLHEIGHT = 0x40000000, // Draw the full height of the upper/lower sections ML_PORTALCONNECT = 0x80000000, // for internal use only: This line connects to a sector with a linked portal (used to speed up sight checks.) + // Flag words may not exceed 32 bit due to VM limitations. + ML2_BLOCKLANDMONSTERS = 0x1, // MBF21 }; @@ -370,7 +373,7 @@ struct FMapThing double Gravity; double Alpha; uint32_t fillcolor; - DVector2 Scale; + FVector2 Scale; double Health; int score; int16_t pitch; @@ -418,6 +421,7 @@ enum EMapThingFlags MTF_SECRET = 0x080000, // Secret pickup MTF_NOINFIGHTING = 0x100000, + MTF_NOCOUNT = 0x200000, // Removes COUNTKILL/COUNTITEM // BOOM and DOOM compatible versions of some of the above diff --git a/src/doomdef.h b/src/doomdef.h index 30e24add197..f1f4f352e17 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -57,15 +57,15 @@ typedef enum #endif #endif +// State updates, number of tics / second. +constexpr int TICRATE = 35; + // Global constants that were defines. enum { // The maximum number of players, multiplayer/networking. MAXPLAYERS = 8, - // State updates, number of tics / second. - TICRATE = 35, - // Amount of damage done by a telefrag. TELEFRAG_DAMAGE = 1000000 }; @@ -99,130 +99,10 @@ enum ESkillLevels // a mode 1 keyboard scan code. // -#define KEY_PAUSE 0xc5 // DIK_PAUSE -#define KEY_RIGHTARROW 0xcd // DIK_RIGHT -#define KEY_LEFTARROW 0xcb // DIK_LEFT -#define KEY_UPARROW 0xc8 // DIK_UP -#define KEY_DOWNARROW 0xd0 // DIK_DOWN -#define KEY_ESCAPE 0x01 // DIK_ESCAPE -#define KEY_ENTER 0x1c // DIK_RETURN -#define KEY_SPACE 0x39 // DIK_SPACE -#define KEY_TAB 0x0f // DIK_TAB -#define KEY_F1 0x3b // DIK_F1 -#define KEY_F2 0x3c // DIK_F2 -#define KEY_F3 0x3d // DIK_F3 -#define KEY_F4 0x3e // DIK_F4 -#define KEY_F5 0x3f // DIK_F5 -#define KEY_F6 0x40 // DIK_F6 -#define KEY_F7 0x41 // DIK_F7 -#define KEY_F8 0x42 // DIK_F8 -#define KEY_F9 0x43 // DIK_F9 -#define KEY_F10 0x44 // DIK_F10 -#define KEY_F11 0x57 // DIK_F11 -#define KEY_F12 0x58 // DIK_F12 -#define KEY_GRAVE 0x29 // DIK_GRAVE - -#define KEY_BACKSPACE 0x0e // DIK_BACK - -#define KEY_EQUALS 0x0d // DIK_EQUALS -#define KEY_MINUS 0x0c // DIK_MINUS - -#define KEY_LSHIFT 0x2A // DIK_LSHIFT -#define KEY_LCTRL 0x1d // DIK_LCONTROL -#define KEY_LALT 0x38 // DIK_LMENU - -#define KEY_RSHIFT KEY_LSHIFT -#define KEY_RCTRL KEY_LCTRL -#define KEY_RALT KEY_LALT - -#define KEY_INS 0xd2 // DIK_INSERT -#define KEY_DEL 0xd3 // DIK_DELETE -#define KEY_END 0xcf // DIK_END -#define KEY_HOME 0xc7 // DIK_HOME -#define KEY_PGUP 0xc9 // DIK_PRIOR -#define KEY_PGDN 0xd1 // DIK_NEXT - -#define KEY_MOUSE1 0x100 -#define KEY_MOUSE2 0x101 -#define KEY_MOUSE3 0x102 -#define KEY_MOUSE4 0x103 -#define KEY_MOUSE5 0x104 -#define KEY_MOUSE6 0x105 -#define KEY_MOUSE7 0x106 -#define KEY_MOUSE8 0x107 - -#define KEY_FIRSTJOYBUTTON 0x108 -#define KEY_JOY1 (KEY_FIRSTJOYBUTTON+0) -#define KEY_JOY2 (KEY_FIRSTJOYBUTTON+1) -#define KEY_JOY3 (KEY_FIRSTJOYBUTTON+2) -#define KEY_JOY4 (KEY_FIRSTJOYBUTTON+3) -#define KEY_JOY5 (KEY_FIRSTJOYBUTTON+4) -#define KEY_JOY6 (KEY_FIRSTJOYBUTTON+5) -#define KEY_JOY7 (KEY_FIRSTJOYBUTTON+6) -#define KEY_JOY8 (KEY_FIRSTJOYBUTTON+7) -#define KEY_LASTJOYBUTTON 0x187 -#define KEY_JOYPOV1_UP 0x188 -#define KEY_JOYPOV1_RIGHT 0x189 -#define KEY_JOYPOV1_DOWN 0x18a -#define KEY_JOYPOV1_LEFT 0x18b -#define KEY_JOYPOV2_UP 0x18c -#define KEY_JOYPOV3_UP 0x190 -#define KEY_JOYPOV4_UP 0x194 - -#define KEY_MWHEELUP 0x198 -#define KEY_MWHEELDOWN 0x199 -#define KEY_MWHEELRIGHT 0x19A -#define KEY_MWHEELLEFT 0x19B - -#define KEY_JOYAXIS1PLUS 0x19C -#define KEY_JOYAXIS1MINUS 0x19D -#define KEY_JOYAXIS2PLUS 0x19E -#define KEY_JOYAXIS2MINUS 0x19F -#define KEY_JOYAXIS3PLUS 0x1A0 -#define KEY_JOYAXIS3MINUS 0x1A1 -#define KEY_JOYAXIS4PLUS 0x1A2 -#define KEY_JOYAXIS4MINUS 0x1A3 -#define KEY_JOYAXIS5PLUS 0x1A4 -#define KEY_JOYAXIS5MINUS 0x1A5 -#define KEY_JOYAXIS6PLUS 0x1A6 -#define KEY_JOYAXIS6MINUS 0x1A7 -#define KEY_JOYAXIS7PLUS 0x1A8 -#define KEY_JOYAXIS7MINUS 0x1A9 -#define KEY_JOYAXIS8PLUS 0x1AA -#define KEY_JOYAXIS8MINUS 0x1AB -#define NUM_JOYAXISBUTTONS 8 - -#define KEY_PAD_LTHUMB_RIGHT 0x1AC -#define KEY_PAD_LTHUMB_LEFT 0x1AD -#define KEY_PAD_LTHUMB_DOWN 0x1AE -#define KEY_PAD_LTHUMB_UP 0x1AF - -#define KEY_PAD_RTHUMB_RIGHT 0x1B0 -#define KEY_PAD_RTHUMB_LEFT 0x1B1 -#define KEY_PAD_RTHUMB_DOWN 0x1B2 -#define KEY_PAD_RTHUMB_UP 0x1B3 - -#define KEY_PAD_DPAD_UP 0x1B4 -#define KEY_PAD_DPAD_DOWN 0x1B5 -#define KEY_PAD_DPAD_LEFT 0x1B6 -#define KEY_PAD_DPAD_RIGHT 0x1B7 -#define KEY_PAD_START 0x1B8 -#define KEY_PAD_BACK 0x1B9 -#define KEY_PAD_LTHUMB 0x1BA -#define KEY_PAD_RTHUMB 0x1BB -#define KEY_PAD_LSHOULDER 0x1BC -#define KEY_PAD_RSHOULDER 0x1BD -#define KEY_PAD_LTRIGGER 0x1BE -#define KEY_PAD_RTRIGGER 0x1BF -#define KEY_PAD_A 0x1C0 -#define KEY_PAD_B 0x1C1 -#define KEY_PAD_X 0x1C2 -#define KEY_PAD_Y 0x1C3 - -#define NUM_KEYS 0x1C4 +#include "keydef.h" // [RH] dmflags bits (based on Q2's) -enum +enum : unsigned { DF_NO_HEALTH = 1 << 0, // Do not spawn health items (DM) DF_NO_ITEMS = 1 << 1, // Do not spawn powerups (DM) @@ -256,12 +136,13 @@ enum DF_COOP_LOSE_POWERUPS = 1 << 28, // Lose powerups when respawning in coop DF_COOP_LOSE_AMMO = 1 << 29, // Lose ammo when respawning in coop DF_COOP_HALVE_AMMO = 1 << 30, // Lose half your ammo when respawning in coop (but not less than the normal starting amount) + DF_INSTANT_REACTION = 1u << 31, // Monsters react instantly }; // [BC] More dmflags. w00p! -enum +enum : unsigned { -// DF2_YES_IMPALING = 1 << 0, // Player gets implaed on MF2_IMPALE items +// DF2_YES_IMPALING = 1 << 0, // Player gets impaled on MF2_IMPALE items DF2_YES_WEAPONDROP = 1 << 1, // Drop current weapon upon death // DF2_NO_RUNES = 1 << 2, // Don't spawn runes // DF2_INSTANT_RETURN = 1 << 3, // Instantly return flags and skulls when player carrying it dies (ST/CTF) @@ -289,6 +170,23 @@ enum DF2_KILLBOSSMONST = 1 << 25, // Kills all monsters spawned by a boss cube when the boss dies DF2_NOCOUNTENDMONST = 1 << 26, // Do not count monsters in 'end level when dying' sectors towards kill count DF2_RESPAWN_SUPER = 1 << 27, // Respawn invulnerability and invisibility + DF2_NO_COOP_THING_SPAWN = 1 << 28, // Don't spawn multiplayer things in coop games + DF2_ALWAYS_SPAWN_MULTI = 1 << 29, // Always spawn multiplayer items + DF2_NOVERTSPREAD = 1 << 30, // Don't allow vertical spread for hitscan weapons (excluding ssg) + DF2_NO_EXTRA_AMMO = 1u << 31, // Don't add extra ammo when picking up weapons (like in original Doom) +}; + +// [Nash] dmflags3 in 2023 let's gooooo +enum : unsigned +{ + DF3_NO_PLAYER_CLIP = 1 << 0, // Players can walk through and shoot through each other + DF3_COOP_SHARE_KEYS = 1 << 1, // Keys and other core items will be given to all players in coop + DF3_LOCAL_ITEMS = 1 << 2, // Items are picked up client-side rather than fully taken by the client who picked it up + DF3_NO_LOCAL_DROPS = 1 << 3, // Drops from Actors aren't picked up locally + DF3_NO_COOP_ONLY_ITEMS = 1 << 4, // Items that only appear in co-op are disabled + DF3_NO_COOP_ONLY_THINGS = 1 << 5, // Any Actor that only appears in co-op is disabled + DF3_REMEMBER_LAST_WEAP = 1 << 6, // When respawning in co-op, keep the last used weapon out instead of switching to the best new one. + DF3_PISTOL_START = 1 << 7, // Take player inventory when exiting to the next level. }; // [RH] Compatibility flags. @@ -319,10 +217,10 @@ enum : unsigned int COMPATF_MINOTAUR = 1 << 22, // Minotaur's floor flame is exploded immediately when feet are clipped COMPATF_MUSHROOM = 1 << 23, // Force original velocity calculations for A_Mushroom in Dehacked mods. COMPATF_MBFMONSTERMOVE = 1 << 24, // Monsters are affected by friction and pushers/pullers. - COMPATF_CORPSEGIBS = 1 << 25, // Crushed monsters are turned into gibs, rather than replaced by gibs. + COMPATF_VILEGHOSTS = 1 << 25, // Crushed monsters are resurrected as ghosts. COMPATF_NOBLOCKFRIENDS = 1 << 26, // Friendly monsters aren't blocked by monster-blocking lines. COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance - COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code. + COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap and hit check code. COMPATF_LIGHT = 1 << 29, // Find neighboring light level like Doom COMPATF_POLYOBJ = 1 << 30, // Draw polyobjects the old fashioned way COMPATF_MASKEDMIDTEX = 1u << 31, // Ignore compositing when drawing masked midtextures @@ -339,6 +237,13 @@ enum : unsigned int COMPATF2_EXPLODE2 = 1 << 9, // Use original explosion code throughout. COMPATF2_RAILING = 1 << 10, // Bugged Strife railings. COMPATF2_SCRIPTWAIT = 1 << 11, // Use old scriptwait implementation where it doesn't wait on a non-running script. + COMPATF2_AVOID_HAZARDS = 1 << 12, // another MBF thing. + COMPATF2_STAYONLIFT = 1 << 13, // yet another MBF thing. + COMPATF2_NOMBF21 = 1 << 14, // disable MBF21 features that may clash with certain maps + COMPATF2_VOODOO_ZOMBIES = 1 << 15, // [RL0] allow playerinfo, playerpawn, and voodoo health to all be different, and skip killing the player's mobj if a voodoo doll dies to allow voodoo zombies + COMPATF2_FDTELEPORT = 1 << 16, // Emulate Final Doom's teleporter z glitch. + COMPATF2_NOACSARGCHECK = 1 << 17, // Disable arg count checking for ACS + }; // Emulate old bugs for select maps. These are not exposed by a cvar @@ -347,7 +252,6 @@ enum { BCOMPATF_SETSLOPEOVERFLOW = 1 << 0, // SetSlope things can overflow BCOMPATF_RESETPLAYERSPEED = 1 << 1, // Set player speed to 1.0 when changing maps - BCOMPATF_VILEGHOSTS = 1 << 2, // Monsters' radius and height aren't restored properly when resurrected. BCOMPATF_BADTELEPORTERS = 1 << 3, // Ignore tags on Teleport specials BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior BCOMPATF_REBUILDNODES = 1 << 5, // Force node rebuild @@ -355,6 +259,8 @@ enum BCOMPATF_FLOATBOB = 1 << 8, // Use Hexen's original method of preventing floatbobbing items from falling down BCOMPATF_NOSLOPEID = 1 << 9, // disable line IDs on slopes. BCOMPATF_CLIPMIDTEX = 1 << 10, // Always Clip midtex's in the software renderer (required to run certain GZDoom maps, has no effect in the hardware renderer) + BCOMPATF_NOSECTIONMERGE = 1 << 11, // (for IWAD maps) keep separate sections for sectors with intra-sector linedefs. + BCOMPATF_NOMIRRORS = 1 << 12, // disable mirrors, for maps that have broken setups. }; // phares 3/20/98: diff --git a/src/doomstat.cpp b/src/doomstat.cpp index 8519489068e..ef681fb8557 100644 --- a/src/doomstat.cpp +++ b/src/doomstat.cpp @@ -35,7 +35,6 @@ int SaveVersion; // Localizable strings -FStringTable GStrings; // Game speed EGameSpeed GameSpeed = SPEED_Normal; @@ -47,6 +46,4 @@ int NextSkill = -1; int SinglePlayerClass[MAXPLAYERS]; -bool ToggleFullscreen; - FString LumpFilterIWAD; diff --git a/src/doomstat.h b/src/doomstat.h index da160f01ef4..cc991a4feb5 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -64,8 +64,6 @@ extern FString startmap; // [RH] Actual map name now extern bool autostart; -extern FString StoredWarp; // [RH] +warp at the command line - // Selected by user. EXTERN_CVAR (Int, gameskill); extern int NextSkill; // [RH] Skill to use at next level load @@ -107,18 +105,9 @@ EXTERN_CVAR (Float, snd_musicvolume) // maximum volume for music // Status flags for refresh. // -enum EMenuState : int -{ - MENU_Off, // Menu is closed - MENU_On, // Menu is opened - MENU_WaitKey, // Menu is opened and waiting for a key in the controls menu - MENU_OnNoPause, // Menu is opened but does not pause the game -}; +#include "menustate.h" extern bool automapactive; // In AutoMap mode? -extern EMenuState menuactive; // Menu overlayed? -extern int paused; // Game Pause? -extern bool pauseext; extern bool viewactive; @@ -180,7 +169,6 @@ extern bool playeringame[/*MAXPLAYERS*/]; // File handling stuff. extern FILE* debugfile; -extern FILE* hashfile; // if true, load all graphics at level load extern bool precache; @@ -193,7 +181,6 @@ extern bool precache; extern bool setsizeneeded; -EXTERN_CVAR (Float, mouse_sensitivity) //? // debug flag to cancel adaptiveness extern bool singletics; @@ -246,6 +233,7 @@ EXTERN_CVAR (Int, infighting) EXTERN_CVAR (Int, dmflags); EXTERN_CVAR (Int, dmflags2); // [BC] +EXTERN_CVAR (Int, dmflags3); // [Nash] EXTERN_CVAR (Int, compatflags); EXTERN_CVAR (Int, compatflags2); diff --git a/src/doomtype.h b/src/doomtype.h index ce644f7374a..2a3fecbd0f7 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -28,166 +28,17 @@ #include "tarray.h" #include "name.h" #include "zstring.h" +#include "cmdlib.h" class PClassActor; typedef TMap FClassMap; - -#if defined(_MSC_VER) -#define NOVTABLE __declspec(novtable) -#else -#define NOVTABLE -#endif - -#if defined(__GNUC__) -// With versions of GCC newer than 4.2, it appears it was determined that the -// cost of an unaligned pointer on PPC was high enough to add padding to the -// end of packed structs. For whatever reason __packed__ and pragma pack are -// handled differently in this regard. Note that this only needs to be applied -// to types which are used in arrays or sizeof is needed. This also prevents -// code from taking references to the struct members. -#define FORCE_PACKED __attribute__((__packed__)) -#else -#define FORCE_PACKED -#endif - -#include "basictypes.h" - -extern bool batchrun; +#include "basics.h" +#include "printf.h" // Bounding box coordinate storage. -enum -{ - BOXTOP, - BOXBOTTOM, - BOXLEFT, - BOXRIGHT -}; // bbox coordinates - - -// [RH] This gets used all over; define it here: -int Printf (int printlevel, const char *, ...) GCCPRINTF(2,3); -int Printf (const char *, ...) GCCPRINTF(1,2); - -// [RH] Same here: -int DPrintf (int level, const char *, ...) GCCPRINTF(2,3); - -extern "C" int mysnprintf(char *buffer, size_t count, const char *format, ...) GCCPRINTF(3,4); -extern "C" int myvsnprintf(char *buffer, size_t count, const char *format, va_list argptr) GCCFORMAT(3); - - -// game print flags -enum -{ - PRINT_LOW, // pickup messages - PRINT_MEDIUM, // death messages - PRINT_HIGH, // critical messages - PRINT_CHAT, // chat messages - PRINT_TEAMCHAT, // chat messages from a teammate - PRINT_LOG, // only to logfile - PRINT_BOLD = 200, // What Printf_Bold used - PRINT_TYPES = 1023, // Bitmask. - PRINT_NONOTIFY = 1024, // Flag - do not add to notify buffer - PRINT_NOLOG = 2048, // Flag - do not print to log file -}; - -enum -{ - DMSG_OFF, // no developer messages. - DMSG_ERROR, // general notification messages - DMSG_WARNING, // warnings - DMSG_NOTIFY, // general notification messages - DMSG_SPAMMY, // for those who want to see everything, regardless of its usefulness. -}; - #include "palentry.h" - -enum class ETextureType : uint8_t -{ - Any, - Wall, - Flat, - Sprite, - WallPatch, - Build, // no longer used but needs to remain for ZScript - SkinSprite, - Decal, - MiscPatch, - FontChar, - Override, // For patches between TX_START/TX_END - Autopage, // Automap background - used to enable the use of FAutomapTexture - SkinGraphic, - Null, - FirstDefined, - SWCanvas, -}; - -class FTextureID -{ - friend class FTextureManager; - friend void R_InitSpriteDefs(); - -public: - FTextureID() = default; - bool isNull() const { return texnum == 0; } - bool isValid() const { return texnum > 0; } - bool Exists() const { return texnum >= 0; } - void SetInvalid() { texnum = -1; } - void SetNull() { texnum = 0; } - bool operator ==(const FTextureID &other) const { return texnum == other.texnum; } - bool operator !=(const FTextureID &other) const { return texnum != other.texnum; } - FTextureID operator +(int offset) throw(); - int GetIndex() const { return texnum; } // Use this only if you absolutely need the index! - - // The switch list needs these to sort the switches by texture index - int operator -(FTextureID other) const { return texnum - other.texnum; } - bool operator < (FTextureID other) const { return texnum < other.texnum; } - bool operator > (FTextureID other) const { return texnum > other.texnum; } - -protected: - FTextureID(int num) { texnum = num; } -private: - int texnum; -}; - -// This is for the script interface which needs to do casts from int to texture. -class FSetTextureID : public FTextureID -{ -public: - FSetTextureID(int v) : FTextureID(v) {} -}; - - -struct VersionInfo -{ - uint16_t major; - uint16_t minor; - uint32_t revision; - - bool operator <=(const VersionInfo &o) const - { - return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision >= this->revision); - } - bool operator >=(const VersionInfo &o) const - { - return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision <= this->revision); - } - bool operator > (const VersionInfo &o) const - { - return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision < this->revision); - } - bool operator < (const VersionInfo &o) const - { - return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision > this->revision); - } - void operator=(const char *string); -}; - -// Cannot be a constructor because Lemon would puke on it. -inline VersionInfo MakeVersion(unsigned int ma, unsigned int mi, unsigned int re = 0) -{ - return{ (uint16_t)ma, (uint16_t)mi, (uint32_t)re }; -} +#include "textureid.h" enum class ELightMode : int8_t { @@ -197,57 +48,9 @@ enum class ELightMode : int8_t Doom = 2, DoomDark = 3, DoomLegacy = 4, + Build = 5, ZDoomSoftware = 8, DoomSoftware = 16 }; -// Screenshot buffer image data types -enum ESSType -{ - SS_PAL, - SS_RGB, - SS_BGRA -}; - -// always use our own definition for consistency. -#ifdef M_PI -#undef M_PI -#endif - -const double M_PI = 3.14159265358979323846; // matches value in gcc v2 math.h - -inline float DEG2RAD(float deg) -{ - return deg * float(M_PI / 180.0); -} - -inline double DEG2RAD(double deg) -{ - return deg * (M_PI / 180.0); -} - -inline float RAD2DEG(float deg) -{ - return deg * float(180. / M_PI); -} - - -// Auto-registration sections for GCC. -// Apparently, you cannot do string concatenation inside section attributes. -#ifdef __MACH__ -#define SECTION_AREG "__DATA,areg" -#define SECTION_CREG "__DATA,creg" -#define SECTION_FREG "__DATA,freg" -#define SECTION_GREG "__DATA,greg" -#define SECTION_MREG "__DATA,mreg" -#define SECTION_YREG "__DATA,yreg" -#else -#define SECTION_AREG "areg" -#define SECTION_CREG "creg" -#define SECTION_FREG "freg" -#define SECTION_GREG "greg" -#define SECTION_MREG "mreg" -#define SECTION_YREG "yreg" -#endif - #endif diff --git a/src/events.cpp b/src/events.cpp index eafefb09ed7..a4773d13326 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -31,7 +31,6 @@ ** */ #include "events.h" -#include "vm.h" #include "vmintern.h" #include "r_utility.h" #include "g_levellocals.h" @@ -45,6 +44,225 @@ EventManager staticEventManager; +static int ListGetInt(VMVa_List& tags) +{ + if (tags.curindex < tags.numargs) + { + if (tags.reginfo[tags.curindex] == REGT_FLOAT) + return static_cast(tags.args[tags.curindex++].f); + + if (tags.reginfo[tags.curindex] == REGT_INT) + return tags.args[tags.curindex++].i; + + ThrowAbortException(X_OTHER, "Invalid parameter in network command function, int expected"); + } + + return TAG_DONE; +} + +static double ListGetDouble(VMVa_List& tags) +{ + if (tags.curindex < tags.numargs) + { + if (tags.reginfo[tags.curindex] == REGT_FLOAT) + return tags.args[tags.curindex++].f; + + if (tags.reginfo[tags.curindex] == REGT_INT) + return tags.args[tags.curindex++].i; + + ThrowAbortException(X_OTHER, "Invalid parameter in network command function, float expected"); + } + + return TAG_DONE; +} + +static const FString* ListGetString(VMVa_List& tags) +{ + if (tags.curindex < tags.numargs) + { + if (tags.reginfo[tags.curindex] == REGT_STRING) + return &tags.args[tags.curindex++].s(); + + ThrowAbortException(X_OTHER, "Invalid parameter in network command function, string expected"); + } + + return nullptr; +} + +IMPLEMENT_CLASS(DNetworkBuffer, false, false); + +void DNetworkBuffer::AddInt8(int byte) +{ + ++_size; + _buffer.Push({ NET_INT8, byte }); +} + +void DNetworkBuffer::AddInt16(int word) +{ + _size += 2u; + _buffer.Push({ NET_INT16, word }); +} + +void DNetworkBuffer::AddInt(int msg) +{ + _size += 4u; + _buffer.Push({ NET_INT, msg }); +} + +void DNetworkBuffer::AddFloat(double msg) +{ + _size += 4u; + _buffer.Push({ NET_FLOAT, msg }); +} + +void DNetworkBuffer::AddDouble(double msg) +{ + _size += 8u; + _buffer.Push({ NET_DOUBLE, msg }); +} + +void DNetworkBuffer::AddString(const FString& msg) +{ + _size += msg.Len() + 1u; + _buffer.Push({ NET_STRING, msg }); +} + +void DNetworkBuffer::OnDestroy() +{ + Super::OnDestroy(); + + _buffer.Reset(); +} + +void DNetworkBuffer::Serialize(FSerializer& arc) +{ + Super::Serialize(arc); + + if (arc.isWriting()) + { + if (!_buffer.Size()) + return; + + if (arc.BeginArray("types")) + { + for (const auto& value : _buffer) + { + int i = value.GetType(); + arc(nullptr, i); + } + + arc.EndArray(); + } + + if (arc.BeginArray("values")) + { + for (const auto& value : _buffer) + { + switch (value.GetType()) + { + case NET_DOUBLE: + case NET_FLOAT: + { + double f = value.GetDouble(); + arc(nullptr, f); + break; + } + + case NET_STRING: + { + FString s = value.GetString(); + arc(nullptr, s); + break; + } + + default: + { + int i = value.GetInt(); + arc(nullptr, i); + break; + } + } + } + + arc.EndArray(); + } + } + else + { + TArray types = {}; + arc("types", types); + + if (!types.Size()) + return; + + if (arc.BeginArray("values")) + { + // Something got corrupted, don't repopulate the buffer. + if (arc.ArraySize() != types.Size()) + { + arc.EndArray(); + return; + } + + for (int type : types) + { + switch (type) + { + case NET_INT8: + { + int i = 0; + arc(nullptr, i); + AddInt8(i); + break; + } + + case NET_INT16: + { + int i = 0; + arc(nullptr, i); + AddInt16(i); + break; + } + + case NET_INT: + { + int i = 0; + arc(nullptr, i); + AddInt(i); + break; + } + + case NET_FLOAT: + { + double f = 0.0; + arc(nullptr, f); + AddFloat(f); + break; + } + + case NET_DOUBLE: + { + double f = 0.0; + arc(nullptr, f); + AddDouble(f); + break; + } + + case NET_STRING: + { + FString s = {}; + arc(nullptr, s); + AddString(s); + break; + } + } + } + + arc.EndArray(); + } + } +} + void EventManager::CallOnRegister() { for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next) @@ -162,16 +380,160 @@ bool EventManager::UnregisterHandler(DStaticEventHandler* handler) bool EventManager::SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual) { - if (gamestate != GS_LEVEL) + if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) + return false; + + Net_WriteInt8(DEM_NETEVENT); + Net_WriteString(name.GetChars()); + Net_WriteInt8(3); + Net_WriteInt32(arg1); + Net_WriteInt32(arg2); + Net_WriteInt32(arg3); + Net_WriteInt8(manual); + + return true; +} + +bool EventManager::SendNetworkCommand(const FName& cmd, VMVa_List& args) +{ + if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) + return false; + + // Calculate the size of the message so we know where it ends. + unsigned int bytes = 0u; + int tag = ListGetInt(args); + while (tag != TAG_DONE) + { + switch (tag) + { + case NET_INT8: + ++bytes; + break; + + case NET_INT16: + bytes += 2u; + break; + + case NET_INT: + case NET_FLOAT: + bytes += 4u; + break; + + case NET_DOUBLE: + bytes += 8u; + break; + + case NET_STRING: + { + ++bytes; // Strings will always consume at least one byte. + const FString* str = ListGetString(args); + if (str != nullptr) + bytes += str->Len(); + break; + } + } + + if (tag != NET_STRING) + ++args.curindex; + + tag = ListGetInt(args); + } + + Net_WriteInt8(DEM_ZSC_CMD); + Net_WriteString(cmd.GetChars()); + Net_WriteInt16(bytes); + + constexpr char Default[] = ""; + + args.curindex = 0; + tag = ListGetInt(args); + while (tag != TAG_DONE) + { + switch (tag) + { + default: + ++args.curindex; + break; + + case NET_INT8: + Net_WriteInt8(ListGetInt(args)); + break; + + case NET_INT16: + Net_WriteInt16(ListGetInt(args)); + break; + + case NET_INT: + Net_WriteInt32(ListGetInt(args)); + break; + + case NET_FLOAT: + Net_WriteFloat(ListGetDouble(args)); + break; + + case NET_DOUBLE: + Net_WriteDouble(ListGetDouble(args)); + break; + + case NET_STRING: + { + const FString* str = ListGetString(args); + if (str != nullptr) + Net_WriteString(str->GetChars()); + else + Net_WriteString(Default); // Still have to send something here to be read correctly. + break; + } + } + + tag = ListGetInt(args); + } + + return true; +} + +bool EventManager::SendNetworkBuffer(const FName& cmd, const DNetworkBuffer* buffer) +{ + if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) return false; - Net_WriteByte(DEM_NETEVENT); - Net_WriteString(name); - Net_WriteByte(3); - Net_WriteLong(arg1); - Net_WriteLong(arg2); - Net_WriteLong(arg3); - Net_WriteByte(manual); + Net_WriteInt8(DEM_ZSC_CMD); + Net_WriteString(cmd.GetChars()); + Net_WriteInt16(buffer != nullptr ? buffer->GetBytes() : 0); + + if (buffer != nullptr) + { + for (unsigned int i = 0u; i < buffer->GetBufferSize(); ++i) + { + const auto& value = buffer->GetValue(i); + switch (value.GetType()) + { + case NET_INT8: + Net_WriteInt8(value.GetInt()); + break; + + case NET_INT16: + Net_WriteInt16(value.GetInt()); + break; + + case NET_INT: + Net_WriteInt32(value.GetInt()); + break; + + case NET_FLOAT: + Net_WriteFloat(value.GetDouble()); + break; + + case NET_DOUBLE: + Net_WriteDouble(value.GetDouble()); + break; + + case NET_STRING: + Net_WriteString(value.GetString()); + break; + } + } + } return true; } @@ -280,6 +642,14 @@ void EventManager::Shutdown() handler->name(); \ } +void EventManager::OnEngineInitialize() +{ + for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsStatic()) + handler->OnEngineInitialize(); + } +} // note for the functions below. // *Unsafe is executed on EVERY map load/close, including savegame loading, etc. @@ -294,11 +664,11 @@ void EventManager::WorldLoaded() } } -void EventManager::WorldUnloaded() +void EventManager::WorldUnloaded(const FString& nextmap) { for (DStaticEventHandler* handler = LastEventHandler; handler; handler = handler->prev) { - handler->WorldUnloaded(); + handler->WorldUnloaded(nextmap); } } @@ -331,6 +701,18 @@ void EventManager::WorldThingDied(AActor* actor, AActor* inflictor) handler->WorldThingDied(actor, inflictor); } +void EventManager::WorldThingGround(AActor* actor, FState* st) +{ + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return; + + if (ShouldCallStatic(true)) staticEventManager.WorldThingGround(actor, st); + + for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next) + handler->WorldThingGround(actor, st); +} + void EventManager::WorldThingRevived(AActor* actor) { // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. @@ -418,6 +800,14 @@ void EventManager::PlayerEntered(int num, bool fromhub) handler->PlayerEntered(num, fromhub); } +void EventManager::PlayerSpawned(int num) +{ + if (ShouldCallStatic(true)) staticEventManager.PlayerSpawned(num); + + for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next) + handler->PlayerSpawned(num); +} + void EventManager::PlayerRespawned(int num) { if (ShouldCallStatic(true)) staticEventManager.PlayerRespawned(num); @@ -491,17 +881,25 @@ bool EventManager::Responder(const event_t* ev) return true; // event was processed } } - if (ShouldCallStatic(false)) uiProcessorsFound = staticEventManager.Responder(ev); + if (ShouldCallStatic(false) && staticEventManager.Responder(ev)) return true; return false; } -void EventManager::Console(int player, FString name, int arg1, int arg2, int arg3, bool manual) +void EventManager::NetCommand(FNetworkCommand& cmd) +{ + if (ShouldCallStatic(false)) staticEventManager.NetCommand(cmd); + + for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next) + handler->NetCommandProcess(cmd); +} + +void EventManager::Console(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui) { - if (ShouldCallStatic(false)) staticEventManager.Console(player, name, arg1, arg2, arg3, manual); + if (ShouldCallStatic(false)) staticEventManager.Console(player, name, arg1, arg2, arg3, manual, ui); for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next) - handler->ConsoleProcess(player, name, arg1, arg2, arg3, manual); + handler->ConsoleProcess(player, name, arg1, arg2, arg3, manual, ui); } void EventManager::RenderOverlay(EHudState state) @@ -609,6 +1007,7 @@ DEFINE_FIELD_X(RenderEvent, FRenderEvent, Camera); DEFINE_FIELD_X(WorldEvent, FWorldEvent, IsSaveGame); DEFINE_FIELD_X(WorldEvent, FWorldEvent, IsReopen); +DEFINE_FIELD_X(WorldEvent, FWorldEvent, NextMap); DEFINE_FIELD_X(WorldEvent, FWorldEvent, Thing); DEFINE_FIELD_X(WorldEvent, FWorldEvent, Inflictor); DEFINE_FIELD_X(WorldEvent, FWorldEvent, Damage); @@ -626,26 +1025,11 @@ DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamageLineSide); DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamagePosition); DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamageIsRadius); DEFINE_FIELD_X(WorldEvent, FWorldEvent, NewDamage); +DEFINE_FIELD_X(WorldEvent, FWorldEvent, CrushedState); DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, PlayerNumber); DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, IsReturn); -DEFINE_FIELD_X(UiEvent, FUiEvent, Type); -DEFINE_FIELD_X(UiEvent, FUiEvent, KeyString); -DEFINE_FIELD_X(UiEvent, FUiEvent, KeyChar); -DEFINE_FIELD_X(UiEvent, FUiEvent, MouseX); -DEFINE_FIELD_X(UiEvent, FUiEvent, MouseY); -DEFINE_FIELD_X(UiEvent, FUiEvent, IsShift); -DEFINE_FIELD_X(UiEvent, FUiEvent, IsAlt); -DEFINE_FIELD_X(UiEvent, FUiEvent, IsCtrl); - -DEFINE_FIELD_X(InputEvent, FInputEvent, Type); -DEFINE_FIELD_X(InputEvent, FInputEvent, KeyScan); -DEFINE_FIELD_X(InputEvent, FInputEvent, KeyString); -DEFINE_FIELD_X(InputEvent, FInputEvent, KeyChar); -DEFINE_FIELD_X(InputEvent, FInputEvent, MouseX); -DEFINE_FIELD_X(InputEvent, FInputEvent, MouseY); - DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, Player) DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, Name) DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, Args) @@ -659,6 +1043,501 @@ DEFINE_FIELD_X(ReplacedEvent, FReplacedEvent, Replacee) DEFINE_FIELD_X(ReplacedEvent, FReplacedEvent, Replacement) DEFINE_FIELD_X(ReplacedEvent, FReplacedEvent, IsFinal) +DEFINE_FIELD(FNetworkCommand, Player) +DEFINE_FIELD(FNetworkCommand, Command) + +static int NativeReadInt8(FNetworkCommand* const self) { return self->ReadInt8(); } + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadInt8, NativeReadInt8) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_INT(self->ReadInt8()); +} + +static int NativeReadInt16(FNetworkCommand* const self) { return self->ReadInt16(); } + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadInt16, NativeReadInt16) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_INT(self->ReadInt16()); +} + +static int NativeReadInt(FNetworkCommand* const self) { return self->ReadInt(); } + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadInt, NativeReadInt) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_INT(self->ReadInt()); +} + +static double NativeReadFloat(FNetworkCommand* const self) { return self->ReadFloat(); } + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadFloat, NativeReadFloat) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_FLOAT(self->ReadFloat()); +} + +static double NativeReadDouble(FNetworkCommand* const self) { return self->ReadDouble(); } + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadDouble, NativeReadDouble) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_FLOAT(self->ReadDouble()); +} + +static void NativeReadString(FNetworkCommand* const self, FString* const result) +{ + const auto str = self->ReadString(); + if (str != nullptr) + *result = str; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadString, NativeReadString) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + FString res = {}; + NativeReadString(self, &res); + ACTION_RETURN_STRING(res); +} + +static int NativeReadName(FNetworkCommand* const self) +{ + FName res = NAME_None; + const auto str = self->ReadString(); + if (str != nullptr) + res = str; + + return res.GetIndex(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadName, NativeReadName) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_INT(NativeReadName(self)); +} + +static double NativeReadMapUnit(FNetworkCommand* const self) +{ + constexpr double FixedToFloat = 1.0 / (1 << 16); + return self->ReadInt() * FixedToFloat; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadMapUnit, NativeReadMapUnit) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_FLOAT(NativeReadMapUnit(self)); +} + +static double NativeReadAngle(FNetworkCommand* const self) { return DAngle::fromBam(self->ReadInt()).Degrees(); } + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadAngle, NativeReadAngle) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_FLOAT(DAngle::fromBam(self->ReadInt()).Degrees()); +} + +static void NativeReadVector2(FNetworkCommand* const self, DVector2* const result) +{ + result->X = self->ReadDouble(); + result->Y = self->ReadDouble(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadVector2, NativeReadVector2) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_VEC2(DVector2(self->ReadDouble(), self->ReadDouble())); +} + +static void NativeReadVector3(FNetworkCommand* const self, DVector3* const result) +{ + result->X = self->ReadDouble(); + result->Y = self->ReadDouble(); + result->Z = self->ReadDouble(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadVector3, NativeReadVector3) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_VEC3(DVector3(self->ReadDouble(), self->ReadDouble(), self->ReadDouble())); +} + +static void NativeReadVector4(FNetworkCommand* const self, DVector4* const result) +{ + result->X = self->ReadDouble(); + result->Y = self->ReadDouble(); + result->Z = self->ReadDouble(); + result->W = self->ReadDouble(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadVector4, NativeReadVector4) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_VEC4(DVector4(self->ReadDouble(), self->ReadDouble(), self->ReadDouble(), self->ReadDouble())); +} + +static void NativeReadQuat(FNetworkCommand* const self, DQuaternion* const result) +{ + result->X = self->ReadDouble(); + result->Y = self->ReadDouble(); + result->Z = self->ReadDouble(); + result->W = self->ReadDouble(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadQuat, NativeReadQuat) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_QUAT(DQuaternion(self->ReadDouble(), self->ReadDouble(), self->ReadDouble(), self->ReadDouble())); +} + +static void NativeReadIntArray(FNetworkCommand* const self, TArray* const values, const int type) +{ + const unsigned int size = self->ReadInt(); + for (unsigned int i = 0u; i < size; ++i) + { + switch (type) + { + case NET_INT8: + values->Push(self->ReadInt8()); + break; + + case NET_INT16: + values->Push(self->ReadInt16()); + break; + + default: + values->Push(self->ReadInt()); + break; + } + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadIntArray, NativeReadIntArray) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + PARAM_OUTPOINTER(values, TArray); + PARAM_INT(type); + + NativeReadIntArray(self, values, type); + return 0; +} + +static void NativeReadDoubleArray(FNetworkCommand* const self, TArray* const values, const bool doublePrecision) +{ + const unsigned int size = self->ReadInt(); + for (unsigned int i = 0u; i < size; ++i) + { + if (doublePrecision) + values->Push(self->ReadDouble()); + else + values->Push(self->ReadFloat()); + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadDoubleArray, NativeReadDoubleArray) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + PARAM_OUTPOINTER(values, TArray); + PARAM_BOOL(doublePrecision); + + NativeReadDoubleArray(self, values, doublePrecision); + return 0; +} + +static void NativeReadStringArray(FNetworkCommand* const self, TArray* const values, const bool skipEmpty) +{ + const unsigned int size = self->ReadInt(); + for (unsigned int i = 0u; i < size; ++i) + { + FString res = {}; + const auto str = self->ReadString(); + if (str != nullptr) + res = str; + + if (!skipEmpty || !res.IsEmpty()) + values->Push(res); + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, ReadStringArray, NativeReadStringArray) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + PARAM_OUTPOINTER(values, TArray); + PARAM_BOOL(skipEmpty); + + NativeReadStringArray(self, values, skipEmpty); + return 0; +} + +static int EndOfStream(FNetworkCommand* const self) { return self->EndOfStream(); } + +DEFINE_ACTION_FUNCTION_NATIVE(FNetworkCommand, EndOfStream, EndOfStream) +{ + PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand); + + ACTION_RETURN_BOOL(self->EndOfStream()); +} + +static void AddInt8(DNetworkBuffer* const self, const int value) { self->AddInt8(value); } + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddInt8, AddInt8) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_INT(value); + self->AddInt8(value); + return 0; +} + +static void AddInt16(DNetworkBuffer* const self, const int value) { self->AddInt16(value); } + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddInt16, AddInt16) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_INT(value); + self->AddInt16(value); + return 0; +} + +static void AddInt(DNetworkBuffer* const self, const int value) { self->AddInt(value); } + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddInt, AddInt) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_INT(value); + self->AddInt(value); + return 0; +} + +static void AddFloat(DNetworkBuffer* const self, const double value) { self->AddFloat(value); } + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddFloat, AddFloat) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_FLOAT(value); + self->AddFloat(value); + return 0; +} + +static void AddDouble(DNetworkBuffer* const self, const double value) { self->AddDouble(value); } + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddDouble, AddDouble) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_FLOAT(value); + self->AddDouble(value); + return 0; +} + +static void AddString(DNetworkBuffer* const self, const FString& value) { self->AddString(value); } + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddString, AddString) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_STRING(value); + self->AddString(value); + return 0; +} + +static void AddName(DNetworkBuffer* const self, const int value) { FName x = ENamedName(value); self->AddString(x.GetChars()); } + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddName, AddName) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_NAME(value); + self->AddString(value.GetChars()); + return 0; +} + +static void AddMapUnit(DNetworkBuffer* const self, const double value) +{ + constexpr int FloatToFixed = 1 << 16; + self->AddInt(static_cast(value * FloatToFixed)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddMapUnit, AddMapUnit) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_FLOAT(value); + + AddMapUnit(self, value); + return 0; +} + +static void AddAngle(DNetworkBuffer* const self, const double value) { self->AddInt(DAngle::fromDeg(value).BAMs()); } + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddAngle, AddAngle) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_ANGLE(value); + self->AddInt(value.BAMs()); + return 0; +} + +static void AddVector2(DNetworkBuffer* const self, const double x, const double y) +{ + self->AddDouble(x); + self->AddDouble(y); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddVector2, AddVector2) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + self->AddDouble(x); + self->AddDouble(y); + return 0; +} + +static void AddVector3(DNetworkBuffer* const self, const double x, const double y, const double z) +{ + self->AddDouble(x); + self->AddDouble(y); + self->AddDouble(z); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddVector3, AddVector3) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + self->AddDouble(x); + self->AddDouble(y); + self->AddDouble(z); + return 0; +} + +static void AddVector4(DNetworkBuffer* const self, const double x, const double y, const double z, const double w) +{ + self->AddDouble(x); + self->AddDouble(y); + self->AddDouble(z); + self->AddDouble(w); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddVector4, AddVector4) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_FLOAT(w); + self->AddDouble(x); + self->AddDouble(y); + self->AddDouble(z); + self->AddDouble(w); + return 0; +} + +static void AddQuat(DNetworkBuffer* const self, const double x, const double y, const double z, const double w) +{ + self->AddDouble(x); + self->AddDouble(y); + self->AddDouble(z); + self->AddDouble(w); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddQuat, AddQuat) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_FLOAT(w); + self->AddDouble(x); + self->AddDouble(y); + self->AddDouble(z); + self->AddDouble(w); + return 0; +} + +static void AddIntArray(DNetworkBuffer* const self, TArray* const values, const int type) +{ + const unsigned int size = values->Size(); + self->AddInt(size); + for (unsigned int i = 0u; i < size; ++i) + { + switch (type) + { + case NET_INT8: + self->AddInt8((*values)[i]); + break; + + case NET_INT16: + self->AddInt16((*values)[i]); + break; + + default: + self->AddInt((*values)[i]); + break; + } + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddIntArray, AddIntArray) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_POINTER(values, TArray); + PARAM_INT(type); + + AddIntArray(self, values, type); + return 0; +} + +static void AddDoubleArray(DNetworkBuffer* const self, TArray* const values, const bool doublePrecision) +{ + const unsigned int size = values->Size(); + self->AddInt(size); + for (unsigned int i = 0u; i < size; ++i) + { + if (doublePrecision) + self->AddDouble((*values)[i]); + else + self->AddFloat((*values)[i]); + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddDoubleArray, AddDoubleArray) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_POINTER(values, TArray); + PARAM_BOOL(doublePrecision); + + AddDoubleArray(self, values, doublePrecision); + return 0; +} + +static void AddStringArray(DNetworkBuffer* const self, TArray* const values) +{ + const unsigned int size = values->Size(); + self->AddInt(size); + for (unsigned int i = 0u; i < size; ++i) + self->AddString((*values)[i]); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DNetworkBuffer, AddStringArray, AddStringArray) +{ + PARAM_SELF_PROLOGUE(DNetworkBuffer); + PARAM_POINTER(values, TArray); + + AddStringArray(self, values); + return 0; +} + DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder) { PARAM_SELF_PROLOGUE(DStaticEventHandler); @@ -668,6 +1547,25 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder) return 0; } +DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkCommand) +{ + PARAM_PROLOGUE; + PARAM_NAME(cmd); + PARAM_VA_POINTER(va_reginfo); + + VMVa_List args = { param + 1, 0, numparam - 2, va_reginfo + 1 }; + ACTION_RETURN_BOOL(currentVMLevel->localEventManager->SendNetworkCommand(cmd, args)); +} + +DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkBuffer) +{ + PARAM_PROLOGUE; + PARAM_NAME(cmd); + PARAM_OBJECT(buffer, DNetworkBuffer); + + ACTION_RETURN_BOOL(currentVMLevel->localEventManager->SendNetworkBuffer(cmd, buffer)); +} + DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkEvent) { PARAM_PROLOGUE; @@ -680,6 +1578,21 @@ DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkEvent) ACTION_RETURN_BOOL(currentVMLevel->localEventManager->SendNetworkEvent(name, arg1, arg2, arg3, false)); } +DEFINE_ACTION_FUNCTION(DEventHandler, SendInterfaceEvent) +{ + PARAM_PROLOGUE; + PARAM_INT(playerNum); + PARAM_STRING(name); + PARAM_INT(arg1); + PARAM_INT(arg2); + PARAM_INT(arg3); + + if (playerNum == consoleplayer) + primaryLevel->localEventManager->Console(-1, name, arg1, arg2, arg3, false, true); + + return 0; +} + DEFINE_ACTION_FUNCTION(DEventHandler, Find) { PARAM_PROLOGUE; @@ -748,10 +1661,22 @@ FWorldEvent EventManager::SetupWorldEvent() FWorldEvent e; e.IsSaveGame = savegamerestore; e.IsReopen = Level->FromSnapshot && !savegamerestore; // each one by itself isnt helpful, but with hub load we have savegamerestore==0 and level.FromSnapshot==1. - e.DamageAngle = 0.0; + e.DamageAngle = nullAngle; return e; } +void DStaticEventHandler::OnEngineInitialize() +{ + IFVIRTUAL(DStaticEventHandler, OnEngineInitialize) + { + // don't create excessive DObjects if not going to be processed anyway + if (isEmpty(func)) return; + VMValue params[1] = { (DStaticEventHandler*)this }; + VMCall(func, params, 1, nullptr, 0); + } +} + + void DStaticEventHandler::WorldLoaded() { IFVIRTUAL(DStaticEventHandler, WorldLoaded) @@ -764,13 +1689,14 @@ void DStaticEventHandler::WorldLoaded() } } -void DStaticEventHandler::WorldUnloaded() +void DStaticEventHandler::WorldUnloaded(const FString& nextmap) { IFVIRTUAL(DStaticEventHandler, WorldUnloaded) { // don't create excessive DObjects if not going to be processed anyway if (isEmpty(func)) return; FWorldEvent e = owner->SetupWorldEvent(); + e.NextMap = nextmap; VMValue params[2] = { (DStaticEventHandler*)this, &e }; VMCall(func, params, 2, nullptr, 0); } @@ -803,6 +1729,21 @@ void DStaticEventHandler::WorldThingDied(AActor* actor, AActor* inflictor) } } +void DStaticEventHandler::WorldThingGround(AActor* actor, FState* st) +{ + IFVIRTUAL(DStaticEventHandler, WorldThingGround) + { + // don't create excessive DObjects if not going to be processed anyway + if (isEmpty(func)) return; + FWorldEvent e = owner->SetupWorldEvent(); + e.Thing = actor; + e.CrushedState = st; + VMValue params[2] = { (DStaticEventHandler*)this, &e }; + VMCall(func, params, 2, nullptr, 0); + } +} + + void DStaticEventHandler::WorldThingRevived(AActor* actor) { IFVIRTUAL(DStaticEventHandler, WorldThingRevived) @@ -1014,6 +1955,18 @@ void DStaticEventHandler::PlayerEntered(int num, bool fromhub) } } +void DStaticEventHandler::PlayerSpawned(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerSpawned) + { + // don't create excessive DObjects if not going to be processed anyway + if (isEmpty(func)) return; + FPlayerEvent e = { num, false }; + VMValue params[2] = { (DStaticEventHandler*)this, &e }; + VMCall(func, params, 2, nullptr, 0); + } +} + void DStaticEventHandler::PlayerRespawned(int num) { IFVIRTUAL(DStaticEventHandler, PlayerRespawned) @@ -1050,46 +2003,6 @@ void DStaticEventHandler::PlayerDisconnected(int num) } } -FUiEvent::FUiEvent(const event_t *ev) -{ - Type = (EGUIEvent)ev->subtype; - KeyChar = 0; - IsShift = false; - IsAlt = false; - IsCtrl = false; - MouseX = 0; - MouseY = 0; - // we don't want the modders to remember what weird fields mean what for what events. - switch (ev->subtype) - { - case EV_GUI_None: - break; - case EV_GUI_KeyDown: - case EV_GUI_KeyRepeat: - case EV_GUI_KeyUp: - KeyChar = ev->data1; - KeyString = FString(char(ev->data1)); - IsShift = !!(ev->data3 & GKM_SHIFT); - IsAlt = !!(ev->data3 & GKM_ALT); - IsCtrl = !!(ev->data3 & GKM_CTRL); - break; - case EV_GUI_Char: - KeyChar = ev->data1; - KeyString = MakeUTF8(ev->data1); - IsAlt = !!ev->data2; // only true for Win32, not sure about SDL - break; - default: // mouse event - // note: SDL input doesn't seem to provide these at all - //Printf("Mouse data: %d, %d, %d, %d\n", ev->x, ev->y, ev->data1, ev->data2); - MouseX = ev->data1; - MouseY = ev->data2; - IsShift = !!(ev->data3 & GKM_SHIFT); - IsAlt = !!(ev->data3 & GKM_ALT); - IsCtrl = !!(ev->data3 & GKM_CTRL); - break; - } -} - bool DStaticEventHandler::UiProcess(const event_t* ev) { IFVIRTUAL(DStaticEventHandler, UiProcess) @@ -1108,33 +2021,6 @@ bool DStaticEventHandler::UiProcess(const event_t* ev) return false; } -FInputEvent::FInputEvent(const event_t *ev) -{ - Type = (EGenericEvent)ev->type; - // we don't want the modders to remember what weird fields mean what for what events. - KeyScan = 0; - KeyChar = 0; - MouseX = 0; - MouseY = 0; - switch (Type) - { - case EV_None: - break; - case EV_KeyDown: - case EV_KeyUp: - KeyScan = ev->data1; - KeyChar = ev->data2; - KeyString = FString(char(ev->data1)); - break; - case EV_Mouse: - MouseX = ev->x; - MouseY = ev->y; - break; - default: - break; // EV_DeviceChange = wat? - } -} - bool DStaticEventHandler::InputProcess(const event_t* ev) { IFVIRTUAL(DStaticEventHandler, InputProcess) @@ -1176,26 +2062,63 @@ void DStaticEventHandler::PostUiTick() } } -void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual) +void DStaticEventHandler::NetCommandProcess(FNetworkCommand& cmd) { - if (player < 0) + IFVIRTUAL(DStaticEventHandler, NetworkCommandProcess) { - IFVIRTUAL(DStaticEventHandler, ConsoleProcess) - { - // don't create excessive DObjects if not going to be processed anyway - if (isEmpty(func)) return; - FConsoleEvent e; + if (isEmpty(func)) + return; - // - e.Player = player; - e.Name = name; - e.Args[0] = arg1; - e.Args[1] = arg2; - e.Args[2] = arg3; - e.IsManual = manual; + VMValue params[] = { this, &cmd }; + VMCall(func, params, 2, nullptr, 0); - VMValue params[2] = { (DStaticEventHandler*)this, &e }; - VMCall(func, params, 2, nullptr, 0); + cmd.Reset(); + } +} + +void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui) +{ + if (player < 0) + { + if (ui) + { + IFVIRTUAL(DStaticEventHandler, InterfaceProcess) + { + // don't create excessive DObjects if not going to be processed anyway + if (isEmpty(func)) return; + FConsoleEvent e; + + // + e.Player = player; + e.Name = name; + e.Args[0] = arg1; + e.Args[1] = arg2; + e.Args[2] = arg3; + e.IsManual = manual; + + VMValue params[2] = { (DStaticEventHandler*)this, &e }; + VMCall(func, params, 2, nullptr, 0); + } + } + else + { + IFVIRTUAL(DStaticEventHandler, ConsoleProcess) + { + // don't create excessive DObjects if not going to be processed anyway + if (isEmpty(func)) return; + FConsoleEvent e; + + // + e.Player = player; + e.Name = name; + e.Args[0] = arg1; + e.Args[1] = arg2; + e.Args[2] = arg3; + e.IsManual = manual; + + VMValue params[2] = { (DStaticEventHandler*)this, &e }; + VMCall(func, params, 2, nullptr, 0); + } } } else @@ -1271,6 +2194,25 @@ void DStaticEventHandler::OnDestroy() // console stuff // this is kinda like puke, except it distinguishes between local events and playsim events. +CCMD(interfaceevent) +{ + int argc = argv.argc(); + + if (argc < 2 || argc > 5) + { + Printf("Usage: interfaceevent [arg1] [arg2] [arg3]\n"); + } + else + { + int arg[3] = { 0, 0, 0 }; + int argn = min(argc - 2, countof(arg)); + for (int i = 0; i < argn; i++) + arg[i] = atoi(argv[2 + i]); + // call locally + primaryLevel->localEventManager->Console(-1, argv[1], arg[0], arg[1], arg[2], true, true); + } +} + CCMD(event) { int argc = argv.argc(); @@ -1282,11 +2224,11 @@ CCMD(event) else { int arg[3] = { 0, 0, 0 }; - int argn = MIN(argc - 2, countof(arg)); + int argn = min(argc - 2, countof(arg)); for (int i = 0; i < argn; i++) arg[i] = atoi(argv[2 + i]); // call locally - primaryLevel->localEventManager->Console(-1, argv[1], arg[0], arg[1], arg[2], true); + primaryLevel->localEventManager->Console(-1, argv[1], arg[0], arg[1], arg[2], true, false); } } @@ -1307,7 +2249,7 @@ CCMD(netevent) else { int arg[3] = { 0, 0, 0 }; - int argn = MIN(argc - 2, countof(arg)); + int argn = min(argc - 2, countof(arg)); for (int i = 0; i < argn; i++) arg[i] = atoi(argv[2 + i]); // call networked diff --git a/src/events.h b/src/events.h index 52bf9ac2170..d71922b9a8b 100755 --- a/src/events.h +++ b/src/events.h @@ -1,13 +1,18 @@ #pragma once +#include #include "dobject.h" #include "serializer.h" #include "d_event.h" -#include "d_gui.h" #include "sbar.h" +#include "info.h" +#include "vm.h" class DStaticEventHandler; struct EventManager; +struct line_t; +struct sector_t; +struct FLevelLocals; enum class EventHandlerType { @@ -15,6 +20,229 @@ enum class EventHandlerType PerMap }; +enum ENetCmd +{ + NET_INT8 = 1, + NET_INT16, + NET_INT, + NET_FLOAT, + NET_DOUBLE, + NET_STRING, +}; + +struct FNetworkCommand +{ +private: + size_t _index = 0; + TArray _stream; + +public: + int Player; + FName Command; + + FNetworkCommand(const int player, const FName& command, TArray& stream) : Player(player), Command(command) + { + _stream.Swap(stream); + } + + inline bool EndOfStream() const + { + return _index >= _stream.Size(); + } + + inline void Reset() + { + _index = 0; + } + + int ReadInt8() + { + if (EndOfStream()) + return 0; + + return _stream[_index++]; + } + + // If a value has to cut off early, just treat the previous value as the full one. + int ReadInt16() + { + if (EndOfStream()) + return 0; + + int value = _stream[_index++]; + if (!EndOfStream()) + value = (value << 8) | _stream[_index++]; + + return value; + } + + int ReadInt() + { + if (EndOfStream()) + return 0; + + int value = _stream[_index++]; + if (!EndOfStream()) + { + value = (value << 8) | _stream[_index++]; + if (!EndOfStream()) + { + value = (value << 8) | _stream[_index++]; + if (!EndOfStream()) + value = (value << 8) | _stream[_index++]; + } + } + + return value; + } + + // Floats without their first bits are pretty meaningless so those are done first. + double ReadFloat() + { + if (EndOfStream()) + return 0.0; + + int value = _stream[_index++] << 24; + if (!EndOfStream()) + { + value |= _stream[_index++] << 16; + if (!EndOfStream()) + { + value |= _stream[_index++] << 8; + if (!EndOfStream()) + value |= _stream[_index++]; + } + } + + union + { + int32_t i; + float f; + } floatCaster; + floatCaster.i = value; + return floatCaster.f; + } + + double ReadDouble() + { + if (EndOfStream()) + return 0.0; + + int64_t value = int64_t(_stream[_index++]) << 56; + if (!EndOfStream()) + { + value |= int64_t(_stream[_index++]) << 48; + if (!EndOfStream()) + { + value |= int64_t(_stream[_index++]) << 40; + if (!EndOfStream()) + { + value |= int64_t(_stream[_index++]) << 32; + if (!EndOfStream()) + { + value |= int64_t(_stream[_index++]) << 24; + if (!EndOfStream()) + { + value |= int64_t(_stream[_index++]) << 16; + if (!EndOfStream()) + { + value |= int64_t(_stream[_index++]) << 8; + if (!EndOfStream()) + value |= int64_t(_stream[_index++]); + } + } + } + } + } + } + + union + { + int64_t i; + double f; + } floatCaster; + floatCaster.i = value; + return floatCaster.f; + } + + const char* ReadString() + { + if (EndOfStream()) + return nullptr; + + const char* str = reinterpret_cast(&_stream[_index]); + _index += strlen(str) + 1; + return str; + } +}; + +class DNetworkBuffer final : public DObject +{ + DECLARE_CLASS(DNetworkBuffer, DObject) + +public: + struct BufferValue + { + private: + ENetCmd _type; + std::variant _message; + + public: + BufferValue(const ENetCmd type, const int message) : _type(type), _message(message) {} + BufferValue(const ENetCmd type, const double message) : _type(type), _message(message) {} + BufferValue(const ENetCmd type, const FString& message) : _type(type), _message(message) {} + + inline ENetCmd GetType() const + { + return _type; + } + + inline int GetInt() const + { + return std::get(_message); + } + + inline double GetDouble() const + { + return std::get(_message); + } + + inline const char* GetString() const + { + return std::get(_message).GetChars(); + } + }; + +private: + unsigned int _size = 0u; + TArray _buffer = {}; + +public: + inline unsigned int GetBytes() const + { + return _size; + } + + inline unsigned int GetBufferSize() const + { + return _buffer.Size(); + } + + inline const BufferValue& GetValue(unsigned int i) const + { + return _buffer[i]; + } + + void AddInt8(int byte); + void AddInt16(int word); + void AddInt(int msg); + void AddFloat(double msg); + void AddDouble(double msg); + void AddString(const FString& msg); + void OnDestroy() override; + void Serialize(FSerializer& arc) override; +}; + // ============================================== // // EventHandler - base class @@ -74,10 +302,12 @@ class DStaticEventHandler : public DObject // make it a part of normal GC proces void OnUnregister(); // + void OnEngineInitialize(); void WorldLoaded(); - void WorldUnloaded(); + void WorldUnloaded(const FString& nextmap); void WorldThingSpawned(AActor* actor); void WorldThingDied(AActor* actor, AActor* inflictor); + void WorldThingGround(AActor* actor, FState* st); void WorldThingRevived(AActor* actor); void WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle); void WorldThingDestroyed(AActor* actor); @@ -95,6 +325,7 @@ class DStaticEventHandler : public DObject // make it a part of normal GC proces // void PlayerEntered(int num, bool fromhub); + void PlayerSpawned(int num); void PlayerRespawned(int num); void PlayerDied(int num); void PlayerDisconnected(int num); @@ -106,7 +337,8 @@ class DStaticEventHandler : public DObject // make it a part of normal GC proces void PostUiTick(); // - void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual); + void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui); + void NetCommandProcess(FNetworkCommand& cmd); // void CheckReplacement(PClassActor* replacee, PClassActor** replacement, bool* final); @@ -139,6 +371,7 @@ struct FWorldEvent // for loaded/unloaded bool IsSaveGame = false; bool IsReopen = false; + FString NextMap; // for thingspawned, thingdied, thingdestroyed AActor* Thing = nullptr; // for thingdied AActor* Inflictor = nullptr; // can be null - for damagemobj @@ -159,6 +392,7 @@ struct FWorldEvent DVector3 DamagePosition; bool DamageIsRadius; // radius damage yes/no int NewDamage = 0; // sector/line damaged. allows modifying damage + FState* CrushedState = nullptr; // custom crush state set in thingground }; struct FPlayerEvent @@ -172,39 +406,6 @@ struct FPlayerEvent bool IsReturn; }; -struct FUiEvent -{ - // this essentially translates event_t UI events to ZScript. - EGUIEvent Type; - // for keys/chars/whatever - FString KeyString; - int KeyChar; - // for mouse - int MouseX; - int MouseY; - // global (?) - bool IsShift; - bool IsCtrl; - bool IsAlt; - - FUiEvent(const event_t *ev); -}; - -struct FInputEvent -{ - // this translates regular event_t events to ZScript (not UI, UI events are sent via DUiEvent and only if requested!) - EGenericEvent Type = EV_None; - // for keys - int KeyScan; - FString KeyString; - int KeyChar; - // for mouse - int MouseX; - int MouseY; - - FInputEvent(const event_t *ev); -}; - struct FConsoleEvent { // player that activated this event. note that it's always -1 for non-playsim events (i.e. these not called with netevent) @@ -256,14 +457,18 @@ struct EventManager // shutdown handlers void Shutdown(); + // after the engine is done creating data + void OnEngineInitialize(); // called right after the map has loaded (approximately same time as OPEN ACS scripts) void WorldLoaded(); // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) - void WorldUnloaded(); + void WorldUnloaded(const FString& nextmap); // called around PostBeginPlay of each actor. void WorldThingSpawned(AActor* actor); // called after AActor::Die of each actor. void WorldThingDied(AActor* actor, AActor* inflictor); + // called inside AActor::Grind just before the corpse is destroyed + void WorldThingGround(AActor* actor, FState* st); // called after AActor::Revive. void WorldThingRevived(AActor* actor); // called before P_DamageMobj and before AActor::DamageMobj virtuals. @@ -294,6 +499,8 @@ struct EventManager void RenderUnderlay(EHudState state); // this executes when a player enters the level (once). PlayerEnter+inhub = RETURN void PlayerEntered(int num, bool fromhub); + // this executes at the same time as ENTER scripts + void PlayerSpawned(int num); // this executes when a player respawns. includes resurrect cheat. void PlayerRespawned(int num); // this executes when a player dies (partially duplicating worldthingdied, but whatever) @@ -303,7 +510,9 @@ struct EventManager // this executes on events. bool Responder(const event_t* ev); // splits events into InputProcess and UiProcess // this executes on console/net events. - void Console(int player, FString name, int arg1, int arg2, int arg3, bool manual); + void Console(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui); + // This reads from ZScript network commands. + void NetCommand(FNetworkCommand& cmd); // called when looking up the replacement for an actor class bool CheckReplacement(PClassActor* replacee, PClassActor** replacement); @@ -315,6 +524,10 @@ struct EventManager // send networked event. unified function. bool SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual); + // Send a custom network command from ZScript. + bool SendNetworkCommand(const FName& cmd, VMVa_List& args); + // Send a pre-built command buffer over. + bool SendNetworkBuffer(const FName& cmd, const DNetworkBuffer* buffer); // check if there is anything that should receive GUI events bool CheckUiProcessors(); diff --git a/src/g_cvars.cpp b/src/g_cvars.cpp index db029c56660..14c83256853 100644 --- a/src/g_cvars.cpp +++ b/src/g_cvars.cpp @@ -41,6 +41,7 @@ #include "v_font.h" #include "utf8.h" #include "gi.h" +#include "i_interface.h" void I_UpdateWindowTitle(); @@ -50,15 +51,9 @@ CVAR(Bool, gl_cachenodes, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Float, gl_cachetime, 0.6f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, alwaysapplydmflags, false, CVAR_SERVERINFO); -// Show developer messages if true. -CVAR(Int, developer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - // [RH] Feature control cvars CVAR(Bool, var_friction, true, CVAR_SERVERINFO); -// Option Search -CVAR(Bool, os_isanyof, true, CVAR_ARCHIVE); - CUSTOM_CVAR (Int, turnspeedwalkfast, 640, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (self <= 0) self = 1; @@ -153,57 +148,4 @@ CUSTOM_CVAR(Float, teamdamage, 0.f, CVAR_SERVERINFO | CVAR_NOINITCALL) } } -bool generic_ui; -EXTERN_CVAR(String, language) - -bool CheckFontComplete(FFont *font) -{ - // Also check if the SmallFont contains all characters this language needs. - // If not, switch back to the original one. - return font->CanPrint(GStrings["REQUIRED_CHARACTERS"]); -} - -void UpdateGenericUI(bool cvar) -{ - auto switchstr = GStrings["USE_GENERIC_FONT"]; - generic_ui = (cvar || (switchstr && strtoll(switchstr, nullptr, 0)) || ((gameinfo.gametype & GAME_Raven) && !strnicmp(language, "el", 2))); - if (!generic_ui) - { - // Use the mod's SmallFont if it is complete. - // Otherwise use the stock Smallfont if it is complete. - // If none is complete, fall back to the VGA font. - // The font being set here will be used in 3 places: Notifications, centered messages and menu confirmations. - if (CheckFontComplete(SmallFont)) - { - AlternativeSmallFont = SmallFont; - } - else if (OriginalSmallFont && CheckFontComplete(OriginalSmallFont)) - { - AlternativeSmallFont = OriginalSmallFont; - } - else - { - AlternativeSmallFont = NewSmallFont; - } - - // Todo: Do the same for the BigFont - } -} - -CUSTOM_CVAR(Bool, ui_generic, false, CVAR_NOINITCALL) // This is for allowing to test the generic font system with all languages -{ - UpdateGenericUI(self); -} - - -CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) -{ - GStrings.UpdateLanguage(); - for (auto Level : AllLevels()) - { - // does this even make sense on secondary levels...? - if (Level->info != nullptr) Level->LevelName = Level->info->LookupLevelName(); - } - UpdateGenericUI(ui_generic); - I_UpdateWindowTitle(); -} +CVAR(Float, cl_scaleweaponfov, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) diff --git a/src/g_dumpinfo.cpp b/src/g_dumpinfo.cpp index c21525b8b35..227b98f501e 100644 --- a/src/g_dumpinfo.cpp +++ b/src/g_dumpinfo.cpp @@ -39,10 +39,12 @@ #include "a_sharedglobal.h" #include "d_net.h" #include "p_setup.h" -#include "w_wad.h" +#include "filesystem.h" #include "v_text.h" #include "c_functions.h" #include "gstrings.h" +#include "texturemanager.h" +#include "d_main.h" //========================================================================== // @@ -73,8 +75,8 @@ CCMD(listlights) if (dl->target) { - FTextureID spr = sprites[dl->target->sprite].GetSpriteFrame(dl->target->frame, 0, 0., nullptr); - Printf(", frame = %s ", TexMan.GetTexture(spr)->GetName().GetChars()); + FTextureID spr = sprites[dl->target->sprite].GetSpriteFrame(dl->target->frame, 0, nullAngle, nullptr); + Printf(", frame = %s ", TexMan.GetGameTexture(spr)->GetName().GetChars()); } @@ -121,13 +123,13 @@ CCMD (countdecals) CCMD (spray) { - if (who == NULL || argv.argc() < 2) + if (players[consoleplayer].mo == NULL || argv.argc() < 2) { Printf ("Usage: spray \n"); return; } - Net_WriteByte (DEM_SPRAY); + Net_WriteInt8 (DEM_SPRAY); Net_WriteString (argv[1]); } @@ -156,7 +158,7 @@ CCMD (mapchecksum) else { map->GetChecksum(cksum); - const char *wadname = Wads.GetWadName(Wads.GetLumpFile(map->lumpnum)); + const char *wadname = fileSystem.GetResourceFileName(fileSystem.GetFileContainer(map->lumpnum)); delete map; for (size_t j = 0; j < sizeof(cksum); ++j) { @@ -359,15 +361,30 @@ CCMD(targetinv) CCMD(listmaps) { + int iwadNum = fileSystem.GetIwadNum(); + for (unsigned i = 0; i < wadlevelinfos.Size(); i++) { level_info_t *info = &wadlevelinfos[i]; - MapData *map = P_OpenMapData(info->MapName, true); + MapData *map = P_OpenMapData(info->MapName.GetChars(), true); if (map != NULL) { - Printf("%s: '%s' (%s)\n", info->MapName.GetChars(), info->LookupLevelName().GetChars(), - Wads.GetWadName(Wads.GetLumpFile(map->lumpnum))); + int mapWadNum = fileSystem.GetFileContainer(map->lumpnum); + + if (argv.argc() == 1 + || CheckWildcards(argv[1], info->MapName.GetChars()) + || CheckWildcards(argv[1], info->LookupLevelName().GetChars()) + || CheckWildcards(argv[1], fileSystem.GetResourceFileName(mapWadNum))) + { + bool isFromPwad = mapWadNum != iwadNum; + + const char* lineColor = isFromPwad ? TEXTCOLOR_LIGHTBLUE : ""; + + Printf("%s%s: '%s' (%s)\n", lineColor, info->MapName.GetChars(), + info->LookupLevelName().GetChars(), + fileSystem.GetResourceFileName(mapWadNum)); + } delete map; } } @@ -383,7 +400,7 @@ CCMD(skyfog) if (argv.argc() > 1) { // Do this only on the primary level. - primaryLevel->skyfog = MAX(0, (int)strtoull(argv[1], NULL, 0)); + primaryLevel->skyfog = max(0, (int)strtoull(argv[1], NULL, 0)); } } @@ -404,23 +421,3 @@ CCMD(listsnapshots) } } } - - -CCMD(printlocalized) -{ - if (argv.argc() > 1) - { - if (argv.argc() > 2) - { - FString lang = argv[2]; - lang.ToLower(); - if (lang.Len() >= 2) - { - Printf("%s\n", GStrings.GetLanguageString(argv[1], MAKE_ID(lang[0], lang[1], lang[2], 0))); - return; - } - } - Printf("%s\n", GStrings(argv[1])); - } - -} diff --git a/src/g_game.cpp b/src/g_game.cpp index 300e4bb3513..105b16aa74c 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -29,7 +29,7 @@ #include #include "i_time.h" -#include "templates.h" + #include "version.h" #include "doomdef.h" #include "doomstat.h" @@ -38,7 +38,7 @@ #include "intermission/intermission.h" #include "m_argv.h" #include "m_misc.h" -#include "menu/menu.h" +#include "menu.h" #include "m_crc32.h" #include "p_saveg.h" #include "p_tick.h" @@ -50,7 +50,7 @@ #include "c_console.h" #include "c_bind.h" #include "c_dispatch.h" -#include "w_wad.h" +#include "filesystem.h" #include "p_local.h" #include "gstrings.h" #include "r_sky.h" @@ -67,22 +67,36 @@ #include "r_utility.h" #include "a_morph.h" #include "p_spec.h" -#include "serializer.h" +#include "serializer_doom.h" #include "vm.h" #include "dobjgc.h" #include "gi.h" #include "a_dynlight.h" #include "i_system.h" #include "p_conversation.h" +#include "v_palette.h" +#include "s_music.h" +#include "p_setup.h" +#include "d_event.h" +#include "model.h" +#include "v_video.h" #include "g_hub.h" #include "g_levellocals.h" #include "events.h" +#include "c_buttons.h" +#include "d_buttons.h" +#include "hwrenderer/scene/hw_drawinfo.h" +#include "doommenu.h" +#include "screenjob.h" +#include "i_interface.h" +#include "fs_findfile.h" static FRandom pr_dmspawn ("DMSpawn"); static FRandom pr_pspawn ("PlayerSpawn"); +bool WriteZip(const char* filename, const FileSys::FCompressedBuffer* content, size_t contentcount); bool G_CheckDemoStatus (void); void G_ReadDemoTiccmd (ticcmd_t *cmd, int player); void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf); @@ -99,17 +113,16 @@ void G_DoAutoSave (); void G_DoQuickSave (); void STAT_Serialize(FSerializer &file); -bool WriteZip(const char *filename, TArray &filenames, TArray &content); -FIntCVar gameskill ("skill", 2, CVAR_SERVERINFO|CVAR_LATCH); +CVARD_NAMED(Int, gameskill, skill, 2, CVAR_SERVERINFO|CVAR_LATCH, "sets the skill for the next newly started game") CVAR(Bool, save_formatted, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // use formatted JSON for saves (more readable but a larger files and a bit slower. CVAR (Int, deathmatch, 0, CVAR_SERVERINFO|CVAR_LATCH); CVAR (Bool, chasedemo, false, 0); CVAR (Bool, storesavepic, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, longsavemessages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (String, save_dir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); +CVAR (Bool, longsavemessages, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, cl_waitforsave, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR (Bool, enablescriptscreenshot, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR (Bool, cl_restartondeath, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); EXTERN_CVAR (Float, con_midtime); //========================================================================== @@ -130,13 +143,10 @@ CUSTOM_CVAR (Int, displaynametags, 0, CVAR_ARCHIVE) CVAR(Int, nametagcolor, CR_GOLD, CVAR_ARCHIVE) +extern bool playedtitlemusic; gameaction_t gameaction; -gamestate_t gamestate = GS_STARTUP; -FName SelectedSlideshow; // what to start when ga_slideshow -int paused; -bool pauseext; bool sendpause; // send a pause event next tic bool sendsave; // send a save event next tic bool sendturn180; // [RH] send a 180 degree turn next tic @@ -149,13 +159,10 @@ bool noblit; // for comparative timing purposes bool viewactive; -bool netgame; // only true if packets are broadcast -bool multiplayer; bool multiplayernext = false; // [SP] Map coop/dm implementation player_t players[MAXPLAYERS]; bool playeringame[MAXPLAYERS]; -int consoleplayer; // player taking events int gametic; CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); @@ -190,26 +197,26 @@ EXTERN_CVAR (Int, turnspeedwalkslow) EXTERN_CVAR (Int, turnspeedsprintslow) int forwardmove[2], sidemove[2]; -FIntCVar *angleturn[4] = {&turnspeedwalkfast, &turnspeedsprintfast, &turnspeedwalkslow, &turnspeedsprintslow}; +FIntCVarRef *angleturn[4] = {&turnspeedwalkfast, &turnspeedsprintfast, &turnspeedwalkslow, &turnspeedsprintslow}; int flyspeed[2] = {1*256, 3*256}; int lookspeed[2] = {450, 512}; #define SLOWTURNTICS 6 CVAR (Bool, cl_run, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) // Always run? -CVAR (Bool, invertmouse, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) // Invert mouse look down/up? CVAR (Bool, freelook, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) // Always mlook? CVAR (Bool, lookstrafe, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) // Always strafe with mouse? -CVAR (Float, m_pitch, 1.f, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) // Mouse speeds -CVAR (Float, m_yaw, 1.f, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) CVAR (Float, m_forward, 1.f, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) CVAR (Float, m_side, 2.f, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) int turnheld; // for accelerative turning - + +EXTERN_CVAR (Bool, invertmouse) +EXTERN_CVAR (Bool, invertmousex) + // mouse values are used once -int mousex; -int mousey; +float mousex; +float mousey; FString savegamefile; FString savedescription; @@ -315,7 +322,8 @@ CCMD (slot) } // [Nash] Option to display the name of the weapon being switched to. - if (players[consoleplayer].playerstate != PST_LIVE) return; + if ((paused || pauseext) || players[consoleplayer].playerstate != PST_LIVE) + return; if (SendItemUse != players[consoleplayer].ReadyWeapon && (displaynametags & 2) && StatusBar && SmallFont && SendItemUse) { StatusBar->AttachMessage(Create(nullptr, SendItemUse->GetTag(), @@ -326,12 +334,14 @@ CCMD (slot) CCMD (centerview) { - Net_WriteByte (DEM_CENTERVIEW); + if ((players[consoleplayer].cheats & CF_TOTALLYFROZEN)) + return; + Net_WriteInt8 (DEM_CENTERVIEW); } CCMD(crouch) { - Net_WriteByte(DEM_CROUCH); + Net_WriteInt8(DEM_CROUCH); } CCMD (land) @@ -364,7 +374,7 @@ CCMD (weapnext) } // [BC] Option to display the name of the weapon being cycled to. - if (players[consoleplayer].playerstate != PST_LIVE) return; + if ((paused || pauseext) || players[consoleplayer].playerstate != PST_LIVE) return; if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse) { StatusBar->AttachMessage(Create(nullptr, SendItemUse->GetTag(), @@ -391,7 +401,7 @@ CCMD (weapprev) } // [BC] Option to display the name of the weapon being cycled to. - if (players[consoleplayer].playerstate != PST_LIVE) return; + if ((paused || pauseext) || players[consoleplayer].playerstate != PST_LIVE) return; if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse) { StatusBar->AttachMessage(Create(nullptr, SendItemUse->GetTag(), @@ -421,11 +431,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, DisplayNameTag, DisplayNameTag) CCMD (invnext) { - if (who != NULL) + if (players[consoleplayer].mo != nullptr) { IFVM(PlayerPawn, InvNext) { - VMValue param = who; + VMValue param = players[consoleplayer].mo; VMCall(func, ¶m, 1, nullptr, 0); } } @@ -433,11 +443,11 @@ CCMD (invnext) CCMD(invprev) { - if (who != NULL) + if (players[consoleplayer].mo != nullptr) { IFVM(PlayerPawn, InvPrev) { - VMValue param = who; + VMValue param = players[consoleplayer].mo; VMCall(func, ¶m, 1, nullptr, 0); } } @@ -466,11 +476,17 @@ CCMD(invquery) } } +constexpr char True[] = "true"; + CCMD (use) { - if (argv.argc() > 1 && who != NULL) + if (argv.argc() > 1 && players[consoleplayer].mo != NULL) { - SendItemUse = who->FindInventory(argv[1]); + bool subclass = false; + if (argv.argc() > 2) + subclass = !stricmp(argv[2], True) || atoi(argv[2]); + + SendItemUse = players[consoleplayer].mo->FindInventory(argv[1], subclass); } } @@ -491,19 +507,23 @@ CCMD (weapdrop) CCMD (drop) { - if (argv.argc() > 1 && who != NULL) + if (argv.argc() > 1 && players[consoleplayer].mo != NULL) { - SendItemDrop = who->FindInventory(argv[1]); + bool subclass = false; + if (argv.argc() > 3) + subclass = !stricmp(argv[3], True) || atoi(argv[3]); + + SendItemDrop = players[consoleplayer].mo->FindInventory(argv[1], subclass); SendItemDropAmount = argv.argc() > 2 ? atoi(argv[2]) : -1; } } CCMD (useflechette) { - if (who == nullptr) return; - IFVIRTUALPTRNAME(who, NAME_PlayerPawn, GetFlechetteItem) + if (players[consoleplayer].mo == nullptr) return; + IFVIRTUALPTRNAME(players[consoleplayer].mo, NAME_PlayerPawn, GetFlechetteItem) { - VMValue params[] = { who }; + VMValue params[] = { players[consoleplayer].mo }; AActor *cls; VMReturn ret((void**)&cls); VMCall(func, params, 1, &ret, 1); @@ -514,15 +534,21 @@ CCMD (useflechette) CCMD (select) { + if (!players[consoleplayer].mo) return; + auto user = players[consoleplayer].mo; if (argv.argc() > 1) { - auto item = who->FindInventory(argv[1]); + bool subclass = false; + if (argv.argc() > 2) + subclass = !stricmp(argv[2], True) || atoi(argv[2]); + + auto item = user->FindInventory(argv[1], subclass); if (item != NULL) { - who->PointerVar(NAME_InvSel) = item; + user->PointerVar(NAME_InvSel) = item; } } - who->player->inventorytics = 5*TICRATE; + user->player->inventorytics = 5*TICRATE; } static inline int joyint(double val) @@ -537,6 +563,29 @@ static inline int joyint(double val) } } +FBaseCVar* G_GetUserCVar(int playernum, const char* cvarname) +{ + if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) + { + return nullptr; + } + FBaseCVar** cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true)); + FBaseCVar* cvar; + if (cvar_p == nullptr || (cvar = *cvar_p) == nullptr || (cvar->GetFlags() & CVAR_IGNORE)) + { + return nullptr; + } + return cvar; +} + +static ticcmd_t emptycmd; + +ticcmd_t* G_BaseTiccmd() +{ + return &emptycmd; +} + + // // G_BuildTiccmd // Builds a ticcmd from all of the available inputs @@ -553,20 +602,20 @@ void G_BuildTiccmd (ticcmd_t *cmd) ticcmd_t *base; - base = I_BaseTiccmd (); // empty, or external driver + base = G_BaseTiccmd (); *cmd = *base; cmd->consistancy = consistancy[consoleplayer][(maketic/ticdup)%BACKUPTICS]; - strafe = Button_Strafe.bDown; - speed = Button_Speed.bDown ^ (int)cl_run; + strafe = buttonMap.ButtonDown(Button_Strafe); + speed = buttonMap.ButtonDown(Button_Speed) ^ (int)cl_run; forward = side = fly = 0; // [RH] only use two stage accelerative turning on the keyboard // and not the joystick, since we treat the joystick as // the analog device it is. - if (Button_Left.bDown || Button_Right.bDown) + if (buttonMap.ButtonDown(Button_Left) || buttonMap.ButtonDown(Button_Right)) turnheld += ticdup; else turnheld = 0; @@ -574,9 +623,9 @@ void G_BuildTiccmd (ticcmd_t *cmd) // let movement keys cancel each other out if (strafe) { - if (Button_Right.bDown) + if (buttonMap.ButtonDown(Button_Right)) side += sidemove[speed]; - if (Button_Left.bDown) + if (buttonMap.ButtonDown(Button_Left)) side -= sidemove[speed]; } else @@ -586,77 +635,78 @@ void G_BuildTiccmd (ticcmd_t *cmd) if (turnheld < SLOWTURNTICS) tspeed += 2; // slow turn - if (Button_Right.bDown) + if (buttonMap.ButtonDown(Button_Right)) { G_AddViewAngle (*angleturn[tspeed]); } - if (Button_Left.bDown) + if (buttonMap.ButtonDown(Button_Left)) { G_AddViewAngle (-*angleturn[tspeed]); } } - if (Button_LookUp.bDown) + if (buttonMap.ButtonDown(Button_LookUp)) { G_AddViewPitch (lookspeed[speed]); } - if (Button_LookDown.bDown) + if (buttonMap.ButtonDown(Button_LookDown)) { G_AddViewPitch (-lookspeed[speed]); } - if (Button_MoveUp.bDown) + if (buttonMap.ButtonDown(Button_MoveUp)) fly += flyspeed[speed]; - if (Button_MoveDown.bDown) + if (buttonMap.ButtonDown(Button_MoveDown)) fly -= flyspeed[speed]; - if (Button_Klook.bDown) + if (buttonMap.ButtonDown(Button_Klook)) { - if (Button_Forward.bDown) + if (buttonMap.ButtonDown(Button_Forward)) G_AddViewPitch (lookspeed[speed]); - if (Button_Back.bDown) + if (buttonMap.ButtonDown(Button_Back)) G_AddViewPitch (-lookspeed[speed]); } else { - if (Button_Forward.bDown) + if (buttonMap.ButtonDown(Button_Forward)) forward += forwardmove[speed]; - if (Button_Back.bDown) + if (buttonMap.ButtonDown(Button_Back)) forward -= forwardmove[speed]; } - if (Button_MoveRight.bDown) + if (buttonMap.ButtonDown(Button_MoveRight)) side += sidemove[speed]; - if (Button_MoveLeft.bDown) + if (buttonMap.ButtonDown(Button_MoveLeft)) side -= sidemove[speed]; // buttons - if (Button_Attack.bDown) cmd->ucmd.buttons |= BT_ATTACK; - if (Button_AltAttack.bDown) cmd->ucmd.buttons |= BT_ALTATTACK; - if (Button_Use.bDown) cmd->ucmd.buttons |= BT_USE; - if (Button_Jump.bDown) cmd->ucmd.buttons |= BT_JUMP; - if (Button_Crouch.bDown) cmd->ucmd.buttons |= BT_CROUCH; - if (Button_Zoom.bDown) cmd->ucmd.buttons |= BT_ZOOM; - if (Button_Reload.bDown) cmd->ucmd.buttons |= BT_RELOAD; - - if (Button_User1.bDown) cmd->ucmd.buttons |= BT_USER1; - if (Button_User2.bDown) cmd->ucmd.buttons |= BT_USER2; - if (Button_User3.bDown) cmd->ucmd.buttons |= BT_USER3; - if (Button_User4.bDown) cmd->ucmd.buttons |= BT_USER4; - - if (Button_Speed.bDown) cmd->ucmd.buttons |= BT_SPEED; - if (Button_Strafe.bDown) cmd->ucmd.buttons |= BT_STRAFE; - if (Button_MoveRight.bDown) cmd->ucmd.buttons |= BT_MOVERIGHT; - if (Button_MoveLeft.bDown) cmd->ucmd.buttons |= BT_MOVELEFT; - if (Button_LookDown.bDown) cmd->ucmd.buttons |= BT_LOOKDOWN; - if (Button_LookUp.bDown) cmd->ucmd.buttons |= BT_LOOKUP; - if (Button_Back.bDown) cmd->ucmd.buttons |= BT_BACK; - if (Button_Forward.bDown) cmd->ucmd.buttons |= BT_FORWARD; - if (Button_Right.bDown) cmd->ucmd.buttons |= BT_RIGHT; - if (Button_Left.bDown) cmd->ucmd.buttons |= BT_LEFT; - if (Button_MoveDown.bDown) cmd->ucmd.buttons |= BT_MOVEDOWN; - if (Button_MoveUp.bDown) cmd->ucmd.buttons |= BT_MOVEUP; - if (Button_ShowScores.bDown) cmd->ucmd.buttons |= BT_SHOWSCORES; + if (buttonMap.ButtonDown(Button_Attack)) cmd->ucmd.buttons |= BT_ATTACK; + if (buttonMap.ButtonDown(Button_AltAttack)) cmd->ucmd.buttons |= BT_ALTATTACK; + if (buttonMap.ButtonDown(Button_Use)) cmd->ucmd.buttons |= BT_USE; + if (buttonMap.ButtonDown(Button_Jump)) cmd->ucmd.buttons |= BT_JUMP; + if (buttonMap.ButtonDown(Button_Crouch)) cmd->ucmd.buttons |= BT_CROUCH; + if (buttonMap.ButtonDown(Button_Zoom)) cmd->ucmd.buttons |= BT_ZOOM; + if (buttonMap.ButtonDown(Button_Reload)) cmd->ucmd.buttons |= BT_RELOAD; + + if (buttonMap.ButtonDown(Button_User1)) cmd->ucmd.buttons |= BT_USER1; + if (buttonMap.ButtonDown(Button_User2)) cmd->ucmd.buttons |= BT_USER2; + if (buttonMap.ButtonDown(Button_User3)) cmd->ucmd.buttons |= BT_USER3; + if (buttonMap.ButtonDown(Button_User4)) cmd->ucmd.buttons |= BT_USER4; + + if (buttonMap.ButtonDown(Button_Speed)) cmd->ucmd.buttons |= BT_SPEED; + if (buttonMap.ButtonDown(Button_Strafe)) cmd->ucmd.buttons |= BT_STRAFE; + if (buttonMap.ButtonDown(Button_MoveRight)) cmd->ucmd.buttons |= BT_MOVERIGHT; + if (buttonMap.ButtonDown(Button_MoveLeft)) cmd->ucmd.buttons |= BT_MOVELEFT; + if (buttonMap.ButtonDown(Button_LookDown)) cmd->ucmd.buttons |= BT_LOOKDOWN; + if (buttonMap.ButtonDown(Button_LookUp)) cmd->ucmd.buttons |= BT_LOOKUP; + if (buttonMap.ButtonDown(Button_Back)) cmd->ucmd.buttons |= BT_BACK; + if (buttonMap.ButtonDown(Button_Forward)) cmd->ucmd.buttons |= BT_FORWARD; + if (buttonMap.ButtonDown(Button_Right)) cmd->ucmd.buttons |= BT_RIGHT; + if (buttonMap.ButtonDown(Button_Left)) cmd->ucmd.buttons |= BT_LEFT; + if (buttonMap.ButtonDown(Button_MoveDown)) cmd->ucmd.buttons |= BT_MOVEDOWN; + if (buttonMap.ButtonDown(Button_MoveUp)) cmd->ucmd.buttons |= BT_MOVEUP; + if (buttonMap.ButtonDown(Button_ShowScores)) cmd->ucmd.buttons |= BT_SHOWSCORES; + if (speed) cmd->ucmd.buttons |= BT_RUN; // Handle joysticks/game controllers. float joyaxes[NUM_JOYAXIS]; @@ -664,12 +714,12 @@ void G_BuildTiccmd (ticcmd_t *cmd) I_GetAxes(joyaxes); // Remap some axes depending on button state. - if (Button_Strafe.bDown || (Button_Mlook.bDown && lookstrafe)) + if (buttonMap.ButtonDown(Button_Strafe) || (buttonMap.ButtonDown(Button_Mlook) && lookstrafe)) { joyaxes[JOYAXIS_Side] = joyaxes[JOYAXIS_Yaw]; joyaxes[JOYAXIS_Yaw] = 0; } - if (Button_Mlook.bDown) + if (buttonMap.ButtonDown(Button_Mlook)) { joyaxes[JOYAXIS_Pitch] = joyaxes[JOYAXIS_Forward]; joyaxes[JOYAXIS_Forward] = 0; @@ -689,9 +739,9 @@ void G_BuildTiccmd (ticcmd_t *cmd) fly += joyint(joyaxes[JOYAXIS_Up] * 2048); // Handle mice. - if (!Button_Mlook.bDown && !freelook) + if (!buttonMap.ButtonDown(Button_Mlook) && !freelook) { - forward += (int)((float)mousey * m_forward); + forward += xs_CRoundToInt(mousey * m_forward); } cmd->ucmd.pitch = LocalViewPitch >> 16; @@ -703,7 +753,7 @@ void G_BuildTiccmd (ticcmd_t *cmd) } if (strafe || lookstrafe) - side += (int)((float)mousex * m_side); + side += xs_CRoundToInt(mousex * m_side); mousex = mousey = 0; @@ -733,32 +783,32 @@ void G_BuildTiccmd (ticcmd_t *cmd) if (sendpause) { sendpause = false; - Net_WriteByte (DEM_PAUSE); + Net_WriteInt8 (DEM_PAUSE); } if (sendsave) { sendsave = false; - Net_WriteByte (DEM_SAVEGAME); - Net_WriteString (savegamefile); - Net_WriteString (savedescription); + Net_WriteInt8 (DEM_SAVEGAME); + Net_WriteString (savegamefile.GetChars()); + Net_WriteString (savedescription.GetChars()); savegamefile = ""; } if (SendItemUse == (const AActor *)1) { - Net_WriteByte (DEM_INVUSEALL); + Net_WriteInt8 (DEM_INVUSEALL); SendItemUse = NULL; } else if (SendItemUse != NULL) { - Net_WriteByte (DEM_INVUSE); - Net_WriteLong (SendItemUse->InventoryID); + Net_WriteInt8 (DEM_INVUSE); + Net_WriteInt32 (SendItemUse->InventoryID); SendItemUse = NULL; } if (SendItemDrop != NULL) { - Net_WriteByte (DEM_INVDROP); - Net_WriteLong (SendItemDrop->InventoryID); - Net_WriteLong(SendItemDropAmount); + Net_WriteInt8 (DEM_INVDROP); + Net_WriteInt32 (SendItemDrop->InventoryID); + Net_WriteInt32(SendItemDropAmount); SendItemDrop = NULL; } @@ -766,9 +816,6 @@ void G_BuildTiccmd (ticcmd_t *cmd) cmd->ucmd.sidemove <<= 8; } -//[Graf Zahl] This really helps if the mouse update rate can't be increased! -CVAR (Bool, smooth_mouse, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) - static int LookAdjust(int look) { look <<= 16; @@ -809,7 +856,7 @@ void G_AddViewPitch (int look, bool mouse) } else { - LocalViewPitch = MIN(LocalViewPitch + look, 0x78000000); + LocalViewPitch = min(LocalViewPitch + look, 0x78000000); } } else if (look < 0) @@ -821,12 +868,12 @@ void G_AddViewPitch (int look, bool mouse) } else { - LocalViewPitch = MAX(LocalViewPitch + look, -0x78000000); + LocalViewPitch = max(LocalViewPitch + look, -0x78000000); } } if (look != 0) { - LocalKeyboardTurner = (!mouse || smooth_mouse); + LocalKeyboardTurner = !mouse; } } @@ -841,7 +888,7 @@ void G_AddViewAngle (int yaw, bool mouse) LocalViewAngle -= yaw; if (yaw != 0) { - LocalKeyboardTurner = (!mouse || smooth_mouse); + LocalKeyboardTurner = !mouse; } } @@ -871,7 +918,7 @@ static void ChangeSpy (int changespy) // has done this for you, since it could desync otherwise. if (!demoplayback) { - Net_WriteByte(DEM_REVERTCAMERA); + Net_WriteInt8(DEM_REVERTCAMERA); } return; } @@ -937,6 +984,15 @@ CCMD (spycancel) // bool G_Responder (event_t *ev) { + // check events + if (ev->type != EV_Mouse && primaryLevel->localEventManager->Responder(ev)) // [ZZ] ZScript ate the event // update 07.03.17: mouse events are handled directly + return true; + + if (gamestate == GS_INTRO || gamestate == GS_CUTSCENE) + { + return ScreenJobResponder(ev); + } + // any other key pops up menu if in demos // [RH] But only if the key isn't bound to a "special" command if (gameaction == ga_nothing && @@ -982,14 +1038,9 @@ bool G_Responder (event_t *ev) { if (ST_Responder (ev)) return true; // status window ate it - if (!viewactive && primaryLevel->automap->Responder (ev, false)) + if (!viewactive && primaryLevel->automap && primaryLevel->automap->Responder (ev, false)) return true; // automap ate it } - else if (gamestate == GS_FINALE) - { - if (F_Responder (ev)) - return true; // finale ate the event - } switch (ev->type) { @@ -1003,9 +1054,23 @@ bool G_Responder (event_t *ev) break; // [RH] mouse buttons are sent as key up/down events - case EV_Mouse: - mousex = (int)(ev->x * mouse_sensitivity); - mousey = (int)(ev->y * mouse_sensitivity); + case EV_Mouse: + if(invertmousex) + { + mousex = -ev->x; + } + else + { + mousex = ev->x; + } + if(invertmouse) + { + mousey = -ev->y; + } + else + { + mousey = ev->y; + } break; } @@ -1020,6 +1085,51 @@ bool G_Responder (event_t *ev) } +static void G_FullConsole() +{ + int oldgs = gamestate; + + if (hud_toggled) + D_ToggleHud(); + if (demoplayback) + G_CheckDemoStatus(); + D_QuitNetGame(); + advancedemo = false; + C_FullConsole(); + + if (oldgs != GS_STARTUP) + { + primaryLevel->Music = ""; + S_Start(); + S_StopMusic(true); + P_FreeLevelData(false); + } + +} + +//========================================================================== +// +// FRandom :: StaticSumSeeds +// +// This function produces a uint32_t that can be used to check the consistancy +// of network games between different machines. Only a select few RNGs are +// used for the sum, because not all RNGs are important to network sync. +// +//========================================================================== + +extern FRandom pr_spawnmobj; +extern FRandom pr_acs; +extern FRandom pr_chase; +extern FRandom pr_damagemobj; + +static uint32_t StaticSumSeeds() +{ + return + pr_spawnmobj.Seed() + + pr_acs.Seed() + + pr_chase.Seed() + + pr_damagemobj.Seed(); +} // // G_Ticker @@ -1049,7 +1159,7 @@ void G_Ticker () if (ToggleFullscreen) { ToggleFullscreen = false; - AddCommandString ("toggle fullscreen"); + AddCommandString ("toggle vid_fullscreen"); } // do things to change the game state @@ -1065,8 +1175,9 @@ void G_Ticker () { case ga_recordgame: G_CheckDemoStatus(); - G_RecordDemo(newdemoname); - G_BeginRecording(newdemomap); + G_RecordDemo(newdemoname.GetChars()); + G_BeginRecording(newdemomap.GetChars()); + [[fallthrough]]; case ga_newgame2: // Silence GCC (see above) case ga_newgame: G_DoNewGame (); @@ -1077,7 +1188,7 @@ void G_Ticker () G_DoLoadGame (); break; case ga_savegame: - G_DoSaveGame (true, false, savegamefile, savedescription); + G_DoSaveGame (true, false, savegamefile, savedescription.GetChars()); gameaction = ga_nothing; savegamefile = ""; savedescription = ""; @@ -1089,25 +1200,22 @@ void G_Ticker () case ga_loadgameplaydemo: G_DoLoadGame (); // fallthrough - case ga_playdemo: + case ga_playdemo: G_DoPlayDemo (); break; case ga_completed: G_DoCompleted (); break; - case ga_slideshow: - if (gamestate == GS_LEVEL) F_StartIntermission(SelectedSlideshow, FSTATE_InLevel); - break; case ga_worlddone: G_DoWorldDone (); break; case ga_screenshot: - M_ScreenShot (shotfile); + M_ScreenShot (shotfile.GetChars()); shotfile = ""; gameaction = ga_nothing; break; case ga_fullconsole: - C_FullConsole (); + G_FullConsole (); gameaction = ga_nothing; break; case ga_togglemap: @@ -1118,6 +1226,20 @@ void G_Ticker () P_ResumeConversation (); gameaction = ga_nothing; break; + case ga_intermission: + gamestate = GS_CUTSCENE; + gameaction = ga_nothing; + break; + case ga_titleloop: + D_StartTitle(); + break; + case ga_intro: + gamestate = GS_INTRO; + gameaction = ga_nothing; + break; + + + default: case ga_nothing: break; @@ -1125,20 +1247,12 @@ void G_Ticker () C_AdjustBottom (); } - if (oldgamestate != gamestate) - { - if (oldgamestate == GS_FINALE) - { - F_EndFinale (); - } - } - // get commands, check consistancy, and build new consistancy check int buf = (gametic/ticdup)%BACKUPTICS; // [RH] Include some random seeds and player stuff in the consistancy // check, not just the player's x position like BOOM. - uint32_t rngsum = FRandom::StaticSumSeeds (); + uint32_t rngsum = StaticSumSeeds (); //Added by MC: For some of that bot stuff. The main bot function. primaryLevel->BotInfo.Main (primaryLevel); @@ -1215,14 +1329,6 @@ void G_Ticker () P_Ticker (); break; - case GS_INTERMISSION: - WI_Ticker (); - break; - - case GS_FINALE: - F_Ticker (); - break; - case GS_DEMOSCREEN: D_PageTicker (); break; @@ -1235,6 +1341,15 @@ void G_Ticker () } break; + case GS_CUTSCENE: + case GS_INTRO: + if (ScreenJobTick()) + { + // synchronize termination with the playsim. + Net_WriteInt8(DEM_ENDSCREENJOB); + } + break; + default: break; } @@ -1324,6 +1439,7 @@ void FLevelLocals::PlayerReborn (int player) p->oldbuttons = ~0, p->attackdown = true; p->usedown = true; // don't do anything immediately p->original_oldbuttons = ~0; p->playerstate = PST_LIVE; + NetworkEntityManager::SetClientNetworkEntity(p->mo, p - players); if (gamestate != GS_TITLELEVEL) { @@ -1389,7 +1505,7 @@ bool FLevelLocals::CheckSpot (int playernum, FPlayerStart *mthing) // return false; players[playernum].mo->flags |= MF_SOLID; - i = P_CheckPosition(players[playernum].mo, spot); + i = P_CheckPosition(players[playernum].mo, spot.XY()); players[playernum].mo->flags &= ~MF_SOLID; players[playernum].mo->SetZ(oldz); // [RH] Restore corpse's height if (!i) @@ -1505,10 +1621,20 @@ void FLevelLocals::DeathMatchSpawnPlayer (int playernum) if (selections < 1) I_Error ("No deathmatch starts"); + bool hasSpawned = false; + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (PlayerInGame(i) && Players[i]->mo != nullptr && Players[i]->health > 0) + { + hasSpawned = true; + break; + } + } + // At level start, none of the players have mobjs attached to them, // so we always use the random deathmatch spawn. During the game, // though, we use whatever dmflags specifies. - if ((dmflags & DF_SPAWN_FARTHEST) && players[playernum].mo) + if ((dmflags & DF_SPAWN_FARTHEST) && hasSpawned) spot = SelectFarthestDeathmatchSpot (selections); else spot = SelectRandomDeathmatchSpot (playernum, selections); @@ -1613,9 +1739,9 @@ void FLevelLocals::QueueBody (AActor *body) GetTranslationType(body->Translation) == TRANSLATION_PlayersExtra) { // This needs to be able to handle multiple levels, in case a level with dead players is used as a secondary one later. - *translationtables[TRANSLATION_PlayerCorpses][modslot] = *TranslationToTable(body->Translation); - body->Translation = TRANSLATION(TRANSLATION_PlayerCorpses,modslot); - translationtables[TRANSLATION_PlayerCorpses][modslot]->UpdateNative(); + GPalette.CopyTranslation(TRANSLATION(TRANSLATION_PlayerCorpses, modslot), body->Translation); + body->Translation = TRANSLATION(TRANSLATION_PlayerCorpses, modslot); + } const int skinidx = body->player->userinfo.GetSkin(); @@ -1641,7 +1767,7 @@ void FLevelLocals::DoReborn (int playernum, bool freshbot) if (!multiplayer && !(flags2 & LEVEL2_ALLOWRESPAWN) && !sv_singleplayerrespawn && !G_SkillProperty(SKILLP_PlayerRespawn)) { - if (BackupSaveName.Len() > 0 && FileExists (BackupSaveName.GetChars())) + if (!(cl_restartondeath) && (BackupSaveName.Len() > 0 && FileExists (BackupSaveName))) { // Load game from the last point it was saved savename = BackupSaveName; gameaction = ga_autoloadgame; @@ -1650,13 +1776,30 @@ void FLevelLocals::DoReborn (int playernum, bool freshbot) { // Reload the level from scratch bool indemo = demoplayback; BackupSaveName = ""; - G_InitNew (MapName, false); + G_InitNew (MapName.GetChars(), false); demoplayback = indemo; } } else { - bool isUnfriendly = players[playernum].mo && !(players[playernum].mo->flags & MF_FRIENDLY); + bool isUnfriendly; + + PlayerSpawnPickClass(playernum); + + // this condition should never be false + assert(players[playernum].cls != NULL); + + if (players[playernum].cls != NULL) + { + isUnfriendly = !(GetDefaultByType(players[playernum].cls)->flags & MF_FRIENDLY); + DPrintf(DMSG_NOTIFY, "Player class IS defined: unfriendly is %i\n", isUnfriendly); + } + else + { + // we shouldn't be here, but if we are, get the player's current status + isUnfriendly = players[playernum].mo && !(players[playernum].mo->flags & MF_FRIENDLY); + DPrintf(DMSG_NOTIFY, "Player class NOT defined: unfriendly is %i\n", isUnfriendly); + } // respawn at the start // first disassociate the corpse @@ -1696,9 +1839,10 @@ void G_DoPlayerPop(int playernum) { playeringame[playernum] = false; - FString message = GStrings(deathmatch? "TXT_LEFTWITHFRAGS" : "TXT_LEFTTHEGAME"); + FString message = GStrings.GetString(deathmatch? "TXT_LEFTWITHFRAGS" : "TXT_LEFTTHEGAME"); message.Substitute("%s", players[playernum].userinfo.GetName()); message.Substitute("%d", FStringf("%d", players[playernum].fragcount)); + Printf("%s\n", message.GetChars()); // [RH] Revert each player to their own view if spying through the player who left for (int ii = 0; ii < MAXPLAYERS; ++ii) @@ -1739,8 +1883,11 @@ void G_DoPlayerPop(int playernum) void G_ScreenShot (const char *filename) { - shotfile = filename; - gameaction = ga_screenshot; + if (gameaction == ga_nothing) + { + shotfile = filename; + gameaction = ga_screenshot; + } } @@ -1764,13 +1911,13 @@ static bool CheckSingleWad (const char *name, bool &printRequires, bool printwar { return true; } - if (Wads.CheckIfWadLoaded (name) < 0) + if (fileSystem.CheckIfResourceFileLoaded (name) < 0) { if (printwarn) { if (!printRequires) { - Printf ("%s:\n%s", GStrings("TXT_SAVEGAMENEEDS"), name); + Printf ("%s:\n%s", GStrings.GetString("TXT_SAVEGAMENEEDS"), name); } else { @@ -1787,12 +1934,12 @@ static bool CheckSingleWad (const char *name, bool &printRequires, bool printwar bool G_CheckSaveGameWads (FSerializer &arc, bool printwarn) { bool printRequires = false; - FString text; - arc("Game WAD", text); - CheckSingleWad (text, printRequires, printwarn); - arc("Map WAD", text); + const char *text = arc.GetString("Game WAD"); CheckSingleWad (text, printRequires, printwarn); + const char *text2 = arc.GetString("Map WAD"); + // do not validate the same file twice. + if (text != nullptr && text2 != nullptr && stricmp(text, text2) != 0) CheckSingleWad (text2, printRequires, printwarn); if (printRequires) { @@ -1808,13 +1955,65 @@ bool G_CheckSaveGameWads (FSerializer &arc, bool printwarn) static void LoadGameError(const char *label, const char *append = "") { - FString message = GStrings(label); + FString message = GStrings.GetString(label); message.Substitute("%s", savename); Printf ("%s %s\n", message.GetChars(), append); } +void C_SerializeCVars(FSerializer& arc, const char* label, uint32_t filter) +{ + FString dump; + + if (arc.BeginObject(label)) + { + if (arc.isWriting()) + { + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + + if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE | CVAR_IGNORE | CVAR_CONFIG_ONLY))) + { + UCVarValue val = cvar->GetGenericRep(CVAR_String); + char* c = const_cast(val.String); + arc(cvar->GetName(), c); + } + } + } + else + { + decltype(cvarMap)::Iterator it(cvarMap); + decltype(cvarMap)::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE | CVAR_IGNORE | CVAR_CONFIG_ONLY))) + { + UCVarValue val; + char* c = nullptr; + arc(cvar->GetName(), c); + if (c != nullptr) + { + val.String = c; + cvar->SetGenericRep(val, CVAR_String); + delete[] c; + } + } + } + } + arc.EndObject(); + } +} + + +void SetupLoadingCVars(); +void FinishLoadingCVars(); + void G_DoLoadGame () { + SetupLoadingCVars(); bool hidecon; if (gameaction != ga_autoloadgame) @@ -1824,14 +2023,14 @@ void G_DoLoadGame () hidecon = gameaction == ga_loadgamehidecon; gameaction = ga_nothing; - std::unique_ptr resfile(FResourceFile::OpenResourceFile(savename.GetChars(), true, true)); + std::unique_ptr resfile(FResourceFile::OpenResourceFile(savename.GetChars(), true)); if (resfile == nullptr) { LoadGameError("TXT_COULDNOTREAD"); return; } - FResourceLump *info = resfile->FindLump("info.json"); - if (info == nullptr) + auto info = resfile->FindEntry("info.json"); + if (info < 0) { LoadGameError("TXT_NOINFOJSON"); return; @@ -1839,9 +2038,9 @@ void G_DoLoadGame () SaveVersion = 0; - void *data = info->CacheLump(); - FSerializer arc(nullptr); - if (!arc.OpenReader((const char *)data, info->LumpSize)) + auto data = resfile->Read(info); + FSerializer arc; + if (!arc.OpenReader(data.string(), data.size())) { LoadGameError("TXT_FAILEDTOREADSG"); return; @@ -1865,7 +2064,7 @@ void G_DoLoadGame () } else { - LoadGameError("TXT_IOTHERENGINESG", engine.GetChars()); + LoadGameError("TXT_OTHERENGINESG", engine.GetChars()); } return; } @@ -1875,16 +2074,16 @@ void G_DoLoadGame () FString message; if (SaveVersion < MINSAVEVER) { - message = GStrings("TXT_TOOOLDSG"); + message = GStrings.GetString("TXT_TOOOLDSG"); message.Substitute("%e", FStringf("%d", MINSAVEVER)); } else { - message = GStrings("TXT_TOONEWSG"); + message = GStrings.GetString("TXT_TOONEWSG"); message.Substitute("%e", FStringf("%d", SAVEVER)); } message.Substitute("%d", FStringf("%d", SaveVersion)); - LoadGameError(message); + LoadGameError(message.GetChars()); return; } @@ -1908,15 +2107,15 @@ void G_DoLoadGame () // we are done with info.json. arc.Close(); - info = resfile->FindLump("globals.json"); - if (info == nullptr) + info = resfile->FindEntry("globals.json"); + if (info < 0) { LoadGameError("TXT_NOGLOBALSJSON"); return; } - data = info->CacheLump(); - if (!arc.OpenReader((const char *)data, info->LumpSize)) + data = resfile->Read(info); + if (!arc.OpenReader(data.string(), data.size())) { LoadGameError("TXT_SGINFOERR"); return; @@ -1928,6 +2127,8 @@ void G_DoLoadGame () primaryLevel->BotInfo.RemoveAllBots(primaryLevel, true); + savegamerestore = true; // Use the player actors in the savegame + FString cvar; arc("importantcvars", cvar); if (!cvar.IsEmpty()) @@ -1953,9 +2154,9 @@ void G_DoLoadGame () G_ReadVisited(arc); // load a base level - savegamerestore = true; // Use the player actors in the savegame bool demoplaybacksave = demoplayback; - G_InitNew(map, false); + G_InitNew(map.GetChars(), false); + FinishLoadingCVars(); demoplayback = demoplaybacksave; savegamerestore = false; @@ -1988,19 +2189,19 @@ void G_SaveGame (const char *filename, const char *description) { if (sendsave || gameaction == ga_savegame) { - Printf ("%s\n", GStrings("TXT_SAVEPENDING")); + Printf ("%s\n", GStrings.GetString("TXT_SAVEPENDING")); } else if (!usergame) { - Printf ("%s\n", GStrings("TXT_NOTSAVEABLE")); + Printf ("%s\n", GStrings.GetString("TXT_NOTSAVEABLE")); } else if (gamestate != GS_LEVEL) { - Printf ("%s\n", GStrings("TXT_NOTINLEVEL")); + Printf ("%s\n", GStrings.GetString("TXT_NOTINLEVEL")); } else if (players[consoleplayer].health <= 0 && !multiplayer) { - Printf ("%s\n", GStrings("TXT_SPPLAYERDEAD")); + Printf ("%s\n", GStrings.GetString("TXT_SPPLAYERDEAD")); } else { @@ -2010,35 +2211,11 @@ void G_SaveGame (const char *filename, const char *description) } } -FString G_BuildSaveName (const char *prefix, int slot) +CCMD(opensaves) { - FString name; - FString leader; - const char *slash = ""; - - leader = Args->CheckValue ("-savedir"); - if (leader.IsEmpty()) - { - leader = save_dir; - if (leader.IsEmpty()) - { - leader = M_GetSavegamesPath(); - } - } - size_t len = leader.Len(); - if (leader[0] != '\0' && leader[len-1] != '\\' && leader[len-1] != '/') - { - slash = "/"; - } - name << leader << slash; - name = NicePath(name); - CreatePath(name); - name << prefix; - if (slot >= 0) - { - name.AppendFormat("%d." SAVEGAME_EXT, slot); - } - return name; + FString name = G_GetSavegamesFolder(); + CreatePath(name.GetChars()); + I_OpenShellFolder(name.GetChars()); } CVAR (Int, autosavenum, 0, CVAR_NOSET|CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -2074,9 +2251,9 @@ void G_DoAutoSave () } num.Int = nextautosave; - autosavenum.ForceSet (num, CVAR_Int); + autosavenum->ForceSet (num, CVAR_Int); - file = G_BuildSaveName ("auto", nextautosave); + file = G_BuildSaveName(FStringf("auto%02d", nextautosave).GetChars()); // The hint flag is only relevant on the primary level. if (!(primaryLevel->flags2 & LEVEL2_NOAUTOSAVEHINT)) @@ -2091,7 +2268,7 @@ void G_DoAutoSave () readableTime = myasctime (); description.Format("Autosave %s", readableTime); - G_DoSaveGame (false, false, file, description); + G_DoSaveGame (false, false, file, description.GetChars()); } void G_DoQuickSave () @@ -2113,13 +2290,13 @@ void G_DoQuickSave () } num.Int = lastquicksave; - quicksavenum.ForceSet (num, CVAR_Int); + quicksavenum->ForceSet (num, CVAR_Int); - file = G_BuildSaveName ("quick", lastquicksave); + file = G_BuildSaveName(FStringf("quick%02d", lastquicksave).GetChars()); readableTime = myasctime (); description.Format("Quicksave %s", readableTime); - G_DoSaveGame (true, true, file, description); + G_DoSaveGame (true, true, file, description.GetChars()); } @@ -2128,15 +2305,12 @@ static void PutSaveWads (FSerializer &arc) const char *name; // Name of IWAD - name = Wads.GetWadName (Wads.GetIwadNum()); + name = fileSystem.GetResourceFileName (fileSystem.GetIwadNum()); arc.AddString("Game WAD", name); // Name of wad the map resides in - if (Wads.GetLumpFile (primaryLevel->lumpnum) > Wads.GetIwadNum()) - { - name = Wads.GetWadName (Wads.GetLumpFile (primaryLevel->lumpnum)); - arc.AddString("Map WAD", name); - } + name = fileSystem.GetResourceFileName (fileSystem.GetFileContainer (primaryLevel->lumpnum)); + arc.AddString("Map WAD", name); } static void PutSaveComment (FSerializer &arc) @@ -2145,68 +2319,18 @@ static void PutSaveComment (FSerializer &arc) FString comment = myasctime(); - arc.AddString("Creation Time", comment); + arc.AddString("Creation Time", comment.GetChars()); // Get level name comment.Format("%s - %s\n", primaryLevel->MapName.GetChars(), primaryLevel->LevelName.GetChars()); // Append elapsed time - const char *const time = GStrings("SAVECOMMENT_TIME"); + const char *const time = GStrings.GetString("SAVECOMMENT_TIME"); levelTime = primaryLevel->time / TICRATE; comment.AppendFormat("%s: %02d:%02d:%02d", time, levelTime/3600, (levelTime%3600)/60, levelTime%60); // Write out the comment - arc.AddString("Comment", comment); -} - -void DoWriteSavePic(FileWriter *file, ESSType ssformat, uint8_t *scr, int width, int height, sector_t *viewsector, bool upsidedown) -{ - PalEntry palette[256]; - PalEntry modulateColor; - auto blend = screen->CalcBlend(viewsector, &modulateColor); - int pixelsize = 1; - // Apply the screen blend, because the renderer does not provide this. - if (ssformat == SS_RGB) - { - int numbytes = width * height * 3; - pixelsize = 3; - if (modulateColor != 0xffffffff) - { - float r = modulateColor.r / 255.f; - float g = modulateColor.g / 255.f; - float b = modulateColor.b / 255.f; - for (int i = 0; i < numbytes; i += 3) - { - scr[i] = uint8_t(scr[i] * r); - scr[i + 1] = uint8_t(scr[i + 1] * g); - scr[i + 2] = uint8_t(scr[i + 2] * b); - } - } - float iblendfac = 1.f - blend.W; - blend.X *= blend.W; - blend.Y *= blend.W; - blend.Z *= blend.W; - for (int i = 0; i < numbytes; i += 3) - { - scr[i] = uint8_t(scr[i] * iblendfac + blend.X); - scr[i + 1] = uint8_t(scr[i + 1] * iblendfac + blend.Y); - scr[i + 2] = uint8_t(scr[i + 2] * iblendfac + blend.Z); - } - } - else - { - // Apply the screen blend to the palette. The colormap related parts get skipped here because these are already part of the image. - DoBlending(GPalette.BaseColors, palette, 256, uint8_t(blend.X), uint8_t(blend.Y), uint8_t(blend.Z), uint8_t(blend.W*255)); - } - - int pitch = width * pixelsize; - if (upsidedown) - { - scr += ((height - 1) * width * pixelsize); - pitch *= -1; - } - - M_CreatePNG(file, scr, ssformat == SS_PAL? palette : nullptr, ssformat, width, height, pitch, Gamma); + arc.AddString("Comment", comment.GetChars()); } static void PutSavePic (FileWriter *file, int width, int height) @@ -2219,7 +2343,7 @@ static void PutSavePic (FileWriter *file, int width, int height) { D_Render([&]() { - screen->WriteSavePic(&players[consoleplayer], file, width, height); + WriteSavePic(&players[consoleplayer], file, width, height); }, false); } } @@ -2240,7 +2364,7 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c if (demoplayback) { - filename = G_BuildSaveName ("demosave." SAVEGAME_EXT, -1); + filename = G_BuildSaveName ("demosave"); } if (cl_waitforsave) @@ -2272,8 +2396,8 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c } BufferWriter savepic; - FSerializer savegameinfo(nullptr); // this is for displayable info about the savegame - FSerializer savegameglobals(nullptr); // and this for non-level related info that must be saved. + FSerializer savegameinfo; // this is for displayable info about the savegame + FSerializer savegameglobals; // and this for non-level related info that must be saved. savegameinfo.OpenWriter(true); savegameglobals.OpenWriter(save_formatted); @@ -2284,7 +2408,7 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c // put some basic info into the PNG so that this isn't lost when the image gets extracted. M_AppendPNGText(&savepic, "Software", buf); M_AppendPNGText(&savepic, "Title", description); - M_AppendPNGText(&savepic, "Current Map", primaryLevel->MapName); + M_AppendPNGText(&savepic, "Current Map", primaryLevel->MapName.GetChars()); M_FinishPNG(&savepic); int ver = SAVEVER; @@ -2292,7 +2416,7 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c .AddString("Engine", GAMESIG) ("Save Version", ver) .AddString("Title", description) - .AddString("Current Map", primaryLevel->MapName); + .AddString("Current Map", primaryLevel->MapName.GetChars()); PutSaveWads (savegameinfo); @@ -2322,7 +2446,7 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c } auto picdata = savepic.GetBuffer(); - FCompressedBuffer bufpng = { picdata->Size(), picdata->Size(), METHOD_STORED, 0, static_cast(crc32(0, &(*picdata)[0], picdata->Size())), (char*)&(*picdata)[0] }; + FCompressedBuffer bufpng = { picdata->size(), picdata->size(), FileSys::METHOD_STORED, static_cast(crc32(0, &(*picdata)[0], picdata->size())), (char*)&(*picdata)[0] }; savegame_content.Push(bufpng); savegame_filenames.Push("savepic.png"); @@ -2330,16 +2454,17 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c savegame_filenames.Push("info.json"); savegame_content.Push(savegameglobals.GetCompressedOutput()); savegame_filenames.Push("globals.json"); - G_WriteSnapshots (savegame_filenames, savegame_content); + for (unsigned i = 0; i < savegame_content.Size(); i++) + savegame_content[i].filename = savegame_filenames[i].GetChars(); bool succeeded = false; - if (WriteZip(filename, savegame_filenames, savegame_content)) + if (WriteZip(filename.GetChars(), savegame_content.Data(), savegame_content.Size())) { // Check whether the file is ok by trying to open it. - FResourceFile *test = FResourceFile::OpenResourceFile(filename, true); + FResourceFile *test = FResourceFile::OpenResourceFile(filename.GetChars(), true); if (test != nullptr) { delete test; @@ -2352,12 +2477,12 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c savegameManager.NotifyNewSave(filename, description, okForQuicksave, forceQuicksave); BackupSaveName = filename; - if (longsavemessages) Printf("%s (%s)\n", GStrings("GGSAVED"), filename.GetChars()); - else Printf("%s\n", GStrings("GGSAVED")); + if (longsavemessages) Printf("%s (%s)\n", GStrings.GetString("GGSAVED"), filename.GetChars()); + else Printf("%s\n", GStrings.GetString("GGSAVED")); } else { - Printf(PRINT_HIGH, "%s\n", GStrings("TXT_SAVEFAILED")); + Printf(PRINT_HIGH, "%s\n", GStrings.GetString("TXT_SAVEFAILED")); } @@ -2395,7 +2520,7 @@ void G_ReadDemoTiccmd (ticcmd_t *cmd, int player) break; } - id = ReadByte (&demo_p); + id = ReadInt8 (&demo_p); switch (id) { @@ -2414,7 +2539,7 @@ void G_ReadDemoTiccmd (ticcmd_t *cmd, int player) case DEM_DROPPLAYER: { - uint8_t i = ReadByte (&demo_p); + uint8_t i = ReadInt8 (&demo_p); if (i < MAXPLAYERS) { playeringame[i] = false; @@ -2508,23 +2633,23 @@ void G_BeginRecording (const char *startmap) if (startmap == NULL) { - startmap = primaryLevel->MapName; + startmap = primaryLevel->MapName.GetChars(); } demo_p = demobuffer; - WriteLong (FORM_ID, &demo_p); // Write FORM ID + WriteInt32 (FORM_ID, &demo_p); // Write FORM ID demo_p += 4; // Leave space for len - WriteLong (ZDEM_ID, &demo_p); // Write ZDEM ID + WriteInt32 (ZDEM_ID, &demo_p); // Write ZDEM ID // Write header chunk StartChunk (ZDHD_ID, &demo_p); - WriteWord (DEMOGAMEVERSION, &demo_p); // Write ZDoom version + WriteInt16 (DEMOGAMEVERSION, &demo_p); // Write ZDoom version *demo_p++ = 2; // Write minimum version needed to use this demo. *demo_p++ = 3; // (Useful?) strcpy((char*)demo_p, startmap); // Write name of map demo was recorded on. demo_p += strlen(startmap) + 1; - WriteLong(rngseed, &demo_p); // Write RNG seed + WriteInt32(rngseed, &demo_p); // Write RNG seed *demo_p++ = consoleplayer; FinishChunk (&demo_p); @@ -2533,10 +2658,12 @@ void G_BeginRecording (const char *startmap) { if (playeringame[i]) { - StartChunk (UINF_ID, &demo_p); - WriteByte ((uint8_t)i, &demo_p); - D_WriteUserInfoStrings (i, &demo_p); - FinishChunk (&demo_p); + StartChunk(UINF_ID, &demo_p); + WriteInt8((uint8_t)i, &demo_p); + auto str = D_GetUserInfoStrings(i); + memcpy(demo_p, str.GetChars(), str.Len() + 1); + demo_p += str.Len(); + FinishChunk(&demo_p); } } @@ -2562,7 +2689,7 @@ void G_BeginRecording (const char *startmap) // Indicate body is compressed StartChunk (COMP_ID, &demo_p); democompspot = demo_p; - WriteLong (0, &demo_p); + WriteInt32 (0, &demo_p); FinishChunk (&demo_p); // Begin BODY chunk @@ -2627,13 +2754,13 @@ bool G_ProcessIFFDemo (FString &mapname) for (i = 0; i < MAXPLAYERS; i++) playeringame[i] = 0; - len = ReadLong (&demo_p); + len = ReadInt32 (&demo_p); zdemformend = demo_p + len + (len & 1); // Check to make sure this is a ZDEM chunk file. // TODO: Support multiple FORM ZDEMs in a CAT. Might be useful. - id = ReadLong (&demo_p); + id = ReadInt32 (&demo_p); if (id != ZDEM_ID) { Printf ("Not a " GAMENAME " demo file!\n"); @@ -2644,8 +2771,8 @@ bool G_ProcessIFFDemo (FString &mapname) while (demo_p < zdemformend && !bodyHit) { - id = ReadLong (&demo_p); - len = ReadLong (&demo_p); + id = ReadInt32 (&demo_p); + len = ReadInt32 (&demo_p); nextchunk = demo_p + len + (len & 1); if (nextchunk > zdemformend) { @@ -2658,13 +2785,13 @@ bool G_ProcessIFFDemo (FString &mapname) case ZDHD_ID: headerHit = true; - demover = ReadWord (&demo_p); // ZDoom version demo was created with + demover = ReadInt16 (&demo_p); // ZDoom version demo was created with if (demover < MINDEMOVERSION) { Printf ("Demo requires an older version of " GAMENAME "!\n"); //return true; } - if (ReadWord (&demo_p) > DEMOGAMEVERSION) // Minimum ZDoom version + if (ReadInt16 (&demo_p) > DEMOGAMEVERSION) // Minimum ZDoom version { Printf ("Demo requires a newer version of " GAMENAME "!\n"); return true; @@ -2679,7 +2806,7 @@ bool G_ProcessIFFDemo (FString &mapname) mapname = FString((char*)demo_p, 8); demo_p += 8; } - rngseed = ReadLong (&demo_p); + rngseed = ReadInt32 (&demo_p); // Only reset the RNG if this demo is not in conjunction with a savegame. if (mapname[0] != 0) { @@ -2693,7 +2820,7 @@ bool G_ProcessIFFDemo (FString &mapname) break; case UINF_ID: - i = ReadByte (&demo_p); + i = ReadInt8 (&demo_p); if (!playeringame[i]) { playeringame[i] = 1; @@ -2716,7 +2843,7 @@ bool G_ProcessIFFDemo (FString &mapname) break; case COMP_ID: - uncompSize = ReadLong (&demo_p); + uncompSize = ReadInt32 (&demo_p); break; } @@ -2772,19 +2899,19 @@ void G_DoPlayDemo (void) gameaction = ga_nothing; // [RH] Allow for demos not loaded as lumps - demolump = Wads.CheckNumForFullName (defdemoname, true); + demolump = fileSystem.CheckNumForFullName (defdemoname.GetChars(), true); if (demolump >= 0) { - int demolen = Wads.LumpLength (demolump); + int demolen = fileSystem.FileLength (demolump); demobuffer = (uint8_t *)M_Malloc(demolen); - Wads.ReadLump (demolump, demobuffer); + fileSystem.ReadFile (demolump, demobuffer); } else { FixPathSeperator (defdemoname); DefaultExtension (defdemoname, ".lmp"); FileReader fr; - if (!fr.OpenFile(defdemoname)) + if (!fr.OpenFile(defdemoname.GetChars())) { I_Error("Unable to open demo '%s'", defdemoname.GetChars()); } @@ -2801,7 +2928,7 @@ void G_DoPlayDemo (void) C_BackupCVars (); // [RH] Save cvars that might be affected by demo - if (ReadLong (&demo_p) != FORM_ID) + if (ReadInt32 (&demo_p) != FORM_ID) { const char *eek = "Cannot play non-" GAMENAME " demos.\n"; @@ -2831,7 +2958,7 @@ void G_DoPlayDemo (void) demonew = true; if (mapname.Len() != 0) { - G_InitNew (mapname, false); + G_InitNew (mapname.GetChars(), false); } else if (primaryLevel->sectors.Size() == 0) { @@ -2843,6 +2970,7 @@ void G_DoPlayDemo (void) usergame = false; demoplayback = true; + playedtitlemusic = false; } } @@ -2934,7 +3062,7 @@ bool G_CheckDemoStatus (void) { uint8_t *formlen; - WriteByte (DEM_STOP, &demo_p); + WriteInt8 (DEM_STOP, &demo_p); if (demo_compress) { @@ -2949,23 +3077,23 @@ bool G_CheckDemoStatus (void) if (r == Z_OK && outlen < len) { formlen = democompspot; - WriteLong (len, &democompspot); + WriteInt32 (len, &democompspot); memcpy (demobodyspot, compressed.Data(), outlen); demo_p = demobodyspot + outlen; } } FinishChunk (&demo_p); formlen = demobuffer + 4; - WriteLong (int(demo_p - demobuffer - 8), &formlen); + WriteInt32 (int(demo_p - demobuffer - 8), &formlen); - auto fw = FileWriter::Open(demoname); + auto fw = FileWriter::Open(demoname.GetChars()); bool saved = false; if (fw != nullptr) { const size_t size = demo_p - demobuffer; saved = fw->Write(demobuffer, size) == size; delete fw; - if (!saved) remove(demoname); + if (!saved) RemoveFile(demoname.GetChars()); } M_Free (demobuffer); demorecording = false; @@ -2985,8 +3113,16 @@ bool G_CheckDemoStatus (void) void G_StartSlideshow(FLevelLocals *Level, FName whichone) { - gameaction = ga_slideshow; - SelectedSlideshow = whichone == NAME_None ? Level->info->slideshow : whichone; + auto SelectedSlideshow = whichone == NAME_None ? Level->info->slideshow : whichone; + auto slide = F_StartIntermission(SelectedSlideshow); + RunIntermission(nullptr, nullptr, slide, nullptr, [](bool) + { + primaryLevel->SetMusic(); + gamestate = GS_LEVEL; + wipegamestate = GS_LEVEL; + gameaction = ga_resumeconversation; + + }); } DEFINE_ACTION_FUNCTION(FLevelLocals, StartSlideshow) @@ -3008,7 +3144,10 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, MakeScreenShot) void G_MakeAutoSave() { - gameaction = ga_autosave; + if (gameaction == ga_nothing) + { + gameaction = ga_autosave; + } } DEFINE_ACTION_FUNCTION(FLevelLocals, MakeAutoSave) @@ -3022,7 +3161,6 @@ DEFINE_GLOBAL(playeringame) DEFINE_GLOBAL(PlayerClasses) DEFINE_GLOBAL_NAMED(Skins, PlayerSkins) DEFINE_GLOBAL(consoleplayer) -DEFINE_GLOBAL_NAMED(PClass::AllClasses, AllClasses) DEFINE_GLOBAL_NAMED(PClassActor::AllActorClasses, AllActorClasses) DEFINE_GLOBAL_NAMED(primaryLevel, Level) DEFINE_GLOBAL(validcount) @@ -3034,5 +3172,8 @@ DEFINE_GLOBAL(globalfreeze) DEFINE_GLOBAL(gametic) DEFINE_GLOBAL(demoplayback) DEFINE_GLOBAL(automapactive); +DEFINE_GLOBAL(viewactive); DEFINE_GLOBAL(Net_Arbitrator); DEFINE_GLOBAL(netgame); +DEFINE_GLOBAL(paused); +DEFINE_GLOBAL(Terrains); diff --git a/src/g_game.h b/src/g_game.h index 47d9231a07c..caaf931884f 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -30,29 +30,12 @@ struct event_t; -#include "dobjgc.h" +#include -// The current state of the game: whether we are -// playing, gazing at the intermission screen, -// the game final animation, or a demo. -enum gamestate_t : int -{ - GS_LEVEL, - GS_INTERMISSION, - GS_FINALE, - GS_DEMOSCREEN, - GS_FULLCONSOLE, // [RH] Fullscreen console - GS_HIDECONSOLE, // [RH] The menu just did something that should hide fs console - GS_STARTUP, // [RH] Console is fullscreen, and game is just starting - GS_TITLELEVEL, // [RH] A combination of GS_LEVEL and GS_DEMOSCREEN - - GS_FORCEWIPE = -1, - GS_FORCEWIPEFADE = -2, - GS_FORCEWIPEBURN = -3, - GS_FORCEWIPEMELT = -4 -}; +#include "dobjgc.h" +#include "name.h" +#include "gamestate.h" -extern gamestate_t gamestate; // wipegamestate can be set to -1 // to force a wipe on the next draw @@ -100,8 +83,6 @@ bool G_Responder (event_t* ev); void G_ScreenShot (const char* filename); void G_StartSlideshow(FLevelLocals *Level, FName whichone); -FString G_BuildSaveName (const char *prefix, int slot); - class FSerializer; bool G_CheckSaveGameWads (FSerializer &arc, bool printwarn); @@ -122,10 +103,15 @@ void G_AddViewPitch (int look, bool mouse = false); // Adds to consoleplayer's viewangle if allowed void G_AddViewAngle (int yaw, bool mouse = false); +class FBaseCVar; +FBaseCVar* G_GetUserCVar(int playernum, const char* cvarname); + +class DIntermissionController; +struct level_info_t; +void RunIntermission(level_info_t* oldlevel, level_info_t* newlevel, DIntermissionController* intermissionScreen, DObject* statusScreen, std::function completionf); + extern const AActor *SendItemUse, *SendItemDrop; extern int SendItemDropAmount; -const int SAVEPICWIDTH = 216; -const int SAVEPICHEIGHT = 162; #endif diff --git a/src/g_hub.cpp b/src/g_hub.cpp index a31de7d4266..250db2fd081 100644 --- a/src/g_hub.cpp +++ b/src/g_hub.cpp @@ -54,6 +54,7 @@ struct FHubInfo { int levelnum; + int totalkills; int maxkills; int maxitems; int maxsecret; @@ -63,11 +64,12 @@ struct FHubInfo FHubInfo &operator=(const wbstartstruct_t &wbs) { - levelnum = wbs.finished_ep; - maxkills = wbs.maxkills; - maxsecret= wbs.maxsecret; - maxitems = wbs.maxitems; - maxfrags = wbs.maxfrags; + levelnum = wbs.finished_ep; + totalkills = wbs.totalkills; + maxkills = wbs.maxkills; + maxsecret = wbs.maxsecret; + maxitems = wbs.maxitems; + maxfrags = wbs.maxfrags; memcpy(plyr, wbs.plyr, sizeof(plyr)); return *this; } @@ -107,6 +109,7 @@ void G_LeavingHub(FLevelLocals *Level, int mode, cluster_info_t * cluster, wbsta if (mode != FINISH_SameHub) { + wbs->totalkills = Level->killed_monsters; wbs->maxkills = wbs->maxitems = wbs->maxsecret = 0; for (i = 0; i < MAXPLAYERS; i++) { @@ -129,7 +132,7 @@ void G_LeavingHub(FLevelLocals *Level, int mode, cluster_info_t * cluster, wbsta { if (cluster->flags & CLUSTER_LOOKUPNAME) { - wbs->thisname = GStrings(cluster->ClusterName); + wbs->thisname = GStrings.GetString(cluster->ClusterName); } else { @@ -169,6 +172,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FHubInfo &h, FHubInfo if (arc.BeginObject(key)) { arc("levelnum", h.levelnum) + ("totalkills", h.totalkills) ("maxkills", h.maxkills) ("maxitems", h.maxitems) ("maxsecret", h.maxsecret) diff --git a/src/g_level.cpp b/src/g_level.cpp index e0ddc56a214..1278494b245 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -33,19 +33,20 @@ */ #include -#include "templates.h" + #include "d_main.h" #include "g_level.h" #include "g_game.h" #include "s_sound.h" #include "d_event.h" #include "m_random.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "doomstat.h" #include "wi_stuff.h" -#include "w_wad.h" +#include "filesystem.h" #include "am_map.h" #include "c_dispatch.h" +#include "i_interface.h" #include "p_setup.h" #include "p_local.h" @@ -69,11 +70,11 @@ #include "cmdlib.h" #include "d_net.h" #include "d_netinf.h" -#include "menu/menu.h" +#include "doommenu.h" #include "a_sharedglobal.h" #include "r_utility.h" #include "p_spec.h" -#include "serializer.h" +#include "serializer_doom.h" #include "vm.h" #include "events.h" #include "i_music.h" @@ -81,18 +82,27 @@ #include "p_conversation.h" #include "p_effect.h" #include "stringtable.h" +#include "c_buttons.h" +#include "screenjob.h" +#include "types.h" +#include "gstrings.h" #include "gi.h" + #include "g_hub.h" #include "g_levellocals.h" #include "actorinlines.h" #include "i_time.h" #include "p_maputl.h" #include "s_music.h" +#include "fragglescript/t_script.h" + +#include "texturemanager.h" void STAT_StartNewGame(const char *lev); void STAT_ChangeLevel(const char *newl, FLevelLocals *Level); +FString STAT_EpisodeName(); EXTERN_CVAR(Bool, save_formatted) EXTERN_CVAR (Float, sv_gravity) @@ -136,20 +146,32 @@ CUSTOM_CVAR(Bool, gl_notexturefill, false, CVAR_NOINITCALL) } } -CUSTOM_CVAR(Int, gl_lightmode, 3, CVAR_ARCHIVE | CVAR_NOINITCALL) +CUSTOM_CVAR(Int, gl_maplightmode, -1, CVAR_NOINITCALL | CVAR_CHEAT) // this is just for testing. -1 means 'inactive' { - int newself = self; - if (newself > 8) newself = 16; // use 8 and 16 for software lighting to avoid conflicts with the bit mask - else if (newself > 4) newself = 8; - else if (newself < 0) newself = 0; - if (self != newself) self = newself; - else for (auto Level : AllLevels()) - { - if ((Level->info == nullptr || Level->info->lightmode == ELightMode::NotSet)) Level->lightMode = (ELightMode)*self; - } + if (self > 5 || self < -1) self = -1; } +CUSTOM_CVARD(Int, gl_lightmode, 1, CVAR_ARCHIVE, "Select lighting mode. 2 is vanilla accurate, 1 is accurate to the ZDoom software renderer and 0 is a less demanding non-shader implementation") +{ + if (self < 0 || self > 2) self = 1; +} + +ELightMode getRealLightmode(FLevelLocals* Level, bool for3d) +{ + // The rules are: + // 1) if the map sets a proper light mode, it is taken unconditionally. + if (Level->info->lightmode != ELightMode::NotSet) return Level->info->lightmode; + // 2) if the user sets gl_maplightmode, this is being used. + if (gl_maplightmode != -1) return (ELightMode)*gl_maplightmode; + // 3) if not for 3D use lightmode Doom. This is for the automap where the software light modes do not work + if (!for3d) return ELightMode::Doom; + // otherwise use lightmode Doom or software lighting based on user preferences. + if (gl_lightmode == 1) return ELightMode::ZDoomSoftware; + else if (gl_lightmode == 2) return ELightMode::DoomSoftware; + return ELightMode::Doom; +} +CVAR(Int, sv_alwaystally, 0, CVAR_SERVERINFO) static FRandom pr_classchoice ("RandomPlayerClassChoice"); @@ -165,7 +187,7 @@ extern FString BackupSaveName; bool savegamerestore; int finishstate = FINISH_NoHub; -extern int mousex, mousey; +extern float mousex, mousey; extern bool sendpause, sendsave, sendturn180, SendLand; void *statcopy; // for statistics driver @@ -173,8 +195,60 @@ void *statcopy; // for statistics driver FLevelLocals level; // info about current level FLevelLocals *primaryLevel = &level; // level for which to display the user interface. FLevelLocals *currentVMLevel = &level; // level which currently ticks. Used as global input to the VM and some functions called by it. +static PType* maprecordtype; +//============================================================================= +// +// +// +//============================================================================= + +void Local_Job_Init() +{ + maprecordtype = NewPointer(NewStruct("MapRecord", nullptr, true)); +} + +//============================================================================= +// +// +// +//============================================================================= + +static void CallCreateMapFunction(const char* qname, DObject* runner, level_info_t* map) +{ + auto func = LookupFunction(qname); + if (func->Proto->ArgumentTypes.Size() == 1) return CallCreateFunction(qname, runner); // accept functions without map parameter as well here. + if (func->Proto->ArgumentTypes.Size() != 2) I_Error("Bad map-cutscene function %s. Must receive precisely two arguments.", qname); + if (func->Proto->ArgumentTypes[0] != cutscene.runnerclasstype && func->Proto->ArgumentTypes[1] != maprecordtype) + I_Error("Bad cutscene function %s. Must receive ScreenJobRunner and LevelInfo reference.", qname); + VMValue val[2] = { runner, map }; + VMCall(func, val, 2, nullptr, 0); +} + +//============================================================================= +// +// +// +//============================================================================= + +bool CreateCutscene(CutsceneDef* cs, DObject* runner, level_info_t* map) +{ + if (cs->function.CompareNoCase("none") == 0) + return true; // play nothing but return as being validated + if (cs->function.IsNotEmpty()) + { + CallCreateMapFunction(cs->function.GetChars(), runner, map); + return true; + } + else if (cs->video.IsNotEmpty()) + { + AddGenericVideo(runner, cs->video, cs->GetSound(), cs->framespersec); + return true; + } + return false; +} + //========================================================================== // // G_InitNew @@ -194,14 +268,34 @@ void G_DeferedInitNew (const char *mapname, int newskill) gameaction = ga_newgame2; } -void G_DeferedInitNew (FGameStartup *gs) +void G_DeferedInitNew (FNewGameStartup *gs) { - if (gs->PlayerClass != NULL) playerclass = gs->PlayerClass; + if (gs->hasPlayerClass) playerclass = gs->PlayerClass.GetChars(); d_mapname = AllEpisodes[gs->Episode].mEpisodeMap; d_skill = gs->Skill; CheckWarpTransMap (d_mapname, true); gameaction = ga_newgame2; finishstate = FINISH_NoHub; + + if (AllEpisodes[gs->Episode].mIntro.isdefined()) + { + cutscene.runner = CreateRunner(false); + GC::WriteBarrier(cutscene.runner); + + if (!CreateCutscene(&AllEpisodes[gs->Episode].mIntro, cutscene.runner, nullptr)) + { + return; + } + + cutscene.completion = [](bool) { gameaction = ga_newgame2; }; + if (!ScreenJobValidate()) + { + DeleteScreenJob(); + cutscene.completion = nullptr; + return; + } + gameaction = ga_intermission; + } } //========================================================================== @@ -324,7 +418,7 @@ UNSAFE_CCMD (open) { d_mapname = "file:"; d_mapname += argv[1]; - if (!P_CheckMapData(d_mapname)) + if (!P_CheckMapData(d_mapname.GetChars())) { Printf ("No map %s\n", d_mapname.GetChars()); } @@ -371,6 +465,12 @@ void G_NewInit () pawn->flags |= MF_NOSECTOR | MF_NOBLOCKMAP; pawn->Destroy(); } + if (primaryLevel->FraggleScriptThinker) primaryLevel->FraggleScriptThinker->Destroy(); + primaryLevel->FraggleScriptThinker = nullptr; + + // Destroy thinkers that may remain after change level failure + // Usually, the list contains just a sentinel when such error occurred + primaryLevel->Thinkers.DestroyThinkersInList(STAT_TRAVELLING); G_ClearSnapshots (); netgame = false; @@ -415,7 +515,7 @@ void G_DoNewGame (void) { gameskill = d_skill; } - G_InitNew (d_mapname, false); + G_InitNew (d_mapname.GetChars(), false); gameaction = ga_nothing; } @@ -458,8 +558,9 @@ void G_InitNew (const char *mapname, bool bTitleLevel) // did we have any level before? if (primaryLevel->info != nullptr) - staticEventManager.WorldUnloaded(); + staticEventManager.WorldUnloaded(FString()); // [MK] don't pass the new map, as it's not a level transition + UnlatchCVars (); if (!savegamerestore) { G_ClearHubInfo(); @@ -469,9 +570,14 @@ void G_InitNew (const char *mapname, bool bTitleLevel) // [RH] Mark all levels as not visited for (unsigned int i = 0; i < wadlevelinfos.Size(); i++) wadlevelinfos[i].flags = wadlevelinfos[i].flags & ~LEVEL_VISITED; + + auto redirectmap = FindLevelInfo(mapname); + if (redirectmap->RedirectCVAR != NAME_None) + redirectmap = redirectmap->CheckLevelRedirect(); + if (redirectmap && redirectmap->MapName.IsNotEmpty()) + mapname = redirectmap->MapName.GetChars(); } - UnlatchCVars (); G_VerifySkill(); UnlatchCVars (); globalfreeze = globalchangefreeze = 0; @@ -578,6 +684,26 @@ static bool unloading; EXTERN_CVAR(Bool, sv_singleplayerrespawn) +bool FLevelLocals::ShouldDoIntermission(cluster_info_t* nextcluster, cluster_info_t* thiscluster) +{ + // this is here to remove some code duplication + + if ((sv_alwaystally == 2) || (deathmatch)) + return true; + + if ((sv_alwaystally == 0) && (flags & LEVEL_NOINTERMISSION)) + return false; + + bool withinSameCluster = (nextcluster == thiscluster); + bool clusterIsHub = (thiscluster->flags & CLUSTER_HUB); + bool hubNoIntermission = !(thiscluster->flags & CLUSTER_ALLOWINTERMISSION); + + if (withinSameCluster && clusterIsHub && hubNoIntermission) + return false; + + return true; +} + void FLevelLocals::ChangeLevel(const char *levelname, int position, int inflags, int nextSkill) { if (!isPrimaryLevel()) return; // only the primary level may exit. @@ -605,14 +731,14 @@ void FLevelLocals::ChangeLevel(const char *levelname, int position, int inflags, } else { - nextlevel.Format("enDSeQ%04x", int(gameinfo.DefaultEndSequence)); + nextlevel.Format("enDSeQ%04x", gameinfo.DefaultEndSequence.GetIndex()); } } else if (strncmp(levelname, "enDSeQ", 6) != 0) { FString reallevelname = levelname; CheckWarpTransMap(reallevelname, true); - nextinfo = FindLevelInfo (reallevelname, false); + nextinfo = FindLevelInfo (reallevelname.GetChars(), false); if (nextinfo != NULL) { level_info_t *nextredir = nextinfo->CheckLevelRedirect(); @@ -633,7 +759,7 @@ void FLevelLocals::ChangeLevel(const char *levelname, int position, int inflags, } if (nextSkill != -1) - NextSkill = nextSkill; + NextSkill = (unsigned)nextSkill < AllSkills.Size() ? nextSkill : -1; if (inflags & CHANGELEVEL_NOINTERMISSION) { @@ -650,11 +776,12 @@ void FLevelLocals::ChangeLevel(const char *levelname, int position, int inflags, { if (thiscluster != nextcluster || (thiscluster && !(thiscluster->flags & CLUSTER_HUB))) { - if (nextinfo->flags2 & LEVEL2_RESETINVENTORY) + const bool doReset = dmflags3 & DF3_PISTOL_START; + if (doReset || (nextinfo->flags2 & LEVEL2_RESETINVENTORY)) { inflags |= CHANGELEVEL_RESETINVENTORY; } - if (nextinfo->flags2 & LEVEL2_RESETHEALTH) + if (doReset || (nextinfo->flags2 & LEVEL2_RESETHEALTH)) { inflags |= CHANGELEVEL_RESETHEALTH; } @@ -671,17 +798,17 @@ void FLevelLocals::ChangeLevel(const char *levelname, int position, int inflags, for (auto Level : AllLevels()) { // Todo: This must be exolicitly sandboxed! - Level->localEventManager->WorldUnloaded(); + Level->localEventManager->WorldUnloaded(nextlevel); } // [ZZ] unsafe world unload (changemap != map) - staticEventManager.WorldUnloaded(); + staticEventManager.WorldUnloaded(nextlevel); unloading = false; - STAT_ChangeLevel(nextlevel, this); + STAT_ChangeLevel(nextlevel.GetChars(), this); if (thiscluster && (thiscluster->flags & CLUSTER_HUB)) { - if ((flags & LEVEL_NOINTERMISSION) || ((nextcluster == thiscluster) && !(thiscluster->flags & CLUSTER_ALLOWINTERMISSION))) + if (!ShouldDoIntermission(nextcluster, thiscluster)) NoWipe = 35; D_DrawIcon = "TELEICON"; } @@ -717,6 +844,17 @@ void FLevelLocals::ChangeLevel(const char *levelname, int position, int inflags, ::nextlevel = nextlevel; } +DEFINE_ACTION_FUNCTION(FLevelLocals, ChangeLevel) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_STRING(levelname); + PARAM_INT(position); + PARAM_INT(inflags); + PARAM_INT(nextSkill); + self->ChangeLevel(levelname.GetChars(), position, inflags, nextSkill); + return 0; +} + //========================================================================== // // @@ -724,13 +862,13 @@ void FLevelLocals::ChangeLevel(const char *levelname, int position, int inflags, const char *FLevelLocals::GetSecretExitMap() { - const char *nextmap = NextMap; + const char *nextmap = NextMap.GetChars(); if (NextSecretMap.Len() > 0) { - if (P_CheckMapData(NextSecretMap)) + if (NextSecretMap.Compare("enDSeQ", 6) == 0 || P_CheckMapData(NextSecretMap.GetChars())) { - nextmap = NextSecretMap; + nextmap = NextSecretMap.GetChars(); } } return nextmap; @@ -745,7 +883,7 @@ const char *FLevelLocals::GetSecretExitMap() void FLevelLocals::ExitLevel (int position, bool keepFacing) { flags3 |= LEVEL3_EXITNORMALUSED; - ChangeLevel(NextMap, position, keepFacing ? CHANGELEVEL_KEEPFACING : 0); + ChangeLevel(NextMap.GetChars(), position, keepFacing ? CHANGELEVEL_KEEPFACING : 0); } static void LevelLocals_ExitLevel(FLevelLocals *self, int position, bool keepFacing) @@ -787,6 +925,167 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SecretExitLevel, LevelLocals_SecretE //========================================================================== static wbstartstruct_t staticWmInfo; +DIntermissionController* FLevelLocals::CreateIntermission() +{ + DIntermissionController* controller = nullptr; + cluster_info_t *nextcluster; + cluster_info_t *thiscluster; + + if (flags & LEVEL_CHANGEMAPCHEAT) + return nullptr; + + thiscluster = FindClusterInfo (cluster); + + bool endgame = strncmp (nextlevel.GetChars(), "enDSeQ", 6) == 0; + if (endgame) + { + FName endsequence = ENamedName(strtoll(nextlevel.GetChars()+6, NULL, 16)); + // Strife needs a special case here to choose between good and sad ending. Bad is handled elsewhere. + if (endsequence == NAME_Inter_Strife) + { + if (Players[0]->mo->FindInventory (NAME_QuestItem25) || + Players[0]->mo->FindInventory (NAME_QuestItem28)) + { + endsequence = NAME_Inter_Strife_Good; + } + else + { + endsequence = NAME_Inter_Strife_Sad; + } + } + + auto ext = info->ExitMapTexts.CheckKey(flags3 & LEVEL3_EXITSECRETUSED ? NAME_Secret : NAME_Normal); + if (ext != nullptr && (ext->mDefined & FExitText::DEF_TEXT)) + { + controller = F_StartFinale(ext->mDefined & FExitText::DEF_MUSIC ? ext->mMusic.GetChars() : gameinfo.finaleMusic.GetChars(), + ext->mDefined & FExitText::DEF_MUSIC ? ext->mOrder : gameinfo.finaleOrder, + -1, 0, + ext->mDefined & FExitText::DEF_BACKDROP ? ext->mBackdrop.GetChars() : gameinfo.FinaleFlat.GetChars(), + ext->mText.GetChars(), + false, + ext->mDefined & FExitText::DEF_PIC, + ext->mDefined & FExitText::DEF_LOOKUP, + true, endsequence); + } + else if (!(info->flags2 & LEVEL2_NOCLUSTERTEXT)) + { + controller = F_StartFinale(thiscluster->MessageMusic.GetChars(), thiscluster->musicorder, + thiscluster->cdtrack, thiscluster->cdid, + thiscluster->FinaleFlat.GetChars(), thiscluster->ExitText.GetChars(), + thiscluster->flags & CLUSTER_EXITTEXTINLUMP, + thiscluster->flags & CLUSTER_FINALEPIC, + thiscluster->flags & CLUSTER_LOOKUPEXITTEXT, + true, endsequence); + } + } + else if (!deathmatch) + { + FExitText *ext = nullptr; + + if (flags3 & LEVEL3_EXITSECRETUSED) ext = info->ExitMapTexts.CheckKey(NAME_Secret); + else if (flags3 & LEVEL3_EXITNORMALUSED) ext = info->ExitMapTexts.CheckKey(NAME_Normal); + if (ext == nullptr) ext = info->ExitMapTexts.CheckKey(nextlevel); + + if (ext != nullptr) + { + if ((ext->mDefined & FExitText::DEF_TEXT)) + { + controller = F_StartFinale(ext->mDefined & FExitText::DEF_MUSIC ? ext->mMusic.GetChars() : gameinfo.finaleMusic.GetChars(), + ext->mDefined & FExitText::DEF_MUSIC ? ext->mOrder : gameinfo.finaleOrder, + -1, 0, + ext->mDefined & FExitText::DEF_BACKDROP ? ext->mBackdrop.GetChars() : gameinfo.FinaleFlat.GetChars(), + ext->mText.GetChars(), + false, + ext->mDefined & FExitText::DEF_PIC, + ext->mDefined & FExitText::DEF_LOOKUP, + false); + } + return controller; + } + + nextcluster = FindClusterInfo (FindLevelInfo (nextlevel.GetChars())->cluster); + + if (nextcluster->cluster != cluster && !(info->flags2 & LEVEL2_NOCLUSTERTEXT)) + { + // Only start the finale if the next level's cluster is different + // than the current one and we're not in deathmatch. + if (nextcluster->EnterText.IsNotEmpty()) + { + controller = F_StartFinale (nextcluster->MessageMusic.GetChars(), nextcluster->musicorder, + nextcluster->cdtrack, nextcluster->cdid, + nextcluster->FinaleFlat.GetChars(), nextcluster->EnterText.GetChars(), + nextcluster->flags & CLUSTER_ENTERTEXTINLUMP, + nextcluster->flags & CLUSTER_FINALEPIC, + nextcluster->flags & CLUSTER_LOOKUPENTERTEXT, + false); + } + else if (thiscluster->ExitText.IsNotEmpty()) + { + controller = F_StartFinale (thiscluster->MessageMusic.GetChars(), thiscluster->musicorder, + thiscluster->cdtrack, nextcluster->cdid, + thiscluster->FinaleFlat.GetChars(), thiscluster->ExitText.GetChars(), + thiscluster->flags & CLUSTER_EXITTEXTINLUMP, + thiscluster->flags & CLUSTER_FINALEPIC, + thiscluster->flags & CLUSTER_LOOKUPEXITTEXT, + false); + } + } + } + return controller; +} + +//============================================================================= +// +// +// +//============================================================================= + +void RunIntermission(level_info_t* fromMap, level_info_t* toMap, DIntermissionController* intermissionScreen, DObject* statusScreen, std::function completionf) +{ + cutscene.runner = CreateRunner(false); + GC::WriteBarrier(cutscene.runner); + cutscene.completion = std::move(completionf); + + // retrieve cluster relations for cluster-based cutscenes. + cluster_info_t* fromcluster = nullptr, *tocluster = nullptr; + if (fromMap) fromcluster = FindClusterInfo(fromMap->cluster); + if (toMap) tocluster = FindClusterInfo(toMap->cluster); + if (fromcluster == tocluster) fromcluster = tocluster = nullptr; + + if (fromMap) + { + if (!CreateCutscene(&fromMap->outro, cutscene.runner, fromMap)) + { + if (fromcluster != nullptr) CreateCutscene(&fromcluster->outro, cutscene.runner, fromMap); + } + } + + auto func = LookupFunction("DoomCutscenes.BuildMapTransition"); + if (func == nullptr) + { + I_Error("Script function 'DoomCutscenes.BuildMapTransition' not found"); + } + VMValue val[3] = { cutscene.runner, intermissionScreen, statusScreen }; + VMCall(func, val, 3, nullptr, 0); + + if (toMap) + { + if (!CreateCutscene(&toMap->intro, cutscene.runner, toMap)) + { + if (tocluster != nullptr) CreateCutscene(&tocluster->intro, cutscene.runner, toMap); + } + } + + if (!ScreenJobValidate()) + { + DeleteScreenJob(); + if (cutscene.completion) cutscene.completion(false); + cutscene.completion = nullptr; + return; + } + gameaction = ga_intermission; +} + void G_DoCompleted (void) { gameaction = ga_nothing; @@ -812,24 +1111,32 @@ void G_DoCompleted (void) // Close the conversation menu if open. P_FreeStrifeConversations (); + bool playinter = primaryLevel->DoCompleted(nextlevel, staticWmInfo); S_StopAllChannels(); for (auto Level : AllLevels()) { SN_StopAllSequences(Level); } - if (primaryLevel->DoCompleted(nextlevel, staticWmInfo)) + // todo: create end of level screenjob + DObject* statusScreen = nullptr; + DIntermissionController* intermissionScreen = nullptr; + if (playinter) { - gamestate = GS_INTERMISSION; - viewactive = false; - automapactive = false; - // [RH] If you ever get a statistics driver operational, adapt this. // if (statcopy) // memcpy (statcopy, &wminfo, sizeof(wminfo)); - WI_Start (&staticWmInfo); + statusScreen = WI_Start (&staticWmInfo); } + bool endgame = strncmp(nextlevel.GetChars(), "enDSeQ", 6) == 0; + intermissionScreen = primaryLevel->CreateIntermission(); + auto nextinfo = !playinter || endgame? nullptr : FindLevelInfo(nextlevel.GetChars(), false); + RunIntermission(primaryLevel->info, nextinfo, intermissionScreen, statusScreen, [=](bool) + { + if (!endgame) primaryLevel->WorldDone(); + else D_StartTitle(); + }); } //========================================================================== @@ -849,7 +1156,7 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) uint32_t langtable[2] = {}; wminfo.finished_ep = cluster - 1; - wminfo.LName0 = TexMan.CheckForTexture(info->PName, ETextureType::MiscPatch); + wminfo.LName0 = TexMan.CheckForTexture(info->PName.GetChars(), ETextureType::MiscPatch); wminfo.thisname = info->LookupLevelName(&langtable[0]); // re-get the name so we have more info about its origin. if (!wminfo.LName0.isValid() || !(info->flags3 & LEVEL3_HIDEAUTHORNAME)) wminfo.thisauthor = info->AuthorName; wminfo.current = MapName; @@ -865,8 +1172,8 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) } else { - level_info_t *nextinfo = FindLevelInfo (nextlevel, false); - if (nextinfo == NULL || strncmp (nextlevel, "enDSeQ", 6) == 0) + level_info_t *nextinfo = FindLevelInfo (nextlevel.GetChars(), false); + if (nextinfo == NULL || strncmp (nextlevel.GetChars(), "enDSeQ", 6) == 0) { wminfo.next = ""; wminfo.LName1.SetInvalid(); @@ -876,7 +1183,7 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) else { wminfo.next = nextinfo->MapName; - wminfo.LName1 = TexMan.CheckForTexture(nextinfo->PName, ETextureType::MiscPatch); + wminfo.LName1 = TexMan.CheckForTexture(nextinfo->PName.GetChars(), ETextureType::MiscPatch); wminfo.nextname = nextinfo->LookupLevelName(&langtable[1]); if (!wminfo.LName1.isValid() || !(nextinfo->flags3 & LEVEL3_HIDEAUTHORNAME)) wminfo.nextauthor = nextinfo->AuthorName; } @@ -892,14 +1199,10 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) { if (texids[i]->isValid() && langtable[i] != FStringTable::default_table) { - FTexture *tex = TexMan.GetTexture(*texids[i]); - if (tex != nullptr) + FGameTexture *tex = TexMan.GetGameTexture(*texids[i]); + if (tex != nullptr && !tex->isUserContent()) { - int filenum = Wads.GetLumpFile(tex->GetSourceLump()); - if (filenum >= 0 && filenum <= Wads.GetMaxIwadNum()) - { - texids[i]->SetInvalid(); - } + texids[i]->SetInvalid(); } } } @@ -908,7 +1211,8 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) CheckWarpTransMap (wminfo.next, true); nextlevel = wminfo.next; - wminfo.next_ep = FindLevelInfo (wminfo.next)->cluster - 1; + wminfo.next_ep = FindLevelInfo (wminfo.next.GetChars())->cluster - 1; + wminfo.totalkills = killed_monsters; wminfo.maxkills = total_monsters; wminfo.maxitems = total_items; wminfo.maxsecret = total_secrets; @@ -957,6 +1261,8 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) // Intermission stats for entire hubs G_LeavingHub(this, mode, thiscluster, &wminfo); + // Do not allow playing sounds in here - they'd never be able to play properly. + soundEngine->BlockNewSounds(true); for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) @@ -964,6 +1270,7 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) G_PlayerFinishLevel (i, mode, changeflags); } } + soundEngine->BlockNewSounds(false); if (mode == FINISH_SameHub) { // Remember the level's state for re-entry. @@ -994,14 +1301,7 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) finishstate = mode; - if (!deathmatch && - ((flags & LEVEL_NOINTERMISSION) || - ((nextcluster == thiscluster) && (thiscluster->flags & CLUSTER_HUB) && !(thiscluster->flags & CLUSTER_ALLOWINTERMISSION)))) - { - WorldDone (); - return false; - } - return true; + return ShouldDoIntermission(nextcluster, thiscluster); } //========================================================================== @@ -1021,7 +1321,7 @@ IMPLEMENT_CLASS(DAutosaver, false, false) void DAutosaver::Tick () { - Net_WriteByte (DEM_CHECKAUTOSAVE); + Net_WriteInt8 (DEM_CHECKAUTOSAVE); Destroy (); } @@ -1052,7 +1352,7 @@ void G_DoLoadLevel(const FString &nextmapname, int position, bool autosave, bool gameaction = ga_nothing; // clear cmd building stuff - ResetButtonStates(); + buttonMap.ResetButtonStates(); SendItemUse = nullptr; SendItemDrop = nullptr; @@ -1080,7 +1380,7 @@ void FLevelLocals::DoLoadLevel(const FString &nextmapname, int position, bool au { UCVarValue val; val.Int = NextSkill; - gameskill.ForceSet (val, CVAR_Int); + gameskill->ForceSet (val, CVAR_Int); NextSkill = -1; } @@ -1104,7 +1404,7 @@ void FLevelLocals::DoLoadLevel(const FString &nextmapname, int position, bool au { FString mapname = nextmapname; mapname.ToUpper(); - Printf("\n%s\n\n" TEXTCOLOR_BOLD "%s - %s\n\n", console_bar, mapname.GetChars(), LevelName.GetChars()); + Printf(PRINT_HIGH | PRINT_NONOTIFY, "\n" TEXTCOLOR_NORMAL "%s\n\n" TEXTCOLOR_BOLD "%s - %s\n\n", console_bar, mapname.GetChars(), LevelName.GetChars()); } // Set the sky map. @@ -1112,7 +1412,7 @@ void FLevelLocals::DoLoadLevel(const FString &nextmapname, int position, bool au // a flat. The data is in the WAD only because // we look for an actual index, instead of simply // setting one. - skyflatnum = TexMan.GetTextureID (gameinfo.SkyFlatName, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + skyflatnum = TexMan.GetTextureID (gameinfo.SkyFlatName.GetChars(), ETextureType::Flat, FTextureManager::TEXMAN_Overridable); // [RH] Set up details about sky rendering InitSkyMap (this); @@ -1178,7 +1478,7 @@ void FLevelLocals::DoLoadLevel(const FString &nextmapname, int position, bool au for (int i = 0; imo != nullptr) - P_PlayerStartStomp(Players[i]->mo); + P_PlayerStartStomp(Players[i]->mo, !deathmatch); } } @@ -1241,10 +1541,7 @@ void FLevelLocals::DoLoadLevel(const FString &nextmapname, int position, bool au //========================================================================== void FLevelLocals::WorldDone (void) -{ - cluster_info_t *nextcluster; - cluster_info_t *thiscluster; - +{ gameaction = ga_worlddone; @@ -1254,110 +1551,11 @@ void FLevelLocals::WorldDone (void) BotInfo.RemoveAllBots(this, consoleplayer != Net_Arbitrator); } - if (flags & LEVEL_CHANGEMAPCHEAT) - return; - - thiscluster = FindClusterInfo (cluster); - - if (strncmp (nextlevel, "enDSeQ", 6) == 0) - { - FName endsequence = ENamedName(strtoll(nextlevel.GetChars()+6, NULL, 16)); - // Strife needs a special case here to choose between good and sad ending. Bad is handled elsewhere. - if (endsequence == NAME_Inter_Strife) - { - if (Players[0]->mo->FindInventory (NAME_QuestItem25) || - Players[0]->mo->FindInventory (NAME_QuestItem28)) - { - endsequence = NAME_Inter_Strife_Good; - } - else - { - endsequence = NAME_Inter_Strife_Sad; - } - } - - auto ext = info->ExitMapTexts.CheckKey(flags3 & LEVEL3_EXITSECRETUSED ? NAME_Secret : NAME_Normal); - if (ext != nullptr && (ext->mDefined & FExitText::DEF_TEXT)) - { - F_StartFinale(ext->mDefined & FExitText::DEF_MUSIC ? ext->mMusic : gameinfo.finaleMusic, - ext->mDefined & FExitText::DEF_MUSIC ? ext->mOrder : gameinfo.finaleOrder, - -1, 0, - ext->mDefined & FExitText::DEF_BACKDROP ? ext->mBackdrop : gameinfo.FinaleFlat, - ext->mText, - false, - ext->mDefined & FExitText::DEF_PIC, - ext->mDefined & FExitText::DEF_LOOKUP, - true, endsequence); - } - else if (!(info->flags2 & LEVEL2_NOCLUSTERTEXT)) - { - F_StartFinale(thiscluster->MessageMusic, thiscluster->musicorder, - thiscluster->cdtrack, thiscluster->cdid, - thiscluster->FinaleFlat, thiscluster->ExitText, - thiscluster->flags & CLUSTER_EXITTEXTINLUMP, - thiscluster->flags & CLUSTER_FINALEPIC, - thiscluster->flags & CLUSTER_LOOKUPEXITTEXT, - true, endsequence); - } - } - else if (!deathmatch) - { - FExitText *ext = nullptr; - - if (flags3 & LEVEL3_EXITSECRETUSED) ext = info->ExitMapTexts.CheckKey(NAME_Secret); - else if (flags3 & LEVEL3_EXITNORMALUSED) ext = info->ExitMapTexts.CheckKey(NAME_Normal); - if (ext == nullptr) ext = info->ExitMapTexts.CheckKey(nextlevel); - - if (ext != nullptr) - { - if ((ext->mDefined & FExitText::DEF_TEXT)) - { - F_StartFinale(ext->mDefined & FExitText::DEF_MUSIC ? ext->mMusic : gameinfo.finaleMusic, - ext->mDefined & FExitText::DEF_MUSIC ? ext->mOrder : gameinfo.finaleOrder, - -1, 0, - ext->mDefined & FExitText::DEF_BACKDROP ? ext->mBackdrop : gameinfo.FinaleFlat, - ext->mText, - false, - ext->mDefined & FExitText::DEF_PIC, - ext->mDefined & FExitText::DEF_LOOKUP, - false); - } - return; - } - - nextcluster = FindClusterInfo (FindLevelInfo (nextlevel)->cluster); - - if (nextcluster->cluster != cluster && !(info->flags2 & LEVEL2_NOCLUSTERTEXT)) - { - // Only start the finale if the next level's cluster is different - // than the current one and we're not in deathmatch. - if (nextcluster->EnterText.IsNotEmpty()) - { - F_StartFinale (nextcluster->MessageMusic, nextcluster->musicorder, - nextcluster->cdtrack, nextcluster->cdid, - nextcluster->FinaleFlat, nextcluster->EnterText, - nextcluster->flags & CLUSTER_ENTERTEXTINLUMP, - nextcluster->flags & CLUSTER_FINALEPIC, - nextcluster->flags & CLUSTER_LOOKUPENTERTEXT, - false); - } - else if (thiscluster->ExitText.IsNotEmpty()) - { - F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder, - thiscluster->cdtrack, nextcluster->cdid, - thiscluster->FinaleFlat, thiscluster->ExitText, - thiscluster->flags & CLUSTER_EXITTEXTINLUMP, - thiscluster->flags & CLUSTER_FINALEPIC, - thiscluster->flags & CLUSTER_LOOKUPEXITTEXT, - false); - } - } - } -} +} DEFINE_ACTION_FUNCTION(FLevelLocals, WorldDone) { - primaryLevel->WorldDone(); + // This is just a dummy to make old status screens happy. return 0; } @@ -1500,6 +1698,7 @@ int FLevelLocals::FinishTravel () pawn->ceilingpic = pawndup->ceilingpic; pawn->Floorclip = pawndup->Floorclip; pawn->waterlevel = pawndup->waterlevel; + pawn->waterdepth = pawndup->waterdepth; } else if (failnum == 0) // In the failure case this may run into some undefined data. { @@ -1513,7 +1712,7 @@ int FLevelLocals::FinishTravel () pawn->flags2 &= ~MF2_BLASTED; if (oldpawn != nullptr) { - DObject::StaticPointerSubstitution (oldpawn, pawn); + PlayerPointerSubstitution (oldpawn, pawn, true); oldpawn->Destroy(); } if (pawndup != NULL) @@ -1522,6 +1721,7 @@ int FLevelLocals::FinishTravel () } pawn->LinkToWorld (nullptr); pawn->ClearInterpolation(); + pawn->ClearFOVInterpolation(); const int tid = pawn->tid; // Save TID (actor isn't linked into the hash chain yet) pawn->tid = 0; // Reset TID pawn->SetTID(tid); // Set TID (and link actor into the hash chain) @@ -1532,6 +1732,7 @@ int FLevelLocals::FinishTravel () { inv->ChangeStatNum (STAT_INVENTORY); inv->LinkToWorld (nullptr); + P_FindFloorCeiling(inv, FFCF_ONLYSPAWNPOS); IFVIRTUALPTRNAME(inv, NAME_Inventory, Travelled) { @@ -1543,6 +1744,12 @@ int FLevelLocals::FinishTravel () { pawn->Speed = pawn->GetDefault()->Speed; } + + IFVIRTUALPTRNAME(pawn, NAME_PlayerPawn, Travelled) + { + VMValue params[1] = { pawn }; + VMCall(func, params, 1, nullptr, 0); + } // [ZZ] we probably don't want to fire any scripts before all players are in, especially with runNow = true. pawns[pawnsnum++] = pawn; } @@ -1575,6 +1782,7 @@ FLevelLocals::FLevelLocals() : Behaviors(this), tagManager(this) FLevelLocals::~FLevelLocals() { if (localEventManager) delete localEventManager; + if (aabbTree) delete aabbTree; } //========================================================================== @@ -1586,8 +1794,7 @@ void FLevelLocals::Init() { P_InitParticles(this); P_ClearParticles(this); - BaseBlendA = 0.0f; // Remove underwater blend effect, if any - + gravity = sv_gravity * 35/TICRATE; aircontrol = sv_aircontrol; AirControlChanged(); @@ -1598,30 +1805,34 @@ void FLevelLocals::Init() ImpactDecalCount = 0; frozenstate = 0; - info = FindLevelInfo (MapName); + info = FindLevelInfo (MapName.GetChars()); skyspeed1 = info->skyspeed1; skyspeed2 = info->skyspeed2; - skytexture1 = TexMan.GetTextureID(info->SkyPic1, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); - skytexture2 = TexMan.GetTextureID(info->SkyPic2, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); + skytexture1 = TexMan.GetTextureID(info->SkyPic1.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); + skytexture2 = TexMan.GetTextureID(info->SkyPic2.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); fadeto = info->fadeto; cdtrack = info->cdtrack; cdid = info->cdid; FromSnapshot = false; if (fadeto == 0) { - if (strnicmp (info->FadeTable, "COLORMAP", 8) != 0) + if (strnicmp (info->FadeTable.GetChars(), "COLORMAP", 8) != 0) { flags |= LEVEL_HASFADETABLE; } } + + + globalcolormap = R_ColormapNumForName(info->CustomColorMap.GetChars()); airsupply = info->airsupply*TICRATE; outsidefog = info->outsidefog; WallVertLight = info->WallVertLight*2; WallHorizLight = info->WallHorizLight*2; if (info->gravity != 0.f) { - gravity = info->gravity * 35/TICRATE; + if (info->gravity == DBL_MAX) gravity = 0; + else gravity = info->gravity * 35/TICRATE; } if (info->aircontrol != 0.f) { @@ -1644,6 +1855,7 @@ void FLevelLocals::Init() flags2 |= info->flags2; flags3 |= info->flags3; levelnum = info->levelnum; + LightningSound = info->LightningSound; Music = info->Music; musicorder = info->musicorder; MusicVolume = 1.f; @@ -1665,12 +1877,11 @@ void FLevelLocals::Init() pixelstretch = info->pixelstretch; - compatflags.Callback(); - compatflags2.Callback(); + compatflags->Callback(); + compatflags2->Callback(); DefaultEnvironment = info->DefaultEnvironment; - lightMode = info->lightmode == ELightMode::NotSet? (ELightMode)*gl_lightmode : info->lightmode; brightfog = info->brightfog < 0? gl_brightfog : !!info->brightfog; lightadditivesurfaces = info->lightadditivesurfaces < 0 ? gl_lightadditivesurfaces : !!info->lightadditivesurfaces; notexturefill = info->notexturefill < 0 ? gl_notexturefill : !!info->notexturefill; @@ -1691,8 +1902,7 @@ FString CalcMapName (int episode, int level) } else { - lumpname = ""; - lumpname << 'E' << ('0' + episode) << 'M' << ('0' + level); + lumpname.Format("E%01dM%01d", episode, level); } return lumpname; } @@ -1758,7 +1968,7 @@ void G_WriteVisited(FSerializer &arc) { if (wi.flags & LEVEL_VISITED) { - arc.AddString(nullptr, wi.MapName); + arc.AddString(nullptr, wi.MapName.GetChars()); } } arc.EndArray(); @@ -1776,9 +1986,8 @@ void G_WriteVisited(FSerializer &arc) { if (playeringame[i]) { - FString key; - key.Format("%d", i); - arc(key, players[i].cls); + FStringf key("%d", i); + arc(key.GetChars(), players[i].cls); } } arc.EndObject(); @@ -1797,31 +2006,28 @@ void G_ReadSnapshots(FResourceFile *resf) G_ClearSnapshots(); - for (unsigned j = 0; j < resf->LumpCount(); j++) + for (unsigned j = 0; j < resf->EntryCount(); j++) { - FResourceLump * resl = resf->GetLump(j); - if (resl != nullptr) + auto name = resf->getName(j); + auto ptr = strstr(name, ".map.json"); + if (ptr != nullptr) { - auto ptr = strstr(resl->FullName, ".map.json"); - if (ptr != nullptr) + ptrdiff_t maplen = ptr - name; + FString mapname(name, (size_t)maplen); + i = FindLevelInfo(mapname.GetChars()); + if (i != nullptr) { - ptrdiff_t maplen = ptr - resl->FullName.GetChars(); - FString mapname(resl->FullName.GetChars(), (size_t)maplen); - i = FindLevelInfo(mapname); - if (i != nullptr) - { - i->Snapshot = resl->GetRawData(); - } + i->Snapshot = resf->GetRawData(j); } - else + } + else + { + auto ptr = strstr(name, ".mapd.json"); + if (ptr != nullptr) { - auto ptr = strstr(resl->FullName, ".mapd.json"); - if (ptr != nullptr) - { - ptrdiff_t maplen = ptr - resl->FullName.GetChars(); - FString mapname(resl->FullName.GetChars(), (size_t)maplen); - TheDefaultLevelInfo.Snapshot = resl->GetRawData(); - } + ptrdiff_t maplen = ptr - name; + FString mapname(name, (size_t)maplen); + TheDefaultLevelInfo.Snapshot = resf->GetRawData(j); } } } @@ -1840,7 +2046,7 @@ void G_ReadVisited(FSerializer &arc) { FString str; arc(nullptr, str); - auto i = FindLevelInfo(str); + auto i = FindLevelInfo(str.GetChars()); if (i != nullptr) i->flags |= LEVEL_VISITED; } arc.EndArray(); @@ -1852,9 +2058,8 @@ void G_ReadVisited(FSerializer &arc) { for (int i = 0; i < MAXPLAYERS; ++i) { - FString key; - key.Format("%d", i); - arc(key, players[i].cls); + FStringf key("%d", i); + arc(key.GetChars(), players[i].cls); } arc.EndObject(); } @@ -1886,7 +2091,7 @@ void P_WriteACSDefereds (FSerializer &arc) { if (wi.deferred.Size() > 0) { - arc(wi.MapName, wi.deferred); + arc(wi.MapName.GetChars(), wi.deferred); } } } @@ -2114,9 +2319,9 @@ void FLevelLocals::SetInterMusic(const char *nextmap) { auto mus = info->MapInterMusic.CheckKey(nextmap); if (mus != nullptr) - S_ChangeMusic(mus->first, mus->second); + S_ChangeMusic(mus->first.GetChars(), mus->second); else if (info->InterMusic.IsNotEmpty()) - S_ChangeMusic(info->InterMusic, info->intermusicorder); + S_ChangeMusic(info->InterMusic.GetChars(), info->intermusicorder); else S_ChangeMusic(gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); } @@ -2125,7 +2330,7 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, SetInterMusic) { PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); PARAM_STRING(map); - self->SetInterMusic(map); + self->SetInterMusic(map.GetChars()); return 0; } @@ -2232,6 +2437,33 @@ int IsPointInMap(FLevelLocals *Level, double x, double y, double z) void FLevelLocals::SetMusic() { - S_ChangeMusic(Music, musicorder); + S_ChangeMusic(Music.GetChars(), musicorder); +} + + +DEFINE_ACTION_FUNCTION(FLevelLocals, GetClusterName) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals) + cluster_info_t* cluster = FindClusterInfo(self->cluster); + FString retval; + + if (cluster) + { + if (cluster->flags & CLUSTER_LOOKUPNAME) + retval = GStrings.GetString(cluster->ClusterName); + else + retval = cluster->ClusterName; + } + ACTION_RETURN_STRING(retval); +} + +DEFINE_ACTION_FUNCTION(FLevelLocals, GetEpisodeName) +{ + // this is a bit of a crapshoot because ZDoom never assigned a level to an episode + // and retroactively fixing this is not possible. + // This will need some heuristics to assign a proper episode to each existing level. + // Stuff for later. for now this just checks the STAT module for the currently running episode, + // which should be fine unless cheating. + ACTION_RETURN_STRING(GStrings.localize(STAT_EpisodeName().GetChars())); } diff --git a/src/g_level.h b/src/g_level.h index 5a8ca237c26..71ae6f2762e 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -3,10 +3,10 @@ #include "doomtype.h" #include "vectors.h" #include "sc_man.h" -#include "resourcefiles/file_zip.h" #include "g_mapinfo.h" +using FileSys::FCompressedBuffer; extern bool savegamerestore; void G_InitNew (const char *mapname, bool bTitleLevel); @@ -15,8 +15,8 @@ void G_InitNew (const char *mapname, bool bTitleLevel); // A normal game starts at map 1, // but a warp test can start elsewhere void G_DeferedInitNew (const char *mapname, int skill = -1); -struct FGameStartup; -void G_DeferedInitNew (FGameStartup *gs); +struct FNewGameStartup; +void G_DeferedInitNew (FNewGameStartup *gs); enum { diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 863133705db..cf63f81b2da 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -54,6 +54,8 @@ #include "r_data/r_sections.h" #include "r_data/r_canvastexture.h" #include "r_data/r_interpolate.h" +#include "doom_aabbtree.h" +#include "doom_levelmesh.h" //============================================================================ // @@ -101,6 +103,7 @@ struct EventManager; typedef TMap FDialogueIDMap; // maps dialogue IDs to dialogue array index (for ACS) typedef TMap FDialogueMap; // maps actor class names to dialogue array index typedef TMap FUDMFKeyMap; +class DIntermissionController; struct FLevelLocals { @@ -121,12 +124,13 @@ struct FLevelLocals friend class MapLoader; + DIntermissionController* CreateIntermission(); void Tick(); void Mark(); void AddScroller(int secnum); void SetInterMusic(const char *nextmap); void SetMusicVolume(float v); - void ClearLevelData(); + void ClearLevelData(bool fullgc = true); void ClearPortals(); bool CheckIfExitIsGood(AActor *self, level_info_t *newmap); void FormatMapName(FString &mapname, const char *mapnamecolor); @@ -149,7 +153,8 @@ struct FLevelLocals void Init(); private: - line_t *FindPortalDestination(line_t *src, int tag); + bool ShouldDoIntermission(cluster_info_t* nextcluster, cluster_info_t* thiscluster); + line_t *FindPortalDestination(line_t *src, int tag, int matchtype = -1); void BuildPortalBlockmap(); void UpdatePortal(FLinePortal *port); void CollectLinkedPortals(); @@ -164,6 +169,7 @@ struct FLevelLocals void ReadOnePlayer(FSerializer &arc, bool skipload); void ReadMultiplePlayers(FSerializer &arc, int numPlayers, int numPlayersNow, bool skipload); void SerializeSounds(FSerializer &arc); + void PlayerSpawnPickClass (int playernum); public: void SnapshotLevel(); @@ -188,7 +194,7 @@ struct FLevelLocals AActor *SpawnMapThing(int index, FMapThing *mt, int position); AActor *SpawnPlayer(FPlayerStart *mthing, int playernum, int flags = 0); void StartLightning(); - void ForceLightning(int mode); + void ForceLightning(int mode, FSoundID tempSound = NO_SOUND); void ClearDynamic3DFloorData(); void WorldDone(void); void AirControlChanged(); @@ -373,6 +379,11 @@ struct FLevelLocals return PointInSubsector(pos.X, pos.Y)->sector; } + sector_t* PointInSector(const DVector3& pos) + { + return PointInSubsector(pos.X, pos.Y)->sector; + } + sector_t *PointInSector(double x, double y) { return PointInSubsector(x, y)->sector; @@ -383,6 +394,11 @@ struct FLevelLocals return PointInRenderSubsector(FloatToFixed(pos.X), FloatToFixed(pos.Y)); } + subsector_t* PointInRenderSubsector(const DVector3& pos) + { + return PointInRenderSubsector(FloatToFixed(pos.X), FloatToFixed(pos.Y)); + } + FPolyObj *GetPolyobj (int polyNum) { auto index = Polyobjects.FindEx([=](const auto &poly) { return poly.tag == polyNum; }); @@ -411,6 +427,8 @@ struct FLevelLocals DThinker *thinker = static_cast(cls->CreateNew()); assert(thinker->IsKindOf(RUNTIME_CLASS(DThinker))); thinker->ObjectFlags |= OF_JustSpawned; + if (thinker->IsKindOf(RUNTIME_CLASS(DVisualThinker))) // [MC] This absolutely must happen for this class! + statnum = STAT_VISUALTHINKER; Thinkers.Link(thinker, statnum); thinker->Level = this; return thinker; @@ -426,9 +444,9 @@ struct FLevelLocals void SetMusic(); - TArray vertexes; TArray sectors; + TArray extsectors; // container for non-trivial sector information. sector_t must be trivially copyable for *_fakeflat to work as intended. TArray linebuffer; // contains the line lists for the sectors. TArray subsectorbuffer; // contains the subsector lists for the sectors. TArray lines; @@ -447,6 +465,20 @@ struct FLevelLocals TArray sectorPortals; TArray linePortals; + // Lightmaps + TArray LMSurfaces; + TArray LMTexCoords; + int LMTextureCount = 0; + int LMTextureSize = 0; + TArray LMTextureData; + TArray LightProbes; + int LPMinX = 0; + int LPMinY = 0; + int LPWidth = 0; + int LPHeight = 0; + static const int LPCellSize = 32; + TArray LPCells; + // Portal information. FDisplacementTable Displacements; FPortalBlockmap PortalBlockmap; @@ -456,6 +488,8 @@ struct FLevelLocals FSectionContainer sections; FCanvasTextureInfo canvasTextureInfo; EventManager *localEventManager = nullptr; + DoomLevelAABBTree* aabbTree = nullptr; + DoomLevelMesh* levelMesh = nullptr; // [ZZ] Destructible geometry information TMap healthGroups; @@ -520,7 +554,7 @@ struct FLevelLocals static const int BODYQUESIZE = 32; TObjPtr bodyque[BODYQUESIZE]; - TObjPtr automap = nullptr; + TObjPtr automap = MakeObjPtr(nullptr); int bodyqueslot; // For now this merely points to the global player array, but with this in place, access to this array can be moved over to the level. @@ -579,6 +613,12 @@ struct FLevelLocals return p->camera == mo; } + bool MBF21Enabled() const + { + // The affected features only are a problem with Doom format maps - the flag should have no effect in Hexen and UDMF format. + return !(i_compatflags2 & COMPATF2_NOMBF21) || maptype != MAPTYPE_DOOM; + } + int NumMapSections; uint32_t flags; @@ -591,6 +631,7 @@ struct FLevelLocals uint32_t hazardcolor; // what color strife hazard blends the screen color as uint32_t hazardflash; // what color strife hazard flashes the screen color as + FString LightningSound = "world/thunder"; FString Music; int musicorder; int cdtrack; @@ -604,6 +645,7 @@ struct FLevelLocals double sky1pos, sky2pos; float hw_sky1pos, hw_sky2pos; bool skystretch; + uint32_t globalcolormap; int total_secrets; int found_secrets; @@ -626,6 +668,7 @@ struct FLevelLocals DSeqNode *SequenceListHead; // [RH] particle globals + uint32_t OldestParticle; // [MC] Oldest particle for replacing with SPF_REPLACE uint32_t ActiveParticles; uint32_t InactiveParticles; TArray Particles; @@ -654,7 +697,6 @@ struct FLevelLocals float MusicVolume; // Hardware render stuff that can either be set via CVAR or MAPINFO - ELightMode lightMode; bool brightfog; bool lightadditivesurfaces; bool notexturefill; @@ -664,10 +706,10 @@ struct FLevelLocals // links to global game objects TArray> CorpseQueue; - TObjPtr FraggleScriptThinker = nullptr; - TObjPtr ACSThinker = nullptr; + TObjPtr FraggleScriptThinker = MakeObjPtr(nullptr); + TObjPtr ACSThinker = MakeObjPtr(nullptr); - TObjPtr SpotState = nullptr; + TObjPtr SpotState = MakeObjPtr(nullptr); //========================================================================== // @@ -796,19 +838,19 @@ inline FLevelLocals *line_t::GetLevel() const } inline FLinePortal *line_t::getPortal() const { - return portalindex >= GetLevel()->linePortals.Size() ? (FLinePortal*)nullptr : &GetLevel()->linePortals[portalindex]; + return portalindex == UINT_MAX && portalindex >= GetLevel()->linePortals.Size() ? (FLinePortal*)nullptr : &GetLevel()->linePortals[portalindex]; } // returns true if the portal is crossable by actors inline bool line_t::isLinePortal() const { - return portalindex >= GetLevel()->linePortals.Size() ? false : !!(GetLevel()->linePortals[portalindex].mFlags & PORTF_PASSABLE); + return portalindex == UINT_MAX && portalindex >= GetLevel()->linePortals.Size() ? false : !!(GetLevel()->linePortals[portalindex].mFlags & PORTF_PASSABLE); } // returns true if the portal needs to be handled by the renderer inline bool line_t::isVisualPortal() const { - return portalindex >= GetLevel()->linePortals.Size() ? false : !!(GetLevel()->linePortals[portalindex].mFlags & PORTF_VISIBLE); + return portalindex == UINT_MAX && portalindex >= GetLevel()->linePortals.Size() ? false : !!(GetLevel()->linePortals[portalindex].mFlags & PORTF_VISIBLE); } inline line_t *line_t::getPortalDestination() const @@ -816,16 +858,36 @@ inline line_t *line_t::getPortalDestination() const return portalindex >= GetLevel()->linePortals.Size() ? (line_t*)nullptr : GetLevel()->linePortals[portalindex].mDestination; } +inline int line_t::getPortalFlags() const +{ + return portalindex >= GetLevel()->linePortals.Size() ? 0 : GetLevel()->linePortals[portalindex].mFlags; +} + inline int line_t::getPortalAlignment() const { return portalindex >= GetLevel()->linePortals.Size() ? 0 : GetLevel()->linePortals[portalindex].mAlign; } +inline int line_t::getPortalType() const +{ + return portalindex >= GetLevel()->linePortals.Size() ? 0 : GetLevel()->linePortals[portalindex].mType; +} + +inline DVector2 line_t::getPortalDisplacement() const +{ + return portalindex >= GetLevel()->linePortals.Size() ? DVector2(0., 0.) : GetLevel()->linePortals[portalindex].mDisplacement; +} + +inline DAngle line_t::getPortalAngleDiff() const +{ + return portalindex >= GetLevel()->linePortals.Size() ? DAngle::fromDeg(0.) : GetLevel()->linePortals[portalindex].mAngleDiff; +} + inline bool line_t::hitSkyWall(AActor* mo) const { return backsector && backsector->GetTexture(sector_t::ceiling) == skyflatnum && - mo->Z() >= backsector->ceilingplane.ZatPoint(mo->PosRelative(this)); + mo->Z() >= backsector->ceilingplane.ZatPoint(mo->PosRelative(this).XY()); } // This must later be extended to return an array with all levels. @@ -834,3 +896,5 @@ inline TArrayView AllLevels() { return TArrayView(&primaryLevel, 1); } + +ELightMode getRealLightmode(FLevelLocals* Level, bool for3d); diff --git a/src/g_pch.h b/src/g_pch.h index bad3eda563b..a6623a2dad5 100644 --- a/src/g_pch.h +++ b/src/g_pch.h @@ -1,3 +1,4 @@ +#pragma once #include #include #include @@ -9,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/g_pch2.h b/src/g_pch2.h index 4cd69197e04..5ac06f8f077 100644 --- a/src/g_pch2.h +++ b/src/g_pch2.h @@ -1,4 +1,5 @@ // This is separate because the files being compiled with it use different compiler settings which may affect how the header is compiled +#pragma once #include #include #include @@ -10,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/g_statusbar/hudmessages.cpp b/src/g_statusbar/hudmessages.cpp index c4ea1cf8dca..c03922505a0 100644 --- a/src/g_statusbar/hudmessages.cpp +++ b/src/g_statusbar/hudmessages.cpp @@ -32,17 +32,18 @@ ** */ -#include "templates.h" + #include "doomdef.h" #include "sbar.h" #include "c_cvars.h" #include "v_video.h" #include "cmdlib.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "doomstat.h" #include "vm.h" - -EXTERN_CVAR(Int, con_scaletext) +#include "c_console.h" +#include "v_draw.h" IMPLEMENT_CLASS(DHUDMessageBase, false, true) IMPLEMENT_POINTERS_START(DHUDMessageBase) @@ -207,26 +208,11 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h TextColor = textColor; State = 0; - SourceText = copystring (text); + SourceText = text; VisibilityFlags = 0; Style = STYLE_Translucent; Alpha = 1.; - ResetText (SourceText); -} - -//============================================================================ -// -// DHUDMessage Destructor -// -//============================================================================ - -void DHUDMessage::OnDestroy() -{ - if (SourceText != NULL) - { - delete[] SourceText; - SourceText = nullptr; - } + ResetText (SourceText.GetChars()); } //============================================================================ @@ -262,7 +248,7 @@ void DHUDMessage::Serialize(FSerializer &arc) if (arc.isReading()) { - ResetText(SourceText); + ResetText(SourceText.GetChars()); } } @@ -276,7 +262,7 @@ void DHUDMessage::ScreenSizeChanged () { if (HUDWidth == 0) { - ResetText (SourceText); + ResetText (SourceText.GetChars()); } } @@ -297,12 +283,12 @@ void DHUDMessage::CalcClipCoords(int hudheight) { // No clipping rectangle set; use the full screen. ClipLeft = 0; ClipTop = 0; - ClipRight = screen->GetWidth(); - ClipBot = screen->GetHeight(); + ClipRight = twod->GetWidth(); + ClipBot = twod->GetHeight(); } else { - screen->VirtualToRealCoordsInt(x, y, w, h, + VirtualToRealCoordsInt(twod, x, y, w, h, HUDWidth, hudheight, false, HandleAspect); ClipLeft = x; ClipTop = y; @@ -327,7 +313,7 @@ void DHUDMessage::ResetText (const char *text) } else { - width = SCREENWIDTH / active_con_scaletext(); + width = twod->GetWidth() / active_con_scaletext(twod); } Lines = V_BreakLines (Font, NoWrap ? INT_MAX : width, (uint8_t *)text); @@ -339,7 +325,7 @@ void DHUDMessage::ResetText (const char *text) for (auto &line : Lines) { Height += Font->GetHeight (); - Width = MAX (Width, line.Width); + Width = max (Width, line.Width); } } @@ -382,12 +368,12 @@ void DHUDMessage::Draw (int bottom, int visibility) DrawSetup (); - int screen_width = SCREENWIDTH; - int screen_height = SCREENHEIGHT; + int screen_width = twod->GetWidth(); + int screen_height = twod->GetHeight(); xscale = yscale = 1; if (HUDWidth == 0) { - int scale = active_con_scaletext(); + int scale = active_con_scaletext(twod); screen_width /= scale; screen_height /= scale; bottom /= scale; @@ -491,10 +477,10 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) { if (hudheight == 0) { - int scale = active_con_scaletext(); - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH / scale, - DTA_VirtualHeight, SCREENHEIGHT / scale, + int scale = active_con_scaletext(twod); + DrawText(twod, Font, TextColor, x, y, Lines[linenum].Text.GetChars(), + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, DTA_Alpha, Alpha, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -502,7 +488,7 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) } else { - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DrawText(twod, Font, TextColor, x, y, Lines[linenum].Text.GetChars(), DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, DTA_ClipLeft, ClipLeft, @@ -584,10 +570,10 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh float trans = float(Alpha * -(Tics - FadeOutTics) / FadeOutTics); if (hudheight == 0) { - int scale = active_con_scaletext(); - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH / scale, - DTA_VirtualHeight, SCREENHEIGHT / scale, + int scale = active_con_scaletext(twod); + DrawText(twod, Font, TextColor, x, y, Lines[linenum].Text.GetChars(), + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, DTA_Alpha, trans, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -595,7 +581,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh } else { - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DrawText(twod, Font, TextColor, x, y, Lines[linenum].Text.GetChars(), DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, DTA_ClipLeft, ClipLeft, @@ -673,10 +659,10 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu float trans = float(Alpha * Tics / FadeInTics); if (hudheight == 0) { - int scale = active_con_scaletext(); - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH / scale, - DTA_VirtualHeight, SCREENHEIGHT / scale, + int scale = active_con_scaletext(twod); + DrawText(twod, Font, TextColor, x, y, Lines[linenum].Text.GetChars(), + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, DTA_Alpha, trans, DTA_RenderStyle, Style, DTA_KeepRatio, true, @@ -684,7 +670,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu } else { - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DrawText(twod, Font, TextColor, x, y, Lines[linenum].Text.GetChars(), DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, DTA_ClipLeft, ClipLeft, @@ -750,7 +736,7 @@ void DHUDMessageTypeOnFadeOut::Serialize(FSerializer &arc) LineLen = CurrLine = 0; } - clamp(LineVisible, 0, LineLen); + LineVisible = clamp(LineVisible, 0, LineLen); } } @@ -857,10 +843,10 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in { if (hudheight == 0) { - int scale = active_con_scaletext(); - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, - DTA_VirtualWidth, SCREENWIDTH / scale, - DTA_VirtualHeight, SCREENHEIGHT / scale, + int scale = active_con_scaletext(twod); + DrawText(twod, Font, TextColor, x, y, Lines[linenum].Text.GetChars(), + DTA_VirtualWidth, twod->GetWidth() / scale, + DTA_VirtualHeight, twod->GetHeight() / scale, DTA_KeepRatio, true, DTA_TextLen, LineVisible, DTA_Alpha, Alpha, @@ -869,7 +855,7 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in } else { - screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DrawText(twod, Font, TextColor, x, y, Lines[linenum].Text.GetChars(), DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, DTA_ClipLeft, ClipLeft, @@ -888,3 +874,39 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in DHUDMessageFadeOut::DoDraw (linenum, x, y, clean, hudheight); } } + +/* Printing in the middle of the screen */ + +CVAR(Float, con_midtime, 3.f, CVAR_ARCHIVE) + +const char* console_bar = "----------------------------------------"; + +void C_MidPrint(FFont* font, const char* msg, bool bold) +{ + if (StatusBar == nullptr || screen == nullptr) + return; + + // [MK] allow the status bar to take over MidPrint + IFVIRTUALPTR(StatusBar, DBaseStatusBar, ProcessMidPrint) + { + FString msgstr = msg; + VMValue params[] = { (DObject*)StatusBar, font, &msgstr, bold }; + int rv; + VMReturn ret(&rv); + VMCall(func, params, countof(params), &ret, 1); + if (!!rv) return; + } + + if (msg != nullptr) + { + auto color = (EColorRange)PrintColors[bold ? PRINTLEVELS + 1 : PRINTLEVELS]; + Printf(PRINT_HIGH | PRINT_NONOTIFY, TEXTCOLOR_ESCAPESTR "%c%s\n%s\n%s\n", color, console_bar, msg, console_bar); + + StatusBar->AttachMessage(Create(font, msg, 1.5f, 0.375f, 0, 0, color, con_midtime), MAKE_ID('C', 'N', 'T', 'R')); + } + else + { + StatusBar->DetachMessage(MAKE_ID('C', 'N', 'T', 'R')); + } +} + diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 350d1350287..a1fa6926c94 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -35,13 +35,25 @@ #ifndef __SBAR_H__ #define __SBAR_H__ -#include "dobject.h" +#include "base_sbar.h" #include "v_collection.h" #include "v_text.h" -#include "r_data/renderstyle.h" +#include "renderstyle.h" +#include "v_2ddrawer.h" +#include "v_draw.h" +#include "c_cvars.h" + +class AActor; + +EXTERN_CVAR(Int, con_scaletext); +inline int active_con_scaletext(F2DDrawer* drawer, bool newconfont = false) +{ + return newconfont ? GetConScale(drawer, con_scaletext) : GetUIScale(drawer, con_scaletext); +} class player_t; struct FRemapTable; +class FGameTexture; enum EHudState { @@ -73,7 +85,8 @@ class DHUDMessageBase : public DObject void CallDraw(int bottom, int visibility); private: - TObjPtr Next = nullptr; + TObjPtr Next = MakeObjPtr(nullptr); +; uint32_t SBarID = 0; friend class DBaseStatusBar; @@ -87,7 +100,6 @@ class DHUDMessage : public DHUDMessageBase public: DHUDMessage (FFont *font, const char *text, float x, float y, int hudwidth, int hudheight, EColorRange textColor, float holdTime); - virtual void OnDestroy () override; virtual void Serialize(FSerializer &arc); @@ -113,7 +125,7 @@ class DHUDMessage : public DHUDMessageBase void SetNoWrap(bool nowrap) { NoWrap = nowrap; - ResetText(SourceText); + ResetText(SourceText.GetChars()); } void SetClipRect(int x, int y, int width, int height, bool aspect) { @@ -126,7 +138,7 @@ class DHUDMessage : public DHUDMessageBase void SetWrapWidth(int wrap) { WrapWidth = wrap; - ResetText(SourceText); + ResetText(SourceText.GetChars()); } protected: @@ -148,10 +160,10 @@ class DHUDMessage : public DHUDMessageBase double Alpha; void CalcClipCoords(int hudheight); - DHUDMessage () : SourceText(NULL) {} + DHUDMessage() = default; private: - char *SourceText; + FString SourceText; }; @@ -233,7 +245,7 @@ struct FMugShotFrame FMugShotFrame(); ~FMugShotFrame(); - FTexture *GetTexture(const char *default_face, const char *skin_face, int random, int level=0, + FGameTexture *GetTexture(const char *default_face, const char *skin_face, int random, int level=0, int direction=0, bool usesLevels=false, bool health2=false, bool healthspecial=false, bool directional=false); }; @@ -256,7 +268,7 @@ struct FMugShotState void Tick(); void Reset(); FMugShotFrame &GetCurrentFrame() { return Frames[Position]; } - FTexture *GetCurrentFrameTexture(const char *default_face, const char *skin_face, int level=0, int direction=0) + FGameTexture *GetCurrentFrameTexture(const char *default_face, const char *skin_face, int level=0, int direction=0) { return GetCurrentFrame().GetTexture(default_face, skin_face, Random, level, direction, bUsesLevels, bHealth2, bHealthSpecial, bDirectional); } @@ -287,7 +299,7 @@ class FMugShot void Tick(player_t *player); bool SetState(const char *state_name, bool wait_till_done=false, bool reset=false); int UpdateState(player_t *player, StateFlags stateflags=STANDARD); - FTexture *GetFace(player_t *player, const char *default_face, int accuracy, StateFlags stateflags=STANDARD); + FGameTexture *GetFace(player_t *player, const char *default_face, int accuracy, StateFlags stateflags=STANDARD); private: FMugShotState *CurrentState; @@ -308,7 +320,7 @@ int FindMugShotStateIndex(FName state); // Base Status Bar ---------------------------------------------------------- -class FTexture; +class FGameTexture; enum { @@ -321,34 +333,10 @@ enum }; -//============================================================================ -// -// encapsulates all settings a HUD font may need -// -//============================================================================ - -class DHUDFont : public DObject -{ - // this blocks CreateNew on this class which is the intent here. - DECLARE_ABSTRACT_CLASS(DHUDFont, DObject); - -public: - FFont *mFont; - int mSpacing; - EMonospacing mMonospacing; - int mShadowX; - int mShadowY; - - DHUDFont(FFont *f, int sp, EMonospacing ms, int sx, int sy) - : mFont(f), mSpacing(sp), mMonospacing(ms), mShadowX(sx), mShadowY(sy) - {} -}; - - -class DBaseStatusBar : public DObject +class DBaseStatusBar : public DStatusBarCore { friend class DSBarInfo; - DECLARE_CLASS (DBaseStatusBar, DObject) + DECLARE_CLASS (DBaseStatusBar, DStatusBarCore) HAS_OBJECT_POINTERS public: // Popup screens for Strife's status bar @@ -381,26 +369,7 @@ class DBaseStatusBar : public DObject }; - enum EAlign - { - TOP = 0, - VCENTER = 1, - BOTTOM = 2, - VOFFSET = 3, - VMASK = 3, - - LEFT = 0, - HCENTER = 4, - RIGHT = 8, - HOFFSET = 12, - HMASK = 12, - - CENTER = VCENTER | HCENTER, - CENTER_BOTTOM = BOTTOM | HCENTER - }; - DBaseStatusBar (); - void SetSize(int reltop = 32, int hres = 320, int vres = 200, int hhres = -1, int hvres = -1); void OnDestroy() override; void AttachMessage (DHUDMessageBase *msg, uint32_t id=0, int layer=HUDMSGLayer_Default); @@ -424,7 +393,7 @@ class DBaseStatusBar : public DObject void DrawBottomStuff (EHudState state); void DrawTopStuff (EHudState state); void AttachToPlayer(player_t *player); - DVector2 GetHUDScale() const; + DVector2 GetHUDScale() const override; virtual void FlashCrosshair (); void NewGame (); virtual void ScreenSizeChanged (); @@ -433,21 +402,12 @@ class DBaseStatusBar : public DObject virtual bool MustDrawLog(EHudState state); virtual void SetMugShotState (const char *state_name, bool wait_till_done=false, bool reset=false); void DrawLog(); - uint32_t GetTranslation() const; + FTranslationID GetTranslation() const override; void CreateAltHUD(); void DrawAltHUD(); - void DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY); - void DrawString(FFont *font, const FString &cstring, double x, double y, int flags, double Alpha, int translation, int spacing, EMonospacing monospacing, int shadowX, int shadowY, double scaleX, double scaleY); - void TransformRect(double &x, double &y, double &w, double &h, int flags = 0); - void Fill(PalEntry color, double x, double y, double w, double h, int flags = 0); - void SetClipRect(double x, double y, double w, double h, int flags = 0); - - void BeginStatusBar(int resW, int resH, int relTop, bool forceScaled); - void BeginHUD(int resW, int resH, double Alpha, bool forceScaled = false); bool ForceHUDScale(bool on) { std::swap(ForcedScale, on); return on; } // This is for SBARINFO which should not use BeginStatusBar or BeginHUD. - void StatusbarToRealCoords(double &x, double &y, double &w, double &h) const; int GetTopOfStatusbar() const { return SBarTop; @@ -470,19 +430,10 @@ class DBaseStatusBar : public DObject void DrawCrosshair (); // Sizing info for ths status bar. - int ST_X; - int ST_Y; - int SBarTop; - DVector2 SBarScale; - int RelTop; - int HorizontalResolution, VerticalResolution; bool Scaled; // This needs to go away. - DVector2 defaultScale; // factor for fully scaled fullscreen display. - bool ForcedScale = false; bool Centering; bool FixedOrigin; - bool CompleteBorder; double CrosshairSize; double Displacement; bool ShowLog; @@ -491,10 +442,6 @@ class DBaseStatusBar : public DObject player_t *CPlayer; - double Alpha = 1.; - DVector2 drawOffset = { 0,0 }; // can be set by subclasses to offset drawing operations - double drawClip[4] = { 0,0,0,0 }; // defines a clipping rectangle (not used yet) - bool fullscreenOffsets = false; // current screen is displayed with fullscreen behavior. FMugShot mugshot; private: @@ -502,16 +449,8 @@ class DBaseStatusBar : public DObject void DrawMessages (int layer, int bottom); void DrawConsistancy () const; void DrawWaiting () const; - void SetDrawSize(int reltop, int hres, int vres); TObjPtr Messages[NUM_HUDMSGLAYERS]; - - int BaseRelTop; - int BaseSBarHorizontalResolution; - int BaseSBarVerticalResolution; - int BaseHUDHorizontalResolution; - int BaseHUDVerticalResolution; - }; extern DBaseStatusBar *StatusBar; @@ -525,87 +464,12 @@ DBaseStatusBar *CreateCustomStatusBar(int script=0); void ST_LoadCrosshair(bool alwaysload=false); void ST_Clear(); void ST_CreateStatusBar(bool bTitleLevel); -extern FTexture *CrosshairImage; int GetInventoryIcon(AActor *item, uint32_t flags, int *applyscale = nullptr); +class FFont; +void C_MidPrint(FFont* font, const char* message, bool bold = false); -enum DI_Flags -{ - DI_SKIPICON = 0x1, - DI_SKIPALTICON = 0x2, - DI_SKIPSPAWN = 0x4, - DI_SKIPREADY = 0x8, - DI_ALTICONFIRST = 0x10, - DI_TRANSLATABLE = 0x20, - DI_FORCESCALE = 0x40, - DI_DIM = 0x80, - DI_DRAWCURSORFIRST = 0x100, // only for DrawInventoryBar. - DI_ALWAYSSHOWCOUNT = 0x200, // only for DrawInventoryBar. - DI_DIMDEPLETED = 0x400, - DI_DONTANIMATE = 0x800, // do not animate the texture - DI_MIRROR = 0x1000, // flip the texture horizontally, like a mirror - - DI_SCREEN_AUTO = 0, // decide based on given offsets. - DI_SCREEN_MANUAL_ALIGN = 0x4000, // If this is on, the following flags will have an effect - - DI_SCREEN_TOP = DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_VCENTER = 0x8000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_BOTTOM = 0x10000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_VOFFSET = 0x18000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_VMASK = 0x18000 | DI_SCREEN_MANUAL_ALIGN, - - DI_SCREEN_LEFT = DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_HCENTER = 0x20000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_RIGHT = 0x40000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_HOFFSET = 0x60000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_HMASK = 0x60000 | DI_SCREEN_MANUAL_ALIGN, - - DI_SCREEN_LEFT_TOP = DI_SCREEN_TOP|DI_SCREEN_LEFT, - DI_SCREEN_RIGHT_TOP = DI_SCREEN_TOP|DI_SCREEN_RIGHT, - DI_SCREEN_LEFT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_LEFT, - DI_SCREEN_RIGHT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_RIGHT, - DI_SCREEN_CENTER = DI_SCREEN_VCENTER|DI_SCREEN_HCENTER, - DI_SCREEN_CENTER_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_HCENTER, - DI_SCREEN_OFFSETS = DI_SCREEN_HOFFSET|DI_SCREEN_VOFFSET, - - DI_ITEM_AUTO = 0, // equivalent with bottom center, which is the default alignment. - - DI_ITEM_TOP = 0x80000, - DI_ITEM_VCENTER = 0x100000, - DI_ITEM_BOTTOM = 0, // this is the default vertical alignment - DI_ITEM_VOFFSET = 0x180000, - DI_ITEM_VMASK = 0x180000, - - DI_ITEM_LEFT = 0x200000, - DI_ITEM_HCENTER = 0, // this is the deafault horizontal alignment - DI_ITEM_RIGHT = 0x400000, - DI_ITEM_HOFFSET = 0x600000, - DI_ITEM_HMASK = 0x600000, - - DI_ITEM_LEFT_TOP = DI_ITEM_TOP|DI_ITEM_LEFT, - DI_ITEM_RIGHT_TOP = DI_ITEM_TOP|DI_ITEM_RIGHT, - DI_ITEM_LEFT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_LEFT, - DI_ITEM_RIGHT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_RIGHT, - DI_ITEM_CENTER = DI_ITEM_VCENTER|DI_ITEM_HCENTER, - DI_ITEM_CENTER_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_HCENTER, - DI_ITEM_OFFSETS = DI_ITEM_HOFFSET|DI_ITEM_VOFFSET, - - DI_TEXT_ALIGN_LEFT = 0, - DI_TEXT_ALIGN_RIGHT = 0x800000, - DI_TEXT_ALIGN_CENTER = 0x1000000, - DI_TEXT_ALIGN = 0x1800000, - - DI_ALPHAMAPPED = 0x2000000, - DI_NOSHADOW = 0x4000000, - DI_ALWAYSSHOWCOUNTERS = 0x8000000, - DI_ARTIFLASH = 0x10000000, - DI_FORCEFILL = 0x20000000, - - // These 2 flags are only used by SBARINFO so these duplicate other flags not used by SBARINFO - DI_DRAWINBOX = DI_TEXT_ALIGN_RIGHT, - DI_ALTERNATEONFAIL = DI_TEXT_ALIGN_CENTER, -}; #endif /* __SBAR_H__ */ diff --git a/src/g_statusbar/sbar_mugshot.cpp b/src/g_statusbar/sbar_mugshot.cpp index d494efbe8c5..49312438981 100644 --- a/src/g_statusbar/sbar_mugshot.cpp +++ b/src/g_statusbar/sbar_mugshot.cpp @@ -39,6 +39,7 @@ #include "sbar.h" #include "r_utility.h" #include "actorinlines.h" +#include "texturemanager.h" #define ST_RAMPAGEDELAY (2*TICRATE) #define ST_MUCHPAIN 20 @@ -70,11 +71,11 @@ FMugShotFrame::~FMugShotFrame() // // FMugShotFrame :: GetTexture // -// Assemble a graphic name with the specified prefix and return the FTexture. +// Assemble a graphic name with the specified prefix and return the FGameTexture. // //=========================================================================== -FTexture *FMugShotFrame::GetTexture(const char *default_face, const char *skin_face, int random, int level, +FGameTexture *FMugShotFrame::GetTexture(const char *default_face, const char *skin_face, int random, int level, int direction, bool uses_levels, bool health2, bool healthspecial, bool directional) { int index = !directional ? random % Graphic.Size() : direction; @@ -96,7 +97,7 @@ FTexture *FMugShotFrame::GetTexture(const char *default_face, const char *skin_f } sprite.UnlockBuffer(); } - return TexMan.GetTexture(TexMan.CheckForTexture(sprite, ETextureType::Any, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_AllowSkins)); + return TexMan.GetGameTexture(TexMan.CheckForTexture(sprite.GetChars(), ETextureType::Any, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_AllowSkins)); } //=========================================================================== @@ -354,11 +355,11 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) // The next 12 lines are from the Doom statusbar code. DAngle badguyangle = player->mo->AngleTo(player->attacker); DAngle diffang = deltaangle(player->mo->Angles.Yaw, badguyangle); - if (diffang > 45.) + if (diffang > DAngle::fromDeg(45.)) { // turn face right damage_angle = 2; } - else if (diffang < -45.) + else if (diffang < DAngle::fromDeg(-45.)) { // turn face left damage_angle = 0; } @@ -374,8 +375,8 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) { full_state_name = "pain."; } - full_state_name += player->LastDamageType; - if (SetState(full_state_name, false, true)) + full_state_name += player->LastDamageType.GetChars(); + if (SetState(full_state_name.GetChars(), false, true)) { bDamageFaceActive = (CurrentState != NULL); LastDamageAngle = damage_angle; @@ -401,8 +402,8 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) { full_state_name = "pain."; } - full_state_name += player->LastDamageType; - if (SetState(full_state_name)) + full_state_name += player->LastDamageType.GetChars(); + if (SetState(full_state_name.GetChars())) { bOuchActive = use_ouch; } @@ -443,8 +444,8 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) { full_state_name = "xdeath."; } - full_state_name += player->LastDamageType; - SetState(full_state_name); + full_state_name += player->LastDamageType.GetChars(); + SetState(full_state_name.GetChars()); bNormal = true; //Allow the face to return to alive states when the player respawns. } return 0; @@ -458,7 +459,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) // //=========================================================================== -FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accuracy, StateFlags stateflags) +FGameTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accuracy, StateFlags stateflags) { int angle = UpdateState(player, stateflags); int level = 0; @@ -478,7 +479,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu if (CurrentState != NULL) { int skin = player->userinfo.GetSkin(); - const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? (GetDefaultByType(player->MorphedPlayerClass))->NameVar(NAME_Face).GetChars() : Skins[skin].Face.GetChars()); + const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->mo->alternative != nullptr ? (GetDefaultByType(player->MorphedPlayerClass))->NameVar(NAME_Face).GetChars() : Skins[skin].Face.GetChars()); return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index 104895ed052..6bb27d1798d 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -34,11 +34,12 @@ */ #include "doomtype.h" +#include "basics.h" #include "doomstat.h" #include "v_font.h" #include "v_video.h" #include "sbar.h" -#include "w_wad.h" +#include "filesystem.h" #include "d_player.h" #include "a_keys.h" #include "sbarinfo.h" @@ -49,6 +50,9 @@ #include "vm.h" #include "i_system.h" #include "utf8.h" +#include "texturemanager.h" +#include "v_palette.h" +#include "v_draw.h" #define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) enum @@ -62,7 +66,6 @@ enum EXTERN_CVAR(Int, fraglimit) EXTERN_CVAR(Int, screenblocks) -EXTERN_CVAR(Bool, vid_fps) class DSBarInfo; static double nulclip[] = { 0,0,0,0 }; @@ -240,7 +243,7 @@ class SBarInfoCommandFlowControl : public SBarInfoCommand void Negate() { - swapvalues(commands[0], commands[1]); + std::swap(commands[0], commands[1]); } private: @@ -440,7 +443,7 @@ void SBarInfo::Load() { if(gameinfo.statusbar.IsNotEmpty()) { - int lump = Wads.CheckNumForFullName(gameinfo.statusbar, true); + int lump = fileSystem.CheckNumForFullName(gameinfo.statusbar.GetChars(), true); if(lump != -1) { if (!batchrun) Printf ("ParseSBarInfo: Loading default status bar definition.\n"); @@ -451,12 +454,12 @@ void SBarInfo::Load() } } - if(Wads.CheckNumForName("SBARINFO") != -1) + if(fileSystem.CheckNumForName("SBARINFO") != -1) { if (!batchrun) Printf ("ParseSBarInfo: Loading custom status bar definition.\n"); int lastlump, lump; lastlump = 0; - while((lump = Wads.FindLump("SBARINFO", &lastlump)) != -1) + while((lump = fileSystem.FindLump("SBARINFO", &lastlump)) != -1) { if(SBarInfoScript[SCRIPT_CUSTOM] == NULL) SBarInfoScript[SCRIPT_CUSTOM] = new SBarInfo(lump); @@ -478,7 +481,7 @@ void SBarInfo::ParseSBarInfo(int lump) if(sc.TokenType == TK_Include) { sc.MustGetToken(TK_StringConst); - int lump = Wads.CheckNumForFullName(sc.String, true); + int lump = fileSystem.CheckNumForFullName(sc.String, true); if (lump == -1) sc.ScriptError("Lump '%s' not found", sc.String); ParseSBarInfo(lump); @@ -493,15 +496,15 @@ void SBarInfo::ParseSBarInfo(int lump) sc.MustGetToken(TK_Identifier); if(sc.Compare("Doom")) { - baselump = Wads.CheckNumForFullName("sbarinfo/doom.txt", true); + baselump = fileSystem.CheckNumForFullName("sbarinfo/doom.txt", true); } else if(sc.Compare("Heretic")) { - baselump = Wads.CheckNumForFullName("sbarinfo/heretic.txt", true); + baselump = fileSystem.CheckNumForFullName("sbarinfo/heretic.txt", true); } else if(sc.Compare("Hexen")) { - baselump = Wads.CheckNumForFullName("sbarinfo/hexen.txt", true); + baselump = fileSystem.CheckNumForFullName("sbarinfo/hexen.txt", true); } else if(sc.Compare("Strife")) gameType = GAME_Strife; @@ -516,10 +519,10 @@ void SBarInfo::ParseSBarInfo(int lump) { sc.ScriptError("Standard %s status bar not found.", sc.String); } - else if (Wads.GetLumpFile(baselump) > 0) + else if (fileSystem.GetFileContainer(baselump) > 0) { I_FatalError("File %s is overriding core lump sbarinfo/%s.txt.", - Wads.GetWadFullName(Wads.GetLumpFile(baselump)), sc.String); + fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(baselump)), sc.String); } ParseSBarInfo(baselump); } @@ -720,10 +723,10 @@ void SBarInfo::ParseSBarInfo(int lump) popup.transition = Popup::TRANSITION_FADE; sc.MustGetToken(','); sc.MustGetToken(TK_FloatConst); - popup.speed = 1.0 / (35.0 * sc.Float); + popup.speed = 1.0 / (TICRATE * sc.Float); sc.MustGetToken(','); sc.MustGetToken(TK_FloatConst); - popup.speed2 = 1.0 / (35.0 * sc.Float); + popup.speed2 = 1.0 / (TICRATE * sc.Float); } else sc.ScriptError("Unkown transition type: '%s'", sc.String); @@ -792,7 +795,7 @@ int SBarInfo::newImage(const char *patchname) } for(unsigned int i = 0;i < this->Images.Size();i++) //did we already load it? { - if(stricmp(this->Images[i], patchname) == 0) + if(stricmp(this->Images[i].GetChars(), patchname) == 0) { return i; } @@ -963,11 +966,11 @@ void Popup::close() inline void adjustRelCenter(bool relX, bool relY, const double &x, const double &y, double &outX, double &outY, double ScaleX, double ScaleY) { if(relX) - outX = x + (SCREENWIDTH/(ScaleX*2)); + outX = x + (twod->GetWidth()/(ScaleX*2)); else outX = x; if(relY) - outY = y + (SCREENHEIGHT/(ScaleY*2)); + outY = y + (twod->GetHeight()/(ScaleY*2)); else outY = y; } @@ -993,7 +996,7 @@ class DSBarInfo unsigned int i = 0; for(i = 0;i < script->Images.Size();i++) { - patchnames[i] = script->Images[i]; + patchnames[i] = script->Images[i].GetChars(); } for(i = 0;i < 9;i++) { @@ -1033,7 +1036,7 @@ class DSBarInfo ammocount2 = ammo2 != nullptr ? ammo2->IntVar(NAME_Amount) : 0; //prepare ammo counts - armor = CPlayer->mo->FindInventory(NAME_BasicArmor); + armor = CPlayer->mo->FindInventory(NAME_BasicArmor, true); } void _Draw (EHudState state) @@ -1189,7 +1192,7 @@ class DSBarInfo } //draws an image with the specified flags - void DrawGraphic(FTexture* texture, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, double Alpha, bool fullScreenOffsets, bool translate=false, bool dim=false, int offsetflags=0, bool alphaMap=false, int forceWidth=-1, int forceHeight=-1, const double *clip = nulclip, bool clearDontDraw=false) const + void DrawGraphic(FGameTexture* texture, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, double Alpha, bool fullScreenOffsets, bool translate=false, bool dim=false, int offsetflags=0, bool alphaMap=false, int forceWidth=-1, int forceHeight=-1, const double *clip = nulclip, bool clearDontDraw=false) const { if (texture == NULL) return; @@ -1199,11 +1202,11 @@ class DSBarInfo if((offsetflags & SBarInfoCommand::CENTER) == SBarInfoCommand::CENTER) { - if (forceWidth < 0) dx -= (texture->GetDisplayWidthDouble()/2.0)-texture->GetDisplayLeftOffsetDouble(); - else dx -= forceWidth*(0.5-(texture->GetDisplayLeftOffsetDouble()/texture->GetDisplayWidthDouble())); + if (forceWidth < 0) dx -= (texture->GetDisplayWidth()/2.0)-texture->GetDisplayLeftOffset(); + else dx -= forceWidth*(0.5-(texture->GetDisplayLeftOffset()/texture->GetDisplayWidth())); - if (forceHeight < 0) dy -= (texture->GetDisplayHeightDouble()/2.0)-texture->GetDisplayTopOffsetDouble(); - else dy -= forceHeight*(0.5-(texture->GetDisplayTopOffsetDouble()/texture->GetDisplayHeightDouble())); + if (forceHeight < 0) dy -= (texture->GetDisplayHeight()/2.0)-texture->GetDisplayTopOffset(); + else dy -= forceHeight*(0.5-(texture->GetDisplayTopOffset()/texture->GetDisplayHeight())); } dx += xOffset; @@ -1212,12 +1215,12 @@ class DSBarInfo if(!fullScreenOffsets) { double tmp = 0; - w = forceWidth < 0 ? texture->GetDisplayWidthDouble() : forceWidth; - h = forceHeight < 0 ? texture->GetDisplayHeightDouble() : forceHeight; - double dcx = clip[0] == 0 ? 0 : dx + clip[0] - texture->GetDisplayLeftOffsetDouble(); - double dcy = clip[1] == 0 ? 0 : dy + clip[1] - texture->GetDisplayTopOffsetDouble(); - double dcr = clip[2] == 0 ? INT_MAX : dx + w - clip[2] - texture->GetDisplayLeftOffsetDouble(); - double dcb = clip[3] == 0 ? INT_MAX : dy + h - clip[3] - texture->GetDisplayTopOffsetDouble(); + w = forceWidth < 0 ? texture->GetDisplayWidth() : forceWidth; + h = forceHeight < 0 ? texture->GetDisplayHeight() : forceHeight; + double dcx = clip[0] == 0 ? 0 : dx + clip[0] - texture->GetDisplayLeftOffset(); + double dcy = clip[1] == 0 ? 0 : dy + clip[1] - texture->GetDisplayTopOffset(); + double dcr = clip[2] == 0 ? INT_MAX : dx + w - clip[2] - texture->GetDisplayLeftOffset(); + double dcb = clip[3] == 0 ? INT_MAX : dy + h - clip[3] - texture->GetDisplayTopOffset(); if(clip[0] != 0 || clip[1] != 0) { @@ -1232,19 +1235,19 @@ class DSBarInfo wrapper->StatusbarToRealCoords(dx, dy, w, h); if(clearDontDraw) - screen->Clear(static_cast(MAX(dx, dcx)), static_cast(MAX(dy, dcy)), static_cast(MIN(dcr,w+MAX(dx, dcx))), static_cast(MIN(dcb,MAX(dy, dcy)+h)), GPalette.BlackIndex, 0); + ClearRect(twod, static_cast(max(dx, dcx)), static_cast(max(dy, dcy)), static_cast(min(dcr,w+max(dx, dcx))), static_cast(min(dcb,max(dy, dcy)+h)), GPalette.BlackIndex, 0); else { if(alphaMap) { - screen->DrawTexture(texture, dx, dy, + DrawTexture(twod, texture, dx, dy, DTA_DestWidthF, w, DTA_DestHeightF, h, DTA_ClipLeft, static_cast(dcx), DTA_ClipTop, static_cast(dcy), - DTA_ClipRight, static_cast(MIN(INT_MAX, dcr)), - DTA_ClipBottom, static_cast(MIN(INT_MAX, dcb)), - DTA_TranslationIndex, translate ? GetTranslation() : 0, + DTA_ClipRight, static_cast(min(INT_MAX, dcr)), + DTA_ClipBottom, static_cast(min(INT_MAX, dcb)), + DTA_TranslationIndex, GetTranslationIndex(translate), DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, DTA_Alpha, Alpha, @@ -1254,14 +1257,14 @@ class DSBarInfo } else { - screen->DrawTexture(texture, dx, dy, + DrawTexture(twod, texture, dx, dy, DTA_DestWidthF, w, DTA_DestHeightF, h, DTA_ClipLeft, static_cast(dcx), DTA_ClipTop, static_cast(dcy), - DTA_ClipRight, static_cast(MIN(INT_MAX, dcr)), - DTA_ClipBottom, static_cast(MIN(INT_MAX, dcb)), - DTA_TranslationIndex, translate ? GetTranslation() : 0, + DTA_ClipRight, static_cast(min(INT_MAX, dcr)), + DTA_ClipBottom, static_cast(min(INT_MAX, dcb)), + DTA_TranslationIndex, GetTranslationIndex(translate), DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, DTA_Alpha, Alpha, @@ -1281,10 +1284,8 @@ class DSBarInfo bool xright = *x < 0 && !x.RelCenter(); bool ybot = *y < 0 && !y.RelCenter(); - w = (forceWidth < 0 ? texture->GetDisplayWidthDouble() : forceWidth); - h = (forceHeight < 0 ? texture->GetDisplayHeightDouble() : forceHeight); - if(vid_fps && rx < 0 && ry >= 0) - ry += 10; + w = (forceWidth < 0 ? texture->GetDisplayWidth() : forceWidth); + h = (forceHeight < 0 ? texture->GetDisplayHeight() : forceHeight); rx *= Scale.X; ry *= Scale.Y; @@ -1292,33 +1293,33 @@ class DSBarInfo h *= Scale.Y; if(xright) - rx = SCREENWIDTH + rx; + rx = twod->GetWidth() + rx; if(ybot) - ry = SCREENHEIGHT + ry; + ry = twod->GetHeight() + ry; // Check for clipping if(clip[0] != 0 || clip[1] != 0 || clip[2] != 0 || clip[3] != 0) { - rcx = clip[0] == 0 ? 0 : rx+((clip[0] - texture->GetDisplayLeftOffsetDouble())*Scale.X); - rcy = clip[1] == 0 ? 0 : ry+((clip[1] - texture->GetDisplayTopOffsetDouble())*Scale.Y); - rcr = clip[2] == 0 ? INT_MAX : rx+w-((clip[2] + texture->GetDisplayLeftOffsetDouble())*Scale.X); - rcb = clip[3] == 0 ? INT_MAX : ry+h-((clip[3] + texture->GetDisplayTopOffsetDouble())*Scale.Y); + rcx = clip[0] == 0 ? 0 : rx+((clip[0] - texture->GetDisplayLeftOffset())*Scale.X); + rcy = clip[1] == 0 ? 0 : ry+((clip[1] - texture->GetDisplayTopOffset())*Scale.Y); + rcr = clip[2] == 0 ? INT_MAX : rx+w-((clip[2] + texture->GetDisplayLeftOffset())*Scale.X); + rcb = clip[3] == 0 ? INT_MAX : ry+h-((clip[3] + texture->GetDisplayTopOffset())*Scale.Y); } if(clearDontDraw) - screen->Clear(static_cast(rcx), static_cast(rcy), static_cast(MIN(rcr, rcx+w)), static_cast(MIN(rcb, rcy+h)), GPalette.BlackIndex, 0); + ClearRect(twod, static_cast(rcx), static_cast(rcy), static_cast(min(rcr, rcx+w)), static_cast(min(rcb, rcy+h)), GPalette.BlackIndex, 0); else { if(alphaMap) { - screen->DrawTexture(texture, rx, ry, + DrawTexture(twod, texture, rx, ry, DTA_DestWidthF, w, DTA_DestHeightF, h, DTA_ClipLeft, static_cast(rcx), DTA_ClipTop, static_cast(rcy), DTA_ClipRight, static_cast(rcr), DTA_ClipBottom, static_cast(rcb), - DTA_TranslationIndex, translate ? GetTranslation() : 0, + DTA_TranslationIndex, GetTranslationIndex(translate), DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, DTA_Alpha, Alpha, @@ -1328,14 +1329,14 @@ class DSBarInfo } else { - screen->DrawTexture(texture, rx, ry, + DrawTexture(twod, texture, rx, ry, DTA_DestWidthF, w, DTA_DestHeightF, h, DTA_ClipLeft, static_cast(rcx), DTA_ClipTop, static_cast(rcy), DTA_ClipRight, static_cast(rcr), DTA_ClipBottom, static_cast(rcb), - DTA_TranslationIndex, translate ? GetTranslation() : 0, + DTA_TranslationIndex, GetTranslationIndex(translate), DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, DTA_Alpha, Alpha, @@ -1391,7 +1392,7 @@ class DSBarInfo else width = font->GetCharWidth((unsigned char) script->spacingCharacter); bool redirected = false; - FTexture* c = font->GetChar(ch, fontcolor, &width); + auto c = font->GetChar(ch, fontcolor, &width); if(c == NULL) //missing character. { continue; @@ -1403,8 +1404,8 @@ class DSBarInfo double rx, ry, rw, rh; rx = ax + xOffset; ry = ay + yOffset; - rw = c->GetDisplayWidthDouble(); - rh = c->GetDisplayHeightDouble(); + rw = c->GetDisplayWidth(); + rh = c->GetDisplayHeight(); if(script->spacingCharacter != '\0') { @@ -1428,8 +1429,6 @@ class DSBarInfo } else { - if(vid_fps && ax < 0 && ay >= 0) - ry += 10; bool xright = rx < 0; bool ybot = ry < 0; @@ -1440,41 +1439,46 @@ class DSBarInfo rh *= Scale.Y; if(xright) - rx = SCREENWIDTH + rx; + rx = twod->GetWidth() + rx; if(ybot) - ry = SCREENHEIGHT + ry; + ry = twod->GetHeight() + ry; } if(drawshadow) { double salpha = (Alpha *HR_SHADOW); double srx = rx + (shadowX*Scale.X); double sry = ry + (shadowY*Scale.Y); - screen->DrawChar(font, CR_UNTRANSLATED, srx, sry, ch, + DrawChar(twod, font, CR_UNTRANSLATED, srx, sry, ch, DTA_DestWidthF, rw, DTA_DestHeightF, rh, DTA_Alpha, salpha, DTA_FillColor, 0, TAG_DONE); } - screen->DrawChar(font, fontcolor, rx, ry, ch, + DrawChar(twod, font, fontcolor, rx, ry, ch, DTA_DestWidthF, rw, DTA_DestHeightF, rh, DTA_Alpha, Alpha, TAG_DONE); if (script->spacingCharacter == '\0') - ax += width + spacing - (c->GetDisplayLeftOffsetDouble() + 1); + ax += width + spacing - (c->GetDisplayLeftOffset() + 1); else //width gets changed at the call to GetChar() ax += font->GetCharWidth((unsigned char) script->spacingCharacter) + spacing; } } - uint32_t GetTranslation() const + FTranslationID GetTranslation() const { if(gameinfo.gametype & GAME_Raven) return TRANSLATION(TRANSLATION_PlayersExtra, int(CPlayer - players)); return TRANSLATION(TRANSLATION_Players, int(CPlayer - players)); } + int GetTranslationIndex(bool translate) const + { + return translate? GetTranslation().index() : 0; + } + PClassActor *AmmoType(int no) const { auto w = StatusBar->CPlayer->ReadyWeapon; diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index b00489e069d..749294adc29 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -69,8 +69,8 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { double scale1, scale2; scale1 = scale2 = 1.0f; - double texwidth = (int) (texture->GetDisplayWidthDouble()*spawnScaleX); - double texheight = (int) (texture->GetDisplayHeightDouble()*spawnScaleY); + double texwidth = (int) (texture->GetDisplayWidth()*spawnScaleX); + double texheight = (int) (texture->GetDisplayHeight()*spawnScaleY); if (w != -1 && (wGetDisplayWidthDouble()*spawnScaleX); - h=(int) (texture->GetDisplayHeightDouble()*spawnScaleY); + w=(int) (texture->GetDisplayWidth()*spawnScaleX); + h=(int) (texture->GetDisplayHeight()*spawnScaleY); } statusBar->DrawGraphic(texture, imgx, imgy, block->XOffset(), block->YOffset(), frameAlpha, block->FullScreenOffsets(), translatable, false, offset, false, w, h); @@ -241,7 +241,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl applyscale = false; } if(type == PLAYERICON) - texture = TexMan.ByIndex(statusBar->CPlayer->mo->IntVar(NAME_ScoreIcon), true); + texture = TexMan.GameByIndex(statusBar->CPlayer->mo->IntVar(NAME_ScoreIcon), true); else if(type == AMMO1) { auto ammo = statusBar->ammo1; @@ -270,13 +270,13 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { auto item = statusBar->CPlayer->mo->FindInventory(NAME_Sigil); if (item != NULL) - texture = TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true); + texture = TexMan.GetGameTexture(item->TextureIDVar(NAME_Icon), true); } else if(type == HEXENARMOR_ARMOR || type == HEXENARMOR_SHIELD || type == HEXENARMOR_HELM || type == HEXENARMOR_AMULET) { int armorType = type - HEXENARMOR_ARMOR; - auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor); + auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor, true); if (harmor != NULL) { double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); @@ -284,7 +284,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl if (Slots[armorType] > 0 && SlotsIncrement[armorType] > 0) { //combine the alpha values - alpha *= MIN(1., Slots[armorType] / SlotsIncrement[armorType]); + alpha *= min(1., Slots[armorType] / SlotsIncrement[armorType]); texture = statusBar->Images[image]; } else @@ -292,9 +292,9 @@ class CommandDrawImage : public SBarInfoCommandFlowControl } } else if(type == INVENTORYICON) - texture = TexMan.GetTexture(sprite, true); + texture = TexMan.GetGameTexture(sprite, true); else if(type == SELECTEDINVENTORYICON && statusBar->CPlayer->mo->PointerVar(NAME_InvSel) != NULL) - texture = TexMan.GetTexture(statusBar->CPlayer->mo->PointerVar(NAME_InvSel)->TextureIDVar(NAME_Icon), true); + texture = TexMan.GetGameTexture(statusBar->CPlayer->mo->PointerVar(NAME_InvSel)->TextureIDVar(NAME_Icon), true); else if(image >= 0) texture = statusBar->Images[image]; @@ -316,7 +316,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl spawnScaleY = item->Scale.Y; } - texture = TexMan.GetTexture(icon, true); + texture = TexMan.GetGameTexture(icon, true); } enum ImageType @@ -353,7 +353,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl SBarInfoCoordinate imgy; Offset offset; - FTexture *texture; + FGameTexture *texture; double alpha; }; @@ -596,7 +596,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage } else if(condition == ARMORTYPE) { - auto armor = statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor); + auto armor = statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor, true); if(armor != NULL) { auto n = armor->NameVar(NAME_ArmorType).GetIndex(); @@ -692,7 +692,7 @@ class CommandDrawString : public SBarInfoCommand auto lines = V_BreakLines(font, breakWidth, str.GetChars()); for(unsigned i = 0; i < lines.Size();i++) { - statusBar->DrawString(font, lines[i].Text, x, y+i*(font->GetHeight()+4), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), translation, spacing, shadow, shadowX, shadowY); + statusBar->DrawString(font, lines[i].Text.GetChars(), x, y+i*(font->GetHeight()+4), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), translation, spacing, shadow, shadowX, shadowY); } } else @@ -824,10 +824,7 @@ class CommandDrawString : public SBarInfoCommand { strValue = CONSTANT; sc.MustGetToken(TK_StringConst); - if(sc.String[0] == '$') - str = GStrings[sc.String+1]; - else - str = sc.String; + label = sc.String; } } void Reset() @@ -923,9 +920,11 @@ class CommandDrawString : public SBarInfoCommand break; } case LOGTEXT: - str = GStrings(statusBar->CPlayer->LogText); + str = GStrings.GetString(statusBar->CPlayer->LogText); break; default: + str = GStrings.localize(label.GetChars()); + RealignString(); break; } } @@ -993,6 +992,7 @@ class CommandDrawString : public SBarInfoCommand StringValueType strValue; int valueArgument; FString str; + FString label; StringAlignment alignment; private: @@ -1183,7 +1183,7 @@ class CommandDrawNumber : public CommandDrawString // We have a name, but make sure it exists. If not, send notification so modders // are aware of the situation. - FBaseCVar *CVar = FindCVar(cvarName, nullptr); + FBaseCVar *CVar = FindCVar(cvarName.GetChars(), nullptr); if (CVar != nullptr) { @@ -1413,7 +1413,7 @@ class CommandDrawNumber : public CommandDrawString case SAVEPERCENT: { double add = 0; - auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor); + auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor, true); if(harmor != NULL) { double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); @@ -1484,7 +1484,7 @@ class CommandDrawNumber : public CommandDrawString break; case INTCVAR: { - FBaseCVar *CVar = GetCVar(int(statusBar->CPlayer - players), cvarName); + FBaseCVar *CVar = GetCVar(int(statusBar->CPlayer - players), cvarName.GetChars()); if (CVar != nullptr) { ECVarType cvartype = CVar->GetRealType(); @@ -1618,7 +1618,7 @@ class CommandDrawMugShot : public SBarInfoCommand void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) { - FTexture *face = statusBar->wrapper->mugshot.GetFace(statusBar->CPlayer, defaultFace, accuracy, stateFlags); + FGameTexture *face = statusBar->wrapper->mugshot.GetFace(statusBar->CPlayer, defaultFace.GetChars(), accuracy, stateFlags); if (face != NULL) statusBar->DrawGraphic(face, x, y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } @@ -1972,7 +1972,7 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl private: int FindRatio() { - float aspect = ActiveRatio(screen->GetWidth(), screen->GetHeight()); + float aspect = ActiveRatio(twod->GetWidth(), twod->GetHeight()); static std::pair ratioTypes[] = { @@ -1986,10 +1986,10 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl }; int ratio = ratioTypes[0].second; - float distance = fabs(ratioTypes[0].first - aspect); + float distance = fabsf(ratioTypes[0].first - aspect); for (int i = 1; ratioTypes[i].first != 0.0f; i++) { - float d = fabs(ratioTypes[i].first - aspect); + float d = fabsf(ratioTypes[i].first - aspect); if (d < distance) { ratio = ratioTypes[i].second; @@ -2045,10 +2045,10 @@ class CommandDrawShader : public SBarInfoCommand } GetCoordinates(sc, fullScreenOffsets, x, y); sc.MustGetToken(';'); - shaders[0] = TexMan.FindTexture("BarShaderHF"); - shaders[1] = TexMan.FindTexture("BarShaderHR"); - shaders[2] = TexMan.FindTexture("BarShaderVF"); - shaders[3] = TexMan.FindTexture("BarShaderVR"); + shaders[0] = TexMan.FindGameTexture("BarShaderHF"); + shaders[1] = TexMan.FindGameTexture("BarShaderHR"); + shaders[2] = TexMan.FindGameTexture("BarShaderVF"); + shaders[3] = TexMan.FindGameTexture("BarShaderVR"); } protected: bool vertical; @@ -2059,7 +2059,7 @@ class CommandDrawShader : public SBarInfoCommand SBarInfoCoordinate y; private: - FTexture *shaders[4]; + FGameTexture *shaders[4]; }; //////////////////////////////////////////////////////////////////////////////// @@ -2132,7 +2132,7 @@ class CommandDrawInventoryBar : public SBarInfoCommand statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgARTIBOX], rx, ry, block->XOffset(), block->YOffset(), bgalpha, block->FullScreenOffsets()); if(style != STYLE_Strife) //Strife draws the cursor before the icons - statusBar->DrawGraphic(TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true), rx - (style == STYLE_HexenStrict ? 2 : 0), ry - (style == STYLE_HexenStrict ? 1 : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->IntVar(NAME_Amount) <= 0); + statusBar->DrawGraphic(TexMan.GetGameTexture(item->TextureIDVar(NAME_Icon), true), rx - (style == STYLE_HexenStrict ? 2 : 0), ry - (style == STYLE_HexenStrict ? 1 : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->IntVar(NAME_Amount) <= 0); if(item == statusBar->CPlayer->mo->PointerVar(NAME_InvSel)) { if(style == STYLE_Heretic) @@ -2147,7 +2147,7 @@ class CommandDrawInventoryBar : public SBarInfoCommand statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } if(style == STYLE_Strife) - statusBar->DrawGraphic(TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true), rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->IntVar(NAME_Amount) <= 0); + statusBar->DrawGraphic(TexMan.GetGameTexture(item->TextureIDVar(NAME_Icon), true), rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->IntVar(NAME_Amount) <= 0); if(counters != NULL && (alwaysShowCounter || item->IntVar(NAME_Amount) != 1)) { counters[i]->valueArgument = item->IntVar(NAME_Amount); @@ -2255,7 +2255,7 @@ class CommandDrawInventoryBar : public SBarInfoCommand } int GetCounterSpacing(const DSBarInfo *statusBar) const { - FTexture *box = (style != STYLE_Strife) + FGameTexture *box = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX] : statusBar->Images[statusBar->invBarOffset + imgCURSOR]; if (box == NULL) @@ -2265,13 +2265,14 @@ class CommandDrawInventoryBar : public SBarInfoCommand else { int spacing; + // Intentionally rounded down. if (!vertical) { - spacing = box->GetDisplayWidth(); + spacing = (int)box->GetDisplayWidth(); } else { - spacing = box->GetDisplayHeight(); + spacing = (int)box->GetDisplayHeight(); } return spacing + ((style != STYLE_Strife) ? 1 : -1); } @@ -2368,24 +2369,25 @@ class CommandDrawKeyBar : public SBarInfoCommand } if(i >= keyOffset) //Should we start drawing? { + auto tex = TexMan.GetGameTexture(item->TextureIDVar(NAME_Icon), true); if(!vertical) { - statusBar->DrawGraphic(TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true), x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); - rowWidth = rowIconSize == -1 ? TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true)->GetDisplayHeight()+2 : rowIconSize; + statusBar->DrawGraphic(tex, x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + rowWidth = rowIconSize == -1 ? (int)tex->GetDisplayHeight()+2 : rowIconSize; } else { - statusBar->DrawGraphic(TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true), x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); - rowWidth = rowIconSize == -1 ? TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true)->GetDisplayWidth()+2 : rowIconSize; + statusBar->DrawGraphic(tex, x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + rowWidth = rowIconSize == -1 ? (int)tex->GetDisplayWidth()+2 : rowIconSize; } // If cmd.special is -1 then the slot size is auto detected if(iconSize == -1) { if(!vertical) - slotOffset += (reverse ? -1 : 1) * (TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true)->GetDisplayWidth() + 2); + slotOffset += (reverse ? -1 : 1) * ((int)tex->GetDisplayWidth() + 2); else - slotOffset += (reverse ? -1 : 1) * (TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true)->GetDisplayHeight() + 2); + slotOffset += (reverse ? -1 : 1) * ((int)tex->GetDisplayHeight() + 2); } else slotOffset += (reverse ? -iconSize : iconSize); @@ -2491,8 +2493,8 @@ class CommandDrawBar : public SBarInfoCommand return; //don't draw anything. assert(statusBar->Images[foreground] != NULL); - FTexture *fg = statusBar->Images[foreground]; - FTexture *bg = (background != -1) ? statusBar->Images[background] : NULL; + FGameTexture *fg = statusBar->Images[foreground]; + FGameTexture *bg = (background != -1) ? statusBar->Images[background] : NULL; double value = drawValue; if(border != 0) @@ -2514,7 +2516,7 @@ class CommandDrawBar : public SBarInfoCommand // {cx, cy, cr, cb} double Clip[4] = {0, 0, 0, 0}; - int sizeOfImage = (horizontal ? fg->GetDisplayWidth()-border*2 : fg->GetDisplayHeight()-border*2); + double sizeOfImage = (horizontal ? fg->GetDisplayWidth()-border*2 : fg->GetDisplayHeight()-border*2); Clip[(!horizontal)|((horizontal ? !reverse : reverse)<<1)] = sizeOfImage - sizeOfImage *value; // Draw background if(border != 0) @@ -2773,7 +2775,7 @@ class CommandDrawBar : public SBarInfoCommand case SAVEPERCENT: { double add = 0; - auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor); + auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor, true); if (harmor != NULL) { double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr); @@ -2794,7 +2796,7 @@ class CommandDrawBar : public SBarInfoCommand if(max != 0 && value > 0) { - value = MIN(value / max, 1.); + value = min(value / max, 1.); } else value = 0; @@ -2803,7 +2805,7 @@ class CommandDrawBar : public SBarInfoCommand // [BL] Since we used a percentage (in order to get the most fluid animation) // we need to establish a cut off point so the last pixel won't hang as the animation slows if(pixel == -1 && statusBar->Images[foreground]) - pixel = MAX(1 / 65536., 1./statusBar->Images[foreground]->GetDisplayWidth()); + pixel = std::max(1 / 65536., 1./statusBar->Images[foreground]->GetDisplayWidth()); if(fabs(drawValue - value) < pixel) drawValue = value; @@ -2952,7 +2954,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl bool foundClass = false; for(unsigned int c = 0;c < PlayerClasses.Size();c++) { - if(stricmp(sc.String, PlayerClasses[c].Type->GetDisplayName()) == 0) + if(stricmp(sc.String, PlayerClasses[c].Type->GetDisplayName().GetChars()) == 0) { foundClass = true; classes.Push(PlayerClasses[c].Type); @@ -3108,15 +3110,15 @@ class CommandDrawGem : public SBarInfoCommand void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) { - FTexture *chainImg = statusBar->Images[chain]; - FTexture *gemImg = statusBar->Images[gem]; + FGameTexture *chainImg = statusBar->Images[chain]; + FGameTexture *gemImg = statusBar->Images[gem]; if(chainImg == NULL) return; SBarInfoCoordinate drawY = y; if(wiggle && drawValue != goalValue) // Should only wiggle when the value doesn't equal what is being drawn. drawY += chainWiggle; - int chainWidth = chainImg->GetDisplayWidth(); + double chainWidth = chainImg->GetDisplayWidth(); int offset = (int) (((double) (chainWidth-leftPadding-rightPadding)/100)*drawValue); statusBar->DrawGraphic(chainImg, x+(offset%chainSize), drawY, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); if(gemImg != NULL) @@ -3497,7 +3499,7 @@ class CommandIfCVarInt : public SBarInfoNegatableFlowControl } cvarname = sc.String; - cvar = FindCVar(cvarname, nullptr); + cvar = FindCVar(cvarname.GetChars(), nullptr); if (cvar != nullptr) { @@ -3534,7 +3536,7 @@ class CommandIfCVarInt : public SBarInfoNegatableFlowControl SBarInfoNegatableFlowControl::Tick(block, statusBar, hudChanged); bool result = false; - cvar = GetCVar(int(statusBar->CPlayer - players), cvarname); + cvar = GetCVar(int(statusBar->CPlayer - players), cvarname.GetChars()); if (cvar != nullptr) { diff --git a/src/g_statusbar/shared_hud.cpp b/src/g_statusbar/shared_hud.cpp index 2a3e467f529..f53e93a74f2 100644 --- a/src/g_statusbar/shared_hud.cpp +++ b/src/g_statusbar/shared_hud.cpp @@ -35,7 +35,7 @@ #include "doomdef.h" #include "v_video.h" #include "gi.h" -#include "w_wad.h" +#include "filesystem.h" #include "a_keys.h" #include "sbar.h" #include "sc_man.h" @@ -48,6 +48,7 @@ #include "cmdlib.h" #include "g_levellocals.h" #include "vm.h" +#include "v_draw.h" #include @@ -62,14 +63,18 @@ CVAR (Bool, hud_showitems, false,CVAR_ARCHIVE); // Show item stats on HUD CVAR (Bool, hud_showstats, false, CVAR_ARCHIVE); // for stamina and accuracy. CVAR (Bool, hud_showscore, false, CVAR_ARCHIVE); // for user maintained score CVAR (Bool, hud_showweapons, true, CVAR_ARCHIVE); // Show weapons collected +CVAR (Bool, am_showepisode, false, CVAR_ARCHIVE); // Show current episode name +CVAR (Bool, am_showcluster, false, CVAR_ARCHIVE); // Show current cluster name CVAR (Int , hud_showammo, 2, CVAR_ARCHIVE); // Show ammo collected CVAR (Int , hud_showtime, 0, CVAR_ARCHIVE); // Show time on HUD +CVAR (Int , hud_showtimestat, 0, CVAR_ARCHIVE); // Show time on HUD as statistics widget CVAR (Int , hud_timecolor, CR_GOLD,CVAR_ARCHIVE); // Color of in-game time on HUD CVAR (Int , hud_showlag, 0, CVAR_ARCHIVE); // Show input latency (maketic - gametic difference) CVAR (Int, hud_ammo_order, 0, CVAR_ARCHIVE); // ammo image and text order CVAR (Int, hud_ammo_red, 25, CVAR_ARCHIVE) // ammo percent less than which status is red CVAR (Int, hud_ammo_yellow, 50, CVAR_ARCHIVE) // ammo percent less is yellow more green +CVAR (Bool, hud_swaphealtharmor, false, CVAR_ARCHIVE); // swap health and armor position on HUD CVAR (Int, hud_health_red, 25, CVAR_ARCHIVE) // health amount less than which status is red CVAR (Int, hud_health_yellow, 50, CVAR_ARCHIVE) // health amount less than which status is yellow CVAR (Int, hud_health_green, 100, CVAR_ARCHIVE) // health amount above is blue, below is green @@ -158,20 +163,34 @@ void DBaseStatusBar::CreateAltHUD() // //--------------------------------------------------------------------------- EXTERN_CVAR(Bool, hud_aspectscale) +EXTERN_CVAR(Bool, hud_oldscale) +EXTERN_CVAR(Float, hud_scalefactor) void DBaseStatusBar::DrawAltHUD() { player_t * CPlayer = StatusBar->CPlayer; players[consoleplayer].inventorytics = 0; - int scale = GetUIScale(hud_althudscale); - int hudwidth = SCREENWIDTH / scale; - int hudheight = hud_aspectscale ? int(SCREENHEIGHT / (scale*1.2)) : SCREENHEIGHT / scale; + int hudwidth; + int hudheight; - IFVM(AltHud, Draw) + if (hud_oldscale) + { + int scale = GetUIScale(twod, hud_althudscale); + hudwidth = twod->GetWidth() / scale; + hudheight = twod->GetHeight() / scale; + } + else + { + hudwidth = int(640 / hud_scalefactor); + hudheight = hudwidth * twod->GetHeight() / twod->GetWidth(); + } + if (hud_aspectscale) hudheight = hudheight * 5 / 6; + + + IFVIRTUALPTRNAME(AltHud, "AltHud", Draw) { VMValue params[] = { AltHud, CPlayer, hudwidth, hudheight }; VMCall(func, params, countof(params), nullptr, 0); } } - diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 31e3e451d71..de125725b9e 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -35,13 +35,13 @@ #include -#include "templates.h" + #include "sbar.h" #include "c_cvars.h" #include "c_dispatch.h" #include "c_console.h" #include "v_video.h" -#include "w_wad.h" +#include "filesystem.h" #include "s_sound.h" #include "gi.h" #include "doomstat.h" @@ -49,6 +49,7 @@ #include "d_net.h" #include "d_player.h" #include "serializer.h" +#include "serialize_obj.h" #include "r_utility.h" #include "cmdlib.h" #include "g_levellocals.h" @@ -59,6 +60,10 @@ #include "events.h" #include "g_game.h" #include "utf8.h" +#include "texturemanager.h" +#include "v_palette.h" +#include "v_draw.h" +#include "m_fixed.h" #include "../version.h" @@ -66,7 +71,6 @@ #define XHAIRPICKUPSIZE (2+XHAIRSHRINKSIZE) #define POWERUPICONSIZE 32 -IMPLEMENT_CLASS(DHUDFont, true, false); IMPLEMENT_CLASS(DBaseStatusBar, false, true) IMPLEMENT_POINTERS_START(DBaseStatusBar) @@ -81,26 +85,24 @@ EXTERN_CVAR (Bool, am_showsecrets) EXTERN_CVAR (Bool, am_showitems) EXTERN_CVAR (Bool, am_showtime) EXTERN_CVAR (Bool, am_showtotaltime) -EXTERN_CVAR (Bool, noisedebug) -EXTERN_CVAR (Int, con_scaletext) -EXTERN_CVAR(Bool, vid_fps) EXTERN_CVAR(Bool, inter_subtitles) +EXTERN_CVAR(Bool, ui_screenborder_classic_scaling) + CVAR(Int, hud_scale, 0, CVAR_ARCHIVE); CVAR(Bool, log_vgafont, false, CVAR_ARCHIVE) +CVAR(Bool, hud_oldscale, true, CVAR_ARCHIVE) DBaseStatusBar *StatusBar; extern int setblocks; -FTexture *CrosshairImage; -static int CrosshairNum; - CVAR (Int, paletteflash, 0, CVAR_ARCHIVE) CVAR (Flag, pf_hexenweaps, paletteflash, PF_HEXENWEAPONS) CVAR (Flag, pf_poison, paletteflash, PF_POISON) CVAR (Flag, pf_ice, paletteflash, PF_ICE) CVAR (Flag, pf_hazard, paletteflash, PF_HAZARD) + // Stretch status bar to full screen width? CUSTOM_CVAR (Int, st_scale, 0, CVAR_ARCHIVE) { @@ -115,22 +117,13 @@ CUSTOM_CVAR (Int, st_scale, 0, CVAR_ARCHIVE) setsizeneeded = true; } } -CUSTOM_CVAR(Bool, hud_aspectscale, false, CVAR_ARCHIVE) -{ - if (StatusBar) - { - StatusBar->SetScale(); - setsizeneeded = true; - } -} + +EXTERN_CVAR(Float, hud_scalefactor) +EXTERN_CVAR(Bool, hud_aspectscale) CVAR (Bool, crosshairon, true, CVAR_ARCHIVE); CVAR (Int, crosshair, 0, CVAR_ARCHIVE) CVAR (Bool, crosshairforce, false, CVAR_ARCHIVE) -CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE); -CVAR (Int, crosshairhealth, 1, CVAR_ARCHIVE); -CVAR (Float, crosshairscale, 1.0, CVAR_ARCHIVE); -CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE); CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE) { if (self < 0 || self > 2) self = 2; @@ -138,6 +131,87 @@ CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE) CVAR (Bool, idmypos, false, 0); +//========================================================================== +// +// V_DrawFrame +// +// Draw a frame around the specified area using the view border +// frame graphics. The border is drawn outside the area, not in it. +// +//========================================================================== + +void V_DrawFrame(F2DDrawer* drawer, int left, int top, int width, int height, bool scalemode) +{ + FGameTexture* p; + const gameborder_t* border = &gameinfo.Border; + // Sanity check for incomplete gameinfo + if (border == NULL) + return; + int offset = border->offset; + int right = left + width; + int bottom = top + height; + + float sw = drawer->GetClassicFlatScalarWidth(); + float sh = drawer->GetClassicFlatScalarHeight(); + + if (!scalemode) + { + // Draw top and bottom sides. + p = TexMan.GetGameTextureByName(border->t.GetChars()); + drawer->AddFlatFill(left, top - (int)p->GetDisplayHeight(), right, top, p, true); + p = TexMan.GetGameTextureByName(border->b.GetChars()); + drawer->AddFlatFill(left, bottom, right, bottom + (int)p->GetDisplayHeight(), p, true); + + // Draw left and right sides. + p = TexMan.GetGameTextureByName(border->l.GetChars()); + drawer->AddFlatFill(left - (int)p->GetDisplayWidth(), top, left, bottom, p, true); + p = TexMan.GetGameTextureByName(border->r.GetChars()); + drawer->AddFlatFill(right, top, right + (int)p->GetDisplayWidth(), bottom, p, true); + + // Draw beveled corners. + DrawTexture(drawer, TexMan.GetGameTextureByName(border->tl.GetChars()), left - offset, top - offset, TAG_DONE); + DrawTexture(drawer, TexMan.GetGameTextureByName(border->tr.GetChars()), left + width, top - offset, TAG_DONE); + DrawTexture(drawer, TexMan.GetGameTextureByName(border->bl.GetChars()), left - offset, top + height, TAG_DONE); + DrawTexture(drawer, TexMan.GetGameTextureByName(border->br.GetChars()), left + width, top + height, TAG_DONE); + } + else + { + // Draw top and bottom sides. + p = TexMan.GetGameTextureByName(border->t.GetChars()); + drawer->AddFlatFill(left, top - (int)(p->GetDisplayHeight() / sh), right, top, p, -2); + p = TexMan.GetGameTextureByName(border->b.GetChars()); + drawer->AddFlatFill(left, bottom, right, bottom + (int)(p->GetDisplayHeight() / sh), p, -2); + + // Draw left and right sides. + p = TexMan.GetGameTextureByName(border->l.GetChars()); + drawer->AddFlatFill(left - (int)(p->GetDisplayWidth() / sw), top, left, bottom, p, -2); + p = TexMan.GetGameTextureByName(border->r.GetChars()); + drawer->AddFlatFill(right, top, right + (int)(p->GetDisplayWidth() / sw), bottom, p, -2); + + // Draw beveled corners. + p = TexMan.GetGameTextureByName(border->tl.GetChars()); + drawer->AddFlatFill(left - (int)(p->GetDisplayWidth() / sw), top - (int)(p->GetDisplayHeight() / sh), left, top, p, -2); + p = TexMan.GetGameTextureByName(border->tr.GetChars()); + drawer->AddFlatFill(right, top - (int)(p->GetDisplayHeight() / sh), right + (int)(p->GetDisplayWidth() / sw), top, p, -2); + p = TexMan.GetGameTextureByName(border->bl.GetChars()); + drawer->AddFlatFill(left - (int)(p->GetDisplayWidth() / sw), bottom, left, bottom + (int)(p->GetDisplayHeight() / sh), p, -2); + p = TexMan.GetGameTextureByName(border->br.GetChars()); + drawer->AddFlatFill(right, bottom, right + (int)(p->GetDisplayWidth() / sw), bottom + (int)(p->GetDisplayHeight() / sh), p, -2); + } +} + +DEFINE_ACTION_FUNCTION(_Screen, DrawFrame) +{ + PARAM_PROLOGUE; + PARAM_INT(x); + PARAM_INT(y); + PARAM_INT(w); + PARAM_INT(h); + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + V_DrawFrame(twod, x, y, w, h, false); + return 0; +} + //--------------------------------------------------------------------------- // // Load crosshair definitions @@ -147,7 +221,6 @@ CVAR (Bool, idmypos, false, 0); void ST_LoadCrosshair(bool alwaysload) { int num = 0; - char name[16], size; if (!crosshairforce && players[consoleplayer].camera != NULL && @@ -160,38 +233,14 @@ void ST_LoadCrosshair(bool alwaysload) { num = crosshair; } - if (!alwaysload && CrosshairNum == num && CrosshairImage != NULL) - { // No change. - return; - } - - if (num == 0) - { - CrosshairNum = 0; - CrosshairImage = NULL; - return; - } if (num < 0) { - num = -num; - } - size = (SCREENWIDTH < 640) ? 'S' : 'B'; - - mysnprintf (name, countof(name), "XHAIR%c%d", size, num); - FTextureID texid = TexMan.CheckForTexture(name, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly); - if (!texid.isValid()) - { - mysnprintf (name, countof(name), "XHAIR%c1", size); - texid = TexMan.CheckForTexture(name, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly); - if (!texid.isValid()) - { - texid = TexMan.CheckForTexture("XHAIRS1", ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly); - } + num = 0; } - CrosshairNum = num; - CrosshairImage = TexMan.GetTexture(texid); + ST_LoadCrosshair(num, alwaysload); } + //--------------------------------------------------------------------------- // // ST_Clear @@ -205,8 +254,7 @@ void ST_Clear() StatusBar->Destroy(); StatusBar = NULL; } - CrosshairImage = NULL; - CrosshairNum = 0; + ST_UnloadCrosshair(); } //--------------------------------------------------------------------------- @@ -258,6 +306,7 @@ void ST_CreateStatusBar(bool bTitleLevel) StatusBar->Destroy(); StatusBar = NULL; } + GC::AddMarkerFunc([]() { GC::Mark(StatusBar); }); bool shouldWarn = true; @@ -270,8 +319,8 @@ void ST_CreateStatusBar(bool bTitleLevel) // The old rule of 'what came last wins' goes here, as well. // If the most recent SBARINFO definition comes before a status bar class definition it will be picked, // if the class is defined later, this will be picked. If both come from the same file, the class definition will win. - int sbarinfolump = Wads.CheckNumForName("SBARINFO"); - int sbarinfofile = Wads.GetLumpFile(sbarinfolump); + int sbarinfolump = fileSystem.CheckNumForName("SBARINFO"); + int sbarinfofile = fileSystem.GetFileContainer(sbarinfolump); if (gameinfo.statusbarclassfile >= gameinfo.statusbarfile && gameinfo.statusbarclassfile >= sbarinfofile) { CreateGameInfoStatusBar(shouldWarn); @@ -350,89 +399,6 @@ DBaseStatusBar::DBaseStatusBar () CreateAltHUD(); } -static void ValidateResolution(int &hres, int &vres) -{ - if (hres == 0) - { - static const int HORIZONTAL_RESOLUTION_DEFAULT = 320; - hres = HORIZONTAL_RESOLUTION_DEFAULT; - } - - if (vres == 0) - { - static const int VERTICAL_RESOLUTION_DEFAULT = 200; - vres = VERTICAL_RESOLUTION_DEFAULT; - } -} - -void DBaseStatusBar::SetSize(int reltop, int hres, int vres, int hhres, int hvres) -{ - ValidateResolution(hres, vres); - - BaseRelTop = reltop; - BaseSBarHorizontalResolution = hres; - BaseSBarVerticalResolution = vres; - BaseHUDHorizontalResolution = hhres < 0? hres : hhres; - BaseHUDVerticalResolution = hvres < 0? vres : hvres; - SetDrawSize(reltop, hres, vres); -} - -static void ST_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany) -{ - float ratio; - int cwidth; - int cheight; - int cx1, cy1, cx2, cy2; - - ratio = ActiveRatio(realwidth, realheight); - if (AspectTallerThanWide(ratio)) - { - cwidth = realwidth; - cheight = realheight * AspectMultiplier(ratio) / 48; - } - else - { - cwidth = realwidth * AspectMultiplier(ratio) / 48; - cheight = realheight; - } - // Use whichever pair of cwidth/cheight or width/height that produces less difference - // between CleanXfac and CleanYfac. - cx1 = MAX(cwidth / designwidth, 1); - cy1 = MAX(cheight / designheight, 1); - cx2 = MAX(realwidth / designwidth, 1); - cy2 = MAX(realheight / designheight, 1); - if (abs(cx1 - cy1) <= abs(cx2 - cy2) || MAX(cx1, cx2) >= 4) - { // e.g. 640x360 looks better with this. - *cleanx = cx1; - *cleany = cy1; - } - else - { // e.g. 720x480 looks better with this. - *cleanx = cx2; - *cleany = cy2; - } - - if (*cleanx < *cleany) - *cleany = *cleanx; - else - *cleanx = *cleany; -} - -void DBaseStatusBar::SetDrawSize(int reltop, int hres, int vres) -{ - ValidateResolution(hres, vres); - - RelTop = reltop; - HorizontalResolution = hres; - VerticalResolution = vres; - int x, y; - ST_CalcCleanFacs(hres, vres, SCREENWIDTH, SCREENHEIGHT, &x, &y); - defaultScale = { (double)x, (double)y }; - - SetScale(); // recalculate positioning info. -} - - //--------------------------------------------------------------------------- // // PROP Destroy @@ -465,10 +431,16 @@ void DBaseStatusBar::OnDestroy () void DBaseStatusBar::SetScale () { + if (!hud_oldscale) + { + Super::SetScale(); + return; + } + ValidateResolution(HorizontalResolution, VerticalResolution); - int w = SCREENWIDTH; - int h = SCREENHEIGHT; + int w = twod->GetWidth(); + int h = twod->GetHeight(); if (st_scale < 0 || ForcedScale) { // This is the classic fullscreen scale with aspect ratio compensation. @@ -498,7 +470,7 @@ void DBaseStatusBar::SetScale () // Since status bars and HUDs can be designed for non 320x200 screens this needs to be factored in here. // The global scaling factors are for resources at 320x200, so if the actual ones are higher resolution // the resulting scaling factor needs to be reduced accordingly. - int realscale = clamp((320 * GetUIScale(st_scale)) / HorizontalResolution, 1, w / HorizontalResolution); + int realscale = clamp((320 * GetUIScale(twod, st_scale)) / HorizontalResolution, 1, w / HorizontalResolution); double realscaley = realscale * (hud_aspectscale ? 1.2 : 1.); @@ -526,12 +498,17 @@ void DBaseStatusBar::SetScale () DVector2 DBaseStatusBar::GetHUDScale() const { + if (!hud_oldscale) + { + return Super::GetHUDScale(); + } + int scale; if (hud_scale < 0 || ForcedScale) // a negative value is the equivalent to the old boolean hud_scale. This can yield different values for x and y for higher resolutions. { return defaultScale; } - scale = GetUIScale(hud_scale); + scale = GetUIScale(twod, hud_scale); int hres = HorizontalResolution; int vres = VerticalResolution; @@ -540,38 +517,10 @@ DVector2 DBaseStatusBar::GetHUDScale() const // Since status bars and HUDs can be designed for non 320x200 screens this needs to be factored in here. // The global scaling factors are for resources at 320x200, so if the actual ones are higher resolution // the resulting scaling factor needs to be reduced accordingly. - int realscale = MAX(1, (320 * scale) / hres); + int realscale = max(1, (320 * scale) / hres); return{ double(realscale), double(realscale * (hud_aspectscale ? 1.2 : 1.)) }; } -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -void DBaseStatusBar::BeginStatusBar(int resW, int resH, int relTop, bool forceScaled) -{ - SetDrawSize(relTop < 0? BaseRelTop : relTop, resW < 0? BaseSBarHorizontalResolution : resW, resH < 0? BaseSBarVerticalResolution : resH); - ForcedScale = forceScaled; - fullscreenOffsets = false; -} - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -void DBaseStatusBar::BeginHUD(int resW, int resH, double Alpha, bool forcescaled) -{ - SetDrawSize(RelTop, resW < 0? BaseHUDHorizontalResolution : resW, resH < 0? BaseHUDVerticalResolution : resH); - this->Alpha = Alpha; - ForcedScale = forcescaled; - CompleteBorder = false; - fullscreenOffsets = true; -} - //============================================================================ // // automap HUD common drawer @@ -585,11 +534,12 @@ void FormatMapName(FLevelLocals *self, int cr, FString *result); void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight) { - auto scale = GetUIScale(hud_scale); + auto scalev = GetHUDScale(); + int vwidth = int(twod->GetWidth() / scalev.X); + int vheight = int(twod->GetHeight() / scalev.Y); + auto font = generic_ui ? NewSmallFont : SmallFont; auto font2 = font; - auto vwidth = screen->GetWidth() / scale; - auto vheight = screen->GetHeight() / scale; auto fheight = font->GetHeight(); FString textbuffer; int sec; @@ -600,15 +550,14 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight) if (!generic_ui) { // If the original font does not have accents this will strip them - but a fallback to the VGA font is not desirable here for such cases. - if (!font->CanPrint(GStrings("AM_MONSTERS")) || !font->CanPrint(GStrings("AM_SECRETS")) || !font->CanPrint(GStrings("AM_ITEMS"))) font2 = OriginalSmallFont; + if (!font->CanPrint(GStrings.GetString("AM_MONSTERS")) || !font->CanPrint(GStrings.GetString("AM_SECRETS")) || !font->CanPrint(GStrings.GetString("AM_ITEMS"))) font2 = OriginalSmallFont; } if (am_showtime) { - if (vid_fps) y += (NewConsoleFont->GetHeight() * active_con_scale() + 5) / scale; sec = Tics2Seconds(primaryLevel->time); textbuffer.Format("%02d:%02d:%02d", sec / 3600, (sec % 3600) / 60, sec % 60); - screen->DrawText(font, crdefault, vwidth - zerowidth * 8 - textdist, y, textbuffer, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, + DrawText(twod, font, crdefault, vwidth - zerowidth * 8 - textdist, y, textbuffer.GetChars(), DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, DTA_Monospace, EMonospacing::CellCenter, DTA_Spacing, zerowidth, DTA_KeepRatio, true, TAG_END); y += fheight; } @@ -617,7 +566,7 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight) { sec = Tics2Seconds(primaryLevel->totaltime); textbuffer.Format("%02d:%02d:%02d", sec / 3600, (sec % 3600) / 60, sec % 60); - screen->DrawText(font, crdefault, vwidth - zerowidth * 8 - textdist, y, textbuffer, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, + DrawText(twod, font, crdefault, vwidth - zerowidth * 8 - textdist, y, textbuffer.GetChars(), DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, DTA_Monospace, EMonospacing::CellCenter, DTA_Spacing, zerowidth, DTA_KeepRatio, true, TAG_END); } @@ -626,23 +575,23 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight) y = 0; if (am_showmonsters) { - textbuffer.Format("%s\34%c %d/%d", GStrings("AM_MONSTERS"), crdefault + 65, primaryLevel->killed_monsters, primaryLevel->total_monsters); - screen->DrawText(font2, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); + textbuffer.Format("%s\34%c %d/%d", GStrings.GetString("AM_MONSTERS"), crdefault + 65, primaryLevel->killed_monsters, primaryLevel->total_monsters); + DrawText(twod, font2, highlight, textdist, y, textbuffer.GetChars(), DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); y += fheight; } if (am_showsecrets) { - textbuffer.Format("%s\34%c %d/%d", GStrings("AM_SECRETS"), crdefault + 65, primaryLevel->found_secrets, primaryLevel->total_secrets); - screen->DrawText(font2, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); + textbuffer.Format("%s\34%c %d/%d", GStrings.GetString("AM_SECRETS"), crdefault + 65, primaryLevel->found_secrets, primaryLevel->total_secrets); + DrawText(twod, font2, highlight, textdist, y, textbuffer.GetChars(), DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); y += fheight; } // Draw item count if (am_showitems) { - textbuffer.Format("%s\34%c %d/%d", GStrings("AM_ITEMS"), crdefault + 65, primaryLevel->found_items, primaryLevel->total_items); - screen->DrawText(font2, highlight, textdist, y, textbuffer, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); + textbuffer.Format("%s\34%c %d/%d", GStrings.GetString("AM_ITEMS"), crdefault + 65, primaryLevel->found_items, primaryLevel->total_items); + DrawText(twod, font2, highlight, textdist, y, textbuffer.GetChars(), DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); y += fheight; } @@ -664,10 +613,10 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight) double x = 0, yy = 0, w = HorizontalResolution, h = 0; StatusbarToRealCoords(x, yy, w, h); - IFVIRTUAL(DBaseStatusBar, GetProtrusion) + IFVIRTUAL(DStatusBarCore, GetProtrusion) { int prot = 0; - VMValue params[] = { this, double(finalwidth * scale / w) }; + VMValue params[] = { this, double(finalwidth * scalev.X / w) }; VMReturn ret(&prot); VMCall(func, params, 2, &ret, 1); h = prot; @@ -676,13 +625,13 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight) StatusbarToRealCoords(x, yy, w, h); // Get the y coordinate for the first line of the map name text. - y = Scale(GetTopOfStatusbar() - int(h), vheight, screen->GetHeight()) - fheight * numlines; + y = Scale(GetTopOfStatusbar() - int(h), vheight, twod->GetHeight()) - fheight * numlines; // Draw the texts centered above the status bar. for (unsigned i = 0; i < numlines; i++) { int x = (vwidth - font->StringWidth(lines[i].Text)) / 2; - screen->DrawText(font, highlight, x, y, lines[i].Text, DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); + DrawText(twod, font, highlight, x, y, lines[i].Text.GetChars(), DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); y += fheight; } } @@ -931,10 +880,10 @@ static FTextureID GetBorderTexture(FLevelLocals *Level) { if (Level != nullptr && Level->info != nullptr && Level->info->BorderTexture.Len() != 0) { - auto picnum = TexMan.CheckForTexture (Level->info->BorderTexture, ETextureType::Flat); + auto picnum = TexMan.CheckForTexture (Level->info->BorderTexture.GetChars(), ETextureType::Flat); if (picnum.isValid()) return picnum; } - return TexMan.CheckForTexture (gameinfo.BorderFlat, ETextureType::Flat); + return TexMan.CheckForTexture (gameinfo.BorderFlat.GetChars(), ETextureType::Flat); } //========================================================================== @@ -949,18 +898,18 @@ void DBaseStatusBar::RefreshViewBorder () { if (setblocks < 10) { - int Width = screen->GetWidth(); + int Width = twod->GetWidth(); if (viewwidth == Width) { return; } auto tex = GetBorderTexture(primaryLevel); - screen->DrawBorder (tex, 0, 0, Width, viewwindowy); - screen->DrawBorder (tex, 0, viewwindowy, viewwindowx, viewheight + viewwindowy); - screen->DrawBorder (tex, viewwindowx + viewwidth, viewwindowy, Width, viewheight + viewwindowy); - screen->DrawBorder (tex, 0, viewwindowy + viewheight, Width, StatusBar->GetTopOfStatusbar()); + DrawBorder(twod, tex, 0, 0, Width, viewwindowy); + DrawBorder(twod, tex, 0, viewwindowy, viewwindowx, viewheight + viewwindowy); + DrawBorder(twod, tex, viewwindowx + viewwidth, viewwindowy, Width, viewheight + viewwindowy); + DrawBorder(twod, tex, 0, viewwindowy + viewheight, Width, StatusBar->GetTopOfStatusbar()); - screen->DrawFrame (viewwindowx, viewwindowy, viewwidth, viewheight); + V_DrawFrame(twod, viewwindowx, viewwindowy, viewwidth, viewheight, ui_screenborder_classic_scaling); } } @@ -974,48 +923,60 @@ void DBaseStatusBar::RefreshBackground () const { int x, x2, y; - float ratio = ActiveRatio (SCREENWIDTH, SCREENHEIGHT); + float ratio = ActiveRatio (twod->GetWidth(), twod->GetHeight()); x = ST_X; y = SBarTop; - if (x == 0 && y == SCREENHEIGHT) return; + if (x == 0 && y == twod->GetHeight()) return; auto tex = GetBorderTexture(primaryLevel); + float sh = twod->GetClassicFlatScalarHeight(); + if(!CompleteBorder) { - if(y < SCREENHEIGHT) + if(y < twod->GetHeight()) { - screen->DrawBorder (tex, x+1, y, SCREENWIDTH, y+1); - screen->DrawBorder (tex, x+1, SCREENHEIGHT-1, SCREENWIDTH, SCREENHEIGHT); + DrawBorder(twod, tex, x+1, y, twod->GetWidth(), y+1); + DrawBorder(twod, tex, x+1, twod->GetHeight()-1, twod->GetWidth(), twod->GetHeight()); } } else { - x = SCREENWIDTH; + x = twod->GetWidth(); } if (x > 0) { if(!CompleteBorder) { - x2 = SCREENWIDTH - ST_X; + x2 = twod->GetWidth() - ST_X; } else { - x2 = SCREENWIDTH; + x2 = twod->GetWidth(); } - screen->DrawBorder (tex, 0, y, x+1, SCREENHEIGHT); - screen->DrawBorder (tex, x2-1, y, SCREENWIDTH, SCREENHEIGHT); + DrawBorder(twod, tex, 0, y, x+1, twod->GetHeight()); + DrawBorder(twod, tex, x2-1, y, twod->GetWidth(), twod->GetHeight()); if (setblocks >= 10) { - FTexture *p = TexMan.GetTextureByName(gameinfo.Border.b); + FGameTexture *p = TexMan.GetGameTextureByName(gameinfo.Border.b.GetChars()); if (p != NULL) { - screen->FlatFill(0, y, x, y + p->GetDisplayHeight(), p, true); - screen->FlatFill(x2, y, SCREENWIDTH, y + p->GetDisplayHeight(), p, true); + if (!ui_screenborder_classic_scaling) + { + int h = int(0.5 + p->GetDisplayHeight()); + twod->AddFlatFill(0, y, x, y + h, p, true); + twod->AddFlatFill(x2, y, twod->GetWidth(), y + h, p, true); + } + else + { + int h = (int)((0.5f + p->GetDisplayHeight()) / sh); + twod->AddFlatFill(0, y, x, y + h, p, -2); + twod->AddFlatFill(x2, y, twod->GetWidth(), y + h, p, -2); + } } } } @@ -1029,10 +990,6 @@ void DBaseStatusBar::RefreshBackground () const void DBaseStatusBar::DrawCrosshair () { - uint32_t color; - double size; - int w, h; - if (!crosshairon) { return; @@ -1047,84 +1004,13 @@ void DBaseStatusBar::DrawCrosshair () ST_LoadCrosshair(); // Don't draw the crosshair if there is none - if (CrosshairImage == NULL || gamestate == GS_TITLELEVEL || r_viewpoint.camera->health <= 0) + if (gamestate == GS_TITLELEVEL || r_viewpoint.camera->health <= 0) { return; } + int health = Scale(CPlayer->health, 100, CPlayer->mo->GetDefault()->health); - if (crosshairscale > 0.0f) - { - size = SCREENHEIGHT * crosshairscale / 200.; - } - else - { - size = 1.; - } - - if (crosshairgrow) - { - size *= CrosshairSize; - } - w = int(CrosshairImage->GetDisplayWidth() * size); - h = int(CrosshairImage->GetDisplayHeight() * size); - - if (crosshairhealth == 1) { - // "Standard" crosshair health (green-red) - int health = Scale(CPlayer->health, 100, CPlayer->mo->GetDefault()->health); - - if (health >= 85) - { - color = 0x00ff00; - } - else - { - int red, green; - health -= 25; - if (health < 0) - { - health = 0; - } - if (health < 30) - { - red = 255; - green = health * 255 / 30; - } - else - { - red = (60 - health) * 255 / 30; - green = 255; - } - color = (red<<16) | (green<<8); - } - } - else if (crosshairhealth == 2) - { - // "Enhanced" crosshair health (blue-green-yellow-red) - int health = clamp(Scale(CPlayer->health, 100, CPlayer->mo->GetDefault()->health), 0, 200); - float rr, gg, bb; - - float saturation = health < 150 ? 1.f : 1.f - (health - 150) / 100.f; - - HSVtoRGB(&rr, &gg, &bb, health * 1.2f, saturation, 1); - int red = int(rr * 255); - int green = int(gg * 255); - int blue = int(bb * 255); - - color = (red<<16) | (green<<8) | blue; - } - else - { - color = crosshaircolor; - } - - screen->DrawTexture (CrosshairImage, - viewwidth / 2 + viewwindowx, - viewheight / 2 + viewwindowy, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_AlphaChannel, true, - DTA_FillColor, color & 0xFFFFFF, - TAG_DONE); + ST_DrawCrosshair(health, viewwidth / 2 + viewwindowx, viewheight / 2 + viewwindowy, CrosshairSize); } //--------------------------------------------------------------------------- @@ -1217,7 +1103,7 @@ void DBaseStatusBar::CallDraw(EHudState state, double ticFrac) VMCall(func, params, countof(params), nullptr, 0); } else Draw(state, ticFrac); - screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. + twod->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. BeginStatusBar(BaseSBarHorizontalResolution, BaseSBarVerticalResolution, BaseRelTop, false); } @@ -1229,13 +1115,13 @@ void DBaseStatusBar::DrawLog () if (text.IsNotEmpty()) { // This uses the same scaling as regular HUD messages - auto scale = active_con_scaletext(generic_ui || log_vgafont); - hudwidth = SCREENWIDTH / scale; - hudheight = SCREENHEIGHT / scale; + auto scale = active_con_scaletext(twod, generic_ui || log_vgafont); + hudwidth = twod->GetWidth() / scale; + hudheight = twod->GetHeight() / scale; FFont *font = (generic_ui || log_vgafont)? NewSmallFont : SmallFont; int linelen = hudwidth<640? Scale(hudwidth,9,10)-40 : 560; - auto lines = V_BreakLines (font, linelen, text[0] == '$'? GStrings(text.GetChars()+1) : text.GetChars()); + auto lines = V_BreakLines (font, linelen, text[0] == '$'? GStrings.GetString(text.GetChars()+1) : text.GetChars()); int height = 20; for (unsigned i = 0; i < lines.Size(); i++) height += font->GetHeight (); @@ -1255,13 +1141,13 @@ void DBaseStatusBar::DrawLog () if (y<0) y=0; w=600; } - screen->Dim(0, 0.5f, Scale(x, SCREENWIDTH, hudwidth), Scale(y, SCREENHEIGHT, hudheight), - Scale(w, SCREENWIDTH, hudwidth), Scale(height, SCREENHEIGHT, hudheight)); + Dim(twod, 0, 0.5f, Scale(x, twod->GetWidth(), hudwidth), Scale(y, twod->GetHeight(), hudheight), + Scale(w, twod->GetWidth(), hudwidth), Scale(height, twod->GetHeight(), hudheight)); x+=20; y+=10; for (const FBrokenLines &line : lines) { - screen->DrawText (font, CPlayer->SubtitleCounter? CR_CYAN : CR_UNTRANSLATED, x, y, line.Text, + DrawText(twod, font, CPlayer->SubtitleCounter? CR_CYAN : CR_UNTRANSLATED, x, y, line.Text.GetChars(), DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, TAG_DONE); y += font->GetHeight (); @@ -1301,7 +1187,7 @@ void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone, b void DBaseStatusBar::DrawBottomStuff (EHudState state) { primaryLevel->localEventManager->RenderUnderlay(state); - DrawMessages (HUDMSGLayer_UnderHUD, (state == HUD_StatusBar) ? GetTopOfStatusbar() : SCREENHEIGHT); + DrawMessages (HUDMSGLayer_UnderHUD, (state == HUD_StatusBar) ? GetTopOfStatusbar() : twod->GetHeight()); } //--------------------------------------------------------------------------- @@ -1314,7 +1200,7 @@ void DBaseStatusBar::DrawTopStuff (EHudState state) { if (demoplayback && demover != DEMOGAMEVERSION) { - screen->DrawText (SmallFont, CR_TAN, 0, GetTopOfStatusbar() - 40 * CleanYfac, + DrawText(twod, SmallFont, CR_TAN, 0, GetTopOfStatusbar() - 40 * CleanYfac, "Demo was recorded with a different version\n" "of " GAMENAME ". Expect it to go out of sync.", DTA_CleanNoMove, true, TAG_DONE); @@ -1334,94 +1220,76 @@ void DBaseStatusBar::DrawTopStuff (EHudState state) if (automapactive && !viewactive) { - DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? GetTopOfStatusbar() : SCREENHEIGHT); + DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? GetTopOfStatusbar() : twod->GetHeight()); } - DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? GetTopOfStatusbar() : SCREENHEIGHT); + DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? GetTopOfStatusbar() : twod->GetHeight()); primaryLevel->localEventManager->RenderOverlay(state); DrawConsistancy (); DrawWaiting (); if ((ShowLog && MustDrawLog(state)) || (inter_subtitles && CPlayer->SubtitleCounter > 0)) DrawLog (); - - if (noisedebug) - { - S_NoiseDebug (); - } } void DBaseStatusBar::DrawConsistancy () const { - static bool firsttime = true; - int i; - char conbuff[64], *buff_p; - if (!netgame) return; - buff_p = NULL; - for (i = 0; i < MAXPLAYERS; i++) + bool desync = false; + FString text = "Out of sync with:"; + for (int i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && players[i].inconsistant) { - if (buff_p == NULL) - { - strcpy (conbuff, "Out of sync with:"); - buff_p = conbuff + 17; - } - *buff_p++ = ' '; - *buff_p++ = '1' + i; - *buff_p = 0; + desync = true; + text.AppendFormat(" %s (%d)", players[i].userinfo.GetName(10u), i + 1); } } - if (buff_p != NULL) + if (desync) { - if (firsttime) + auto lines = V_BreakLines(SmallFont, twod->GetWidth() / CleanXfac - 40, text.GetChars()); + const int height = SmallFont->GetHeight() * CleanYfac; + double y = 0.0; + for (auto& line : lines) { - firsttime = false; - if (debugfile) - { - fprintf (debugfile, "%s as of tic %d (%d)\n", conbuff, - players[1-consoleplayer].inconsistant, - players[1-consoleplayer].inconsistant/ticdup); - } + DrawText(twod, SmallFont, CR_GREEN, + (twod->GetWidth() - SmallFont->StringWidth(line.Text) * CleanXfac) * 0.5, + y, line.Text.GetChars(), DTA_CleanNoMove, true, TAG_DONE); + y += height; } - screen->DrawText (SmallFont, CR_GREEN, - (screen->GetWidth() - SmallFont->StringWidth (conbuff)*CleanXfac) / 2, - 0, conbuff, DTA_CleanNoMove, true, TAG_DONE); } } void DBaseStatusBar::DrawWaiting () const { - int i; - char conbuff[64], *buff_p; - if (!netgame) return; - buff_p = NULL; - for (i = 0; i < MAXPLAYERS; i++) + FString text = "Waiting for:"; + bool isWaiting = false; + for (int i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && players[i].waiting) { - if (buff_p == NULL) - { - strcpy (conbuff, "Waiting for:"); - buff_p = conbuff + 12; - } - *buff_p++ = ' '; - *buff_p++ = '1' + i; - *buff_p = 0; + isWaiting = true; + text.AppendFormat(" %s (%d)", players[i].userinfo.GetName(10u), i + 1); } } - if (buff_p != NULL) + if (isWaiting) { - screen->DrawText (SmallFont, CR_ORANGE, - (screen->GetWidth() - SmallFont->StringWidth (conbuff)*CleanXfac) / 2, - SmallFont->GetHeight()*CleanYfac, conbuff, DTA_CleanNoMove, true, TAG_DONE); + auto lines = V_BreakLines(SmallFont, twod->GetWidth() / CleanXfac - 40, text.GetChars()); + const int height = SmallFont->GetHeight() * CleanYfac; + double y = 0.0; + for (auto& line : lines) + { + DrawText(twod, SmallFont, CR_ORANGE, + (twod->GetWidth() - SmallFont->StringWidth(line.Text) * CleanXfac) * 0.5, + y, line.Text.GetChars(), DTA_CleanNoMove, true, TAG_DONE); + y += height; + } } } @@ -1499,434 +1367,13 @@ AActor *DBaseStatusBar::ValidateInvFirst (int numVisible) const return nullptr; } -uint32_t DBaseStatusBar::GetTranslation() const +FTranslationID DBaseStatusBar::GetTranslation() const { if (gameinfo.gametype & GAME_Raven) return TRANSLATION(TRANSLATION_PlayersExtra, int(CPlayer - players)); return TRANSLATION(TRANSLATION_Players, int(CPlayer - players)); } -//============================================================================ -// -// draw stuff -// -//============================================================================ - -void DBaseStatusBar::StatusbarToRealCoords(double &x, double &y, double &w, double &h) const -{ - if (SBarScale.X == -1 || ForcedScale) - { - int hres = HorizontalResolution; - int vres = VerticalResolution; - ValidateResolution(hres, vres); - - screen->VirtualToRealCoords(x, y, w, h, hres, vres, true, true); - } - else - { - x = ST_X + x * SBarScale.X; - y = ST_Y + y * SBarScale.Y; - w *= SBarScale.X; - h *= SBarScale.Y; - } -} - -//============================================================================ -// -// draw stuff -// -//============================================================================ - -void DBaseStatusBar::DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY) -{ - if (!texture.isValid()) - return; - - FTexture *tex = TexMan.GetTexture(texture, !(flags & DI_DONTANIMATE)); - - double texwidth = tex->GetDisplayWidthDouble() * scaleX; - double texheight = tex->GetDisplayHeightDouble() * scaleY; - - if (boxwidth > 0 || boxheight > 0) - { - if (!(flags & DI_FORCEFILL)) - { - double scale1 = 1., scale2 = 1.; - - if (boxwidth > 0 && (boxwidth < texwidth || (flags & DI_FORCESCALE))) - { - scale1 = boxwidth / texwidth; - } - if (boxheight != -1 && (boxheight < texheight || (flags & DI_FORCESCALE))) - { - scale2 = boxheight / texheight; - } - - if (flags & DI_FORCESCALE) - { - if (boxwidth <= 0 || (boxheight > 0 && scale2 < scale1)) - scale1 = scale2; - } - else scale1 = MIN(scale1, scale2); - - boxwidth = texwidth * scale1; - boxheight = texheight * scale1; - } - } - else - { - boxwidth = texwidth; - boxheight = texheight; - } - - // resolve auto-alignment before making any adjustments to the position values. - if (!(flags & DI_SCREEN_MANUAL_ALIGN)) - { - if (x < 0) flags |= DI_SCREEN_RIGHT; - else flags |= DI_SCREEN_LEFT; - if (y < 0) flags |= DI_SCREEN_BOTTOM; - else flags |= DI_SCREEN_TOP; - } - - Alpha *= this->Alpha; - if (Alpha <= 0) return; - x += drawOffset.X; - y += drawOffset.Y; - - switch (flags & DI_ITEM_HMASK) - { - case DI_ITEM_HCENTER: x -= boxwidth / 2; break; - case DI_ITEM_RIGHT: x -= boxwidth; break; - case DI_ITEM_HOFFSET: x -= tex->GetDisplayLeftOffsetDouble() * boxwidth / texwidth; break; - } - - switch (flags & DI_ITEM_VMASK) - { - case DI_ITEM_VCENTER: y -= boxheight / 2; break; - case DI_ITEM_BOTTOM: y -= boxheight; break; - case DI_ITEM_VOFFSET: y -= tex->GetDisplayTopOffsetDouble() * boxheight / texheight; break; - } - - if (!fullscreenOffsets) - { - StatusbarToRealCoords(x, y, boxwidth, boxheight); - } - else - { - double orgx, orgy; - - switch (flags & DI_SCREEN_HMASK) - { - default: orgx = 0; break; - case DI_SCREEN_HCENTER: orgx = screen->GetWidth() / 2; break; - case DI_SCREEN_RIGHT: orgx = screen->GetWidth(); break; - } - - switch (flags & DI_SCREEN_VMASK) - { - default: orgy = 0; break; - case DI_SCREEN_VCENTER: orgy = screen->GetHeight() / 2; break; - case DI_SCREEN_BOTTOM: orgy = screen->GetHeight(); break; - } - - // move stuff in the top right corner a bit down if the fps counter is on. - if ((flags & (DI_SCREEN_HMASK|DI_SCREEN_VMASK)) == DI_SCREEN_RIGHT_TOP && vid_fps) y += 10; - - DVector2 Scale = GetHUDScale(); - - x *= Scale.X; - y *= Scale.Y; - boxwidth *= Scale.X; - boxheight *= Scale.Y; - x += orgx; - y += orgy; - } - screen->DrawTexture(tex, x, y, - DTA_TopOffset, 0, - DTA_LeftOffset, 0, - DTA_DestWidthF, boxwidth, - DTA_DestHeightF, boxheight, - DTA_TranslationIndex, (flags & DI_TRANSLATABLE) ? GetTranslation() : 0, - DTA_ColorOverlay, (flags & DI_DIM) ? MAKEARGB(170, 0, 0, 0) : 0, - DTA_Alpha, Alpha, - DTA_AlphaChannel, !!(flags & DI_ALPHAMAPPED), - DTA_FillColor, (flags & DI_ALPHAMAPPED) ? 0 : -1, - DTA_FlipX, !!(flags & DI_MIRROR), - TAG_DONE); -} - - -//============================================================================ -// -// draw a string -// -//============================================================================ - -void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, double y, int flags, double Alpha, int translation, int spacing, EMonospacing monospacing, int shadowX, int shadowY, double scaleX, double scaleY) -{ - bool monospaced = monospacing != EMonospacing::Off; - double dx = 0; - - switch (flags & DI_TEXT_ALIGN) - { - default: - break; - case DI_TEXT_ALIGN_RIGHT: - dx = monospaced - ? static_cast ((spacing)*cstring.CharacterCount()) //monospaced, so just multiply the character size - : static_cast (font->StringWidth(cstring) + (spacing * cstring.CharacterCount())); - break; - case DI_TEXT_ALIGN_CENTER: - dx = monospaced - ? static_cast ((spacing)*cstring.CharacterCount()) / 2 //monospaced, so just multiply the character size - : static_cast (font->StringWidth(cstring) + (spacing * cstring.CharacterCount())) / 2; - break; - } - - // Take text scale into account - x -= dx * scaleX; - - const uint8_t* str = (const uint8_t*)cstring.GetChars(); - const EColorRange boldTranslation = EColorRange(translation ? translation - 1 : NumTextColors - 1); - int fontcolor = translation; - double orgx = 0, orgy = 0; - DVector2 Scale; - - if (fullscreenOffsets) - { - Scale = GetHUDScale(); - shadowX *= (int)Scale.X; - shadowY *= (int)Scale.Y; - - switch (flags & DI_SCREEN_HMASK) - { - default: orgx = 0; break; - case DI_SCREEN_HCENTER: orgx = screen->GetWidth() / 2; break; - case DI_SCREEN_RIGHT: orgx = screen->GetWidth(); break; - } - - switch (flags & DI_SCREEN_VMASK) - { - default: orgy = 0; break; - case DI_SCREEN_VCENTER: orgy = screen->GetHeight() / 2; break; - case DI_SCREEN_BOTTOM: orgy = screen->GetHeight(); break; - } - - // move stuff in the top right corner a bit down if the fps counter is on. - if ((flags & (DI_SCREEN_HMASK | DI_SCREEN_VMASK)) == DI_SCREEN_RIGHT_TOP && vid_fps) y += 10; - } - else - { - Scale = { 1.,1. }; - } - int ch; - while (ch = GetCharFromString(str), ch != '\0') - { - if (ch == ' ') - { - x += monospaced ? spacing : font->GetSpaceWidth() + spacing; - continue; - } - else if (ch == TEXTCOLOR_ESCAPE) - { - EColorRange newColor = V_ParseFontColor(str, translation, boldTranslation); - if (newColor != CR_UNDEFINED) - fontcolor = newColor; - continue; - } - - int width; - FTexture* c = font->GetChar(ch, fontcolor, &width); - if (c == NULL) //missing character. - { - continue; - } - - if (!monospaced) //If we are monospaced lets use the offset - x += (c->GetDisplayLeftOffsetDouble() + 1); //ignore x offsets since we adapt to character size - - double rx, ry, rw, rh; - rx = x + drawOffset.X; - ry = y + drawOffset.Y; - rw = c->GetDisplayWidthDouble(); - rh = c->GetDisplayHeightDouble(); - - if (monospacing == EMonospacing::CellCenter) - rx += (spacing - rw) / 2; - else if (monospacing == EMonospacing::CellRight) - rx += (spacing - rw); - - if (!fullscreenOffsets) - { - StatusbarToRealCoords(rx, ry, rw, rh); - } - else - { - rx *= Scale.X; - ry *= Scale.Y; - rw *= Scale.X; - rh *= Scale.Y; - - rx += orgx; - ry += orgy; - } - - // Apply text scale - rw *= scaleX; - rh *= scaleY; - - // This is not really such a great way to draw shadows because they can overlap with previously drawn characters. - // This may have to be changed to draw the shadow text up front separately. - if ((shadowX != 0 || shadowY != 0) && !(flags & DI_NOSHADOW)) - { - screen->DrawChar(font, CR_UNTRANSLATED, rx + shadowX, ry + shadowY, ch, - DTA_DestWidthF, rw, - DTA_DestHeightF, rh, - DTA_Alpha, (Alpha * HR_SHADOW), - DTA_FillColor, 0, - TAG_DONE); - } - screen->DrawChar(font, fontcolor, rx, ry, ch, - DTA_DestWidthF, rw, - DTA_DestHeightF, rh, - DTA_Alpha, Alpha, - TAG_DONE); - - dx = monospaced - ? spacing - : width + spacing - (c->GetDisplayLeftOffsetDouble() + 1); - - // Take text scale into account - x += dx * scaleX; - } -} - -void SBar_DrawString(DBaseStatusBar *self, DHUDFont *font, const FString &string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY) -{ - if (font == nullptr) ThrowAbortException(X_READ_NIL, nullptr); - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - - // resolve auto-alignment before making any adjustments to the position values. - if (!(flags & DI_SCREEN_MANUAL_ALIGN)) - { - if (x < 0) flags |= DI_SCREEN_RIGHT; - else flags |= DI_SCREEN_LEFT; - if (y < 0) flags |= DI_SCREEN_BOTTOM; - else flags |= DI_SCREEN_TOP; - } - - if (wrapwidth > 0) - { - auto brk = V_BreakLines(font->mFont, int(wrapwidth * scaleX), string, true); - for (auto &line : brk) - { - self->DrawString(font->mFont, line.Text, x, y, flags, alpha, trans, font->mSpacing, font->mMonospacing, font->mShadowX, font->mShadowY, scaleX, scaleY); - y += (font->mFont->GetHeight() + linespacing) * scaleY; - } - } - else - { - self->DrawString(font->mFont, string, x, y, flags, alpha, trans, font->mSpacing, font->mMonospacing, font->mShadowX, font->mShadowY, scaleX, scaleY); - } -} - - -//============================================================================ -// -// draw stuff -// -//============================================================================ - -void DBaseStatusBar::TransformRect(double &x, double &y, double &w, double &h, int flags) -{ - // resolve auto-alignment before making any adjustments to the position values. - if (!(flags & DI_SCREEN_MANUAL_ALIGN)) - { - if (x < 0) flags |= DI_SCREEN_RIGHT; - else flags |= DI_SCREEN_LEFT; - if (y < 0) flags |= DI_SCREEN_BOTTOM; - else flags |= DI_SCREEN_TOP; - } - - x += drawOffset.X; - y += drawOffset.Y; - - if (!fullscreenOffsets) - { - StatusbarToRealCoords(x, y, w, h); - } - else - { - double orgx, orgy; - - switch (flags & DI_SCREEN_HMASK) - { - default: orgx = 0; break; - case DI_SCREEN_HCENTER: orgx = screen->GetWidth() / 2; break; - case DI_SCREEN_RIGHT: orgx = screen->GetWidth(); break; - } - - switch (flags & DI_SCREEN_VMASK) - { - default: orgy = 0; break; - case DI_SCREEN_VCENTER: orgy = screen->GetHeight() / 2; break; - case DI_SCREEN_BOTTOM: orgy = screen->GetHeight(); break; - } - - // move stuff in the top right corner a bit down if the fps counter is on. - if ((flags & (DI_SCREEN_HMASK | DI_SCREEN_VMASK)) == DI_SCREEN_RIGHT_TOP && vid_fps) y += 10; - - DVector2 Scale = GetHUDScale(); - - x *= Scale.X; - y *= Scale.Y; - w *= Scale.X; - h *= Scale.Y; - x += orgx; - y += orgy; - } -} - - -//============================================================================ -// -// draw stuff -// -//============================================================================ - -void DBaseStatusBar::Fill(PalEntry color, double x, double y, double w, double h, int flags) -{ - double Alpha = color.a * this->Alpha / 255; - if (Alpha <= 0) return; - - TransformRect(x, y, w, h, flags); - - int x1 = int(x); - int y1 = int(y); - int ww = int(x + w - x1); // account for scaling to non-integers. Truncating the values separately would fail for cases like - int hh = int(y + h - y1); // y=3.5, height = 5.5 where adding both values gives a larger integer than adding the two integers. - - screen->Dim(color, float(Alpha), x1, y1, ww, hh); -} - - -//============================================================================ -// -// draw stuff -// -//============================================================================ - -void DBaseStatusBar::SetClipRect(double x, double y, double w, double h, int flags) -{ - TransformRect(x, y, w, h, flags); - int x1 = int(x); - int y1 = int(y); - int ww = int(x + w - x1); // account for scaling to non-integers. Truncating the values separately would fail for cases like - int hh = int(y + h - y1); // y=3.5, height = 5.5 where adding both values gives a larger integer than adding the two integers. - screen->SetClipRect(x1, y1, ww, hh); -} - - //============================================================================ // // CCMD showpop @@ -1961,31 +1408,6 @@ static DObject *InitObject(PClass *type, int paramnum, VM_ARGS) -enum ENumFlags -{ - FNF_WHENNOTZERO = 0x1, - FNF_FILLZEROS = 0x2, -}; - -void FormatNumber(int number, int minsize, int maxsize, int flags, const FString &prefix, FString *result) -{ - static int maxvals[] = { 1, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999 }; - - if (number == 0 && (flags & FNF_WHENNOTZERO)) - { - *result = ""; - return; - } - if (maxsize > 0 && maxsize < 10) - { - number = clamp(number, -maxvals[maxsize - 1], maxvals[maxsize]); - } - FString &fmt = *result; - if (minsize <= 1) fmt.Format("%s%d", prefix.GetChars(), number); - else if (flags & FNF_FILLZEROS) fmt.Format("%s%0*d", prefix.GetChars(), minsize, number); - else fmt.Format("%s%*d", prefix.GetChars(), minsize, number); -} - //--------------------------------------------------------------------------- // // Weapons List diff --git a/src/g_statusbar/shiftstate.h b/src/g_statusbar/shiftstate.h new file mode 100644 index 00000000000..4ac337ff995 --- /dev/null +++ b/src/g_statusbar/shiftstate.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include "d_event.h" + +class ShiftState +{ + bool ShiftStatus = false; + +public: + + bool ShiftPressed() + { + return ShiftStatus; + } + + void AddEvent(const event_t *ev) + { + if ((ev->type == EV_KeyDown || ev->type == EV_KeyUp) && (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)) + { + ShiftStatus = ev->type == EV_KeyDown; + } + } + + void Clear() + { + ShiftStatus = false; + } + + +}; + +inline ShiftState shiftState; diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index a04264dbef9..a0f27899e70 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -47,6 +47,7 @@ #include "doomstat.h" #include "gi.h" #include "d_main.h" +#include "v_video.h" #if !defined _MSC_VER && !defined __APPLE__ #include "i_system.h" // for SHARE_DIR #endif // !_MSC_VER && !__APPLE__ @@ -67,6 +68,17 @@ EXTERN_CVAR (Int, gl_texture_hqresizemult) EXTERN_CVAR (Int, vid_preferbackend) EXTERN_CVAR (Float, vid_scale_custompixelaspect) EXTERN_CVAR (Bool, vid_scale_linear) +EXTERN_CVAR(Float, m_sensitivity_x) +EXTERN_CVAR(Float, m_sensitivity_y) +EXTERN_CVAR(Int, adl_volume_model) +EXTERN_CVAR (Int, gl_texture_hqresize_targets) +EXTERN_CVAR(Int, wipetype) +EXTERN_CVAR(Bool, i_pauseinbackground) +EXTERN_CVAR(Bool, i_soundinbackground) + +#ifdef _WIN32 +EXTERN_CVAR(Int, in_mouse) +#endif FGameConfigFile::FGameConfigFile () { @@ -80,14 +92,14 @@ FGameConfigFile::FGameConfigFile () OkayToWrite = false; // Do not allow saving of the config before DoKeySetup() bModSetup = false; pathname = GetConfigPath (true); - ChangePathName (pathname); + ChangePathName (pathname.GetChars()); LoadConfigFile (); // If zdoom.ini was read from the program directory, switch // to the user directory now. If it was read from the user // directory, this effectively does nothing. pathname = GetConfigPath (false); - ChangePathName (pathname); + ChangePathName (pathname.GetChars()); // Set default IWAD search paths if none present if (!SetSection ("IWADSearch.Directories")) @@ -96,15 +108,16 @@ FGameConfigFile::FGameConfigFile () SetValueForKey ("Path", ".", true); SetValueForKey ("Path", "$DOOMWADDIR", true); #ifdef __APPLE__ - SetValueForKey ("Path", user_docs, true); - SetValueForKey ("Path", user_app_support, true); + SetValueForKey ("Path", user_docs.GetChars(), true); + SetValueForKey ("Path", user_app_support.GetChars(), true); SetValueForKey ("Path", "$PROGDIR", true); - SetValueForKey ("Path", local_app_support, true); + SetValueForKey ("Path", local_app_support.GetChars(), true); #elif !defined(__unix__) SetValueForKey ("Path", "$HOME", true); SetValueForKey ("Path", "$PROGDIR", true); #else SetValueForKey ("Path", "$HOME/" GAME_DIR, true); + SetValueForKey ("Path", "$HOME/.local/share/games/doom", true); // Arch Linux likes them in /usr/share/doom // Debian likes them in /usr/share/games/doom // I assume other distributions don't do anything radically different @@ -120,14 +133,15 @@ FGameConfigFile::FGameConfigFile () { SetSection ("FileSearch.Directories", true); #ifdef __APPLE__ - SetValueForKey ("Path", user_docs, true); - SetValueForKey ("Path", user_app_support, true); + SetValueForKey ("Path", user_docs.GetChars(), true); + SetValueForKey ("Path", user_app_support.GetChars(), true); SetValueForKey ("Path", "$PROGDIR", true); - SetValueForKey ("Path", local_app_support, true); + SetValueForKey ("Path", local_app_support.GetChars(), true); #elif !defined(__unix__) SetValueForKey ("Path", "$PROGDIR", true); #else SetValueForKey ("Path", "$HOME/" GAME_DIR, true); + SetValueForKey ("Path", "$HOME/.local/share/games/doom", true); SetValueForKey ("Path", SHARE_DIR, true); SetValueForKey ("Path", "/usr/local/share/doom", true); SetValueForKey ("Path", "/usr/local/share/games/doom", true); @@ -142,20 +156,22 @@ FGameConfigFile::FGameConfigFile () { SetSection("SoundfontSearch.Directories", true); #ifdef __APPLE__ - SetValueForKey("Path", user_docs + "/soundfonts", true); - SetValueForKey("Path", user_docs + "/fm_banks", true); - SetValueForKey("Path", user_app_support + "/soundfonts", true); - SetValueForKey("Path", user_app_support + "/fm_banks", true); + SetValueForKey("Path", (user_docs + "/soundfonts").GetChars(), true); + SetValueForKey("Path", (user_docs + "/fm_banks").GetChars(), true); + SetValueForKey("Path", (user_app_support + "/soundfonts").GetChars(), true); + SetValueForKey("Path", (user_app_support + "/fm_banks").GetChars(), true); SetValueForKey("Path", "$PROGDIR/soundfonts", true); SetValueForKey("Path", "$PROGDIR/fm_banks", true); - SetValueForKey("Path", local_app_support + "/soundfonts", true); - SetValueForKey("Path", local_app_support + "/fm_banks", true); + SetValueForKey("Path", (local_app_support + "/soundfonts").GetChars(), true); + SetValueForKey("Path", (local_app_support + "/fm_banks").GetChars(), true); #elif !defined(__unix__) SetValueForKey("Path", "$PROGDIR/soundfonts", true); SetValueForKey("Path", "$PROGDIR/fm_banks", true); #else SetValueForKey("Path", "$HOME/" GAME_DIR "/soundfonts", true); SetValueForKey("Path", "$HOME/" GAME_DIR "/fm_banks", true); + SetValueForKey("Path", "$HOME/.local/share/games/doom/soundfonts", true); + SetValueForKey("Path", "$HOME/.local/share/games/doom/fm_banks", true); SetValueForKey("Path", "/usr/local/share/doom/soundfonts", true); SetValueForKey("Path", "/usr/local/share/doom/fm_banks", true); SetValueForKey("Path", "/usr/local/share/games/doom/soundfonts", true); @@ -241,7 +257,7 @@ void FGameConfigFile::DoAutoloadSetup (FIWadManager *iwad_man) { FString section = workname + ".Autoload"; CreateSectionAtStart(section.GetChars()); - long dotpos = workname.LastIndexOf('.'); + auto dotpos = workname.LastIndexOf('.'); if (dotpos < 0) break; workname.Truncate(dotpos); } @@ -294,47 +310,6 @@ void FGameConfigFile::DoGlobalSetup () if (lastver != NULL) { double last = atof (lastver); - if (last < 123.1) - { - FBaseCVar *noblitter = FindCVar ("vid_noblitter", NULL); - if (noblitter != NULL) - { - noblitter->ResetToDefault (); - } - } - if (last < 202) - { - // Make sure the Hexen hotkeys are accessible by default. - if (SetSection ("Hexen.Bindings")) - { - SetValueForKey ("\\", "use ArtiHealth"); - SetValueForKey ("scroll", "+showscores"); - SetValueForKey ("0", "useflechette"); - SetValueForKey ("9", "use ArtiBlastRadius"); - SetValueForKey ("8", "use ArtiTeleport"); - SetValueForKey ("7", "use ArtiTeleportOther"); - SetValueForKey ("6", "use ArtiPork"); - SetValueForKey ("5", "use ArtiInvulnerability2"); - } - } - if (last < 204) - { // The old default for vsync was true, but with an unlimited framerate - // now, false is a better default. - FBaseCVar *vsync = FindCVar ("vid_vsync", NULL); - if (vsync != NULL) - { - vsync->ResetToDefault (); - } - } - /* spc_amp no longer exists - if (last < 206) - { // spc_amp is now a float, not an int. - if (spc_amp > 16) - { - spc_amp = spc_amp / 16.f; - } - } - */ if (last < 207) { // Now that snd_midiprecache works again, you probably don't want it on. FBaseCVar *precache = FindCVar ("snd_midiprecache", NULL); @@ -550,6 +525,7 @@ void FGameConfigFile::DoGlobalSetup () case 1: newvalue.Int = 0; var->SetGenericRep(newvalue, CVAR_Int); + [[fallthrough]]; case 3: case 4: vid_scale_linear = true; @@ -560,6 +536,86 @@ void FGameConfigFile::DoGlobalSetup () } } } + if (last < 220) + { + auto var = FindCVar("Gamma", NULL); + if (var != NULL) + { + UCVarValue v = var->GetGenericRep(CVAR_Float); + vid_gamma = v.Float; + } + var = FindCVar("fullscreen", NULL); + if (var != NULL) + { + UCVarValue v = var->GetGenericRep(CVAR_Bool); + vid_fullscreen = v.Float; + } + } + if (last < 221) + { + // Transfer the messed up mouse scaling config to something sane and consistent. +#ifndef _WIN32 + double xfact = 3, yfact = 2; +#else + double xfact = in_mouse == 1? 1.5 : 4, yfact = 1; +#endif + auto var = FindCVar("m_noprescale", NULL); + if (var != NULL) + { + UCVarValue v = var->GetGenericRep(CVAR_Bool); + if (v.Bool) xfact = yfact = 1; + } + + var = FindCVar("mouse_sensitivity", NULL); + if (var != NULL) + { + UCVarValue v = var->GetGenericRep(CVAR_Float); + xfact *= v.Float; + yfact *= v.Float; + } + m_sensitivity_x = (float)xfact; + m_sensitivity_y = (float)yfact; + + adl_volume_model = 0; + + // if user originally wanted the in-game textures resized, set model skins to resize too + int old_targets = gl_texture_hqresize_targets; + old_targets |= (old_targets & 1) ? 8 : 0; + gl_texture_hqresize_targets = old_targets; + } + if (last < 222) + { + auto var = FindCVar("mod_dumb_mastervolume", NULL); + if (var != NULL) + { + UCVarValue v = var->GetGenericRep(CVAR_Float); + v.Float /= 4.f; + if (v.Float < 1.f) v.Float = 1.f; + } + } + if (last < 223) + { + // ooooh boy did i open a can of worms with this one. + i_pauseinbackground = !(i_soundinbackground); + } + if (last < 224) + { + if (const auto var = FindCVar("m_sensitivity_x", NULL)) + { + UCVarValue v = var->GetGenericRep(CVAR_Float); + v.Float *= 0.5f; + var->SetGenericRep(v, CVAR_Float); + } + } + if (last < 225) + { + if (const auto var = FindCVar("gl_lightmode", NULL)) + { + UCVarValue v = var->GetGenericRep(CVAR_Int); + v.Int = v.Int == 16 ? 2 : v.Int == 8 ? 1 : 0; + var->SetGenericRep(v, CVAR_Int); + } + } } } } @@ -596,6 +652,11 @@ void FGameConfigFile::DoGameSetup (const char *gamename) SetRavenDefaults (gameinfo.gametype == GAME_Hexen); } + if (gameinfo.gametype & GAME_Strife) + { + SetStrifeDefaults (); + } + // The NetServerInfo section will be read and override anything loaded // here when it's determined that a netgame is being played. strncpy (subsection, "LocalServerInfo", sublen); @@ -879,40 +940,50 @@ void FGameConfigFile::SetRavenDefaults (bool isHexen) UCVarValue val; val.Bool = false; - wi_percents.SetGenericRepDefault (val, CVAR_Bool); + wi_percents->SetGenericRepDefault (val, CVAR_Bool); val.Bool = true; - con_centernotify.SetGenericRepDefault (val, CVAR_Bool); - snd_pitched.SetGenericRepDefault (val, CVAR_Bool); + con_centernotify->SetGenericRepDefault (val, CVAR_Bool); + snd_pitched->SetGenericRepDefault (val, CVAR_Bool); val.Int = 9; - msg0color.SetGenericRepDefault (val, CVAR_Int); + msg0color->SetGenericRepDefault (val, CVAR_Int); val.Int = CR_WHITE; - msgmidcolor.SetGenericRepDefault (val, CVAR_Int); + msgmidcolor->SetGenericRepDefault (val, CVAR_Int); val.Int = CR_YELLOW; - msgmidcolor2.SetGenericRepDefault (val, CVAR_Int); + msgmidcolor2->SetGenericRepDefault (val, CVAR_Int); val.Int = 0x543b17; - am_wallcolor.SetGenericRepDefault (val, CVAR_Int); + am_wallcolor->SetGenericRepDefault (val, CVAR_Int); val.Int = 0xd0b085; - am_fdwallcolor.SetGenericRepDefault (val, CVAR_Int); + am_fdwallcolor->SetGenericRepDefault (val, CVAR_Int); val.Int = 0x734323; - am_cdwallcolor.SetGenericRepDefault (val, CVAR_Int); + am_cdwallcolor->SetGenericRepDefault (val, CVAR_Int); + + val.Int = 0; + wipetype->SetGenericRepDefault(val, CVAR_Int); // Fix the Heretic/Hexen automap colors so they are correct. // (They were wrong on older versions.) if (*am_wallcolor == 0x2c1808 && *am_fdwallcolor == 0x887058 && *am_cdwallcolor == 0x4c3820) { - am_wallcolor.ResetToDefault (); - am_fdwallcolor.ResetToDefault (); - am_cdwallcolor.ResetToDefault (); + am_wallcolor->ResetToDefault (); + am_fdwallcolor->ResetToDefault (); + am_cdwallcolor->ResetToDefault (); } if (!isHexen) { val.Int = 0x3f6040; - color.SetGenericRepDefault (val, CVAR_Int); + color->SetGenericRepDefault (val, CVAR_Int); } } +void FGameConfigFile::SetStrifeDefaults () +{ + UCVarValue val; + val.Int = 3; + wipetype->SetGenericRepDefault(val, CVAR_Int); +} + CCMD (whereisini) { FString path = M_GetConfigPath(false); diff --git a/src/gameconfigfile.h b/src/gameconfigfile.h index 9ef46848984..0b898112ebe 100644 --- a/src/gameconfigfile.h +++ b/src/gameconfigfile.h @@ -36,6 +36,7 @@ #include "doomtype.h" #include "configfile.h" +#include "files.h" class FArgs; class FIWadManager; @@ -63,7 +64,8 @@ class FGameConfigFile : public FConfigFile private: void SetRavenDefaults (bool isHexen); - void ReadCVars (uint32_t flags); + void SetStrifeDefaults (); + void ReadCVars (unsigned flags); bool bModSetup; diff --git a/src/gamedata/a_keys.cpp b/src/gamedata/a_keys.cpp index d331d319e87..32f680a4238 100644 --- a/src/gamedata/a_keys.cpp +++ b/src/gamedata/a_keys.cpp @@ -36,8 +36,8 @@ #include "gi.h" #include "gstrings.h" #include "d_player.h" -#include "c_console.h" -#include "w_wad.h" +#include "sbar.h" +#include "filesystem.h" #include "v_font.h" #include "vm.h" @@ -218,7 +218,7 @@ static void PrintMessage (const char *str) { if (str[0]=='$') { - str = GStrings(str+1); + str = GStrings.GetString(str+1); } C_MidPrint (nullptr, str); } @@ -254,8 +254,8 @@ static void ParseLock(FScanner &sc, int ¤tnumber) auto lock = keynum == -1? &sink : &Locks.InsertNew(keynum); - lock->locksound.Push("*keytry"); - lock->locksound.Push("misc/keytry"); + lock->locksound.Push(S_FindSound("*keytry")); + lock->locksound.Push(S_FindSound("misc/keytry")); while (!sc.CheckString("}")) { @@ -298,7 +298,7 @@ static void ParseLock(FScanner &sc, int ¤tnumber) for (;;) { sc.MustGetString(); - lock->locksound.Push(sc.String); + lock->locksound.Push(S_FindSound(sc.String)); if (!sc.GetString()) { break; @@ -422,7 +422,7 @@ void P_InitKeyMessages() lastlump = 0; ClearLocks(); - while ((lump = Wads.FindLump ("LOCKDEFS", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("LOCKDEFS", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString ()) @@ -469,7 +469,7 @@ int P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet) // Just a safety precaution. The messages should have been initialized upon game start. if (!keysdone) P_InitKeyMessages(); - FSoundID failage[2] = { "*keytry", "misc/keytry" }; + FSoundID failage[2] = { S_FindSound("*keytry"), S_FindSound("misc/keytry") }; auto lock = Locks.CheckKey(keynum); if (!lock) @@ -487,7 +487,7 @@ int P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet) { if (lock->check(owner)) return true; if (quiet) return false; - failtext = remote? lock->RemoteMsg : lock->Message; + failtext = remote? lock->RemoteMsg.GetChars() : lock->Message.GetChars(); failsound = &lock->locksound[0]; numfailsounds = lock->locksound.Size(); } @@ -501,10 +501,10 @@ int P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet) // Play the first defined key sound. for (int i = 0; i < numfailsounds; ++i) { - if (failsound[i] != 0) + if (failsound[i] != NO_SOUND) { - int snd = S_FindSkinnedSound(owner, failsound[i]); - if (snd != 0) + auto snd = S_FindSkinnedSound(owner, failsound[i]); + if (snd != NO_SOUND) { S_Sound (owner, CHAN_VOICE, 0, snd, 1, ATTN_NORM); break; @@ -516,6 +516,12 @@ int P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet) return false; } +// [MK] for ZScript, simply returns if a lock is defined or not +int P_IsLockDefined(int keynum) +{ + return !!Locks.CheckKey(keynum); +} + //========================================================================== // // These functions can be used to get color information for diff --git a/src/gamedata/a_keys.h b/src/gamedata/a_keys.h index 15c19c01712..7eee7e3df19 100644 --- a/src/gamedata/a_keys.h +++ b/src/gamedata/a_keys.h @@ -5,6 +5,7 @@ class AActor; class PClassActor; int P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet = false); +int P_IsLockDefined (int lock); void P_InitKeyMessages (); int P_GetMapColorForLock (int lock); int P_GetMapColorForKey (AActor *key); diff --git a/src/gamedata/a_weapons.cpp b/src/gamedata/a_weapons.cpp index fe57612226d..93768fd54b4 100644 --- a/src/gamedata/a_weapons.cpp +++ b/src/gamedata/a_weapons.cpp @@ -208,20 +208,6 @@ void FWeaponSlot::Sort() } } -//=========================================================================== -// -// FWeaponSlots - Copy Constructor -// -//=========================================================================== - -FWeaponSlots::FWeaponSlots(const FWeaponSlots &other) -{ - for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) - { - Slots[i] = other.Slots[i]; - } -} - //=========================================================================== // // FWeaponSlots :: Clear @@ -422,9 +408,9 @@ void FWeaponSlots::LocalSetup(PClassActor *type) { FString sectionclass(WeaponSection); sectionclass << '.' << type->TypeName.GetChars(); - if (RestoreSlots(GameConfig, sectionclass) == 0) + if (RestoreSlots(GameConfig, sectionclass.GetChars()) == 0) { - RestoreSlots(GameConfig, WeaponSection); + RestoreSlots(GameConfig, WeaponSection.GetChars()); } } else @@ -464,15 +450,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) // The slots differ. Send mine. if (playernum == consoleplayer) { - Net_WriteByte(DEM_SETSLOT); + Net_WriteInt8(DEM_SETSLOT); } else { - Net_WriteByte(DEM_SETSLOTPNUM); - Net_WriteByte(playernum); + Net_WriteInt8(DEM_SETSLOTPNUM); + Net_WriteInt8(playernum); } - Net_WriteByte(i); - Net_WriteByte(Slots[i].Size()); + Net_WriteInt8(i); + Net_WriteInt8(Slots[i].Size()); for (j = 0; j < Slots[i].Size(); ++j) { Net_WriteWeapon(Slots[i].GetWeapon(j)); @@ -496,7 +482,7 @@ void FWeaponSlots::SetFromPlayer(PClassActor *type) { if (Slot[i] != NAME_None) { - Slots[i].AddWeaponList(Slot[i], false); + Slots[i].AddWeaponList(Slot[i].GetChars(), false); } } } @@ -518,7 +504,7 @@ int FWeaponSlots::RestoreSlots(FConfigFile *config, const char *section) int slotsread = 0; section_name += ".Weapons"; - if (!config->SetSection(section_name)) + if (!config->SetSection(section_name.GetChars())) { return 0; } @@ -544,6 +530,9 @@ int FWeaponSlots::RestoreSlots(FConfigFile *config, const char *section) // //=========================================================================== +// Strict handling of SetSlot and ClearPlayerClasses in KEYCONF +CVAR(Bool,setslotstrict,true,CVAR_ARCHIVE); + void FWeaponSlots::PrintSettings() { for (int i = 1; i <= NUM_WEAPON_SLOTS; ++i) @@ -589,7 +578,12 @@ CCMD (setslot) } else if (PlayingKeyConf != nullptr) { - PlayingKeyConf->ClearSlot(slot); + // Only clear the slot first if setslotstrict is true + // If not, we'll just add to the slot without clearing it + if(setslotstrict) + { + PlayingKeyConf->ClearSlot(slot); + } for (int i = 2; i < argv.argc(); ++i) { PlayingKeyConf->AddWeapon(slot, argv[i]); @@ -602,9 +596,9 @@ CCMD (setslot) Printf ("Slot %d cleared\n", slot); } - Net_WriteByte(DEM_SETSLOT); - Net_WriteByte(slot); - Net_WriteByte(argv.argc()-2); + Net_WriteInt8(DEM_SETSLOT); + Net_WriteInt8(slot); + Net_WriteInt8(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { Net_WriteWeapon(PClass::FindActor(argv[i])); @@ -653,8 +647,8 @@ CCMD (addslot) } else { - Net_WriteByte(DEM_ADDSLOT); - Net_WriteByte(slot); + Net_WriteInt8(DEM_ADDSLOT); + Net_WriteInt8(slot); Net_WriteWeapon(type); } } @@ -729,8 +723,8 @@ CCMD (addslotdefault) } else { - Net_WriteByte(DEM_ADDSLOTDEFAULT); - Net_WriteByte(slot); + Net_WriteInt8(DEM_ADDSLOTDEFAULT); + Net_WriteInt8(slot); Net_WriteWeapon(type); } } @@ -748,7 +742,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) PlayingKeyConf = slots; for (unsigned int i = 0; i < KeyConfWeapons.Size(); ++i) { - AddCommandString(KeyConfWeapons[i]); + AddCommandString(KeyConfWeapons[i].GetChars()); } PlayingKeyConf = nullptr; } @@ -863,7 +857,7 @@ static int ntoh_cmp(const void *a, const void *b) void P_WriteDemoWeaponsChunk(uint8_t **demo) { - WriteWord(Weapons_ntoh.Size(), demo); + WriteInt16(Weapons_ntoh.Size(), demo); for (unsigned int i = 1; i < Weapons_ntoh.Size(); ++i) { WriteString(Weapons_ntoh[i]->TypeName.GetChars(), demo); @@ -885,7 +879,7 @@ void P_ReadDemoWeaponsChunk(uint8_t **demo) PClassActor *type; const char *s; - count = ReadWord(demo); + count = ReadInt16(demo); Weapons_ntoh.Resize(count); Weapons_hton.Clear(count); @@ -929,12 +923,12 @@ void Net_WriteWeapon(PClassActor *type) assert(index >= 0 && index <= 32767); if (index < 128) { - Net_WriteByte(index); + Net_WriteInt8(index); } else { - Net_WriteByte(0x80 | index); - Net_WriteByte(index >> 7); + Net_WriteInt8(0x80 | index); + Net_WriteInt8(index >> 7); } } @@ -948,10 +942,10 @@ PClassActor *Net_ReadWeapon(uint8_t **stream) { int index; - index = ReadByte(stream); + index = ReadInt8(stream); if (index & 0x80) { - index = (index & 0x7F) | (ReadByte(stream) << 7); + index = (index & 0x7F) | (ReadInt8(stream) << 7); } if ((unsigned)index >= Weapons_ntoh.Size()) { diff --git a/src/gamedata/a_weapons.h b/src/gamedata/a_weapons.h index 82cfd2999d0..3de18cf4b93 100644 --- a/src/gamedata/a_weapons.h +++ b/src/gamedata/a_weapons.h @@ -51,7 +51,8 @@ enum ESlotDef struct FWeaponSlots { FWeaponSlots() { Clear(); } - FWeaponSlots(const FWeaponSlots &other); + FWeaponSlots(const FWeaponSlots &other) = default; + FWeaponSlots& operator=(const FWeaponSlots& other) = default; private: FWeaponSlot Slots[NUM_WEAPON_SLOTS]; @@ -154,9 +155,9 @@ enum WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles) WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI. - //WIF_DEHAMMO = 0x00010000, - WIF_NODEATHDESELECT = 0x00020000, // Don't jump to the Deselect state when the player dies - WIF_NODEATHINPUT = 0x00040000, // The weapon cannot be fired/reloaded/whatever when the player is dead - WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil) + WIF_NODEATHDESELECT = 0x00010000, // Don't jump to the Deselect state when the player dies + WIF_NODEATHINPUT = 0x00020000, // The weapon cannot be fired/reloaded/whatever when the player is dead + WIF_CHEATNOTWEAPON = 0x00040000, // Give cheat considers this not a weapon (used by Sigil) + WIF_NOAUTOSWITCHTO = 0x00080000, // cannot be switched to when autoswitching weapons. }; diff --git a/src/gamedata/d_dehacked.cpp b/src/gamedata/d_dehacked.cpp index 2e309514ca6..77e9d13206e 100644 --- a/src/gamedata/d_dehacked.cpp +++ b/src/gamedata/d_dehacked.cpp @@ -44,28 +44,31 @@ #include #include "doomtype.h" -#include "templates.h" + #include "doomstat.h" #include "info.h" #include "d_dehacked.h" #include "g_level.h" #include "cmdlib.h" #include "gstrings.h" -#include "w_wad.h" +#include "filesystem.h" #include "d_player.h" #include "r_state.h" #include "c_dispatch.h" #include "decallib.h" #include "a_sharedglobal.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "p_effect.h" #include "serializer.h" #include "thingdef.h" #include "v_text.h" -#include "backend/vmbuilder.h" +#include "vmbuilder.h" #include "types.h" #include "m_argv.h" #include "actorptrselect.h" +#include "g_levellocals.h" + +extern TArray TranslationColors; void JitDumpLog(FILE *file, VMScriptFunction *func); @@ -94,6 +97,7 @@ static TArray OrgHeights; // disappear, but that doesn't explain why frame patches specify an exact // state rather than a code pointer.) static TArray CodePConv; +static bool dsdhacked = false; // Sprite names in the order Doom originally had them. struct DEHSprName @@ -101,6 +105,8 @@ struct DEHSprName char c[5]; }; static TArray OrgSprNames; +size_t OrgSprOrgSize; +static TMap stateSprites; struct StateMapper { @@ -119,6 +125,94 @@ static TArray SoundMap; // Names of different actor types, in original Doom 2 order static TArray InfoNames; +static PClassActor* FindInfoName(int index, bool mustexist = false) +{ + if (index < 0) return nullptr; + if (index < (int)InfoNames.Size()) return InfoNames[index]; + + if (dsdhacked) + { + FStringf name("~Dsdhacked~%d", index); + auto cls = PClass::FindActor(name); + if (!mustexist) + { + cls = static_cast(RUNTIME_CLASS(AActor)->CreateDerivedClass(name.GetChars(), (unsigned)sizeof(AActor))); + NewClassType(cls, -1); // This needs a VM type to work as intended. + cls->InitializeDefaults(); + } + if (cls) + { + GetDefaultByType(cls)->flags8 |= MF8_RETARGETAFTERSLAM; // This flag is not a ZDoom default, but it must be a Dehacked default. + return cls; + } + } + return nullptr; +} + +static FSoundID DehFindSound(int index,bool mustexist = false) +{ + if (index < 0) return NO_SOUND; + if (index < (int) SoundMap.Size() && SoundMap[index].isvalid()) return SoundMap[index]; + if (dsdhacked && !mustexist) + { + FStringf name("~dsdhacked/#%d", index); + return soundEngine->FindSoundTentative(name.GetChars()); + } + return NO_SOUND; +} + +static void ReplaceSoundName(int index, const char* newname) +{ + // This must physically replace the sound's lump name in the sound record. + auto snd = DehFindSound(index-1); + if (snd == NO_SOUND) return; + auto sfx = soundEngine->GetWritableSfx(snd); + FStringf dsname("ds%s", newname); + sfx->lumpnum = fileSystem.CheckNumForName(dsname.GetChars(), FileSys::ns_sounds); + sfx->bTentative = false; + sfx->bRandomHeader = false; + sfx->bLoadRAW = false; + sfx->b16bit = false; + sfx->bUsed = false; + sfx->UserData[0] = 0; +} + +void RemapAllSprites() +{ + TMap::Iterator it(stateSprites); + TMap::Pair *pair; + + while (it.NextPair(pair)) + { + int frameNum = 0; // Hmmm... + auto info = pair->Key; + int val = pair->Value; + unsigned int i; + + if (val >= 0 && val < (int)OrgSprNames.Size()) + { + for (i = 0; i < sprites.Size(); i++) + { + if (memcmp (OrgSprNames[val].c, sprites[i].name, 4) == 0) + { + info->sprite = (int)i; + break; + } + } + if (i == sprites.Size ()) + { + Printf ("Frame %d: Sprite %d (%s) is undefined\n", + frameNum, val, OrgSprNames[val].c); + } + } + else + { + Printf ("Frame %d: Sprite %d out of range\n", frameNum, val); + } + } + stateSprites.Clear(); +} + // bit flags for PatchThing (a .bex extension): struct BitName { @@ -141,20 +235,66 @@ static TArray StyleNames; static TArray AmmoNames; static TArray WeaponNames; +struct MBFArgs +{ + int64_t args[8]; + int argsused; +}; +static TMap stateargs; +static FState* FindState(int statenum, bool mustexist = false); + // DeHackEd trickery to support MBF-style parameters // List of states that are hacked to use a codepointer struct MBFParamState { FState *state; int pointer; + int argsused; + int64_t* args; + + PClassActor* GetTypeArg(int i) + { + int num = (int)args[i]; + return FindInfoName(num-1, true); + } + + FState* GetStateArg(int i) + { + int num = (int)args[i]; + return FindState(num); + } + + + int GetIntArg(int i, int def = 0) + { + return argsused & (1 << i)? (int)args[i] : def; + } + + FSoundID GetSoundArg(int i, int def = 0) + { + int num = argsused & (1 << i) ? (int)args[i] : def; + return DehFindSound(num-1); + } + + double GetFloatArg(int i, double def = 0) + { + return argsused & (1 << i) ? FixedToFloat((fixed_t)args[i]) : def; + } + + void ValidateArgCount(int num, const char* function) + { + if (argsused >= (1 << num)) + { + Printf("Too many args for %s\n", function); // got no line number... :( + } + } }; static TArray MBFParamStates; // Data on how to correctly modify the codepointers struct CodePointerAlias { FName name; - char alias[20]; - uint8_t params; + FString alias; }; static TArray MBFCodePointers; @@ -165,6 +305,13 @@ struct AmmoPerAttack VMFunction *ptr; }; +struct DehBits +{ + const char* name; + int value; +}; + + // Default ammo use of the various weapon attacks static AmmoPerAttack AmmoPerAttacks[] = { { NAME_A_Punch, 0}, @@ -277,7 +424,8 @@ DehSpriteMappings[] = #define CHECKKEY(a,b) if (!stricmp (Line1, (a))) (b) = atoi(Line2); -static char *PatchFile, *PatchPt, *PatchName; +static char* PatchFile, * PatchPt; +FString PatchName; static int PatchSize; static char *Line1, *Line2; static int dversion, pversion; @@ -298,26 +446,28 @@ struct Key { ptrdiff_t offset; }; -static int PatchThing (int); -static int PatchSound (int); -static int PatchFrame (int); -static int PatchSprite (int); -static int PatchAmmo (int); -static int PatchWeapon (int); -static int PatchPointer (int); -static int PatchCheats (int); -static int PatchMisc (int); -static int PatchText (int); -static int PatchStrings (int); -static int PatchPars (int); -static int PatchCodePtrs (int); -static int PatchMusic (int); -static int DoInclude (int); -static bool DoDehPatch(); +static int PatchThing (int, int); +static int PatchSound (int, int); +static int PatchFrame (int, int); +static int PatchSprite (int, int); +static int PatchAmmo (int, int); +static int PatchWeapon (int, int); +static int PatchPointer (int, int); +static int PatchCheats (int, int); +static int PatchMisc (int, int); +static int PatchText (int, int); +static int PatchStrings (int, int); +static int PatchPars (int, int); +static int PatchCodePtrs (int, int); +static int PatchMusic (int, int); +static int DoInclude (int, int); +static int PatchSpriteNames(int, int); +static int PatchSoundNames(int, int); +static bool DoDehPatch(int); static const struct { const char *name; - int (*func)(int); + int (*func)(int, int); } Modes[] = { // These appear in .deh and .bex files { "Thing", PatchThing }, @@ -336,16 +486,18 @@ static const struct { { "[PARS]", PatchPars }, { "[CODEPTR]", PatchCodePtrs }, { "[MUSIC]", PatchMusic }, + { "[SPRITES]", PatchSpriteNames }, + { "[SOUNDS]", PatchSoundNames }, { NULL, NULL }, }; -static int HandleMode (const char *mode, int num); +static int HandleMode (const char *mode, int num, int flags); static bool HandleKey (const struct Key *keys, void *structure, const char *key, int value); static bool ReadChars (char **stuff, int size); static char *igets (void); static int GetLine (void); -inline double DEHToDouble(int acsval) +inline double DEHToDouble(int64_t acsval) { return acsval / 65536.; } @@ -357,14 +509,14 @@ static void PushTouchedActor(PClassActor *cls) } -static int HandleMode (const char *mode, int num) +static int HandleMode (const char *mode, int num, int flags) { int i = 0; while (Modes[i].name && stricmp (Modes[i].name, mode)) i++; if (Modes[i].name) - return Modes[i].func (num); + return Modes[i].func (num, flags); // Handle unknown or unimplemented data Printf ("Unknown chunk %s encountered. Skipping.\n", mode); @@ -396,19 +548,19 @@ static int FindSprite (const char *sprname) return f == UnchangedSpriteNames.Size() ? -1 : f; } -static FState *FindState (int statenum) +static FState *FindState (int statenum, bool mustexist) { int stateacc; unsigned i; - if (statenum == 0) + if (statenum <= 0) return NULL; for (i = 0, stateacc = 1; i < StateMap.Size(); i++) { if (stateacc <= statenum && stateacc + StateMap[i].StateSpan > statenum) { - if (StateMap[i].State != NULL) + if (StateMap[i].State != nullptr) { if (StateMap[i].OwnerIsPickup) { @@ -416,11 +568,28 @@ static FState *FindState (int statenum) } return StateMap[i].State + statenum - stateacc; } - else return NULL; + else break; } stateacc += StateMap[i].StateSpan; } - return NULL; + if (dsdhacked) + { + auto p = dehExtStates.CheckKey(statenum); + if (p) return *p; + if (!mustexist) + { + auto state = (FState*)ClassDataAllocator.Alloc(sizeof(FState)); + dehExtStates.Insert(statenum, state); + memset(state, 0, sizeof(*state)); + state->Tics = -1; + state->NextState = state; + state->DehIndex = statenum; + state->UseFlags = SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM; + return state; + } + + } + return nullptr; } int FindStyle (const char *namestr) @@ -622,7 +791,7 @@ static int GetLine (void) // misc1 = vrange (arg +3), misc2 = hrange (arg+4) -static void CreateMushroomFunc(FunctionCallEmitter &emitters, int value1, int value2) +static void CreateMushroomFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) { // A_Mushroom emitters.AddParameterPointerConst(PClass::FindClass("FatShot")); // itemtype emitters.AddParameterIntConst(0); // numspawns @@ -632,28 +801,29 @@ static void CreateMushroomFunc(FunctionCallEmitter &emitters, int value1, int va } // misc1 = type (arg +0), misc2 = Z-pos (arg +2) -static void CreateSpawnFunc(FunctionCallEmitter &emitters, int value1, int value2) +static void CreateSpawnFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) { // A_SpawnItem - if (InfoNames[value1-1] == nullptr) + auto p = FindInfoName(value1 - 1, true); + if (p == nullptr) { I_Error("No class found for dehackednum %d!\n", value1+1); } - emitters.AddParameterPointerConst(InfoNames[value1-1]); // itemtype - emitters.AddParameterFloatConst(value2); // distance - emitters.AddParameterFloatConst(0); // height + emitters.AddParameterPointerConst(p); // itemtype + emitters.AddParameterFloatConst(0); // distance + emitters.AddParameterFloatConst(value2); // height emitters.AddParameterIntConst(0); // useammo emitters.AddParameterIntConst(0); // transfer_translation } // misc1 = angle (in degrees) (arg +0 but factor in current actor angle too) -static void CreateTurnFunc(FunctionCallEmitter &emitters, int value1, int value2) +static void CreateTurnFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) { // A_Turn emitters.AddParameterFloatConst(value1); // angle } // misc1 = angle (in degrees) (arg +0) -static void CreateFaceFunc(FunctionCallEmitter &emitters, int value1, int value2) +static void CreateFaceFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) { // A_SetAngle emitters.AddParameterFloatConst(value1); // angle emitters.AddParameterIntConst(0); // flags @@ -661,19 +831,19 @@ static void CreateFaceFunc(FunctionCallEmitter &emitters, int value1, int value2 } // misc1 = damage, misc 2 = sound -static void CreateScratchFunc(FunctionCallEmitter &emitters, int value1, int value2) +static void CreateScratchFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) { // A_CustomMeleeAttack emitters.AddParameterIntConst(value1); // damage - emitters.AddParameterIntConst(value2 ? (int)SoundMap[value2 - 1] : 0); // hit sound + emitters.AddParameterIntConst(DehFindSound(value2 - 1, true).index()); // hit sound emitters.AddParameterIntConst(0); // miss sound emitters.AddParameterIntConst(NAME_None); // damage type emitters.AddParameterIntConst(true); // bleed } // misc1 = sound, misc2 = attenuation none (true) or normal (false) -static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int value2) +static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) { // A_PlaySound - emitters.AddParameterIntConst(value1 ? (int)SoundMap[value1 - 1] : 0); // soundid + emitters.AddParameterIntConst(DehFindSound(value1 - 1, false).index()); // soundid emitters.AddParameterIntConst(CHAN_BODY); // channel emitters.AddParameterFloatConst(1); // volume emitters.AddParameterIntConst(false); // looping @@ -683,9 +853,9 @@ static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int v } // misc1 = state, misc2 = probability -static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int value2) +static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) { // A_Jump - auto symlabel = StateLabels.AddPointer(FindState(value1)); + auto symlabel = StateLabels.AddPointer(FindState(value1, true)); emitters.AddParameterIntConst(value2); // maxchance emitters.AddParameterIntConst(symlabel); // jumpto @@ -693,7 +863,7 @@ static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int } // misc1 = Boom linedef type, misc2 = sector tag -static void CreateLineEffectFunc(FunctionCallEmitter &emitters, int value1, int value2) +static void CreateLineEffectFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) { // A_LineEffect // This is the second MBF codepointer that couldn't be translated easily. // Calling P_TranslateLineDef() here was a simple matter, as was adding an @@ -704,28 +874,162 @@ static void CreateLineEffectFunc(FunctionCallEmitter &emitters, int value1, int emitters.AddParameterIntConst(value2); // tag } -// No misc, but it's basically A_Explode with an added effect -static void CreateNailBombFunc(FunctionCallEmitter &emitters, int value1, int value2) -{ // A_Explode - // This one does not actually have MBF-style parameters. But since - // we're aliasing it to an extension of A_Explode... - emitters.AddParameterIntConst(-1); // damage - emitters.AddParameterIntConst(-1); // distance - emitters.AddParameterIntConst(1); // flags (1=XF_HURTSOURCE) - emitters.AddParameterIntConst(0); // alert - emitters.AddParameterIntConst(0); // fulldamagedistance - emitters.AddParameterIntConst(30); // nails - emitters.AddParameterIntConst(10); // naildamage - emitters.AddParameterPointerConst(PClass::FindClass(NAME_BulletPuff)); // itemtype - emitters.AddParameterIntConst(NAME_None); // damage type +static void CreateSpawnObjectFunc(FunctionCallEmitter& emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(8, "A_SpawnObject"); + emitters.AddParameterPointerConst(state->GetTypeArg(0)); + emitters.AddParameterFloatConst(state->GetFloatArg(1)); + emitters.AddParameterFloatConst(state->GetFloatArg(2)); + emitters.AddParameterFloatConst(state->GetFloatArg(3)); + emitters.AddParameterFloatConst(state->GetFloatArg(4)); + emitters.AddParameterFloatConst(state->GetFloatArg(5)); + emitters.AddParameterFloatConst(state->GetFloatArg(6)); + emitters.AddParameterFloatConst(state->GetFloatArg(7)); +} + +static void CreateMonsterProjectileFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(5, "A_MonsterProjectile"); + emitters.AddParameterPointerConst(state->GetTypeArg(0)); + emitters.AddParameterFloatConst(state->GetFloatArg(1)); + emitters.AddParameterFloatConst(state->GetFloatArg(2)); + emitters.AddParameterFloatConst(state->GetFloatArg(3)); + emitters.AddParameterFloatConst(state->GetFloatArg(4)); +} + +static void CreateMonsterBulletAttackFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(5, "A_MonsterBulletAttack"); + emitters.AddParameterFloatConst(state->GetFloatArg(0)); + emitters.AddParameterFloatConst(state->GetFloatArg(1)); + emitters.AddParameterIntConst(state->GetIntArg(2, 1)); + emitters.AddParameterIntConst(state->GetIntArg(3, 3)); + emitters.AddParameterIntConst(state->GetIntArg(4, 5)); +} + +static void CreateMonsterMeleeAttackFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(4, "A_MonsterMeleeAttack"); + emitters.AddParameterIntConst(state->GetIntArg(0, 3)); + emitters.AddParameterIntConst(state->GetIntArg(1, 8)); + emitters.AddParameterIntConst(state->GetSoundArg(2, 0).index()); + emitters.AddParameterFloatConst(state->GetFloatArg(3)); + +} + +static void CreateRadiusDamageFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_RadiusDamage"); + emitters.AddParameterIntConst(state->GetIntArg(0, 0)); + emitters.AddParameterIntConst(state->GetIntArg(1, 0)); +} + +static void CreateHealChaseFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_HealChase"); + emitters.AddParameterPointerConst(state->GetStateArg(0)); + emitters.AddParameterIntConst(state->GetSoundArg(1).index()); +} + +static void CreateSeekTracerFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_SeekTracer"); + emitters.AddParameterFloatConst(state->GetFloatArg(0, 0)); + emitters.AddParameterFloatConst(state->GetFloatArg(1, 0)); +} + +static void CreateFindTracerFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_FindTracer"); + emitters.AddParameterFloatConst(state->GetFloatArg(0)); + emitters.AddParameterIntConst(state->GetIntArg(1, 10)); +} + +static void CreateJumpIfHealthBelowFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_JumpIfHealthBelow"); + emitters.AddParameterPointerConst(state->GetStateArg(0)); + emitters.AddParameterIntConst(state->GetIntArg(1)); +} + +static void CreateJumpIfFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_JumpIf.."); + emitters.AddParameterPointerConst(state->GetStateArg(0)); + emitters.AddParameterFloatConst(state->GetFloatArg(1)); +} + +static void CreateJumpIfFlagSetFunc(FunctionCallEmitter& emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_JumpIfFlagsSet"); + emitters.AddParameterPointerConst(state->GetStateArg(0)); + emitters.AddParameterIntConst(state->GetIntArg(1)); + emitters.AddParameterIntConst(state->GetIntArg(2)); +} + +static void CreateFlagSetFunc(FunctionCallEmitter& emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_...Flags"); + emitters.AddParameterIntConst(state->GetIntArg(0)); + emitters.AddParameterIntConst(state->GetIntArg(1)); +} + +static void CreateWeaponProjectileFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(5, "A_WeaponProjectile"); + emitters.AddParameterPointerConst(state->GetTypeArg(0)); + emitters.AddParameterFloatConst(state->GetFloatArg(1)); + emitters.AddParameterFloatConst(state->GetFloatArg(2)); + emitters.AddParameterFloatConst(state->GetFloatArg(3)); + emitters.AddParameterFloatConst(state->GetFloatArg(4)); +} + +static void CreateWeaponBulletAttackFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(5, "A_WeaponBulletAttack"); + emitters.AddParameterFloatConst(state->GetFloatArg(0)); + emitters.AddParameterFloatConst(state->GetFloatArg(1)); + emitters.AddParameterIntConst(state->GetIntArg(2, 1)); + emitters.AddParameterIntConst(state->GetIntArg(3, 5)); + emitters.AddParameterIntConst(state->GetIntArg(4, 3)); +} + +static void CreateWeaponMeleeAttackFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(5, "A_WeaponMeleeAttack"); + emitters.AddParameterIntConst(state->GetIntArg(0, 2)); + emitters.AddParameterIntConst(state->GetIntArg(1, 10)); + emitters.AddParameterFloatConst(state->GetFloatArg(2, 1)); + emitters.AddParameterIntConst(state->GetSoundArg(3).index()); + emitters.AddParameterFloatConst(state->GetFloatArg(4)); +} + +static void CreateWeaponSoundFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_WeaponSound"); + emitters.AddParameterIntConst(state->GetSoundArg(0).index()); + emitters.AddParameterIntConst(state->GetIntArg(1)); +} + +static void CreateWeaponJumpFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(2, "A_WeaponJump"); + emitters.AddParameterPointerConst(state->GetStateArg(0)); + emitters.AddParameterIntConst(state->GetIntArg(1)); +} + +static void CreateConsumeAmmoFunc(FunctionCallEmitter &emitters, int value1, int value2, MBFParamState* state) +{ + state->ValidateArgCount(1, "A_ConsumeAmmo"); + emitters.AddParameterIntConst(state->GetIntArg(0)); + } // This array must be in sync with the Aliases array in DEHSUPP. -static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int) = +static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int, MBFParamState*) = { // Die and Detonate are not in this list because these codepointers have // no dehacked arguments and therefore do not need special handling. - // NailBomb has no argument but is implemented as new parameters for A_Explode. CreateMushroomFunc, CreateSpawnFunc, CreateTurnFunc, @@ -734,25 +1038,43 @@ static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int) = CreatePlaySoundFunc, CreateRandomJumpFunc, CreateLineEffectFunc, - CreateNailBombFunc + CreateSpawnObjectFunc, + CreateMonsterProjectileFunc, + CreateMonsterBulletAttackFunc, + CreateMonsterMeleeAttackFunc, + CreateRadiusDamageFunc, + CreateHealChaseFunc, + CreateSeekTracerFunc, + CreateFindTracerFunc, + CreateJumpIfHealthBelowFunc, + CreateJumpIfFunc, + CreateJumpIfFunc, + CreateJumpIfFunc, + CreateJumpIfFunc, + CreateWeaponProjectileFunc, + CreateWeaponBulletAttackFunc, + CreateWeaponMeleeAttackFunc, + CreateWeaponSoundFunc, + CreateWeaponJumpFunc, + CreateConsumeAmmoFunc, + CreateWeaponJumpFunc, + CreateWeaponJumpFunc, + CreateWeaponJumpFunc, + CreateJumpIfFlagSetFunc, + CreateFlagSetFunc, + CreateFlagSetFunc }; // Creates new functions for the given state so as to convert MBF-args (misc1 and misc2) into real args. -static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &disasmdump) +static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &disasmdump, MBFParamState* pstate) { static const uint8_t regts[] = { REGT_POINTER, REGT_POINTER, REGT_POINTER }; int value1 = state->GetMisc1(); int value2 = state->GetMisc2(); - if (!(value1|value2)) return; bool returnsState = codepointer == 6; - // Fakey fake script position thingamajig. Because NULL cannot be used instead. - // Even if the lump was parsed by an FScanner, there would hardly be a way to - // identify which line is troublesome. - FScriptPosition *pos = new FScriptPosition(FString("DEHACKED"), 0); - // Let's identify the codepointer we're dealing with. PFunction *sym; sym = dyn_cast(PClass::FindActor(NAME_Weapon)->FindSymbol(FName(MBFCodePointers[codepointer].name), true)); @@ -765,6 +1087,12 @@ static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &di } else { + MBFArgs scratchargs{}; + auto args = stateargs.CheckKey(pstate->state); + if (!args) args = &scratchargs; + pstate->args = args->args; + pstate->argsused = args->argsused; + int numargs = sym->GetImplicitArgs(); auto funcsym = CreateAnonymousFunction(RUNTIME_CLASS(AActor)->VMType, returnsState? (PType*)TypeState : TypeVoid, numargs==3? SUF_ACTOR|SUF_WEAPON : SUF_ACTOR); VMFunctionBuilder buildit(numargs); @@ -778,7 +1106,7 @@ static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &di emitters.AddParameterPointer(i, false); } // Emit code for action parameters. - MBFCodePointerFactories[codepointer](emitters, value1, value2); + MBFCodePointerFactories[codepointer](emitters, value1, value2, pstate); auto where = emitters.EmitCall(&buildit); if (!returnsState) buildit.Emit(OP_RET, RET_FINAL, REGT_NIL, 0); else buildit.Emit(OP_RET, RET_FINAL, EncodeRegType(where), where.RegNum); @@ -793,7 +1121,7 @@ static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &di sfunc->NumArgs = numargs; sfunc->ImplicitArgs = numargs; state->SetAction(sfunc); - sfunc->PrintableName.Format("Dehacked.%s.%d.%d", MBFCodePointers[codepointer].name.GetChars(), value1, value2); + sfunc->PrintableName = ClassDataAllocator.Strdup(FStringf("Dehacked.%s.%d.%d", MBFCodePointers[codepointer].name.GetChars(), value1, value2).GetChars()); disasmdump.Write(sfunc, sfunc->PrintableName); @@ -811,7 +1139,49 @@ static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &di } } -static int PatchThing (int thingy) +struct DehFlags2 +{ + const char* name; + void (*setter)(AActor* defaults); +}; + +// not all of these map to real flags so this table needs handler callbacks. +static const struct DehFlags2 deh_mobjflags_mbf21[] = { + {"LOGRAV", [](AActor* defaults) { defaults->Gravity = 1. / 8.; }}, // low gravity + {"SHORTMRANGE", [](AActor* defaults) { defaults->maxtargetrange = 896.; }}, // short missile range + {"DMGIGNORED", [](AActor* defaults) { defaults->flags3 |= MF3_NOTARGET; }}, // other things ignore its attacks + {"NORADIUSDMG", [](AActor* defaults) { defaults->flags3 |= MF3_NORADIUSDMG; }}, // doesn't take splash damage + {"FORCERADIUSDMG", [](AActor* defaults) { defaults->flags4 |= MF4_FORCERADIUSDMG; }}, // causes splash damage even if target immune + {"HIGHERMPROB", [](AActor* defaults) { defaults->MinMissileChance = 160; }}, // higher missile attack probability + {"RANGEHALF", [](AActor* defaults) { defaults->flags4 |= MF4_MISSILEMORE; }}, // use half distance for missile attack probability + {"NOTHRESHOLD", [](AActor* defaults) { defaults->flags4 |= MF4_QUICKTORETALIATE; }}, // no targeting threshold + {"LONGMELEE", [](AActor* defaults) { defaults->meleethreshold = 196; }}, // long melee range + {"BOSS", [](AActor* defaults) { defaults->flags2 |= MF2_BOSS; defaults->flags3 |= MF3_NORADIUSDMG; }}, // full volume see / death sound + splash immunity + {"MAP07BOSS1", [](AActor* defaults) { defaults->flags8 |= MF8_MAP07BOSS1; }}, // Tag 666 "boss" on doom 2 map 7 + {"MAP07BOSS2", [](AActor* defaults) { defaults->flags8 |= MF8_MAP07BOSS2; }}, // Tag 667 "boss" on doom 2 map 7 + {"E1M8BOSS", [](AActor* defaults) { defaults->flags8 |= MF8_E1M8BOSS; }}, // E1M8 boss + {"E2M8BOSS", [](AActor* defaults) { defaults->flags8 |= MF8_E2M8BOSS; }}, // E2M8 boss + {"E3M8BOSS", [](AActor* defaults) { defaults->flags8 |= MF8_E3M8BOSS; }}, // E3M8 boss + {"E4M6BOSS", [](AActor* defaults) { defaults->flags8 |= MF8_E4M6BOSS; }}, // E4M6 boss + {"E4M8BOSS", [](AActor* defaults) { defaults->flags8 |= MF8_E4M8BOSS; }}, // E4M8 boss + {"RIP", [](AActor* defaults) { defaults->flags2 |= MF2_RIP; }}, // projectile rips through targets + {"FULLVOLSOUNDS", [](AActor* defaults) { defaults->flags8 |= MF8_FULLVOLSEE; defaults->flags3 |= MF3_FULLVOLDEATH; } }, // full volume see / death sound +}; + +static void ClearBits2Stuff(AActor* defaults) +{ + defaults->Gravity = 1.; + defaults->maxtargetrange = 0; + defaults->MinMissileChance = 200; + defaults->meleethreshold = 0; + defaults->flags2 &= ~(MF2_BOSS | MF2_RIP); + defaults->flags3 &= ~(MF3_NOTARGET | MF3_NORADIUSDMG | MF3_FULLVOLDEATH); + defaults->flags4 &= ~(MF4_MISSILEMORE | MF4_QUICKTORETALIATE | MF4_FORCERADIUSDMG); + defaults->flags8 &= ~(MF8_E1M8BOSS | MF8_E2M8BOSS | MF8_E3M8BOSS | MF8_E4M8BOSS | MF8_E4M6BOSS | MF8_MAP07BOSS1 | MF8_MAP07BOSS2 | MF8_FULLVOLSEE); +} + + +static int PatchThing (int thingy, int flags) { enum { @@ -843,29 +1213,17 @@ static int PatchThing (int thingy) type = NULL; info = (AActor *)&dummy; ednum = &dummyed; - if (thingy > (int)InfoNames.Size() || thingy <= 0) + auto thingytype = FindInfoName(thingy-1); + if (thingytype == nullptr) { - Printf ("Thing %d out of range.\n", thingy); + Printf ("Thing %d out of range or invalid.\n", thingy); } else { DPrintf (DMSG_SPAMMY, "Thing %d\n", thingy); - if (thingy > 0) - { - type = InfoNames[thingy - 1]; - if (type == NULL) - { - info = (AActor *)&dummy; - ednum = &dummyed; - // An error for the name has already been printed while loading DEHSUPP. - Printf ("Could not find thing %d\n", thingy); - } - else - { - info = GetDefaultByType (type); - ednum = &type->ActorInfo()->DoomEdNum; - } - } + type = thingytype; + info = GetDefaultByType (type); + ednum = &type->ActorInfo()->DoomEdNum; } oldflags = info->flags; @@ -873,16 +1231,21 @@ static int PatchThing (int thingy) while ((result = GetLine ()) == 1) { char *endptr; - unsigned long val = (unsigned long)strtoull (Line2, &endptr, 10); + int64_t val = (int64_t)strtoll (Line2, &endptr, 10); size_t linelen = strlen (Line1); - if (linelen == 10 && stricmp (Line1, "Hit points") == 0) + // Supported value range is all valid representations of signed int and unsigned int. + if (val < INT_MIN || val > UINT_MAX) + { + Printf("Bad numeric constant %s for %s\n", Line2, Line1); + } + else if (linelen == 10 && stricmp (Line1, "Hit points") == 0) { - info->health = val; + info->health = (int)val; } else if (linelen == 13 && stricmp (Line1, "Reaction time") == 0) { - info->reactiontime = val; + info->reactiontime = (int)val; } else if (linelen == 11 && stricmp (Line1, "Pain chance") == 0) { @@ -892,6 +1255,7 @@ static int PatchThing (int thingy) { info->Alpha = DEHToDouble(val); info->RenderStyle = STYLE_Translucent; + info->renderflags &= ~RF_ZDOOMTRANS; hadTranslucency = true; hadStyle = true; } @@ -903,13 +1267,13 @@ static int PatchThing (int thingy) } else if (linelen == 14 && stricmp (Line1, "Missile damage") == 0) { - info->SetDamage(val); + info->SetDamage((int)val); } else if (linelen == 5) { if (stricmp (Line1, "Speed") == 0) { - info->Speed = (signed long)val; // handle fixed point later. + info->Speed = (double)val; // handle fixed point later. } else if (stricmp (Line1, "Width") == 0) { @@ -922,7 +1286,7 @@ static int PatchThing (int thingy) } else if (stricmp (Line1, "Scale") == 0) { - info->Scale.Y = info->Scale.X = clamp(atof (Line2), 1./65536, 256.); + info->Scale.Y = info->Scale.X = clamp((float)atof (Line2), 1.f/65536, 256.f); } else if (stricmp (Line1, "Decal") == 0) { @@ -948,22 +1312,136 @@ static int PatchThing (int thingy) hadStyle = true; } } - else if (linelen > 6) + else if (linelen == 12 && stricmp(Line1, "No Ice Death") == 0) + { + if (val) + { + info->flags4 |= MF4_NOICEDEATH; + } + else + { + info->flags4 &= ~MF4_NOICEDEATH; + } + } + else if (linelen == 16 && stricmp(Line1, "infighting group") == 0) + { + if (val < 0) + { + Printf("Infighting groups must be >= 0 (check your dehacked)\n"); + val = 0; + } + type->ActorInfo()->infighting_group = (int)val; + } + else if (linelen == 16 && stricmp(Line1, "projectile group") == 0) + { + if (val < 0) val = -1; + type->ActorInfo()->projectile_group = (int)val; + } + else if (linelen == 12 && stricmp(Line1, "splash group") == 0) + { + if (val < 0) + { + Printf("Splash groups must be >= 0 (check your dehacked)\n"); + val = 0; + } + type->ActorInfo()->splash_group = (int)val; + } + else if (linelen == 10 && stricmp(Line1, "fast speed") == 0) + { + double fval = val >= 256 ? DEHToDouble(val) : double(val); + info->FloatVar(NAME_FastSpeed) = fval; + } + else if (linelen == 11 && stricmp(Line1, "melee range") == 0) + { + info->meleerange = DEHToDouble(val) - 20; // -20 is needed because DSDA subtracts it in P_CheckMeleeRange, while GZDoom does not. + } + else if (linelen == 12 && stricmp(Line1, "dropped item") == 0) { - if (linelen == 12 && stricmp (Line1, "No Ice Death") == 0) + auto drop = FindInfoName(val - 1); + if (drop) { - if (val) + FDropItem* di = (FDropItem*)ClassDataAllocator.Alloc(sizeof(FDropItem)); + + di->Next = nullptr; + di->Name = drop->TypeName; + di->Probability = 255; + di->Amount = -1; + info->GetInfo()->DropItems = di; + } + else if ((int)val == -1) + { + info->GetInfo()->DropItems = nullptr; + } + } + else if (linelen == 11 && stricmp(Line1, "blood color") == 0) + { + static const unsigned int bloodcolor[] = { + 0, // 0 - Red (normal) + 0xffcccccc, // 1 - Grey + 0xff63af57, // 2 - Green + 0xff6357af, // 3 - Blue + 0xffffd300, // 4 - Yellow + 0xff333333, // 5 - Black + 0xffff30ff, // 6 - Purple + 0xffffffff, // 7 - White + 0xffff8000, // 8 - Orange + }; + + if (val > 8 || val < 0) val = 0; + unsigned color = bloodcolor[val]; + info->BloodColor = color; + info->BloodTranslation = val == 0? NO_TRANSLATION : CreateBloodTranslation(color); + } + else if (linelen == 10 && stricmp(Line1, "MBF21 Bits") == 0) + { + uint32_t value = 0; + bool vchanged = false; + + char* strval; + + for (strval = Line2; (strval = strtok(strval, ",+| \t\f\r")); strval = NULL) + { + if (IsNum(strval)) { - info->flags4 |= MF4_NOICEDEATH; + value |= (uint32_t)strtoll(strval, NULL, 10); + vchanged = true; } else { - info->flags4 &= ~MF4_NOICEDEATH; + unsigned i; + for (i = 0; i < countof(deh_mobjflags_mbf21); i++) + { + if (!stricmp(strval, deh_mobjflags_mbf21[i].name)) + { + vchanged = true; + value |= 1 << i; + break; + } + } + if (i == countof(deh_mobjflags_mbf21)) + { + DPrintf(DMSG_ERROR, "Unknown bit mnemonic %s\n", strval); + } } } - else if (stricmp (Line1 + linelen - 6, " frame") == 0) + if (vchanged) { - FState *state = FindState (val); + ClearBits2Stuff(info); + for (size_t i = 0; i < countof(deh_mobjflags_mbf21); i++) + { + if (value & (1 << i)) + { + deh_mobjflags_mbf21[i].setter(info); + } + } + } + DPrintf(DMSG_SPAMMY, "MBF21 Bits: %d (0x%08x)\n", info->flags.GetValue(), info->flags.GetValue()); + } + else if (linelen > 6) + { + if (stricmp (Line1 + linelen - 6, " frame") == 0) + { + FState *state = FindState ((int)val); if (type != NULL && !patchedStates) { @@ -1001,21 +1479,17 @@ static int PatchThing (int thingy) } else if (stricmp (Line1 + linelen - 6, " sound") == 0) { - FSoundID snd = 0; + FSoundID snd = DehFindSound(val - 1, false); - if (val == 0 || val >= SoundMap.Size()) + if (snd == NO_SOUND) // This won't trigger for dsdhacked patches! { if (endptr == Line2) { // Sound was not a (valid) number, // so treat it as an actual sound name. stripwhite (Line2); - snd = Line2; + snd = S_FindSound(Line2); } } - else - { - snd = SoundMap[val-1]; - } if (!strnicmp (Line1, "Alert", 5)) info->SeeSound = snd; @@ -1027,13 +1501,16 @@ static int PatchThing (int thingy) info->DeathSound = snd; else if (!strnicmp (Line1, "Action", 6)) info->ActiveSound = snd; + else if (!strnicmp(Line1, "Rip", 3)) + info->SoundVar(NAME_RipSound) = snd; + } } else if (linelen == 4) { if (stricmp (Line1, "Mass") == 0) { - info->Mass = val; + info->Mass = (int)val; } else if (stricmp (Line1, "Bits") == 0) { @@ -1052,7 +1529,7 @@ static int PatchThing (int thingy) { if (IsNum (strval)) { - value[0] |= (unsigned long)strtoll(strval, NULL, 10); + value[0] |= (uint32_t)strtoll(strval, NULL, 10); vchanged[0] = true; } else @@ -1077,12 +1554,6 @@ static int PatchThing (int thingy) } if (vchanged[0]) { - if (value[0] & MF_SLIDE) - { - // SLIDE (which occupies in Doom what is the MF_INCHASE slot in ZDoom) - value[0] &= ~MF_SLIDE; // clean the slot - // Nothing else to do, this flag is never actually used. - } if (value[0] & MF_TRANSLATION) { info->Translation = TRANSLATION (TRANSLATION_Standard, @@ -1118,10 +1589,10 @@ static int PatchThing (int thingy) // This is different from BOUNCE_Heretic behavior as in Heretic the missiles // die when they bounce, while in MBF they will continue to bounce until they // collide with a wall or a solid actor. - if (value[0] & MF_MISSILE) info->BounceFlags = BOUNCE_Classic; + if (value[0] & MF_MISSILE) info->BounceFlags = BOUNCE_Classic | BOUNCE_DEH; // MBF bouncing actors that do not have the missile flag will also rebound on // walls, and this does correspond roughly to the ZDoom bounce style. - else info->BounceFlags = BOUNCE_Grenade; + else info->BounceFlags = BOUNCE_Grenade | BOUNCE_DEH; // MBF grenades are dehacked rockets that gain the BOUNCES flag but // lose the MISSILE flag, so they can be identified here easily. @@ -1131,27 +1602,13 @@ static int PatchThing (int thingy) info->effects |= FX_GRENADE; // by grenade trail } - // MBF bounce factors depend on flag combos: - const double MBF_BOUNCE_NOGRAVITY = 1; // With NOGRAVITY: full momentum - const double MBF_BOUNCE_FLOATDROPOFF = 0.85; // With FLOAT and DROPOFF: 85% - const double MBF_BOUNCE_FLOAT = 0.7; // With FLOAT alone: 70% - const double MBF_BOUNCE_DEFAULT = 0.45; // Without the above flags: 45% - const double MBF_BOUNCE_WALL = 0.5; // Bouncing off walls: 50% + // bounce factors are dynamic, we only set some defaults here. + info->bouncefactor = 0.45; + info->wallbouncefactor = 0.85; - info->bouncefactor = ((value[0] & MF_NOGRAVITY) ? MBF_BOUNCE_NOGRAVITY - : (value[0] & MF_FLOAT) ? (value[0] & MF_DROPOFF) ? MBF_BOUNCE_FLOATDROPOFF - : MBF_BOUNCE_FLOAT : MBF_BOUNCE_DEFAULT); - - info->wallbouncefactor = ((value[0] & MF_NOGRAVITY) ? MBF_BOUNCE_NOGRAVITY : MBF_BOUNCE_WALL); - - // MBF sentient actors with BOUNCE and FLOAT are able to "jump" by floating up. - if (info->IsSentient()) - { - if (value[0] & MF_FLOAT) info->flags6 |= MF6_CANJUMP; - } - // Non sentient actors can be damaged but they shouldn't bleed. - else + if (!info->IsSentient()) { + // Non sentient actors can be damaged but they shouldn't bleed. value[0] |= MF_NOBLOOD; } } @@ -1173,6 +1630,11 @@ static int PatchThing (int thingy) value[0] &= ~MF_TRANSLUCENT; // clean the slot vchanged[2] = true; value[2] |= 2; // let the TRANSLUCxx code below handle it } + if (value[0] & MF_MISSILE) + { + // all missiles in Doom are NOTELEPORT, the other flags are for consistency. + info->flags2 |= MF2_IMPACT | MF2_PCROSS | MF2_NOTELEPORT; + } if ((info->flags & MF_MISSILE) && (info->flags2 & MF2_NOTELEPORT) && !(value[0] & MF_MISSILE)) { @@ -1225,6 +1687,7 @@ static int PatchThing (int thingy) else if (value[2] & 4) info->Alpha = 0.75; info->RenderStyle = STYLE_Translucent; + info->renderflags &= ~RF_ZDOOMTRANS; } if (value[2] & 8) info->renderflags |= RF_INVISIBLE; @@ -1313,7 +1776,7 @@ static int PatchThing (int thingy) // real benefit to doing this, and it would be very difficult for // me to emulate it, I have disabled them entirely. -static int PatchSound (int soundNum) +static int PatchSound (int soundNum, int flags) { int result; @@ -1365,13 +1828,19 @@ static int PatchSound (int soundNum) return result; } -static int PatchFrame (int frameNum) +DehBits sbits[] = { + { "SKILL5FAST", STF_FAST } +}; + + +static int PatchFrame (int frameNum, int flags) { + MBFArgs args{}; int result; int tics, misc1, frame; FState *info, dummy; - info = FindState (frameNum); + info = FindState (frameNum, false); if (info) { DPrintf (DMSG_SPAMMY, "Frame %d\n", frameNum); @@ -1399,7 +1868,8 @@ static int PatchFrame (int frameNum) while ((result = GetLine ()) == 1) { - int val = atoi (Line2); + int64_t val64 = atoll(Line2); + int val = int(val64); size_t keylen = strlen (Line1); if (keylen == 8 && stricmp (Line1, "Duration") == 0) @@ -1416,28 +1886,7 @@ static int PatchFrame (int frameNum) } else if (keylen == 13 && stricmp (Line1, "Sprite number") == 0) { - unsigned int i; - - if (val < (int)OrgSprNames.Size()) - { - for (i = 0; i < sprites.Size(); i++) - { - if (memcmp (OrgSprNames[val].c, sprites[i].name, 4) == 0) - { - info->sprite = (int)i; - break; - } - } - if (i == sprites.Size ()) - { - Printf ("Frame %d: Sprite %d (%s) is undefined\n", - frameNum, val, OrgSprNames[val].c); - } - } - else - { - Printf ("Frame %d: Sprite %d out of range\n", frameNum, val); - } + stateSprites.Insert(info, val); } else if (keylen == 10 && stricmp (Line1, "Next frame") == 0) { @@ -1448,6 +1897,68 @@ static int PatchFrame (int frameNum) { frame = val; } + else if (keylen == 5 && strnicmp(Line1, "Args", 4) == 0) + { + int arg = Line1[4] - '1'; + if (arg < 0 || arg >= 8) + { + Printf("Invalid frame arg %d\n", arg); + } + else + { + args.args[arg] = val64; + args.argsused |= (1 << arg); + } + } + else if (stricmp(Line1, "MBF21 Bits") == 0) + { + uint32_t value = 0; + bool vchanged = false; + + char* strval; + + for (strval = Line2; (strval = strtok(strval, ",+| \t\f\r")); strval = NULL) + { + if (IsNum(strval)) + { + value |= (uint32_t)strtoll(strval, NULL, 10); + vchanged = true; + } + else + { + unsigned i; + for (i = 0; i < countof(sbits); i++) + { + if (!stricmp(strval, sbits[i].name)) + { + vchanged = true; + value |= 1 << i; + break; + } + } + if (i == countof(sbits)) + { + DPrintf(DMSG_ERROR, "Unknown bit mnemonic %s\n", strval); + } + } + } + if (vchanged) + { + int flags = 0; + int mask = 0; + for (size_t i = 0; i < countof(sbits); i++) + { + mask |= sbits[i].value; + if (value & (1 << i)) + { + flags |= sbits[i].value; + } + } + info->StateFlags = (info->StateFlags & ~mask) | flags; + } + DPrintf(DMSG_SPAMMY, "MBF21 Bits: %d (0x%08x)\n", info->StateFlags, info->StateFlags); + } + else { Printf (unknown_str, Line1, "Frame", frameNum); @@ -1466,17 +1977,18 @@ static int PatchFrame (int frameNum) info->Frame = frame & 0x3f; if (frame & 0x8000) info->StateFlags |= STF_FULLBRIGHT; else info->StateFlags &= ~STF_FULLBRIGHT; + stateargs.Insert(info, args); } return result; } -static int PatchSprite (int sprNum) +static int PatchSprite (int sprNum, int flags) { int result; int offset = 0; - if ((unsigned)sprNum < OrgSprNames.Size()) + if ((unsigned)sprNum < OrgSprOrgSize) { DPrintf (DMSG_SPAMMY, "Sprite %d\n", sprNum); } @@ -1493,12 +2005,12 @@ static int PatchSprite (int sprNum) else Printf (unknown_str, Line1, "Sprite", sprNum); } - if (offset > 0 && sprNum != -1) + if (offset > 0 && sprNum != -1 && !dsdhacked) { // Calculate offset from beginning of sprite names. offset = (offset - toff[dversion] - 22044) / 8; - if ((unsigned)offset < OrgSprNames.Size()) + if ((unsigned)offset < OrgSprOrgSize) { sprNum = FindSprite (OrgSprNames[sprNum].c); if (sprNum != -1) @@ -1513,7 +2025,7 @@ static int PatchSprite (int sprNum) return result; } -static int PatchAmmo (int ammoNum) +static int PatchAmmo (int ammoNum, int flags) { PClassActor *ammoType = NULL; AActor *defaultAmmo = NULL; @@ -1595,7 +2107,16 @@ static int PatchAmmo (int ammoNum) return result; } -static int PatchWeapon (int weapNum) +DehBits wbits[] = { + { "NOTHRUST", -1 }, // i.e. set kickback to 0 + { "SILENT", WIF_NOALERT }, + { "NOAUTOFIRE", WIF_NOAUTOFIRE }, + { "FLEEMELEE", WIF_MELEEWEAPON }, + { "AUTOSWITCHFROM", WIF_WIMPY_WEAPON }, // ugh, I wish I could change this stupid name... + { "NOAUTOSWITCHTO", WIF_NOAUTOSWITCHTO } +}; + +static int PatchWeapon (int weapNum, int flags) { int result; PClassActor *type = nullptr; @@ -1618,64 +2139,62 @@ static int PatchWeapon (int weapNum) Printf ("Weapon %d out of range.\n", weapNum); } + FState* readyState = nullptr; while ((result = GetLine ()) == 1) { int val = atoi (Line2); - if (strlen (Line1) >= 9) + size_t len = strlen(Line1); + if (len > 6 && stricmp (Line1 + len - 6, " frame") == 0) { - if (stricmp (Line1 + strlen (Line1) - 6, " frame") == 0) - { - FState *state = FindState (val); + FState *state = FindState (val); - if (type != NULL && !patchedStates) - { - statedef.MakeStateDefines(type); - patchedStates = true; - } + if (type != nullptr && !patchedStates) + { + statedef.MakeStateDefines(type); + patchedStates = true; + } - if (strnicmp (Line1, "Deselect", 8) == 0) - statedef.SetStateLabel("Select", state); - else if (strnicmp (Line1, "Select", 6) == 0) - statedef.SetStateLabel("Deselect", state); - else if (strnicmp (Line1, "Bobbing", 7) == 0) - statedef.SetStateLabel("Ready", state); - else if (strnicmp (Line1, "Shooting", 8) == 0) - statedef.SetStateLabel("Fire", state); - else if (strnicmp (Line1, "Firing", 6) == 0) - statedef.SetStateLabel("Flash", state); + if (strnicmp (Line1, "Deselect", 8) == 0) + statedef.SetStateLabel("Select", state); + else if (strnicmp (Line1, "Select", 6) == 0) + statedef.SetStateLabel("Deselect", state); + else if (strnicmp(Line1, "Bobbing", 7) == 0) + { + readyState = state; + statedef.SetStateLabel("Ready", state); } - else if (stricmp (Line1, "Ammo type") == 0) + else if (strnicmp (Line1, "Shooting", 8) == 0) + statedef.SetStateLabel("Fire", state); + else if (strnicmp (Line1, "Firing", 6) == 0) + statedef.SetStateLabel("Flash", state); + } + else if (stricmp (Line1, "Ammo type") == 0) + { + if (val < 0 || val >= 12 || (unsigned)val >= AmmoNames.Size()) { - if (val < 0 || val >= 12 || (unsigned)val >= AmmoNames.Size()) - { - val = 5; - } - if (info) + val = 5; + } + if (info) + { + auto &AmmoType = info->PointerVar(NAME_AmmoType1); + AmmoType = AmmoNames[val]; + if (AmmoType != nullptr) { - auto &AmmoType = info->PointerVar(NAME_AmmoType1); - AmmoType = AmmoNames[val]; - if (AmmoType != nullptr) + info->IntVar(NAME_AmmoGive1) = GetDefaultByType(AmmoType)->IntVar(NAME_Amount) * 2; + auto &AmmoUse = info->IntVar(NAME_AmmoUse1); + if (AmmoUse == 0) { - info->IntVar(NAME_AmmoGive1) = GetDefaultByType(AmmoType)->IntVar(NAME_Amount) * 2; - auto &AmmoUse = info->IntVar(NAME_AmmoUse1); - if (AmmoUse == 0) - { - AmmoUse = 1; - } + AmmoUse = 1; } } } - else - { - Printf (unknown_str, Line1, "Weapon", weapNum); - } } else if (stricmp (Line1, "Decal") == 0) { stripwhite (Line2); const FDecalTemplate *decal = DecalLibrary.GetDecalByName (Line2); - if (decal != NULL) + if (decal != nullptr) { if (info) info->DecalGenerator = const_cast (decal); } @@ -1692,10 +2211,61 @@ static int PatchWeapon (int weapNum) info->flags6 |= MF6_INTRYMOVE; // flag the weapon for postprocessing (reuse a flag that can't be set by external means) } } - else if (stricmp (Line1, "Min ammo") == 0) - { - if (info) info->IntVar(NAME_MinSelAmmo1) = val; - } + else if (stricmp (Line1, "Min ammo") == 0) + { + if (info) info->IntVar(NAME_MinSelAmmo1) = val; + } + else if (stricmp(Line1, "MBF21 Bits") == 0) + { + uint32_t value = 0; + bool vchanged = false; + + char* strval; + + for (strval = Line2; (strval = strtok(strval, ",+| \t\f\r")); strval = NULL) + { + if (IsNum(strval)) + { + value |= (uint32_t)strtoll(strval, NULL, 10); + vchanged = true; + } + else + { + unsigned i; + for (i = 0; i < countof(wbits); i++) + { + if (!stricmp(strval, wbits[i].name)) + { + vchanged = true; + value |= 1 << i; + break; + } + } + if (i == countof(wbits)) + { + DPrintf(DMSG_ERROR, "Unknown bit mnemonic %s\n", strval); + } + } + } + if (vchanged) + { + int kickback = 100; + int flags = 0; + for (size_t i = 0; i < countof(wbits); i++) + { + if (value & (1 << i)) + { + int val = wbits[i].value; + if (val == -1) kickback = 0; + else flags |= wbits[i].value; + } + } + info->IntVar(NAME_Kickback) = kickback; + info->IntVar(NAME_WeaponFlags) = flags; + } + DPrintf(DMSG_SPAMMY, "MBF21 Bits: %d (0x%08x)\n", info->flags.GetValue(), info->flags.GetValue()); + } + else { Printf (unknown_str, Line1, "Weapon", weapNum); @@ -1704,6 +2274,20 @@ static int PatchWeapon (int weapNum) if (info) { + // Emulate the hard coded ready sound of the chainsaw as good as possible. + if (readyState) + { + FState* state = FindState(67); // S_SAW + if (readyState == state) + { + info->IntVar(NAME_ReadySound) = S_FindSound("weapons/sawidle").index(); + } + else + { + info->IntVar(NAME_ReadySound) = 0; + } + } + if (info->PointerVar(NAME_AmmoType1) == nullptr) { info->IntVar(NAME_AmmoUse1) = 0; @@ -1718,12 +2302,11 @@ static int PatchWeapon (int weapNum) return result; } -static void SetPointer(FState *state, PFunction *sym, int frame = 0) +static int SetPointer(FState *state, PFunction *sym, int frame = 0) { if (sym == NULL) { state->ClearAction(); - return; } else { @@ -1733,17 +2316,15 @@ static void SetPointer(FState *state, PFunction *sym, int frame = 0) { if (sym->SymbolName == MBFCodePointers[i].name) { - MBFParamState newstate; - newstate.state = state; - newstate.pointer = i; - MBFParamStates.Push(newstate); - break; // No need to cycle through the rest of the list. + MBFParamState newstate = { state, int(i) }; + return MBFParamStates.Push(newstate); } } } + return -1; } -static int PatchPointer (int ptrNum) +static int PatchPointer (int ptrNum, int flags) { int result; @@ -1780,7 +2361,7 @@ static int PatchPointer (int ptrNum) { if ((unsigned)ptrNum < CodePConv.Size() && (!stricmp (Line1, "Codep Frame"))) { - FState *state = FindState (CodePConv[ptrNum]); + FState *state = FindState (CodePConv[ptrNum], true); if (state) { int index = atoi(Line2); @@ -1805,7 +2386,7 @@ static int PatchPointer (int ptrNum) return result; } -static int PatchCheats (int dummy) +static int PatchCheats (int dummy, int flags) { int result; @@ -1817,7 +2398,7 @@ static int PatchCheats (int dummy) return result; } -static int PatchMisc (int dummy) +static int PatchMisc (int dummy, int flags) { static const struct Key keys[] = { { "Initial Health", static_cast(myoffsetof(struct DehInfo,StartHealth)) }, @@ -1964,7 +2545,7 @@ static int PatchMisc (int dummy) auto health = GetDefaultByName ("HealthBonus"); if (health!=NULL) { - health->IntVar(NAME_MaxAmount) = 2 * deh.MaxHealth; + health->IntVar(NAME_MaxAmount) = -1; // needs to be evaluated at run time due to the compat flag. } health = GetDefaultByName ("Soulsphere"); @@ -2011,7 +2592,7 @@ static int PatchMisc (int dummy) return result; } -static int PatchPars (int dummy) +static int PatchPars (int dummy, int flags) { char *space, mapname[8], *moredata; level_info_t *info; @@ -2032,7 +2613,7 @@ static int PatchPars (int dummy) { while ('\0' != *str) { - if (isspace((unsigned char)*str)) + if (*str != '\r' && isspace((unsigned char)*str)) { return str; } @@ -2076,7 +2657,8 @@ static int PatchPars (int dummy) return result; } -static int PatchCodePtrs (int dummy) + +static int PatchCodePtrs (int dummy, int flags) { int result; @@ -2102,20 +2684,24 @@ static int PatchCodePtrs (int dummy) { FString symname; - if ((Line2[0] == 'A' || Line2[0] == 'a') && Line2[1] == '_') symname = Line2; else symname.Format("A_%s", Line2); + // Hack alert: If A_ConsumeAmmo is used we need to handle the ammo use differently. + // Since this is a parameterized code pointer the AmmoPerAttack check cannot find it easily without some help. + if (symname.CompareNoCase("A_ConsumeAmmo") == 0) + state->StateFlags |= STF_CONSUMEAMMO; + // Let's consider as aliases some redundant MBF pointer bool ismbfcp = false; for (unsigned int i = 0; i < MBFCodePointers.Size(); i++) { if (!symname.CompareNoCase(MBFCodePointers[i].alias)) { - symname = MBFCodePointers[i].name; - DPrintf(DMSG_SPAMMY, "%s --> %s\n", MBFCodePointers[i].alias, MBFCodePointers[i].name.GetChars()); + symname = MBFCodePointers[i].name.GetChars(); + DPrintf(DMSG_SPAMMY, "%s --> %s\n", MBFCodePointers[i].alias.GetChars(), MBFCodePointers[i].name.GetChars()); ismbfcp = true; break; } @@ -2123,6 +2709,8 @@ static int PatchCodePtrs (int dummy) // This skips the action table and goes directly to the internal symbol table // DEH compatible functions are easy to recognize. + // Note that A_CPosAttack needs to be remapped because it differs from the original and cannot be renamed anymore. + if (!symname.CompareNoCase("A_CPosAttack")) symname = "A_CPosAttackDehacked"; PFunction *sym = dyn_cast(PClass::FindActor(NAME_Weapon)->FindSymbol(symname, true)); if (sym == NULL) { @@ -2145,7 +2733,7 @@ static int PatchCodePtrs (int dummy) return result; } -static int PatchMusic (int dummy) +static int PatchMusic (int dummy, int flags) { int result; @@ -2165,8 +2753,42 @@ static int PatchMusic (int dummy) return result; } + +// This repplaces a sprite name in the current working data +static void ReplaceSpriteInData(const char* oldStr, const char* newStr) + { + if (strncmp ("PLAY", oldStr, 4) == 0) + { + strncpy (deh.PlayerSprite, newStr, 4); + } + // If this sprite is used by a pickup, then the DehackedPickup sprite map + // needs to be updated too. + for (size_t i = 0; i < countof(DehSpriteMappings); ++i) + { + if (strncmp (DehSpriteMappings[i].Sprite, oldStr, 4) == 0) + { + // Found a match, so change it. + strncpy (DehSpriteMappings[i].Sprite, newStr, 4); + + // Now shift the map's entries around so that it stays sorted. + // This must be done because the map is scanned using a binary search. + while (i > 0 && strncmp (DehSpriteMappings[i-1].Sprite, newStr, 4) > 0) + { + std::swap (DehSpriteMappings[i-1], DehSpriteMappings[i]); + --i; + } + while ((size_t)i < countof(DehSpriteMappings)-1 && + strncmp (DehSpriteMappings[i+1].Sprite, newStr, 4) < 0) + { + std::swap (DehSpriteMappings[i+1], DehSpriteMappings[i]); + ++i; + } + break; + } + } + } -static int PatchText (int oldSize) +static int PatchText (int oldSize, int flags) { int newSize; char *oldStr; @@ -2190,22 +2812,18 @@ static int PatchText (int oldSize) } newSize = atoi (temp); - oldStr = new char[oldSize + 1]; - newStr = new char[newSize + 1]; - - if (!oldStr || !newStr) - { - Printf ("Out of memory.\n"); - goto donewithtext; - } - + FString oldStrData, newStrData; + oldStr = oldStrData.LockNewBuffer(oldSize + 1); + newStr = newStrData.LockNewBuffer(newSize + 1); + good = ReadChars (&oldStr, oldSize); good += ReadChars (&newStr, newSize); + oldStrData.UnlockBuffer(); + newStrData.UnlockBuffer(); + if (!good) { - delete[] newStr; - delete[] oldStr; Printf ("Unexpected end-of-file.\n"); return 0; } @@ -2226,55 +2844,37 @@ static int PatchText (int oldSize) if (i != -1) { strncpy (sprites[i].name, newStr, 4); - if (strncmp ("PLAY", oldStr, 4) == 0) - { - strncpy (deh.PlayerSprite, newStr, 4); - } - for (unsigned ii = 0; ii < OrgSprNames.Size(); ii++) + for (unsigned ii = 0; ii < OrgSprOrgSize; ii++) { if (!stricmp(OrgSprNames[ii].c, oldStr)) { strcpy(OrgSprNames[ii].c, newStr); } } - // If this sprite is used by a pickup, then the DehackedPickup sprite map - // needs to be updated too. - for (i = 0; (size_t)i < countof(DehSpriteMappings); ++i) - { - if (strncmp (DehSpriteMappings[i].Sprite, oldStr, 4) == 0) - { - // Found a match, so change it. - strncpy (DehSpriteMappings[i].Sprite, newStr, 4); - - // Now shift the map's entries around so that it stays sorted. - // This must be done because the map is scanned using a binary search. - while (i > 0 && strncmp (DehSpriteMappings[i-1].Sprite, newStr, 4) > 0) - { - swapvalues (DehSpriteMappings[i-1], DehSpriteMappings[i]); - --i; - } - while ((size_t)i < countof(DehSpriteMappings)-1 && - strncmp (DehSpriteMappings[i+1].Sprite, newStr, 4) < 0) - { - swapvalues (DehSpriteMappings[i+1], DehSpriteMappings[i]); - ++i; - } - break; - } - } + ReplaceSpriteInData(oldStr, newStr); goto donewithtext; } } // Search through most other texts const char *str; - do + + // hackhack: If the given string is "Doom", only replace "MUSIC_DOOM". + // This is the only music or texture name clashing with common words in the string table. + if (!stricmp(oldStr, "Doom")) + { + str = "MUSIC_DOOM"; + TableElement te = { LumpFileNum, { newStrData, newStrData, newStrData, newStrData } }; + DehStrings.Insert(str, te); + good = true; + } + else do { + oldStrData.MergeChars(' '); str = EnglishStrings.MatchString(oldStr); if (str != NULL) { - FString newname = newStr; - TableElement te = { LumpFileNum, { newname, newname, newname, newname } }; + TableElement te = { LumpFileNum, { newStrData, newStrData, newStrData, newStrData } }; DehStrings.Insert(str, te); EnglishStrings.Remove(str); // remove entry so that it won't get found again by the next iteration or by another replacement later good = true; @@ -2288,11 +2888,6 @@ static int PatchText (int oldSize) } donewithtext: - if (newStr) - delete[] newStr; - if (oldStr) - delete[] oldStr; - // Fetch next identifier for main loop while ((result = GetLine ()) == 1) ; @@ -2300,7 +2895,7 @@ static int PatchText (int oldSize) return result; } -static int PatchStrings (int dummy) +static int PatchStrings (int dummy, int flags) { int result; @@ -2324,24 +2919,81 @@ static int PatchStrings (int dummy) } } while (Line2 && *Line2); - ReplaceSpecialChars (holdstring.LockBuffer()); - holdstring.UnlockBuffer(); - // Account for a discrepancy between Boom's and ZDoom's name for the red skull key pickup message - const char *ll = Line1; - if (!stricmp(ll, "GOTREDSKULL")) ll = "GOTREDSKUL"; - TableElement te = { LumpFileNum, { holdstring, holdstring, holdstring, holdstring } }; - DehStrings.Insert(ll, te); - DPrintf (DMSG_SPAMMY, "%s set to:\n%s\n", Line1, holdstring.GetChars()); + if(!(flags & DEH_SKIP_BEX_STRINGS_IF_LANGUAGE)) + { + ReplaceSpecialChars (holdstring.LockBuffer()); + holdstring.UnlockBuffer(); + // Account for a discrepancy between Boom's and ZDoom's name for the red skull key pickup message + const char *ll = Line1; + if (!stricmp(ll, "GOTREDSKULL")) ll = "GOTREDSKUL"; + TableElement te = { LumpFileNum, { holdstring, holdstring, holdstring, holdstring } }; + DehStrings.Insert(ll, te); + DPrintf (DMSG_SPAMMY, "%s set to:\n%s\n", Line1, holdstring.GetChars()); + } + } + + return result; +} + +static int PatchSoundNames (int dummy, int flags) +{ + int result; + + DPrintf (DMSG_SPAMMY, "[Sounds]\n"); + + while ((result = GetLine()) == 1) + { + stripwhite(Line2); + FString newname = skipwhite (Line2); + ReplaceSoundName((int)strtoll(Line1, nullptr, 10), newname.GetChars()); + DPrintf (DMSG_SPAMMY, "Sound %d set to:\n%s\n", Line1, newname.GetChars()); } return result; } -static int DoInclude (int dummy) +static int PatchSpriteNames (int dummy, int flags) +{ + int result; + + DPrintf (DMSG_SPAMMY, "[Sprites]\n"); + + while ((result = GetLine()) == 1) + { + stripwhite(Line2); + FString newname = skipwhite (Line2); + if (newname.Len() != 4) + { + Printf("Sprite name must be 4 characters long, got '%s'\n", newname.GetChars()); + continue; + } + int64_t line1val = strtoll(Line1, nullptr, 10); + if (line1val >= OrgSprNames.Size()) + { + unsigned osize = OrgSprNames.Size(); + OrgSprNames.Resize(line1val + 1); + DEHSprName nulname{}; + for (unsigned o = osize; o < OrgSprNames.Size(); o++) + { + OrgSprNames[o] = nulname; + } + } + int v = GetSpriteIndex(newname.GetChars()); + memcpy(OrgSprNames[line1val].c, sprites[v].name, 5); + + DPrintf (DMSG_SPAMMY, "Sprite %d set to:\n%s\n", Line1, newname.GetChars()); + } + + return result; + } + + +static int DoInclude (int dummy, int flags) { char *data; int savedversion, savepversion, savepatchsize; - char *savepatchfile, *savepatchpt, *savepatchname; + char* savepatchfile, * savepatchpt; + FString savepatchname; if (including) { @@ -2382,15 +3034,15 @@ static int DoInclude (int dummy) // Try looking for the included file in the same directory // as the patch before looking in the current file. - const char *lastSlash = savepatchname ? strrchr (savepatchname, '/') : NULL; + const char *lastSlash = strrchr(savepatchname.GetChars(), '/'); char *path = data; if (lastSlash != NULL) { - size_t pathlen = lastSlash - savepatchname + strlen (data) + 2; + size_t pathlen = lastSlash - savepatchname.GetChars() + strlen (data) + 2; path = new char[pathlen]; - strncpy (path, savepatchname, (lastSlash - savepatchname) + 1); - strcpy (path + (lastSlash - savepatchname) + 1, data); + strncpy (path, savepatchname.GetChars(), (lastSlash - savepatchname.GetChars()) + 1); + strcpy (path + (lastSlash - savepatchname.GetChars()) + 1, data); if (!FileExists (path)) { delete[] path; @@ -2398,7 +3050,7 @@ static int DoInclude (int dummy) } } - D_LoadDehFile(path); + D_LoadDehFile(path, flags); if (data != path) { @@ -2424,33 +3076,46 @@ CVAR(Int, dehload, 0, CVAR_ARCHIVE) // Autoloading of .DEH lumps is disabled by // checks if lump is a .deh or .bex file. Only lumps in the root directory are considered valid. static bool isDehFile(int lumpnum) { - const char* const fullName = Wads.GetLumpFullName(lumpnum); + const char* const fullName = fileSystem.GetFileFullName(lumpnum); const char* const extension = strrchr(fullName, '.'); return NULL != extension && strchr(fullName, '/') == NULL && (0 == stricmp(extension, ".deh") || 0 == stricmp(extension, ".bex")); } -int D_LoadDehLumps(DehLumpSource source) +int D_LoadDehLumps(DehLumpSource source, int flags) { int lastlump = 0, lumpnum, count = 0; - while ((lumpnum = Wads.FindLump("DEHACKED", &lastlump)) >= 0) + while ((lumpnum = fileSystem.FindLump("DEHACKED", &lastlump)) >= 0) { - const int filenum = Wads.GetLumpFile(lumpnum); + const int filenum = fileSystem.GetFileContainer(lumpnum); - if (FromIWAD == source && filenum > Wads.GetMaxIwadNum()) + if (FromIWAD == source && filenum > fileSystem.GetMaxIwadNum()) { // No more DEHACKED lumps in IWAD break; } - else if (FromPWADs == source && filenum <= Wads.GetMaxIwadNum()) + else if (FromPWADs == source && filenum <= fileSystem.GetMaxIwadNum()) { // Skip DEHACKED lumps from IWAD continue; } - count += D_LoadDehLump(lumpnum); + int filtered_flags = flags & ~DEH_SKIP_BEX_STRINGS_IF_LANGUAGE; + + if((flags & DEH_SKIP_BEX_STRINGS_IF_LANGUAGE) && FromIWAD == source) + { + int iwadnum = fileSystem.GetIwadNum(); + int lastlump2 = fileSystem.GetFirstEntry(iwadnum); + int lumpnum2 = fileSystem.FindLump("LANGUAGE", &lastlump2); + + if(lumpnum2 >= 0 && fileSystem.GetFileContainer(lumpnum2) == iwadnum) + { + filtered_flags |= DEH_SKIP_BEX_STRINGS_IF_LANGUAGE; + } + } + count += D_LoadDehLump(lumpnum, filtered_flags); } if (FromPWADs == source && 0 == PatchSize && dehload > 0) @@ -2459,21 +3124,21 @@ int D_LoadDehLumps(DehLumpSource source) if (dehload == 1) // load all .DEH lumps that are found. { - for (lumpnum = 0, lastlump = Wads.GetNumLumps(); lumpnum < lastlump; ++lumpnum) + for (lumpnum = 0, lastlump = fileSystem.GetNumEntries(); lumpnum < lastlump; ++lumpnum) { if (isDehFile(lumpnum)) { - count += D_LoadDehLump(lumpnum); + count += D_LoadDehLump(lumpnum, 0); } } } else // only load the last .DEH lump that is found. { - for (lumpnum = Wads.GetNumLumps()-1; lumpnum >=0; --lumpnum) + for (lumpnum = fileSystem.GetNumEntries()-1; lumpnum >=0; --lumpnum) { if (isDehFile(lumpnum)) { - count += D_LoadDehLump(lumpnum); + count += D_LoadDehLump(lumpnum, 0); break; } } @@ -2483,24 +3148,24 @@ int D_LoadDehLumps(DehLumpSource source) return count; } -bool D_LoadDehLump(int lumpnum) +bool D_LoadDehLump(int lumpnum, int flags) { auto ls = LumpFileNum; - LumpFileNum = Wads.GetLumpFile(lumpnum); + LumpFileNum = fileSystem.GetFileContainer(lumpnum); - PatchSize = Wads.LumpLength(lumpnum); + PatchSize = fileSystem.FileLength(lumpnum); - PatchName = copystring(Wads.GetLumpFullPath(lumpnum)); + PatchName = fileSystem.GetFileFullPath(lumpnum).c_str(); PatchFile = new char[PatchSize + 1]; - Wads.ReadLump(lumpnum, PatchFile); + fileSystem.ReadFile(lumpnum, PatchFile); PatchFile[PatchSize] = '\0'; // terminate with a '\0' character - auto res = DoDehPatch(); + auto res = DoDehPatch(flags); LumpFileNum = ls; return res; } -bool D_LoadDehFile(const char *patchfile) +bool D_LoadDehFile(const char *patchfile, int flags) { FileReader fr; @@ -2508,37 +3173,37 @@ bool D_LoadDehFile(const char *patchfile) { PatchSize = (int)fr.GetLength(); - PatchName = copystring(patchfile); + PatchName = patchfile; PatchFile = new char[PatchSize + 1]; fr.Read(PatchFile, PatchSize); fr.Close(); PatchFile[PatchSize] = '\0'; // terminate with a '\0' character - return DoDehPatch(); + return DoDehPatch(flags); } else { // Couldn't find it in the filesystem; try from a lump instead. - int lumpnum = Wads.CheckNumForFullName(patchfile, true); + int lumpnum = fileSystem.CheckNumForFullName(patchfile, true); if (lumpnum < 0) { // Compatibility fallback. It's just here because // some WAD may need it. Should be deleted if it can // be confirmed that nothing uses this case. FString filebase(ExtractFileBase(patchfile)); - lumpnum = Wads.CheckNumForName(filebase); + lumpnum = fileSystem.CheckNumForName(filebase.GetChars()); } if (lumpnum >= 0) { - return D_LoadDehLump(lumpnum); + return D_LoadDehLump(lumpnum, flags); } } Printf ("Could not open DeHackEd patch \"%s\"\n", patchfile); return false; } -static bool DoDehPatch() +static bool DoDehPatch(int flags) { - if (!batchrun) Printf("Adding dehacked patch %s\n", PatchName); + if (!batchrun) Printf("Adding dehacked patch %s\n", PatchName.GetChars()); int cont; @@ -2548,8 +3213,8 @@ static bool DoDehPatch() { if (PatchFile[25] < '3' && (PatchFile[25] < '2' || PatchFile[27] < '3')) { - Printf (PRINT_BOLD, "\"%s\" is an old and unsupported DeHackEd patch\n", PatchName); - delete[] PatchName; + Printf (PRINT_BOLD, "\"%s\" is an old and unsupported DeHackEd patch\n", PatchName.GetChars()); + PatchName = ""; delete[] PatchFile; return false; } @@ -2567,8 +3232,8 @@ static bool DoDehPatch() } if (!cont || dversion == -1 || pversion == -1) { - Printf (PRINT_BOLD, "\"%s\" is not a DeHackEd patch file\n", PatchName); - delete[] PatchName; + Printf (PRINT_BOLD, "\"%s\" is not a DeHackEd patch file\n", PatchName.GetChars()); + PatchName = ""; delete[] PatchFile; return false; } @@ -2598,17 +3263,22 @@ static bool DoDehPatch() dversion = 1; else if (dversion == 21) dversion = 4; + else if (dversion == 2021) + { + dversion = 4; + dsdhacked = true; + } else { Printf ("Patch created with unknown DOOM version.\nAssuming version 1.9.\n"); dversion = 3; } - if (!LoadDehSupp ()) + if (StateMap.Size() == 0 && !LoadDehSupp ()) // only load this once. { Printf ("Could not load DEH support data\n"); UnloadDehSupp (); - delete[] PatchName; + PatchName = ""; delete[] PatchFile; return false; } @@ -2622,12 +3292,11 @@ static bool DoDehPatch() } else if (cont == 2) { - cont = HandleMode (Line1, atoi (Line2)); + cont = HandleMode (Line1, atoi (Line2), flags); } } while (cont); - UnloadDehSupp (); - delete[] PatchName; + PatchName = ""; delete[] PatchFile; if (!batchrun) Printf ("Patch installed\n"); return true; @@ -2638,68 +3307,53 @@ static inline bool CompareLabel (const char *want, const uint8_t *have) return *(uint32_t *)want == *(uint32_t *)have; } -static int DehUseCount; - static void UnloadDehSupp () { - if (--DehUseCount <= 0) - { - VMDisassemblyDumper disasmdump(VMDisassemblyDumper::Append); + VMDisassemblyDumper disasmdump(VMDisassemblyDumper::Append); - // Handle MBF params here, before the required arrays are cleared - for (unsigned int i=0; i < MBFParamStates.Size(); i++) - { - SetDehParams(MBFParamStates[i].state, MBFParamStates[i].pointer, disasmdump); - } - MBFParamStates.Clear(); - MBFParamStates.ShrinkToFit(); - MBFCodePointers.Clear(); - MBFCodePointers.ShrinkToFit(); - // StateMap is not freed here, because if you load a second - // dehacked patch through some means other than including it - // in the first patch, it won't see the state information - // that was altered by the first. So we need to keep the - // StateMap around until all patches have been applied. - DehUseCount = 0; - Actions.Reset(); - OrgHeights.Reset(); - CodePConv.Reset(); - OrgSprNames.Reset(); - SoundMap.Reset(); - InfoNames.Reset(); - BitNames.Reset(); - StyleNames.Reset(); - AmmoNames.Reset(); - UnchangedSpriteNames.Reset(); + // Handle MBF params here, before the required arrays are cleared + for (unsigned int i=0; i < MBFParamStates.Size(); i++) + { + SetDehParams(MBFParamStates[i].state, MBFParamStates[i].pointer, disasmdump, &MBFParamStates[i]); } + stateargs.Clear(); + MBFParamStates.Clear(); + MBFParamStates.ShrinkToFit(); + MBFCodePointers.Clear(); + MBFCodePointers.ShrinkToFit(); + OrgSprNames.Reset(); + StateMap.Reset(); + Actions.Reset(); + OrgHeights.Reset(); + CodePConv.Reset(); + SoundMap.Reset(); + InfoNames.Reset(); + BitNames.Reset(); + StyleNames.Reset(); + AmmoNames.Reset(); + UnchangedSpriteNames.Reset(); } -static bool LoadDehSupp () +bool LoadDehSupp () { try { // Make sure we only get the DEHSUPP lump from zdoom.pk3 // User modifications are not supported! - int lump = Wads.CheckNumForName("DEHSUPP"); + int lump = fileSystem.CheckNumForName("DEHSUPP"); if (lump == -1) { return false; } - if (Wads.GetLumpFile(lump) > 0) + if (fileSystem.GetFileContainer(lump) > 0) { Printf("Warning: DEHSUPP no longer supported. DEHACKED patch disabled.\n"); return false; } bool gotnames = false; - - if (++DehUseCount > 1) - { - return true; - } - if (EnglishStrings.CountUsed() == 0) EnglishStrings = GStrings.GetDefaultStrings(); @@ -2732,7 +3386,8 @@ static bool LoadDehSupp () // all relevant code pointers are either defined in Weapon // or Actor so this will find all of them. FString name = "A_"; - name << sc.String; + if (sc.Compare("CPosAttack")) name << "CPosAttackDehacked"; + else name << sc.String; PFunction *sym = dyn_cast(wcls->FindSymbol(name, true)); if (sym == NULL) { @@ -2777,6 +3432,7 @@ static bool LoadDehSupp () } else if (sc.Compare("OrgSprNames")) { + bool addit = OrgSprNames.Size() == 0; sc.MustGetStringName("{"); while (!sc.CheckString("}")) { @@ -2796,14 +3452,16 @@ static bool LoadDehSupp () { sc.ScriptError("Invalid sprite name '%s' (must be 4 characters)", sc.String); } - OrgSprNames.Push(s); + if (addit) OrgSprNames.Push(s); if (sc.CheckString("}")) break; sc.MustGetStringName(","); } + OrgSprOrgSize = OrgSprNames.Size(); } else if (sc.Compare("StateMap")) { bool addit = StateMap.Size() == 0; + int dehcount = 0; sc.MustGetStringName("{"); while (!sc.CheckString("}")) @@ -2845,6 +3503,14 @@ static bool LoadDehSupp () if (sc.CheckString("}")) break; sc.MustGetStringName(","); + // This mapping is mainly for P_SetSafeFlash. + for (int i = 0; i < s.StateSpan; i++) + { + assert(FState::StaticFindStateOwner(s.State + i)); + dehExtStates.Insert(dehcount, s.State + i); + s.State[i].DehIndex = dehcount; + dehcount++; + } } } else if (sc.Compare("SoundMap")) @@ -2966,14 +3632,10 @@ static bool LoadDehSupp () { CodePointerAlias temp; sc.MustGetString(); - strncpy(temp.alias, sc.String, 19); - temp.alias[19]=0; + temp.alias = sc.String; sc.MustGetStringName(","); sc.MustGetString(); temp.name = sc.String; - sc.MustGetStringName(","); - sc.MustGetNumber(); - temp.params = sc.Number; MBFCodePointers.Push(temp); if (sc.CheckString("}")) break; sc.MustGetStringName(","); @@ -3008,7 +3670,8 @@ void FinishDehPatch () { GetDefaultByType(cls)->flags8 |= MF8_RETARGETAFTERSLAM; } - + RemapAllSprites(); + for (touchedIndex = 0; touchedIndex < TouchedActors.Size(); ++touchedIndex) { PClassActor *subclass; @@ -3027,10 +3690,12 @@ void FinishDehPatch () { // Retry until we find a free name. This is unlikely to happen but not impossible. mysnprintf(typeNameBuilder, countof(typeNameBuilder), "DehackedPickup%d", nameindex++); - subclass = static_cast(dehtype->CreateDerivedClass(typeNameBuilder, dehtype->Size)); + bool newlycreated; + subclass = static_cast(dehtype->CreateDerivedClass(typeNameBuilder, dehtype->Size, &newlycreated, 0)); + if (newlycreated) subclass->InitializeDefaults(); } while (subclass == nullptr); - NewClassType(subclass); // This needs a VM type to work as intended. + NewClassType(subclass, 0); // This needs a VM type to work as intended. AActor *defaults2 = GetDefaultByType (subclass); memcpy ((void *)defaults2, (void *)defaults1, sizeof(AActor)); @@ -3052,8 +3717,10 @@ void FinishDehPatch () type->ActorInfo()->Replacement = subclass; subclass->ActorInfo()->Replacee = type; + subclass->ActorInfo()->LightAssociations = type->ActorInfo()->LightAssociations; // If this actor was already replaced by another actor, copy that // replacement over to this item. + if (old_replacement != NULL) { subclass->ActorInfo()->Replacement = old_replacement; @@ -3073,11 +3740,11 @@ void FinishDehPatch () } } } - // Now that all Dehacked patches have been processed, it's okay to free StateMap. - StateMap.Reset(); + UnloadDehSupp(); TouchedActors.Reset(); EnglishStrings.Clear(); - GStrings.SetDehackedStrings(std::move(DehStrings)); + GStrings.SetOverrideStrings(DehStrings); + DehStrings.Clear(); // Now it gets nasty: We have to fiddle around with the weapons' ammo use info to make Doom's original // ammo consumption work as intended. @@ -3094,8 +3761,8 @@ void FinishDehPatch () } else { + bool handled = false; weap->BoolVar(NAME_bDehAmmo) = true; - weap->IntVar(NAME_AmmoUse1) = 0; // to allow proper checks in CheckAmmo we have to find the first attack pointer in the Fire sequence // and set its default ammo use as the weapon's AmmoUse1. @@ -3110,25 +3777,39 @@ void FinishDehPatch () break; // State has already been checked so we reached a loop } StateVisited[state] = true; + if (state->StateFlags & STF_CONSUMEAMMO) + { + // If A_ConsumeAmmo is being used we have to rely on the existing AmmoUse1 value. + handled = true; + state->StateFlags &= ~STF_CONSUMEAMMO; + break; + } for(unsigned j = 0; AmmoPerAttacks[j].func != NAME_None; j++) { if (AmmoPerAttacks[j].ptr == nullptr) { auto p = dyn_cast(wcls->FindSymbol(AmmoPerAttacks[j].func, true)); if (p != nullptr) AmmoPerAttacks[j].ptr = p->Variants[0].Implementation; + assert(AmmoPerAttacks[j].ptr); } - if (state->ActionFunc == AmmoPerAttacks[j].ptr) + if (state->ActionFunc == AmmoPerAttacks[j].ptr && AmmoPerAttacks[j].ptr) { found = true; int use = AmmoPerAttacks[j].ammocount; if (use < 0) use = deh.BFGCells; weap->IntVar(NAME_AmmoUse1) = use; + handled = true; break; } } if (found) break; state = state->GetNextState(); } + if (!handled) + { + weap->IntVar(NAME_AmmoUse1) = 0; + + } } } WeaponNames.Clear(); @@ -3163,3 +3844,367 @@ DEFINE_ACTION_FUNCTION(ADehackedPickup, DetermineType) } ACTION_RETURN_POINTER(nullptr); } + +// Handling the flags is not as trivial as it seems... + +struct FlagHandler +{ + void (*setter)(AActor*); + void (*clearer)(AActor*); + bool (*checker)(AActor*); +}; + +// cut down on boilerplate +#define F(flag) { [](AActor* a) { a->flags |= flag; }, [](AActor* a) { a->flags &= ~flag; }, [](AActor* a)->bool { return a->flags & flag; } } +#define F2(flag) { [](AActor* a) { a->flags2 |= flag; }, [](AActor* a) { a->flags2 &= ~flag; }, [](AActor* a)->bool { return a->flags2 & flag; } } +#define F3(flag) { [](AActor* a) { a->flags3 |= flag; }, [](AActor* a) { a->flags3 &= ~flag; }, [](AActor* a)->bool { return a->flags3 & flag; } } +#define F4(flag) { [](AActor* a) { a->flags4 |= flag; }, [](AActor* a) { a->flags4 &= ~flag; }, [](AActor* a)->bool { return a->flags4 & flag; } } +#define F6(flag) { [](AActor* a) { a->flags6 |= flag; }, [](AActor* a) { a->flags6 &= ~flag; }, [](AActor* a)->bool { return a->flags6 & flag; } } +#define F8(flag) { [](AActor* a) { a->flags8 |= flag; }, [](AActor* a) { a->flags8 &= ~flag; }, [](AActor* a)->bool { return a->flags8 & flag; } } +#define DEPF(flag) { [](AActor* a) { HandleDeprecatedFlags(a, nullptr, true, flag); }, [](AActor* a) { HandleDeprecatedFlags(a, nullptr, false, flag); }, [](AActor* a)->bool { return CheckDeprecatedFlags(a, nullptr, flag); } } + +void SetNoSector(AActor* a) +{ + a->UnlinkFromWorld(nullptr); + a->flags |= MF_NOSECTOR; + a->LinkToWorld(nullptr); +} + +void ClearNoSector(AActor* a) +{ + a->UnlinkFromWorld(nullptr); + a->flags &= ~MF_NOSECTOR; + a->LinkToWorld(nullptr); +} + +void SetNoBlockmap(AActor* a) +{ + a->UnlinkFromWorld(nullptr); + a->flags |= MF_NOBLOCKMAP; + a->LinkToWorld(nullptr); +} + +void ClearNoBlockmap(AActor* a) +{ + a->UnlinkFromWorld(nullptr); + a->flags &= ~MF_NOBLOCKMAP; + a->LinkToWorld(nullptr); +} + +void SetCountkill(AActor* a) +{ + if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--; + a->flags |= MF_COUNTKILL; + if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++; +} + +void ClearCountkill(AActor* a) +{ + if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--; + a->flags &= ~MF_COUNTKILL; + if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++; +} + +void SetBoss(AActor* a) +{ + a->flags2 |= MF2_BOSS; + a->flags3 |= MF3_NORADIUSDMG; +} + +void ClearBoss(AActor* a) +{ + a->flags2 &= ~MF2_BOSS; + a->flags3 &= ~MF3_NORADIUSDMG; +} + +void SetCountitem(AActor* a) +{ + if (!(a->flags & MF_COUNTITEM)) + { + a->flags |= MF_COUNTITEM; + a->Level->total_items++; + } +} + +void ClearCountitem(AActor* a) +{ + if (a->flags & MF_COUNTITEM) + { + a->flags |= MF_COUNTITEM; + a->Level->total_items--; + } +} + +void SetFriendly(AActor* a) +{ + if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--; + a->flags |= MF_FRIENDLY; + if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++; +} + +void ClearFriendly(AActor* a) +{ + if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--; + a->flags &= ~MF_FRIENDLY; + if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++; +} + +void SetFullVol(AActor* a) +{ + a->flags8 |= MF8_FULLVOLSEE; + a->flags3 |= MF3_FULLVOLDEATH; +} + +void ClearFullVol(AActor* a) +{ + a->flags8 &= ~MF8_FULLVOLSEE; + a->flags3 &= ~MF3_FULLVOLDEATH; +} + +void SetTranslucent(AActor* a) +{ + a->RenderStyle = STYLE_Translucent; + a->Alpha = 0.5; + a->renderflags &= ~RF_ZDOOMTRANS; +} + +void ClearTranslucent(AActor* a) +{ + a->RenderStyle = STYLE_Normal; + a->Alpha = 1; + a->renderflags &= ~RF_ZDOOMTRANS; +} + +bool CheckTranslucent(AActor* a) +{ + // This is solely for MBF21. It will treat all objects with ZDOOMTRANS as non-translucent to ensure consistent results. + // This also means that all translucency changes via Dehacked need to clear this flag. + return !(a->renderflags & RF_ZDOOMTRANS) && a->Alpha < 1 - FLT_EPSILON; +} + +constexpr FTranslationID t1 = TRANSLATION(TRANSLATION_Standard, 0); +constexpr FTranslationID t2 = TRANSLATION(TRANSLATION_Standard, 1); +constexpr FTranslationID t3 = TRANSLATION(TRANSLATION_Standard, 2); + +void SetTranslation1(AActor* a) +{ + if (a->Translation == t2 || a->Translation == t3) a->Translation = t3; + else a->Translation = t1; +} + +void ClearTranslation1(AActor* a) +{ + if (a->Translation == t3 || a->Translation == t2) a->Translation = t2; + else a->Translation = NO_TRANSLATION; +} + +bool CheckTranslation1(AActor* a) +{ + return a->Translation == t1 || a->Translation == t3; +} + +void SetTranslation2(AActor* a) +{ + if (a->Translation == t1 || a->Translation == t3) a->Translation = t3; + else a->Translation = t2; +} + +void ClearTranslation2(AActor* a) +{ + if (a->Translation == t3 || a->Translation == t1) a->Translation = t1; + else a->Translation = NO_TRANSLATION; +} + +bool CheckTranslation2(AActor* a) +{ + return a->Translation == t2 || a->Translation == t3; +} + +// Bounces is very complex... +void SetBounces(AActor* info) +{ + info->flags6 |= MF6_VULNERABLE; + info->flags3 |= MF3_NOBLOCKMONST; + info->flags4 |= (MF4_FORCERADIUSDMG | MF4_DONTHARMCLASS); + info->effects &= ~FX_ROCKET; // disable rocket trail if set. + + if (info->flags & MF_MISSILE) info->BounceFlags = BOUNCE_Classic | BOUNCE_DEH; + else info->BounceFlags = BOUNCE_Grenade | BOUNCE_DEH; + +} + +void ClearBounces(AActor* info) +{ + info->flags6 &= ~MF6_VULNERABLE; + info->flags3 &= ~MF3_NOBLOCKMONST; + info->flags4 &= ~(MF4_FORCERADIUSDMG | MF4_DONTHARMCLASS); + info->BounceFlags = 0; +} + +// The missile flag affects the bouncing mode. +void SetMissile(AActor* info) +{ + info->flags |= MF_MISSILE; + info->flags2 |= MF2_NOTELEPORT | MF2_PCROSS | MF2_IMPACT; + if (info->BounceFlags & BOUNCE_DEH) info->BounceFlags = BOUNCE_Classic | BOUNCE_DEH; +} + +void ClearMissile(AActor* info) +{ + info->flags &= ~MF_MISSILE; + info->flags2 &= ~(MF2_NOTELEPORT | MF2_PCROSS | MF2_IMPACT); + if (info->BounceFlags & BOUNCE_DEH) info->BounceFlags = BOUNCE_Grenade | BOUNCE_DEH; +} + +void SetShadow(AActor* info) +{ + info->flags |= MF_SHADOW; + info->RenderStyle = LegacyRenderStyles[STYLE_OptFuzzy]; + info->renderflags &= ~RF_ZDOOMTRANS; +} + +void ClearShadow(AActor* info) +{ + info->flags &= ~MF_SHADOW; + info->RenderStyle = LegacyRenderStyles[info->Alpha >= 1 - FLT_EPSILON? STYLE_Normal : STYLE_Translucent]; + info->renderflags &= ~RF_ZDOOMTRANS; +} + +static FlagHandler flag1handlers[32] = { + F(MF_SPECIAL), + F(MF_SOLID), + F(MF_SHOOTABLE), + { SetNoSector, ClearNoSector, [](AActor* a)->bool { return a->flags & MF_NOSECTOR; } }, + { SetNoBlockmap, ClearNoBlockmap, [](AActor* a)->bool { return a->flags & MF_NOBLOCKMAP; } }, + F(MF_AMBUSH), + F(MF_JUSTHIT), + F(MF_JUSTATTACKED), + F(MF_SPAWNCEILING), + F(MF_NOGRAVITY), + F(MF_DROPOFF), + F(MF_PICKUP), + F(MF_NOCLIP), + F(MF_SLIDE), + F(MF_FLOAT), + F(MF_TELEPORT), + { SetMissile, ClearMissile, [](AActor* a)->bool { return a->flags & MF_MISSILE; } }, + F(MF_DROPPED), + { SetShadow, ClearShadow, [](AActor* a)->bool { return a->flags & MF_SHADOW; } }, + F(MF_NOBLOOD), + F(MF_CORPSE), + F(MF_INFLOAT), + { SetCountkill, ClearCountkill, [](AActor* a)->bool { return a->flags & MF_COUNTKILL; } }, + { SetCountitem, ClearCountitem, [](AActor* a)->bool { return a->flags & MF_COUNTITEM; } }, + F(MF_SKULLFLY), + F(MF_NOTDMATCH), + { SetTranslation1, ClearTranslation1, CheckTranslation1 }, + { SetTranslation2, ClearTranslation2, CheckTranslation2 }, + F6(MF6_TOUCHY), + { SetBounces, ClearBounces, [](AActor* a)->bool { return a->BounceFlags & BOUNCE_DEH; } }, + F(MF_FRIENDLY), + { SetTranslucent, ClearTranslucent, CheckTranslucent }, +}; + +static FlagHandler flag2handlers[32] = { + DEPF(DEPF_LOWGRAVITY), + DEPF(DEPF_SHORTMISSILERANGE), + F3(MF3_NOTARGET), + F3(MF3_NORADIUSDMG), + F4(MF4_FORCERADIUSDMG), + DEPF(DEPF_HIGHERMPROB), + F4(MF4_MISSILEMORE), + F4(MF4_QUICKTORETALIATE), + DEPF(DEPF_LONGMELEERANGE), + { SetBoss, ClearBoss, [](AActor* a)->bool { return a->flags2 & MF2_BOSS; } }, + F8(MF8_MAP07BOSS1), + F8(MF8_MAP07BOSS2), + F8(MF8_E1M8BOSS), + F8(MF8_E2M8BOSS), + F8(MF8_E3M8BOSS), + F8(MF8_E4M6BOSS), + F8(MF8_E4M8BOSS), + F2(MF2_RIP), + { SetFullVol, ClearFullVol, [](AActor* a)->bool { return a->flags8 & MF8_FULLVOLSEE; } }, // checking one of the two flags should suffice here. +}; + + +// +// A_JumpIfFlagsSet +// Jumps to a state if caller has the specified thing flags set. +// args[0]: State to jump to +// args[1]: Standard Flag(s) to check +// args[2]: MBF21 Flag(s) to check +// +DEFINE_ACTION_FUNCTION(AActor, MBF21_JumpIfFlagsSet) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(tstate, FState); + PARAM_INT(flags); + PARAM_INT(flags2); + + for (int i = 0; i < 32; i++) + { + if (flags & (1 << i) && flag1handlers[i].checker) + { + if (!flag1handlers[i].checker(self)) return 0; + } + if (flags2 & (1 << i) && flag2handlers[i].checker) + { + if (!flag2handlers[i].checker(self)) return 0; + } + } + self->SetState(tstate); + return 0; +} + +// +// A_AddFlags +// Adds the specified thing flags to the caller. +// args[0]: Standard Flag(s) to add +// args[1]: MBF21 Flag(s) to add +// +DEFINE_ACTION_FUNCTION(AActor, MBF21_AddFlags) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(flags); + PARAM_INT(flags2); + + for (int i = 0; i < 32; i++) + { + if (flags & (1 << i) && flag1handlers[i].setter) + { + flag1handlers[i].setter(self); + } + if (flags2 & (1 << i) && flag2handlers[i].setter) + { + flag2handlers[i].setter(self); + } + } + return 0; +} + +// +// A_RemoveFlags +// Removes the specified thing flags from the caller. +// args[0]: Flag(s) to remove +// args[1]: MBF21 Flag(s) to remove +// +DEFINE_ACTION_FUNCTION(AActor, MBF21_RemoveFlags) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(flags); + PARAM_INT(flags2); + + for (int i = 0; i < 32; i++) + { + if (flags & (1 << i) && flag1handlers[i].clearer) + { + flag1handlers[i].clearer(self); + } + if (flags2 & (1 << i) && flag2handlers[i].clearer) + { + flag2handlers[i].clearer(self); + } + } + return 0; +} diff --git a/src/gamedata/d_dehacked.h b/src/gamedata/d_dehacked.h index bb87993e9ab..44996494386 100644 --- a/src/gamedata/d_dehacked.h +++ b/src/gamedata/d_dehacked.h @@ -40,9 +40,14 @@ enum DehLumpSource FromPWADs }; -int D_LoadDehLumps(DehLumpSource source); -bool D_LoadDehLump(int lumpnum); -bool D_LoadDehFile(const char *filename); +enum DehFlags +{ + DEH_SKIP_BEX_STRINGS_IF_LANGUAGE = 1, +}; + +int D_LoadDehLumps(DehLumpSource source, int flags); +bool D_LoadDehLump(int lumpnum, int flags); +bool D_LoadDehFile(const char *filename, int flags); void FinishDehPatch (); #endif //__D_DEHACK_H__ diff --git a/src/gamedata/decallib.cpp b/src/gamedata/decallib.cpp index 6cfffb36763..8dee4e7fd4f 100644 --- a/src/gamedata/decallib.cpp +++ b/src/gamedata/decallib.cpp @@ -34,19 +34,20 @@ #include "decallib.h" #include "sc_man.h" -#include "w_wad.h" +#include "filesystem.h" #include "v_video.h" #include "cmdlib.h" #include "m_random.h" #include "weightedlist.h" #include "statnums.h" -#include "templates.h" + #include "a_sharedglobal.h" #include "gi.h" #include "b_bot.h" #include "serializer.h" #include "g_levellocals.h" #include "a_decalfx.h" +#include "texturemanager.h" FDecalLib DecalLibrary; @@ -91,7 +92,7 @@ struct FDecalLib::FTranslation uint32_t StartColor, EndColor; FTranslation *Next; - uint32_t Index; + FTranslationID Index; }; struct FDecalAnimator @@ -264,7 +265,7 @@ void FDecalLib::ReadAllDecals () DecalLibrary.Clear(); - while ((lump = Wads.FindLump ("DECALDEF", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("DECALDEF", &lastlump)) != -1) { FScanner sc(lump); ReadDecals (sc); @@ -283,7 +284,7 @@ void FDecalLib::ReadAllDecals () FName v = ENamedName(intptr_t(def->DecalGenerator)); if (v.IsValidName()) { - def->DecalGenerator = ScanTreeForName (v, Root); + def->DecalGenerator = ScanTreeForName (v.GetChars(), Root); } } } @@ -341,7 +342,7 @@ uint16_t FDecalLib::GetDecalID (FScanner &sc) } else { - unsigned long num = strtoul (sc.String, NULL, 10); + uint64_t num = strtoull (sc.String, NULL, 10); if (num < 1 || num > 65535) { sc.ScriptError ("Decal ID must be between 1 and 65535"); @@ -375,7 +376,7 @@ void FDecalLib::ParseDecal (FScanner &sc) sc.MustGetString (); if (sc.Compare ("}")) { - AddDecal (decalName, decalNum, newdecal); + AddDecal(decalName.GetChars(), decalNum, newdecal); break; } switch (sc.MustMatchString (DecalKeywords)) @@ -391,7 +392,7 @@ void FDecalLib::ParseDecal (FScanner &sc) case DECAL_PIC: sc.MustGetString (); picnum = TexMan.CheckForTexture (sc.String, ETextureType::Any); - if (!picnum.Exists() && (lumpnum = Wads.CheckNumForName (sc.String, ns_graphics)) >= 0) + if (!picnum.Exists() && (lumpnum = fileSystem.CheckNumForName (sc.String, FileSys::ns_graphics)) >= 0) { picnum = TexMan.CreateTexture (lumpnum, ETextureType::Decal); } @@ -442,7 +443,7 @@ void FDecalLib::ParseDecal (FScanner &sc) sc.MustGetString (); if (!sc.Compare("BloodDefault")) { - newdecal.ShadeColor = V_GetColor (NULL, sc); + newdecal.ShadeColor = V_GetColor (sc); } else { @@ -457,8 +458,8 @@ void FDecalLib::ParseDecal (FScanner &sc) case DECAL_COLORS: uint32_t startcolor, endcolor; - sc.MustGetString (); startcolor = V_GetColor (NULL, sc); - sc.MustGetString (); endcolor = V_GetColor (NULL, sc); + sc.MustGetString (); startcolor = V_GetColor (sc); + sc.MustGetString (); endcolor = V_GetColor (sc); newdecal.Translation = GenerateTranslation (startcolor, endcolor)->Index; break; @@ -576,7 +577,7 @@ void FDecalLib::ParseFader (FScanner &sc) sc.MustGetString (); if (sc.Compare ("}")) { - FDecalFaderAnim *fader = new FDecalFaderAnim (faderName); + FDecalFaderAnim *fader = new FDecalFaderAnim (faderName.GetChars()); fader->DecayStart = startTime; fader->DecayTime = decayTime; Animators.Push (fader); @@ -616,7 +617,7 @@ void FDecalLib::ParseStretcher (FScanner &sc) { if (goalX >= 0 || goalY >= 0) { - FDecalStretcherAnim *stretcher = new FDecalStretcherAnim (stretcherName); + FDecalStretcherAnim *stretcher = new FDecalStretcherAnim (stretcherName.GetChars()); stretcher->StretchStart = startTime; stretcher->StretchTime = takeTime; stretcher->GoalX = goalX; @@ -667,7 +668,7 @@ void FDecalLib::ParseSlider (FScanner &sc) { if ((/*distX |*/ distY) != 0) { - FDecalSliderAnim *slider = new FDecalSliderAnim (sliderName); + FDecalSliderAnim *slider = new FDecalSliderAnim (sliderName.GetChars()); slider->SlideStart = startTime; slider->SlideTime = takeTime; /*slider->DistX = distX;*/ @@ -718,7 +719,7 @@ void FDecalLib::ParseColorchanger (FScanner &sc) sc.MustGetString (); if (sc.Compare ("}")) { - FDecalColorerAnim *fader = new FDecalColorerAnim (faderName); + FDecalColorerAnim *fader = new FDecalColorerAnim (faderName.GetChars()); fader->DecayStart = startTime; fader->DecayTime = decayTime; fader->GoalColor = goal; @@ -738,7 +739,7 @@ void FDecalLib::ParseColorchanger (FScanner &sc) else if (sc.Compare ("Color")) { sc.MustGetString (); - goal = V_GetColor (NULL, sc); + goal = V_GetColor (sc); } else { @@ -771,7 +772,7 @@ void FDecalLib::ParseCombiner (FScanner &sc) if (last > first) { - FDecalCombinerAnim *combiner = new FDecalCombinerAnim (combinerName); + FDecalCombinerAnim *combiner = new FDecalCombinerAnim (combinerName.GetChars()); combiner->FirstAnimator = (int)first; combiner->NumAnimators = (int)(last - first); Animators.Push (combiner); @@ -809,7 +810,7 @@ void FDecalLib::AddDecal (FDecalBase *decal) // Check if this decal already exists. while (node != NULL) { - int lexx = stricmp (decal->Name, node->Name); + int lexx = stricmp (decal->Name.GetChars(), node->Name.GetChars()); if (lexx == 0) { break; @@ -885,7 +886,7 @@ const FDecalTemplate *FDecalLib::GetDecalByName (const char *name) const FDecalBase *base = ScanTreeForName (name, Root); if (base != NULL) { - return static_cast(base); + return base->GetDecal(); } return NULL; } @@ -910,7 +911,7 @@ FDecalBase *FDecalLib::ScanTreeForName (const char *name, FDecalBase *root) { while (root != NULL) { - int lexx = stricmp (name, root->Name); + int lexx = stricmp (name, root->Name.GetChars()); if (lexx == 0) { break; @@ -1001,7 +1002,7 @@ FDecalLib::FTranslation::FTranslation (uint32_t start, uint32_t end) if (DecalTranslations.Size() == 256*256) { Printf ("Too many decal translations defined\n"); - Index = 0; + Index = NO_TRANSLATION; return; } @@ -1027,7 +1028,7 @@ FDecalLib::FTranslation::FTranslation (uint32_t start, uint32_t end) table[i] = ColorMatcher.Pick (ri >> 24, gi >> 24, bi >> 24); } table[0] = table[1]; - Index = (uint32_t)TRANSLATION(TRANSLATION_Decals, tablei >> 8); + Index = TRANSLATION(TRANSLATION_Decals, tablei >> 8); } FDecalLib::FTranslation *FDecalLib::FTranslation::LocateTranslation (uint32_t start, uint32_t end) @@ -1145,7 +1146,7 @@ FDecalAnimator *FDecalLib::FindAnimator (const char *name) for (i = (int)Animators.Size ()-1; i >= 0; --i) { - if (stricmp (name, Animators[i]->Name) == 0) + if (stricmp (name, Animators[i]->Name.GetChars()) == 0) { return Animators[i]; } diff --git a/src/gamedata/decallib.h b/src/gamedata/decallib.h index 04c0ea0e682..d077c6c4605 100644 --- a/src/gamedata/decallib.h +++ b/src/gamedata/decallib.h @@ -37,7 +37,8 @@ #include #include "doomtype.h" -#include "r_data/renderstyle.h" +#include "renderstyle.h" +#include "palettecontainer.h" class FScanner; class FDecalTemplate; @@ -67,7 +68,7 @@ class FDecalTemplate : public FDecalBase { friend class FDecalLib; public: - FDecalTemplate () : Translation (0) {} + FDecalTemplate () : Translation (NO_TRANSLATION) {} void ApplyToDecal (DBaseDecal *actor, side_t *wall) const; const FDecalTemplate *GetDecal () const; @@ -75,7 +76,7 @@ class FDecalTemplate : public FDecalBase double ScaleX, ScaleY; uint32_t ShadeColor; - uint32_t Translation; + FTranslationID Translation; FRenderStyle RenderStyle; FTextureID PicNum; uint16_t RenderFlags; diff --git a/src/gamedata/doomfont.h b/src/gamedata/doomfont.h new file mode 100644 index 00000000000..fedeb513c4c --- /dev/null +++ b/src/gamedata/doomfont.h @@ -0,0 +1,148 @@ +// +// Globally visible constants. +// +#pragma once +#define HU_FONTSTART uint8_t('!') // the first font characters +#define HU_FONTEND uint8_t('\377') // the last font characters + +// Calculate # of glyphs in font. +#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) + + + +void InitDoomFonts() +{ + // load the heads-up font + if (!(SmallFont = V_GetFont("SmallFont", "SMALLFNT"))) + { + if (fileSystem.CheckNumForName("FONTA_S") >= 0) + { + int wadfile = -1; + auto a = fileSystem.CheckNumForName("FONTA33", FileSys::ns_graphics); + if (a != -1) wadfile = fileSystem.GetFileContainer(a); + if (wadfile > fileSystem.GetIwadNum()) + { + // The font has been replaced, so we need to create a copy of the original as well. + SmallFont = new FFont("SmallFont", "FONTA%02u", nullptr, HU_FONTSTART, HU_FONTSIZE, 1, -1); + SmallFont->SetCursor('['); + } + else + { + SmallFont = new FFont("SmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1); + SmallFont->SetCursor('['); + } + } + else if (fileSystem.CheckNumForName("STCFN033", FileSys::ns_graphics) >= 0) + { + int wadfile = -1; + auto a = fileSystem.CheckNumForName("STCFN065", FileSys::ns_graphics); + if (a != -1) wadfile = fileSystem.GetFileContainer(a); + if (wadfile > fileSystem.GetIwadNum()) + { + // The font has been replaced, so we need to create a copy of the original as well. + SmallFont = new FFont("SmallFont", "STCFN%.3d", nullptr, HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, false, true); + } + else + { + SmallFont = new FFont("SmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, false, true); + } + } + } + + // Create the original small font as a fallback for incomplete definitions. + if (fileSystem.CheckNumForName("FONTA_S") >= 0) + { + OriginalSmallFont = new FFont("OriginalSmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); + OriginalSmallFont->SetCursor('['); + } + else if (fileSystem.CheckNumForName("STCFN033", FileSys::ns_graphics) >= 0) + { + OriginalSmallFont = new FFont("OriginalSmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, true, true); + } + + + if (!(SmallFont2 = V_GetFont("SmallFont2"))) // Only used by Strife + { + if (fileSystem.CheckNumForName("STBFN033", FileSys::ns_graphics) >= 0) + { + SmallFont2 = new FFont("SmallFont2", "STBFN%.3d", "defsmallfont2", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); + } + } + + //This must be read before BigFont so that it can be properly substituted. + BigUpper = V_GetFont("BigUpper"); + + if (!(BigFont = V_GetFont("BigFont"))) + { + if (fileSystem.CheckNumForName("FONTB_S") >= 0) + { + BigFont = new FFont("BigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1); + } + } + + if (!BigFont) + { + // Load the generic fallback if no BigFont is found. + BigFont = V_GetFont("BigFont", "ZBIGFONT"); + } + + if (fileSystem.CheckNumForName("FONTB_S") >= 0) + { + OriginalBigFont = new FFont("OriginalBigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); + } + else + { + OriginalBigFont = new FFont("OriginalBigFont", nullptr, "bigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); + } + + // let PWAD BIGFONTs override the stock BIGUPPER font. (This check needs to be made smarter.) + if (BigUpper && BigFont->GetType() != FFont::Folder && BigUpper->GetType() == FFont::Folder) + { + delete BigUpper; + BigUpper = BigFont; + } + + if (BigUpper == nullptr) + { + BigUpper = BigFont; + } + if (!ConFont) + { + ConFont = SmallFont; + } + if (!(IntermissionFont = FFont::FindFont("IntermissionFont"))) + { + if (TexMan.CheckForTexture("WINUM0", ETextureType::MiscPatch).isValid()) + { + IntermissionFont = FFont::FindFont("IntermissionFont_Doom"); + } + if (IntermissionFont == nullptr) + { + IntermissionFont = BigFont; + } + } + // This can only happen if gzdoom.pk3 is corrupted. ConFont should always be present. + if (ConFont == nullptr) + { + I_FatalError("Console font not found."); + } + // SmallFont and SmallFont2 have no default provided by the engine. BigFont only has in non-Raven games. + if (OriginalSmallFont == nullptr) + { + OriginalSmallFont = ConFont; + } + if (SmallFont == nullptr) + { + SmallFont = OriginalSmallFont; + } + if (SmallFont2 == nullptr) + { + SmallFont2 = SmallFont; + } + if (BigFont == nullptr) + { + BigFont = OriginalBigFont; + } + AlternativeSmallFont = OriginalSmallFont; + AlternativeBigFont = OriginalBigFont; +} diff --git a/src/gamedata/fonts/font.cpp b/src/gamedata/fonts/font.cpp deleted file mode 100644 index 85053ad3226..00000000000 --- a/src/gamedata/fonts/font.cpp +++ /dev/null @@ -1,1278 +0,0 @@ -/* -** v_font.cpp -** Font management -** -**--------------------------------------------------------------------------- -** Copyright 1998-2016 Randy Heit -** Copyright 2005-2019 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include - -#include "templates.h" -#include "doomtype.h" -#include "m_swap.h" -#include "v_font.h" -#include "v_video.h" -#include "w_wad.h" -#include "gi.h" -#include "cmdlib.h" -#include "sc_man.h" -#include "hu_stuff.h" -#include "gstrings.h" -#include "v_text.h" -#include "vm.h" -#include "image.h" -#include "utf8.h" -#include "myiswalpha.h" -#include "textures/formats/fontchars.h" -#include "textures/formats/multipatchtexture.h" - -#include "fontinternals.h" - - - -//========================================================================== -// -// FFont :: FFont -// -// Loads a multi-texture font. -// -//========================================================================== - -FFont::FFont (const char *name, const char *nametemplate, const char *filetemplate, int lfirst, int lcount, int start, int fdlump, int spacewidth, bool notranslate, bool iwadonly) -{ - int i; - FTextureID lump; - char buffer[12]; - int maxyoffs; - bool doomtemplate = (nametemplate && (gameinfo.gametype & GAME_DoomChex)) ? strncmp (nametemplate, "STCFN", 5) == 0 : false; - DVector2 Scale = { 1, 1 }; - - noTranslate = notranslate; - Lump = fdlump; - GlobalKerning = false; - FontName = name; - Next = FirstFont; - FirstFont = this; - Cursor = '_'; - ActiveColors = 0; - SpaceWidth = 0; - FontHeight = 0; - uint8_t pp = 0; - for (auto &p : PatchRemap) p = pp++; - translateUntranslated = false; - int FixedWidth = 0; - - maxyoffs = 0; - - TMap charMap; - int minchar = INT_MAX; - int maxchar = INT_MIN; - - // Read the font's configuration. - // This will not be done for the default fonts, because they are not atomic and the default content does not need it. - - TArray folderdata; - if (filetemplate != nullptr) - { - FStringf path("fonts/%s/", filetemplate); - // If a name template is given, collect data from all resource files. - // For anything else, each folder is being treated as an atomic, self-contained unit and mixing from different glyph sets is blocked. - Wads.GetLumpsInFolder(path, folderdata, nametemplate == nullptr); - - //if (nametemplate == nullptr) - { - FStringf infpath("fonts/%s/font.inf", filetemplate); - - unsigned index = folderdata.FindEx([=](const FolderEntry &entry) - { - return infpath.CompareNoCase(entry.name) == 0; - }); - - if (index < folderdata.Size()) - { - FScanner sc; - sc.OpenLumpNum(folderdata[index].lumpnum); - while (sc.GetToken()) - { - sc.TokenMustBe(TK_Identifier); - if (sc.Compare("Kerning")) - { - sc.MustGetValue(false); - GlobalKerning = sc.Number; - } - else if (sc.Compare("Scale")) - { - sc.MustGetValue(true); - Scale.Y = Scale.X = sc.Float; - if (sc.CheckToken(',')) - { - sc.MustGetValue(true); - Scale.Y = sc.Float; - } - } - else if (sc.Compare("SpaceWidth")) - { - sc.MustGetValue(false); - SpaceWidth = sc.Number; - } - else if (sc.Compare("FontHeight")) - { - sc.MustGetValue(false); - FontHeight = sc.Number; - } - else if (sc.Compare("CellSize")) - { - sc.MustGetValue(false); - FixedWidth = sc.Number; - sc.MustGetToken(','); - sc.MustGetValue(false); - FontHeight = sc.Number; - } - else if (sc.Compare("Translationtype")) - { - sc.MustGetToken(TK_Identifier); - if (sc.Compare("console")) - { - TranslationType = 1; - } - else if (sc.Compare("standard")) - { - TranslationType = 0; - } - else - { - sc.ScriptError("Unknown translation type %s", sc.String); - } - } - } - } - } - } - - if (FixedWidth > 0) - { - ReadSheetFont(folderdata, FixedWidth, FontHeight, Scale); - Type = Folder; - } - else - { - if (nametemplate != nullptr) - { - if (!iwadonly) - { - for (i = 0; i < lcount; i++) - { - int position = lfirst + i; - mysnprintf(buffer, countof(buffer), nametemplate, i + start); - - lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch); - if (doomtemplate && lump.isValid() && i + start == 121) - { // HACKHACK: Don't load STCFN121 in doom(2), because - // it's not really a lower-case 'y' but a '|'. - // Because a lot of wads with their own font seem to foolishly - // copy STCFN121 and make it a '|' themselves, wads must - // provide STCFN120 (x) and STCFN122 (z) for STCFN121 to load as a 'y'. - if (!TexMan.CheckForTexture("STCFN120", ETextureType::MiscPatch).isValid() || - !TexMan.CheckForTexture("STCFN122", ETextureType::MiscPatch).isValid()) - { - // insert the incorrectly named '|' graphic in its correct position. - position = 124; - } - } - if (lump.isValid()) - { - Type = Multilump; - if (position < minchar) minchar = position; - if (position > maxchar) maxchar = position; - charMap.Insert(position, TexMan.GetTexture(lump)); - } - } - } - else - { - FTexture *texs[256] = {}; - if (lcount > 256 - start) lcount = 256 - start; - for (i = 0; i < lcount; i++) - { - TArray array; - mysnprintf(buffer, countof(buffer), nametemplate, i + start); - - TexMan.ListTextures(buffer, array, true); - for (auto entry : array) - { - FTexture *tex = TexMan.GetTexture(entry, false); - if (tex && tex->SourceLump >= 0 && Wads.GetLumpFile(tex->SourceLump) <= Wads.GetMaxIwadNum() && tex->UseType == ETextureType::MiscPatch) - { - texs[i] = tex; - } - } - } - if (doomtemplate) - { - // Handle the misplaced '|'. - if (texs[121 - '!'] && !texs[120 - '!'] && !texs[122 - '!'] && !texs[124 - '!']) - { - texs[124 - '!'] = texs[121 - '!']; - texs[121 - '!'] = nullptr; - } - } - - for (i = 0; i < lcount; i++) - { - if (texs[i]) - { - int position = lfirst + i; - Type = Multilump; - if (position < minchar) minchar = position; - if (position > maxchar) maxchar = position; - charMap.Insert(position, texs[i]); - } - } - } - } - if (folderdata.Size() > 0) - { - // all valid lumps must be named with a hex number that represents its Unicode character index. - for (auto &entry : folderdata) - { - char *endp; - auto base = ExtractFileBase(entry.name); - auto position = strtoll(base.GetChars(), &endp, 16); - if ((*endp == 0 || (*endp == '.' && position >= '!' && position < 0xffff))) - { - auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); - if (lump.isValid()) - { - if ((int)position < minchar) minchar = (int)position; - if ((int)position > maxchar) maxchar = (int)position; - auto tex = TexMan.GetTexture(lump); - tex->SetScale(Scale); - charMap.Insert((int)position, tex); - Type = Folder; - } - } - } - } - FirstChar = minchar; - LastChar = maxchar; - auto count = maxchar - minchar + 1; - Chars.Resize(count); - int fontheight = 0; - int asciiheight = 0; - - for (i = 0; i < count; i++) - { - auto lump = charMap.CheckKey(FirstChar + i); - if (lump != nullptr) - { - FTexture *pic = *lump; - if (pic != nullptr) - { - int height = pic->GetDisplayHeight(); - int yoffs = pic->GetDisplayTopOffset(); - - if (yoffs > maxyoffs) - { - maxyoffs = yoffs; - } - height += abs(yoffs); - if (height > fontheight) - { - fontheight = height; - } - if (height > asciiheight && FirstChar + 1 < 128) - { - asciiheight = height; - } - } - - Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); - Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); - Chars[i].OriginalPic->CopySize(pic); - TexMan.AddTexture(Chars[i].OriginalPic); - - if (!noTranslate) - { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), ""); - Chars[i].TranslatedPic->CopySize(pic); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - TexMan.AddTexture(Chars[i].TranslatedPic); - } - else - { - Chars[i].TranslatedPic = Chars[i].OriginalPic; - } - - Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); - } - else - { - Chars[i].TranslatedPic = nullptr; - Chars[i].XMove = INT_MIN; - } - } - - if (SpaceWidth == 0) // An explicit override from the .inf file must always take precedence - { - if (spacewidth != -1) - { - SpaceWidth = spacewidth; - } - else if ('N' - FirstChar >= 0 && 'N' - FirstChar < count && Chars['N' - FirstChar].TranslatedPic != nullptr) - { - SpaceWidth = (Chars['N' - FirstChar].XMove + 1) / 2; - } - else - { - SpaceWidth = 4; - } - } - if (FontHeight == 0) FontHeight = fontheight; - if (AsciiHeight == 0) AsciiHeight = asciiheight; - - FixXMoves(); - } - - if (!noTranslate) LoadTranslations(); - - -} - -void FFont::ReadSheetFont(TArray &folderdata, int width, int height, const DVector2 &Scale) -{ - // all valid lumps must be named with a hex number that represents the Unicode character index for its first character, - TArray part(1, true); - TMap charMap; - int minchar = INT_MAX; - int maxchar = INT_MIN; - for (auto &entry : folderdata) - { - char *endp; - auto base = ExtractFileBase(entry.name); - auto position = strtoll(base.GetChars(), &endp, 16); - if ((*endp == 0 || (*endp == '.' && position >= 0 && position < 0xffff))) // Sheet fonts may fill in the low control chars. - { - auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); - if (lump.isValid()) - { - auto tex = TexMan.GetTexture(lump); - int numtex_x = tex->GetWidth() / width; - int numtex_y = tex->GetHeight() / height; - int maxinsheet = int(position) + numtex_x * numtex_y - 1; - if (minchar > position) minchar = int(position); - if (maxchar < maxinsheet) maxchar = maxinsheet; - - for (int y = 0; y < numtex_y; y++) - { - for (int x = 0; x < numtex_x; x++) - { - part[0].OriginX = -width * x; - part[0].OriginY = -height * y; - part[0].Image = tex->GetImage(); - FMultiPatchTexture *image = new FMultiPatchTexture(width, height, part, false, false); - FImageTexture *tex = new FImageTexture(image, ""); - tex->SetUseType(ETextureType::FontChar); - tex->bMultiPatch = true; - tex->Width = width; - tex->Height = height; - tex->_LeftOffset[0] = - tex->_LeftOffset[1] = - tex->_TopOffset[0] = - tex->_TopOffset[1] = 0; - tex->Scale = Scale; - tex->bMasked = true; - tex->bTranslucent = -1; - tex->bWorldPanning = true; - tex->bNoDecals = false; - tex->SourceLump = -1; // We do not really care. - TexMan.AddTexture(tex); - charMap.Insert(int(position) + x + y * numtex_x, tex); - } - } - } - } - } - - - FirstChar = minchar; - bool map1252 = false; - if (minchar < 0x80 && maxchar >= 0xa0) // should be a settable option, but that'd probably cause more problems than it'd solve. - { - if (maxchar < 0x2122) maxchar = 0x2122; - map1252 = true; - } - LastChar = maxchar; - auto count = maxchar - minchar + 1; - Chars.Resize(count); - int fontheight = 0; - - for (int i = 0; i < count; i++) - { - auto lump = charMap.CheckKey(FirstChar + i); - if (lump != nullptr) - { - FTexture *pic = *lump; - - auto b = pic->Get8BitPixels(false); - - Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); - Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); - Chars[i].OriginalPic->CopySize(pic); - Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), ""); - Chars[i].TranslatedPic->CopySize(pic); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - TexMan.AddTexture(Chars[i].OriginalPic); - TexMan.AddTexture(Chars[i].TranslatedPic); - } - Chars[i].XMove = width; - } - - if (map1252) - { - // Move the Windows-1252 characters to their proper place. - for (int i = 0x80; i < 0xa0; i++) - { - if (win1252map[i - 0x80] != i && Chars[i - minchar].TranslatedPic != nullptr && Chars[win1252map[i - 0x80] - minchar].TranslatedPic == nullptr) - { - std::swap(Chars[i - minchar], Chars[win1252map[i - 0x80] - minchar]); - } - } - } - - SpaceWidth = width; -} - -//========================================================================== -// -// FFont :: ~FFont -// -//========================================================================== - -FFont::~FFont () -{ - FFont **prev = &FirstFont; - FFont *font = *prev; - - while (font != nullptr && font != this) - { - prev = &font->Next; - font = *prev; - } - - if (font != nullptr) - { - *prev = font->Next; - } -} - -//========================================================================== -// -// FFont :: CheckCase -// -//========================================================================== - -void FFont::CheckCase() -{ - int lowercount = 0, uppercount = 0; - for (unsigned i = 0; i < Chars.Size(); i++) - { - unsigned chr = i + FirstChar; - if (lowerforupper[chr] == chr && upperforlower[chr] == chr) - { - continue; // not a letter; - } - if (myislower(chr)) - { - if (Chars[i].TranslatedPic != nullptr) lowercount++; - } - else - { - if (Chars[i].TranslatedPic != nullptr) uppercount++; - } - } - if (lowercount == 0) return; // This is an uppercase-only font and we are done. - - // The ß needs special treatment because it is far more likely to be supplied lowercase only, even in an uppercase font. - if (Chars[0xdf - FirstChar].TranslatedPic != nullptr) - { - if (LastChar < 0x1e9e) - { - Chars.Resize(0x1e9f - FirstChar); - LastChar = 0x1e9e; - } - if (Chars[0x1e9e - FirstChar].TranslatedPic == nullptr) - { - std::swap(Chars[0xdf - FirstChar], Chars[0x1e9e - FirstChar]); - lowercount--; - uppercount++; - if (lowercount == 0) return; - } - } -} - -//========================================================================== -// -// FFont :: FindFont -// -// Searches for the named font in the list of loaded fonts, returning the -// font if it was found. The disk is not checked if it cannot be found. -// -//========================================================================== - -FFont *FFont::FindFont (FName name) -{ - if (name == NAME_None) - { - return nullptr; - } - FFont *font = FirstFont; - - while (font != nullptr) - { - if (font->FontName == name) return font; - font = font->Next; - } - return nullptr; -} - -//========================================================================== -// -// RecordTextureColors -// -// Given a 256 entry buffer, sets every entry that corresponds to a color -// used by the texture to 1. -// -//========================================================================== - -void RecordTextureColors (FImageSource *pic, uint32_t *usedcolors) -{ - int x; - - auto pixels = pic->GetPalettedPixels(false); - auto size = pic->GetWidth() * pic->GetHeight(); - - for(x = 0;x < size; x++) - { - usedcolors[pixels[x]]++; - } -} - -//========================================================================== -// -// RecordAllTextureColors -// -// Given a 256 entry buffer, sets every entry that corresponds to a color -// used by the font. -// -//========================================================================== - -void FFont::RecordAllTextureColors(uint32_t *usedcolors) -{ - for (unsigned int i = 0; i < Chars.Size(); i++) - { - if (Chars[i].TranslatedPic) - { - FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); - if (pic) - { - // The remap must be temporarily reset here because this can be called on an initialized font. - auto sr = pic->ResetSourceRemap(); - RecordTextureColors(pic, usedcolors); - pic->SetSourceRemap(sr); - } - } - } -} - -//========================================================================== -// -// SetDefaultTranslation -// -// Builds a translation to map the stock font to a mod provided replacement. -// -//========================================================================== - -void FFont::SetDefaultTranslation(uint32_t *othercolors) -{ - uint32_t mycolors[256] = {}; - RecordAllTextureColors(mycolors); - - uint8_t mytranslation[256], othertranslation[256], myreverse[256], otherreverse[256]; - TArray myluminosity, otherluminosity; - - SimpleTranslation(mycolors, mytranslation, myreverse, myluminosity); - SimpleTranslation(othercolors, othertranslation, otherreverse, otherluminosity); - - FRemapTable remap(ActiveColors); - remap.Remap[0] = 0; - remap.Palette[0] = 0; - - for (unsigned l = 1; l < myluminosity.Size(); l++) - { - for (unsigned o = 1; o < otherluminosity.Size()-1; o++) // luminosity[0] is for the transparent color - { - if (myluminosity[l] >= otherluminosity[o] && myluminosity[l] <= otherluminosity[o+1]) - { - PalEntry color1 = GPalette.BaseColors[otherreverse[o]]; - PalEntry color2 = GPalette.BaseColors[otherreverse[o+1]]; - double weight = 0; - if (otherluminosity[o] != otherluminosity[o + 1]) - { - weight = (myluminosity[l] - otherluminosity[o]) / (otherluminosity[o + 1] - otherluminosity[o]); - } - int r = int(color1.r + weight * (color2.r - color1.r)); - int g = int(color1.g + weight * (color2.g - color1.g)); - int b = int(color1.b + weight * (color2.b - color1.b)); - - r = clamp(r, 0, 255); - g = clamp(g, 0, 255); - b = clamp(b, 0, 255); - remap.Remap[l] = ColorMatcher.Pick(r, g, b); - remap.Palette[l] = PalEntry(255, r, g, b); - break; - } - } - } - Translations[CR_UNTRANSLATED] = remap.StoreTranslation(TRANSLATION_Font); - forceremap = true; -} - - -//========================================================================== -// -// compare -// -// Used for sorting colors by brightness. -// -//========================================================================== - -static int compare (const void *arg1, const void *arg2) -{ - if (RPART(GPalette.BaseColors[*((uint8_t *)arg1)]) * 299 + - GPART(GPalette.BaseColors[*((uint8_t *)arg1)]) * 587 + - BPART(GPalette.BaseColors[*((uint8_t *)arg1)]) * 114 < - RPART(GPalette.BaseColors[*((uint8_t *)arg2)]) * 299 + - GPART(GPalette.BaseColors[*((uint8_t *)arg2)]) * 587 + - BPART(GPalette.BaseColors[*((uint8_t *)arg2)]) * 114) - return -1; - else - return 1; -} - -//========================================================================== -// -// FFont :: SimpleTranslation -// -// Colorsused, translation, and reverse must all be 256 entry buffers. -// Colorsused must already be filled out. -// Translation be set to remap the source colors to a new range of -// consecutive colors based at 1 (0 is transparent). -// Reverse will be just the opposite of translation: It maps the new color -// range to the original colors. -// *Luminosity will be an array just large enough to hold the brightness -// levels of all the used colors, in consecutive order. It is sorted from -// darkest to lightest and scaled such that the darkest color is 0.0 and -// the brightest color is 1.0. -// The return value is the number of used colors and thus the number of -// entries in *luminosity. -// -//========================================================================== - -int FFont::SimpleTranslation (uint32_t *colorsused, uint8_t *translation, uint8_t *reverse, TArray &Luminosity) -{ - double min, max, diver; - int i, j; - - memset (translation, 0, 256); - - reverse[0] = 0; - for (i = 1, j = 1; i < 256; i++) - { - if (colorsused[i]) - { - reverse[j++] = i; - } - } - - qsort (reverse+1, j-1, 1, compare); - - Luminosity.Resize(j); - Luminosity[0] = 0.0; // [BL] Prevent uninitalized memory - max = 0.0; - min = 100000000.0; - for (i = 1; i < j; i++) - { - translation[reverse[i]] = i; - - Luminosity[i] = RPART(GPalette.BaseColors[reverse[i]]) * 0.299 + - GPART(GPalette.BaseColors[reverse[i]]) * 0.587 + - BPART(GPalette.BaseColors[reverse[i]]) * 0.114; - if (Luminosity[i] > max) - max = Luminosity[i]; - if (Luminosity[i] < min) - min = Luminosity[i]; - } - diver = 1.0 / (max - min); - for (i = 1; i < j; i++) - { - Luminosity[i] = (Luminosity[i] - min) * diver; - } - - return j; -} - -//========================================================================== -// -// FFont :: BuildTranslations -// -// Build color translations for this font. Luminosity is an array of -// brightness levels. The ActiveColors member must be set to indicate how -// large this array is. Identity is an array that remaps the colors to -// their original values; it is only used for CR_UNTRANSLATED. Ranges -// is an array of TranslationParm structs defining the ranges for every -// possible color, in order. Palette is the colors to use for the -// untranslated version of the font. -// -//========================================================================== - -void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity, - const void *ranges, int total_colors, const PalEntry *palette, std::function post) -{ - int i, j; - const TranslationParm *parmstart = (const TranslationParm *)ranges; - - FRemapTable remap(total_colors); - - // Create different translations for different color ranges - Translations.Clear(); - for (i = 0; i < NumTextColors; i++) - { - if (i == CR_UNTRANSLATED) - { - if (identity != nullptr) - { - memcpy(remap.Remap, identity, ActiveColors); - if (palette != nullptr) - { - memcpy(remap.Palette, palette, ActiveColors * sizeof(PalEntry)); - } - else - { - remap.Palette[0] = GPalette.BaseColors[identity[0]] & MAKEARGB(0, 255, 255, 255); - for (j = 1; j < ActiveColors; ++j) - { - remap.Palette[j] = GPalette.BaseColors[identity[j]] | MAKEARGB(255, 0, 0, 0); - } - } - Translations.Push(remap.StoreTranslation(TRANSLATION_Font)); - } - else - { - Translations.Push(Translations[0]); - } - continue; - } - - assert(parmstart->RangeStart >= 0); - - remap.Remap[0] = 0; - remap.Palette[0] = 0; - - for (j = 1; j < ActiveColors; j++) - { - int v = int(luminosity[j] * 256.0); - - // Find the color range that this luminosity value lies within. - const TranslationParm *parms = parmstart - 1; - do - { - parms++; - if (parms->RangeStart <= v && parms->RangeEnd >= v) - break; - } - while (parms[1].RangeStart > parms[0].RangeEnd); - - // Linearly interpolate to find out which color this luminosity level gets. - int rangev = ((v - parms->RangeStart) << 8) / (parms->RangeEnd - parms->RangeStart); - int r = ((parms->Start[0] << 8) + rangev * (parms->End[0] - parms->Start[0])) >> 8; // red - int g = ((parms->Start[1] << 8) + rangev * (parms->End[1] - parms->Start[1])) >> 8; // green - int b = ((parms->Start[2] << 8) + rangev * (parms->End[2] - parms->Start[2])) >> 8; // blue - r = clamp(r, 0, 255); - g = clamp(g, 0, 255); - b = clamp(b, 0, 255); - remap.Remap[j] = ColorMatcher.Pick(r, g, b); - remap.Palette[j] = PalEntry(255,r,g,b); - } - if (post) post(&remap); - Translations.Push(remap.StoreTranslation(TRANSLATION_Font)); - - // Advance to the next color range. - while (parmstart[1].RangeStart > parmstart[0].RangeEnd) - { - parmstart++; - } - parmstart++; - } -} - -//========================================================================== -// -// FFont :: GetColorTranslation -// -//========================================================================== - -int FFont::GetColorTranslation (EColorRange range, PalEntry *color) const -{ - if (noTranslate) - { - PalEntry retcolor = PalEntry(255, 255, 255, 255); - if (range >= 0 && range < NumTextColors && range != CR_UNTRANSLATED) - { - retcolor = TranslationColors[range]; - retcolor.a = 255; - } - if (color != nullptr) *color = retcolor; - } - if (ActiveColors == 0) - return -1; - else if (range >= NumTextColors) - range = CR_UNTRANSLATED; - //if (range == CR_UNTRANSLATED && !translateUntranslated) return nullptr; - return Translations[range]; -} - -//========================================================================== -// -// FFont :: GetCharCode -// -// If the character code is in the font, returns it. If it is not, but it -// is lowercase and has an uppercase variant present, return that. Otherwise -// return -1. -// -//========================================================================== - -int FFont::GetCharCode(int code, bool needpic) const -{ - if (code < 0 && code >= -128) - { - // regular chars turn negative when the 8th bit is set. - code &= 255; - } - if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) - { - return code; - } - - // Use different substitution logic based on the fonts content: - // In a font which has both upper and lower case, prefer unaccented small characters over capital ones. - // In a pure upper-case font, do not check for lower case replacements. - if (!MixedCase) - { - // Try converting lowercase characters to uppercase. - if (myislower(code)) - { - code = upperforlower[code]; - if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) - { - return code; - } - } - // Try stripping accents from accented characters. - int newcode = stripaccent(code); - if (newcode != code) - { - code = newcode; - if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) - { - return code; - } - } - } - else - { - int originalcode = code; - int newcode; - - // Try stripping accents from accented characters. This may repeat to allow multi-step fallbacks. - while ((newcode = stripaccent(code)) != code) - { - code = newcode; - if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) - { - return code; - } - } - - code = originalcode; - if (myislower(code)) - { - int upper = upperforlower[code]; - // Stripping accents did not help - now try uppercase for lowercase - if (upper != code) return GetCharCode(upper, needpic); - } - - // Same for the uppercase character. Since we restart at the accented version this must go through the entire thing again. - while ((newcode = stripaccent(code)) != code) - { - code = newcode; - if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) - { - return code; - } - } - - } - - return -1; -} - -//========================================================================== -// -// FFont :: GetChar -// -//========================================================================== - -FTexture *FFont::GetChar (int code, int translation, int *const width, bool *redirected) const -{ - code = GetCharCode(code, true); - int xmove = SpaceWidth; - - if (code >= 0) - { - code -= FirstChar; - xmove = Chars[code].XMove; - } - - if (width != nullptr) - { - *width = xmove; - } - if (code < 0) return nullptr; - - - if (translation == CR_UNTRANSLATED && !forceremap) - { - bool redirect = Chars[code].OriginalPic && Chars[code].OriginalPic != Chars[code].TranslatedPic; - if (redirected) *redirected = redirect; - if (redirect) - { - assert(Chars[code].OriginalPic->UseType == ETextureType::FontChar); - return Chars[code].OriginalPic; - } - } - if (redirected) *redirected = false; - assert(Chars[code].TranslatedPic->UseType == ETextureType::FontChar); - return Chars[code].TranslatedPic; -} - -//========================================================================== -// -// FFont :: GetCharWidth -// -//========================================================================== - -int FFont::GetCharWidth (int code) const -{ - code = GetCharCode(code, true); - if (code >= 0) return Chars[code - FirstChar].XMove; - return SpaceWidth; -} - -//========================================================================== -// -// -// -//========================================================================== - -double GetBottomAlignOffset(FFont *font, int c) -{ - int w; - FTexture *tex_zero = font->GetChar('0', CR_UNDEFINED, &w); - FTexture *texc = font->GetChar(c, CR_UNDEFINED, &w); - double offset = 0; - if (texc) offset += texc->GetDisplayTopOffsetDouble(); - if (tex_zero) offset += -tex_zero->GetDisplayTopOffsetDouble() + tex_zero->GetDisplayHeightDouble(); - return offset; -} - -//========================================================================== -// -// Checks if the font contains proper glyphs for all characters in the string -// -//========================================================================== - -bool FFont::CanPrint(const uint8_t *string) const -{ - if (!string) return true; - while (*string) - { - auto chr = GetCharFromString(string); - if (!MixedCase) chr = upperforlower[chr]; // For uppercase-only fonts we shouldn't check lowercase characters. - if (chr == TEXTCOLOR_ESCAPE) - { - // We do not need to check for UTF-8 in here. - if (*string == '[') - { - while (*string != '\0' && *string != ']') - { - ++string; - } - } - if (*string != '\0') - { - ++string; - } - continue; - } - else if (chr != '\n') - { - int cc = GetCharCode(chr, true); - if (chr != cc && myiswalpha(chr) && cc != getAlternative(chr)) - { - return false; - } - } - } - - return true; -} - -//========================================================================== -// -// Find string width using this font -// -//========================================================================== - -int FFont::StringWidth(const uint8_t *string) const -{ - int w = 0; - int maxw = 0; - - while (*string) - { - auto chr = GetCharFromString(string); - if (chr == TEXTCOLOR_ESCAPE) - { - // We do not need to check for UTF-8 in here. - if (*string == '[') - { - while (*string != '\0' && *string != ']') - { - ++string; - } - } - if (*string != '\0') - { - ++string; - } - continue; - } - else if (chr == '\n') - { - if (w > maxw) - maxw = w; - w = 0; - } - else - { - w += GetCharWidth(chr) + GlobalKerning; - } - } - - return MAX(maxw, w); -} - -//========================================================================== -// -// Get the largest ascender in the first line of this text. -// -//========================================================================== - -int FFont::GetMaxAscender(const uint8_t* string) const -{ - int retval = 0; - - while (*string) - { - auto chr = GetCharFromString(string); - if (chr == TEXTCOLOR_ESCAPE) - { - // We do not need to check for UTF-8 in here. - if (*string == '[') - { - while (*string != '\0' && *string != ']') - { - ++string; - } - } - if (*string != '\0') - { - ++string; - } - continue; - } - else if (chr == '\n') - { - break; - } - else - { - auto ctex = GetChar(chr, CR_UNTRANSLATED, nullptr); - if (ctex) - { - auto offs = int(ctex->GetScaledTopOffset(0)); - if (offs > retval) retval = offs; - } - } - } - - return retval; -} - -//========================================================================== -// -// FFont :: LoadTranslations -// -//========================================================================== - -void FFont::LoadTranslations() -{ - unsigned int count = LastChar - FirstChar + 1; - uint32_t usedcolors[256] = {}; - uint8_t identity[256]; - TArray Luminosity; - - for (unsigned int i = 0; i < count; i++) - { - if (Chars[i].TranslatedPic) - { - FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); - if (pic) - { - pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture - RecordTextureColors(pic, usedcolors); - } - } - } - - ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity); - - for (unsigned int i = 0; i < count; i++) - { - if(Chars[i].TranslatedPic) - static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); - } - - BuildTranslations (Luminosity.Data(), identity, &TranslationParms[TranslationType][0], ActiveColors, nullptr); -} - -//========================================================================== -// -// FFont :: FFont - default constructor -// -//========================================================================== - -FFont::FFont (int lump) -{ - Lump = lump; - FontName = NAME_None; - Cursor = '_'; - noTranslate = false; - uint8_t pp = 0; - for (auto &p : PatchRemap) p = pp++; -} - -//========================================================================== -// -// FFont :: FixXMoves -// -// If a font has gaps in its characters, set the missing characters' -// XMoves to either SpaceWidth or the unaccented or uppercase variant's -// XMove. Missing XMoves must be initialized with INT_MIN beforehand. -// -//========================================================================== - -void FFont::FixXMoves() -{ - if (FirstChar < 'a' && LastChar >= 'z') - { - MixedCase = true; - // First check if this is a mixed case font. - // For this the basic Latin small characters all need to be present. - for (int i = 'a'; i <= 'z'; i++) - if (Chars[i - FirstChar].OriginalPic == nullptr) - { - MixedCase = false; - break; - } - } - - for (int i = 0; i <= LastChar - FirstChar; ++i) - { - if (Chars[i].XMove == INT_MIN) - { - // Try an uppercase character. - if (myislower(i + FirstChar)) - { - int upper = upperforlower[FirstChar + i]; - if (upper >= FirstChar && upper <= LastChar ) - { - Chars[i].XMove = Chars[upper - FirstChar].XMove; - continue; - } - } - // Try an unnaccented character. - int noaccent = stripaccent(i + FirstChar); - if (noaccent != i + FirstChar) - { - noaccent -= FirstChar; - if (noaccent >= 0) - { - Chars[i].XMove = Chars[noaccent].XMove; - continue; - } - } - Chars[i].XMove = SpaceWidth; - } - if (Chars[i].OriginalPic) - { - int ofs = Chars[i].OriginalPic->GetScaledTopOffset(0); - if (ofs > Displacement) Displacement = ofs; - } - } -} - - diff --git a/src/gamedata/fonts/fontinternals.h b/src/gamedata/fonts/fontinternals.h deleted file mode 100644 index 6d68c6aa868..00000000000 --- a/src/gamedata/fonts/fontinternals.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include "tarray.h" - -// This structure is used by BuildTranslations() to hold color information. -struct TranslationParm -{ - short RangeStart; // First level for this range - short RangeEnd; // Last level for this range - uint8_t Start[3]; // Start color for this range - uint8_t End[3]; // End color for this range -}; - -struct TempParmInfo -{ - unsigned int StartParm[2]; - unsigned int ParmLen[2]; - int Index; -}; -struct TempColorInfo -{ - FName Name; - unsigned int ParmInfo; - PalEntry LogColor; -}; - -struct TranslationMap -{ - FName Name; - int Number; -}; - -extern TArray TranslationParms[2]; -extern TArray TranslationLookup; -extern TArray TranslationColors; -extern uint16_t lowerforupper[65536]; -extern uint16_t upperforlower[65536]; - -class FImageSource; - -void RecordTextureColors (FImageSource *pic, uint32_t *usedcolors); -bool myislower(int code); -bool myisupper(int code); -int stripaccent(int code); -int getAlternative(int code); diff --git a/src/gamedata/fonts/hexfont.cpp b/src/gamedata/fonts/hexfont.cpp deleted file mode 100644 index fde86bc3d9c..00000000000 --- a/src/gamedata/fonts/hexfont.cpp +++ /dev/null @@ -1,450 +0,0 @@ -/* -** bdffont.cpp -** Management for the VGA consolefont -** -**--------------------------------------------------------------------------- -** Copyright 2019 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "doomerrors.h" -#include "textures.h" -#include "image.h" -#include "v_font.h" -#include "w_wad.h" -#include "utf8.h" -#include "sc_man.h" - -#include "fontinternals.h" - - -struct HexDataSource -{ - int FirstChar = INT_MAX, LastChar = INT_MIN; - TArray glyphdata; - unsigned glyphmap[65536] = {}; - - //========================================================================== - // - // parse a HEX font - // - //========================================================================== - - void ParseDefinition(int lumpnum) - { - FScanner sc; - - sc.OpenLumpNum(lumpnum); - sc.SetCMode(true); - glyphdata.Push(0); // ensure that index 0 can be used as 'not present'. - while (sc.GetString()) - { - int codepoint = (int)strtoull(sc.String, nullptr, 16); - sc.MustGetStringName(":"); - sc.MustGetString(); - if (codepoint >= 0 && codepoint < 65536 && !sc.Compare("00000000000000000000000000000000")) // don't set up empty glyphs. - { - unsigned size = (unsigned)strlen(sc.String); - unsigned offset = glyphdata.Reserve(size / 2 + 1); - glyphmap[codepoint] = offset; - glyphdata[offset++] = size / 2; - for (unsigned i = 0; i < size; i += 2) - { - char hex[] = { sc.String[i], sc.String[i + 1], 0 }; - glyphdata[offset++] = (uint8_t)strtoull(hex, nullptr, 16); - } - if (codepoint < FirstChar) FirstChar = codepoint; - if (codepoint > LastChar) LastChar = codepoint; - } - } - } -}; - -static HexDataSource hexdata; - -// This is a font character that reads RLE compressed data. -class FHexFontChar : public FImageSource -{ -public: - FHexFontChar(uint8_t *sourcedata, int swidth, int width, int height); - - TArray CreatePalettedPixels(int conversion) override; - -protected: - int SourceWidth; - const uint8_t *SourceData; -}; - - -//========================================================================== -// -// FHexFontChar :: FHexFontChar -// -// Used by HEX fonts. -// -//========================================================================== - -FHexFontChar::FHexFontChar (uint8_t *sourcedata, int swidth, int width, int height) -: SourceData (sourcedata) -{ - SourceWidth = swidth; - Width = width; - Height = height; - LeftOffset = 0; - TopOffset = 0; -} - -//========================================================================== -// -// FHexFontChar :: Get8BitPixels -// -// The render style has no relevance here. -// -//========================================================================== - -TArray FHexFontChar::CreatePalettedPixels(int) -{ - int destSize = Width * Height; - TArray Pixels(destSize, true); - uint8_t *dest_p = Pixels.Data(); - const uint8_t *src_p = SourceData; - - memset(dest_p, 0, destSize); - for (int y = 0; y < Height; y++) - { - for (int x = 0; x < SourceWidth; x++) - { - int byte = *src_p++; - uint8_t *pixelstart = dest_p + 8 * x * Height + y; - for (int bit = 0; bit < 8; bit++) - { - if (byte & (128 >> bit)) - { - pixelstart[bit*Height] = y+2; - // Add a shadow at the bottom right, similar to the old console font. - if (y != Height - 1) - { - pixelstart[bit*Height + Height + 1] = 1; - } - } - } - } - } - return Pixels; -} - -class FHexFontChar2 : public FHexFontChar -{ -public: - FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height); - - TArray CreatePalettedPixels(int conversion) override; -}; - - -//========================================================================== -// -// FHexFontChar :: FHexFontChar -// -// Used by HEX fonts. -// -//========================================================================== - -FHexFontChar2::FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height) - : FHexFontChar(sourcedata, swidth, width, height) -{ -} - -//========================================================================== -// -// FHexFontChar :: Get8BitPixels -// -// The render style has no relevance here. -// -//========================================================================== - -TArray FHexFontChar2::CreatePalettedPixels(int) -{ - int destSize = Width * Height; - TArray Pixels(destSize, true); - uint8_t *dest_p = Pixels.Data(); - - assert(SourceData); - if (SourceData) - { - auto drawLayer = [&](int ix, int iy, int color) - { - const uint8_t *src_p = SourceData; - for (int y = 0; y < Height - 2; y++) - { - for (int x = 0; x < SourceWidth; x++) - { - int byte = *src_p++; - uint8_t *pixelstart = dest_p + (ix + 8 * x) * Height + (iy + y); - for (int bit = 0; bit < 8; bit++) - { - if (byte & (128 >> bit)) - { - pixelstart[bit*Height] = color; - } - } - } - } - }; - memset(dest_p, 0, destSize); - - const int darkcolor = 1; - const int brightcolor = 14; - for (int xx = 0; xx < 3; xx++) for (int yy = 0; yy < 3; yy++) if (xx != 1 || yy != 1) - drawLayer(xx, yy, darkcolor); - drawLayer(1, 1, brightcolor); - } - return Pixels; -} - - - -class FHexFont : public FFont -{ - -public: - //========================================================================== - // - // FHexFont :: FHexFont - // - // Loads a HEX font - // - //========================================================================== - - FHexFont (const char *fontname, int lump) - : FFont(lump) - { - assert(lump >= 0); - - FontName = fontname; - - FirstChar = hexdata.FirstChar; - LastChar = hexdata.LastChar; - - Next = FirstFont; - FirstFont = this; - FontHeight = 16; - SpaceWidth = 9; - GlobalKerning = 0; - translateUntranslated = true; - - LoadTranslations(); - } - - //========================================================================== - // - // FHexFont :: LoadTranslations - // - //========================================================================== - - void LoadTranslations() - { - const int spacing = 9; - double luminosity[256]; - - memset (PatchRemap, 0, 256); - for (int i = 0; i < 18; i++) - { - // Create a gradient similar to the old console font. - PatchRemap[i] = i; - luminosity[i] = i == 1? 0.01 : 0.5 + (i-2) * (0.5 / 17.); - } - ActiveColors = 18; - - Chars.Resize(LastChar - FirstChar + 1); - for (int i = FirstChar; i <= LastChar; i++) - { - if (hexdata.glyphmap[i] > 0) - { - auto offset = hexdata.glyphmap[i]; - int size = hexdata.glyphdata[offset] / 16; - Chars[i - FirstChar].TranslatedPic = new FImageTexture(new FHexFontChar (&hexdata.glyphdata[offset+1], size, size * 9, 16)); - Chars[i - FirstChar].TranslatedPic->SetUseType(ETextureType::FontChar); - Chars[i - FirstChar].XMove = size * spacing; - TexMan.AddTexture(Chars[i - FirstChar].TranslatedPic); - } - else Chars[i - FirstChar].XMove = spacing; - - } - BuildTranslations (luminosity, nullptr, &TranslationParms[1][0], ActiveColors, nullptr); - } - -}; - - -class FHexFont2 : public FFont -{ - -public: - //========================================================================== - // - // FHexFont :: FHexFont - // - // Loads a HEX font - // - //========================================================================== - - FHexFont2(const char *fontname, int lump) - : FFont(lump) - { - assert(lump >= 0); - - FontName = fontname; - - FirstChar = hexdata.FirstChar; - LastChar = hexdata.LastChar; - - Next = FirstFont; - FirstFont = this; - FontHeight = 18; - SpaceWidth = 10; - GlobalKerning = -1; - translateUntranslated = true; - - LoadTranslations(); - } - - //========================================================================== - // - // FHexFont :: LoadTranslations - // - //========================================================================== - - void LoadTranslations() - { - const int spacing = 9; - double luminosity[256]; - - memset(PatchRemap, 0, 256); - for (int i = 0; i < 18; i++) - { - // Create a gradient similar to the old console font. - PatchRemap[i] = i; - luminosity[i] = i / 17.; - } - ActiveColors = 18; - - Chars.Resize(LastChar - FirstChar + 1); - for (int i = FirstChar; i <= LastChar; i++) - { - if (hexdata.glyphmap[i] > 0) - { - auto offset = hexdata.glyphmap[i]; - int size = hexdata.glyphdata[offset] / 16; - Chars[i - FirstChar].TranslatedPic = new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18)); - Chars[i - FirstChar].TranslatedPic->SetUseType(ETextureType::FontChar); - Chars[i - FirstChar].XMove = size * spacing; - TexMan.AddTexture(Chars[i - FirstChar].TranslatedPic); - } - else Chars[i - FirstChar].XMove = spacing; - - } - BuildTranslations(luminosity, nullptr, &TranslationParms[0][0], ActiveColors, nullptr); - } - - void SetDefaultTranslation(uint32_t *colors) override - { - double myluminosity[18]; - - myluminosity[0] = 0; - for (int i = 1; i < 18; i++) - { - myluminosity[i] = (i - 1) / 16.; - } - - uint8_t othertranslation[256], otherreverse[256]; - TArray otherluminosity; - - SimpleTranslation(colors, othertranslation, otherreverse, otherluminosity); - - FRemapTable remap(ActiveColors); - remap.Remap[0] = 0; - remap.Palette[0] = 0; - - for (unsigned l = 1; l < 18; l++) - { - for (unsigned o = 1; o < otherluminosity.Size() - 1; o++) // luminosity[0] is for the transparent color - { - if (myluminosity[l] >= otherluminosity[o] && myluminosity[l] <= otherluminosity[o + 1]) - { - PalEntry color1 = GPalette.BaseColors[otherreverse[o]]; - PalEntry color2 = GPalette.BaseColors[otherreverse[o + 1]]; - double weight = 0; - if (otherluminosity[o] != otherluminosity[o + 1]) - { - weight = (myluminosity[l] - otherluminosity[o]) / (otherluminosity[o + 1] - otherluminosity[o]); - } - int r = int(color1.r + weight * (color2.r - color1.r)); - int g = int(color1.g + weight * (color2.g - color1.g)); - int b = int(color1.b + weight * (color2.b - color1.b)); - - r = clamp(r, 0, 255); - g = clamp(g, 0, 255); - b = clamp(b, 0, 255); - remap.Remap[l] = ColorMatcher.Pick(r, g, b); - remap.Palette[l] = PalEntry(255, r, g, b); - break; - } - } - } - Translations[CR_UNTRANSLATED] = remap.StoreTranslation(TRANSLATION_Font); - forceremap = true; - - } - -}; - - -//========================================================================== -// -// -// -//========================================================================== - -FFont *CreateHexLumpFont (const char *fontname, int lump) -{ - if (hexdata.FirstChar == INT_MAX) hexdata.ParseDefinition(lump); - return new FHexFont(fontname, lump); -} - -//========================================================================== -// -// -// -//========================================================================== - -FFont *CreateHexLumpFont2(const char *fontname, int lump) -{ - if (hexdata.FirstChar == INT_MAX) hexdata.ParseDefinition(lump); - return new FHexFont2(fontname, lump); -} diff --git a/src/gamedata/fonts/singlelumpfont.cpp b/src/gamedata/fonts/singlelumpfont.cpp deleted file mode 100644 index 02e8564b12e..00000000000 --- a/src/gamedata/fonts/singlelumpfont.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/* -** singlelumpfont.cpp -** Management for compiled font lumps -** -**--------------------------------------------------------------------------- -** Copyright 1998-2016 Randy Heit -** Copyright 2005-2019 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "doomerrors.h" -#include "textures.h" -#include "image.h" -#include "v_font.h" -#include "w_wad.h" -#include "utf8.h" -#include "textures/formats/fontchars.h" - -#include "fontinternals.h" - -/* Special file formats handled here: - -FON1 "console" fonts have the following header: - char Magic[4]; -- The characters "FON1" - uword CharWidth; -- Character cell width - uword CharHeight; -- Character cell height - -The FON1 header is followed by RLE character data for all 256 -8-bit ASCII characters. - - -FON2 "standard" fonts have the following header: - char Magic[4]; -- The characters "FON2" - uword FontHeight; -- Every character in a font has the same height - ubyte FirstChar; -- First character defined by this font. - ubyte LastChar; -- Last character definde by this font. - ubyte bConstantWidth; - ubyte ShadingType; - ubyte PaletteSize; -- size of palette in entries (not bytes!) - ubyte Flags; - -There is presently only one flag for FON2: - FOF_WHOLEFONTKERNING 1 -- The Kerning field is present in the file - -The FON2 header is followed by variable length data: - word Kerning; - -- only present if FOF_WHOLEFONTKERNING is set - - ubyte Palette[PaletteSize+1][3]; - -- The last entry is the delimiter color. The delimiter is not used - -- by the font but is used by imagetool when converting the font - -- back to an image. Color 0 is the transparent color and is also - -- used only for converting the font back to an image. The other - -- entries are all presorted in increasing order of brightness. - - ubyte CharacterData[...]; - -- RLE character data, in order -*/ - -class FSingleLumpFont : public FFont -{ -public: - FSingleLumpFont (const char *fontname, int lump); - -protected: - void CheckFON1Chars (double *luminosity); - void BuildTranslations2 (); - void FixupPalette (uint8_t *identity, double *luminosity, const uint8_t *palette, - bool rescale, PalEntry *out_palette); - void LoadTranslations (); - void LoadFON1 (int lump, const uint8_t *data); - void LoadFON2 (int lump, const uint8_t *data); - void LoadBMF (int lump, const uint8_t *data); - void CreateFontFromPic (FTextureID picnum); - - static int BMFCompare(const void *a, const void *b); - - enum - { - FONT1, - FONT2, - BMFFONT - } FontType; - uint8_t PaletteData[768]; - bool RescalePalette; -}; - - -//========================================================================== -// -// FSingleLumpFont :: FSingleLumpFont -// -// Loads a FON1 or FON2 font resource. -// -//========================================================================== - -FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump) -{ - assert(lump >= 0); - - FontName = name; - - FMemLump data1 = Wads.ReadLump (lump); - const uint8_t *data = (const uint8_t *)data1.GetMem(); - - if (data[0] == 0xE1 && data[1] == 0xE6 && data[2] == 0xD5 && data[3] == 0x1A) - { - LoadBMF(lump, data); - Type = BMF; - } - else if (data[0] != 'F' || data[1] != 'O' || data[2] != 'N' || - (data[3] != '1' && data[3] != '2')) - { - I_Error ("%s is not a recognizable font", name); - } - else - { - switch (data[3]) - { - case '1': - LoadFON1 (lump, data); - Type = Fon1; - break; - - case '2': - LoadFON2 (lump, data); - Type = Fon2; - break; - } - } - - Next = FirstFont; - FirstFont = this; -} - -//========================================================================== -// -// FSingleLumpFont :: CreateFontFromPic -// -//========================================================================== - -void FSingleLumpFont::CreateFontFromPic (FTextureID picnum) -{ - FTexture *pic = TexMan.GetTexture(picnum); - - FontHeight = pic->GetDisplayHeight (); - SpaceWidth = pic->GetDisplayWidth (); - GlobalKerning = 0; - - FirstChar = LastChar = 'A'; - Chars.Resize(1); - Chars[0].TranslatedPic = pic; - - // Only one color range. Don't bother with the others. - ActiveColors = 0; -} - -//========================================================================== -// -// FSingleLumpFont :: LoadTranslations -// -//========================================================================== - -void FSingleLumpFont::LoadTranslations() -{ - double luminosity[256]; - uint8_t identity[256]; - PalEntry local_palette[256]; - bool useidentity = true; - bool usepalette = false; - const void* ranges; - unsigned int count = LastChar - FirstChar + 1; - - switch(FontType) - { - case FONT1: - useidentity = false; - ranges = &TranslationParms[1][0]; - CheckFON1Chars (luminosity); - break; - - case BMFFONT: - case FONT2: - usepalette = true; - FixupPalette (identity, luminosity, PaletteData, RescalePalette, local_palette); - - ranges = &TranslationParms[0][0]; - break; - - default: - // Should be unreachable. - I_Error("Unknown font type in FSingleLumpFont::LoadTranslation."); - return; - } - - for(unsigned int i = 0;i < count;++i) - { - if(Chars[i].TranslatedPic) - static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); - } - - BuildTranslations (luminosity, useidentity ? identity : nullptr, ranges, ActiveColors, usepalette ? local_palette : nullptr); -} - -//========================================================================== -// -// FSingleLumpFont :: LoadFON1 -// -// FON1 is used for the console font. -// -//========================================================================== - -void FSingleLumpFont::LoadFON1 (int lump, const uint8_t *data) -{ - int w, h; - - // The default console font is for Windows-1252 and fills the 0x80-0x9f range with valid glyphs. - // Since now all internal text is processed as Unicode, these have to be remapped to their proper places. - // The highest valid character in this range is 0x2122, so we need 0x2123 entries in our character table. - Chars.Resize(0x2123); - - w = data[4] + data[5]*256; - h = data[6] + data[7]*256; - - FontType = FONT1; - FontHeight = h; - SpaceWidth = w; - FirstChar = 0; - LastChar = 255; // This is to allow LoadTranslations to function. The way this is all set up really needs to be changed. - GlobalKerning = 0; - translateUntranslated = true; - LoadTranslations(); - LastChar = 0x2122; - - // Move the Windows-1252 characters to their proper place. - for (int i = 0x80; i < 0xa0; i++) - { - if (win1252map[i-0x80] != i && Chars[i].TranslatedPic != nullptr && Chars[win1252map[i - 0x80]].TranslatedPic == nullptr) - { - std::swap(Chars[i], Chars[win1252map[i - 0x80]]); - } - } -} - -//========================================================================== -// -// FSingleLumpFont :: LoadFON2 -// -// FON2 is used for everything but the console font. The console font should -// probably use FON2 as well, but oh well. -// -//========================================================================== - -void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data) -{ - int count, i, totalwidth; - uint16_t *widths; - const uint8_t *palette; - const uint8_t *data_p; - - FontType = FONT2; - FontHeight = data[4] + data[5]*256; - FirstChar = data[6]; - LastChar = data[7]; - ActiveColors = data[10]+1; - RescalePalette = data[9] == 0; - - count = LastChar - FirstChar + 1; - Chars.Resize(count); - TArray widths2(count, true); - if (data[11] & 1) - { // Font specifies a kerning value. - GlobalKerning = LittleShort(*(int16_t *)&data[12]); - widths = (uint16_t *)(data + 14); - } - else - { // Font does not specify a kerning value. - GlobalKerning = 0; - widths = (uint16_t *)(data + 12); - } - totalwidth = 0; - - if (data[8]) - { // Font is mono-spaced. - totalwidth = LittleShort(widths[0]); - for (i = 0; i < count; ++i) - { - widths2[i] = totalwidth; - } - totalwidth *= count; - palette = (uint8_t *)&widths[1]; - } - else - { // Font has varying character widths. - for (i = 0; i < count; ++i) - { - widths2[i] = LittleShort(widths[i]); - totalwidth += widths2[i]; - } - palette = (uint8_t *)(widths + i); - } - - if (FirstChar <= ' ' && LastChar >= ' ') - { - SpaceWidth = widths2[' '-FirstChar]; - } - else if (FirstChar <= 'N' && LastChar >= 'N') - { - SpaceWidth = (widths2['N' - FirstChar] + 1) / 2; - } - else - { - SpaceWidth = totalwidth * 2 / (3 * count); - } - - memcpy(PaletteData, palette, ActiveColors*3); - - data_p = palette + ActiveColors*3; - - for (i = 0; i < count; ++i) - { - int destSize = widths2[i] * FontHeight; - Chars[i].XMove = widths2[i]; - if (destSize <= 0) - { - Chars[i].TranslatedPic = nullptr; - } - else - { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - TexMan.AddTexture(Chars[i].TranslatedPic); - do - { - int8_t code = *data_p++; - if (code >= 0) - { - data_p += code+1; - destSize -= code+1; - } - else if (code != -128) - { - data_p++; - destSize -= (-code)+1; - } - } while (destSize > 0); - } - if (destSize < 0) - { - i += FirstChar; - I_FatalError ("Overflow decompressing char %d (%c) of %s", i, i, FontName.GetChars()); - } - } - - LoadTranslations(); -} - -//========================================================================== -// -// FSingleLumpFont :: LoadBMF -// -// Loads a BMF font. The file format is described at -// -// -//========================================================================== - -void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data) -{ - const uint8_t *chardata; - int numchars, count, totalwidth, nwidth; - int infolen; - int i, chari; - uint8_t raw_palette[256*3]; - PalEntry sort_palette[256]; - - FontType = BMFFONT; - FontHeight = data[5]; - GlobalKerning = (int8_t)data[8]; - ActiveColors = data[16]; - SpaceWidth = -1; - nwidth = -1; - RescalePalette = true; - - infolen = data[17 + ActiveColors*3]; - chardata = data + 18 + ActiveColors*3 + infolen; - numchars = chardata[0] + 256*chardata[1]; - chardata += 2; - - // Scan for lowest and highest characters defined and total font width. - FirstChar = 256; - LastChar = 0; - totalwidth = 0; - for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2]) - { - if ((chardata[chari+1] == 0 || chardata[chari+2] == 0) && chardata[chari+5] == 0) - { // Don't count empty characters. - continue; - } - if (chardata[chari] < FirstChar) - { - FirstChar = chardata[chari]; - } - if (chardata[chari] > LastChar) - { - LastChar = chardata[chari]; - } - totalwidth += chardata[chari+1]; - } - if (LastChar < FirstChar) - { - I_FatalError("BMF font defines no characters"); - } - count = LastChar - FirstChar + 1; - Chars.Resize(count); - // BMF palettes are only six bits per component. Fix that. - for (i = 0; i < ActiveColors*3; ++i) - { - raw_palette[i+3] = (data[17 + i] << 2) | (data[17 + i] >> 4); - } - ActiveColors++; - - // Sort the palette by increasing brightness - for (i = 0; i < ActiveColors; ++i) - { - PalEntry *pal = &sort_palette[i]; - pal->a = i; // Use alpha part to point back to original entry - pal->r = raw_palette[i*3 + 0]; - pal->g = raw_palette[i*3 + 1]; - pal->b = raw_palette[i*3 + 2]; - } - qsort(sort_palette + 1, ActiveColors - 1, sizeof(PalEntry), BMFCompare); - - // Create the PatchRemap table from the sorted "alpha" values. - PatchRemap[0] = 0; - for (i = 1; i < ActiveColors; ++i) - { - PatchRemap[sort_palette[i].a] = i; - } - - memcpy(PaletteData, raw_palette, 768); - - // Now scan through the characters again, creating glyphs for each one. - for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2]) - { - assert(chardata[chari] - FirstChar >= 0); - assert(chardata[chari] - FirstChar < count); - if (chardata[chari] == ' ') - { - SpaceWidth = chardata[chari+5]; - } - else if (chardata[chari] == 'N') - { - nwidth = chardata[chari+5]; - } - Chars[chardata[chari] - FirstChar].XMove = chardata[chari+5]; - if (chardata[chari+1] == 0 || chardata[chari+2] == 0) - { // Empty character: skip it. - continue; - } - auto tex = new FImageTexture(new FFontChar2(lump, int(chardata + chari + 6 - data), - chardata[chari+1], // width - chardata[chari+2], // height - -(int8_t)chardata[chari+3], // x offset - -(int8_t)chardata[chari+4] // y offset - )); - tex->SetUseType(ETextureType::FontChar); - Chars[chardata[chari] - FirstChar].TranslatedPic = tex; - TexMan.AddTexture(tex); - } - - // If the font did not define a space character, determine a suitable space width now. - if (SpaceWidth < 0) - { - if (nwidth >= 0) - { - SpaceWidth = nwidth; - } - else - { - SpaceWidth = totalwidth * 2 / (3 * count); - } - } - - FixXMoves(); - LoadTranslations(); -} - -//========================================================================== -// -// FSingleLumpFont :: BMFCompare STATIC -// -// Helper to sort BMF palettes. -// -//========================================================================== - -int FSingleLumpFont::BMFCompare(const void *a, const void *b) -{ - const PalEntry *pa = (const PalEntry *)a; - const PalEntry *pb = (const PalEntry *)b; - - return (pa->r * 299 + pa->g * 587 + pa->b * 114) - - (pb->r * 299 + pb->g * 587 + pb->b * 114); -} - -//========================================================================== -// -// FSingleLumpFont :: CheckFON1Chars -// -// Scans a FON1 resource for all the color values it uses and sets up -// some tables like SimpleTranslation. Data points to the RLE data for -// the characters. Also sets up the character textures. -// -//========================================================================== - -void FSingleLumpFont::CheckFON1Chars (double *luminosity) -{ - FMemLump memLump = Wads.ReadLump(Lump); - const uint8_t* data = (const uint8_t*) memLump.GetMem(); - - uint8_t used[256], reverse[256]; - const uint8_t *data_p; - int i, j; - - memset (used, 0, 256); - data_p = data + 8; - - for (i = 0; i < 256; ++i) - { - int destSize = SpaceWidth * FontHeight; - - if(!Chars[i].TranslatedPic) - { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight)); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - Chars[i].XMove = SpaceWidth; - TexMan.AddTexture(Chars[i].TranslatedPic); - } - - // Advance to next char's data and count the used colors. - do - { - int8_t code = *data_p++; - if (code >= 0) - { - destSize -= code+1; - while (code-- >= 0) - { - used[*data_p++] = 1; - } - } - else if (code != -128) - { - used[*data_p++] = 1; - destSize -= 1 - code; - } - } while (destSize > 0); - } - - memset (PatchRemap, 0, 256); - reverse[0] = 0; - for (i = 1, j = 1; i < 256; ++i) - { - if (used[i]) - { - reverse[j++] = i; - } - } - for (i = 1; i < j; ++i) - { - PatchRemap[reverse[i]] = i; - luminosity[i] = (reverse[i] - 1) / 254.0; - } - ActiveColors = j; -} - -//========================================================================== -// -// FSingleLumpFont :: FixupPalette -// -// Finds the best matches for the colors used by a FON2 font and sets up -// some tables like SimpleTranslation. -// -//========================================================================== - -void FSingleLumpFont::FixupPalette (uint8_t *identity, double *luminosity, const uint8_t *palette, bool rescale, PalEntry *out_palette) -{ - int i; - double maxlum = 0.0; - double minlum = 100000000.0; - double diver; - - identity[0] = 0; - palette += 3; // Skip the transparent color - - for (i = 1; i < ActiveColors; ++i, palette += 3) - { - int r = palette[0]; - int g = palette[1]; - int b = palette[2]; - double lum = r*0.299 + g*0.587 + b*0.114; - identity[i] = ColorMatcher.Pick (r, g, b); - luminosity[i] = lum; - out_palette[i].r = r; - out_palette[i].g = g; - out_palette[i].b = b; - out_palette[i].a = 255; - if (lum > maxlum) - maxlum = lum; - if (lum < minlum) - minlum = lum; - } - out_palette[0] = 0; - - if (rescale) - { - diver = 1.0 / (maxlum - minlum); - } - else - { - diver = 1.0 / 255.0; - } - for (i = 1; i < ActiveColors; ++i) - { - luminosity[i] = (luminosity[i] - minlum) * diver; - } -} - -FFont *CreateSingleLumpFont (const char *fontname, int lump) -{ - return new FSingleLumpFont(fontname, lump); -} diff --git a/src/gamedata/fonts/specialfont.cpp b/src/gamedata/fonts/specialfont.cpp deleted file mode 100644 index 6231db07e47..00000000000 --- a/src/gamedata/fonts/specialfont.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* -** v_font.cpp -** Font management -** -**--------------------------------------------------------------------------- -** Copyright 1998-2016 Randy Heit -** Copyright 2005-2019 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "v_font.h" -#include "textures.h" -#include "image.h" -#include "textures/formats/fontchars.h" - -#include "fontinternals.h" - -// Essentially a normal multilump font but with an explicit list of character patches -class FSpecialFont : public FFont -{ -public: - FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); - - void LoadTranslations(); - -protected: - bool notranslate[256]; -}; - - -//========================================================================== -// -// FSpecialFont :: FSpecialFont -// -//========================================================================== - -FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) - : FFont(lump) -{ - int i; - TArray charlumps(count, true); - int maxyoffs; - FTexture *pic; - - memcpy(this->notranslate, notranslate, 256*sizeof(bool)); - - noTranslate = donttranslate; - FontName = name; - Chars.Resize(count); - FirstChar = first; - LastChar = first + count - 1; - FontHeight = 0; - GlobalKerning = false; - Next = FirstFont; - FirstFont = this; - - maxyoffs = 0; - - for (i = 0; i < count; i++) - { - pic = charlumps[i] = lumplist[i]; - if (pic != nullptr) - { - int height = pic->GetDisplayHeight(); - int yoffs = pic->GetDisplayTopOffset(); - - if (yoffs > maxyoffs) - { - maxyoffs = yoffs; - } - height += abs (yoffs); - if (height > FontHeight) - { - FontHeight = height; - } - } - - if (charlumps[i] != nullptr) - { - auto pic = charlumps[i]; - Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); - Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); - Chars[i].OriginalPic->CopySize(pic); - TexMan.AddTexture(Chars[i].OriginalPic); - - if (!noTranslate) - { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (charlumps[i]->GetImage()), ""); - Chars[i].TranslatedPic->CopySize(charlumps[i]); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - TexMan.AddTexture(Chars[i].TranslatedPic); - } - else Chars[i].TranslatedPic = Chars[i].OriginalPic; - Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); - } - else - { - Chars[i].TranslatedPic = nullptr; - Chars[i].XMove = INT_MIN; - } - } - - // Special fonts normally don't have all characters so be careful here! - if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].TranslatedPic != nullptr) - { - SpaceWidth = (Chars['N' - first].XMove + 1) / 2; - } - else - { - SpaceWidth = 4; - } - - FixXMoves(); - - if (noTranslate) - { - ActiveColors = 0; - } - else - { - LoadTranslations(); - } -} - -//========================================================================== -// -// FSpecialFont :: LoadTranslations -// -//========================================================================== - -void FSpecialFont::LoadTranslations() -{ - int count = LastChar - FirstChar + 1; - uint32_t usedcolors[256] = {}; - uint8_t identity[256]; - TArray Luminosity; - int TotalColors; - int i; - - for (i = 0; i < count; i++) - { - if (Chars[i].TranslatedPic) - { - FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); - if (pic) - { - pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture - RecordTextureColors(pic, usedcolors); - } - } - } - - // exclude the non-translated colors from the translation calculation - for (i = 0; i < 256; i++) - if (notranslate[i]) - usedcolors[i] = false; - - TotalColors = ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity); - - // Map all untranslated colors into the table of used colors - for (i = 0; i < 256; i++) - { - if (notranslate[i]) - { - PatchRemap[i] = TotalColors; - identity[TotalColors] = i; - TotalColors++; - } - } - - for (i = 0; i < count; i++) - { - if(Chars[i].TranslatedPic) - static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); - } - - BuildTranslations(Luminosity.Data(), identity, &TranslationParms[0][0], TotalColors, nullptr, [=](FRemapTable* remap) - { - // add the untranslated colors to the Ranges tables - if (ActiveColors < TotalColors) - { - for (int j = ActiveColors; j < TotalColors; ++j) - { - remap->Remap[j] = identity[j]; - remap->Palette[j] = GPalette.BaseColors[identity[j]]; - remap->Palette[j].a = 0xff; - } - } - }); - - ActiveColors = TotalColors; -} - -FFont *CreateSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) -{ - return new FSpecialFont(name, first, count, lumplist, notranslate, lump, donttranslate); -} diff --git a/src/gamedata/fonts/v_font.cpp b/src/gamedata/fonts/v_font.cpp deleted file mode 100644 index d961829a7a7..00000000000 --- a/src/gamedata/fonts/v_font.cpp +++ /dev/null @@ -1,1710 +0,0 @@ -/* -** v_font.cpp -** Font management -** -**--------------------------------------------------------------------------- -** Copyright 1998-2016 Randy Heit -** Copyright 2005-2019 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include - -#include "templates.h" -#include "doomtype.h" -#include "m_swap.h" -#include "v_font.h" -#include "v_video.h" -#include "w_wad.h" -#include "gi.h" -#include "cmdlib.h" -#include "sc_man.h" -#include "hu_stuff.h" -#include "gstrings.h" -#include "v_text.h" -#include "vm.h" -#include "image.h" -#include "utf8.h" -#include "textures/formats/fontchars.h" - -#include "fontinternals.h" - -// MACROS ------------------------------------------------------------------ - -#define DEFAULT_LOG_COLOR PalEntry(223,223,223) - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static int TranslationMapCompare (const void *a, const void *b); -void UpdateGenericUI(bool cvar); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern int PrintColors[]; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FFont *FFont::FirstFont = nullptr; -int NumTextColors; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -TArray TranslationParms[2]; -TArray TranslationLookup; -TArray TranslationColors; - -// CODE -------------------------------------------------------------------- - -uint16_t lowerforupper[65536]; -uint16_t upperforlower[65536]; -bool islowermap[65536]; -bool isuppermap[65536]; - -// This is a supposedly complete mapping of all lower <-> upper pairs. Most will most likely never be needed by Doom but this way there won't be any future surprises -static const uint16_t loweruppercase[] = { -0x0061,0x0041, -0x0062,0x0042, -0x0063,0x0043, -0x0064,0x0044, -0x0065,0x0045, -0x0066,0x0046, -0x0067,0x0047, -0x0068,0x0048, -0x0069,0x0049, -0x006A,0x004A, -0x006B,0x004B, -0x006C,0x004C, -0x006D,0x004D, -0x006E,0x004E, -0x006F,0x004F, -0x0070,0x0050, -0x0071,0x0051, -0x0072,0x0052, -0x0073,0x0053, -0x0074,0x0054, -0x0075,0x0055, -0x0076,0x0056, -0x0077,0x0057, -0x0078,0x0058, -0x0079,0x0059, -0x007A,0x005A, -0x00DF,0x1E9E, -0x00E0,0x00C0, -0x00E1,0x00C1, -0x00E2,0x00C2, -0x00E3,0x00C3, -0x00E4,0x00C4, -0x00E5,0x00C5, -0x00E6,0x00C6, -0x00E7,0x00C7, -0x00E8,0x00C8, -0x00E9,0x00C9, -0x00EA,0x00CA, -0x00EB,0x00CB, -0x00EC,0x00CC, -0x00ED,0x00CD, -0x00EE,0x00CE, -0x00EF,0x00CF, -0x00F0,0x00D0, -0x00F1,0x00D1, -0x00F2,0x00D2, -0x00F3,0x00D3, -0x00F4,0x00D4, -0x00F5,0x00D5, -0x00F6,0x00D6, -0x00F8,0x00D8, -0x00F9,0x00D9, -0x00FA,0x00DA, -0x00FB,0x00DB, -0x00FC,0x00DC, -0x00FD,0x00DD, -0x00FE,0x00DE, -0x00FF,0x0178, -0x0101,0x0100, -0x0103,0x0102, -0x0105,0x0104, -0x0107,0x0106, -0x0109,0x0108, -0x010B,0x010A, -0x010D,0x010C, -0x010F,0x010E, -0x0111,0x0110, -0x0113,0x0112, -0x0115,0x0114, -0x0117,0x0116, -0x0119,0x0118, -0x011B,0x011A, -0x011D,0x011C, -0x011F,0x011E, -0x0121,0x0120, -0x0123,0x0122, -0x0125,0x0124, -0x0127,0x0126, -0x0129,0x0128, -0x012B,0x012A, -0x012D,0x012C, -0x012F,0x012E, -0x0131,0x0049, -0x0133,0x0132, -0x0135,0x0134, -0x0137,0x0136, -0x013A,0x0139, -0x013C,0x013B, -0x013E,0x013D, -0x0140,0x013F, -0x0142,0x0141, -0x0144,0x0143, -0x0146,0x0145, -0x0148,0x0147, -0x014B,0x014A, -0x014D,0x014C, -0x014F,0x014E, -0x0151,0x0150, -0x0153,0x0152, -0x0155,0x0154, -0x0157,0x0156, -0x0159,0x0158, -0x015B,0x015A, -0x015D,0x015C, -0x015F,0x015E, -0x0161,0x0160, -0x0163,0x0162, -0x0165,0x0164, -0x0167,0x0166, -0x0169,0x0168, -0x016B,0x016A, -0x016D,0x016C, -0x016F,0x016E, -0x0171,0x0170, -0x0173,0x0172, -0x0175,0x0174, -0x0177,0x0176, -0x017A,0x0179, -0x017C,0x017B, -0x017E,0x017D, -0x0183,0x0182, -0x0185,0x0184, -0x0188,0x0187, -0x018C,0x018B, -0x0192,0x0191, -0x0199,0x0198, -0x01A1,0x01A0, -0x01A3,0x01A2, -0x01A5,0x01A4, -0x01A8,0x01A7, -0x01AD,0x01AC, -0x01B0,0x01AF, -0x01B4,0x01B3, -0x01B6,0x01B5, -0x01B9,0x01B8, -0x01BD,0x01BC, -0x01C6,0x01C4, -0x01C9,0x01C7, -0x01CC,0x01CA, -0x01CE,0x01CD, -0x01D0,0x01CF, -0x01D2,0x01D1, -0x01D4,0x01D3, -0x01D6,0x01D5, -0x01D8,0x01D7, -0x01DA,0x01D9, -0x01DC,0x01DB, -0x01DF,0x01DE, -0x01E1,0x01E0, -0x01E3,0x01E2, -0x01E5,0x01E4, -0x01E7,0x01E6, -0x01E9,0x01E8, -0x01EB,0x01EA, -0x01ED,0x01EC, -0x01EF,0x01EE, -0x01F3,0x01F1, -0x01F5,0x01F4, -0x01FB,0x01FA, -0x01FD,0x01FC, -0x01FF,0x01FE, -0x0201,0x0200, -0x0203,0x0202, -0x0205,0x0204, -0x0207,0x0206, -0x0209,0x0208, -0x020B,0x020A, -0x020D,0x020C, -0x020F,0x020E, -0x0211,0x0210, -0x0213,0x0212, -0x0215,0x0214, -0x0217,0x0216, -0x0253,0x0181, -0x0254,0x0186, -0x0257,0x018A, -0x0258,0x018E, -0x0259,0x018F, -0x025B,0x0190, -0x0260,0x0193, -0x0263,0x0194, -0x0268,0x0197, -0x0269,0x0196, -0x026F,0x019C, -0x0272,0x019D, -0x0275,0x019F, -0x0283,0x01A9, -0x0288,0x01AE, -0x028A,0x01B1, -0x028B,0x01B2, -0x0292,0x01B7, -0x03AC,0x0386, -0x03AD,0x0388, -0x03AE,0x0389, -0x03AF,0x038A, -0x03B1,0x0391, -0x03B2,0x0392, -0x03B3,0x0393, -0x03B4,0x0394, -0x03B5,0x0395, -0x03B6,0x0396, -0x03B7,0x0397, -0x03B8,0x0398, -0x03B9,0x0399, -0x03BA,0x039A, -0x03BB,0x039B, -0x03BC,0x039C, -0x03BD,0x039D, -0x03BE,0x039E, -0x03BF,0x039F, -0x03C0,0x03A0, -0x03C1,0x03A1, -0x03C3,0x03A3, -0x03C4,0x03A4, -0x03C5,0x03A5, -0x03C6,0x03A6, -0x03C7,0x03A7, -0x03C8,0x03A8, -0x03C9,0x03A9, -0x03CA,0x03AA, -0x03CB,0x03AB, -0x03CC,0x038C, -0x03CD,0x038E, -0x03CE,0x038F, -0x03E3,0x03E2, -0x03E5,0x03E4, -0x03E7,0x03E6, -0x03E9,0x03E8, -0x03EB,0x03EA, -0x03ED,0x03EC, -0x03EF,0x03EE, -0x0430,0x0410, -0x0431,0x0411, -0x0432,0x0412, -0x0433,0x0413, -0x0434,0x0414, -0x0435,0x0415, -0x0436,0x0416, -0x0437,0x0417, -0x0438,0x0418, -0x0439,0x0419, -0x043A,0x041A, -0x043B,0x041B, -0x043C,0x041C, -0x043D,0x041D, -0x043E,0x041E, -0x043F,0x041F, -0x0440,0x0420, -0x0441,0x0421, -0x0442,0x0422, -0x0443,0x0423, -0x0444,0x0424, -0x0445,0x0425, -0x0446,0x0426, -0x0447,0x0427, -0x0448,0x0428, -0x0449,0x0429, -0x044A,0x042A, -0x044B,0x042B, -0x044C,0x042C, -0x044D,0x042D, -0x044E,0x042E, -0x044F,0x042F, -0x0451,0x0401, -0x0452,0x0402, -0x0453,0x0403, -0x0454,0x0404, -0x0455,0x0405, -0x0456,0x0406, -0x0457,0x0407, -0x0458,0x0408, -0x0459,0x0409, -0x045A,0x040A, -0x045B,0x040B, -0x045C,0x040C, -0x045E,0x040E, -0x045F,0x040F, -0x0461,0x0460, -0x0463,0x0462, -0x0465,0x0464, -0x0467,0x0466, -0x0469,0x0468, -0x046B,0x046A, -0x046D,0x046C, -0x046F,0x046E, -0x0471,0x0470, -0x0473,0x0472, -0x0475,0x0474, -0x0477,0x0476, -0x0479,0x0478, -0x047B,0x047A, -0x047D,0x047C, -0x047F,0x047E, -0x0481,0x0480, -0x0491,0x0490, -0x0493,0x0492, -0x0495,0x0494, -0x0497,0x0496, -0x0499,0x0498, -0x049B,0x049A, -0x049D,0x049C, -0x049F,0x049E, -0x04A1,0x04A0, -0x04A3,0x04A2, -0x04A5,0x04A4, -0x04A7,0x04A6, -0x04A9,0x04A8, -0x04AB,0x04AA, -0x04AD,0x04AC, -0x04AF,0x04AE, -0x04B1,0x04B0, -0x04B3,0x04B2, -0x04B5,0x04B4, -0x04B7,0x04B6, -0x04B9,0x04B8, -0x04BB,0x04BA, -0x04BD,0x04BC, -0x04BF,0x04BE, -0x04C2,0x04C1, -0x04C4,0x04C3, -0x04C8,0x04C7, -0x04CC,0x04CB, -0x04D1,0x04D0, -0x04D3,0x04D2, -0x04D5,0x04D4, -0x04D7,0x04D6, -0x04D9,0x04D8, -0x04DB,0x04DA, -0x04DD,0x04DC, -0x04DF,0x04DE, -0x04E1,0x04E0, -0x04E3,0x04E2, -0x04E5,0x04E4, -0x04E7,0x04E6, -0x04E9,0x04E8, -0x04EB,0x04EA, -0x04EF,0x04EE, -0x04F1,0x04F0, -0x04F3,0x04F2, -0x04F5,0x04F4, -0x04F9,0x04F8, -0x0561,0x0531, -0x0562,0x0532, -0x0563,0x0533, -0x0564,0x0534, -0x0565,0x0535, -0x0566,0x0536, -0x0567,0x0537, -0x0568,0x0538, -0x0569,0x0539, -0x056A,0x053A, -0x056B,0x053B, -0x056C,0x053C, -0x056D,0x053D, -0x056E,0x053E, -0x056F,0x053F, -0x0570,0x0540, -0x0571,0x0541, -0x0572,0x0542, -0x0573,0x0543, -0x0574,0x0544, -0x0575,0x0545, -0x0576,0x0546, -0x0577,0x0547, -0x0578,0x0548, -0x0579,0x0549, -0x057A,0x054A, -0x057B,0x054B, -0x057C,0x054C, -0x057D,0x054D, -0x057E,0x054E, -0x057F,0x054F, -0x0580,0x0550, -0x0581,0x0551, -0x0582,0x0552, -0x0583,0x0553, -0x0584,0x0554, -0x0585,0x0555, -0x0586,0x0556, -0x10D0,0x10A0, -0x10D1,0x10A1, -0x10D2,0x10A2, -0x10D3,0x10A3, -0x10D4,0x10A4, -0x10D5,0x10A5, -0x10D6,0x10A6, -0x10D7,0x10A7, -0x10D8,0x10A8, -0x10D9,0x10A9, -0x10DA,0x10AA, -0x10DB,0x10AB, -0x10DC,0x10AC, -0x10DD,0x10AD, -0x10DE,0x10AE, -0x10DF,0x10AF, -0x10E0,0x10B0, -0x10E1,0x10B1, -0x10E2,0x10B2, -0x10E3,0x10B3, -0x10E4,0x10B4, -0x10E5,0x10B5, -0x10E6,0x10B6, -0x10E7,0x10B7, -0x10E8,0x10B8, -0x10E9,0x10B9, -0x10EA,0x10BA, -0x10EB,0x10BB, -0x10EC,0x10BC, -0x10ED,0x10BD, -0x10EE,0x10BE, -0x10EF,0x10BF, -0x10F0,0x10C0, -0x10F1,0x10C1, -0x10F2,0x10C2, -0x10F3,0x10C3, -0x10F4,0x10C4, -0x10F5,0x10C5, -0x1E01,0x1E00, -0x1E03,0x1E02, -0x1E05,0x1E04, -0x1E07,0x1E06, -0x1E09,0x1E08, -0x1E0B,0x1E0A, -0x1E0D,0x1E0C, -0x1E0F,0x1E0E, -0x1E11,0x1E10, -0x1E13,0x1E12, -0x1E15,0x1E14, -0x1E17,0x1E16, -0x1E19,0x1E18, -0x1E1B,0x1E1A, -0x1E1D,0x1E1C, -0x1E1F,0x1E1E, -0x1E21,0x1E20, -0x1E23,0x1E22, -0x1E25,0x1E24, -0x1E27,0x1E26, -0x1E29,0x1E28, -0x1E2B,0x1E2A, -0x1E2D,0x1E2C, -0x1E2F,0x1E2E, -0x1E31,0x1E30, -0x1E33,0x1E32, -0x1E35,0x1E34, -0x1E37,0x1E36, -0x1E39,0x1E38, -0x1E3B,0x1E3A, -0x1E3D,0x1E3C, -0x1E3F,0x1E3E, -0x1E41,0x1E40, -0x1E43,0x1E42, -0x1E45,0x1E44, -0x1E47,0x1E46, -0x1E49,0x1E48, -0x1E4B,0x1E4A, -0x1E4D,0x1E4C, -0x1E4F,0x1E4E, -0x1E51,0x1E50, -0x1E53,0x1E52, -0x1E55,0x1E54, -0x1E57,0x1E56, -0x1E59,0x1E58, -0x1E5B,0x1E5A, -0x1E5D,0x1E5C, -0x1E5F,0x1E5E, -0x1E61,0x1E60, -0x1E63,0x1E62, -0x1E65,0x1E64, -0x1E67,0x1E66, -0x1E69,0x1E68, -0x1E6B,0x1E6A, -0x1E6D,0x1E6C, -0x1E6F,0x1E6E, -0x1E71,0x1E70, -0x1E73,0x1E72, -0x1E75,0x1E74, -0x1E77,0x1E76, -0x1E79,0x1E78, -0x1E7B,0x1E7A, -0x1E7D,0x1E7C, -0x1E7F,0x1E7E, -0x1E81,0x1E80, -0x1E83,0x1E82, -0x1E85,0x1E84, -0x1E87,0x1E86, -0x1E89,0x1E88, -0x1E8B,0x1E8A, -0x1E8D,0x1E8C, -0x1E8F,0x1E8E, -0x1E91,0x1E90, -0x1E93,0x1E92, -0x1E95,0x1E94, -0x1EA1,0x1EA0, -0x1EA3,0x1EA2, -0x1EA5,0x1EA4, -0x1EA7,0x1EA6, -0x1EA9,0x1EA8, -0x1EAB,0x1EAA, -0x1EAD,0x1EAC, -0x1EAF,0x1EAE, -0x1EB1,0x1EB0, -0x1EB3,0x1EB2, -0x1EB5,0x1EB4, -0x1EB7,0x1EB6, -0x1EB9,0x1EB8, -0x1EBB,0x1EBA, -0x1EBD,0x1EBC, -0x1EBF,0x1EBE, -0x1EC1,0x1EC0, -0x1EC3,0x1EC2, -0x1EC5,0x1EC4, -0x1EC7,0x1EC6, -0x1EC9,0x1EC8, -0x1ECB,0x1ECA, -0x1ECD,0x1ECC, -0x1ECF,0x1ECE, -0x1ED1,0x1ED0, -0x1ED3,0x1ED2, -0x1ED5,0x1ED4, -0x1ED7,0x1ED6, -0x1ED9,0x1ED8, -0x1EDB,0x1EDA, -0x1EDD,0x1EDC, -0x1EDF,0x1EDE, -0x1EE1,0x1EE0, -0x1EE3,0x1EE2, -0x1EE5,0x1EE4, -0x1EE7,0x1EE6, -0x1EE9,0x1EE8, -0x1EEB,0x1EEA, -0x1EED,0x1EEC, -0x1EEF,0x1EEE, -0x1EF1,0x1EF0, -0x1EF3,0x1EF2, -0x1EF5,0x1EF4, -0x1EF7,0x1EF6, -0x1EF9,0x1EF8, -0x1F00,0x1F08, -0x1F01,0x1F09, -0x1F02,0x1F0A, -0x1F03,0x1F0B, -0x1F04,0x1F0C, -0x1F05,0x1F0D, -0x1F06,0x1F0E, -0x1F07,0x1F0F, -0x1F10,0x1F18, -0x1F11,0x1F19, -0x1F12,0x1F1A, -0x1F13,0x1F1B, -0x1F14,0x1F1C, -0x1F15,0x1F1D, -0x1F20,0x1F28, -0x1F21,0x1F29, -0x1F22,0x1F2A, -0x1F23,0x1F2B, -0x1F24,0x1F2C, -0x1F25,0x1F2D, -0x1F26,0x1F2E, -0x1F27,0x1F2F, -0x1F30,0x1F38, -0x1F31,0x1F39, -0x1F32,0x1F3A, -0x1F33,0x1F3B, -0x1F34,0x1F3C, -0x1F35,0x1F3D, -0x1F36,0x1F3E, -0x1F37,0x1F3F, -0x1F40,0x1F48, -0x1F41,0x1F49, -0x1F42,0x1F4A, -0x1F43,0x1F4B, -0x1F44,0x1F4C, -0x1F45,0x1F4D, -0x1F51,0x1F59, -0x1F53,0x1F5B, -0x1F55,0x1F5D, -0x1F57,0x1F5F, -0x1F60,0x1F68, -0x1F61, 0x1F69, -0x1F62, 0x1F6A, -0x1F63, 0x1F6B, -0x1F64, 0x1F6C, -0x1F65, 0x1F6D, -0x1F66, 0x1F6E, -0x1F67, 0x1F6F, -0x1F80, 0x1F88, -0x1F81, 0x1F89, -0x1F82, 0x1F8A, -0x1F83, 0x1F8B, -0x1F84, 0x1F8C, -0x1F85, 0x1F8D, -0x1F86, 0x1F8E, -0x1F87, 0x1F8F, -0x1F90, 0x1F98, -0x1F91, 0x1F99, -0x1F92, 0x1F9A, -0x1F93, 0x1F9B, -0x1F94, 0x1F9C, -0x1F95, 0x1F9D, -0x1F96, 0x1F9E, -0x1F97, 0x1F9F, -0x1FA0, 0x1FA8, -0x1FA1, 0x1FA9, -0x1FA2, 0x1FAA, -0x1FA3, 0x1FAB, -0x1FA4, 0x1FAC, -0x1FA5, 0x1FAD, -0x1FA6, 0x1FAE, -0x1FA7, 0x1FAF, -0x1FB0, 0x1FB8, -0x1FB1, 0x1FB9, -0x1FD0, 0x1FD8, -0x1FD1, 0x1FD9, -0x1FE0, 0x1FE8, -0x1FE1, 0x1FE9, -0x24D0, 0x24B6, -0x24D1, 0x24B7, -0x24D2, 0x24B8, -0x24D3, 0x24B9, -0x24D4, 0x24BA, -0x24D5, 0x24BB, -0x24D6, 0x24BC, -0x24D7, 0x24BD, -0x24D8, 0x24BE, -0x24D9, 0x24BF, -0x24DA, 0x24C0, -0x24DB, 0x24C1, -0x24DC, 0x24C2, -0x24DD, 0x24C3, -0x24DE, 0x24C4, -0x24DF, 0x24C5, -0x24E0, 0x24C6, -0x24E1, 0x24C7, -0x24E2, 0x24C8, -0x24E3, 0x24C9, -0x24E4, 0x24CA, -0x24E5, 0x24CB, -0x24E6, 0x24CC, -0x24E7, 0x24CD, -0x24E8, 0x24CE, -0x24E9, 0x24CF, -0xFF41, 0xFF21, -0xFF42, 0xFF22, -0xFF43, 0xFF23, -0xFF44, 0xFF24, -0xFF45, 0xFF25, -0xFF46, 0xFF26, -0xFF47, 0xFF27, -0xFF48, 0xFF28, -0xFF49, 0xFF29, -0xFF4A, 0xFF2A, -0xFF4B, 0xFF2B, -0xFF4C, 0xFF2C, -0xFF4D, 0xFF2D, -0xFF4E, 0xFF2E, -0xFF4F, 0xFF2F, -0xFF50, 0xFF30, -0xFF51, 0xFF31, -0xFF52, 0xFF32, -0xFF53, 0xFF33, -0xFF54, 0xFF34, -0xFF55, 0xFF35, -0xFF56, 0xFF36, -0xFF57, 0xFF37, -0xFF58, 0xFF38, -0xFF59, 0xFF39, -0xFF5A, 0xFF3A, -0, 0 -}; - -void InitLowerUpper() -{ - for (int i = 0; i < 65536; i++) - { - lowerforupper[i] = i; - upperforlower[i] = i; - } - for (int i = 0; loweruppercase[i]; i += 2) - { - auto lower = loweruppercase[i]; - auto upper = loweruppercase[i + 1]; - if (lowerforupper[upper] == upper) lowerforupper[upper] = lower; // This mapping is ambiguous (see 0x0131 -> 0x0049, (small Turkish 'i' without dot.) so only pick the first match. - if (upperforlower[lower] == lower) upperforlower[lower] = upper; - isuppermap[upper] = islowermap[lower] = true; - } - // Special treatment for the two variants of the small sigma in Greek. - islowermap[0x3c2] = true; - upperforlower[0x3c2] = 0x3a3; -} - - -bool myislower(int code) -{ - if (code >= 0 && code < 65536) return islowermap[code]; - return false; -} - -bool myisupper(int code) -{ - if (code >= 0 && code < 65536) return isuppermap[code]; - return false; -} - - -// Returns a character without an accent mark (or one with a similar looking accent in some cases where direct support is unlikely.) - -int stripaccent(int code) -{ - if (code < 0x8a) - return code; - if (code < 0x100) - { - if (code == 0x8a) // Latin capital letter S with caron - return 'S'; - if (code == 0x8e) // Latin capital letter Z with caron - return 'Z'; - if (code == 0x9a) // Latin small letter S with caron - return 's'; - if (code == 0x9e) // Latin small letter Z with caron - return 'z'; - if (code == 0x9f) // Latin capital letter Y with diaeresis - return 'Y'; - if (code == 0xab || code == 0xbb) return '"'; // typographic quotation marks. - if (code == 0xff) // Latin small letter Y with diaeresis - return 'y'; - // Every other accented character has the high two bits set. - if ((code & 0xC0) == 0) - return code; - // Make lowercase characters uppercase so there are half as many tests. - int acode = code & 0xDF; - if (acode >= 0xC0 && acode <= 0xC5) // A with accents - return 'A' + (code & 0x20); - if (acode == 0xC7) // Cedilla - return 'C' + (acode & 0x20); - if (acode >= 0xC8 && acode <= 0xCB) // E with accents - return 'E' + (code & 0x20); - if (acode >= 0xCC && acode <= 0xCF) // I with accents - return 'I' + (code & 0x20); - if (acode == 0xD0) // Eth - return 'D' + (code & 0x20); - if (acode == 0xD1) // N with tilde - return 'N' + (code & 0x20); - if ((acode >= 0xD2 && acode <= 0xD6) || // O with accents - acode == 0xD8) // O with stroke - return 'O' + (code & 0x20); - if (acode >= 0xD9 && acode <= 0xDC) // U with accents - return 'U' + (code & 0x20); - if (acode == 0xDD) // Y with accute - return 'Y' + (code & 0x20); - if (acode == 0xDE) // Thorn - return 'P' + (code & 0x20); // well, it sort of looks like a 'P' - } - else if (code >= 0x100 && code < 0x180) - { - // For the double-accented Hungarian letters it makes more sense to first map them to the very similar looking Umlauts. - // (And screw the crappy specs that do not allow UTF-8 multibyte character literals here.) - if (code == 0x150) code = 0xd6; - else if (code == 0x151) code = 0xf6; - else if (code == 0x170) code = 0xdc; - else if (code == 0x171) code = 0xfc; - else - { - static const char accentless[] = "AaAaAaCcCcCcCcDdDdEeEeEeEeEeGgGgGgGgHhHhIiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnnNnOoOoOoOoRrRrRrSsSsSsSsTtTtTtUuUuUuUuUuUuWwYyYZzZzZzs"; - return accentless[code - 0x100]; - } - } - else if (code >= 0x200 && code < 0x218) - { - // 0x200-0x217 are irrelevant but easy to map to other characters more likely to exist. - static const uint16_t u200map[] = {0xc4, 0xe4, 0xc2, 0xe2, 0xcb, 0xeb, 0xca, 0xea, 0xcf, 0xef, 0xce, 0xee, 0xd6, 0xf6, 0xd4, 0xe4, 'R', 'r', 'R', 'r', 0xdc, 0xfc, 0xdb, 0xfb}; - return u200map[code - 0x200]; - } - return getAlternative(code); -} - -int getAlternative(int code) -{ - // This is for determining replacements that do not make CanPrint fail. - switch (code) - { - default: - return code; - - case 0x17f: return 's'; // The 'long s' can be safely remapped to the regular variant, not that this gets used in any real text... - case 0x218: return 0x15e; // Romanian S with comma below may get remapped to S with cedilla. - case 0x219: return 0x15f; - case 0x21a: return 0x162; // Romanian T with comma below may get remapped to T with cedilla. - case 0x21b: return 0x163; - case 0x386: return 0x391; // Greek characters with accents must map to their base form due to the "no accents in allcaps " rule. - case 0x388: return 0x395; - case 0x389: return 0x397; - case 0x38a: return 0x399; - case 0x38c: return 0x39f; - case 0x3a0: return 0x41f; - case 0x38e: return 0x3a5; - case 0x38f: return 0x3a9; - case 0x391: return 'A';// Greek characters with equivalents in either Latin or Cyrillic. This is only suitable for uppercase fonts! - case 0x392: return 'B'; - case 0x393: return 0x413; - case 0x395: return 'E'; - case 0x396: return 'Z'; - case 0x397: return 'H'; - case 0x399: return 'I'; - case 0x39a: return 'K'; - case 0x39c: return 'M'; - case 0x39d: return 'N'; - case 0x39f: return 'O'; - case 0x3a1: return 'P'; - case 0x3a4: return 'T'; - case 0x3a5: return 'Y'; - case 0x3a6: return 0x424; - case 0x3a7: return 'X'; - case 0x3aa: return 0xcf; - case 0x3ab: return 0x178; - case 0x3bf: return 'o'; // the Omicron is the only small Greek character that's easily mappable to a Latin equivalent. :( - case 0x3c2: return 0x3c3; // Lowercase Sigma character in Greek, which changes depending on its positioning in a word; if the font is uppercase only or features a smallcaps style, the second variant of the letter will remain unused - case 0x390: return 0x3ca; // For smallcaps fonts the small accented Greek characters remap to the unaccented versions. - case 0x3ac: return 0x3b1; - case 0x3ad: return 0x3b5; - case 0x3ae: return 0x3b7; - case 0x3af: return 0x3b9; - case 0x3b0: return 0x3cb; - case 0x3cc: return 0x3bf; - case 0x3cd: return 0x3c5; - case 0x3ce: return 0x3c9; - case 0x400: return 0xc8; // Cyrillic characters with equivalents in the Latin alphabet. - case 0x401: return 0xcb; - case 0x405: return 'S'; - case 0x406: return 'I'; - case 0x407: return 0xcf; - case 0x408: return 'J'; - case 0x450: return 0xe8; - case 0x451: return 0xeb; - case 0x455: return 's'; - case 0x456: return 'i'; - case 0x457: return 0xef; - case 0x458: return 'j'; - } - return code; -} - - -FFont *V_GetFont(const char *name, const char *fontlumpname) -{ - if (!stricmp(name, "DBIGFONT")) name = "BigFont"; - else if (!stricmp(name, "CONFONT")) name = "ConsoleFont"; // several mods have used the name CONFONT directly and effectively duplicated the font. - FFont *font = FFont::FindFont (name); - if (font == nullptr) - { - if (!stricmp(name, "BIGUPPER")) - { - font = FFont::FindFont("BIGFONT"); - if (font) return font; - } - - int lump = -1; - int folderfile = -1; - - TArray folderdata; - FStringf path("fonts/%s/", name); - - // Use a folder-based font only if it comes from a later file than the single lump version. - if (Wads.GetLumpsInFolder(path, folderdata, true)) - { - // This assumes that any custom font comes in one piece and not distributed across multiple resource files. - folderfile = Wads.GetLumpFile(folderdata[0].lumpnum); - } - - - lump = Wads.CheckNumForFullName(fontlumpname? fontlumpname : name, true); - - if (lump != -1 && Wads.GetLumpFile(lump) >= folderfile) - { - uint32_t head; - { - auto lumpy = Wads.OpenLumpReader (lump); - lumpy.Read (&head, 4); - } - if ((head & MAKE_ID(255,255,255,0)) == MAKE_ID('F','O','N',0) || - head == MAKE_ID(0xE1,0xE6,0xD5,0x1A)) - { - FFont *CreateSingleLumpFont (const char *fontname, int lump); - return CreateSingleLumpFont (name, lump); - } - } - FTextureID picnum = TexMan.CheckForTexture (name, ETextureType::Any); - if (picnum.isValid()) - { - FTexture *tex = TexMan.GetTexture(picnum); - if (tex && tex->GetSourceLump() >= folderfile) - { - FFont *CreateSinglePicFont(const char *name); - return CreateSinglePicFont (name); - } - } - if (folderdata.Size() > 0) - { - return new FFont(name, nullptr, name, HU_FONTSTART, HU_FONTSIZE, 1, -1); - } - } - return font; -} - -//========================================================================== -// -// V_InitCustomFonts -// -// Initialize a list of custom multipatch fonts -// -//========================================================================== - -void V_InitCustomFonts() -{ - FScanner sc; - FTexture *lumplist[256]; - bool notranslate[256]; - bool donttranslate; - FString namebuffer, templatebuf; - int i; - int llump,lastlump=0; - int format; - int start; - int first; - int count; - int spacewidth; - int kerning; - char cursor = '_'; - - while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1) - { - sc.OpenLumpNum(llump); - while (sc.GetString()) - { - memset (lumplist, 0, sizeof(lumplist)); - memset (notranslate, 0, sizeof(notranslate)); - donttranslate = false; - namebuffer = sc.String; - format = 0; - start = 33; - first = 33; - count = 223; - spacewidth = -1; - kerning = 0; - - sc.MustGetStringName ("{"); - while (!sc.CheckString ("}")) - { - sc.MustGetString(); - if (sc.Compare ("TEMPLATE")) - { - if (format == 2) goto wrong; - sc.MustGetString(); - templatebuf = sc.String; - format = 1; - } - else if (sc.Compare ("BASE")) - { - if (format == 2) goto wrong; - sc.MustGetNumber(); - start = sc.Number; - format = 1; - } - else if (sc.Compare ("FIRST")) - { - if (format == 2) goto wrong; - sc.MustGetNumber(); - first = sc.Number; - format = 1; - } - else if (sc.Compare ("COUNT")) - { - if (format == 2) goto wrong; - sc.MustGetNumber(); - count = sc.Number; - format = 1; - } - else if (sc.Compare ("CURSOR")) - { - sc.MustGetString(); - cursor = sc.String[0]; - } - else if (sc.Compare ("SPACEWIDTH")) - { - if (format == 2) goto wrong; - sc.MustGetNumber(); - spacewidth = sc.Number; - format = 1; - } - else if (sc.Compare("DONTTRANSLATE")) - { - donttranslate = true; - } - else if (sc.Compare ("NOTRANSLATION")) - { - if (format == 1) goto wrong; - while (sc.CheckNumber() && !sc.Crossed) - { - if (sc.Number >= 0 && sc.Number < 256) - notranslate[sc.Number] = true; - } - format = 2; - } - else if (sc.Compare("KERNING")) - { - sc.MustGetNumber(); - kerning = sc.Number; - } - else - { - if (format == 1) goto wrong; - FTexture **p = &lumplist[*(unsigned char*)sc.String]; - sc.MustGetString(); - FTextureID texid = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); - if (texid.Exists()) - { - *p = TexMan.GetTexture(texid); - } - else if (Wads.GetLumpFile(sc.LumpNum) >= Wads.GetIwadNum()) - { - // Print a message only if this isn't in zdoom.pk3 - sc.ScriptMessage("%s: Unable to find texture in font definition for %s", sc.String, namebuffer.GetChars()); - } - format = 2; - } - } - if (format == 1) - { - FFont *fnt = new FFont (namebuffer, templatebuf, nullptr, first, count, start, llump, spacewidth, donttranslate); - fnt->SetCursor(cursor); - fnt->SetKerning(kerning); - } - else if (format == 2) - { - for (i = 0; i < 256; i++) - { - if (lumplist[i] != nullptr) - { - first = i; - break; - } - } - for (i = 255; i >= 0; i--) - { - if (lumplist[i] != nullptr) - { - count = i - first + 1; - break; - } - } - if (count > 0) - { - FFont *CreateSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); - FFont *fnt = CreateSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump, donttranslate); - fnt->SetCursor(cursor); - fnt->SetKerning(kerning); - } - } - else goto wrong; - } - sc.Close(); - } - return; - -wrong: - sc.ScriptError ("Invalid combination of properties in font '%s'", namebuffer.GetChars()); -} - -//========================================================================== -// -// V_InitFontColors -// -// Reads the list of color translation definitions into memory. -// -//========================================================================== - -void V_InitFontColors () -{ - TArray names; - int lump, lastlump = 0; - TranslationParm tparm = { 0, 0, {0}, {0} }; // Silence GCC (for real with -Wextra ) - TArray parms; - TArray parminfo; - TArray colorinfo; - int c, parmchoice; - TempParmInfo info; - TempColorInfo cinfo; - PalEntry logcolor; - unsigned int i, j; - int k, index; - - info.Index = -1; - - TranslationParms[0].Clear(); - TranslationParms[1].Clear(); - TranslationLookup.Clear(); - TranslationColors.Clear(); - - while ((lump = Wads.FindLump ("TEXTCOLO", &lastlump)) != -1) - { - FScanner sc(lump); - while (sc.GetString()) - { - names.Clear(); - - logcolor = DEFAULT_LOG_COLOR; - - // Everything until the '{' is considered a valid name for the - // color range. - names.Push (sc.String); - while (sc.MustGetString(), !sc.Compare ("{")) - { - if (names[0] == NAME_Untranslated) - { - sc.ScriptError ("The \"untranslated\" color may not have any other names"); - } - names.Push (sc.String); - } - - parmchoice = 0; - info.StartParm[0] = parms.Size(); - info.StartParm[1] = 0; - info.ParmLen[1] = info.ParmLen[0] = 0; - tparm.RangeEnd = tparm.RangeStart = -1; - - while (sc.MustGetString(), !sc.Compare ("}")) - { - if (sc.Compare ("Console:")) - { - if (parmchoice == 1) - { - sc.ScriptError ("Each color may only have one set of console ranges"); - } - parmchoice = 1; - info.StartParm[1] = parms.Size(); - info.ParmLen[0] = info.StartParm[1] - info.StartParm[0]; - tparm.RangeEnd = tparm.RangeStart = -1; - } - else if (sc.Compare ("Flat:")) - { - sc.MustGetString(); - logcolor = V_GetColor (nullptr, sc); - } - else - { - // Get first color - c = V_GetColor (nullptr, sc); - tparm.Start[0] = RPART(c); - tparm.Start[1] = GPART(c); - tparm.Start[2] = BPART(c); - - // Get second color - sc.MustGetString(); - c = V_GetColor (nullptr, sc); - tparm.End[0] = RPART(c); - tparm.End[1] = GPART(c); - tparm.End[2] = BPART(c); - - // Check for range specifier - if (sc.CheckNumber()) - { - if (tparm.RangeStart == -1 && sc.Number != 0) - { - sc.ScriptError ("The first color range must start at position 0"); - } - if (sc.Number < 0 || sc.Number > 256) - { - sc.ScriptError ("The color range must be within positions [0,256]"); - } - if (sc.Number <= tparm.RangeEnd) - { - sc.ScriptError ("The color range must not start before the previous one ends"); - } - tparm.RangeStart = sc.Number; - - sc.MustGetNumber(); - if (sc.Number < 0 || sc.Number > 256) - { - sc.ScriptError ("The color range must be within positions [0,256]"); - } - if (sc.Number <= tparm.RangeStart) - { - sc.ScriptError ("The color range end position must be larger than the start position"); - } - tparm.RangeEnd = sc.Number; - } - else - { - tparm.RangeStart = tparm.RangeEnd + 1; - tparm.RangeEnd = 256; - if (tparm.RangeStart >= tparm.RangeEnd) - { - sc.ScriptError ("The color has too many ranges"); - } - } - parms.Push (tparm); - } - } - info.ParmLen[parmchoice] = parms.Size() - info.StartParm[parmchoice]; - if (info.ParmLen[0] == 0) - { - if (names[0] != NAME_Untranslated) - { - sc.ScriptError ("There must be at least one normal range for a color"); - } - } - else - { - if (names[0] == NAME_Untranslated) - { - sc.ScriptError ("The \"untranslated\" color must be left undefined"); - } - } - if (info.ParmLen[1] == 0 && names[0] != NAME_Untranslated) - { // If a console translation is unspecified, make it white, since the console - // font has no color information stored with it. - tparm.RangeStart = 0; - tparm.RangeEnd = 256; - tparm.Start[2] = tparm.Start[1] = tparm.Start[0] = 0; - tparm.End[2] = tparm.End[1] = tparm.End[0] = 255; - info.StartParm[1] = parms.Push (tparm); - info.ParmLen[1] = 1; - } - cinfo.ParmInfo = parminfo.Push (info); - // Record this color information for each name it goes by - for (i = 0; i < names.Size(); ++i) - { - // Redefine duplicates in-place - for (j = 0; j < colorinfo.Size(); ++j) - { - if (colorinfo[j].Name == names[i]) - { - colorinfo[j].ParmInfo = cinfo.ParmInfo; - colorinfo[j].LogColor = logcolor; - break; - } - } - if (j == colorinfo.Size()) - { - cinfo.Name = names[i]; - cinfo.LogColor = logcolor; - colorinfo.Push (cinfo); - } - } - } - } - // Make permananent copies of all the color information we found. - for (i = 0, index = 0; i < colorinfo.Size(); ++i) - { - TranslationMap tmap; - TempParmInfo *pinfo; - - tmap.Name = colorinfo[i].Name; - pinfo = &parminfo[colorinfo[i].ParmInfo]; - if (pinfo->Index < 0) - { - // Write out the set of remappings for this color. - for (k = 0; k < 2; ++k) - { - for (j = 0; j < pinfo->ParmLen[k]; ++j) - { - TranslationParms[k].Push (parms[pinfo->StartParm[k] + j]); - } - } - TranslationColors.Push (colorinfo[i].LogColor); - pinfo->Index = index++; - } - tmap.Number = pinfo->Index; - TranslationLookup.Push (tmap); - } - // Leave a terminating marker at the ends of the lists. - tparm.RangeStart = -1; - TranslationParms[0].Push (tparm); - TranslationParms[1].Push (tparm); - // Sort the translation lookups for fast binary searching. - qsort (&TranslationLookup[0], TranslationLookup.Size(), sizeof(TranslationLookup[0]), TranslationMapCompare); - - NumTextColors = index; - assert (NumTextColors >= NUM_TEXT_COLORS); -} - -//========================================================================== -// -// TranslationMapCompare -// -//========================================================================== - -static int TranslationMapCompare (const void *a, const void *b) -{ - return int(((const TranslationMap *)a)->Name) - int(((const TranslationMap *)b)->Name); -} - -//========================================================================== -// -// V_FindFontColor -// -// Returns the color number for a particular named color range. -// -//========================================================================== - -EColorRange V_FindFontColor (FName name) -{ - int min = 0, max = TranslationLookup.Size() - 1; - - while (min <= max) - { - unsigned int mid = (min + max) / 2; - const TranslationMap *probe = &TranslationLookup[mid]; - if (probe->Name == name) - { - return EColorRange(probe->Number); - } - else if (probe->Name < name) - { - min = mid + 1; - } - else - { - max = mid - 1; - } - } - return CR_UNTRANSLATED; -} - -//========================================================================== -// -// V_LogColorFromColorRange -// -// Returns the color to use for text in the startup/error log window. -// -//========================================================================== - -PalEntry V_LogColorFromColorRange (EColorRange range) -{ - if ((unsigned int)range >= TranslationColors.Size()) - { // Return default color - return DEFAULT_LOG_COLOR; - } - return TranslationColors[range]; -} - -//========================================================================== -// -// V_ParseFontColor -// -// Given a pointer to a color identifier (presumably just after a color -// escape character), return the color it identifies and advances -// color_value to just past it. -// -//========================================================================== - -EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int boldcolor) -{ - const uint8_t *ch = color_value; - int newcolor = *ch++; - - if (newcolor == '-') // Normal - { - newcolor = normalcolor; - } - else if (newcolor == '+') // Bold - { - newcolor = boldcolor; - } - else if (newcolor == '!') // Team chat - { - newcolor = PrintColors[PRINT_TEAMCHAT]; - } - else if (newcolor == '*') // Chat - { - newcolor = PrintColors[PRINT_CHAT]; - } - else if (newcolor == '[') // Named - { - const uint8_t *namestart = ch; - while (*ch != ']' && *ch != '\0') - { - ch++; - } - FName rangename((const char *)namestart, int(ch - namestart), true); - if (*ch != '\0') - { - ch++; - } - newcolor = V_FindFontColor (rangename); - } - else if (newcolor >= 'A' && newcolor < NUM_TEXT_COLORS + 'A') // Standard, uppercase - { - newcolor -= 'A'; - } - else if (newcolor >= 'a' && newcolor < NUM_TEXT_COLORS + 'a') // Standard, lowercase - { - newcolor -= 'a'; - } - else // Incomplete! - { - color_value = ch - (newcolor == '\0'); - return CR_UNDEFINED; - } - color_value = ch; - return EColorRange(newcolor); -} - -//========================================================================== -// -// V_InitFonts -// -//========================================================================== - -void V_InitFonts() -{ - InitLowerUpper(); - V_InitCustomFonts(); - - FFont *CreateHexLumpFont(const char *fontname, int lump); - FFont *CreateHexLumpFont2(const char *fontname, int lump); - - auto lump = Wads.CheckNumForFullName("newconsolefont.hex", 0); // This is always loaded from gzdoom.pk3 to prevent overriding it with incomplete replacements. - if (lump == -1) I_FatalError("newconsolefont.hex not found"); // This font is needed - do not start up without it. - NewConsoleFont = CreateHexLumpFont("NewConsoleFont", lump); - NewSmallFont = CreateHexLumpFont2("NewSmallFont", lump); - CurrentConsoleFont = NewConsoleFont; - - // load the heads-up font - if (!(SmallFont = V_GetFont("SmallFont", "SMALLFNT"))) - { - if (Wads.CheckNumForName("FONTA_S") >= 0) - { - int wadfile = -1; - auto a = Wads.CheckNumForName("FONTA33", ns_graphics); - if (a != -1) wadfile = Wads.GetLumpFile(a); - if (wadfile > Wads.GetIwadNum()) - { - // The font has been replaced, so we need to create a copy of the original as well. - SmallFont = new FFont("SmallFont", "FONTA%02u", nullptr, HU_FONTSTART, HU_FONTSIZE, 1, -1); - SmallFont->SetCursor('['); - } - else - { - SmallFont = new FFont("SmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1); - SmallFont->SetCursor('['); - } - } - else if (Wads.CheckNumForName("STCFN033", ns_graphics) >= 0) - { - int wadfile = -1; - auto a = Wads.CheckNumForName("STCFN065", ns_graphics); - if (a != -1) wadfile = Wads.GetLumpFile(a); - if (wadfile > Wads.GetIwadNum()) - { - // The font has been replaced, so we need to create a copy of the original as well. - SmallFont = new FFont("SmallFont", "STCFN%.3d", nullptr, HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); - } - else - { - SmallFont = new FFont("SmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); - } - } - } - - // Create the original small font as a fallback for incomplete definitions. - if (Wads.CheckNumForName("FONTA_S") >= 0) - { - OriginalSmallFont = new FFont("OriginalSmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); - OriginalSmallFont->SetCursor('['); - } - else if (Wads.CheckNumForName("STCFN033", ns_graphics) >= 0) - { - OriginalSmallFont = new FFont("OriginalSmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, true); - } - - if (SmallFont) - { - uint32_t colors[256] = {}; - SmallFont->RecordAllTextureColors(colors); - if (OriginalSmallFont != nullptr) OriginalSmallFont->SetDefaultTranslation(colors); - NewSmallFont->SetDefaultTranslation(colors); - } - - if (!(SmallFont2 = V_GetFont("SmallFont2"))) // Only used by Strife - { - if (Wads.CheckNumForName("STBFN033", ns_graphics) >= 0) - { - SmallFont2 = new FFont("SmallFont2", "STBFN%.3d", "defsmallfont2", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1); - } - } - - //This must be read before BigFont so that it can be properly substituted. - BigUpper = V_GetFont("BigUpper"); - - if (!(BigFont = V_GetFont("BigFont"))) - { - if (Wads.CheckNumForName("FONTB_S") >= 0) - { - BigFont = new FFont("BigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1); - } - } - - if (!BigFont) - { - // Load the generic fallback if no BigFont is found. - BigFont = V_GetFont("BigFont", "ZBIGFONT"); - } - - if (gameinfo.gametype & GAME_Raven) - { - OriginalBigFont = new FFont("OriginalBigFont", "FONTB%02u", "defbigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); - } - else - { - OriginalBigFont = new FFont("OriginalBigFont", nullptr, "bigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true); - } - - if (BigFont) - { - uint32_t colors[256] = {}; - BigFont->RecordAllTextureColors(colors); - if (OriginalBigFont != nullptr) OriginalBigFont->SetDefaultTranslation(colors); - } - - // let PWAD BIGFONTs override the stock BIGUPPER font. (This check needs to be made smarter.) - if (BigUpper && BigFont->Type != FFont::Folder && BigUpper->Type == FFont::Folder) - { - delete BigUpper; - BigUpper = BigFont; - } - - if (BigUpper == nullptr) - { - BigUpper = BigFont; - } - if (!(ConFont = V_GetFont("ConsoleFont", "CONFONT"))) - { - ConFont = SmallFont; - } - if (!(IntermissionFont = FFont::FindFont("IntermissionFont"))) - { - if (gameinfo.gametype & GAME_DoomChex) - { - IntermissionFont = FFont::FindFont("IntermissionFont_Doom"); - } - if (IntermissionFont == nullptr) - { - IntermissionFont = BigFont; - } - } - // This can only happen if gzdoom.pk3 is corrupted. ConFont should always be present. - if (ConFont == nullptr) - { - I_FatalError("Console font not found."); - } - // SmallFont and SmallFont2 have no default provided by the engine. BigFont only has in non-Raven games. - if (OriginalSmallFont == nullptr) - { - OriginalSmallFont = ConFont; - } - if (SmallFont == nullptr) - { - SmallFont = OriginalSmallFont; - } - if (SmallFont2 == nullptr) - { - SmallFont2 = SmallFont; - } - if (BigFont == nullptr) - { - BigFont = OriginalBigFont; - } - AlternativeSmallFont = OriginalSmallFont; - UpdateGenericUI(false); -} - -void V_ClearFonts() -{ - while (FFont::FirstFont != nullptr) - { - delete FFont::FirstFont; - } - FFont::FirstFont = nullptr; - AlternativeSmallFont = OriginalSmallFont = CurrentConsoleFont = NewSmallFont = NewConsoleFont = SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = nullptr; -} - -//========================================================================== -// -// CleanseString -// -// Does some mild sanity checking on a string: If it ends with an incomplete -// color escape, the escape is removed. -// -//========================================================================== - -char* CleanseString(char* str) -{ - char* escape = strrchr(str, TEXTCOLOR_ESCAPE); - if (escape != NULL) - { - if (escape[1] == '\0') - { - *escape = '\0'; - } - else if (escape[1] == '[') - { - char* close = strchr(escape + 2, ']'); - if (close == NULL) - { - *escape = '\0'; - } - } - } - return str; -} - diff --git a/src/gamedata/fonts/v_font.h b/src/gamedata/fonts/v_font.h deleted file mode 100644 index e97a5ebc493..00000000000 --- a/src/gamedata/fonts/v_font.h +++ /dev/null @@ -1,196 +0,0 @@ -/* -** v_font.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __V_FONT_H__ -#define __V_FONT_H__ - -#include "doomtype.h" -#include "w_wad.h" -#include "vectors.h" - -class DCanvas; -class FTexture; -struct FRemapTable; - -enum EColorRange : int -{ - CR_UNDEFINED = -1, - CR_BRICK, - CR_TAN, - CR_GRAY, - CR_GREY = CR_GRAY, - CR_GREEN, - CR_BROWN, - CR_GOLD, - CR_RED, - CR_BLUE, - CR_ORANGE, - CR_WHITE, - CR_YELLOW, - CR_UNTRANSLATED, - CR_BLACK, - CR_LIGHTBLUE, - CR_CREAM, - CR_OLIVE, - CR_DARKGREEN, - CR_DARKRED, - CR_DARKBROWN, - CR_PURPLE, - CR_DARKGRAY, - CR_CYAN, - CR_ICE, - CR_FIRE, - CR_SAPPHIRE, - CR_TEAL, - NUM_TEXT_COLORS, -}; - -extern int NumTextColors; - - -class FFont -{ -public: - - enum EFontType - { - Unknown, - Folder, - Multilump, - Fon1, - Fon2, - BMF, - Custom - }; - - FFont (const char *fontname, const char *nametemplate, const char *filetemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false, bool iwadonly = false); - virtual ~FFont (); - - virtual FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const; - virtual int GetCharWidth (int code) const; - int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; - int GetLump() const { return Lump; } - int GetSpaceWidth () const { return SpaceWidth; } - int GetHeight () const { return FontHeight; } - int GetDefaultKerning () const { return GlobalKerning; } - int GetMaxAscender(const uint8_t* text) const; - int GetMaxAscender(const char* text) const { return GetMaxAscender((uint8_t*)text); } - int GetMaxAscender(const FString &text) const { return GetMaxAscender((uint8_t*)text.GetChars()); } - virtual void LoadTranslations(); - FName GetName() const { return FontName; } - - static FFont *FindFont(FName fontname); - - // Return width of string in pixels (unscaled) - int StringWidth (const uint8_t *str) const; - inline int StringWidth (const char *str) const { return StringWidth ((const uint8_t *)str); } - inline int StringWidth (const FString &str) const { return StringWidth ((const uint8_t *)str.GetChars()); } - - // Checks if the font contains all characters to print this text. - bool CanPrint(const uint8_t *str) const; - inline bool CanPrint(const char *str) const { return CanPrint((const uint8_t *)str); } - inline bool CanPrint(const FString &str) const { return CanPrint((const uint8_t *)str.GetChars()); } - - int GetCharCode(int code, bool needpic) const; - char GetCursor() const { return Cursor; } - void SetCursor(char c) { Cursor = c; } - void SetKerning(int c) { GlobalKerning = c; } - bool NoTranslate() const { return noTranslate; } - void RecordAllTextureColors(uint32_t *usedcolors); - virtual void SetDefaultTranslation(uint32_t *colors); - void CheckCase(); - - int GetDisplacement() const { return Displacement; } - - -protected: - FFont (int lump); - - void BuildTranslations (const double *luminosity, const uint8_t *identity, - const void *ranges, int total_colors, const PalEntry *palette, std::function post = nullptr); - void FixXMoves(); - - static int SimpleTranslation (uint32_t *colorsused, uint8_t *translation, - uint8_t *identity, TArray &Luminosity); - - void ReadSheetFont(TArray &folderdata, int width, int height, const DVector2 &Scale); - - EFontType Type = EFontType::Unknown; - int FirstChar, LastChar; - int SpaceWidth; - int FontHeight; - int AsciiHeight = 0; - int GlobalKerning; - int TranslationType = 0; - int Displacement = 0; - char Cursor; - bool noTranslate; - bool translateUntranslated; - bool MixedCase = false; - bool forceremap = false; - struct CharData - { - FTexture *TranslatedPic = nullptr; // Texture for use with font translations. - FTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization. - int XMove = INT_MIN; - }; - TArray Chars; - int ActiveColors; - TArray Translations; - uint8_t PatchRemap[256]; - - int Lump; - FName FontName = NAME_None; - FFont *Next; - - static FFont *FirstFont; - friend struct FontsDeleter; - - friend void V_ClearFonts(); - friend void V_InitFonts(); -}; - - -extern FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont, *OriginalSmallFont, *AlternativeSmallFont, *OriginalBigFont; - -void V_InitFonts(); -void V_ClearFonts(); -EColorRange V_FindFontColor (FName name); -PalEntry V_LogColorFromColorRange (EColorRange range); -EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int boldcolor); -FFont *V_GetFont(const char *fontname, const char *fontlumpname = nullptr); -void V_InitFontColors(); -char* CleanseString(char* str); - - -#endif //__V_FONT_H__ diff --git a/src/gamedata/fonts/v_text.cpp b/src/gamedata/fonts/v_text.cpp deleted file mode 100644 index fbbbde9e1e4..00000000000 --- a/src/gamedata/fonts/v_text.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* -** v_text.cpp -** Draws text to a canvas. Also has a text line-breaker thingy. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#include -#include - -#include "v_text.h" -#include "utf8.h" - - -#include "v_video.h" -#include "w_wad.h" - -#include "gstrings.h" -#include "vm.h" -#include "serializer.h" - -//========================================================================== -// -// Break long lines of text into multiple lines no longer than maxwidth pixels -// -//========================================================================== - -static void breakit (FBrokenLines *line, FFont *font, const uint8_t *start, const uint8_t *stop, FString &linecolor) -{ - if (!linecolor.IsEmpty()) - { - line->Text = TEXTCOLOR_ESCAPE; - line->Text += linecolor; - } - line->Text.AppendCStrPart ((const char *)start, stop - start); - line->Width = font->StringWidth (line->Text); -} - -TArray V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bool preservecolor) -{ - TArray Lines(128); - - const uint8_t *space = NULL, *start = string; - int c, w, nw; - FString lastcolor, linecolor; - bool lastWasSpace = false; - int kerning = font->GetDefaultKerning (); - - // The real isspace is a bit too badly defined, so use our own one - auto myisspace = [](int ch) { return ch == '\t' || ch == '\r' || ch == '\n' || ch == ' '; }; - - w = 0; - - while ( (c = GetCharFromString(string)) ) - { - if (c == TEXTCOLOR_ESCAPE) - { - if (*string) - { - if (*string == '[') - { - const uint8_t *start = string; - while (*string != ']' && *string != '\0') - { - string++; - } - if (*string != '\0') - { - string++; - } - lastcolor = FString((const char *)start, string - start); - } - else - { - lastcolor = *string++; - } - } - continue; - } - - if (myisspace(c)) - { - if (!lastWasSpace) - { - space = string - 1; - lastWasSpace = true; - } - } - else - { - lastWasSpace = false; - } - - nw = font->GetCharWidth (c); - - if ((w > 0 && w + nw > maxwidth) || c == '\n') - { // Time to break the line - if (!space) - { - for (space = string - 1; (*space & 0xc0) == 0x80 && space > start; space--); - } - - auto index = Lines.Reserve(1); - breakit (&Lines[index], font, start, space, linecolor); - if (c == '\n' && !preservecolor) - { - lastcolor = ""; // Why, oh why, did I do it like this? - } - linecolor = lastcolor; - - w = 0; - lastWasSpace = false; - start = space; - space = NULL; - - while (*start && myisspace (*start) && *start != '\n') - start++; - if (*start == '\n') - start++; - else - while (*start && myisspace (*start)) - start++; - string = start; - } - else - { - w += nw + kerning; - } - } - - // String here is pointing one character after the '\0' - if (--string - start >= 1) - { - const uint8_t *s = start; - - while (s < string) - { - // If there is any non-white space in the remainder of the string, add it. - if (!myisspace (*s++)) - { - auto i = Lines.Reserve(1); - breakit (&Lines[i], font, start, string, linecolor); - break; - } - } - } - return Lines; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FBrokenLines& g, FBrokenLines *def) -{ - if (arc.BeginObject(key)) - { - arc("text", g.Text) - ("width", g.Width) - .EndObject(); - } - return arc; -} - - - -class DBrokenLines : public DObject -{ - DECLARE_CLASS(DBrokenLines, DObject) - -public: - TArray mBroken; - - DBrokenLines() = default; - - DBrokenLines(TArray &broken) - { - mBroken = std::move(broken); - } - - void Serialize(FSerializer &arc) override - { - arc("lines", mBroken); - } -}; - -IMPLEMENT_CLASS(DBrokenLines, false, false); - -DEFINE_ACTION_FUNCTION(DBrokenLines, Count) -{ - PARAM_SELF_PROLOGUE(DBrokenLines); - ACTION_RETURN_INT(self->mBroken.Size()); -} - -DEFINE_ACTION_FUNCTION(DBrokenLines, StringWidth) -{ - PARAM_SELF_PROLOGUE(DBrokenLines); - PARAM_INT(index); - ACTION_RETURN_INT((unsigned)index >= self->mBroken.Size()? -1 : self->mBroken[index].Width); -} - -DEFINE_ACTION_FUNCTION(DBrokenLines, StringAt) -{ - - PARAM_SELF_PROLOGUE(DBrokenLines); - PARAM_INT(index); - ACTION_RETURN_STRING((unsigned)index >= self->mBroken.Size() ? -1 : self->mBroken[index].Text); -} - -DEFINE_ACTION_FUNCTION(FFont, BreakLines) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - PARAM_STRING(text); - PARAM_INT(maxwidth); - - auto broken = V_BreakLines(self, maxwidth, text, true); - ACTION_RETURN_OBJECT(Create(broken)); -} diff --git a/src/gamedata/fonts/v_text.h b/src/gamedata/fonts/v_text.h deleted file mode 100644 index cb16ebb7452..00000000000 --- a/src/gamedata/fonts/v_text.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -** v_text.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __V_TEXT_H__ -#define __V_TEXT_H__ - -#include "v_font.h" - -struct FBrokenLines -{ - unsigned Width; - FString Text; -}; - -#define TEXTCOLOR_ESCAPE '\034' -#define TEXTCOLOR_ESCAPESTR "\034" - -#define TEXTCOLOR_BRICK "\034A" -#define TEXTCOLOR_TAN "\034B" -#define TEXTCOLOR_GRAY "\034C" -#define TEXTCOLOR_GREY "\034C" -#define TEXTCOLOR_GREEN "\034D" -#define TEXTCOLOR_BROWN "\034E" -#define TEXTCOLOR_GOLD "\034F" -#define TEXTCOLOR_RED "\034G" -#define TEXTCOLOR_BLUE "\034H" -#define TEXTCOLOR_ORANGE "\034I" -#define TEXTCOLOR_WHITE "\034J" -#define TEXTCOLOR_YELLOW "\034K" -#define TEXTCOLOR_UNTRANSLATED "\034L" -#define TEXTCOLOR_BLACK "\034M" -#define TEXTCOLOR_LIGHTBLUE "\034N" -#define TEXTCOLOR_CREAM "\034O" -#define TEXTCOLOR_OLIVE "\034P" -#define TEXTCOLOR_DARKGREEN "\034Q" -#define TEXTCOLOR_DARKRED "\034R" -#define TEXTCOLOR_DARKBROWN "\034S" -#define TEXTCOLOR_PURPLE "\034T" -#define TEXTCOLOR_DARKGRAY "\034U" -#define TEXTCOLOR_CYAN "\034V" -#define TEXTCOLOR_ICE "\034W" -#define TEXTCOLOR_FIRE "\034X" -#define TEXTCOLOR_SAPPHIRE "\034Y" -#define TEXTCOLOR_TEAL "\034Z" - -#define TEXTCOLOR_NORMAL "\034-" -#define TEXTCOLOR_BOLD "\034+" - -#define TEXTCOLOR_CHAT "\034*" -#define TEXTCOLOR_TEAMCHAT "\034!" - -TArray V_BreakLines (FFont *font, int maxwidth, const uint8_t *str, bool preservecolor = false); -inline TArray V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false) - { return V_BreakLines (font, maxwidth, (const uint8_t *)str, preservecolor); } -inline TArray V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false) - { return V_BreakLines (font, maxwidth, (const uint8_t *)str.GetChars(), preservecolor); } - -#endif //__V_TEXT_H__ diff --git a/src/gamedata/g_doomedmap.cpp b/src/gamedata/g_doomedmap.cpp index c1e3abc58f6..9aadd956d29 100644 --- a/src/gamedata/g_doomedmap.cpp +++ b/src/gamedata/g_doomedmap.cpp @@ -38,7 +38,7 @@ #include "p_lnspec.h" #include "c_dispatch.h" #include "v_text.h" -#include "doomerrors.h" +#include "engineerrors.h" const char *SpecialMapthingNames[] = { diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index c7fc1c1726d..3d9bc8bd923 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -34,9 +34,9 @@ */ #include -#include "templates.h" + #include "g_level.h" -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" #include "v_video.h" #include "p_lnspec.h" @@ -50,6 +50,7 @@ #include "g_levellocals.h" #include "events.h" #include "i_system.h" +#include "screenjob.h" static TArray wadclusterinfos; TArray wadlevelinfos; @@ -198,6 +199,14 @@ void G_ClearSnapshots (void) { wadlevelinfos[i].Snapshot.Clean(); } + + // Clear current levels' snapshots just in case they are not defined via MAPINFO, + // so they were not handled by the loop above + if (primaryLevel && primaryLevel->info) + primaryLevel->info->Snapshot.Clean(); + if (currentVMLevel && currentVMLevel->info) + currentVMLevel->info->Snapshot.Clean(); + // Since strings are only locked when snapshotting a level, unlock them // all now, since we got rid of all the snapshots that cared about them. GlobalACSStrings.UnlockAll(); @@ -241,10 +250,12 @@ void level_info_t::Reset() else flags2 = LEVEL2_LAXMONSTERACTIVATION; flags3 = 0; + LightningSound = "world/thunder"; Music = ""; LevelName = ""; AuthorName = ""; FadeTable = "COLORMAP"; + CustomColorMap = "COLORMAP"; WallHorizLight = -8; WallVertLight = +8; F1Pic = ""; @@ -265,6 +276,8 @@ void level_info_t::Reset() Translator = ""; RedirectType = NAME_None; RedirectMapName = ""; + RedirectCVAR = NAME_None; + RedirectCVARMapName = ""; EnterPic = ""; ExitPic = ""; Intermission = NAME_None; @@ -293,7 +306,8 @@ void level_info_t::Reset() lightadditivesurfaces = -1; skyrotatevector = FVector3(0, 0, 1); skyrotatevector2 = FVector3(0, 0, 1); - + lightblendmode = ELightBlendMode::DEFAULT; + tonemap = ETonemapMode::None; } @@ -309,10 +323,10 @@ FString level_info_t::LookupLevelName(uint32_t *langtable) if (flags & LEVEL_LOOKUPLEVELNAME) { const char *thename; - const char *lookedup = GStrings.GetString(LevelName, langtable); + const char *lookedup = GStrings.CheckString(LevelName.GetChars(), langtable); if (lookedup == NULL) { - thename = LevelName; + thename = LevelName.GetChars(); } else { @@ -369,15 +383,38 @@ level_info_t *level_info_t::CheckLevelRedirect () if (playeringame[i] && players[i].mo->FindInventory(type)) { // check for actual presence of the map. - if (P_CheckMapData(RedirectMapName)) + if (P_CheckMapData(RedirectMapName.GetChars())) { - return FindLevelInfo(RedirectMapName); + return FindLevelInfo(RedirectMapName.GetChars()); } break; } } } } + if (RedirectCVAR != NAME_None) + { + auto var = FindCVar(RedirectCVAR.GetChars(), NULL); + if (var && (var->GetRealType() == CVAR_Bool) && !(var->GetFlags() & CVAR_IGNORE)) // only check Bool cvars that are currently defined + { + if (var->GetFlags() & CVAR_USERINFO) + { + // user sync'd cvar, check for all players + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && (var = GetCVar(i, RedirectCVAR.GetChars()))) + { + if (var->ToInt()) + if (P_CheckMapData(RedirectCVARMapName.GetChars())) + return FindLevelInfo(RedirectCVARMapName.GetChars()); + } + } + } + else if (var->ToInt()) + if (P_CheckMapData(RedirectCVARMapName.GetChars())) + return FindLevelInfo(RedirectCVARMapName.GetChars()); + } + } return NULL; } @@ -733,6 +770,30 @@ void FMapInfoParser::ParseMusic(FString &name, int &order) } } +//========================================================================== +// +// +// +//========================================================================== + +void FMapInfoParser::ParseCutscene(CutsceneDef& cdef) +{ + FString sound; + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("video")) { ParseAssign(); sc.MustGetString(); cdef.video = sc.String; cdef.function = ""; } + else if (sc.Compare("function")) { ParseAssign(); sc.SetCMode(false); sc.MustGetString(); sc.SetCMode(true); cdef.function = sc.String; cdef.video = ""; } + else if (sc.Compare("sound")) { ParseAssign(); sc.MustGetString(); cdef.soundName = sc.String; } + else if (sc.Compare("soundid")) { ParseAssign(); sc.MustGetNumber(); cdef.soundID = sc.Number; } + else if (sc.Compare("fps")) { ParseAssign(); sc.MustGetNumber(); cdef.framespersec = sc.Number; } + //else if (sc.Compare("transitiononly")) cdef.transitiononly = true; + else if (sc.Compare("delete")) { cdef.function = "none"; cdef.video = ""; } // this means 'play nothing', not 'not defined'. + else if (sc.Compare("clear")) cdef = {}; + } +} + //========================================================================== // // ParseCluster @@ -771,7 +832,7 @@ void FMapInfoParser::ParseCluster() else { FStringf testlabel("CLUSTERENTER%d", clusterinfo->cluster); - if (GStrings.MatchDefaultString(testlabel, clusterinfo->EnterText)) + if (GStrings.MatchDefaultString(testlabel.GetChars(), clusterinfo->EnterText.GetChars())) { clusterinfo->EnterText = testlabel; clusterinfo->flags |= CLUSTER_LOOKUPENTERTEXT; @@ -786,7 +847,7 @@ void FMapInfoParser::ParseCluster() else { FStringf testlabel("CLUSTEREXIT%d", clusterinfo->cluster); - if (GStrings.MatchDefaultString(testlabel, clusterinfo->ExitText)) + if (GStrings.MatchDefaultString(testlabel.GetChars(), clusterinfo->ExitText.GetChars())) { clusterinfo->ExitText = testlabel; clusterinfo->flags |= CLUSTER_LOOKUPEXITTEXT; @@ -837,6 +898,18 @@ void FMapInfoParser::ParseCluster() { clusterinfo->flags |= CLUSTER_EXITTEXTINLUMP; } + else if (sc.Compare("intro")) + { + ParseCutscene(clusterinfo->intro); + } + else if (sc.Compare("outro")) + { + ParseCutscene(clusterinfo->outro); + } + else if (sc.Compare("gameover")) + { + ParseCutscene(clusterinfo->gameover); + } else if (!ParseCloseBrace()) { // Unknown @@ -851,16 +924,16 @@ void FMapInfoParser::ParseCluster() // Remap Hexen's CLUS?MSG lumps to the string table, if applicable. The code here only checks what can actually be in an IWAD. if (clusterinfo->flags & CLUSTER_EXITTEXTINLUMP) { - int lump = Wads.CheckNumForFullName(clusterinfo->ExitText, true); + int lump = fileSystem.CheckNumForFullName(clusterinfo->ExitText.GetChars(), true); if (lump > 0) { // Check if this comes from either Hexen.wad or Hexdd.wad and if so, map to the string table. - int fileno = Wads.GetLumpFile(lump); - auto fn = Wads.GetWadName(fileno); + int fileno = fileSystem.GetFileContainer(lump); + auto fn = fileSystem.GetResourceFileName(fileno); if (fn && (!stricmp(fn, "HEXEN.WAD") || !stricmp(fn, "HEXDD.WAD"))) { FStringf key("TXT_%.5s_%s", fn, clusterinfo->ExitText.GetChars()); - if (GStrings.exists(key)) + if (GStrings.exists(key.GetChars())) { clusterinfo->ExitText = key; clusterinfo->flags &= ~CLUSTER_EXITTEXTINLUMP; @@ -901,7 +974,7 @@ void FMapInfoParser::ParseNextMap(FString &mapname) FName seq = CheckEndSequence(); if (seq != NAME_None) { - mapname.Format("enDSeQ%04x", int(seq)); + mapname.Format("enDSeQ%04x", seq.GetIndex()); } } } @@ -925,6 +998,13 @@ DEFINE_MAP_OPTION(next, true) parse.ParseNextMap(info->NextMap); } +DEFINE_MAP_OPTION(lightningsound, true) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + info->LightningSound = parse.sc.String; +} + DEFINE_MAP_OPTION(author, true) { parse.ParseAssign(); @@ -977,7 +1057,7 @@ DEFINE_MAP_OPTION(sky1, true) { parse.sc.Float /= 256; } - info->skyspeed1 = float(parse.sc.Float * (35. / 1000.)); + info->skyspeed1 = float(parse.sc.Float * (TICRATE / 1000.)); } } @@ -991,7 +1071,7 @@ DEFINE_MAP_OPTION(sky2, true) { parse.sc.Float /= 256; } - info->skyspeed2 = float(parse.sc.Float * (35. / 1000.)); + info->skyspeed2 = float(parse.sc.Float * (TICRATE / 1000.)); } } @@ -1007,14 +1087,14 @@ DEFINE_MAP_OPTION(fade, true) { parse.ParseAssign(); parse.sc.MustGetString(); - info->fadeto = V_GetColor(NULL, parse.sc); + info->fadeto = V_GetColor(parse.sc); } DEFINE_MAP_OPTION(outsidefog, true) { parse.ParseAssign(); parse.sc.MustGetString(); - info->outsidefog = V_GetColor(NULL, parse.sc); + info->outsidefog = V_GetColor(parse.sc); } DEFINE_MAP_OPTION(titlepatch, true) @@ -1083,6 +1163,12 @@ DEFINE_MAP_OPTION(fadetable, true) parse.ParseLumpOrTextureName(info->FadeTable); } +DEFINE_MAP_OPTION(colormap, true) +{ + parse.ParseAssign(); + parse.ParseLumpOrTextureName(info->CustomColorMap); +} + DEFINE_MAP_OPTION(evenlighting, true) { info->WallVertLight = info->WallHorizLight = 0; @@ -1130,6 +1216,11 @@ DEFINE_MAP_OPTION(gravity, true) info->gravity = parse.sc.Float; } +DEFINE_MAP_OPTION(nogravity, true) +{ + info->gravity = DBL_MAX; +} + DEFINE_MAP_OPTION(aircontrol, true) { parse.ParseAssign(); @@ -1197,8 +1288,8 @@ DEFINE_MAP_OPTION(PrecacheSounds, true) do { parse.sc.MustGetString(); - FSoundID snd = parse.sc.String; - if (snd == 0) + FSoundID snd = S_FindSound(parse.sc.String); + if (snd == NO_SOUND) { parse.sc.ScriptMessage("Unknown sound \"%s\"", parse.sc.String); } @@ -1253,6 +1344,15 @@ DEFINE_MAP_OPTION(redirect, true) parse.ParseNextMap(info->RedirectMapName); } +DEFINE_MAP_OPTION(cvar_redirect, true) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + info->RedirectCVAR = parse.sc.String; + parse.ParseComma(); + parse.ParseNextMap(info->RedirectCVARMapName); +} + DEFINE_MAP_OPTION(sndseq, true) { parse.ParseAssign(); @@ -1390,14 +1490,14 @@ DEFINE_MAP_OPTION(hazardcolor, true) { parse.ParseAssign(); parse.sc.MustGetString(); - info->hazardcolor = V_GetColor(NULL, parse.sc); + info->hazardcolor = V_GetColor(parse.sc); } DEFINE_MAP_OPTION(hazardflash, true) { parse.ParseAssign(); parse.sc.MustGetString(); - info->hazardflash = V_GetColor(NULL, parse.sc); + info->hazardflash = V_GetColor(parse.sc); } DEFINE_MAP_OPTION(fogdensity, false) @@ -1441,7 +1541,8 @@ DEFINE_MAP_OPTION(lightmode, false) parse.ParseAssign(); parse.sc.MustGetNumber(); - if ((parse.sc.Number >= 0 && parse.sc.Number <= 4) || parse.sc.Number == 8 || parse.sc.Number == 16) + if (parse.sc.Number == 8 || parse.sc.Number == 16) info->lightmode = ELightMode::NotSet; + else if (parse.sc.Number >= 0 && parse.sc.Number <= 5) { info->lightmode = ELightMode(parse.sc.Number); } @@ -1451,6 +1552,57 @@ DEFINE_MAP_OPTION(lightmode, false) } } +DEFINE_MAP_OPTION(lightblendmode, false) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + + if (parse.sc.Compare("Default") || parse.sc.Compare("Clamp")) + { + info->lightblendmode = ELightBlendMode::DEFAULT; + } + else if (parse.sc.Compare("ColoredClamp")) + { + info->lightblendmode = ELightBlendMode::CLAMP_COLOR; + } + else if (parse.sc.Compare("Unclamped")) + { + info->lightblendmode = ELightBlendMode::NOCLAMP; + if(parse.sc.CheckString(",")) + { + parse.sc.MustGetString(); + if (parse.sc.Compare("None")) + { + info->tonemap = ETonemapMode::None; + } + else if (parse.sc.Compare("Linear")) + { + info->tonemap = ETonemapMode::Linear; + } + else if (parse.sc.Compare("Uncharted2")) + { + info->tonemap = ETonemapMode::Uncharted2; + } + else if (parse.sc.Compare("HejlDawson")) + { + info->tonemap = ETonemapMode::HejlDawson; + } + else if (parse.sc.Compare("Reinhard")) + { + info->tonemap = ETonemapMode::Reinhard; + } + else + { + parse.sc.ScriptMessage("Invalid tonemap %s", parse.sc.String); + } + } + } + else + { + parse.sc.ScriptMessage("Invalid light blend mode %s", parse.sc.String); + } +} + DEFINE_MAP_OPTION(notexturefill, false) { if (parse.CheckAssign()) @@ -1532,6 +1684,16 @@ DEFINE_MAP_OPTION(loadacs, false) info->acsName = parse.sc.String; } +DEFINE_MAP_OPTION(intro, true) +{ + parse.ParseCutscene(info->intro); +} + +DEFINE_MAP_OPTION(outro, true) +{ + parse.ParseCutscene(info->outro); +} + //========================================================================== // @@ -1553,6 +1715,7 @@ enum EMIType MITYPE_CLRFLAG3, MITYPE_SCFLAGS3, MITYPE_COMPATFLAG, + MITYPE_CLRCOMPATFLAG, }; struct MapInfoFlagHandler @@ -1575,6 +1738,11 @@ MapFlagHandlers[] = { "minotaurspecial", MITYPE_SETFLAG, LEVEL_MINOTAURSPECIAL, 0 }, { "dsparilspecial", MITYPE_SETFLAG, LEVEL_SORCERER2SPECIAL, 0 }, { "ironlichspecial", MITYPE_SETFLAG, LEVEL_HEADSPECIAL, 0 }, + { "e1m8special", MITYPE_SETFLAG3,LEVEL3_E1M8SPECIAL, 0 }, + { "e2m8special", MITYPE_SETFLAG3,LEVEL3_E2M8SPECIAL, 0 }, + { "e3m8special", MITYPE_SETFLAG3,LEVEL3_E3M8SPECIAL, 0 }, + { "e4m8special", MITYPE_SETFLAG3,LEVEL3_E4M8SPECIAL, 0 }, + { "e4m6special", MITYPE_SETFLAG3,LEVEL3_E4M6SPECIAL, 0 }, { "specialaction_exitlevel", MITYPE_SCFLAGS, 0, ~LEVEL_SPECACTIONSMASK }, { "specialaction_opendoor", MITYPE_SCFLAGS, LEVEL_SPECOPENDOOR, ~LEVEL_SPECACTIONSMASK }, { "specialaction_lowerfloor", MITYPE_SCFLAGS, LEVEL_SPECLOWERFLOOR, ~LEVEL_SPECACTIONSMASK }, @@ -1644,7 +1812,17 @@ MapFlagHandlers[] = { "nolightfade", MITYPE_SETFLAG3, LEVEL3_NOLIGHTFADE, 0 }, { "nocoloredspritelighting", MITYPE_SETFLAG3, LEVEL3_NOCOLOREDSPRITELIGHTING, 0 }, { "forceworldpanning", MITYPE_SETFLAG3, LEVEL3_FORCEWORLDPANNING, 0 }, + { "propermonsterfallingdamage", MITYPE_SETFLAG3, LEVEL3_PROPERMONSTERFALLINGDAMAGE, 0 }, + { "disableshadowmap", MITYPE_SETFLAG3, LEVEL3_NOSHADOWMAP, 0 }, + { "enableshadowmap", MITYPE_CLRFLAG3, LEVEL3_NOSHADOWMAP, 0 }, + { "enableskyboxao", MITYPE_SETFLAG3, LEVEL3_SKYBOXAO, 0 }, + { "disableskyboxao", MITYPE_CLRFLAG3, LEVEL3_SKYBOXAO, 0 }, + { "avoidmelee", MITYPE_SETFLAG3, LEVEL3_AVOIDMELEE, 0 }, + { "attenuatelights", MITYPE_SETFLAG3, LEVEL3_ATTENUATE, 0 }, + { "nofogofwar", MITYPE_SETFLAG3, LEVEL3_NOFOGOFWAR, 0 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes + { "nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ, 0 }, + { "passover", MITYPE_CLRCOMPATFLAG, COMPATF_NO_PASSMOBJ, 0 }, { "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX, 0 }, { "compat_stairs", MITYPE_COMPATFLAG, COMPATF_STAIRINDEX, 0 }, { "compat_limitpain", MITYPE_COMPATFLAG, COMPATF_LIMITPAIN, 0 }, @@ -1667,7 +1845,8 @@ MapFlagHandlers[] = { "compat_minotaur", MITYPE_COMPATFLAG, COMPATF_MINOTAUR, 0 }, { "compat_mushroom", MITYPE_COMPATFLAG, COMPATF_MUSHROOM, 0 }, { "compat_mbfmonstermove", MITYPE_COMPATFLAG, COMPATF_MBFMONSTERMOVE, 0 }, - { "compat_corpsegibs", MITYPE_COMPATFLAG, COMPATF_CORPSEGIBS, 0 }, + { "compat_corpsegibs", MITYPE_COMPATFLAG, 0, 0 }, // this flag no longer exists, but we need it here for old mapinfos. + { "compat_vileghosts", MITYPE_COMPATFLAG, COMPATF_VILEGHOSTS, 0 }, { "compat_noblockfriends", MITYPE_COMPATFLAG, COMPATF_NOBLOCKFRIENDS, 0 }, { "compat_spritesort", MITYPE_COMPATFLAG, COMPATF_SPRITESORT, 0 }, { "compat_light", MITYPE_COMPATFLAG, COMPATF_LIGHT, 0 }, @@ -1685,6 +1864,11 @@ MapFlagHandlers[] = { "compat_explode2", MITYPE_COMPATFLAG, 0, COMPATF2_EXPLODE2 }, { "compat_railing", MITYPE_COMPATFLAG, 0, COMPATF2_RAILING }, { "compat_scriptwait", MITYPE_COMPATFLAG, 0, COMPATF2_SCRIPTWAIT }, + { "compat_avoidhazards", MITYPE_COMPATFLAG, 0, COMPATF2_AVOID_HAZARDS }, + { "compat_stayonlift", MITYPE_COMPATFLAG, 0, COMPATF2_STAYONLIFT }, + { "compat_nombf21", MITYPE_COMPATFLAG, 0, COMPATF2_NOMBF21 }, + { "compat_voodoozombies", MITYPE_COMPATFLAG, 0, COMPATF2_VOODOO_ZOMBIES }, + { "compat_noacsargcheck", MITYPE_COMPATFLAG, 0, COMPATF2_NOACSARGCHECK }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, @@ -1791,6 +1975,13 @@ void FMapInfoParser::ParseMapDefinition(level_info_t &info) info.flags3 = (info.flags3 & handler->data2) | handler->data1; break; + case MITYPE_CLRCOMPATFLAG: + info.compatflags &= ~handler->data1; + info.compatflags2 &= ~handler->data2; + info.compatmask |= handler->data1; + info.compatmask2 |= handler->data2; + break; + case MITYPE_COMPATFLAG: { int set = 1; @@ -1830,23 +2021,24 @@ void FMapInfoParser::ParseMapDefinition(level_info_t &info) } else { - FAutoSegIterator probe(YRegHead, YRegTail); bool success = false; - while (*++probe != NULL) + AutoSegs::MapInfoOptions.ForEach([this, &success, &info](FMapOptInfo* option) { - if (sc.Compare(((FMapOptInfo *)(*probe))->name)) + if (sc.Compare(option->name)) { - if (!((FMapOptInfo *)(*probe))->old && format_type != FMT_New) + if (!option->old && format_type != FMT_New) { sc.ScriptError("MAPINFO option '%s' requires the new MAPINFO format", sc.String); } - ((FMapOptInfo *)(*probe))->handler(*this, &info); + option->handler(*this, &info); success = true; - break; + return false; // break } - } - + + return true; // continue + }); + if (!success) { if (!ParseCloseBrace()) @@ -1925,7 +2117,7 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo) sc.MustGetString(); mapname = sc.String; } - int levelindex = FindWadLevelInfo (mapname); + int levelindex = FindWadLevelInfo (mapname.GetChars()); if (levelindex == -1) { levelindex = wadlevelinfos.Reserve(1); @@ -1951,7 +2143,7 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo) } - levelinfo->MapName = mapname; + levelinfo->MapName = mapname.GetChars(); levelinfo->MapName.ToUpper(); sc.MustGetString (); if (sc.String[0] == '$') @@ -1974,7 +2166,7 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo) // This checks for a string labelled with the MapName and if that is identical to what got parsed here // the string table entry will be used. - if (GStrings.MatchDefaultString(levelinfo->MapName, sc.String)) + if (GStrings.MatchDefaultString(levelinfo->MapName.GetChars(), sc.String)) { levelinfo->flags |= LEVEL_LOOKUPLEVELNAME; levelinfo->LevelName = levelinfo->MapName; @@ -1986,12 +2178,12 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo) if (HexenHack) { // Try to localize Hexen's map names. This does not use the above feature to allow these names to be unique. - int fileno = Wads.GetLumpFile(sc.LumpNum); - auto fn = Wads.GetWadName(fileno); + int fileno = fileSystem.GetFileContainer(sc.LumpNum); + auto fn = fileSystem.GetResourceFileName(fileno); if (fn && (!stricmp(fn, "HEXEN.WAD") || !stricmp(fn, "HEXDD.WAD"))) { FStringf key("TXT_%.5s_%s", fn, levelinfo->MapName.GetChars()); - if (GStrings.exists(key)) + if (GStrings.exists(key.GetChars())) { levelinfo->flags |= LEVEL_LOOKUPLEVELNAME; levelinfo->LevelName = key; @@ -2004,7 +2196,7 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo) // Set up levelnum now so that you can use Teleport_NewMap specials // to teleport to maps with standard names without needing a levelnum. - levelinfo->levelnum = GetDefaultLevelNum(levelinfo->MapName); + levelinfo->levelnum = GetDefaultLevelNum(levelinfo->MapName.GetChars()); // Does this map have a song defined via SNDINFO's $map command? // Set that as this map's default music if it does. @@ -2042,6 +2234,7 @@ void FMapInfoParser::ParseEpisodeInfo () bool noskill = false; bool optional = false; bool extended = false; + CutsceneDef introscene; // Get map name sc.MustGetString (); @@ -2098,6 +2291,11 @@ void FMapInfoParser::ParseEpisodeInfo () { noskill = true; } + else if (sc.Compare("intro")) + { + ParseCutscene(introscene); + } + else if (!ParseCloseBrace()) { // Unknown @@ -2119,7 +2317,7 @@ void FMapInfoParser::ParseEpisodeInfo () if (optional && !remove) { - if (!P_CheckMapData(map)) + if (!P_CheckMapData(map.GetChars())) { // If the episode is optional and the map does not exist // just ignore this episode definition. @@ -2156,6 +2354,7 @@ void FMapInfoParser::ParseEpisodeInfo () epi->mPicName = pic; epi->mShortcut = tolower(key); epi->mNoSkill = noskill; + epi->mIntro = introscene; } } @@ -2206,23 +2405,25 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i if (sc.Compare("include")) { sc.MustGetString(); - int inclump = Wads.CheckNumForFullName(sc.String, true); + int inclump = fileSystem.CheckNumForFullName(sc.String, true); if (inclump < 0) { sc.ScriptError("include file '%s' not found", sc.String); } - if (Wads.GetLumpFile(sc.LumpNum) != Wads.GetLumpFile(inclump)) + if (fileSystem.GetFileContainer(sc.LumpNum) != fileSystem.GetFileContainer(inclump)) { // Do not allow overriding includes from the default MAPINFO - if (Wads.GetLumpFile(sc.LumpNum) == 0) + if (fileSystem.GetFileContainer(sc.LumpNum) == 0) { I_FatalError("File %s is overriding core lump %s.", - Wads.GetWadFullName(Wads.GetLumpFile(inclump)), sc.String); + fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(inclump)), sc.String); } } - FScanner saved_sc = sc; - ParseMapInfo(inclump, gamedefaults, defaultinfo); - sc = saved_sc; + // use a new parser object to parse the include. Otherwise we'd have to save the entire FScanner in a local variable which is a lot more messy. + FMapInfoParser includer(&sc); + includer.format_type = format_type; + includer.HexenHack = HexenHack; + includer.ParseMapInfo(inclump, gamedefaults, defaultinfo); } else if (sc.Compare("gamedefaults")) { @@ -2401,43 +2602,97 @@ void G_ParseMapInfo (FString basemapinfo) int lump, lastlump = 0; level_info_t gamedefaults; + int flags1 = 0, flags2 = 0; + if (gameinfo.gametype == GAME_Doom) + { + int comp = fileSystem.CheckNumForName("COMPLVL"); + if (comp >= 0) + { + auto complvl = fileSystem.ReadFile(comp); + auto data = complvl.string(); + int length = fileSystem.FileLength(comp); + if (length == 7 && !strnicmp("vanilla", data, 7)) + { + flags1 = + COMPATF_SHORTTEX | COMPATF_STAIRINDEX | COMPATF_USEBLOCKING | COMPATF_NODOORLIGHT | COMPATF_SPRITESORT | + COMPATF_TRACE | COMPATF_MISSILECLIP | COMPATF_SOUNDTARGET | COMPATF_DEHHEALTH | COMPATF_CROSSDROPOFF | + COMPATF_LIGHT | COMPATF_MASKEDMIDTEX | + COMPATF_LIMITPAIN | COMPATF_INVISIBILITY | COMPATF_VILEGHOSTS; + + flags2 = + COMPATF2_FLOORMOVE | COMPATF2_EXPLODE1 | COMPATF2_NOMBF21 | COMPATF2_POINTONLINE; + } + else if (length == 4 && !strnicmp("boom", data, 4)) + { + flags1 = + COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_MASKEDMIDTEX | + COMPATF_INVISIBILITY; + + flags2 = + COMPATF2_EXPLODE1 | COMPATF2_NOMBF21 | COMPATF2_POINTONLINE; + } + else if (length == 3 && !strnicmp("mbf", data, 3)) + { + flags1 = + COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_MUSHROOM | + COMPATF_MBFMONSTERMOVE | COMPATF_NOBLOCKFRIENDS | COMPATF_MASKEDMIDTEX | COMPATF_INVISIBILITY; + + flags2 = + COMPATF2_EXPLODE1 | COMPATF2_AVOID_HAZARDS | COMPATF2_STAYONLIFT | COMPATF2_NOMBF21 | COMPATF2_POINTONLINE; + } + else if (length == 5 && !strnicmp("mbf21", data, 5)) + { + flags1 = + COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_MUSHROOM | + COMPATF_MASKEDMIDTEX | COMPATF_INVISIBILITY; + + flags2 = + COMPATF2_EXPLODE1 | COMPATF2_AVOID_HAZARDS | COMPATF2_STAYONLIFT | COMPATF2_POINTONLINE; + } + } + } + // Parse the default MAPINFO for the current game. This lump *MUST* come from zdoom.pk3. if (basemapinfo.IsNotEmpty()) { FMapInfoParser parse; level_info_t defaultinfo; - int baselump = Wads.GetNumForFullName(basemapinfo); - if (Wads.GetLumpFile(baselump) > 0) + int baselump = fileSystem.GetNumForFullName(basemapinfo.GetChars()); + if (fileSystem.GetFileContainer(baselump) > 0) { I_FatalError("File %s is overriding core lump %s.", - Wads.GetWadFullName(Wads.GetLumpFile(baselump)), basemapinfo.GetChars()); + fileSystem.GetResourceFileName(fileSystem.GetFileContainer(baselump)), basemapinfo.GetChars()); } parse.ParseMapInfo(baselump, gamedefaults, defaultinfo); } - + gamedefaults.compatflags |= flags1; + gamedefaults.compatmask |= flags1; + gamedefaults.compatflags2 |= flags2; + gamedefaults.compatmask2 |= flags2; + static const char *mapinfonames[] = { "MAPINFO", "ZMAPINFO", "UMAPINFO", NULL }; int nindex; // Parse any extra MAPINFOs. - while ((lump = Wads.FindLumpMulti (mapinfonames, &lastlump, false, &nindex)) != -1) + while ((lump = fileSystem.FindLumpMulti (mapinfonames, &lastlump, false, &nindex)) != -1) { if (nindex == 0) { // If this lump is named MAPINFO we need to check if the same WAD contains a ZMAPINFO lump. // If that exists we need to skip this one. - int wad = Wads.GetLumpFile(lump); - int altlump = Wads.CheckNumForName("ZMAPINFO", ns_global, wad, true); + int wad = fileSystem.GetFileContainer(lump); + int altlump = fileSystem.CheckNumForName("ZMAPINFO", FileSys::ns_global, wad, true); if (altlump >= 0) continue; } else if (nindex == 2) { // MAPINFO and ZMAPINFO will override UMAPINFO if in the same WAD. - int wad = Wads.GetLumpFile(lump); - int altlump = Wads.CheckNumForName("ZMAPINFO", ns_global, wad, true); + int wad = fileSystem.GetFileContainer(lump); + int altlump = fileSystem.CheckNumForName("ZMAPINFO", FileSys::ns_global, wad, true); if (altlump >= 0) continue; - altlump = Wads.CheckNumForName("MAPINFO", ns_global, wad, true); + altlump = fileSystem.CheckNumForName("MAPINFO", FileSys::ns_global, wad, true); if (altlump >= 0) continue; } if (nindex != 2) diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index 6e287fadce4..73b46d7e0a8 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -34,18 +34,21 @@ #ifndef __G_LEVEL_H__ #define __G_LEVEL_H__ +#include "autosegs.h" #include "doomtype.h" #include "vectors.h" #include "sc_man.h" -#include "resourcefiles/file_zip.h" +#include "screenjob.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "hw_viewpointuniforms.h" struct level_info_t; struct cluster_info_t; class FSerializer; #if defined(_MSC_VER) -#pragma section(".yreg$u",read) -#define MSVC_YSEG __declspec(allocate(".yreg$u")) +#pragma section(SECTION_YREG,read) +#define MSVC_YSEG __declspec(allocate(SECTION_YREG)) #define GCC_YSEG #else #define MSVC_YSEG @@ -72,9 +75,14 @@ FSerializer &Serialize(FSerializer &arc, const char *key, acsdefered_t &defer, a struct FIntermissionDescriptor; struct FIntermissionAction; +struct CutsceneDef; struct FMapInfoParser { + FMapInfoParser(FScanner* parent) + : sc(parent ? &parent->GetSymbols() : nullptr) + { + } enum EFormatType { FMT_Unknown, @@ -94,6 +102,8 @@ struct FMapInfoParser bool ParseLookupName(FString &dest); void ParseMusic(FString &name, int &order); + void ParseCutscene(CutsceneDef& cdef); + //void ParseLumpOrTextureName(char *name); void ParseLumpOrTextureName(FString &name); void ParseExitText(FName formap, level_info_t *info); @@ -249,6 +259,18 @@ enum ELevelFlags : unsigned int LEVEL3_EXITSECRETUSED = 0x00000040, LEVEL3_FORCEWORLDPANNING = 0x00000080, // Forces the world panning flag for all textures, even those without it explicitly set. LEVEL3_HIDEAUTHORNAME = 0x00000100, + LEVEL3_PROPERMONSTERFALLINGDAMAGE = 0x00000200, // Properly apply falling damage to the monsters + LEVEL3_SKYBOXAO = 0x00000400, // Apply SSAO to sector skies + LEVEL3_E1M8SPECIAL = 0x00000800, + LEVEL3_E2M8SPECIAL = 0x00001000, + LEVEL3_E3M8SPECIAL = 0x00002000, + LEVEL3_E4M8SPECIAL = 0x00004000, + LEVEL3_E4M6SPECIAL = 0x00008000, + LEVEL3_NOSHADOWMAP = 0x00010000, // disables shadowmaps for a given level. + LEVEL3_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support. + LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag. + LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame + LEVEL3_NOFOGOFWAR = 0x00100000, // disables effect of r_radarclipper CVAR on this map }; @@ -309,6 +331,7 @@ struct level_info_t FString SkyPic1; FString SkyPic2; FString FadeTable; + FString CustomColorMap; FString F1Pic; FString BorderTexture; FString MapBackground; @@ -322,12 +345,13 @@ struct level_info_t uint32_t flags2; uint32_t flags3; + FString LightningSound = "world/thunder"; FString Music; FString LevelName; FString AuthorName; int8_t WallVertLight, WallHorizLight; int musicorder; - FCompressedBuffer Snapshot; + FileSys::FCompressedBuffer Snapshot; TArray deferred; float skyspeed1; float skyspeed2; @@ -358,6 +382,11 @@ struct level_info_t FName RedirectType; FString RedirectMapName; + // CVAR Redirection: If the CVAR Bool returns true, then + // you go to the RedirectMap instead of this one. + FName RedirectCVAR; + FString RedirectCVARMapName; + FString EnterPic; FString ExitPic; FString InterMusic; @@ -373,7 +402,7 @@ struct level_info_t TArray specialactions; - TArray PrecacheSounds; + TArray PrecacheSounds; TArray PrecacheTextures; TArray PrecacheClasses; @@ -389,6 +418,10 @@ struct level_info_t FString EDName; FString acsName; bool fs_nocheckposition; + ELightBlendMode lightblendmode; + ETonemapMode tonemap; + + CutsceneDef intro, outro; level_info_t() @@ -418,6 +451,9 @@ struct cluster_info_t FString ExitText; FString EnterText; FString MessageMusic; + CutsceneDef intro; // plays when entering this cluster, aside from starting a new game + CutsceneDef outro; // plays when leaving this cluster + CutsceneDef gameover; // when defined, plays when the player dies in this cluster int musicorder; int flags; int cdtrack; @@ -472,6 +508,8 @@ enum ESkillProperty SKILLP_SlowMonsters, SKILLP_Infight, SKILLP_PlayerRespawn, + SKILLP_SpawnMulti, + SKILLP_InstantReaction, }; enum EFSkillProperty // floating point properties { @@ -515,6 +553,8 @@ struct FSkillInfo int RespawnLimit; double Aggressiveness; int SpawnFilter; + bool SpawnMulti; + bool InstantReaction; int ACSReturn; FString MenuName; FString PicName; @@ -555,6 +595,7 @@ struct FEpisode FString mPicName; char mShortcut; bool mNoSkill; + CutsceneDef mIntro; }; extern TArray AllEpisodes; diff --git a/src/gamedata/g_skill.cpp b/src/gamedata/g_skill.cpp index c47f5d2f143..8a0f69fb3f8 100644 --- a/src/gamedata/g_skill.cpp +++ b/src/gamedata/g_skill.cpp @@ -76,6 +76,8 @@ void FMapInfoParser::ParseSkill () skill.RespawnLimit = 0; skill.Aggressiveness = 1.; skill.SpawnFilter = 0; + skill.SpawnMulti = false; + skill.InstantReaction = false; skill.ACSReturn = 0; skill.MustConfirm = false; skill.Shortcut = 0; @@ -192,6 +194,14 @@ void FMapInfoParser::ParseSkill () else if (sc.Compare("nightmare")) skill.SpawnFilter |= 16; } } + else if (sc.Compare ("spawnmulti")) + { + skill.SpawnMulti = true; + } + else if (sc.Compare ("InstantReaction")) + { + skill.InstantReaction = true; + } else if (sc.Compare("ACSReturn")) { ParseAssign(); @@ -395,6 +405,12 @@ int G_SkillProperty(ESkillProperty prop) case SKILLP_PlayerRespawn: return AllSkills[gameskill].PlayerRespawn; + + case SKILLP_SpawnMulti: + return AllSkills[gameskill].SpawnMulti; + + case SKILLP_InstantReaction: + return AllSkills[gameskill].InstantReaction; } } return 0; @@ -472,18 +488,18 @@ DEFINE_ACTION_FUNCTION(DObject, G_SkillPropertyFloat) const char * G_SkillName() { - const char *name = AllSkills[gameskill].MenuName; + const char *name = AllSkills[gameskill].MenuName.GetChars(); player_t *player = &players[consoleplayer]; - const char *playerclass = player->mo->GetInfo()->DisplayName; + const char *playerclass = player->mo->GetInfo()->DisplayName.GetChars(); if (playerclass != NULL) { FString * pmnm = AllSkills[gameskill].MenuNamesForPlayerClass.CheckKey(playerclass); - if (pmnm != NULL) name = *pmnm; + if (pmnm != NULL) name = pmnm->GetChars(); } - if (*name == '$') name = GStrings(name+1); + if (*name == '$') name = GStrings.GetString(name+1); return name; } @@ -532,6 +548,8 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) RespawnLimit= other.RespawnLimit; Aggressiveness= other.Aggressiveness; SpawnFilter = other.SpawnFilter; + SpawnMulti = other.SpawnMulti; + InstantReaction = other.InstantReaction; ACSReturn = other.ACSReturn; MenuName = other.MenuName; PicName = other.PicName; diff --git a/src/gamedata/gi.cpp b/src/gamedata/gi.cpp index 5076938c584..ed9b0bfa967 100644 --- a/src/gamedata/gi.cpp +++ b/src/gamedata/gi.cpp @@ -36,7 +36,7 @@ #include "info.h" #include "gi.h" #include "sc_man.h" -#include "w_wad.h" +#include "filesystem.h" #include "v_video.h" #include "g_level.h" #include "vm.h" @@ -52,6 +52,8 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, BasicArmorClass) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, HexenArmorClass) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, norandomplayerclass) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, infoPages) @@ -67,6 +69,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_single) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_coop) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_dm) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mSliderColor) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mSliderBackColor) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, defaultbloodcolor) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, telefogheight) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, defKickback) @@ -75,6 +78,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, berserkpic) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, defaultdropstyle) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, normforwardmove) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, normsidemove) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mHideParTimes) const char *GameNames[17] = { @@ -154,7 +158,7 @@ const char* GameInfoBorders[] = { \ sc.ScriptError("Value for '%s' can not be longer than %d characters.", #key, length); \ } \ - gameinfo.key[gameinfo.key.Reserve(1)] = FSoundID(sc.String); \ + gameinfo.key[gameinfo.key.Reserve(1)] = S_FindSound(sc.String); \ } \ while (sc.CheckToken(',')); \ } @@ -171,7 +175,7 @@ const char* GameInfoBorders[] = { \ sc.MustGetToken(TK_StringConst); \ gameinfo.key = sc.String; \ - gameinfo.stampvar = Wads.GetLumpFile(sc.LumpNum); \ + gameinfo.stampvar = fileSystem.GetFileContainer(sc.LumpNum); \ } #define GAMEINFOKEY_INT(key, variable) \ @@ -210,10 +214,10 @@ const char* GameInfoBorders[] = { \ sc.MustGetToken(TK_StringConst); \ FString color = sc.String; \ - FString colorName = V_GetColorStringByName(color); \ + FString colorName = V_GetColorStringByName(color.GetChars()); \ if(!colorName.IsEmpty()) \ color = colorName; \ - gameinfo.key = V_GetColorFromString(NULL, color); \ + gameinfo.key = V_GetColorFromString(color.GetChars()); \ } #define GAMEINFOKEY_BOOL(key, variable) \ @@ -272,6 +276,12 @@ void FMapInfoParser::ParseGameInfo() if (sc.TokenType == '}') break; sc.TokenMustBe(TK_Identifier); + if (sc.Compare("intro")) + { + ParseCutscene(gameinfo.IntroScene); + continue; + } + FString nextKey = sc.String; sc.MustGetToken('='); @@ -354,6 +364,13 @@ void FMapInfoParser::ParseGameInfo() } else gameinfo.mCheatMapArrow = ""; } + else if (nextKey.CompareNoCase("dialogue") == 0) + { + sc.MustGetToken(TK_StringConst); + gameinfo.Dialogue = sc.String; + gameinfo.AddDialogues.Clear(); + } + // Insert valid keys here. GAMEINFOKEY_STRING(mCheatKey, "cheatKey") GAMEINFOKEY_STRING(mEasyKey, "easyKey") @@ -376,7 +393,9 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_STRINGARRAY(PrecachedTextures, "precachetextures", 0, false) GAMEINFOKEY_SOUNDARRAY(PrecachedSounds, "precachesounds", 0, false) GAMEINFOKEY_STRINGARRAY(EventHandlers, "addeventhandlers", 0, false) - GAMEINFOKEY_STRINGARRAY(EventHandlers, "eventhandlers", 0, true) + GAMEINFOKEY_STRINGARRAY(EventHandlers, "eventhandlers", 0, false) + GAMEINFOKEY_STRING(BasicArmorClass, "BasicArmorClass") + GAMEINFOKEY_STRING(HexenArmorClass, "HexenArmorClass") GAMEINFOKEY_STRING(PauseSign, "pausesign") GAMEINFOKEY_STRING(quitSound, "quitSound") GAMEINFOKEY_STRING(BorderFlat, "borderFlat") @@ -396,6 +415,8 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_MUSIC(intermissionMusic, intermissionOrder, "intermissionMusic") GAMEINFOKEY_STRING(CursorPic, "CursorPic") GAMEINFOKEY_STRING(MessageBoxClass, "MessageBoxClass") + GAMEINFOKEY_STRING(HelpMenuClass, "HelpMenuClass") + GAMEINFOKEY_STRING(MenuDelegateClass, "MenuDelegateClass") GAMEINFOKEY_BOOL(noloopfinalemusic, "noloopfinalemusic") GAMEINFOKEY_BOOL(drawreadthis, "drawreadthis") GAMEINFOKEY_BOOL(swapmenu, "swapmenu") @@ -409,6 +430,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_FLOAT(dimamount, "dimamount") GAMEINFOKEY_FLOAT(bluramount, "bluramount") GAMEINFOKEY_STRING(mSliderColor, "menuslidercolor") + GAMEINFOKEY_STRING(mSliderBackColor, "menusliderbackcolor") GAMEINFOKEY_INT(definventorymaxamount, "definventorymaxamount") GAMEINFOKEY_INT(defaultrespawntime, "defaultrespawntime") GAMEINFOKEY_INT(defaultdropstyle, "defaultdropstyle") @@ -434,12 +456,14 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_FONT(mStatscreenAuthorFont, "statscreen_authorfont") GAMEINFOKEY_BOOL(norandomplayerclass, "norandomplayerclass") GAMEINFOKEY_BOOL(forcekillscripts, "forcekillscripts") // [JM] Force kill scripts on thing death. (MF7_NOKILLSCRIPTS overrides.) - GAMEINFOKEY_STRING(Dialogue, "dialogue") + GAMEINFOKEY_STRINGARRAY(AddDialogues, "adddialogues", 0, false) GAMEINFOKEY_STRING(statusscreen_single, "statscreen_single") GAMEINFOKEY_STRING(statusscreen_coop, "statscreen_coop") GAMEINFOKEY_STRING(statusscreen_dm, "statscreen_dm") GAMEINFOKEY_TWODOUBLES(normforwardmove, "normforwardmove") GAMEINFOKEY_TWODOUBLES(normsidemove, "normsidemove") + GAMEINFOKEY_BOOL(nomergepickupmsg, "nomergepickupmsg") + GAMEINFOKEY_BOOL(mHideParTimes, "hidepartimes") else { @@ -450,12 +474,19 @@ void FMapInfoParser::ParseGameInfo() SkipToNext(); } } - turbo.Callback(); + turbo->Callback(); } const char *gameinfo_t::GetFinalePage(unsigned int num) const { if (finalePages.Size() == 0) return "-NOFLAT-"; - else if (num < 1 || num > finalePages.Size()) return finalePages[0]; - else return finalePages[num-1]; + else if (num < 1 || num > finalePages.Size()) return finalePages[0].GetChars(); + else return finalePages[num-1].GetChars(); +} + +bool CheckGame(const char* string, bool chexisdoom) +{ + int test = gameinfo.gametype; + if (test == GAME_Chex && chexisdoom) test = GAME_Doom; + return !stricmp(string, GameNames[test]); } diff --git a/src/gamedata/gi.h b/src/gamedata/gi.h index 5d5f061e3b5..a8d4fa66cae 100644 --- a/src/gamedata/gi.h +++ b/src/gamedata/gi.h @@ -34,8 +34,10 @@ #ifndef __GI_H__ #define __GI_H__ -#include "basictypes.h" +#include "basics.h" #include "zstring.h" +#include "name.h" +#include "screenjob.h" // Flags are not user configurable and only depend on the standard IWADs enum @@ -49,6 +51,7 @@ enum GI_COMPATPOLY1 = 0x00000040, // Hexen's MAP36 needs old polyobject drawing GI_COMPATPOLY2 = 0x00000080, // so does HEXDD's MAP47 GI_IGNORETITLEPATCHES = 0x00000200, // Ignore the map name graphics when not runnning in English language + GI_NOSECTIONMERGE = 0x00000400, // For the original id IWADs: avoid merging sections due to how idbsp created its sectors. }; #include "gametype.h" @@ -129,7 +132,7 @@ struct gameinfo_t TArray PrecachedClasses; TArray PrecachedTextures; - TArray PrecachedSounds; + TArray PrecachedSounds; TArray EventHandlers; FString titleMusic; @@ -145,6 +148,8 @@ struct gameinfo_t FString SkyFlatName; FString ArmorIcon1; FString ArmorIcon2; + FName BasicArmorClass; + FName HexenArmorClass; FString PauseSign; FString Endoom; double Armor2Percent; @@ -161,6 +166,8 @@ struct gameinfo_t FName althudclass; int statusbarclassfile = -1; FName MessageBoxClass; + FName HelpMenuClass; + FName MenuDelegateClass; FName backpacktype; FString intermissionMusic; int intermissionOrder; @@ -181,6 +188,7 @@ struct gameinfo_t FName mFontColorHighlight; FName mFontColorSelection; FName mSliderColor; + FName mSliderBackColor; FString mBackButton; double gibfactor; int TextScreenX; @@ -190,6 +198,7 @@ struct gameinfo_t FString mMapArrow, mCheatMapArrow; FString mEasyKey, mCheatKey; FString Dialogue; + TArray AddDialogues; FGIFont mStatscreenMapNameFont; FGIFont mStatscreenFinishedFont; FGIFont mStatscreenEnteringFont; @@ -204,7 +213,10 @@ struct gameinfo_t int berserkpic; double normforwardmove[2]; double normsidemove[2]; - int fullscreenautoaspect = 0; + int fullscreenautoaspect = 3; + bool nomergepickupmsg; + bool mHideParTimes; + CutsceneDef IntroScene; const char *GetFinalePage(unsigned int num) const; }; @@ -217,11 +229,6 @@ inline const char *GameTypeName() return GameNames[gameinfo.gametype]; } -inline bool CheckGame(const char *string, bool chexisdoom) -{ - int test = gameinfo.gametype; - if (test == GAME_Chex && chexisdoom) test = GAME_Doom; - return !stricmp(string, GameNames[test]); -} +bool CheckGame(const char *string, bool chexisdoom); #endif //__GI_H__ diff --git a/src/gamedata/info.cpp b/src/gamedata/info.cpp index dbc2410b931..67fb87f678d 100644 --- a/src/gamedata/info.cpp +++ b/src/gamedata/info.cpp @@ -50,8 +50,11 @@ #include "d_player.h" #include "events.h" #include "types.h" -#include "w_wad.h" +#include "filesystem.h" #include "g_levellocals.h" +#include "texturemanager.h" +#include "d_main.h" +#include "maps.h" extern void LoadActors (); extern void InitBotStuff(); @@ -62,6 +65,7 @@ FRandom FState::pr_statetics("StateTics"); cycle_t ActionCycles; +void InitServices(); //========================================================================== // @@ -128,16 +132,16 @@ void FState::CheckCallerType(AActor *self, AActor *stateowner) // This should really never happen. Any valid action function must have actor pointers here. if (!requiredType->isObjectPointer()) { - ThrowAbortException(X_OTHER, "Bad function prototype in function call to %s", ActionFunc->PrintableName.GetChars()); + ThrowAbortException(X_OTHER, "Bad function prototype in function call to %s", ActionFunc->PrintableName); } auto cls = static_cast(requiredType)->PointedClass(); if (check == nullptr) { - ThrowAbortException(X_OTHER, "%s called without valid caller. %s expected", ActionFunc->PrintableName.GetChars(), cls->TypeName.GetChars()); + ThrowAbortException(X_OTHER, "%s called without valid caller. %s expected", ActionFunc->PrintableName, cls->TypeName.GetChars()); } if (!(StateFlags & STF_DEHACKED) && !check->IsKindOf(cls)) { - ThrowAbortException(X_OTHER, "Invalid class %s in function call to %s. %s expected", check->GetClass()->TypeName.GetChars(), ActionFunc->PrintableName.GetChars(), cls->TypeName.GetChars()); + ThrowAbortException(X_OTHER, "Invalid class %s in function call to %s. %s expected", check->GetClass()->TypeName.GetChars(), ActionFunc->PrintableName, cls->TypeName.GetChars()); } }; @@ -316,7 +320,7 @@ static void LoadAltHudStuff() break; } - while ((lump = Wads.FindLump("ALTHUDCF", &lastlump)) != -1) + while ((lump = fileSystem.FindLump("ALTHUDCF", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString()) @@ -365,6 +369,7 @@ static void LoadAltHudStuff() // PClassActor :: StaticInit STATIC // //========================================================================== +void InitServices(); void PClassActor::StaticInit() { @@ -391,6 +396,17 @@ void PClassActor::StaticInit() if (!batchrun) Printf ("LoadActors: Load actor definitions.\n"); ClearStrifeTypes(); LoadActors (); + InitServices(); + + + for (auto cls : AllClasses) + { + if (cls->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + AllActorClasses.Push(static_cast(cls)); + } + } + LoadAltHudStuff(); InitBotStuff(); @@ -443,6 +459,68 @@ bool PClassActor::SetReplacement(FName replaceName) return true; } +//========================================================================== +// +// PClassActor :: InitializeNativeDefaults +// +//========================================================================== + +void PClassActor::InitializeDefaults() +{ + if (IsDescendantOf(RUNTIME_CLASS(AActor))) + { + assert(Defaults == nullptr); + Defaults = (uint8_t*)M_Malloc(Size); + + ConstructNative(Defaults); + // We must unlink the defaults from the class list because it's just a static block of data to the engine. + DObject* optr = (DObject*)Defaults; + GC::Root = optr->ObjNext; + optr->ObjNext = nullptr; + optr->SetClass(this); + + // Copy the defaults from the parent but leave the DObject part alone because it contains important data. + if (ParentClass->Defaults != nullptr) + { + memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject)); + if (Size > ParentClass->Size) + { + memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size); + } + + optr->ObjectFlags = ((DObject*)ParentClass->Defaults)->ObjectFlags & OF_Transient; + } + else + { + memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject)); + } + + assert(MetaSize >= ParentClass->MetaSize); + if (MetaSize != 0) + { + Meta = (uint8_t*)M_Malloc(MetaSize); + + // Copy the defaults from the parent but leave the DObject part alone because it contains important data. + if (ParentClass->Meta != nullptr) + { + memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + if (MetaSize > ParentClass->MetaSize) + { + memset(Meta + ParentClass->MetaSize, 0, MetaSize - ParentClass->MetaSize); + } + } + else + { + memset(Meta, 0, MetaSize); + } + + if (MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + else memset(Meta, 0, MetaSize); + } + } + PClass::InitializeDefaults(); +} + //========================================================================== // // PClassActor :: RegisterIDs @@ -660,7 +738,7 @@ void PClassActor::SetPainChance(FName type, int chance) if (chance >= 0) { - ActorInfo()->PainChances.Push({ type, MIN(chance, 256) }); + ActorInfo()->PainChances.Push({ type, min(chance, 256) }); } } @@ -707,22 +785,17 @@ static void SummonActor (int command, int command2, FCommandLine argv) Printf ("Unknown actor '%s'\n", argv[1]); return; } - if (type->bAbstract) - { - Printf("Cannot instantiate abstract class %s\n", argv[1]); - return; - } - Net_WriteByte (argv.argc() > 2 ? command2 : command); + Net_WriteInt8 (argv.argc() > 2 ? command2 : command); Net_WriteString (type->TypeName.GetChars()); if (argv.argc () > 2) { - Net_WriteWord (atoi (argv[2])); // angle - Net_WriteWord ((argv.argc() > 3) ? atoi(argv[3]) : 0); // TID - Net_WriteByte ((argv.argc() > 4) ? atoi(argv[4]) : 0); // special + Net_WriteInt16 (atoi (argv[2])); // angle + Net_WriteInt16 ((argv.argc() > 3) ? atoi(argv[3]) : 0); // TID + Net_WriteInt8 ((argv.argc() > 4) ? atoi(argv[4]) : 0); // special for (int i = 5; i < 10; i++) { // args[5] - Net_WriteLong((i < argv.argc()) ? atoi(argv[i]) : 0); + Net_WriteInt32((i < argv.argc()) ? atoi(argv[i]) : 0); } } } diff --git a/src/gamedata/info.h b/src/gamedata/info.h index 622ffe6a0c6..69ad560e007 100644 --- a/src/gamedata/info.h +++ b/src/gamedata/info.h @@ -50,6 +50,7 @@ struct FActorInfo; class FIntCVar; class FStateDefinitions; class FInternalLightAssociation; +struct FState; enum EStateDefineFlags { @@ -71,14 +72,7 @@ enum EStateFlags STF_SAMEFRAME = 16, // Ignore Frame (except when spawning actor) STF_CANRAISE = 32, // Allows a monster to be resurrected without waiting for an infinate frame STF_DEHACKED = 64, // Modified by Dehacked -}; - -enum EStateUseFlags -{ - SUF_ACTOR = 1, - SUF_OVERLAY = 2, - SUF_WEAPON = 4, - SUF_ITEM = 8, + STF_CONSUMEAMMO = 128, // Needed by the Dehacked parser. }; enum EStateType : int // this must ensure proper alignment. @@ -118,6 +112,7 @@ struct FState uint8_t DefineFlags; int32_t Misc1; // Was changed to int8_t, reverted to long for MBF compat int32_t Misc2; // Was changed to uint8_t, reverted to long for MBF compat + int32_t DehIndex; // we need this to resolve offsets in P_SetSafeFlash. public: inline int GetFrame() const { @@ -179,11 +174,13 @@ struct FState static PClassActor *StaticFindStateOwner (const FState *state); static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info); - static FString StaticGetStateName(const FState *state); + static FString StaticGetStateName(const FState *state, PClassActor *info = nullptr); static FRandom pr_statetics; }; +extern TMap dehExtStates; + struct FStateLabels; struct FStateLabel { @@ -252,6 +249,9 @@ struct FActorInfo uint16_t SpawnID = 0; uint16_t ConversationID = 0; int16_t DoomEdNum = -1; + int infighting_group = 0; + int projectile_group = 0; + int splash_group = 0; FStateLabels *StateList = nullptr; DmgFactors DamageFactors; @@ -306,6 +306,7 @@ class PClassActor : public PClass void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); bool SetReplacement(FName replaceName); + void InitializeDefaults(); FActorInfo *ActorInfo() const { diff --git a/src/gamedata/keysections.cpp b/src/gamedata/keysections.cpp index 7076ebbaaab..bcde05eddde 100644 --- a/src/gamedata/keysections.cpp +++ b/src/gamedata/keysections.cpp @@ -34,12 +34,15 @@ */ -#include "menu/menu.h" +#include "menu.h" #include "gi.h" #include "c_bind.h" #include "c_dispatch.h" #include "gameconfigfile.h" -#include "w_wad.h" +#include "filesystem.h" +#include "gi.h" +#include "d_player.h" +#include "c_dispatch.h" TArray KeySections; extern TArray KeyConfWeapons; @@ -69,7 +72,7 @@ static void DoSaveKeys (FConfigFile *config, const char *section, FKeySection *k FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings; for (unsigned i = 0; i < keysection->mActions.Size(); ++i) { - bindings->ArchiveBindings (config, keysection->mActions[i].mAction); + bindings->ArchiveBindings (config, keysection->mActions[i].mAction.GetChars()); } } @@ -160,15 +163,15 @@ void D_LoadWadSettings () KeySections.Clear(); KeyConfWeapons.Clear(); - while ((lump = Wads.FindLump ("KEYCONF", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("KEYCONF", &lastlump)) != -1) { - FMemLump data = Wads.ReadLump (lump); - const char *eof = (char *)data.GetMem() + Wads.LumpLength (lump); - const char *conf = (char *)data.GetMem(); + auto data = fileSystem.ReadFile (lump); + const char* conf = data.string(); + const char *eof = conf + data.size(); while (conf < eof) { - size_t i; + size_t i = 0; // Fetch a line to execute command.Clear(); @@ -176,14 +179,14 @@ void D_LoadWadSettings () { command.Push(conf[i]); } - if (i == 0) + if (i == 0) // Blank line { conf++; continue; } command.Push(0); conf += i; - if (*conf == '\n') + if (conf >= eof || *conf == '\n') { conf++; } @@ -223,11 +226,45 @@ void D_LoadWadSettings () ParsingKeyConf = false; } +// Strict handling of SetSlot and ClearPlayerClasses in KEYCONF (see a_weapons.cpp) +EXTERN_CVAR (Bool, setslotstrict) + +// Specifically hunt for and remove IWAD playerclasses +void ClearIWADPlayerClasses (PClassActor *ti) +{ + for(unsigned i=0; i < PlayerClasses.Size(); i++) + { + if(PlayerClasses[i].Type==ti) + { + for(unsigned j = i; j < PlayerClasses.Size()-1; j++) + { + PlayerClasses[j] = PlayerClasses[j+1]; + } + PlayerClasses.Pop(); + } + } +} + CCMD(clearplayerclasses) { if (ParsingKeyConf) - { - PlayerClasses.Clear(); + { + // Only clear the playerclasses first if setslotstrict is true + // If not, we'll only remove the IWAD playerclasses + if(setslotstrict) + PlayerClasses.Clear(); + else + { + // I wish I had a better way to pick out IWAD playerclasses + // without having to explicitly name them here... + ClearIWADPlayerClasses(PClass::FindActor("DoomPlayer")); + ClearIWADPlayerClasses(PClass::FindActor("HereticPlayer")); + ClearIWADPlayerClasses(PClass::FindActor("StrifePlayer")); + ClearIWADPlayerClasses(PClass::FindActor("FighterPlayer")); + ClearIWADPlayerClasses(PClass::FindActor("ClericPlayer")); + ClearIWADPlayerClasses(PClass::FindActor("MagePlayer")); + ClearIWADPlayerClasses(PClass::FindActor("ChexPlayer")); + } } } @@ -245,6 +282,16 @@ CCMD(addplayerclass) newclass.Type = ti; newclass.Flags = 0; + + // If this class was already added, don't add it again + for(unsigned i = 0; i < PlayerClasses.Size(); i++) + { + if(PlayerClasses[i].Type == ti) + { + return; + } + } + int arg = 2; while (arg < argv.argc()) diff --git a/src/gamedata/options.cpp b/src/gamedata/options.cpp new file mode 100644 index 00000000000..85a9b930d76 --- /dev/null +++ b/src/gamedata/options.cpp @@ -0,0 +1,205 @@ +// +// Copyright(C) 2020 by Ryan Krafnick +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// DSDA Options Lump +// + +#include "filesystem.h" +#include "g_mapinfo.h" +#include "doomdef.h" +#include "templates.h" + + +struct dsda_options +{ + int monsters_remember = -1; + int monster_infighting = -1; + int monster_backing = -1; + int monster_avoid_hazards = -1; + int monster_friction = -1; + int help_friends = 0; + int player_helpers = 0; + int friend_distance = 128; + int dog_jumping = -1; + int comp_dropoff = -1; + int comp_vile = -1; + int comp_pain = -1; + int comp_doorlight = -1; + int comp_model = -1; + int comp_floors = -1; + int comp_pursuit = -1; // 1 for 'latest' + int comp_staylift = -1; + int comp_stairs = -1; + int comp_ledgeblock = -1; + int comp_friendlyspawn = -1; +}; + +struct dsda_option_t +{ + const char* key; + int dsda_options::* value; + int min; + int max; +}; + +static dsda_option_t option_list[] = { + { "monsters_remember", &dsda_options::monsters_remember, 0, 1 }, + { "monster_infighting", &dsda_options::monster_infighting, 0, 1 }, + { "monster_backing", &dsda_options::monster_backing, 0, 1 }, + { "monster_avoid_hazards", &dsda_options::monster_avoid_hazards, 0, 1 }, + { "monster_friction", &dsda_options::monster_friction, 0, 1 }, + { "help_friends", &dsda_options::help_friends, 0, 1 }, + { "player_helpers", &dsda_options::player_helpers, 0, 3 }, + { "friend_distance", &dsda_options::friend_distance, 0, 999 }, + { "dog_jumping", &dsda_options::dog_jumping, 0, 1 }, + { "comp_dropoff", &dsda_options::comp_dropoff, 0, 1 }, + { "comp_vile", &dsda_options::comp_vile, 0, 1 }, + { "comp_pain", &dsda_options::comp_pain, 0, 1 }, + { "comp_doorlight", &dsda_options::comp_doorlight, 0, 1 }, + { "comp_model", &dsda_options::comp_model, 0, 1 }, + { "comp_floors", &dsda_options::comp_floors, 0, 1 }, + { "comp_pursuit", &dsda_options::comp_pursuit, 0, 1 }, + { "comp_staylift", &dsda_options::comp_staylift, 0, 1 }, + { "comp_stairs", &dsda_options::comp_stairs, 0, 1 }, + { "comp_ledgeblock", &dsda_options::comp_ledgeblock, 0, 1 }, + { "comp_friendlyspawn", &dsda_options::comp_friendlyspawn, 0, 1 }, + { 0 } +}; + +enum { OPTIONS_LINE_LENGTH = 80 }; + +struct options_lump_t +{ + const char* data; + int length; +}; + +static const char* dsda_ReadOption(char* buf, size_t size, options_lump_t* lump) +{ + if (lump->length <= 0) + return nullptr; + + while (size > 1 && *lump->data && lump->length) + { + size--; + lump->length--; + if ((*buf++ = *lump->data++) == '\n') + break; + } + + *buf = '\0'; + + return lump->data; +} + +static struct dsda_options dsda_LumpOptions(int lumpnum) +{ + struct dsda_options mbf_options; + + options_lump_t lump; + char buf[OPTIONS_LINE_LENGTH]; + char key[OPTIONS_LINE_LENGTH]; + char* scan; + int value, count; + dsda_option_t* option; + + lump.length = fileSystem.FileLength(lumpnum); + auto data = fileSystem.ReadFile(lumpnum); + lump.data = (char*)data.GetMem(); + + while (dsda_ReadOption(buf, OPTIONS_LINE_LENGTH, &lump)) + { + if (buf[0] == '#') + continue; + + scan = buf; + count = sscanf(scan, "%79s %d", key, &value); + + if (count != 2) + continue; + + for (option = option_list; option->value; option++) + { + if (!strncmp(key, option->key, OPTIONS_LINE_LENGTH)) + { + mbf_options.*option->value = clamp(option->min, option->max, value); + + //lprintf(LO_INFO, "dsda_LumpOptions: %s = %d\n", key, value); + + break; + } + } + } + return mbf_options; +} + + +void parseOptions() +{ + int lumpnum = fileSystem.FindFile("OPTIONS"); + + if (lumpnum == -1) + return; + + auto opt = dsda_LumpOptions(lumpnum); + + auto setflag = [](auto& flag, auto mask, bool set) + { + if (set) flag |= mask; + else flag &= ~mask; + }; + + for (auto& lev : wadlevelinfos) + { + setflag(lev.flags2, LEVEL2_NOINFIGHTING, opt.monster_infighting); + setflag(lev.flags3, LEVEL3_AVOIDMELEE, opt.monster_backing); + setflag(lev.compatflags2, COMPATF2_AVOID_HAZARDS, opt.monster_avoid_hazards); + setflag(lev.compatmask2, COMPATF2_AVOID_HAZARDS, opt.monster_avoid_hazards); + setflag(lev.compatflags, COMPATF_MBFMONSTERMOVE, opt.monster_friction); + setflag(lev.compatmask, COMPATF_MBFMONSTERMOVE, opt.monster_friction); + setflag(lev.compatflags, COMPATF_DROPOFF, opt.comp_dropoff); + setflag(lev.compatmask, COMPATF_DROPOFF, opt.comp_dropoff); + setflag(lev.compatflags, COMPATF_DROPOFF, opt.comp_dropoff); + setflag(lev.compatmask, COMPATF_DROPOFF, opt.comp_dropoff); + setflag(lev.compatflags, COMPATF_CORPSEGIBS, opt.comp_vile); + setflag(lev.compatmask, COMPATF_CORPSEGIBS, opt.comp_vile); + setflag(lev.flags3, LEVEL3_VILEOPTION, opt.comp_vile); + setflag(lev.flags3, LEVEL3_NOJUMPDOWN, !opt.dog_jumping); // this one's rather pointless, but well... + setflag(lev.compatflags, COMPATF_LIMITPAIN, opt.comp_pain); + setflag(lev.compatmask, COMPATF_LIMITPAIN, opt.comp_pain); + setflag(lev.compatflags, COMPATF_NODOORLIGHT, opt.comp_doorlight); + setflag(lev.compatmask, COMPATF_NODOORLIGHT, opt.comp_doorlight); + setflag(lev.compatflags, COMPATF_LIGHT | COMPATF_SHORTTEX, opt.comp_model); // only the relevant parts of this catch-all option. + setflag(lev.compatmask, COMPATF_LIGHT | COMPATF_SHORTTEX, opt.comp_model); + setflag(lev.compatflags2, COMPATF2_FLOORMOVE, opt.comp_floors); + setflag(lev.compatmask2, COMPATF2_FLOORMOVE, opt.comp_floors); + setflag(lev.compatflags2, COMPATF2_STAYONLIFT, opt.comp_staylift); + setflag(lev.compatmask2, COMPATF2_STAYONLIFT, opt.comp_staylift); + setflag(lev.compatflags, COMPATF_STAIRINDEX, opt.comp_stairs); + setflag(lev.compatmask, COMPATF_STAIRINDEX, opt.comp_stairs); + setflag(lev.compatflags, COMPATF_CROSSDROPOFF, opt.comp_ledgeblock); + setflag(lev.compatmask, COMPATF_CROSSDROPOFF, opt.comp_ledgeblock); + + /* later. these should be supported but are not implemented yet. + if (opt.monsters_remember == 0) + if (opt.comp_pursuit) + if (opt.comp_friendlyspawn == 0) + int help_friends = 0; + int player_helpers = 0; + int friend_distance = 128; + */ + + } +} + diff --git a/src/gamedata/p_blockmap.h b/src/gamedata/p_blockmap.h index f528ae1561f..06c03deb385 100644 --- a/src/gamedata/p_blockmap.h +++ b/src/gamedata/p_blockmap.h @@ -43,10 +43,7 @@ struct FBlockmap // mapblocks are used to check movement // against lines and things - enum - { - MAPBLOCKUNITS = 128 - }; + static constexpr int MAPBLOCKUNITS = 128; inline int GetBlockX(double xpos) { diff --git a/src/gamedata/p_terrain.cpp b/src/gamedata/p_terrain.cpp index 58eeba9b90a..4d0efcff982 100644 --- a/src/gamedata/p_terrain.cpp +++ b/src/gamedata/p_terrain.cpp @@ -41,11 +41,12 @@ #include "p_terrain.h" #include "gi.h" #include "r_state.h" -#include "w_wad.h" +#include "filesystem.h" #include "sc_man.h" #include "p_local.h" #include "actor.h" #include "vm.h" +#include "texturemanager.h" // MACROS ------------------------------------------------------------------ @@ -249,7 +250,7 @@ void P_InitTerrainTypes () MakeDefaultTerrain (); lastlump = 0; - while (-1 != (lump = Wads.FindLump ("TERRAIN", &lastlump)) ) + while (-1 != (lump = fileSystem.FindLump ("TERRAIN", &lastlump)) ) { FScanner sc(lump); ParseOuter (sc); @@ -354,7 +355,7 @@ static void ParseOuter (FScanner &sc) static void SetSplashDefaults (FSplashDef *splashdef) { splashdef->SmallSplashSound = - splashdef->NormalSplashSound = 0; + splashdef->NormalSplashSound = NO_SOUND; splashdef->SmallSplash = splashdef->SplashBase = splashdef->SplashChunk = NULL; @@ -536,7 +537,7 @@ static void GenericParse (FScanner &sc, FGenericParse *parser, const char **keyw case GEN_Sound: sc.MustGetString (); - SET_FIELD (FSoundID, FSoundID(sc.String)); + SET_FIELD (FSoundID, S_FindSound(sc.String)); /* unknown sounds never produce errors anywhere else so they shouldn't here either. if (val == 0) { @@ -644,11 +645,15 @@ static void ParseFloor (FScanner &sc) return; } sc.MustGetString (); + if (sc.Compare("Null") || sc.Compare("None")) + { + TerrainTypes.Set(picnum.GetIndex(), 0xffff); + return; + } terrain = P_FindTerrain (sc.String); if (terrain == -1) { Printf ("Unknown terrain %s\n", sc.String); - terrain = 0; } TerrainTypes.Set(picnum.GetIndex(), terrain); } @@ -703,7 +708,7 @@ int P_FindTerrain (FName name) { unsigned int i; - if (name == NAME_Null) return -1; + if (name == NAME_Null || name == NAME_None) return -1; for (i = 0; i < Terrains.Size (); i++) { if (Terrains[i].Name == name) diff --git a/src/gamedata/p_terrain.h b/src/gamedata/p_terrain.h index f041ef7a665..a225b8a738c 100644 --- a/src/gamedata/p_terrain.h +++ b/src/gamedata/p_terrain.h @@ -35,7 +35,7 @@ #define __P_TERRAIN_H__ #include "s_sound.h" -#include "textures/textures.h" +#include "textures.h" class PClass; diff --git a/src/gamedata/p_xlat.cpp b/src/gamedata/p_xlat.cpp index 2ab3ebf1292..13de256493e 100644 --- a/src/gamedata/p_xlat.cpp +++ b/src/gamedata/p_xlat.cpp @@ -68,6 +68,7 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde uint32_t flags1 = flags; uint32_t newflags = 0; + uint32_t newflags2 = 0; for(int i=0;i<16;i++) { @@ -80,7 +81,8 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde { if ((flags1 & (1<LineFlagTranslations[i].ismask) { - switch (translator->LineFlagTranslations[i].newvalue) + unsigned val = translator->LineFlagTranslations[i].newvalue; + switch ((int)val) { case -1: passthrough = true; @@ -92,12 +94,14 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde ld->alpha = 0.25; break; default: - newflags |= translator->LineFlagTranslations[i].newvalue; + if ((val & 0x80000000) && val != 0x80000000) newflags2 |= val; + else newflags |= val; break; } } } flags = newflags; + ld->flags2 = newflags2; if (lineindexforid >= 0) { @@ -191,6 +195,7 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde { case WalkMany: flags |= ML_REPEAT_SPECIAL; + [[fallthrough]]; case WalkOnce: ld->activation = SPAC_Cross; break; @@ -198,6 +203,7 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde case SwitchMany: case PushMany: flags |= ML_REPEAT_SPECIAL; + [[fallthrough]]; case SwitchOnce: case PushOnce: if (passthrough) @@ -208,6 +214,7 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde case GunMany: flags |= ML_REPEAT_SPECIAL; + [[fallthrough]]; case GunOnce: ld->activation = SPAC_Impact; break; diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index 1ea203f2dd5..943893c66a8 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -31,10 +31,17 @@ #define __R_DEFS_H__ #include "doomdef.h" -#include "templates.h" + #include "m_bbox.h" #include "dobjgc.h" #include "r_data/r_translate.h" +#include "texmanip.h" +#include "fcolormap.h" +#include "r_sky.h" +#include "p_terrain.h" +#include "p_effect.h" + +#include "hwrenderer/data/buffers.h" // Some more or less basic data types // we depend on. @@ -54,9 +61,8 @@ struct sector_t; class AActor; struct FSection; struct FLevelLocals; - -#define MAXWIDTH 12000 -#define MAXHEIGHT 5000 +struct LightmapSurface; +struct LightProbe; const uint16_t NO_INDEX = 0xffffu; const uint32_t NO_SIDE = 0xffffffffu; @@ -297,6 +303,7 @@ struct secplane_t DVector3 normal; double D, negiC; // negative iC because that also saves a negation in all methods using this. public: + bool dithertransflag; // Render plane with dithering transparency shader (gets reset every frame) friend FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p, secplane_t *def); void set(double aa, double bb, double cc, double dd) @@ -359,11 +366,21 @@ struct secplane_t return (D + normal.X*pos.X + normal.Y*pos.Y) * negiC; } + double ZatPoint(const DVector3& pos) const + { + return (D + normal.X * pos.X + normal.Y * pos.Y) * negiC; + } + double ZatPoint(const FVector2 &pos) const { return (D + normal.X*pos.X + normal.Y*pos.Y) * negiC; } + double ZatPoint(const FVector3& pos) const + { + return (D + normal.X * pos.X + normal.Y * pos.Y) * negiC; + } + double ZatPoint(const vertex_t *v) const { return (D + normal.X*v->fX() + normal.Y*v->fY()) * negiC; @@ -486,6 +503,7 @@ enum SECMF_HIDDEN = 256, // Do not draw on textured automap SECMF_OVERLAPPING = 512, // floor and ceiling overlap and require special renderer action. SECMF_NOSKYWALLS = 1024, // Do not draw "sky walls" + SECMF_LIFT = 2048, // For MBF monster AI }; enum @@ -502,13 +520,16 @@ enum SECF_ENDLEVEL = 512, // ends level when health goes below 10 SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. SECF_NOATTACK = 2048, // monsters cannot start attacks in this sector. + SECF_EXIT1 = 4096, + SECF_EXIT2 = 8192, + SECF_KILLMONSTERS = 16384, SECF_WASSECRET = 1 << 30, // a secret that was discovered SECF_SECRET = 1 << 31, // a secret sector SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags - SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers + SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH|SECF_EXIT1|SECF_EXIT2|SECF_KILLMONSTERS, // these flags originate from 'special' and must be transferrable by floor thinkers }; enum @@ -521,8 +542,8 @@ struct FDynamicColormap; struct FLinkedSector { - sector_t *Sector; - int Type; + sector_t *Sector = nullptr; + int Type = 0; }; @@ -593,7 +614,7 @@ struct secspecial_t { FName damagetype; // [RH] Means-of-death for applied damage int damageamount; // [RH] Damage to do while standing on floor - short special; + int special; short damageinterval; // Interval for damage application short leakydamage; // chance of leaking through radiation suit int Flags; @@ -648,6 +669,7 @@ struct sector_t float GlowHeight; FTextureID Texture; TextureManipulation TextureFx; + FTextureID skytexture[2]; }; @@ -669,17 +691,17 @@ struct sector_t FColormap Colormap; // Sector's own color/fog info. - short special; // map-defined sector special type - short lightlevel; + int special; // map-defined sector special type - int sky; // MBF sky transfer info. + int skytransfer; // MBF sky transfer info. int validcount; // if == validcount, already checked - uint32_t bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps + uint32_t selfmap, bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps // [RH] these can also be blend values if // the alpha mask is non-zero bool transdoor; // For transparent door hacks + short lightlevel; uint16_t MoreFlags; // [RH] Internal sector flags uint32_t Flags; // Sector flags @@ -690,19 +712,20 @@ struct sector_t int sectornum; // for comparing sector copies // GL only stuff starts here - float reflect[2]; - int subsectorcount; // list of subsectors + float reflect[2]; double transdoorheight; // for transparent door hacks subsector_t ** subsectors; FSectorPortalGroup * portals[2]; // floor and ceiling portals int vboindex[4]; // VBO indices of the 4 planes this sector uses during rendering. This is only needed for updating plane heights. int iboindex[4]; // IBO indices of the 4 planes this sector uses during rendering - double vboheight[2]; // Last calculated height for the 2 planes of this actual sector + double vboheight[HW_MAX_PIPELINE_BUFFERS][2]; // Last calculated height for the 2 planes of this actual sector int vbocount[2]; // Total count of vertices belonging to this sector's planes. This is used when a sector height changes and also contains all attached planes. int ibocount; // number of indices per plane (identical for all planes.) If this is -1 the index buffer is not in use. + bool HasLightmaps = false; // Sector has lightmaps, each subsector vertex needs its own unique lightmap UV data + // Below are all properties which are not used by the renderer. TObjPtr SoundTarget; @@ -777,7 +800,6 @@ struct sector_t bool IsLinked(sector_t *other, bool ceiling) const; - sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH] void RemoveForceField(); int Index() const { return sectornum; } @@ -789,6 +811,7 @@ struct sector_t int GetFloorLight() const; int GetCeilingLight() const; + int GetSpriteLight() const; sector_t *GetHeightSec() const { @@ -806,7 +829,6 @@ struct sector_t int CheckSpriteGlow(int lightlevel, const DVector3 &pos); bool GetWallGlow(float *topglowcolor, float *bottomglowcolor); - void SetXOffset(int pos, double o) { planes[pos].xform.xOffs = o; @@ -1144,15 +1166,22 @@ class DBaseDecal; enum { - WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative - WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall - WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel - WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles. - WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side. - WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side. - WALLF_POLYOBJ = 64, // This wall belongs to a polyobject. - WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. - WALLF_EXTCOLOR = 256, // enables the extended color options (flagged to allow the renderer to easily skip the relevant code) + WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative + WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall + WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel + WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles. + WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side. + WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side. + WALLF_POLYOBJ = 64, // This wall belongs to a polyobject. + WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. + WALLF_EXTCOLOR = 256, // enables the extended color options (flagged to allow the renderer to easily skip the relevant code) + + WALLF_ABSLIGHTING_TIER = 512, // Per-tier absolute lighting flags + WALLF_ABSLIGHTING_TOP = WALLF_ABSLIGHTING_TIER << 0, // Top tier light is absolute instead of relative + WALLF_ABSLIGHTING_MID = WALLF_ABSLIGHTING_TIER << 1, // Mid tier light is absolute instead of relative + WALLF_ABSLIGHTING_BOTTOM = WALLF_ABSLIGHTING_TIER << 2, // Bottom tier light is absolute instead of relative + + WALLF_DITHERTRANS = 8192, // Render with dithering transparency shader (gets reset every frame) }; struct side_t @@ -1169,6 +1198,15 @@ struct side_t walltop = 0, wallbottom = 1, }; + enum ESkew + { + skew_none = 0, + skew_front_floor = 1, + skew_front_ceiling = 2, + skew_back_floor = 3, + skew_back_ceiling = 4 + }; + struct part { enum EPartFlags @@ -1184,7 +1222,8 @@ struct side_t double xScale; double yScale; TObjPtr interpolation; - int flags; + int16_t flags; + int8_t skew; FTextureID texture; TextureManipulation TextureFx; PalEntry SpecialColors[2]; @@ -1209,20 +1248,28 @@ struct side_t uint32_t LeftSide, RightSide; // [RH] Group walls into loops uint16_t TexelLength; int16_t Light; + int16_t TierLights[3]; // per-tier light levels uint16_t Flags; int UDMFIndex; // needed to access custom UDMF fields which are stored in loading order. FLightNode * lighthead; // all dynamic lights that may affect this wall + LightmapSurface* lightmap; seg_t **segs; // all segs belonging to this sidedef in ascending order. Used for precise rendering int numsegs; int sidenum; - int GetLightLevel (bool foggy, int baselight, bool is3dlight=false, int *pfakecontrast_usedbygzdoom=NULL) const; + int GetLightLevel (bool foggy, int baselight, int which, bool is3dlight=false, int *pfakecontrast_usedbygzdoom=NULL) const; void SetLight(int16_t l) { Light = l; } + void SetLight(int16_t l, int which) + { + TierLights[which] = l; + } + + FLevelLocals *GetLevel() { return sector->Level; @@ -1321,15 +1368,32 @@ struct side_t textures[which].yScale *= delta; } - void SetSpecialColor(int which, int slot, int r, int g, int b) + int GetTextureFlags(int which) + { + return textures[which].flags; + } + + void ChangeTextureFlags(int which, int And, int Or) + { + textures[which].flags &= ~And; + textures[which].flags |= Or; + } + + void SetSpecialColor(int which, int slot, int r, int g, int b, bool useown = true) { textures[which].SpecialColors[slot] = PalEntry(255, r, g, b); + if (useown) textures[which].flags |= part::UseOwnSpecialColors; + else textures[which].flags &= ~part::UseOwnSpecialColors; + Flags |= WALLF_EXTCOLOR; } - void SetSpecialColor(int which, int slot, PalEntry rgb) + void SetSpecialColor(int which, int slot, PalEntry rgb, bool useown = true) { rgb.a = 255; textures[which].SpecialColors[slot] = rgb; + if (useown) textures[which].flags |= part::UseOwnSpecialColors; + else textures[which].flags &= ~part::UseOwnSpecialColors; + Flags |= WALLF_EXTCOLOR; } // Note that the sector being passed in here may not be the actual sector this sidedef belongs to @@ -1416,11 +1480,25 @@ enum AutomapLineStyle : int AMLS_COUNT }; -struct line_t +struct linebase_t { - vertex_t *v1, *v2; // vertices, from v1 to v2 + vertex_t* v1, * v2; // vertices, from v1 to v2 DVector2 delta; // precalculated v2 - v1 for side checking - uint32_t flags; + + DVector2 Delta() const + { + return delta; + } + + void setDelta(double x, double y) + { + delta = { x, y }; + } +}; + +struct line_t : public linebase_t +{ + uint32_t flags, flags2; uint32_t activation; // activation type int special; int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) @@ -1437,16 +1515,6 @@ struct line_t int healthgroup; // [ZZ] this is the "destructible object" id int linenum; - DVector2 Delta() const - { - return delta; - } - - void setDelta(double x, double y) - { - delta = { x, y }; - } - void setAlpha(double a) { alpha = a; @@ -1460,7 +1528,11 @@ struct line_t inline bool isLinePortal() const; inline bool isVisualPortal() const; inline line_t *getPortalDestination() const; + inline int getPortalFlags() const; inline int getPortalAlignment() const; + inline int getPortalType() const; + inline DVector2 getPortalDisplacement() const; + inline DAngle getPortalAngleDiff() const; inline bool hitSkyWall(AActor* mo) const; int Index() const { return linenum; } @@ -1585,6 +1657,7 @@ struct subsector_t uint32_t numlines; uint16_t flags; short mapsection; + FBoundingBox bbox; // [DVR] For alternative space culling in orthographic projection with no fog of war // subsector related GL data int validcount; @@ -1594,6 +1667,8 @@ struct subsector_t int Index() const { return subsectornum; } // 2: has one-sided walls FPortalCoverage portalcoverage[2]; + TArray sprites; + LightmapSurface *lightmap[2]; }; @@ -1638,6 +1713,40 @@ struct FMiniBSP TArray Verts; }; +// Lightmap data + +enum SurfaceType +{ + ST_NULL, + ST_MIDDLEWALL, + ST_UPPERWALL, + ST_LOWERWALL, + ST_CEILING, + ST_FLOOR +}; + +struct LightmapSurface +{ + SurfaceType Type; + subsector_t *Subsector; + side_t *Side; + sector_t *ControlSector; + uint32_t LightmapNum; + float *TexCoords; +}; + +struct LightProbe +{ + float X, Y, Z; + float Red, Green, Blue; +}; + +struct LightProbeCell +{ + LightProbe* FirstProbe = nullptr; + int NumProbes = 0; +}; + // // OTHER TYPES // @@ -1650,21 +1759,21 @@ typedef uint8_t lighttable_t; // This could be wider for >8 bit display. // //---------------------------------------------------------------------------------- -inline bool FBoundingBox::inRange(const line_t *ld) const +inline bool inRange(const FBoundingBox &box, const line_t *ld) { - return Left() < ld->bbox[BOXRIGHT] && - Right() > ld->bbox[BOXLEFT] && - Top() > ld->bbox[BOXBOTTOM] && - Bottom() < ld->bbox[BOXTOP]; + return box.Left() < ld->bbox[BOXRIGHT] && + box.Right() > ld->bbox[BOXLEFT] && + box.Top() > ld->bbox[BOXBOTTOM] && + box.Bottom() < ld->bbox[BOXTOP]; } -inline void FColormap::CopyFrom3DLight(lightlist_t *light) +inline void CopyFrom3DLight(FColormap &cm, lightlist_t *light) { - CopyLight(light->extra_colormap); + cm.CopyLight(light->extra_colormap); if (light->caster && (light->caster->flags&FF_FADEWALLS) && light->extra_colormap.FadeColor != 0) { - CopyFog(light->extra_colormap); + cm.CopyFog(light->extra_colormap); } } @@ -1696,6 +1805,7 @@ void TransferSpecial(sector_t *self, sector_t *model); void GetSpecial(sector_t *self, secspecial_t *spec); void SetSpecial(sector_t *self, const secspecial_t *spec); int GetTerrain(const sector_t *, int pos); +FTerrainDef *GetFloorTerrain_S(const sector_t* sec, int pos); void CheckPortalPlane(sector_t *sector, int plane); void AdjustFloorClip(const sector_t *sector); void SetColor(sector_t *sector, int color, int desat); @@ -1705,6 +1815,8 @@ int GetCeilingLight(const sector_t *); double GetFriction(const sector_t *self, int plane, double *movefac); double HighestCeilingAt(sector_t *sec, double x, double y, sector_t **resultsec = nullptr); double LowestFloorAt(sector_t *sec, double x, double y, sector_t **resultsec = nullptr); +sector_t* P_NextSpecialSector(sector_t* sect, int type, sector_t* prev); +sector_t* P_NextSpecialSectorVC(sector_t* sect, int type); // uses validcount inline void sector_t::RemoveForceField() { return ::RemoveForceField(this); } inline bool sector_t::PlaneMoving(int pos) { return !!::PlaneMoving(this, pos); } @@ -1718,6 +1830,10 @@ inline void sector_t::SetColor(PalEntry pe, int desat) { ::SetColor(this, pe, de inline void sector_t::SetFade(PalEntry pe) { ::SetFade(this, pe); } inline int sector_t::GetFloorLight() const { return ::GetFloorLight(this); } inline int sector_t::GetCeilingLight() const { return ::GetCeilingLight(this); } +inline int sector_t::GetSpriteLight() const +{ + return GetTexture(ceiling) == skyflatnum ? GetCeilingLight() : GetFloorLight(); +} inline double sector_t::GetFriction(int plane, double *movefac) const { return ::GetFriction(this, plane, movefac); } inline void sector_t::CheckExColorFlag() diff --git a/src/gamedata/resourcefiles/ancientzip.h b/src/gamedata/resourcefiles/ancientzip.h deleted file mode 100644 index cffd239ad3c..00000000000 --- a/src/gamedata/resourcefiles/ancientzip.h +++ /dev/null @@ -1,50 +0,0 @@ -#include "files.h" -#include "doomerrors.h" - -class FZipExploder -{ - unsigned int Hold, Bits; - FileReader *In; - unsigned int InLeft; - - /**************************************************************** - Shannon-Fano tree structures, variables and related routines - ****************************************************************/ - - struct HuffNode - { - unsigned char Value; - unsigned char Length; - unsigned short ChildTable; - }; - - struct TableBuilder - { - unsigned char Value; - unsigned char Length; - unsigned short Code; - }; - - TArray LiteralDecoder; - TArray DistanceDecoder; - TArray LengthDecoder; - unsigned char ReadBuf[256]; - unsigned int bs, be; - - static int buildercmp(const void *a, const void *b); - void InsertCode(TArray &decoder, unsigned int pos, int bits, unsigned short code, int len, unsigned char value); - unsigned int InitTable(TArray &decoder, int numspots); - int BuildDecoder(TArray &decoder, TableBuilder *values, int numvals); - int DecodeSFValue(const TArray ¤tTree); - int DecodeSF(TArray &decoder, int numvals); -public: - int Explode(unsigned char *out, unsigned int outsize, FileReader &in, unsigned int insize, int flags); -}; - -class CExplosionError : CRecoverableError -{ -public: - CExplosionError(const char *message) : CRecoverableError(message) {} -}; - -int ShrinkLoop(unsigned char *out, unsigned int outsize, FileReader &in, unsigned int insize); \ No newline at end of file diff --git a/src/gamedata/resourcefiles/file_7z.cpp b/src/gamedata/resourcefiles/file_7z.cpp deleted file mode 100644 index 27b59634131..00000000000 --- a/src/gamedata/resourcefiles/file_7z.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/* -** file_7z.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2009 Randy Heit -** Copyright 2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -// Note that 7z made the unwise decision to include windows.h :( -#include "7z.h" -#include "7zCrc.h" - -#include "resourcefile.h" -#include "cmdlib.h" -#include "v_text.h" -#include "w_wad.h" - - - -//----------------------------------------------------------------------- -// -// Interface classes to 7z library -// -//----------------------------------------------------------------------- - -extern ISzAlloc g_Alloc; - -struct CZDFileInStream -{ - ISeekInStream s; - FileReader &File; - - CZDFileInStream(FileReader &_file) - : File(_file) - { - s.Read = Read; - s.Seek = Seek; - } - - static SRes Read(const ISeekInStream *pp, void *buf, size_t *size) - { - CZDFileInStream *p = (CZDFileInStream *)pp; - auto numread = p->File.Read(buf, (long)*size); - if (numread < 0) - { - *size = 0; - return SZ_ERROR_READ; - } - *size = numread; - return SZ_OK; - } - - static SRes Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin) - { - CZDFileInStream *p = (CZDFileInStream *)pp; - FileReader::ESeek move_method; - int res; - if (origin == SZ_SEEK_SET) - { - move_method = FileReader::SeekSet; - } - else if (origin == SZ_SEEK_CUR) - { - move_method = FileReader::SeekCur; - } - else if (origin == SZ_SEEK_END) - { - move_method = FileReader::SeekEnd; - } - else - { - return 1; - } - res = (int)p->File.Seek((long)*pos, move_method); - *pos = p->File.Tell(); - return res; - } -}; - -struct C7zArchive -{ - CSzArEx DB; - CZDFileInStream ArchiveStream; - CLookToRead2 LookStream; - Byte StreamBuffer[1<<14]; - UInt32 BlockIndex; - Byte *OutBuffer; - size_t OutBufferSize; - - C7zArchive(FileReader &file) : ArchiveStream(file) - { - if (g_CrcTable[1] == 0) - { - CrcGenerateTable(); - } - file.Seek(0, FileReader::SeekSet); - LookToRead2_CreateVTable(&LookStream, false); - LookStream.realStream = &ArchiveStream.s; - LookToRead2_Init(&LookStream); - LookStream.bufSize = sizeof(StreamBuffer); - LookStream.buf = StreamBuffer; - SzArEx_Init(&DB); - BlockIndex = 0xFFFFFFFF; - OutBuffer = NULL; - OutBufferSize = 0; - } - - ~C7zArchive() - { - if (OutBuffer != NULL) - { - IAlloc_Free(&g_Alloc, OutBuffer); - } - SzArEx_Free(&DB, &g_Alloc); - } - - SRes Open() - { - return SzArEx_Open(&DB, &LookStream.vt, &g_Alloc, &g_Alloc); - } - - SRes Extract(UInt32 file_index, char *buffer) - { - size_t offset, out_size_processed; - SRes res = SzArEx_Extract(&DB, &LookStream.vt, file_index, - &BlockIndex, &OutBuffer, &OutBufferSize, - &offset, &out_size_processed, - &g_Alloc, &g_Alloc); - if (res == SZ_OK) - { - memcpy(buffer, OutBuffer + offset, out_size_processed); - } - return res; - } -}; -//========================================================================== -// -// Zip Lump -// -//========================================================================== - -struct F7ZLump : public FResourceLump -{ - int Position; - - virtual int FillCache(); - -}; - - -//========================================================================== -// -// 7-zip file -// -//========================================================================== - -class F7ZFile : public FResourceFile -{ - friend struct F7ZLump; - - F7ZLump *Lumps; - C7zArchive *Archive; - -public: - F7ZFile(const char * filename, FileReader &filer); - bool Open(bool quiet); - virtual ~F7ZFile(); - virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } -}; - - - -//========================================================================== -// -// 7Z file -// -//========================================================================== - -F7ZFile::F7ZFile(const char * filename, FileReader &filer) - : FResourceFile(filename, filer) -{ - Lumps = NULL; - Archive = NULL; -} - - -//========================================================================== -// -// Open it -// -//========================================================================== - -bool F7ZFile::Open(bool quiet) -{ - Archive = new C7zArchive(Reader); - int skipped = 0; - SRes res; - - res = Archive->Open(); - if (res != SZ_OK) - { - delete Archive; - Archive = NULL; - if (!quiet) - { - Printf("\n" TEXTCOLOR_RED "%s: ", FileName.GetChars()); - if (res == SZ_ERROR_UNSUPPORTED) - { - Printf("Decoder does not support this archive\n"); - } - else if (res == SZ_ERROR_MEM) - { - Printf("Cannot allocate memory\n"); - } - else if (res == SZ_ERROR_CRC) - { - Printf("CRC error\n"); - } - else - { - Printf("error #%d\n", res); - } - } - return false; - } - - CSzArEx* const archPtr = &Archive->DB; - - NumLumps = archPtr->NumFiles; - Lumps = new F7ZLump[NumLumps]; - - F7ZLump *lump_p = Lumps; - TArray nameUTF16; - TArray nameASCII; - - for (uint32_t i = 0; i < NumLumps; ++i) - { - // skip Directories - if (SzArEx_IsDir(archPtr, i)) - { - skipped++; - continue; - } - - const size_t nameLength = SzArEx_GetFileNameUtf16(archPtr, i, NULL); - - if (0 == nameLength) - { - ++skipped; - continue; - } - - nameUTF16.Resize((unsigned)nameLength); - nameASCII.Resize((unsigned)nameLength); - SzArEx_GetFileNameUtf16(archPtr, i, &nameUTF16[0]); - for (size_t c = 0; c < nameLength; ++c) - { - nameASCII[c] = static_cast(nameUTF16[c]); - } - FixPathSeperator(&nameASCII[0]); - - FString name = &nameASCII[0]; - name.ToLower(); - - lump_p->LumpNameSetup(name); - lump_p->LumpSize = static_cast(SzArEx_GetFileSize(archPtr, i)); - lump_p->Owner = this; - lump_p->Flags = LUMPF_ZIPFILE|LUMPF_COMPRESSED; - lump_p->Position = i; - lump_p->CheckEmbedded(); - lump_p++; - } - // Resize the lump record array to its actual size - NumLumps -= skipped; - - if (NumLumps > 0) - { - // Quick check for unsupported compression method - - TArray temp; - temp.Resize(Lumps[0].LumpSize); - - if (SZ_OK != Archive->Extract(Lumps[0].Position, &temp[0])) - { - if (!quiet) Printf("\n%s: unsupported 7z/LZMA file!\n", FileName.GetChars()); - return false; - } - } - - if (!quiet && !batchrun) Printf(", %d lumps\n", NumLumps); - - GenerateHash(); - PostProcessArchive(&Lumps[0], sizeof(F7ZLump)); - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -F7ZFile::~F7ZFile() -{ - if (Lumps != NULL) - { - delete[] Lumps; - } - if (Archive != NULL) - { - delete Archive; - } -} - -//========================================================================== -// -// Fills the lump cache and performs decompression -// -//========================================================================== - -int F7ZLump::FillCache() -{ - Cache = new char[LumpSize]; - static_cast(Owner)->Archive->Extract(Position, Cache); - RefCount = 1; - return 1; -} - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet) -{ - char head[k7zSignatureSize]; - - if (file.GetLength() >= k7zSignatureSize) - { - file.Seek(0, FileReader::SeekSet); - file.Read(&head, k7zSignatureSize); - file.Seek(0, FileReader::SeekSet); - if (!memcmp(head, k7zSignature, k7zSignatureSize)) - { - FResourceFile *rf = new F7ZFile(filename, file); - if (rf->Open(quiet)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; - } - } - return NULL; -} - - - diff --git a/src/gamedata/resourcefiles/file_directory.cpp b/src/gamedata/resourcefiles/file_directory.cpp deleted file mode 100644 index bd04f27432f..00000000000 --- a/src/gamedata/resourcefiles/file_directory.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* -** file_directory.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2008-2009 Randy Heit -** Copyright 2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - - -#include - -#include "resourcefile.h" -#include "cmdlib.h" -#include "doomtype.h" -#include "i_system.h" - - - -//========================================================================== -// -// Zip Lump -// -//========================================================================== - -struct FDirectoryLump : public FResourceLump -{ - virtual FileReader NewReader(); - virtual int FillCache(); - - FString mFullPath; -}; - - -//========================================================================== -// -// Zip file -// -//========================================================================== - -class FDirectory : public FResourceFile -{ - TArray Lumps; - const bool nosubdir; - - int AddDirectory(const char *dirpath); - void AddEntry(const char *fullpath, int size); - -public: - FDirectory(const char * dirname, bool nosubdirflag = false); - bool Open(bool quiet); - virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } -}; - - - -//========================================================================== -// -// -// -//========================================================================== - -FDirectory::FDirectory(const char * directory, bool nosubdirflag) -: FResourceFile(NULL), nosubdir(nosubdirflag) -{ - FString dirname; - - #ifdef _WIN32 - directory = _fullpath(NULL, directory, _MAX_PATH); - #else - // Todo for Linux: Resolve the path before using it - #endif - dirname = directory; -#ifdef _WIN32 - free((void *)directory); -#endif - dirname.Substitute("\\", "/"); - if (dirname[dirname.Len()-1] != '/') dirname += '/'; - FileName = dirname; -} - - -//========================================================================== -// -// Windows version -// -//========================================================================== - -int FDirectory::AddDirectory(const char *dirpath) -{ - void * handle; - int count = 0; - - FString dirmatch = dirpath; - findstate_t find; - dirmatch += '*'; - - handle = I_FindFirst(dirmatch.GetChars(), &find); - if (handle == ((void *)(-1))) - { - Printf("Could not scan '%s': %s\n", dirpath, strerror(errno)); - } - else - { - do - { - // I_FindName only returns the file's name and not its full path - auto attr = I_FindAttr(&find); - if (attr & FA_HIDDEN) - { - // Skip hidden files and directories. (Prevents SVN bookkeeping - // info from being included.) - continue; - } - FString fi = I_FindName(&find); - if (attr & FA_DIREC) - { - if (nosubdir || (fi[0] == '.' && - (fi[1] == '\0' || - (fi[1] == '.' && fi[2] == '\0')))) - { - // Do not record . and .. directories. - continue; - } - FString newdir = dirpath; - newdir << fi << '/'; - count += AddDirectory(newdir); - } - else - { - if (strstr(fi, ".orig") || strstr(fi, ".bak")) - { - // We shouldn't add backup files to the file system - continue; - } - size_t size = 0; - FString fn = FString(dirpath) + fi; - if (GetFileInfo(fn, &size, nullptr)) - { - AddEntry(fn, (int)size); - count++; - } - } - - } while (I_FindNext (handle, &find) == 0); - I_FindClose (handle); - } - return count; -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FDirectory::Open(bool quiet) -{ - NumLumps = AddDirectory(FileName); - if (!quiet) Printf(", %d lumps\n", NumLumps); - PostProcessArchive(&Lumps[0], sizeof(FDirectoryLump)); - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FDirectory::AddEntry(const char *fullpath, int size) -{ - FDirectoryLump *lump_p = &Lumps[Lumps.Reserve(1)]; - - // Store the full path here so that we can access the file later, even if it is from a filter directory. - lump_p->mFullPath = fullpath; - - // [mxd] Convert name to lowercase - FString name = fullpath + strlen(FileName); - name.ToLower(); - - // The lump's name is only the part relative to the main directory - lump_p->LumpNameSetup(name); - lump_p->LumpSize = size; - lump_p->Owner = this; - lump_p->Flags = 0; - lump_p->CheckEmbedded(); -} - - -//========================================================================== -// -// -// -//========================================================================== - -FileReader FDirectoryLump::NewReader() -{ - FileReader fr; - fr.OpenFile(mFullPath); - return fr; -} - -//========================================================================== -// -// -// -//========================================================================== - -int FDirectoryLump::FillCache() -{ - FileReader fr; - Cache = new char[LumpSize]; - if (!fr.OpenFile(mFullPath)) - { - memset(Cache, 0, LumpSize); - return 0; - } - fr.Read(Cache, LumpSize); - RefCount = 1; - return 1; -} - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *CheckDir(const char *filename, bool quiet) -{ - FResourceFile *rf = new FDirectory(filename); - if (rf->Open(quiet)) return rf; - delete rf; - return NULL; -} - diff --git a/src/gamedata/resourcefiles/file_grp.cpp b/src/gamedata/resourcefiles/file_grp.cpp deleted file mode 100644 index 81657a3c5d2..00000000000 --- a/src/gamedata/resourcefiles/file_grp.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -** file_grp.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** Copyright 2005-2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "resourcefile.h" -#include "w_wad.h" -#include "doomtype.h" - -//========================================================================== -// -// -// -//========================================================================== - -struct GrpInfo -{ - uint32_t Magic[3]; - uint32_t NumLumps; -}; - -struct GrpLump -{ - union - { - struct - { - char Name[12]; - uint32_t Size; - }; - char NameWithZero[13]; - }; -}; - - -//========================================================================== -// -// Build GRP file -// -//========================================================================== - -class FGrpFile : public FUncompressedFile -{ -public: - FGrpFile(const char * filename, FileReader &file); - bool Open(bool quiet); -}; - - -//========================================================================== -// -// Initializes a Build GRP file -// -//========================================================================== - -FGrpFile::FGrpFile(const char *filename, FileReader &file) -: FUncompressedFile(filename, file) -{ -} - -//========================================================================== -// -// Open it -// -//========================================================================== - -bool FGrpFile::Open(bool quiet) -{ - GrpInfo header; - - Reader.Read(&header, sizeof(header)); - NumLumps = LittleLong(header.NumLumps); - - GrpLump *fileinfo = new GrpLump[NumLumps]; - Reader.Read (fileinfo, NumLumps * sizeof(GrpLump)); - - Lumps.Resize(NumLumps); - - int Position = sizeof(GrpInfo) + NumLumps * sizeof(GrpLump); - - for(uint32_t i = 0; i < NumLumps; i++) - { - Lumps[i].Owner = this; - Lumps[i].Position = Position; - Lumps[i].LumpSize = LittleLong(fileinfo[i].Size); - Position += fileinfo[i].Size; - Lumps[i].Namespace = ns_global; - Lumps[i].Flags = 0; - fileinfo[i].NameWithZero[12] = '\0'; // Be sure filename is null-terminated - Lumps[i].LumpNameSetup(fileinfo[i].NameWithZero); - } - if (!quiet && !batchrun) Printf(", %d lumps\n", NumLumps); - GenerateHash(); - delete[] fileinfo; - return true; -} - - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet) -{ - char head[12]; - - if (file.GetLength() >= 12) - { - file.Seek(0, FileReader::SeekSet); - file.Read(&head, 12); - file.Seek(0, FileReader::SeekSet); - if (!memcmp(head, "KenSilverman", 12)) - { - FResourceFile *rf = new FGrpFile(filename, file); - if (rf->Open(quiet)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; - } - } - return NULL; -} - diff --git a/src/gamedata/resourcefiles/file_lump.cpp b/src/gamedata/resourcefiles/file_lump.cpp deleted file mode 100644 index bd0cc1f1b51..00000000000 --- a/src/gamedata/resourcefiles/file_lump.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* -** file_lump.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "resourcefile.h" -#include "cmdlib.h" -#include "w_wad.h" -#include "doomtype.h" - -//========================================================================== -// -// Single lump -// -//========================================================================== - -class FLumpFile : public FUncompressedFile -{ -public: - FLumpFile(const char * filename, FileReader &file); - bool Open(bool quiet); -}; - - -//========================================================================== -// -// FLumpFile::FLumpFile -// -//========================================================================== - -FLumpFile::FLumpFile(const char *filename, FileReader &file) - : FUncompressedFile(filename, file) -{ -} - -//========================================================================== -// -// Open it -// -//========================================================================== - -bool FLumpFile::Open(bool quiet) -{ - FString name(ExtractFileBase (FileName)); - - Lumps.Resize(1); - uppercopy(Lumps[0].Name, name); - Lumps[0].Name[8] = 0; - Lumps[0].Owner = this; - Lumps[0].Position = 0; - Lumps[0].LumpSize = (int)Reader.GetLength(); - Lumps[0].Namespace = ns_global; - Lumps[0].Flags = 0; - Lumps[0].FullName = ""; - NumLumps = 1; - if (!quiet) - { - Printf("\n"); - } - return true; -} - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *CheckLump(const char *filename, FileReader &file, bool quiet) -{ - // always succeeds - FResourceFile *rf = new FLumpFile(filename, file); - if (rf->Open(quiet)) return rf; - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; - return NULL; -} - diff --git a/src/gamedata/resourcefiles/file_pak.cpp b/src/gamedata/resourcefiles/file_pak.cpp deleted file mode 100644 index 2b4d3965865..00000000000 --- a/src/gamedata/resourcefiles/file_pak.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -** file_pak.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "resourcefile.h" -#include "w_wad.h" -#include "doomtype.h" - -//========================================================================== -// -// -// -//========================================================================== - -struct dpackfile_t -{ - char name[56]; - int filepos, filelen; -} ; - -struct dpackheader_t -{ - int ident; // == IDPAKHEADER - int dirofs; - int dirlen; -} ; - - -//========================================================================== -// -// Wad file -// -//========================================================================== - -class FPakFile : public FUncompressedFile -{ -public: - FPakFile(const char * filename, FileReader &file); - bool Open(bool quiet); -}; - - -//========================================================================== -// -// FWadFile::FWadFile -// -// Initializes a WAD file -// -//========================================================================== - -FPakFile::FPakFile(const char *filename, FileReader &file) - : FUncompressedFile(filename, file) -{ -} - -//========================================================================== -// -// Open it -// -//========================================================================== - -bool FPakFile::Open(bool quiet) -{ - dpackheader_t header; - - Reader.Read(&header, sizeof(header)); - NumLumps = LittleLong(header.dirlen) / sizeof(dpackfile_t); - header.dirofs = LittleLong(header.dirofs); - - TArray fileinfo(NumLumps, true); - Reader.Seek (header.dirofs, FileReader::SeekSet); - Reader.Read (fileinfo.Data(), NumLumps * sizeof(dpackfile_t)); - - Lumps.Resize(NumLumps); - - if (!quiet && !batchrun) Printf(", %d lumps\n", NumLumps); - - for(uint32_t i = 0; i < NumLumps; i++) - { - Lumps[i].LumpNameSetup(fileinfo[i].name); - Lumps[i].Owner = this; - Lumps[i].Position = LittleLong(fileinfo[i].filepos); - Lumps[i].LumpSize = LittleLong(fileinfo[i].filelen); - Lumps[i].CheckEmbedded(); - } - GenerateHash(); - return true; -} - - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet) -{ - char head[4]; - - if (file.GetLength() >= 12) - { - file.Seek(0, FileReader::SeekSet); - file.Read(&head, 4); - file.Seek(0, FileReader::SeekSet); - if (!memcmp(head, "PACK", 4)) - { - FResourceFile *rf = new FPakFile(filename, file); - if (rf->Open(quiet)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; - } - } - return NULL; -} - diff --git a/src/gamedata/resourcefiles/file_rff.cpp b/src/gamedata/resourcefiles/file_rff.cpp deleted file mode 100644 index 35402c3add9..00000000000 --- a/src/gamedata/resourcefiles/file_rff.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* -** file_rff.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** Copyright 2005-2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "resourcefile.h" -#include "templates.h" -#include "w_wad.h" -#include "doomtype.h" - -//========================================================================== -// -// -// -//========================================================================== - -struct RFFInfo -{ - // Should be "RFF\x18" - uint32_t Magic; - uint32_t Version; - uint32_t DirOfs; - uint32_t NumLumps; -}; - -struct RFFLump -{ - uint32_t DontKnow1[4]; - uint32_t FilePos; - uint32_t Size; - uint32_t DontKnow2; - uint32_t Time; - uint8_t Flags; - char Extension[3]; - char Name[8]; - uint32_t IndexNum; // Used by .sfx, possibly others -}; - -//========================================================================== -// -// Blood RFF lump (uncompressed lump with encryption) -// -//========================================================================== - -struct FRFFLump : public FUncompressedLump -{ - virtual FileReader *GetReader(); - virtual int FillCache(); - - uint32_t IndexNum; - - int GetIndexNum() const { return IndexNum; } -}; - -//========================================================================== -// -// BloodCrypt -// -//========================================================================== - -void BloodCrypt (void *data, int key, int len) -{ - int p = (uint8_t)key, i; - - for (i = 0; i < len; ++i) - { - ((uint8_t *)data)[i] ^= (unsigned char)(p+(i>>1)); - } -} - - -//========================================================================== -// -// Blood RFF file -// -//========================================================================== - -class FRFFFile : public FResourceFile -{ - FRFFLump *Lumps; - -public: - FRFFFile(const char * filename, FileReader &file); - virtual ~FRFFFile(); - virtual bool Open(bool quiet); - virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } -}; - - -//========================================================================== -// -// Initializes a Blood RFF file -// -//========================================================================== - -FRFFFile::FRFFFile(const char *filename, FileReader &file) -: FResourceFile(filename, file) -{ - Lumps = NULL; -} - -//========================================================================== -// -// Initializes a Blood RFF file -// -//========================================================================== - -bool FRFFFile::Open(bool quiet) -{ - RFFLump *lumps; - RFFInfo header; - - Reader.Read(&header, sizeof(header)); - - NumLumps = LittleLong(header.NumLumps); - header.DirOfs = LittleLong(header.DirOfs); - lumps = new RFFLump[header.NumLumps]; - Reader.Seek (header.DirOfs, FileReader::SeekSet); - Reader.Read (lumps, header.NumLumps * sizeof(RFFLump)); - BloodCrypt (lumps, header.DirOfs, header.NumLumps * sizeof(RFFLump)); - - Lumps = new FRFFLump[NumLumps]; - - if (!quiet && !batchrun) Printf(", %d lumps\n", NumLumps); - for (uint32_t i = 0; i < NumLumps; ++i) - { - Lumps[i].Position = LittleLong(lumps[i].FilePos); - Lumps[i].LumpSize = LittleLong(lumps[i].Size); - Lumps[i].Owner = this; - if (lumps[i].Flags & 0x10) - { - Lumps[i].Flags |= LUMPF_BLOODCRYPT; - } - Lumps[i].IndexNum = LittleLong(lumps[i].IndexNum); - // Rearrange the name and extension to construct the fullname. - char name[13]; - strncpy(name, lumps[i].Name, 8); - name[8] = 0; - size_t len = strlen(name); - assert(len + 4 <= 12); - name[len+0] = '.'; - name[len+1] = lumps[i].Extension[0]; - name[len+2] = lumps[i].Extension[1]; - name[len+3] = lumps[i].Extension[2]; - name[len+4] = 0; - Lumps[i].LumpNameSetup(name); - if (name[len+1] == 'S' && name[len+2] == 'F' && name[len+3] == 'X') - { - Lumps[i].Namespace = ns_bloodsfx; - } - else if (name[len+1] == 'R' && name[len+2] == 'A' && name[len+3] == 'W') - { - Lumps[i].Namespace = ns_bloodraw; - } - } - delete[] lumps; - GenerateHash(); - return true; -} - -FRFFFile::~FRFFFile() -{ - if (Lumps != NULL) - { - delete[] Lumps; - } -} - - -//========================================================================== -// -// Get reader (only returns non-NULL if not encrypted) -// -//========================================================================== - -FileReader *FRFFLump::GetReader() -{ - // Don't return the reader if this lump is encrypted - // In that case always force caching of the lump - if (!(Flags & LUMPF_BLOODCRYPT)) - { - return FUncompressedLump::GetReader(); - } - else - { - return NULL; - } -} - -//========================================================================== -// -// Fills the lump cache and performs decryption -// -//========================================================================== - -int FRFFLump::FillCache() -{ - int res = FUncompressedLump::FillCache(); - - if (Flags & LUMPF_BLOODCRYPT) - { - int cryptlen = MIN (LumpSize, 256); - uint8_t *data = (uint8_t *)Cache; - - for (int i = 0; i < cryptlen; ++i) - { - data[i] ^= i >> 1; - } - } - return res; -} - - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet) -{ - char head[4]; - - if (file.GetLength() >= 16) - { - file.Seek(0, FileReader::SeekSet); - file.Read(&head, 4); - file.Seek(0, FileReader::SeekSet); - if (!memcmp(head, "RFF\x1a", 4)) - { - FResourceFile *rf = new FRFFFile(filename, file); - if (rf->Open(quiet)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; - } - } - return NULL; -} - - - diff --git a/src/gamedata/resourcefiles/file_wad.cpp b/src/gamedata/resourcefiles/file_wad.cpp deleted file mode 100644 index 169cd975d7e..00000000000 --- a/src/gamedata/resourcefiles/file_wad.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/* -** file_wad.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** Copyright 2005-2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include -#include "resourcefile.h" -#include "v_text.h" -#include "w_wad.h" -#include "gi.h" -#include "doomerrors.h" - -//========================================================================== -// -// Wad Lump (with console doom LZSS support) -// -//========================================================================== - -class FWadFileLump : public FResourceLump -{ -public: - bool Compressed; - int Position; - - int GetFileOffset() { return Position; } - FileReader *GetReader() - { - if(!Compressed) - { - Owner->Reader.Seek(Position, FileReader::SeekSet); - return &Owner->Reader; - } - return NULL; - } - int FillCache() - { - if(!Compressed) - { - const char * buffer = Owner->Reader.GetBuffer(); - - if (buffer != NULL) - { - // This is an in-memory file so the cache can point directly to the file's data. - Cache = const_cast(buffer) + Position; - RefCount = -1; - return -1; - } - } - - Owner->Reader.Seek(Position, FileReader::SeekSet); - Cache = new char[LumpSize]; - - if(Compressed) - { - FileReader lzss; - if (lzss.OpenDecompressor(Owner->Reader, LumpSize, METHOD_LZSS, false, [](const char* err) { I_Error("%s", err); })) - { - lzss.Read(Cache, LumpSize); - } - } - else - Owner->Reader.Read(Cache, LumpSize); - - RefCount = 1; - return 1; - } -}; - -//========================================================================== -// -// Wad file -// -//========================================================================== - -class FWadFile : public FResourceFile -{ - FWadFileLump *Lumps; - - bool IsMarker(int lump, const char *marker); - void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, bool flathack=false); - void SkinHack (); - -public: - FWadFile(const char * filename, FileReader &file); - ~FWadFile(); - void FindStrifeTeaserVoices (); - FResourceLump *GetLump(int lump) { return &Lumps[lump]; } - bool Open(bool quiet); -}; - - -//========================================================================== -// -// FWadFile::FWadFile -// -// Initializes a WAD file -// -//========================================================================== - -FWadFile::FWadFile(const char *filename, FileReader &file) - : FResourceFile(filename, file) -{ - Lumps = NULL; -} - -FWadFile::~FWadFile() -{ - delete[] Lumps; -} - -//========================================================================== -// -// Open it -// -//========================================================================== - -bool FWadFile::Open(bool quiet) -{ - wadinfo_t header; - uint32_t InfoTableOfs; - bool isBigEndian = false; // Little endian is assumed until proven otherwise - auto wadSize = Reader.GetLength(); - - Reader.Read(&header, sizeof(header)); - NumLumps = LittleLong(header.NumLumps); - InfoTableOfs = LittleLong(header.InfoTableOfs); - - // Check to see if the little endian interpretation is valid - // This should be sufficient to detect big endian wads. - if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) - { - NumLumps = BigLong(header.NumLumps); - InfoTableOfs = BigLong(header.InfoTableOfs); - isBigEndian = true; - - // Check again to detect broken wads - if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) - { - I_Error("Cannot load broken WAD file %s\n", FileName.GetChars()); - } - } - - wadlump_t *fileinfo = new wadlump_t[NumLumps]; - Reader.Seek (InfoTableOfs, FileReader::SeekSet); - Reader.Read (fileinfo, NumLumps * sizeof(wadlump_t)); - - Lumps = new FWadFileLump[NumLumps]; - - for(uint32_t i = 0; i < NumLumps; i++) - { - uppercopy (Lumps[i].Name, fileinfo[i].Name); - Lumps[i].Name[8] = 0; - Lumps[i].Compressed = !(gameinfo.flags & GI_SHAREWARE) && (Lumps[i].Name[0] & 0x80) == 0x80; - Lumps[i].Name[0] &= ~0x80; - - Lumps[i].Owner = this; - Lumps[i].Position = isBigEndian ? BigLong(fileinfo[i].FilePos) : LittleLong(fileinfo[i].FilePos); - Lumps[i].LumpSize = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size); - Lumps[i].Namespace = ns_global; - Lumps[i].Flags = Lumps[i].Compressed? LUMPF_COMPRESSED : 0; - Lumps[i].FullName = ""; - - // Check if the lump is within the WAD file and print a warning if not. - if (Lumps[i].Position + Lumps[i].LumpSize > wadSize || Lumps[i].Position < 0 || Lumps[i].LumpSize < 0) - { - if (Lumps[i].LumpSize != 0) - { - Printf(PRINT_HIGH, "%s: Lump %s contains invalid positioning info and will be ignored\n", FileName.GetChars(), Lumps[i].Name); - Lumps[i].Name[0] = 0; - } - Lumps[i].LumpSize = Lumps[i].Position = 0; - } - } - - delete[] fileinfo; - GenerateHash(); // Do this before the lump processing below. - - if (!quiet) - { - if (!batchrun) Printf(", %d lumps\n", NumLumps); - - // don't bother with namespaces here. We won't need them. - SetNamespace("S_START", "S_END", ns_sprites); - SetNamespace("F_START", "F_END", ns_flats, true); - SetNamespace("C_START", "C_END", ns_colormaps); - SetNamespace("A_START", "A_END", ns_acslibrary); - SetNamespace("TX_START", "TX_END", ns_newtextures); - SetNamespace("V_START", "V_END", ns_strifevoices); - SetNamespace("HI_START", "HI_END", ns_hires); - SetNamespace("VX_START", "VX_END", ns_voxels); - SkinHack(); - } - return true; -} - -//========================================================================== -// -// IsMarker -// -// (from BOOM) -// -//========================================================================== - -inline bool FWadFile::IsMarker(int lump, const char *marker) -{ - if (Lumps[lump].Name[0] == marker[0]) - { - return (!strcmp(Lumps[lump].Name, marker) || - (marker[1] == '_' && !strcmp(Lumps[lump].Name+1, marker))); - } - else return false; -} - -//========================================================================== -// -// SetNameSpace -// -// Sets namespace information for the lumps. It always looks for the first -// x_START and the last x_END lump, except when loading flats. In this case -// F_START may be absent and if that is the case all lumps with a size of -// 4096 will be flagged appropriately. -// -//========================================================================== - -// This class was supposed to be local in the function but GCC -// does not like that. -struct Marker -{ - int markertype; - unsigned int index; -}; - -void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, bool flathack) -{ - bool warned = false; - int numstartmarkers = 0, numendmarkers = 0; - unsigned int i; - TArray markers; - - for(i = 0; i < NumLumps; i++) - { - if (IsMarker(i, startmarker)) - { - Marker m = { 0, i }; - markers.Push(m); - numstartmarkers++; - } - else if (IsMarker(i, endmarker)) - { - Marker m = { 1, i }; - markers.Push(m); - numendmarkers++; - } - } - - if (numstartmarkers == 0) - { - if (numendmarkers == 0) return; // no markers found - - Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", endmarker, startmarker); - - - if (flathack) - { - // We have found no F_START but one or more F_END markers. - // mark all lumps before the last F_END marker as potential flats. - unsigned int end = markers[markers.Size()-1].index; - for(unsigned int i = 0; i < end; i++) - { - if (Lumps[i].LumpSize == 4096) - { - // We can't add this to the flats namespace but - // it needs to be flagged for the texture manager. - DPrintf(DMSG_NOTIFY, "Marking %s as potential flat\n", Lumps[i].Name); - Lumps[i].Flags |= LUMPF_MAYBEFLAT; - } - } - } - return; - } - - i = 0; - while (i < markers.Size()) - { - int start, end; - if (markers[i].markertype != 0) - { - Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", endmarker, startmarker); - i++; - continue; - } - start = i++; - - // skip over subsequent x_START markers - while (i < markers.Size() && markers[i].markertype == 0) - { - Printf(TEXTCOLOR_YELLOW"WARNING: duplicate %s marker found.\n", startmarker); - i++; - continue; - } - // same for x_END markers - while (i < markers.Size()-1 && (markers[i].markertype == 1 && markers[i+1].markertype == 1)) - { - Printf(TEXTCOLOR_YELLOW"WARNING: duplicate %s marker found.\n", endmarker); - i++; - continue; - } - // We found a starting marker but no end marker. Ignore this block. - if (i >= markers.Size()) - { - Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", startmarker, endmarker); - end = NumLumps; - } - else - { - end = markers[i++].index; - } - - // we found a marked block - DPrintf(DMSG_NOTIFY, "Found %s block at (%d-%d)\n", startmarker, markers[start].index, end); - for(int j = markers[start].index + 1; j < end; j++) - { - if (Lumps[j].Namespace != ns_global) - { - if (!warned) - { - Printf(TEXTCOLOR_YELLOW"WARNING: Overlapping namespaces found (lump %d)\n", j); - } - warned = true; - } - else if (space == ns_sprites && Lumps[j].LumpSize < 8) - { - // sf 26/10/99: - // ignore sprite lumps smaller than 8 bytes (the smallest possible) - // in size -- this was used by some dmadds wads - // as an 'empty' graphics resource - DPrintf(DMSG_WARNING, " Skipped empty sprite %s (lump %d)\n", Lumps[j].Name, j); - } - else - { - Lumps[j].Namespace = space; - } - } - } -} - - -//========================================================================== -// -// W_SkinHack -// -// Tests a wad file to see if it contains an S_SKIN marker. If it does, -// every lump in the wad is moved into a new namespace. Because skins are -// only supposed to replace player sprites, sounds, or faces, this should -// not be a problem. Yes, there are skins that replace more than that, but -// they are such a pain, and breaking them like this was done on purpose. -// This also renames any S_SKINxx lumps to just S_SKIN. -// -//========================================================================== - -void FWadFile::SkinHack () -{ - static int namespc = ns_firstskin; - bool skinned = false; - bool hasmap = false; - uint32_t i; - - for (i = 0; i < NumLumps; i++) - { - FResourceLump *lump = &Lumps[i]; - - if (lump->Name[0] == 'S' && - lump->Name[1] == '_' && - lump->Name[2] == 'S' && - lump->Name[3] == 'K' && - lump->Name[4] == 'I' && - lump->Name[5] == 'N') - { // Wad has at least one skin. - lump->Name[6] = lump->Name[7] = 0; - if (!skinned) - { - skinned = true; - uint32_t j; - - for (j = 0; j < NumLumps; j++) - { - Lumps[j].Namespace = namespc; - } - namespc++; - } - } - if ((lump->Name[0] == 'M' && - lump->Name[1] == 'A' && - lump->Name[2] == 'P' && - lump->Name[3] >= '0' && lump->Name[3] <= '9' && - lump->Name[4] >= '0' && lump->Name[4] <= '9' && - lump->Name[5] >= '\0') - || - (lump->Name[0] == 'E' && - lump->Name[1] >= '0' && lump->Name[1] <= '9' && - lump->Name[2] == 'M' && - lump->Name[3] >= '0' && lump->Name[3] <= '9' && - lump->Name[4] >= '\0')) - { - hasmap = true; - } - } - if (skinned && hasmap) - { - Printf (TEXTCOLOR_BLUE - "The maps in %s will not be loaded because it has a skin.\n" - TEXTCOLOR_BLUE - "You should remove the skin from the wad to play these maps.\n", - FileName.GetChars()); - } -} - - -//========================================================================== -// -// FindStrifeTeaserVoices -// -// Strife0.wad does not have the voices between V_START/V_END markers, so -// figure out which lumps are voices based on their names. -// -//========================================================================== - -void FWadFile::FindStrifeTeaserVoices () -{ - for (uint32_t i = 0; i <= NumLumps; ++i) - { - if (Lumps[i].Name[0] == 'V' && - Lumps[i].Name[1] == 'O' && - Lumps[i].Name[2] == 'C') - { - int j; - - for (j = 3; j < 8; ++j) - { - if (Lumps[i].Name[j] != 0 && !isdigit(Lumps[i].Name[j])) - break; - } - if (j == 8) - { - Lumps[i].Namespace = ns_strifevoices; - } - } - } -} - - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet) -{ - char head[4]; - - if (file.GetLength() >= 12) - { - file.Seek(0, FileReader::SeekSet); - file.Read(&head, 4); - file.Seek(0, FileReader::SeekSet); - if (!memcmp(head, "IWAD", 4) || !memcmp(head, "PWAD", 4)) - { - FResourceFile *rf = new FWadFile(filename, file); - if (rf->Open(quiet)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; - } - } - return NULL; -} - diff --git a/src/gamedata/resourcefiles/file_zip.cpp b/src/gamedata/resourcefiles/file_zip.cpp deleted file mode 100644 index d661a8158f5..00000000000 --- a/src/gamedata/resourcefiles/file_zip.cpp +++ /dev/null @@ -1,671 +0,0 @@ -/* -** file_zip.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** Copyright 2005-2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include -#include "file_zip.h" -#include "cmdlib.h" -#include "templates.h" -#include "v_text.h" -#include "w_wad.h" -#include "w_zip.h" - -#include "ancientzip.h" - -#define BUFREADCOMMENT (0x400) - -//========================================================================== -// -// Decompression subroutine -// -//========================================================================== - -static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int LumpSize, int CompressedSize, int GPFlags) -{ - try - { - switch (Method) - { - case METHOD_STORED: - { - Reader.Read(Cache, LumpSize); - break; - } - - case METHOD_DEFLATE: - case METHOD_BZIP2: - case METHOD_LZMA: - { - FileReader frz; - if (frz.OpenDecompressor(Reader, LumpSize, Method, false, [](const char* err) { I_Error("%s", err); })) - { - frz.Read(Cache, LumpSize); - } - break; - } - - // Fixme: These should also use a stream - case METHOD_IMPLODE: - { - FZipExploder exploder; - exploder.Explode((unsigned char *)Cache, LumpSize, Reader, CompressedSize, GPFlags); - break; - } - - case METHOD_SHRINK: - { - ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize); - break; - } - - default: - assert(0); - return false; - } - } - catch (CRecoverableError &err) - { - Printf("%s\n", err.GetMessage()); - return false; - } - return true; -} - -bool FCompressedBuffer::Decompress(char *destbuffer) -{ - FileReader mr; - mr.OpenMemory(mBuffer, mCompressedSize); - return UncompressZipLump(destbuffer, mr, mMethod, mSize, mCompressedSize, mZipFlags); -} - -//----------------------------------------------------------------------- -// -// Finds the central directory end record in the end of the file. -// Taken from Quake3 source but the file in question is not GPL'ed. ;) -// -//----------------------------------------------------------------------- - -static uint32_t Zip_FindCentralDir(FileReader &fin) -{ - unsigned char buf[BUFREADCOMMENT + 4]; - uint32_t FileSize; - uint32_t uBackRead; - uint32_t uMaxBack; // maximum size of global comment - uint32_t uPosFound=0; - - FileSize = (uint32_t)fin.GetLength(); - uMaxBack = MIN(0xffff, FileSize); - - uBackRead = 4; - while (uBackRead < uMaxBack) - { - uint32_t uReadSize, uReadPos; - int i; - if (uBackRead + BUFREADCOMMENT > uMaxBack) - uBackRead = uMaxBack; - else - uBackRead += BUFREADCOMMENT; - uReadPos = FileSize - uBackRead; - - uReadSize = MIN((BUFREADCOMMENT + 4), (FileSize - uReadPos)); - - if (fin.Seek(uReadPos, FileReader::SeekSet) != 0) break; - - if (fin.Read(buf, (int32_t)uReadSize) != (int32_t)uReadSize) break; - - for (i = (int)uReadSize - 3; (i--) > 0;) - { - if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 5 && buf[i+3] == 6) - { - uPosFound = uReadPos + i; - break; - } - } - - if (uPosFound != 0) - break; - } - return uPosFound; -} - -//========================================================================== -// -// Zip file -// -//========================================================================== - -FZipFile::FZipFile(const char * filename, FileReader &file) -: FResourceFile(filename, file) -{ - Lumps = NULL; -} - -bool FZipFile::Open(bool quiet) -{ - uint32_t centraldir = Zip_FindCentralDir(Reader); - FZipEndOfCentralDirectory info; - int skipped = 0; - - Lumps = NULL; - - if (centraldir == 0) - { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: ZIP file corrupt!\n", FileName.GetChars()); - return false; - } - - // Read the central directory info. - Reader.Seek(centraldir, FileReader::SeekSet); - Reader.Read(&info, sizeof(FZipEndOfCentralDirectory)); - - // No multi-disk zips! - if (info.NumEntries != info.NumEntriesOnAllDisks || - info.FirstDisk != 0 || info.DiskNumber != 0) - { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars()); - return false; - } - - NumLumps = LittleShort(info.NumEntries); - Lumps = new FZipLump[NumLumps]; - - // Load the entire central directory. Too bad that this contains variable length entries... - int dirsize = LittleLong(info.DirectorySize); - void *directory = malloc(dirsize); - Reader.Seek(LittleLong(info.DirectoryOffset), FileReader::SeekSet); - Reader.Read(directory, dirsize); - - char *dirptr = (char*)directory; - FZipLump *lump_p = Lumps; - - FString name0; - bool foundspeciallump = false; - - // Check if all files have the same prefix so that this can be stripped out. - // This will only be done if there is either a MAPINFO, ZMAPINFO or GAMEINFO lump in the subdirectory, denoting a ZDoom mod. - if (NumLumps > 1) for (uint32_t i = 0; i < NumLumps; i++) - { - FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; - - int len = LittleShort(zip_fh->NameLength); - FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); - - dirptr += sizeof(FZipCentralDirectoryInfo) + - LittleShort(zip_fh->NameLength) + - LittleShort(zip_fh->ExtraLength) + - LittleShort(zip_fh->CommentLength); - - if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. - { - free(directory); - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); - return false; - } - - name.ToLower(); - if (i == 0) - { - // check for special names, if one of these gets found this must be treated as a normal zip. - bool isspecial = !name.Compare("flats/") || - name.IndexOf("/") < 0 || - !name.Compare("textures/") || - !name.Compare("hires/") || - !name.Compare("sprites/") || - !name.Compare("voxels/") || - !name.Compare("colormaps/") || - !name.Compare("acs/") || - !name.Compare("maps/") || - !name.Compare("voices/") || - !name.Compare("patches/") || - !name.Compare("graphics/") || - !name.Compare("sounds/") || - !name.Compare("music/"); - if (isspecial) break; - name0 = name; - } - else - { - if (name.IndexOf(name0) != 0) - { - name0 = ""; - break; - } - else if (!foundspeciallump) - { - // at least one of the more common definition lumps must be present. - if (name.IndexOf(name0 + "mapinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "zmapinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "gameinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "sndinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "sbarinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "menudef") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "gldefs") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "animdefs") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "decorate.") == 0) foundspeciallump = true; // DECORATE is a common subdirectory name, so the check needs to be a bit different. - else if (name.Compare(name0 + "decorate") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "zscript.") == 0) foundspeciallump = true; // same here. - else if (name.Compare(name0 + "zscript") == 0) foundspeciallump = true; - else if (name.Compare(name0 + "maps/") == 0) foundspeciallump = true; - } - } - } - // If it ran through the list without finding anything it should not attempt any path remapping. - if (!foundspeciallump) name0 = ""; - - dirptr = (char*)directory; - lump_p = Lumps; - for (uint32_t i = 0; i < NumLumps; i++) - { - FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; - - int len = LittleShort(zip_fh->NameLength); - FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); - if (name0.IsNotEmpty()) name = name.Mid(name0.Len()); - dirptr += sizeof(FZipCentralDirectoryInfo) + - LittleShort(zip_fh->NameLength) + - LittleShort(zip_fh->ExtraLength) + - LittleShort(zip_fh->CommentLength); - - if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. - { - free(directory); - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); - return false; - } - - // skip Directories - if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize) == 0)) - { - skipped++; - continue; - } - - // Ignore unknown compression formats - zip_fh->Method = LittleShort(zip_fh->Method); - if (zip_fh->Method != METHOD_STORED && - zip_fh->Method != METHOD_DEFLATE && - zip_fh->Method != METHOD_LZMA && - zip_fh->Method != METHOD_BZIP2 && - zip_fh->Method != METHOD_IMPLODE && - zip_fh->Method != METHOD_SHRINK) - { - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", FileName.GetChars(), name.GetChars(), zip_fh->Method); - skipped++; - continue; - } - // Also ignore encrypted entries - zip_fh->Flags = LittleShort(zip_fh->Flags); - if (zip_fh->Flags & ZF_ENCRYPTED) - { - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is encrypted. Encryption is not supported.\n", FileName.GetChars(), name.GetChars()); - skipped++; - continue; - } - - FixPathSeperator(name); - name.ToLower(); - - lump_p->LumpNameSetup(name); - lump_p->LumpSize = LittleLong(zip_fh->UncompressedSize); - lump_p->Owner = this; - // The start of the Reader will be determined the first time it is accessed. - lump_p->Flags = LUMPF_ZIPFILE | LUMPFZIP_NEEDFILESTART; - lump_p->Method = uint8_t(zip_fh->Method); - if (lump_p->Method != METHOD_STORED) lump_p->Flags |= LUMPF_COMPRESSED; - lump_p->GPFlags = zip_fh->Flags; - lump_p->CRC32 = zip_fh->CRC32; - lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize); - lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset); - lump_p->CheckEmbedded(); - - // Ignore some very specific names - if (0 == stricmp("dehacked.exe", name)) - { - memset(lump_p->Name, 0, sizeof(lump_p->Name)); - } - - lump_p++; - } - // Resize the lump record array to its actual size - NumLumps -= skipped; - free(directory); - - if (!quiet && !batchrun) Printf(TEXTCOLOR_NORMAL ", %d lumps\n", NumLumps); - - GenerateHash(); - PostProcessArchive(&Lumps[0], sizeof(FZipLump)); - return true; -} - -//========================================================================== -// -// Zip file -// -//========================================================================== - -FZipFile::~FZipFile() -{ - if (Lumps != NULL) delete [] Lumps; -} - -//========================================================================== -// -// -// -//========================================================================== - -FCompressedBuffer FZipLump::GetRawData() -{ - FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)CompressedSize, Method, GPFlags, CRC32, new char[CompressedSize] }; - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); - Owner->Reader.Seek(Position, FileReader::SeekSet); - Owner->Reader.Read(cbuf.mBuffer, CompressedSize); - return cbuf; -} - -//========================================================================== -// -// SetLumpAddress -// -//========================================================================== - -void FZipLump::SetLumpAddress() -{ - // This file is inside a zip and has not been opened before. - // Position points to the start of the local file header, which we must - // read and skip so that we can get to the actual file data. - FZipLocalFileHeader localHeader; - int skiplen; - - Owner->Reader.Seek(Position, FileReader::SeekSet); - Owner->Reader.Read(&localHeader, sizeof(localHeader)); - skiplen = LittleShort(localHeader.NameLength) + LittleShort(localHeader.ExtraLength); - Position += sizeof(localHeader) + skiplen; - Flags &= ~LUMPFZIP_NEEDFILESTART; -} - -//========================================================================== -// -// Get reader (only returns non-NULL if not encrypted) -// -//========================================================================== - -FileReader *FZipLump::GetReader() -{ - // Don't return the reader if this lump is encrypted - // In that case always force caching of the lump - if (Method == METHOD_STORED) - { - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); - Owner->Reader.Seek(Position, FileReader::SeekSet); - return &Owner->Reader; - } - else return NULL; -} - -//========================================================================== -// -// Fills the lump cache and performs decompression -// -//========================================================================== - -int FZipLump::FillCache() -{ - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); - const char *buffer; - - if (Method == METHOD_STORED && (buffer = Owner->Reader.GetBuffer()) != NULL) - { - // This is an in-memory file so the cache can point directly to the file's data. - Cache = const_cast(buffer) + Position; - RefCount = -1; - return -1; - } - - Owner->Reader.Seek(Position, FileReader::SeekSet); - Cache = new char[LumpSize]; - UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); - RefCount = 1; - return 1; -} - -//========================================================================== -// -// -// -//========================================================================== - -int FZipLump::GetFileOffset() -{ - if (Method != METHOD_STORED) return -1; - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); - return Position; -} - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet) -{ - char head[4]; - - if (file.GetLength() >= (long)sizeof(FZipLocalFileHeader)) - { - file.Seek(0, FileReader::SeekSet); - file.Read(&head, 4); - file.Seek(0, FileReader::SeekSet); - if (!memcmp(head, "PK\x3\x4", 4)) - { - FResourceFile *rf = new FZipFile(filename, file); - if (rf->Open(quiet)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; - } - } - return NULL; -} - - - -//========================================================================== -// -// time_to_dos -// -// Converts time from struct tm to the DOS format used by zip files. -// -//========================================================================== - -static std::pair time_to_dos(struct tm *time) -{ - std::pair val; - if (time == NULL || time->tm_year < 80) - { - val.first = val.second = 0; - } - else - { - val.first = (time->tm_year - 80) * 512 + (time->tm_mon + 1) * 32 + time->tm_mday; - val.second= time->tm_hour * 2048 + time->tm_min * 32 + time->tm_sec / 2; - } - return val; -} - -//========================================================================== -// -// append_to_zip -// -// Write a given file to the zipFile. -// -// zipfile: zip object to be written to -// -// returns: position = success, -1 = error -// -//========================================================================== - -int AppendToZip(FileWriter *zip_file, const char *filename, FCompressedBuffer &content, std::pair &dostime) -{ - FZipLocalFileHeader local; - int position; - - local.Magic = ZIP_LOCALFILE; - local.VersionToExtract[0] = 20; - local.VersionToExtract[1] = 0; - local.Flags = content.mMethod == METHOD_DEFLATE ? LittleShort((uint16_t)2) : LittleShort((uint16_t)content.mZipFlags); - local.Method = LittleShort((uint16_t)content.mMethod); - local.ModDate = LittleShort(dostime.first); - local.ModTime = LittleShort(dostime.second); - local.CRC32 = content.mCRC32; - local.UncompressedSize = LittleLong(content.mSize); - local.CompressedSize = LittleLong(content.mCompressedSize); - local.NameLength = LittleShort((unsigned short)strlen(filename)); - local.ExtraLength = 0; - - // Fill in local directory header. - - position = (int)zip_file->Tell(); - - // Write out the header, file name, and file data. - if (zip_file->Write(&local, sizeof(local)) != sizeof(local) || - zip_file->Write(filename, strlen(filename)) != strlen(filename) || - zip_file->Write(content.mBuffer, content.mCompressedSize) != content.mCompressedSize) - { - return -1; - } - return position; -} - - -//========================================================================== -// -// write_central_dir -// -// Writes the central directory entry for a file. -// -//========================================================================== - -int AppendCentralDirectory(FileWriter *zip_file, const char *filename, FCompressedBuffer &content, std::pair &dostime, int position) -{ - FZipCentralDirectoryInfo dir; - - dir.Magic = ZIP_CENTRALFILE; - dir.VersionMadeBy[0] = 20; - dir.VersionMadeBy[1] = 0; - dir.VersionToExtract[0] = 20; - dir.VersionToExtract[1] = 0; - dir.Flags = content.mMethod == METHOD_DEFLATE ? LittleShort((uint16_t)2) : LittleShort((uint16_t)content.mZipFlags); - dir.Method = LittleShort((uint16_t)content.mMethod); - dir.ModTime = LittleShort(dostime.first); - dir.ModDate = LittleShort(dostime.second); - dir.CRC32 = content.mCRC32; - dir.CompressedSize = LittleLong(content.mCompressedSize); - dir.UncompressedSize = LittleLong(content.mSize); - dir.NameLength = LittleShort((unsigned short)strlen(filename)); - dir.ExtraLength = 0; - dir.CommentLength = 0; - dir.StartingDiskNumber = 0; - dir.InternalAttributes = 0; - dir.ExternalAttributes = 0; - dir.LocalHeaderOffset = LittleLong(position); - - if (zip_file->Write(&dir, sizeof(dir)) != sizeof(dir) || - zip_file->Write(filename, strlen(filename)) != strlen(filename)) - { - return -1; - } - return 0; -} - -bool WriteZip(const char *filename, TArray &filenames, TArray &content) -{ - // try to determine local time - struct tm *ltime; - time_t ttime; - ttime = time(nullptr); - ltime = localtime(&ttime); - auto dostime = time_to_dos(ltime); - - TArray positions; - - if (filenames.Size() != content.Size()) return false; - - auto f = FileWriter::Open(filename); - if (f != nullptr) - { - for (unsigned i = 0; i < filenames.Size(); i++) - { - int pos = AppendToZip(f, filenames[i], content[i], dostime); - if (pos == -1) - { - delete f; - remove(filename); - return false; - } - positions.Push(pos); - } - - int dirofs = (int)f->Tell(); - for (unsigned i = 0; i < filenames.Size(); i++) - { - if (AppendCentralDirectory(f, filenames[i], content[i], dostime, positions[i]) < 0) - { - delete f; - remove(filename); - return false; - } - } - - // Write the directory terminator. - FZipEndOfCentralDirectory dirend; - dirend.Magic = ZIP_ENDOFDIR; - dirend.DiskNumber = 0; - dirend.FirstDisk = 0; - dirend.NumEntriesOnAllDisks = dirend.NumEntries = LittleShort((uint16_t)filenames.Size()); - dirend.DirectoryOffset = LittleLong(dirofs); - dirend.DirectorySize = LittleLong((uint32_t)(f->Tell() - dirofs)); - dirend.ZipCommentLength = 0; - if (f->Write(&dirend, sizeof(dirend)) != sizeof(dirend)) - { - delete f; - remove(filename); - return false; - } - delete f; - return true; - } - return false; -} diff --git a/src/gamedata/resourcefiles/file_zip.h b/src/gamedata/resourcefiles/file_zip.h deleted file mode 100644 index 466292e40c8..00000000000 --- a/src/gamedata/resourcefiles/file_zip.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __FILE_ZIP_H -#define __FILE_ZIP_H - -#include "resourcefile.h" - -enum -{ - LUMPFZIP_NEEDFILESTART = 128 -}; - -//========================================================================== -// -// Zip Lump -// -//========================================================================== - -struct FZipLump : public FResourceLump -{ - uint16_t GPFlags; - uint8_t Method; - int CompressedSize; - int Position; - unsigned CRC32; - - virtual FileReader *GetReader(); - virtual int FillCache(); - -private: - void SetLumpAddress(); - virtual int GetFileOffset(); - FCompressedBuffer GetRawData(); -}; - - -//========================================================================== -// -// Zip file -// -//========================================================================== - -class FZipFile : public FResourceFile -{ - FZipLump *Lumps; - -public: - FZipFile(const char * filename, FileReader &file); - virtual ~FZipFile(); - bool Open(bool quiet); - virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } -}; - - -#endif \ No newline at end of file diff --git a/src/gamedata/resourcefiles/resourcefile.cpp b/src/gamedata/resourcefiles/resourcefile.cpp deleted file mode 100644 index db56d4e5537..00000000000 --- a/src/gamedata/resourcefiles/resourcefile.cpp +++ /dev/null @@ -1,784 +0,0 @@ -/* -** resourcefile.cpp -** -** Base classes for resource file management -** -**--------------------------------------------------------------------------- -** Copyright 2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include -#include "resourcefile.h" -#include "cmdlib.h" -#include "w_wad.h" -#include "gi.h" -#include "doomstat.h" -#include "doomtype.h" -#include "md5.h" - - -//========================================================================== -// -// File reader that reads from a lump's cache -// -//========================================================================== - -class FLumpReader : public MemoryReader -{ - FResourceLump *source; - -public: - FLumpReader(FResourceLump *src) - : MemoryReader(NULL, src->LumpSize), source(src) - { - src->CacheLump(); - bufptr = src->Cache; - } - - ~FLumpReader() - { - source->ReleaseCache(); - } -}; - - -//========================================================================== -// -// Base class for resource lumps -// -//========================================================================== - -FResourceLump::~FResourceLump() -{ - if (Cache != NULL && RefCount >= 0) - { - delete [] Cache; - Cache = NULL; - } - Owner = NULL; -} - - -//========================================================================== -// -// Sets up the lump name information for anything not coming from a WAD file. -// -//========================================================================== - -void FResourceLump::LumpNameSetup(FString iname) -{ - long slash = iname.LastIndexOf('/'); - FString base = (slash >= 0) ? iname.Mid(slash + 1) : iname; - auto dot = base.LastIndexOf('.'); - if (dot >= 0) base.Truncate(dot); - uppercopy(Name, base); - Name[8] = 0; - FullName = iname; - - // Map some directories to WAD namespaces. - // Note that some of these namespaces don't exist in WADS. - // CheckNumForName will handle any request for these namespaces accordingly. - Namespace = !strncmp(iname, "flats/", 6) ? ns_flats : - !strncmp(iname, "textures/", 9) ? ns_newtextures : - !strncmp(iname, "hires/", 6) ? ns_hires : - !strncmp(iname, "sprites/", 8) ? ns_sprites : - !strncmp(iname, "voxels/", 7) ? ns_voxels : - !strncmp(iname, "colormaps/", 10) ? ns_colormaps : - !strncmp(iname, "acs/", 4) ? ns_acslibrary : - !strncmp(iname, "voices/", 7) ? ns_strifevoices : - !strncmp(iname, "patches/", 8) ? ns_patches : - !strncmp(iname, "graphics/", 9) ? ns_graphics : - !strncmp(iname, "sounds/", 7) ? ns_sounds : - !strncmp(iname, "music/", 6) ? ns_music : - !strchr(iname, '/') ? ns_global : - ns_hidden; - - // Anything that is not in one of these subdirectories or the main directory - // should not be accessible through the standard WAD functions but only through - // the ones which look for the full name. - if (Namespace == ns_hidden) - { - memset(Name, 0, 8); - } - - // Since '\' can't be used as a file name's part inside a ZIP - // we have to work around this for sprites because it is a valid - // frame character. - else if (Namespace == ns_sprites || Namespace == ns_voxels || Namespace == ns_hires) - { - char *c; - - while ((c = (char*)memchr(Name, '^', 8))) - { - *c = '\\'; - } - } -} - -//========================================================================== -// -// Checks for embedded resource files -// -//========================================================================== - -static bool IsWadInFolder(const FResourceFile* const archive, const char* const resPath) -{ - // Checks a special case when was put in - // directory inside - - if (NULL == archive) - { - return false; - } - - const FString dirName = ExtractFileBase(archive->FileName); - const FString fileName = ExtractFileBase(resPath, true); - const FString filePath = dirName + '/' + fileName; - - return 0 == filePath.CompareNoCase(resPath); -} - -void FResourceLump::CheckEmbedded() -{ - // Checks for embedded archives - const char *c = strstr(FullName, ".wad"); - if (c && strlen(c) == 4 && (!strchr(FullName, '/') || IsWadInFolder(Owner, FullName))) - { - // Mark all embedded WADs - Flags |= LUMPF_EMBEDDED; - memset(Name, 0, 8); - } - /* later - else - { - if (c==NULL) c = strstr(Name, ".zip"); - if (c==NULL) c = strstr(Name, ".pk3"); - if (c==NULL) c = strstr(Name, ".7z"); - if (c==NULL) c = strstr(Name, ".pak"); - if (c && strlen(c) <= 4) - { - // Mark all embedded archives in any directory - Flags |= LUMPF_EMBEDDED; - memset(Name, 0, 8); - } - } - */ - -} - - -//========================================================================== -// -// this is just for completeness. For non-Zips only an uncompressed lump can -// be returned. -// -//========================================================================== - -FCompressedBuffer FResourceLump::GetRawData() -{ - FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)LumpSize, METHOD_STORED, 0, 0, new char[LumpSize] }; - memcpy(cbuf.mBuffer, CacheLump(), LumpSize); - cbuf.mCRC32 = crc32(0, (uint8_t*)cbuf.mBuffer, LumpSize); - ReleaseCache(); - return cbuf; -} - - -//========================================================================== -// -// Returns the owner's FileReader if it can be used to access this lump -// -//========================================================================== - -FileReader *FResourceLump::GetReader() -{ - return NULL; -} - -//========================================================================== -// -// Returns a file reader to the lump's cache -// -//========================================================================== - -FileReader FResourceLump::NewReader() -{ - return FileReader(new FLumpReader(this)); -} - -//========================================================================== -// -// Caches a lump's content and increases the reference counter -// -//========================================================================== - -void *FResourceLump::CacheLump() -{ - if (Cache != NULL) - { - if (RefCount > 0) RefCount++; - } - else if (LumpSize > 0) - { - FillCache(); - } - return Cache; -} - -//========================================================================== -// -// Decrements reference counter and frees lump if counter reaches 0 -// -//========================================================================== - -int FResourceLump::ReleaseCache() -{ - if (LumpSize > 0 && RefCount > 0) - { - if (--RefCount == 0) - { - delete [] Cache; - Cache = NULL; - } - } - return RefCount; -} - -//========================================================================== -// -// Opens a resource file -// -//========================================================================== - -typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, bool quiet); - -FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet); -FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckLump(const char *filename,FileReader &file, bool quiet); -FResourceFile *CheckDir(const char *filename, bool quiet); - -static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckLump }; - -FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly) -{ - for(size_t i = 0; i < countof(funcs) - containeronly; i++) - { - FResourceFile *resfile = funcs[i](filename, file, quiet); - if (resfile != NULL) return resfile; - } - return NULL; -} - -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly) -{ - return DoOpenResourceFile(filename, file, quiet, containeronly); -} - - -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool quiet, bool containeronly) -{ - FileReader file; - if (!file.OpenFile(filename)) return nullptr; - return DoOpenResourceFile(filename, file, quiet, containeronly); -} - -FResourceFile *FResourceFile::OpenResourceFileFromLump(int lumpnum, bool quiet, bool containeronly) -{ - FileReader file = Wads.ReopenLumpReader(lumpnum); - return DoOpenResourceFile("internal", file, quiet, containeronly); -} - - -FResourceFile *FResourceFile::OpenDirectory(const char *filename, bool quiet) -{ - return CheckDir(filename, quiet); -} - -//========================================================================== -// -// Resource file base class -// -//========================================================================== - -FResourceFile::FResourceFile(const char *filename) - : FileName(filename) -{ -} - -FResourceFile::FResourceFile(const char *filename, FileReader &r) - : FResourceFile(filename) -{ - Reader = std::move(r); -} - -FResourceFile::~FResourceFile() -{ -} - -int lumpcmp(const void * a, const void * b) -{ - FResourceLump * rec1 = (FResourceLump *)a; - FResourceLump * rec2 = (FResourceLump *)b; - - return rec1->FullName.CompareNoCase(rec2->FullName); -} - -//========================================================================== -// -// FResourceFile :: GenerateHash -// -// Generates a hash identifier for use in file identification. -// Potential uses are mod-wide compatibility settings or localization add-ons. -// This only hashes the lump directory but not the actual content -// -//========================================================================== - -void FResourceFile::GenerateHash() -{ - // hash the lump directory after sorting - - Hash.Format(("%08X-%04X-"), (unsigned)Reader.GetLength(), NumLumps); - - MD5Context md5; - - uint8_t digest[16]; - for(uint32_t i = 0; i < NumLumps; i++) - { - auto lump = GetLump(i); - md5.Update((const uint8_t*)lump->Name, (unsigned)strlen(lump->Name) + 1); // +1 to hash the terminating 0 as well. - md5.Update((const uint8_t*)lump->FullName.GetChars(), (unsigned)lump->FullName.Len() + 1); - md5.Update((const uint8_t*)&lump->LumpSize, 4); - } - md5.Final(digest); - for (auto c : digest) - { - Hash.AppendFormat("%02X", c); - } -} - -//========================================================================== -// -// FResourceFile :: PostProcessArchive -// -// Sorts files by name. -// For files named "filter//*": Using the same filter rules as config -// autoloading, move them to the end and rename them without the "filter/" -// prefix. Filtered files that don't match are deleted. -// -//========================================================================== - -void FResourceFile::PostProcessArchive(void *lumps, size_t lumpsize) -{ - // Entries in archives are sorted alphabetically - qsort(lumps, NumLumps, lumpsize, lumpcmp); - - - // Filter out lumps using the same names as the Autoload.* sections - // in the ini file use. We reduce the maximum lump concidered after - // each one so that we don't risk refiltering already filtered lumps. - uint32_t max = NumLumps; - max -= FilterLumpsByGameType(gameinfo.gametype, lumps, lumpsize, max); - - long len; - int lastpos = -1; - FString file; - if (LumpFilterIWAD.IndexOf('.') < 0) - { - max -= FilterLumps(LumpFilterIWAD, lumps, lumpsize, max); - } - else while ((len = LumpFilterIWAD.IndexOf('.', lastpos+1)) > 0) - { - max -= FilterLumps(LumpFilterIWAD.Left(len), lumps, lumpsize, max); - lastpos = len; - } - JunkLeftoverFilters(lumps, lumpsize, max); -} - -//========================================================================== -// -// FResourceFile :: FilterLumps -// -// Finds any lumps between [0,) that match the pattern -// "filter//*" and moves them to the end of the lump list. -// Returns the number of lumps moved. -// -//========================================================================== - -int FResourceFile::FilterLumps(FString filtername, void *lumps, size_t lumpsize, uint32_t max) -{ - FString filter; - uint32_t start, end; - - if (filtername.IsEmpty()) - { - return 0; - } - filter << "filter/" << filtername << '/'; - - bool found = FindPrefixRange(filter, lumps, lumpsize, max, start, end); - - // Workaround for old Doom filter names. - if (!found && filtername.IndexOf("doom.id.doom") == 0) - { - filter.Substitute("doom.id.doom", "doom.doom"); - found = FindPrefixRange(filter, lumps, lumpsize, max, start, end); - } - - if (found) - { - void *from = (uint8_t *)lumps + start * lumpsize; - - // Remove filter prefix from every name - void *lump_p = from; - for (uint32_t i = start; i < end; ++i, lump_p = (uint8_t *)lump_p + lumpsize) - { - FResourceLump *lump = (FResourceLump *)lump_p; - assert(lump->FullName.CompareNoCase(filter, (int)filter.Len()) == 0); - lump->LumpNameSetup(lump->FullName.Mid(filter.Len())); - } - - // Move filtered lumps to the end of the lump list. - size_t count = (end - start) * lumpsize; - void *to = (uint8_t *)lumps + NumLumps * lumpsize - count; - assert (to >= from); - - if (from != to) - { - // Copy filtered lumps to a temporary buffer. - uint8_t *filteredlumps = new uint8_t[count]; - memcpy(filteredlumps, from, count); - - // Shift lumps left to make room for the filtered ones at the end. - memmove(from, (uint8_t *)from + count, (NumLumps - end) * lumpsize); - - // Copy temporary buffer to newly freed space. - memcpy(to, filteredlumps, count); - - delete[] filteredlumps; - } - } - return end - start; -} - -//========================================================================== -// -// FResourceFile :: FilterLumpsByGameType -// -// Matches any lumps that match "filter/game-/*". Includes -// inclusive gametypes like Raven. -// -//========================================================================== - -int FResourceFile::FilterLumpsByGameType(int type, void *lumps, size_t lumpsize, uint32_t max) -{ - static const struct { int match; const char *name; } blanket[] = - { - { GAME_Raven, "game-Raven" }, - { GAME_DoomStrifeChex, "game-DoomStrifeChex" }, - { GAME_DoomChex, "game-DoomChex" }, - { GAME_Any, NULL } - }; - if (type == 0) - { - return 0; - } - int count = 0; - for (int i = 0; blanket[i].name != NULL; ++i) - { - if (type & blanket[i].match) - { - count += FilterLumps(blanket[i].name, lumps, lumpsize, max); - } - } - FString filter = "game-"; - filter += GameNames[type]; - return count + FilterLumps(filter, lumps, lumpsize, max); -} - -//========================================================================== -// -// FResourceFile :: JunkLeftoverFilters -// -// Deletes any lumps beginning with "filter/" that were not matched. -// -//========================================================================== - -void FResourceFile::JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t max) -{ - uint32_t start, end; - if (FindPrefixRange("filter/", lumps, lumpsize, max, start, end)) - { - // Since the resource lumps may contain non-POD data besides the - // full name, we "delete" them by erasing their names so they - // can't be found. - void *stop = (uint8_t *)lumps + end * lumpsize; - for (void *p = (uint8_t *)lumps + start * lumpsize; p < stop; p = (uint8_t *)p + lumpsize) - { - FResourceLump *lump = (FResourceLump *)p; - lump->FullName = ""; - lump->Name[0] = '\0'; - lump->Namespace = ns_hidden; - } - } -} - -//========================================================================== -// -// FResourceFile :: FindPrefixRange -// -// Finds a range of lumps that start with the prefix string. is left -// indicating the first matching one. is left at one plus the last -// matching one. -// -//========================================================================== - -bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize, uint32_t maxlump, uint32_t &start, uint32_t &end) -{ - uint32_t min, max, mid, inside; - FResourceLump *lump; - int cmp; - - end = start = 0; - - // Pretend that our range starts at 1 instead of 0 so that we can avoid - // unsigned overflow if the range starts at the first lump. - lumps = (uint8_t *)lumps - lumpsize; - - // Binary search to find any match at all. - min = 1, max = maxlump; - while (min <= max) - { - mid = min + (max - min) / 2; - lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); - if (cmp == 0) - break; - else if (cmp < 0) - min = mid + 1; - else - max = mid - 1; - } - if (max < min) - { // matched nothing - return false; - } - - // Binary search to find first match. - inside = mid; - min = 1, max = mid; - while (min <= max) - { - mid = min + (max - min) / 2; - lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); - // Go left on matches and right on misses. - if (cmp == 0) - max = mid - 1; - else - min = mid + 1; - } - start = mid + (cmp != 0) - 1; - - // Binary search to find last match. - min = inside, max = maxlump; - while (min <= max) - { - mid = min + (max - min) / 2; - lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); - // Go right on matches and left on misses. - if (cmp == 0) - min = mid + 1; - else - max = mid - 1; - } - end = mid - (cmp != 0); - return true; -} - -//========================================================================== -// -// Needs to be virtual in the base class. Implemented only for WADs -// -//========================================================================== - -void FResourceFile::FindStrifeTeaserVoices () -{ -} - -//========================================================================== -// -// Finds a lump by a given name. Used for savegames -// -//========================================================================== - -FResourceLump *FResourceFile::FindLump(const char *name) -{ - for (unsigned i = 0; i < NumLumps; i++) - { - FResourceLump *lump = GetLump(i); - if (!stricmp(name, lump->FullName)) - { - return lump; - } - } - return nullptr; -} - -//========================================================================== -// -// Caches a lump's content and increases the reference counter -// -//========================================================================== - -FileReader *FUncompressedLump::GetReader() -{ - Owner->Reader.Seek(Position, FileReader::SeekSet); - return &Owner->Reader; -} - -//========================================================================== -// -// Caches a lump's content and increases the reference counter -// -//========================================================================== - -int FUncompressedLump::FillCache() -{ - const char * buffer = Owner->Reader.GetBuffer(); - - if (buffer != NULL) - { - // This is an in-memory file so the cache can point directly to the file's data. - Cache = const_cast(buffer) + Position; - RefCount = -1; - return -1; - } - - Owner->Reader.Seek(Position, FileReader::SeekSet); - Cache = new char[LumpSize]; - Owner->Reader.Read(Cache, LumpSize); - RefCount = 1; - return 1; -} - -//========================================================================== -// -// Base class for uncompressed resource files -// -//========================================================================== - -FUncompressedFile::FUncompressedFile(const char *filename) -: FResourceFile(filename) -{} - -FUncompressedFile::FUncompressedFile(const char *filename, FileReader &r) - : FResourceFile(filename, r) -{} - - -//========================================================================== -// -// external lump -// -//========================================================================== - -FExternalLump::FExternalLump(const char *_filename, int filesize) - : Filename(_filename) -{ - if (filesize == -1) - { - FileReader f; - - if (f.OpenFile(_filename)) - { - LumpSize = (int)f.GetLength(); - } - else - { - LumpSize = 0; - } - } - else - { - LumpSize = filesize; - } -} - - -//========================================================================== -// -// Caches a lump's content and increases the reference counter -// For external lumps this reopens the file each time it is accessed -// -//========================================================================== - -int FExternalLump::FillCache() -{ - Cache = new char[LumpSize]; - FileReader f; - - if (f.OpenFile(Filename)) - { - f.Read(Cache, LumpSize); - } - else - { - memset(Cache, 0, LumpSize); - } - RefCount = 1; - return 1; -} - - -bool FMemoryFile::Open(bool quiet) -{ - FString name(ExtractFileBase(FileName)); - FString fname(ExtractFileBase(FileName, true)); - - Lumps.Resize(1); - uppercopy(Lumps[0].Name, name); - Lumps[0].Name[8] = 0; - Lumps[0].FullName = fname; - Lumps[0].Owner = this; - Lumps[0].Position = 0; - Lumps[0].LumpSize = (int)Reader.GetLength(); - Lumps[0].Namespace = ns_global; - Lumps[0].Flags = 0; - Lumps[0].FullName = ""; - NumLumps = 1; - return true; -} - - diff --git a/src/gamedata/resourcefiles/resourcefile.h b/src/gamedata/resourcefiles/resourcefile.h deleted file mode 100644 index 5ff10c930de..00000000000 --- a/src/gamedata/resourcefiles/resourcefile.h +++ /dev/null @@ -1,174 +0,0 @@ - - -#ifndef __RESFILE_H -#define __RESFILE_H - -#include "files.h" - -class FResourceFile; -class FTexture; - -// This holds a compresed Zip entry with all needed info to decompress it. -struct FCompressedBuffer -{ - unsigned mSize; - unsigned mCompressedSize; - int mMethod; - int mZipFlags; - unsigned mCRC32; - char *mBuffer; - - bool Decompress(char *destbuffer); - void Clean() - { - mSize = mCompressedSize = 0; - if (mBuffer != nullptr) - { - delete[] mBuffer; - mBuffer = nullptr; - } - } -}; - -struct FResourceLump -{ - friend class FResourceFile; - - int LumpSize; - FString FullName; // only valid for files loaded from a non-wad archive - union - { - char Name[9]; - - uint32_t dwName; // These are for accessing the first 4 or 8 chars of - uint64_t qwName; // Name as a unit without breaking strict aliasing rules - }; - uint8_t Flags; - int8_t RefCount; - char * Cache; - FResourceFile * Owner; - FTexture * LinkedTexture; - int Namespace; - - FResourceLump() - { - Cache = NULL; - Owner = NULL; - Flags = 0; - RefCount = 0; - Namespace = 0; // ns_global - *Name = 0; - LinkedTexture = NULL; - } - - virtual ~FResourceLump(); - virtual FileReader *GetReader(); - virtual FileReader NewReader(); - virtual int GetFileOffset() { return -1; } - virtual int GetIndexNum() const { return 0; } - void LumpNameSetup(FString iname); - void CheckEmbedded(); - virtual FCompressedBuffer GetRawData(); - - void *CacheLump(); - int ReleaseCache(); - -protected: - virtual int FillCache() { return -1; } - -}; - -class FResourceFile -{ -public: - FileReader Reader; - FString FileName; -protected: - uint32_t NumLumps; - FString Hash; - - FResourceFile(const char *filename); - FResourceFile(const char *filename, FileReader &r); - - // for archives that can contain directories - void GenerateHash(); - void PostProcessArchive(void *lumps, size_t lumpsize); - -private: - uint32_t FirstLump; - - int FilterLumps(FString filtername, void *lumps, size_t lumpsize, uint32_t max); - int FilterLumpsByGameType(int gametype, void *lumps, size_t lumpsize, uint32_t max); - bool FindPrefixRange(FString filter, void *lumps, size_t lumpsize, uint32_t max, uint32_t &start, uint32_t &end); - void JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t max); - static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly); - -public: - static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool quiet = false, bool containeronly = false); - static FResourceFile *OpenResourceFile(const char *filename, bool quiet = false, bool containeronly = false); - static FResourceFile *OpenResourceFileFromLump(int lumpnum, bool quiet = false, bool containeronly = false); - static FResourceFile *OpenDirectory(const char *filename, bool quiet = false); - virtual ~FResourceFile(); - // If this FResourceFile represents a directory, the Reader object is not usable so don't return it. - FileReader *GetReader() { return Reader.isOpen()? &Reader : nullptr; } - uint32_t LumpCount() const { return NumLumps; } - uint32_t GetFirstLump() const { return FirstLump; } - void SetFirstLump(uint32_t f) { FirstLump = f; } - const FString &GetHash() const { return Hash; } - - - virtual void FindStrifeTeaserVoices (); - virtual bool Open(bool quiet) = 0; - virtual FResourceLump *GetLump(int no) = 0; - FResourceLump *FindLump(const char *name); -}; - -struct FUncompressedLump : public FResourceLump -{ - int Position; - - virtual FileReader *GetReader(); - virtual int FillCache(); - virtual int GetFileOffset() { return Position; } - -}; - - -// Base class for uncompressed resource files (WAD, GRP, PAK and single lumps) -class FUncompressedFile : public FResourceFile -{ -protected: - TArray Lumps; - - FUncompressedFile(const char *filename); - FUncompressedFile(const char *filename, FileReader &r); - virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } -}; - - -struct FExternalLump : public FResourceLump -{ - FString Filename; - - FExternalLump(const char *_filename, int filesize = -1); - virtual int FillCache(); - -}; - -struct FMemoryFile : public FUncompressedFile -{ - FMemoryFile(const char *_filename, const void *sdata, int length) - : FUncompressedFile(_filename) - { - Reader.OpenMemoryArray(sdata, length); - } - - bool Open(bool quiet); - - -}; - - - - -#endif diff --git a/src/gamedata/statistics.cpp b/src/gamedata/statistics.cpp index 7514bae90f1..95d8165ae06 100644 --- a/src/gamedata/statistics.cpp +++ b/src/gamedata/statistics.cpp @@ -45,8 +45,8 @@ #include "d_net.h" #include "g_game.h" #include "m_png.h" -#include "doomerrors.h" -#include "w_wad.h" +#include "engineerrors.h" +#include "filesystem.h" #include "p_local.h" #include "p_setup.h" #include "s_sound.h" @@ -202,15 +202,7 @@ int compare_episode_names(const void *a, const void *b) FStatistics *A = (FStatistics*)a; FStatistics *B = (FStatistics*)b; - return strnatcasecmp(A->epi_header, B->epi_header); -} - -int compare_level_names(const void *a, const void *b) -{ - FLevelStatistics *A = (FLevelStatistics*)a; - FLevelStatistics *B = (FLevelStatistics*)b; - - return strnatcasecmp(A->name, B->name); + return strnatcasecmp(A->epi_header.GetChars(), B->epi_header.GetChars()); } int compare_dates(const void *a, const void *b) @@ -248,7 +240,11 @@ static void SaveStatistics(const char *fn, TArray &statlist) unsigned int j; FileWriter *fw = FileWriter::Open(fn); - if (fw == nullptr) return; + if (fw == nullptr) + { + Printf(PRINT_HIGH, "Unable to save statistics to %s\n", fn); + return; + } qsort(&statlist[0], statlist.Size(), sizeof(statlist[0]), compare_episode_names); for(unsigned i=0;i &statlist) { fw->Printf("\t{\n"); - qsort(&ls[0], ls.Size(), sizeof(ls[0]), compare_level_names); - for(unsigned k=0;kPrintf("\t\t%-8s \"%-33s\" %02d:%02d:%02d\n", ls[k].name, ls[k].info, @@ -297,7 +291,7 @@ static FStatistics *GetStatisticsList(TArray &statlist, const char { for(unsigned int i=0;iLevelname.GetChars(), B->Levelname.GetChars()); +} + + static void StoreLevelStats(FLevelLocals *Level) { unsigned int i; @@ -423,6 +426,8 @@ static void StoreLevelStats(FLevelLocals *Level) } if (mc == 0) LevelData[i].killcount = LevelData[i].totalkills; } + // sort level names alphabetically to bring the newly added level to its proper place when playing a hub. + qsort(&LevelData[0], LevelData.Size(), sizeof(LevelData[0]), compare_level_names); } //========================================================================== @@ -453,19 +458,19 @@ void STAT_ChangeLevel(const char *newl, FLevelLocals *Level) { // we reached the end of this episode int wad = 0; - MapData * map = P_OpenMapData(StartEpisode->mEpisodeMap, false); + MapData * map = P_OpenMapData(StartEpisode->mEpisodeMap.GetChars(), false); if (map != NULL) { - wad = Wads.GetLumpFile(map->lumpnum); + wad = fileSystem.GetFileContainer(map->lumpnum); delete map; } - const char * name = Wads.GetWadName(wad); + const char * name = fileSystem.GetResourceFileName(wad); FString section = ExtractFileBase(name) + "." + StartEpisode->mEpisodeMap; section.ToUpper(); - const char *ep_name = StartEpisode->mEpisodeName; - if (*ep_name == '$') ep_name = GStrings(ep_name+1); - FStatistics *sl = GetStatisticsList(EpisodeStatistics, section, ep_name); + const char *ep_name = StartEpisode->mEpisodeName.GetChars(); + if (*ep_name == '$') ep_name = GStrings.GetString(ep_name+1); + FStatistics *sl = GetStatisticsList(EpisodeStatistics, section.GetChars(), ep_name); int statvals[6] = {0,0,0,0,0,0}; FString infostring; @@ -481,7 +486,7 @@ void STAT_ChangeLevel(const char *newl, FLevelLocals *Level) } infostring.Format("%4d/%4d, %4d/%4d, %3d/%3d, %2d", statvals[0], statvals[1], statvals[2], statvals[3], statvals[4], statvals[5], validlevels); - FSessionStatistics *es = StatisticsEntry(sl, infostring, Level->totaltime); + FSessionStatistics *es = StatisticsEntry(sl, infostring.GetChars(), Level->totaltime); for(unsigned i = 0; i < LevelData.Size(); i++) { @@ -490,7 +495,7 @@ void STAT_ChangeLevel(const char *newl, FLevelLocals *Level) infostring.Format("%4d/%4d, %4d/%4d, %3d/%3d", LevelData[i].killcount, LevelData[i].totalkills, LevelData[i].itemcount, LevelData[i].totalitems, LevelData[i].secretcount, LevelData[i].totalsecrets); - LevelStatEntry(es, lsection, infostring, LevelData[i].leveltime); + LevelStatEntry(es, lsection.GetChars(), infostring.GetChars(), LevelData[i].leveltime); } SaveStatistics(statfile, EpisodeStatistics); } @@ -556,6 +561,12 @@ void STAT_Serialize(FSerializer &arc) } +FString STAT_EpisodeName() +{ + if (StartEpisode == nullptr) return ""; + return StartEpisode->mEpisodeName; +} + //========================================================================== // // show statistics @@ -584,14 +595,14 @@ CCMD(printstats) CCMD(finishgame) { - bool gamestatecheck = gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_FINALE; + bool gamestatecheck = gamestate == GS_LEVEL || gamestate == GS_CUTSCENE; if (!gamestatecheck) { Printf("Cannot use 'finishgame' while not in a game!\n"); return; } // This CCMD simulates an end-of-game action and exists to end mods that never exit their last Level-> - Net_WriteByte(DEM_FINISHGAME); + Net_WriteInt8(DEM_FINISHGAME); } ADD_STAT(statistics) diff --git a/src/gamedata/stringtable.h b/src/gamedata/stringtable.h deleted file mode 100644 index 37dac5553e3..00000000000 --- a/src/gamedata/stringtable.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -** stringtable.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -** FStringTable -** -** This class manages a list of localizable strings stored in a wad file. -*/ - -#ifndef __STRINGTABLE_H__ -#define __STRINGTABLE_H__ - -#ifdef _MSC_VER -#pragma once -#endif - - -#include -#include "doomdef.h" -#include "doomtype.h" - -struct TableElement -{ - int filenum; - FString strings[4]; -}; - -// This public interface is for Dehacked -class StringMap : public TMap -{ -public: - const char *MatchString(const char *string) const; -}; - - -struct StringMacro -{ - FString Replacements[4]; -}; - - -class FStringTable -{ -public: - enum : uint32_t - { - default_table = MAKE_ID('*', '*', 0, 0), - global_table = MAKE_ID('*', 0, 0, 0), - dehacked_table = MAKE_ID('*', '*', '*', 0) - }; - - using LangMap = TMap; - using StringMacroMap = TMap; - - void LoadStrings (); - void UpdateLanguage(); - StringMap GetDefaultStrings() { return allStrings[default_table]; } // Dehacked needs these for comparison - void SetDehackedStrings(StringMap && map) - { - allStrings.Insert(dehacked_table, map); - UpdateLanguage(); - } - - const char *GetLanguageString(const char *name, uint32_t langtable, int gender = -1) const; - bool MatchDefaultString(const char *name, const char *content) const; - const char *GetString(const char *name, uint32_t *langtable, int gender = -1) const; - const char *operator() (const char *name) const; // Never returns NULL - const char *operator[] (const char *name) const - { - return GetString(name, nullptr); - } - bool exists(const char *name); - -private: - - StringMacroMap allMacros; - LangMap allStrings; - TArray> currentLanguageSet; - - void LoadLanguage (int lumpnum, const TArray &buffer); - TArray> parseCSV(const TArray &buffer); - bool ParseLanguageCSV(int lumpnum, const TArray &buffer); - - bool LoadLanguageFromSpreadsheet(int lumpnum, const TArray &buffer); - bool readMacros(int lumpnum); - void InsertString(int lumpnum, int langid, FName label, const FString &string); - void DeleteString(int langid, FName label); - void DeleteForLabel(int lumpnum, FName label); - - static size_t ProcessEscapes (char *str); -}; - -#endif //__STRINGTABLE_H__ diff --git a/src/gamedata/teaminfo.cpp b/src/gamedata/teaminfo.cpp index 5a70429e0d2..44e8c0e374c 100644 --- a/src/gamedata/teaminfo.cpp +++ b/src/gamedata/teaminfo.cpp @@ -38,10 +38,12 @@ #include "gi.h" #include "teaminfo.h" +#include "texturemanager.h" #include "v_font.h" #include "v_video.h" -#include "w_wad.h" +#include "filesystem.h" #include "vm.h" +#include "d_player.h" // MACROS ------------------------------------------------------------------ @@ -55,9 +57,11 @@ // EXTERNAL DATA DECLARATIONS ---------------------------------------------- +extern bool playeringame[MAXPLAYERS]; +extern player_t players[MAXPLAYERS]; + // PUBLIC DATA DEFINITIONS ------------------------------------------------- -FTeam TeamLibrary; TArray Teams; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -133,7 +137,7 @@ void FTeam::ParseTeamInfo () int iLump, iLastLump = 0; Teams.Clear(); - while ((iLump = Wads.FindLump ("TEAMINFO", &iLastLump)) != -1) + while ((iLump = fileSystem.FindLump ("TEAMINFO", &iLastLump)) != -1) { FScanner Scan (iLump); @@ -183,7 +187,7 @@ void FTeam::ParseTeamDefinition (FScanner &Scan) case TEAMINFO_PlayerColor: Scan.MustGetString (); - Team.m_iPlayerColor = V_GetColor (NULL, Scan); + Team.m_iPlayerColor = V_GetColor (Scan); break; case TEAMINFO_TextColor: @@ -244,7 +248,7 @@ void FTeam::ClearTeams () // //========================================================================== -bool FTeam::IsValidTeam (unsigned int uiTeam) +bool FTeam::IsValid (unsigned int uiTeam) { if (uiTeam >= Teams.Size ()) return false; @@ -252,6 +256,16 @@ bool FTeam::IsValidTeam (unsigned int uiTeam) return true; } +bool FTeam::ChangeTeam(unsigned int pNum, unsigned int newTeam) +{ + if (!multiplayer || !teamplay || pNum >= MAXPLAYERS || !playeringame[pNum] || !FTeam::IsValid(newTeam) || players[pNum].userinfo.GetTeam() == newTeam) + return false; + + players[pNum].userinfo.TeamChanged(newTeam); + R_BuildPlayerTranslation(pNum); + return true; +} + //========================================================================== // // FTeam :: GetName @@ -260,7 +274,7 @@ bool FTeam::IsValidTeam (unsigned int uiTeam) const char *FTeam::GetName () const { - return m_Name; + return m_Name.GetChars(); } //========================================================================== @@ -303,7 +317,7 @@ int FTeam::GetTextColor () const // //========================================================================== -FString FTeam::GetLogo () const +const FString& FTeam::GetLogo () const { return m_Logo; } @@ -338,3 +352,89 @@ CCMD (teamlist) DEFINE_GLOBAL(Teams) DEFINE_FIELD_NAMED(FTeam, m_Name, mName) + +static int IsValid(unsigned int id) +{ + return FTeam::IsValid(id); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FTeam, IsValid, IsValid) +{ + PARAM_PROLOGUE; + PARAM_UINT(id); + + ACTION_RETURN_BOOL(FTeam::IsValid(id)); +} + +static int ChangeTeam(unsigned int pNum, unsigned int newTeam) +{ + return FTeam::ChangeTeam(pNum, newTeam); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FTeam, ChangeTeam, ChangeTeam) +{ + PARAM_PROLOGUE; + PARAM_UINT(pNum); + PARAM_UINT(newTeam); + + ACTION_RETURN_BOOL(FTeam::ChangeTeam(pNum, newTeam)); +} + +static int GetPlayerColor(FTeam* self) +{ + return self->GetPlayerColor(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FTeam, GetPlayerColor, GetPlayerColor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FTeam); + ACTION_RETURN_INT(self->GetPlayerColor()); +} + +static int GetTextColor(FTeam* self) +{ + return self->GetTextColor(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FTeam, GetTextColor, GetTextColor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FTeam); + ACTION_RETURN_INT(self->GetTextColor()); +} + +static int GetLogo(FTeam* self) +{ + const FString& name = self->GetLogo(); + if (name.IsEmpty()) + return -1; + + return TexMan.CheckForTexture(name.GetChars(), ETextureType::Any).GetIndex(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FTeam, GetLogo, GetLogo) +{ + PARAM_SELF_STRUCT_PROLOGUE(FTeam); + ACTION_RETURN_INT(GetLogo(self)); +} + +static void GetLogoName(FTeam* self, FString* res) +{ + *res = self->GetLogo(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FTeam, GetLogoName, GetLogoName) +{ + PARAM_SELF_STRUCT_PROLOGUE(FTeam); + ACTION_RETURN_STRING(self->GetLogo()); +} + +static int AllowsCustomPlayerColor(FTeam* self) +{ + return self->GetAllowCustomPlayerColor(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FTeam, AllowsCustomPlayerColor, AllowsCustomPlayerColor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FTeam); + ACTION_RETURN_BOOL(self->GetAllowCustomPlayerColor()); +} diff --git a/src/gamedata/teaminfo.h b/src/gamedata/teaminfo.h index 1c84d9b9b83..17be9dd4639 100644 --- a/src/gamedata/teaminfo.h +++ b/src/gamedata/teaminfo.h @@ -45,13 +45,14 @@ class FTeam { public: FTeam (); - void ParseTeamInfo (); - bool IsValidTeam (unsigned int uiTeam); + static void ParseTeamInfo (); + static bool IsValid (unsigned int uiTeam); + static bool ChangeTeam(unsigned int pNum, unsigned int newTeam); const char *GetName () const; int GetPlayerColor () const; int GetTextColor () const; - FString GetLogo () const; + const FString& GetLogo () const; bool GetAllowCustomPlayerColor () const; int m_iPlayerCount; @@ -60,8 +61,8 @@ class FTeam int m_iTies; private: - void ParseTeamDefinition (FScanner &Scan); - void ClearTeams (); + static void ParseTeamDefinition (FScanner &Scan); + static void ClearTeams (); public: // needed for script access. FString m_Name; @@ -72,7 +73,6 @@ class FTeam bool m_bAllowCustomPlayerColor; }; -extern FTeam TeamLibrary; extern TArray Teams; #endif diff --git a/src/gamedata/textures/anim_switches.cpp b/src/gamedata/textures/anim_switches.cpp index 24ac8aad810..ce7166ba951 100644 --- a/src/gamedata/textures/anim_switches.cpp +++ b/src/gamedata/textures/anim_switches.cpp @@ -32,14 +32,16 @@ ** */ -#include "templates.h" -#include "textures/textures.h" + +#include "textures.h" #include "s_sound.h" #include "r_state.h" -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" #include "sc_man.h" #include "gi.h" +#include "animations.h" +#include "texturemanager.h" static int SortSwitchDefs (const void *a, const void *b) @@ -57,15 +59,15 @@ static int SortSwitchDefs (const void *a, const void *b) // //========================================================================== -void FTextureManager::InitSwitchList () +void FTextureAnimator::InitSwitchList () { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; - int lump = Wads.CheckNumForName ("SWITCHES"); + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; + int lump = fileSystem.CheckNumForName ("SWITCHES"); if (lump != -1) { - FMemLump lumpdata = Wads.ReadLump (lump); - const char *alphSwitchList = (const char *)lumpdata.GetMem(); + auto lumpdata = fileSystem.ReadFile (lump); + auto alphSwitchList = lumpdata.string(); const char *list_p; FSwitchDef *def1, *def2; @@ -78,17 +80,18 @@ void FTextureManager::InitSwitchList () continue; } // [RH] Skip this switch if its textures can't be found. - if (CheckForTexture (list_p /* .name1 */, ETextureType::Wall, texflags).Exists() && - CheckForTexture (list_p + 9 /* .name2 */, ETextureType::Wall, texflags).Exists()) + if (TexMan.CheckForTexture (list_p /* .name1 */, ETextureType::Wall, texflags).Exists() && + TexMan.CheckForTexture (list_p + 9 /* .name2 */, ETextureType::Wall, texflags).Exists()) { def1 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); - def1->PreTexture = def2->frames[0].Texture = CheckForTexture (list_p /* .name1 */, ETextureType::Wall, texflags); - def2->PreTexture = def1->frames[0].Texture = CheckForTexture (list_p + 9, ETextureType::Wall, texflags); - def1->Sound = def2->Sound = 0; + def1->PreTexture = def2->frames[0].Texture = TexMan.CheckForTexture (list_p /* .name1 */, ETextureType::Wall, texflags); + def2->PreTexture = def1->frames[0].Texture = TexMan.CheckForTexture (list_p + 9, ETextureType::Wall, texflags); + def1->Sound = def2->Sound = NO_SOUND; def1->NumFrames = def2->NumFrames = 1; def1->frames[0].TimeMin = def2->frames[0].TimeMin = 0; def1->frames[0].TimeRnd = def2->frames[0].TimeRnd = 0; + def1->QuestPanel = def2->QuestPanel = false; AddSwitchPair(def1, def2); } } @@ -104,16 +107,16 @@ void FTextureManager::InitSwitchList () // //========================================================================== -void FTextureManager::ProcessSwitchDef (FScanner &sc) +void FTextureAnimator::ProcessSwitchDef (FScanner &sc) { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; FString picname; FSwitchDef *def1, *def2; FTextureID picnum; int gametype; bool quest = false; - def1 = def2 = NULL; + def1 = def2 = nullptr; sc.MustGetString (); if (sc.Compare ("doom")) { @@ -145,7 +148,7 @@ void FTextureManager::ProcessSwitchDef (FScanner &sc) } sc.MustGetString (); - picnum = CheckForTexture (sc.String, ETextureType::Wall, texflags); + picnum = TexMan.CheckForTexture (sc.String, ETextureType::Wall, texflags); picname = sc.String; while (sc.GetString ()) { @@ -155,7 +158,7 @@ void FTextureManager::ProcessSwitchDef (FScanner &sc) } else if (sc.Compare ("on")) { - if (def1 != NULL) + if (def1 != nullptr) { sc.ScriptError ("Switch already has an on state"); } @@ -163,7 +166,7 @@ void FTextureManager::ProcessSwitchDef (FScanner &sc) } else if (sc.Compare ("off")) { - if (def2 != NULL) + if (def2 != nullptr) { sc.ScriptError ("Switch already has an off state"); } @@ -176,14 +179,14 @@ void FTextureManager::ProcessSwitchDef (FScanner &sc) } } - if (def1 == NULL || !picnum.Exists() || + if (def1 == nullptr || !picnum.Exists() || (gametype != GAME_Any && !(gametype & gameinfo.gametype))) { - if (def2 != NULL) + if (def2 != nullptr) { M_Free (def2); } - if (def1 != NULL) + if (def1 != nullptr) { M_Free (def1); } @@ -192,7 +195,7 @@ void FTextureManager::ProcessSwitchDef (FScanner &sc) // If the switch did not have an off state, create one that just returns // it to the original texture without doing anything interesting - if (def2 == NULL) + if (def2 == nullptr) { def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); def2->Sound = def1->Sound; @@ -218,15 +221,15 @@ void FTextureManager::ProcessSwitchDef (FScanner &sc) // //========================================================================== -FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad) +FSwitchDef *FTextureAnimator::ParseSwitchDef (FScanner &sc, bool ignoreBad) { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; FSwitchDef *def; TArray frames; FSwitchDef::frame thisframe; FTextureID picnum; bool bad; - FSoundID sound = 0; + FSoundID sound = NO_SOUND; bad = false; @@ -234,17 +237,17 @@ FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad) { if (sc.Compare ("sound")) { - if (sound != 0) + if (sound != NO_SOUND) { sc.ScriptError ("Switch state already has a sound"); } sc.MustGetString (); - sound = sc.String; + sound = S_FindSound(sc.String); } else if (sc.Compare ("pic")) { sc.MustGetString (); - picnum = CheckForTexture (sc.String, ETextureType::Wall, texflags); + picnum = TexMan.CheckForTexture (sc.String, ETextureType::Wall, texflags); if (!picnum.Exists() && !ignoreBad) { //Printf ("Unknown switch texture %s\n", sc.String); @@ -268,7 +271,7 @@ FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad) max = sc.Number & 65535; if (min > max) { - swapvalues (min, max); + std::swap (min, max); } thisframe.TimeMin = min; thisframe.TimeRnd = (max - min + 1); @@ -293,14 +296,14 @@ FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad) } if (bad) { - return NULL; + return nullptr; } def = (FSwitchDef *)M_Malloc (myoffsetof (FSwitchDef, frames[0]) + frames.Size()*sizeof(frames[0])); def->Sound = sound; def->NumFrames = frames.Size(); memcpy (&def->frames[0], &frames[0], frames.Size() * sizeof(frames[0])); - def->PairDef = NULL; + def->PairDef = nullptr; return def; } @@ -310,11 +313,11 @@ FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad) // //========================================================================== -void FTextureManager::AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2) +void FTextureAnimator::AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2) { unsigned int i; - FSwitchDef *sw1 = NULL; - FSwitchDef *sw2 = NULL; + FSwitchDef *sw1 = nullptr; + FSwitchDef *sw2 = nullptr; unsigned int index1 = 0xffffffff, index2 = 0xffffffff; for (i = mSwitchDefs.Size (); i-- > 0; ) @@ -336,7 +339,7 @@ void FTextureManager::AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2) def1->PairDef = def2; def2->PairDef = def1; - if (sw1 != NULL && sw2 != NULL && sw1->PairDef == sw2 && sw2->PairDef == sw1) + if (sw1 != nullptr && sw2 != nullptr && sw1->PairDef == sw2 && sw2->PairDef == sw1) { //We are replacing an existing pair so we can safely delete the old definitions M_Free(sw1); @@ -350,10 +353,10 @@ void FTextureManager::AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2) // We should not break up an old pair if the new one only redefined one // of the two textures. These paired definitions will only be used // as the return animation so their names don't matter. Better clear them to be safe. - if (sw1 != NULL) sw1->PreTexture.SetInvalid(); - if (sw2 != NULL) sw2->PreTexture.SetInvalid(); - sw1 = NULL; - sw2 = NULL; + if (sw1 != nullptr) sw1->PreTexture.SetInvalid(); + if (sw2 != nullptr) sw2->PreTexture.SetInvalid(); + sw1 = nullptr; + sw2 = nullptr; unsigned int pos = mSwitchDefs.Reserve(2); mSwitchDefs[pos] = def1; mSwitchDefs[pos+1] = def2; @@ -366,7 +369,7 @@ void FTextureManager::AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2) // //========================================================================== -FSwitchDef *FTextureManager::FindSwitch (FTextureID texture) +FSwitchDef *FTextureAnimator::FindSwitch (FTextureID texture) { int mid, low, high; @@ -391,6 +394,6 @@ FSwitchDef *FTextureManager::FindSwitch (FTextureID texture) } } while (low <= high); } - return NULL; + return nullptr; } diff --git a/src/gamedata/textures/animations.cpp b/src/gamedata/textures/animations.cpp index 0132fc33615..d40f2c7c501 100644 --- a/src/gamedata/textures/animations.cpp +++ b/src/gamedata/textures/animations.cpp @@ -34,13 +34,16 @@ #include "doomtype.h" #include "cmdlib.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "r_sky.h" #include "m_random.h" #include "d_player.h" #include "p_spec.h" -#include "w_wad.h" +#include "filesystem.h" #include "serializer.h" +#include "animations.h" +#include "texturemanager.h" +#include "image.h" // MACROS ------------------------------------------------------------------ @@ -49,6 +52,7 @@ // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- +FTextureAnimator TexAnim; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -56,85 +60,103 @@ static FRandom pr_animatepictures ("AnimatePics"); // CODE -------------------------------------------------------------------- +void FTextureAnimator::DeleteAll() +{ + mAnimations.Clear(); + + for (unsigned i = 0; i < mSwitchDefs.Size(); i++) + { + if (mSwitchDefs[i] != NULL) + { + M_Free(mSwitchDefs[i]); + mSwitchDefs[i] = NULL; + } + } + mSwitchDefs.Clear(); + mAnimatedDoors.Clear(); +} + //========================================================================== // -// FTextureManager :: AddAnim +// FTextureAnimator :: AddAnim // // Adds a new animation to the array. If one with the same basepic as the // new one already exists, it is replaced. // //========================================================================== -FAnimDef *FTextureManager::AddAnim (FAnimDef *anim) +FAnimDef *FTextureAnimator::AddAnim (FAnimDef& anim) { // Search for existing duplicate. - for (unsigned int i = 0; i < mAnimations.Size(); ++i) - { - if (mAnimations[i]->BasePic == anim->BasePic) - { - // Found one! - M_Free (mAnimations[i]); - mAnimations[i] = anim; - return anim; - } + uint16_t * index = mAnimationIndices.CheckKey(anim.BasePic); + + if(index) + { // Found one! + mAnimations[*index] = anim; + return &mAnimations[*index]; + } + else + { // Didn't find one, so add it at the end. + mAnimationIndices.Insert(anim.BasePic, mAnimations.Size()); + mAnimations.Push (anim); + return &mAnimations.Last(); } - // Didn't find one, so add it at the end. - mAnimations.Push (anim); - return anim; } //========================================================================== // -// FTextureManager :: AddSimpleAnim +// FTextureAnimator :: AddSimpleAnim // // Creates an animation with simple characteristics. This is used for // original Doom (non-ANIMDEFS-style) animations and Build animations. // //========================================================================== -FAnimDef *FTextureManager::AddSimpleAnim (FTextureID picnum, int animcount, uint32_t speedmin, uint32_t speedrange) +FAnimDef *FTextureAnimator::AddSimpleAnim (FTextureID picnum, int animcount, uint32_t speedmin, uint32_t speedrange) { - if (AreTexturesCompatible(picnum, picnum + (animcount - 1))) - { - FAnimDef *anim = (FAnimDef *)M_Malloc (sizeof(FAnimDef)); - anim->CurFrame = 0; - anim->BasePic = picnum; - anim->NumFrames = animcount; - anim->AnimType = FAnimDef::ANIM_Forward; - anim->bDiscrete = false; - anim->SwitchTime = 0; - anim->Frames[0].SpeedMin = speedmin; - anim->Frames[0].SpeedRange = speedrange; - anim->Frames[0].FramePic = anim->BasePic; + if (TexMan.AreTexturesCompatible(picnum, picnum + (animcount - 1))) + { + FAnimDef anim; + anim.CurFrame = 0; + anim.BasePic = picnum; + anim.NumFrames = animcount; + anim.AnimType = FAnimDef::ANIM_Forward; + anim.bDiscrete = false; + anim.SwitchTime = 0; + anim.Frames = (FAnimDef::FAnimFrame*)ImageArena.Alloc(sizeof(FAnimDef::FAnimFrame)); + anim.Frames[0].SpeedMin = speedmin; + anim.Frames[0].SpeedRange = speedrange; + anim.Frames[0].FramePic = anim.BasePic; return AddAnim (anim); } - return NULL; + return nullptr; } //========================================================================== // -// FTextureManager :: AddComplexAnim +// FTextureAnimator :: AddComplexAnim // // Creates an animation with individually defined frames. // //========================================================================== -FAnimDef *FTextureManager::AddComplexAnim (FTextureID picnum, const TArray &frames) +FAnimDef *FTextureAnimator::AddComplexAnim (FTextureID picnum, const TArray &frames) { - FAnimDef *anim = (FAnimDef *)M_Malloc (sizeof(FAnimDef) + (frames.Size()-1) * sizeof(frames[0])); - anim->BasePic = picnum; - anim->NumFrames = frames.Size(); - anim->CurFrame = 0; - anim->AnimType = FAnimDef::ANIM_Forward; - anim->bDiscrete = true; - anim->SwitchTime = 0; - memcpy (&anim->Frames[0], &frames[0], frames.Size() * sizeof(frames[0])); + FAnimDef anim; + anim.BasePic = picnum; + anim.NumFrames = frames.Size(); + anim.CurFrame = 0; + anim.AnimType = FAnimDef::ANIM_Forward; + anim.bDiscrete = true; + anim.SwitchTime = 0; + anim.Frames = (FAnimDef::FAnimFrame*)ImageArena.Alloc(frames.Size() * sizeof(frames[0])); + memcpy (&anim.Frames[0], &frames[0], frames.Size() * sizeof(frames[0])); return AddAnim (anim); } //========================================================================== // -// FTextureManager :: Initanimated +// FTextureAnimator :: Initanimated // // [description copied from BOOM] // Load the table of animation definitions, checking for existence of @@ -172,19 +194,19 @@ FAnimDef *FTextureManager::AddComplexAnim (FTextureID picnum, const TArraybNoDecals = Texture(pic1)->bNoDecals = !(*anim_p & 2); + bool nodecals = !(*anim_p & 2); + TexMan.GameTexture(pic2)->SetNoDecals(nodecals); + TexMan.GameTexture(pic1)->SetNoDecals(nodecals); } else { - if (!(pic1 = CheckForTexture ((const char*)(anim_p + 10) /* .startname */, ETextureType::Flat, texflags)).Exists() || - !(pic2 = CheckForTexture ((const char*)(anim_p + 1) /* .startname */, ETextureType::Flat, texflags)).Exists()) + if (!(pic1 = TexMan.CheckForTexture ((const char*)(anim_p + 10) /* .startname */, ETextureType::Flat, texflags)).Exists() || + !(pic2 = TexMan.CheckForTexture ((const char*)(anim_p + 1) /* .startname */, ETextureType::Flat, texflags)).Exists()) continue; } - FTexture *tex1 = Texture(pic1); - FTexture *tex2 = Texture(pic2); + auto tex1 = TexMan.GameTexture(pic1); + auto tex2 = TexMan.GameTexture(pic2); animspeed = (anim_p[19] << 0) | (anim_p[20] << 8) | (anim_p[21] << 16) | (anim_p[22] << 24); @@ -226,13 +250,13 @@ void FTextureManager::InitAnimated (void) // SMMU-style swirly hack? Don't apply on already-warping texture if (animspeed > 65535 && tex1 != NULL && !tex1->isWarped()) { - tex1->bWarped = 2; + tex1->SetWarpStyle(2); } // These tests were not really relevant for swirling textures, or even potentially // harmful, so they have been moved to the else block. else { - if (tex1->UseType != tex2->UseType) + if (tex1->GetUseType() != tex2->GetUseType()) { // not the same type - continue; @@ -241,8 +265,8 @@ void FTextureManager::InitAnimated (void) if (debuganimated) { Printf("Defining animation '%s' (texture %d, lump %d, file %d) to '%s' (texture %d, lump %d, file %d)\n", - tex1->Name.GetChars(), pic1.GetIndex(), tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()), - tex2->Name.GetChars(), pic2.GetIndex(), tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump())); + tex1->GetName().GetChars(), pic1.GetIndex(), tex1->GetSourceLump(), fileSystem.GetFileContainer(tex1->GetSourceLump()), + tex2->GetName().GetChars(), pic2.GetIndex(), tex2->GetSourceLump(), fileSystem.GetFileContainer(tex2->GetSourceLump())); } if (pic1 == pic2) @@ -254,12 +278,12 @@ void FTextureManager::InitAnimated (void) // [RH] Allow for backward animations as well as forward. else if (pic1 > pic2) { - swapvalues (pic1, pic2); + std::swap (pic1, pic2); animtype = FAnimDef::ANIM_Backward; } // Speed is stored as tics, but we want ms so scale accordingly. - FAnimDef *adef = AddSimpleAnim (pic1, pic2 - pic1 + 1, Scale (animspeed, 1000, 35)); + FAnimDef *adef = AddSimpleAnim (pic1, pic2 - pic1 + 1, Scale (animspeed, 1000, TICRATE)); if (adef != NULL) adef->AnimType = animtype; } } @@ -268,18 +292,18 @@ void FTextureManager::InitAnimated (void) //========================================================================== // -// FTextureManager :: InitAnimDefs +// FTextureAnimator :: InitAnimDefs // // This uses a Hexen ANIMDEFS lump to define the animation sequences // //========================================================================== -void FTextureManager::InitAnimDefs () +void FTextureAnimator::InitAnimDefs () { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; int lump, lastlump = 0; - while ((lump = Wads.FindLump ("ANIMDEFS", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("ANIMDEFS", &lastlump)) != -1) { FScanner sc(lump); @@ -302,6 +326,10 @@ void FTextureManager::InitAnimDefs () { ParseWarp(sc); } + else if (sc.Compare("canvastexture")) + { + ParseCanvasTexture(sc); + } else if (sc.Compare ("cameratexture")) { ParseCameraTexture(sc); @@ -313,11 +341,11 @@ void FTextureManager::InitAnimDefs () else if (sc.Compare("skyoffset")) { sc.MustGetString (); - FTextureID picnum = CheckForTexture (sc.String, ETextureType::Wall, texflags); + FTextureID picnum = TexMan.CheckForTexture (sc.String, ETextureType::Wall, texflags); sc.MustGetNumber(); if (picnum.Exists()) { - Texture(picnum)->SkyOffset = sc.Number; + TexMan.GameTexture(picnum)->SetSkyOffset(sc.Number); } } else @@ -330,16 +358,16 @@ void FTextureManager::InitAnimDefs () //========================================================================== // -// FTextureManager :: ParseAnim +// FTextureAnimator :: ParseAnim // // Parse a single animation definition out of an ANIMDEFS lump and // create the corresponding animation structure. // //========================================================================== -void FTextureManager::ParseAnim (FScanner &sc, ETextureType usetype) +void FTextureAnimator::ParseAnim (FScanner &sc, ETextureType usetype) { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; TArray frames (32); FTextureID picnum; int defined = 0; @@ -353,7 +381,7 @@ void FTextureManager::ParseAnim (FScanner &sc, ETextureType usetype) optional = true; sc.MustGetString (); } - picnum = CheckForTexture (sc.String, usetype, texflags); + picnum = TexMan.CheckForTexture (sc.String, usetype, texflags); if (!picnum.Exists()) { @@ -370,7 +398,7 @@ void FTextureManager::ParseAnim (FScanner &sc, ETextureType usetype) // no decals on animating textures, by default if (picnum.isValid()) { - Texture(picnum)->bNoDecals = true; + TexMan.GameTexture(picnum)->SetNoDecals(true); } while (sc.GetString ()) @@ -379,7 +407,7 @@ void FTextureManager::ParseAnim (FScanner &sc, ETextureType usetype) { if (picnum.isValid()) { - Texture(picnum)->bNoDecals = false; + TexMan.GameTexture(picnum)->SetNoDecals(false); } continue; } @@ -401,7 +429,7 @@ void FTextureManager::ParseAnim (FScanner &sc, ETextureType usetype) } else if (sc.Compare ("range")) { - if (picnum.Exists() && Texture(picnum)->Name.IsEmpty()) + if (picnum.Exists() && TexMan.GameTexture(picnum)->GetName().IsEmpty()) { // long texture name: We cannot do ranged anims on these because they have no defined order sc.ScriptError ("You cannot use \"range\" for long texture names."); @@ -417,6 +445,17 @@ void FTextureManager::ParseAnim (FScanner &sc, ETextureType usetype) defined = 1; ani = ParseRangeAnim (sc, picnum, usetype, missing); } + else if (sc.Compare("notrim")) + { + if (picnum.isValid()) + { + auto tex = TexMan.GetGameTexture(picnum); + + if (tex) tex->SetNoTrimming(true); + else sc.ScriptError("NoTrim: %s not found", sc.String); + } + else sc.ScriptError("NoTrim: %s is not a sprite", sc.String); + } else if (sc.Compare ("pic")) { if (defined == 1) @@ -452,14 +491,14 @@ void FTextureManager::ParseAnim (FScanner &sc, ETextureType usetype) //========================================================================== // -// FTextureManager :: ParseRangeAnim +// FTextureAnimator :: ParseRangeAnim // // Parse an animation defined using "range". Not that one range entry is // enough to define a complete animation, unlike "pic". // //========================================================================== -FAnimDef *FTextureManager::ParseRangeAnim (FScanner &sc, FTextureID picnum, ETextureType usetype, bool missing) +FAnimDef *FTextureAnimator::ParseRangeAnim (FScanner &sc, FTextureID picnum, ETextureType usetype, bool missing) { int type; FTextureID framenum; @@ -475,7 +514,7 @@ FAnimDef *FTextureManager::ParseRangeAnim (FScanner &sc, FTextureID picnum, ETex return NULL; // Animation is only one frame or does not exist } - if (Texture(framenum)->Name.IsEmpty()) + if (TexMan.GameTexture(framenum)->GetName().IsEmpty()) { // long texture name: We cannot do ranged anims on these because they have no defined order sc.ScriptError ("You cannot use \"range\" for long texture names."); @@ -484,8 +523,8 @@ FAnimDef *FTextureManager::ParseRangeAnim (FScanner &sc, FTextureID picnum, ETex if (framenum < picnum) { type = FAnimDef::ANIM_Backward; - Texture(framenum)->bNoDecals = Texture(picnum)->bNoDecals; - swapvalues (framenum, picnum); + TexMan.GameTexture(framenum)->SetNoDecals(TexMan.GameTexture(picnum)->allowNoDecals()); + std::swap (framenum, picnum); } FAnimDef *ani = AddSimpleAnim (picnum, framenum - picnum + 1, min, max - min); if (ani != NULL) ani->AnimType = type; @@ -494,13 +533,13 @@ FAnimDef *FTextureManager::ParseRangeAnim (FScanner &sc, FTextureID picnum, ETex //========================================================================== // -// FTextureManager :: ParsePicAnim +// FTextureAnimator :: ParsePicAnim // // Parse a single frame from ANIMDEFS defined using "pic". // //========================================================================== -void FTextureManager::ParsePicAnim (FScanner &sc, FTextureID picnum, ETextureType usetype, bool missing, TArray &frames) +void FTextureAnimator::ParsePicAnim (FScanner &sc, FTextureID picnum, ETextureType usetype, bool missing, TArray &frames) { FTextureID framenum; uint32_t min = 1, max = 1; @@ -521,16 +560,16 @@ void FTextureManager::ParsePicAnim (FScanner &sc, FTextureID picnum, ETextureTyp //========================================================================== // -// FTextureManager :: ParseFramenum +// FTextureAnimator :: ParseFramenum // // Reads a frame's texture from ANIMDEFS. It can either be an integral // offset from basepicnum or a specific texture name. // //========================================================================== -FTextureID FTextureManager::ParseFramenum (FScanner &sc, FTextureID basepicnum, ETextureType usetype, bool allowMissing) +FTextureID FTextureAnimator::ParseFramenum (FScanner &sc, FTextureID basepicnum, ETextureType usetype, bool allowMissing) { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; FTextureID framenum; sc.MustGetString (); @@ -540,7 +579,7 @@ FTextureID FTextureManager::ParseFramenum (FScanner &sc, FTextureID basepicnum, } else { - framenum = CheckForTexture (sc.String, usetype, texflags); + framenum = TexMan.CheckForTexture (sc.String, usetype, texflags); if (!framenum.Exists() && !allowMissing) { sc.ScriptError ("Unknown texture %s", sc.String); @@ -551,26 +590,26 @@ FTextureID FTextureManager::ParseFramenum (FScanner &sc, FTextureID basepicnum, //========================================================================== // -// FTextureManager :: ParseTime +// FTextureAnimator :: ParseTime // // Reads a tics or rand time definition from ANIMDEFS. // //========================================================================== -void FTextureManager::ParseTime (FScanner &sc, uint32_t &min, uint32_t &max) +void FTextureAnimator::ParseTime (FScanner &sc, uint32_t &min, uint32_t &max) { sc.MustGetString (); if (sc.Compare ("tics")) { sc.MustGetFloat (); - min = max = uint32_t(sc.Float * 1000 / 35); + min = max = uint32_t(sc.Float * 1000 / TICRATE); } else if (sc.Compare ("rand")) { sc.MustGetFloat (); - min = uint32_t(sc.Float * 1000 / 35); + min = uint32_t(sc.Float * 1000 / TICRATE); sc.MustGetFloat (); - max = uint32_t(sc.Float * 1000 / 35); + max = uint32_t(sc.Float * 1000 / TICRATE); } else { @@ -581,15 +620,15 @@ void FTextureManager::ParseTime (FScanner &sc, uint32_t &min, uint32_t &max) //========================================================================== // -// FTextureManager :: ParseWarp +// FTextureAnimator :: ParseWarp // // Parses a warping texture definition // //========================================================================== -void FTextureManager::ParseWarp(FScanner &sc) +void FTextureAnimator::ParseWarp(FScanner &sc) { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; bool isflat = false; bool type2 = sc.Compare ("warp2"); // [GRB] sc.MustGetString (); @@ -607,13 +646,13 @@ void FTextureManager::ParseWarp(FScanner &sc) { sc.ScriptError (NULL); } - FTextureID picnum = CheckForTexture (sc.String, isflat ? ETextureType::Flat : ETextureType::Wall, texflags); + FTextureID picnum = TexMan.CheckForTexture (sc.String, isflat ? ETextureType::Flat : ETextureType::Wall, texflags); if (picnum.isValid()) { - FTexture *warper = Texture(picnum); + auto warper = TexMan.GameTexture(picnum); - if (warper->Name.IsEmpty()) + if (warper->GetName().IsEmpty()) { // long texture name: We cannot do warps on these due to the way the texture manager implements warping as a texture replacement. sc.ScriptError ("You cannot use \"warp\" for long texture names."); @@ -623,23 +662,23 @@ void FTextureManager::ParseWarp(FScanner &sc) // don't warp a texture more than once if (!warper->isWarped()) { - warper->bWarped = type2? 2:1; + warper->SetWarpStyle(type2 ? 2 : 1); } if (sc.CheckFloat()) { - warper->SetSpeed(float(sc.Float)); + warper->SetShaderSpeed(float(sc.Float)); } // No decals on warping textures, by default. // Warping information is taken from the last warp // definition for this texture. - warper->bNoDecals = true; + warper->SetNoDecals(true); if (sc.GetString ()) { if (sc.Compare ("allowdecals")) { - warper->bNoDecals = false; + warper->SetNoDecals(false); } else { @@ -649,6 +688,21 @@ void FTextureManager::ParseWarp(FScanner &sc) } } + +//========================================================================== +// +// ParseCameraTexture +// +// Parses a canvas texture definition +// +//========================================================================== + +void FTextureAnimator::ParseCanvasTexture(FScanner& sc) +{ + // This is currently identical to camera textures. + ParseCameraTexture(sc); +} + //========================================================================== // // ParseCameraTexture @@ -657,11 +711,11 @@ void FTextureManager::ParseWarp(FScanner &sc) // //========================================================================== -void FTextureManager::ParseCameraTexture(FScanner &sc) +void FTextureAnimator::ParseCameraTexture(FScanner &sc) { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny | TEXMAN_ShortNameOnly; + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly; int width, height; - int fitwidth, fitheight; + double fitwidth, fitheight; FString picname; sc.MustGetString (); @@ -670,23 +724,34 @@ void FTextureManager::ParseCameraTexture(FScanner &sc) width = sc.Number; sc.MustGetNumber (); height = sc.Number; - FTextureID picnum = CheckForTexture (picname, ETextureType::Flat, texflags); - FTexture *viewer = new FCanvasTexture (picname, width, height); + FTextureID picnum = TexMan.CheckForTexture (picname.GetChars(), ETextureType::Flat, texflags); + auto canvas = new FCanvasTexture(width, height); + FGameTexture *viewer = MakeGameTexture(canvas, picname.GetChars(), ETextureType::Wall); if (picnum.Exists()) { - FTexture *oldtex = Texture(picnum); - fitwidth = oldtex->GetScaledWidth (); - fitheight = oldtex->GetScaledHeight (); - viewer->UseType = oldtex->UseType; - ReplaceTexture (picnum, viewer, true); + auto oldtex = TexMan.GameTexture(picnum); + fitwidth = oldtex->GetDisplayWidth (); + fitheight = oldtex->GetDisplayHeight (); + viewer->SetUseType(oldtex->GetUseType()); + TexMan.ReplaceTexture (picnum, viewer, true); } else { fitwidth = width; fitheight = height; // [GRB] No need for oldtex - viewer->UseType = ETextureType::Wall; - AddTexture (viewer); + TexMan.AddGameTexture (viewer); + } + if (sc.GetString()) + { + if (sc.Compare ("hdr")) + { + canvas->SetHDR(true); + } + else + { + sc.UnGet(); + } } if (sc.GetString()) { @@ -706,19 +771,20 @@ void FTextureManager::ParseCameraTexture(FScanner &sc) { if (sc.Compare("WorldPanning")) { - viewer->bWorldPanning = true; + viewer->SetWorldPanning(true); } else { sc.UnGet(); } } - viewer->SetScaledSize(fitwidth, fitheight); + canvas->aspectRatio = (float)fitwidth / (float)fitheight; + viewer->SetDisplaySize((float)fitwidth, (float)fitheight); } //========================================================================== // -// FTextureManager :: FixAnimations +// FTextureAnimator :: FixAnimations // // Copy the "front sky" flag from an animated texture to the rest // of the textures in the animation, and make every texture in an @@ -726,44 +792,26 @@ void FTextureManager::ParseCameraTexture(FScanner &sc) // //========================================================================== -void FTextureManager::FixAnimations () +void FTextureAnimator::FixAnimations () { unsigned int i; int j; for (i = 0; i < mAnimations.Size(); ++i) { - FAnimDef *anim = mAnimations[i]; - if (anim->bDiscrete) - { - if (Texture(anim->BasePic)->bNoRemap0) - { - for (j = 0; j < anim->NumFrames; ++j) - { - Texture(anim->Frames[j].FramePic)->SetFrontSkyLayer (); - } - } - } - else + const FAnimDef *anim = &mAnimations[i]; + if (!anim->bDiscrete) { bool nodecals; bool noremap = false; const char *name; - name = Texture(anim->BasePic)->Name; - nodecals = Texture(anim->BasePic)->bNoDecals; + name = TexMan.GameTexture(anim->BasePic)->GetName().GetChars(); + nodecals = TexMan.GameTexture(anim->BasePic)->allowNoDecals(); for (j = 0; j < anim->NumFrames; ++j) { - FTexture *tex = Texture(anim->BasePic + j); - noremap |= tex->bNoRemap0; - tex->bNoDecals = nodecals; - } - if (noremap) - { - for (j = 0; j < anim->NumFrames; ++j) - { - Texture(anim->BasePic + j)->SetFrontSkyLayer (); - } + auto tex = TexMan.GameTexture(anim->BasePic + j); + tex->SetNoDecals(nodecals); } } } @@ -777,16 +825,16 @@ void FTextureManager::FixAnimations () // //========================================================================== -void FTextureManager::ParseAnimatedDoor(FScanner &sc) +void FTextureAnimator::ParseAnimatedDoor(FScanner &sc) { - const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; FDoorAnimation anim; TArray frames; bool error = false; FTextureID v; sc.MustGetString(); - anim.BaseTexture = CheckForTexture (sc.String, ETextureType::Wall, texflags); + anim.BaseTexture = TexMan.CheckForTexture (sc.String, ETextureType::Wall, texflags); anim.OpenSound = anim.CloseSound = NAME_None; if (!anim.BaseTexture.Exists()) @@ -795,7 +843,7 @@ void FTextureManager::ParseAnimatedDoor(FScanner &sc) } else { - Texture(anim.BaseTexture)->bNoDecals = true; + TexMan.GameTexture(anim.BaseTexture)->SetNoDecals(true); } while (sc.GetString()) { @@ -818,7 +866,7 @@ void FTextureManager::ParseAnimatedDoor(FScanner &sc) } else { - v = CheckForTexture (sc.String, ETextureType::Wall, texflags); + v = TexMan.CheckForTexture (sc.String, ETextureType::Wall, texflags); if (!v.Exists() && anim.BaseTexture.Exists() && !error) { sc.ScriptError ("Unknown texture %s", sc.String); @@ -828,7 +876,7 @@ void FTextureManager::ParseAnimatedDoor(FScanner &sc) } else if (sc.Compare("allowdecals")) { - if (anim.BaseTexture.Exists()) Texture(anim.BaseTexture)->bNoDecals = false; + if (anim.BaseTexture.Exists()) TexMan.GameTexture(anim.BaseTexture)->SetNoDecals(false); } else { @@ -838,7 +886,7 @@ void FTextureManager::ParseAnimatedDoor(FScanner &sc) } if (!error) { - anim.TextureFrames = new FTextureID[frames.Size()]; + anim.TextureFrames = (FTextureID*)ImageArena.Alloc(sizeof(FTextureID) * frames.Size()); memcpy (anim.TextureFrames, &frames[0], sizeof(FTextureID) * frames.Size()); anim.NumTextureFrames = frames.Size(); mAnimatedDoors.Push (anim); @@ -851,7 +899,7 @@ void FTextureManager::ParseAnimatedDoor(FScanner &sc) // //========================================================================== -FDoorAnimation *FTextureManager::FindAnimatedDoor (FTextureID picnum) +FDoorAnimation *FTextureAnimator::FindAnimatedDoor (FTextureID picnum) { unsigned int i; @@ -883,41 +931,118 @@ void FAnimDef::SetSwitchTime (uint64_t mstime) } } +static void AdvanceFrame(uint16_t &frame, uint8_t &AnimType, const FAnimDef &anim) +{ + switch (AnimType) + { + default: + case FAnimDef::ANIM_Forward: + frame = (frame + 1) % anim.NumFrames; + break; -//========================================================================== -// -// FTextureManager :: SetTranslation -// -// Sets animation translation for a texture -// -//========================================================================== + case FAnimDef::ANIM_Backward: + if (frame == 0) + { + frame = anim.NumFrames - 1; + } + else + { + frame--; + } + break; + case FAnimDef::ANIM_Random: + // select a random frame other than the current one + if (anim.NumFrames > 1) + { + uint16_t rndFrame = (uint16_t)pr_animatepictures(anim.NumFrames - 1); + if(rndFrame == frame) rndFrame++; + frame = rndFrame % anim.NumFrames; + } + break; + + case FAnimDef::ANIM_OscillateUp: + frame = frame + 1; + assert(frame < anim.NumFrames); + if (frame == anim.NumFrames - 1) + { + AnimType = FAnimDef::ANIM_OscillateDown; + } + break; + + case FAnimDef::ANIM_OscillateDown: + frame = frame - 1; + if (frame == 0) + { + AnimType = FAnimDef::ANIM_OscillateUp; + } + break; + } +} + +constexpr double msPerTic = 1'000.0 / TICRATE; -void FTextureManager::SetTranslation (FTextureID fromtexnum, FTextureID totexnum) +bool FTextureAnimator::InitStandaloneAnimation(FStandaloneAnimation &animInfo, FTextureID tex, uint32_t curTic) { - if ((size_t)fromtexnum.texnum < Translation.Size()) + animInfo.ok = false; + uint16_t * index = mAnimationIndices.CheckKey(tex); + if(!index) return false; + FAnimDef * anim = &mAnimations[*index]; + + animInfo.ok = true; + animInfo.AnimIndex = *index; + animInfo.CurFrame = 0; + animInfo.SwitchTic = curTic; + animInfo.AnimType = (anim->AnimType == FAnimDef::ANIM_OscillateDown) ? FAnimDef::ANIM_OscillateUp : anim->AnimType; + uint32_t time = anim->Frames[0].SpeedMin; + if(anim->Frames[0].SpeedRange != 0) { - if ((size_t)totexnum.texnum >= Textures.Size()) + time += pr_animatepictures(anim->Frames[0].SpeedRange); + } + animInfo.SwitchTic += time / msPerTic; + return true; +} + +FTextureID FTextureAnimator::UpdateStandaloneAnimation(FStandaloneAnimation &animInfo, double curTic) +{ + if(!animInfo.ok) return nullptr; + auto &anim = mAnimations[animInfo.AnimIndex]; + if(animInfo.SwitchTic <= curTic) + { + uint16_t frame = animInfo.CurFrame; + uint16_t speedframe = anim.bDiscrete ? frame : 0; + while(animInfo.SwitchTic <= curTic) { - totexnum.texnum = fromtexnum.texnum; + AdvanceFrame(frame, animInfo.AnimType, anim); + + if(anim.bDiscrete) speedframe = frame; + + uint32_t time = anim.Frames[speedframe].SpeedMin; + if(anim.Frames[speedframe].SpeedRange != 0) + { + time += pr_animatepictures(anim.Frames[speedframe].SpeedRange); + } + + animInfo.SwitchTic += time / msPerTic; } - Translation[fromtexnum.texnum] = totexnum.texnum; + animInfo.CurFrame = frame; } + return anim.bDiscrete ? anim.Frames[animInfo.CurFrame].FramePic : (anim.BasePic + animInfo.CurFrame); } //========================================================================== // -// FTextureManager :: UpdateAnimations +// FTextureAnimator :: UpdateAnimations // // Updates texture translations for each animation and scrolls the skies. // //========================================================================== -void FTextureManager::UpdateAnimations (uint64_t mstime) +void FTextureAnimator::UpdateAnimations (uint64_t mstime) { for (unsigned int j = 0; j < mAnimations.Size(); ++j) { - FAnimDef *anim = mAnimations[j]; + FAnimDef *anim = &mAnimations[j]; // If this is the first time through R_UpdateAnimations, just // initialize the anim's switch time without actually animating. @@ -929,62 +1054,19 @@ void FTextureManager::UpdateAnimations (uint64_t mstime) { // Multiple frames may have passed since the last time calling // R_UpdateAnimations, so be sure to loop through them all. - switch (anim->AnimType) - { - default: - case FAnimDef::ANIM_Forward: - anim->CurFrame = (anim->CurFrame + 1) % anim->NumFrames; - break; - - case FAnimDef::ANIM_Backward: - if (anim->CurFrame == 0) - { - anim->CurFrame = anim->NumFrames - 1; - } - else - { - anim->CurFrame -= 1; - } - break; - - case FAnimDef::ANIM_Random: - // select a random frame other than the current one - if (anim->NumFrames > 1) - { - uint16_t rndFrame = (uint16_t)pr_animatepictures(anim->NumFrames - 1); - if (rndFrame >= anim->CurFrame) rndFrame++; - anim->CurFrame = rndFrame; - } - break; - - case FAnimDef::ANIM_OscillateUp: - anim->CurFrame = anim->CurFrame + 1; - if (anim->CurFrame >= anim->NumFrames - 1) - { - anim->AnimType = FAnimDef::ANIM_OscillateDown; - } - break; - - case FAnimDef::ANIM_OscillateDown: - anim->CurFrame = anim->CurFrame - 1; - if (anim->CurFrame == 0) - { - anim->AnimType = FAnimDef::ANIM_OscillateUp; - } - break; - } + AdvanceFrame(anim->CurFrame, anim->AnimType, *anim); anim->SetSwitchTime (mstime); } if (anim->bDiscrete) { - SetTranslation (anim->BasePic, anim->Frames[anim->CurFrame].FramePic); + TexMan.SetTranslation (anim->BasePic, anim->Frames[anim->CurFrame].FramePic); } else { for (unsigned int i = 0; i < anim->NumFrames; i++) { - SetTranslation (anim->BasePic + i, anim->BasePic + (i + anim->CurFrame) % anim->NumFrames); + TexMan.SetTranslation (anim->BasePic + i, anim->BasePic + (i + anim->CurFrame) % anim->NumFrames); } } } @@ -1002,7 +1084,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimat Serialize(arc, key, tex, def ? &(*def)->BaseTexture : nullptr); if (arc.isReading()) { - p = TexMan.FindAnimatedDoor(tex); + p = TexAnim.FindAnimatedDoor(tex); } return arc; } diff --git a/src/gamedata/textures/animations.h b/src/gamedata/textures/animations.h new file mode 100644 index 00000000000..aa6b00e4e11 --- /dev/null +++ b/src/gamedata/textures/animations.h @@ -0,0 +1,134 @@ +#pragma once + +#include +#include "name.h" +#include "textureid.h" +#include "tarray.h" +#include "s_soundinternal.h" + +struct FStandaloneAnimation +{ + double SwitchTic; + uint32_t AnimIndex; + uint16_t CurFrame; + bool ok = false; + uint8_t AnimType; +}; + +static_assert(sizeof(FStandaloneAnimation) == sizeof(uint64_t)*2); + +struct FAnimDef +{ + struct FAnimFrame + { + uint32_t SpeedMin; // Speeds are in ms, not tics + uint32_t SpeedRange; + FTextureID FramePic; + }; + + FTextureID BasePic; + uint16_t NumFrames; + uint16_t CurFrame; + uint8_t AnimType; + bool bDiscrete; // taken out of AnimType to have better control + uint64_t SwitchTime; // Time to advance to next frame + FAnimFrame* Frames; + enum + { + ANIM_Forward, + ANIM_Backward, + ANIM_OscillateUp, + ANIM_OscillateDown, + ANIM_Random + }; + + void SetSwitchTime(uint64_t mstime); +}; + +struct FSwitchDef +{ + FTextureID PreTexture; // texture to switch from + FSwitchDef* PairDef; // switch def to use to return to PreTexture + uint16_t NumFrames; // # of animation frames + bool QuestPanel; // Special texture for Strife mission + FSoundID Sound; // sound to play at start of animation. Changed to int to avoiud having to include s_sound here. + struct frame // Array of times followed by array of textures + { // actual length of each array is + uint16_t TimeMin; + uint16_t TimeRnd; + FTextureID Texture; + } frames[1]; +}; + +struct FDoorAnimation +{ + FTextureID BaseTexture; + FTextureID* TextureFrames; + int NumTextureFrames; + FName OpenSound; + FName CloseSound; +}; + + + +class FTextureAnimator +{ + TMap mAnimationIndices; + TArray mAnimations; + TArray mSwitchDefs; + TArray mAnimatedDoors; + + void ParseAnim(FScanner& sc, ETextureType usetype); + FAnimDef* ParseRangeAnim(FScanner& sc, FTextureID picnum, ETextureType usetype, bool missing); + void ParsePicAnim(FScanner& sc, FTextureID picnum, ETextureType usetype, bool missing, TArray& frames); + void ParseWarp(FScanner& sc); + void ParseCanvasTexture(FScanner& sc); + void ParseCameraTexture(FScanner& sc); + FTextureID ParseFramenum(FScanner& sc, FTextureID basepicnum, ETextureType usetype, bool allowMissing); + void ParseTime(FScanner& sc, uint32_t& min, uint32_t& max); + + void FixAnimations(); + void InitAnimated(); + void InitAnimDefs(); + void InitSwitchList(); + void ProcessSwitchDef(FScanner& sc); + FSwitchDef* ParseSwitchDef(FScanner& sc, bool ignoreBad); + void AddSwitchPair(FSwitchDef* def1, FSwitchDef* def2); + void ParseAnimatedDoor(FScanner& sc); + +public: + + ~FTextureAnimator() + { + DeleteAll(); + } + + // Animation stuff + FAnimDef* AddAnim(FAnimDef& anim); + void DeleteAll(); + + FAnimDef* AddSimpleAnim(FTextureID picnum, int animcount, uint32_t speedmin, uint32_t speedrange = 0); + FAnimDef* AddComplexAnim(FTextureID picnum, const TArray& frames); + + FSwitchDef* FindSwitch(FTextureID texture); + FDoorAnimation* FindAnimatedDoor(FTextureID picnum); + void UpdateAnimations(uint64_t mstime); + + const TArray& GetAnimations() const { return mAnimations; } + + void Init() + { + DeleteAll(); + InitAnimated(); + InitAnimDefs(); + FixAnimations(); + InitSwitchList(); + } + + bool InitStandaloneAnimation(FStandaloneAnimation &animInfo, FTextureID tex, uint32_t curTic); + FTextureID UpdateStandaloneAnimation(FStandaloneAnimation &animInfo, double curTic); +}; + +extern FTextureAnimator TexAnim; + + diff --git a/src/gamedata/textures/buildloader.cpp b/src/gamedata/textures/buildloader.cpp new file mode 100644 index 00000000000..83c547b5019 --- /dev/null +++ b/src/gamedata/textures/buildloader.cpp @@ -0,0 +1,298 @@ +/* +** buildtexture.cpp +** Handling Build textures (now as a usable editing feature!) +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" + +#include "cmdlib.h" +#include "colormatcher.h" +#include "bitmap.h" +#include "textures.h" +#include "fs_filesystem.h" +#include "image.h" +#include "animations.h" +#include "texturemanager.h" +#include "r_translate.h" +#include "r_data/sprites.h" +#include "m_swap.h" + +//=========================================================================== +// +// CountTiles +// +// Returns the number of tiles provided by an artfile +// +//=========================================================================== + +static int CountTiles (const void *tiles) +{ + int version = LittleLong(*(uint32_t *)tiles); + if (version != 1) + { + return 0; + } + + int tilestart = LittleLong(((uint32_t *)tiles)[2]); + int tileend = LittleLong(((uint32_t *)tiles)[3]); + + return tileend >= tilestart ? tileend - tilestart + 1 : 0; +} + +//=========================================================================== +// +// Create palette data and remap table for the tile set's palette +// +//=========================================================================== + +static int BuildPaletteTranslation(int lump) +{ + if (fileSystem.FileLength(lump) < 768) + { + return false; + } + + auto data = fileSystem.ReadFile(lump); + auto ipal = data.bytes(); + FRemapTable opal; + + bool blood = false; + for (int c = 0; c < 765; c++) // Build used VGA palettes (color values 0..63), Blood used full palettes (0..255) Let's hope this doesn't screw up... + { + if (ipal[c] >= 64) + { + blood = true; + break; + } + } + + for (int c = 0; c < 255; c++) + { + int r, g, b; + if (!blood) + { + r = (ipal[3*c ] << 2) | (ipal[3 * c ] >> 4); + g = (ipal[3*c + 1] << 2) | (ipal[3 * c + 1] >> 4); + b = (ipal[3*c + 2] << 2) | (ipal[3 * c + 2] >> 4); + } + else + { + r = ipal[3 * c] << 2; + g = ipal[3 * c + 1] << 2; + b = ipal[3 * c + 2] << 2; + } + opal.Palette[c] = PalEntry(255, r, g, b); + opal.Remap[c] = ColorMatcher.Pick(r, g, b); + } + // The last entry is transparent. + opal.Palette[255] = 0; + opal.Remap[255] = 0; + // Store the remap table in the translation manager so that we do not need to keep track of it ourselves. + // Slot 0 for internal translations is a convenient location because normally it only contains a small number of translations. + return GetTranslationIndex(GPalette.StoreTranslation(TRANSLATION_Standard, &opal)); +} + + +//=========================================================================== +// +// AddTiles +// +// Adds all the tiles in an artfile to the texture manager. +// +//=========================================================================== + +void AddTiles(const FString& pathprefix, const void* tiles, FRemapTable *remap) +{ + + // int numtiles = LittleLong(((uint32_t *)tiles)[1]); // This value is not reliable + int tilestart = LittleLong(((uint32_t*)tiles)[2]); + int tileend = LittleLong(((uint32_t*)tiles)[3]); + const uint16_t* tilesizx = &((const uint16_t*)tiles)[8]; + const uint16_t* tilesizy = &tilesizx[tileend - tilestart + 1]; + const uint32_t* picanm = (const uint32_t*)&tilesizy[tileend - tilestart + 1]; + const uint8_t* tiledata = (const uint8_t*)&picanm[tileend - tilestart + 1]; + + for (int i = tilestart; i <= tileend; ++i) + { + int pic = i - tilestart; + int width = LittleShort(tilesizx[pic]); + int height = LittleShort(tilesizy[pic]); + uint32_t anm = LittleLong(picanm[pic]); + int xoffs = (int8_t)((anm >> 8) & 255) + width / 2; + int yoffs = (int8_t)((anm >> 16) & 255) + height / 2; + int size = width * height; + FTextureID texnum; + + if (width <= 0 || height <= 0) continue; + + FStringf name("%sBTIL%04d", pathprefix.GetChars(), i); + auto tex = MakeGameTexture(new FImageTexture(new FBuildTexture(pathprefix, i, tiledata, remap, width, height, xoffs, yoffs)), name.GetChars(), ETextureType::Override); + texnum = TexMan.AddGameTexture(tex); + tiledata += size; + + + // reactivate only if the texture counter works here. + //StartScreen->Progress(); + + if ((picanm[pic] & 63) && (picanm[pic] & 192)) + { + int type, speed; + + switch (picanm[pic] & 192) + { + case 64: type = 2; break; + case 128: type = 0; break; + case 192: type = 1; break; + default: type = 0; break; // Won't happen, but GCC bugs me if I don't put this here. + } + + speed = (anm >> 24) & 15; + speed = max(1, (1 << speed) * 1000 / 120); // Convert from 120 Hz to 1000 Hz. + + TexAnim.AddSimpleAnim(texnum, picanm[pic] & 63, type, speed); + } + + // Blood's rotation types: + // 0 - Single + // 1 - 5 Full + // 2 - 8 Full + // 3 - Bounce (looks no different from Single; seems to signal bouncy sprites) + // 4 - 5 Half (not used in game) + // 5 - 3 Flat (not used in game) + // 6 - Voxel + // 7 - Spin Voxel + + int rotType = (anm >> 28) & 7; + if (rotType == 1) + { + spriteframe_t rot; + rot.Texture[0] = + rot.Texture[1] = texnum; + for (int j = 1; j < 4; ++j) + { + rot.Texture[j * 2].SetIndex(texnum.GetIndex() + j); + rot.Texture[j * 2 + 1].SetIndex(texnum.GetIndex() + j); + rot.Texture[16 - j * 2].SetIndex(texnum.GetIndex() + j); + rot.Texture[17 - j * 2].SetIndex(texnum.GetIndex() + j); + } + rot.Texture[8].SetIndex(texnum.GetIndex()); + rot.Texture[9].SetIndex(texnum.GetIndex()); + rot.Flip = 0x00FC; + rot.Voxel = NULL; + tex->SetRotations(SpriteFrames.Push(rot)); + } + else if (rotType == 2) + { + spriteframe_t rot; + rot.Texture[0] = + rot.Texture[1] = texnum; + for (int j = 1; j < 8; ++j) + { + rot.Texture[16 - j * 2].SetIndex(texnum.GetIndex() + j); + rot.Texture[17 - j * 2].SetIndex(texnum.GetIndex() + j); + } + rot.Flip = 0; + rot.Voxel = NULL; + tex->SetRotations(SpriteFrames.Push(rot)); + } + } +} + +//=========================================================================== +// +// R_CountBuildTiles +// +// Returns the number of tiles found. Also loads all the data for +// R_InitBuildTiles() to process later. +// +//=========================================================================== + +void InitBuildTiles() +{ + int lumpnum; + int numtiles; + int totaltiles = 0; + + // The search rules are as follows: + // - scan the entire lump directory for palette.dat files. + // - if one is found, process the directory for .ART files and add textures for them. + // - once all have been found, process all directories that may contain Build data. + // - the root is not excluded which allows to read this from .GRP files as well. + // - Blood support has been removed because it is not useful for modding to have loose .ART files. + // + // Unfortunately neither the palettes nor the .ART files contain any usable identifying marker + // so this can only go by the file names. + + int numlumps = fileSystem.GetNumEntries(); + for (int i = 0; i < numlumps; i++) + { + const char* name = fileSystem.GetFileFullName(i); + if (fileSystem.CheckNumForFullName(name) != i) continue; // This palette is hidden by a later one. Do not process + FString base = ExtractFileBase(name, true); + base.ToLower(); + if (base.Compare("palette.dat") == 0 && fileSystem.FileLength(i) >= 768) // must be a valid palette, i.e. at least 256 colors. + { + FString path = ExtractFilePath(name); + if (path.IsNotEmpty() && path.Back() != '/') path += '/'; + + int translation = BuildPaletteTranslation(i); + auto remap = GPalette.GetTranslation(TRANSLATION_Standard, translation); + + for (int numartfiles = 0; numartfiles < 1000; numartfiles++) + { + FStringf artpath("%stiles%03d.art", path.GetChars(), numartfiles); + // only read from the same source as the palette. + // The entire format here is just too volatile to allow liberal mixing. + // An .ART set must be treated as one unit. + lumpnum = fileSystem.CheckNumForFullName(artpath.GetChars(), fileSystem.GetFileContainer(i)); + if (lumpnum < 0) + { + break; + } + + auto& artdata = TexMan.GetNewBuildTileData(); + artdata.Resize(fileSystem.FileLength(lumpnum)); + fileSystem.ReadFile(lumpnum, &artdata[0]); + + if ((numtiles = CountTiles(&artdata[0])) > 0) + { + AddTiles(path, &artdata[0], remap); + totaltiles += numtiles; + } + } + } + } +} + diff --git a/src/gamedata/textures/formats/buildtexture.cpp b/src/gamedata/textures/formats/buildtexture.cpp deleted file mode 100644 index 1b5be654353..00000000000 --- a/src/gamedata/textures/formats/buildtexture.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* -** buildtexture.cpp -** Handling Build textures (now as a usable editing feature!) -** -**--------------------------------------------------------------------------- -** Copyright 2004-2006 Randy Heit -** Copyright 2018 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "doomtype.h" -#include "files.h" -#include "w_wad.h" -#include "templates.h" -#include "cmdlib.h" -#include "colormatcher.h" -#include "bitmap.h" -#include "textures/textures.h" -#include "r_data/sprites.h" -#include "resourcefiles/resourcefile.h" -#include "image.h" - - -//========================================================================== -// -// A texture defined in a Build TILESxxx.ART file -// -//========================================================================== - -class FBuildTexture : public FImageSource -{ -public: - FBuildTexture (const FString &pathprefix, int tilenum, const uint8_t *pixels, int translation, int width, int height, int left, int top); - TArray CreatePalettedPixels(int conversion) override; - int CopyPixels(FBitmap *bmp, int conversion) override; - -protected: - const uint8_t *RawPixels; - int Translation; -}; - - -//========================================================================== -// -// -// -//========================================================================== - -FBuildTexture::FBuildTexture(const FString &pathprefix, int tilenum, const uint8_t *pixels, int translation, int width, int height, int left, int top) -: RawPixels (pixels), Translation(translation) -{ - Width = width; - Height = height; - LeftOffset = left; - TopOffset = top; -} - -TArray FBuildTexture::CreatePalettedPixels(int conversion) -{ - TArray Pixels(Width * Height, true); - FRemapTable *Remap = translationtables[TRANSLATION_Standard][Translation]; - for (int i = 0; i < Width*Height; i++) - { - auto c = RawPixels[i]; - Pixels[i] = conversion == luminance ? Remap->Palette[c].Luminance() : Remap->Remap[c]; - } - return Pixels; -} - -int FBuildTexture::CopyPixels(FBitmap *bmp, int conversion) -{ - PalEntry *Remap = translationtables[TRANSLATION_Standard][Translation]->Palette; - bmp->CopyPixelData(0, 0, RawPixels, Width, Height, Height, 1, 0, Remap); - return -1; - -} - -//=========================================================================== -// -// AddTiles -// -// Adds all the tiles in an artfile to the texture manager. -// -//=========================================================================== - -void FTextureManager::AddTiles (const FString &pathprefix, const void *tiles, int translation) -{ - -// int numtiles = LittleLong(((uint32_t *)tiles)[1]); // This value is not reliable - int tilestart = LittleLong(((uint32_t *)tiles)[2]); - int tileend = LittleLong(((uint32_t *)tiles)[3]); - const uint16_t *tilesizx = &((const uint16_t *)tiles)[8]; - const uint16_t *tilesizy = &tilesizx[tileend - tilestart + 1]; - const uint32_t *picanm = (const uint32_t *)&tilesizy[tileend - tilestart + 1]; - const uint8_t *tiledata = (const uint8_t *)&picanm[tileend - tilestart + 1]; - - for (int i = tilestart; i <= tileend; ++i) - { - int pic = i - tilestart; - int width = LittleShort(tilesizx[pic]); - int height = LittleShort(tilesizy[pic]); - uint32_t anm = LittleLong(picanm[pic]); - int xoffs = (int8_t)((anm >> 8) & 255) + width/2; - int yoffs = (int8_t)((anm >> 16) & 255) + height/2; - int size = width*height; - FTextureID texnum; - FTexture *tex; - - if (width <= 0 || height <= 0) continue; - - tex = new FImageTexture(new FBuildTexture (pathprefix, i, tiledata, translation, width, height, xoffs, yoffs)); - texnum = AddTexture (tex); - tiledata += size; - tex->Name.Format("%sBTIL%04d", pathprefix.GetChars(), i); - tex->UseType = ETextureType::Override; - - - // reactivate only if the texture counter works here. - //StartScreen->Progress(); - - if ((picanm[pic] & 63) && (picanm[pic] & 192)) - { - int type, speed; - - switch (picanm[pic] & 192) - { - case 64: type = 2; break; - case 128: type = 0; break; - case 192: type = 1; break; - default: type = 0; break; // Won't happen, but GCC bugs me if I don't put this here. - } - - speed = (anm >> 24) & 15; - speed = MAX (1, (1 << speed) * 1000 / 120); // Convert from 120 Hz to 1000 Hz. - - AddSimpleAnim (texnum, picanm[pic] & 63, type, speed); - } - - // Blood's rotation types: - // 0 - Single - // 1 - 5 Full - // 2 - 8 Full - // 3 - Bounce (looks no different from Single; seems to signal bouncy sprites) - // 4 - 5 Half (not used in game) - // 5 - 3 Flat (not used in game) - // 6 - Voxel - // 7 - Spin Voxel - - int rotType = (anm >> 28) & 7; - if (rotType == 1) - { - spriteframe_t rot; - rot.Texture[0] = - rot.Texture[1] = texnum; - for (int j = 1; j < 4; ++j) - { - rot.Texture[j*2] = - rot.Texture[j*2+1] = - rot.Texture[16-j*2] = - rot.Texture[17-j*2] = texnum.GetIndex() + j; - } - rot.Texture[8] = - rot.Texture[9] = texnum.GetIndex() + 4; - rot.Flip = 0x00FC; - rot.Voxel = NULL; - tex->Rotations = SpriteFrames.Push (rot); - } - else if (rotType == 2) - { - spriteframe_t rot; - rot.Texture[0] = - rot.Texture[1] = texnum; - for (int j = 1; j < 8; ++j) - { - rot.Texture[16-j*2] = - rot.Texture[17-j*2] = texnum.GetIndex() + j; - } - rot.Flip = 0; - rot.Voxel = NULL; - tex->Rotations = SpriteFrames.Push (rot); - } - } -} - -//=========================================================================== -// -// CountTiles -// -// Returns the number of tiles provided by an artfile -// -//=========================================================================== - -static int CountTiles (const void *tiles) -{ - int version = LittleLong(*(uint32_t *)tiles); - if (version != 1) - { - return 0; - } - - int tilestart = LittleLong(((uint32_t *)tiles)[2]); - int tileend = LittleLong(((uint32_t *)tiles)[3]); - - return tileend >= tilestart ? tileend - tilestart + 1 : 0; -} - -//=========================================================================== -// -// Create palette data and remap table for the tile set's palette -// -//=========================================================================== - -static int BuildPaletteTranslation(int lump) -{ - if (Wads.LumpLength(lump) < 768) - { - return false; - } - - FMemLump data = Wads.ReadLump(lump); - const uint8_t *ipal = (const uint8_t *)data.GetMem(); - FRemapTable opal; - - bool blood = false; - for (int c = 0; c < 765; c++) // Build used VGA palettes (color values 0..63), Blood used full palettes (0..255) Let's hope this doesn't screw up... - { - if (ipal[c] >= 64) - { - blood = true; - break; - } - } - - for (int c = 0; c < 255; c++) - { - int r, g, b; - if (!blood) - { - r = (ipal[3*c ] << 2) | (ipal[3 * c ] >> 4); - g = (ipal[3*c + 1] << 2) | (ipal[3 * c + 1] >> 4); - b = (ipal[3*c + 2] << 2) | (ipal[3 * c + 2] >> 4); - } - else - { - r = ipal[3 * c] << 2; - g = ipal[3 * c + 1] << 2; - b = ipal[3 * c + 2] << 2; - } - opal.Palette[c] = PalEntry(255, r, g, b); - opal.Remap[c] = ColorMatcher.Pick(r, g, b); - } - // The last entry is transparent. - opal.Palette[255] = 0; - opal.Remap[255] = 0; - // Store the remap table in the translation manager so that we do not need to keep track of it ourselves. - // Slot 0 for internal translations is a convenient location because normally it only contains a small number of translations. - return GetTranslationIndex(opal.StoreTranslation(TRANSLATION_Standard)); -} - - -//=========================================================================== -// -// R_CountBuildTiles -// -// Returns the number of tiles found. Also loads all the data for -// R_InitBuildTiles() to process later. -// -//=========================================================================== - -void FTextureManager::InitBuildTiles() -{ - int lumpnum; - int numtiles; - int totaltiles = 0; - - // The search rules are as follows: - // - scan the entire lump directory for palette.dat files. - // - if one is found, process the directory for .ART files and add textures for them. - // - once all have been found, process all directories that may contain Build data. - // - the root is not excluded which allows to read this from .GRP files as well. - // - Blood support has been removed because it is not useful for modding to have loose .ART files. - // - // Unfortunately neither the palettes nor the .ART files contain any usable identifying marker - // so this can only go by the file names. - - int numlumps = Wads.GetNumLumps(); - for (int i = 0; i < numlumps; i++) - { - const char *name = Wads.GetLumpFullName(i); - if (Wads.CheckNumForFullName(name) != i) continue; // This palette is hidden by a later one. Do not process - FString base = ExtractFileBase(name, true); - base.ToLower(); - if (base.Compare("palette.dat") == 0 && Wads.LumpLength(i) >= 768) // must be a valid palette, i.e. at least 256 colors. - { - FString path = ExtractFilePath(name); - if (path.IsNotEmpty() && path.Back() != '/') path += '/'; - - int translation = BuildPaletteTranslation(i); - for (int numartfiles = 0; numartfiles < 1000; numartfiles++) - { - FStringf artpath("%stiles%03d.art", path.GetChars(), numartfiles); - // only read from the same source as the palette. - // The entire format here is just too volatile to allow liberal mixing. - // An .ART set must be treated as one unit. - lumpnum = Wads.CheckNumForFullName(artpath, Wads.GetLumpFile(i)); - if (lumpnum < 0) - { - break; - } - - BuildTileData.Reserve(1); - auto &artdata = BuildTileData.Last(); - artdata.Resize(Wads.LumpLength(lumpnum)); - Wads.ReadLump(lumpnum, &artdata[0]); - - if ((numtiles = CountTiles(&artdata[0])) > 0) - { - AddTiles(path, &artdata[0], translation); - totaltiles += numtiles; - } - } - } - } -} - diff --git a/src/gamedata/textures/formats/canvastexture.cpp b/src/gamedata/textures/formats/canvastexture.cpp deleted file mode 100644 index d2ddcea959f..00000000000 --- a/src/gamedata/textures/formats/canvastexture.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* -** canvastexture.cpp -** Texture class for camera textures -** -**--------------------------------------------------------------------------- -** Copyright 2004-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "doomtype.h" -#include "v_video.h" - - diff --git a/src/gamedata/textures/formats/fontchars.cpp b/src/gamedata/textures/formats/fontchars.cpp deleted file mode 100644 index 250e34ac57a..00000000000 --- a/src/gamedata/textures/formats/fontchars.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* -** fontchars.cpp -** Texture class for font characters -** -**--------------------------------------------------------------------------- -** Copyright 2004-2006 Randy Heit -** Copyright 2006-2018 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "doomtype.h" -#include "w_wad.h" -#include "v_palette.h" -#include "v_video.h" -#include "bitmap.h" -#include "image.h" -#include "imagehelpers.h" -#include "fontchars.h" -#include "doomerrors.h" - -//========================================================================== -// -// FFontChar1 :: FFontChar1 -// -// Used by fonts made from textures. -// -//========================================================================== - -FFontChar1::FFontChar1 (FImageSource *sourcelump) -: BaseTexture(sourcelump), SourceRemap (nullptr) -{ - // now copy all the properties from the base texture - assert(BaseTexture != nullptr); - CopySize(*BaseTexture); - bUseGamePalette = false; -} - -//========================================================================== -// -// FFontChar1 :: GetPixels -// -// Render style is not relevant for fonts. This must not use it! -// -//========================================================================== - -TArray FFontChar1::CreatePalettedPixels (int) -{ - // Make the texture as normal, then remap it so that all the colors - // are at the low end of the palette - // Why? It only creates unnecessary work! - auto Pixels = BaseTexture->GetPalettedPixels(normal); - - if (SourceRemap) - { - for (int x = 0; x < Width*Height; ++x) - { - Pixels[x] = SourceRemap[Pixels[x]]; - } - } - return Pixels; -} - -//========================================================================== -// -// FFontChar2 :: FFontChar2 -// -// Used by FON1 and FON2 fonts. -// -//========================================================================== - -FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs) -: SourceLump (sourcelump), SourcePos (sourcepos), SourceRemap(nullptr) -{ - Width = width; - Height = height; - LeftOffset = leftofs; - TopOffset = topofs; -} - -//========================================================================== -// -// FFontChar2 :: SetSourceRemap -// -//========================================================================== - -void FFontChar2::SetSourceRemap(const uint8_t *sourceremap) -{ - SourceRemap = sourceremap; -} - -//========================================================================== -// -// FFontChar2 :: Get8BitPixels -// -// Like for FontChar1, the render style has no relevance here as well. -// -//========================================================================== - -TArray FFontChar2::CreatePalettedPixels(int) -{ - auto lump = Wads.OpenLumpReader (SourceLump); - int destSize = Width * Height; - uint8_t max = 255; - bool rle = true; - - // This is to "fix" bad fonts - { - uint8_t buff[16]; - lump.Read (buff, 4); - if (buff[3] == '2') - { - lump.Read (buff, 7); - max = buff[6]; - lump.Seek (SourcePos - 11, FileReader::SeekCur); - } - else if (buff[3] == 0x1A) - { - lump.Read(buff, 13); - max = buff[12] - 1; - lump.Seek (SourcePos - 17, FileReader::SeekCur); - rle = false; - } - else - { - lump.Seek (SourcePos - 4, FileReader::SeekCur); - } - } - - TArray Pixels(destSize, true); - - int runlen = 0, setlen = 0; - uint8_t setval = 0; // Shut up, GCC! - uint8_t *dest_p = Pixels.Data(); - int dest_adv = Height; - int dest_rew = destSize - 1; - - if (rle) - { - for (int y = Height; y != 0; --y) - { - for (int x = Width; x != 0; ) - { - if (runlen != 0) - { - uint8_t color = lump.ReadUInt8(); - color = MIN (color, max); - if (SourceRemap != nullptr) - { - color = SourceRemap[color]; - } - *dest_p = color; - dest_p += dest_adv; - x--; - runlen--; - } - else if (setlen != 0) - { - *dest_p = setval; - dest_p += dest_adv; - x--; - setlen--; - } - else - { - int8_t code = lump.ReadInt8(); - if (code >= 0) - { - runlen = code + 1; - } - else if (code != -128) - { - uint8_t color = lump.ReadUInt8(); - setlen = (-code) + 1; - setval = MIN (color, max); - if (SourceRemap != nullptr) - { - setval = SourceRemap[setval]; - } - } - } - } - dest_p -= dest_rew; - } - } - else - { - for (int y = Height; y != 0; --y) - { - for (int x = Width; x != 0; --x) - { - uint8_t color = lump.ReadUInt8(); - if (color > max) - { - color = max; - } - if (SourceRemap != nullptr) - { - color = SourceRemap[color]; - } - *dest_p = color; - dest_p += dest_adv; - } - dest_p -= dest_rew; - } - } - - if (destSize < 0) - { - char name[9]; - Wads.GetLumpName (name, SourceLump); - name[8] = 0; - I_FatalError ("The font %s is corrupt", name); - } - return Pixels; -} - diff --git a/src/gamedata/textures/formats/fontchars.h b/src/gamedata/textures/formats/fontchars.h deleted file mode 100644 index 341fb9445fd..00000000000 --- a/src/gamedata/textures/formats/fontchars.h +++ /dev/null @@ -1,32 +0,0 @@ - - -// This is a font character that loads a texture and recolors it. -class FFontChar1 : public FImageSource -{ -public: - FFontChar1 (FImageSource *sourcelump); - TArray CreatePalettedPixels(int conversion) override; - void SetSourceRemap(const uint8_t *sourceremap) { SourceRemap = sourceremap; } - const uint8_t *ResetSourceRemap() { auto p = SourceRemap; SourceRemap = nullptr; return p; } - FImageSource *GetBase() const { return BaseTexture; } - -protected: - - FImageSource *BaseTexture; - const uint8_t *SourceRemap; -}; - -// This is a font character that reads RLE compressed data. -class FFontChar2 : public FImageSource -{ -public: - FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0); - - TArray CreatePalettedPixels(int conversion) override; - void SetSourceRemap(const uint8_t *sourceremap); - -protected: - int SourceLump; - int SourcePos; - const uint8_t *SourceRemap; -}; diff --git a/src/gamedata/textures/formats/jpegtexture.cpp b/src/gamedata/textures/formats/jpegtexture.cpp deleted file mode 100644 index 68ead4a7d05..00000000000 --- a/src/gamedata/textures/formats/jpegtexture.cpp +++ /dev/null @@ -1,462 +0,0 @@ -/* -** jpegtexture.cpp -** Texture class for JPEG images -** -**--------------------------------------------------------------------------- -** Copyright 2006-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include -extern "C" -{ -#include -} - -#include "doomtype.h" -#include "files.h" -#include "w_wad.h" -#include "v_text.h" -#include "bitmap.h" -#include "v_video.h" -#include "imagehelpers.h" -#include "image.h" - - -struct FLumpSourceMgr : public jpeg_source_mgr -{ - FileReader *Lump; - JOCTET Buffer[4096]; - bool StartOfFile; - - FLumpSourceMgr (FileReader *lump, j_decompress_ptr cinfo); - static void InitSource (j_decompress_ptr cinfo); - static boolean FillInputBuffer (j_decompress_ptr cinfo); - static void SkipInputData (j_decompress_ptr cinfo, long num_bytes); - static void TermSource (j_decompress_ptr cinfo); -}; - - -//========================================================================== -// -// -// -//========================================================================== - -void FLumpSourceMgr::InitSource (j_decompress_ptr cinfo) -{ - ((FLumpSourceMgr *)(cinfo->src))->StartOfFile = true; -} - -//========================================================================== -// -// -// -//========================================================================== - -boolean FLumpSourceMgr::FillInputBuffer (j_decompress_ptr cinfo) -{ - FLumpSourceMgr *me = (FLumpSourceMgr *)(cinfo->src); - auto nbytes = me->Lump->Read (me->Buffer, sizeof(me->Buffer)); - - if (nbytes <= 0) - { - me->Buffer[0] = (JOCTET)0xFF; - me->Buffer[1] = (JOCTET)JPEG_EOI; - nbytes = 2; - } - me->next_input_byte = me->Buffer; - me->bytes_in_buffer = nbytes; - me->StartOfFile = false; - return TRUE; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FLumpSourceMgr::SkipInputData (j_decompress_ptr cinfo, long num_bytes) -{ - FLumpSourceMgr *me = (FLumpSourceMgr *)(cinfo->src); - if (num_bytes <= (long)me->bytes_in_buffer) - { - me->bytes_in_buffer -= num_bytes; - me->next_input_byte += num_bytes; - } - else - { - num_bytes -= (long)me->bytes_in_buffer; - me->Lump->Seek (num_bytes, FileReader::SeekCur); - FillInputBuffer (cinfo); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FLumpSourceMgr::TermSource (j_decompress_ptr cinfo) -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -FLumpSourceMgr::FLumpSourceMgr (FileReader *lump, j_decompress_ptr cinfo) -: Lump (lump) -{ - cinfo->src = this; - init_source = InitSource; - fill_input_buffer = FillInputBuffer; - skip_input_data = SkipInputData; - resync_to_restart = jpeg_resync_to_restart; - term_source = TermSource; - bytes_in_buffer = 0; - next_input_byte = NULL; -} - -//========================================================================== -// -// -// -//========================================================================== - -void JPEG_ErrorExit (j_common_ptr cinfo) -{ - (*cinfo->err->output_message) (cinfo); - throw -1; -} - -//========================================================================== -// -// -// -//========================================================================== - -void JPEG_OutputMessage (j_common_ptr cinfo) -{ - char buffer[JMSG_LENGTH_MAX]; - - (*cinfo->err->format_message) (cinfo, buffer); - Printf (TEXTCOLOR_ORANGE "JPEG failure: %s\n", buffer); -} - -//========================================================================== -// -// A JPEG texture -// -//========================================================================== - -class FJPEGTexture : public FImageSource -{ -public: - FJPEGTexture (int lumpnum, int width, int height); - - int CopyPixels(FBitmap *bmp, int conversion) override; - TArray CreatePalettedPixels(int conversion) override; -}; - -//========================================================================== -// -// -// -//========================================================================== - -FImageSource *JPEGImage_TryCreate(FileReader & data, int lumpnum) -{ - union - { - uint32_t dw; - uint16_t w[2]; - uint8_t b[4]; - } first4bytes; - - data.Seek(0, FileReader::SeekSet); - if (data.Read(&first4bytes, 4) < 4) return NULL; - - if (first4bytes.b[0] != 0xFF || first4bytes.b[1] != 0xD8 || first4bytes.b[2] != 0xFF) - return NULL; - - // Find the SOFn marker to extract the image dimensions, - // where n is 0, 1, or 2 (other types are unsupported). - while ((unsigned)first4bytes.b[3] - 0xC0 >= 3) - { - if (data.Read (first4bytes.w, 2) != 2) - { - return NULL; - } - data.Seek (BigShort(first4bytes.w[0]) - 2, FileReader::SeekCur); - if (data.Read (first4bytes.b + 2, 2) != 2 || first4bytes.b[2] != 0xFF) - { - return NULL; - } - } - if (data.Read (first4bytes.b, 3) != 3) - { - return NULL; - } - if (BigShort (first4bytes.w[0]) < 5) - { - return NULL; - } - if (data.Read (first4bytes.b, 4) != 4) - { - return NULL; - } - return new FJPEGTexture (lumpnum, BigShort(first4bytes.w[1]), BigShort(first4bytes.w[0])); -} - -//========================================================================== -// -// -// -//========================================================================== - -FJPEGTexture::FJPEGTexture (int lumpnum, int width, int height) -: FImageSource(lumpnum) -{ - bMasked = false; - - Width = width; - Height = height; -} - -//========================================================================== -// -// -// -//========================================================================== - -TArray FJPEGTexture::CreatePalettedPixels(int conversion) -{ - auto lump = Wads.OpenLumpReader (SourceLump); - JSAMPLE *buff = NULL; - - jpeg_decompress_struct cinfo; - jpeg_error_mgr jerr; - - TArray Pixels(Width * Height, true); - memset (Pixels.Data(), 0xBA, Width * Height); - - cinfo.err = jpeg_std_error(&jerr); - cinfo.err->output_message = JPEG_OutputMessage; - cinfo.err->error_exit = JPEG_ErrorExit; - jpeg_create_decompress(&cinfo); - - FLumpSourceMgr sourcemgr(&lump, &cinfo); - try - { - bool doalpha = conversion == luminance; - jpeg_read_header(&cinfo, TRUE); - if (!((cinfo.out_color_space == JCS_RGB && cinfo.num_components == 3) || - (cinfo.out_color_space == JCS_CMYK && cinfo.num_components == 4) || - (cinfo.out_color_space == JCS_YCbCr && cinfo.num_components == 3) || - (cinfo.out_color_space == JCS_GRAYSCALE && cinfo.num_components == 1))) - { - Printf(TEXTCOLOR_ORANGE "Unsupported color format in %s\n", Wads.GetLumpFullPath(SourceLump).GetChars()); - } - else - { - jpeg_start_decompress(&cinfo); - - int y = 0; - buff = new uint8_t[cinfo.output_width * cinfo.output_components]; - - while (cinfo.output_scanline < cinfo.output_height) - { - int num_scanlines = jpeg_read_scanlines(&cinfo, &buff, 1); - uint8_t *in = buff; - uint8_t *out = Pixels.Data() + y; - switch (cinfo.out_color_space) - { - case JCS_RGB: - for (int x = Width; x > 0; --x) - { - *out = ImageHelpers::RGBToPalette(doalpha, in[0], in[1], in[2]); - out += Height; - in += 3; - } - break; - - case JCS_GRAYSCALE: - { - auto remap = ImageHelpers::GetRemap(doalpha, true); - for (int x = Width; x > 0; --x) - { - *out = remap[in[0]]; - out += Height; - in += 1; - } - break; - } - case JCS_CMYK: - // What are you doing using a CMYK image? :) - for (int x = Width; x > 0; --x) - { - // To be precise, these calculations should use 255, but - // 256 is much faster and virtually indistinguishable. - int r = in[3] - (((256 - in[0])*in[3]) >> 8); - int g = in[3] - (((256 - in[1])*in[3]) >> 8); - int b = in[3] - (((256 - in[2])*in[3]) >> 8); - *out = ImageHelpers::RGBToPalette(doalpha, r, g, b); - out += Height; - in += 4; - } - break; - - case JCS_YCbCr: - // Probably useless but since I had the formula available... - for (int x = Width; x > 0; --x) - { - double Y = in[0], Cb = in[1], Cr = in[2]; - int r = clamp((int)(Y + 1.40200 * (Cr - 0x80)), 0, 255); - int g = clamp((int)(Y - 0.34414 * (Cb - 0x80) - 0.71414 * (Cr - 0x80)), 0, 255); - int b = clamp((int)(Y + 1.77200 * (Cb - 0x80)), 0, 255); - *out = ImageHelpers::RGBToPalette(doalpha, r, g, b); - out += Height; - in += 4; - } - break; - - default: - // The other colorspaces were considered above and discarded, - // but GCC will complain without a default for them here. - break; - } - y++; - } - jpeg_finish_decompress(&cinfo); - } - } - catch (int) - { - Printf(TEXTCOLOR_ORANGE "JPEG error in %s\n", Wads.GetLumpFullPath(SourceLump).GetChars()); - } - jpeg_destroy_decompress(&cinfo); - if (buff != NULL) - { - delete[] buff; - } - return Pixels; -} - - -//=========================================================================== -// -// FJPEGTexture::CopyPixels -// -// Preserves the full color information (unlike software mode) -// -//=========================================================================== - -int FJPEGTexture::CopyPixels(FBitmap *bmp, int conversion) -{ - PalEntry pe[256]; - - auto lump = Wads.OpenLumpReader (SourceLump); - - jpeg_decompress_struct cinfo; - jpeg_error_mgr jerr; - - cinfo.err = jpeg_std_error(&jerr); - cinfo.err->output_message = JPEG_OutputMessage; - cinfo.err->error_exit = JPEG_ErrorExit; - jpeg_create_decompress(&cinfo); - - FLumpSourceMgr sourcemgr(&lump, &cinfo); - try - { - jpeg_read_header(&cinfo, TRUE); - - if (!((cinfo.out_color_space == JCS_RGB && cinfo.num_components == 3) || - (cinfo.out_color_space == JCS_CMYK && cinfo.num_components == 4) || - (cinfo.out_color_space == JCS_YCbCr && cinfo.num_components == 3) || - (cinfo.out_color_space == JCS_GRAYSCALE && cinfo.num_components == 1))) - { - Printf(TEXTCOLOR_ORANGE "Unsupported color format in %s\n", Wads.GetLumpFullPath(SourceLump).GetChars()); - } - else - { - jpeg_start_decompress(&cinfo); - - int yc = 0; - TArray buff(cinfo.output_height * cinfo.output_width * cinfo.output_components, true); - - while (cinfo.output_scanline < cinfo.output_height) - { - uint8_t * ptr = buff.Data() + cinfo.output_width * cinfo.output_components * yc; - jpeg_read_scanlines(&cinfo, &ptr, 1); - yc++; - } - - switch (cinfo.out_color_space) - { - case JCS_RGB: - bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height, - 3, cinfo.output_width * cinfo.output_components, 0, CF_RGB); - break; - - case JCS_GRAYSCALE: - for (int i = 0; i < 256; i++) pe[i] = PalEntry(255, i, i, i); // default to a gray map - bmp->CopyPixelData(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height, - 1, cinfo.output_width, 0, pe); - break; - - case JCS_CMYK: - bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height, - 4, cinfo.output_width * cinfo.output_components, 0, CF_CMYK); - break; - - case JCS_YCbCr: - bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height, - 4, cinfo.output_width * cinfo.output_components, 0, CF_YCbCr); - break; - - default: - assert(0); - break; - } - jpeg_finish_decompress(&cinfo); - } - } - catch (int) - { - Printf(TEXTCOLOR_ORANGE "JPEG error in %s\n", Wads.GetLumpFullPath(SourceLump).GetChars()); - } - jpeg_destroy_decompress(&cinfo); - return 0; -} - diff --git a/src/gamedata/textures/formats/multipatchtexture.h b/src/gamedata/textures/formats/multipatchtexture.h deleted file mode 100644 index 8994cf4ce92..00000000000 --- a/src/gamedata/textures/formats/multipatchtexture.h +++ /dev/null @@ -1,138 +0,0 @@ -#pragma once -#include "sc_man.h" - -//========================================================================== -// -// TexPart is the data that will get passed to the final texture. -// -//========================================================================== - -struct TexPart -{ - FRemapTable *Translation = nullptr; - FImageSource *Image = nullptr; - PalEntry Blend = 0; - blend_t Alpha = FRACUNIT; - int16_t OriginX = 0; - int16_t OriginY = 0; - uint8_t Rotate = 0; - uint8_t op = OP_COPY; -}; - - - -//========================================================================== -// -// A texture defined in a TEXTURE1 or TEXTURE2 lump -// -//========================================================================== - -class FMultiPatchTexture : public FImageSource -{ - friend class FTexture; -public: - FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual); - -protected: - int NumParts; - bool bComplex; - bool bTextual; - TexPart *Parts; - - // The getters must optionally redirect if it's a simple one-patch texture. - int CopyPixels(FBitmap *bmp, int conversion) override; - TArray CreatePalettedPixels(int conversion) override; - void CopyToBlock(uint8_t *dest, int dwidth, int dheight, FImageSource *source, int xpos, int ypos, int rotate, const uint8_t *translation, int style); - void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor); - -}; - - -//========================================================================== -// -// Additional data per patch which is needed for initialization -// -//========================================================================== - -struct TexInit -{ - FString TexName; - ETextureType UseType = ETextureType::Null; - FTexture *Texture = nullptr; - bool Silent = false; - bool HasLine = false; - bool UseOffsets = false; - FScriptPosition sc; -}; - -//========================================================================== -// -// All build info only needed to construct the multipatch textures -// -//========================================================================== - -struct FPatchLookup; - -struct BuildInfo -{ - FString Name; - TArray Parts; - TArray Inits; - int Width = 0; - int Height = 0; - DVector2 Scale = { 1, 1 }; - bool bWorldPanning = false; // This sucks! - int DefinitionLump = 0; - bool bComplex = false; - bool textual = false; - bool bNoDecals = false; - int LeftOffset[2] = {}; - int TopOffset[2] = {}; - FImageTexture *tex = nullptr; - - void swap(BuildInfo &other) - { - Name.Swap(other.Name); - Parts.Swap(other.Parts); - Inits.Swap(other.Inits); - std::swap(Width, other.Width); - std::swap(Height, other.Height); - std::swap(Scale, other.Scale); - std::swap(bWorldPanning, other.bWorldPanning); - std::swap(DefinitionLump, other.DefinitionLump); - std::swap(bComplex, other.bComplex); - std::swap(textual, other.textual); - std::swap(bNoDecals, other.bNoDecals); - std::swap(LeftOffset[0], other.LeftOffset[0]); - std::swap(LeftOffset[1], other.LeftOffset[1]); - std::swap(TopOffset[0], other.TopOffset[0]); - std::swap(TopOffset[1], other.TopOffset[1]); - std::swap(tex, other.tex); - } -}; - - - -class FMultipatchTextureBuilder -{ - FTextureManager &TexMan; - TArray BuiltTextures; - - void MakeTexture(BuildInfo &buildinfo, ETextureType usetype); - - void BuildTexture(const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum, ETextureType usetyoe); - void AddTexturesLump(const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup, bool texture1); - - void ParsePatch(FScanner &sc, BuildInfo &info, TexPart &part, TexInit &init); - void CheckForHacks(BuildInfo &buildinfo); - void ResolvePatches(BuildInfo &buildinfo); - -public: - FMultipatchTextureBuilder(FTextureManager &texMan) : TexMan(texMan) - { - } - - void AddTexturesLumps(int lump1, int lump2, int patcheslump); - void ParseTexture(FScanner &sc, ETextureType usetype); - void ResolveAllPatches(); -}; diff --git a/src/gamedata/textures/image.cpp b/src/gamedata/textures/image.cpp deleted file mode 100644 index 9c524c56be3..00000000000 --- a/src/gamedata/textures/image.cpp +++ /dev/null @@ -1,390 +0,0 @@ -/* -** texture.cpp -** The base texture class -** -**--------------------------------------------------------------------------- -** Copyright 2004-2007 Randy Heit -** Copyright 2006-2018 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "v_video.h" -#include "bitmap.h" -#include "image.h" -#include "w_wad.h" -#include "files.h" - -FMemArena FImageSource::ImageArena(32768); -TArrayFImageSource::ImageForLump; -int FImageSource::NextID; -static PrecacheInfo precacheInfo; - -struct PrecacheDataPaletted -{ - TArray Pixels; - int RefCount; - int ImageID; -}; - -struct PrecacheDataRgba -{ - FBitmap Pixels; - int TransInfo; - int RefCount; - int ImageID; -}; - -// TMap doesn't handle this kind of data well. std::map neither. The linear search is still faster, even for a few 100 entries because it doesn't have to access the heap as often.. -TArray precacheDataPaletted; -TArray precacheDataRgba; - -//=========================================================================== -// -// the default just returns an empty texture. -// -//=========================================================================== - -TArray FImageSource::CreatePalettedPixels(int conversion) -{ - TArray Pixels(Width * Height, true); - memset(Pixels.Data(), 0, Width * Height); - return Pixels; -} - -PalettedPixels FImageSource::GetCachedPalettedPixels(int conversion) -{ - PalettedPixels ret; - - FString name; - Wads.GetLumpName(name, SourceLump); - - std::pair *info = nullptr; - auto imageID = ImageID; - - // Do we have this image in the cache? - unsigned index = conversion != normal? UINT_MAX : precacheDataPaletted.FindEx([=](PrecacheDataPaletted &entry) { return entry.ImageID == imageID; }); - if (index < precacheDataPaletted.Size()) - { - auto cache = &precacheDataPaletted[index]; - - if (cache->RefCount > 1) - { - //Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount); - ret.Pixels.Set(cache->Pixels.Data(), cache->Pixels.Size()); - cache->RefCount--; - } - else if (cache->Pixels.Size() > 0) - { - //Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount); - ret.PixelStore = std::move(cache->Pixels); - ret.Pixels.Set(ret.PixelStore.Data(), ret.PixelStore.Size()); - precacheDataPaletted.Delete(index); - } - else - { - //Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount); - } - } - else - { - // The image wasn't cached. Now there's two possibilities: - auto info = precacheInfo.CheckKey(ImageID); - if (!info || info->second <= 1 || conversion != normal) - { - // This is either the only copy needed or some access outside the caching block. In these cases create a new one and directly return it. - //Printf("returning fresh copy of %s\n", name.GetChars()); - ret.PixelStore = CreatePalettedPixels(conversion); - ret.Pixels.Set(ret.PixelStore.Data(), ret.PixelStore.Size()); - } - else - { - //Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->second); - // This is the first time it gets accessed and needs to be placed in the cache. - PrecacheDataPaletted *pdp = &precacheDataPaletted[precacheDataPaletted.Reserve(1)]; - - pdp->ImageID = imageID; - pdp->RefCount = info->second - 1; - info->second = 0; - pdp->Pixels = CreatePalettedPixels(normal); - ret.Pixels.Set(pdp->Pixels.Data(), pdp->Pixels.Size()); - } - } - return ret; -} - -TArray FImageSource::GetPalettedPixels(int conversion) -{ - auto pix = GetCachedPalettedPixels(conversion); - if (pix.ownsPixels()) - { - // return the pixel store of the returned data directly if this was the last reference. - auto array = std::move(pix.PixelStore); - return array; - } - else - { - // If there are pending references, make a copy. - TArray array(pix.Pixels.Size(), true); - memcpy(array.Data(), pix.Pixels.Data(), array.Size()); - return array; - } -} - - - -//=========================================================================== -// -// FImageSource::CopyPixels -// -// this is the generic case that can handle -// any properly implemented texture for software rendering. -// Its drawback is that it is limited to the base palette which is -// why all classes that handle different palettes should subclass this -// method -// -//=========================================================================== - -int FImageSource::CopyPixels(FBitmap *bmp, int conversion) -{ - if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source. - PalEntry *palette = GPalette.BaseColors; - for(int i=1;i<256;i++) palette[i].a = 255; // set proper alpha values - auto ppix = CreatePalettedPixels(conversion); - bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr); - for(int i=1;i<256;i++) palette[i].a = 0; - return 0; -} - -int FImageSource::CopyTranslatedPixels(FBitmap *bmp, PalEntry *remap) -{ - auto ppix = CreatePalettedPixels(false); - bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, remap, nullptr); - return 0; -} - -//========================================================================== -// -// -// -//========================================================================== - -FBitmap FImageSource::GetCachedBitmap(PalEntry *remap, int conversion, int *ptrans) -{ - FBitmap ret; - - FString name; - int trans = -1; - Wads.GetLumpName(name, SourceLump); - - std::pair *info = nullptr; - auto imageID = ImageID; - - if (remap != nullptr) - { - // Remapped images are never run through the cache because they would complicate matters too much for very little gain. - // Translated images are normally sprites which normally just consist of a single image and use no composition. - // Additionally, since translation requires the base palette, the really time consuming stuff will never be subjected to it. - ret.Create(Width, Height); - trans = CopyTranslatedPixels(&ret, remap); - } - else - { - if (conversion == luminance) conversion = normal; // luminance has no meaning for true color. - // Do we have this image in the cache? - unsigned index = conversion != normal? UINT_MAX : precacheDataRgba.FindEx([=](PrecacheDataRgba &entry) { return entry.ImageID == imageID; }); - if (index < precacheDataRgba.Size()) - { - auto cache = &precacheDataRgba[index]; - - trans = cache->TransInfo; - if (cache->RefCount > 1) - { - //Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount); - ret.Copy(cache->Pixels, false); - cache->RefCount--; - } - else if (cache->Pixels.GetPixels()) - { - //Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount); - ret = std::move(cache->Pixels); - precacheDataRgba.Delete(index); - } - else - { - // This should never happen if the function is implemented correctly - //Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount); - ret.Create(Width, Height); - trans = CopyPixels(&ret, normal); - } - } - else - { - // The image wasn't cached. Now there's two possibilities: - auto info = precacheInfo.CheckKey(ImageID); - if (!info || info->first <= 1 || conversion != normal) - { - // This is either the only copy needed or some access outside the caching block. In these cases create a new one and directly return it. - //Printf("returning fresh copy of %s\n", name.GetChars()); - ret.Create(Width, Height); - trans = CopyPixels(&ret, conversion); - } - else - { - //Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->first); - // This is the first time it gets accessed and needs to be placed in the cache. - PrecacheDataRgba *pdr = &precacheDataRgba[precacheDataRgba.Reserve(1)]; - - pdr->ImageID = imageID; - pdr->RefCount = info->first - 1; - info->first = 0; - pdr->Pixels.Create(Width, Height); - trans = pdr->TransInfo = CopyPixels(&pdr->Pixels, normal); - ret.Copy(pdr->Pixels, false); - } - } - } - if (ptrans) *ptrans = trans; - return ret; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FImageSource::CollectForPrecache(PrecacheInfo &info, bool requiretruecolor) -{ - auto val = info.CheckKey(ImageID); - bool tc = requiretruecolor || V_IsTrueColor(); - if (val) - { - val->first += tc; - val->second += !tc; - } - else - { - auto pair = std::make_pair(tc, !tc); - info.Insert(ImageID, pair); - } -} - -void FImageSource::BeginPrecaching() -{ - precacheInfo.Clear(); -} - -void FImageSource::EndPrecaching() -{ - precacheDataPaletted.Clear(); - precacheDataRgba.Clear(); -} - -void FImageSource::RegisterForPrecache(FImageSource *img) -{ - img->CollectForPrecache(precacheInfo); -} - -//========================================================================== -// -// -// -//========================================================================== - -typedef FImageSource * (*CreateFunc)(FileReader & file, int lumpnum); - -struct TexCreateInfo -{ - CreateFunc TryCreate; - ETextureType usetype; -}; - -FImageSource *IMGZImage_TryCreate(FileReader &, int lumpnum); -FImageSource *PNGImage_TryCreate(FileReader &, int lumpnum); -FImageSource *JPEGImage_TryCreate(FileReader &, int lumpnum); -FImageSource *DDSImage_TryCreate(FileReader &, int lumpnum); -FImageSource *PCXImage_TryCreate(FileReader &, int lumpnum); -FImageSource *TGAImage_TryCreate(FileReader &, int lumpnum); -FImageSource *StbImage_TryCreate(FileReader &, int lumpnum); -FImageSource *RawPageImage_TryCreate(FileReader &, int lumpnum); -FImageSource *FlatImage_TryCreate(FileReader &, int lumpnum); -FImageSource *PatchImage_TryCreate(FileReader &, int lumpnum); -FImageSource *EmptyImage_TryCreate(FileReader &, int lumpnum); -FImageSource *AutomapImage_TryCreate(FileReader &, int lumpnum); - - -// Examines the lump contents to decide what type of texture to create, -// and creates the texture. -FImageSource * FImageSource::GetImage(int lumpnum, ETextureType usetype) -{ - static TexCreateInfo CreateInfo[] = { - { IMGZImage_TryCreate, ETextureType::Any }, - { PNGImage_TryCreate, ETextureType::Any }, - { JPEGImage_TryCreate, ETextureType::Any }, - { DDSImage_TryCreate, ETextureType::Any }, - { PCXImage_TryCreate, ETextureType::Any }, - { StbImage_TryCreate, ETextureType::Any }, - { TGAImage_TryCreate, ETextureType::Any }, - { RawPageImage_TryCreate, ETextureType::MiscPatch }, - { FlatImage_TryCreate, ETextureType::Flat }, - { PatchImage_TryCreate, ETextureType::Any }, - { EmptyImage_TryCreate, ETextureType::Any }, - { AutomapImage_TryCreate, ETextureType::MiscPatch }, - }; - - if (lumpnum == -1) return nullptr; - - unsigned size = ImageForLump.Size(); - if (size <= (unsigned)lumpnum) - { - // Hires textures can be added dynamically to the end of the lump array, so this must be checked each time. - ImageForLump.Resize(lumpnum + 1); - for (; size < ImageForLump.Size(); size++) ImageForLump[size] = nullptr; - } - // An image for this lump already exists. We do not need another one. - if (ImageForLump[lumpnum] != nullptr) return ImageForLump[lumpnum]; - - auto data = Wads.OpenLumpReader(lumpnum); - if (!data.isOpen()) - return nullptr; - - for (size_t i = 0; i < countof(CreateInfo); i++) - { - if ((CreateInfo[i].usetype == usetype || CreateInfo[i].usetype == ETextureType::Any)) - { - auto image = CreateInfo[i].TryCreate(data, lumpnum); - if (image != nullptr) - { - ImageForLump[lumpnum] = image; - return image; - } - } - } - return nullptr; -} diff --git a/src/gamedata/textures/image.h b/src/gamedata/textures/image.h deleted file mode 100644 index 75efc56e4dc..00000000000 --- a/src/gamedata/textures/image.h +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -#include -#include "tarray.h" -#include "textures/bitmap.h" -#include "memarena.h" - -class FImageSource; -using PrecacheInfo = TMap>; - -struct PalettedPixels -{ - friend class FImageSource; - TArrayView Pixels; -private: - TArray PixelStore; - - bool ownsPixels() const - { - return Pixels.Data() == PixelStore.Data(); - } -}; - -// This represents a naked image. It has no high level logic attached to it. -// All it can do is provide raw image data to its users. -class FImageSource -{ - friend class FBrightmapTexture; -protected: - - static FMemArena ImageArena; - static TArrayImageForLump; - static int NextID; - - int SourceLump; - int Width = 0, Height = 0; - int LeftOffset = 0, TopOffset = 0; // Offsets stored in the image. - bool bUseGamePalette = false; // true if this is an image without its own color set. - int ImageID = -1; - - // Internal image creation functions. All external access should go through the cache interface, - // so that all code can benefit from future improvements to that. - - virtual TArray CreatePalettedPixels(int conversion); - virtual int CopyPixels(FBitmap *bmp, int conversion); // This will always ignore 'luminance'. - int CopyTranslatedPixels(FBitmap *bmp, PalEntry *remap); - - -public: - - void CopySize(FImageSource &other) - { - Width = other.Width; - Height = other.Height; - LeftOffset = other.LeftOffset; - TopOffset = other.TopOffset; - SourceLump = other.SourceLump; - } - - // Images are statically allocated and freed in bulk. None of the subclasses may hold any destructible data. - void *operator new(size_t block) { return ImageArena.Alloc(block); } - void operator delete(void *block) {} - - bool bMasked = true; // Image (might) have holes (Assume true unless proven otherwise!) - int8_t bTranslucent = -1; // Image has pixels with a non-0/1 value. (-1 means the user needs to do a real check) - - int GetId() const { return ImageID; } - - // 'noremap0' will only be looked at by FPatchTexture and forwarded by FMultipatchTexture. - - // Either returns a reference to the cache, or a newly created item. The return of this has to be considered transient. If you need to store the result, use GetPalettedPixels - PalettedPixels GetCachedPalettedPixels(int conversion); - - // tries to get a buffer from the cache. If not available, create a new one. If further references are pending, create a copy. - TArray GetPalettedPixels(int conversion); - - - // Unlile for paletted images there is no variant here that returns a persistent bitmap, because all users have to process the returned image into another format. - FBitmap GetCachedBitmap(PalEntry *remap, int conversion, int *trans = nullptr); - - static void ClearImages() { ImageArena.FreeAll(); ImageForLump.Clear(); NextID = 0; } - static FImageSource * GetImage(int lumpnum, ETextureType usetype); - - - - // Conversion option - enum EType - { - normal = 0, - luminance = 1, - noremap0 = 2 - }; - - FImageSource(int sourcelump = -1) : SourceLump(sourcelump) { ImageID = ++NextID; } - virtual ~FImageSource() {} - - int GetWidth() const - { - return Width; - } - - int GetHeight() const - { - return Height; - } - - std::pair GetSize() const - { - return std::make_pair(Width, Height); - } - - std::pair GetOffsets() const - { - return std::make_pair(LeftOffset, TopOffset); - } - - void SetOffsets(int x, int y) - { - LeftOffset = x; - TopOffset = y; - } - - int LumpNum() const - { - return SourceLump; - } - - bool UseGamePalette() const - { - return bUseGamePalette; - } - - virtual void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor = false); - static void BeginPrecaching(); - static void EndPrecaching(); - static void RegisterForPrecache(FImageSource *img); -}; - -//========================================================================== -// -// a TGA texture -// -//========================================================================== - -class FImageTexture : public FTexture -{ - FImageSource *mImage; -public: - FImageTexture (FImageSource *image, const char *name = nullptr); - virtual TArray Get8BitPixels(bool alphatex); - - void SetImage(FImageSource *img) // This is only for the multipatch texture builder! - { - mImage = img; - } - - FImageSource *GetImage() const override { return mImage; } - FBitmap GetBgraBitmap(PalEntry *p, int *trans) override; - -}; - diff --git a/src/gamedata/textures/imagetexture.cpp b/src/gamedata/textures/imagetexture.cpp deleted file mode 100644 index 43adee19a26..00000000000 --- a/src/gamedata/textures/imagetexture.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* -** imagetexture.cpp -** Texture class based on FImageSource -** -**--------------------------------------------------------------------------- -** Copyright 2018 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "doomtype.h" -#include "files.h" -#include "w_wad.h" -#include "templates.h" -#include "bitmap.h" -#include "v_video.h" -#include "image.h" - - -//========================================================================== -// -// -// -//========================================================================== - -FImageTexture::FImageTexture(FImageSource *img, const char *name) -: FTexture(name, img? img->LumpNum() : 0) -{ - mImage = img; - if (img != nullptr) - { - if (name == nullptr) Wads.GetLumpName(Name, img->LumpNum()); - Width = img->GetWidth(); - Height = img->GetHeight(); - - auto offsets = img->GetOffsets(); - _LeftOffset[1] = _LeftOffset[0] = offsets.first; - _TopOffset[1] = _TopOffset[0] = offsets.second; - - bMasked = img->bMasked; - bTranslucent = img->bTranslucent; - } -} - -//=========================================================================== -// -// -// -//=========================================================================== - -FBitmap FImageTexture::GetBgraBitmap(PalEntry *p, int *trans) -{ - return mImage->GetCachedBitmap(p, bNoRemap0? FImageSource::noremap0 : FImageSource::normal, trans); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -TArray FImageTexture::Get8BitPixels(bool alpha) -{ - return mImage->GetPalettedPixels(alpha? alpha : bNoRemap0 ? FImageSource::noremap0 : FImageSource::normal); -} - -//========================================================================== -// -// FMultiPatchTexture :: GetRawTexture -// -// Doom ignored all compositing of mid-sided textures on two-sided lines. -// Since these textures had to be single-patch in Doom, that essentially -// means it ignores their Y offsets. -// -// If this texture is composed of only one patch, return that patch. -// Otherwise, return this texture, since Doom wouldn't have been able to -// draw it anyway. -// -//========================================================================== - -/* todo: this needs to be reimplemented without assuming that the underlying patch will be usable as-is. -FTexture *FMultiPatchTexture::GetRawTexture() -{ - return NumParts == 1 && UseType == ETextureType::Wall && bMultiPatch == 1 && Scale == Parts->Texture->Scale ? Parts->Texture : this; -} -*/ - diff --git a/src/gamedata/textures/skyboxtexture.cpp b/src/gamedata/textures/skyboxtexture.cpp deleted file mode 100644 index 45e79bf74df..00000000000 --- a/src/gamedata/textures/skyboxtexture.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2004-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#include "doomtype.h" -#include "w_wad.h" -#include "textures.h" -#include "skyboxtexture.h" -#include "bitmap.h" - - - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -FSkyBox::FSkyBox(const char *name) -: FTexture(name) -{ - FTextureID texid = TexMan.CheckForTexture(name, ETextureType::Wall); - previous = nullptr; - if (texid.isValid()) - { - previous = TexMan.GetTexture(texid); - CopySize(previous); - } - faces[0]=faces[1]=faces[2]=faces[3]=faces[4]=faces[5] = nullptr; - UseType = ETextureType::Override; - bSkybox = true; - fliptop = false; -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -TArray FSkyBox::Get8BitPixels(bool alphatex) -{ - return previous->Get8BitPixels(alphatex); -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -FBitmap FSkyBox::GetBgraBitmap(PalEntry *p, int *trans) -{ - return previous->GetBgraBitmap(p, trans); -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -FImageSource *FSkyBox::GetImage() const -{ - return previous->GetImage(); -} diff --git a/src/gamedata/textures/skyboxtexture.h b/src/gamedata/textures/skyboxtexture.h deleted file mode 100644 index 2288a40942b..00000000000 --- a/src/gamedata/textures/skyboxtexture.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "textures.h" -//----------------------------------------------------------------------------- -// -// This is not a real texture but will be added to the texture manager -// so that it can be handled like any other sky. -// -//----------------------------------------------------------------------------- - -class FSkyBox : public FTexture -{ -public: - - FTexture *previous; - FTexture * faces[6]; - bool fliptop; - - FSkyBox(const char *name); - TArray Get8BitPixels(bool alphatex); - FBitmap GetBgraBitmap(PalEntry *, int *trans) override; - FImageSource *GetImage() const override; - - - void SetSize() - { - if (!previous && faces[0]) previous = faces[0]; - if (previous) - { - CopySize(previous); - } - } - - bool Is3Face() const - { - return faces[5] == nullptr; - } - - bool IsFlipped() const - { - return fliptop; - } -}; diff --git a/src/gamedata/textures/texture.cpp b/src/gamedata/textures/texture.cpp deleted file mode 100644 index 2506744f06f..00000000000 --- a/src/gamedata/textures/texture.cpp +++ /dev/null @@ -1,915 +0,0 @@ -/* -** texture.cpp -** The base texture class -** -**--------------------------------------------------------------------------- -** Copyright 2004-2007 Randy Heit -** Copyright 2006-2018 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "doomtype.h" -#include "files.h" -#include "w_wad.h" -#include "templates.h" - -#include "r_data/r_translate.h" -#include "bitmap.h" -#include "colormatcher.h" -#include "c_dispatch.h" -#include "v_video.h" -#include "m_fixed.h" -#include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/textures/hw_ihwtexture.h" -#include "swrenderer/textures/r_swtexture.h" -#include "imagehelpers.h" -#include "image.h" -#include "formats/multipatchtexture.h" -#include "g_levellocals.h" - -FTexture *CreateBrightmapTexture(FImageSource*); - -// Make sprite offset adjustment user-configurable per renderer. -int r_spriteadjustSW, r_spriteadjustHW; -CUSTOM_CVAR(Int, r_spriteadjust, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - r_spriteadjustHW = !!(self & 2); - r_spriteadjustSW = !!(self & 1); - TexMan.SpriteAdjustChanged(); -} - -//========================================================================== -// -// -// -//========================================================================== - -uint8_t ImageHelpers::GrayMap[256]; - -void FTexture::InitGrayMap() -{ - for (int i = 0; i < 256; ++i) - { - ImageHelpers::GrayMap[i] = ColorMatcher.Pick(i, i, i); - } -} - - -//========================================================================== -// -// -// -//========================================================================== - - -// Examines the lump contents to decide what type of texture to create, -// and creates the texture. -FTexture * FTexture::CreateTexture(const char *name, int lumpnum, ETextureType usetype) -{ - if (lumpnum == -1) return nullptr; - - auto image = FImageSource::GetImage(lumpnum, usetype); - if (image != nullptr) - { - FTexture *tex = new FImageTexture(image); - if (tex != nullptr) - { - tex->UseType = usetype; - if (usetype == ETextureType::Flat) - { - int w = tex->GetWidth(); - int h = tex->GetHeight(); - - // Auto-scale flats with dimensions 128x128 and 256x256. - // In hindsight, a bad idea, but RandomLag made it sound better than it really is. - // Now we're stuck with this stupid behaviour. - if (w==128 && h==128) - { - tex->Scale.X = tex->Scale.Y = 2; - tex->bWorldPanning = true; - } - else if (w==256 && h==256) - { - tex->Scale.X = tex->Scale.Y = 4; - tex->bWorldPanning = true; - } - } - tex->Name = name; - tex->Name.ToUpper(); - return tex; - } - } - return nullptr; -} - -//========================================================================== -// -// -// -//========================================================================== - -FTexture::FTexture (const char *name, int lumpnum) - : - Scale(1,1), SourceLump(lumpnum), - UseType(ETextureType::Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false), - bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bFullNameTexture(false), - Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0) -{ - bBrightmapChecked = false; - bGlowing = false; - bAutoGlowing = false; - bFullbright = false; - bDisableFullbright = false; - bSkybox = false; - bNoCompress = false; - bNoExpand = false; - bTranslucent = -1; - - - _LeftOffset[0] = _LeftOffset[1] = _TopOffset[0] = _TopOffset[1] = 0; - id.SetInvalid(); - if (name != NULL) - { - Name = name; - Name.ToUpper(); - } - else if (lumpnum < 0) - { - Name = FString(); - } - else - { - Wads.GetLumpName (Name, lumpnum); - } -} - -FTexture::~FTexture () -{ - FTexture *link = Wads.GetLinkedTexture(SourceLump); - if (link == this) Wads.SetLinkedTexture(SourceLump, nullptr); - if (areas != nullptr) delete[] areas; - areas = nullptr; - - for (int i = 0; i < 2; i++) - { - if (Material[i] != nullptr) delete Material[i]; - Material[i] = nullptr; - } - if (SoftwareTexture != nullptr) - { - delete SoftwareTexture; - SoftwareTexture = nullptr; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FTexture::SetFrontSkyLayer () -{ - bNoRemap0 = true; -} - -//=========================================================================== -// -// FTexture::GetBgraBitmap -// -// Default returns just an empty bitmap. This needs to be overridden by -// any subclass that actually does return a software pixel buffer. -// -//=========================================================================== - -FBitmap FTexture::GetBgraBitmap(PalEntry *remap, int *ptrans) -{ - FBitmap bmp; - bmp.Create(Width, Height); - return bmp; -} - -//========================================================================== -// -// -// -//========================================================================== - -FTexture *FTexture::GetRawTexture() -{ - if (OffsetLess) return OffsetLess; - // Reject anything that cannot have been a single-patch multipatch texture in vanilla. - auto image = static_cast(GetImage()); - if (bMultiPatch != 1 || UseType != ETextureType::Wall || Scale.X != 1 || Scale.Y != 1 || bWorldPanning || image == nullptr || image->NumParts != 1 || _TopOffset[0] == 0) - { - OffsetLess = this; - return this; - } - // Set up a new texture that directly references the underlying patch. - // From here we cannot retrieve the original texture made for it, so just create a new one. - FImageSource *source = image->Parts[0].Image; - - // Size must match for this to work as intended - if (source->GetWidth() != Width || source->GetHeight() != Height) - { - OffsetLess = this; - return this; - } - - - OffsetLess = new FImageTexture(source, ""); - TexMan.AddTexture(OffsetLess); - return OffsetLess; -} - -void FTexture::SetScaledSize(int fitwidth, int fitheight) -{ - Scale.X = double(Width) / fitwidth; - Scale.Y =double(Height) / fitheight; - // compensate for roundoff errors - if (int(Scale.X * fitwidth) != Width) Scale.X += (1 / 65536.); - if (int(Scale.Y * fitheight) != Height) Scale.Y += (1 / 65536.); -} - -//=========================================================================== -// -// Gets the average color of a texture for use as a sky cap color -// -//=========================================================================== - -PalEntry FTexture::averageColor(const uint32_t *data, int size, int maxout) -{ - int i; - unsigned int r, g, b; - - // First clear them. - r = g = b = 0; - if (size == 0) - { - return PalEntry(255, 255, 255); - } - for (i = 0; i < size; i++) - { - b += BPART(data[i]); - g += GPART(data[i]); - r += RPART(data[i]); - } - - r = r / size; - g = g / size; - b = b / size; - - int maxv = MAX(MAX(r, g), b); - - if (maxv && maxout) - { - r = ::Scale(r, maxout, maxv); - g = ::Scale(g, maxout, maxv); - b = ::Scale(b, maxout, maxv); - } - return PalEntry(255, r, g, b); -} - -PalEntry FTexture::GetSkyCapColor(bool bottom) -{ - if (!bSWSkyColorDone) - { - bSWSkyColorDone = true; - - FBitmap bitmap = GetBgraBitmap(nullptr); - int w = bitmap.GetWidth(); - int h = bitmap.GetHeight(); - - const uint32_t *buffer = (const uint32_t *)bitmap.GetPixels(); - if (buffer) - { - CeilingSkyColor = averageColor((uint32_t *)buffer, w * MIN(30, h), 0); - if (h>30) - { - FloorSkyColor = averageColor(((uint32_t *)buffer) + (h - 30)*w, w * 30, 0); - } - else FloorSkyColor = CeilingSkyColor; - } - } - return bottom ? FloorSkyColor : CeilingSkyColor; -} - -//==================================================================== -// -// CheckRealHeight -// -// Checks the posts in a texture and returns the lowest row (plus one) -// of the texture that is actually used. -// -//==================================================================== - -int FTexture::CheckRealHeight() -{ - auto pixels = Get8BitPixels(false); - - for(int h = GetHeight()-1; h>= 0; h--) - { - for(int w = 0; w < GetWidth(); w++) - { - if (pixels[h + w * GetHeight()] != 0) - { - // Scale maxy before returning it - h = int((h * 2) / Scale.Y); - h = (h >> 1) + (h & 1); - return h; - } - } - } - return 0; -} - -//========================================================================== -// -// Search auto paths for extra material textures -// -//========================================================================== - -void FTexture::AddAutoMaterials() -{ - struct AutoTextureSearchPath - { - const char *path; - FTexture *FTexture::*pointer; - }; - - static AutoTextureSearchPath autosearchpaths[] = - { - { "brightmaps/", &FTexture::Brightmap }, // For backwards compatibility, only for short names - { "materials/brightmaps/", &FTexture::Brightmap }, - { "materials/normalmaps/", &FTexture::Normal }, - { "materials/specular/", &FTexture::Specular }, - { "materials/metallic/", &FTexture::Metallic }, - { "materials/roughness/", &FTexture::Roughness }, - { "materials/ao/", &FTexture::AmbientOcclusion } - }; - - - int startindex = bFullNameTexture ? 1 : 0; - FString searchname = Name; - - if (bFullNameTexture) - { - auto dot = searchname.LastIndexOf('.'); - auto slash = searchname.LastIndexOf('/'); - if (dot > slash) searchname.Truncate(dot); - } - - for (size_t i = 0; i < countof(autosearchpaths); i++) - { - auto &layer = autosearchpaths[i]; - if (this->*(layer.pointer) == nullptr) // only if no explicit assignment had been done. - { - FStringf lookup("%s%s%s", layer.path, bFullNameTexture ? "" : "auto/", searchname.GetChars()); - auto lump = Wads.CheckNumForFullName(lookup, false, ns_global, true); - if (lump != -1) - { - auto bmtex = TexMan.FindTexture(Wads.GetLumpFullName(lump), ETextureType::Any, FTextureManager::TEXMAN_TryAny); - if (bmtex != nullptr) - { - bmtex->bMasked = false; - this->*(layer.pointer) = bmtex; - } - } - } - } -} - -//=========================================================================== -// -// Checks if the texture has a default brightmap and creates it if so -// -//=========================================================================== -void FTexture::CreateDefaultBrightmap() -{ - if (!bBrightmapChecked) - { - // Check for brightmaps - if (GetImage() && GetImage()->UseGamePalette() && TexMan.HasGlobalBrightmap && - UseType != ETextureType::Decal && UseType != ETextureType::MiscPatch && UseType != ETextureType::FontChar && - Brightmap == NULL && bWarped == 0) - { - // May have one - let's check when we use this texture - auto texbuf = Get8BitPixels(false); - const int white = ColorMatcher.Pick(255, 255, 255); - - int size = GetWidth() * GetHeight(); - for (int i = 0; i(this)->GetImage()); - bBrightmapChecked = true; - TexMan.AddTexture(Brightmap); - return; - } - } - // No bright pixels found - DPrintf(DMSG_SPAMMY, "No bright pixels found in texture '%s'\n", Name.GetChars()); - bBrightmapChecked = 1; - } - else - { - // does not have one so set the flag to 'done' - bBrightmapChecked = 1; - } - } -} - - -//========================================================================== -// -// Calculates glow color for a texture -// -//========================================================================== - -void FTexture::GetGlowColor(float *data) -{ - if (bGlowing && GlowColor == 0) - { - auto buffer = GetBgraBitmap(nullptr); - GlowColor = averageColor((uint32_t*)buffer.GetPixels(), buffer.GetWidth() * buffer.GetHeight(), 153); - - // Black glow equals nothing so switch glowing off - if (GlowColor == 0) bGlowing = false; - } - data[0] = GlowColor.r / 255.0f; - data[1] = GlowColor.g / 255.0f; - data[2] = GlowColor.b / 255.0f; -} - -//=========================================================================== -// -// Finds gaps in the texture which can be skipped by the renderer -// This was mainly added to speed up one area in E4M6 of 007LTSD -// -//=========================================================================== - -bool FTexture::FindHoles(const unsigned char * buffer, int w, int h) -{ - const unsigned char * li; - int y, x; - int startdraw, lendraw; - int gaps[5][2]; - int gapc = 0; - - - // already done! - if (areacount) return false; - if (UseType == ETextureType::Flat) return false; // flats don't have transparent parts - areacount = -1; //whatever happens next, it shouldn't be done twice! - - // large textures are excluded for performance reasons - if (h>512) return false; - - startdraw = -1; - lendraw = 0; - for (y = 0; y 0) - { - FloatRect * rcs = new FloatRect[gapc]; - - for (x = 0; x < gapc; x++) - { - // gaps are stored as texture (u/v) coordinates - rcs[x].width = rcs[x].left = -1.0f; - rcs[x].top = (float)gaps[x][0] / (float)h; - rcs[x].height = (float)gaps[x][1] / (float)h; - } - areas = rcs; - } - else areas = nullptr; - areacount = gapc; - - return true; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void FTexture::CheckTrans(unsigned char * buffer, int size, int trans) -{ - if (bTranslucent == -1) - { - bTranslucent = trans; - if (trans == -1) - { - uint32_t * dwbuf = (uint32_t*)buffer; - for (int i = 0; i> 24; - - if (alpha != 0xff && alpha != 0) - { - bTranslucent = 1; - return; - } - } - bTranslucent = 0; - } - } -} - - -//=========================================================================== -// -// smooth the edges of transparent fields in the texture -// -//=========================================================================== - -#ifdef WORDS_BIGENDIAN -#define MSB 0 -#define SOME_MASK 0xffffff00 -#else -#define MSB 3 -#define SOME_MASK 0x00ffffff -#endif - -#define CHKPIX(ofs) (l1[(ofs)*4+MSB]==255 ? (( ((uint32_t*)l1)[0] = ((uint32_t*)l1)[ofs]&SOME_MASK), trans=true ) : false) - -bool FTexture::SmoothEdges(unsigned char * buffer, int w, int h) -{ - int x, y; - bool trans = buffer[MSB] == 0; // If I set this to false here the code won't detect textures - // that only contain transparent pixels. - bool semitrans = false; - unsigned char * l1; - - if (h <= 1 || w <= 1) return false; // makes (a) no sense and (b) doesn't work with this code! - - l1 = buffer; - - - if (l1[MSB] == 0 && !CHKPIX(1)) CHKPIX(w); - else if (l1[MSB]<255) semitrans = true; - l1 += 4; - for (x = 1; xGetId(); - builder.translation = MAX(0, translation); - builder.expand = exx; - result.mContentId = builder.id; - } - else result.mContentId = 0; // for non-image backed textures this has no meaning so leave it at 0. - - result.mBuffer = buffer; - result.mWidth = W; - result.mHeight = H; - - // Only do postprocessing for image-backed textures. (i.e. not for the burn texture which can also pass through here.) - if (GetImage() && flags & CTF_ProcessData) - { - CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly); - if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false); - } - - return result; -} - -//=========================================================================== -// -// Dummy texture for the 0-entry. -// -//=========================================================================== - -bool FTexture::GetTranslucency() -{ - if (bTranslucent == -1) - { - if (!bHasCanvas) - { - // This will calculate all we need, so just discard the result. - CreateTexBuffer(0); - } - else - { - bTranslucent = 0; - } - } - return !!bTranslucent; -} - -//=========================================================================== -// -// Sprite adjust has changed. -// This needs to alter the material's sprite rect. -// -//=========================================================================== - -void FTexture::SetSpriteAdjust() -{ - for (auto mat : Material) - { - if (mat != nullptr) mat->SetSpriteRect(); - } -} - -//=========================================================================== -// -// the default just returns an empty texture. -// -//=========================================================================== - -TArray FTexture::Get8BitPixels(bool alphatex) -{ - TArray Pixels(Width * Height, true); - memset(Pixels.Data(), 0, Width * Height); - return Pixels; -} - -//========================================================================== -// -// -// -//========================================================================== - -FWrapperTexture::FWrapperTexture(int w, int h, int bits) -{ - Width = w; - Height = h; - Format = bits; - UseType = ETextureType::SWCanvas; - bNoCompress = true; - auto hwtex = screen->CreateHardwareTexture(); - // todo: Initialize here. - SystemTextures.AddHardwareTexture(0, false, hwtex); -} - -//=========================================================================== -// -// Coordinate helper. -// The only reason this is even needed is that many years ago someone -// was convinced that having per-texel panning on walls was a good idea. -// If it wasn't for this relatively useless feature the entire positioning -// code for wall textures could be a lot simpler. -// -//=========================================================================== - -//=========================================================================== -// -// -// -//=========================================================================== - -float FTexCoordInfo::RowOffset(float rowoffset) const -{ - float scale = fabs(mScale.Y); - if (scale == 1.f || mWorldPanning) return rowoffset; - else return rowoffset / scale; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -float FTexCoordInfo::TextureOffset(float textureoffset) const -{ - float scale = fabs(mScale.X); - if (scale == 1.f || mWorldPanning) return textureoffset; - else return textureoffset / scale; -} - -//=========================================================================== -// -// Returns the size for which texture offset coordinates are used. -// -//=========================================================================== - -float FTexCoordInfo::TextureAdjustWidth() const -{ - if (mWorldPanning) - { - float tscale = fabs(mTempScale.X); - if (tscale == 1.f) return (float)mRenderWidth; - else return mWidth / fabs(tscale); - } - else return (float)mWidth; -} - - -//=========================================================================== -// -// Retrieve texture coordinate info for per-wall scaling -// -//=========================================================================== - -void FTexCoordInfo::GetFromTexture(FTexture *tex, float x, float y, bool forceworldpanning) -{ - if (x == 1.f) - { - mRenderWidth = tex->GetScaledWidth(); - mScale.X = (float)tex->Scale.X; - mTempScale.X = 1.f; - } - else - { - float scale_x = x * (float)tex->Scale.X; - mRenderWidth = xs_CeilToInt(tex->GetWidth() / scale_x); - mScale.X = scale_x; - mTempScale.X = x; - } - - if (y == 1.f) - { - mRenderHeight = tex->GetScaledHeight(); - mScale.Y = (float)tex->Scale.Y; - mTempScale.Y = 1.f; - } - else - { - float scale_y = y * (float)tex->Scale.Y; - mRenderHeight = xs_CeilToInt(tex->GetHeight() / scale_y); - mScale.Y = scale_y; - mTempScale.Y = y; - } - if (tex->bHasCanvas) - { - mScale.Y = -mScale.Y; - mRenderHeight = -mRenderHeight; - } - mWorldPanning = tex->bWorldPanning || forceworldpanning; - mWidth = tex->GetWidth(); -} - - diff --git a/src/gamedata/textures/texturemanager.cpp b/src/gamedata/textures/texturemanager.cpp deleted file mode 100644 index ee5badce806..00000000000 --- a/src/gamedata/textures/texturemanager.cpp +++ /dev/null @@ -1,1737 +0,0 @@ -/* -** texturemanager.cpp -** The texture manager class -** -**--------------------------------------------------------------------------- -** Copyright 2004-2008 Randy Heit -** Copyright 2006-2008 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "doomtype.h" -#include "doomstat.h" -#include "w_wad.h" -#include "templates.h" -#include "i_system.h" -#include "gstrings.h" - -#include "r_data/r_translate.h" -#include "r_data/sprites.h" -#include "c_dispatch.h" -#include "v_text.h" -#include "sc_man.h" -#include "gi.h" -#include "st_start.h" -#include "cmdlib.h" -#include "g_level.h" -#include "v_video.h" -#include "r_sky.h" -#include "vm.h" -#include "image.h" -#include "formats/multipatchtexture.h" -#include "swrenderer/textures/r_swtexture.h" - -FTextureManager TexMan; - -CUSTOM_CVAR(Bool, vid_nopalsubstitutions, false, CVAR_ARCHIVE|CVAR_NOINITCALL) -{ - // This is in case the sky texture has been substituted. - R_InitSkyMap (); -} - -//========================================================================== -// -// FTextureManager :: FTextureManager -// -//========================================================================== - -FTextureManager::FTextureManager () -{ - memset (HashFirst, -1, sizeof(HashFirst)); - - for (int i = 0; i < 2048; ++i) - { - sintable[i] = short(sin(i*(M_PI / 1024)) * 16384); - } -} - -//========================================================================== -// -// FTextureManager :: ~FTextureManager -// -//========================================================================== - -FTextureManager::~FTextureManager () -{ - DeleteAll(); -} - -//========================================================================== -// -// FTextureManager :: DeleteAll -// -//========================================================================== - -void FTextureManager::DeleteAll() -{ - FImageSource::ClearImages(); - for (unsigned int i = 0; i < Textures.Size(); ++i) - { - delete Textures[i].Texture; - } - Textures.Clear(); - Translation.Clear(); - FirstTextureForFile.Clear(); - memset (HashFirst, -1, sizeof(HashFirst)); - DefaultTexture.SetInvalid(); - - for (unsigned i = 0; i < mAnimations.Size(); i++) - { - if (mAnimations[i] != NULL) - { - M_Free (mAnimations[i]); - mAnimations[i] = NULL; - } - } - mAnimations.Clear(); - - for (unsigned i = 0; i < mSwitchDefs.Size(); i++) - { - if (mSwitchDefs[i] != NULL) - { - M_Free (mSwitchDefs[i]); - mSwitchDefs[i] = NULL; - } - } - mSwitchDefs.Clear(); - - for (unsigned i = 0; i < mAnimatedDoors.Size(); i++) - { - if (mAnimatedDoors[i].TextureFrames != NULL) - { - delete[] mAnimatedDoors[i].TextureFrames; - mAnimatedDoors[i].TextureFrames = NULL; - } - } - mAnimatedDoors.Clear(); - BuildTileData.Clear(); - tmanips.Clear(); -} - -//========================================================================== -// -// Flushes all hardware dependent data. -// Thia must not, under any circumstances, delete the wipe textures, because -// all CCMDs triggering a flush can be executed while a wipe is in progress -// -// This now also deletes the software textures because having the software -// renderer use the texture scalers is a planned feature and that is the -// main reason to call this outside of the destruction code. -// -//========================================================================== - -void FTextureManager::FlushAll() -{ - for (int i = TexMan.NumTextures() - 1; i >= 0; i--) - { - for (int j = 0; j < 2; j++) - { - Textures[i].Texture->SystemTextures.Clean(true, true); - delete Textures[i].Texture->SoftwareTexture; - Textures[i].Texture->SoftwareTexture = nullptr; - } - } -} - -//========================================================================== -// -// FTextureManager :: CheckForTexture -// -//========================================================================== - -FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType usetype, BITFIELD flags) -{ - int i; - int firstfound = -1; - auto firsttype = ETextureType::Null; - - if (name == NULL || name[0] == '\0') - { - return FTextureID(-1); - } - // [RH] Doom counted anything beginning with '-' as "no texture". - // Hopefully nobody made use of that and had textures like "-EMPTY", - // because -NOFLAT- is a valid graphic for ZDoom. - if (name[0] == '-' && name[1] == '\0') - { - return FTextureID(0); - } - - for(i = HashFirst[MakeKey(name) % HASH_SIZE]; i != HASH_END; i = Textures[i].HashNext) - { - const FTexture *tex = Textures[i].Texture; - - - if (stricmp (tex->Name, name) == 0 ) - { - // If we look for short names, we must ignore any long name texture. - if ((flags & TEXMAN_ShortNameOnly) && tex->bFullNameTexture) - { - continue; - } - // The name matches, so check the texture type - if (usetype == ETextureType::Any) - { - // All NULL textures should actually return 0 - if (tex->UseType == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0; - if (tex->UseType == ETextureType::SkinGraphic && !(flags & TEXMAN_AllowSkins)) return 0; - return FTextureID(tex->UseType==ETextureType::Null ? 0 : i); - } - else if ((flags & TEXMAN_Overridable) && tex->UseType == ETextureType::Override) - { - return FTextureID(i); - } - else if (tex->UseType == usetype) - { - return FTextureID(i); - } - else if (tex->UseType == ETextureType::FirstDefined && usetype == ETextureType::Wall) - { - if (!(flags & TEXMAN_ReturnFirst)) return FTextureID(0); - else return FTextureID(i); - } - else if (tex->UseType == ETextureType::Null && usetype == ETextureType::Wall) - { - // We found a NULL texture on a wall -> return 0 - return FTextureID(0); - } - else - { - if (firsttype == ETextureType::Null || - (firsttype == ETextureType::MiscPatch && - tex->UseType != firsttype && - tex->UseType != ETextureType::Null) - ) - { - firstfound = i; - firsttype = tex->UseType; - } - } - } - } - - if ((flags & TEXMAN_TryAny) && usetype != ETextureType::Any) - { - // Never return the index of NULL textures. - if (firstfound != -1) - { - if (firsttype == ETextureType::Null) return FTextureID(0); - if (firsttype == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return FTextureID(0); - return FTextureID(firstfound); - } - } - - - if (!(flags & TEXMAN_ShortNameOnly)) - { - // We intentionally only look for textures in subdirectories. - // Any graphic being placed in the zip's root directory can not be found by this. - if (strchr(name, '/')) - { - FTexture *const NO_TEXTURE = (FTexture*)-1; - int lump = Wads.CheckNumForFullName(name); - if (lump >= 0) - { - FTexture *tex = Wads.GetLinkedTexture(lump); - if (tex == NO_TEXTURE) return FTextureID(-1); - if (tex != NULL) return tex->id; - if (flags & TEXMAN_DontCreate) return FTextureID(-1); // we only want to check, there's no need to create a texture if we don't have one yet. - tex = FTexture::CreateTexture("", lump, ETextureType::Override); - if (tex != NULL) - { - tex->AddAutoMaterials(); - Wads.SetLinkedTexture(lump, tex); - return AddTexture(tex); - } - else - { - // mark this lump as having no valid texture so that we don't have to retry creating one later. - Wads.SetLinkedTexture(lump, NO_TEXTURE); - } - } - } - } - - return FTextureID(-1); -} - -static int CheckForTexture(const FString &name, int type, int flags) -{ - return TexMan.CheckForTexture(name, static_cast(type), flags).GetIndex(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, CheckForTexture, CheckForTexture) -{ - PARAM_PROLOGUE; - PARAM_STRING(name); - PARAM_INT(type); - PARAM_INT(flags); - ACTION_RETURN_INT(CheckForTexture(name, type, flags)); -} - -//========================================================================== -// -// FTextureManager :: ListTextures -// -//========================================================================== - -int FTextureManager::ListTextures (const char *name, TArray &list, bool listall) -{ - int i; - - if (name == NULL || name[0] == '\0') - { - return 0; - } - // [RH] Doom counted anything beginning with '-' as "no texture". - // Hopefully nobody made use of that and had textures like "-EMPTY", - // because -NOFLAT- is a valid graphic for ZDoom. - if (name[0] == '-' && name[1] == '\0') - { - return 0; - } - i = HashFirst[MakeKey (name) % HASH_SIZE]; - - while (i != HASH_END) - { - const FTexture *tex = Textures[i].Texture; - - if (stricmp (tex->Name, name) == 0) - { - // NULL textures must be ignored. - if (tex->UseType!=ETextureType::Null) - { - unsigned int j = list.Size(); - if (!listall) - { - for (j = 0; j < list.Size(); j++) - { - // Check for overriding definitions from newer WADs - if (Textures[list[j].GetIndex()].Texture->UseType == tex->UseType) break; - } - } - if (j==list.Size()) list.Push(FTextureID(i)); - } - } - i = Textures[i].HashNext; - } - return list.Size(); -} - -//========================================================================== -// -// FTextureManager :: GetTextures -// -//========================================================================== - -FTextureID FTextureManager::GetTextureID (const char *name, ETextureType usetype, BITFIELD flags) -{ - FTextureID i; - - if (name == NULL || name[0] == 0) - { - return FTextureID(0); - } - else - { - i = CheckForTexture (name, usetype, flags | TEXMAN_TryAny); - } - - if (!i.Exists()) - { - // Use a default texture instead of aborting like Doom did - Printf ("Unknown texture: \"%s\"\n", name); - i = DefaultTexture; - } - return FTextureID(i); -} - -//========================================================================== -// -// FTextureManager :: FindTexture -// -//========================================================================== - -FTexture *FTextureManager::FindTexture(const char *texname, ETextureType usetype, BITFIELD flags) -{ - FTextureID texnum = CheckForTexture (texname, usetype, flags); - return GetTexture(texnum.GetIndex()); -} - -//========================================================================== -// -// Defines how graphics substitution is handled. -// 0: Never replace a text-containing graphic with a font-based text. -// 1: Always replace, regardless of any missing information. Useful for testing the substitution without providing full data. -// 2: Only replace for non-default texts, i.e. if some language redefines the string's content, use it instead of the graphic. Never replace a localized graphic. -// 3: Only replace if the string is not the default and the graphic comes from the IWAD. Never replace a localized graphic. -// 4: Like 1, but lets localized graphics pass. -// -// The default is 3, which only replaces known content with non-default texts. -// -//========================================================================== - -CUSTOM_CVAR(Int, cl_gfxlocalization, 3, CVAR_ARCHIVE) -{ - if (self < 0 || self > 4) self = 0; -} - -//========================================================================== -// -// FTextureManager :: OkForLocalization -// -//========================================================================== - -bool FTextureManager::OkForLocalization(FTextureID texnum, const char *substitute) -{ - if (!texnum.isValid()) return false; - - // First the unconditional settings, 0='never' and 1='always'. - if (cl_gfxlocalization == 1 || gameinfo.forcetextinmenus) return false; - if (cl_gfxlocalization == 0 || gameinfo.forcenogfxsubstitution) return true; - - uint32_t langtable = 0; - if (*substitute == '$') substitute = GStrings.GetString(substitute+1, &langtable); - else return true; // String literals from the source data should never override graphics from the same definition. - if (substitute == nullptr) return true; // The text does not exist. - - // Modes 2, 3 and 4 must not replace localized textures. - int localizedTex = ResolveLocalizedTexture(texnum.GetIndex()); - if (localizedTex != texnum.GetIndex()) return true; // Do not substitute a localized variant of the graphics patch. - - // For mode 4 we are done now. - if (cl_gfxlocalization == 4) return false; - - // Mode 2 and 3 must reject any text replacement from the default language tables. - if ((langtable & MAKE_ID(255,0,0,0)) == MAKE_ID('*', 0, 0, 0)) return true; // Do not substitute if the string comes from the default table. - if (cl_gfxlocalization == 2) return false; - - // Mode 3 must also reject substitutions for non-IWAD content. - int file = Wads.GetLumpFile(Textures[texnum.GetIndex()].Texture->SourceLump); - if (file > Wads.GetMaxIwadNum()) return true; - - return false; -} - -static int OkForLocalization(int index, const FString &substitute) -{ - return TexMan.OkForLocalization(FSetTextureID(index), substitute); -} - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, OkForLocalization, OkForLocalization) -{ - PARAM_PROLOGUE; - PARAM_INT(name); - PARAM_STRING(subst) - ACTION_RETURN_INT(OkForLocalization(name, subst)); -} - -//========================================================================== -// -// FTextureManager :: AddTexture -// -//========================================================================== - -FTextureID FTextureManager::AddTexture (FTexture *texture) -{ - int bucket; - int hash; - - if (texture == NULL) return FTextureID(-1); - - // Later textures take precedence over earlier ones - - // Textures without name can't be looked for - if (texture->Name[0] != '\0') - { - bucket = int(MakeKey (texture->Name) % HASH_SIZE); - hash = HashFirst[bucket]; - } - else - { - bucket = -1; - hash = -1; - } - - TextureHash hasher = { texture, hash }; - int trans = Textures.Push (hasher); - Translation.Push (trans); - if (bucket >= 0) HashFirst[bucket] = trans; - return (texture->id = FTextureID(trans)); -} - -//========================================================================== -// -// FTextureManager :: CreateTexture -// -// Calls FTexture::CreateTexture and adds the texture to the manager. -// -//========================================================================== - -FTextureID FTextureManager::CreateTexture (int lumpnum, ETextureType usetype) -{ - if (lumpnum != -1) - { - FString str; - Wads.GetLumpName(str, lumpnum); - FTexture *out = FTexture::CreateTexture(str, lumpnum, usetype); - - if (out != NULL) return AddTexture (out); - else - { - Printf (TEXTCOLOR_ORANGE "Invalid data encountered for texture %s\n", Wads.GetLumpFullPath(lumpnum).GetChars()); - return FTextureID(-1); - } - } - return FTextureID(-1); -} - -//========================================================================== -// -// FTextureManager :: ReplaceTexture -// -//========================================================================== - -void FTextureManager::ReplaceTexture (FTextureID picnum, FTexture *newtexture, bool free) -{ - int index = picnum.GetIndex(); - if (unsigned(index) >= Textures.Size()) - return; - - FTexture *oldtexture = Textures[index].Texture; - - newtexture->Name = oldtexture->Name; - newtexture->UseType = oldtexture->UseType; - Textures[index].Texture = newtexture; - newtexture->id = oldtexture->id; - oldtexture->Name = ""; - AddTexture(oldtexture); -} - -//========================================================================== -// -// FTextureManager :: AreTexturesCompatible -// -// Checks if 2 textures are compatible for a ranged animation -// -//========================================================================== - -bool FTextureManager::AreTexturesCompatible (FTextureID picnum1, FTextureID picnum2) -{ - int index1 = picnum1.GetIndex(); - int index2 = picnum2.GetIndex(); - if (unsigned(index1) >= Textures.Size() || unsigned(index2) >= Textures.Size()) - return false; - - FTexture *texture1 = Textures[index1].Texture; - FTexture *texture2 = Textures[index2].Texture; - - // both textures must be the same type. - if (texture1 == NULL || texture2 == NULL || texture1->UseType != texture2->UseType) - return false; - - // both textures must be from the same file - for(unsigned i = 0; i < FirstTextureForFile.Size() - 1; i++) - { - if (index1 >= FirstTextureForFile[i] && index1 < FirstTextureForFile[i+1]) - { - return (index2 >= FirstTextureForFile[i] && index2 < FirstTextureForFile[i+1]); - } - } - return false; -} - - -//========================================================================== -// -// FTextureManager :: AddGroup -// -//========================================================================== - -void FTextureManager::AddGroup(int wadnum, int ns, ETextureType usetype) -{ - int firsttx = Wads.GetFirstLump(wadnum); - int lasttx = Wads.GetLastLump(wadnum); - FString Name; - - // Go from first to last so that ANIMDEFS work as expected. However, - // to avoid duplicates (and to keep earlier entries from overriding - // later ones), the texture is only inserted if it is the one returned - // by doing a check by name in the list of wads. - - for (; firsttx <= lasttx; ++firsttx) - { - if (Wads.GetLumpNamespace(firsttx) == ns) - { - Wads.GetLumpName (Name, firsttx); - - if (Wads.CheckNumForName (Name, ns) == firsttx) - { - CreateTexture (firsttx, usetype); - } - StartScreen->Progress(); - } - else if (ns == ns_flats && Wads.GetLumpFlags(firsttx) & LUMPF_MAYBEFLAT) - { - if (Wads.CheckNumForName (Name, ns) < firsttx) - { - CreateTexture (firsttx, usetype); - } - StartScreen->Progress(); - } - } -} - -//========================================================================== -// -// Adds all hires texture definitions. -// -//========================================================================== - -void FTextureManager::AddHiresTextures (int wadnum) -{ - int firsttx = Wads.GetFirstLump(wadnum); - int lasttx = Wads.GetLastLump(wadnum); - - FString Name; - TArray tlist; - - if (firsttx == -1 || lasttx == -1) - { - return; - } - - for (;firsttx <= lasttx; ++firsttx) - { - if (Wads.GetLumpNamespace(firsttx) == ns_hires) - { - Wads.GetLumpName (Name, firsttx); - - if (Wads.CheckNumForName (Name, ns_hires) == firsttx) - { - tlist.Clear(); - int amount = ListTextures(Name, tlist); - if (amount == 0) - { - // A texture with this name does not yet exist - FTexture * newtex = FTexture::CreateTexture (Name, firsttx, ETextureType::Any); - if (newtex != NULL) - { - newtex->UseType=ETextureType::Override; - AddTexture(newtex); - } - } - else - { - for(unsigned int i = 0; i < tlist.Size(); i++) - { - FTexture * newtex = FTexture::CreateTexture ("", firsttx, ETextureType::Any); - if (newtex != NULL) - { - FTexture * oldtex = Textures[tlist[i].GetIndex()].Texture; - - // Replace the entire texture and adjust the scaling and offset factors. - newtex->bWorldPanning = true; - newtex->SetScaledSize(oldtex->GetScaledWidth(), oldtex->GetScaledHeight()); - newtex->_LeftOffset[0] = int(oldtex->GetScaledLeftOffset(0) * newtex->Scale.X); - newtex->_LeftOffset[1] = int(oldtex->GetScaledLeftOffset(1) * newtex->Scale.X); - newtex->_TopOffset[0] = int(oldtex->GetScaledTopOffset(0) * newtex->Scale.Y); - newtex->_TopOffset[1] = int(oldtex->GetScaledTopOffset(1) * newtex->Scale.Y); - ReplaceTexture(tlist[i], newtex, true); - } - } - } - StartScreen->Progress(); - } - } - } -} - -//========================================================================== -// -// Loads the HIRESTEX lumps -// -//========================================================================== - -void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname, FMultipatchTextureBuilder &build) -{ - int remapLump, lastLump; - - lastLump = 0; - - while ((remapLump = Wads.FindLump(lumpname, &lastLump)) != -1) - { - if (Wads.GetLumpFile(remapLump) == wadnum) - { - ParseTextureDef(remapLump, build); - } - } -} - -void FTextureManager::ParseTextureDef(int lump, FMultipatchTextureBuilder &build) -{ - TArray tlist; - - FScanner sc(lump); - while (sc.GetString()) - { - if (sc.Compare("remap")) // remap an existing texture - { - sc.MustGetString(); - - // allow selection by type - int mode; - ETextureType type; - if (sc.Compare("wall")) type=ETextureType::Wall, mode=FTextureManager::TEXMAN_Overridable; - else if (sc.Compare("flat")) type=ETextureType::Flat, mode=FTextureManager::TEXMAN_Overridable; - else if (sc.Compare("sprite")) type=ETextureType::Sprite, mode=0; - else type = ETextureType::Any, mode = 0; - - if (type != ETextureType::Any) sc.MustGetString(); - - sc.String[8]=0; - - tlist.Clear(); - int amount = ListTextures(sc.String, tlist); - FName texname = sc.String; - - sc.MustGetString(); - int lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_patches); - if (lumpnum == -1) lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_graphics); - - if (tlist.Size() == 0) - { - Printf("Attempting to remap non-existent texture %s to %s\n", - texname.GetChars(), sc.String); - } - else if (lumpnum == -1) - { - Printf("Attempting to remap texture %s to non-existent lump %s\n", - texname.GetChars(), sc.String); - } - else - { - for(unsigned int i = 0; i < tlist.Size(); i++) - { - FTexture * oldtex = Textures[tlist[i].GetIndex()].Texture; - int sl; - - // only replace matching types. For sprites also replace any MiscPatches - // based on the same lump. These can be created for icons. - if (oldtex->UseType == type || type == ETextureType::Any || - (mode == TEXMAN_Overridable && oldtex->UseType == ETextureType::Override) || - (type == ETextureType::Sprite && oldtex->UseType == ETextureType::MiscPatch && - (sl=oldtex->GetSourceLump()) >= 0 && Wads.GetLumpNamespace(sl) == ns_sprites) - ) - { - FTexture * newtex = FTexture::CreateTexture ("", lumpnum, ETextureType::Any); - if (newtex != NULL) - { - // Replace the entire texture and adjust the scaling and offset factors. - newtex->bWorldPanning = true; - newtex->SetScaledSize(oldtex->GetScaledWidth(), oldtex->GetScaledHeight()); - newtex->_LeftOffset[0] = int(oldtex->GetScaledLeftOffset(0) * newtex->Scale.X); - newtex->_LeftOffset[1] = int(oldtex->GetScaledLeftOffset(1) * newtex->Scale.X); - newtex->_TopOffset[0] = int(oldtex->GetScaledTopOffset(0) * newtex->Scale.Y); - newtex->_TopOffset[1] = int(oldtex->GetScaledTopOffset(1) * newtex->Scale.Y); - ReplaceTexture(tlist[i], newtex, true); - } - } - } - } - } - else if (sc.Compare("define")) // define a new "fake" texture - { - sc.GetString(); - - FString base = ExtractFileBase(sc.String, false); - if (!base.IsEmpty()) - { - FString src = base.Left(8); - - int lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_patches); - if (lumpnum == -1) lumpnum = Wads.CheckNumForFullName(sc.String, true, ns_graphics); - - sc.GetString(); - bool is32bit = !!sc.Compare("force32bit"); - if (!is32bit) sc.UnGet(); - - sc.MustGetNumber(); - int width = sc.Number; - sc.MustGetNumber(); - int height = sc.Number; - - if (lumpnum>=0) - { - FTexture *newtex = FTexture::CreateTexture(src, lumpnum, ETextureType::Override); - - if (newtex != NULL) - { - // Replace the entire texture and adjust the scaling and offset factors. - newtex->bWorldPanning = true; - newtex->SetScaledSize(width, height); - - FTextureID oldtex = TexMan.CheckForTexture(src, ETextureType::MiscPatch); - if (oldtex.isValid()) - { - ReplaceTexture(oldtex, newtex, true); - newtex->UseType = ETextureType::Override; - } - else AddTexture(newtex); - } - } - } - //else Printf("Unable to define hires texture '%s'\n", tex->Name); - } - else if (sc.Compare("texture")) - { - build.ParseTexture(sc, ETextureType::Override); - } - else if (sc.Compare("sprite")) - { - build.ParseTexture(sc, ETextureType::Sprite); - } - else if (sc.Compare("walltexture")) - { - build.ParseTexture(sc, ETextureType::Wall); - } - else if (sc.Compare("flat")) - { - build.ParseTexture(sc, ETextureType::Flat); - } - else if (sc.Compare("graphic")) - { - build.ParseTexture(sc, ETextureType::MiscPatch); - } - else if (sc.Compare("#include")) - { - sc.MustGetString(); - - // This is not using sc.Open because it can print a more useful error message when done here - int includelump = Wads.CheckNumForFullName(sc.String, true); - if (includelump == -1) - { - sc.ScriptError("Lump '%s' not found", sc.String); - } - else - { - ParseTextureDef(includelump, build); - } - } - else - { - sc.ScriptError("Texture definition expected, found '%s'", sc.String); - } - } -} - -//========================================================================== -// -// FTextureManager :: AddPatches -// -//========================================================================== - -void FTextureManager::AddPatches (int lumpnum) -{ - auto file = Wads.ReopenLumpReader (lumpnum, true); - uint32_t numpatches, i; - char name[9]; - - numpatches = file.ReadUInt32(); - name[8] = '\0'; - - for (i = 0; i < numpatches; ++i) - { - file.Read (name, 8); - - if (CheckForTexture (name, ETextureType::WallPatch, 0) == -1) - { - CreateTexture (Wads.CheckNumForName (name, ns_patches), ETextureType::WallPatch); - } - StartScreen->Progress(); - } -} - - -//========================================================================== -// -// FTextureManager :: LoadTexturesX -// -// Initializes the texture list with the textures from the world map. -// -//========================================================================== - -void FTextureManager::LoadTextureX(int wadnum, FMultipatchTextureBuilder &build) -{ - // Use the most recent PNAMES for this WAD. - // Multiple PNAMES in a WAD will be ignored. - int pnames = Wads.CheckNumForName("PNAMES", ns_global, wadnum, false); - - if (pnames < 0) - { - // should never happen except for zdoom.pk3 - return; - } - - // Only add the patches if the PNAMES come from the current file - // Otherwise they have already been processed. - if (Wads.GetLumpFile(pnames) == wadnum) TexMan.AddPatches (pnames); - - int texlump1 = Wads.CheckNumForName ("TEXTURE1", ns_global, wadnum); - int texlump2 = Wads.CheckNumForName ("TEXTURE2", ns_global, wadnum); - build.AddTexturesLumps (texlump1, texlump2, pnames); -} - -//========================================================================== -// -// FTextureManager :: AddTexturesForWad -// -//========================================================================== - -void FTextureManager::AddTexturesForWad(int wadnum, FMultipatchTextureBuilder &build) -{ - int firsttexture = Textures.Size(); - int lumpcount = Wads.GetNumLumps(); - bool iwad = wadnum >= Wads.GetIwadNum() && wadnum <= Wads.GetMaxIwadNum(); - - FirstTextureForFile.Push(firsttexture); - - // First step: Load sprites - AddGroup(wadnum, ns_sprites, ETextureType::Sprite); - - // When loading a Zip, all graphics in the patches/ directory should be - // added as well. - AddGroup(wadnum, ns_patches, ETextureType::WallPatch); - - // Second step: TEXTUREx lumps - LoadTextureX(wadnum, build); - - // Third step: Flats - AddGroup(wadnum, ns_flats, ETextureType::Flat); - - // Fourth step: Textures (TX_) - AddGroup(wadnum, ns_newtextures, ETextureType::Override); - - // Sixth step: Try to find any lump in the WAD that may be a texture and load as a TEX_MiscPatch - int firsttx = Wads.GetFirstLump(wadnum); - int lasttx = Wads.GetLastLump(wadnum); - - for (int i= firsttx; i <= lasttx; i++) - { - bool skin = false; - FString Name; - Wads.GetLumpName(Name, i); - - // Ignore anything not in the global namespace - int ns = Wads.GetLumpNamespace(i); - if (ns == ns_global) - { - // In Zips all graphics must be in a separate namespace. - if (Wads.GetLumpFlags(i) & LUMPF_ZIPFILE) continue; - - // Ignore lumps with empty names. - if (Wads.CheckLumpName(i, "")) continue; - - // Ignore anything belonging to a map - if (Wads.CheckLumpName(i, "THINGS")) continue; - if (Wads.CheckLumpName(i, "LINEDEFS")) continue; - if (Wads.CheckLumpName(i, "SIDEDEFS")) continue; - if (Wads.CheckLumpName(i, "VERTEXES")) continue; - if (Wads.CheckLumpName(i, "SEGS")) continue; - if (Wads.CheckLumpName(i, "SSECTORS")) continue; - if (Wads.CheckLumpName(i, "NODES")) continue; - if (Wads.CheckLumpName(i, "SECTORS")) continue; - if (Wads.CheckLumpName(i, "REJECT")) continue; - if (Wads.CheckLumpName(i, "BLOCKMAP")) continue; - if (Wads.CheckLumpName(i, "BEHAVIOR")) continue; - - bool force = false; - // Don't bother looking at this lump if something later overrides it. - if (Wads.CheckNumForName(Name, ns_graphics) != i) - { - if (iwad) - { - // We need to make an exception for font characters of the SmallFont coming from the IWAD to be able to construct the original font. - if (Name.IndexOf("STCFN") != 0 && Name.IndexOf("FONTA") != 0) continue; - force = true; - } - else continue; - } - - // skip this if it has already been added as a wall patch. - if (!force && CheckForTexture(Name, ETextureType::WallPatch, 0).Exists()) continue; - } - else if (ns == ns_graphics) - { - if (Wads.CheckNumForName(Name, ns_graphics) != i) - { - if (iwad) - { - // We need to make an exception for font characters of the SmallFont coming from the IWAD to be able to construct the original font. - if (Name.IndexOf("STCFN") != 0 && Name.IndexOf("FONTA") != 0) continue; - } - else continue; - } - } - else if (ns >= ns_firstskin) - { - // Don't bother looking this lump if something later overrides it. - if (Wads.CheckNumForName(Name, ns) != i) continue; - skin = true; - } - else continue; - - // Try to create a texture from this lump and add it. - // Unfortunately we have to look at everything that comes through here... - FTexture *out = FTexture::CreateTexture(Name, i, skin ? ETextureType::SkinGraphic : ETextureType::MiscPatch); - - if (out != NULL) - { - AddTexture (out); - } - } - - // Check for text based texture definitions - LoadTextureDefs(wadnum, "TEXTURES", build); - LoadTextureDefs(wadnum, "HIRESTEX", build); - - // Seventh step: Check for hires replacements. - AddHiresTextures(wadnum); - - SortTexturesByType(firsttexture, Textures.Size()); -} - -//========================================================================== -// -// FTextureManager :: SortTexturesByType -// sorts newly added textures by UseType so that anything defined -// in TEXTURES and HIRESTEX gets in its proper place. -// -//========================================================================== - -void FTextureManager::SortTexturesByType(int start, int end) -{ - TArray newtextures; - - // First unlink all newly added textures from the hash chain - for (int i = 0; i < HASH_SIZE; i++) - { - while (HashFirst[i] >= start && HashFirst[i] != HASH_END) - { - HashFirst[i] = Textures[HashFirst[i]].HashNext; - } - } - newtextures.Resize(end-start); - for(int i=start; iUseType == texturetypes[i]) - { - AddTexture(newtextures[j]); - newtextures[j] = NULL; - } - } - } - // This should never happen. All other UseTypes are only used outside - for(unsigned j = 0; jName.GetChars()); - AddTexture(newtextures[j]); - } - } -} - -//========================================================================== -// -// FTextureManager :: AddLocalizedVariants -// -//========================================================================== - -void FTextureManager::AddLocalizedVariants() -{ - TArray content; - Wads.GetLumpsInFolder("localized/textures/", content, false); - for (auto &entry : content) - { - FString name = entry.name; - auto tokens = name.Split(".", FString::TOK_SKIPEMPTY); - if (tokens.Size() == 2) - { - auto ext = tokens[1]; - // Do not interpret common extensions for images as language IDs. - if (ext.CompareNoCase("png") == 0 || ext.CompareNoCase("jpg") == 0 || ext.CompareNoCase("gfx") == 0 || ext.CompareNoCase("tga") == 0 || ext.CompareNoCase("lmp") == 0) - { - Printf("%s contains no language IDs and will be ignored\n", entry.name); - continue; - } - } - if (tokens.Size() >= 2) - { - FString base = ExtractFileBase(tokens[0]); - FTextureID origTex = CheckForTexture(base, ETextureType::MiscPatch); - if (origTex.isValid()) - { - FTextureID tex = CheckForTexture(entry.name, ETextureType::MiscPatch); - if (tex.isValid()) - { - FTexture *otex = GetTexture(origTex); - FTexture *ntex = GetTexture(tex); - if (otex->GetDisplayWidth() != ntex->GetDisplayWidth() || otex->GetDisplayHeight() != ntex->GetDisplayHeight()) - { - Printf("Localized texture %s must be the same size as the one it replaces\n", entry.name); - } - else - { - tokens[1].ToLower(); - auto langids = tokens[1].Split("-", FString::TOK_SKIPEMPTY); - for (auto &lang : langids) - { - if (lang.Len() == 2 || lang.Len() == 3) - { - uint32_t langid = MAKE_ID(lang[0], lang[1], lang[2], 0); - uint64_t comboid = (uint64_t(langid) << 32) | origTex.GetIndex(); - LocalizedTextures.Insert(comboid, tex.GetIndex()); - Textures[origTex.GetIndex()].HasLocalization = true; - } - else - { - Printf("Invalid language ID in texture %s\n", entry.name); - } - } - } - } - else - { - Printf("%s is not a texture\n", entry.name); - } - } - else - { - Printf("Unknown texture %s for localized variant %s\n", tokens[0].GetChars(), entry.name); - } - } - else - { - Printf("%s contains no language IDs and will be ignored\n", entry.name); - } - - } -} - -//========================================================================== -// -// FTextureManager :: Init -// -//========================================================================== -FTexture *CreateShaderTexture(bool, bool); - -void FTextureManager::Init() -{ - DeleteAll(); - GenerateGlobalBrightmapFromColormap(); - SpriteFrames.Clear(); - //if (BuildTileFiles.Size() == 0) CountBuildTiles (); - FTexture::InitGrayMap(); - - // Texture 0 is a dummy texture used to indicate "no texture" - auto nulltex = new FImageTexture(nullptr, ""); - nulltex->SetUseType(ETextureType::Null); - AddTexture (nulltex); - // some special textures used in the game. - AddTexture(CreateShaderTexture(false, false)); - AddTexture(CreateShaderTexture(false, true)); - AddTexture(CreateShaderTexture(true, false)); - AddTexture(CreateShaderTexture(true, true)); - - int wadcnt = Wads.GetNumWads(); - - FMultipatchTextureBuilder build(*this); - - for(int i = 0; i< wadcnt; i++) - { - AddTexturesForWad(i, build); - } - build.ResolveAllPatches(); - - // Add one marker so that the last WAD is easier to handle and treat - // Build tiles as a completely separate block. - FirstTextureForFile.Push(Textures.Size()); - InitBuildTiles (); - FirstTextureForFile.Push(Textures.Size()); - - DefaultTexture = CheckForTexture ("-NOFLAT-", ETextureType::Override, 0); - - // The Hexen scripts use BLANK as a blank texture, even though it's really not. - // I guess the Doom renderer must have clipped away the line at the bottom of - // the texture so it wasn't visible. Change its use type to a blank null texture to really make it blank. - if (gameinfo.gametype == GAME_Hexen) - { - FTextureID tex = CheckForTexture ("BLANK", ETextureType::Wall, false); - if (tex.Exists()) - { - auto texture = GetTexture(tex, false); - texture->UseType = ETextureType::Null; - } - } - - // Hexen parallax skies use color 0 to indicate transparency on the front - // layer, so we must not remap color 0 on these textures. Unfortunately, - // the only way to identify these textures is to check the MAPINFO. - for (unsigned int i = 0; i < wadlevelinfos.Size(); ++i) - { - if (wadlevelinfos[i].flags & LEVEL_DOUBLESKY) - { - FTextureID picnum = CheckForTexture (wadlevelinfos[i].SkyPic1, ETextureType::Wall, false); - if (picnum.isValid()) - { - Textures[picnum.GetIndex()].Texture->SetFrontSkyLayer (); - } - } - } - - InitAnimated(); - InitAnimDefs(); - FixAnimations(); - InitSwitchList(); - InitPalettedVersions(); - AdjustSpriteOffsets(); - // Add auto materials to each texture after everything has been set up. - // Textures array can be reallocated in process, so ranged for loop is not suitable. - // There is no need to process discovered material textures here, - // CheckForTexture() did this already. - for (unsigned int i = 0, count = Textures.Size(); i < count; ++i) - { - Textures[i].Texture->AddAutoMaterials(); - } - - glLight = TexMan.CheckForTexture("glstuff/gllight.png", ETextureType::MiscPatch); - glPart2 = TexMan.CheckForTexture("glstuff/glpart2.png", ETextureType::MiscPatch); - glPart = TexMan.CheckForTexture("glstuff/glpart.png", ETextureType::MiscPatch); - mirrorTexture = TexMan.CheckForTexture("glstuff/mirror.png", ETextureType::MiscPatch); - AddLocalizedVariants(); -} - -//========================================================================== -// -// FTextureManager :: InitPalettedVersions -// -//========================================================================== - -void FTextureManager::InitPalettedVersions() -{ - int lump, lastlump = 0; - - while ((lump = Wads.FindLump("PALVERS", &lastlump)) != -1) - { - FScanner sc(lump); - - while (sc.GetString()) - { - FTextureID pic1 = CheckForTexture(sc.String, ETextureType::Any); - if (!pic1.isValid()) - { - sc.ScriptMessage("Unknown texture %s to replace", sc.String); - } - sc.MustGetString(); - FTextureID pic2 = CheckForTexture(sc.String, ETextureType::Any); - if (!pic2.isValid()) - { - sc.ScriptMessage("Unknown texture %s to use as replacement", sc.String); - } - if (pic1.isValid() && pic2.isValid()) - { - FTexture *owner = GetTexture(pic1); - FTexture *owned = GetTexture(pic2); - - if (owner && owned) owner->PalVersion = owned; - } - } - } -} - -//========================================================================== -// -// FTextureManager :: PalCheck -// -//========================================================================== - -int FTextureManager::PalCheck(int tex) -{ - // In any true color mode this shouldn't do anything. - if (vid_nopalsubstitutions || V_IsTrueColor()) return tex; - auto ftex = Textures[tex].Texture; - if (ftex != nullptr && ftex->PalVersion != nullptr) return ftex->PalVersion->id.GetIndex(); - return tex; -} - -//========================================================================== -// -// FTextureManager :: PalCheck -// -//========================================================================== -EXTERN_CVAR(String, language) - -int FTextureManager::ResolveLocalizedTexture(int tex) -{ - size_t langlen = strlen(language); - int lang = (langlen < 2 || langlen > 3) ? - MAKE_ID('e', 'n', 'u', '\0') : - MAKE_ID(language[0], language[1], language[2], '\0'); - - uint64_t index = (uint64_t(lang) << 32) + tex; - if (auto pTex = LocalizedTextures.CheckKey(index)) return *pTex; - index = (uint64_t(lang & MAKE_ID(255, 255, 0, 0)) << 32) + tex; - if (auto pTex = LocalizedTextures.CheckKey(index)) return *pTex; - - return tex; -} - -//=========================================================================== -// -// R_GuesstimateNumTextures -// -// Returns an estimate of the number of textures R_InitData will have to -// process. Used by D_DoomMain() when it calls ST_Init(). -// -//=========================================================================== - -int FTextureManager::GuesstimateNumTextures () -{ - int numtex = 0; - - for(int i = Wads.GetNumLumps()-1; i>=0; i--) - { - int space = Wads.GetLumpNamespace(i); - switch(space) - { - case ns_flats: - case ns_sprites: - case ns_newtextures: - case ns_hires: - case ns_patches: - case ns_graphics: - numtex++; - break; - - default: - if (Wads.GetLumpFlags(i) & LUMPF_MAYBEFLAT) numtex++; - - break; - } - } - - //numtex += CountBuildTiles (); // this cannot be done with a lot of overhead so just leave it out. - numtex += CountTexturesX (); - return numtex; -} - -//=========================================================================== -// -// R_CountTexturesX -// -// See R_InitTextures() for the logic in deciding what lumps to check. -// -//=========================================================================== - -int FTextureManager::CountTexturesX () -{ - int count = 0; - int wadcount = Wads.GetNumWads(); - for (int wadnum = 0; wadnum < wadcount; wadnum++) - { - // Use the most recent PNAMES for this WAD. - // Multiple PNAMES in a WAD will be ignored. - int pnames = Wads.CheckNumForName("PNAMES", ns_global, wadnum, false); - - // should never happen except for zdoom.pk3 - if (pnames < 0) continue; - - // Only count the patches if the PNAMES come from the current file - // Otherwise they have already been counted. - if (Wads.GetLumpFile(pnames) == wadnum) - { - count += CountLumpTextures (pnames); - } - - int texlump1 = Wads.CheckNumForName ("TEXTURE1", ns_global, wadnum); - int texlump2 = Wads.CheckNumForName ("TEXTURE2", ns_global, wadnum); - - count += CountLumpTextures (texlump1) - 1; - count += CountLumpTextures (texlump2) - 1; - } - return count; -} - -//=========================================================================== -// -// R_CountLumpTextures -// -// Returns the number of patches in a PNAMES/TEXTURE1/TEXTURE2 lump. -// -//=========================================================================== - -int FTextureManager::CountLumpTextures (int lumpnum) -{ - if (lumpnum >= 0) - { - auto file = Wads.OpenLumpReader (lumpnum); - uint32_t numtex = file.ReadUInt32();; - - return int(numtex) >= 0 ? numtex : 0; - } - return 0; -} - -//----------------------------------------------------------------------------- -// -// Adjust sprite offsets for GL rendering (IWAD resources only) -// -//----------------------------------------------------------------------------- - -void FTextureManager::AdjustSpriteOffsets() -{ - int lump, lastlump = 0; - int sprid; - TMap donotprocess; - - int numtex = Wads.GetNumLumps(); - - for (int i = 0; i < numtex; i++) - { - if (Wads.GetLumpFile(i) > Wads.GetMaxIwadNum()) break; // we are past the IWAD - if (Wads.GetLumpNamespace(i) == ns_sprites && Wads.GetLumpFile(i) >= Wads.GetIwadNum() && Wads.GetLumpFile(i) <= Wads.GetMaxIwadNum()) - { - char str[9]; - Wads.GetLumpName(str, i); - str[8] = 0; - FTextureID texid = TexMan.CheckForTexture(str, ETextureType::Sprite, 0); - if (texid.isValid() && Wads.GetLumpFile(GetTexture(texid)->SourceLump) > Wads.GetMaxIwadNum()) - { - // This texture has been replaced by some PWAD. - memcpy(&sprid, str, 4); - donotprocess[sprid] = true; - } - } - } - - while ((lump = Wads.FindLump("SPROFS", &lastlump, false)) != -1) - { - FScanner sc; - sc.OpenLumpNum(lump); - sc.SetCMode(true); - int ofslumpno = Wads.GetLumpFile(lump); - while (sc.GetString()) - { - int x, y; - bool iwadonly = false; - bool forced = false; - FTextureID texno = TexMan.CheckForTexture(sc.String, ETextureType::Sprite); - sc.MustGetStringName(","); - sc.MustGetNumber(); - x = sc.Number; - sc.MustGetStringName(","); - sc.MustGetNumber(); - y = sc.Number; - if (sc.CheckString(",")) - { - sc.MustGetString(); - if (sc.Compare("iwad")) iwadonly = true; - if (sc.Compare("iwadforced")) forced = iwadonly = true; - } - if (texno.isValid()) - { - FTexture * tex = GetTexture(texno); - - int lumpnum = tex->GetSourceLump(); - // We only want to change texture offsets for sprites in the IWAD or the file this lump originated from. - if (lumpnum >= 0 && lumpnum < Wads.GetNumLumps()) - { - int wadno = Wads.GetLumpFile(lumpnum); - if ((iwadonly && wadno >= Wads.GetIwadNum() && wadno <= Wads.GetMaxIwadNum()) || (!iwadonly && wadno == ofslumpno)) - { - if (wadno >= Wads.GetIwadNum() && wadno <= Wads.GetMaxIwadNum() && !forced && iwadonly) - { - memcpy(&sprid, &tex->Name[0], 4); - if (donotprocess.CheckKey(sprid)) continue; // do not alter sprites that only get partially replaced. - } - tex->_LeftOffset[1] = x; - tex->_TopOffset[1] = y; - } - } - } - } - } -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void FTextureManager::SpriteAdjustChanged() -{ - for (auto &texi : Textures) - { - auto tex = texi.Texture; - if (tex->GetLeftOffset(0) != tex->GetLeftOffset(1) || tex->GetTopOffset(0) != tex->GetTopOffset(1)) - { - tex->SetSpriteAdjust(); - } - } -} - -//=========================================================================== -// -// Examines the colormap to see if some of the colors have to be -// considered fullbright all the time. -// -//=========================================================================== - -void FTextureManager::GenerateGlobalBrightmapFromColormap() -{ - Wads.CheckNumForFullName("textures/tgapal", false, 0, true); - HasGlobalBrightmap = false; - int lump = Wads.CheckNumForName("COLORMAP"); - if (lump == -1) lump = Wads.CheckNumForName("COLORMAP", ns_colormaps); - if (lump == -1) return; - FMemLump cmap = Wads.ReadLump(lump); - uint8_t palbuffer[768]; - ReadPalette(Wads.GetNumForName("PLAYPAL"), palbuffer); - - const unsigned char *cmapdata = (const unsigned char *)cmap.GetMem(); - const uint8_t *paldata = palbuffer; - - const int black = 0; - const int white = ColorMatcher.Pick(255, 255, 255); - - - GlobalBrightmap.MakeIdentity(); - memset(GlobalBrightmap.Remap, white, 256); - for (int i = 0; i<256; i++) GlobalBrightmap.Palette[i] = PalEntry(255, 255, 255, 255); - for (int j = 0; j<32; j++) - { - for (int i = 0; i<256; i++) - { - // the palette comparison should be for ==0 but that gives false positives with Heretic - // and Hexen. - if (cmapdata[i + j * 256] != i || (paldata[3 * i]<10 && paldata[3 * i + 1]<10 && paldata[3 * i + 2]<10)) - { - GlobalBrightmap.Remap[i] = black; - GlobalBrightmap.Palette[i] = PalEntry(255, 0, 0, 0); - } - } - } - for (int i = 0; i<256; i++) - { - HasGlobalBrightmap |= GlobalBrightmap.Remap[i] == white; - if (GlobalBrightmap.Remap[i] == white) DPrintf(DMSG_NOTIFY, "Marked color %d as fullbright\n", i); - } -} - - -//========================================================================== -// -// -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(_TexMan, GetName) -{ - PARAM_PROLOGUE; - PARAM_INT(texid); - auto tex = TexMan.ByIndex(texid); - FString retval; - - if (tex != nullptr) - { - if (tex->GetName().IsNotEmpty()) retval = tex->GetName(); - else - { - // Textures for full path names do not have their own name, they merely link to the source lump. - auto lump = tex->GetSourceLump(); - if (Wads.GetLinkedTexture(lump) == tex) - retval = Wads.GetLumpFullName(lump); - } - } - ACTION_RETURN_STRING(retval); -} - -//========================================================================== -// -// -// -//========================================================================== - -static int GetTextureSize(int texid, int *py) -{ - auto tex = TexMan.ByIndex(texid); - int x, y; - if (tex != nullptr) - { - x = tex->GetDisplayWidth(); - y = tex->GetDisplayHeight(); - } - else x = y = -1; - if (py) *py = y; - return x; -} - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, GetSize, GetTextureSize) -{ - PARAM_PROLOGUE; - PARAM_INT(texid); - int x, y; - x = GetTextureSize(texid, &y); - if (numret > 0) ret[0].SetInt(x); - if (numret > 1) ret[1].SetInt(y); - return MIN(numret, 2); -} - -//========================================================================== -// -// -// -//========================================================================== -static void GetScaledSize(int texid, DVector2 *pvec) -{ - auto tex = TexMan.ByIndex(texid); - double x, y; - if (tex != nullptr) - { - x = tex->GetDisplayWidthDouble(); - y = tex->GetDisplayHeightDouble(); - } - else x = y = -1; - if (pvec) - { - pvec->X = x; - pvec->Y = y; - } -} - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, GetScaledSize, GetScaledSize) -{ - PARAM_PROLOGUE; - PARAM_INT(texid); - DVector2 vec; - GetScaledSize(texid, &vec); - ACTION_RETURN_VEC2(vec); -} - -//========================================================================== -// -// -// -//========================================================================== -static void GetScaledOffset(int texid, DVector2 *pvec) -{ - auto tex = TexMan.ByIndex(texid); - double x, y; - if (tex != nullptr) - { - x = tex->GetDisplayLeftOffsetDouble(); - y = tex->GetDisplayTopOffsetDouble(); - } - else x = y = -1; - if (pvec) - { - pvec->X = x; - pvec->Y = y; - } -} - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, GetScaledOffset, GetScaledOffset) -{ - PARAM_PROLOGUE; - PARAM_INT(texid); - DVector2 vec; - GetScaledOffset(texid, &vec); - ACTION_RETURN_VEC2(vec); -} - -//========================================================================== -// -// -// -//========================================================================== - -static int CheckRealHeight(int texid) -{ - auto tex = TexMan.ByIndex(texid); - if (tex != nullptr) return tex->CheckRealHeight(); - else return -1; -} - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, CheckRealHeight, CheckRealHeight) -{ - PARAM_PROLOGUE; - PARAM_INT(texid); - ACTION_RETURN_INT(CheckRealHeight(texid)); -} - -//========================================================================== -// -// FTextureID::operator+ -// Does not return invalid texture IDs -// -//========================================================================== - -FTextureID FTextureID::operator +(int offset) throw() -{ - if (!isValid()) return *this; - if (texnum + offset >= TexMan.NumTextures()) return FTextureID(-1); - return FTextureID(texnum + offset); -} diff --git a/src/gamedata/textures/textures.h b/src/gamedata/textures/textures.h deleted file mode 100644 index 4978ad81142..00000000000 --- a/src/gamedata/textures/textures.h +++ /dev/null @@ -1,790 +0,0 @@ -/* -** textures.h -** -**--------------------------------------------------------------------------- -** Copyright 2005-2016 Randy Heit -** Copyright 2005-2016 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __TEXTURES_H -#define __TEXTURES_H - -#include "doomtype.h" -#include "vectors.h" -#include "v_palette.h" -#include "r_data/v_colortables.h" -#include "colormatcher.h" -#include "r_data/renderstyle.h" -#include "r_data/r_translate.h" -#include "hwrenderer/textures/hw_texcontainer.h" -#include - -// 15 because 0th texture is our texture -#define MAX_CUSTOM_HW_SHADER_TEXTURES 15 - -typedef TMap SpriteHits; -class FImageSource; - -enum MaterialShaderIndex -{ - SHADER_Default, - SHADER_Warp1, - SHADER_Warp2, - SHADER_Brightmap, - SHADER_Specular, - SHADER_SpecularBrightmap, - SHADER_PBR, - SHADER_PBRBrightmap, - SHADER_Paletted, - SHADER_NoTexture, - SHADER_BasicFuzz, - SHADER_SmoothFuzz, - SHADER_SwirlyFuzz, - SHADER_TranslucentFuzz, - SHADER_JaggedFuzz, - SHADER_NoiseFuzz, - SHADER_SmoothNoiseFuzz, - SHADER_SoftwareFuzz, - FIRST_USER_SHADER -}; - -struct UserShaderDesc -{ - FString shader; - MaterialShaderIndex shaderType; - FString defines; - bool disablealphatest = false; -}; - -extern TArray usershaders; - - -struct FloatRect -{ - float left,top; - float width,height; - - - void Offset(float xofs,float yofs) - { - left+=xofs; - top+=yofs; - } - void Scale(float xfac,float yfac) - { - left*=xfac; - width*=xfac; - top*=yfac; - height*=yfac; - } -}; - -enum ECreateTexBufferFlags -{ - CTF_Expand = 2, // create buffer with a one-pixel wide border - CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture. - CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures. -}; - - - -class FBitmap; -struct FRemapTable; -struct FCopyInfo; -class FScanner; - -// Texture IDs -class FTextureManager; -class FTerrainTypeArray; -class IHardwareTexture; -class FMaterial; -class FMultipatchTextureBuilder; - -extern int r_spriteadjustSW, r_spriteadjustHW; - -class FNullTextureID : public FTextureID -{ -public: - FNullTextureID() : FTextureID(0) {} -}; - -// -// Animating textures and planes -// -// [RH] Expanded to work with a Hexen ANIMDEFS lump -// - -struct FAnimDef -{ - FTextureID BasePic; - uint16_t NumFrames; - uint16_t CurFrame; - uint8_t AnimType; - bool bDiscrete; // taken out of AnimType to have better control - uint64_t SwitchTime; // Time to advance to next frame - struct FAnimFrame - { - uint32_t SpeedMin; // Speeds are in ms, not tics - uint32_t SpeedRange; - FTextureID FramePic; - } Frames[1]; - enum - { - ANIM_Forward, - ANIM_Backward, - ANIM_OscillateUp, - ANIM_OscillateDown, - ANIM_Random - }; - - void SetSwitchTime (uint64_t mstime); -}; - -struct FSwitchDef -{ - FTextureID PreTexture; // texture to switch from - FSwitchDef *PairDef; // switch def to use to return to PreTexture - uint16_t NumFrames; // # of animation frames - bool QuestPanel; // Special texture for Strife mission - int Sound; // sound to play at start of animation. Changed to int to avoiud having to include s_sound here. - struct frame // Array of times followed by array of textures - { // actual length of each array is - uint16_t TimeMin; - uint16_t TimeRnd; - FTextureID Texture; - } frames[1]; -}; - -struct FDoorAnimation -{ - FTextureID BaseTexture; - FTextureID *TextureFrames; - int NumTextureFrames; - FName OpenSound; - FName CloseSound; -}; - -// Patches. -// A patch holds one or more columns. -// Patches are used for sprites and all masked pictures, and we compose -// textures from the TEXTURE1/2 lists of patches. -struct patch_t -{ - int16_t width; // bounding box size - int16_t height; - int16_t leftoffset; // pixels to the left of origin - int16_t topoffset; // pixels below the origin - uint32_t columnofs[]; // only [width] used - // the [0] is &columnofs[width] -}; - -// All FTextures present their data to the world in 8-bit format, but if -// the source data is something else, this is it. -enum FTextureFormat : uint32_t -{ - TEX_Pal, - TEX_Gray, - TEX_RGB, // Actually ARGB - - TEX_Count -}; - -class FSoftwareTexture; -class FGLRenderState; - -struct spriteframewithrotate; -class FSerializer; -namespace OpenGLRenderer -{ - class FGLRenderState; - class FHardwareTexture; -} - -union FContentIdBuilder -{ - uint64_t id; - struct - { - unsigned imageID : 24; - unsigned translation : 16; - unsigned expand : 1; - unsigned scaler : 4; - unsigned scalefactor : 4; - }; -}; - -struct FTextureBuffer -{ - uint8_t *mBuffer = nullptr; - int mWidth = 0; - int mHeight = 0; - uint64_t mContentId = 0; // unique content identifier. (Two images created from the same image source with the same settings will return the same value.) - - FTextureBuffer() = default; - - ~FTextureBuffer() - { - if (mBuffer) delete[] mBuffer; - } - - FTextureBuffer(const FTextureBuffer &other) = delete; - FTextureBuffer(FTextureBuffer &&other) - { - mBuffer = other.mBuffer; - mWidth = other.mWidth; - mHeight = other.mHeight; - mContentId = other.mContentId; - other.mBuffer = nullptr; - } - - FTextureBuffer& operator=(FTextureBuffer &&other) - { - mBuffer = other.mBuffer; - mWidth = other.mWidth; - mHeight = other.mHeight; - mContentId = other.mContentId; - other.mBuffer = nullptr; - return *this; - } - -}; - -// Base texture class -class FTexture -{ - // This is initialization code that is allowed to have full access. - friend void R_InitSpriteDefs (); - friend void R_InstallSprite (int num, spriteframewithrotate *sprtemp, int &maxframe); - friend class GLDefsParser; - friend class FMultipatchTextureBuilder; - - // The serializer also needs access to more specific info that shouldn't be accessible through the interface. - friend FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval); - - // For now only give access to classes which cannot be reworked yet. None of these should remain here when all is done. - friend class FSoftwareTexture; - friend class FWarpTexture; - friend class FMaterial; - friend class OpenGLRenderer::FGLRenderState; // For now this needs access to some fields in ApplyMaterial. This should be rerouted through the Material class - friend class VkRenderState; - friend class PolyRenderState; - friend struct FTexCoordInfo; - friend class OpenGLRenderer::FHardwareTexture; - friend class VkHardwareTexture; - friend class PolyHardwareTexture; - friend class FMultiPatchTexture; - friend class FSkyBox; - friend class FBrightmapTexture; - friend class FFont; - friend class FSpecialFont; - - -public: - static FTexture *CreateTexture(const char *name, int lumpnum, ETextureType usetype); - virtual ~FTexture (); - virtual FImageSource *GetImage() const { return nullptr; } - void AddAutoMaterials(); - void CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly); - - // These are mainly meant for 2D code which only needs logical information about the texture to position it properly. - int GetDisplayWidth() { return GetScaledWidth(); } - int GetDisplayHeight() { return GetScaledHeight(); } - double GetDisplayWidthDouble() { return GetScaledWidthDouble(); } - double GetDisplayHeightDouble() { return GetScaledHeightDouble(); } - int GetDisplayLeftOffset() { return GetScaledLeftOffset(0); } - int GetDisplayTopOffset() { return GetScaledTopOffset(0); } - double GetDisplayLeftOffsetDouble() { return GetScaledLeftOffsetDouble(0); } - double GetDisplayTopOffsetDouble() { return GetScaledTopOffsetDouble(0); } - - - bool isValid() const { return UseType != ETextureType::Null; } - bool isSWCanvas() const { return UseType == ETextureType::SWCanvas; } - bool isSkybox() const { return bSkybox; } - bool isFullbrightDisabled() const { return bDisableFullbright; } - bool isHardwareCanvas() const { return bHasCanvas; } // There's two here so that this can deal with software canvases in the hardware renderer later. - bool isCanvas() const { return bHasCanvas; } - bool isMiscPatch() const { return UseType == ETextureType::MiscPatch; } // only used by the intermission screen to decide whether to tile the background image or not. - int isWarped() const { return bWarped; } - int GetRotations() const { return Rotations; } - void SetRotations(int rot) { Rotations = int16_t(rot); } - bool isSprite() const { return UseType == ETextureType::Sprite || UseType == ETextureType::SkinSprite || UseType == ETextureType::Decal; } - - const FString &GetName() const { return Name; } - bool allowNoDecals() const { return bNoDecals; } - bool isScaled() const { return Scale.X != 1 || Scale.Y != 1; } - bool isMasked() const { return bMasked; } - int GetSkyOffset() const { return SkyOffset; } - FTextureID GetID() const { return id; } - PalEntry GetSkyCapColor(bool bottom); - FTexture *GetRawTexture(); - virtual int GetSourceLump() { return SourceLump; } // needed by the scripted GetName method. - void GetGlowColor(float *data); - bool isGlowing() const { return bGlowing; } - bool isAutoGlowing() const { return bAutoGlowing; } - int GetGlowHeight() const { return GlowHeight; } - bool isFullbright() const { return bFullbright; } - void CreateDefaultBrightmap(); - bool FindHoles(const unsigned char * buffer, int w, int h); - void SetUseType(ETextureType type) { UseType = type; } - ETextureType GetUseType() const { return UseType; } - - // Returns the whole texture, stored in column-major order - virtual TArray Get8BitPixels(bool alphatex); - virtual FBitmap GetBgraBitmap(PalEntry *remap, int *trans = nullptr); - -public: - static bool SmoothEdges(unsigned char * buffer,int w, int h); - static PalEntry averageColor(const uint32_t *data, int size, int maxout); - - - FSoftwareTexture *GetSoftwareTexture(); - -protected: - - DVector2 Scale; - - int SourceLump; - FTextureID id; - - FMaterial *Material[2] = { nullptr, nullptr }; -public: - FHardwareTextureContainer SystemTextures; -protected: - FSoftwareTexture *SoftwareTexture = nullptr; - - // None of the following pointers are owned by this texture, they are all controlled by the texture manager. - - // Offset-less version for COMPATF_MASKEDMIDTEX - FTexture *OffsetLess = nullptr; - // Paletted variant - FTexture *PalVersion = nullptr; - // Material layers - FTexture *Brightmap = nullptr; - FTexture *Normal = nullptr; // Normal map texture - FTexture *Specular = nullptr; // Specular light texture for the diffuse+normal+specular light model - FTexture *Metallic = nullptr; // Metalness texture for the physically based rendering (PBR) light model - FTexture *Roughness = nullptr; // Roughness texture for PBR - FTexture *AmbientOcclusion = nullptr; // Ambient occlusion texture for PBR - - FTexture *CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES] = { nullptr }; // Custom texture maps for custom hardware shaders - - FString Name; - ETextureType UseType; // This texture's primary purpose - - uint8_t bNoDecals:1; // Decals should not stick to texture - uint8_t bNoRemap0:1; // Do not remap color 0 (used by front layer of parallax skies) - uint8_t bWorldPanning:1; // Texture is panned in world units rather than texels - uint8_t bMasked:1; // Texture (might) have holes - uint8_t bAlphaTexture:1; // Texture is an alpha channel without color information - uint8_t bHasCanvas:1; // Texture is based off FCanvasTexture - uint8_t bWarped:2; // This is a warped texture. Used to avoid multiple warps on one texture - uint8_t bComplex:1; // Will be used to mark extended MultipatchTextures that have to be - // fully composited before subjected to any kind of postprocessing instead of - // doing it per patch. - uint8_t bMultiPatch:2; // This is a multipatch texture (we really could use real type info for textures...) - uint8_t bFullNameTexture : 1; - uint8_t bBrightmapChecked : 1; // Set to 1 if brightmap has been checked - uint8_t bGlowing : 1; // Texture glow color - uint8_t bAutoGlowing : 1; // Glow info is determined from texture image. - uint8_t bFullbright : 1; // always draw fullbright - uint8_t bDisableFullbright : 1; // This texture will not be displayed as fullbright sprite - uint8_t bSkybox : 1; // is a cubic skybox - uint8_t bNoCompress : 1; - uint8_t bNoExpand : 1; - int8_t bTranslucent : 2; - bool bHiresHasColorKey = false; // Support for old color-keyed Doomsday textures - - uint16_t Rotations; - int16_t SkyOffset; - FloatRect *areas = nullptr; - int areacount = 0; - int GlowHeight = 128; - PalEntry GlowColor = 0; - int HiresLump = -1; // For external hires textures. - float Glossiness = 10.f; - float SpecularLevel = 0.1f; - float shaderspeed = 1.f; - int shaderindex = 0; - - // This is only used for the null texture and for Heretic's skies. - void SetSize(int w, int h) - { - Width = w; - Height = h; - } - - void SetSpeed(float fac) { shaderspeed = fac; } - - int GetWidth () { return Width; } - int GetHeight () { return Height; } - - int GetScaledWidth () { int foo = int((Width * 2) / Scale.X); return (foo >> 1) + (foo & 1); } - int GetScaledHeight () { int foo = int((Height * 2) / Scale.Y); return (foo >> 1) + (foo & 1); } - double GetScaledWidthDouble () { return Width / Scale.X; } - double GetScaledHeightDouble () { return Height / Scale.Y; } - double GetScaleY() const { return Scale.Y; } - - // Now with improved offset adjustment. - int GetLeftOffset(int adjusted) { return _LeftOffset[adjusted]; } - int GetTopOffset(int adjusted) { return _TopOffset[adjusted]; } - int GetScaledLeftOffset (int adjusted) { int foo = int((_LeftOffset[adjusted] * 2) / Scale.X); return (foo >> 1) + (foo & 1); } - int GetScaledTopOffset (int adjusted) { int foo = int((_TopOffset[adjusted] * 2) / Scale.Y); return (foo >> 1) + (foo & 1); } - double GetScaledLeftOffsetDouble(int adjusted) { return _LeftOffset[adjusted] / Scale.X; } - double GetScaledTopOffsetDouble(int adjusted) { return _TopOffset[adjusted] / Scale.Y; } - - // Interfaces for the different renderers. Everything that needs to check renderer-dependent offsets - // should use these, so that if changes are needed, this is the only place to edit. - - // For the hardware renderer. The software renderer's have been offloaded to FSoftwareTexture - int GetLeftOffsetHW() { return _LeftOffset[r_spriteadjustHW]; } - int GetTopOffsetHW() { return _TopOffset[r_spriteadjustHW]; } - - virtual void ResolvePatches() {} - - void SetFrontSkyLayer(); - - static void InitGrayMap(); - - void CopySize(FTexture *BaseTexture) - { - Width = BaseTexture->GetWidth(); - Height = BaseTexture->GetHeight(); - _TopOffset[0] = BaseTexture->_TopOffset[0]; - _TopOffset[1] = BaseTexture->_TopOffset[1]; - _LeftOffset[0] = BaseTexture->_LeftOffset[0]; - _LeftOffset[1] = BaseTexture->_LeftOffset[1]; - Scale = BaseTexture->Scale; - } - - void SetScaledSize(int fitwidth, int fitheight); - void SetScale(const DVector2 &scale) - { - Scale = scale; - } - -protected: - uint16_t Width, Height; - int16_t _LeftOffset[2], _TopOffset[2]; - - FTexture (const char *name = NULL, int lumpnum = -1); - -public: - FTextureBuffer CreateTexBuffer(int translation, int flags = 0); - bool GetTranslucency(); - -private: - int CheckDDPK3(); - int CheckExternalFile(bool & hascolorkey); - - bool bSWSkyColorDone = false; - PalEntry FloorSkyColor; - PalEntry CeilingSkyColor; - -public: - - void CheckTrans(unsigned char * buffer, int size, int trans); - bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch); - int CheckRealHeight(); - void SetSpriteAdjust(); - - friend class FTextureManager; -}; - - -class FxAddSub; -// Texture manager -class FTextureManager -{ - friend class FxAddSub; // needs access to do a bounds check on the texture ID. -public: - FTextureManager (); - ~FTextureManager (); - -private: - int ResolveLocalizedTexture(int texnum); - int PalCheck(int tex); - - FTexture *InternalGetTexture(int texnum, bool animate, bool localize, bool palettesubst) - { - if ((unsigned)texnum >= Textures.Size()) return nullptr; - if (animate) texnum = Translation[texnum]; - if (localize && Textures[texnum].HasLocalization) texnum = ResolveLocalizedTexture(texnum); - if (palettesubst) texnum = PalCheck(texnum); - return Textures[texnum].Texture; - } -public: - // This only gets used in UI code so we do not need PALVERS handling. - FTexture *GetTextureByName(const char *name, bool animate = false) - { - FTextureID texnum = GetTextureID (name, ETextureType::MiscPatch); - return InternalGetTexture(texnum.GetIndex(), animate, true, false); - } - - FTexture *GetTexture(FTextureID texnum, bool animate = false) - { - return InternalGetTexture(texnum.GetIndex(), animate, true, false); - } - - // This is the only access function that should be used inside the software renderer. - FTexture *GetPalettedTexture(FTextureID texnum, bool animate) - { - return InternalGetTexture(texnum.GetIndex(), animate, true, true); - } - - FTexture *ByIndex(int i, bool animate = false) - { - return InternalGetTexture(i, animate, true, false); - } - - FTexture *FindTexture(const char *texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny); - bool OkForLocalization(FTextureID texnum, const char *substitute); - - void FlushAll(); - - - enum - { - TEXMAN_TryAny = 1, - TEXMAN_Overridable = 2, - TEXMAN_ReturnFirst = 4, - TEXMAN_AllowSkins = 8, - TEXMAN_ShortNameOnly = 16, - TEXMAN_DontCreate = 32, - TEXMAN_Localize = 64 - }; - - enum - { - HIT_Wall = 1, - HIT_Flat = 2, - HIT_Sky = 4, - HIT_Sprite = 8, - - HIT_Columnmode = HIT_Wall|HIT_Sky|HIT_Sprite - }; - - FTextureID CheckForTexture (const char *name, ETextureType usetype, BITFIELD flags=TEXMAN_TryAny); - FTextureID GetTextureID (const char *name, ETextureType usetype, BITFIELD flags=0); - int ListTextures (const char *name, TArray &list, bool listall = false); - - void AddGroup(int wadnum, int ns, ETextureType usetype); - void AddPatches (int lumpnum); - void AddHiresTextures (int wadnum); - void LoadTextureDefs(int wadnum, const char *lumpname, FMultipatchTextureBuilder &build); - void ParseColorization(FScanner& sc); - void ParseTextureDef(int remapLump, FMultipatchTextureBuilder &build); - void SortTexturesByType(int start, int end); - bool AreTexturesCompatible (FTextureID picnum1, FTextureID picnum2); - void AddLocalizedVariants(); - - FTextureID CreateTexture (int lumpnum, ETextureType usetype=ETextureType::Any); // Also calls AddTexture - FTextureID AddTexture (FTexture *texture); - FTextureID GetDefaultTexture() const { return DefaultTexture; } - - void LoadTextureX(int wadnum, FMultipatchTextureBuilder &build); - void AddTexturesForWad(int wadnum, FMultipatchTextureBuilder &build); - void Init(); - void DeleteAll(); - void SpriteAdjustChanged(); - - void ReplaceTexture (FTextureID picnum, FTexture *newtexture, bool free); - - int NumTextures () const { return (int)Textures.Size(); } - - void UpdateAnimations (uint64_t mstime); - int GuesstimateNumTextures (); - - FSwitchDef *FindSwitch (FTextureID texture); - FDoorAnimation *FindAnimatedDoor (FTextureID picnum); - - TextureManipulation* GetTextureManipulation(FName name) - { - return tmanips.CheckKey(name); - } - void InsertTextureManipulation(FName cname, TextureManipulation tm) - { - tmanips.Insert(cname, tm); - } - void RemoveTextureManipulation(FName cname) - { - tmanips.Remove(cname); - } - -private: - - // texture counting - int CountTexturesX (); - int CountLumpTextures (int lumpnum); - void AdjustSpriteOffsets(); - - // Build tiles - void AddTiles (const FString &pathprefix, const void *, int translation); - //int CountBuildTiles (); - void InitBuildTiles (); - - // Animation stuff - FAnimDef *AddAnim (FAnimDef *anim); - void FixAnimations (); - void InitAnimated (); - void InitAnimDefs (); - FAnimDef *AddSimpleAnim (FTextureID picnum, int animcount, uint32_t speedmin, uint32_t speedrange=0); - FAnimDef *AddComplexAnim (FTextureID picnum, const TArray &frames); - void ParseAnim (FScanner &sc, ETextureType usetype); - FAnimDef *ParseRangeAnim (FScanner &sc, FTextureID picnum, ETextureType usetype, bool missing); - void ParsePicAnim (FScanner &sc, FTextureID picnum, ETextureType usetype, bool missing, TArray &frames); - void ParseWarp(FScanner &sc); - void ParseCameraTexture(FScanner &sc); - FTextureID ParseFramenum (FScanner &sc, FTextureID basepicnum, ETextureType usetype, bool allowMissing); - void ParseTime (FScanner &sc, uint32_t &min, uint32_t &max); - FTexture *Texture(FTextureID id) { return Textures[id.GetIndex()].Texture; } - void SetTranslation (FTextureID fromtexnum, FTextureID totexnum); - void ParseAnimatedDoor(FScanner &sc); - - void InitPalettedVersions(); - void GenerateGlobalBrightmapFromColormap(); - - // Switches - - void InitSwitchList (); - void ProcessSwitchDef (FScanner &sc); - FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad); - void AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2); - - struct TextureHash - { - FTexture *Texture; - int HashNext; - bool HasLocalization; - }; - enum { HASH_END = -1, HASH_SIZE = 1027 }; - TArray Textures; - TMap LocalizedTextures; - TArray Translation; - int HashFirst[HASH_SIZE]; - FTextureID DefaultTexture; - TArray FirstTextureForFile; - TArray > BuildTileData; - - TArray mSwitchDefs; - TArray mAnimatedDoors; - TMap tmanips; - -public: - TArray mAnimations; - - bool HasGlobalBrightmap; - FRemapTable GlobalBrightmap; - short sintable[2048]; // for texture warping - enum - { - SINMASK = 2047 - }; - - FTextureID glLight; - FTextureID glPart2; - FTextureID glPart; - FTextureID mirrorTexture; - -}; - - -// A texture that can be drawn to. -class DCanvas; -class AActor; - -class FCanvasTexture : public FTexture -{ -public: - FCanvasTexture(const char *name, int width, int height) - { - Name = name; - Width = width; - Height = height; - - bMasked = false; - bHasCanvas = true; - bTranslucent = false; - bNoExpand = true; - UseType = ETextureType::Wall; - } - - void NeedUpdate() { bNeedsUpdate = true; } - void SetUpdated(bool rendertype) { bNeedsUpdate = false; bFirstUpdate = false; bLastUpdateType = rendertype; } - -protected: - - bool bLastUpdateType = false; - bool bNeedsUpdate = true; -public: - bool bFirstUpdate = true; - - friend struct FCanvasTextureInfo; -}; - -// A wrapper around a hardware texture, to allow using it in the 2D drawing interface. -class FWrapperTexture : public FTexture -{ - int Format; -public: - FWrapperTexture(int w, int h, int bits = 1); - IHardwareTexture *GetSystemTexture() - { - return SystemTextures.GetHardwareTexture(0, false); - } - - int GetColorFormat() const - { - return Format; - } -}; - -extern FTextureManager TexMan; - -struct FTexCoordInfo -{ - int mRenderWidth; - int mRenderHeight; - int mWidth; - FVector2 mScale; - FVector2 mTempScale; - bool mWorldPanning; - - float FloatToTexU(float v) const { return v / mRenderWidth; } - float FloatToTexV(float v) const { return v / mRenderHeight; } - float RowOffset(float ofs) const; - float TextureOffset(float ofs) const; - float TextureAdjustWidth() const; - void GetFromTexture(FTexture *tex, float x, float y, bool forceworldpanning); -}; - - - -#endif - - diff --git a/src/gamedata/umapinfo.cpp b/src/gamedata/umapinfo.cpp index 38046b0053c..08e16d9f88b 100644 --- a/src/gamedata/umapinfo.cpp +++ b/src/gamedata/umapinfo.cpp @@ -19,7 +19,7 @@ #include #include -#include "w_wad.h" +#include "filesystem.h" #include "g_level.h" #include "r_defs.h" #include "p_setup.h" @@ -42,6 +42,7 @@ struct UMapEntry FString InterText; FString InterTextSecret; TArray BossActions; + bool BossCleared = false; char levelpic[9] = ""; char nextmap[9] = ""; @@ -193,7 +194,7 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) else if (!pname.CompareNoCase("partime")) { scanner.MustGetValue(false); - mape->partime = TICRATE * scanner.Number; + mape->partime = scanner.Number; } else if (!pname.CompareNoCase("intertext")) { @@ -229,7 +230,7 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) if (split.Size() > 1) { - epi.mEpisodeName = strbin1(split[1]); + epi.mEpisodeName = strbin1(split[1].GetChars()); } if (split.Size() > 2 && split[2].IsNotEmpty()) { @@ -268,6 +269,7 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) // mark level free of boss actions classnum = special = tag = -1; mape->BossActions.Clear(); + mape->BossCleared = true; } else { @@ -387,7 +389,7 @@ void CommitUMapinfo(level_info_t *defaultinfo) { for (auto &map : Maps) { - auto levelinfo = FindLevelInfo(map.MapName, false); + auto levelinfo = FindLevelInfo(map.MapName.GetChars(), false); if (levelinfo == nullptr) { // Map did not exist yet. @@ -421,7 +423,7 @@ void CommitUMapinfo(level_info_t *defaultinfo) } if (name != NAME_None) { - levelinfo->NextMap.Format("enDSeQ%04x", int(name)); + levelinfo->NextMap.Format("enDSeQ%04x", name.GetIndex()); } } @@ -441,16 +443,19 @@ void CommitUMapinfo(level_info_t *defaultinfo) if (map.partime > 0) levelinfo->partime = map.partime; if (map.enterpic[0]) levelinfo->EnterPic = map.enterpic; if (map.exitpic[0]) levelinfo->ExitPic = map.exitpic; + /* UMAPINFO's intermusic is for the text screen, not the summary. if (map.intermusic[0]) { levelinfo->InterMusic = map.intermusic; levelinfo->intermusicorder = 0; } - if (map.BossActions.Size() > 0) + */ + if (map.BossActions.Size() > 0 || map.BossCleared) { // Setting a boss action will deactivate the flag based monster actions. levelinfo->specialactions = std::move(map.BossActions); levelinfo->flags &= ~(LEVEL_BRUISERSPECIAL | LEVEL_CYBORGSPECIAL | LEVEL_SPIDERSPECIAL | LEVEL_MAP07SPECIAL | LEVEL_MINOTAURSPECIAL | LEVEL_HEADSPECIAL | LEVEL_SORCERER2SPECIAL | LEVEL_SPECACTIONSMASK | LEVEL_SPECKILLMONSTERS); + levelinfo->flags3 &= ~(LEVEL3_E1M8SPECIAL | LEVEL3_E2M8SPECIAL | LEVEL3_E3M8SPECIAL | LEVEL3_E4M8SPECIAL | LEVEL3_E4M6SPECIAL); } const int exflags = FExitText::DEF_TEXT | FExitText::DEF_BACKDROP | FExitText::DEF_MUSIC; diff --git a/src/gamedata/w_wad.cpp b/src/gamedata/w_wad.cpp deleted file mode 100644 index 95926835032..00000000000 --- a/src/gamedata/w_wad.cpp +++ /dev/null @@ -1,1776 +0,0 @@ -/* -** w_wad.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** Copyright 2005-2009 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include - -#include "doomtype.h" -#include "m_argv.h" -#include "cmdlib.h" -#include "c_dispatch.h" -#include "w_wad.h" -#include "m_crc32.h" -#include "v_text.h" -#include "gi.h" -#include "resourcefiles/resourcefile.h" -#include "md5.h" -#include "doomstat.h" -#include "vm.h" - -// MACROS ------------------------------------------------------------------ - -#define NULL_INDEX (0xffffffff) - -// -// WADFILE I/O related stuff. -// -struct FWadCollection::LumpRecord -{ - int wadnum; - FResourceLump *lump; -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- -extern bool nospriterename; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static void PrintLastError (); - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FWadCollection Wads; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// uppercoppy -// -// [RH] Copy up to 8 chars, upper-casing them in the process -//========================================================================== - -void uppercopy (char *to, const char *from) -{ - int i; - - for (i = 0; i < 8 && from[i]; i++) - to[i] = toupper (from[i]); - for (; i < 8; i++) - to[i] = 0; -} - -FWadCollection::FWadCollection () -{ -} - -FWadCollection::~FWadCollection () -{ - DeleteAll(); -} - -void FWadCollection::DeleteAll () -{ - LumpInfo.Clear(); - NumLumps = 0; - - // we must count backward to ensure that embedded WADs are deleted before - // the ones that contain their data. - for (int i = Files.Size() - 1; i >= 0; --i) - { - delete Files[i]; - } - Files.Clear(); -} - -//========================================================================== -// -// W_InitMultipleFiles -// -// Pass a null terminated list of files to use. All files are optional, -// but at least one file must be found. Lump names can appear multiple -// times. The name searcher looks backwards, so a later file can -// override an earlier one. -// -//========================================================================== - -void FWadCollection::InitMultipleFiles (TArray &filenames, const TArray &deletelumps) -{ - int numfiles; - - // open all the files, load headers, and count lumps - DeleteAll(); - numfiles = 0; - - for(unsigned i=0;iGetHash().GetChars()); - MoveLumpsInFolder(path); - } - - NumLumps = LumpInfo.Size(); - if (NumLumps == 0) - { - I_FatalError ("W_InitMultipleFiles: no files found"); - } - RenameNerve(); - RenameSprites(deletelumps); - FixMacHexen(); - - // [RH] Set up hash table - Hashes.Resize(6 * NumLumps); - FirstLumpIndex = &Hashes[0]; - NextLumpIndex = &Hashes[NumLumps]; - FirstLumpIndex_FullName = &Hashes[NumLumps*2]; - NextLumpIndex_FullName = &Hashes[NumLumps*3]; - FirstLumpIndex_NoExt = &Hashes[NumLumps*4]; - NextLumpIndex_NoExt = &Hashes[NumLumps*5]; - InitHashChains (); - LumpInfo.ShrinkToFit(); - Files.ShrinkToFit(); -} - -//----------------------------------------------------------------------- -// -// Adds an external file to the lump list but not to the hash chains -// It's just a simple means to assign a lump number to some file so that -// the texture manager can read from it. -// -//----------------------------------------------------------------------- - -int FWadCollection::AddExternalFile(const char *filename) -{ - FResourceLump *lump = new FExternalLump(filename); - - FWadCollection::LumpRecord *lumprec = &LumpInfo[LumpInfo.Reserve(1)]; - lumprec->lump = lump; - lumprec->wadnum = -1; - return LumpInfo.Size()-1; // later -} - -//========================================================================== -// -// W_AddFile -// -// Files with a .wad extension are wadlink files with multiple lumps, -// other files are single lumps with the base filename for the lump name. -// -// [RH] Removed reload hack -//========================================================================== - -void FWadCollection::AddFile (const char *filename, FileReader *wadr) -{ - int startlump; - bool isdir = false; - FileReader wadreader; - - if (wadr == nullptr) - { - // Does this exist? If so, is it a directory? - if (!DirEntryExists(filename, &isdir)) - { - Printf(TEXTCOLOR_RED "%s: File or Directory not found\n", filename); - PrintLastError(); - return; - } - - if (!isdir) - { - if (!wadreader.OpenFile(filename)) - { // Didn't find file - Printf (TEXTCOLOR_RED "%s: File not found\n", filename); - PrintLastError (); - return; - } - } - } - else wadreader = std::move(*wadr); - - if (!batchrun) Printf (" adding %s", filename); - startlump = NumLumps; - - FResourceFile *resfile; - - if (!isdir) - resfile = FResourceFile::OpenResourceFile(filename, wadreader); - else - resfile = FResourceFile::OpenDirectory(filename); - - if (resfile != NULL) - { - uint32_t lumpstart = LumpInfo.Size(); - - resfile->SetFirstLump(lumpstart); - for (uint32_t i=0; i < resfile->LumpCount(); i++) - { - FResourceLump *lump = resfile->GetLump(i); - FWadCollection::LumpRecord *lump_p = &LumpInfo[LumpInfo.Reserve(1)]; - - lump_p->lump = lump; - lump_p->wadnum = Files.Size(); - } - - if (static_cast(Files.Size()) == GetIwadNum() && gameinfo.gametype == GAME_Strife && gameinfo.flags & GI_SHAREWARE) - { - resfile->FindStrifeTeaserVoices(); - } - Files.Push(resfile); - - for (uint32_t i=0; i < resfile->LumpCount(); i++) - { - FResourceLump *lump = resfile->GetLump(i); - if (lump->Flags & LUMPF_EMBEDDED) - { - FString path; - path.Format("%s:%s", filename, lump->FullName.GetChars()); - auto embedded = lump->NewReader(); - AddFile(path, &embedded); - } - } - - if (hashfile) - { - uint8_t cksum[16]; - char cksumout[33]; - memset(cksumout, 0, sizeof(cksumout)); - - if (wadreader.isOpen()) - { - MD5Context md5; - wadreader.Seek(0, FileReader::SeekSet); - md5.Update(wadreader, (unsigned)wadreader.GetLength()); - md5.Final(cksum); - - for (size_t j = 0; j < sizeof(cksum); ++j) - { - sprintf(cksumout + (j * 2), "%02X", cksum[j]); - } - - fprintf(hashfile, "file: %s, hash: %s, size: %d\n", filename, cksumout, (int)wadreader.GetLength()); - } - - else - fprintf(hashfile, "file: %s, Directory structure\n", filename); - - for (uint32_t i = 0; i < resfile->LumpCount(); i++) - { - FResourceLump *lump = resfile->GetLump(i); - - if (!(lump->Flags & LUMPF_EMBEDDED)) - { - MD5Context md5; - auto reader = lump->NewReader(); - md5.Update(reader, lump->LumpSize); - md5.Final(cksum); - - for (size_t j = 0; j < sizeof(cksum); ++j) - { - sprintf(cksumout + (j * 2), "%02X", cksum[j]); - } - - fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %d\n", filename, - lump->FullName.IsNotEmpty() ? lump->FullName.GetChars() : lump->Name, - cksumout, lump->LumpSize); - } - } - } - return; - } -} - -//========================================================================== -// -// W_CheckIfWadLoaded -// -// Returns true if the specified wad is loaded, false otherwise. -// If a fully-qualified path is specified, then the wad must match exactly. -// Otherwise, any wad with that name will work, whatever its path. -// Returns the wads index if found, or -1 if not. -// -//========================================================================== - -int FWadCollection::CheckIfWadLoaded (const char *name) -{ - unsigned int i; - - if (strrchr (name, '/') != NULL) - { - for (i = 0; i < Files.Size(); ++i) - { - if (stricmp (GetWadFullName (i), name) == 0) - { - return i; - } - } - } - else - { - for (i = 0; i < Files.Size(); ++i) - { - if (stricmp (GetWadName (i), name) == 0) - { - return i; - } - } - } - return -1; -} - -//========================================================================== -// -// W_NumLumps -// -//========================================================================== - -int FWadCollection::GetNumLumps () const -{ - return NumLumps; -} - -DEFINE_ACTION_FUNCTION(_Wads, GetNumLumps) -{ - PARAM_PROLOGUE; - ACTION_RETURN_INT(Wads.GetNumLumps()); -} - -//========================================================================== -// -// GetNumFiles -// -//========================================================================== - -int FWadCollection::GetNumWads () const -{ - return Files.Size(); -} - -//========================================================================== -// -// W_CheckNumForName -// -// Returns -1 if name not found. The version with a third parameter will -// look exclusively in the specified wad for the lump. -// -// [RH] Changed to use hash lookup ala BOOM instead of a linear search -// and namespace parameter -//========================================================================== - -int FWadCollection::CheckNumForName (const char *name, int space) -{ - union - { - char uname[8]; - uint64_t qname; - }; - uint32_t i; - - if (name == NULL) - { - return -1; - } - - // Let's not search for names that are longer than 8 characters and contain path separators - // They are almost certainly full path names passed to this function. - if (strlen(name) > 8 && strpbrk(name, "/.")) - { - return -1; - } - - uppercopy (uname, name); - i = FirstLumpIndex[LumpNameHash (uname) % NumLumps]; - - while (i != NULL_INDEX) - { - FResourceLump *lump = LumpInfo[i].lump; - - if (lump->qwName == qname) - { - if (lump->Namespace == space) break; - // If the lump is from one of the special namespaces exclusive to Zips - // the check has to be done differently: - // If we find a lump with this name in the global namespace that does not come - // from a Zip return that. WADs don't know these namespaces and single lumps must - // work as well. - if (space > ns_specialzipdirectory && lump->Namespace == ns_global && - !(lump->Flags & LUMPF_ZIPFILE)) break; - } - i = NextLumpIndex[i]; - } - - return i != NULL_INDEX ? i : -1; -} - -int FWadCollection::CheckNumForName (const char *name, int space, int wadnum, bool exact) -{ - FResourceLump *lump; - union - { - char uname[8]; - uint64_t qname; - }; - uint32_t i; - - if (wadnum < 0) - { - return CheckNumForName (name, space); - } - - uppercopy (uname, name); - i = FirstLumpIndex[LumpNameHash (uname) % NumLumps]; - - // If exact is true if will only find lumps in the same WAD, otherwise - // also those in earlier WADs. - - while (i != NULL_INDEX && - (lump = LumpInfo[i].lump, lump->qwName != qname || - lump->Namespace != space || - (exact? (LumpInfo[i].wadnum != wadnum) : (LumpInfo[i].wadnum > wadnum)) )) - { - i = NextLumpIndex[i]; - } - - return i != NULL_INDEX ? i : -1; -} - -DEFINE_ACTION_FUNCTION(_Wads, CheckNumForName) -{ - PARAM_PROLOGUE; - PARAM_STRING(name); - PARAM_INT(ns); - PARAM_INT(wadnum); - PARAM_BOOL(exact); - ACTION_RETURN_INT(Wads.CheckNumForName(name, ns, wadnum, exact)); -} -//========================================================================== -// -// W_GetNumForName -// -// Calls W_CheckNumForName, but bombs out if not found. -// -//========================================================================== - -int FWadCollection::GetNumForName (const char *name, int space) -{ - int i; - - i = CheckNumForName (name, space); - - if (i == -1) - I_Error ("GetNumForName: %s not found!", name); - - return i; -} - - -//========================================================================== -// -// W_CheckNumForFullName -// -// Same as above but looks for a fully qualified name from a .zip -// These don't care about namespaces though because those are part -// of the path. -// -//========================================================================== - -int FWadCollection::CheckNumForFullName (const char *name, bool trynormal, int namespc, bool ignoreext) -{ - uint32_t i; - - if (name == NULL) - { - return -1; - } - uint32_t *fli = ignoreext ? FirstLumpIndex_NoExt : FirstLumpIndex_FullName; - uint32_t *nli = ignoreext ? NextLumpIndex_NoExt : NextLumpIndex_FullName; - auto len = strlen(name); - - for (i = fli[MakeKey(name) % NumLumps]; i != NULL_INDEX; i = nli[i]) - { - if (strnicmp(name, LumpInfo[i].lump->FullName, len)) continue; - if (LumpInfo[i].lump->FullName[len] == 0) break; // this is a full match - if (ignoreext && LumpInfo[i].lump->FullName[len] == '.') - { - // is this the last '.' in the last path element, indicating that the remaining part of the name is only an extension? - if (strpbrk(LumpInfo[i].lump->FullName.GetChars() + len + 1, "./") == nullptr) break; - } - } - - if (i != NULL_INDEX) return i; - - if (trynormal && strlen(name) <= 8 && !strpbrk(name, "./")) - { - return CheckNumForName(name, namespc); - } - return -1; -} - -DEFINE_ACTION_FUNCTION(_Wads, CheckNumForFullName) -{ - PARAM_PROLOGUE; - PARAM_STRING(name); - ACTION_RETURN_INT(Wads.CheckNumForFullName(name)); -} - -int FWadCollection::CheckNumForFullName (const char *name, int wadnum) -{ - uint32_t i; - - if (wadnum < 0) - { - return CheckNumForFullName (name); - } - - i = FirstLumpIndex_FullName[MakeKey (name) % NumLumps]; - - while (i != NULL_INDEX && - (stricmp(name, LumpInfo[i].lump->FullName) || LumpInfo[i].wadnum != wadnum)) - { - i = NextLumpIndex_FullName[i]; - } - - return i != NULL_INDEX ? i : -1; -} - -//========================================================================== -// -// W_GetNumForFullName -// -// Calls W_CheckNumForFullName, but bombs out if not found. -// -//========================================================================== - -int FWadCollection::GetNumForFullName (const char *name) -{ - int i; - - i = CheckNumForFullName (name); - - if (i == -1) - I_Error ("GetNumForFullName: %s not found!", name); - - return i; -} - -//========================================================================== -// -// link a texture with a given lump -// -//========================================================================== - -void FWadCollection::SetLinkedTexture(int lump, FTexture *tex) -{ - if ((size_t)lump < NumLumps) - { - FResourceLump *reslump = LumpInfo[lump].lump; - reslump->LinkedTexture = tex; - } -} - -//========================================================================== -// -// retrieve linked texture -// -//========================================================================== - -FTexture *FWadCollection::GetLinkedTexture(int lump) -{ - if ((size_t)lump < NumLumps) - { - FResourceLump *reslump = LumpInfo[lump].lump; - return reslump->LinkedTexture; - } - return NULL; -} - -//========================================================================== -// -// W_LumpLength -// -// Returns the buffer size needed to load the given lump. -// -//========================================================================== - -int FWadCollection::LumpLength (int lump) const -{ - if ((size_t)lump >= NumLumps) - { - I_Error ("W_LumpLength: %i >= NumLumps",lump); - } - - return LumpInfo[lump].lump->LumpSize; -} - -//========================================================================== -// -// GetLumpOffset -// -// Returns the offset from the beginning of the file to the lump. -// Returns -1 if the lump is compressed or can't be read directly -// -//========================================================================== - -int FWadCollection::GetLumpOffset (int lump) -{ - if ((size_t)lump >= NumLumps) - { - I_Error ("GetLumpOffset: %i >= NumLumps",lump); - } - - return LumpInfo[lump].lump->GetFileOffset(); -} - -//========================================================================== -// -// GetLumpOffset -// -//========================================================================== - -int FWadCollection::GetLumpFlags (int lump) -{ - if ((size_t)lump >= NumLumps) - { - return 0; - } - - return LumpInfo[lump].lump->Flags; -} - -//========================================================================== -// -// W_LumpNameHash -// -// NOTE: s should already be uppercase, in contrast to the BOOM version. -// -// Hash function used for lump names. -// Must be mod'ed with table size. -// Can be used for any 8-character names. -// -//========================================================================== - -uint32_t FWadCollection::LumpNameHash (const char *s) -{ - const uint32_t *table = GetCRCTable ();; - uint32_t hash = 0xffffffff; - int i; - - for (i = 8; i > 0 && *s; --i, ++s) - { - hash = CRC1 (hash, *s, table); - } - return hash ^ 0xffffffff; -} - -//========================================================================== -// -// W_InitHashChains -// -// Prepares the lumpinfos for hashing. -// (Hey! This looks suspiciously like something from Boom! :-) -// -//========================================================================== - -void FWadCollection::InitHashChains (void) -{ - char name[8]; - unsigned int i, j; - - // Mark all buckets as empty - memset (FirstLumpIndex, 255, NumLumps*sizeof(FirstLumpIndex[0])); - memset (NextLumpIndex, 255, NumLumps*sizeof(NextLumpIndex[0])); - memset (FirstLumpIndex_FullName, 255, NumLumps*sizeof(FirstLumpIndex_FullName[0])); - memset (NextLumpIndex_FullName, 255, NumLumps*sizeof(NextLumpIndex_FullName[0])); - memset(FirstLumpIndex_NoExt, 255, NumLumps * sizeof(FirstLumpIndex_NoExt[0])); - memset(NextLumpIndex_NoExt, 255, NumLumps * sizeof(NextLumpIndex_NoExt[0])); - - // Now set up the chains - for (i = 0; i < (unsigned)NumLumps; i++) - { - uppercopy (name, LumpInfo[i].lump->Name); - j = LumpNameHash (name) % NumLumps; - NextLumpIndex[i] = FirstLumpIndex[j]; - FirstLumpIndex[j] = i; - - // Do the same for the full paths - if (LumpInfo[i].lump->FullName.IsNotEmpty()) - { - j = MakeKey(LumpInfo[i].lump->FullName) % NumLumps; - NextLumpIndex_FullName[i] = FirstLumpIndex_FullName[j]; - FirstLumpIndex_FullName[j] = i; - - FString nameNoExt = LumpInfo[i].lump->FullName; - auto dot = nameNoExt.LastIndexOf('.'); - auto slash = nameNoExt.LastIndexOf('/'); - if (dot > slash) nameNoExt.Truncate(dot); - - j = MakeKey(nameNoExt) % NumLumps; - NextLumpIndex_NoExt[i] = FirstLumpIndex_NoExt[j]; - FirstLumpIndex_NoExt[j] = i; - - } - } -} - -//========================================================================== -// -// RenameSprites -// -// Renames sprites in IWADs so that unique actors can have unique sprites, -// making it possible to import any actor from any game into any other -// game without jumping through hoops to resolve duplicate sprite names. -// You just need to know what the sprite's new name is. -// -//========================================================================== - -void FWadCollection::RenameSprites (const TArray &deletelumps) -{ - bool renameAll; - bool MNTRZfound = false; - const char *altbigfont = gameinfo.gametype == GAME_Strife? "SBIGFONT" : (gameinfo.gametype & GAME_Raven)? "HBIGFONT" : "DBIGFONT"; - - static const uint32_t HereticRenames[] = - { MAKE_ID('H','E','A','D'), MAKE_ID('L','I','C','H'), // Ironlich - }; - - static const uint32_t HexenRenames[] = - { MAKE_ID('B','A','R','L'), MAKE_ID('Z','B','A','R'), // ZBarrel - MAKE_ID('A','R','M','1'), MAKE_ID('A','R','_','1'), // MeshArmor - MAKE_ID('A','R','M','2'), MAKE_ID('A','R','_','2'), // FalconShield - MAKE_ID('A','R','M','3'), MAKE_ID('A','R','_','3'), // PlatinumHelm - MAKE_ID('A','R','M','4'), MAKE_ID('A','R','_','4'), // AmuletOfWarding - MAKE_ID('S','U','I','T'), MAKE_ID('Z','S','U','I'), // ZSuitOfArmor and ZArmorChunk - MAKE_ID('T','R','E','1'), MAKE_ID('Z','T','R','E'), // ZTree and ZTreeDead - MAKE_ID('T','R','E','2'), MAKE_ID('T','R','E','S'), // ZTreeSwamp150 - MAKE_ID('C','A','N','D'), MAKE_ID('B','C','A','N'), // ZBlueCandle - MAKE_ID('R','O','C','K'), MAKE_ID('R','O','K','K'), // rocks and dirt in a_debris.cpp - MAKE_ID('W','A','T','R'), MAKE_ID('H','W','A','T'), // Strife also has WATR - MAKE_ID('G','I','B','S'), MAKE_ID('P','O','L','5'), // RealGibs - MAKE_ID('E','G','G','M'), MAKE_ID('P','R','K','M'), // PorkFX - MAKE_ID('I','N','V','U'), MAKE_ID('D','E','F','N'), // Icon of the Defender - }; - - static const uint32_t StrifeRenames[] = - { MAKE_ID('M','I','S','L'), MAKE_ID('S','M','I','S'), // lots of places - MAKE_ID('A','R','M','1'), MAKE_ID('A','R','M','3'), // MetalArmor - MAKE_ID('A','R','M','2'), MAKE_ID('A','R','M','4'), // LeatherArmor - MAKE_ID('P','M','A','P'), MAKE_ID('S','M','A','P'), // StrifeMap - MAKE_ID('T','L','M','P'), MAKE_ID('T','E','C','H'), // TechLampSilver and TechLampBrass - MAKE_ID('T','R','E','1'), MAKE_ID('T','R','E','T'), // TreeStub - MAKE_ID('B','A','R','1'), MAKE_ID('B','A','R','C'), // BarricadeColumn - MAKE_ID('S','H','T','2'), MAKE_ID('M','P','U','F'), // MaulerPuff - MAKE_ID('B','A','R','L'), MAKE_ID('B','B','A','R'), // StrifeBurningBarrel - MAKE_ID('T','R','C','H'), MAKE_ID('T','R','H','L'), // SmallTorchLit - MAKE_ID('S','H','R','D'), MAKE_ID('S','H','A','R'), // glass shards - MAKE_ID('B','L','S','T'), MAKE_ID('M','A','U','L'), // Mauler - MAKE_ID('L','O','G','G'), MAKE_ID('L','O','G','W'), // StickInWater - MAKE_ID('V','A','S','E'), MAKE_ID('V','A','Z','E'), // Pot and Pitcher - MAKE_ID('C','N','D','L'), MAKE_ID('K','N','D','L'), // Candle - MAKE_ID('P','O','T','1'), MAKE_ID('M','P','O','T'), // MetalPot - MAKE_ID('S','P','I','D'), MAKE_ID('S','T','L','K'), // Stalker - }; - - const uint32_t *renames; - int numrenames; - - switch (gameinfo.gametype) - { - case GAME_Doom: - default: - // Doom's sprites don't get renamed. - renames = nullptr; - numrenames = 0; - break; - - case GAME_Heretic: - renames = HereticRenames; - numrenames = sizeof(HereticRenames)/8; - break; - - case GAME_Hexen: - renames = HexenRenames; - numrenames = sizeof(HexenRenames)/8; - break; - - case GAME_Strife: - renames = StrifeRenames; - numrenames = sizeof(StrifeRenames)/8; - break; - } - - - for (uint32_t i=0; i< LumpInfo.Size(); i++) - { - // check for full Minotaur animations. If this is not found - // some frames need to be renamed. - if (LumpInfo[i].lump->Namespace == ns_sprites) - { - if (LumpInfo[i].lump->dwName == MAKE_ID('M', 'N', 'T', 'R') && LumpInfo[i].lump->Name[4] == 'Z' ) - { - MNTRZfound = true; - break; - } - } - } - - renameAll = !!Args->CheckParm ("-oldsprites") || nospriterename; - - for (uint32_t i = 0; i < LumpInfo.Size(); i++) - { - if (LumpInfo[i].lump->Namespace == ns_sprites) - { - // Only sprites in the IWAD normally get renamed - if (renameAll || LumpInfo[i].wadnum == GetIwadNum()) - { - for (int j = 0; j < numrenames; ++j) - { - if (LumpInfo[i].lump->dwName == renames[j*2]) - { - LumpInfo[i].lump->dwName = renames[j*2+1]; - } - } - if (gameinfo.gametype == GAME_Hexen) - { - if (CheckLumpName (i, "ARTIINVU")) - { - LumpInfo[i].lump->Name[4]='D'; LumpInfo[i].lump->Name[5]='E'; - LumpInfo[i].lump->Name[6]='F'; LumpInfo[i].lump->Name[7]='N'; - } - } - } - - if (!MNTRZfound) - { - if (LumpInfo[i].lump->dwName == MAKE_ID('M', 'N', 'T', 'R')) - { - for (size_t fi : {4, 6}) - { - if (LumpInfo[i].lump->Name[fi] >= 'F' && LumpInfo[i].lump->Name[fi] <= 'K') - { - LumpInfo[i].lump->Name[fi] += 'U' - 'F'; - } - } - } - } - - // When not playing Doom rename all BLOD sprites to BLUD so that - // the same blood states can be used everywhere - if (!(gameinfo.gametype & GAME_DoomChex)) - { - if (LumpInfo[i].lump->dwName == MAKE_ID('B', 'L', 'O', 'D')) - { - LumpInfo[i].lump->dwName = MAKE_ID('B', 'L', 'U', 'D'); - } - } - } - else if (LumpInfo[i].lump->Namespace == ns_global) - { - if (LumpInfo[i].wadnum >= GetIwadNum() && LumpInfo[i].wadnum <= GetMaxIwadNum() && deletelumps.Find(LumpInfo[i].lump->Name) < deletelumps.Size()) - { - LumpInfo[i].lump->Name[0] = 0; // Lump must be deleted from directory. - } - // Rename the game specific big font lumps so that the font manager does not have to do problematic special checks for them. - else if (!strcmp(LumpInfo[i].lump->Name, altbigfont)) - { - strcpy(LumpInfo[i].lump->Name, "BIGFONT"); - } - } - } -} - -//========================================================================== -// -// RenameNerve -// -// Renames map headers and map name pictures in nerve.wad so as to load it -// alongside Doom II and offer both episodes without causing conflicts. -// MD5 checksum for NERVE.WAD: 967d5ae23daf45196212ae1b605da3b0 (3,819,855) -// MD5 checksum for Unity version of NERVE.WAD: 4214c47651b63ee2257b1c2490a518c9 (3,821,966) -// -//========================================================================== -void FWadCollection::RenameNerve () -{ - if (gameinfo.gametype != GAME_Doom) - return; - - const int numnerveversions = 2; - - bool found = false; - uint8_t cksum[16]; - static const uint8_t nerve[numnerveversions][16] = { - { 0x96, 0x7d, 0x5a, 0xe2, 0x3d, 0xaf, 0x45, 0x19, - 0x62, 0x12, 0xae, 0x1b, 0x60, 0x5d, 0xa3, 0xb0 }, - { 0x42, 0x14, 0xc4, 0x76, 0x51, 0xb6, 0x3e, 0xe2, - 0x25, 0x7b, 0x1c, 0x24, 0x90, 0xa5, 0x18, 0xc9 } - }; - size_t nervesize[numnerveversions] = { 3819855, 3821966 } ; // NERVE.WAD's file size - int w = GetIwadNum(); - while (++w < GetNumWads()) - { - auto fr = GetFileReader(w); - int isizecheck = -1; - if (fr == NULL) - { - continue; - } - for (int icheck = 0; icheck < numnerveversions; icheck++) - if (fr->GetLength() == (long)nervesize[icheck]) - isizecheck = icheck; - if (isizecheck == -1) - { - // Skip MD5 computation when there is a - // cheaper way to know this is not the file - continue; - } - fr->Seek(0, FileReader::SeekSet); - MD5Context md5; - md5.Update(*fr, (unsigned)fr->GetLength()); - md5.Final(cksum); - if (memcmp(nerve[isizecheck], cksum, 16) == 0) - { - found = true; - break; - } - } - - if (!found) - return; - - for (int i = GetFirstLump(w); i <= GetLastLump(w); i++) - { - // Only rename the maps from NERVE.WAD - assert(LumpInfo[i].wadnum == w); - if (LumpInfo[i].lump->dwName == MAKE_ID('C', 'W', 'I', 'L')) - { - LumpInfo[i].lump->Name[0] = 'N'; - } - else if (LumpInfo[i].lump->dwName == MAKE_ID('M', 'A', 'P', '0')) - { - LumpInfo[i].lump->Name[6] = LumpInfo[i].lump->Name[4]; - LumpInfo[i].lump->Name[5] = '0'; - LumpInfo[i].lump->Name[4] = 'L'; - LumpInfo[i].lump->dwName = MAKE_ID('L', 'E', 'V', 'E'); - } - } -} - -//========================================================================== -// -// FixMacHexen -// -// Discard all extra lumps in Mac version of Hexen IWAD (demo or full) -// to avoid any issues caused by names of these lumps, including: -// * Wrong height of small font -// * Broken life bar of mage class -// -//========================================================================== - -void FWadCollection::FixMacHexen() -{ - if (GAME_Hexen != gameinfo.gametype) - { - return; - } - - FileReader *reader = GetFileReader(GetIwadNum()); - auto iwadSize = reader->GetLength(); - - static const long DEMO_SIZE = 13596228; - static const long BETA_SIZE = 13749984; - static const long FULL_SIZE = 21078584; - - if ( DEMO_SIZE != iwadSize - && BETA_SIZE != iwadSize - && FULL_SIZE != iwadSize) - { - return; - } - - reader->Seek(0, FileReader::SeekSet); - - uint8_t checksum[16]; - MD5Context md5; - - md5.Update(*reader, (unsigned)iwadSize); - md5.Final(checksum); - - static const uint8_t HEXEN_DEMO_MD5[16] = - { - 0x92, 0x5f, 0x9f, 0x50, 0x00, 0xe1, 0x7d, 0xc8, - 0x4b, 0x0a, 0x6a, 0x3b, 0xed, 0x3a, 0x6f, 0x31 - }; - - static const uint8_t HEXEN_BETA_MD5[16] = - { - 0x2a, 0xf1, 0xb2, 0x7c, 0xd1, 0x1f, 0xb1, 0x59, - 0xe6, 0x08, 0x47, 0x2a, 0x1b, 0x53, 0xe4, 0x0e - }; - - static const uint8_t HEXEN_FULL_MD5[16] = - { - 0xb6, 0x81, 0x40, 0xa7, 0x96, 0xf6, 0xfd, 0x7f, - 0x3a, 0x5d, 0x32, 0x26, 0xa3, 0x2b, 0x93, 0xbe - }; - - const bool isBeta = 0 == memcmp(HEXEN_BETA_MD5, checksum, sizeof checksum); - - if ( !isBeta - && 0 != memcmp(HEXEN_DEMO_MD5, checksum, sizeof checksum) - && 0 != memcmp(HEXEN_FULL_MD5, checksum, sizeof checksum)) - { - return; - } - - static const int EXTRA_LUMPS = 299; - - // Hexen Beta is very similar to Demo but it has MAP41: Maze at the end of the WAD - // So keep this map if it's present but discard all extra lumps - - const int lastLump = GetLastLump(GetIwadNum()) - (isBeta ? 12 : 0); - assert(GetFirstLump(GetIwadNum()) + 299 < lastLump); - - for (int i = lastLump - EXTRA_LUMPS + 1; i <= lastLump; ++i) - { - LumpInfo[i].lump->Name[0] = '\0'; - } -} - -//========================================================================== -// -// MoveLumpsInFolder -// -// Moves all content from the given subfolder of the internal -// resources to the current end of the directory. -// Used to allow modifying content in the base files, this is needed -// so that Hacx and Harmony can override some content that clashes -// with localization, and to inject modifying data into mods, in case -// this is needed for some compatibility requirement. -// -//========================================================================== - -static FResourceLump placeholderLump; - -void FWadCollection::MoveLumpsInFolder(const char *path) -{ - auto len = strlen(path); - auto wadnum = LumpInfo.Last().wadnum; - - unsigned i; - for (i = 0; i < LumpInfo.Size(); i++) - { - auto& li = LumpInfo[i]; - if (li.wadnum >= GetIwadNum()) break; - if (li.lump->FullName.Left(len).CompareNoCase(path) == 0) - { - LumpInfo.Push(li); - li.lump = &placeholderLump; // Make the old entry point to something empty. We cannot delete the lump record here because it'd require adjustment of all indices in the list. - auto &ln = LumpInfo.Last(); - ln.wadnum = wadnum; // pretend this is from the WAD this is injected into. - ln.lump->LumpNameSetup(ln.lump->FullName.Mid(len)); - } - } -} - -//========================================================================== -// -// W_FindLump -// -// Find a named lump. Specifically allows duplicates for merging of e.g. -// SNDINFO lumps. -// -//========================================================================== - -int FWadCollection::FindLump (const char *name, int *lastlump, bool anyns) -{ - union - { - char name8[8]; - uint64_t qname; - }; - LumpRecord *lump_p; - - uppercopy (name8, name); - - assert(lastlump != NULL && *lastlump >= 0); - lump_p = &LumpInfo[*lastlump]; - while (lump_p < &LumpInfo[NumLumps]) - { - FResourceLump *lump = lump_p->lump; - - if ((anyns || lump->Namespace == ns_global) && lump->qwName == qname) - { - int lump = int(lump_p - &LumpInfo[0]); - *lastlump = lump + 1; - return lump; - } - lump_p++; - } - - *lastlump = NumLumps; - return -1; -} - -DEFINE_ACTION_FUNCTION(_Wads, FindLump) -{ - PARAM_PROLOGUE; - PARAM_STRING(name); - PARAM_INT(startlump); - PARAM_INT(ns); - const bool isLumpValid = startlump >= 0 && startlump < Wads.GetNumLumps(); - ACTION_RETURN_INT(isLumpValid ? Wads.FindLump(name, &startlump, 0 != ns) : -1); -} - -//========================================================================== -// -// W_FindLumpMulti -// -// Find a named lump. Specifically allows duplicates for merging of e.g. -// SNDINFO lumps. Returns everything having one of the passed names. -// -//========================================================================== - -int FWadCollection::FindLumpMulti (const char **names, int *lastlump, bool anyns, int *nameindex) -{ - LumpRecord *lump_p; - - assert(lastlump != NULL && *lastlump >= 0); - lump_p = &LumpInfo[*lastlump]; - while (lump_p < &LumpInfo[NumLumps]) - { - FResourceLump *lump = lump_p->lump; - - if (anyns || lump->Namespace == ns_global) - { - - for(const char **name = names; *name != NULL; name++) - { - if (!strnicmp(*name, lump->Name, 8)) - { - int lump = int(lump_p - &LumpInfo[0]); - *lastlump = lump + 1; - if (nameindex != NULL) *nameindex = int(name - names); - return lump; - } - } - } - lump_p++; - } - - *lastlump = NumLumps; - return -1; -} - -//========================================================================== -// -// W_CheckLumpName -// -//========================================================================== - -bool FWadCollection::CheckLumpName (int lump, const char *name) -{ - if ((size_t)lump >= NumLumps) - return false; - - return !strnicmp (LumpInfo[lump].lump->Name, name, 8); -} - -//========================================================================== -// -// W_GetLumpName -// -//========================================================================== - -void FWadCollection::GetLumpName (char *to, int lump) const -{ - if ((size_t)lump >= NumLumps) - *to = 0; - else - uppercopy (to, LumpInfo[lump].lump->Name); -} - -void FWadCollection::GetLumpName(FString &to, int lump) const -{ - if ((size_t)lump >= NumLumps) - to = FString(); - else { - to = LumpInfo[lump].lump->Name; - to.ToUpper(); - } -} - -DEFINE_ACTION_FUNCTION(_Wads, GetLumpName) -{ - PARAM_PROLOGUE; - PARAM_INT(lump); - FString lumpname; - Wads.GetLumpName(lumpname, lump); - ACTION_RETURN_STRING(lumpname); -} - -//========================================================================== -// -// FWadCollection :: GetLumpFullName -// -// Returns the lump's full name if it has one or its short name if not. -// -//========================================================================== - -const char *FWadCollection::GetLumpFullName (int lump) const -{ - if ((size_t)lump >= NumLumps) - return NULL; - else if (LumpInfo[lump].lump->FullName.IsNotEmpty()) - return LumpInfo[lump].lump->FullName; - else - return LumpInfo[lump].lump->Name; -} - -DEFINE_ACTION_FUNCTION(_Wads, GetLumpFullName) -{ - PARAM_PROLOGUE; - PARAM_INT(lump); - ACTION_RETURN_STRING(Wads.GetLumpFullName(lump)); -} - -//========================================================================== -// -// FWadCollection :: GetLumpFullPath -// -// Returns the name of the lump's wad prefixed to the lump's full name. -// -//========================================================================== - -FString FWadCollection::GetLumpFullPath(int lump) const -{ - FString foo; - - if ((size_t) lump < NumLumps) - { - foo << GetWadName(LumpInfo[lump].wadnum) << ':' << GetLumpFullName(lump); - } - return foo; -} - -//========================================================================== -// -// GetLumpNamespace -// -//========================================================================== - -int FWadCollection::GetLumpNamespace (int lump) const -{ - if ((size_t)lump >= NumLumps) - return ns_global; - else - return LumpInfo[lump].lump->Namespace; -} - -DEFINE_ACTION_FUNCTION(_Wads, GetLumpNamespace) -{ - PARAM_PROLOGUE; - PARAM_INT(lump); - ACTION_RETURN_INT(Wads.GetLumpNamespace(lump)); -} - -//========================================================================== -// -// FWadCollection :: GetLumpIndexNum -// -// Returns the index number for this lump. This is *not* the lump's position -// in the lump directory, but rather a special value that RFF can associate -// with files. Other archive types will return 0, since they don't have it. -// -//========================================================================== - -int FWadCollection::GetLumpIndexNum(int lump) const -{ - if ((size_t)lump >= NumLumps) - return 0; - else - return LumpInfo[lump].lump->GetIndexNum(); -} - -//========================================================================== -// -// W_GetLumpFile -// -//========================================================================== - -int FWadCollection::GetLumpFile (int lump) const -{ - if ((size_t)lump >= LumpInfo.Size()) - return -1; - return LumpInfo[lump].wadnum; -} - -//========================================================================== -// -// W_GetLumpFile -// -//========================================================================== - -FResourceLump *FWadCollection::GetLumpRecord(int lump) const -{ - if ((size_t)lump >= LumpInfo.Size()) - return nullptr; - return LumpInfo[lump].lump; -} - -//========================================================================== -// -// GetLumpsInFolder -// -// Gets all lumps within a single folder in the hierarchy. -// If 'atomic' is set, it treats folders as atomic, i.e. only the -// content of the last found resource file having the given folder name gets used. -// -//========================================================================== - -static int folderentrycmp(const void *a, const void *b) -{ - auto A = (FolderEntry*)a; - auto B = (FolderEntry*)b; - return strcmp(A->name, B->name); -} - -unsigned FWadCollection::GetLumpsInFolder(const char *inpath, TArray &result, bool atomic) const -{ - FString path = inpath; - FixPathSeperator(path); - path.ToLower(); - if (path[path.Len() - 1] != '/') path += '/'; - result.Clear(); - for (unsigned i = 0; i < LumpInfo.Size(); i++) - { - if (LumpInfo[i].lump->FullName.IndexOf(path) == 0) - { - // Only if it hasn't been replaced. - if ((unsigned)Wads.CheckNumForFullName(LumpInfo[i].lump->FullName) == i) - { - result.Push({ LumpInfo[i].lump->FullName.GetChars(), i }); - } - } - } - if (result.Size()) - { - int maxfile = -1; - if (atomic) - { - // Find the highest resource file having content in the given folder. - for (auto & entry : result) - { - int thisfile = Wads.GetLumpFile(entry.lumpnum); - if (thisfile > maxfile) maxfile = thisfile; - } - // Delete everything from older files. - for (int i = result.Size() - 1; i >= 0; i--) - { - if (Wads.GetLumpFile(result[i].lumpnum) != maxfile) result.Delete(i); - } - } - qsort(result.Data(), result.Size(), sizeof(FolderEntry), folderentrycmp); - } - return result.Size(); -} - -//========================================================================== -// -// W_ReadLump -// -// Loads the lump into the given buffer, which must be >= W_LumpLength(). -// -//========================================================================== - -void FWadCollection::ReadLump (int lump, void *dest) -{ - auto lumpr = OpenLumpReader (lump); - auto size = lumpr.GetLength (); - auto numread = lumpr.Read (dest, size); - - if (numread != size) - { - I_Error ("W_ReadLump: only read %ld of %ld on lump %i\n", - numread, size, lump); - } -} - -//========================================================================== -// -// W_ReadLump -// -// Loads the lump into a TArray and returns it. -// -//========================================================================== - -TArray FWadCollection::ReadLumpIntoArray(int lump, int pad) -{ - auto lumpr = OpenLumpReader(lump); - auto size = lumpr.GetLength(); - TArray data(size + pad, true); - auto numread = lumpr.Read(data.Data(), size); - - if (numread != size) - { - I_Error("W_ReadLump: only read %ld of %ld on lump %i\n", - numread, size, lump); - } - if (pad > 0) memset(&data[size], 0, pad); - return data; -} - -//========================================================================== -// -// ReadLump - variant 2 -// -// Loads the lump into a newly created buffer and returns it. -// -//========================================================================== - -FMemLump FWadCollection::ReadLump (int lump) -{ - return FMemLump(FString(ELumpNum(lump))); -} - -DEFINE_ACTION_FUNCTION(_Wads, ReadLump) -{ - PARAM_PROLOGUE; - PARAM_INT(lump); - const bool isLumpValid = lump >= 0 && lump < Wads.GetNumLumps(); - ACTION_RETURN_STRING(isLumpValid ? Wads.ReadLump(lump).GetString() : FString()); -} - -//========================================================================== -// -// OpenLumpReader -// -// uses a more abstract interface to allow for easier low level optimization later -// -//========================================================================== - - -FileReader FWadCollection::OpenLumpReader(int lump) -{ - if ((unsigned)lump >= (unsigned)LumpInfo.Size()) - { - I_Error("W_OpenLumpNum: %u >= NumLumps", lump); - } - - auto rl = LumpInfo[lump].lump; - auto rd = rl->GetReader(); - - if (rl->RefCount == 0 && rd != nullptr && !rd->GetBuffer() && !(rl->Flags & (LUMPF_BLOODCRYPT | LUMPF_COMPRESSED))) - { - FileReader rdr; - rdr.OpenFilePart(*rd, rl->GetFileOffset(), rl->LumpSize); - return rdr; - } - return rl->NewReader(); // This always gets a reader to the cache -} - -FileReader FWadCollection::ReopenLumpReader(int lump, bool alwayscache) -{ - if ((unsigned)lump >= (unsigned)LumpInfo.Size()) - { - I_Error("ReopenLumpReader: %u >= NumLumps", lump); - } - - auto rl = LumpInfo[lump].lump; - auto rd = rl->GetReader(); - - if (rl->RefCount == 0 && rd != nullptr && !rd->GetBuffer() && !alwayscache && !(rl->Flags & (LUMPF_BLOODCRYPT|LUMPF_COMPRESSED))) - { - int fileno = Wads.GetLumpFile(lump); - const char *filename = Wads.GetWadFullName(fileno); - FileReader fr; - if (fr.OpenFile(filename, rl->GetFileOffset(), rl->LumpSize)) - { - return fr; - } - } - return rl->NewReader(); // This always gets a reader to the cache -} - -//========================================================================== -// -// GetFileReader -// -// Retrieves the File reader object to access the given WAD -// Careful: This is only useful for real WAD files! -// -//========================================================================== - -FileReader *FWadCollection::GetFileReader(int wadnum) -{ - if ((uint32_t)wadnum >= Files.Size()) - { - return NULL; - } - - return Files[wadnum]->GetReader(); -} - -//========================================================================== -// -// W_GetWadName -// -// Returns the name of the given wad. -// -//========================================================================== - -const char *FWadCollection::GetWadName (int wadnum) const -{ - const char *name, *slash; - - if ((uint32_t)wadnum >= Files.Size()) - { - return NULL; - } - - name = Files[wadnum]->FileName; - slash = strrchr (name, '/'); - return slash != NULL ? slash+1 : name; -} - -//========================================================================== -// -// -//========================================================================== - -int FWadCollection::GetFirstLump (int wadnum) const -{ - if ((uint32_t)wadnum >= Files.Size()) - { - return 0; - } - - return Files[wadnum]->GetFirstLump(); -} - -//========================================================================== -// -// -//========================================================================== - -int FWadCollection::GetLastLump (int wadnum) const -{ - if ((uint32_t)wadnum >= Files.Size()) - { - return 0; - } - - return Files[wadnum]->GetFirstLump() + Files[wadnum]->LumpCount() - 1; -} - -//========================================================================== -// -// -//========================================================================== - -int FWadCollection::GetLumpCount (int wadnum) const -{ - if ((uint32_t)wadnum >= Files.Size()) - { - return 0; - } - - return Files[wadnum]->LumpCount(); -} - - -//========================================================================== -// -// W_GetWadFullName -// -// Returns the name of the given wad, including any path -// -//========================================================================== - -const char *FWadCollection::GetWadFullName (int wadnum) const -{ - if ((unsigned int)wadnum >= Files.Size()) - { - return nullptr; - } - - return Files[wadnum]->FileName; -} - - -//========================================================================== -// -// IsEncryptedFile -// -// Returns true if the first 256 bytes of the lump are encrypted for Blood. -// -//========================================================================== - -bool FWadCollection::IsEncryptedFile(int lump) const -{ - if ((unsigned)lump >= (unsigned)NumLumps) - { - return false; - } - return !!(LumpInfo[lump].lump->Flags & LUMPF_BLOODCRYPT); -} - - -// FMemLump ----------------------------------------------------------------- - -FMemLump::FMemLump () -{ -} - -FMemLump::FMemLump (const FMemLump ©) -{ - Block = copy.Block; -} - -FMemLump &FMemLump::operator = (const FMemLump ©) -{ - Block = copy.Block; - return *this; -} - -FMemLump::FMemLump (const FString &source) -: Block (source) -{ -} - -FMemLump::~FMemLump () -{ -} - -FString::FString (ELumpNum lumpnum) -{ - auto lumpr = Wads.OpenLumpReader ((int)lumpnum); - auto size = lumpr.GetLength (); - AllocBuffer (1 + size); - auto numread = lumpr.Read (&Chars[0], size); - Chars[size] = '\0'; - - if (numread != size) - { - I_Error ("ConstructStringFromLump: Only read %ld of %ld bytes on lump %i (%s)\n", - numread, size, lumpnum, Wads.GetLumpFullName((int)lumpnum)); - } -} - -//========================================================================== -// -// PrintLastError -// -//========================================================================== - -#ifdef _WIN32 -//#define WIN32_LEAN_AND_MEAN -//#include - -extern "C" { -__declspec(dllimport) unsigned long __stdcall FormatMessageA( - unsigned long dwFlags, - const void *lpSource, - unsigned long dwMessageId, - unsigned long dwLanguageId, - char **lpBuffer, - unsigned long nSize, - va_list *Arguments - ); -__declspec(dllimport) void * __stdcall LocalFree (void *); -__declspec(dllimport) unsigned long __stdcall GetLastError (); -} - -static void PrintLastError () -{ - char *lpMsgBuf; - FormatMessageA(0x1300 /*FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS*/, - NULL, - GetLastError(), - 1 << 10 /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, // Default language - &lpMsgBuf, - 0, - NULL - ); - Printf (TEXTCOLOR_RED " %s\n", lpMsgBuf); - // Free the buffer. - LocalFree( lpMsgBuf ); -} -#else -static void PrintLastError () -{ - Printf (TEXTCOLOR_RED " %s\n", strerror(errno)); -} -#endif - -#ifdef _DEBUG -//========================================================================== -// -// CCMD LumpNum -// -//========================================================================== - -CCMD(lumpnum) -{ - for (int i = 1; i < argv.argc(); ++i) - { - Printf("%s: %d\n", argv[i], Wads.CheckNumForName(argv[i])); - } -} - -//========================================================================== -// -// CCMD LumpNumFull -// -//========================================================================== - -CCMD(lumpnumfull) -{ - for (int i = 1; i < argv.argc(); ++i) - { - Printf("%s: %d\n", argv[i], Wads.CheckNumForFullName(argv[i])); - } -} -#endif diff --git a/src/gamedata/w_wad.h b/src/gamedata/w_wad.h deleted file mode 100644 index 610e67e9a51..00000000000 --- a/src/gamedata/w_wad.h +++ /dev/null @@ -1,232 +0,0 @@ -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// WAD I/O functions. -// -//----------------------------------------------------------------------------- - - -#ifndef __W_WAD__ -#define __W_WAD__ - -#include "files.h" -#include "doomdef.h" -#include "tarray.h" -#include "zstring.h" - -class FResourceFile; -struct FResourceLump; -class FTexture; - -struct wadinfo_t -{ - // Should be "IWAD" or "PWAD". - uint32_t Magic; - uint32_t NumLumps; - uint32_t InfoTableOfs; -}; - -struct wadlump_t -{ - uint32_t FilePos; - uint32_t Size; - char Name[8]; -}; - -#define IWAD_ID MAKE_ID('I','W','A','D') -#define PWAD_ID MAKE_ID('P','W','A','D') - - -// [RH] Namespaces from BOOM. -typedef enum { - ns_hidden = -1, - - ns_global = 0, - ns_sprites, - ns_flats, - ns_colormaps, - ns_acslibrary, - ns_newtextures, - ns_bloodraw, - ns_bloodsfx, - ns_bloodmisc, - ns_strifevoices, - ns_hires, - ns_voxels, - - // These namespaces are only used to mark lumps in special subdirectories - // so that their contents doesn't interfere with the global namespace. - // searching for data in these namespaces works differently for lumps coming - // from Zips or other files. - ns_specialzipdirectory, - ns_sounds, - ns_patches, - ns_graphics, - ns_music, - - ns_firstskin, -} namespace_t; - -enum ELumpFlags -{ - LUMPF_MAYBEFLAT=1, // might be a flat outside F_START/END - LUMPF_ZIPFILE=2, // contains a full path - LUMPF_EMBEDDED=4, // from an embedded WAD - LUMPF_BLOODCRYPT = 8, // encrypted - LUMPF_COMPRESSED = 16, // compressed - LUMPF_SEQUENTIAL = 32, // compressed but a sequential reader can be retrieved. -}; - - -// [RH] Copy an 8-char string and uppercase it. -void uppercopy (char *to, const char *from); - -// A lump in memory. -class FMemLump -{ -public: - FMemLump (); - - FMemLump (const FMemLump ©); - FMemLump &operator= (const FMemLump ©); - ~FMemLump (); - void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); } - size_t GetSize () { return Block.Len(); } - FString GetString () { return Block; } - -private: - FMemLump (const FString &source); - - FString Block; - - friend class FWadCollection; -}; - -struct FolderEntry -{ - const char *name; - unsigned lumpnum; -}; - -class FWadCollection -{ -public: - FWadCollection (); - ~FWadCollection (); - - // The wadnum for the IWAD - int GetIwadNum() { return IwadIndex; } - void SetIwadNum(int x) { IwadIndex = x; } - - int GetMaxIwadNum() { return MaxIwadIndex; } - void SetMaxIwadNum(int x) { MaxIwadIndex = x; } - - void InitMultipleFiles (TArray &filenames, const TArray &deletelumps); - void AddFile (const char *filename, FileReader *wadinfo = NULL); - int CheckIfWadLoaded (const char *name); - - const char *GetWadName (int wadnum) const; - const char *GetWadFullName (int wadnum) const; - - int GetFirstLump(int wadnum) const; - int GetLastLump(int wadnum) const; - int GetLumpCount(int wadnum) const; - - int CheckNumForName (const char *name, int namespc); - int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true); - int GetNumForName (const char *name, int namespc); - - inline int CheckNumForName (const uint8_t *name) { return CheckNumForName ((const char *)name, ns_global); } - inline int CheckNumForName (const char *name) { return CheckNumForName (name, ns_global); } - inline int CheckNumForName (const FString &name) { return CheckNumForName (name.GetChars()); } - inline int CheckNumForName (const uint8_t *name, int ns) { return CheckNumForName ((const char *)name, ns); } - inline int GetNumForName (const char *name) { return GetNumForName (name, ns_global); } - inline int GetNumForName (const FString &name) { return GetNumForName (name.GetChars(), ns_global); } - inline int GetNumForName (const uint8_t *name) { return GetNumForName ((const char *)name); } - inline int GetNumForName (const uint8_t *name, int ns) { return GetNumForName ((const char *)name, ns); } - - int CheckNumForFullName (const char *name, bool trynormal = false, int namespc = ns_global, bool ignoreext = false); - int CheckNumForFullName (const char *name, int wadfile); - int GetNumForFullName (const char *name); - - inline int CheckNumForFullName(const FString &name, bool trynormal = false, int namespc = ns_global) { return CheckNumForFullName(name.GetChars(), trynormal, namespc); } - inline int CheckNumForFullName (const FString &name, int wadfile) { return CheckNumForFullName(name.GetChars(), wadfile); } - inline int GetNumForFullName (const FString &name) { return GetNumForFullName(name.GetChars()); } - - void SetLinkedTexture(int lump, FTexture *tex); - FTexture *GetLinkedTexture(int lump); - - - void ReadLump (int lump, void *dest); - TArray ReadLumpIntoArray(int lump, int pad = 0); // reads lump into a writable buffer and optionally adds some padding at the end. (FMemLump isn't writable!) - FMemLump ReadLump (int lump); - FMemLump ReadLump (const char *name) { return ReadLump (GetNumForName (name)); } - - FileReader OpenLumpReader(int lump); // opens a reader that redirects to the containing file's one. - FileReader ReopenLumpReader(int lump, bool alwayscache = false); // opens an independent reader. - - int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication - int FindLumpMulti (const char **names, int *lastlump, bool anyns = false, int *nameindex = NULL); // same with multiple possible names - bool CheckLumpName (int lump, const char *name); // [RH] True if lump's name == name - - static uint32_t LumpNameHash (const char *name); // [RH] Create hash key from an 8-char name - - int LumpLength (int lump) const; - int GetLumpOffset (int lump); // [RH] Returns offset of lump in the wadfile - int GetLumpFlags (int lump); // Return the flags for this lump - void GetLumpName (char *to, int lump) const; // [RH] Copies the lump name to to using uppercopy - void GetLumpName (FString &to, int lump) const; - const char *GetLumpFullName (int lump) const; // [RH] Returns the lump's full name - FString GetLumpFullPath (int lump) const; // [RH] Returns wad's name + lump's full name - int GetLumpFile (int lump) const; // [RH] Returns wadnum for a specified lump - int GetLumpNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to - int GetLumpIndexNum (int lump) const; // Returns the RFF index number for this lump - FResourceLump *GetLumpRecord(int lump) const; // Returns the FResourceLump, in case the caller wants to have direct access to the lump cache. - bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match - unsigned GetLumpsInFolder(const char *path, TArray &result, bool atomic) const; - - bool IsEncryptedFile(int lump) const; - - int GetNumLumps () const; - int GetNumWads () const; - - int AddExternalFile(const char *filename); - -protected: - - struct LumpRecord; - - TArray Files; - TArray LumpInfo; - - TArray Hashes; // one allocation for all hash lists. - uint32_t *FirstLumpIndex; // [RH] Hashing stuff moved out of lumpinfo structure - uint32_t *NextLumpIndex; - - uint32_t *FirstLumpIndex_FullName; // The same information for fully qualified paths from .zips - uint32_t *NextLumpIndex_FullName; - - uint32_t *FirstLumpIndex_NoExt; // The same information for fully qualified paths from .zips - uint32_t *NextLumpIndex_NoExt; - - uint32_t NumLumps = 0; // Not necessarily the same as LumpInfo.Size() - uint32_t NumWads; - - int IwadIndex = -1; - int MaxIwadIndex = -1; - - void InitHashChains (); // [RH] Set up the lumpinfo hashing - -private: - void RenameSprites(const TArray &deletelumps); - void RenameNerve(); - void FixMacHexen(); - void DeleteAll(); - void MoveLumpsInFolder(const char *); - - FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD -}; - -extern FWadCollection Wads; - -#endif diff --git a/src/gamedata/w_zip.h b/src/gamedata/w_zip.h deleted file mode 100644 index 0a2ce6d4e47..00000000000 --- a/src/gamedata/w_zip.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef __W_ZIP -#define __W_ZIP - -#pragma pack(1) -// FZipCentralInfo -struct FZipEndOfCentralDirectory -{ - uint32_t Magic; - uint16_t DiskNumber; - uint16_t FirstDisk; - uint16_t NumEntries; - uint16_t NumEntriesOnAllDisks; - uint32_t DirectorySize; - uint32_t DirectoryOffset; - uint16_t ZipCommentLength; -} FORCE_PACKED; - -// FZipFileInfo -struct FZipCentralDirectoryInfo -{ - uint32_t Magic; - uint8_t VersionMadeBy[2]; - uint8_t VersionToExtract[2]; - uint16_t Flags; - uint16_t Method; - uint16_t ModTime; - uint16_t ModDate; - uint32_t CRC32; - uint32_t CompressedSize; - uint32_t UncompressedSize; - uint16_t NameLength; - uint16_t ExtraLength; - uint16_t CommentLength; - uint16_t StartingDiskNumber; - uint16_t InternalAttributes; - uint32_t ExternalAttributes; - uint32_t LocalHeaderOffset; - // file name and other variable length info follows -} FORCE_PACKED; - -// FZipLocalHeader -struct FZipLocalFileHeader -{ - uint32_t Magic; - uint8_t VersionToExtract[2]; - uint16_t Flags; - uint16_t Method; - uint16_t ModTime; - uint16_t ModDate; - uint32_t CRC32; - uint32_t CompressedSize; - uint32_t UncompressedSize; - uint16_t NameLength; - uint16_t ExtraLength; - // file name and other variable length info follows -} FORCE_PACKED; - - -#pragma pack() - -#define ZIP_LOCALFILE MAKE_ID('P','K',3,4) -#define ZIP_CENTRALFILE MAKE_ID('P','K',1,2) -#define ZIP_ENDOFDIR MAKE_ID('P','K',5,6) - -// File header flags. -#define ZF_ENCRYPTED 0x1 - -#endif diff --git a/src/gamedata/xlat/parsecontext.cpp b/src/gamedata/xlat/parsecontext.cpp index 9631c4b494b..0caa72f4b2d 100644 --- a/src/gamedata/xlat/parsecontext.cpp +++ b/src/gamedata/xlat/parsecontext.cpp @@ -35,7 +35,7 @@ #include #include -#include "w_wad.h" +#include "filesystem.h" #include "parsecontext.h" #include "p_lnspec.h" @@ -78,7 +78,7 @@ bool FParseContext::FindSym (char *sym, FParseSymbol **val) // // //========================================================================== -int FParseContext::GetToken (char *&sourcep, FParseToken *yylval) +int FParseContext::GetToken (const char *&sourcep, FParseToken *yylval) { char token[80]; int toksize; @@ -103,7 +103,7 @@ int FParseContext::GetToken (char *&sourcep, FParseToken *yylval) c = *sourcep++; if (c == 'x' || c == 'X') { - yylval->val = (int)strtoll(sourcep, &sourcep, 16); + yylval->val = (int)strtoll(sourcep, (char**)&sourcep, 16); return TokenTrans[NUM]; } else @@ -118,7 +118,7 @@ int FParseContext::GetToken (char *&sourcep, FParseToken *yylval) if (*endp == '.') { // It's a float - yylval->fval = strtod(sourcep, &sourcep); + yylval->fval = strtod(sourcep, (char**)& sourcep); return TokenTrans[FLOATVAL]; } else @@ -314,7 +314,7 @@ void FParseContext::ParseLump(const char *lumpname) const char *SavedSourceFile = SourceFile; FParseToken token; - int lumpno = Wads.CheckNumForFullName(lumpname, true); + int lumpno = fileSystem.CheckNumForFullName(lumpname, true); if (lumpno == -1) { @@ -323,12 +323,12 @@ void FParseContext::ParseLump(const char *lumpname) } // Read the lump into a buffer and add a 0-terminator - auto lumpdata = Wads.ReadLumpIntoArray(lumpno, 1); SourceLine = 0; SourceFile = lumpname; - char *sourcep = (char*)lumpdata.Data(); + FString source = GetStringFromLump(lumpno); + const char *sourcep = source.GetChars(); while ( (tokentype = GetToken(sourcep, &token)) ) { // It is much easier to handle include statements outside the main parser. diff --git a/src/gamedata/xlat/parsecontext.h b/src/gamedata/xlat/parsecontext.h index 48a3425474a..82c345f782f 100644 --- a/src/gamedata/xlat/parsecontext.h +++ b/src/gamedata/xlat/parsecontext.h @@ -146,7 +146,7 @@ struct FParseContext void AddSym (char *sym, int val); bool FindSym (char *sym, FParseSymbol **val); virtual bool FindToken (char *tok, int *type) = 0; - int GetToken (char *&sourcep, FParseToken *yylval); + int GetToken (const char *&sourcep, FParseToken *yylval); int PrintError (const char *s); void ParseLump(const char *lumpname); }; diff --git a/src/gamedata/xlat/xlat.h b/src/gamedata/xlat/xlat.h index f488704ff1b..516104af121 100644 --- a/src/gamedata/xlat/xlat.h +++ b/src/gamedata/xlat/xlat.h @@ -82,7 +82,7 @@ struct FBoomTranslator { uint16_t FirstLinetype = 0; uint16_t LastLinetype = 0; - uint8_t NewSpecial = 0; + uint16_t NewSpecial = 0; TArray Args; } ; diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index a053115e5da..d7cde85fcf1 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -37,7 +37,7 @@ #include "c_console.h" #include "teaminfo.h" -#include "templates.h" + #include "v_video.h" #include "doomstat.h" #include "g_level.h" @@ -51,6 +51,8 @@ #include "g_levellocals.h" #include "g_game.h" #include "sbar.h" +#include "texturemanager.h" +#include "v_draw.h" // MACROS ------------------------------------------------------------------ @@ -147,7 +149,7 @@ static int FontScale; void HU_DrawScores (player_t *player) { displayFont = NewSmallFont; - FontScale = MAX(screen->GetHeight() / 400, 1); + FontScale = max(screen->GetHeight() / 400, 1); if (deathmatch) { @@ -218,15 +220,15 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth, int &maxiconheigh auto icon = FSetTextureID(players[i].mo->IntVar(NAME_ScoreIcon)); if (icon.isValid()) { - FTexture *pic = TexMan.GetTexture(icon); - width = pic->GetDisplayWidth() - pic->GetDisplayLeftOffset() + 2; + auto pic = TexMan.GetGameTexture(icon); + width = int(pic->GetDisplayWidth() - pic->GetDisplayLeftOffset() + 2.5); if (width > maxscorewidth) { maxscorewidth = width; } // The icon's top offset does not count toward its height, because // zdoom.pk3's standard Hexen class icons are designed that way. - int height = pic->GetDisplayHeight() - pic->GetDisplayTopOffset(); + int height = int(pic->GetDisplayHeight() - pic->GetDisplayTopOffset() + 0.5); if (height > maxiconheight) { maxiconheight = height; @@ -244,7 +246,7 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth, int &maxiconheigh static void HU_DrawFontScaled(double x, double y, int color, const char *text) { - screen->DrawText(displayFont, color, x / FontScale, y / FontScale, text, DTA_VirtualWidth, screen->GetWidth() / FontScale, DTA_VirtualHeight, screen->GetHeight() / FontScale, TAG_END); + DrawText(twod, displayFont, color, x / FontScale, y / FontScale, text, DTA_VirtualWidth, twod->GetWidth() / FontScale, DTA_VirtualHeight, twod->GetHeight() / FontScale, TAG_END); } static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYERS]) @@ -271,11 +273,11 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); height = displayFont->GetHeight() * FontScale; - lineheight = MAX(height, maxiconheight * CleanYfac); + lineheight = max(height, maxiconheight * CleanYfac); ypadding = (lineheight - height + 1) / 2; bottom = StatusBar->GetTopOfStatusbar(); - y = MAX(48*CleanYfac, (bottom - MAXPLAYERS * (height + CleanYfac + 1)) / 2); + y = max(48*CleanYfac, (bottom - MAXPLAYERS * (height + CleanYfac + 1)) / 2); HU_DrawTimeRemaining (bottom - height); @@ -291,7 +293,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER for (i = 0; i < MAXPLAYERS; ++i) { - if (playeringame[sortedplayers[i]-players] && TeamLibrary.IsValidTeam (sortedplayers[i]->userinfo.GetTeam())) + if (playeringame[sortedplayers[i]-players] && FTeam::IsValid (sortedplayers[i]->userinfo.GetTeam())) { if (Teams[sortedplayers[i]->userinfo.GetTeam()].m_iPlayerCount++ == 0) { @@ -302,7 +304,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER } } - int scorexwidth = SCREENWIDTH / MAX(8, numTeams); + int scorexwidth = twod->GetWidth() / max(8, numTeams); int numscores = 0; int scorex; @@ -314,7 +316,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER } } - scorex = (SCREENWIDTH - scorexwidth * (numscores - 1)) / 2; + scorex = (twod->GetWidth() - scorexwidth * (numscores - 1)) / 2; for (i = 0; i < Teams.Size(); ++i) { @@ -323,7 +325,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER char score[80]; mysnprintf (score, countof(score), "%d", Teams[i].m_iScore); - screen->DrawText (BigFont, Teams[i].GetTextColor(), + DrawText(twod, BigFont, Teams[i].GetTextColor(), scorex - BigFont->StringWidth(score)*CleanXfac/2, y, score, DTA_CleanNoMove, true, TAG_DONE); @@ -334,16 +336,16 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER y += (BigFont->GetHeight() + 8) * CleanYfac; } - const char *text_color = GStrings("SCORE_COLOR"), - *text_frags = GStrings(deathmatch ? "SCORE_FRAGS" : "SCORE_KILLS"), - *text_name = GStrings("SCORE_NAME"), - *text_delay = GStrings("SCORE_DELAY"); + const char *text_color = GStrings.GetString("SCORE_COLOR"), + *text_frags = GStrings.GetString(deathmatch ? "SCORE_FRAGS" : "SCORE_KILLS"), + *text_name = GStrings.GetString("SCORE_NAME"), + *text_delay = GStrings.GetString("SCORE_DELAY"); col2 = (displayFont->StringWidth(text_color) + 16) * FontScale; col3 = col2 + (displayFont->StringWidth(text_frags) + 16) * FontScale; col4 = col3 + maxscorewidth * FontScale; col5 = col4 + (maxnamewidth + 16) * FontScale; - x = (SCREENWIDTH >> 1) - (((displayFont->StringWidth(text_delay) * FontScale) + col5) >> 1); + x = (twod->GetWidth() >> 1) - (((displayFont->StringWidth(text_delay) * FontScale) + col5) >> 1); //HU_DrawFontScaled(x, y, color, text_color); HU_DrawFontScaled(x + col2, y, color, text_frags); @@ -391,7 +393,7 @@ static void HU_DrawTimeRemaining (int y) else mysnprintf (str, countof(str), "Level ends in %d:%02d", minutes, seconds); - HU_DrawFontScaled(SCREENWIDTH / 2 - displayFont->StringWidth(str) / 2 * FontScale, y, CR_GRAY, str); + HU_DrawFontScaled(twod->GetWidth() / 2 - displayFont->StringWidth(str) / 2 * FontScale, y, CR_GRAY, str); } } @@ -411,7 +413,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, // The teamplay mode uses colors to show teams, so we need some // other way to do highlighting. And it may as well be used for // all modes for the sake of consistancy. - screen->Dim(MAKERGB(200,245,255), 0.125f, col1 - 12*FontScale, y - 1, col5 + (maxnamewidth + 24)*FontScale, height + 2); + Dim(twod, MAKERGB(200,245,255), 0.125f, col1 - 12*FontScale, y - 1, col5 + (maxnamewidth + 24)*FontScale, height + 2); } col2 += col1; @@ -428,8 +430,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, auto icon = FSetTextureID(player->mo->IntVar(NAME_ScoreIcon)); if (icon.isValid()) { - FTexture *pic = TexMan.GetTexture(icon); - screen->DrawTexture (pic, col3, y, + DrawTexture(twod, icon, false, col3, y, DTA_CleanNoMove, true, TAG_DONE); } @@ -449,8 +450,8 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, if (teamplay && Teams[player->userinfo.GetTeam()].GetLogo().IsNotEmpty ()) { - FTexture *pic = TexMan.GetTextureByName(Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()); - screen->DrawTexture (pic, col1 - (pic->GetDisplayWidth() + 2) * CleanXfac, y, + auto pic = TexMan.GetGameTextureByName(Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()); + DrawTexture(twod, pic, col1 - (pic->GetDisplayWidth() + 2) * CleanXfac, y, DTA_CleanNoMove, true, TAG_DONE); } } @@ -468,10 +469,7 @@ void HU_DrawColorBar(int x, int y, int height, int playernum) D_GetPlayerColor (playernum, &h, &s, &v, NULL); HSVtoRGB (&r, &g, &b, h, s, v); - //float aspect = ActiveRatio(SCREENWIDTH, SCREENHEIGHT); - //if (!AspectTallerThanWide(aspect)) x += (screen->GetWidth() - AspectBaseWidth(aspect)) / 2; - - screen->Clear (x, y, x + 24*FontScale, y + height, -1, + ClearRect(twod, x, y, x + 24*FontScale, y + height, -1, MAKEARGB(255,clamp(int(r*255.f),0,255), clamp(int(g*255.f),0,255), clamp(int(b*255.f),0,255))); @@ -487,7 +485,7 @@ int HU_GetRowColor(player_t *player, bool highlight) { if (teamplay && deathmatch) { - if (TeamLibrary.IsValidTeam (player->userinfo.GetTeam())) + if (FTeam::IsValid (player->userinfo.GetTeam())) return Teams[player->userinfo.GetTeam()].GetTextColor(); else return CR_GREY; diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 9003b53e31e..5c6fe4b0269 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -32,15 +32,6 @@ struct event_t; class player_t; -// -// Globally visible constants. -// -#define HU_FONTSTART uint8_t('!') // the first font characters -#define HU_FONTEND uint8_t('\377') // the last font characters - -// Calculate # of glyphs in font. -#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) - // // Chat routines // @@ -49,8 +40,6 @@ void CT_Init (void); bool CT_Responder (event_t* ev); void CT_Drawer (void); -extern int chatmodeon; - // [RH] Draw deathmatch scores void HU_DrawScores (player_t *me); diff --git a/src/i_net.h b/src/i_net.h deleted file mode 100644 index 63b91c63d8b..00000000000 --- a/src/i_net.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __I_NET_H__ -#define __I_NET_H__ - -// Called by D_DoomMain. -int I_InitNetwork (void); -void I_NetCmd (void); - -#endif diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 2012d9c342b..c32812ce279 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -35,7 +35,7 @@ #include "doomtype.h" #include "g_game.h" #include "d_event.h" -#include "w_wad.h" +#include "filesystem.h" #include "gi.h" #include "v_video.h" #include "d_main.h" @@ -46,12 +46,18 @@ #include "r_state.h" #include "c_bind.h" #include "p_conversation.h" -#include "menu/menu.h" +#include "menu.h" #include "d_net.h" #include "g_levellocals.h" #include "utf8.h" -#include "templates.h" + #include "s_music.h" +#include "texturemanager.h" +#include "v_draw.h" +#include "doommenu.h" +#include "sbar.h" +#include "screenjob.h" +#include "vm.h" FIntermissionDescriptorList IntermissionDescriptors; @@ -69,7 +75,16 @@ IMPLEMENT_POINTERS_END extern int NoWipe; CVAR(Bool, nointerscrollabort, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); -CVAR(Bool, inter_subtitles, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); + +CVAR(Bool, inter_classic_scaling, true, CVAR_ARCHIVE); + +DEFINE_ACTION_FUNCTION(_Screen, GetTextScreenSize) +{ + auto scale = active_con_scaletext(twod, generic_ui); + int hudwidth = twod->GetWidth() / scale; + int hudheight = twod->GetHeight() / scale; + ACTION_RETURN_VEC2(DVector2(hudwidth, hudheight)); +} //========================================================================== // @@ -77,15 +92,15 @@ CVAR(Bool, inter_subtitles, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); // //========================================================================== -void DrawFullscreenSubtitle(const char *text) +void DrawFullscreenSubtitle(FFont* font, const char *text) { if (!text || !*text || !inter_subtitles) return; + text = GStrings.localize(text); // This uses the same scaling as regular HUD messages - auto scale = active_con_scaletext(generic_ui); - int hudwidth = SCREENWIDTH / scale; - int hudheight = SCREENHEIGHT / scale; - FFont *font = generic_ui? NewSmallFont : SmallFont; + auto scale = active_con_scaletext(twod, generic_ui); + int hudwidth = twod->GetWidth() / scale; + int hudheight = twod->GetHeight() / scale; int linelen = hudwidth < 640 ? Scale(hudwidth, 9, 10) - 40 : 560; auto lines = V_BreakLines(font, linelen, text); @@ -108,13 +123,13 @@ void DrawFullscreenSubtitle(const char *text) if (y < 0) y = 0; w = 600; } - screen->Dim(0, 0.5f, Scale(x, SCREENWIDTH, hudwidth), Scale(y, SCREENHEIGHT, hudheight), - Scale(w, SCREENWIDTH, hudwidth), Scale(height, SCREENHEIGHT, hudheight)); + Dim(twod, 0, 0.5f, Scale(x, twod->GetWidth(), hudwidth), Scale(y, twod->GetHeight(), hudheight), + Scale(w, twod->GetWidth(), hudwidth), Scale(height, twod->GetHeight(), hudheight)); x += 20; y += 10; for (const FBrokenLines &line : lines) { - screen->DrawText(font, CR_UNTRANSLATED, x, y, line.Text, + DrawText(twod, font, CR_UNTRANSLATED, x, y, line.Text.GetChars(), DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, TAG_DONE); y += font->GetHeight(); @@ -129,18 +144,13 @@ void DrawFullscreenSubtitle(const char *text) void DIntermissionScreen::Init(FIntermissionAction *desc, bool first) { - if (desc->mMusic.IsEmpty()) - { - // only start the default music if this is the first action in an intermission - if (first) S_ChangeMusic (gameinfo.finaleMusic, gameinfo.finaleOrder, desc->mMusicLooping); - } - else + if (!first && desc->mMusic.IsNotEmpty()) { - S_ChangeMusic (desc->mMusic, desc->mMusicOrder, desc->mMusicLooping); + S_ChangeMusic (desc->mMusic.GetChars(), desc->mMusicOrder, desc->mMusicLooping); } mDuration = desc->mDuration; - const char *texname = desc->mBackground; + const char *texname = desc->mBackground.GetChars(); if (*texname == '@') { char *pp; @@ -160,7 +170,7 @@ void DIntermissionScreen::Init(FIntermissionAction *desc, bool first) } else if (*texname == '$') { - texname = GStrings(texname+1); + texname = GStrings.GetString(texname+1); } if (texname[0] != 0) { @@ -174,16 +184,35 @@ void DIntermissionScreen::Init(FIntermissionAction *desc, bool first) mOverlays[i].x = desc->mOverlays[i].x; mOverlays[i].y = desc->mOverlays[i].y; mOverlays[i].mCondition = desc->mOverlays[i].mCondition; - mOverlays[i].mPic = TexMan.CheckForTexture(desc->mOverlays[i].mName, ETextureType::MiscPatch); + mOverlays[i].mPic = TexMan.CheckForTexture(desc->mOverlays[i].mName.GetChars(), ETextureType::MiscPatch); } mTicker = 0; mSubtitle = desc->mSubtitle; + mFirst = first; + // If this is the first element of an intermission we must delay starting the music until Start() is called. + mMusic = desc->mMusic; + mMusicLooping = desc->mMusicLooping; + mMusicOrder = desc->mMusicOrder; } +void DIntermissionScreen::Start() +{ + if (mFirst) + { + if (mMusic.IsEmpty()) + { + S_ChangeMusic(gameinfo.finaleMusic.GetChars(), gameinfo.finaleOrder, mMusicLooping); + } + else + { + S_ChangeMusic(mMusic.GetChars(), mMusicOrder, mMusicLooping); + } + } +} -int DIntermissionScreen::Responder (event_t *ev) +int DIntermissionScreen::Responder (FInputEvent *ev) { - if (ev->type == EV_KeyDown) + if (ev->Type == EV_KeyDown) { return -1; } @@ -215,28 +244,24 @@ void DIntermissionScreen::Drawer () { if (!mFlatfill) { - screen->DrawTexture (TexMan.GetTexture(mBackground), 0, 0, DTA_Fullscreen, true, TAG_DONE); + DrawTexture(twod, mBackground, false, 0, 0, DTA_Fullscreen, true, TAG_DONE); } else { - screen->FlatFill (0,0, SCREENWIDTH, SCREENHEIGHT, TexMan.GetTexture(mBackground)); + twod->AddFlatFill(0,0, twod->GetWidth(), twod->GetHeight(), TexMan.GetGameTexture(mBackground), (inter_classic_scaling ? -1 : 0)); } } else { - screen->Clear (0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0); + ClearRect(twod, 0, 0, twod->GetWidth(), twod->GetHeight(), 0, 0); } for (unsigned i=0; i < mOverlays.Size(); i++) { if (CheckOverlay(i)) - screen->DrawTexture (TexMan.GetTexture(mOverlays[i].mPic), mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, TAG_DONE); - } - if (mSubtitle) - { - const char *sub = mSubtitle.GetChars(); - if (sub && *sub == '$') sub = GStrings[sub + 1]; - if (sub) DrawFullscreenSubtitle(sub); + DrawTexture(twod, mOverlays[i].mPic, false, mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, TAG_DONE); } + FFont* font = generic_ui ? NewSmallFont : SmallFont; + DrawFullscreenSubtitle(font, mSubtitle.GetChars()); } void DIntermissionScreen::OnDestroy() @@ -263,9 +288,9 @@ void DIntermissionScreenFader::Init(FIntermissionAction *desc, bool first) // //=========================================================================== -int DIntermissionScreenFader::Responder (event_t *ev) +int DIntermissionScreenFader::Responder (FInputEvent *ev) { - if (ev->type == EV_KeyDown) + if (ev->Type == EV_KeyDown) { return -1; } @@ -286,11 +311,11 @@ void DIntermissionScreenFader::Drawer () if (mType == FADE_In) factor = 1.0 - factor; int color = MAKEARGB(int(factor*255), 0,0,0); - screen->DrawTexture (TexMan.GetTexture(mBackground), 0, 0, DTA_Fullscreen, true, DTA_ColorOverlay, color, TAG_DONE); + DrawTexture(twod, mBackground, false, 0, 0, DTA_Fullscreen, true, DTA_ColorOverlay, color, TAG_DONE); for (unsigned i=0; i < mOverlays.Size(); i++) { if (CheckOverlay(i)) - screen->DrawTexture (TexMan.GetTexture(mOverlays[i].mPic), mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, DTA_ColorOverlay, color, TAG_DONE); + DrawTexture(twod, mOverlays[i].mPic, false, mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, DTA_ColorOverlay, color, TAG_DONE); } } } @@ -305,7 +330,16 @@ void DIntermissionScreenText::Init(FIntermissionAction *desc, bool first) { Super::Init(desc, first); mText = static_cast(desc)->mText; - if (mText[0] == '$') mText = GStrings(&mText[1]); + if (mText[0] == '$') mText = GStrings.GetString(&mText[1]); + + auto lines = mText.Split("\n"); + mText = ""; + for (auto& line : lines) + { + line.StripRight(); + mText << line << "\n"; + } + mTextSpeed = static_cast(desc)->mTextSpeed; mTextX = static_cast(desc)->mTextX; usesDefault = mTextX < 0; @@ -346,9 +380,9 @@ void DIntermissionScreenText::Init(FIntermissionAction *desc, bool first) if (mDuration > 0) mDuration += mTextDelay + mTextSpeed * mTextLen; } -int DIntermissionScreenText::Responder (event_t *ev) +int DIntermissionScreenText::Responder (FInputEvent *ev) { - if (ev->type == EV_KeyDown) + if (ev->Type == EV_KeyDown) { if (mTicker < mTextDelay + (mTextLen * mTextSpeed)) { @@ -364,7 +398,6 @@ void DIntermissionScreenText::Drawer () Super::Drawer(); if (mTicker >= mTextDelay) { - FTexture *pic; int w; size_t count; int c; @@ -374,9 +407,9 @@ void DIntermissionScreenText::Drawer () // line feed characters. int numrows; auto font = generic_ui ? NewSmallFont : SmallFont; - auto fontscale = MAX(generic_ui ? MIN(screen->GetWidth() / 640, screen->GetHeight() / 400) : MIN(screen->GetWidth() / 400, screen->GetHeight() / 250), 1); - int cleanwidth = screen->GetWidth() / fontscale; - int cleanheight = screen->GetHeight() / fontscale; + auto fontscale = max(generic_ui ? min(twod->GetWidth() / 640, twod->GetHeight() / 400) : min(twod->GetWidth() / 400, twod->GetHeight() / 250), 1); + int cleanwidth = twod->GetWidth() / fontscale; + int cleanheight = twod->GetHeight() / fontscale; int refwidth = generic_ui ? 640 : 320; int refheight = generic_ui ? 400 : 200; const int kerning = font->GetDefaultKerning(); @@ -389,29 +422,29 @@ void DIntermissionScreenText::Drawer () int rowheight = font->GetHeight() * fontscale; int rowpadding = (generic_ui? 2 : ((gameinfo.gametype & (GAME_DoomStrifeChex) ? 3 : -1))) * fontscale; - int cx = (mTextX - refwidth/2) * fontscale + screen->GetWidth() / 2; - int cy = (mTextY - refheight/2) * fontscale + screen->GetHeight() / 2; - cx = MAX(0, cx); + int cx = (mTextX - refwidth/2) * fontscale + twod->GetWidth() / 2; + int cy = (mTextY - refheight/2) * fontscale + twod->GetHeight() / 2; + cx = max(0, cx); int startx = cx; if (usesDefault) { int allheight; - while ((allheight = numrows * (rowheight + rowpadding)), allheight > screen->GetHeight() && rowpadding > 0) + while ((allheight = numrows * (rowheight + rowpadding)), allheight > twod->GetHeight() && rowpadding > 0) { rowpadding--; } allheight = numrows * (rowheight + rowpadding); - if (screen->GetHeight() - cy - allheight < cy) + if (twod->GetHeight() - cy - allheight < cy) { - cy = (screen->GetHeight() - allheight) / 2; + cy = (twod->GetHeight() - allheight) / 2; if (cy < 0) cy = 0; } } else { // Does this text fall off the end of the screen? If so, try to eliminate some margins first. - while (rowpadding > 0 && cy + numrows * (rowheight + rowpadding) - rowpadding > screen->GetHeight()) + while (rowpadding > 0 && cy + numrows * (rowheight + rowpadding) - rowpadding > twod->GetHeight()) { rowpadding--; } @@ -434,13 +467,13 @@ void DIntermissionScreenText::Drawer () continue; } - pic = font->GetChar (c, mTextColor, &w); + w = font->GetCharWidth(c); w += kerning; w *= fontscale; - if (cx + w > SCREENWIDTH) + if (cx + w > twod->GetWidth()) continue; - screen->DrawChar(font, mTextColor, cx/fontscale, cy/fontscale, c, DTA_KeepRatio, true, DTA_VirtualWidth, cleanwidth, DTA_VirtualHeight, cleanheight, TAG_DONE); + DrawChar(twod, font, mTextColor, cx/fontscale, cy/fontscale, c, DTA_KeepRatio, true, DTA_VirtualWidth, cleanwidth, DTA_VirtualHeight, cleanheight, TAG_DONE); cx += w; } } @@ -455,7 +488,7 @@ void DIntermissionScreenText::Drawer () void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first) { Super::Init(desc, first); - mName = static_cast(desc)->mName; + mName = static_cast(desc)->mName.GetChars(); mClass = PClass::FindActor(static_cast(desc)->mCastClass); if (mClass != NULL) mDefaults = GetDefaultByType(mClass); else @@ -470,7 +503,7 @@ void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first) { mCastSounds[i].mSequence = static_cast(desc)->mCastSounds[i].mSequence; mCastSounds[i].mIndex = static_cast(desc)->mCastSounds[i].mIndex; - mCastSounds[i].mSound = static_cast(desc)->mCastSounds[i].mSound; + mCastSounds[i].mSound = S_FindSound(static_cast(desc)->mCastSounds[i].mSound); } caststate = mDefaults->SeeState; if (mClass->IsDescendantOf(NAME_PlayerPawn)) @@ -481,8 +514,8 @@ void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first) else { advplayerstate = NULL; - casttranslation = 0; - if (mDefaults->Translation != 0) + casttranslation = NO_TRANSLATION; + if (mDefaults->Translation != NO_TRANSLATION) { casttranslation = mDefaults->Translation; } @@ -491,15 +524,15 @@ void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first) castframes = 0; castonmelee = 0; castattacking = false; - if (mDefaults->SeeSound) + if (mDefaults->SeeSound.isvalid()) { S_Sound (CHAN_VOICE, CHANF_UI, mDefaults->SeeSound, 1, ATTN_NONE); } } -int DIntermissionScreenCast::Responder (event_t *ev) +int DIntermissionScreenCast::Responder (FInputEvent *ev) { - if (ev->type != EV_KeyDown) return 0; + if (ev->Type != EV_KeyDown) return 0; if (castdeath) return 1; // already in dying frames @@ -518,10 +551,10 @@ int DIntermissionScreenCast::Responder (event_t *ev) if (mClass->IsDescendantOf(NAME_PlayerPawn)) { - int snd = S_FindSkinnedSound(players[consoleplayer].mo, "*death"); - if (snd != 0) S_Sound (CHAN_VOICE, CHANF_UI, snd, 1, ATTN_NONE); + auto snd = S_FindSkinnedSound(players[consoleplayer].mo, S_FindSound("*death")); + if (snd != NO_SOUND) S_Sound (CHAN_VOICE, CHANF_UI, snd, 1, ATTN_NONE); } - else if (mDefaults->DeathSound) + else if (mDefaults->DeathSound.isvalid()) { S_Sound (CHAN_VOICE, CHANF_UI, mDefaults->DeathSound, 1, ATTN_NONE); } @@ -619,7 +652,6 @@ int DIntermissionScreenCast::Ticker () void DIntermissionScreenCast::Drawer () { spriteframe_t* sprframe; - FTexture* pic; Super::Drawer(); @@ -627,10 +659,10 @@ void DIntermissionScreenCast::Drawer () if (name != NULL) { auto font = generic_ui ? NewSmallFont : SmallFont; - if (*name == '$') name = GStrings(name+1); - screen->DrawText (font, CR_UNTRANSLATED, - (SCREENWIDTH - font->StringWidth (name) * CleanXfac)/2, - (SCREENHEIGHT * 180) / 200, + if (*name == '$') name = GStrings.GetString(name+1); + DrawText(twod, font, CR_UNTRANSLATED, + (twod->GetWidth() - font->StringWidth (name) * CleanXfac)/2, + (twod->GetHeight() * 180) / 200, name, DTA_CleanNoMove, true, TAG_DONE); } @@ -666,16 +698,16 @@ void DIntermissionScreenCast::Drawer () } sprframe = &SpriteFrames[sprites[castsprite].spriteframes + caststate->GetFrame()]; - pic = TexMan.GetTexture(sprframe->Texture[0], true); + auto pic = TexMan.GetGameTexture(sprframe->Texture[0], true); - screen->DrawTexture (pic, 160, 170, + DrawTexture(twod, pic, 160, 170, DTA_320x200, true, DTA_FlipX, sprframe->Flip & 1, - DTA_DestHeightF, pic->GetDisplayHeightDouble() * castscale.Y, - DTA_DestWidthF, pic->GetDisplayWidthDouble() * castscale.X, + DTA_DestHeightF, pic->GetDisplayHeight() * castscale.Y, + DTA_DestWidthF, pic->GetDisplayWidth() * castscale.X, DTA_RenderStyle, mDefaults->RenderStyle, DTA_Alpha, mDefaults->Alpha, - DTA_TranslationIndex, casttranslation, + DTA_TranslationIndex, casttranslation.index(), TAG_DONE); } } @@ -690,13 +722,13 @@ void DIntermissionScreenScroller::Init(FIntermissionAction *desc, bool first) { Super::Init(desc, first); mFirstPic = mBackground; - mSecondPic = TexMan.CheckForTexture(static_cast(desc)->mSecondPic, ETextureType::MiscPatch); + mSecondPic = TexMan.CheckForTexture(static_cast(desc)->mSecondPic.GetChars(), ETextureType::MiscPatch); mScrollDelay = static_cast(desc)->mScrollDelay; mScrollTime = static_cast(desc)->mScrollTime; mScrollDir = static_cast(desc)->mScrollDir; } -int DIntermissionScreenScroller::Responder (event_t *ev) +int DIntermissionScreenScroller::Responder (FInputEvent *ev) { int res = Super::Responder(ev); if (res == -1 && !nointerscrollabort) @@ -709,69 +741,114 @@ int DIntermissionScreenScroller::Responder (event_t *ev) void DIntermissionScreenScroller::Drawer () { - FTexture *tex = TexMan.GetTexture(mFirstPic); - FTexture *tex2 = TexMan.GetTexture(mSecondPic); - if (mTicker >= mScrollDelay && mTicker < mScrollDelay + mScrollTime && tex != NULL && tex2 != NULL) - { + auto tex = TexMan.GetGameTexture(mFirstPic); + auto tex2 = TexMan.GetGameTexture(mSecondPic); - int fwidth = tex->GetDisplayWidth(); - int fheight = tex->GetDisplayHeight(); + // These must round down to the nearest full pixel to cover seams between the two textures. + int fwidth = (int)tex->GetDisplayWidth(); + int fheight = (int)tex->GetDisplayHeight(); + int fwidth2 = (int)tex2->GetDisplayWidth(); + int fheight2 = (int)tex2->GetDisplayHeight(); - double xpos1 = 0, ypos1 = 0, xpos2 = 0, ypos2 = 0; + double xpos1 = 0, ypos1 = 0, xpos2 = 0, ypos2 = 0; - switch (mScrollDir) - { - case SCROLL_Up: - ypos1 = double(mTicker - mScrollDelay) * fheight / mScrollTime; - ypos2 = ypos1 - fheight; - break; + int aheight = fheight == 200 ? 240 : fheight == 400 ? 480 : fheight; + DoubleRect drect; - case SCROLL_Down: - ypos1 = -double(mTicker - mScrollDelay) * fheight / mScrollTime; - ypos2 = ypos1 + fheight; - break; + if (mScrollDir == SCROLL_Left || mScrollDir == SCROLL_Right) + { + // guesstimate the intended aspect ratio. + int awidth = aheight * 4 / 3; + int atotalwidth = fwidth + fwidth2; + int sidespace = (atotalwidth - 2*awidth); + // Now set a clipping rectangle for the intended viewport + double displayratio = atotalwidth / double(aheight) - 4./3.; + double displaywidth = aheight * displayratio; + GetFullscreenRect(displaywidth, aheight, FSMode_ScaleToFit43, &drect); + twod->SetClipRect(int(drect.left), int(drect.top), int(drect.width), int(drect.height)); + + int ticker = clamp(mTicker - mScrollDelay, 0, mScrollTime); + switch (mScrollDir) + { case SCROLL_Left: default: - xpos1 = double(mTicker - mScrollDelay) * fwidth / mScrollTime; - xpos2 = xpos1 - fwidth; + xpos2 = -awidth + double(ticker) * awidth / mScrollTime; + xpos1 = xpos2 + fwidth2; break; case SCROLL_Right: - xpos1 = -double(mTicker - mScrollDelay) * fwidth / mScrollTime; + xpos1 = -double(ticker) * awidth / mScrollTime; xpos2 = xpos1 + fwidth; break; } + double scale = drect.height / aheight; + xpos1 *= scale; + xpos2 *= scale; - screen->DrawTexture (tex, xpos1, ypos1, - DTA_VirtualWidth, fwidth, - DTA_VirtualHeight, fheight, + DrawTexture(twod, tex, xpos1 + drect.left, drect.top, + DTA_DestWidthF, fwidth * scale, + DTA_DestHeightF, aheight * scale, DTA_Masked, false, TAG_DONE); - screen->DrawTexture (tex2, xpos2, ypos2, - DTA_VirtualWidth, fwidth, - DTA_VirtualHeight, fheight, + DrawTexture(twod, tex2, xpos2 + drect.left, drect.top, + DTA_DestWidthF, fwidth2 * scale, + DTA_DestHeightF, aheight * scale, DTA_Masked, false, TAG_DONE); - mBackground = mSecondPic; + + twod->ClearClipRect(); } - else + else { - Super::Drawer(); + // guesstimate the intended aspect ratio. + GetFullscreenRect(fwidth, aheight, FSMode_ScaleToFit43, &drect); + twod->SetClipRect(int(drect.left), int(drect.top), int(drect.width), int(drect.height)); + + int ticker = clamp(mTicker - mScrollDelay, 0, mScrollTime); + + switch (mScrollDir) + { + case SCROLL_Up: + default: + ypos1 = double(ticker) * aheight / mScrollTime; + ypos2 = ypos1 - aheight; + break; + + case SCROLL_Down: + ypos1 = -double(ticker) * aheight / mScrollTime; + ypos2 = ypos1 + aheight; + break; + } + double scale = drect.height / aheight; + ypos1 *= scale; + ypos2 *= scale; + + DrawTexture(twod, tex, drect.left, drect.top + ypos1, + DTA_DestWidthF, fwidth * scale, + DTA_DestHeightF, aheight * scale, + DTA_Masked, false, + TAG_DONE); + DrawTexture(twod, tex2, drect.left, drect.top + ypos2, + DTA_DestWidthF, fwidth2 * scale, + DTA_DestHeightF, aheight * scale, + DTA_Masked, false, + TAG_DONE); + + + twod->ClearClipRect(); } + mBackground = mSecondPic; } - //========================================================================== // // // //========================================================================== -DIntermissionController *DIntermissionController::CurrentIntermission; - -DIntermissionController::DIntermissionController(FIntermissionDescriptor *Desc, bool DeleteDesc, uint8_t state) +DIntermissionController::DIntermissionController(FIntermissionDescriptor *Desc, bool DeleteDesc, bool ending) { mDesc = Desc; mDeleteDesc = DeleteDesc; @@ -780,7 +857,7 @@ DIntermissionController::DIntermissionController(FIntermissionDescriptor *Desc, mSentAdvance = false; mScreen = nullptr; mFirst = true; - mGameState = state; + mEndGame = ending; } bool DIntermissionController::NextPage () @@ -790,8 +867,8 @@ bool DIntermissionController::NextPage () if (mIndex == (int)mDesc->mActions.Size() && mDesc->mLink == NAME_None) { - // last page - return false; + // last page (must block when ending the game.) + return mEndGame; } bg.SetInvalid(); @@ -810,8 +887,6 @@ bool DIntermissionController::NextPage () } else if (action->mClass == TITLE_ID) { - Destroy(); - D_StartTitle (); return false; } else @@ -839,44 +914,48 @@ bool DIntermissionController::NextPage () return false; } -bool DIntermissionController::Responder (event_t *ev) +void DIntermissionController::Start() +{ + if (mScreen) mScreen->Start(); +} + +bool DIntermissionController::Responder (FInputEvent *ev) { if (mScreen != NULL) { - if (ev->type == EV_KeyDown) + if (ev->Type == EV_KeyDown) { - const char *cmd = Bindings.GetBind (ev->data1); + const char *cmd = Bindings.GetBind (ev->KeyScan); - if (cmd != NULL && - (!stricmp(cmd, "toggleconsole") || - !stricmp(cmd, "screenshot"))) + if (cmd != nullptr) { - return false; - } - - // The following is needed to be able to enter main menu with a controller, - // by pressing buttons that are usually assigned to this action, Start and Back by default - if (!stricmp(cmd, "menu_main") || !stricmp(cmd, "pause")) - { - M_StartControlPanel(true); - M_SetMenu(NAME_Mainmenu, -1); - return true; + if (!stricmp(cmd, "toggleconsole") || !stricmp(cmd, "screenshot")) + { + return false; + } + // The following is needed to be able to enter main menu with a controller, + // by pressing buttons that are usually assigned to this action, Start and Back by default + else if (!stricmp(cmd, "menu_main") || !stricmp(cmd, "pause")) + { + M_StartControlPanel(true); + M_SetMenu(NAME_Mainmenu, -1); + return true; + } } } if (mScreen->mTicker < 2) return false; // prevent some leftover events from auto-advancing int res = mScreen->Responder(ev); - if (res == -1 && !mSentAdvance) + if (res == -1) { - Net_WriteByte(DEM_ADVANCEINTER); - mSentAdvance = true; + mAdvance = true; } return !!res; } return false; } -void DIntermissionController::Ticker () +bool DIntermissionController::Ticker () { if (mAdvance) { @@ -891,34 +970,17 @@ void DIntermissionController::Ticker () mAdvance = false; if (!NextPage()) { - switch (mGameState) - { - case FSTATE_InLevel: - primaryLevel->SetMusic(); - gamestate = GS_LEVEL; - wipegamestate = GS_LEVEL; - gameaction = ga_resumeconversation; - viewactive = true; - Destroy(); - break; - - case FSTATE_ChangingLevel: - gameaction = ga_worlddone; - Destroy(); - break; - - default: - break; - } + return false; } } + return true; } void DIntermissionController::Drawer () { if (mScreen != NULL) { - screen->FillBorder(nullptr); + twod->ClearScreen(); mScreen->Drawer(); } } @@ -929,7 +991,6 @@ void DIntermissionController::OnDestroy () if (mScreen != NULL) mScreen->Destroy(); if (mDeleteDesc) delete mDesc; mDesc = NULL; - if (CurrentIntermission == this) CurrentIntermission = NULL; } @@ -939,28 +1000,24 @@ void DIntermissionController::OnDestroy () // //========================================================================== -void F_StartIntermission(FIntermissionDescriptor *desc, bool deleteme, uint8_t state) +DIntermissionController* F_StartIntermission(FIntermissionDescriptor *desc, bool deleteme, bool ending) { - ScaleOverrider s; - if (DIntermissionController::CurrentIntermission != NULL) - { - DIntermissionController::CurrentIntermission->Destroy(); - } + ScaleOverrider s(twod); S_StopAllChannels (); gameaction = ga_nothing; gamestate = GS_FINALE; - if (state == FSTATE_InLevel) wipegamestate = GS_FINALE; // don't wipe when within a level. - viewactive = false; - automapactive = false; - DIntermissionController::CurrentIntermission = Create(desc, deleteme, state); + //if (state == FSTATE_InLevel) wipegamestate = GS_FINALE; // don't wipe when within a level. + auto CurrentIntermission = Create(desc, deleteme, ending); // If the intermission finishes straight away then cancel the wipe. - if (!DIntermissionController::CurrentIntermission->NextPage()) + if (!CurrentIntermission->NextPage()) { - wipegamestate = GS_FINALE; + CurrentIntermission->Destroy(); + return nullptr; } - GC::WriteBarrier(DIntermissionController::CurrentIntermission); + GC::WriteBarrier(CurrentIntermission); + return CurrentIntermission; } @@ -970,91 +1027,59 @@ void F_StartIntermission(FIntermissionDescriptor *desc, bool deleteme, uint8_t s // //========================================================================== -void F_StartIntermission(FName seq, uint8_t state) +DIntermissionController* F_StartIntermission(FName seq) { FIntermissionDescriptor **pdesc = IntermissionDescriptors.CheckKey(seq); - if (pdesc != NULL) + if (pdesc == nullptr || (*pdesc)->mActions.Size() == 0) { - F_StartIntermission(*pdesc, false, state); + return nullptr; } -} - -//========================================================================== -// -// Called by main loop. -// -//========================================================================== - -bool F_Responder (event_t* ev) -{ - ScaleOverrider s; - if (DIntermissionController::CurrentIntermission != NULL) + else { - return DIntermissionController::CurrentIntermission->Responder(ev); + auto desc = *pdesc; + auto action = desc->mActions[0]; + if (action->mClass == TITLE_ID) + { + // is handled elsewhere. + return nullptr; + } + + return F_StartIntermission(desc, false); } - return false; } -//========================================================================== -// -// Called by main loop. -// -//========================================================================== -void F_Ticker () +DEFINE_ACTION_FUNCTION(DIntermissionController, Responder) { - ScaleOverrider s; - if (DIntermissionController::CurrentIntermission != NULL) - { - DIntermissionController::CurrentIntermission->Ticker(); - } + PARAM_SELF_PROLOGUE(DIntermissionController); + PARAM_POINTER(evt, FInputEvent); + ACTION_RETURN_BOOL(self->Responder(evt)); } -//========================================================================== -// -// Called by main loop. -// -//========================================================================== - -void F_Drawer () +DEFINE_ACTION_FUNCTION(DIntermissionController, Ticker) { - ScaleOverrider s; - if (DIntermissionController::CurrentIntermission != NULL) - { - DIntermissionController::CurrentIntermission->Drawer(); - } + PARAM_SELF_PROLOGUE(DIntermissionController); + ACTION_RETURN_BOOL(self->Ticker()); } - -//========================================================================== -// -// Called by main loop. -// -//========================================================================== - -void F_EndFinale () +DEFINE_ACTION_FUNCTION(DIntermissionController, Start) { - ScaleOverrider s; - if (DIntermissionController::CurrentIntermission != NULL) - { - DIntermissionController::CurrentIntermission->Destroy(); - DIntermissionController::CurrentIntermission = NULL; - } + PARAM_SELF_PROLOGUE(DIntermissionController); + self->Start(); + return 0; } -//========================================================================== -// -// Called by net loop. -// -//========================================================================== +DEFINE_ACTION_FUNCTION(DIntermissionController, Drawer) +{ + PARAM_SELF_PROLOGUE(DIntermissionController); + self->Drawer(); + return 0; +} -void F_AdvanceIntermission() +DEFINE_ACTION_FUNCTION(DIntermissionController, NextPage) { - ScaleOverrider s; - if (DIntermissionController::CurrentIntermission != NULL) - { - DIntermissionController::CurrentIntermission->mAdvance = true; - } + PARAM_SELF_PROLOGUE(DIntermissionController); + ACTION_RETURN_BOOL(self->NextPage()); } #include "c_dispatch.h" diff --git a/src/intermission/intermission.h b/src/intermission/intermission.h index 15cc604b711..45c2efd8bc1 100644 --- a/src/intermission/intermission.h +++ b/src/intermission/intermission.h @@ -4,13 +4,14 @@ #include "doomdef.h" #include "dobject.h" #include "m_fixed.h" -#include "textures/textures.h" +#include "textures.h" #include "s_sound.h" #include "v_font.h" #include "g_game.h" #include "v_text.h" -struct event_t; +struct FInputEvent; +struct FState; #define DECLARE_SUPER_CLASS(cls,parent) \ private: \ @@ -165,7 +166,11 @@ class DIntermissionScreen : public DObject int mDuration; FTextureID mBackground; FString mSubtitle; + FString mMusic; + int mMusicOrder; + bool mMusicLooping; bool mFlatfill; + bool mFirst; TArray mOverlays; bool CheckOverlay(int i); @@ -175,7 +180,8 @@ class DIntermissionScreen : public DObject DIntermissionScreen() {} virtual void Init(FIntermissionAction *desc, bool first); - virtual int Responder (event_t *ev); + virtual void Start(); + virtual int Responder (FInputEvent *ev); virtual int Ticker (); virtual void Drawer (); void OnDestroy() override; @@ -201,7 +207,7 @@ class DIntermissionScreenFader : public DIntermissionScreen DIntermissionScreenFader() {} virtual void Init(FIntermissionAction *desc, bool first); - virtual int Responder (event_t *ev); + virtual int Responder (FInputEvent *ev); virtual int Ticker (); virtual void Drawer (); }; @@ -226,7 +232,7 @@ class DIntermissionScreenText : public DIntermissionScreen DIntermissionScreenText() {} virtual void Init(FIntermissionAction *desc, bool first); - virtual int Responder (event_t *ev); + virtual int Responder (FInputEvent *ev); virtual void Drawer (); }; @@ -240,7 +246,7 @@ class DIntermissionScreenCast : public DIntermissionScreen TArray mCastSounds; int casttics; - uint32_t casttranslation; // [RH] Draw "our hero" with their chosen suit color + FTranslationID casttranslation; // [RH] Draw "our hero" with their chosen suit color FState* caststate; FState* basestate; FState* advplayerstate; @@ -255,7 +261,7 @@ class DIntermissionScreenCast : public DIntermissionScreen DIntermissionScreenCast() {} virtual void Init(FIntermissionAction *desc, bool first); - virtual int Responder (event_t *ev); + virtual int Responder (FInputEvent *ev); virtual int Ticker (); virtual void Drawer (); }; @@ -274,7 +280,7 @@ class DIntermissionScreenScroller : public DIntermissionScreen DIntermissionScreenScroller() {} virtual void Init(FIntermissionAction *desc, bool first); - virtual int Responder (event_t *ev); + virtual int Responder (FInputEvent *ev); virtual void Drawer (); }; @@ -295,36 +301,29 @@ class DIntermissionController : public DObject bool mDeleteDesc; bool mFirst; bool mAdvance, mSentAdvance; - uint8_t mGameState; int mIndex; - bool NextPage(); - public: - static DIntermissionController *CurrentIntermission; + bool mEndGame; - DIntermissionController(FIntermissionDescriptor *mDesc = NULL, bool mDeleteDesc = false, uint8_t state = FSTATE_ChangingLevel); - bool Responder (event_t *ev); - void Ticker (); + DIntermissionController(FIntermissionDescriptor *mDesc = NULL, bool mDeleteDesc = false, bool ending = false); + bool Responder (FInputEvent *ev); + bool Ticker (); + void Start(); void Drawer (); void OnDestroy() override; + bool NextPage(); - friend void F_AdvanceIntermission(); - friend void F_StartIntermission(FIntermissionDescriptor *, bool, uint8_t); + friend DIntermissionController* F_StartIntermission(FIntermissionDescriptor *, bool, uint8_t); }; // Interface for main loop -bool F_Responder (event_t* ev); -void F_Ticker (); -void F_Drawer (); -void F_StartIntermission(FIntermissionDescriptor *desc, bool deleteme, uint8_t state); -void F_StartIntermission(FName desc, uint8_t state); -void F_EndFinale (); -void F_AdvanceIntermission(); +DIntermissionController* F_StartIntermission(FIntermissionDescriptor *desc, bool deleteme, bool ending = false); +DIntermissionController* F_StartIntermission(FName desc); // Create an intermission from old cluster data -void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int cdid, const char *flat, +DIntermissionController* F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int cdid, const char *flat, const char *text, INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText, bool ending, FName endsequence = NAME_None); diff --git a/src/intermission/intermission_parse.cpp b/src/intermission/intermission_parse.cpp index 69ff818310e..d1089526b22 100644 --- a/src/intermission/intermission_parse.cpp +++ b/src/intermission/intermission_parse.cpp @@ -37,10 +37,12 @@ #include #include "intermission/intermission.h" #include "g_level.h" -#include "w_wad.h" +#include "filesystem.h" #include "c_dispatch.h" #include "gstrings.h" #include "gi.h" +#include "screenjob.h" +#include "d_event.h" static void ReplaceIntermission(FName intname,FIntermissionDescriptor *desc) @@ -301,29 +303,29 @@ bool FIntermissionActionTextscreen::ParseKey(FScanner &sc) { sc.MustGetToken('='); sc.MustGetToken(TK_StringConst); - int lump = Wads.CheckNumForFullName(sc.String, true); + int lump = fileSystem.CheckNumForFullName(sc.String, true); bool done = false; if (lump > 0) { // Check if this comes from either Hexen.wad or Hexdd.wad and if so, map to the string table. - int fileno = Wads.GetLumpFile(lump); - auto fn = Wads.GetWadName(fileno); + int fileno = fileSystem.GetFileContainer(lump); + auto fn = fileSystem.GetResourceFileName(fileno); if (fn && (!stricmp(fn, "HEXEN.WAD") || !stricmp(fn, "HEXDD.WAD"))) { FStringf key("TXT_%.5s_%s", fn, sc.String); - if (GStrings.exists(key)) + if (GStrings.exists(key.GetChars())) { mText = "$" + key; done = true; } } if (!done) - mText = Wads.ReadLump(lump).GetString(); + mText = GetStringFromLump(lump); } else { // only print an error if coming from a PWAD - if (Wads.GetLumpFile(sc.LumpNum) > Wads.GetMaxIwadNum()) + if (fileSystem.GetFileContainer(sc.LumpNum) > fileSystem.GetMaxIwadNum()) sc.ScriptMessage("Unknown text lump '%s'", sc.String); mText.Format("Unknown text lump '%s'", sc.String); } @@ -849,7 +851,7 @@ FName FMapInfoParser::CheckEndSequence() // //========================================================================== -void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int cdid, const char *flat, +DIntermissionController* F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int cdid, const char *flat, const char *text, INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText, bool ending, FName endsequence) { @@ -859,10 +861,10 @@ void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int FIntermissionActionTextscreen *textscreen = new FIntermissionActionTextscreen; if (textInLump) { - int lump = Wads.CheckNumForFullName(text, true); + int lump = fileSystem.CheckNumForFullName(text, true); if (lump > 0) { - textscreen->mText = Wads.ReadLump(lump).GetString(); + textscreen->mText = GetStringFromLump(lump); } else { @@ -909,19 +911,19 @@ void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int desc->mActions.Push(wiper); } - F_StartIntermission(desc, true, ending? FSTATE_EndingGame : FSTATE_ChangingLevel); + return F_StartIntermission(desc, true, ending && endsequence != NAME_None); } else if (ending) { FIntermissionDescriptor **pdesc = IntermissionDescriptors.CheckKey(endsequence); if (pdesc != NULL) { - F_StartIntermission(*pdesc, false, ending? FSTATE_EndingGame : FSTATE_ChangingLevel); + return F_StartIntermission(*pdesc, false, ending); } } + return nullptr; } - CCMD(testfinale) { if (argv.argc() < 2) @@ -933,7 +935,7 @@ CCMD(testfinale) if (argv.argc() == 2) { - text = GStrings.GetString(argv[1], nullptr); + text = GStrings.CheckString(argv[1], nullptr); } else { @@ -952,5 +954,7 @@ CCMD(testfinale) return; } - F_StartFinale(gameinfo.finaleMusic, gameinfo.finaleOrder, -1, 0, gameinfo.FinaleFlat, text, false, false, true, true); + auto controller = F_StartFinale(gameinfo.finaleMusic.GetChars(), gameinfo.finaleOrder, -1, 0, gameinfo.FinaleFlat.GetChars(), text, false, false, true, true); + RunIntermission(nullptr, nullptr, controller, nullptr, [=](bool) { gameaction = ga_nothing; }); + } diff --git a/src/launcher/launcherbanner.cpp b/src/launcher/launcherbanner.cpp new file mode 100644 index 00000000000..823b0021d01 --- /dev/null +++ b/src/launcher/launcherbanner.cpp @@ -0,0 +1,34 @@ + +#include "launcherbanner.h" +#include "gstrings.h" +#include "version.h" +#include +#include +#include + +LauncherBanner::LauncherBanner(Widget* parent) : Widget(parent) +{ + Logo = new ImageBox(this); + VersionLabel = new TextLabel(this); + VersionLabel->SetTextAlignment(TextLabelAlignment::Right); + + Logo->SetImage(Image::LoadResource("widgets/banner.png")); +} + +void LauncherBanner::UpdateLanguage() +{ + FString versionText = GStrings.GetString("PICKER_VERSION"); + versionText.Substitute("%s", GetVersionString()); + VersionLabel->SetText(versionText.GetChars()); +} + +double LauncherBanner::GetPreferredHeight() const +{ + return Logo->GetPreferredHeight(); +} + +void LauncherBanner::OnGeometryChanged() +{ + Logo->SetFrameGeometry(0.0, 0.0, GetWidth(), Logo->GetPreferredHeight()); + VersionLabel->SetFrameGeometry(20.0, GetHeight() - 10.0 - VersionLabel->GetPreferredHeight(), GetWidth() - 40.0, VersionLabel->GetPreferredHeight()); +} diff --git a/src/launcher/launcherbanner.h b/src/launcher/launcherbanner.h new file mode 100644 index 00000000000..9a27a5694d8 --- /dev/null +++ b/src/launcher/launcherbanner.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +class ImageBox; +class TextLabel; + +class LauncherBanner : public Widget +{ +public: + LauncherBanner(Widget* parent); + void UpdateLanguage(); + + double GetPreferredHeight() const; + +private: + void OnGeometryChanged() override; + + ImageBox* Logo = nullptr; + TextLabel* VersionLabel = nullptr; +}; diff --git a/src/launcher/launcherbuttonbar.cpp b/src/launcher/launcherbuttonbar.cpp new file mode 100644 index 00000000000..789881000e0 --- /dev/null +++ b/src/launcher/launcherbuttonbar.cpp @@ -0,0 +1,46 @@ + +#include "launcherbuttonbar.h" +#include "launcherwindow.h" +#include "gstrings.h" +#include + +LauncherButtonbar::LauncherButtonbar(LauncherWindow* parent) : Widget(parent) +{ + PlayButton = new PushButton(this); + ExitButton = new PushButton(this); + + PlayButton->OnClick = [=]() { OnPlayButtonClicked(); }; + ExitButton->OnClick = [=]() { OnExitButtonClicked(); }; +} + +void LauncherButtonbar::UpdateLanguage() +{ + PlayButton->SetText(GStrings.GetString("PICKER_PLAY")); + ExitButton->SetText(GStrings.GetString("PICKER_EXIT")); +} + +double LauncherButtonbar::GetPreferredHeight() const +{ + return 20.0 + std::max(PlayButton->GetPreferredHeight(), ExitButton->GetPreferredHeight()); +} + +void LauncherButtonbar::OnGeometryChanged() +{ + PlayButton->SetFrameGeometry(20.0, 10.0, 120.0, PlayButton->GetPreferredHeight()); + ExitButton->SetFrameGeometry(GetWidth() - 20.0 - 120.0, 10.0, 120.0, PlayButton->GetPreferredHeight()); +} + +void LauncherButtonbar::OnPlayButtonClicked() +{ + GetLauncher()->Start(); +} + +void LauncherButtonbar::OnExitButtonClicked() +{ + GetLauncher()->Exit(); +} + +LauncherWindow* LauncherButtonbar::GetLauncher() const +{ + return static_cast(Parent()); +} diff --git a/src/launcher/launcherbuttonbar.h b/src/launcher/launcherbuttonbar.h new file mode 100644 index 00000000000..4872cb6127f --- /dev/null +++ b/src/launcher/launcherbuttonbar.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +class LauncherWindow; +class PushButton; + +class LauncherButtonbar : public Widget +{ +public: + LauncherButtonbar(LauncherWindow* parent); + void UpdateLanguage(); + + double GetPreferredHeight() const; + +private: + void OnGeometryChanged() override; + void OnPlayButtonClicked(); + void OnExitButtonClicked(); + + LauncherWindow* GetLauncher() const; + + PushButton* PlayButton = nullptr; + PushButton* ExitButton = nullptr; +}; diff --git a/src/launcher/launcherwindow.cpp b/src/launcher/launcherwindow.cpp new file mode 100644 index 00000000000..860d1a109f5 --- /dev/null +++ b/src/launcher/launcherwindow.cpp @@ -0,0 +1,96 @@ +#include "launcherwindow.h" +#include "launcherbanner.h" +#include "launcherbuttonbar.h" +#include "playgamepage.h" +#include "settingspage.h" +#include "v_video.h" +#include "version.h" +#include "i_interface.h" +#include "gstrings.h" +#include +#include +#include + +int LauncherWindow::ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString * extraArgs) +{ + Size screenSize = GetScreenSize(); + double windowWidth = 615.0; + double windowHeight = 700.0; + + auto launcher = std::make_unique(wads, numwads, defaultiwad, autoloadflags); + launcher->SetFrameGeometry((screenSize.width - windowWidth) * 0.5, (screenSize.height - windowHeight) * 0.5, windowWidth, windowHeight); + launcher->Show(); + + DisplayWindow::RunLoop(); + + if(extraArgs) *extraArgs = launcher->PlayGame->GetExtraArgs(); + + return launcher->ExecResult; +} + +LauncherWindow::LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags) : Widget(nullptr, WidgetType::Window) +{ + SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); + SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51)); + SetWindowCaptionColor(Colorf::fromRgba8(33, 33, 33)); + SetWindowCaptionTextColor(Colorf::fromRgba8(226, 223, 219)); + SetWindowTitle(GAMENAME); + + Banner = new LauncherBanner(this); + Pages = new TabWidget(this); + Buttonbar = new LauncherButtonbar(this); + + PlayGame = new PlayGamePage(this, wads, numwads, defaultiwad); + Settings = new SettingsPage(this, autoloadflags); + + Pages->AddTab(PlayGame, "Play"); + Pages->AddTab(Settings, "Settings"); + + UpdateLanguage(); + + Pages->SetCurrentWidget(PlayGame); + PlayGame->SetFocus(); +} + +void LauncherWindow::Start() +{ + Settings->Save(); + + ExecResult = PlayGame->GetSelectedGame(); + DisplayWindow::ExitLoop(); +} + +void LauncherWindow::Exit() +{ + ExecResult = -1; + DisplayWindow::ExitLoop(); +} + +void LauncherWindow::UpdateLanguage() +{ + Pages->SetTabText(PlayGame, GStrings.GetString("PICKER_TAB_PLAY")); + Pages->SetTabText(Settings, GStrings.GetString("OPTMNU_TITLE")); + Banner->UpdateLanguage(); + PlayGame->UpdateLanguage(); + Settings->UpdateLanguage(); + Buttonbar->UpdateLanguage(); +} + +void LauncherWindow::OnClose() +{ + Exit(); +} + +void LauncherWindow::OnGeometryChanged() +{ + double top = 0.0; + double bottom = GetHeight(); + + Banner->SetFrameGeometry(0.0, top, GetWidth(), Banner->GetPreferredHeight()); + top += Banner->GetPreferredHeight(); + + bottom -= Buttonbar->GetPreferredHeight(); + Buttonbar->SetFrameGeometry(0.0, bottom, GetWidth(), Buttonbar->GetPreferredHeight()); + + Pages->SetFrameGeometry(0.0, top, GetWidth(), std::max(bottom - top, 0.0)); +} diff --git a/src/launcher/launcherwindow.h b/src/launcher/launcherwindow.h new file mode 100644 index 00000000000..8e7c8bbe678 --- /dev/null +++ b/src/launcher/launcherwindow.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "tarray.h" +#include "zstring.h" + +class TabWidget; +class LauncherBanner; +class LauncherButtonbar; +class PlayGamePage; +class SettingsPage; +struct WadStuff; + +class LauncherWindow : public Widget +{ +public: + static int ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString * extraArgs = nullptr); + + LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags); + void UpdateLanguage(); + + void Start(); + void Exit(); + +private: + void OnClose() override; + void OnGeometryChanged() override; + + LauncherBanner* Banner = nullptr; + TabWidget* Pages = nullptr; + LauncherButtonbar* Buttonbar = nullptr; + + PlayGamePage* PlayGame = nullptr; + SettingsPage* Settings = nullptr; + + int ExecResult = -1; +}; diff --git a/src/launcher/playgamepage.cpp b/src/launcher/playgamepage.cpp new file mode 100644 index 00000000000..46bd16a92c0 --- /dev/null +++ b/src/launcher/playgamepage.cpp @@ -0,0 +1,100 @@ + +#include "playgamepage.h" +#include "launcherwindow.h" +#include "i_interface.h" +#include "gstrings.h" +#include "version.h" +#include +#include +#include + +PlayGamePage::PlayGamePage(LauncherWindow* launcher, WadStuff* wads, int numwads, int defaultiwad) : Widget(nullptr), Launcher(launcher) +{ + WelcomeLabel = new TextLabel(this); + SelectLabel = new TextLabel(this); + ParametersLabel = new TextLabel(this); + GamesList = new ListView(this); + ParametersEdit = new LineEdit(this); + + for (int i = 0; i < numwads; i++) + { + const char* filepart = strrchr(wads[i].Path.GetChars(), '/'); + if (filepart == NULL) + filepart = wads[i].Path.GetChars(); + else + filepart++; + + FString work; + if (*filepart) work.Format("%s (%s)", wads[i].Name.GetChars(), filepart); + else work = wads[i].Name.GetChars(); + + GamesList->AddItem(work.GetChars()); + } + + if (defaultiwad >= 0 && defaultiwad < numwads) + { + GamesList->SetSelectedItem(defaultiwad); + GamesList->ScrollToItem(defaultiwad); + } + + GamesList->OnActivated = [=]() { OnGamesListActivated(); }; +} + +std::string PlayGamePage::GetExtraArgs() +{ + return ParametersEdit->GetText(); +} + +int PlayGamePage::GetSelectedGame() +{ + return GamesList->GetSelectedItem(); +} + +void PlayGamePage::UpdateLanguage() +{ + SelectLabel->SetText(GStrings.GetString("PICKER_SELECT")); + ParametersLabel->SetText(GStrings.GetString("PICKER_ADDPARM")); + FString welcomeText = GStrings.GetString("PICKER_WELCOME"); + welcomeText.Substitute("%s", GAMENAME); + WelcomeLabel->SetText(welcomeText.GetChars()); +} + +void PlayGamePage::OnGamesListActivated() +{ + Launcher->Start(); +} + +void PlayGamePage::OnSetFocus() +{ + GamesList->SetFocus(); +} + +void PlayGamePage::OnGeometryChanged() +{ + double y = 10.0; + + WelcomeLabel->SetFrameGeometry(0.0, y, GetWidth(), WelcomeLabel->GetPreferredHeight()); + y += WelcomeLabel->GetPreferredHeight(); + + y += 10.0; + + SelectLabel->SetFrameGeometry(0.0, y, GetWidth(), SelectLabel->GetPreferredHeight()); + y += SelectLabel->GetPreferredHeight(); + + double listViewTop = y; + + y = GetHeight() - 10.0; + + double editHeight = 24.0; + y -= editHeight; + ParametersEdit->SetFrameGeometry(0.0, y, GetWidth(), editHeight); + y -= 5.0; + + double labelHeight = ParametersLabel->GetPreferredHeight(); + y -= labelHeight; + ParametersLabel->SetFrameGeometry(0.0, y, GetWidth(), labelHeight); + y -= 10.0; + + double listViewBottom = y - 10.0; + GamesList->SetFrameGeometry(0.0, listViewTop, GetWidth(), std::max(listViewBottom - listViewTop, 0.0)); +} diff --git a/src/launcher/playgamepage.h b/src/launcher/playgamepage.h new file mode 100644 index 00000000000..af0e95bc351 --- /dev/null +++ b/src/launcher/playgamepage.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +class LauncherWindow; +class TextLabel; +class ListView; +class LineEdit; +struct WadStuff; + +class PlayGamePage : public Widget +{ +public: + PlayGamePage(LauncherWindow* launcher, WadStuff* wads, int numwads, int defaultiwad); + void UpdateLanguage(); + + std::string GetExtraArgs(); + int GetSelectedGame(); + +private: + void OnGeometryChanged() override; + void OnSetFocus() override; + void OnGamesListActivated(); + + LauncherWindow* Launcher = nullptr; + + TextLabel* WelcomeLabel = nullptr; + TextLabel* SelectLabel = nullptr; + TextLabel* ParametersLabel = nullptr; + ListView* GamesList = nullptr; + LineEdit* ParametersEdit = nullptr; +}; diff --git a/src/launcher/settingspage.cpp b/src/launcher/settingspage.cpp new file mode 100644 index 00000000000..1bfe54d22d8 --- /dev/null +++ b/src/launcher/settingspage.cpp @@ -0,0 +1,207 @@ + +#include "settingspage.h" +#include "launcherwindow.h" +#include "gstrings.h" +#include "i_interface.h" +#include "v_video.h" +#include +#include +#include +#include + +#ifdef RENDER_BACKENDS +EXTERN_CVAR(Int, vid_preferbackend); +#endif + +EXTERN_CVAR(String, language) +EXTERN_CVAR(Bool, queryiwad); + +SettingsPage::SettingsPage(LauncherWindow* launcher, int* autoloadflags) : Widget(nullptr), Launcher(launcher), AutoloadFlags(autoloadflags) +{ + LangLabel = new TextLabel(this); + GeneralLabel = new TextLabel(this); + ExtrasLabel = new TextLabel(this); + FullscreenCheckbox = new CheckboxLabel(this); + DisableAutoloadCheckbox = new CheckboxLabel(this); + DontAskAgainCheckbox = new CheckboxLabel(this); + LightsCheckbox = new CheckboxLabel(this); + BrightmapsCheckbox = new CheckboxLabel(this); + WidescreenCheckbox = new CheckboxLabel(this); + +#ifdef RENDER_BACKENDS + BackendLabel = new TextLabel(this); + VulkanCheckbox = new CheckboxLabel(this); + OpenGLCheckbox = new CheckboxLabel(this); + GLESCheckbox = new CheckboxLabel(this); +#endif + + FullscreenCheckbox->SetChecked(vid_fullscreen); + DontAskAgainCheckbox->SetChecked(!queryiwad); + + int flags = *autoloadflags; + DisableAutoloadCheckbox->SetChecked(flags & 1); + LightsCheckbox->SetChecked(flags & 2); + BrightmapsCheckbox->SetChecked(flags & 4); + WidescreenCheckbox->SetChecked(flags & 8); + +#ifdef RENDER_BACKENDS + OpenGLCheckbox->SetRadioStyle(true); + VulkanCheckbox->SetRadioStyle(true); + GLESCheckbox->SetRadioStyle(true); + OpenGLCheckbox->FuncChanged = [this](bool on) { if (on) { VulkanCheckbox->SetChecked(false); GLESCheckbox->SetChecked(false); }}; + VulkanCheckbox->FuncChanged = [this](bool on) { if (on) { OpenGLCheckbox->SetChecked(false); GLESCheckbox->SetChecked(false); }}; + GLESCheckbox->FuncChanged = [this](bool on) { if (on) { VulkanCheckbox->SetChecked(false); OpenGLCheckbox->SetChecked(false); }}; + switch (vid_preferbackend) + { + case 0: + OpenGLCheckbox->SetChecked(true); + break; + case 1: + VulkanCheckbox->SetChecked(true); + break; + case 2: + GLESCheckbox->SetChecked(true); + break; + } +#endif + + LangList = new ListView(this); + + try + { + auto data = LoadWidgetData("menudef.txt"); + FScanner sc; + sc.OpenMem("menudef.txt", data); + while (sc.GetString()) + { + if (sc.Compare("OptionString")) + { + sc.MustGetString(); + if (sc.Compare("LanguageOptions")) + { + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + FString iso = sc.String; + sc.MustGetStringName(","); + sc.MustGetString(); + if(iso.CompareNoCase("auto")) + languages.push_back(std::make_pair(iso, FString(sc.String))); + } + } + } + } + } + catch (const std::exception& ex) + { + hideLanguage = true; + } + int i = 0; + for (auto& l : languages) + { + LangList->AddItem(l.second.GetChars()); + if (!l.first.CompareNoCase(::language)) + LangList->SetSelectedItem(i); + i++; + } + + LangList->OnChanged = [=](int i) { OnLanguageChanged(i); }; +} + +void SettingsPage::Save() +{ + vid_fullscreen = FullscreenCheckbox->GetChecked(); + queryiwad = !DontAskAgainCheckbox->GetChecked(); + + int flags = 0; + if (DisableAutoloadCheckbox->GetChecked()) flags |= 1; + if (LightsCheckbox->GetChecked()) flags |= 2; + if (BrightmapsCheckbox->GetChecked()) flags |= 4; + if (WidescreenCheckbox->GetChecked()) flags |= 8; + *AutoloadFlags = flags; + +#ifdef RENDER_BACKENDS + int v = 1; + if (OpenGLCheckbox->GetChecked()) v = 0; + else if (VulkanCheckbox->GetChecked()) v = 1; + else if (GLESCheckbox->GetChecked()) v = 2; + if (v != vid_preferbackend) vid_preferbackend = v; +#endif +} + +void SettingsPage::UpdateLanguage() +{ + LangLabel->SetText(GStrings.GetString("OPTMNU_LANGUAGE")); + GeneralLabel->SetText(GStrings.GetString("PICKER_GENERAL")); + ExtrasLabel->SetText(GStrings.GetString("PICKER_EXTRA")); + FullscreenCheckbox->SetText(GStrings.GetString("PICKER_FULLSCREEN")); + DisableAutoloadCheckbox->SetText(GStrings.GetString("PICKER_NOAUTOLOAD")); + DontAskAgainCheckbox->SetText(GStrings.GetString("PICKER_DONTASK")); + LightsCheckbox->SetText(GStrings.GetString("PICKER_LIGHTS")); + BrightmapsCheckbox->SetText(GStrings.GetString("PICKER_BRIGHTMAPS")); + WidescreenCheckbox->SetText(GStrings.GetString("PICKER_WIDESCREEN")); + +#ifdef RENDER_BACKENDS + BackendLabel->SetText(GStrings.GetString("PICKER_PREFERBACKEND")); + VulkanCheckbox->SetText(GStrings.GetString("OPTVAL_VULKAN")); + OpenGLCheckbox->SetText(GStrings.GetString("OPTVAL_OPENGL")); + GLESCheckbox->SetText(GStrings.GetString("OPTVAL_OPENGLES")); +#endif +} + +void SettingsPage::OnLanguageChanged(int i) +{ + ::language = languages[i].first.GetChars(); + GStrings.UpdateLanguage(::language); // CVAR callbacks are not active yet. + UpdateLanguage(); + Update(); + Launcher->UpdateLanguage(); +} + +void SettingsPage::OnGeometryChanged() +{ + double panelWidth = 160.0; + double y = 0.0; + double w = GetWidth(); + double h = GetHeight(); + + GeneralLabel->SetFrameGeometry(0.0, y, 190.0, GeneralLabel->GetPreferredHeight()); + ExtrasLabel->SetFrameGeometry(w - panelWidth, y, panelWidth, ExtrasLabel->GetPreferredHeight()); + y += GeneralLabel->GetPreferredHeight(); + + FullscreenCheckbox->SetFrameGeometry(0.0, y, 190.0, FullscreenCheckbox->GetPreferredHeight()); + LightsCheckbox->SetFrameGeometry(w - panelWidth, y, panelWidth, LightsCheckbox->GetPreferredHeight()); + y += FullscreenCheckbox->GetPreferredHeight(); + + DisableAutoloadCheckbox->SetFrameGeometry(0.0, y, 190.0, DisableAutoloadCheckbox->GetPreferredHeight()); + BrightmapsCheckbox->SetFrameGeometry(w - panelWidth, y, panelWidth, BrightmapsCheckbox->GetPreferredHeight()); + y += DisableAutoloadCheckbox->GetPreferredHeight(); + + DontAskAgainCheckbox->SetFrameGeometry(0.0, y, 190.0, DontAskAgainCheckbox->GetPreferredHeight()); + WidescreenCheckbox->SetFrameGeometry(w - panelWidth, y, panelWidth, WidescreenCheckbox->GetPreferredHeight()); + y += DontAskAgainCheckbox->GetPreferredHeight(); + +#ifdef RENDER_BACKENDS + double x = w / 2 - panelWidth / 2; + y = 0; + BackendLabel->SetFrameGeometry(x, y, 190.0, BackendLabel->GetPreferredHeight()); + y += BackendLabel->GetPreferredHeight(); + + VulkanCheckbox->SetFrameGeometry(x, y, 190.0, VulkanCheckbox->GetPreferredHeight()); + y += VulkanCheckbox->GetPreferredHeight(); + + OpenGLCheckbox->SetFrameGeometry(x, y, 190.0, OpenGLCheckbox->GetPreferredHeight()); + y += OpenGLCheckbox->GetPreferredHeight(); + + GLESCheckbox->SetFrameGeometry(x, y, 190.0, GLESCheckbox->GetPreferredHeight()); + y += GLESCheckbox->GetPreferredHeight(); +#endif + + if (!hideLanguage) + { + LangLabel->SetFrameGeometry(0.0, y, w, LangLabel->GetPreferredHeight()); + y += LangLabel->GetPreferredHeight(); + LangList->SetFrameGeometry(0.0, y, w, std::max(h - y, 0.0)); + } +} diff --git a/src/launcher/settingspage.h b/src/launcher/settingspage.h new file mode 100644 index 00000000000..a65f4f164f0 --- /dev/null +++ b/src/launcher/settingspage.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include "gstrings.h" + +#define RENDER_BACKENDS + +class LauncherWindow; +class TextLabel; +class CheckboxLabel; +class ListView; + +class SettingsPage : public Widget +{ +public: + SettingsPage(LauncherWindow* launcher, int* autoloadflags); + void UpdateLanguage(); + + void Save(); + +private: + void OnLanguageChanged(int i); + void OnGeometryChanged() override; + + LauncherWindow* Launcher = nullptr; + + TextLabel* LangLabel = nullptr; + TextLabel* GeneralLabel = nullptr; + TextLabel* ExtrasLabel = nullptr; + CheckboxLabel* FullscreenCheckbox = nullptr; + CheckboxLabel* DisableAutoloadCheckbox = nullptr; + CheckboxLabel* DontAskAgainCheckbox = nullptr; + CheckboxLabel* LightsCheckbox = nullptr; + CheckboxLabel* BrightmapsCheckbox = nullptr; + CheckboxLabel* WidescreenCheckbox = nullptr; +#ifdef RENDER_BACKENDS + TextLabel* BackendLabel = nullptr; + CheckboxLabel* VulkanCheckbox = nullptr; + CheckboxLabel* OpenGLCheckbox = nullptr; + CheckboxLabel* GLESCheckbox = nullptr; +#endif + ListView* LangList = nullptr; + + int* AutoloadFlags = nullptr; + + TArray> languages; + bool hideLanguage = false; +}; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index c8256dda444..e918c240823 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -49,10 +49,12 @@ #include "a_keys.h" #include "d_net.h" #include "serializer.h" +#include "serialize_obj.h" #include "r_utility.h" #include "a_morph.h" #include "g_levellocals.h" #include "vm.h" +#include "d_main.h" uint8_t globalfreeze, globalchangefreeze; // user's freeze state. @@ -64,7 +66,7 @@ void cht_DoMDK(player_t *player, const char *mod) { if (player->mo == NULL) { - Printf("%s\n", GStrings("TXT_WHAT_KILL")); + Printf("%s\n", GStrings.GetString("TXT_WHAT_KILL")); } else if (!deathmatch) { @@ -113,44 +115,45 @@ void cht_DoCheat (player_t *player, int cheat) player->health = deh.GodHealth; } // fall through to CHT_GOD + [[fallthrough]]; case CHT_GOD: player->cheats ^= CF_GODMODE; if (player->cheats & CF_GODMODE) - msg = GStrings("STSTR_DQDON"); + msg = GStrings.GetString("STSTR_DQDON"); else - msg = GStrings("STSTR_DQDOFF"); + msg = GStrings.GetString("STSTR_DQDOFF"); break; case CHT_BUDDHA: player->cheats ^= CF_BUDDHA; if (player->cheats & CF_BUDDHA) - msg = GStrings("TXT_BUDDHAON"); + msg = GStrings.GetString("TXT_BUDDHAON"); else - msg = GStrings("TXT_BUDDHAOFF"); + msg = GStrings.GetString("TXT_BUDDHAOFF"); break; case CHT_GOD2: player->cheats ^= CF_GODMODE2; if (player->cheats & CF_GODMODE2) - msg = GStrings("STSTR_DQD2ON"); + msg = GStrings.GetString("STSTR_DQD2ON"); else - msg = GStrings("STSTR_DQD2OFF"); + msg = GStrings.GetString("STSTR_DQD2OFF"); break; case CHT_BUDDHA2: player->cheats ^= CF_BUDDHA2; if (player->cheats & CF_BUDDHA2) - msg = GStrings("TXT_BUDDHA2ON"); + msg = GStrings.GetString("TXT_BUDDHA2ON"); else - msg = GStrings("TXT_BUDDHA2OFF"); + msg = GStrings.GetString("TXT_BUDDHA2OFF"); break; case CHT_NOCLIP: player->cheats ^= CF_NOCLIP; if (player->cheats & CF_NOCLIP) - msg = GStrings("STSTR_NCON"); + msg = GStrings.GetString("STSTR_NCON"); else - msg = GStrings("STSTR_NCOFF"); + msg = GStrings.GetString("STSTR_NCOFF"); break; case CHT_NOCLIP2: @@ -158,12 +161,12 @@ void cht_DoCheat (player_t *player, int cheat) if (player->cheats & CF_NOCLIP2) { player->cheats |= CF_NOCLIP; - msg = GStrings("STSTR_NC2ON"); + msg = GStrings.GetString("STSTR_NC2ON"); } else { player->cheats &= ~CF_NOCLIP; - msg = GStrings("STSTR_NCOFF"); + msg = GStrings.GetString("STSTR_NC2OFF"); } if (player->mo->Vel.X == 0) player->mo->Vel.X = MinVel; // force some lateral movement so that internal variables are up to date break; @@ -171,9 +174,9 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_NOVELOCITY: player->cheats ^= CF_NOVELOCITY; if (player->cheats & CF_NOVELOCITY) - msg = GStrings("TXT_LEADBOOTSON"); + msg = GStrings.GetString("TXT_LEADBOOTSON"); else - msg = GStrings("TXT_LEADBOOTSOFF"); + msg = GStrings.GetString("TXT_LEADBOOTSOFF"); break; case CHT_FLY: @@ -184,13 +187,13 @@ void cht_DoCheat (player_t *player, int cheat) { player->mo->flags |= MF_NOGRAVITY; player->mo->flags2 |= MF2_FLY; - msg = GStrings("TXT_LIGHTER"); + msg = GStrings.GetString("TXT_LIGHTER"); } else { player->mo->flags &= ~MF_NOGRAVITY; player->mo->flags2 &= ~MF2_FLY; - msg = GStrings("TXT_GRAVITY"); + msg = GStrings.GetString("TXT_GRAVITY"); } } break; @@ -203,25 +206,25 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_NOTARGET: player->cheats ^= CF_NOTARGET; if (player->cheats & CF_NOTARGET) - msg = GStrings("TXT_NOTARGET_ON"); + msg = GStrings.GetString("TXT_NOTARGET_ON"); else - msg = GStrings("TXT_NOTARGET_OFF"); + msg = GStrings.GetString("TXT_NOTARGET_OFF"); break; case CHT_ANUBIS: player->cheats ^= CF_FRIGHTENING; if (player->cheats & CF_FRIGHTENING) - msg = GStrings("TXT_ANUBIS_ON"); + msg = GStrings.GetString("TXT_ANUBIS_ON"); else - msg = GStrings("TXT_ANUBIS_OFF"); + msg = GStrings.GetString("TXT_ANUBIS_OFF"); break; case CHT_CHASECAM: player->cheats ^= CF_CHASECAM; if (player->cheats & CF_CHASECAM) - msg = GStrings("TXT_CHASECAM_ON"); + msg = GStrings.GetString("TXT_CHASECAM_ON"); else - msg = GStrings("TXT_CHASECAM_OFF"); + msg = GStrings.GetString("TXT_CHASECAM_OFF"); R_ResetViewInterpolation (); break; @@ -233,7 +236,7 @@ void cht_DoCheat (player_t *player, int cheat) { player->mo->GiveInventoryType (type); } - msg = GStrings("STSTR_CHOPPERS"); + msg = GStrings.GetString("STSTR_CHOPPERS"); } // [RH] The original cheat also set powers[pw_invulnerability] to true. // Since this is a timer and not a boolean, it effectively turned off @@ -248,12 +251,12 @@ void cht_DoCheat (player_t *player, int cheat) if (item != NULL) { item->Destroy (); - msg = GStrings("TXT_CHEATPOWEROFF"); + msg = GStrings.GetString("TXT_CHEATPOWEROFF"); } else { player->mo->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2)); - msg = GStrings("TXT_CHEATPOWERON"); + msg = GStrings.GetString("TXT_CHEATPOWERON"); } } break; @@ -264,7 +267,7 @@ void cht_DoCheat (player_t *player, int cheat) cht_Give (player, "ammo"); cht_Give (player, "keys"); cht_Give (player, "armor"); - msg = GStrings("STSTR_KFAADDED"); + msg = GStrings.GetString("STSTR_KFAADDED"); break; case CHT_IDFA: @@ -272,7 +275,7 @@ void cht_DoCheat (player_t *player, int cheat) cht_Give (player, "weapons"); cht_Give (player, "ammo"); cht_Give (player, "armor"); - msg = GStrings("STSTR_FAADDED"); + msg = GStrings.GetString("STSTR_FAADDED"); break; case CHT_BEHOLDV: @@ -317,7 +320,7 @@ void cht_DoCheat (player_t *player, int cheat) item->Destroy (); } } - msg = GStrings("STSTR_BEHOLDX"); + msg = GStrings.GetString("STSTR_BEHOLDX"); break; case CHT_MASSACRE: @@ -327,12 +330,12 @@ void cht_DoCheat (player_t *player, int cheat) // killough 3/22/98: make more intelligent about plural if (killcount == 1) { - msg = GStrings(cheat == CHT_MASSACRE? "TXT_MONSTER_KILLED" : "TXT_BADDIE_KILLED"); + msg = GStrings.GetString(cheat == CHT_MASSACRE? "TXT_MONSTER_KILLED" : "TXT_BADDIE_KILLED"); } else { // Note: Do not use the language string directly as a format template! - smsg = GStrings(cheat == CHT_MASSACRE? "TXT_MONSTERS_KILLED" : "TXT_BADDIES_KILLED"); + smsg = GStrings.GetString(cheat == CHT_MASSACRE? "TXT_MONSTERS_KILLED" : "TXT_BADDIES_KILLED"); FStringf countstr("%d", killcount); smsg.Substitute("%d", countstr); msg = smsg.GetChars(); @@ -344,13 +347,13 @@ void cht_DoCheat (player_t *player, int cheat) if (player->mo != NULL && player->playerstate == PST_LIVE) { player->health = player->mo->health = player->mo->GetDefault()->health; - msg = GStrings("TXT_CHEATHEALTH"); + msg = GStrings.GetString("TXT_CHEATHEALTH"); } break; case CHT_KEYS: cht_Give (player, "keys"); - msg = GStrings("TXT_CHEATKEYS"); + msg = GStrings.GetString("TXT_CHEATKEYS"); break; // [GRB] @@ -359,7 +362,7 @@ void cht_DoCheat (player_t *player, int cheat) { if (player->mo->IsKindOf("PlayerChunk")) { - Printf("%s\n", GStrings("TXT_NO_RESURRECT")); + Printf("%s\n", GStrings.GetString("TXT_NO_RESURRECT")); return; } else @@ -371,52 +374,52 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_GIMMIEA: cht_Give (player, "ArtiInvulnerability"); - msg = GStrings("TAG_ARTIINVULNERABILITY"); + msg = GStrings.GetString("TAG_ARTIINVULNERABILITY"); break; case CHT_GIMMIEB: cht_Give (player, "ArtiInvisibility"); - msg = GStrings("TAG_ARTIINVISIBILITY"); + msg = GStrings.GetString("TAG_ARTIINVISIBILITY"); break; case CHT_GIMMIEC: cht_Give (player, "ArtiHealth"); - msg = GStrings("TAG_ARTIHEALTH"); + msg = GStrings.GetString("TAG_ARTIHEALTH"); break; case CHT_GIMMIED: cht_Give (player, "ArtiSuperHealth"); - msg = GStrings("TAG_ARTISUPERHEALTH"); + msg = GStrings.GetString("TAG_ARTISUPERHEALTH"); break; case CHT_GIMMIEE: cht_Give (player, "ArtiTomeOfPower"); - msg = GStrings("TAG_ARTITOMEOFPOWER"); + msg = GStrings.GetString("TAG_ARTITOMEOFPOWER"); break; case CHT_GIMMIEF: cht_Give (player, "ArtiTorch"); - msg = GStrings("TAG_ARTITORCH"); + msg = GStrings.GetString("TAG_ARTITORCH"); break; case CHT_GIMMIEG: cht_Give (player, "ArtiTimeBomb"); - msg = GStrings("TAG_ARTIFIREBOMB"); + msg = GStrings.GetString("TAG_ARTIFIREBOMB"); break; case CHT_GIMMIEH: cht_Give (player, "ArtiEgg"); - msg = GStrings("TAG_ARTIEGG"); + msg = GStrings.GetString("TAG_ARTIEGG"); break; case CHT_GIMMIEI: cht_Give (player, "ArtiFly"); - msg = GStrings("TAG_ARTIFLY"); + msg = GStrings.GetString("TAG_ARTIFLY"); break; case CHT_GIMMIEJ: cht_Give (player, "ArtiTeleport"); - msg = GStrings("TAG_ARTITELEPORT"); + msg = GStrings.GetString("TAG_ARTITELEPORT"); break; case CHT_GIMMIEZ: @@ -424,17 +427,17 @@ void cht_DoCheat (player_t *player, int cheat) { cht_Give (player, "artifacts"); } - msg = GStrings("TAG_ALL_ARTIFACTS"); + msg = GStrings.GetString("TAG_ALL_ARTIFACTS"); break; case CHT_TAKEWEAPS: cht_Takeweaps(player); - msg = GStrings("TXT_CHEATIDKFA"); + msg = GStrings.GetString("TXT_CHEATIDKFA"); break; case CHT_NOWUDIE: cht_Suicide (player); - msg = GStrings("TXT_CHEATIDDQD"); + msg = GStrings.GetString("TXT_CHEATIDDQD"); break; case CHT_ALLARTI: @@ -442,18 +445,18 @@ void cht_DoCheat (player_t *player, int cheat) { cht_Give (player, "artifacts"); } - msg = GStrings("TXT_CHEATARTIFACTS3"); + msg = GStrings.GetString("TXT_CHEATARTIFACTS3"); break; case CHT_PUZZLE: cht_Give (player, "puzzlepieces"); - msg = GStrings("TXT_CHEATARTIFACTS3"); + msg = GStrings.GetString("TXT_CHEATARTIFACTS3"); break; case CHT_MDK: if (player->mo == nullptr) { - Printf ("%s\n", GStrings("TXT_WHAT_KILL")); + Printf ("%s\n", GStrings.GetString("TXT_WHAT_KILL")); return; } else if (!deathmatch) @@ -468,7 +471,7 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_DONNYTRUMP: cht_Give (player, "HealthTraining"); - msg = GStrings("TXT_MIDASTOUCH"); + msg = GStrings.GetString("TXT_MIDASTOUCH"); break; case CHT_LEGO: @@ -504,34 +507,34 @@ void cht_DoCheat (player_t *player, int cheat) cht_Give (player, "MedPatch"); cht_Give (player, "MedicalKit"); cht_Give (player, "SurgeryKit"); - msg = GStrings("TXT_GOTSTUFF"); + msg = GStrings.GetString("TXT_GOTSTUFF"); break; case CHT_PUMPUPP: cht_Give (player, "AmmoSatchel"); - msg = GStrings("TXT_GOTSTUFF"); + msg = GStrings.GetString("TXT_GOTSTUFF"); break; case CHT_PUMPUPS: cht_Give (player, "UpgradeStamina", 10); cht_Give (player, "UpgradeAccuracy"); - msg = GStrings("TXT_GOTSTUFF"); + msg = GStrings.GetString("TXT_GOTSTUFF"); break; case CHT_CLEARFROZENPROPS: player->cheats &= ~(CF_FROZEN|CF_TOTALLYFROZEN); - msg = GStrings("TXT_NOT_FROZEN"); + msg = GStrings.GetString("TXT_NOT_FROZEN"); break; case CHT_FREEZE: globalchangefreeze ^= 1; if (globalfreeze ^ globalchangefreeze) { - msg = GStrings("TXT_FREEZEON"); + msg = GStrings.GetString("TXT_FREEZEON"); } else { - msg = GStrings("TXT_FREEZEOFF"); + msg = GStrings.GetString("TXT_FREEZEOFF"); } break; } @@ -543,7 +546,7 @@ void cht_DoCheat (player_t *player, int cheat) Printf ("%s\n", msg); else if (cheat != CHT_CHASECAM) { - FString message = GStrings("TXT_X_CHEATS"); + FString message = GStrings.GetString("TXT_X_CHEATS"); message.Substitute("%s", player->userinfo.GetName()); Printf("%s: %s\n", message.GetChars(), msg); } @@ -623,10 +626,13 @@ class DSuicider : public DThinker double plyrdmgfact = Pawn->DamageFactor; Pawn->DamageFactor = 1.; P_DamageMobj (Pawn, Pawn, Pawn, TELEFRAG_DAMAGE, NAME_Suicide); - Pawn->DamageFactor = plyrdmgfact; - if (Pawn->health <= 0) + if (Pawn != nullptr) { - Pawn->flags &= ~MF_SHOOTABLE; + Pawn->DamageFactor = plyrdmgfact; + if (Pawn->health <= 0) + { + Pawn->flags &= ~MF_SHOOTABLE; + } } Destroy(); } @@ -673,6 +679,6 @@ CCMD (mdk) return; const char *name = argv.argc() > 1 ? argv[1] : ""; - Net_WriteByte (DEM_MDK); + Net_WriteInt8 (DEM_MDK); Net_WriteString(name); } diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 0f3fe90724e..1b451486bfa 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -45,7 +45,7 @@ #include "m_swap.h" #include "m_argv.h" -#include "w_wad.h" +#include "filesystem.h" #include "c_cvars.h" #include "c_dispatch.h" @@ -74,7 +74,7 @@ CVAR(String, screenshot_type, "png", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); CVAR(String, screenshot_dir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); EXTERN_CVAR(Bool, longsavemessages); -static long ParseCommandLine (const char *args, int *argc, char **argv); +static size_t ParseCommandLine (const char *args, int *argc, char **argv); //--------------------------------------------------------------------------- @@ -98,10 +98,9 @@ void M_FindResponseFile (void) else { char **argv; - TArray file; + FileSys::FileData file; int argc = 0; - int size; - long argsize = 0; + size_t argsize = 0; int index; // Any more response files after the limit will be removed from the @@ -117,10 +116,8 @@ void M_FindResponseFile (void) else { Printf ("Found response file %s!\n", Args->GetArg(i) + 1); - size = (int)fr.GetLength(); - file = fr.Read (size); - file[size] = 0; - argsize = ParseCommandLine ((char*)file.Data(), &argc, NULL); + file = fr.ReadPadded(1); + argsize = ParseCommandLine (file.string(), &argc, nullptr); } } else @@ -132,7 +129,7 @@ void M_FindResponseFile (void) { argv = (char **)M_Malloc (argc*sizeof(char *) + argsize); argv[0] = (char *)argv + argc*sizeof(char *); - ParseCommandLine ((char*)file.Data(), NULL, argv); + ParseCommandLine (file.string(), nullptr, argv); // Create a new argument vector FArgs *newargs = new FArgs; @@ -179,17 +176,19 @@ void M_FindResponseFile (void) // This is just like the version in c_dispatch.cpp, except it does not // do cvar expansion. -static long ParseCommandLine (const char *args, int *argc, char **argv) +static size_t ParseCommandLine (const char *args, int *argc, char **argv) { int count; + char* buffstart; char *buffplace; count = 0; - buffplace = NULL; + buffstart = NULL; if (argv != NULL) { - buffplace = argv[0]; + buffstart = argv[0]; } + buffplace = buffstart; for (;;) { @@ -257,7 +256,7 @@ static long ParseCommandLine (const char *args, int *argc, char **argv) { *argc = count; } - return (long)(buffplace - (char *)0); + return (buffplace - buffstart); } @@ -279,7 +278,7 @@ bool M_SaveDefaults (const char *filename) GameConfig->ArchiveGlobalData (); if (gameinfo.ConfigName.IsNotEmpty()) { - GameConfig->ArchiveGameData (gameinfo.ConfigName); + GameConfig->ArchiveGameData (gameinfo.ConfigName.GetChars()); } success = GameConfig->WriteConfigFile (); if (filename != nullptr) @@ -292,7 +291,7 @@ bool M_SaveDefaults (const char *filename) void M_SaveDefaultsFinal () { if (GameConfig == nullptr) return; - while (!M_SaveDefaults (nullptr) && I_WriteIniFailed ()) + while (!M_SaveDefaults (nullptr) && I_WriteIniFailed (GameConfig->GetPathName())) { /* Loop until the config saves or I_WriteIniFailed() returns false */ } @@ -313,6 +312,12 @@ UNSAFE_CCMD (writeini) } } +CCMD(openconfig) +{ + M_SaveDefaults(nullptr); + I_OpenShellFolder(ExtractFilePath(GameConfig->GetPathName()).GetChars()); +} + // // M_LoadDefaults // @@ -514,7 +519,7 @@ void WritePNGfile (FileWriter *file, const uint8_t *buffer, const PalEntry *pale !M_AppendPNGText (file, "Software", software) || !M_FinishPNG (file)) { - Printf ("%s\n", GStrings("TXT_SCREENSHOTERR")); + Printf ("%s\n", GStrings.GetString("TXT_SCREENSHOTERR")); } } @@ -529,7 +534,7 @@ static bool FindFreeName (FString &fullname, const char *extension) for (i = 0; i <= 9999; i++) { - const char *gamename = gameinfo.ConfigName; + const char *gamename = gameinfo.ConfigName.GetChars(); time_t now; tm *tm; @@ -593,8 +598,8 @@ void M_ScreenShot (const char *filename) autoname += '/'; } } - autoname = NicePath(autoname); - CreatePath(autoname); + autoname = NicePath(autoname.GetChars()); + CreatePath(autoname.GetChars()); if (!FindFreeName (autoname, writepcx ? "pcx" : "png")) { Printf ("M_ScreenShot: Delete some screenshots\n"); @@ -615,7 +620,7 @@ void M_ScreenShot (const char *filename) auto buffer = screen->GetScreenshotBuffer(pitch, color_type, gamma); if (buffer.Size() > 0) { - file = FileWriter::Open(autoname); + file = FileWriter::Open(autoname.GetChars()); if (file == NULL) { Printf ("Could not open %s\n", autoname.GetChars()); @@ -635,7 +640,7 @@ void M_ScreenShot (const char *filename) if (!screenshot_quiet) { - int slash = -1; + ptrdiff_t slash = -1; if (!longsavemessages) slash = autoname.LastIndexOfAny(":/\\"); Printf ("Captured %s\n", autoname.GetChars()+slash+1); } @@ -657,3 +662,32 @@ UNSAFE_CCMD (screenshot) G_ScreenShot (argv[1]); } +CCMD(openscreenshots) +{ + size_t dirlen; + FString autoname; + autoname = Args->CheckValue("-shotdir"); + if (autoname.IsEmpty()) + { + autoname = screenshot_dir; + } + dirlen = autoname.Len(); + if (dirlen == 0) + { + autoname = M_GetScreenshotsPath(); + dirlen = autoname.Len(); + } + if (dirlen > 0) + { + if (autoname[dirlen-1] != '/' && autoname[dirlen-1] != '\\') + { + autoname += '/'; + } + } + autoname = NicePath(autoname.GetChars()); + + CreatePath(autoname.GetChars()); + + I_OpenShellFolder(autoname.GetChars()); +} + diff --git a/src/m_misc.h b/src/m_misc.h index 8a0b9ef7b2d..4de7eb5ad96 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -24,7 +24,7 @@ #ifndef __M_MISC__ #define __M_MISC__ -#include "basictypes.h" +#include "basics.h" #include "zstring.h" class FConfigFile; @@ -44,23 +44,6 @@ void M_LoadDefaults (); bool M_SaveDefaults (const char *filename); void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen); -// Get special directory paths (defined in m_specialpaths.cpp) - -#ifdef __unix__ -FString GetUserFile (const char *path); // Prepends ~/.zdoom to path -#endif -FString M_GetAppDataPath(bool create); -FString M_GetCachePath(bool create); -FString M_GetAutoexecPath(); -FString M_GetCajunPath(const char *filename); -FString M_GetConfigPath(bool for_reading); -FString M_GetScreenshotsPath(); -FString M_GetSavegamesPath(); -FString M_GetDocumentsPath(); - -#ifdef __APPLE__ -FString M_GetMacAppSupportPath(const bool create = true); -void M_GetMacSearchDirectories(FString& user_docs, FString& user_app_support, FString& local_app_support); -#endif // __APPLE__ +#include "i_specialpaths.h" #endif diff --git a/src/maploader/compatibility.cpp b/src/maploader/compatibility.cpp index cabb2ade17e..1ba18d444ef 100644 --- a/src/maploader/compatibility.cpp +++ b/src/maploader/compatibility.cpp @@ -47,7 +47,7 @@ #include "g_level.h" #include "p_lnspec.h" #include "p_tags.h" -#include "w_wad.h" +#include "filesystem.h" #include "textures.h" #include "g_levellocals.h" #include "actor.h" @@ -119,13 +119,16 @@ static FCompatOption Options[] = { { "setslopeoverflow", BCOMPATF_SETSLOPEOVERFLOW, SLOT_BCOMPAT }, { "resetplayerspeed", BCOMPATF_RESETPLAYERSPEED, SLOT_BCOMPAT }, - { "vileghosts", BCOMPATF_VILEGHOSTS, SLOT_BCOMPAT }, + { "vileghosts", COMPATF_VILEGHOSTS, SLOT_COMPAT }, { "ignoreteleporttags", BCOMPATF_BADTELEPORTERS, SLOT_BCOMPAT }, { "rebuildnodes", BCOMPATF_REBUILDNODES, SLOT_BCOMPAT }, { "linkfrozenprops", BCOMPATF_LINKFROZENPROPS, SLOT_BCOMPAT }, { "floatbob", BCOMPATF_FLOATBOB, SLOT_BCOMPAT }, { "noslopeid", BCOMPATF_NOSLOPEID, SLOT_BCOMPAT }, { "clipmidtex", BCOMPATF_CLIPMIDTEX, SLOT_BCOMPAT }, + { "nosectionmerge", BCOMPATF_NOSECTIONMERGE, SLOT_BCOMPAT }, + { "nomirrors", BCOMPATF_NOMIRRORS, SLOT_BCOMPAT }, + // list copied from g_mapinfo.cpp { "shorttex", COMPATF_SHORTTEX, SLOT_COMPAT }, @@ -150,7 +153,6 @@ static FCompatOption Options[] = { "anybossdeath", COMPATF_ANYBOSSDEATH, SLOT_COMPAT },// [GZ] Added for UAC_DEAD { "mushroom", COMPATF_MUSHROOM, SLOT_COMPAT }, { "mbfmonstermove", COMPATF_MBFMONSTERMOVE, SLOT_COMPAT }, - { "corpsegibs", COMPATF_CORPSEGIBS, SLOT_COMPAT }, { "noblockfriends", COMPATF_NOBLOCKFRIENDS, SLOT_COMPAT }, { "spritesort", COMPATF_SPRITESORT, SLOT_COMPAT }, { "hitscan", COMPATF_HITSCAN, SLOT_COMPAT }, @@ -169,6 +171,10 @@ static FCompatOption Options[] = { "explode2", COMPATF2_EXPLODE2, SLOT_COMPAT2 }, { "railing", COMPATF2_RAILING, SLOT_COMPAT2 }, { "scriptwait", COMPATF2_SCRIPTWAIT, SLOT_COMPAT2 }, + { "nombf21", COMPATF2_NOMBF21, SLOT_COMPAT2 }, + { "voodoozombies", COMPATF2_VOODOO_ZOMBIES, SLOT_COMPAT2 }, + { "fdteleport", COMPATF2_FDTELEPORT, SLOT_COMPAT2 }, + { "noacsargcheck", COMPATF2_NOACSARGCHECK, SLOT_COMPAT2 }, { NULL, 0, 0 } }; @@ -207,7 +213,7 @@ void ParseCompatibility() // The contents of this file are not cumulative, as it should not // be present in user-distributed maps. - FScanner sc(Wads.GetNumForFullName("compatibility.txt")); + FScanner sc(fileSystem.GetNumForFullName("compatibility.txt")); while (sc.GetString()) // Get MD5 signature { @@ -288,13 +294,20 @@ FName MapLoader::CheckCompatibility(MapData *map) Level->ii_compatflags2 = 0; Level->ib_compatflags = 0; - // When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT. + // When playing Doom IWAD levels force BCOMPATF_NOSECTIONMERGE, COMPAT_SHORTTEX and COMPATF_LIGHT. // I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt. // TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD. - if (Wads.GetLumpFile(map->lumpnum) == Wads.GetIwadNum() && (gameinfo.flags & GI_COMPATSHORTTEX) && Level->maptype == MAPTYPE_DOOM) + if (fileSystem.GetFileContainer(map->lumpnum) == fileSystem.GetIwadNum()) { - Level->ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT; - if (gameinfo.flags & GI_COMPATSTAIRS) Level->ii_compatflags |= COMPATF_STAIRINDEX; + if ((gameinfo.flags & GI_COMPATSHORTTEX) && Level->maptype == MAPTYPE_DOOM) + { + Level->ii_compatflags = COMPATF_SHORTTEX | COMPATF_LIGHT; + if (gameinfo.flags & GI_COMPATSTAIRS) Level->ii_compatflags |= COMPATF_STAIRINDEX; + } + if (gameinfo.flags & GI_NOSECTIONMERGE) + { + //Level->ib_compatflags |= BCOMPATF_NOSECTIONMERGE; + } } map->GetChecksum(md5.Bytes); diff --git a/src/maploader/edata.cpp b/src/maploader/edata.cpp index 77ae9fa31cf..044fb081159 100644 --- a/src/maploader/edata.cpp +++ b/src/maploader/edata.cpp @@ -34,7 +34,7 @@ ** */ -#include "w_wad.h" +#include "filesystem.h" #include "m_argv.h" #include "sc_man.h" #include "g_level.h" @@ -296,7 +296,7 @@ static void parseSector(FScanner &sc, TMap &EDSectors) { sc.CheckString("="); sc.MustGetFloat(); - sec.angle[sector_t::floor] = sc.Float; + sec.angle[sector_t::floor] = DAngle::fromDeg(sc.Float); } else if (sc.Compare("flooroffsetx")) { @@ -320,7 +320,7 @@ static void parseSector(FScanner &sc, TMap &EDSectors) { sc.CheckString("="); sc.MustGetFloat(); - sec.angle[sector_t::ceiling] = sc.Float; + sec.angle[sector_t::ceiling] = DAngle::fromDeg(sc.Float); } else if (sc.Compare("ceilingoffsetx")) { @@ -520,7 +520,7 @@ void MapLoader::InitED() FScanner sc; if (filename.IsEmpty()) return; - int lump = Wads.CheckNumForFullName(filename, true, ns_global); + int lump = fileSystem.CheckNumForFullName(filename.GetChars(), true, FileSys::ns_global); if (lump == -1) return; sc.OpenLumpNum(lump); @@ -659,7 +659,7 @@ void MapLoader::LoadMapinfoACSLump() { if (Level->info->acsName.IsNotEmpty()) { - int lump = Wads.CheckNumForName(Level->info->acsName); + int lump = fileSystem.CheckNumForName(Level->info->acsName.GetChars()); if (lump >= 0) Level->Behaviors.LoadModule(lump); } } diff --git a/src/maploader/glnodes.cpp b/src/maploader/glnodes.cpp index 39a040b6268..33051b6c121 100644 --- a/src/maploader/glnodes.cpp +++ b/src/maploader/glnodes.cpp @@ -34,24 +34,18 @@ #ifndef _WIN32 #include - -#else -#include - -#define rmdir _rmdir - #endif -#include -#include "templates.h" +#include + #include "m_argv.h" #include "c_dispatch.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "p_local.h" #include "nodebuild.h" #include "doomstat.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "p_setup.h" #include "version.h" #include "md5.h" @@ -60,6 +54,7 @@ #include "g_levellocals.h" #include "i_time.h" #include "maploader.h" +#include "fs_findfile.h" EXTERN_CVAR(Bool, gl_cachenodes) EXTERN_CVAR(Float, gl_cachetime) @@ -208,7 +203,7 @@ bool MapLoader::LoadGLVertexes(FileReader &lump) auto gllen=lump.GetLength(); if (gllen < 4) return false; - auto gldata = glbuf.Data(); + auto gldata = glbuf.bytes(); if (*(int *)gldata == gNd5) { @@ -287,13 +282,13 @@ bool MapLoader::LoadGLSegs(FileReader &lump) const unsigned numverts = Level->vertexes.Size(); const unsigned numlines = Level->lines.Size(); - if (!format5 && memcmp(data.Data(), "gNd3", 4)) + if (!format5 && memcmp(data.data(), "gNd3", 4)) { numsegs/=sizeof(glseg_t); segs.Alloc(numsegs); memset(&segs[0],0,sizeof(seg_t)*numsegs); - glseg_t * ml = (glseg_t*)data.Data(); + auto ml = (const glseg_t*)data.data(); for(i = 0; i < numsegs; i++) { // check for gl-vertices @@ -323,21 +318,21 @@ bool MapLoader::LoadGLSegs(FileReader &lump) ldef = &Level->lines[lineidx]; segs[i].linedef = ldef; - ml->side=LittleShort(ml->side); - if (ml->side > 1) + auto side=LittleShort(ml->side); + if (side > 1) return false; - segs[i].sidedef = ldef->sidedef[ml->side]; - if (ldef->sidedef[ml->side] != nullptr) + segs[i].sidedef = ldef->sidedef[side]; + if (ldef->sidedef[side] != nullptr) { - segs[i].frontsector = ldef->sidedef[ml->side]->sector; + segs[i].frontsector = ldef->sidedef[side]->sector; } else { segs[i].frontsector = nullptr; } - if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != nullptr) + if (ldef->flags & ML_TWOSIDED && ldef->sidedef[side^1] != nullptr) { - segs[i].backsector = ldef->sidedef[ml->side^1]->sector; + segs[i].backsector = ldef->sidedef[side^1]->sector; } else { @@ -364,7 +359,7 @@ bool MapLoader::LoadGLSegs(FileReader &lump) segs.Alloc(numsegs); memset(&segs[0],0,sizeof(seg_t)*numsegs); - glseg3_t * ml = (glseg3_t*)(data.Data() + (format5? 0:4)); + const glseg3_t * ml = (const glseg3_t*)(data.bytes() + (format5? 0:4)); for(i = 0; i < numsegs; i++) { // check for gl-vertices const unsigned v1idx = checkGLVertex3(LittleLong(ml->v1)); @@ -394,21 +389,21 @@ bool MapLoader::LoadGLSegs(FileReader &lump) segs[i].linedef = ldef; - ml->side=LittleShort(ml->side); - if (ml->side > 1) + auto side=LittleShort(ml->side); + if (side > 1) return false; - segs[i].sidedef = ldef->sidedef[ml->side]; - if (ldef->sidedef[ml->side] != nullptr) + segs[i].sidedef = ldef->sidedef[side]; + if (ldef->sidedef[side] != nullptr) { - segs[i].frontsector = ldef->sidedef[ml->side]->sector; + segs[i].frontsector = ldef->sidedef[side]->sector; } else { segs[i].frontsector = nullptr; } - if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != nullptr) + if (ldef->flags & ML_TWOSIDED && ldef->sidedef[side^1] != nullptr) { - segs[i].backsector = ldef->sidedef[ml->side^1]->sector; + segs[i].backsector = ldef->sidedef[side^1]->sector; } else { @@ -453,9 +448,9 @@ bool MapLoader::LoadGLSubsectors(FileReader &lump) return false; } - if (!format5 && memcmp(datab.Data(), "gNd3", 4)) + if (!format5 && memcmp(datab.data(), "gNd3", 4)) { - mapsubsector_t * data = (mapsubsector_t*) datab.Data(); + auto data = (const mapsubsector_t*) datab.data(); numsubsectors /= sizeof(mapsubsector_t); Level->subsectors.Alloc(numsubsectors); auto &subsectors = Level->subsectors; @@ -477,7 +472,7 @@ bool MapLoader::LoadGLSubsectors(FileReader &lump) } else { - gl3_mapsubsector_t * data = (gl3_mapsubsector_t*) (datab.Data()+(format5? 0:4)); + auto data = (const gl3_mapsubsector_t*) (datab.bytes()+(format5? 0:4)); numsubsectors /= sizeof(gl3_mapsubsector_t); Level->subsectors.Alloc(numsubsectors); auto &subsectors = Level->subsectors; @@ -544,7 +539,7 @@ bool MapLoader::LoadNodes (FileReader &lump) lump.Seek(0, FileReader::SeekSet); auto buf = lump.Read(); - basemn = mn = (mapnode_t*)buf.Data(); + basemn = mn = (mapnode_t*)buf.data(); used.Resize(numnodes); memset (used.Data(), 0, sizeof(uint16_t)*numnodes); @@ -600,7 +595,7 @@ bool MapLoader::LoadNodes (FileReader &lump) lump.Seek(0, FileReader::SeekSet); auto buf = lump.Read(); - basemn = mn = (gl5_mapnode_t*)buf.Data(); + basemn = mn = (gl5_mapnode_t*)buf.data(); used.Resize(numnodes); memset(used.Data(), 0, sizeof(uint16_t)*numnodes); @@ -708,7 +703,7 @@ static bool MatchHeader(const char * label, const char * hdata) if (memcmp(hdata, "LEVEL=", 6) == 0) { size_t labellen = strlen(label); - labellen = MIN(size_t(8), labellen); + labellen = min(size_t(8), labellen); if (strnicmp(hdata+6, label, labellen)==0 && (hdata[6+labellen]==0xa || hdata[6+labellen]==0xd)) @@ -729,31 +724,31 @@ static bool MatchHeader(const char * label, const char * hdata) static int FindGLNodesInWAD(int labellump) { - int wadfile = Wads.GetLumpFile(labellump); + int wadfile = fileSystem.GetFileContainer(labellump); FString glheader; - glheader.Format("GL_%s", Wads.GetLumpFullName(labellump)); + glheader.Format("GL_%s", fileSystem.GetFileFullName(labellump)); if (glheader.Len()<=8) { - int gllabel = Wads.CheckNumForName(glheader, ns_global, wadfile); + int gllabel = fileSystem.CheckNumForName(glheader.GetChars(), FileSys::ns_global, wadfile); if (gllabel >= 0) return gllabel; } else { // Before scanning the entire WAD directory let's check first whether // it is necessary. - int gllabel = Wads.CheckNumForName("GL_LEVEL", ns_global, wadfile); + int gllabel = fileSystem.CheckNumForName("GL_LEVEL", FileSys::ns_global, wadfile); if (gllabel >= 0) { int lastlump=0; int lump; - while ((lump=Wads.FindLump("GL_LEVEL", &lastlump))>=0) + while ((lump=fileSystem.FindLump("GL_LEVEL", &lastlump))>=0) { - if (Wads.GetLumpFile(lump)==wadfile) + if (fileSystem.GetFileContainer(lump)==wadfile) { - FMemLump mem = Wads.ReadLump(lump); - if (MatchHeader(Wads.GetLumpFullName(labellump), (const char *)mem.GetMem())) return lump; + auto mem = fileSystem.ReadFile(lump); + if (MatchHeader(fileSystem.GetFileFullName(labellump), GetStringFromLump(lump).GetChars())) return lump; } } } @@ -779,7 +774,7 @@ static int FindGLNodesInFile(FResourceFile * f, const char * label) FString glheader; bool mustcheck=false; - uint32_t numentries = f->LumpCount(); + uint32_t numentries = f->EntryCount(); glheader.Format("GL_%.8s", label); if (glheader.Len()>8) @@ -792,13 +787,13 @@ static int FindGLNodesInFile(FResourceFile * f, const char * label) { for(uint32_t i=0;iGetLump(i)->Name, glheader, 8)) + if (!strnicmp(f->getName(i), glheader.GetChars(), 8)) { if (mustcheck) { char check[16]={0}; - auto fr = f->GetLump(i)->GetReader(); - fr->Read(check, 16); + auto fr = f->GetEntryReader(i, FileSys::READER_SHARED); + fr.Read(check, 16); if (MatchHeader(label, check)) return i; } else return i; @@ -854,11 +849,11 @@ bool MapLoader::LoadGLNodes(MapData * map) FileReader gwalumps[4]; char path[256]; int li; - int lumpfile = Wads.GetLumpFile(map->lumpnum); + int lumpfile = fileSystem.GetFileContainer(map->lumpnum); bool mapinwad = map->InWad; FResourceFile * f_gwa = map->resource; - const char * name = Wads.GetWadFullName(lumpfile); + const char * name = fileSystem.GetResourceFileFullName(lumpfile); if (mapinwad) { @@ -869,7 +864,7 @@ bool MapLoader::LoadGLNodes(MapData * map) // GL nodes are loaded with a WAD for(int i=0;i<4;i++) { - gwalumps[i]=Wads.ReopenLumpReader(li+i+1); + gwalumps[i]=fileSystem.ReopenFileReader(li+i+1); } return DoLoadGLNodes(gwalumps); } @@ -883,10 +878,10 @@ bool MapLoader::LoadGLNodes(MapData * map) strcpy(ext, ".gwa"); // Todo: Compare file dates - f_gwa = FResourceFile::OpenResourceFile(path, true); + f_gwa = FResourceFile::OpenResourceFile(path); if (f_gwa==nullptr) return false; - strncpy(map->MapLumps[0].Name, Wads.GetLumpFullName(map->lumpnum), 8); + strncpy(map->MapLumps[0].Name, fileSystem.GetFileFullName(map->lumpnum), 8); } } } @@ -899,13 +894,14 @@ bool MapLoader::LoadGLNodes(MapData * map) result=true; for(unsigned i=0; i<4;i++) { - if (strnicmp(f_gwa->GetLump(li+i+1)->Name, check[i], 8)) + if (strnicmp(f_gwa->getName(li + i + 1), check[i], 8)) { result=false; break; } else - gwalumps[i] = f_gwa->GetLump(li+i+1)->NewReader(); + // This is a special case. The container for the map WAD is not set up to create new file handles for itself so this needs to cache the content here. + gwalumps[i] = f_gwa->GetEntryReader(li + i + 1, FileSys::READER_CACHED, FileSys::READERFLAG_SEEKABLE); } if (result) result = DoLoadGLNodes(gwalumps); } @@ -1000,14 +996,14 @@ typedef TArray MemFile; static FString CreateCacheName(MapData *map, bool create) { FString path = M_GetCachePath(create); - FString lumpname = Wads.GetLumpFullPath(map->lumpnum); - int separator = lumpname.IndexOf(':'); + FString lumpname = fileSystem.GetFileFullPath(map->lumpnum).c_str(); + auto separator = lumpname.IndexOf(':'); path << '/' << lumpname.Left(separator); - if (create) CreatePath(path); + if (create) CreatePath(path.GetChars()); lumpname.ReplaceChars('/', '%'); lumpname.ReplaceChars(':', '$'); - path << '/' << lumpname.Right(lumpname.Len() - separator - 1) << ".gzc"; + path << '/' << lumpname.Right((ptrdiff_t)lumpname.Len() - separator - 1) << ".gzc"; return path; } @@ -1124,7 +1120,7 @@ void MapLoader::CreateCachedNodes(MapData *map) memcpy(&compressed[offset - 4], "ZGL3", 4); FString path = CreateCacheName(map, true); - FileWriter *fw = FileWriter::Open(path); + FileWriter *fw = FileWriter::Open(path.GetChars()); if (fw != nullptr) { @@ -1153,7 +1149,7 @@ bool MapLoader::CheckCachedNodes(MapData *map) FString path = CreateCacheName(map, false); FileReader fr; - if (!fr.OpenFile(path)) return false; + if (!fr.OpenFile(path.GetChars())) return false; if (fr.Read(magic, 4) != 4) return false; if (memcmp(magic, "CACH", 4)) return false; @@ -1198,11 +1194,11 @@ bool MapLoader::CheckCachedNodes(MapData *map) UNSAFE_CCMD(clearnodecache) { - TArray list; + FileSys::FileList list; FString path = M_GetCachePath(false); path += "/"; - if (!ScanDirectory(list, path)) + if (!FileSys::ScanDirectory(list, path.GetChars(), "*", false)) { Printf("Unable to scan node cache directory %s\n", path.GetChars()); return; @@ -1210,15 +1206,15 @@ UNSAFE_CCMD(clearnodecache) // Scan list backwards so that when we reach a directory // all files within are already deleted. - for(int i = list.Size()-1; i >= 0; i--) + for(int i = (int)list.size()-1; i >= 0; i--) { if (list[i].isDirectory) { - rmdir(list[i].Filename); + RemoveDir(list[i].FilePath.c_str()); } else { - remove(list[i].Filename); + RemoveFile(list[i].FilePath.c_str()); } } diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index e021ba843d5..fe050d13cc5 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -59,6 +59,7 @@ #include +#include // needed for std::floor on mac #include "maploader.h" #include "c_cvars.h" #include "actor.h" @@ -68,18 +69,22 @@ #include "v_text.h" #include "p_setup.h" #include "gi.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "types.h" -#include "w_wad.h" +#include "filesystem.h" #include "p_conversation.h" #include "v_video.h" #include "i_time.h" #include "m_argv.h" #include "fragglescript/t_fs.h" #include "swrenderer/r_swrenderer.h" -#include "hwrenderer/data/flatvertices.h" +#include "flatvertices.h" #include "xlat/xlat.h" #include "vm.h" +#include "texturemanager.h" +#include "hw_vertexbuilder.h" +#include "version.h" +#include "fs_decompress.h" enum { @@ -422,7 +427,7 @@ void MapLoader::LoadVertexes(MapData * map) if (numvertexes == 0) { - I_Error("Map has no vertices.\n"); + I_Error("Map has no vertices."); } // Allocate memory for buffer. @@ -493,6 +498,11 @@ void MapLoader::LoadGLZSegs (FileReader &data, int type) uint32_t partner = data.ReadUInt32(); uint32_t line; + if (partner != 0xffffffffu && partner >= Level->segs.Size()) + { + I_Error("partner seg index out of range for subsector %d, seg %d", i, j); + } + if (type >= 2) { line = data.ReadUInt32(); @@ -559,7 +569,7 @@ void MapLoader::LoadZNodes(FileReader &data, int glnodes) if (orgVerts > Level->vertexes.Size()) { // These nodes are based on a map with more vertex data than we have. // We can't use them. - throw CRecoverableError("Incorrect number of vertexes in nodes.\n"); + I_Error("Incorrect number of vertexes in nodes."); } auto oldvertexes = &Level->vertexes[0]; if (orgVerts + newVerts != Level->vertexes.Size()) @@ -602,7 +612,7 @@ void MapLoader::LoadZNodes(FileReader &data, int glnodes) // segs used by subsectors. if (numSegs != currSeg) { - throw CRecoverableError("Incorrect number of segs in nodes.\n"); + I_Error("Incorrect number of segs in nodes."); } Level->segs.Alloc(numSegs); @@ -729,39 +739,37 @@ bool MapLoader::LoadExtendedNodes (FileReader &dalump, uint32_t id) if (compressed) { FileReader zip; - try + if (OpenDecompressor(zip, dalump, -1, FileSys::METHOD_ZLIB, FileSys::DCF_EXCEPTIONS)) { - if (zip.OpenDecompressor(dalump, -1, METHOD_ZLIB, false, [](const char* err) { I_Error("%s", err); })) - { - LoadZNodes(zip, type); - } - else - { - Printf("Error loading nodes: Corrupt data.\n"); - return false; - } + LoadZNodes(zip, type); + return true; } - catch (const CRecoverableError& err) + else { - Printf("Error loading nodes: %s.\n", err.what()); - return false; + Printf("Error loading nodes: Corrupt data.\n"); } } else { LoadZNodes(dalump, type); + return true; } - return true; } catch (CRecoverableError &error) { Printf("Error loading nodes: %s\n", error.GetMessage()); - - Level->subsectors.Clear(); - Level->segs.Clear(); - Level->nodes.Clear(); - return false; } + catch (FileSys::FileSystemException& error) + { + Printf("Error loading nodes: %s\n", error.what()); + } + // clean up. + Printf("The BSP will be rebuilt\n"); + ForceNodeBuild = true; + Level->subsectors.Clear(); + Level->segs.Clear(); + Level->nodes.Clear(); + return false; } @@ -862,7 +870,7 @@ bool MapLoader::LoadSegs (MapData * map) if (vnum1 >= numvertexes || vnum2 >= numvertexes) { - throw badseg(0, i, MAX(vnum1, vnum2)); + throw badseg(0, i, max(vnum1, vnum2)); } li->v1 = &Level->vertexes[vnum1]; @@ -901,10 +909,10 @@ bool MapLoader::LoadSegs (MapData * map) // errors _can_ cause firelines. DAngle ptp_angle = (li->v2->fPos() - li->v1->fPos()).Angle(); - DAngle seg_angle = AngleToFloat(segangle << 16); + DAngle seg_angle = DAngle::fromBam(segangle << 16); DAngle delta_angle = absangle(ptp_angle, seg_angle); - if (delta_angle >= 1.) + if (delta_angle >= DAngle::fromDeg(1.)) { double dis = (li->v2->fPos() - li->v1->fPos()).Length(); DVector2 delta = seg_angle.ToVector(dis); @@ -1064,6 +1072,7 @@ void MapLoader::LoadSectors (MapData *map, FMissingTextureTracker &missingtex) unsigned numsectors = lumplen / sizeof(mapsector_t); Level->sectors.Alloc(numsectors); + Level->extsectors.Alloc(numsectors); auto sectors = &Level->sectors[0]; memset (sectors, 0, numsectors*sizeof(sector_t)); @@ -1076,12 +1085,9 @@ void MapLoader::LoadSectors (MapData *map, FMissingTextureTracker &missingtex) ms = (mapsector_t*)msp.Data(); ss = sectors; - // Extended properties - sectors[0].e = new extsector_t[numsectors]; - for (unsigned i = 0; i < numsectors; i++, ss++, ms++) { - ss->e = §ors[0].e[i]; + ss->e = &Level->extsectors[i]; ss->Level = Level; if (!map->HasBehavior) ss->Flags |= SECF_FLOORDROP; ss->SetPlaneTexZ(sector_t::floor, (double)LittleShort(ms->floorheight)); @@ -1158,12 +1164,11 @@ void MapLoader::LoadSectors (MapData *map, FMissingTextureTracker &missingtex) template bool MapLoader::LoadNodes (MapData * map) { - FMemLump data; + FileSys::FileData data; int j; int k; nodetype *mn; node_t* no; - uint16_t* used; int lumplen = map->Size(ML_NODES); int maxss = map->Size(ML_SSECTORS) / sizeof(subsectortype); @@ -1176,8 +1181,8 @@ bool MapLoader::LoadNodes (MapData * map) auto &nodes = Level->nodes; nodes.Alloc(numnodes); - used = (uint16_t *)alloca (sizeof(uint16_t)*numnodes); - memset (used, 0, sizeof(uint16_t)*numnodes); + TArray used(numnodes, true); + memset (used.data(), 0, sizeof(uint16_t) * numnodes); auto mnp = map->Read(ML_NODES); mn = (nodetype*)(mnp.Data() + nodetype::NF_LUMPOFFSET); @@ -1655,7 +1660,7 @@ void MapLoader::FinishLoadingLineDefs () } else { - I_Error ("%d sidedefs is not enough\n", sidecount); + I_Error ("%d sidedefs is not enough", sidecount); } } @@ -1673,6 +1678,7 @@ void MapLoader::LoadLineDefs (MapData * map) auto mldf = map->Read(ML_LINEDEFS); int numlines = mldf.Size() / sizeof(maplinedef_t); + int numsides = map->Size(ML_SIDEDEFS) / sizeof(mapsidedef_t); linemap.Resize(numlines); // [RH] Count the number of sidedef references. This is the number of @@ -1700,13 +1706,6 @@ void MapLoader::LoadLineDefs (MapData * map) } else { - // patch missing first sides instead of crashing out. - // Visual glitches are better than not being able to play. - if (LittleShort(mld->sidenum[0]) == NO_INDEX) - { - Printf("Line %d has no first side.\n", i); - mld->sidenum[0] = 0; - } sidecount++; if (LittleShort(mld->sidenum[1]) != NO_INDEX) sidecount++; @@ -1745,6 +1744,22 @@ void MapLoader::LoadLineDefs (MapData * map) ProcessEDLinedef(ld, mld->tag); } #endif + // cph 2006/09/30 - fix sidedef errors right away. + for (int j=0; j < 2; j++) + { + if (LittleShort(mld->sidenum[j]) != NO_INDEX && mld->sidenum[j] >= numsides) + { + mld->sidenum[j] = 0; // dummy sidedef + Printf("Linedef %d has a bad sidedef\n", i); + } + } + // patch missing first sides instead of crashing out. + // Visual glitches are better than not being able to play. + if (LittleShort(mld->sidenum[0]) == NO_INDEX) + { + Printf("Line %d has no first side.\n", i); + mld->sidenum[0] = 0; + } ld->v1 = &Level->vertexes[LittleShort(mld->v1)]; ld->v2 = &Level->vertexes[LittleShort(mld->v2)]; @@ -1874,7 +1889,7 @@ void MapLoader::LoadLineDefs2 (MapData * map) Level->sides.Alloc(count); memset(&Level->sides[0], 0, count * sizeof(side_t)); - sidetemp.Resize(MAX(count, Level->vertexes.Size())); + sidetemp.Resize(max(count, Level->vertexes.Size())); for (i = 0; i < count; i++) { sidetemp[i].a.special = sidetemp[i].a.tag = 0; @@ -1902,7 +1917,7 @@ void MapLoader::LoopSidedefs (bool firstloop) int i; int numsides = Level->sides.Size(); - sidetemp.Resize(MAX(Level->vertexes.Size(), numsides)); + sidetemp.Resize(max(Level->vertexes.Size(), numsides)); for (i = 0; i < (int)Level->vertexes.Size(); ++i) { @@ -1978,7 +1993,7 @@ void MapLoader::LoopSidedefs (bool firstloop) if (sidetemp[right].b.next != NO_SIDE) { int bestright = right; // Shut up, GCC - DAngle bestang = 360.; + DAngle bestang = DAngle::fromDeg(360.); line_t *leftline, *rightline; DAngle ang1, ang2, ang; @@ -1986,7 +2001,7 @@ void MapLoader::LoopSidedefs (bool firstloop) ang1 = leftline->Delta().Angle(); if (!sidetemp[i].b.lineside) { - ang1 += 180; + ang1 += DAngle::fromDeg(180); } while (right != NO_SIDE) @@ -1999,12 +2014,12 @@ void MapLoader::LoopSidedefs (bool firstloop) ang2 = rightline->Delta().Angle(); if (sidetemp[right].b.lineside) { - ang2 += 180; + ang2 += DAngle::fromDeg(180); } ang = (ang2 - ang1).Normalized360(); - if (ang != 0 && ang <= bestang) + if (ang != nullAngle && ang <= bestang) { bestright = right; bestang = ang; @@ -2032,52 +2047,6 @@ void MapLoader::LoopSidedefs (bool firstloop) // //=========================================================================== -int MapLoader::DetermineTranslucency (int lumpnum) -{ - auto tranmap = Wads.OpenLumpReader (lumpnum); - uint8_t index; - PalEntry newcolor; - PalEntry newcolor2; - - tranmap.Seek (GPalette.BlackIndex * 256 + GPalette.WhiteIndex, FileReader::SeekSet); - tranmap.Read (&index, 1); - - newcolor = GPalette.BaseColors[GPalette.Remap[index]]; - - tranmap.Seek (GPalette.WhiteIndex * 256 + GPalette.BlackIndex, FileReader::SeekSet); - tranmap.Read (&index, 1); - newcolor2 = GPalette.BaseColors[GPalette.Remap[index]]; - if (newcolor2.r == 255) // if black on white results in white it's either - // fully transparent or additive - { - if (developer >= DMSG_NOTIFY) - { - char lumpname[9]; - lumpname[8] = 0; - Wads.GetLumpName (lumpname, lumpnum); - Printf ("%s appears to be additive translucency %d (%d%%)\n", lumpname, newcolor.r, - newcolor.r*100/255); - } - return -newcolor.r; - } - - if (developer >= DMSG_NOTIFY) - { - char lumpname[9]; - lumpname[8] = 0; - Wads.GetLumpName (lumpname, lumpnum); - Printf ("%s appears to be translucency %d (%d%%)\n", lumpname, newcolor.r, - newcolor.r*100/255); - } - return newcolor.r; -} - -//=========================================================================== -// -// -// -//=========================================================================== - void MapLoader::ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, intmapsidedef_t *msd, int special, int tag, short *alpha, FMissingTextureTracker &missingtex) { switch (special) @@ -2089,9 +2058,9 @@ void MapLoader::ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec // instead of figuring something out from the colormap. if (sec != nullptr) { - SetTexture (sd, side_t::bottom, &sec->bottommap, msd->bottomtexture); - SetTexture (sd, side_t::mid, &sec->midmap, msd->midtexture); - SetTexture (sd, side_t::top, &sec->topmap, msd->toptexture); + SetTexture (sd, side_t::bottom, &sec->bottommap, msd->bottomtexture.GetChars()); + SetTexture (sd, side_t::mid, &sec->midmap, msd->midtexture.GetChars()); + SetTexture (sd, side_t::top, &sec->topmap, msd->toptexture.GetChars()); } break; @@ -2103,9 +2072,9 @@ void MapLoader::ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec uint32_t color = MAKERGB(255,255,255), fog = 0; bool colorgood, foggood; - SetTextureNoErr (sd, side_t::bottom, &fog, msd->bottomtexture, &foggood, true); - SetTextureNoErr (sd, side_t::top, &color, msd->toptexture, &colorgood, false); - SetTexture(sd, side_t::mid, msd->midtexture, missingtex); + SetTextureNoErr (sd, side_t::bottom, &fog, msd->bottomtexture.GetChars(), &foggood, true); + SetTextureNoErr (sd, side_t::top, &color, msd->toptexture.GetChars(), &colorgood, false); + SetTexture(sd, side_t::mid, msd->midtexture.GetChars(), missingtex); if (colorgood | foggood) { @@ -2145,15 +2114,24 @@ void MapLoader::ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec { int lumpnum; - if (strnicmp ("TRANMAP", msd->midtexture, 8) == 0) + if (strnicmp ("TRANMAP", msd->midtexture.GetChars(), 8) == 0) { // The translator set the alpha argument already; no reason to do it again. sd->SetTexture(side_t::mid, FNullTextureID()); } - else if ((lumpnum = Wads.CheckNumForName (msd->midtexture)) > 0 && - Wads.LumpLength (lumpnum) == 65536) + else if ((lumpnum = fileSystem.CheckNumForName (msd->midtexture.GetChars())) > 0 && + fileSystem.FileLength (lumpnum) == 65536) { - *alpha = (short)DetermineTranslucency (lumpnum); + auto fr = fileSystem.OpenFileReader(lumpnum); + *alpha = (short)GPalette.DetermineTranslucency (fr); + + if (developer >= DMSG_NOTIFY) + { + const char *lumpname = fileSystem.GetFileShortName(lumpnum); + if (*alpha < 0) Printf("%s appears to be additive translucency %d (%d%%)\n", lumpname, -*alpha, -*alpha * 100 / 255); + else Printf("%s appears to be translucency %d (%d%%)\n", lumpname, *alpha, *alpha * 100 / 255); + } + sd->SetTexture(side_t::mid, FNullTextureID()); } else @@ -2166,6 +2144,7 @@ void MapLoader::ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec break; } // Fallthrough for Hexen maps is intentional + [[fallthrough]]; default: // normal cases @@ -2213,11 +2192,11 @@ void MapLoader::LoadSideDefs2 (MapData *map, FMissingTextureTracker &missingtex) // killough 4/4/98: allow sidedef texture names to be overloaded // killough 4/11/98: refined to allow colormaps to work as wall // textures if invalid as colormaps but valid as textures. - + // cph 2006/09/30 - catch out-of-range sector numbers; use sector 0 instead if ((unsigned)LittleShort(msd->sector)>=Level->sectors.Size()) { Printf (PRINT_HIGH, "Sidedef %d has a bad sector\n", i); - sd->sector = sec = nullptr; + sd->sector = sec = &Level->sectors[0]; } else { @@ -2410,7 +2389,7 @@ void MapLoader::CreateBlockMap () { if (bx > bx2) { - swapvalues (block, endblock); + std::swap (block, endblock); } do { @@ -2422,7 +2401,7 @@ void MapLoader::CreateBlockMap () { if (by > by2) { - swapvalues (block, endblock); + std::swap (block, endblock); } do { @@ -2722,7 +2701,7 @@ void MapLoader::GroupLines (bool buildmap) } if (flaggedNoFronts) { - I_Error ("You need to fix these lines to play this map.\n"); + I_Error ("You need to fix these lines to play this map."); } // build line tables for each sector @@ -2834,7 +2813,7 @@ void MapLoader::LoadReject (MapData * map, bool junk) else { // Check if the reject has some actual content. If not, free it. - rejectsize = MIN (rejectsize, neededsize); + rejectsize = min (rejectsize, neededsize); Level->rejectmatrix.Alloc(rejectsize); map->Read (ML_REJECT, &Level->rejectmatrix[0], rejectsize); @@ -3113,8 +3092,8 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) } } - // If loading the regular nodes failed try GL nodes before considering a rebuild - if (!NodesLoaded) + // If loading the regular nodes failed try GL nodes before considering a rebuild (unless a rebuild was already asked for) + if (!NodesLoaded && !ForceNodeBuild) { if (LoadGLNodes(map)) reloop = true; @@ -3224,6 +3203,12 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) SpawnThings(position); + // Load and link lightmaps - must be done after P_Spawn3DFloors (and SpawnThings? Potentially for baking static model actors?) + if (!ForceNodeBuild) + { + LoadLightmap(map); + } + for (int i = 0; i < MAXPLAYERS; ++i) { if (Level->PlayerInGame(i) && Level->Players[i]->mo != nullptr) @@ -3257,7 +3242,9 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) InitRenderInfo(); // create hardware independent renderer resources for the level. This must be done BEFORE the PolyObj Spawn!!! Level->ClearDynamic3DFloorData(); // CreateVBO must be run on the plain 3D floor data. - screen->mVertexData->CreateVBO(Level->sectors); + CreateVBO(screen->mVertexData, Level->sectors); + + screen->InitLightmap(Level->LMTextureSize, Level->LMTextureCount, Level->LMTextureData); for (auto &sec : Level->sectors) { @@ -3272,5 +3259,278 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) PO_Init(); // Initialize the polyobjs if (!Level->IsReentering()) Level->FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them. + + Level->aabbTree = new DoomLevelAABBTree(Level); + Level->levelMesh = new DoomLevelMesh(*Level); + + // [DVR] Populate subsector->bbox for alternative space culling in orthographic projection with no fog of war + subsector_t* sub = &Level->subsectors[0]; + seg_t* seg; + for (unsigned int kk = 0; kk < Level->subsectors.Size(); kk++) + { + sub[kk].bbox.ClearBox(); + unsigned int count = sub[kk].numlines; + seg = sub[kk].firstline; + while(count--) + { + if((seg->v1 != nullptr) && (seg->v2 != nullptr)) + { + sub[kk].bbox.AddToBox(seg->v1->fPos()); + sub[kk].bbox.AddToBox(seg->v2->fPos()); + } + seg++; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void MapLoader::SetSubsectorLightmap(const LightmapSurface &surface) +{ + if (!surface.ControlSector) + { + int index = surface.Type == ST_CEILING ? 1 : 0; + surface.Subsector->lightmap[index][0] = surface; + } + else + { + int index = surface.Type == ST_CEILING ? 0 : 1; + const auto &ffloors = surface.Subsector->sector->e->XFloor.ffloors; + for (unsigned int i = 0; i < ffloors.Size(); i++) + { + if (ffloors[i]->model == surface.ControlSector) + { + surface.Subsector->lightmap[index][i + 1] = surface; + } + } + } +} + +void MapLoader::SetSideLightmap(const LightmapSurface &surface) +{ + if (!surface.ControlSector) + { + if (surface.Type == ST_UPPERWALL) + { + surface.Side->lightmap[0] = surface; + } + else if (surface.Type == ST_MIDDLEWALL) + { + surface.Side->lightmap[1] = surface; + surface.Side->lightmap[2] = surface; + } + else if (surface.Type == ST_LOWERWALL) + { + surface.Side->lightmap[3] = surface; + } + } + else + { + const auto &ffloors = surface.Side->sector->e->XFloor.ffloors; + for (unsigned int i = 0; i < ffloors.Size(); i++) + { + if (ffloors[i]->model == surface.ControlSector) + { + surface.Side->lightmap[4 + i] = surface; + } + } + } } +void MapLoader::LoadLightmap(MapData *map) +{ + // We have to reset everything as FLevelLocals is recycled between maps + Level->LightProbes.Reset(); + Level->LPCells.Reset(); + Level->LMTexCoords.Reset(); + Level->LMSurfaces.Reset(); + Level->LMTextureData.Reset(); + Level->LMTextureCount = 0; + Level->LMTextureSize = 0; + Level->LPMinX = 0; + Level->LPMinY = 0; + Level->LPWidth = 0; + Level->LPHeight = 0; + + if (!Args->CheckParm("-enablelightmaps")) + return; // this feature is still too early WIP to allow general access + + if (!map->Size(ML_LIGHTMAP)) + return; + + FileReader fr; + if (!OpenDecompressor(fr, map->Reader(ML_LIGHTMAP), -1, FileSys::METHOD_ZLIB)) + return; + + + int version = fr.ReadInt32(); + if (version != 0) + { + Printf(PRINT_HIGH, "LoadLightmap: unsupported lightmap lump version\n"); + return; + } + + uint16_t textureSize = fr.ReadUInt16(); + uint16_t numTextures = fr.ReadUInt16(); + uint32_t numSurfaces = fr.ReadUInt32(); + uint32_t numTexCoords = fr.ReadUInt32(); + uint32_t numLightProbes = fr.ReadUInt32(); + uint32_t numSubsectors = fr.ReadUInt32(); + uint32_t numTexBytes = numTextures * textureSize * textureSize * 3 * 2; + + if (numSurfaces == 0 || numTexCoords == 0 || numTexBytes == 0) + return; + + Printf(PRINT_HIGH, "WARNING! Lightmaps are an experimental feature and are subject to change before being finalized. Do not expect this to work as-is in future releases of %s!\n", GAMENAME); + + /*if (numSubsectors != Level->subsectors.Size()) + { + Printf(PRINT_HIGH, "LoadLightmap: subsector count for level doesn't match (%d in wad vs %d in engine)\n", (int)numSubsectors, (int)Level->subsectors.Size()); + }*/ + + if (numLightProbes > 0) + { + Level->LightProbes.Resize(numLightProbes); + fr.Read(&Level->LightProbes[0], sizeof(LightProbe) * numLightProbes); + + // Sort the light probes so that they are ordered by cell. + // This lets us point at the first probe knowing all other probes in the cell will follow. + // Also improves locality. + + double rcpCellSize = 1.0 / Level->LPCellSize; + auto cellCompareLess = [=](const LightProbe& a, const LightProbe& b) + { + double cellY_A = std::floor(a.Y * rcpCellSize); + double cellY_B = std::floor(b.Y * rcpCellSize); + if (cellY_A != cellY_B) + return cellY_A < cellY_B; + double cellX_A = std::floor(a.X * rcpCellSize); + double cellX_B = std::floor(b.X * rcpCellSize); + return cellX_A < cellX_B; + }; + std::sort(Level->LightProbes.begin(), Level->LightProbes.end(), cellCompareLess); + + // Find probe bounds and the grid that covers it + float probesMinX = Level->LightProbes[0].X; + float probesMaxX = Level->LightProbes[0].X; + float probesMinY = Level->LightProbes[0].Y; + float probesMaxY = Level->LightProbes[0].Y; + for (const LightProbe& p : Level->LightProbes) + { + probesMinX = std::min(probesMinX, p.X); + probesMaxX = std::max(probesMaxX, p.X); + probesMinY = std::min(probesMinY, p.Y); + probesMaxY = std::max(probesMaxY, p.Y); + } + Level->LPMinX = (int)std::floor(probesMinX * rcpCellSize); + Level->LPMinY = (int)std::floor(probesMinY * rcpCellSize); + Level->LPWidth = (int)std::floor(probesMaxX * rcpCellSize) + 1 - Level->LPMinX; + Level->LPHeight = (int)std::floor(probesMaxY * rcpCellSize) + 1 - Level->LPMinY; + + // Place probes in a grid for faster search + Level->LPCells.Resize(Level->LPWidth * Level->LPHeight); + int minX = Level->LPMinX; + int minY = Level->LPMinY; + int width = Level->LPWidth; + int height = Level->LPHeight; + for (LightProbe& p : Level->LightProbes) + { + int gridX = (int)std::floor(p.X * rcpCellSize) - minX; + int gridY = (int)std::floor(p.Y * rcpCellSize) - minY; + if (gridX >= 0 && gridY >= 0 && gridX < width && gridY < height) + { + LightProbeCell& cell = Level->LPCells[gridX + (size_t)gridY * width]; + if (!cell.FirstProbe) + cell.FirstProbe = &p; + cell.NumProbes++; + } + } + } + + Level->LMTexCoords.Resize(numTexCoords * 2); + + // Allocate room for all surfaces + + unsigned int allSurfaces = 0; + + for (unsigned int i = 0; i < Level->sides.Size(); i++) + allSurfaces += 4 + Level->sides[i].sector->e->XFloor.ffloors.Size(); + + for (unsigned int i = 0; i < Level->subsectors.Size(); i++) + allSurfaces += 2 + Level->subsectors[i].sector->e->XFloor.ffloors.Size() * 2; + + Level->LMSurfaces.Resize(allSurfaces); + memset(&Level->LMSurfaces[0], 0, sizeof(LightmapSurface) * allSurfaces); + + // Link the surfaces to sectors, sides and their 3D floors + + unsigned int offset = 0; + for (unsigned int i = 0; i < Level->sides.Size(); i++) + { + auto& side = Level->sides[i]; + side.lightmap = &Level->LMSurfaces[offset]; + offset += 4 + side.sector->e->XFloor.ffloors.Size(); + } + for (unsigned int i = 0; i < Level->subsectors.Size(); i++) + { + auto& subsector = Level->subsectors[i]; + unsigned int count = 1 + subsector.sector->e->XFloor.ffloors.Size(); + subsector.lightmap[0] = &Level->LMSurfaces[offset]; + subsector.lightmap[1] = &Level->LMSurfaces[offset + count]; + offset += count * 2; + } + + // Load the surfaces we have lightmap data for + + for (uint32_t i = 0; i < numSurfaces; i++) + { + LightmapSurface surface; + memset(&surface, 0, sizeof(LightmapSurface)); + + SurfaceType type = (SurfaceType)fr.ReadUInt32(); + uint32_t typeIndex = fr.ReadUInt32(); + uint32_t controlSector = fr.ReadUInt32(); + uint32_t lightmapNum = fr.ReadUInt32(); + uint32_t firstTexCoord = fr.ReadUInt32(); + + if (controlSector != 0xffffffff) + surface.ControlSector = &Level->sectors[controlSector]; + + surface.Type = type; + surface.LightmapNum = lightmapNum; + surface.TexCoords = &Level->LMTexCoords[firstTexCoord * 2]; + + if (type == ST_CEILING || type == ST_FLOOR) + { + surface.Subsector = &Level->subsectors[typeIndex]; + surface.Subsector->firstline->sidedef->sector->HasLightmaps = true; + SetSubsectorLightmap(surface); + } + else if (type != ST_NULL) + { + surface.Side = &Level->sides[typeIndex]; + SetSideLightmap(surface); + } + } + + // Load texture coordinates + + fr.Read(&Level->LMTexCoords[0], numTexCoords * 2 * sizeof(float)); + + // Load lightmap textures + + Level->LMTextureCount = numTextures; + Level->LMTextureSize = textureSize; + Level->LMTextureData.Resize((numTexBytes + 1) / 2); + uint8_t* data = (uint8_t*)&Level->LMTextureData[0]; + fr.Read(data, numTexBytes); +#if 0 + // Apply compression predictor + for (uint32_t i = 1; i < numTexBytes; i++) + data[i] += data[i - 1]; +#endif +} diff --git a/src/maploader/maploader.h b/src/maploader/maploader.h index 6932b8aa038..5479016d7db 100644 --- a/src/maploader/maploader.h +++ b/src/maploader/maploader.h @@ -2,8 +2,8 @@ #include "nodebuild.h" #include "g_levellocals.h" +#include "files.h" -class FileReader; struct FStrifeDialogueNode; struct FStrifeDialogueReply; struct Response; @@ -110,8 +110,6 @@ class MapLoader int firstglvertex; // helpers for loading GL nodes from GWA files. bool format5; - TArray vertexdatas; - TMap MapThingsUserDataIndex; // from mapthing idx -> user data idx TArray MapThingsUserData; int sidecount = 0; @@ -120,6 +118,8 @@ class MapLoader public: // for the scripted compatibility system these two members need to be public. TArray MapThingsConverted; bool ForceNodeBuild = false; + // This needs to be public to fetch this from DLevelPostProcessor native functions + TArray vertexdatas; private: // Extradata loader @@ -152,7 +152,7 @@ class MapLoader // Polyobjects void InitSideLists(); void IterFindPolySides(FPolyObj *po, side_t *side); - void SpawnPolyobj(int index, int tag, int type); + void SpawnPolyobj(int index, int tag, int type, int damage); void TranslateToStartSpot(int tag, const DVector2 &origin); void InitPolyBlockMap(void); @@ -194,7 +194,7 @@ class MapLoader void SpawnSpecials(); void InitSectorSpecial(sector_t *sector, int special); void SpawnLights(sector_t *sector); - void CreateScroller(EScroll type, double dx, double dy, sector_t *affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all); + void CreateScroller(EScroll type, double dx, double dy, sector_t *sect, side_t* side, int accel, EScrollPos scrollpos = EScrollPos::scw_all, int scrollmode = 15/*SCROLL_All*/); void SpawnScrollers(); void SpawnFriction(); void SpawnPushers(); @@ -212,6 +212,10 @@ class MapLoader void Spawn3DFloors (); void SetTexture(side_t *side, int position, const char *name, FMissingTextureTracker &track); + void SetTexture(side_t* side, int position, const FString& name, FMissingTextureTracker& track) + { + SetTexture(side, position, name.GetChars(), track); + } void SetTexture(sector_t *sector, int index, int position, const char *name, FMissingTextureTracker &track, bool truncate); void SetTexture(side_t *side, int position, uint32_t *blend, const char *name); void SetTextureNoErr(side_t *side, int position, uint32_t *color, const char *name, bool *validcolor, bool isFog); @@ -221,7 +225,6 @@ class MapLoader void LoadZSegs(FileReader &data); void LoadZNodes(FileReader &data, int glnodes); - int DetermineTranslucency(int lumpnum); void SetLineID(int i, line_t *ld); void SaveLineSpecial(line_t *ld); void FinishLoadingLineDef(line_t *ld, int alpha); @@ -305,6 +308,10 @@ class MapLoader void SetSlopes(); void CopySlopes(); + void SetSubsectorLightmap(const LightmapSurface &surface); + void SetSideLightmap(const LightmapSurface &surface); + void LoadLightmap(MapData *map); + void LoadLevel(MapData *map, const char *lumpname, int position); MapLoader(FLevelLocals *lev) diff --git a/src/maploader/polyobjects.cpp b/src/maploader/polyobjects.cpp index 3c0a567adbc..1f662b134cb 100644 --- a/src/maploader/polyobjects.cpp +++ b/src/maploader/polyobjects.cpp @@ -36,6 +36,7 @@ #include "g_levellocals.h" #include "actorinlines.h" #include "v_text.h" +#include "s_sndseq.h" #include "maploader/maploader.h" @@ -147,7 +148,22 @@ static int posicmp(const void *a, const void *b) return (*(const side_t **)a)->linedef->args[1] - (*(const side_t **)b)->linedef->args[1]; } -void MapLoader::SpawnPolyobj (int index, int tag, int type) +int SetPolyobjDamage(int type, int damage) +{ + int dam; + if (type != SMT_PolySpawn) + { + if (damage == 1) + dam = 3; + else if (damage > 1) + dam = TELEFRAG_DAMAGE; + else if (damage < 0) + dam = abs(damage); + } + return (type != SMT_PolySpawn) ? dam : 0; +} + +void MapLoader::SpawnPolyobj (int index, int tag, int type, int damage) { unsigned int ii; int i; @@ -180,11 +196,12 @@ void MapLoader::SpawnPolyobj (int index, int tag, int type) sd->linedef->args[0] = 0; IterFindPolySides(&Level->Polyobjects[index], sd); po->MirrorNum = sd->linedef->args[1]; - po->crush = (type != SMT_PolySpawn) ? 3 : 0; + po->crush = SetPolyobjDamage(type,damage); po->bHurtOnTouch = (type == SMT_PolySpawnHurt); + po->tag = tag; po->seqType = sd->linedef->args[2]; - if (po->seqType < 0 || po->seqType > 63) + if (po->seqType < 0 || po->seqType > (MAX_SNDSEQS - 1)) { po->seqType = 0; } @@ -221,7 +238,7 @@ void MapLoader::SpawnPolyobj (int index, int tag, int type) qsort(&po->Sidedefs[0], po->Sidedefs.Size(), sizeof(po->Sidedefs[0]), posicmp); if (po->Sidedefs.Size() > 0) { - po->crush = (type != SMT_PolySpawn) ? 3 : 0; + po->crush = SetPolyobjDamage(type,damage); po->bHurtOnTouch = (type == SMT_PolySpawnHurt); po->tag = tag; po->seqType = po->Sidedefs[0]->linedef->args[3]; @@ -294,8 +311,8 @@ void MapLoader::TranslateToStartSpot (int tag, const DVector2 &origin) Printf(TEXTCOLOR_RED "TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag); return; } - po->OriginalPts.Resize(po->Sidedefs.Size()); - po->PrevPts.Resize(po->Sidedefs.Size()); + po->OriginalPts.Resize(po->Vertices.Size()); + po->PrevPts.Resize(po->Vertices.Size()); delta = origin - po->StartSpot.pos; for (unsigned i = 0; i < po->Sidedefs.Size(); i++) @@ -331,7 +348,7 @@ void MapLoader::PO_Init (void) TArray polythings; for (auto &mthing : MapThingsConverted) { - if (mthing.EdNum == 0 || mthing.EdNum == -1 || mthing.info == nullptr) continue; + if (mthing.EdNum == 0 || mthing.EdNum == -1 || mthing.info == nullptr || mthing.info->Type != nullptr) continue; FDoomEdEntry *mentry = mthing.info; switch (mentry->Special) @@ -358,13 +375,13 @@ void MapLoader::PO_Init (void) // Find the startSpot points, and spawn each polyobj for (int i=polythings.Size()-1; i >= 0; i--) { - // 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch + // 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch, Health = crusher/hurter damage int type = polythings[i]->info->Special; if (type >= SMT_PolySpawn && type <= SMT_PolySpawnHurt) { // Polyobj StartSpot Pt. - Level->Polyobjects[polyIndex].StartSpot.pos = polythings[i]->pos; - SpawnPolyobj(polyIndex, polythings[i]->angle, type); + Level->Polyobjects[polyIndex].StartSpot.pos = polythings[i]->pos.XY(); + SpawnPolyobj(polyIndex, polythings[i]->angle, type, polythings[i]->Health); polyIndex++; } } @@ -374,7 +391,7 @@ void MapLoader::PO_Init (void) if (type == SMT_PolyAnchor) { // Polyobj Anchor Pt. - TranslateToStartSpot (polythings[i]->angle, polythings[i]->pos); + TranslateToStartSpot (polythings[i]->angle, polythings[i]->pos.XY()); } } @@ -414,4 +431,3 @@ void MapLoader::PO_Init (void) } } } - diff --git a/src/maploader/postprocessor.cpp b/src/maploader/postprocessor.cpp index 74dc576ead2..e94e7d4d74e 100644 --- a/src/maploader/postprocessor.cpp +++ b/src/maploader/postprocessor.cpp @@ -39,7 +39,7 @@ #include "g_level.h" #include "p_lnspec.h" #include "p_tags.h" -#include "w_wad.h" +#include "filesystem.h" #include "textures.h" #include "g_levellocals.h" #include "actor.h" @@ -110,6 +110,37 @@ DEFINE_ACTION_FUNCTION(DLevelPostProcessor, OffsetSectorPlane) return 0; } +DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetSectorPlane) +{ + PARAM_SELF_PROLOGUE(DLevelPostProcessor); + PARAM_INT(sector); + PARAM_INT(planeval); + PARAM_FLOAT(normal_x); + PARAM_FLOAT(normal_y); + PARAM_FLOAT(normal_z); + PARAM_FLOAT(d); + + if ((unsigned)sector < self->Level->sectors.Size()) + { + sector_t* sec = &self->Level->sectors[sector]; + secplane_t& plane = sector_t::floor == planeval ? sec->floorplane : sec->ceilingplane; + if (normal_z != 0) + { + plane.normal = DVector3(normal_x, normal_y, normal_z); + plane.D = d; + plane.negiC = -1 / normal_z; + } + else + { + plane.normal = DVector3(0, 0, sector_t::floor == planeval ? 1 : -1); + plane.D = d; + plane.negiC = -1 / plane.normal.Z; + } + } + + return 0; +} + DEFINE_ACTION_FUNCTION(DLevelPostProcessor, ClearSectorTags) { PARAM_SELF_PROLOGUE(DLevelPostProcessor); @@ -369,7 +400,7 @@ DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingStringArgument) const FName argument = thing < self->loader->MapThingsConverted.Size() ? self->loader->MapThingsConverted[thing].arg0str : NAME_None; - ACTION_RETURN_INT(argument); + ACTION_RETURN_INT(argument.GetIndex()); } DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingArgument) @@ -437,6 +468,75 @@ DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetVertex) return 0; } +DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetVertexZ) +{ + PARAM_SELF_PROLOGUE(DLevelPostProcessor); + PARAM_UINT(vertex); + PARAM_INT(planeval); + + double value = 0; + bool isset = false; + + if (vertex < self->Level->vertexes.Size() && vertex < self->loader->vertexdatas.Size()) + { + vertexdata_t& data = self->loader->vertexdatas[vertex]; + value = sector_t::floor == planeval ? data.zFloor : data.zCeiling; + isset = data.flags & (sector_t::floor == planeval ? VERTEXFLAG_ZFloorEnabled : VERTEXFLAG_ZCeilingEnabled); + } + + if (numret > 1) + { + numret = 2; + ret[1].SetInt(isset); + } + + if (numret > 0) + { + ret[0].SetFloat(value); + } + + return numret; +} + +DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetVertexZ) +{ + PARAM_SELF_PROLOGUE(DLevelPostProcessor); + PARAM_UINT(vertex); + PARAM_INT(planeval); + PARAM_FLOAT(z); + + if (vertex < self->Level->vertexes.Size() && vertex < self->loader->vertexdatas.Size()) + { + vertexdata_t& data = self->loader->vertexdatas[vertex]; + if (sector_t::floor == planeval) { + data.flags |= VERTEXFLAG_ZFloorEnabled; + data.zFloor = z; + } + else + { + data.flags |= VERTEXFLAG_ZCeilingEnabled; + data.zCeiling = z; + } + } + + return 0; +} + +DEFINE_ACTION_FUNCTION(DLevelPostProcessor, RemoveVertexZ) +{ + PARAM_SELF_PROLOGUE(DLevelPostProcessor); + PARAM_UINT(vertex); + PARAM_INT(planeval); + + if (vertex < self->Level->vertexes.Size() && vertex < self->loader->vertexdatas.Size()) + { + vertexdata_t& data = self->loader->vertexdatas[vertex]; + data.flags &= ~(sector_t::floor == planeval ? VERTEXFLAG_ZFloorEnabled : VERTEXFLAG_ZCeilingEnabled); + } + + return 0; +} + DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetLineVertexes) { PARAM_SELF_PROLOGUE(DLevelPostProcessor); diff --git a/src/maploader/renderinfo.cpp b/src/maploader/renderinfo.cpp index 32ec955ac1c..533526237fb 100644 --- a/src/maploader/renderinfo.cpp +++ b/src/maploader/renderinfo.cpp @@ -402,6 +402,10 @@ void MapLoader::InitVertexData() for(auto &line : Level->lines) { + if (line.Index() == 13380) + { + int a = 0; + } for(int j = 0; j < 2; ++j) { vertex_t * v = j==0? line.v1 : line.v2; @@ -412,10 +416,13 @@ void MapLoader::InitVertexData() if (sec) { - extsector_t::xfloor &x = sec->e->XFloor; - AddToVertex(Index(sec), vt_sectorlists[Index(v)]); if (sec->heightsec) AddToVertex(Index(sec->heightsec), vt_sectorlists[Index(v)]); + extsector_t::xfloor& x = sec->e->XFloor; + for (auto& ff : x.ffloors) + { + AddToVertex(Index(ff->model), vt_sectorlists[Index(v)]); + } } } } @@ -709,7 +716,7 @@ void MapLoader::InitRenderInfo() PrepareSectorData(); InitVertexData(); FloodSectorStacks(); - TArray checkmap(Level->vertexes.Size()); + TArray checkmap(Level->vertexes.Size(), true); memset(checkmap.Data(), -1, sizeof(int)*Level->vertexes.Size()); for(auto &sec : Level->sectors) { @@ -821,7 +828,7 @@ void MapLoader::FixHoles() segloops.Reserve(1); auto *segloop = &segloops.Last(); - seg_t *startseg; + seg_t *startseg = nullptr; seg_t *checkseg; while (bogussegs.Size() > 0) { diff --git a/src/maploader/slopes.cpp b/src/maploader/slopes.cpp index 2fb44e628ec..77c33cd7456 100644 --- a/src/maploader/slopes.cpp +++ b/src/maploader/slopes.cpp @@ -160,22 +160,22 @@ void MapLoader::SetSlope (secplane_t *plane, bool setCeil, int xyangi, int zangi if (zangi >= 180) { - zang = 179.; + zang = DAngle::fromDeg(179.); } else if (zangi <= 0) { - zang = 1.; + zang = DAngle::fromDeg(1.); } else { - zang = (double)zangi; + zang = DAngle::fromDeg(zangi); } if (setCeil) { - zang += 180.; + zang += DAngle::fromDeg(180.); } - xyang = (double)xyangi; + xyang = DAngle::fromDeg(xyangi); DVector3 norm; @@ -417,18 +417,18 @@ void MapLoader::SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt, const i mt->EdNum = 0; } } + SetSlopesFromVertexHeights(firstmt, lastmt, oldvertextable); for (mt = firstmt; mt < lastmt; ++mt) { if (mt->info != NULL && mt->info->Type == NULL && (mt->info->Special == SMT_CopyFloorPlane || mt->info->Special == SMT_CopyCeilingPlane)) { - CopyPlane (mt->args[0], mt->pos, mt->info->Special == SMT_CopyCeilingPlane); + CopyPlane (mt->args[0], mt->pos.XY(), mt->info->Special == SMT_CopyCeilingPlane); mt->EdNum = 0; } } - SetSlopesFromVertexHeights(firstmt, lastmt, oldvertextable); } diff --git a/src/maploader/specials.cpp b/src/maploader/specials.cpp index 64f3ea7b80d..47663e81210 100644 --- a/src/maploader/specials.cpp +++ b/src/maploader/specials.cpp @@ -67,7 +67,7 @@ #include -#include "templates.h" + #include "doomdef.h" #include "doomstat.h" #include "d_event.h" @@ -120,17 +120,18 @@ void MapLoader::SpawnLinePortal(line_t* line) // portal destination is special argument #0 line_t* dst = nullptr; - if (line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED) + if ((line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED) || line->special == Line_QuickPortal) { - dst = Level->FindPortalDestination(line, line->args[0]); + int type = (line->special != Line_QuickPortal) ? line->args[2] : line->args[0] == 0 ? PORTT_LINKED : PORTT_VISUAL; + int tag = (line->special == Line_QuickPortal) ? Level->tagManager.GetFirstLineID(line) : line->args[0]; + dst = Level->FindPortalDestination(line, tag, line->special == Line_QuickPortal? Line_QuickPortal : -1); line->portalindex = Level->linePortals.Reserve(1); FLinePortal *port = &Level->linePortals.Last(); - memset(port, 0, sizeof(FLinePortal)); port->mOrigin = line; port->mDestination = dst; - port->mType = uint8_t(line->args[2]); // range check is done above. + port->mType = uint8_t(type); // range check is done above. if (port->mType == PORTT_LINKED) { @@ -139,7 +140,8 @@ void MapLoader::SpawnLinePortal(line_t* line) } else { - port->mAlign = uint8_t(line->args[3] >= PORG_ABSOLUTE && line->args[3] <= PORG_CEILING ? line->args[3] : PORG_ABSOLUTE); + int flags = (line->special == Line_QuickPortal) ? PORG_ABSOLUTE : line->args[3]; + port->mAlign = uint8_t(flags >= PORG_ABSOLUTE && flags <= PORG_CEILING ? flags : PORG_ABSOLUTE); if (port->mType == PORTT_INTERACTIVE && port->mAlign != PORG_ABSOLUTE) { // Due to the way z is often handled, these pose a major issue for parts of the code that needs to transparently handle interactive portals. @@ -164,7 +166,7 @@ void MapLoader::SpawnLinePortal(line_t* line) line->portalindex = Level->linePortals.Reserve(1); FLinePortal *port = &Level->linePortals.Last(); - memset(port, 0, sizeof(FLinePortal)); + port->Clear(); port->mOrigin = line; port->mDestination = &ln; port->mType = PORTT_LINKED; @@ -175,7 +177,7 @@ void MapLoader::SpawnLinePortal(line_t* line) ln.portalindex = Level->linePortals.Reserve(1); port = &Level->linePortals.Last(); - memset(port, 0, sizeof(FLinePortal)); + port->Clear(); port->mOrigin = &ln; port->mDestination = line; port->mType = PORTT_LINKED; @@ -279,7 +281,7 @@ void MapLoader::SetupPortals() { if (s.mType == PORTS_STACKEDSECTORTHING && s.mSkybox) { - s.mDisplacement = s.mSkybox->Pos() - s.mSkybox->target->Pos(); + s.mDisplacement = s.mSkybox->Pos().XY() - s.mSkybox->target->Pos().XY(); s.mSkybox = nullptr; } } @@ -447,10 +449,10 @@ void MapLoader::SpawnSkybox(AActor *origin) static void SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags) { // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials. - if (sector->damageamount == 0) + if (sector->damageamount == 0 && !(sector->Flags & (SECF_EXIT1|SECF_EXIT2))) { sector->damageamount = damage; - sector->damageinterval = MAX(1, interval); + sector->damageinterval = max(1, interval); sector->leakydamage = leakchance; sector->damagetype = type; sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS); @@ -482,17 +484,44 @@ void MapLoader::InitSectorSpecial(sector_t *sector, int special) { sector->Flags |= SECF_PUSH; } - if ((sector->special & DAMAGE_MASK) == 0x100) + // Nom MBF21 compatibility needs to be checked here, because after this point there is no longer any context in which it can be done. + if ((sector->special & KILL_MONSTERS_MASK) && Level->MBF21Enabled()) { - SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0); + sector->Flags |= SECF_KILLMONSTERS; } - else if ((sector->special & DAMAGE_MASK) == 0x200) + if (!(sector->special & DEATH_MASK) || !Level->MBF21Enabled()) { - SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + if ((sector->special & DAMAGE_MASK) == 0x100) + { + SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x200) + { + SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x300) + { + SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + } } - else if ((sector->special & DAMAGE_MASK) == 0x300) + else { - SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + if ((sector->special & DAMAGE_MASK) == 0x100) + { + SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x200) + { + sector->Flags |= SECF_EXIT1; + } + else if ((sector->special & DAMAGE_MASK) == 0x300) + { + sector->Flags |= SECF_EXIT2; + } + else // 0 + { + SetupSectorDamage(sector, TELEFRAG_DAMAGE-1, 0, 0, NAME_InstantDeath, 0); + } } sector->special &= 0xff; @@ -545,7 +574,7 @@ void MapLoader::InitSectorSpecial(sector_t *sector, int special) case dScroll_EastLavaDamage: SetupSectorDamage(sector, 5, 16, 256, NAME_Fire, SECF_DMGTERRAINFX); - CreateScroller(EScroll::sc_floor, -4., 0, sector, 0); + CreateScroller(EScroll::sc_floor, -4., 0, sector, nullptr, 0); keepspecial = true; break; @@ -580,7 +609,7 @@ void MapLoader::InitSectorSpecial(sector_t *sector, int special) break; case Sky2: - sector->sky = PL_SKYFLAT; + sector->skytransfer = PL_SKYFLAT; break; default: @@ -602,13 +631,13 @@ void MapLoader::InitSectorSpecial(sector_t *sector, int special) int i = sector->special - Scroll_North_Slow; double dx = hexenScrollies[i][0] / 2.; double dy = hexenScrollies[i][1] / 2.; - CreateScroller(EScroll::sc_floor, dx, dy, sector, 0); + CreateScroller(EScroll::sc_floor, dx, dy, sector, nullptr, 0); } else if (sector->special >= Carry_East5 && sector->special <= Carry_East35) { // Heretic scroll special // Only east scrollers also scroll the texture - CreateScroller(EScroll::sc_floor, -0.5 * (1 << ((sector->special & 0xff) - Carry_East5)), 0, sector, 0); + CreateScroller(EScroll::sc_floor, -0.5 * (1 << ((sector->special & 0xff) - Carry_East5)), 0, sector, nullptr, 0); } keepspecial = true; break; @@ -755,9 +784,32 @@ void MapLoader::SpawnSpecials () break; case Line_SetPortal: + case Line_QuickPortal: SpawnLinePortal(&line); break; + // partial support for MBF's stay-on-lift feature. + // Unlike MBF we cannot scan all lines for a proper special each time because it'd take too long. + // So instead, set the info here, but only for repeatable lifts to keep things simple. + // This also cannot consider lifts triggered by scripts etc. + case Generic_Lift: + if (line.args[3] != 1) continue; + [[fallthrough]]; + case Plat_DownWaitUpStay: + case Plat_DownWaitUpStayLip: + case Plat_UpWaitDownStay: + case Plat_UpNearestWaitDownStay: + if (line.flags & ML_REPEAT_SPECIAL) + { + auto it = Level->GetSectorTagIterator(line.args[0], &line); + int secno; + while ((secno = it.Next()) != -1) + { + Level->sectors[secno].MoreFlags |= SECMF_LIFT; + } + } + break; + // [RH] ZDoom Static_Init settings case Static_Init: switch (line.args[1]) @@ -820,7 +872,7 @@ void MapLoader::SpawnSpecials () { auto itr = Level->GetSectorTagIterator(line.args[0]); while ((s = itr.Next()) >= 0) - Level->sectors[s].sky = (line.Index() + 1) | PL_SKYFLAT; + Level->sectors[s].skytransfer = (line.Index() + 1) | PL_SKYFLAT; break; } } @@ -943,7 +995,8 @@ int MapLoader::Set3DFloor(line_t * line, int param, int param2, int alpha) // if flooding is used the floor must be non-solid and is automatically made shootthrough and seethrough if ((param2 & 128) && !(flags & FF_SOLID)) flags |= FF_FLOOD | FF_SEETHROUGH | FF_SHOOTTHROUGH; if (param2 & 512) flags |= FF_FADEWALLS; - if (param2&1024) flags |= FF_RESET; + if (param2 & 1024) flags |= FF_RESET; + if (param2 & 2048) flags |= FF_NODAMAGE; FTextureID tex = line->sidedef[0]->GetTexture(side_t::top); if (!tex.Exists() && alpha < 255) { @@ -970,7 +1023,7 @@ int MapLoader::Set3DFloor(line_t * line, int param, int param2, int alpha) void MapLoader::Spawn3DFloors () { - static int flagvals[] = {512, 2+512, 512+1024}; + static int flagvals[] = {512+2048, 2+512+2048, 512+1024+2048}; for (auto &line : Level->lines) { @@ -1096,8 +1149,8 @@ AActor *MapLoader::GetPushThing(int s) thing = sec->thinglist; while (thing && - thing->GetClass()->TypeName != NAME_PointPusher && - thing->GetClass()->TypeName != NAME_PointPuller) + !thing->IsKindOf(NAME_PointPusher) && + !thing->IsKindOf(NAME_PointPuller)) { thing = thing->snext; } @@ -1156,8 +1209,8 @@ void MapLoader::SpawnPushers() while ((thing = iterator.Next())) { - if (thing->GetClass()->TypeName == NAME_PointPusher || - thing->GetClass()->TypeName == NAME_PointPuller) + if (thing->IsKindOf(NAME_PointPusher) || + thing->IsKindOf(NAME_PointPuller)) { Level->CreateThinker(DPusher::p_push, l->args[3] ? l : NULL, l->args[2], 0, thing, thing->Sector->Index()); } @@ -1342,11 +1395,34 @@ void MapLoader::SpawnScrollers() } case Scroll_Texture_Offsets: + { + double divider = max(1, l->args[3]); // killough 3/2/98: scroll according to sidedef offsets - side = Level->lines[i].sidedef[0]; - Level->CreateThinker(EScroll::sc_side, -side->GetTextureXOffset(side_t::mid), - side->GetTextureYOffset(side_t::mid), nullptr, nullptr, side, accel, SCROLLTYPE(l->args[0])); + side = l->sidedef[0]; + if (l->args[2] & 3) + { + // if 1, then displacement + // if 2, then accelerative (also if 3) + control = l->sidedef[0]->sector; + if (l->args[2] & 2) + accel = 1; + } + double dx = -side->GetTextureXOffset(side_t::mid) / divider; + double dy = side->GetTextureYOffset(side_t::mid) / divider; + if (l->args[1] == 0) + { + Level->CreateThinker(EScroll::sc_side, dx, dy, control, nullptr, side, accel, SCROLLTYPE(l->args[0])); + } + else + { + auto it = Level->GetLineIdIterator(l->args[1]); + while ((s = it.Next()) >= 0) + { + Level->CreateThinker(EScroll::sc_side, dx, dy, control, nullptr, Level->lines[s].sidedef[0], accel, SCROLLTYPE(l->args[0])); + } + } break; + } case Scroll_Texture_Left: l->special = special; // Restore the special, for compat_useblocking's benefit. @@ -1390,7 +1466,8 @@ void MapLoader::SpawnScrollers() } -void MapLoader::CreateScroller(EScroll type, double dx, double dy, sector_t *affectee, int accel, EScrollPos scrollpos) +void MapLoader::CreateScroller(EScroll type, double dx, double dy, sector_t *sect, side_t* side, int accel, EScrollPos scrollpos, int scrollmode) { - Level->CreateThinker(type, dx, dy, nullptr, affectee, nullptr, accel, scrollpos); + Level->CreateThinker(type, dx, dy, nullptr, sect, side, accel, scrollpos, scrollmode); } + diff --git a/src/maploader/strifedialogue.cpp b/src/maploader/strifedialogue.cpp index 89bc7bfd0e8..ac927362189 100644 --- a/src/maploader/strifedialogue.cpp +++ b/src/maploader/strifedialogue.cpp @@ -37,7 +37,7 @@ #include "actor.h" #include "p_conversation.h" -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" #include "v_text.h" #include "gi.h" @@ -105,6 +105,20 @@ void MapLoader::LoadStrifeConversations (MapData *map, const char *mapname) } else { + // additive dialogues via MAPINFO + bool addedDialogues = false; + for (const FString &addd : gameinfo.AddDialogues) + { + if (!LoadScriptFile(addd.GetChars(), true, 0)) + { + continue; + } + else + { + addedDialogues = true; + } + } + if (strnicmp (mapname, "MAP", 3) == 0) { char scriptname_b[9] = { 'S','C','R','I','P','T',mapname[3],mapname[4],0 }; @@ -119,8 +133,12 @@ void MapLoader::LoadStrifeConversations (MapData *map, const char *mapname) if (gameinfo.Dialogue.IsNotEmpty()) { - if (LoadScriptFile(gameinfo.Dialogue, false, 0)) + if (LoadScriptFile(gameinfo.Dialogue.GetChars(), false, 0)) { + if (addedDialogues) + { + Printf(TEXTCOLOR_RED "Warning! Dialogue was mixed with AddDialogues! Previous AddDialogues have been overwritten\n"); + } return; } } @@ -139,9 +157,9 @@ void MapLoader::LoadStrifeConversations (MapData *map, const char *mapname) bool MapLoader::LoadScriptFile (const char *name, bool include, int type) { - int lumpnum = Wads.CheckNumForName (name); + int lumpnum = fileSystem.CheckNumForName (name); const bool found = lumpnum >= 0 - || (lumpnum = Wads.CheckNumForFullName (name)) >= 0; + || (lumpnum = fileSystem.CheckNumForFullName (name)) >= 0; if (!found) { @@ -152,13 +170,13 @@ bool MapLoader::LoadScriptFile (const char *name, bool include, int type) return false; } - FileReader lump = Wads.ReopenLumpReader (lumpnum); + FileReader lump = fileSystem.ReopenFileReader (lumpnum); - auto fn = Wads.GetLumpFile(lumpnum); - auto wadname = Wads.GetWadName(fn); + auto fn = fileSystem.GetFileContainer(lumpnum); + auto wadname = fileSystem.GetResourceFileName(fn); if (stricmp(wadname, "STRIFE0.WAD") && stricmp(wadname, "STRIFE1.WAD") && stricmp(wadname, "SVE.WAD")) name = nullptr; // Only localize IWAD content. - bool res = LoadScriptFile(name, lumpnum, lump, Wads.LumpLength(lumpnum), include, type); + bool res = LoadScriptFile(name, lumpnum, lump, fileSystem.FileLength(lumpnum), include, type); return res; } @@ -177,7 +195,7 @@ bool MapLoader::LoadScriptFile(const char *name, int lumpnum, FileReader &lump, if ((type == 1 && !isbinary) || (type == 2 && isbinary)) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", fileSystem.GetFileFullName(lumpnum)); return false; } @@ -197,7 +215,7 @@ bool MapLoader::LoadScriptFile(const char *name, int lumpnum, FileReader &lump, // is exactly 1516 bytes long. if (numnodes % 1516 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", fileSystem.GetFileFullName(lumpnum)); return false; } numnodes /= 1516; @@ -207,7 +225,7 @@ bool MapLoader::LoadScriptFile(const char *name, int lumpnum, FileReader &lump, // And the teaser version has 1488-byte entries. if (numnodes % 1488 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", fileSystem.GetFileFullName(lumpnum)); return false; } numnodes /= 1488; @@ -301,7 +319,7 @@ FStrifeDialogueNode *MapLoader::ReadRetailNode (const char *name, FileReader &lu // The speaker's voice for this node, if any. speech.Backdrop[0] = 0; //speech.Sound[8] = 0; mysnprintf (fullsound, countof(fullsound), "svox/%s", speech.Sound); - node->SpeakerVoice = fullsound; + node->SpeakerVoice = S_FindSound(fullsound); // The speaker's name, if any. speech.Sound[0] = 0; //speech.Name[16] = 0; @@ -327,7 +345,7 @@ FStrifeDialogueNode *MapLoader::ReadRetailNode (const char *name, FileReader &lu for (j = 0; j < 3; ++j) { auto inv = GetStrifeType(speech.ItemCheck[j]); - if (!inv->IsDescendantOf(NAME_Inventory)) inv = nullptr; + if (inv == NULL || !inv->IsDescendantOf(NAME_Inventory)) inv = nullptr; node->ItemCheck[j].Item = inv; node->ItemCheck[j].Amount = -1; } @@ -397,11 +415,11 @@ FStrifeDialogueNode *MapLoader::ReadTeaserNode (const char *name, FileReader &lu if (speech.VoiceNumber != 0) { mysnprintf (fullsound, countof(fullsound), "svox/voc%u", speech.VoiceNumber); - node->SpeakerVoice = fullsound; + node->SpeakerVoice = S_FindSound(fullsound); } else { - node->SpeakerVoice = 0; + node->SpeakerVoice = NO_SOUND; } // The speaker's name, if any. @@ -498,7 +516,7 @@ void MapLoader::ParseReplies (const char *name, int pos, FStrifeDialogueReply ** for (k = 0; k < 3; ++k) { auto inv = GetStrifeType(rsp->Item[k]); - if (!inv->IsDescendantOf(NAME_Inventory)) inv = nullptr; + if (inv == NULL || !inv->IsDescendantOf(NAME_Inventory)) inv = nullptr; reply->ItemCheck[k].Item = inv; reply->ItemCheck[k].Amount = rsp->Count[k]; } diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index bdc28d7ab83..725b95b91f3 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -42,7 +42,7 @@ #include "g_level.h" #include "udmf.h" #include "r_state.h" -#include "w_wad.h" +#include "filesystem.h" #include "p_tags.h" #include "p_terrain.h" #include "p_spec.h" @@ -51,6 +51,9 @@ #include "vm.h" #include "xlat/xlat.h" #include "maploader.h" +#include "texturemanager.h" +#include "a_scroll.h" +#include "p_spec_thinkers.h" //=========================================================================== // @@ -103,26 +106,47 @@ static char HexenSectorSpecialOk[256]={ 1,1,1,1,1, }; +#if 0 +static const char* udmfsolidskewtypes[] = +{ + "none", + "front", + "back", + nullptr +}; + +static const char* udmfmaskedskewtypes[] = +{ + "none", + "front_floor", + "front_ceiling", + "back_floor", + "back_ceiling", + nullptr +}; +#endif + static inline bool P_IsThingSpecial(int specnum) { return (specnum >= Thing_Projectile && specnum <= Thing_SpawnNoFog) || specnum == Thing_SpawnFacing || specnum == Thing_ProjectileIntercept || specnum == Thing_ProjectileAimed; } - -enum +namespace { - Dm=1, - Ht=2, - Hx=4, - St=8, - Zd=16, - Zdt=32, - Va=64, - - // will be extended later. Unknown namespaces will always be treated like the base - // namespace for each game -}; - + enum + { + Dm=1, // Doom + Ht=2, // Heretic + Hx=4, // Hexen + St=8, // Strife + Zd=16, // ZDoom + Zdt=32, // ZDoom Translated + Va=64, // Vavoom + + // will be extended later. Unknown namespaces will always be treated like the base + // namespace for each game + }; +} #define CHECK_N(f) if (!(namespace_bits&(f))) break; //=========================================================================== @@ -226,58 +250,72 @@ FName UDMFParserBase::ParseKey(bool checkblock, bool *isblock) // //=========================================================================== -int UDMFParserBase::CheckInt(const char *key) +int UDMFParserBase::CheckInt(FName key) { if (sc.TokenType != TK_IntConst) { - sc.ScriptMessage("Integer value expected for key '%s'", key); + sc.ScriptMessage("Integer value expected for key '%s'", key.GetChars()); } return sc.Number; } -double UDMFParserBase::CheckFloat(const char *key) +double UDMFParserBase::CheckFloat(FName key) { if (sc.TokenType != TK_IntConst && sc.TokenType != TK_FloatConst) { - sc.ScriptMessage("Floating point value expected for key '%s'", key); + sc.ScriptMessage("Floating point value expected for key '%s'", key.GetChars()); } return sc.Float; } -double UDMFParserBase::CheckCoordinate(const char *key) +double UDMFParserBase::CheckCoordinate(FName key) { if (sc.TokenType != TK_IntConst && sc.TokenType != TK_FloatConst) { - sc.ScriptMessage("Floating point value expected for key '%s'", key); + sc.ScriptMessage("Floating point value expected for key '%s'", key.GetChars()); } if (sc.Float < -32768 || sc.Float > 32768) { - sc.ScriptMessage("Value %f out of range for a coordinate '%s'. Valid range is [-32768 .. 32768]", sc.Float, key); + sc.ScriptMessage("Value %f out of range for a coordinate '%s'. Valid range is [-32768 .. 32768]", sc.Float, key.GetChars()); BadCoordinates = true; // If this happens the map must not allowed to be started. } return sc.Float; } -DAngle UDMFParserBase::CheckAngle(const char *key) +DAngle UDMFParserBase::CheckAngle(FName key) { - return DAngle(CheckFloat(key)).Normalized360(); + return DAngle::fromDeg(CheckFloat(key)).Normalized360(); } -bool UDMFParserBase::CheckBool(const char *key) +bool UDMFParserBase::CheckBool(FName key) { if (sc.TokenType == TK_True) return true; if (sc.TokenType == TK_False) return false; - sc.ScriptMessage("Boolean value expected for key '%s'", key); + sc.ScriptMessage("Boolean value expected for key '%s'", key.GetChars()); return false; } -const char *UDMFParserBase::CheckString(const char *key) +const char *UDMFParserBase::CheckString(FName key) { if (sc.TokenType != TK_StringConst) { - sc.ScriptMessage("String value expected for key '%s'", key); + sc.ScriptMessage("String value expected for key '%s'", key.GetChars()); } - return parsedString; + return parsedString.GetChars(); +} + +int UDMFParserBase::MatchString(FName key, const char* const* strings, int defval) +{ + const char* string = CheckString(key); + for (int i = 0; *strings != nullptr; i++, strings++) + { + if (!stricmp(string, *strings)) + { + return i; + } + } + sc.ScriptMessage("Unknown value %s for key '%s'", string, key.GetChars()); + return defval; } //=========================================================================== @@ -291,7 +329,7 @@ static int udmfcmp(const void *a, const void *b) FUDMFKey *A = (FUDMFKey*)a; FUDMFKey *B = (FUDMFKey*)b; - return int(A->Key) - int(B->Key); + return int(A->Key.GetIndex()) - int(B->Key.GetIndex()); } void FUDMFKeys::Sort() @@ -392,10 +430,10 @@ FString GetUDMFString(FLevelLocals *Level, int type, int index, FName key) struct UDMFScroll { - bool ceiling; + int where; int index; double x, y; - FName type; + int scrolltype; }; class UDMFParser : public UDMFParserBase @@ -411,7 +449,9 @@ class UDMFParser : public UDMFParserBase TArray ParsedSideTextures; TArray ParsedSectors; TArray ParsedVertices; - TArray UDMFScrollers; + TArray UDMFSectorScrollers; + TArray UDMFWallScrollers; + TArray UDMFThrusters; FDynamicColormap *fogMap = nullptr, *normMap = nullptr; FMissingTextureTracker &missingTex; @@ -482,7 +522,7 @@ class UDMFParser : public UDMFParserBase while (!sc.CheckToken('}')) { FName key = ParseKey(); - switch(key) + switch(key.GetIndex()) { case NAME_Id: th->thingid = CheckInt(key); @@ -530,7 +570,7 @@ class UDMFParser : public UDMFParserBase case NAME_Arg3: case NAME_Arg4: CHECK_N(Hx | Zd | Zdt | Va) - th->args[int(key)-int(NAME_Arg0)] = CheckInt(key); + th->args[key.GetIndex() - int(NAME_Arg0)] = CheckInt(key); break; case NAME_Arg0Str: @@ -560,8 +600,8 @@ class UDMFParser : public UDMFParserBase case NAME_Skill14: case NAME_Skill15: case NAME_Skill16: - if (CheckBool(key)) th->SkillFilter |= (1<<(int(key)-NAME_Skill1)); - else th->SkillFilter &= ~(1<<(int(key)-NAME_Skill1)); + if (CheckBool(key)) th->SkillFilter |= (1<<(key.GetIndex()-NAME_Skill1)); + else th->SkillFilter &= ~(1<<(key.GetIndex()-NAME_Skill1)); break; case NAME_Class1: @@ -581,8 +621,8 @@ class UDMFParser : public UDMFParserBase case NAME_Class15: case NAME_Class16: CHECK_N(Hx | Zd | Zdt | Va) - if (CheckBool(key)) th->ClassFilter |= (1<<(int(key)-NAME_Class1)); - else th->ClassFilter &= ~(1<<(int(key)-NAME_Class1)); + if (CheckBool(key)) th->ClassFilter |= (1<<(key.GetIndex()-NAME_Class1)); + else th->ClassFilter &= ~(1<<(key.GetIndex()-NAME_Class1)); break; case NAME_Ambush: @@ -636,6 +676,11 @@ class UDMFParser : public UDMFParserBase Flag(th->flags, MTF_SECRET, key); break; + case NAME_NoCount: + CHECK_N(Zd | Zdt) + Flag(th->flags, MTF_NOCOUNT, key); + break; + case NAME_Floatbobphase: CHECK_N(Zd | Zdt) th->FloatbobPhase = CheckInt(key); @@ -644,7 +689,7 @@ class UDMFParser : public UDMFParserBase case NAME_Renderstyle: { FName style = CheckString(key); - switch (style) + switch (style.GetIndex()) { case NAME_None: th->RenderStyle = STYLE_None; @@ -730,15 +775,15 @@ class UDMFParser : public UDMFParserBase break; case NAME_ScaleX: - th->Scale.X = CheckFloat(key); + th->Scale.X = (float)CheckFloat(key); break; case NAME_ScaleY: - th->Scale.Y = CheckFloat(key); + th->Scale.Y = (float)CheckFloat(key); break; case NAME_Scale: - th->Scale.X = th->Scale.Y = CheckFloat(key); + th->Scale.X = th->Scale.Y = (float)CheckFloat(key); break; case NAME_FriendlySeeBlocks: @@ -746,6 +791,11 @@ class UDMFParser : public UDMFParserBase th->friendlyseeblocks = CheckInt(key); break; + case NAME_lm_suncolor: + case NAME_lm_sampledist: + CHECK_N(Zd | Zdt) + break; + default: CHECK_N(Zd | Zdt) if (0 == strnicmp("user_", key.GetChars(), 5)) @@ -755,16 +805,20 @@ class UDMFParser : public UDMFParserBase ReadUserKey(ukey); loader->MapThingsUserData.Push(ukey); } + else if (stricmp("comment", key.GetChars())) + { + DPrintf(DMSG_WARNING, "Unknown UDMF thing key %s\n", key.GetChars()); + } break; } } if (arg0str.IsNotEmpty() && (P_IsACSSpecial(th->special) || th->special == 0)) { - th->args[0] = -FName(arg0str); + th->args[0] = -FName(arg0str).GetIndex(); } if (arg1str.IsNotEmpty() && (P_IsThingSpecial(th->special) || th->special == 0)) { - th->args[1] = -FName(arg1str); + th->args[1] = -FName(arg1str).GetIndex(); } // Thing specials are only valid in namespaces with Hexen-type specials // and in ZDoomTranslated - which will use the translator on them. @@ -821,7 +875,7 @@ class UDMFParser : public UDMFParserBase FName key = ParseKey(); // This switch contains all keys of the UDMF base spec - switch(key) + switch(key.GetIndex()) { case NAME_V1: ld->v1 = (vertex_t*)(intptr_t)CheckInt(key); // must be relocated later @@ -859,7 +913,7 @@ class UDMFParser : public UDMFParserBase case NAME_Arg2: case NAME_Arg3: case NAME_Arg4: - ld->args[int(key)-int(NAME_Arg0)] = CheckInt(key); + ld->args[key.GetIndex()-int(NAME_Arg0)] = CheckInt(key); continue; case NAME_Arg0Str: @@ -918,6 +972,12 @@ class UDMFParser : public UDMFParserBase Flag(ld->flags, ML_BLOCK_FLOATERS, key); continue; + case NAME_Blocklandmonsters: + // This is from MBF21 so it may later be needed for a lower level namespace. + CHECK_N(St | Zd | Zdt | Va) + Flag(ld->flags2, ML2_BLOCKLANDMONSTERS, key); + continue; + case NAME_Translucent: CHECK_N(St | Zd | Zdt | Va) strifetrans = CheckBool(key); @@ -934,11 +994,13 @@ class UDMFParser : public UDMFParserBase continue; default: + if (!stricmp("comment", key.GetChars())) + continue; break; } // This switch contains all keys of the UDMF base spec which only apply to Hexen format specials - if (!isTranslated) switch (key) + if (!isTranslated) switch (key.GetIndex()) { case NAME_Playercross: Flag(ld->activation, SPAC_Cross, key); @@ -985,7 +1047,7 @@ class UDMFParser : public UDMFParserBase } // This switch contains all keys which are ZDoom specific - if (namespace_bits & (Zd|Zdt|Va)) switch(key) + if (namespace_bits & (Zd|Zdt|Va)) switch(key.GetIndex()) { case NAME_Alpha: ld->setAlpha(CheckFloat(key)); @@ -1104,7 +1166,16 @@ class UDMFParser : public UDMFParserBase ld->healthgroup = CheckInt(key); break; + case NAME_lm_sampledist: + case NAME_lm_sampledist_top: + case NAME_lm_sampledist_mid: + case NAME_lm_sampledist_bot: + CHECK_N(Zd | Zdt) + break; + default: + if (strnicmp("user_", key.GetChars(), 5)) + DPrintf(DMSG_WARNING, "Unknown UDMF linedef key %s\n", key.GetChars()); break; } @@ -1156,11 +1227,11 @@ class UDMFParser : public UDMFParserBase } if (arg0str.IsNotEmpty() && (P_IsACSSpecial(ld->special) || ld->special == 0)) { - ld->args[0] = -FName(arg0str); + ld->args[0] = -FName(arg0str).GetIndex(); } if (arg1str.IsNotEmpty() && (P_IsThingSpecial(ld->special) || ld->special == 0)) { - ld->args[1] = -FName(arg1str); + ld->args[1] = -FName(arg1str).GetIndex(); } if ((ld->flags & ML_3DMIDTEX_IMPASS) && !(ld->flags & ML_3DMIDTEX)) // [TP] { @@ -1177,6 +1248,7 @@ class UDMFParser : public UDMFParserBase void ParseSidedef(side_t *sd, intmapsidedef_t *sdt, int index) { double texOfs[2]={0,0}; + DVector2 scrolls[4] = {}; memset(sd, 0, sizeof(*sd)); sdt->bottomtexture = "-"; @@ -1190,7 +1262,7 @@ class UDMFParser : public UDMFParserBase while (!sc.CheckToken('}')) { FName key = ParseKey(); - switch(key) + switch(key.GetIndex()) { case NAME_Offsetx: @@ -1218,10 +1290,12 @@ class UDMFParser : public UDMFParserBase continue; default: + if (!stricmp("comment", key.GetChars())) + continue; break; } - if (namespace_bits & (Zd|Zdt|Va)) switch(key) + if (namespace_bits & (Zd|Zdt|Va)) switch(key.GetIndex()) { case NAME_offsetx_top: sd->SetTextureXOffset(side_t::top, CheckFloat(key)); @@ -1279,6 +1353,30 @@ class UDMFParser : public UDMFParserBase Flag(sd->Flags, WALLF_ABSLIGHTING, key); continue; + case NAME_light_top: + sd->SetLight(CheckInt(key), side_t::top); + continue; + + case NAME_lightabsolute_top: + Flag(sd->Flags, WALLF_ABSLIGHTING_TOP, key); + continue; + + case NAME_light_mid: + sd->SetLight(CheckInt(key), side_t::mid); + continue; + + case NAME_lightabsolute_mid: + Flag(sd->Flags, WALLF_ABSLIGHTING_MID, key); + continue; + + case NAME_light_bottom: + sd->SetLight(CheckInt(key), side_t::bottom); + continue; + + case NAME_lightabsolute_bottom: + Flag(sd->Flags, WALLF_ABSLIGHTING_BOTTOM, key); + continue; + case NAME_lightfog: Flag(sd->Flags, WALLF_LIGHT_FOG, key); continue; @@ -1404,19 +1502,86 @@ class UDMFParser : public UDMFParserBase break; case NAME_useowncoloradd_top: - Flag(sd->textures[side_t::top].flags, side_t::part::UseOwnAdditiveColor, key); - sd->Flags |= WALLF_EXTCOLOR; + if (Flag(sd->textures[side_t::top].flags, side_t::part::UseOwnAdditiveColor, key)) + sd->Flags |= WALLF_EXTCOLOR; + break; case NAME_useowncoloradd_mid: if (Flag(sd->textures[side_t::mid].flags, side_t::part::UseOwnAdditiveColor, key)) sd->Flags |= WALLF_EXTCOLOR; + break; case NAME_useowncoloradd_bottom: if (Flag(sd->textures[side_t::bottom].flags, side_t::part::UseOwnAdditiveColor, key)) sd->Flags |= WALLF_EXTCOLOR; break; + case NAME_lm_sampledist: + case NAME_lm_sampledist_top: + case NAME_lm_sampledist_mid: + case NAME_lm_sampledist_bot: + CHECK_N(Zd | Zdt) + break; + +#if 0 // specs are to rough and too vague - needs to be cleared first how this works. + case NAME_skew_top_type: + CHECK_N(Zd | Zdt) + sd->textures[side_t::top].skew = MatchString(key, udmfsolidskewtypes, 0); + break; + + case NAME_skew_middle_type: + CHECK_N(Zd | Zdt) + sd->textures[side_t::mid].skew = MatchString(key, udmfmaskedskewtypes, 0); + break; + + case NAME_skew_bottom_type: + CHECK_N(Zd | Zdt) + sd->textures[side_t::bottom].skew = MatchString(key, udmfsolidskewtypes, 0); + break; +#endif + + case NAME_skew_top: + CHECK_N(Zd | Zdt) + sd->textures[side_t::top].skew = CheckInt(key); + break; + + case NAME_skew_middle: + CHECK_N(Zd | Zdt) + sd->textures[side_t::mid].skew = CheckInt(key); + break; + + case NAME_skew_bottom: + CHECK_N(Zd | Zdt) + sd->textures[side_t::bottom].skew = CheckInt(key); + break; + + case NAME_xscroll: + scrolls[0].X = CheckFloat(key); + break; + case NAME_yscroll: + scrolls[0].Y = CheckFloat(key); + break; + case NAME_xscrolltop: + scrolls[1].X = CheckFloat(key); + break; + case NAME_yscrolltop: + scrolls[1].Y = CheckFloat(key); + break; + case NAME_xscrollmid: + scrolls[2].X = CheckFloat(key); + break; + case NAME_yscrollmid: + scrolls[2].Y = CheckFloat(key); + break; + case NAME_xscrollbottom: + scrolls[3].X = CheckFloat(key); + break; + case NAME_yscrollbottom: + scrolls[3].Y = CheckFloat(key); + break; default: + if (strnicmp("user_", key.GetChars(), 5)) + DPrintf(DMSG_WARNING, "Unknown UDMF sidedef key %s\n", key.GetChars()); break; } @@ -1432,6 +1597,21 @@ class UDMFParser : public UDMFParserBase sd->AddTextureYOffset(side_t::top, texOfs[1]); sd->AddTextureYOffset(side_t::mid, texOfs[1]); sd->AddTextureYOffset(side_t::bottom, texOfs[1]); + int scroll = scw_all; + for (int i = 1; i < 4; i++) + { + auto& scrl = scrolls[i]; + if (!scrl.isZero()) + { + int where = 1 << (i - 1); + scroll &= ~where; + UDMFWallScrollers.Push({ where, index, scrl.X, scrl.Y, 0 }); + } + } + if (!scrolls[0].isZero() && scroll) + { + UDMFWallScrollers.Push({ scroll, index, scrolls[0].X, scrolls[0].Y, 0}); + } } //=========================================================================== @@ -1453,11 +1633,19 @@ class UDMFParser : public UDMFParserBase // Brand new UDMF scroller properties double scroll_ceil_x = 0; double scroll_ceil_y = 0; - FName scroll_ceil_type = NAME_None; + int scroll_ceil_type = 0; double scroll_floor_x = 0; double scroll_floor_y = 0; - FName scroll_floor_type = NAME_None; + int scroll_floor_type = 0; + + double friction = -FLT_MAX, movefactor = -FLT_MAX; + + DVector2 thrust = { 0,0 }; + int thrustgroup = 0; + int thrustlocation = 0; + + const double scrollfactor = 1 / 3.2; // I hope this is correct, it's just a guess taken from Eternity's code. memset(sec, 0, sizeof(*sec)); sec->Level = Level; @@ -1496,7 +1684,7 @@ class UDMFParser : public UDMFParserBase while (!sc.CheckToken('}')) { FName key = ParseKey(); - switch(key) + switch(key.GetIndex()) { case NAME_Heightfloor: sec->SetPlaneTexZ(sector_t::floor, CheckCoordinate(key)); @@ -1533,10 +1721,12 @@ class UDMFParser : public UDMFParserBase continue; default: + if (!stricmp("comment", key.GetChars())) + continue; break; } - if (namespace_bits & (Zd|Zdt|Va)) switch(key) + if (namespace_bits & (Zd|Zdt|Va)) switch(key.GetIndex()) { case NAME_Xpanningfloor: sec->SetXOffset(sector_t::floor, CheckFloat(key)); @@ -1869,30 +2059,110 @@ class UDMFParser : public UDMFParserBase break; case NAME_scroll_ceil_x: + scroll_ceil_x = CheckFloat(key) * scrollfactor; + break; + + case NAME_xscrollceiling: scroll_ceil_x = CheckFloat(key); break; case NAME_scroll_ceil_y: + scroll_ceil_y = CheckFloat(key) * scrollfactor; + break; + + case NAME_yscrollceiling: scroll_ceil_y = CheckFloat(key); break; + case NAME_scrollceilingmode: + scroll_ceil_type = CheckInt(key); + break; + case NAME_scroll_ceil_type: - scroll_ceil_type = CheckString(key); + { + const char* val = CheckString(key); + if (!stricmp(val, "both")) scroll_ceil_type = SCROLL_All; + else if (!stricmp(val, "visual")) scroll_ceil_type = SCROLL_Textures; + if (!stricmp(val, "physical")) scroll_ceil_type = SCROLL_All & ~SCROLL_Textures; + else scroll_ceil_type = 0; break; + } case NAME_scroll_floor_x: + scroll_floor_x = CheckFloat(key) * scrollfactor; + break; + + case NAME_xscrollfloor: scroll_floor_x = CheckFloat(key); break; case NAME_scroll_floor_y: + scroll_floor_y = CheckFloat(key) * scrollfactor; + break; + + case NAME_yscrollfloor: scroll_floor_y = CheckFloat(key); break; + case NAME_scrollfloormode: + scroll_floor_type = CheckInt(key); + break; + case NAME_scroll_floor_type: - scroll_floor_type = CheckString(key); + { + const char* val = CheckString(key); + if (!stricmp(val, "both")) scroll_floor_type = SCROLL_All; + else if (!stricmp(val, "visual")) scroll_floor_type = SCROLL_Textures; + if (!stricmp(val, "physical")) scroll_floor_type = SCROLL_All & ~SCROLL_Textures; + else scroll_floor_type = 0; + break; + } + + case NAME_colormap: + sec->selfmap = R_ColormapNumForName(CheckString(key)); + break; + + case NAME_frictionfactor: + friction = CheckFloat(key); + break; + + case NAME_movefactor: + movefactor = CheckFloat(key); break; - // These two are used by Eternity for something I do not understand. + case NAME_skyfloor: + sec->planes[sector_t::floor].skytexture[0] = TexMan.CheckForTexture(CheckString(key), ETextureType::Wall, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); + break; + + case NAME_skyfloor2: + sec->planes[sector_t::floor].skytexture[1] = TexMan.CheckForTexture(CheckString(key), ETextureType::Wall, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); + break; + + case NAME_skyceiling: + sec->planes[sector_t::ceiling].skytexture[0] = TexMan.CheckForTexture(CheckString(key), ETextureType::Wall, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); + break; + + case NAME_skyceiling2: + sec->planes[sector_t::ceiling].skytexture[1] = TexMan.CheckForTexture(CheckString(key), ETextureType::Wall, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); + break; + + case NAME_xthrust: + thrust.X = CheckFloat(key); + break; + + case NAME_ythrust: + thrust.Y = CheckFloat(key); + break; + + case NAME_thrustgroup: + thrustgroup = CheckInt(key); + break; + + case NAME_thrustlocation: + thrustlocation = CheckInt(key); + break; + + // These two are used by Eternity for something I do not understand. //case NAME_portal_ceil_useglobaltex: //case NAME_portal_floor_useglobaltex: @@ -1919,8 +2189,15 @@ class UDMFParser : public UDMFParserBase case NAME_Health3DGroup: sec->health3dgroup = CheckInt(key); break; - + + case NAME_lm_sampledist_floor: + case NAME_lm_sampledist_ceiling: + CHECK_N(Zd | Zdt) + break; + default: + if (strnicmp("user_", key.GetChars(), 5)) + DPrintf(DMSG_WARNING, "Unknown UDMF sector key %s\n", key.GetChars()); break; } if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5)) @@ -1950,14 +2227,18 @@ class UDMFParser : public UDMFParserBase sec->Flags &= ~SECF_DAMAGEFLAGS; } - // Cannot be initialized yet because they need the final sector array. + // These cannot be initialized yet because they need the final sector array. if (scroll_ceil_type != NAME_None) { - UDMFScrollers.Push({ true, index, scroll_ceil_x, scroll_ceil_y, scroll_ceil_type }); + UDMFSectorScrollers.Push({ true, index, scroll_ceil_x, scroll_ceil_y, scroll_ceil_type }); } if (scroll_floor_type != NAME_None) { - UDMFScrollers.Push({ false, index, scroll_floor_x, scroll_floor_y, scroll_floor_type }); + UDMFSectorScrollers.Push({ false, index, scroll_floor_x, scroll_floor_y, scroll_floor_type }); + } + if (!thrust.isZero()) + { + UDMFThrusters.Push({ thrustlocation, index, thrust.X, thrust.Y, thrustgroup }); } @@ -1981,6 +2262,7 @@ class UDMFParser : public UDMFParserBase DVector3 n = DVector3(cp[0], cp[1], cp[2]).Unit(); sec->ceilingplane.set(n.X, n.Y, n.Z, cp[3]); } + sec->CheckOverlap(); if (lightcolor == ~0u && fadecolor == ~0u && desaturation == -1 && fogdensity == -1) { @@ -2010,6 +2292,16 @@ class UDMFParser : public UDMFParserBase sec->Colormap.Desaturation = clamp(desaturation, 0, 255); sec->Colormap.FogDensity = clamp(fogdensity, 0, 512) / 2; } + if (friction > -FLT_MAX) + { + sec->friction = clamp(friction, 0., 1.); + sec->movefactor = FrictionToMoveFactor(sec->friction); + sec->Flags |= SECF_FRICTION; + } + if (movefactor > -FLT_MAX) + { + sec->movefactor = max(movefactor, 1 / 2048.); + } } //=========================================================================== @@ -2028,7 +2320,7 @@ class UDMFParser : public UDMFParserBase while (!sc.CheckToken('}')) { FName key = ParseKey(); - switch (key) + switch (key.GetIndex()) { case NAME_X: x = CheckCoordinate(key); @@ -2061,7 +2353,7 @@ class UDMFParser : public UDMFParserBase // //=========================================================================== - void ProcessLineDefs() + void ProcessLineDefs(TArray>& siderefs) { int sidecount = 0; for(unsigned i = 0, skipped = 0; i < ParsedLines.Size();) @@ -2096,6 +2388,7 @@ class UDMFParser : public UDMFParserBase } } unsigned numlines = ParsedLines.Size(); + siderefs.Resize(ParsedSides.Size()); Level->sides.Alloc(sidecount); Level->lines.Alloc(numlines); int line, side; @@ -2115,11 +2408,25 @@ class UDMFParser : public UDMFParserBase int mapside = int(intptr_t(lines[line].sidedef[sd]))-1; if (mapside < sidecount) { + siderefs[mapside].Push(side); sides[side] = ParsedSides[mapside]; sides[side].linedef = &lines[line]; sides[side].sector = &Level->sectors[intptr_t(sides[side].sector)]; lines[line].sidedef[sd] = &sides[side]; +#if 0 + if (sd == 1) + { + // fix flags for backside. The definition is linedef relative, not sidedef relative. + static const uint8_t swaps[] = { 0, side_t::skew_back, side_t::skew_front }; + static const uint8_t swapsm[] = {0, side_t::skew_back_floor, side_t::skew_back_ceiling, side_t::skew_front_floor, side_t::skew_front_ceiling}; + + sides[side].textures[side_t::top].skew = swaps[sides[side].textures[side_t::top].skew]; + sides[side].textures[side_t::bottom].skew = swaps[sides[side].textures[side_t::bottom].skew]; + sides[side].textures[side_t::mid].skew = swapsm[sides[side].textures[side_t::mid].skew]; + } +#endif + loader->ProcessSideTextures(!isExtended, &sides[side], sides[side].sector, &ParsedSideTextures[mapside], lines[line].special, lines[line].args[0], &tempalpha[sd], missingTex); @@ -2161,16 +2468,18 @@ class UDMFParser : public UDMFParserBase isExtended = false; floordrop = false; - sc.OpenMem(Wads.GetLumpFullName(map->lumpnum), map->Read(ML_TEXTMAP)); + sc.OpenMem(fileSystem.GetFileFullName(map->lumpnum), map->Read(ML_TEXTMAP)); sc.SetCMode(true); if (sc.CheckString("namespace")) { sc.MustGetStringName("="); sc.MustGetString(); namespc = sc.String; - switch(namespc) + switch(namespc.GetIndex()) { + case NAME_Dsda: case NAME_ZDoom: + case NAME_Eternity: namespace_bits = Zd; isTranslated = false; break; @@ -2302,28 +2611,39 @@ class UDMFParser : public UDMFParserBase // Create the real sectors Level->sectors.Alloc(ParsedSectors.Size()); memcpy(&Level->sectors[0], &ParsedSectors[0], Level->sectors.Size() * sizeof(sector_t)); - Level->sectors[0].e = new extsector_t[Level->sectors.Size()]; + Level->extsectors.Alloc(Level->sectors.Size()); for(unsigned i = 0; i < Level->sectors.Size(); i++) { - Level->sectors[i].e = &Level->sectors[0].e[i]; + Level->sectors[i].e = &Level->extsectors[i]; } + + // Create the real linedefs and decompress the sidedefs. Must be done before + TArray> siderefs; + ProcessLineDefs(siderefs); + // Now create the scrollers. - for (auto &scroll : UDMFScrollers) + for (auto &scroll : UDMFSectorScrollers) { - const double scrollfactor = 1 / 3.2; // I hope this is correct, it's just a guess taken from Eternity's code. - if (scroll.type == NAME_Both || scroll.type == NAME_Visual) + if (scroll.scrolltype & SCROLL_Textures) { - loader->CreateScroller(scroll.ceiling ? EScroll::sc_ceiling : EScroll::sc_floor, scroll.x * scrollfactor, scroll.y * scrollfactor, &Level->sectors[scroll.index], 0); + loader->CreateScroller(scroll.where == 1 ? EScroll::sc_ceiling : EScroll::sc_floor, -scroll.x, scroll.y, &Level->sectors[scroll.index], nullptr, 0); } - if (scroll.type == NAME_Both || scroll.type == NAME_Physical) + if (scroll.scrolltype & (SCROLL_StaticObjects | SCROLL_Players | SCROLL_Monsters)) { - // sc_carry_ceiling doesn't do anything yet. - loader->CreateScroller(scroll.ceiling ? EScroll::sc_carry_ceiling : EScroll::sc_carry, scroll.x * scrollfactor, scroll.y * scrollfactor, &Level->sectors[scroll.index], 0); + loader->CreateScroller(scroll.where == 1 ? EScroll::sc_carry_ceiling : EScroll::sc_carry, scroll.x, scroll.y, &Level->sectors[scroll.index], nullptr, 0, scw_all, scroll.scrolltype); } } - - // Create the real linedefs and decompress the sidedefs - ProcessLineDefs(); + for (auto& scroll : UDMFWallScrollers) + { + for(auto sd : siderefs[scroll.index]) + { + loader->CreateScroller(EScroll::sc_side, scroll.x, scroll.y, nullptr, &Level->sides[sd], 0); + } + } + for (auto& scroll : UDMFThrusters) + { + Level->CreateThinker(&Level->sectors[scroll.index], scroll.x, scroll.y, scroll.scrolltype, scroll.where); + } } }; diff --git a/src/maploader/udmf.h b/src/maploader/udmf.h index a6f402bf1fb..38d904288b9 100644 --- a/src/maploader/udmf.h +++ b/src/maploader/udmf.h @@ -15,15 +15,16 @@ class UDMFParserBase void Skip(); FName ParseKey(bool checkblock = false, bool *isblock = NULL); - int CheckInt(const char *key); - double CheckFloat(const char *key); - double CheckCoordinate(const char *key); - DAngle CheckAngle(const char *key); - bool CheckBool(const char *key); - const char *CheckString(const char *key); + int CheckInt(FName key); + double CheckFloat(FName key); + double CheckCoordinate(FName key); + DAngle CheckAngle(FName key); + bool CheckBool(FName key); + const char *CheckString(FName key); + int MatchString(FName key, const char* const* strings, int defval); template - bool Flag(T &value, int mask, const char *key) + bool Flag(T &value, int mask, FName key) { if (CheckBool(key)) { diff --git a/src/maploader/usdf.cpp b/src/maploader/usdf.cpp index 6d398ce337c..ed8bc4cfef3 100644 --- a/src/maploader/usdf.cpp +++ b/src/maploader/usdf.cpp @@ -36,10 +36,10 @@ #include "p_lnspec.h" #include "p_conversation.h" #include "udmf.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "actor.h" #include "a_pickups.h" -#include "w_wad.h" +#include "filesystem.h" #include "g_levellocals.h" #include "maploader.h" @@ -57,7 +57,7 @@ class USDFParser : public UDMFParserBase // //=========================================================================== - PClassActor *CheckActorType(const char *key) + PClassActor *CheckActorType(FName key) { PClassActor *type = nullptr; if (namespace_bits == St) @@ -69,7 +69,7 @@ class USDFParser : public UDMFParserBase PClassActor *cls = PClass::FindActor(CheckString(key)); if (cls == nullptr) { - sc.ScriptMessage("Unknown actor class '%s'", key); + sc.ScriptMessage("Unknown actor class '%s'", key.GetChars()); return nullptr; } type = cls; @@ -77,7 +77,7 @@ class USDFParser : public UDMFParserBase return type; } - PClassActor *CheckInventoryActorType(const char *key) + PClassActor *CheckInventoryActorType(FName key) { PClassActor* const type = CheckActorType(key); return nullptr != type && type->IsDescendantOf(NAME_Inventory) ? type : nullptr; @@ -98,7 +98,7 @@ class USDFParser : public UDMFParserBase while (!sc.CheckToken('}')) { FName key = ParseKey(); - switch(key) + switch(key.GetIndex()) { case NAME_Item: check.Item = CheckInventoryActorType(key); @@ -110,7 +110,7 @@ class USDFParser : public UDMFParserBase } } - switch (type) + switch (type.GetIndex()) { case NAME_Cost: response->ItemCheck.Push(check); break; case NAME_Require: response->ItemCheckRequire.Push(check); break; @@ -147,7 +147,7 @@ class USDFParser : public UDMFParserBase FName key = ParseKey(true, &block); if (!block) { - switch(key) + switch(key.GetIndex()) { case NAME_Text: ReplyString = CheckString(key); @@ -216,7 +216,7 @@ class USDFParser : public UDMFParserBase case NAME_Arg2: case NAME_Arg3: case NAME_Arg4: - reply->Args[int(key)-int(NAME_Arg0)] = CheckInt(key); + reply->Args[key.GetIndex()-int(NAME_Arg0)] = CheckInt(key); break; @@ -224,7 +224,7 @@ class USDFParser : public UDMFParserBase } else { - switch(key) + switch(key.GetIndex()) { case NAME_Cost: case NAME_Require: @@ -288,14 +288,13 @@ class USDFParser : public UDMFParserBase while (!sc.CheckToken('}')) { FName key = ParseKey(); - switch(key) + switch(key.GetIndex()) { case NAME_Item: check.Item = CheckInventoryActorType(key); break; - case NAME_Count: - // Not yet implemented in the engine. Todo later + case NAME_Amount: check.Amount = CheckInt(key); break; } @@ -329,7 +328,7 @@ class USDFParser : public UDMFParserBase FName key = ParseKey(true, &block); if (!block) { - switch(key) + switch(key.GetIndex()) { case NAME_Pagename: if (namespace_bits != Gz) @@ -360,10 +359,10 @@ class USDFParser : public UDMFParserBase { FString soundname = "svox/"; soundname += name; - node->SpeakerVoice = FSoundID(S_FindSound(soundname)); - if (node->SpeakerVoice == 0 && (namespace_bits & ( Zd | Gz ))) + node->SpeakerVoice = S_FindSound(soundname); + if (node->SpeakerVoice == NO_SOUND && (namespace_bits & ( Zd | Gz ))) { - node->SpeakerVoice = FSoundID(S_FindSound(name)); + node->SpeakerVoice = S_FindSound(name); } } } @@ -395,7 +394,7 @@ class USDFParser : public UDMFParserBase } else { - switch(key) + switch(key.GetIndex()) { case NAME_Ifitem: if (!ParseIfItem(node)) return false; @@ -437,7 +436,7 @@ class USDFParser : public UDMFParserBase FName key = ParseKey(true, &block); if (!block) { - switch(key) + switch(key.GetIndex()) { case NAME_Actor: type = CheckActorType(key); @@ -464,7 +463,7 @@ class USDFParser : public UDMFParserBase } else { - switch(key) + switch(key.GetIndex()) { case NAME_Page: if (!ParsePage()) return false; @@ -563,7 +562,7 @@ class USDFParser : public UDMFParserBase bool Parse(MapLoader *loader,int lumpnum, FileReader &lump, int lumplen) { Level = loader->Level; - sc.OpenMem(Wads.GetLumpFullName(lumpnum), lump.Read(lumplen)); + sc.OpenMem(fileSystem.GetFileFullName(lumpnum), lump.Read(lumplen)); sc.SetCMode(true); // Namespace must be the first field because everything else depends on it. if (sc.CheckString("namespace")) @@ -571,7 +570,7 @@ class USDFParser : public UDMFParserBase sc.MustGetToken('='); sc.MustGetToken(TK_StringConst); namespc = sc.String; - switch(namespc) + switch(namespc.GetIndex()) { case NAME_GZDoom: namespace_bits = Gz; diff --git a/src/menu/doommenu.cpp b/src/menu/doommenu.cpp new file mode 100644 index 00000000000..5718bd6b0e4 --- /dev/null +++ b/src/menu/doommenu.cpp @@ -0,0 +1,1549 @@ +/* +** menu.cpp +** Menu base class and global interface +** +**--------------------------------------------------------------------------- +** Copyright 2010 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_dispatch.h" +#include "d_gui.h" +#include "c_buttons.h" +#include "c_console.h" +#include "c_bind.h" +#include "d_eventbase.h" +#include "g_input.h" +#include "configfile.h" +#include "gstrings.h" +#include "menu.h" +#include "vm.h" +#include "v_video.h" +#include "i_system.h" +#include "types.h" +#include "texturemanager.h" +#include "v_draw.h" +#include "vm.h" +#include "gamestate.h" +#include "i_interface.h" +#include "gi.h" +#include "g_game.h" +#include "g_level.h" +#include "d_event.h" +#include "p_tick.h" +#include "startscreen.h" +#include "d_main.h" +#include "i_system.h" +#include "doommenu.h" +#include "r_utility.h" +#include "gameconfigfile.h" +#include "d_player.h" +#include "teaminfo.h" +#include "i_time.h" +#include "shiftstate.h" +#include "s_music.h" +#include "hwrenderer/scene/hw_drawinfo.h" + +EXTERN_CVAR(Int, cl_gfxlocalization) +EXTERN_CVAR(Bool, m_quickexit) +EXTERN_CVAR(Bool, saveloadconfirmation) // [mxd] +EXTERN_CVAR(Bool, quicksaverotation) +EXTERN_CVAR(Bool, show_messages) +EXTERN_CVAR(Float, hud_scalefactor) + +CVAR(Bool, m_simpleoptions, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +typedef void(*hfunc)(); +DMenu* CreateMessageBoxMenu(DMenu* parent, const char* message, int messagemode, bool playsound, FName action = NAME_None, hfunc handler = nullptr); +bool OkForLocalization(FTextureID texnum, const char* substitute); + + +FNewGameStartup NewGameStartupInfo; +int LastSkill = -1; + +void StartGameDirect(bool hasPlayerClass, bool randomPlayerClass, PClassActor * playerClass, int Episode, int Skill) +{ + // shouldn't work outside of a menu + if (DMenu::InMenu) + { + if(!netgame) + { + NewGameStartupInfo.hasPlayerClass = hasPlayerClass; + + if(hasPlayerClass) + { + if(randomPlayerClass) + { + NewGameStartupInfo.PlayerClass = "Random"; + } + else if(!playerClass) + { + NullParam("playerClass"); + } + else + { + NewGameStartupInfo.PlayerClass = playerClass->GetDisplayName(); + } + } + + NewGameStartupInfo.Episode = Episode; + NewGameStartupInfo.Skill = Skill; + + G_DeferedInitNew (&NewGameStartupInfo); + + if (gamestate == GS_FULLCONSOLE) + { + gamestate = GS_HIDECONSOLE; + gameaction = ga_newgame; + } + } + else + { + DPrintf(DMSG_WARNING, TEXTCOLOR_RED "Cannot start a new game during a netgame\n"); + } + + M_ClearMenus (); + } + else + { + ThrowAbortException(X_OTHER, "Attempt to start a new game outside of menu code"); + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(DMenu, StartGameDirect, StartGameDirect) +{ + PARAM_PROLOGUE; + PARAM_BOOL(hasPlayerClass); + PARAM_BOOL(randomPlayerClass); + PARAM_POINTER(playerClass, PClassActor); + PARAM_INT(Episode); + PARAM_INT(Skill); + StartGameDirect(hasPlayerClass, randomPlayerClass, playerClass, Episode, Skill); + return 0; +} + +bool M_SetSpecialMenu(FName& menu, int param) +{ + // some menus need some special treatment + switch (menu.GetIndex()) + { + case NAME_Mainmenu: + if (gameinfo.gametype & GAME_DoomStrifeChex) // Raven's games always used text based menus + { + if (gameinfo.forcetextinmenus) // If text is forced, this overrides any check. + { + menu = NAME_MainmenuTextOnly; + } + else if (cl_gfxlocalization != 0 && !gameinfo.forcenogfxsubstitution) + { + // For these games we must check up-front if they get localized because in that case another template must be used. + DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Mainmenu); + if (desc != nullptr) + { + if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) + { + DListMenuDescriptor *ld = static_cast(*desc); + if (ld->mFromEngine) + { + // This assumes that replacing one graphic will replace all of them. + // So this only checks the "New game" entry for localization capability. + FTextureID texid = TexMan.CheckForTexture("M_NGAME", ETextureType::MiscPatch); + if (!OkForLocalization(texid, "$MNU_NEWGAME")) + { + menu = NAME_MainmenuTextOnly; + } + } + } + } + } + } + break; + case NAME_Episodemenu: + // sent from the player class menu + NewGameStartupInfo.Skill = -1; + NewGameStartupInfo.Episode = -1; + + if(param == -1000) + { + NewGameStartupInfo.hasPlayerClass = false; + } + else + { + NewGameStartupInfo.hasPlayerClass = true; + NewGameStartupInfo.PlayerClass = (param == -1) ? FString("Random") : PlayerClasses[param].Type->GetDisplayName(); + } + + M_StartupEpisodeMenu(&NewGameStartupInfo); // needs player class name from class menu (later) + break; + + case NAME_Skillmenu: + // sent from the episode menu + + if ((gameinfo.flags & GI_SHAREWARE) && param > 0) + { + // Only Doom and Heretic have multi-episode shareware versions. + M_StartMessage(GStrings.GetString("SWSTRING"), 1); + return false; + } + + NewGameStartupInfo.Episode = param; + M_StartupSkillMenu(&NewGameStartupInfo); // needs player class name from class menu (later) + break; + + case NAME_StartgameConfirm: + { + // sent from the skill menu for a skill that needs to be confirmed + NewGameStartupInfo.Skill = param; + LastSkill = param; + + const char *msg = AllSkills[param].MustConfirmText.GetChars(); + if (*msg==0) msg = GStrings.GetString("NIGHTMARE"); + M_StartMessage (msg, 0, NAME_StartgameConfirmed); + return false; + } + + case NAME_Startgame: + // sent either from skill menu or confirmation screen. Skill gets only set if sent from skill menu + // Now we can finally start the game. Ugh... + LastSkill = param; + NewGameStartupInfo.Skill = param; + [[fallthrough]]; + case NAME_StartgameConfirmed: + + G_DeferedInitNew (&NewGameStartupInfo); + if (gamestate == GS_FULLCONSOLE) + { + gamestate = GS_HIDECONSOLE; + gameaction = ga_newgame; + } + M_ClearMenus (); + return false; + + case NAME_Savegamemenu: + if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer) || gamestate != GS_LEVEL) + { + // cannot save outside the game. + M_StartMessage (GStrings.GetString("SAVEDEAD"), 1); + return false; + } + break; + + case NAME_Quitmenu: + // The separate menu class no longer exists but the name still needs support for existing mods. + C_DoCommand("menu_quit"); + return false; + + case NAME_EndGameMenu: + // The separate menu class no longer exists but the name still needs support for existing mods. + void ActivateEndGameMenu(); + ActivateEndGameMenu(); + return false; + + case NAME_Playermenu: + menu = NAME_NewPlayerMenu; // redirect the old player menu to the new one. + break; + + case NAME_Optionsmenu: + if (m_simpleoptions) menu = NAME_OptionsmenuSimple; + break; + + case NAME_OptionsmenuFull: + menu = NAME_Optionsmenu; + break; + + case NAME_Readthismenu: + // [MK] allow us to override the ReadThisMenu class + menu = gameinfo.HelpMenuClass; + break; + } + + DMenuDescriptor** desc = MenuDescriptors.CheckKey(menu); + if (desc != nullptr) + { + if ((*desc)->mNetgameMessage.IsNotEmpty() && netgame && !demoplayback) + { + M_StartMessage((*desc)->mNetgameMessage.GetChars(), 1); + return false; + } + } + + + // End of special checks + return true; +} + +//============================================================================= +// +// +// +//============================================================================= + +void OnMenuOpen(bool makeSound) +{ + if (hud_toggled) + D_ToggleHud(); + + // intro might call this repeatedly + if (CurrentMenu != nullptr) + return; + + P_CheckTickerPaused(); + + if (makeSound) + { + S_Sound(CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE); + } +} + + +//========================================================================== +// +// M_Dim +// +// Applies a colored overlay to the entire screen, with the opacity +// determined by the dimamount cvar. +// +//========================================================================== + +CUSTOM_CVAR(Float, dimamount, -1.f, CVAR_ARCHIVE) +{ + if (self < 0.f && self != -1.f) + { + self = -1.f; + } + else if (self > 1.f) + { + self = 1.f; + } +} +CVAR(Color, dimcolor, 0xffd700, CVAR_ARCHIVE) + +void System_M_Dim() +{ + PalEntry dimmer; + float amount; + + if (dimamount >= 0) + { + dimmer = PalEntry(dimcolor); + amount = dimamount; + } + else + { + dimmer = gameinfo.dimcolor; + amount = gameinfo.dimamount; + } + + Dim(twod, dimmer, amount, 0, 0, twod->GetWidth(), twod->GetHeight()); +} + + +static void M_Quit() +{ + DeleteScreenJob(); + S_StopAllChannels(); + S_StopMusic(true); + CleanSWDrawer(); + ST_Endoom(); +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD (menu_quit) +{ // F10 + if (m_quickexit) + { + M_Quit(); + } + + M_StartControlPanel (true); + + const size_t messageindex = static_cast(gametic) % gameinfo.quitmessages.Size(); + FString EndString; + const char *msg = gameinfo.quitmessages[messageindex].GetChars(); + if (msg[0] == '$') + { + if (msg[1] == '*') + { + EndString = GStrings.GetString(msg + 2); + } + else + { + EndString.Format("%s\n\n%s", GStrings.GetString(msg + 1), GStrings.GetString("DOSY")); + } + } + else EndString = gameinfo.quitmessages[messageindex]; + + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, EndString.GetChars(), 0, false, NAME_None, []() + { + if (!netgame) + { + if (gameinfo.quitSound.IsNotEmpty()) + { + S_Sound(CHAN_VOICE, CHANF_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE); + I_WaitVBL(105); + } + } + M_Quit(); + }); + + + M_ActivateMenu(newmenu); +} + + + +//============================================================================= +// +// +// +//============================================================================= + +void ActivateEndGameMenu() +{ + FString tempstring = GStrings.GetString(netgame ? "NETEND" : "ENDGAME"); + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring.GetChars(), 0, false, NAME_None, []() + { + M_ClearMenus(); + if (!netgame) + { + if (demorecording) + G_CheckDemoStatus(); + D_StartTitle(); + } + }); + + M_ActivateMenu(newmenu); +} + +CCMD (menu_endgame) +{ // F7 + if (!usergame) + { + S_Sound (CHAN_VOICE, CHANF_UI, "menu/invalid", snd_menuvolume, ATTN_NONE); + return; + } + + //M_StartControlPanel (true); + S_Sound (CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE); + + ActivateEndGameMenu(); +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD (quicksave) +{ // F6 + if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer)) + { + S_Sound (CHAN_VOICE, CHANF_UI, "menu/invalid", snd_menuvolume, ATTN_NONE); + return; + } + + if (gamestate != GS_LEVEL) + return; + + // If the quick save rotation is enabled, it handles the save slot. + if (quicksaverotation) + { + G_DoQuickSave(); + return; + } + + if (savegameManager.quickSaveSlot == NULL || savegameManager.quickSaveSlot == (FSaveGameNode*)1) + { + S_Sound(CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE); + M_StartControlPanel(false); + M_SetMenu(NAME_Savegamemenu); + return; + } + + // [mxd]. Just save the game, no questions asked. + if (!saveloadconfirmation) + { + G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); + return; + } + + S_Sound(CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE); + + FString tempstring = GStrings.GetString("QSPROMPT"); + tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars()); + + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring.GetChars(), 0, false, NAME_None, []() + { + G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); + S_Sound(CHAN_VOICE, CHANF_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); + M_ClearMenus(); + }); + + M_ActivateMenu(newmenu); +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD (quickload) +{ // F9 + if (netgame) + { + M_StartControlPanel(true); + M_StartMessage (GStrings.GetString("QLOADNET"), 1); + return; + } + + if (savegameManager.quickSaveSlot == NULL || savegameManager.quickSaveSlot == (FSaveGameNode*)1) + { + M_StartControlPanel(true); + // signal that whatever gets loaded should be the new quicksave + savegameManager.quickSaveSlot = (FSaveGameNode *)1; + M_SetMenu(NAME_Loadgamemenu); + return; + } + + // [mxd]. Just load the game, no questions asked. + if (!saveloadconfirmation) + { + G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); + return; + } + FString tempstring = GStrings.GetString("QLPROMPT"); + tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars()); + + M_StartControlPanel(true); + + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring.GetChars(), 0, false, NAME_None, []() + { + G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); + S_Sound(CHAN_VOICE, CHANF_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); + M_ClearMenus(); + }); + M_ActivateMenu(newmenu); +} + + + + +// +// Toggle messages on/off +// +CCMD (togglemessages) +{ + if (show_messages) + { + Printf(TEXTCOLOR_RED "%s\n", GStrings.GetString("MSGOFF")); + show_messages = false; + } + else + { + show_messages = true; + Printf(TEXTCOLOR_RED "%s\n", GStrings.GetString("MSGON")); + } +} + +EXTERN_CVAR (Int, screenblocks) + +CCMD (sizedown) +{ + if (shiftState.ShiftPressed()) + { + hud_scalefactor = hud_scalefactor - 0.04f; + } + else + { + screenblocks = screenblocks - 1; + } + S_Sound (CHAN_VOICE, CHANF_UI, "menu/change", snd_menuvolume, ATTN_NONE); +} + +CCMD (sizeup) +{ + if (shiftState.ShiftPressed()) + { + hud_scalefactor = hud_scalefactor + 0.04f; + } + else + { + screenblocks = screenblocks + 1; + } + S_Sound(CHAN_VOICE, CHANF_UI, "menu/change", snd_menuvolume, ATTN_NONE); +} + +CCMD(reset2defaults) +{ + C_SetDefaultBindings (); + C_SetCVarsToDefaults (); + R_SetViewSize (screenblocks); +} + +CCMD(reset2saved) +{ + GameConfig->DoGlobalSetup (); + GameConfig->DoGameSetup (gameinfo.ConfigName.GetChars()); + GameConfig->DoModSetup (gameinfo.ConfigName.GetChars()); + R_SetViewSize (screenblocks); +} + +CCMD(resetb2defaults) +{ + C_SetDefaultBindings (); +} + + +//============================================================================= +// +// Creates the episode menu +// Falls back on an option menu if there's not enough screen space to show all episodes +// +//============================================================================= + +void M_StartupEpisodeMenu(FNewGameStartup *gs) +{ + // Build episode menu + bool success = false; + bool isOld = false; + DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Episodemenu); + if (desc != nullptr) + { + if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) + { + DListMenuDescriptor *ld = static_cast(*desc); + + // Delete previous contents + for(unsigned i=0; imItems.Size(); i++) + { + FName n = ld->mItems[i]->mAction; + if (n == NAME_Skillmenu) + { + isOld = true; + ld->mItems.Resize(i); + break; + } + } + + + int posx = (int)ld->mXpos; + int posy = (int)ld->mYpos; + int topy = posy; + + // Get lowest y coordinate of any static item in the menu + for(unsigned i = 0; i < ld->mItems.Size(); i++) + { + int y = (int)ld->mItems[i]->GetY(); + if (y < topy) topy = y; + } + + int spacing = ld->mLinespacing; + for (unsigned i = 0; i < AllEpisodes.Size(); i++) + { + if (AllEpisodes[i].mPicName.IsNotEmpty()) + { + FTextureID tex = GetMenuTexture(AllEpisodes[i].mPicName.GetChars()); + if (AllEpisodes[i].mEpisodeName.IsEmpty() || OkForLocalization(tex, AllEpisodes[i].mEpisodeName.GetChars())) + continue; + } + if ((gameinfo.gametype & GAME_DoomStrifeChex) && spacing == 16) spacing = 18; + break; + } + + // center the menu on the screen if the top space is larger than the bottom space + int totalheight = posy + AllEpisodes.Size() * spacing - topy; + + if (ld->mForceList || totalheight < 190 || AllEpisodes.Size() == 1) + { + int newtop = max(10, 200 - totalheight) / 2; + int topdelta = newtop - topy; + if (topdelta < 0) + { + for(unsigned i = 0; i < ld->mItems.Size(); i++) + { + ld->mItems[i]->OffsetPositionY(topdelta); + } + posy += topdelta; + ld->mYpos += topdelta; + } + + if (!isOld) ld->mSelectedItem = ld->mItems.Size(); + + for (unsigned i = 0; i < AllEpisodes.Size(); i++) + { + DMenuItemBase *it = nullptr; + if (AllEpisodes[i].mPicName.IsNotEmpty()) + { + FTextureID tex = GetMenuTexture(AllEpisodes[i].mPicName.GetChars()); + if (AllEpisodes[i].mEpisodeName.IsEmpty() || OkForLocalization(tex, AllEpisodes[i].mEpisodeName.GetChars())) + continue; // We do not measure patch based entries. They are assumed to fit + } + const char *c = AllEpisodes[i].mEpisodeName.GetChars(); + if (*c == '$') c = GStrings.GetString(c + 1); + int textwidth = ld->mFont->StringWidth(c); + int textright = posx + textwidth; + if (posx + textright > 320) posx = max(0, 320 - textright); + } + + for(unsigned i = 0; i < AllEpisodes.Size(); i++) + { + DMenuItemBase *it = nullptr; + if (AllEpisodes[i].mPicName.IsNotEmpty()) + { + FTextureID tex = GetMenuTexture(AllEpisodes[i].mPicName.GetChars()); + if (AllEpisodes[i].mEpisodeName.IsEmpty() || OkForLocalization(tex, AllEpisodes[i].mEpisodeName.GetChars())) + it = CreateListMenuItemPatch(posx, posy, spacing, AllEpisodes[i].mShortcut, tex, NAME_Skillmenu, i); + } + if (it == nullptr) + { + it = CreateListMenuItemText(posx, posy, spacing, AllEpisodes[i].mShortcut, + AllEpisodes[i].mEpisodeName.GetChars(), ld->mFont, ld->mFontColor, ld->mFontColor2, NAME_Skillmenu, i); + } + ld->mItems.Push(it); + posy += spacing; + } + if (AllEpisodes.Size() == 1) + { + ld->mAutoselect = ld->mSelectedItem; + } + success = true; + for (auto &p : ld->mItems) + { + GC::WriteBarrier(*desc, p); + } + } + } + else return; // do not recreate the option menu variant, because it is always text based. + } + if (!success) + { + // Couldn't create the episode menu, either because there's too many episodes or some error occured + // Create an option menu for episode selection instead. + DOptionMenuDescriptor *od = Create(); + MenuDescriptors[NAME_Episodemenu] = od; + od->mMenuName = NAME_Episodemenu; + od->mFont = gameinfo.gametype == GAME_Doom ? BigUpper : BigFont; + od->mTitle = "$MNU_EPISODE"; + od->mSelectedItem = 0; + od->mScrollPos = 0; + od->mClass = nullptr; + od->mPosition = -15; + od->mScrollTop = 0; + od->mIndent = 160; + od->mDontDim = false; + od->mDontBlur = false; + od->mAnimatedTransition = false; + od->mAnimated = false; + GC::WriteBarrier(od); + for(unsigned i = 0; i < AllEpisodes.Size(); i++) + { + auto it = CreateOptionMenuItemSubmenu(AllEpisodes[i].mEpisodeName.GetChars(), "Skillmenu", i); + od->mItems.Push(it); + GC::WriteBarrier(od, it); + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + +static void BuildPlayerclassMenu() +{ + bool success = false; + + // Build player class menu + DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Playerclassmenu); + if (desc != nullptr) + { + if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) + { + DListMenuDescriptor *ld = static_cast(*desc); + // add player display + + ld->mSelectedItem = ld->mItems.Size(); + + int posy = (int)ld->mYpos; + int topy = posy; + + // Get lowest y coordinate of any static item in the menu + for(unsigned i = 0; i < ld->mItems.Size(); i++) + { + int y = (int)ld->mItems[i]->GetY(); + if (y < topy) topy = y; + } + + // Count the number of items this menu will show + int numclassitems = 0; + for (unsigned i = 0; i < PlayerClasses.Size (); i++) + { + if (!(PlayerClasses[i].Flags & PCF_NOMENU)) + { + const char *pname = GetPrintableDisplayName(PlayerClasses[i].Type).GetChars(); + if (pname != nullptr) + { + numclassitems++; + } + } + } + + // center the menu on the screen if the top space is larger than the bottom space + int totalheight = posy + (numclassitems+1) * ld->mLinespacing - topy; + + if (numclassitems <= 1) + { + // create a dummy item that auto-chooses the default class. + auto it = CreateListMenuItemText(0, 0, 0, 'p', "player", + ld->mFont,ld->mFontColor, ld->mFontColor2, NAME_Episodemenu, -1000); + ld->mAutoselect = ld->mItems.Push(it); + success = true; + } + else if (ld->mForceList || totalheight <= 190) + { + int newtop = (max(10, 200 - totalheight) + topy) / 2; + int topdelta = newtop - topy; + if (topdelta < 0) + { + for(unsigned i = 0; i < ld->mItems.Size(); i++) + { + ld->mItems[i]->OffsetPositionY(topdelta); + } + posy -= topdelta; + } + + int n = 0; + for (unsigned i = 0; i < PlayerClasses.Size (); i++) + { + if (!(PlayerClasses[i].Flags & PCF_NOMENU)) + { + const char *pname = GetPrintableDisplayName(PlayerClasses[i].Type).GetChars(); + if (pname != nullptr) + { + auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname, + pname, ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, i); + ld->mItems.Push(it); + ld->mYpos += ld->mLinespacing; + n++; + } + } + } + if (n > 1 && !gameinfo.norandomplayerclass) + { + auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, 'r', + "$MNU_RANDOM", ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, -1); + ld->mItems.Push(it); + } + if (n == 0) + { + const char *pname = GetPrintableDisplayName(PlayerClasses[0].Type).GetChars(); + if (pname != nullptr) + { + auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname, + pname, ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, 0); + ld->mItems.Push(it); + } + } + success = true; + for (auto &p : ld->mItems) + { + GC::WriteBarrier(ld, p); + } + } + } + } + if (!success) + { + // Couldn't create the playerclass menu, either because there's too many episodes or some error occured + // Create an option menu for class selection instead. + DOptionMenuDescriptor *od = Create(); + MenuDescriptors[NAME_Playerclassmenu] = od; + od->mMenuName = NAME_Playerclassmenu; + od->mFont = gameinfo.gametype == GAME_Doom ? BigUpper : BigFont; + od->mTitle = "$MNU_CHOOSECLASS"; + od->mSelectedItem = 0; + od->mScrollPos = 0; + od->mClass = nullptr; + od->mPosition = -15; + od->mScrollTop = 0; + od->mIndent = 160; + od->mDontDim = false; + od->mDontBlur = false; + od->mAnimatedTransition = false; + od->mAnimated = false; + od->mNetgameMessage = "$NEWGAME"; + GC::WriteBarrier(od); + for (unsigned i = 0; i < PlayerClasses.Size (); i++) + { + if (!(PlayerClasses[i].Flags & PCF_NOMENU)) + { + const char *pname = GetPrintableDisplayName(PlayerClasses[i].Type).GetChars(); + if (pname != nullptr) + { + auto it = CreateOptionMenuItemSubmenu(pname, "Episodemenu", i); + od->mItems.Push(it); + GC::WriteBarrier(od, it); + } + } + } + auto it = CreateOptionMenuItemSubmenu("Random", "Episodemenu", -1); + od->mItems.Push(it); + GC::WriteBarrier(od, it); + } +} + +//============================================================================= +// +// Reads any XHAIRS lumps for the names of crosshairs and +// adds them to the display options menu. +// +//============================================================================= + +static void InitCrosshairsList() +{ + int lastlump, lump; + + lastlump = 0; + + FOptionValues **opt = OptionValues.CheckKey(NAME_Crosshairs); + if (opt == nullptr) + { + return; // no crosshair value list present. No need to go on. + } + + FOptionValues::Pair *pair = &(*opt)->mValues[(*opt)->mValues.Reserve(1)]; + pair->Value = 0; + pair->Text = "None"; + + while ((lump = fileSystem.FindLump("XHAIRS", &lastlump)) != -1) + { + FScanner sc(lump); + while (sc.GetNumber()) + { + FOptionValues::Pair value; + value.Value = sc.Number; + sc.MustGetString(); + value.Text = sc.String; + if (value.Value != 0) + { // Check if it already exists. If not, add it. + unsigned int i; + + for (i = 1; i < (*opt)->mValues.Size(); ++i) + { + if ((*opt)->mValues[i].Value == value.Value) + { + break; + } + } + if (i < (*opt)->mValues.Size()) + { + (*opt)->mValues[i].Text = value.Text; + } + else + { + (*opt)->mValues.Push(value); + } + } + } + } +} + +//============================================================================= +// +// With the current workings of the menu system this cannot be done any longer +// from within the respective CCMDs. +// +//============================================================================= + +static void InitKeySections() +{ + DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_CustomizeControls); + if (desc != nullptr) + { + if ((*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) + { + DOptionMenuDescriptor *menu = static_cast(*desc); + + for (unsigned i = 0; i < KeySections.Size(); i++) + { + FKeySection *sect = &KeySections[i]; + DMenuItemBase *item = CreateOptionMenuItemStaticText(" "); + menu->mItems.Push(item); + item = CreateOptionMenuItemStaticText(sect->mTitle.GetChars(), 1); + menu->mItems.Push(item); + for (unsigned j = 0; j < sect->mActions.Size(); j++) + { + FKeyAction *act = §->mActions[j]; + item = CreateOptionMenuItemControl(act->mTitle.GetChars(), act->mAction, &Bindings); + menu->mItems.Push(item); + } + } + for (auto &p : menu->mItems) + { + GC::WriteBarrier(*desc, p); + } + } + } +} + + +//============================================================================= +// +// Special menus will be created once all engine data is loaded +// +//============================================================================= + +void M_CreateGameMenus() +{ + BuildPlayerclassMenu(); + InitCrosshairsList(); + InitKeySections(); + + auto opt = OptionValues.CheckKey(NAME_PlayerTeam); + if (opt != nullptr) + { + auto op = *opt; + op->mValues.Resize(Teams.Size() + 1); + op->mValues[0].Value = 0; + op->mValues[0].Text = "$OPTVAL_NONE"; + for (unsigned i = 0; i < Teams.Size(); i++) + { + op->mValues[i+1].Value = i+1; + op->mValues[i+1].Text = Teams[i].GetName(); + } + } + opt = OptionValues.CheckKey(NAME_PlayerClass); + if (opt != nullptr) + { + auto op = *opt; + int o = 0; + if (!gameinfo.norandomplayerclass && PlayerClasses.Size() > 1) + { + op->mValues.Resize(PlayerClasses.Size()+1); + op->mValues[0].Value = -1; + op->mValues[0].Text = "$MNU_RANDOM"; + o = 1; + } + else op->mValues.Resize(PlayerClasses.Size()); + for (unsigned i = 0; i < PlayerClasses.Size(); i++) + { + op->mValues[i+o].Value = i; + op->mValues[i+o].Text = GetPrintableDisplayName(PlayerClasses[i].Type); + } + } +} + +DEFINE_ACTION_FUNCTION(DNewPlayerMenu, UpdateColorsets) +{ + PARAM_PROLOGUE; + PARAM_POINTER(playerClass, FPlayerClass); + + TArray PlayerColorSets; + + EnumColorSets(playerClass->Type, &PlayerColorSets); + + auto opt = OptionValues.CheckKey(NAME_PlayerColors); + if (opt != nullptr) + { + auto op = *opt; + op->mValues.Resize(PlayerColorSets.Size() + 1); + op->mValues[0].Value = -1; + op->mValues[0].Text = "$OPTVAL_CUSTOM"; + for (unsigned i = 0; i < PlayerColorSets.Size(); i++) + { + auto cset = GetColorSet(playerClass->Type, PlayerColorSets[i]); + op->mValues[i + 1].Value = PlayerColorSets[i]; + op->mValues[i + 1].Text = cset? cset->Name.GetChars() : "?"; // The null case should never happen here. + } + } + return 0; +} + +DEFINE_ACTION_FUNCTION(DNewPlayerMenu, UpdateSkinOptions) +{ + PARAM_PROLOGUE; + PARAM_POINTER(playerClass, FPlayerClass); + + auto opt = OptionValues.CheckKey(NAME_PlayerSkin); + if (opt != nullptr) + { + auto op = *opt; + + if ((GetDefaultByType(playerClass->Type)->flags4 & MF4_NOSKIN) || players[consoleplayer].userinfo.GetPlayerClassNum() == -1) + { + op->mValues.Resize(1); + op->mValues[0].Value = -1; + op->mValues[0].Text = "$OPTVAL_DEFAULT"; + } + else + { + op->mValues.Clear(); + for (unsigned i = 0; i < Skins.Size(); i++) + { + op->mValues.Reserve(1); + op->mValues.Last().Value = i; + op->mValues.Last().Text = Skins[i].Name; + } + } + } + return 0; +} + +//============================================================================= +// +// The skill menu must be refeshed each time it starts up +// +//============================================================================= +extern int restart; + +void M_StartupSkillMenu(FNewGameStartup *gs) +{ + static int done = -1; + bool success = false; + TArray MenuSkills; + TArray SkillIndices; + if (MenuSkills.Size() == 0) + { + for (unsigned ind = 0; ind < AllSkills.Size(); ind++) + { + if (!AllSkills[ind].NoMenu) + { + MenuSkills.Push(&AllSkills[ind]); + SkillIndices.Push(ind); + } + } + } + if (MenuSkills.Size() == 0) I_Error("No valid skills for menu found. At least one must be defined."); + + int defskill = LastSkill > -1? LastSkill : DefaultSkill; // use the last selected skill, if available. + if ((unsigned int)defskill >= MenuSkills.Size()) + { + defskill = SkillIndices[(MenuSkills.Size() - 1) / 2]; + } + if (AllSkills[defskill].NoMenu) + { + for (defskill = 0; defskill < (int)AllSkills.Size(); defskill++) + { + if (!AllSkills[defskill].NoMenu) break; + } + } + int defindex = 0; + for (unsigned i = 0; i < MenuSkills.Size(); i++) + { + if (MenuSkills[i] == &AllSkills[defskill]) + { + defindex = i; + break; + } + } + + DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Skillmenu); + if (desc != nullptr) + { + if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) + { + DListMenuDescriptor *ld = static_cast(*desc); + int posx = (int)ld->mXpos; + int y = (int)ld->mYpos; + + // Delete previous contents + for(unsigned i=0; imItems.Size(); i++) + { + FName n = ld->mItems[i]->mAction; + if (n == NAME_Startgame || n == NAME_StartgameConfirm) + { + ld->mItems.Resize(i); + break; + } + } + + int spacing = ld->mLinespacing; + //if (done != restart) + { + //done = restart; + ld->mSelectedItem = ld->mItems.Size() + defindex; + + int posy = y; + int topy = posy; + + // Get lowest y coordinate of any static item in the menu + for(unsigned i = 0; i < ld->mItems.Size(); i++) + { + int y = (int)ld->mItems[i]->GetY(); + if (y < topy) topy = y; + } + + for (unsigned i = 0; i < MenuSkills.Size(); i++) + { + if (MenuSkills[i]->PicName.IsNotEmpty()) + { + FTextureID tex = GetMenuTexture(MenuSkills[i]->PicName.GetChars()); + if (MenuSkills[i]->MenuName.IsEmpty() || OkForLocalization(tex, MenuSkills[i]->MenuName.GetChars())) + continue; + } + if ((gameinfo.gametype & GAME_DoomStrifeChex) && spacing == 16) spacing = 18; + break; + } + + // center the menu on the screen if the top space is larger than the bottom space + int totalheight = posy + MenuSkills.Size() * spacing - topy; + + if (ld->mForceList || totalheight < 190 || MenuSkills.Size() == 1) + { + int newtop = max(10, 200 - totalheight) / 2; + int topdelta = newtop - topy; + if (topdelta < 0) + { + for(unsigned i = 0; i < ld->mItems.Size(); i++) + { + ld->mItems[i]->OffsetPositionY(topdelta); + } + ld->mYpos = y = posy + topdelta; + } + } + else + { + // too large + desc = nullptr; + done = false; + goto fail; + } + } + + for (unsigned int i = 0; i < MenuSkills.Size(); i++) + { + FSkillInfo &skill = *MenuSkills[i]; + DMenuItemBase *li = nullptr; + + FString *pItemText = nullptr; + if (gs->hasPlayerClass) + { + pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass); + } + + if (skill.PicName.Len() != 0 && pItemText == nullptr) + { + FTextureID tex = GetMenuTexture(skill.PicName.GetChars()); + if (skill.MenuName.IsEmpty() || OkForLocalization(tex, skill.MenuName.GetChars())) + continue; + } + const char *c = pItemText ? pItemText->GetChars() : skill.MenuName.GetChars(); + if (*c == '$') c = GStrings.GetString(c + 1); + int textwidth = ld->mFont->StringWidth(c); + int textright = posx + textwidth; + if (posx + textright > 320) posx = max(0, 320 - textright); + } + + unsigned firstitem = ld->mItems.Size(); + for(unsigned int i = 0; i < MenuSkills.Size(); i++) + { + FSkillInfo &skill = *MenuSkills[i]; + DMenuItemBase *li = nullptr; + // Using a different name for skills that must be confirmed makes handling this easier. + FName action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ? + NAME_StartgameConfirm : NAME_Startgame; + FString *pItemText = nullptr; + if (gs->hasPlayerClass) + { + pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass); + } + + EColorRange color = (EColorRange)skill.GetTextColor(); + if (color == CR_UNTRANSLATED) color = ld->mFontColor; + if (skill.PicName.Len() != 0 && pItemText == nullptr) + { + FTextureID tex = GetMenuTexture(skill.PicName.GetChars()); + if (skill.MenuName.IsEmpty() || OkForLocalization(tex, skill.MenuName.GetChars())) + li = CreateListMenuItemPatch(posx, y, spacing, skill.Shortcut, tex, action, SkillIndices[i]); + } + if (li == nullptr) + { + li = CreateListMenuItemText(posx, y, spacing, skill.Shortcut, + pItemText? pItemText->GetChars() : skill.MenuName.GetChars(), ld->mFont, color, ld->mFontColor2, action, SkillIndices[i]); + } + ld->mItems.Push(li); + GC::WriteBarrier(*desc, li); + y += spacing; + } + if (AllEpisodes[gs->Episode].mNoSkill || MenuSkills.Size() == 1) + { + ld->mAutoselect = firstitem + defindex; + } + else + { + ld->mAutoselect = -1; + } + success = true; + } + } + if (success) return; +fail: + // Option menu fallback for overlong skill lists + DOptionMenuDescriptor *od; + if (desc == nullptr) + { + od = Create(); + MenuDescriptors[NAME_Skillmenu] = od; + od->mMenuName = NAME_Skillmenu; + od->mFont = gameinfo.gametype == GAME_Doom ? BigUpper : BigFont; + od->mTitle = "$MNU_CHOOSESKILL"; + od->mSelectedItem = defindex; + od->mScrollPos = 0; + od->mClass = nullptr; + od->mPosition = -15; + od->mScrollTop = 0; + od->mIndent = 160; + od->mDontDim = false; + od->mDontBlur = false; + od->mAnimatedTransition = false; + od->mAnimated = false; + GC::WriteBarrier(od); + } + else + { + od = static_cast(*desc); + od->mItems.Clear(); + } + for(unsigned int i = 0; i < MenuSkills.Size(); i++) + { + FSkillInfo &skill = *MenuSkills[i]; + DMenuItemBase *li; + // Using a different name for skills that must be confirmed makes handling this easier. + const char *action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ? + "StartgameConfirm" : "Startgame"; + + FString *pItemText = nullptr; + if (gs->hasPlayerClass) + { + pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass); + } + li = CreateOptionMenuItemSubmenu(pItemText? pItemText->GetChars() : skill.MenuName.GetChars(), action, SkillIndices[i]); + od->mItems.Push(li); + GC::WriteBarrier(od, li); + if (!done) + { + done = true; + od->mSelectedItem = defindex; + } + } +} + +//========================================================================== +// +// Defines how graphics substitution is handled. +// 0: Never replace a text-containing graphic with a font-based text. +// 1: Always replace, regardless of any missing information. Useful for testing the substitution without providing full data. +// 2: Only replace for non-default texts, i.e. if some language redefines the string's content, use it instead of the graphic. Never replace a localized graphic. +// 3: Only replace if the string is not the default and the graphic comes from the IWAD. Never replace a localized graphic. +// 4: Like 1, but lets localized graphics pass. +// +// The default is 3, which only replaces known content with non-default texts. +// +//========================================================================== + +CUSTOM_CVAR(Int, cl_gfxlocalization, 3, CVAR_ARCHIVE) +{ + if (self < 0 || self > 4) self = 0; +} + +bool OkForLocalization(FTextureID texnum, const char* substitute) +{ + if (!texnum.isValid()) return false; + + // First the unconditional settings, 0='never' and 1='always'. + if (cl_gfxlocalization == 1 || gameinfo.forcetextinmenus) return false; + if (cl_gfxlocalization == 0 || gameinfo.forcenogfxsubstitution) return true; + return TexMan.OkForLocalization(texnum, substitute, cl_gfxlocalization); +} + +bool CheckSkipGameOptionBlock(const char *str) +{ + bool filter = false; + if (!stricmp(str, "ReadThis")) filter |= gameinfo.drawreadthis; + else if (!stricmp(str, "Swapmenu")) filter |= gameinfo.swapmenu; + return filter; +} + +void SetDefaultMenuColors() +{ + OptionSettings.mTitleColor = V_FindFontColor(gameinfo.mTitleColor); + OptionSettings.mFontColor = V_FindFontColor(gameinfo.mFontColor); + OptionSettings.mFontColorValue = V_FindFontColor(gameinfo.mFontColorValue); + OptionSettings.mFontColorMore = V_FindFontColor(gameinfo.mFontColorMore); + OptionSettings.mFontColorHeader = V_FindFontColor(gameinfo.mFontColorHeader); + OptionSettings.mFontColorHighlight = V_FindFontColor(gameinfo.mFontColorHighlight); + OptionSettings.mFontColorSelection = V_FindFontColor(gameinfo.mFontColorSelection); + + auto cls = PClass::FindClass(gameinfo.HelpMenuClass); + if (!cls) + I_FatalError("%s: Undefined help menu class", gameinfo.HelpMenuClass.GetChars()); + if (!cls->IsDescendantOf(RUNTIME_CLASS(DMenu))) + I_FatalError("'%s' does not inherit from Menu", gameinfo.HelpMenuClass.GetChars()); + + cls = PClass::FindClass(gameinfo.MenuDelegateClass); + if (!cls) + I_FatalError("%s: Undefined menu delegate class", gameinfo.MenuDelegateClass.GetChars()); + if (!cls->IsDescendantOf("MenuDelegateBase")) + I_FatalError("'%s' does not inherit from MenuDelegateBase", gameinfo.MenuDelegateClass.GetChars()); + menuDelegate = cls->CreateNew(); +} + +CCMD (menu_main) +{ + if (gamestate == GS_FULLCONSOLE) gamestate = GS_MENUSCREEN; + M_StartControlPanel(true); + M_SetMenu(NAME_Mainmenu, -1); +} + +CCMD (menu_load) +{ // F3 + M_StartControlPanel (true); + M_SetMenu(NAME_Loadgamemenu, -1); +} + +CCMD (menu_save) +{ // F2 + M_StartControlPanel (true); + M_SetMenu(NAME_Savegamemenu, -1); +} + +CCMD (menu_help) +{ // F1 + M_StartControlPanel (true); + M_SetMenu(NAME_Readthismenu, -1); +} + +CCMD (menu_game) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_Playerclassmenu, -1); // The playerclass menu is the first in the 'start game' chain +} + +CCMD (menu_options) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_Optionsmenu, -1); +} + +CCMD (menu_player) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_Playermenu, -1); +} + +CCMD (menu_messages) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_MessageOptions, -1); +} + +CCMD (menu_automap) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_AutomapOptions, -1); +} + +CCMD (menu_scoreboard) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_ScoreboardOptions, -1); +} + +CCMD (menu_mapcolors) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_MapColorMenu, -1); +} + +CCMD (menu_keys) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_CustomizeControls, -1); +} + +CCMD (menu_gameplay) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_GameplayOptions, -1); +} + +CCMD (menu_compatibility) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_CompatibilityOptions, -1); +} + +CCMD (menu_mouse) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_MouseOptions, -1); +} + +CCMD (menu_joystick) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_JoystickOptions, -1); +} + +CCMD (menu_sound) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_SoundOptions, -1); +} + +CCMD (menu_advsound) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_AdvSoundOptions, -1); +} + +CCMD (menu_modreplayer) +{ + M_StartControlPanel(true); + M_SetMenu(NAME_ModReplayerOptions, -1); +} + +CCMD (menu_display) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_VideoOptions, -1); +} + +CCMD (menu_video) +{ + M_StartControlPanel (true); + M_SetMenu(NAME_VideoModeMenu, -1); +} diff --git a/src/menu/doommenu.h b/src/menu/doommenu.h new file mode 100644 index 00000000000..3e9b5a75aaa --- /dev/null +++ b/src/menu/doommenu.h @@ -0,0 +1,30 @@ +#pragma once +#include "menu.h" +#include "savegamemanager.h" + +struct FNewGameStartup +{ + bool hasPlayerClass; + FString PlayerClass; + int Episode; + int Skill; +}; + +extern FNewGameStartup NewGameStartupInfo; +void M_StartupEpisodeMenu(FNewGameStartup *gs); +void M_StartupSkillMenu(FNewGameStartup *gs); +void M_CreateGameMenus(); +void SetDefaultMenuColors(); +void OnMenuOpen(bool makeSound); + +class FSavegameManager : public FSavegameManagerBase +{ + void PerformSaveGame(const char *fn, const char *sgdesc) override; + void PerformLoadGame(const char *fn, bool) override; + FString ExtractSaveComment(FSerializer &arc) override; + FString BuildSaveName(const char* prefix, int slot) override; + void ReadSaveStrings() override; +}; + +extern FSavegameManager savegameManager; + diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 9c79906e95a..331575737e6 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -4,7 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2001-2010 Randy Heit -** Copyright 2010-2017 Christoph Oelckers +** Copyright 2010-2020 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -33,114 +33,23 @@ ** */ -#include "menu/menu.h" +#include "doommenu.h" #include "version.h" #include "g_game.h" #include "m_png.h" -#include "w_wad.h" +#include "filesystem.h" #include "v_text.h" #include "gstrings.h" #include "serializer.h" #include "vm.h" #include "i_system.h" +#include "v_video.h" +#include "fs_findfile.h" +#include "v_draw.h" // Save name length limit for old binary formats. #define OLDSAVESTRINGSIZE 24 -//============================================================================= -// -// Save data maintenance -// -//============================================================================= - -void FSavegameManager::ClearSaveGames() -{ - for (unsigned i = 0; ibNoDelete) - delete SaveGames[i]; - } - SaveGames.Clear(); -} - -FSavegameManager::~FSavegameManager() -{ - ClearSaveGames(); -} - -//============================================================================= -// -// Save data maintenance -// -//============================================================================= - -int FSavegameManager::RemoveSaveSlot(int index) -{ - int listindex = SaveGames[0]->bNoDelete ? index - 1 : index; - if (listindex < 0) return index; - - remove(SaveGames[index]->Filename.GetChars()); - UnloadSaveData(); - - FSaveGameNode *file = SaveGames[index]; - - if (quickSaveSlot == SaveGames[index]) - { - quickSaveSlot = nullptr; - } - if (!file->bNoDelete) delete file; - - if (LastSaved == listindex) LastSaved = -1; - else if (LastSaved > listindex) LastSaved--; - if (LastAccessed == listindex) LastAccessed = -1; - else if (LastAccessed > listindex) LastAccessed--; - - SaveGames.Delete(index); - if ((unsigned)index >= SaveGames.Size()) index--; - ExtractSaveData(index); - return index; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveSaveSlot) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(sel); - ACTION_RETURN_INT(self->RemoveSaveSlot(sel)); -} - - -//============================================================================= -// -// -// -//============================================================================= - -int FSavegameManager::InsertSaveNode(FSaveGameNode *node) -{ - if (SaveGames.Size() == 0) - { - return SaveGames.Push(node); - } - - if (node->bOldVersion) - { // Add node at bottom of list - return SaveGames.Push(node); - } - else - { // Add node at top of list - unsigned int i; - for (i = 0; i < SaveGames.Size(); i++) - { - if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0) - { - break; - } - } - SaveGames.Insert(i, node); - return i; - } -} - //============================================================================= // // M_ReadSaveStrings @@ -153,36 +62,29 @@ void FSavegameManager::ReadSaveStrings() { if (SaveGames.Size() == 0) { - void *filefirst; - findstate_t c_file; FString filter; LastSaved = LastAccessed = -1; quickSaveSlot = nullptr; - filter = G_BuildSaveName("*." SAVEGAME_EXT, -1); - filefirst = I_FindFirst(filter.GetChars(), &c_file); - if (filefirst != ((void *)(-1))) + FileSys::FileList list; + if (FileSys::ScanDirectory(list, G_GetSavegamesFolder().GetChars(), "*." SAVEGAME_EXT, true)) { - do + for (auto& entry : list) { - // I_FindName only returns the file's name and not its full path - FString filepath = G_BuildSaveName(I_FindName(&c_file), -1); - - FResourceFile *savegame = FResourceFile::OpenResourceFile(filepath, true, true); + std::unique_ptr savegame(FResourceFile::OpenResourceFile(entry.FilePath.c_str(), true)); if (savegame != nullptr) { bool oldVer = false; bool missing = false; - FResourceLump *info = savegame->FindLump("info.json"); - if (info == nullptr) + auto info = savegame->FindEntry("info.json"); + if (info < 0) { // savegame info not found. This is not a savegame so leave it alone. - delete savegame; continue; } - void *data = info->CacheLump(); - FSerializer arc(nullptr); - if (arc.OpenReader((const char *)data, info->LumpSize)) + auto data = savegame->Read(info); + FSerializer arc; + if (arc.OpenReader(data.string(), data.size())) { int savever = 0; arc("Save Version", savever); @@ -195,7 +97,6 @@ void FSavegameManager::ReadSaveStrings() { // different engine or newer version: // not our business. Leave it alone. - delete savegame; continue; } @@ -204,167 +105,27 @@ void FSavegameManager::ReadSaveStrings() // old, incompatible savegame. List as not usable. oldVer = true; } - else if (iwad.CompareNoCase(Wads.GetWadName(Wads.GetIwadNum())) == 0) + else if (iwad.CompareNoCase(fileSystem.GetResourceFileName(fileSystem.GetIwadNum())) == 0) { missing = !G_CheckSaveGameWads(arc, false); } else { // different game. Skip this. - delete savegame; continue; } FSaveGameNode *node = new FSaveGameNode; - node->Filename = filepath; + node->Filename = entry.FilePath.c_str(); node->bOldVersion = oldVer; node->bMissingWads = missing; node->SaveTitle = title; InsertSaveNode(node); - delete savegame; - } - - } - else // check for old formats. - { - FileReader file; - if (file.OpenFile(filepath)) - { - PNGHandle *png; - char sig[16]; - char title[OLDSAVESTRINGSIZE + 1]; - bool oldVer = true; - bool addIt = false; - bool missing = false; - - // ZDoom 1.23 betas 21-33 have the savesig first. - // Earlier versions have the savesig second. - // Later versions have the savegame encapsulated inside a PNG. - // - // Old savegame versions are always added to the menu so - // the user can easily delete them if desired. - - title[OLDSAVESTRINGSIZE] = 0; - - if (nullptr != (png = M_VerifyPNG(file))) - { - char *ver = M_GetPNGText(png, "ZDoom Save Version"); - if (ver != nullptr) - { - // An old version - if (!M_GetPNGText(png, "Title", title, OLDSAVESTRINGSIZE)) - { - strncpy(title, I_FindName(&c_file), OLDSAVESTRINGSIZE); - } - addIt = true; - delete[] ver; - } - delete png; - } - else - { - file.Seek(0, FileReader::SeekSet); - if (file.Read(sig, 16) == 16) - { - - if (strncmp(sig, "ZDOOMSAVE", 9) == 0) - { - if (file.Read(title, OLDSAVESTRINGSIZE) == OLDSAVESTRINGSIZE) - { - addIt = true; - } - } - else - { - memcpy(title, sig, 16); - if (file.Read(title + 16, OLDSAVESTRINGSIZE - 16) == OLDSAVESTRINGSIZE - 16 && - file.Read(sig, 16) == 16 && - strncmp(sig, "ZDOOMSAVE", 9) == 0) - { - addIt = true; - } - } - } - } - - if (addIt) - { - FSaveGameNode *node = new FSaveGameNode; - node->Filename = filepath; - node->bOldVersion = true; - node->bMissingWads = false; - node->SaveTitle = title; - InsertSaveNode(node); - } } } - } while (I_FindNext(filefirst, &c_file) == 0); - I_FindClose(filefirst); - } - } -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - self->ReadSaveStrings(); - return 0; -} - - -//============================================================================= -// -// -// -//============================================================================= - -void FSavegameManager::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave) -{ - FSaveGameNode *node; - - if (file.IsEmpty()) - return; - - ReadSaveStrings(); - - // See if the file is already in our list - for (unsigned i = 0; iFilename.Compare(file) == 0) -#else - if (node->Filename.CompareNoCase(file) == 0) -#endif - { - node->SaveTitle = title; - node->bOldVersion = false; - node->bMissingWads = false; - if (okForQuicksave) - { - if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; - LastAccessed = LastSaved = i; } - return; } } - - node = new FSaveGameNode; - node->SaveTitle = title; - node->Filename = file; - node->bOldVersion = false; - node->bMissingWads = false; - int index = InsertSaveNode(node); - - if (okForQuicksave) - { - if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; - LastAccessed = LastSaved = index; - } - else - { - LastAccessed = ++LastSaved; - } } //============================================================================= @@ -373,23 +134,9 @@ void FSavegameManager::NotifyNewSave(const FString &file, const FString &title, // //============================================================================= -void FSavegameManager::LoadSavegame(int Selected) +void FSavegameManager::PerformLoadGame(const char *fn, bool flag) { - G_LoadGame(SaveGames[Selected]->Filename.GetChars(), true); - if (quickSaveSlot == (FSaveGameNode*)1) - { - quickSaveSlot = SaveGames[Selected]; - } - M_ClearMenus(); - LastAccessed = Selected; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(sel); - self->LoadSavegame(sel); - return 0; + G_LoadGame(fn, flag); } //============================================================================= @@ -398,200 +145,9 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame) // //============================================================================= -void FSavegameManager::DoSave(int Selected, const char *savegamestring) -{ - if (Selected != 0) - { - auto node = SaveGames[Selected]; - G_SaveGame(node->Filename.GetChars(), savegamestring); - } - else - { - // Find an unused filename and save as that - FString filename; - int i; - - for (i = 0;; ++i) - { - filename = G_BuildSaveName("save", i); - if (!FileExists(filename)) - { - break; - } - } - G_SaveGame(filename, savegamestring); - } - M_ClearMenus(); -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(sel); - PARAM_STRING(name); - self->DoSave(sel, name); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -unsigned FSavegameManager::ExtractSaveData(int index) -{ - FResourceFile *resf; - FSaveGameNode *node; - - if (index == -1) - { - if (SaveGames.Size() > 0 && SaveGames[0]->bNoDelete) - { - index = LastSaved + 1; - } - else - { - index = LastAccessed < 0? 0 : LastAccessed; - } - } - - UnloadSaveData(); - - if ((unsigned)index < SaveGames.Size() && - (node = SaveGames[index]) && - !node->Filename.IsEmpty() && - !node->bOldVersion && - (resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr) - { - FResourceLump *info = resf->FindLump("info.json"); - if (info == nullptr) - { - // this should not happen because the file has already been verified. - return index; - } - void *data = info->CacheLump(); - FSerializer arc(nullptr); - if (arc.OpenReader((const char *)data, info->LumpSize)) - { - FString comment; - - FString time = arc.GetString("Creation Time"); - FString pcomment = arc.GetString("Comment"); - - comment = time; - if (time.Len() > 0) comment += "\n"; - comment += pcomment; - SaveCommentString = comment; - - // Extract pic - FResourceLump *pic = resf->FindLump("savepic.png"); - if (pic != nullptr) - { - FileReader picreader; - - picreader.OpenMemoryArray([=](TArray &array) - { - auto cache = pic->CacheLump(); - array.Resize(pic->LumpSize); - memcpy(&array[0], cache, pic->LumpSize); - pic->ReleaseCache(); - return true; - }); - PNGHandle *png = M_VerifyPNG(picreader); - if (png != nullptr) - { - SavePic = PNGTexture_CreateFromFile(png, node->Filename); - delete png; - if (SavePic && SavePic->GetDisplayWidth() == 1 && SavePic->GetDisplayHeight() == 1) - { - delete SavePic; - SavePic = nullptr; - SavePicData.Clear(); - } - } - } - } - delete resf; - } - return index; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(sel); - ACTION_RETURN_INT(self->ExtractSaveData(sel)); -} - -//============================================================================= -// -// -// -//============================================================================= - -void FSavegameManager::UnloadSaveData() -{ - if (SavePic != nullptr) - { - delete SavePic; - } - - SaveCommentString = ""; - SavePic = nullptr; - SavePicData.Clear(); -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, UnloadSaveData) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - self->UnloadSaveData(); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -void FSavegameManager::ClearSaveStuff() -{ - UnloadSaveData(); - if (quickSaveSlot == (FSaveGameNode*)1) - { - quickSaveSlot = nullptr; - } -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, ClearSaveStuff) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - self->ClearSaveStuff(); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -bool FSavegameManager::DrawSavePic(int x, int y, int w, int h) +void FSavegameManager::PerformSaveGame(const char *fn, const char *savegamestring) { - if (SavePic == nullptr) return false; - screen->DrawTexture(SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE); - return true; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(x); - PARAM_INT(y); - PARAM_INT(w); - PARAM_INT(h); - ACTION_RETURN_BOOL(self->DrawSavePic(x, y, w, h)); + G_SaveGame(fn, savegamestring); } //============================================================================= @@ -600,38 +156,22 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic) // //============================================================================= -void FSavegameManager::SetFileInfo(int Selected) +FString FSavegameManager::ExtractSaveComment(FSerializer &arc) { - if (!SaveGames[Selected]->Filename.IsEmpty()) - { - SaveCommentString.Format("File on disk:\n%s", SaveGames[Selected]->Filename.GetChars()); - } -} + FString comment; -DEFINE_ACTION_FUNCTION(FSavegameManager, SetFileInfo) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(i); - self->SetFileInfo(i); - return 0; -} + FString time = arc.GetString("Creation Time"); + FString pcomment = arc.GetString("Comment"); - -//============================================================================= -// -// -// -//============================================================================= - -unsigned FSavegameManager::SavegameCount() -{ - return SaveGames.Size(); + comment = time; + if (time.Len() > 0) comment += "\n"; + comment += pcomment; + return comment; } -DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount) +FString FSavegameManager::BuildSaveName(const char* prefix, int slot) { - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - ACTION_RETURN_INT(self->SavegameCount()); + return G_BuildSaveName(FStringf("%s%02d", prefix, slot).GetChars()); } //============================================================================= @@ -640,61 +180,6 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount) // //============================================================================= -FSaveGameNode *FSavegameManager::GetSavegame(int i) -{ - return SaveGames[i]; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(i); - ACTION_RETURN_POINTER(self->GetSavegame(i)); -} - -//============================================================================= -// -// -// -//============================================================================= - -void FSavegameManager::InsertNewSaveNode() -{ - NewSaveNode.SaveTitle = GStrings["NEWSAVE"]; - NewSaveNode.bNoDelete = true; - SaveGames.Insert(0, &NewSaveNode); -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, InsertNewSaveNode) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - self->InsertNewSaveNode(); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -bool FSavegameManager::RemoveNewSaveNode() -{ - if (SaveGames[0] == &NewSaveNode) - { - SaveGames.Delete(0); - return true; - } - return false; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - ACTION_RETURN_INT(self->RemoveNewSaveNode()); -} - - FSavegameManager savegameManager; DEFINE_ACTION_FUNCTION(FSavegameManager, GetManager) @@ -703,15 +188,3 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, GetManager) ACTION_RETURN_POINTER(&savegameManager); } - - -DEFINE_FIELD(FSaveGameNode, SaveTitle); -DEFINE_FIELD(FSaveGameNode, Filename); -DEFINE_FIELD(FSaveGameNode, bOldVersion); -DEFINE_FIELD(FSaveGameNode, bMissingWads); -DEFINE_FIELD(FSaveGameNode, bNoDelete); - -DEFINE_FIELD(FSavegameManager, WindowSize); -DEFINE_FIELD(FSavegameManager, quickSaveSlot); -DEFINE_FIELD(FSavegameManager, SaveCommentString); - diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp deleted file mode 100644 index 2c94cffb096..00000000000 --- a/src/menu/menu.cpp +++ /dev/null @@ -1,1406 +0,0 @@ -/* -** menu.cpp -** Menu base class and global interface -** -**--------------------------------------------------------------------------- -** Copyright 2010 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "doomdef.h" -#include "doomstat.h" -#include "c_dispatch.h" -#include "d_gui.h" -#include "d_player.h" -#include "c_console.h" -#include "c_bind.h" -#include "p_tick.h" -#include "g_game.h" -#include "d_event.h" -#include "hu_stuff.h" -#include "gi.h" -#include "g_input.h" -#include "gameconfigfile.h" -#include "gstrings.h" -#include "r_utility.h" -#include "menu/menu.h" -#include "vm.h" -#include "events.h" -#include "v_video.h" -#include "i_system.h" -#include "scripting/types.h" - -int DMenu::InMenu; -static ScaleOverrider *CurrentScaleOverrider; -// -// Todo: Move these elsewhere -// -CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE) -CVAR (Int, m_showinputgrid, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, m_blockcontrollers, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - -CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE) -CVAR(Int, m_use_mouse, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR(Int, m_show_backbutton, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -CUSTOM_CVAR(Float, dimamount, -1.f, CVAR_ARCHIVE) -{ - if (self < 0.f && self != -1.f) - { - self = -1.f; - } - else if (self > 1.f) - { - self = 1.f; - } -} -CVAR(Color, dimcolor, 0xffd700, CVAR_ARCHIVE) - - - -static DMenu *GetCurrentMenu() -{ - return CurrentMenu; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DMenu, GetCurrentMenu, GetCurrentMenu) -{ - ACTION_RETURN_OBJECT(CurrentMenu); -} - -static int GetMenuTime() -{ - return MenuTime; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DMenu, MenuTime, GetMenuTime) -{ - ACTION_RETURN_INT(MenuTime); -} - -FGameStartup GameStartupInfo; -EMenuState menuactive; -bool M_DemoNoPlay; -FButtonStatus MenuButtons[NUM_MKEYS]; -int MenuButtonTickers[NUM_MKEYS]; -bool MenuButtonOrigin[NUM_MKEYS]; -int BackbuttonTime; -float BackbuttonAlpha; -static bool MenuEnabled = true; -DMenu *CurrentMenu; -int MenuTime; - -extern PClass *DefaultListMenuClass; -extern PClass *DefaultOptionMenuClass; -extern bool hud_toggled; -void D_ToggleHud(); - - -#define KEY_REPEAT_DELAY (TICRATE*5/12) -#define KEY_REPEAT_RATE (3) - -//============================================================================ -// -// -// -//============================================================================ - -IMPLEMENT_CLASS(DMenuDescriptor, false, false) -IMPLEMENT_CLASS(DListMenuDescriptor, false, false) -IMPLEMENT_CLASS(DOptionMenuDescriptor, false, false) - -DMenuDescriptor *GetMenuDescriptor(int name) -{ - DMenuDescriptor **desc = MenuDescriptors.CheckKey(ENamedName(name)); - return desc ? *desc : nullptr; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DMenuDescriptor, GetDescriptor, GetMenuDescriptor) -{ - PARAM_PROLOGUE; - PARAM_NAME(name); - ACTION_RETURN_OBJECT(GetMenuDescriptor(name)); -} - -size_t DListMenuDescriptor::PropagateMark() -{ - for (auto item : mItems) GC::Mark(item); - return 0; -} - -size_t DOptionMenuDescriptor::PropagateMark() -{ - for (auto item : mItems) GC::Mark(item); - return 0; -} - -void M_MarkMenus() -{ - MenuDescriptorList::Iterator it(MenuDescriptors); - MenuDescriptorList::Pair *pair; - while (it.NextPair(pair)) - { - GC::Mark(pair->Value); - } - GC::Mark(CurrentMenu); -} -//============================================================================ -// -// DMenu base class -// -//============================================================================ - -IMPLEMENT_CLASS(DMenu, false, true) - -IMPLEMENT_POINTERS_START(DMenu) - IMPLEMENT_POINTER(mParentMenu) -IMPLEMENT_POINTERS_END - -DMenu::DMenu(DMenu *parent) -{ - mParentMenu = parent; - mMouseCapture = false; - mBackbuttonSelected = false; - DontDim = false; - GC::WriteBarrier(this, parent); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DMenu::CallResponder(event_t *ev) -{ - if (ev->type == EV_GUI_Event) - { - IFVIRTUAL(DMenu, OnUIEvent) - { - FUiEvent e = ev; - VMValue params[] = { (DObject*)this, &e }; - int retval; - VMReturn ret(&retval); - InMenu++; - VMCall(func, params, 2, &ret, 1); - InMenu--; - return !!retval; - } - } - else - { - IFVIRTUAL(DMenu, OnInputEvent) - { - FInputEvent e = ev; - VMValue params[] = { (DObject*)this, &e }; - int retval; - VMReturn ret(&retval); - InMenu++; - VMCall(func, params, 2, &ret, 1); - InMenu--; - return !!retval; - } - } - return false; -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) -{ - IFVIRTUAL(DMenu, MenuEvent) - { - VMValue params[] = { (DObject*)this, mkey, fromcontroller }; - int retval; - VMReturn ret(&retval); - InMenu++; - VMCall(func, params, 3, &ret, 1); - InMenu--; - return !!retval; - } - else return false; -} -//============================================================================= -// -// -// -//============================================================================= - -static void SetMouseCapture(bool on) -{ - if (on) I_SetMouseCapture(); - else I_ReleaseMouseCapture(); -} -DEFINE_ACTION_FUNCTION_NATIVE(DMenu, SetMouseCapture, SetMouseCapture) -{ - PARAM_PROLOGUE; - PARAM_BOOL(on); - SetMouseCapture(on); - return 0; -} - -void DMenu::Close () -{ - if (CurrentMenu == nullptr) return; // double closing can happen in the save menu. - assert(CurrentMenu == this); - CurrentMenu = mParentMenu; - Destroy(); - if (CurrentMenu != nullptr) - { - GC::WriteBarrier(CurrentMenu); - IFVIRTUALPTR(CurrentMenu, DMenu, OnReturn) - { - VMValue params[] = { CurrentMenu }; - VMCall(func, params, 1, nullptr, 0); - } - - } - else - { - M_ClearMenus (); - } -} - - -static void Close(DMenu *menu) -{ - menu->Close(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DMenu, Close, Close) -{ - PARAM_SELF_PROLOGUE(DMenu); - self->Close(); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -void DMenu::CallTicker() -{ - IFVIRTUAL(DMenu, Ticker) - { - VMValue params[] = { (DObject*)this }; - VMCall(func, params, 1, nullptr, 0); - } -} - - -void DMenu::CallDrawer() -{ - IFVIRTUAL(DMenu, Drawer) - { - VMValue params[] = { (DObject*)this }; - VMCall(func, params, 1, nullptr, 0); - screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. - } -} - -bool DMenu::TranslateKeyboardEvents() -{ - IFVIRTUAL(DMenu, TranslateKeyboardEvents) - { - VMValue params[] = { (DObject*)this }; - int retval; - VMReturn ret(&retval); - VMCall(func, params, countof(params), &ret, 1); - return !!retval; - } - return true; -} - -//============================================================================= -// -// -// -//============================================================================= - -void M_StartControlPanel (bool makeSound, bool scaleoverride) -{ - if (hud_toggled) - D_ToggleHud(); - - // intro might call this repeatedly - if (CurrentMenu != nullptr) - return; - - ResetButtonStates (); - for (int i = 0; i < NUM_MKEYS; ++i) - { - MenuButtons[i].ReleaseKey(0); - } - - C_HideConsole (); // [RH] Make sure console goes bye bye. - menuactive = MENU_On; - // Pause sound effects before we play the menu switch sound. - // That way, it won't be paused. - P_CheckTickerPaused (); - - if (makeSound) - { - S_Sound (CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE); - } - BackbuttonTime = 0; - BackbuttonAlpha = 0; - if (scaleoverride && !CurrentScaleOverrider) CurrentScaleOverrider = new ScaleOverrider; - else if (!scaleoverride && CurrentScaleOverrider) delete CurrentScaleOverrider; -} - -//============================================================================= -// -// -// -//============================================================================= - -void M_ActivateMenu(DMenu *menu) -{ - if (menuactive == MENU_Off) menuactive = MENU_On; - if (CurrentMenu != nullptr && CurrentMenu->mMouseCapture) - { - CurrentMenu->mMouseCapture = false; - I_ReleaseMouseCapture(); - } - CurrentMenu = menu; - GC::WriteBarrier(CurrentMenu); -} - -DEFINE_ACTION_FUNCTION(DMenu, ActivateMenu) -{ - PARAM_SELF_PROLOGUE(DMenu); - M_ActivateMenu(self); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -EXTERN_CVAR(Int, cl_gfxlocalization) - - -void M_SetMenu(FName menu, int param) -{ - // some menus need some special treatment - switch (menu) - { - case NAME_Mainmenu: - if (gameinfo.gametype & GAME_DoomStrifeChex) // Raven's games always used text based menus - { - if (gameinfo.forcetextinmenus) // If text is forced, this overrides any check. - { - menu = NAME_MainmenuTextOnly; - } - else if (cl_gfxlocalization != 0 && !gameinfo.forcenogfxsubstitution) - { - // For these games we must check up-front if they get localized because in that case another template must be used. - DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Mainmenu); - if (desc != nullptr) - { - if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) - { - DListMenuDescriptor *ld = static_cast(*desc); - if (ld->mFromEngine) - { - // This assumes that replacing one graphic will replace all of them. - // So this only checks the "New game" entry for localization capability. - FTextureID texid = TexMan.CheckForTexture("M_NGAME", ETextureType::MiscPatch); - if (!TexMan.OkForLocalization(texid, "$MNU_NEWGAME")) - { - menu = NAME_MainmenuTextOnly; - } - } - } - } - } - } - break; - case NAME_Episodemenu: - // sent from the player class menu - GameStartupInfo.Skill = -1; - GameStartupInfo.Episode = -1; - GameStartupInfo.PlayerClass = - param == -1000? nullptr : - param == -1? "Random" : GetPrintableDisplayName(PlayerClasses[param].Type).GetChars(); - M_StartupEpisodeMenu(&GameStartupInfo); // needs player class name from class menu (later) - break; - - case NAME_Skillmenu: - // sent from the episode menu - - if ((gameinfo.flags & GI_SHAREWARE) && param > 0) - { - // Only Doom and Heretic have multi-episode shareware versions. - M_StartMessage(GStrings("SWSTRING"), 1); - return; - } - - GameStartupInfo.Episode = param; - M_StartupSkillMenu(&GameStartupInfo); // needs player class name from class menu (later) - break; - - case NAME_StartgameConfirm: - { - // sent from the skill menu for a skill that needs to be confirmed - GameStartupInfo.Skill = param; - - const char *msg = AllSkills[param].MustConfirmText; - if (*msg==0) msg = GStrings("NIGHTMARE"); - M_StartMessage (msg, 0, NAME_StartgameConfirmed); - return; - } - - case NAME_Startgame: - // sent either from skill menu or confirmation screen. Skill gets only set if sent from skill menu - // Now we can finally start the game. Ugh... - GameStartupInfo.Skill = param; - case NAME_StartgameConfirmed: - - G_DeferedInitNew (&GameStartupInfo); - if (gamestate == GS_FULLCONSOLE) - { - gamestate = GS_HIDECONSOLE; - gameaction = ga_newgame; - } - M_ClearMenus (); - return; - - case NAME_Savegamemenu: - if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer) || gamestate != GS_LEVEL) - { - // cannot save outside the game. - M_StartMessage (GStrings("SAVEDEAD"), 1); - return; - } - - case NAME_VideoModeMenu: - break; - - case NAME_Quitmenu: - // The separate menu class no longer exists but the name still needs support for existing mods. - C_DoCommand("menu_quit"); - return; - - case NAME_EndGameMenu: - // The separate menu class no longer exists but the name still needs support for existing mods. - void ActivateEndGameMenu(); - ActivateEndGameMenu(); - return; - - case NAME_Playermenu: - menu = NAME_NewPlayerMenu; // redirect the old player menu to the new one. - break; - } - - // End of special checks - - DMenuDescriptor **desc = MenuDescriptors.CheckKey(menu); - if (desc != nullptr) - { - if ((*desc)->mNetgameMessage.IsNotEmpty() && netgame && !demoplayback) - { - M_StartMessage((*desc)->mNetgameMessage, 1); - return; - } - - if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) - { - DListMenuDescriptor *ld = static_cast(*desc); - if (ld->mAutoselect >= 0 && ld->mAutoselect < (int)ld->mItems.Size()) - { - // recursively activate the autoselected item without ever creating this menu. - ld->mItems[ld->mAutoselect]->Activate(); - } - else - { - PClass *cls = ld->mClass; - if (cls == nullptr) cls = DefaultListMenuClass; - if (cls == nullptr) cls = PClass::FindClass("ListMenu"); - - DMenu *newmenu = (DMenu *)cls->CreateNew(); - IFVIRTUALPTRNAME(newmenu, "ListMenu", Init) - { - VMValue params[3] = { newmenu, CurrentMenu, ld }; - VMCall(func, params, 3, nullptr, 0); - } - M_ActivateMenu(newmenu); - } - } - else if ((*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) - { - DOptionMenuDescriptor *ld = static_cast(*desc); - PClass *cls = ld->mClass; - if (cls == nullptr) cls = DefaultOptionMenuClass; - if (cls == nullptr) cls = PClass::FindClass("OptionMenu"); - - DMenu *newmenu = (DMenu*)cls->CreateNew(); - IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init) - { - VMValue params[3] = { newmenu, CurrentMenu, ld }; - VMCall(func, params, 3, nullptr, 0); - } - M_ActivateMenu(newmenu); - } - return; - } - else - { - PClass *menuclass = PClass::FindClass(menu); - if (menuclass != nullptr) - { - if (menuclass->IsDescendantOf("GenericMenu")) - { - DMenu *newmenu = (DMenu*)menuclass->CreateNew(); - - IFVIRTUALPTRNAME(newmenu, "GenericMenu", Init) - { - VMValue params[3] = { newmenu, CurrentMenu }; - VMCall(func, params, 2, nullptr, 0); - } - M_ActivateMenu(newmenu); - return; - } - } - } - Printf("Attempting to open menu of unknown type '%s'\n", menu.GetChars()); - M_ClearMenus(); -} - -DEFINE_ACTION_FUNCTION(DMenu, SetMenu) -{ - PARAM_PROLOGUE; - PARAM_NAME(menu); - PARAM_INT(mparam); - M_SetMenu(menu, mparam); - return 0; -} -//============================================================================= -// -// -// -//============================================================================= - -bool M_Responder (event_t *ev) -{ - int ch = 0; - bool keyup = false; - int mkey = NUM_MKEYS; - bool fromcontroller = true; - - if (chatmodeon) - { - return false; - } - - if (CurrentMenu != nullptr && menuactive != MENU_Off) - { - // There are a few input sources we are interested in: - // - // EV_KeyDown / EV_KeyUp : joysticks/gamepads/controllers - // EV_GUI_KeyDown / EV_GUI_KeyUp : the keyboard - // EV_GUI_Char : printable characters, which we want in string input mode - // - // This code previously listened for EV_GUI_KeyRepeat to handle repeating - // in the menus, but that doesn't work with gamepads, so now we combine - // the multiple inputs into buttons and handle the repetition manually. - if (ev->type == EV_GUI_Event) - { - fromcontroller = false; - if (ev->subtype == EV_GUI_KeyRepeat) - { - // We do our own key repeat handling but still want to eat the - // OS's repeated keys. - return true; - } - else if (ev->subtype == EV_GUI_BackButtonDown || ev->subtype == EV_GUI_BackButtonUp) - { - mkey = MKEY_Back; - keyup = ev->subtype == EV_GUI_BackButtonUp; - } - else if (ev->subtype != EV_GUI_KeyDown && ev->subtype != EV_GUI_KeyUp) - { - // do we want mouse input? - if (ev->subtype >= EV_GUI_FirstMouseEvent && ev->subtype <= EV_GUI_LastMouseEvent) - { - if (!m_use_mouse) - return true; - } - - // pass everything else on to the current menu - return CurrentMenu->CallResponder(ev); - } - else if (CurrentMenu->TranslateKeyboardEvents()) - { - ch = ev->data1; - keyup = ev->subtype == EV_GUI_KeyUp; - switch (ch) - { - case GK_BACK: mkey = MKEY_Back; break; - case GK_ESCAPE: mkey = MKEY_Back; break; - case GK_RETURN: mkey = MKEY_Enter; break; - case GK_UP: mkey = MKEY_Up; break; - case GK_DOWN: mkey = MKEY_Down; break; - case GK_LEFT: mkey = MKEY_Left; break; - case GK_RIGHT: mkey = MKEY_Right; break; - case GK_BACKSPACE: mkey = MKEY_Clear; break; - case GK_PGUP: mkey = MKEY_PageUp; break; - case GK_PGDN: mkey = MKEY_PageDown; break; - default: - if (!keyup) - { - return CurrentMenu->CallResponder(ev); - } - break; - } - } - } - else if (menuactive != MENU_WaitKey && (ev->type == EV_KeyDown || ev->type == EV_KeyUp)) - { - // eat blocked controller events without dispatching them. - if (ev->data1 >= KEY_FIRSTJOYBUTTON && m_blockcontrollers) return true; - - keyup = ev->type == EV_KeyUp; - - ch = ev->data1; - switch (ch) - { - case KEY_JOY1: - case KEY_PAD_A: - mkey = MKEY_Enter; - break; - - case KEY_JOY2: - case KEY_PAD_B: - mkey = MKEY_Back; - break; - - case KEY_JOY3: - case KEY_PAD_X: - mkey = MKEY_Clear; - break; - - case KEY_JOY5: - case KEY_PAD_LSHOULDER: - mkey = MKEY_PageUp; - break; - - case KEY_JOY6: - case KEY_PAD_RSHOULDER: - mkey = MKEY_PageDown; - break; - - case KEY_PAD_DPAD_UP: - case KEY_PAD_LTHUMB_UP: - case KEY_JOYAXIS1MINUS: - case KEY_JOYPOV1_UP: - mkey = MKEY_Up; - break; - - case KEY_PAD_DPAD_DOWN: - case KEY_PAD_LTHUMB_DOWN: - case KEY_JOYAXIS1PLUS: - case KEY_JOYPOV1_DOWN: - mkey = MKEY_Down; - break; - - case KEY_PAD_DPAD_LEFT: - case KEY_PAD_LTHUMB_LEFT: - case KEY_JOYAXIS2MINUS: - case KEY_JOYPOV1_LEFT: - mkey = MKEY_Left; - break; - - case KEY_PAD_DPAD_RIGHT: - case KEY_PAD_LTHUMB_RIGHT: - case KEY_JOYAXIS2PLUS: - case KEY_JOYPOV1_RIGHT: - mkey = MKEY_Right; - break; - } - } - - if (mkey != NUM_MKEYS) - { - if (keyup) - { - MenuButtons[mkey].ReleaseKey(ch); - return false; - } - else - { - MenuButtons[mkey].PressKey(ch); - MenuButtonOrigin[mkey] = fromcontroller; - if (mkey <= MKEY_PageDown) - { - MenuButtonTickers[mkey] = KEY_REPEAT_DELAY; - } - CurrentMenu->CallMenuEvent(mkey, fromcontroller); - return true; - } - } - return CurrentMenu->CallResponder(ev) || !keyup; - } - else if (MenuEnabled) - { - if (ev->type == EV_KeyDown) - { - // Pop-up menu? - if (ev->data1 == KEY_ESCAPE) - { - M_StartControlPanel(true); - M_SetMenu(NAME_Mainmenu, -1); - return true; - } - // If devparm is set, pressing F1 always takes a screenshot no matter - // what it's bound to. (for those who don't bother to read the docs) - if (devparm && ev->data1 == KEY_F1) - { - G_ScreenShot(nullptr); - return true; - } - return false; - } - else if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_LButtonDown && - ConsoleState != c_down && gamestate != GS_LEVEL && m_use_mouse) - { - M_StartControlPanel(true); - M_SetMenu(NAME_Mainmenu, -1); - return true; - } - } - return false; -} - -//============================================================================= -// -// -// -//============================================================================= - -void M_Ticker (void) -{ - MenuTime++; - if (CurrentMenu != nullptr && menuactive != MENU_Off) - { - CurrentMenu->CallTicker(); - } - - // Check again because menu could be closed from Ticker() - if (CurrentMenu != nullptr && menuactive != MENU_Off) - { - for (int i = 0; i < NUM_MKEYS; ++i) - { - if (MenuButtons[i].bDown) - { - if (MenuButtonTickers[i] > 0 && --MenuButtonTickers[i] <= 0) - { - MenuButtonTickers[i] = KEY_REPEAT_RATE; - CurrentMenu->CallMenuEvent(i, MenuButtonOrigin[i]); - } - } - } - if (BackbuttonTime > 0) - { - if (BackbuttonAlpha < 1.f) BackbuttonAlpha += .1f; - if (BackbuttonAlpha > 1.f) BackbuttonAlpha = 1.f; - BackbuttonTime--; - } - else - { - if (BackbuttonAlpha > 0) BackbuttonAlpha -= .1f; - if (BackbuttonAlpha < 0) BackbuttonAlpha = 0; - } - } -} - -//========================================================================== -// -// M_Dim -// -// Applies a colored overlay to the entire screen, with the opacity -// determined by the dimamount cvar. -// -//========================================================================== - -static void M_Dim() -{ - PalEntry dimmer; - float amount; - - if (dimamount >= 0) - { - dimmer = PalEntry(dimcolor); - amount = dimamount; - } - else - { - dimmer = gameinfo.dimcolor; - amount = gameinfo.dimamount; - } - - screen->Dim(dimmer, amount, 0, 0, screen->GetWidth(), screen->GetHeight()); -} - - -//============================================================================= -// -// -// -//============================================================================= - -void M_Drawer (void) -{ - player_t *player = &players[consoleplayer]; - AActor *camera = player->camera; - PalEntry fade = 0; - - if (CurrentMenu != nullptr && menuactive != MENU_Off) - { - if (!CurrentMenu->DontBlur) screen->BlurScene(gameinfo.bluramount); - if (!CurrentMenu->DontDim) - { - M_Dim(); - } - CurrentMenu->CallDrawer(); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void M_ClearMenus() -{ - M_DemoNoPlay = false; - while (CurrentMenu != nullptr) - { - DMenu* parent = CurrentMenu->mParentMenu; - CurrentMenu->Destroy(); - CurrentMenu = parent; - } - menuactive = MENU_Off; - if (CurrentScaleOverrider) delete CurrentScaleOverrider; - CurrentScaleOverrider = nullptr; -} - -//============================================================================= -// -// -// -//============================================================================= - -void M_PreviousMenu() -{ - if (CurrentMenu != nullptr) - { - DMenu* parent = CurrentMenu->mParentMenu; - CurrentMenu->Destroy(); - CurrentMenu = parent; - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void M_Init (void) -{ - try - { - M_ParseMenuDefs(); - } - catch (CVMAbortException &err) - { - err.MaybePrintMessage(); - Printf("%s", err.stacktrace.GetChars()); - I_FatalError("Failed to initialize menus"); - } - M_CreateMenus(); -} - - -//============================================================================= -// -// -// -//============================================================================= - -void M_EnableMenu (bool on) -{ - MenuEnabled = on; -} - - -//============================================================================= -// -// [RH] Most menus can now be accessed directly -// through console commands. -// -//============================================================================= - -CCMD (menu_main) -{ - M_StartControlPanel(true); - M_SetMenu(NAME_Mainmenu, -1); -} - -CCMD (menu_load) -{ // F3 - M_StartControlPanel (true); - M_SetMenu(NAME_Loadgamemenu, -1); -} - -CCMD (menu_save) -{ // F2 - M_StartControlPanel (true); - M_SetMenu(NAME_Savegamemenu, -1); -} - -CCMD (menu_help) -{ // F1 - M_StartControlPanel (true); - M_SetMenu(NAME_Readthismenu, -1); -} - -CCMD (menu_game) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_Playerclassmenu, -1); // The playerclass menu is the first in the 'start game' chain -} - -CCMD (menu_options) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_Optionsmenu, -1); -} - -CCMD (menu_player) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_Playermenu, -1); -} - -CCMD (menu_messages) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_MessageOptions, -1); -} - -CCMD (menu_automap) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_AutomapOptions, -1); -} - -CCMD (menu_scoreboard) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_ScoreboardOptions, -1); -} - -CCMD (menu_mapcolors) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_MapColorMenu, -1); -} - -CCMD (menu_keys) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_CustomizeControls, -1); -} - -CCMD (menu_gameplay) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_GameplayOptions, -1); -} - -CCMD (menu_compatibility) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_CompatibilityOptions, -1); -} - -CCMD (menu_mouse) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_MouseOptions, -1); -} - -CCMD (menu_joystick) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_JoystickOptions, -1); -} - -CCMD (menu_sound) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_SoundOptions, -1); -} - -CCMD (menu_advsound) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_AdvSoundOptions, -1); -} - -CCMD (menu_modreplayer) -{ - M_StartControlPanel(true); - M_SetMenu(NAME_ModReplayerOptions, -1); -} - -CCMD (menu_display) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_VideoOptions, -1); -} - -CCMD (menu_video) -{ - M_StartControlPanel (true); - M_SetMenu(NAME_VideoModeMenu, -1); -} - - - -CCMD (openmenu) -{ - if (argv.argc() < 2) - { - Printf("Usage: openmenu \"menu_name\"\n"); - return; - } - M_StartControlPanel (true); - M_SetMenu(argv[1], -1); -} - -CCMD (closemenu) -{ - M_ClearMenus(); -} - -CCMD (prevmenu) -{ - M_PreviousMenu(); -} - -// -// Toggle messages on/off -// -CCMD (togglemessages) -{ - if (show_messages) - { - Printf (128, "%s\n", GStrings("MSGOFF")); - show_messages = false; - } - else - { - Printf (128, "%s\n", GStrings("MSGON")); - show_messages = true; - } -} - -EXTERN_CVAR (Int, screenblocks) - -CCMD (sizedown) -{ - screenblocks = screenblocks - 1; - S_Sound (CHAN_VOICE, CHANF_UI, "menu/change", snd_menuvolume, ATTN_NONE); -} - -CCMD (sizeup) -{ - screenblocks = screenblocks + 1; - S_Sound (CHAN_VOICE, CHANF_UI, "menu/change", snd_menuvolume, ATTN_NONE); -} - -CCMD(menuconsole) -{ - M_ClearMenus(); - C_ToggleConsole(); -} - -CCMD(reset2defaults) -{ - C_SetDefaultBindings (); - C_SetCVarsToDefaults (); - R_SetViewSize (screenblocks); -} - -CCMD(reset2saved) -{ - GameConfig->DoGlobalSetup (); - GameConfig->DoGameSetup (gameinfo.ConfigName); - GameConfig->DoModSetup (gameinfo.ConfigName); - R_SetViewSize (screenblocks); -} - - -// This really should be in the script but we can't do scripted CCMDs yet. -CCMD(undocolorpic) -{ - if (CurrentMenu != NULL) - { - IFVIRTUALPTR(CurrentMenu, DMenu, ResetColor) - { - VMValue params[] = { (DObject*)CurrentMenu }; - VMCall(func, params, countof(params), nullptr, 0); - } - } -} - - -DEFINE_GLOBAL(menuactive) -DEFINE_GLOBAL(BackbuttonTime) -DEFINE_GLOBAL(BackbuttonAlpha) - -DEFINE_FIELD(DMenu, mParentMenu) -DEFINE_FIELD(DMenu, mMouseCapture); -DEFINE_FIELD(DMenu, mBackbuttonSelected); -DEFINE_FIELD(DMenu, DontDim); -DEFINE_FIELD(DMenu, DontBlur); - -DEFINE_FIELD(DMenuDescriptor, mMenuName) -DEFINE_FIELD(DMenuDescriptor, mNetgameMessage) -DEFINE_FIELD(DMenuDescriptor, mClass) - -DEFINE_FIELD(DMenuItemBase, mXpos) -DEFINE_FIELD(DMenuItemBase, mYpos) -DEFINE_FIELD(DMenuItemBase, mAction) -DEFINE_FIELD(DMenuItemBase, mEnabled) - -DEFINE_FIELD(DListMenuDescriptor, mItems) -DEFINE_FIELD(DListMenuDescriptor, mSelectedItem) -DEFINE_FIELD(DListMenuDescriptor, mSelectOfsX) -DEFINE_FIELD(DListMenuDescriptor, mSelectOfsY) -DEFINE_FIELD(DListMenuDescriptor, mSelector) -DEFINE_FIELD(DListMenuDescriptor, mDisplayTop) -DEFINE_FIELD(DListMenuDescriptor, mXpos) -DEFINE_FIELD(DListMenuDescriptor, mYpos) -DEFINE_FIELD(DListMenuDescriptor, mWLeft) -DEFINE_FIELD(DListMenuDescriptor, mWRight) -DEFINE_FIELD(DListMenuDescriptor, mLinespacing) -DEFINE_FIELD(DListMenuDescriptor, mAutoselect) -DEFINE_FIELD(DListMenuDescriptor, mFont) -DEFINE_FIELD(DListMenuDescriptor, mFontColor) -DEFINE_FIELD(DListMenuDescriptor, mFontColor2) -DEFINE_FIELD(DListMenuDescriptor, mCenter) - -DEFINE_FIELD(DOptionMenuDescriptor, mItems) -DEFINE_FIELD(DOptionMenuDescriptor, mTitle) -DEFINE_FIELD(DOptionMenuDescriptor, mSelectedItem) -DEFINE_FIELD(DOptionMenuDescriptor, mDrawTop) -DEFINE_FIELD(DOptionMenuDescriptor, mScrollTop) -DEFINE_FIELD(DOptionMenuDescriptor, mScrollPos) -DEFINE_FIELD(DOptionMenuDescriptor, mIndent) -DEFINE_FIELD(DOptionMenuDescriptor, mPosition) -DEFINE_FIELD(DOptionMenuDescriptor, mDontDim) -DEFINE_FIELD(DOptionMenuDescriptor, mFont) - -DEFINE_FIELD(FOptionMenuSettings, mTitleColor) -DEFINE_FIELD(FOptionMenuSettings, mFontColor) -DEFINE_FIELD(FOptionMenuSettings, mFontColorValue) -DEFINE_FIELD(FOptionMenuSettings, mFontColorMore) -DEFINE_FIELD(FOptionMenuSettings, mFontColorHeader) -DEFINE_FIELD(FOptionMenuSettings, mFontColorHighlight) -DEFINE_FIELD(FOptionMenuSettings, mFontColorSelection) -DEFINE_FIELD(FOptionMenuSettings, mLinespacing) - - -struct IJoystickConfig; -// These functions are used by dynamic menu creation. -DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, int v) -{ - auto c = PClass::FindClass("OptionMenuItemStaticText"); - auto p = c->CreateNew(); - FString namestr = name; - VMValue params[] = { p, &namestr, v }; - auto f = dyn_cast(c->FindSymbol("Init", false)); - VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); - return (DMenuItemBase*)p; -} - -DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy) -{ - auto c = PClass::FindClass("OptionMenuItemJoyConfigMenu"); - auto p = c->CreateNew(); - FString namestr = label; - VMValue params[] = { p, &namestr, joy }; - auto f = dyn_cast(c->FindSymbol("Init", false)); - VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); - return (DMenuItemBase*)p; -} - -DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center) -{ - auto c = PClass::FindClass("OptionMenuItemSubmenu"); - auto p = c->CreateNew(); - FString namestr = label; - VMValue params[] = { p, &namestr, cmd.GetIndex(), center, false }; - auto f = dyn_cast(c->FindSymbol("Init", false)); - VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); - return (DMenuItemBase*)p; -} - -DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings) -{ - auto c = PClass::FindClass("OptionMenuItemControlBase"); - auto p = c->CreateNew(); - FString namestr = label; - VMValue params[] = { p, &namestr, cmd.GetIndex(), bindings }; - auto f = dyn_cast(c->FindSymbol("Init", false)); - VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); - return (DMenuItemBase*)p; -} - -DMenuItemBase * CreateOptionMenuItemCommand(const char *label, FName cmd, bool centered) -{ - auto c = PClass::FindClass("OptionMenuItemCommand"); - auto p = c->CreateNew(); - FString namestr = label; - VMValue params[] = { p, &namestr, cmd.GetIndex(), centered, false }; - auto f = dyn_cast(c->FindSymbol("Init", false)); - VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); - auto unsafe = dyn_cast(c->FindSymbol("mUnsafe", false)); - unsafe->Type->SetValue(reinterpret_cast(p) + unsafe->Offset, 0); - return (DMenuItemBase*)p; -} - -DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param) -{ - auto c = PClass::FindClass("ListMenuItemPatchItem"); - auto p = c->CreateNew(); - FString keystr = FString(char(hotkey)); - VMValue params[] = { p, x, y, height, tex.GetIndex(), &keystr, command.GetIndex(), param }; - auto f = dyn_cast(c->FindSymbol("InitDirect", false)); - VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); - return (DMenuItemBase*)p; -} - -DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param) -{ - auto c = PClass::FindClass("ListMenuItemTextItem"); - auto p = c->CreateNew(); - FString keystr = FString(char(hotkey)); - FString textstr = text; - VMValue params[] = { p, x, y, height, &keystr, &textstr, font, int(color1.d), int(color2.d), command.GetIndex(), param }; - auto f = dyn_cast(c->FindSymbol("InitDirect", false)); - VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); - return (DMenuItemBase*)p; -} - -bool DMenuItemBase::Activate() -{ - IFVIRTUAL(DMenuItemBase, Activate) - { - VMValue params[] = { (DObject*)this }; - int retval; - VMReturn ret(&retval); - VMCall(func, params, countof(params), &ret, 1); - return !!retval; - } - return false; -} - -bool DMenuItemBase::SetString(int i, const char *s) -{ - IFVIRTUAL(DMenuItemBase, SetString) - { - FString namestr = s; - VMValue params[] = { (DObject*)this, i, &namestr }; - int retval; - VMReturn ret(&retval); - VMCall(func, params, countof(params), &ret, 1); - return !!retval; - } - return false; -} - -bool DMenuItemBase::GetString(int i, char *s, int len) -{ - IFVIRTUAL(DMenuItemBase, GetString) - { - VMValue params[] = { (DObject*)this, i }; - int retval; - FString retstr; - VMReturn ret[2]; ret[0].IntAt(&retval); ret[1].StringAt(&retstr); - VMCall(func, params, countof(params), ret, 2); - strncpy(s, retstr, len); - return !!retval; - } - return false; -} - - -bool DMenuItemBase::SetValue(int i, int value) -{ - IFVIRTUAL(DMenuItemBase, SetValue) - { - VMValue params[] = { (DObject*)this, i, value }; - int retval; - VMReturn ret(&retval); - VMCall(func, params, countof(params), &ret, 1); - return !!retval; - } - return false; -} - -bool DMenuItemBase::GetValue(int i, int *pvalue) -{ - IFVIRTUAL(DMenuItemBase, GetValue) - { - VMValue params[] = { (DObject*)this, i }; - int retval[2]; - VMReturn ret[2]; ret[0].IntAt(&retval[0]); ret[1].IntAt(&retval[1]); - VMCall(func, params, countof(params), ret, 2); - *pvalue = retval[1]; - return !!retval[0]; - } - return false; -} - -IMPLEMENT_CLASS(DMenuItemBase, false, false) diff --git a/src/menu/menu.h b/src/menu/menu.h deleted file mode 100644 index d93dabd8c86..00000000000 --- a/src/menu/menu.h +++ /dev/null @@ -1,369 +0,0 @@ -#ifndef __M_MENU_MENU_H__ -#define __M_MENU_MENU_H__ - - - - -#include "dobject.h" -#include "d_player.h" -#include "r_data/r_translate.h" -#include "c_cvars.h" -#include "v_font.h" -#include "gi.h" -#include "textures/textures.h" - -EXTERN_CVAR(Float, snd_menuvolume) -EXTERN_CVAR(Int, m_use_mouse); - - -struct event_t; -class FTexture; -class FFont; -enum EColorRange : int; -class FPlayerClass; -class FKeyBindings; -struct FBrokenLines; - -enum EMenuKey -{ - MKEY_Up, - MKEY_Down, - MKEY_Left, - MKEY_Right, - MKEY_PageUp, - MKEY_PageDown, - //----------------- Keys past here do not repeat. - MKEY_Enter, - MKEY_Back, // Back to previous menu - MKEY_Clear, // Clear keybinding/flip player sprite preview - NUM_MKEYS, - - // These are not buttons but events sent from other menus - - MKEY_Input, // Sent when input is confirmed - MKEY_Abort, // Input aborted - MKEY_MBYes, - MKEY_MBNo, -}; - - -struct FGameStartup -{ - const char *PlayerClass; - int Episode; - int Skill; -}; - -extern FGameStartup GameStartupInfo; - -struct FSaveGameNode -{ - FString SaveTitle; - FString Filename; - bool bOldVersion = false; - bool bMissingWads = false; - bool bNoDelete = false; -}; - -struct FSavegameManager -{ -private: - TArray SaveGames; - FSaveGameNode NewSaveNode; - int LastSaved = -1; - int LastAccessed = -1; - TArray SavePicData; - FTexture *SavePic = nullptr; - -public: - int WindowSize = 0; - FString SaveCommentString; - FSaveGameNode *quickSaveSlot = nullptr; - ~FSavegameManager(); - -private: - int InsertSaveNode(FSaveGameNode *node); -public: - void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave); - void ClearSaveGames(); - - void ReadSaveStrings(); - void UnloadSaveData(); - - int RemoveSaveSlot(int index); - void LoadSavegame(int Selected); - void DoSave(int Selected, const char *savegamestring); - unsigned ExtractSaveData(int index); - void ClearSaveStuff(); - bool DrawSavePic(int x, int y, int w, int h); - void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor); - void SetFileInfo(int Selected); - unsigned SavegameCount(); - FSaveGameNode *GetSavegame(int i); - void InsertNewSaveNode(); - bool RemoveNewSaveNode(); - -}; - -extern FSavegameManager savegameManager; -class DMenu; -extern DMenu *CurrentMenu; -extern int MenuTime; -class DMenuItemBase; - -//============================================================================= -// -// menu descriptor. This is created from the menu definition lump -// Items must be inserted in the order they are cycled through with the cursor -// -//============================================================================= - -class DMenuDescriptor : public DObject -{ - DECLARE_CLASS(DMenuDescriptor, DObject) -public: - FName mMenuName = NAME_None; - FString mNetgameMessage; - PClass *mClass = nullptr; - bool mProtected = false; - TArray mItems; - - virtual size_t PropagateMark() { return 0; } -}; - - -class DListMenuDescriptor : public DMenuDescriptor -{ - DECLARE_CLASS(DListMenuDescriptor, DMenuDescriptor) - -public: - int mSelectedItem; - double mSelectOfsX; - double mSelectOfsY; - FTextureID mSelector; - int mDisplayTop; - double mXpos, mYpos; - int mWLeft, mWRight; - int mLinespacing; // needs to be stored for dynamically created menus - int mAutoselect; // this can only be set by internal menu creation functions - FFont *mFont; - EColorRange mFontColor; - EColorRange mFontColor2; - bool mCenter; - bool mFromEngine; - - void Reset() - { - // Reset the default settings (ignore all other values in the struct) - mSelectOfsX = 0; - mSelectOfsY = 0; - mSelector.SetInvalid(); - mDisplayTop = 0; - mXpos = 0; - mYpos = 0; - mLinespacing = 0; - mNetgameMessage = ""; - mFont = NULL; - mFontColor = CR_UNTRANSLATED; - mFontColor2 = CR_UNTRANSLATED; - mFromEngine = false; - } - - size_t PropagateMark() override; -}; - -struct FOptionMenuSettings -{ - EColorRange mTitleColor; - EColorRange mFontColor; - EColorRange mFontColorValue; - EColorRange mFontColorMore; - EColorRange mFontColorHeader; - EColorRange mFontColorHighlight; - EColorRange mFontColorSelection; - int mLinespacing; -}; - -class DOptionMenuDescriptor : public DMenuDescriptor -{ - DECLARE_CLASS(DOptionMenuDescriptor, DMenuDescriptor) - -public: - FString mTitle; - int mSelectedItem; - int mDrawTop; - int mScrollTop; - int mScrollPos; - int mIndent; - int mPosition; - bool mDontDim; - FFont *mFont; - - void CalcIndent(); - DMenuItemBase *GetItem(FName name); - void Reset() - { - // Reset the default settings (ignore all other values in the struct) - mPosition = 0; - mScrollTop = 0; - mIndent = 0; - mDontDim = 0; - mFont = gameinfo.gametype == GAME_Doom ? BigUpper : BigFont; - - } - size_t PropagateMark() override; - ~DOptionMenuDescriptor() - { - } -}; - - -typedef TMap MenuDescriptorList; - -extern FOptionMenuSettings OptionSettings; -extern MenuDescriptorList MenuDescriptors; - -#define CURSORSPACE (14 * CleanXfac_1) - -//============================================================================= -// -// -// -//============================================================================= - -struct FMenuRect -{ - int x, y; - int width, height; - - void set(int _x, int _y, int _w, int _h) - { - x = _x; - y = _y; - width = _w; - height = _h; - } - - bool inside(int _x, int _y) - { - return _x >= x && _x < x+width && _y >= y && _y < y+height; - } - -}; - - -class DMenu : public DObject -{ - DECLARE_CLASS (DMenu, DObject) - HAS_OBJECT_POINTERS - - - -public: - enum - { - MOUSE_Click, - MOUSE_Move, - MOUSE_Release - }; - - TObjPtr mParentMenu; - bool mMouseCapture; - bool mBackbuttonSelected; - bool DontDim; - bool DontBlur; - static int InMenu; - - DMenu(DMenu *parent = NULL); - bool TranslateKeyboardEvents(); - virtual void Close(); - - bool CallResponder(event_t *ev); - bool CallMenuEvent(int mkey, bool fromcontroller); - void CallTicker(); - void CallDrawer(); -}; - -//============================================================================= -// -// base class for menu items -// -//============================================================================= - -class DMenuItemBase : public DObject -{ - DECLARE_CLASS(DMenuItemBase, DObject) -public: - double mXpos, mYpos; - FName mAction; - bool mEnabled; - - bool Activate(); - bool SetString(int i, const char *s); - bool GetString(int i, char *s, int len); - bool SetValue(int i, int value); - bool GetValue(int i, int *pvalue); - void OffsetPositionY(int ydelta) { mYpos += ydelta; } - double GetY() { return mYpos; } -}; - -//============================================================================= -// -// -// -//============================================================================= -struct FOptionValues -{ - struct Pair - { - double Value; - FString TextValue; - FString Text; - }; - - TArray mValues; -}; - -typedef TMap< FName, FOptionValues* > FOptionMap; - -extern FOptionMap OptionValues; - - -//============================================================================= -// -// -// -//============================================================================= - -struct event_t; -void M_EnableMenu (bool on) ; -bool M_Responder (event_t *ev); -void M_Ticker (void); -void M_Drawer (void); -void M_Init (void); -void M_CreateMenus(); -void M_ActivateMenu(DMenu *menu); -void M_ClearMenus (); -void M_PreviousMenu (); -void M_ParseMenuDefs(); -void M_StartupEpisodeMenu(FGameStartup *gs); -void M_StartupSkillMenu(FGameStartup *gs); -void M_StartControlPanel (bool makeSound, bool scaleoverride = false); -void M_SetMenu(FName menu, int param = -1); -void M_StartMessage(const char *message, int messagemode, FName action = NAME_None); -DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar); -void M_MarkMenus(); - - -struct IJoystickConfig; -DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, int v = -1); -DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center); -DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings); -DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy); -DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param); -DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param); -DMenuItemBase * CreateOptionMenuItemCommand(const char *label, FName cmd, bool centered = false); - -void UpdateVRModes(bool considerQuadBuffered=true); - -#endif diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp deleted file mode 100644 index 3d12ec50c9a..00000000000 --- a/src/menu/menudef.cpp +++ /dev/null @@ -1,1883 +0,0 @@ -/* -** menudef.cpp -** MENUDEF parser amd menu generation code -** -**--------------------------------------------------------------------------- -** Copyright 2010 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ -#include - -#include "menu/menu.h" -#include "w_wad.h" -#include "c_bind.h" -#include "i_music.h" -#include "gi.h" -#include "i_sound.h" -#include "cmdlib.h" -#include "vm.h" -#include "types.h" -#include "gameconfigfile.h" -#include "m_argv.h" -#include "i_soundfont.h" -#include "i_system.h" -#include "v_video.h" -#include "gstrings.h" -#include "teaminfo.h" -#include "r_data/sprites.h" -#include - - -void ClearSaveGames(); - -MenuDescriptorList MenuDescriptors; -static DListMenuDescriptor *DefaultListMenuSettings; // contains common settings for all list menus -static DOptionMenuDescriptor *DefaultOptionMenuSettings; // contains common settings for all Option menus -FOptionMenuSettings OptionSettings; -FOptionMap OptionValues; -bool mustPrintErrors; -PClass *DefaultListMenuClass; -PClass *DefaultOptionMenuClass; - -void I_BuildALDeviceList(FOptionValues *opt); -void I_BuildALResamplersList(FOptionValues *opt); - -DEFINE_GLOBAL_NAMED(OptionSettings, OptionMenuSettings) - -DEFINE_ACTION_FUNCTION(FOptionValues, GetCount) -{ - PARAM_PROLOGUE; - PARAM_NAME(grp); - int cnt = 0; - FOptionValues **pGrp = OptionValues.CheckKey(grp); - if (pGrp != nullptr) - { - cnt = (*pGrp)->mValues.Size(); - } - ACTION_RETURN_INT(cnt); -} - -DEFINE_ACTION_FUNCTION(FOptionValues, GetValue) -{ - PARAM_PROLOGUE; - PARAM_NAME(grp); - PARAM_UINT(index); - double val = 0; - FOptionValues **pGrp = OptionValues.CheckKey(grp); - if (pGrp != nullptr) - { - if (index < (*pGrp)->mValues.Size()) - { - val = (*pGrp)->mValues[index].Value; - } - } - ACTION_RETURN_FLOAT(val); -} - -DEFINE_ACTION_FUNCTION(FOptionValues, GetTextValue) -{ - PARAM_PROLOGUE; - PARAM_NAME(grp); - PARAM_UINT(index); - FString val; - FOptionValues **pGrp = OptionValues.CheckKey(grp); - if (pGrp != nullptr) - { - if (index < (*pGrp)->mValues.Size()) - { - val = (*pGrp)->mValues[index].TextValue; - } - } - ACTION_RETURN_STRING(val); -} - -DEFINE_ACTION_FUNCTION(FOptionValues, GetText) -{ - PARAM_PROLOGUE; - PARAM_NAME(grp); - PARAM_UINT(index); - FString val; - FOptionValues **pGrp = OptionValues.CheckKey(grp); - if (pGrp != nullptr) - { - if (index < (*pGrp)->mValues.Size()) - { - val = (*pGrp)->mValues[index].Text; - } - } - ACTION_RETURN_STRING(val); -} - - -void DeinitMenus() -{ - M_ClearMenus(); - { - FOptionMap::Iterator it(OptionValues); - - FOptionMap::Pair *pair; - - while (it.NextPair(pair)) - { - delete pair->Value; - pair->Value = nullptr; - } - } - MenuDescriptors.Clear(); - OptionValues.Clear(); - savegameManager.ClearSaveGames(); -} - -static FTextureID GetMenuTexture(const char* const name) -{ - const FTextureID texture = TexMan.CheckForTexture(name, ETextureType::MiscPatch); - - if (!texture.Exists() && mustPrintErrors) - { - Printf("Missing menu texture: \"%s\"\n", name); - } - - return texture; -} - -//============================================================================= -// -// -// -//============================================================================= - -static void SkipSubBlock(FScanner &sc) -{ - sc.MustGetStringName("{"); - int depth = 1; - while (depth > 0) - { - sc.MustGetString(); - if (sc.Compare("{")) depth++; - if (sc.Compare("}")) depth--; - } -} - -//============================================================================= -// -// -// -//============================================================================= - -static bool CheckSkipGameBlock(FScanner &sc) -{ - bool filter = false; - sc.MustGetStringName("("); - do - { - sc.MustGetString(); - filter |= CheckGame(sc.String, false); - } - while (sc.CheckString(",")); - sc.MustGetStringName(")"); - if (!filter) - { - SkipSubBlock(sc); - return !sc.CheckString("else"); - } - return false; -} - -//============================================================================= -// -// -// -//============================================================================= - -static bool CheckSkipOptionBlock(FScanner &sc) -{ - bool filter = false; - sc.MustGetStringName("("); - do - { - sc.MustGetString(); - if (sc.Compare("ReadThis")) filter |= gameinfo.drawreadthis; - else if (sc.Compare("Swapmenu")) filter |= gameinfo.swapmenu; - else if (sc.Compare("Windows")) - { - #ifdef _WIN32 - filter = true; - #endif - } - else if (sc.Compare("unix")) - { - #ifdef __unix__ - filter = true; - #endif - } - else if (sc.Compare("Mac")) - { - #ifdef __APPLE__ - filter = true; - #endif - } - else if (sc.Compare("OpenAL")) - { - filter |= IsOpenALPresent(); - } - else if (sc.Compare("MMX")) - { - #ifdef HAVE_MMX - filter = true; - #endif - } - } - while (sc.CheckString(",")); - sc.MustGetStringName(")"); - if (!filter) - { - SkipSubBlock(sc); - return !sc.CheckString("else"); - } - return false; -} - -//============================================================================= -// -// -// -//============================================================================= - -static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) -{ - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) - { - sc.MustGetString(); - if (sc.Compare("else")) - { - SkipSubBlock(sc); - } - else if (sc.Compare("ifgame")) - { - if (!CheckSkipGameBlock(sc)) - { - // recursively parse sub-block - ParseListMenuBody(sc, desc); - } - } - else if (sc.Compare("ifoption")) - { - if (!CheckSkipOptionBlock(sc)) - { - // recursively parse sub-block - ParseListMenuBody(sc, desc); - } - } - else if (sc.Compare("Class")) - { - sc.MustGetString(); - PClass *cls = PClass::FindClass(sc.String); - if (cls == nullptr || !cls->IsDescendantOf("ListMenu")) - { - sc.ScriptError("Unknown menu class '%s'", sc.String); - } - desc->mClass = cls; - } - else if (sc.Compare("Selector")) - { - sc.MustGetString(); - desc->mSelector = GetMenuTexture(sc.String); - sc.MustGetStringName(","); - sc.MustGetFloat(); - desc->mSelectOfsX = sc.Float; - sc.MustGetStringName(","); - sc.MustGetFloat(); - desc->mSelectOfsY = sc.Float; - } - else if (sc.Compare("Linespacing")) - { - sc.MustGetNumber(); - desc->mLinespacing = sc.Number; - } - else if (sc.Compare("Position")) - { - sc.MustGetFloat(); - desc->mXpos = sc.Float; - sc.MustGetStringName(","); - sc.MustGetFloat(); - desc->mYpos = sc.Float; - } - else if (sc.Compare("Centermenu")) - { - desc->mCenter = true; - } - else if (sc.Compare("MouseWindow")) - { - sc.MustGetNumber(); - desc->mWLeft = sc.Number; - sc.MustGetStringName(","); - sc.MustGetNumber(); - desc->mWRight = sc.Number; - } - else if (sc.Compare("Font")) - { - sc.MustGetString(); - FFont *newfont = V_GetFont(sc.String); - if (newfont != nullptr) desc->mFont = newfont; - if (sc.CheckString(",")) - { - sc.MustGetString(); - desc->mFontColor2 = desc->mFontColor = V_FindFontColor((FName)sc.String); - if (sc.CheckString(",")) - { - sc.MustGetString(); - desc->mFontColor2 = V_FindFontColor((FName)sc.String); - } - } - else - { - desc->mFontColor = OptionSettings.mFontColor; - desc->mFontColor2 = OptionSettings.mFontColorValue; - } - } - else if (sc.Compare("NetgameMessage")) - { - sc.MustGetString(); - desc->mNetgameMessage = sc.String; - } - else - { - bool success = false; - FStringf buildname("ListMenuItem%s", sc.String); - PClass *cls = PClass::FindClass(buildname); - if (cls != nullptr && cls->IsDescendantOf("ListMenuItem")) - { - auto func = dyn_cast(cls->FindSymbol("Init", true)); - if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protected init method. - { - auto &args = func->Variants[0].Proto->ArgumentTypes; - TArray params; - int start = 1; - - params.Push(0); - if (args.Size() > 1 && args[1] == NewPointer(PClass::FindClass("ListMenuDescriptor"))) - { - params.Push(desc); - start = 2; - } - auto TypeCVar = NewPointer(NewStruct("CVar", nullptr, true)); - - // Note that this array may not be reallocated so its initial size must be the maximum possible elements. - TArray strings(args.Size()); - for (unsigned i = start; i < args.Size(); i++) - { - sc.MustGetString(); - if (args[i] == TypeString) - { - strings.Push(sc.String); - params.Push(&strings.Last()); - } - else if (args[i] == TypeName) - { - params.Push(FName(sc.String).GetIndex()); - } - else if (args[i] == TypeColor) - { - params.Push(V_GetColor(nullptr, sc)); - } - else if (args[i] == TypeFont) - { - auto f = V_GetFont(sc.String); - if (f == nullptr) - { - sc.ScriptError("Unknown font %s", sc.String); - } - params.Push(f); - } - else if (args[i] == TypeTextureID) - { - auto f = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); - if (!f.Exists()) - { - sc.ScriptMessage("Unknown texture %s", sc.String); - } - params.Push(f.GetIndex()); - } - else if (args[i]->isIntCompatible()) - { - char *endp; - int v = (int)strtoll(sc.String, &endp, 0); - if (*endp != 0) - { - // special check for font color ranges. - v = V_FindFontColor(sc.String); - if (v == CR_UNTRANSLATED && !sc.Compare("untranslated")) - { - // todo: check other data types that may get used. - sc.ScriptError("Integer expected, got %s", sc.String); - } - } - if (args[i] == TypeBool) v = !!v; - params.Push(v); - } - else if (args[i]->isFloat()) - { - char *endp; - double v = strtod(sc.String, &endp); - if (*endp != 0) - { - sc.ScriptError("Float expected, got %s", sc.String); - } - params.Push(v); - } - else if (args[i] == TypeCVar) - { - auto cv = FindCVar(sc.String, nullptr); - if (cv == nullptr && *sc.String) - { - sc.ScriptError("Unknown CVar %s", sc.String); - } - params.Push(cv); - } - else - { - sc.ScriptError("Invalid parameter type %s for menu item", args[i]->DescriptiveName()); - } - if (sc.CheckString(",")) - { - if (i == args.Size() - 1) - { - sc.ScriptError("Too many parameters for %s", cls->TypeName.GetChars()); - } - } - else - { - if (i < args.Size() - 1 && !(func->Variants[0].ArgFlags[i + 1] & VARF_Optional)) - { - sc.ScriptError("Insufficient parameters for %s", cls->TypeName.GetChars()); - } - break; - } - } - DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew(); - params[0] = item; - VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0); - desc->mItems.Push((DMenuItemBase*)item); - - if (cls->IsDescendantOf("ListMenuItemSelectable")) - { - desc->mYpos += desc->mLinespacing; - if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size() - 1; - } - success = true; - } - } - if (!success) - { - sc.ScriptError("Unknown keyword '%s'", sc.String); - } - } - } - for (auto &p : desc->mItems) - { - GC::WriteBarrier(p); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -static bool CheckCompatible(DMenuDescriptor *newd, DMenuDescriptor *oldd) -{ - if (oldd->mClass == nullptr) return true; - return newd->mClass->IsDescendantOf(oldd->mClass); -} - -static int GetGroup(DMenuItemBase *desc) -{ - if (desc->IsKindOf(NAME_OptionMenuItemCommand)) return 2; - if (desc->IsKindOf(NAME_OptionMenuItemSubmenu)) return 1; - if (desc->IsKindOf(NAME_OptionMenuItemControlBase)) return 3; - if (desc->IsKindOf(NAME_OptionMenuItemOptionBase)) return 4; - if (desc->IsKindOf(NAME_OptionMenuSliderBase)) return 4; - if (desc->IsKindOf(NAME_OptionMenuFieldBase)) return 4; - if (desc->IsKindOf(NAME_OptionMenuItemColorPicker)) return 4; - if (desc->IsKindOf(NAME_OptionMenuItemStaticText)) return 5; - if (desc->IsKindOf(NAME_OptionMenuItemStaticTextSwitchable)) return 5; - return 0; -} - -static bool FindMatchingItem(DMenuItemBase *desc) -{ - int grp = GetGroup(desc); - if (grp == 0) return false; // no idea what this is. - if (grp == 5) return true; // static texts always match - - FName name = desc->mAction; - - if (grp == 1) - { - // Check for presence of menu - auto menu = MenuDescriptors.CheckKey(name); - if (menu == nullptr) return false; - } - else if (grp == 4) - { - static const FName CVarBlacklist[] = { - NAME_snd_waterlp, NAME_snd_output, NAME_snd_output_format, NAME_snd_speakermode, NAME_snd_resampler, NAME_AlwaysRun }; - - // Check for presence of CVAR and blacklist - auto cv = FindCVar(name.GetChars(), nullptr); - if (cv == nullptr) return true; - - for (auto bname : CVarBlacklist) - { - if (name == bname) return true; - } - } - - MenuDescriptorList::Iterator it(MenuDescriptors); - MenuDescriptorList::Pair *pair; - while (it.NextPair(pair)) - { - for (auto it : pair->Value->mItems) - { - if (it->mAction == name && GetGroup(it) == grp) return true; - } - } - return false; -} - -static bool ReplaceMenu(FScanner &sc, DMenuDescriptor *desc) -{ - DMenuDescriptor **pOld = MenuDescriptors.CheckKey(desc->mMenuName); - if (pOld != nullptr && *pOld != nullptr) - { - if ((*pOld)->mProtected) - { - // If this tries to replace an option menu with an option menu, let's append all new entries to the old menu. - // Otherwise bail out because for list menus it's not that simple. - if (desc->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor)) || (*pOld)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) - { - sc.ScriptMessage("Cannot replace protected menu %s.", desc->mMenuName.GetChars()); - return true; - } - for (int i = desc->mItems.Size()-1; i >= 0; i--) - { - if (FindMatchingItem(desc->mItems[i])) - { - desc->mItems.Delete(i); - } - } - if (desc->mItems.Size() > 0) - { - auto sep = CreateOptionMenuItemStaticText(" "); - (*pOld)->mItems.Push(sep); - sep = CreateOptionMenuItemStaticText("---------------", 1); - (*pOld)->mItems.Push(sep); - for (auto it : desc->mItems) - { - (*pOld)->mItems.Push(it); - } - desc->mItems.Clear(); - //sc.ScriptMessage("Merged %d items into %s", desc->mItems.Size(), desc->mMenuName.GetChars()); - } - return true; - } - - if (!CheckCompatible(desc, *pOld)) - { - sc.ScriptMessage("Tried to replace menu '%s' with a menu of different type", desc->mMenuName.GetChars()); - return true; - } - } - MenuDescriptors[desc->mMenuName] = desc; - GC::WriteBarrier(desc); - return false; -} - -//============================================================================= -// -// -// -//============================================================================= - -static void ParseListMenu(FScanner &sc) -{ - sc.MustGetString(); - - DListMenuDescriptor *desc = Create(); - desc->mMenuName = sc.String; - desc->mSelectedItem = -1; - desc->mAutoselect = -1; - desc->mSelectOfsX = DefaultListMenuSettings->mSelectOfsX; - desc->mSelectOfsY = DefaultListMenuSettings->mSelectOfsY; - desc->mSelector = DefaultListMenuSettings->mSelector; - desc->mDisplayTop = DefaultListMenuSettings->mDisplayTop; - desc->mXpos = DefaultListMenuSettings->mXpos; - desc->mYpos = DefaultListMenuSettings->mYpos; - desc->mLinespacing = DefaultListMenuSettings->mLinespacing; - desc->mNetgameMessage = DefaultListMenuSettings->mNetgameMessage; - desc->mFont = DefaultListMenuSettings->mFont; - desc->mFontColor = DefaultListMenuSettings->mFontColor; - desc->mFontColor2 = DefaultListMenuSettings->mFontColor2; - desc->mClass = nullptr; - desc->mWLeft = 0; - desc->mWRight = 0; - desc->mCenter = false; - desc->mFromEngine = Wads.GetLumpFile(sc.LumpNum) == 0; // flags menu if the definition is from the IWAD. - - ParseListMenuBody(sc, desc); - ReplaceMenu(sc, desc); -} - -//============================================================================= -// -// -// -//============================================================================= - -static void ParseOptionValue(FScanner &sc) -{ - FOptionValues *val = new FOptionValues; - sc.MustGetString(); - FName optname = sc.String; - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) - { - FOptionValues::Pair &pair = val->mValues[val->mValues.Reserve(1)]; - sc.MustGetFloat(); - pair.Value = sc.Float; - sc.MustGetStringName(","); - sc.MustGetString(); - pair.Text = strbin1(sc.String); - } - FOptionValues **pOld = OptionValues.CheckKey(optname); - if (pOld != nullptr && *pOld != nullptr) - { - delete *pOld; - } - OptionValues[optname] = val; -} - - -//============================================================================= -// -// -// -//============================================================================= - -static void ParseOptionString(FScanner &sc) -{ - FOptionValues *val = new FOptionValues; - sc.MustGetString(); - FName optname = sc.String; - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) - { - FOptionValues::Pair &pair = val->mValues[val->mValues.Reserve(1)]; - sc.MustGetString(); - pair.Value = DBL_MAX; - pair.TextValue = sc.String; - sc.MustGetStringName(","); - sc.MustGetString(); - pair.Text = strbin1(sc.String); - } - FOptionValues **pOld = OptionValues.CheckKey(optname); - if (pOld != nullptr && *pOld != nullptr) - { - delete *pOld; - } - OptionValues[optname] = val; -} - - -//============================================================================= -// -// -// -//============================================================================= - -static void ParseOptionSettings(FScanner &sc) -{ - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) - { - sc.MustGetString(); - if (sc.Compare("else")) - { - SkipSubBlock(sc); - } - else if (sc.Compare("ifgame")) - { - if (!CheckSkipGameBlock(sc)) - { - // recursively parse sub-block - ParseOptionSettings(sc); - } - } - else if (sc.Compare("Linespacing")) - { - sc.MustGetNumber(); - OptionSettings.mLinespacing = sc.Number; - } - else if (sc.Compare("LabelOffset")) - { - sc.MustGetNumber(); - // ignored - } - else - { - sc.ScriptError("Unknown keyword '%s'", sc.String); - } - } -} - -//============================================================================= -// -// -// -//============================================================================= - -static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) -{ - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) - { - sc.MustGetString(); - if (sc.Compare("else")) - { - SkipSubBlock(sc); - } - else if (sc.Compare("ifgame")) - { - if (!CheckSkipGameBlock(sc)) - { - // recursively parse sub-block - ParseOptionMenuBody(sc, desc); - } - } - else if (sc.Compare("ifoption")) - { - if (!CheckSkipOptionBlock(sc)) - { - // recursively parse sub-block - ParseOptionMenuBody(sc, desc); - } - } - else if (sc.Compare("Class")) - { - sc.MustGetString(); - PClass *cls = PClass::FindClass(sc.String); - if (cls == nullptr || !cls->IsDescendantOf("OptionMenu")) - { - sc.ScriptError("Unknown menu class '%s'", sc.String); - } - desc->mClass = cls; - } - else if (sc.Compare("Title")) - { - sc.MustGetString(); - desc->mTitle = sc.String; - } - else if (sc.Compare("Position")) - { - sc.MustGetNumber(); - desc->mPosition = sc.Number; - } - else if (sc.Compare("DefaultSelection")) - { - sc.MustGetNumber(); - desc->mSelectedItem = sc.Number; - } - else if (sc.Compare("ScrollTop")) - { - sc.MustGetNumber(); - desc->mScrollTop = sc.Number; - } - else if (sc.Compare("Indent")) - { - sc.MustGetNumber(); - desc->mIndent = sc.Number; - } - else - { - bool success = false; - FStringf buildname("OptionMenuItem%s", sc.String); - // Handle one special case: MapControl maps to Control with one parameter different - PClass *cls = PClass::FindClass(buildname); - if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem")) - { - auto func = dyn_cast(cls->FindSymbol("Init", true)); - if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method. - { - auto &args = func->Variants[0].Proto->ArgumentTypes; - TArray params; - - params.Push(0); - auto TypeCVar = NewPointer(NewStruct("CVar", nullptr, true)); - - // Note that this array may not be reallocated so its initial size must be the maximum possible elements. - TArray strings(args.Size()); - for (unsigned i = 1; i < args.Size(); i++) - { - sc.MustGetString(); - if (args[i] == TypeString) - { - strings.Push(sc.String); - params.Push(&strings.Last()); - } - else if (args[i] == TypeName) - { - params.Push(FName(sc.String).GetIndex()); - } - else if (args[i] == TypeColor) - { - params.Push(V_GetColor(nullptr, sc)); - } - else if (args[i]->isIntCompatible()) - { - char *endp; - int v = (int)strtoll(sc.String, &endp, 0); - if (*endp != 0) - { - // special check for font color ranges. - v = V_FindFontColor(sc.String); - if (v == CR_UNTRANSLATED && !sc.Compare("untranslated")) - { - // todo: check other data types that may get used. - sc.ScriptError("Integer expected, got %s", sc.String); - } - // Color ranges need to be marked for option menu items to support an older feature where a boolean number could be passed instead. - v |= 0x12340000; - } - if (args[i] == TypeBool) v = !!v; - params.Push(v); - } - else if (args[i]->isFloat()) - { - char *endp; - double v = strtod(sc.String, &endp); - if (*endp != 0) - { - sc.ScriptError("Float expected, got %s", sc.String); - } - params.Push(v); - } - else if (args[i] == TypeCVar) - { - auto cv = FindCVar(sc.String, nullptr); - if (cv == nullptr && *sc.String) - { - if (func->Variants[0].ArgFlags[i] & VARF_Optional) - sc.ScriptMessage("Unknown CVar %s", sc.String); - else - sc.ScriptError("Unknown CVar %s", sc.String); - } - params.Push(cv); - } - else - { - sc.ScriptError("Invalid parameter type %s for menu item", args[i]->DescriptiveName()); - } - if (sc.CheckString(",")) - { - if (i == args.Size() - 1) - { - sc.ScriptError("Too many parameters for %s", cls->TypeName.GetChars()); - } - } - else - { - if (i < args.Size() - 1 && !(func->Variants[0].ArgFlags[i + 1] & VARF_Optional)) - { - sc.ScriptError("Insufficient parameters for %s", cls->TypeName.GetChars()); - } - break; - } - } - - DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew(); - params[0] = item; - VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0); - desc->mItems.Push((DMenuItemBase*)item); - - success = true; - } - } - if (!success) - { - sc.ScriptError("Unknown keyword '%s'", sc.String); - } - } - } - for (auto &p : desc->mItems) - { - GC::WriteBarrier(p); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -static void ParseOptionMenu(FScanner &sc) -{ - sc.MustGetString(); - - DOptionMenuDescriptor *desc = Create(); - desc->mFont = gameinfo.gametype == GAME_Doom ? BigUpper : BigFont; - desc->mMenuName = sc.String; - desc->mSelectedItem = -1; - desc->mScrollPos = 0; - desc->mClass = nullptr; - desc->mPosition = DefaultOptionMenuSettings->mPosition; - desc->mScrollTop = DefaultOptionMenuSettings->mScrollTop; - desc->mIndent = DefaultOptionMenuSettings->mIndent; - desc->mDontDim = DefaultOptionMenuSettings->mDontDim; - desc->mProtected = sc.CheckString("protected"); - - ParseOptionMenuBody(sc, desc); - ReplaceMenu(sc, desc); -} - - -//============================================================================= -// -// -// -//============================================================================= - -static void ParseAddOptionMenu(FScanner &sc) -{ - sc.MustGetString(); - - DMenuDescriptor **pOld = MenuDescriptors.CheckKey(sc.String); - if (pOld == nullptr || *pOld == nullptr || !(*pOld)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) - { - sc.ScriptError("%s is not an option menu that can be extended", sc.String); - } - ParseOptionMenuBody(sc, (DOptionMenuDescriptor*)(*pOld)); -} - - -//============================================================================= -// -// -// -//============================================================================= - -void M_ParseMenuDefs() -{ - int lump, lastlump = 0; - - OptionSettings.mTitleColor = V_FindFontColor(gameinfo.mTitleColor); - OptionSettings.mFontColor = V_FindFontColor(gameinfo.mFontColor); - OptionSettings.mFontColorValue = V_FindFontColor(gameinfo.mFontColorValue); - OptionSettings.mFontColorMore = V_FindFontColor(gameinfo.mFontColorMore); - OptionSettings.mFontColorHeader = V_FindFontColor(gameinfo.mFontColorHeader); - OptionSettings.mFontColorHighlight = V_FindFontColor(gameinfo.mFontColorHighlight); - OptionSettings.mFontColorSelection = V_FindFontColor(gameinfo.mFontColorSelection); - // these are supposed to get GC'd after parsing is complete. - DefaultListMenuSettings = Create(); - DefaultOptionMenuSettings = Create(); - DefaultListMenuSettings->Reset(); - DefaultOptionMenuSettings->Reset(); - - int IWADMenu = Wads.CheckNumForName("MENUDEF", ns_global, Wads.GetIwadNum()); - - while ((lump = Wads.FindLump ("MENUDEF", &lastlump)) != -1) - { - FScanner sc(lump); - - mustPrintErrors = lump >= IWADMenu; - sc.SetCMode(true); - while (sc.GetString()) - { - if (sc.Compare("LISTMENU")) - { - ParseListMenu(sc); - } - else if (sc.Compare("DEFAULTLISTMENU")) - { - ParseListMenuBody(sc, DefaultListMenuSettings); - if (DefaultListMenuSettings->mItems.Size() > 0) - { - I_FatalError("You cannot add menu items to the menu default settings."); - } - } - else if (sc.Compare("OPTIONVALUE")) - { - ParseOptionValue(sc); - } - else if (sc.Compare("OPTIONSTRING")) - { - ParseOptionString(sc); - } - else if (sc.Compare("OPTIONMENUSETTINGS")) - { - ParseOptionSettings(sc); - } - else if (sc.Compare("OPTIONMENU")) - { - ParseOptionMenu(sc); - } - else if (sc.Compare("ADDOPTIONMENU")) - { - ParseAddOptionMenu(sc); - } - else if (sc.Compare("DEFAULTOPTIONMENU")) - { - ParseOptionMenuBody(sc, DefaultOptionMenuSettings); - if (DefaultOptionMenuSettings->mItems.Size() > 0) - { - I_FatalError("You cannot add menu items to the menu default settings."); - } - } - else - { - sc.ScriptError("Unknown keyword '%s'", sc.String); - } - } - if (Args->CheckParm("-nocustommenu")) break; - } - DefaultListMenuClass = DefaultListMenuSettings->mClass; - DefaultListMenuSettings = nullptr; - DefaultOptionMenuClass = DefaultOptionMenuSettings->mClass; - DefaultOptionMenuSettings = nullptr; -} - - -//============================================================================= -// -// Creates the episode menu -// Falls back on an option menu if there's not enough screen space to show all episodes -// -//============================================================================= - -void M_StartupEpisodeMenu(FGameStartup *gs) -{ - // Build episode menu - bool success = false; - bool isOld = false; - DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Episodemenu); - if (desc != nullptr) - { - if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) - { - DListMenuDescriptor *ld = static_cast(*desc); - - // Delete previous contents - for(unsigned i=0; imItems.Size(); i++) - { - FName n = ld->mItems[i]->mAction; - if (n == NAME_Skillmenu) - { - isOld = true; - ld->mItems.Resize(i); - break; - } - } - - - int posx = (int)ld->mXpos; - int posy = (int)ld->mYpos; - int topy = posy; - - // Get lowest y coordinate of any static item in the menu - for(unsigned i = 0; i < ld->mItems.Size(); i++) - { - int y = (int)ld->mItems[i]->GetY(); - if (y < topy) topy = y; - } - - // center the menu on the screen if the top space is larger than the bottom space - int totalheight = posy + AllEpisodes.Size() * ld->mLinespacing - topy; - - if (totalheight < 190 || AllEpisodes.Size() == 1) - { - int newtop = (200 - totalheight + topy) / 2; - int topdelta = newtop - topy; - if (topdelta < 0) - { - for(unsigned i = 0; i < ld->mItems.Size(); i++) - { - ld->mItems[i]->OffsetPositionY(topdelta); - } - posy -= topdelta; - } - - if (!isOld) ld->mSelectedItem = ld->mItems.Size(); - - for (unsigned i = 0; i < AllEpisodes.Size(); i++) - { - DMenuItemBase *it = nullptr; - if (AllEpisodes[i].mPicName.IsNotEmpty()) - { - FTextureID tex = GetMenuTexture(AllEpisodes[i].mPicName); - if (AllEpisodes[i].mEpisodeName.IsEmpty() || TexMan.OkForLocalization(tex, AllEpisodes[i].mEpisodeName)) - continue; // We do not measure patch based entries. They are assumed to fit - } - const char *c = AllEpisodes[i].mEpisodeName; - if (*c == '$') c = GStrings(c + 1); - int textwidth = ld->mFont->StringWidth(c); - int textright = posx + textwidth; - if (posx + textright > 320) posx = std::max(0, 320 - textright); - } - - for(unsigned i = 0; i < AllEpisodes.Size(); i++) - { - DMenuItemBase *it = nullptr; - if (AllEpisodes[i].mPicName.IsNotEmpty()) - { - FTextureID tex = GetMenuTexture(AllEpisodes[i].mPicName); - if (AllEpisodes[i].mEpisodeName.IsEmpty() || TexMan.OkForLocalization(tex, AllEpisodes[i].mEpisodeName)) - it = CreateListMenuItemPatch(posx, posy, ld->mLinespacing, AllEpisodes[i].mShortcut, tex, NAME_Skillmenu, i); - } - if (it == nullptr) - { - it = CreateListMenuItemText(posx, posy, ld->mLinespacing, AllEpisodes[i].mShortcut, - AllEpisodes[i].mEpisodeName, ld->mFont, ld->mFontColor, ld->mFontColor2, NAME_Skillmenu, i); - } - ld->mItems.Push(it); - posy += ld->mLinespacing; - } - if (AllEpisodes.Size() == 1) - { - ld->mAutoselect = ld->mSelectedItem; - } - success = true; - for (auto &p : ld->mItems) - { - GC::WriteBarrier(*desc, p); - } - } - } - else return; // do not recreate the option menu variant, because it is always text based. - } - if (!success) - { - // Couldn't create the episode menu, either because there's too many episodes or some error occured - // Create an option menu for episode selection instead. - DOptionMenuDescriptor *od = Create(); - MenuDescriptors[NAME_Episodemenu] = od; - od->mMenuName = NAME_Episodemenu; - od->mFont = gameinfo.gametype == GAME_Doom ? BigUpper : BigFont; - od->mTitle = "$MNU_EPISODE"; - od->mSelectedItem = 0; - od->mScrollPos = 0; - od->mClass = nullptr; - od->mPosition = -15; - od->mScrollTop = 0; - od->mIndent = 160; - od->mDontDim = false; - GC::WriteBarrier(od); - for(unsigned i = 0; i < AllEpisodes.Size(); i++) - { - auto it = CreateOptionMenuItemSubmenu(AllEpisodes[i].mEpisodeName, "Skillmenu", i); - od->mItems.Push(it); - GC::WriteBarrier(od, it); - } - } -} - -//============================================================================= -// -// -// -//============================================================================= - -static void BuildPlayerclassMenu() -{ - bool success = false; - - // Build player class menu - DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Playerclassmenu); - if (desc != nullptr) - { - if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) - { - DListMenuDescriptor *ld = static_cast(*desc); - // add player display - - ld->mSelectedItem = ld->mItems.Size(); - - int posy = (int)ld->mYpos; - int topy = posy; - - // Get lowest y coordinate of any static item in the menu - for(unsigned i = 0; i < ld->mItems.Size(); i++) - { - int y = (int)ld->mItems[i]->GetY(); - if (y < topy) topy = y; - } - - // Count the number of items this menu will show - int numclassitems = 0; - for (unsigned i = 0; i < PlayerClasses.Size (); i++) - { - if (!(PlayerClasses[i].Flags & PCF_NOMENU)) - { - const char *pname = GetPrintableDisplayName(PlayerClasses[i].Type); - if (pname != nullptr) - { - numclassitems++; - } - } - } - - // center the menu on the screen if the top space is larger than the bottom space - int totalheight = posy + (numclassitems+1) * ld->mLinespacing - topy; - - if (numclassitems <= 1) - { - // create a dummy item that auto-chooses the default class. - auto it = CreateListMenuItemText(0, 0, 0, 'p', "player", - ld->mFont,ld->mFontColor, ld->mFontColor2, NAME_Episodemenu, -1000); - ld->mAutoselect = ld->mItems.Push(it); - success = true; - } - else if (totalheight <= 190) - { - int newtop = (200 - totalheight + topy) / 2; - int topdelta = newtop - topy; - if (topdelta < 0) - { - for(unsigned i = 0; i < ld->mItems.Size(); i++) - { - ld->mItems[i]->OffsetPositionY(topdelta); - } - posy -= topdelta; - } - - int n = 0; - for (unsigned i = 0; i < PlayerClasses.Size (); i++) - { - if (!(PlayerClasses[i].Flags & PCF_NOMENU)) - { - const char *pname = GetPrintableDisplayName(PlayerClasses[i].Type); - if (pname != nullptr) - { - auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname, - pname, ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, i); - ld->mItems.Push(it); - ld->mYpos += ld->mLinespacing; - n++; - } - } - } - if (n > 1 && !gameinfo.norandomplayerclass) - { - auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, 'r', - "$MNU_RANDOM", ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, -1); - ld->mItems.Push(it); - } - if (n == 0) - { - const char *pname = GetPrintableDisplayName(PlayerClasses[0].Type); - if (pname != nullptr) - { - auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname, - pname, ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, 0); - ld->mItems.Push(it); - } - } - success = true; - for (auto &p : ld->mItems) - { - GC::WriteBarrier(ld, p); - } - } - } - } - if (!success) - { - // Couldn't create the playerclass menu, either because there's too many episodes or some error occured - // Create an option menu for class selection instead. - DOptionMenuDescriptor *od = Create(); - MenuDescriptors[NAME_Playerclassmenu] = od; - od->mMenuName = NAME_Playerclassmenu; - od->mFont = gameinfo.gametype == GAME_Doom ? BigUpper : BigFont; - od->mTitle = "$MNU_CHOOSECLASS"; - od->mSelectedItem = 0; - od->mScrollPos = 0; - od->mClass = nullptr; - od->mPosition = -15; - od->mScrollTop = 0; - od->mIndent = 160; - od->mDontDim = false; - od->mNetgameMessage = "$NEWGAME"; - GC::WriteBarrier(od); - for (unsigned i = 0; i < PlayerClasses.Size (); i++) - { - if (!(PlayerClasses[i].Flags & PCF_NOMENU)) - { - const char *pname = GetPrintableDisplayName(PlayerClasses[i].Type); - if (pname != nullptr) - { - auto it = CreateOptionMenuItemSubmenu(pname, "Episodemenu", i); - od->mItems.Push(it); - GC::WriteBarrier(od, it); - } - } - } - auto it = CreateOptionMenuItemSubmenu("Random", "Episodemenu", -1); - od->mItems.Push(it); - GC::WriteBarrier(od, it); - } -} - -//============================================================================= -// -// Reads any XHAIRS lumps for the names of crosshairs and -// adds them to the display options menu. -// -//============================================================================= - -static void InitCrosshairsList() -{ - int lastlump, lump; - - lastlump = 0; - - FOptionValues **opt = OptionValues.CheckKey(NAME_Crosshairs); - if (opt == nullptr) - { - return; // no crosshair value list present. No need to go on. - } - - FOptionValues::Pair *pair = &(*opt)->mValues[(*opt)->mValues.Reserve(1)]; - pair->Value = 0; - pair->Text = "None"; - - while ((lump = Wads.FindLump("XHAIRS", &lastlump)) != -1) - { - FScanner sc(lump); - while (sc.GetNumber()) - { - FOptionValues::Pair value; - value.Value = sc.Number; - sc.MustGetString(); - value.Text = sc.String; - if (value.Value != 0) - { // Check if it already exists. If not, add it. - unsigned int i; - - for (i = 1; i < (*opt)->mValues.Size(); ++i) - { - if ((*opt)->mValues[i].Value == value.Value) - { - break; - } - } - if (i < (*opt)->mValues.Size()) - { - (*opt)->mValues[i].Text = value.Text; - } - else - { - (*opt)->mValues.Push(value); - } - } - } - } -} - -//============================================================================= -// -// Initialize the music configuration submenus -// -//============================================================================= -extern "C" -{ - extern int adl_getBanksCount(); - extern const char *const *adl_getBankNames(); -} - -static void InitMusicMenus() -{ - DMenuDescriptor **advmenu = MenuDescriptors.CheckKey("AdvSoundOptions"); - auto soundfonts = sfmanager.GetList(); - std::tuple sfmenus[] = { std::make_tuple("GusConfigMenu", SF_SF2 | SF_GUS, "midi_config"), - std::make_tuple("WildMidiConfigMenu", SF_GUS, "wildmidi_config"), - std::make_tuple("TimidityConfigMenu", SF_SF2 | SF_GUS, "timidity_config"), - std::make_tuple("FluidPatchsetMenu", SF_SF2, "fluid_patchset"), - std::make_tuple("ADLMIDICustomBanksMenu", SF_WOPL, "adl_custom_bank"), - std::make_tuple("OPNMIDICustomBanksMenu", SF_WOPN, "opn_custom_bank")}; - - for (auto &p : sfmenus) - { - DMenuDescriptor **menu = MenuDescriptors.CheckKey(std::get<0>(p)); - - if (menu != nullptr) - { - if (soundfonts.Size() > 0) - { - for (auto &entry : soundfonts) - { - if (entry.type & std::get<1>(p)) - { - FString display = entry.mName; - display.ReplaceChars("_", ' '); - auto it = CreateOptionMenuItemCommand(display, FStringf("%s \"%s\"", std::get<2>(p), entry.mName.GetChars()), true); - static_cast(*menu)->mItems.Push(it); - } - } - } - else if (advmenu != nullptr) - { - // Remove the item for this submenu - auto d = static_cast(*advmenu); - auto it = d->GetItem(std::get<0>(p)); - if (it != nullptr) d->mItems.Delete(d->mItems.Find(it)); - } - } - } - - DMenuDescriptor **menu = MenuDescriptors.CheckKey("ADLBankMenu"); - - if (menu != nullptr) - { - const char* const* adl_bank_names; - int adl_banks_count = ZMusic_GetADLBanks(&adl_bank_names); - for (int i=0; i < adl_banks_count; i++) - { - auto it = CreateOptionMenuItemCommand(adl_bank_names[i], FStringf("adl_bank %d", i), true); - static_cast(*menu)->mItems.Push(it); - } - } -} - -//============================================================================= -// -// With the current workings of the menu system this cannot be done any longer -// from within the respective CCMDs. -// -//============================================================================= - -static void InitKeySections() -{ - DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_CustomizeControls); - if (desc != nullptr) - { - if ((*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) - { - DOptionMenuDescriptor *menu = static_cast(*desc); - - for (unsigned i = 0; i < KeySections.Size(); i++) - { - FKeySection *sect = &KeySections[i]; - DMenuItemBase *item = CreateOptionMenuItemStaticText(" "); - menu->mItems.Push(item); - item = CreateOptionMenuItemStaticText(sect->mTitle, 1); - menu->mItems.Push(item); - for (unsigned j = 0; j < sect->mActions.Size(); j++) - { - FKeyAction *act = §->mActions[j]; - item = CreateOptionMenuItemControl(act->mTitle, act->mAction, &Bindings); - menu->mItems.Push(item); - } - } - for (auto &p : menu->mItems) - { - GC::WriteBarrier(*desc, p); - } - } - } -} - -//============================================================================= -// -// Special menus will be created once all engine data is loaded -// -//============================================================================= - -void M_CreateMenus() -{ - BuildPlayerclassMenu(); - InitCrosshairsList(); - InitMusicMenus(); - InitKeySections(); - - FOptionValues **opt = OptionValues.CheckKey(NAME_Mididevices); - if (opt != nullptr) - { - I_BuildMIDIMenuList(*opt); - } - opt = OptionValues.CheckKey(NAME_Aldevices); - if (opt != nullptr) - { - I_BuildALDeviceList(*opt); - } - opt = OptionValues.CheckKey(NAME_Alresamplers); - if (opt != nullptr) - { - I_BuildALResamplersList(*opt); - } - opt = OptionValues.CheckKey(NAME_PlayerTeam); - if (opt != nullptr) - { - auto op = *opt; - op->mValues.Resize(Teams.Size() + 1); - op->mValues[0].Value = 0; - op->mValues[0].Text = "$OPTVAL_NONE"; - for (unsigned i = 0; i < Teams.Size(); i++) - { - op->mValues[i+1].Value = i+1; - op->mValues[i+1].Text = Teams[i].GetName(); - } - } - opt = OptionValues.CheckKey(NAME_PlayerClass); - if (opt != nullptr) - { - auto op = *opt; - int o = 0; - if (!gameinfo.norandomplayerclass && PlayerClasses.Size() > 1) - { - op->mValues.Resize(PlayerClasses.Size()+1); - op->mValues[0].Value = -1; - op->mValues[0].Text = "$MNU_RANDOM"; - o = 1; - } - else op->mValues.Resize(PlayerClasses.Size()); - for (unsigned i = 0; i < PlayerClasses.Size(); i++) - { - op->mValues[i+o].Value = i; - op->mValues[i+o].Text = GetPrintableDisplayName(PlayerClasses[i].Type); - } - } -} - - -DEFINE_ACTION_FUNCTION(DMenu, UpdateColorsets) -{ - PARAM_PROLOGUE; - PARAM_POINTER(playerClass, FPlayerClass); - - TArray PlayerColorSets; - - EnumColorSets(playerClass->Type, &PlayerColorSets); - - auto opt = OptionValues.CheckKey(NAME_PlayerColors); - if (opt != nullptr) - { - auto op = *opt; - op->mValues.Resize(PlayerColorSets.Size() + 1); - op->mValues[0].Value = -1; - op->mValues[0].Text = "$OPTVAL_CUSTOM"; - for (unsigned i = 0; i < PlayerColorSets.Size(); i++) - { - auto cset = GetColorSet(playerClass->Type, PlayerColorSets[i]); - op->mValues[i + 1].Value = PlayerColorSets[i]; - op->mValues[i + 1].Text = cset? cset->Name.GetChars() : "?"; // The null case should never happen here. - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(DMenu, UpdateSkinOptions) -{ - PARAM_PROLOGUE; - PARAM_POINTER(playerClass, FPlayerClass); - - auto opt = OptionValues.CheckKey(NAME_PlayerSkin); - if (opt != nullptr) - { - auto op = *opt; - - if ((GetDefaultByType(playerClass->Type)->flags4 & MF4_NOSKIN) || players[consoleplayer].userinfo.GetPlayerClassNum() == -1) - { - op->mValues.Resize(1); - op->mValues[0].Value = -1; - op->mValues[0].Text = "$OPTVAL_DEFAULT"; - } - else - { - op->mValues.Clear(); - for (unsigned i = 0; i < Skins.Size(); i++) - { - op->mValues.Reserve(1); - op->mValues.Last().Value = i; - op->mValues.Last().Text = Skins[i].Name; - } - } - } - return 0; -} - -//============================================================================= -// -// The skill menu must be refeshed each time it starts up -// -//============================================================================= -extern int restart; - -void M_StartupSkillMenu(FGameStartup *gs) -{ - static int done = -1; - bool success = false; - TArray MenuSkills; - TArray SkillIndices; - if (MenuSkills.Size() == 0) - { - for (unsigned ind = 0; ind < AllSkills.Size(); ind++) - { - if (!AllSkills[ind].NoMenu) - { - MenuSkills.Push(&AllSkills[ind]); - SkillIndices.Push(ind); - } - } - } - if (MenuSkills.Size() == 0) I_Error("No valid skills for menu found. At least one must be defined."); - - int defskill = DefaultSkill; - if ((unsigned int)defskill >= MenuSkills.Size()) - { - defskill = SkillIndices[(MenuSkills.Size() - 1) / 2]; - } - if (AllSkills[defskill].NoMenu) - { - for (defskill = 0; defskill < (int)AllSkills.Size(); defskill++) - { - if (!AllSkills[defskill].NoMenu) break; - } - } - int defindex = 0; - for (unsigned i = 0; i < MenuSkills.Size(); i++) - { - if (MenuSkills[i] == &AllSkills[defskill]) - { - defindex = i; - break; - } - } - - DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Skillmenu); - if (desc != nullptr) - { - if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) - { - DListMenuDescriptor *ld = static_cast(*desc); - int posx = (int)ld->mXpos; - int y = (int)ld->mYpos; - - // Delete previous contents - for(unsigned i=0; imItems.Size(); i++) - { - FName n = ld->mItems[i]->mAction; - if (n == NAME_Startgame || n == NAME_StartgameConfirm) - { - ld->mItems.Resize(i); - break; - } - } - - if (done != restart) - { - done = restart; - ld->mSelectedItem = ld->mItems.Size() + defindex; - - int posy = y; - int topy = posy; - - // Get lowest y coordinate of any static item in the menu - for(unsigned i = 0; i < ld->mItems.Size(); i++) - { - int y = (int)ld->mItems[i]->GetY(); - if (y < topy) topy = y; - } - - // center the menu on the screen if the top space is larger than the bottom space - int totalheight = posy + MenuSkills.Size() * ld->mLinespacing - topy; - - if (totalheight < 190 || MenuSkills.Size() == 1) - { - int newtop = (200 - totalheight + topy) / 2; - int topdelta = newtop - topy; - if (topdelta < 0) - { - for(unsigned i = 0; i < ld->mItems.Size(); i++) - { - ld->mItems[i]->OffsetPositionY(topdelta); - } - ld->mYpos = y = posy - topdelta; - } - } - else - { - // too large - desc = nullptr; - done = false; - goto fail; - } - } - - for (unsigned int i = 0; i < MenuSkills.Size(); i++) - { - FSkillInfo &skill = *MenuSkills[i]; - DMenuItemBase *li = nullptr; - - FString *pItemText = nullptr; - if (gs->PlayerClass != nullptr) - { - pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass); - } - - if (skill.PicName.Len() != 0 && pItemText == nullptr) - { - FTextureID tex = GetMenuTexture(skill.PicName); - if (skill.MenuName.IsEmpty() || TexMan.OkForLocalization(tex, skill.MenuName)) - continue; - } - const char *c = pItemText ? pItemText->GetChars() : skill.MenuName.GetChars(); - if (*c == '$') c = GStrings(c + 1); - int textwidth = ld->mFont->StringWidth(c); - int textright = posx + textwidth; - if (posx + textright > 320) posx = std::max(0, 320 - textright); - } - - unsigned firstitem = ld->mItems.Size(); - for(unsigned int i = 0; i < MenuSkills.Size(); i++) - { - FSkillInfo &skill = *MenuSkills[i]; - DMenuItemBase *li = nullptr; - // Using a different name for skills that must be confirmed makes handling this easier. - FName action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ? - NAME_StartgameConfirm : NAME_Startgame; - FString *pItemText = nullptr; - if (gs->PlayerClass != nullptr) - { - pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass); - } - - EColorRange color = (EColorRange)skill.GetTextColor(); - if (color == CR_UNTRANSLATED) color = ld->mFontColor; - if (skill.PicName.Len() != 0 && pItemText == nullptr) - { - FTextureID tex = GetMenuTexture(skill.PicName); - if (skill.MenuName.IsEmpty() || TexMan.OkForLocalization(tex, skill.MenuName)) - li = CreateListMenuItemPatch(posx, y, ld->mLinespacing, skill.Shortcut, tex, action, SkillIndices[i]); - } - if (li == nullptr) - { - li = CreateListMenuItemText(posx, y, ld->mLinespacing, skill.Shortcut, - pItemText? *pItemText : skill.MenuName, ld->mFont, color,ld->mFontColor2, action, SkillIndices[i]); - } - ld->mItems.Push(li); - GC::WriteBarrier(*desc, li); - y += ld->mLinespacing; - } - if (AllEpisodes[gs->Episode].mNoSkill || MenuSkills.Size() == 1) - { - ld->mAutoselect = firstitem + defindex; - } - else - { - ld->mAutoselect = -1; - } - success = true; - } - } - if (success) return; -fail: - // Option menu fallback for overlong skill lists - DOptionMenuDescriptor *od; - if (desc == nullptr) - { - od = Create(); - MenuDescriptors[NAME_Skillmenu] = od; - od->mMenuName = NAME_Skillmenu; - od->mFont = gameinfo.gametype == GAME_Doom ? BigUpper : BigFont; - od->mTitle = "$MNU_CHOOSESKILL"; - od->mSelectedItem = defindex; - od->mScrollPos = 0; - od->mClass = nullptr; - od->mPosition = -15; - od->mScrollTop = 0; - od->mIndent = 160; - od->mDontDim = false; - GC::WriteBarrier(od); - } - else - { - od = static_cast(*desc); - od->mItems.Clear(); - } - for(unsigned int i = 0; i < MenuSkills.Size(); i++) - { - FSkillInfo &skill = *MenuSkills[i]; - DMenuItemBase *li; - // Using a different name for skills that must be confirmed makes handling this easier. - const char *action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ? - "StartgameConfirm" : "Startgame"; - - FString *pItemText = nullptr; - if (gs->PlayerClass != nullptr) - { - pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass); - } - li = CreateOptionMenuItemSubmenu(pItemText? *pItemText : skill.MenuName, action, SkillIndices[i]); - od->mItems.Push(li); - GC::WriteBarrier(od, li); - if (!done) - { - done = true; - od->mSelectedItem = defindex; - } - } -} - - -#ifdef _WIN32 -EXTERN_CVAR(Bool, vr_enable_quadbuffered) -#endif - -void UpdateVRModes(bool considerQuadBuffered) -{ - FOptionValues ** pVRModes = OptionValues.CheckKey("VRMode"); - if (pVRModes == nullptr) return; - - TArray & vals = (*pVRModes)->mValues; - TArray filteredValues; - int cnt = vals.Size(); - for (int i = 0; i < cnt; ++i) { - auto const & mode = vals[i]; - if (mode.Value == 7) { // Quad-buffered stereo -#ifdef _WIN32 - if (!vr_enable_quadbuffered) continue; -#else - continue; // Remove quad-buffered option on Mac and Linux -#endif - if (!considerQuadBuffered) continue; // Probably no compatible screen mode was found - } - filteredValues.Push(mode); - } - vals = filteredValues; -} diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp deleted file mode 100644 index 75685678b85..00000000000 --- a/src/menu/messagebox.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* -** messagebox.cpp -** Confirmation, notification screns -** -**--------------------------------------------------------------------------- -** Copyright 2010 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include "menu/menu.h" -#include "d_main.h" -#include "gstrings.h" -#include "gi.h" -#include "i_video.h" -#include "st_start.h" -#include "c_dispatch.h" -#include "g_game.h" -#include "vm.h" - -EXTERN_CVAR (Bool, saveloadconfirmation) // [mxd] -EXTERN_CVAR (Bool, quicksaverotation) - -CVAR(Bool, m_quickexit, false, CVAR_ARCHIVE) - -typedef void(*hfunc)(); -DEFINE_ACTION_FUNCTION(DMessageBoxMenu, CallHandler) -{ - PARAM_PROLOGUE; - PARAM_POINTERTYPE(Handler, hfunc); - Handler(); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action = NAME_None, hfunc handler = nullptr) -{ - auto c = PClass::FindClass(gameinfo.MessageBoxClass); - if (!c->IsDescendantOf(NAME_MessageBoxMenu)) c = PClass::FindClass(NAME_MessageBoxMenu); - auto p = c->CreateNew(); - FString namestr = message; - - IFVIRTUALPTRNAME(p, NAME_MessageBoxMenu, Init) - { - VMValue params[] = { p, parent, &namestr, messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; - VMCall(func, params, countof(params), nullptr, 0); - return (DMenu*)p; - } - return nullptr; -} - -//============================================================================= -// -// -// -//============================================================================= - -CCMD (menu_quit) -{ // F10 - if (m_quickexit) - { - ST_Endoom(); - } - - M_StartControlPanel (true); - - const size_t messageindex = static_cast(gametic) % gameinfo.quitmessages.Size(); - FString EndString; - const char *msg = gameinfo.quitmessages[messageindex]; - if (msg[0] == '$') - { - if (msg[1] == '*') - { - EndString = GStrings(msg + 2); - } - else - { - EndString.Format("%s\n\n%s", GStrings(msg + 1), GStrings("DOSY")); - } - } - else EndString = gameinfo.quitmessages[messageindex]; - - DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, EndString, 0, false, NAME_None, []() - { - if (!netgame) - { - if (gameinfo.quitSound.IsNotEmpty()) - { - S_Sound(CHAN_VOICE, CHANF_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE); - I_WaitVBL(105); - } - } - ST_Endoom(); - }); - - - M_ActivateMenu(newmenu); -} - - - -//============================================================================= -// -// -// -//============================================================================= - -void ActivateEndGameMenu() -{ - FString tempstring = GStrings(netgame ? "NETEND" : "ENDGAME"); - DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() - { - M_ClearMenus(); - if (!netgame) - { - if (demorecording) - G_CheckDemoStatus(); - D_StartTitle(); - } - }); - - M_ActivateMenu(newmenu); -} - -CCMD (menu_endgame) -{ // F7 - if (!usergame) - { - S_Sound (CHAN_VOICE, CHANF_UI, "menu/invalid", snd_menuvolume, ATTN_NONE); - return; - } - - //M_StartControlPanel (true); - S_Sound (CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE); - - ActivateEndGameMenu(); -} - -//============================================================================= -// -// -// -//============================================================================= - -CCMD (quicksave) -{ // F6 - if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer)) - { - S_Sound (CHAN_VOICE, CHANF_UI, "menu/invalid", snd_menuvolume, ATTN_NONE); - return; - } - - if (gamestate != GS_LEVEL) - return; - - // If the quick save rotation is enabled, it handles the save slot. - if (quicksaverotation) - { - G_DoQuickSave(); - return; - } - - if (savegameManager.quickSaveSlot == NULL || savegameManager.quickSaveSlot == (FSaveGameNode*)1) - { - S_Sound(CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE); - M_StartControlPanel(false); - M_SetMenu(NAME_Savegamemenu); - return; - } - - // [mxd]. Just save the game, no questions asked. - if (!saveloadconfirmation) - { - G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); - return; - } - - S_Sound(CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE); - - FString tempstring = GStrings("QSPROMPT"); - tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars()); - - DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() - { - G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); - S_Sound(CHAN_VOICE, CHANF_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); - M_ClearMenus(); - }); - - M_ActivateMenu(newmenu); -} - -//============================================================================= -// -// -// -//============================================================================= - -CCMD (quickload) -{ // F9 - if (netgame) - { - M_StartControlPanel(true); - M_StartMessage (GStrings("QLOADNET"), 1); - return; - } - - if (savegameManager.quickSaveSlot == NULL || savegameManager.quickSaveSlot == (FSaveGameNode*)1) - { - M_StartControlPanel(true); - // signal that whatever gets loaded should be the new quicksave - savegameManager.quickSaveSlot = (FSaveGameNode *)1; - M_SetMenu(NAME_Loadgamemenu); - return; - } - - // [mxd]. Just load the game, no questions asked. - if (!saveloadconfirmation) - { - G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); - return; - } - FString tempstring = GStrings("QLPROMPT"); - tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars()); - - M_StartControlPanel(true); - - DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() - { - G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); - S_Sound(CHAN_VOICE, CHANF_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); - M_ClearMenus(); - }); - M_ActivateMenu(newmenu); -} - -//============================================================================= -// -// -// -//============================================================================= - -void M_StartMessage(const char *message, int messagemode, FName action) -{ - if (CurrentMenu == NULL) - { - // only play a sound if no menu was active before - M_StartControlPanel(menuactive == MENU_Off); - } - DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, message, messagemode, false, action); - newmenu->mParentMenu = CurrentMenu; - M_ActivateMenu(newmenu); -} - -DEFINE_ACTION_FUNCTION(DMenu, StartMessage) -{ - PARAM_PROLOGUE; - PARAM_STRING(msg); - PARAM_INT(mode); - PARAM_NAME(action); - M_StartMessage(msg, mode, action); - return 0; -} diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 84ed9fc1a3e..07192a2d904 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -1,6 +1,6 @@ /* ** playermenu.cpp -** The player setup menu +** The player setup menu's setters. These are native for security purposes. ** **--------------------------------------------------------------------------- ** Copyright 2001-2010 Randy Heit @@ -33,12 +33,13 @@ ** */ -#include "menu/menu.h" +#include "menu.h" #include "gi.h" #include "c_dispatch.h" #include "teaminfo.h" #include "r_state.h" #include "vm.h" +#include "d_player.h" EXTERN_CVAR(Int, team) EXTERN_CVAR(Float, autoaim) @@ -80,7 +81,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged) { PARAM_PROLOGUE; PARAM_STRING(s); - const char *pp = s; + const char *pp = s.GetChars(); FString command("name \""); if (DMenu::InMenu) @@ -95,7 +96,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged) command << *p; } command << '"'; - C_DoCommand(command); + C_DoCommand(command.GetChars()); } return 0; } @@ -154,7 +155,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) if (DMenu::InMenu) { players[consoleplayer].userinfo.SkinNumChanged(sel); - cvar_set("skin", Skins[sel].Name); + cvar_set("skin", Skins[sel].Name.GetChars()); } return 0; } diff --git a/src/namedef_custom.h b/src/namedef_custom.h new file mode 100644 index 00000000000..59752245b8d --- /dev/null +++ b/src/namedef_custom.h @@ -0,0 +1,902 @@ +// GZDoom specific names + +xx(Doom) +xx(Heretic) +xx(Hexen) +xx(Strife) +xx(Raven) + +// blood spawning +xx(Blood) +xx(BloodSplatter) +xx(AxeBlood) +xx(Spray) + +// Actor properties +xx(BobPivot3D) + +// Invulnerability types +xx(Ghost) +xx(Reflective) + +// Iron Feet types +//xx(Normal) // defined below +xx(Full) + +// Invisibility types +xx(Additive) +xx(Fuzzy) +xx(Stencil) +xx(AddStencil) + +// Healingradius types +xx(Mana) +xx(Armor) + +// Hexen sound sequence names +xx(Platform) +xx(PlatformMetal) +xx(Silence) +xx(Lava) +xx(Water) +xx(Ice) +xx(Earth) +xx(PlatformMetal2) +xx(DoorNormal) +xx(DoorHeavy) +xx(DoorMetal) +xx(DoorCreak) +xx(DoorMetal2) +xx(Wind) + +xx(PointPusher) +xx(PointPuller) + +xx(UpperStackLookOnly) +xx(LowerStackLookOnly) +xx(StackPoint) +xx(SkyCamCompat) + +xx(BasicArmorBonus) +xx(BasicArmorPickup) +xx(SaveAmount) +xx(SavePercent) +xx(MaxAbsorb) +xx(MaxFullAbsorb) +xx(MaxAmount) +xx(ActualSaveAmount) +xx(ArmorType) +xx(HexenArmor) +xx(Slots) +xx(SlotsIncrement) +xx(InterHubAmount) +xx(Icon) +xx(AltHUDIcon) +xx(PickupFlash) + +xx(BulletPuff) +xx(StrifePuff) +xx(MaulerPuff) + +// Special bosses A_BossDeath knows about +xx(Fatso) +xx(Arachnotron) +xx(BaronOfHell) +xx(Cyberdemon) +xx(SpiderMastermind) +xx(Ironlich) +xx(Minotaur) +xx(Sorcerer2) + +// Bots check this +xx(Megasphere) +xx(MegasphereHealth) + +// Standard player classes +xx(DoomPlayer) +xx(HereticPlayer) +xx(StrifePlayer) +xx(FighterPlayer) +xx(ClericPlayer) +xx(MagePlayer) +xx(ChexPlayer) +xx(ChickenPlayer) +xx(PigPlayer) + +// Flechette names for the different Hexen player classes +xx(ArtiPoisonBag1) +xx(ArtiPoisonBag2) +xx(ArtiPoisonBag3) + +// Strife quests +xx(QuestItem) +xx(Sigil) +xx(GiveSigilPiece) +xx(SetWeapon) +xx(SetSprite) + +// Armor +xx(BasicArmor) + +// Doom ammo types +xx(Clip) + +xx(PuzzleItem) +xx(PuzzleItemNumber) +xx(HealthPickup) +xx(autousemode) +xx(Ammo) +xx(WeaponGiver) +xx(DehackedPickup) +xx(PowerTargeter) +xx(PowerInvulnerable) +xx(PowerStrength) +xx(PowerInvisibility) +xx(PowerIronFeet) +xx(PowerLightAmp) +xx(PowerWeaponLevel2) +xx(PowerFlight) +xx(PowerSpeed) +xx(PowerTorch) +xx(PowerHighJump) +xx(PowerReflection) +xx(PowerDrain) +xx(Reflection) +xx(CustomInventory) +xx(Inventory) +xx(StateProvider) +xx(CallTryPickup) +xx(QuestItem25) +xx(QuestItem28) +xx(PowerDoubleFiringSpeed) +xx(PowerInfiniteAmmo) +xx(PowerBuddha) + +xx(TeleportDest) +xx(TeleportDest2) + + +xx(Fist) +//xx(Berserk) +xx(Chainsaw) +xx(Pistol) +xx(Shotgun) +xx(SSG) +xx(Chaingun) +xx(Rocket) +xx(Plasma) +xx(BFG) +//xx(Railgun) +xx(Dagger) + +// Damage types +//xx(Fire) already defined above +//xx(Ice) +//xx(Disintegrate) +xx(Drowning) +xx(Slime) +//xx(Crush) +xx(Telefrag) +xx(Falling) +xx(Suicide) +xx(Exit) +xx(Railgun) +xx(Poison) +xx(Electric) +xx(BFGSplash) +xx(DrainLife) // A weapon like the Sigil that drains your life away. +xx(Massacre) // For death by a cheater! +//(Melee) already defined above, so don't define it again +xx(InstantDeath) // Strife "instant death" +xx(PoisonCloud) // makes monsters howl. +xx(Hitscan) // for normal guns and the like +xx(Quake) + +// Special death name for getting killed excessively. Could be used as +// a damage type if you wanted to force an extreme death. +xx(Extreme) +xx(MDK) +xx(Cast) // 'damage type' for the cast call + +// Various actor names which are used internally +xx(MapSpot) +xx(PatrolPoint) +xx(PatrolSpecial) +xx(Communicator) +xx(PowerScanner) + +xx(DeathmatchStatusScreen) +xx(CoopStatusScreen) +xx(DoomStatusScreen) +xx(RavenStatusScreen) +xx(DoomStatusScreenSized) +xx(RavenStatusScreenSized) + +xx(Owner) +xx(FlameThrower) + +// Dehacked +xx(A_Punch) +xx(A_FirePistol) +xx(A_FireShotgun) +xx(A_FireShotgun2) +xx(A_FireCGun) +xx(A_FireMissile) +xx(A_Saw) +xx(A_FirePlasma) +xx(A_FireBFG) +xx(A_FireOldBFG) +xx(A_FireRailgun) +xx(MBF21_ConsumeAmmo) + +// Special translation names +xx(RainPillar1) +xx(RainPillar2) +xx(RainPillar3) +xx(RainPillar4) +xx(RainPillar5) +xx(RainPillar6) +xx(RainPillar7) +xx(RainPillar8) + +xx(Player1) +xx(Player2) +xx(Player3) +xx(Player4) +xx(Player5) +xx(Player6) +xx(Player7) +xx(Player8) +xx(PlayerChunk) +xx(RestrictedToPlayerClass) +xx(ForbiddenToPlayerClass) + +// Weapon member fields that need direct access +xx(Ammo1) +xx(Ammo2) +xx(AmmoType1) +xx(AmmoType2) +xx(AmmoGive1) +xx(AmmoGive2) +xx(AmmoUse1) +xx(SisterWeapon) +xx(BobStyle) +xx(Kickback) +xx(MinSelAmmo1) +xx(bDehAmmo) +xx(FOVScale) +xx(LookScale) +xx(YAdjust) +xx(Crosshair) +xx(WeaponFlags) +xx(DropTime) +xx(PickupSound) +xx(WeaponScaleX) +xx(WeaponScaleY) +xx(ReadySound) +xx(A_WeaponReady) + +// PlayerPawn member fields +xx(ColorRangeStart) +xx(ColorRangeEnd) +xx(InvFirst) +xx(ForwardMove1) +xx(ForwardMove2) +xx(SideMove1) +xx(SideMove2) +xx(Face) +xx(Slot) +xx(SoundClass) +xx(FlyBob) +xx(ViewBob) +xx(WaterClimbSpeed) +xx(DamageFade) +xx(MaxHealth) +xx(crouchsprite) +xx(UseRange) +xx(AttackZOffset) +xx(SpawnMask) +xx(ScoreIcon) +xx(ViewHeight) +xx(ViewAngle) +xx(ViewPitch) +xx(ViewRoll) +xx(FallingScreamMinSpeed) +xx(FallingScreamMaxSpeed) +xx(GruntSpeed) +xx(JumpZ) +xx(MugShotMaxHealth) +xx(BonusHealth) +xx(PlayerFlags) +xx(InvSel) +xx(FullHeight) + +xx(BlueCard) +xx(YellowCard) +xx(RedCard) +xx(BlueSkull) +xx(YellowSkull) +xx(RedSkull) +xx(DynamicLight) +xx(SpotInnerAngle) +xx(SpotOuterAngle) +xx(lightflags) +xx(lighttype) +xx(InternalDynamicLight) +xx(_a_chase_default) +xx(MapMarker) +xx(Spawn2) +xx(PlayerTeam) +xx(PlayerColors) +xx(PlayerSkin) +xx(NewPlayerMenu) +xx(AltHud) +xx(GameScreen) +xx(ListM) + +// Standard animator names. +xx(Spawn) +xx(See) +xx(Pain) +xx(Melee) +xx(Missile) +xx(Crash) +xx(Death) +xx(Raise) +xx(Wound) +xx(Heal) +xx(Crush) +xx(Yes) +xx(No) +xx(Greetings) +xx(Idle) +xx(GenericFreezeDeath) +xx(GenericCrush) +xx(DieFromSpawn) +xx(Slam) + +// Bounce state names +xx(Bounce) +xx(Wall) +xx(Ceiling) +xx(Creature) + +// Compatible death names for the decorate parser. +xx(XDeath) +xx(Burn) +//xx(Ice) // already defined above +xx(Disintegrate) +xx(Smash) + +// Weapon animator names. +xx(Select) +xx(Deselect) +xx(DeadLowered) +xx(Ready) +xx(Fire) +xx(Hold) +xx(AltFire) +xx(AltHold) +xx(Flash) +xx(AltFlash) +xx(Reload) +xx(Zoom) +xx(User1) +xx(User2) +xx(User3) +xx(User4) + +// State names used by ASwitchableDecoration +xx(Active) +xx(Inactive) + +// State names used by ACustomInventory +xx(Pickup) +xx(Use) +xx(Drop) + + +// ScriptUtil entry points +xx(ScriptUtil) +xx(SetMarineWeapon) +xx(SetMarineSprite) +xx(GiveInventory) +xx(TakeInventory) +xx(ClearInventory) + +// summary +xx(cwidth) +xx(cheight) +xx(wrapwidth) +xx(scalefactorx) +xx(scalefactory) +xx(scalemode) + +xx(Team) +xx(Skin) +xx(Gender) +xx(Autoaim) +xx(Multiplayer) + +xx(CustomizeControls) +xx(MessageOptions) +xx(AutomapOptions) +xx(ScoreboardOptions) +xx(MapColorMenu) +xx(GameplayOptions) +xx(CompatibilityOptions) +xx(MouseOptions) +xx(SoundOptions) +xx(AdvSoundOptions) +xx(ModReplayerOptions) +xx(VideoOptions) +xx(JoystickConfigMenu) +xx(VideoModeMenu) + +// end sequences +xx(Inter_Chess) +xx(Inter_Strife) +xx(Inter_Strife_Good) +xx(Inter_Strife_Sad) +xx(Inter_Strife_Bad) +xx(Inter_Strife_Lose) +xx(Inter_Strife_MAP03) +xx(Inter_Strife_MAP10) + +xx(BuiltinCallLineSpecial) + +xx(MainmenuTextOnly) +xx(Playerclassmenu) +xx(HexenDefaultPlayerclassmenu) +xx(Readthismenu) +xx(Playermenu) + +// more stuff +xx(ColorSet) +xx(NeverSwitchOnPickup) +xx(MoveBob) +xx(FViewBob) +xx(StillBob) +xx(ClassicFlight) +xx(WBobSpeed) +xx(WBobFire) +xx(PlayerClass) +xx(MonsterClass) +xx(Morph) +xx(MorphedMonster) +xx(Wi_NoAutostartMap) + +xx(Duration) +xx(MorphStyle) +xx(MorphFlash) +xx(UnMorphFlash) +xx(Powerup) +xx(EffectTics) +xx(PowerupGiver) +xx(BlendColor) +xx(Strength) +xx(Mode) +xx(PowerupType) +xx(PlayerPawn) +xx(RipSound) +xx(Archvile) + +xx(ResolveState) + + + +// UDMF keywords (todo: take these out of the global name table +xx(Alpha) +//xx(Angle) +xx(Args) +xx(CeilingZ) +xx(FloorZ) +xx(Health) +xx(Pitch) +xx(SpecialName) +xx(Special) +xx(TID) +xx(TIDtoHate) +xx(WaterLevel) +xx(WaterDepth) +xx(MomX) +xx(MomY) +xx(MomZ) +xx(Threshold) +xx(DefThreshold) +xx(TeleportSpecial) +xx(Teleport) +xx(CallACS) +xx(IsPointerEqual) +xx(Pick) +xx(Mass) +xx(VelX) +xx(VelY) +xx(VelZ) +xx(Accuracy) +xx(Stamina) +xx(Radius) +xx(ReactionTime) +xx(MeleeRange) +xx(Speed) +xx(FastSpeed) +xx(HowlSound) +xx(VisibleStartAngle) +xx(VisibleStartPitch) +xx(VisibleEndAngle) +xx(VisibleEndPitch) +xx(Format) +xx(PickupMsg) +xx(Respawnable) +xx(ExplosionDamage) +xx(ExplosionRadius) +xx(DontHurtShooter) +xx(Noattack) +xx(PushSound) + +//xx(X) +//xx(Y) +xx(ZFloor) +xx(ZCeiling) +xx(Height) +//xx(Tid) +//xx(Angle) +xx(Type) +//xx(Special) +xx(Arg0) +xx(Arg1) +xx(Arg2) +xx(Arg3) +xx(Arg4) +xx(Arg0Str) +xx(Arg1Str) +xx(Id) +xx(MoreIds) +xx(V1) +xx(V2) + +xx(Sidefront) +xx(Sideback) +xx(Offsetx) +xx(Offsety) +xx(Texturetop) +xx(Texturebottom) +xx(Texturemiddle) +xx(Sector) +xx(Heightfloor) +xx(Heightceiling) +xx(Lightlevel) +xx(Texturefloor) +xx(Textureceiling) +xx(Nodecals) + +xx(Skill1) +xx(Skill2) +xx(Skill3) +xx(Skill4) +xx(Skill5) +xx(Skill6) +xx(Skill7) +xx(Skill8) +xx(Skill9) +xx(Skill10) +xx(Skill11) +xx(Skill12) +xx(Skill13) +xx(Skill14) +xx(Skill15) +xx(Skill16) +xx(Medium) +xx(Hard) +xx(Ambush) +xx(Dormant) +xx(Class0) +xx(Class1) +xx(Class2) +xx(Class3) +xx(Class4) +xx(Class5) +xx(Class6) +xx(Class7) +xx(Class8) +xx(Class9) +xx(Class10) +xx(Class11) +xx(Class12) +xx(Class13) +xx(Class14) +xx(Class15) +xx(Class16) +xx(Single) +xx(Coop) +xx(Dm) +xx(Translucent) +xx(Invisible) +xx(Friend) +xx(Strifeally) +xx(Standing) +xx(Countsecret) +xx(NoCount) +xx(Score) +xx(Roll) +xx(Scale) +xx(ScaleX) +xx(ScaleY) +xx(FriendlySeeBlocks) +xx(Floatbobphase) +xx(Floatbobstrength) +xx(Target) +xx(Master) +xx(Tracer) + +xx(Blocking) +xx(Blockmonsters) +xx(Twosided) +xx(Dontpegtop) +xx(Dontpegbottom) +xx(Secret) +xx(Blocksound) +xx(Dontdraw) +xx(Mapped) +xx(Monsteractivate) +xx(Blockplayers) +xx(Blockeverything) +xx(Zoneboundary) +xx(Jumpover) +xx(Blockfloaters) +xx(Blocklandmonsters) +xx(Clipmidtex) +xx(Wrapmidtex) +xx(Midtex3d) +xx(Checkswitchrange) +xx(Firstsideonly) +xx(Transparent) +xx(Passuse) +xx(Repeatspecial) +xx(Conversation) +xx(Locknumber) +xx(Midtex3dimpassible) +xx(Revealed) +xx(AutomapStyle) +xx(DrawFullHeight) + +xx(Playercross) +xx(Playeruse) +xx(Playeruseback) +xx(Monstercross) +xx(Impact) +xx(Playerpush) +xx(Missilecross) +xx(Anycross) +xx(Monsteruse) +xx(Monsterpush) + +xx(ZDoom) +xx(ZDoomTranslated) +xx(Vavoom) +xx(GZDoom) +xx(Eternity) +xx(Dsda) + +xx(Xpanningfloor) +xx(Ypanningfloor) +xx(Xpanningceiling) +xx(Ypanningceiling) +xx(Xscalefloor) +xx(Yscalefloor) +xx(Xscaleceiling) +xx(Yscaleceiling) +xx(Rotationfloor) +xx(Rotationceiling) +xx(Lightfloor) +xx(Lightceiling) +xx(Lightfloorabsolute) +xx(Lightceilingabsolute) +xx(Gravity) +xx(Lightcolor) +xx(Fadecolor) +xx(Color_Floor) +xx(Color_Ceiling) +xx(Color_Walltop) +xx(Color_Wallbottom) +xx(Color_Sprites) +xx(ColorAdd_Floor) +xx(ColorAdd_Ceiling) +xx(ColorAdd_Sprites) +xx(ColorAdd_Walls) +xx(NoSkyWalls) +xx(Desaturation) +xx(SoundSequence) +xx(Silent) +xx(Nofallingdamage) +xx(Dropactors) +xx(NoRespawn) +xx(Alphafloor) +xx(Alphaceiling) +xx(Renderstylefloor) +xx(Renderstyleceiling) +xx(Waterzone) +xx(portal_ceil_blocksound) +xx(portal_ceil_disabled) +xx(portal_ceil_nopass) +xx(portal_ceil_norender) +xx(portal_ceil_overlaytype) +xx(portal_ceil_useglobaltex) +xx(portal_floor_blocksound) +xx(portal_floor_disabled) +xx(portal_floor_nopass) +xx(portal_floor_norender) +xx(portal_floor_overlaytype) +xx(portal_floor_useglobaltex) +xx(scroll_ceil_x) +xx(scroll_ceil_y) +xx(scroll_ceil_type) +xx(scroll_floor_x) +xx(scroll_floor_y) +xx(scroll_floor_type) + +xx(offsetx_top) +xx(offsety_top) +xx(offsetx_mid) +xx(offsety_mid) +xx(offsetx_bottom) +xx(offsety_bottom) +xx(scalex_top) +xx(scaley_top) +xx(scalex_mid) +xx(scaley_mid) +xx(scalex_bottom) +xx(scaley_bottom) +xx(light) +xx(lightabsolute) +xx(lightfog) +xx(light_top) +xx(lightabsolute_top) +xx(light_mid) +xx(lightabsolute_mid) +xx(light_bottom) +xx(lightabsolute_bottom) +xx(nofakecontrast) +xx(smoothlighting) +xx(blockprojectiles) +xx(blockuse) +xx(hidden) +xx(blocksight) +xx(blockhitscan) + +xx(nogradient_top) +xx(flipgradient_top) +xx(clampgradient_top) +xx(useowncolors_top) +xx(uppercolor_top) +xx(lowercolor_top) +xx(nogradient_mid) +xx(flipgradient_mid) +xx(clampgradient_mid) +xx(useowncolors_mid) +xx(uppercolor_mid) +xx(lowercolor_mid) +xx(nogradient_bottom) +xx(flipgradient_bottom) +xx(clampgradient_bottom) +xx(useowncolors_bottom) +xx(uppercolor_bottom) +xx(lowercolor_bottom) +xx(useowncoloradd_top) +xx(coloradd_top) +xx(useowncoloradd_mid) +xx(coloradd_mid) +xx(useowncoloradd_bottom) +xx(coloradd_bottom) +xx(colorization_top) +xx(colorization_mid) +xx(colorization_bottom) +xx(colorization_floor) +xx(colorization_ceiling) + +xx(ceilingplane_a) +xx(ceilingplane_b) +xx(ceilingplane_c) +xx(ceilingplane_d) +xx(floorplane_a) +xx(floorplane_b) +xx(floorplane_c) +xx(floorplane_d) +xx(damageamount) +xx(damagetype) +xx(damageinterval) +xx(leakiness) +xx(damageterraineffect) +xx(damagehazard) +xx(floorterrain) +xx(ceilingterrain) +xx(floor_reflect) +xx(ceiling_reflect) +xx(floorglowcolor) +xx(floorglowheight) +xx(ceilingglowcolor) +xx(ceilingglowheight) +xx(fogdensity) + +xx(HealthFloor) +xx(HealthCeiling) +xx(Health3D) +xx(DamageSpecial) +xx(DeathSpecial) +xx(HealthFloorGroup) +xx(HealthCeilingGroup) +xx(Health3DGroup) +xx(HealthGroup) +xx(Renderstyle) + +// USDF keywords +xx(Amount) +xx(Text) +xx(Displaycost) +xx(Yesmessage) +xx(Nomessage) +xx(Giveitem) +xx(Nextpage) +xx(Closedialog) +xx(Cost) +xx(Page) +xx(Count) +xx(Panel) +xx(Dialog) +xx(Ifitem) +xx(Choice) +xx(Link) +xx(Goodbye) +xx(Require) +xx(Exclude) +xx(Userstring) +xx(Sky) +xx(Pagename) + +// Lightmap/ZDRay keywords +xx(lm_sampledist) +xx(lm_sampledist_top) +xx(lm_sampledist_mid) +xx(lm_sampledist_bot) +xx(lm_sampledist_floor) +xx(lm_sampledist_ceiling) +xx(lm_dynamic) +xx(lm_suncolor) + +// Light keywords +xx(SoftShadowRadius) + +xx(skew_bottom_type) +xx(skew_middle_type) +xx(skew_top_type) +xx(skew_bottom) +xx(skew_middle) +xx(skew_top) + +xx(xscroll) +xx(yscroll) +xx(xscrolltop) +xx(yscrolltop) +xx(xscrollmid) +xx(yscrollmid) +xx(xscrollbottom) +xx(yscrollbottom) +xx(xscrollfloor) +xx(yscrollfloor) +xx(scrollfloormode) +xx(xscrollceiling) +xx(yscrollceiling) +xx(scrollceilingmode) +xx(xthrust) +xx(ythrust) +xx(thrustgroup) +xx(thrustlocation) +xx(colormap) +xx(skyfloor) +xx(skyceiling) +xx(skyfloor2) +xx(skyceiling2) +xx(frictionfactor) +xx(movefactor) + +xx(Corona) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 4ae7352bdaf..f8ee0a8e5be 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -33,10 +33,11 @@ */ #include +#include #include "actor.h" #include "p_conversation.h" -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" #include "v_text.h" #include "gi.h" @@ -52,11 +53,14 @@ #include "sbar.h" #include "p_lnspec.h" #include "p_local.h" -#include "menu/menu.h" +#include "menu.h" #include "g_levellocals.h" #include "vm.h" #include "v_video.h" #include "actorinlines.h" +#include "v_draw.h" +#include "doommenu.h" +#include "g_game.h" static FRandom pr_randomspeech("RandomSpeech"); @@ -149,6 +153,22 @@ int FLevelLocals::FindNode (const FStrifeDialogueNode *node) return rootnode; } +//============================================================================ +// +// ClearConversationStuff +// +// Clear the conversation pointers on the player +// +//============================================================================ + +static void ClearConversationStuff(player_t* player) +{ + player->ConversationFaceTalker = false; + player->ConversationNPC = nullptr; + player->ConversationPC = nullptr; + player->ConversationNPCAngle = nullAngle; +} + //============================================================================ // // CheckStrifeItem @@ -256,17 +276,17 @@ DEFINE_ACTION_FUNCTION(DConversationMenu, SendConversationReply) switch (node) { case -1: - Net_WriteByte(DEM_CONVNULL); + Net_WriteInt8(DEM_CONVNULL); break; case -2: - Net_WriteByte(DEM_CONVCLOSE); + Net_WriteInt8(DEM_CONVCLOSE); break; default: - Net_WriteByte(DEM_CONVREPLY); - Net_WriteWord(node); - Net_WriteByte(reply); + Net_WriteInt8(DEM_CONVREPLY); + Net_WriteInt16(node); + Net_WriteInt8(reply); break; } StaticLastReply = reply; @@ -374,13 +394,15 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang } } + // [Nash] Play voice clip from the actor so that positional audio can be heard by all players + if (CurNode->SpeakerVoice != NO_SOUND) S_Sound(npc, CHAN_VOICE, CHANF_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM); + // The rest is only done when the conversation is actually displayed. if (pc->player == Level->GetConsolePlayer()) { - if (CurNode->SpeakerVoice != 0) + if (CurNode->SpeakerVoice != NO_SOUND) { I_SetMusicVolume (dlg_musicvolume); - S_Sound (npc, CHAN_VOICE, CHANF_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM); } M_StartControlPanel(false, true); @@ -469,6 +491,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply if (!(npc->flags8 & MF8_DONTFACETALKER)) npc->Angles.Yaw = player->ConversationNPCAngle; npc->flags5 &= ~MF5_INCONVERSATION; + if (gameaction != ga_intermission) ClearConversationStuff(player); return; } @@ -480,12 +503,13 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply // No, you don't. Say so and let the NPC animate negatively. if (reply->QuickNo.IsNotEmpty() && isconsole) { - TerminalResponse(reply->QuickNo); + TerminalResponse(reply->QuickNo.GetChars()); } npc->ConversationAnimation(2); if (!(npc->flags8 & MF8_DONTFACETALKER)) npc->Angles.Yaw = player->ConversationNPCAngle; npc->flags5 &= ~MF5_INCONVERSATION; + if (gameaction != ga_intermission) ClearConversationStuff(player); return; } } @@ -526,7 +550,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } if (reply->GiveType->IsDescendantOf("SlideshowStarter")) - gameaction = ga_slideshow; + G_StartSlideshow(primaryLevel, NAME_None); } else { @@ -552,7 +576,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply { TakeStrifeItem (player, reply->ItemCheck[i].Item, reply->ItemCheck[i].Amount); } - replyText = reply->QuickYes; + replyText = reply->QuickYes.GetChars(); } else { @@ -562,10 +586,10 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply // Update the quest log, if needed. if (reply->LogString.IsNotEmpty()) { - const char *log = reply->LogString; + const char *log = reply->LogString.GetChars(); if (log[0] == '$') { - log = GStrings(log + 1); + log = GStrings.GetString(log + 1); } player->SetLogText(log); @@ -595,7 +619,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply if (!(reply->CloseDialog)) { - if (gameaction != ga_slideshow) + if (gameaction != ga_intermission) { P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false); return; @@ -621,13 +645,10 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply // [CW] Set these to NULL because we're not using to them // anymore. However, this can interfere with slideshows // so we don't set them to NULL in that case. - if (gameaction != ga_slideshow) + if (gameaction != ga_intermission) { npc->flags5 &= ~MF5_INCONVERSATION; - player->ConversationFaceTalker = false; - player->ConversationNPC = nullptr; - player->ConversationPC = nullptr; - player->ConversationNPCAngle = 0.; + ClearConversationStuff(player); } if (isconsole) @@ -656,8 +677,8 @@ void P_ConversationCommand (int netcode, int pnum, uint8_t **stream) } if (netcode == DEM_CONVREPLY) { - int nodenum = ReadWord(stream); - int replynum = ReadByte(stream); + int nodenum = ReadInt16(stream); + int replynum = ReadInt8(stream); HandleReply(player, pnum == consoleplayer, nodenum, replynum); } else @@ -671,10 +692,7 @@ void P_ConversationCommand (int netcode, int pnum, uint8_t **stream) } if (netcode == DEM_CONVNULL) { - player->ConversationFaceTalker = false; - player->ConversationNPC = nullptr; - player->ConversationPC = nullptr; - player->ConversationNPCAngle = 0.; + ClearConversationStuff(player); } } } @@ -695,12 +713,12 @@ static void TerminalResponse (const char *str) // handle string table replacement if (str[0] == '$') { - str = GStrings(str + 1); + str = GStrings.GetString(str + 1); } if (StatusBar != NULL) { - Printf(PRINT_NONOTIFY, "%s\n", str); + Printf(PRINT_HIGH | PRINT_NONOTIFY, "%s\n", str); // The message is positioned a bit above the menu choices, because // merchants can tell you something like this but continue to show // their dialogue screen. I think most other conversations use this diff --git a/src/p_conversation.h b/src/p_conversation.h index 4b0497a511f..d674b3d53e9 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -4,7 +4,7 @@ #include #include "s_sound.h" -#include "textures/textures.h" +#include "textures.h" struct FStrifeDialogueReply; class FTexture; @@ -29,7 +29,7 @@ struct FStrifeDialogueNode PClassActor *SpeakerType = nullptr; FString SpeakerName; - FSoundID SpeakerVoice = 0; + FSoundID SpeakerVoice = NO_SOUND; FString Backdrop; FString Dialogue; FString Goodbye; // must init to null for binary scripts to work as intended @@ -72,7 +72,5 @@ void P_ResumeConversation (); void P_ConversationCommand (int netcode, int player, uint8_t **stream); -class FileReader; - #endif diff --git a/src/p_openmap.cpp b/src/p_openmap.cpp index 765d91797dc..ef688cda6b9 100644 --- a/src/p_openmap.cpp +++ b/src/p_openmap.cpp @@ -37,9 +37,14 @@ #include "p_setup.h" #include "cmdlib.h" -#include "w_wad.h" +#include "filesystem.h" #include "md5.h" #include "g_levellocals.h" +#include "cmdlib.h" + +#define IWAD_ID MAKE_ID('I','W','A','D') +#define PWAD_ID MAKE_ID('P','W','A','D') + inline bool P_IsBuildMap(MapData *map) { @@ -76,6 +81,7 @@ static int GetMapIndex(const char *mapname, int lastindex, const char *lumpname, {"REJECT", false}, {"BLOCKMAP", false}, {"BEHAVIOR", false}, + {"LIGHTMAP", false }, //{"SCRIPTS", false}, }; @@ -119,8 +125,8 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) delete map; return NULL; } - map->resource = FResourceFile::OpenResourceFile(mapname, true); - wadReader = map->resource->GetReader(); + map->resource = FResourceFile::OpenResourceFile(mapname); + wadReader = map->resource->GetContainerReader(); } else { @@ -132,16 +138,16 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) // Check for both *.wad and *.map in order to load Build maps // as well. The higher one will take precedence. // Names with more than 8 characters will only be checked as .wad and .map. - if (strlen(mapname) <= 8) lump_name = Wads.CheckNumForName(mapname); + if (strlen(mapname) <= 8) lump_name = fileSystem.CheckNumForName(mapname); fmt.Format("maps/%s.wad", mapname); - lump_wad = Wads.CheckNumForFullName(fmt); + lump_wad = fileSystem.CheckNumForFullName(fmt.GetChars()); fmt.Format("maps/%s.map", mapname); - lump_map = Wads.CheckNumForFullName(fmt); + lump_map = fileSystem.CheckNumForFullName(fmt.GetChars()); if (lump_name > lump_wad && lump_name > lump_map && lump_name != -1) { - int lumpfile = Wads.GetLumpFile(lump_name); - int nextfile = Wads.GetLumpFile(lump_name+1); + int lumpfile = fileSystem.GetFileContainer(lump_name); + int nextfile = fileSystem.GetFileContainer(lump_name+1); map->lumpnum = lump_name; @@ -149,7 +155,7 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) { // The following lump is from a different file so whatever this is, // it is not a multi-lump Doom level so let's assume it is a Build map. - map->MapLumps[0].Reader = Wads.ReopenLumpReader(lump_name); + map->MapLumps[0].Reader = fileSystem.ReopenFileReader(lump_name); if (!P_IsBuildMap(map)) { delete map; @@ -160,30 +166,19 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) // This case can only happen if the lump is inside a real WAD file. // As such any special handling for other types of lumps is skipped. - map->MapLumps[0].Reader = Wads.ReopenLumpReader(lump_name); - strncpy(map->MapLumps[0].Name, Wads.GetLumpFullName(lump_name), 8); - map->Encrypted = Wads.IsEncryptedFile(lump_name); + map->MapLumps[0].Reader = fileSystem.ReopenFileReader(lump_name); + strncpy(map->MapLumps[0].Name, fileSystem.GetFileFullName(lump_name), 8); map->InWad = true; - if (map->Encrypted) - { // If it's encrypted, then it's a Blood file, presumably a map. - if (!P_IsBuildMap(map)) - { - delete map; - return NULL; - } - return map; - } - int index = 0; - if (stricmp(Wads.GetLumpFullName(lump_name + 1), "TEXTMAP") != 0) + if (stricmp(fileSystem.GetFileFullName(lump_name + 1), "TEXTMAP") != 0) { for(int i = 1;; i++) { // Since levels must be stored in WADs they can't really have full // names and for any valid level lump this always returns the short name. - const char * lumpname = Wads.GetLumpFullName(lump_name + i); + const char * lumpname = fileSystem.GetFileFullName(lump_name + i); try { index = GetMapIndex(mapname, index, lumpname, !justcheck); @@ -203,17 +198,17 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) // The next lump is not part of this map anymore if (index < 0) break; - map->MapLumps[index].Reader = Wads.ReopenLumpReader(lump_name + i); + map->MapLumps[index].Reader = fileSystem.ReopenFileReader(lump_name + i); strncpy(map->MapLumps[index].Name, lumpname, 8); } } else { map->isText = true; - map->MapLumps[1].Reader = Wads.ReopenLumpReader(lump_name + 1); + map->MapLumps[1].Reader = fileSystem.ReopenFileReader(lump_name + 1); for(int i = 2;; i++) { - const char * lumpname = Wads.GetLumpFullName(lump_name + i); + const char * lumpname = fileSystem.GetFileFullName(lump_name + i); if (lumpname == NULL) { @@ -241,12 +236,16 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) index = ML_BEHAVIOR; map->HasBehavior = true; } + else if (!stricmp(lumpname, "LIGHTMAP")) + { + index = ML_LIGHTMAP; + } else if (!stricmp(lumpname, "ENDMAP")) { break; } else continue; - map->MapLumps[index].Reader = Wads.ReopenLumpReader(lump_name + i); + map->MapLumps[index].Reader = fileSystem.ReopenFileReader(lump_name + i); strncpy(map->MapLumps[index].Name, lumpname, 8); } } @@ -264,9 +263,9 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) return NULL; } map->lumpnum = lump_wad; - auto reader = Wads.ReopenLumpReader(lump_wad); - map->resource = FResourceFile::OpenResourceFile(Wads.GetLumpFullName(lump_wad), reader, true); - wadReader = map->resource->GetReader(); + auto reader = fileSystem.ReopenFileReader(lump_wad); + map->resource = FResourceFile::OpenResourceFile(fileSystem.GetFileFullName(lump_wad), reader, true); + wadReader = map->resource->GetContainerReader(); } } uint32_t id; @@ -281,21 +280,21 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) char maplabel[9]=""; int index=0; - map->MapLumps[0].Reader = map->resource->GetLump(0)->NewReader(); - strncpy(map->MapLumps[0].Name, map->resource->GetLump(0)->Name, 8); + map->MapLumps[0].Reader = map->resource->GetEntryReader(0, FileSys::READER_SHARED); + uppercopy(map->MapLumps[0].Name, map->resource->getName(0)); - for(uint32_t i = 1; i < map->resource->LumpCount(); i++) + for(uint32_t i = 1; i < map->resource->EntryCount(); i++) { - const char* lumpname = map->resource->GetLump(i)->Name; + const char* lumpname = map->resource->getName(i); if (i == 1 && !strnicmp(lumpname, "TEXTMAP", 8)) { map->isText = true; - map->MapLumps[ML_TEXTMAP].Reader = map->resource->GetLump(i)->NewReader(); + map->MapLumps[ML_TEXTMAP].Reader = map->resource->GetEntryReader(i, FileSys::READER_SHARED); strncpy(map->MapLumps[ML_TEXTMAP].Name, lumpname, 8); for(int i = 2;; i++) { - lumpname = map->resource->GetLump(i)->Name; + lumpname = map->resource->getName(i); if (!strnicmp(lumpname, "ZNODES",8)) { index = ML_GLZNODES; @@ -318,12 +317,16 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) index = ML_BEHAVIOR; map->HasBehavior = true; } + else if (!strnicmp(lumpname, "LIGHTMAP", 8)) + { + index = ML_LIGHTMAP; + } else if (!strnicmp(lumpname, "ENDMAP",8)) { return map; } else continue; - map->MapLumps[index].Reader = map->resource->GetLump(i)->NewReader(); + map->MapLumps[index].Reader = map->resource->GetEntryReader(i, FileSys::READER_SHARED); strncpy(map->MapLumps[index].Name, lumpname, 8); } } @@ -355,7 +358,7 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) maplabel[8]=0; } - map->MapLumps[index].Reader = map->resource->GetLump(i)->NewReader(); + map->MapLumps[index].Reader = map->resource->GetEntryReader(i, FileSys::READER_SHARED); strncpy(map->MapLumps[index].Name, lumpname, 8); } } @@ -395,19 +398,19 @@ void MapData::GetChecksum(uint8_t cksum[16]) if (isText) { - md5.Update(Reader(ML_TEXTMAP), Size(ML_TEXTMAP)); + md5Update(Reader(ML_TEXTMAP), md5, Size(ML_TEXTMAP)); } else { - md5.Update(Reader(ML_LABEL), Size(ML_LABEL)); - md5.Update(Reader(ML_THINGS), Size(ML_THINGS)); - md5.Update(Reader(ML_LINEDEFS), Size(ML_LINEDEFS)); - md5.Update(Reader(ML_SIDEDEFS), Size(ML_SIDEDEFS)); - md5.Update(Reader(ML_SECTORS), Size(ML_SECTORS)); + md5Update(Reader(ML_LABEL), md5, Size(ML_LABEL)); + md5Update(Reader(ML_THINGS), md5, Size(ML_THINGS)); + md5Update(Reader(ML_LINEDEFS), md5, Size(ML_LINEDEFS)); + md5Update(Reader(ML_SIDEDEFS), md5, Size(ML_SIDEDEFS)); + md5Update(Reader(ML_SECTORS), md5, Size(ML_SECTORS)); } if (HasBehavior) { - md5.Update(Reader(ML_BEHAVIOR), Size(ML_BEHAVIOR)); + md5Update(Reader(ML_BEHAVIOR), md5, Size(ML_BEHAVIOR)); } md5.Final(cksum); } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index add4ce024ba..e5812475979 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -52,7 +52,8 @@ #include "sbar.h" #include "r_utility.h" #include "r_sky.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "g_levellocals.h" #include "events.h" #include "p_destructible.h" @@ -60,6 +61,8 @@ #include "version.h" #include "fragglescript/t_script.h" #include "s_music.h" +#include "model.h" +#include "d_net.h" EXTERN_CVAR(Bool, save_formatted) @@ -74,16 +77,18 @@ FSerializer &Serialize(FSerializer &arc, const char *key, line_t &line, line_t * if (arc.BeginObject(key)) { arc("flags", line.flags, def->flags) + ("flags2", line.flags2, def->flags2) ("activation", line.activation, def->activation) ("special", line.special, def->special) ("alpha", line.alpha, def->alpha) - .Args("args", line.args, def->args, line.special) ("portalindex", line.portalindex, def->portalindex) ("locknumber", line.locknumber, def->locknumber) - ("health", line.health, def->health) + ("health", line.health, def->health); // Unless the map loader is changed the sidedef references will not change between map loads so there's no need to save them. //.Array("sides", line.sidedef, 2) - .EndObject(); + + SerializeArgs(arc, "args", line.args, def->args, line.special); + arc.EndObject(); } return arc; @@ -136,6 +141,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, side_t::part &part, si ("texture", part.texture, def->texture) ("interpolation", part.interpolation) ("flags", part.flags, def->flags) + ("skew", part.skew, def->skew) ("color1", part.SpecialColors[0], def->SpecialColors[0]) ("color2", part.SpecialColors[1], def->SpecialColors[1]) ("addcolor", part.AdditiveColor, def->AdditiveColor) @@ -298,11 +304,12 @@ FSerializer &Serialize(FSerializer &arc, const char *key, sector_t &p, sector_t //("bottommap", p.bottommap) //("midmap", p.midmap) //("topmap", p.topmap) + //("selfmap", p.selfmap) // todo: if this becomes changeable we need a colormap serializer. ("damageamount", p.damageamount, def->damageamount) ("damageinterval", p.damageinterval, def->damageinterval) ("leakydamage", p.leakydamage, def->leakydamage) ("damagetype", p.damagetype, def->damagetype) - ("sky", p.sky, def->sky) + ("sky", p.skytransfer, def->skytransfer) ("moreflags", p.MoreFlags, def->MoreFlags) ("flags", p.Flags, def->Flags) .Array("portals", p.Portals, def->Portals, 2, true) @@ -324,14 +331,15 @@ FSerializer &Serialize(FSerializer &arc, const char *key, sector_t &p, sector_t .Array("specialcolors", p.SpecialColors, def->SpecialColors, 5, true) .Array("additivecolors", p.AdditiveColors, def->AdditiveColors, 5, true) ("gravity", p.gravity, def->gravity) - .Terrain("floorterrain", p.terrainnum[0], &def->terrainnum[0]) - .Terrain("ceilingterrain", p.terrainnum[1], &def->terrainnum[1]) ("healthfloor", p.healthfloor, def->healthfloor) ("healthceiling", p.healthceiling, def->healthceiling) ("health3d", p.health3d, def->health3d) // GZDoom exclusive: - .Array("reflect", p.reflect, def->reflect, 2, true) - .EndObject(); + .Array("reflect", p.reflect, def->reflect, 2, true); + + SerializeTerrain(arc, "floorterrain", p.terrainnum[0], &def->terrainnum[0]); + SerializeTerrain(arc, "ceilingterrain", p.terrainnum[1], &def->terrainnum[1]); + arc.EndObject(); } return arc; } @@ -374,7 +382,7 @@ FSerializer &FLevelLocals::SerializeSubsectors(FSerializer &arc, const char *key auto numsubsectors = subsectors.Size(); if (arc.isWriting()) { - TArray encoded(1 + (numsubsectors + 5) / 6); + TArray encoded(1 + (numsubsectors + 5) / 6, true); int p = 0; for (unsigned i = 0; i < numsubsectors; i += 6) { @@ -521,9 +529,12 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj &poly, FPolyO if (arc.isReading()) { - poly.RotatePolyobj(angle, true); - delta -= poly.StartSpot.pos; - poly.MovePolyobj(delta, true); + if (poly.OriginalPts.Size() > 0) + { + poly.RotatePolyobj(angle, true); + delta -= poly.StartSpot.pos; + poly.MovePolyobj(delta, true); + } } } return arc; @@ -643,6 +654,15 @@ void FLevelLocals::SerializePlayers(FSerializer &arc, bool skipload) ReadMultiplePlayers(arc, numPlayers, numPlayersNow, skipload); } arc.EndArray(); + + if (!skipload) + { + for (unsigned int i = 0u; i < MAXPLAYERS; ++i) + { + if (PlayerInGame(i) && Players[i]->mo != nullptr) + NetworkEntityManager::SetClientNetworkEntity(Players[i]->mo, i); + } + } } if (!skipload && numPlayersNow > numPlayers) { @@ -809,7 +829,7 @@ void FLevelLocals::ReadMultiplePlayers(FSerializer &arc, int numPlayers, int num } else { - for (i = 0; i < MAXPLAYERS; ++i) + for (i = 0; i < numPlayers; ++i) { players[i].mo = playertemp[i].mo; } @@ -847,7 +867,7 @@ void FLevelLocals::CopyPlayer(player_t *dst, player_t *src, const char *name) if (dst->Bot != nullptr) { botinfo_t *thebot = BotInfo.botinfo; - while (thebot && stricmp(name, thebot->name)) + while (thebot && thebot->Name.CompareNoCase(name)) { thebot = thebot->next; } @@ -862,11 +882,11 @@ void FLevelLocals::CopyPlayer(player_t *dst, player_t *src, const char *name) { dst->userinfo.TransferFrom(uibackup); // The player class must come from the save, so that the menu reflects the currently playing one. - dst->userinfo.PlayerClassChanged(src->mo->GetInfo()->DisplayName); + dst->userinfo.PlayerClassChanged(src->mo->GetInfo()->DisplayName.GetChars()); } // Validate the skin - dst->userinfo.SkinNumChanged(R_FindSkin(Skins[dst->userinfo.GetSkin()].Name, dst->CurrentPlayerClass)); + dst->userinfo.SkinNumChanged(R_FindSkin(Skins[dst->userinfo.GetSkin()].Name.GetChars(), dst->CurrentPlayerClass)); // Make sure the player pawn points to the proper player struct. if (dst->mo != nullptr) @@ -948,17 +968,23 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) } arc("saveversion", SaveVersion); + // this sets up some static data needed further down which means it must be done first. + StaticSerializeTranslations(arc); + if (arc.isReading()) { Thinkers.DestroyAllThinkers(); interpolator.ClearInterpolations(); arc.ReadObjects(hubload); + // If there have been object deserialization errors we must absolutely not continue here because scripted objects can do unpredictable things. + if (arc.mObjectErrors) I_Error("Failed to load savegame"); } arc("multiplayer", multiplayer); arc("flags", flags) ("flags2", flags2) + ("flags3", flags3) ("fadeto", fadeto) ("found_secrets", found_secrets) ("found_items", found_items) @@ -1025,7 +1051,6 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) arc("polyobjs", Polyobjects); SerializeSubsectors(arc, "subsectors"); StatusBar->SerializeMessages(arc); - FRemapTable::StaticSerializeTranslations(arc); canvasTextureInfo.Serialize(arc); SerializePlayers(arc, hubload); SerializeSounds(arc); @@ -1057,6 +1082,8 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) automap->UpdateShowAllLines(); } + // clean up the static data we allocated + StaticClearSerializeTranslationsData(); } @@ -1072,7 +1099,7 @@ void FLevelLocals::SnapshotLevel() if (info->isValid()) { - FSerializer arc(this); + FDoomSerializer arc(this); if (arc.OpenWriter(save_formatted)) { @@ -1097,7 +1124,7 @@ void FLevelLocals::UnSnapshotLevel(bool hubLoad) if (info->isValid()) { - FSerializer arc(this); + FDoomSerializer arc(this); if (!arc.OpenReader(&info->Snapshot)) { I_Error("Failed to load savegame"); @@ -1121,7 +1148,7 @@ void FLevelLocals::UnSnapshotLevel(bool hubLoad) // If this isn't the unmorphed original copy of a player, destroy it, because it's extra. for (i = 0; i < MAXPLAYERS; ++i) { - if (PlayerInGame(i) && Players[i]->morphTics && Players[i]->mo->alternative == pawn) + if (PlayerInGame(i) && Players[i]->mo->alternative == pawn) { break; } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index b7d5540cafa..23bf28e981f 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -30,11 +30,11 @@ #include // for alloca() #endif -#include "templates.h" + #include "d_player.h" #include "m_argv.h" #include "g_game.h" -#include "w_wad.h" +#include "filesystem.h" #include "p_local.h" #include "p_effect.h" #include "p_terrain.h" @@ -44,7 +44,7 @@ #include "p_acs.h" #include "announcer.h" #include "wi_stuff.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "gi.h" #include "p_conversation.h" #include "a_keys.h" @@ -67,7 +67,7 @@ #include "p_destructible.h" #include "types.h" #include "i_time.h" -#include "scripting/vm/vm.h" +#include "vm.h" #include "a_specialspot.h" #include "maploader/maploader.h" #include "p_acs.h" @@ -76,6 +76,10 @@ #include "v_video.h" #include "fragglescript/t_script.h" #include "s_music.h" +#include "animations.h" +#include "texturemanager.h" +#include "p_lnspec.h" +#include "d_main.h" extern AActor *SpawnMapThing (int index, FMapThing *mthing, int position); @@ -98,11 +102,11 @@ static void AddToList(uint8_t *hitlist, FTextureID texid, int bitmask) const auto addAnimations = [hitlist, bitmask](const FTextureID texid) { - for (auto anim : TexMan.mAnimations) + for (auto& anim : TexAnim.GetAnimations()) { - if (texid == anim->BasePic || (!anim->bDiscrete && anim->BasePic < texid && texid < anim->BasePic + anim->NumFrames)) + if (texid == anim.BasePic || (!anim.bDiscrete && anim.BasePic < texid && texid < anim.BasePic + anim.NumFrames)) { - for (int i = anim->BasePic.GetIndex(); i < anim->BasePic.GetIndex() + anim->NumFrames; i++) + for (int i = anim.BasePic.GetIndex(); i < anim.BasePic.GetIndex() + anim.NumFrames; i++) { hitlist[i] |= (uint8_t)bitmask; } @@ -112,7 +116,7 @@ static void AddToList(uint8_t *hitlist, FTextureID texid, int bitmask) addAnimations(texid); - auto switchdef = TexMan.FindSwitch(texid); + auto switchdef = TexAnim.FindSwitch(texid); if (switchdef) { const FSwitchDef *const pair = switchdef->PairDef; @@ -136,7 +140,7 @@ static void AddToList(uint8_t *hitlist, FTextureID texid, int bitmask) } } - auto adoor = TexMan.FindAnimatedDoor(texid); + auto adoor = TexAnim.FindAnimatedDoor(texid); if (adoor) { for (int i = 0; i < adoor->NumTextureFrames; i++) @@ -182,13 +186,21 @@ static void PrecacheLevel(FLevelLocals *Level) { AddToList(hitlist.Data(), Level->sectors[i].GetTexture(sector_t::floor), FTextureManager::HIT_Flat); AddToList(hitlist.Data(), Level->sectors[i].GetTexture(sector_t::ceiling), FTextureManager::HIT_Flat); + AddToList(hitlist.Data(), Level->sectors[i].planes[0].skytexture[0], FTextureManager::HIT_Wall); + AddToList(hitlist.Data(), Level->sectors[i].planes[0].skytexture[1], FTextureManager::HIT_Wall); + AddToList(hitlist.Data(), Level->sectors[i].planes[1].skytexture[0], FTextureManager::HIT_Wall); + AddToList(hitlist.Data(), Level->sectors[i].planes[1].skytexture[1], FTextureManager::HIT_Wall); } for (i = Level->sides.Size() - 1; i >= 0; i--) { - AddToList(hitlist.Data(), Level->sides[i].GetTexture(side_t::top), FTextureManager::HIT_Wall); - AddToList(hitlist.Data(), Level->sides[i].GetTexture(side_t::mid), FTextureManager::HIT_Wall); - AddToList(hitlist.Data(), Level->sides[i].GetTexture(side_t::bottom), FTextureManager::HIT_Wall); + auto &sd = Level->sides[i]; + int hitflag = FTextureManager::HIT_Wall; + // Only precache skyboxes when this is actually used as a sky transfer. + if (sd.linedef->sidedef[0] == &sd && sd.linedef->special == Static_Init && sd.linedef->args[1] == Init_TransferSky) hitflag |= FTextureManager::HIT_Sky; + AddToList(hitlist.Data(), sd.GetTexture(side_t::top), hitflag); + AddToList(hitlist.Data(), sd.GetTexture(side_t::mid), FTextureManager::HIT_Wall); + AddToList(hitlist.Data(), sd.GetTexture(side_t::bottom), hitflag); } @@ -201,14 +213,16 @@ static void PrecacheLevel(FLevelLocals *Level) AddToList(hitlist.Data(), Level->skytexture2, FTextureManager::HIT_Sky); } + static const BITFIELD checkForTextureFlags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst | FTextureManager::TEXMAN_DontCreate; + for (auto n : gameinfo.PrecachedTextures) { - FTextureID tex = TexMan.CheckForTexture(n, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); + FTextureID tex = TexMan.CheckForTexture(n.GetChars(), ETextureType::Wall, checkForTextureFlags); if (tex.Exists()) AddToList(hitlist.Data(), tex, FTextureManager::HIT_Wall); } for (unsigned i = 0; i < Level->info->PrecacheTextures.Size(); i++) { - FTextureID tex = TexMan.CheckForTexture(Level->info->PrecacheTextures[i], ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); + FTextureID tex = TexMan.CheckForTexture(Level->info->PrecacheTextures[i].GetChars(), ETextureType::Wall, checkForTextureFlags); if (tex.Exists()) AddToList(hitlist.Data(), tex, FTextureManager::HIT_Wall); } @@ -235,11 +249,11 @@ void FLevelLocals::ClearPortals() PortalBlockmap.Clear(); // The first entry must always be the default skybox. This is what every sector gets by default. - memset(§orPortals[0], 0, sizeof(sectorPortals[0])); + sectorPortals[0].Clear(); sectorPortals[0].mType = PORTS_SKYVIEWPOINT; sectorPortals[0].mFlags = PORTSF_SKYFLATONLY; // The second entry will be the default sky. This is for forcing a regular sky through the skybox picker - memset(§orPortals[1], 0, sizeof(sectorPortals[0])); + sectorPortals[1].Clear(); sectorPortals[1].mType = PORTS_SKYVIEWPOINT; sectorPortals[1].mFlags = PORTSF_SKYFLATONLY; @@ -269,10 +283,19 @@ void FLevelLocals::ClearPortals() // //========================================================================== -void FLevelLocals::ClearLevelData() +void FLevelLocals::ClearLevelData(bool fullgc) { + { + auto it = GetThinkerIterator(NAME_None, STAT_TRAVELLING); + for (AActor *actor = it.Next(); actor != nullptr; actor = it.Next()) + { + actor->BlockingLine = actor->MovementBlockingLine = nullptr; + actor->BlockingFloor = actor->BlockingCeiling = actor->Blocking3DFloor = nullptr; + } + } + interpolator.ClearInterpolations(); // [RH] Nothing to interpolate on a fresh level. - Thinkers.DestroyAllThinkers(); + Thinkers.DestroyAllThinkers(fullgc); ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process. total_monsters = total_items = total_secrets = @@ -297,11 +320,6 @@ void FLevelLocals::ClearLevelData() DialogueRoots.Clear(); ClassRoots.Clear(); - // delete allocated data in the level arrays. - if (sectors.Size() > 0) - { - delete[] sectors[0].e; - } for (auto &sub : subsectors) { if (sub.BSP != nullptr) delete sub.BSP; @@ -318,6 +336,7 @@ void FLevelLocals::ClearLevelData() canvasTextureInfo.EmptyList(); sections.Clear(); segs.Clear(); + extsectors.Clear(); sectors.Clear(); linebuffer.Clear(); subsectorbuffer.Clear(); @@ -356,6 +375,12 @@ void FLevelLocals::ClearLevelData() if (automap) automap->Destroy(); Behaviors.UnloadModules(); localEventManager->Shutdown(); + if (aabbTree) delete aabbTree; + if (levelMesh) delete levelMesh; + aabbTree = nullptr; + levelMesh = nullptr; + if (screen) + screen->SetAABBTree(nullptr); } //========================================================================== @@ -364,13 +389,13 @@ void FLevelLocals::ClearLevelData() // //========================================================================== -void P_FreeLevelData () +void P_FreeLevelData (bool fullgc) { R_FreePastViewers(); for (auto Level : AllLevels()) { - Level->ClearLevelData(); + Level->ClearLevelData(fullgc); } // primaryLevel->FreeSecondaryLevels(); } @@ -406,17 +431,8 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame) { Level->Players[i]->mo = nullptr; } - // [RH] Clear any scripted translation colors the previous level may have set. - for (i = 0; i < int(translationtables[TRANSLATION_LevelScripted].Size()); ++i) - { - FRemapTable *table = translationtables[TRANSLATION_LevelScripted][i]; - if (table != nullptr) - { - delete table; - translationtables[TRANSLATION_LevelScripted][i] = nullptr; - } - } - translationtables[TRANSLATION_LevelScripted].Clear(); + GPalette.ClearTranslationSlot(TRANSLATION_LevelScripted); + // Initial height of PointOfView will be set by player think. auto p = Level->GetConsolePlayer(); @@ -424,7 +440,14 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame) // Make sure all sounds are stopped before Z_FreeTags. S_Start(); - S_StartMusic(); + S_ResetMusic(); + + // Don't start the music if loading a savegame, because the music is stored there. + // Don't start the music if revisiting a level in a hub for the same reason. + if (!primaryLevel->IsReentering()) + { + primaryLevel->SetMusic(); + } // [RH] clear out the mid-screen message C_MidPrint(nullptr, nullptr); @@ -432,7 +455,7 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame) // Free all level data from the previous map P_FreeLevelData(); - MapData *map = P_OpenMapData(Level->MapName, true); + MapData *map = P_OpenMapData(Level->MapName.GetChars(), true); if (map == nullptr) { I_Error("Unable to open map '%s'\n", Level->MapName.GetChars()); @@ -481,6 +504,18 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame) } } } + else if (newGame) + { + for (i = 0; i < MAXPLAYERS; ++i) + { + // Didn't have a player spawn available so spawn it now. + if (Level->PlayerInGame(i) && Level->Players[i]->playerstate == PST_ENTER && Level->Players[i]->mo == nullptr) + { + FPlayerStart* mthing = Level->PickPlayerStart(i); + Level->SpawnPlayer(mthing, i, (Level->flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); + } + } + } // [SP] move unfriendly players around // horribly hacky - yes, this needs rewritten. @@ -581,6 +616,9 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame) auto it = Level->GetThinkerIterator(); AActor* ac; + + Level->flags3 |= LEVEL3_LIGHTCREATED; + // Initial setup of the dynamic lights. while ((ac = it.Next())) { diff --git a/src/p_setup.h b/src/p_setup.h index 0cae8124cbc..e9142b3562f 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -28,10 +28,11 @@ #ifndef __P_SETUP__ #define __P_SETUP__ -#include "resourcefiles/resourcefile.h" +#include "fs_filesystem.h" #include "doomdata.h" #include "r_defs.h" #include "nodebuild.h" +#include "cmdlib.h" struct MapData @@ -64,7 +65,6 @@ struct MapData FileReader nofile; public: bool HasBehavior = false; - bool Encrypted = false; bool isText = false; bool InWad = false; int lumpnum = -1; @@ -141,8 +141,9 @@ MapData * P_OpenMapData(const char * mapname, bool justcheck); bool P_CheckMapData(const char * mapname); void P_SetupLevel (FLevelLocals *Level, int position, bool newGame); +void P_LoadLightmap(MapData *map); -void P_FreeLevelData(); +void P_FreeLevelData(bool fullgc = true); // Called by startup code. void P_Init (void); diff --git a/src/p_states.cpp b/src/p_states.cpp index 50adf53c6e7..841bb492526 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -39,10 +39,13 @@ #include "v_text.h" #include "thingdef.h" #include "r_state.h" +#include "templates.h" +#include "codegen.h" // stores indices for symbolic state labels for some old-style DECORATE functions. FStateLabelStorage StateLabels; +TMap dehExtStates; // Each state is owned by an actor. Actors can own any number of // states, but a single state cannot be owned by more than one @@ -64,22 +67,27 @@ DEFINE_ACTION_FUNCTION(FState, GetSpriteTexture) PARAM_INT(skin); PARAM_FLOAT(scalex); PARAM_FLOAT(scaley); + PARAM_INT(spritenum); + PARAM_INT(framenum); + + int sprnum = (spritenum == -1) ? self->sprite : spritenum; + int frnum = (framenum == -1) ? self->GetFrame() : framenum; spriteframe_t *sprframe; if (skin == 0) { - sprframe = &SpriteFrames[sprites[self->sprite].spriteframes + self->GetFrame()]; + sprframe = &SpriteFrames[sprites[sprnum].spriteframes + frnum]; } else { - sprframe = &SpriteFrames[sprites[Skins[skin].sprite].spriteframes + self->GetFrame()]; + sprframe = &SpriteFrames[sprites[Skins[skin].sprite].spriteframes + frnum]; scalex = Skins[skin].Scale.X; scaley = Skins[skin].Scale.Y; } if (numret > 0) ret[0].SetInt(sprframe->Texture[rotation].GetIndex()); if (numret > 1) ret[1].SetInt(!!(sprframe->Flip & (1 << rotation))); if (numret > 2) ret[2].SetVector2(DVector2(scalex, scaley)); - return MIN(3, numret); + return min(3, numret); } @@ -128,9 +136,18 @@ PClassActor *FState::StaticFindStateOwner (const FState *state, PClassActor *inf // //========================================================================== -FString FState::StaticGetStateName(const FState *state) +FString FState::StaticGetStateName(const FState *state, PClassActor *info) { auto so = FState::StaticFindStateOwner(state); + if (so == nullptr) + { + so = FState::StaticFindStateOwner(state, info); + } + if (so == nullptr) + { + if (state->DehIndex > 0) return FStringf("DehExtraState.%d", state->DehIndex); + return ""; + } return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->GetStates())); } @@ -202,7 +219,7 @@ TArray &MakeStateNameList(const char * fname) // Handle the old names for the existing death states char *name = copystring(fname); firstpart = strtok(name, "."); - switch (firstpart) + switch (firstpart.GetIndex()) { case NAME_Burn: firstpart = NAME_Death; @@ -370,7 +387,7 @@ FState *FStateLabelStorage::GetState(int pos, PClassActor *cls, bool exact) //========================================================================== // -// State label conversion function for scripts +// State label conversion functions for scripts // //========================================================================== @@ -378,7 +395,7 @@ DEFINE_ACTION_FUNCTION(AActor, FindState) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(newstate); - PARAM_BOOL(exact) + PARAM_BOOL(exact); ACTION_RETURN_STATE(StateLabels.GetState(newstate, self->GetClass(), exact)); } @@ -390,6 +407,15 @@ DEFINE_ACTION_FUNCTION(AActor, ResolveState) ACTION_RETURN_STATE(newstate); } +// find state by string instead of label +DEFINE_ACTION_FUNCTION(AActor, FindStateByString) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(newstate); + PARAM_BOOL(exact); + ACTION_RETURN_STATE(self->GetClass()->FindStateByString(newstate.GetChars(), exact)); +} + //========================================================================== // // Search one list of state definitions for the given name @@ -480,8 +506,10 @@ int FStateDefinitions::GetStateLabelIndex (FName statename) { return -1; } - assert((size_t)std->State <= StateArray.Size() + 1); - return (int)((ptrdiff_t)std->State - 1); + if ((size_t)std->State <= StateArray.Size() + 1) + return (int)((ptrdiff_t)std->State - 1); + else + return -1; } //========================================================================== @@ -520,7 +548,7 @@ static int labelcmp(const void *a, const void *b) { FStateLabel *A = (FStateLabel *)a; FStateLabel *B = (FStateLabel *)b; - return ((int)A->Label - (int)B->Label); + return ((int)A->Label.GetIndex() - (int)B->Label.GetIndex()); } FStateLabels *FStateDefinitions::CreateStateLabelList(TArray & statelist) @@ -691,7 +719,7 @@ void FStateDefinitions::RetargetStatePointers (intptr_t count, const char *targe } else { - statelist[i].State = (FState *)copystring (target); + statelist[i].State = (FState *)FxAlloc.Strdup(target); statelist[i].DefineFlags = SDF_LABEL; } } @@ -792,7 +820,6 @@ FState *FStateDefinitions::ResolveGotoLabel (PClassActor *mytype, char *name) { Printf (TEXTCOLOR_RED "Attempt to get invalid state %s from actor %s.\n", label, type->TypeName.GetChars()); } - delete[] namestart; // free the allocated string buffer return state; } @@ -856,7 +883,7 @@ bool FStateDefinitions::SetGotoLabel(const char *string) // copy the text - this must be resolved later! if (laststate != NULL) { // Following a state definition: Modify it. - laststate->NextState = (FState*)copystring(string); + laststate->NextState = (FState*)FxAlloc.Strdup(string); laststate->DefineFlags = SDF_LABEL; laststatebeforelabel = NULL; return true; @@ -866,7 +893,7 @@ bool FStateDefinitions::SetGotoLabel(const char *string) RetargetStates (lastlabel+1, string); if (laststatebeforelabel != NULL) { - laststatebeforelabel->NextState = (FState*)copystring(string); + laststatebeforelabel->NextState = (FState*)FxAlloc.Strdup(string); laststatebeforelabel->DefineFlags = SDF_LABEL; laststatebeforelabel = NULL; } @@ -1020,6 +1047,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor) for (i = 0; i < count; i++) { + realstates[i].DehIndex = -1; // resolve labels and jumps switch (realstates[i].DefineFlags) { @@ -1065,16 +1093,20 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) { for (int i = 0; i < StateList->NumLabels; i++) { - if (StateList->Labels[i].State != NULL) + auto state = StateList->Labels[i].State; + if (state != NULL) { - const PClassActor *owner = FState::StaticFindStateOwner(StateList->Labels[i].State); + const PClassActor *owner = FState::StaticFindStateOwner(state); if (owner == NULL) { - Printf(PRINT_LOG, "%s%s: invalid\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars()); + if (state->DehIndex >= 0) + Printf(PRINT_LOG, "%s%s: DehExtra %d\n", prefix.GetChars(), state->DehIndex); + else + Printf(PRINT_LOG, "%s%s: invalid\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars()); } else { - Printf(PRINT_LOG, "%s%s: %s\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(), FState::StaticGetStateName(StateList->Labels[i].State).GetChars()); + Printf(PRINT_LOG, "%s%s: %s\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(), FState::StaticGetStateName(state).GetChars()); } } if (StateList->Labels[i].Children != NULL) @@ -1126,7 +1158,7 @@ DEFINE_ACTION_FUNCTION(FState, DistanceTo) { // Safely calculate the distance between two states. auto o1 = FState::StaticFindStateOwner(self); - if (o1->OwnsState(other)) retv = int(other - self); + if (o1 && o1->OwnsState(other)) retv = int(other - self); } ACTION_RETURN_INT(retv); } diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 7253eafbe59..59d66a285ce 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -38,6 +38,7 @@ #include "events.h" #include "actorinlines.h" #include "g_game.h" +#include "i_interface.h" extern gamestate_t wipegamestate; extern uint8_t globalfreeze, globalchangefreeze; @@ -157,6 +158,7 @@ void P_Ticker (void) while ((ac = it.Next())) { ac->ClearInterpolation(); + ac->ClearFOVInterpolation(); } P_ThinkParticles(Level); // [RH] make the particles think @@ -175,22 +177,6 @@ void P_Ticker (void) { P_UpdateSpecials(Level); } - it = Level->GetThinkerIterator(); - - // Set dynamic lights at the end of the tick, so that this catches all changes being made through the last frame. - while ((ac = it.Next())) - { - if (ac->flags8 & MF8_RECREATELIGHTS) - { - ac->flags8 &= ~MF8_RECREATELIGHTS; - ac->SetDynamicLights(); - } - // This was merged from P_RunEffects to eliminate the costly duplicate ThinkerIterator loop. - if ((ac->effects || ac->fountaincolor) && !Level->isFrozen()) - { - P_RunEffect(ac, ac->effects); - } - } // for par times Level->time++; diff --git a/src/playsim/a_action.cpp b/src/playsim/a_action.cpp index c5e96adcda4..d9f53903d80 100644 --- a/src/playsim/a_action.cpp +++ b/src/playsim/a_action.cpp @@ -104,7 +104,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse) if (corpse) corpse->Destroy(); corpsequeue.Delete(0); } - corpsequeue.Push(self); + corpsequeue.Push(MakeObjPtr(self)); + GC::WriteBarrier(self); } return 0; } diff --git a/src/playsim/a_corona.cpp b/src/playsim/a_corona.cpp new file mode 100644 index 00000000000..edeba7566fa --- /dev/null +++ b/src/playsim/a_corona.cpp @@ -0,0 +1,34 @@ +/* +** Light Coronas +** Copyright (c) 2022 Nash Muhandes, Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "actor.h" +#include "a_corona.h" +#include "a_dynlight.h" + +#if 0 +IMPLEMENT_CLASS(ACorona, false, false) + +void ACorona::Tick() +{ + Super::Tick(); +} +#endif \ No newline at end of file diff --git a/src/playsim/a_corona.h b/src/playsim/a_corona.h new file mode 100644 index 00000000000..c1863f8a2e2 --- /dev/null +++ b/src/playsim/a_corona.h @@ -0,0 +1,40 @@ +/* +** Light Coronas +** Copyright (c) 2022 Nash Muhandes, Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#pragma once + +#include "actor.h" + +EXTERN_CVAR(Bool, gl_coronas) + +class AActor; + +#if 0 +class ACorona : public AActor +{ + DECLARE_CLASS(ACorona, AActor) + +public: + void Tick(); + + float CoronaFade = 0.0f; +}; +#endif \ No newline at end of file diff --git a/src/playsim/a_decals.cpp b/src/playsim/a_decals.cpp index 8eb4af153b8..1d9aa9b266f 100644 --- a/src/playsim/a_decals.cpp +++ b/src/playsim/a_decals.cpp @@ -40,10 +40,11 @@ #include "decallib.h" #include "c_dispatch.h" #include "d_net.h" -#include "serializer.h" +#include "serializer_doom.h" #include "doomdata.h" #include "g_levellocals.h" #include "vm.h" +#include "texturemanager.h" EXTERN_CVAR (Bool, cl_spreaddecals) EXTERN_CVAR (Int, cl_maxdecals) @@ -242,17 +243,6 @@ void DBaseDecal::SetShade (int r, int g, int b) AlphaColor = MAKEARGB(ColorMatcher.Pick (r, g, b), r, g, b); } -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void DBaseDecal::SetTranslation(uint32_t trans) -{ - Translation = trans; -} - //---------------------------------------------------------------------------- // // Returns the texture the decal stuck to. @@ -340,7 +330,7 @@ FTextureID DBaseDecal::StickToWall (side_t *wall, double x, double y, F3DFloor * else return FNullTextureID(); CalcFracPos (wall, x, y); - FTexture *texture = TexMan.GetTexture(tex); + auto texture = TexMan.GetGameTexture(tex); if (texture == NULL || texture->allowNoDecals()) { @@ -612,19 +602,19 @@ void DBaseDecal::SpreadRight (double r, side_t *feelwall, double wallsize, F3DFl void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, double x, double y, double z, F3DFloor * ffloor) { SpreadInfo spread; - FTexture *tex; + FGameTexture *tex; vertex_t *v1; double rorg, ldx, ldy; GetWallStuff (wall, v1, ldx, ldy); rorg = Length (x - v1->fX(), y - v1->fY()); - if ((tex = TexMan.GetTexture(PicNum)) == NULL) + if ((tex = TexMan.GetGameTexture(PicNum)) == NULL) { return; } - int dwidth = tex->GetDisplayWidth (); + double dwidth = tex->GetDisplayWidth (); spread.DecalWidth = dwidth * ScaleX; spread.DecalLeft = tex->GetDisplayLeftOffset() * ScaleX; @@ -707,7 +697,7 @@ void DImpactDecal::Expired() // //---------------------------------------------------------------------------- -DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color, uint32_t bloodTranslation) +DBaseDecal* DImpactDecal::StaticCreate (FLevelLocals *Level, const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color, FTranslationID bloodTranslation) { if (cl_maxdecals > 0) { @@ -718,7 +708,7 @@ DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const char *name, return StaticCreate (Level, tpl, pos, wall, ffloor, color, bloodTranslation); } } - return NULL; + return nullptr; } //---------------------------------------------------------------------------- @@ -727,10 +717,10 @@ DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const char *name, // //---------------------------------------------------------------------------- -DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color, uint32_t bloodTranslation) +DBaseDecal* DImpactDecal::StaticCreate (FLevelLocals *Level, const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color, FTranslationID bloodTranslation, bool permanent) { - DImpactDecal *decal = NULL; - if (tpl != NULL && cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS)) + DBaseDecal *decal = NULL; + if (tpl != NULL && ((cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS)) || permanent)) { if (tpl->LowerDecal) { @@ -742,11 +732,10 @@ DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const FDecalTempl if (tpl->ShadeColor != tpl_low->ShadeColor) lowercolor=0; else lowercolor = color; - uint32_t lowerTrans = (bloodTranslation != 0 ? bloodTranslation : 0); - - StaticCreate (Level, tpl_low, pos, wall, ffloor, lowercolor, lowerTrans); + StaticCreate (Level, tpl_low, pos, wall, ffloor, lowercolor, bloodTranslation, permanent); } - decal = Level->CreateThinker(pos.Z); + if (!permanent) decal = Level->CreateThinker(pos.Z); + else decal = Level->CreateThinker(pos.Z); if (decal == NULL) { return NULL; @@ -754,9 +743,10 @@ DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const FDecalTempl if (!decal->StickToWall (wall, pos.X, pos.Y, ffloor).isValid()) { + decal->Destroy(); return NULL; } - decal->CheckMax(); + if (!permanent) static_cast(decal)->CheckMax(); tpl->ApplyToDecal (decal, wall); if (color != 0) @@ -765,7 +755,7 @@ DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const FDecalTempl } // [Nash] opaque blood - if (bloodTranslation != 0 && tpl->ShadeColor == 0 && tpl->opaqueBlood) + if (bloodTranslation != NO_TRANSLATION && tpl->ShadeColor == 0 && tpl->opaqueBlood) { decal->SetTranslation(bloodTranslation); decal->RenderStyle = STYLE_Normal; @@ -829,20 +819,42 @@ DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, double ix, doubl // //---------------------------------------------------------------------------- -void SprayDecal(AActor *shooter, const char *name, double distance) +void SprayDecal(AActor *shooter, const char *name, double distance, DVector3 offset, DVector3 direction, bool useBloodColor, uint32_t decalColor) { + //just in case + if (!shooter) + return; + FTraceResults trace; + DVector3 off(0, 0, 0), dir(0, 0, 0); + + //use vanilla offset only if "custom" equal to zero + if (offset.isZero() ) + off = shooter->PosPlusZ(shooter->Height / 2); - DAngle ang = shooter->Angles.Yaw; - DAngle pitch = shooter->Angles.Pitch; - double c = pitch.Cos(); - DVector3 vec(c * ang.Cos(), c * ang.Sin(), -pitch.Sin()); + else + off = shooter->Pos() + offset; + + //same for direction + if (direction.isZero() ) + { + DAngle ang = shooter->Angles.Yaw; + DAngle pitch = shooter->Angles.Pitch; + double c = pitch.Cos(); + dir = DVector3(c * ang.Cos(), c * ang.Sin(), -pitch.Sin()); + } + + else + dir = direction; - if (Trace(shooter->PosPlusZ(shooter->Height / 2), shooter->Sector, vec, distance, 0, ML_BLOCKEVERYTHING, shooter, trace, TRACE_NoSky)) + auto bloodTrans = useBloodColor ? shooter->BloodTranslation : NO_TRANSLATION; + PalEntry entry = !useBloodColor ? (PalEntry)decalColor : shooter->BloodColor; + + if (Trace(off, shooter->Sector, dir, distance, 0, ML_BLOCKEVERYTHING, shooter, trace, TRACE_NoSky)) { if (trace.HitType == TRACE_HitWall) { - DImpactDecal::StaticCreate(shooter->Level, name, trace.HitPos, trace.Line->sidedef[trace.Side], NULL); + DImpactDecal::StaticCreate(shooter->Level, name, trace.HitPos, trace.Line->sidedef[trace.Side], NULL, entry, bloodTrans); } } } @@ -861,30 +873,12 @@ DBaseDecal *ShootDecal(FLevelLocals *Level, const FDecalTemplate *tpl, sector_t } FTraceResults trace; - DBaseDecal *decal; - side_t *wall; Trace(DVector3(x,y,z), sec, DVector3(angle.ToVector(), 0), tracedist, 0, 0, NULL, trace, TRACE_NoSky); if (trace.HitType == TRACE_HitWall) { - if (permanent) - { - decal = Level->CreateThinker(trace.HitPos.Z); - wall = trace.Line->sidedef[trace.Side]; - decal->StickToWall(wall, trace.HitPos.X, trace.HitPos.Y, trace.ffloor); - tpl->ApplyToDecal(decal, wall); - // Spread decal to nearby walls if it does not all fit on this one - if (cl_spreaddecals) - { - decal->Spread(tpl, wall, trace.HitPos.X, trace.HitPos.Y, trace.HitPos.Z, trace.ffloor); - } - return decal; - } - else - { - return DImpactDecal::StaticCreate(Level, tpl, trace.HitPos, trace.Line->sidedef[trace.Side], NULL); - } + return DImpactDecal::StaticCreate(Level, tpl, trace.HitPos, trace.Line->sidedef[trace.Side], trace.ffloor, 0, NO_TRANSLATION, permanent); } return NULL; } @@ -922,7 +916,7 @@ static void SpawnDecal(AActor *self) // Look for a wall within 64 units behind the actor. If none can be // found, then no decal is created, and this actor is destroyed // without effectively doing anything. - if (!ShootDecal(self->Level, tpl, self->Sector, self->X(), self->Y(), self->Z(), self->Angles.Yaw + 180, 64., true)) + if (!ShootDecal(self->Level, tpl, self->Sector, self->X(), self->Y(), self->Z(), self->Angles.Yaw + DAngle::fromDeg(180), 64., true)) { DPrintf (DMSG_WARNING, "Could not find a wall to stick decal to at (%f,%f)\n", self->X(), self->Y()); } diff --git a/src/playsim/a_dynlight.cpp b/src/playsim/a_dynlight.cpp index b538a769f6f..6d67d4e1b84 100644 --- a/src/playsim/a_dynlight.cpp +++ b/src/playsim/a_dynlight.cpp @@ -115,7 +115,7 @@ void AttachLight(AActor *self) light->pPitch = &self->Angles.Pitch; light->pLightFlags = (LightFlags*)&self->IntVar(NAME_lightflags); light->pArgs = self->args; - light->specialf1 = DAngle(double(self->SpawnAngle)).Normalized360().Degrees; + light->specialf1 = DAngle::fromDeg(double(self->SpawnAngle)).Normalized360().Degrees(); light->Sector = self->Sector; light->target = self; light->mShadowmapIndex = 1024; @@ -255,7 +255,7 @@ void FDynamicLight::Tick() if (owned) { - if (!target->state) + if (!target->state || !target->ShouldRenderLocally()) { Deactivate(); return; @@ -395,7 +395,7 @@ void FDynamicLight::UpdateLocation() if (lighttype == FlickerLight || lighttype == RandomFlickerLight || lighttype == PulseLight) { - intensity = float(MAX(GetIntensity(), GetSecondaryIntensity())); + intensity = float(max(GetIntensity(), GetSecondaryIntensity())); } else { @@ -748,6 +748,7 @@ void AActor::AttachLight(unsigned int count, const FLightDefaults *lightdef) AttachedLights.Push(light); } lightdef->ApplyProperties(light); + light->UpdateLocation(); } //========================================================================== @@ -849,6 +850,7 @@ int AttachLightDef(AActor *self, int _lightid, int _lightname) auto userlight = self->UserLights[FindUserLight(self, lightid, true)]; userlight->CopyFrom(*LightDefaults[lightdef]); self->flags8 |= MF8_RECREATELIGHTS; + self->Level->flags3 |= LEVEL3_LIGHTCREATED; return 1; } return 0; @@ -893,6 +895,7 @@ int AttachLightDirect(AActor *self, int _lightid, int type, int color, int radiu userlight->UnsetSpotPitch(); } self->flags8 |= MF8_RECREATELIGHTS; + self->Level->flags3 |= LEVEL3_LIGHTCREATED; return 1; } @@ -912,7 +915,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_AttachLight, AttachLightDirect) PARAM_FLOAT(spoti); PARAM_FLOAT(spoto); PARAM_FLOAT(spotp); - ACTION_RETURN_BOOL(AttachLightDirect(self, lightid, type, color, radius1, radius2, flags, ofs_x, ofs_y, ofs_z, parami, spoti, spoto, spotp)); + ACTION_RETURN_BOOL(AttachLightDirect(self, lightid.GetIndex(), type, color, radius1, radius2, flags, ofs_x, ofs_y, ofs_z, parami, spoti, spoto, spotp)); } //========================================================================== @@ -930,6 +933,7 @@ int RemoveLight(AActor *self, int _lightid) delete self->UserLights[userlight]; self->UserLights.Delete(userlight); self->flags8 |= MF8_RECREATELIGHTS; + self->Level->flags3 |= LEVEL3_LIGHTCREATED; return 1; } return 0; @@ -939,7 +943,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_RemoveLight, RemoveLight) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME(lightid); - ACTION_RETURN_BOOL(RemoveLight(self, lightid)); + ACTION_RETURN_BOOL(RemoveLight(self, lightid.GetIndex())); } diff --git a/src/playsim/a_dynlight.h b/src/playsim/a_dynlight.h index 38f9019bd90..0aee31790f6 100644 --- a/src/playsim/a_dynlight.h +++ b/src/playsim/a_dynlight.h @@ -1,7 +1,7 @@ #pragma once #include "c_cvars.h" #include "actor.h" -#include "r_data/cycler.h" +#include "cycler.h" #include "g_levellocals.h" struct side_t; @@ -40,7 +40,9 @@ enum LightFlag LF_ATTENUATE = 8, LF_NOSHADOWMAP = 16, LF_DONTLIGHTACTORS = 32, - LF_SPOT = 64 + LF_SPOT = 64, + LF_DONTLIGHTOTHERS = 128, + LF_DONTLIGHTMAP = 256 }; typedef TFlags LightFlags; @@ -72,20 +74,23 @@ class FLightDefaults void SetDontLightSelf(bool add) { if (add) m_lightFlags |= LF_DONTLIGHTSELF; else m_lightFlags &= ~LF_DONTLIGHTSELF; } void SetAttenuate(bool on) { m_attenuate = on; if (on) m_lightFlags |= LF_ATTENUATE; else m_lightFlags &= ~LF_ATTENUATE; } void SetDontLightActors(bool on) { if (on) m_lightFlags |= LF_DONTLIGHTACTORS; else m_lightFlags &= ~LF_DONTLIGHTACTORS; } + void SetDontLightOthers(bool on) { if (on) m_lightFlags |= LF_DONTLIGHTOTHERS; else m_lightFlags &= ~LF_DONTLIGHTOTHERS; } + void SetDontLightMap(bool on) { if (on) m_lightFlags |= LF_DONTLIGHTMAP; else m_lightFlags &= ~LF_DONTLIGHTMAP; } void SetNoShadowmap(bool on) { if (on) m_lightFlags |= LF_NOSHADOWMAP; else m_lightFlags &= ~LF_NOSHADOWMAP; } void SetSpot(bool spot) { if (spot) m_lightFlags |= LF_SPOT; else m_lightFlags &= ~LF_SPOT; } - void SetSpotInnerAngle(double angle) { m_spotInnerAngle = angle; } - void SetSpotOuterAngle(double angle) { m_spotOuterAngle = angle; } + void SetSpotInnerAngle(double angle) { m_spotInnerAngle = DAngle::fromDeg(angle); } + void SetSpotOuterAngle(double angle) { m_spotOuterAngle = DAngle::fromDeg(angle); } void SetSpotPitch(double pitch) { - m_pitch = pitch; + m_pitch = DAngle::fromDeg(pitch); m_explicitPitch = true; } void UnsetSpotPitch() { - m_pitch = 0.; + m_pitch = nullAngle; m_explicitPitch = false; } + void SetType(ELightType type) { m_type = type; } void CopyFrom(const FLightDefaults &other) { @@ -120,9 +125,9 @@ class FLightDefaults bool m_swapped = false; bool m_spot = false; bool m_explicitPitch = false; - DAngle m_spotInnerAngle = 10.0; - DAngle m_spotOuterAngle = 25.0; - DAngle m_pitch = 0.0; + DAngle m_spotInnerAngle = DAngle::fromDeg(10.0); + DAngle m_spotOuterAngle = DAngle::fromDeg(25.0); + DAngle m_pitch = nullAngle; friend FSerializer &Serialize(FSerializer &arc, const char *key, FLightDefaults &value, FLightDefaults *def); }; @@ -201,7 +206,10 @@ struct FDynamicLight bool ShouldLightActor(AActor *check) { - return visibletoplayer && IsActive() && (!((*pLightFlags) & LF_DONTLIGHTSELF) || target != check) && !((*pLightFlags) & LF_DONTLIGHTACTORS); + return visibletoplayer && IsActive() && + (!((*pLightFlags) & LF_DONTLIGHTSELF) || target != check) && + (!((*pLightFlags) & LF_DONTLIGHTOTHERS) || target == check) && + (!((*pLightFlags) & LF_DONTLIGHTACTORS)); } void SetOffset(const DVector3 &pos) @@ -225,6 +233,8 @@ struct FDynamicLight bool DontShadowmap() const { return !!((*pLightFlags) & LF_NOSHADOWMAP); } bool DontLightSelf() const { return !!((*pLightFlags) & (LF_DONTLIGHTSELF|LF_DONTLIGHTACTORS)); } // dontlightactors implies dontlightself. bool DontLightActors() const { return !!((*pLightFlags) & LF_DONTLIGHTACTORS); } + bool DontLightOthers() const { return !!((*pLightFlags) & (LF_DONTLIGHTOTHERS)); } + bool DontLightMap() const { return !!((*pLightFlags) & (LF_DONTLIGHTMAP)); } void Deactivate() { m_active = false; } void Activate(); diff --git a/src/playsim/a_flashfader.cpp b/src/playsim/a_flashfader.cpp index e08ae8bf653..41dcc2d8870 100644 --- a/src/playsim/a_flashfader.cpp +++ b/src/playsim/a_flashfader.cpp @@ -35,6 +35,7 @@ #include "a_sharedglobal.h" #include "d_player.h" #include "serializer.h" +#include "serialize_obj.h" #include "g_levellocals.h" IMPLEMENT_CLASS(DFlashFader, false, true) diff --git a/src/playsim/a_morph.cpp b/src/playsim/a_morph.cpp index 80e6807af5b..5f6c38b91a5 100644 --- a/src/playsim/a_morph.cpp +++ b/src/playsim/a_morph.cpp @@ -37,7 +37,7 @@ bool P_MorphActor(AActor *activator, AActor *victim, PClassActor *ptype, PClassA bool P_UnmorphActor(AActor *activator, AActor *morphed, int flags, bool force) { - IFVIRTUALPTR(morphed, AActor, UnMorph) + IFVIRTUALPTR(morphed, AActor, Unmorph) { VMValue params[] = { morphed, activator, flags, force }; int retval; diff --git a/src/playsim/a_morph.h b/src/playsim/a_morph.h index 00303533cbf..762cd01bb5e 100644 --- a/src/playsim/a_morph.h +++ b/src/playsim/a_morph.h @@ -26,6 +26,8 @@ enum MORPH_UNDOBYTIMEOUT = 0x00001000, // Player unmorphs once countdown expires MORPH_UNDOALWAYS = 0x00002000, // Powerups must always unmorph, no matter what. MORPH_TRANSFERTRANSLATION = 0x00004000, // Transfer translation from the original actor to the morphed one + MORPH_KEEPARMOR = 0x00008000, // Don't lose current armor value when morphing. + MORPH_IGNOREINVULN = 0x00010000, // Completely ignore invulnerability status on players. MORPH_STANDARDUNDOING = MORPH_UNDOBYTOMEOFPOWER | MORPH_UNDOBYCHAOSDEVICE | MORPH_UNDOBYTIMEOUT, }; diff --git a/src/playsim/a_pickups.cpp b/src/playsim/a_pickups.cpp index 98347df84a4..d5a9a524ffc 100644 --- a/src/playsim/a_pickups.cpp +++ b/src/playsim/a_pickups.cpp @@ -41,6 +41,7 @@ #include "d_player.h" #include "vm.h" #include "g_levellocals.h" +#include "gi.h" EXTERN_CVAR(Bool, sv_unlimited_pickup) @@ -55,13 +56,14 @@ static FString StaticLastMessage; void PrintPickupMessage(bool localview, const FString &str) { - if (str.IsNotEmpty() && localview && (StaticLastMessageTic != gametic || StaticLastMessage.Compare(str))) + // [MK] merge identical messages on same tic unless disabled in gameinfo + if (str.IsNotEmpty() && localview && (gameinfo.nomergepickupmsg || StaticLastMessageTic != gametic || StaticLastMessage.Compare(str))) { StaticLastMessageTic = gametic; StaticLastMessage = str; const char *pstr = str.GetChars(); - if (pstr[0] == '$') pstr = GStrings(pstr + 1); + if (pstr[0] == '$') pstr = GStrings.GetString(pstr + 1); if (pstr[0] != 0) Printf(PRINT_LOW, "%s\n", pstr); StatusBar->FlashCrosshair(); } diff --git a/src/playsim/a_sharedglobal.h b/src/playsim/a_sharedglobal.h index 9396b10a801..4e4a9403e66 100644 --- a/src/playsim/a_sharedglobal.h +++ b/src/playsim/a_sharedglobal.h @@ -12,7 +12,7 @@ class DBaseDecal; struct SpreadInfo; DBaseDecal *ShootDecal(FLevelLocals *Level, const FDecalTemplate *tpl, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent); -void SprayDecal(AActor *shooter, const char *name,double distance = 172.); +void SprayDecal(AActor *shooter, const char *name,double distance = 172., DVector3 offset = DVector3(0., 0., 0.), DVector3 direction = DVector3(0., 0., 0.), bool useBloodColor = false, uint32_t decalColor = 0); class DBaseDecal : public DThinker { @@ -31,7 +31,11 @@ class DBaseDecal : public DThinker double GetRealZ (const side_t *wall) const; void SetShade (uint32_t rgb); void SetShade (int r, int g, int b); - void SetTranslation(uint32_t trans); + void SetTranslation(FTranslationID trans) + { + Translation = trans; + } + void Spread (const FDecalTemplate *tpl, side_t *wall, double x, double y, double z, F3DFloor * ffloor); void GetXY (side_t *side, double &x, double &y) const; @@ -42,7 +46,7 @@ class DBaseDecal : public DThinker double ScaleX = 1, ScaleY = 1; double Alpha = 1; uint32_t AlphaColor = 0; - int Translation = 0; + FTranslationID Translation = NO_TRANSLATION; FTextureID PicNum; uint32_t RenderFlags = 0; FRenderStyle RenderStyle; @@ -69,8 +73,8 @@ class DImpactDecal : public DBaseDecal } void Construct(side_t *wall, const FDecalTemplate *templ); - static DImpactDecal *StaticCreate(FLevelLocals *Level, const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0, uint32_t bloodTranslation = 0); - static DImpactDecal *StaticCreate(FLevelLocals *Level, const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0, uint32_t bloodTranslation = 0); + static DBaseDecal *StaticCreate(FLevelLocals *Level, const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0, FTranslationID bloodTranslation = NO_TRANSLATION); + static DBaseDecal *StaticCreate(FLevelLocals *Level, const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0, FTranslationID bloodTranslation = NO_TRANSLATION, bool permanent = false); void BeginPlay (); void Expired() override; @@ -112,15 +116,20 @@ enum QF_MAX = 1 << 3, QF_FULLINTENSITY = 1 << 4, QF_WAVE = 1 << 5, + QF_3D = 1 << 6, + QF_GROUNDONLY = 1 << 7, + QF_AFFECTACTORS = 1 << 8, + QF_SHAKEONLY = 1 << 9, + QF_DAMAGEFALLOFF = 1 << 10, }; struct FQuakeJiggers { - DVector3 Intensity; - DVector3 RelIntensity; - DVector3 Offset; - DVector3 RelOffset; - double RollIntensity, RollWave; + DVector3 Intensity = {}; + DVector3 RelIntensity = {}; + DVector3 Offset = {}; + DVector3 RelOffset = {}; + double RollIntensity = 0.0, RollWave = 0.0; }; class DEarthquake : public DThinker @@ -129,9 +138,9 @@ class DEarthquake : public DThinker HAS_OBJECT_POINTERS public: static const int DEFAULT_STAT = STAT_EARTHQUAKE; - void Construct(AActor *center, int intensityX, int intensityY, int intensityZ, int duration, - int damrad, int tremrad, FSoundID quakesfx, int flags, - double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave); + void Construct(AActor *center, double intensityX, double intensityY, double intensityZ, int duration, + double damrad, double tremrad, FSoundID quakesfx, int flags, + double waveSpeedX, double waveSpeedY, double waveSpeedZ, double falloff, int highpoint, double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage); void Serialize(FSerializer &arc); void Tick (); @@ -146,10 +155,13 @@ class DEarthquake : public DThinker double m_Falloff; int m_Highpoint, m_MiniCount; double m_RollIntensity, m_RollWave; + double m_DamageMultiplier, m_ThrustMultiplier; + int m_Damage; double GetModIntensity(double intensity, bool fake = false) const; double GetModWave(double ticFrac, double waveMultiplier) const; - double GetFalloff(double dist) const; + double GetFalloff(double dist, double radius) const; + void DoQuakeDamage(DEarthquake *quake, AActor *victim, bool falloff) const; static int StaticGetQuakeIntensities(double ticFrac, AActor *viewer, FQuakeJiggers &jiggers); }; diff --git a/src/playsim/a_specialspot.cpp b/src/playsim/a_specialspot.cpp index c8261208ce5..b658c183007 100644 --- a/src/playsim/a_specialspot.cpp +++ b/src/playsim/a_specialspot.cpp @@ -35,7 +35,7 @@ #include "a_specialspot.h" #include "p_local.h" #include "doomstat.h" -#include "serializer.h" +#include "serializer_doom.h" #include "a_pickups.h" #include "vm.h" diff --git a/src/playsim/actionspecials.h b/src/playsim/actionspecials.h index d62f93536ee..7cfa43ce56c 100644 --- a/src/playsim/actionspecials.h +++ b/src/playsim/actionspecials.h @@ -138,6 +138,9 @@ DEFINE_SPECIAL(Floor_Waggle, 138, 5, 5, 5) DEFINE_SPECIAL(Thing_SpawnFacing, 139, 2, 4, 4) DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2) +DEFINE_SPECIAL(Line_SetHealth, 150, 2, 2, 2) +DEFINE_SPECIAL(Sector_SetHealth, 151, 3, 3, 3) + DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3) // portal specials DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 4) @@ -152,8 +155,6 @@ DEFINE_SPECIAL(Sector_Set3DFloor, 160, -1, -1, 5) DEFINE_SPECIAL(Sector_SetContents, 161, -1, -1, 3) // [RH] Begin new specials for ZDoom -DEFINE_SPECIAL(Line_SetHealth, 150, 2, 2, 2) -DEFINE_SPECIAL(Sector_SetHealth, 151, 3, 3, 3) DEFINE_SPECIAL(Ceiling_CrushAndRaiseDist, 168, 3, 5, 5) DEFINE_SPECIAL(Generic_Crusher2, 169, 5, 5, 5) DEFINE_SPECIAL(Sector_SetCeilingScale2, 170, 3, 3, 3) @@ -211,7 +212,7 @@ DEFINE_SPECIAL(Scroll_Texture_Both, 221, 5, 5, 5) DEFINE_SPECIAL(Scroll_Texture_Model, 222, -1, -1, 2) DEFINE_SPECIAL(Scroll_Floor, 223, 4, 4, 5) DEFINE_SPECIAL(Scroll_Ceiling, 224, 4, 4, 5) -DEFINE_SPECIAL(Scroll_Texture_Offsets, 225, -1, -1, 1) +DEFINE_SPECIAL(Scroll_Texture_Offsets, 225, -1, -1, 4) DEFINE_SPECIAL(ACS_ExecuteAlways, 226, 1, 5, 5) DEFINE_SPECIAL(PointPush_SetForce, 227, -1, -1, 4) DEFINE_SPECIAL(Plat_RaiseAndStayTx0, 228, 2, 3, 3) @@ -270,5 +271,9 @@ DEFINE_SPECIAL(Floor_MoveToValueAndCrush, 279, 4, 5, 5) DEFINE_SPECIAL(Ceiling_MoveToValueAndCrush, 280, 4, 5, 5) DEFINE_SPECIAL(Line_SetAutomapFlags, 281, 3, 3, 3) DEFINE_SPECIAL(Line_SetAutomapStyle, 282, 2, 2, 2) +DEFINE_SPECIAL(Polyobj_StopSound, 283, 1, 1, 1) +DEFINE_SPECIAL(Generic_CrusherDist, 284, 5, 5, 5) + +DEFINE_SPECIAL(Line_QuickPortal, 301, -1, -1, 1) #undef DEFINE_SPECIAL diff --git a/src/playsim/actor.h b/src/playsim/actor.h index d7ccf45dfb2..30fdc55e873 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -30,7 +30,7 @@ #define __P_MOBJ_H__ // Basics. -#include "templates.h" + // We need the thinker_t stuff. #include "dthinker.h" @@ -40,13 +40,14 @@ #include "info.h" #include "doomdef.h" -#include "textures/textures.h" -#include "r_data/renderstyle.h" +#include "textures.h" +#include "renderstyle.h" #include "s_sound.h" #include "memarena.h" #include "g_level.h" #include "tflags.h" #include "portal.h" +#include "bonecomponents.h" struct subsector_t; struct FBlockNode; @@ -142,7 +143,7 @@ enum ActorFlag MF_DROPOFF = 0x00000400, // allow jumps from high places MF_PICKUP = 0x00000800, // for players to pick up items MF_NOCLIP = 0x00001000, // player cheat - MF_INCHASE = 0x00002000, // [RH] used by A_Chase and A_Look to avoid recursion + MF_SLIDE = 0x00002000, // Not used anymore but needed for MBF21 flag checkers. MF_FLOAT = 0x00004000, // allow moves to any height, no gravity MF_TELEPORT = 0x00008000, // don't cross lines or look at heights MF_MISSILE = 0x00010000, // don't hit same species, explode on block @@ -167,9 +168,6 @@ enum ActorFlag MF_NOLIFTDROP = 0x20000000, // [RH] Used with MF_NOGRAVITY to avoid dropping with lifts MF_STEALTH = 0x40000000, // [RH] Andy Baker's stealth monsters MF_ICECORPSE = 0x80000000, // a frozen corpse (for blasting) [RH] was 0x800000 - - // --- dummies for unknown/unimplemented Strife flags --- - MF_STRIFEx8000000 = 0, // seems related to MF_SHADOW }; // --- mobj.flags2 --- @@ -208,8 +206,7 @@ enum ActorFlag2 // but still considered solid MF2_INVULNERABLE = 0x08000000, // mobj is invulnerable MF2_DORMANT = 0x10000000, // thing is dormant - MF2_ARGSDEFINED = 0x20000000, // Internal flag used by DECORATE to signal that the - // args should not be taken from the mapthing definition + MF2_ARGSDEFINED = 0x20000000, // Internal flag used by DECORATE to signal that the args should not be taken from the mapthing definition MF2_SEEKERMISSILE = 0x40000000, // is a seeker (for reflection) MF2_REFLECTIVE = 0x80000000, // reflects missiles }; @@ -396,10 +393,13 @@ enum ActorFlag7 MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified. MF7_SMASHABLE = 0x04000000, // dies if hitting the floor. MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields. - MF7_FORCEZERORADIUSDMG = 0x10000000, // passes zero radius damage on to P_DamageMobj, this is necessary in some cases where DoSpecialDamage gets overrideen. + MF7_FORCEZERORADIUSDMG = 0x10000000,// passes zero radius damage on to P_DamageMobj, this is necessary in some cases where DoSpecialDamage gets overrideen. MF7_NOINFIGHTSPECIES = 0x20000000, // don't start infights with one's own species. MF7_FORCEINFIGHTING = 0x40000000, // overrides a map setting of 'no infighting'. + MF7_INCHASE = 0x80000000, // [RH] used by A_Chase and A_Look to avoid recursion }; + +// --- mobj.flags8 --- enum ActorFlag8 { MF8_FRIGHTENING = 0x00000001, // for those moments when halloween just won't do @@ -412,6 +412,37 @@ enum ActorFlag8 MF8_RETARGETAFTERSLAM = 0x00000080, // Forces jumping to the idle state after slamming into something MF8_RECREATELIGHTS = 0x00000100, // Internal flag that signifies that the light attachments need to be recreated at the MF8_STOPRAILS = 0x00000200, // [MC] Prevent rails from going further if an actor has this flag. + MF8_ABSVIEWANGLES = 0x00000400, // [MC] By default view angle/pitch/roll is an offset. This will make it absolute instead. + MF8_FALLDAMAGE = 0x00000800, // Monster will take fall damage regardless of map settings. + MF8_MINVISIBLE = 0x00001000, // Actor not visible to monsters + MF8_MVISBLOCKED = 0x00002000, // Monster(only) sight checks to actor always fail + MF8_ALLOWTHRUBITS = 0x00008000, // [MC] Enable ThruBits property + MF8_FULLVOLSEE = 0x00010000, // Play see sound at full volume + MF8_E1M8BOSS = 0x00020000, // MBF21 boss death. + MF8_E2M8BOSS = 0x00040000, // MBF21 boss death. + MF8_E3M8BOSS = 0x00080000, // MBF21 boss death. + MF8_E4M8BOSS = 0x00100000, // MBF21 boss death. + MF8_E4M6BOSS = 0x00200000, // MBF21 boss death. + MF8_MAP07BOSS1 = 0x00400000, // MBF21 boss death. + MF8_MAP07BOSS2 = 0x00800000, // MBF21 boss death. + MF8_AVOIDHAZARDS = 0x01000000, // MBF AI enhancement. + MF8_STAYONLIFT = 0x02000000, // MBF AI enhancement. + MF8_DONTFOLLOWPLAYERS = 0x04000000, // [inkoalawetrust] Friendly monster will not follow players. + MF8_SEEFRIENDLYMONSTERS = 0X08000000, // [inkoalawetrust] Hostile monster can see friendly monsters. + MF8_CROSSLINECHECK = 0x10000000, // [MC] Enables CanCrossLine virtual + MF8_MASTERNOSEE = 0x20000000, // Don't show object in first person if their master is the current camera. + MF8_ADDLIGHTLEVEL = 0x40000000, // [MC] Actor light level is additive with sector. + MF8_ONLYSLAMSOLID = 0x80000000, // [B] Things with skullfly will ignore non-solid Actors. +}; + +// --- mobj.flags9 --- +enum ActorFlag9 +{ + MF9_SHADOWAIM = 0x00000001, // [inkoalawetrust] Monster still gets aim penalty from aiming at shadow actors even with MF6_SEEINVISIBLE on. + MF9_DOSHADOWBLOCK = 0x00000002, // [inkoalawetrust] Should the monster look for SHADOWBLOCK actors ? + MF9_SHADOWBLOCK = 0x00000004, // [inkoalawetrust] Actors in the line of fire with this flag trigger the MF_SHADOW aiming penalty. + MF9_SHADOWAIMVERT = 0x00000008, // [inkoalawetrust] Monster aim is also offset vertically when aiming at shadow actors. + MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states }; // --- mobj.renderflags --- @@ -450,13 +481,28 @@ enum ActorRenderFlag RF_MASKROTATION = 0x00200000, // [MC] Only draw the actor when viewed from a certain angle range. RF_ABSMASKANGLE = 0x00400000, // [MC] The mask rotation does not offset by the actor's angle. RF_ABSMASKPITCH = 0x00800000, // [MC] The mask rotation does not offset by the actor's pitch. - RF_INTERPOLATEANGLES = 0x01000000, // [MC] Allow interpolation of the actor's angle, pitch and roll. + RF_INTERPOLATEANGLES = 0x01000000, // [MC] Allow interpolation of the actor's angle, pitch and roll. RF_MAYBEINVISIBLE = 0x02000000, RF_DONTINTERPOLATE = 0x04000000, // no render interpolation ever! RF_SPRITEFLIP = 0x08000000, // sprite flipped on x-axis RF_ZDOOMTRANS = 0x10000000, // is not normally transparent in Vanilla Doom + RF_CASTSPRITESHADOW = 0x20000000, // actor will cast a sprite shadow RF_NOINTERPOLATEVIEW = 0x40000000, // don't interpolate the view next frame if this actor is a camera. + RF_NOSPRITESHADOW = 0x80000000, // actor will not cast a sprite shadow +}; + +enum ActorRenderFlag2 +{ + RF2_INVISIBLEINMIRRORS = 0x0001, // [Nash] won't render in mirrors + RF2_ONLYVISIBLEINMIRRORS = 0x0002, // [Nash] only renders in mirrors + RF2_BILLBOARDFACECAMERA = 0x0004, // Sprite billboard face camera (override gl_billboard_faces_camera) + RF2_BILLBOARDNOFACECAMERA = 0x0008, // Sprite billboard face camera angle (override gl_billboard_faces_camera) + RF2_FLIPSPRITEOFFSETX = 0x0010, + RF2_FLIPSPRITEOFFSETY = 0x0020, + RF2_CAMFOLLOWSPLAYER = 0x0040, // Matches the cam's base position and angles to the main viewpoint. + RF2_NOMIPMAP = 0x0080, // [Nash] forces no mipmapping on sprites. Useful for tiny sprites that need to remain visually crisp + RF2_ISOMETRICSPRITES = 0x0100, }; // This translucency value produces the closest match to Heretic's TINTTAB. @@ -497,6 +543,7 @@ enum ActorBounceFlag BOUNCE_NotOnShootables = 1<<15, // do not bounce off shootable actors if we are a projectile. Explode instead. BOUNCE_BounceOnUnrips = 1<<16, // projectile bounces on actors with DONTRIP BOUNCE_NotOnSky = 1<<17, // Don't bounce on sky floors / ceilings / walls + BOUNCE_DEH = 1<<18, // Flag was set through Dehacked. BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF, @@ -559,7 +606,9 @@ typedef TFlags ActorFlags5; typedef TFlags ActorFlags6; typedef TFlags ActorFlags7; typedef TFlags ActorFlags8; +typedef TFlags ActorFlags9; typedef TFlags ActorRenderFlags; +typedef TFlags ActorRenderFlags2; typedef TFlags ActorBounceFlags; typedef TFlags ActorRenderFeatureFlags; DEFINE_TFLAGS_OPERATORS (ActorFlags) @@ -570,7 +619,9 @@ DEFINE_TFLAGS_OPERATORS (ActorFlags5) DEFINE_TFLAGS_OPERATORS (ActorFlags6) DEFINE_TFLAGS_OPERATORS (ActorFlags7) DEFINE_TFLAGS_OPERATORS (ActorFlags8) +DEFINE_TFLAGS_OPERATORS (ActorFlags9) DEFINE_TFLAGS_OPERATORS (ActorRenderFlags) +DEFINE_TFLAGS_OPERATORS (ActorRenderFlags2) DEFINE_TFLAGS_OPERATORS (ActorBounceFlags) DEFINE_TFLAGS_OPERATORS (ActorRenderFeatureFlags) @@ -605,6 +656,11 @@ inline AActor *GetDefaultByName (const char *name) return (AActor *)(PClass::FindClass(name)->Defaults); } +inline AActor* GetDefaultByName(FName name) +{ + return (AActor*)(PClass::FindClass(name)->Defaults); +} + inline AActor *GetDefaultByType (const PClass *type) { return (AActor *)(type->Defaults); @@ -635,24 +691,127 @@ struct FDropItem int Amount; }; +enum EViewPosFlags // [MC] Flags for SetViewPos. +{ + VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles. + VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position. + VPSF_ALLOWOUTOFBOUNDS = 1 << 3, // Allow viewpoint to go out of bounds (hardware renderer only). + VPSF_ORTHOGRAPHIC = 1 << 4, // Use orthographic projection (hardware renderer only). +}; + +enum EAnimOverrideFlags +{ + ANIMOVERRIDE_NONE = 1 << 0, // no animation + ANIMOVERRIDE_LOOP = 1 << 1, // animation loops, otherwise it stays on the last frame once it ends +}; + +struct AnimOverride +{ + int firstFrame; + int lastFrame; + int loopFrame; + double startFrame; + int flags = ANIMOVERRIDE_NONE; + float framerate; + double startTic; // when the current animation started (changing framerates counts as restarting) (or when animation starts if interpolating from previous animation) + double switchOffset; // when the animation was changed -- where to interpolate the switch from +}; + +struct ModelOverride +{ + int modelID; + TArray surfaceSkinIDs; +}; + +struct AnimModelOverride +{ + int id; + + AnimModelOverride() = default; + + AnimModelOverride(int i) : id(i) {} + operator int() { return id; } +}; + +enum EModelDataFlags +{ + MODELDATA_HADMODEL = 1 << 0, + MODELDATA_OVERRIDE_FLAGS = 1 << 1, +}; + +class DActorModelData : public DObject +{ + DECLARE_CLASS(DActorModelData, DObject); +public: + PClass * modelDef; + TArray models; + TArray skinIDs; + TArray animationIDs; + TArray modelFrameGenerators; + int flags; + int overrideFlagsSet; + int overrideFlagsClear; + + AnimOverride curAnim; + AnimOverride prevAnim; // used for interpolation when switching anims + + DActorModelData() = default; + virtual void Serialize(FSerializer& arc) override; + virtual void OnDestroy() override; +}; + +class DViewPosition : public DObject +{ + DECLARE_CLASS(DViewPosition, DObject); +public: + // Variables + // Exposed to ZScript + DVector3 Offset; + int Flags; + + // Functions + DViewPosition() + { + Offset = { 0,0,0 }; + Flags = 0; + } + + void Set(DVector3 &off, int f = -1) + { + ZeroSubnormalsF(off.X); + ZeroSubnormalsF(off.Y); + ZeroSubnormalsF(off.Z); + Offset = off; + + if (f > -1) + Flags = f; + } + + bool isZero() const + { + return Offset.isZero(); + } +}; + const double MinVel = EQUAL_EPSILON; // Map Object definition. -class AActor : public DThinker +class AActor final : public DThinker { DECLARE_CLASS_WITH_META (AActor, DThinker, PClassActor) HAS_OBJECT_POINTERS public: AActor() = default; AActor(const AActor &other) = delete; // Calling this would be disastrous. - AActor &operator= (const AActor &other); - ~AActor (); + AActor &operator= (const AActor &other) = delete; + ~AActor () = default; virtual void OnDestroy() override; virtual void Serialize(FSerializer &arc) override; virtual void PostSerialize() override; virtual void PostBeginPlay() override; // Called immediately before the actor's first tick virtual void Tick() override; + void EnableNetworking(const bool enable) override; static AActor *StaticSpawn (FLevelLocals *Level, PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false); @@ -669,18 +828,12 @@ class AActor : public DThinker FDropItem *GetDropItems() const; - // Return true if the monster should use a missile attack, false for melee - bool SuggestMissileAttack (double dist); - // Adjusts the angle for deflection/reflection of incoming missiles // Returns true if the missile should be allowed to explode anyway bool AdjustReflectionAngle (AActor *thing, DAngle &angle); int AbsorbDamage(int damage, FName dmgtype, AActor *inflictor, AActor *source, int flags); void AlterWeaponSprite(visstyle_t *vis); - // Returns true if this actor is within melee range of its target - bool CheckMeleeRange(); - bool CheckNoDelay(); virtual void BeginPlay(); // Called immediately after the actor is created @@ -717,9 +870,12 @@ class AActor : public DThinker bool CallSlam(AActor *victim); // Something just touched this actor. - virtual void Touch(AActor *toucher); void CallTouch(AActor *toucher); + // Apply gravity and/or make actor sink in water. + virtual void FallAndSink(double grav, double oldfloorz); + void CallFallAndSink(double grav, double oldfloorz); + // Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed // Made a metadata property so no longer virtual void Howl (); @@ -727,6 +883,9 @@ class AActor : public DThinker // plays bouncing sound void PlayBounceSound(bool onfloor); + // plays pushing sound + void PlayPushSound(); + // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor bool FloorBounceMissile (secplane_t &plane); @@ -744,6 +903,11 @@ class AActor : public DThinker // (virtual on the script side only) int SpecialMissileHit (AActor *victim); + // Called when bouncing to allow for custom behavior. + // Returns -1 for normal behavior, 0 to stop, and 1 to keep going. + // (virtual on the script side only) + int SpecialBounceHit(AActor* bounceMobj, line_t* bounceLine, secplane_t* bouncePlane); + // Returns true if it's okay to switch target to "other" after being attacked by it. bool CallOkayToSwitchTarget(AActor *other); bool OkayToSwitchTarget (AActor *other); @@ -754,11 +918,11 @@ class AActor : public DThinker // Tosses an item out of the inventory. AActor *DropInventory (AActor *item, int amt = -1); - // Removes all items from the inventory. - void ClearInventory(); - // Returns true if this view is considered "local" for the player. bool CheckLocalView() const; + // Allows for enabling/disabling client-side rendering in a way the playsim can't access. + void DisableLocalRendering(const unsigned int pNum, const bool disable); + bool ShouldRenderLocally() const; // Finds the first item of a particular type. AActor *FindInventory (PClassActor *type, bool subclass=false); @@ -771,9 +935,6 @@ class AActor : public DThinker // Adds one item of a particular type. Returns NULL if it could not be added. AActor *GiveInventoryType (PClassActor *type); - // Destroys all the inventory the actor is holding. - void DestroyAllInventory (); - // Set the alphacolor field properly void SetShade (uint32_t rgb); void SetShade (int r, int g, int b); @@ -791,7 +952,6 @@ class AActor : public DThinker bool Massacre (); // Transforms the actor into a finely-ground paste - bool Grind(bool items); bool CallGrind(bool items); // Get this actor's team @@ -840,22 +1000,30 @@ class AActor : public DThinker } // These also set CF_INTERPVIEW for players. - void SetPitch(DAngle p, bool interpolate, bool forceclamp = false); - void SetAngle(DAngle ang, bool interpolate); - void SetRoll(DAngle roll, bool interpolate); + DAngle ClampPitch(DAngle p); + void SetPitch(DAngle p, int fflags); + void SetAngle(DAngle ang, int fflags); + void SetRoll(DAngle roll, int fflags); + + // These also set CF_INTERPVIEWANGLES for players. + void SetViewPitch(DAngle p, int fflags); + void SetViewAngle(DAngle ang, int fflags); + void SetViewRoll(DAngle roll, int fflags); + + double GetFOV(double ticFrac); PClassActor *GetBloodType(int type = 0) const; double Distance2DSquared(AActor *other, bool absolute = false) { - DVector2 otherpos = absolute ? other->Pos() : other->PosRelative(this); - return (Pos().XY() - otherpos).LengthSquared(); + DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return (Pos().XY() - otherpos.XY()).LengthSquared(); } - double Distance2D(AActor *other, bool absolute = false) + double Distance2D(AActor *other, bool absolute = false) const { - DVector2 otherpos = absolute ? other->Pos() : other->PosRelative(this); - return (Pos().XY() - otherpos).Length(); + DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return (Pos().XY() - otherpos.XY()).Length(); } double Distance2D(double x, double y) const @@ -863,7 +1031,7 @@ class AActor : public DThinker return DVector2(X() - x, Y() - y).Length(); } - double Distance2D(AActor *other, double xadd, double yadd, bool absolute = false) + double Distance2D(AActor *other, double xadd, double yadd, bool absolute = false) const { DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this); return DVector2(X() - otherpos.X + xadd, Y() - otherpos.Y + yadd).Length(); @@ -885,19 +1053,19 @@ class AActor : public DThinker DAngle AngleTo(AActor *other, bool absolute = false) { - DVector2 otherpos = absolute ? other->Pos() : other->PosRelative(this); - return VecToAngle(otherpos - Pos().XY()); + DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return VecToAngle(otherpos.XY() - Pos().XY()); } DAngle AngleTo(AActor *other, double oxofs, double oyofs, bool absolute = false) const { - DVector2 otherpos = absolute ? other->Pos() : other->PosRelative(this); - return VecToAngle(otherpos - Pos() + DVector2(oxofs, oyofs)); + DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return VecToAngle(otherpos.XY() - Pos().XY() + DVector2(oxofs, oyofs)); } DVector2 Vec2To(AActor *other) const { - return other->PosRelative(this) - Pos(); + return other->PosRelative(this).XY() - Pos().XY(); } DVector3 Vec3To(AActor *other) const @@ -913,6 +1081,7 @@ class AActor : public DThinker DVector3 Vec3Angle(double length, DAngle angle, double dz, bool absolute = false); void ClearInterpolation(); + void ClearFOVInterpolation(); void Move(const DVector3 &vel) { @@ -938,6 +1107,7 @@ class AActor : public DThinker bool IsSentient() const; const char *GetTag(const char *def = NULL) const; void SetTag(const char *def); + const char *GetCharacterName() const; // Triggers SECSPAC_Exit/SECSPAC_Enter and related events if oldsec != current sector void CheckSectorTransition(sector_t *oldsec); @@ -955,7 +1125,12 @@ class AActor : public DThinker DAngle SpriteAngle; DAngle SpriteRotation; + DVector2 AutomapOffsets; // Offset the actors' sprite view on the automap by these coordinates. + float isoscaleY; // Y-scale to compensate for Y-billboarding for isometric sprites + float isotheta; // Rotation angle to compensate for Y-billboarding for isometric sprites DRotator Angles; + DRotator ViewAngles; // Angle offsets for cameras + TObjPtr ViewPos; // Position offsets for cameras DVector2 Scale; // Scaling values; 1 is normal size double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double. @@ -966,12 +1141,14 @@ class AActor : public DThinker FRenderStyle RenderStyle; // Style to draw this actor with FTextureID picnum; // Draw this instead of sprite if valid uint32_t fillcolor; // Color to draw when STYLE_Shaded - uint32_t Translation; + FTranslationID Translation; uint32_t RenderRequired; // current renderer must have this feature set uint32_t RenderHidden; // current renderer must *not* have any of these features + bool NoLocalRender; // DO NOT EXPORT THIS! This is a way to disable rendering such that the playsim cannot access it. ActorRenderFlags renderflags; // Different rendering flags + ActorRenderFlags2 renderflags2; // More rendering flags... ActorFlags flags; ActorFlags2 flags2; // Heretic flags ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable @@ -980,18 +1157,23 @@ class AActor : public DThinker ActorFlags6 flags6; // Shit! Where did all the flags go? ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? ActorFlags8 flags8; // I see your 8, and raise you a bet for 9. + ActorFlags9 flags9; // Happy ninth actor flag field GZDoom ! double Floorclip; // value to use for floor clipping double radius, Height; // for movement checking - DAngle VisibleStartAngle; - DAngle VisibleStartPitch; - DAngle VisibleEndAngle; - DAngle VisibleEndPitch; + FAngle VisibleStartAngle; + FAngle VisibleStartPitch; + FAngle VisibleEndAngle; + FAngle VisibleEndPitch; DVector3 OldRenderPos; DVector3 Vel; + DVector2 SpriteOffset; + DVector3 WorldOffset; double Speed; double FloatSpeed; + TObjPtr modelData; + TObjPtr boneComponentData; // interaction info FBlockNode *BlockNode; // links in blocks (if needed) @@ -1001,11 +1183,13 @@ class AActor : public DThinker double floorz, ceilingz; // closest together of contacted secs double dropoffz; // killough 11/98: the lowest floor over all contacted Sectors. - struct sector_t *floorsector; + uint32_t ThruBits; FTextureID floorpic; // contacted sec floorpic int floorterrain; - struct sector_t *ceilingsector; FTextureID ceilingpic; // contacted sec ceilingpic + + struct sector_t *floorsector; + struct sector_t *ceilingsector; double renderradius; double projectilepassheight; // height for clipping projectile movement against this actor @@ -1021,40 +1205,44 @@ class AActor : public DThinker FState *state; //VMFunction *Damage; // For missiles and monster railgun int DamageVal; - VMFunction *DamageFunc; int projectileKickback; + VMFunction *DamageFunc; // [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it. - uint32_t VisibleToTeam; int special1; // Special info int special2; // Special info double specialf1; // With floats we cannot use the int versions for storing position or angle data without reverting to fixed point (which we do not want.) double specialf2; + uint32_t VisibleToTeam; int weaponspecial; // Special info for weapons. int health; + int32_t reactiontime; // if non 0, don't attack yet; used by + // player to freeze a bit after teleporting + int32_t threshold; // if > 0, the target will be chased + int32_t DefThreshold; // [MC] Default threshold which the actor will reset its threshold to after switching targets + uint8_t movedir; // 0-7 int8_t visdir; int16_t movecount; // when 0, select a new dir + int16_t strafecount; // for MF3_AVOIDMELEE + int16_t LightLevel; // Allows for overriding sector light levels. + uint16_t SpawnAngle; + TObjPtr target; // thing being chased/attacked (or NULL) // also the originator for missiles TObjPtr lastenemy; // Last known enemy -- killough 2/15/98 TObjPtr LastHeard; // [RH] Last actor this one heard - int32_t reactiontime; // if non 0, don't attack yet; used by - // player to freeze a bit after teleporting - int32_t threshold; // if > 0, the target will be chased - int32_t DefThreshold; // [MC] Default threshold which the actor will reset its threshold to after switching targets // no matter what (even if shot) player_t *player; // only valid if type of PlayerPawn TObjPtr LastLookActor; // Actor last looked for (if TIDtoHate != 0) DVector3 SpawnPoint; // For nightmare respawn - uint16_t SpawnAngle; int StartHealth; uint8_t WeaveIndexXY; // Separated from special2 because it's used by globally accessible functions. uint8_t WeaveIndexZ; - int skillrespawncount; + uint16_t skillrespawncount; int TIDtoHate; // TID of things to hate (0 if none) FName Species; // For monster families TObjPtr alternative; // (Un)Morphed actors stored here. Those with the MF_UNMORPHED flag are the originals. @@ -1070,6 +1258,7 @@ class AActor : public DThinker AActor *inext, **iprev;// Links to other mobjs in same bucket TObjPtr goal; // Monster's goal if not chasing anything int waterlevel; // 0=none, 1=feet, 2=waist, 3=eyes + double waterdepth; // Stores how deep into water you are, in map units uint8_t boomwaterlevel; // splash information for non-swimmable water sectors uint8_t MinMissileChance;// [RH] If a random # is > than this, then missile attack. int8_t LastLookPlayerNumber;// Player number last looked for (if TIDtoHate == 0) @@ -1082,11 +1271,13 @@ class AActor : public DThinker double maxtargetrange; // any target farther away cannot be attacked double bouncefactor; // Strife's grenades use 50%, Hexen's Flechettes 70. double wallbouncefactor; // The bounce factor for walls can be different. - int bouncecount; // Strife's grenades only bounce twice before exploding double Gravity; // [GRB] Gravity factor double Friction; - int FastChaseStrafeCount; double pushfactor; + double ShadowAimFactor; // [inkoalawetrust] How much the actors' aim is affected when attacking shadow actors. + double ShadowPenaltyFactor;// [inkoalawetrust] How much the shadow actor affects its' shooters' aim. + int bouncecount; // Strife's grenades only bounce twice before exploding + int FastChaseStrafeCount; int lastpush; int activationtype; // How the thing behaves when activated with USESPECIAL or BUMPSPECIAL int lastbump; // Last time the actor was bumped, used to control BUMPSPECIAL @@ -1097,10 +1288,13 @@ class AActor : public DThinker AActor *BlockingMobj; // Actor that blocked the last move line_t *BlockingLine; // Line that blocked the last move + line_t *MovementBlockingLine; // Line that stopped the Actor's movement in P_XYMovement sector_t *Blocking3DFloor; // 3D floor that blocked the last move (if any) sector_t *BlockingCeiling; // Sector that blocked the last move (ceiling plane slope) sector_t *BlockingFloor; // Sector that blocked the last move (floor plane slope) + uint32_t freezetics; // actor has actions completely frozen (including movement) for this many tics, but they still get Tick() calls + int PoisonDamage; // Damage received per tic from poison. FName PoisonDamageType; // Damage type dealt by poison. int PoisonDuration; // Duration left for receiving poison damage. @@ -1125,24 +1319,25 @@ class AActor : public DThinker uint8_t smokecounter; uint8_t FloatBobPhase; - double FloatBobStrength; uint8_t FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) + double FloatBobStrength; PalEntry BloodColor; - uint32_t BloodTranslation; + FTranslationID BloodTranslation; // [RH] Stuff that used to be part of an Actor Info - FSoundIDNoInit SeeSound; - FSoundIDNoInit AttackSound; - FSoundIDNoInit PainSound; - FSoundIDNoInit DeathSound; - FSoundIDNoInit ActiveSound; - FSoundIDNoInit UseSound; // [RH] Sound to play when an actor is used. - FSoundIDNoInit BounceSound; - FSoundIDNoInit WallBounceSound; - FSoundIDNoInit CrushPainSound; + FSoundID SeeSound; + FSoundID AttackSound; + FSoundID PainSound; + FSoundID DeathSound; + FSoundID ActiveSound; + FSoundID UseSound; // [RH] Sound to play when an actor is used. + FSoundID BounceSound; + FSoundID WallBounceSound; + FSoundID CrushPainSound; double MaxDropOffHeight; double MaxStepHeight; + double MaxSlopeSteepness; int32_t Mass; int16_t PainChance; @@ -1160,14 +1355,14 @@ class AActor : public DThinker int RipLevelMin; int RipLevelMax; + int ConversationRoot; // THe root of the current dialogue + FStrifeDialogueNode* Conversation; // [RH] The dialogue to show when this actor is "used." + FState *SpawnState; FState *SeeState; FState *MeleeState; FState *MissileState; - - int ConversationRoot; // THe root of the current dialogue - FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." // [RH] Decal(s) this weapon/projectile generates on impact. FDecalBase *DecalGenerator; @@ -1175,14 +1370,23 @@ class AActor : public DThinker // [RH] Used to interpolate the view to get >35 FPS DVector3 Prev; DRotator PrevAngles; - int PrevPortalGroup; + DAngle PrevFOV; TArray AttachedLights; TDeletingArray UserLights; + int PrevPortalGroup; // When was this actor spawned? int SpawnTime; uint32_t SpawnOrder; + int UnmorphTime; + int MorphFlags; + int PremorphProperties; + PClassActor* MorphExitFlash; + // landing speed from a jump with normal gravity (squats the player's view) + // (note: this is put into AActor instead of the PlayerPawn because non-players also use the value) + double LandingSpeed; + // ThingIDs void SetTID (int newTID); @@ -1205,10 +1409,10 @@ class AActor : public DThinker void UnlinkFromWorld(FLinkContext *ctx); void AdjustFloorClip (); bool IsMapActor(); - int GetTics(FState * newstate); bool SetState (FState *newstate, bool nofunction=false); - virtual void SplashCheck(); - virtual bool UpdateWaterLevel (bool splash=true); + void SplashCheck(); + void PlayDiveOrSurfaceSounds(int oldlevel = 0); + bool UpdateWaterLevel (bool splash=true); bool isFast(); bool isSlow(); void SetIdle(bool nofunction=false); @@ -1278,7 +1482,7 @@ class AActor : public DThinker double RenderRadius() const { - return MAX(radius, renderradius); + return max(radius, renderradius); } DVector3 PosRelative(int grp) const; @@ -1305,6 +1509,11 @@ class AActor : public DThinker result.Roll = PrevAngles.Roll + deltaangle(PrevAngles.Roll, Angles.Roll) * ticFrac; return result; } + float GetSpriteOffset(bool y) const + { + if (y) return (float)(renderflags2 & RF2_FLIPSPRITEOFFSETY ? SpriteOffset.Y : -SpriteOffset.Y); + else return (float)(renderflags2 & RF2_FLIPSPRITEOFFSETX ? SpriteOffset.X : -SpriteOffset.X); + } DAngle GetSpriteAngle(DAngle viewangle, double ticFrac) { if (flags7 & MF7_SPRITEANGLE) @@ -1428,17 +1637,19 @@ class AActor : public DThinker // This is used by many vertical velocity calculations. // Better have it in one place, if something needs to be changed about the formula. - double DistanceBySpeed(AActor *dest, double speed) + double DistanceBySpeed(AActor *dest, double speed) const { - return MAX(1., Distance2D(dest) / speed); + return max(1., Distance2D(dest) / speed); } + int GetLightLevel(sector_t* rendersector); int ApplyDamageFactor(FName damagetype, int damage) const; int GetModifiedDamage(FName damagetype, int damage, bool passive, AActor *inflictor, AActor *source, int flags = 0); void DeleteAttachedLights(); - bool isFrozen(); + bool isFrozen() const; bool hasmodel; + }; class FActorIterator @@ -1552,6 +1763,8 @@ struct FTranslatedLineTarget bool unlinked; // found by a trace that went through an unlinked portal. }; +void PlayerPointerSubstitution(AActor* oldPlayer, AActor* newPlayer, bool removeOld); +int MorphPointerSubstitution(AActor* from, AActor* to); #define S_FREETARGMOBJ 1 diff --git a/src/playsim/actorinlines.h b/src/playsim/actorinlines.h index 3e4f7684bbf..939807c98d7 100644 --- a/src/playsim/actorinlines.h +++ b/src/playsim/actorinlines.h @@ -34,6 +34,14 @@ inline void AActor::ClearInterpolation() else PrevPortalGroup = 0; } +inline void AActor::ClearFOVInterpolation() +{ + if (player) + PrevFOV = DAngle::fromDeg(player->FOV); + else + PrevFOV = DAngle::fromDeg(CameraFOV); +} + inline double secplane_t::ZatPoint(const AActor *ac) const { return (D + normal.X*ac->X() + normal.Y*ac->Y()) * negiC; @@ -49,6 +57,12 @@ inline double sector_t::LowestFloorAt(AActor *a, sector_t **resultsec) return ::LowestFloorAt(this, a->X(), a->Y(), resultsec); } +// Emulates the old floatbob offset table with direct calls to trig functions. +inline double BobSin(double fb) +{ + return g_sindeg(double(fb * (180.0 / 32))) * 8; +} + inline double AActor::GetBobOffset(double ticfrac) const { if (!(flags2 & MF2_FLOATBOB)) @@ -157,8 +171,10 @@ inline DVector3 AActor::Vec3Angle(double length, DAngle angle, double dz, bool a } } -inline bool AActor::isFrozen() +inline bool AActor::isFrozen() const { + if (freezetics > 0) + return true; if (!(flags5 & MF5_NOTIMEFREEZE)) { auto state = Level->isFrozen(); @@ -178,3 +194,84 @@ inline bool AActor::isFrozen() return false; } +inline int AActor::GetLightLevel(sector_t* rendersector) +{ + int lightlevel = rendersector->GetSpriteLight(); + + if (flags8 & MF8_ADDLIGHTLEVEL) + { + lightlevel += LightLevel; + } + else if (LightLevel > -1) + { + lightlevel = LightLevel; + } + return lightlevel; +} + + +// Consolidated from all (incomplete) variants that check if a line should block. +inline bool P_IsBlockedByLine(AActor* actor, line_t* line) +{ + // Keep this stuff readable - so no chained and nested 'if's! + + // Unconditional blockers. + if (line->flags & (ML_BLOCKING | ML_BLOCKEVERYTHING)) return true; + + // MBF considers that friendly monsters are not blocked by monster-blocking lines. + // This is added here as a compatibility option. Note that monsters that are dehacked + // into being friendly with the MBF flag automatically gain MF3_NOBLOCKMONST, so this + // just optionally generalizes the behavior to other friendly monsters. + + if (!((actor->flags3 & MF3_NOBLOCKMONST) + || ((actor->Level->i_compatflags & COMPATF_NOBLOCKFRIENDS) && (actor->flags & MF_FRIENDLY)))) + { + // the regular 'blockmonsters' flag. + if (line->flags & ML_BLOCKMONSTERS) return true; + // MBF21's flag for walking monsters + if ((line->flags2 & ML2_BLOCKLANDMONSTERS) && actor->Level->MBF21Enabled() && !(actor->flags & MF_FLOAT)) return true; + } + + // Blocking players + if ((((actor->player != nullptr) || (actor->flags8 & MF8_BLOCKASPLAYER)) && (line->flags & ML_BLOCK_PLAYERS)) && actor->Level->MBF21Enabled()) return true; + + // Blocking floaters. + if ((actor->flags & MF_FLOAT) && (line->flags & ML_BLOCK_FLOATERS)) return true; + + return false; +} + +// For Dehacked modified actors we need to dynamically check the bounce factors because MBF didn't bother to implement this properly and with other flags changing this must adjust. +inline double GetMBFBounceFactor(AActor* actor) +{ + if (actor->BounceFlags & BOUNCE_DEH) // only when modified through Dehacked. + { + constexpr double MBF_BOUNCE_NOGRAVITY = 1; // With NOGRAVITY: full momentum + constexpr double MBF_BOUNCE_FLOATDROPOFF = 0.85; // With FLOAT and DROPOFF: 85% + constexpr double MBF_BOUNCE_FLOAT = 0.7; // With FLOAT alone: 70% + constexpr double MBF_BOUNCE_DEFAULT = 0.45; // Without the above flags: 45% + + if (actor->flags & MF_NOGRAVITY) return MBF_BOUNCE_NOGRAVITY; + if (actor->flags & MF_FLOAT) return (actor->flags & MF_DROPOFF) ? MBF_BOUNCE_FLOATDROPOFF : MBF_BOUNCE_FLOAT; + return MBF_BOUNCE_DEFAULT; + } + return actor->bouncefactor; +} + +inline double GetWallBounceFactor(AActor* actor) +{ + if (actor->BounceFlags & BOUNCE_DEH) // only when modified through Dehacked. + { + constexpr double MBF_BOUNCE_NOGRAVITY = 1; // With NOGRAVITY: full momentum + constexpr double MBF_BOUNCE_WALL = 0.5; // Bouncing off walls: 50% + return ((actor->flags & MF_NOGRAVITY) ? MBF_BOUNCE_NOGRAVITY : MBF_BOUNCE_WALL); + } + return actor->wallbouncefactor; +} + +// Yet another hack for MBF... +inline bool CanJump(AActor* actor) +{ + return (actor->flags6 & MF6_CANJUMP) || ( + (actor->BounceFlags & BOUNCE_MBF) && actor->IsSentient() && (actor->flags & MF_FLOAT)); +} \ No newline at end of file diff --git a/src/playsim/bots/b_bot.cpp b/src/playsim/bots/b_bot.cpp index bb15fc8bc47..56a12b75eb5 100644 --- a/src/playsim/bots/b_bot.cpp +++ b/src/playsim/bots/b_bot.cpp @@ -45,11 +45,13 @@ #include "cmdlib.h" #include "teaminfo.h" #include "d_net.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "d_player.h" -#include "w_wad.h" +#include "filesystem.h" #include "vm.h" #include "g_levellocals.h" +#include "d_main.h" IMPLEMENT_CLASS(DBot, false, true) @@ -72,7 +74,7 @@ void DBot::Construct() void DBot::Clear () { player = nullptr; - Angle = 0.; + Angle = nullAngle; dest = nullptr; prev = nullptr; enemy = nullptr; @@ -154,7 +156,7 @@ CVAR (Int, bot_next_color, 11, 0) CCMD (addbot) { - if (gamestate != GS_LEVEL && gamestate != GS_INTERMISSION) + if (gamestate != GS_LEVEL) { Printf ("Bots cannot be added when not in a game!\n"); return; @@ -186,7 +188,7 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam) players[i].mo = nullptr; } botinfo_t *bot = botinfo; - while (bot && stricmp (players[i].userinfo.GetName(), bot->name)) + while (bot && stricmp (players[i].userinfo.GetName(), bot->Name.GetChars())) bot = bot->next; if (bot) { @@ -200,7 +202,7 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam) } players[i].~player_t(); ::new(&players[i]) player_t; - players[i].userinfo.Reset(); + players[i].userinfo.Reset(i); playeringame[i] = false; } @@ -212,7 +214,7 @@ CCMD (removebots) return; } - Net_WriteByte (DEM_KILLBOTS); + Net_WriteInt8 (DEM_KILLBOTS); } CCMD (freeze) @@ -226,8 +228,8 @@ CCMD (freeze) return; } - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_FREEZE); + Net_WriteInt8(DEM_GENERICCHEAT); + Net_WriteInt8(CHT_FREEZE); } CCMD (listbots) @@ -237,7 +239,7 @@ CCMD (listbots) while (thebot) { - Printf ("%s%s\n", thebot->name, thebot->inuse == BOTINUSE_Yes ? " (active)" : ""); + Printf ("%s%s\n", thebot->Name.GetChars(), thebot->inuse == BOTINUSE_Yes ? " (active)" : ""); thebot = thebot->next; count++; } @@ -253,7 +255,7 @@ void InitBotStuff() { int lump; int lastlump = 0; - while (-1 != (lump = Wads.FindLump("BOTSUPP", &lastlump))) + while (-1 != (lump = fileSystem.FindLump("BOTSUPP", &lastlump))) { FScanner sc(lump); sc.SetCMode(true); diff --git a/src/playsim/bots/b_bot.h b/src/playsim/bots/b_bot.h index a4f632eae9d..2f214bbd9f9 100644 --- a/src/playsim/bots/b_bot.h +++ b/src/playsim/bots/b_bot.h @@ -71,12 +71,12 @@ enum //Info given to bots when they're spawned. struct botinfo_t { - botinfo_t *next; - char *name; - char *info; - botskill_t skill; - int inuse; - int lastteam; + botinfo_t *next = nullptr; + FString Name; + FString Info; + botskill_t skill = {}; + int inuse = 0; + int lastteam = 0; }; struct BotInfoData diff --git a/src/playsim/bots/b_func.cpp b/src/playsim/bots/b_func.cpp index f9925f53431..e537bf9f7e5 100644 --- a/src/playsim/bots/b_func.cpp +++ b/src/playsim/bots/b_func.cpp @@ -151,9 +151,9 @@ bool DBot::Check_LOS (AActor *to, DAngle vangle) { if (!P_CheckSight (player->mo, to, SF_SEEPASTBLOCKEVERYTHING)) return false; // out of sight - if (vangle >= 360.) + if (vangle >= DAngle::fromDeg(360.)) return true; - if (vangle == 0) + if (vangle == nullAngle) return false; //Looker seems to be blind. return absangle(player->mo->AngleTo(to), player->mo->Angles.Yaw) <= (vangle/2); @@ -180,7 +180,7 @@ void DBot::Dofire (ticcmd_t *cmd) if (player->ReadyWeapon == NULL) return; - if (player->damagecount > skill.isp) + if (player->damagecount > (unsigned)skill.isp) { first_shot = true; return; @@ -212,7 +212,7 @@ void DBot::Dofire (ticcmd_t *cmd) { //MAKEME: This should be smarter. if ((pr_botdofire()%200)<=skill.reaction) - if(Check_LOS(enemy, SHOOTFOV)) + if(Check_LOS(enemy, DAngle::fromDeg(SHOOTFOV))) no_fire = false; } else if (GetBotInfo(player->ReadyWeapon).projectileType != NULL) @@ -221,11 +221,11 @@ void DBot::Dofire (ticcmd_t *cmd) { //Special rules for RL an = FireRox (enemy, cmd); - if(an != 0) + if(an != nullAngle) { Angle = an; //have to be somewhat precise. to avoid suicide. - if (absangle(an, player->mo->Angles.Yaw) < 12.) + if (absangle(an, player->mo->Angles.Yaw) < DAngle::fromDeg(12.)) { t_rocket = 9; no_fire = false; @@ -237,7 +237,7 @@ void DBot::Dofire (ticcmd_t *cmd) fm = Dist / GetDefaultByType (GetBotInfo(player->ReadyWeapon).projectileType)->Speed; Level->BotInfo.SetBodyAt(Level, enemy->Pos() + enemy->Vel.XY() * fm * 2, 1); Angle = player->mo->AngleTo(Level->BotInfo.body1); - if (Check_LOS (enemy, SHOOTFOV)) + if (Check_LOS (enemy, DAngle::fromDeg(SHOOTFOV))) no_fire = false; } else @@ -254,11 +254,11 @@ void DBot::Dofire (ticcmd_t *cmd) aiming_value = skill.aiming - aiming_penalty; if (aiming_value <= 0) aiming_value = 1; - m = ((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200)); //Higher skill is more accurate - if (m <= 0) - m = 1.; //Prevents lock. + m = DAngle::fromDeg(((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200))); //Higher skill is more accurate + if (m <= nullAngle) + m = DAngle::fromDeg(1.); //Prevents lock. - if (m != 0) + if (m != nullAngle) { if (increase) Angle += m; @@ -266,12 +266,12 @@ void DBot::Dofire (ticcmd_t *cmd) Angle -= m; } - if (absangle(Angle, player->mo->Angles.Yaw) < 4.) + if (absangle(Angle, player->mo->Angles.Yaw) < DAngle::fromDeg(4.)) { increase = !increase; } - if (Check_LOS (enemy, (SHOOTFOV/2))) + if (Check_LOS (enemy, DAngle::fromDeg(SHOOTFOV/2))) no_fire = false; } if (!no_fire) //If going to fire weapon @@ -328,7 +328,7 @@ void FCajunMaster::BotTick(AActor *mo) { if (!players[i].Bot->missile && (mo->flags3 & MF3_WARNBOT)) { //warn for incoming missiles. - if (mo->target != players[i].mo && players[i].Bot->Check_LOS(mo, 90.)) + if (mo->target != players[i].mo && players[i].Bot->Check_LOS(mo, DAngle::fromDeg(90.))) players[i].Bot->missile = mo; } } @@ -425,9 +425,9 @@ AActor *DBot::Find_enemy () //Note: It's hard to ambush a bot who is not alone if (allround || mate) - vangle = 360.; + vangle = DAngle::fromDeg(360.); else - vangle = ENEMY_SCAN_FOV; + vangle = DAngle::fromDeg(ENEMY_SCAN_FOV); allround = false; target = NULL; @@ -537,11 +537,11 @@ DAngle DBot::FireRox (AActor *enemy, ticcmd_t *cmd) dist = actor->Distance2D (enemy); if (dist < SAFE_SELF_MISDIST) - return 0.; + return nullAngle; //Predict. m = ((dist+1) / GetDefaultByName("Rocket")->Speed); - Level->BotInfo.SetBodyAt(Level, DVector3((enemy->Pos() + enemy->Vel * (m + 2)), ONFLOORZ), 1); + Level->BotInfo.SetBodyAt(Level, DVector3((enemy->Pos().XY() + enemy->Vel * (m + 2)), ONFLOORZ), 1); //try the predicted location if (P_CheckSight (actor, Level->BotInfo.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile @@ -563,7 +563,7 @@ DAngle DBot::FireRox (AActor *enemy, ticcmd_t *cmd) return player->mo->AngleTo(enemy); } } - return 0.; + return nullAngle; } // [RH] We absolutely do not want to pick things up here. The bot code is diff --git a/src/playsim/bots/b_game.cpp b/src/playsim/bots/b_game.cpp index ad24d7bbd98..3863ac923b2 100644 --- a/src/playsim/bots/b_game.cpp +++ b/src/playsim/bots/b_game.cpp @@ -94,6 +94,10 @@ Everything that is changed is marked (maybe commented) with "Added by MC" #include "vm.h" #include "g_levellocals.h" +#if !defined _WIN32 && !defined __APPLE__ +#include "i_system.h" // for SHARE_DIR +#endif // !_WIN32 && !__APPLE__ + static FRandom pr_botspawn ("BotSpawn"); cycle_t BotThinkCycles, BotSupportCycles; @@ -138,7 +142,7 @@ void FCajunMaster::Main(FLevelLocals *Level) { if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY)) { - if (!SpawnBot (getspawned[spawn_tries])) + if (!SpawnBot (getspawned[spawn_tries].GetChars())) wanted_botnum--; spawn_tries++; } @@ -237,7 +241,7 @@ bool FCajunMaster::SpawnBot (const char *name, int color) if (name) { // Check if exist or already in the game. - while (thebot && stricmp (name, thebot->name)) + while (thebot && thebot->Name.CompareNoCase(name)) { botshift++; thebot = thebot->next; @@ -292,40 +296,38 @@ bool FCajunMaster::SpawnBot (const char *name, int color) thebot->inuse = BOTINUSE_Waiting; - Net_WriteByte (DEM_ADDBOT); - Net_WriteByte (botshift); + Net_WriteInt8 (DEM_ADDBOT); + Net_WriteInt8 (botshift); { //Set color. - char concat[512]; - strcpy (concat, thebot->info); + FString concat = thebot->Info; if (color == NOCOLOR && bot_next_color < NOCOLOR && bot_next_color >= 0) { - strcat (concat, colors[bot_next_color]); + concat << colors[bot_next_color]; } - if (TeamLibrary.IsValidTeam (thebot->lastteam)) + if (FTeam::IsValid (thebot->lastteam)) { // Keep the bot on the same team when switching levels - mysnprintf (concat + strlen(concat), countof(concat) - strlen(concat), - "\\team\\%d\n", thebot->lastteam); + concat.AppendFormat("\\team\\%d\n", thebot->lastteam); } - Net_WriteString (concat); + Net_WriteString (concat.GetChars()); } - Net_WriteByte(thebot->skill.aiming); - Net_WriteByte(thebot->skill.perfection); - Net_WriteByte(thebot->skill.reaction); - Net_WriteByte(thebot->skill.isp); + Net_WriteInt8(thebot->skill.aiming); + Net_WriteInt8(thebot->skill.perfection); + Net_WriteInt8(thebot->skill.reaction); + Net_WriteInt8(thebot->skill.isp); return true; } void FCajunMaster::TryAddBot (FLevelLocals *Level, uint8_t **stream, int player) { - int botshift = ReadByte (stream); + int botshift = ReadInt8 (stream); char *info = ReadString (stream); botskill_t skill; - skill.aiming = ReadByte (stream); - skill.perfection = ReadByte (stream); - skill.reaction = ReadByte (stream); - skill.isp = ReadByte (stream); + skill.aiming = ReadInt8 (stream); + skill.perfection = ReadInt8 (stream); + skill.reaction = ReadInt8 (stream); + skill.isp = ReadInt8 (stream); botinfo_t *thebot = NULL; @@ -453,26 +455,9 @@ void FCajunMaster::RemoveAllBots (FLevelLocals *Level, bool fromlist) // ??? any other valid userinfo strings can go here //} -static void appendinfo (char *&front, const char *back) +static void appendinfo (FString &front, const char *back) { - char *newstr; - - if (front) - { - size_t newlen = strlen (front) + strlen (back) + 2; - newstr = new char[newlen]; - strcpy (newstr, front); - delete[] front; - } - else - { - size_t newlen = strlen (back) + 2; - newstr = new char[newlen]; - newstr[0] = 0; - } - strcat (newstr, "\\"); - strcat (newstr, back); - front = newstr; + front << "\\" << back; } void FCajunMaster::ForgetBots () @@ -482,8 +467,6 @@ void FCajunMaster::ForgetBots () while (thebot) { botinfo_t *next = thebot->next; - delete[] thebot->name; - delete[] thebot->info; delete thebot; thebot = next; } @@ -491,6 +474,43 @@ void FCajunMaster::ForgetBots () botinfo = NULL; } +#if defined _WIN32 || defined __APPLE__ + +FString M_GetCajunPath(const char* botfilename) +{ + FString path; + + path << progdir << "zcajun/" << botfilename; + if (!FileExists(path)) + { + path = ""; + } + return path; +} + +#else + +FString M_GetCajunPath(const char* botfilename) +{ + FString path; + + // Check first in $HOME/.config/zdoom/botfilename. + path = GetUserFile(botfilename); + if (!FileExists(path)) + { + // Then check in SHARE_DIR/botfilename. + path = SHARE_DIR; + path << botfilename; + if (!FileExists(path)) + { + path = ""; + } + } + return path; +} + +#endif + bool FCajunMaster::LoadBots () { FScanner sc; @@ -505,7 +525,7 @@ bool FCajunMaster::LoadBots () DPrintf (DMSG_ERROR, "No " BOTFILENAME ", so no bots\n"); return false; } - if (!sc.OpenFile(tmp)) + if (!sc.OpenFile(tmp.GetChars())) { Printf("Unable to open %s. So no bots\n", tmp.GetChars()); return false; @@ -521,9 +541,7 @@ bool FCajunMaster::LoadBots () botinfo_t *newinfo = new botinfo_t; bool gotclass = false; - memset (newinfo, 0, sizeof(*newinfo)); - - newinfo->info = copystring ("\\autoaim\\0\\movebob\\.25"); + newinfo->Info = "\\autoaim\\0\\movebob\\.25"; for (;;) { @@ -535,9 +553,9 @@ bool FCajunMaster::LoadBots () { case BOTCFG_NAME: sc.MustGetString (); - appendinfo (newinfo->info, "name"); - appendinfo (newinfo->info, sc.String); - newinfo->name = copystring (sc.String); + appendinfo (newinfo->Info, "name"); + appendinfo (newinfo->Info, sc.String); + newinfo->Name = sc.String; break; case BOTCFG_AIMING: @@ -569,7 +587,7 @@ bool FCajunMaster::LoadBots () if (IsNum (sc.String)) { teamnum = atoi (sc.String); - if (!TeamLibrary.IsValidTeam (teamnum)) + if (!FTeam::IsValid (teamnum)) { teamnum = TEAM_NONE; } @@ -586,9 +604,9 @@ bool FCajunMaster::LoadBots () } } } - appendinfo (newinfo->info, "team"); + appendinfo (newinfo->Info, "team"); mysnprintf (teamstr, countof(teamstr), "%d", teamnum); - appendinfo (newinfo->info, teamstr); + appendinfo (newinfo->Info, teamstr); gotteam = true; break; } @@ -598,21 +616,21 @@ bool FCajunMaster::LoadBots () { gotclass = true; } - appendinfo (newinfo->info, sc.String); + appendinfo (newinfo->Info, sc.String); sc.MustGetString (); - appendinfo (newinfo->info, sc.String); + appendinfo (newinfo->Info, sc.String); break; } } if (!gotclass) { // Bots that don't specify a class get a random one - appendinfo (newinfo->info, "playerclass"); - appendinfo (newinfo->info, "random"); + appendinfo (newinfo->Info, "playerclass"); + appendinfo (newinfo->Info, "random"); } if (!gotteam) { // Same for bot teams - appendinfo (newinfo->info, "team"); - appendinfo (newinfo->info, "255"); + appendinfo (newinfo->Info, "team"); + appendinfo (newinfo->Info, "255"); } newinfo->next = botinfo; newinfo->lastteam = TEAM_NONE; diff --git a/src/playsim/bots/b_move.cpp b/src/playsim/bots/b_move.cpp index a22867af146..4d91839d8e2 100644 --- a/src/playsim/bots/b_move.cpp +++ b/src/playsim/bots/b_move.cpp @@ -77,9 +77,9 @@ void DBot::Roam (ticcmd_t *cmd) int delta = angle - (player->mo->movedir << 29); if (delta > 0) - Angle -= 45; + Angle -= DAngle::fromDeg(45); else if (delta < 0) - Angle += 45; + Angle += DAngle::fromDeg(45); } // chase towards destination. @@ -357,18 +357,18 @@ void DBot::TurnToAng () if(enemy) if(!dest) //happens when running after item in combat situations, or normal, prevents weak turns if(GetBotInfo(player->ReadyWeapon).projectileType == NULL && GetBotInfo(player->ReadyWeapon).MoveCombatDist > 0) - if(Check_LOS(enemy, SHOOTFOV+5)) + if(Check_LOS(enemy, DAngle::fromDeg(SHOOTFOV+5))) maxturn = 3; } DAngle distance = deltaangle(player->mo->Angles.Yaw, Angle); - if (fabs (distance) < OKAYRANGE && !enemy) + if (fabs (distance) < DAngle::fromDeg(OKAYRANGE) && !enemy) return; distance /= TURNSENS; - if (fabs (distance) > maxturn) - distance = distance < 0 ? -maxturn : maxturn; + if (fabs (distance) > DAngle::fromDeg(maxturn)) + distance = DAngle::fromDeg(distance < nullAngle ? -maxturn : maxturn); player->mo->Angles.Yaw += distance; } @@ -380,7 +380,7 @@ void DBot::Pitch (AActor *target) diff = target->Z() - player->mo->Z(); aim = g_atan(diff / player->mo->Distance2D(target)); - player->mo->Angles.Pitch = DAngle::ToDegrees(aim); + player->mo->Angles.Pitch = DAngle::fromRad(aim); } //Checks if a sector is dangerous. diff --git a/src/playsim/bots/b_think.cpp b/src/playsim/bots/b_think.cpp index 4152e475d70..9fba192d58f 100644 --- a/src/playsim/bots/b_think.cpp +++ b/src/playsim/bots/b_think.cpp @@ -78,13 +78,13 @@ void DBot::Think () ThinkForMove (cmd); TurnToAng (); - cmd->ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees * (65536 / 360.f)) / ticdup; - cmd->ucmd.pitch = (short)((oldpitch - actor->Angles.Pitch).Degrees * (65536 / 360.f)); + cmd->ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees() * (65536 / 360.f)) / ticdup; + cmd->ucmd.pitch = (short)((oldpitch - actor->Angles.Pitch).Degrees() * (65536 / 360.f)); if (cmd->ucmd.pitch == -32768) cmd->ucmd.pitch = -32767; cmd->ucmd.pitch /= ticdup; - actor->Angles.Yaw = oldyaw + DAngle(cmd->ucmd.yaw * ticdup * (360 / 65536.f)); - actor->Angles.Pitch = oldpitch - DAngle(cmd->ucmd.pitch * ticdup * (360 / 65536.f)); + actor->Angles.Yaw = oldyaw + DAngle::fromDeg(cmd->ucmd.yaw * ticdup * (360 / 65536.f)); + actor->Angles.Pitch = oldpitch - DAngle::fromDeg(cmd->ucmd.pitch * ticdup * (360 / 65536.f)); } if (t_active) t_active--; @@ -118,7 +118,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) dist = dest ? player->mo->Distance2D(dest) : 0; if (missile && - (!missile->Vel.X || !missile->Vel.Y || !Check_LOS(missile, SHOOTFOV*3/2))) + (!missile->Vel.X || !missile->Vel.Y || !Check_LOS(missile, DAngle::fromDeg(SHOOTFOV*3/2)))) { sleft = !sleft; missile = nullptr; //Probably ended its travel. @@ -147,7 +147,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) } //If able to see enemy while avoiding missile, still fire at enemy. - if (enemy && Check_LOS (enemy, SHOOTFOV)) + if (enemy && Check_LOS (enemy, DAngle::fromDeg(SHOOTFOV))) Dofire (cmd); //Order bot to fire current weapon } else if (enemy && P_CheckSight (player->mo, enemy, 0)) //Fight! @@ -259,7 +259,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) ///// roam: ///// - if (enemy && Check_LOS (enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it. + if (enemy && Check_LOS (enemy, DAngle::fromDeg(SHOOTFOV*3/2))) //If able to see enemy while avoiding missile , still fire at it. Dofire (cmd); //Order bot to fire current weapon if (dest && !(dest->flags&MF_SPECIAL) && dest->health < 0) @@ -339,7 +339,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) if (t_fight<(AFTERTICS/2)) player->mo->flags |= MF_DROPOFF; - old = player->mo->Pos(); + old = player->mo->Pos().XY(); } int P_GetRealMaxHealth(AActor *actor, int max); @@ -387,8 +387,8 @@ void DBot::WhatToGet (AActor *item) else if (item->GetClass()->TypeName == NAME_Megasphere || item->IsKindOf(NAME_Health)) { // do the test with the health item that's actually given. - AActor* const testItem = NAME_Megasphere == item->GetClass()->TypeName - ? GetDefaultByName("MegasphereHealth") + AActor* const testItem = item->GetClass()->TypeName == NAME_Megasphere + ? GetDefaultByName(NAME_MegasphereHealth) : item; if (nullptr != testItem) { diff --git a/src/playsim/d_player.h b/src/playsim/d_player.h index 3bd6431aa21..a717bb42c89 100644 --- a/src/playsim/d_player.h +++ b/src/playsim/d_player.h @@ -122,6 +122,10 @@ typedef enum CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame + CF_INTERPVIEWANGLES = 1 << 15, // [MR] flag for interpolating view angles without interpolating the entire frame + CF_NOFOVINTERP = 1 << 16, // [B] Disable FOV interpolation when instantly zooming + CF_SCALEDNOLERP = 1 << 17, // [MR] flag for applying angles changes in the ticrate without interpolating the frame + CF_NOVIEWPOSINTERP = 1 << 18, // Disable view position interpolation. CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either. CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either. @@ -148,7 +152,7 @@ enum // The VM cannot deal with this as an invalid pointer because it performs a read barrier on every object pointer read. // This doesn't have to point to a valid weapon, though, because WP_NOCHANGE is never dereferenced, but it must point to a valid object // and the class descriptor just works fine for that. -extern AActor *WP_NOCHANGE; +extern DObject *WP_NOCHANGE; // [GRB] Custom player classes @@ -161,7 +165,7 @@ class FPlayerClass { public: FPlayerClass (); - FPlayerClass (const FPlayerClass &other); + FPlayerClass (const FPlayerClass &other) = default; ~FPlayerClass (); bool CheckSkin (int skin); @@ -200,9 +204,25 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_Autoaim)); } - const char *GetName() const + const char *GetName(unsigned int charLimit = 0u) const { - return *static_cast(*CheckKey(NAME_Name)); + const char* name = *static_cast(*CheckKey(NAME_Name)); + if (charLimit) + { + FString temp = name; + if (temp.CharacterCount() > charLimit) + { + int next = 0; + for (unsigned int i = 0u; i < charLimit; ++i) + temp.GetNextCharacter(next); + + temp.Truncate(next); + temp += "..."; + name = temp.GetChars(); + } + } + + return name; } int GetTeam() const { @@ -224,6 +244,10 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_MoveBob)); } + bool GetFViewBob() const + { + return *static_cast(*CheckKey(NAME_FViewBob)); + } double GetStillBob() const { return *static_cast(*CheckKey(NAME_StillBob)); @@ -232,6 +256,10 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_WBobSpeed)); } + double GetWBobFire() const + { + return *static_cast(*CheckKey(NAME_WBobFire)); + } int GetPlayerClassNum() const { return *static_cast(*CheckKey(NAME_PlayerClass)); @@ -258,7 +286,7 @@ struct userinfo_t : TMap return *static_cast(*CheckKey(NAME_Wi_NoAutostartMap)); } - void Reset(); + void Reset(int pnum); int TeamChanged(int team); int SkinChanged(const char *skinname, int playerclass); int SkinNumChanged(int skinnum); @@ -336,7 +364,7 @@ class player_t AActor *ReadyWeapon = nullptr; AActor *PendingWeapon = nullptr; // WP_NOCHANGE if not changing - TObjPtr psprites = nullptr; // view sprites (gun, etc) + TObjPtr psprites = MakeObjPtr(nullptr); // view sprites (gun, etc) int cheats = 0; // bit flags int timefreezer = 0; // Player has an active time freezer @@ -344,15 +372,15 @@ class player_t short inconsistant = 0; bool waiting = 0; int killcount = 0, itemcount = 0, secretcount = 0; // for intermission - int damagecount = 0, bonuscount = 0;// for screen flashing + uint32_t damagecount = 0, bonuscount = 0;// for screen flashing int hazardcount = 0; // for delayed Strife damage int hazardinterval = 0; // Frequency of damage infliction FName hazardtype = NAME_None; // Damage type of last hazardous damage encounter. int poisoncount = 0; // screen flash for poison damage FName poisontype = NAME_None; // type of poison damage to apply FName poisonpaintype = NAME_None; // type of Pain state to enter for poison damage - TObjPtr poisoner = nullptr; // NULL for non-player actors - TObjPtr attacker = nullptr; // who did damage (NULL for floors) + TObjPtr poisoner = MakeObjPtr(nullptr); // NULL for non-player actors + TObjPtr attacker = MakeObjPtr(nullptr); // who did damage (NULL for floors) int extralight = 0; // so gun flashes light up areas short fixedcolormap = 0; // can be set to REDCOLORMAP, etc. short fixedlightlevel = 0; @@ -360,19 +388,20 @@ class player_t PClassActor *MorphedPlayerClass = nullptr; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle = 0; // which effects to apply for this player instance when morphed PClassActor *MorphExitFlash = nullptr; // flash to apply when demorphing (cache of value given to MorphPlayer) - TObjPtr PremorphWeapon = nullptr; // ready weapon before morphing + TObjPtr PremorphWeapon = MakeObjPtr(nullptr); // ready weapon before morphing int chickenPeck = 0; // chicken peck countdown int jumpTics = 0; // delay the next jump for a moment bool onground = 0; // Identifies if this player is on the ground or other object + bool crossingPortal = 0; // Crossing a portal (disables sprite from showing up) int respawn_time = 0; // [RH] delay respawning until this tic - TObjPtr camera = nullptr; // [RH] Whose eyes this player sees through + TObjPtr camera = MakeObjPtr(nullptr); // [RH] Whose eyes this player sees through int air_finished = 0; // [RH] Time when you start drowning FName LastDamageType = NAME_None; // [RH] For damage-specific pain and death sounds - TObjPtr MUSINFOactor = nullptr; // For MUSINFO purposes + TObjPtr MUSINFOactor = MakeObjPtr(nullptr); // For MUSINFO purposes int8_t MUSINFOtics = 0; bool settings_controller = false; // Player can control game settings. @@ -380,19 +409,20 @@ class player_t int8_t crouchdir = 0; //Added by MC: - TObjPtr Bot = nullptr; + TObjPtr Bot = MakeObjPtr(nullptr); float BlendR = 0; // [RH] Final blending values float BlendG = 0; float BlendB = 0; float BlendA = 0; + FString SoundClass; FString LogText; // [RH] Log for Strife FString SubtitleText; int SubtitleCounter; - DAngle MinPitch = 0.; // Viewpitch limits (negative is up, positive is down) - DAngle MaxPitch = 0.; + DAngle MinPitch = nullAngle; // Viewpitch limits (negative is up, positive is down) + DAngle MaxPitch = nullAngle; double crouchfactor = 0; double crouchoffset = 0; @@ -401,8 +431,8 @@ class player_t FWeaponSlots weapons; // [CW] I moved these here for multiplayer conversation support. - TObjPtr ConversationNPC = nullptr, ConversationPC = nullptr; - DAngle ConversationNPCAngle = 0.; + TObjPtr ConversationNPC = MakeObjPtr(nullptr), ConversationPC = MakeObjPtr(nullptr); + DAngle ConversationNPCAngle = nullAngle; bool ConversationFaceTalker = false; double GetDeltaViewHeight() const @@ -415,7 +445,6 @@ class player_t return mo->FloatVar(NAME_ViewHeight); } - void Uncrouch() { if (crouchfactor != 1) @@ -444,6 +473,9 @@ class player_t void SetFOV(float fov); bool HasWeaponsInSlot(int slot) const; bool Resurrect(); + + // Scaled angle adjustment info. Not for direct manipulation. + DRotator angleOffsetTargets; }; // Bookkeeping on players - state. @@ -476,4 +508,6 @@ inline bool AActor::IsNoClip2() const bool P_IsPlayerTotallyFrozen(const player_t *player); +bool P_NoInterpolation(player_t const *player, AActor const *actor); + #endif // __D_PLAYER_H__ diff --git a/src/playsim/dthinker.cpp b/src/playsim/dthinker.cpp index 16b7f666fc2..4229de792f6 100644 --- a/src/playsim/dthinker.cpp +++ b/src/playsim/dthinker.cpp @@ -35,14 +35,16 @@ #include "dthinker.h" #include "stats.h" #include "p_local.h" -#include "serializer.h" +#include "serializer_doom.h" #include "d_player.h" #include "vm.h" #include "c_dispatch.h" #include "v_text.h" #include "g_levellocals.h" #include "a_dynlight.h" - +#include "v_video.h" +#include "g_cvars.h" +#include "d_main.h" static int ThinkCount; static cycle_t ThinkCycles; @@ -82,7 +84,7 @@ void FThinkerCollection::Link(DThinker *thinker, int statnum) } else { - thinker->ObjectFlags &= ~OF_JustSpawned; + if (statnum != STAT_TRAVELLING) thinker->ObjectFlags &= ~OF_JustSpawned; list = &Thinkers[statnum]; } list->AddTail(thinker); @@ -106,6 +108,37 @@ void FThinkerCollection::RunThinkers(FLevelLocals *Level) ThinkCycles.Clock(); + bool dolights; + if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4)) + { + dolights = true;// Level->lights || (Level->flags3 & LEVEL3_LIGHTCREATED); + } + else + { + dolights = false; + } + Level->flags3 &= ~LEVEL3_LIGHTCREATED; + + + auto recreateLights = [=]() { + auto it = Level->GetThinkerIterator(); + + // Set dynamic lights at the end of the tick, so that this catches all changes being made through the last frame. + while (auto ac = it.Next()) + { + if (ac->flags8 & MF8_RECREATELIGHTS) + { + ac->flags8 &= ~MF8_RECREATELIGHTS; + if (dolights) ac->SetDynamicLights(); + } + // This was merged from P_RunEffects to eliminate the costly duplicate ThinkerIterator loop. + if ((ac->effects || ac->fountaincolor) && ac->ShouldRenderLocally() && !Level->isFrozen()) + { + P_RunEffect(ac, ac->effects); + } + } + }; + if (!profilethinkers) { // Tick every thinker left from last time @@ -124,11 +157,15 @@ void FThinkerCollection::RunThinkers(FLevelLocals *Level) } } while (count != 0); - for (auto light = Level->lights; light;) + recreateLights(); + if (dolights) { - auto next = light->next; - light->Tick(); - light = next; + for (auto light = Level->lights; light;) + { + auto next = light->next; + light->Tick(); + light = next; + } } } else @@ -150,7 +187,8 @@ void FThinkerCollection::RunThinkers(FLevelLocals *Level) } } while (count != 0); - if (Level->lights) + recreateLights(); + if (dolights) { // Also profile the internal dynamic lights, even though they are not implemented as thinkers. auto &prof = Profiles[NAME_InternalDynamicLight]; @@ -209,7 +247,7 @@ void FThinkerCollection::RunThinkers(FLevelLocals *Level) Printf(TEXTCOLOR_YELLOW "Total, ms Averg, ms Calls Actor class\n"); Printf(TEXTCOLOR_YELLOW "---------- ---------- ------ --------------------\n"); - const unsigned count = MIN(profilelimit > 0 ? profilelimit : UINT_MAX, sorted.Size()); + const unsigned count = min(profilelimit > 0 ? profilelimit : UINT_MAX, sorted.Size()); for (unsigned i = 0; i < count; ++i) { @@ -233,7 +271,7 @@ void FThinkerCollection::RunThinkers(FLevelLocals *Level) // //========================================================================== -void FThinkerCollection::DestroyAllThinkers() +void FThinkerCollection::DestroyAllThinkers(bool fullgc) { int i; bool error = false; @@ -247,11 +285,12 @@ void FThinkerCollection::DestroyAllThinkers() } } error |= Thinkers[MAX_STATNUM + 1].DoDestroyThinkers(); - GC::FullGC(); + if (fullgc) GC::FullGC(); if (error) { ClearGlobalVMStack(); - I_Error("DestroyAllThinkers failed"); + if (fullgc) I_Error("DestroyAllThinkers failed"); + else I_FatalError("DestroyAllThinkers failed"); } } @@ -499,7 +538,7 @@ bool FThinkerList::DoDestroyThinkers() { Printf("VM exception in DestroyThinkers:\n"); exception.MaybePrintMessage(); - Printf("%s", exception.stacktrace.GetChars()); + Printf(PRINT_NONOTIFY | PRINT_BOLD, "%s", exception.stacktrace.GetChars()); // forcibly delete this. Cleanup may be incomplete, though. node->ObjectFlags |= OF_YesReallyDelete; delete node; @@ -507,7 +546,7 @@ bool FThinkerList::DoDestroyThinkers() } catch (CRecoverableError &exception) { - Printf("Error in DestroyThinkers: %s\n", exception.GetMessage()); + Printf(PRINT_NONOTIFY | PRINT_BOLD, "Error in DestroyThinkers: %s\n", exception.GetMessage()); // forcibly delete this. Cleanup may be incomplete, though. node->ObjectFlags |= OF_YesReallyDelete; delete node; @@ -578,7 +617,6 @@ int FThinkerList::TickThinkers(FThinkerList *dest) ThinkCount++; node->CallTick(); node->ObjectFlags &= ~OF_JustSpawned; - GC::CheckGC(); } node = NextToThink; } @@ -629,7 +667,6 @@ int FThinkerList::ProfileThinkers(FThinkerList *dest) node->CallTick(); prof.timer.Unclock(); node->ObjectFlags &= ~OF_JustSpawned; - GC::CheckGC(); } node = NextToThink; } @@ -770,7 +807,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(DThinker, ChangeStatNum, ChangeStatNum) { PARAM_SELF_PROLOGUE(DThinker); PARAM_INT(stat); - ChangeStatNum(self, stat); + + // do not allow ZScript to reposition thinkers in or out of particle ticking. + if (stat != STAT_VISUALTHINKER && !dynamic_cast(self)) + { + ChangeStatNum(self, stat); + } return 0; } diff --git a/src/playsim/dthinker.h b/src/playsim/dthinker.h index 07d884fc415..78dcd1520bd 100644 --- a/src/playsim/dthinker.h +++ b/src/playsim/dthinker.h @@ -79,7 +79,7 @@ struct FThinkerCollection } void RunThinkers(FLevelLocals *Level); // The level is needed to tick the lights - void DestroyAllThinkers(); + void DestroyAllThinkers(bool fullgc = true); void SerializeThinkers(FSerializer &arc, bool keepPlayers); void MarkRoots(); DThinker *FirstThinker(int statnum); @@ -116,7 +116,7 @@ class DThinker : public DObject friend struct FThinkerCollection; friend class FThinkerIterator; friend class DObject; - friend class FSerializer; + friend class FDoomSerializer; DThinker *NextThinker = nullptr, *PrevThinker = nullptr; diff --git a/src/playsim/fragglescript/t_func.cpp b/src/playsim/fragglescript/t_func.cpp index 69b819202bb..f9fff1b9eff 100644 --- a/src/playsim/fragglescript/t_func.cpp +++ b/src/playsim/fragglescript/t_func.cpp @@ -34,13 +34,13 @@ //--------------------------------------------------------------------------- // -#include "templates.h" + #include "p_local.h" #include "t_script.h" -#include "c_console.h" +#include "sbar.h" #include "c_dispatch.h" #include "d_player.h" -#include "w_wad.h" +#include "filesystem.h" #include "gi.h" #include "v_font.h" #include "serializer.h" @@ -52,6 +52,9 @@ #include "vm.h" #include "a_lights.h" #include "s_music.h" +#include "texturemanager.h" + +using namespace FileSys; static FRandom pr_script("FScript"); @@ -348,24 +351,24 @@ static FSoundID T_FindSound(const char * name) char buffer[40]; FSoundID so=S_FindSound(name); - if (so>0) return so; + if (so.isvalid()) return so; // Now it gets dirty! if (gameinfo.gametype & GAME_DoomStrifeChex) { mysnprintf(buffer, countof(buffer), "DS%.35s", name); - if (Wads.CheckNumForName(buffer, ns_sounds)<0) strcpy(buffer, name); + if (fileSystem.CheckNumForName(buffer, ns_sounds)<0) strcpy(buffer, name); } else { strcpy(buffer, name); - if (Wads.CheckNumForName(buffer, ns_sounds)<0) mysnprintf(buffer, countof(buffer), "DS%.35s", name); + if (fileSystem.CheckNumForName(buffer, ns_sounds)<0) mysnprintf(buffer, countof(buffer), "DS%.35s", name); } - int id = S_AddSound(name, buffer); + FSoundID id = S_AddSound(name, buffer); soundEngine->HashSounds(); - return FSoundID(id); + return id; } @@ -556,7 +559,7 @@ void FParser::SF_Include(void) { if(t_argv[0].type == svt_string) { - strncpy(tempstr, t_argv[0].string, 8); + strncpy(tempstr, t_argv[0].string.GetChars(), 8); tempstr[8]=0; } else @@ -826,7 +829,7 @@ void FParser::SF_Spawn(void) { DVector3 pos; PClassActor *pclass; - DAngle angle = 0.; + DAngle angle = nullAngle; if (CheckArgs(3)) { @@ -852,7 +855,7 @@ void FParser::SF_Spawn(void) if(t_argc >= 4) { - angle = floatvalue(t_argv[3]); + angle = DAngle::fromDeg(floatvalue(t_argv[3])); } t_return.type = svt_mobj; @@ -1012,7 +1015,7 @@ void FParser::SF_ObjAngle(void) mo = Script->trigger; } - t_return.setDouble(mo ? mo->Angles.Yaw.Degrees : 0.); + t_return.setDouble(mo ? mo->Angles.Yaw.Degrees() : 0.); } @@ -1216,7 +1219,7 @@ void FParser::SF_PushThing(void) AActor * mo = actorvalue(t_argv[0]); if(!mo) return; - DAngle angle = floatvalue(t_argv[1]); + DAngle angle = DAngle::fromDeg(floatvalue(t_argv[1])); double force = floatvalue(t_argv[2]); mo->Thrust(angle, force); } @@ -1272,7 +1275,7 @@ void FParser::SF_MobjTarget(void) } t_return.type = svt_mobj; - t_return.value.mobj = mo ? mo->target : NULL; + t_return.value.mobj = mo ? mo->target.Get() : nullptr; } } @@ -1363,7 +1366,7 @@ void FParser::SF_PointToAngle(void) double x2 = floatvalue(t_argv[2]); double y2 = floatvalue(t_argv[3]); - t_return.setDouble(DVector2(x2 - x1, y2 - y1).Angle().Normalized360().Degrees); + t_return.setDouble(DVector2(x2 - x1, y2 - y1).Angle().Normalized360().Degrees()); } } @@ -1414,15 +1417,15 @@ void FParser::SF_SetCamera(void) return; // nullptr check } - angle = t_argc < 2 ? newcamera->Angles.Yaw : floatvalue(t_argv[1]); + angle = t_argc < 2 ? newcamera->Angles.Yaw : DAngle::fromDeg(floatvalue(t_argv[1])); - newcamera->specialf1 = newcamera->Angles.Yaw.Degrees; + newcamera->specialf1 = newcamera->Angles.Yaw.Degrees(); newcamera->specialf2 = newcamera->Z(); double z = t_argc < 3 ? newcamera->Sector->floorplane.ZatPoint(newcamera) + 41 : floatvalue(t_argv[2]); newcamera->SetOrigin(newcamera->PosAtZ(z), false); newcamera->Angles.Yaw = angle; - if (t_argc < 4) newcamera->Angles.Pitch = 0.; - else newcamera->Angles.Pitch = clamp(floatvalue(t_argv[3]), -50., 50.) * (20. / 32.); + if (t_argc < 4) newcamera->Angles.Pitch = nullAngle; + else newcamera->Angles.Pitch = DAngle::fromDeg(clamp(floatvalue(t_argv[3]), -50., 50.) * (20. / 32.)); player->camera=newcamera; newcamera->renderflags |= RF_NOINTERPOLATEVIEW; } @@ -1444,7 +1447,7 @@ void FParser::SF_ClearCamera(void) if (cam) { player->camera=player->mo; - cam->Angles.Yaw = cam->specialf1; + cam->Angles.Yaw = DAngle::fromDeg(cam->specialf1); cam->SetZ(cam->specialf2); } @@ -1866,7 +1869,7 @@ void FParser::SF_FloorTexture(void) if(t_argc > 1) { int i = -1; - FTextureID picnum = TexMan.GetTextureID(t_argv[1].string, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + FTextureID picnum = TexMan.GetTextureID(t_argv[1].string.GetChars(), ETextureType::Flat, FTextureManager::TEXMAN_Overridable); // set all sectors with tag auto itr = Level->GetSectorTagIterator(tagnum); @@ -1877,8 +1880,8 @@ void FParser::SF_FloorTexture(void) } t_return.type = svt_string; - FTexture * tex = TexMan.GetTexture(sector->GetTexture(sector_t::floor)); - t_return.string = tex? tex->GetName() : ""; + auto tex = TexMan.GetGameTexture(sector->GetTexture(sector_t::floor)); + t_return.string = tex? tex->GetName() : FString(); } } @@ -1956,7 +1959,7 @@ void FParser::SF_CeilingTexture(void) if(t_argc > 1) { int i = -1; - FTextureID picnum = TexMan.GetTextureID(t_argv[1].string, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + FTextureID picnum = TexMan.GetTextureID(t_argv[1].string.GetChars(), ETextureType::Flat, FTextureManager::TEXMAN_Overridable); // set all sectors with tag auto itr = Level->GetSectorTagIterator(tagnum); @@ -1967,8 +1970,8 @@ void FParser::SF_CeilingTexture(void) } t_return.type = svt_string; - FTexture * tex = TexMan.GetTexture(sector->GetTexture(sector_t::ceiling)); - t_return.string = tex? tex->GetName() : ""; + auto tex = TexMan.GetGameTexture(sector->GetTexture(sector_t::ceiling)); + t_return.string = tex? tex->GetName() : FString(); } } @@ -2086,14 +2089,14 @@ bool FS_ChangeMusic(const char * string) { char buffer[40]; - if (Wads.CheckNumForName(string, ns_music)<0 || !S_ChangeMusic(string,true)) + if (fileSystem.CheckNumForName(string, ns_music)<0 || !S_ChangeMusic(string,true)) { // Retry with O_ prepended to the music name, then with D_ mysnprintf(buffer, countof(buffer), "O_%s", string); - if (Wads.CheckNumForName(buffer, ns_music)<0 || !S_ChangeMusic(buffer,true)) + if (fileSystem.CheckNumForName(buffer, ns_music)<0 || !S_ChangeMusic(buffer,true)) { mysnprintf(buffer, countof(buffer), "D_%s", string); - if (Wads.CheckNumForName(buffer, ns_music)<0) + if (fileSystem.CheckNumForName(buffer, ns_music)<0) { S_ChangeMusic(NULL, 0); return false; @@ -2226,7 +2229,7 @@ void FParser::SF_SetLineTexture(void) } else // and an improved legacy version { - FTextureID picnum = TexMan.GetTextureID(t_argv[1].string, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + FTextureID picnum = TexMan.GetTextureID(t_argv[1].string.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable); side = !!intvalue(t_argv[2]); int sections = intvalue(t_argv[3]); @@ -2421,7 +2424,7 @@ void FParser::SF_PlayerKeys(void) if(t_argc == 2) { t_return.type = svt_int; - t_return.value.i = CheckInventory(Level->Players[playernum]->mo, keyname); + t_return.value.i = CheckInventory(Level->Players[playernum]->mo, keyname.GetChars()); return; } else @@ -2522,7 +2525,7 @@ void FParser::SF_PlayerWeapon() { wp->Destroy(); // If the weapon is active pick a replacement. Legacy didn't do this! - if (Level->Players[playernum]->PendingWeapon==wp) Level->Players[playernum]->PendingWeapon=WP_NOCHANGE; + if (Level->Players[playernum]->PendingWeapon==wp) Level->Players[playernum]->PendingWeapon=(AActor*)WP_NOCHANGE; if (Level->Players[playernum]->ReadyWeapon==wp) { Level->Players[playernum]->ReadyWeapon=nullptr; @@ -2711,7 +2714,7 @@ void FParser::SF_MoveCamera(void) double targetheight = floatvalue(t_argv[2]); double movespeed = floatvalue(t_argv[3]); DVector3 campos = cam->Pos(); - DVector3 targpos = DVector3(target->Pos(), targetheight); + DVector3 targpos = DVector3(target->Pos().XY(), targetheight); DVector3 movement = targpos - campos; double movelen = movement.Length(); @@ -2731,14 +2734,14 @@ void FParser::SF_MoveCamera(void) } else finishedmove = true; - DAngle targetangle = DAngle(floatvalue(t_argv[4])).Normalized360(); + DAngle targetangle = DAngle::fromDeg(floatvalue(t_argv[4])).Normalized360(); if (cam->Angles.Yaw != targetangle) { - DAngle anglespeed = floatvalue(t_argv[5]); + DAngle anglespeed = DAngle::fromDeg(floatvalue(t_argv[5])); DAngle anglenow = targetangle; const DAngle diffangle = deltaangle(cam->Angles.Yaw, targetangle); - if (movespeed > 0 && anglespeed == 0.) + if (movespeed > 0 && anglespeed == nullAngle) { if (!finishedmove) { @@ -2748,7 +2751,7 @@ void FParser::SF_MoveCamera(void) } else { - if (diffangle > 0) + if (diffangle > nullAngle) { anglenow = (cam->Angles.Yaw + anglespeed).Normalized360(); } @@ -2757,7 +2760,7 @@ void FParser::SF_MoveCamera(void) anglenow = (cam->Angles.Yaw - anglespeed).Normalized360(); } const DAngle diffangle2 = deltaangle(anglenow, targetangle); - if (diffangle.Degrees * diffangle2.Degrees <= 0) + if (diffangle.Degrees() * diffangle2.Degrees() <= 0) { anglenow = targetangle; finishedangle = true; @@ -2911,7 +2914,7 @@ void FParser::SF_SpawnExplosion() { spawn->ClearCounters(); t_return.value.i = spawn->SetState(spawn->FindState(NAME_Death)); - if(spawn->DeathSound) S_Sound (spawn, CHAN_BODY, 0, spawn->DeathSound, 1, ATTN_NORM); + if(spawn->DeathSound.isvalid()) S_Sound (spawn, CHAN_BODY, 0, spawn->DeathSound, 1, ATTN_NORM); } } } @@ -3306,7 +3309,7 @@ void FParser::SF_LineAttack() mo = actorvalue(t_argv[0]); damage = intvalue(t_argv[2]); - angle = floatvalue(t_argv[1]); + angle = DAngle::fromDeg(floatvalue(t_argv[1])); slope = P_AimLineAttack(mo, angle, MISSILERANGE); P_LineAttack(mo, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff); diff --git a/src/playsim/fragglescript/t_load.cpp b/src/playsim/fragglescript/t_load.cpp index 8d2b5d6d770..32518aa196b 100644 --- a/src/playsim/fragglescript/t_load.cpp +++ b/src/playsim/fragglescript/t_load.cpp @@ -24,7 +24,7 @@ // -#include "w_wad.h" +#include "filesystem.h" #include "g_level.h" #include "s_sound.h" #include "r_sky.h" @@ -35,6 +35,7 @@ #include "xlat/xlat.h" #include "maploader/maploader.h" #include "s_music.h" +#include "texturemanager.h" class FScriptLoader { @@ -136,7 +137,7 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc) sc.MustGetString(); if (!FS_ChangeMusic(sc.String)) { - S_ChangeMusic(Level->Music, Level->musicorder); + S_ChangeMusic(Level->Music.GetChars(), Level->musicorder); } } else if (sc.Compare("skyname")) @@ -221,13 +222,13 @@ bool FScriptLoader::ParseInfo(MapData * map) if (lumpsize==0) { // Try a global FS lump - int lumpnum=Wads.CheckNumForName("FSGLOBAL"); + int lumpnum=fileSystem.CheckNumForName("FSGLOBAL"); if (lumpnum<0) return false; - lumpsize=Wads.LumpLength(lumpnum); + lumpsize=fileSystem.FileLength(lumpnum); if (lumpsize==0) return false; fsglobal=true; lump=new char[lumpsize+3]; - Wads.ReadLump(lumpnum,lump); + fileSystem.ReadFile(lumpnum,lump); } else { @@ -264,7 +265,8 @@ bool FScriptLoader::ParseInfo(MapData * map) } auto th = Level->CreateThinker(); - th->LevelScript->data = copystring(scriptsrc.GetChars()); + th->LevelScript->Data.Resize((unsigned)scriptsrc.Len() + 1); + memcpy(th->LevelScript->Data.Data(), scriptsrc.GetChars(), scriptsrc.Len() + 1); Level->FraggleScriptThinker = th; if (drownflag==-1) drownflag = (Level->maptype != MAPTYPE_DOOM || fsglobal); @@ -313,6 +315,6 @@ void T_AddSpawnedThing(FLevelLocals *Level, AActor * ac) if (Level->FraggleScriptThinker) { auto &SpawnedThings = Level->FraggleScriptThinker->SpawnedThings; - SpawnedThings.Push(GC::ReadBarrier(ac)); + SpawnedThings.Push(MakeObjPtr(ac)); } } diff --git a/src/playsim/fragglescript/t_oper.cpp b/src/playsim/fragglescript/t_oper.cpp index 8b4368db773..beac99d0eba 100644 --- a/src/playsim/fragglescript/t_oper.cpp +++ b/src/playsim/fragglescript/t_oper.cpp @@ -167,7 +167,7 @@ void FParser::OPcmp(svalue_t &result, int start, int n, int stop) if(left.type == svt_string && right.type == svt_string) { - result.value.i = !strcmp(left.string, right.string); + result.value.i = !strcmp(left.string.GetChars(), right.string.GetChars()); return; } diff --git a/src/playsim/fragglescript/t_parse.cpp b/src/playsim/fragglescript/t_parse.cpp index 78bfc3aed12..a0bd931020c 100644 --- a/src/playsim/fragglescript/t_parse.cpp +++ b/src/playsim/fragglescript/t_parse.cpp @@ -709,10 +709,10 @@ void FParser::ErrorMessage(FString msg) int linenum = 0; // find the line number - if(Rover >= Script->data && Rover <= Script->data+Script->len) + if(Rover >= Script->Data.Data() && Rover <= Script->Data.Data() +Script->len) { char *temp; - for(temp = Script->data; tempData.Data(); tempstart_index; + return Data.Data() + sec->start_index; } //========================================================================== @@ -99,7 +100,7 @@ char *DFsScript::SectionStart(const DFsSection *sec) char *DFsScript::SectionEnd(const DFsSection *sec) { - return data + sec->end_index; + return Data.Data() + sec->end_index; } //========================================================================== @@ -110,7 +111,7 @@ char *DFsScript::SectionEnd(const DFsSection *sec) char *DFsScript::SectionLoop(const DFsSection *sec) { - return data + sec->loop_index; + return Data.Data() + sec->loop_index; } //========================================================================== @@ -283,7 +284,7 @@ char *DFsScript::ProcessFindChar(char *datap, char find) Printf(PRINT_BOLD,"Script %d: ':' encountrered in incorrect position!\n",scriptnum); } - DFsVariable *newlabel = NewVariable(labelname, svt_label); + DFsVariable *newlabel = NewVariable(labelname.GetChars(), svt_label); newlabel->value.i = MakeIndex(labelptr); } @@ -335,8 +336,8 @@ char *DFsScript::ProcessFindChar(char *datap, char find) void DFsScript::DryRunScript(FLevelLocals *Level) { - char *end = data + len; - char *rover = data; + char *end = Data.Data() + len; + char *rover = Data.Data(); // allocate space for the tokens FParser parse(Level, this); @@ -389,8 +390,8 @@ void DFsScript::DryRunScript(FLevelLocals *Level) void DFsScript::Preprocess(FLevelLocals *Level) { - len = (int)strlen(data); - ProcessFindChar(data, 0); // fill in everything + len = (int)Data.Size() - 1; + ProcessFindChar(Data.Data(), 0); // fill in everything DryRunScript(Level); } @@ -409,30 +410,26 @@ void DFsScript::Preprocess(FLevelLocals *Level) void DFsScript::ParseInclude(FLevelLocals *Level, char *lumpname) { int lumpnum; - char *lump; - if((lumpnum = Wads.CheckNumForName(lumpname)) == -1) + if((lumpnum = fileSystem.CheckNumForName(lumpname)) == -1) { I_Error("include lump '%s' not found!\n", lumpname); return; } - int lumplen=Wads.LumpLength(lumpnum); - lump=new char[lumplen+10]; - Wads.ReadLump(lumpnum,lump); + int lumplen=fileSystem.FileLength(lumpnum); + TArray lump(lumplen + 10); + fileSystem.ReadFile(lumpnum,lump.Data()); lump[lumplen]=0; // preprocess the include // we assume that it does not include sections or labels or // other nasty things - ProcessFindChar(lump, 0); + ProcessFindChar(lump.Data(), 0); // now parse the lump FParser parse(Level, this); - parse.Run(lump, lump, lump+lumplen); - - // free the lump - delete[] lump; + parse.Run(lump.Data(), lump.Data(), lump.Data() + lumplen); } diff --git a/src/playsim/fragglescript/t_script.cpp b/src/playsim/fragglescript/t_script.cpp index fd2cbcefcc6..7af1424ab82 100644 --- a/src/playsim/fragglescript/t_script.cpp +++ b/src/playsim/fragglescript/t_script.cpp @@ -38,6 +38,7 @@ #include "p_spec.h" #include "c_dispatch.h" #include "serializer.h" +#include "serialize_obj.h" #include "g_levellocals.h" //========================================================================== @@ -127,7 +128,6 @@ DFsScript::DFsScript() for(i=0; i data+len) + if(position < Data.Data() || position > Data.Data() +len) { Printf("script %d: trying to continue from point outside script!\n", scriptnum); return; @@ -216,7 +202,7 @@ void DFsScript::ParseScript(char *position, DFraggleThinker *th) try { FParser parse(th->Level, this); - parse.Run(position, data, data + len); + parse.Run(position, Data.Data(), Data.Data() + len); } catch (CFraggleScriptError &err) { @@ -528,7 +514,7 @@ void DFraggleThinker::Tick() next = current->next; // save before freeing // continue the script - current->script->ParseScript (current->script->data + current->save_point, this); + current->script->ParseScript (current->script->Data.Data() + current->save_point, this); // free current->Destroy(); @@ -563,9 +549,9 @@ size_t DFraggleThinker::PropagateMark() // //========================================================================== -size_t DFraggleThinker::PointerSubstitution (DObject *old, DObject *notOld) +size_t DFraggleThinker::PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail) { - size_t changed = Super::PointerSubstitution(old, notOld); + size_t changed = Super::PointerSubstitution(old, notOld, nullOnFail); for(unsigned i=0;i(old)) diff --git a/src/playsim/fragglescript/t_script.h b/src/playsim/fragglescript/t_script.h index f213008871f..2dc79a95e5c 100644 --- a/src/playsim/fragglescript/t_script.h +++ b/src/playsim/fragglescript/t_script.h @@ -28,7 +28,7 @@ #include "p_lnspec.h" #include "m_fixed.h" #include "actor.h" -#include "doomerrors.h" +#include "engineerrors.h" #ifdef _MSC_VER // This pragma saves 8kb of wasted code. @@ -38,11 +38,11 @@ class DFraggleThinker; -class CFraggleScriptError : public CDoomError +class CFraggleScriptError : public CEngineError { public: - CFraggleScriptError() : CDoomError() {} - CFraggleScriptError(const char *message) : CDoomError(message) {} + CFraggleScriptError() : CEngineError() {} + CFraggleScriptError(const char *message) : CEngineError(message) {} }; @@ -101,13 +101,8 @@ struct svalue_t value.i = 0; } - svalue_t(const svalue_t & other) - { - type = other.type; - string = other.string; - value = other.value; - } - + svalue_t(const svalue_t & other) = default; + svalue_t& operator=(const svalue_t& other) = default; void setInt(int ip) { value.i = ip; @@ -278,7 +273,7 @@ class CFsError CFsError(const FString &in) { - strncpy(msg, in, 2047); + strncpy(msg, in.GetChars(), 2047); msg[2047]=0; } }; @@ -303,7 +298,7 @@ class DFsScript : public DObject public: // script data - char *data; + TArray Data; int scriptnum; // this script's number int len; @@ -335,7 +330,6 @@ class DFsScript : public DObject // true or false DFsScript(); - ~DFsScript(); void OnDestroy() override; void Serialize(FSerializer &ar); @@ -354,7 +348,7 @@ class DFsScript : public DObject void ClearSections(); void ClearChildren(); - int MakeIndex(const char *p) { return int(p-data); } + int MakeIndex(const char *p) { return int(p-Data.Data()); } // preprocessor int section_hash(const char *b) { return MakeIndex(b) % SECTIONSLOTS; } @@ -707,7 +701,7 @@ class DFraggleThinker : public DThinker void Tick(); void InitFunctions(); size_t PropagateMark(); - size_t PointerSubstitution (DObject *old, DObject *notOld); + size_t PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail); bool wait_finished(DRunningScript *script); void AddRunningScript(DRunningScript *runscr); diff --git a/src/playsim/fragglescript/t_spec.cpp b/src/playsim/fragglescript/t_spec.cpp index 5361c7c1e38..e9373224294 100644 --- a/src/playsim/fragglescript/t_spec.cpp +++ b/src/playsim/fragglescript/t_spec.cpp @@ -416,14 +416,14 @@ void FParser::spec_script() datasize = (Section->end_index - Section->start_index - 2); // alloc extra 10 for safety - newscript->data = (char *)malloc(datasize+10); + newscript->Data.Resize(datasize+1); // copy from parent newscript (levelscript) // ignore first char which is { - memcpy(newscript->data, Script->SectionStart(Section) + 1, datasize); + memcpy(newscript->Data.Data(), Script->SectionStart(Section) + 1, datasize); // tack on a 0 to end the string - newscript->data[datasize] = '\0'; + newscript->Data.Data()[datasize] = '\0'; newscript->scriptnum = scriptnum; newscript->parent = Script; // remember parent diff --git a/src/playsim/fragglescript/t_variable.cpp b/src/playsim/fragglescript/t_variable.cpp index c73bf14fc80..f3ab2388392 100644 --- a/src/playsim/fragglescript/t_variable.cpp +++ b/src/playsim/fragglescript/t_variable.cpp @@ -42,6 +42,7 @@ #include "t_script.h" #include "a_pickups.h" #include "serializer.h" +#include "serialize_obj.h" #include "g_levellocals.h" @@ -53,7 +54,7 @@ int intvalue(const svalue_t &v) { - return (v.type == svt_string ? atoi(v.string) : + return (v.type == svt_string ? atoi(v.string.GetChars()) : v.type == svt_fixed ? (int)(v.value.f / 65536.) : v.type == svt_mobj ? -1 : v.value.i ); } @@ -67,7 +68,7 @@ int intvalue(const svalue_t &v) fsfix fixedvalue(const svalue_t &v) { return (v.type == svt_fixed ? v.value.f : - v.type == svt_string ? (fsfix)(atof(v.string) * 65536.) : + v.type == svt_string ? (fsfix)(atof(v.string.GetChars()) * 65536.) : v.type == svt_mobj ? -65536 : v.value.i * 65536 ); } @@ -80,7 +81,7 @@ fsfix fixedvalue(const svalue_t &v) double floatvalue(const svalue_t &v) { return - v.type == svt_string ? atof(v.string) : + v.type == svt_string ? atof(v.string.GetChars()) : v.type == svt_fixed ? v.value.f / 65536. : v.type == svt_mobj ? -1. : (double)v.value.i; } @@ -98,11 +99,11 @@ const char *stringvalue(const svalue_t & v) switch(v.type) { case svt_string: - return v.string; + return v.string.GetChars(); case svt_mobj: // return the class name - return (const char *)v.value.mobj->GetClass()->TypeName; + return (const char *)v.value.mobj->GetClass()->TypeName.GetChars(); case svt_fixed: { @@ -348,7 +349,7 @@ DFsVariable *DFsScript::VariableForName(const char *name) while(current) { - if(!strcmp(name, current->Name)) // found it? + if(!strcmp(name, current->Name.GetChars())) // found it? return current; current = current->next; // check next in chain } @@ -428,7 +429,7 @@ void DFsScript::ClearVariables(bool complete) char *DFsScript::LabelValue(const svalue_t &v) { - if (v.type == svt_label) return data + v.value.i; + if (v.type == svt_label) return Data.Data() + v.value.i; else return NULL; } diff --git a/src/playsim/mapthinkers/a_ceiling.cpp b/src/playsim/mapthinkers/a_ceiling.cpp index b9c168ed92d..1afdf4509eb 100644 --- a/src/playsim/mapthinkers/a_ceiling.cpp +++ b/src/playsim/mapthinkers/a_ceiling.cpp @@ -252,6 +252,7 @@ bool FLevelLocals::CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t case DCeiling::ceilCrushAndRaise: case DCeiling::ceilCrushRaiseAndStay: ceiling->m_TopHeight = sec->ceilingplane.fD(); + [[fallthrough]]; case DCeiling::ceilLowerAndCrush: targheight = FindHighestFloorPoint (sec, &spot); targheight += height; diff --git a/src/playsim/mapthinkers/a_ceiling.h b/src/playsim/mapthinkers/a_ceiling.h index d1db8b70a87..2954fb11852 100644 --- a/src/playsim/mapthinkers/a_ceiling.h +++ b/src/playsim/mapthinkers/a_ceiling.h @@ -54,6 +54,9 @@ class DCeiling : public DMovingCeiling void Serialize(FSerializer &arc); void Tick (); + int getCrush() const { return m_Crush; } + int getDirection() const { return m_Direction; } + protected: ECeiling m_Type; double m_BottomHeight; diff --git a/src/playsim/mapthinkers/a_decalfx.cpp b/src/playsim/mapthinkers/a_decalfx.cpp index 33b5e360749..7052373c7ea 100644 --- a/src/playsim/mapthinkers/a_decalfx.cpp +++ b/src/playsim/mapthinkers/a_decalfx.cpp @@ -34,7 +34,8 @@ #include "decallib.h" #include "a_decalfx.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "a_sharedglobal.h" #include "g_levellocals.h" #include "m_fixed.h" diff --git a/src/playsim/mapthinkers/a_doors.cpp b/src/playsim/mapthinkers/a_doors.cpp index f517d20db57..2d8d2c70ca9 100644 --- a/src/playsim/mapthinkers/a_doors.cpp +++ b/src/playsim/mapthinkers/a_doors.cpp @@ -34,10 +34,12 @@ #include "r_state.h" #include "gi.h" #include "a_keys.h" -#include "serializer.h" +#include "serializer_doom.h" #include "d_player.h" #include "p_spec.h" #include "g_levellocals.h" +#include "animations.h" +#include "texturemanager.h" //============================================================================ // @@ -289,7 +291,7 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const if (line->backsector == NULL) continue; - FTexture *tex = TexMan.GetTexture(line->sidedef[0]->GetTexture(side_t::top)); + auto tex = TexMan.GetGameTexture(line->sidedef[0]->GetTexture(side_t::top)); texname = tex ? tex->GetName().GetChars() : NULL; if (texname != NULL && texname[0] == 'D' && texname[1] == 'O' && texname[2] == 'R') { @@ -714,7 +716,7 @@ void DAnimatedDoor::Construct(sector_t *sec, line_t *line, int speed, int delay, picnum = tex1[side_t::top].texture; - FTexture *tex = TexMan.GetTexture(picnum); + auto tex = TexMan.GetGameTexture(picnum); topdist = tex ? tex->GetDisplayHeight() : 64; topdist = m_Sector->ceilingplane.fD() - topdist * m_Sector->ceilingplane.fC(); @@ -764,7 +766,7 @@ bool FLevelLocals::EV_SlidingDoor (line_t *line, AActor *actor, int tag, int spe // Make sure door isn't already being animated if (sec->ceilingdata != NULL ) { - if (actor->player == NULL) + if (actor == NULL || actor->player == NULL) return false; if (sec->ceilingdata->IsA (RUNTIME_CLASS(DAnimatedDoor))) @@ -780,7 +782,7 @@ bool FLevelLocals::EV_SlidingDoor (line_t *line, AActor *actor, int tag, int spe // Do not attempt to close the door if it already is else if (type == DAnimatedDoor::adClose) return false; - FDoorAnimation *anim = TexMan.FindAnimatedDoor (line->sidedef[0]->GetTexture(side_t::top)); + FDoorAnimation *anim = TexAnim.FindAnimatedDoor (line->sidedef[0]->GetTexture(side_t::top)); if (anim != NULL) { CreateThinker(sec, line, speed, delay, anim, type); @@ -816,7 +818,7 @@ bool FLevelLocals::EV_SlidingDoor (line_t *line, AActor *actor, int tag, int spe { continue; } - FDoorAnimation *anim = TexMan.FindAnimatedDoor (line->sidedef[0]->GetTexture(side_t::top)); + FDoorAnimation *anim = TexAnim.FindAnimatedDoor (line->sidedef[0]->GetTexture(side_t::top)); if (anim != NULL) { rtn = true; diff --git a/src/playsim/mapthinkers/a_floor.cpp b/src/playsim/mapthinkers/a_floor.cpp index 0bd2ae5b729..0d330e4e906 100644 --- a/src/playsim/mapthinkers/a_floor.cpp +++ b/src/playsim/mapthinkers/a_floor.cpp @@ -34,11 +34,14 @@ #include "doomstat.h" #include "r_state.h" #include "serializer.h" +#include "serialize_obj.h" #include "p_3dmidtex.h" #include "p_spec.h" #include "r_data/r_interpolate.h" #include "g_levellocals.h" #include "vm.h" +#include "r_utility.h" +#include "actorinlines.h" //========================================================================== // @@ -152,7 +155,7 @@ void DFloor::Tick () case genFloorChgT: case genFloorChg0: m_Sector->SetSpecial(&m_NewSpecial); - //fall thru + [[fallthrough]]; case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); break; @@ -168,7 +171,7 @@ void DFloor::Tick () case genFloorChgT: case genFloorChg0: m_Sector->SetSpecial(&m_NewSpecial); - //fall thru + [[fallthrough]]; case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); break; @@ -319,6 +322,7 @@ bool FLevelLocals::CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t * case DFloor::floorLowerInstant: floor->m_Speed = height; + [[fallthrough]]; case DFloor::floorLowerByValue: floor->m_Direction = -1; newheight = sec->CenterFloor() - height; @@ -327,6 +331,7 @@ bool FLevelLocals::CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t * case DFloor::floorRaiseInstant: floor->m_Speed = height; + [[fallthrough]]; case DFloor::floorRaiseByValue: floor->m_Direction = 1; newheight = sec->CenterFloor() + height; @@ -341,6 +346,7 @@ bool FLevelLocals::CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t * case DFloor::floorRaiseAndCrushDoom: height = 8; + [[fallthrough]]; case DFloor::floorRaiseToLowestCeiling: floor->m_Direction = 1; newheight = FindLowestCeilingSurrounding(sec, &spot) - height; @@ -644,7 +650,7 @@ bool FLevelLocals::EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, d floor->m_Instant = false; floor->m_Crush = (usespecials & DFloor::stairCrush) ? 10 : -1; //jff 2/27/98 fix uninitialized crush field - floor->m_Hexencrush = false; + floor->m_Hexencrush = true; floor->m_Speed = speed; height = sec->CenterFloor() + stairstep; @@ -657,6 +663,8 @@ bool FLevelLocals::EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, d // 1. Find 2-sided line with same sector side[0] (lowest numbered) // 2. Other side is the next sector to raise // 3. Unless already moving, or different texture, then stop building + validcount++; + sec->validcount = validcount; do { ok = 0; @@ -664,12 +672,13 @@ bool FLevelLocals::EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, d if (usespecials & DFloor::stairUseSpecials) { // [RH] Find the next sector by scanning for Stairs_Special? - tsec = sec->NextSpecialSector ( + tsec = P_NextSpecialSectorVC(sec, sec->special == Stairs_Special1 ? - Stairs_Special2 : Stairs_Special1, prev); + Stairs_Special2 : Stairs_Special1); - if ( (ok = (tsec != NULL)) ) + if ( (ok = (tsec != nullptr)) ) { + tsec->validcount = validcount; height += stairstep; // if sector's floor already moving, look for another @@ -802,13 +811,12 @@ bool FLevelLocals::EV_DoDonut (int tag, line_t *line, double pillarspeed, double if (!s2) // note lowest numbered line around continue; // pillar must be two-sided - if (s2->PlaneMoving(sector_t::floor)) + if (!(i_compatflags2 & COMPATF2_FLOORMOVE) && s2->PlaneMoving(sector_t::floor)) continue; for (auto ln : s2->Lines) { - if (!(ln->flags & ML_TWOSIDED) || - (ln->backsector == s1)) + if (ln->backsector == nullptr || ln->backsector == s1) continue; s3 = ln->backsector; diff --git a/src/playsim/mapthinkers/a_lightning.cpp b/src/playsim/mapthinkers/a_lightning.cpp index 541df51a57a..f6e0f713dde 100644 --- a/src/playsim/mapthinkers/a_lightning.cpp +++ b/src/playsim/mapthinkers/a_lightning.cpp @@ -26,7 +26,7 @@ #include "doomstat.h" #include "p_lnspec.h" #include "m_random.h" -#include "templates.h" + #include "s_sound.h" #include "p_acs.h" #include "r_sky.h" @@ -36,6 +36,7 @@ #include "g_levellocals.h" #include "events.h" #include "gi.h" +#include static FRandom pr_lightning ("Lightning"); @@ -47,11 +48,12 @@ IMPLEMENT_CLASS(DLightningThinker, false, false) // //---------------------------------------------------------------------------- -void DLightningThinker::Construct() +void DLightningThinker::Construct(FSoundID tempSound) { Stopped = false; LightningFlashCount = 0; - NextLightningFlash = ((pr_lightning()&15)+5)*35; // don't flash at level start + NextLightningFlash = ((pr_lightning()&15)+5)*TICRATE; // don't flash at level start + TempLightningSound = tempSound; LightningLightLevels.Resize(Level->sectors.Size()); fillshort(&LightningLightLevels[0], LightningLightLevels.Size(), SHRT_MAX); @@ -73,7 +75,8 @@ void DLightningThinker::Serialize(FSerializer &arc) arc("stopped", Stopped) ("next", NextLightningFlash) ("count", LightningFlashCount) - ("levels", LightningLightLevels); + ("levels", LightningLightLevels) + ("tempsound", TempLightningSound); } //---------------------------------------------------------------------------- @@ -157,11 +160,11 @@ void DLightningThinker::LightningFlash () LightningLightLevels[j] = tempSec->lightlevel; if (special == Light_IndoorLightning1) { - tempSec->SetLightLevel(MIN (tempSec->lightlevel+64, flashLight)); + tempSec->SetLightLevel(min (tempSec->lightlevel+64, flashLight)); } else if (special == Light_IndoorLightning2) { - tempSec->SetLightLevel(MIN (tempSec->lightlevel+32, flashLight)); + tempSec->SetLightLevel(min (tempSec->lightlevel+32, flashLight)); } else { @@ -176,7 +179,15 @@ void DLightningThinker::LightningFlash () } Level->flags |= LEVEL_SWAPSKIES; // set alternate sky - S_Sound (CHAN_AUTO, 0, "world/thunder", 1.0, ATTN_NONE); + if (TempLightningSound == NO_SOUND) + { + S_Sound(CHAN_AUTO, 0, Level->LightningSound, 1.0, ATTN_NONE); + } + else + { + S_Sound(CHAN_AUTO, 0, TempLightningSound, 1.0, ATTN_NONE); + TempLightningSound = NO_SOUND; + } // [ZZ] just in case Level->localEventManager->WorldLightning(); // start LIGHTNING scripts @@ -193,11 +204,11 @@ void DLightningThinker::LightningFlash () { if (pr_lightning() < 128 && !(Level->time&32)) { - NextLightningFlash = ((pr_lightning()&7)+2)*35; + NextLightningFlash = ((pr_lightning()&7)+2)*TICRATE; } else { - NextLightningFlash = ((pr_lightning()&15)+5)*35; + NextLightningFlash = ((pr_lightning()&15)+5)*TICRATE; } } } @@ -209,16 +220,18 @@ void DLightningThinker::LightningFlash () // //---------------------------------------------------------------------------- -void DLightningThinker::ForceLightning (int mode) +void DLightningThinker::ForceLightning (int mode, FSoundID tempSound) { switch (mode) { default: NextLightningFlash = 0; + TempLightningSound = tempSound; break; case 1: NextLightningFlash = 0; + TempLightningSound = tempSound; // Fall through case 2: Stopped = true; @@ -285,15 +298,24 @@ void FLevelLocals::StartLightning () // //---------------------------------------------------------------------------- -void FLevelLocals::ForceLightning (int mode) +void FLevelLocals::ForceLightning (int mode, FSoundID tempSound) { DLightningThinker *lightning = LocateLightning (this); if (lightning == nullptr) { - lightning = CreateThinker(); + lightning = CreateThinker(tempSound); } if (lightning != nullptr) { - lightning->ForceLightning (mode); + lightning->ForceLightning (mode, tempSound); } } + +DEFINE_ACTION_FUNCTION(FLevelLocals, ForceLightning) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_INT(mode); + PARAM_SOUND(tempSound); + self->ForceLightning(mode,tempSound); + return 0; +} \ No newline at end of file diff --git a/src/playsim/mapthinkers/a_lightning.h b/src/playsim/mapthinkers/a_lightning.h index 89992f620e8..f8f9b71dfbb 100644 --- a/src/playsim/mapthinkers/a_lightning.h +++ b/src/playsim/mapthinkers/a_lightning.h @@ -6,17 +6,18 @@ #endif #include "dthinker.h" +#include "s_soundinternal.h" class DLightningThinker : public DThinker { DECLARE_CLASS (DLightningThinker, DThinker); public: static const int DEFAULT_STAT = STAT_LIGHTNING; - void Construct(); + void Construct(FSoundID tempSound = NO_SOUND); ~DLightningThinker (); void Serialize(FSerializer &arc); void Tick (); - void ForceLightning (int mode); + void ForceLightning (int mode, FSoundID tempSound = NO_SOUND); void TerminateLightning(); protected: @@ -25,6 +26,7 @@ class DLightningThinker : public DThinker int NextLightningFlash; int LightningFlashCount; bool Stopped; + FSoundID TempLightningSound; TArray LightningLightLevels; }; diff --git a/src/playsim/mapthinkers/a_lights.cpp b/src/playsim/mapthinkers/a_lights.cpp index 68c417446a4..9cd7fb20f1d 100644 --- a/src/playsim/mapthinkers/a_lights.cpp +++ b/src/playsim/mapthinkers/a_lights.cpp @@ -26,7 +26,7 @@ //----------------------------------------------------------------------------- -#include "templates.h" + #include "m_random.h" #include "doomdef.h" @@ -521,7 +521,7 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev else l = Level->CreateThinker (sector, baselevel); - int numsteps = PhaseHelper (sector->NextSpecialSector ( + int numsteps = PhaseHelper (P_NextSpecialSector (sector, sector->special == LightSequenceSpecial1 ? LightSequenceSpecial2 : LightSequenceSpecial1, prev), index + 1, l->m_BaseLevel, sector); diff --git a/src/playsim/mapthinkers/a_lighttransfer.cpp b/src/playsim/mapthinkers/a_lighttransfer.cpp index 931de98daac..f5185ea592e 100644 --- a/src/playsim/mapthinkers/a_lighttransfer.cpp +++ b/src/playsim/mapthinkers/a_lighttransfer.cpp @@ -34,7 +34,7 @@ #include "p_spec.h" #include "a_lighttransfer.h" -#include "serializer.h" +#include "serializer_doom.h" #include "g_levellocals.h" // diff --git a/src/playsim/mapthinkers/a_pillar.cpp b/src/playsim/mapthinkers/a_pillar.cpp index fb76056176b..c5a9c287743 100644 --- a/src/playsim/mapthinkers/a_pillar.cpp +++ b/src/playsim/mapthinkers/a_pillar.cpp @@ -38,6 +38,7 @@ #include "g_level.h" #include "s_sndseq.h" #include "serializer.h" +#include "serialize_obj.h" #include "r_data/r_interpolate.h" #include "g_levellocals.h" diff --git a/src/playsim/mapthinkers/a_plats.cpp b/src/playsim/mapthinkers/a_plats.cpp index 8decb188fe8..c688295e4e3 100644 --- a/src/playsim/mapthinkers/a_plats.cpp +++ b/src/playsim/mapthinkers/a_plats.cpp @@ -127,6 +127,7 @@ void DPlat::Tick () // better use a flag to avoid problems elsewhere. For example, // keeping the thinker would make tagwait wait indefinitely. m_Sector->planes[sector_t::floor].Flags |= PLANEF_BLOCKED; + [[fallthrough]]; case platRaiseAndStay: case platDownByValue: case platDownWaitUpStay: @@ -282,6 +283,7 @@ bool FLevelLocals::EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, doub { case DPlat::platToggle: rtn = true; + [[fallthrough]]; case DPlat::platPerpetualRaise: ActivateInStasisPlat (tag); break; diff --git a/src/playsim/mapthinkers/a_pusher.cpp b/src/playsim/mapthinkers/a_pusher.cpp index 92cb502f7c6..eefb427a107 100644 --- a/src/playsim/mapthinkers/a_pusher.cpp +++ b/src/playsim/mapthinkers/a_pusher.cpp @@ -30,6 +30,7 @@ #include "actor.h" #include "p_spec.h" #include "serializer.h" +#include "serialize_obj.h" #include "p_lnspec.h" #include "p_maputl.h" #include "p_local.h" @@ -231,7 +232,7 @@ void DPusher::Tick () if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY))) { DAngle pushangle = pos.Angle(); - if (m_Source->GetClass()->TypeName == NAME_PointPuller) pushangle += 180; + if (m_Source->IsKindOf(NAME_PointPuller)) pushangle += DAngle::fromDeg(180); thing->Thrust(pushangle, speed); } } @@ -271,13 +272,13 @@ void DPusher::Tick () { pushvel = m_PushVec; // full force } - else if (thing->player->viewz < ht) // underwater + else if (thing->player && thing->player->viewz < ht) // underwater { pushvel.Zero(); // no force } else // wading in water { - pushvel = m_PushVec / 2; // full force + pushvel = m_PushVec / 2; // half force } } } diff --git a/src/playsim/mapthinkers/a_pusher.h b/src/playsim/mapthinkers/a_pusher.h index c3cf30efae6..4ce7c73a5ac 100644 --- a/src/playsim/mapthinkers/a_pusher.h +++ b/src/playsim/mapthinkers/a_pusher.h @@ -26,7 +26,7 @@ class DPusher : public DThinker int CheckForSectorMatch (EPusher type, int tag); void ChangeValues (int magnitude, int angle) { - DAngle ang = angle * (360. / 256.); + DAngle ang = DAngle::fromDeg(angle * (360. / 256.)); m_PushVec = ang.ToVector(magnitude); m_Magnitude = magnitude; } @@ -44,3 +44,18 @@ class DPusher : public DThinker friend bool PIT_PushThing (AActor *thing); }; +class DThruster : public DThinker +{ + DECLARE_CLASS(DThruster, DThinker) + + DVector2 m_PushVec; + sector_t* m_Sector; + int m_Type; + int m_Location; + +public: + void Construct(sector_t* sec, double dx, double dy, int type, int location); + void Serialize(FSerializer& arc); + void Tick(); + +}; diff --git a/src/playsim/mapthinkers/a_quake.cpp b/src/playsim/mapthinkers/a_quake.cpp index e21c3c313d5..b21951562e3 100644 --- a/src/playsim/mapthinkers/a_quake.cpp +++ b/src/playsim/mapthinkers/a_quake.cpp @@ -22,16 +22,19 @@ // Hexen's earthquake system, significantly enhanced // -#include "templates.h" + #include "doomtype.h" #include "doomstat.h" #include "p_local.h" #include "actor.h" #include "a_sharedglobal.h" #include "serializer.h" +#include "serialize_obj.h" #include "d_player.h" #include "r_utility.h" #include "g_levellocals.h" +#include "actorinlines.h" +#include static FRandom pr_quake ("Quake"); @@ -47,10 +50,10 @@ IMPLEMENT_POINTERS_END // //========================================================================== -void DEarthquake::Construct(AActor *center, int intensityX, int intensityY, int intensityZ, int duration, - int damrad, int tremrad, FSoundID quakesound, int flags, - double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, - double rollIntensity, double rollWave) +void DEarthquake::Construct(AActor *center, double intensityX, double intensityY, double intensityZ, int duration, + double damrad, double tremrad, FSoundID quakesound, int flags, + double waveSpeedX, double waveSpeedY, double waveSpeedZ, double falloff, int highpoint, + double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage) { m_QuakeSFX = quakesound; m_Spot = center; @@ -67,6 +70,9 @@ void DEarthquake::Construct(AActor *center, int intensityX, int intensityY, int m_MiniCount = highpoint; m_RollIntensity = rollIntensity; m_RollWave = rollWave; + m_DamageMultiplier = damageMultiplier; + m_ThrustMultiplier = thrustMultiplier; + m_Damage = damage; } //========================================================================== @@ -92,13 +98,16 @@ void DEarthquake::Serialize(FSerializer &arc) ("minicount", m_MiniCount) ("rollintensity", m_RollIntensity) ("rollwave", m_RollWave); + ("damagemultiplier", m_DamageMultiplier); + ("thrustmultiplier", m_ThrustMultiplier); + ("damage", m_Damage); } //========================================================================== // // DEarthquake :: Tick // -// Deals damage to any players near the earthquake and makes sure it's +// Deals damage to any actors near the earthquake and makes sure it's // making noise. // //========================================================================== @@ -120,25 +129,29 @@ void DEarthquake::Tick () if (m_DamageRadius > 0) { - for (i = 0; i < MAXPLAYERS; i++) + if (m_Flags & QF_AFFECTACTORS) { - if (Level->PlayerInGame(i) && !(Level->Players[i]->cheats & CF_NOCLIP)) + FPortalGroupArray check(FPortalGroupArray::PGA_Full3d); + FMultiBlockThingsIterator it(check,m_Spot,m_DamageRadius,false); + FMultiBlockThingsIterator::CheckResult cres; + + while (it.Next(&cres)) { - AActor *victim = Level->Players[i]->mo; - double dist; + AActor *mo = cres.thing; + if (mo == nullptr || mo == m_Spot) //Ignore null references and the earthquake origin. + continue; - dist = m_Spot->Distance2D(victim, true); - // Check if in damage radius - if (dist < m_DamageRadius && victim->Z() <= victim->floorz) + DoQuakeDamage(this, mo, !!(m_Flags & QF_DAMAGEFALLOFF)); + } + } + else + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (Level->PlayerInGame(i) && !(Level->Players[i]->cheats & CF_NOCLIP)) { - if (pr_quake() < 50) - { - P_DamageMobj (victim, NULL, NULL, pr_quake.HitDice (1), NAME_Quake); - } - // Thrust player around - DAngle an = victim->Angles.Yaw + pr_quake(); - victim->Vel.X += m_Intensity.X * an.Cos() * 0.5; - victim->Vel.Y += m_Intensity.Y * an.Sin() * 0.5; + AActor* victim = Level->Players[i]->mo; + DoQuakeDamage(this, victim, !!(m_Flags & QF_DAMAGEFALLOFF)); } } } @@ -156,6 +169,50 @@ void DEarthquake::Tick () } } +//========================================================================== +// +// DEarthquake :: DoQuakeDamage +// +// Handles performing earthquake damage and thrust to the specified victim. +// +//========================================================================== + +void DEarthquake::DoQuakeDamage(DEarthquake *quake, AActor *victim, bool falloff) const +{ + double dist; + double thrustfalloff; + int damage; + + if (!quake || !victim) return; + + dist = quake->m_Spot->Distance2D(victim); + thrustfalloff = falloff ? GetFalloff(dist, m_DamageRadius) : 1.0; + // Check if in damage radius + if (dist < m_DamageRadius && victim->Z() <= victim->floorz) + { + if (!(quake->m_Flags & QF_SHAKEONLY) && pr_quake() < 50) + { + if (m_Damage < 1) + damage = falloff ? (int)(pr_quake.HitDice(1) * GetFalloff(dist, m_DamageRadius) * m_DamageMultiplier) : (int)(pr_quake.HitDice(1) * m_DamageMultiplier); + //[inkoalawetrust] Do the exact specified damage. + else + damage = falloff ? (int)(m_Damage * GetFalloff(dist, m_DamageRadius) * m_DamageMultiplier) : (int)(m_Damage * m_DamageMultiplier); + + damage = damage < 1 ? 1 : damage; //Do at least a tiny bit of damage when in radius. + + P_DamageMobj(victim, NULL, NULL, damage, NAME_Quake); + } + // Thrust pushable actor around + if (!(victim->flags7 & MF7_DONTTHRUST) && m_ThrustMultiplier > 0) + { + DAngle an = victim->Angles.Yaw + DAngle::fromDeg(pr_quake()); + victim->Vel.X += m_Intensity.X * an.Cos() * m_ThrustMultiplier * thrustfalloff; + victim->Vel.Y += m_Intensity.Y * an.Sin() * m_ThrustMultiplier * thrustfalloff; + } + } + return; +} + //========================================================================== // // DEarthquake :: GetModWave @@ -209,8 +266,8 @@ double DEarthquake::GetModIntensity(double intensity, bool fake) const { // Defaults to middle of the road. divider = m_CountdownStart; - scalar = (m_Flags & QF_MAX) ? MAX(m_Countdown, m_CountdownStart - m_Countdown) - : MIN(m_Countdown, m_CountdownStart - m_Countdown); + scalar = (m_Flags & QF_MAX) ? max(m_Countdown, m_CountdownStart - m_Countdown) + : min(m_Countdown, m_CountdownStart - m_Countdown); } scalar = (scalar > divider) ? divider : scalar; @@ -248,19 +305,19 @@ double DEarthquake::GetModIntensity(double intensity, bool fake) const // // DEarthquake :: GetFalloff // -// Given the distance of the player from the quake, find the multiplier. +// Given the distance of the actor from the quake, find the multiplier. // //========================================================================== -double DEarthquake::GetFalloff(double dist) const +double DEarthquake::GetFalloff(double dist, double radius) const { - if ((dist < m_Falloff) || (m_Falloff >= m_TremorRadius) || (m_Falloff <= 0) || (m_TremorRadius - m_Falloff <= 0)) - { //Player inside the minimum falloff range, or safety check kicked in. + if ((dist < m_Falloff) || (m_Falloff >= radius) || (m_Falloff <= 0) || (radius - m_Falloff <= 0)) + { //Actor inside the minimum falloff range, or safety check kicked in. return 1.; } - else if ((dist > m_Falloff) && (dist < m_TremorRadius)) - { //Player inside the radius, and outside the min distance for falloff. - double tremorsize = m_TremorRadius - m_Falloff; + else if ((dist > m_Falloff) && (dist < radius)) + { //Actor inside the radius, and outside the min distance for falloff. + double tremorsize = radius - m_Falloff; assert(tremorsize > 0); return (1. - ((dist - m_Falloff) / tremorsize)); } @@ -294,13 +351,17 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak while ( (quake = iterator.Next()) != nullptr) { - if (quake->m_Spot != nullptr) + if (quake->m_Spot != nullptr && !(quake->m_Flags & QF_GROUNDONLY && victim->Z() > victim->floorz)) { - const double dist = quake->m_Spot->Distance2D(victim, true); + double dist; + + if (quake->m_Flags & QF_3D) dist = quake->m_Spot->Distance3D(victim); + else dist = quake->m_Spot->Distance2D(victim); + if (dist < quake->m_TremorRadius) { ++count; - const double falloff = quake->GetFalloff(dist); + const double falloff = quake->GetFalloff(dist, quake->m_TremorRadius); const double r = quake->GetModIntensity(quake->m_RollIntensity); const double strength = quake->GetModIntensity(1.0, true); DVector3 intensity; @@ -310,20 +371,20 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak if (!(quake->m_Flags & QF_WAVE)) { - jiggers.RollIntensity = MAX(r, jiggers.RollIntensity) * falloff; + jiggers.RollIntensity = max(r, jiggers.RollIntensity) * falloff; intensity *= falloff; if (quake->m_Flags & QF_RELATIVE) { - jiggers.RelIntensity.X = MAX(intensity.X, jiggers.RelIntensity.X); - jiggers.RelIntensity.Y = MAX(intensity.Y, jiggers.RelIntensity.Y); - jiggers.RelIntensity.Z = MAX(intensity.Z, jiggers.RelIntensity.Z); + jiggers.RelIntensity.X = max(intensity.X, jiggers.RelIntensity.X); + jiggers.RelIntensity.Y = max(intensity.Y, jiggers.RelIntensity.Y); + jiggers.RelIntensity.Z = max(intensity.Z, jiggers.RelIntensity.Z); } else { - jiggers.Intensity.X = MAX(intensity.X, jiggers.Intensity.X); - jiggers.Intensity.Y = MAX(intensity.Y, jiggers.Intensity.Y); - jiggers.Intensity.Z = MAX(intensity.Z, jiggers.Intensity.Z); + jiggers.Intensity.X = max(intensity.X, jiggers.Intensity.X); + jiggers.Intensity.Y = max(intensity.Y, jiggers.Intensity.Y); + jiggers.Intensity.Z = max(intensity.Z, jiggers.Intensity.Z); } } else @@ -367,24 +428,24 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak // //========================================================================== -bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration, - int damrad, int tremrad, FSoundID quakesfx, int flags, - double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, - double rollIntensity, double rollWave) +bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double intensityX, double intensityY, double intensityZ, int duration, + double damrad, double tremrad, FSoundID quakesfx, int flags, + double waveSpeedX, double waveSpeedY, double waveSpeedZ, double falloff, int highpoint, + double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage) { AActor *center; bool res = false; - if (intensityX) intensityX = clamp(intensityX, 1, 9); - if (intensityY) intensityY = clamp(intensityY, 1, 9); - if (intensityZ) intensityZ = clamp(intensityZ, 1, 9); + intensityX = clamp(intensityX, 0.0, 9.0); + intensityY = clamp(intensityY, 0.0, 9.0); + intensityZ = clamp(intensityZ, 0.0, 9.0); if (tid == 0) { if (activator != NULL) { Level->CreateThinker(activator, intensityX, intensityY, intensityZ, duration, damrad, tremrad, - quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave); + quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave, damageMultiplier, thrustMultiplier, damage); return true; } } @@ -395,14 +456,14 @@ bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, int intens { res = true; Level->CreateThinker(center, intensityX, intensityY, intensityZ, duration, damrad, tremrad, - quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave); + quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave, damageMultiplier, thrustMultiplier, damage); } } return res; } -bool P_StartQuake(FLevelLocals *Level, AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx) +bool P_StartQuake(FLevelLocals * Level, AActor * activator, int tid, double intensity, int duration, double damrad, double tremrad, FSoundID quakesfx) { //Maintains original behavior by passing 0 to intensityZ, flags, and everything else after QSFX. - return P_StartQuakeXYZ(Level, activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0, 0, 0, 0, 0, 0, 0, 0); + return P_StartQuakeXYZ(Level, activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0.5, 0); } diff --git a/src/playsim/mapthinkers/a_scroll.cpp b/src/playsim/mapthinkers/a_scroll.cpp index c62aafe6f79..9ac20ccfb94 100644 --- a/src/playsim/mapthinkers/a_scroll.cpp +++ b/src/playsim/mapthinkers/a_scroll.cpp @@ -58,7 +58,8 @@ #include #include "actor.h" #include "p_spec.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "p_lnspec.h" #include "r_data/r_interpolate.h" #include "g_levellocals.h" @@ -104,8 +105,11 @@ void DScroller::Serialize(FSerializer &arc) ("vdx", m_vdx) ("vdy", m_vdy) ("accel", m_Accel) + ("affect", m_Affect) .Enum("parts", m_Parts) .Array("interpolations", m_Interpolations, 3); + + if (arc.isReading() && m_Affect == 0) m_Affect = SCROLL_All; } //----------------------------------------------------------------------------- @@ -118,7 +122,7 @@ void DScroller::Serialize(FSerializer &arc) static void RotationComp(const sector_t *sec, int which, double dx, double dy, double &tdx, double &tdy) { DAngle an = sec->GetAngle(which); - if (an == 0) + if (an == nullAngle) { tdx = dx; tdy = dy; @@ -217,11 +221,55 @@ void DScroller::Tick () // mark all potentially affected things here so that the very expensive calculation loop in AActor::Tick does not need to run for actors which do not touch a scrolling sector. for (auto n = m_Sector->touching_thinglist; n; n = n->m_snext) { + AActor* actor = n->m_thing; + if (actor->player) + { + if (!(m_Affect & SCROLL_Players)) + continue; + } + else if (actor->flags3 & MF3_ISMONSTER) + { + if (!(m_Affect & SCROLL_Monsters)) + continue; + } + else if (!(m_Affect & SCROLL_StaticObjects)) + continue; + n->m_thing->flags8 |= MF8_INSCROLLSEC; } break; - case EScroll::sc_carry_ceiling: // to be added later + case EScroll::sc_carry_ceiling: + // this just copies DSDA's implementation. Usability is limited. + for (auto n = m_Sector->touching_thinglist; n; n = n->m_snext) + { + AActor* actor = n->m_thing; + + if ( + !(actor->flags & MF_NOCLIP) && + actor->flags & MF_SPAWNCEILING && + actor->flags & MF_NOGRAVITY && + actor->Top() == m_Sector->ceilingplane.ZatPoint(actor->Pos().XY()) + ) + { + + if (actor->player) + { + if (!(m_Affect & SCROLL_Players)) + continue; + } + else if (actor->flags3 & MF3_ISMONSTER) + { + if (!(m_Affect & SCROLL_Monsters)) + continue; + } + else if (!(m_Affect & SCROLL_StaticObjects)) + continue; + + n->m_thing->Vel.X = m_dx; + n->m_thing->Vel.Y = m_dy; + } + } break; } } @@ -246,7 +294,7 @@ void DScroller::Tick () // //----------------------------------------------------------------------------- -void DScroller::Construct (EScroll type, double dx, double dy, sector_t *ctrl, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos) +void DScroller::Construct (EScroll type, double dx, double dy, sector_t *ctrl, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos, int aff) { m_Type = type; m_dx = dx; @@ -255,6 +303,7 @@ void DScroller::Construct (EScroll type, double dx, double dy, sector_t *ctrl, m_Parts = scrollpos; m_vdx = m_vdy = 0; m_LastHeight = 0; + m_Affect = aff; if ((m_Controller = ctrl) != nullptr) { m_LastHeight = m_Controller->CenterFloor() + m_Controller->CenterCeiling(); @@ -343,6 +392,7 @@ void DScroller::Construct(double dx, double dy, const line_t *l, sector_t * cont m_Accel = accel; m_Parts = scrollpos; m_LastHeight = 0; + m_Affect = SCROLL_All; // not really relevant, so use the default. if ((m_Controller = control) != nullptr) { m_LastHeight = m_Controller->CenterFloor() + m_Controller->CenterCeiling(); diff --git a/src/playsim/mapthinkers/a_scroll.h b/src/playsim/mapthinkers/a_scroll.h index 95d985117b5..f4d7c37966f 100644 --- a/src/playsim/mapthinkers/a_scroll.h +++ b/src/playsim/mapthinkers/a_scroll.h @@ -1,5 +1,14 @@ #pragma once +enum EScrollAffect +{ + SCROLL_Textures = 1, + SCROLL_StaticObjects = 2, + SCROLL_Players = 4, + SCROLL_Monsters = 8, + SCROLL_All = 15 +}; + //----------------------------------------------------------------------------- // // killough 3/7/98: Add generalized scroll effects @@ -13,7 +22,7 @@ class DScroller : public DThinker public: static const int DEFAULT_STAT = STAT_SCROLLER; - void Construct(EScroll type, double dx, double dy, sector_t *control, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos = EScrollPos::scw_all); + void Construct(EScroll type, double dx, double dy, sector_t *control, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos = EScrollPos::scw_all, int aff = SCROLL_All); void Construct(double dx, double dy, const line_t *l, sector_t *control, int accel, EScrollPos scrollpos = EScrollPos::scw_all); void OnDestroy() override; @@ -29,6 +38,7 @@ class DScroller : public DThinker protected: EScroll m_Type; // Type of scroll effect + int m_Affect; double m_dx, m_dy; // (dx,dy) scroll speeds sector_t *m_Sector; // Affected sector side_t *m_Side; // ... or side diff --git a/src/playsim/mapthinkers/a_thruster.cpp b/src/playsim/mapthinkers/a_thruster.cpp new file mode 100644 index 00000000000..ca052678bdf --- /dev/null +++ b/src/playsim/mapthinkers/a_thruster.cpp @@ -0,0 +1,155 @@ +//----------------------------------------------------------------------------- +// +// Copyright 2023 Ryan Krafnick +// Copyright 2023 Christoph Oelckers +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// UDMF-style thruster +// +//----------------------------------------------------------------------------- + + +#include +#include "actor.h" +#include "p_spec.h" +#include "serializer.h" +#include "serializer_doom.h" +#include "p_spec_thinkers.h" + +EXTERN_CVAR(Bool, var_pushers); + +IMPLEMENT_CLASS(DThruster, false, false) + +enum +{ + THRUST_STATIC = 0x01, + THRUST_PLAYER = 0x02, + THRUST_MONSTER = 0x04, + THRUST_PROJECTILE = 0x08, + THRUST_WINDTHRUST = 0x10, + + THRUST_GROUNDED = 1, + THRUST_AIRBORNE = 2, + THRUST_CEILING = 4 +}; + + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void DThruster::Serialize(FSerializer &arc) +{ + Super::Serialize (arc); + arc("type", m_Type) + ("location", m_Location) + ("pushvec", m_PushVec) + ("sector", m_Sector); +} + + +//----------------------------------------------------------------------------- +// +// Add a thrust thinker to the thinker list +// +//----------------------------------------------------------------------------- + +void DThruster::Construct(sector_t* sec, double dx, double dy, int type, int location) +{ + m_Type = type; + m_Location = location; + m_Sector = sec; + m_PushVec = { dx, dy }; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void DThruster::Tick () +{ + sector_t* sec = m_Sector; + + if (m_PushVec.isZero()) + return; + + for (auto node = sec->touching_thinglist; node; node = node->m_snext) + { + bool thrust_it = false; + AActor* thing = node->m_thing; + + if (thing->flags & MF_NOCLIP) + continue; + + if (!(thing->flags & MF_NOGRAVITY) && thing->Z() <= thing->floorz) + { + if (m_Location & THRUST_GROUNDED) + thrust_it = true; + } + else if ( + thing->flags & MF_SPAWNCEILING && + thing->flags & MF_NOGRAVITY && + thing->Top() == thing->ceilingz + ) + { + if (m_Location & THRUST_CEILING) + thrust_it = true; + } + else if (thing->flags & MF_NOGRAVITY || thing->Z() > thing->floorz) + { + if (m_Location & THRUST_AIRBORNE) + thrust_it = true; + } + + if (thrust_it) + { + thrust_it = false; + + if (thing->flags2 & MF2_WINDTHRUST && m_Type & THRUST_WINDTHRUST) + thrust_it = true; + else if (thing->flags3 & MF3_ISMONSTER) + { + if (m_Type & THRUST_MONSTER) + thrust_it = true; + } + else if (thing->player) + { + if (m_Type & THRUST_PLAYER) + thrust_it = true; + } + else if (thing->flags & MF_MISSILE) + { + if (m_Type & THRUST_PROJECTILE) + thrust_it = true; + } + else + { + if (m_Type & THRUST_STATIC) + thrust_it = true; + } + + if (thrust_it) + { + thing->Vel += m_PushVec; + } + } + } +} + diff --git a/src/playsim/mapthinkers/dsectoreffect.cpp b/src/playsim/mapthinkers/dsectoreffect.cpp index 8fbf3c8a78d..e14f628b4f4 100644 --- a/src/playsim/mapthinkers/dsectoreffect.cpp +++ b/src/playsim/mapthinkers/dsectoreffect.cpp @@ -30,7 +30,8 @@ #include "g_levellocals.h" #include "p_3dmidtex.h" #include "r_data/r_interpolate.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "doomstat.h" #include "vm.h" @@ -318,7 +319,7 @@ EMoveResult sector_t::MoveCeiling(double speed, double dest, int crush, int dire ceilingplane.setD(dest); flag = P_ChangeSector (this, crush, move, 1, false); - if (flag) + if (flag && !(crush >= 0 && !hexencrush && movedest == dest)) { ceilingplane.setD(lastpos); P_ChangeSector (this, crush, -move, 1, true); diff --git a/src/playsim/mapthinkers/dsectoreffect.h b/src/playsim/mapthinkers/dsectoreffect.h index cbaff9efcfd..36270235144 100644 --- a/src/playsim/mapthinkers/dsectoreffect.h +++ b/src/playsim/mapthinkers/dsectoreffect.h @@ -22,7 +22,7 @@ class DSectorEffect : public DThinker class DMover : public DSectorEffect { - DECLARE_ABSTRACT_CLASS (DMover, DSectorEffect) + DECLARE_CLASS (DMover, DSectorEffect) HAS_OBJECT_POINTERS protected: void Construct(sector_t *sector); @@ -39,14 +39,14 @@ class DMover : public DSectorEffect class DMovingFloor : public DMover { - DECLARE_ABSTRACT_CLASS (DMovingFloor, DMover) + DECLARE_CLASS (DMovingFloor, DMover) protected: void Construct(sector_t *sector); }; class DMovingCeiling : public DMover { - DECLARE_ABSTRACT_CLASS (DMovingCeiling, DMover) + DECLARE_CLASS (DMovingCeiling, DMover) protected: void Construct(sector_t *sector, bool interpolate = true); }; diff --git a/src/playsim/p_3dfloors.cpp b/src/playsim/p_3dfloors.cpp index 4f8a5d961f9..dd5a2bb0a7e 100644 --- a/src/playsim/p_3dfloors.cpp +++ b/src/playsim/p_3dfloors.cpp @@ -35,11 +35,11 @@ ** */ -#include "templates.h" + #include "p_local.h" #include "p_lnspec.h" #include "p_maputl.h" -#include "w_wad.h" +#include "filesystem.h" #include "g_level.h" #include "p_terrain.h" #include "d_player.h" @@ -217,10 +217,11 @@ void P_PlayerOnSpecial3DFloor(player_t* player) // Player must be on top of the floor to be affected... if(player->mo->Z() != rover->top.plane->ZatPoint(player->mo)) continue; } - else + else { //Water and DEATH FOG!!! heh - if (player->mo->Z() > rover->top.plane->ZatPoint(player->mo) || + if ((rover->flags & FF_NODAMAGE) || + player->mo->Z() > rover->top.plane->ZatPoint(player->mo) || player->mo->Top() < rover->bottom.plane->ZatPoint(player->mo)) continue; } @@ -779,7 +780,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li double low1 = (open.lowfloorthroughportal & 1) ? open.lowfloor : lowestfloor[0]; double low2 = (open.lowfloorthroughportal & 2) ? open.lowfloor : lowestfloor[1]; - open.lowfloor = MIN(low1, low2); + open.lowfloor = min(low1, low2); } } } diff --git a/src/playsim/p_3dfloors.h b/src/playsim/p_3dfloors.h index f0b1e87fd92..05d222137e9 100644 --- a/src/playsim/p_3dfloors.h +++ b/src/playsim/p_3dfloors.h @@ -23,7 +23,7 @@ typedef enum FF_UPPERTEXTURE = 0x20000, FF_LOWERTEXTURE = 0x40000, FF_THINFLOOR = 0x80000, // EDGE - FF_SCROLLY = 0x100000, // EDGE - not yet implemented!!! + FF_NODAMAGE = 0x100000, // no damage transfers FF_FIX = 0x200000, // use floor of model sector as floor and floor of real sector as ceiling FF_INVERTSECTOR = 0x400000, // swap meaning of sector planes FF_DYNAMIC = 0x800000, // created by partitioning another 3D-floor due to overlap diff --git a/src/playsim/p_3dmidtex.cpp b/src/playsim/p_3dmidtex.cpp index be5ab900067..0e2d7e10dfb 100644 --- a/src/playsim/p_3dmidtex.cpp +++ b/src/playsim/p_3dmidtex.cpp @@ -35,7 +35,7 @@ */ -#include "templates.h" + #include "p_3dmidtex.h" #include "p_local.h" #include "p_terrain.h" @@ -43,6 +43,8 @@ #include "p_spec.h" #include "g_levellocals.h" #include "actor.h" +#include "texturemanager.h" +#include "vm.h" //============================================================================ @@ -230,7 +232,7 @@ bool P_GetMidTexturePosition(const line_t *line, int sideno, double *ptextop, do side_t *side = line->sidedef[sideno]; FTextureID texnum = side->GetTexture(side_t::mid); if (!texnum.isValid()) return false; - FTexture * tex= TexMan.GetTexture(texnum, true); + FGameTexture * tex= TexMan.GetGameTexture(texnum, true); if (!tex) return false; FTexCoordInfo tci; @@ -243,20 +245,34 @@ bool P_GetMidTexturePosition(const line_t *line, int sideno, double *ptextop, do if(line->flags & ML_DONTPEGBOTTOM) { *ptexbot = y_offset + - MAX(line->frontsector->GetPlaneTexZ(sector_t::floor), line->backsector->GetPlaneTexZ(sector_t::floor)); + max(line->frontsector->GetPlaneTexZ(sector_t::floor), line->backsector->GetPlaneTexZ(sector_t::floor)); *ptextop = *ptexbot + textureheight; } else { *ptextop = y_offset + - MIN(line->frontsector->GetPlaneTexZ(sector_t::ceiling), line->backsector->GetPlaneTexZ(sector_t::ceiling)); + min(line->frontsector->GetPlaneTexZ(sector_t::ceiling), line->backsector->GetPlaneTexZ(sector_t::ceiling)); *ptexbot = *ptextop - textureheight; } return true; } +DEFINE_ACTION_FUNCTION(_Line, GetMidTexturePosition) +{ + PARAM_SELF_STRUCT_PROLOGUE(line_t); + PARAM_INT(side); + double top = 0.0; + double bottom = 0.0; + + bool res = P_GetMidTexturePosition(self,side,&top,&bottom); + if (numret > 2) ret[2].SetFloat(bottom); + if (numret > 1) ret[1].SetFloat(top); + if (numret > 0) ret[0].SetInt(int(res)); + return numret; +} + //============================================================================ // // P_LineOpening_3dMidtex diff --git a/src/playsim/p_acs.cpp b/src/playsim/p_acs.cpp index dca86a7c87c..d05f5dae3b5 100644 --- a/src/playsim/p_acs.cpp +++ b/src/playsim/p_acs.cpp @@ -51,7 +51,7 @@ #include "s_sndseq.h" #include "sbar.h" #include "a_sharedglobal.h" -#include "w_wad.h" +#include "filesystem.h" #include "r_sky.h" #include "gstrings.h" #include "gi.h" @@ -62,7 +62,8 @@ #include "p_setup.h" #include "po_man.h" #include "actorptrselect.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "decallib.h" #include "p_terrain.h" #include "version.h" @@ -75,6 +76,8 @@ #include "types.h" #include "scriptutil.h" #include "s_music.h" +#include "v_video.h" +#include "texturemanager.h" // P-codes for ACS scripts enum @@ -532,6 +535,7 @@ PLAYERINFO_PLAYERCLASS, PLAYERINFO_FOV, PLAYERINFO_DESIREDFOV, + PLAYERINFO_FVIEWBOB, }; @@ -566,6 +570,8 @@ FRandom pr_acs ("ACS"); // SpawnDecal flags #define SDF_ABSANGLE 1 #define SDF_PERMANENT 2 +#define SDF_FIXED_ZOFF 4 +#define SDF_FIXED_DISTANCE 8 // GetArmorInfo enum @@ -610,17 +616,17 @@ inline int DoubleToACS(double val) inline DAngle ACSToAngle(int acsval) { - return acsval * (360. / 65536.); + return DAngle::fromQ16(acsval); } inline int AngleToACS(DAngle ang) { - return ang.BAMs() >> 16; + return ang.Normalized360().Q16(); } inline int PitchToACS(DAngle ang) { - return int(ang.Normalized180().Degrees * (65536. / 360)); + return ang.Normalized180().Q16(); } struct CallReturn @@ -742,7 +748,7 @@ class DLevelScript : public DObject int DoSpawnSpot(int type, int spot, int tid, int angle, bool forced); int DoSpawnSpotFacing(int type, int spot, int tid, bool forced); int DoClassifyActor(int tid); - int CallFunction(int argCount, int funcIndex, int32_t *args); + int CallFunction(int argCount, int funcIndex, int32_t *args, int &needCount); void DoFadeTo(int r, int g, int b, int a, int time); void DoFadeRange(int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2, int time); @@ -973,7 +979,7 @@ int ACSStringPool::AddString(FString &str) { unsigned int h = SuperFastHash(str.GetChars(), str.Len()); unsigned int bucketnum = h % NUM_BUCKETS; - int i = FindString(str, str.Len(), h, bucketnum); + int i = FindString(str.GetChars(), str.Len(), h, bucketnum); if (i >= 0) { return i | STRPOOL_LIBRARYID_OR; @@ -993,7 +999,7 @@ const char *ACSStringPool::GetString(int strnum) strnum &= ~LIBRARYID_MASK; if ((unsigned)strnum < Pool.Size() && Pool[strnum].Next != FREE_ENTRY) { - return Pool[strnum].Str; + return Pool[strnum].Str.GetChars(); } return NULL; } @@ -1293,7 +1299,7 @@ void ACSStringPool::ReadStrings(FSerializer &file, const char *key) file("string", Pool[ii].Str) ("locks", Pool[ii].Locks); - unsigned h = SuperFastHash(Pool[ii].Str, Pool[ii].Str.Len()); + unsigned h = SuperFastHash(Pool[ii].Str.GetChars(), Pool[ii].Str.Len()); unsigned bucketnum = h % NUM_BUCKETS; Pool[ii].Hash = h; Pool[ii].Next = PoolBuckets[bucketnum]; @@ -1589,7 +1595,7 @@ static void WriteArrayVars (FSerializer &file, FWorldGlobalArray *vars, unsigned FString arraykey; arraykey.Format("%d", i); - if (file.BeginObject(arraykey)) + if (file.BeginObject(arraykey.GetChars())) { FWorldGlobalArray::ConstIterator it(vars[i]); const FWorldGlobalArray::Pair *pair; @@ -1871,7 +1877,6 @@ void DPlaneWatcher::Serialize(FSerializer &arc) { Super::Serialize (arc); arc("special", Special) - .Args("args", Args, nullptr, Special) ("sector", Sector) ("ceiling", bCeiling) ("watchd", WatchD) @@ -1880,6 +1885,7 @@ void DPlaneWatcher::Serialize(FSerializer &arc) ("line", Line) ("lineside", LineSide); + SerializeArgs(arc, "args", Args, nullptr, Special); } void DPlaneWatcher::Tick () @@ -1919,12 +1925,12 @@ void FBehaviorContainer::LoadDefaultModules () // Scan each LOADACS lump and load the specified modules in order int lump, lastlump = 0; - while ((lump = Wads.FindLump ("LOADACS", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("LOADACS", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString()) { - int acslump = Wads.CheckNumForName (sc.String, ns_acslibrary); + int acslump = fileSystem.CheckNumForName (sc.String, FileSys::ns_acslibrary); if (acslump >= 0) { LoadModule (acslump); @@ -1957,7 +1963,7 @@ FBehavior *FBehaviorContainer::LoadModule (int lumpnum, FileReader *fr, int len, else { delete behavior; - Printf(TEXTCOLOR_RED "%s: invalid ACS module\n", Wads.GetLumpFullName(lumpnum)); + Printf(TEXTCOLOR_RED "%s: invalid ACS module\n", fileSystem.GetFileFullName(lumpnum)); return NULL; } } @@ -2223,7 +2229,7 @@ bool FBehavior::Init(FLevelLocals *Level, int lumpnum, FileReader * fr, int len, // 2. Corrupt modules won't be reported when a level is being loaded if this function quits before // adding it to the list. - if (fr == NULL) len = Wads.LumpLength (lumpnum); + if (fr == NULL) len = fileSystem.FileLength (lumpnum); @@ -2239,7 +2245,7 @@ bool FBehavior::Init(FLevelLocals *Level, int lumpnum, FileReader * fr, int len, object = new uint8_t[len]; if (fr == NULL) { - Wads.ReadLump (lumpnum, object); + fileSystem.ReadFile (lumpnum, object); } else { @@ -2271,8 +2277,7 @@ bool FBehavior::Init(FLevelLocals *Level, int lumpnum, FileReader * fr, int len, if (fr == NULL) { - Wads.GetLumpName (ModuleName, lumpnum); - ModuleName[8] = 0; + strcpy(ModuleName, fileSystem.GetFileShortName (lumpnum)); } else { @@ -2316,8 +2321,8 @@ bool FBehavior::Init(FLevelLocals *Level, int lumpnum, FileReader * fr, int len, // If this is an original Hexen BEHAVIOR, set up some localization info for it. Original Hexen BEHAVIORs are always in the old format. if ((Level->flags2 & LEVEL2_HEXENHACK) && gameinfo.gametype == GAME_Hexen && lumpnum == -1 && reallumpnum > 0) { - int fileno = Wads.GetLumpFile(reallumpnum); - const char * filename = Wads.GetWadName(fileno); + int fileno = fileSystem.GetFileContainer(reallumpnum); + const char * filename = fileSystem.GetResourceFileName(fileno); if (!stricmp(filename, "HEXEN.WAD") || !stricmp(filename, "HEXDD.WAD")) { ShouldLocalize = true; @@ -2449,7 +2454,7 @@ bool FBehavior::Init(FLevelLocals *Level, int lumpnum, FileReader * fr, int len, // Use unsigned iterator here to avoid issue with GCC 4.9/5.x // optimizer. Might be some undefined behavior in this code, // but I don't know what it is. - unsigned int initsize = MIN (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4); + unsigned int initsize = min (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4); int32_t *elems = ArrayStore[arraynum].Elements; for (unsigned int j = 0; j < initsize; ++j) { @@ -2527,7 +2532,7 @@ bool FBehavior::Init(FLevelLocals *Level, int lumpnum, FileReader * fr, int len, { int32_t *elems = ArrayStore[arraynum].Elements; // Ending zeros may be left out. - for (int j = MIN(LittleLong(chunk[1])-5, ArrayStore[arraynum].ArraySize); j > 0; --j, ++elems, ++chunkData) + for (int j = min(LittleLong(chunk[1])-5, ArrayStore[arraynum].ArraySize); j > 0; --j, ++elems, ++chunkData) { // For ATAG, a value of 0 = Integer, 1 = String, 2 = FunctionPtr // Our implementation uses the same tags for both String and FunctionPtr @@ -2562,7 +2567,7 @@ bool FBehavior::Init(FLevelLocals *Level, int lumpnum, FileReader * fr, int len, if (parse[i]) { FBehavior *module = NULL; - int lump = Wads.CheckNumForName (&parse[i], ns_acslibrary); + int lump = fileSystem.CheckNumForName (&parse[i], FileSys::ns_acslibrary); if (lump < 0) { Printf (TEXTCOLOR_RED "Could not find ACS library %s.\n", &parse[i]); @@ -2837,7 +2842,7 @@ void FBehavior::LoadScriptsDirectory () // Make the closed version the first one. if (Scripts[i+1].Type == SCRIPT_Closed) { - swapvalues(Scripts[i], Scripts[i+1]); + std::swap(Scripts[i], Scripts[i+1]); } } } @@ -2908,7 +2913,7 @@ void FBehavior::LoadScriptsDirectory () { const char *str = (const char *)(scripts.b + 8 + scripts.dw[3 + (-Scripts[i].Number - 1)]); FName name(str); - Scripts[i].Number = -name; + Scripts[i].Number = -name.GetIndex(); } } // We need to resort scripts, because the new numbers for named scripts likely @@ -3243,7 +3248,7 @@ const char *FBehavior::LookupString (uint32_t index, bool forprint) const token.Truncate(5); FStringf label("TXT_ACS_%s_%d_%.5s", Level->MapName.GetChars(), index, token.GetChars()); - auto p = GStrings[label]; + auto p = GStrings.CheckString(label.GetChars()); if (p) return p; } @@ -3584,7 +3589,7 @@ int DLevelScript::Random (int min, int max) { if (max < min) { - swapvalues (max, min); + std::swap (max, min); } return min + pr_acs(max - min + 1); @@ -3786,7 +3791,7 @@ int DLevelScript::DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle, int DLevelScript::DoSpawn(int type, int x, int y, int z, int tid, int angle, bool force) { - return DoSpawn(type, DVector3(ACSToDouble(x), ACSToDouble(y), ACSToDouble(z)), tid, angle * (360. / 256), force); + return DoSpawn(type, DVector3(ACSToDouble(x), ACSToDouble(y), ACSToDouble(z)), tid, DAngle::fromDeg(angle * (360. / 256)), force); } @@ -3801,12 +3806,12 @@ int DLevelScript::DoSpawnSpot (int type, int spot, int tid, int angle, bool forc while ( (aspot = iterator.Next ()) ) { - spawned += DoSpawn (type, aspot->Pos(), tid, angle * (360. / 256), force); + spawned += DoSpawn (type, aspot->Pos(), tid, DAngle::fromDeg(angle * (360. / 256)), force); } } else if (activator != NULL) { - spawned += DoSpawn (type, activator->Pos(), tid, angle * (360. / 256), force); + spawned += DoSpawn (type, activator->Pos(), tid, DAngle::fromDeg(angle * (360. / 256)), force); } return spawned; } @@ -3992,53 +3997,56 @@ int DoGetMasterTID (AActor *self) enum { - APROP_Health = 0, - APROP_Speed = 1, - APROP_Damage = 2, - APROP_Alpha = 3, - APROP_RenderStyle = 4, - APROP_SeeSound = 5, // Sounds can only be set, not gotten - APROP_AttackSound = 6, - APROP_PainSound = 7, - APROP_DeathSound = 8, - APROP_ActiveSound = 9, - APROP_Ambush = 10, - APROP_Invulnerable = 11, - APROP_JumpZ = 12, // [GRB] - APROP_ChaseGoal = 13, - APROP_Frightened = 14, - APROP_Gravity = 15, - APROP_Friendly = 16, - APROP_SpawnHealth = 17, - APROP_Dropped = 18, - APROP_Notarget = 19, - APROP_Species = 20, - APROP_NameTag = 21, - APROP_Score = 22, - APROP_Notrigger = 23, - APROP_DamageFactor = 24, - APROP_MasterTID = 25, - APROP_TargetTID = 26, - APROP_TracerTID = 27, - APROP_WaterLevel = 28, - APROP_ScaleX = 29, - APROP_ScaleY = 30, - APROP_Dormant = 31, - APROP_Mass = 32, - APROP_Accuracy = 33, - APROP_Stamina = 34, - APROP_Height = 35, - APROP_Radius = 36, - APROP_ReactionTime = 37, - APROP_MeleeRange = 38, - APROP_ViewHeight = 39, - APROP_AttackZOffset = 40, - APROP_StencilColor = 41, - APROP_Friction = 42, - APROP_DamageMultiplier=43, - APROP_MaxStepHeight = 44, - APROP_MaxDropOffHeight= 45, - APROP_DamageType = 46, + APROP_Health = 0, + APROP_Speed = 1, + APROP_Damage = 2, + APROP_Alpha = 3, + APROP_RenderStyle = 4, + APROP_SeeSound = 5, // Sounds can only be set, not gotten + APROP_AttackSound = 6, + APROP_PainSound = 7, + APROP_DeathSound = 8, + APROP_ActiveSound = 9, + APROP_Ambush = 10, + APROP_Invulnerable = 11, + APROP_JumpZ = 12, // [GRB] + APROP_ChaseGoal = 13, + APROP_Frightened = 14, + APROP_Gravity = 15, + APROP_Friendly = 16, + APROP_SpawnHealth = 17, + APROP_Dropped = 18, + APROP_Notarget = 19, + APROP_Species = 20, + APROP_NameTag = 21, + APROP_Score = 22, + APROP_Notrigger = 23, + APROP_DamageFactor = 24, + APROP_MasterTID = 25, + APROP_TargetTID = 26, + APROP_TracerTID = 27, + APROP_WaterLevel = 28, + APROP_ScaleX = 29, + APROP_ScaleY = 30, + APROP_Dormant = 31, + APROP_Mass = 32, + APROP_Accuracy = 33, + APROP_Stamina = 34, + APROP_Height = 35, + APROP_Radius = 36, + APROP_ReactionTime = 37, + APROP_MeleeRange = 38, + APROP_ViewHeight = 39, + APROP_AttackZOffset = 40, + APROP_StencilColor = 41, + APROP_Friction = 42, + APROP_DamageMultiplier = 43, + APROP_MaxStepHeight = 44, + APROP_MaxDropOffHeight = 45, + APROP_DamageType = 46, + APROP_SoundClass = 47, + APROP_FriendlySeeBlocks = 48, + APROP_WaterDepth = 49, }; // These are needed for ACS's APROP_RenderStyle @@ -4193,23 +4201,23 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) break; case APROP_SeeSound: - actor->SeeSound = Level->Behaviors.LookupString(value); + actor->SeeSound = S_FindSound(Level->Behaviors.LookupString(value)); break; case APROP_AttackSound: - actor->AttackSound = Level->Behaviors.LookupString(value); + actor->AttackSound = S_FindSound(Level->Behaviors.LookupString(value)); break; case APROP_PainSound: - actor->PainSound = Level->Behaviors.LookupString(value); + actor->PainSound = S_FindSound(Level->Behaviors.LookupString(value)); break; case APROP_DeathSound: - actor->DeathSound = Level->Behaviors.LookupString(value); + actor->DeathSound = S_FindSound(Level->Behaviors.LookupString(value)); break; case APROP_ActiveSound: - actor->ActiveSound = Level->Behaviors.LookupString(value); + actor->ActiveSound = S_FindSound(Level->Behaviors.LookupString(value)); break; case APROP_Species: @@ -4239,11 +4247,11 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) break; case APROP_ScaleX: - actor->Scale.X = ACSToDouble(value); + actor->Scale.X = (float)ACSToDouble(value); break; case APROP_ScaleY: - actor->Scale.Y = ACSToDouble(value); + actor->Scale.Y = (float)ACSToDouble(value); break; case APROP_Mass: @@ -4302,6 +4310,19 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) actor->DamageType = Level->Behaviors.LookupString(value); break; + case APROP_SoundClass: + if (actor->IsKindOf(NAME_PlayerPawn)) + { + if (actor->player != nullptr) + { + actor->player->SoundClass = Level->Behaviors.LookupString(value); + } + } + break; + case APROP_FriendlySeeBlocks: + actor->friendlyseeblocks = value; + break; + default: // do nothing. break; @@ -4392,13 +4413,16 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_PainSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->PainSound)); case APROP_DeathSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->DeathSound)); case APROP_ActiveSound: return GlobalACSStrings.AddString(S_GetSoundName(actor->ActiveSound)); - case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies()); + case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies().GetChars()); case APROP_NameTag: return GlobalACSStrings.AddString(actor->GetTag()); case APROP_StencilColor:return actor->fillcolor; case APROP_Friction: return DoubleToACS(actor->Friction); case APROP_MaxStepHeight: return DoubleToACS(actor->MaxStepHeight); case APROP_MaxDropOffHeight: return DoubleToACS(actor->MaxDropOffHeight); - case APROP_DamageType: return GlobalACSStrings.AddString(actor->DamageType); + case APROP_DamageType: return GlobalACSStrings.AddString(actor->DamageType.GetChars()); + case APROP_SoundClass: return GlobalACSStrings.AddString(S_GetSoundClass(actor)); + case APROP_FriendlySeeBlocks: return actor->friendlyseeblocks; + case APROP_WaterDepth: return DoubleToACS(actor->waterdepth); default: return 0; } @@ -4448,6 +4472,8 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_MaxStepHeight: case APROP_MaxDropOffHeight: case APROP_StencilColor: + case APROP_FriendlySeeBlocks: + case APROP_WaterDepth: return (GetActorProperty(tid, property) == value); // Boolean values need to compare to a binary version of value @@ -4469,9 +4495,10 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_PainSound: string = S_GetSoundName(actor->PainSound); break; case APROP_DeathSound: string = S_GetSoundName(actor->DeathSound); break; case APROP_ActiveSound: string = S_GetSoundName(actor->ActiveSound); break; - case APROP_Species: string = actor->GetSpecies(); break; + case APROP_Species: string = actor->GetSpecies().GetChars(); break; case APROP_NameTag: string = actor->GetTag(); break; - case APROP_DamageType: string = actor->DamageType; break; + case APROP_DamageType: string = actor->DamageType.GetChars(); break; + case APROP_SoundClass: string = S_GetSoundClass(actor); break; } if (string == NULL) string = ""; return (!stricmp(string, Level->Behaviors.LookupString(value))); @@ -4631,6 +4658,7 @@ enum SOUND_WallBounce, SOUND_CrushPain, SOUND_Howl, + SOUND_Push, }; static FSoundID GetActorSound(AActor *actor, int soundtype) @@ -4647,7 +4675,8 @@ static FSoundID GetActorSound(AActor *actor, int soundtype) case SOUND_WallBounce: return actor->WallBounceSound; case SOUND_CrushPain: return actor->CrushPainSound; case SOUND_Howl: return actor->SoundVar(NAME_HowlSound); - default: return 0; + case SOUND_Push: return actor->SoundVar(NAME_PushSound); + default: return NO_SOUND; } } @@ -4776,6 +4805,7 @@ enum EACSFunctions ACSF_StartSlideshow, ACSF_GetSectorHealth, ACSF_GetLineHealth, + ACSF_SetSubtitleNumber, // Eternity's ACSF_GetLineX = 300, @@ -5148,7 +5178,7 @@ int DLevelScript::SwapActorTeleFog(AActor *activator, int tid) if ((activator == NULL) || (activator->TeleFogSourceType == activator->TeleFogDestType)) return 0; //Does nothing if they're the same. - swapvalues (activator->TeleFogSourceType, activator->TeleFogDestType); + std::swap (activator->TeleFogSourceType, activator->TeleFogDestType); return 1; } else @@ -5161,7 +5191,7 @@ int DLevelScript::SwapActorTeleFog(AActor *activator, int tid) if (actor->TeleFogSourceType == actor->TeleFogDestType) continue; //They're the same. Save the effort. - swapvalues (actor->TeleFogSourceType, actor->TeleFogDestType); + std::swap (actor->TeleFogSourceType, actor->TeleFogDestType); count++; } } @@ -5232,7 +5262,7 @@ int DLevelScript::SwapActorTeleFog(AActor *activator, int tid) } else if (argtype == TypeSound) { - params.Push(int(FSoundID(Level->Behaviors.LookupString(args[i])))); + params.Push(S_FindSound(Level->Behaviors.LookupString(args[i])).index()); } else { @@ -5258,14 +5288,14 @@ int DLevelScript::SwapActorTeleFog(AActor *activator, int tid) if (rettype == TypeSInt32 || rettype == TypeBool || rettype == TypeColor || rettype == TypeName || rettype == TypeSound) { VMReturn ret(&retval); - VMCall(func, ¶ms[0], params.Size(), &ret, 1); + VMCallWithDefaults(func, params, &ret, 1); if (rettype == TypeName) { - retval = GlobalACSStrings.AddString(FName(ENamedName(retval))); + retval = GlobalACSStrings.AddString(FName(ENamedName(retval)).GetChars()); } else if (rettype == TypeSound) { - retval = GlobalACSStrings.AddString(S_GetSoundName(FSoundID(retval))); + retval = GlobalACSStrings.AddString(S_GetSoundName(FSoundID::fromInt(retval))); } } else if (rettype == TypeFloat64) @@ -5292,46 +5322,66 @@ int DLevelScript::SwapActorTeleFog(AActor *activator, int tid) return retval; } -int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) +// Macro for CallFunction. Checks passed number of arguments with minimum required. Sets needCount and returns if not enough. +#define MIN_ARG_COUNT(minCount) \ + do { \ + if (argCount < minCount && !(Level->i_compatflags2 & COMPATF2_NOACSARGCHECK)) { \ + needCount = minCount; \ + return 0; \ + } \ + } while(0) + +int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args, int &needCount) { AActor *actor; switch(funcIndex) { case ACSF_GetLineUDMFInt: + MIN_ARG_COUNT(2); return GetUDMFInt(Level, UDMF_Line, LineFromID(args[0]), Level->Behaviors.LookupString(args[1])); case ACSF_GetLineUDMFFixed: + MIN_ARG_COUNT(2); return DoubleToACS(GetUDMFFloat(Level, UDMF_Line, LineFromID(args[0]), Level->Behaviors.LookupString(args[1]))); case ACSF_GetThingUDMFInt: case ACSF_GetThingUDMFFixed: + MIN_ARG_COUNT(2); return 0; // Not implemented yet case ACSF_GetSectorUDMFInt: + MIN_ARG_COUNT(2); return GetUDMFInt(Level, UDMF_Sector, Level->FindFirstSectorFromTag(args[0]), Level->Behaviors.LookupString(args[1])); case ACSF_GetSectorUDMFFixed: + MIN_ARG_COUNT(2); return DoubleToACS(GetUDMFFloat(Level, UDMF_Sector, Level->FindFirstSectorFromTag(args[0]), Level->Behaviors.LookupString(args[1]))); case ACSF_GetSideUDMFInt: + MIN_ARG_COUNT(3); return GetUDMFInt(Level, UDMF_Side, SideFromID(args[0], args[1]), Level->Behaviors.LookupString(args[2])); case ACSF_GetSideUDMFFixed: + MIN_ARG_COUNT(3); return DoubleToACS(GetUDMFFloat(Level, UDMF_Side, SideFromID(args[0], args[1]), Level->Behaviors.LookupString(args[2]))); case ACSF_GetActorVelX: + MIN_ARG_COUNT(1); actor = Level->SingleActorFromTID(args[0], activator); return actor != NULL? DoubleToACS(actor->Vel.X) : 0; case ACSF_GetActorVelY: + MIN_ARG_COUNT(1); actor = Level->SingleActorFromTID(args[0], activator); return actor != NULL? DoubleToACS(actor->Vel.Y) : 0; case ACSF_GetActorVelZ: + MIN_ARG_COUNT(1); actor = Level->SingleActorFromTID(args[0], activator); return actor != NULL? DoubleToACS(actor->Vel.Z) : 0; case ACSF_SetPointer: + MIN_ARG_COUNT(2); if (activator) { AActor *ptr = Level->SingleActorFromTID(args[1], activator); @@ -5346,6 +5396,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) return 0; case ACSF_SetActivator: + MIN_ARG_COUNT(1); if (argCount > 1 && args[1] != AAPTR_DEFAULT) // condition (x != AAPTR_DEFAULT) is essentially condition (x). { activator = COPY_AAPTREX(Level, Level->SingleActorFromTID(args[0], activator), args[1]); @@ -5357,6 +5408,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) return activator != NULL; case ACSF_SetActivatorToTarget: + MIN_ARG_COUNT(1); // [KS] I revised this a little bit actor = Level->SingleActorFromTID(args[0], activator); if (actor != NULL) @@ -5380,6 +5432,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) return 0; case ACSF_GetActorViewHeight: + MIN_ARG_COUNT(1); actor = Level->SingleActorFromTID(args[0], activator); if (actor != NULL) { @@ -5395,6 +5448,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) else return 0; case ACSF_GetChar: + MIN_ARG_COUNT(2); { const char *p = Level->Behaviors.LookupString(args[0]); if (p != NULL && args[1] >= 0 && args[1] < int(strlen(p))) @@ -5408,6 +5462,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_GetAirSupply: + MIN_ARG_COUNT(1); { if (args[0] < 0 || args[0] >= MAXPLAYERS || !Level->PlayerInGame(args[0])) { @@ -5420,6 +5475,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_SetAirSupply: + MIN_ARG_COUNT(2); { if (args[0] < 0 || args[0] >= MAXPLAYERS || !Level->PlayerInGame(args[0])) { @@ -5433,6 +5489,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_SetSkyScrollSpeed: + MIN_ARG_COUNT(2); { if (args[0] == 1) Level->skyspeed1 = ACSToFloat(args[1]); else if (args[0] == 2) Level->skyspeed2 = ACSToFloat(args[1]); @@ -5440,6 +5497,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_GetArmorType: + MIN_ARG_COUNT(2); { if (args[1] < 0 || args[1] >= MAXPLAYERS || !Level->PlayerInGame(args[1])) { @@ -5448,17 +5506,18 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) else { FName p(Level->Behaviors.LookupString(args[0])); - auto armor = Level->Players[args[1]]->mo->FindInventory(NAME_BasicArmor); + auto armor = Level->Players[args[1]]->mo->FindInventory(NAME_BasicArmor, true); if (armor && armor->NameVar(NAME_ArmorType) == p) return armor->IntVar(NAME_Amount); } return 0; } case ACSF_GetArmorInfo: + MIN_ARG_COUNT(1); { if (activator == NULL || activator->player == NULL) return 0; - auto equippedarmor = activator->FindInventory(NAME_BasicArmor); + auto equippedarmor = activator->FindInventory(NAME_BasicArmor, true); if (equippedarmor && equippedarmor->IntVar(NAME_Amount) != 0) { @@ -5490,15 +5549,19 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_SpawnSpotForced: + MIN_ARG_COUNT(4); return DoSpawnSpot(args[0], args[1], args[2], args[3], true); case ACSF_SpawnSpotFacingForced: + MIN_ARG_COUNT(3); return DoSpawnSpotFacing(args[0], args[1], args[2], true); case ACSF_CheckActorProperty: + MIN_ARG_COUNT(3); return (CheckActorProperty(args[0], args[1], args[2])); case ACSF_SetActorVelocity: + MIN_ARG_COUNT(6); { DVector3 vel(ACSToDouble(args[1]), ACSToDouble(args[2]), ACSToDouble(args[3])); if (args[0] == 0) @@ -5518,6 +5581,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_SetUserVariable: + MIN_ARG_COUNT(3); { int cnt = 0; FName varname(Level->Behaviors.LookupString(args[1]), true); @@ -5546,6 +5610,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_GetUserVariable: + MIN_ARG_COUNT(2); { FName varname(Level->Behaviors.LookupString(args[1]), true); if (varname != NAME_None) @@ -5557,6 +5622,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_SetUserArray: + MIN_ARG_COUNT(4); { int cnt = 0; FName varname(Level->Behaviors.LookupString(args[1]), true); @@ -5585,6 +5651,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_GetUserArray: + MIN_ARG_COUNT(3); { FName varname(Level->Behaviors.LookupString(args[1]), true); if (varname != NAME_None) @@ -5596,22 +5663,26 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_Radius_Quake2: - P_StartQuake(Level, activator, args[0], args[1], args[2], args[3], args[4], Level->Behaviors.LookupString(args[5])); + MIN_ARG_COUNT(6); + P_StartQuake(Level, activator, args[0], (double)args[1], args[2], args[3], args[4], S_FindSound(Level->Behaviors.LookupString(args[5]))); break; case ACSF_CheckActorClass: + MIN_ARG_COUNT(2); { AActor *a = Level->SingleActorFromTID(args[0], activator); return a == NULL ? false : a->GetClass()->TypeName == FName(Level->Behaviors.LookupString(args[1])); } case ACSF_GetActorClass: + MIN_ARG_COUNT(1); { AActor *a = Level->SingleActorFromTID(args[0], activator); return GlobalACSStrings.AddString(a == NULL ? "None" : a->GetClass()->TypeName.GetChars()); } case ACSF_SoundSequenceOnActor: + MIN_ARG_COUNT(2); { const char *seqname = Level->Behaviors.LookupString(args[1]); if (seqname != NULL) @@ -5638,6 +5709,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) break; case ACSF_SoundSequenceOnSector: + MIN_ARG_COUNT(3); { const char *seqname = Level->Behaviors.LookupString(args[1]); int space = args[2] < CHAN_FLOOR || args[2] > CHAN_INTERIOR ? CHAN_FULLHEIGHT : args[2]; @@ -5654,6 +5726,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) break; case ACSF_SoundSequenceOnPolyobj: + MIN_ARG_COUNT(2); { const char *seqname = Level->Behaviors.LookupString(args[1]); if (seqname != NULL) @@ -5668,6 +5741,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) break; case ACSF_GetPolyobjX: + MIN_ARG_COUNT(1); { FPolyObj *poly = Level->GetPolyobj(args[0]); if (poly != NULL) @@ -5678,6 +5752,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) return FIXED_MAX; case ACSF_GetPolyobjY: + MIN_ARG_COUNT(1); { FPolyObj *poly = Level->GetPolyobj(args[0]); if (poly != NULL) @@ -5688,6 +5763,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) return FIXED_MAX; case ACSF_CheckSight: + MIN_ARG_COUNT(3); { AActor *source; AActor *dest; @@ -5733,7 +5809,8 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) } case ACSF_SpawnForced: - return DoSpawn(args[0], args[1], args[2], args[3], args[4], args[5], true); + MIN_ARG_COUNT(4); + return DoSpawn(args[0], args[1], args[2], args[3], argCount > 4 ? args[4] : 0, argCount > 5 ? args[5] : 0, true); case ACSF_ACS_NamedExecute: case ACSF_ACS_NamedSuspend: @@ -5742,8 +5819,9 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) case ACSF_ACS_NamedLockedExecuteDoor: case ACSF_ACS_NamedExecuteWithResult: case ACSF_ACS_NamedExecuteAlways: + MIN_ARG_COUNT(1); { - int scriptnum = -FName(Level->Behaviors.LookupString(args[0])); + int scriptnum = -FName(Level->Behaviors.LookupString(args[0])).GetIndex(); int arg1 = argCount > 1 ? args[1] : 0; int arg2 = argCount > 2 ? args[2] : 0; int arg3 = argCount > 3 ? args[3] : 0; @@ -5758,15 +5836,19 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) return Level->FindUniqueTID(argCount > 0 ? args[0] : 0, (argCount > 1 && args[1] >= 0) ? args[1] : 0); case ACSF_IsTIDUsed: + MIN_ARG_COUNT(1); return Level->IsTIDUsed(args[0]); case ACSF_Sqrt: + MIN_ARG_COUNT(1); return xs_FloorToInt(g_sqrt(double(args[0]))); case ACSF_FixedSqrt: + MIN_ARG_COUNT(1); return DoubleToACS(g_sqrt(ACSToDouble(args[0]))); case ACSF_VectorLength: + MIN_ARG_COUNT(2); return DoubleToACS(DVector2(ACSToDouble(args[0]), ACSToDouble(args[1])).Length()); case ACSF_SetHUDClipRect: @@ -5783,56 +5865,36 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) break; case ACSF_GetCVarString: - if (argCount == 1) - { - return DoGetCVar(GetCVar(activator && activator->player ? int(activator->player - players) : -1, Level->Behaviors.LookupString(args[0])), true); - } - break; + MIN_ARG_COUNT(1); + return DoGetCVar(GetCVar(activator && activator->player ? int(activator->player - players) : -1, Level->Behaviors.LookupString(args[0])), true); case ACSF_SetCVar: - if (argCount == 2) - { - return SetCVar(activator, Level->Behaviors.LookupString(args[0]), args[1], false); - } - break; + MIN_ARG_COUNT(2); + return SetCVar(activator, Level->Behaviors.LookupString(args[0]), args[1], false); case ACSF_SetCVarString: - if (argCount == 2) - { - return SetCVar(activator, Level->Behaviors.LookupString(args[0]), args[1], true); - } - break; + MIN_ARG_COUNT(2); + return SetCVar(activator, Level->Behaviors.LookupString(args[0]), args[1], true); case ACSF_GetUserCVar: - if (argCount == 2) - { - return DoGetCVar(GetUserCVar(args[0], Level->Behaviors.LookupString(args[1])), false); - } - break; + MIN_ARG_COUNT(2); + return DoGetCVar(G_GetUserCVar(args[0], Level->Behaviors.LookupString(args[1])), false); case ACSF_GetUserCVarString: - if (argCount == 2) - { - return DoGetCVar(GetUserCVar(args[0], Level->Behaviors.LookupString(args[1])), true); - } - break; + MIN_ARG_COUNT(2); + return DoGetCVar(G_GetUserCVar(args[0], Level->Behaviors.LookupString(args[1])), true); case ACSF_SetUserCVar: - if (argCount == 3) - { - return SetUserCVar(args[0], Level->Behaviors.LookupString(args[1]), args[2], false); - } - break; + MIN_ARG_COUNT(3); + return SetUserCVar(args[0], Level->Behaviors.LookupString(args[1]), args[2], false); case ACSF_SetUserCVarString: - if (argCount == 3) - { - return SetUserCVar(args[0], Level->Behaviors.LookupString(args[1]), args[2], true); - } - break; + MIN_ARG_COUNT(3); + return SetUserCVar(args[0], Level->Behaviors.LookupString(args[1]), args[2], true); //[RC] A bullet firing function for ACS. Thanks to DavidPH. case ACSF_LineAttack: + MIN_ARG_COUNT(4); { DAngle angle = ACSToAngle(args[1]); DAngle pitch = ACSToAngle(args[2]); @@ -5875,18 +5937,19 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) case ACSF_PlaySound: case ACSF_PlayActorSound: // PlaySound(tid, "SoundName", channel, volume, looping, attenuation, local) + MIN_ARG_COUNT(2); { - FSoundID sid = 0; + FSoundID sid = NO_SOUND; if (funcIndex == ACSF_PlaySound) { const char *lookup = Level->Behaviors.LookupString(args[1]); if (lookup != NULL) { - sid = lookup; + sid = S_FindSound(lookup); } } - if (sid != 0 || funcIndex == ACSF_PlayActorSound) + if (sid != NO_SOUND || funcIndex == ACSF_PlayActorSound) { auto it = Level->GetActorIterator(args[0]); AActor *spot; @@ -5908,7 +5971,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) { sid = GetActorSound(spot, args[1]); } - if (sid != 0) + if (sid != NO_SOUND) { // What a mess. I think it's a given that this was used with sound flags so it will forever be restricted to the original 8 channels. if (local) chan |= CHANF_LOCAL; @@ -5921,6 +5984,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_StopSound: + MIN_ARG_COUNT(1); { int chan = argCount > 1 ? args[1] : CHAN_BODY; @@ -5943,6 +6007,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_SoundVolume: // SoundVolume(int tid, int channel, fixed volume) + MIN_ARG_COUNT(3); { int chan = args[1]; double volume = ACSToDouble(args[2]); @@ -5966,7 +6031,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_strcmp: case ACSF_stricmp: - if (argCount >= 2) + MIN_ARG_COUNT(2); { const char *a, *b; // If the string indicies are the same, then they are the same string. @@ -5995,7 +6060,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_StrLeft: case ACSF_StrRight: - if (argCount >= 2) + MIN_ARG_COUNT(2); { const char *oldstr = Level->Behaviors.LookupString(args[0]); if (oldstr == NULL || *oldstr == '\0') @@ -6015,7 +6080,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_StrMid: - if (argCount >= 3) + MIN_ARG_COUNT(3); { const char *oldstr = Level->Behaviors.LookupString(args[0]); if (oldstr == NULL || *oldstr == '\0') @@ -6034,7 +6099,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) { newlen = oldlen - pos; } - return GlobalACSStrings.AddString(FString(oldstr + pos, newlen)); + return GlobalACSStrings.AddString(FString(oldstr + pos, newlen).GetChars()); } break; @@ -6050,8 +6115,9 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_SpawnDecal: - // int SpawnDecal(int tid, str decalname, int flags, fixed angle, int zoffset, int distance) + // int SpawnDecal(int tid, str decalname, int flags, fixed angle, int|fixed zoffset, int|fixed distance) // Returns number of decals spawned (not including spreading) + MIN_ARG_COUNT(2); { int count = 0; const FDecalTemplate *tpl = DecalLibrary.GetDecalByName(Level->Behaviors.LookupString(args[1])); @@ -6059,8 +6125,8 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) { int flags = (argCount > 2) ? args[2] : 0; DAngle angle = ACSToAngle((argCount > 3) ? args[3] : 0); - int zoffset = (argCount > 4) ? args[4]: 0; - int distance = (argCount > 5) ? args[5] : 64; + double zoffset = (argCount > 4) ? ((flags & SDF_FIXED_ZOFF) ? ACSToDouble(args[4]) : args[4]) : 0; + double distance = (argCount > 5) ? ((flags & SDF_FIXED_DISTANCE) ? ACSToDouble(args[5]) : args[5]) : 64; if (args[0] == 0) { @@ -6086,9 +6152,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_CheckFont: // bool CheckFont(str fontname) + MIN_ARG_COUNT(1); return V_GetFont(Level->Behaviors.LookupString(args[0])) != NULL; case ACSF_DropItem: + MIN_ARG_COUNT(2); { const char *type = Level->Behaviors.LookupString(args[1]); int amount = argCount >= 3? args[2] : -1; @@ -6122,6 +6190,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_DropInventory: + MIN_ARG_COUNT(2); { const char *type = Level->Behaviors.LookupString(args[1]); AActor *inv; @@ -6158,6 +6227,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_CheckFlag: + MIN_ARG_COUNT(2); { AActor *actor = Level->SingleActorFromTID(args[0], activator); if (actor != NULL) @@ -6168,8 +6238,9 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_QuakeEx: + MIN_ARG_COUNT(8); { - return P_StartQuakeXYZ(Level, activator, args[0], args[1], args[2], args[3], args[4], args[5], args[6], Level->Behaviors.LookupString(args[7]), + return P_StartQuakeXYZ(Level, activator, args[0], args[1], args[2], args[3], args[4], args[5], args[6], S_FindSound(Level->Behaviors.LookupString(args[7])), argCount > 8 ? args[8] : 0, argCount > 9 ? ACSToDouble(args[9]) : 1.0, argCount > 10 ? ACSToDouble(args[10]) : 1.0, @@ -6177,23 +6248,29 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) argCount > 12 ? args[12] : 0, argCount > 13 ? args[13] : 0, argCount > 14 ? ACSToDouble(args[14]) : 0, - argCount > 15 ? ACSToDouble(args[15]) : 0); + argCount > 15 ? ACSToDouble(args[15]) : 0, + argCount > 16 ? ACSToDouble(args[16]) : 1.0, + argCount > 17 ? ACSToDouble(args[17]) : 0.5, + argCount > 18 ? args[18] : 0); } case ACSF_SetLineActivation: - if (argCount >= 2) + MIN_ARG_COUNT(2); { int line; auto itr = Level->GetLineIdIterator(args[0]); + int repeat = argCount > 2 ? args[2] : -1; while ((line = itr.Next()) >= 0) { Level->lines[line].activation = args[1]; + if (repeat > 0) Level->lines[line].flags |= ML_REPEAT_SPECIAL; + else if (repeat == 0) Level->lines[line].flags &= ~ML_REPEAT_SPECIAL; } } break; case ACSF_GetLineActivation: - if (argCount > 0) + MIN_ARG_COUNT(1); { int line = Level->FindFirstLineFromID(args[0]); return line >= 0 ? Level->lines[line].activation : 0; @@ -6201,7 +6278,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_GetActorPowerupTics: - if (argCount >= 2) + MIN_ARG_COUNT(2); { PClassActor *powerupclass = PClass::FindActor(Level->Behaviors.LookupString(args[1])); if (powerupclass == NULL || !powerupclass->IsDescendantOf(NAME_Powerup)) @@ -6222,32 +6299,26 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_ChangeActorAngle: - if (argCount >= 2) - { - SetActorAngle(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); - } + MIN_ARG_COUNT(2); + SetActorAngle(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); break; case ACSF_ChangeActorPitch: - if (argCount >= 2) - { - SetActorPitch(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); - } + MIN_ARG_COUNT(2); + SetActorPitch(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); break; + case ACSF_SetActorTeleFog: - if (argCount >= 3) - { - SetActorTeleFog(activator, args[0], Level->Behaviors.LookupString(args[1]), Level->Behaviors.LookupString(args[2])); - } + MIN_ARG_COUNT(3); + SetActorTeleFog(activator, args[0], Level->Behaviors.LookupString(args[1]), Level->Behaviors.LookupString(args[2])); break; + case ACSF_SwapActorTeleFog: - if (argCount >= 1) - { - return SwapActorTeleFog(activator, args[0]); - } - break; + MIN_ARG_COUNT(1); + return SwapActorTeleFog(activator, args[0]); + case ACSF_PickActor: - if (argCount >= 5) + MIN_ARG_COUNT(5); { actor = Level->SingleActorFromTID(args[0], activator); if (actor == NULL) @@ -6292,11 +6363,12 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_IsPointerEqual: + MIN_ARG_COUNT(2); { int tid1 = 0, tid2 = 0; switch (argCount) { - case 4: tid2 = args[3]; + case 4: tid2 = args[3]; [[fallthrough]]; case 3: tid1 = args[2]; } @@ -6308,7 +6380,8 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_CanRaiseActor: - if (argCount >= 1) { + MIN_ARG_COUNT(1); + { if (args[0] == 0) { actor = Level->SingleActorFromTID(args[0], activator); if (actor != NULL) { @@ -6320,7 +6393,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) bool canraiseall = true; while ((actor = iterator.Next())) { - canraiseall = P_Thing_CanRaise(actor) & canraiseall; + canraiseall &= P_Thing_CanRaise(actor); } return canraiseall; @@ -6329,22 +6402,23 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) // [Nash] Actor roll functions. Let's roll! case ACSF_SetActorRoll: + MIN_ARG_COUNT(2); SetActorRoll(activator, args[0], args[1], false); - return 0; + break; case ACSF_ChangeActorRoll: - if (argCount >= 2) - { - SetActorRoll(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); - } + MIN_ARG_COUNT(2); + SetActorRoll(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); break; case ACSF_GetActorRoll: + MIN_ARG_COUNT(1); actor = Level->SingleActorFromTID(args[0], activator); return actor != NULL? AngleToACS(actor->Angles.Roll) : 0; // [ZK] A_Warp in ACS case ACSF_Warp: + MIN_ARG_COUNT(6); { if (nullptr == activator) { @@ -6396,6 +6470,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return true; } case ACSF_GetMaxInventory: + MIN_ARG_COUNT(2); actor = Level->SingleActorFromTID(args[0], activator); if (actor != NULL) { @@ -6404,7 +6479,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_SetSectorDamage: - if (argCount >= 2) + MIN_ARG_COUNT(2); { auto it = Level->GetSectorTagIterator(args[0]); int s; @@ -6421,7 +6496,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_SetSectorTerrain: - if (argCount >= 3) + MIN_ARG_COUNT(3); { if (args[1] == sector_t::floor || args[1] == sector_t::ceiling) { @@ -6437,10 +6512,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_SpawnParticle: + MIN_ARG_COUNT(1); { PalEntry color = args[0]; bool fullbright = argCount > 1 ? !!args[1] : false; - int lifetime = argCount > 2 ? args[2] : 35; + int lifetime = argCount > 2 ? args[2] : TICRATE; double size = argCount > 3 ? args[3] : 1.; int x = argCount > 4 ? args[4] : 0; int y = argCount > 5 ? args[5] : 0; @@ -6469,10 +6545,12 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; case ACSF_SetMusicVolume: + MIN_ARG_COUNT(1); Level->SetMusicVolume(ACSToFloat(args[0])); break; case ACSF_CheckProximity: + MIN_ARG_COUNT(3); { // [zombie] ACS version of A_CheckProximity actor = Level->SingleActorFromTID(args[0], activator); @@ -6485,6 +6563,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_CheckActorState: + MIN_ARG_COUNT(2); { actor = Level->SingleActorFromTID(args[0], activator); const char *statename = Level->Behaviors.LookupString(args[1]); @@ -6497,12 +6576,14 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_CheckClass: + MIN_ARG_COUNT(1); { const char *clsname = Level->Behaviors.LookupString(args[0]); return !!PClass::FindActor(clsname); } case ACSF_DamageActor: // [arookas] wrapper around P_DamageMobj + MIN_ARG_COUNT(6); { // (target, ptr_select1, inflictor, ptr_select2, amount, damagetype) AActor* target = COPY_AAPTREX(Level, Level->SingleActorFromTID(args[0], activator), args[1]); @@ -6512,6 +6593,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_SetActorFlag: + MIN_ARG_COUNT(3); { int tid = args[0]; FString flagname = Level->Behaviors.LookupString(args[1]); @@ -6540,6 +6622,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_SetTranslation: + MIN_ARG_COUNT(2); { int tid = args[0]; const char *trname = Level->Behaviors.LookupString(args[1]); @@ -6561,6 +6644,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) // OpenGL exclusive functions case ACSF_SetSectorGlow: + MIN_ARG_COUNT(6); { int which = !!args[1]; PalEntry color(args[2], args[3], args[4]); @@ -6578,6 +6662,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_SetFogDensity: + MIN_ARG_COUNT(2); { auto it = Level->GetSectorTagIterator(args[0]); int s; @@ -6590,11 +6675,12 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_GetActorFloorTexture: + MIN_ARG_COUNT(1); { auto a = Level->SingleActorFromTID(args[0], activator); if (a != nullptr) { - return GlobalACSStrings.AddString(TexMan.GetTexture(a->floorpic)->GetName()); + return GlobalACSStrings.AddString(TexMan.GetGameTexture(a->floorpic)->GetName().GetChars()); } else { @@ -6604,11 +6690,12 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_GetActorFloorTerrain: + MIN_ARG_COUNT(1); { auto a = Level->SingleActorFromTID(args[0], activator); if (a != nullptr) { - return GlobalACSStrings.AddString(Terrains[a->floorterrain].Name); + return GlobalACSStrings.AddString(Terrains[a->floorterrain].Name.GetChars()); } else { @@ -6618,25 +6705,32 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_StrArg: - return -FName(Level->Behaviors.LookupString(args[0])); + MIN_ARG_COUNT(1); + return -FName(Level->Behaviors.LookupString(args[0])).GetIndex(); case ACSF_Floor: + MIN_ARG_COUNT(1); return args[0] & ~0xffff; case ACSF_Ceil: + MIN_ARG_COUNT(1); return (args[0] & ~0xffff) + 0x10000; case ACSF_Round: + MIN_ARG_COUNT(1); return (args[0] + 32768) & ~0xffff; case ACSF_ScriptCall: + MIN_ARG_COUNT(1); return ScriptCall(activator, argCount, args); case ACSF_StartSlideshow: + MIN_ARG_COUNT(1); G_StartSlideshow(Level, FName(Level->Behaviors.LookupString(args[0]))); break; case ACSF_GetSectorHealth: + MIN_ARG_COUNT(2); { int part = args[1]; auto it = Level->GetSectorTagIterator(args[0]); @@ -6664,6 +6758,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } case ACSF_GetLineHealth: + MIN_ARG_COUNT(1); { auto it = Level->GetLineIdIterator(args[0]); int l = it.Next(); @@ -6681,6 +6776,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_GetLineX: case ACSF_GetLineY: + MIN_ARG_COUNT(3); { auto it = Level->GetLineIdIterator(args[0]); int lineno = it.Next(); @@ -6694,11 +6790,31 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } return DoubleToACS(result); } + + case ACSF_SetSubtitleNumber: + MIN_ARG_COUNT(2); + // only players allowed as activator + if (activator != nullptr && activator->player != nullptr) + { + int logNum = args[0]; + FSoundID sid = NO_SOUND; + + const char* lookup = Level->Behaviors.LookupString(args[1]); + if (lookup != nullptr) + { + sid = S_FindSound(lookup); + } + + activator->player->SetSubtitle(logNum, sid); + } + break; + default: break; } return 0; } +#undef MIN_ARG_COUNT enum { @@ -6770,6 +6886,7 @@ int DLevelScript::RunScript() ScriptFunction *activeFunction = NULL; FRemapTable *translation = 0; int resultValue = 1; + int transi = -1; if (InModuleScriptNumber >= 0) { @@ -6955,7 +7072,7 @@ int DLevelScript::RunScript() break; case PCD_SWAP: - swapvalues(Stack[sp-2], Stack[sp-1]); + std::swap(Stack[sp-2], Stack[sp-1]); break; case PCD_LSPEC1: @@ -7111,7 +7228,12 @@ int DLevelScript::RunScript() int argCount = NEXTBYTE; int funcIndex = NEXTSHORT; - int retval = CallFunction(argCount, funcIndex, &STACK(argCount)); + int retval, minCount = 0; + retval = CallFunction(argCount, funcIndex, &STACK(argCount), minCount); + if (minCount != 0) + { + Printf("Called ACS function index %d with too few args: %d (need %d)\n", funcIndex, argCount, minCount); + } sp -= argCount-1; STACK(1) = retval; } @@ -8105,6 +8227,7 @@ int DLevelScript::RunScript() case PCD_SETRESULTVALUE: resultValue = STACK(1); + [[fallthrough]]; case PCD_DROP: //fall through. sp--; break; @@ -8320,7 +8443,7 @@ int DLevelScript::RunScript() } case PCD_SCRIPTWAITNAMED: - statedata = -FName(Level->Behaviors.LookupString(STACK(1))); + statedata = -FName(Level->Behaviors.LookupString(STACK(1))).GetIndex(); sp--; goto scriptwait; @@ -8386,7 +8509,7 @@ int DLevelScript::RunScript() lookup = Level->Behaviors.LookupString (STACK(1), true); if (pcd == PCD_PRINTLOCALIZED) { - lookup = GStrings(lookup); + lookup = GStrings.GetString(lookup); } if (lookup != NULL) { @@ -8528,7 +8651,7 @@ int DLevelScript::RunScript() int capacity, offset, a, c; if (CharArrayParms(capacity, offset, a, Stack, sp, pcd == PCD_PRINTMAPCHRANGE)) { - while (capacity-- && (c = activeBehavior->GetArrayVal (a, offset)) != '\0') + while (capacity-- && (c = activeBehavior->GetArrayVal (*activeBehavior->MapVars[a], offset)) != '\0') { work += (char)c; offset++; @@ -8574,7 +8697,7 @@ int DLevelScript::RunScript() lookup = Level->Behaviors.LookupString (STACK(1)); if (lookup != NULL) { - int key1 = 0, key2 = 0; + int key1, key2; Bindings.GetKeysForCommand ((char *)lookup, &key1, &key2); @@ -8612,7 +8735,7 @@ int DLevelScript::RunScript() if (pcd == PCD_ENDPRINTBOLD || screen == NULL || screen->CheckLocalView()) { - C_MidPrint (activefont, work, pcd == PCD_ENDPRINTBOLD && (gameinfo.correctprintbold || (Level->flags2 & LEVEL2_HEXENHACK))); + C_MidPrint (activefont, work.GetChars(), pcd == PCD_ENDPRINTBOLD && (gameinfo.correctprintbold || (Level->flags2 & LEVEL2_HEXENHACK))); } STRINGBUILDER_FINISH(work); } @@ -8667,13 +8790,13 @@ int DLevelScript::RunScript() { default: // normal alpha = (optstart < sp) ? ACSToFloat(Stack[optstart]) : 1.f; - msg = Create (activefont, work, x, y, hudwidth, hudheight, color, holdTime); + msg = Create (activefont, work.GetChars(), x, y, hudwidth, hudheight, color, holdTime); break; case 1: // fade out { float fadeTime = (optstart < sp) ? ACSToFloat(Stack[optstart]) : 0.5f; alpha = (optstart < sp-1) ? ACSToFloat(Stack[optstart+1]) : 1.f; - msg = Create (activefont, work, x, y, hudwidth, hudheight, color, holdTime, fadeTime); + msg = Create (activefont, work.GetChars(), x, y, hudwidth, hudheight, color, holdTime, fadeTime); } break; case 2: // type on, then fade out @@ -8681,7 +8804,7 @@ int DLevelScript::RunScript() float typeTime = (optstart < sp) ? ACSToFloat(Stack[optstart]) : 0.05f; float fadeTime = (optstart < sp-1) ? ACSToFloat(Stack[optstart+1]) : 0.5f; alpha = (optstart < sp-2) ? ACSToFloat(Stack[optstart+2]) : 1.f; - msg = Create (activefont, work, x, y, hudwidth, hudheight, color, typeTime, holdTime, fadeTime); + msg = Create (activefont, work.GetChars(), x, y, hudwidth, hudheight, color, typeTime, holdTime, fadeTime); } break; case 3: // fade in, then fade out @@ -8689,7 +8812,7 @@ int DLevelScript::RunScript() float inTime = (optstart < sp) ? ACSToFloat(Stack[optstart]) : 0.5f; float outTime = (optstart < sp-1) ? ACSToFloat(Stack[optstart+1]) : 0.5f; alpha = (optstart < sp-2) ? ACSToFloat(Stack[optstart + 2]) : 1.f; - msg = Create (activefont, work, x, y, hudwidth, hudheight, color, holdTime, inTime, outTime); + msg = Create (activefont, work.GetChars(), x, y, hudwidth, hudheight, color, holdTime, inTime, outTime); } break; } @@ -8715,8 +8838,8 @@ int DLevelScript::RunScript() (type & HUDMSG_LAYER_MASK) >> HUDMSG_LAYER_SHIFT); if (type & HUDMSG_LOG) { - int consolecolor = color >= CR_BRICK && color <= CR_YELLOW ? color + 'A' : '-'; - Printf(PRINT_NONOTIFY, "\n" TEXTCOLOR_ESCAPESTR "%c%s\n%s\n%s\n", consolecolor, console_bar, work.GetChars(), console_bar); + int consolecolor = color >= CR_BRICK && color < NUM_TEXT_COLORS && color != CR_UNTRANSLATED ? color + 'A' : '-'; + Printf(PRINT_HIGH | PRINT_NONOTIFY, "\n" TEXTCOLOR_ESCAPESTR "%c%s\n%s\n%s\n", consolecolor, console_bar, work.GetChars(), console_bar); } } } @@ -8775,7 +8898,7 @@ int DLevelScript::RunScript() case PCD_PLAYERARMORPOINTS: if (activator) { - auto armor = activator->FindInventory(NAME_BasicArmor); + auto armor = activator->FindInventory(NAME_BasicArmor, true); PushToStack (armor ? armor->IntVar(NAME_Amount) : 0); } else @@ -8818,7 +8941,7 @@ int DLevelScript::RunScript() S_Sound ( activationline->frontsector, CHAN_AUTO, 0, // Not CHAN_AREA, because that'd probably break existing scripts. - lookup, + S_FindSound(lookup), (float)(STACK(1)) / 127.f, ATTN_NORM); } @@ -8967,7 +9090,7 @@ int DLevelScript::RunScript() if (specnum >= -ACSF_ACS_NamedExecuteAlways && specnum <= -ACSF_ACS_NamedExecute) { specnum = NamedACSToNormalACS[-specnum - ACSF_ACS_NamedExecute]; - arg0 = -FName(Level->Behaviors.LookupString(arg0)); + arg0 = -FName(Level->Behaviors.LookupString(arg0)).GetIndex(); } auto itr = Level->GetLineIdIterator(STACK(7)); @@ -8996,7 +9119,7 @@ int DLevelScript::RunScript() if (specnum >= -ACSF_ACS_NamedExecuteAlways && specnum <= -ACSF_ACS_NamedExecute) { specnum = NamedACSToNormalACS[-specnum - ACSF_ACS_NamedExecute]; - arg0 = -FName(Level->Behaviors.LookupString(arg0)); + arg0 = -FName(Level->Behaviors.LookupString(arg0)).GetIndex(); } if (STACK(7) != 0) @@ -9045,15 +9168,19 @@ int DLevelScript::RunScript() break; case PCD_FIXEDMUL: - STACK(2) = FixedMul (STACK(2), STACK(1)); + STACK(2) = MulScale(STACK(2), STACK(1), 16); sp--; break; case PCD_FIXEDDIV: - STACK(2) = FixedDiv (STACK(2), STACK(1)); + { + int a = STACK(2), b = STACK(1); + // Overflow check. + if ((uint32_t)abs(a) >> (31 - 16) >= (uint32_t)abs(b)) STACK(2) = (a ^ b) < 0 ? FIXED_MIN : FIXED_MAX; + else STACK(2) = DivScale(STACK(2), STACK(1), 16); sp--; break; - + } case PCD_SETGRAVITY: Level->gravity = ACSToDouble(STACK(1)); sp--; @@ -9499,13 +9626,9 @@ int DLevelScript::RunScript() sp--; if (i >= 1 && i <= MAX_ACS_TRANSLATIONS) { - translation = translationtables[TRANSLATION_LevelScripted].GetVal(i - 1); - if (translation == NULL) - { - translation = new FRemapTable; - translationtables[TRANSLATION_LevelScripted].SetVal(i - 1, translation); - } + translation = new FRemapTable; translation->MakeIdentity(); + transi = i - 1; } } break; @@ -9592,7 +9715,8 @@ int DLevelScript::RunScript() case PCD_ENDTRANSLATION: if (translation != NULL) { - translation->UpdateNative(); + GPalette.UpdateTranslation(TRANSLATION(TRANSLATION_LevelScripted, transi), translation); + delete translation; translation = NULL; } break; @@ -9606,7 +9730,7 @@ int DLevelScript::RunScript() break; case PCD_VECTORANGLE: - STACK(2) = AngleToACS(VecToAngle(STACK(2), STACK(1)).Degrees); + STACK(2) = AngleToACS(VecToAngle(STACK(2), STACK(1))); sp--; break; @@ -9707,14 +9831,14 @@ int DLevelScript::RunScript() // Like Thing_Projectile(Gravity) specials, but you can give the // projectile a TID. // Thing_Projectile2 (tid, type, angle, speed, vspeed, gravity, newtid); - Level->EV_Thing_Projectile(STACK(7), activator, STACK(6), NULL, STACK(5) * (360. / 256.), + Level->EV_Thing_Projectile(STACK(7), activator, STACK(6), NULL, DAngle::fromDeg(STACK(5) * (360. / 256.)), STACK(4) / 8., STACK(3) / 8., 0, NULL, STACK(2), STACK(1), false); sp -= 7; break; case PCD_SPAWNPROJECTILE: // Same, but takes an actor name instead of a spawn ID. - Level->EV_Thing_Projectile(STACK(7), activator, 0, Level->Behaviors.LookupString(STACK(6)), STACK(5) * (360. / 256.), + Level->EV_Thing_Projectile(STACK(7), activator, 0, Level->Behaviors.LookupString(STACK(6)), DAngle::fromDeg(STACK(5) * (360. / 256.)), STACK(4) / 8., STACK(3) / 8., 0, NULL, STACK(2), STACK(1), false); sp -= 7; break; @@ -9904,6 +10028,7 @@ int DLevelScript::RunScript() case PLAYERINFO_PLAYERCLASS: STACK(2) = userinfo->GetPlayerClassNum(); break; case PLAYERINFO_DESIREDFOV: STACK(2) = (int)pl->DesiredFOV; break; case PLAYERINFO_FOV: STACK(2) = (int)pl->FOV; break; + case PLAYERINFO_FVIEWBOB: STACK(2) = (bool)userinfo->GetFViewBob(); break; default: STACK(2) = 0; break; } } @@ -10026,9 +10151,14 @@ int DLevelScript::RunScript() else { auto iterator = Level->GetActorIterator(tag); - AActor *actor; + TArray actorsToMorph; - while ( (actor = iterator.Next ()) ) + while (AActor *actor = iterator.Next()) + { + actorsToMorph.Push(actor); + } + + for (AActor *actor : actorsToMorph) { changes += P_MorphActor(activator, actor, playerclass, monsterclass, duration, style, morphflash, unmorphflash); } @@ -10052,9 +10182,14 @@ int DLevelScript::RunScript() else { auto iterator = Level->GetActorIterator(tag); - AActor *actor; + TArray actorsToUnmorph; - while ( (actor = iterator.Next ()) ) + while (AActor *actor = iterator.Next()) + { + actorsToUnmorph.Push(actor); + } + + for (AActor *actor : actorsToUnmorph) { changes += P_UnmorphActor(activator, actor, 0, force); } @@ -10256,7 +10391,7 @@ DLevelScript::DLevelScript (FLevelLocals *l, AActor *who, line_t *where, int num assert(code->VarCount >= code->ArgCount); Localvars.Resize(code->VarCount); memset(&Localvars[0], 0, code->VarCount * sizeof(int32_t)); - for (int i = 0; i < MIN(argcount, code->ArgCount); ++i) + for (int i = 0; i < min(argcount, code->ArgCount); ++i) { Localvars[i] = args[i]; } @@ -10375,7 +10510,7 @@ EXTERN_CVAR (Bool, sv_cheats) int P_StartScript (FLevelLocals *Level, AActor *who, line_t *where, int script, const char *map, const int *args, int argcount, int flags) { - if (map == NULL || 0 == strnicmp (Level->MapName, map, 8)) + if (map == NULL || 0 == strnicmp (Level->MapName.GetChars(), map, 8)) { FBehavior *module = NULL; const ScriptPtr *scriptdata; @@ -10430,7 +10565,7 @@ int P_StartScript (FLevelLocals *Level, AActor *who, line_t *where, int script, void P_SuspendScript (FLevelLocals *Level, int script, const char *map) { - if (strnicmp (Level->MapName, map, 8)) + if (strnicmp (Level->MapName.GetChars(), map, 8)) addDefered (FindLevelInfo (map), acsdefered_t::defsuspend, script, NULL, 0, NULL); else SetScriptState (Level->ACSThinker, script, DLevelScript::SCRIPT_Suspended); @@ -10438,7 +10573,7 @@ void P_SuspendScript (FLevelLocals *Level, int script, const char *map) void P_TerminateScript (FLevelLocals *Level, int script, const char *map) { - if (strnicmp (Level->MapName, map, 8)) + if (strnicmp (Level->MapName.GetChars(), map, 8)) addDefered (FindLevelInfo (map), acsdefered_t::defterminate, script, NULL, 0, NULL); else SetScriptState (Level->ACSThinker, script, DLevelScript::SCRIPT_PleaseRemove); @@ -10612,7 +10747,7 @@ static int sort_by_runs(const void *a_, const void *b_) return b->ProfileData->NumRuns - a->ProfileData->NumRuns; } -static void ShowProfileData(TArray &profiles, long ilimit, +static void ShowProfileData(TArray &profiles, int ilimit, int (*sorter)(const void *, const void *), bool functions) { static const char *const typelabels[2] = { "script", "function" }; @@ -10630,7 +10765,7 @@ static void ShowProfileData(TArray &profiles, long ilimit, if (ilimit > 0) { - Printf(TEXTCOLOR_ORANGE "Top %ld %ss:\n", ilimit, typelabels[functions]); + Printf(TEXTCOLOR_ORANGE "Top %lld %ss:\n", ilimit, typelabels[functions]); limit = (unsigned int)ilimit; } else @@ -10696,7 +10831,7 @@ void ACSProfile(FLevelLocals *Level, FCommandLine &argv) static const uint8_t sort_match_len[] = { 1, 2, 2, 1, 1 }; TArray ScriptProfiles, FuncProfiles; - long limit = 10; + int limit = 10; int (*sorter)(const void *, const void *) = sort_by_total_instr; assert(countof(sort_names) == countof(sort_match_len)); @@ -10718,7 +10853,7 @@ void ACSProfile(FLevelLocals *Level, FCommandLine &argv) { // If it's a number, set the display limit. char *endptr; - long num = strtol(argv[i], &endptr, 0); + int num = (int)strtoll(argv[i], &endptr, 0); if (endptr != argv[i]) { limit = num; diff --git a/src/playsim/p_acs.h b/src/playsim/p_acs.h index 7c31068a03a..695b2294883 100644 --- a/src/playsim/p_acs.h +++ b/src/playsim/p_acs.h @@ -37,13 +37,13 @@ #include "doomtype.h" #include "dthinker.h" -#include "doomerrors.h" +#include "engineerrors.h" +#include "files.h" #define LOCAL_SIZE 20 #define NUM_MAPVARS 128 class FFont; -class FileReader; struct line_t; class FSerializer; diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index b8b3ab7dacc..4a647af4efd 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -50,7 +50,7 @@ #include "decallib.h" #include "p_local.h" #include "c_console.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "a_sharedglobal.h" #include "v_font.h" #include "doomstat.h" @@ -69,20 +69,23 @@ #include "sbar.h" #include "actorinlines.h" #include "types.h" +#include "model.h" +#include "shadowinlines.h" +#include "i_time.h" static FRandom pr_camissile ("CustomActorfire"); static FRandom pr_cabullet ("CustomBullet"); static FRandom pr_cwjump ("CustomWpJump"); static FRandom pr_cwpunch ("CustomWpPunch"); static FRandom pr_grenade ("ThrowGrenade"); -static FRandom pr_crailgun ("CustomRailgun"); + FRandom pr_crailgun ("CustomRailgun"); static FRandom pr_spawndebris ("SpawnDebris"); static FRandom pr_spawnitemex ("SpawnItemEx"); static FRandom pr_burst ("Burst"); static FRandom pr_monsterrefire ("MonsterRefire"); static FRandom pr_teleport("A_Teleport"); static FRandom pr_bfgselfdamage("BFGSelfDamage"); -FRandom pr_cajump("CustomJump"); + FRandom pr_cajump("CustomJump"); //========================================================================== // @@ -126,9 +129,8 @@ static int CallStateChain (AActor *self, AActor *actor, FState *state) if (state->ActionFunc->Unsafe) { // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. - auto owner = FState::StaticFindStateOwner(state); Printf(TEXTCOLOR_RED "Unsafe state call in state %s to %s which accesses user variables. The action function has been removed from this state\n", - FState::StaticGetStateName(state).GetChars(), state->ActionFunc->PrintableName.GetChars()); + FState::StaticGetStateName(state).GetChars(), state->ActionFunc->PrintableName); state->ActionFunc = nullptr; } @@ -383,7 +385,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCVar) PARAM_SELF_PROLOGUE(AActor); PARAM_STRING(cvarname); - FBaseCVar *cvar = GetCVar(self->player ? int(self->player - players) : -1, cvarname); + FBaseCVar *cvar = GetCVar(self->player ? int(self->player - players) : -1, cvarname.GetChars()); if (cvar == nullptr) { ret->SetFloat(0); @@ -413,7 +415,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCVarString) PARAM_SELF_PROLOGUE(AActor); PARAM_STRING(cvarname); - FBaseCVar *cvar = GetCVar(self->player? int(self->player - players) : -1, cvarname); + FBaseCVar *cvar = GetCVar(self->player? int(self->player - players) : -1, cvarname.GetChars()); if (cvar == nullptr) { ret->SetString(""); @@ -715,13 +717,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlaySoundEx) if (!looping) { - S_Sound (self, int(channel) - NAME_Auto, 0, soundid, 1, attenuation); + S_Sound (self, channel.GetIndex() - NAME_Auto, 0, soundid, 1, attenuation); } else { - if (!S_IsActorPlayingSomething (self, int(channel) - NAME_Auto, soundid)) + if (!S_IsActorPlayingSomething (self, channel.GetIndex() - NAME_Auto, soundid)) { - S_Sound (self, (int(channel) - NAME_Auto), CHANF_LOOP, soundid, 1, attenuation); + S_Sound (self, (channel.GetIndex() - NAME_Auto), CHANF_LOOP, soundid, 1, attenuation); } } return 0; @@ -734,7 +736,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_StopSoundEx) if (channel > NAME_Auto && channel <= NAME_SoundSlot7) { - S_StopSound (self, int(channel) - NAME_Auto); + S_StopSound (self, channel.GetIndex() - NAME_Auto); } return 0; } @@ -764,7 +766,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SeekerMissile) { self->tracer = P_RoughMonsterSearch (self, distance, true); } - if (!P_SeekerMissile(self, clamp(ang1, 0, 90), clamp(ang2, 0, 90), !!(flags & SMF_PRECISE), !!(flags & SMF_CURSPEED))) + if (!P_SeekerMissile(self, DAngle::fromDeg(clamp(ang1, 0, 90)), DAngle::fromDeg(clamp(ang2, 0, 90)), !!(flags & SMF_PRECISE), !!(flags & SMF_CURSPEED))) { if (flags & SMF_LOOK) { // This monster is no longer seekable, so let us look for another one next time. @@ -794,7 +796,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) S_Sound (self, CHAN_WEAPON, 0, self->AttackSound, 1, ATTN_NORM); for (i = self->GetMissileDamage (0, 1); i > 0; --i) { - DAngle angle = self->Angles.Yaw + pr_cabullet.Random2() * (5.625 / 256.); + DAngle angle = self->Angles.Yaw + DAngle::fromDeg(pr_cabullet.Random2() * (5.625 / 256.)); int damage = ((pr_cabullet()%5)+1)*3; P_LineAttack(self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff); @@ -845,6 +847,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RadiusDamageSelf) int actualDamage; double actualDistance; + if (self->target == nullptr) return 0; actualDistance = self->Distance3D(self->target); if (actualDistance < distance) { @@ -929,7 +932,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnProjectile) { if (ti) { - DAngle angle = self->Angles.Yaw - 90; + DAngle angle = self->Angles.Yaw - DAngle::fromDeg(90.); double x = Spawnofs_xy * angle.Cos(); double y = Spawnofs_xy * angle.Sin(); double z = Spawnheight + self->GetBobOffset() - 32 + (self->player? self->player->crouchoffset : 0.); @@ -1072,9 +1075,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomMeleeAttack) return 0; A_FaceTarget (self); - if (self->CheckMeleeRange ()) + if (P_CheckMeleeRange(self)) { - if (meleesound) + if (meleesound.isvalid()) S_Sound (self, CHAN_WEAPON, 0, meleesound, 1, ATTN_NORM); int newdam = P_DamageMobj (self->target, self, self, damage, damagetype); if (bleed) @@ -1082,7 +1085,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomMeleeAttack) } else { - if (misssound) + if (misssound.isvalid()) S_Sound (self, CHAN_WEAPON, 0, misssound, 1, ATTN_NORM); } return 0; @@ -1107,11 +1110,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomComboAttack) return 0; A_FaceTarget (self); - if (self->CheckMeleeRange()) + if (P_CheckMeleeRange(self)) { if (damagetype == NAME_None) damagetype = NAME_Melee; // Melee is the default type - if (meleesound) + if (meleesound.isvalid()) S_Sound (self, CHAN_WEAPON, 0, meleesound, 1, ATTN_NORM); int newdam = P_DamageMobj (self->target, self, self, damage, damagetype); if (bleed) @@ -1200,7 +1203,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomRailgun) { self->Angles.Yaw = self->AngleTo(self->target); } - self->Angles.Pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE, &t, 60., 0, aim ? self->target : NULL); + self->Angles.Pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE, &t, DAngle::fromDeg(60.), 0, aim ? self->target.Get() : nullptr); if (t.linetarget == NULL && aim) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. @@ -1224,11 +1227,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomRailgun) self->Angles.Yaw = self->AngleTo(self->target,- self->target->Vel.X * veleffect, -self->target->Vel.Y * veleffect); } - if (self->target->flags & MF_SHADOW) - { - DAngle rnd = pr_crailgun.Random2() * (45. / 256.); - self->Angles.Yaw += rnd; - } + A_CustomRailgun_ShadowHandling(self, spawnofs_xy, spawnofs_z, spread_xy, flags); } if (!(flags & CRF_EXPLICITANGLE)) @@ -1274,7 +1273,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Recoil) PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(xyvel); - self->Thrust(self->Angles.Yaw + 180., xyvel); + self->Thrust(self->Angles.Yaw + DAngle::fromDeg(180.), xyvel); return 0; } @@ -1293,7 +1292,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Print) PARAM_FLOAT (time); PARAM_NAME (fontname); - if (text[0] == '$') text = GStrings(&text[1]); + if (text[0] == '$') text = GStrings.GetString(&text[1]); if (self->CheckLocalView() || (self->target != NULL && self->target->CheckLocalView())) { @@ -1302,13 +1301,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Print) if (fontname != NAME_None) { - font = V_GetFont(fontname); + font = V_GetFont(fontname.GetChars()); } if (time > 0) { con_midtime = float(time); } - FString formatted = strbin1(text); + FString formatted = strbin1(text.GetChars()); C_MidPrint(font, formatted.GetChars()); con_midtime = saved; } @@ -1331,16 +1330,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_PrintBold) float saved = con_midtime; FFont *font = NULL; - if (text[0] == '$') text = GStrings(&text[1]); + if (text[0] == '$') text = GStrings.GetString(&text[1]); if (fontname != NAME_None) { - font = V_GetFont(fontname); + font = V_GetFont(fontname.GetChars()); } if (time > 0) { con_midtime = float(time); } - FString formatted = strbin1(text); + FString formatted = strbin1(text.GetChars()); C_MidPrint(font, formatted.GetChars(), true); con_midtime = saved; return 0; @@ -1360,8 +1359,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Log) if (local && !self->CheckLocalView()) return 0; - if (text[0] == '$') text = GStrings(&text[1]); - FString formatted = strbin1(text); + if (text[0] == '$') text = GStrings.GetString(&text[1]); + FString formatted = strbin1(text.GetChars()); Printf("%s\n", formatted.GetChars()); return 0; } @@ -1397,7 +1396,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LogFloat) if (local && !self->CheckLocalView()) return 0; IGNORE_FORMAT_PRE - Printf("%H\n", num); + Printf("%g\n", num); IGNORE_FORMAT_POST return 0; } @@ -1609,15 +1608,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnDebris) // A_SpawnParticle // //=========================================================================== -enum SPFflag -{ - SPF_FULLBRIGHT = 1, - SPF_RELPOS = 1 << 1, - SPF_RELVEL = 1 << 2, - SPF_RELACCEL = 1 << 3, - SPF_RELANG = 1 << 4, - SPF_NOTIMEFREEZE = 1 << 5, -}; DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticle) { @@ -1648,7 +1638,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticle) if (flags & SPF_RELANG) angle += self->Angles.Yaw; double s = angle.Sin(); double c = angle.Cos(); - DVector3 pos(xoff, yoff, zoff); + DVector3 pos(xoff, yoff, zoff + self->GetBobOffset()); DVector3 vel(xvel, yvel, zvel); DVector3 acc(accelx, accely, accelz); //[MC] Code ripped right out of A_SpawnItemEx. @@ -1674,6 +1664,76 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticle) return 0; } +DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticleEx) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_COLOR (color); + PARAM_INT (i_texid) + PARAM_INT (style) + PARAM_INT (flags) + PARAM_INT (lifetime) + PARAM_FLOAT (size) + PARAM_ANGLE (angle) + PARAM_FLOAT (xoff) + PARAM_FLOAT (yoff) + PARAM_FLOAT (zoff) + PARAM_FLOAT (xvel) + PARAM_FLOAT (yvel) + PARAM_FLOAT (zvel) + PARAM_FLOAT (accelx) + PARAM_FLOAT (accely) + PARAM_FLOAT (accelz) + PARAM_FLOAT (startalpha) + PARAM_FLOAT (fadestep) + PARAM_FLOAT (sizestep) + PARAM_FLOAT (startroll) + PARAM_FLOAT (rollvel) + PARAM_FLOAT (rollacc) + + startalpha = clamp(startalpha, 0., 1.); + fadestep = clamp(fadestep, -1.0, 1.0); + + size = fabs(size); + if (lifetime != 0) + { + if (flags & SPF_RELANG) angle += self->Angles.Yaw; + double s = angle.Sin(); + double c = angle.Cos(); + DVector3 pos(xoff, yoff, zoff + self->GetBobOffset()); + DVector3 vel(xvel, yvel, zvel); + DVector3 acc(accelx, accely, accelz); + //[MC] Code ripped right out of A_SpawnItemEx. + if (flags & SPF_RELPOS) + { + // in relative mode negative y values mean 'left' and positive ones mean 'right' + // This is the inverse orientation of the absolute mode! + pos.X = xoff * c + yoff * s; + pos.Y = xoff * s - yoff * c; + } + if (flags & SPF_RELVEL) + { + vel.X = xvel * c + yvel * s; + vel.Y = xvel * s - yvel * c; + } + if (flags & SPF_RELACCEL) + { + acc.X = accelx * c + accely * s; + acc.Y = accelx * s - accely * c; + } + + FTextureID texid; + texid.SetIndex(i_texid); + + if(style < 0 || style >= STYLE_Count) + { + style = STYLE_None; + } + + P_SpawnParticle(self->Level, self->Vec3Offset(pos), vel, acc, color, startalpha, lifetime, size, fadestep, sizestep, flags, texid, ERenderStyle(style), startroll, rollvel, rollacc); + } + return 0; +} + //=========================================================================== // // A_CheckSight @@ -1920,9 +1980,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Burst) // base the number of shards on the size of the dead thing, so bigger // things break up into more shards than smaller things. // An self with radius 20 and height 64 creates ~40 chunks. - numChunks = MAX (4, int(self->radius * self->Height)/32); + numChunks = max (4, int(self->radius * self->Height)/32); i = (pr_burst.Random2()) % (numChunks/4); - for (i = MAX (24, numChunks + i); i >= 0; i--) + for (i = max (24, numChunks + i); i >= 0; i--) { double xo = (pr_burst() - 128) * self->radius / 128; double yo = (pr_burst() - 128) * self->radius / 128; @@ -1985,7 +2045,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Respawn) } else { - oktorespawn = P_CheckPosition(self, self->Pos(), true); + oktorespawn = P_CheckPosition(self, self->Pos().XY(), true); } if (oktorespawn) @@ -2018,6 +2078,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Respawn) self->flags6 = defs->flags6; self->flags7 = defs->flags7; self->flags8 = defs->flags8; + self->flags9 = defs->flags9; self->SetState (self->SpawnState); self->renderflags &= ~RF_INVISIBLE; @@ -2421,7 +2482,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckIfTargetInLOS) else { // Does the player aim at something that can be shot? - P_AimLineAttack(self, self->Angles.Yaw, MISSILERANGE, &t, (flags & JLOSF_NOAUTOAIM) ? 0.5 : 0., ALF_PORTALRESTRICT); + P_AimLineAttack(self, self->Angles.Yaw, MISSILERANGE, &t, DAngle::fromDeg((flags & JLOSF_NOAUTOAIM) ? 0.5 : 0.), ALF_PORTALRESTRICT); if (!t.linetarget) { @@ -2433,14 +2494,14 @@ DEFINE_ACTION_FUNCTION(AActor, CheckIfTargetInLOS) { case JLOSF_TARGETLOS|JLOSF_FLIPFOV: // target makes sight check, player makes fov check; player has verified fov - fov = 0.; + fov = nullAngle; // fall-through case JLOSF_TARGETLOS: doCheckSight = !(flags & JLOSF_NOSIGHT); // The target is responsible for sight check and fov break; default: // player has verified sight and fov - fov = 0.; + fov = nullAngle; // fall-through case JLOSF_FLIPFOV: // Player has verified sight, but target must verify fov doCheckSight = false; @@ -2471,7 +2532,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckIfTargetInLOS) ACTION_RETURN_BOOL(false); } if (flags & JLOSF_CLOSENOFOV) - fov = 0.; + fov = nullAngle; if (flags & JLOSF_CLOSENOSIGHT) doCheckSight = false; @@ -2491,9 +2552,9 @@ DEFINE_ACTION_FUNCTION(AActor, CheckIfTargetInLOS) else { target = viewport; viewport = self; } } - fov = MIN(fov, 360.); + fov = min(fov, DAngle::fromDeg(360.)); - if (fov > 0) + if (fov > nullAngle) { DAngle an = absangle(viewport->AngleTo(target), viewport->Angles.Yaw); @@ -2565,13 +2626,13 @@ DEFINE_ACTION_FUNCTION(AActor, CheckIfInTargetLOS) ACTION_RETURN_BOOL(false); } if (flags & JLOSF_CLOSENOFOV) - fov = 0.; + fov = nullAngle; if (flags & JLOSF_CLOSENOSIGHT) doCheckSight = false; } - if (fov > 0 && (fov < 360.)) + if (fov > nullAngle && (fov < DAngle::fromDeg(360.))) { DAngle an = absangle(target->AngleTo(self), target->Angles.Yaw); @@ -2615,7 +2676,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckFlag) PARAM_INT (checkpointer); AActor *owner = COPY_AAPTR(self, checkpointer); - ACTION_RETURN_BOOL(owner != nullptr && CheckActorFlag(owner, flagname)); + ACTION_RETURN_BOOL(owner != nullptr && CheckActorFlag(owner, flagname.GetChars())); } @@ -2792,24 +2853,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRefire) // Set actor's angle (in degrees). // //=========================================================================== -enum -{ - SPF_FORCECLAMP = 1, // players always clamp - SPF_INTERPOLATE = 2, -}; - DEFINE_ACTION_FUNCTION(AActor, A_SetAngle) { PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT(angle); + PARAM_ANGLE(angle); PARAM_INT(flags); PARAM_INT(ptr); AActor *ref = COPY_AAPTR(self, ptr); if (ref != NULL) { - ref->SetAngle(angle, !!(flags & SPF_INTERPOLATE)); + ref->SetAngle(angle, flags); } return 0; } @@ -2825,7 +2880,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetAngle) DEFINE_ACTION_FUNCTION(AActor, A_SetPitch) { PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT(pitch); + PARAM_ANGLE(pitch); PARAM_INT(flags); PARAM_INT(ptr); @@ -2833,7 +2888,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetPitch) if (ref != NULL) { - ref->SetPitch(pitch, !!(flags & SPF_INTERPOLATE), !!(flags & SPF_FORCECLAMP)); + ref->SetPitch(pitch, flags); } return 0; } @@ -2849,15 +2904,102 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetPitch) DEFINE_ACTION_FUNCTION(AActor, A_SetRoll) { PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT (roll); + PARAM_ANGLE (roll); PARAM_INT (flags); PARAM_INT (ptr) ; AActor *ref = COPY_AAPTR(self, ptr); if (ref != NULL) { - ref->SetRoll(roll, !!(flags & SPF_INTERPOLATE)); + ref->SetRoll(roll, flags); + } + return 0; +} + +//=========================================================================== +// +// A_SetViewAngle +// +// Set actor's viewangle (in degrees). +// +//=========================================================================== + +static void SetViewAngleNative(AActor* self, double angle, int flags, int ptr) +{ + AActor *ref = COPY_AAPTR(self, ptr); + if (ref != nullptr) + { + ref->SetViewAngle(DAngle::fromDeg(angle), flags); + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SetViewAngle, SetViewAngleNative) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(angle); + PARAM_INT(flags); + PARAM_INT(ptr); + + SetViewAngleNative(self, angle, flags, ptr); + + return 0; +} + +//=========================================================================== +// +// A_SetViewPitch +// +// Set actor's viewpitch (in degrees). +// +//=========================================================================== + +static void SetViewPitchNative(AActor* self, double pitch, int flags, int ptr) +{ + AActor *ref = COPY_AAPTR(self, ptr); + if (ref != nullptr) + { + ref->SetViewPitch(DAngle::fromDeg(pitch), flags); } +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SetViewPitch, SetViewPitchNative) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(pitch); + PARAM_INT(flags); + PARAM_INT(ptr); + + SetViewPitchNative(self, pitch, flags, ptr); + + return 0; +} + +//=========================================================================== +// +// [MC] A_SetViewRoll +// +// Set actor's viewroll (in degrees). +// +//=========================================================================== + +static void SetViewRollNative(AActor* self, double roll, int flags, int ptr) +{ + AActor *ref = COPY_AAPTR(self, ptr); + if (ref != nullptr) + { + ref->SetViewRoll(DAngle::fromDeg(roll), flags); + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SetViewRoll, SetViewRollNative) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(roll); + PARAM_INT(flags); + PARAM_INT(ptr); + + SetViewRollNative(self, roll, flags, ptr); + return 0; } @@ -3178,10 +3320,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_Teleport) DEFINE_ACTION_FUNCTION(AActor, A_Quake) { PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (intensity); + PARAM_FLOAT (intensity); PARAM_INT (duration); - PARAM_INT (damrad); - PARAM_INT (tremrad); + PARAM_FLOAT (damrad); + PARAM_FLOAT (tremrad); PARAM_SOUND (sound); P_StartQuake(self->Level, self, 0, intensity, duration, damrad, tremrad, sound); @@ -3199,23 +3341,26 @@ DEFINE_ACTION_FUNCTION(AActor, A_Quake) DEFINE_ACTION_FUNCTION(AActor, A_QuakeEx) { PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(intensityX); - PARAM_INT(intensityY); - PARAM_INT(intensityZ); + PARAM_FLOAT(intensityX); + PARAM_FLOAT(intensityY); + PARAM_FLOAT(intensityZ); PARAM_INT(duration); - PARAM_INT(damrad); - PARAM_INT(tremrad); + PARAM_FLOAT(damrad); + PARAM_FLOAT(tremrad); PARAM_SOUND(sound); PARAM_INT(flags); PARAM_FLOAT(mulWaveX); PARAM_FLOAT(mulWaveY); PARAM_FLOAT(mulWaveZ); - PARAM_INT(falloff); + PARAM_FLOAT(falloff); PARAM_INT(highpoint); PARAM_FLOAT(rollIntensity); PARAM_FLOAT(rollWave); + PARAM_FLOAT(damageMultiplier); + PARAM_FLOAT(thrustMultiplier); + PARAM_INT(damage); P_StartQuakeXYZ(self->Level, self, 0, intensityX, intensityY, intensityZ, duration, damrad, tremrad, sound, flags, mulWaveX, mulWaveY, mulWaveZ, falloff, highpoint, - rollIntensity, rollWave); + rollIntensity, rollWave, damageMultiplier, thrustMultiplier, damage); return 0; } @@ -3234,7 +3379,7 @@ void A_Weave(AActor *self, int xyspeed, int zspeed, double xydist, double zdist) weaveXY = self->WeaveIndexXY & 63; weaveZ = self->WeaveIndexZ & 63; - angle = self->Angles.Yaw + 90; + angle = self->Angles.Yaw + DAngle::fromDeg(90); if (xydist != 0 && xyspeed != 0) { @@ -3349,7 +3494,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WolfAttack) // Target can dodge if it can see enemy DAngle angle = absangle(self->target->Angles.Yaw, self->target->AngleTo(self)); - bool dodge = (P_CheckSight(self->target, self) && angle < 30. * 256. / 360.); // 30 byteangles ~ 21� + bool dodge = (P_CheckSight(self->target, self) && angle < DAngle::fromDeg(30. * 256. / 360.)); // 30 byteangles ~ 21° // Distance check is simplistic DVector2 vec = self->Vec2To(self->target); @@ -3371,7 +3516,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WolfAttack) hitchance -= idist * (dodge ? 16 : 8); // While we're here, we may as well do something for this: - if (self->target->flags & MF_SHADOW) + if (A_WolfAttack_ShadowHandling(self)) { hitchance >>= 2; } @@ -4597,7 +4742,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckBlock) if (flags & CBF_NOACTORS) fpass |= PCM_NOACTORS; if (flags & CBF_NOLINES) fpass |= PCM_NOLINES; mobj->SetZ(pos.Z); - checker = P_CheckMove(mobj, pos, fpass); + checker = P_CheckMove(mobj, pos.XY(), fpass); mobj->SetZ(oldpos.Z); } else @@ -4668,16 +4813,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FaceMovementDirection) //Done because using anglelimit directly causes a signed/unsigned mismatch. //Code borrowed from A_Face*. - if (anglelimit > 0) + if (anglelimit > nullAngle) { DAngle delta = -deltaangle(current, angle); if (fabs(delta) > anglelimit) { - if (delta < 0) + if (delta < nullAngle) { current += anglelimit + offset; } - else if (delta > 0) + else if (delta > nullAngle) { current -= anglelimit + offset; } @@ -4695,19 +4840,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_FaceMovementDirection) DAngle current = mobj->Angles.Pitch; const DVector2 velocity = mobj->Vel.XY(); DAngle pitch = -VecToAngle(velocity.Length(), mobj->Vel.Z); - if (pitchlimit > 0) + if (pitchlimit > nullAngle) { DAngle pdelta = deltaangle(current, pitch); if (fabs(pdelta) > pitchlimit) { - if (pdelta > 0) + if (pdelta > nullAngle) { - current -= MIN(pitchlimit, pdelta); + current -= min(pitchlimit, pdelta); } else //if (pdelta < 0) { - current += MIN(pitchlimit, -pdelta); + current += min(pitchlimit, -pdelta); } mobj->SetPitch(current, !!(flags & FMDF_INTERPOLATE)); } @@ -4775,10 +4920,10 @@ enum VRFFlags DEFINE_ACTION_FUNCTION(AActor, A_SetVisibleRotation) { PARAM_SELF_PROLOGUE(AActor); - PARAM_ANGLE(anglestart) - PARAM_ANGLE(angleend) - PARAM_ANGLE(pitchstart) - PARAM_ANGLE(pitchend) + PARAM_FANGLE(anglestart) + PARAM_FANGLE(angleend) + PARAM_FANGLE(pitchstart) + PARAM_FANGLE(pitchend) PARAM_INT(flags) PARAM_INT(ptr) @@ -4838,7 +4983,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) if (self->Z() == sec->floorplane.ZatPoint(self) && sec->PortalBlocksMovement(sector_t::floor)) { - if (sec->special == Damage_InstantDeath) + if (sec->damageamount >= TELEFRAG_DAMAGE) { P_DamageMobj(self, NULL, NULL, 999, NAME_InstantDeath); } @@ -4846,7 +4991,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) { int anglespeed = self->Level->GetFirstSectorTag(sec) - 100; double speed = (anglespeed % 10) / 16.; - DAngle an = (anglespeed / 10) * (360 / 8.); + DAngle an = DAngle::fromDeg((anglespeed / 10) * (360 / 8.)); self->Thrust(an, speed); } } @@ -4917,7 +5062,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_SprayDecal) PARAM_SELF_PROLOGUE(AActor); PARAM_STRING(name); PARAM_FLOAT(dist); - SprayDecal(self, name, dist); + PARAM_FLOAT(offset_x); + PARAM_FLOAT(offset_y); + PARAM_FLOAT(offset_z); + PARAM_FLOAT(direction_x); + PARAM_FLOAT(direction_y); + PARAM_FLOAT(direction_z); + PARAM_BOOL(useBloodColor); + PARAM_COLOR(decalColor); + SprayDecal(self, name.GetChars(), dist, DVector3(offset_x, offset_y, offset_z), DVector3(direction_x, direction_y, direction_z), useBloodColor, decalColor); return 0; } @@ -4926,7 +5079,490 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetMugshotState) PARAM_SELF_PROLOGUE(AActor); PARAM_STRING(name); if (self->CheckLocalView()) - StatusBar->SetMugShotState(name); + StatusBar->SetMugShotState(name.GetChars()); + return 0; +} + +//========================================================================== +// +// A_ChangeModel(modeldef, modelpath, model, modelindex, skinpath, skin, skinid, flags) +// +// This function allows the changing of an actor's modeldef, or models and/or skins at a given index +//========================================================================== + +static void EnsureModelData(AActor * mobj) +{ + if (mobj->modelData == nullptr) + { + auto ptr = Create(); + + ptr->flags = (mobj->hasmodel ? MODELDATA_HADMODEL : 0); + ptr->modelDef = nullptr; + + mobj->modelData = ptr; + mobj->hasmodel = true; + GC::WriteBarrier(mobj, ptr); + } +} + +static void CleanupModelData(AActor * mobj) +{ + if ( !(mobj->flags9 & MF9_DECOUPLEDANIMATIONS) + && mobj->modelData->models.Size() == 0 + && mobj->modelData->modelFrameGenerators.Size() == 0 + && mobj->modelData->skinIDs.Size() == 0 + && mobj->modelData->animationIDs.Size() == 0 + && mobj->modelData->modelDef == nullptr + &&(mobj->modelData->flags & ~MODELDATA_HADMODEL) == 0 ) + { + mobj->hasmodel = mobj->modelData->flags & MODELDATA_HADMODEL; + mobj->modelData->Destroy(); + mobj->modelData = nullptr; + } +} + +enum ESetAnimationFlags +{ + SAF_INSTANT = 1 << 0, + SAF_LOOP = 1 << 1, + SAF_NOOVERRIDE = 1 << 2, +}; + +extern double getCurrentFrame(const AnimOverride &anim, double tic); + +void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags, double ticFrac) +{ + if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self"); + + if(!(self->flags9 & MF9_DECOUPLEDANIMATIONS)) + { + ThrowAbortException(X_OTHER, "Cannot set animation for non-decoupled actors"); + } + + if(!BaseSpriteModelFrames.CheckKey(self->GetClass())) + { + ThrowAbortException(X_OTHER, "Actor class is missing a MODELDEF definition or a MODELDEF BaseFrame"); + } + + if(interpolateTics <= 0) interpolateTics = 1; + + EnsureModelData(self); + + if(animName == NAME_None) + { + self->modelData->curAnim.flags = ANIMOVERRIDE_NONE; + return; + } + + double tic = self->Level->totaltime; + if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !self->Level->isFrozen()) + { + tic += ticFrac; + } + + FModel * mdl = Models[(self->modelData->models.Size() > 0 && self->modelData->models[0].modelID >= 0) ? self->modelData->models[0].modelID : BaseSpriteModelFrames[self->GetClass()].modelIDs[0]]; + + int animStart = mdl->FindFirstFrame(animName); + if(animStart == FErr_NotFound) + { + self->modelData->curAnim.flags = ANIMOVERRIDE_NONE; + Printf("Could not find animation %s\n", animName.GetChars()); + return; + } + + if((flags & SAF_NOOVERRIDE) && self->modelData->curAnim.flags != ANIMOVERRIDE_NONE && self->modelData->curAnim.firstFrame == animStart) + { + //same animation as current, skip setting it + return; + } + + if(!(flags & SAF_INSTANT)) + { + self->modelData->prevAnim = self->modelData->curAnim; + } + + int animEnd = mdl->FindLastFrame(animName); + + if(framerate < 0) + { + framerate = mdl->FindFramerate(animName); + } + + int len = animEnd - animStart; + + if(startFrame >= len) + { + self->modelData->curAnim.flags = ANIMOVERRIDE_NONE; + Printf("frame %d (startFrame) is past the end of animation %s\n", startFrame, animName.GetChars()); + return; + } + else if(loopFrame >= len) + { + self->modelData->curAnim.flags = ANIMOVERRIDE_NONE; + Printf("frame %d (loopFrame) is past the end of animation %s\n", startFrame, animName.GetChars()); + return; + } + else if(endFrame >= len) + { + self->modelData->curAnim.flags = ANIMOVERRIDE_NONE; + Printf("frame %d (endFrame) is past the end of animation %s\n", endFrame, animName.GetChars()); + return; + } + + self->modelData->curAnim.firstFrame = animStart; + self->modelData->curAnim.lastFrame = endFrame < 0 ? animEnd - 1 : animStart + endFrame; + self->modelData->curAnim.startFrame = startFrame < 0 ? animStart : animStart + startFrame; + self->modelData->curAnim.loopFrame = loopFrame < 0 ? animStart : animStart + loopFrame; + self->modelData->curAnim.flags = (flags&SAF_LOOP) ? ANIMOVERRIDE_LOOP : 0; + self->modelData->curAnim.framerate = (float)framerate; + + if(!(flags & SAF_INSTANT)) + { + self->modelData->prevAnim.startFrame = getCurrentFrame(self->modelData->prevAnim, tic); + + int startTic = floor(tic) + interpolateTics; + self->modelData->curAnim.startTic = startTic; + self->modelData->curAnim.switchOffset = startTic - tic; + } + else + { + self->modelData->curAnim.startTic = tic; + self->modelData->curAnim.switchOffset = 0; + } +} + +void SetAnimationNative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags) +{ + SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, 1); +} + +void SetAnimationUINative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags) +{ + SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, I_GetTimeFrac()); +} + +void SetAnimationFrameRateInternal(AActor * self, double framerate, double ticFrac) +{ + if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self"); + + if(!(self->flags9 & MF9_DECOUPLEDANIMATIONS)) + { + ThrowAbortException(X_OTHER, "Cannot set animation for non-decoupled actors"); + } + + EnsureModelData(self); + + if(self->modelData->curAnim.flags & ANIMOVERRIDE_NONE) return; + + if(framerate < 0) + { + ThrowAbortException(X_OTHER, "Cannot set negative framerate"); + } + + + double tic = self->Level->totaltime; + if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !self->Level->isFrozen()) + { + tic += ticFrac; + } + + if(self->modelData->curAnim.startTic >= tic) + { + self->modelData->curAnim.framerate = (float)framerate; + return; + } + + double frame = getCurrentFrame(self->modelData->curAnim, tic); + + self->modelData->curAnim.startFrame = frame; + self->modelData->curAnim.startTic = tic; + self->modelData->curAnim.switchOffset = 0; + self->modelData->curAnim.framerate = (float)framerate; +} + +void SetAnimationFrameRateNative(AActor * self, double framerate) +{ + SetAnimationFrameRateInternal(self, framerate, 1); +} + +void SetAnimationFrameRateUINative(AActor * self, double framerate) +{ + SetAnimationFrameRateInternal(self, framerate, I_GetTimeFrac()); +} + +void SetModelFlag(AActor * self, int flag) +{ + EnsureModelData(self); + self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS; + self->modelData->overrideFlagsSet |= flag; + self->modelData->overrideFlagsClear &= ~flag; +} + +void ClearModelFlag(AActor * self, int flag) +{ + EnsureModelData(self); + self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS; + self->modelData->overrideFlagsClear |= flag; + self->modelData->overrideFlagsSet &= ~flag; +} + +void ResetModelFlags(AActor * self) +{ + if(self->modelData) + { + self->modelData->overrideFlagsClear = 0; + self->modelData->overrideFlagsSet = 0; + self->modelData->flags &= ~MODELDATA_OVERRIDE_FLAGS; + } +} + +enum ChangeModelFlags +{ + CMDL_WEAPONTOPLAYER = 1 << 0, + CMDL_HIDEMODEL = 1 << 1, + CMDL_USESURFACESKIN = 1 << 2, +}; + +void ChangeModelNative( + AActor * self, + AActor * invoker, + FStateParamInfo * stateinfo, + int i_modeldef, + int i_modelindex, + const FString &p_modelpath, + int i_model, + int i_skinindex, + const FString &p_skinpath, + int i_skin, + int flags, + int generatorindex, + int i_animationindex, + const FString &p_animationpath, + int i_animation +) { + if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self"); + + FName n_modeldef { ENamedName(i_modeldef) }; + FName model { ENamedName(i_model) }; + FName skin { ENamedName(i_skin) }; + FName animation { ENamedName(i_animation) }; + + PClass * modeldef = nullptr; + + if (n_modeldef != NAME_None && (modeldef = PClass::FindActor(n_modeldef.GetChars())) == nullptr) + { + Printf("Attempt to pass invalid modeldef name %s in %s.\n", n_modeldef.GetChars(), self->GetCharacterName()); + return; + } + + unsigned modelindex = i_modelindex < 0 ? 0 : i_modelindex; + unsigned skinindex = i_skinindex < 0 ? 0 : i_skinindex; + unsigned animationindex = i_animationindex < 0 ? 0 : i_animationindex; + + AActor* mobj = (ACTION_CALL_FROM_PSPRITE() && (flags & CMDL_WEAPONTOPLAYER)) || ACTION_CALL_FROM_INVENTORY() ? self : invoker; + + FString modelpath = p_modelpath; + FString skinpath = p_skinpath; + FString animationpath = p_animationpath; + + if (modelpath.Len() != 0 && modelpath[(int)modelpath.Len() - 1] != '/') modelpath += '/'; + if (skinpath.Len() != 0 && skinpath[(int)skinpath.Len() - 1] != '/') skinpath += '/'; + if (animationpath.Len() != 0 && animationpath[(int)animationpath.Len() - 1] != '/') animationpath += '/'; + + EnsureModelData(mobj); + + int queryModel = !(flags & CMDL_HIDEMODEL) ? model != NAME_None ? FindModel(modelpath.GetChars(), model.GetChars()) : -1 : -2; + int queryAnimation = animation != NAME_None ? FindModel(animationpath.GetChars(), animation.GetChars()) : -1; + + mobj->modelData->modelDef = modeldef; + + assert(mobj->modelData->models.Size() == mobj->modelData->modelFrameGenerators.Size()); + + if(mobj->modelData->models.Size() < modelindex) + { + mobj->modelData->models.AppendFill({-1, {}}, modelindex - mobj->modelData->models.Size()); + mobj->modelData->modelFrameGenerators.AppendFill(-1, modelindex - mobj->modelData->modelFrameGenerators.Size()); + } + + if(mobj->modelData->animationIDs.Size() < animationindex) + { + mobj->modelData->animationIDs.AppendFill(-1, animationindex - mobj->modelData->animationIDs.Size()); + } + + auto skindata = skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID(); + + if(mobj->modelData->models.Size() == modelindex) + { + + if(flags & CMDL_USESURFACESKIN && skinindex >= 0) + { + TArray surfaceSkins; + if(skinindex > 0) + { + surfaceSkins.AppendFill(FNullTextureID(), skinindex); + } + surfaceSkins.Push(skindata); + mobj->modelData->models.Push({queryModel, std::move(surfaceSkins)}); + mobj->modelData->modelFrameGenerators.Push(generatorindex); + } + else + { + mobj->modelData->models.Push({queryModel, {}}); + mobj->modelData->modelFrameGenerators.Push(generatorindex); + } + } + else + { + if(flags & CMDL_USESURFACESKIN && skinindex >= 0) + { + if(skinindex > mobj->modelData->models[modelindex].surfaceSkinIDs.Size()) + { + mobj->modelData->models[modelindex].surfaceSkinIDs.AppendFill(FNullTextureID(), skinindex - mobj->modelData->models[modelindex].surfaceSkinIDs.Size()); + } + + if(skinindex == mobj->modelData->models[modelindex].surfaceSkinIDs.Size()) + { + mobj->modelData->models[modelindex].surfaceSkinIDs.Push(skindata); + } + else + { + mobj->modelData->models[modelindex].surfaceSkinIDs[skinindex] = skindata; + } + } + if(queryModel != -1) mobj->modelData->models[modelindex].modelID = queryModel; + if(generatorindex != -1) mobj->modelData->modelFrameGenerators[modelindex] = generatorindex; + } + + if(mobj->modelData->animationIDs.Size() == animationindex) + { + mobj->modelData->animationIDs.Push(queryAnimation); + } + else + { + mobj->modelData->animationIDs[animationindex] = queryAnimation; + } + + if (!(flags & CMDL_USESURFACESKIN)) + { + if(mobj->modelData->skinIDs.Size() < skinindex) + { + mobj->modelData->skinIDs.AppendFill(FNullTextureID(), skinindex - mobj->modelData->skinIDs.Size()); + } + + if(mobj->modelData->skinIDs.Size() == skinindex) + { + mobj->modelData->skinIDs.Push(skindata); + } + else + { + mobj->modelData->skinIDs[skinindex] = skindata; + } + } + + CleanupModelData(mobj); + + return; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_ChangeModel, ChangeModelNative) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_NAME(modeldef); + PARAM_INT(modelindex); + PARAM_STRING_VAL(modelpath); + PARAM_NAME(model); + PARAM_INT(skinindex); + PARAM_STRING_VAL(skinpath); + PARAM_NAME(skin); + PARAM_INT(flags); + PARAM_INT(generatorindex); + PARAM_INT(animationindex); + PARAM_STRING_VAL(animationpath); + PARAM_NAME(animation); + + ChangeModelNative(self,stateowner,stateinfo,modeldef.GetIndex(),modelindex,modelpath,model.GetIndex(),skinindex,skinpath,skin.GetIndex(),flags,generatorindex,animationindex,animationpath,animation.GetIndex()); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimation, SetAnimationNative) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_NAME(animName); + PARAM_FLOAT(framerate); + PARAM_INT(startFrame); + PARAM_INT(loopFrame); + PARAM_INT(endFrame); + PARAM_INT(interpolateTics); + PARAM_INT(flags); + + SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, 1); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationUI, SetAnimationUINative) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_NAME(animName); + PARAM_FLOAT(framerate); + PARAM_INT(startFrame); + PARAM_INT(loopFrame); + PARAM_INT(endFrame); + PARAM_INT(interpolateTics); + PARAM_INT(flags); + + SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, I_GetTimeFrac()); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationFrameRate, SetAnimationFrameRateNative) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_FLOAT(framerate); + + SetAnimationFrameRateInternal(self, framerate, 1); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationFrameRateUI, SetAnimationFrameRateUINative) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_FLOAT(framerate); + + SetAnimationFrameRateInternal(self, framerate, I_GetTimeFrac()); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetModelFlag, SetModelFlag) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(flag); + + SetModelFlag(self, flag); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearModelFlag, ClearModelFlag) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(flag); + + ClearModelFlag(self, flag); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, ResetModelFlags, ResetModelFlags) +{ + PARAM_ACTION_PROLOGUE(AActor); + + ResetModelFlags(self); + return 0; } diff --git a/src/playsim/p_destructible.cpp b/src/playsim/p_destructible.cpp index 126ddbd422c..8e8b94f18b7 100644 --- a/src/playsim/p_destructible.cpp +++ b/src/playsim/p_destructible.cpp @@ -448,11 +448,11 @@ static void PGRA_InsertIfCloser(TMap& damageGroupPos, int grou EXTERN_CVAR(Float, splashfactor); -void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, int bombdistance, FName damagetype, int fulldamagedistance) +void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, double bombdistance, FName damagetype, double fulldamagedistance) { TMap damageGroupPos; - double bombdistancefloat = 1. / (double)(bombdistance - fulldamagedistance); + double bombdistancefloat = 1.0 / (bombdistance - fulldamagedistance); // now, this is not entirely correct... but sector actions still _do_ require a valid source actor to trigger anything if (!bombspot) @@ -588,8 +588,8 @@ void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage int damage = 0; if (dst < bombdistance) { - dst = clamp(dst - (double)fulldamagedistance, 0, dst); - damage = (int)((double)bombdamage * (1. - dst * bombdistancefloat)); + dst = clamp(dst - fulldamagedistance, 0.0, dst); + damage = (int)((double)bombdamage * (1.0 - dst * bombdistancefloat)); if (bombsource == bombspot) damage = (int)(damage * splashfactor); } @@ -661,8 +661,8 @@ void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage int damage = 0; if (dst < bombdistance) { - dst = clamp(dst - (double)fulldamagedistance, 0, dst); - damage = (int)((double)bombdamage * (1. - dst * bombdistancefloat)); + dst = clamp(dst - fulldamagedistance, 0.0, dst); + damage = (int)((double)bombdamage * (1.0 - dst * bombdistancefloat)); if (bombsource == bombspot) damage = (int)(damage * splashfactor); } @@ -716,7 +716,7 @@ bool P_ProjectileHitLinedef(AActor* mo, line_t* line) } } - int wside = P_PointOnLineSide(mo->Pos(), line); + int wside = P_PointOnLineSide(mo->Pos().XY(), line); int oside = !wside; side_t* otherside = line->sidedef[oside]; // check if hit upper or lower part @@ -950,9 +950,9 @@ DEFINE_ACTION_FUNCTION(FDestructible, GeometryRadiusAttack) PARAM_OBJECT(bombspot, AActor); PARAM_OBJECT(bombsource, AActor); PARAM_INT(bombdamage); - PARAM_INT(bombdistance); + PARAM_FLOAT(bombdistance); PARAM_NAME(damagetype); - PARAM_INT(fulldamagedistance); + PARAM_FLOAT(fulldamagedistance); P_GeometryRadiusAttack(bombspot, bombsource, bombdamage, bombdistance, damagetype, fulldamagedistance); return 0; } diff --git a/src/playsim/p_destructible.h b/src/playsim/p_destructible.h index 24a95b6a48a..c4e6e9d2307 100644 --- a/src/playsim/p_destructible.h +++ b/src/playsim/p_destructible.h @@ -34,7 +34,7 @@ void P_DamageSector(sector_t* sector, AActor* source, int damage, FName damagety void P_DamageLinedef(line_t* line, AActor* source, int damage, FName damagetype, int side, DVector3 position, bool isradius, bool dogroups); void P_GeometryLineAttack(FTraceResults& trace, AActor* thing, int damage, FName damageType); -void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, int bombdistance, FName damagetype, int fulldamagedistance); +void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, double bombdistance, FName damagetype, double fulldamagedistance); bool P_ProjectileHitLinedef(AActor* projectile, line_t* line); bool P_ProjectileHitPlane(AActor* projectile, int part); diff --git a/src/playsim/p_effect.cpp b/src/playsim/p_effect.cpp index 58e2daf7166..459d267bef8 100644 --- a/src/playsim/p_effect.cpp +++ b/src/playsim/p_effect.cpp @@ -49,9 +49,16 @@ #include "vm.h" #include "actorinlines.h" #include "g_game.h" +#include "serializer_doom.h" + +#include "hwrenderer/scene/hw_drawstructs.h" + +#ifdef _MSC_VER +#pragma warning(disable: 6011) // dereference null pointer in thinker iterator +#endif CVAR (Int, cl_rockettrails, 1, CVAR_ARCHIVE); -CVAR (Bool, r_rail_smartspiral, 0, CVAR_ARCHIVE); +CVAR (Bool, r_rail_smartspiral, false, CVAR_ARCHIVE); CVAR (Int, r_rail_spiralsparsity, 1, CVAR_ARCHIVE); CVAR (Int, r_rail_trailsparsity, 1, CVAR_ARCHIVE); CVAR (Bool, r_particles, true, 0); @@ -99,15 +106,63 @@ static const struct ColorList { {NULL, 0, 0, 0 } }; -inline particle_t *NewParticle (FLevelLocals *Level) +inline particle_t *NewParticle (FLevelLocals *Level, bool replace = false) { particle_t *result = nullptr; - if (Level->InactiveParticles != NO_PARTICLE) + // [MC] Thanks to RaveYard and randi for helping me with this addition. + // Array's filled up + if (Level->InactiveParticles == NO_PARTICLE) + { + if (replace) + { + result = &Level->Particles[Level->OldestParticle]; + + // There should be NO_PARTICLE for the oldest's tnext + if (result->tprev != NO_PARTICLE) + { + // tnext: youngest to oldest + // tprev: oldest to youngest + + // 2nd oldest -> oldest + particle_t *nbottom = &Level->Particles[result->tprev]; + nbottom->tnext = NO_PARTICLE; + + // now oldest becomes youngest + Level->OldestParticle = result->tprev; + result->tnext = Level->ActiveParticles; + result->tprev = NO_PARTICLE; + Level->ActiveParticles = uint32_t(result - Level->Particles.Data()); + + // youngest -> 2nd youngest + particle_t* ntop = &Level->Particles[result->tnext]; + ntop->tprev = Level->ActiveParticles; + } + // [MC] Future proof this by resetting everything when replacing a particle. + auto tnext = result->tnext; + auto tprev = result->tprev; + *result = {}; + result->tnext = tnext; + result->tprev = tprev; + } + return result; + } + + // Array isn't full. + uint32_t current = Level->ActiveParticles; + result = &Level->Particles[Level->InactiveParticles]; + Level->InactiveParticles = result->tnext; + result->tnext = current; + result->tprev = NO_PARTICLE; + Level->ActiveParticles = uint32_t(result - Level->Particles.Data()); + + if (current != NO_PARTICLE) // More than one active particles { - result = &Level->Particles[Level->InactiveParticles]; - Level->InactiveParticles = result->tnext; - result->tnext = Level->ActiveParticles; - Level->ActiveParticles = uint32_t(result - Level->Particles.Data()); + particle_t* next = &Level->Particles[current]; + next->tprev = Level->ActiveParticles; + } + else // Just one active particle + { + Level->OldestParticle = Level->ActiveParticles; } return result; } @@ -138,20 +193,42 @@ void P_InitParticles (FLevelLocals *Level) void P_ClearParticles (FLevelLocals *Level) { int i = 0; - memset (Level->Particles.Data(), 0, Level->Particles.Size() * sizeof(particle_t)); + Level->OldestParticle = NO_PARTICLE; Level->ActiveParticles = NO_PARTICLE; Level->InactiveParticles = 0; for (auto &p : Level->Particles) + { + p = {}; + p.tprev = i - 1; p.tnext = ++i; + } Level->Particles.Last().tnext = NO_PARTICLE; + Level->Particles.Data()->tprev = NO_PARTICLE; } // Group particles by subsectors. Because particles are always // in motion, there is little benefit to caching this information // from one frame to the next. +// [MC] VisualThinkers hitches a ride here void P_FindParticleSubsectors (FLevelLocals *Level) { + // [MC] Hitch a ride on particle subsectors since VisualThinkers are effectively using the same kind of system. + for (uint32_t i = 0; i < Level->subsectors.Size(); i++) + { + Level->subsectors[i].sprites.Clear(); + } + // [MC] Not too happy about using an iterator for this but I can't think of another way to handle it. + // At least it's on its own statnum for maximum efficiency. + auto it = Level->GetThinkerIterator(NAME_None, STAT_VISUALTHINKER); + DVisualThinker* sp; + while (sp = it.Next()) + { + if (!sp->PT.subsector) sp->PT.subsector = Level->PointInRenderSubsector(sp->PT.Pos); + + sp->PT.subsector->sprites.Push(sp); + } + // End VisualThinker hitching. Now onto the particles. if (Level->ParticlesInSubsec.Size() < Level->subsectors.Size()) { Level->ParticlesInSubsec.Reserve (Level->subsectors.Size() - Level->ParticlesInSubsec.Size()); @@ -212,31 +289,38 @@ void P_InitEffects () void P_ThinkParticles (FLevelLocals *Level) { - int i; - particle_t *particle, *prev; - - i = Level->ActiveParticles; - prev = NULL; + int i = Level->ActiveParticles; + particle_t *particle = nullptr, *prev = nullptr; while (i != NO_PARTICLE) { particle = &Level->Particles[i]; i = particle->tnext; - if (!particle->notimefreeze && Level->isFrozen()) + if (Level->isFrozen() && !(particle->flags &SPF_NOTIMEFREEZE)) { + if(particle->flags & SPF_LOCAL_ANIM) + { + particle->animData.SwitchTic++; + } + prev = particle; continue; } - auto oldtrans = particle->alpha; particle->alpha -= particle->fadestep; particle->size += particle->sizestep; - if (particle->alpha <= 0 || oldtrans < particle->alpha || --particle->ttl <= 0 || (particle->size <= 0)) + if (particle->alpha <= 0 || --particle->ttl <= 0 || (particle->size <= 0)) { // The particle has expired, so free it - memset (particle, 0, sizeof(particle_t)); + *particle = {}; if (prev) prev->tnext = i; else Level->ActiveParticles = i; + + if (i != NO_PARTICLE) + { + particle_t *next = &Level->Particles[i]; + next->tprev = particle->tprev; + } particle->tnext = Level->InactiveParticles; Level->InactiveParticles = (int)(particle - Level->Particles.Data()); continue; @@ -248,6 +332,13 @@ void P_ThinkParticles (FLevelLocals *Level) particle->Pos.Y = newxy.Y; particle->Pos.Z += particle->Vel.Z; particle->Vel += particle->Acc; + + if(particle->flags & SPF_ROLL) + { + particle->Roll += particle->RollVel; + particle->RollVel += particle->RollAcc; + } + particle->subsector = Level->PointInRenderSubsector(particle->Pos); sector_t *s = particle->subsector->sector; // Handle crossing a sector portal. @@ -271,31 +362,33 @@ void P_ThinkParticles (FLevelLocals *Level) } } -enum PSFlag -{ - PS_FULLBRIGHT = 1, - PS_NOTIMEFREEZE = 1 << 5, -}; - void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size, - double fadestep, double sizestep, int flags) + double fadestep, double sizestep, int flags, FTextureID texture, ERenderStyle style, double startroll, double rollvel, double rollacc) { - particle_t *particle = NewParticle(Level); + particle_t *particle = NewParticle(Level, !!(flags & SPF_REPLACE)); if (particle) { particle->Pos = pos; - particle->Vel = vel; - particle->Acc = accel; + particle->Vel = FVector3(vel); + particle->Acc = FVector3(accel); particle->color = ParticleColor(color); particle->alpha = float(startalpha); - if (fadestep < 0) particle->fadestep = FADEFROMTTL(lifetime); + if ((fadestep < 0 && !(flags & SPF_NEGATIVE_FADESTEP)) || fadestep <= -1.0) particle->fadestep = FADEFROMTTL(lifetime); else particle->fadestep = float(fadestep); particle->ttl = lifetime; - particle->bright = !!(flags & PS_FULLBRIGHT); particle->size = size; particle->sizestep = sizestep; - particle->notimefreeze = !!(flags & PS_NOTIMEFREEZE); + particle->texture = texture; + particle->style = style; + particle->Roll = startroll; + particle->RollVel = rollvel; + particle->RollAcc = rollacc; + particle->flags = flags; + if(flags & SPF_LOCAL_ANIM) + { + TexAnim.InitStandaloneAnimation(particle->animData, texture, Level->maptime); + } } } @@ -341,15 +434,15 @@ static void MakeFountain (AActor *actor, int color1, int color2) if (particle) { - DAngle an = M_Random() * (360. / 256); + DAngle an = DAngle::fromDeg(M_Random() * (360. / 256)); double out = actor->radius * M_Random() / 256.; particle->Pos = actor->Vec3Angle(out, an, actor->Height + 1); if (out < actor->radius/8) - particle->Vel.Z += 10./3; + particle->Vel.Z += 10.f/3; else particle->Vel.Z += 3; - particle->Acc.Z -= 1./11; + particle->Acc.Z -= 1.f/11; if (M_Random() < 30) { particle->size = 4; particle->color = color2; @@ -374,7 +467,7 @@ void P_RunEffect (AActor *actor, int effects) double backy = -actor->radius * 2 * moveangle.Sin(); double backz = actor->Height * ((2. / 3) - actor->Vel.Z / 8); - DAngle an = moveangle + 90.; + DAngle an = moveangle + DAngle::fromDeg(90.); double speed; particle = JitterParticle (actor->Level, 3 + (M_Random() & 31)); @@ -388,8 +481,8 @@ void P_RunEffect (AActor *actor, int effects) speed = (M_Random () - 128) * (1./200); particle->Vel.X += speed * an.Cos(); particle->Vel.Y += speed * an.Sin(); - particle->Vel.Z -= 1./36; - particle->Acc.Z -= 1./20; + particle->Vel.Z -= 1.f/36; + particle->Acc.Z -= 1.f/20; particle->color = yellow; particle->size = 2; } @@ -406,8 +499,8 @@ void P_RunEffect (AActor *actor, int effects) speed = (M_Random () - 128) * (1./200); particle->Vel.X += speed * an.Cos(); particle->Vel.Y += speed * an.Sin(); - particle->Vel.Z += 1. / 80; - particle->Acc.Z += 1. / 40; + particle->Vel.Z += 1.f / 80; + particle->Acc.Z += 1.f / 40; if (M_Random () & 7) particle->color = grey2; else @@ -423,7 +516,7 @@ void P_RunEffect (AActor *actor, int effects) DVector3 pos = actor->Vec3Angle(-actor->radius * 2, moveangle, -actor->Height * actor->Vel.Z / 8 + actor->Height * (2. / 3)); - P_DrawSplash2 (actor->Level, 6, pos, moveangle + 180, 2, 2); + P_DrawSplash2 (actor->Level, 6, pos, moveangle + DAngle::fromDeg(180), 2, 2); } if (actor->fountaincolor) { @@ -440,6 +533,7 @@ void P_RunEffect (AActor *actor, int effects) &grey4, &white }; int color = actor->fountaincolor*2; + if (color < 0 || color >= 16) color = 0; MakeFountain (actor, *fountainColors[color], *fountainColors[color+1]); } if (effects & FX_RESPAWNINVUL) @@ -453,7 +547,7 @@ void P_RunEffect (AActor *actor, int effects) particle = JitterParticle (actor->Level, 16); if (particle != NULL) { - DAngle ang = M_Random() * (360 / 256.); + DAngle ang = DAngle::fromDeg(M_Random() * (360 / 256.)); DVector3 pos = actor->Vec3Angle(actor->radius, ang, 0); particle->Pos = pos; particle->color = *protectColors[M_Random() & 1]; @@ -499,7 +593,7 @@ void P_DrawSplash (FLevelLocals *Level, int count, const DVector3 &pos, DAngle a p->Acc.X += (M_Random () - 128) / 8192.; p->Acc.Y += (M_Random () - 128) / 8192.; p->Pos.Z = pos.Z - M_Random () / 64.; - angle += M_Random() * (45./256); + angle += DAngle::fromDeg(M_Random() * (45./256)); p->Pos.X = pos.X + (M_Random() & 15)*angle.Cos(); p->Pos.Y = pos.Y + (M_Random() & 15)*angle.Sin(); } @@ -548,16 +642,16 @@ void P_DrawSplash2 (FLevelLocals *Level, int count, const DVector3 &pos, DAngle p->size = 4; p->color = M_Random() & 0x80 ? color1 : color2; p->Vel.Z = M_Random() * zvel; - p->Acc.Z = -1 / 22.; + p->Acc.Z = -1 / 22.f; if (kind) { - an = angle + ((M_Random() - 128) * (180 / 256.)); + an = angle + DAngle::fromDeg((M_Random() - 128) * (180 / 256.)); p->Vel.X = M_Random() * an.Cos() / 2048.; p->Vel.Y = M_Random() * an.Sin() / 2048.; p->Acc.X = p->Vel.X / 16.; p->Acc.Y = p->Vel.Y / 16.; } - an = angle + ((M_Random() - 128) * (90 / 256.)); + an = angle + DAngle::fromDeg((M_Random() - 128) * (90 / 256.)); p->Pos.X = pos.X + ((M_Random() & 31) - 15) * an.Cos(); p->Pos.Y = pos.Y + ((M_Random() & 31) - 15) * an.Sin(); p->Pos.Z = pos.Z + (M_Random() + zadd - 128) * zspread; @@ -620,7 +714,7 @@ void P_DrawRailTrail(AActor *source, TArray &portalhits, int color1, AActor *mo = player->camera; double r = ((seg.start.Y - mo->Y()) * (-seg.dir.Y) - (seg.start.X - mo->X()) * (seg.dir.X)) / (seg.length * seg.length); r = clamp(r, 0., 1.); - seg.soundpos = seg.start + r * seg.dir; + seg.soundpos = seg.start.XY() + r * seg.dir.XY(); seg.sounddist = (seg.soundpos - mo->Pos()).LengthSquared(); } else @@ -647,8 +741,8 @@ void P_DrawRailTrail(AActor *source, TArray &portalhits, int color1, // Allow other sounds than 'weapons/railgf'! if (!source->player) sound = source->AttackSound; else if (source->player->ReadyWeapon) sound = source->player->ReadyWeapon->AttackSound; - else sound = 0; - if (!sound) sound = "weapons/railgf"; + else sound = NO_SOUND; + if (!sound.isvalid()) sound = S_FindSound("weapons/railgf"); // The railgun's sound is special. It gets played from the // point on the slug's trail that is closest to the hearing player. @@ -686,7 +780,7 @@ void P_DrawRailTrail(AActor *source, TArray &portalhits, int color1, color1 = color1 == 0 ? -1 : ParticleColor(color1); pos = trail[0].start; - deg = (double)SpiralOffset; + deg = DAngle::fromDeg(SpiralOffset); for (i = spiral_steps; i; i--) { particle_t *p = NewParticle (source->Level); @@ -695,19 +789,22 @@ void P_DrawRailTrail(AActor *source, TArray &portalhits, int color1, if (!p) return; - int spiralduration = (duration == 0) ? 35 : duration; + int spiralduration = (duration == 0) ? TICRATE : duration; p->alpha = 1.f; p->ttl = spiralduration; p->fadestep = FADEFROMTTL(spiralduration); p->size = 3; - p->bright = fullbright; + if(fullbright) + { + p->flags |= SPF_FULLBRIGHT; + } tempvec = DMatrix3x3(trail[segment].dir, deg) * trail[segment].extend; - p->Vel = tempvec * drift / 16.; + p->Vel = FVector3(tempvec * drift / 16.); p->Pos = tempvec + pos; pos += trail[segment].dir * stepsize; - deg += double(r_rail_spiralsparsity * 14); + deg += DAngle::fromDeg(r_rail_spiralsparsity * 14); lencount -= stepsize; if (color1 == -1) { @@ -784,7 +881,10 @@ void P_DrawRailTrail(AActor *source, TArray &portalhits, int color1, p->Acc.Z -= 1./4096; pos += trail[segment].dir * stepsize; lencount -= stepsize; - p->bright = fullbright; + if(fullbright) + { + p->flags |= SPF_FULLBRIGHT; + } if (color2 == -1) { @@ -896,3 +996,307 @@ void P_DisconnectEffect (AActor *actor) p->size = 4; } } + +//=========================================================================== +// +// ZScript Sprite (DVisualThinker) +// Concept by Major Cooke +// Most code borrowed by Actor and particles above +// +//=========================================================================== + +void DVisualThinker::Construct() +{ + PT = {}; + PT.Pos = { 0,0,0 }; + PT.Vel = { 0,0,0 }; + Offset = { 0,0 }; + Scale = { 1,1 }; + PT.Roll = 0.0; + PT.alpha = 1.0; + LightLevel = -1; + PT.texture = FTextureID(); + PT.style = STYLE_Normal; + PT.flags = 0; + Translation = NO_TRANSLATION; + PT.subsector = nullptr; + cursector = nullptr; + PT.color = 0xffffff; + spr = new HWSprite(); + AnimatedTexture.SetNull(); +} + +DVisualThinker::DVisualThinker() +{ + Construct(); +} + +void DVisualThinker::OnDestroy() +{ + PT.alpha = 0.0; // stops all rendering. + if(spr) + { + delete spr; + spr = nullptr; + } + Super::OnDestroy(); +} + +DVisualThinker* DVisualThinker::NewVisualThinker(FLevelLocals* Level, PClass* type) +{ + if (type == nullptr) + return nullptr; + else if (type->bAbstract) + { + Printf("Attempt to spawn an instance of abstract VisualThinker class %s\n", type->TypeName.GetChars()); + return nullptr; + } + else if (!type->IsDescendantOf(RUNTIME_CLASS(DVisualThinker))) + { + Printf("Attempt to spawn class not inherent to VisualThinker: %s\n", type->TypeName.GetChars()); + return nullptr; + } + + DVisualThinker *zs = static_cast(Level->CreateThinker(type, STAT_VISUALTHINKER)); + zs->Construct(); + return zs; +} + +static DVisualThinker* SpawnVisualThinker(FLevelLocals* Level, PClass* type) +{ + return DVisualThinker::NewVisualThinker(Level, type); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnVisualThinker, SpawnVisualThinker) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_CLASS_NOT_NULL(type, DVisualThinker); + DVisualThinker* zs = SpawnVisualThinker(self, type); + ACTION_RETURN_OBJECT(zs); +} + +void DVisualThinker::UpdateSpriteInfo() +{ + PT.style = ERenderStyle(GetRenderStyle()); + if((PT.flags & SPF_LOCAL_ANIM) && PT.texture != AnimatedTexture) + { + AnimatedTexture = PT.texture; + TexAnim.InitStandaloneAnimation(PT.animData, PT.texture, Level->maptime); + } +} + +// This runs just like Actor's, make sure to call Super.Tick() in ZScript. +void DVisualThinker::Tick() +{ + if (ObjectFlags & OF_EuthanizeMe) + return; + + // There won't be a standard particle for this, it's only for graphics. + if (!PT.texture.isValid()) + { + Printf("No valid texture, destroyed"); + Destroy(); + return; + } + + if (isFrozen()) + { // needed here because it won't retroactively update like actors do. + PT.subsector = Level->PointInRenderSubsector(PT.Pos); + cursector = PT.subsector->sector; + UpdateSpriteInfo(); + return; + } + Prev = PT.Pos; + PrevRoll = PT.Roll; + // Handle crossing a line portal + DVector2 newxy = Level->GetPortalOffsetPosition(PT.Pos.X, PT.Pos.Y, PT.Vel.X, PT.Vel.Y); + PT.Pos.X = newxy.X; + PT.Pos.Y = newxy.Y; + PT.Pos.Z += PT.Vel.Z; + + PT.subsector = Level->PointInRenderSubsector(PT.Pos); + cursector = PT.subsector->sector; + // Handle crossing a sector portal. + if (!cursector->PortalBlocksMovement(sector_t::ceiling)) + { + if (PT.Pos.Z > cursector->GetPortalPlaneZ(sector_t::ceiling)) + { + PT.Pos += cursector->GetPortalDisplacement(sector_t::ceiling); + PT.subsector = Level->PointInRenderSubsector(PT.Pos); + cursector = PT.subsector->sector; + } + } + else if (!cursector->PortalBlocksMovement(sector_t::floor)) + { + if (PT.Pos.Z < cursector->GetPortalPlaneZ(sector_t::floor)) + { + PT.Pos += cursector->GetPortalDisplacement(sector_t::floor); + PT.subsector = Level->PointInRenderSubsector(PT.Pos); + cursector = PT.subsector->sector; + } + } + UpdateSpriteInfo(); +} + +int DVisualThinker::GetLightLevel(sector_t* rendersector) const +{ + int lightlevel = rendersector->GetSpriteLight(); + + if (bAddLightLevel) + { + lightlevel += LightLevel; + } + else if (LightLevel > -1) + { + lightlevel = LightLevel; + } + return lightlevel; +} + +FVector3 DVisualThinker::InterpolatedPosition(double ticFrac) const +{ + if (bDontInterpolate) return FVector3(PT.Pos); + + DVector3 proc = Prev + (ticFrac * (PT.Pos - Prev)); + return FVector3(proc); + +} + +float DVisualThinker::InterpolatedRoll(double ticFrac) const +{ + if (bDontInterpolate) return PT.Roll; + + return float(PrevRoll + (PT.Roll - PrevRoll) * ticFrac); +} + + + +void DVisualThinker::SetTranslation(FName trname) +{ + // There is no constant for the empty name... + if (trname.GetChars()[0] == 0) + { + // '' removes it + Translation = NO_TRANSLATION; + return; + } + + auto tnum = R_FindCustomTranslation(trname); + if (tnum != INVALID_TRANSLATION) + { + Translation = tnum; + } + // silently ignore if the name does not exist, this would create some insane message spam otherwise. +} + +void SetTranslation(DVisualThinker * self, int i_trans) +{ + FName trans {ENamedName(i_trans)}; + self->SetTranslation(trans); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, SetTranslation, SetTranslation) +{ + PARAM_SELF_PROLOGUE(DVisualThinker); + PARAM_NAME(trans); + self->SetTranslation(trans); + return 0; +} + +static int IsFrozen(DVisualThinker * self) +{ + return !!(self->Level->isFrozen() && !(self->PT.flags & SPF_NOTIMEFREEZE)); +} + +bool DVisualThinker::isFrozen() +{ + return IsFrozen(this); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, IsFrozen, IsFrozen) +{ + PARAM_SELF_PROLOGUE(DVisualThinker); + ACTION_RETURN_BOOL(self->isFrozen()); +} + +static void SetRenderStyle(DVisualThinker *self, int mode) +{ + if(mode >= 0 && mode < STYLE_Count) + { + self->PT.style = ERenderStyle(mode); + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, SetRenderStyle, SetRenderStyle) +{ + PARAM_SELF_PROLOGUE(DVisualThinker); + PARAM_INT(mode); + + self->PT.style = ERenderStyle(mode); + return 0; +} + +int DVisualThinker::GetRenderStyle() +{ + return PT.style; +} + +float DVisualThinker::GetOffset(bool y) const // Needed for the renderer. +{ + if (y) + return (float)(bFlipOffsetY ? Offset.Y : -Offset.Y); + else + return (float)(bFlipOffsetX ? Offset.X : -Offset.X); +} + +void DVisualThinker::Serialize(FSerializer& arc) +{ + Super::Serialize(arc); + + arc + ("pos", PT.Pos) + ("vel", PT.Vel) + ("prev", Prev) + ("scale", Scale) + ("roll", PT.Roll) + ("prevroll", PrevRoll) + ("offset", Offset) + ("alpha", PT.alpha) + ("texture", PT.texture) + ("style", *reinterpret_cast(&PT.style)) + ("translation", Translation) + ("cursector", cursector) + ("scolor", PT.color) + ("flipx", bXFlip) + ("flipy", bYFlip) + ("dontinterpolate", bDontInterpolate) + ("addlightlevel", bAddLightLevel) + ("flipoffsetx", bFlipOffsetX) + ("flipoffsetY", bFlipOffsetY) + ("lightlevel", LightLevel) + ("flags", PT.flags); + +} + +IMPLEMENT_CLASS(DVisualThinker, false, false); +DEFINE_FIELD_NAMED(DVisualThinker, PT.color, SColor); +DEFINE_FIELD_NAMED(DVisualThinker, PT.Pos, Pos); +DEFINE_FIELD_NAMED(DVisualThinker, PT.Vel, Vel); +DEFINE_FIELD_NAMED(DVisualThinker, PT.Roll, Roll); +DEFINE_FIELD_NAMED(DVisualThinker, PT.alpha, Alpha); +DEFINE_FIELD_NAMED(DVisualThinker, PT.texture, Texture); +DEFINE_FIELD_NAMED(DVisualThinker, PT.flags, Flags); + +DEFINE_FIELD(DVisualThinker, Prev); +DEFINE_FIELD(DVisualThinker, Scale); +DEFINE_FIELD(DVisualThinker, Offset); +DEFINE_FIELD(DVisualThinker, PrevRoll); +DEFINE_FIELD(DVisualThinker, Translation); +DEFINE_FIELD(DVisualThinker, LightLevel); +DEFINE_FIELD(DVisualThinker, cursector); +DEFINE_FIELD(DVisualThinker, bXFlip); +DEFINE_FIELD(DVisualThinker, bYFlip); +DEFINE_FIELD(DVisualThinker, bDontInterpolate); +DEFINE_FIELD(DVisualThinker, bAddLightLevel); +DEFINE_FIELD(DVisualThinker, bFlipOffsetX); +DEFINE_FIELD(DVisualThinker, bFlipOffsetY); diff --git a/src/playsim/p_effect.h b/src/playsim/p_effect.h index a2aeacbec63..5eafdcd4bb6 100644 --- a/src/playsim/p_effect.h +++ b/src/playsim/p_effect.h @@ -34,35 +34,66 @@ #pragma once #include "vectors.h" +#include "doomdef.h" +#include "renderstyle.h" +#include "dthinker.h" +#include "palettecontainer.h" +#include "animations.h" -#define FX_ROCKET 0x00000001 -#define FX_GRENADE 0x00000002 -#define FX_RESPAWNINVUL 0x00000020 -#define FX_VISIBILITYPULSE 0x00000040 +enum +{ + FX_ROCKET = 0x00000001, + FX_GRENADE = 0x00000002, + FX_RESPAWNINVUL = 0x00000020, + FX_VISIBILITYPULSE = 0x00000040 +}; struct subsector_t; struct FLevelLocals; // [RH] Particle details +enum EParticleFlags +{ + SPF_FULLBRIGHT = 1 << 0, + SPF_RELPOS = 1 << 1, + SPF_RELVEL = 1 << 2, + SPF_RELACCEL = 1 << 3, + SPF_RELANG = 1 << 4, + SPF_NOTIMEFREEZE = 1 << 5, + SPF_ROLL = 1 << 6, + SPF_REPLACE = 1 << 7, + SPF_NO_XY_BILLBOARD = 1 << 8, + SPF_LOCAL_ANIM = 1 << 9, + SPF_NEGATIVE_FADESTEP = 1 << 10, + SPF_FACECAMERA = 1 << 11, + SPF_NOFACECAMERA = 1 << 12, + SPF_ROLLCENTER = 1 << 13, + SPF_NOMIPMAP = 1 << 14, +}; + +class DVisualThinker; struct particle_t { - DVector3 Pos; - DVector3 Vel; - DVector3 Acc; - double size; - double sizestep; - subsector_t * subsector; - int32_t ttl; - uint8_t bright; - bool notimefreeze; - float fadestep; - float alpha; - int color; - uint16_t tnext; - uint16_t snext; + subsector_t* subsector; //+8 = 8 + DVector3 Pos; //+24 = 32 + FVector3 Vel; //+12 = 44 + FVector3 Acc; //+12 = 56 + float size, sizestep; //+8 = 64 + float fadestep, alpha; //+8 = 72 + int32_t ttl; // +4 = 76 + int color; //+4 = 80 + FTextureID texture; // +4 = 84 + ERenderStyle style; //+4 = 88 + float Roll, RollVel, RollAcc; //+12 = 100 + uint16_t tnext, snext, tprev; //+6 = 106 + uint16_t flags; //+2 = 108 + // uint32_t padding; //+4 = 112 + FStandaloneAnimation animData; //+16 = 128 }; +static_assert(sizeof(particle_t) == 128, "Only LP64/LLP64 is supported"); + const uint16_t NO_PARTICLE = 0xffff; void P_InitParticles(FLevelLocals *); @@ -76,7 +107,32 @@ particle_t *JitterParticle (FLevelLocals *Level, int ttl); particle_t *JitterParticle (FLevelLocals *Level, int ttl, double drift); void P_ThinkParticles (FLevelLocals *Level); -void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size, double fadestep, double sizestep, int flags = 0); + +struct FSpawnParticleParams +{ + int color; + FTextureID texture; + int style; + int flags; + int lifetime; + + double size; + double sizestep; + + DVector3 pos; + DVector3 vel; + DVector3 accel; + + double startalpha; + double fadestep; + + double startroll; + double rollvel; + double rollacc; +}; + +void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size, double fadestep, double sizestep, int flags = 0, FTextureID texture = FNullTextureID(), ERenderStyle style = STYLE_None, double startroll = 0, double rollvel = 0, double rollacc = 0); + void P_InitEffects (void); void P_RunEffect (AActor *actor, int effects); @@ -88,7 +144,59 @@ struct SPortalHit DVector3 OutDir; }; -void P_DrawRailTrail(AActor *source, TArray &portalhits, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = 0., int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270, DAngle pitch = 0.); +void P_DrawRailTrail(AActor *source, TArray &portalhits, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = nullAngle, int duration = TICRATE, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270, DAngle pitch = nullAngle); void P_DrawSplash (FLevelLocals *Level, int count, const DVector3 &pos, DAngle angle, int kind); void P_DrawSplash2 (FLevelLocals *Level, int count, const DVector3 &pos, DAngle angle, int updown, int kind); void P_DisconnectEffect (AActor *actor); + +//=========================================================================== +// +// VisualThinkers +// by Major Cooke +// Credit to phantombeta, RicardoLuis0 & RaveYard for aid +// +//=========================================================================== +class HWSprite; +struct FTranslationID; +class DVisualThinker : public DThinker +{ + DECLARE_CLASS(DVisualThinker, DThinker); +public: + DVector3 Prev; + DVector2 Scale, + Offset; + float PrevRoll; + int16_t LightLevel; + FTranslationID Translation; + FTextureID AnimatedTexture; + sector_t *cursector; + + bool bFlipOffsetX, + bFlipOffsetY, + bXFlip, + bYFlip, // flip the sprite on the x/y axis. + bDontInterpolate, // disable all interpolation + bAddLightLevel; // adds sector light level to 'LightLevel' + + // internal only variables + particle_t PT; + HWSprite *spr; //in an effort to cache the result. + + DVisualThinker(); + void Construct(); + void OnDestroy() override; + + static DVisualThinker* NewVisualThinker(FLevelLocals* Level, PClass* type); + void SetTranslation(FName trname); + int GetRenderStyle(); + bool isFrozen(); + int GetLightLevel(sector_t *rendersector) const; + FVector3 InterpolatedPosition(double ticFrac) const; + float InterpolatedRoll(double ticFrac) const; + + void Tick() override; + void UpdateSpriteInfo(); + void Serialize(FSerializer& arc) override; + + float GetOffset(bool y) const; +}; \ No newline at end of file diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 5d9191900e4..cf15cbf3888 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -31,7 +31,7 @@ #include -#include "templates.h" + #include "m_random.h" #include "doomdef.h" @@ -49,6 +49,8 @@ #include "g_levellocals.h" #include "vm.h" #include "actorinlines.h" +#include "a_ceiling.h" +#include "shadowinlines.h" #include "gi.h" @@ -60,13 +62,15 @@ static FRandom pr_lookformonsters ("LookForMonsters"); static FRandom pr_lookforplayers ("LookForPlayers"); static FRandom pr_scaredycat ("Anubis"); FRandom pr_chase ("Chase"); -static FRandom pr_facetarget ("FaceTarget"); -static FRandom pr_railface ("RailFace"); + FRandom pr_facetarget ("FaceTarget"); + FRandom pr_railface ("RailFace"); static FRandom pr_look2 ("LookyLooky"); static FRandom pr_look3 ("IGotHooky"); static FRandom pr_slook ("SlooK"); static FRandom pr_dropoff ("Dropoff"); static FRandom pr_defect ("Defect"); +static FRandom pr_avoidcrush("AvoidCrush"); +static FRandom pr_stayonlift("StayOnLift"); static FRandom pr_skiptarget("SkipTarget"); static FRandom pr_enemystrafe("EnemyStrafe"); @@ -260,47 +264,52 @@ void P_NoiseAlert (AActor *emitter, AActor *target, bool splash, double maxdist) // //---------------------------------------------------------------------------- -bool AActor::CheckMeleeRange () +int P_CheckMeleeRange (AActor* actor, double range) { - AActor *pl = target; + AActor *pl = actor->target; double dist; - - if (!pl || (Sector->Flags & SECF_NOATTACK)) + + if (!pl) return false; - - dist = Distance2D (pl); - if (dist >= meleerange + pl->radius) + dist = actor->Distance2D (pl); + if (range < 0) range = actor->meleerange; + + if (dist >= range + pl->radius) return false; // [RH] If moving toward goal, then we've reached it. - if (pl == goal) + if (pl == actor->goal) return true; + if (actor->Sector->Flags & SECF_NOATTACK) + return false; + // [RH] Don't melee things too far above or below actor. - if (!(flags5 & MF5_NOVERTICALMELEERANGE)) + if (!(actor->flags5 & MF5_NOVERTICALMELEERANGE)) { - if (pl->Z() > Top()) + if (pl->Z() > actor->Top()) return false; - if (pl->Top() < Z()) + if (pl->Top() < actor->Z()) return false; } // killough 7/18/98: friendly monsters don't attack other friends - if (IsFriend(pl)) + if (actor->IsFriend(pl)) return false; - if (!P_CheckSight (this, pl, 0)) + if (!P_CheckSight (actor, pl, 0)) return false; return true; } -DEFINE_ACTION_FUNCTION(AActor, CheckMeleeRange) +DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckMeleeRange, P_CheckMeleeRange) { PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_INT(self->CheckMeleeRange()); + PARAM_FLOAT(range); + ACTION_RETURN_INT(P_CheckMeleeRange(self, range)); } //============================================================================= @@ -308,7 +317,8 @@ DEFINE_ACTION_FUNCTION(AActor, CheckMeleeRange) // P_CheckMissileRange // //============================================================================= -bool P_CheckMissileRange (AActor *actor) + +static int P_CheckMissileRange (AActor *actor) { double dist; @@ -356,34 +366,26 @@ bool P_CheckMissileRange (AActor *actor) if (actor->MeleeState == NULL) dist -= 128; // no melee attack, so fire more - return actor->SuggestMissileAttack (dist); + + if (actor->maxtargetrange > 0 && dist > actor->maxtargetrange) + return false; // The Arch Vile's special behavior turned into a property + + if (actor->MeleeState != nullptr && dist < actor->meleethreshold) + return false; // From the Revenant: close enough for fist attack + + if (actor->flags4 & MF4_MISSILEMORE) dist *= 0.5; + if (actor->flags4 & MF4_MISSILEEVENMORE) dist *= 0.125; + + int mmc = int(actor->MinMissileChance * G_SkillProperty(SKILLP_Aggressiveness)); + return pr_checkmissilerange() >= min(int(dist), mmc); } -DEFINE_ACTION_FUNCTION(AActor, CheckMissileRange) +DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckMissileRange, P_CheckMissileRange) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(P_CheckMissileRange(self)); } -bool AActor::SuggestMissileAttack (double dist) -{ - // new version encapsulates the different behavior in flags instead of virtual functions - // The advantage is that this allows inheriting the missile attack attributes from the - // various Doom monsters by custom monsters - - if (maxtargetrange > 0 && dist > maxtargetrange) - return false; // The Arch Vile's special behavior turned into a property - - if (MeleeState != NULL && dist < meleethreshold) - return false; // From the Revenant: close enough for fist attack - - if (flags4 & MF4_MISSILEMORE) dist *= 0.5; - if (flags4 & MF4_MISSILEEVENMORE) dist *= 0.125; - - int mmc = int(MinMissileChance * G_SkillProperty(SKILLP_Aggressiveness)); - return pr_checkmissilerange() >= MIN (int(dist), mmc); -} - //============================================================================= // // P_HitFriend() @@ -403,7 +405,7 @@ int P_HitFriend(AActor * self) { DAngle angle = self->AngleTo(self->target); double dist = self->Distance2D(self->target); - P_AimLineAttack (self, angle, dist, &t, 0., true); + P_AimLineAttack (self, angle, dist, &t, nullAngle, true); if (t.linetarget != NULL && t.linetarget != self->target) { return self->IsFriend (t.linetarget); @@ -412,13 +414,82 @@ int P_HitFriend(AActor * self) return false; } +/* + * P_IsOnLift + * + * killough 9/9/98: + * + * Returns true if the object is on a lift. Used for AI, + * since it may indicate the need for crowded conditions, + * or that a monster should stay on the lift for a while + * while it goes up or down. + */ + +static bool P_IsOnLift(const AActor* actor) +{ + sector_t* sec = actor->Sector; + + // Short-circuit: it's on a lift which is active. + DSectorEffect* e = sec->floordata; + if (e && e->IsKindOf(RUNTIME_CLASS(DPlat))) + return true; + + // Check to see if it's in a sector which can be activated as a lift. + // This is a bit more restrictive than MBF as it only considers repeatable lifts moving from A->B->A and stop. + // Other types of movement are not easy to detect with the more complex map setup + // and also do not really make sense in this context unless they are actually active + return !!(sec->MoreFlags & SECMF_LIFT); +} + +/* + * P_IsUnderDamage + * + * killough 9/9/98: + * + * Returns nonzero if the object is under damage based on + * their current position. Returns 1 if the damage is moderate, + * -1 if it is serious. Used for AI. + */ + +static int P_IsUnderDamage(AActor* actor) +{ + msecnode_t* seclist; + int dir = 0; + for (seclist = actor->touching_sectorlist; seclist; seclist = seclist->m_tnext) + { + DSectorEffect* e = seclist->m_sector->ceilingdata; + if (e && e->IsKindOf(RUNTIME_CLASS(DCeiling))) + { + auto cl = (DCeiling*)e; + if (cl->getCrush() > 0) // unlike MBF we need to consider non-crushing ceiling movers here. + dir |= cl->getDirection(); + } + // Q: consider crushing 3D floors too? + } + return dir; +} + +// +// P_CheckTags +// Checks if 2 sectors share the same primary activation tag +// + +bool P_CheckTags(sector_t* sec1, sector_t* sec2) +{ + auto Level = sec1->Level; + if (!Level->SectorHasTags(sec1) || !Level->SectorHasTags(sec2)) return sec1 == sec2; + if (Level->GetFirstSectorTag(sec1) == Level->GetFirstSectorTag(sec2)) return true; + // todo: check secondary tags as well. + return false; +} + // // P_Move // Move in the current direction, // returns false if the move is blocked. // -int P_Move (AActor *actor) +static int P_Move (AActor *actor) { double tryx, tryy, deltax, deltay, origx, origy; @@ -443,7 +514,7 @@ int P_Move (AActor *actor) // want to yank them to the ground here as Doom did, since that makes // it difficult to thrust them vertically in a reasonable manner. // [GZ] Let jumping actors jump. - if (!((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP)) + if (!((actor->flags & MF_NOGRAVITY) || CanJump(actor)) && actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) { return false; @@ -454,7 +525,7 @@ int P_Move (AActor *actor) // and only if the target is immediately on the other side of the line. AActor *target = actor->target; - if ((actor->flags6 & MF6_JUMPDOWN) && target && + if ((actor->flags6 & MF6_JUMPDOWN) && target && !(actor->Level->flags3 & LEVEL3_NOJUMPDOWN) && !(target->IsFriend(actor)) && actor->Distance2D(target) < 144 && pr_dropoff() < 235) @@ -528,12 +599,12 @@ int P_Move (AActor *actor) { DAngle anglediff = deltaangle(oldangle, actor->Angles.Yaw); - if (anglediff != 0) + if (anglediff != nullAngle) { move = move.Rotated(anglediff); oldangle = actor->Angles.Yaw; } - start = actor->Pos() - move * i / steps; + start = actor->Pos().XY() - move * i / steps; } } @@ -556,10 +627,15 @@ int P_Move (AActor *actor) // to the floor if it is within MaxStepHeight, presuming that it is // actually walking down a step. if (try_ok && - !((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP)) - && actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) + !((actor->flags & MF_NOGRAVITY) || CanJump(actor)) + && !(actor->flags2 & MF2_ONMOBJ)) + { - if (actor->Z() <= actor->floorz + actor->MaxStepHeight) + // account for imprecisions with slopes. A walking actor should never be below its own floorz. + if (actor->Z() < actor->floorz) + actor->SetZ(actor->floorz); + + else if (actor->Z() <= actor->floorz + actor->MaxStepHeight) { double savedz = actor->Z(); actor->SetZ(actor->floorz); @@ -583,7 +659,7 @@ int P_Move (AActor *actor) if (!try_ok) { - if (((actor->flags6 & MF6_CANJUMP)||(actor->flags & MF_FLOAT)) && tm.floatok) + if ((CanJump(actor) || (actor->flags & MF_FLOAT)) && tm.floatok) { // must adjust height double savedz = actor->Z(); @@ -594,7 +670,7 @@ int P_Move (AActor *actor) // [RH] Check to make sure there's nothing in the way of the float - if (P_TestMobjZ (actor)) + if (P_TestMobjZ(actor)) { actor->flags |= MF_INFLOAT; return true; @@ -651,6 +727,46 @@ int P_Move (AActor *actor) return true; } +// +// P_SmartMove +// +// killough 9/12/98: Same as P_Move, except smarter +// + +int P_SmartMove(AActor* actor) +{ + AActor* target = actor->target; + int on_lift = false, dropoff = false, under_damage; + bool monster_avoid_hazards = (actor->Level->i_compatflags2 & COMPATF2_AVOID_HAZARDS) || (actor->flags8 & MF8_AVOIDHAZARDS); + + /* killough 9/12/98: Stay on a lift if target is on one */ + on_lift = ((actor->flags8 & MF8_STAYONLIFT) || (actor->Level->i_compatflags2 & COMPATF2_STAYONLIFT)) + && target && target->health > 0 && P_IsOnLift(actor) + && P_CheckTags(target->Sector, actor->Sector); + + under_damage = monster_avoid_hazards && P_IsUnderDamage(actor) != 0;//e6y + + if (!P_Move(actor)) + return false; + + // killough 9/9/98: avoid crushing ceilings or other damaging areas + if ( + (on_lift && pr_stayonlift() < 230 && // Stay on lift + !P_IsOnLift(actor)) + || + (monster_avoid_hazards && !under_damage && //e6y // Get away from damage + (under_damage = P_IsUnderDamage(actor)) && + (under_damage < 0 || pr_avoidcrush() < 200)) + ) + actor->movedir = DI_NODIR; // avoid the area (most of the time anyway) + + if (actor->flags2 & MF2_FLOORCLIP) + { + actor->AdjustFloorClip(); + } + return true; +} + //============================================================================= // // TryWalk @@ -667,7 +783,7 @@ int P_Move (AActor *actor) bool P_TryWalk (AActor *actor) { - if (!P_Move (actor)) + if (!P_SmartMove (actor)) { return false; } @@ -728,7 +844,7 @@ void P_DoNewChaseDir (AActor *actor, double deltax, double deltay) { if ((pr_newchasedir() > 200 || fabs(deltay) > fabs(deltax))) { - swapvalues (d[0], d[1]); + std::swap (d[0], d[1]); } if (d[0] == turnaround) @@ -875,8 +991,8 @@ void P_NewChaseDir(AActor * actor) while ((line = it.Next())) { if (line->backsector && // Ignore one-sided linedefs - box.inRange(line) && - box.BoxOnLineSide(line) == -1) + inRange(box, line) && + BoxOnLineSide(box, line) == -1) { double front = line->frontsector->floorplane.ZatPoint(actor->PosRelative(line)); double back = line->backsector->floorplane.ZatPoint(actor->PosRelative(line)); @@ -891,7 +1007,7 @@ void P_NewChaseDir(AActor * actor) } else if (front == actor->Z() && back < actor->Z() - actor->MaxDropOffHeight) { - angle = line->Delta().Angle() + 180.; // back side dropoff + angle = line->Delta().Angle() + DAngle::fromDeg(180.); // back side dropoff } else continue; @@ -941,7 +1057,7 @@ void P_NewChaseDir(AActor * actor) if (target->health > 0 && !actor->IsFriend(target) && target != actor->goal) { // Live enemy target - if (actor->flags3 & MF3_AVOIDMELEE) + if ((actor->flags3 & MF3_AVOIDMELEE) || (actor->Level->flags3 & LEVEL3_AVOIDMELEE)) { bool ismeleeattacker = false; double dist = actor->Distance2D(target); @@ -989,7 +1105,7 @@ void P_RandomChaseDir (AActor *actor) int turndir; // Friendly monsters like to head toward a player - if (actor->flags & MF_FRIENDLY) + if (actor->flags & MF_FRIENDLY && !(actor->flags8 & MF8_DONTFOLLOWPLAYERS)) { AActor *player; DVector2 delta; @@ -1041,7 +1157,7 @@ void P_RandomChaseDir (AActor *actor) // try other directions if (pr_newchasedir() > 200 || fabs(delta.Y) > fabs(delta.X)) { - swapvalues (d[1], d[2]); + std::swap (d[1], d[2]); } if (d[1] == turnaround) @@ -1146,7 +1262,7 @@ int P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams double mindist; DAngle fov; - if (other == nullptr) + if (other == nullptr || (other->flags8 & MF8_MVISBLOCKED)) { return false; } @@ -1155,12 +1271,12 @@ int P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams { maxdist = params->maxDist; mindist = params->minDist; - fov = params->Fov; + fov = allaround ? DAngle::fromDeg(0.) : params->Fov; // [RK] Account for LOOKALLAROUND flag. } else { mindist = maxdist = 0; - fov = allaround ? 0. : 180.; + fov = DAngle::fromDeg(allaround ? 0. : 180.); } double dist = lookee->Distance2D (other); @@ -1171,7 +1287,7 @@ int P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams if (mindist && dist < mindist) return false; // [KS] too close - if (fov != 0) + if (fov != nullAngle) { DAngle an = absangle(lookee->AngleTo(other), lookee->Angles.Yaw); @@ -1452,25 +1568,32 @@ AActor *LookForEnemiesInBlock (AActor *lookee, int index, void *extparam) continue; other = NULL; - if (link->flags & MF_FRIENDLY) + if (lookee->flags & MF_FRIENDLY) { - if (!lookee->IsFriend(link)) - { - // This is somebody else's friend, so go after it - other = link; - } - else if (link->target != NULL && !(link->target->flags & MF_FRIENDLY)) + if (link->flags & MF_FRIENDLY) { - other = link->target; - if (!(other->flags & MF_SHOOTABLE) || - other->health <= 0 || - (other->flags2 & MF2_DORMANT)) + if (!lookee->IsFriend(link)) { - other = NULL;; + // This is somebody else's friend, so go after it + other = link; } + else if (link->target != NULL && !(link->target->flags & MF_FRIENDLY)) + { + other = link->target; + if (!(other->flags & MF_SHOOTABLE) || + other->health <= 0 || + (other->flags2 & MF2_DORMANT)) + { + other = NULL;; + } + } + } + else + { + other = link; } } - else + else if (lookee->flags8 & MF8_SEEFRIENDLYMONSTERS && link->flags & MF_FRIENDLY) { other = link; } @@ -1514,7 +1637,7 @@ int P_LookForEnemies (AActor *actor, INTBOOL allaround, FLookExParams *params) { AActor *other; - other = P_BlockmapSearch (actor, actor->friendlyseeblocks, LookForEnemiesInBlock, params); + other = P_BlockmapSearch(actor, actor->friendlyseeblocks, LookForEnemiesInBlock, params); if (other != NULL) { @@ -1623,6 +1746,12 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) } // [SP] if false, and in deathmatch, intentional fall-through + else if (actor->flags8 & MF8_SEEFRIENDLYMONSTERS) + { + bool result = P_LookForEnemies (actor, allaround, params); + + if (result) return true; + } if (!(gameinfo.gametype & (GAME_DoomStrifeChex)) && actor->Level->isPrimaryLevel() && @@ -1844,9 +1973,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) if (self->reactiontime > self->Level->maptime) self->target = nullptr; } - else if (self->SeeSound) + else if (self->SeeSound.isvalid()) { - if (self->flags2 & MF2_BOSS) + if ((self->flags2 & MF2_BOSS) || (self->flags8 & MF8_FULLVOLSEE)) { // full volume S_Sound (self, CHAN_VOICE, 0, self->SeeSound, 1, ATTN_NONE); } @@ -1883,7 +2012,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx) AActor *targ = NULL; // Shuts up gcc double dist; - if (fov == 0) fov = 180.; + if (fov == nullAngle) fov = DAngle::fromDeg(180.); FLookExParams params = { fov, minseedist, maxseedist, maxheardist, flags, seestate }; if (self->flags5 & MF5_INCONVERSATION) @@ -1957,12 +2086,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx) { // If we find a valid target here, the wandering logic should *not* // be activated! If would cause the seestate to be set twice. - if (P_LookForPlayers(self, true, ¶ms)) + if (P_LookForPlayers(self, (self->flags4 & MF4_LOOKALLAROUND), ¶ms)) // [RK] Passing true for allround should only occur if the flag is actually set. goto seeyou; } // Let the self wander around aimlessly looking for a fight - if (!(self->flags & MF_INCHASE)) + if (!(self->flags7 & MF7_INCHASE)) { if (seestate) { @@ -2010,7 +2139,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx) if (!(flags & LOF_NOSIGHTCHECK)) { - if (!P_LookForPlayers(self, true, ¶ms)) + if (!P_LookForPlayers(self, (self->flags4 & MF4_LOOKALLAROUND), ¶ms)) // [RK] Account for the flag being set. return 0; } else @@ -2026,7 +2155,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx) if (self->reactiontime > self->Level->maptime) self->target = nullptr; } - else if (self->SeeSound && !(flags & LOF_NOSEESOUND)) + else if (self->SeeSound.isvalid() && !(flags & LOF_NOSEESOUND)) { if (flags & LOF_FULLVOLSEESOUND) { // full volume @@ -2038,7 +2167,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx) } } - if (self->target && !(self->flags & MF_INCHASE)) + if (self->target && !(self->flags7 & MF7_INCHASE)) { if (!(flags & LOF_NOJUMP)) { @@ -2086,6 +2215,8 @@ enum ChaseFlags CHF_NODIRECTIONTURN = 64, CHF_NOPOSTATTACKTURN = 128, CHF_STOPIFBLOCKED = 256, + CHF_DONTIDLE = 512, + CHF_DONTLOOKALLAROUND = 1024, }; void A_Wander(AActor *self, int flags) @@ -2109,19 +2240,19 @@ void A_Wander(AActor *self, int flags) // turn towards movement direction if not there yet if (!(flags & CHF_NODIRECTIONTURN) && (self->movedir < DI_NODIR)) { - self->Angles.Yaw = floor(self->Angles.Yaw.Degrees / 45) * 45.; - DAngle delta = deltaangle(self->Angles.Yaw, (self->movedir * 45)); - if (delta < 0) + self->Angles.Yaw = DAngle::fromDeg(floor(self->Angles.Yaw.Degrees() / 45) * 45.); + DAngle delta = deltaangle(self->Angles.Yaw, DAngle::fromDeg(self->movedir * 45)); + if (delta < nullAngle) { - self->Angles.Yaw -= 45; + self->Angles.Yaw -= DAngle::fromDeg(45); } - else if (delta > 0) + else if (delta > nullAngle) { - self->Angles.Yaw += 45; + self->Angles.Yaw += DAngle::fromDeg(45); } } - if ((--self->movecount < 0 && !(flags & CHF_NORANDOMTURN)) || (!P_Move(self) && !(flags & CHF_STOPIFBLOCKED))) + if ((--self->movecount < 0 && !(flags & CHF_NORANDOMTURN)) || (!P_SmartMove(self) && !(flags & CHF_STOPIFBLOCKED))) { P_RandomChaseDir(self); self->movecount += 5; @@ -2202,15 +2333,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2) void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove, int flags) { - if (actor->flags5 & MF5_INCONVERSATION) return; - if (actor->flags & MF_INCHASE) + if (actor->flags7 & MF7_INCHASE) { return; } - actor->flags |= MF_INCHASE; + actor->flags7 |= MF7_INCHASE; // [RH] Andy Baker's stealth monsters if (actor->flags & MF_STEALTH) @@ -2225,7 +2355,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi // [RH] Don't chase invisible targets if (actor->target != NULL && - actor->target->renderflags & RF_INVISIBLE && + ((actor->target->renderflags & RF_INVISIBLE) || (actor->target->flags8 & MF8_MINVISIBLE)) && actor->target != actor->goal) { actor->target = nullptr; @@ -2263,15 +2393,15 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } else if (!(flags & CHF_NODIRECTIONTURN) && actor->movedir < 8) { - actor->Angles.Yaw = floor(actor->Angles.Yaw.Degrees / 45) * 45.; - DAngle delta = deltaangle(actor->Angles.Yaw, (actor->movedir * 45)); - if (delta < 0) + actor->Angles.Yaw = DAngle::fromDeg(floor(actor->Angles.Yaw.Degrees() / 45) * 45.); + DAngle delta = deltaangle(actor->Angles.Yaw, DAngle::fromDeg(actor->movedir * 45)); + if (delta < nullAngle) { - actor->Angles.Yaw -= 45; + actor->Angles.Yaw -= DAngle::fromDeg(45); } - else if (delta > 0) + else if (delta > nullAngle) { - actor->Angles.Yaw += 45; + actor->Angles.Yaw += DAngle::fromDeg(45); } } @@ -2313,7 +2443,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) { // look for a new target - if (actor->target != NULL && (actor->target->flags2 & MF2_NONSHOOTABLE)) + if (actor->target != nullptr && (actor->target->flags2 & MF2_NONSHOOTABLE)) { // Target is only temporarily unshootable, so remember it. actor->lastenemy = actor->target; @@ -2321,27 +2451,27 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi // hurt our old one temporarily. actor->threshold = 0; } - if (P_LookForPlayers (actor, true, NULL) && actor->target != actor->goal) + if (P_LookForPlayers (actor, !(flags & CHF_DONTLOOKALLAROUND), nullptr) && actor->target != actor->goal) { // got a new target - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; return; } - if (actor->target == NULL) + if (actor->target == nullptr) { - if (actor->flags & MF_FRIENDLY) + if (flags & CHF_DONTIDLE || actor->flags & MF_FRIENDLY) { //A_Look(actor); - if (actor->target == NULL) + if (actor->target == nullptr) { if (!dontmove) A_Wander(actor); - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; return; } } else { actor->SetIdle(); - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; return; } } @@ -2360,7 +2490,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi //over and over again. if (flags & CHF_STOPIFBLOCKED) actor->movecount = pr_trywalk() & 15; - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; return; } @@ -2369,7 +2499,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi { AActor * savedtarget = actor->target; actor->target = actor->goal; - bool result = actor->CheckMeleeRange(); + bool result = P_CheckMeleeRange(actor); actor->target = savedtarget; if (result) @@ -2408,7 +2538,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->flags4 |= MF4_INCOMBAT; actor->SetIdle(); } - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; actor->goal = newgoal; return; } @@ -2436,30 +2566,29 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi if (pr_chase() < 100) { DAngle ang = actor->AngleTo(actor->target); - if (pr_chase() < 128) ang += 90.; - else ang -= 90.; + if (pr_chase() < 128) ang += DAngle::fromDeg(90.); + else ang -= DAngle::fromDeg(90.); actor->VelFromAngle(13., ang); actor->FastChaseStrafeCount = 3; // strafe time } } } - } // [RH] Scared monsters attack less frequently - if (((actor->target->player == NULL || + if (((actor->target->player == nullptr || !((actor->target->player->cheats & CF_FRIGHTENING) || (actor->target->flags8 & MF8_FRIGHTENING))) && !(actor->flags4 & MF4_FRIGHTENED)) || pr_scaredycat() < 43) { // check for melee attack - if (meleestate && actor->CheckMeleeRange ()) + if (meleestate && P_CheckMeleeRange(actor)) { - if (actor->AttackSound) + if (actor->AttackSound.isvalid()) S_Sound (actor, CHAN_WEAPON, 0, actor->AttackSound, 1, ATTN_NORM); actor->SetState (meleestate); - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; return; } @@ -2477,7 +2606,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->SetState (missilestate); actor->flags |= MF_JUSTATTACKED; actor->flags4 |= MF4_INCOMBAT; - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; return; } } @@ -2496,14 +2625,14 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi lookForBetter = true; } AActor * oldtarget = actor->target; - gotNew = P_LookForPlayers (actor, true, NULL); + gotNew = P_LookForPlayers (actor, !(flags & CHF_DONTLOOKALLAROUND), nullptr); if (lookForBetter) { actor->flags3 |= MF3_NOSIGHTCHECK; } if (gotNew && actor->target != oldtarget) { - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; return; // got a new target } } @@ -2519,12 +2648,12 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi if ((!fastchase || !actor->FastChaseStrafeCount) && !dontmove) { // CANTLEAVEFLOORPIC handling was completely missing in the non-serpent functions. - DVector2 old = actor->Pos(); + DVector2 old = actor->Pos().XY(); int oldgroup = actor->PrevPortalGroup; FTextureID oldFloor = actor->floorpic; // chase towards player - if ((--actor->movecount < 0 && !(flags & CHF_NORANDOMTURN)) || (!P_Move(actor) && !(flags & CHF_STOPIFBLOCKED))) + if ((--actor->movecount < 0 && !(flags & CHF_NORANDOMTURN)) || (!P_SmartMove(actor) && !(flags & CHF_STOPIFBLOCKED))) { P_NewChaseDir(actor); } @@ -2553,7 +2682,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->PlayActiveSound (); } - actor->flags &= ~MF_INCHASE; + actor->flags7 &= ~MF7_INCHASE; } //========================================================================== @@ -2616,7 +2745,7 @@ bool P_CanResurrect(AActor *raiser, AActor *thing) // //========================================================================== -bool P_CheckForResurrection(AActor *self, bool usevilestates) +bool P_CheckForResurrection(AActor* self, bool usevilestates, FState* state = nullptr, FSoundID sound = NO_SOUND) { const AActor *info; AActor *temp; @@ -2681,7 +2810,7 @@ bool P_CheckForResurrection(AActor *self, bool usevilestates) corpsehit->flags |= MF_SOLID; corpsehit->Height = corpsehit->GetDefault()->Height; - bool check = P_CheckPosition(corpsehit, corpsehit->Pos()); + bool check = P_CheckPosition(corpsehit, corpsehit->Pos().XY()); corpsehit->flags = oldflags; corpsehit->radius = oldradius; corpsehit->Height = oldheight; @@ -2702,8 +2831,8 @@ bool P_CheckForResurrection(AActor *self, bool usevilestates) self->target = temp; // Make the state the monster enters customizable. - FState * state = self->FindState(NAME_Heal); - if (state != NULL) + if (state == nullptr) state = self->FindState(NAME_Heal); + if (state != nullptr) { self->SetState(state); } @@ -2711,20 +2840,21 @@ bool P_CheckForResurrection(AActor *self, bool usevilestates) { // For Dehacked compatibility this has to use the Arch Vile's // heal state as a default if the actor doesn't define one itself. - PClassActor *archvile = PClass::FindActor("Archvile"); + PClassActor *archvile = PClass::FindActor(NAME_Archvile); if (archvile != NULL) { self->SetState(archvile->FindState(NAME_Heal)); } } - S_Sound(corpsehit, CHAN_BODY, 0, "vile/raise", 1, ATTN_IDLE); + if (sound == NO_SOUND) sound = S_FindSound("vile/raise"); + S_Sound(corpsehit, CHAN_BODY, 0, sound, 1, ATTN_IDLE); info = corpsehit->GetDefault(); if (GetTranslationType(corpsehit->Translation) == TRANSLATION_Blood) { corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses } - if (self->Level->ib_compatflags & BCOMPATF_VILEGHOSTS) + if (self->Level->i_compatflags & COMPATF_VILEGHOSTS) { corpsehit->Height *= 4; // [GZ] This was a commented-out feature, so let's make use of it, @@ -2769,13 +2899,8 @@ void A_Chase(AActor *self) A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); } -DEFINE_ACTION_FUNCTION(AActor, A_Chase) +void A_ChaseNative(AActor * self, int meleelabel, int missilelabel, int flags) { - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATELABEL(meleelabel); - PARAM_STATELABEL(missilelabel); - PARAM_INT(flags); - FName meleename = ENamedName(meleelabel - 0x10000000); FName missilename = ENamedName(missilelabel - 0x10000000); if (meleename != NAME__a_chase_default || missilename != NAME__a_chase_default) @@ -2783,7 +2908,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Chase) FState *melee = StateLabels.GetState(meleelabel, self->GetClass()); FState *missile = StateLabels.GetState(missilelabel, self->GetClass()); if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false)) - return 0; + return; A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE), flags & 0x3fffffff); @@ -2792,6 +2917,36 @@ DEFINE_ACTION_FUNCTION(AActor, A_Chase) { A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); } +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_Chase, A_ChaseNative) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STATELABEL(meleelabel); + PARAM_STATELABEL(missilelabel); + PARAM_INT(flags); + + A_ChaseNative(self, meleelabel, missilelabel, flags); + + return 0; +} + +void A_DoChaseNative(AActor * self, FState *melee, FState *missile, int flags) +{ + if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false)) + return; + A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE), flags & 0x3fffffff); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_DoChase, A_DoChaseNative) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STATE(melee); + PARAM_STATE(missile); + PARAM_INT(flags); + + A_DoChaseNative(self, melee, missile, flags); + return 0; } @@ -2827,9 +2982,9 @@ void A_Face(AActor *self, AActor *other, DAngle max_turn, DAngle max_pitch, DAng // 0 means no limit. Also, if we turn in a single step anyways, no need to go through the algorithms. // It also means that there is no need to check for going past the other. - if (max_turn != 0 && (max_turn < fabs(delta))) + if (max_turn != nullAngle && (max_turn < fabs(delta))) { - if (delta > 0) + if (delta > nullAngle) { self->Angles.Yaw -= max_turn + ang_offset; } @@ -2845,7 +3000,7 @@ void A_Face(AActor *self, AActor *other, DAngle max_turn, DAngle max_pitch, DAng // [DH] Now set pitch. In order to maintain compatibility, this can be // disabled and is so by default. - if (max_pitch <= 180.) + if (max_pitch <= DAngle::fromDeg(180.)) { DVector2 dist = self->Vec2To(other); @@ -2878,18 +3033,18 @@ void A_Face(AActor *self, AActor *other, DAngle max_turn, DAngle max_pitch, DAng double dist_z = target_z - source_z; double ddist = g_sqrt(dist.X*dist.X + dist.Y*dist.Y + dist_z*dist_z); - DAngle other_pitch = -DAngle::ToDegrees(g_asin(dist_z / ddist)).Normalized180(); + DAngle other_pitch = -DAngle::fromRad(g_asin(dist_z / ddist)).Normalized180(); - if (max_pitch != 0) + if (max_pitch != nullAngle) { if (self->Angles.Pitch > other_pitch) { - max_pitch = MIN(max_pitch, (self->Angles.Pitch - other_pitch).Normalized360()); + max_pitch = min(max_pitch, (self->Angles.Pitch - other_pitch).Normalized360()); self->Angles.Pitch -= max_pitch; } else { - max_pitch = MIN(max_pitch, (other_pitch - self->Angles.Pitch).Normalized360()); + max_pitch = min(max_pitch, (other_pitch - self->Angles.Pitch).Normalized360()); self->Angles.Pitch += max_pitch; } } @@ -2898,15 +3053,11 @@ void A_Face(AActor *self, AActor *other, DAngle max_turn, DAngle max_pitch, DAng self->Angles.Pitch = other_pitch; } self->Angles.Pitch += pitch_offset; + A_Face_ShadowHandling(self, other, max_pitch, other_pitch, true); } - - // This will never work well if the turn angle is limited. - if (max_turn == 0 && (self->Angles.Yaw == other_angle) && other->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE) ) - { - self->Angles.Yaw += pr_facetarget.Random2() * (45 / 256.); - } + A_Face_ShadowHandling(self,other,max_turn,other_angle,false); } void A_FaceTarget(AActor *self) @@ -2941,7 +3092,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) self->Angles.Yaw = self->AngleTo(self->target); - self->Angles.Pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE, &t, 60., 0, self->target); + self->Angles.Pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE, &t, DAngle::fromDeg(60.), 0, self->target); if (t.linetarget == NULL) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. @@ -2953,10 +3104,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) // Let the aim trail behind the player self->Angles.Yaw = self->AngleTo(self->target, -self->target->Vel.X * 3, -self->target->Vel.Y * 3); - if (self->target->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE)) - { - self->Angles.Yaw += pr_railface.Random2() * 45./256; - } + A_MonsterRail_ShadowHandling(self); FRailParams p; @@ -2991,10 +3139,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_Pain) PARAM_SELF_PROLOGUE(AActor); // [RH] Vary player pain sounds depending on health (ala Quake2) - if (self->player && self->player->morphTics == 0) + if (self->player && self->alternative == nullptr) { const char *pain_amount; - FSoundID sfx_id = 0; + FSoundID sfx_id = NO_SOUND; if (self->health < 25) pain_amount = "*pain25"; @@ -3010,24 +3158,24 @@ DEFINE_ACTION_FUNCTION(AActor, A_Pain) { FString pain_sound = pain_amount; pain_sound += '-'; - pain_sound += self->player->LastDamageType; - sfx_id = pain_sound; - if (sfx_id == 0) + pain_sound += self->player->LastDamageType.GetChars(); + sfx_id = S_FindSound(pain_sound); + if (sfx_id == NO_SOUND) { // Try again without a specific pain amount. pain_sound = "*pain-"; - pain_sound += self->player->LastDamageType; - sfx_id = pain_sound; + pain_sound += self->player->LastDamageType.GetChars(); + sfx_id = S_FindSound(pain_sound); } } - if (sfx_id == 0) + if (sfx_id == NO_SOUND) { - sfx_id = pain_amount; + sfx_id = S_FindSound(pain_amount); } S_Sound (self, CHAN_VOICE, 0, sfx_id, 1, ATTN_NORM); } - else if (self->PainSound) + else if (self->PainSound.isvalid()) { S_Sound (self, CHAN_VOICE, 0, self->PainSound, 1, ATTN_NORM); } @@ -3082,7 +3230,12 @@ void A_BossDeath(AActor *self) FName mytype = self->GetClass()->TypeName; // Ugh... - FName type = self->GetClass()->GetReplacee(self->Level)->TypeName; + auto replacee = self->GetClass()->GetReplacee(self->Level); + FName type = replacee->TypeName; + int flags8 = self->flags8; + + if (type != mytype) flags8 |= ((AActor*)replacee->Defaults)->flags8; + // Do generic special death actions first bool checked = false; @@ -3119,24 +3272,30 @@ void A_BossDeath(AActor *self) // [RH] These all depend on the presence of level flags now // rather than being hard-coded to specific levels/episodes. - if ((Level->flags & (LEVEL_MAP07SPECIAL| + if (((Level->flags & (LEVEL_MAP07SPECIAL| LEVEL_BRUISERSPECIAL| LEVEL_CYBORGSPECIAL| LEVEL_SPIDERSPECIAL| LEVEL_HEADSPECIAL| LEVEL_MINOTAURSPECIAL| - LEVEL_SORCERER2SPECIAL)) == 0) + LEVEL_SORCERER2SPECIAL)) == 0) && + ((Level->flags3 & (LEVEL3_E1M8SPECIAL | LEVEL3_E2M8SPECIAL | LEVEL3_E3M8SPECIAL | LEVEL3_E4M8SPECIAL | LEVEL3_E4M6SPECIAL)) == 0)) return; if ((Level->i_compatflags & COMPATF_ANYBOSSDEATH) || ( // [GZ] Added for UAC_DEAD - ((Level->flags & LEVEL_MAP07SPECIAL) && (type == NAME_Fatso || type == NAME_Arachnotron)) || + ((Level->flags & LEVEL_MAP07SPECIAL) && (flags8 & (MF8_MAP07BOSS1|MF8_MAP07BOSS2))) || ((Level->flags & LEVEL_BRUISERSPECIAL) && (type == NAME_BaronOfHell)) || ((Level->flags & LEVEL_CYBORGSPECIAL) && (type == NAME_Cyberdemon)) || ((Level->flags & LEVEL_SPIDERSPECIAL) && (type == NAME_SpiderMastermind)) || ((Level->flags & LEVEL_HEADSPECIAL) && (type == NAME_Ironlich)) || ((Level->flags & LEVEL_MINOTAURSPECIAL) && (type == NAME_Minotaur)) || - ((Level->flags & LEVEL_SORCERER2SPECIAL) && (type == NAME_Sorcerer2)) - )) + ((Level->flags & LEVEL_SORCERER2SPECIAL) && (type == NAME_Sorcerer2)) || + ((Level->flags3 & LEVEL3_E1M8SPECIAL) && (flags8 & MF8_E1M8BOSS)) || + ((Level->flags3 & LEVEL3_E2M8SPECIAL) && (flags8 & MF8_E2M8BOSS)) || + ((Level->flags3 & LEVEL3_E3M8SPECIAL) && (flags8 & MF8_E3M8BOSS)) || + ((Level->flags3 & LEVEL3_E4M8SPECIAL) && (flags8 & MF8_E4M8BOSS)) || + ((Level->flags3 & LEVEL3_E4M6SPECIAL) && (flags8 & MF8_E4M6BOSS)) + )) ; else return; @@ -3153,17 +3312,25 @@ void A_BossDeath(AActor *self) } if (Level->flags & LEVEL_MAP07SPECIAL) { - if (type == NAME_Fatso) + // samereplacement will only be considered if both Fatso and Arachnotron are flagged as MAP07 bosses and the current monster maps to one of them. + PClassActor * fatso = PClass::FindActor(NAME_Fatso); + PClassActor * arachnotron = PClass::FindActor(NAME_Arachnotron); + bool samereplacement = (type == NAME_Fatso || type == NAME_Arachnotron) && + fatso && arachnotron && + (GetDefaultByType(fatso)->flags8 & MF8_MAP07BOSS1) && + (GetDefaultByType(arachnotron)->flags8 & MF8_MAP07BOSS2) && + fatso->GetReplacement(Level) == arachnotron->GetReplacement(Level); + + if ((flags8 & MF8_MAP07BOSS1) || samereplacement) { Level->EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, 1., 0, -1, 0, false); - return; } - if (type == NAME_Arachnotron) + if ((flags8 & MF8_MAP07BOSS2) || samereplacement) { Level->EV_DoFloor (DFloor::floorRaiseByTexture, NULL, 667, 1., 0, -1, 0, false); - return; } + return; } else { diff --git a/src/playsim/p_enemy.h b/src/playsim/p_enemy.h index 3086cbb50c4..9f13128ffa9 100644 --- a/src/playsim/p_enemy.h +++ b/src/playsim/p_enemy.h @@ -7,6 +7,7 @@ struct sector_t; class AActor; class PClass; +struct FState; enum dirtype_t @@ -46,10 +47,11 @@ struct FLookExParams }; int P_HitFriend (AActor *self); -void P_NoiseAlert (AActor *emmiter, AActor *target, bool splash=false, double maxdist=0); +void P_NoiseAlert (AActor *emitter, AActor *target, bool splash=false, double maxdist=0); +int P_CheckMeleeRange(AActor* actor, double range = -1); bool P_CheckMeleeRange2 (AActor *actor); -int P_Move (AActor *actor); +int P_SmartMove (AActor *actor); bool P_TryWalk (AActor *actor); void P_NewChaseDir (AActor *actor); void P_RandomChaseDir(AActor *actor);; @@ -70,12 +72,11 @@ void A_Wander(AActor *self, int flags = 0); void A_DoChase(AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove, int flags); void A_Chase(AActor *self); void A_FaceTarget(AActor *actor); -void A_Face(AActor *self, AActor *other, DAngle max_turn = 0., DAngle max_pitch = 270., DAngle ang_offset = 0., DAngle pitch_offset = 0., int flags = 0, double z_add = 0); -bool P_CheckForResurrection(AActor *self, bool usevilestates); +void A_Face(AActor *self, AActor *other, DAngle max_turn = nullAngle, DAngle max_pitch = DAngle::fromDeg(270.), DAngle ang_offset = nullAngle, DAngle pitch_offset = nullAngle, int flags = 0, double z_add = 0); +class FSoundID; int CheckBossDeath (AActor *); int P_Massacre (bool baddies = false, PClassActor *cls = nullptr); -bool P_CheckMissileRange (AActor *actor); #define SKULLSPEED (20.) void A_SkullAttack(AActor *self, double speed); diff --git a/src/playsim/p_interaction.cpp b/src/playsim/p_interaction.cpp index f6dadb21055..0ae77e914c5 100644 --- a/src/playsim/p_interaction.cpp +++ b/src/playsim/p_interaction.cpp @@ -61,6 +61,7 @@ #include "g_levellocals.h" #include "events.h" #include "actorinlines.h" +#include "d_main.h" static FRandom pr_botrespawn ("BotRespawn"); static FRandom pr_killmobj ("ActorDie"); @@ -76,6 +77,7 @@ EXTERN_CVAR (Bool, show_obituaries) CVAR (Float, sv_damagefactormobj, 1.0, CVAR_SERVERINFO|CVAR_CHEAT) CVAR (Float, sv_damagefactorfriendly, 1.0, CVAR_SERVERINFO|CVAR_CHEAT) CVAR (Float, sv_damagefactorplayer, 1.0, CVAR_SERVERINFO|CVAR_CHEAT) +CVAR (Float, sv_ammofactor, 1.0, CVAR_SERVERINFO|CVAR_CHEAT) // used in the zscript ammo code // // GET STUFF @@ -90,7 +92,7 @@ void P_TouchSpecialThing (AActor *special, AActor *toucher) // The pickup is at or above the toucher's feet OR // The pickup is below the toucher. - if (delta > toucher->Height || delta < MIN(-32., -special->Height)) + if (delta > toucher->Height || delta < min(-32., -special->Height)) { // out of reach return; } @@ -187,7 +189,7 @@ void PronounMessage (const char *from, char *to, int pronoun, const char *victim // void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgflags, FName MeansOfDeath) { - FString ret; + FString ret, lookup; char gendermessage[1024]; // No obituaries for non-players, voodoo dolls or when not wanted @@ -217,10 +219,10 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf } FString obit = DamageTypeDefinition::GetObituary(mod); - if (attacker == nullptr && obit.IsNotEmpty()) messagename = obit; + if (attacker == nullptr && obit.IsNotEmpty()) messagename = obit.GetChars(); else { - switch (mod) + switch (mod.GetIndex()) { case NAME_Suicide: messagename = "$OB_SUICIDE"; break; case NAME_Falling: messagename = "$OB_FALLING"; break; @@ -238,20 +240,30 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf messagename = "$OB_VOODOO"; } - if (attacker != NULL && message == NULL) + if (attacker != nullptr && message == nullptr) { if (attacker == self) { message = "$OB_KILLEDSELF"; } - else + else { - IFVIRTUALPTR(attacker, AActor, GetObituary) + lookup.Format("$Obituary_%s_%s", attacker->GetClass()->TypeName.GetChars(), mod.GetChars()); + if (GStrings.CheckString(lookup.GetChars() + 1)) message = lookup.GetChars(); + else { - VMValue params[] = { attacker, self, inflictor, mod.GetIndex(), !!(dmgflags & DMG_PLAYERATTACK) }; - VMReturn rett(&ret); - VMCall(func, params, countof(params), &rett, 1); - if (ret.IsNotEmpty()) message = ret; + lookup.Format("$Obituary_%s", attacker->GetClass()->TypeName.GetChars()); + if (GStrings.CheckString(lookup.GetChars() + 1)) message = lookup.GetChars(); + else + { + IFVIRTUALPTR(attacker, AActor, GetObituary) + { + VMValue params[] = { attacker, self, inflictor, mod.GetIndex(), !!(dmgflags & DMG_PLAYERATTACK) }; + VMReturn rett(&ret); + VMCall(func, params, countof(params), &rett, 1); + if (ret.IsNotEmpty()) message = ret.GetChars(); + } + } } } } @@ -261,7 +273,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf if (message != NULL && message[0] == '$') { - message = GStrings.GetString(message+1, nullptr, self->player->userinfo.GetGender()); + message = GStrings.CheckString(message+1, nullptr, self->player->userinfo.GetGender()); } if (message == NULL) @@ -271,16 +283,16 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf if (mod == NAME_Melee) { FStringf ob("DEFHITOB_%s", cls); - message = GStrings.GetString(ob, nullptr, self->player->userinfo.GetGender()); + message = GStrings.CheckString(ob.GetChars(), nullptr, self->player->userinfo.GetGender()); } if (message == nullptr) { FStringf ob("DEFOB_%s", cls); - message = GStrings.GetString(ob, nullptr, self->player->userinfo.GetGender()); + message = GStrings.CheckString(ob.GetChars(), nullptr, self->player->userinfo.GetGender()); } if (message == nullptr) { - message = GStrings.GetString("OB_DEFAULT", nullptr, self->player->userinfo.GetGender()); + message = GStrings.CheckString("OB_DEFAULT", nullptr, self->player->userinfo.GetGender()); } } @@ -301,36 +313,54 @@ EXTERN_CVAR (Int, fraglimit) void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOfDeath) { - // Handle possible unmorph on death bool wasgibbed = (health < GetGibHealth()); + // Check to see if unmorph Actors need to be killed as well. Originally this was always + // called but that puts an unnecessary burden on the modder to determine whether it's + // a valid call or not. + if (alternative != nullptr && !(flags & MF_UNMORPHED)) { IFVIRTUAL(AActor, MorphedDeath) { - AActor *realthis = NULL; - int realstyle = 0; - int realhealth = 0; + // Return values are no longer used to ensure things stay properly managed. + AActor* const realMo = alternative; + int morphStyle = 0; VMValue params[] = { this }; - VMReturn returns[3]; - returns[0].PointerAt((void**)&realthis); - returns[1].IntAt(&realstyle); - returns[2].IntAt(&realhealth); - VMCall(func, params, 1, returns, 3); - if (realthis && !(realstyle & MORPH_UNDOBYDEATHSAVES)) { - if (wasgibbed) + IFVM(Actor, GetMorphStyle) { - int realgibhealth = realthis->GetGibHealth(); - if (realthis->health >= realgibhealth) - { - realthis->health = realgibhealth - 1; // if morphed was gibbed, so must original be (where allowed)l - } + VMReturn ret[] = { &morphStyle }; + VMCall(func, params, 1, ret, 1); } - realthis->CallDie(source, inflictor, dmgflags, MeansOfDeath); } + VMCall(func, params, 1, nullptr, 0); + + // Kill the dummy Actor if it didn't unmorph, otherwise checking the morph flags. Player pawns need + // to stay, otherwise they won't respawn correctly. + if (realMo != nullptr && !(realMo->flags6 & MF6_KILLED) + && ((alternative != nullptr && player == nullptr) || (alternative == nullptr && !(morphStyle & MORPH_UNDOBYDEATHSAVES)))) + { + if (wasgibbed) + { + const int realGibHealth = realMo->GetGibHealth(); + if (realMo->health >= realGibHealth) + realMo->health = realGibHealth - 1; // If morphed was gibbed, so must original be (where allowed). + } + else if (realMo->health > 0) + { + realMo->health = 0; + } + + // Pass appropriate damage information along when it's confirmed to die. + realMo->DamageTypeReceived = DamageTypeReceived; + realMo->DamageType = DamageType; + realMo->special1 = special1; + + realMo->CallDie(source, inflictor, dmgflags, MeansOfDeath); + } } } @@ -424,7 +454,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf player->fragcount--; if (deathmatch && player->spreecount >= 5 && cl_showsprees) { - PronounMessage (GStrings("SPREEKILLSELF"), buff, + PronounMessage (GStrings.GetString("SPREEKILLSELF"), buff, player->userinfo.GetGender(), player->userinfo.GetName(), player->userinfo.GetName()); StatusBar->AttachMessage (Create(nullptr, buff, @@ -446,7 +476,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf ++source->player->spreecount; } - if (source->player->morphTics) + if (source->alternative != nullptr) { // Make a super chicken source->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2)); } @@ -459,19 +489,19 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf switch (source->player->spreecount) { case 5: - spreemsg = GStrings("SPREE5"); + spreemsg = GStrings.GetString("SPREE5"); break; case 10: - spreemsg = GStrings("SPREE10"); + spreemsg = GStrings.GetString("SPREE10"); break; case 15: - spreemsg = GStrings("SPREE15"); + spreemsg = GStrings.GetString("SPREE15"); break; case 20: - spreemsg = GStrings("SPREE20"); + spreemsg = GStrings.GetString("SPREE20"); break; case 25: - spreemsg = GStrings("SPREE25"); + spreemsg = GStrings.GetString("SPREE25"); break; default: spreemsg = NULL; @@ -482,7 +512,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf { if (!AnnounceSpreeLoss (this)) { - PronounMessage (GStrings("SPREEOVER"), buff, player->userinfo.GetGender(), + PronounMessage (GStrings.GetString("SPREEOVER"), buff, player->userinfo.GetGender(), player->userinfo.GetName(), source->player->userinfo.GetName()); StatusBar->AttachMessage (Create (nullptr, buff, 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); @@ -524,16 +554,16 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf multimsg = NULL; break; case 2: - multimsg = GStrings("MULTI2"); + multimsg = GStrings.GetString("MULTI2"); break; case 3: - multimsg = GStrings("MULTI3"); + multimsg = GStrings.GetString("MULTI3"); break; case 4: - multimsg = GStrings("MULTI4"); + multimsg = GStrings.GetString("MULTI4"); break; default: - multimsg = GStrings("MULTI5"); + multimsg = GStrings.GetString("MULTI5"); break; } if (multimsg != NULL) @@ -557,7 +587,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf if (deathmatch && fraglimit && fraglimit <= D_GetFragCount (source->player)) { - Printf ("%s\n", GStrings("TXT_FRAGLIMIT")); + Printf ("%s\n", GStrings.GetString("TXT_FRAGLIMIT")); Level->ExitLevel (0, false); } } @@ -832,7 +862,7 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int return; player_t *player = target->player; - if (player) + if (player && player->mo) { if ((player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NOPAIN) || ((player->cheats & CF_GODMODE) && damage < TELEFRAG_DAMAGE)) @@ -1195,7 +1225,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da //[RC] Backported from the Zandronum source.. Mostly. - if( target->player && + if( target->player && target->player->mo && damage > 0 && source && mod != NAME_Reflection && @@ -1242,7 +1272,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da { IFVIRTUALPTR(target, AActor, ApplyKickback) { - VMValue params[] = { target, inflictor, source, damage, angle.Degrees, mod.GetIndex(), flags }; + VMValue params[] = { target, inflictor, source, damage, angle.Degrees(), mod.GetIndex(), flags }; VMCall(func, params, countof(params), nullptr, 0); } } @@ -1266,7 +1296,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da // // player specific // - if (player) + if (player && player->mo) { // Don't allow DMG_FORCED to work on ultimate degreeslessness/buddha and nodamage. if ((player->cheats & (CF_GODMODE2 | CF_BUDDHA2)) || (player->mo->flags5 & MF5_NODAMAGE)) @@ -1317,19 +1347,30 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (damage >= player->health && !telefragDamage && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) - && !player->morphTics) + && target->alternative == nullptr) { // Try to use some inventory health P_AutoUseHealth (player, damage - player->health + 1); } } + bool compat_voodoo_zombie = target->Level->i_compatflags2 & COMPATF2_VOODOO_ZOMBIES; + player->health -= damage; // mirror mobj health here for Dave - // [RH] Make voodoo dolls and real players record the same health - target->health = player->mo->health -= damage; + if(compat_voodoo_zombie) + { // [RL0] To allow voodoo zombies, don't set the voodoo doll to the player mobj's health and don't change the player mobj's health on damage + target->health -= damage; + } + else + { // [RH] Make voodoo dolls and real players record the same health + target->health = player->mo->health -= damage; + } if (player->health < 50 && !deathmatch && !(flags & DMG_FORCED)) { P_AutoUseStrifeHealth (player); - player->mo->health = player->health; + if(!compat_voodoo_zombie) + { // [RL0] To match vanilla behavior, don't set the player mo's health to 0 if voodoo zombies compat is enabled + player->mo->health = player->health; + } } if (player->health <= 0) { @@ -1362,10 +1403,10 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da temp = damage < 100 ? damage : 100; if (player == target->Level->GetConsolePlayer() ) { - I_Tactile (40,10,40+temp*2); + //I_Tactile (40,10,40+temp*2); } } - else + else if (!player) { // Armor for monsters. if (!(flags & (DMG_NO_ARMOR|DMG_FORCED)) && target->Inventory != NULL && damage > 0) @@ -1440,7 +1481,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da // check for special fire damage or ice damage deaths if (mod == NAME_Fire) { - if (player && !player->morphTics) + if (player && target->alternative == nullptr) { // Check for flame death if (!inflictor || ((target->health > -50) && (damage > 25)) || @@ -1467,7 +1508,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da } } - const int realdamage = MAX(0, damage); + const int realdamage = max(0, damage); target->Level->localEventManager->WorldThingDamaged(target, inflictor, source, realdamage, mod, flags, angle); needevent = false; @@ -1475,7 +1516,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da return realdamage; } } - return MAX(0, damage); + return max(0, damage); } static int DoDamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, DAngle angle) @@ -1492,7 +1533,7 @@ static int DoDamageMobj(AActor *target, AActor *inflictor, AActor *source, int d target->Level->localEventManager->WorldThingDamaged(target, inflictor, source, realdamage, mod, flags, angle); } - return MAX(0, realdamage); + return max(0, realdamage); } DEFINE_ACTION_FUNCTION(AActor, DamageMobj) @@ -1503,7 +1544,7 @@ DEFINE_ACTION_FUNCTION(AActor, DamageMobj) PARAM_INT(damage); PARAM_NAME(mod); PARAM_INT(flags); - PARAM_FLOAT(angle); + PARAM_ANGLE(angle); ACTION_RETURN_INT(DoDamageMobj(self, inflictor, source, damage, mod, flags, angle)); } @@ -1511,7 +1552,7 @@ int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, { IFVIRTUALPTR(target, AActor, DamageMobj) { - VMValue params[7] = { target, inflictor, source, damage, mod.GetIndex(), flags, angle.Degrees }; + VMValue params[7] = { target, inflictor, source, damage, mod.GetIndex(), flags, angle.Degrees() }; VMReturn ret; int retval; ret.IntAt(&retval); @@ -1591,6 +1632,9 @@ DEFINE_ACTION_FUNCTION(AActor, PoisonMobj) bool AActor::OkayToSwitchTarget(AActor *other) { + if (other == nullptr) + return false; + if (other == this) return false; // [RH] Don't hate self (can happen when shooting barrels) @@ -1600,13 +1644,13 @@ bool AActor::OkayToSwitchTarget(AActor *other) if (!(other->flags & MF_SHOOTABLE)) return false; // Don't attack things that can't be hurt - if ((flags4 & MF4_NOTARGETSWITCH) && target != NULL) + if ((flags4 & MF4_NOTARGETSWITCH) && target != nullptr) return false; // Don't switch target if not allowed - if ((master != NULL && other->IsA(master->GetClass())) || // don't attack your master (or others of its type) - (other->master != NULL && IsA(other->master->GetClass()))) // don't attack your minion (or those of others of your type) + if ((master != nullptr && other->IsA(master->GetClass())) || // don't attack your master (or others of its type) + (other->master != nullptr && IsA(other->master->GetClass()))) // don't attack your minion (or those of others of your type) { - if (!IsHostile (other) && // allow target switch if other is considered hostile + if (!IsHostile(other) && // allow target switch if other is considered hostile (other->tid != TIDtoHate || TIDtoHate == 0) && // or has the tid we hate other->TIDtoHate == TIDtoHate) // or has different hate information { @@ -1614,6 +1658,12 @@ bool AActor::OkayToSwitchTarget(AActor *other) } } + // MBF21 support. + auto mygroup = GetClass()->ActorInfo()->infighting_group; + auto othergroup = other->GetClass()->ActorInfo()->infighting_group; + if (mygroup != 0 && mygroup == othergroup) + return false; + if ((flags7 & MF7_NOINFIGHTSPECIES) && GetSpecies() == other->GetSpecies()) return false; // Don't fight own species. @@ -1765,7 +1815,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPain } if (damage >= player->health && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) - && !player->morphTics) + && target->alternative == nullptr) { // Try to use some inventory health P_AutoUseHealth(player, damage - player->health+1); } @@ -1795,7 +1845,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPain else { target->special1 = damage; - if (player && !player->morphTics) + if (player && target->alternative == nullptr) { // Check for flame death if ((player->poisontype == NAME_Fire) && (target->health > -50) && (damage > 25)) { @@ -1851,8 +1901,8 @@ CCMD (kill) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_MASSACRE); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_MASSACRE); } else if (!stricmp (argv[1], "baddies")) { @@ -1860,12 +1910,12 @@ CCMD (kill) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_MASSACRE2); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (CHT_MASSACRE2); } else { - Net_WriteByte (DEM_KILLCLASSCHEAT); + Net_WriteInt8 (DEM_KILLCLASSCHEAT); Net_WriteString (argv[1]); } } @@ -1876,7 +1926,7 @@ CCMD (kill) return; // Kill the player - Net_WriteByte (DEM_SUICIDE); + Net_WriteInt8 (DEM_SUICIDE); } C_HideConsole (); } @@ -1888,7 +1938,7 @@ CCMD(remove) if (CheckCheatmode()) return; - Net_WriteByte(DEM_REMOVE); + Net_WriteInt8(DEM_REMOVE); Net_WriteString(argv[1]); C_HideConsole(); } diff --git a/src/playsim/p_linkedsectors.cpp b/src/playsim/p_linkedsectors.cpp index 5d327643e8b..1b5a958e5b9 100644 --- a/src/playsim/p_linkedsectors.cpp +++ b/src/playsim/p_linkedsectors.cpp @@ -33,7 +33,7 @@ ** */ -#include "templates.h" + #include "p_local.h" #include "p_lnspec.h" #include "p_spec.h" diff --git a/src/playsim/p_lnspec.cpp b/src/playsim/p_lnspec.cpp index 5a3a67996ec..00318dfbb19 100644 --- a/src/playsim/p_lnspec.cpp +++ b/src/playsim/p_lnspec.cpp @@ -57,6 +57,7 @@ #include "g_levellocals.h" #include "vm.h" #include "p_destructible.h" +#include "s_sndseq.h" // Remaps EE sector change types to Generic_Floor values. According to the Eternity Wiki: /* @@ -77,7 +78,7 @@ static const uint8_t ChangeMap[8] = { 0, 1, 5, 3, 7, 2, 6, 0 }; #define SPEED(a) ((a) / 8.) #define TICS(a) (((a)*TICRATE)/35) #define OCTICS(a) (((a)*TICRATE)/8) -#define BYTEANGLE(a) ((a) * (360./256.)) +#define BYTEANGLE(a) DAngle::fromDeg((a) * (360./256.)) #define CRUSH(a) ((a) > 0? (a) : -1) #define CHANGE(a) (((a) >= 0 && (a)<=7)? ChangeMap[a]:0) @@ -174,7 +175,7 @@ FUNC(LS_Polyobj_MoveToSpot) auto iterator = Level->GetActorIterator(arg2); AActor *spot = iterator.Next(); if (spot == NULL) return false; - return EV_MovePolyTo (Level, ln, arg0, SPEED(arg1), spot->Pos(), false); + return EV_MovePolyTo (Level, ln, arg0, SPEED(arg1), spot->Pos().XY(), false); } FUNC(LS_Polyobj_DoorSwing) @@ -225,7 +226,7 @@ FUNC(LS_Polyobj_OR_MoveToSpot) auto iterator = Level->GetActorIterator(arg2); AActor *spot = iterator.Next(); if (spot == NULL) return false; - return EV_MovePolyTo (Level, ln, arg0, SPEED(arg1), spot->Pos(), true); + return EV_MovePolyTo (Level, ln, arg0, SPEED(arg1), spot->Pos().XY(), true); } FUNC(LS_Polyobj_Stop) @@ -234,6 +235,20 @@ FUNC(LS_Polyobj_Stop) return EV_StopPoly (Level, arg0); } +FUNC(LS_Polyobj_StopSound) +// Polyobj_StopSound (po) +{ + FPolyObj *poly; + + poly = Level->GetPolyobj(arg0); + if (poly != nullptr) + { + SN_StopSequence(poly); + } + + return true; +} + FUNC(LS_Door_Close) // Door_Close (tag, speed, lighttag) { @@ -558,7 +573,7 @@ FUNC(LS_Generic_Floor) } return Level->EV_DoFloor (type, ln, arg0, SPEED(arg1), arg2, - (arg4 & 16) ? 20 : -1, arg4 & 7, false); + (arg4 & 16) ? 20 : -1, arg4 & 7, true); } @@ -926,6 +941,13 @@ FUNC(LS_Generic_Crusher2) SPEED(arg2), 0, arg4, arg3 ? 2 : 0, 0, DCeiling::ECrushMode::crushHexen); } +FUNC(LS_Generic_CrusherDist) +// Generic_CrusherDist (tag, dnspeed, upspeed, silent, damage) +{ + return Level->EV_DoCeiling(DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), + SPEED(arg2), 8, arg4, arg3 ? 2 : 0, 0, (arg1 <= 24 && arg2 <= 24) ? DCeiling::ECrushMode::crushSlowdown : DCeiling::ECrushMode::crushDoom); +} + FUNC(LS_Plat_PerpetualRaise) // Plat_PerpetualRaise (tag, speed, delay) { @@ -1060,7 +1082,7 @@ FUNC(LS_Generic_Lift) FUNC(LS_Exit_Normal) // Exit_Normal (position) { - if (Level->CheckIfExitIsGood (it, FindLevelInfo(Level->NextMap))) + if (Level->CheckIfExitIsGood (it, FindLevelInfo(Level->NextMap.GetChars()))) { Level->ExitLevel (arg0, false); return true; @@ -1088,7 +1110,7 @@ FUNC(LS_Teleport_NewMap) if (info && Level->CheckIfExitIsGood (it, info)) { - Level->ChangeLevel(info->MapName, arg1, arg2 ? CHANGELEVEL_KEEPFACING : 0); + Level->ChangeLevel(info->MapName.GetChars(), arg1, arg2 ? CHANGELEVEL_KEEPFACING : 0); return true; } } @@ -1098,7 +1120,7 @@ FUNC(LS_Teleport_NewMap) FUNC(LS_Teleport) // Teleport (tid, sectortag, bNoSourceFog) { - int flags = TELF_DESTFOG; + int flags = TELF_DESTFOG | TELF_FDCOMPAT; if (!arg2) { flags |= TELF_SOURCEFOG; @@ -1721,13 +1743,13 @@ FUNC(LS_Thing_Hate) FUNC(LS_Thing_ProjectileAimed) // Thing_ProjectileAimed (tid, type, speed, target, newtid) { - return Level->EV_Thing_Projectile (arg0, it, arg1, NULL, 0., SPEED(arg2), 0, arg3, it, 0, arg4, false); + return Level->EV_Thing_Projectile (arg0, it, arg1, NULL, nullAngle, SPEED(arg2), 0, arg3, it, 0, arg4, false); } FUNC(LS_Thing_ProjectileIntercept) // Thing_ProjectileIntercept (tid, type, speed, target, newtid) { - return Level->EV_Thing_Projectile (arg0, it, arg1, NULL, 0., SPEED(arg2), 0, arg3, it, 0, arg4, true); + return Level->EV_Thing_Projectile (arg0, it, arg1, NULL, nullAngle, SPEED(arg2), 0, arg3, it, 0, arg4, true); } // [BC] added newtid for next two @@ -1746,7 +1768,7 @@ FUNC(LS_Thing_SpawnNoFog) FUNC(LS_Thing_SpawnFacing) // Thing_SpawnFacing (tid, type, nofog, newtid) { - return Level->EV_Thing_Spawn (arg0, it, arg1, 1000000., arg2 ? false : true, arg3); + return Level->EV_Thing_Spawn (arg0, it, arg1, DAngle::fromDeg(1000000.), arg2 ? false : true, arg3); } FUNC(LS_Thing_Raise) @@ -1855,7 +1877,7 @@ FUNC(LS_Thing_SetTranslation) // Thing_SetTranslation (tid, range) { auto iterator = Level->GetActorIterator(arg0); - int range; + FTranslationID range; AActor *target; bool ok = false; @@ -1873,7 +1895,7 @@ FUNC(LS_Thing_SetTranslation) } else { - range = 0; + range = NO_TRANSLATION; } if (arg0 == 0) @@ -1881,7 +1903,7 @@ FUNC(LS_Thing_SetTranslation) if (it != NULL) { ok = true; - it->Translation = range==0? it->GetDefault()->Translation : range; + it->Translation = range == NO_TRANSLATION ? it->GetDefault()->Translation : range; } } else @@ -1889,7 +1911,7 @@ FUNC(LS_Thing_SetTranslation) while ( (target = iterator.Next ()) ) { ok = true; - target->Translation = range==0? target->GetDefault()->Translation : range; + target->Translation = range == NO_TRANSLATION ? target->GetDefault()->Translation : range; } } @@ -1906,11 +1928,11 @@ FUNC(LS_ACS_Execute) if (arg1 == 0) { - mapname = Level->MapName; + mapname = Level->MapName.GetChars(); } else if ((info = FindLevelByNum(arg1)) != NULL) { - mapname = info->MapName; + mapname = info->MapName.GetChars(); } else { @@ -1929,11 +1951,11 @@ FUNC(LS_ACS_ExecuteAlways) if (arg1 == 0) { - mapname = Level->MapName; + mapname = Level->MapName.GetChars(); } else if ((info = FindLevelByNum(arg1)) != NULL) { - mapname = info->MapName; + mapname = info->MapName.GetChars(); } else { @@ -1969,7 +1991,7 @@ FUNC(LS_ACS_ExecuteWithResult) int args[4] = { arg1, arg2, arg3, arg4 }; int flags = (backSide ? ACS_BACKSIDE : 0) | ACS_ALWAYS | ACS_WANTRESULT; - return P_StartScript (Level, it, ln, arg0, Level->MapName, args, 4, flags); + return P_StartScript (Level, it, ln, arg0, Level->MapName.GetChars(), args, 4, flags); } FUNC(LS_ACS_Suspend) @@ -1978,9 +2000,9 @@ FUNC(LS_ACS_Suspend) level_info_t *info; if (arg1 == 0) - P_SuspendScript (Level, arg0, Level->MapName); + P_SuspendScript (Level, arg0, Level->MapName.GetChars()); else if ((info = FindLevelByNum (arg1)) ) - P_SuspendScript (Level, arg0, info->MapName); + P_SuspendScript (Level, arg0, info->MapName.GetChars()); return true; } @@ -1991,9 +2013,9 @@ FUNC(LS_ACS_Terminate) level_info_t *info; if (arg1 == 0) - P_TerminateScript (Level, arg0, Level->MapName); + P_TerminateScript (Level, arg0, Level->MapName.GetChars()); else if ((info = FindLevelByNum (arg1)) ) - P_TerminateScript (Level, arg0, info->MapName); + P_TerminateScript (Level, arg0, info->MapName.GetChars()); return true; } @@ -2146,7 +2168,7 @@ FUNC(LS_Light_Stop) FUNC(LS_Radius_Quake) // Radius_Quake (intensity, duration, damrad, tremrad, tid) { - return P_StartQuake (Level, it, arg4, arg0, arg1, arg2*64, arg3*64, "world/quake"); + return P_StartQuake (Level, it, arg4, (double)arg0, arg1, arg2*64, arg3*64, S_FindSound("world/quake")); } FUNC(LS_UsePuzzleItem) @@ -2568,8 +2590,8 @@ FUNC(LS_Sector_SetCeilingScale2) FUNC(LS_Sector_SetRotation) // Sector_SetRotation (tag, floor-angle, ceiling-angle) { - DAngle ceiling = (double)arg2; - DAngle floor = (double)arg1; + DAngle ceiling = DAngle::fromDeg(arg2); + DAngle floor = DAngle::fromDeg(arg1); auto itr = Level->GetSectorTagIterator(arg0); int secnum; @@ -2721,40 +2743,47 @@ FUNC(LS_Line_SetTextureScale) FUNC(LS_Line_SetBlocking) // Line_SetBlocking (id, setflags, clearflags) { - static const int flagtrans[] = - { - ML_BLOCKING, - ML_BLOCKMONSTERS, - ML_BLOCK_PLAYERS, - ML_BLOCK_FLOATERS, - ML_BLOCKPROJECTILE, - ML_BLOCKEVERYTHING, - ML_RAILING, - ML_BLOCKUSE, - ML_BLOCKSIGHT, - ML_BLOCKHITSCAN, - ML_SOUNDBLOCK, - -1 - }; - - if (arg0 == 0) return false; - - int setflags = 0; - int clearflags = 0; - - for(int i = 0; flagtrans[i] != -1; i++, arg1 >>= 1, arg2 >>= 1) - { - if (arg1 & 1) setflags |= flagtrans[i]; - if (arg2 & 1) clearflags |= flagtrans[i]; - } - - auto itr = Level->GetLineIdIterator(arg0); - int line; - while ((line = itr.Next()) >= 0) - { - Level->lines[line].flags = (Level->lines[line].flags & ~clearflags) | setflags; - } - return true; + struct FlagTransEntry + { + int fieldIndex, bitmask; + }; + + static const FlagTransEntry flagtrans[] = + { + {0, ML_BLOCKING}, + {0, ML_BLOCKMONSTERS}, + {0, ML_BLOCK_PLAYERS}, + {0, ML_BLOCK_FLOATERS}, + {0, ML_BLOCKPROJECTILE}, + {0, ML_BLOCKEVERYTHING}, + {0, ML_RAILING}, + {0, ML_BLOCKUSE}, + {0, ML_BLOCKSIGHT}, + {0, ML_BLOCKHITSCAN}, + {0, ML_SOUNDBLOCK}, + {1, ML2_BLOCKLANDMONSTERS}, + {-1, -1}, + }; + + if (arg0 == 0) return false; + + int setflags[2] = {}; + int clearflags[2] = {}; + + for (int i = 0; flagtrans[i].bitmask != -1; i++, arg1 >>= 1, arg2 >>= 1) + { + if (arg1 & 1) setflags[flagtrans[i].fieldIndex] |= flagtrans[i].bitmask; + if (arg2 & 1) clearflags[flagtrans[i].fieldIndex] |= flagtrans[i].bitmask; + } + + auto itr = Level->GetLineIdIterator(arg0); + int line; + while ((line = itr.Next()) >= 0) + { + Level->lines[line].flags = (Level->lines[line].flags & ~clearflags[0]) | setflags[0]; + Level->lines[line].flags2 = (Level->lines[line].flags2 & ~clearflags[1]) | setflags[1]; + } + return true; } FUNC(LS_Line_SetAutomapFlags) @@ -2892,7 +2921,14 @@ enum PROP_UNUSED1, PROP_UNUSED2, PROP_SPEED, + PROP_BUDDHA, + PROP_BUDDHA2, + PROP_FRIGHTENING, + PROP_NOCLIP, + PROP_NOCLIP2, + PROP_GODMODE, + PROP_GODMODE2, }; FUNC(LS_SetPlayerProperty) @@ -3013,24 +3049,43 @@ FUNC(LS_SetPlayerProperty) // Set or clear a flag switch (arg2) { - case PROP_BUDDHA: - mask = CF_BUDDHA; - break; - case PROP_FROZEN: - mask = CF_FROZEN; - break; - case PROP_NOTARGET: - mask = CF_NOTARGET; - break; - case PROP_INSTANTWEAPONSWITCH: - mask = CF_INSTANTWEAPSWITCH; - break; - case PROP_FLY: - //mask = CF_FLY; - break; - case PROP_TOTALLYFROZEN: - mask = CF_TOTALLYFROZEN; - break; + case PROP_BUDDHA: + mask = CF_BUDDHA; + break; + case PROP_BUDDHA2: + mask = CF_BUDDHA2; + break; + case PROP_FROZEN: + mask = CF_FROZEN; + break; + case PROP_NOTARGET: + mask = CF_NOTARGET; + break; + case PROP_INSTANTWEAPONSWITCH: + mask = CF_INSTANTWEAPSWITCH; + break; + //CF_FLY has special handling + case PROP_FLY: + //mask = CF_FLY; + break; + case PROP_TOTALLYFROZEN: + mask = CF_TOTALLYFROZEN; + break; + case PROP_FRIGHTENING: + mask = CF_FRIGHTENING; + break; + case PROP_NOCLIP: + mask = CF_NOCLIP; + break; + case PROP_NOCLIP2: + mask = CF_NOCLIP|CF_NOCLIP2; //Both must be on. + break; + case PROP_GODMODE: + mask = CF_GODMODE; + break; + case PROP_GODMODE2: + mask = CF_GODMODE2; + break; } if (arg0 == 0) @@ -3125,7 +3180,7 @@ FUNC(LS_Autosave) if (gameaction != ga_savegame) { Level->flags2 &= ~LEVEL2_NOAUTOSAVEHINT; - Net_WriteByte (DEM_CHECKAUTOSAVE); + Net_WriteInt8 (DEM_CHECKAUTOSAVE); } return true; } @@ -3196,13 +3251,14 @@ FUNC(LS_SendToCommunicator) if (it->CheckLocalView()) { S_StopSound (CHAN_VOICE); - it->player->SetSubtitle(arg0, name); - S_Sound (CHAN_VOICE, 0, name, 1, ATTN_NORM); + auto snd = S_FindSound(name); + it->player->SetSubtitle(arg0, snd); + S_Sound (CHAN_VOICE, 0, snd, 1, ATTN_NORM); // Get the message from the LANGUAGE lump. FString msg; msg.Format("TXT_COMM%d", arg2); - const char *str = GStrings[msg]; + const char *str = GStrings.CheckString(msg.GetChars()); if (str != NULL) { Printf (PRINT_CHAT, "%s\n", str); @@ -3219,7 +3275,7 @@ FUNC(LS_ForceField) if (it != NULL) { P_DamageMobj (it, NULL, NULL, 16, NAME_None); - it->Thrust(it->Angles.Yaw + 180, 7.8125); + it->Thrust(it->Angles.Yaw + DAngle::fromDeg(180), 7.8125); } return true; } @@ -3293,7 +3349,7 @@ FUNC(LS_GlassBreak) } if (glass != nullptr) { - glass->Angles.Yaw = pr_glass() * (360 / 256.); + glass->Angles.Yaw = DAngle::fromDeg(pr_glass() * (360 / 256.)); glass->VelFromAngle(pr_glass() & 3); glass->Vel.Z = (pr_glass() & 7); // [RH] Let the shards stick around longer than they did in Strife. @@ -3813,8 +3869,8 @@ static lnSpecFunc LineSpecials[] = /* 280 */ LS_Ceiling_MoveToValueAndCrush, /* 281 */ LS_Line_SetAutomapFlags, /* 282 */ LS_Line_SetAutomapStyle, - - + /* 283 */ LS_Polyobj_StopSound, + /* 284 */ LS_Generic_CrusherDist }; #define DEFINE_SPECIAL(name, num, min, max, mmax) {#name, num, min, max, mmax}, @@ -3911,6 +3967,13 @@ int P_FindLineSpecial (const char *string, int *min_args, int *max_args) max = mid - 1; } } + // Alias for ZScript. Check here to have universal support everywhere. + if (!stricmp(string, "TeleportSpecial")) + { + if (min_args != NULL) *min_args = 1; + if (max_args != NULL) *max_args = 3; + return Teleport; + } return 0; } @@ -3958,4 +4021,3 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, ExecuteSpecial) ACTION_RETURN_INT(P_ExecuteSpecial(self, special, linedef, activator, lineside, arg1, arg2, arg3, arg4, arg5)); } - diff --git a/src/playsim/p_lnspec.h b/src/playsim/p_lnspec.h index 044605b1599..7072e31e53c 100644 --- a/src/playsim/p_lnspec.h +++ b/src/playsim/p_lnspec.h @@ -180,10 +180,18 @@ typedef enum { // [RH] Equivalents for BOOM's generalized sector types -#define DAMAGE_MASK 0x0300 -#define SECRET_MASK 0x0400 -#define FRICTION_MASK 0x0800 -#define PUSH_MASK 0x1000 +enum +{ + DAMAGE_MASK = 0x0300, + SECRET_MASK = 0x0400, + FRICTION_MASK = 0x0800, + PUSH_MASK = 0x1000, + SILENCE_MASK = 0x2000, // Unimplemented Boom flag - handled differently. + SILENTMOVE_MASK = 0x4000, // Unimplemented Boom flag - handled differently. + // mbf21 + DEATH_MASK = 0x8000, + KILL_MONSTERS_MASK = 0x10000 +}; struct line_t; class AActor; diff --git a/src/playsim/p_local.h b/src/playsim/p_local.h index 0c7bb1bc724..cde45f403ca 100644 --- a/src/playsim/p_local.h +++ b/src/playsim/p_local.h @@ -50,6 +50,8 @@ struct secplane_t; struct FCheckPosition; struct FTranslatedLineTarget; struct FLinePortal; +class DViewPosition; +struct FRenderViewpoint; #include @@ -61,7 +63,6 @@ struct FLinePortal; #define USERANGE (64.) #define DEFMELEERANGE (64.) -#define SAWRANGE (64.+(1./65536.)) // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states) #define MISSILERANGE (32*64.) #define PLAYERMISSILERANGE (8192.) // [RH] New MISSILERANGE for players @@ -92,8 +93,7 @@ void P_PredictionLerpReset(); #define SPF_TEMPPLAYER 1 // spawning a short-lived dummy player #define SPF_WEAPONFULLYUP 2 // spawn with weapon already raised -int P_FaceMobj (AActor *source, AActor *target, DAngle *delta); -bool P_SeekerMissile (AActor *actor, double thresh, double turnMax, bool precise = false, bool usecurspeed=false); +bool P_SeekerMissile (AActor *actor, DAngle thresh, DAngle turnMax, bool precise = false, bool usecurspeed=false); enum EPuffFlags { @@ -117,8 +117,6 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct AActor *P_SpawnMissile (AActor* source, AActor* dest, PClassActor *type, AActor* owner = NULL); AActor *P_SpawnMissileZ(AActor* source, double z, AActor* dest, PClassActor *type); AActor *P_SpawnMissileXYZ(DVector3 pos, AActor *source, AActor *dest, PClassActor *type, bool checkspawn = true, AActor *owner = NULL); -AActor *P_SpawnMissileAngle(AActor *source, PClassActor *type, DAngle angle, double vz); -AActor *P_SpawnMissileAngleZ(AActor *source, double z, PClassActor *type, DAngle angle, double vz); AActor *P_SpawnMissileAngleZSpeed(AActor *source, double z, PClassActor *type, DAngle angle, double vz, double speed, AActor *owner = NULL, bool checkspawn = true); AActor *P_SpawnMissileZAimed(AActor *source, double z, AActor *dest, PClassActor *type); @@ -217,6 +215,13 @@ enum WARPF WARPF_COPYPITCH = 0x8000, }; +enum SPF +{ + SPF_FORCECLAMP = 1, // players always clamp + SPF_INTERPOLATE = 2, + SPF_SCALEDNOLERP = 4, +}; + enum PCM { PCM_DROPOFF = 1, @@ -225,8 +230,9 @@ enum PCM }; +int P_CheckFov(AActor* t1, AActor* t2, double fov); AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false, bool frontonly = false); +AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false, bool frontonly = false, double fov = 0); // // P_MAP @@ -246,6 +252,7 @@ extern TArray portalhit; int P_TestMobjLocation (AActor *mobj); int P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL); bool P_CheckPosition(AActor *thing, const DVector2 &pos, bool actorsonly = false); +void P_DoMissileDamage(AActor* inflictor, AActor* target); bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, bool actorsonly = false); AActor *P_CheckOnmobj (AActor *thing); void P_FakeZMovement (AActor *mo); @@ -262,6 +269,7 @@ void P_PlayerStartStomp (AActor *actor, bool mononly=false); // [RH] Stomp on t void P_SlideMove (AActor* mo, const DVector2 &pos, int numsteps); bool P_BounceWall (AActor *mo); bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); +bool P_ReflectOffActor(AActor* mo, AActor* blocking); int P_CheckSight (AActor *t1, AActor *t2, int flags=0); enum ESightFlags @@ -293,7 +301,7 @@ void P_FindFloorCeiling (AActor *actor, int flags=0); bool P_ChangeSector (sector_t* sector, int crunch, double amt, int floorOrCeil, bool isreset, bool instant = false); -DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLineTarget *pLineTarget = NULL, DAngle vrange = 0., int flags = 0, AActor *target = NULL, AActor *friender = NULL); +DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLineTarget *pLineTarget = NULL, DAngle vrange = nullAngle, int flags = 0, AActor *target = NULL, AActor *friender = NULL); enum // P_AimLineAttack flags { @@ -304,6 +312,7 @@ enum // P_AimLineAttack flags ALF_NOFRIENDS = 16, ALF_PORTALRESTRICT = 32, // only work through portals with a global offset (to be used for stuff that cannot remember the calculated FTranslatedLineTarget info) ALF_NOWEAPONCHECK = 64, // ignore NOAUTOAIM flag on a player's weapon. + ALF_IGNORENOAUTOAIM = 128, // for informative stuff like 'linetarget' CCMD. }; enum // P_LineAttack flags @@ -356,8 +365,8 @@ struct FRailParams double maxdiff = 0; int flags = 0; PClassActor *puff = nullptr; - DAngle angleoffset = 0.; - DAngle pitchoffset = 0.; + DAngle angleoffset = nullAngle; + DAngle pitchoffset = nullAngle; double distance = 8192; int duration = 0; double sparsity = 1.0; @@ -384,8 +393,9 @@ bool P_CheckMissileSpawn(AActor *missile, double maxdist); void P_PlaySpawnSound(AActor *missile, AActor *spawner); -// [RH] Position the chasecam -void P_AimCamera (AActor *t1, DVector3 &, DAngle &, sector_t *&sec, bool &unlinked); +// [RH] Position the cam's view offsets. +void R_OffsetView(FRenderViewpoint& viewPoint, const DVector3& dir, const double distance); + // [RH] Means of death enum @@ -395,11 +405,14 @@ enum RADF_SOURCEISSPOT = 4, RADF_NODAMAGE = 8, RADF_THRUSTZ = 16, - RADF_OLDRADIUSDAMAGE = 32 + RADF_OLDRADIUSDAMAGE = 32, + RADF_THRUSTLESS = 64, + RADF_NOALLIES = 128, + RADF_CIRCULAR = 256 }; -int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg); -int P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, - FName damageType, int flags, int fulldamagedistance=0); +int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, double distance, double fulldmgdistance, bool oldradiusdmg, bool circular); +int P_RadiusAttack (AActor *spot, AActor *source, int damage, double distance, + FName damageType, int flags, double fulldamagedistance=0.0, FName species = NAME_None); void P_DelSeclist(msecnode_t *, msecnode_t *sector_t::*seclisthead); void P_DelSeclist(portnode_t *, portnode_t *FLinePortal::*seclisthead); @@ -421,7 +434,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, DVector2 &move); // P_INTER // void P_TouchSpecialThing (AActor *special, AActor *toucher); -int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0, DAngle angle = 0.); +int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0, DAngle angle = nullAngle); void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type); bool P_GiveBody (AActor *actor, int num, int max=0); bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index ae0eecef0cf..af8df92a7e4 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -61,7 +61,7 @@ #include #include -#include "templates.h" + #include "m_bbox.h" #include "m_random.h" @@ -82,6 +82,7 @@ #include "p_blockmap.h" #include "p_3dmidtex.h" #include "vm.h" +#include "d_main.h" #include "decallib.h" @@ -92,6 +93,7 @@ #include "r_sky.h" #include "g_levellocals.h" #include "actorinlines.h" +#include CVAR(Bool, cl_bloodsplats, true, CVAR_ARCHIVE) CVAR(Int, sv_smartaim, 0, CVAR_ARCHIVE | CVAR_SERVERINFO) @@ -111,6 +113,20 @@ static FRandom pr_crunch("DoCrunch"); TArray spechit; TArray portalhit; +//========================================================================== +// +// P_ShouldPassThroughPlayer +// Allows players to walk through and shoot through each other (useful in +// multiplayer) +// +//========================================================================== + +bool P_ShouldPassThroughPlayer(AActor *self, AActor *other) +{ + return (dmflags3 & DF3_NO_PLAYER_CLIP) && + other->player && other->player->mo == other && + self->IsFriend(other); +} //========================================================================== // @@ -155,6 +171,57 @@ bool P_CanCollideWith(AActor *tmthing, AActor *thing) return true; } +void P_CollidedWith(AActor* const collider, AActor* const collidee) +{ + { + IFVIRTUALPTR(collider, AActor, CollidedWith) + { + VMValue params[] = { collider, collidee, false }; + VMCall(func, params, 3, nullptr, 0); + } + } + + { + IFVIRTUALPTR(collidee, AActor, CollidedWith) + { + VMValue params[] = { collidee, collider, true }; + VMCall(func, params, 3, nullptr, 0); + } + } +} + +//========================================================================== +// +// CanCrossLine +// +// Checks if an actor can cross a line after all checks are processed. +// If false, the line blocks them. +//========================================================================== + +bool P_CanCrossLine(AActor *mo, line_t *line, DVector3 next) +{ + static unsigned VIndex = ~0u; + if (VIndex == ~0u) + { + VIndex = GetVirtualIndex(RUNTIME_CLASS(AActor), "CanCrossLine"); + assert(VIndex != ~0u); + } + + VMValue params[] = { mo, line, next.X, next.Y, next.Z, false }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + + auto clss = mo->GetClass(); + VMFunction *func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; + if (func != nullptr) + { + VMCall(func, params, countof(params), &ret, 1); + return retval; + } + return true; +} + //========================================================================== // // FindRefPoint @@ -204,7 +271,7 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLines { line_t *ld = cres.line; - if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1) + if (!inRange(box, ld) || BoxOnLineSide(box, ld) != -1) return true; // A line has been hit @@ -220,7 +287,7 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLines return true; } - DVector2 refpoint = FindRefPoint(ld, cres.Position); + DVector2 refpoint = FindRefPoint(ld, cres.Position.XY()); FLineOpening open; P_LineOpening(open, tmf.thing, ld, refpoint, &cres.Position, flags); @@ -447,11 +514,14 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi if (th == thing) continue; - double blockdist = th->radius + tmf.thing->radius; - if (fabs(th->X() - cres2.Position.X) >= blockdist || fabs(th->Y() - cres2.Position.Y) >= blockdist) + if ((th->flags2 | tmf.thing->flags2) & MF2_THRUACTORS) continue; - if ((th->flags2 | tmf.thing->flags2) & MF2_THRUACTORS) + if ((th->ThruBits & tmf.thing->ThruBits) && ((th->flags8 | tmf.thing->flags8) & MF8_ALLOWTHRUBITS)) + continue; + + double blockdist = th->radius + tmf.thing->radius; + if (fabs(th->X() - cres2.Position.X) >= blockdist || fabs(th->Y() - cres2.Position.Y) >= blockdist) continue; if (tmf.thing->flags6 & MF6_THRUSPECIES && tmf.thing->GetSpecies() == th->GetSpecies()) @@ -474,7 +544,10 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi continue; // Don't let players and monsters block item teleports (all other actor types will still block.) - if (thing->IsKindOf(NAME_Inventory) && !(thing->flags & MF_SOLID) && ((th->flags3 & MF3_ISMONSTER) || th->player != nullptr)) + if ((thing->IsKindOf(NAME_Inventory) || (thing->flags2 & MF2_TELESTOMP)) && !(thing->flags & MF_SOLID) && ((th->flags3 & MF3_ISMONSTER) || th->player != nullptr)) + continue; + + if (tmf.thing->player && P_ShouldPassThroughPlayer(tmf.thing, th)) continue; // monsters don't stomp things except on boss level @@ -487,6 +560,7 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi P_DamageMobj(th, thing, thing, TELEFRAG_DAMAGE, NAME_Telefrag, DMG_THRUSTLESS); continue; } + return false; } @@ -776,7 +850,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec line_t *ld = cres.line; bool rail = false; - if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1) + if (!inRange(box, ld) || BoxOnLineSide(box, ld) != -1) return true; // A line has been hit @@ -797,8 +871,8 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec { spechit_t spec; spec.line = ld; - spec.Refpos = cres.Position; - spec.Oldrefpos = tm.thing->PosRelative(ld); + spec.Refpos = cres.Position.XY(); + spec.Oldrefpos = tm.thing->PosRelative(ld).XY(); portalhit.Push(spec); return true; } @@ -846,12 +920,6 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec // MBF bouncers are treated as missiles here. bool Projectile = (tm.thing->flags & MF_MISSILE || tm.thing->BounceFlags & BOUNCE_MBF); - // MBF considers that friendly monsters are not blocked by monster-blocking lines. - // This is added here as a compatibility option. Note that monsters that are dehacked - // into being friendly with the MBF flag automatically gain MF3_NOBLOCKMONST, so this - // just optionally generalizes the behavior to other friendly monsters. - bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST) - || ((tm.thing->Level->i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY))); uint32_t ProjectileBlocking = ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE; if ( tm.thing->flags8 & MF8_BLOCKASPLAYER ) ProjectileBlocking |= ML_BLOCK_PLAYERS | ML_BLOCKING; @@ -862,11 +930,8 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec { rail = true; } - else if ((ld->flags & (ML_BLOCKING | ML_BLOCKEVERYTHING)) || // explicitly blocking everything - (!(NotBlocked) && (ld->flags & ML_BLOCKMONSTERS)) || // block monsters only - (((tm.thing->player != NULL) || (tm.thing->flags8 & MF8_BLOCKASPLAYER)) && (ld->flags & ML_BLOCK_PLAYERS)) || // block players - ((Projectile) && (ld->flags & ML_BLOCKPROJECTILE)) || // block projectiles - ((tm.thing->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS))) // block floaters + else if (P_IsBlockedByLine(tm.thing, ld) || + ((Projectile) && (ld->flags & ML_BLOCKPROJECTILE))) { if (cres.portalflags & FFCF_NOFLOOR) { @@ -918,12 +983,12 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec tm.thing->BlockingLine = ld; } // Calculate line side based on the actor's original position, not the new one. - CheckForPushSpecial(ld, P_PointOnLineSide(cres.Position, ld), tm.thing); + CheckForPushSpecial(ld, P_PointOnLineSide(cres.Position.XY(), ld), tm.thing); return false; } } } - DVector2 ref = FindRefPoint(ld, cres.Position); + DVector2 ref = FindRefPoint(ld, cres.Position.XY()); FLineOpening open; P_LineOpening(open, tm.thing, ld, ref, &cres.Position, cres.portalflags); @@ -952,13 +1017,20 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec if (!(tm.thing->flags & MF_DROPOFF) && !(tm.thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) { - if ((open.frontfloorplane.fC() < STEEPSLOPE) != (open.backfloorplane.fC() < STEEPSLOPE)) + if ((open.frontfloorplane.fC() < tm.thing->MaxSlopeSteepness) != (open.backfloorplane.fC() < tm.thing->MaxSlopeSteepness)) { // on the boundary of a steep slope return false; } } + if ((tm.thing->flags8 & MF8_CROSSLINECHECK) && !P_CanCrossLine(tm.thing, ld, tm.pos)) + { + if (wasfit) + tm.thing->BlockingLine = ld; + + return false; + } // If the floor planes on both sides match we should recalculate open.bottom at the actual position we are checking // This is to avoid bumpy movement when crossing a linedef with the same slope on both sides. // This should never narrow down the opening, though, only widen it. @@ -1037,15 +1109,15 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec if (ld->special) { spec.line = ld; - spec.Refpos = cres.Position; - spec.Oldrefpos = tm.thing->PosRelative(ld); + spec.Refpos = cres.Position.XY(); + spec.Oldrefpos = tm.thing->PosRelative(ld).XY(); spechit.Push(spec); } if (ld->isLinePortal()) { spec.line = ld; - spec.Refpos = cres.Position; - spec.Oldrefpos = tm.thing->PosRelative(ld); + spec.Refpos = cres.Position.XY(); + spec.Oldrefpos = tm.thing->PosRelative(ld).XY(); portalhit.Push(spec); } @@ -1073,7 +1145,7 @@ static bool PIT_CheckPortal(FMultiBlockLinesIterator &mit, FMultiBlockLinesItera // if in another vertical section let's just ignore it. if (cres.portalflags & (FFCF_NOCEILING | FFCF_NOFLOOR)) return false; - if (!box.inRange(cres.line) || box.BoxOnLineSide(cres.line) != -1) + if (!inRange(box, cres.line) || BoxOnLineSide(box, cres.line) != -1) return false; line_t *lp = cres.line->getPortalDestination(); @@ -1095,13 +1167,13 @@ static bool PIT_CheckPortal(FMultiBlockLinesIterator &mit, FMultiBlockLinesItera // Check all lines at the destination while ((ld = it.Next())) { - if (!pbox.inRange(ld) || pbox.BoxOnLineSide(ld) != -1) + if (!inRange(pbox, ld) || BoxOnLineSide(pbox, ld) != -1) continue; if (ld->backsector == NULL) continue; - DVector2 ref = FindRefPoint(ld, cres.Position); + DVector2 ref = FindRefPoint(ld, cres.Position.XY()); FLineOpening open; P_LineOpening(open, tm.thing, ld, ref, &cres.Position, 0); @@ -1163,6 +1235,29 @@ static bool CheckRipLevel(AActor *victim, AActor *projectile) // //========================================================================== +static bool P_ProjectileImmune(AActor* target, AActor* source) +{ + // This one's directly taken from DSDA. + auto targetgroup = target->GetClass()->ActorInfo()->projectile_group; + auto sourcegroup = source->GetClass()->ActorInfo()->projectile_group; + + return + ( // PG_GROUPLESS means no immunity, even to own species + targetgroup != -1/*PG_GROUPLESS*/ || + target == source + ) && + ( + ( // target type has default behaviour, and things are the same type + targetgroup == 0/*PG_DEFAULT*/ && + (source->GetSpecies() == target->GetSpecies() && !(target->flags6 & MF6_DOHARMSPECIES)) + ) || + ( // target type has special behaviour, and things have the same group + targetgroup != 0/*PG_DEFAULT*/ && + targetgroup == sourcegroup + ) + ); +} + static bool CanAttackHurt(AActor *victim, AActor *shooter) { // players are never subject to infighting settings and are always allowed @@ -1210,7 +1305,8 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) // [RH] Don't hurt monsters that hate the same victim as you do return false; } - if (victim->GetSpecies() == shooter->GetSpecies() && !(victim->flags6 & MF6_DOHARMSPECIES)) + + if (P_ProjectileImmune(victim, shooter)) { // Don't hurt same species or any relative - // but only if the target isn't one's hostile. @@ -1230,6 +1326,57 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) return true; } +//========================================================================== +// +// P_DoMissileDamage +// Handle damaging/poisoning enemies from missiles. +// target is the target to be dealt damage to. +// inflictor is the actor dealing the damage. +// +//========================================================================== + +void P_DoMissileDamage(AActor* inflictor, AActor* target) +{ + // Do poisoning (if using new style poison) + if (inflictor->PoisonDamage > 0 && inflictor->PoisonDuration != INT_MIN) + { + P_PoisonMobj(target, inflictor, inflictor->target, inflictor->PoisonDamage, inflictor->PoisonDuration, inflictor->PoisonPeriod, inflictor->PoisonDamageType); + } + + // Do damage + int damage = inflictor->GetMissileDamage((inflictor->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1); + if ((damage > 0) || (inflictor->flags6 & MF6_FORCEPAIN) || (inflictor->flags7 & MF7_CAUSEPAIN)) + { + int newdam = P_DamageMobj(target, inflictor, inflictor->target, damage, inflictor->DamageType); + if (damage > 0) + { + if ((inflictor->flags5 & MF5_BLOODSPLATTER) && + !(target->flags & MF_NOBLOOD) && + !(target->flags2 & MF2_REFLECTIVE) && + !(target->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)) && + !(inflictor->flags3 & MF3_BLOODLESSIMPACT) && + (pr_checkthing() < 192)) + { + P_BloodSplatter(inflictor->Pos(), target, inflictor->AngleTo(target)); + } + if (!(inflictor->flags3 & MF3_BLOODLESSIMPACT)) + { + P_TraceBleed(newdam > 0 ? newdam : damage, target, inflictor); + } + } + } + else + { + P_GiveBody(target, -damage); + } +} +DEFINE_ACTION_FUNCTION(AActor, DoMissileDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); + P_DoMissileDamage(self, target); + return 0; +} //========================================================================== // // PIT_CheckThing @@ -1247,6 +1394,12 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch if (thing == tm.thing) return true; + if ((thing->flags2 | tm.thing->flags2) & MF2_THRUACTORS) + return true; + + if ((thing->ThruBits & tm.thing->ThruBits) && ((thing->flags8 | tm.thing->flags8) & MF8_ALLOWTHRUBITS)) + return true; + if (!((thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)) || thing->flags6 & MF6_TOUCHY)) return true; // can't hit thing @@ -1254,10 +1407,10 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch if (fabs(thing->X() - cres.Position.X) >= blockdist || fabs(thing->Y() - cres.Position.Y) >= blockdist) return true; - if ((thing->flags2 | tm.thing->flags2) & MF2_THRUACTORS) + if ((tm.thing->flags6 & MF6_THRUSPECIES) && (tm.thing->GetSpecies() == thing->GetSpecies())) return true; - if ((tm.thing->flags6 & MF6_THRUSPECIES) && (tm.thing->GetSpecies() == thing->GetSpecies())) + if (tm.thing->player && P_ShouldPassThroughPlayer(tm.thing, thing)) return true; tm.thing->BlockingMobj = thing; @@ -1447,6 +1600,12 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch return true; } + if (tm.thing->target && tm.thing->target != thing && + tm.thing->target->player && P_ShouldPassThroughPlayer(tm.thing->target, thing)) + { + return true; + } + double clipheight; if (thing->projectilepassheight > 0) @@ -1477,7 +1636,8 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // MBF bouncer might have a non-0 damage value, but they must not deal damage on impact either. if ((tm.thing->BounceFlags & BOUNCE_Actors) && (tm.thing->IsZeroDamage() || !(tm.thing->flags & MF_MISSILE))) { - return ((tm.thing->target == thing && !(tm.thing->flags8 & MF8_HITOWNER)) || !(thing->flags & MF_SOLID)); + return (((tm.thing->target == thing && !(tm.thing->flags8 & MF8_HITOWNER)) || !(thing->flags & MF_SOLID)) && + (tm.thing->SpecialMissileHit(thing) != 0)); } switch (tm.thing->SpecialMissileHit(thing)) @@ -1526,7 +1686,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch { // Ok to spawn blood P_RipperBlood(tm.thing, thing); } - S_Sound(tm.thing, CHAN_BODY, 0, "misc/ripslop", 1, ATTN_IDLE); + S_Sound(tm.thing, CHAN_BODY, 0, tm.thing->SoundVar(NAME_RipSound), 1, ATTN_IDLE); // Do poisoning (if using new style poison) if (tm.thing->PoisonDamage > 0 && tm.thing->PoisonDuration != INT_MIN) @@ -1555,38 +1715,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch } } - // Do poisoning (if using new style poison) - if (tm.thing->PoisonDamage > 0 && tm.thing->PoisonDuration != INT_MIN) - { - P_PoisonMobj(thing, tm.thing, tm.thing->target, tm.thing->PoisonDamage, tm.thing->PoisonDuration, tm.thing->PoisonPeriod, tm.thing->PoisonDamageType); - } - - // Do damage - damage = tm.thing->GetMissileDamage((tm.thing->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1); - if ((damage > 0) || (tm.thing->flags6 & MF6_FORCEPAIN) || (tm.thing->flags7 & MF7_CAUSEPAIN)) - { - int newdam = P_DamageMobj(thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); - if (damage > 0) - { - if ((tm.thing->flags5 & MF5_BLOODSPLATTER) && - !(thing->flags & MF_NOBLOOD) && - !(thing->flags2 & MF2_REFLECTIVE) && - !(thing->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)) && - !(tm.thing->flags3 & MF3_BLOODLESSIMPACT) && - (pr_checkthing() < 192)) - { - P_BloodSplatter(tm.thing->Pos(), thing, tm.thing->AngleTo(thing)); - } - if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) - { - P_TraceBleed(newdam > 0 ? newdam : damage, thing, tm.thing); - } - } - } - else - { - P_GiveBody(thing, -damage); - } + P_DoMissileDamage(tm.thing, thing); if ((thing->flags7 & MF7_THRUREFLECT) && (thing->flags2 & MF2_REFLECTIVE) && (tm.thing->flags & MF_MISSILE)) { @@ -1603,6 +1732,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch { // Push thing if (thing->lastpush != tm.PushTime) { + thing->PlayPushSound(); thing->Vel += tm.thing->Vel.XY() * thing->pushfactor; thing->lastpush = tm.PushTime; } @@ -1767,6 +1897,7 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, boo FMultiBlockThingsIterator it2(pcheck, thing->Level, pos.X, pos.Y, thing->Z(), thing->Height, thing->radius, false, newsec); FMultiBlockThingsIterator::CheckResult tcres; + if (!(thing->flags2 & MF2_THRUACTORS)) while ((it2.Next(&tcres))) { if (!PIT_CheckThing(it2, tcres, it2.Box(), tm)) @@ -1906,7 +2037,7 @@ int P_TestMobjLocation(AActor *mobj) flags = mobj->flags; mobj->flags &= ~MF_PICKUP; - if (P_CheckPosition(mobj, mobj->Pos())) + if (P_CheckPosition(mobj, mobj->Pos().XY())) { // XY is ok, now check Z mobj->flags = flags; if ((mobj->Z() < mobj->floorz) || (mobj->Top() > mobj->ceilingz)) @@ -1935,8 +2066,15 @@ AActor *P_CheckOnmobj(AActor *thing) oldz = thing->Z(); P_FakeZMovement(thing); good = P_TestMobjZ(thing, false, &onmobj); - thing->SetZ(oldz); + // Make sure we don't double call a collision with it. + if (!good && onmobj != nullptr && onmobj != thing->BlockingMobj + && (thing->player == nullptr || !(thing->player->cheats & CF_PREDICTING))) + { + P_CollidedWith(thing, onmobj); + } + + thing->SetZ(oldz); return good ? NULL : onmobj; } @@ -1950,7 +2088,7 @@ int P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) { AActor *onmobj = nullptr; if (pOnmobj) *pOnmobj = nullptr; - if (actor->flags & MF_NOCLIP) + if ((actor->flags & MF_NOCLIP) || (actor->flags2 & MF2_THRUACTORS)) { return true; } @@ -1968,7 +2106,11 @@ int P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) { continue; } - if ((actor->flags2 | thing->flags2) & MF2_THRUACTORS) + if (thing->flags2 & MF2_THRUACTORS) + { + continue; + } + if ((actor->ThruBits & thing->ThruBits) && ((actor->flags8 | thing->flags8) & MF8_ALLOWTHRUBITS)) { continue; } @@ -2017,7 +2159,10 @@ int P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) { // If they cannot collide, they cannot block each other. continue; } - + if (actor->player && P_ShouldPassThroughPlayer(actor, thing)) + { + continue; + } onmobj = thing; if (quick) break; @@ -2055,7 +2200,7 @@ void P_FakeZMovement(AActor *mo) } if (mo->player && mo->flags&MF_NOGRAVITY && (mo->Z() > mo->floorz) && !mo->IsNoClip2()) { - mo->AddZ(DAngle(4.5 * mo->Level->maptime).Sin()); + mo->AddZ(DAngle::fromDeg(4.5 * mo->Level->maptime).Sin()); } // @@ -2171,6 +2316,11 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, if (!P_CheckPosition(thing, pos, tm)) { AActor *BlockingMobj = thing->BlockingMobj; + // This gets called regardless of whether or not the following checks allow the thing to pass. This is because a player + // could step on top of an enemy but we still want it to register as a collision. + if (BlockingMobj != nullptr && (thing->player == nullptr || !(thing->player->cheats & CF_PREDICTING))) + P_CollidedWith(thing, BlockingMobj); + // Solid wall or thing if (!BlockingMobj || BlockingMobj->player || !thing->player) { @@ -2310,7 +2460,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, // This is so that it does not walk off of things onto a drop off. if (thing->flags2 & MF2_ONMOBJ) { - floorz = MAX(thing->Z(), tm.floorz); + floorz = max(thing->Z(), tm.floorz); } if (floorz - tm.dropoffz > thing->MaxDropOffHeight && @@ -2393,8 +2543,8 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, while (true) { double bestfrac = 1.1; - spechit_t besthit; - int besthitnum; + spechit_t besthit{}; + int besthitnum = -1; // find the portal nearest to the crossing actor for (unsigned i = 0; i < portalhit.Size();i++) { @@ -2429,25 +2579,29 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, { FLinkContext ctx; thing->UnlinkFromWorld(&ctx); - thing->SetXY(tm.pos + port->mDisplacement); + thing->SetXY(tm.pos.XY() + port->mDisplacement); thing->Prev += port->mDisplacement; thing->LinkToWorld(&ctx); P_FindFloorCeiling(thing); portalcrossed = true; tm.portalstep = false; + tm.pos += port->mDisplacement; } else if (!portalcrossed) { - DVector3 pos(tm.pos, thing->Z()); + DVector3 pos(tm.pos.XY(), thing->Z()); DVector3 oldthingpos = thing->Pos(); - DVector2 thingpos = oldthingpos; + DVector2 thingpos = oldthingpos.XY(); P_TranslatePortalXY(ld, pos.X, pos.Y); P_TranslatePortalXY(ld, thingpos.X, thingpos.Y); P_TranslatePortalZ(ld, pos.Z); thing->SetXYZ(thingpos.X, thingpos.Y, pos.Z); - if (!P_CheckPosition(thing, pos, true)) // check if some actor blocks us on the other side. (No line checks, because of the mess that'd create.) + if (!P_CheckPosition(thing, pos.XY(), true)) // check if some actor blocks us on the other side. (No line checks, because of the mess that'd create.) { + if (thing->BlockingMobj != nullptr && (thing->player == nullptr || !(thing->player->cheats && CF_PREDICTING))) + P_CollidedWith(thing, thing->BlockingMobj); + thing->SetXYZ(oldthingpos); thing->flags6 &= ~MF6_INTRYMOVE; return false; @@ -2468,7 +2622,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, if (thing->Level->isCamera(thing)) { divline_t dl1 = { besthit.Oldrefpos.X,besthit.Oldrefpos.Y, besthit.Refpos.X - besthit.Oldrefpos.X, besthit.Refpos.Y - besthit.Oldrefpos.Y }; - DVector3a hit = { {dl1.x + dl1.dx * bestfrac, dl1.y + dl1.dy * bestfrac, 0.},0. }; + DVector3a hit = { {dl1.x + dl1.dx * bestfrac, dl1.y + dl1.dy * bestfrac, 0.},nullAngle }; R_AddInterpolationPoint(hit); if (port->mType == PORTT_LINKED) @@ -2483,13 +2637,15 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, auto p = thing->Level->GetConsolePlayer(); if (p) p->viewz += hit.pos.Z; // needs to be done here because otherwise the renderer will not catch the change. P_TranslatePortalAngle(ld, hit.angle); + if (thing->player && (port->mType == PORTT_INTERACTIVE || port->mType == PORTT_TELEPORT)) + thing->player->crossingPortal = true; } R_AddInterpolationPoint(hit); } if (port->mType == PORTT_LINKED) { continue; - } + } } break; } @@ -2525,7 +2681,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP))) { spechit_t spec; - DVector2 lastpos = thing->Pos(); + DVector2 lastpos = thing->Pos().XY(); while (spechit.Pop(spec)) { line_t *ld = spec.line; @@ -2625,6 +2781,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, pushline: thing->flags6 &= ~MF6_INTRYMOVE; + thing->SetZ(oldz); // [RH] Don't activate anything if just predicting if (thing->player && (thing->player->cheats & CF_PREDICTING)) @@ -2632,7 +2789,6 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, return false; } - thing->SetZ(oldz); if (!(thing->flags&(MF_TELEPORT | MF_NOCLIP))) { int numSpecHitTemp; @@ -2869,21 +3025,21 @@ void FSlide::HitSlideLine(line_t* ld) // less than 45 degrees. // phares DVector3 pos = slidemo->PosRelative(ld); - side = P_PointOnLineSide(pos, ld); + side = P_PointOnLineSide(pos.XY(), ld); lineangle = ld->Delta().Angle(); if (side == 1) - lineangle += 180.; + lineangle += DAngle::fromDeg(180.); moveangle = tmmove.Angle(); // prevents sudden path reversal due to rounding error | // phares - moveangle += 3600/65536.*65536.; // Boom added 10 to the angle here. + moveangle += DAngle::fromDeg(3600/65536.*65536.); // Boom added 10 to the angle here. deltaangle = ::deltaangle(lineangle, moveangle); // V movelen = tmmove.Length(); - if (icyfloor && (deltaangle > 45) && (deltaangle < 135)) + if (icyfloor && (deltaangle > DAngle::fromDeg(45)) && (deltaangle < DAngle::fromDeg(135))) { moveangle = ::deltaangle(deltaangle, lineangle); movelen /= 2; // absorb @@ -2962,26 +3118,14 @@ void FSlide::SlideTraverse(const DVector2 &start, const DVector2 &end) if (!(li->flags & ML_TWOSIDED) || !li->backsector) { DVector3 pos = slidemo->PosRelative(li); - if (P_PointOnLineSide(pos, li)) + if (P_PointOnLineSide(pos.XY(), li)) { // don't hit the back side continue; } goto isblocking; } - if (li->flags & (ML_BLOCKING | ML_BLOCKEVERYTHING)) - { - goto isblocking; - } - if (li->flags & ML_BLOCK_PLAYERS && ((slidemo->player != NULL) || (slidemo->flags8 & MF8_BLOCKASPLAYER))) - { - goto isblocking; - } - if (li->flags & ML_BLOCKMONSTERS && !((slidemo->flags3 & MF3_NOBLOCKMONST) - || ((slidemo->Level->i_compatflags & COMPATF_NOBLOCKFRIENDS) && (slidemo->flags & MF_FRIENDLY)))) - { - goto isblocking; - } + if (P_IsBlockedByLine(slidemo, li)) goto isblocking; // set openrange, opentop, openbottom P_LineOpening(open, slidemo, li, it.InterceptPoint(in)); @@ -3096,11 +3240,11 @@ void FSlide::SlideMove(AActor *mo, DVector2 tryp, int numsteps) // killough 3/15/98: Allow objects to drop off ledges move = { 0, tryp.Y }; walkplane = P_CheckSlopeWalk(mo, move); - if (!P_TryMove(mo, mo->Pos() + move, true, walkplane)) + if (!P_TryMove(mo, mo->Pos().XY() + move, true, walkplane)) { move = { tryp.X, 0 }; walkplane = P_CheckSlopeWalk(mo, move); - P_TryMove(mo, mo->Pos() + move, true, walkplane); + P_TryMove(mo, mo->Pos().XY() + move, true, walkplane); } return; } @@ -3115,7 +3259,7 @@ void FSlide::SlideMove(AActor *mo, DVector2 tryp, int numsteps) const DVector2 startvel = mo->Vel.XY(); // killough 3/15/98: Allow objects to drop off ledges - if (!P_TryMove(mo, mo->Pos() + newpos, true)) + if (!P_TryMove(mo, mo->Pos().XY() + newpos, true)) goto stairstep; if (mo->Vel.XY() != startvel) @@ -3148,7 +3292,7 @@ void FSlide::SlideMove(AActor *mo, DVector2 tryp, int numsteps) walkplane = P_CheckSlopeWalk(mo, tmmove); // killough 3/15/98: Allow objects to drop off ledges - if (!P_TryMove(mo, mo->Pos() + tmmove, true, walkplane)) + if (!P_TryMove(mo, mo->Pos().XY() + tmmove, true, walkplane)) { goto retry; } @@ -3228,12 +3372,12 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, DVector2 &move) DVector2 dest; double t; - dest = actor->Pos() + move; + dest = actor->Pos().XY() + move; t = (plane->Normal() | DVector3(dest, actor->Z())) + plane->fD(); if (t < 0) { // Desired location is behind (below) the plane // (i.e. Walking up the plane) - if (plane->fC() < STEEPSLOPE) + if (plane->fC() < actor->MaxSlopeSteepness) { // Can't climb up slopes of ~45 degrees or more if (actor->flags & MF_NOCLIP) { @@ -3244,12 +3388,12 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, DVector2 &move) const msecnode_t *node; bool dopush = true; - if (plane->fC() > STEEPSLOPE * 2 / 3) + if (plane->fC() > actor->MaxSlopeSteepness * 2 / 3) { for (node = actor->touching_sectorlist; node; node = node->m_tnext) { sector_t *sec = node->m_sector; - if (sec->floorplane.fC() >= STEEPSLOPE) + if (sec->floorplane.fC() >= actor->MaxSlopeSteepness) { DVector3 pos = actor->PosRelative(sec) +move; @@ -3263,7 +3407,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, DVector2 &move) } if (dopush) { - move = plane->Normal() * 2; + move = plane->Normal().XY() * 2; actor->Vel.X = move.X; actor->Vel.Y = move.Y; } @@ -3272,7 +3416,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, DVector2 &move) } // Slide the desired location along the plane's normal // so that it lies on the plane's surface - dest -= plane->Normal() * t; + dest -= plane->Normal().XY() * t; move = dest - actor->Pos().XY(); return (actor->floorsector == actor->Sector) ? plane : NULL; } @@ -3282,7 +3426,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, DVector2 &move) { // Actor's current spot is on/in the plane, so walk down it // Same principle as walking up, except reversed - dest += plane->Normal() * t; + dest += plane->Normal().XY() * t; move = dest - actor->Pos().XY(); return (actor->floorsector == actor->Sector) ? plane : NULL; } @@ -3321,7 +3465,7 @@ bool FSlide::BounceTraverse(const DVector2 &start, const DVector2 &end) } if (!(li->flags&ML_TWOSIDED) || !li->backsector) { - if (P_PointOnLineSide(slidemo->Pos(), li)) + if (P_PointOnLineSide(slidemo->Pos().XY(), li)) continue; // don't hit the back side goto bounceblocking; } @@ -3411,9 +3555,19 @@ bool FSlide::BounceWall(AActor *mo) } line = bestslideline; + if (mo->flags & MF_MISSILE) + { + switch (mo->SpecialBounceHit(nullptr, line, nullptr)) + { + case 1: return true; + case 0: return false; + default: break; + } + } + if (line->special == Line_Horizon || ((mo->BounceFlags & BOUNCE_NotOnSky) && line->hitSkyWall(mo))) { - mo->SeeSound = mo->BounceSound = 0; // it might make a sound otherwise + mo->SeeSound = mo->BounceSound = NO_SOUND; // it might make a sound otherwise mo->Destroy(); return true; } @@ -3440,20 +3594,20 @@ bool FSlide::BounceWall(AActor *mo) return true; } - side = P_PointOnLineSide(mo->Pos(), line); + side = P_PointOnLineSide(mo->Pos().XY(), line); lineangle = line->Delta().Angle(); if (side == 1) { - lineangle += 180; + lineangle += DAngle::fromDeg(180); } moveangle = mo->Vel.Angle(); deltaangle = (lineangle * 2) - moveangle; mo->Angles.Yaw = deltaangle; - movelen = mo->Vel.XY().Length() * mo->wallbouncefactor; + movelen = mo->Vel.XY().Length() * GetWallBounceFactor(mo); FBoundingBox box(mo->X(), mo->Y(), mo->radius); - if (box.BoxOnLineSide(line) == -1) + if (BoxOnLineSide(box, line) == -1) { DVector2 ofs = deltaangle.ToVector(mo->radius); DVector3 pos = mo->Vec3Offset(ofs.X, ofs.Y, 0.); @@ -3493,8 +3647,25 @@ bool P_BounceWall(AActor *mo) extern FRandom pr_bounce; bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) { + if (mo && (mo->flags & MF_MISSILE) && BlockingMobj) + { + switch (mo->SpecialMissileHit(BlockingMobj)) + { + case 1: return true; + case 0: return false; + default: break; + } + + switch (mo->SpecialBounceHit(BlockingMobj, nullptr, nullptr)) + { + case 1: return true; + case 0: return false; + default: break; + } + } + //Don't go through all of this if the actor is reflective and wants things to pass through them. - if (BlockingMobj && ((BlockingMobj->flags2 & MF2_REFLECTIVE) && (BlockingMobj->flags7 & MF7_THRUREFLECT))) return true; + if (BlockingMobj && ((BlockingMobj->flags2 & MF2_REFLECTIVE) && (BlockingMobj->flags7 & MF7_THRUREFLECT))) return true; if (mo && BlockingMobj && ((mo->BounceFlags & BOUNCE_AllActors) || ((mo->flags & MF_MISSILE) && (!(mo->flags2 & MF2_RIP) || (BlockingMobj->flags5 & MF5_DONTRIP) @@ -3526,8 +3697,8 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) if (!ontop) { - DAngle angle = BlockingMobj->AngleTo(mo) + ((pr_bounce() % 16) - 8); - double speed = mo->VelXYToSpeed() * mo->wallbouncefactor; // [GZ] was 0.75, using wallbouncefactor seems more consistent + DAngle angle = BlockingMobj->AngleTo(mo) + DAngle::fromDeg((pr_bounce() % 16) - 8); + double speed = mo->VelXYToSpeed() * GetWallBounceFactor(mo); // [GZ] was 0.75, using wallbouncefactor seems more consistent if (fabs(speed) < EQUAL_EPSILON) speed = 0; mo->Angles.Yaw = angle; mo->VelFromAngle(speed); @@ -3549,7 +3720,7 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) } else { - mo->Vel.Z *= mo->bouncefactor; + mo->Vel.Z *= GetMBFBounceFactor(mo); } } else // Don't run through this for MBF-style bounces @@ -3590,6 +3761,48 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) return false; } +bool P_ReflectOffActor(AActor* mo, AActor* blocking) +{ + if (!(blocking->flags2 & MF2_REFLECTIVE)) + return false; + + // Don't change the angle if there's THRUREFLECT on the monster. + if (!(blocking->flags7 & MF7_THRUREFLECT)) + { + DAngle angle = blocking->AngleTo(mo); + if (mo->AdjustReflectionAngle(blocking, angle)) + return false; + + // Change angle for deflection/reflection + auto target = mo->target != NULL ? mo->target : blocking->target; + if (target && (blocking->flags7 & MF7_AIMREFLECT)) + { + //dest->x - source->x + DVector3 vect = mo->Vec3To(target); + vect.Z += target->Height * 0.5; + mo->Vel = vect.Resized(mo->Speed); + } + else if (blocking->flags7 & MF7_MIRRORREFLECT) + { + mo->Angles.Yaw += DAngle::fromDeg(180.0); + mo->Vel *= -0.5; + } + else + { + mo->Angles.Yaw = angle; + mo->VelFromAngle(mo->Speed * 0.5); + mo->Vel.Z *= -0.5; + } + } + + if (mo->flags2 & MF2_SEEKERMISSILE) + mo->tracer = mo->target; + + mo->target = blocking; + + return true; +} + //============================================================================ // // Aiming @@ -3871,7 +4084,7 @@ struct aim_t newtrace.startfrac = frac + 1 / attackrange; // this is to skip the transition line to the portal which would produce a bogus opening - DVector2 pos = newtrace.startpos + newtrace.aimtrace * newtrace.startfrac; + DVector2 pos = newtrace.startpos.XY() + newtrace.aimtrace * newtrace.startfrac; newtrace.lastsector = li->GetLevel()->PointInSector(pos); P_TranslatePortalZ(li, limitz); @@ -3965,8 +4178,8 @@ struct aim_t lastfloorplane = lastceilingplane = NULL; // check the initial sector for 3D-floors and portals - bool ceilingportalstate = (aimdir & aim_t::aim_up) && toppitch < 0 && !lastsector->PortalBlocksMovement(sector_t::ceiling); - bool floorportalstate = (aimdir & aim_t::aim_down) && bottompitch > 0 && !lastsector->PortalBlocksMovement(sector_t::floor); + bool ceilingportalstate = (aimdir & aim_t::aim_up) && toppitch < nullAngle && !lastsector->PortalBlocksMovement(sector_t::ceiling); + bool floorportalstate = (aimdir & aim_t::aim_down) && bottompitch > nullAngle && !lastsector->PortalBlocksMovement(sector_t::floor); for (auto rover : lastsector->e->XFloor.ffloors) { @@ -3989,8 +4202,8 @@ struct aim_t floorportalstate = false; } } - if (ceilingportalstate) EnterSectorPortal(sector_t::ceiling, 0, lastsector, toppitch, MIN(0., bottompitch)); - if (floorportalstate) EnterSectorPortal(sector_t::floor, 0, lastsector, MAX(0., toppitch), bottompitch); + if (ceilingportalstate) EnterSectorPortal(sector_t::ceiling, 0, lastsector, toppitch, min(nullAngle, bottompitch)); + if (floorportalstate) EnterSectorPortal(sector_t::floor, 0, lastsector, max(nullAngle, toppitch), bottompitch); FPathTraverse it(lastsector->Level, startpos.X, startpos.Y, aimtrace.X, aimtrace.Y, PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE | PT_DELTA, startfrac); intercept_t *in; @@ -4016,7 +4229,7 @@ struct aim_t int frontflag = P_PointOnLineSidePrecise(startpos, li); if (aimdebug) - Printf("Found line %d: toppitch = %f, bottompitch = %f\n", li->Index(), toppitch.Degrees, bottompitch.Degrees); + Printf("Found line %d: toppitch = %f, bottompitch = %f\n", li->Index(), toppitch.Degrees(), bottompitch.Degrees()); if (li->isLinePortal() && frontflag == 0) { @@ -4060,19 +4273,19 @@ struct aim_t return; if (aimdebug) - Printf("After line %d: toppitch = %f, bottompitch = %f, planestocheck = %d\n", li->Index(), toppitch.Degrees, bottompitch.Degrees, planestocheck); + Printf("After line %d: toppitch = %f, bottompitch = %f, planestocheck = %d\n", li->Index(), toppitch.Degrees(), bottompitch.Degrees(), planestocheck); sector_t *entersec = frontflag ? li->frontsector : li->backsector; sector_t *exitsec = frontflag ? li->backsector : li->frontsector; lastsector = entersec; // check portal in backsector when aiming up/downward is possible, the line doesn't have portals on both sides and there's actually a portal in the backsector - if ((planestocheck & aim_up) && toppitch < 0 && open.top != LINEOPEN_MAX && !entersec->PortalBlocksMovement(sector_t::ceiling)) + if ((planestocheck & aim_up) && toppitch < nullAngle && open.top != LINEOPEN_MAX && !entersec->PortalBlocksMovement(sector_t::ceiling)) { - EnterSectorPortal(sector_t::ceiling, in->frac, entersec, toppitch, MIN(0., bottompitch)); + EnterSectorPortal(sector_t::ceiling, in->frac, entersec, toppitch, min(nullAngle, bottompitch)); } - if ((planestocheck & aim_down) && bottompitch > 0 && open.bottom != LINEOPEN_MIN && !entersec->PortalBlocksMovement(sector_t::floor)) + if ((planestocheck & aim_down) && bottompitch > nullAngle && open.bottom != LINEOPEN_MIN && !entersec->PortalBlocksMovement(sector_t::floor)) { - EnterSectorPortal(sector_t::floor, in->frac, entersec, MAX(0., toppitch), bottompitch); + EnterSectorPortal(sector_t::floor, in->frac, entersec, max(nullAngle, toppitch), bottompitch); } continue; // shot continues } @@ -4085,6 +4298,9 @@ struct aim_t if (aimtarget != NULL && th != aimtarget) continue; // only care about target, and you're not it + if (shootthing->player && P_ShouldPassThroughPlayer(shootthing, th)) + continue; + // If we want to start a conversation anything that has one should be // found, regardless of other settings. if (!(flags & ALF_CHECKCONVERSATION) || th->Conversation == NULL) @@ -4107,7 +4323,7 @@ struct aim_t dist = attackrange * in->frac; // Don't autoaim certain special actors - if (!cl_doautoaim && th->flags6 & MF6_NOTAUTOAIMED) + if (!cl_doautoaim && !(flags & ALF_IGNORENOAUTOAIM) && th->flags6 & MF6_NOTAUTOAIMED) { continue; } @@ -4282,11 +4498,11 @@ DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLin double shootz = t1->Center() - t1->Floorclip + t1->AttackOffset(); // can't shoot outside view angles - if (vrange == 0) + if (vrange == nullAngle) { if (t1->player == NULL || !t1->Level->IsFreelookAllowed()) { - vrange = 35.; + vrange = DAngle::fromDeg(35.); } else { @@ -4294,7 +4510,7 @@ DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLin auto weapon = t1->player->ReadyWeapon; if ((weapon && (weapon->IntVar(NAME_WeaponFlags) & WIF_NOAUTOAIM)) && !(flags & ALF_NOWEAPONCHECK)) { - vrange = 0.5; + vrange = DAngle::fromDeg(0.5); } else { @@ -4302,7 +4518,7 @@ DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLin // vrange of 0 degrees, because then toppitch and bottompitch will // be equal, and PTR_AimTraverse will never find anything to shoot at // if it crosses a line. - vrange = clamp(t1->player->userinfo.GetAimDist(), 0.5, 35.); + vrange = DAngle::fromDeg(clamp(t1->player->userinfo.GetAimDist(), 0.5, 35.)); } } } @@ -4333,6 +4549,11 @@ DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLin { *pLineTarget = *result; } + + DAngle newPitch = P_AimLineAttack_ShadowHandling(t1,target,result->linetarget,shootz); + if (newPitch != nullAngle) + result->pitch = newPitch; + return result->linetarget ? result->pitch : t1->Angles.Pitch; } @@ -4350,6 +4571,9 @@ struct Origin bool MThruSpecies; bool ThruSpecies; bool ThruActors; + bool UseThruBits; + bool Spectral; + uint32_t ThruBits; }; static ETraceStatus CheckForActor(FTraceResults &res, void *userdata) @@ -4362,15 +4586,21 @@ static ETraceStatus CheckForActor(FTraceResults &res, void *userdata) Origin *data = (Origin *)userdata; // Skip actors if the puff has: - // 1. THRUACTORS or SPECTRAL - // 2. MTHRUSPECIES on puff and the shooter has same species as the hit actor - // 3. THRUSPECIES on puff and the puff has same species as the hit actor - // 4. THRUGHOST on puff and the GHOST flag on the hit actor - - if ((data->ThruActors) || (res.Actor->flags4 & MF4_SPECTRAL) || + // 1. THRUACTORS + // 2. SPECTRAL (unless the puff has SPECTRAL) + // 3. MTHRUSPECIES on puff and the shooter has same species as the hit actor + // 4. THRUSPECIES on puff and the puff has same species as the hit actor + // 5. THRUGHOST on puff and the GHOST flag on the hit actor + // 6. Matching ThruBits + // 7. A player caller with no player clip enabled + + if ((data->ThruActors) || + (!(data->Spectral) && res.Actor->flags4 & MF4_SPECTRAL) || (data->MThruSpecies && res.Actor->GetSpecies() == data->Caller->GetSpecies()) || (data->ThruSpecies && res.Actor->GetSpecies() == data->PuffSpecies) || - (data->hitGhosts && res.Actor->flags3 & MF3_GHOST)) + (data->hitGhosts && res.Actor->flags3 & MF3_GHOST) || + (data->UseThruBits && (data->ThruBits & res.Actor->ThruBits)) || + (data->Caller->player && P_ShouldPassThroughPlayer(data->Caller, res.Actor))) { return TRACE_Skip; } @@ -4442,6 +4672,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, spawnSky = (puffDefaults && (puffDefaults->flags3 & MF3_SKYEXPLODE)); TData.MThruSpecies = (puffDefaults && (puffDefaults->flags6 & MF6_MTHRUSPECIES)); TData.PuffSpecies = NAME_None; + TData.Spectral = (puffDefaults && (puffDefaults->flags4 & MF4_SPECTRAL)); // [MC] To prevent possible mod breakage, this flag is pretty much necessary. // Somewhere, someone is relying on these to spawn on actors and move through them. @@ -4450,7 +4681,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, { TData.ThruSpecies = (puffDefaults && (puffDefaults->flags6 & MF6_THRUSPECIES)); TData.ThruActors = (puffDefaults && (puffDefaults->flags2 & MF2_THRUACTORS)); - + // [MC] Because this is a one-hit trace event, we need to spawn the puff, get the species // and destroy it. Assume there is no species unless tempuff isn't NULL. We cannot get // a proper species the same way as puffDefaults flags it appears... @@ -4461,6 +4692,8 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, if (tempuff != NULL) { TData.PuffSpecies = tempuff->GetSpecies(); + TData.UseThruBits = tempuff->flags8 & MF8_ALLOWTHRUBITS; + TData.ThruBits = tempuff->ThruBits; tempuff->Destroy(); } } @@ -4468,6 +4701,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, { TData.ThruSpecies = false; TData.ThruActors = false; + TData.UseThruBits = false; } // if the puff uses a non-standard damage type, this will override default, hitscan and melee damage type. // All other explicitly passed damage types (currenty only MDK) will be preserved. @@ -4515,7 +4749,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, if (!Trace(tempos, t1->Sector, direction, distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING | ML_BLOCKHITSCAN, t1, trace, tflags, CheckForActor, &TData)) { // hit nothing - if (!nointeract && puffDefaults && puffDefaults->ActiveSound) + if (!nointeract && puffDefaults && puffDefaults->ActiveSound.isvalid()) { // Play miss sound S_Sound(t1, CHAN_WEAPON, 0, puffDefaults->ActiveSound, 1, ATTN_NORM); } @@ -4549,14 +4783,14 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, } P_GeometryLineAttack(trace, t1, damage, damageType); - + if (victim != NULL) victim->unlinked = trace.unlinked; // position a bit closer for puffs if (nointeract || trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky)) { DVector2 pos = t1->Level->GetPortalOffsetPosition(trace.HitPos.X, trace.HitPos.Y, -trace.HitVector.X * 4, -trace.HitVector.Y * 4); puff = P_SpawnPuff(t1, pufftype, DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4), trace.SrcAngleFromTarget, - trace.SrcAngleFromTarget - 90, 0, puffFlags); + trace.SrcAngleFromTarget - DAngle::fromDeg(90), 0, puffFlags); puff->radius = 1/65536.; if (nointeract) @@ -4620,7 +4854,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, puffFlags |= PF_HITTHINGBLEED; // We must pass the unreplaced puff type here - puff = P_SpawnPuff(t1, pufftype, bleedpos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 2, puffFlags | PF_HITTHING, trace.Actor); + puff = P_SpawnPuff(t1, pufftype, bleedpos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - DAngle::fromDeg(90), 2, puffFlags | PF_HITTHING, trace.Actor); } if (victim != NULL) { @@ -4658,7 +4892,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, { // Since the puff is the damage inflictor we need it here // regardless of whether it is displayed or not. - puff = P_SpawnPuff(t1, pufftype, bleedpos, 0., 0., 2, puffFlags | PF_HITTHING | PF_TEMPORARY); + puff = P_SpawnPuff(t1, pufftype, bleedpos, nullAngle, nullAngle, 2, puffFlags | PF_HITTHING | PF_TEMPORARY); killPuff = true; } auto src = t1; @@ -4673,7 +4907,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, { IFVIRTUALPTR(trace.Actor, AActor, SpawnLineAttackBlood) { - VMValue params[] = { trace.Actor, t1, bleedpos.X, bleedpos.Y, bleedpos.Z, trace.SrcAngleFromTarget.Degrees, damage, newdam }; + VMValue params[] = { trace.Actor, t1, bleedpos.X, bleedpos.Y, bleedpos.Z, trace.SrcAngleFromTarget.Degrees(), damage, newdam }; VMCall(func, params, countof(params), nullptr, 0); } if (damage) @@ -4688,7 +4922,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, { if (puff == NULL) { // Spawn puff just to get a mass for the splash - puff = P_SpawnPuff(t1, pufftype, trace.HitPos, 0., 0., 2, puffFlags | PF_HITTHING | PF_TEMPORARY); + puff = P_SpawnPuff(t1, pufftype, trace.HitPos, nullAngle, nullAngle, 2, puffFlags | PF_HITTHING | PF_TEMPORARY); killPuff = true; } SpawnDeepSplash(t1, trace, puff); @@ -4709,10 +4943,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, PClassActor *type = PClass::FindActor(pufftype); if (type == NULL) { - if (victim != NULL) - { - memset(victim, 0, sizeof(*victim)); - } + if (victim != NULL) *victim = {}; Printf("Attempt to spawn unknown actor type '%s'\n", pufftype.GetChars()); return NULL; } @@ -4837,6 +5068,7 @@ int P_LineTrace(AActor *t1, DAngle angle, double distance, outdata->HitTexture = trace.Line->sidedef[trace.Side]->textures[2].texture; break; case TIER_FFloor: + outdata->LinePart = 1; // act as if middle was hit txpart = (trace.ffloor->flags & FF_UPPERTEXTURE) ? 0 : (trace.ffloor->flags & FF_LOWERTEXTURE) ? 2 : 1; outdata->HitTexture = trace.ffloor->master->sidedef[0]->textures[txpart].texture; break; @@ -4846,7 +5078,8 @@ int P_LineTrace(AActor *t1, DAngle angle, double distance, outdata->HitLocation = trace.HitPos; outdata->HitDir = trace.HitVector; outdata->Distance = trace.Distance; - outdata->NumPortals = TData.NumPortals; + // [MK] Subtract two "bogus" portal crossings used internally by trace code + outdata->NumPortals = TData.NumPortals-2; outdata->HitType = trace.HitType; } return ret; @@ -4949,8 +5182,8 @@ void P_TraceBleed(int damage, const DVector3 &pos, AActor *actor, DAngle angle, { FTraceResults bleedtrace; - DAngle bleedang = angle + (pr_tracebleed() - 128) * noise; - DAngle bleedpitch = pitch + (pr_tracebleed() - 128) * noise; + DAngle bleedang = angle + DAngle::fromDeg((pr_tracebleed() - 128) * noise); + DAngle bleedpitch = pitch + DAngle::fromDeg((pr_tracebleed() - 128) * noise); double cosp = bleedpitch.Cos(); DVector3 vdir = DVector3(cosp * bleedang.Cos(), cosp * bleedang.Sin(), -bleedpitch.Sin()); @@ -4967,7 +5200,7 @@ void P_TraceBleed(int damage, const DVector3 &pos, AActor *actor, DAngle angle, bloodcolor.a = 1; } - uint32_t bloodTrans = (bloodcolor != 0 ? actor->BloodTranslation : 0); + auto bloodTrans = (bloodcolor != 0 ? actor->BloodTranslation : NO_TRANSLATION); DImpactDecal::StaticCreate(actor->Level, bloodType, bleedtrace.HitPos, bleedtrace.Line->sidedef[bleedtrace.Side], bleedtrace.ffloor, bloodcolor, bloodTrans); @@ -5002,11 +5235,11 @@ void P_TraceBleed(int damage, AActor *target, AActor *missile) double aim; aim = g_atan(missile->Vel.Z / target->Distance2D(missile)); - pitch = -DAngle::ToDegrees(aim); + pitch = -DAngle::fromRad(aim); } else { - pitch = 0.; + pitch = nullAngle; } P_TraceBleed(damage, target->PosPlusZ(target->Height/2), target, missile->AngleTo(target), pitch); } @@ -5024,7 +5257,7 @@ void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff) return; } - DAngle pitch = (pr_tracebleed() - 128) * (360 / 65536.); + DAngle pitch = DAngle::fromDeg((pr_tracebleed() - 128) * (360 / 65536.)); P_TraceBleed(damage, t->linetarget->PosPlusZ(t->linetarget->Height/2), t->linetarget, t->angleFromSource, pitch); } @@ -5039,8 +5272,8 @@ void P_TraceBleed(int damage, AActor *target) { if (target != NULL) { - DAngle angle = pr_tracebleed() * (360 / 256.); - DAngle pitch = (pr_tracebleed() - 128) * (360 / 65536.); + DAngle angle = DAngle::fromDeg(pr_tracebleed() * (360 / 256.)); + DAngle pitch = DAngle::fromDeg((pr_tracebleed() - 128) * (360 / 65536.)); P_TraceBleed(damage, target->PosPlusZ(target->Height / 2), target, angle, pitch); } } @@ -5069,6 +5302,8 @@ struct RailData bool ThruSpecies; bool MThruSpecies; bool ThruActors; + bool UseThruBits; + uint32_t ThruBits; int limit; int count; }; @@ -5096,11 +5331,14 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata) // 2. MTHRUSPECIES on puff and the shooter has same species as the hit actor // 3. THRUSPECIES on puff and the puff has same species as the hit actor // 4. THRUGHOST on puff and the GHOST flag on the hit actor + // 5. Skip through players in coop if sv_noplayerclip is enabled if ((data->ThruActors) || + (data->UseThruBits && (data->ThruBits & res.Actor->ThruBits)) || (data->MThruSpecies && res.Actor->GetSpecies() == data->Caller->GetSpecies()) || (data->ThruSpecies && res.Actor->GetSpecies() == data->PuffSpecies) || - (data->ThruGhosts && res.Actor->flags3 & MF3_GHOST)) + (data->ThruGhosts && res.Actor->flags3 & MF3_GHOST) || + (data->Caller->player && P_ShouldPassThroughPlayer(data->Caller, res.Actor))) { return TRACE_Skip; } @@ -5167,7 +5405,7 @@ void P_RailAttack(FRailParams *p) puffflags |= PF_NORANDOMZ; } - DVector2 xy = source->Vec2Angle(p->offset_xy, angle - 90.); + DVector2 xy = source->Vec2Angle(p->offset_xy, angle - DAngle::fromDeg(90.)); RailData rail_data; rail_data.Caller = source; @@ -5195,12 +5433,14 @@ void P_RailAttack(FRailParams *p) rail_data.ThruGhosts = !!(puffDefaults->flags2 & MF2_THRUGHOST); rail_data.ThruSpecies = !!(puffDefaults->flags6 & MF6_THRUSPECIES); rail_data.ThruActors = !!(puffDefaults->flags2 & MF2_THRUACTORS); + rail_data.UseThruBits = true; } else { rail_data.ThruGhosts = false; rail_data.MThruSpecies = false; rail_data.ThruActors = false; + rail_data.UseThruBits = false; } // used as damage inflictor AActor *thepuff = NULL; @@ -5208,6 +5448,13 @@ void P_RailAttack(FRailParams *p) if (puffclass != NULL) thepuff = Spawn(source->Level, puffclass, source->Pos(), ALLOW_REPLACE); rail_data.PuffSpecies = (thepuff != NULL) ? thepuff->GetSpecies() : NAME_None; + if (thepuff) + { + rail_data.ThruBits = thepuff->ThruBits; + if (rail_data.UseThruBits) + rail_data.UseThruBits = !!(thepuff->flags8 & MF8_ALLOWTHRUBITS); + } + Trace(start, source->Sector, vec, p->distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data); // Hurt anything the trace hit @@ -5221,6 +5468,7 @@ void P_RailAttack(FRailParams *p) int actorpuffflags = puffflags | PF_HITTHING; AActor *hitactor = rail_data.RailHits[i].HitActor; + AActor *hitpuff = NULL; DVector3 &hitpos = rail_data.RailHits[i].HitPos; DAngle hitangle = rail_data.RailHits[i].HitAngle; @@ -5240,21 +5488,25 @@ void P_RailAttack(FRailParams *p) } if (spawnpuff) { - P_SpawnPuff(source, puffclass, hitpos, hitangle, hitangle - 90, 1, actorpuffflags, hitactor); + hitpuff = P_SpawnPuff(source, puffclass, hitpos, hitangle, hitangle - DAngle::fromDeg(90), 1, actorpuffflags, hitactor); } - + // https://github.com/coelckers/gzdoom/pull/1668#pullrequestreview-1039431156 + if (!hitpuff) { + hitpuff = thepuff; + } + int dmgFlagPass = DMG_INFLICTOR_IS_PUFF; if (puffDefaults != NULL) // is this even possible? { if (puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) { - P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); + P_PoisonMobj(hitactor, hitpuff ? hitpuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); } if (puffDefaults->flags3 & MF3_FOILINVUL) dmgFlagPass |= DMG_FOILINVUL; if (puffDefaults->flags7 & MF7_FOILBUDDHA) dmgFlagPass |= DMG_FOILBUDDHA; } // [RK] If the attack source is a player, send the DMG_PLAYERATTACK flag. - int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, p->damage, damagetype, dmgFlagPass | DMG_USEANGLE | (source->player ? DMG_PLAYERATTACK : 0), hitangle); + int newdam = P_DamageMobj(hitactor, hitpuff ? hitpuff : source, source, p->damage, damagetype, dmgFlagPass | DMG_USEANGLE | (source->player ? DMG_PLAYERATTACK : 0), hitangle); if (bleed) { @@ -5272,7 +5524,7 @@ void P_RailAttack(FRailParams *p) if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { - puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 1, puffflags); + puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - DAngle::fromDeg(90), 1, puffflags); if (puff && (trace.Line != NULL) && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE)) puff->Destroy(); } @@ -5287,7 +5539,7 @@ void P_RailAttack(FRailParams *p) AActor* puff = NULL; if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { - puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 1, puffflags); + puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - DAngle::fromDeg(90), 1, puffflags); if (puff && !(puff->flags3 & MF3_SKYEXPLODE) && (((trace.HitType == TRACE_HitFloor) && (puff->floorpic == skyflatnum)) || ((trace.HitType == TRACE_HitCeiling) && (puff->ceilingpic == skyflatnum)))) @@ -5322,35 +5574,49 @@ void P_RailAttack(FRailParams *p) CVAR(Float, chase_height, -8.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, chase_dist, 90.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -void P_AimCamera(AActor *t1, DVector3 &campos, DAngle &camangle, sector_t *&CameraSector, bool &unlinked) +void R_OffsetView(FRenderViewpoint& viewPoint, const DVector3& dir, const double distance) { - double distance = clamp(chase_dist, 0, 30000); - DAngle angle = t1->Angles.Yaw - 180; - DAngle pitch = t1->Angles.Pitch; - FTraceResults trace; - DVector3 vvec; - double sz; - - double pc = pitch.Cos(); - - vvec = { pc * angle.Cos(), pc * angle.Sin(), pitch.Sin() }; - sz = t1->Top() - t1->Floorclip + clamp(chase_height, -1000, 1000); - - if (Trace(t1->PosAtZ(sz), t1->Sector, vvec, distance, 0, 0, NULL, trace) && - trace.Distance > 10) + const DAngle baseYaw = dir.Angle(); + FTraceResults trace = {}; + if (viewPoint.IsAllowedOoB() && V_IsHardwareRenderer()) { - // Position camera slightly in front of hit thing - campos = t1->PosAtZ(sz) + vvec *(trace.Distance - 5); + viewPoint.Pos += dir * distance; + viewPoint.sector = viewPoint.ViewLevel->PointInRenderSubsector(viewPoint.Pos)->sector; + } + else if (Trace(viewPoint.Pos, viewPoint.sector, dir, distance, 0u, 0u, nullptr, trace)) + { + viewPoint.Pos = trace.HitPos - trace.HitVector * min(5.0, trace.Distance); + viewPoint.sector = viewPoint.ViewLevel->PointInRenderSubsector(viewPoint.Pos)->sector; + viewPoint.Angles.Yaw += deltaangle(baseYaw, trace.SrcAngleFromTarget); } else { - campos = trace.HitPos - trace.HitVector * 1/256.; + viewPoint.Pos = trace.HitPos; + viewPoint.sector = trace.Sector; + viewPoint.Angles.Yaw += deltaangle(baseYaw, trace.SrcAngleFromTarget); } - CameraSector = trace.Sector; - unlinked = trace.unlinked; - camangle = trace.SrcAngleFromTarget - 180.; -} + // TODO: Why does this even need to be done? Please fix tracers already. + if (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer()) + { + if (dir.Z < 0.0) + { + while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor) && viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor)) + { + viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::floor); + viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination; + } + } + else if (dir.Z > 0.0) + { + while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling)) + { + viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::ceiling); + viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination; + } + } + } +} //========================================================================== // @@ -5368,7 +5634,7 @@ bool P_TalkFacing(AActor *player) for (double angle : angleofs) { - P_AimLineAttack(player, player->Angles.Yaw + angle, TALKRANGE, &t, 35., ALF_FORCENOSMART | ALF_CHECKCONVERSATION | ALF_PORTALRESTRICT); + P_AimLineAttack(player, player->Angles.Yaw + DAngle::fromDeg(angle), TALKRANGE, &t, DAngle::fromDeg(35.), ALF_FORCENOSMART | ALF_CHECKCONVERSATION | ALF_PORTALRESTRICT); if (t.linetarget != NULL) { if (t.linetarget->health > 0 && // Dead things can't talk. @@ -5458,7 +5724,7 @@ bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end, return true; } - sec = P_PointOnLineSide(xpos, in->d.line) == 0 ? + sec = P_PointOnLineSide(xpos.XY(), in->d.line) == 0 ? in->d.line->frontsector : in->d.line->backsector; if (sec != NULL && sec->SecActTarget && @@ -5477,7 +5743,7 @@ bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end, continue; // not a special line, but keep checking } - if (P_PointOnLineSide(xpos, in->d.line) == 1) + if (P_PointOnLineSide(xpos.XY(), in->d.line) == 1) { if (!(in->d.line->activation & SPAC_UseBack)) { @@ -5571,7 +5837,7 @@ void P_UseLines(player_t *player) bool foundline = false; // If the player is transitioning a portal, use the group that is at its vertical center. - DVector2 start = player->mo->GetPortalTransition(player->mo->Height / 2); + DVector2 start = player->mo->GetPortalTransition(player->mo->Height / 2).XY(); // [NS] Now queries the Player's UseRange. DVector2 end = start + player->mo->Angles.Yaw.ToVector(player->mo->FloatVar(NAME_UseRange)); @@ -5611,7 +5877,7 @@ int P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType) else usedist = USERANGE; - start = PuzzleItemUser->GetPortalTransition(PuzzleItemUser->Height / 2); + start = PuzzleItemUser->GetPortalTransition(PuzzleItemUser->Height / 2).XY(); end = PuzzleItemUser->Angles.Yaw.ToVector(usedist); FPathTraverse it(PuzzleItemUser->Level, start.X, start.Y, end.X, end.Y, PT_DELTA | PT_ADDLINES | PT_ADDTHINGS); @@ -5633,7 +5899,7 @@ int P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType) } continue; } - if (P_PointOnLineSide(PuzzleItemUser->Pos(), in->d.line) == 1) + if (P_PointOnLineSide(PuzzleItemUser->Pos().XY(), in->d.line) == 1) { // Don't use back sides return false; } @@ -5667,7 +5933,7 @@ int P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType) //========================================================================== // // RADIUS ATTACK -// +// Most of the explosion code resides here. Except P_GeometryRadiusAttack(). // //========================================================================== @@ -5693,7 +5959,7 @@ CUSTOM_CVAR(Float, splashfactor, 1.f, CVAR_SERVERINFO) // Used by anything without OLDRADIUSDMG flag //========================================================================== -static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, int bombdistance, int fulldamagedistance, bool thingbombsource) +static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, double bombdistance, double fulldamagedistance, bool thingbombsource, bool round) { // [RH] New code. The bounding box only covers the // height of the thing and not the height of the map. @@ -5702,47 +5968,55 @@ static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, double dx, dy; double boxradius; - double bombdistancefloat = 1. / (double)(bombdistance - fulldamagedistance); + double bombdistancefloat = 1.0 / (bombdistance - fulldamagedistance); double bombdamagefloat = (double)bombdamage; - DVector2 vec = bombspot->Vec2To(thing); - dx = fabs(vec.X); - dy = fabs(vec.Y); - boxradius = thing->radius; - - // The damage pattern is square, not circular. - len = double(dx > dy ? dx : dy); - - if (bombspot->Z() < thing->Z() || bombspot->Z() >= thing->Top()) + if (!round) { - double dz; + DVector2 vec = bombspot->Vec2To(thing); + dx = fabs(vec.X); + dy = fabs(vec.Y); + boxradius = thing->radius; - if (bombspot->Z() > thing->Z()) - { - dz = double(bombspot->Z() - thing->Top()); - } - else - { - dz = double(thing->Z() - bombspot->Z()); - } - if (len <= boxradius) + // The damage pattern is square, not circular. + len = double(dx > dy ? dx : dy); + + if (bombspot->Z() < thing->Z() || bombspot->Z() >= thing->Top()) { - len = dz; + double dz; + + if (bombspot->Z() > thing->Z()) + { + dz = double(bombspot->Z() - thing->Top()); + } + else + { + dz = double(thing->Z() - bombspot->Z()); + } + if (len <= boxradius) + { + len = dz; + } + else + { + len -= boxradius; + len = g_sqrt(len*len + dz*dz); + } } else { len -= boxradius; - len = g_sqrt(len*len + dz*dz); + if (len < 0.f) + len = 0.f; } } + //[inkoalwetrust]: Round explosions just use the actual distance between the source and victim. else { - len -= boxradius; - if (len < 0.f) - len = 0.f; + len = bombspot->Distance3D (thing); } - len = clamp(len - (double)fulldamagedistance, 0, len); - points = bombdamagefloat * (1. - len * bombdistancefloat); + len = clamp(len - fulldamagedistance, 0.0, len); + points = bombdamagefloat * (1.0 - len * bombdistancefloat); // Calculate the splash and radius damage factor if called by P_RadiusAttack. // Otherwise, just get the raw damage. This allows modders to manipulate it @@ -5770,7 +6044,7 @@ static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, // based on XY distance. //========================================================================== -static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, int bombdistance, int fulldamagedistance) +static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, double bombdistance, double fulldamagedistance) { const int ret = fromaction ? 0 : -1; // -1 is specifically for P_RadiusAttack; continue onto another actor. double dx, dy, dist; @@ -5791,8 +6065,8 @@ static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, // When called from the action function, ignore the sight check. if (fromaction || P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) { - dist = clamp(dist - fulldamagedistance, 0, dist); - int damage = Scale(bombdamage, bombdistance - int(dist), bombdistance); + dist = clamp(dist - fulldamagedistance, 0.0, dist); + int damage = (int)Scale((double)bombdamage, bombdistance - dist, bombdistance); if (!fromaction) { @@ -5814,7 +6088,7 @@ static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, // damage and not taking into account any damage reduction. //========================================================================== -int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg) +int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, double distance, double fulldmgdistance, bool oldradiusdmg, bool circular) { if (!thing) @@ -5826,15 +6100,15 @@ int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int return damage; } - fulldmgdistance = clamp(fulldmgdistance, 0, distance - 1); + fulldmgdistance = clamp(fulldmgdistance, 0.0, distance - 1.0); // Mirroring A_Explode's behavior. - if (distance <= 0) + if (distance <= 0.0) distance = damage; const int newdam = oldradiusdmg ? GetOldRadiusDamage(true, self, thing, damage, distance, fulldmgdistance) - : int(GetRadiusDamage(true, self, thing, damage, distance, fulldmgdistance, false)); + : int(GetRadiusDamage(true, self, thing, damage, distance, fulldmgdistance, false, circular)); return newdam; } @@ -5846,15 +6120,15 @@ int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int // //========================================================================== -int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bombdistance, FName bombmod, - int flags, int fulldamagedistance) +int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, double bombdistance, FName bombmod, + int flags, double fulldamagedistance, FName species) { - if (bombdistance <= 0) + if (bombdistance <= 0.0) return 0; - fulldamagedistance = clamp(fulldamagedistance, 0, bombdistance - 1); + fulldamagedistance = clamp(fulldamagedistance, 0.0, bombdistance - 1.0); FPortalGroupArray grouplist(FPortalGroupArray::PGA_Full3d); - FMultiBlockThingsIterator it(grouplist, bombspot->Level, bombspot->X(), bombspot->Y(), bombspot->Z() - bombdistance, bombspot->Height + bombdistance*2, bombdistance, false, bombspot->Sector); + FMultiBlockThingsIterator it(grouplist, bombspot->Level, bombspot->X(), bombspot->Y(), bombspot->Z() - bombdistance, bombspot->Height + bombdistance*2.0, bombdistance, false, bombspot->Sector); FMultiBlockThingsIterator::CheckResult cres; if (flags & RADF_SOURCEISSPOT) @@ -5879,11 +6153,17 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom if (thing->flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG)) continue; + // allow rocket splash damage if (!(flags & RADF_HURTSOURCE) && (thing == bombsource || thing == bombspot)) { // don't damage the source of the explosion continue; } + // MBF21 + auto targetgroup = thing->GetClass()->ActorInfo()->splash_group; + auto sourcegroup = bombspot->GetClass()->ActorInfo()->splash_group; + if (targetgroup != 0 && targetgroup == sourcegroup) continue; + // a much needed option: monsters that fire explosive projectiles cannot // be hurt by projectiles fired by a monster of the same type. // Controlled by the DONTHARMCLASS and DONTHARMSPECIES flags. @@ -5895,6 +6175,16 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom ) ) continue; + if ((species != NAME_None) && (thing->Species != species)) + continue; + + //[inkoalawetrust] Don't harm actors friendly to the explosions' source. But do harm the source. + if ((flags & RADF_NOALLIES) && bombsource && bombsource->IsFriend(thing) && !(thing == bombsource || thing == bombspot)) + continue; + + if (bombsource && thing != bombsource && bombsource->player && P_ShouldPassThroughPlayer(bombsource, thing)) + continue; + targets.Push(thing); } @@ -5907,7 +6197,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom if ((flags & RADF_NODAMAGE) || (!((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG) && !(flags & RADF_OLDRADIUSDAMAGE) && !(thing->Level->i_compatflags2 & COMPATF2_EXPLODE2))) { - double points = GetRadiusDamage(false, bombspot, thing, bombdamage, bombdistance, fulldamagedistance, bombsource == thing); + double points = GetRadiusDamage(false, bombspot, thing, bombdamage, bombdistance, fulldamagedistance, bombsource == thing,!!(flags & RADF_CIRCULAR)); double check = int(points) * bombdamage; // points and bombdamage should be the same sign (the double cast of 'points' is needed to prevent overflows and incorrect values slipping through.) if ((check > 0 || (check == 0 && bombspot->flags7 & MF7_FORCEZERORADIUSDMG)) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) @@ -5916,15 +6206,22 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom double thrust; int damage = abs((int)points); int newdam = damage; + int dmgmask = 0; if (!(flags & RADF_NODAMAGE)) { + //[inkoalawetrust] Thrustless explosions don't push anything. + if (!(flags & RADF_THRUSTLESS)) + dmgmask = DMG_EXPLOSION; + else + dmgmask = DMG_EXPLOSION | DMG_THRUSTLESS; + //[MC] Don't count actors saved by buddha if already at 1 health. int prehealth = thing->health; - newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod, DMG_EXPLOSION); + newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod, dmgmask); if (thing->health < prehealth) count++; } - else if (thing->player == NULL && (!(flags & RADF_NOIMPACTDAMAGE) && !(thing->flags7 & MF7_DONTTHRUST))) + else if (thing->player == NULL && (!(flags & RADF_NOIMPACTDAMAGE && !(flags & RADF_THRUSTLESS)) && !(thing->flags7 & MF7_DONTTHRUST))) thing->flags2 |= MF2_BLASTED; if (!(thing->flags & MF_ICECORPSE)) @@ -5932,13 +6229,12 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom if (!(flags & RADF_NODAMAGE) && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) P_TraceBleed(newdam > 0 ? newdam : damage, thing, bombspot); - if ((flags & RADF_NODAMAGE) || !(bombspot->flags2 & MF2_NODMGTHRUST)) + if ((flags & RADF_NODAMAGE && !(flags & RADF_THRUSTLESS)) || !(bombspot->flags2 & MF2_NODMGTHRUST) && !(flags & RADF_THRUSTLESS)) { if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST)) { if (!(thing->flags7 & MF7_DONTTHRUST)) { - thrust = points * 0.5 / (double)thing->Mass; if (bombsource == thing) { @@ -6045,7 +6341,7 @@ bool P_AdjustFloorCeil(AActor *thing, FChangePosition *cpos) thing->flags2 |= MF2_PASSMOBJ; } - bool isgood = P_CheckPosition(thing, thing->Pos(), tm); + bool isgood = P_CheckPosition(thing, thing->Pos().XY(), tm); if (!(thing->flags4 & MF4_ACTLIKEBRIDGE)) { thing->floorz = tm.floorz; @@ -6215,7 +6511,7 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos) mo->Vel.X = pr_crunch.Random2() / 16.; mo->Vel.Y = pr_crunch.Random2() / 16.; - if (thing->BloodTranslation != 0 && !(mo->flags2 & MF2_DONTTRANSLATE)) + if (thing->BloodTranslation != NO_TRANSLATION && !(mo->flags2 & MF2_DONTTRANSLATE)) { mo->Translation = thing->BloodTranslation; } @@ -6228,13 +6524,13 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos) if (!(cl_bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE; } - DAngle an = (M_Random() - 128) * (360./256); + DAngle an = DAngle::fromDeg((M_Random() - 128) * (360./256)); if (cl_bloodtype >= 1) { P_DrawSplash2(thing->Level, 32, thing->PosPlusZ(thing->Height/2), an, 2, thing->BloodColor); } } - if (thing->CrushPainSound != 0 && !S_GetSoundPlayingInfo(thing, thing->CrushPainSound)) + if (thing->CrushPainSound != NO_SOUND && !S_GetSoundPlayingInfo(thing, thing->CrushPainSound)) { S_Sound(thing, CHAN_VOICE, 0, thing->CrushPainSound, 1.f, ATTN_NORM); } @@ -6282,6 +6578,9 @@ int P_PushUp(AActor *thing, FChangePosition *cpos) if (!P_CanCollideWith(thing, intersect)) continue; + if (thing->player && P_ShouldPassThroughPlayer(thing, intersect)) + continue; + if (!(intersect->flags2 & MF2_PASSMOBJ) || (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || (intersect->flags4 & MF4_ACTLIKEBRIDGE) @@ -6346,6 +6645,9 @@ int P_PushDown(AActor *thing, FChangePosition *cpos) if (!P_CanCollideWith(thing, intersect)) continue; + if (thing->player && P_ShouldPassThroughPlayer(thing, intersect)) + continue; + if (!(intersect->flags2 & MF2_PASSMOBJ) || (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || (intersect->flags4 & MF4_ACTLIKEBRIDGE) @@ -6581,7 +6883,7 @@ void PIT_CeilingRaise(AActor *thing, FChangePosition *cpos) AActor *onmobj; if (!P_TestMobjZ(thing, true, &onmobj) && onmobj->Z() <= thing->Z()) { - thing->SetZ(MIN(thing->ceilingz - thing->Height, onmobj->Top())); + thing->SetZ(min(thing->ceilingz - thing->Height, onmobj->Top())); thing->UpdateRenderSectorList(); } } diff --git a/src/playsim/p_maputl.cpp b/src/playsim/p_maputl.cpp index cb21be2e35c..8c172c479f8 100644 --- a/src/playsim/p_maputl.cpp +++ b/src/playsim/p_maputl.cpp @@ -415,11 +415,11 @@ bool AActor::FixMapthingPos() DAngle ang = ldef->Delta().Angle(); if (ldef->backsector != NULL && ldef->backsector == secstart) { - ang += 90.; + ang += DAngle::fromDeg(90.); } else { - ang -= 90.; + ang -= DAngle::fromDeg(90.); } // Get the distance we have to move the object away from the wall @@ -527,10 +527,10 @@ void AActor::LinkToWorld(FLinkContext *ctx, bool spawningmapthing, sector_t *sec } else { // [RH] Link into every block this actor touches, not just the center one - x1 = MAX(0, x1); - y1 = MAX(0, y1); - x2 = MIN(Level->blockmap.bmapwidth - 1, x2); - y2 = MIN(Level->blockmap.bmapheight - 1, y2); + x1 = max(0, x1); + y1 = max(0, y1); + x2 = min(Level->blockmap.bmapwidth - 1, x2); + y2 = min(Level->blockmap.bmapheight - 1, y2); for (int y = y1; y <= y2; ++y) { for (int x = x1; x <= x2; ++x) @@ -889,7 +889,7 @@ void FMultiBlockLinesIterator::Reset() //=========================================================================== FBlockThingsIterator::FBlockThingsIterator(FLevelLocals *l) -: DynHash(0) +: DynHash() { Level = l; minx = maxx = 0; @@ -899,7 +899,7 @@ FBlockThingsIterator::FBlockThingsIterator(FLevelLocals *l) } FBlockThingsIterator::FBlockThingsIterator(FLevelLocals *l, int _minx, int _miny, int _maxx, int _maxy) -: DynHash(0) +: DynHash() { Level = l; minx = _minx; @@ -910,13 +910,13 @@ FBlockThingsIterator::FBlockThingsIterator(FLevelLocals *l, int _minx, int _miny Reset(); } -void FBlockThingsIterator::init(const FBoundingBox &box) +void FBlockThingsIterator::init(const FBoundingBox &box, bool clearhash) { maxy = Level->blockmap.GetBlockY(box.Top()); miny = Level->blockmap.GetBlockY(box.Bottom()); maxx = Level->blockmap.GetBlockX(box.Right()); minx = Level->blockmap.GetBlockX(box.Left()); - ClearHash(); + if (clearhash) ClearHash(); Reset(); } @@ -1139,7 +1139,7 @@ void FMultiBlockThingsIterator::startIteratorForGroup(int group) offset.X += checkpoint.X; offset.Y += checkpoint.Y; bbox.setBox(offset.X, offset.Y, checkpoint.Z); - blockIterator.init(bbox); + blockIterator.init(bbox, false); } //=========================================================================== @@ -1153,6 +1153,7 @@ void FMultiBlockThingsIterator::Reset() index = -1; portalflags = 0; startIteratorForGroup(basegroup); + blockIterator.ClearHash(); } //=========================================================================== @@ -1679,6 +1680,23 @@ FPathTraverse::~FPathTraverse() } +// +// P_CheckFov +// Returns true if t2 is within t1's field of view. +// +int P_CheckFov(AActor* t1, AActor* t2, double fov) +{ + return absangle(t1->AngleTo(PARAM_NULLCHECK(t2,t2)), t1->Angles.Yaw) <= DAngle::fromDeg(fov); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckFov, P_CheckFov) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(t, AActor); + PARAM_FLOAT(fov); + ACTION_RETURN_BOOL(P_CheckFov(self, t, fov)); +} + //=========================================================================== // // P_RoughMonsterSearch @@ -1784,6 +1802,7 @@ struct BlockCheckInfo bool onlyseekable; bool frontonly; divline_t frontline; + double fov; }; //=========================================================================== @@ -1810,6 +1829,12 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param) { continue; } + // skip actors outside of specified FOV + if (info->fov > 0 && !P_CheckFov(mo, link->Me, info->fov)) + { + continue; + } + if (mo->IsOkayToAttack (link->Me)) { return link->Me; @@ -1819,10 +1844,11 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param) return NULL; } -AActor *P_RoughMonsterSearch(AActor *mo, int distance, bool onlyseekable, bool frontonly) +AActor *P_RoughMonsterSearch(AActor *mo, int distance, bool onlyseekable, bool frontonly, double fov) { BlockCheckInfo info; info.onlyseekable = onlyseekable; + info.fov = fov; if ((info.frontonly = frontonly)) { info.frontline.x = mo->X(); @@ -1929,8 +1955,8 @@ int P_VanillaPointOnLineSide(double x, double y, const line_t* line) auto dx = FloatToFixed(x - line->v1->fX()); auto dy = FloatToFixed(y - line->v1->fY()); - auto left = FixedMul( int(delta.Y * 256) , dx ); - auto right = FixedMul( dy , int(delta.X * 256) ); + auto left = MulScale( int(delta.Y * 256) , dx, 16 ); + auto right = MulScale( dy , int(delta.X * 256), 16 ); if (right < left) return 0; // front side @@ -2017,3 +2043,91 @@ subsector_t *FLevelLocals::PointInRenderSubsector (fixed_t x, fixed_t y) return (subsector_t *)((uint8_t *)node - 1); } + +//========================================================================== +// +// FBoundingBox :: BoxOnLineSide +// +// Considers the line to be infinite +// Returns side 0 or 1, -1 if box crosses the line. +// +//========================================================================== + +int BoxOnLineSide(const FBoundingBox &box, const line_t* ld) +{ + int p1; + int p2; + + if (ld->Delta().X == 0) + { // ST_VERTICAL + p1 = box.Right() < ld->v1->fX(); + p2 = box.Left() < ld->v1->fX(); + if (ld->Delta().Y < 0) + { + p1 ^= 1; + p2 ^= 1; + } + } + else if (ld->Delta().Y == 0) + { // ST_HORIZONTAL: + p1 = box.Top() > ld->v1->fY(); + p2 = box.Bottom() > ld->v1->fY(); + if (ld->Delta().X < 0) + { + p1 ^= 1; + p2 ^= 1; + } + } + else if ((ld->Delta().X * ld->Delta().Y) >= 0) + { // ST_POSITIVE: + p1 = P_PointOnLineSide(box.Left(), box.Top(), ld); + p2 = P_PointOnLineSide(box.Right(), box.Bottom(), ld); + } + else + { // ST_NEGATIVE: + p1 = P_PointOnLineSide(box.Right(), box.Top(), ld); + p2 = P_PointOnLineSide(box.Left(), box.Bottom(), ld); + } + + return (p1 == p2) ? p1 : -1; +} + +DEFINE_ACTION_FUNCTION(FLevelLocals, PointOnLineSide) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_POINTER(l, line_t); + PARAM_BOOL(precise); + + int res; + if (precise) // allow forceful overriding of compat flag + res = P_PointOnLineSidePrecise(x, y, l); + else + res = P_PointOnLineSide(x, y, l); + + ACTION_RETURN_INT(res); +} + +DEFINE_ACTION_FUNCTION(FLevelLocals, ActorOnLineSide) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_OBJECT(mo, AActor); + PARAM_POINTER(l, line_t); + + FBoundingBox box(mo->X(), mo->Y(), mo->radius); + ACTION_RETURN_INT(BoxOnLineSide(box, l)); +} + +DEFINE_ACTION_FUNCTION(FLevelLocals, BoxOnLineSide) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(radius); + PARAM_POINTER(l, line_t); + + FBoundingBox box(x, y, radius); + ACTION_RETURN_INT(BoxOnLineSide(box, l)); +} + diff --git a/src/playsim/p_maputl.h b/src/playsim/p_maputl.h index e86d363cf85..7c89bab062f 100644 --- a/src/playsim/p_maputl.h +++ b/src/playsim/p_maputl.h @@ -6,6 +6,7 @@ #include "doomstat.h" #include "doomdata.h" #include "m_bbox.h" +#include "cmdlib.h" extern int validcount; struct FBlockNode; @@ -38,12 +39,17 @@ struct intercept_t // //========================================================================== -inline int P_PointOnLineSidePrecise(double x, double y, const line_t *line) +inline int P_PointOnLineSidePrecise(double x, double y, const linebase_t *line) { return (y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - x) * line->Delta().Y > EQUAL_EPSILON; } -inline int P_PointOnLineSidePrecise(const DVector2 &pt, const line_t *line) +inline int P_PointOnLineSidePrecise(const DVector2 &pt, const linebase_t *line) +{ + return (pt.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pt.X) * line->Delta().Y > EQUAL_EPSILON; +} + +inline int P_PointOnLineSidePrecise(const DVector3& pt, const linebase_t* line) { return (pt.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pt.X) * line->Delta().Y > EQUAL_EPSILON; } @@ -318,7 +324,7 @@ class FBlockThingsIterator Level = l; init(box); } - void init(const FBoundingBox &box); + void init(const FBoundingBox &box, bool clearhash = true); AActor *Next(bool centeronly = false); void Reset() { StartBlock(minx, miny); } }; @@ -416,4 +422,6 @@ double P_InterceptVector(const divline_t *v2, const divline_t *v1); #define PT_COMPATIBLE 4 #define PT_DELTA 8 // x2,y2 is passed as a delta, not as an endpoint +int BoxOnLineSide(const FBoundingBox& box, const line_t* ld); + #endif diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 7208305ddb8..d216d30d8c6 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -58,7 +58,7 @@ // HEADER FILES ------------------------------------------------------------ #include -#include "templates.h" + #include "m_random.h" #include "doomdef.h" @@ -88,7 +88,8 @@ #include "po_man.h" #include "p_spec.h" #include "p_checkposition.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "r_utility.h" #include "thingdef.h" #include "d_player.h" @@ -98,6 +99,9 @@ #include "actorinlines.h" #include "a_dynlight.h" #include "fragglescript/t_fs.h" +#include "shadowinlines.h" +#include "model.h" +#include "d_net.h" // MACROS ------------------------------------------------------------------ @@ -119,7 +123,6 @@ EXTERN_CVAR (Int, cl_rockettrails) // PRIVATE DATA DEFINITIONS ------------------------------------------------ static FRandom pr_explodemissile ("ExplodeMissile"); -FRandom pr_bounce ("Bounce"); static FRandom pr_reflect ("Reflect"); static FRandom pr_nightmarerespawn ("NightmareRespawn"); static FRandom pr_botspawnmobj ("BotSpawnActor"); @@ -132,7 +135,6 @@ static FRandom pr_splat ("FAxeSplatter"); static FRandom pr_ripperblood ("RipperBlood"); static FRandom pr_chunk ("Chunk"); static FRandom pr_checkmissilespawn ("CheckMissileSpawn"); -static FRandom pr_spawnmissile ("SpawnMissile"); static FRandom pr_missiledamage ("MissileDamage"); static FRandom pr_multiclasschoice ("MultiClassChoice"); static FRandom pr_rockettrail("RocketTrail"); @@ -141,6 +143,8 @@ static FRandom pr_uniquetid("UniqueTID"); // PUBLIC DATA DEFINITIONS ------------------------------------------------- FRandom pr_spawnmobj ("SpawnActor"); +FRandom pr_bounce("Bounce"); +FRandom pr_spawnmissile("SpawnMissile"); CUSTOM_CVAR (Float, sv_gravity, 800.f, CVAR_SERVERINFO|CVAR_NOSAVE|CVAR_NOINITCALL) { @@ -157,6 +161,7 @@ CVAR (Int, cl_bloodtype, 0, CVAR_ARCHIVE); // CODE -------------------------------------------------------------------- +IMPLEMENT_CLASS(DActorModelData, false, false); IMPLEMENT_CLASS(AActor, false, true) IMPLEMENT_POINTERS_START(AActor) @@ -170,14 +175,27 @@ IMPLEMENT_POINTERS_START(AActor) IMPLEMENT_POINTER(master) IMPLEMENT_POINTER(Poisoner) IMPLEMENT_POINTER(alternative) + IMPLEMENT_POINTER(ViewPos) + IMPLEMENT_POINTER(modelData) + IMPLEMENT_POINTER(boneComponentData) IMPLEMENT_POINTERS_END -AActor::~AActor () +//========================================================================== +// +// Make sure Actors can never have their networking disabled. +// +//========================================================================== + +void AActor::EnableNetworking(const bool enable) { - // Please avoid calling the destructor directly (or through delete)! - // Use Destroy() instead. -} + if (!enable) + { + ThrowAbortException(X_OTHER, "Cannot disable networking on Actors. Consider a Thinker instead."); + return; + } + Super::EnableNetworking(true); +} //========================================================================== // @@ -185,8 +203,6 @@ AActor::~AActor () // //========================================================================== - - #define A(a,b) ((a), (b), def->b) void AActor::Serialize(FSerializer &arc) @@ -203,6 +219,7 @@ void AActor::Serialize(FSerializer &arc) A("scale", Scale) A("renderstyle", RenderStyle) A("renderflags", renderflags) + A("renderflags2", renderflags2) A("picnum", picnum) A("floorpic", floorpic) A("ceilingpic", ceilingpic) @@ -227,7 +244,6 @@ void AActor::Serialize(FSerializer &arc) A("tics", tics) A("state", state) A("damage", DamageVal) - .Terrain("floorterrain", floorterrain, &def->floorterrain) A("projectilekickback", projectileKickback) A("flags", flags) A("flags2", flags2) @@ -237,6 +253,7 @@ void AActor::Serialize(FSerializer &arc) A("flags6", flags6) A("flags7", flags7) A("flags8", flags8) + A("flags9", flags9) A("weaponspecial", weaponspecial) A("special1", special1) A("special2", special2) @@ -261,7 +278,6 @@ void AActor::Serialize(FSerializer &arc) A("floorclip", Floorclip) A("tid", tid) A("special", special) - .Args("args", args, def->args, special) A("accuracy", accuracy) A("stamina", stamina) ("goal", goal) @@ -294,6 +310,7 @@ void AActor::Serialize(FSerializer &arc) A("meleestate", MeleeState) A("missilestate", MissileState) A("maxdropoffheight", MaxDropOffHeight) + A("maxslopesteepness", MaxSlopeSteepness) A("maxstepheight", MaxStepHeight) A("bounceflags", BounceFlags) A("bouncefactor", bouncefactor) @@ -312,6 +329,7 @@ void AActor::Serialize(FSerializer &arc) A("smokecounter", smokecounter) ("blockingmobj", BlockingMobj) A("blockingline", BlockingLine) + A("movementblockingline", MovementBlockingLine) A("blocking3dfloor", Blocking3DFloor) A("blockingceiling", BlockingCeiling) A("blockingfloor", BlockingFloor) @@ -328,6 +346,7 @@ void AActor::Serialize(FSerializer &arc) A("damagemultiply", DamageMultiply) A("waveindexxy", WeaveIndexXY) A("weaveindexz", WeaveIndexZ) + A("freezetics", freezetics) A("pdmgreceived", PoisonDamageReceived) A("pdurreceived", PoisonDurationReceived) A("ppreceived", PoisonPeriodReceived) @@ -349,13 +368,14 @@ void AActor::Serialize(FSerializer &arc) A("spriteangle", SpriteAngle) A("spriterotation", SpriteRotation) ("alternative", alternative) + A("thrubits", ThruBits) A("cameraheight", CameraHeight) A("camerafov", CameraFOV) A("tag", Tag) - A("visiblestartangle",VisibleStartAngle) - A("visibleendangle",VisibleEndAngle) - A("visiblestartpitch",VisibleStartPitch) - A("visibleendpitch",VisibleEndPitch) + A("visiblestartangle", VisibleStartAngle) + A("visibleendangle", VisibleEndAngle) + A("visiblestartpitch", VisibleStartPitch) + A("visibleendpitch", VisibleEndPitch) A("woundhealth", WoundHealth) A("rdfactor", RadiusDamageFactor) A("selfdamagefactor", SelfDamageFactor) @@ -363,10 +383,27 @@ void AActor::Serialize(FSerializer &arc) A("renderhidden", RenderHidden) A("renderrequired", RenderRequired) A("friendlyseeblocks", friendlyseeblocks) + A("viewangles", ViewAngles) A("spawntime", SpawnTime) A("spawnorder", SpawnOrder) A("friction", Friction) - A("userlights", UserLights); + A("SpriteOffset", SpriteOffset) + ("viewpos", ViewPos) + A("lightlevel", LightLevel) + A("userlights", UserLights) + A("WorldOffset", WorldOffset) + ("modelData", modelData) + A("LandingSpeed", LandingSpeed) + + ("unmorphtime", UnmorphTime) + ("morphflags", MorphFlags) + ("premorphproperties", PremorphProperties) + ("morphexitflash", MorphExitFlash); + + + SerializeTerrain(arc, "floorterrain", floorterrain, &def->floorterrain); + SerializeArgs(arc, "args", args, def->args, special); + } #undef A @@ -399,17 +436,11 @@ void AActor::PostSerialize() } } ClearInterpolation(); + ClearFOVInterpolation(); UpdateWaterLevel(false); } - -AActor &AActor::operator= (const AActor &other) -{ - memcpy (&snext, &other.snext, (uint8_t *)&this[1] - (uint8_t *)&snext); - return *this; -} - //========================================================================== // // AActor::InStateSequence @@ -466,14 +497,14 @@ bool AActor::IsMapActor() // //========================================================================== -int AActor::GetTics(FState * newstate) +inline int GetTics(AActor* actor, FState * newstate) { int tics = newstate->GetTics(); - if (isFast() && newstate->GetFast()) + if (actor->isFast() && newstate->GetFast()) { return tics - (tics>>1); } - else if (isSlow() && newstate->GetSlow()) + else if (actor->isSlow() && newstate->GetSlow()) { return tics<<1; } @@ -492,6 +523,8 @@ bool AActor::SetState (FState *newstate, bool nofunction) { if (debugfile && player && (player->cheats & CF_PREDICTING)) fprintf (debugfile, "for pl %d: SetState while predicting!\n", Level->PlayerNum(player)); + + auto oldstate = state; do { if (newstate == NULL) @@ -518,7 +551,7 @@ bool AActor::SetState (FState *newstate, bool nofunction) return false; } state = newstate; - tics = GetTics(newstate); + tics = GetTics(this, newstate); renderflags = (renderflags & ~RF_FULLBRIGHT) | ActorRenderFlags::FromInt (newstate->GetFullbright()); newsprite = newstate->sprite; if (newsprite != SPR_FIXED) @@ -577,7 +610,11 @@ bool AActor::SetState (FState *newstate, bool nofunction) newstate = newstate->GetNextState(); } while (tics == 0); - flags8 |= MF8_RECREATELIGHTS; + if (GetInfo()->LightAssociations.Size() || (state && state->Light > 0) || (oldstate && oldstate->Light > 0)) + { + flags8 |= MF8_RECREATELIGHTS; + Level->flags3 |= LEVEL3_LIGHTCREATED; + } return true; } @@ -592,13 +629,14 @@ DEFINE_ACTION_FUNCTION(AActor, SetState) //============================================================================ // -// AActor :: DestroyAllInventory +// DestroyAllInventory +// Destroys all the inventory the actor is holding. // //============================================================================ -void AActor::DestroyAllInventory () +static void DestroyAllInventory(AActor* actor) { - AActor *inv = Inventory; + AActor *inv = PARAM_NULLCHECK(actor, self)->Inventory; if (inv != nullptr) { TArray toDelete; @@ -625,10 +663,10 @@ void AActor::DestroyAllInventory () } } -DEFINE_ACTION_FUNCTION(AActor, DestroyAllInventory) +DEFINE_ACTION_FUNCTION_NATIVE(AActor, DestroyAllInventory, DestroyAllInventory) { PARAM_SELF_PROLOGUE(AActor); - self->DestroyAllInventory(); + DestroyAllInventory(self); return 0; } //============================================================================ @@ -750,23 +788,6 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType) ACTION_RETURN_OBJECT(self->GiveInventoryType(type)); } -//============================================================================ -// -// AActor :: ClearInventory -// -// Clears the inventory of a single actor. -// -//============================================================================ - -void AActor::ClearInventory() -{ - IFVIRTUAL(AActor, ClearInventory) - { - VMValue params[] = { this }; - VMCall(func, params, 1, nullptr, 0); - } -} - //============================================================================ // // AActor :: CopyFriendliness @@ -822,7 +843,7 @@ int P_GetRealMaxHealth(AActor *actor, int max) { max = actor->GetMaxHealth(true); // [MH] First step in predictable generic morph effects - if (player->morphTics) + if (actor->alternative != nullptr) { if (player->MorphStyle & MORPH_FULLHEALTH) { @@ -844,7 +865,7 @@ int P_GetRealMaxHealth(AActor *actor, int max) else { // Bonus health should be added on top of the item's limit. - if (player->morphTics == 0 || (player->MorphStyle & MORPH_ADDSTAMINA)) + if (actor->alternative == nullptr || (player->MorphStyle & MORPH_ADDSTAMINA)) { max += actor->IntVar(NAME_BonusHealth); } @@ -975,6 +996,44 @@ DEFINE_ACTION_FUNCTION(AActor, CheckLocalView) ACTION_RETURN_BOOL(self->CheckLocalView()); } +void AActor::DisableLocalRendering(const unsigned int pNum, const bool disable) +{ + if (pNum == consoleplayer) + NoLocalRender = disable; +} + +static void DisableLocalRendering(AActor* const self, const unsigned int pNum, const int disable) +{ + self->DisableLocalRendering(pNum, disable); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, DisableLocalRendering, DisableLocalRendering) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_UINT(pNum); + PARAM_INT(disable); + + DisableLocalRendering(self, pNum, disable); + return 0; +} + +bool AActor::ShouldRenderLocally() const +{ + return !NoLocalRender; +} + +static int ShouldRenderLocally(const AActor* const self) +{ + return self->ShouldRenderLocally(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, ShouldRenderLocally, ShouldRenderLocally) +{ + PARAM_SELF_PROLOGUE(AActor); + + ACTION_RETURN_INT(ShouldRenderLocally(self)); +} + //============================================================================ // // AActor :: IsInsideVisibleAngles @@ -994,10 +1053,10 @@ bool AActor::IsInsideVisibleAngles() const if (p == nullptr || p->camera == nullptr) return true; - DAngle anglestart = VisibleStartAngle; - DAngle angleend = VisibleEndAngle; - DAngle pitchstart = VisibleStartPitch; - DAngle pitchend = VisibleEndPitch; + DAngle anglestart = DAngle::fromDeg(VisibleStartAngle.Degrees()); + DAngle angleend = DAngle::fromDeg(VisibleEndAngle.Degrees()); + DAngle pitchstart = DAngle::fromDeg(VisibleStartPitch.Degrees()); + DAngle pitchend = DAngle::fromDeg(VisibleEndPitch.Degrees()); if (anglestart > angleend) { @@ -1018,8 +1077,8 @@ bool AActor::IsInsideVisibleAngles() const if (mo != nullptr) { - - DVector3 diffang = r_viewpoint.Pos - Pos(); + DVector2 offset = Level->Displacements.getOffset(r_viewpoint.sector->PortalGroup, Sector->PortalGroup); + DVector3 diffang = r_viewpoint.Pos + offset - Pos(); DAngle to = diffang.Angle(); if (!(renderflags & RF_ABSMASKANGLE)) @@ -1054,6 +1113,9 @@ bool AActor::IsVisibleToPlayer() const // [BB] Safety check. This should never be NULL. Nevertheless, we return true to leave the default ZDoom behavior unaltered. if (p == nullptr || p->camera == nullptr ) return true; + + if (!ShouldRenderLocally()) + return false; if (VisibleToTeam != 0 && teamplay && (signed)(VisibleToTeam-1) != p->userinfo.GetTeam() ) @@ -1118,18 +1180,6 @@ void AActor::ConversationAnimation (int animnum) // //============================================================================ -void AActor::Touch (AActor *toucher) -{ -} - -DEFINE_ACTION_FUNCTION(AActor, Touch) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT_NOT_NULL(toucher, AActor); - self->Touch(toucher); - return 0; -} - void AActor::CallTouch(AActor *toucher) { IFVIRTUAL(AActor, Touch) @@ -1137,7 +1187,6 @@ void AActor::CallTouch(AActor *toucher) VMValue params[2] = { (DObject*)this, toucher }; VMCall(func, params, 2, nullptr, 0); } - else Touch(toucher); } //============================================================================ @@ -1150,20 +1199,22 @@ void AActor::CallTouch(AActor *toucher) // Bool items is true if it should destroy() dropped items, false otherwise. //============================================================================ -bool AActor::Grind(bool items) +static int Grind(AActor* actor, int items) { + PARAM_NULLCHECK(actor, actor); // crunch bodies to giblets - if ((flags & MF_CORPSE) && !(flags3 & MF3_DONTGIB) && (health <= 0)) + if ((actor->flags & MF_CORPSE) && !(actor->flags3 & MF3_DONTGIB) && (actor->health <= 0)) { - FState * state = FindState(NAME_Crush); + FState * state = actor->FindState(NAME_Crush); // In Heretic and Chex Quest we don't change the actor's sprite, just its size. if (state == NULL && gameinfo.dontcrunchcorpses) { - flags &= ~MF_SOLID; - flags3 |= MF3_DONTGIB; - Height = 0; - radius = 0; + actor->flags &= ~MF_SOLID; + actor->flags3 |= MF3_DONTGIB; + actor->Height = 0; + actor->radius = 0; + actor->Vel.Zero(); return false; } @@ -1172,45 +1223,46 @@ bool AActor::Grind(bool items) // The reason for the change was originally because of a problem with players, // see rh_log entry for February 21, 1999. Don't know if it is still relevant. if (state == NULL // Only use the default crushed state if: - && !(flags & MF_NOBLOOD) // 1. the monster bleeeds, - && (Level->i_compatflags & COMPATF_CORPSEGIBS) // 2. the compat setting is on, - && player == NULL) // 3. and the thing isn't a player. + && !(actor->flags & MF_NOBLOOD) // 1. the monster bleeeds, + && actor->player == NULL) // 3. and the thing isn't a player. { isgeneric = true; - state = FindState(NAME_GenericCrush); + state = actor->FindState(NAME_GenericCrush); if (state != NULL && (sprites[state->sprite].numframes <= 0)) state = NULL; // If one of these tests fails, do not use that state. } - if (state != NULL && !(flags & MF_ICECORPSE)) + if (state != NULL && !(actor->flags & MF_ICECORPSE)) { - if (this->flags4 & MF4_BOSSDEATH) + if (actor->flags4 & MF4_BOSSDEATH) { - A_BossDeath(this); + A_BossDeath(actor); } - flags &= ~MF_SOLID; - flags3 |= MF3_DONTGIB; - Height = 0; - radius = 0; - SetState (state); + actor->flags &= ~MF_SOLID; + actor->flags3 |= MF3_DONTGIB; + actor->Height = 0; + actor->radius = 0; + actor->Vel.Zero(); + actor->SetState (state); if (isgeneric) // Not a custom crush state, so colorize it appropriately. { - S_Sound (this, CHAN_BODY, 0, "misc/fallingsplat", 1, ATTN_IDLE); - Translation = BloodTranslation; + S_Sound (actor, CHAN_BODY, 0, "misc/fallingsplat", 1, ATTN_IDLE); + actor->Translation = actor->BloodTranslation; } + actor->Level->localEventManager->WorldThingGround(actor, state); return false; } - if (!(flags & MF_NOBLOOD)) + if (!(actor->flags & MF_NOBLOOD)) { - if (this->flags4 & MF4_BOSSDEATH) + if (actor->flags4 & MF4_BOSSDEATH) { - A_BossDeath(this); + A_BossDeath(actor); } PClassActor *i = PClass::FindActor("RealGibs"); if (i != NULL) { - i = i->GetReplacement(Level); + i = i->GetReplacement(actor->Level); const AActor *defaults = GetDefaultByType (i); if (defaults->SpawnState == NULL || @@ -1222,67 +1274,69 @@ bool AActor::Grind(bool items) if (i == NULL) { // if there's no gib sprite don't crunch it. - flags &= ~MF_SOLID; - flags3 |= MF3_DONTGIB; - Height = 0; - radius = 0; + actor->flags &= ~MF_SOLID; + actor->flags3 |= MF3_DONTGIB; + actor->Height = 0; + actor->radius = 0; + actor->Vel.Zero(); return false; } - AActor *gib = Spawn (Level, i, Pos(), ALLOW_REPLACE); + AActor *gib = Spawn (actor->Level, i, actor->Pos(), ALLOW_REPLACE); if (gib != NULL) { - gib->RenderStyle = RenderStyle; - gib->Alpha = Alpha; + gib->RenderStyle = actor->RenderStyle; + gib->Alpha = actor->Alpha; gib->Height = 0; gib->radius = 0; - gib->Translation = BloodTranslation; + gib->Translation = actor->BloodTranslation; } - S_Sound (this, CHAN_BODY, 0, "misc/fallingsplat", 1, ATTN_IDLE); + S_Sound (actor, CHAN_BODY, 0, "misc/fallingsplat", 1, ATTN_IDLE); + actor->Level->localEventManager->WorldThingGround(actor, nullptr); } - if (flags & MF_ICECORPSE) + if (actor->flags & MF_ICECORPSE) { - tics = 1; - Vel.Zero(); + actor->tics = 1; + actor->Vel.Zero(); } - else if (player) + else if (actor->player) { - flags |= MF_NOCLIP; - flags3 |= MF3_DONTGIB; - renderflags |= RF_INVISIBLE; + actor->flags |= MF_NOCLIP; + actor->flags3 |= MF3_DONTGIB; + actor->renderflags |= RF_INVISIBLE; } else { - Destroy (); + actor->Destroy (); } return false; // keep checking } // killough 11/98: kill touchy things immediately - if (flags6 & MF6_TOUCHY && (flags6 & MF6_ARMED || IsSentient())) + if (actor->flags6 & MF6_TOUCHY && (actor->flags6 & MF6_ARMED || actor->IsSentient())) { - flags6 &= ~MF6_ARMED; // Disarm - P_DamageMobj (this, NULL, NULL, health, NAME_Crush, DMG_FORCED); // kill object + actor->flags6 &= ~MF6_ARMED; // Disarm + P_DamageMobj (actor, NULL, NULL, actor->health, NAME_Crush, DMG_FORCED); // kill object return true; // keep checking } - if (!(flags & MF_SOLID) || (flags & MF_NOCLIP)) + if (!(actor->flags & MF_SOLID) || (actor->flags & MF_NOCLIP)) { return false; } - if (!(flags & MF_SHOOTABLE)) + if (!(actor->flags & MF_SHOOTABLE)) { return false; // assume it is bloody gibs or something } return true; } -DEFINE_ACTION_FUNCTION(AActor, Grind) +DEFINE_ACTION_FUNCTION_NATIVE(AActor, Grind, Grind) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL(items); - ACTION_RETURN_BOOL(self->Grind(items)); + ACTION_RETURN_BOOL(Grind(self, items)); } bool AActor::CallGrind(bool items) @@ -1295,7 +1349,7 @@ bool AActor::CallGrind(bool items) VMCall(func, params, 2, &ret, 1); return !!retv; } - return Grind(items); + return false; } //============================================================================ @@ -1334,6 +1388,100 @@ bool AActor::Massacre () return false; } +//---------------------------------------------------------------------------- +// +// Serialize DActorModelData +// +//---------------------------------------------------------------------------- + +void SerializeModelID(FSerializer &arc, const char *key, int &id) +{ // TODO: make it a proper serializable type (FModelID) instead of an int + if(arc.isWriting()) + { + if(id >= 0) + { + arc(key, Models[id]->mFilePath); + } + } + else + { + if(arc.HasKey(key)) + { + std::pair modelFile; + arc(key, modelFile); + + id = FindModel(modelFile.first.GetChars(), modelFile.second.GetChars(), true); + } + else + { + id = -1; + } + } +} + +FSerializer &Serialize(FSerializer &arc, const char *key, ModelOverride &mo, ModelOverride *def) +{ + arc.BeginObject(key); + SerializeModelID(arc, "model", mo.modelID); + arc("surfaceSkinIDs", mo.surfaceSkinIDs); + arc.EndObject(); + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, AnimModelOverride &amo, AnimModelOverride *def) +{ + int ok = arc.BeginObject(key); + if(arc.isReading() && !ok) + { + amo.id = -1; + } + else if(ok) + { + SerializeModelID(arc, "model", amo.id); + arc.EndObject(); + } + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def) +{ + arc.BeginObject(key); + arc("firstFrame", ao.firstFrame); + arc("lastFrame", ao.lastFrame); + arc("loopFrame", ao.loopFrame); + arc("startFrame", ao.startFrame); + arc("flags", ao.flags); + arc("framerate", ao.framerate); + arc("startTic", ao.startTic); + arc("switchOffset", ao.switchOffset); + arc.EndObject(); + return arc; +} + +void DActorModelData::Serialize(FSerializer& arc) +{ + Super::Serialize(arc); + arc("modelDef", modelDef) + ("models", models) + ("skinIDs", skinIDs) + ("animationIDs", animationIDs) + ("modelFrameGenerators", modelFrameGenerators) + ("flags", flags) + ("overrideFlagsSet", overrideFlagsSet) + ("overrideFlagsClear", overrideFlagsClear) + ("curAnim", curAnim) + ("prevAnim", prevAnim); +} + +void DActorModelData::OnDestroy() +{ + models.Reset(); + modelFrameGenerators.Reset(); + skinIDs.Reset(); + //surfaceSkinIDs.Reset(); + animationIDs.Reset(); +} + //---------------------------------------------------------------------------- // // PROC P_ExplodeMissile @@ -1435,7 +1583,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target, bool onsky, FNa } // play the sound before changing the state, so that AActor::OnDestroy can call S_RelinkSounds on it and the death state can override it. - if (mo->DeathSound) + if (mo->DeathSound.isvalid()) { S_Sound (mo, CHAN_VOICE, 0, mo->DeathSound, 1, (mo->flags3 & MF3_FULLVOLDEATH) ? ATTN_NONE : ATTN_NORM); @@ -1503,7 +1651,7 @@ void AActor::PlayBounceSound(bool onfloor) { S_Sound (this, CHAN_VOICE, 0, SeeSound, 1, ATTN_IDLE); } - else if (onfloor || WallBounceSound <= 0) + else if (onfloor || !WallBounceSound.isvalid()) { S_Sound (this, CHAN_VOICE, 0, BounceSound, 1, ATTN_IDLE); } @@ -1523,6 +1671,17 @@ void AActor::PlayBounceSound(bool onfloor) bool AActor::FloorBounceMissile (secplane_t &plane) { + if (flags & MF_MISSILE) + { + switch (SpecialBounceHit(nullptr, nullptr, &plane)) + { + // This one is backwards for some reason... + case 1: return false; + case 0: return true; + default: break; + } + } + // [ZZ] if bouncing missile hits a damageable sector(plane), it dies if (P_ProjectileHitPlane(this, -1) && bouncecount > 0) { @@ -1599,7 +1758,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane) flags &= ~MF_INBOUNCE; return false; } - else Vel.Z *= bouncefactor; + else Vel.Z *= GetMBFBounceFactor(this); } else // Don't run through this for MBF-style bounces { @@ -1648,12 +1807,12 @@ bool AActor::FloorBounceMissile (secplane_t &plane) // //---------------------------------------------------------------------------- -int P_FaceMobj (AActor *source, AActor *target, DAngle *delta) +static int P_FaceMobj (AActor *source, AActor *target, DAngle *delta) { DAngle diff; diff = deltaangle(source->Angles.Yaw, source->AngleTo(target)); - if (diff > 0) + if (diff > nullAngle) { *delta = diff; return 1; @@ -1679,6 +1838,7 @@ bool AActor::CanSeek(AActor *target) const if ((flags2 & MF2_DONTSEEKINVISIBLE) && ((target->flags & MF_SHADOW) || (target->renderflags & RF_INVISIBLE) || + (target->flags8 & MF8_MINVISIBLE) || !target->RenderStyle.IsVisible(target->Alpha) ) ) return false; @@ -1701,7 +1861,7 @@ DEFINE_ACTION_FUNCTION(AActor, CanSeek) // //---------------------------------------------------------------------------- -bool P_SeekerMissile (AActor *actor, double thresh, double turnMax, bool precise, bool usecurspeed) +bool P_SeekerMissile (AActor *actor, DAngle thresh, DAngle turnMax, bool precise, bool usecurspeed) { int dir; DAngle delta; @@ -1756,10 +1916,10 @@ bool P_SeekerMissile (AActor *actor, double thresh, double turnMax, bool precise } else { - DAngle pitch = 0.; + DAngle pitch = nullAngle; if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { // Need to seek vertically - double dist = MAX(1., actor->Distance2D(target)); + double dist = max(1., actor->Distance2D(target)); // Aim at a player's eyes and at the middle of the actor for everything else. double aimheight = target->Height/2; if (target->player) @@ -1783,7 +1943,7 @@ bool P_SeekerMissile (AActor *actor, double thresh, double turnMax, bool precise #define STOPSPEED (0x1000/65536.) #define CARRYSTOPSPEED ((0x1000*32/3)/65536.) -double P_XYMovement (AActor *mo, DVector2 scroll) +static double P_XYMovement (AActor *mo, DVector2 scroll) { static int pushtime = 0; bool bForceSlide = !scroll.isZero(); @@ -1806,16 +1966,16 @@ double P_XYMovement (AActor *mo, DVector2 scroll) switch (special) { case 40: case 41: case 42: // Wind_East - mo->Thrust(0., windTab[special-40]); + mo->Thrust(DAngle::fromDeg(0.), windTab[special-40]); break; case 43: case 44: case 45: // Wind_North - mo->Thrust(90., windTab[special-43]); + mo->Thrust(DAngle::fromDeg(90.), windTab[special-43]); break; case 46: case 47: case 48: // Wind_South - mo->Thrust(270., windTab[special-46]); + mo->Thrust(DAngle::fromDeg(270.), windTab[special-46]); break; case 49: case 50: case 51: // Wind_West - mo->Thrust(180., windTab[special-49]); + mo->Thrust(DAngle::fromDeg(180.), windTab[special-49]); break; } } @@ -1834,7 +1994,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) // preserve the direction instead of clamping x and y independently. double cx = mo->Vel.X == 0 ? 1. : clamp(mo->Vel.X, -maxmove, maxmove) / mo->Vel.X; double cy = mo->Vel.Y == 0 ? 1. : clamp(mo->Vel.Y, -maxmove, maxmove) / mo->Vel.Y; - double fac = MIN(cx, cy); + double fac = min(cx, cy); mo->Vel.X *= fac; mo->Vel.Y *= fac; @@ -1844,7 +2004,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) { mo->Vel.MakeResize(VELOCITY_THRESHOLD); } - move = mo->Vel; + move = mo->Vel.XY(); // [RH] Carrying sectors didn't work with low speeds in BOOM. This is // because BOOM relied on the speed being fast enough to accumulate // despite friction. If the speed is too low, then its movement will get @@ -1930,7 +2090,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) // because it also calls P_CheckSlopeWalk on its clipped steps. DVector2 onestep = startmove / steps; - start = mo->Pos(); + start = mo->Pos().XY(); step = 1; totalsteps = steps; @@ -1955,7 +2115,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) ptry = start + move * step / steps; - DVector2 startvel = mo->Vel; + DVector2 startvel = mo->Vel.XY(); // killough 3/15/98: Allow objects to drop off // [RH] If walking on a slope, stay on the slope @@ -1963,7 +2123,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) { // blocked move AActor *BlockingMobj = mo->BlockingMobj; - line_t *BlockingLine = mo->BlockingLine; + line_t *BlockingLine = mo->MovementBlockingLine = mo->BlockingLine; // [ZZ] if (!BlockingLine && !BlockingMobj) // hit floor or ceiling while XY movement - sector actions @@ -1995,7 +2155,9 @@ double P_XYMovement (AActor *mo, DVector2 scroll) (mo->player->cmd.ucmd.forwardmove | mo->player->cmd.ucmd.sidemove) && mo->BlockingLine->sidedef[1] != NULL) { - mo->Vel.Z = WATER_JUMP_SPEED; + double spd = mo->FloatVar(NAME_WaterClimbSpeed); + if (fabs(spd) >= EQUAL_EPSILON) + mo->Vel.Z = spd; } // If the blocked move executed any push specials that changed the // actor's velocity, do not attempt to slide. @@ -2007,7 +2169,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) // If the move is done a second time (because it was too fast for one move), it // is still clipped against the wall at its full speed, so you effectively // execute two moves in one tic. - P_SlideMove (mo, mo->Vel, 1); + P_SlideMove (mo, mo->Vel.XY(), 1); } else { @@ -2021,7 +2183,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) { if (!player || !(mo->Level->i_compatflags & COMPATF_WALLRUN)) { - move = mo->Vel; + move = mo->Vel.XY(); onestep = move / steps; P_CheckSlopeWalk (mo, move); } @@ -2038,7 +2200,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) DVector2 t; t.X = 0, t.Y = onestep.Y; walkplane = P_CheckSlopeWalk (mo, t); - if (P_TryMove (mo, mo->Pos() + t, true, walkplane, tm)) + if (P_TryMove (mo, mo->Pos().XY() + t, true, walkplane, tm)) { mo->Vel.X = 0; } @@ -2046,7 +2208,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll) { t.X = onestep.X, t.Y = 0; walkplane = P_CheckSlopeWalk (mo, t); - if (P_TryMove (mo, mo->Pos() + t, true, walkplane, tm)) + if (P_TryMove (mo, mo->Pos().XY() + t, true, walkplane, tm)) { mo->Vel.Y = 0; } @@ -2089,57 +2251,11 @@ double P_XYMovement (AActor *mo, DVector2 scroll) return Oldfloorz; } } - if (BlockingMobj && (BlockingMobj->flags2 & MF2_REFLECTIVE)) + if (BlockingMobj && P_ReflectOffActor(mo, BlockingMobj)) { - bool seeker = (mo->flags2 & MF2_SEEKERMISSILE) ? true : false; - // Don't change the angle if there's THRUREFLECT on the monster. - if (!(BlockingMobj->flags7 & MF7_THRUREFLECT)) - { - DAngle angle = BlockingMobj->AngleTo(mo); - bool dontReflect = (mo->AdjustReflectionAngle(BlockingMobj, angle)); - // Change angle for deflection/reflection - - if (!dontReflect) - { - bool tg = (mo->target != NULL); - bool blockingtg = (BlockingMobj->target != NULL); - if ((BlockingMobj->flags7 & MF7_AIMREFLECT) && (tg | blockingtg)) - { - AActor *origin = tg ? mo->target : BlockingMobj->target; - - //dest->x - source->x - DVector3 vect = mo->Vec3To(origin); - vect.Z += origin->Height / 2; - mo->Vel = vect.Resized(mo->Speed); - } - else - { - if ((BlockingMobj->flags7 & MF7_MIRRORREFLECT) && (tg | blockingtg)) - { - mo->Angles.Yaw += 180.; - mo->Vel *= -.5; - } - else - { - mo->Angles.Yaw = angle; - mo->VelFromAngle(mo->Speed / 2); - mo->Vel.Z *= -.5; - } - } - } - else - { - goto explode; - } - } - if (mo->flags2 & MF2_SEEKERMISSILE) - { - mo->tracer = mo->target; - } - mo->target = BlockingMobj; return Oldfloorz; } -explode: + // explode a missile bool onsky = false; if (tm.ceilingline && tm.ceilingline->hitSkyWall(mo)) @@ -2198,12 +2314,12 @@ double P_XYMovement (AActor *mo, DVector2 scroll) // For that we need to adjust the start point, and the movement vector. DAngle anglediff = deltaangle(oldangle, mo->Angles.Yaw); - if (anglediff != 0) + if (anglediff != nullAngle) { move = move.Rotated(anglediff); oldangle = mo->Angles.Yaw; } - start = mo->Pos() - move * step / steps; + start = mo->Pos().XY() - move * step / steps; } } } @@ -2334,13 +2450,13 @@ double P_XYMovement (AActor *mo, DVector2 scroll) return Oldfloorz; } -// Move this to p_inter *** -void P_MonsterFallingDamage (AActor *mo) + +static void P_MonsterFallingDamage (AActor *mo) { int damage; double vel; - if (!(mo->Level->flags2 & LEVEL2_MONSTERFALLINGDAMAGE)) + if (!(mo->Level->flags2 & LEVEL2_MONSTERFALLINGDAMAGE) && !(mo->flags8 & MF8_FALLDAMAGE)) return; if (mo->floorsector->Flags & SECF_NOFALLINGDAMAGE) return; @@ -2354,7 +2470,7 @@ void P_MonsterFallingDamage (AActor *mo) { damage = int((vel - 23)*6); } - damage = TELEFRAG_DAMAGE; // always kill 'em + if (!(mo->Level->flags3 & LEVEL3_PROPERMONSTERFALLINGDAMAGE)) damage = TELEFRAG_DAMAGE; P_DamageMobj (mo, NULL, NULL, damage, NAME_Falling); } @@ -2362,7 +2478,7 @@ void P_MonsterFallingDamage (AActor *mo) // P_ZMovement // -void P_ZMovement (AActor *mo, double oldfloorz) +static void P_ZMovement (AActor *mo, double oldfloorz) { double dist; double delta; @@ -2380,84 +2496,7 @@ void P_ZMovement (AActor *mo, double oldfloorz) mo->AddZ(mo->Vel.Z); -// -// apply gravity -// - if (mo->Z() > mo->floorz && !(mo->flags & MF_NOGRAVITY)) - { - double startvelz = mo->Vel.Z; - - if (mo->waterlevel == 0 || (mo->player && - !(mo->player->cmd.ucmd.forwardmove | mo->player->cmd.ucmd.sidemove))) - { - // [RH] Double gravity only if running off a ledge. Coming down from - // an upward thrust (e.g. a jump) should not double it. - if (mo->Vel.Z == 0 && oldfloorz > mo->floorz && mo->Z() == oldfloorz) - { - mo->Vel.Z -= grav + grav; - } - else - { - mo->Vel.Z -= grav; - } - } - if (mo->player == NULL) - { - if (mo->waterlevel >= 1) - { - double sinkspeed; - - if ((mo->flags & MF_SPECIAL) && !(mo->flags3 & MF3_ISMONSTER)) - { // Pickup items don't sink if placed and drop slowly if dropped - sinkspeed = (mo->flags & MF_DROPPED) ? -WATER_SINK_SPEED / 8 : 0; - } - else - { - sinkspeed = -WATER_SINK_SPEED; - - // If it's not a player, scale sinkspeed by its mass, with - // 100 being equivalent to a player. - if (mo->player == NULL) - { - sinkspeed = sinkspeed * clamp(mo->Mass, 1, 4000) / 100; - } - } - if (mo->Vel.Z < sinkspeed) - { // Dropping too fast, so slow down toward sinkspeed. - mo->Vel.Z -= MAX(sinkspeed*2, -8.); - if (mo->Vel.Z > sinkspeed) - { - mo->Vel.Z = sinkspeed; - } - } - else if (mo->Vel.Z > sinkspeed) - { // Dropping too slow/going up, so trend toward sinkspeed. - mo->Vel.Z = startvelz + MAX(sinkspeed/3, -8.); - if (mo->Vel.Z < sinkspeed) - { - mo->Vel.Z = sinkspeed; - } - } - } - } - else - { - if (mo->waterlevel > 1) - { - double sinkspeed = -WATER_SINK_SPEED; - - if (mo->Vel.Z < sinkspeed) - { - mo->Vel.Z = (startvelz < sinkspeed) ? startvelz : sinkspeed; - } - else - { - mo->Vel.Z = startvelz + ((mo->Vel.Z - startvelz) * - (mo->waterlevel == 1 ? WATER_SINK_SMALL_FACTOR : WATER_SINK_FACTOR)); - } - } - } - } + mo->CallFallAndSink(grav, oldfloorz); // Hexen compatibility handling for floatbobbing. Ugh... // Hexen yanked all items to the floor, except those being spawned at map start in the air. @@ -2486,9 +2525,12 @@ void P_ZMovement (AActor *mo, double oldfloorz) } if (mo->player && (mo->flags & MF_NOGRAVITY) && (mo->Z() > mo->floorz)) { - if (!mo->IsNoClip2()) + FBaseCVar* const fViewBobCvar = G_GetUserCVar(int(mo->player - players),"FViewBob"); + bool const fViewBob = fViewBobCvar->GetGenericRep(fViewBobCvar->GetRealType()).Bool; + + if (!mo->IsNoClip2() && fViewBob) { - mo->AddZ(DAngle(360 / 80.f * mo->Level->maptime).Sin() / 8); + mo->AddZ(DAngle::fromDeg(360 / 80.f * mo->Level->maptime).Sin() / 8 * mo->FloatVar(NAME_FlyBob)); } if (!(mo->flags8 & MF8_NOFRICTION)) @@ -2542,7 +2584,7 @@ void P_ZMovement (AActor *mo, double oldfloorz) if (mo->BounceFlags & BOUNCE_Floors) { mo->FloorBounceMissile (mo->floorsector->floorplane); - /* if (!(mo->flags6 & MF6_CANJUMP)) */ return; + /* if (!CanJump(mo)) */ return; } else if (mo->flags3 & MF3_NOEXPLODEFLOOR) { @@ -2589,11 +2631,9 @@ void P_ZMovement (AActor *mo, double oldfloorz) mo->SetZ(mo->floorz); if (mo->Vel.Z < 0) { - const double minvel = -8; // landing speed from a jump with normal gravity - // Spawn splashes, etc. P_HitFloor (mo); - if (mo->DamageType == NAME_Ice && mo->Vel.Z < minvel) + if (mo->DamageType == NAME_Ice && mo->Vel.Z < mo->LandingSpeed) { mo->tics = 1; mo->Vel.Zero(); @@ -2606,11 +2646,11 @@ void P_ZMovement (AActor *mo, double oldfloorz) } if (mo->player) { - if (mo->player->jumpTics < 0 || mo->Vel.Z < minvel) + if (mo->player->jumpTics < 0 || mo->Vel.Z < mo->LandingSpeed) { // delay any jumping for a short while mo->player->jumpTics = 7; } - if (mo->Vel.Z < minvel && !(mo->flags & MF_NOGRAVITY)) + if (mo->Vel.Z < mo->LandingSpeed && !(mo->flags & MF_NOGRAVITY)) { // Squat down. // Decrease viewheight for a moment after hitting the ground (hard), @@ -2651,7 +2691,7 @@ void P_ZMovement (AActor *mo, double oldfloorz) if (mo->BounceFlags & BOUNCE_Ceilings) { // ceiling bounce mo->FloorBounceMissile (mo->ceilingsector->ceilingplane); - /*if (!(mo->flags6 & MF6_CANJUMP))*/ return; + /* if (!CanJump(mo)) */ return; } if (mo->flags & MF_SKULLFLY) { // the skull slammed into something @@ -2762,45 +2802,144 @@ DEFINE_ACTION_FUNCTION(AActor, CheckFakeFloorTriggers) // //=========================================================================== -static void PlayerLandedOnThing (AActor *mo, AActor *onmobj) +static void PlayerLandedMakeGruntSound(AActor* self, AActor *onmobj) { - bool grunted; - - if (!mo->player) - return; + IFVIRTUALPTR(self, AActor, PlayerLandedMakeGruntSound) + { + VMValue params[2] = { self, onmobj }; + VMCall(func, params, 2, nullptr, 0); + } +} - if (mo->player->mo == mo) +static void PlayerSquatView(AActor *self, AActor *onmobj) +{ + IFVIRTUALPTR(self, AActor, PlayerSquatView) { - mo->player->deltaviewheight = mo->Vel.Z / 8.; + VMValue params[2] = { self, onmobj }; + VMCall(func, params, 2, nullptr, 0); } +} + +static void PlayerLandedOnThing (AActor *mo, AActor *onmobj) +{ + PlayerSquatView(mo, onmobj); if (mo->player->cheats & CF_PREDICTING) return; P_FallingDamage (mo); - // [RH] only make noise if alive - if (mo->health > 0 && !mo->player->morphTics) + PlayerLandedMakeGruntSound(mo, onmobj); + +// mo->player->centering = true; +} + +//========================================================================== +// +// AActor :: FallAndSink +// +//========================================================================== + +void AActor::FallAndSink(double grav, double oldfloorz) +{ + if (Z() > floorz && !(flags & MF_NOGRAVITY)) { - grunted = false; - // Why should this number vary by gravity? - if (mo->Vel.Z < -mo->player->mo->FloatVar(NAME_GruntSpeed)) + double startvelz = Vel.Z; + + if (waterlevel == 0 || (player && + !(player->cmd.ucmd.forwardmove | player->cmd.ucmd.sidemove))) { - S_Sound (mo, CHAN_VOICE, 0, "*grunt", 1, ATTN_NORM); - grunted = true; + // [RH] Double gravity only if running off a ledge. Coming down from + // an upward thrust (e.g. a jump) should not double it. + if (Vel.Z == 0 && oldfloorz > floorz && Z() == oldfloorz) + { + Vel.Z -= grav + grav; + } + else + { + Vel.Z -= grav; + } } - if (onmobj != NULL || !Terrains[P_GetThingFloorType (mo)].IsLiquid) + if (player == NULL) { - if (!grunted || !S_AreSoundsEquivalent (mo, "*grunt", "*land")) + if (waterlevel >= 1) { - S_Sound (mo, CHAN_AUTO, 0, "*land", 1, ATTN_NORM); + double sinkspeed; + + if ((flags & MF_SPECIAL) && !(flags3 & MF3_ISMONSTER)) + { // Pickup items don't sink if placed and drop slowly if dropped + sinkspeed = (flags & MF_DROPPED) ? -WATER_SINK_SPEED / 8 : 0; + } + else + { + sinkspeed = -WATER_SINK_SPEED; + + // If it's not a player, scale sinkspeed by its mass, with + // 100 being equivalent to a player. + if (player == NULL) + { + sinkspeed = sinkspeed * clamp(Mass, 1, 4000) / 100; + } + } + if (Vel.Z < sinkspeed) + { // Dropping too fast, so slow down toward sinkspeed. + Vel.Z -= max(sinkspeed * 2, -8.); + if (Vel.Z > sinkspeed) + { + Vel.Z = sinkspeed; + } + } + else if (Vel.Z > sinkspeed) + { // Dropping too slow/going up, so trend toward sinkspeed. + Vel.Z = startvelz + max(sinkspeed / 3, -8.); + if (Vel.Z < sinkspeed) + { + Vel.Z = sinkspeed; + } + } + } + } + else + { + if (waterlevel > 1) + { + double sinkspeed = -WATER_SINK_SPEED; + + if (Vel.Z < sinkspeed) + { + Vel.Z = (startvelz < sinkspeed) ? startvelz : sinkspeed; + } + else + { + Vel.Z = startvelz + ((Vel.Z - startvelz) * + (waterlevel == 1 ? WATER_SINK_SMALL_FACTOR : WATER_SINK_FACTOR)); + } } } } -// mo->player->centering = true; } +DEFINE_ACTION_FUNCTION(AActor, FallAndSink) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(grav); + PARAM_FLOAT(oldfloorz); + self->FallAndSink(grav, oldfloorz); + return 0; +} +void AActor::CallFallAndSink(double grav, double oldfloorz) +{ + IFVIRTUAL(AActor, FallAndSink) + { + VMValue params[3] = { (DObject*)this, grav, oldfloorz }; + VMCall(func, params, 3, nullptr, 0); + } + else + { + FallAndSink(grav, oldfloorz); + } +} // // P_NightmareRespawn @@ -2864,7 +3003,7 @@ void P_NightmareRespawn (AActor *mobj) } // something is occupying its position? - if (!P_CheckPosition(mo, mo->Pos(), true)) + if (!P_CheckPosition(mo, mo->Pos().XY(), true)) { //[GrafZahl] MF_COUNTKILL still needs to be checked here. mo->ClearCounters(); @@ -2878,7 +3017,7 @@ void P_NightmareRespawn (AActor *mobj) mo->SpawnPoint = mobj->SpawnPoint; mo->SpawnAngle = mobj->SpawnAngle; mo->SpawnFlags = mobj->SpawnFlags & ~MTF_DORMANT; // It wasn't dormant when it died, so it's not dormant now, either. - mo->Angles.Yaw = (double)mobj->SpawnAngle; + mo->Angles.Yaw = DAngle::fromDeg(mobj->SpawnAngle); mo->HandleSpawnFlags (); mo->reactiontime = 18; @@ -2893,7 +3032,7 @@ void P_NightmareRespawn (AActor *mobj) P_SpawnTeleportFog(mobj, mobj->Pos(), true, true); // spawn a teleport fog at the new spot - P_SpawnTeleportFog(mobj, DVector3(mobj->SpawnPoint, z), false, true); + P_SpawnTeleportFog(mobj, DVector3(mobj->SpawnPoint.XY(), z), false, true); // remove the old monster mobj->Destroy (); @@ -3120,6 +3259,12 @@ DEFINE_ACTION_FUNCTION(AActor, Howl) bool AActor::Slam (AActor *thing) { + if ((flags8 & MF8_ONLYSLAMSOLID) + && !(thing->flags & MF_SOLID) && !(thing->flags & MF_SHOOTABLE)) + { + return true; + } + flags &= ~MF_SKULLFLY; Vel.Zero(); if (health > 0) @@ -3132,8 +3277,13 @@ bool AActor::Slam (AActor *thing) // The charging monster may have died by the target's actions here. if (health > 0) { - if (SeeState != NULL && !(flags8 & MF8_RETARGETAFTERSLAM)) SetState (SeeState); - else SetIdle(); + FState *slam = FindState(NAME_Slam); + if (slam != NULL) + SetState(slam); + else if (SeeState != NULL && !(flags8 & MF8_RETARGETAFTERSLAM)) + SetState (SeeState); + else + SetIdle(); } } else @@ -3184,6 +3334,21 @@ int AActor::SpecialMissileHit (AActor *victim) else return -1; } +// This virtual method only exists on the script side. +int AActor::SpecialBounceHit(AActor* bounceMobj, line_t* bounceLine, secplane_t* bouncePlane) +{ + IFVIRTUAL(AActor, SpecialBounceHit) + { + VMValue params[4] = { (DObject*)this, bounceMobj, bounceLine, bouncePlane }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + VMCall(func, params, 4, &ret, 1); + return retval; + } + else return -1; +} + bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) { if (flags2 & MF2_DONTREFLECT) return true; @@ -3192,28 +3357,26 @@ bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) if (thing->flags4&MF4_SHIELDREFLECT) { // Shield reflection (from the Centaur) - if (absangle(angle, thing->Angles.Yaw) > 45) + if ((flags7 & MF7_NOSHIELDREFLECT) || absangle(angle, thing->Angles.Yaw) > DAngle::fromDeg(45)) return true; // Let missile explode - if (thing->flags7 & MF7_NOSHIELDREFLECT) return true; - if (pr_reflect () < 128) - angle += 45; + angle += DAngle::fromDeg(45); else - angle -= 45; + angle -= DAngle::fromDeg(45); } else if (thing->flags4&MF4_DEFLECT) { // deflect (like the Heresiarch) if(pr_reflect() < 128) - angle += 45; + angle += DAngle::fromDeg(45); else - angle -= 45; + angle -= DAngle::fromDeg(45); } else { - angle += ((pr_reflect() % 16) - 8); + angle += DAngle::fromDeg((pr_reflect() % 16) - 8); } //Always check for AIMREFLECT, no matter what else is checked above. if (thing->flags7 & MF7_AIMREFLECT) @@ -3233,8 +3396,11 @@ bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) int AActor::AbsorbDamage(int damage, FName dmgtype, AActor *inflictor, AActor *source, int flags) { - for (AActor *item = Inventory; item != nullptr; item = item->Inventory) + AActor *next; + for (AActor *item = Inventory; item != nullptr; item = next) { + // [Player701] Remember the next item now in case the current item is destroyed later + next = item->Inventory; IFVIRTUALPTRNAME(item, NAME_Inventory, AbsorbDamage) { VMValue params[7] = { item, damage, dmgtype.GetIndex(), &damage, inflictor, source, flags }; @@ -3265,7 +3431,7 @@ void AActor::AlterWeaponSprite(visstyle_t *vis) void AActor::PlayActiveSound () { - if (ActiveSound && !S_IsActorPlayingSomething (this, CHAN_VOICE, -1)) + if (ActiveSound.isvalid() && !S_IsActorPlayingSomething(this, CHAN_VOICE)) { S_Sound (this, CHAN_VOICE, 0, ActiveSound, 1, (flags3 & MF3_FULLVOLACTIVE) ? ATTN_NONE : ATTN_IDLE); @@ -3279,6 +3445,22 @@ DEFINE_ACTION_FUNCTION(AActor, PlayActiveSound) return 0; } +void AActor::PlayPushSound() +{ + FSoundID push = SoundVar(NAME_PushSound); + if (!S_IsActorPlayingSomething(this, CHAN_BODY, push)) + { + S_Sound(this, CHAN_BODY, 0, push, 1, ATTN_NORM); + } +} + +DEFINE_ACTION_FUNCTION(AActor, PlayPushSound) +{ + PARAM_SELF_PROLOGUE(AActor); + self->PlayPushSound(); + return 0; +} + bool AActor::IsOkayToAttack (AActor *link) { // Standard things to eliminate: an actor shouldn't attack itself, @@ -3294,7 +3476,7 @@ bool AActor::IsOkayToAttack (AActor *link) // its target; and for a summoned minion, its tracer. AActor * Friend; if (flags5 & MF5_SUMMONEDMONSTER) Friend = tracer; - else if (flags2 & MF2_SEEKERMISSILE) Friend = target; + else if (flags & MF_MISSILE) Friend = target; else if ((flags & MF_FRIENDLY) && FriendPlayer) Friend = Level->Players[FriendPlayer-1]->mo; else Friend = this; @@ -3313,11 +3495,11 @@ bool AActor::IsOkayToAttack (AActor *link) if (P_CheckSight (this, link)) { // AMageStaffFX2::IsOkayToAttack had an extra check here, generalized with a flag, - // to only allow the check to succeed if the enemy was in a ~84� FOV of the player + // to only allow the check to succeed if the enemy was in a ~84 FOV of the player if (flags3 & MF3_SCREENSEEKER) { DAngle angle = absangle(Friend->AngleTo(link), Friend->Angles.Yaw); - if (angle < 30 * (256./360.)) + if (angle < DAngle::fromDeg(30 * (256./360.))) { return true; } @@ -3348,54 +3530,165 @@ DEFINE_ACTION_FUNCTION(AActor, SetShade) return 0; } -void AActor::SetPitch(DAngle p, bool interpolate, bool forceclamp) +// [MC] Helper function for Set(View)Pitch. +DAngle AActor::ClampPitch(DAngle p) +{ + // clamp the pitch we set + DAngle min, max; + + if (player != nullptr) + { + min = player->MinPitch; + max = player->MaxPitch; + } + else + { + min = DAngle::fromDeg(-89.); + max = DAngle::fromDeg(89.); + } + p = clamp(p, min, max); + return p; +} + +void AActor::SetPitch(DAngle p, int fflags) { - if (player != NULL || forceclamp) - { // clamp the pitch we set - DAngle min, max; + if (player != nullptr || (fflags & SPF_FORCECLAMP)) + { + p = ClampPitch(p); + } - if (player != NULL) + if (p != Angles.Pitch) + { + if (player != nullptr) { - min = player->MinPitch; - max = player->MaxPitch; + if (fflags & SPF_SCALEDNOLERP) + { + player->angleOffsetTargets.Pitch = deltaangle(Angles.Pitch, p); + player->cheats |= CF_SCALEDNOLERP; + } + else + { + Angles.Pitch = p; + if (fflags & SPF_INTERPOLATE) + player->cheats |= CF_INTERPVIEW; + } } else { - min = -89.; - max = 89.; + Angles.Pitch = p; } - p = clamp(p, min, max); } - if (p != Angles.Pitch) + +} + +void AActor::SetAngle(DAngle ang, int fflags) +{ + if (ang != Angles.Yaw) { - Angles.Pitch = p; - if (player != NULL && interpolate) + if (player != nullptr) + { + if (fflags & SPF_SCALEDNOLERP) + { + player->angleOffsetTargets.Yaw = deltaangle(Angles.Yaw, ang); + player->cheats |= CF_SCALEDNOLERP; + } + else + { + Angles.Yaw = ang; + if (fflags & SPF_INTERPOLATE) + player->cheats |= CF_INTERPVIEW; + } + } + else { - player->cheats |= CF_INTERPVIEW; + Angles.Yaw = ang; } } + } -void AActor::SetAngle(DAngle ang, bool interpolate) +void AActor::SetRoll(DAngle r, int fflags) { - if (ang != Angles.Yaw) + if (r != Angles.Roll) { - Angles.Yaw = ang; - if (player != NULL && interpolate) + if (player != nullptr) + { + if (fflags & SPF_SCALEDNOLERP) + { + player->angleOffsetTargets.Roll = deltaangle(Angles.Roll, r); + player->cheats |= CF_SCALEDNOLERP; + } + else + { + Angles.Roll = r; + if (fflags & SPF_INTERPOLATE) + player->cheats |= CF_INTERPVIEW; + } + } + else { - player->cheats |= CF_INTERPVIEW; + Angles.Roll = r; } } } -void AActor::SetRoll(DAngle r, bool interpolate) +void AActor::SetViewPitch(DAngle p, int fflags) { - if (r != Angles.Roll) + if (player != NULL || (fflags & SPF_FORCECLAMP)) + { + p = ClampPitch(p); + } + + if (p != ViewAngles.Pitch) { - Angles.Roll = r; - if (player != NULL && interpolate) + ViewAngles.Pitch = p; + if (player != nullptr && (fflags & SPF_INTERPOLATE)) { - player->cheats |= CF_INTERPVIEW; + player->cheats |= CF_INTERPVIEWANGLES; + } + } + +} + +void AActor::SetViewAngle(DAngle ang, int fflags) +{ + if (ang != ViewAngles.Yaw) + { + ViewAngles.Yaw = ang; + if (player != nullptr && (fflags & SPF_INTERPOLATE)) + { + player->cheats |= CF_INTERPVIEWANGLES; + } + } + +} + +double AActor::GetFOV(double ticFrac) +{ + double fov; + if (player) + { + if (player->cheats & CF_NOFOVINTERP) + return player->FOV; + + fov = player->FOV; + } + else + { + fov = CameraFOV; + } + + return PrevFOV.Degrees() * (1 - ticFrac) + fov * ticFrac; +} + +void AActor::SetViewRoll(DAngle r, int fflags) +{ + if (r != ViewAngles.Roll) + { + ViewAngles.Roll = r; + if (player != nullptr && (fflags & SPF_INTERPOLATE)) + { + player->cheats |= CF_INTERPVIEWANGLES; } } } @@ -3518,6 +3811,30 @@ void AActor::Tick () static const uint8_t HereticScrollDirs[4] = { 6, 9, 1, 4 }; static const uint8_t HereticSpeedMuls[5] = { 5, 10, 25, 30, 35 }; + // Check for Actor unmorphing, but only on the thing that is the morphed Actor. + // Players do their own special checking for this. + if (alternative != nullptr && player == nullptr) + { + if (flags & MF_UNMORPHED) + return; + + int res = false; + IFVIRTUAL(AActor, CheckUnmorph) + { + VMValue params[] = { this }; + VMReturn ret[] = { &res }; + VMCall(func, params, 1, ret, 1); + } + + if (res) + return; + } + + if (freezetics > 0) + { + freezetics--; + return; + } AActor *onmo; @@ -3544,6 +3861,12 @@ void AActor::Tick () { special2++; } + + if(flags9 & MF9_DECOUPLEDANIMATIONS && modelData && !(modelData->curAnim.flags & ANIMOVERRIDE_NONE)) + { + modelData->curAnim.startTic += 1; + } + return; } @@ -3560,7 +3883,8 @@ void AActor::Tick () } else { - + if (player) + player->crossingPortal = false; if (!player || !(player->cheats & CF_PREDICTING)) { // Handle powerup effects here so that the order is controlled @@ -3590,6 +3914,12 @@ void AActor::Tick () { special2++; } + + if(flags9 & MF9_DECOUPLEDANIMATIONS && modelData && !(modelData->curAnim.flags & ANIMOVERRIDE_NONE)) + { + modelData->curAnim.startTic += 1; + } + return; } @@ -3787,7 +4117,7 @@ void AActor::Tick () { // Strife scroll special int anglespeed = Level->GetFirstSectorTag(sec) - 100; double carryspeed = (anglespeed % 10) / (16 * CARRYFACTOR); - DAngle angle = ((anglespeed / 10) * 45.); + DAngle angle = DAngle::fromDeg(((anglespeed / 10) * 45.)); scrollv += angle.ToVector(carryspeed); } } @@ -3850,18 +4180,18 @@ void AActor::Tick () // Check 3D floors as well floorplane = P_FindFloorPlane(floorsector, PosAtZ(floorz)); - if (floorplane.fC() < STEEPSLOPE && + if (floorplane.fC() < MaxSlopeSteepness && floorplane.ZatPoint (PosRelative(floorsector)) <= floorz) { const msecnode_t *node; bool dopush = true; - if (floorplane.fC() > STEEPSLOPE*2/3) + if (floorplane.fC() > MaxSlopeSteepness*2/3) { for (node = touching_sectorlist; node; node = node->m_tnext) { const sector_t *sec = node->m_sector; - if (sec->floorplane.fC() >= STEEPSLOPE) + if (sec->floorplane.fC() >= MaxSlopeSteepness) { if (floorplane.ZatPoint(PosRelative(node->m_sector)) >= Z() - MaxStepHeight) { @@ -3890,6 +4220,7 @@ void AActor::Tick () // Handle X and Y velocities BlockingMobj = nullptr; + MovementBlockingLine = nullptr; sector_t* oldBlockingCeiling = BlockingCeiling; sector_t* oldBlockingFloor = BlockingFloor; Blocking3DFloor = nullptr; @@ -3973,6 +4304,7 @@ void AActor::Tick () // to be in line with the case when an actor's side is hit. if (!res && (flags & MF_MISSILE)) { + P_DoMissileDamage(this, onmo); P_ExplodeMissile(this, nullptr, onmo); } } @@ -4012,7 +4344,7 @@ void AActor::Tick () // Check for poison damage, but only once per PoisonPeriod tics (or once per second if none). if (PoisonDurationReceived && (Level->time % (PoisonPeriodReceived ? PoisonPeriodReceived : TICRATE) == 0)) { - P_DamageMobj(this, NULL, Poisoner, PoisonDamageReceived, PoisonDamageTypeReceived ? PoisonDamageTypeReceived : (FName)NAME_Poison, 0); + P_DamageMobj(this, NULL, Poisoner, PoisonDamageReceived, PoisonDamageTypeReceived != NAME_None ? PoisonDamageTypeReceived : (FName)NAME_Poison, 0); --PoisonDurationReceived; @@ -4030,12 +4362,20 @@ void AActor::Tick () } if (!CheckNoDelay()) return; // freed itself - // cycle through states, calling action functions at transitions UpdateRenderSectorList(); + if (Sector->Flags & SECF_KILLMONSTERS && Z() == floorz && + player == nullptr && (flags & MF_SHOOTABLE) && !(flags & MF_FLOAT)) + { + P_DamageMobj(this, nullptr, nullptr, TELEFRAG_DAMAGE, NAME_InstantDeath); + // must have been removed + if (ObjectFlags & OF_EuthanizeMe) return; + } + if (tics != -1) { + // cycle through states, calling action functions at transitions // [RH] Use tics <= 0 instead of == 0 so that spawnstates // of 0 tics work as expected. if (--tics <= 0) @@ -4159,102 +4499,136 @@ void AActor::CheckSectorTransition(sector_t *oldsec) //========================================================================== // -// AActor::SplashCheck +// UpdateWaterDepth // -// Returns true if actor should splash +// Updates the actor's current waterlevel and waterdepth. +// Consolidates common code in UpdateWaterLevel and SplashCheck. +// +// Returns the floor height used for the depth check, or -FLT_MAX +// if the actor wasn't in a sector. // //========================================================================== -void AActor::SplashCheck() +static double UpdateWaterDepth(AActor* actor, bool splash) { double fh = -FLT_MAX; bool reset = false; - waterlevel = 0; + actor->waterlevel = 0; + actor->waterdepth = 0; - if (Sector == NULL) + if (actor->Sector == NULL) { - return; + return fh; } - if (Sector->MoreFlags & SECMF_UNDERWATER) // intentionally not SECMF_UNDERWATERMASK + if (actor->Sector->MoreFlags & SECMF_UNDERWATER) // intentionally not SECMF_UNDERWATERMASK { - waterlevel = 3; + actor->waterdepth = actor->Height; } else { - const sector_t *hsec = Sector->GetHeightSec(); + const sector_t *hsec = actor->Sector->GetHeightSec(); if (hsec != NULL) { - fh = hsec->floorplane.ZatPoint(this); - //if (hsec->MoreFlags & SECMF_UNDERWATERMASK) // also check Boom-style non-swimmable sectors + fh = hsec->floorplane.ZatPoint(actor); + + // splash checks also check Boom-style non-swimmable sectors + // as well as non-solid, visible 3D floors (below) + if (splash || hsec->MoreFlags & SECMF_UNDERWATERMASK) { - if (Z() < fh) - { - waterlevel = 1; - if (Center() < fh) - { - waterlevel = 2; - if ((player && Z() + player->viewheight <= fh) || - (Top() <= fh)) - { - waterlevel = 3; - } - } - } - else if (!(hsec->MoreFlags & SECMF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint(this))) - { - waterlevel = 3; - } - else + actor->waterdepth = fh - actor->Z(); + + if (actor->waterdepth <= 0 && !(hsec->MoreFlags & SECMF_FAKEFLOORONLY) && (actor->Top() > hsec->ceilingplane.ZatPoint(actor))) { - waterlevel = 0; + actor->waterdepth = actor->Height; } } } else { // Check 3D floors as well! - for (auto rover : Sector->e->XFloor.ffloors) + for (auto rover : actor->Sector->e->XFloor.ffloors) { if (!(rover->flags & FF_EXISTS)) continue; if (rover->flags & FF_SOLID) continue; bool reset = !(rover->flags & FF_SWIMMABLE); - if (reset && rover->alpha == 0) continue; - double ff_bottom = rover->bottom.plane->ZatPoint(this); - double ff_top = rover->top.plane->ZatPoint(this); + if (splash) { reset &= rover->alpha == 0; } + if (reset) continue; - if (ff_top <= Z() || ff_bottom > (Center())) continue; + double ff_bottom = rover->bottom.plane->ZatPoint(actor); + double ff_top = rover->top.plane->ZatPoint(actor); - fh = ff_top; - if (Z() < fh) - { - waterlevel = 1; - if (Center() < fh) - { - waterlevel = 2; - if ((player && Z() + player->viewheight <= fh) || - (Top() <= fh)) - { - waterlevel = 3; - } - } - } + if (ff_top <= actor->Z() || ff_bottom > actor->Center()) continue; + fh = ff_top; + actor->waterdepth = ff_top - actor->Z(); break; } } } - // some additional checks to make deep sectors like Boom's splash without setting - // the water flags. - if (boomwaterlevel == 0 && waterlevel != 0) + if (actor->waterdepth < 0) { actor->waterdepth = 0; } + + if (actor->waterdepth > (actor->Height / 2)) + { + // When noclipping around and going from low to high sector, your view height + // can go negative, which is why this is nested inside here + if ((actor->player && (actor->waterdepth >= actor->player->viewheight)) || (actor->waterdepth >= actor->Height)) + { + actor->waterlevel = 3; + } + else + { + actor->waterlevel = 2; + } + } + else if (actor->waterdepth > 0) + { + actor->waterlevel = 1; + } + + return fh; +} + +//========================================================================== +// +// AActor::SplashCheck +// +// Returns true if actor should splash +// +//========================================================================== + +void AActor::SplashCheck() +{ + double fh = UpdateWaterDepth(this, true); + + // some additional checks to make deep sectors like Boom's splash without setting + // the water flags. + if (boomwaterlevel == 0 && waterlevel != 0) + { + P_HitWater(this, Sector, PosAtZ(fh), true); + } + boomwaterlevel = waterlevel; + return; +} + +//========================================================================== +// +// AActor::PlayDiveOrSurfaceSounds +// +// Plays diving or surfacing sounds for the player +// +//========================================================================== + +void AActor::PlayDiveOrSurfaceSounds(int oldlevel) +{ + IFVIRTUAL(AActor, PlayDiveOrSurfaceSounds) { - P_HitWater(this, Sector, PosAtZ(fh), true); + VMValue params[2] = { (DObject *)this, oldlevel }; + VMCall(func, params, 2, nullptr, 0); } - boomwaterlevel = waterlevel; - return; } //========================================================================== @@ -4270,103 +4644,19 @@ bool AActor::UpdateWaterLevel(bool dosplash) int oldlevel = waterlevel; if (dosplash) SplashCheck(); + UpdateWaterDepth(this, false); - double fh = -FLT_MAX; - bool reset = false; - - waterlevel = 0; + // Play surfacing and diving sounds, as appropriate. + // + // (used to be that this code was wrapped around a "Sector != nullptr" check, + // but actors should always be within a sector, and besides, this is just + // sound stuff) - if (Sector != nullptr) + if (player != nullptr) { - if (Sector->MoreFlags & SECMF_UNDERWATER) // intentionally not SECMF_UNDERWATERMASK - { - waterlevel = 3; - } - else - { - const sector_t *hsec = Sector->GetHeightSec(); - if (hsec != NULL) - { - fh = hsec->floorplane.ZatPoint(this); - if (hsec->MoreFlags & SECMF_UNDERWATERMASK) // also check Boom-style non-swimmable sectors - { - if (Z() < fh) - { - waterlevel = 1; - if (Center() < fh) - { - waterlevel = 2; - if ((player && Z() + player->viewheight <= fh) || - (Top() <= fh)) - { - waterlevel = 3; - } - } - } - else if (!(hsec->MoreFlags & SECMF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint(this))) - { - waterlevel = 3; - } - else - { - waterlevel = 0; - } - } - } - else - { - // Check 3D floors as well! - for (auto rover : Sector->e->XFloor.ffloors) - { - if (!(rover->flags & FF_EXISTS)) continue; - if (rover->flags & FF_SOLID) continue; - if (!(rover->flags & FF_SWIMMABLE)) continue; - - double ff_bottom = rover->bottom.plane->ZatPoint(this); - double ff_top = rover->top.plane->ZatPoint(this); - - if (ff_top <= Z() || ff_bottom > (Center())) continue; - - fh = ff_top; - if (Z() < fh) - { - waterlevel = 1; - if (Center() < fh) - { - waterlevel = 2; - if ((player && Z() + player->viewheight <= fh) || - (Top() <= fh)) - { - waterlevel = 3; - } - } - } - - break; - } - } - } - - // Play surfacing and diving sounds, as appropriate. - if (player != nullptr) - { - if (oldlevel < 3 && waterlevel == 3) - { - // Our head just went under. - S_Sound(this, CHAN_VOICE, 0, "*dive", 1, ATTN_NORM); - } - else if (oldlevel == 3 && waterlevel < 3) - { - // Our head just came up. - if (player->air_finished > Level->maptime) - { - // We hadn't run out of air yet. - S_Sound(this, CHAN_VOICE, 0, "*surface", 1, ATTN_NORM); - } - // If we were running out of air, then ResetAirSupply() will play *gasp. - } - } + PlayDiveOrSurfaceSounds(oldlevel); } + return false; // we did the splash ourselves } @@ -4410,7 +4700,8 @@ void ConstructActor(AActor *actor, const DVector3 &pos, bool SpawningMapThing) FRandom &rng = Level->BotInfo.m_Thinking ? pr_botspawnmobj : pr_spawnmobj; - if (actor->isFast() && actor->flags3 & MF3_ISMONSTER) + if ((!!G_SkillProperty(SKILLP_InstantReaction) || actor->flags5 & MF5_ALWAYSFAST || !!(dmflags & DF_INSTANT_REACTION)) + && actor->flags3 & MF3_ISMONSTER) actor->reactiontime = 0; if (actor->flags3 & MF3_ISMONSTER) @@ -4440,6 +4731,7 @@ void ConstructActor(AActor *actor, const DVector3 &pos, bool SpawningMapThing) // set subsector and/or block links actor->LinkToWorld (nullptr, SpawningMapThing); actor->ClearInterpolation(); + actor->ClearFOVInterpolation(); actor->dropoffz = actor->floorz = actor->Sector->floorplane.ZatPoint(pos); actor->ceilingz = actor->Sector->ceilingplane.ZatPoint(pos); @@ -4534,7 +4826,7 @@ void ConstructActor(AActor *actor, const DVector3 &pos, bool SpawningMapThing) return; } } - if (Level->flags & LEVEL_NOALLIES && !actor->player) + if (Level->flags & LEVEL_NOALLIES && !actor->IsKindOf(NAME_PlayerPawn)) { actor->flags &= ~MF_FRIENDLY; } @@ -4564,6 +4856,12 @@ AActor *AActor::StaticSpawn(FLevelLocals *Level, PClassActor *type, const DVecto { I_Error("Tried to spawn a class-less actor\n"); } + else if (type->bAbstract) + { + // [Player701] Abstract actors cannot be spawned by any means + Printf("Attempt to spawn an instance of abstract actor class %s\n", type->TypeName.GetChars()); + return nullptr; + } if (allowreplacement) { @@ -4573,6 +4871,7 @@ AActor *AActor::StaticSpawn(FLevelLocals *Level, PClassActor *type, const DVecto AActor *actor; actor = static_cast(Level->CreateThinker(type)); + actor->EnableNetworking(true); ConstructActor(actor, pos, SpawningMapThing); return actor; @@ -4661,6 +4960,19 @@ void AActor::HandleSpawnFlags () Level->total_secrets++; } } + if (SpawnFlags & MTF_NOCOUNT) + { + if (flags & MF_COUNTKILL) + { + flags &= ~MF_COUNTKILL; + Level->total_monsters--; + } + if (flags & MF_COUNTITEM) + { + flags &= ~MF_COUNTITEM; + Level->total_items--; + } + } } DEFINE_ACTION_FUNCTION(AActor, HandleSpawnFlags) @@ -4704,7 +5016,11 @@ void AActor::PostBeginPlay () { PrevAngles = Angles; flags7 |= MF7_HANDLENODELAY; - flags8 |= MF8_RECREATELIGHTS; + if (GetInfo()->LightAssociations.Size() || (state && state->Light > 0)) + { + flags8 |= MF8_RECREATELIGHTS; + Level->flags3 |= LEVEL3_LIGHTCREATED; + } } void AActor::CallPostBeginPlay() @@ -4824,6 +5140,16 @@ void AActor::CallDeactivate(AActor *activator) void AActor::OnDestroy () { + // If the Actor is leaving behind a premorph Actor, make sure it gets cleaned up as + // well so it's not stuck in the map. + if (alternative != nullptr && !(flags & MF_UNMORPHED)) + { + alternative->ClearCounters(); + alternative->alternative = nullptr; + alternative->Destroy(); + alternative = nullptr; + } + // [ZZ] call destroy event hook. // note that this differs from ThingSpawned in that you can actually override OnDestroy to avoid calling the hook. // but you can't really do that without utterly breaking the game, so it's ok. @@ -4838,7 +5164,7 @@ void AActor::OnDestroy () ClearRenderLineList(); // [RH] Destroy any inventory this actor is carrying - DestroyAllInventory (); + DestroyAllInventory (this); // [RH] Unlink from tid chain RemoveFromHash (); @@ -4847,6 +5173,12 @@ void AActor::OnDestroy () UnlinkFromWorld (nullptr); flags |= MF_NOSECTOR|MF_NOBLOCKMAP; + if (ViewPos != nullptr) + { + ViewPos->Destroy(); + ViewPos = nullptr; + } + // Transform any playing sound into positioned, non-actor sounds. S_RelinkSound (this, NULL); @@ -4870,22 +5202,37 @@ void AActor::AdjustFloorClip () double shallowestclip = INT_MAX; const msecnode_t *m; - // possibly standing on a 3D-floor - if (Sector->e->XFloor.ffloors.Size() && Z() > Sector->floorplane.ZatPoint(this)) Floorclip = 0; - // [RH] clip based on shallowest floor player is standing on // If the sector has a deep water effect, then let that effect // do the floorclipping instead of the terrain type. for (m = touching_sectorlist; m; m = m->m_tnext) { DVector3 pos = PosRelative(m->m_sector); - sector_t *hsec = m->m_sector->GetHeightSec(); - if (hsec == NULL && m->m_sector->floorplane.ZatPoint (pos) == Z()) + sector_t* hsec = m->m_sector->GetHeightSec(); + if (hsec == NULL) { - double clip = Terrains[m->m_sector->GetTerrain(sector_t::floor)].FootClip; - if (clip < shallowestclip) + if (m->m_sector->floorplane.ZatPoint(pos) == Z()) + { + double clip = Terrains[m->m_sector->GetTerrain(sector_t::floor)].FootClip; + if (clip < shallowestclip) + { + shallowestclip = clip; + } + } + else { - shallowestclip = clip; + for (auto& ff : m->m_sector->e->XFloor.ffloors) + { + if ((ff->flags & FF_SOLID) && (ff->flags & FF_EXISTS) && ff->top.plane->ZatPoint(pos) == Z()) + { + double clip = Terrains[ff->top.model->GetTerrain(ff->top.isceiling)].FootClip; + if (clip < shallowestclip) + { + shallowestclip = clip; + } + } + } + } } } @@ -4922,29 +5269,204 @@ EXTERN_CVAR(Float, fov) extern bool demonew; -AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) +//========================================================================== +// +// This function is only designed for swapping player pawns +// over to their new ones upon changing levels or respawning. It SHOULD NOT be +// used for anything else! Do not export this functionality as it's +// meant strictly for internal usage. +// +//========================================================================== + +void PlayerPointerSubstitution(AActor* oldPlayer, AActor* newPlayer, bool removeOld) { - player_t *p; - AActor *mobj, *oldactor; - uint8_t state; - DVector3 spawn; - DAngle SpawnAngle; + if (oldPlayer == nullptr || newPlayer == nullptr || oldPlayer == newPlayer + || !oldPlayer->IsKindOf(NAME_PlayerPawn) || !newPlayer->IsKindOf(NAME_PlayerPawn)) + { + return; + } - if (mthing == NULL) + // Go through player infos. + for (int i = 0; i < MAXPLAYERS; ++i) { - return NULL; + if (!oldPlayer->Level->PlayerInGame(i)) + continue; + + auto p = oldPlayer->Level->Players[i]; + + if (p->mo == oldPlayer) + p->mo = newPlayer; + if (p->poisoner == oldPlayer) + p->poisoner = newPlayer; + if (p->attacker == oldPlayer) + p->attacker = newPlayer; + if (p->camera == oldPlayer) + p->camera = newPlayer; + if (p->ConversationNPC == oldPlayer) + p->ConversationNPC = newPlayer; + if (p->ConversationPC == oldPlayer) + p->ConversationPC = newPlayer; } - // not playing? - if ((unsigned)playernum >= (unsigned)MAXPLAYERS || !PlayerInGame(playernum) ) - return NULL; - // Old lerp data needs to go - if (playernum == consoleplayer) + // Go through sectors. + for (auto& sec : oldPlayer->Level->sectors) { - P_PredictionLerpReset(); + if (sec.SoundTarget == oldPlayer) + sec.SoundTarget = newPlayer; } - p = Players[playernum]; + // Update all the remaining object pointers. + for (DObject* probe = GC::Root; probe != nullptr; probe = probe->ObjNext) + probe->PointerSubstitution(oldPlayer, newPlayer, removeOld); +} + +//========================================================================== +// +// This has some extra barriers compared to PlayerPointerSubstitution to allow +// Actors to freely morph into other Actors which is its main usage. +// It also allows morphing to be more extendable from ZScript. +// +//========================================================================== + +int MorphPointerSubstitution(AActor* from, AActor* to) +{ + // Special care is taken here to make sure things marked as a dummy Actor for a morphed thing aren't + // allowed to be changed into other things. Anything being morphed into that's considered a player + // is automatically out of the question to ensure modders aren't swapping clients around. + if (from == nullptr || to == nullptr || from == to || to->player != nullptr + || (from->flags & MF_UNMORPHED) // Another thing's dummy Actor, unmorphing the wrong way, etc. + || (from->alternative == nullptr && to->alternative != nullptr) // Morphing into something that's already morphed. + || (from->alternative != nullptr && from->alternative != to)) // Only allow something morphed to unmorph. + { + return false; + } + + const bool toIsPlayer = to->IsKindOf(NAME_PlayerPawn); + if (from->IsKindOf(NAME_PlayerPawn)) + { + // Players are only allowed to turn into other valid player pawns. For + // valid pawns, make sure an actual player is changing into an empty one. + // Voodoo dolls aren't allowed to morph since that should be passed to + // the main player directly. + if (!toIsPlayer || from->player == nullptr || from->player->mo != from) + return false; + } + else if (toIsPlayer || from->player != nullptr + || (from->IsKindOf(NAME_Inventory) && from->PointerVar(NAME_Owner) != nullptr) + || (to->IsKindOf(NAME_Inventory) && to->PointerVar(NAME_Owner) != nullptr)) + { + // Only allow items to be swapped around if they aren't currently owned. Also prevent non-players from + // turning into fake players. + return false; + } + + // [MC] Had to move this here since ObtainInventory was also moved as well. Should be called + // before any transference of items since that's what was intended when introduced. + if (!from->alternative) // Morphing into + { + { + IFVIRTUALPTR(from, AActor, PreMorph) + { + VMValue params[] = { from, to, false }; + VMCall(func, params, 3, nullptr, 0); + } + } + { + IFVIRTUALPTR(to, AActor, PreMorph) + { + VMValue params[] = { to, from, true }; + VMCall(func, params, 3, nullptr, 0); + } + } + } + else // Unmorphing back + { + { + IFVIRTUALPTR(from, AActor, PreUnmorph) + { + VMValue params[] = { from, to, false }; + VMCall(func, params, 3, nullptr, 0); + } + } + { + IFVIRTUALPTR(to, AActor, PreUnmorph) + { + VMValue params[] = { to, from, true }; + VMCall(func, params, 3, nullptr, 0); + } + } + } + // Since the check is good, move the inventory items over. This should always be done when + // morphing to emulate Heretic/Hexen's behavior since those stored the inventory in their + // player structs. + IFVM(Actor, ObtainInventory) + { + VMValue params[] = { to, from }; + VMCall(func, params, 2, nullptr, 0); + } + + // Go through player infos. + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (!from->Level->PlayerInGame(i)) + continue; + + auto p = from->Level->Players[i]; + + if (p->mo == from) + p->mo = to; + if (p->poisoner == from) + p->poisoner = to; + if (p->attacker == from) + p->attacker = to; + if (p->camera == from) + p->camera = to; + if (p->ConversationNPC == from) + p->ConversationNPC = to; + if (p->ConversationPC == from) + p->ConversationPC = to; + } + + // Go through sectors. + for (auto& sec : from->Level->sectors) + { + if (sec.SoundTarget == from) + sec.SoundTarget = to; + } + + // Replace any object pointers that are safe to swap around. + for (DObject* probe = GC::Root; probe != nullptr; probe = probe->ObjNext) + probe->PointerSubstitution(from, to, false); + + // Remaining maintenance related to morphing. + if (from->player != nullptr) + { + to->player = from->player; + from->player = nullptr; + + // Swap the new body into the right network slot if it's a client (this doesn't + // really matter for regular Actors since they grab any ID they can get anyway). + NetworkEntityManager::SetClientNetworkEntity(to, to->player - players); + } + + if (from->alternative != nullptr) + { + to->flags &= ~MF_UNMORPHED; + to->alternative = from->alternative = nullptr; + } + else + { + from->flags |= MF_UNMORPHED; + from->alternative = to; + to->alternative = from; + } + + return true; +} + +void FLevelLocals::PlayerSpawnPickClass (int playernum) +{ + auto p = Players[playernum]; if (p->cls == NULL) { @@ -4973,6 +5495,33 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag } p->cls = PlayerClasses[p->CurrentPlayerClass].Type; } +} + +AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) +{ + player_t *p; + AActor *mobj, *oldactor; + uint8_t state; + DVector3 spawn; + DAngle SpawnAngle; + + if (mthing == NULL) + { + return NULL; + } + // not playing? + if ((unsigned)playernum >= (unsigned)MAXPLAYERS || !PlayerInGame(playernum) ) + return NULL; + + // Old lerp data needs to go + if (playernum == consoleplayer) + { + P_PredictionLerpReset(); + } + + p = Players[playernum]; + + PlayerSpawnPickClass(playernum); if (( dmflags2 & DF2_SAME_SPAWN_SPOT ) && ( p->playerstate == PST_REBORN ) && @@ -4992,10 +5541,10 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag spawn.Y = mthing->pos.Y; // Allow full angular precision - SpawnAngle = (double)mthing->angle; + SpawnAngle = DAngle::fromDeg(mthing->angle); if (i_compatflags2 & COMPATF2_BADANGLES) { - SpawnAngle += 0.01; + SpawnAngle += DAngle::fromDeg(0.01); } if (GetDefaultByType(p->cls)->flags & MF_SPAWNCEILING) @@ -5022,6 +5571,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag p->mo = mobj; mobj->player = p; state = p->playerstate; + const auto heldWeap = state == PST_REBORN && (dmflags3 & DF3_REMEMBER_LAST_WEAP) ? p->ReadyWeapon : nullptr; if (state == PST_REBORN || state == PST_ENTER) { PlayerReborn (playernum); @@ -5038,7 +5588,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag } // [GRB] Reset skin - p->userinfo.SkinNumChanged(R_FindSkin (Skins[p->userinfo.GetSkin()].Name, p->CurrentPlayerClass)); + p->userinfo.SkinNumChanged(R_FindSkin (Skins[p->userinfo.GetSkin()].Name.GetChars(), p->CurrentPlayerClass)); if (!(mobj->flags2 & MF2_DONTTRANSLATE)) { @@ -5050,7 +5600,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag } mobj->Angles.Yaw = SpawnAngle; - mobj->Angles.Pitch = mobj->Angles.Roll = 0.; + mobj->Angles.Pitch = mobj->Angles.Roll = nullAngle; mobj->health = p->health; // [RH] Set player sprite based on skin @@ -5080,7 +5630,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag p->lastkilltime = 0; p->BlendR = p->BlendG = p->BlendB = p->BlendA = 0.f; p->Uncrouch(); - p->MinPitch = p->MaxPitch = 0.; // will be filled in by PostBeginPlay()/netcode + p->MinPitch = p->MaxPitch = nullAngle; // will be filled in by PostBeginPlay()/netcode p->MUSINFOactor = nullptr; p->MUSINFOtics = -1; p->Vel.Zero(); // killough 10/98: initialize bobbing to 0. @@ -5122,14 +5672,14 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag { // Special inventory handling for respawning in coop IFVM(PlayerPawn, FilterCoopRespawnInventory) { - VMValue params[] = { p->mo, oldactor }; + VMValue params[] = { p->mo, oldactor, ((heldWeap == nullptr || (heldWeap->ObjectFlags & OF_EuthanizeMe)) ? nullptr : heldWeap) }; VMCall(func, params, 2, nullptr, 0); } } if (oldactor != NULL) { // Remove any inventory left from the old actor. Coop handles // it above, but the other modes don't. - oldactor->DestroyAllInventory(); + DestroyAllInventory(oldactor); } // [BC] Handle temporary invulnerability when respawned if (state == PST_REBORN || state == PST_ENTER) @@ -5164,6 +5714,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag if (state == PST_ENTER || (state == PST_LIVE && !savegamerestore)) { Behaviors.StartTypedScripts (SCRIPT_Enter, p->mo, true); + localEventManager->PlayerSpawned(PlayerNum(p)); } else if (state == PST_REBORN) { @@ -5184,7 +5735,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag if (sec.SoundTarget == oldactor) sec.SoundTarget = nullptr; } - DObject::StaticPointerSubstitution (oldactor, p->mo); + PlayerPointerSubstitution (oldactor, p->mo, false); localEventManager->PlayerRespawned(PlayerNum(p)); Behaviors.StartTypedScripts (SCRIPT_Respawn, p->mo, true); @@ -5193,7 +5744,6 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag return mobj; } - // // P_SpawnMapThing // The fields of the mapthing should @@ -5206,6 +5756,8 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) int mask; AActor *mobj; + bool spawnmulti = G_SkillProperty(SKILLP_SpawnMulti) || !!(dmflags2 & DF2_ALWAYS_SPAWN_MULTI); + if (mthing->EdNum == 0 || mthing->EdNum == -1) return NULL; @@ -5285,6 +5837,10 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) { mask = MTF_COOPERATIVE; } + else if (spawnmulti) + { + mask = MTF_COOPERATIVE|MTF_SINGLE; + } else { mask = MTF_SINGLE; @@ -5414,9 +5970,27 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) const AActor *info = GetDefaultByType (i); - // don't spawn keycards and players in deathmatch - if (deathmatch && info->flags & MF_NOTDMATCH) - return NULL; + // Don't spawn keycards and players in deathmatch. + if (deathmatch && (info->flags & MF_NOTDMATCH)) + return nullptr; + + // Don't spawn extra things in co-op if desired. + if (multiplayer && !deathmatch) + { + // Don't spawn DM-only things in co-op. + if ((dmflags2 & DF2_NO_COOP_THING_SPAWN) && (mthing->flags & (MTF_DEATHMATCH|MTF_SINGLE)) == MTF_DEATHMATCH) + return nullptr; + // Having co-op only functionality is a bit odd, but you never know. + if (!mthing->special && !mthing->thingid && (mthing->flags & (MTF_COOPERATIVE | MTF_SINGLE)) == MTF_COOPERATIVE) + { + // Don't spawn co-op only things in general. + if (dmflags3 & DF3_NO_COOP_ONLY_THINGS) + return nullptr; + // Don't spawn co-op only items. + if ((dmflags3 & DF3_NO_COOP_ONLY_ITEMS) && i->IsDescendantOf(NAME_Inventory)) + return nullptr; + } + } // [RH] don't spawn extra weapons in coop if so desired if (multiplayer && !deathmatch && (dmflags & DF_NO_COOP_WEAPON_SPAWN)) @@ -5454,7 +6028,7 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) else sz = ONFLOORZ; - mobj = AActor::StaticSpawn (this, i, DVector3(mthing->pos, sz), NO_REPLACE, true); + mobj = AActor::StaticSpawn (this, i, DVector3(mthing->pos.XY(), sz), NO_REPLACE, true); if (sz == ONFLOORZ) { @@ -5467,6 +6041,11 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) else if (sz == ONCEILINGZ) mobj->AddZ(-mthing->pos.Z); + if (mobj->flags2 & MF2_FLOORCLIP) + { + mobj->AdjustFloorClip(); + } + mobj->SpawnPoint = mthing->pos; mobj->SpawnAngle = mthing->angle; mobj->SpawnFlags = mthing->flags; @@ -5498,7 +6077,7 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) // [RH] Add ThingID to mobj and link it in with the others mobj->SetTID(mthing->thingid); - mobj->PrevAngles.Yaw = mobj->Angles.Yaw = (double)mthing->angle; + mobj->PrevAngles.Yaw = mobj->Angles.Yaw = DAngle::fromDeg(mthing->angle); // Check if this actor's mapthing has a conversation defined if (mthing->Conversation > 0) @@ -5522,9 +6101,9 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) if (mthing->Scale.Y != 0) mobj->Scale.Y = mthing->Scale.Y * mobj->Scale.Y; if (mthing->pitch) - mobj->Angles.Pitch = (double)mthing->pitch; + mobj->Angles.Pitch = DAngle::fromDeg(mthing->pitch); if (mthing->roll) - mobj->Angles.Roll = (double)mthing->roll; + mobj->Angles.Roll = DAngle::fromDeg(mthing->roll); if (mthing->score) mobj->Score = mthing->score; if (mthing->fillcolor) @@ -5536,7 +6115,7 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) { if (mthing->arg0str != NAME_None) { - PalEntry color = V_GetColor(nullptr, mthing->arg0str); + PalEntry color = V_GetColor(mthing->arg0str.GetChars()); mobj->args[0] = color.r; mobj->args[1] = color.g; mobj->args[2] = color.b; @@ -5550,8 +6129,8 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) if (mobj->IntVar(NAME_lightflags) & LF_SPOT) { - mobj->AngleVar(NAME_SpotInnerAngle) = double(mthing->args[1]); - mobj->AngleVar(NAME_SpotOuterAngle) = double(mthing->args[2]); + mobj->AngleVar(NAME_SpotInnerAngle) = DAngle::fromDeg(mthing->args[1]); + mobj->AngleVar(NAME_SpotOuterAngle) = DAngle::fromDeg(mthing->args[2]); } } @@ -5566,7 +6145,12 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position) else mobj->health = -int(mthing->Health); if (mthing->Health == 0) - mobj->CallDie(NULL, NULL); + { + // We cannot call 'Die' here directly because the level is not yet fully set up. + // This needs to be delayed by one tic. + auto state = mobj->FindState(NAME_DieFromSpawn); + if (state) mobj->SetState(state, true); + } else if (mthing->Health != 1) mobj->StartHealth = mobj->health; @@ -5634,7 +6218,7 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 puff->target = source; // Angle is the opposite of the hit direction (i.e. the puff faces the source.) - puff->Angles.Yaw = hitdir + 180; + puff->Angles.Yaw = hitdir + DAngle::fromDeg(180); // If a puff has a crash state and an actor was not hit, // it will enter the crash state. This is used by the StrifeSpark @@ -5667,11 +6251,11 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 if (cl_pufftype == 1) puff->renderflags |= RF_INVISIBLE; } - if ((flags & PF_HITTHING) && puff->SeeSound) + if ((flags & PF_HITTHING) && puff->SeeSound.isvalid()) { // Hit thing sound S_Sound (puff, CHAN_BODY, 0, puff->SeeSound, 1, ATTN_NORM); } - else if (puff->AttackSound) + else if (puff->AttackSound.isvalid()) { S_Sound (puff, CHAN_BODY, 0, puff->AttackSound, 1, ATTN_NORM); } @@ -5838,7 +6422,7 @@ void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle) } if (bloodtype >= 1) { - P_DrawSplash2 (originator->Level, 40, pos, hitangle-180., 2, originator->BloodColor); + P_DrawSplash2 (originator->Level, 40, pos, hitangle - DAngle::fromDeg(180.), 2, originator->BloodColor); } } @@ -5879,7 +6463,7 @@ void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle) } if (bloodtype >= 1) { - P_DrawSplash2(originator->Level, 40, pos + add, hitangle - 180., 2, originator->BloodColor); + P_DrawSplash2(originator->Level, 40, pos + add, hitangle - DAngle::fromDeg(180.), 2, originator->BloodColor); } } @@ -5939,7 +6523,7 @@ void P_RipperBlood (AActor *mo, AActor *bleeder) } if (bloodtype >= 1) { - P_DrawSplash2(bleeder->Level, 28, pos, bleeder->AngleTo(mo) + 180., 0, bleeder->BloodColor); + P_DrawSplash2(bleeder->Level, 28, pos, bleeder->AngleTo(mo) + DAngle::fromDeg(180.), 0, bleeder->BloodColor); } } @@ -6071,6 +6655,7 @@ bool P_HitWater (AActor * thing, sector_t * sec, const DVector3 &pos, bool check if (smallsplash && splash->SmallSplash) { mo = Spawn(sec->Level, splash->SmallSplash, pos, ALLOW_REPLACE); + mo->target = thing; if (mo) mo->Floorclip += splash->SmallSplashClip; } else @@ -6092,6 +6677,7 @@ bool P_HitWater (AActor * thing, sector_t * sec, const DVector3 &pos, bool check if (splash->SplashBase) { mo = Spawn(sec->Level, splash->SplashBase, pos, ALLOW_REPLACE); + mo->target = thing; } if (thing->player && !splash->NoAlert && alert) { @@ -6252,7 +6838,7 @@ bool P_CheckMissileSpawn (AActor* th, double maxdist) // killough 3/15/98: no dropoff (really = don't care for missiles) auto oldf2 = th->flags2; th->flags2 &= ~(MF2_MCROSS|MF2_PCROSS); // The following check is not supposed to activate missile triggers. - if (!(P_TryMove (th, newpos, false, NULL, tm, true))) + if (!(P_TryMove (th, newpos.XY(), false, NULL, tm, true))) { // [RH] Don't explode ripping missiles that spawn inside something if (th->BlockingMobj == NULL || !(th->flags2 & MF2_RIP) || (th->BlockingMobj->flags5 & MF5_DONTRIP)) @@ -6270,7 +6856,7 @@ bool P_CheckMissileSpawn (AActor* th, double maxdist) } else { - P_ExplodeMissile (th, NULL, th->BlockingMobj); + P_ExplodeMissile (th, th->BlockingLine, th->BlockingMobj); } return false; } @@ -6299,7 +6885,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckMissileSpawn) void P_PlaySpawnSound(AActor *missile, AActor *spawner) { - if (missile->SeeSound != 0) + if (missile->SeeSound != NO_SOUND) { if (!(missile->flags & MF_SPAWNSOUNDSOURCE)) { @@ -6361,7 +6947,7 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct if (dest == NULL) { - Printf ("P_SpawnMissilyXYZ: Tried to shoot %s from %s with no dest\n", + Printf ("P_SpawnMissileXYZ: Tried to shoot %s from %s with no destination\n", type->TypeName.GetChars(), source->GetClass()->TypeName.GetChars()); return NULL; } @@ -6400,21 +6986,8 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct } th->Vel = velocity.Resized(speed); - // invisible target: rotate velocity vector in 2D - // [RC] Now monsters can aim at invisible player as if they were fully visible. - if (dest->flags & MF_SHADOW && !(source->flags6 & MF6_SEEINVISIBLE)) - { - DAngle an = pr_spawnmissile.Random2() * (22.5 / 256); - double c = an.Cos(); - double s = an.Sin(); - - double newx = th->Vel.X * c - th->Vel.Y * s; - double newy = th->Vel.X * s + th->Vel.Y * c; - - th->Vel.X = newx; - th->Vel.Y = newy; - } - + P_SpawnMissileXYZ_ShadowHandling(source,dest,th,pos); + th->AngleFromVel(); if (th->flags4 & MF4_SPECTRAL) @@ -6491,7 +7064,7 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct th->VelFromAngle(); - double dist = source->DistanceBySpeed(dest, MAX(1., th->Speed)); + double dist = source->DistanceBySpeed(dest, max(1., th->Speed)); th->Vel.Z = (dest->Z() - source->Z()) / dist; if (th->flags4 & MF4_SPECTRAL) @@ -6522,24 +7095,6 @@ DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile) // //--------------------------------------------------------------------------- -AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, double vz) -{ - if (source == nullptr || type == nullptr) - { - return NULL; - } - return P_SpawnMissileAngleZSpeed (source, source->Z() + 32 + source->GetBobOffset(), type, angle, vz, GetDefaultSpeed (type)); -} - -AActor *P_SpawnMissileAngleZ (AActor *source, double z, PClassActor *type, DAngle angle, double vz) -{ - if (type == nullptr) - { - return nullptr; - } - return P_SpawnMissileAngleZSpeed (source, z, type, angle, vz, GetDefaultSpeed (type)); -} - AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActor *type) { if (source == nullptr || type == nullptr) @@ -6553,14 +7108,11 @@ AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActo an = source->Angles.Yaw; - if (dest->flags & MF_SHADOW) - { - an += pr_spawnmissile.Random2() * (16. / 360.); - } dist = source->Distance2D (dest); speed = GetDefaultSpeed (type); dist /= speed; vz = dist != 0 ? (dest->Z() - source->Z())/dist : speed; + an += P_SpawnMissileZAimed_ShadowHandling(source, dest, vz, speed, source->PosAtZ(z)); return P_SpawnMissileAngleZSpeed (source, z, type, an, vz, speed); } @@ -6685,13 +7237,14 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, { return nullptr; } + aimflags &= ~ALF_IGNORENOAUTOAIM; // just to be safe. static const double angdiff[3] = { -5.625, 5.625, 0 }; DAngle an = angle; DAngle pitch; FTranslatedLineTarget scratch; AActor *defaultobject = GetDefaultByType(type); - DAngle vrange = nofreeaim ? 35. : 0.; + DAngle vrange = DAngle::fromDeg(nofreeaim ? 35. : 0.); if (!pLineTarget) pLineTarget = &scratch; if (!(aimflags & ALF_NOWEAPONCHECK) && source->player && source->player->ReadyWeapon && ((source->player->ReadyWeapon->IntVar(NAME_WeaponFlags) & WIF_NOAUTOAIM) || noautoaim)) @@ -6711,7 +7264,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, int i = 2; do { - an = angle + angdiff[i]; + an = angle + DAngle::fromDeg(angdiff[i]); pitch = P_AimLineAttack (source, an, linetargetrange, pLineTarget, vrange, aimflags); if (source->player != NULL && @@ -6728,7 +7281,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, an = angle; if (nofreeaim || !source->Level->IsFreelookAllowed()) { - pitch = 0.; + pitch = nullAngle; } } } @@ -6782,7 +7335,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnPlayerMissile) PARAM_BOOL(noautoaim); PARAM_INT(aimflags); AActor *missileactor; - if (angle == 1e37) angle = self->Angles.Yaw; + if (angle == DAngle::fromDeg(1e37)) angle = self->Angles.Yaw; AActor *misl = P_SpawnPlayerMissile(self, x, y, z, type, angle, lt, &missileactor, nofreeaim, noautoaim, aimflags); if (numret > 0) ret[0].SetObject(misl); if (numret > 1) ret[1].SetObject(missileactor), numret = 2; @@ -7210,7 +7763,7 @@ const char *AActor::GetTag(const char *def) const const char *tag = Tag->GetChars(); if (tag[0] == '$') { - return GStrings(tag + 1); + return GStrings.GetString(tag + 1); } else { @@ -7233,6 +7786,19 @@ void AActor::SetTag(const char *def) else Tag = mStringPropertyData.Alloc(def); } +const char *AActor::GetCharacterName() const +{ + if (Conversation && Conversation->SpeakerName.Len() != 0) + { + const char *cname = Conversation->SpeakerName.GetChars(); + if (cname[0] == '$') + { + return GStrings.GetString(cname + 1); + } + else return cname; + } + return GetTag(); +} void AActor::ClearCounters() { @@ -7258,14 +7824,15 @@ void AActor::ClearCounters() int AActor::GetModifiedDamage(FName damagetype, int damage, bool passive, AActor *inflictor, AActor *source, int flags) { auto inv = Inventory; - while (inv != nullptr) + while (inv != nullptr && !(inv->ObjectFlags & OF_EuthanizeMe)) { + auto nextinv = inv->Inventory; IFVIRTUALPTRNAME(inv, NAME_Inventory, ModifyDamage) { - VMValue params[8] = { (DObject*)inv, damage, int(damagetype), &damage, passive, inflictor, source, flags }; + VMValue params[8] = { (DObject*)inv, damage, damagetype.GetIndex(), &damage, passive, inflictor, source, flags }; VMCall(func, params, 8, nullptr, 0); } - inv = inv->Inventory; + inv = nextinv; } return damage; } @@ -7291,8 +7858,8 @@ void AActor::SetTranslation(FName trname) return; } - int tnum = R_FindCustomTranslation(trname); - if (tnum >= 0) + auto tnum = R_FindCustomTranslation(trname); + if (tnum != INVALID_TRANSLATION) { Translation = tnum; } @@ -7309,7 +7876,7 @@ static FRandom pr_restore("RestorePos"); void AActor::RestoreSpecialPosition() { // Move item back to its original location - DVector2 sp = SpawnPoint; + DVector2 sp = SpawnPoint.XY(); FLinkContext ctx; UnlinkFromWorld(&ctx); @@ -7410,6 +7977,9 @@ void PrintMiscActorInfo(AActor *query) Printf("\n flags8: %x", query->flags8.GetValue()); for (flagi = 0; flagi <= 31; flagi++) if (query->flags8 & ActorFlags8::FromInt(1<flags9.GetValue()); + for (flagi = 0; flagi <= 31; flagi++) + if (query->flags9 & ActorFlags9::FromInt(1 << flagi)) Printf(" %s", FLAG_NAME(1 << flagi, flags9)); Printf("\nBounce flags: %x\nBounce factors: f:%f, w:%f", query->BounceFlags.GetValue(), query->bouncefactor, query->wallbouncefactor); diff --git a/src/playsim/p_pspr.cpp b/src/playsim/p_pspr.cpp index c282995e06c..923923420b3 100644 --- a/src/playsim/p_pspr.cpp +++ b/src/playsim/p_pspr.cpp @@ -36,10 +36,11 @@ #include "s_sound.h" #include "doomstat.h" #include "p_pspr.h" -#include "templates.h" + #include "g_level.h" #include "d_player.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "v_text.h" #include "cmdlib.h" #include "g_levellocals.h" @@ -89,7 +90,7 @@ enum EWRF_Options // [SO] 1=Weapons states are all 1 tick // 2=states with a function 1 tick, others 0 ticks. -CVAR(Int, sv_fastweapons, false, CVAR_SERVERINFO); +CVAR(Int, sv_fastweapons, 0, CVAR_SERVERINFO); // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -131,9 +132,21 @@ DEFINE_FIELD(DPSprite, x) DEFINE_FIELD(DPSprite, y) DEFINE_FIELD(DPSprite, oldx) DEFINE_FIELD(DPSprite, oldy) +DEFINE_FIELD(DPSprite, baseScale) +DEFINE_FIELD(DPSprite, pivot) +DEFINE_FIELD(DPSprite, scale) +DEFINE_FIELD(DPSprite, rotation) +DEFINE_FIELD_NAMED(DPSprite, Coord[0], Coord0) +DEFINE_FIELD_NAMED(DPSprite, Coord[1], Coord1) +DEFINE_FIELD_NAMED(DPSprite, Coord[2], Coord2) +DEFINE_FIELD_NAMED(DPSprite, Coord[3], Coord3) DEFINE_FIELD(DPSprite, firstTic) DEFINE_FIELD(DPSprite, Tics) +DEFINE_FIELD(DPSprite, Translation) +DEFINE_FIELD(DPSprite, HAlign) +DEFINE_FIELD(DPSprite, VAlign) DEFINE_FIELD(DPSprite, alpha) +DEFINE_FIELD(DPSprite, InterpolateTic) DEFINE_FIELD_BIT(DPSprite, Flags, bAddWeapon, PSPF_ADDWEAPON) DEFINE_FIELD_BIT(DPSprite, Flags, bAddBob, PSPF_ADDBOB) DEFINE_FIELD_BIT(DPSprite, Flags, bPowDouble, PSPF_POWDOUBLE) @@ -141,6 +154,8 @@ DEFINE_FIELD_BIT(DPSprite, Flags, bCVarFast, PSPF_CVARFAST) DEFINE_FIELD_BIT(DPSprite, Flags, bFlip, PSPF_FLIP) DEFINE_FIELD_BIT(DPSprite, Flags, bMirror, PSPF_MIRROR) DEFINE_FIELD_BIT(DPSprite, Flags, bPlayerTranslated, PSPF_PLAYERTRANSLATED) +DEFINE_FIELD_BIT(DPSprite, Flags, bPivotPercent, PSPF_PIVOTPERCENT) +DEFINE_FIELD_BIT(DPSprite, Flags, bInterpolate, PSPF_INTERPOLATE) //------------------------------------------------------------------------ // @@ -149,12 +164,15 @@ DEFINE_FIELD_BIT(DPSprite, Flags, bPlayerTranslated, PSPF_PLAYERTRANSLATED) //------------------------------------------------------------------------ DPSprite::DPSprite(player_t *owner, AActor *caller, int id) -: x(.0), y(.0), +: HAlign(0), + VAlign(0), + x(.0), y(.0), oldx(.0), oldy(.0), + InterpolateTic(false), firstTic(true), Tics(0), + Translation(NO_TRANSLATION), Flags(0), - Caller(caller), Owner(owner), State(nullptr), Sprite(0), @@ -162,6 +180,17 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id) ID(id), processPending(true) { + Caller = caller; + baseScale = {1.0, 1.2}; + rotation = nullAngle; + scale = {1.0, 1.0}; + pivot = {0.0, 0.0}; + for (int i = 0; i < 4; i++) + { + Coord[i] = DVector2(0, 0); + Prev.v[i] = Vert.v[i] = FVector2(0,0); + } + alpha = 1; Renderstyle = STYLE_Normal; @@ -189,7 +218,7 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id) Next->Destroy(); // Replace it. if (Caller->IsKindOf(NAME_Weapon) || Caller->IsKindOf(NAME_PlayerPawn)) - Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST); + Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST|PSPF_PIVOTPERCENT); } //------------------------------------------------------------------------ @@ -223,6 +252,26 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, FindPSprite) // the underscore is needed to } +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +static DPSprite *P_CreatePsprite(player_t *player, AActor *caller, int layer) +{ + DPSprite *pspr = Create(player, caller, layer); + + // [XA] apply WeaponScaleX/WeaponScaleY properties for weapon psprites + if (caller != nullptr && caller->IsKindOf(NAME_Weapon)) + { + pspr->baseScale.X = caller->FloatVar(NAME_WeaponScaleX); + pspr->baseScale.Y = caller->FloatVar(NAME_WeaponScaleY); + } + + return pspr; +} + //------------------------------------------------------------------------ // // @@ -267,16 +316,23 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) newcaller = ReadyWeapon; } - if (newcaller == nullptr) return nullptr; // Error case was not handled properly. This function cannot give a guarantee to always succeed! + if (newcaller == nullptr || layer == PSP_CALLERID) return nullptr; // Error case was not handled properly. This function cannot give a guarantee to always succeed! DPSprite *pspr = FindPSprite(layer); if (pspr == nullptr) { - pspr = Create(this, newcaller, layer); + pspr = P_CreatePsprite(this, newcaller, layer); } else { oldcaller = pspr->Caller; + + // update scaling properties here + if (newcaller != nullptr && newcaller->IsKindOf(NAME_Weapon)) + { + pspr->baseScale.X = newcaller->FloatVar(NAME_WeaponScaleX); + pspr->baseScale.Y = newcaller->FloatVar(NAME_WeaponScaleY); + } } // Always update the caller here in case we switched weapon @@ -291,7 +347,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) } else { - pspr->Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_CVARFAST|PSPF_POWDOUBLE); + pspr->Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_CVARFAST|PSPF_POWDOUBLE|PSPF_PIVOTPERCENT); } if (layer == PSP_STRIFEHANDS) { @@ -507,7 +563,7 @@ void DPSprite::SetState(FState *newstate, bool pending) { // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. Printf(TEXTCOLOR_RED "Unsafe state call in state %sd to %s which accesses user variables. The action function has been removed from this state\n", - FState::StaticGetStateName(newstate).GetChars(), newstate->ActionFunc->PrintableName.GetChars()); + FState::StaticGetStateName(newstate).GetChars(), newstate->ActionFunc->PrintableName); newstate->ActionFunc = nullptr; } if (newstate->CallAction(Owner->mo, Caller, &stp, &nextstate)) @@ -585,6 +641,19 @@ void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac) DVector2 result; VMReturn ret(&result); VMCall(func, param, 2, &ret, 1); + + auto inv = player->mo->Inventory; + while(inv != nullptr && !(inv->ObjectFlags & OF_EuthanizeMe)) // same loop as ModifyDamage, except it actually checks if it's overriden before calling + { + auto nextinv = inv->Inventory; + IFOVERRIDENVIRTUALPTRNAME(inv, NAME_Inventory, ModifyBob) + { + VMValue param[] = { (DObject*)inv, result.X, result.Y, ticfrac }; + VMCall(func, param, 4, &ret, 1); + } + inv = nextinv; + } + *x = (float)result.X; *y = (float)result.Y; return; @@ -592,6 +661,40 @@ void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac) *x = *y = 0; } +void P_BobWeapon3D (player_t *player, FVector3 *translation, FVector3 *rotation, double ticfrac) +{ + IFVIRTUALPTRNAME(player->mo, NAME_PlayerPawn, BobWeapon3D) + { + VMValue param[] = { player->mo, ticfrac }; + DVector3 t, r; + VMReturn returns[2]; + returns[0].Vec3At(&t); + returns[1].Vec3At(&r); + VMCall(func, param, 2, returns, 2); + + auto inv = player->mo->Inventory; + while(inv != nullptr && !(inv->ObjectFlags & OF_EuthanizeMe)) + { + auto nextinv = inv->Inventory; + IFOVERRIDENVIRTUALPTRNAME(inv, NAME_Inventory, ModifyBob3D) + { + VMValue param[] = { (DObject*)inv, t.X, t.Y, t.Z, r.X, r.Y, r.Z, ticfrac }; + VMCall(func, param, 8, returns, 2); + } + inv = nextinv; + } + + translation->X = (float)t.X; + translation->Y = (float)t.Y; + translation->Z = (float)t.Z; + rotation->X = (float)r.X; + rotation->Y = (float)r.Y; + rotation->Z = (float)r.Z; + return; + } + *translation = *rotation = {}; +} + //--------------------------------------------------------------------------- // // PROC P_CheckWeaponButtons @@ -634,18 +737,160 @@ DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponButtons) return 0; } + + +enum WOFFlags +{ + WOF_KEEPX = 1, + WOF_KEEPY = 1 << 1, + WOF_ADD = 1 << 2, + WOF_INTERPOLATE = 1 << 3, + WOF_RELATIVE = 1 << 4, + WOF_ZEROY = 1 << 5, +}; + +void HandleOverlayRelative(DPSprite *psp, double *x, double *y) +{ + double wx = *x; + double wy = *y; + + double c = psp->rotation.Cos(), s = psp->rotation.Sin(); + double nx = wx * c + wy * s; + double ny = wx * s - wy * c; + *x = nx; *y = ny; +} + //--------------------------------------------------------------------------- // -// PROC A_OverlayOffset +// PROC A_OverlayVertexOffset // //--------------------------------------------------------------------------- -enum WOFFlags + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayVertexOffset) { - WOF_KEEPX = 1, - WOF_KEEPY = 1 << 1, - WOF_ADD = 1 << 2, - WOF_INTERPOLATE = 1 << 3, -}; + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(layer) + PARAM_INT(index) + PARAM_FLOAT(x) + PARAM_FLOAT(y) + PARAM_INT(flags) + + if (index < 0 || index > 3 || ((flags & WOF_KEEPX) && (flags & WOF_KEEPY)) || !ACTION_CALL_FROM_PSPRITE()) + return 0; + + DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); + + if (pspr == nullptr) + return 0; + + if (!(flags & WOF_KEEPX)) pspr->Coord[index].X = (flags & WOF_ADD) ? pspr->Coord[index].X + x : x; + if (!(flags & WOF_KEEPY)) pspr->Coord[index].Y = (flags & WOF_ADD) ? pspr->Coord[index].Y + y : y; + + if (flags & (WOF_ADD | WOF_INTERPOLATE)) pspr->InterpolateTic = true; + + return 0; +} + +//--------------------------------------------------------------------------- +// +// PROC A_OverlayScale +// +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayScale) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(layer) + PARAM_FLOAT(wx) + PARAM_FLOAT(wy) + PARAM_INT(flags) + + if (!ACTION_CALL_FROM_PSPRITE() || ((flags & WOF_KEEPX) && (flags & WOF_KEEPY))) + return 0; + + DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); + + if (pspr == nullptr) + return 0; + + if (!(flags & WOF_ZEROY) && wy == 0.0) + wy = wx; + + if (!(flags & WOF_KEEPX)) pspr->scale.X = (flags & WOF_ADD) ? pspr->scale.X + wx : wx; + if (!(flags & WOF_KEEPY)) pspr->scale.Y = (flags & WOF_ADD) ? pspr->scale.Y + wy : wy; + + if (flags & (WOF_ADD | WOF_INTERPOLATE)) pspr->InterpolateTic = true; + + return 0; +} + +//--------------------------------------------------------------------------- +// +// PROC A_OverlayRotate +// +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayRotate) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(layer) + PARAM_ANGLE(degrees) + PARAM_INT(flags) + + if (!ACTION_CALL_FROM_PSPRITE()) + return 0; + + DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); + + if (pspr != nullptr) + { + pspr->rotation = (flags & WOF_ADD) ? pspr->rotation + degrees : degrees; + if (flags & (WOF_ADD | WOF_INTERPOLATE)) pspr->InterpolateTic = true; + } + + return 0; +} + +//--------------------------------------------------------------------------- +// +// PROC A_OverlayPivot +// +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayPivot) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(layer) + PARAM_FLOAT(wx) + PARAM_FLOAT(wy) + PARAM_INT(flags) + + if (!ACTION_CALL_FROM_PSPRITE() || ((flags & WOF_KEEPX) && (flags & WOF_KEEPY))) + return 0; + + DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); + + if (pspr == nullptr) + return 0; + + if (flags & WOF_RELATIVE) + { + HandleOverlayRelative(pspr, &wx, &wy); + } + + if (!(flags & WOF_KEEPX)) pspr->pivot.X = (flags & WOF_ADD) ? pspr->pivot.X + wx : wx; + if (!(flags & WOF_KEEPY)) pspr->pivot.Y = (flags & WOF_ADD) ? pspr->pivot.Y + wy : wy; + + if (flags & (WOF_ADD | WOF_INTERPOLATE)) pspr->InterpolateTic = true; + + return 0; +} + +//--------------------------------------------------------------------------- +// +// PROC A_OverlayOffset +// +//--------------------------------------------------------------------------- void A_OverlayOffset(AActor *self, int layer, double wx, double wy, int flags) { @@ -664,30 +909,16 @@ void A_OverlayOffset(AActor *self, int layer, double wx, double wy, int flags) if (psp == nullptr) return; - if (!(flags & WOF_KEEPX)) + if (flags & WOF_RELATIVE) { - if (flags & WOF_ADD) - { - psp->x += wx; - } - else - { - psp->x = wx; - if (!(flags & WOF_INTERPOLATE)) psp->oldx = psp->x; - } - } - if (!(flags & WOF_KEEPY)) - { - if (flags & WOF_ADD) - { - psp->y += wy; - } - else - { - psp->y = wy; - if (!(flags & WOF_INTERPOLATE)) psp->oldy = psp->y; - } + HandleOverlayRelative(psp, &wx, &wy); } + + if (!(flags & WOF_KEEPX)) psp->x = (flags & WOF_ADD) ? psp->x + wx : wx; + if (!(flags & WOF_KEEPY)) psp->y = (flags & WOF_ADD) ? psp->y + wy : wy; + + if (!(flags & (WOF_ADD | WOF_INTERPOLATE))) + psp->ResetInterpolation(); } } @@ -736,8 +967,74 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags) if (set) pspr->Flags |= flags; else + { pspr->Flags &= ~flags; + // This is the only way to shut off the temporary interpolation tic + // in the event another mod is causing potential interference + if (flags & PSPF_INTERPOLATE) + pspr->ResetInterpolation(); + } + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayPivotAlign) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(layer); + PARAM_INT(halign); + PARAM_INT(valign); + + if (!ACTION_CALL_FROM_PSPRITE()) + return 0; + + DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); + + if (pspr != nullptr) + { + if (halign >= PSPA_LEFT && halign <= PSPA_RIGHT) + pspr->HAlign = halign; + if (valign >= PSPA_TOP && valign <= PSPA_BOTTOM) + pspr->VAlign = valign; + } + return 0; +} + +//--------------------------------------------------------------------------- +// +// PROC A_OverlayTranslation +// +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayTranslation) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(layer); + PARAM_NAME(trname); + + if (!ACTION_CALL_FROM_PSPRITE()) + return 0; + + DPSprite* pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); + if (pspr != nullptr) + { + // There is no constant for the empty name... + if (trname.GetChars()[0] == 0) + { + // an empty string resets to the default + // (unlike AActor::SetTranslation, there is no Default block for PSprites, so just set the translation to 0) + pspr->Translation = NO_TRANSLATION; + return 0; + } + + auto tnum = R_FindCustomTranslation(trname); + if (tnum != INVALID_TRANSLATION) + { + pspr->Translation = tnum; + } + // silently ignore if the name does not exist, this would create some insane message spam otherwise. + } + return 0; } @@ -889,7 +1186,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Overlay) } DPSprite *pspr; - pspr = Create(player, stateowner, layer); + pspr = P_CreatePsprite(player, stateowner, layer); pspr->SetState(state); ACTION_RETURN_BOOL(true); } @@ -955,13 +1252,14 @@ DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget, int aimfla DAngle pitch; FTranslatedLineTarget scratch; + aimflags &= ~ALF_IGNORENOAUTOAIM; // just to be safe. if (pLineTarget == NULL) pLineTarget = &scratch; // see which target is to be aimed at i = 2; do { - an = mo->Angles.Yaw + angdiff[i]; - pitch = P_AimLineAttack (mo, an, 16.*64, pLineTarget, 0., aimflags); + an = mo->Angles.Yaw + DAngle::fromDeg(angdiff[i]); + pitch = P_AimLineAttack (mo, an, 16.*64, pLineTarget, nullAngle, aimflags); if (mo->player != nullptr && mo->Level->IsFreelookAllowed() && @@ -979,7 +1277,7 @@ DEFINE_ACTION_FUNCTION(AActor, BulletSlope) PARAM_SELF_PROLOGUE(AActor); PARAM_POINTER(t, FTranslatedLineTarget); PARAM_INT(aimflags); - ACTION_RETURN_FLOAT(P_BulletSlope(self, t, aimflags).Degrees); + ACTION_RETURN_FLOAT(P_BulletSlope(self, t, aimflags).Degrees()); } //------------------------------------------------------------------------ @@ -996,7 +1294,7 @@ void P_SetupPsprites(player_t *player, bool startweaponup) player->DestroyPSprites(); // Spawn the ready weapon - player->PendingWeapon = !startweaponup ? player->ReadyWeapon : WP_NOCHANGE; + player->PendingWeapon = !startweaponup ? player->ReadyWeapon : (AActor*)WP_NOCHANGE; P_BringUpWeapon (player); } @@ -1016,6 +1314,7 @@ void DPSprite::Serialize(FSerializer &arc) ("flags", Flags) ("state", State) ("tics", Tics) + ("translation", Translation) .Sprite("sprite", Sprite, nullptr) ("frame", Frame) ("id", ID) @@ -1024,7 +1323,13 @@ void DPSprite::Serialize(FSerializer &arc) ("oldx", oldx) ("oldy", oldy) ("alpha", alpha) - ("renderstyle_", Renderstyle); // The underscore is intentional to avoid problems with old savegames which had this as an ERenderStyle (which is not future proof.) + ("pivot", pivot) + ("scale", scale) + ("rotation", rotation) + ("halign", HAlign) + ("valign", VAlign) + ("renderstyle_", Renderstyle) // The underscore is intentional to avoid problems with old savegames which had this as an ERenderStyle (which is not future proof.) + ("baseScale", baseScale); } //------------------------------------------------------------------------ @@ -1073,25 +1378,35 @@ void P_SetSafeFlash(AActor *weapon, player_t *player, FState *flashstate, int in P_SetPsprite(player, PSP_FLASH, flashstate + index, true); return; } - else + else if (flashstate->DehIndex < 0) { - // oh, no! The state is beyond the end of the state table so use the original flash state. + // oh, no! The state is beyond the end of the state table so use the original flash state if it does not have a Dehacked index. P_SetPsprite(player, PSP_FLASH, flashstate, true); return; } + else break; // no need to continue. } // try again with parent class cls = static_cast(cls->ParentClass); } - // if we get here the state doesn't seem to belong to any class in the inheritance chain - // This can happen with Dehacked if the flash states are remapped. - // The only way to check this would be to go through all Dehacked modifiable actors, convert - // their states into a single flat array and find the correct one. - // Rather than that, just check to make sure it belongs to something. - if (FState::StaticFindStateOwner(flashstate + index) == NULL) - { // Invalid state. With no index offset, it should at least be valid. - index = 0; + + // if we get here the target state doesn't belong to any class in the inheritance chain. + // This can happen with Dehacked if the flash states are remapped. + // In this case we should check the Dehacked state map to get the proper state. + if (flashstate->DehIndex >= 0) + { + auto pTargetstate = dehExtStates.CheckKey(flashstate->DehIndex + index); + if (pTargetstate) + { + P_SetPsprite(player, PSP_FLASH, *pTargetstate, true); + return; + } } + + // If we still haven't found anything here, just use the base flash state. + // Normally this code should not be reachable. + index = 0; + } P_SetPsprite(player, PSP_FLASH, flashstate + index, true); } diff --git a/src/playsim/p_pspr.h b/src/playsim/p_pspr.h index b807e4f09a7..de019e62fc8 100644 --- a/src/playsim/p_pspr.h +++ b/src/playsim/p_pspr.h @@ -30,7 +30,8 @@ #ifndef __P_PSPR_H__ #define __P_PSPR_H__ -#include "r_data/renderstyle.h" +#include "renderstyle.h" +#include "palettecontainer.h" // Basic data types. // Needs fixed point, and BAM angles. @@ -40,6 +41,8 @@ #define WEAPONTOP 32. #define WEAPON_FUDGE_Y 0.375 struct FTranslatedLineTarget; +struct FState; +class player_t; // // Overlay psprites are scaled shapes @@ -49,6 +52,7 @@ struct FTranslatedLineTarget; enum PSPLayers { PSP_STRIFEHANDS = -1, + PSP_CALLERID = 0, PSP_WEAPON = 1, PSP_FLASH = 1000, PSP_TARGETCENTER = INT_MAX - 2, @@ -68,7 +72,23 @@ enum PSPFlags PSPF_FORCEALPHA = 1 << 7, PSPF_FORCESTYLE = 1 << 8, PSPF_MIRROR = 1 << 9, - PSPF_PLAYERTRANSLATED = 1 << 10 + PSPF_PLAYERTRANSLATED = 1 << 10, + PSPF_PIVOTPERCENT = 1 << 11, + PSPF_INTERPOLATE = 1 << 12, +}; + +enum PSPAlign +{ + PSPA_TOP = 0, + PSPA_CENTER, + PSPA_BOTTOM, + PSPA_LEFT = PSPA_TOP, + PSPA_RIGHT = 2 +}; + +struct WeaponInterp +{ + FVector2 v[4]; }; class DPSprite : public DObject @@ -81,23 +101,34 @@ class DPSprite : public DObject static void NewTick(); void SetState(FState *newstate, bool pending = false); - int GetID() const { return ID; } - int GetSprite() const { return Sprite; } - int GetFrame() const { return Frame; } - int GetTics() const { return Tics; } - FState* GetState() const { return State; } - DPSprite* GetNext() { return Next; } - AActor* GetCaller() { return Caller; } - void SetCaller(AActor *newcaller) { Caller = newcaller; } - void ResetInterpolation() { oldx = x; oldy = y; } + int GetID() const { return ID; } + int GetSprite() const { return Sprite; } + int GetFrame() const { return Frame; } + int GetTics() const { return Tics; } + FTranslationID GetTranslation() { return Translation; } + FState* GetState() const { return State; } + DPSprite* GetNext() { return Next; } + AActor* GetCaller() { return Caller; } + void SetCaller(AActor *newcaller) { Caller = newcaller; } + void ResetInterpolation() { oldx = x; oldy = y; Prev = Vert; InterpolateTic = false; } void OnDestroy() override; std::pair GetRenderStyle(FRenderStyle ownerstyle, double owneralpha); float GetYAdjust(bool fullscreen); + int HAlign, VAlign; // Horizontal and vertical alignment + DVector2 baseScale; // Base scale (set by weapon); defaults to (1.0, 1.2) since that's Doom's native aspect ratio + DAngle rotation; // How much rotation to apply. + DVector2 pivot; // pivot points + DVector2 scale; // Dynamic scale (set by A_Overlay functions) double x, y, alpha; double oldx, oldy; + bool InterpolateTic; // One tic interpolation (WOF_INTERPOLATE) + DVector2 Coord[4]; // Offsets + WeaponInterp Prev; // Interpolation + WeaponInterp Vert; // Current Position bool firstTic; int Tics; + FTranslationID Translation; int Flags; FRenderStyle Renderstyle; @@ -126,6 +157,7 @@ void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending = void P_BringUpWeapon (player_t *player); void P_FireWeapon (player_t *player); void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac); +void P_BobWeapon3D (player_t *player, FVector3 *translation, FVector3 *rotation, double ticfrac); DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0); AActor *P_AimTarget(AActor *mo); diff --git a/src/playsim/p_secnodes.cpp b/src/playsim/p_secnodes.cpp index bdbc99eabc5..e19846c7504 100644 --- a/src/playsim/p_secnodes.cpp +++ b/src/playsim/p_secnodes.cpp @@ -242,7 +242,7 @@ msecnode_t *P_CreateSecNodeList(AActor *thing, double radius, msecnode_t *sector while ((ld = it.Next())) { - if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1) + if (!inRange(box, ld) || BoxOnLineSide(box, ld) != -1) continue; // This line crosses through the object. @@ -390,7 +390,7 @@ void AActor::UpdateRenderSectorList() { int bx = Level->blockmap.GetBlockX(X()); int by = Level->blockmap.GetBlockY(Y()); - FBoundingBox bb(X(), Y(), MIN(radius*1.5, 128.)); // Don't go further than 128 map units, even for large actors + FBoundingBox bb(X(), Y(), min(radius*1.5, 128.)); // Don't go further than 128 map units, even for large actors // Are there any portals near the actor's position? if (Level->blockmap.isValidBlock(bx, by) && Level->PortalBlockmap(bx, by).neighborContainsLines) { @@ -398,7 +398,7 @@ void AActor::UpdateRenderSectorList() for (auto &p : Level->linePortals) { if (p.mType == PORTT_VISUAL) continue; - if (bb.inRange(p.mOrigin) && bb.BoxOnLineSide(p.mOrigin)) + if (inRange(bb, p.mOrigin) && BoxOnLineSide(bb, p.mOrigin)) { touching_lineportallist = P_AddPortalnode(&p, this, touching_lineportallist); } @@ -414,7 +414,7 @@ void AActor::UpdateRenderSectorList() if (planeh <= lasth) break; // broken setup. if (Top() + SPRITE_SPACE < planeh) break; lasth = planeh; - DVector2 newpos = Pos() + sec->GetPortalDisplacement(sector_t::ceiling); + DVector2 newpos = Pos().XY() + sec->GetPortalDisplacement(sector_t::ceiling); sec = sec->Level->PointInSector(newpos); touching_sectorportallist = P_AddSecnode(sec, this, touching_sectorportallist, sec->sectorportal_thinglist); } @@ -426,7 +426,7 @@ void AActor::UpdateRenderSectorList() if (planeh >= lasth) break; // broken setup. if (Z() - SPRITE_SPACE > planeh) break; lasth = planeh; - DVector2 newpos = Pos() + sec->GetPortalDisplacement(sector_t::floor); + DVector2 newpos = Pos().XY() + sec->GetPortalDisplacement(sector_t::floor); sec = sec->Level->PointInSector(newpos); touching_sectorportallist = P_AddSecnode(sec, this, touching_sectorportallist, sec->sectorportal_thinglist); } diff --git a/src/playsim/p_sectors.cpp b/src/playsim/p_sectors.cpp index 41bf380d11f..a9014c2ce28 100644 --- a/src/playsim/p_sectors.cpp +++ b/src/playsim/p_sectors.cpp @@ -70,6 +70,7 @@ #include "r_sky.h" #include "g_levellocals.h" #include "vm.h" +#include "texturemanager.h" //========================================================================== // @@ -77,7 +78,7 @@ // //========================================================================== -CUSTOM_CVAR(Int, r_fakecontrast, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, r_fakecontrast, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (self < 0) self = 1; else if (self > 2) self = 2; @@ -88,27 +89,44 @@ CUSTOM_CVAR(Int, r_fakecontrast, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // // Returns the next special sector attached to this sector // with a certain special. -sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const + +sector_t* P_NextSpecialSectorVC(sector_t* sec, int type) +{ + sector_t* tsec; + for (auto ln : sec->Lines) + { + if (nullptr != (tsec = getNextSector(ln, sec)) && + tsec->validcount != validcount && + tsec->special == type) + { + return tsec; + } + } + return nullptr; +} + + +sector_t *P_NextSpecialSector (sector_t* sec, int type, sector_t *nogood) { sector_t *tsec; - for (auto ln : Lines) + for (auto ln : sec->Lines) { - if (NULL != (tsec = getNextSector (ln, this)) && + if (nullptr != (tsec = getNextSector (ln, sec)) && tsec != nogood && tsec->special == type) { return tsec; } } - return NULL; + return nullptr; } -DEFINE_ACTION_FUNCTION(_Sector, NextSpecialSector) +DEFINE_ACTION_FUNCTION_NATIVE(_Sector, NextSpecialSector, P_NextSpecialSector) { PARAM_SELF_STRUCT_PROLOGUE(sector_t); PARAM_INT(type); PARAM_POINTER(nogood, sector_t); - ACTION_RETURN_POINTER(self->NextSpecialSector(type, nogood)); + ACTION_RETURN_POINTER(P_NextSpecialSector(self, type, nogood)); } // @@ -488,7 +506,7 @@ static inline void CheckShortestTex (FLevelLocals *Level, FTextureID texnum, dou { if (texnum.isValid() || (texnum.isNull() && (Level->i_compatflags & COMPATF_SHORTTEX))) { - FTexture *tex = TexMan.GetTexture(texnum); + auto tex = TexMan.GetGameTexture(texnum); if (tex != NULL) { double h = tex->GetDisplayHeight(); @@ -512,7 +530,7 @@ double FindShortestTextureAround (sector_t *sec) CheckShortestTex (sec->Level, check->sidedef[1]->GetTexture(side_t::bottom), minsize); } } - return minsize < FLT_MAX ? minsize : TexMan.ByIndex(0)->GetDisplayHeight(); + return minsize < FLT_MAX ? minsize : TexMan.GameByIndex(0)->GetDisplayHeight(); } // @@ -537,7 +555,7 @@ double FindShortestUpperAround (sector_t *sec) CheckShortestTex (sec->Level, check->sidedef[1]->GetTexture(side_t::top), minsize); } } - return minsize < FLT_MAX ? minsize : TexMan.ByIndex(0)->GetDisplayHeight(); + return minsize < FLT_MAX ? minsize : TexMan.GameByIndex(0)->GetDisplayHeight(); } // @@ -920,7 +938,12 @@ int GetTerrain(const sector_t *sector, int pos) return sector->terrainnum[pos] >= 0 ? sector->terrainnum[pos] : TerrainTypes[sector->GetTexture(pos)]; } - //===================================================================================== +FTerrainDef *GetFloorTerrain_S(const sector_t* sec, int pos) +{ + return &Terrains[GetTerrain(sec, pos)]; +} + +//===================================================================================== // // //===================================================================================== @@ -1155,10 +1178,10 @@ double GetFriction(const sector_t *self, int plane, double *pMoveFac) auto c = planes[sector_t::floor].GlowColor; if (c == 0) { - FTexture *tex = TexMan.GetTexture(GetTexture(sector_t::floor)); + auto tex = TexMan.GetGameTexture(GetTexture(sector_t::floor)); if (tex != NULL && tex->isGlowing()) { - if (!tex->isAutoGlowing()) tex = TexMan.GetTexture(GetTexture(sector_t::floor), true); + if (!tex->isAutoGlowing()) tex = TexMan.GetGameTexture(GetTexture(sector_t::floor), true); if (tex->isGlowing()) // recheck the current animation frame. { tex->GetGlowColor(bottomglowcolor); @@ -1200,10 +1223,10 @@ double GetFriction(const sector_t *self, int plane, double *pMoveFac) auto c = planes[sector_t::ceiling].GlowColor; if (c == 0) { - FTexture *tex = TexMan.GetTexture(GetTexture(sector_t::ceiling)); + auto tex = TexMan.GetGameTexture(GetTexture(sector_t::ceiling)); if (tex != NULL && tex->isGlowing()) { - if (!tex->isAutoGlowing()) tex = TexMan.GetTexture(GetTexture(sector_t::ceiling), true); + if (!tex->isAutoGlowing()) tex = TexMan.GetGameTexture(GetTexture(sector_t::ceiling), true); if (tex->isGlowing()) // recheck the current animation frame. { ret = true; @@ -1224,10 +1247,10 @@ double GetFriction(const sector_t *self, int plane, double *pMoveFac) c = planes[sector_t::floor].GlowColor; if (c == 0) { - FTexture *tex = TexMan.GetTexture(GetTexture(sector_t::floor)); + auto tex = TexMan.GetGameTexture(GetTexture(sector_t::floor)); if (tex != NULL && tex->isGlowing()) { - if (!tex->isAutoGlowing()) tex = TexMan.GetTexture(GetTexture(sector_t::floor), true); + if (!tex->isAutoGlowing()) tex = TexMan.GetGameTexture(GetTexture(sector_t::floor), true); if (tex->isGlowing()) // recheck the current animation frame. { ret = true; @@ -1378,12 +1401,12 @@ bool FLevelLocals::AlignFlat (int linenum, int side, int fc) return false; DAngle angle = line->Delta().Angle(); - DAngle norm = angle - 90; + DAngle norm = angle - DAngle::fromDeg(90.); double dist = -(norm.Cos() * line->v1->fX() + norm.Sin() * line->v1->fY()); if (side) { - angle += 180.; + angle += DAngle::fromDeg(180.); dist = -dist; } @@ -1474,6 +1497,12 @@ void subsector_t::BuildPolyBSP() BSP->Subsectors[i].sector = sector; BSP->Subsectors[i].section = section; } + for (unsigned i = 0; i < BSP->Segs.Size(); i++) + { + BSP->Segs[i].Subsector = this; + BSP->Segs[i].PartnerSeg = nullptr; + } + } //=========================================================================== @@ -1515,11 +1544,18 @@ void line_t::AdjustLine() // //========================================================================== -int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfakecontrast) const +int side_t::GetLightLevel (bool foggy, int baselight, int which, bool is3dlight, int *pfakecontrast) const { - if (!is3dlight && (Flags & WALLF_ABSLIGHTING)) + if (!is3dlight) { - baselight = Light; + if (Flags & (WALLF_ABSLIGHTING_TIER << which)) + { + baselight = TierLights[which]; + } + else if (Flags & WALLF_ABSLIGHTING) + { + baselight = Light + TierLights[which]; + } } if (pfakecontrast != NULL) @@ -1558,9 +1594,9 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfake } } } - if (!is3dlight && !(Flags & WALLF_ABSLIGHTING) && (!foggy || (Flags & WALLF_LIGHT_FOG))) + if (!is3dlight && !(Flags & WALLF_ABSLIGHTING) && !(Flags & (WALLF_ABSLIGHTING_TIER << which)) && (!foggy || (Flags & WALLF_LIGHT_FOG))) { - baselight += this->Light; + baselight += this->Light + this->TierLights[which]; } return baselight; } diff --git a/src/playsim/p_sight.cpp b/src/playsim/p_sight.cpp index 0f1738f38ce..2cf957c8ced 100644 --- a/src/playsim/p_sight.cpp +++ b/src/playsim/p_sight.cpp @@ -127,7 +127,7 @@ class SightCheck void init(AActor * t1, AActor * t2, sector_t *startsector, SightTask *task, int flags) { sightstart = t1->PosRelative(task->portalgroup); - sightend = t2->PosRelative(task->portalgroup); + sightend = t2->PosRelative(task->portalgroup).XY(); sightstart.Z += t1->Height * 0.75; portalgroup = task->portalgroup; @@ -192,8 +192,8 @@ void SightCheck::P_SightOpening(SightOpening &open, const line_t *linedef, doubl if (ff == 0) ff = front->floorplane.ZatPoint(x, y); if (bf == 0) bf = back->floorplane.ZatPoint(x, y); - open.bottom = MAX(ff, bf); - open.top = MIN(fc, bc); + open.bottom = max(ff, bf); + open.top = min(fc, bc); // we only want to know if there is an opening, not how large it is. open.range = open.bottom < open.top; @@ -849,6 +849,11 @@ int P_CheckSight (AActor *t1, AActor *t2, int flags) return false; } + if ((t2->flags8 & MF8_MVISBLOCKED) && !(flags & SF_IGNOREVISIBILITY)) + { + return false; + } + auto s1 = t1->Sector; auto s2 = t2->Sector; // @@ -866,7 +871,10 @@ sightcounts[0]++; // // [RH] Andy Baker's stealth monsters: // Cannot see an invisible object - if ((flags & SF_IGNOREVISIBILITY) == 0 && ((t2->renderflags & RF_INVISIBLE) || !t2->RenderStyle.IsVisible(t2->Alpha))) + if ((flags & SF_IGNOREVISIBILITY) == 0 && + ((t2->renderflags & RF_INVISIBLE) || + (t2->flags8 & MF8_MINVISIBLE) || + !t2->RenderStyle.IsVisible(t2->Alpha))) { // small chance of an attack being made anyway if ((t1->Level->BotInfo.m_Thinking ? pr_botchecksight() : pr_checksight()) > 50) { diff --git a/src/playsim/p_spec.cpp b/src/playsim/p_spec.cpp index 80a506f2571..ba203697153 100644 --- a/src/playsim/p_spec.cpp +++ b/src/playsim/p_spec.cpp @@ -67,7 +67,7 @@ #include -#include "templates.h" + #include "doomdef.h" #include "doomstat.h" #include "d_event.h" @@ -249,7 +249,7 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType, auto Level = line->GetLevel(); int lineActivation = line->activation; - if (line->flags & ML_FIRSTSIDEONLY && side == 1) + if ((line->flags & ML_FIRSTSIDEONLY && side == 1) || line->special == 0) { return false; } @@ -345,6 +345,7 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType, { break; } + [[fallthrough]]; case Teleport: case Teleport_NoFog: case Teleport_Line: @@ -383,7 +384,9 @@ bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType) // Only predict a very specifc section of specials if (line->special != Teleport_Line && - line->special != Teleport) + line->special != Teleport && + line->special != Teleport_NoFog && + line->special != Teleport_NoStop) { return false; } @@ -427,24 +430,47 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } // Has hit ground. - AActor *ironfeet; auto Level = sector->Level; // [RH] Apply any customizable damage + + if (sector->damageinterval <= 0) + sector->damageinterval = 32; // repair invalid damageinterval values + + if (sector->Flags & (SECF_EXIT1 | SECF_EXIT2)) + { + for (int i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + P_DamageMobj(players[i].mo, nullptr, nullptr, TELEFRAG_DAMAGE, NAME_InstantDeath); + if (sector->Flags & SECF_EXIT2) + Level->SecretExitLevel(0); + else + Level->ExitLevel(0, false); + return; + } + if (sector->damageamount > 0) { // Allow subclasses. Better would be to implement it as armor and let that reduce // the damage as part of the normal damage procedure. Unfortunately, I don't have // different damage types yet, so that's not happening for now. - for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) + // [MK] account for subclasses that may have "Full" protection (i.e.: prevent leaky damage) + int ironfeet = 0; + for (auto i = player->mo->Inventory; i != NULL; i = i->Inventory) { - if (ironfeet->IsKindOf(NAME_PowerIronFeet)) - break; + if (i->IsKindOf(NAME_PowerIronFeet)) + { + FName mode = i->NameVar(NAME_Mode); + if ( ironfeet < 2 && mode == NAME_Full ) + ironfeet = 2; + else if ( ironfeet < 1 && mode == NAME_Normal ) + ironfeet = 1; + } } if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE; - if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) + if ((ironfeet == 0 || (ironfeet < 2 && pr_playerinspecialsector() < sector->leakydamage))) { if (sector->Flags & SECF_HAZARD) { @@ -454,7 +480,10 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } else if (Level->time % sector->damageinterval == 0) { - if (!(player->cheats & (CF_GODMODE|CF_GODMODE2))) P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype); + if (!(player->cheats & (CF_GODMODE | CF_GODMODE2))) + { + P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype); + } if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) { Level->ExitLevel(0, false); @@ -592,10 +621,10 @@ void P_GiveSecret(FLevelLocals *Level, AActor *actor, bool printmessage, bool pl { if (printmessage) { - C_MidPrint(nullptr, GStrings["SECRETMESSAGE"]); + C_MidPrint(nullptr, GStrings.CheckString("SECRETMESSAGE")); if (showsecretsector && sectornum >= 0) { - Printf(PRINT_NONOTIFY, "Secret found in sector %d\n", sectornum); + Printf(PRINT_HIGH | PRINT_NONOTIFY, "Secret found in sector %d\n", sectornum); } } if (playsound) S_Sound (CHAN_AUTO, CHANF_UI, "misc/secret", 1, ATTN_NORM); @@ -625,7 +654,7 @@ void P_PlayerOnSpecialFlat (player_t *player, int floorType) auto Level = player->mo->Level; if (Terrains[floorType].DamageAmount && - !(Level->time & Terrains[floorType].DamageTimeMask)) + !(Level->time % (Terrains[floorType].DamageTimeMask+1))) { AActor *ironfeet = NULL; @@ -669,7 +698,7 @@ void P_UpdateSpecials (FLevelLocals *Level) { if (Level->maptime >= (int)(timelimit * TICRATE * 60)) { - Printf ("%s\n", GStrings("TXT_TIMELIMIT")); + Printf ("%s\n", GStrings.GetString("TXT_TIMELIMIT")); Level->ExitLevel(0, false); } } diff --git a/src/playsim/p_spec.h b/src/playsim/p_spec.h index 9508dd2253a..cc7d990a97c 100644 --- a/src/playsim/p_spec.h +++ b/src/playsim/p_spec.h @@ -141,6 +141,7 @@ enum TELF_KEEPHEIGHT = 16, TELF_ROTATEBOOM = 32, TELF_ROTATEBOOMINVERSE = 64, + TELF_FDCOMPAT = 128, }; //Spawns teleport fog. Pass the actor to pluck TeleFogFromType and TeleFogToType. 'from' determines if this is the fog to spawn at the old position (true) or new (false). @@ -164,7 +165,7 @@ void P_TerminateScript (FLevelLocals *Level, int script, const char *map); // // [RH] p_quake.c // -bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags, double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave); -bool P_StartQuake(FLevelLocals *Level, AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx); +bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double intensityX, double intensityY, double intensityZ, int duration, double damrad, double tremrad, FSoundID quakesfx, int flags, double waveSpeedX, double waveSpeedY, double waveSpeedZ, double falloff, int highpoint, double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage); +bool P_StartQuake(FLevelLocals *Level, AActor *activator, int tid, double intensity, int duration, double damrad, double tremrad, FSoundID quakesfx); #endif diff --git a/src/playsim/p_switch.cpp b/src/playsim/p_switch.cpp index 51248e6b5b5..e89f0301141 100644 --- a/src/playsim/p_switch.cpp +++ b/src/playsim/p_switch.cpp @@ -32,7 +32,7 @@ ** */ -#include "templates.h" + #include "doomdef.h" #include "p_local.h" @@ -41,12 +41,13 @@ #include "m_random.h" #include "s_sound.h" #include "doomstat.h" -#include "serializer.h" +#include "serializer_doom.h" #include "p_maputl.h" #include "p_spec.h" #include "textures.h" #include "actor.h" #include "actorinlines.h" +#include "animations.h" static FRandom pr_switchanim ("AnimSwitch"); @@ -174,7 +175,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, const DVector3 * if (open.range <= 0) goto onesided; - if ((TexMan.FindSwitch(side->GetTexture(side_t::top))) != NULL) + if ((TexAnim.FindSwitch(side->GetTexture(side_t::top))) != NULL) { // Check 3D floors on back side @@ -194,11 +195,14 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, const DVector3 * } } - return (user->Level->i_compatflags2 & COMPATF2_CHECKSWITCHRANGE) + if ((user->Level->i_compatflags2 & COMPATF2_CHECKSWITCHRANGE) ? (user->Top() >= open.top) - : (user->Top() > open.top); + : (user->Top() > open.top)) + { + return true; + } } - else if ((TexMan.FindSwitch(side->GetTexture(side_t::bottom))) != NULL) + if ((TexAnim.FindSwitch(side->GetTexture(side_t::bottom))) != NULL) { // Check 3D floors on back side { @@ -218,11 +222,14 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, const DVector3 * } } - return (user->Level->i_compatflags2 & COMPATF2_CHECKSWITCHRANGE) + if ((user->Level->i_compatflags2 & COMPATF2_CHECKSWITCHRANGE) ? (user->Z() <= open.bottom) - : (user->Z() < open.bottom); + : (user->Z() < open.bottom)) + { + return true; + } } - else if ((flags & ML_3DMIDTEX) || (TexMan.FindSwitch(side->GetTexture(side_t::mid))) != NULL) + if ((flags & ML_3DMIDTEX) || (TexAnim.FindSwitch(side->GetTexture(side_t::mid))) != NULL) { // 3DMIDTEX lines will force a mid texture check if no switch is found on this line // to keep compatibility with Eternity's implementation. @@ -249,20 +256,20 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, const DVector3 * bool P_ChangeSwitchTexture (side_t *side, int useAgain, uint8_t special, bool *quest) { int texture; - int sound; + FSoundID sound; FSwitchDef *Switch; - if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::top))) != NULL) + if ((Switch = TexAnim.FindSwitch (side->GetTexture(side_t::top))) != NULL) { texture = side_t::top; } - else if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::bottom))) != NULL) + else if ((Switch = TexAnim.FindSwitch(side->GetTexture(side_t::mid))) != NULL) { - texture = side_t::bottom; + texture = side_t::mid; } - else if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::mid))) != NULL) + else if ((Switch = TexAnim.FindSwitch (side->GetTexture(side_t::bottom))) != NULL) { - texture = side_t::mid; + texture = side_t::bottom; } else { @@ -274,7 +281,7 @@ bool P_ChangeSwitchTexture (side_t *side, int useAgain, uint8_t special, bool *q } // EXIT SWITCH? - if (Switch->Sound != 0) + if (Switch->Sound != NO_SOUND) { sound = Switch->Sound; } @@ -353,7 +360,7 @@ template<> FSerializer &Serialize (FSerializer &arc, const char *key, FSwitchDef FTextureID tex; tex.SetInvalid(); Serialize(arc, key, tex, nullptr); - Switch = TexMan.FindSwitch(tex); + Switch = TexAnim.FindSwitch(tex); } return arc; } @@ -403,7 +410,7 @@ void DActiveButton::Tick () { m_Frame = -1; S_Sound (Level, DVector3(m_Pos, 0), CHAN_VOICE, CHANF_LISTENERZ, - def->Sound != 0 ? FSoundID(def->Sound) : FSoundID("switches/normbutn"), + def->Sound != NO_SOUND ? FSoundID(def->Sound) : S_FindSound("switches/normbutn"), 1, ATTN_STATIC); bFlippable = false; } diff --git a/src/playsim/p_tags.cpp b/src/playsim/p_tags.cpp index ae5ba5727a4..591fcb0ed80 100644 --- a/src/playsim/p_tags.cpp +++ b/src/playsim/p_tags.cpp @@ -111,7 +111,7 @@ void FTagManager::RemoveLineIDs(int line) { while (allIDs[start].target == line) { - allTags[start].tag = allTags[start].target = -1; + allIDs[start].tag = allIDs[start].target = -1; start++; } } @@ -314,6 +314,96 @@ void FTagManager::DumpTags() } } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +int FTagManager::CountSectorTags(const sector_t *sector) +{ + int i = sector->Index(); + + if (SectorHasTags(i)) + { + const int n = allTags.Size(); + + int j = startForSector[i]; + int c = 0; + + while(j < n && allTags[j].target == i) + { + j++; + c++; + } + + return c; + } + + return 0; +} + +int FTagManager::GetSectorTag(const sector_t *sector, int index) +{ + int i = sector->Index(); + + if (SectorHasTags(i)) + { + const int n = allTags.Size(); + + int j = startForSector[i] + index; + + return (j < n && allTags[j].target == i) ? allTags[j].tag : 0; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +int FTagManager::CountLineIDs(const line_t *line) +{ + int i = line->Index(); + + if (LineHasIDs(i)) + { + const int n = allIDs.Size(); + + int j = startForLine[i]; + int c = 0; + + while(j < n && allIDs[j].target == i) + { + j++; + c++; + } + + return c; + } + + return 0; +} + +int FTagManager::GetLineID(const line_t *line, int index) +{ + int i = line->Index(); + + if (LineHasIDs(i)) + { + const int n = allIDs.Size(); + + int j = startForLine[i] + index; + + return (j < n && allIDs[j].target == i) ? allIDs[j].tag : 0; + } + + return 0; +} + //----------------------------------------------------------------------------- // // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO diff --git a/src/playsim/p_tags.h b/src/playsim/p_tags.h index 7452ef755d4..aee44fbd45c 100644 --- a/src/playsim/p_tags.h +++ b/src/playsim/p_tags.h @@ -77,6 +77,12 @@ class FTagManager void RemoveLineIDs(int line); void DumpTags(); + + int CountSectorTags(const sector_t *sector); + int GetSectorTag(const sector_t *sector, int index); + + int CountLineIDs(const line_t *line); + int GetLineID(const line_t *line, int index); }; class FSectorTagIterator diff --git a/src/playsim/p_teleport.cpp b/src/playsim/p_teleport.cpp index e0e57e53e4d..a69d3654c03 100644 --- a/src/playsim/p_teleport.cpp +++ b/src/playsim/p_teleport.cpp @@ -60,7 +60,7 @@ void P_SpawnTeleportFog(AActor *mobj, const DVector3 &pos, bool beforeTele, bool else { double fogDelta = mobj->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; - mo = Spawn(mobj->Level, (beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType), DVector3(pos, pos.Z + fogDelta), ALLOW_REPLACE); + mo = Spawn(mobj->Level, (beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType), pos.plusZ(fogDelta), ALLOW_REPLACE); } if (mo != NULL && setTarget) @@ -128,7 +128,15 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags) } else { - pos.Z = floorheight; + if (!(thing->Level->i_compatflags2 & COMPATF2_FDTELEPORT) || !(flags & TELF_FDCOMPAT) || floorheight > thing->Z()) + { + pos.Z = floorheight; + } + else + { + pos.Z = thing->Z(); + } + if (!(flags & TELF_KEEPORIENTATION)) { resetpitch = false; @@ -145,8 +153,30 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags) } else { - pos.Z = floorheight; + // emulation of Final Doom's teleport glitch. + // For walking monsters we still have to force them to the ground because the handling of off-ground monsters is different from vanilla. + if (!(thing->Level->i_compatflags2 & COMPATF2_FDTELEPORT) || !(flags & TELF_FDCOMPAT) || !(thing->flags & MF_NOGRAVITY) || floorheight > pos.Z) + { + pos.Z = floorheight; + } + else + { + pos.Z = thing->Z(); + } + } + } + // [MK] notify thing of incoming teleport, check for an early cancel + // if it returns false + { + int nocancel = 1; + IFVIRTUALPTR(thing, AActor, PreTeleport) + { + VMValue params[] = { thing, pos.X, pos.Y, pos.Z, angle.Degrees(), flags }; + VMReturn ret; + ret.IntAt(&nocancel); + VMCall(func, params, countof(params), &ret, 1); } + if ( !nocancel ) return false; } if (!P_TeleportMove (thing, pos, false)) { @@ -157,7 +187,7 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags) player->viewz = thing->Z() + player->viewheight; if (resetpitch) { - player->mo->Angles.Pitch = 0.; + player->mo->Angles.Pitch = nullAngle; } } if (!(flags & TELF_KEEPORIENTATION)) @@ -187,7 +217,7 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags) // [RH] Zoom player's field of vision // [BC] && bHaltVelocity. if (telezoom && thing->player->mo == thing && !(flags & TELF_KEEPVELOCITY)) - thing->player->FOV = MIN (175.f, thing->player->DesiredFOV + 45.f); + thing->player->FOV = min (175.f, thing->player->DesiredFOV + 45.f); } } // [BC] && bHaltVelocity. @@ -213,6 +243,14 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags) // killough 10/98: kill all bobbing velocity too if (player) player->Vel.Zero(); } + // [MK] notify thing of successful teleport + { + IFVIRTUALPTR(thing, AActor, PostTeleport) + { + VMValue params[] = { thing, pos.X, pos.Y, pos.Z, angle.Degrees(), flags }; + VMCall(func, params, countof(params), nullptr, 1); + } + } return true; } @@ -224,7 +262,7 @@ DEFINE_ACTION_FUNCTION(AActor, Teleport) PARAM_FLOAT(z); PARAM_ANGLE(an); PARAM_INT(flags); - ACTION_RETURN_BOOL(P_Teleport(self, DVector3(x, y, z), an, flags)); + ACTION_RETURN_BOOL(P_Teleport(self, DVector3(x, y, z), an, flags & ~TELF_FDCOMPAT)); } //----------------------------------------------------------------------------- @@ -338,10 +376,10 @@ bool FLevelLocals::EV_Teleport (int tid, int tag, line_t *line, int side, AActor { AActor *searcher; double z; - DAngle angle = 0.; + DAngle angle = nullAngle; double s = 0, c = 0; double vx = 0, vy = 0; - DAngle badangle = 0.; + DAngle badangle = nullAngle; if (thing == NULL) { // Teleport function called with an invalid actor @@ -368,7 +406,7 @@ bool FLevelLocals::EV_Teleport (int tid, int tag, line_t *line, int side, AActor // Rotate 90 degrees, so that walking perpendicularly across // teleporter linedef causes thing to exit in the direction // indicated by the exit thing. - angle = line->Delta().Angle() - searcher->Angles.Yaw + 90.; + angle = line->Delta().Angle() - searcher->Angles.Yaw + DAngle::fromDeg(90.); if (flags & TELF_ROTATEBOOMINVERSE) angle = -angle; // Sine, cosine of angle adjustment @@ -391,9 +429,9 @@ bool FLevelLocals::EV_Teleport (int tid, int tag, line_t *line, int side, AActor } if ((i_compatflags2 & COMPATF2_BADANGLES) && (thing->player != NULL)) { - badangle = 0.01; + badangle = DAngle::fromDeg(0.01); } - if (P_Teleport (thing, DVector3(searcher->Pos(), z), searcher->Angles.Yaw + badangle, flags)) + if (P_Teleport (thing, DVector3(searcher->Pos().XY(), z), searcher->Angles.Yaw + badangle, flags)) { // [RH] Lee Killough's changes for silent teleporters from BOOM if (line) @@ -481,7 +519,7 @@ bool FLevelLocals::EV_SilentLineTeleport (line_t *line, int side, AActor *thing, if (!reverse) { - angle += 180.; + angle += DAngle::fromDeg(180.); pos = 1 - pos; } @@ -637,14 +675,15 @@ bool FLevelLocals::EV_TeleportOther (int other_tid, int dest_tid, bool fog) bool DoGroupForOne (AActor *victim, AActor *source, AActor *dest, bool floorz, bool fog) { DAngle an = dest->Angles.Yaw - source->Angles.Yaw; - DVector2 off = victim->Pos() - source->Pos(); + DVector2 off = victim->Pos().XY() - source->Pos().XY(); DAngle offAngle = victim->Angles.Yaw - source->Angles.Yaw; DVector2 newp = { off.X * an.Cos() - off.Y * an.Sin(), off.X * an.Sin() + off.Y * an.Cos() }; double z = floorz ? ONFLOORZ : dest->Z() + victim->Z() - source->Z(); + int flags = fog ? (TELF_DESTFOG | TELF_SOURCEFOG | TELF_KEEPORIENTATION) : TELF_KEEPORIENTATION; bool res = P_Teleport (victim, DVector3(dest->Pos().XY() + newp, z), - 0., fog ? (TELF_DESTFOG | TELF_SOURCEFOG) : TELF_KEEPORIENTATION); + nullAngle, flags); // P_Teleport only changes angle if fog is true victim->Angles.Yaw = (dest->Angles.Yaw + victim->Angles.Yaw - source->Angles.Yaw).Normalized360(); @@ -703,7 +742,7 @@ bool FLevelLocals::EV_TeleportGroup (int group_tid, AActor *victim, int source_t if (moveSource && didSomething) { didSomething |= - P_Teleport (sourceOrigin, destOrigin->PosAtZ(floorz ? ONFLOORZ : destOrigin->Z()), 0., TELF_KEEPORIENTATION); + P_Teleport (sourceOrigin, destOrigin->PosAtZ(floorz ? ONFLOORZ : destOrigin->Z()), nullAngle, TELF_KEEPORIENTATION); sourceOrigin->Angles.Yaw = destOrigin->Angles.Yaw; } diff --git a/src/playsim/p_things.cpp b/src/playsim/p_things.cpp index 7e000a74a04..3391030aac0 100644 --- a/src/playsim/p_things.cpp +++ b/src/playsim/p_things.cpp @@ -87,7 +87,7 @@ bool FLevelLocals::EV_Thing_Spawn (int tid, AActor *source, int type, DAngle ang if (P_TestMobjLocation (mobj)) { rtn++; - mobj->Angles.Yaw = (angle != 1000000. ? angle : spot->Angles.Yaw); + mobj->Angles.Yaw = (angle != DAngle::fromDeg(1000000.) ? angle : spot->Angles.Yaw); if (fog) { P_SpawnTeleportFog(mobj, spot->Pos(), false, true); @@ -171,10 +171,11 @@ void InterceptDefaultAim(AActor *mobj, AActor *targ, DVector3 aim, double speed) // [MC] Was part of P_Thing_Projectile, now its own function for use in ZScript. // Aims mobj at targ based on speed and targ's velocity. -static void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch = false, bool oldvel = false, bool leadtarget = true) +static void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch = false, bool oldvel = false, bool resetvel = false, bool leadtarget = true) { if (targ == nullptr || mobj == nullptr) return; + DVector3 prevel = mobj->Vel; DVector3 aim = mobj->Vec3To(targ); aim.Z += targ->Height / 2; @@ -198,6 +199,10 @@ static void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch if (targ->Vel.X == 0 && targ->Vel.Y == 0) { InterceptDefaultAim(mobj, targ, aim, speed); + if (resetvel) + { + mobj->Vel = prevel; + } return; } } @@ -207,7 +212,6 @@ static void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch double a = g_acos(clamp(ydotx / targspeed / dist, -1.0, 1.0)); double multiplier = double(pr_leadtarget.Random2())*0.1 / 255 + 1.1; double sinb = -clamp(targspeed*multiplier * g_sin(a) / speed, -1.0, 1.0); - DVector3 prevel = mobj->Vel; // Use the cross product of two of the triangle's sides to get a // rotation vector. DVector3 rv(tvel ^ aim); @@ -235,6 +239,10 @@ static void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch { InterceptDefaultAim(mobj, targ, aim, speed); } + if (resetvel) + { + mobj->Vel = prevel; + } } DEFINE_ACTION_FUNCTION(AActor, VelIntercept) @@ -244,8 +252,9 @@ DEFINE_ACTION_FUNCTION(AActor, VelIntercept) PARAM_FLOAT(speed); PARAM_BOOL(aimpitch); PARAM_BOOL(oldvel); + PARAM_BOOL(resetvel); if (speed < 0) speed = self->Speed; - VelIntercept(targ, self, speed, aimpitch, oldvel); + VelIntercept(targ, self, speed, aimpitch, oldvel, resetvel); return 0; } @@ -331,7 +340,7 @@ bool FLevelLocals::EV_Thing_Projectile (int tid, AActor *source, int type, const if (targ != nullptr) { - VelIntercept(targ, mobj, speed, false, false, leadTarget); + VelIntercept(targ, mobj, speed, false, false, false, leadTarget); if (mobj->flags2 & MF2_SEEKERMISSILE) { @@ -459,7 +468,7 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser, int flags) thing->flags |= MF_SOLID; thing->Height = info->Height; // [RH] Use real height thing->radius = info->radius; // [RH] Use real radius - if (!(flags & RF_NOCHECKPOSITION) && !P_CheckPosition (thing, thing->Pos())) + if (!(flags & RF_NOCHECKPOSITION) && !P_CheckPosition (thing, thing->Pos().XY())) { thing->flags = oldflags; thing->radius = oldradius; @@ -503,7 +512,7 @@ bool P_Thing_CanRaise(AActor *thing) thing->Height = info->Height; thing->radius = info->radius; - bool check = P_CheckPosition (thing, thing->Pos()); + bool check = P_CheckPosition (thing, thing->Pos().XY()); // Restore checked properties thing->flags = oldflags; @@ -767,7 +776,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, do if (flags & WARPF_COPYPITCH) caller->SetPitch(reference->Angles.Pitch, false); - if (pitch != 0) + if (pitch != nullAngle) caller->SetPitch(caller->Angles.Pitch + pitch, false); if (flags & WARPF_COPYVELOCITY) @@ -804,7 +813,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, do { caller->AddZ(reference->GetBobOffset()); } - P_TryMove(caller, caller->Pos(), false); + P_TryMove(caller, caller->Pos().XY(), false); } return true; } diff --git a/src/playsim/p_trace.cpp b/src/playsim/p_trace.cpp index 02608b8dea2..ed37d5e34b6 100644 --- a/src/playsim/p_trace.cpp +++ b/src/playsim/p_trace.cpp @@ -406,7 +406,7 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit, bool spec } else { - lineside = P_PointOnLineSide(Start, in->d.line); + lineside = P_PointOnLineSide(Start.XY(), in->d.line); CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector; } } @@ -633,6 +633,9 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit, bool spec case TRACE_Stop: return false; + case TRACE_ContinueOutOfBounds: + return true; + case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; @@ -732,6 +735,7 @@ bool FTraceInfo::ThingCheck(intercept_t *in, double dist, DVector3 hit) switch (TraceCallback(*Results, TraceCallbackData)) { case TRACE_Continue: return true; + case TRACE_ContinueOutOfBounds: return true; case TRACE_Stop: return false; case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; case TRACE_Skip: Results->HitType = TRACE_HitNone; return true; @@ -839,10 +843,10 @@ bool FTraceInfo::TraceTraverse (int ptflags) { if (in->d.line->isLinePortal() && P_PointOnLineSidePrecise(Start, in->d.line) == 0) { - sector_t *entersector = in->d.line->backsector; + sector_t* entersector = in->d.line->backsector; if (entersector == NULL || (hit.Z >= entersector->floorplane.ZatPoint(hit) && hit.Z <= entersector->ceilingplane.ZatPoint(hit))) { - FLinePortal *port = in->d.line->getPortal(); + FLinePortal* port = in->d.line->getPortal(); // The caller cannot handle portals without global offset. if (port->mType == PORTT_LINKED || !(TraceFlags & TRACE_PortalRestrict)) { @@ -853,7 +857,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) } if (!LineCheck(in, dist, hit, false)) break; } - else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis) + else if (((in->d.thing->flags & ActorMask) || ActorMask == 0xffffffff) && in->d.thing != IgnoreThis) { if (!ThingCheck(in, dist, hit)) break; } @@ -894,9 +898,14 @@ bool FTraceInfo::TraceTraverse (int ptflags) } Results = res; } - if (Results->HitType == TRACE_HitNone && Results->Distance == 0) + if (Results->HitType == TRACE_HitNone) { - Results->HitPos = Start + Vec * MaxDist; + // [MK] If we didn't cross anything, it's an easy guess, + // otherwise, complete the line using the remaining distance + if (Results->Distance == 0) + Results->HitPos = Start + Vec * MaxDist; + else + Results->HitPos += Vec * (MaxDist - Results->Distance); SetSourcePosition(); Results->Distance = MaxDist; Results->Fraction = 1.; @@ -1063,10 +1072,14 @@ DEFINE_ACTION_FUNCTION(DLineTracer, Trace) PARAM_FLOAT(direction_y); PARAM_FLOAT(direction_z); PARAM_FLOAT(maxDist); - // actor flags and wall flags are not supported due to how flags are implemented on the ZScript side. + // actor flags are not supported due to how flags are implemented on the ZScript side. // say thanks to oversimplifying the user API. PARAM_INT(traceFlags); + PARAM_UINT(wallMask); + PARAM_BOOL(ignoreAllActors); + PARAM_OBJECT(ignore, AActor); + // these are internal hacks. traceFlags &= ~(TRACE_PCross | TRACE_Impact); // this too @@ -1074,7 +1087,7 @@ DEFINE_ACTION_FUNCTION(DLineTracer, Trace) // Trace(vector3 start, Sector sector, vector3 direction, double maxDist, ETraceFlags traceFlags) bool res = Trace(DVector3(start_x, start_y, start_z), sector, DVector3(direction_x, direction_y, direction_z), maxDist, - (ActorFlag)0xFFFFFFFF, 0xFFFFFFFF, nullptr, self->Results, traceFlags, &DLineTracer::TraceCallback, self); + (ActorFlag)(ignoreAllActors ? 0x0 : 0xFFFFFFFF), wallMask, ignore, self->Results, traceFlags, &DLineTracer::TraceCallback, self); ACTION_RETURN_BOOL(res); } diff --git a/src/playsim/p_trace.h b/src/playsim/p_trace.h index 5e733b4c4c6..9035ae965ff 100644 --- a/src/playsim/p_trace.h +++ b/src/playsim/p_trace.h @@ -37,7 +37,7 @@ #include #include "actor.h" #include "cmdlib.h" -#include "textures/textures.h" +#include "textures.h" struct sector_t; struct line_t; @@ -109,6 +109,7 @@ enum ETraceStatus TRACE_Continue, // continue the trace, returning this hit if there are none further along TRACE_Skip, // continue the trace; do not return this hit TRACE_Abort, // stop the trace, returning no hits + TRACE_ContinueOutOfBounds, // continue the trace through walls; don't use this for railguns }; bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, double maxDist, diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index bfc59d9beff..fefb0f94352 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -58,7 +58,7 @@ ** */ -#include "templates.h" + #include "doomdef.h" #include "d_event.h" #include "p_local.h" @@ -70,14 +70,15 @@ #include "p_enemy.h" #include "a_sharedglobal.h" #include "a_keys.h" -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" #include "sbar.h" #include "intermission/intermission.h" #include "c_console.h" #include "c_dispatch.h" #include "d_net.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "d_player.h" #include "r_utility.h" #include "p_blockmap.h" @@ -92,6 +93,7 @@ #include "v_video.h" #include "gstrings.h" #include "s_music.h" +#include "d_main.h" static FRandom pr_skullpop ("SkullPop"); @@ -99,18 +101,33 @@ static FRandom pr_skullpop ("SkullPop"); CVAR(Bool, sv_singleplayerrespawn, false, CVAR_SERVERINFO | CVAR_CHEAT) // Variables for prediction -CVAR (Bool, cl_noprediction, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, cl_predict_specials, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +// Deprecated +CVAR(Bool, cl_noprediction, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Float, cl_predict_lerpscale, 0.05f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CUSTOM_CVAR(Float, cl_predict_lerpscale, 0.05f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, cl_rubberband_scale, 0.3f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { - P_PredictionLerpReset(); + if (self < 0.0f) + self = 0.0f; + else if (self > 1.0f) + self = 1.0f; } -CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, cl_rubberband_threshold, 20.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (self < 0.1f) self = 0.1f; - P_PredictionLerpReset(); +} +CUSTOM_CVAR(Float, cl_rubberband_minmove, 20.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0.1f) + self = 0.1f; +} +CUSTOM_CVAR(Float, cl_rubberband_limit, 756.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0.0f) + self = 0.0f; } ColorSetList ColorSets; @@ -123,13 +140,9 @@ CUSTOM_CVAR(Float, fov, 90.f, CVAR_ARCHIVE | CVAR_USERINFO | CVAR_NOINITCALL) p->SetFOV(fov); } -struct PredictPos -{ - int gametic; - DVector3 pos; - DRotator angles; -} static PredictionLerpFrom, PredictionLerpResult, PredictionLast; -static int PredictionLerptics; +static DVector3 LastPredictedPosition; +static int LastPredictedPortalGroup; +static int LastPredictedTic; static player_t PredictionPlayerBackup; static AActor *PredictionActor; @@ -148,6 +161,12 @@ static TArray PredictionPortalSectors_sprev_Backup; static TArray PredictionPortalLinesBackup; static TArray PredictionPortalLines_sprev_Backup; +struct +{ + DVector3 Pos = {}; + int Flags = 0; +} static PredictionViewPosBackup; + // [GRB] Custom player classes TArray PlayerClasses; @@ -157,13 +176,6 @@ FPlayerClass::FPlayerClass () Flags = 0; } -FPlayerClass::FPlayerClass (const FPlayerClass &other) -{ - Type = other.Type; - Flags = other.Flags; - Skins = other.Skins; -} - FPlayerClass::~FPlayerClass () { } @@ -227,7 +239,7 @@ void SetupPlayerClasses () for (unsigned i = 0; i < gameinfo.PlayerClasses.Size(); i++) { PClassActor *cls = PClass::FindActor(gameinfo.PlayerClasses[i]); - if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i])) + if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i].GetChars())) { newclass.Flags = 0; newclass.Type = cls; @@ -345,6 +357,8 @@ void player_t::CopyFrom(player_t &p, bool copyPSP) ConversationFaceTalker = p.ConversationFaceTalker; MUSINFOactor = p.MUSINFOactor; MUSINFOtics = p.MUSINFOtics; + SoundClass = p.SoundClass; + angleOffsetTargets = p.angleOffsetTargets; if (copyPSP) { // This needs to transfer ownership completely. @@ -380,7 +394,7 @@ void player_t::SetLogNumber (int num) // First look up TXT_LOGTEXT%d in the string table mysnprintf(lumpname, countof(lumpname), "$TXT_LOGTEXT%d", num); - auto text = GStrings[lumpname+1]; + auto text = GStrings.CheckString(lumpname+1); if (text) { SetLogText(lumpname); // set the label, not the content, so that a language change can be picked up. @@ -388,17 +402,17 @@ void player_t::SetLogNumber (int num) } mysnprintf (lumpname, countof(lumpname), "LOG%d", num); - lumpnum = Wads.CheckNumForName (lumpname); + lumpnum = fileSystem.CheckNumForName (lumpname); if (lumpnum != -1) { - auto fn = Wads.GetLumpFile(lumpnum); - auto wadname = Wads.GetWadName(fn); + auto fn = fileSystem.GetFileContainer(lumpnum); + auto wadname = fileSystem.GetResourceFileName(fn); if (!stricmp(wadname, "STRIFE0.WAD") || !stricmp(wadname, "STRIFE1.WAD") || !stricmp(wadname, "SVE.WAD")) { // If this is an original IWAD text, try looking up its lower priority string version first. mysnprintf(lumpname, countof(lumpname), "$TXT_ILOG%d", num); - auto text = GStrings[lumpname + 1]; + auto text = GStrings.CheckString(lumpname + 1); if (text) { SetLogText(lumpname); // set the label, not the content, so that a language change can be picked up. @@ -406,8 +420,8 @@ void player_t::SetLogNumber (int num) } } - auto lump = Wads.ReadLump(lumpnum); - SetLogText (lump.GetString()); + auto lump = fileSystem.ReadFile(lumpnum); + SetLogText (lump.string()); } } @@ -426,7 +440,7 @@ void player_t::SetLogText (const char *text) if (mo && mo->CheckLocalView()) { // Print log text to console - Printf(PRINT_NONOTIFY, TEXTCOLOR_GOLD "%s\n", LogText[0] == '$' ? GStrings(text + 1) : text); + Printf(PRINT_HIGH | PRINT_NONOTIFY, TEXTCOLOR_GOLD "%s\n", LogText[0] == '$' ? GStrings.GetString(text + 1) : text); } } @@ -434,7 +448,7 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, SetLogText) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_STRING(log); - self->SetLogText(log); + self->SetLogText(log.GetChars()); return 0; } @@ -450,7 +464,7 @@ void player_t::SetSubtitle(int num, FSoundID soundid) if (text != nullptr) { SubtitleText = lumpname; - int sl = soundid == 0 ? 7000 : std::max(7000, S_GetMSLength(soundid)); + int sl = soundid == NO_SOUND ? 7000 : max(7000, S_GetMSLength(soundid)); SubtitleCounter = sl * TICRATE / 1000; } } @@ -482,7 +496,7 @@ void player_t::SetFOV(float fov) { if (consoleplayer == Net_Arbitrator) { - Net_WriteByte(DEM_MYFOV); + Net_WriteInt8(DEM_MYFOV); } else { @@ -492,7 +506,7 @@ void player_t::SetFOV(float fov) } else { - Net_WriteByte(DEM_MYFOV); + Net_WriteInt8(DEM_MYFOV); } Net_WriteFloat(clamp(fov, 5.f, 179.f)); } @@ -620,8 +634,8 @@ EXTERN_CVAR(Bool, cl_oldfreelooklimit); static int GetSoftPitch(bool down) { - int MAX_DN_ANGLE = MIN(56, (int)maxviewpitch); // Max looking down angle - int MAX_UP_ANGLE = MIN(32, (int)maxviewpitch); // Max looking up angle + int MAX_DN_ANGLE = min(56, (int)maxviewpitch); // Max looking down angle + int MAX_UP_ANGLE = min(32, (int)maxviewpitch); // Max looking up angle return (down ? MAX_DN_ANGLE : ((cl_oldfreelooklimit) ? MAX_UP_ANGLE : MAX_DN_ANGLE)); } @@ -631,7 +645,7 @@ void player_t::SendPitchLimits() const { int uppitch, downpitch; - if (V_IsSoftwareRenderer()) + if (!V_IsHardwareRenderer()) { uppitch = GetSoftPitch(false); downpitch = GetSoftPitch(true); @@ -641,9 +655,9 @@ void player_t::SendPitchLimits() const uppitch = downpitch = (int)maxviewpitch; } - Net_WriteByte(DEM_SETPITCHLIMIT); - Net_WriteByte(uppitch); - Net_WriteByte(downpitch); + Net_WriteInt8(DEM_SETPITCHLIMIT); + Net_WriteInt8(uppitch); + Net_WriteInt8(downpitch); } } @@ -697,7 +711,7 @@ bool player_t::Resurrect() P_BringUpWeapon(this); } - if (morphTics) + if (mo->alternative != nullptr) { P_UnmorphActor(mo, mo); } @@ -719,7 +733,8 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, Resurrect) DEFINE_ACTION_FUNCTION(_PlayerInfo, GetUserName) { PARAM_SELF_STRUCT_PROLOGUE(player_t); - ACTION_RETURN_STRING(self->userinfo.GetName()); + PARAM_UINT(charLimit); + ACTION_RETURN_STRING(self->userinfo.GetName(charLimit)); } DEFINE_ACTION_FUNCTION(_PlayerInfo, GetNeverSwitch) @@ -788,12 +803,24 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetWBobSpeed) ACTION_RETURN_FLOAT(self->userinfo.GetWBobSpeed()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetWBobFire) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_FLOAT(self->userinfo.GetWBobFire()); +} + DEFINE_ACTION_FUNCTION(_PlayerInfo, GetMoveBob) { PARAM_SELF_STRUCT_PROLOGUE(player_t); ACTION_RETURN_FLOAT(self->userinfo.GetMoveBob()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetFViewBob) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_BOOL(self->userinfo.GetFViewBob()); +} + DEFINE_ACTION_FUNCTION(_PlayerInfo, GetStillBob) { PARAM_SELF_STRUCT_PROLOGUE(player_t); @@ -820,16 +847,16 @@ static int SetupCrouchSprite(AActor *self, int crouchsprite) FString normspritename = sprites[self->SpawnState->sprite].name; FString crouchspritename = sprites[crouchsprite].name; - int spritenorm = Wads.CheckNumForName(normspritename + "A1", ns_sprites); + int spritenorm = fileSystem.CheckNumForName((normspritename + "A1").GetChars(), FileSys::ns_sprites); if (spritenorm == -1) { - spritenorm = Wads.CheckNumForName(normspritename + "A0", ns_sprites); + spritenorm = fileSystem.CheckNumForName((normspritename + "A0").GetChars(), FileSys::ns_sprites); } - int spritecrouch = Wads.CheckNumForName(crouchspritename + "A1", ns_sprites); + int spritecrouch = fileSystem.CheckNumForName((crouchspritename + "A1").GetChars(), FileSys::ns_sprites); if (spritecrouch == -1) { - spritecrouch = Wads.CheckNumForName(crouchspritename + "A0", ns_sprites); + spritecrouch = fileSystem.CheckNumForName((crouchspritename + "A0").GetChars(), FileSys::ns_sprites); } if (spritenorm == -1 || spritecrouch == -1) @@ -838,10 +865,10 @@ static int SetupCrouchSprite(AActor *self, int crouchsprite) return false; } - int wadnorm = Wads.GetLumpFile(spritenorm); - int wadcrouch = Wads.GetLumpFile(spritenorm); + int wadnorm = fileSystem.GetFileContainer(spritenorm); + int wadcrouch = fileSystem.GetFileContainer(spritenorm); - if (wadnorm > Wads.GetMaxIwadNum() && wadcrouch <= Wads.GetMaxIwadNum()) + if (wadnorm > fileSystem.GetMaxIwadNum() && wadcrouch <= fileSystem.GetMaxIwadNum()) { // Question: Add an option / disable crouching or do what? return false; @@ -885,12 +912,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) { PARAM_SELF_PROLOGUE(AActor); - int sound = 0; + FSoundID sound = NO_SOUND; int chan = CHAN_VOICE; - if (self->player == NULL || self->DeathSound != 0) + if (self->player == NULL || self->DeathSound != NO_SOUND) { - if (self->DeathSound != 0) + if (self->DeathSound != NO_SOUND) { S_Sound (self, CHAN_VOICE, 0, self->DeathSound, 1, ATTN_NORM); } @@ -906,33 +933,33 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) (DF_FORCE_FALLINGZD | DF_FORCE_FALLINGHX)) && self->Vel.Z <= -39) { - sound = S_FindSkinnedSound (self, "*splat"); + sound = S_FindSkinnedSound (self, S_FindSound("*splat")); chan = CHAN_BODY; } - if (!sound && self->special1<10) + if (!sound.isvalid() && self->special1<10) { // Wimpy death sound - sound = S_FindSkinnedSoundEx (self, "*wimpydeath", self->player->LastDamageType); + sound = S_FindSkinnedSoundEx (self, "*wimpydeath", self->player->LastDamageType.GetChars()); } - if (!sound && self->health <= -50) + if (!sound.isvalid() && self->health <= -50) { if (self->health > -100) { // Crazy death sound - sound = S_FindSkinnedSoundEx (self, "*crazydeath", self->player->LastDamageType); + sound = S_FindSkinnedSoundEx (self, "*crazydeath", self->player->LastDamageType.GetChars()); } - if (!sound) + if (!sound.isvalid()) { // Extreme death sound - sound = S_FindSkinnedSoundEx (self, "*xdeath", self->player->LastDamageType); - if (!sound) + sound = S_FindSkinnedSoundEx (self, "*xdeath", self->player->LastDamageType.GetChars()); + if (!sound.isvalid()) { - sound = S_FindSkinnedSoundEx (self, "*gibbed", self->player->LastDamageType); + sound = S_FindSkinnedSoundEx (self, "*gibbed", self->player->LastDamageType.GetChars()); chan = CHAN_BODY; } } } - if (!sound) + if (!sound.isvalid()) { // Normal death sound - sound = S_FindSkinnedSoundEx (self, "*death", self->player->LastDamageType); + sound = S_FindSkinnedSoundEx (self, "*death", self->player->LastDamageType.GetChars()); } if (chan != CHAN_VOICE) @@ -969,8 +996,8 @@ void P_CheckPlayerSprite(AActor *actor, int &spritenum, DVector2 &scale) { // Convert from default scale to skin scale. DVector2 defscale = actor->GetDefault()->Scale; - scale.X *= Skins[player->userinfo.GetSkin()].Scale.X / defscale.X; - scale.Y *= Skins[player->userinfo.GetSkin()].Scale.Y / defscale.Y; + scale.X *= Skins[player->userinfo.GetSkin()].Scale.X / double(defscale.X); + scale.Y *= Skins[player->userinfo.GetSkin()].Scale.Y / double(defscale.Y); } // Set the crouch sprite? @@ -1164,11 +1191,11 @@ void P_CheckEnvironment(player_t *player) P_PlayerOnSpecialFlat(player, P_GetThingFloorType(player->mo)); } if (player->mo->Vel.Z <= -player->mo->FloatVar(NAME_FallingScreamMinSpeed) && - player->mo->Vel.Z >= -player->mo->FloatVar(NAME_FallingScreamMaxSpeed) && !player->morphTics && + player->mo->Vel.Z >= -player->mo->FloatVar(NAME_FallingScreamMaxSpeed) && player->mo->alternative == nullptr && player->mo->waterlevel == 0) { - int id = S_FindSkinnedSound(player->mo, "*falling"); - if (id != 0 && !S_IsActorPlayingSomething(player->mo, CHAN_VOICE, id)) + auto id = S_FindSkinnedSound(player->mo, S_FindSound("*falling")); + if (id != NO_SOUND && !S_IsActorPlayingSomething(player->mo, CHAN_VOICE, id)) { S_Sound(player->mo, CHAN_VOICE, 0, id, 1, ATTN_NORM); } @@ -1231,6 +1258,17 @@ void P_PlayerThink (player_t *player) I_Error ("No player %td start\n", player - players + 1); } + for (unsigned int i = 0u; i < 3u; ++i) + { + if (fabs(player->angleOffsetTargets[i].Degrees()) >= EQUAL_EPSILON) + { + player->mo->Angles[i] += player->angleOffsetTargets[i]; + player->mo->PrevAngles[i] = player->mo->Angles[i]; + } + + player->angleOffsetTargets[i] = nullAngle; + } + if (player->SubtitleCounter > 0) { player->SubtitleCounter--; @@ -1246,7 +1284,7 @@ void P_PlayerThink (player_t *player) { fprintf (debugfile, "tic %d for pl %d: (%f, %f, %f, %f) b:%02x p:%d y:%d f:%d s:%d u:%d\n", gametic, (int)(player-players), player->mo->X(), player->mo->Y(), player->mo->Z(), - player->mo->Angles.Yaw.Degrees, player->cmd.ucmd.buttons, + player->mo->Angles.Yaw.Degrees(), player->cmd.ucmd.buttons, player->cmd.ucmd.pitch, player->cmd.ucmd.yaw, player->cmd.ucmd.forwardmove, player->cmd.ucmd.sidemove, player->cmd.ucmd.upmove); } @@ -1256,6 +1294,11 @@ void P_PlayerThink (player_t *player) player->original_cmd = cmd->ucmd; // Don't interpolate the view for more than one tic player->cheats &= ~CF_INTERPVIEW; + player->cheats &= ~CF_INTERPVIEWANGLES; + player->cheats &= ~CF_SCALEDNOLERP; + player->cheats &= ~CF_NOFOVINTERP; + player->cheats &= ~CF_NOVIEWPOSINTERP; + player->mo->FloatVar("prevBob") = player->bob; IFVIRTUALPTRNAME(player->mo, NAME_PlayerPawn, PlayerThink) { @@ -1266,23 +1309,25 @@ void P_PlayerThink (player_t *player) void P_PredictionLerpReset() { - PredictionLerptics = PredictionLast.gametic = PredictionLerpFrom.gametic = PredictionLerpResult.gametic = 0; + LastPredictedPosition = DVector3{}; + LastPredictedPortalGroup = 0; + LastPredictedTic = -1; } -bool P_LerpCalculate(AActor *pmo, PredictPos from, PredictPos to, PredictPos &result, float scale) +void P_LerpCalculate(AActor* pmo, const DVector3& from, DVector3 &result, float scale, float threshold, float minMove) { - DVector3 vecFrom = from.pos; - DVector3 vecTo = to.pos; - DVector3 vecResult; - vecResult = vecTo - vecFrom; - vecResult *= scale; - vecResult = vecResult + vecFrom; - DVector3 delta = vecResult - vecTo; - - result.pos = pmo->Vec3Offset(vecResult - to.pos); + DVector3 diff = pmo->Pos() - from; + diff.XY() += pmo->Level->Displacements.getOffset(pmo->Sector->PortalGroup, pmo->Level->PointInSector(from.XY())->PortalGroup); + double dist = diff.Length(); + if (dist <= max(threshold, minMove)) + { + result = pmo->Pos(); + return; + } - // As a fail safe, assume extrapolation is the threshold. - return (delta.LengthSquared() > cl_predict_lerpthreshold && scale <= 1.00f); + diff /= dist; + diff *= min(dist * (1.0f - scale), dist - minMove); + result = pmo->Vec3Offset(-diff.X, -diff.Y, -diff.Z); } template @@ -1383,8 +1428,7 @@ void P_PredictPlayer (player_t *player) { int maxtic; - if (cl_noprediction || - singletics || + if (singletics || demoplayback || player->mo == NULL || player != player->mo->Level->GetConsolePlayer() || @@ -1411,9 +1455,16 @@ void P_PredictPlayer (player_t *player) PredictionActorBackupArray.Resize(act->GetClass()->Size); memcpy(PredictionActorBackupArray.Data(), &act->snext, act->GetClass()->Size - ((uint8_t *)&act->snext - (uint8_t *)act)); + // Since this is a DObject it needs to have its fields backed up manually for restore, otherwise any changes + // to it will be permanent while predicting. This is now auto-created on pawns to prevent creation spam. + if (act->ViewPos != nullptr) + { + PredictionViewPosBackup.Pos = act->ViewPos->Offset; + PredictionViewPosBackup.Flags = act->ViewPos->Flags; + } + act->flags &= ~MF_PICKUP; act->flags2 &= ~MF2_PUSHWALL; - act->renderflags &= ~RF_NOINTERPOLATEVIEW; player->cheats |= CF_PREDICTING; BackupNodeList(act, act->touching_sectorlist, §or_t::touching_thinglist, PredictionTouchingSectors_sprev_Backup, PredictionTouchingSectorsBackup); @@ -1449,64 +1500,76 @@ void P_PredictPlayer (player_t *player) } act->BlockNode = NULL; - // Values too small to be usable for lerping can be considered "off". - bool CanLerp = (!(cl_predict_lerpscale < 0.01f) && (ticdup == 1)), DoLerp = false, NoInterpolateOld = R_GetViewInterpolationStatus(); + // This essentially acts like a mini P_Ticker where only the stuff relevant to the client is actually + // called. Call order is preserved. + bool rubberband = false, rubberbandLimit = false; + DVector3 rubberbandPos = {}; + const bool canRubberband = LastPredictedTic >= 0 && cl_rubberband_scale > 0.0f && cl_rubberband_scale < 1.0f; + const double rubberbandThreshold = max(cl_rubberband_minmove, cl_rubberband_threshold); for (int i = gametic; i < maxtic; ++i) { - if (!NoInterpolateOld) - R_RebuildViewInterpolation(player); - - player->cmd = localcmds[i % LOCALCMDTICS]; - P_PlayerThink (player); - player->mo->Tick (); - - if (CanLerp && PredictionLast.gametic > 0 && i == PredictionLast.gametic && !NoInterpolateOld) + // Make sure any portal paths have been cleared from the previous movement. + R_ClearInterpolationPath(); + r_NoInterpolate = false; + // Because we're always predicting, this will get set by teleporters and then can never unset itself in the renderer properly. + player->mo->renderflags &= ~RF_NOINTERPOLATEVIEW; + + // Got snagged on something. Start correcting towards the player's final predicted position. We're + // being intentionally generous here by not really caring how the player got to that position, only + // that they ended up in the same spot on the same tick. + if (canRubberband && LastPredictedTic == i) { - // Z is not compared as lifts will alter this with no apparent change - // Make lerping less picky by only testing whole units - DoLerp = (int)PredictionLast.pos.X != (int)player->mo->X() || (int)PredictionLast.pos.Y != (int)player->mo->Y(); - - // Aditional Debug information - if (developer >= DMSG_NOTIFY && DoLerp) + DVector3 diff = player->mo->Pos() - LastPredictedPosition; + diff += player->mo->Level->Displacements.getOffset(player->mo->Sector->PortalGroup, LastPredictedPortalGroup); + double dist = diff.LengthSquared(); + if (dist >= EQUAL_EPSILON * EQUAL_EPSILON && dist > rubberbandThreshold * rubberbandThreshold) { - DPrintf(DMSG_NOTIFY, "Lerp! Ltic (%d) && Ptic (%d) | Lx (%f) && Px (%f) | Ly (%f) && Py (%f)\n", - PredictionLast.gametic, i, - (PredictionLast.pos.X), (player->mo->X()), - (PredictionLast.pos.Y), (player->mo->Y())); + rubberband = true; + rubberbandPos = player->mo->Pos(); + rubberbandLimit = cl_rubberband_limit > 0.0f && dist > cl_rubberband_limit * cl_rubberband_limit; } } + + player->oldbuttons = player->cmd.ucmd.buttons; + player->cmd = localcmds[i % LOCALCMDTICS]; + player->mo->ClearInterpolation(); + player->mo->ClearFOVInterpolation(); + P_PlayerThink(player); + player->mo->CallTick(); } - if (CanLerp) + if (rubberband) { - if (NoInterpolateOld) - P_PredictionLerpReset(); + DPrintf(DMSG_NOTIFY, "Prediction mismatch at (%.3f, %.3f, %.3f)\nExpected: (%.3f, %.3f, %.3f)\nCorrecting to (%.3f, %.3f, %.3f)\n", + LastPredictedPosition.X, LastPredictedPosition.Y, LastPredictedPosition.Z, + rubberbandPos.X, rubberbandPos.Y, rubberbandPos.Z, + player->mo->X(), player->mo->Y(), player->mo->Z()); - else if (DoLerp) + if (rubberbandLimit) { - // If lerping is already in effect, use the previous camera postion so the view doesn't suddenly snap - PredictionLerpFrom = (PredictionLerptics == 0) ? PredictionLast : PredictionLerpResult; - PredictionLerptics = 1; + // If too far away, instantly snap the player's view to their correct position. + player->mo->renderflags |= RF_NOINTERPOLATEVIEW; } - - PredictionLast.gametic = maxtic - 1; - PredictionLast.pos = player->mo->Pos(); - //PredictionLast.portalgroup = player->mo->Sector->PortalGroup; - - if (PredictionLerptics > 0) + else { - if (PredictionLerpFrom.gametic > 0 && - P_LerpCalculate(player->mo, PredictionLerpFrom, PredictionLast, PredictionLerpResult, (float)PredictionLerptics * cl_predict_lerpscale)) - { - PredictionLerptics++; - player->mo->SetXYZ(PredictionLerpResult.pos); - } - else - { - PredictionLerptics = 0; - } + R_ClearInterpolationPath(); + player->mo->renderflags &= ~RF_NOINTERPOLATEVIEW; + + DVector3 snapPos = {}; + P_LerpCalculate(player->mo, LastPredictedPosition, snapPos, cl_rubberband_scale, cl_rubberband_threshold, cl_rubberband_minmove); + player->mo->PrevPortalGroup = LastPredictedPortalGroup; + player->mo->Prev = LastPredictedPosition; + const double zOfs = player->viewz - player->mo->Z(); + player->mo->SetXYZ(snapPos); + player->viewz = snapPos.Z + zOfs; } } + + // This is intentionally done after rubberbanding starts since it'll automatically smooth itself towards + // the right spot until it reaches it. + LastPredictedTic = maxtic; + LastPredictedPosition = player->mo->Pos(); + LastPredictedPortalGroup = player->mo->Level->PointInSector(LastPredictedPosition)->PortalGroup; } void P_UnPredictPlayer () @@ -1547,6 +1610,12 @@ void P_UnPredictPlayer () act->UnlinkFromWorld(&ctx); memcpy(&act->snext, PredictionActorBackupArray.Data(), PredictionActorBackupArray.Size() - ((uint8_t *)&act->snext - (uint8_t *)act)); + if (act->ViewPos != nullptr) + { + act->ViewPos->Offset = PredictionViewPosBackup.Pos; + act->ViewPos->Flags = PredictionViewPosBackup.Flags; + } + // The blockmap ordering needs to remain unchanged, too. // Restore sector links and refrences. // [ED850] This is somewhat of a duplicate of LinkToWorld(), but we need to keep every thing the same, @@ -1608,6 +1677,7 @@ void player_t::Serialize(FSerializer &arc) if (arc.isReading()) { + userinfo.Reset(mo->Level->PlayerNum(this)); ReadUserInfo(arc, userinfo, skinname); } else @@ -1687,7 +1757,8 @@ void player_t::Serialize(FSerializer &arc) ("settings_controller", settings_controller) ("onground", onground) ("musinfoactor", MUSINFOactor) - ("musinfotics", MUSINFOtics); + ("musinfotics", MUSINFOtics) + ("soundclass", SoundClass); if (arc.isWriting ()) { @@ -1698,7 +1769,7 @@ void player_t::Serialize(FSerializer &arc) } if (skinname.IsNotEmpty()) { - userinfo.SkinChanged(skinname, CurrentPlayerClass); + userinfo.SkinChanged(skinname.GetChars(), CurrentPlayerClass); } } @@ -1803,6 +1874,7 @@ DEFINE_FIELD_X(PlayerInfo, player_t, original_cmd) DEFINE_FIELD_X(PlayerInfo, player_t, userinfo) DEFINE_FIELD_X(PlayerInfo, player_t, weapons) DEFINE_FIELD_NAMED_X(PlayerInfo, player_t, cmd.ucmd.buttons, buttons) +DEFINE_FIELD_X(PlayerInfo, player_t, SoundClass) DEFINE_FIELD_X(UserCmd, usercmd_t, buttons) DEFINE_FIELD_X(UserCmd, usercmd_t, pitch) diff --git a/src/playsim/po_man.cpp b/src/playsim/po_man.cpp index 5147d77fff1..a547d619a87 100644 --- a/src/playsim/po_man.cpp +++ b/src/playsim/po_man.cpp @@ -32,7 +32,8 @@ #include "r_data/r_interpolate.h" #include "po_man.h" #include "p_setup.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "p_blockmap.h" #include "p_maputl.h" #include "r_utility.h" @@ -225,7 +226,7 @@ void DMovePoly::Serialize(FSerializer &arc) void DMovePoly::Construct(FPolyObj *polyNum) { Super::Construct(polyNum); - m_Angle = 0.; + m_Angle = nullAngle; m_Speedv = { 0,0 }; } @@ -274,7 +275,7 @@ void DPolyDoor::Construct (FPolyObj * polyNum, podoortype_t type) { Super::Construct(polyNum); m_Type = type; - m_Direction = 0.; + m_Direction = nullAngle; m_TotalDist = 0; m_Tics = 0; m_WaitTics = 0; @@ -299,7 +300,7 @@ void DRotatePoly::Tick () m_Speed = m_Speed < 0 ? -m_Dist : m_Dist; } - if (m_PolyObj->RotatePolyobj (m_Speed)) + if (m_PolyObj->RotatePolyobj (DAngle::fromDeg(m_Speed))) { if (m_Dist == -1) { // perpetual polyobj @@ -441,7 +442,7 @@ bool EV_MovePoly (FLevelLocals *Level, line_t *line, int polyNum, double speed, pe->StopInterpolation (); } - angle += 180.; // Reverse the angle. + angle += DAngle::fromDeg(180.); // Reverse the angle. } return pe != nullptr; // Return true if something started moving. } @@ -510,6 +511,7 @@ bool EV_MovePolyTo(FLevelLocals *Level, line_t *line, int polyNum, double speed, pe->m_Speed = speed; pe->m_Speedv = dist * speed; pe->m_Target = poly->StartSpot.pos + dist * distlen; + SN_StartSequence(poly, poly->seqType, SEQ_DOOR, 0); if ((pe->m_Dist / pe->m_Speed) <= 2) { pe->StopInterpolation(); @@ -583,7 +585,7 @@ void DPolyDoor::Tick () break; case PODOOR_SWING: - if (m_Dist <= 0 || m_PolyObj->RotatePolyobj (m_Speed)) + if (m_Dist <= 0 || m_PolyObj->RotatePolyobj(DAngle::fromDeg(m_Speed))) { double absSpeed = fabs (m_Speed); m_Dist -= absSpeed; @@ -666,14 +668,14 @@ bool EV_OpenPolyDoor(FLevelLocals *Level, line_t *line, int polyNum, double spee pd->m_Direction = angle; pd->m_Speedv = angle.ToVector(speed); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); - angle += 180.; // reverse the angle + angle += DAngle::fromDeg(180.); // reverse the angle } else if (type == PODOOR_SWING) { pd->m_WaitTics = delay; - pd->m_Direction.Degrees = swingdir; + pd->m_Direction = DAngle::fromDeg(swingdir); pd->m_Speed = (speed*swingdir*(90. / 64)) / 8; - pd->m_Dist = pd->m_TotalDist = angle.Degrees; + pd->m_Dist = pd->m_TotalDist = angle.Degrees(); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); swingdir = -swingdir; // reverse the direction } @@ -716,7 +718,7 @@ bool EV_StopPoly(FLevelLocals *Level, int polynum) FPolyObj::FPolyObj() { StartSpot.pos = { 0,0 }; - Angle = 0.; + Angle = nullAngle; tag = 0; memset(bbox, 0, sizeof(bbox)); validcount = 0; @@ -760,7 +762,7 @@ void FPolyObj::ThrustMobj (AActor *actor, side_t *side) } vertex_t *v1 = side->V1(); vertex_t *v2 = side->V2(); - thrustAngle = (v2->fPos() - v1->fPos()).Angle() - 90.; + thrustAngle = (v2->fPos() - v1->fPos()).Angle() - DAngle::fromDeg(90.); pe = static_cast(specialdata); if (pe) @@ -1078,11 +1080,7 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) open.top = LINEOPEN_MAX; open.bottom = LINEOPEN_MIN; // [TN] Check wether this actor gets blocked by the line. - if (ld->backsector != nullptr && - !(ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) - && !(ld->flags & ML_BLOCK_PLAYERS && (mobj->player || (mobj->flags8 & MF8_BLOCKASPLAYER))) - && !(ld->flags & ML_BLOCKMONSTERS && mobj->flags3 & MF3_ISMONSTER) - && !((mobj->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS)) + if (ld->backsector != nullptr && !P_IsBlockedByLine(mobj, ld) && (!(ld->flags & ML_3DMIDTEX) || (!P_LineOpening_3dMidtex(mobj, ld, open) && (mobj->Top() < open.top) @@ -1099,10 +1097,10 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) performBlockingThrust = true; } - DVector2 pos = mobj->PosRelative(ld); + DVector2 pos = mobj->PosRelative(ld).XY(); FBoundingBox box(pos.X, pos.Y, mobj->radius); - if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1) + if (!inRange(box, ld) || BoxOnLineSide(box, ld) != -1) { continue; } @@ -1110,7 +1108,7 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) if (ld->isLinePortal()) { // Fixme: this still needs to figure out if the polyobject move made the player cross the portal line. - if (P_TryMove(mobj, mobj->Pos(), false)) + if (P_TryMove(mobj, mobj->Pos().XY(), false)) { continue; } diff --git a/src/playsim/portal.cpp b/src/playsim/portal.cpp index 5076e0a984b..f94f7f9149d 100644 --- a/src/playsim/portal.cpp +++ b/src/playsim/portal.cpp @@ -51,6 +51,17 @@ DEFINE_FIELD(FSectorPortal, mDisplacement); DEFINE_FIELD(FSectorPortal, mPlaneZ); DEFINE_FIELD(FSectorPortal, mSkybox); +DEFINE_FIELD(FLinePortal, mOrigin); +DEFINE_FIELD(FLinePortal, mDestination); +DEFINE_FIELD(FLinePortal, mDisplacement); +DEFINE_FIELD(FLinePortal, mType); +DEFINE_FIELD(FLinePortal, mFlags); +DEFINE_FIELD(FLinePortal, mDefFlags); +DEFINE_FIELD(FLinePortal, mAlign); +DEFINE_FIELD(FLinePortal, mAngleDiff); +DEFINE_FIELD(FLinePortal, mSinRot); +DEFINE_FIELD(FLinePortal, mCosRot); + //============================================================================ // // BuildBlockmap @@ -175,7 +186,7 @@ void FLinePortalTraverse::AddLineIntercepts(int bx, int by) // //============================================================================ -line_t *FLevelLocals::FindPortalDestination(line_t *src, int tag) +line_t *FLevelLocals::FindPortalDestination(line_t *src, int tag, int matchtype) { if (tag) { @@ -184,7 +195,7 @@ line_t *FLevelLocals::FindPortalDestination(line_t *src, int tag) while ((lineno = it.Next()) >= 0) { - if (&lines[lineno] != src) + if (&lines[lineno] != src && (matchtype == -1 || matchtype == lines[lineno].special)) { return &lines[lineno]; } @@ -208,9 +219,9 @@ static void SetPortalRotation(FLinePortal *port) { line_t *dst = port->mDestination; line_t *line = port->mOrigin; - DAngle angle = dst->Delta().Angle() - line->Delta().Angle() + 180.; - port->mSinRot = sindeg(angle.Degrees); // Here precision matters so use the slower but more precise versions. - port->mCosRot = cosdeg(angle.Degrees); + DAngle angle = dst->Delta().Angle() - line->Delta().Angle() + DAngle::fromDeg(180.); + port->mSinRot = sindeg(angle.Degrees()); // Here precision matters so use the slower but more precise versions. + port->mCosRot = cosdeg(angle.Degrees()); port->mAngleDiff = angle; if ((line->sidedef[0]->Flags & WALLF_POLYOBJ) || (dst->sidedef[0]->Flags & WALLF_POLYOBJ)) { @@ -226,7 +237,7 @@ static void SetPortalRotation(FLinePortal *port) // Linked portals have no angular difference. port->mSinRot = 0.; port->mCosRot = 1.; - port->mAngleDiff = 0.; + port->mAngleDiff = nullAngle; } } } @@ -388,13 +399,13 @@ bool FLevelLocals::ChangePortal(line_t *ln, int thisid, int destid) // //============================================================================ -inline int P_GetLineSide(const DVector2 &pos, const line_t *line) +inline int P_GetLineSide(const DVector2 &pos, const linebase_t *line) { double v = (pos.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pos.X) * line->Delta().Y; return v < -1. / 65536. ? -1 : v > 1. / 65536 ? 1 : 0; } -bool P_ClipLineToPortal(line_t* line, line_t* portal, DVector2 view, bool partial, bool samebehind) +bool P_ClipLineToPortal(linebase_t* line, linebase_t* portal, DVector2 view, bool partial, bool samebehind) { int behind1 = P_GetLineSide(line->v1->fPos(), portal); int behind2 = P_GetLineSide(line->v2->fPos(), portal); @@ -540,7 +551,6 @@ unsigned FLevelLocals::GetSkyboxPortal(AActor *actor) if (sectorPortals[i].mSkybox == actor) return i; } unsigned i = sectorPortals.Reserve(1); - memset(§orPortals[i], 0, sizeof(sectorPortals[i])); sectorPortals[i].mType = PORTS_SKYVIEWPOINT; sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf("SkyCamCompat") ? 0 : PORTSF_SKYFLATONLY; sectorPortals[i].mSkybox = actor; @@ -565,7 +575,6 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GetSkyboxPortal) unsigned FLevelLocals::GetPortal(int type, int plane, sector_t *from, sector_t *to, const DVector2 &displacement) { unsigned i = sectorPortals.Reserve(1); - memset(§orPortals[i], 0, sizeof(sectorPortals[i])); sectorPortals[i].mType = type; sectorPortals[i].mPlane = plane; sectorPortals[i].mOrigin = from; @@ -586,7 +595,6 @@ unsigned FLevelLocals::GetPortal(int type, int plane, sector_t *from, sector_t * unsigned FLevelLocals::GetStackPortal(AActor *point, int plane) { unsigned i = sectorPortals.Reserve(1); - memset(§orPortals[i], 0, sizeof(sectorPortals[i])); sectorPortals[i].mType = PORTS_STACKEDSECTORTHING; sectorPortals[i].mPlane = plane; sectorPortals[i].mOrigin = point->target->Sector; @@ -1079,7 +1087,7 @@ bool FLevelLocals::CollectConnectedGroups(int startgroup, const DVector3 &positi FBoundingBox box(position.X + disp.pos.X, position.Y + disp.pos.Y, checkradius); - if (!box.inRange(ld) || box.BoxOnLineSide(linkedPortals[i]->mOrigin) != -1) continue; // not touched + if (!inRange(box, ld) || BoxOnLineSide(box, linkedPortals[i]->mOrigin) != -1) continue; // not touched foundPortals.Push(linkedPortals[i]); } bool foundone = true; @@ -1138,7 +1146,7 @@ bool FLevelLocals::CollectConnectedGroups(int startgroup, const DVector3 &positi line_t *ld; while ((ld = it.Next())) { - if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1) + if (!inRange(box, ld) || BoxOnLineSide(box, ld) != -1) continue; if (!(thisgroup & FPortalGroupArray::LOWER)) diff --git a/src/playsim/portal.h b/src/playsim/portal.h index b5e2b7a1b6a..74413fb2a34 100644 --- a/src/playsim/portal.h +++ b/src/playsim/portal.h @@ -1,9 +1,13 @@ #ifndef _PORTALS_H_ #define _PORTALS_H_ -#include "basictypes.h" +#include "basics.h" #include "m_bbox.h" +struct linebase_t; +struct line_t; +struct sector_t; + struct FPortalGroupArray; struct portnode_t; struct subsector_t; @@ -190,6 +194,16 @@ struct FLinePortal double mCosRot; portnode_t *lineportal_thinglist; FLinePortalSpan *mGroup; + + FLinePortal() + { + Clear(); + } + + void Clear() + { + memset((void*)this, 0, sizeof * this); + } }; struct FLinePortalSpan @@ -235,6 +249,16 @@ struct FSectorPortal double mPlaneZ; TObjPtr mSkybox; + FSectorPortal() + { + Clear(); + } + + void Clear() + { + memset((void*)this, 0, sizeof * this); + } + bool MergeAllowed() const { // For thing based stack sectors and regular skies the portal has no relevance for merging visplanes. @@ -265,7 +289,7 @@ struct FSectorPortalGroup /* code ported from prototype */ -bool P_ClipLineToPortal(line_t* line, line_t* portal, DVector2 view, bool partial = true, bool samebehind = true); +bool P_ClipLineToPortal(linebase_t* line, linebase_t* portal, DVector2 view, bool partial = true, bool samebehind = true); void P_TranslatePortalXY(line_t* src, double& vx, double& vy); void P_TranslatePortalVXVY(line_t* src, double &velx, double &vely); void P_TranslatePortalAngle(line_t* src, DAngle& angle); diff --git a/src/playsim/shadowinlines.h b/src/playsim/shadowinlines.h new file mode 100644 index 00000000000..574abd2519a --- /dev/null +++ b/src/playsim/shadowinlines.h @@ -0,0 +1,238 @@ +#pragma once + +#include "actor.h" +#include "r_defs.h" +#include "m_random.h" + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// Handling of MF_SHADOW related code for attack and aiming functions. +// +//----------------------------------------------------------------------------- + + +// RNG VARIABLES ------------------------------------------------ +extern FRandom pr_spawnmissile; +extern FRandom pr_facetarget; +extern FRandom pr_railface; +extern FRandom pr_crailgun; +inline FRandom pr_shadowaimz("VerticalShadowAim"); + +//========================================================================== +// +// Generic checks +// +//========================================================================== + +struct SightCheckData +{ + AActor* HitShadow; +}; + +inline ETraceStatus CheckForShadowBlockers(FTraceResults& res, void* userdata) +{ + SightCheckData* output = (SightCheckData*)userdata; + if (res.HitType == TRACE_HitActor && res.Actor && (res.Actor->flags9 & MF9_SHADOWBLOCK)) + { + output->HitShadow = res.Actor; + return TRACE_Stop; + } + + if (res.HitType != TRACE_HitActor) + { + return TRACE_Stop; + } + + return TRACE_Continue; +} + +// [inkoalawetrust] Check if an MF9_SHADOWBLOCK actor is standing between t1 and t2. +inline AActor* P_CheckForShadowBlock(AActor* t1, AActor* t2, DVector3 pos, double& penaltyFactor) +{ + FTraceResults result; + SightCheckData ShadowCheck; + ShadowCheck.HitShadow = nullptr; + DVector3 dir; + double dist; + if (t2) + { + dir = t1->Vec3To(t2); + dist = dir.Length(); + } + //No second actor, fall back to shooting at facing direction. + else + { + dir = DRotator(-(t1->Angles.Pitch), t1->Angles.Yaw, t1->Angles.Yaw); + dist = 65536.0; //Arbitrary large value. + } + + Trace(pos, t1->Sector, dir, dist, ActorFlags::FromInt(0xFFFFFFFF), ML_BLOCKEVERYTHING, t1, result, 0, CheckForShadowBlockers, &ShadowCheck); + + //Use the penalty factor of the shadowblocker that was hit. Otherwise, use the factor passed by PerformShadowChecks(). + if (ShadowCheck.HitShadow) + { + penaltyFactor = ShadowCheck.HitShadow->ShadowPenaltyFactor; + } + + return ShadowCheck.HitShadow; +} + +inline bool AffectedByShadows(AActor* self) +{ + return (!(self->flags6 & MF6_SEEINVISIBLE) || self->flags9 & MF9_SHADOWAIM); +} + +inline AActor* CheckForShadows(AActor* self, AActor* other, DVector3 pos, double& penaltyFactor) +{ + if ((other && (other->flags & MF_SHADOW)) || (self->flags9 & MF9_DOSHADOWBLOCK)) + { + AActor* shadowBlock = P_CheckForShadowBlock(self, other, pos, penaltyFactor); + return shadowBlock ? shadowBlock : other; + } + return nullptr; +} + +inline AActor* PerformShadowChecks(AActor* self, AActor* other, DVector3 pos, double& penaltyFactor) +{ + if (other != nullptr) penaltyFactor = other->ShadowPenaltyFactor; //Use target penalty factor by default. + else penaltyFactor = 1.0; + return AffectedByShadows(self) ? CheckForShadows(self, other, pos, penaltyFactor) : nullptr; +} + +//========================================================================== +// +// Function-specific inlines. +// +//========================================================================== + +inline void P_SpawnMissileXYZ_ShadowHandling(AActor* source, AActor* target, AActor* missile, DVector3 pos) +{ + double penaltyFactor; + // invisible target: rotate velocity vector in 2D + // [RC] Now monsters can aim at invisible player as if they were fully visible. + if (PerformShadowChecks(source, target, pos, penaltyFactor)) + { + DAngle an = DAngle::fromDeg(pr_spawnmissile.Random2() * (22.5 / 256)) * source->ShadowAimFactor * penaltyFactor; + double c = an.Cos(); + double s = an.Sin(); + + double newx = missile->Vel.X * c - missile->Vel.Y * s; + double newy = missile->Vel.X * s + missile->Vel.Y * c; + + missile->Vel.X = newx; + missile->Vel.Y = newy; + + if (source->flags9 & MF9_SHADOWAIMVERT) + { + DAngle pitch = DAngle::fromDeg(pr_spawnmissile.Random2() * (22.5 / 256)) * source->ShadowAimFactor * penaltyFactor; + double newz = -pitch.Sin() * missile->Speed; + missile->Vel.Z = newz; + } + } + return; +} + +//P_SpawnMissileZAimed uses a local variable for the angle it passes on. +inline DAngle P_SpawnMissileZAimed_ShadowHandling(AActor* source, AActor* target, double& vz, double speed, DVector3 pos) +{ + double penaltyFactor; + if (PerformShadowChecks(source, target, pos, penaltyFactor)) + { + if (source->flags9 & MF9_SHADOWAIMVERT) + { + DAngle pitch = DAngle::fromDeg(pr_spawnmissile.Random2() * (16. / 360.)) * source->ShadowAimFactor * penaltyFactor; + vz += -pitch.Sin() * speed; //Modify the Z velocity pointer that is then passed to P_SpawnMissileAngleZSpeed. + } + return DAngle::fromDeg(pr_spawnmissile.Random2() * (16. / 360.)) * source->ShadowAimFactor * penaltyFactor; + } + return nullAngle; +} + +inline void A_Face_ShadowHandling(AActor* self, AActor* other, DAngle max_turn, DAngle other_angle, bool vertical) +{ + double penaltyFactor; + if (!vertical) + { + // This will never work well if the turn angle is limited. + if (max_turn == nullAngle && (self->Angles.Yaw == other_angle) && PerformShadowChecks(self, other, self->PosAtZ(self->Center()), penaltyFactor)) + { + self->Angles.Yaw += DAngle::fromDeg(pr_facetarget.Random2() * (45 / 256.)) * self->ShadowAimFactor * penaltyFactor; + } + } + else + { + //Randomly offset the pitch when looking at shadows. + if (self->flags9 & MF9_SHADOWAIMVERT && max_turn == nullAngle && (self->Angles.Pitch == other_angle) && PerformShadowChecks(self, other, self->PosAtZ(self->Center()), penaltyFactor)) + { + self->Angles.Pitch += DAngle::fromDeg(pr_facetarget.Random2() * (45 / 256.)) * self->ShadowAimFactor * penaltyFactor; + } + } + return; +} + +inline void A_MonsterRail_ShadowHandling(AActor* self) +{ + double penaltyFactor; + double shootZ = self->Center() - self->FloatSpeed - self->Floorclip; // The formula P_RailAttack uses, minus offset_z since A_MonsterRail doesn't use it. + + if (PerformShadowChecks(self, self->target, self->PosAtZ(shootZ), penaltyFactor)) + { + self->Angles.Yaw += DAngle::fromDeg(pr_railface.Random2() * 45. / 256) * self->ShadowAimFactor * penaltyFactor; + if (self->flags9 & MF9_SHADOWAIMVERT) + self->Angles.Pitch += DAngle::fromDeg(pr_railface.Random2() * 45. / 256) * self->ShadowAimFactor * penaltyFactor; + } + return; +} + +//Also passes parameters to determine a firing position for the SHADOWBLOCK check. +inline void A_CustomRailgun_ShadowHandling(AActor* self, double spawnofs_xy, double spawnofs_z, DAngle spread_xy, int flags) +{ + double penaltyFactor; + // [inkoalawetrust] The exact formula P_RailAttack uses to determine where the railgun trace should spawn from. + DVector2 shootXY = (self->Vec2Angle(spawnofs_xy, (self->Angles.Yaw + spread_xy) - DAngle::fromDeg(90.))); + double shootZ = self->Center() - self->FloatSpeed + spawnofs_z - self->Floorclip; + if (flags & 16) shootZ += self->AttackOffset(); //16 is RGF_CENTERZ + DVector3 checkPos; + checkPos.X = shootXY.X; + checkPos.Y = shootXY.Y; + checkPos.Z = shootZ; + + if (PerformShadowChecks(self, self->target, checkPos, penaltyFactor)) + { + self->Angles.Yaw += DAngle::fromDeg(pr_crailgun.Random2() * (45. / 256.)) * self->ShadowAimFactor * penaltyFactor; + if (self->flags9 & MF9_SHADOWAIMVERT) + { + self->Angles.Pitch += DAngle::fromDeg(pr_crailgun.Random2() * (45. / 256.)) * self->ShadowAimFactor * penaltyFactor; + } + } + return; +} + +//If anything is returned, then AimLineAttacks' result pitch is changed to that value. +inline DAngle P_AimLineAttack_ShadowHandling(AActor*source, AActor* target, AActor* linetarget, double shootZ) +{ + double penaltyFactor; + AActor* mo; + if (target) + mo = target; + else + mo = linetarget; + + // [inkoalawetrust] Randomly offset the vertical aim of monsters. Roughly uses the SSG vertical spread. + if (source->player == NULL && source->flags9 & MF9_SHADOWAIMVERT && PerformShadowChecks (source, mo, source->PosAtZ (shootZ), penaltyFactor)) + { + if (linetarget) + return DAngle::fromDeg(pr_shadowaimz.Random2() * (28.388 / 256.)) * source->ShadowAimFactor * penaltyFactor; //Change the autoaims' pitch to this. + else + source->Angles.Pitch = DAngle::fromDeg(pr_shadowaimz.Random2() * (28.388 / 256.)) * source->ShadowAimFactor * penaltyFactor; + } + return nullAngle; +} + +//A_WolfAttack directly harms the target instead of firing a hitscan or projectile. So it handles shadows by lowering the chance of harming the target. +inline bool A_WolfAttack_ShadowHandling(AActor* self) +{ + double p; //Does nothing. + return (PerformShadowChecks(self, self->target, self->PosAtZ(self->Center()), p)); +} \ No newline at end of file diff --git a/src/playsim/statnums.h b/src/playsim/statnums.h index 7450ccbddcc..f33ac21c033 100644 --- a/src/playsim/statnums.h +++ b/src/playsim/statnums.h @@ -69,6 +69,7 @@ enum STAT_ACTORMOVER, // actor movers STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay STAT_BOT, // Bot thinker + STAT_VISUALTHINKER, // VisualThinker Thinker }; #endif \ No newline at end of file diff --git a/src/posix/cocoa/i_joystick.cpp b/src/posix/cocoa/i_joystick.cpp deleted file mode 100644 index bebf43b423c..00000000000 --- a/src/posix/cocoa/i_joystick.cpp +++ /dev/null @@ -1,1244 +0,0 @@ -/* - ** i_joystick.cpp - ** - **--------------------------------------------------------------------------- - ** Copyright 2012-2015 Alexey Lysiuk - ** All rights reserved. - ** - ** Redistribution and use in source and binary forms, with or without - ** modification, are permitted provided that the following conditions - ** are met: - ** - ** 1. Redistributions of source code must retain the above copyright - ** notice, this list of conditions and the following disclaimer. - ** 2. 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. - ** 3. The name of the author may not be used to endorse or promote products - ** derived from this software without specific prior written permission. - ** - ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - **--------------------------------------------------------------------------- - ** - */ - -#include -#include -#include - -#include "d_event.h" -#include "doomdef.h" -#include "i_system.h" -#include "m_argv.h" -#include "m_joy.h" -#include "templates.h" -#include "v_text.h" - - -EXTERN_CVAR(Bool, joy_axespolling) - - -namespace -{ - -FString ToFString(const CFStringRef string) -{ - if (NULL == string) - { - return FString(); - } - - const CFIndex stringLength = CFStringGetLength(string); - - if (0 == stringLength) - { - return FString(); - } - - const size_t bufferSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1; - - char buffer[bufferSize]; - memset(buffer, 0, bufferSize); - - CFStringGetCString(string, buffer, bufferSize, kCFStringEncodingUTF8); - - return FString(buffer); -} - - -// --------------------------------------------------------------------------- - - -class IOKitJoystick : public IJoystickConfig -{ -public: - explicit IOKitJoystick(io_object_t device); - virtual ~IOKitJoystick(); - - virtual FString GetName(); - virtual float GetSensitivity(); - virtual void SetSensitivity(float scale); - - virtual int GetNumAxes(); - virtual float GetAxisDeadZone(int axis); - virtual EJoyAxis GetAxisMap(int axis); - virtual const char* GetAxisName(int axis); - virtual float GetAxisScale(int axis); - - virtual void SetAxisDeadZone(int axis, float deadZone); - virtual void SetAxisMap(int axis, EJoyAxis gameAxis); - virtual void SetAxisScale(int axis, float scale); - - virtual bool IsSensitivityDefault(); - virtual bool IsAxisDeadZoneDefault(int axis); - virtual bool IsAxisMapDefault(int axis); - virtual bool IsAxisScaleDefault(int axis); - - virtual void SetDefaultConfig(); - virtual FString GetIdentifier(); - - void AddAxes(float axes[NUM_JOYAXIS]) const; - - void Update(); - - void UseAxesPolling(bool axesPolling); - - io_object_t* GetNotificationPtr(); - -private: - IOHIDDeviceInterface** m_interface; - IOHIDQueueInterface** m_queue; - - FString m_name; - FString m_identifier; - - float m_sensitivity; - - struct AnalogAxis - { - IOHIDElementCookie cookie; - - char name[64]; - - float value; - - int32_t minValue; - int32_t maxValue; - - float deadZone; - float defaultDeadZone; - float sensitivity; - float defaultSensitivity; - - EJoyAxis gameAxis; - EJoyAxis defaultGameAxis; - - AnalogAxis() - { - memset(this, 0, sizeof *this); - } - }; - - TArray m_axes; - - struct DigitalButton - { - IOHIDElementCookie cookie; - int32_t value; - - explicit DigitalButton(const IOHIDElementCookie cookie) - : cookie(cookie) - , value(0) - { } - }; - - TArray m_buttons; - TArray m_POVs; - - bool m_useAxesPolling; - - io_object_t m_notification; - - - static const float DEFAULT_DEADZONE; - static const float DEFAULT_SENSITIVITY; - - void ProcessAxes(); - bool ProcessAxis (const IOHIDEventStruct& event); - bool ProcessButton(const IOHIDEventStruct& event); - bool ProcessPOV (const IOHIDEventStruct& event); - - void GatherDeviceInfo(io_object_t device, CFDictionaryRef properties); - - static void GatherElementsHandler(const void* value, void* parameter); - void GatherCollectionElements(CFDictionaryRef properties); - - void AddAxis(CFDictionaryRef element); - void AddButton(CFDictionaryRef element); - void AddPOV(CFDictionaryRef element); - - void AddToQueue(IOHIDElementCookie cookie); - void RemoveFromQueue(IOHIDElementCookie cookie); -}; - - -const float IOKitJoystick::DEFAULT_DEADZONE = 0.25f; -const float IOKitJoystick::DEFAULT_SENSITIVITY = 1.0f; - - -IOHIDDeviceInterface** CreateDeviceInterface(const io_object_t device) -{ - IOCFPlugInInterface** plugInInterface = NULL; - SInt32 score = 0; - - const kern_return_t pluginResult = IOCreatePlugInInterfaceForService(device, - kIOHIDDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); - - IOHIDDeviceInterface** interface = NULL; - - if (KERN_SUCCESS == pluginResult) - { - // Call a method of the intermediate plug-in to create the device interface - - const HRESULT queryResult = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), reinterpret_cast(&interface)); - - IODestroyPlugInInterface(plugInInterface); // [?] or maybe (*plugInInterface)->Release(plugInInterface); - - if (S_OK == queryResult) - { - const IOReturn openResult = (*interface)->open(interface, 0); - - if (kIOReturnSuccess != openResult) - { - (*interface)->Release(interface); - - Printf(TEXTCOLOR_RED "IOHIDDeviceInterface::open() failed with code 0x%08X\n", openResult); - return NULL; - } - } - else - { - Printf(TEXTCOLOR_RED "IOCFPlugInInterface::QueryInterface() failed with code 0x%08X\n", - static_cast(queryResult)); - return NULL; - } - } - else - { - Printf(TEXTCOLOR_RED "IOCreatePlugInInterfaceForService() failed with code %i\n", pluginResult); - return NULL; - } - - return interface; -} - -IOHIDQueueInterface** CreateDeviceQueue(IOHIDDeviceInterface** const interface) -{ - if (NULL == interface) - { - return NULL; - } - - IOHIDQueueInterface** queue = (*interface)->allocQueue(interface); - - if (NULL == queue) - { - Printf(TEXTCOLOR_RED "IOHIDDeviceInterface::allocQueue() failed\n"); - return NULL; - } - - static const uint32_t QUEUE_FLAGS = 0; - static const uint32_t QUEUE_DEPTH = 0; - - const IOReturn queueResult = (*queue)->create(queue, QUEUE_FLAGS, QUEUE_DEPTH); - - if (kIOReturnSuccess != queueResult) - { - (*queue)->Release(queue); - - Printf(TEXTCOLOR_RED "IOHIDQueueInterface::create() failed with code 0x%08X\n", queueResult); - return NULL; - } - - return queue; -} - - -IOKitJoystick::IOKitJoystick(const io_object_t device) -: m_interface(CreateDeviceInterface(device)) -, m_queue(CreateDeviceQueue(m_interface)) -, m_sensitivity(DEFAULT_SENSITIVITY) -, m_useAxesPolling(true) -, m_notification(0) -{ - if (NULL == m_interface || NULL == m_queue) - { - return; - } - - CFMutableDictionaryRef properties = NULL; - const kern_return_t propertiesResult = - IORegistryEntryCreateCFProperties(device, &properties, kCFAllocatorDefault, kNilOptions); - - if (KERN_SUCCESS != propertiesResult || NULL == properties) - { - Printf(TEXTCOLOR_RED "IORegistryEntryCreateCFProperties() failed with code %i\n", propertiesResult); - return; - } - - GatherDeviceInfo(device, properties); - GatherCollectionElements(properties); - - CFRelease(properties); - - UseAxesPolling(joy_axespolling); - - (*m_queue)->start(m_queue); - - SetDefaultConfig(); -} - -IOKitJoystick::~IOKitJoystick() -{ - M_SaveJoystickConfig(this); - - if (0 != m_notification) - { - IOObjectRelease(m_notification); - } - - if (NULL != m_queue) - { - (*m_queue)->stop(m_queue); - (*m_queue)->dispose(m_queue); - (*m_queue)->Release(m_queue); - } - - if (NULL != m_interface) - { - (*m_interface)->close(m_interface); - (*m_interface)->Release(m_interface); - } -} - - -FString IOKitJoystick::GetName() -{ - return m_name; -} - - -float IOKitJoystick::GetSensitivity() -{ - return m_sensitivity; -} - -void IOKitJoystick::SetSensitivity(float scale) -{ - m_sensitivity = scale; -} - - -int IOKitJoystick::GetNumAxes() -{ - return static_cast(m_axes.Size()); -} - -#define IS_AXIS_VALID (static_cast(axis) < m_axes.Size()) - -float IOKitJoystick::GetAxisDeadZone(int axis) -{ - return IS_AXIS_VALID ? m_axes[axis].deadZone : 0.0f; -} - -EJoyAxis IOKitJoystick::GetAxisMap(int axis) -{ - return IS_AXIS_VALID ? m_axes[axis].gameAxis : JOYAXIS_None; -} - -const char* IOKitJoystick::GetAxisName(int axis) -{ - return IS_AXIS_VALID ? m_axes[axis].name : "Invalid"; -} - -float IOKitJoystick::GetAxisScale(int axis) -{ - return IS_AXIS_VALID ? m_axes[axis].sensitivity : 0.0f; -} - -void IOKitJoystick::SetAxisDeadZone(int axis, float deadZone) -{ - if (IS_AXIS_VALID) - { - m_axes[axis].deadZone = clamp(deadZone, 0.0f, 1.0f); - } -} - -void IOKitJoystick::SetAxisMap(int axis, EJoyAxis gameAxis) -{ - if (IS_AXIS_VALID) - { - m_axes[axis].gameAxis = (gameAxis> JOYAXIS_None && gameAxis = 3) - { - m_axes[0].gameAxis = JOYAXIS_Side; - m_axes[1].gameAxis = JOYAXIS_Forward; - m_axes[2].gameAxis = JOYAXIS_Yaw; - - // Four axes? First two are movement, last two are looking around. - - if (axisCount >= 4) - { - m_axes[3].gameAxis = JOYAXIS_Pitch; -// ??? m_axes[3].sensitivity = 0.75f; - - // Five axes? Use the fifth one for moving up and down. - - if (axisCount >= 5) - { - m_axes[4].gameAxis = JOYAXIS_Up; - } - } - } - - // If there is only one axis, then we make no assumptions about how - // the user might want to use it. - - // Preserve defaults for config saving. - - for (size_t i = 0; i < axisCount; ++i) - { - m_axes[i].defaultDeadZone = m_axes[i].deadZone; - m_axes[i].defaultSensitivity = m_axes[i].sensitivity; - m_axes[i].defaultGameAxis = m_axes[i].gameAxis; - } -} - - -FString IOKitJoystick::GetIdentifier() -{ - return m_identifier; -} - - -void IOKitJoystick::AddAxes(float axes[NUM_JOYAXIS]) const -{ - for (size_t i = 0, count = m_axes.Size(); i < count; ++i) - { - const EJoyAxis axis = m_axes[i].gameAxis; - - if (JOYAXIS_None == axis) - { - continue; - } - - axes[axis] -= m_axes[i].value; - } -} - - -void IOKitJoystick::UseAxesPolling(const bool axesPolling) -{ - m_useAxesPolling = axesPolling; - - for (size_t i = 0, count = m_axes.Size(); i < count; ++i) - { - AnalogAxis& axis = m_axes[i]; - - if (m_useAxesPolling) - { - RemoveFromQueue(axis.cookie); - } - else - { - AddToQueue(axis.cookie); - } - } -} - - -void IOKitJoystick::Update() -{ - if (NULL == m_queue) - { - return; - } - - IOHIDEventStruct event = { }; - AbsoluteTime zeroTime = { }; - - const IOReturn eventResult = (*m_queue)->getNextEvent(m_queue, &event, zeroTime, 0); - - if (kIOReturnSuccess == eventResult) - { - if (use_joystick) - { - ProcessAxis(event) || ProcessButton(event) || ProcessPOV(event); - } - } - else if (kIOReturnUnderrun != eventResult) - { - Printf(TEXTCOLOR_RED "IOHIDQueueInterface::getNextEvent() failed with code 0x%08X\n", eventResult); - } - - ProcessAxes(); -} - - -void IOKitJoystick::ProcessAxes() -{ - if (NULL == m_interface || !m_useAxesPolling) - { - return; - } - - for (size_t i = 0, count = m_axes.Size(); i < count; ++i) - { - AnalogAxis& axis = m_axes[i]; - - static const double scaledMin = -1; - static const double scaledMax = 1; - - IOHIDEventStruct event; - - if (kIOReturnSuccess == (*m_interface)->getElementValue(m_interface, axis.cookie, &event)) - { - const double scaledValue = scaledMin + - (event.value - axis.minValue) * (scaledMax - scaledMin) / (axis.maxValue - axis.minValue); - const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, NULL); - - axis.value = static_cast(filteredValue * m_sensitivity * axis.sensitivity); - } - else - { - axis.value = 0.0f; - } - } -} - - -bool IOKitJoystick::ProcessAxis(const IOHIDEventStruct& event) -{ - if (m_useAxesPolling) - { - return false; - } - - for (size_t i = 0, count = m_axes.Size(); i < count; ++i) - { - if (event.elementCookie != m_axes[i].cookie) - { - continue; - } - - AnalogAxis& axis = m_axes[i]; - - static const double scaledMin = -1; - static const double scaledMax = 1; - - const double scaledValue = scaledMin + - (event.value - axis.minValue) * (scaledMax - scaledMin) / (axis.maxValue - axis.minValue); - const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, NULL); - - axis.value = static_cast(filteredValue * m_sensitivity * axis.sensitivity); - - return true; - } - - return false; -} - -bool IOKitJoystick::ProcessButton(const IOHIDEventStruct& event) -{ - for (size_t i = 0, count = m_buttons.Size(); i < count; ++i) - { - if (event.elementCookie != m_buttons[i].cookie) - { - continue; - } - - int32_t& current = m_buttons[i].value; - const int32_t previous = current; - current = event.value; - - Joy_GenerateButtonEvents(previous, current, 1, static_cast(KEY_FIRSTJOYBUTTON + i)); - - return true; - } - - return false; -} - -bool IOKitJoystick::ProcessPOV(const IOHIDEventStruct& event) -{ - for (size_t i = 0, count = m_POVs.Size(); i ( - CFDictionaryGetValue(properties, CFSTR(kIOHIDManufacturerKey))); - CFStringRef productRef = static_cast( - CFDictionaryGetValue(properties, CFSTR(kIOHIDProductKey))); - CFNumberRef vendorIDRef = static_cast( - CFDictionaryGetValue(properties, CFSTR(kIOHIDVendorIDKey))); - CFNumberRef productIDRef = static_cast( - CFDictionaryGetValue(properties, CFSTR(kIOHIDProductIDKey))); - - CFMutableDictionaryRef usbProperties = NULL; - - if ( NULL == vendorRef || NULL == productRef - || NULL == vendorIDRef || NULL == productIDRef) - { - // OS X is not mirroring all USB properties to HID page, so need to look at USB device page also - // Step up two levels and get dictionary of USB properties - - io_registry_entry_t parent1; - kern_return_t ioResult = IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent1); - - if (KERN_SUCCESS == ioResult) - { - io_registry_entry_t parent2; - ioResult = IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent2); - - if (KERN_SUCCESS == ioResult) - { - ioResult = IORegistryEntryCreateCFProperties(parent2, &usbProperties, kCFAllocatorDefault, kNilOptions); - - if (KERN_SUCCESS != ioResult) - { - Printf(TEXTCOLOR_RED "IORegistryEntryCreateCFProperties() failed with code %i\n", ioResult); - } - - IOObjectRelease(parent2); - } - else - { - Printf(TEXTCOLOR_RED "IORegistryEntryGetParentEntry(2) failed with code %i\n", ioResult); - } - - IOObjectRelease(parent1); - } - else - { - Printf(TEXTCOLOR_RED "IORegistryEntryGetParentEntry(1) failed with code %i\n", ioResult); - } - } - - if (NULL != usbProperties) - { - if (NULL == vendorRef) - { - vendorRef = static_cast( - CFDictionaryGetValue(usbProperties, CFSTR("USB Vendor Name"))); - } - - if (NULL == productRef) - { - productRef = static_cast( - CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name"))); - } - - if (NULL == vendorIDRef) - { - vendorIDRef = static_cast( - CFDictionaryGetValue(usbProperties, CFSTR("idVendor"))); - } - - if (NULL == productIDRef) - { - productIDRef = static_cast( - CFDictionaryGetValue(usbProperties, CFSTR("idProduct"))); - } - } - - m_name += ToFString(vendorRef); - m_name += " "; - m_name += ToFString(productRef); - - int vendorID = 0, productID = 0; - - if (NULL != vendorIDRef) - { - CFNumberGetValue(vendorIDRef, kCFNumberIntType, &vendorID); - } - - if (NULL != productIDRef) - { - CFNumberGetValue(productIDRef, kCFNumberIntType, &productID); - } - - m_identifier.AppendFormat("VID_%04x_PID_%04x", vendorID, productID); - - if (NULL != usbProperties) - { - CFRelease(usbProperties); - } -} - - -long GetElementValue(const CFDictionaryRef element, const CFStringRef key) -{ - const CFNumberRef number = - static_cast(CFDictionaryGetValue(element, key)); - long result = 0; - - if (NULL != number && CFGetTypeID(number) == CFNumberGetTypeID()) - { - CFNumberGetValue(number, kCFNumberLongType, &result); - } - - return result; -} - -void IOKitJoystick::GatherElementsHandler(const void* value, void* parameter) -{ - assert(NULL != value); - assert(NULL != parameter); - - const CFDictionaryRef element = static_cast(value); - IOKitJoystick* thisPtr = static_cast(parameter); - - if (CFGetTypeID(element) != CFDictionaryGetTypeID()) - { - Printf(TEXTCOLOR_RED "IOKitJoystick: Encountered wrong element type\n"); - return; - } - - const long type = GetElementValue(element, CFSTR(kIOHIDElementTypeKey)); - - if (kIOHIDElementTypeCollection == type) - { - thisPtr->GatherCollectionElements(element); - } - else if (0 != type) - { - const long usagePage = GetElementValue(element, CFSTR(kIOHIDElementUsagePageKey)); - - if (kHIDPage_GenericDesktop == usagePage) - { - const long usage = GetElementValue(element, CFSTR(kIOHIDElementUsageKey)); - - if ( kHIDUsage_GD_Slider == usage - || kHIDUsage_GD_X == usage || kHIDUsage_GD_Y == usage || kHIDUsage_GD_Z == usage - || kHIDUsage_GD_Rx == usage || kHIDUsage_GD_Ry == usage || kHIDUsage_GD_Rz == usage) - { - thisPtr->AddAxis(element); - } - else if (kHIDUsage_GD_Hatswitch == usage && thisPtr->m_POVs.Size() < 4) - { - thisPtr->AddPOV(element); - } - } - else if (kHIDPage_Button == usagePage) - { - thisPtr->AddButton(element); - } - } -} - -void IOKitJoystick::GatherCollectionElements(const CFDictionaryRef properties) -{ - const CFArrayRef topElement = static_cast( - CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey))); - - if (NULL == topElement || CFGetTypeID(topElement) != CFArrayGetTypeID()) - { - Printf(TEXTCOLOR_RED "GatherCollectionElements: invalid properties dictionary\n"); - return; - } - - const CFRange range = { 0, CFArrayGetCount(topElement) }; - - CFArrayApplyFunction(topElement, range, GatherElementsHandler, this); -} - - -IOHIDElementCookie GetElementCookie(const CFDictionaryRef element) -{ - // Use C-style cast to avoid 32/64-bit IOHIDElementCookie type issue - return (IOHIDElementCookie)GetElementValue(element, CFSTR(kIOHIDElementCookieKey)); -} - -void IOKitJoystick::AddAxis(const CFDictionaryRef element) -{ - AnalogAxis axis; - - axis.cookie = GetElementCookie(element); - axis.minValue = GetElementValue(element, CFSTR(kIOHIDElementMinKey)); - axis.maxValue = GetElementValue(element, CFSTR(kIOHIDElementMaxKey)); - - const CFStringRef nameRef = static_cast( - CFDictionaryGetValue(element, CFSTR(kIOHIDElementNameKey))); - - if (NULL != nameRef && CFStringGetTypeID() == CFGetTypeID(nameRef)) - { - CFStringGetCString(nameRef, axis.name, sizeof(axis.name) - 1, kCFStringEncodingUTF8); - } - else - { - snprintf(axis.name, sizeof(axis.name), "Axis %i", m_axes.Size() + 1); - } - - m_axes.Push(axis); -} - -void IOKitJoystick::AddButton(CFDictionaryRef element) -{ - const DigitalButton button(GetElementCookie(element)); - - m_buttons.Push(button); - - AddToQueue(button.cookie); -} - -void IOKitJoystick::AddPOV(CFDictionaryRef element) -{ - const DigitalButton pov(GetElementCookie(element)); - - m_POVs.Push(pov); - - AddToQueue(pov.cookie); -} - - -void IOKitJoystick::AddToQueue(const IOHIDElementCookie cookie) -{ - if (NULL == m_queue) - { - return; - } - - if (!(*m_queue)->hasElement(m_queue, cookie)) - { - (*m_queue)->addElement(m_queue, cookie, 0); - } -} - -void IOKitJoystick::RemoveFromQueue(const IOHIDElementCookie cookie) -{ - if (NULL == m_queue) - { - return; - } - - if ((*m_queue)->hasElement(m_queue, cookie)) - { - (*m_queue)->removeElement(m_queue, cookie); - } -} - - -io_object_t* IOKitJoystick::GetNotificationPtr() -{ - return &m_notification; -} - - -// --------------------------------------------------------------------------- - - -class IOKitJoystickManager -{ -public: - IOKitJoystickManager(); - ~IOKitJoystickManager(); - - void GetJoysticks(TArray& joysticks) const; - - void AddAxes(float axes[NUM_JOYAXIS]) const; - - // Updates axes/buttons states - void Update(); - - void UseAxesPolling(bool axesPolling); - -private: - typedef TDeletingArray JoystickList; - JoystickList m_joysticks; - - static const size_t NOTIFICATION_PORT_COUNT = 2; - - IONotificationPortRef m_notificationPorts[NOTIFICATION_PORT_COUNT]; - io_iterator_t m_notifications [NOTIFICATION_PORT_COUNT]; - - // Rebuilds device list - void Rescan(int usagePage, int usage, size_t notificationPortIndex); - void AddDevices(IONotificationPortRef notificationPort, const io_iterator_t iterator); - - static void OnDeviceAttached(void* refcon, io_iterator_t iterator); - static void OnDeviceRemoved(void* refcon, io_service_t service, - natural_t messageType, void* messageArgument); -}; - - -IOKitJoystickManager* s_joystickManager; - - -IOKitJoystickManager::IOKitJoystickManager() -{ - memset(m_notifications, 0, sizeof m_notifications); - - for (size_t i = 0; i < NOTIFICATION_PORT_COUNT; ++i) - { - m_notificationPorts[i] = IONotificationPortCreate(kIOMasterPortDefault); - - if (NULL == m_notificationPorts[i]) - { - Printf(TEXTCOLOR_RED "IONotificationPortCreate(%zu) failed\n", i); - return; - } - - CFRunLoopAddSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(m_notificationPorts[i]), kCFRunLoopDefaultMode); - } - - Rescan(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, 0); - Rescan(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, 1); -} - -IOKitJoystickManager::~IOKitJoystickManager() -{ - for (size_t i = 0; i < NOTIFICATION_PORT_COUNT; ++i) - { - IONotificationPortRef& port = m_notificationPorts[i]; - - if (NULL != port) - { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(port), kCFRunLoopDefaultMode); - - IONotificationPortDestroy(port); - port = NULL; - } - - io_iterator_t& notification = m_notifications[i]; - - if (0 != notification) - { - IOObjectRelease(notification); - notification = 0; - } - } -} - - -void IOKitJoystickManager::GetJoysticks(TArray& joysticks) const -{ - const size_t joystickCount = m_joysticks.Size(); - - joysticks.Resize(joystickCount); - - for (size_t i = 0; i < joystickCount; ++i) - { - M_LoadJoystickConfig(m_joysticks[i]); - - joysticks[i] = m_joysticks[i]; - } -} - -void IOKitJoystickManager::AddAxes(float axes[NUM_JOYAXIS]) const -{ - for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) - { - m_joysticks[i]->AddAxes(axes); - } -} - - -void IOKitJoystickManager::Update() -{ - for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) - { - m_joysticks[i]->Update(); - } -} - - -void IOKitJoystickManager::UseAxesPolling(const bool axesPolling) -{ - for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) - { - m_joysticks[i]->UseAxesPolling(axesPolling); - } -} - - -void PostDeviceChangeEvent() -{ - const event_t event = { EV_DeviceChange }; - D_PostEvent(&event); -} - - -void IOKitJoystickManager::Rescan(const int usagePage, const int usage, const size_t notificationPortIndex) -{ - CFMutableDictionaryRef deviceMatching = IOServiceMatching(kIOHIDDeviceKey); - - if (NULL == deviceMatching) - { - Printf(TEXTCOLOR_RED "IOServiceMatching() returned NULL\n"); - return; - } - - const CFNumberRef usagePageRef = - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage); - CFDictionarySetValue(deviceMatching, CFSTR(kIOHIDPrimaryUsagePageKey), usagePageRef); - - const CFNumberRef usageRef = - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); - CFDictionarySetValue(deviceMatching, CFSTR(kIOHIDPrimaryUsageKey), usageRef); - - assert(notificationPortIndex < NOTIFICATION_PORT_COUNT); - io_iterator_t* iteratorPtr = &m_notifications[notificationPortIndex]; - - const IONotificationPortRef notificationPort = m_notificationPorts[notificationPortIndex]; - assert(NULL != notificationPort); - - const kern_return_t notificationResult = IOServiceAddMatchingNotification(notificationPort, - kIOFirstMatchNotification, deviceMatching, OnDeviceAttached, notificationPort, iteratorPtr); - - // IOServiceAddMatchingNotification() consumes one reference of matching dictionary - // Thus CFRelease(deviceMatching) is not needed - - CFRelease(usageRef); - CFRelease(usagePageRef); - - if (KERN_SUCCESS != notificationResult) - { - Printf(TEXTCOLOR_RED "IOServiceAddMatchingNotification() failed with code %i\n", notificationResult); - } - - AddDevices(notificationPort, *iteratorPtr); -} - -void IOKitJoystickManager::AddDevices(const IONotificationPortRef notificationPort, const io_iterator_t iterator) -{ - while (io_object_t device = IOIteratorNext(iterator)) - { - IOKitJoystick* joystick = new IOKitJoystick(device); - m_joysticks.Push(joystick); - - const kern_return_t notificationResult = IOServiceAddInterestNotification(notificationPort, - device, kIOGeneralInterest, OnDeviceRemoved, joystick, joystick->GetNotificationPtr()); - if (KERN_SUCCESS != notificationResult) - { - Printf(TEXTCOLOR_RED "IOServiceAddInterestNotification() failed with code %i\n", notificationResult); - } - - IOObjectRelease(device); - - PostDeviceChangeEvent(); - } -} - - -void IOKitJoystickManager::OnDeviceAttached(void* const refcon, const io_iterator_t iterator) -{ - assert(NULL != refcon); - const IONotificationPortRef notificationPort = static_cast(refcon); - - assert(NULL != s_joystickManager); - s_joystickManager->AddDevices(notificationPort, iterator); -} - -void IOKitJoystickManager::OnDeviceRemoved(void* const refcon, io_service_t, const natural_t messageType, void*) -{ - if (messageType != kIOMessageServiceIsTerminated) - { - return; - } - - assert(NULL != refcon); - IOKitJoystick* const joystick = static_cast(refcon); - - assert(NULL != s_joystickManager); - JoystickList& joysticks = s_joystickManager->m_joysticks; - - for (unsigned int i = 0, count = joysticks.Size(); i < count; ++i) - { - if (joystick == joysticks[i]) - { - joysticks.Delete(i); - break; - } - } - - delete joystick; - - PostDeviceChangeEvent(); -} - -} // unnamed namespace - - -// --------------------------------------------------------------------------- - - -void I_ShutdownInput() -{ - delete s_joystickManager; - s_joystickManager = NULL; -} - -void I_GetJoysticks(TArray& sticks) -{ - // Instances of IOKitJoystick depend on GameConfig object. - // M_SaveDefaultsFinal() must be called after destruction of IOKitJoystickManager. - // To ensure this, its initialization is moved here. - // As M_LoadDefaults() was already called at this moment, - // the order of atterm's functions will be correct - - if (NULL == s_joystickManager && !Args->CheckParm("-nojoy")) - { - s_joystickManager = new IOKitJoystickManager; - } - - if (NULL != s_joystickManager) - { - s_joystickManager->GetJoysticks(sticks); - } -} - -void I_GetAxes(float axes[NUM_JOYAXIS]) -{ - for (size_t i = 0; i < NUM_JOYAXIS; ++i) - { - axes[i] = 0.0f; - } - - if (use_joystick && NULL != s_joystickManager) - { - s_joystickManager->AddAxes(axes); - } -} - -IJoystickConfig* I_UpdateDeviceList() -{ - // Does nothing, device list is always kept up-to-date - - return NULL; -} - - -// --------------------------------------------------------------------------- - - -void I_ProcessJoysticks() -{ - if (NULL != s_joystickManager) - { - s_joystickManager->Update(); - } -} - - -// --------------------------------------------------------------------------- - - -CUSTOM_CVAR(Bool, joy_axespolling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - if (NULL != s_joystickManager) - { - s_joystickManager->UseAxesPolling(self); - } -} diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm deleted file mode 100644 index d27ccd6dd77..00000000000 --- a/src/posix/cocoa/i_system.mm +++ /dev/null @@ -1,177 +0,0 @@ -/* - ** i_system.mm - ** - **--------------------------------------------------------------------------- - ** Copyright 2012-2018 Alexey Lysiuk - ** All rights reserved. - ** - ** Redistribution and use in source and binary forms, with or without - ** modification, are permitted provided that the following conditions - ** are met: - ** - ** 1. Redistributions of source code must retain the above copyright - ** notice, this list of conditions and the following disclaimer. - ** 2. 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. - ** 3. The name of the author may not be used to endorse or promote products - ** derived from this software without specific prior written permission. - ** - ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - **--------------------------------------------------------------------------- - ** - */ - -#include "i_common.h" - -#include - -#include "i_system.h" -#include "st_console.h" -#include "v_text.h" - - -double PerfToSec, PerfToMillisec; - -void CalculateCPUSpeed() -{ - long long frequency; - size_t size = sizeof frequency; - - if (0 == sysctlbyname("machdep.tsc.frequency", &frequency, &size, nullptr, 0) && 0 != frequency) - { - PerfToSec = 1.0 / frequency; - PerfToMillisec = 1000.0 / frequency; - - if (!batchrun) - { - Printf("CPU speed: %.0f MHz\n", 0.001 / PerfToMillisec); - } - } -} - - -void I_SetIWADInfo() -{ - FConsoleWindow::GetInstance().SetTitleText(); -} - - -void I_DebugPrint(const char *cp) -{ - NSLog(@"%s", cp); -} - - -void I_PrintStr(const char* const message) -{ - FConsoleWindow::GetInstance().AddText(message); - - // Strip out any color escape sequences before writing to output - char* const copy = new char[strlen(message) + 1]; - const char* srcp = message; - char* dstp = copy; - - while ('\0' != *srcp) - { - if (TEXTCOLOR_ESCAPE == *srcp) - { - if ('\0' != srcp[1]) - { - srcp += 2; - } - else - { - break; - } - } - else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character - { - *dstp++ = '-'; - ++srcp; - } - else if (0x1e == *srcp) // Middle bar character - { - *dstp++ = '='; - ++srcp; - } - else - { - *dstp++ = *srcp++; - } - } - - *dstp = '\0'; - - fputs(copy, stdout); - delete[] copy; - fflush(stdout); -} - - -void Mac_I_FatalError(const char* const message); - -void I_ShowFatalError(const char *message) -{ - Mac_I_FatalError(message); -} - - -int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad) -{ - if (!showwin) - { - return defaultiwad; - } - - I_SetMainWindowVisible(false); - - extern int I_PickIWad_Cocoa(WadStuff*, int, bool, int); - const int result = I_PickIWad_Cocoa(wads, numwads, showwin, defaultiwad); - - I_SetMainWindowVisible(true); - - return result; -} - - -void I_PutInClipboard(const char* const string) -{ - NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; - NSString* const stringType = NSStringPboardType; - NSArray* const types = [NSArray arrayWithObjects:stringType, nil]; - NSString* const content = [NSString stringWithUTF8String:string]; - - [pasteBoard declareTypes:types - owner:nil]; - [pasteBoard setString:content - forType:stringType]; -} - -FString I_GetFromClipboard(bool returnNothing) -{ - if (returnNothing) - { - return FString(); - } - - NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; - NSString* const value = [pasteBoard stringForType:NSStringPboardType]; - - return FString([value UTF8String]); -} - - -unsigned int I_MakeRNGSeed() -{ - return static_cast(arc4random()); -} diff --git a/src/posix/i_steam.cpp b/src/posix/i_steam.cpp index dccadb0218d..f65478f3ea4 100644 --- a/src/posix/i_steam.cpp +++ b/src/posix/i_steam.cpp @@ -38,7 +38,7 @@ #include "m_misc.h" #endif // __APPLE__ -#include "doomerrors.h" +#include "engineerrors.h" #include "d_main.h" #include "sc_man.h" #include "cmdlib.h" @@ -160,7 +160,11 @@ static struct SteamAppInfo {"Hexen Deathkings of the Dark Citadel/base", 2370}, {"Ultimate Doom/base", 2280}, {"DOOM 3 BFG Edition/base/wads", 208200}, - {"Strife", 317040} + {"Strife", 317040}, + {"Ultimate Doom/rerelease/DOOM_Data/StreamingAssets", 2280}, + {"Doom 2/rerelease/DOOM II_Data/StreamingAssets", 2300}, + {"Doom 2/finaldoombase", 2300}, + {"Master Levels of Doom/doom2", 9160} }; TArray I_GetSteamPath() @@ -176,7 +180,7 @@ TArray I_GetSteamPath() FString regPath = appSupportPath + "/Steam/config/config.vdf"; try { - SteamInstallFolders = ParseSteamRegistry(regPath); + SteamInstallFolders = ParseSteamRegistry(regPath.GetChars()); } catch(class CRecoverableError &error) { @@ -184,7 +188,7 @@ TArray I_GetSteamPath() return result; } - SteamInstallFolders.Push(appSupportPath + "/Steam/SteamApps/common"); + SteamInstallFolders.Push(appSupportPath + "/Steam/steamapps/common"); #else char* home = getenv("HOME"); if(home != NULL && *home != '\0') @@ -195,11 +199,11 @@ TArray I_GetSteamPath() // .steam at some point. Not sure if it's just my setup so I guess we // can fall back on it? if(!FileExists(regPath)) - regPath.Format("%s/.local/share/Steam/config/config.vdf", home); + regPath.Format("%s/.steam/steam/config/config.vdf", home); try { - SteamInstallFolders = ParseSteamRegistry(regPath); + SteamInstallFolders = ParseSteamRegistry(regPath.GetChars()); } catch(class CRecoverableError &error) { @@ -207,7 +211,7 @@ TArray I_GetSteamPath() return result; } - regPath.Format("%s/.local/share/Steam/SteamApps/common", home); + regPath.Format("%s/.steam/steam/steamapps/common", home); SteamInstallFolders.Push(regPath); } #endif @@ -218,10 +222,16 @@ TArray I_GetSteamPath() { struct stat st; FString candidate(SteamInstallFolders[i] + "/" + AppInfo[app].BasePath); - if(DirExists(candidate)) + if(DirExists(candidate.GetChars())) result.Push(candidate); } } return result; } + +TArray I_GetGogPaths() +{ + // GOG's Doom games are Windows only at the moment + return TArray(); +} diff --git a/src/posix/i_system.h b/src/posix/i_system.h deleted file mode 100644 index e4c3d68dbf5..00000000000 --- a/src/posix/i_system.h +++ /dev/null @@ -1,157 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// System specific interface stuff. -// -//----------------------------------------------------------------------------- - - -#ifndef __I_SYSTEM__ -#define __I_SYSTEM__ - -#include -#include - -#if defined(__sun) || defined(__sun__) || defined(__SRV4) || defined(__srv4__) -#define __solaris__ 1 -#endif - -#include "doomtype.h" -#include -#include - -struct ticcmd_t; -struct WadStuff; - -#ifndef SHARE_DIR -#define SHARE_DIR "/usr/local/share/" -#endif - - -// Called by DoomMain. -void I_Init (void); - -// Return a seed value for the RNG. -unsigned int I_MakeRNGSeed(); - - -// -// Called by D_DoomLoop, -// called before processing any tics in a frame -// (just after displaying a frame). -// Time consuming syncronous operations -// are performed here (joystick reading). -// Can call D_PostEvent. -// -void I_StartFrame (void); - - -// -// Called by D_DoomLoop, -// called before processing each tic in a frame. -// Quick syncronous operations are performed here. -// Can call D_PostEvent. -void I_StartTic (void); - -// Asynchronous interrupt functions should maintain private queues -// that are read by the synchronous functions -// to be converted into events. - -// Either returns a null ticcmd, -// or calls a loadable driver to build it. -// This ticcmd will then be modified by the gameloop -// for normal input. -ticcmd_t *I_BaseTiccmd (void); - -void I_Tactile (int on, int off, int total); - -void I_DebugPrint (const char *cp); - -// Print a console string -void I_PrintStr (const char *str); - -// Set the title string of the startup window -void I_SetIWADInfo (); - -// Pick from multiple IWADs to use -int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad); - -// [RH] Checks the registry for Steam's install path, so we can scan its -// directories for IWADs if the user purchased any through Steam. -TArray I_GetSteamPath(); - -TArray I_GetGogPaths(); - -// The ini could not be saved at exit -bool I_WriteIniFailed (); - -class FTexture; -bool I_SetCursor(FTexture *); - -// Directory searching routines - -struct findstate_t -{ -private: - FString path; - struct dirent **namelist; - int current; - int count; - - friend void *I_FindFirst(const char *filespec, findstate_t *fileinfo); - friend int I_FindNext(void *handle, findstate_t *fileinfo); - friend const char *I_FindName(findstate_t *fileinfo); - friend int I_FindAttr(findstate_t *fileinfo); - friend int I_FindClose(void *handle); -}; - -void *I_FindFirst (const char *filespec, findstate_t *fileinfo); -int I_FindNext (void *handle, findstate_t *fileinfo); -int I_FindClose (void *handle); -int I_FindAttr (findstate_t *fileinfo); - -inline const char *I_FindName(findstate_t *fileinfo) -{ - return (fileinfo->namelist[fileinfo->current]->d_name); -} - -#define FA_RDONLY 1 -#define FA_HIDDEN 2 -#define FA_SYSTEM 4 -#define FA_DIREC 8 -#define FA_ARCH 16 - -static inline char *strlwr(char *str) -{ - char *ptr = str; - while(*ptr) - { - *ptr = tolower(*ptr); - ++ptr; - } - return str; -} - -inline int I_GetNumaNodeCount() { return 1; } -inline int I_GetNumaNodeThreadCount(int numaNode) { return std::max(std::thread::hardware_concurrency(), 1); } -inline void I_SetThreadNumaNode(std::thread &thread, int numaNode) { } - -#endif diff --git a/src/posix/i_system_posix.cpp b/src/posix/i_system_posix.cpp deleted file mode 100644 index 0f4f5599c16..00000000000 --- a/src/posix/i_system_posix.cpp +++ /dev/null @@ -1,156 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// - -#include - -#ifdef __APPLE__ -#include -#endif // __APPLE__ - -#include "cmdlib.h" -#include "d_protocol.h" -#include "i_system.h" -#include "gameconfigfile.h" -#include "x86.h" - - -void I_Tactile(int /*on*/, int /*off*/, int /*total*/) -{ -} - -static ticcmd_t emptycmd; - -ticcmd_t *I_BaseTiccmd() -{ - return &emptycmd; -} - -// -// I_Init -// -void I_Init() -{ - extern void CalculateCPUSpeed(); - - CheckCPUID(&CPU); - CalculateCPUSpeed(); - DumpCPUInfo(&CPU); -} - - -bool I_WriteIniFailed() -{ - printf("The config file %s could not be saved:\n%s\n", GameConfig->GetPathName(), strerror(errno)); - return false; // return true to retry -} - - -static const char *pattern; - -#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED < 1080 -static int matchfile(struct dirent *ent) -#else -static int matchfile(const struct dirent *ent) -#endif -{ - return fnmatch(pattern, ent->d_name, FNM_NOESCAPE) == 0; -} - -void *I_FindFirst(const char *const filespec, findstate_t *const fileinfo) -{ - FString dir; - - const char *const slash = strrchr(filespec, '/'); - - if (slash) - { - pattern = slash + 1; - dir = FString(filespec, slash - filespec + 1); - fileinfo->path = dir; - } - else - { - pattern = filespec; - dir = "."; - } - - fileinfo->current = 0; - fileinfo->count = scandir(dir.GetChars(), &fileinfo->namelist, matchfile, alphasort); - - if (fileinfo->count > 0) - { - return fileinfo; - } - - return (void *)-1; -} - -int I_FindNext(void *const handle, findstate_t *const fileinfo) -{ - findstate_t *const state = static_cast(handle); - - if (state->current < fileinfo->count) - { - return ++state->current < fileinfo->count ? 0 : -1; - } - - return -1; -} - -int I_FindClose(void *const handle) -{ - findstate_t *const state = static_cast(handle); - - if (handle != (void *)-1 && state->count > 0) - { - for (int i = 0; i < state->count; ++i) - { - free(state->namelist[i]); - } - - free(state->namelist); - state->namelist = nullptr; - state->count = 0; - } - - return 0; -} - -int I_FindAttr(findstate_t *const fileinfo) -{ - dirent *const ent = fileinfo->namelist[fileinfo->current]; - const FString path = fileinfo->path + ent->d_name; - bool isdir; - - if (DirEntryExists(path, &isdir)) - { - return isdir ? FA_DIREC : 0; - } - - return 0; -} - - -TArray I_GetGogPaths() -{ - // GOG's Doom games are Windows only at the moment - return TArray(); -} diff --git a/src/posix/osx/zdoom-info.plist b/src/posix/osx/zdoom-info.plist index f0bbbf3d983..cb386fec7b8 100644 --- a/src/posix/osx/zdoom-info.plist +++ b/src/posix/osx/zdoom-info.plist @@ -23,7 +23,7 @@ LSApplicationCategoryType public.app-category.action-games LSMinimumSystemVersion - 10.9 + 10.13 CFBundleDocumentTypes diff --git a/src/posix/sdl/hardware.cpp b/src/posix/sdl/hardware.cpp deleted file mode 100644 index 9493b7c4874..00000000000 --- a/src/posix/sdl/hardware.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* -** hardware.cpp -** Somewhat OS-independant interface to the screen, mouse, keyboard, and stick -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include - -#include "i_system.h" -#include "hardware.h" -#include "c_dispatch.h" -#include "v_text.h" -#include "doomstat.h" -#include "m_argv.h" -#include "doomerrors.h" -#include "swrenderer/r_swrenderer.h" - -IVideo *Video; - -void I_RestartRenderer(); - - -void I_ShutdownGraphics () -{ - if (screen) - { - DFrameBuffer *s = screen; - screen = NULL; - delete s; - } - if (Video) - delete Video, Video = NULL; - - SDL_QuitSubSystem (SDL_INIT_VIDEO); -} - -void I_InitGraphics () -{ -#ifdef __APPLE__ - SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "0"); -#endif // __APPLE__ - - if (SDL_InitSubSystem (SDL_INIT_VIDEO) < 0) - { - I_FatalError ("Could not initialize SDL video:\n%s\n", SDL_GetError()); - return; - } - - Printf("Using video driver %s\n", SDL_GetCurrentVideoDriver()); - - extern IVideo *gl_CreateVideo(); - Video = gl_CreateVideo(); - - if (Video == NULL) - I_FatalError ("Failed to initialize display"); -} diff --git a/src/posix/sdl/i_input.cpp b/src/posix/sdl/i_input.cpp deleted file mode 100644 index 77e6f1860b5..00000000000 --- a/src/posix/sdl/i_input.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/* -** i_input.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2005-2016 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ -#include -#include "doomtype.h" -#include "doomdef.h" -#include "doomstat.h" -#include "m_argv.h" -#include "v_video.h" - -#include "d_main.h" -#include "d_event.h" -#include "d_gui.h" -#include "c_console.h" -#include "c_dispatch.h" -#include "dikeys.h" -#include "events.h" -#include "g_game.h" -#include "g_levellocals.h" -#include "utf8.h" -#include "doomerrors.h" - - -static void I_CheckGUICapture (); -static void I_CheckNativeMouse (); - -bool GUICapture; -static bool NativeMouse = true; - -extern int paused; - -CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - - -extern int WaitingForKey, chatmodeon; -extern constate_e ConsoleState; - -static const SDL_Keycode DIKToKeySym[256] = -{ - 0, SDLK_ESCAPE, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6, - SDLK_7, SDLK_8, SDLK_9, SDLK_0,SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSPACE, SDLK_TAB, - SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, SDLK_i, - SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, SDLK_RETURN, SDLK_LCTRL, SDLK_a, SDLK_s, - SDLK_d, SDLK_f, SDLK_g, SDLK_h, SDLK_j, SDLK_k, SDLK_l, SDLK_SEMICOLON, - SDLK_QUOTE, SDLK_BACKQUOTE, SDLK_LSHIFT, SDLK_BACKSLASH, SDLK_z, SDLK_x, SDLK_c, SDLK_v, - SDLK_b, SDLK_n, SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH, SDLK_RSHIFT, SDLK_KP_MULTIPLY, - SDLK_LALT, SDLK_SPACE, SDLK_CAPSLOCK, SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, - SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_NUMLOCKCLEAR, SDLK_SCROLLLOCK, SDLK_KP_7, - SDLK_KP_8, SDLK_KP_9, SDLK_KP_MINUS, SDLK_KP_4, SDLK_KP_5, SDLK_KP_6, SDLK_KP_PLUS, SDLK_KP_1, - SDLK_KP_2, SDLK_KP_3, SDLK_KP_0, SDLK_KP_PERIOD, 0, 0, 0, SDLK_F11, - SDLK_F12, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, SDLK_F13, SDLK_F14, SDLK_F15, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, SDLK_KP_EQUALS, 0, 0, - 0, SDLK_AT, SDLK_COLON, 0, 0, 0, 0, 0, - 0, 0, 0, 0, SDLK_KP_ENTER, SDLK_RCTRL, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, SDLK_KP_COMMA, 0, SDLK_KP_DIVIDE, 0, SDLK_SYSREQ, - SDLK_RALT, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, SDLK_PAUSE, 0, SDLK_HOME, - SDLK_UP, SDLK_PAGEUP, 0, SDLK_LEFT, 0, SDLK_RIGHT, 0, SDLK_END, - SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE, 0, 0, 0, 0, - 0, 0, 0, SDLK_LGUI, SDLK_RGUI, SDLK_MENU, SDLK_POWER, SDLK_SLEEP, - 0, 0, 0, 0, 0, SDLK_AC_SEARCH, SDLK_AC_BOOKMARKS, SDLK_AC_REFRESH, - SDLK_AC_STOP, SDLK_AC_FORWARD, SDLK_AC_BACK, SDLK_COMPUTER, SDLK_MAIL, SDLK_MEDIASELECT, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const SDL_Scancode DIKToKeyScan[256] = -{ - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6, - SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9, SDL_SCANCODE_0 ,SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, SDL_SCANCODE_BACKSPACE, SDL_SCANCODE_TAB, - SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, SDL_SCANCODE_T, SDL_SCANCODE_Y, SDL_SCANCODE_U, SDL_SCANCODE_I, - SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_RETURN, SDL_SCANCODE_LCTRL, SDL_SCANCODE_A, SDL_SCANCODE_S, - SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H, SDL_SCANCODE_J, SDL_SCANCODE_K, SDL_SCANCODE_L, SDL_SCANCODE_SEMICOLON, - SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_GRAVE, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_BACKSLASH, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V, - SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M, SDL_SCANCODE_COMMA, SDL_SCANCODE_PERIOD, SDL_SCANCODE_SLASH, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_KP_MULTIPLY, - SDL_SCANCODE_LALT, SDL_SCANCODE_SPACE, SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_F1, SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5, - SDL_SCANCODE_F6, SDL_SCANCODE_F7, SDL_SCANCODE_F8, SDL_SCANCODE_F9, SDL_SCANCODE_F10, SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_KP_7, - SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_4, SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_KP_1, - SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_0, SDL_SCANCODE_KP_PERIOD, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F11, - SDL_SCANCODE_F12, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_EQUALS, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_RCTRL, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_COMMA, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_SYSREQ, - SDL_SCANCODE_RALT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_PAUSE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_HOME, - SDL_SCANCODE_UP, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_END, - SDL_SCANCODE_DOWN, SDL_SCANCODE_PAGEDOWN, SDL_SCANCODE_INSERT, SDL_SCANCODE_DELETE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LGUI, SDL_SCANCODE_RGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_POWER, SDL_SCANCODE_SLEEP, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_AC_SEARCH, SDL_SCANCODE_AC_BOOKMARKS, SDL_SCANCODE_AC_REFRESH, - SDL_SCANCODE_AC_STOP, SDL_SCANCODE_AC_FORWARD, SDL_SCANCODE_AC_BACK, SDL_SCANCODE_COMPUTER, SDL_SCANCODE_MAIL, SDL_SCANCODE_MEDIASELECT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN -}; - -static TMap InitKeySymMap () -{ - TMap KeySymToDIK; - - for (int i = 0; i < 256; ++i) - { - KeySymToDIK[DIKToKeySym[i]] = i; - } - KeySymToDIK[0] = 0; - KeySymToDIK[SDLK_RSHIFT] = DIK_LSHIFT; - KeySymToDIK[SDLK_RCTRL] = DIK_LCONTROL; - KeySymToDIK[SDLK_RALT] = DIK_LMENU; - // Depending on your Linux flavor, you may get SDLK_PRINT or SDLK_SYSREQ - KeySymToDIK[SDLK_PRINTSCREEN] = DIK_SYSRQ; - - return KeySymToDIK; -} -static const TMap KeySymToDIK(InitKeySymMap()); - -static TMap InitKeyScanMap () -{ - TMap KeyScanToDIK; - - for (int i = 0; i < 256; ++i) - { - KeyScanToDIK[DIKToKeyScan[i]] = i; - } - - return KeyScanToDIK; -} -static const TMap KeyScanToDIK(InitKeyScanMap()); - -static void I_CheckGUICapture () -{ - bool wantCapt; - - if (menuactive == MENU_Off) - { - wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon; - } - else - { - wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause); - } - - // [ZZ] check active event handlers that want the UI processing - if (!wantCapt && primaryLevel->localEventManager->CheckUiProcessors()) - wantCapt = true; - - if (wantCapt != GUICapture) - { - GUICapture = wantCapt; - ResetButtonStates(); - } -} - -void I_SetMouseCapture() -{ - // Clear out any mouse movement. - SDL_GetRelativeMouseState (NULL, NULL); - SDL_SetRelativeMouseMode (SDL_TRUE); -} - -void I_ReleaseMouseCapture() -{ - SDL_SetRelativeMouseMode (SDL_FALSE); -} - -static void PostMouseMove (int x, int y) -{ - static int lastx = 0, lasty = 0; - event_t ev = { 0,0,0,0,0,0,0 }; - - if (m_filter) - { - ev.x = (x + lastx) / 2; - ev.y = (y + lasty) / 2; - } - else - { - ev.x = x; - ev.y = y; - } - lastx = x; - lasty = y; - if (ev.x | ev.y) - { - ev.type = EV_Mouse; - D_PostEvent (&ev); - } -} - -static void MouseRead () -{ - int x, y; - - if (NativeMouse) - { - return; - } - - SDL_GetRelativeMouseState (&x, &y); - if (!m_noprescale) - { - x *= 3; - y *= 2; - } - if (x | y) - { - PostMouseMove (x, -y); - } -} - -CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) -{ - if (self < 0) self = 0; - else if (self > 2) self = 2; -} - -static bool inGame() -{ - switch (mouse_capturemode) - { - default: - case 0: - return gamestate == GS_LEVEL; - case 1: - return gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_FINALE; - case 2: - return true; - } -} - -static void I_CheckNativeMouse () -{ - bool focus = SDL_GetKeyboardFocus() != NULL; - bool fs = screen->IsFullscreen(); - - bool wantNative = !focus || (!use_mouse || GUICapture || paused || demoplayback || !inGame()); - - if (wantNative != NativeMouse) - { - NativeMouse = wantNative; - SDL_ShowCursor (wantNative); - if (wantNative) - I_ReleaseMouseCapture (); - else - I_SetMouseCapture (); - } -} - -void MessagePump (const SDL_Event &sev) -{ - static int lastx = 0, lasty = 0; - int x, y; - event_t event = { 0,0,0,0,0,0,0 }; - - switch (sev.type) - { - case SDL_QUIT: - throw CExitEvent(0); - - case SDL_WINDOWEVENT: - extern void ProcessSDLWindowEvent(const SDL_WindowEvent &); - ProcessSDLWindowEvent(sev.window); - break; - - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - if (!GUICapture) - { - event.type = sev.type == SDL_MOUSEBUTTONDOWN ? EV_KeyDown : EV_KeyUp; - - switch (sev.button.button) - { - case SDL_BUTTON_LEFT: event.data1 = KEY_MOUSE1; break; - case SDL_BUTTON_MIDDLE: event.data1 = KEY_MOUSE3; break; - case SDL_BUTTON_RIGHT: event.data1 = KEY_MOUSE2; break; - case SDL_BUTTON_X1: event.data1 = KEY_MOUSE4; break; - case SDL_BUTTON_X2: event.data1 = KEY_MOUSE5; break; - case 6: event.data1 = KEY_MOUSE6; break; - case 7: event.data1 = KEY_MOUSE7; break; - case 8: event.data1 = KEY_MOUSE8; break; - default: printf("SDL mouse button %s %d\n", - sev.type == SDL_MOUSEBUTTONDOWN ? "down" : "up", sev.button.button); break; - } - - if (event.data1 != 0) - { - D_PostEvent(&event); - } - } - else if ((sev.button.button >= SDL_BUTTON_LEFT && sev.button.button <= SDL_BUTTON_X2)) - { - int x, y; - SDL_GetMouseState(&x, &y); - - event.type = EV_GUI_Event; - event.data1 = x; - event.data2 = y; - - screen->ScaleCoordsFromWindow(event.data1, event.data2); - - if (sev.type == SDL_MOUSEBUTTONDOWN) - { - switch(sev.button.button) - { - case SDL_BUTTON_LEFT: event.subtype = EV_GUI_LButtonDown; break; - case SDL_BUTTON_MIDDLE: event.subtype = EV_GUI_MButtonDown; break; - case SDL_BUTTON_RIGHT: event.subtype = EV_GUI_RButtonDown; break; - case SDL_BUTTON_X1: event.subtype = EV_GUI_BackButtonDown; break; - case SDL_BUTTON_X2: event.subtype = EV_GUI_FwdButtonDown; break; - default: assert(false); event.subtype = EV_GUI_None; break; - } - } - else - { - switch(sev.button.button) - { - case SDL_BUTTON_LEFT: event.subtype = EV_GUI_LButtonUp; break; - case SDL_BUTTON_MIDDLE: event.subtype = EV_GUI_MButtonUp; break; - case SDL_BUTTON_RIGHT: event.subtype = EV_GUI_RButtonUp; break; - case SDL_BUTTON_X1: event.subtype = EV_GUI_BackButtonUp; break; - case SDL_BUTTON_X2: event.subtype = EV_GUI_FwdButtonUp; break; - default: assert(false); event.subtype = EV_GUI_None; break; - } - } - - SDL_Keymod kmod = SDL_GetModState(); - event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | - ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | - ((kmod & KMOD_ALT) ? GKM_ALT : 0); - - D_PostEvent(&event); - } - break; - - case SDL_MOUSEMOTION: - if (GUICapture) - { - event.data1 = sev.motion.x; - event.data2 = sev.motion.y; - - screen->ScaleCoordsFromWindow(event.data1, event.data2); - - event.type = EV_GUI_Event; - event.subtype = EV_GUI_MouseMove; - - SDL_Keymod kmod = SDL_GetModState(); - event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | - ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | - ((kmod & KMOD_ALT) ? GKM_ALT : 0); - - D_PostEvent(&event); - } - break; - - case SDL_MOUSEWHEEL: - if (GUICapture) - { - event.type = EV_GUI_Event; - - if (sev.wheel.y == 0) - event.subtype = sev.wheel.x > 0 ? EV_GUI_WheelRight : EV_GUI_WheelLeft; - else - event.subtype = sev.wheel.y > 0 ? EV_GUI_WheelUp : EV_GUI_WheelDown; - - SDL_Keymod kmod = SDL_GetModState(); - event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | - ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | - ((kmod & KMOD_ALT) ? GKM_ALT : 0); - - D_PostEvent (&event); - } - else - { - event.type = EV_KeyDown; - - if (sev.wheel.y != 0) - event.data1 = sev.wheel.y > 0 ? KEY_MWHEELUP : KEY_MWHEELDOWN; - else - event.data1 = sev.wheel.x > 0 ? KEY_MWHEELRIGHT : KEY_MWHEELLEFT; - - D_PostEvent (&event); - event.type = EV_KeyUp; - D_PostEvent (&event); - } - break; - - case SDL_KEYDOWN: - case SDL_KEYUP: - if (!GUICapture) - { - if (sev.key.repeat) - { - break; - } - - event.type = sev.type == SDL_KEYDOWN ? EV_KeyDown : EV_KeyUp; - - // Try to look up our key mapped key for conversion to DirectInput. - // If that fails, then we'll do a lookup against the scan code, - // which may not return the right key, but at least the key should - // work in the game. - if (const uint8_t *dik = KeySymToDIK.CheckKey (sev.key.keysym.sym)) - event.data1 = *dik; - else if (const uint8_t *dik = KeyScanToDIK.CheckKey (sev.key.keysym.scancode)) - event.data1 = *dik; - - if (event.data1) - { - if (sev.key.keysym.sym < 256) - { - event.data2 = sev.key.keysym.sym; - } - D_PostEvent (&event); - } - } - else - { - event.type = EV_GUI_Event; - event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp; - SDL_Keymod kmod = SDL_GetModState(); - event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | - ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | - ((kmod & KMOD_ALT) ? GKM_ALT : 0); - - if (event.subtype == EV_GUI_KeyDown && sev.key.repeat) - { - event.subtype = EV_GUI_KeyRepeat; - } - - switch (sev.key.keysym.sym) - { - case SDLK_KP_ENTER: event.data1 = GK_RETURN; break; - case SDLK_PAGEUP: event.data1 = GK_PGUP; break; - case SDLK_PAGEDOWN: event.data1 = GK_PGDN; break; - case SDLK_END: event.data1 = GK_END; break; - case SDLK_HOME: event.data1 = GK_HOME; break; - case SDLK_LEFT: event.data1 = GK_LEFT; break; - case SDLK_RIGHT: event.data1 = GK_RIGHT; break; - case SDLK_UP: event.data1 = GK_UP; break; - case SDLK_DOWN: event.data1 = GK_DOWN; break; - case SDLK_DELETE: event.data1 = GK_DEL; break; - case SDLK_ESCAPE: event.data1 = GK_ESCAPE; break; - case SDLK_F1: event.data1 = GK_F1; break; - case SDLK_F2: event.data1 = GK_F2; break; - case SDLK_F3: event.data1 = GK_F3; break; - case SDLK_F4: event.data1 = GK_F4; break; - case SDLK_F5: event.data1 = GK_F5; break; - case SDLK_F6: event.data1 = GK_F6; break; - case SDLK_F7: event.data1 = GK_F7; break; - case SDLK_F8: event.data1 = GK_F8; break; - case SDLK_F9: event.data1 = GK_F9; break; - case SDLK_F10: event.data1 = GK_F10; break; - case SDLK_F11: event.data1 = GK_F11; break; - case SDLK_F12: event.data1 = GK_F12; break; - default: - if (sev.key.keysym.sym < 256) - { - event.data1 = sev.key.keysym.sym; - } - break; - } - if (event.data1 < 128) - { - event.data1 = toupper(event.data1); - D_PostEvent (&event); - } - } - break; - - case SDL_TEXTINPUT: - if (GUICapture) - { - int size; - - int unichar = utf8_decode((const uint8_t*)sev.text.text, &size); - if (size != 4) - { - event.type = EV_GUI_Event; - event.subtype = EV_GUI_Char; - event.data1 = (int16_t)unichar; - event.data2 = !!(SDL_GetModState() & KMOD_ALT); - D_PostEvent (&event); - } - } - break; - - case SDL_JOYBUTTONDOWN: - case SDL_JOYBUTTONUP: - if (!GUICapture) - { - event.type = sev.type == SDL_JOYBUTTONDOWN ? EV_KeyDown : EV_KeyUp; - event.data1 = KEY_FIRSTJOYBUTTON + sev.jbutton.button; - if(event.data1 != 0) - D_PostEvent(&event); - } - break; - } -} - -void I_GetEvent () -{ - SDL_Event sev; - - while (SDL_PollEvent (&sev)) - { - MessagePump (sev); - } - if (use_mouse) - { - MouseRead (); - } -} - -void I_StartTic () -{ - I_CheckGUICapture (); - I_CheckNativeMouse (); - I_GetEvent (); -} - -void I_ProcessJoysticks (); -void I_StartFrame () -{ - I_ProcessJoysticks(); -} diff --git a/src/posix/sdl/i_joystick.cpp b/src/posix/sdl/i_joystick.cpp deleted file mode 100644 index 14015550b63..00000000000 --- a/src/posix/sdl/i_joystick.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/* -** i_joystick.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2005-2016 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ -#include - -#include "doomdef.h" -#include "templates.h" -#include "m_joy.h" - -// Very small deadzone so that floating point magic doesn't happen -#define MIN_DEADZONE 0.000001f - -class SDLInputJoystick: public IJoystickConfig -{ -public: - SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f) - { - Device = SDL_JoystickOpen(DeviceIndex); - if(Device != NULL) - { - NumAxes = SDL_JoystickNumAxes(Device); - NumHats = SDL_JoystickNumHats(Device); - - SetDefaultConfig(); - } - } - ~SDLInputJoystick() - { - if(Device != NULL) - M_SaveJoystickConfig(this); - SDL_JoystickClose(Device); - } - - bool IsValid() const - { - return Device != NULL; - } - - FString GetName() - { - return SDL_JoystickName(Device); - } - float GetSensitivity() - { - return Multiplier; - } - void SetSensitivity(float scale) - { - Multiplier = scale; - } - - int GetNumAxes() - { - return NumAxes + NumHats*2; - } - float GetAxisDeadZone(int axis) - { - return Axes[axis].DeadZone; - } - EJoyAxis GetAxisMap(int axis) - { - return Axes[axis].GameAxis; - } - const char *GetAxisName(int axis) - { - return Axes[axis].Name.GetChars(); - } - float GetAxisScale(int axis) - { - return Axes[axis].Multiplier; - } - - void SetAxisDeadZone(int axis, float zone) - { - Axes[axis].DeadZone = clamp(zone, MIN_DEADZONE, 1.f); - } - void SetAxisMap(int axis, EJoyAxis gameaxis) - { - Axes[axis].GameAxis = gameaxis; - } - void SetAxisScale(int axis, float scale) - { - Axes[axis].Multiplier = scale; - } - - // Used by the saver to not save properties that are at their defaults. - bool IsSensitivityDefault() - { - return Multiplier == 1.0f; - } - bool IsAxisDeadZoneDefault(int axis) - { - return Axes[axis].DeadZone <= MIN_DEADZONE; - } - bool IsAxisMapDefault(int axis) - { - if(axis >= 5) - return Axes[axis].GameAxis == JOYAXIS_None; - return Axes[axis].GameAxis == DefaultAxes[axis]; - } - bool IsAxisScaleDefault(int axis) - { - return Axes[axis].Multiplier == 1.0f; - } - - void SetDefaultConfig() - { - for(int i = 0;i < GetNumAxes();i++) - { - AxisInfo info; - if(i < NumAxes) - info.Name.Format("Axis %d", i+1); - else - info.Name.Format("Hat %d (%c)", (i-NumAxes)/2 + 1, (i-NumAxes)%2 == 0 ? 'x' : 'y'); - info.DeadZone = MIN_DEADZONE; - info.Multiplier = 1.0f; - info.Value = 0.0; - info.ButtonValue = 0; - if(i >= 5) - info.GameAxis = JOYAXIS_None; - else - info.GameAxis = DefaultAxes[i]; - Axes.Push(info); - } - } - FString GetIdentifier() - { - char id[16]; - mysnprintf(id, countof(id), "JS:%d", DeviceIndex); - return id; - } - - void AddAxes(float axes[NUM_JOYAXIS]) - { - // Add to game axes. - for (int i = 0; i < GetNumAxes(); ++i) - { - if(Axes[i].GameAxis != JOYAXIS_None) - axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier); - } - } - - void ProcessInput() - { - uint8_t buttonstate; - - for (int i = 0; i < NumAxes; ++i) - { - buttonstate = 0; - - Axes[i].Value = SDL_JoystickGetAxis(Device, i)/32767.0; - Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate); - - // Map button to axis - // X and Y are handled differently so if we have 2 or more axes then we'll use that code instead. - if (NumAxes == 1 || (i >= 2 && i < NUM_JOYAXISBUTTONS)) - { - Joy_GenerateButtonEvents(Axes[i].ButtonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2); - Axes[i].ButtonValue = buttonstate; - } - } - - if(NumAxes > 1) - { - buttonstate = Joy_XYAxesToButtons(Axes[0].Value, Axes[1].Value); - Joy_GenerateButtonEvents(Axes[0].ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS); - Axes[0].ButtonValue = buttonstate; - } - - // Map POV hats to buttons and axes. Why axes? Well apparently I have - // a gamepad where the left control stick is a POV hat (instead of the - // d-pad like you would expect, no that's pressure sensitive). Also - // KDE's joystick dialog maps them to axes as well. - for (int i = 0; i < NumHats; ++i) - { - AxisInfo &x = Axes[NumAxes + i*2]; - AxisInfo &y = Axes[NumAxes + i*2 + 1]; - - buttonstate = SDL_JoystickGetHat(Device, i); - - // If we're going to assume that we can pass SDL's value into - // Joy_GenerateButtonEvents then we might as well assume the format here. - if(buttonstate & 0x1) // Up - y.Value = -1.0; - else if(buttonstate & 0x4) // Down - y.Value = 1.0; - else - y.Value = 0.0; - if(buttonstate & 0x2) // Left - x.Value = 1.0; - else if(buttonstate & 0x8) // Right - x.Value = -1.0; - else - x.Value = 0.0; - - if(i < 4) - { - Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4); - x.ButtonValue = buttonstate; - } - } - } - -protected: - struct AxisInfo - { - FString Name; - float DeadZone; - float Multiplier; - EJoyAxis GameAxis; - double Value; - uint8_t ButtonValue; - }; - static const EJoyAxis DefaultAxes[5]; - - int DeviceIndex; - SDL_Joystick *Device; - - float Multiplier; - TArray Axes; - int NumAxes; - int NumHats; -}; -const EJoyAxis SDLInputJoystick::DefaultAxes[5] = {JOYAXIS_Side, JOYAXIS_Forward, JOYAXIS_Pitch, JOYAXIS_Yaw, JOYAXIS_Up}; - -class SDLInputJoystickManager -{ -public: - SDLInputJoystickManager() - { - for(int i = 0;i < SDL_NumJoysticks();i++) - { - SDLInputJoystick *device = new SDLInputJoystick(i); - if(device->IsValid()) - Joysticks.Push(device); - else - delete device; - } - } - ~SDLInputJoystickManager() - { - for(unsigned int i = 0;i < Joysticks.Size();i++) - delete Joysticks[i]; - } - - void AddAxes(float axes[NUM_JOYAXIS]) - { - for(unsigned int i = 0;i < Joysticks.Size();i++) - Joysticks[i]->AddAxes(axes); - } - void GetDevices(TArray &sticks) - { - for(unsigned int i = 0;i < Joysticks.Size();i++) - { - M_LoadJoystickConfig(Joysticks[i]); - sticks.Push(Joysticks[i]); - } - } - - void ProcessInput() const - { - for(unsigned int i = 0;i < Joysticks.Size();++i) - Joysticks[i]->ProcessInput(); - } -protected: - TArray Joysticks; -}; -static SDLInputJoystickManager *JoystickManager; - -void I_StartupJoysticks() -{ - if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0) - JoystickManager = new SDLInputJoystickManager(); -} -void I_ShutdownInput() -{ - if(JoystickManager) - { - delete JoystickManager; - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - } -} - -void I_GetJoysticks(TArray &sticks) -{ - sticks.Clear(); - - JoystickManager->GetDevices(sticks); -} - -void I_GetAxes(float axes[NUM_JOYAXIS]) -{ - for (int i = 0; i < NUM_JOYAXIS; ++i) - { - axes[i] = 0; - } - if (use_joystick) - { - JoystickManager->AddAxes(axes); - } -} - -void I_ProcessJoysticks() -{ - if (use_joystick) - JoystickManager->ProcessInput(); -} - -IJoystickConfig *I_UpdateDeviceList() -{ - return NULL; -} diff --git a/src/posix/sdl/i_main.cpp b/src/posix/sdl/i_main.cpp deleted file mode 100644 index 9004dc0a3f0..00000000000 --- a/src/posix/sdl/i_main.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* -** i_main.cpp -** System-specific startup code. Eventually calls D_DoomMain. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include -#include -#include - -#include "doomerrors.h" -#include "m_argv.h" -#include "d_main.h" -#include "c_console.h" -#include "version.h" -#include "w_wad.h" -#include "g_level.h" -#include "g_levellocals.h" -#include "cmdlib.h" -#include "r_utility.h" -#include "doomstat.h" -#include "vm.h" -#include "doomerrors.h" -#include "i_system.h" -#include "g_game.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -extern "C" int cc_install_handlers(int, char**, int, int*, const char*, int(*)(char*, char*)); - -#ifdef __APPLE__ -void Mac_I_FatalError(const char* errortext); -#endif - -#ifdef __linux__ -void Linux_I_FatalError(const char* errortext); -#endif - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// The command line arguments. -FArgs *Args; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - - -// CODE -------------------------------------------------------------------- - - - -static int DoomSpecificInfo (char *buffer, char *end) -{ - const char *arg; - int size = end-buffer-2; - int i, p; - - p = 0; - p += snprintf (buffer+p, size-p, GAMENAME" version %s (%s)\n", GetVersionString(), GetGitHash()); -#ifdef __VERSION__ - p += snprintf (buffer+p, size-p, "Compiler version: %s\n", __VERSION__); -#endif - - // If Args is nullptr, then execution is at either - // * early stage of initialization, additional info contains only default values - // * late stage of shutdown, most likely main() was done, and accessing global variables is no longer safe - if (Args) - { - p += snprintf(buffer + p, size - p, "\nCommand line:"); - for (i = 0; i < Args->NumArgs(); ++i) - { - p += snprintf(buffer + p, size - p, " %s", Args->GetArg(i)); - } - p += snprintf(buffer + p, size - p, "\n"); - - for (i = 0; (arg = Wads.GetWadName(i)) != NULL; ++i) - { - p += snprintf(buffer + p, size - p, "\nWad %d: %s", i, arg); - } - - if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) - { - p += snprintf(buffer + p, size - p, "\n\nNot in a level."); - } - else - { - p += snprintf(buffer + p, size - p, "\n\nCurrent map: %s", primaryLevel->MapName.GetChars()); - - if (!viewactive) - { - p += snprintf(buffer + p, size - p, "\n\nView not active."); - } - else - { - auto& vp = r_viewpoint; - p += snprintf(buffer + p, size - p, "\n\nviewx = %f", vp.Pos.X); - p += snprintf(buffer + p, size - p, "\nviewy = %f", vp.Pos.Y); - p += snprintf(buffer + p, size - p, "\nviewz = %f", vp.Pos.Z); - p += snprintf(buffer + p, size - p, "\nviewangle = %f", vp.Angles.Yaw.Degrees); - } - } - } - - buffer[p++] = '\n'; - buffer[p++] = '\0'; - - return p; -} - -void I_DetectOS() -{ - // The POSIX version never implemented this. -} - -void I_StartupJoysticks(); - -int main (int argc, char **argv) -{ -#if !defined (__APPLE__) - { - int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS }; - cc_install_handlers(argc, argv, 4, s, GAMENAMELOWERCASE "-crash.log", DoomSpecificInfo); - } -#endif // !__APPLE__ - - printf(GAMENAME" %s - %s - SDL version\nCompiled on %s\n", - GetVersionString(), GetGitTime(), __DATE__); - - seteuid (getuid ()); - // Set LC_NUMERIC environment variable in case some library decides to - // clear the setlocale call at least this will be correct. - // Note that the LANG environment variable is overridden by LC_* - setenv ("LC_NUMERIC", "C", 1); - - setlocale (LC_ALL, "C"); - - if (SDL_Init (0) < 0) - { - fprintf (stderr, "Could not initialize SDL:\n%s\n", SDL_GetError()); - return -1; - } - - printf("\n"); - - Args = new FArgs(argc, argv); - - // Should we even be doing anything with progdir on Unix systems? - char program[PATH_MAX]; - if (realpath (argv[0], program) == NULL) - strcpy (program, argv[0]); - char *slash = strrchr (program, '/'); - if (slash != NULL) - { - *(slash + 1) = '\0'; - progdir = program; - } - else - { - progdir = "./"; - } - - I_StartupJoysticks(); - - const int result = D_DoomMain(); - - SDL_Quit(); - - return result; -} diff --git a/src/posix/sdl/i_system.cpp b/src/posix/sdl/i_system.cpp deleted file mode 100644 index b1f1c261c89..00000000000 --- a/src/posix/sdl/i_system.cpp +++ /dev/null @@ -1,264 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// - -#include -#include -#include - -#include - -#include "d_main.h" -#include "i_system.h" -#include "version.h" -#include "x86.h" - - -#ifndef NO_GTK -bool I_GtkAvailable (); -int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad); -void I_ShowFatalError_Gtk(const char* errortext); -#elif defined(__APPLE__) -int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad); -#endif - -double PerfToSec, PerfToMillisec; - -void I_SetIWADInfo() -{ -} - -// -// I_Error -// - -#ifdef __APPLE__ -void Mac_I_FatalError(const char* errortext); -#endif - -#ifdef __linux__ -void Linux_I_FatalError(const char* errortext) -{ - // Close window or exit fullscreen and release mouse capture - SDL_Quit(); - - const char *str; - if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0) - { - FString cmd; - cmd << "kdialog --title \"" GAMENAME " " << GetVersionString() - << "\" --msgbox \"" << errortext << "\""; - popen(cmd, "r"); - } -#ifndef NO_GTK - else if (I_GtkAvailable()) - { - I_ShowFatalError_Gtk(errortext); - } -#endif - else - { - FString title; - title << GAMENAME " " << GetVersionString(); - - if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, errortext, NULL) < 0) - { - printf("\n%s\n", errortext); - } - } -} -#endif - - -void I_ShowFatalError(const char *message) -{ -#ifdef __APPLE__ - Mac_I_FatalError(message); -#elif defined __linux__ - Linux_I_FatalError(message); -#else - // ??? -#endif -} - -void CalculateCPUSpeed() -{ -} - -void I_DebugPrint(const char *cp) -{ -} - -void I_PrintStr(const char *cp) -{ - // Strip out any color escape sequences before writing to debug output - TArray copy(strlen(cp) + 1, true); - const char * srcp = cp; - char * dstp = copy.Data(); - - while (*srcp != 0) - { - if (*srcp != 0x1c && *srcp != 0x1d && *srcp != 0x1e && *srcp != 0x1f) - { - *dstp++ = *srcp++; - } - else - { - if (srcp[1] != 0) srcp += 2; - else break; - } - } - *dstp = 0; - - fputs(copy.Data(), stdout); - fflush(stdout); -} - -int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) -{ - int i; - - if (!showwin) - { - return defaultiwad; - } - -#ifndef __APPLE__ - const char *str; - if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0) - { - FString cmd("kdialog --title \"" GAMENAME " "); - cmd << GetVersionString() << ": Select an IWAD to use\"" - " --menu \"" GAMENAME " found more than one IWAD\n" - "Select from the list below to determine which one to use:\""; - - for(i = 0; i < numwads; ++i) - { - const char *filepart = strrchr(wads[i].Path, '/'); - if(filepart == NULL) - filepart = wads[i].Path; - else - filepart++; - // Menu entries are specified in "tag" "item" pairs, where when a - // particular item is selected (and the Okay button clicked), its - // corresponding tag is printed to stdout for identification. - cmd.AppendFormat(" \"%d\" \"%s (%s)\"", i, wads[i].Name.GetChars(), filepart); - } - - if(defaultiwad >= 0 && defaultiwad < numwads) - { - const char *filepart = strrchr(wads[defaultiwad].Path, '/'); - if(filepart == NULL) - filepart = wads[defaultiwad].Path; - else - filepart++; - cmd.AppendFormat(" --default \"%s (%s)\"", wads[defaultiwad].Name.GetChars(), filepart); - } - - FILE *f = popen(cmd, "r"); - if(f != NULL) - { - char gotstr[16]; - - if(fgets(gotstr, sizeof(gotstr), f) == NULL || - sscanf(gotstr, "%d", &i) != 1) - i = -1; - - // Exit status = 1 means the selection was canceled (either by - // Cancel/Esc or the X button), not that there was an error running - // the program. In that case, nothing was printed so fgets will - // have failed. Other values can indicate an error running the app, - // so fall back to whatever else can be used. - int status = pclose(f); - if(WIFEXITED(status) && (WEXITSTATUS(status) == 0 || WEXITSTATUS(status) == 1)) - return i; - } - } -#endif - -#ifndef NO_GTK - if (I_GtkAvailable()) - { - return I_PickIWad_Gtk (wads, numwads, showwin, defaultiwad); - } -#endif - -#ifdef __APPLE__ - return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad); -#endif - - if (!isatty(fileno(stdin))) - { - return defaultiwad; - } - - printf ("Please select a game wad (or 0 to exit):\n"); - for (i = 0; i < numwads; ++i) - { - const char *filepart = strrchr (wads[i].Path, '/'); - if (filepart == NULL) - filepart = wads[i].Path; - else - filepart++; - printf ("%d. %s (%s)\n", i+1, wads[i].Name.GetChars(), filepart); - } - printf ("Which one? "); - if (scanf ("%d", &i) != 1 || i > numwads) - return -1; - return i-1; -} - -void I_PutInClipboard (const char *str) -{ - SDL_SetClipboardText(str); -} - -FString I_GetFromClipboard (bool use_primary_selection) -{ - if(char *ret = SDL_GetClipboardText()) - { - FString text(ret); - SDL_free(ret); - return text; - } - return ""; -} - -// Return a random seed, preferably one with lots of entropy. -unsigned int I_MakeRNGSeed() -{ - unsigned int seed; - int file; - - // Try reading from /dev/urandom first, then /dev/random, then - // if all else fails, use a crappy seed from time(). - seed = time(NULL); - file = open("/dev/urandom", O_RDONLY); - if (file < 0) - { - file = open("/dev/random", O_RDONLY); - } - if (file >= 0) - { - read(file, &seed, sizeof(seed)); - close(file); - } - return seed; -} diff --git a/src/posix/sdl/i_system.mm b/src/posix/sdl/i_system.mm deleted file mode 100644 index 50faf94a8e9..00000000000 --- a/src/posix/sdl/i_system.mm +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include "SDL.h" - -void Mac_I_FatalError(const char* errortext) -{ - // Close window or exit fullscreen and release mouse capture - SDL_Quit(); - - const CFStringRef errorString = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault, - errortext, kCFStringEncodingASCII, kCFAllocatorNull ); - if ( NULL != errorString ) - { - CFOptionFlags dummy; - - CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, - CFSTR( "Fatal Error" ), errorString, CFSTR( "Exit" ), NULL, NULL, &dummy ); - CFRelease( errorString ); - } -} diff --git a/src/posix/sdl/sdlglvideo.cpp b/src/posix/sdl/sdlglvideo.cpp deleted file mode 100644 index e8c0969da0c..00000000000 --- a/src/posix/sdl/sdlglvideo.cpp +++ /dev/null @@ -1,774 +0,0 @@ -/* -** sdlglvideo.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2005-2016 Christoph Oelckers et.al. -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "doomtype.h" - -#include "i_module.h" -#include "i_system.h" -#include "i_video.h" -#include "m_argv.h" -#include "v_video.h" -#include "version.h" -#include "c_console.h" -#include "c_dispatch.h" -#include "s_sound.h" - -#include "hardware.h" -#include "gl_sysfb.h" -#include "gl_load/gl_system.h" -#include "r_defs.h" - -#include "gl/renderer/gl_renderer.h" -#include "gl/system/gl_framebuffer.h" -#include "gl/shaders/gl_shader.h" - -#ifdef HAVE_VULKAN -#include "rendering/vulkan/system/vk_framebuffer.h" -#endif - -#include "rendering/polyrenderer/backend/poly_framebuffer.h" - -// MACROS ------------------------------------------------------------------ - -// Requires SDL 2.0.6 or newer -//#define SDL2_STATIC_LIBRARY - -#if defined SDL2_STATIC_LIBRARY && defined HAVE_VULKAN -#include -#endif // SDL2_STATIC_LIBRARY && HAVE_VULKAN - -// TYPES ------------------------------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern IVideo *Video; - -EXTERN_CVAR (Int, vid_adapter) -EXTERN_CVAR (Int, vid_displaybits) -EXTERN_CVAR (Int, vid_defwidth) -EXTERN_CVAR (Int, vid_defheight) -EXTERN_CVAR (Int, vid_preferbackend) -EXTERN_CVAR (Bool, cl_capfps) - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - Printf("This won't take effect until " GAMENAME " is restarted.\n"); -} -CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - Printf("This won't take effect until " GAMENAME " is restarted.\n"); -} - -CVAR(Bool, i_soundinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - -CVAR (Int, vid_adapter, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - -CUSTOM_CVAR(String, vid_sdl_render_driver, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - Printf("This won't take effect until " GAMENAME " is restarted.\n"); -} - -CCMD(vid_list_sdl_render_drivers) -{ - for (int i = 0; i < SDL_GetNumRenderDrivers(); ++i) - { - SDL_RendererInfo info; - if (SDL_GetRenderDriverInfo(i, &info) == 0) - Printf("%s\n", info.name); - } -} - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -namespace Priv -{ -#ifdef SDL2_STATIC_LIBRARY - -#define SDL2_OPTIONAL_FUNCTION(RESULT, NAME, ...) \ - RESULT(*NAME)(__VA_ARGS__) = SDL_ ## NAME - -#else // !SDL2_STATIC_LIBRARY - - FModule library("SDL2"); - -#define SDL2_OPTIONAL_FUNCTION(RESULT, NAME, ...) \ - static TOptProc NAME("SDL_" #NAME) - -#endif // SDL2_STATIC_LIBRARY - - SDL2_OPTIONAL_FUNCTION(int, GetWindowBordersSize, SDL_Window *window, int *top, int *left, int *bottom, int *right); -#ifdef HAVE_VULKAN - SDL2_OPTIONAL_FUNCTION(void, Vulkan_GetDrawableSize, SDL_Window *window, int *width, int *height); - SDL2_OPTIONAL_FUNCTION(SDL_bool, Vulkan_GetInstanceExtensions, SDL_Window *window, unsigned int *count, const char **names); - SDL2_OPTIONAL_FUNCTION(SDL_bool, Vulkan_CreateSurface, SDL_Window *window, VkInstance instance, VkSurfaceKHR *surface); -#endif - -#undef SDL2_OPTIONAL_FUNCTION - - static const uint32_t VulkanWindowFlag = 0x1000'0000; - - SDL_Window *window; - bool vulkanEnabled; - bool softpolyEnabled; - bool fullscreenSwitch; - - void CreateWindow(uint32_t extraFlags) - { - assert(Priv::window == nullptr); - - // Set default size - SDL_Rect bounds; - SDL_GetDisplayBounds(vid_adapter, &bounds); - - if (win_w <= 0 || win_h <= 0) - { - win_w = bounds.w * 8 / 10; - win_h = bounds.h * 8 / 10; - } - - FString caption; - caption.Format(GAMENAME " %s (%s)", GetVersionString(), GetGitTime()); - - const uint32_t windowFlags = (win_maximized ? SDL_WINDOW_MAXIMIZED : 0) | SDL_WINDOW_RESIZABLE | extraFlags; - Priv::window = SDL_CreateWindow(caption, - (win_x <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_x, - (win_y <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_y, - win_w, win_h, windowFlags); - - if (Priv::window != nullptr) - { - // Enforce minimum size limit - SDL_SetWindowMinimumSize(Priv::window, VID_MIN_WIDTH, VID_MIN_HEIGHT); - } - } - - void DestroyWindow() - { - assert(Priv::window != nullptr); - - SDL_DestroyWindow(Priv::window); - Priv::window = nullptr; - } - - void SetupPixelFormat(int multisample, const int *glver) - { - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - if (multisample > 0) { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisample); - } - if (gl_debug) - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); - - if (gl_es) - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - } - else if (glver[0] > 2) - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, glver[0]); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, glver[1]); - } - else - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - } - } -} - -class SDLVideo : public IVideo -{ -public: - SDLVideo (); - ~SDLVideo (); - - DFrameBuffer *CreateFrameBuffer (); - -private: -#ifdef HAVE_VULKAN - VulkanDevice *device = nullptr; -#endif -}; - -// CODE -------------------------------------------------------------------- - -#ifdef HAVE_VULKAN -void I_GetVulkanDrawableSize(int *width, int *height) -{ - assert(Priv::vulkanEnabled); - assert(Priv::window != nullptr); - assert(Priv::Vulkan_GetDrawableSize); - Priv::Vulkan_GetDrawableSize(Priv::window, width, height); -} - -bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names) -{ - assert(Priv::vulkanEnabled); - assert(Priv::window != nullptr); - return Priv::Vulkan_GetInstanceExtensions(Priv::window, count, names) == SDL_TRUE; -} - -bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface) -{ - assert(Priv::vulkanEnabled); - assert(Priv::window != nullptr); - return Priv::Vulkan_CreateSurface(Priv::window, instance, surface) == SDL_TRUE; -} -#endif - -namespace -{ - SDL_Renderer* polyrendertarget = nullptr; - SDL_Texture* polytexture = nullptr; - int polytexturew = 0; - int polytextureh = 0; - bool polyvsync = false; - bool polyfirstinit = true; -} - -void I_PolyPresentInit() -{ - assert(Priv::softpolyEnabled); - assert(Priv::window != nullptr); - - if (strcmp(vid_sdl_render_driver, "") != 0) - { - SDL_SetHint(SDL_HINT_RENDER_DRIVER, vid_sdl_render_driver); - } -} - -uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch) -{ - // When vsync changes we need to reinitialize - if (polyrendertarget && polyvsync != vsync) - { - I_PolyPresentDeinit(); - } - - if (!polyrendertarget) - { - polyvsync = vsync; - - polyrendertarget = SDL_CreateRenderer(Priv::window, -1, vsync ? SDL_RENDERER_PRESENTVSYNC : 0); - if (!polyrendertarget) - { - I_FatalError("Could not create render target for softpoly: %s\n", SDL_GetError()); - } - - // Tell the user which render driver is being used, but don't repeat - // outselves if we're just changing vsync. - if (polyfirstinit) - { - polyfirstinit = false; - - SDL_RendererInfo rendererInfo; - if (SDL_GetRendererInfo(polyrendertarget, &rendererInfo) == 0) - { - Printf("Using render driver %s\n", rendererInfo.name); - } - else - { - Printf("Failed to query render driver\n"); - } - } - - // Mask color - SDL_SetRenderDrawColor(polyrendertarget, 0, 0, 0, 255); - } - - if (!polytexture || polytexturew != w || polytextureh != h) - { - if (polytexture) - { - SDL_DestroyTexture(polytexture); - polytexture = nullptr; - polytexturew = polytextureh = 0; - } - if ((polytexture = SDL_CreateTexture(polyrendertarget, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h)) == nullptr) - I_Error("Failed to create %dx%d render target texture.", w, h); - polytexturew = w; - polytextureh = h; - } - - uint8_t* pixels; - SDL_LockTexture(polytexture, nullptr, (void**)&pixels, &pitch); - return pixels; -} - -void I_PolyPresentUnlock(int x, int y, int width, int height) -{ - SDL_UnlockTexture(polytexture); - - int ClientWidth, ClientHeight; - SDL_GetRendererOutputSize(polyrendertarget, &ClientWidth, &ClientHeight); - - SDL_Rect clearrects[4]; - int count = 0; - if (y > 0) - { - clearrects[count].x = 0; - clearrects[count].y = 0; - clearrects[count].w = ClientWidth; - clearrects[count].h = y; - count++; - } - if (y + height < ClientHeight) - { - clearrects[count].x = 0; - clearrects[count].y = y + height; - clearrects[count].w = ClientWidth; - clearrects[count].h = ClientHeight - clearrects[count].y; - count++; - } - if (x > 0) - { - clearrects[count].x = 0; - clearrects[count].y = y; - clearrects[count].w = x; - clearrects[count].h = height; - count++; - } - if (x + width < ClientWidth) - { - clearrects[count].x = x + width; - clearrects[count].y = y; - clearrects[count].w = ClientWidth - clearrects[count].x; - clearrects[count].h = height; - count++; - } - - if (count > 0) - SDL_RenderFillRects(polyrendertarget, clearrects, count); - - SDL_Rect dstrect; - dstrect.x = x; - dstrect.y = y; - dstrect.w = width; - dstrect.h = height; - SDL_RenderCopy(polyrendertarget, polytexture, nullptr, &dstrect); - - SDL_RenderPresent(polyrendertarget); -} - -void I_PolyPresentDeinit() -{ - if (polytexture) - { - SDL_DestroyTexture(polytexture); - polytexture = nullptr; - } - - if (polyrendertarget) - { - SDL_DestroyRenderer(polyrendertarget); - polyrendertarget = nullptr; - } -} - - - -SDLVideo::SDLVideo () -{ - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - fprintf(stderr, "Video initialization failed: %s\n", SDL_GetError()); - return; - } - -#ifndef SDL2_STATIC_LIBRARY - // Load optional SDL functions - if (!Priv::library.IsLoaded()) - { - Priv::library.Load({ "libSDL2-2.0.so.0", "libSDL2-2.0.so", "libSDL2.so" }); - } -#endif // !SDL2_STATIC_LIBRARY - - Priv::softpolyEnabled = vid_preferbackend == 2; -#ifdef HAVE_VULKAN - Priv::vulkanEnabled = vid_preferbackend == 1 - && Priv::Vulkan_GetDrawableSize && Priv::Vulkan_GetInstanceExtensions && Priv::Vulkan_CreateSurface; - - if (Priv::vulkanEnabled) - { - Priv::CreateWindow(Priv::VulkanWindowFlag | SDL_WINDOW_HIDDEN); - - if (Priv::window == nullptr) - { - Priv::vulkanEnabled = false; - } - } -#endif - if (Priv::softpolyEnabled) - { - Priv::CreateWindow(SDL_WINDOW_HIDDEN); - } -} - -SDLVideo::~SDLVideo () -{ -#ifdef HAVE_VULKAN - delete device; -#endif -} - -DFrameBuffer *SDLVideo::CreateFrameBuffer () -{ - SystemBaseFrameBuffer *fb = nullptr; - - // first try Vulkan, if that fails OpenGL -#ifdef HAVE_VULKAN - if (Priv::vulkanEnabled) - { - try - { - assert(device == nullptr); - device = new VulkanDevice(); - fb = new VulkanFrameBuffer(nullptr, fullscreen, device); - } - catch (CVulkanError const&) - { - if (Priv::window != nullptr) - { - Priv::DestroyWindow(); - } - - Priv::vulkanEnabled = false; - } - } -#endif - - if (Priv::softpolyEnabled) - { - fb = new PolyFrameBuffer(nullptr, fullscreen); - } - - if (fb == nullptr) - { - fb = new OpenGLRenderer::OpenGLFrameBuffer(0, fullscreen); - } - - return fb; -} - - -IVideo *gl_CreateVideo() -{ - return new SDLVideo(); -} - - -// FrameBuffer Implementation ----------------------------------------------- - -SystemBaseFrameBuffer::SystemBaseFrameBuffer (void *, bool fullscreen) -: DFrameBuffer (vid_defwidth, vid_defheight) -{ - if (Priv::window != nullptr) - { - SDL_SetWindowFullscreen(Priv::window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); - SDL_ShowWindow(Priv::window); - } -} - -int SystemBaseFrameBuffer::GetClientWidth() -{ - int width = 0; - - if (Priv::softpolyEnabled) - { - if (polyrendertarget) - SDL_GetRendererOutputSize(polyrendertarget, &width, nullptr); - else - SDL_GetWindowSize(Priv::window, &width, nullptr); - return width; - } - -#ifdef HAVE_VULKAN - assert(Priv::vulkanEnabled); - Priv::Vulkan_GetDrawableSize(Priv::window, &width, nullptr); -#endif - - return width; -} - -int SystemBaseFrameBuffer::GetClientHeight() -{ - int height = 0; - - if (Priv::softpolyEnabled) - { - if (polyrendertarget) - SDL_GetRendererOutputSize(polyrendertarget, nullptr, &height); - else - SDL_GetWindowSize(Priv::window, nullptr, &height); - return height; - } - -#ifdef HAVE_VULKAN - assert(Priv::vulkanEnabled); - Priv::Vulkan_GetDrawableSize(Priv::window, nullptr, &height); -#endif - - return height; -} - -bool SystemBaseFrameBuffer::IsFullscreen () -{ - return (SDL_GetWindowFlags(Priv::window) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; -} - -void SystemBaseFrameBuffer::ToggleFullscreen(bool yes) -{ - SDL_SetWindowFullscreen(Priv::window, yes ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); - if ( !yes ) - { - if ( !Priv::fullscreenSwitch ) - { - Priv::fullscreenSwitch = true; - fullscreen = false; - } - else - { - Priv::fullscreenSwitch = false; - SetWindowSize(win_w, win_h); - } - } -} - -void SystemBaseFrameBuffer::SetWindowSize(int w, int h) -{ - if (w < VID_MIN_WIDTH || h < VID_MIN_HEIGHT) - { - w = VID_MIN_WIDTH; - h = VID_MIN_HEIGHT; - } - win_w = w; - win_h = h; - if ( fullscreen ) - { - fullscreen = false; - } - else - { - win_maximized = false; - SDL_SetWindowSize(Priv::window, w, h); - SDL_SetWindowPosition(Priv::window, SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter), SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter)); - SetSize(GetClientWidth(), GetClientHeight()); - int x, y; - SDL_GetWindowPosition(Priv::window, &x, &y); - win_x = x; - win_y = y; - } -} - - -SystemGLFrameBuffer::SystemGLFrameBuffer(void *hMonitor, bool fullscreen) -: SystemBaseFrameBuffer(hMonitor, fullscreen) -{ - // NOTE: Core profiles were added with GL 3.2, so there's no sense trying - // to set core 3.1 or 3.0. We could try a forward-compatible context - // instead, but that would be too restrictive (w.r.t. shaders). - static const int glvers[][2] = { - { 4, 6 }, { 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 }, - { 3, 3 }, { 3, 2 }, { 2, 0 }, - { 0, 0 }, - }; - int glveridx = 0; - int i; - - const char *version = Args->CheckValue("-glversion"); - if (version != NULL) - { - double gl_version = strtod(version, NULL) + 0.01; - int vermaj = (int)gl_version; - int vermin = (int)(gl_version*10.0) % 10; - - while (glvers[glveridx][0] > vermaj || (glvers[glveridx][0] == vermaj && - glvers[glveridx][1] > vermin)) - { - glveridx++; - if (glvers[glveridx][0] == 0) - { - glveridx = 0; - break; - } - } - } - - for ( ; glvers[glveridx][0] > 0; ++glveridx) - { - Priv::SetupPixelFormat(0, glvers[glveridx]); - Priv::CreateWindow(SDL_WINDOW_OPENGL | (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)); - - if (Priv::window == nullptr) - { - continue; - } - - GLContext = SDL_GL_CreateContext(Priv::window); - if (GLContext == nullptr) - { - Priv::DestroyWindow(); - } - else - { - break; - } - } -} - -SystemGLFrameBuffer::~SystemGLFrameBuffer () -{ - if (Priv::window) - { - if (GLContext) - { - SDL_GL_DeleteContext(GLContext); - } - - Priv::DestroyWindow(); - } -} - -int SystemGLFrameBuffer::GetClientWidth() -{ - int width = 0; - SDL_GL_GetDrawableSize(Priv::window, &width, nullptr); - return width; -} - -int SystemGLFrameBuffer::GetClientHeight() -{ - int height = 0; - SDL_GL_GetDrawableSize(Priv::window, nullptr, &height); - return height; -} - -void SystemGLFrameBuffer::SetVSync( bool vsync ) -{ -#if defined (__APPLE__) - const GLint value = vsync ? 1 : 0; - CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, &value ); -#else - if (vsync) - { - if (SDL_GL_SetSwapInterval(-1) == -1) - SDL_GL_SetSwapInterval(1); - } - else - { - SDL_GL_SetSwapInterval(0); - } -#endif -} - -void SystemGLFrameBuffer::SwapBuffers() -{ - SDL_GL_SwapWindow(Priv::window); -} - - -void ProcessSDLWindowEvent(const SDL_WindowEvent &event) -{ - switch (event.event) - { - extern bool AppActive; - - case SDL_WINDOWEVENT_FOCUS_GAINED: - S_SetSoundPaused(1); - AppActive = true; - break; - - case SDL_WINDOWEVENT_FOCUS_LOST: - S_SetSoundPaused(i_soundinbackground); - AppActive = false; - break; - - case SDL_WINDOWEVENT_MOVED: - if (!fullscreen && Priv::GetWindowBordersSize) - { - int top = 0, left = 0; - Priv::GetWindowBordersSize(Priv::window, &top, &left, nullptr, nullptr); - win_x = event.data1-left; - win_y = event.data2-top; - } - break; - - case SDL_WINDOWEVENT_RESIZED: - if (!fullscreen && !Priv::fullscreenSwitch) - { - win_w = event.data1; - win_h = event.data2; - } - break; - - case SDL_WINDOWEVENT_MAXIMIZED: - win_maximized = true; - break; - - case SDL_WINDOWEVENT_RESTORED: - win_maximized = false; - break; - } -} - - -// each platform has its own specific version of this function. -void I_SetWindowTitle(const char* caption) -{ - if (caption) - { - SDL_SetWindowTitle(Priv::window, caption); - } - else - { - FString default_caption; - default_caption.Format(GAMENAME " %s (%s)", GetVersionString(), GetGitTime()); - SDL_SetWindowTitle(Priv::window, default_caption); - } -} - diff --git a/src/posix/sdl/st_start.cpp b/src/posix/sdl/st_start.cpp deleted file mode 100644 index 7e673d96112..00000000000 --- a/src/posix/sdl/st_start.cpp +++ /dev/null @@ -1,331 +0,0 @@ -/* -** st_start.cpp -** Handles the startup screen. -** -**--------------------------------------------------------------------------- -** Copyright 2006-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include - -#include "st_start.h" -#include "doomdef.h" -#include "i_system.h" -#include "c_cvars.h" -#include "doomerrors.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -class FTTYStartupScreen : public FStartupScreen -{ - public: - FTTYStartupScreen(int max_progress); - ~FTTYStartupScreen(); - - void Progress(); - void NetInit(const char *message, int num_players); - void NetProgress(int count); - void NetMessage(const char *format, ...); // cover for printf - void NetDone(); - bool NetLoop(bool (*timer_callback)(void *), void *userdata); - protected: - bool DidNetInit; - int NetMaxPos, NetCurPos; - const char *TheNetMessage; - termios OldTermIOS; -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FStartupScreen *StartScreen; - -CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (self < 0) self = 0; - else if (self > 2) self=2; -} - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static const char SpinnyProgressChars[4] = { '|', '/', '-', '\\' }; - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// FStartupScreen :: CreateInstance -// -// Initializes the startup screen for the detected game. -// Sets the size of the progress bar and displays the startup screen. -// -//========================================================================== - -FStartupScreen *FStartupScreen::CreateInstance(int max_progress) -{ - return new FTTYStartupScreen(max_progress); -} - -//=========================================================================== -// -// FTTYStartupScreen Constructor -// -// Sets the size of the progress bar and displays the startup screen. -// -//=========================================================================== - -FTTYStartupScreen::FTTYStartupScreen(int max_progress) - : FStartupScreen(max_progress) -{ - DidNetInit = false; - NetMaxPos = 0; - NetCurPos = 0; - TheNetMessage = NULL; -} - -//=========================================================================== -// -// FTTYStartupScreen Destructor -// -// Called just before entering graphics mode to deconstruct the startup -// screen. -// -//=========================================================================== - -FTTYStartupScreen::~FTTYStartupScreen() -{ - NetDone(); // Just in case it wasn't called yet and needs to be. -} - -//=========================================================================== -// -// FTTYStartupScreen :: Progress -// -// If there was a progress bar, this would move it. But the basic TTY -// startup screen doesn't have one, so this function does nothing. -// -//=========================================================================== - -void FTTYStartupScreen::Progress() -{ -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetInit -// -// Sets stdin for unbuffered I/O, displays the given message, and shows -// a progress meter. -// -//=========================================================================== - -void FTTYStartupScreen::NetInit(const char *message, int numplayers) -{ - if (!DidNetInit) - { - termios rawtermios; - - fprintf (stderr, "Press 'Q' to abort network game synchronization."); - // Set stdin to raw mode so we can get keypresses in ST_CheckNetAbort() - // immediately without waiting for an EOL. - tcgetattr (STDIN_FILENO, &OldTermIOS); - rawtermios = OldTermIOS; - rawtermios.c_lflag &= ~(ICANON | ECHO); - tcsetattr (STDIN_FILENO, TCSANOW, &rawtermios); - DidNetInit = true; - } - if (numplayers == 1) - { - // Status message without any real progress info. - fprintf (stderr, "\n%s.", message); - } - else - { - fprintf (stderr, "\n%s: ", message); - } - fflush (stderr); - TheNetMessage = message; - NetMaxPos = numplayers; - NetCurPos = 0; - NetProgress(1); // You always know about yourself -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetDone -// -// Restores the old stdin tty settings. -// -//=========================================================================== - -void FTTYStartupScreen::NetDone() -{ - // Restore stdin settings - if (DidNetInit) - { - tcsetattr (STDIN_FILENO, TCSANOW, &OldTermIOS); - printf ("\n"); - DidNetInit = false; - } -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetMessage -// -// Call this between NetInit() and NetDone() instead of Printf() to -// display messages, because the progress meter is mixed in the same output -// stream as normal messages. -// -//=========================================================================== - -void FTTYStartupScreen::NetMessage(const char *format, ...) -{ - FString str; - va_list argptr; - - va_start (argptr, format); - str.VFormat (format, argptr); - va_end (argptr); - fprintf (stderr, "\r%-40s\n", str.GetChars()); -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetProgress -// -// Sets the network progress meter. If count is 0, it gets bumped by 1. -// Otherwise, it is set to count. -// -//=========================================================================== - -void FTTYStartupScreen::NetProgress(int count) -{ - int i; - - if (count == 0) - { - NetCurPos++; - } - else if (count > 0) - { - NetCurPos = count; - } - if (NetMaxPos == 0) - { - // Spinny-type progress meter, because we're a guest waiting for the host. - fprintf (stderr, "\r%s: %c", TheNetMessage, SpinnyProgressChars[NetCurPos & 3]); - fflush (stderr); - } - else if (NetMaxPos > 1) - { - // Dotty-type progress meter. - fprintf (stderr, "\r%s: ", TheNetMessage); - for (i = 0; i < NetCurPos; ++i) - { - fputc ('.', stderr); - } - fprintf (stderr, "%*c[%2d/%2d]", NetMaxPos + 1 - NetCurPos, ' ', NetCurPos, NetMaxPos); - fflush (stderr); - } -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetLoop -// -// The timer_callback function is called at least two times per second -// and passed the userdata value. It should return true to stop the loop and -// return control to the caller or false to continue the loop. -// -// ST_NetLoop will return true if the loop was halted by the callback and -// false if the loop was halted because the user wants to abort the -// network synchronization. -// -//=========================================================================== - -bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) -{ - fd_set rfds; - struct timeval tv; - int retval; - char k; - - for (;;) - { - // Don't flood the network with packets on startup. - tv.tv_sec = 0; - tv.tv_usec = 500000; - - FD_ZERO (&rfds); - FD_SET (STDIN_FILENO, &rfds); - - retval = select (1, &rfds, NULL, NULL, &tv); - - if (retval == -1) - { - // Error - } - else if (retval == 0) - { - if (timer_callback (userdata)) - { - fputc ('\n', stderr); - return true; - } - } - else if (read (STDIN_FILENO, &k, 1) == 1) - { - // Check input on stdin - if (k == 'q' || k == 'Q') - { - fprintf (stderr, "\nNetwork game synchronization aborted."); - return false; - } - } - } -} - -void ST_Endoom() -{ - throw CExitEvent(0); -} diff --git a/src/posix/unix/gtk_dialogs.cpp b/src/posix/unix/gtk_dialogs.cpp deleted file mode 100644 index 2475035a9ad..00000000000 --- a/src/posix/unix/gtk_dialogs.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/* -** gtk_dialogs.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2008-2016 Braden Obrzut -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef NO_GTK - -#if !DYN_GTK -// Function addresses will never be NULL, but that's because we're using the -// same code for both dynamic and static. -#pragma GCC diagnostic ignored "-Waddress" -#endif - -#include -#if GTK_MAJOR_VERSION >= 3 -#include -#else -#include -typedef enum -{ - GTK_ALIGN_FULL, - GTK_ALIGN_START, - GTK_ALIGN_END, - GTK_ALIGN_CENTER, - GTK_ALIGN_BASELINE -} GtkAlign; -#endif - -#include "c_cvars.h" -#include "d_main.h" -#include "i_module.h" -#include "i_system.h" -#include "version.h" - -EXTERN_CVAR (Bool, queryiwad); - -namespace Gtk { - -FModuleMaybe GtkModule{"GTK"}; -static int GtkAvailable = -1; - -#define DYN_GTK_SYM(x) const FModuleMaybe::Req x{#x}; -#define DYN_GTK_REQ_SYM(x, proto) const FModuleMaybe::Req x{#x}; -#if GTK_MAJOR_VERSION >= 3 -#define DYN_GTK_OPT2_SYM(x, proto) const FModuleMaybe::Opt x{#x}; -#define DYN_GTK_OPT3_SYM(x, proto) const FModuleMaybe::Opt x{#x}; -#else -#define DYN_GTK_OPT2_SYM(x, proto) const FModuleMaybe::Opt x{#x}; -#define DYN_GTK_OPT3_SYM(x, proto) const FModuleMaybe::Opt x{#x}; -#endif - -DYN_GTK_SYM(g_main_context_iteration); -DYN_GTK_SYM(g_signal_connect_data); -DYN_GTK_SYM(g_type_check_instance_cast); -DYN_GTK_SYM(g_type_check_instance_is_a); -DYN_GTK_SYM(g_value_get_int); -DYN_GTK_SYM(g_value_unset); -DYN_GTK_SYM(gtk_box_get_type); -DYN_GTK_SYM(gtk_box_pack_end); -DYN_GTK_SYM(gtk_box_pack_start); -DYN_GTK_SYM(gtk_box_set_spacing); -DYN_GTK_SYM(gtk_button_box_get_type); -DYN_GTK_SYM(gtk_button_box_set_layout); -DYN_GTK_SYM(gtk_button_new_with_label); -DYN_GTK_SYM(gtk_cell_renderer_text_new); -DYN_GTK_SYM(gtk_check_button_new_with_label); -DYN_GTK_SYM(gtk_container_add); -DYN_GTK_SYM(gtk_container_get_type); -DYN_GTK_SYM(gtk_container_set_border_width); -DYN_GTK_SYM(gtk_init_check); -DYN_GTK_SYM(gtk_label_new); -DYN_GTK_SYM(gtk_list_store_append); -DYN_GTK_SYM(gtk_list_store_new); -DYN_GTK_SYM(gtk_list_store_set); -DYN_GTK_SYM(gtk_toggle_button_get_type); -DYN_GTK_SYM(gtk_toggle_button_set_active); -DYN_GTK_SYM(gtk_tree_model_get_type); -DYN_GTK_SYM(gtk_tree_model_get_value); -DYN_GTK_SYM(gtk_tree_selection_get_selected); -DYN_GTK_SYM(gtk_tree_selection_select_iter); -DYN_GTK_SYM(gtk_tree_view_append_column); -// Explicitly give the type so that attributes don't cause a warning. -DYN_GTK_REQ_SYM(gtk_tree_view_column_new_with_attributes, GtkTreeViewColumn *(*)(const gchar *, GtkCellRenderer *, ...)); -DYN_GTK_SYM(gtk_toggle_button_get_active); -DYN_GTK_SYM(gtk_tree_view_get_selection); -DYN_GTK_SYM(gtk_tree_view_get_type); -DYN_GTK_SYM(gtk_tree_view_new_with_model); -DYN_GTK_SYM(gtk_main); -DYN_GTK_SYM(gtk_main_quit); -DYN_GTK_SYM(gtk_widget_destroy); -DYN_GTK_SYM(gtk_widget_grab_default); -DYN_GTK_SYM(gtk_widget_get_type); -DYN_GTK_SYM(gtk_widget_set_can_default); -DYN_GTK_SYM(gtk_widget_show_all); -DYN_GTK_SYM(gtk_window_activate_default); -DYN_GTK_SYM(gtk_window_get_type); -DYN_GTK_SYM(gtk_window_new); -DYN_GTK_SYM(gtk_window_set_gravity); -DYN_GTK_SYM(gtk_window_set_position); -DYN_GTK_SYM(gtk_window_set_title); -DYN_GTK_SYM(gtk_window_set_resizable); -DYN_GTK_SYM(gtk_dialog_run); -DYN_GTK_SYM(gtk_dialog_get_type); - -// Gtk3 Only -DYN_GTK_OPT3_SYM(gtk_box_new, GtkWidget *(*)(GtkOrientation, gint)); -DYN_GTK_OPT3_SYM(gtk_button_box_new, GtkWidget *(*)(GtkOrientation)); -DYN_GTK_OPT3_SYM(gtk_widget_set_halign, void(*)(GtkWidget *, GtkAlign)); -DYN_GTK_OPT3_SYM(gtk_widget_set_valign, void(*)(GtkWidget *, GtkAlign)); -DYN_GTK_OPT3_SYM(gtk_message_dialog_new, GtkWidget* (*)(GtkWindow*, GtkDialogFlags, GtkMessageType, GtkButtonsType, const gchar*, ...)); - -// Gtk2 Only -DYN_GTK_OPT2_SYM(gtk_misc_get_type, GType(*)()); -DYN_GTK_OPT2_SYM(gtk_hbox_new, GtkWidget *(*)(gboolean, gint)); -DYN_GTK_OPT2_SYM(gtk_hbutton_box_new, GtkWidget *(*)()); -DYN_GTK_OPT2_SYM(gtk_misc_set_alignment, void(*)(GtkMisc *, gfloat, gfloat)); -DYN_GTK_OPT2_SYM(gtk_vbox_new, GtkWidget *(*)(gboolean, gint)); - -#undef DYN_GTK_SYM -#undef DYN_GTK_REQ_SYM -#undef DYN_GTK_OPT2_SYM -#undef DYN_GTK_OPT3_SYM - -// GtkTreeViews eats return keys. I want this to be like a Windows listbox -// where pressing Return can still activate the default button. -static gint AllowDefault(GtkWidget *widget, GdkEventKey *event, gpointer func_data) -{ - if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Return) - { - gtk_window_activate_default (GTK_WINDOW(func_data)); - } - return FALSE; -} - -// Double-clicking an entry in the list is the same as pressing OK. -static gint DoubleClickChecker(GtkWidget *widget, GdkEventButton *event, gpointer func_data) -{ - if (event->type == GDK_2BUTTON_PRESS) - { - *(int *)func_data = 1; - gtk_main_quit(); - } - return FALSE; -} - -// When the user presses escape, that should be the same as canceling the dialog. -static gint CheckEscape (GtkWidget *widget, GdkEventKey *event, gpointer func_data) -{ - if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Escape) - { - gtk_main_quit(); - } - return FALSE; -} - -static void ClickedOK(GtkButton *button, gpointer func_data) -{ - *(int *)func_data = 1; - gtk_main_quit(); -} - -static int PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) -{ - GtkWidget *window; - GtkWidget *vbox = nullptr; - GtkWidget *hbox = nullptr; - GtkWidget *bbox = nullptr; - GtkWidget *widget; - GtkWidget *tree; - GtkWidget *check; - GtkListStore *store; - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - GtkTreeSelection *selection; - GtkTreeIter iter, defiter; - int close_style = 0; - int i; - char caption[100]; - - // Create the dialog window. - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - mysnprintf(caption, countof(caption), GAMENAME " %s: Select an IWAD to use", GetVersionString()); - gtk_window_set_title (GTK_WINDOW(window), caption); - gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER); - gtk_window_set_gravity (GTK_WINDOW(window), GDK_GRAVITY_CENTER); - gtk_container_set_border_width (GTK_CONTAINER(window), 10); - g_signal_connect (window, "delete_event", G_CALLBACK(gtk_main_quit), NULL); - g_signal_connect (window, "key_press_event", G_CALLBACK(CheckEscape), NULL); - - // Create the vbox container. - if (gtk_box_new) // Gtk3 - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); - else if (gtk_vbox_new) // Gtk2 - vbox = gtk_vbox_new (FALSE, 10); - - gtk_container_add (GTK_CONTAINER(window), vbox); - - // Create the top label. - widget = gtk_label_new (GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:"); - gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0); - - if (gtk_widget_set_halign && gtk_widget_set_valign) // Gtk3 - { - gtk_widget_set_halign (widget, GTK_ALIGN_START); - gtk_widget_set_valign (widget, GTK_ALIGN_START); - } - else if (gtk_misc_set_alignment && gtk_misc_get_type) // Gtk2 - gtk_misc_set_alignment (GTK_MISC(widget), 0, 0); - - // Create a list store with all the found IWADs. - store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); - for (i = 0; i < numwads; ++i) - { - const char *filepart = strrchr (wads[i].Path, '/'); - if (filepart == NULL) - filepart = wads[i].Path; - else - filepart++; - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - 0, filepart, - 1, wads[i].Name.GetChars(), - 2, i, - -1); - if (i == defaultiwad) - { - defiter = iter; - } - } - - // Create the tree view control to show the list. - tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)); - renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("IWAD", renderer, "text", 0, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); - renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("Game", renderer, "text", 1, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); - gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(tree), true, true, 0); - g_signal_connect(G_OBJECT(tree), "button_press_event", G_CALLBACK(DoubleClickChecker), &close_style); - g_signal_connect(G_OBJECT(tree), "key_press_event", G_CALLBACK(AllowDefault), window); - - // Select the default IWAD. - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree)); - gtk_tree_selection_select_iter (selection, &defiter); - - // Create the hbox for the bottom row. - if (gtk_box_new) // Gtk3 - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - else if (gtk_hbox_new) // Gtk2 - hbox = gtk_hbox_new (FALSE, 0); - - gtk_box_pack_end (GTK_BOX(vbox), hbox, false, false, 0); - - // Create the "Don't ask" checkbox. - check = gtk_check_button_new_with_label ("Don't ask me this again"); - gtk_box_pack_start (GTK_BOX(hbox), check, false, false, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(check), !showwin); - - // Create the OK/Cancel button box. - if (gtk_button_box_new) // Gtk3 - bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); - else if (gtk_hbutton_box_new) // Gtk2 - bbox = gtk_hbutton_box_new (); - - gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_box_set_spacing (GTK_BOX(bbox), 10); - gtk_box_pack_end (GTK_BOX(hbox), bbox, false, false, 0); - - // Create the OK button. - widget = gtk_button_new_with_label ("OK"); - - gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); - - gtk_widget_set_can_default (widget, true); - - gtk_widget_grab_default (widget); - g_signal_connect (widget, "clicked", G_CALLBACK(ClickedOK), &close_style); - g_signal_connect (widget, "activate", G_CALLBACK(ClickedOK), &close_style); - - // Create the cancel button. - widget = gtk_button_new_with_label ("Cancel"); - - gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); - g_signal_connect (widget, "clicked", G_CALLBACK(gtk_main_quit), &window); - - // Finally we can show everything. - gtk_widget_show_all (window); - - gtk_main (); - - if (close_style == 1) - { - GtkTreeModel *model; - GValue value = { 0, { {0} } }; - - // Find out which IWAD was selected. - gtk_tree_selection_get_selected (selection, &model, &iter); - gtk_tree_model_get_value (GTK_TREE_MODEL(model), &iter, 2, &value); - i = g_value_get_int (&value); - g_value_unset (&value); - - // Set state of queryiwad based on the checkbox. - queryiwad = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check)); - } - else - { - i = -1; - } - - if (GTK_IS_WINDOW(window)) - { - gtk_widget_destroy (window); - // If we don't do this, then the X window might not actually disappear. - while (g_main_context_iteration (NULL, FALSE)) {} - } - - return i; -} - -static void ShowError(const char* errortext) -{ - GtkWidget *window; - GtkWidget *widget; - GtkWidget *vbox = nullptr; - GtkWidget *bbox = nullptr; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW(window), "Fatal error"); - gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER); - gtk_window_set_gravity (GTK_WINDOW(window), GDK_GRAVITY_CENTER); - gtk_window_set_resizable (GTK_WINDOW(window), false); - gtk_container_set_border_width (GTK_CONTAINER(window), 10); - g_signal_connect (window, "delete_event", G_CALLBACK(gtk_main_quit), NULL); - g_signal_connect (window, "key_press_event", G_CALLBACK(CheckEscape), NULL); - - // Create the vbox container. - if (gtk_box_new) // Gtk3 - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); - else if (gtk_vbox_new) // Gtk2 - vbox = gtk_vbox_new (FALSE, 10); - - gtk_container_add (GTK_CONTAINER(window), vbox); - - // Create the label. - widget = gtk_label_new ((const gchar *) errortext); - gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0); - - if (gtk_widget_set_halign && gtk_widget_set_valign) // Gtk3 - { - gtk_widget_set_halign (widget, GTK_ALIGN_START); - gtk_widget_set_valign (widget, GTK_ALIGN_START); - } - else if (gtk_misc_set_alignment && gtk_misc_get_type) // Gtk2 - gtk_misc_set_alignment (GTK_MISC(widget), 0, 0); - - // Create the Exit button box. - if (gtk_button_box_new) // Gtk3 - bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); - else if (gtk_hbutton_box_new) // Gtk2 - bbox = gtk_hbutton_box_new (); - - gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_box_set_spacing (GTK_BOX(bbox), 10); - gtk_box_pack_end (GTK_BOX(vbox), bbox, false, false, 0); - - // Create the cancel button. - widget = gtk_button_new_with_label ("Exit"); - gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); - g_signal_connect (widget, "clicked", G_CALLBACK(gtk_main_quit), &window); - - // Finally we can show everything. - gtk_widget_show_all (window); - - gtk_main (); - - if (GTK_IS_WINDOW(window)) - { - gtk_widget_destroy (window); - // If we don't do this, then the X window might not actually disappear. - while (g_main_context_iteration (NULL, FALSE)) {} - } -} - -} // namespace Gtk - -int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad) -{ - return Gtk::PickIWad (wads, numwads, showwin, defaultiwad); -} - -void I_ShowFatalError_Gtk(const char* errortext) { - Gtk::ShowError(errortext); -} - -bool I_GtkAvailable() -{ - using namespace Gtk; - - if(GtkAvailable < 0) - { - if (!GtkModule.Load({"libgtk-3.so.0", "libgtk-x11-2.0.so.0"})) - { - GtkAvailable = 0; - return false; - } - - int argc = 0; - char **argv = nullptr; - GtkAvailable = Gtk::gtk_init_check (&argc, &argv); - } - - return GtkAvailable != 0; -} - -#endif diff --git a/src/posix/unix/i_specialpaths.cpp b/src/posix/unix/i_specialpaths.cpp deleted file mode 100644 index b6cba526ac1..00000000000 --- a/src/posix/unix/i_specialpaths.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* -** i_specialpaths.cpp -** Gets special system folders where data should be stored. (Unix version) -** -**--------------------------------------------------------------------------- -** Copyright 2013-2016 Randy Heit -** Copyright 2016 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#include "i_system.h" -#include "cmdlib.h" -#include "doomerrors.h" - -#include "version.h" // for GAMENAME - - -FString GetUserFile (const char *file) -{ - FString path; - struct stat info; - - path = NicePath("$HOME/" GAME_DIR "/"); - - if (stat (path, &info) == -1) - { - struct stat extrainfo; - - // Sanity check for $HOME/.config - FString configPath = NicePath("$HOME/.config/"); - if (stat (configPath, &extrainfo) == -1) - { - if (mkdir (configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) - { - I_FatalError ("Failed to create $HOME/.config directory:\n%s", strerror(errno)); - } - } - else if (!S_ISDIR(extrainfo.st_mode)) - { - I_FatalError ("$HOME/.config must be a directory"); - } - - // This can be removed after a release or two - // Transfer the old zdoom directory to the new location - bool moved = false; - FString oldpath = NicePath("$HOME/." GAMENAMELOWERCASE "/"); - if (stat (oldpath, &extrainfo) != -1) - { - if (rename(oldpath, path) == -1) - { - I_Error ("Failed to move old " GAMENAMELOWERCASE " directory (%s) to new location (%s).", - oldpath.GetChars(), path.GetChars()); - } - else - moved = true; - } - - if (!moved && mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) - { - I_FatalError ("Failed to create %s directory:\n%s", - path.GetChars(), strerror (errno)); - } - } - else - { - if (!S_ISDIR(info.st_mode)) - { - I_FatalError ("%s must be a directory", path.GetChars()); - } - } - path += file; - return path; -} - -//=========================================================================== -// -// M_GetAppDataPath Unix -// -// Returns the path for the AppData folder. -// -//=========================================================================== - -FString M_GetAppDataPath(bool create) -{ - // Don't use GAME_DIR and such so that ZDoom and its child ports can - // share the node cache. - FString path = NicePath("$HOME/.config/" GAMENAMELOWERCASE); - if (create) - { - CreatePath(path); - } - return path; -} - -//=========================================================================== -// -// M_GetCachePath Unix -// -// Returns the path for cache GL nodes. -// -//=========================================================================== - -FString M_GetCachePath(bool create) -{ - // Don't use GAME_DIR and such so that ZDoom and its child ports can - // share the node cache. - FString path = NicePath("$HOME/.config/zdoom/cache"); - if (create) - { - CreatePath(path); - } - return path; -} - -//=========================================================================== -// -// M_GetAutoexecPath Unix -// -// Returns the expected location of autoexec.cfg. -// -//=========================================================================== - -FString M_GetAutoexecPath() -{ - return GetUserFile("autoexec.cfg"); -} - -//=========================================================================== -// -// M_GetCajunPath Unix -// -// Returns the location of the Cajun Bot definitions. -// -//=========================================================================== - -FString M_GetCajunPath(const char *botfilename) -{ - FString path; - - // Check first in $HOME/.config/zdoom/botfilename. - path = GetUserFile(botfilename); - if (!FileExists(path)) - { - // Then check in SHARE_DIR/botfilename. - path = SHARE_DIR; - path << botfilename; - if (!FileExists(path)) - { - path = ""; - } - } - return path; -} - -//=========================================================================== -// -// M_GetConfigPath Unix -// -// Returns the path to the config file. On Windows, this can vary for reading -// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try -// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. -// -//=========================================================================== - -FString M_GetConfigPath(bool for_reading) -{ - return GetUserFile(GAMENAMELOWERCASE ".ini"); -} - -//=========================================================================== -// -// M_GetScreenshotsPath Unix -// -// Returns the path to the default screenshots directory. -// -//=========================================================================== - -FString M_GetScreenshotsPath() -{ - return NicePath("$HOME/" GAME_DIR "/screenshots/"); -} - -//=========================================================================== -// -// M_GetSavegamesPath Unix -// -// Returns the path to the default save games directory. -// -//=========================================================================== - -FString M_GetSavegamesPath() -{ - return NicePath("$HOME/" GAME_DIR); -} - -//=========================================================================== -// -// M_GetDocumentsPath Unix -// -// Returns the path to the default documents directory. -// -//=========================================================================== - -FString M_GetDocumentsPath() -{ - return NicePath("$HOME/" GAME_DIR); -} diff --git a/src/r_data/colormaps.cpp b/src/r_data/colormaps.cpp index f33463d5c43..4d9604b6148 100644 --- a/src/r_data/colormaps.cpp +++ b/src/r_data/colormaps.cpp @@ -39,10 +39,12 @@ #include -#include "w_wad.h" +#include "filesystem.h" #include "r_sky.h" +#include "textures.h" #include "colormaps.h" -#include "templates.h" + +#include "c_cvars.h" CUSTOM_CVAR(Bool, cl_customizeinvulmap, false, CVAR_ARCHIVE|CVAR_NOINITCALL) { @@ -62,114 +64,10 @@ CUSTOM_CVAR(Color, cl_custominvulmapcolor2, 0xa6a67a, CVAR_ARCHIVE|CVAR_NOINITCA TArray fakecmaps; -TArray SpecialColormaps; -uint8_t DesaturateColormap[31][256]; - -struct FSpecialColormapParameters -{ - float Start[3], End[3]; -}; - -static FSpecialColormapParameters SpecialColormapParms[] = -{ - // Doom invulnerability is an inverted grayscale. - // Strife uses it when firing the Sigil - { { 1, 1, 1 }, { 0, 0, 0 } }, - - // Heretic invulnerability is a golden shade. - { { 0, 0, 0 }, { 1.5, 0.75, 0 }, }, - - // [BC] Build the Doomsphere colormap. It is red! - { { 0, 0, 0 }, { 1.5, 0, 0 } }, - - // [BC] Build the Guardsphere colormap. It's a greenish-white kind of thing. - { { 0, 0, 0 }, { 1.25, 1.5, 1 } }, - - // Build a blue colormap. - { { 0, 0, 0 }, { 0, 0, 1.5 } }, -}; - static void FreeSpecialLights(); -//========================================================================== -// -// -// -//========================================================================== - -static void UpdateSpecialColormap(unsigned int index, float r1, float g1, float b1, float r2, float g2, float b2); - -int AddSpecialColormap(float r1, float g1, float b1, float r2, float g2, float b2) -{ - // Clamp these in range for the hardware shader. - r1 = clamp(r1, 0.0f, 2.0f); - g1 = clamp(g1, 0.0f, 2.0f); - b1 = clamp(b1, 0.0f, 2.0f); - r2 = clamp(r2, 0.0f, 2.0f); - g2 = clamp(g2, 0.0f, 2.0f); - b2 = clamp(b2, 0.0f, 2.0f); - - for(unsigned i=0; iColorizeStart[0] = float(r1); - cm->ColorizeStart[1] = float(g1); - cm->ColorizeStart[2] = float(b1); - cm->ColorizeEnd[0] = float(r2); - cm->ColorizeEnd[1] = float(g2); - cm->ColorizeEnd[2] = float(b2); - - r2 -= r1; - g2 -= g1; - b2 -= b1; - r1 *= 255; - g1 *= 255; - b1 *= 255; - - for (int c = 0; c < 256; c++) - { - double intensity = (GPalette.BaseColors[c].r * 77 + - GPalette.BaseColors[c].g * 143 + - GPalette.BaseColors[c].b * 37) / 256.0; - - PalEntry pe = PalEntry( MIN(255, int(r1 + intensity*r2)), - MIN(255, int(g1 + intensity*g2)), - MIN(255, int(b1 + intensity*b2))); - - cm->Colormap[c] = ColorMatcher.Pick(pe); - } - - // This table is used by the texture composition code - for(int i = 0;i < 256; i++) - { - cm->GrayscaleToColor[i] = PalEntry( MIN(255, int(r1 + i*r2)), - MIN(255, int(g1 + i*g2)), - MIN(255, int(b1 + i*b2))); - } -} - //========================================================================== // // R_DeinitColormaps @@ -202,17 +100,15 @@ void R_InitColormaps (bool allowCustomColormap) cm.blend = 0; fakecmaps.Push(cm); - uint32_t NumLumps = Wads.GetNumLumps(); + uint32_t NumLumps = fileSystem.GetNumEntries(); for (uint32_t i = 0; i < NumLumps; i++) { - if (Wads.GetLumpNamespace(i) == ns_colormaps) + if (fileSystem.GetFileNamespace(i) == FileSys::ns_colormaps) { - char name[9]; - name[8] = 0; - Wads.GetLumpName (name, i); + auto name = fileSystem.GetFileShortName(i); - if (Wads.CheckNumForName (name, ns_colormaps) == (int)i) + if (fileSystem.CheckNumForName (name, FileSys::ns_colormaps) == (int)i) { strncpy(cm.name, name, 8); cm.blend = 0; @@ -242,10 +138,10 @@ void R_InitColormaps (bool allowCustomColormap) for (unsigned j = 1; j < fakecmaps.Size(); j++) { - if (Wads.LumpLength (fakecmaps[j].lump) >= 256) + if (fileSystem.FileLength (fakecmaps[j].lump) >= 256) { int k, r, g, b; - auto lump = Wads.OpenLumpReader (fakecmaps[j].lump); + auto lump = fileSystem.OpenFileReader (fakecmaps[j].lump); lump.Read(map, 256); r = g = b = 0; @@ -259,7 +155,7 @@ void R_InitColormaps (bool allowCustomColormap) g /= 256; b /= 256; // The calculated average is too dark so brighten it according to the palettes's overall brightness - int maxcol = MAX(MAX(palette_brightness, r), MAX(g, b)); + int maxcol = max(max(palette_brightness, r), max(g, b)); fakecmaps[j].blend = PalEntry (255, r * 255 / maxcol, g * 255 / maxcol, b * 255 / maxcol); } @@ -267,29 +163,8 @@ void R_InitColormaps (bool allowCustomColormap) } // build default special maps (e.g. invulnerability) - - for (unsigned i = 0; i < countof(SpecialColormapParms); ++i) - { - AddSpecialColormap(SpecialColormapParms[i].Start[0], SpecialColormapParms[i].Start[1], - SpecialColormapParms[i].Start[2], SpecialColormapParms[i].End[0], - SpecialColormapParms[i].End[1], SpecialColormapParms[i].End[2]); - } - // desaturated colormaps. These are used for texture composition - for(int m = 0; m < 31; m++) - { - uint8_t *shade = DesaturateColormap[m]; - for (int c = 0; c < 256; c++) - { - int intensity = (GPalette.BaseColors[c].r * 77 + - GPalette.BaseColors[c].g * 143 + - GPalette.BaseColors[c].b * 37) / 256; - - int r = (GPalette.BaseColors[c].r * (31-m) + intensity *m) / 31; - int g = (GPalette.BaseColors[c].g * (31-m) + intensity *m) / 31; - int b = (GPalette.BaseColors[c].b * (31-m) + intensity *m) / 31; - shade[c] = ColorMatcher.Pick(r, g, b); - } - } + InitSpecialColormaps(GPalette.BaseColors); + R_UpdateInvulnerabilityColormap(); } //========================================================================== @@ -339,32 +214,24 @@ uint32_t R_BlendForColormap (uint32_t map) void R_UpdateInvulnerabilityColormap() { - float r1, g1, b1, r2, g2, b2; - // some of us really don't like Doom's idea of an invulnerability sphere colormap // this hack will override that if (cl_customizeinvulmap) { uint32_t color1 = cl_custominvulmapcolor1; uint32_t color2 = cl_custominvulmapcolor2; - r1 = (float)((color1 & 0xff0000) >> 16) / 128.f; - g1 = (float)((color1 & 0x00ff00) >> 8) / 128.f; - b1 = (float)((color1 & 0x0000ff) >> 0) / 128.f; - r2 = (float)((color2 & 0xff0000) >> 16) / 128.f; - g2 = (float)((color2 & 0x00ff00) >> 8) / 128.f; - b2 = (float)((color2 & 0x0000ff) >> 0) / 128.f; + float r1 = (float)((color1 & 0xff0000) >> 16) / 128.f; + float g1 = (float)((color1 & 0x00ff00) >> 8) / 128.f; + float b1 = (float)((color1 & 0x0000ff) >> 0) / 128.f; + float r2 = (float)((color2 & 0xff0000) >> 16) / 128.f; + float g2 = (float)((color2 & 0x00ff00) >> 8) / 128.f; + float b2 = (float)((color2 & 0x0000ff) >> 0) / 128.f; + UpdateSpecialColormap(GPalette.BaseColors, 0, r1, g1, b1, r2, g2, b2); } else { - FSpecialColormapParameters &defaultColors = SpecialColormapParms[0]; - r1 = defaultColors.Start[0]; - g1 = defaultColors.Start[1]; - b1 = defaultColors.Start[2]; - r2 = defaultColors.End[0]; - g2 = defaultColors.End[1]; - b2 = defaultColors.End[2]; + SpecialColormaps[INVERSECOLORMAP] = SpecialColormaps[REALINVERSECOLORMAP]; } - UpdateSpecialColormap(0, r1, g1, b1, r2, g2, b2); } diff --git a/src/r_data/colormaps.h b/src/r_data/colormaps.h index 90927f52540..e7ee2be4295 100644 --- a/src/r_data/colormaps.h +++ b/src/r_data/colormaps.h @@ -23,70 +23,7 @@ struct FakeCmap extern TArray fakecmaps; -// for internal use -struct FColormap -{ - PalEntry LightColor; // a is saturation (0 full, 31=b/w, other=custom colormap) - PalEntry FadeColor; // a is fadedensity>>1 - uint8_t Desaturation; - uint8_t BlendFactor; // This is for handling Legacy-style colormaps which use a different formula to calculate how the color affects lighting. - uint16_t FogDensity; - - void Clear() - { - LightColor = 0xffffff; - FadeColor = 0; - Desaturation = 0; - BlendFactor = 0; - FogDensity = 0; - } - - void MakeWhite() - { - LightColor = 0xffffff; - } - - void ClearColor() - { - LightColor = 0xffffff; - BlendFactor = 0; - Desaturation = 0; - } - - void CopyLight(FColormap &from) - { - LightColor = from.LightColor; - Desaturation = from.Desaturation; - BlendFactor = from.BlendFactor; - } - - void CopyFog(FColormap &from) - { - FadeColor = from.FadeColor; - FogDensity = from.FogDensity; - } - - void CopyFrom3DLight(lightlist_t *light); - - void Decolorize() - { - LightColor.Decolorize(); - } - - bool operator == (const FColormap &other) - { - return LightColor == other.LightColor && FadeColor == other.FadeColor && Desaturation == other.Desaturation && - BlendFactor == other.BlendFactor && FogDensity == other.FogDensity; - } - - bool operator != (const FColormap &other) - { - return !operator==(other); - } - -}; - - +#include "fcolormap.h" // For hardware-accelerated weapon sprites in colored sectors struct FColormapStyle @@ -97,23 +34,6 @@ struct FColormapStyle float FadeLevel; }; -enum -{ - NOFIXEDCOLORMAP = -1, - INVERSECOLORMAP, // the inverse map is used explicitly in a few places. -}; - - -struct FSpecialColormap -{ - float ColorizeStart[3]; - float ColorizeEnd[3]; - uint8_t Colormap[256]; - PalEntry GrayscaleToColor[256]; -}; - -extern TArray SpecialColormaps; - // some utility functions to store special colormaps in powerup blends #define SPECIALCOLORMAP_MASK 0x00b60000 @@ -123,24 +43,4 @@ inline uint32_t MakeSpecialColormap(int index) return index | SPECIALCOLORMAP_MASK; } -int AddSpecialColormap(float r1, float g1, float b1, float r2, float g2, float b2); - - - -extern uint8_t DesaturateColormap[31][256]; - - -enum EColorManipulation -{ - CM_PLAIN2D = -2, // regular 2D drawing. - CM_INVALID = -1, - CM_DEFAULT = 0, // untranslated - CM_FIRSTSPECIALCOLORMAP, // first special fixed colormap - CM_FIRSTSPECIALCOLORMAPFORCED = 0x08000000, // first special fixed colormap, application forced (for 2D overlays) -}; - -#define CM_MAXCOLORMAP int(CM_FIRSTSPECIALCOLORMAP + SpecialColormaps.Size()) -#define CM_MAXCOLORMAPFORCED int(CM_FIRSTSPECIALCOLORMAPFORCED + SpecialColormaps.Size()) - - #endif diff --git a/src/r_data/gldefs.cpp b/src/r_data/gldefs.cpp index a08ee8f6ea8..9b5be0e25a3 100644 --- a/src/r_data/gldefs.cpp +++ b/src/r_data/gldefs.cpp @@ -35,8 +35,8 @@ #include #include "sc_man.h" -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "gi.h" #include "r_state.h" #include "stats.h" @@ -44,19 +44,65 @@ #include "g_levellocals.h" #include "a_dynlight.h" #include "v_video.h" -#include "textures/skyboxtexture.h" +#include "skyboxtexture.h" #include "hwrenderer/postprocessing/hw_postprocessshader.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_material.h" +#include "texturemanager.h" +#include "gameconfigfile.h" +#include "m_argv.h" void AddLightDefaults(FLightDefaults *defaults, double attnFactor); void AddLightAssociation(const char *actor, const char *frame, const char *light); void InitializeActorLights(TArray &LightAssociations); void ParseColorization(FScanner& sc); -TArray usershaders; extern TDeletingArray LightDefaults; extern int AttenuationIsSet; +bool addedcvars = false; + +struct ExtraUniformCVARData +{ + FString Shader; + FString Uniform; + double* vec4 = nullptr; + ExtraUniformCVARData* Next = nullptr; +}; + +static void do_uniform_set(float value, ExtraUniformCVARData* data) +{ + if (!(data->vec4)) + { + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader& shader = PostProcessShaders[i]; + if (strcmp(shader.Name.GetChars(), data->Shader.GetChars()) == 0) + { + data->vec4 = shader.Uniforms[data->Uniform].Values; + } + } + } + double* vec4 = data->vec4; + if (vec4) + { + vec4[0] = value; + vec4[1] = 0.0; + vec4[2] = 0.0; + vec4[3] = 1.0; + } + if (data->Next) + do_uniform_set(value, data->Next); +} + +void uniform_callback_int(FIntCVar &self) +{ + do_uniform_set ((float)self, (ExtraUniformCVARData*)self.GetExtraDataPointer()); +} + +void uniform_callback_float(FFloatCVar &self) +{ + do_uniform_set ((float)self, (ExtraUniformCVARData*)self.GetExtraDataPointer()); +} //----------------------------------------------------------------------------- // @@ -66,7 +112,7 @@ extern int AttenuationIsSet; static void ParseVavoomSkybox() { - int lump = Wads.CheckNumForName("SKYBOXES"); + int lump = fileSystem.CheckNumForName("SKYBOXES"); if (lump < 0) return; @@ -76,6 +122,7 @@ static void ParseVavoomSkybox() int facecount=0; int maplump = -1; bool error = false; + FString s = sc.String; FSkyBox * sb = new FSkyBox(sc.String); sb->fliptop = true; sc.MustGetStringName("{"); @@ -87,12 +134,12 @@ static void ParseVavoomSkybox() sc.MustGetStringName("map"); sc.MustGetString(); - maplump = Wads.CheckNumForFullName(sc.String, true); + maplump = fileSystem.CheckNumForFullName(sc.String, true); - FTexture *tex = TexMan.FindTexture(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny); + auto tex = TexMan.FindGameTexture(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny); if (tex == NULL) { - sc.ScriptMessage("Texture '%s' not found in Vavoom skybox '%s'\n", sc.String, sb->GetName().GetChars()); + sc.ScriptMessage("Texture '%s' not found in Vavoom skybox '%s'\n", sc.String, s.GetChars()); error = true; } sb->faces[facecount] = tex; @@ -102,12 +149,12 @@ static void ParseVavoomSkybox() } if (facecount != 6) { - sc.ScriptError("%s: Skybox definition requires 6 faces", sb->GetName().GetChars()); + sc.ScriptError("%s: Skybox definition requires 6 faces", s.GetChars()); } sb->SetSize(); if (!error) { - TexMan.AddTexture(sb); + TexMan.AddGameTexture(MakeGameTexture(sb, s.GetChars(), ETextureType::Override)); } } } @@ -142,6 +189,8 @@ static const char *LightTags[]= "dontlightactors", "spot", "noshadowmap", + "dontlightothers", + "dontlightmap", nullptr }; @@ -166,6 +215,8 @@ enum { LIGHTTAG_DONTLIGHTACTORS, LIGHTTAG_SPOT, LIGHTTAG_NOSHADOWMAP, + LIGHTTAG_DONTLIGHTOTHERS, + LIGHTTAG_DONTLIGHTMAP, }; //========================================================================== @@ -466,6 +517,12 @@ class GLDefsParser case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTOTHERS: + defaults->SetDontLightOthers(ParseInt(sc) != 0); + break; + case LIGHTTAG_DONTLIGHTMAP: + defaults->SetDontLightMap(ParseInt(sc) != 0); + break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); @@ -562,6 +619,12 @@ class GLDefsParser case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTOTHERS: + defaults->SetDontLightOthers(ParseInt(sc) != 0); + break; + case LIGHTTAG_DONTLIGHTMAP: + defaults->SetDontLightMap(ParseInt(sc) != 0); + break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); @@ -661,6 +724,12 @@ class GLDefsParser case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTOTHERS: + defaults->SetDontLightOthers(ParseInt(sc) != 0); + break; + case LIGHTTAG_DONTLIGHTMAP: + defaults->SetDontLightMap(ParseInt(sc) != 0); + break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); @@ -759,6 +828,12 @@ class GLDefsParser case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTOTHERS: + defaults->SetDontLightOthers(ParseInt(sc) != 0); + break; + case LIGHTTAG_DONTLIGHTMAP: + defaults->SetDontLightMap(ParseInt(sc) != 0); + break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); @@ -854,6 +929,12 @@ class GLDefsParser case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTOTHERS: + defaults->SetDontLightOthers(ParseInt(sc) != 0); + break; + case LIGHTTAG_DONTLIGHTMAP: + defaults->SetDontLightMap(ParseInt(sc) != 0); + break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); @@ -916,7 +997,7 @@ class GLDefsParser break; case LIGHTTAG_LIGHT: ParseString(sc); - AddLightAssociation(name, frameName, sc.String); + AddLightAssociation(name.GetChars(), frameName.GetChars(), sc.String); break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); @@ -990,8 +1071,8 @@ class GLDefsParser sc.MustGetString(); - FSkyBox * sb = new FSkyBox(sc.String); - sb->Name.ToUpper(); + FString s = sc.String; + FSkyBox * sb = new FSkyBox(s.GetChars()); if (sc.CheckString("fliptop")) { sb->fliptop = true; @@ -1002,16 +1083,16 @@ class GLDefsParser sc.MustGetString(); if (facecount<6) { - sb->faces[facecount] = TexMan.GetTexture(TexMan.GetTextureID(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_Overridable)); + sb->faces[facecount] = TexMan.GetGameTexture(TexMan.GetTextureID(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_Overridable)); } facecount++; } if (facecount != 3 && facecount != 6) { - sc.ScriptError("%s: Skybox definition requires either 3 or 6 faces", sb->Name.GetChars()); + sc.ScriptError("%s: Skybox definition requires either 3 or 6 faces", s.GetChars()); } sb->SetSize(); - TexMan.AddTexture(sb); + TexMan.AddGameTexture(MakeGameTexture(sb, s.GetChars(), ETextureType::Override)); } //=========================================================================== @@ -1033,8 +1114,8 @@ class GLDefsParser { sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Flat,FTextureManager::TEXMAN_TryAny); - FTexture *tex = TexMan.GetTexture(flump); - if (tex) tex->bAutoGlowing = tex->bGlowing = tex->bFullbright = true; + auto tex = TexMan.GetGameTexture(flump); + if (tex) tex->SetAutoGlowing(); } } else if (sc.Compare("WALLS")) @@ -1044,8 +1125,8 @@ class GLDefsParser { sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Wall,FTextureManager::TEXMAN_TryAny); - FTexture *tex = TexMan.GetTexture(flump); - if (tex) tex->bAutoGlowing = tex->bGlowing = tex->bFullbright = true; + auto tex = TexMan.GetGameTexture(flump); + if (tex) tex->SetAutoGlowing(); } } else if (sc.Compare("TEXTURE")) @@ -1053,31 +1134,29 @@ class GLDefsParser sc.SetCMode(true); sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Flat,FTextureManager::TEXMAN_TryAny); - FTexture *tex = TexMan.GetTexture(flump); + auto tex = TexMan.GetGameTexture(flump); sc.MustGetStringName(","); sc.MustGetString(); - PalEntry color = V_GetColor(NULL, sc.String); + PalEntry color = V_GetColor(sc.String); //sc.MustGetStringName(","); //sc.MustGetNumber(); if (sc.CheckString(",")) { if (sc.CheckNumber()) { - if (tex) tex->GlowHeight = sc.Number; + if (tex) tex->SetGlowHeight(sc.Number); if (!sc.CheckString(",")) goto skip_fb; } sc.MustGetStringName("fullbright"); - if (tex) tex->bFullbright = true; + if (tex) tex->SetFullbright(); } skip_fb: sc.SetCMode(false); if (tex && color != 0) { - tex->bAutoGlowing = false; - tex->bGlowing = true; - tex->GlowColor = color; + tex->SetGlowing(color); } } } @@ -1096,7 +1175,7 @@ class GLDefsParser bool disable_fullbright=false; bool thiswad = false; bool iwad = false; - FTexture *bmtex = NULL; + FGameTexture *bmtex = NULL; sc.MustGetString(); if (sc.Compare("texture")) type = ETextureType::Wall; @@ -1106,7 +1185,7 @@ class GLDefsParser sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable); - FTexture *tex = TexMan.GetTexture(no); + auto tex = TexMan.GetGameTexture(no); sc.MustGetToken('{'); while (!sc.CheckToken('}')) @@ -1135,13 +1214,13 @@ class GLDefsParser if (bmtex != NULL) { - Printf("Multiple brightmap definitions in texture %s\n", tex? tex->Name.GetChars() : "(null)"); + Printf("Multiple brightmap definitions in texture %s\n", tex? tex->GetName().GetChars() : "(null)"); } - bmtex = TexMan.FindTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); + bmtex = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); if (bmtex == NULL) - Printf("Brightmap '%s' not found in texture '%s'\n", sc.String, tex? tex->Name.GetChars() : "(null)"); + Printf("Brightmap '%s' not found in texture '%s'\n", sc.String, tex? tex->GetName().GetChars() : "(null)"); } } if (!tex) @@ -1155,28 +1234,27 @@ class GLDefsParser if (lumpnum != -1) { - if (iwad && Wads.GetLumpFile(lumpnum) <= Wads.GetMaxIwadNum()) useme = true; - if (thiswad && Wads.GetLumpFile(lumpnum) == workingLump) useme = true; + if (iwad && fileSystem.GetFileContainer(lumpnum) <= fileSystem.GetMaxIwadNum()) useme = true; + if (thiswad && fileSystem.GetFileContainer(lumpnum) == fileSystem.GetFileContainer(workingLump)) useme = true; } if (!useme) return; } if (bmtex != NULL) { - bmtex->bMasked = false; - tex->Brightmap = bmtex; + tex->SetBrightmap(bmtex); } - tex->bDisableFullbright = disable_fullbright; + tex->SetDisableFullbright(disable_fullbright); } - void SetShaderIndex(FTexture *tex, unsigned index) + void SetShaderIndex(FGameTexture *tex, unsigned index) { auto desc = usershaders[index - FIRST_USER_SHADER]; if (desc.disablealphatest) { - tex->bTranslucent = true; + tex->SetTranslucent(true); } - tex->shaderindex = index; + tex->SetShaderIndex(index); } //========================================================================== @@ -1198,10 +1276,10 @@ class GLDefsParser TArray texNameIndex; float speed = 1.f; - FTexture *textures[6]; + MaterialLayers mlay = { -1000, -1000 }; + FGameTexture* textures[6] = {}; const char *keywords[7] = { "brightmap", "normal", "specular", "metallic", "roughness", "ao", nullptr }; const char *notFound[6] = { "Brightmap", "Normalmap", "Specular texture", "Metallic texture", "Roughness texture", "Ambient occlusion texture" }; - memset(textures, 0, sizeof(textures)); sc.MustGetString(); if (sc.Compare("texture")) type = ETextureType::Wall; @@ -1211,12 +1289,13 @@ class GLDefsParser sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable); - FTexture *tex = TexMan.GetTexture(no); + auto tex = TexMan.GetGameTexture(no); if (tex == nullptr) { sc.ScriptMessage("Material definition refers nonexistent texture '%s'\n", sc.String); } + else tex->AddAutoMaterials(); // We need these before setting up the texture. sc.MustGetToken('{'); while (!sc.CheckToken('}')) @@ -1243,14 +1322,12 @@ class GLDefsParser else if (sc.Compare("glossiness")) { sc.MustGetFloat(); - if (tex) - tex->Glossiness = (float)sc.Float; + mlay.Glossiness = (float)sc.Float; } else if (sc.Compare("specularlevel")) { sc.MustGetFloat(); - if (tex) - tex->SpecularLevel = (float)sc.Float; + mlay.SpecularLevel = (float)sc.Float; } else if (sc.Compare("speed")) { @@ -1270,32 +1347,32 @@ class GLDefsParser { if (!texName.Compare(textureName)) { - sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex ? tex->Name.GetChars() : "(null)"); + sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex ? tex->GetName().GetChars() : "(null)"); } } sc.MustGetString(); if (tex) { bool okay = false; - for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++) + for (size_t i = 0; i < countof(mlay.CustomShaderTextures); i++) { - if (!tex->CustomShaderTextures[i]) + if (!mlay.CustomShaderTextures[i]) { - tex->CustomShaderTextures[i] = TexMan.FindTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); - if (!tex->CustomShaderTextures[i]) + mlay.CustomShaderTextures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); + if (!mlay.CustomShaderTextures[i]) { - sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex->Name.GetChars()); + sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex->GetName().GetChars()); } texNameList.Push(textureName); - texNameIndex.Push(i); + texNameIndex.Push((int)i); okay = true; break; } } if (!okay) { - sc.ScriptError("Error: out of texture units in texture '%s'", tex->Name.GetChars()); + sc.ScriptError("Error: out of texture units in texture '%s'", tex->GetName().GetChars()); } } } @@ -1319,10 +1396,10 @@ class GLDefsParser { sc.MustGetString(); if (textures[i]) - Printf("Multiple %s definitions in texture %s\n", keywords[i], tex? tex->Name.GetChars() : "(null)"); - textures[i] = TexMan.FindTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); + Printf("Multiple %s definitions in texture %s\n", keywords[i], tex? tex->GetName().GetChars() : "(null)"); + textures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); if (!textures[i]) - Printf("%s '%s' not found in texture '%s'\n", notFound[i], sc.String, tex? tex->Name.GetChars() : "(null)"); + Printf("%s '%s' not found in texture '%s'\n", notFound[i], sc.String, tex? tex->GetName().GetChars() : "(null)"); break; } } @@ -1339,50 +1416,49 @@ class GLDefsParser if (lumpnum != -1) { - if (iwad && Wads.GetLumpFile(lumpnum) <= Wads.GetMaxIwadNum()) useme = true; - if (thiswad && Wads.GetLumpFile(lumpnum) == workingLump) useme = true; + if (iwad && fileSystem.GetFileContainer(lumpnum) <= fileSystem.GetMaxIwadNum()) useme = true; + if (thiswad && fileSystem.GetFileContainer(lumpnum) == fileSystem.GetFileContainer(workingLump)) useme = true; } if (!useme) return; } - FTexture **bindings[6] = + FGameTexture **bindings[6] = { - &tex->Brightmap, - &tex->Normal, - &tex->Specular, - &tex->Metallic, - &tex->Roughness, - &tex->AmbientOcclusion + &mlay.Brightmap, + &mlay.Normal, + &mlay.Specular, + &mlay.Metallic, + &mlay.Roughness, + &mlay.AmbientOcclusion }; for (int i = 0; keywords[i] != nullptr; i++) { if (textures[i]) { - textures[i]->bMasked = false; *bindings[i] = textures[i]; } } if (disable_fullbright_specified) - tex->bDisableFullbright = disable_fullbright; + tex->SetDisableFullbright(disable_fullbright); if (usershader.shader.IsNotEmpty()) { int firstUserTexture; - if (tex->Normal && tex->Specular) + if ((mlay.Normal || tex->GetNormalmap()) && (mlay.Specular || tex->GetSpecularmap())) { - usershader.shaderType = tex->Brightmap ? SHADER_SpecularBrightmap : SHADER_Specular; - firstUserTexture = tex->Brightmap ? 5 : 4; + usershader.shaderType = SHADER_Specular; + firstUserTexture = 7; } - else if (tex->Normal && tex->Metallic && tex->Roughness && tex->AmbientOcclusion) + else if ((mlay.Normal || tex->GetNormalmap()) && (mlay.Metallic || tex->GetMetallic()) && (mlay.Roughness || tex->GetRoughness()) && (mlay.AmbientOcclusion || tex->GetAmbientOcclusion())) { - usershader.shaderType = tex->Brightmap ? SHADER_PBRBrightmap : SHADER_PBR; - firstUserTexture = tex->Brightmap ? 7 : 6; + usershader.shaderType = SHADER_PBR; + firstUserTexture = 9; } else { - usershader.shaderType = tex->Brightmap ? SHADER_Brightmap : SHADER_Default; - firstUserTexture = tex->Brightmap ? 3 : 2; + usershader.shaderType = SHADER_Default; + firstUserTexture = 5; } for (unsigned int i = 0; i < texNameList.Size(); i++) @@ -1392,10 +1468,10 @@ class GLDefsParser if (tex->isWarped() != 0) { - Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->Name.GetChars()); + Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->GetName().GetChars()); return; } - tex->shaderspeed = speed; + tex->SetShaderSpeed(speed); for (unsigned i = 0; i < usershaders.Size(); i++) { if (!usershaders[i].shader.CompareNoCase(usershader.shader) && @@ -1403,11 +1479,13 @@ class GLDefsParser !usershaders[i].defines.Compare(usershader.defines)) { SetShaderIndex(tex, i + FIRST_USER_SHADER); + tex->SetShaderLayers(mlay); return; } } SetShaderIndex(tex, usershaders.Push(usershader) + FIRST_USER_SHADER); } + tex->SetShaderLayers(mlay); } @@ -1454,8 +1532,10 @@ class GLDefsParser sc.MustGetString(); shaderdesc.Name = sc.String; } - else if (sc.Compare("uniform")) + else if (sc.Compare("uniform") || sc.Compare("cvar_uniform")) { + bool is_cvar = sc.Compare("cvar_uniform"); + sc.MustGetString(); FString uniformType = sc.String; uniformType.ToLower(); @@ -1476,8 +1556,96 @@ class GLDefsParser else sc.ScriptError("Unrecognized uniform type '%s'", sc.String); + auto strUniformType = sc.String; + if (parsedType != PostProcessUniformType::Undefined) shaderdesc.Uniforms[uniformName].Type = parsedType; + + if (is_cvar) + { + addedcvars = true; + if (shaderdesc.Name.IsEmpty()) + sc.ScriptError("Shader must have a name to use cvar uniforms"); + + ECVarType cvartype = CVAR_Dummy; + int cvarflags = CVAR_MOD|CVAR_ARCHIVE|CVAR_VIRTUAL; + FBaseCVar *cvar; + void (*callback)(FBaseCVar&) = NULL; + FString cvarname; + switch (parsedType) + { + case PostProcessUniformType::Int: + cvartype = CVAR_Int; + callback = (void (*)(FBaseCVar&))uniform_callback_int; + break; + case PostProcessUniformType::Float: + cvartype = CVAR_Float; + callback = (void (*)(FBaseCVar&))uniform_callback_float; + break; + default: + sc.ScriptError("'%s' not supported for CVAR uniforms!", strUniformType); + break; + } + sc.MustGetString(); + cvarname = sc.String; + cvar = FindCVar(cvarname.GetChars(), NULL); + + UCVarValue oldval; + UCVarValue val; + ExtraUniformCVARData* oldextra = nullptr; + sc.MustGetFloat(); + + val.Float = oldval.Float = (float)sc.Float; + + if (!Args->CheckParm ("-shaderuniformtest")) + { + // these aren't really release-ready, so lock them behind a command-line argument for now. + sc.ScriptMessage("Warning - Use -shaderuniformtest to enable shader uniforms!"); + } + else + { + if (!cvar) + { + cvar = C_CreateCVar(cvarname.GetChars(), cvartype, cvarflags); + } + else if (cvar && (((cvar->GetFlags()) & CVAR_MOD) == CVAR_MOD)) + { + // this value may have been previously loaded + oldval.Float = cvar->GetGenericRep(CVAR_Float).Float; + oldextra = (ExtraUniformCVARData*)cvar->GetExtraDataPointer(); + } + + if (!(cvar->GetFlags() & CVAR_MOD)) + { + if (!((cvar->GetFlags() & (CVAR_AUTO | CVAR_UNSETTABLE)) == (CVAR_AUTO | CVAR_UNSETTABLE))) + sc.ScriptError("CVAR '%s' already in use!", cvarname.GetChars()); + } + + // must've picked this up from an autoexec.cfg, handle accordingly + if (cvar && ((cvar->GetFlags() & (CVAR_MOD|CVAR_AUTO|CVAR_UNSETTABLE)) == (CVAR_AUTO | CVAR_UNSETTABLE))) + { + oldval.Float = cvar->GetGenericRep(CVAR_Float).Float; + delete cvar; + cvar = C_CreateCVar(cvarname.GetChars(), cvartype, cvarflags); + oldextra = (ExtraUniformCVARData*)cvar->GetExtraDataPointer(); + } + + shaderdesc.Uniforms[uniformName].Values[0] = oldval.Float; + + cvar->SetGenericRepDefault(val, CVAR_Float); + + if (val.Float != oldval.Float) // it's not default anymore + cvar->SetGenericRep(oldval.Float, CVAR_Float); + + if (callback) + cvar->SetCallback(callback); + ExtraUniformCVARData* extra = new ExtraUniformCVARData; + extra->Shader = shaderdesc.Name.GetChars(); + extra->Uniform = uniformName.GetChars(); + extra->Next = oldextra; + cvar->SetExtraDataPointer(extra); + } + } } else if (sc.Compare("texture")) { @@ -1522,7 +1690,9 @@ class GLDefsParser sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type); - FTexture *tex = TexMan.GetTexture(no); + auto tex = TexMan.GetGameTexture(no); + if (tex) tex->AddAutoMaterials(); + MaterialLayers mlay = { -1000, -1000 }; sc.MustGetToken('{'); while (!sc.CheckToken('}')) @@ -1536,14 +1706,16 @@ class GLDefsParser else if (sc.Compare("material")) { sc.MustGetString(); - MaterialShaderIndex typeIndex[6] = { SHADER_Default, SHADER_Brightmap, SHADER_Specular, SHADER_SpecularBrightmap, SHADER_PBR, SHADER_PBRBrightmap }; - const char *typeName[6] = { "normal", "brightmap", "specular", "specularbrightmap", "pbr", "pbrbrightmap" }; + static MaterialShaderIndex typeIndex[6] = { SHADER_Default, SHADER_Default, SHADER_Specular, SHADER_Specular, SHADER_PBR, SHADER_PBR }; + static bool usesBrightmap[6] = { false, true, false, true, false, true }; + static const char *typeName[6] = { "normal", "brightmap", "specular", "specularbrightmap", "pbr", "pbrbrightmap" }; bool found = false; for (int i = 0; i < 6; i++) { if (sc.Compare(typeName[i])) { desc.shaderType = typeIndex[i]; + if (usesBrightmap[i]) desc.shaderFlags |= SFlag_Brightmap; found = true; break; } @@ -1564,30 +1736,30 @@ class GLDefsParser { if(!texName.Compare(textureName)) { - sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex? tex->Name.GetChars() : "(null)"); + sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex? tex->GetName().GetChars() : "(null)"); } } sc.MustGetString(); bool okay = false; - for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++) + for (size_t i = 0; i < countof(mlay.CustomShaderTextures); i++) { - if (!tex->CustomShaderTextures[i]) + if (!mlay.CustomShaderTextures[i]) { - tex->CustomShaderTextures[i] = TexMan.FindTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); - if (!tex->CustomShaderTextures[i]) + mlay.CustomShaderTextures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); + if (!mlay.CustomShaderTextures[i]) { - sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex? tex->Name.GetChars() : "(null)"); + sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex? tex->GetName().GetChars() : "(null)"); } texNameList.Push(textureName); - texNameIndex.Push(i); + texNameIndex.Push((int)i); okay = true; break; } } if(!okay) { - sc.ScriptError("Error: out of texture units in texture '%s'", tex? tex->Name.GetChars() : "(null)"); + sc.ScriptError("Error: out of texture units in texture '%s'", tex? tex->GetName().GetChars() : "(null)"); } } else if(sc.Compare("define")) @@ -1616,12 +1788,9 @@ class GLDefsParser switch (desc.shaderType) { default: - case SHADER_Default: firstUserTexture = 2; break; - case SHADER_Brightmap: firstUserTexture = 3; break; - case SHADER_Specular: firstUserTexture = 4; break; - case SHADER_SpecularBrightmap: firstUserTexture = 5; break; - case SHADER_PBR: firstUserTexture = 6; break; - case SHADER_PBRBrightmap: firstUserTexture = 7; break; + case SHADER_Default: firstUserTexture = 5; break; + case SHADER_Specular: firstUserTexture = 7; break; + case SHADER_PBR: firstUserTexture = 9; break; } for (unsigned int i = 0; i < texNameList.Size(); i++) @@ -1633,10 +1802,10 @@ class GLDefsParser { if (tex->isWarped() != 0) { - Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->Name.GetChars()); + Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->GetName().GetChars()); return; } - tex->shaderspeed = speed; + tex->SetShaderSpeed(speed); for (unsigned i = 0; i < usershaders.Size(); i++) { if (!usershaders[i].shader.CompareNoCase(desc.shader) && @@ -1644,11 +1813,13 @@ class GLDefsParser !usershaders[i].defines.Compare(desc.defines)) { SetShaderIndex(tex, i + FIRST_USER_SHADER); + tex->SetShaderLayers(mlay); return; } } SetShaderIndex(tex, usershaders.Push(desc) + FIRST_USER_SHADER); } + tex->SetShaderLayers(mlay); } } @@ -1670,12 +1841,12 @@ class GLDefsParser else if (sc.Compare("AddColor")) { sc.MustGetString(); - tm.AddColor = (tm.AddColor & 0xff000000) | (V_GetColor(NULL, sc) & 0xffffff); + tm.AddColor = (tm.AddColor & 0xff000000) | (V_GetColor(sc) & 0xffffff); } else if (sc.Compare("ModulateColor")) { sc.MustGetString(); - tm.ModulateColor = V_GetColor(NULL, sc) & 0xffffff; + tm.ModulateColor = V_GetColor(sc) & 0xffffff; if (sc.CheckToken(',')) { sc.MustGetNumber(); @@ -1686,7 +1857,7 @@ class GLDefsParser else if (sc.Compare("BlendColor")) { sc.MustGetString(); - tm.BlendColor = V_GetColor(NULL, sc) & 0xffffff; + tm.BlendColor = V_GetColor(sc) & 0xffffff; sc.MustGetToken(','); sc.MustGetString(); static const char* opts[] = { "none", "alpha", "screen", "overlay", "hardlight", nullptr }; @@ -1732,6 +1903,8 @@ class GLDefsParser sc.SavePos(); if (!sc.GetToken ()) { + if (addedcvars) + GameConfig->DoModSetup (gameinfo.ConfigName.GetChars()); return; } type = sc.MatchString(CoreKeywords); @@ -1741,7 +1914,7 @@ class GLDefsParser { sc.MustGetString(); // This is not using sc.Open because it can print a more useful error message when done here - lump = Wads.CheckNumForFullName(sc.String, true); + lump = fileSystem.CheckNumForFullName(sc.String, true); if (lump==-1) sc.ScriptError("Lump '%s' not found", sc.String); @@ -1835,7 +2008,7 @@ void LoadGLDefs(const char *defsLump) static const char *gldefsnames[] = { "GLDEFS", defsLump, nullptr }; lastLump = 0; - while ((workingLump = Wads.FindLumpMulti(gldefsnames, &lastLump)) != -1) + while ((workingLump = fileSystem.FindLumpMulti(gldefsnames, &lastLump)) != -1) { GLDefsParser sc(workingLump, LightAssociations); sc.DoParseDefs(); diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp new file mode 100644 index 00000000000..866e538c3d9 --- /dev/null +++ b/src/r_data/models.cpp @@ -0,0 +1,1172 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2005-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_models.cpp +** +** General model handling code +** +**/ + +#include "filesystem.h" +#include "cmdlib.h" +#include "sc_man.h" +#include "m_crc32.h" +#include "c_console.h" +#include "g_game.h" +#include "doomstat.h" +#include "g_level.h" +#include "r_state.h" +#include "d_player.h" +#include "g_levellocals.h" +#include "r_utility.h" +#include "models.h" +#include "model_kvx.h" +#include "i_time.h" +#include "texturemanager.h" +#include "modelrenderer.h" +#include "actor.h" +#include "actorinlines.h" + + +#ifdef _MSC_VER +#pragma warning(disable:4244) // warning C4244: conversion from 'double' to 'float', possible loss of data +#endif + +CVAR(Bool, gl_interpolate_model_frames, true, CVAR_ARCHIVE) +EXTERN_CVAR (Bool, r_drawvoxels) + +extern TDeletingArray Voxels; +extern TDeletingArray VoxelDefs; + +void RenderFrameModels(FModelRenderer* renderer, FLevelLocals* Level, const FSpriteModelFrame *smf, const FState* curState, const int curTics, FTranslationID translation, AActor* actor); + + +void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, double ticFrac) +{ + // Setup transformation. + + int smf_flags = smf->getFlags(actor->modelData); + + FTranslationID translation = NO_TRANSLATION; + if (!(smf_flags & MDL_IGNORETRANSLATION)) + translation = actor->Translation; + + // y scale for a sprite means height, i.e. z in the world! + float scaleFactorX = actor->Scale.X * smf->xscale; + float scaleFactorY = actor->Scale.X * smf->yscale; + float scaleFactorZ = actor->Scale.Y * smf->zscale; + float pitch = 0; + float roll = 0; + double rotateOffset = 0; + DRotator angles; + if (actor->renderflags & RF_INTERPOLATEANGLES) // [Nash] use interpolated angles + angles = actor->InterpolatedAngles(ticFrac); + else + angles = actor->Angles; + float angle = angles.Yaw.Degrees(); + + // [BB] Workaround for the missing pitch information. + if ((smf_flags & MDL_PITCHFROMMOMENTUM)) + { + const double x = actor->Vel.X; + const double y = actor->Vel.Y; + const double z = actor->Vel.Z; + + if (actor->Vel.LengthSquared() > EQUAL_EPSILON) + { + // [BB] Calculate the pitch using spherical coordinates. + if (z || x || y) pitch = float(atan(z / sqrt(x*x + y*y)) / M_PI * 180); + + // Correcting pitch if model is moving backwards + if (fabs(x) > EQUAL_EPSILON || fabs(y) > EQUAL_EPSILON) + { + if ((x * cos(angle * M_PI / 180) + y * sin(angle * M_PI / 180)) / sqrt(x * x + y * y) < 0) pitch *= -1; + } + else pitch = fabs(pitch); + } + } + + if (smf_flags & MDL_ROTATING) + { + if (smf->rotationSpeed > 0.0000000001 || smf->rotationSpeed < -0.0000000001) + { + double turns = (I_GetTime() + I_GetTimeFrac()) / (200.0 / smf->rotationSpeed); + turns -= floor(turns); + rotateOffset = turns * 360.0; + } + else + { + rotateOffset = 0.0; + } + } + + // Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing. + // If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the velocity vector pitch. + if (smf_flags & MDL_USEACTORPITCH) + { + double d = angles.Pitch.Degrees(); + if (smf_flags & MDL_BADROTATION) pitch += d; + else pitch -= d; + } + if (smf_flags & MDL_USEACTORROLL) roll += angles.Roll.Degrees(); + + VSMatrix objectToWorldMatrix; + objectToWorldMatrix.loadIdentity(); + + // Model space => World space + objectToWorldMatrix.translate(x, z, y); + + // [Nash] take SpriteRotation into account + angle += actor->SpriteRotation.Degrees(); + + // consider the pixel stretching. For non-voxels this must be factored out here + float stretch = 1.f; + + // [MK] distortions might happen depending on when the pixel stretch is compensated for + // so we make the "undistorted" behavior opt-in + if (smf_flags & MDL_CORRECTPIXELSTRETCH) + { + stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level->info->pixelstretch) : 1.f) / actor->Level->info->pixelstretch; + objectToWorldMatrix.scale(1, stretch, 1); + } + + // Applying model transformations: + // 1) Applying actor angle, pitch and roll to the model + if (smf_flags & MDL_USEROTATIONCENTER) + { + objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterZ/stretch, smf->rotationCenterY); + } + objectToWorldMatrix.rotate(-angle, 0, 1, 0); + objectToWorldMatrix.rotate(pitch, 0, 0, 1); + objectToWorldMatrix.rotate(-roll, 1, 0, 0); + if (smf_flags & MDL_USEROTATIONCENTER) + { + objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterZ/stretch, -smf->rotationCenterY); + } + + // 2) Applying Doomsday like rotation of the weapon pickup models + // The rotation angle is based on the elapsed time. + + if (smf_flags & MDL_ROTATING) + { + objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterY/stretch, smf->rotationCenterZ); + objectToWorldMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate); + objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterY/stretch, -smf->rotationCenterZ); + } + + // 3) Scaling model. + objectToWorldMatrix.scale(scaleFactorX, scaleFactorZ, scaleFactorY); + + // 4) Aplying model offsets (model offsets do not depend on model scalings). + objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / (smf->zscale*stretch), smf->yoffset / smf->yscale); + + // 5) Applying model rotations. + objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0); + objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1); + objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0); + + if (!(smf_flags & MDL_CORRECTPIXELSTRETCH)) + { + stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level->info->pixelstretch) : 1.f) / actor->Level->info->pixelstretch; + objectToWorldMatrix.scale(1, stretch, 1); + } + + float orientation = scaleFactorX * scaleFactorY * scaleFactorZ; + + renderer->BeginDrawModel(actor->RenderStyle, smf_flags, objectToWorldMatrix, orientation < 0); + RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, translation, actor); + renderer->EndDrawModel(actor->RenderStyle, smf_flags); +} + +void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf) +{ + AActor * playermo = players[consoleplayer].camera; + + int smf_flags = smf->getFlags(psp->Caller->modelData); + + // [BB] No model found for this sprite, so we can't render anything. + if (smf == nullptr) + return; + + // The model position and orientation has to be drawn independently from the position of the player, + // but we need to position it correctly in the world for light to work properly. + VSMatrix objectToWorldMatrix = renderer->GetViewToWorldMatrix(); + + // [Nash] Optional scale weapon FOV + float fovscale = 1.0f; + if (smf_flags & MDL_SCALEWEAPONFOV) + { + fovscale = tan(players[consoleplayer].DesiredFOV * (0.5f * M_PI / 180.f)); + fovscale = 1.f + (fovscale - 1.f) * cl_scaleweaponfov; + } + + // Scaling model (y scale for a sprite means height, i.e. z in the world!). + objectToWorldMatrix.scale(smf->xscale, smf->zscale, smf->yscale / fovscale); + + // Aplying model offsets (model offsets do not depend on model scalings). + objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale); + + // [BB] Weapon bob, very similar to the normal Doom weapon bob. + + + + objectToWorldMatrix.translate(rotation_pivot.X, rotation_pivot.Y, rotation_pivot.Z); + + objectToWorldMatrix.rotate(rotation.X, 0, 1, 0); + objectToWorldMatrix.rotate(rotation.Y, 1, 0, 0); + objectToWorldMatrix.rotate(rotation.Z, 0, 0, 1); + + objectToWorldMatrix.translate(-rotation_pivot.X, -rotation_pivot.Y, -rotation_pivot.Z); + + objectToWorldMatrix.translate(translation.X, translation.Y, translation.Z); + + + // [BB] For some reason the jDoom models need to be rotated. + objectToWorldMatrix.rotate(90.f, 0, 1, 0); + + // Applying angleoffset, pitchoffset, rolloffset. + objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0); + objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1); + objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0); + + float orientation = smf->xscale * smf->yscale * smf->zscale; + + renderer->BeginDrawHUDModel(playermo->RenderStyle, objectToWorldMatrix, orientation < 0, smf_flags); + auto trans = psp->GetTranslation(); + if ((psp->Flags & PSPF_PLAYERTRANSLATED)) trans = psp->Owner->mo->Translation; + + RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), trans, psp->Caller); + renderer->EndDrawHUDModel(playermo->RenderStyle, smf_flags); +} + +double getCurrentFrame(const AnimOverride &anim, double tic) +{ + if(anim.framerate <= 0) return anim.startFrame; + + double frame = ((tic - anim.startTic) / GameTicRate) * anim.framerate; // position in frames + + double duration = double(anim.lastFrame) - anim.startFrame; + + if((anim.flags & ANIMOVERRIDE_LOOP) && frame >= duration) + { + frame = frame - duration; + return fmod(frame, anim.lastFrame - anim.loopFrame) + anim.loopFrame; + } + else + { + return min(frame, duration) + anim.startFrame; + } +} + +static void calcFrame(const AnimOverride &anim, double tic, double &inter, int &prev, int &next) +{ + double frame = getCurrentFrame(anim, tic); + + prev = int(floor(frame)); + + inter = frame - prev; + + next = int(ceil(frame)); +} + +void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, FTranslationID translation, AActor* actor) +{ + // [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation + // and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame. + + int smf_flags = smf->getFlags(actor->modelData); + + const FSpriteModelFrame * smfNext = nullptr; + double inter = 0.; + double inter_main = -1.f; + double inter_next = -1.f; + + bool is_decoupled = (actor->flags9 & MF9_DECOUPLEDANIMATIONS); + + int decoupled_main_prev_frame = -1; + int decoupled_next_prev_frame = -1; + + int decoupled_main_frame = -1; + int decoupled_next_frame = -1; + + // if prev_frame == -1: interpolate(main_frame, next_frame, inter), else: interpolate(interpolate(main_prev_frame, main_frame, inter_main), interpolate(next_prev_frame, next_frame, inter_next), inter) + // 4-way interpolation is needed to interpolate animation switches between animations that aren't 35hz + + if(is_decoupled) + { + smfNext = smf = &BaseSpriteModelFrames[actor->GetClass()]; + if(actor->modelData && !(actor->modelData->curAnim.flags & ANIMOVERRIDE_NONE)) + { + double tic = actor->Level->totaltime; + if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !actor->isFrozen()) + { + tic += I_GetTimeFrac(); + } + if(actor->modelData->curAnim.startTic > tic) + { + inter = (tic - (actor->modelData->curAnim.startTic - actor->modelData->curAnim.switchOffset)) / actor->modelData->curAnim.switchOffset; + + double nextFrame = actor->modelData->curAnim.startFrame; + + double prevFrame = actor->modelData->prevAnim.startFrame; + + decoupled_next_prev_frame = floor(nextFrame); + decoupled_next_frame = ceil(nextFrame); + inter_next = nextFrame - floor(nextFrame); + + decoupled_main_prev_frame = floor(prevFrame); + decoupled_main_frame = ceil(prevFrame); + inter_main = prevFrame - floor(prevFrame); + } + else + { + calcFrame(actor->modelData->curAnim, tic, inter, decoupled_main_frame, decoupled_next_frame); + } + } + } + else if (gl_interpolate_model_frames && !(smf_flags & MDL_NOINTERPOLATION)) + { + FState *nextState = curState->GetNextState(); + if (curState != nextState && nextState) + { + // [BB] To interpolate at more than 35 fps we take tic fractions into account. + float ticFraction = 0.; + // [BB] In case the tic counter is frozen we have to leave ticFraction at zero. + if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !Level->isFrozen()) + { + ticFraction = I_GetTimeFrac(); + } + inter = static_cast(curState->Tics - curTics + ticFraction) / static_cast(curState->Tics); + + // [BB] For some actors (e.g. ZPoisonShroom) spr->actor->tics can be bigger than curState->Tics. + // In this case inter is negative and we need to set it to zero. + if (curState->Tics < curTics) + inter = 0.; + else + { + // [BB] Workaround for actors that use the same frame twice in a row. + // Most of the standard Doom monsters do this in their see state. + if ((smf_flags & MDL_INTERPOLATEDOUBLEDFRAMES)) + { + const FState *prevState = curState - 1; + if ((curState->sprite == prevState->sprite) && (curState->Frame == prevState->Frame)) + { + inter /= 2.; + inter += 0.5; + } + if (nextState && ((curState->sprite == nextState->sprite) && (curState->Frame == nextState->Frame))) + { + inter /= 2.; + nextState = nextState->GetNextState(); + } + } + if (nextState && inter != 0.0) + smfNext = FindModelFrame(actor, nextState->sprite, nextState->Frame, false); + } + } + } + + unsigned modelsamount = smf->modelsAmount; + //[SM] - if we added any models for the frame to also render, then we also need to update modelsAmount for this smf + if (actor->modelData != nullptr) + { + if (actor->modelData->models.Size() > modelsamount) + modelsamount = actor->modelData->models.Size(); + } + + TArray surfaceskinids; + + TArray boneData; + int boneStartingPosition = 0; + bool evaluatedSingle = false; + + for (unsigned i = 0; i < modelsamount; i++) + { + int modelid = -1; + int animationid = -1; + int modelframe = -1; + int modelframenext = -1; + FTextureID skinid(nullptr); + + surfaceskinids.Clear(); + + if (actor->modelData != nullptr) + { + //modelID + if (actor->modelData->models.Size() > i && actor->modelData->models[i].modelID >= 0) + { + modelid = actor->modelData->models[i].modelID; + } + else if(actor->modelData->models.Size() > i && actor->modelData->models[i].modelID == -2) + { + continue; + } + else if(smf->modelsAmount > i) + { + modelid = smf->modelIDs[i]; + } + + //animationID + if (actor->modelData->animationIDs.Size() > i && actor->modelData->animationIDs[i] >= 0) + { + animationid = actor->modelData->animationIDs[i]; + } + else if(smf->modelsAmount > i) + { + animationid = smf->animationIDs[i]; + } + if(!is_decoupled) + { + //modelFrame + if (actor->modelData->modelFrameGenerators.Size() > i + && (unsigned)actor->modelData->modelFrameGenerators[i] < modelsamount + && smf->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0 + ) { + modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]]; + + if (smfNext) + { + if(smfNext->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0) + { + modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]]; + } + else + { + modelframenext = smfNext->modelframes[i]; + } + } + } + else if(smf->modelsAmount > i) + { + modelframe = smf->modelframes[i]; + if (smfNext) modelframenext = smfNext->modelframes[i]; + } + } + + //skinID + if (actor->modelData->skinIDs.Size() > i && actor->modelData->skinIDs[i].isValid()) + { + skinid = actor->modelData->skinIDs[i]; + } + else if(smf->modelsAmount > i) + { + skinid = smf->skinIDs[i]; + } + + //surfaceSkinIDs + if(actor->modelData->models.Size() > i && actor->modelData->models[i].surfaceSkinIDs.Size() > 0) + { + unsigned sz1 = smf->surfaceskinIDs.Size(); + unsigned sz2 = actor->modelData->models[i].surfaceSkinIDs.Size(); + unsigned start = i * MD3_MAX_SURFACES; + + surfaceskinids = actor->modelData->models[i].surfaceSkinIDs; + surfaceskinids.Resize(MD3_MAX_SURFACES); + + for (unsigned surface = 0; surface < MD3_MAX_SURFACES; surface++) + { + if (sz2 > surface && (actor->modelData->models[i].surfaceSkinIDs[surface].isValid())) + { + continue; + } + if((surface + start) < sz1) + { + surfaceskinids[surface] = smf->surfaceskinIDs[surface + start]; + } + else + { + surfaceskinids[surface].SetNull(); + } + } + } + } + else + { + modelid = smf->modelIDs[i]; + animationid = smf->animationIDs[i]; + modelframe = smf->modelframes[i]; + if (smfNext) modelframenext = smfNext->modelframes[i]; + skinid = smf->skinIDs[i]; + } + + if (modelid >= 0 && modelid < Models.size()) + { + FModel * mdl = Models[modelid]; + auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr; + mdl->BuildVertexBuffer(renderer); + + auto ssidp = surfaceskinids.Size() > 0 + ? surfaceskinids.Data() + : (((i * MD3_MAX_SURFACES) < smf->surfaceskinIDs.Size()) ? &smf->surfaceskinIDs[i * MD3_MAX_SURFACES] : nullptr); + + + bool nextFrame = smfNext && modelframe != modelframenext; + + if (actor->boneComponentData == nullptr) + { + auto ptr = Create(); + ptr->trscomponents.Resize(modelsamount); + ptr->trsmatrix.Resize(modelsamount); + actor->boneComponentData = ptr; + GC::WriteBarrier(actor, ptr); + } + + // [RL0] while per-model animations aren't done, DECOUPLEDANIMATIONS does the same as MODELSAREATTACHMENTS + if ((!(smf_flags & MDL_MODELSAREATTACHMENTS) && !is_decoupled) || !evaluatedSingle) + { + if (animationid >= 0) + { + FModel* animation = Models[animationid]; + const TArray* animationData = animation->AttachAnimationData(); + + if(is_decoupled) + { + if(decoupled_main_frame != -1) + { + boneData = animation->CalculateBones(decoupled_main_frame, decoupled_next_frame, inter, decoupled_main_prev_frame, inter_main, decoupled_next_prev_frame, inter_next, animationData, actor->boneComponentData, i); + } + } + else + { + boneData = animation->CalculateBones(modelframe, modelframenext, nextFrame ? inter : -1.f, 0, -1.f, 0, -1.f, animationData, actor->boneComponentData, i); + } + boneStartingPosition = renderer->SetupFrame(animation, 0, 0, 0, boneData, -1); + evaluatedSingle = true; + } + else + { + if(is_decoupled) + { + if(decoupled_main_frame != -1) + { + boneData = mdl->CalculateBones(decoupled_main_frame, decoupled_next_frame, inter, decoupled_main_prev_frame, inter_main, decoupled_next_prev_frame, inter_next, nullptr, actor->boneComponentData, i); + } + } + else + { + boneData = mdl->CalculateBones(modelframe, modelframenext, nextFrame ? inter : -1.f, 0, -1.f, 0, -1.f, nullptr, actor->boneComponentData, i); + } + boneStartingPosition = renderer->SetupFrame(mdl, 0, 0, 0, boneData, -1); + evaluatedSingle = true; + } + } + + mdl->RenderFrame(renderer, tex, modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : -1.f, translation, ssidp, boneData, boneStartingPosition); + } + } +} + + +static TArray SpriteModelHash; +//TArray StateModelFrames; + +//=========================================================================== +// +// InitModels +// +//=========================================================================== + +void ParseModelDefLump(int Lump); + +void InitModels() +{ + Models.DeleteAndClear(); + SpriteModelFrames.Clear(); + SpriteModelHash.Clear(); + + // First, create models for each voxel + for (unsigned i = 0; i < Voxels.Size(); i++) + { + FVoxelModel *md = new FVoxelModel(Voxels[i], false); + Voxels[i]->VoxelIndex = Models.Push(md); + } + // now create GL model frames for the voxeldefs + for (unsigned i = 0; i < VoxelDefs.Size(); i++) + { + FVoxelModel *md = (FVoxelModel*)Models[VoxelDefs[i]->Voxel->VoxelIndex]; + FSpriteModelFrame smf; + memset(&smf, 0, sizeof(smf)); + smf.isVoxel = true; + smf.modelsAmount = 1; + smf.modelframes.Alloc(1); + smf.modelframes[0] = -1; + smf.modelIDs.Alloc(1); + smf.modelIDs[0] = VoxelDefs[i]->Voxel->VoxelIndex; + smf.skinIDs.Alloc(1); + smf.skinIDs[0] = md->GetPaletteTexture(); + smf.animationIDs.Alloc(1); + smf.animationIDs[0] = -1; + smf.xscale = smf.yscale = smf.zscale = VoxelDefs[i]->Scale; + smf.angleoffset = VoxelDefs[i]->AngleOffset.Degrees(); + smf.xoffset = VoxelDefs[i]->xoffset; + smf.yoffset = VoxelDefs[i]->yoffset; + smf.zoffset = VoxelDefs[i]->zoffset; + // this helps catching uninitialized data. + assert(VoxelDefs[i]->PitchFromMomentum == true || VoxelDefs[i]->PitchFromMomentum == false); + if (VoxelDefs[i]->PitchFromMomentum) smf.flags |= MDL_PITCHFROMMOMENTUM; + if (VoxelDefs[i]->UseActorPitch) smf.flags |= MDL_USEACTORPITCH; + if (VoxelDefs[i]->UseActorRoll) smf.flags |= MDL_USEACTORROLL; + if (VoxelDefs[i]->PlacedSpin != 0) + { + smf.yrotate = 1.f; + smf.rotationSpeed = VoxelDefs[i]->PlacedSpin / 55.55f; + smf.flags |= MDL_ROTATING; + } + VoxelDefs[i]->VoxeldefIndex = SpriteModelFrames.Push(smf); + if (VoxelDefs[i]->PlacedSpin != VoxelDefs[i]->DroppedSpin) + { + if (VoxelDefs[i]->DroppedSpin != 0) + { + smf.yrotate = 1.f; + smf.rotationSpeed = VoxelDefs[i]->DroppedSpin / 55.55f; + smf.flags |= MDL_ROTATING; + } + else + { + smf.yrotate = 0; + smf.rotationSpeed = 0; + smf.flags &= ~MDL_ROTATING; + } + SpriteModelFrames.Push(smf); + } + } + + int Lump; + int lastLump = 0; + while ((Lump = fileSystem.FindLump("MODELDEF", &lastLump)) != -1) + { + ParseModelDefLump(Lump); + } + + // create a hash table for quick access + SpriteModelHash.Resize(SpriteModelFrames.Size ()); + memset(SpriteModelHash.Data(), 0xff, SpriteModelFrames.Size () * sizeof(int)); + + for (unsigned int i = 0; i < SpriteModelFrames.Size (); i++) + { + int j = ModelFrameHash(&SpriteModelFrames[i]) % SpriteModelFrames.Size (); + + SpriteModelFrames[i].hashnext = SpriteModelHash[j]; + SpriteModelHash[j]=i; + } +} + +void ParseModelDefLump(int Lump) +{ + FScanner sc(Lump); + while (sc.GetString()) + { + if (sc.Compare("model")) + { + int index, surface; + FString path = ""; + sc.MustGetString(); + + FSpriteModelFrame smf; + memset(&smf, 0, sizeof(smf)); + smf.xscale=smf.yscale=smf.zscale=1.f; + + auto type = PClass::FindClass(sc.String); + if (!type || type->Defaults == nullptr) + { + sc.ScriptError("MODELDEF: Unknown actor type '%s'\n", sc.String); + } + smf.type = type; + FScanner::SavedPos scPos = sc.SavePos(); + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("model")) + { + sc.MustGetNumber(); + index = sc.Number; + if (index < 0) + { + sc.ScriptError("Model index must be 0 or greater in %s", type->TypeName.GetChars()); + } + smf.modelsAmount = index + 1; + } + } + //Make sure modelsAmount is at least equal to MIN_MODELS(4) to ensure compatibility with old mods + if (smf.modelsAmount < MIN_MODELS) + { + smf.modelsAmount = MIN_MODELS; + } + + const auto initArray = [](auto& array, const unsigned count, const auto value) + { + array.Alloc(count); + std::fill(array.begin(), array.end(), value); + }; + + initArray(smf.modelIDs, smf.modelsAmount, -1); + initArray(smf.skinIDs, smf.modelsAmount, FNullTextureID()); + initArray(smf.surfaceskinIDs, smf.modelsAmount * MD3_MAX_SURFACES, FNullTextureID()); + initArray(smf.animationIDs, smf.modelsAmount, -1); + initArray(smf.modelframes, smf.modelsAmount, 0); + + sc.RestorePos(scPos); + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("path")) + { + sc.MustGetString(); + FixPathSeperator(sc.String); + path = sc.String; + if (path[(int)path.Len()-1]!='/') path+='/'; + } + else if (sc.Compare("model")) + { + sc.MustGetNumber(); + index = sc.Number; + if (index < 0) + { + sc.ScriptError("Model index must be 0 or greater in %s", type->TypeName.GetChars()); + } + else if (index >= smf.modelsAmount) + { + sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); + } + sc.MustGetString(); + FixPathSeperator(sc.String); + smf.modelIDs[index] = FindModel(path.GetChars(), sc.String); + if (smf.modelIDs[index] == -1) + { + Printf("%s: model not found in %s\n", sc.String, path.GetChars()); + } + } + else if (sc.Compare("animation")) + { + sc.MustGetNumber(); + index = sc.Number; + if (index < 0) + { + sc.ScriptError("Animation index must be 0 or greater in %s", type->TypeName.GetChars()); + } + else if (index >= smf.modelsAmount) + { + sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); + } + sc.MustGetString(); + FixPathSeperator(sc.String); + smf.animationIDs[index] = FindModel(path.GetChars(), sc.String); + if (smf.animationIDs[index] == -1) + { + Printf("%s: animation model not found in %s\n", sc.String, path.GetChars()); + } + } + else if (sc.Compare("scale")) + { + sc.MustGetFloat(); + smf.xscale = sc.Float; + sc.MustGetFloat(); + smf.yscale = sc.Float; + sc.MustGetFloat(); + smf.zscale = sc.Float; + } + // [BB] Added zoffset reading. + // Now it must be considered deprecated. + else if (sc.Compare("zoffset")) + { + sc.MustGetFloat(); + smf.zoffset=sc.Float; + } + // Offset reading. + else if (sc.Compare("offset")) + { + sc.MustGetFloat(); + smf.xoffset = sc.Float; + sc.MustGetFloat(); + smf.yoffset = sc.Float; + sc.MustGetFloat(); + smf.zoffset = sc.Float; + } + // angleoffset, pitchoffset and rolloffset reading. + else if (sc.Compare("angleoffset")) + { + sc.MustGetFloat(); + smf.angleoffset = sc.Float; + } + else if (sc.Compare("pitchoffset")) + { + sc.MustGetFloat(); + smf.pitchoffset = sc.Float; + } + else if (sc.Compare("rolloffset")) + { + sc.MustGetFloat(); + smf.rolloffset = sc.Float; + } + // [BB] Added model flags reading. + else if (sc.Compare("ignoretranslation")) + { + smf.flags |= MDL_IGNORETRANSLATION; + } + else if (sc.Compare("pitchfrommomentum")) + { + smf.flags |= MDL_PITCHFROMMOMENTUM; + } + else if (sc.Compare("inheritactorpitch")) + { + smf.flags |= MDL_USEACTORPITCH | MDL_BADROTATION; + } + else if (sc.Compare("inheritactorroll")) + { + smf.flags |= MDL_USEACTORROLL; + } + else if (sc.Compare("useactorpitch")) + { + smf.flags |= MDL_USEACTORPITCH; + } + else if (sc.Compare("useactorroll")) + { + smf.flags |= MDL_USEACTORROLL; + } + else if (sc.Compare("noperpixellighting")) + { + smf.flags |= MDL_NOPERPIXELLIGHTING; + } + else if (sc.Compare("scaleweaponfov")) + { + smf.flags |= MDL_SCALEWEAPONFOV; + } + else if (sc.Compare("modelsareattachments")) + { + smf.flags |= MDL_MODELSAREATTACHMENTS; + } + else if (sc.Compare("rotating")) + { + smf.flags |= MDL_ROTATING; + smf.xrotate = 0.; + smf.yrotate = 1.; + smf.zrotate = 0.; + smf.rotationCenterX = 0.; + smf.rotationCenterY = 0.; + smf.rotationCenterZ = 0.; + smf.rotationSpeed = 1.; + } + else if (sc.Compare("rotation-speed")) + { + sc.MustGetFloat(); + smf.rotationSpeed = sc.Float; + } + else if (sc.Compare("rotation-vector")) + { + sc.MustGetFloat(); + smf.xrotate = sc.Float; + sc.MustGetFloat(); + smf.yrotate = sc.Float; + sc.MustGetFloat(); + smf.zrotate = sc.Float; + } + else if (sc.Compare("rotation-center")) + { + sc.MustGetFloat(); + smf.rotationCenterX = sc.Float; + sc.MustGetFloat(); + smf.rotationCenterY = sc.Float; + sc.MustGetFloat(); + smf.rotationCenterZ = sc.Float; + } + else if (sc.Compare("interpolatedoubledframes")) + { + smf.flags |= MDL_INTERPOLATEDOUBLEDFRAMES; + } + else if (sc.Compare("nointerpolation")) + { + smf.flags |= MDL_NOINTERPOLATION; + } + else if (sc.Compare("skin")) + { + sc.MustGetNumber(); + index=sc.Number; + if (index<0 || index>= smf.modelsAmount) + { + sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); + } + sc.MustGetString(); + FixPathSeperator(sc.String); + if (sc.Compare("")) + { + smf.skinIDs[index]=FNullTextureID(); + } + else + { + smf.skinIDs[index] = LoadSkin(path.GetChars(), sc.String); + if (!smf.skinIDs[index].isValid()) + { + Printf("Skin '%s' not found in '%s'\n", + sc.String, type->TypeName.GetChars()); + } + } + } + else if (sc.Compare("surfaceskin")) + { + sc.MustGetNumber(); + index = sc.Number; + sc.MustGetNumber(); + surface = sc.Number; + + if (index<0 || index >= smf.modelsAmount) + { + sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); + } + + if (surface<0 || surface >= MD3_MAX_SURFACES) + { + sc.ScriptError("Invalid MD3 Surface %d in %s", MD3_MAX_SURFACES, type->TypeName.GetChars()); + } + + sc.MustGetString(); + FixPathSeperator(sc.String); + int ssIndex = surface + index * MD3_MAX_SURFACES; + if (sc.Compare("")) + { + smf.surfaceskinIDs[ssIndex] = FNullTextureID(); + } + else + { + smf.surfaceskinIDs[ssIndex] = LoadSkin(path.GetChars(), sc.String); + if (!smf.surfaceskinIDs[ssIndex].isValid()) + { + Printf("Surface Skin '%s' not found in '%s'\n", + sc.String, type->TypeName.GetChars()); + } + } + } + else if (sc.Compare("baseframe")) + { + FSpriteModelFrame *smfp = &BaseSpriteModelFrames.Insert(type, smf); + for(int modelID : smf.modelIDs) + { + if(modelID >= 0) + Models[modelID]->baseFrame = smfp; + } + GetDefaultByType(type)->hasmodel = true; + } + else if (sc.Compare("frameindex") || sc.Compare("frame")) + { + bool isframe=!!sc.Compare("frame"); + + sc.MustGetString(); + smf.sprite = -1; + for (int i = 0; i < (int)sprites.Size (); ++i) + { + if (strnicmp (sprites[i].name, sc.String, 4) == 0) + { + if (sprites[i].numframes==0) + { + //sc.ScriptError("Sprite %s has no frames", sc.String); + } + smf.sprite = i; + break; + } + } + if (smf.sprite==-1) + { + sc.ScriptError("Unknown sprite %s in model definition for %s", sc.String, type->TypeName.GetChars()); + } + + sc.MustGetString(); + FString framechars = sc.String; + + sc.MustGetNumber(); + index=sc.Number; + if (index<0 || index>= smf.modelsAmount) + { + sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); + } + if (isframe) + { + sc.MustGetString(); + if (smf.modelIDs[index] != -1) + { + FModel *model = Models[smf.modelIDs[index]]; + if (smf.animationIDs[index] != -1) + { + model = Models[smf.animationIDs[index]]; + } + smf.modelframes[index] = model->FindFrame(sc.String); + if (smf.modelframes[index]==-1) sc.ScriptError("Unknown frame '%s' in %s", sc.String, type->TypeName.GetChars()); + } + else smf.modelframes[index] = -1; + } + else + { + sc.MustGetNumber(); + smf.modelframes[index] = sc.Number; + } + + for(int i=0; framechars[i]>0; i++) + { + char map[29]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int c = toupper(framechars[i])-'A'; + + if (c<0 || c>=29) + { + sc.ScriptError("Invalid frame character %c found", c+'A'); + } + if (map[c]) continue; + smf.frame=c; + SpriteModelFrames.Push(smf); + GetDefaultByType(type)->hasmodel = true; + map[c]=1; + } + } + else if (sc.Compare("dontcullbackfaces")) + { + smf.flags |= MDL_DONTCULLBACKFACES; + } + else if (sc.Compare("userotationcenter")) + { + smf.flags |= MDL_USEROTATIONCENTER; + smf.rotationCenterX = 0.; + smf.rotationCenterY = 0.; + smf.rotationCenterZ = 0.; + } + else if (sc.Compare("correctpixelstretch")) + { + smf.flags |= MDL_CORRECTPIXELSTRETCH; + } + else if (sc.Compare("forcecullbackfaces")) + { + smf.flags |= MDL_FORCECULLBACKFACES; + } + else + { + sc.ScriptMessage("Unrecognized string \"%s\"", sc.String); + } + } + } + else if (sc.Compare("#include")) + { + sc.MustGetString(); + // This is not using sc.Open because it can print a more useful error message when done here + int includelump = fileSystem.CheckNumForFullName(sc.String, true); + if (includelump == -1) + { + if (strcmp(sc.String, "sentinel.modl") != 0) // Gene Tech mod has a broken #include statement + sc.ScriptError("Lump '%s' not found", sc.String); + } + else + { + ParseModelDefLump(includelump); + } + } + } +} + +//=========================================================================== +// +// FindModelFrame +// +//=========================================================================== + +FSpriteModelFrame * FindModelFrameRaw(const PClass * ti, int sprite, int frame, bool dropped) +{ + auto def = GetDefaultByType(ti); + if (def->hasmodel) + { + if(def->flags9 & MF9_DECOUPLEDANIMATIONS) + { + FSpriteModelFrame * smf = BaseSpriteModelFrames.CheckKey((void*)ti); + if(smf) return smf; + } + else + { + FSpriteModelFrame smf; + + memset(&smf, 0, sizeof(smf)); + smf.type=ti; + smf.sprite=sprite; + smf.frame=frame; + + int hash = SpriteModelHash[ModelFrameHash(&smf) % SpriteModelFrames.Size()]; + + while (hash>=0) + { + FSpriteModelFrame * smff = &SpriteModelFrames[hash]; + if (smff->type==ti && smff->sprite==sprite && smff->frame==frame) return smff; + hash=smff->hashnext; + } + } + } + + // Check for voxel replacements + if (r_drawvoxels) + { + spritedef_t *sprdef = &sprites[sprite]; + if (frame < sprdef->numframes) + { + spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + frame]; + if (sprframe->Voxel != nullptr) + { + int index = sprframe->Voxel->VoxeldefIndex; + if (dropped && sprframe->Voxel->DroppedSpin !=sprframe->Voxel->PlacedSpin) index++; + return &SpriteModelFrames[index]; + } + } + } + return nullptr; +} + +FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, bool dropped) +{ + if(!thing) return nullptr; + + if(thing->flags9 & MF9_DECOUPLEDANIMATIONS) + { + return BaseSpriteModelFrames.CheckKey((thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass()); + } + else + { + return FindModelFrameRaw((thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass(), sprite, frame, dropped); + } +} + +//=========================================================================== +// +// IsHUDModelForPlayerAvailable +// +//=========================================================================== + +bool IsHUDModelForPlayerAvailable (player_t * player) +{ + if (player == nullptr || player->psprites == nullptr) + return false; + + // [MK] check that at least one psprite uses models + for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) + { + if ( FindModelFrame(psp->Caller, psp->GetSprite(), psp->GetFrame(), false) != nullptr ) return true; + } + return false; +} + + +unsigned int FSpriteModelFrame::getFlags(class DActorModelData * defs) const +{ + return (defs && defs->flags & MODELDATA_OVERRIDE_FLAGS)? (flags | defs->overrideFlagsSet) & ~(defs->overrideFlagsClear) : flags; +} \ No newline at end of file diff --git a/src/r_data/models.h b/src/r_data/models.h new file mode 100644 index 00000000000..4a7154446be --- /dev/null +++ b/src/r_data/models.h @@ -0,0 +1,119 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2005-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#ifndef __GL_MODELS_H_ +#define __GL_MODELS_H_ + +#include "tarray.h" +#include "matrix.h" +#include "m_bbox.h" +#include "r_defs.h" +#include "g_levellocals.h" +#include "voxels.h" +#include "i_modelvertexbuffer.h" +#include "model.h" + +class FModelRenderer; + +struct FSpriteModelFrame; +class IModelVertexBuffer; +struct FLevelLocals; + +// +// [BB] Model rendering flags. +// +enum +{ + // [BB] Color translations for the model skin are ignored. This is + // useful if the skin texture is not using the game palette. + MDL_IGNORETRANSLATION = 1<<0, + MDL_PITCHFROMMOMENTUM = 1<<1, + MDL_ROTATING = 1<<2, + MDL_INTERPOLATEDOUBLEDFRAMES = 1<<3, + MDL_NOINTERPOLATION = 1<<4, + MDL_USEACTORPITCH = 1<<5, + MDL_USEACTORROLL = 1<<6, + MDL_BADROTATION = 1<<7, + MDL_DONTCULLBACKFACES = 1<<8, + MDL_USEROTATIONCENTER = 1<<9, + MDL_NOPERPIXELLIGHTING = 1<<10, // forces a model to not use per-pixel lighting. useful for voxel-converted-to-model objects. + MDL_SCALEWEAPONFOV = 1<<11, // scale weapon view model with higher user FOVs + MDL_MODELSAREATTACHMENTS = 1<<12, // any model index after 0 is treated as an attachment, and therefore will use the bone results of index 0 + MDL_CORRECTPIXELSTRETCH = 1<<13, // ensure model does not distort with pixel stretch when pitch/roll is applied + MDL_FORCECULLBACKFACES = 1<<14, +}; + +FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, bool dropped); +FSpriteModelFrame * FindModelFrameRaw(const PClass * ti, int sprite, int frame, bool dropped); +bool IsHUDModelForPlayerAvailable(player_t * player); + +// Check if circle potentially intersects with node AABB +inline bool CheckBBoxCircle(float *bbox, float x, float y, float radiusSquared) +{ + float centerX = (bbox[BOXRIGHT] + bbox[BOXLEFT]) * 0.5f; + float centerY = (bbox[BOXBOTTOM] + bbox[BOXTOP]) * 0.5f; + float extentX = (bbox[BOXRIGHT] - bbox[BOXLEFT]) * 0.5f; + float extentY = (bbox[BOXBOTTOM] - bbox[BOXTOP]) * 0.5f; + float aabbRadiusSquared = extentX * extentX + extentY * extentY; + x -= centerX; + y -= centerY; + float dist = x * x + y * y; + return dist <= radiusSquared + aabbRadiusSquared; +} + +// Helper function for BSPWalkCircle +template +void BSPNodeWalkCircle(void *node, float x, float y, float radiusSquared, const Callback &callback) +{ + while (!((size_t)node & 1)) + { + node_t *bsp = (node_t *)node; + + if (CheckBBoxCircle(bsp->bbox[0], x, y, radiusSquared)) + BSPNodeWalkCircle(bsp->children[0], x, y, radiusSquared, callback); + + if (!CheckBBoxCircle(bsp->bbox[1], x, y, radiusSquared)) + return; + + node = bsp->children[1]; + } + + subsector_t *sub = (subsector_t *)((uint8_t *)node - 1); + callback(sub); +} + +// Search BSP for subsectors within the given radius and call callback(subsector) for each found +template +void BSPWalkCircle(FLevelLocals *Level, float x, float y, float radiusSquared, const Callback &callback) +{ + if (Level->nodes.Size() == 0) + callback(&Level->subsectors[0]); + else + BSPNodeWalkCircle(Level->HeadNode(), x, y, radiusSquared, callback); +} + +void RenderModel(FModelRenderer* renderer, float x, float y, float z, FSpriteModelFrame* smf, AActor* actor, double ticFrac); +void RenderHUDModel(FModelRenderer* renderer, DPSprite* psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf); + +EXTERN_CVAR(Float, cl_scaleweaponfov) + +#endif diff --git a/src/r_data/models/models.cpp b/src/r_data/models/models.cpp deleted file mode 100644 index 51ff94b74a3..00000000000 --- a/src/r_data/models/models.cpp +++ /dev/null @@ -1,931 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_models.cpp -** -** General model handling code -** -**/ - -#include "w_wad.h" -#include "cmdlib.h" -#include "sc_man.h" -#include "m_crc32.h" -#include "c_console.h" -#include "g_game.h" -#include "doomstat.h" -#include "g_level.h" -#include "r_state.h" -#include "d_player.h" -#include "g_levellocals.h" -#include "r_utility.h" -#include "r_data/models/models.h" -#include "r_data/models/models_ue1.h" -#include "r_data/models/models_obj.h" -#include "i_time.h" - -#ifdef _MSC_VER -#pragma warning(disable:4244) // warning C4244: conversion from 'double' to 'float', possible loss of data -#endif - -CVAR(Bool, gl_interpolate_model_frames, true, CVAR_ARCHIVE) -EXTERN_CVAR (Bool, r_drawvoxels) - -extern TDeletingArray Voxels; -extern TDeletingArray VoxelDefs; - -TDeletingArray Models; - -void FModelRenderer::RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, double ticFrac) -{ - // Setup transformation. - - int translation = 0; - if (!(smf->flags & MDL_IGNORETRANSLATION)) - translation = actor->Translation; - - // y scale for a sprite means height, i.e. z in the world! - float scaleFactorX = actor->Scale.X * smf->xscale; - float scaleFactorY = actor->Scale.X * smf->yscale; - float scaleFactorZ = actor->Scale.Y * smf->zscale; - float pitch = 0; - float roll = 0; - double rotateOffset = 0; - DRotator angles; - if (actor->renderflags & RF_INTERPOLATEANGLES) // [Nash] use interpolated angles - angles = actor->InterpolatedAngles(ticFrac); - else - angles = actor->Angles; - float angle = angles.Yaw.Degrees; - - // [BB] Workaround for the missing pitch information. - if ((smf->flags & MDL_PITCHFROMMOMENTUM)) - { - const double x = actor->Vel.X; - const double y = actor->Vel.Y; - const double z = actor->Vel.Z; - - if (actor->Vel.LengthSquared() > EQUAL_EPSILON) - { - // [BB] Calculate the pitch using spherical coordinates. - if (z || x || y) pitch = float(atan(z / sqrt(x*x + y*y)) / M_PI * 180); - - // Correcting pitch if model is moving backwards - if (fabs(x) > EQUAL_EPSILON || fabs(y) > EQUAL_EPSILON) - { - if ((x * cos(angle * M_PI / 180) + y * sin(angle * M_PI / 180)) / sqrt(x * x + y * y) < 0) pitch *= -1; - } - else pitch = fabs(pitch); - } - } - - if (smf->flags & MDL_ROTATING) - { - if (smf->rotationSpeed > 0.0000000001 || smf->rotationSpeed < -0.0000000001) - { - double turns = (I_GetTime() + I_GetTimeFrac()) / (200.0 / smf->rotationSpeed); - turns -= floor(turns); - rotateOffset = turns * 360.0; - } - else - { - rotateOffset = 0.0; - } - } - - // Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing. - // If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the velocity vector pitch. - if (smf->flags & MDL_USEACTORPITCH) - { - double d = angles.Pitch.Degrees; - if (smf->flags & MDL_BADROTATION) pitch += d; - else pitch -= d; - } - if (smf->flags & MDL_USEACTORROLL) roll += angles.Roll.Degrees; - - VSMatrix objectToWorldMatrix; - objectToWorldMatrix.loadIdentity(); - - // Model space => World space - objectToWorldMatrix.translate(x, z, y); - - // [Nash] take SpriteRotation into account - angle += actor->SpriteRotation.Degrees; - - // Applying model transformations: - // 1) Applying actor angle, pitch and roll to the model - if (smf->flags & MDL_USEROTATIONCENTER) - { - objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterZ, smf->rotationCenterY); - } - objectToWorldMatrix.rotate(-angle, 0, 1, 0); - objectToWorldMatrix.rotate(pitch, 0, 0, 1); - objectToWorldMatrix.rotate(-roll, 1, 0, 0); - if (smf->flags & MDL_USEROTATIONCENTER) - { - objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterZ, -smf->rotationCenterY); - } - - // 2) Applying Doomsday like rotation of the weapon pickup models - // The rotation angle is based on the elapsed time. - - if (smf->flags & MDL_ROTATING) - { - objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ); - objectToWorldMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate); - objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ); - } - - // 3) Scaling model. - objectToWorldMatrix.scale(scaleFactorX, scaleFactorZ, scaleFactorY); - - // 4) Aplying model offsets (model offsets do not depend on model scalings). - objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale); - - // 5) Applying model rotations. - objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0); - objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1); - objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0); - - // consider the pixel stretching. For non-voxels this must be factored out here - float stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level) : 1.f) / actor->Level->info->pixelstretch; - objectToWorldMatrix.scale(1, stretch, 1); - - float orientation = scaleFactorX * scaleFactorY * scaleFactorZ; - - BeginDrawModel(actor, smf, objectToWorldMatrix, orientation < 0); - RenderFrameModels(actor->Level, smf, actor->state, actor->tics, actor->GetClass(), translation); - EndDrawModel(actor, smf); -} - -void FModelRenderer::RenderHUDModel(DPSprite *psp, float ofsX, float ofsY) -{ - AActor * playermo = players[consoleplayer].camera; - FSpriteModelFrame *smf = FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetSprite(), psp->GetFrame(), false); - - // [BB] No model found for this sprite, so we can't render anything. - if (smf == nullptr) - return; - - // The model position and orientation has to be drawn independently from the position of the player, - // but we need to position it correctly in the world for light to work properly. - VSMatrix objectToWorldMatrix = GetViewToWorldMatrix(); - - // Scaling model (y scale for a sprite means height, i.e. z in the world!). - objectToWorldMatrix.scale(smf->xscale, smf->zscale, smf->yscale); - - // Aplying model offsets (model offsets do not depend on model scalings). - objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale); - - // [BB] Weapon bob, very similar to the normal Doom weapon bob. - objectToWorldMatrix.rotate(ofsX / 4, 0, 1, 0); - objectToWorldMatrix.rotate((ofsY - WEAPONTOP) / -4., 1, 0, 0); - - // [BB] For some reason the jDoom models need to be rotated. - objectToWorldMatrix.rotate(90.f, 0, 1, 0); - - // Applying angleoffset, pitchoffset, rolloffset. - objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0); - objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1); - objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0); - - float orientation = smf->xscale * smf->yscale * smf->zscale; - - BeginDrawHUDModel(playermo, objectToWorldMatrix, orientation < 0); - RenderFrameModels(playermo->Level, smf, psp->GetState(), psp->GetTics(), playermo->player->ReadyWeapon->GetClass(), psp->Flags & PSPF_PLAYERTRANSLATED ? psp->Owner->mo->Translation : 0); - EndDrawHUDModel(playermo); -} - -void FModelRenderer::RenderFrameModels(FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, const PClass *ti, int translation) -{ - // [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation - // and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame. - FSpriteModelFrame * smfNext = nullptr; - double inter = 0.; - if (gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION)) - { - FState *nextState = curState->GetNextState(); - if (curState != nextState && nextState) - { - // [BB] To interpolate at more than 35 fps we take tic fractions into account. - float ticFraction = 0.; - // [BB] In case the tic counter is frozen we have to leave ticFraction at zero. - if (ConsoleState == c_up && menuactive != MENU_On && !Level->isFrozen()) - { - ticFraction = I_GetTimeFrac(); - } - inter = static_cast(curState->Tics - curTics + ticFraction) / static_cast(curState->Tics); - - // [BB] For some actors (e.g. ZPoisonShroom) spr->actor->tics can be bigger than curState->Tics. - // In this case inter is negative and we need to set it to zero. - if (curState->Tics < curTics) - inter = 0.; - else - { - // [BB] Workaround for actors that use the same frame twice in a row. - // Most of the standard Doom monsters do this in their see state. - if ((smf->flags & MDL_INTERPOLATEDOUBLEDFRAMES)) - { - const FState *prevState = curState - 1; - if ((curState->sprite == prevState->sprite) && (curState->Frame == prevState->Frame)) - { - inter /= 2.; - inter += 0.5; - } - if (nextState && ((curState->sprite == nextState->sprite) && (curState->Frame == nextState->Frame))) - { - inter /= 2.; - nextState = nextState->GetNextState(); - } - } - if (nextState && inter != 0.0) - smfNext = FindModelFrame(ti, nextState->sprite, nextState->Frame, false); - } - } - } - - for (int i = 0; imodelIDs[i] != -1) - { - FModel * mdl = Models[smf->modelIDs[i]]; - FTexture *tex = smf->skinIDs[i].isValid() ? TexMan.GetTexture(smf->skinIDs[i], true) : nullptr; - mdl->BuildVertexBuffer(this); - - mdl->PushSpriteMDLFrame(smf, i); - - if (smfNext && smf->modelframes[i] != smfNext->modelframes[i]) - mdl->RenderFrame(this, tex, smf->modelframes[i], smfNext->modelframes[i], inter, translation); - else - mdl->RenderFrame(this, tex, smf->modelframes[i], smf->modelframes[i], 0.f, translation); - } - } -} - -///////////////////////////////////////////////////////////////////////////// - -void FlushModels() -{ - for (int i = Models.Size() - 1; i >= 0; i--) - { - Models[i]->DestroyVertexBuffer(); - } -} - -///////////////////////////////////////////////////////////////////////////// - -FModel::FModel() -{ - for (int i = 0; i < NumModelRendererTypes; i++) - mVBuf[i] = nullptr; -} - -FModel::~FModel() -{ - DestroyVertexBuffer(); -} - -void FModel::DestroyVertexBuffer() -{ - for (int i = 0; i < NumModelRendererTypes; i++) - { - delete mVBuf[i]; - mVBuf[i] = nullptr; - } -} - -static TArray SpriteModelFrames; -static TArray SpriteModelHash; -//TArray StateModelFrames; - -//=========================================================================== -// -// FindGFXFile -// -//=========================================================================== - -static int FindGFXFile(FString & fn) -{ - int lump = Wads.CheckNumForFullName(fn); // if we find something that matches the name plus the extension, return it and do not enter the substitution logic below. - if (lump != -1) return lump; - - int best = -1; - int dot = fn.LastIndexOf('.'); - int slash = fn.LastIndexOf('/'); - if (dot > slash) fn.Truncate(dot); - - static const char * extensions[] = { ".png", ".jpg", ".tga", ".pcx", nullptr }; - - for (const char ** extp=extensions; *extp; extp++) - { - int lump = Wads.CheckNumForFullName(fn + *extp); - if (lump >= best) best = lump; - } - return best; -} - - -//=========================================================================== -// -// LoadSkin -// -//=========================================================================== - -FTextureID LoadSkin(const char * path, const char * fn) -{ - FString buffer; - - buffer.Format("%s%s", path, fn); - - int texlump = FindGFXFile(buffer); - const char * const texname = texlump < 0 ? fn : Wads.GetLumpFullName(texlump); - return TexMan.CheckForTexture(texname, ETextureType::Any, FTextureManager::TEXMAN_TryAny); -} - -//=========================================================================== -// -// ModelFrameHash -// -//=========================================================================== - -static int ModelFrameHash(FSpriteModelFrame * smf) -{ - const uint32_t *table = GetCRCTable (); - uint32_t hash = 0xffffffff; - - const char * s = (const char *)(&smf->type); // this uses type, sprite and frame for hashing - const char * se= (const char *)(&smf->hashnext); - - for (; smFileName.CompareNoCase(fullname)) return i; - } - - int len = Wads.LumpLength(lump); - FMemLump lumpd = Wads.ReadLump(lump); - char * buffer = (char*)lumpd.GetMem(); - - if ( (size_t)fullname.LastIndexOf("_d.3d") == fullname.Len()-5 ) - { - FString anivfile = fullname.GetChars(); - anivfile.Substitute("_d.3d","_a.3d"); - if ( Wads.CheckNumForFullName(anivfile) > 0 ) - { - model = new FUE1Model; - } - } - else if ( (size_t)fullname.LastIndexOf("_a.3d") == fullname.Len()-5 ) - { - FString datafile = fullname.GetChars(); - datafile.Substitute("_a.3d","_d.3d"); - if ( Wads.CheckNumForFullName(datafile) > 0 ) - { - model = new FUE1Model; - } - } - else if ( (size_t)fullname.LastIndexOf(".obj") == fullname.Len() - 4 ) - { - model = new FOBJModel; - } - else if (!memcmp(buffer, "DMDM", 4)) - { - model = new FDMDModel; - } - else if (!memcmp(buffer, "IDP2", 4)) - { - model = new FMD2Model; - } - else if (!memcmp(buffer, "IDP3", 4)) - { - model = new FMD3Model; - } - - if (model != nullptr) - { - if (!model->Load(path, lump, buffer, len)) - { - delete model; - return -1; - } - } - else - { - // try loading as a voxel - FVoxel *voxel = R_LoadKVX(lump); - if (voxel != nullptr) - { - model = new FVoxelModel(voxel, true); - } - else - { - Printf("LoadModel: Unknown model format in '%s'\n", fullname.GetChars()); - return -1; - } - } - // The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized - model->mFileName = fullname; - return Models.Push(model); -} - -//=========================================================================== -// -// InitModels -// -//=========================================================================== - -static void ParseModelDefLump(int Lump); - -void InitModels() -{ - Models.DeleteAndClear(); - SpriteModelFrames.Clear(); - SpriteModelHash.Clear(); - - // First, create models for each voxel - for (unsigned i = 0; i < Voxels.Size(); i++) - { - FVoxelModel *md = new FVoxelModel(Voxels[i], false); - Voxels[i]->VoxelIndex = Models.Push(md); - } - // now create GL model frames for the voxeldefs - for (unsigned i = 0; i < VoxelDefs.Size(); i++) - { - FVoxelModel *md = (FVoxelModel*)Models[VoxelDefs[i]->Voxel->VoxelIndex]; - FSpriteModelFrame smf; - memset(&smf, 0, sizeof(smf)); - smf.isVoxel = true; - smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1; - smf.modelIDs[0] = VoxelDefs[i]->Voxel->VoxelIndex; - smf.skinIDs[0] = md->GetPaletteTexture(); - smf.xscale = smf.yscale = smf.zscale = VoxelDefs[i]->Scale; - smf.angleoffset = VoxelDefs[i]->AngleOffset.Degrees; - if (VoxelDefs[i]->PlacedSpin != 0) - { - smf.yrotate = 1.f; - smf.rotationSpeed = VoxelDefs[i]->PlacedSpin / 55.55f; - smf.flags |= MDL_ROTATING; - } - VoxelDefs[i]->VoxeldefIndex = SpriteModelFrames.Push(smf); - if (VoxelDefs[i]->PlacedSpin != VoxelDefs[i]->DroppedSpin) - { - if (VoxelDefs[i]->DroppedSpin != 0) - { - smf.yrotate = 1.f; - smf.rotationSpeed = VoxelDefs[i]->DroppedSpin / 55.55f; - smf.flags |= MDL_ROTATING; - } - else - { - smf.yrotate = 0; - smf.rotationSpeed = 0; - smf.flags &= ~MDL_ROTATING; - } - SpriteModelFrames.Push(smf); - } - } - - int Lump; - int lastLump = 0; - while ((Lump = Wads.FindLump("MODELDEF", &lastLump)) != -1) - { - ParseModelDefLump(Lump); - } - - // create a hash table for quick access - SpriteModelHash.Resize(SpriteModelFrames.Size ()); - memset(SpriteModelHash.Data(), 0xff, SpriteModelFrames.Size () * sizeof(int)); - - for (unsigned int i = 0; i < SpriteModelFrames.Size (); i++) - { - int j = ModelFrameHash(&SpriteModelFrames[i]) % SpriteModelFrames.Size (); - - SpriteModelFrames[i].hashnext = SpriteModelHash[j]; - SpriteModelHash[j]=i; - } -} - -static void ParseModelDefLump(int Lump) -{ - FScanner sc(Lump); - while (sc.GetString()) - { - if (sc.Compare("model")) - { - int index, surface; - FString path = ""; - sc.MustGetString(); - - FSpriteModelFrame smf; - memset(&smf, 0, sizeof(smf)); - smf.modelIDs[0] = smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1; - smf.xscale=smf.yscale=smf.zscale=1.f; - - smf.type = PClass::FindClass(sc.String); - if (!smf.type || smf.type->Defaults == nullptr) - { - sc.ScriptError("MODELDEF: Unknown actor type '%s'\n", sc.String); - } - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) - { - sc.MustGetString(); - if (sc.Compare("path")) - { - sc.MustGetString(); - FixPathSeperator(sc.String); - path = sc.String; - if (path[(int)path.Len()-1]!='/') path+='/'; - } - else if (sc.Compare("model")) - { - sc.MustGetNumber(); - index = sc.Number; - if (index < 0 || index >= MAX_MODELS_PER_FRAME) - { - sc.ScriptError("Too many models in %s", smf.type->TypeName.GetChars()); - } - sc.MustGetString(); - FixPathSeperator(sc.String); - smf.modelIDs[index] = FindModel(path.GetChars(), sc.String); - if (smf.modelIDs[index] == -1) - { - Printf("%s: model not found in %s\n", sc.String, path.GetChars()); - } - } - else if (sc.Compare("scale")) - { - sc.MustGetFloat(); - smf.xscale = sc.Float; - sc.MustGetFloat(); - smf.yscale = sc.Float; - sc.MustGetFloat(); - smf.zscale = sc.Float; - } - // [BB] Added zoffset reading. - // Now it must be considered deprecated. - else if (sc.Compare("zoffset")) - { - sc.MustGetFloat(); - smf.zoffset=sc.Float; - } - // Offset reading. - else if (sc.Compare("offset")) - { - sc.MustGetFloat(); - smf.xoffset = sc.Float; - sc.MustGetFloat(); - smf.yoffset = sc.Float; - sc.MustGetFloat(); - smf.zoffset = sc.Float; - } - // angleoffset, pitchoffset and rolloffset reading. - else if (sc.Compare("angleoffset")) - { - sc.MustGetFloat(); - smf.angleoffset = sc.Float; - } - else if (sc.Compare("pitchoffset")) - { - sc.MustGetFloat(); - smf.pitchoffset = sc.Float; - } - else if (sc.Compare("rolloffset")) - { - sc.MustGetFloat(); - smf.rolloffset = sc.Float; - } - // [BB] Added model flags reading. - else if (sc.Compare("ignoretranslation")) - { - smf.flags |= MDL_IGNORETRANSLATION; - } - else if (sc.Compare("pitchfrommomentum")) - { - smf.flags |= MDL_PITCHFROMMOMENTUM; - } - else if (sc.Compare("inheritactorpitch")) - { - smf.flags |= MDL_USEACTORPITCH | MDL_BADROTATION; - } - else if (sc.Compare("inheritactorroll")) - { - smf.flags |= MDL_USEACTORROLL; - } - else if (sc.Compare("useactorpitch")) - { - smf.flags |= MDL_USEACTORPITCH; - } - else if (sc.Compare("useactorroll")) - { - smf.flags |= MDL_USEACTORROLL; - } - else if (sc.Compare("rotating")) - { - smf.flags |= MDL_ROTATING; - smf.xrotate = 0.; - smf.yrotate = 1.; - smf.zrotate = 0.; - smf.rotationCenterX = 0.; - smf.rotationCenterY = 0.; - smf.rotationCenterZ = 0.; - smf.rotationSpeed = 1.; - } - else if (sc.Compare("rotation-speed")) - { - sc.MustGetFloat(); - smf.rotationSpeed = sc.Float; - } - else if (sc.Compare("rotation-vector")) - { - sc.MustGetFloat(); - smf.xrotate = sc.Float; - sc.MustGetFloat(); - smf.yrotate = sc.Float; - sc.MustGetFloat(); - smf.zrotate = sc.Float; - } - else if (sc.Compare("rotation-center")) - { - sc.MustGetFloat(); - smf.rotationCenterX = sc.Float; - sc.MustGetFloat(); - smf.rotationCenterY = sc.Float; - sc.MustGetFloat(); - smf.rotationCenterZ = sc.Float; - } - else if (sc.Compare("interpolatedoubledframes")) - { - smf.flags |= MDL_INTERPOLATEDOUBLEDFRAMES; - } - else if (sc.Compare("nointerpolation")) - { - smf.flags |= MDL_NOINTERPOLATION; - } - else if (sc.Compare("skin")) - { - sc.MustGetNumber(); - index=sc.Number; - if (index<0 || index>=MAX_MODELS_PER_FRAME) - { - sc.ScriptError("Too many models in %s", smf.type->TypeName.GetChars()); - } - sc.MustGetString(); - FixPathSeperator(sc.String); - if (sc.Compare("")) - { - smf.skinIDs[index]=FNullTextureID(); - } - else - { - smf.skinIDs[index] = LoadSkin(path.GetChars(), sc.String); - if (!smf.skinIDs[index].isValid()) - { - Printf("Skin '%s' not found in '%s'\n", - sc.String, smf.type->TypeName.GetChars()); - } - } - } - else if (sc.Compare("surfaceskin")) - { - sc.MustGetNumber(); - index = sc.Number; - sc.MustGetNumber(); - surface = sc.Number; - - if (index<0 || index >= MAX_MODELS_PER_FRAME) - { - sc.ScriptError("Too many models in %s", smf.type->TypeName.GetChars()); - } - - if (surface<0 || surface >= MD3_MAX_SURFACES) - { - sc.ScriptError("Invalid MD3 Surface %d in %s", MD3_MAX_SURFACES, smf.type->TypeName.GetChars()); - } - - sc.MustGetString(); - FixPathSeperator(sc.String); - if (sc.Compare("")) - { - smf.surfaceskinIDs[index][surface] = FNullTextureID(); - } - else - { - smf.surfaceskinIDs[index][surface] = LoadSkin(path.GetChars(), sc.String); - if (!smf.surfaceskinIDs[index][surface].isValid()) - { - Printf("Surface Skin '%s' not found in '%s'\n", - sc.String, smf.type->TypeName.GetChars()); - } - } - } - else if (sc.Compare("frameindex") || sc.Compare("frame")) - { - bool isframe=!!sc.Compare("frame"); - - sc.MustGetString(); - smf.sprite = -1; - for (int i = 0; i < (int)sprites.Size (); ++i) - { - if (strnicmp (sprites[i].name, sc.String, 4) == 0) - { - if (sprites[i].numframes==0) - { - //sc.ScriptError("Sprite %s has no frames", sc.String); - } - smf.sprite = i; - break; - } - } - if (smf.sprite==-1) - { - sc.ScriptError("Unknown sprite %s in model definition for %s", sc.String, smf.type->TypeName.GetChars()); - } - - sc.MustGetString(); - FString framechars = sc.String; - - sc.MustGetNumber(); - index=sc.Number; - if (index<0 || index>=MAX_MODELS_PER_FRAME) - { - sc.ScriptError("Too many models in %s", smf.type->TypeName.GetChars()); - } - if (isframe) - { - sc.MustGetString(); - if (smf.modelIDs[index] != -1) - { - FModel *model = Models[smf.modelIDs[index]]; - smf.modelframes[index] = model->FindFrame(sc.String); - if (smf.modelframes[index]==-1) sc.ScriptError("Unknown frame '%s' in %s", sc.String, smf.type->TypeName.GetChars()); - } - else smf.modelframes[index] = -1; - } - else - { - sc.MustGetNumber(); - smf.modelframes[index] = sc.Number; - } - - for(int i=0; framechars[i]>0; i++) - { - char map[29]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - int c = toupper(framechars[i])-'A'; - - if (c<0 || c>=29) - { - sc.ScriptError("Invalid frame character %c found", c+'A'); - } - if (map[c]) continue; - smf.frame=c; - SpriteModelFrames.Push(smf); - GetDefaultByType(smf.type)->hasmodel = true; - map[c]=1; - } - } - else if (sc.Compare("dontcullbackfaces")) - { - smf.flags |= MDL_DONTCULLBACKFACES; - } - else if (sc.Compare("userotationcenter")) - { - smf.flags |= MDL_USEROTATIONCENTER; - smf.rotationCenterX = 0.; - smf.rotationCenterY = 0.; - smf.rotationCenterZ = 0.; - } - else - { - sc.ScriptMessage("Unrecognized string \"%s\"", sc.String); - } - } - } - else if (sc.Compare("#include")) - { - sc.MustGetString(); - // This is not using sc.Open because it can print a more useful error message when done here - int includelump = Wads.CheckNumForFullName(sc.String, true); - if (includelump == -1) - { - if (strcmp(sc.String, "sentinel.modl") != 0) // Gene Tech mod has a broken #include statement - sc.ScriptError("Lump '%s' not found", sc.String); - } - else - { - ParseModelDefLump(includelump); - } - } - } -} - -//=========================================================================== -// -// FindModelFrame -// -//=========================================================================== - -FSpriteModelFrame * FindModelFrame(const PClass * ti, int sprite, int frame, bool dropped) -{ - if (GetDefaultByType(ti)->hasmodel) - { - FSpriteModelFrame smf; - - memset(&smf, 0, sizeof(smf)); - smf.type=ti; - smf.sprite=sprite; - smf.frame=frame; - - int hash = SpriteModelHash[ModelFrameHash(&smf) % SpriteModelFrames.Size()]; - - while (hash>=0) - { - FSpriteModelFrame * smff = &SpriteModelFrames[hash]; - if (smff->type==ti && smff->sprite==sprite && smff->frame==frame) return smff; - hash=smff->hashnext; - } - } - - // Check for voxel replacements - if (r_drawvoxels) - { - spritedef_t *sprdef = &sprites[sprite]; - if (frame < sprdef->numframes) - { - spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + frame]; - if (sprframe->Voxel != nullptr) - { - int index = sprframe->Voxel->VoxeldefIndex; - if (dropped && sprframe->Voxel->DroppedSpin !=sprframe->Voxel->PlacedSpin) index++; - return &SpriteModelFrames[index]; - } - } - } - return nullptr; -} - -//=========================================================================== -// -// IsHUDModelForPlayerAvailable -// -//=========================================================================== - -bool IsHUDModelForPlayerAvailable (player_t * player) -{ - if (player == nullptr || player->ReadyWeapon == nullptr) - return false; - - DPSprite *psp = player->FindPSprite(PSP_WEAPON); - - if (psp == nullptr) - return false; - - FSpriteModelFrame *smf = FindModelFrame(player->ReadyWeapon->GetClass(), psp->GetSprite(), psp->GetFrame(), false); - return ( smf != nullptr ); -} - diff --git a/src/r_data/models/models.h b/src/r_data/models/models.h deleted file mode 100644 index b9a41039c0c..00000000000 --- a/src/r_data/models/models.h +++ /dev/null @@ -1,514 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#ifndef __GL_MODELS_H_ -#define __GL_MODELS_H_ - -#include "tarray.h" -#include "matrix.h" -#include "actor.h" -#include "dobject.h" -#include "p_pspr.h" -#include "r_data/voxels.h" -#include "info.h" -#include "g_levellocals.h" - -#define MAX_LODS 4 - -enum { VX, VZ, VY }; - -#define MD2_MAGIC 0x32504449 -#define DMD_MAGIC 0x4D444D44 -#define MD3_MAGIC 0x33504449 -#define NUMVERTEXNORMALS 162 -#define MD3_MAX_SURFACES 32 - -FTextureID LoadSkin(const char * path, const char * fn); - -struct FSpriteModelFrame; -class IModelVertexBuffer; -struct FLevelLocals; - -enum ModelRendererType -{ - GLModelRendererType, - SWModelRendererType, - PolyModelRendererType, - NumModelRendererTypes -}; - -class FModelRenderer -{ -public: - virtual ~FModelRenderer() { } - - void RenderModel(float x, float y, float z, FSpriteModelFrame *modelframe, AActor *actor, double ticFrac); - void RenderHUDModel(DPSprite *psp, float ofsx, float ofsy); - - virtual ModelRendererType GetType() const = 0; - - virtual void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0; - virtual void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) = 0; - - virtual IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) = 0; - - virtual VSMatrix GetViewToWorldMatrix() = 0; - - virtual void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0; - virtual void EndDrawHUDModel(AActor *actor) = 0; - - virtual void SetInterpolation(double interpolation) = 0; - virtual void SetMaterial(FTexture *skin, bool clampNoFilter, int translation) = 0; - virtual void DrawArrays(int start, int count) = 0; - virtual void DrawElements(int numIndices, size_t offset) = 0; - -private: - void RenderFrameModels(FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, const PClass *ti, int translation); -}; - -struct FModelVertex -{ - float x, y, z; // world position - float u, v; // texture coordinates - unsigned packedNormal; // normal vector as GL_INT_2_10_10_10_REV. - - void Set(float xx, float yy, float zz, float uu, float vv) - { - x = xx; - y = yy; - z = zz; - u = uu; - v = vv; - } - - void SetNormal(float nx, float ny, float nz) - { - int inx = clamp(int(nx * 512), -512, 511); - int iny = clamp(int(ny * 512), -512, 511); - int inz = clamp(int(nz * 512), -512, 511); - int inw = 0; - packedNormal = (inw << 30) | ((inz & 1023) << 20) | ((iny & 1023) << 10) | (inx & 1023); - } -}; - -#define VMO ((FModelVertex*)NULL) - -class FModelRenderer; - -class IModelVertexBuffer -{ -public: - virtual ~IModelVertexBuffer() { } - - virtual FModelVertex *LockVertexBuffer(unsigned int size) = 0; - virtual void UnlockVertexBuffer() = 0; - - virtual unsigned int *LockIndexBuffer(unsigned int size) = 0; - virtual void UnlockIndexBuffer() = 0; - - virtual void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) = 0; -}; - -class FModel -{ -public: - FModel(); - virtual ~FModel(); - - virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0; - virtual int FindFrame(const char * name) = 0; - virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0; - virtual void BuildVertexBuffer(FModelRenderer *renderer) = 0; - virtual void AddSkins(uint8_t *hitlist) = 0; - virtual float getAspectFactor(FLevelLocals *) { return 1.f; } - - void SetVertexBuffer(FModelRenderer *renderer, IModelVertexBuffer *buffer) { mVBuf[renderer->GetType()] = buffer; } - IModelVertexBuffer *GetVertexBuffer(FModelRenderer *renderer) const { return mVBuf[renderer->GetType()]; } - void DestroyVertexBuffer(); - - const FSpriteModelFrame *curSpriteMDLFrame; - int curMDLIndex; - void PushSpriteMDLFrame(const FSpriteModelFrame *smf, int index) { curSpriteMDLFrame = smf; curMDLIndex = index; }; - - FString mFileName; - -private: - IModelVertexBuffer *mVBuf[NumModelRendererTypes]; -}; - -class FDMDModel : public FModel -{ -protected: - - struct FTriangle - { - unsigned short vertexIndices[3]; - unsigned short textureIndices[3]; - }; - - - struct DMDHeader - { - int magic; - int version; - int flags; - }; - - struct DMDModelVertex - { - float xyz[3]; - }; - - struct FTexCoord - { - short s, t; - }; - - struct FGLCommandVertex - { - float s, t; - int index; - }; - - struct DMDInfo - { - int skinWidth; - int skinHeight; - int frameSize; - int numSkins; - int numVertices; - int numTexCoords; - int numFrames; - int numLODs; - int offsetSkins; - int offsetTexCoords; - int offsetFrames; - int offsetLODs; - int offsetEnd; - }; - - struct ModelFrame - { - char name[16]; - unsigned int vindex; - }; - - struct ModelFrameVertexData - { - DMDModelVertex *vertices; - DMDModelVertex *normals; - }; - - struct DMDLoDInfo - { - int numTriangles; - int numGlCommands; - int offsetTriangles; - int offsetGlCommands; - }; - - struct DMDLoD - { - FTriangle * triangles; - }; - - - int mLumpNum; - DMDHeader header; - DMDInfo info; - FTextureID * skins; - ModelFrame * frames; - bool allowTexComp; // Allow texture compression with this. - - // Temp data only needed for buffer construction - FTexCoord * texCoords; - ModelFrameVertexData *framevtx; - DMDLoDInfo lodInfo[MAX_LODS]; - DMDLoD lods[MAX_LODS]; - -public: - FDMDModel() - { - mLumpNum = -1; - frames = NULL; - skins = NULL; - for (int i = 0; i < MAX_LODS; i++) - { - lods[i].triangles = NULL; - } - info.numLODs = 0; - texCoords = NULL; - framevtx = NULL; - } - virtual ~FDMDModel(); - - virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length); - virtual int FindFrame(const char * name); - virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0); - virtual void LoadGeometry(); - virtual void AddSkins(uint8_t *hitlist); - - void UnloadGeometry(); - void BuildVertexBuffer(FModelRenderer *renderer); - -}; - -// This uses the same internal representation as DMD -class FMD2Model : public FDMDModel -{ -public: - FMD2Model() {} - virtual ~FMD2Model(); - - virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length); - virtual void LoadGeometry(); - -}; - - -class FMD3Model : public FModel -{ - struct MD3Tag - { - // Currently I have no use for this - }; - - struct MD3TexCoord - { - float s,t; - }; - - struct MD3Vertex - { - float x,y,z; - float nx,ny,nz; - }; - - struct MD3Triangle - { - int VertIndex[3]; - }; - - struct MD3Surface - { - unsigned numVertices; - unsigned numTriangles; - unsigned numSkins; - - TArray Skins; - TArray Tris; - TArray Texcoords; - TArray Vertices; - - unsigned int vindex = UINT_MAX; // contains numframes arrays of vertices - unsigned int iindex = UINT_MAX; - - void UnloadGeometry() - { - Tris.Reset(); - Vertices.Reset(); - Texcoords.Reset(); - } - }; - - struct MD3Frame - { - // The bounding box information is of no use in the Doom engine - // That will still be done with the actor's size information. - char Name[16]; - float origin[3]; - }; - - int numTags; - int mLumpNum; - - TArray Frames; - TArray Surfaces; - -public: - FMD3Model() = default; - - virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length); - virtual int FindFrame(const char * name); - virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0); - void LoadGeometry(); - void BuildVertexBuffer(FModelRenderer *renderer); - virtual void AddSkins(uint8_t *hitlist); -}; - -struct FVoxelVertexHash -{ - // Returns the hash value for a key. - hash_t Hash(const FModelVertex &key) - { - int ix = xs_RoundToInt(key.x); - int iy = xs_RoundToInt(key.y); - int iz = xs_RoundToInt(key.z); - return (hash_t)(ix + (iy<<9) + (iz<<18)); - } - - // Compares two keys, returning zero if they are the same. - int Compare(const FModelVertex &left, const FModelVertex &right) - { - return left.x != right.x || left.y != right.y || left.z != right.z || left.u != right.u || left.v != right.v; - } -}; - -struct FIndexInit -{ - void Init(unsigned int &value) - { - value = 0xffffffff; - } -}; - -typedef TMap FVoxelMap; - - -class FVoxelModel : public FModel -{ -protected: - FVoxel *mVoxel; - bool mOwningVoxel; // if created through MODELDEF deleting this object must also delete the voxel object - FTextureID mPalette; - unsigned int mNumIndices; - TArray mVertices; - TArray mIndices; - - void MakeSlabPolys(int x, int y, kvxslab_t *voxptr, FVoxelMap &check); - void AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3, int x4, int y4, int z4, uint8_t color, FVoxelMap &check); - unsigned int AddVertex(FModelVertex &vert, FVoxelMap &check); - -public: - FVoxelModel(FVoxel *voxel, bool owned); - ~FVoxelModel(); - bool Load(const char * fn, int lumpnum, const char * buffer, int length); - void Initialize(); - virtual int FindFrame(const char * name); - virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0); - virtual void AddSkins(uint8_t *hitlist); - FTextureID GetPaletteTexture() const { return mPalette; } - void BuildVertexBuffer(FModelRenderer *renderer); - float getAspectFactor(FLevelLocals *) override; -}; - - - -#define MAX_MODELS_PER_FRAME 4 - -// -// [BB] Model rendering flags. -// -enum -{ - // [BB] Color translations for the model skin are ignored. This is - // useful if the skin texture is not using the game palette. - MDL_IGNORETRANSLATION = 1, - MDL_PITCHFROMMOMENTUM = 2, - MDL_ROTATING = 4, - MDL_INTERPOLATEDOUBLEDFRAMES = 8, - MDL_NOINTERPOLATION = 16, - MDL_USEACTORPITCH = 32, - MDL_USEACTORROLL = 64, - MDL_BADROTATION = 128, - MDL_DONTCULLBACKFACES = 256, - MDL_USEROTATIONCENTER = 512, -}; - -struct FSpriteModelFrame -{ - int modelIDs[MAX_MODELS_PER_FRAME]; - FTextureID skinIDs[MAX_MODELS_PER_FRAME]; - FTextureID surfaceskinIDs[MAX_MODELS_PER_FRAME][MD3_MAX_SURFACES]; - int modelframes[MAX_MODELS_PER_FRAME]; - float xscale, yscale, zscale; - // [BB] Added zoffset, rotation parameters and flags. - // Added xoffset, yoffset - float xoffset, yoffset, zoffset; - float xrotate, yrotate, zrotate; - float rotationCenterX, rotationCenterY, rotationCenterZ; - float rotationSpeed; - unsigned int flags; - const PClass * type; - short sprite; - short frame; - FState * state; // for later! - int hashnext; - float angleoffset; - // added pithoffset, rolloffset. - float pitchoffset, rolloffset; // I don't want to bother with type transformations, so I made this variables float. - bool isVoxel; -}; - -FSpriteModelFrame * FindModelFrame(const PClass * ti, int sprite, int frame, bool dropped); -bool IsHUDModelForPlayerAvailable(player_t * player); -void FlushModels(); - - -extern TDeletingArray Models; - -// Check if circle potentially intersects with node AABB -inline bool CheckBBoxCircle(float *bbox, float x, float y, float radiusSquared) -{ - float centerX = (bbox[BOXRIGHT] + bbox[BOXLEFT]) * 0.5f; - float centerY = (bbox[BOXBOTTOM] + bbox[BOXTOP]) * 0.5f; - float extentX = (bbox[BOXRIGHT] - bbox[BOXLEFT]) * 0.5f; - float extentY = (bbox[BOXBOTTOM] - bbox[BOXTOP]) * 0.5f; - float aabbRadiusSquared = extentX * extentX + extentY * extentY; - x -= centerX; - y -= centerY; - float dist = x * x + y * y; - return dist <= radiusSquared + aabbRadiusSquared; -} - -// Helper function for BSPWalkCircle -template -void BSPNodeWalkCircle(void *node, float x, float y, float radiusSquared, const Callback &callback) -{ - while (!((size_t)node & 1)) - { - node_t *bsp = (node_t *)node; - - if (CheckBBoxCircle(bsp->bbox[0], x, y, radiusSquared)) - BSPNodeWalkCircle(bsp->children[0], x, y, radiusSquared, callback); - - if (!CheckBBoxCircle(bsp->bbox[1], x, y, radiusSquared)) - return; - - node = bsp->children[1]; - } - - subsector_t *sub = (subsector_t *)((uint8_t *)node - 1); - callback(sub); -} - -// Search BSP for subsectors within the given radius and call callback(subsector) for each found -template -void BSPWalkCircle(FLevelLocals *Level, float x, float y, float radiusSquared, const Callback &callback) -{ - if (Level->nodes.Size() == 0) - callback(&Level->subsectors[0]); - else - BSPNodeWalkCircle(Level->HeadNode(), x, y, radiusSquared, callback); -} - -#endif diff --git a/src/r_data/models/models_obj.h b/src/r_data/models/models_obj.h deleted file mode 100644 index 01a6e03cf2b..00000000000 --- a/src/r_data/models/models_obj.h +++ /dev/null @@ -1,104 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2018 Kevin Caccamo -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#ifndef __GL_MODELS_OBJ_H__ -#define __GL_MODELS_OBJ_H__ - -#include "models.h" -#include "sc_man.h" - -class FOBJModel : public FModel -{ -private: - const char *newSideSep = "$"; // OBJ side separator is /, which is parsed as a line comment by FScanner if two of them are next to each other. - bool hasMissingNormals; - bool hasSmoothGroups; - - enum class FaceElement - { - VertexIndex, - UVIndex, - VNormalIndex - }; - - struct OBJTriRef - { - unsigned int surf; - unsigned int tri; - OBJTriRef(): surf(0), tri(0) {} - OBJTriRef(unsigned int surf, unsigned int tri): surf(surf), tri(tri) {} - bool operator== (OBJTriRef other) { return surf == other.surf && tri == other.tri; } - }; - struct OBJFaceSide - { - int vertref; - int normref; - int uvref; - }; - struct OBJFace - { - unsigned int sideCount; - unsigned int smoothGroup; - OBJFaceSide sides[4]; - OBJFace(): sideCount(0), smoothGroup(0) {} - }; - struct OBJSurface // 1 surface per 'usemtl' - { - unsigned int numTris; // Number of triangulated faces - unsigned int numFaces; // Number of faces - unsigned int vbStart; // First index in vertex buffer - unsigned int faceStart; // Index of first face in faces array - OBJFace* tris; // Triangles - FTextureID skin; - OBJSurface(FTextureID skin): numTris(0), numFaces(0), vbStart(0), faceStart(0), tris(nullptr), skin(skin) {} - }; - - TArray verts; - TArray norms; - TArray uvs; - TArray faces; - TArray surfaces; - FScanner sc; - TArray* vertFaces; - - int ResolveIndex(int origIndex, FaceElement el); - template void ParseVector(TArray &array); - bool ParseFaceSide(const FString &side, OBJFace &face, int sidx); - void ConstructSurfaceTris(OBJSurface &surf); - void AddVertFaces(); - void TriangulateQuad(const OBJFace &quad, OBJFace *tris); - FVector3 RealignVector(FVector3 vecToRealign); - FVector2 FixUV(FVector2 vecToRealign); - FVector3 CalculateNormalFlat(unsigned int surfIdx, unsigned int triIdx); - FVector3 CalculateNormalFlat(OBJTriRef otr); - FVector3 CalculateNormalSmooth(unsigned int vidx, unsigned int smoothGroup); -public: - FOBJModel(): hasMissingNormals(false), hasSmoothGroups(false), vertFaces(nullptr) {} - ~FOBJModel(); - bool Load(const char* fn, int lumpnum, const char* buffer, int length) override; - int FindFrame(const char* name) override; - void RenderFrame(FModelRenderer* renderer, FTexture* skin, int frame, int frame2, double inter, int translation=0) override; - void BuildVertexBuffer(FModelRenderer* renderer) override; - void AddSkins(uint8_t* hitlist) override; -}; - -#endif diff --git a/src/r_data/models/models_ue1.cpp b/src/r_data/models/models_ue1.cpp deleted file mode 100644 index c51dbc7fbbf..00000000000 --- a/src/r_data/models/models_ue1.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2018 Marisa Kirisame -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#include "w_wad.h" -#include "cmdlib.h" -#include "r_data/models/models_ue1.h" - -float unpackuvert( uint32_t n, int c ) -{ - switch( c ) - { - case 0: - return ((int16_t)((n&0x7ff)<<5))/128.f; - case 1: - return ((int16_t)(((n>>11)&0x7ff)<<5))/128.f; - case 2: - return ((int16_t)(((n>>22)&0x3ff)<<6))/128.f; - default: - return 0.f; - } -} - -bool FUE1Model::Load( const char *filename, int lumpnum, const char *buffer, int length ) -{ - int lumpnum2; - FString realfilename = Wads.GetLumpFullName(lumpnum); - if ( (size_t)realfilename.IndexOf("_d.3d") == realfilename.Len()-5 ) - { - realfilename.Substitute("_d.3d","_a.3d"); - lumpnum2 = Wads.CheckNumForFullName(realfilename); - mDataLump = lumpnum; - mAnivLump = lumpnum2; - } - else - { - realfilename.Substitute("_a.3d","_d.3d"); - lumpnum2 = Wads.CheckNumForFullName(realfilename); - mAnivLump = lumpnum; - mDataLump = lumpnum2; - } - return true; -} - -void FUE1Model::LoadGeometry() -{ - FMemLump lump, lump2; - const char *buffer, *buffer2; - lump = Wads.ReadLump(mDataLump); - buffer = (char*)lump.GetMem(); - lump2 = Wads.ReadLump(mAnivLump); - buffer2 = (char*)lump2.GetMem(); - // map structures - dhead = (d3dhead*)(buffer); - dpolys = (d3dpoly*)(buffer+sizeof(d3dhead)); - ahead = (a3dhead*)(buffer2); - // detect deus ex format - if ( (ahead->framesize/dhead->numverts) == 8 ) - { - averts = NULL; - dxverts = (dxvert*)(buffer2+sizeof(a3dhead)); - } - else - { - averts = (uint32_t*)(buffer2+sizeof(a3dhead)); - dxverts = NULL; - } - weaponPoly = -1; - // set counters - numVerts = dhead->numverts; - numFrames = ahead->numframes; - numPolys = dhead->numpolys; - numGroups = 0; - // populate vertex arrays - for ( int i=0; i= numFrames) || (frame2 >= numFrames) ) return; - renderer->SetInterpolation(inter); - int vsize, fsize = 0, vofs = 0; - for ( int i=0; isurfaceskinIDs[curMDLIndex][groups[i].texNum].isValid() ) - sskin = TexMan.GetTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][groups[i].texNum], true); - if ( !sskin ) - { - vofs += vsize; - continue; - } - } - // TODO: Handle per-group render styles and other flags once functions for it are implemented - // Future note: poly renderstyles should always be enforced unless the actor itself has a style other than Normal - renderer->SetMaterial(sskin,false,translation); - GetVertexBuffer(renderer)->SetupFrame(renderer,vofs+frame*fsize,vofs+frame2*fsize,vsize); - renderer->DrawArrays(0,vsize); - vofs += vsize; - } - renderer->SetInterpolation(0.f); -} - -void FUE1Model::BuildVertexBuffer( FModelRenderer *renderer ) -{ - if (GetVertexBuffer(renderer)) - return; - if ( !mDataLoaded ) - LoadGeometry(); - int vsize = 0; - for ( int i=0; iCreateVertexBuffer(false,numFrames==1); - SetVertexBuffer(renderer, vbuf); - FModelVertex *vptr = vbuf->LockVertexBuffer(vsize); - int vidx = 0; - for ( int i=0; iSet(V.Pos.X,V.Pos.Y,V.Pos.Z,C.X,C.Y); - if ( groups[j].type&PT_Curvy ) // use facet normal - { - vert->SetNormal(polys[groups[j].P[k]].Normals[i].X, - polys[groups[j].P[k]].Normals[i].Y, - polys[groups[j].P[k]].Normals[i].Z); - } - else vert->SetNormal(V.Normal.X,V.Normal.Y,V.Normal.Z); - } - } - } - } - vbuf->UnlockVertexBuffer(); -} - -void FUE1Model::AddSkins( uint8_t *hitlist ) -{ - for ( int i=0; isurfaceskinIDs[curMDLIndex][groups[i].texNum].isValid() ) - hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][groups[i].texNum].GetIndex()] |= FTextureManager::HIT_Flat; -} - -FUE1Model::~FUE1Model() -{ - UnloadGeometry(); -} diff --git a/src/r_data/models/models_ue1.h b/src/r_data/models/models_ue1.h deleted file mode 100644 index be9f57a10b8..00000000000 --- a/src/r_data/models/models_ue1.h +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once - -#include "models.h" - -class FUE1Model : public FModel -{ -public: - enum EPolyType - { - PT_Normal = 0, // normal renderstyle - PT_TwoSided = 1, // like normal, but don't cull backfaces - PT_Translucent = 2, // additive blending - PT_Masked = 3, // draw with alpha testing - PT_Modulated = 4, // overlay-like blending (rgb values below 128 darken, 128 is unchanged, and above 128 lighten) - // types mask - PT_Type = 7, - // flags - PT_WeaponTriangle = 0x08, // this poly is used for positioning a weapon attachment and should not be drawn - PT_Unlit = 0x10, // this poly is fullbright - PT_Curvy = 0x20, // this poly uses the facet normal - PT_EnvironmentMap = 0x40, // vertex UVs are remapped to their view-space X and Z normals, fake cubemap look - PT_NoSmooth = 0x80 // this poly forcibly uses nearest filtering - }; - - bool Load(const char * fn, int lumpnum, const char * buffer, int length) override; - int FindFrame(const char * name) override; - void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0) override; - void BuildVertexBuffer(FModelRenderer *renderer) override; - void AddSkins(uint8_t *hitlist) override; - void LoadGeometry(); - void UnloadGeometry(); - FUE1Model() - { - mDataLump = -1; - mAnivLump = -1; - mDataLoaded = false; - dhead = NULL; - dpolys = NULL; - ahead = NULL; - averts = NULL; - numVerts = 0; - numFrames = 0; - numPolys = 0; - numGroups = 0; - } - ~FUE1Model(); - -private: - int mDataLump, mAnivLump; - bool mDataLoaded; - - // raw data structures - struct d3dhead - { - uint16_t numpolys, numverts; - uint16_t bogusrot, bogusframe; - uint32_t bogusnorm[3]; - uint32_t fixscale; - uint32_t unused[3]; - uint8_t padding[12]; - }; - struct d3dpoly - { - uint16_t vertices[3]; - uint8_t type, color; - uint8_t uv[3][2]; - uint8_t texnum, flags; - }; - struct a3dhead - { - uint16_t numframes, framesize; - }; - d3dhead * dhead; - d3dpoly * dpolys; - a3dhead * ahead; - uint32_t * averts; - struct dxvert - { - int16_t x, y, z, pad; - }; - dxvert * dxverts; - - // converted data structures - struct UE1Vertex - { - FVector3 Pos, Normal; - }; - struct UE1Poly - { - int V[3]; - FVector2 C[3]; - TArray Normals; - }; - struct UE1Group - { - TArray P; - int numPolys, texNum, type; - }; - - int numVerts; - int numFrames; - int numPolys; - int numGroups; - int weaponPoly; // for future model attachment support, unused for now - - TArray verts; - TArray polys; - TArray groups; -}; diff --git a/src/r_data/portalgroups.cpp b/src/r_data/portalgroups.cpp index 8d682b78e7d..b7f0e7255d4 100644 --- a/src/r_data/portalgroups.cpp +++ b/src/r_data/portalgroups.cpp @@ -400,7 +400,7 @@ static void GroupLinePortals(FLevelLocals *Level) for (unsigned i = 0; i < Level->linePortals.Size(); i++) { - auto port = Level->linePortals[i]; + const auto& port = Level->linePortals[i]; bool gotsome; if (tempindex[i] == -1) diff --git a/src/r_data/r_canvastexture.cpp b/src/r_data/r_canvastexture.cpp index 4a159170f5c..49e4e8ab20a 100644 --- a/src/r_data/r_canvastexture.cpp +++ b/src/r_data/r_canvastexture.cpp @@ -38,6 +38,8 @@ #include "r_canvastexture.h" #include "g_levellocals.h" #include "serializer.h" +#include "serialize_obj.h" +#include "texturemanager.h" //========================================================================== // @@ -55,10 +57,11 @@ void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, double fov) { return; } - texture = static_cast(TexMan.GetTexture(picnum)); + auto gt = TexMan.GetGameTexture(picnum); + texture = static_cast(gt->GetTexture()); if (!texture->bHasCanvas) { - Printf ("%s is not a valid target for a camera\n", texture->Name.GetChars()); + Printf ("%s is not a valid target for a camera\n", gt->GetName().GetChars()); return; } @@ -95,12 +98,12 @@ void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, double fov) void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov) { - FTextureID textureid = TexMan.CheckForTexture(texturename, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + FTextureID textureid = TexMan.CheckForTexture(texturename.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable); if (textureid.isValid()) { // Only proceed if the texture actually has a canvas. - FTexture *tex = TexMan.GetTexture(textureid); - if (tex && tex->isCanvas()) + auto tex = TexMan.GetGameTexture(textureid); + if (tex && tex->isHardwareCanvas()) // Q: how to deal with the software renderer here? { viewpoint->Level->canvasTextureInfo.Add(viewpoint, textureid, fov); } diff --git a/src/r_data/r_canvastexture.h b/src/r_data/r_canvastexture.h index b69c4668709..22f5a730fff 100644 --- a/src/r_data/r_canvastexture.h +++ b/src/r_data/r_canvastexture.h @@ -1,6 +1,8 @@ #pragma once +class FCanvas; class FCanvasTexture; + // This list keeps track of the cameras that draw into canvas textures. struct FCanvasTextureEntry { diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index ed9c7f58a22..30dff51c69d 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -38,7 +38,8 @@ #include "r_data/r_interpolate.h" #include "p_local.h" #include "po_man.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "g_levellocals.h" //========================================================================== diff --git a/src/r_data/r_interpolate.h b/src/r_data/r_interpolate.h index 888f387c515..29f3f56dfa6 100644 --- a/src/r_data/r_interpolate.h +++ b/src/r_data/r_interpolate.h @@ -17,8 +17,8 @@ class DInterpolation : public DObject DECLARE_ABSTRACT_CLASS(DInterpolation, DObject) HAS_OBJECT_POINTERS - TObjPtr Next = nullptr; - TObjPtr Prev = nullptr; + TObjPtr Next; + TObjPtr Prev; protected: FLevelLocals *Level; @@ -46,7 +46,7 @@ class DInterpolation : public DObject struct FInterpolator { - TObjPtr Head = nullptr; + TObjPtr Head = MakeObjPtr(nullptr); bool didInterp = false; int count = 0; diff --git a/src/r_data/r_sections.cpp b/src/r_data/r_sections.cpp index 998945aa64f..c4149248284 100644 --- a/src/r_data/r_sections.cpp +++ b/src/r_data/r_sections.cpp @@ -243,7 +243,8 @@ class FSectionCreator { if (sub->firstline[i].PartnerSeg && sub->firstline[i].Subsector->render_sector == sub->firstline[i].PartnerSeg->Subsector->render_sector) { - seglist.Push(sub->firstline[i].PartnerSeg); + if (sub->firstline[i].sidedef == nullptr || !(Level->ib_compatflags & BCOMPATF_NOSECTIONMERGE)) + seglist.Push(sub->firstline[i].PartnerSeg); } } }; @@ -803,6 +804,21 @@ class FSectionCreator sub.section = bestfit; } } + + // Set all empty sectors' initial index to 0, so that we do not have to range-check each access. + for (unsigned i = 0; i < Level->sectors.Size(); i++) + { + if (Level->sections.firstSectionForSectorPtr[i] < 0) + { + Level->sections.firstSectionForSectorPtr[i] = 0; + if (Level->sections.numberOfSectionForSectorPtr[i] > 0) + { + // This should never happen. + Printf("Warning: Sector %d has a non-empty section list with no address\n", i); + Level->sections.numberOfSectionForSectorPtr = 0; + } + } + } } }; diff --git a/src/r_data/r_sections.h b/src/r_data/r_sections.h index fcd7cd3b2aa..fd13a80e7a5 100644 --- a/src/r_data/r_sections.h +++ b/src/r_data/r_sections.h @@ -72,8 +72,8 @@ struct BoundingRect double distanceTo(const BoundingRect &other) const { if (intersects(other)) return 0; - return std::max(std::min(fabs(left - other.right), fabs(right - other.left)), - std::min(fabs(top - other.bottom), fabs(bottom - other.top))); + return max(min(fabs(left - other.right), fabs(right - other.left)), + min(fabs(top - other.bottom), fabs(bottom - other.top))); } void addVertex(double x, double y) @@ -141,6 +141,7 @@ class FSectionContainer } TArrayView SectionsForSector(int sindex) { + if (numberOfSectionForSectorPtr[sindex] == 0) return TArrayView(nullptr); return sindex < 0 ? TArrayView(0) : TArrayView(&allSections[firstSectionForSectorPtr[sindex]], numberOfSectionForSectorPtr[sindex]); } int SectionIndex(const FSection *sect) diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index ed5ce9bc3fe..8b197cda7d5 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -34,14 +34,14 @@ #include -#include "templates.h" + #include "r_data/r_translate.h" #include "v_video.h" #include "g_game.h" #include "d_netinf.h" #include "sc_man.h" -#include "doomerrors.h" -#include "w_wad.h" +#include "engineerrors.h" +#include "filesystem.h" #include "serializer.h" #include "d_player.h" #include "r_data/sprites.h" @@ -50,215 +50,17 @@ #include "v_text.h" #include "m_crc32.h" #include "g_levellocals.h" +#include "palutil.h" #include "gi.h" -TAutoGrowArray translationtables[NUM_TRANSLATION_TABLES]; - - -const uint8_t IcePalette[16][3] = -{ - { 10, 8, 18 }, - { 15, 15, 26 }, - { 20, 16, 36 }, - { 30, 26, 46 }, - { 40, 36, 57 }, - { 50, 46, 67 }, - { 59, 57, 78 }, - { 69, 67, 88 }, - { 79, 77, 99 }, - { 89, 87,109 }, - { 99, 97,120 }, - { 109,107,130 }, - { 118,118,141 }, - { 128,128,151 }, - { 138,138,162 }, - { 148,148,172 } -}; - -static bool IndexOutOfRange(const int color) -{ - const bool outOfRange = color < 0 || color > 255; - - if (outOfRange) - { - Printf(TEXTCOLOR_ORANGE "Palette index %i is out of range [0..255]\n", color); - } - - return outOfRange; -} - -static bool IndexOutOfRange(const int start, const int end) -{ - const bool outOfRange = IndexOutOfRange(start); - return IndexOutOfRange(end) || outOfRange; -} - -static bool IndexOutOfRange(const int start1, const int end1, const int start2, const int end2) -{ - const bool outOfRange = IndexOutOfRange(start1, end1); - return IndexOutOfRange(start2, end2) || outOfRange; -} - - - -TArray FUniquePalette::AllPalettes; - -//---------------------------------------------------------------------------- -// -// Helper class to deal with frequently changing translations from ACS -// -//---------------------------------------------------------------------------- - -bool FUniquePalette::Update() -{ - PalData pd; - - memset(pd.pe, 0, sizeof(pd.pe)); - memcpy(pd.pe, remap->Palette, remap->NumEntries * sizeof(*remap->Palette)); - pd.crc32 = CalcCRC32((uint8_t*)pd.pe, sizeof(pd.pe)); - for (unsigned int i = 0; i< AllPalettes.Size(); i++) - { - if (pd.crc32 == AllPalettes[i].crc32) - { - if (!memcmp(pd.pe, AllPalettes[i].pe, sizeof(pd.pe))) - { - Index = 1 + i; - return true; - } - } - } - Index = 1 + AllPalettes.Push(pd); - return true; -} - -/****************************************************/ -/****************************************************/ - -FRemapTable::FRemapTable(int count) -{ - assert(count <= 256); - Inactive = false; - Alloc(count); - - // Note that the tables are left uninitialized. It is assumed that - // the caller will do that next, if only by calling MakeIdentity(). -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -FRemapTable::~FRemapTable() -{ - Free(); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -int FRemapTable::GetUniqueIndex() -{ - if (Inactive) return 0; - if (Native == nullptr) - { - Native = new FUniquePalette(this); - Native->Update(); - } - return Native->GetIndex(); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void FRemapTable::Alloc(int count) -{ - Remap = (uint8_t *)M_Malloc(count*sizeof(*Remap) + count*sizeof(*Palette)); - assert (Remap != NULL); - Palette = (PalEntry *)(Remap + count*(sizeof(*Remap))); - Native = NULL; - NumEntries = count; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void FRemapTable::Free() -{ - KillNative(); - if (Remap != NULL) - { - M_Free(Remap); - Remap = NULL; - Palette = NULL; - NumEntries = 0; - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -FRemapTable::FRemapTable(const FRemapTable &o) -{ - Remap = NULL; - Native = NULL; - NumEntries = 0; - operator= (o); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -FRemapTable &FRemapTable::operator=(const FRemapTable &o) -{ - if (&o == this) - { - return *this; - } - if (o.NumEntries != NumEntries) - { - Free(); - } - if (Remap == NULL) - { - Alloc(o.NumEntries); - } - Inactive = o.Inactive; - memcpy(Remap, o.Remap, NumEntries*sizeof(*Remap) + NumEntries*sizeof(*Palette)); - return *this; -} - //---------------------------------------------------------------------------- // -// +// helper stuff for serializing TRANSLATION_User // //---------------------------------------------------------------------------- -bool FRemapTable::operator==(const FRemapTable &o) -{ - // Two translations are identical when they have the same amount of colors - // and the palette values for both are identical. - if (&o == this) return true; - if (o.NumEntries != NumEntries) return false; - return !memcmp(o.Palette, Palette, NumEntries * sizeof(*Palette)); -} +static TArray> usertransmap; //---------------------------------------------------------------------------- // @@ -266,25 +68,16 @@ bool FRemapTable::operator==(const FRemapTable &o) // //---------------------------------------------------------------------------- -void FRemapTable::Serialize(FSerializer &arc) +static void SerializeRemap(FSerializer &arc, FRemapTable &remap) { - int n = NumEntries; - - arc("numentries", NumEntries); - if (arc.isReading()) - { - if (n != NumEntries) - { - Free(); - Alloc(NumEntries); - } - } - arc.Array("remap", Remap, NumEntries); - arc.Array("palette", Palette, NumEntries); + arc("numentries", remap.NumEntries); + arc.Array("remap", remap.Remap, remap.NumEntries); + arc.Array("palette", remap.Palette, remap.NumEntries); } -void FRemapTable::StaticSerializeTranslations(FSerializer &arc) +void StaticSerializeTranslations(FSerializer &arc) { + usertransmap.Clear(); if (arc.BeginArray("translations")) { // Does this level have custom translations? @@ -292,15 +85,16 @@ void FRemapTable::StaticSerializeTranslations(FSerializer &arc) int w; if (arc.isWriting()) { - for (unsigned int i = 0; i < translationtables[TRANSLATION_LevelScripted].Size(); ++i) + auto size = GPalette.NumTranslations(TRANSLATION_LevelScripted); + for (unsigned int i = 0; i < size; ++i) { - trans = translationtables[TRANSLATION_LevelScripted][i]; + trans = GPalette.GetTranslation(TRANSLATION_LevelScripted, i); if (trans != NULL && !trans->IsIdentity()) { if (arc.BeginObject(nullptr)) { arc("index", i); - trans->Serialize(arc); + SerializeRemap(arc, *trans); arc.EndObject(); } } @@ -311,523 +105,70 @@ void FRemapTable::StaticSerializeTranslations(FSerializer &arc) while (arc.BeginObject(nullptr)) { arc("index", w); - trans = translationtables[TRANSLATION_LevelScripted].GetVal(w); - if (trans == NULL) - { - trans = new FRemapTable; - translationtables[TRANSLATION_LevelScripted].SetVal(w, trans); - } - trans->Serialize(arc); + FRemapTable remap; + SerializeRemap(arc, remap); + GPalette.UpdateTranslation(TRANSLATION(TRANSLATION_LevelScripted, w), &remap); arc.EndObject(); } } arc.EndArray(); } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void FRemapTable::MakeIdentity() -{ - int i; - - for (i = 0; i < NumEntries; ++i) - { - Remap[i] = i; - } - for (i = 0; i < NumEntries; ++i) - { - Palette[i] = GPalette.BaseColors[i]; - } - for (i = 1; i < NumEntries; ++i) + if (arc.BeginArray("usertranslations")) { - Palette[i].a = 255; - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool FRemapTable::IsIdentity() const -{ - for (int j = 0; j < 256; ++j) - { - if (Remap[j] != j) + // Does this level have custom translations? + FRemapTable* trans; + int w; + if (arc.isWriting()) { - return false; + auto size = GPalette.NumTranslations(TRANSLATION_User); + for (unsigned int i = 0; i < size; ++i) + { + trans = GPalette.GetTranslation(TRANSLATION_User, i); + if (trans != NULL && !trans->IsIdentity()) + { + if (arc.BeginObject(nullptr)) + { + arc("index", i); + SerializeRemap(arc, *trans); + arc.EndObject(); + } + } + } } - } - return true; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void FRemapTable::KillNative() -{ - if (Native != NULL) - { - delete Native; - Native = NULL; - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void FRemapTable::UpdateNative() -{ - if (Native != NULL) - { - Native->Update(); - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2) -{ - if (IndexOutOfRange(start, end, pal1, pal2)) - { - return false; - } - - double palcol, palstep; - - if (start > end) - { - swapvalues (start, end); - swapvalues (pal1, pal2); - } - else if (start == end) - { - start = GPalette.Remap[start]; - pal1 = GPalette.Remap[pal1]; - Remap[start] = pal1; - Palette[start] = GPalette.BaseColors[pal1]; - Palette[start].a = start == 0 ? 0 : 255; - return true; - } - palcol = pal1; - palstep = (pal2 - palcol) / (end - start); - for (int i = start; i <= end; palcol += palstep, ++i) - { - int j = GPalette.Remap[i], k = GPalette.Remap[int(round(palcol))]; - Remap[j] = k; - Palette[j] = GPalette.BaseColors[k]; - Palette[j].a = j == 0 ? 0 : 255; - } - return true; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, int _r2, int _g2, int _b2) -{ - if (IndexOutOfRange(start, end)) - { - return false; - } - - double r1 = _r1; - double g1 = _g1; - double b1 = _b1; - double r2 = _r2; - double g2 = _g2; - double b2 = _b2; - double r, g, b; - double rs, gs, bs; - - if (start > end) - { - swapvalues (start, end); - r = r2; - g = g2; - b = b2; - rs = r1 - r2; - gs = g1 - g2; - bs = b1 - b2; - } - else - { - r = r1; - g = g1; - b = b1; - rs = r2 - r1; - gs = g2 - g1; - bs = b2 - b1; - } - if (start == end) - { - start = GPalette.Remap[start]; - Palette[start] = PalEntry(start == 0 ? 0 : 255, int(r), int(g), int(b)); - Remap[start] = ColorMatcher.Pick(Palette[start]); - } - else - { - rs /= (end - start); - gs /= (end - start); - bs /= (end - start); - for (int i = start; i <= end; ++i) + else { - int j = GPalette.Remap[i]; - Palette[j] = PalEntry(j == 0 ? 0 : 255, int(r), int(g), int(b)); - Remap[j] = ColorMatcher.Pick(Palette[j]); - r += rs; - g += gs; - b += bs; + while (arc.BeginObject(nullptr)) + { + arc("index", w); + FRemapTable remap; + SerializeRemap(arc, remap); + // do not add the translation to the global list yet. We want to avoid adding tables that are not needed anymore. + usertransmap.Push(std::make_pair(TRANSLATION(TRANSLATION_User, w), remap)); + arc.EndObject(); + } } - } - return true; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool FRemapTable::AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2) -{ - if (IndexOutOfRange(start, end)) - { - return false; - } - - r1 = clamp(r1, 0.0, 2.0); - g1 = clamp(g1, 0.0, 2.0); - b1 = clamp(b1, 0.0, 2.0); - r2 = clamp(r2, 0.0, 2.0); - g2 = clamp(g2, 0.0, 2.0); - b2 = clamp(b2, 0.0, 2.0); - - if (start > end) - { - swapvalues(start, end); - swapvalues(r1, r2); - swapvalues(g1, g2); - swapvalues(b1, b2); - } - - r2 -= r1; - g2 -= g1; - b2 -= b1; - r1 *= 255; - g1 *= 255; - b1 *= 255; - - for(int c = start; c <= end; c++) - { - double intensity = (GPalette.BaseColors[c].r * 77 + - GPalette.BaseColors[c].g * 143 + - GPalette.BaseColors[c].b * 37) / 256.0; - - PalEntry pe = PalEntry( MIN(255, int(r1 + intensity*r2)), - MIN(255, int(g1 + intensity*g2)), - MIN(255, int(b1 + intensity*b2))); - - int cc = GPalette.Remap[c]; - - Remap[cc] = ColorMatcher.Pick(pe); - Palette[cc] = pe; - Palette[cc].a = cc == 0 ? 0:255; - } - return true; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool FRemapTable::AddColourisation(int start, int end, int r, int g, int b) -{ - if (IndexOutOfRange(start, end)) - { - return false; - } - - for (int i = start; i < end; ++i) - { - double br = GPalette.BaseColors[i].r; - double bg = GPalette.BaseColors[i].g; - double bb = GPalette.BaseColors[i].b; - double grey = (br * 0.299 + bg * 0.587 + bb * 0.114) / 255.0f; - if (grey > 1.0) grey = 1.0; - br = r * grey; - bg = g * grey; - bb = b * grey; - - int j = GPalette.Remap[i]; - Palette[j] = PalEntry(j == 0 ? 0 : 255, int(br), int(bg), int(bb)); - Remap[j] = ColorMatcher.Pick(Palette[j]); - } - return true; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool FRemapTable::AddTint(int start, int end, int r, int g, int b, int amount) -{ - if (IndexOutOfRange(start, end)) - { - return false; - } - - for (int i = start; i < end; ++i) - { - float br = GPalette.BaseColors[i].r; - float bg = GPalette.BaseColors[i].g; - float bb = GPalette.BaseColors[i].b; - float a = amount * 0.01f; - float ia = 1.0f - a; - br = br * ia + r * a; - bg = bg * ia + g * a; - bb = bb * ia + b * a; - - int j = GPalette.Remap[i]; - Palette[j] = PalEntry(j == 0 ? 0 : 255, int(br), int(bg), int(bb)); - Remap[j] = ColorMatcher.Pick(Palette[j]); - } - return true; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool FRemapTable::AddToTranslation(const char *range) -{ - int start,end; - bool desaturated = false; - FScanner sc; - - sc.OpenMem("translation", range, int(strlen(range))); - sc.SetCMode(true); - - sc.MustGetToken(TK_IntConst); - start = sc.Number; - sc.MustGetToken(':'); - sc.MustGetToken(TK_IntConst); - end = sc.Number; - sc.MustGetToken('='); - if (start < 0 || start > 255 || end < 0 || end > 255) - { - sc.ScriptError("Palette index out of range"); - return false; - } - - sc.MustGetAnyToken(); - - if (sc.TokenType == '[') - { - // translation using RGB values - int r1,g1,b1,r2,g2,b2; - - sc.MustGetToken(TK_IntConst); - r1 = sc.Number; - sc.MustGetToken(','); - - sc.MustGetToken(TK_IntConst); - g1 = sc.Number; - sc.MustGetToken(','); - - sc.MustGetToken(TK_IntConst); - b1 = sc.Number; - sc.MustGetToken(']'); - sc.MustGetToken(':'); - sc.MustGetToken('['); - - sc.MustGetToken(TK_IntConst); - r2 = sc.Number; - sc.MustGetToken(','); - - sc.MustGetToken(TK_IntConst); - g2 = sc.Number; - sc.MustGetToken(','); - - sc.MustGetToken(TK_IntConst); - b2 = sc.Number; - sc.MustGetToken(']'); - - return AddColorRange(start, end, r1, g1, b1, r2, g2, b2); - } - else if (sc.TokenType == '%') - { - // translation using RGB values - double r1,g1,b1,r2,g2,b2; - - sc.MustGetToken('['); - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - r1 = sc.Float; - sc.MustGetToken(','); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - g1 = sc.Float; - sc.MustGetToken(','); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - b1 = sc.Float; - sc.MustGetToken(']'); - sc.MustGetToken(':'); - sc.MustGetToken('['); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - r2 = sc.Float; - sc.MustGetToken(','); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - g2 = sc.Float; - sc.MustGetToken(','); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - b2 = sc.Float; - sc.MustGetToken(']'); - - return AddDesaturation(start, end, r1, g1, b1, r2, g2, b2); - } - else if (sc.TokenType == '#') - { - // Colourise translation - int r, g, b; - sc.MustGetToken('['); - sc.MustGetToken(TK_IntConst); - r = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - g = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - b = sc.Number; - sc.MustGetToken(']'); - - return AddColourisation(start, end, r, g, b); - } - else if (sc.TokenType == '@') - { - // Tint translation - int a, r, g, b; - - sc.MustGetToken(TK_IntConst); - a = sc.Number; - sc.MustGetToken('['); - sc.MustGetToken(TK_IntConst); - r = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - g = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - b = sc.Number; - sc.MustGetToken(']'); - - return AddTint(start, end, r, g, b, a); - } - else - { - int pal1, pal2; - - sc.TokenMustBe(TK_IntConst); - pal1 = sc.Number; - sc.MustGetToken(':'); - sc.MustGetToken(TK_IntConst); - pal2 = sc.Number; - return AddIndexRange(start, end, pal1, pal2); + arc.EndArray(); } } -//---------------------------------------------------------------------------- -// -// Adds raw colors to a given translation -// -//---------------------------------------------------------------------------- - -bool FRemapTable::AddColors(int start, int count, const uint8_t*colors) +void StaticClearSerializeTranslationsData() { - int end = start + count; - if (IndexOutOfRange(start, end)) - { - return false; - } - - for (int i = start; i < end; ++i) - { - auto br = colors[0]; - auto bg = colors[1]; - auto bb = colors[2]; - colors += 3; - - int j = GPalette.Remap[i]; - Palette[j] = PalEntry(j == 0 ? 0 : 255, br, bg, bb); - Remap[j] = ColorMatcher.Pick(Palette[j]); - } - return true; - + usertransmap.Reset(); } -//---------------------------------------------------------------------------- -// -// Stores a copy of this translation in the DECORATE translation table -// -//---------------------------------------------------------------------------- - -int FRemapTable::StoreTranslation(int slot) +FTranslationID RemapUserTranslation(FTranslationID trans) { - unsigned int i; - - for (i = 0; i < translationtables[slot].Size(); i++) + if (GetTranslationType(trans) == TRANSLATION_User) { - if (*this == *translationtables[slot][i]) + for (auto& check : usertransmap) { - // A duplicate of this translation already exists - return TRANSLATION(slot, i); + if (trans == check.first) + return GPalette.AddTranslation(TRANSLATION_User, &check.second); } } - if (translationtables[slot].Size() >= MAX_DECORATE_TRANSLATIONS) - { - I_Error("Too many DECORATE translations"); - } - FRemapTable *newtrans = new FRemapTable; - *newtrans = *this; - i = translationtables[slot].Push(newtrans); - return TRANSLATION(slot, i); + return trans; } - //---------------------------------------------------------------------------- // // @@ -836,14 +177,14 @@ int FRemapTable::StoreTranslation(int slot) static TArray BloodTranslationColors; -int CreateBloodTranslation(PalEntry color) +FTranslationID CreateBloodTranslation(PalEntry color) { unsigned int i; if (BloodTranslationColors.Size() == 0) { // Don't use the first slot. - translationtables[TRANSLATION_Blood].Push(NULL); + GPalette.PushIdentityTable(TRANSLATION_Blood); BloodTranslationColors.Push(0); } @@ -854,64 +195,27 @@ int CreateBloodTranslation(PalEntry color) color.b == BloodTranslationColors[i].b) { // A duplicate of this translation already exists - return i; + return TRANSLATION(TRANSLATION_Blood, i); } } if (BloodTranslationColors.Size() >= MAX_DECORATE_TRANSLATIONS) { I_Error("Too many blood colors"); } - FRemapTable *trans = new FRemapTable; - trans->Palette[0] = 0; - trans->Remap[0] = 0; + FRemapTable trans; + trans.Palette[0] = 0; + trans.Remap[0] = 0; for (i = 1; i < 256; i++) { - int bright = MAX(MAX(GPalette.BaseColors[i].r, GPalette.BaseColors[i].g), GPalette.BaseColors[i].b); + int bright = max(std::max(GPalette.BaseColors[i].r, GPalette.BaseColors[i].g), GPalette.BaseColors[i].b); PalEntry pe = PalEntry(255, color.r*bright/255, color.g*bright/255, color.b*bright/255); int entry = ColorMatcher.Pick(pe.r, pe.g, pe.b); - trans->Palette[i] = pe; - trans->Remap[i] = entry; - } - translationtables[TRANSLATION_Blood].Push(trans); - return BloodTranslationColors.Push(color); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -FRemapTable *TranslationToTable(int translation) -{ - unsigned int type = GetTranslationType(translation); - unsigned int index = GetTranslationIndex(translation); - TAutoGrowArray *slots; - - if (type <= 0 || type >= NUM_TRANSLATION_TABLES) - { - return NULL; + trans.Palette[i] = pe; + trans.Remap[i] = entry; } - slots = &translationtables[type]; - if (index >= slots->Size()) - { - return NULL; - } - return slots->operator[](index); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -static void PushIdentityTable(int slot) -{ - FRemapTable *table = new FRemapTable; - table->MakeIdentity(); - translationtables[slot].Push(table); + GPalette.AddTranslation(TRANSLATION_Blood, &trans); + return TRANSLATION(TRANSLATION_Blood, BloodTranslationColors.Push(color)); } //---------------------------------------------------------------------------- @@ -932,25 +236,26 @@ void R_InitTranslationTables () // maps until then so they won't be invalid. for (i = 0; i < MAXPLAYERS; ++i) { - PushIdentityTable(TRANSLATION_Players); - PushIdentityTable(TRANSLATION_PlayersExtra); - PushIdentityTable(TRANSLATION_RainPillar); + GPalette.PushIdentityTable(TRANSLATION_Players); + GPalette.PushIdentityTable(TRANSLATION_PlayersExtra); + GPalette.PushIdentityTable(TRANSLATION_RainPillar); } // The menu player also gets a separate translation table - PushIdentityTable(TRANSLATION_Players); + GPalette.PushIdentityTable(TRANSLATION_Players); // The three standard translations from Doom or Heretic (seven for Strife), // plus the generic ice translation. + FRemapTable stdremaps[8]; for (i = 0; i < 8; ++i) { - PushIdentityTable(TRANSLATION_Standard); + stdremaps[i].MakeIdentity(); } // Each player corpse has its own translation so they won't change // color if the player who created them changes theirs. for (i = 0; i < FLevelLocals::BODYQUESIZE; ++i) { - PushIdentityTable(TRANSLATION_PlayerCorpses); + GPalette.PushIdentityTable(TRANSLATION_PlayerCorpses); } // Create the standard translation tables @@ -958,160 +263,91 @@ void R_InitTranslationTables () { for (i = 0x70; i < 0x80; i++) { // map green ramp to gray, brown, red - translationtables[TRANSLATION_Standard][0]->Remap[i] = 0x60 + (i&0xf); - translationtables[TRANSLATION_Standard][1]->Remap[i] = 0x40 + (i&0xf); - translationtables[TRANSLATION_Standard][2]->Remap[i] = 0x20 + (i&0xf); + stdremaps[0].Remap[i] = 0x60 + (i&0xf); + stdremaps[1].Remap[i] = 0x40 + (i&0xf); + stdremaps[2].Remap[i] = 0x20 + (i&0xf); - translationtables[TRANSLATION_Standard][0]->Palette[i] = GPalette.BaseColors[0x60 + (i&0xf)] | MAKEARGB(255,0,0,0); - translationtables[TRANSLATION_Standard][1]->Palette[i] = GPalette.BaseColors[0x40 + (i&0xf)] | MAKEARGB(255,0,0,0); - translationtables[TRANSLATION_Standard][2]->Palette[i] = GPalette.BaseColors[0x20 + (i&0xf)] | MAKEARGB(255,0,0,0); + stdremaps[0].Palette[i] = GPalette.BaseColors[0x60 + (i&0xf)] | MAKEARGB(255,0,0,0); + stdremaps[1].Palette[i] = GPalette.BaseColors[0x40 + (i&0xf)] | MAKEARGB(255,0,0,0); + stdremaps[2].Palette[i] = GPalette.BaseColors[0x20 + (i&0xf)] | MAKEARGB(255,0,0,0); } } else if (gameinfo.gametype == GAME_Heretic) { for (i = 225; i <= 240; i++) { - translationtables[TRANSLATION_Standard][0]->Remap[i] = 114+(i-225); // yellow - translationtables[TRANSLATION_Standard][1]->Remap[i] = 145+(i-225); // red - translationtables[TRANSLATION_Standard][2]->Remap[i] = 190+(i-225); // blue + stdremaps[0].Remap[i] = 114+(i-225); // yellow + stdremaps[1].Remap[i] = 145+(i-225); // red + stdremaps[2].Remap[i] = 190+(i-225); // blue - translationtables[TRANSLATION_Standard][0]->Palette[i] = GPalette.BaseColors[114+(i-225)] | MAKEARGB(255,0,0,0); - translationtables[TRANSLATION_Standard][1]->Palette[i] = GPalette.BaseColors[145+(i-225)] | MAKEARGB(255,0,0,0); - translationtables[TRANSLATION_Standard][2]->Palette[i] = GPalette.BaseColors[190+(i-225)] | MAKEARGB(255,0,0,0); + stdremaps[0].Palette[i] = GPalette.BaseColors[114+(i-225)] | MAKEARGB(255,0,0,0); + stdremaps[1].Palette[i] = GPalette.BaseColors[145+(i-225)] | MAKEARGB(255,0,0,0); + stdremaps[2].Palette[i] = GPalette.BaseColors[190+(i-225)] | MAKEARGB(255,0,0,0); } } else if (gameinfo.gametype == GAME_Strife) { for (i = 0x20; i <= 0x3F; ++i) { - translationtables[TRANSLATION_Standard][0]->Remap[i] = i - 0x20; - translationtables[TRANSLATION_Standard][1]->Remap[i] = i - 0x20; - translationtables[TRANSLATION_Standard][2]->Remap[i] = 0xD0 + (i&0xf); - translationtables[TRANSLATION_Standard][3]->Remap[i] = 0xD0 + (i&0xf); - translationtables[TRANSLATION_Standard][4]->Remap[i] = i - 0x20; - translationtables[TRANSLATION_Standard][5]->Remap[i] = i - 0x20; - translationtables[TRANSLATION_Standard][6]->Remap[i] = i - 0x20; + stdremaps[0].Remap[i] = i - 0x20; + stdremaps[1].Remap[i] = i - 0x20; + stdremaps[2].Remap[i] = 0xD0 + (i&0xf); + stdremaps[3].Remap[i] = 0xD0 + (i&0xf); + stdremaps[4].Remap[i] = i - 0x20; + stdremaps[5].Remap[i] = i - 0x20; + stdremaps[6].Remap[i] = i - 0x20; } for (i = 0x50; i <= 0x5F; ++i) { // Merchant hair - translationtables[TRANSLATION_Standard][4]->Remap[i] = 0x80 + (i&0xf); - translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x10 + (i&0xf); - translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x40 + (i&0xf); + stdremaps[4].Remap[i] = 0x80 + (i&0xf); + stdremaps[5].Remap[i] = 0x10 + (i&0xf); + stdremaps[6].Remap[i] = 0x40 + (i&0xf); } for (i = 0x80; i <= 0x8F; ++i) { - translationtables[TRANSLATION_Standard][0]->Remap[i] = 0x40 + (i&0xf); // red - translationtables[TRANSLATION_Standard][1]->Remap[i] = 0xB0 + (i&0xf); // rust - translationtables[TRANSLATION_Standard][2]->Remap[i] = 0x10 + (i&0xf); // gray - translationtables[TRANSLATION_Standard][3]->Remap[i] = 0x30 + (i&0xf); // dark green - translationtables[TRANSLATION_Standard][4]->Remap[i] = 0x50 + (i&0xf); // gold - translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x60 + (i&0xf); // bright green - translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x90 + (i&0xf); // blue + stdremaps[0].Remap[i] = 0x40 + (i&0xf); // red + stdremaps[1].Remap[i] = 0xB0 + (i&0xf); // rust + stdremaps[2].Remap[i] = 0x10 + (i&0xf); // gray + stdremaps[3].Remap[i] = 0x30 + (i&0xf); // dark green + stdremaps[4].Remap[i] = 0x50 + (i&0xf); // gold + stdremaps[5].Remap[i] = 0x60 + (i&0xf); // bright green + stdremaps[6].Remap[i] = 0x90 + (i&0xf); // blue } for (i = 0xC0; i <= 0xCF; ++i) { - translationtables[TRANSLATION_Standard][4]->Remap[i] = 0xA0 + (i&0xf); - translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x20 + (i&0xf); - translationtables[TRANSLATION_Standard][6]->Remap[i] = (i&0xf); + stdremaps[4].Remap[i] = 0xA0 + (i&0xf); + stdremaps[5].Remap[i] = 0x20 + (i&0xf); + stdremaps[6].Remap[i] = (i&0xf); } - translationtables[TRANSLATION_Standard][6]->Remap[0xC0] = 1; + stdremaps[6].Remap[0xC0] = 1; for (i = 0xD0; i <= 0xDF; ++i) { - translationtables[TRANSLATION_Standard][4]->Remap[i] = 0xB0 + (i&0xf); - translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x30 + (i&0xf); - translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x10 + (i&0xf); + stdremaps[4].Remap[i] = 0xB0 + (i&0xf); + stdremaps[5].Remap[i] = 0x30 + (i&0xf); + stdremaps[6].Remap[i] = 0x10 + (i&0xf); } for (i = 0xF1; i <= 0xF6; ++i) { - translationtables[TRANSLATION_Standard][0]->Remap[i] = 0xDF + (i&0xf); + stdremaps[0].Remap[i] = 0xDF + (i&0xf); } for (i = 0xF7; i <= 0xFB; ++i) { - translationtables[TRANSLATION_Standard][0]->Remap[i] = i - 6; + stdremaps[0].Remap[i] = i - 6; } for (i = 0; i < 7; ++i) { for (int j = 0x20; j <= 0xFB; ++j) { - translationtables[TRANSLATION_Standard][i]->Palette[j] = - GPalette.BaseColors[translationtables[TRANSLATION_Standard][i]->Remap[j]] | MAKEARGB(255,0,0,0); + stdremaps[i].Palette[j] = + GPalette.BaseColors[stdremaps[i].Remap[j]] | MAKEARGB(255,0,0,0); } } } - // Create the ice translation table, based on Hexen's. Alas, the standard - // Doom palette has no good substitutes for these bluish-tinted grays, so - // they will just look gray unless you use a different PLAYPAL with Doom. - - uint8_t IcePaletteRemap[16]; - for (i = 0; i < 16; ++i) - { - IcePaletteRemap[i] = ColorMatcher.Pick (IcePalette[i][0], IcePalette[i][1], IcePalette[i][2]); - } - FRemapTable *remap = translationtables[TRANSLATION_Standard][STD_Ice]; - remap->Remap[0] = 0; - remap->Palette[0] = 0; - for (i = 1; i < 256; ++i) - { - int r = GPalette.BaseColors[i].r; - int g = GPalette.BaseColors[i].g; - int b = GPalette.BaseColors[i].b; - int v = (r*77 + g*143 + b*37) >> 12; - remap->Remap[i] = IcePaletteRemap[v]; - remap->Palette[i] = PalEntry(255, IcePalette[v][0], IcePalette[v][1], IcePalette[v][2]); - } - - // The alphatexture translation. This is just a standard index as gray mapping. - PushIdentityTable(TRANSLATION_Standard); - remap = translationtables[TRANSLATION_Standard][STD_Gray]; - remap->Remap[0] = 0; - remap->Palette[0] = 0; - for (i = 1; i < 256; i++) - { - remap->Remap[i] = i; - remap->Palette[i] = PalEntry(255, i, i, i); - } - - // Palette to grayscale ramp. For internal use only, because the remap does not map to the palette. - PushIdentityTable(TRANSLATION_Standard); - remap = translationtables[TRANSLATION_Standard][STD_Grayscale]; - remap->Remap[0] = 0; - remap->Palette[0] = 0; - for (i = 1; i < 256; i++) - { - int r = GPalette.BaseColors[i].r; - int g = GPalette.BaseColors[i].g; - int b = GPalette.BaseColors[i].b; - int v = (r * 77 + g * 143 + b * 37) >> 8; - - remap->Remap[i] = v; - remap->Palette[i] = PalEntry(255, v, v, v); - } - -} + stdremaps[7] = GPalette.IceMap; // this must also be inserted into the translation manager to be usable by sprites. + GPalette.AddTranslation(TRANSLATION_Standard, stdremaps, 8); -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void R_DeinitTranslationTables() -{ - for (int i = 0; i < NUM_TRANSLATION_TABLES; ++i) - { - for (unsigned int j = 0; j < translationtables[i].Size(); ++j) - { - if (translationtables[i][j] != NULL) - { - delete translationtables[i][j]; - translationtables[i][j] = NULL; - } - } - translationtables[i].Clear(); - } - BloodTranslationColors.Clear(); } //---------------------------------------------------------------------------- @@ -1132,7 +368,7 @@ static void SetRemap(FRemapTable *table, int i, float r, float g, float b) //---------------------------------------------------------------------------- // -// Sets the translation Heretic's the rain pillar +// Sets the translation for Heretic's rain pillar // This tries to create a translation that preserves the brightness of // the rain projectiles so that their effect isn't ruined. // @@ -1198,6 +434,9 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC float sdelta, vdelta; float range; + if (alttable) alttable->MakeIdentity(); + if (pillartable) pillartable->MakeIdentity(); + // Set up the base translation for this skin. If the skin was created // for the current game, then this is just an identity translation. // Otherwise, it remaps the colors from the skin's original palette to @@ -1224,7 +463,6 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC if (start == 0 && end == 0) { table->Inactive = true; - table->UpdateNative(); return; } @@ -1234,7 +472,7 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC bases = s; basev = v; - if (colorset != NULL && colorset->Lump >= 0 && Wads.LumpLength(colorset->Lump) < 256) + if (colorset != NULL && colorset->Lump >= 0 && fileSystem.FileLength(colorset->Lump) < 256) { // Bad table length. Ignore it. colorset = NULL; } @@ -1255,8 +493,8 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC } else { - FMemLump translump = Wads.ReadLump(colorset->Lump); - const uint8_t *trans = (const uint8_t *)translump.GetMem(); + auto translump = fileSystem.ReadFile(colorset->Lump); + auto trans = translump.bytes(); for (i = start; i <= end; ++i) { table->Remap[i] = GPalette.Remap[trans[i]]; @@ -1299,22 +537,6 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC HSVtoRGB (&r, &g, &b, h, s, v); SetRemap(table, i, r, g, b); } - - // Build rain/lifegem translation - if (alttable) - { - bases = MIN (bases*1.3f, 1.f); - basev = MIN (basev*1.3f, 1.f); - for (i = 145; i <= 168; i++) - { - s = MIN (bases, 0.8965f - 0.0962f*(float)(i - 161)); - v = MIN (1.f, (0.2102f + 0.0489f*(float)(i - 144)) * basev); - HSVtoRGB (&r, &g, &b, h, s, v); - SetRemap(alttable, i, r, g, b); - SetPillarRemap(pillartable, i, h, s, v); - } - alttable->UpdateNative(); - } } else if (gameinfo.gametype == GAME_Hexen) { @@ -1325,7 +547,7 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC // Build player sprite translation //h = 45.f; - v = MAX (0.1f, v); + v = max (0.1f, v); for (i = start; i <= end; i++) { @@ -1339,7 +561,7 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC float mv[18] = { .16f, .19f, .22f, .25f, .31f, .35f, .38f, .41f, .47f, .54f, .60f, .65f, .71f, .77f, .83f, .89f, .94f, 1.f }; // Build player sprite translation - v = MAX (0.1f, v); + v = max (0.1f, v); for (i = start; i <= end; i++) { @@ -1348,33 +570,51 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC } } } - if (gameinfo.gametype == GAME_Hexen && alttable != NULL) + + if (alttable != NULL) { - // Build Hexen's lifegem translation. - - // Is the player's translation range the same as the gem's and we are using a - // predefined translation? If so, then use the same one for the gem. Otherwise, - // build one as per usual. - if (colorset != NULL && start == 164 && end == 185) + if (gameinfo.gametype == GAME_Heretic) { - *alttable = *table; + // Build rain/lifegem translation + bases = min(bases * 1.3f, 1.f); + basev = min(basev * 1.3f, 1.f); + for (i = 145; i <= 168; i++) + { + s = min(bases, 0.8965f - 0.0962f * (float)(i - 161)); + v = min(1.f, (0.2102f + 0.0489f * (float)(i - 144)) * basev); + HSVtoRGB(&r, &g, &b, h, s, v); + SetRemap(alttable, i, r, g, b); + SetPillarRemap(pillartable, i, h, s, v); + } } - else + else if (gameinfo.gametype == GAME_Hexen) { - for (i = 164; i <= 185; ++i) + // Build Hexen's lifegem translation. + + // Is the player's translation range the same as the gem's and we are using a + // predefined translation? If so, then use the same one for the gem. Otherwise, + // build one as per usual. + if (colorset != NULL && start == 164 && end == 185) { - const PalEntry *base = &GPalette.BaseColors[i]; - float dummy; + *alttable = *table; + } + else + { + for (i = 164; i <= 185; ++i) + { + const PalEntry* base = &GPalette.BaseColors[i]; + float dummy; - RGBtoHSV (base->r/255.f, base->g/255.f, base->b/255.f, &dummy, &s, &v); - HSVtoRGB (&r, &g, &b, h, s*bases, v*basev); - SetRemap(alttable, i, r, g, b); + RGBtoHSV(base->r / 255.f, base->g / 255.f, base->b / 255.f, &dummy, &s, &v); + HSVtoRGB(&r, &g, &b, h, s * bases, v * basev); + SetRemap(alttable, i, r, g, b); + } } } - alttable->UpdateNative(); } - table->UpdateNative(); -} + + + } //---------------------------------------------------------------------------- // @@ -1389,12 +629,12 @@ void R_BuildPlayerTranslation (int player) D_GetPlayerColor (player, &h, &s, &v, &colorset); - R_CreatePlayerTranslation (h, s, v, colorset, - &Skins[players[player].userinfo.GetSkin()], - translationtables[TRANSLATION_Players][player], - translationtables[TRANSLATION_PlayersExtra][player], - translationtables[TRANSLATION_RainPillar][player] - ); + FRemapTable remaps[3]; + R_CreatePlayerTranslation (h, s, v, colorset, &Skins[players[player].userinfo.GetSkin()], &remaps[0], &remaps[1], &remaps[2]); + + GPalette.UpdateTranslation(TRANSLATION(TRANSLATION_Players, player), &remaps[0]); + GPalette.UpdateTranslation(TRANSLATION(TRANSLATION_PlayersExtra, player), &remaps[1]); + GPalette.UpdateTranslation(TRANSLATION(TRANSLATION_RainPillar, player), &remaps[2]); } //---------------------------------------------------------------------------- @@ -1426,7 +666,7 @@ DEFINE_ACTION_FUNCTION(_Translation, SetPlayerTranslation) PARAM_UINT(pnum); PARAM_POINTER(cls, FPlayerClass); - if (pnum >= MAXPLAYERS || tgroup >= NUM_TRANSLATION_TABLES || tnum >= translationtables[tgroup].Size()) + if (pnum >= MAXPLAYERS || tgroup >= NUM_TRANSLATION_TABLES) { ACTION_RETURN_BOOL(false); } @@ -1437,9 +677,11 @@ DEFINE_ACTION_FUNCTION(_Translation, SetPlayerTranslation) if (cls != nullptr) { - PlayerSkin = R_FindSkin(Skins[PlayerSkin].Name, int(cls - &PlayerClasses[0])); + PlayerSkin = R_FindSkin(Skins[PlayerSkin].Name.GetChars(), int(cls - &PlayerClasses[0])); + FRemapTable remap; R_GetPlayerTranslation(PlayerColor, GetColorSet(cls->Type, PlayerColorset), - &Skins[PlayerSkin], translationtables[tgroup][tnum]); + &Skins[PlayerSkin], &remap); + GPalette.UpdateTranslation(TRANSLATION(tgroup, tnum), &remap); } ACTION_RETURN_BOOL(true); } @@ -1449,18 +691,18 @@ DEFINE_ACTION_FUNCTION(_Translation, SetPlayerTranslation) // // //---------------------------------------------------------------------------- -static TMap customTranslationMap; +static TMap customTranslationMap; -int R_FindCustomTranslation(FName name) +FTranslationID R_FindCustomTranslation(FName name) { - switch (name) + switch (name.GetIndex()) { case NAME_Ice: // Ice is a special case which will remain in its original slot. return TRANSLATION(TRANSLATION_Standard, 7); case NAME_None: - return 0; + return NO_TRANSLATION; case NAME_RainPillar1: case NAME_RainPillar2: @@ -1483,15 +725,8 @@ int R_FindCustomTranslation(FName name) return TRANSLATION(TRANSLATION_Players, name.GetIndex() - NAME_Player1); } - int *t = customTranslationMap.CheckKey(FName(name, true)); - return (t != nullptr)? *t : -1; -} - -DEFINE_ACTION_FUNCTION(_Translation, GetID) -{ - PARAM_PROLOGUE; - PARAM_NAME(t); - ACTION_RETURN_INT(R_FindCustomTranslation(t)); + auto t = customTranslationMap.CheckKey(name); + return (t != nullptr)? *t : INVALID_TRANSLATION; } //---------------------------------------------------------------------------- @@ -1503,11 +738,11 @@ DEFINE_ACTION_FUNCTION(_Translation, GetID) void R_ParseTrnslate() { customTranslationMap.Clear(); - translationtables[TRANSLATION_Custom].Clear(); + GPalette.ClearTranslationSlot(TRANSLATION_Custom); int lump; int lastlump = 0; - while (-1 != (lump = Wads.FindLump("TRNSLATE", &lastlump))) + while (-1 != (lump = fileSystem.FindLump("TRNSLATE", &lastlump))) { FScanner sc(lump); while (sc.GetToken()) @@ -1515,7 +750,7 @@ void R_ParseTrnslate() sc.TokenMustBe(TK_Identifier); FName newtrans = sc.String; - FRemapTable *base = nullptr; + FRemapTable NewTranslation; if (sc.CheckToken(':')) { sc.MustGetAnyToken(); @@ -1526,16 +761,16 @@ void R_ParseTrnslate() { sc.ScriptError("Translation must be in the range [0,%d]", max); } - base = translationtables[TRANSLATION_Standard][sc.Number]; + NewTranslation = *GPalette.GetTranslation(TRANSLATION_Standard, sc.Number); } else if (sc.TokenType == TK_Identifier) { - int tnum = R_FindCustomTranslation(sc.String); - if (tnum == -1) + auto tnum = R_FindCustomTranslation(sc.String); + if (tnum == INVALID_TRANSLATION) { sc.ScriptError("Base translation '%s' not found in '%s'", sc.String, newtrans.GetChars()); } - base = translationtables[GetTranslationType(tnum)][GetTranslationIndex(tnum)]; + NewTranslation = *GPalette.TranslationToTable(tnum.index()); } else { @@ -1543,14 +778,12 @@ void R_ParseTrnslate() sc.TokenMustBe(TK_Identifier); } } - sc.MustGetToken('='); - FRemapTable NewTranslation; - if (base != nullptr) NewTranslation = *base; else NewTranslation.MakeIdentity(); + sc.MustGetToken('='); do { sc.MustGetToken(TK_StringConst); - int pallump = Wads.CheckNumForFullName(sc.String, true, ns_global); + int pallump = fileSystem.CheckNumForFullName(sc.String, true, FileSys::ns_global); if (pallump >= 0) // { int start = 0; @@ -1576,7 +809,7 @@ void R_ParseTrnslate() } } while (sc.CheckToken(',')); - int trans = NewTranslation.StoreTranslation(TRANSLATION_Custom); + auto trans = GPalette.StoreTranslation(TRANSLATION_Custom, &NewTranslation); customTranslationMap[newtrans] = trans; } } @@ -1603,7 +836,7 @@ DEFINE_ACTION_FUNCTION(_Translation, AddTranslation) { NewTranslation.Remap[i] = ColorMatcher.Pick(self->colors[i]); } - int trans = NewTranslation.StoreTranslation(TRANSLATION_Custom); - ACTION_RETURN_INT(trans); + auto trans = GPalette.StoreTranslation(TRANSLATION_User, &NewTranslation); + ACTION_RETURN_INT(trans.index()); } diff --git a/src/r_data/r_translate.h b/src/r_data/r_translate.h index 7f57e680d1d..549f4b3a031 100644 --- a/src/r_data/r_translate.h +++ b/src/r_data/r_translate.h @@ -3,13 +3,13 @@ #include "doomtype.h" #include "tarray.h" +#include "palettecontainer.h" class FSerializer; enum { - TRANSLATION_Invalid, - TRANSLATION_Players, + TRANSLATION_Players = 1, TRANSLATION_PlayersExtra, TRANSLATION_Standard, TRANSLATION_LevelScripted, @@ -19,207 +19,35 @@ enum TRANSLATION_Blood, TRANSLATION_RainPillar, TRANSLATION_Custom, - TRANSLATION_Font, + TRANSLATION_User, NUM_TRANSLATION_TABLES }; + enum EStandardTranslations { STD_Ice = 7, - STD_Gray = 8, // a 0-255 gray ramp - STD_Grayscale = 9, // desaturated version of the palette. -}; - -struct FRemapTable; - -class FUniquePalette -{ - friend struct FRemapTable; - struct PalData - { - int crc32; - PalEntry pe[256]; - }; - static TArray AllPalettes; - - int Index; - FRemapTable *remap; - - FUniquePalette(FRemapTable *r) { remap = r; Index = -1; } - -public: - - static PalEntry *GetPalette(unsigned int index) - { - return index > 0 && index <= AllPalettes.Size() ? AllPalettes[index - 1].pe : NULL; - } - bool Update(); - int GetIndex() const { return Index; } -}; - - -struct FRemapTable -{ - FRemapTable(int count=256); - FRemapTable(const FRemapTable &o); - ~FRemapTable(); - - FRemapTable &operator= (const FRemapTable &o); - bool operator==(const FRemapTable &o); - void MakeIdentity(); - void KillNative(); - void UpdateNative(); - bool IsIdentity() const; - void Serialize(FSerializer &arc); - static void StaticSerializeTranslations(FSerializer &arc); - bool AddIndexRange(int start, int end, int pal1, int pal2); - bool AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2); - bool AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2); - bool AddColourisation(int start, int end, int r, int g, int b); - bool AddTint(int start, int end, int r, int g, int b, int amount); - bool AddToTranslation(const char * range); - bool AddColors(int start, int count, const uint8_t*); - int StoreTranslation(int slot); - int GetUniqueIndex(); - - uint8_t *Remap; // For the software renderer - PalEntry *Palette; // The ideal palette this maps to - FUniquePalette *Native; // The index into the list of unique palettes (this is to avoid frequent texture recreation with changing ACS translations) - int NumEntries; // # of elements in this table (usually 256) - bool Inactive; // This table is inactive and should be treated as if it was passed as NULL - -private: - void Free(); - void Alloc(int count); }; -// A class that initializes unusued pointers to NULL. This is used so that when -// the TAutoGrowArray below is expanded, the new elements will be NULLed. -class FRemapTablePtr -{ -public: - FRemapTablePtr() throw() : Ptr(0) {} - FRemapTablePtr(FRemapTable *p) throw() : Ptr(p) {} - FRemapTablePtr(const FRemapTablePtr &p) throw() : Ptr(p.Ptr) {} - operator FRemapTable *() const throw() { return Ptr; } - FRemapTablePtr &operator= (FRemapTable *p) throw() { Ptr = p; return *this; } - FRemapTablePtr &operator= (FRemapTablePtr &p) throw() { Ptr = p.Ptr; return *this; } - FRemapTable &operator*() const throw() { return *Ptr; } - FRemapTable *operator->() const throw() { return Ptr; } -private: - FRemapTable *Ptr; -}; - -extern TAutoGrowArray translationtables[NUM_TRANSLATION_TABLES]; - -#define TRANSLATION_SHIFT 16 -#define TRANSLATION_MASK ((1<> TRANSLATION_SHIFT; -} -inline int GetTranslationIndex(uint32_t trans) -{ - return (trans&TRANSLATION_MASK); -} -// Retrieve the FRemapTable that an actor's translation value maps to. -FRemapTable *TranslationToTable(int translation); - #define MAX_ACS_TRANSLATIONS 65535 #define MAX_DECORATE_TRANSLATIONS 65535 // Initialize color translation tables, for player rendering etc. void R_InitTranslationTables (void); -void R_DeinitTranslationTables(); void R_BuildPlayerTranslation (int player); // [RH] Actually create a player's translation table. void R_GetPlayerTranslation (int color, const struct FPlayerColorSet *colorset, class FPlayerSkin *skin, struct FRemapTable *table); -extern const uint8_t IcePalette[16][3]; +FTranslationID CreateBloodTranslation(PalEntry color); -int CreateBloodTranslation(PalEntry color); - -int R_FindCustomTranslation(FName name); +FTranslationID R_FindCustomTranslation(FName name); void R_ParseTrnslate(); -struct TextureManipulation -{ - enum - { - BlendNone = 0, - BlendAlpha = 1, - BlendScreen = 2, - BlendOverlay = 3, - BlendHardLight = 4, - BlendMask = 7, - InvertBit = 8, - ActiveBit = 16, // Must be set for the shader to do something - }; - PalEntry AddColor; // Alpha contains the blend flags - PalEntry ModulateColor; // Alpha may contain a multiplier to get higher values than 1.0 without promoting this to 4 full floats. - PalEntry BlendColor; - float DesaturationFactor; - - bool CheckIfEnabled() // check if this manipulation is doing something. NoOps do not need to be preserved, unless they override older setttings. - { - if (AddColor != 0 || // this includes a check for the blend mode without which BlendColor is not active - ModulateColor != 0x01ffffff || // 1 in alpha must be the default for a no-op. - DesaturationFactor != 0) - { - AddColor.a |= ActiveBit; // mark as active for the shader's benefit. - return true; - } - return false; - } - - void SetTextureModulateColor(int slot, PalEntry rgb) - { - rgb.a = ModulateColor.a; - ModulateColor = rgb; - } - - void SetTextureModulateScaleFactor(int slot, int fac) - { - ModulateColor.a = (uint8_t)fac; - } - - void SetTextureAdditiveColor(int slot, PalEntry rgb) - { - rgb.a = AddColor.a; - AddColor = rgb; - } - - void SetTextureBlendColor(int slot, PalEntry rgb) - { - BlendColor = rgb; - } - - void SetTextureDesaturationFactor(int slot, double fac) - { - DesaturationFactor = (float)fac; - } - - void SetTextureBlendMode(int slot, int mode) - { - AddColor.a = (AddColor.a & ~TextureManipulation::BlendMask) | (mode & TextureManipulation::BlendMask); - } - - void SetTextureInvert(bool on) - { - AddColor.a |= TextureManipulation::InvertBit; - AddColor.a &= ~TextureManipulation::InvertBit; - } - -}; - - +// serialization stuff. +void StaticSerializeTranslations(FSerializer& arc); +void StaticClearSerializeTranslationsData(); +FTranslationID RemapUserTranslation(FTranslationID trans); #endif // __R_TRANSLATE_H diff --git a/src/r_data/r_vanillatrans.cpp b/src/r_data/r_vanillatrans.cpp index 00f628cf0c1..f63d7ee3284 100644 --- a/src/r_data/r_vanillatrans.cpp +++ b/src/r_data/r_vanillatrans.cpp @@ -36,9 +36,9 @@ ** **/ -#include "templates.h" + #include "c_cvars.h" -#include "w_wad.h" +#include "filesystem.h" #include "doomtype.h" #ifdef _DEBUG #include "c_dispatch.h" @@ -74,13 +74,13 @@ bool UseVanillaTransparency() if (firstTime) { int lastlump = 0; - Wads.FindLump("ZSCRIPT", &lastlump); // ignore first ZScript - if (Wads.FindLump("ZSCRIPT", &lastlump) == -1) // no loaded ZScript + fileSystem.FindLump("ZSCRIPT", &lastlump); // ignore first ZScript + if (fileSystem.FindLump("ZSCRIPT", &lastlump) == -1) // no loaded ZScript { lastlump = 0; - foundDehacked = Wads.FindLump("DEHACKED", &lastlump) != -1; + foundDehacked = fileSystem.FindLump("DEHACKED", &lastlump) != -1; lastlump = 0; - foundDecorate = Wads.FindLump("DECORATE", &lastlump) != -1; + foundDecorate = fileSystem.FindLump("DECORATE", &lastlump) != -1; foundZScript = false; } else diff --git a/src/r_data/r_vanillatrans.h b/src/r_data/r_vanillatrans.h index 702fc82123e..d6b6a5d9ee8 100644 --- a/src/r_data/r_vanillatrans.h +++ b/src/r_data/r_vanillatrans.h @@ -30,6 +30,7 @@ **--------------------------------------------------------------------------- ** */ +#pragma once void UpdateVanillaTransparency(); diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 2bab7627765..0a7be96a120 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -22,7 +22,7 @@ #include "doomtype.h" -#include "w_wad.h" +#include "filesystem.h" #include "s_sound.h" #include "d_player.h" @@ -31,10 +31,12 @@ #include "c_dispatch.h" #include "v_text.h" #include "r_data/sprites.h" -#include "r_data/voxels.h" +#include "voxels.h" #include "vm.h" +#include "texturemanager.h" void InitModels(); +void R_InitVoxels(); // variables used to look up // and range check thing_t sprites patches @@ -75,19 +77,19 @@ FTextureID spritedef_t::GetSpriteFrame(int frame, int rot, DAngle ang, bool *mir { if ((sprframe->Texture[0] == sprframe->Texture[1]) && flipagain) { - rot = (360.0 - ang + 45.0 / 2 * 9).BAMs() >> 28; + rot = (- ang + DAngle::fromDeg(360.0 + 45.0 / 2 * 9)).BAMs() >> 28; } else if (sprframe->Texture[0] == sprframe->Texture[1]) { - rot = (ang + 45.0 / 2 * 9).BAMs() >> 28; + rot = (ang + DAngle::fromDeg(45.0 / 2 * 9)).BAMs() >> 28; } else if (flipagain) { - rot = (360.0 - ang + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + rot = (- ang + DAngle::fromDeg(360.0 + (45.0 / 2 * 9 - 180.0 / 16))).BAMs() >> 28; } else { - rot = (ang + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + rot = (ang + DAngle::fromDeg(45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; } } if (mirror) *mirror = !!(sprframe->Flip&(1 << rot)); @@ -122,7 +124,7 @@ static bool R_InstallSpriteLump (FTextureID lump, unsigned frame, char rot, bool if (frame >= MAX_SPRITE_FRAMES || rotation > 16) { - Printf (TEXTCOLOR_RED "R_InstallSpriteLump: Bad frame characters in lump %s\n", TexMan.GetTexture(lump)->GetName().GetChars()); + Printf (TEXTCOLOR_RED "R_InstallSpriteLump: Bad frame characters in lump %s\n", TexMan.GetGameTexture(lump)->GetName().GetChars()); return false; } @@ -286,7 +288,7 @@ void R_InstallSprite (int num, spriteframewithrotate *sprtemp, int &maxframe) { for (int rot = 0; rot < 16; ++rot) { - TexMan.GetTexture(sprtemp[frame].Texture[rot])->Rotations = framestart + frame; + TexMan.GetGameTexture(sprtemp[frame].Texture[rot])->SetRotations(framestart + frame); } } } @@ -308,7 +310,7 @@ void R_InstallSprite (int num, spriteframewithrotate *sprtemp, int &maxframe) // letter/number appended. // The rotation character can be 0 to signify no rotations. // -#define TEX_DWNAME(tex) MAKE_ID(tex->Name[0], tex->Name[1], tex->Name[2], tex->Name[3]) +#define TEX_DWNAME(tex) MAKE_ID(tex->GetName()[0], tex->GetName()[1], tex->GetName()[2], tex->GetName()[3]) void R_InitSpriteDefs () { @@ -332,8 +334,8 @@ void R_InitSpriteDefs () memset(hashes.Data(), -1, sizeof(Hasher)*smax); for (i = 0; i < smax; ++i) { - FTexture *tex = TexMan.ByIndex(i); - if (tex->UseType == ETextureType::Sprite && strlen(tex->Name) >= 6) + auto tex = TexMan.GameByIndex(i); + if (tex->GetUseType() == ETextureType::Sprite && strlen(tex->GetName().GetChars()) >= 6) { size_t bucket = TEX_DWNAME(tex) % smax; hashes[i].Next = hashes[bucket].Head; @@ -342,20 +344,18 @@ void R_InitSpriteDefs () } // Repeat, for voxels - vmax = Wads.GetNumLumps(); + vmax = fileSystem.GetNumEntries(); TArray vhashes(vmax, true); memset(vhashes.Data(), -1, sizeof(VHasher)*vmax); for (i = 0; i < vmax; ++i) { - if (Wads.GetLumpNamespace(i) == ns_voxels) + if (fileSystem.GetFileNamespace(i) == FileSys::ns_voxels) { - char name[9]; size_t namelen; int spin; int sign; - Wads.GetLumpName(name, i); - name[8] = 0; + const char* name = fileSystem.GetFileShortName(i); namelen = strlen(name); if (namelen < 4) { // name is too short @@ -414,13 +414,13 @@ void R_InitSpriteDefs () int hash = hashes[intname % smax].Head; while (hash != -1) { - FTexture *tex = TexMan.GetTexture(hash); + auto tex = TexMan.GetGameTexture(hash); if (TEX_DWNAME(tex) == intname) { - bool res = R_InstallSpriteLump (FTextureID(hash), tex->Name[4] - 'A', tex->Name[5], false, sprtemp, maxframe); + bool res = R_InstallSpriteLump (FTextureID(hash), tex->GetName()[4] - 'A', tex->GetName()[5], false, sprtemp, maxframe); - if (tex->Name[6] && res) - R_InstallSpriteLump (FTextureID(hash), tex->Name[6] - 'A', tex->Name[7], true, sprtemp, maxframe); + if (tex->GetName()[6] && res) + R_InstallSpriteLump (FTextureID(hash), tex->GetName()[6] - 'A', tex->GetName()[7], true, sprtemp, maxframe); } hash = hashes[hash].Next; } @@ -450,7 +450,7 @@ void R_InitSpriteDefs () { // voxel applies to a specific frame j = vh->Frame - 'A'; sprtemp[j].Voxel = voxdef; - maxframe = MAX(maxframe, j); + maxframe = max(maxframe, j); } } } @@ -571,7 +571,7 @@ void R_InitSkins (void) unsigned i; int j, k, base; int lastlump; - int aliasid; + FSoundID aliasid; bool remove; PClassActor *basetype, *transtype; @@ -581,20 +581,20 @@ void R_InitSkins (void) for (j = 0; j < NUMSKINSOUNDS; ++j) { - playersoundrefs[j] = skinsoundnames[j][1]; + playersoundrefs[j] = S_FindSound(skinsoundnames[j][1]); } - while ((base = Wads.FindLump ("S_SKIN", &lastlump, true)) != -1) + while ((base = fileSystem.FindLump ("S_SKIN", &lastlump, true)) != -1) { // The player sprite has 23 frames. This means that the S_SKIN // marker needs a minimum of 23 lumps after it. - if (base >= Wads.GetNumLumps() - 23 || base == -1) + if (base >= fileSystem.GetNumEntries() - 23 || base == -1) continue; i++; for (j = 0; j < NUMSKINSOUNDS; j++) sndlumps[j] = -1; - Skins[i].namespc = Wads.GetLumpNamespace (base); + Skins[i].namespc = fileSystem.GetFileNamespace (base); FScanner sc(base); intname = 0; @@ -649,7 +649,7 @@ void R_InitSkins (void) } else if (0 == stricmp (key, "scale")) { - Skins[i].Scale.X = clamp(atof (sc.String), 1./65536, 256.); + Skins[i].Scale.X = clamp((float)atof (sc.String), 1.f/65536, 256.f); Skins[i].Scale.Y = Skins[i].Scale.X; } else if (0 == stricmp (key, "game")) @@ -712,29 +712,29 @@ void R_InitSkins (void) } else if (key[0] == '*') { // Player sound replacment (ZDoom extension) - int lump = Wads.CheckNumForName (sc.String, Skins[i].namespc); + int lump = fileSystem.CheckNumForName (sc.String, Skins[i].namespc); if (lump == -1) { - lump = Wads.CheckNumForFullName (sc.String, true, ns_sounds); + lump = fileSystem.CheckNumForFullName (sc.String, true, FileSys::ns_sounds); } if (lump != -1) { if (stricmp (key, "*pain") == 0) { // Replace all pain sounds in one go - aliasid = S_AddPlayerSound (Skins[i].Name, Skins[i].gender, + aliasid = S_AddPlayerSound (Skins[i].Name.GetChars(), Skins[i].gender, playersoundrefs[0], lump, true); for (int l = 3; l > 0; --l) { - S_AddPlayerSoundExisting (Skins[i].Name, Skins[i].gender, + S_AddPlayerSoundExisting (Skins[i].Name.GetChars(), Skins[i].gender, playersoundrefs[l], aliasid, true); } } else { - int sndref = soundEngine->FindSoundNoHash (key); - if (sndref != 0) + auto sndref = soundEngine->FindSoundNoHash (key); + if (sndref.isvalid()) { - S_AddPlayerSound (Skins[i].Name, Skins[i].gender, sndref, lump, true); + S_AddPlayerSound (Skins[i].Name.GetChars(), Skins[i].gender, sndref, lump, true); } } } @@ -745,10 +745,10 @@ void R_InitSkins (void) { if (stricmp (key, skinsoundnames[j][0]) == 0) { - sndlumps[j] = Wads.CheckNumForName (sc.String, Skins[i].namespc); + sndlumps[j] = fileSystem.CheckNumForName (sc.String, Skins[i].namespc); if (sndlumps[j] == -1) { // Replacement not found, try finding it in the global namespace - sndlumps[j] = Wads.CheckNumForFullName (sc.String, true, ns_sounds); + sndlumps[j] = fileSystem.CheckNumForFullName (sc.String, true, FileSys::ns_sounds); } } } @@ -810,12 +810,10 @@ void R_InitSkins (void) // specified, use whatever immediately follows the specifier lump. if (intname == 0) { - char name[9]; - Wads.GetLumpName (name, base+1); - memcpy(&intname, name, 4); + memcpy(&intname, fileSystem.GetFileShortName(base + 1), 4); } - int basens = Wads.GetLumpNamespace(base); + int basens = fileSystem.GetFileNamespace(base); for(int spr = 0; spr<2; spr++) { @@ -841,11 +839,10 @@ void R_InitSkins (void) } } - for (k = base + 1; Wads.GetLumpNamespace(k) == basens; k++) + for (k = base + 1; fileSystem.GetFileNamespace(k) == basens; k++) { - char lname[9]; + const char* lname = fileSystem.GetFileShortName(k); uint32_t lnameint; - Wads.GetLumpName (lname, k); memcpy(&lnameint, lname, 4); if (lnameint == intname) { @@ -864,7 +861,7 @@ void R_InitSkins (void) break; } - Wads.GetLumpName (temp.name, base+1); + memcpy(temp.name, fileSystem.GetFileShortName (base+1), 4); temp.name[4] = 0; int sprno = (int)sprites.Push (temp); if (spr==0) Skins[i].sprite = sprno; @@ -884,19 +881,19 @@ void R_InitSkins (void) } // Register any sounds this skin provides - aliasid = 0; + aliasid = NO_SOUND; for (j = 0; j < NUMSKINSOUNDS; j++) { if (sndlumps[j] != -1) { if (j == 0 || sndlumps[j] != sndlumps[j-1]) { - aliasid = S_AddPlayerSound (Skins[i].Name, Skins[i].gender, + aliasid = S_AddPlayerSound (Skins[i].Name.GetChars(), Skins[i].gender, playersoundrefs[j], sndlumps[j], true); } else { - S_AddPlayerSoundExisting (Skins[i].Name, Skins[i].gender, + S_AddPlayerSoundExisting (Skins[i].Name.GetChars(), Skins[i].gender, playersoundrefs[j], aliasid, true); } } @@ -949,8 +946,8 @@ CCMD (skins) static void R_CreateSkinTranslation (const char *palname) { - FMemLump lump = Wads.ReadLump (palname); - const uint8_t *otherPal = (uint8_t *)lump.GetMem(); + auto lump = fileSystem.ReadFile (palname); + auto otherPal = lump.bytes(); for (int i = 0; i < 256; ++i) { @@ -984,7 +981,7 @@ void R_InitSprites () // [RH] Count the number of skins. numskins = PlayerClasses.Size (); lastlump = 0; - while ((lump = Wads.FindLump ("S_SKIN", &lastlump, true)) != -1) + while ((lump = fileSystem.FindLump ("S_SKIN", &lastlump, true)) != -1) { numskins++; } @@ -1014,12 +1011,12 @@ void R_InitSprites () Skins[i].Name = "Base"; auto face = basetype->NameVar(NAME_Face); - Skins[i].Face = face == NAME_None? FName("STF") : face; + Skins[i].Face = face == NAME_None? "STF" : face.GetChars(); Skins[i].range0start = basetype->IntVar(NAME_ColorRangeStart); Skins[i].range0end = basetype->IntVar(NAME_ColorRangeEnd); Skins[i].Scale = basetype->Scale; Skins[i].sprite = basetype->SpawnState->sprite; - Skins[i].namespc = ns_global; + Skins[i].namespc = FileSys::ns_global; PlayerClasses[i].Skins.Push (i); diff --git a/src/r_data/v_palette.cpp b/src/r_data/v_palette.cpp index 4135fab129d..8af454445db 100644 --- a/src/r_data/v_palette.cpp +++ b/src/r_data/v_palette.cpp @@ -34,379 +34,44 @@ #include "g_level.h" -#ifdef _WIN32 -#include -#else -#define O_BINARY 0 -#endif -#include "templates.h" #include "v_video.h" -#include "w_wad.h" +#include "filesystem.h" #include "i_video.h" #include "c_dispatch.h" #include "st_stuff.h" -#include "x86.h" #include "g_levellocals.h" #include "m_png.h" +#include "v_colortables.h" -uint32_t Col2RGB8[65][256]; -uint32_t *Col2RGB8_LessPrecision[65]; -uint32_t Col2RGB8_Inverse[65][256]; -uint32_t Col2RGB8_2[63][256]; // this array's second dimension is called up by pointer as Col2RGB8_LessPrecision[] elsewhere. -ColorTable32k RGB32k; -ColorTable256k RGB256k; - -FPalette GPalette; -FColorMatcher ColorMatcher; +using namespace FileSys; /* Current color blending values */ int BlendR, BlendG, BlendB, BlendA; -static int sortforremap (const void *a, const void *b); -static int sortforremap2 (const void *a, const void *b); - -/**************************/ -/* Gamma correction stuff */ -/**************************/ - -uint8_t newgamma[256]; -CUSTOM_CVAR (Float, Gamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (self == 0.f) - { // Gamma values of 0 are illegal. - self = 1.f; - return; - } - - if (screen != NULL) - { - screen->SetGamma (); - } -} - -CCMD (bumpgamma) -{ - // [RH] Gamma correction tables are now generated on the fly for *any* gamma level - // Q: What are reasonable limits to use here? - - float newgamma = Gamma + 0.1f; - - if (newgamma > 3.0) - newgamma = 1.0; - - Gamma = newgamma; - Printf ("Gamma correction level %g\n", *Gamma); -} - - - - - - -FPalette::FPalette () -{ -} - -FPalette::FPalette (const uint8_t *colors) -{ - SetPalette (colors); -} - -void FPalette::SetPalette (const uint8_t *colors) -{ - for (int i = 0; i < 256; i++, colors += 3) - { - BaseColors[i] = PalEntry (colors[0], colors[1], colors[2]); - Remap[i] = i; - } - - // Find white and black from the original palette so that they can be - // used to make an educated guess of the translucency % for a BOOM - // translucency map. - WhiteIndex = BestColor ((uint32_t *)BaseColors, 255, 255, 255, 0, 255); - BlackIndex = BestColor ((uint32_t *)BaseColors, 0, 0, 0, 0, 255); -} - -// In ZDoom's new texture system, color 0 is used as the transparent color. -// But color 0 is also a valid color for Doom engine graphics. What to do? -// Simple. The default palette for every game has at least one duplicate -// color, so find a duplicate pair of palette entries, make one of them a -// duplicate of color 0, and remap every graphic so that it uses that entry -// instead of entry 0. -void FPalette::MakeGoodRemap () -{ - PalEntry color0 = BaseColors[0]; - int i; - - // First try for an exact match of color 0. Only Hexen does not have one. - for (i = 1; i < 256; ++i) - { - if (BaseColors[i] == color0) - { - Remap[0] = i; - break; - } - } - - // If there is no duplicate of color 0, find the first set of duplicate - // colors and make one of them a duplicate of color 0. In Hexen's PLAYPAL - // colors 209 and 229 are the only duplicates, but we cannot assume - // anything because the player might be using a custom PLAYPAL where those - // entries are not duplicates. - if (Remap[0] == 0) - { - PalEntry sortcopy[256]; - - for (i = 0; i < 256; ++i) - { - sortcopy[i] = BaseColors[i] | (i << 24); - } - qsort (sortcopy, 256, 4, sortforremap); - for (i = 255; i > 0; --i) - { - if ((sortcopy[i] & 0xFFFFFF) == (sortcopy[i-1] & 0xFFFFFF)) - { - int new0 = sortcopy[i].a; - int dup = sortcopy[i-1].a; - if (new0 > dup) - { - // Make the lower-numbered entry a copy of color 0. (Just because.) - swapvalues (new0, dup); - } - Remap[0] = new0; - Remap[new0] = dup; - BaseColors[new0] = color0; - break; - } - } - } - - // If there were no duplicates, InitPalette() will remap color 0 to the - // closest matching color. Hopefully nobody will use a palette where all - // 256 entries are different. :-) -} - -static int sortforremap (const void *a, const void *b) -{ - return (*(const uint32_t *)a & 0xFFFFFF) - (*(const uint32_t *)b & 0xFFFFFF); -} - -struct RemappingWork -{ - uint32_t Color; - uint8_t Foreign; // 0 = local palette, 1 = foreign palette - uint8_t PalEntry; // Entry # in the palette - uint8_t Pad[2]; -}; - -void FPalette::MakeRemap (const uint32_t *colors, uint8_t *remap, const uint8_t *useful, int numcolors) const -{ - RemappingWork workspace[255+256]; - int i, j, k; - - // Fill in workspace with the colors from the passed palette and this palette. - // By sorting this array, we can quickly find exact matches so that we can - // minimize the time spent calling BestColor for near matches. - - for (i = 1; i < 256; ++i) - { - workspace[i-1].Color = uint32_t(BaseColors[i]) & 0xFFFFFF; - workspace[i-1].Foreign = 0; - workspace[i-1].PalEntry = i; - } - for (i = k = 0, j = 255; i < numcolors; ++i) - { - if (useful == NULL || useful[i] != 0) - { - workspace[j].Color = colors[i] & 0xFFFFFF; - workspace[j].Foreign = 1; - workspace[j].PalEntry = i; - ++j; - ++k; - } - else - { - remap[i] = 0; - } - } - qsort (workspace, j, sizeof(RemappingWork), sortforremap2); - - // Find exact matches - --j; - for (i = 0; i < j; ++i) - { - if (workspace[i].Foreign) - { - if (!workspace[i+1].Foreign && workspace[i].Color == workspace[i+1].Color) - { - remap[workspace[i].PalEntry] = workspace[i+1].PalEntry; - workspace[i].Foreign = 2; - ++i; - --k; - } - } - } - // Find near matches - if (k > 0) - { - for (i = 0; i <= j; ++i) - { - if (workspace[i].Foreign == 1) - { - remap[workspace[i].PalEntry] = BestColor ((uint32_t *)BaseColors, - RPART(workspace[i].Color), GPART(workspace[i].Color), BPART(workspace[i].Color), - 1, 255); - } - } - } -} -static int sortforremap2 (const void *a, const void *b) +void InitPalette () { - const RemappingWork *ap = (const RemappingWork *)a; - const RemappingWork *bp = (const RemappingWork *)b; - - if (ap->Color == bp->Color) - { - return bp->Foreign - ap->Foreign; - } - else - { - return ap->Color - bp->Color; - } -} + uint8_t pal[768]; + + ReadPalette(fileSystem.GetNumForName("PLAYPAL"), pal); -int ReadPalette(int lumpnum, uint8_t *buffer) -{ - if (lumpnum < 0) - { - return 0; - } - FMemLump lump = Wads.ReadLump(lumpnum); - uint8_t *lumpmem = (uint8_t*)lump.GetMem(); - memset(buffer, 0, 768); + GPalette.Init(NUM_TRANSLATION_TABLES, nullptr); + GPalette.SetPalette (pal, -1); - FileReader fr; - fr.OpenMemory(lumpmem, lump.GetSize()); - auto png = M_VerifyPNG(fr); - if (png) - { - uint32_t id, len; - fr.Seek(33, FileReader::SeekSet); - fr.Read(&len, 4); - fr.Read(&id, 4); - bool succeeded = false; - while (id != MAKE_ID('I', 'D', 'A', 'T') && id != MAKE_ID('I', 'E', 'N', 'D')) - { - len = BigLong((unsigned int)len); - if (id != MAKE_ID('P', 'L', 'T', 'E')) - fr.Seek(len, FileReader::SeekCur); - else - { - int PaletteSize = MIN(len, 768); - fr.Read(buffer, PaletteSize); - return PaletteSize / 3; - } - fr.Seek(4, FileReader::SeekCur); // Skip CRC - fr.Read(&len, 4); - id = MAKE_ID('I', 'E', 'N', 'D'); - fr.Read(&id, 4); - } - I_Error("%s contains no palette", Wads.GetLumpFullName(lumpnum)); - } - if (memcmp(lumpmem, "JASC-PAL", 8) == 0) + int lump = fileSystem.CheckNumForName("COLORMAP"); + if (lump == -1) lump = fileSystem.CheckNumForName("COLORMAP", ns_colormaps); + if (lump != -1) { - FScanner sc; - - sc.OpenMem(Wads.GetLumpFullName(lumpnum), (char*)lumpmem, int(lump.GetSize())); - sc.MustGetString(); - sc.MustGetNumber(); // version - ignore - sc.MustGetNumber(); - int colors = MIN(256, sc.Number) * 3; - for (int i = 0; i < colors; i++) - { - sc.MustGetNumber(); - if (sc.Number < 0 || sc.Number > 255) - { - sc.ScriptError("Color %d value out of range.", sc.Number); - } - buffer[i] = sc.Number; - } - return colors / 3; + FileData cmap = fileSystem.ReadFile(lump); + auto cmapdata = cmap.bytes(); + GPalette.GenerateGlobalBrightmapFromColormap(cmapdata, 32); + MakeGoodRemap((uint32_t*)GPalette.BaseColors, GPalette.Remap, cmapdata + 7936); // last entry in colormap } else - { - memcpy(buffer, lumpmem, MIN(768, lump.GetSize())); - return 256; - } -} + MakeGoodRemap ((uint32_t*)GPalette.BaseColors, GPalette.Remap); -//========================================================================== -// -// BuildTransTable -// -// Build the tables necessary for blending -// -//========================================================================== - -static void BuildTransTable (const PalEntry *palette) -{ - int r, g, b; - - // create the RGB555 lookup table - for (r = 0; r < 32; r++) - for (g = 0; g < 32; g++) - for (b = 0; b < 32; b++) - RGB32k.RGB[r][g][b] = ColorMatcher.Pick ((r<<3)|(r>>2), (g<<3)|(g>>2), (b<<3)|(b>>2)); - // create the RGB666 lookup table - for (r = 0; r < 64; r++) - for (g = 0; g < 64; g++) - for (b = 0; b < 64; b++) - RGB256k.RGB[r][g][b] = ColorMatcher.Pick ((r<<2)|(r>>4), (g<<2)|(g>>4), (b<<2)|(b>>4)); - - int x, y; - - // create the swizzled palette - for (x = 0; x < 65; x++) - for (y = 0; y < 256; y++) - Col2RGB8[x][y] = (((palette[y].r*x)>>4)<<20) | - ((palette[y].g*x)>>4) | - (((palette[y].b*x)>>4)<<10); - - // create the swizzled palette with the lsb of red and blue forced to 0 - // (for green, a 1 is okay since it never gets added into) - for (x = 1; x < 64; x++) - { - Col2RGB8_LessPrecision[x] = Col2RGB8_2[x-1]; - for (y = 0; y < 256; y++) - { - Col2RGB8_2[x-1][y] = Col2RGB8[x][y] & 0x3feffbff; - } - } - Col2RGB8_LessPrecision[0] = Col2RGB8[0]; - Col2RGB8_LessPrecision[64] = Col2RGB8[64]; - - // create the inverse swizzled palette - for (x = 0; x < 65; x++) - for (y = 0; y < 256; y++) - { - Col2RGB8_Inverse[x][y] = (((((255-palette[y].r)*x)>>4)<<20) | - (((255-palette[y].g)*x)>>4) | - ((((255-palette[y].b)*x)>>4)<<10)) & 0x3feffbff; - } -} - - -void InitPalette () -{ - uint8_t pal[768]; - - ReadPalette(Wads.GetNumForName("PLAYPAL"), pal); - - GPalette.SetPalette (pal); - GPalette.MakeGoodRemap (); ColorMatcher.SetPalette ((uint32_t *)GPalette.BaseColors); if (GPalette.Remap[0] == 0) @@ -414,6 +79,7 @@ void InitPalette () GPalette.Remap[0] = BestColor ((uint32_t *)GPalette.BaseColors, GPalette.BaseColors[0].r, GPalette.BaseColors[0].g, GPalette.BaseColors[0].b, 1, 255); } + GPalette.BaseColors[0] = 0; // Colormaps have to be initialized before actors are loaded, // otherwise Powerup.Colormap will not work. @@ -422,35 +88,3 @@ void InitPalette () } -CCMD (testblend) -{ - FString colorstring; - int color; - float amt; - - if (argv.argc() < 3) - { - Printf ("testblend \n"); - } - else - { - if ( !(colorstring = V_GetColorStringByName (argv[1])).IsEmpty() ) - { - color = V_GetColorFromString (NULL, colorstring); - } - else - { - color = V_GetColorFromString (NULL, argv[1]); - } - amt = (float)atof (argv[2]); - if (amt > 1.0f) - amt = 1.0f; - else if (amt < 0.0f) - amt = 0.0f; - BaseBlendR = RPART(color); - BaseBlendG = GPART(color); - BaseBlendB = BPART(color); - BaseBlendA = amt; - } -} - diff --git a/src/r_data/v_palette.h b/src/r_data/v_palette.h index dbabd92e8bc..648f205a4fd 100644 --- a/src/r_data/v_palette.h +++ b/src/r_data/v_palette.h @@ -36,29 +36,10 @@ #include "doomtype.h" #include "c_cvars.h" -#include "palette.h" +#include "palutil.h" +#include "vectors.h" -struct FPalette -{ - FPalette (); - FPalette (const uint8_t *colors); - - void SetPalette (const uint8_t *colors); - - void MakeGoodRemap (); - - PalEntry BaseColors[256]; // non-gamma corrected palette - uint8_t Remap[256]; // remap original palette indices to in-game indices - - uint8_t WhiteIndex; // white in original palette index - uint8_t BlackIndex; // black in original palette index - - // Given an array of colors, fills in remap with values to remap the - // passed array of colors to this palette. - void MakeRemap (const uint32_t *colors, uint8_t *remap, const uint8_t *useful, int numcolors) const; -}; -extern FPalette GPalette; // The color overlay to use for depleted items #define DIM_OVERLAY MAKEARGB(170,0,0,0) @@ -76,8 +57,12 @@ enum PaletteFlashFlags }; class player_t; +struct sector_t; void V_AddBlend (float r, float g, float b, float a, float v_blend[4]); void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int maxpainblend); +// Dim part of the canvas +FVector4 V_CalcBlend(sector_t* viewsector, PalEntry* modulateColor); +void V_DrawBlend(sector_t* viewsector); #endif //__V_PALETTE_H__ diff --git a/src/r_data/voxeldef.cpp b/src/r_data/voxeldef.cpp new file mode 100644 index 00000000000..a2eee3c35f1 --- /dev/null +++ b/src/r_data/voxeldef.cpp @@ -0,0 +1,344 @@ + +/* +** voxels.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2010-2011 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include +#include +#include + +#include "m_swap.h" +#include "m_argv.h" +#include "filesystem.h" +#include "v_video.h" +#include "sc_man.h" +#include "voxels.h" +#include "info.h" +#include "s_sound.h" +#include "sbar.h" +#include "g_level.h" +#include "r_data/sprites.h" + +using namespace FileSys; + +struct VoxelOptions +{ + int DroppedSpin = 0; + int PlacedSpin = 0; + double Scale = 1; + DAngle AngleOffset = DAngle90; + double xoffset = 0.0; + double yoffset = 0.0; + double zoffset = 0.0; + bool OverridePalette = false; + bool PitchFromMomentum = false; + bool UseActorPitch = false; + bool UseActorRoll = false; +}; + +void VOX_AddVoxel(int sprnum, int frame, FVoxelDef* def); + +//========================================================================== +// +// VOX_ReadSpriteNames +// +// Reads a list of sprite names from a VOXELDEF lump. +// +//========================================================================== + +static bool VOX_ReadSpriteNames(FScanner &sc, TArray &vsprites) +{ + vsprites.Clear(); + while (sc.GetString()) + { + // A sprite name list is terminated by an '=' character. + if (sc.String[0] == '=') + { + if (vsprites.Size() == 0) + { + sc.ScriptMessage("No sprites specified for voxel.\n"); + } + return true; + } + if (sc.StringLen != 4 && sc.StringLen != 5) + { + sc.ScriptMessage("Sprite name \"%s\" is wrong size.\n", sc.String); + } + else if (sc.StringLen == 5 && (sc.String[4] = toupper(sc.String[4]), sc.String[4] < 'A' || sc.String[4] >= 'A' + MAX_SPRITE_FRAMES)) + { + sc.ScriptMessage("Sprite frame %c is invalid.\n", sc.String[4]); + } + else + { + int frame = (sc.StringLen == 4) ? 255 : sc.String[4] - 'A'; + int i = GetSpriteIndex(sc.String, false); + if (i != -1) + { + vsprites.Push((frame << 24) | i); + } + } + } + if (vsprites.Size() != 0) + { + sc.ScriptMessage("Unexpected end of file\n"); + } + return false; +} + +//========================================================================== +// +// VOX_ReadOptions +// +// Reads a list of options from a VOXELDEF lump, terminated with a '}' +// character. The leading '{' must already be consumed +// +//========================================================================== + +static void VOX_ReadOptions(FScanner &sc, VoxelOptions &opts) +{ + while (sc.GetToken()) + { + if (sc.TokenType == '}') + { + return; + } + sc.TokenMustBe(TK_Identifier); + if (sc.Compare("scale")) + { + sc.MustGetToken('='); + sc.MustGetToken(TK_FloatConst); + opts.Scale = sc.Float; + } + else if (sc.Compare("spin")) + { + int mul = 1; + sc.MustGetToken('='); + if (sc.CheckToken('-')) mul = -1; + sc.MustGetToken(TK_IntConst); + opts.DroppedSpin = opts.PlacedSpin = sc.Number*mul; + } + else if (sc.Compare("placedspin")) + { + int mul = 1; + sc.MustGetToken('='); + if (sc.CheckToken('-')) mul = -1; + sc.MustGetToken(TK_IntConst); + opts.PlacedSpin = sc.Number*mul; + } + else if (sc.Compare("droppedspin")) + { + int mul = 1; + sc.MustGetToken('='); + if (sc.CheckToken('-')) mul = -1; + sc.MustGetToken(TK_IntConst); + opts.DroppedSpin = sc.Number*mul; + } + else if (sc.Compare("angleoffset")) + { + int mul = 1; + sc.MustGetToken('='); + if (sc.CheckToken('-')) mul = -1; + sc.MustGetAnyToken(); + if (sc.TokenType == TK_IntConst) + { + sc.Float = sc.Number; + } + else + { + sc.TokenMustBe(TK_FloatConst); + } + opts.AngleOffset = DAngle::fromDeg(mul * sc.Float + 90.); + } + else if (sc.Compare("xoffset")) + { + int mul = 1; + sc.MustGetToken('='); + if (sc.CheckToken('-')) mul = -1; + sc.MustGetAnyToken(); + if (sc.TokenType == TK_IntConst) + { + sc.Float = sc.Number; + } + else + { + sc.TokenMustBe(TK_FloatConst); + } + opts.xoffset = sc.Float * mul; + } + else if (sc.Compare("yoffset")) + { + int mul = 1; + sc.MustGetToken('='); + if (sc.CheckToken('-')) mul = -1; + sc.MustGetAnyToken(); + if (sc.TokenType == TK_IntConst) + { + sc.Float = sc.Number; + } + else + { + sc.TokenMustBe(TK_FloatConst); + } + opts.yoffset = sc.Float * mul; + } + else if (sc.Compare("zoffset")) + { + int mul = 1; + sc.MustGetToken('='); + if (sc.CheckToken('-')) mul = -1; + sc.MustGetAnyToken(); + if (sc.TokenType == TK_IntConst) + { + sc.Float = sc.Number; + } + else + { + sc.TokenMustBe(TK_FloatConst); + } + opts.zoffset = sc.Float * mul; + } + else if (sc.Compare("overridepalette")) + { + opts.OverridePalette = true; + } + else if (sc.Compare("pitchfrommomentum")) + { + opts.PitchFromMomentum = true; + } + else if (sc.Compare("useactorpitch")) + { + opts.UseActorPitch = true; + } + else if (sc.Compare("useactorroll")) + { + opts.UseActorRoll = true; + } + else + { + sc.ScriptMessage("Unknown voxel option '%s'\n", sc.String); + if (sc.CheckToken('=')) + { + sc.MustGetAnyToken(); + } + } + } + sc.ScriptMessage("Unterminated voxel option block\n"); +} + +//========================================================================== +// +// R_InitVoxels +// +// Process VOXELDEF lumps for defining voxel options that cannot be +// condensed neatly into a sprite name format. +// +//========================================================================== + +void R_InitVoxels() +{ + int lump, lastlump = 0; + + while ((lump = fileSystem.FindLump("VOXELDEF", &lastlump)) != -1) + { + FScanner sc(lump); + TArray vsprites; + + while (VOX_ReadSpriteNames(sc, vsprites)) + { + FVoxel *voxeldata = NULL; + int voxelfile; + VoxelOptions opts; + + sc.SetCMode(true); + sc.MustGetToken(TK_StringConst); + voxelfile = fileSystem.CheckNumForFullName(sc.String, true, ns_voxels); + if (voxelfile < 0) + { + sc.ScriptMessage("Voxel \"%s\" not found.\n", sc.String); + } + else + { + voxeldata = VOX_GetVoxel(voxelfile); + if (voxeldata == NULL) + { + sc.ScriptMessage("\"%s\" is not a valid voxel file.\n", sc.String); + } + } + if (sc.CheckToken('{')) + { + VOX_ReadOptions(sc, opts); + } + sc.SetCMode(false); + if (voxeldata != NULL && vsprites.Size() != 0) + { + if (opts.OverridePalette) + { + voxeldata->RemovePalette(); + } + FVoxelDef *def = new FVoxelDef; + + def->Voxel = voxeldata; + def->Scale = opts.Scale; + def->DroppedSpin = opts.DroppedSpin; + def->PlacedSpin = opts.PlacedSpin; + def->AngleOffset = opts.AngleOffset; + def->xoffset = opts.xoffset; + def->yoffset = opts.yoffset; + def->zoffset = opts.zoffset; + def->PitchFromMomentum = opts.PitchFromMomentum; + def->UseActorPitch = opts.UseActorPitch; + def->UseActorRoll = opts.UseActorRoll; + VoxelDefs.Push(def); + + for (unsigned i = 0; i < vsprites.Size(); ++i) + { + int sprnum = int(vsprites[i] & 0xFFFFFF); + int frame = int(vsprites[i] >> 24); + if (frame == 255) + { // Apply voxel to all frames. + for (int j = MAX_SPRITE_FRAMES - 1; j >= 0; --j) + { + VOX_AddVoxel(sprnum, j, def); + } + } + else + { // Apply voxel to only one frame. + VOX_AddVoxel(sprnum, frame, def); + } + } + } + } + } +} + diff --git a/src/r_data/voxels.cpp b/src/r_data/voxels.cpp deleted file mode 100644 index 8017f2c4d8a..00000000000 --- a/src/r_data/voxels.cpp +++ /dev/null @@ -1,713 +0,0 @@ -/* -** voxels.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2010-2011 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** -*/ - -#include -#include -#include -#include - -#include "m_swap.h" -#include "m_argv.h" -#include "w_wad.h" -#include "v_video.h" -#include "sc_man.h" -#include "s_sound.h" -#include "sbar.h" -#include "g_level.h" -#include "r_data/sprites.h" -#include "voxels.h" -#include "info.h" - -void VOX_AddVoxel(int sprnum, int frame, FVoxelDef *def); - -TDeletingArray Voxels; // used only to auto-delete voxels on exit. -TDeletingArray VoxelDefs; - -struct VoxelOptions -{ - VoxelOptions() - : DroppedSpin(0), PlacedSpin(0), Scale(1.), AngleOffset(90.), OverridePalette(false) - {} - - int DroppedSpin; - int PlacedSpin; - double Scale; - DAngle AngleOffset; - bool OverridePalette; -}; - -//========================================================================== -// -// GetVoxelRemap -// -// Calculates a remap table for the voxel's palette. Results are cached so -// passing the same palette repeatedly will not require repeated -// recalculations. -// -//========================================================================== - -static uint8_t *GetVoxelRemap(const uint8_t *pal) -{ - static uint8_t remap[256]; - static uint8_t oldpal[768]; - static bool firsttime = true; - - if (firsttime || memcmp(oldpal, pal, 768) != 0) - { // Not the same palette as last time, so recalculate. - firsttime = false; - memcpy(oldpal, pal, 768); - for (int i = 0; i < 256; ++i) - { - // The voxel palette uses VGA colors, so we have to expand it - // from 6 to 8 bits per component. - remap[i] = BestColor((uint32_t *)GPalette.BaseColors, - (oldpal[i*3 + 0] << 2) | (oldpal[i*3 + 0] >> 4), - (oldpal[i*3 + 1] << 2) | (oldpal[i*3 + 1] >> 4), - (oldpal[i*3 + 2] << 2) | (oldpal[i*3 + 2] >> 4)); - } - } - return remap; -} - -//========================================================================== -// -// CopyVoxelSlabs -// -// Copy all the slabs in a block of slabs. -// -//========================================================================== - -static bool CopyVoxelSlabs(kvxslab_t *dest, const kvxslab_t *src, int size) -{ - while (size >= 3) - { - int slabzleng = src->zleng; - - if (3 + slabzleng > size) - { // slab is too tall - return false; - } - - dest->ztop = src->ztop; - dest->zleng = src->zleng; - dest->backfacecull = src->backfacecull; - - for (int j = 0; j < slabzleng; ++j) - { - dest->col[j] = src->col[j]; - } - slabzleng += 3; - src = (kvxslab_t *)((uint8_t *)src + slabzleng); - dest = (kvxslab_t *)((uint8_t *)dest + slabzleng); - size -= slabzleng; - } - return true; -} - -//========================================================================== -// -// RemapVoxelSlabs -// -// Remaps all the slabs in a block of slabs. -// -//========================================================================== - -static void RemapVoxelSlabs(kvxslab_t *dest, int size, const uint8_t *remap) -{ - while (size >= 3) - { - int slabzleng = dest->zleng; - - for (int j = 0; j < slabzleng; ++j) - { - dest->col[j] = remap[dest->col[j]]; - } - slabzleng += 3; - dest = (kvxslab_t *)((uint8_t *)dest + slabzleng); - size -= slabzleng; - } -} - -//========================================================================== -// -// R_LoadKVX -// -//========================================================================== - -#if defined __GNUC__ && !defined __clang__ -#pragma GCC push_options -#pragma GCC optimize ("-fno-tree-loop-vectorize") -#endif // __GNUC__ && !__clang__ - -FVoxel *R_LoadKVX(int lumpnum) -{ - const kvxslab_t *slabs[MAXVOXMIPS]; - FVoxel *voxel = new FVoxel; - const uint8_t *rawmip; - int mip, maxmipsize; - int i, j, n; - - FMemLump lump = Wads.ReadLump(lumpnum); // FMemLump adds an extra 0 byte to the end. - uint8_t *rawvoxel = (uint8_t *)lump.GetMem(); - int voxelsize = (int)(lump.GetSize()-1); - - // Oh, KVX, why couldn't you have a proper header? We'll just go through - // and collect each MIP level, doing lots of range checking, and if the - // last one doesn't end exactly 768 bytes before the end of the file, - // we'll reject it. - - for (mip = 0, rawmip = rawvoxel, maxmipsize = voxelsize - 768 - 4; - mip < MAXVOXMIPS; - mip++) - { - int numbytes = GetInt(rawmip); - if (numbytes > maxmipsize || numbytes < 24) - { - break; - } - rawmip += 4; - - FVoxelMipLevel *mipl = &voxel->Mips[mip]; - - // Load header data. - mipl->SizeX = GetInt(rawmip + 0); - mipl->SizeY = GetInt(rawmip + 4); - mipl->SizeZ = GetInt(rawmip + 8); - mipl->Pivot.X = GetInt(rawmip + 12) / 256.; - mipl->Pivot.Y = GetInt(rawmip + 16) / 256.; - mipl->Pivot.Z = GetInt(rawmip + 20) / 256.; - - // How much space do we have for voxdata? - int offsetsize = (mipl->SizeX + 1) * 4 + mipl->SizeX * (mipl->SizeY + 1) * 2; - int voxdatasize = numbytes - 24 - offsetsize; - if (voxdatasize < 0) - { // Clearly, not enough. - break; - } - if (voxdatasize != 0) - { // This mip level is not empty. - // Allocate slab data space. - mipl->OffsetX = new int[(numbytes - 24 + 3) / 4]; - mipl->OffsetXY = (short *)(mipl->OffsetX + mipl->SizeX + 1); - mipl->SlabData = (uint8_t *)(mipl->OffsetXY + mipl->SizeX * (mipl->SizeY + 1)); - - // Load x offsets. - for (i = 0, n = mipl->SizeX; i <= n; ++i) - { - // The X offsets stored in the KVX file are relative to the start of the - // X offsets array. Make them relative to voxdata instead. - mipl->OffsetX[i] = GetInt(rawmip + 24 + i * 4) - offsetsize; - } - - // The first X offset must be 0 (since we subtracted offsetsize), according to the spec: - // NOTE: xoffset[0] = (xsiz+1)*4 + xsiz*(ysiz+1)*2 (ALWAYS) - if (mipl->OffsetX[0] != 0) - { - break; - } - // And the final X offset must point just past the end of the voxdata. - if (mipl->OffsetX[mipl->SizeX] != voxdatasize) - { - break; - } - - // Load xy offsets. - i = 24 + i * 4; - for (j = 0, n *= mipl->SizeY + 1; j < n; ++j) - { - mipl->OffsetXY[j] = GetShort(rawmip + i + j * 2); - } - - // Ensure all offsets are within bounds. - for (i = 0; i < mipl->SizeX; ++i) - { - int xoff = mipl->OffsetX[i]; - for (j = 0; j < mipl->SizeY; ++j) - { - int yoff = mipl->OffsetXY[(mipl->SizeY + 1) * i + j]; - if (unsigned(xoff + yoff) > unsigned(voxdatasize)) - { - delete voxel; - return NULL; - } - } - } - - // Record slab location for the end. - slabs[mip] = (kvxslab_t *)(rawmip + 24 + offsetsize); - } - - // Time for the next mip Level. - rawmip += numbytes; - maxmipsize -= numbytes + 4; - } - // Did we get any mip levels, and if so, does the last one leave just - // enough room for the palette after it? - if (mip == 0 || rawmip != rawvoxel + voxelsize - 768) - { - delete voxel; - return NULL; - } - - // Do not count empty mips at the end. - for (; mip > 0; --mip) - { - if (voxel->Mips[mip - 1].SlabData != NULL) - break; - } - voxel->NumMips = mip; - - // Fix pivot data for submips, since some tools seem to like to just center these. - for (i = 1; i < mip; ++i) - { - voxel->Mips[i].Pivot = voxel->Mips[i - 1].Pivot / 2; - } - - for (i = 0; i < mip; ++i) - { - if (!CopyVoxelSlabs((kvxslab_t *)voxel->Mips[i].SlabData, slabs[i], voxel->Mips[i].OffsetX[voxel->Mips[i].SizeX])) - { // Invalid slabs encountered. Reject this voxel. - delete voxel; - return NULL; - } - } - - voxel->LumpNum = lumpnum; - voxel->Palette.Resize(768); - memcpy(voxel->Palette.Data(), rawvoxel + voxelsize - 768, 768); - - return voxel; -} - -#if defined __GNUC__ && !defined __clang__ -#pragma GCC pop_options -#endif // __GNUC__ && !__clang__ - -//========================================================================== -// -// -// -//========================================================================== - -FVoxelDef *R_LoadVoxelDef(int lumpnum, int spin) -{ - FVoxel *vox = R_LoadKVX(lumpnum); - if (vox == NULL) - { - Printf("%s is not a valid voxel file\n", Wads.GetLumpFullName(lumpnum)); - return NULL; - } - else - { - FVoxelDef *voxdef = new FVoxelDef; - voxdef->Voxel = vox; - voxdef->Scale = 1.; - voxdef->DroppedSpin = voxdef->PlacedSpin = spin; - voxdef->AngleOffset = 90.; - - Voxels.Push(vox); - VoxelDefs.Push(voxdef); - return voxdef; - } -} - -//========================================================================== -// -// FVoxelMipLevel Constructor -// -//========================================================================== - -FVoxelMipLevel::FVoxelMipLevel() -{ - SizeZ = SizeY = SizeX = 0; - Pivot.Zero(); - OffsetX = NULL; - OffsetXY = NULL; - SlabData = NULL; -} - -//========================================================================== -// -// FVoxelMipLevel Destructor -// -//========================================================================== - -FVoxelMipLevel::~FVoxelMipLevel() -{ - if (OffsetX != NULL) - { - delete[] OffsetX; - } -} - -//========================================================================== -// -// FVoxelMipLevel :: GetSlabData -// -//========================================================================== - -uint8_t *FVoxelMipLevel::GetSlabData(bool wantremapped) const -{ - if (wantremapped && SlabDataRemapped.Size() > 0) return &SlabDataRemapped[0]; - return SlabData; -} - -//========================================================================== -// -// Create true color version of the slab data -// -//========================================================================== - -void FVoxel::CreateBgraSlabData() -{ - if (Bgramade) return; - Bgramade = true; - for (int i = 0; i < NumMips; ++i) - { - int size = Mips[i].OffsetX[Mips[i].SizeX]; - if (size <= 0) continue; - - Mips[i].SlabDataBgra.Resize(size); - - kvxslab_t *src = (kvxslab_t*)Mips[i].SlabData; - kvxslab_bgra_t *dest = (kvxslab_bgra_t*)&Mips[i].SlabDataBgra[0]; - - while (size >= 3) - { - dest->backfacecull = src->backfacecull; - dest->ztop = src->ztop; - dest->zleng = src->zleng; - - int slabzleng = src->zleng; - for (int j = 0; j < slabzleng; ++j) - { - int colorIndex = src->col[j]; - - uint32_t red, green, blue; - if (Palette.Size()) - { - red = (Palette[colorIndex * 3 + 0] << 2) | (Palette[colorIndex * 3 + 0] >> 4); - green = (Palette[colorIndex * 3 + 1] << 2) | (Palette[colorIndex * 3 + 1] >> 4); - blue = (Palette[colorIndex * 3 + 2] << 2) | (Palette[colorIndex * 3 + 2] >> 4); - } - else - { - red = GPalette.BaseColors[colorIndex].r; - green = GPalette.BaseColors[colorIndex].g; - blue = GPalette.BaseColors[colorIndex].b; - } - - dest->col[j] = 0xff000000 | (red << 16) | (green << 8) | blue; - } - slabzleng += 3; - - dest = (kvxslab_bgra_t *)((uint32_t *)dest + slabzleng); - src = (kvxslab_t *)((uint8_t *)src + slabzleng); - size -= slabzleng; - } - } -} - -//========================================================================== -// -// Remap the voxel to the game palette -// -//========================================================================== - -void FVoxel::Remap() -{ - if (Remapped) return; - Remapped = true; - if (Palette.Size()) - { - uint8_t *remap = GetVoxelRemap(Palette.Data()); - for (int i = 0; i < NumMips; ++i) - { - int size = Mips[i].OffsetX[Mips[i].SizeX]; - if (size <= 0) continue; - - Mips[i].SlabDataRemapped.Resize(size); - memcpy(&Mips[i].SlabDataRemapped [0], Mips[i].SlabData, size); - RemapVoxelSlabs((kvxslab_t *)&Mips[i].SlabDataRemapped[0], Mips[i].OffsetX[Mips[i].SizeX], remap); - } - } -} - -//========================================================================== -// -// Delete the voxel's built-in palette -// -//========================================================================== - -void FVoxel::RemovePalette() -{ - Palette.Reset(); -} - - - -//========================================================================== -// -// VOX_ReadSpriteNames -// -// Reads a list of sprite names from a VOXELDEF lump. -// -//========================================================================== - -static bool VOX_ReadSpriteNames(FScanner &sc, TArray &vsprites) -{ - vsprites.Clear(); - while (sc.GetString()) - { - // A sprite name list is terminated by an '=' character. - if (sc.String[0] == '=') - { - if (vsprites.Size() == 0) - { - sc.ScriptMessage("No sprites specified for voxel.\n"); - } - return true; - } - if (sc.StringLen != 4 && sc.StringLen != 5) - { - sc.ScriptMessage("Sprite name \"%s\" is wrong size.\n", sc.String); - } - else if (sc.StringLen == 5 && (sc.String[4] = toupper(sc.String[4]), sc.String[4] < 'A' || sc.String[4] >= 'A' + MAX_SPRITE_FRAMES)) - { - sc.ScriptMessage("Sprite frame %c is invalid.\n", sc.String[4]); - } - else - { - int frame = (sc.StringLen == 4) ? 255 : sc.String[4] - 'A'; - int i = GetSpriteIndex(sc.String, false); - if (i != -1) - { - vsprites.Push((frame << 24) | i); - } - } - } - if (vsprites.Size() != 0) - { - sc.ScriptMessage("Unexpected end of file\n"); - } - return false; -} - -//========================================================================== -// -// VOX_ReadOptions -// -// Reads a list of options from a VOXELDEF lump, terminated with a '}' -// character. The leading '{' must already be consumed -// -//========================================================================== - -static void VOX_ReadOptions(FScanner &sc, VoxelOptions &opts) -{ - while (sc.GetToken()) - { - if (sc.TokenType == '}') - { - return; - } - sc.TokenMustBe(TK_Identifier); - if (sc.Compare("scale")) - { - sc.MustGetToken('='); - sc.MustGetToken(TK_FloatConst); - opts.Scale = sc.Float; - } - else if (sc.Compare("spin")) - { - int mul = 1; - sc.MustGetToken('='); - if (sc.CheckToken('-')) mul = -1; - sc.MustGetToken(TK_IntConst); - opts.DroppedSpin = opts.PlacedSpin = sc.Number*mul; - } - else if (sc.Compare("placedspin")) - { - int mul = 1; - sc.MustGetToken('='); - if (sc.CheckToken('-')) mul = -1; - sc.MustGetToken(TK_IntConst); - opts.PlacedSpin = sc.Number*mul; - } - else if (sc.Compare("droppedspin")) - { - int mul = 1; - sc.MustGetToken('='); - if (sc.CheckToken('-')) mul = -1; - sc.MustGetToken(TK_IntConst); - opts.DroppedSpin = sc.Number*mul; - } - else if (sc.Compare("angleoffset")) - { - int mul = 1; - sc.MustGetToken('='); - if (sc.CheckToken('-')) mul = -1; - sc.MustGetAnyToken(); - if (sc.TokenType == TK_IntConst) - { - sc.Float = sc.Number; - } - else - { - sc.TokenMustBe(TK_FloatConst); - } - opts.AngleOffset = mul * sc.Float + 90.; - } - else if (sc.Compare("overridepalette")) - { - opts.OverridePalette = true; - } - else - { - sc.ScriptMessage("Unknown voxel option '%s'\n", sc.String); - if (sc.CheckToken('=')) - { - sc.MustGetAnyToken(); - } - } - } - sc.ScriptMessage("Unterminated voxel option block\n"); -} - -//========================================================================== -// -// VOX_GetVoxel -// -// Returns a voxel object for the given lump or NULL if it is not a valid -// voxel. If the voxel has already been loaded, it will be reused. -// -//========================================================================== - -static FVoxel *VOX_GetVoxel(int lumpnum) -{ - // Is this voxel already loaded? If so, return it. - for (unsigned i = 0; i < Voxels.Size(); ++i) - { - if (Voxels[i]->LumpNum == lumpnum) - { - return Voxels[i]; - } - } - FVoxel *vox = R_LoadKVX(lumpnum); - if (vox != NULL) - { - Voxels.Push(vox); - } - return vox; -} - -//========================================================================== -// -// R_InitVoxels -// -// Process VOXELDEF lumps for defining voxel options that cannot be -// condensed neatly into a sprite name format. -// -//========================================================================== - -void R_InitVoxels() -{ - int lump, lastlump = 0; - - while ((lump = Wads.FindLump("VOXELDEF", &lastlump)) != -1) - { - FScanner sc(lump); - TArray vsprites; - - while (VOX_ReadSpriteNames(sc, vsprites)) - { - FVoxel *voxeldata = NULL; - int voxelfile; - VoxelOptions opts; - - sc.SetCMode(true); - sc.MustGetToken(TK_StringConst); - voxelfile = Wads.CheckNumForFullName(sc.String, true, ns_voxels); - if (voxelfile < 0) - { - sc.ScriptMessage("Voxel \"%s\" not found.\n", sc.String); - } - else - { - voxeldata = VOX_GetVoxel(voxelfile); - if (voxeldata == NULL) - { - sc.ScriptMessage("\"%s\" is not a valid voxel file.\n", sc.String); - } - } - if (sc.CheckToken('{')) - { - VOX_ReadOptions(sc, opts); - } - sc.SetCMode(false); - if (voxeldata != NULL && vsprites.Size() != 0) - { - if (opts.OverridePalette) - { - voxeldata->RemovePalette(); - } - FVoxelDef *def = new FVoxelDef; - - def->Voxel = voxeldata; - def->Scale = opts.Scale; - def->DroppedSpin = opts.DroppedSpin; - def->PlacedSpin = opts.PlacedSpin; - def->AngleOffset = opts.AngleOffset; - VoxelDefs.Push(def); - - for (unsigned i = 0; i < vsprites.Size(); ++i) - { - int sprnum = int(vsprites[i] & 0xFFFFFF); - int frame = int(vsprites[i] >> 24); - if (frame == 255) - { // Apply voxel to all frames. - for (int j = MAX_SPRITE_FRAMES - 1; j >= 0; --j) - { - VOX_AddVoxel(sprnum, j, def); - } - } - else - { // Apply voxel to only one frame. - VOX_AddVoxel(sprnum, frame, def); - } - } - } - } - } -} - diff --git a/src/rendering/2d/f_wipe.cpp b/src/rendering/2d/f_wipe.cpp deleted file mode 100644 index 03de1b916f7..00000000000 --- a/src/rendering/2d/f_wipe.cpp +++ /dev/null @@ -1,396 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// Mission begin melt/wipe screen special effect. -// -//----------------------------------------------------------------------------- - -#include "v_video.h" -#include "m_random.h" -#include "f_wipe.h" -#include "templates.h" -#include "textures/bitmap.h" -#include "hwrenderer/textures/hw_material.h" - -class FBurnTexture : public FTexture -{ - TArray WorkBuffer; -public: - FBurnTexture(int w, int h) - : WorkBuffer(w*h, true) - { - Width = w; - Height = h; - } - - FBitmap GetBgraBitmap(PalEntry*, int *trans) override - { - FBitmap bmp; - bmp.Create(Width, Height); - bmp.CopyPixelDataRGB(0, 0, (uint8_t*)WorkBuffer.Data(), Width, Height, 4, Width*4, 0, CF_RGBA, nullptr); - if (trans) *trans = 0; - return bmp; - } - - uint32_t *GetBuffer() - { - return WorkBuffer.Data(); - } -}; - -int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density) -{ - // This is a modified version of the fire that was once used - // on the player setup menu. - static int voop; - - int a, b; - uint8_t *from; - - // generator - from = &burnarray[width * height]; - b = voop; - voop += density / 3; - for (a = 0; a < density/8; a++) - { - unsigned int offs = (a+b) & (width - 1); - unsigned int v = M_Random(); - v = MIN(from[offs] + 4 + (v & 15) + (v >> 3) + (M_Random() & 31), 255u); - from[offs] = from[width*2 + ((offs + width*3/2) & (width - 1))] = v; - } - - density = MIN(density + 10, width * 7); - - from = burnarray; - for (b = 0; b <= height; b += 2) - { - uint8_t *pixel = from; - - // special case: first pixel on line - uint8_t *p = pixel + (width << 1); - unsigned int top = *p + *(p + width - 1) + *(p + 1); - unsigned int bottom = *(pixel + (width << 2)); - unsigned int c1 = (top + bottom) >> 2; - if (c1 > 1) c1--; - *pixel = c1; - *(pixel + width) = (c1 + bottom) >> 1; - pixel++; - - // main line loop - for (a = 1; a < width-1; a++) - { - // sum top pixels - p = pixel + (width << 1); - top = *p + *(p - 1) + *(p + 1); - - // bottom pixel - bottom = *(pixel + (width << 2)); - - // combine pixels - c1 = (top + bottom) >> 2; - if (c1 > 1) c1--; - - // store pixels - *pixel = c1; - *(pixel + width) = (c1 + bottom) >> 1; // interpolate - - // next pixel - pixel++; - } - - // special case: last pixel on line - p = pixel + (width << 1); - top = *p + *(p - 1) + *(p - width + 1); - bottom = *(pixel + (width << 2)); - c1 = (top + bottom) >> 2; - if (c1 > 1) c1--; - *pixel = c1; - *(pixel + width) = (c1 + bottom) >> 1; - - // next line - from += width << 1; - } - - // Check for done-ness. (Every pixel with level 126 or higher counts as done.) - for (a = width * height, from = burnarray; a != 0; --a, ++from) - { - if (*from < 126) - { - return density; - } - } - return -1; -} - - -// TYPES ------------------------------------------------------------------- - -class Wiper_Crossfade : public Wiper -{ -public: - bool Run(int ticks) override; - -private: - int Clock = 0; -}; - -class Wiper_Melt : public Wiper -{ -public: - Wiper_Melt(); - bool Run(int ticks) override; - -private: - static const int WIDTH = 320, HEIGHT = 200; - int y[WIDTH]; -}; - -class Wiper_Burn : public Wiper -{ -public: - ~Wiper_Burn(); - bool Run(int ticks) override; - void SetTextures(FTexture *startscreen, FTexture *endscreen) override; - -private: - static const int WIDTH = 64, HEIGHT = 64; - uint8_t BurnArray[WIDTH * (HEIGHT + 5)] = {0}; - FBurnTexture *BurnTexture = nullptr; - int Density = 4; - int BurnTime = 8; -}; - -//=========================================================================== -// -// Screen wipes -// -//=========================================================================== - -Wiper *Wiper::Create(int type) -{ - switch(type) - { - case wipe_Burn: - return new Wiper_Burn; - - case wipe_Fade: - return new Wiper_Crossfade; - - case wipe_Melt: - return new Wiper_Melt; - - default: - return nullptr; - } -} - - - - -//========================================================================== -// -// OpenGLFrameBuffer :: WipeCleanup -// -// Release any resources that were specifically created for the wipe. -// -//========================================================================== - -Wiper::~Wiper() -{ - if (startScreen != nullptr) delete startScreen; - if (endScreen != nullptr) delete endScreen; -} - -//========================================================================== -// -// WIPE: CROSSFADE --------------------------------------------------------- -// -//========================================================================== - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Crossfade :: Run -// -// Fades the old screen into the new one over 32 ticks. -// -//========================================================================== - -bool Wiper_Crossfade::Run(int ticks) -{ - Clock += ticks; - screen->DrawTexture(startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); - screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); - return Clock >= 32; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Melt Constructor -// -//========================================================================== - -Wiper_Melt::Wiper_Melt() -{ - int i, r; - - // setup initial column positions - // (y<0 => not ready to scroll yet) - y[0] = -(M_Random() & 15); - for (i = 1; i < WIDTH; ++i) - { - r = (M_Random()%3) - 1; - y[i] = clamp(y[i-1] + r, -15, 0); - } -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Melt :: Run -// -// Melts the old screen into the new one over 32 ticks. -// -//========================================================================== - -bool Wiper_Melt::Run(int ticks) -{ - bool done; - screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); - - // Copy the old screen in vertical strips on top of the new one. - while (ticks--) - { - done = true; - for (int i = 0; i < WIDTH; i++) - { - if (y[i] < 0) - { - y[i]++; - done = false; - } - else if (y[i] < HEIGHT) - { - int dy = (y[i] < 16) ? y[i] + 1 : 8; - y[i] = MIN(y[i] + dy, HEIGHT); - done = false; - } - if (ticks == 0) - { - struct { - int32_t x; - int32_t y; - } dpt; - struct { - int32_t left; - int32_t top; - int32_t right; - int32_t bottom; - } rect; - - // Only draw for the final tick. - // No need for optimization. Wipes won't ever be drawn with anything else. - - int w = startScreen->GetDisplayWidth(); - int h = startScreen->GetDisplayHeight(); - dpt.x = i * w / WIDTH; - dpt.y = MAX(0, y[i] * h / HEIGHT); - rect.left = dpt.x; - rect.top = 0; - rect.right = (i + 1) * w / WIDTH; - rect.bottom = h - dpt.y; - if (rect.bottom > rect.top) - { - screen->DrawTexture(startScreen, 0, dpt.y, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, DTA_Masked, false, TAG_DONE); - } - } - } - } - return done; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Burn Constructor -// -//========================================================================== - -void Wiper_Burn::SetTextures(FTexture *startscreen, FTexture *endscreen) -{ - startScreen = startscreen; - endScreen = endscreen; - BurnTexture = new FBurnTexture(WIDTH, HEIGHT); - auto mat = FMaterial::ValidateTexture(endScreen, false); - mat->AddTextureLayer(BurnTexture); -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Burn Destructor -// -//========================================================================== - -Wiper_Burn::~Wiper_Burn() -{ - if (BurnTexture != nullptr) delete BurnTexture; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Burn :: Run -// -//========================================================================== - -bool Wiper_Burn::Run(int ticks) -{ - bool done; - - - BurnTime += ticks; - ticks *= 2; - - // Make the fire burn - done = false; - while (!done && ticks--) - { - Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); - done = (Density < 0); - } - - BurnTexture->SystemTextures.Clean(true, true); - endScreen->SystemTextures.Clean(false, false); - - const uint8_t *src = BurnArray; - uint32_t *dest = (uint32_t *)BurnTexture->GetBuffer(); - for (int y = HEIGHT; y != 0; --y) - { - for (int x = WIDTH; x != 0; --x) - { - uint8_t s = clamp((*src++)*2, 0, 255); - *dest++ = MAKEARGB(s,255,255,255); - } - } - - screen->DrawTexture(startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); - screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Burn, true, DTA_Masked, false, TAG_DONE); - - // The fire may not always stabilize, so the wipe is forced to end - // after an arbitrary maximum time. - return done || (BurnTime > 40); -} diff --git a/src/rendering/2d/f_wipe.h b/src/rendering/2d/f_wipe.h deleted file mode 100644 index c639307aa67..00000000000 --- a/src/rendering/2d/f_wipe.h +++ /dev/null @@ -1,60 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// Mission start screen wipe/melt, special effects. -// -//----------------------------------------------------------------------------- - - -#ifndef __F_WIPE_H__ -#define __F_WIPE_H__ - -#include "stdint.h" - -class FTexture; -int wipe_CalcBurn(uint8_t *buffer, int width, int height, int density); - -enum -{ - wipe_None, // don't bother - wipe_Melt, // weird screen melt - wipe_Burn, // fade in shape of fire - wipe_Fade, // crossfade from old to new - wipe_NUMWIPES -}; - -class Wiper -{ -protected: - FTexture *startScreen = nullptr, *endScreen = nullptr; -public: - virtual ~Wiper(); - virtual bool Run(int ticks) = 0; - virtual void SetTextures(FTexture *startscreen, FTexture *endscreen) - { - startScreen = startscreen; - endScreen = endscreen; - } - - static Wiper *Create(int type); -}; - - -#endif diff --git a/src/rendering/2d/v_2ddrawer.cpp b/src/rendering/2d/v_2ddrawer.cpp deleted file mode 100644 index beec887459d..00000000000 --- a/src/rendering/2d/v_2ddrawer.cpp +++ /dev/null @@ -1,796 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2016-2018 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** v_2ddrawer.h -** Device independent 2D draw list -** -**/ - -#include -#include "doomtype.h" -#include "templates.h" -#include "r_utility.h" -#include "v_video.h" -#include "g_levellocals.h" -#include "vm.h" - -EXTERN_CVAR(Float, transsouls) - -IMPLEMENT_CLASS(DShape2DTransform, false, false) - -static void Shape2DTransform_Clear(DShape2DTransform* self) -{ - self->transform.Identity(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Clear, Shape2DTransform_Clear) -{ - PARAM_SELF_PROLOGUE(DShape2DTransform); - Shape2DTransform_Clear(self); - return 0; -} - -static void Shape2DTransform_Rotate(DShape2DTransform* self, double angle) -{ - self->transform = DMatrix3x3::Rotate2D(DEG2RAD(angle)) * self->transform; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Rotate, Shape2DTransform_Rotate) -{ - PARAM_SELF_PROLOGUE(DShape2DTransform); - PARAM_FLOAT(angle); - Shape2DTransform_Rotate(self, angle); - return 0; -} - -static void Shape2DTransform_Scale(DShape2DTransform* self, double x, double y) -{ - self->transform = DMatrix3x3::Scale2D(DVector2(x, y)) * self->transform; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Scale, Shape2DTransform_Scale) -{ - PARAM_SELF_PROLOGUE(DShape2DTransform); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - Shape2DTransform_Scale(self, x, y); - return 0; -} - -static void Shape2DTransform_Translate(DShape2DTransform* self, double x, double y) -{ - self->transform = DMatrix3x3::Translate2D(DVector2(x, y)) * self->transform; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Translate, Shape2DTransform_Translate) -{ - PARAM_SELF_PROLOGUE(DShape2DTransform); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - Shape2DTransform_Translate(self, x, y); - return 0; -} - -IMPLEMENT_CLASS(DShape2D, false, false) - -static void Shape2D_SetTransform(DShape2D* self, DShape2DTransform *transform) -{ - self->transform = transform->transform; - self->dirty = true; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, SetTransform, Shape2D_SetTransform) -{ - PARAM_SELF_PROLOGUE(DShape2D); - PARAM_OBJECT(transform, DShape2DTransform); - Shape2D_SetTransform(self, transform); - return 0; -} - -static void Shape2D_Clear(DShape2D* self, int which) -{ - if (which & C_Verts) - { - self->mVertices.Clear(); - self->dirty = true; - } - if (which & C_Coords) self->mCoords.Clear(); - if (which & C_Indices) self->mIndices.Clear(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear) -{ - PARAM_SELF_PROLOGUE(DShape2D); - PARAM_INT(which); - Shape2D_Clear(self, which); - return 0; -} - -static void Shape2D_PushVertex(DShape2D* self, double x, double y) -{ - self->mVertices.Push(DVector2(x, y)); - self->dirty = true; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex) -{ - PARAM_SELF_PROLOGUE(DShape2D); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - Shape2D_PushVertex(self, x, y); - return 0; -} - -static void Shape2D_PushCoord(DShape2D* self, double u, double v) -{ - self->mCoords.Push(DVector2(u, v)); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushCoord, Shape2D_PushCoord) -{ - PARAM_SELF_PROLOGUE(DShape2D); - PARAM_FLOAT(u); - PARAM_FLOAT(v); - Shape2D_PushCoord(self, u, v); - return 0; -} - -static void Shape2D_PushTriangle(DShape2D* self, int a, int b, int c) -{ - self->mIndices.Push(a); - self->mIndices.Push(b); - self->mIndices.Push(c); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle) -{ - PARAM_SELF_PROLOGUE(DShape2D); - PARAM_INT(a); - PARAM_INT(b); - PARAM_INT(c); - Shape2D_PushTriangle(self, a, b, c); - return 0; -} - -//========================================================================== -// -// -// -//========================================================================== - -int F2DDrawer::AddCommand(const RenderCommand *data) -{ - if (mData.Size() > 0 && data->isCompatible(mData.Last())) - { - // Merge with the last command. - mData.Last().mIndexCount += data->mIndexCount; - mData.Last().mVertCount += data->mVertCount; - return mData.Size(); - } - else - { - return mData.Push(*data); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void F2DDrawer::AddIndices(int firstvert, int count, ...) -{ - va_list ap; - va_start(ap, count); - int addr = mIndices.Reserve(count); - for (int i = 0; i < count; i++) - { - mIndices[addr + i] = firstvert + va_arg(ap, int); - } -} - -//========================================================================== -// -// SetStyle -// -// Patterned after R_SetPatchStyle. -// -//========================================================================== - -bool F2DDrawer::SetStyle(FTexture *tex, DrawParms &parms, PalEntry &vertexcolor, RenderCommand &quad) -{ - FRenderStyle style = parms.style; - float alpha; - bool stencilling; - - if (style.Flags & STYLEF_TransSoulsAlpha) - { - alpha = transsouls; - } - else if (style.Flags & STYLEF_Alpha1) - { - alpha = 1; - } - else - { - alpha = clamp(parms.Alpha, 0.f, 1.f); - } - - style.CheckFuzz(); - if (style.BlendOp == STYLEOP_Shadow || style.BlendOp == STYLEOP_Fuzz) - { - style = LegacyRenderStyles[STYLE_TranslucentStencil]; - alpha = 0.3f; - parms.fillcolor = 0; - } - else if (style.BlendOp == STYLEOP_FuzzOrAdd) - { - style.BlendOp = STYLEOP_Add; - } - else if (style.BlendOp == STYLEOP_FuzzOrSub) - { - style.BlendOp = STYLEOP_Sub; - } - else if (style.BlendOp == STYLEOP_FuzzOrRevSub) - { - style.BlendOp = STYLEOP_RevSub; - } - - stencilling = false; - - if (style.Flags & STYLEF_InvertOverlay) - { - // Only the overlay color is inverted, not the overlay alpha. - parms.colorOverlay.r = 255 - parms.colorOverlay.r; - parms.colorOverlay.g = 255 - parms.colorOverlay.g; - parms.colorOverlay.b = 255 - parms.colorOverlay.b; - } - - SetColorOverlay(parms.colorOverlay, alpha, vertexcolor, quad.mColor1); - - if (style.Flags & STYLEF_ColorIsFixed) - { - if (style.Flags & STYLEF_InvertSource) - { // Since the source color is a constant, we can invert it now - // without spending time doing it in the shader. - parms.fillcolor.r = 255 - parms.fillcolor.r; - parms.fillcolor.g = 255 - parms.fillcolor.g; - parms.fillcolor.b = 255 - parms.fillcolor.b; - style.Flags &= ~STYLEF_InvertSource; - } - if (parms.desaturate > 0) - { - // Desaturation can also be computed here without having to do it in the shader. - auto gray = parms.fillcolor.Luminance(); - auto notgray = 255 - gray; - parms.fillcolor.r = uint8_t((parms.fillcolor.r * notgray + gray * 255) / 255); - parms.fillcolor.g = uint8_t((parms.fillcolor.g * notgray + gray * 255) / 255); - parms.fillcolor.b = uint8_t((parms.fillcolor.b * notgray + gray * 255) / 255); - parms.desaturate = 0; - } - - // Set up the color mod to replace the color from the image data. - vertexcolor.r = parms.fillcolor.r; - vertexcolor.g = parms.fillcolor.g; - vertexcolor.b = parms.fillcolor.b; - - if (style.Flags & STYLEF_RedIsAlpha) - { - quad.mDrawMode = TM_ALPHATEXTURE; - } - else - { - quad.mDrawMode = TM_STENCIL; - } - } - else - { - if (style.Flags & STYLEF_RedIsAlpha) - { - quad.mDrawMode = TM_ALPHATEXTURE; - } - else if (style.Flags & STYLEF_InvertSource) - { - quad.mDrawMode = TM_INVERSE; - } - - if (parms.specialcolormap != nullptr) - { // draw with an invulnerability or similar colormap. - - auto scm = parms.specialcolormap; - - quad.mSpecialColormap[0] = PalEntry(255, int(scm->ColorizeStart[0] * 127.5f), int(scm->ColorizeStart[1] * 127.5f), int(scm->ColorizeStart[2] * 127.5f)); - quad.mSpecialColormap[1] = PalEntry(255, int(scm->ColorizeEnd[0] * 127.5f), int(scm->ColorizeEnd[1] * 127.5f), int(scm->ColorizeEnd[2] * 127.5f)); - quad.mColor1 = 0; // this disables the color overlay. - } - quad.mDesaturate = parms.desaturate; - } - // apply the element's own color. This is being blended with anything that came before. - vertexcolor = PalEntry((vertexcolor.a * parms.color.a) / 255, (vertexcolor.r * parms.color.r) / 255, (vertexcolor.g * parms.color.g) / 255, (vertexcolor.b * parms.color.b) / 255); - - if (!parms.masked) - { - // For TM_ALPHATEXTURE and TM_STENCIL the mask cannot be turned off because it would not yield a usable result. - if (quad.mDrawMode == TM_NORMAL) quad.mDrawMode = TM_OPAQUE; - else if (quad.mDrawMode == TM_INVERSE) quad.mDrawMode = TM_INVERTOPAQUE; - } - quad.mRenderStyle = parms.style; // this contains the blend mode and blend equation settings. - if (parms.burn) quad.mFlags |= DTF_Burn; - return true; -} - -//========================================================================== -// -// Draws a texture -// -//========================================================================== - -void F2DDrawer::SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor) -{ - if (color.a != 0 && (color & 0xffffff) != 0) - { - // overlay color uses premultiplied alpha. - int a = color.a * 256 / 255; - overlaycolor.r = (color.r * a) >> 8; - overlaycolor.g = (color.g * a) >> 8; - overlaycolor.b = (color.b * a) >> 8; - overlaycolor.a = 0; // The overlay gets added on top of the texture data so to preserve the pixel's alpha this must be 0. - } - else - { - overlaycolor = 0; - } - // Vertex intensity is the inverse of the overlay so that the shader can do a simple addition to combine them. - uint8_t light = 255 - color.a; - vertexcolor = PalEntry(int(alpha * 255), light, light, light); - - // The real color gets multiplied into vertexcolor later. -} - -//========================================================================== -// -// Draws a texture -// -//========================================================================== - -void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms) -{ - if (parms.style.BlendOp == STYLEOP_None) return; // not supposed to be drawn. - - double xscale = parms.destwidth / parms.texwidth; - double yscale = parms.destheight / parms.texheight; - double x = parms.x - parms.left * xscale; - double y = parms.y - parms.top * yscale; - double w = parms.destwidth; - double h = parms.destheight; - double u1, v1, u2, v2; - PalEntry vertexcolor; - - RenderCommand dg; - - dg.mType = DrawTypeTriangles; - dg.mVertCount = 4; - dg.mTexture = img; - if (img->isWarped()) dg.mFlags |= DTF_Wrap; - - dg.mTranslationId = 0; - SetStyle(img, parms, vertexcolor, dg); - - if (!img->isHardwareCanvas() && parms.TranslationId != -1) - { - dg.mTranslationId = parms.TranslationId; - } - u1 = parms.srcx; - v1 = parms.srcy; - u2 = parms.srcx + parms.srcwidth; - v2 = parms.srcy + parms.srcheight; - - if (parms.flipX) - std::swap(u1, u2); - - if (parms.flipY) - std::swap(v1, v2); - - // This is crap. Only kept for backwards compatibility with scripts that may have used it. - // Note that this only works for unflipped full textures. - if (parms.windowleft > 0 || parms.windowright < parms.texwidth) - { - double wi = MIN(parms.windowright, parms.texwidth); - x += parms.windowleft * xscale; - w -= (parms.texwidth - wi + parms.windowleft) * xscale; - - u1 = float(u1 + parms.windowleft / parms.texwidth); - u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); - } - - if (x < (double)parms.lclip || y < (double)parms.uclip || x + w >(double)parms.rclip || y + h >(double)parms.dclip) - { - dg.mScissor[0] = parms.lclip; - dg.mScissor[1] = parms.uclip; - dg.mScissor[2] = parms.rclip; - dg.mScissor[3] = parms.dclip; - dg.mFlags |= DTF_Scissor; - } - else - { - memset(dg.mScissor, 0, sizeof(dg.mScissor)); - } - - dg.mVertCount = 4; - dg.mVertIndex = (int)mVertices.Reserve(4); - TwoDVertex *ptr = &mVertices[dg.mVertIndex]; - ptr->Set(x, y, 0, u1, v1, vertexcolor); ptr++; - ptr->Set(x, y + h, 0, u1, v2, vertexcolor); ptr++; - ptr->Set(x + w, y, 0, u2, v1, vertexcolor); ptr++; - ptr->Set(x + w, y + h, 0, u2, v2, vertexcolor); ptr++; - dg.mIndexIndex = mIndices.Size(); - dg.mIndexCount += 6; - AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); - AddCommand(&dg); -} - -//========================================================================== -// -// -// -//========================================================================== - -void F2DDrawer::AddShape( FTexture *img, DShape2D *shape, DrawParms &parms ) -{ - // [MK] bail out if vertex/coord array sizes are mismatched - if ( shape->mVertices.Size() != shape->mCoords.Size() ) - ThrowAbortException(X_OTHER, "Mismatch in vertex/coord count: %u != %u", shape->mVertices.Size(), shape->mCoords.Size()); - - if (parms.style.BlendOp == STYLEOP_None) return; // not supposed to be drawn. - - PalEntry vertexcolor; - - RenderCommand dg; - - dg.mType = DrawTypeTriangles; - dg.mVertCount = shape->mVertices.Size(); - dg.mFlags |= DTF_Wrap; - dg.mTexture = img; - - dg.mTranslationId = 0; - SetStyle(img, parms, vertexcolor, dg); - - if (!img->isHardwareCanvas() && parms.TranslationId != -1) - dg.mTranslationId = parms.TranslationId; - - if (shape->dirty) { - if (shape->mVertices.Size() != shape->mTransformedVertices.Size()) - shape->mTransformedVertices.Resize(shape->mVertices.Size()); - for (int i = 0; i < dg.mVertCount; i++) { - shape->mTransformedVertices[i] = (shape->transform * DVector3(shape->mVertices[i], 1.0)).XY(); - } - shape->dirty = false; - } - - double minx = 16383, miny = 16383, maxx = -16384, maxy = -16384; - for ( int i=0; imTransformedVertices[i].X < minx ) minx = shape->mTransformedVertices[i].X; - if ( shape->mTransformedVertices[i].Y < miny ) miny = shape->mTransformedVertices[i].Y; - if ( shape->mTransformedVertices[i].X > maxx ) maxx = shape->mTransformedVertices[i].X; - if ( shape->mTransformedVertices[i].Y > maxy ) maxy = shape->mTransformedVertices[i].Y; - } - if (minx < (double)parms.lclip || miny < (double)parms.uclip || maxx >(double)parms.rclip || maxy >(double)parms.dclip) - { - dg.mScissor[0] = parms.lclip; - dg.mScissor[1] = parms.uclip; - dg.mScissor[2] = parms.rclip; - dg.mScissor[3] = parms.dclip; - dg.mFlags |= DTF_Scissor; - } - else - memset(dg.mScissor, 0, sizeof(dg.mScissor)); - - dg.mVertIndex = (int)mVertices.Reserve(dg.mVertCount); - TwoDVertex *ptr = &mVertices[dg.mVertIndex]; - for ( int i=0; imTransformedVertices[i].X, shape->mTransformedVertices[i].Y, 0, shape->mCoords[i].X, shape->mCoords[i].Y, vertexcolor); - dg.mIndexIndex = mIndices.Size(); - dg.mIndexCount += shape->mIndices.Size(); - for ( int i=0; imIndices.Size()); i+=3 ) - { - // [MK] bail out if any indices are out of bounds - for ( int j=0; j<3; j++ ) - { - if ( shape->mIndices[i+j] < 0 ) - ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Triangle %u index %u is negative: %i\n", i/3, j, shape->mIndices[i+j]); - if ( shape->mIndices[i+j] >= dg.mVertCount ) - ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Triangle %u index %u: %u, max: %u\n", i/3, j, shape->mIndices[i+j], dg.mVertCount-1); - } - AddIndices(dg.mVertIndex, 3, shape->mIndices[i], shape->mIndices[i+1], shape->mIndices[i+2]); - } - AddCommand(&dg); -} - -//========================================================================== -// -// -// -//========================================================================== - -void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, - double originx, double originy, double scalex, double scaley, - DAngle rotation, const FColormap &colormap, PalEntry flatcolor, int lightlevel, - uint32_t *indices, size_t indexcount) -{ - // Use an equation similar to player sprites to determine shade - - // Convert a light level into an unbounded colormap index (shade). - // Why the +12? I wish I knew, but experimentation indicates it - // is necessary in order to best reproduce Doom's original lighting. - double fadelevel; - - if (vid_rendermode != 4 || primaryLevel->lightMode == ELightMode::Doom || primaryLevel->lightMode == ELightMode::ZDoomSoftware || primaryLevel->lightMode == ELightMode::DoomSoftware) - { - double map = (NUMCOLORMAPS * 2.) - ((lightlevel + 12) * (NUMCOLORMAPS / 128.)); - fadelevel = clamp((map - 12) / NUMCOLORMAPS, 0.0, 1.0); - } - else - { - // The hardware renderer's light modes 0, 1 and 4 use a linear light scale which must be used here as well. Otherwise the automap gets too dark. - fadelevel = 1. - clamp(lightlevel, 0, 255) / 255.f; - } - - RenderCommand poly; - - poly.mType = DrawTypeTriangles; - poly.mTexture = texture; - poly.mRenderStyle = DefaultRenderStyle(); - poly.mFlags |= DTF_Wrap; - poly.mDesaturate = colormap.Desaturation; - - PalEntry color0; - double invfade = 1. - fadelevel; - - color0.r = uint8_t(colormap.LightColor.r * invfade); - color0.g = uint8_t(colormap.LightColor.g * invfade); - color0.b = uint8_t(colormap.LightColor.b * invfade); - color0.a = 255; - - poly.mColor1.a = 0; - poly.mColor1.r = uint8_t(colormap.FadeColor.r * fadelevel); - poly.mColor1.g = uint8_t(colormap.FadeColor.g * fadelevel); - poly.mColor1.b = uint8_t(colormap.FadeColor.b * fadelevel); - - bool dorotate = rotation != 0; - - float cosrot = (float)cos(rotation.Radians()); - float sinrot = (float)sin(rotation.Radians()); - - float uscale = float(1.f / (texture->GetDisplayWidth() * scalex)); - float vscale = float(1.f / (texture->GetDisplayHeight() * scaley)); - float ox = float(originx); - float oy = float(originy); - - poly.mVertCount = npoints; - poly.mVertIndex = (int)mVertices.Reserve(npoints); - for (int i = 0; i < npoints; ++i) - { - float u = points[i].X - 0.5f - ox; - float v = points[i].Y - 0.5f - oy; - if (dorotate) - { - float t = u; - u = t * cosrot - v * sinrot; - v = v * cosrot + t * sinrot; - } - mVertices[poly.mVertIndex+i].Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale, color0); - } - poly.mIndexIndex = mIndices.Size(); - - if (indices == nullptr || indexcount == 0) - { - poly.mIndexCount += (npoints - 2) * 3; - for (int i = 2; i < npoints; ++i) - { - AddIndices(poly.mVertIndex, 3, 0, i - 1, i); - } - } - else - { - poly.mIndexCount += (int)indexcount; - int addr = mIndices.Reserve(indexcount); - for (size_t i = 0; i < indexcount; i++) - { - mIndices[addr + i] = poly.mVertIndex + indices[i]; - } - } - - AddCommand(&poly); -} - -//========================================================================== -// -// -// -//========================================================================== - -void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin) -{ - float fU1, fU2, fV1, fV2; - - RenderCommand dg; - - dg.mType = DrawTypeTriangles; - dg.mRenderStyle = DefaultRenderStyle(); - dg.mTexture = src; - dg.mVertCount = 4; - dg.mTexture = src; - dg.mFlags = DTF_Wrap; - - // scaling is not used here. - if (!local_origin) - { - fU1 = float(left) / src->GetDisplayWidth(); - fV1 = float(top) / src->GetDisplayHeight(); - fU2 = float(right) / src->GetDisplayWidth(); - fV2 = float(bottom) / src->GetDisplayHeight(); - } - else - { - fU1 = 0; - fV1 = 0; - fU2 = float(right - left) / src->GetDisplayWidth(); - fV2 = float(bottom - top) / src->GetDisplayHeight(); - } - dg.mVertIndex = (int)mVertices.Reserve(4); - auto ptr = &mVertices[dg.mVertIndex]; - - ptr->Set(left, top, 0, fU1, fV1, 0xffffffff); ptr++; - ptr->Set(left, bottom, 0, fU1, fV2, 0xffffffff); ptr++; - ptr->Set(right, top, 0, fU2, fV1, 0xffffffff); ptr++; - ptr->Set(right, bottom, 0, fU2, fV2, 0xffffffff); ptr++; - dg.mIndexIndex = mIndices.Size(); - dg.mIndexCount += 6; - AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); - AddCommand(&dg); -} - - -//=========================================================================== -// -// -// -//=========================================================================== - -void F2DDrawer::AddColorOnlyQuad(int x1, int y1, int w, int h, PalEntry color, FRenderStyle *style) -{ - RenderCommand dg; - - dg.mType = DrawTypeTriangles; - dg.mVertCount = 4; - dg.mVertIndex = (int)mVertices.Reserve(4); - dg.mRenderStyle = style? *style : LegacyRenderStyles[STYLE_Translucent]; - auto ptr = &mVertices[dg.mVertIndex]; - ptr->Set(x1, y1, 0, 0, 0, color); ptr++; - ptr->Set(x1, y1 + h, 0, 0, 0, color); ptr++; - ptr->Set(x1 + w, y1, 0, 0, 0, color); ptr++; - ptr->Set(x1 + w, y1 + h, 0, 0, 0, color); ptr++; - dg.mIndexIndex = mIndices.Size(); - dg.mIndexCount += 6; - AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); - AddCommand(&dg); -} - -//========================================================================== -// -// -// -//========================================================================== - -void F2DDrawer::AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32_t color, uint8_t alpha) -{ - PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor]; - p.a = alpha; - - RenderCommand dg; - - dg.mType = DrawTypeLines; - dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent]; - dg.mVertCount = 2; - dg.mVertIndex = (int)mVertices.Reserve(2); - mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p); - mVertices[dg.mVertIndex+1].Set(x2, y2, 0, 0, 0, p); - AddCommand(&dg); -} - -//========================================================================== -// -// -// -//========================================================================== - -void F2DDrawer::AddThickLine(int x1, int y1, int x2, int y2, double thickness, uint32_t color, uint8_t alpha) -{ - PalEntry p = (PalEntry)color; - p.a = alpha; - - DVector2 point0(x1, y1); - DVector2 point1(x2, y2); - - DVector2 delta = point1 - point0; - DVector2 perp(-delta.Y, delta.X); - perp.MakeUnit(); - perp *= thickness / 2; - - DVector2 corner0 = point0 + perp; - DVector2 corner1 = point0 - perp; - DVector2 corner2 = point1 + perp; - DVector2 corner3 = point1 - perp; - - RenderCommand dg; - - dg.mType = DrawTypeTriangles; - dg.mVertCount = 4; - dg.mVertIndex = (int)mVertices.Reserve(4); - dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent]; - auto ptr = &mVertices[dg.mVertIndex]; - ptr->Set(corner0.X, corner0.Y, 0, 0, 0, p); ptr++; - ptr->Set(corner1.X, corner1.Y, 0, 0, 0, p); ptr++; - ptr->Set(corner2.X, corner2.Y, 0, 0, 0, p); ptr++; - ptr->Set(corner3.X, corner3.Y, 0, 0, 0, p); ptr++; - dg.mIndexIndex = mIndices.Size(); - dg.mIndexCount += 6; - AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); - AddCommand(&dg); -} - -//========================================================================== -// -// -// -//========================================================================== - -void F2DDrawer::AddPixel(int x1, int y1, int palcolor, uint32_t color) -{ - PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor]; - p.a = 255; - - RenderCommand dg; - - dg.mType = DrawTypePoints; - dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent]; - dg.mVertCount = 1; - dg.mVertIndex = (int)mVertices.Reserve(1); - mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p); - AddCommand(&dg); -} - -//========================================================================== -// -// -// -//========================================================================== - -void F2DDrawer::Clear() -{ - mVertices.Clear(); - mIndices.Clear(); - mData.Clear(); - mIsFirstPass = true; -} diff --git a/src/rendering/2d/v_2ddrawer.h b/src/rendering/2d/v_2ddrawer.h deleted file mode 100644 index 53ea596c954..00000000000 --- a/src/rendering/2d/v_2ddrawer.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef __2DDRAWER_H -#define __2DDRAWER_H - -#include "tarray.h" -#include "textures.h" -#include "v_palette.h" -#include "r_data/renderstyle.h" -#include "r_data/colormaps.h" - -struct DrawParms; - -class DShape2DTransform : public DObject -{ - -DECLARE_CLASS(DShape2DTransform, DObject) -public: - DShape2DTransform() - { - transform.Identity(); - } - DMatrix3x3 transform; -}; - -// intermediate struct for shape drawing - -enum EClearWhich -{ - C_Verts = 1, - C_Coords = 2, - C_Indices = 4, -}; - -class DShape2D : public DObject -{ - - DECLARE_CLASS(DShape2D,DObject) -public: - DShape2D() - { - transform.Identity(); - } - - TArray mIndices; - TArray mVertices; - TArray mCoords; - - DMatrix3x3 transform; - - // dirty stores whether we need to re-apply the transformation - // otherwise it uses the cached values - bool dirty = true; - TArray mTransformedVertices; -}; - -class F2DDrawer -{ -public: - - enum EDrawType : uint8_t - { - DrawTypeTriangles, - DrawTypeLines, - DrawTypePoints, - }; - - enum ETextureFlags : uint8_t - { - DTF_Wrap = 1, - DTF_Scissor = 2, - DTF_Burn = 4, - }; - - - // This vertex type is hardware independent and needs conversion when put into a buffer. - struct TwoDVertex - { - float x, y, z; - float u, v; - PalEntry color0; - - void Set(float xx, float yy, float zz) - { - x = xx; - z = zz; - y = yy; - u = 0; - v = 0; - color0 = 0; - } - - void Set(double xx, double yy, double zz, double uu, double vv, PalEntry col) - { - x = (float)xx; - z = (float)zz; - y = (float)yy; - u = (float)uu; - v = (float)vv; - color0 = col; - } - - }; - - struct RenderCommand - { - EDrawType mType; - int mVertIndex; - int mVertCount; - int mIndexIndex; - int mIndexCount; - - FTexture *mTexture; - int mTranslationId; - PalEntry mSpecialColormap[2]; - int mScissor[4]; - int mDesaturate; - FRenderStyle mRenderStyle; - PalEntry mColor1; // Overlay color - ETexMode mDrawMode; - uint8_t mFlags; - - RenderCommand() - { - memset(this, 0, sizeof(*this)); - } - - // If these fields match, two draw commands can be batched. - bool isCompatible(const RenderCommand &other) const - { - return mTexture == other.mTexture && - mType == other.mType && - mTranslationId == other.mTranslationId && - mSpecialColormap[0].d == other.mSpecialColormap[0].d && - mSpecialColormap[1].d == other.mSpecialColormap[1].d && - !memcmp(mScissor, other.mScissor, sizeof(mScissor)) && - mDesaturate == other.mDesaturate && - mRenderStyle == other.mRenderStyle && - mDrawMode == other.mDrawMode && - mFlags == other.mFlags && - mColor1.d == other.mColor1.d; - - } - }; - - TArray mIndices; - TArray mVertices; - TArray mData; - - int AddCommand(const RenderCommand *data); - void AddIndices(int firstvert, int count, ...); - bool SetStyle(FTexture *tex, DrawParms &parms, PalEntry &color0, RenderCommand &quad); - void SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor); - -public: - void AddTexture(FTexture *img, DrawParms &parms); - void AddShape(FTexture *img, DShape2D *shape, DrawParms &parms); - void AddPoly(FTexture *texture, FVector2 *points, int npoints, - double originx, double originy, double scalex, double scaley, - DAngle rotation, const FColormap &colormap, PalEntry flatcolor, int lightlevel, uint32_t *indices, size_t indexcount); - void AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin); - - void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style); - - void AddDim(PalEntry color, float damount, int x1, int y1, int w, int h); - void AddClear(int left, int top, int right, int bottom, int palcolor, uint32_t color); - - - void AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32_t color, uint8_t alpha = 255); - void AddThickLine(int x1, int y1, int x2, int y2, double thickness, uint32_t color, uint8_t alpha = 255); - void AddPixel(int x1, int y1, int palcolor, uint32_t color); - - void Clear(); - - bool mIsFirstPass = true; -}; - - -#endif diff --git a/src/rendering/2d/v_blend.cpp b/src/rendering/2d/v_blend.cpp index 6e6f31c90c8..ec3a7a39084 100644 --- a/src/rendering/2d/v_blend.cpp +++ b/src/rendering/2d/v_blend.cpp @@ -34,7 +34,7 @@ #include -#include "templates.h" + #include "sbar.h" #include "c_cvars.h" #include "c_dispatch.h" @@ -44,7 +44,13 @@ #include "d_player.h" #include "g_levellocals.h" #include "vm.h" +#include "v_palette.h" +#include "r_utility.h" +#include "hw_cvars.h" +#include "d_main.h" +#include "v_draw.h" +CVAR(Float, underwater_fade_scalar, 1.0f, CVAR_ARCHIVE) // [Nash] user-settable underwater blend intensity CVAR( Float, blood_fade_scalar, 1.0f, CVAR_ARCHIVE ) // [SP] Pulled from Skulltag - changed default from 0.5 to 1.0 CVAR( Float, pickup_fade_scalar, 1.0f, CVAR_ARCHIVE ) // [SP] Uses same logic as blood_fade_scalar except for pickups @@ -135,7 +141,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int if (painFlash.a != 0) { - cnt = DamageToAlpha[MIN (113, CPlayer->damagecount * painFlash.a / 255)]; + cnt = DamageToAlpha[min (CPlayer->damagecount * painFlash.a / 255, (uint32_t)113)]; // [BC] Allow users to tone down the intensity of the blood on the screen. cnt = (int)( cnt * blood_fade_scalar ); @@ -158,7 +164,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int if (CPlayer->poisoncount) { - cnt = MIN (CPlayer->poisoncount, 64); + cnt = min (CPlayer->poisoncount, 64); if (paletteflash & PF_POISON) { V_AddBlend(44/255.f, 92/255.f, 36/255.f, ((cnt + 7) >> 3) * 0.1f, blend); @@ -184,7 +190,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int } else { - cnt= MIN(CPlayer->hazardcount/8, 64); + cnt= min(CPlayer->hazardcount/8, 64); float r = ((Level->hazardcolor & 0xff0000) >> 16) / 255.f; float g = ((Level->hazardcolor & 0xff00) >> 8) / 255.f; float b = ((Level->hazardcolor & 0xff)) / 255.f; @@ -207,3 +213,169 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int // cap opacity if desired if (blend[3] > maxinvalpha) blend[3] = maxinvalpha; } + +//========================================================================== +// +// Draws a blend over the entire view +// +//========================================================================== + +FVector4 V_CalcBlend(sector_t* viewsector, PalEntry* modulateColor) +{ + float blend[4] = { 0,0,0,0 }; + PalEntry blendv = 0; + float extra_red; + float extra_green; + float extra_blue; + player_t* player = nullptr; + bool fullbright = false; + + if (modulateColor) *modulateColor = 0xffffffff; + + if (players[consoleplayer].camera != nullptr) + { + player = players[consoleplayer].camera->player; + if (player) + fullbright = (player->fixedcolormap != NOFIXEDCOLORMAP || player->extralight == INT_MIN || player->fixedlightlevel != -1); + } + + // don't draw sector based blends when any fullbright screen effect is active. + if (!fullbright) + { + const auto& vpp = r_viewpoint.Pos; + if (!viewsector->e->XFloor.ffloors.Size()) + { + if (viewsector->GetHeightSec()) + { + auto s = viewsector->heightsec; + blendv = s->floorplane.PointOnSide(vpp) < 0 ? s->bottommap : s->ceilingplane.PointOnSide(vpp) < 0 ? s->topmap : s->midmap; + } + else if (viewsector->selfmap != 0) blendv = viewsector->selfmap; + else blendv = viewsector->Level->globalcolormap; + } + else + { + TArray& lightlist = viewsector->e->XFloor.lightlist; + + for (unsigned int i = 0; i < lightlist.Size(); i++) + { + double lightbottom; + if (i < lightlist.Size() - 1) + lightbottom = lightlist[i + 1].plane.ZatPoint(vpp); + else + lightbottom = viewsector->floorplane.ZatPoint(vpp); + + if (lightbottom < vpp.Z && (!lightlist[i].caster || !(lightlist[i].caster->flags & FF_FADEWALLS))) + { + // 3d floor 'fog' is rendered as a blending value + blendv = lightlist[i].blend; + // If this is the same as the sector's it doesn't apply! + if (blendv == viewsector->Colormap.FadeColor) blendv = 0; + // a little hack to make this work for Legacy maps. + if (blendv.a == 0 && blendv != 0) blendv.a = 128; + break; + } + } + } + + if (blendv.a == 0 && V_IsTrueColor()) // The paletted software renderer uses the original colormap as this frame's palette, but in true color that isn't doable. + { + blendv = R_BlendForColormap(blendv); + } + + if (blendv.a == 255) + { + + extra_red = blendv.r / 255.0f; + extra_green = blendv.g / 255.0f; + extra_blue = blendv.b / 255.0f; + + // If this is a multiplicative blend do it separately and add the additive ones on top of it. + + // black multiplicative blends are ignored + if (extra_red || extra_green || extra_blue) + { + if (modulateColor) *modulateColor = blendv; + } + blendv = 0; + } + else if (blendv.a) + { + // [Nash] allow user to set blend intensity + int cnt = blendv.a; + cnt = (int)(cnt * underwater_fade_scalar); + + V_AddBlend(blendv.r / 255.f, blendv.g / 255.f, blendv.b / 255.f, cnt / 255.0f, blend); + } + } + else if (player && player->fixedlightlevel != -1 && player->fixedcolormap == NOFIXEDCOLORMAP) + { + // Draw fixedlightlevel effects as a 2D overlay. The hardware renderer just processes such a scene fullbright without any lighting. + auto torchtype = PClass::FindActor(NAME_PowerTorch); + auto litetype = PClass::FindActor(NAME_PowerLightAmp); + PalEntry color = 0xffffffff; + for (AActor* in = player->mo->Inventory; in; in = in->Inventory) + { + // Need special handling for light amplifiers + if (in->IsKindOf(torchtype)) + { + // The software renderer already bakes the torch flickering into its output, so this must be omitted here. + float r = vid_rendermode < 4 ? 1.f : (0.8f + (7 - player->fixedlightlevel) / 70.0f); + if (r > 1.0f) r = 1.0f; + int rr = (int)(r * 255); + int b = rr; + if (gl_enhanced_nightvision) b = b * 3 / 4; + color = PalEntry(255, rr, rr, b); + } + else if (in->IsKindOf(litetype)) + { + if (gl_enhanced_nightvision) + { + color = PalEntry(255, 104, 255, 104); + } + } + } + if (modulateColor) + { + *modulateColor = color; + } + } + + if (player) + { + V_AddPlayerBlend(player, blend, 0.5, 175); + } + + if (players[consoleplayer].camera != NULL) + { + // except for fadeto effects + player_t* player = (players[consoleplayer].camera->player != NULL) ? players[consoleplayer].camera->player : &players[consoleplayer]; + V_AddBlend(player->BlendR, player->BlendG, player->BlendB, player->BlendA, blend); + } + + const float br = clamp(blend[0] * 255.f, 0.f, 255.f); + const float bg = clamp(blend[1] * 255.f, 0.f, 255.f); + const float bb = clamp(blend[2] * 255.f, 0.f, 255.f); + return { br, bg, bb, blend[3] }; +} + +//========================================================================== +// +// Draws a blend over the entire view +// +//========================================================================== + +void V_DrawBlend(sector_t* viewsector) +{ + auto drawer = twod; + PalEntry modulateColor; + auto blend = V_CalcBlend(viewsector, &modulateColor); + if (modulateColor != 0xffffffff) + { + Dim(twod, modulateColor, 1, 0, 0, drawer->GetWidth(), drawer->GetHeight(), &LegacyRenderStyles[STYLE_Multiply]); + } + + const PalEntry bcolor(255, uint8_t(blend.X), uint8_t(blend.Y), uint8_t(blend.Z)); + Dim(drawer, bcolor, blend.W, 0, 0, drawer->GetWidth(), drawer->GetHeight()); +} + diff --git a/src/rendering/2d/v_draw.cpp b/src/rendering/2d/v_draw.cpp deleted file mode 100644 index 13589073f1b..00000000000 --- a/src/rendering/2d/v_draw.cpp +++ /dev/null @@ -1,1592 +0,0 @@ -/* -** v_draw.cpp -** Draw patches and blocks to a canvas -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include - -#include "doomtype.h" -#include "v_video.h" -#include "r_defs.h" -#include "r_utility.h" -#include "doomstat.h" -#include "gi.h" -#include "g_level.h" -#include "sbar.h" -#include "d_player.h" - -#include "i_video.h" -#include "g_levellocals.h" -#include "vm.h" -#include "hwrenderer/utility/hw_cvars.h" - -CVAR(Float, underwater_fade_scalar, 1.0f, CVAR_ARCHIVE) // [Nash] user-settable underwater blend intensity - -CUSTOM_CVAR(Int, uiscale, 0, CVAR_ARCHIVE | CVAR_NOINITCALL) -{ - if (self < 0) - { - self = 0; - return; - } - if (StatusBar != NULL) - { - StatusBar->CallScreenSizeChanged(); - } - setsizeneeded = true; -} - -int GetUIScale(int altval) -{ - int scaleval; - if (altval > 0) scaleval = altval; - else if (uiscale == 0) - { - // Default should try to scale to 640x400 - int vscale = screen->GetHeight() / 400; - int hscale = screen->GetWidth() / 640; - scaleval = clamp(vscale, 1, hscale); - } - else scaleval = uiscale; - - // block scales that result in something larger than the current screen. - int vmax = screen->GetHeight() / 200; - int hmax = screen->GetWidth() / 320; - int max = MAX(vmax, hmax); - return MAX(1,MIN(scaleval, max)); -} - -// The new console font is twice as high, so the scaling calculation must factor that in. -int GetConScale(int altval) -{ - int scaleval; - if (altval > 0) scaleval = (altval+1) / 2; - else if (uiscale == 0) - { - // Default should try to scale to 640x400 - int vscale = screen->GetHeight() / 800; - int hscale = screen->GetWidth() / 1280; - scaleval = clamp(vscale, 1, hscale); - } - else scaleval = (uiscale+1) / 2; - - // block scales that result in something larger than the current screen. - int vmax = screen->GetHeight() / 400; - int hmax = screen->GetWidth() / 640; - int max = MAX(vmax, hmax); - return MAX(1, MIN(scaleval, max)); -} - - -// [RH] Stretch values to make a 320x200 image best fit the screen -// without using fractional steppings -int CleanXfac, CleanYfac; - -// [RH] Effective screen sizes that the above scale values give you -int CleanWidth, CleanHeight; - -// Above minus 1 (or 1, if they are already 1) -int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1; - - -//========================================================================== -// -// ZScript wrappers for inlines -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(_Screen, GetWidth) -{ - PARAM_PROLOGUE; - ACTION_RETURN_INT(screen->GetWidth()); -} - -DEFINE_ACTION_FUNCTION(_Screen, GetHeight) -{ - PARAM_PROLOGUE; - ACTION_RETURN_INT(screen->GetHeight()); -} - -DEFINE_ACTION_FUNCTION(_Screen, PaletteColor) -{ - PARAM_PROLOGUE; - PARAM_INT(index); - if (index < 0 || index > 255) index = 0; - else index = GPalette.BaseColors[index]; - ACTION_RETURN_INT(index); -} - -//========================================================================== -// -// Internal texture drawing function -// -//========================================================================== - -void DFrameBuffer::DrawTexture (FTexture *img, double x, double y, int tags_first, ...) -{ - Va_List tags; - va_start(tags.list, tags_first); - DrawParms parms; - - bool res = ParseDrawTextureTags(img, x, y, tags_first, tags, &parms, false); - va_end(tags.list); - if (!res) - { - return; - } - DrawTextureParms(img, parms); -} - -//========================================================================== -// -// ZScript texture drawing function -// -//========================================================================== - -int ListGetInt(VMVa_List &tags); - -void DFrameBuffer::DrawTexture(FTexture *img, double x, double y, VMVa_List &args) -{ - DrawParms parms; - uint32_t tag = ListGetInt(args); - bool res = ParseDrawTextureTags(img, x, y, tag, args, &parms, false); - if (!res) return; - DrawTextureParms(img, parms); -} - -DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) -{ - PARAM_PROLOGUE; - PARAM_INT(texid); - PARAM_BOOL(animate); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - - PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array - - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - - FTexture *tex = TexMan.ByIndex(texid, animate); - VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 }; - screen->DrawTexture(tex, x, y, args); - return 0; -} - -//========================================================================== -// -// common drawing function -// -//========================================================================== - -void DFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms) -{ - m2DDrawer.AddTexture(img, parms); -} - -//========================================================================== -// -// ZScript arbitrary textured shape drawing functions -// -//========================================================================== - -void DFrameBuffer::DrawShape(FTexture *img, DShape2D *shape, int tags_first, ...) -{ - Va_List tags; - va_start(tags.list, tags_first); - DrawParms parms; - - bool res = ParseDrawTextureTags(img, 0, 0, tags_first, tags, &parms, false); - va_end(tags.list); - if (!res) return; - m2DDrawer.AddShape(img, shape, parms); -} - -void DFrameBuffer::DrawShape(FTexture *img, DShape2D *shape, VMVa_List &args) -{ - DrawParms parms; - uint32_t tag = ListGetInt(args); - - bool res = ParseDrawTextureTags(img, 0, 0, tag, args, &parms, false); - if (!res) return; - m2DDrawer.AddShape(img, shape, parms); -} - -DEFINE_ACTION_FUNCTION(_Screen, DrawShape) -{ - PARAM_PROLOGUE; - PARAM_INT(texid); - PARAM_BOOL(animate); - PARAM_POINTER(shape, DShape2D); - - PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array - - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - - FTexture *tex = TexMan.ByIndex(texid, animate); - VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo + 3 }; - - screen->DrawShape(tex, shape, args); - return 0; -} - -//========================================================================== -// -// Clipping rect -// -//========================================================================== - -void DFrameBuffer::SetClipRect(int x, int y, int w, int h) -{ - clipleft = clamp(x, 0, GetWidth()); - clipwidth = clamp(w, -1, GetWidth() - x); - cliptop = clamp(y, 0, GetHeight()); - clipheight = clamp(h, -1, GetHeight() - y); -} - -DEFINE_ACTION_FUNCTION(_Screen, SetClipRect) -{ - PARAM_PROLOGUE; - PARAM_INT(x); - PARAM_INT(y); - PARAM_INT(w); - PARAM_INT(h); - screen->SetClipRect(x, y, w, h); - return 0; -} - -DEFINE_ACTION_FUNCTION(_Screen, ClearClipRect) -{ - PARAM_PROLOGUE; - screen->ClearClipRect(); - return 0; -} - -void DFrameBuffer::GetClipRect(int *x, int *y, int *w, int *h) -{ - if (x) *x = clipleft; - if (y) *y = cliptop; - if (w) *w = clipwidth; - if (h) *h = clipheight; -} - -DEFINE_ACTION_FUNCTION(_Screen, GetClipRect) -{ - PARAM_PROLOGUE; - int x, y, w, h; - screen->GetClipRect(&x, &y, &w, &h); - if (numret > 0) ret[0].SetInt(x); - if (numret > 1) ret[1].SetInt(y); - if (numret > 2) ret[2].SetInt(w); - if (numret > 3) ret[3].SetInt(h); - return MIN(numret, 4); -} - -DEFINE_ACTION_FUNCTION(_Screen, GetViewWindow) -{ - PARAM_PROLOGUE; - if (numret > 0) ret[0].SetInt(viewwindowx); - if (numret > 1) ret[1].SetInt(viewwindowy); - if (numret > 2) ret[2].SetInt(viewwidth); - if (numret > 3) ret[3].SetInt(viewheight); - return MIN(numret, 4); -} - -//========================================================================== -// -// Draw parameter parsing -// -//========================================================================== - -bool DFrameBuffer::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double yy) const -{ - if (img != NULL) - { - parms->x = xx; - parms->y = yy; - parms->texwidth = img->GetDisplayWidthDouble(); - parms->texheight = img->GetDisplayHeightDouble(); - if (parms->top == INT_MAX || parms->fortext) - { - parms->top = img->GetDisplayTopOffset(); - } - if (parms->left == INT_MAX || parms->fortext) - { - parms->left = img->GetDisplayLeftOffset(); - } - if (parms->destwidth == INT_MAX || parms->fortext) - { - parms->destwidth = img->GetDisplayWidthDouble(); - } - if (parms->destheight == INT_MAX || parms->fortext) - { - parms->destheight = img->GetDisplayHeightDouble(); - } - - switch (parms->cleanmode) - { - default: - break; - - case DTA_Clean: - parms->x = (parms->x - 160.0) * CleanXfac + (Width * 0.5); - parms->y = (parms->y - 100.0) * CleanYfac + (Height * 0.5); - parms->destwidth = parms->texwidth * CleanXfac; - parms->destheight = parms->texheight * CleanYfac; - break; - - case DTA_CleanNoMove: - parms->destwidth = parms->texwidth * CleanXfac; - parms->destheight = parms->texheight * CleanYfac; - break; - - case DTA_CleanNoMove_1: - parms->destwidth = parms->texwidth * CleanXfac_1; - parms->destheight = parms->texheight * CleanYfac_1; - break; - - case DTA_Fullscreen: - case DTA_FullscreenEx: - { - double aspect; - double srcwidth = img->GetDisplayWidthDouble(); - double srcheight = img->GetDisplayHeightDouble(); - int autoaspect = parms->fsscalemode; - aspect = autoaspect == 0 || (srcwidth == 320 && srcheight == 200) || (srcwidth == 640 && srcheight == 400)? 1.333 : srcwidth / srcheight; - parms->x = parms->y = 0; - parms->keepratio = true; - auto screenratio = ActiveRatio(GetWidth(), GetHeight()); - if (autoaspect == 3) - { - if (screenratio >= aspect || aspect < 1.4) autoaspect = 1; // screen is wider than the image -> pillarbox it. 4:3 images must also be pillarboxes if the screen is taller than the image - else if (screenratio > 1.32) autoaspect = 2; // on anything 4:3 and wider crop the sides of the image. - else - { - // special case: Crop image to 4:3 and then letterbox this. This avoids too much cropping on narrow windows. - double width4_3 = srcheight * (4. / 3.); - parms->destwidth = (double)GetWidth() * srcwidth / width4_3; - parms->destheight = GetHeight() * screenratio * (3. / 4.); // use 4:3 for the image - parms->y = (GetHeight() - parms->destheight) / 2; - parms->x = -(srcwidth - width4_3) / 2; - return false; // Do not call VirtualToRealCoords for this! - } - } - - if ((screenratio > aspect) ^ (autoaspect == 2)) - { - // pillarboxed or vertically cropped (i.e. scale to height) - parms->destheight = GetHeight(); - parms->destwidth =GetWidth() * aspect / screenratio; - parms->x = (GetWidth() - parms->destwidth) / 2; - } - else - { - // letterboxed or horizontally cropped (i.e. scale to width) - parms->destwidth = GetWidth(); - parms->destheight = GetHeight() * screenratio / aspect; - parms->y = (GetHeight() - parms->destheight) / 2; - } - return false; // Do not call VirtualToRealCoords for this! - } - - case DTA_HUDRules: - case DTA_HUDRulesC: - { - // Note that this has been deprecated because the HUD should be drawn by the status bar. - bool xright = parms->x < 0; - bool ybot = parms->y < 0; - DVector2 scale = StatusBar->GetHUDScale(); - - parms->x *= scale.X; - if (parms->cleanmode == DTA_HUDRulesC) - parms->x += Width * 0.5; - else if (xright) - parms->x = Width + parms->x; - parms->y *= scale.Y; - if (ybot) - parms->y = Height + parms->y; - parms->destwidth = parms->texwidth * scale.X; - parms->destheight = parms->texheight * scale.Y; - break; - } - } - if (parms->virtWidth != Width || parms->virtHeight != Height) - { - VirtualToRealCoords(parms->x, parms->y, parms->destwidth, parms->destheight, - parms->virtWidth, parms->virtHeight, parms->virtBottom, !parms->keepratio); - } - } - - return false; -} - -//========================================================================== -// -// template helpers -// -//========================================================================== - -static void ListEnd(Va_List &tags) -{ - va_end(tags.list); -} - -static int ListGetInt(Va_List &tags) -{ - return va_arg(tags.list, int); -} - -static inline double ListGetDouble(Va_List &tags) -{ - return va_arg(tags.list, double); -} - -static inline FSpecialColormap * ListGetSpecialColormap(Va_List &tags) -{ - return va_arg(tags.list, FSpecialColormap *); -} - -static void ListEnd(VMVa_List &tags) -{ -} - -int ListGetInt(VMVa_List &tags) -{ - if (tags.curindex < tags.numargs) - { - if (tags.reginfo[tags.curindex] == REGT_INT) - { - return tags.args[tags.curindex++].i; - } - ThrowAbortException(X_OTHER, "Invalid parameter in draw function, int expected"); - } - return TAG_DONE; -} - -static inline double ListGetDouble(VMVa_List &tags) -{ - if (tags.curindex < tags.numargs) - { - if (tags.reginfo[tags.curindex] == REGT_FLOAT) - { - return tags.args[tags.curindex++].f; - } - if (tags.reginfo[tags.curindex] == REGT_INT) - { - return tags.args[tags.curindex++].i; - } - ThrowAbortException(X_OTHER, "Invalid parameter in draw function, float expected"); - } - return 0; -} - -static inline FSpecialColormap * ListGetSpecialColormap(VMVa_List &tags) -{ - ThrowAbortException(X_OTHER, "Invalid tag in draw function"); - return nullptr; -} - -//========================================================================== -// -// Main taglist parsing -// -//========================================================================== - -template -bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, T& tags, DrawParms *parms, bool fortext) const -{ - INTBOOL boolval; - int intval; - bool translationset = false; - bool fillcolorset = false; - - if (!fortext) - { - if (img == NULL || !img->isValid()) - { - ListEnd(tags); - return false; - } - } - - // Do some sanity checks on the coordinates. - if (x < -16383 || x > 16383 || y < -16383 || y > 16383) - { - ListEnd(tags); - return false; - } - - parms->fortext = fortext; - parms->windowleft = 0; - parms->windowright = INT_MAX; - parms->dclip = this->GetHeight(); - parms->uclip = 0; - parms->lclip = 0; - parms->rclip = this->GetWidth(); - parms->left = INT_MAX; - parms->top = INT_MAX; - parms->destwidth = INT_MAX; - parms->destheight = INT_MAX; - parms->Alpha = 1.f; - parms->fillcolor = -1; - parms->TranslationId = -1; - parms->colorOverlay = 0; - parms->alphaChannel = false; - parms->flipX = false; - parms->flipY = false; - parms->color = 0xffffffff; - //parms->shadowAlpha = 0; - parms->shadowColor = 0; - parms->virtWidth = this->GetWidth(); - parms->virtHeight = this->GetHeight(); - parms->keepratio = false; - parms->style.BlendOp = 255; // Dummy "not set" value - parms->masked = true; - parms->bilinear = false; - parms->specialcolormap = NULL; - parms->desaturate = 0; - parms->cleanmode = DTA_Base; - parms->scalex = parms->scaley = 1; - parms->cellx = parms->celly = 0; - parms->maxstrlen = INT_MAX; - parms->virtBottom = false; - parms->srcx = 0.; - parms->srcy = 0.; - parms->srcwidth = 1.; - parms->srcheight = 1.; - parms->burn = false; - parms->monospace = EMonospacing::Off; - parms->spacing = 0; - - // Parse the tag list for attributes. (For floating point attributes, - // consider that the C ABI dictates that all floats be promoted to - // doubles when passed as function arguments.) - while (tag != TAG_DONE) - { - switch (tag) - { - default: - ListGetInt(tags); - break; - - case DTA_DestWidth: - assert(fortext == false); - if (fortext) return false; - parms->cleanmode = DTA_Base; - parms->destwidth = ListGetInt(tags); - break; - - case DTA_DestWidthF: - assert(fortext == false); - if (fortext) return false; - parms->cleanmode = DTA_Base; - parms->destwidth = ListGetDouble(tags); - break; - - case DTA_DestHeight: - assert(fortext == false); - if (fortext) return false; - parms->cleanmode = DTA_Base; - parms->destheight = ListGetInt(tags); - break; - - case DTA_DestHeightF: - assert(fortext == false); - if (fortext) return false; - parms->cleanmode = DTA_Base; - parms->destheight = ListGetDouble(tags); - break; - - case DTA_Clean: - boolval = ListGetInt(tags); - if (boolval) - { - parms->scalex = 1; - parms->scaley = 1; - parms->cleanmode = tag; - } - break; - - case DTA_CleanNoMove: - boolval = ListGetInt(tags); - if (boolval) - { - parms->scalex = CleanXfac; - parms->scaley = CleanYfac; - parms->cleanmode = tag; - } - break; - - case DTA_CleanNoMove_1: - boolval = ListGetInt(tags); - if (boolval) - { - parms->scalex = CleanXfac_1; - parms->scaley = CleanYfac_1; - parms->cleanmode = tag; - } - break; - - case DTA_320x200: - boolval = ListGetInt(tags); - if (boolval) - { - parms->cleanmode = DTA_Base; - parms->scalex = 1; - parms->scaley = 1; - parms->virtWidth = 320; - parms->virtHeight = 200; - } - break; - - case DTA_Bottom320x200: - boolval = ListGetInt(tags); - if (boolval) - { - parms->cleanmode = DTA_Base; - parms->scalex = 1; - parms->scaley = 1; - parms->virtWidth = 320; - parms->virtHeight = 200; - } - parms->virtBottom = true; - break; - - case DTA_HUDRules: - intval = ListGetInt(tags); - parms->cleanmode = intval == HUD_HorizCenter ? DTA_HUDRulesC : DTA_HUDRules; - break; - - case DTA_VirtualWidth: - parms->cleanmode = DTA_Base; - parms->virtWidth = ListGetInt(tags); - break; - - case DTA_VirtualWidthF: - parms->cleanmode = DTA_Base; - parms->virtWidth = ListGetDouble(tags); - break; - - case DTA_VirtualHeight: - parms->cleanmode = DTA_Base; - parms->virtHeight = ListGetInt(tags); - break; - - case DTA_VirtualHeightF: - parms->cleanmode = DTA_Base; - parms->virtHeight = ListGetDouble(tags); - break; - - case DTA_Fullscreen: - - boolval = ListGetInt(tags); - if (boolval) - { - assert(fortext == false); - if (img == NULL) return false; - parms->cleanmode = DTA_Fullscreen; - parms->fsscalemode = (uint8_t)gameinfo.fullscreenautoaspect; - parms->virtWidth = img->GetDisplayWidthDouble(); - parms->virtHeight = img->GetDisplayHeightDouble(); - } - break; - - case DTA_FullscreenEx: - - intval = ListGetInt(tags); - if (intval >= 0 && intval <= 3) - { - assert(fortext == false); - if (img == NULL) return false; - parms->cleanmode = DTA_Fullscreen; - parms->fsscalemode = (uint8_t)intval; - parms->virtWidth = img->GetDisplayWidthDouble(); - parms->virtHeight = img->GetDisplayHeightDouble(); - } - break; - - case DTA_Alpha: - parms->Alpha = (float)(MIN(1., ListGetDouble(tags))); - break; - - case DTA_AlphaChannel: - parms->alphaChannel = ListGetInt(tags); - break; - - case DTA_FillColor: - parms->fillcolor = ListGetInt(tags); - if (parms->fillcolor != ~0u) - { - fillcolorset = true; - } - else if (parms->fillcolor != 0) - { - // The crosshair is the only thing which uses a non-black fill color. - parms->fillcolor = PalEntry(ColorMatcher.Pick(parms->fillcolor), RPART(parms->fillcolor), GPART(parms->fillcolor), BPART(parms->fillcolor)); - } - break; - - case DTA_TranslationIndex: - parms->TranslationId = ListGetInt(tags); - break; - - case DTA_ColorOverlay: - parms->colorOverlay = ListGetInt(tags); - break; - - case DTA_Color: - parms->color = ListGetInt(tags); - break; - - case DTA_FlipX: - parms->flipX = ListGetInt(tags); - break; - - case DTA_FlipY: - parms->flipY = ListGetInt(tags); - break; - - case DTA_SrcX: - parms->srcx = ListGetDouble(tags) / img->GetDisplayWidthDouble(); - break; - - case DTA_SrcY: - parms->srcy = ListGetDouble(tags) / img->GetDisplayHeightDouble(); - break; - - case DTA_SrcWidth: - parms->srcwidth = ListGetDouble(tags) / img->GetDisplayWidthDouble(); - break; - - case DTA_SrcHeight: - parms->srcheight = ListGetDouble(tags) / img->GetDisplayHeightDouble(); - break; - - case DTA_TopOffset: - assert(fortext == false); - if (fortext) return false; - parms->top = ListGetInt(tags); - break; - - case DTA_TopOffsetF: - assert(fortext == false); - if (fortext) return false; - parms->top = ListGetDouble(tags); - break; - - case DTA_LeftOffset: - assert(fortext == false); - if (fortext) return false; - parms->left = ListGetInt(tags); - break; - - case DTA_LeftOffsetF: - assert(fortext == false); - if (fortext) return false; - parms->left = ListGetDouble(tags); - break; - - case DTA_CenterOffset: - assert(fortext == false); - if (fortext) return false; - if (ListGetInt(tags)) - { - parms->left = img->GetDisplayWidthDouble() * 0.5; - parms->top = img->GetDisplayHeightDouble() * 0.5; - } - break; - - case DTA_CenterBottomOffset: - assert(fortext == false); - if (fortext) return false; - if (ListGetInt(tags)) - { - parms->left = img->GetDisplayWidthDouble() * 0.5; - parms->top = img->GetDisplayHeightDouble(); - } - break; - - case DTA_WindowLeft: - assert(fortext == false); - if (fortext) return false; - parms->windowleft = ListGetInt(tags); - break; - - case DTA_WindowLeftF: - assert(fortext == false); - if (fortext) return false; - parms->windowleft = ListGetDouble(tags); - break; - - case DTA_WindowRight: - assert(fortext == false); - if (fortext) return false; - parms->windowright = ListGetInt(tags); - break; - - case DTA_WindowRightF: - assert(fortext == false); - if (fortext) return false; - parms->windowright = ListGetDouble(tags); - break; - - case DTA_ClipTop: - parms->uclip = ListGetInt(tags); - if (parms->uclip < 0) - { - parms->uclip = 0; - } - break; - - case DTA_ClipBottom: - parms->dclip = ListGetInt(tags); - if (parms->dclip > this->GetHeight()) - { - parms->dclip = this->GetHeight(); - } - break; - - case DTA_ClipLeft: - parms->lclip = ListGetInt(tags); - if (parms->lclip < 0) - { - parms->lclip = 0; - } - break; - - case DTA_ClipRight: - parms->rclip = ListGetInt(tags); - if (parms->rclip > this->GetWidth()) - { - parms->rclip = this->GetWidth(); - } - break; - - case DTA_ShadowAlpha: - //parms->shadowAlpha = (float)MIN(1., ListGetDouble(tags)); - break; - - case DTA_ShadowColor: - parms->shadowColor = ListGetInt(tags); - break; - - case DTA_Shadow: - boolval = ListGetInt(tags); - if (boolval) - { - //parms->shadowAlpha = 0.5; - parms->shadowColor = 0; - } - else - { - //parms->shadowAlpha = 0; - } - break; - - case DTA_Masked: - parms->masked = ListGetInt(tags); - break; - - case DTA_BilinearFilter: - parms->bilinear = ListGetInt(tags); - break; - - case DTA_KeepRatio: - // I think this is a terribly misleading name, since it actually turns - // *off* aspect ratio correction. - parms->keepratio = ListGetInt(tags); - break; - - case DTA_RenderStyle: - parms->style.AsDWORD = ListGetInt(tags); - break; - - case DTA_LegacyRenderStyle: // mainly for ZScript which does not handle FRenderStyle that well. - parms->style = (ERenderStyle)ListGetInt(tags); - break; - - case DTA_SpecialColormap: - parms->specialcolormap = ListGetSpecialColormap(tags); - break; - - case DTA_Desaturate: - parms->desaturate = ListGetInt(tags); - break; - - case DTA_TextLen: - parms->maxstrlen = ListGetInt(tags); - break; - - case DTA_CellX: - parms->cellx = ListGetInt(tags); - break; - - case DTA_CellY: - parms->celly = ListGetInt(tags); - break; - - case DTA_Monospace: - parms->monospace = ListGetInt(tags); - break; - - case DTA_Spacing: - parms->spacing = ListGetInt(tags); - break; - - case DTA_Burn: - parms->burn = true; - break; - - } - tag = ListGetInt(tags); - } - ListEnd(tags); - - // intersect with the canvas's clipping rectangle. - if (clipwidth >= 0 && clipheight >= 0) - { - if (parms->lclip < clipleft) parms->lclip = clipleft; - if (parms->rclip > clipleft + clipwidth) parms->rclip = clipleft + clipwidth; - if (parms->uclip < cliptop) parms->uclip = cliptop; - if (parms->dclip > cliptop + clipheight) parms->dclip = cliptop + clipheight; - } - - if (parms->uclip >= parms->dclip || parms->lclip >= parms->rclip) - { - return false; - } - - if (img != NULL) - { - SetTextureParms(parms, img, x, y); - - if (parms->destwidth <= 0 || parms->destheight <= 0) - { - return false; - } - } - - if (parms->style.BlendOp == 255) - { - if (fillcolorset) - { - if (parms->alphaChannel) - { - parms->style = STYLE_Shaded; - } - else if (parms->Alpha < 1.f) - { - parms->style = STYLE_TranslucentStencil; - } - else - { - parms->style = STYLE_Stencil; - } - } - else if (parms->Alpha < 1.f) - { - parms->style = STYLE_Translucent; - } - else - { - parms->style = STYLE_Normal; - } - } - return true; -} -// explicitly instantiate both versions for v_text.cpp. - -template bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, bool fortext) const; -template bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, VMVa_List& tags, DrawParms *parms, bool fortext) const; - -//========================================================================== -// -// Coordinate conversion -// -//========================================================================== - -void DFrameBuffer::VirtualToRealCoords(double &x, double &y, double &w, double &h, - double vwidth, double vheight, bool vbottom, bool handleaspect) const -{ - float myratio = handleaspect ? ActiveRatio (Width, Height) : (4.0f / 3.0f); - - // if 21:9 AR, map to 16:9 for all callers. - // this allows for black bars and stops the stretching of fullscreen images - if (myratio > 1.7f) { - myratio = 16.0f / 9.0f; - } - - double right = x + w; - double bottom = y + h; - - if (myratio > 1.334f) - { // The target surface is either 16:9 or 16:10, so expand the - // specified virtual size to avoid undesired stretching of the - // image. Does not handle non-4:3 virtual sizes. I'll worry about - // those if somebody expresses a desire to use them. - x = (x - vwidth * 0.5) * Width * 960 / (vwidth * AspectBaseWidth(myratio)) + Width * 0.5; - w = (right - vwidth * 0.5) * Width * 960 / (vwidth * AspectBaseWidth(myratio)) + Width * 0.5 - x; - } - else - { - x = x * Width / vwidth; - w = right * Width / vwidth - x; - } - if (AspectTallerThanWide(myratio)) - { // The target surface is 5:4 - y = (y - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5; - h = (bottom - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5 - y; - if (vbottom) - { - y += (Height - Height * AspectMultiplier(myratio) / 48.0) * 0.5; - } - } - else - { - y = y * Height / vheight; - h = bottom * Height / vheight - y; - } -} - -DEFINE_ACTION_FUNCTION(_Screen, VirtualToRealCoords) -{ - PARAM_PROLOGUE; - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_FLOAT(w); - PARAM_FLOAT(h); - PARAM_FLOAT(vw); - PARAM_FLOAT(vh); - PARAM_BOOL(vbottom); - PARAM_BOOL(handleaspect); - screen->VirtualToRealCoords(x, y, w, h, vw, vh, vbottom, handleaspect); - if (numret >= 1) ret[0].SetVector2(DVector2(x, y)); - if (numret >= 2) ret[1].SetVector2(DVector2(w, h)); - return MIN(numret, 2); -} - -void DFrameBuffer::VirtualToRealCoordsInt(int &x, int &y, int &w, int &h, - int vwidth, int vheight, bool vbottom, bool handleaspect) const -{ - double dx, dy, dw, dh; - - dx = x; - dy = y; - dw = w; - dh = h; - VirtualToRealCoords(dx, dy, dw, dh, vwidth, vheight, vbottom, handleaspect); - x = int(dx + 0.5); - y = int(dy + 0.5); - w = int(dx + dw + 0.5) - x; - h = int(dy + dh + 0.5) - y; -} - -//========================================================================== -// -// -// -//========================================================================== - -void DFrameBuffer::FillBorder (FTexture *img) -{ - float myratio = ActiveRatio (Width, Height); - - if (myratio >= 1.3f && myratio <= 1.4f) - { // This is a 4:3 display, so no border to show - return; - } - int bordtop, bordbottom, bordleft, bordright, bord; - if (AspectTallerThanWide(myratio)) - { // Screen is taller than it is wide - bordleft = bordright = 0; - bord = Height - Height * AspectMultiplier(myratio) / 48; - bordtop = bord / 2; - bordbottom = bord - bordtop; - } - else - { // Screen is wider than it is tall - bordtop = bordbottom = 0; - bord = Width - Width * AspectMultiplier(myratio) / 48; - bordleft = bord / 2; - bordright = bord - bordleft; - } - - if (img != NULL) - { - FlatFill (0, 0, Width, bordtop, img); // Top - FlatFill (0, bordtop, bordleft, Height - bordbottom, img); // Left - FlatFill (Width - bordright, bordtop, Width, Height - bordbottom, img); // Right - FlatFill (0, Height - bordbottom, Width, Height, img); // Bottom - } - else - { - Clear (0, 0, Width, bordtop, GPalette.BlackIndex, 0); // Top - Clear (0, bordtop, bordleft, Height - bordbottom, GPalette.BlackIndex, 0); // Left - Clear (Width - bordright, bordtop, Width, Height - bordbottom, GPalette.BlackIndex, 0); // Right - Clear (0, Height - bordbottom, Width, Height, GPalette.BlackIndex, 0); // Bottom - } -} - -//========================================================================== -// -// Draw a line -// -//========================================================================== - -void DFrameBuffer::DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32_t realcolor, uint8_t alpha) -{ - m2DDrawer.AddLine(x0, y0, x1, y1, palColor, realcolor, alpha); -} - -DEFINE_ACTION_FUNCTION(_Screen, DrawLine) -{ - PARAM_PROLOGUE; - PARAM_INT(x0); - PARAM_INT(y0); - PARAM_INT(x1); - PARAM_INT(y1); - PARAM_INT(color); - PARAM_INT(alpha); - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - screen->DrawLine(x0, y0, x1, y1, -1, color | MAKEARGB(255, 0, 0, 0), alpha); - return 0; -} - -void DFrameBuffer::DrawThickLine(int x0, int y0, int x1, int y1, double thickness, uint32_t realcolor, uint8_t alpha) { - m2DDrawer.AddThickLine(x0, y0, x1, y1, thickness, realcolor, alpha); -} - -DEFINE_ACTION_FUNCTION(_Screen, DrawThickLine) -{ - PARAM_PROLOGUE; - PARAM_INT(x0); - PARAM_INT(y0); - PARAM_INT(x1); - PARAM_INT(y1); - PARAM_FLOAT(thickness); - PARAM_INT(color); - PARAM_INT(alpha); - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - screen->DrawThickLine(x0, y0, x1, y1, thickness, color, alpha); - return 0; -} - -//========================================================================== -// -// Draw a single pixel -// -//========================================================================== - -void DFrameBuffer::DrawPixel(int x, int y, int palColor, uint32_t realcolor) -{ - m2DDrawer.AddPixel(x, y, palColor, realcolor); -} - -//========================================================================== -// -// DCanvas :: Clear -// -// Set an area to a specified color. -// -//========================================================================== - -void DFrameBuffer::Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color) -{ - if (clipwidth >= 0 && clipheight >= 0) - { - int w = right - left; - int h = bottom - top; - if (left < clipleft) - { - w -= (clipleft - left); - left = clipleft; - } - if (w > clipwidth) w = clipwidth; - if (w <= 0) return; - - if (top < cliptop) - { - h -= (cliptop - top); - top = cliptop; - } - if (h > clipheight) w = clipheight; - if (h <= 0) return; - right = left + w; - bottom = top + h; - } - - if (palcolor >= 0 && color == 0) - { - color = GPalette.BaseColors[palcolor] | 0xff000000; - } - m2DDrawer.AddColorOnlyQuad(left, top, right - left, bottom - top, color | 0xFF000000, nullptr); -} - -DEFINE_ACTION_FUNCTION(_Screen, Clear) -{ - PARAM_PROLOGUE; - PARAM_INT(x1); - PARAM_INT(y1); - PARAM_INT(x2); - PARAM_INT(y2); - PARAM_INT(color); - PARAM_INT(palcol); - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - screen->Clear(x1, y1, x2, y2, palcol, color); - return 0; -} - -//========================================================================== -// -// DCanvas :: Dim -// -// Applies a colored overlay to an area of the screen. -// -//========================================================================== - -void DFrameBuffer::DoDim(PalEntry color, float amount, int x1, int y1, int w, int h, FRenderStyle *style) -{ - if (amount <= 0) - { - return; - } - if (amount > 1) - { - amount = 1; - } - m2DDrawer.AddColorOnlyQuad(x1, y1, w, h, (color.d & 0xffffff) | (int(amount * 255) << 24), style); -} - -void DFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h, FRenderStyle *style) -{ - if (clipwidth >= 0 && clipheight >= 0) - { - if (x1 < clipleft) - { - w -= (clipleft - x1); - x1 = clipleft; - } - if (w > clipwidth) w = clipwidth; - if (w <= 0) return; - - if (y1 < cliptop) - { - h -= (cliptop - y1); - y1 = cliptop; - } - if (h > clipheight) h = clipheight; - if (h <= 0) return; - } - DoDim(color, damount, x1, y1, w, h, style); -} - -DEFINE_ACTION_FUNCTION(_Screen, Dim) -{ - PARAM_PROLOGUE; - PARAM_INT(color); - PARAM_FLOAT(amount); - PARAM_INT(x1); - PARAM_INT(y1); - PARAM_INT(w); - PARAM_INT(h); - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - screen->Dim(color, float(amount), x1, y1, w, h); - return 0; -} - -//========================================================================== -// -// DCanvas :: FillSimplePoly -// -// Fills a simple polygon with a texture. Here, "simple" means that a -// horizontal scanline at any vertical position within the polygon will -// not cross it more than twice. -// -// The originx, originy, scale, and rotation parameters specify -// transformation of the filling texture, not of the points. -// -// The points must be specified in clockwise order. -// -//========================================================================== - -void DFrameBuffer::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, - double originx, double originy, double scalex, double scaley, DAngle rotation, - const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip, uint32_t *indices, size_t indexcount) -{ - m2DDrawer.AddPoly(tex, points, npoints, originx, originy, scalex, scaley, rotation, colormap, flatcolor, lightlevel, indices, indexcount); -} - -//========================================================================== -// -// DCanvas :: FlatFill -// -// Fill an area with a texture. If local_origin is false, then the origin -// used for the wrapping is (0,0). Otherwise, (left,right) is used. -// -//========================================================================== - -void DFrameBuffer::FlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin) -{ - m2DDrawer.AddFlatFill(left, top, right, bottom, src, local_origin); -} - -//========================================================================== -// -// V_DrawFrame -// -// Draw a frame around the specified area using the view border -// frame graphics. The border is drawn outside the area, not in it. -// -//========================================================================== - -void DFrameBuffer::DrawFrame (int left, int top, int width, int height) -{ - FTexture *p; - const gameborder_t *border = &gameinfo.Border; - // Sanity check for incomplete gameinfo - if (border == NULL) - return; - int offset = border->offset; - int right = left + width; - int bottom = top + height; - - // Draw top and bottom sides. - p = TexMan.GetTextureByName(border->t); - FlatFill(left, top - p->GetDisplayHeight(), right, top, p, true); - p = TexMan.GetTextureByName(border->b); - FlatFill(left, bottom, right, bottom + p->GetDisplayHeight(), p, true); - - // Draw left and right sides. - p = TexMan.GetTextureByName(border->l); - FlatFill(left - p->GetDisplayWidth(), top, left, bottom, p, true); - p = TexMan.GetTextureByName(border->r); - FlatFill(right, top, right + p->GetDisplayWidth(), bottom, p, true); - - // Draw beveled corners. - DrawTexture (TexMan.GetTextureByName(border->tl), left-offset, top-offset, TAG_DONE); - DrawTexture (TexMan.GetTextureByName(border->tr), left+width, top-offset, TAG_DONE); - DrawTexture (TexMan.GetTextureByName(border->bl), left-offset, top+height, TAG_DONE); - DrawTexture (TexMan.GetTextureByName(border->br), left+width, top+height, TAG_DONE); -} - -DEFINE_ACTION_FUNCTION(_Screen, DrawFrame) -{ - PARAM_PROLOGUE; - PARAM_INT(x); - PARAM_INT(y); - PARAM_INT(w); - PARAM_INT(h); - screen->DrawFrame(x, y, w, h); - return 0; -} - -//========================================================================== -// -// screen->DrawBorder -// -//========================================================================== - -void DFrameBuffer::DrawBorder (FTextureID picnum, int x1, int y1, int x2, int y2) -{ - if (picnum.isValid()) - { - FlatFill (x1, y1, x2, y2, TexMan.GetTexture(picnum, false)); - } - else - { - Clear (x1, y1, x2, y2, 0, 0); - } -} - -//========================================================================== -// -// Draws a blend over the entire view -// -//========================================================================== - -FVector4 DFrameBuffer::CalcBlend(sector_t * viewsector, PalEntry *modulateColor) -{ - float blend[4] = { 0,0,0,0 }; - PalEntry blendv = 0; - float extra_red; - float extra_green; - float extra_blue; - player_t *player = nullptr; - bool fullbright = false; - - if (modulateColor) *modulateColor = 0xffffffff; - - if (players[consoleplayer].camera != nullptr) - { - player = players[consoleplayer].camera->player; - if (player) - fullbright = (player->fixedcolormap != NOFIXEDCOLORMAP || player->extralight == INT_MIN || player->fixedlightlevel != -1); - } - - // don't draw sector based blends when any fullbright screen effect is active. - if (!fullbright) - { - const auto &vpp = r_viewpoint.Pos; - if (!viewsector->e->XFloor.ffloors.Size()) - { - if (viewsector->GetHeightSec()) - { - auto s = viewsector->heightsec; - blendv = s->floorplane.PointOnSide(vpp) < 0 ? s->bottommap : s->ceilingplane.PointOnSide(vpp) < 0 ? s->topmap : s->midmap; - } - } - else - { - TArray & lightlist = viewsector->e->XFloor.lightlist; - - for (unsigned int i = 0; i < lightlist.Size(); i++) - { - double lightbottom; - if (i < lightlist.Size() - 1) - lightbottom = lightlist[i + 1].plane.ZatPoint(vpp); - else - lightbottom = viewsector->floorplane.ZatPoint(vpp); - - if (lightbottom < vpp.Z && (!lightlist[i].caster || !(lightlist[i].caster->flags&FF_FADEWALLS))) - { - // 3d floor 'fog' is rendered as a blending value - blendv = lightlist[i].blend; - // If this is the same as the sector's it doesn't apply! - if (blendv == viewsector->Colormap.FadeColor) blendv = 0; - // a little hack to make this work for Legacy maps. - if (blendv.a == 0 && blendv != 0) blendv.a = 128; - break; - } - } - } - - if (blendv.a == 0 && V_IsTrueColor()) // The paletted software renderer uses the original colormap as this frame's palette, but in true color that isn't doable. - { - blendv = R_BlendForColormap(blendv); - } - - if (blendv.a == 255) - { - - extra_red = blendv.r / 255.0f; - extra_green = blendv.g / 255.0f; - extra_blue = blendv.b / 255.0f; - - // If this is a multiplicative blend do it separately and add the additive ones on top of it. - - // black multiplicative blends are ignored - if (extra_red || extra_green || extra_blue) - { - if (modulateColor) *modulateColor = blendv; - } - blendv = 0; - } - else if (blendv.a) - { - // [Nash] allow user to set blend intensity - int cnt = blendv.a; - cnt = (int)(cnt * underwater_fade_scalar); - - V_AddBlend(blendv.r / 255.f, blendv.g / 255.f, blendv.b / 255.f, cnt / 255.0f, blend); - } - } - else if (player && player->fixedlightlevel != -1 && player->fixedcolormap == NOFIXEDCOLORMAP) - { - // Draw fixedlightlevel effects as a 2D overlay. The hardware renderer just processes such a scene fullbright without any lighting. - auto torchtype = PClass::FindActor(NAME_PowerTorch); - auto litetype = PClass::FindActor(NAME_PowerLightAmp); - PalEntry color = 0xffffffff; - for (AActor *in = player->mo->Inventory; in; in = in->Inventory) - { - // Need special handling for light amplifiers - if (in->IsKindOf(torchtype)) - { - // The software renderer already bakes the torch flickering into its output, so this must be omitted here. - float r = vid_rendermode < 4 ? 1.f : (0.8f + (7 - player->fixedlightlevel) / 70.0f); - if (r > 1.0f) r = 1.0f; - int rr = (int)(r * 255); - int b = rr; - if (gl_enhanced_nightvision) b = b * 3 / 4; - color = PalEntry(255, rr, rr, b); - } - else if (in->IsKindOf(litetype)) - { - if (gl_enhanced_nightvision) - { - color = PalEntry(255, 104, 255, 104); - } - } - } - if (modulateColor) - { - *modulateColor = color; - } - } - - if (player) - { - V_AddPlayerBlend(player, blend, 0.5, 175); - } - - if (players[consoleplayer].camera != NULL) - { - // except for fadeto effects - player_t *player = (players[consoleplayer].camera->player != NULL) ? players[consoleplayer].camera->player : &players[consoleplayer]; - V_AddBlend(player->BlendR, player->BlendG, player->BlendB, player->BlendA, blend); - } - - const float br = clamp(blend[0] * 255.f, 0.f, 255.f); - const float bg = clamp(blend[1] * 255.f, 0.f, 255.f); - const float bb = clamp(blend[2] * 255.f, 0.f, 255.f); - return { br, bg, bb, blend[3] }; -} - -//========================================================================== -// -// Draws a blend over the entire view -// -//========================================================================== - -void DFrameBuffer::DrawBlend(sector_t * viewsector) -{ - PalEntry modulateColor; - auto blend = CalcBlend(viewsector, &modulateColor); - if (modulateColor != 0xffffffff) - { - Dim(modulateColor, 1, 0, 0, GetWidth(), GetHeight(), &LegacyRenderStyles[STYLE_Multiply]); - } - - const PalEntry bcolor(255, uint8_t(blend.X), uint8_t(blend.Y), uint8_t(blend.Z)); - Dim(bcolor, blend.W, 0, 0, GetWidth(), GetHeight()); -} - - diff --git a/src/rendering/2d/v_drawtext.cpp b/src/rendering/2d/v_drawtext.cpp deleted file mode 100644 index 4dff23df3b6..00000000000 --- a/src/rendering/2d/v_drawtext.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* -** v_text.cpp -** Draws text to a canvas. Also has a text line-breaker thingy. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#include -#include - -#include "v_text.h" -#include "utf8.h" - - -#include "v_video.h" -#include "w_wad.h" -#include "image.h" -#include "textures/formats/multipatchtexture.h" - -#include "gstrings.h" -#include "vm.h" -#include "serializer.h" - - -int ListGetInt(VMVa_List &tags); - - -//========================================================================== -// -// Create a texture from a text in a given font. -// -//========================================================================== -#if 0 -FTexture * BuildTextTexture(FFont *font, const char *string, int textcolor) -{ - int w; - const uint8_t *ch; - int cx; - int cy; - int trans = -1; - int kerning; - FTexture *pic; - - kerning = font->GetDefaultKerning(); - - ch = (const uint8_t *)string; - cx = 0; - cy = 0; - - - IntRect box; - - while (auto c = GetCharFromString(ch)) - { - if (c == TEXTCOLOR_ESCAPE) - { - // Here we only want to measure the texture so just parse over the color. - V_ParseFontColor(ch, 0, 0); - continue; - } - - if (c == '\n') - { - cx = 0; - cy += font->GetHeight(); - continue; - } - - if (nullptr != (pic = font->GetChar(c, CR_UNTRANSLATED, &w, nullptr))) - { - auto img = pic->GetImage(); - auto offsets = img->GetOffsets(); - int x = cx - offsets.first; - int y = cy - offsets.second; - int ww = img->GetWidth(); - int h = img->GetHeight(); - - box.AddToRect(x, y); - box.AddToRect(x + ww, y + h); - } - cx += (w + kerning); - } - - cx = -box.left; - cy = -box.top; - - TArray part(strlen(string)); - - while (auto c = GetCharFromString(ch)) - { - if (c == TEXTCOLOR_ESCAPE) - { - EColorRange newcolor = V_ParseFontColor(ch, textcolor, textcolor); - if (newcolor != CR_UNDEFINED) - { - trans = font->GetColorTranslation(newcolor); - textcolor = newcolor; - } - continue; - } - - if (c == '\n') - { - cx = 0; - cy += font->GetHeight(); - continue; - } - - if (nullptr != (pic = font->GetChar(c, textcolor, &w, nullptr))) - { - auto img = pic->GetImage(); - auto offsets = img->GetOffsets(); - int x = cx - offsets.first; - int y = cy - offsets.second; - - auto &tp = part[part.Reserve(1)]; - - tp.OriginX = x; - tp.OriginY = y; - tp.Image = img; - tp.Translation = range; - } - cx += (w + kerning); - } - FMultiPatchTexture *image = new FMultiPatchTexture(box.width, box.height, part, false, false); - image->SetOffsets(-box.left, -box.top); - FImageTexture *tex = new FImageTexture(image, ""); - tex->SetUseType(ETextureType::MiscPatch); - TexMan.AddTexture(tex); - return tex; -} -#endif - - -//========================================================================== -// -// DrawChar -// -// Write a single character using the given font -// -//========================================================================== - -void DFrameBuffer::DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...) -{ - if (font == NULL) - return; - - if (normalcolor >= NumTextColors) - normalcolor = CR_UNTRANSLATED; - - FTexture *pic; - int dummy; - bool redirected; - - if (NULL != (pic = font->GetChar (character, normalcolor, &dummy, &redirected))) - { - DrawParms parms; - Va_List tags; - va_start(tags.list, tag_first); - bool res = ParseDrawTextureTags(pic, x, y, tag_first, tags, &parms, false); - va_end(tags.list); - if (!res) - { - return; - } - PalEntry color = 0xffffffff; - parms.TranslationId = redirected? -1 : font->GetColorTranslation((EColorRange)normalcolor, &color); - parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255); - DrawTextureParms(pic, parms); - } -} - -void DFrameBuffer::DrawChar(FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args) -{ - if (font == NULL) - return; - - if (normalcolor >= NumTextColors) - normalcolor = CR_UNTRANSLATED; - - FTexture *pic; - int dummy; - bool redirected; - - if (NULL != (pic = font->GetChar(character, normalcolor, &dummy, &redirected))) - { - DrawParms parms; - uint32_t tag = ListGetInt(args); - bool res = ParseDrawTextureTags(pic, x, y, tag, args, &parms, false); - if (!res) return; - PalEntry color = 0xffffffff; - parms.TranslationId = redirected ? -1 : font->GetColorTranslation((EColorRange)normalcolor, &color); - parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255); - DrawTextureParms(pic, parms); - } -} - -DEFINE_ACTION_FUNCTION(_Screen, DrawChar) -{ - PARAM_PROLOGUE; - PARAM_POINTER(font, FFont); - PARAM_INT(cr); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_INT(chr); - - PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array - - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo + 5 }; - screen->DrawChar(font, cr, x, y, chr, args); - return 0; -} - -//========================================================================== -// -// DrawText -// -// Write a string using the given font -// -//========================================================================== - -// This is only needed as a dummy. The code using wide strings does not need color control. -EColorRange V_ParseFontColor(const char32_t *&color_value, int normalcolor, int boldcolor) { return CR_UNTRANSLATED; } - -template -void DFrameBuffer::DrawTextCommon(FFont *font, int normalcolor, double x, double y, const chartype *string, DrawParms &parms) -{ - int w; - const chartype *ch; - int c; - double cx; - double cy; - int boldcolor; - int trans = -1; - int kerning; - FTexture *pic; - - if (parms.celly == 0) parms.celly = font->GetHeight() + 1; - parms.celly *= parms.scaley; - - if (normalcolor >= NumTextColors) - normalcolor = CR_UNTRANSLATED; - boldcolor = normalcolor ? normalcolor - 1 : NumTextColors - 1; - - PalEntry colorparm = parms.color; - PalEntry color = 0xffffffff; - trans = font->GetColorTranslation((EColorRange)normalcolor, &color); - parms.color = PalEntry(colorparm.a, (color.r * colorparm.r) / 255, (color.g * colorparm.g) / 255, (color.b * colorparm.b) / 255); - - kerning = font->GetDefaultKerning(); - - ch = string; - cx = x; - cy = y; - - if (parms.monospace == EMonospacing::CellCenter) - cx += parms.spacing / 2; - else if (parms.monospace == EMonospacing::CellRight) - cx += parms.spacing; - - - auto currentcolor = normalcolor; - while (ch - string < parms.maxstrlen) - { - c = GetCharFromString(ch); - if (!c) - break; - - if (c == TEXTCOLOR_ESCAPE) - { - EColorRange newcolor = V_ParseFontColor(ch, normalcolor, boldcolor); - if (newcolor != CR_UNDEFINED) - { - trans = font->GetColorTranslation(newcolor, &color); - parms.color = PalEntry(colorparm.a, (color.r * colorparm.r) / 255, (color.g * colorparm.g) / 255, (color.b * colorparm.b) / 255); - currentcolor = newcolor; - } - continue; - } - - if (c == '\n') - { - cx = x; - cy += parms.celly; - continue; - } - - bool redirected = false; - if (NULL != (pic = font->GetChar(c, currentcolor, &w, &redirected))) - { - parms.TranslationId = redirected? -1 : trans; - SetTextureParms(&parms, pic, cx, cy); - if (parms.cellx) - { - w = parms.cellx; - parms.destwidth = parms.cellx; - parms.destheight = parms.celly; - } - if (parms.monospace == EMonospacing::CellLeft) - parms.left = 0; - else if (parms.monospace == EMonospacing::CellCenter) - parms.left = w / 2.; - else if (parms.monospace == EMonospacing::CellRight) - parms.left = w; - - DrawTextureParms(pic, parms); - } - if (parms.monospace == EMonospacing::Off) - { - cx += (w + kerning + parms.spacing) * parms.scalex; - } - else - { - cx += (parms.spacing) * parms.scalex; - } - - } -} - -void DFrameBuffer::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...) -{ - Va_List tags; - DrawParms parms; - - if (font == NULL || string == NULL) - return; - - va_start(tags.list, tag_first); - bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true); - va_end(tags.list); - if (!res) - { - return; - } - DrawTextCommon(font, normalcolor, x, y, (const uint8_t*)string, parms); -} - -void DFrameBuffer::DrawText(FFont *font, int normalcolor, double x, double y, const char32_t *string, int tag_first, ...) -{ - Va_List tags; - DrawParms parms; - - if (font == NULL || string == NULL) - return; - - va_start(tags.list, tag_first); - bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true); - va_end(tags.list); - if (!res) - { - return; - } - DrawTextCommon(font, normalcolor, x, y, string, parms); -} - -void DFrameBuffer::DrawText(FFont *font, int normalcolor, double x, double y, const char *string, VMVa_List &args) -{ - DrawParms parms; - - if (font == NULL || string == NULL) - return; - - uint32_t tag = ListGetInt(args); - bool res = ParseDrawTextureTags(nullptr, 0, 0, tag, args, &parms, true); - if (!res) - { - return; - } - DrawTextCommon(font, normalcolor, x, y, (const uint8_t*)string, parms); -} - -DEFINE_ACTION_FUNCTION(_Screen, DrawText) -{ - PARAM_PROLOGUE; - PARAM_POINTER_NOT_NULL(font, FFont); - PARAM_INT(cr); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_STRING(chr); - - PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array - - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo + 5 }; - const char *txt = chr[0] == '$' ? GStrings(&chr[1]) : chr.GetChars(); - screen->DrawText(font, cr, x, y, txt, args); - return 0; -} - diff --git a/src/rendering/gl/renderer/gl_renderer.cpp b/src/rendering/gl/renderer/gl_renderer.cpp deleted file mode 100644 index 6b722ad7115..00000000000 --- a/src/rendering/gl/renderer/gl_renderer.cpp +++ /dev/null @@ -1,402 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl1_renderer.cpp -** Renderer interface -** -*/ - -#include "gl_load/gl_system.h" -#include "files.h" -#include "v_video.h" -#include "m_png.h" -#include "w_wad.h" -#include "doomstat.h" -#include "i_time.h" -#include "p_effect.h" -#include "d_player.h" -#include "a_dynlight.h" -#include "cmdlib.h" -#include "g_game.h" -#include "swrenderer/r_swscene.h" -#include "hwrenderer/utility/hw_clock.h" - -#include "gl_load/gl_interface.h" -#include "gl/system/gl_framebuffer.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "gl/system/gl_debug.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_renderstate.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "gl/shaders/gl_shaderprogram.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/scene/hw_skydome.h" -#include "hwrenderer/scene/hw_fakeflat.h" -#include "gl/textures/gl_samplers.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "r_videoscale.h" -#include "r_data/models/models.h" -#include "gl/renderer/gl_postprocessstate.h" -#include "gl/system/gl_buffers.h" - -EXTERN_CVAR(Int, screenblocks) -EXTERN_CVAR(Bool, cl_capfps) - -extern bool NoInterpolateView; - -void DoWriteSavePic(FileWriter *file, ESSType ssformat, uint8_t *scr, int width, int height, sector_t *viewsector, bool upsidedown); - -namespace OpenGLRenderer -{ - -//=========================================================================== -// -// Renderer interface -// -//=========================================================================== - -//----------------------------------------------------------------------------- -// -// Initialize -// -//----------------------------------------------------------------------------- - -FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) -{ - framebuffer = fb; -} - -void FGLRenderer::Initialize(int width, int height) -{ - mScreenBuffers = new FGLRenderBuffers(); - mSaveBuffers = new FGLRenderBuffers(); - mBuffers = mScreenBuffers; - mPresentShader = new FPresentShader(); - mPresent3dCheckerShader = new FPresent3DCheckerShader(); - mPresent3dColumnShader = new FPresent3DColumnShader(); - mPresent3dRowShader = new FPresent3DRowShader(); - mShadowMapShader = new FShadowMapShader(); - - // needed for the core profile, because someone decided it was a good idea to remove the default VAO. - glGenQueries(1, &PortalQueryObject); - - glGenVertexArrays(1, &mVAOID); - glBindVertexArray(mVAOID); - FGLDebug::LabelObject(GL_VERTEX_ARRAY, mVAOID, "FGLRenderer.mVAOID"); - - mFBID = 0; - mOldFBID = 0; - - mShaderManager = new FShaderManager; - mSamplerManager = new FSamplerManager; -} - -FGLRenderer::~FGLRenderer() -{ - FlushModels(); - TexMan.FlushAll(); - if (mShaderManager != nullptr) delete mShaderManager; - if (mSamplerManager != nullptr) delete mSamplerManager; - if (mFBID != 0) glDeleteFramebuffers(1, &mFBID); - if (mVAOID != 0) - { - glBindVertexArray(0); - glDeleteVertexArrays(1, &mVAOID); - } - if (PortalQueryObject != 0) glDeleteQueries(1, &PortalQueryObject); - - if (swdrawer) delete swdrawer; - if (mBuffers) delete mBuffers; - if (mSaveBuffers) delete mSaveBuffers; - if (mPresentShader) delete mPresentShader; - if (mPresent3dCheckerShader) delete mPresent3dCheckerShader; - if (mPresent3dColumnShader) delete mPresent3dColumnShader; - if (mPresent3dRowShader) delete mPresent3dRowShader; - if (mShadowMapShader) delete mShadowMapShader; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FGLRenderer::ResetSWScene() -{ - // force recreation of the SW scene drawer to ensure it gets a new set of resources. - if (swdrawer != nullptr) delete swdrawer; - swdrawer = nullptr; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -bool FGLRenderer::StartOffscreen() -{ - bool firstBind = (mFBID == 0); - if (mFBID == 0) - glGenFramebuffers(1, &mFBID); - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mOldFBID); - glBindFramebuffer(GL_FRAMEBUFFER, mFBID); - if (firstBind) - FGLDebug::LabelObject(GL_FRAMEBUFFER, mFBID, "OffscreenFB"); - return true; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FGLRenderer::EndOffscreen() -{ - glBindFramebuffer(GL_FRAMEBUFFER, mOldFBID); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FGLRenderer::UpdateShadowMap() -{ - if (screen->mShadowMap.PerformUpdate()) - { - FGLDebug::PushGroup("ShadowMap"); - - FGLPostProcessState savedState; - - static_cast(screen->mShadowMap.mLightList)->BindBase(); - static_cast(screen->mShadowMap.mNodesBuffer)->BindBase(); - static_cast(screen->mShadowMap.mLinesBuffer)->BindBase(); - - mBuffers->BindShadowMapFB(); - - mShadowMapShader->Bind(); - mShadowMapShader->Uniforms->ShadowmapQuality = gl_shadowmap_quality; - mShadowMapShader->Uniforms->NodesCount = screen->mShadowMap.NodesCount(); - mShadowMapShader->Uniforms.SetData(); - static_cast(mShadowMapShader->Uniforms.GetBuffer())->BindBase(); - - glViewport(0, 0, gl_shadowmap_quality, 1024); - RenderScreenQuad(); - - const auto &viewport = screen->mScreenViewport; - glViewport(viewport.left, viewport.top, viewport.width, viewport.height); - - mBuffers->BindShadowMapTexture(16); - FGLDebug::PopGroup(); - screen->mShadowMap.FinishUpdate(); - } -} - -//----------------------------------------------------------------------------- -// -// renders the view -// -//----------------------------------------------------------------------------- - -sector_t *FGLRenderer::RenderView(player_t* player) -{ - gl_RenderState.SetVertexBuffer(screen->mVertexData); - screen->mVertexData->Reset(); - sector_t *retsec; - - if (!V_IsHardwareRenderer()) - { - if (swdrawer == nullptr) swdrawer = new SWSceneDrawer; - retsec = swdrawer->RenderView(player); - } - else - { - hw_ClearFakeFlat(); - - iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; - - checkBenchActive(); - - // reset statistics counters - ResetProfilingData(); - - // Get this before everything else - if (cl_capfps || r_NoInterpolate) r_viewpoint.TicFrac = 1.; - else r_viewpoint.TicFrac = I_GetTimeFrac(); - - screen->mLights->Clear(); - screen->mViewpoints->Clear(); - - // NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below. - bool saved_niv = NoInterpolateView; - NoInterpolateView = false; - - // Shader start time does not need to be handled per level. Just use the one from the camera to render from. - if (player->camera) - gl_RenderState.CheckTimer(player->camera->Level->ShaderStartTime); - // prepare all camera textures that have been used in the last frame. - // This must be done for all levels, not just the primary one! - for (auto Level : AllLevels()) - { - Level->canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov) - { - RenderTextureView(camtex, camera, fov); - }); - } - NoInterpolateView = saved_niv; - - - // now render the main view - float fovratio; - float ratio = r_viewwindow.WidescreenRatio; - if (r_viewwindow.WidescreenRatio >= 1.3f) - { - fovratio = 1.333333f; - } - else - { - fovratio = ratio; - } - - retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true); - } - All.Unclock(); - return retsec; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FGLRenderer::BindToFrameBuffer(FMaterial *mat) -{ - auto BaseLayer = static_cast(mat->GetLayer(0, 0)); - - if (BaseLayer == nullptr) - { - // must create the hardware texture first - BaseLayer->BindOrCreate(mat->sourcetex, 0, 0, 0, 0); - FHardwareTexture::Unbind(0); - gl_RenderState.ClearLastMaterial(); - } - BaseLayer->BindToFrameBuffer(mat->GetWidth(), mat->GetHeight()); -} - -//=========================================================================== -// -// Camera texture rendering -// -//=========================================================================== - -void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) -{ - // This doesn't need to clear the fake flat cache. It can be shared between camera textures and the main view of a scene. - FMaterial * gltex = FMaterial::ValidateTexture(tex, false); - - int width = gltex->TextureWidth(); - int height = gltex->TextureHeight(); - - StartOffscreen(); - BindToFrameBuffer(gltex); - - IntRect bounds; - bounds.left = bounds.top = 0; - bounds.width = FHardwareTexture::GetTexDimension(gltex->GetWidth()); - bounds.height = FHardwareTexture::GetTexDimension(gltex->GetHeight()); - - FRenderViewpoint texvp; - RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false); - - EndOffscreen(); - - tex->SetUpdated(true); - static_cast(screen)->camtexcount++; -} - -//=========================================================================== -// -// Render the view to a savegame picture -// -//=========================================================================== - -void FGLRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height) -{ - IntRect bounds; - bounds.left = 0; - bounds.top = 0; - bounds.width = width; - bounds.height = height; - - // we must be sure the GPU finished reading from the buffer before we fill it with new data. - glFinish(); - - // Switch to render buffers dimensioned for the savepic - mBuffers = mSaveBuffers; - - hw_ClearFakeFlat(); - gl_RenderState.SetVertexBuffer(screen->mVertexData); - screen->mVertexData->Reset(); - screen->mLights->Clear(); - screen->mViewpoints->Clear(); - - // This shouldn't overwrite the global viewpoint even for a short time. - FRenderViewpoint savevp; - sector_t *viewsector = RenderViewpoint(savevp, players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false); - glDisable(GL_STENCIL_TEST); - gl_RenderState.SetNoSoftLightLevel(); - CopyToBackbuffer(&bounds, false); - - // strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers - glFinish(); - - int numpixels = width * height; - uint8_t * scr = (uint8_t *)M_Malloc(numpixels * 3); - glReadPixels(0,0,width, height,GL_RGB,GL_UNSIGNED_BYTE,scr); - - DoWriteSavePic(file, SS_RGB, scr, width, height, viewsector, true); - M_Free(scr); - - // Switch back the screen render buffers - screen->SetViewportRects(nullptr); - mBuffers = mScreenBuffers; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FGLRenderer::BeginFrame() -{ - mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height); - mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT); -} - -} diff --git a/src/rendering/gl/renderer/gl_renderer.h b/src/rendering/gl/renderer/gl_renderer.h deleted file mode 100644 index 91ac325d5e3..00000000000 --- a/src/rendering/gl/renderer/gl_renderer.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef __GL_RENDERER_H -#define __GL_RENDERER_H - -#include "r_defs.h" -#include "v_video.h" -#include "vectors.h" -#include "swrenderer/r_renderer.h" -#include "matrix.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/dynlights/hw_shadowmap.h" -#include - -#ifdef _MSC_VER -#pragma warning(disable:4244) -#endif - -struct particle_t; -class FCanvasTexture; -class FFlatVertexBuffer; -class FSkyVertexBuffer; -class FShaderManager; -class HWPortal; -class FLightBuffer; -class DPSprite; -class FGLRenderBuffers; -class FGL2DDrawer; -class FHardwareTexture; -class SWSceneDrawer; -class HWViewpointBuffer; -struct FRenderViewpoint; - -namespace OpenGLRenderer -{ - class FSamplerManager; - class OpenGLFrameBuffer; - class FPresentShaderBase; - class FPresentShader; - class FPresent3DCheckerShader; - class FPresent3DColumnShader; - class FPresent3DRowShader; - class FShadowMapShader; - -class FGLRenderer -{ -public: - - OpenGLFrameBuffer *framebuffer; - int mMirrorCount = 0; - int mPlaneMirrorCount = 0; - FShaderManager *mShaderManager = nullptr; - FSamplerManager *mSamplerManager = nullptr; - unsigned int mFBID; - unsigned int mVAOID; - unsigned int PortalQueryObject; - unsigned int mStencilValue = 0; - - int mOldFBID; - - FGLRenderBuffers *mBuffers = nullptr; - FGLRenderBuffers *mScreenBuffers = nullptr; - FGLRenderBuffers *mSaveBuffers = nullptr; - FPresentShader *mPresentShader = nullptr; - FPresent3DCheckerShader *mPresent3dCheckerShader = nullptr; - FPresent3DColumnShader *mPresent3dColumnShader = nullptr; - FPresent3DRowShader *mPresent3dRowShader = nullptr; - FShadowMapShader *mShadowMapShader = nullptr; - - //FRotator mAngles; - - SWSceneDrawer *swdrawer = nullptr; - - FGLRenderer(OpenGLFrameBuffer *fb); - ~FGLRenderer() ; - - void Initialize(int width, int height); - - void ClearBorders(); - - void ResetSWScene(); - - void PresentStereo(); - void RenderScreenQuad(); - void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D); - void AmbientOccludeScene(float m5); - void ClearTonemapPalette(); - void BlurScene(float gameinfobluramount); - void CopyToBackbuffer(const IntRect *bounds, bool applyGamma); - void DrawPresentTexture(const IntRect &box, bool applyGamma); - void Flush(); - void Draw2D(F2DDrawer *data); - void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV); - void WriteSavePic(player_t *player, FileWriter *file, int width, int height); - sector_t *RenderView(player_t *player); - void BeginFrame(); - - sector_t *RenderViewpoint (FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen); - - - bool StartOffscreen(); - void EndOffscreen(); - void UpdateShadowMap(); - - void BindToFrameBuffer(FMaterial *mat); - -private: - - void DrawScene(HWDrawInfo *di, int drawmode); - bool QuadStereoCheckInitialRenderContextState(); - void PresentAnaglyph(bool r, bool g, bool b); - void PresentSideBySide(); - void PresentTopBottom(); - void prepareInterleavedPresent(FPresentShaderBase& shader); - void PresentColumnInterleaved(); - void PresentRowInterleaved(); - void PresentCheckerInterleaved(); - void PresentQuadStereo(); - -}; - -struct TexFilter_s -{ - int minfilter; - int magfilter; - bool mipmapping; -} ; - - -extern FGLRenderer *GLRenderer; - -} -#endif diff --git a/src/rendering/gl/renderer/gl_scene.cpp b/src/rendering/gl/renderer/gl_scene.cpp deleted file mode 100644 index af6c6e58158..00000000000 --- a/src/rendering/gl/renderer/gl_scene.cpp +++ /dev/null @@ -1,227 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2004-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_scene.cpp -** manages the rendering of the player's view -** -*/ - -#include "gl_load/gl_system.h" -#include "gi.h" -#include "m_png.h" -#include "doomstat.h" -#include "g_level.h" -#include "r_data/r_interpolate.h" -#include "r_utility.h" -#include "d_player.h" -#include "p_effect.h" -#include "sbar.h" -#include "po_man.h" -#include "p_local.h" -#include "serializer.h" -#include "g_levellocals.h" -#include "actorinlines.h" -#include "r_data/models/models.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/data/flatvertices.h" - -#include "hwrenderer/dynlights/hw_lightbuffer.h" -#include "gl_load/gl_interface.h" -#include "gl/system/gl_framebuffer.h" -#include "gl/system/gl_debug.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "gl/renderer/gl_renderstate.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "hwrenderer/scene/hw_clipper.h" -#include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/system/gl_buffers.h" - -//========================================================================== -// -// CVARs -// -//========================================================================== -CVAR(Bool, gl_texture, true, 0) -CVAR(Bool, gl_no_skyclear, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR(Float, gl_mask_threshold, 0.5f,CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR(Float, gl_mask_sprite_threshold, 0.5f,CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -EXTERN_CVAR (Bool, cl_capfps) -EXTERN_CVAR (Bool, r_deathcamera) -EXTERN_CVAR (Float, r_visibility) -EXTERN_CVAR (Bool, r_drawvoxels) - - -namespace OpenGLRenderer -{ - -//----------------------------------------------------------------------------- -// -// gl_drawscene - this function renders the scene from the current -// viewpoint, including mirrors and skyboxes and other portals -// It is assumed that the HWPortal::EndFrame returns with the -// stencil, z-buffer and the projection matrix intact! -// -//----------------------------------------------------------------------------- - -void FGLRenderer::DrawScene(HWDrawInfo *di, int drawmode) -{ - static int recursion=0; - static int ssao_portals_available = 0; - const auto &vp = di->Viewpoint; - - bool applySSAO = false; - if (drawmode == DM_MAINVIEW) - { - ssao_portals_available = gl_ssao_portals; - applySSAO = true; - } - else if (drawmode == DM_OFFSCREEN) - { - ssao_portals_available = 0; - } - else if (drawmode == DM_PORTAL && ssao_portals_available > 0) - { - applySSAO = true; - ssao_portals_available--; - } - - if (vp.camera != nullptr) - { - ActorRenderFlags savedflags = vp.camera->renderflags; - di->CreateScene(drawmode == DM_MAINVIEW); - vp.camera->renderflags = savedflags; - } - else - { - di->CreateScene(false); - } - - glDepthMask(true); - if (!gl_no_skyclear) screen->mPortalState->RenderFirstSkyPortal(recursion, di, gl_RenderState); - - di->RenderScene(gl_RenderState); - - if (applySSAO && gl_RenderState.GetPassType() == GBUFFER_PASS) - { - gl_RenderState.EnableDrawBuffers(1); - GLRenderer->AmbientOccludeScene(di->VPUniforms.mProjectionMatrix.get()[5]); - glViewport(screen->mSceneViewport.left, screen->mSceneViewport.top, screen->mSceneViewport.width, screen->mSceneViewport.height); - GLRenderer->mBuffers->BindSceneFB(true); - gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); - gl_RenderState.Apply(); - screen->mViewpoints->Bind(gl_RenderState, di->vpIndex); - } - - // Handle all portals after rendering the opaque objects but before - // doing all translucent stuff - recursion++; - screen->mPortalState->EndFrame(di, gl_RenderState); - recursion--; - di->RenderTranslucent(gl_RenderState); -} - -//----------------------------------------------------------------------------- -// -// Renders one viewpoint in a scene -// -//----------------------------------------------------------------------------- - -sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen) -{ - R_SetupFrame (mainvp, r_viewwindow, camera); - - if (mainview && toscreen) - UpdateShadowMap(); - - // Update the attenuation flag of all light defaults for each viewpoint. - // This function will only do something if the setting differs. - FLightDefaults::SetAttenuationForLevel(!!(camera->Level->flags3 & LEVEL3_ATTENUATE)); - - // Render (potentially) multiple views for stereo 3d - // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. - auto vrmode = VRMode::GetVRMode(mainview && toscreen); - const int eyeCount = vrmode->mEyeCount; - mBuffers->CurrentEye() = 0; // always begin at zero, in case eye count changed - for (int eye_ix = 0; eye_ix < eyeCount; ++eye_ix) - { - const auto &eye = vrmode->mEyes[mBuffers->CurrentEye()]; - screen->SetViewportRects(bounds); - - if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao - { - bool useSSAO = (gl_ssao != 0); - mBuffers->BindSceneFB(useSSAO); - gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); - gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); - gl_RenderState.Apply(); - } - - - auto di = HWDrawInfo::StartDrawInfo(mainvp.ViewLevel, nullptr, mainvp, nullptr); - auto &vp = di->Viewpoint; - - di->Set3DViewport(gl_RenderState); - di->SetViewArea(); - auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr); - di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint) - - // Stereo mode specific perspective projection - di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio); - // Stereo mode specific viewpoint adjustment - vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees); - di->SetupView(gl_RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); - - // std::function until this can be done better in a cross-API fashion. - di->ProcessScene(toscreen, [&](HWDrawInfo *di, int mode) { - DrawScene(di, mode); - }); - - if (mainview) - { - PostProcess.Clock(); - if (toscreen) di->EndDrawScene(mainvp.sector, gl_RenderState); // do not call this for camera textures. - - if (gl_RenderState.GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers - { - gl_RenderState.SetPassType(NORMAL_PASS); - gl_RenderState.EnableDrawBuffers(1); - } - - mBuffers->BlitSceneToTexture(); // Copy the resulting scene to the current post process texture - - PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector, gl_RenderState); }); - PostProcess.Unclock(); - } - di->EndDrawInfo(); - if (eyeCount - eye_ix > 1) - mBuffers->NextEye(eyeCount); - } - - return mainvp.sector; -} - -} diff --git a/src/rendering/gl/renderer/gl_stereo3d.cpp b/src/rendering/gl/renderer/gl_stereo3d.cpp deleted file mode 100644 index fe5b29b2258..00000000000 --- a/src/rendering/gl/renderer/gl_stereo3d.cpp +++ /dev/null @@ -1,386 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_stereo3d.cpp -** Stereoscopic 3D API -** -*/ - -#include "gl_load/gl_system.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "gl/system/gl_framebuffer.h" -#include "gl/renderer/gl_postprocessstate.h" -#include "gl/system/gl_framebuffer.h" -#include "gl/shaders/gl_shaderprogram.h" -#include "gl/system/gl_buffers.h" -#include "menu/menu.h" - -EXTERN_CVAR(Int, vr_mode) -EXTERN_CVAR(Float, vid_saturation) -EXTERN_CVAR(Float, vid_brightness) -EXTERN_CVAR(Float, vid_contrast) -EXTERN_CVAR(Int, gl_satformula) -EXTERN_CVAR(Int, gl_dither_bpc) - -namespace OpenGLRenderer -{ - -//========================================================================== -// -// -// -//========================================================================== - -void FGLRenderer::PresentAnaglyph(bool r, bool g, bool b) -{ - mBuffers->BindOutputFB(); - ClearBorders(); - - glColorMask(r, g, b, 1); - mBuffers->BindEyeTexture(0, 0); - DrawPresentTexture(screen->mOutputLetterbox, true); - - glColorMask(!r, !g, !b, 1); - mBuffers->BindEyeTexture(1, 0); - DrawPresentTexture(screen->mOutputLetterbox, true); - - glColorMask(1, 1, 1, 1); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FGLRenderer::PresentSideBySide() -{ - mBuffers->BindOutputFB(); - ClearBorders(); - - // Compute screen regions to use for left and right eye views - int leftWidth = screen->mOutputLetterbox.width / 2; - int rightWidth = screen->mOutputLetterbox.width - leftWidth; - IntRect leftHalfScreen = screen->mOutputLetterbox; - leftHalfScreen.width = leftWidth; - IntRect rightHalfScreen = screen->mOutputLetterbox; - rightHalfScreen.width = rightWidth; - rightHalfScreen.left += leftWidth; - - mBuffers->BindEyeTexture(0, 0); - DrawPresentTexture(leftHalfScreen, true); - - mBuffers->BindEyeTexture(1, 0); - DrawPresentTexture(rightHalfScreen, true); -} - - -//========================================================================== -// -// -// -//========================================================================== - -void FGLRenderer::PresentTopBottom() -{ - mBuffers->BindOutputFB(); - ClearBorders(); - - // Compute screen regions to use for left and right eye views - int topHeight = screen->mOutputLetterbox.height / 2; - int bottomHeight = screen->mOutputLetterbox.height - topHeight; - IntRect topHalfScreen = screen->mOutputLetterbox; - topHalfScreen.height = topHeight; - topHalfScreen.top = topHeight; - IntRect bottomHalfScreen = screen->mOutputLetterbox; - bottomHalfScreen.height = bottomHeight; - bottomHalfScreen.top = 0; - - mBuffers->BindEyeTexture(0, 0); - DrawPresentTexture(topHalfScreen, true); - - mBuffers->BindEyeTexture(1, 0); - DrawPresentTexture(bottomHalfScreen, true); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FGLRenderer::prepareInterleavedPresent(FPresentShaderBase& shader) -{ - mBuffers->BindOutputFB(); - ClearBorders(); - - - // Bind each eye texture, for composition in the shader - mBuffers->BindEyeTexture(0, 0); - mBuffers->BindEyeTexture(1, 1); - - glActiveTexture(GL_TEXTURE0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glActiveTexture(GL_TEXTURE1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - const IntRect& box = screen->mOutputLetterbox; - glViewport(box.left, box.top, box.width, box.height); - - shader.Bind(); - - if (framebuffer->IsHWGammaActive()) - { - shader.Uniforms->InvGamma = 1.0f; - shader.Uniforms->Contrast = 1.0f; - shader.Uniforms->Brightness = 0.0f; - shader.Uniforms->Saturation = 1.0f; - } - else - { - shader.Uniforms->InvGamma = 1.0f / clamp(Gamma, 0.1f, 4.f); - shader.Uniforms->Contrast = clamp(vid_contrast, 0.1f, 3.f); - shader.Uniforms->Brightness = clamp(vid_brightness, -0.8f, 0.8f); - shader.Uniforms->Saturation = clamp(vid_saturation, -15.0f, 15.0f); - shader.Uniforms->GrayFormula = static_cast(gl_satformula); - } - shader.Uniforms->HdrMode = 0; - shader.Uniforms->ColorScale = (gl_dither_bpc == -1) ? 255.0f : (float)((1 << gl_dither_bpc) - 1); - shader.Uniforms->Scale = { - screen->mScreenViewport.width / (float)mBuffers->GetWidth(), - screen->mScreenViewport.height / (float)mBuffers->GetHeight() - }; - shader.Uniforms->Offset = { 0.0f, 0.0f }; - shader.Uniforms.SetData(); - static_cast(shader.Uniforms.GetBuffer())->BindBase(); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FGLRenderer::PresentColumnInterleaved() -{ - FGLPostProcessState savedState; - savedState.SaveTextureBindings(2); - prepareInterleavedPresent(*mPresent3dColumnShader); - - // Compute absolute offset from top of screen to top of current display window - // because we need screen-relative, not window-relative, scan line parity - - // Todo: - //auto clientoffset = screen->GetClientOffset(); - //auto windowHOffset = clientoffset.X % 2; - int windowHOffset = 0; - - mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset; - mPresent3dColumnShader->Uniforms.SetData(); - static_cast(mPresent3dColumnShader->Uniforms.GetBuffer())->BindBase(); - - RenderScreenQuad(); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FGLRenderer::PresentRowInterleaved() -{ - FGLPostProcessState savedState; - savedState.SaveTextureBindings(2); - prepareInterleavedPresent(*mPresent3dRowShader); - - // Todo: - //auto clientoffset = screen->GetClientOffset(); - //auto windowVOffset = clientoffset.Y % 2; - int windowVOffset = 0; - - mPresent3dRowShader->Uniforms->WindowPositionParity = - (windowVOffset - + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom - ) % 2; - - mPresent3dRowShader->Uniforms.SetData(); - static_cast(mPresent3dRowShader->Uniforms.GetBuffer())->BindBase(); - RenderScreenQuad(); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FGLRenderer::PresentCheckerInterleaved() -{ - FGLPostProcessState savedState; - savedState.SaveTextureBindings(2); - prepareInterleavedPresent(*mPresent3dCheckerShader); - - // Compute absolute offset from top of screen to top of current display window - // because we need screen-relative, not window-relative, scan line parity - - //auto clientoffset = screen->GetClientOffset(); - //auto windowHOffset = clientoffset.X % 2; - //auto windowVOffset = clientoffset.Y % 2; - int windowHOffset = 0; - int windowVOffset = 0; - - mPresent3dCheckerShader->Uniforms->WindowPositionParity = - (windowVOffset - + windowHOffset - + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom - ) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset - - mPresent3dCheckerShader->Uniforms.SetData(); - static_cast(mPresent3dCheckerShader->Uniforms.GetBuffer())->BindBase(); - RenderScreenQuad(); -} - -//========================================================================== -// -// Sometimes the stereo render context is not ready immediately at start up -// -//========================================================================== - -bool FGLRenderer::QuadStereoCheckInitialRenderContextState() -{ - // Keep trying until we see at least one good OpenGL context to render to - bool bQuadStereoSupported = false; - bool bDecentContextWasFound = false; - int contextCheckCount = 0; - if ((!bDecentContextWasFound) && (contextCheckCount < 200)) - { - contextCheckCount += 1; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context - GLboolean supportsStereo, supportsBuffered; - glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered); - if (supportsBuffered) // Finally, a useful OpenGL context - { - // This block will be executed exactly ONCE during a game run - bDecentContextWasFound = true; // now we can stop checking every frame... - // Now check whether this context supports hardware stereo - glGetBooleanv(GL_STEREO, &supportsStereo); - bQuadStereoSupported = supportsStereo && supportsBuffered; - if (! bQuadStereoSupported) - UpdateVRModes(false); - } - } - return bQuadStereoSupported; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FGLRenderer::PresentQuadStereo() -{ - if (QuadStereoCheckInitialRenderContextState()) - { - mBuffers->BindOutputFB(); - - glDrawBuffer(GL_BACK_LEFT); - ClearBorders(); - mBuffers->BindEyeTexture(0, 0); - DrawPresentTexture(screen->mOutputLetterbox, true); - - glDrawBuffer(GL_BACK_RIGHT); - ClearBorders(); - mBuffers->BindEyeTexture(1, 0); - DrawPresentTexture(screen->mOutputLetterbox, true); - - glDrawBuffer(GL_BACK); - } - else - { - mBuffers->BindOutputFB(); - ClearBorders(); - mBuffers->BindEyeTexture(0, 0); - DrawPresentTexture(screen->mOutputLetterbox, true); - } -} - - -void FGLRenderer::PresentStereo() -{ - auto vrmode = VRMode::GetVRMode(true); - const int eyeCount = vrmode->mEyeCount; - // Don't invalidate the bound framebuffer (..., false) - if (eyeCount > 1) - mBuffers->BlitToEyeTexture(mBuffers->CurrentEye(), false); - - switch (vr_mode) - { - default: - return; - - case VR_GREENMAGENTA: - PresentAnaglyph(false, true, false); - break; - - case VR_REDCYAN: - PresentAnaglyph(true, false, false); - break; - - case VR_AMBERBLUE: - PresentAnaglyph(true, true, false); - break; - - case VR_SIDEBYSIDEFULL: - case VR_SIDEBYSIDESQUISHED: - PresentSideBySide(); - break; - - case VR_TOPBOTTOM: - PresentTopBottom(); - break; - - case VR_ROWINTERLEAVED: - PresentRowInterleaved(); - break; - - case VR_COLUMNINTERLEAVED: - PresentColumnInterleaved(); - break; - - case VR_CHECKERINTERLEAVED: - PresentCheckerInterleaved(); - break; - - case VR_QUADSTEREO: - PresentQuadStereo(); - break; - } -} - -} \ No newline at end of file diff --git a/src/rendering/gl/shaders/gl_shader.cpp b/src/rendering/gl/shaders/gl_shader.cpp deleted file mode 100644 index 939faf557d6..00000000000 --- a/src/rendering/gl/shaders/gl_shader.cpp +++ /dev/null @@ -1,837 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2004-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_shader.cpp -** -** GLSL shader handling -** -*/ - -#include "gl_load/gl_system.h" -#include "c_cvars.h" -#include "v_video.h" -#include "w_wad.h" -#include "doomerrors.h" -#include "cmdlib.h" -#include "md5.h" -#include "m_misc.h" -#include "hwrenderer/utility/hw_shaderpatcher.h" -#include "hwrenderer/data/shaderuniforms.h" -#include "hwrenderer/scene/hw_viewpointuniforms.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" - -#include "gl_load/gl_interface.h" -#include "gl/system/gl_debug.h" -#include "matrix.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/shaders/gl_shader.h" -#include -#include - -namespace OpenGLRenderer -{ - -struct ProgramBinary -{ - uint32_t format; - TArray data; -}; - -static const char *ShaderMagic = "ZDSC"; - -static std::map> ShaderCache; // Not a TMap because it doesn't support unique_ptr move semantics - -bool IsShaderCacheActive() -{ - static bool active = true; - static bool firstcall = true; - - if (firstcall) - { - const char *vendor = (const char *)glGetString(GL_VENDOR); - active = !(strstr(vendor, "Intel") == nullptr); - firstcall = false; - } - return active; -} - -static FString CalcProgramBinaryChecksum(const FString &vertex, const FString &fragment) -{ - const GLubyte *vendor = glGetString(GL_VENDOR); - const GLubyte *renderer = glGetString(GL_RENDERER); - const GLubyte *version = glGetString(GL_VERSION); - - uint8_t digest[16]; - MD5Context md5; - md5.Update(vendor, (unsigned int)strlen((const char*)vendor)); - md5.Update(renderer, (unsigned int)strlen((const char*)renderer)); - md5.Update(version, (unsigned int)strlen((const char*)version)); - md5.Update((const uint8_t *)vertex.GetChars(), (unsigned int)vertex.Len()); - md5.Update((const uint8_t *)fragment.GetChars(), (unsigned int)fragment.Len()); - md5.Final(digest); - - char hexdigest[33]; - for (int i = 0; i < 16; i++) - { - int v = digest[i] >> 4; - hexdigest[i * 2] = v < 10 ? ('0' + v) : ('a' + v - 10); - v = digest[i] & 15; - hexdigest[i * 2 + 1] = v < 10 ? ('0' + v) : ('a' + v - 10); - } - hexdigest[32] = 0; - return hexdigest; -} - -static FString CreateProgramCacheName(bool create) -{ - FString path = M_GetCachePath(create); - if (create) CreatePath(path); - path << "/shadercache.zdsc"; - return path; -} - -static void LoadShaders() -{ - static bool loaded = false; - if (loaded) - return; - loaded = true; - - try - { - FString path = CreateProgramCacheName(false); - FileReader fr; - if (!fr.OpenFile(path)) - I_Error("Could not open shader file"); - - char magic[4]; - fr.Read(magic, 4); - if (memcmp(magic, ShaderMagic, 4) != 0) - I_Error("Not a shader cache file"); - - uint32_t count = fr.ReadUInt32(); - if (count > 512) - I_Error("Too many shaders cached"); - - for (uint32_t i = 0; i < count; i++) - { - char hexdigest[33]; - if (fr.Read(hexdigest, 32) != 32) - I_Error("Read error"); - hexdigest[32] = 0; - - std::unique_ptr binary(new ProgramBinary()); - binary->format = fr.ReadUInt32(); - uint32_t size = fr.ReadUInt32(); - if (size > 1024 * 1024) - I_Error("Shader too big, probably file corruption"); - - binary->data.Resize(size); - if (fr.Read(binary->data.Data(), binary->data.Size()) != binary->data.Size()) - I_Error("Read error"); - - ShaderCache[hexdigest] = std::move(binary); - } - } - catch (...) - { - ShaderCache.clear(); - } -} - -static void SaveShaders() -{ - FString path = CreateProgramCacheName(true); - std::unique_ptr fw(FileWriter::Open(path)); - if (fw) - { - uint32_t count = (uint32_t)ShaderCache.size(); - fw->Write(ShaderMagic, 4); - fw->Write(&count, sizeof(uint32_t)); - for (const auto &it : ShaderCache) - { - uint32_t size = it.second->data.Size(); - fw->Write(it.first.GetChars(), 32); - fw->Write(&it.second->format, sizeof(uint32_t)); - fw->Write(&size, sizeof(uint32_t)); - fw->Write(it.second->data.Data(), it.second->data.Size()); - } - } -} - -TArray LoadCachedProgramBinary(const FString &vertex, const FString &fragment, uint32_t &binaryFormat) -{ - LoadShaders(); - - auto it = ShaderCache.find(CalcProgramBinaryChecksum(vertex, fragment)); - if (it != ShaderCache.end()) - { - binaryFormat = it->second->format; - return it->second->data; - } - else - { - binaryFormat = 0; - return {}; - } -} - -void SaveCachedProgramBinary(const FString &vertex, const FString &fragment, const TArray &binary, uint32_t binaryFormat) -{ - auto &entry = ShaderCache[CalcProgramBinaryChecksum(vertex, fragment)]; - entry.reset(new ProgramBinary()); - entry->format = binaryFormat; - entry->data = binary; - - SaveShaders(); -} - -bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * light_fragprog, const char * defines) -{ - static char buffer[10000]; - FString error; - - FString i_data = R"( - // these settings are actually pointless but there seem to be some old ATI drivers that fail to compile the shader without setting the precision here. - precision highp int; - precision highp float; - - // This must match the HWViewpointUniforms struct - layout(std140) uniform ViewpointUBO { - mat4 ProjectionMatrix; - mat4 ViewMatrix; - mat4 NormalViewMatrix; - - vec4 uCameraPos; - vec4 uClipLine; - - float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 - int uPalLightLevels; - int uViewHeight; // Software fuzz scaling - float uClipHeight; - float uClipHeightDirection; - int uShadowmapFilter; - }; - )"; - - i_data += "uniform int uTextureMode;\n"; - i_data += "uniform vec2 uClipSplit;\n"; - i_data += "uniform float uAlphaThreshold;\n"; - - // colors - i_data += "uniform vec4 uObjectColor;\n"; - i_data += "uniform vec4 uObjectColor2;\n"; - i_data += "uniform vec4 uDynLightColor;\n"; - i_data += "uniform vec4 uAddColor;\n"; - i_data += "uniform vec4 uTextureBlendColor;\n"; - i_data += "uniform vec4 uTextureModulateColor;\n"; - i_data += "uniform vec4 uTextureAddColor;\n"; - i_data += "uniform vec4 uBlendColor;\n"; - i_data += "uniform vec4 uFogColor;\n"; - i_data += "uniform float uDesaturationFactor;\n"; - i_data += "uniform float uInterpolationFactor;\n"; - - // Glowing walls stuff - i_data += "uniform vec4 uGlowTopPlane;\n"; - i_data += "uniform vec4 uGlowTopColor;\n"; - i_data += "uniform vec4 uGlowBottomPlane;\n"; - i_data += "uniform vec4 uGlowBottomColor;\n"; - - i_data += "uniform vec4 uGradientTopPlane;\n"; - i_data += "uniform vec4 uGradientBottomPlane;\n"; - - i_data += "uniform vec4 uSplitTopPlane;\n"; - i_data += "uniform vec4 uSplitBottomPlane;\n"; - - // Lighting + Fog - i_data += "uniform vec4 uLightAttr;\n"; - i_data += "#define uLightLevel uLightAttr.a\n"; - i_data += "#define uFogDensity uLightAttr.b\n"; - i_data += "#define uLightFactor uLightAttr.g\n"; - i_data += "#define uLightDist uLightAttr.r\n"; - i_data += "uniform int uFogEnabled;\n"; - - // dynamic lights - i_data += "uniform int uLightIndex;\n"; - - // Blinn glossiness and specular level - i_data += "uniform vec2 uSpecularMaterial;\n"; - - // matrices - i_data += "uniform mat4 ModelMatrix;\n"; - i_data += "uniform mat4 NormalModelMatrix;\n"; - i_data += "uniform mat4 TextureMatrix;\n"; - - // light buffers - i_data += "#ifdef SHADER_STORAGE_LIGHTS\n"; - i_data += "layout(std430, binding = 1) buffer LightBufferSSO\n"; - i_data += "{\n"; - i_data += " vec4 lights[];\n"; - i_data += "};\n"; - i_data += "#elif defined NUM_UBO_LIGHTS\n"; - i_data += "uniform LightBufferUBO\n"; - i_data += "{\n"; - i_data += " vec4 lights[NUM_UBO_LIGHTS];\n"; - i_data += "};\n"; - i_data += "#endif\n"; - - // textures - i_data += "uniform sampler2D tex;\n"; - i_data += "uniform sampler2D ShadowMap;\n"; - i_data += "uniform sampler2D texture2;\n"; - i_data += "uniform sampler2D texture3;\n"; - i_data += "uniform sampler2D texture4;\n"; - i_data += "uniform sampler2D texture5;\n"; - i_data += "uniform sampler2D texture6;\n"; - - // timer data - i_data += "uniform float timer;\n"; - - // material types - i_data += "#if defined(SPECULAR)\n"; - i_data += "#define normaltexture texture2\n"; - i_data += "#define speculartexture texture3\n"; - i_data += "#define brighttexture texture4\n"; - i_data += "#elif defined(PBR)\n"; - i_data += "#define normaltexture texture2\n"; - i_data += "#define metallictexture texture3\n"; - i_data += "#define roughnesstexture texture4\n"; - i_data += "#define aotexture texture5\n"; - i_data += "#define brighttexture texture6\n"; - i_data += "#else\n"; - i_data += "#define brighttexture texture2\n"; - i_data += "#endif\n"; - -#ifdef __APPLE__ - // The noise functions are completely broken in macOS OpenGL drivers - // Garbage values are returned, and their infrequent usage causes extreme slowdown - // Also, these functions must return zeroes since GLSL 4.4 - i_data += "#define noise1(unused) 0.0\n"; - i_data += "#define noise2(unused) vec2(0)\n"; - i_data += "#define noise3(unused) vec3(0)\n"; - i_data += "#define noise4(unused) vec4(0)\n"; -#endif // __APPLE__ - - int vp_lump = Wads.CheckNumForFullName(vert_prog_lump, 0); - if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump); - FMemLump vp_data = Wads.ReadLump(vp_lump); - - int fp_lump = Wads.CheckNumForFullName(frag_prog_lump, 0); - if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump); - FMemLump fp_data = Wads.ReadLump(fp_lump); - - - -// -// The following code uses GetChars on the strings to get rid of terminating 0 characters. Do not remove or the code may break! -// - FString vp_comb; - - assert(screen->mLights != NULL); - - bool lightbuffertype = screen->mLights->GetBufferType(); - unsigned int lightbuffersize = screen->mLights->GetBlockSize(); - if (!lightbuffertype) - { - vp_comb.Format("#version 330 core\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize); - } - else - { - // This differentiation is for Intel which do not seem to expose the full extension, even if marked as required. - if (gl.glslversion < 4.3f) - vp_comb = "#version 400 core\n#extension GL_ARB_shader_storage_buffer_object : require\n#define SHADER_STORAGE_LIGHTS\n"; - else - vp_comb = "#version 430 core\n#define SHADER_STORAGE_LIGHTS\n"; - } - - if (gl.flags & RFL_SHADER_STORAGE_BUFFER) - { - vp_comb << "#define SUPPORTS_SHADOWMAPS\n"; - } - - vp_comb << defines << i_data.GetChars(); - FString fp_comb = vp_comb; - - vp_comb << "#line 1\n"; - fp_comb << "#line 1\n"; - - vp_comb << RemoveLayoutLocationDecl(vp_data.GetString(), "out").GetChars() << "\n"; - fp_comb << RemoveLayoutLocationDecl(fp_data.GetString(), "in").GetChars() << "\n"; - - if (proc_prog_lump != NULL) - { - fp_comb << "#line 1\n"; - - if (*proc_prog_lump != '#') - { - int pp_lump = Wads.CheckNumForFullName(proc_prog_lump); - if (pp_lump == -1) I_Error("Unable to load '%s'", proc_prog_lump); - FMemLump pp_data = Wads.ReadLump(pp_lump); - - if (pp_data.GetString().IndexOf("ProcessMaterial") < 0) - { - // this looks like an old custom hardware shader. - - // add ProcessMaterial function that calls the older ProcessTexel function - int pl_lump = Wads.CheckNumForFullName("shaders/glsl/func_defaultmat.fp", 0); - if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultmat.fp"); - FMemLump pl_data = Wads.ReadLump(pl_lump); - fp_comb << "\n" << pl_data.GetString().GetChars(); - - if (pp_data.GetString().IndexOf("ProcessTexel") < 0) - { - // this looks like an even older custom hardware shader. - // We need to replace the ProcessTexel call to make it work. - - fp_comb.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); - } - - if (pp_data.GetString().IndexOf("ProcessLight") >= 0) - { - // The ProcessLight signatured changed. Forward to the old one. - fp_comb << "\nvec4 ProcessLight(vec4 color);\n"; - fp_comb << "\nvec4 ProcessLight(Material material, vec4 color) { return ProcessLight(color); }\n"; - } - } - - fp_comb << RemoveLegacyUserUniforms(pp_data.GetString()).GetChars(); - fp_comb.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders. - - if (pp_data.GetString().IndexOf("ProcessLight") < 0) - { - int pl_lump = Wads.CheckNumForFullName("shaders/glsl/func_defaultlight.fp", 0); - if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultlight.fp"); - FMemLump pl_data = Wads.ReadLump(pl_lump); - fp_comb << "\n" << pl_data.GetString().GetChars(); - } - } - else - { - // Proc_prog_lump is not a lump name but the source itself (from generated shaders) - fp_comb << proc_prog_lump + 1; - } - } - - if (light_fragprog) - { - int pp_lump = Wads.CheckNumForFullName(light_fragprog, 0); - if (pp_lump == -1) I_Error("Unable to load '%s'", light_fragprog); - FMemLump pp_data = Wads.ReadLump(pp_lump); - fp_comb << pp_data.GetString().GetChars() << "\n"; - } - - if (gl.flags & RFL_NO_CLIP_PLANES) - { - // On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken. - // This will cause some glitches and regressions but is the only way to avoid total display garbage. - vp_comb.Substitute("gl_ClipDistance", "//"); - } - - hShader = glCreateProgram(); - FGLDebug::LabelObject(GL_PROGRAM, hShader, name); - - uint32_t binaryFormat = 0; - TArray binary; - if (IsShaderCacheActive()) - binary = LoadCachedProgramBinary(vp_comb, fp_comb, binaryFormat); - - bool linked = false; - if (binary.Size() > 0 && glProgramBinary) - { - glProgramBinary(hShader, binaryFormat, binary.Data(), binary.Size()); - GLint status = 0; - glGetProgramiv(hShader, GL_LINK_STATUS, &status); - linked = (status == GL_TRUE); - } - - if (!linked) - { - hVertProg = glCreateShader(GL_VERTEX_SHADER); - hFragProg = glCreateShader(GL_FRAGMENT_SHADER); - - FGLDebug::LabelObject(GL_SHADER, hVertProg, vert_prog_lump); - FGLDebug::LabelObject(GL_SHADER, hFragProg, frag_prog_lump); - - int vp_size = (int)vp_comb.Len(); - int fp_size = (int)fp_comb.Len(); - - const char *vp_ptr = vp_comb.GetChars(); - const char *fp_ptr = fp_comb.GetChars(); - - glShaderSource(hVertProg, 1, &vp_ptr, &vp_size); - glShaderSource(hFragProg, 1, &fp_ptr, &fp_size); - - glCompileShader(hVertProg); - glCompileShader(hFragProg); - - glAttachShader(hShader, hVertProg); - glAttachShader(hShader, hFragProg); - - glLinkProgram(hShader); - - glGetShaderInfoLog(hVertProg, 10000, NULL, buffer); - if (*buffer) - { - error << "Vertex shader:\n" << buffer << "\n"; - } - glGetShaderInfoLog(hFragProg, 10000, NULL, buffer); - if (*buffer) - { - error << "Fragment shader:\n" << buffer << "\n"; - } - - glGetProgramInfoLog(hShader, 10000, NULL, buffer); - if (*buffer) - { - error << "Linking:\n" << buffer << "\n"; - } - GLint status = 0; - glGetProgramiv(hShader, GL_LINK_STATUS, &status); - linked = (status == GL_TRUE); - if (!linked) - { - // only print message if there's an error. - I_Error("Init Shader '%s':\n%s\n", name, error.GetChars()); - } - else if (glProgramBinary && IsShaderCacheActive()) - { - int binaryLength = 0; - glGetProgramiv(hShader, GL_PROGRAM_BINARY_LENGTH, &binaryLength); - binary.Resize(binaryLength); - glGetProgramBinary(hShader, binary.Size(), &binaryLength, &binaryFormat, binary.Data()); - binary.Resize(binaryLength); - SaveCachedProgramBinary(vp_comb, fp_comb, binary, binaryFormat); - } - } - else - { - hVertProg = 0; - hFragProg = 0; - } - - muDesaturation.Init(hShader, "uDesaturationFactor"); - muFogEnabled.Init(hShader, "uFogEnabled"); - muTextureMode.Init(hShader, "uTextureMode"); - muLightParms.Init(hShader, "uLightAttr"); - muClipSplit.Init(hShader, "uClipSplit"); - muLightIndex.Init(hShader, "uLightIndex"); - muFogColor.Init(hShader, "uFogColor"); - muDynLightColor.Init(hShader, "uDynLightColor"); - muObjectColor.Init(hShader, "uObjectColor"); - muObjectColor2.Init(hShader, "uObjectColor2"); - muGlowBottomColor.Init(hShader, "uGlowBottomColor"); - muGlowTopColor.Init(hShader, "uGlowTopColor"); - muGlowBottomPlane.Init(hShader, "uGlowBottomPlane"); - muGlowTopPlane.Init(hShader, "uGlowTopPlane"); - muGradientBottomPlane.Init(hShader, "uGradientBottomPlane"); - muGradientTopPlane.Init(hShader, "uGradientTopPlane"); - muSplitBottomPlane.Init(hShader, "uSplitBottomPlane"); - muSplitTopPlane.Init(hShader, "uSplitTopPlane"); - muInterpolationFactor.Init(hShader, "uInterpolationFactor"); - muAlphaThreshold.Init(hShader, "uAlphaThreshold"); - muSpecularMaterial.Init(hShader, "uSpecularMaterial"); - muAddColor.Init(hShader, "uAddColor"); - muTextureAddColor.Init(hShader, "uTextureAddColor"); - muTextureModulateColor.Init(hShader, "uTextureModulateColor"); - muTextureBlendColor.Init(hShader, "uTextureBlendColor"); - muTimer.Init(hShader, "timer"); - - lights_index = glGetUniformLocation(hShader, "lights"); - modelmatrix_index = glGetUniformLocation(hShader, "ModelMatrix"); - texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix"); - normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix"); - - if (!lightbuffertype) - { - int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO"); - if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT); - } - int tempindex = glGetUniformBlockIndex(hShader, "ViewpointUBO"); - if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, VIEWPOINT_BINDINGPOINT); - - glUseProgram(hShader); - - // set up other texture units (if needed by the shader) - for (int i = 2; i<16; i++) - { - char stringbuf[20]; - mysnprintf(stringbuf, 20, "texture%d", i); - int tempindex = glGetUniformLocation(hShader, stringbuf); - if (tempindex > 0) glUniform1i(tempindex, i - 1); - } - - int shadowmapindex = glGetUniformLocation(hShader, "ShadowMap"); - if (shadowmapindex > 0) glUniform1i(shadowmapindex, 16); - - glUseProgram(0); - return linked; -} - -//========================================================================== -// -// -// -//========================================================================== - -FShader::~FShader() -{ - glDeleteProgram(hShader); - if (hVertProg != 0) - glDeleteShader(hVertProg); - if (hFragProg != 0) - glDeleteShader(hFragProg); -} - - -//========================================================================== -// -// -// -//========================================================================== - -bool FShader::Bind() -{ - GLRenderer->mShaderManager->SetActiveShader(this); - return true; -} - -//========================================================================== -// -// Since all shaders are REQUIRED, any error here needs to be fatal -// -//========================================================================== - -FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType) -{ - FString defines; - defines += shaderdefines; - // this can't be in the shader code due to ATI strangeness. - if (!usediscard) defines += "#define NO_ALPHATEST\n"; - if (passType == GBUFFER_PASS) defines += "#define GBUFFER_PASS\n"; - - FShader *shader = NULL; - try - { - shader = new FShader(ShaderName); - if (!shader->Load(ShaderName, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, LightModePath, defines.GetChars())) - { - I_FatalError("Unable to load shader %s\n", ShaderName); - } - } - catch(CRecoverableError &err) - { - if (shader != NULL) delete shader; - shader = NULL; - I_FatalError("Unable to load shader %s:\n%s\n", ShaderName, err.GetMessage()); - } - return shader; -} - -//========================================================================== -// -// -// -//========================================================================== - -FShaderManager::FShaderManager() -{ - for (int passType = 0; passType < MAX_PASS_TYPES; passType++) - mPassShaders.Push(new FShaderCollection((EPassType)passType)); -} - -FShaderManager::~FShaderManager() -{ - glUseProgram(0); - mActiveShader = NULL; - - for (auto collection : mPassShaders) - delete collection; -} - -void FShaderManager::SetActiveShader(FShader *sh) -{ - if (mActiveShader != sh) - { - glUseProgram(sh!= NULL? sh->GetHandle() : 0); - mActiveShader = sh; - } -} - -FShader *FShaderManager::BindEffect(int effect, EPassType passType) -{ - if (passType < mPassShaders.Size()) - return mPassShaders[passType]->BindEffect(effect); - else - return nullptr; -} - -FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) -{ - if (passType < mPassShaders.Size()) - return mPassShaders[passType]->Get(eff, alphateston); - else - return nullptr; -} - -//========================================================================== -// -// -// -//========================================================================== - -FShaderCollection::FShaderCollection(EPassType passType) -{ - CompileShaders(passType); -} - -//========================================================================== -// -// -// -//========================================================================== - -FShaderCollection::~FShaderCollection() -{ - Clean(); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FShaderCollection::CompileShaders(EPassType passType) -{ - mMaterialShaders.Clear(); - mMaterialShadersNAT.Clear(); - for (int i = 0; i < MAX_EFFECTS; i++) - { - mEffectShaders[i] = NULL; - } - - for(int i=0;defaultshaders[i].ShaderName != NULL;i++) - { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, passType); - mMaterialShaders.Push(shc); - if (i < SHADER_NoTexture) - { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, passType); - mMaterialShadersNAT.Push(shc); - } - } - - for(unsigned i = 0; i < usershaders.Size(); i++) - { - FString name = ExtractFileBase(usershaders[i].shader); - FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines; - FShader *shc = Compile(name, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, passType); - mMaterialShaders.Push(shc); - } - - for(int i=0;iLoad(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1, - effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines)) - { - delete eff; - } - else mEffectShaders[i] = eff; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FShaderCollection::Clean() -{ - for (unsigned int i = 0; i < mMaterialShadersNAT.Size(); i++) - { - if (mMaterialShadersNAT[i] != NULL) delete mMaterialShadersNAT[i]; - } - for (unsigned int i = 0; i < mMaterialShaders.Size(); i++) - { - if (mMaterialShaders[i] != NULL) delete mMaterialShaders[i]; - } - for (int i = 0; i < MAX_EFFECTS; i++) - { - if (mEffectShaders[i] != NULL) delete mEffectShaders[i]; - mEffectShaders[i] = NULL; - } - mMaterialShaders.Clear(); - mMaterialShadersNAT.Clear(); -} - -//========================================================================== -// -// -// -//========================================================================== - -int FShaderCollection::Find(const char * shn) -{ - FName sfn = shn; - - for(unsigned int i=0;imName == sfn) - { - return i; - } - } - return -1; -} - - -//========================================================================== -// -// -// -//========================================================================== - -FShader *FShaderCollection::BindEffect(int effect) -{ - if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL) - { - mEffectShaders[effect]->Bind(); - return mEffectShaders[effect]; - } - return NULL; -} - - -//========================================================================== -// -// -// -//========================================================================== - -void gl_DestroyUserShaders() -{ - // todo -} - -} diff --git a/src/rendering/gl/system/gl_buffers.cpp b/src/rendering/gl/system/gl_buffers.cpp deleted file mode 100644 index f7cd34a3e63..00000000000 --- a/src/rendering/gl/system/gl_buffers.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2018 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** Low level vertex buffer class -** -**/ - -#include "gl_load/gl_system.h" -#include "gl_buffers.h" -#include "gl/renderer/gl_renderstate.h" -#include "v_video.h" - -namespace OpenGLRenderer -{ - -//========================================================================== -// -// basic buffer implementation -// -//========================================================================== - -static inline void InvalidateBufferState() -{ - gl_RenderState.ResetVertexBuffer(); // force rebinding of buffers on next Apply call. -} - -GLBuffer::GLBuffer(int usetype) - : mUseType(usetype) -{ - glGenBuffers(1, &mBufferId); -} - -GLBuffer::~GLBuffer() -{ - if (mBufferId != 0) - { - glBindBuffer(mUseType, mBufferId); - glUnmapBuffer(mUseType); - glBindBuffer(mUseType, 0); - glDeleteBuffers(1, &mBufferId); - } -} - -void GLBuffer::Bind() -{ - glBindBuffer(mUseType, mBufferId); -} - - -void GLBuffer::SetData(size_t size, const void *data, bool staticdata) -{ - Bind(); - if (data != nullptr) - { - glBufferData(mUseType, size, data, staticdata? GL_STATIC_DRAW : GL_STREAM_DRAW); - } - else - { - mPersistent = screen->BuffersArePersistent() && !staticdata; - if (mPersistent) - { - glBufferStorage(mUseType, size, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); - map = glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); - } - else - { - glBufferData(mUseType, size, nullptr, staticdata ? GL_STATIC_DRAW : GL_STREAM_DRAW); - map = nullptr; - } - if (!staticdata) nomap = false; - } - buffersize = size; - InvalidateBufferState(); -} - -void GLBuffer::SetSubData(size_t offset, size_t size, const void *data) -{ - Bind(); - glBufferSubData(mUseType, offset, size, data); -} - -void GLBuffer::Map() -{ - assert(nomap == false); // do not allow mapping of static buffers. Vulkan cannot do that so it should be blocked in OpenGL, too. - if (!mPersistent && !nomap) - { - Bind(); - map = (FFlatVertex*)glMapBufferRange(mUseType, 0, buffersize, GL_MAP_WRITE_BIT|GL_MAP_UNSYNCHRONIZED_BIT); - InvalidateBufferState(); - } -} - -void GLBuffer::Unmap() -{ - assert(nomap == false); - if (!mPersistent && map != nullptr) - { - Bind(); - glUnmapBuffer(mUseType); - InvalidateBufferState(); - map = nullptr; - } -} - -void *GLBuffer::Lock(unsigned int size) -{ - // This initializes this buffer as a static object with no data. - SetData(size, nullptr, true); - return glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT); -} - -void GLBuffer::Unlock() -{ - Bind(); - glUnmapBuffer(mUseType); - InvalidateBufferState(); -} - -void GLBuffer::Resize(size_t newsize) -{ - assert(!nomap); // only mappable buffers can be resized. - if (newsize > buffersize && !nomap) - { - // reallocate the buffer with twice the size - unsigned int oldbuffer = mBufferId; - - // first unmap the old buffer - Bind(); - glUnmapBuffer(mUseType); - - glGenBuffers(1, &mBufferId); - SetData(newsize, nullptr, false); - glBindBuffer(GL_COPY_READ_BUFFER, oldbuffer); - - // copy contents and delete the old buffer. - glCopyBufferSubData(GL_COPY_READ_BUFFER, mUseType, 0, 0, buffersize); - glBindBuffer(GL_COPY_READ_BUFFER, 0); - glDeleteBuffers(1, &oldbuffer); - buffersize = newsize; - InvalidateBufferState(); - } -} - - -//=========================================================================== -// -// Vertex buffer implementation -// -//=========================================================================== - -void GLVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) -{ - static int VFmtToGLFmt[] = { GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT_2_10_10_10_REV }; - static uint8_t VFmtToSize[] = {4, 3, 2, 1, 4, 4}; - - mStride = stride; - mNumBindingPoints = numBindingPoints; - - for(int i = 0; i < numAttributes; i++) - { - if (attrs[i].location >= 0 && attrs[i].location < VATTR_MAX) - { - auto & attrinf = mAttributeInfo[attrs[i].location]; - attrinf.format = VFmtToGLFmt[attrs[i].format]; - attrinf.size = VFmtToSize[attrs[i].format]; - attrinf.offset = attrs[i].offset; - attrinf.bindingpoint = attrs[i].binding; - } - } -} - -void GLVertexBuffer::Bind(int *offsets) -{ - int i = 0; - - // This is what gets called from RenderState.Apply. It shouldn't be called anywhere else if the render state is in use - GLBuffer::Bind(); - for(auto &attrinf : mAttributeInfo) - { - if (attrinf.size == 0) - { - glDisableVertexAttribArray(i); - } - else - { - glEnableVertexAttribArray(i); - size_t ofs = offsets == nullptr ? attrinf.offset : attrinf.offset + mStride * offsets[attrinf.bindingpoint]; - glVertexAttribPointer(i, attrinf.size, attrinf.format, attrinf.format != GL_FLOAT, (GLsizei)mStride, (void*)(intptr_t)ofs); - } - i++; - } -} - -void GLDataBuffer::BindRange(FRenderState *state, size_t start, size_t length) -{ - glBindBufferRange(mUseType, mBindingPoint, mBufferId, start, length); -} - -void GLDataBuffer::BindBase() -{ - glBindBufferBase(mUseType, mBindingPoint, mBufferId); -} - -} \ No newline at end of file diff --git a/src/rendering/gl/system/gl_framebuffer.cpp b/src/rendering/gl/system/gl_framebuffer.cpp deleted file mode 100644 index a69172c636f..00000000000 --- a/src/rendering/gl/system/gl_framebuffer.cpp +++ /dev/null @@ -1,508 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2010-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_framebuffer.cpp -** Implementation of the non-hardware specific parts of the -** OpenGL frame buffer -** -*/ - -#include "gl_load/gl_system.h" -#include "v_video.h" -#include "m_png.h" -#include "templates.h" - -#include "gl_load/gl_interface.h" -#include "gl/system/gl_framebuffer.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "gl/textures/gl_samplers.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "hwrenderer/models/hw_models.h" -#include "hwrenderer/scene/hw_skydome.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" -#include "gl/shaders/gl_shaderprogram.h" -#include "gl_debug.h" -#include "r_videoscale.h" -#include "gl_buffers.h" - -#include "hwrenderer/data/flatvertices.h" - -EXTERN_CVAR (Bool, vid_vsync) -EXTERN_CVAR(Bool, r_drawvoxels) -EXTERN_CVAR(Int, gl_tonemap) - -void gl_LoadExtensions(); -void gl_PrintStartupLog(); -void Draw2D(F2DDrawer *drawer, FRenderState &state); - -extern bool vid_hdr_active; - -namespace OpenGLRenderer -{ - FGLRenderer *GLRenderer; - -//========================================================================== -// -// -// -//========================================================================== - -OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, bool fullscreen) : - Super(hMonitor, fullscreen) -{ - // SetVSync needs to be at the very top to workaround a bug in Nvidia's OpenGL driver. - // If wglSwapIntervalEXT is called after glBindFramebuffer in a frame the setting is not changed! - Super::SetVSync(vid_vsync); - - // Make sure all global variables tracking OpenGL context state are reset.. - FHardwareTexture::InitGlobalState(); - gl_RenderState.Reset(); - - GLRenderer = nullptr; -} - -OpenGLFrameBuffer::~OpenGLFrameBuffer() -{ - PPResource::ResetAll(); - - if (mVertexData != nullptr) delete mVertexData; - if (mSkyData != nullptr) delete mSkyData; - if (mViewpoints != nullptr) delete mViewpoints; - if (mLights != nullptr) delete mLights; - mShadowMap.Reset(); - - if (GLRenderer) - { - delete GLRenderer; - GLRenderer = nullptr; - } -} - -//========================================================================== -// -// Initializes the GL renderer -// -//========================================================================== - -void OpenGLFrameBuffer::InitializeState() -{ - static bool first=true; - - if (first) - { - if (ogl_LoadFunctions() == ogl_LOAD_FAILED) - { - I_FatalError("Failed to load OpenGL functions."); - } - } - - gl_LoadExtensions(); - - // Move some state to the framebuffer object for easier access. - hwcaps = gl.flags; - glslversion = gl.glslversion; - uniformblockalignment = gl.uniformblockalignment; - maxuniformblock = gl.maxuniformblock; - vendorstring = gl.vendorstring; - - if (first) - { - first=false; - gl_PrintStartupLog(); - } - - glDepthFunc(GL_LESS); - - glEnable(GL_DITHER); - glDisable(GL_CULL_FACE); - glDisable(GL_POLYGON_OFFSET_FILL); - glEnable(GL_POLYGON_OFFSET_LINE); - glEnable(GL_BLEND); - glEnable(GL_DEPTH_CLAMP); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LINE_SMOOTH); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearDepth(1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - SetViewportRects(nullptr); - - mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight()); - mSkyData = new FSkyVertexBuffer; - mViewpoints = new HWViewpointBuffer; - mLights = new FLightBuffer(); - - GLRenderer = new FGLRenderer(this); - GLRenderer->Initialize(GetWidth(), GetHeight()); - - static_cast(mLights->GetBuffer())->BindBase(); - - mDebug = std::make_shared(); - mDebug->Update(); -} - -//========================================================================== -// -// Updates the screen -// -//========================================================================== - -void OpenGLFrameBuffer::Update() -{ - twoD.Reset(); - Flush3D.Reset(); - - Flush3D.Clock(); - GLRenderer->Flush(); - Flush3D.Unclock(); - - Swap(); - Super::Update(); -} - -//=========================================================================== -// -// Render the view to a savegame picture -// -//=========================================================================== - -void OpenGLFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height) -{ - if (!V_IsHardwareRenderer()) - Super::WriteSavePic(player, file, width, height); - else if (GLRenderer != nullptr) - GLRenderer->WriteSavePic(player, file, width, height); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -sector_t *OpenGLFrameBuffer::RenderView(player_t *player) -{ - if (GLRenderer != nullptr) - return GLRenderer->RenderView(player); - return nullptr; -} - - - -//=========================================================================== -// -// -// -//=========================================================================== - -uint32_t OpenGLFrameBuffer::GetCaps() -{ - if (!V_IsHardwareRenderer()) - return Super::GetCaps(); - - // describe our basic feature set - ActorRenderFeatureFlags FlagSet = RFF_FLATSPRITES | RFF_MODELS | RFF_SLOPE3DFLOORS | - RFF_TILTPITCH | RFF_ROLLSPRITES | RFF_POLYGONAL | RFF_MATSHADER | RFF_POSTSHADER | RFF_BRIGHTMAP; - if (r_drawvoxels) - FlagSet |= RFF_VOXELS; - - if (gl_tonemap != 5) // not running palette tonemap shader - FlagSet |= RFF_TRUECOLOR; - - return (uint32_t)FlagSet; -} - -const char* OpenGLFrameBuffer::DeviceName() const -{ - return gl.modelstring; -} - -//========================================================================== -// -// Swap the buffers -// -//========================================================================== - -CVAR(Bool, gl_finishbeforeswap, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); - -void OpenGLFrameBuffer::Swap() -{ - bool swapbefore = gl_finishbeforeswap && camtexcount == 0; - Finish.Reset(); - Finish.Clock(); - if (swapbefore) glFinish(); - FPSLimit(); - SwapBuffers(); - if (!swapbefore) glFinish(); - Finish.Unclock(); - camtexcount = 0; - FHardwareTexture::UnbindAll(); - mDebug->Update(); -} - -//========================================================================== -// -// Enable/disable vertical sync -// -//========================================================================== - -void OpenGLFrameBuffer::SetVSync(bool vsync) -{ - // Switch to the default frame buffer because some drivers associate the vsync state with the bound FB object. - GLint oldDrawFramebufferBinding = 0, oldReadFramebufferBinding = 0; - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDrawFramebufferBinding); - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldReadFramebufferBinding); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - - Super::SetVSync(vsync); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDrawFramebufferBinding); - glBindFramebuffer(GL_READ_FRAMEBUFFER, oldReadFramebufferBinding); -} - -//=========================================================================== -// -// -//=========================================================================== - -void OpenGLFrameBuffer::CleanForRestart() -{ - if (GLRenderer) - GLRenderer->ResetSWScene(); -} - -void OpenGLFrameBuffer::SetTextureFilterMode() -{ - if (GLRenderer != nullptr && GLRenderer->mSamplerManager != nullptr) GLRenderer->mSamplerManager->SetTextureFilterMode(); -} - -IHardwareTexture *OpenGLFrameBuffer::CreateHardwareTexture() -{ - return new FHardwareTexture(true/*tex->bNoCompress*/); -} - -void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) -{ - auto tex = mat->tex; - if (tex->isSWCanvas()) return; - - int flags = mat->isExpanded() ? CTF_Expand : 0; - int numLayers = mat->GetLayers(); - auto base = static_cast(mat->GetLayer(0, translation)); - - if (base->BindOrCreate(tex, 0, CLAMP_NONE, translation, flags)) - { - for (int i = 1; i < numLayers; i++) - { - FTexture *layer; - auto systex = static_cast(mat->GetLayer(i, 0, &layer)); - systex->BindOrCreate(layer, i, CLAMP_NONE, 0, mat->isExpanded() ? CTF_Expand : 0); - } - } - // unbind everything. - FHardwareTexture::UnbindAll(); -} - -FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli) -{ - return new FHWModelRenderer(nullptr, gl_RenderState, mli); -} - -IVertexBuffer *OpenGLFrameBuffer::CreateVertexBuffer() -{ - return new GLVertexBuffer; -} - -IIndexBuffer *OpenGLFrameBuffer::CreateIndexBuffer() -{ - return new GLIndexBuffer; -} - -IDataBuffer *OpenGLFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) -{ - return new GLDataBuffer(bindingpoint, ssbo); -} - -void OpenGLFrameBuffer::TextureFilterChanged() -{ - if (GLRenderer != NULL && GLRenderer->mSamplerManager != NULL) GLRenderer->mSamplerManager->SetTextureFilterMode(); -} - -void OpenGLFrameBuffer::BlurScene(float amount) -{ - GLRenderer->BlurScene(amount); -} - -void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds) -{ - Super::SetViewportRects(bounds); - if (!bounds) - { - auto vrmode = VRMode::GetVRMode(true); - vrmode->AdjustViewport(this); - } -} - -void OpenGLFrameBuffer::UpdatePalette() -{ - if (GLRenderer) - GLRenderer->ClearTonemapPalette(); -} - - -//=========================================================================== -// -// -// -//=========================================================================== - -void OpenGLFrameBuffer::BeginFrame() -{ - SetViewportRects(nullptr); - if (GLRenderer != nullptr) - GLRenderer->BeginFrame(); -} - -//=========================================================================== -// -// Takes a screenshot -// -//=========================================================================== - -TArray OpenGLFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) -{ - const auto &viewport = mOutputLetterbox; - - // Grab what is in the back buffer. - // We cannot rely on SCREENWIDTH/HEIGHT here because the output may have been scaled. - TArray pixels; - pixels.Resize(viewport.width * viewport.height * 3); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(viewport.left, viewport.top, viewport.width, viewport.height, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]); - glPixelStorei(GL_PACK_ALIGNMENT, 4); - - // Copy to screenshot buffer: - int w = SCREENWIDTH; - int h = SCREENHEIGHT; - - TArray ScreenshotBuffer(w * h * 3, true); - - float rcpWidth = 1.0f / w; - float rcpHeight = 1.0f / h; - for (int y = 0; y < h; y++) - { - for (int x = 0; x < w; x++) - { - float u = (x + 0.5f) * rcpWidth; - float v = (y + 0.5f) * rcpHeight; - int sx = u * viewport.width; - int sy = v * viewport.height; - int sindex = (sx + sy * viewport.width) * 3; - int dindex = (x + (h - y - 1) * w) * 3; - ScreenshotBuffer[dindex] = pixels[sindex]; - ScreenshotBuffer[dindex + 1] = pixels[sindex + 1]; - ScreenshotBuffer[dindex + 2] = pixels[sindex + 2]; - } - } - - pitch = w * 3; - color_type = SS_RGB; - - // Screenshot should not use gamma correction if it was already applied to rendered image - gamma = 1; - if (vid_hdr_active && fullscreen) - gamma *= 2.2f; - return ScreenshotBuffer; -} - -//=========================================================================== -// -// 2D drawing -// -//=========================================================================== - -void OpenGLFrameBuffer::Draw2D() -{ - if (GLRenderer != nullptr) - { - GLRenderer->mBuffers->BindCurrentFB(); - ::Draw2D(&m2DDrawer, gl_RenderState); - } -} - -void OpenGLFrameBuffer::PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) -{ - GLRenderer->PostProcessScene(fixedcm, afterBloomDrawEndScene2D); -} - -//========================================================================== -// -// OpenGLFrameBuffer :: WipeStartScreen -// -// Called before the current screen has started rendering. This needs to -// save what was drawn the previous frame so that it can be animated into -// what gets drawn this frame. -// -//========================================================================== - -FTexture *OpenGLFrameBuffer::WipeStartScreen() -{ - const auto &viewport = screen->mScreenViewport; - - auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); - tex->GetSystemTexture()->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); - glFinish(); - static_cast(tex->GetSystemTexture())->Bind(0, false); - - GLRenderer->mBuffers->BindCurrentFB(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); - return tex; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: WipeEndScreen -// -// The screen we want to animate to has just been drawn. -// -//========================================================================== - -FTexture *OpenGLFrameBuffer::WipeEndScreen() -{ - GLRenderer->Flush(); - const auto &viewport = screen->mScreenViewport; - auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); - tex->GetSystemTexture()->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); - glFinish(); - static_cast(tex->GetSystemTexture())->Bind(0, false); - GLRenderer->mBuffers->BindCurrentFB(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); - return tex; -} - -} diff --git a/src/rendering/gl/system/gl_framebuffer.h b/src/rendering/gl/system/gl_framebuffer.h deleted file mode 100644 index 512ea037b36..00000000000 --- a/src/rendering/gl/system/gl_framebuffer.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __GL_FRAMEBUFFER -#define __GL_FRAMEBUFFER - -#include "gl_sysfb.h" - -#include - -namespace OpenGLRenderer -{ - -class FHardwareTexture; -class FGLDebug; - -class OpenGLFrameBuffer : public SystemGLFrameBuffer -{ - typedef SystemGLFrameBuffer Super; - -public: - - explicit OpenGLFrameBuffer() {} - OpenGLFrameBuffer(void *hMonitor, bool fullscreen) ; - ~OpenGLFrameBuffer(); - - void InitializeState() override; - void Update() override; - - void CleanForRestart() override; - void UpdatePalette() override; - uint32_t GetCaps() override; - const char* DeviceName() const override; - void WriteSavePic(player_t *player, FileWriter *file, int width, int height) override; - sector_t *RenderView(player_t *player) override; - void SetTextureFilterMode() override; - IHardwareTexture *CreateHardwareTexture() override; - void PrecacheMaterial(FMaterial *mat, int translation) override; - FModelRenderer *CreateModelRenderer(int mli) override; - void TextureFilterChanged() override; - void BeginFrame() override; - void SetViewportRects(IntRect *bounds) override; - void BlurScene(float amount) override; - IVertexBuffer *CreateVertexBuffer() override; - IIndexBuffer *CreateIndexBuffer() override; - IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override; - - // Retrieves a buffer containing image data for a screenshot. - // Hint: Pitch can be negative for upside-down images, in which case buffer - // points to the last row in the buffer, which will be the first row output. - virtual TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override; - - void Swap(); - bool IsHWGammaActive() const { return HWGammaActive; } - - void SetVSync(bool vsync); - - void Draw2D() override; - void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) override; - - bool HWGammaActive = false; // Are we using hardware or software gamma? - std::shared_ptr mDebug; // Debug API - - FTexture *WipeStartScreen() override; - FTexture *WipeEndScreen() override; - - int camtexcount = 0; -}; - -} - -#endif //__GL_FRAMEBUFFER diff --git a/src/rendering/gl/textures/gl_hwtexture.h b/src/rendering/gl/textures/gl_hwtexture.h deleted file mode 100644 index db01f363766..00000000000 --- a/src/rendering/gl/textures/gl_hwtexture.h +++ /dev/null @@ -1,72 +0,0 @@ - -#ifndef __GLTEXTURE_H -#define __GLTEXTURE_H - -#ifdef LoadImage -#undef LoadImage -#endif - -#define SHADED_TEXTURE -1 -#define DIRECT_PALETTE -2 - -#include "tarray.h" -#include "gl_load/gl_interface.h" -#include "hwrenderer/textures/hw_ihwtexture.h" - -class FCanvasTexture; -class AActor; - -namespace OpenGLRenderer -{ - -class FHardwareTexture : public IHardwareTexture -{ -public: - - static unsigned int lastbound[MAX_TEXTURES]; - - static int GetTexDimension(int value) - { - if (value > gl.max_texturesize) return gl.max_texturesize; - return value; - } - - static void InitGlobalState() { for (int i = 0; i < MAX_TEXTURES; i++) lastbound[i] = 0; } - -private: - - bool forcenocompression; - - unsigned int glTexID = 0; - unsigned int glDepthID = 0; // only used by camera textures - unsigned int glBufferID = 0; - int glTextureBytes = 4; - bool mipmapped = false; - - int GetDepthBuffer(int w, int h); - -public: - FHardwareTexture(bool nocompress) - { - forcenocompression = nocompress; - } - - ~FHardwareTexture(); - - static void Unbind(int texunit); - static void UnbindAll(); - - void BindToFrameBuffer(int w, int h); - - unsigned int Bind(int texunit, bool needmipmap); - bool BindOrCreate(FTexture *tex, int texunit, int clampmode, int translation, int flags); - - void AllocateBuffer(int w, int h, int texelsize); - uint8_t *MapBuffer(); - - unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name); - unsigned int GetTextureHandle(int translation); -}; - -} -#endif diff --git a/src/rendering/gl/textures/gl_samplers.cpp b/src/rendering/gl/textures/gl_samplers.cpp deleted file mode 100644 index e5fd902818c..00000000000 --- a/src/rendering/gl/textures/gl_samplers.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2014-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#include "gl_load/gl_system.h" -#include "c_cvars.h" - -#include "gl_load/gl_interface.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "gl/system/gl_debug.h" -#include "gl/renderer/gl_renderer.h" -#include "gl_samplers.h" -#include "hwrenderer/textures/hw_material.h" - -namespace OpenGLRenderer -{ - -extern TexFilter_s TexFilter[]; - - -FSamplerManager::FSamplerManager() -{ - glGenSamplers(7, mSamplers); - SetTextureFilterMode(); - glSamplerParameteri(mSamplers[5], GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glSamplerParameteri(mSamplers[5], GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glSamplerParameterf(mSamplers[5], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); - glSamplerParameterf(mSamplers[4], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); - glSamplerParameterf(mSamplers[6], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); - - glSamplerParameteri(mSamplers[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(mSamplers[2], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glSamplerParameteri(mSamplers[3], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(mSamplers[3], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glSamplerParameteri(mSamplers[4], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(mSamplers[4], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - for (int i = 0; i < 7; i++) - { - FString name; - name.Format("mSamplers[%d]", i); - FGLDebug::LabelObject(GL_SAMPLER, mSamplers[i], name.GetChars()); - } -} - -FSamplerManager::~FSamplerManager() -{ - UnbindAll(); - glDeleteSamplers(7, mSamplers); -} - -void FSamplerManager::UnbindAll() -{ - for (int i = 0; i < FHardwareTexture::MAX_TEXTURES; i++) - { - glBindSampler(i, 0); - } -} - -uint8_t FSamplerManager::Bind(int texunit, int num, int lastval) -{ - unsigned int samp = mSamplers[num]; - glBindSampler(texunit, samp); - return 255; -} - - -void FSamplerManager::SetTextureFilterMode() -{ - UnbindAll(); - int filter = V_IsHardwareRenderer() ? gl_texture_filter : 0; - - for (int i = 0; i < 4; i++) - { - glSamplerParameteri(mSamplers[i], GL_TEXTURE_MIN_FILTER, TexFilter[filter].minfilter); - glSamplerParameteri(mSamplers[i], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); - glSamplerParameterf(mSamplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic); - } - glSamplerParameteri(mSamplers[4], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter); - glSamplerParameteri(mSamplers[4], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); - glSamplerParameteri(mSamplers[6], GL_TEXTURE_MIN_FILTER, TexFilter[filter].magfilter); - glSamplerParameteri(mSamplers[6], GL_TEXTURE_MAG_FILTER, TexFilter[filter].magfilter); -} - - -} \ No newline at end of file diff --git a/src/rendering/gl/textures/gl_samplers.h b/src/rendering/gl/textures/gl_samplers.h deleted file mode 100644 index 93c8c741910..00000000000 --- a/src/rendering/gl/textures/gl_samplers.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __GL_SAMPLERS_H -#define __GL_SAMPLERS_H - -#include "gl_hwtexture.h" - -namespace OpenGLRenderer -{ - -class FSamplerManager -{ - // We need 6 different samplers: 4 for the different clamping modes, - // one for 2D-textures and one for voxel textures - unsigned int mSamplers[7]; - - void UnbindAll(); - -public: - - FSamplerManager(); - ~FSamplerManager(); - - uint8_t Bind(int texunit, int num, int lastval); - void SetTextureFilterMode(); - - -}; - -} -#endif - diff --git a/src/rendering/gl_load/gl_interface.cpp b/src/rendering/gl_load/gl_interface.cpp deleted file mode 100644 index 69c1c258fe1..00000000000 --- a/src/rendering/gl_load/gl_interface.cpp +++ /dev/null @@ -1,249 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** r_opengl.cpp -** -** OpenGL system interface -** -*/ - -#include "gl_load/gl_system.h" -#include "doomerrors.h" -#include "tarray.h" -#include "doomtype.h" -#include "m_argv.h" -#include "version.h" -#include "v_video.h" -#include "gl_load/gl_interface.h" -#include "hwrenderer/utility/hw_cvars.h" - -static TArray m_Extensions; -RenderContext gl; -static double realglversion; // this is public so the statistics code can access it. - -//========================================================================== -// -// -// -//========================================================================== - -static void CollectExtensions() -{ - const char *extension; - - int max = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &max); - - // Use modern method to collect extensions - for (int i = 0; i < max; i++) - { - extension = (const char*)glGetStringi(GL_EXTENSIONS, i); - m_Extensions.Push(FString(extension)); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -static bool CheckExtension(const char *ext) -{ - for (unsigned int i = 0; i < m_Extensions.Size(); ++i) - { - if (m_Extensions[i].CompareNoCase(ext) == 0) return true; - } - - return false; -} - - - -//========================================================================== -// -// -// -//========================================================================== - -static void InitContext() -{ - gl.flags=0; -} - -//========================================================================== -// -// -// -//========================================================================== - -#define FUDGE_FUNC(name, ext) if (_ptrc_##name == NULL) _ptrc_##name = _ptrc_##name##ext; - - -void gl_LoadExtensions() -{ - InitContext(); - CollectExtensions(); - - const char *glversion = (const char*)glGetString(GL_VERSION); - - const char *version = Args->CheckValue("-glversion"); - realglversion = strtod(glversion, NULL); - - - if (version == NULL) - { - version = glversion; - } - else - { - double v1 = strtod(version, NULL); - if (v1 >= 3.0 && v1 < 3.3) - { - v1 = 3.3; // promote '3' to 3.3 to avoid falling back to the legacy path. - version = "3.3"; - } - if (realglversion < v1) version = glversion; - else Printf("Emulating OpenGL v %s\n", version); - } - - float gl_version = (float)strtod(version, NULL) + 0.01f; - - // Don't even start if it's lower than 2.0 or no framebuffers are available (The framebuffer extension is needed for glGenerateMipmapsEXT!) - if (gl_version < 3.3f) - { - I_FatalError("Unsupported OpenGL version.\nAt least OpenGL 3.3 is required to run " GAMENAME ".\nFor older versions of OpenGL please download the vintage build of " GAMENAME ".\n"); - } - - - // add 0.01 to account for roundoff errors making the number a tad smaller than the actual version - gl.glslversion = strtod((char*)glGetString(GL_SHADING_LANGUAGE_VERSION), NULL) + 0.01f; - - gl.vendorstring = (char*)glGetString(GL_VENDOR); - gl.modelstring = (char*)glGetString(GL_RENDERER); - - // first test for optional features - if (CheckExtension("GL_ARB_texture_compression")) gl.flags |= RFL_TEXTURE_COMPRESSION; - if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags |= RFL_TEXTURE_COMPRESSION_S3TC; - - if (gl_version < 4.f) - { -#ifdef _WIN32 - if (strstr(gl.vendorstring, "ATI Tech")) - { - gl.flags |= RFL_NO_CLIP_PLANES; // gl_ClipDistance is horribly broken on ATI GL3 drivers for Windows. (TBD: Relegate to vintage build? Maybe after the next survey.) - } -#endif - gl.glslversion = 3.31f; // Force GLSL down to 3.3. - } - else if (gl_version < 4.5f) - { - // don't use GL 4.x features when running a GL 3.x context. - if (CheckExtension("GL_ARB_buffer_storage")) - { - // work around a problem with older AMD drivers: Their implementation of shader storage buffer objects is piss-poor and does not match uniform buffers even closely. - // Recent drivers, GL 4.4 don't have this problem, these can easily be recognized by also supporting the GL_ARB_buffer_storage extension. - if (CheckExtension("GL_ARB_shader_storage_buffer_object")) - { - gl.flags |= RFL_SHADER_STORAGE_BUFFER; - } - gl.flags |= RFL_BUFFER_STORAGE; - } - } - else - { - // Assume that everything works without problems on GL 4.5 drivers where these things are core features. - gl.flags |= RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE; - } - - // Mesa implements shader storage only for fragment shaders. - // Just disable the feature there. The light buffer may just use a uniform buffer without any adverse effects. - int v = 0; - glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &v); - if (v == 0) - gl.flags &= ~RFL_SHADER_STORAGE_BUFFER; - - - if (gl_version >= 4.3f || CheckExtension("GL_ARB_invalidate_subdata")) gl.flags |= RFL_INVALIDATE_BUFFER; - if (gl_version >= 4.3f || CheckExtension("GL_KHR_debug")) gl.flags |= RFL_DEBUG; - - glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &v); - gl.maxuniforms = v; - glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &v); - gl.maxuniformblock = v; - glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v); - gl.uniformblockalignment = v; - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl.max_texturesize); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -} - -//========================================================================== -// -// -// -//========================================================================== - -void gl_PrintStartupLog() -{ - int v = 0; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &v); - - Printf ("GL_VENDOR: %s\n", glGetString(GL_VENDOR)); - Printf ("GL_RENDERER: %s\n", glGetString(GL_RENDERER)); - Printf ("GL_VERSION: %s (%s profile)\n", glGetString(GL_VERSION), (v & GL_CONTEXT_CORE_PROFILE_BIT)? "Core" : "Compatibility"); - Printf ("GL_SHADING_LANGUAGE_VERSION: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); - Printf (PRINT_LOG, "GL_EXTENSIONS:"); - for (unsigned i = 0; i < m_Extensions.Size(); i++) - { - Printf(PRINT_LOG, " %s", m_Extensions[i].GetChars()); - } - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &v); - Printf("\nMax. texture size: %d\n", v); - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &v); - Printf ("Max. texture units: %d\n", v); - glGetIntegerv(GL_MAX_VARYING_FLOATS, &v); - Printf ("Max. varying: %d\n", v); - - if (gl.flags & RFL_SHADER_STORAGE_BUFFER) - { - glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &v); - Printf("Max. combined shader storage blocks: %d\n", v); - glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &v); - Printf("Max. vertex shader storage blocks: %d\n", v); - } - else - { - glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &v); - Printf("Max. uniform block size: %d\n", v); - glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v); - Printf("Uniform block alignment: %d\n", v); - } -} - -std::pair gl_getInfo() -{ - // gl_ARB_bindless_texture is the closest we can get to determine Vulkan support from OpenGL. - // This isn't foolproof because Intel doesn't support it but for NVidia and AMD support of this extension means Vulkan support. - return std::make_pair(realglversion, CheckExtension("GL_ARB_bindless_texture")); -} diff --git a/src/rendering/hwrenderer/data/buffers.h b/src/rendering/hwrenderer/data/buffers.h deleted file mode 100644 index 51110c72cd9..00000000000 --- a/src/rendering/hwrenderer/data/buffers.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include -#include - -class FRenderState; - -// The low level code needs to know which attributes exist. -// OpenGL needs to change the state of all of them per buffer binding. -// VAOs are mostly useless for this because they lump buffer and binding state together which the model code does not want. -enum -{ - VATTR_VERTEX, - VATTR_TEXCOORD, - VATTR_COLOR, - VATTR_VERTEX2, - VATTR_NORMAL, - VATTR_NORMAL2, - - VATTR_MAX -}; - -enum EVertexAttributeFormat -{ - VFmt_Float4, - VFmt_Float3, - VFmt_Float2, - VFmt_Float, - VFmt_Byte4, - VFmt_Packed_A2R10G10B10, -}; - -struct FVertexBufferAttribute -{ - int binding; - int location; - int format; - int offset; -}; - -class IBuffer -{ -protected: - size_t buffersize = 0; - void *map = nullptr; -public: - IBuffer() = default; - IBuffer(const IBuffer &) = delete; - IBuffer &operator=(const IBuffer &) = delete; - virtual ~IBuffer() = default; - - virtual void SetData(size_t size, const void *data, bool staticdata = true) = 0; - virtual void SetSubData(size_t offset, size_t size, const void *data) = 0; - virtual void *Lock(unsigned int size) = 0; - virtual void Unlock() = 0; - virtual void Resize(size_t newsize) = 0; - virtual void Map() {} // Only needed by old OpenGL but this needs to be in the interface. - virtual void Unmap() {} - void *Memory() { assert(map); return map; } - size_t Size() { return buffersize; } -}; - -class IVertexBuffer : virtual public IBuffer -{ -public: - virtual void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) = 0; -}; - -// This merely exists to have a dedicated type for index buffers to inherit from. -class IIndexBuffer : virtual public IBuffer -{ - // Element size is fixed to 4, thanks to OpenGL requiring this info to be coded into the glDrawElements call. - // This mostly prohibits a more flexible buffer setup but GZDoom doesn't use any other format anyway. - // Ob Vulkam, element size is a buffer property and of no concern to the drawing functions (as it should be.) -}; - -class IDataBuffer : virtual public IBuffer -{ - // Can be either uniform or shader storage buffer, depending on its needs. -public: - virtual void BindRange(FRenderState *state, size_t start, size_t length) = 0; - -}; diff --git a/src/rendering/hwrenderer/data/flatvertices.cpp b/src/rendering/hwrenderer/data/flatvertices.cpp deleted file mode 100644 index 2d956e5e2bb..00000000000 --- a/src/rendering/hwrenderer/data/flatvertices.cpp +++ /dev/null @@ -1,401 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** hw_flatvertices.cpp -** Creates flat vertex data for hardware rendering. -** -**/ - -#include "doomtype.h" -#include "p_local.h" -#include "r_state.h" -#include "c_cvars.h" -#include "g_levellocals.h" -#include "flatvertices.h" -#include "v_video.h" -#include "cmdlib.h" -#include "hwrenderer/data/buffers.h" -#include "hwrenderer/scene/hw_renderstate.h" - -//========================================================================== -// -// -// -//========================================================================== - -FFlatVertexBuffer::FFlatVertexBuffer(int width, int height) -{ - vbo_shadowdata.Resize(NUM_RESERVED); - - // the first quad is reserved for handling coordinates through uniforms. - vbo_shadowdata[0].Set(0, 0, 0, 0, 0); - vbo_shadowdata[1].Set(1, 0, 0, 0, 0); - vbo_shadowdata[2].Set(2, 0, 0, 0, 0); - vbo_shadowdata[3].Set(3, 0, 0, 0, 0); - - // and the second one for the fullscreen quad used for blend overlays. - vbo_shadowdata[4].Set(0, 0, 0, 0, 0); - vbo_shadowdata[5].Set(0, (float)height, 0, 0, 1); - vbo_shadowdata[6].Set((float)width, 0, 0, 1, 0); - vbo_shadowdata[7].Set((float)width, (float)height, 0, 1, 1); - - // and this is for the postprocessing copy operation - vbo_shadowdata[8].Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); - vbo_shadowdata[9].Set(-1.0f, 1.0f, 0, 0.0f, 1.f); - vbo_shadowdata[10].Set(1.0f, -1.0f, 0, 1.f, 0.0f); - vbo_shadowdata[11].Set(1.0f, 1.0f, 0, 1.f, 1.f); - - // The next two are the stencil caps. - vbo_shadowdata[12].Set(-32767.0f, 32767.0f, -32767.0f, 0, 0); - vbo_shadowdata[13].Set(-32767.0f, 32767.0f, 32767.0f, 0, 0); - vbo_shadowdata[14].Set(32767.0f, 32767.0f, 32767.0f, 0, 0); - vbo_shadowdata[15].Set(32767.0f, 32767.0f, -32767.0f, 0, 0); - - vbo_shadowdata[16].Set(-32767.0f, -32767.0f, -32767.0f, 0, 0); - vbo_shadowdata[17].Set(-32767.0f, -32767.0f, 32767.0f, 0, 0); - vbo_shadowdata[18].Set(32767.0f, -32767.0f, 32767.0f, 0, 0); - vbo_shadowdata[19].Set(32767.0f, -32767.0f, -32767.0f, 0, 0); - - mVertexBuffer = screen->CreateVertexBuffer(); - mIndexBuffer = screen->CreateIndexBuffer(); - - unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex); - mVertexBuffer->SetData(bytesize, nullptr, false); - - static const FVertexBufferAttribute format[] = { - { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FFlatVertex, x) }, - { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FFlatVertex, u) } - }; - mVertexBuffer->SetFormat(1, 2, sizeof(FFlatVertex), format); - - mIndex = mCurIndex = 0; - mNumReserved = NUM_RESERVED; - Copy(0, NUM_RESERVED); -} - -//========================================================================== -// -// -// -//========================================================================== - -FFlatVertexBuffer::~FFlatVertexBuffer() -{ - delete mIndexBuffer; - delete mVertexBuffer; - mIndexBuffer = nullptr; - mVertexBuffer = nullptr; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FFlatVertexBuffer::OutputResized(int width, int height) -{ - vbo_shadowdata[4].Set(0, 0, 0, 0, 0); - vbo_shadowdata[5].Set(0, (float)height, 0, 0, 1); - vbo_shadowdata[6].Set((float)width, 0, 0, 1, 0); - vbo_shadowdata[7].Set((float)width, (float)height, 0, 1, 1); - Copy(4, 4); -} - -//========================================================================== -// -// Initialize a single vertex -// -//========================================================================== - -void FFlatVertex::SetFlatVertex(vertex_t *vt, const secplane_t & plane) -{ - x = (float)vt->fX(); - y = (float)vt->fY(); - z = (float)plane.ZatPoint(vt); - u = (float)vt->fX()/64.f; - v = -(float)vt->fY()/64.f; -} - -//========================================================================== -// -// Find a 3D floor -// -//========================================================================== - -static F3DFloor *Find3DFloor(sector_t *target, sector_t *model) -{ - for(unsigned i=0; ie->XFloor.ffloors.Size(); i++) - { - F3DFloor *ffloor = target->e->XFloor.ffloors[i]; - if (ffloor->model == model && !(ffloor->flags & FF_THISINSIDE)) return ffloor; - } - return NULL; -} - -//========================================================================== -// -// Creates the vertices for one plane in one subsector -// -//========================================================================== - -int FFlatVertexBuffer::CreateIndexedSectorVertices(sector_t *sec, const secplane_t &plane, int floor, VertexContainer &verts) -{ - unsigned vi = vbo_shadowdata.Reserve(verts.vertices.Size()); - float diff; - - // Create the actual vertices. - if (sec->transdoor && floor) diff = -1.f; - else diff = 0.f; - for (unsigned i = 0; i < verts.vertices.Size(); i++) - { - vbo_shadowdata[vi + i].SetFlatVertex(verts.vertices[i].vertex, plane); - vbo_shadowdata[vi + i].z += diff; - } - - unsigned rt = ibo_data.Reserve(verts.indices.Size()); - for (unsigned i = 0; i < verts.indices.Size(); i++) - { - ibo_data[rt + i] = vi + verts.indices[i]; - } - return (int)rt; -} - -//========================================================================== -// -// -// -//========================================================================== - -int FFlatVertexBuffer::CreateIndexedVertices(int h, sector_t *sec, const secplane_t &plane, int floor, VertexContainers &verts) -{ - sec->vboindex[h] = vbo_shadowdata.Size(); - // First calculate the vertices for the sector itself - sec->vboheight[h] = sec->GetPlaneTexZ(h); - sec->ibocount = verts[sec->Index()].indices.Size(); - sec->iboindex[h] = CreateIndexedSectorVertices(sec, plane, floor, verts[sec->Index()]); - - // Next are all sectors using this one as heightsec - TArray &fakes = sec->e->FakeFloor.Sectors; - for (unsigned g = 0; g < fakes.Size(); g++) - { - sector_t *fsec = fakes[g]; - fsec->iboindex[2 + h] = CreateIndexedSectorVertices(fsec, plane, false, verts[fsec->Index()]); - } - - // and finally all attached 3D floors - TArray &xf = sec->e->XFloor.attached; - for (unsigned g = 0; g < xf.Size(); g++) - { - sector_t *fsec = xf[g]; - F3DFloor *ffloor = Find3DFloor(fsec, sec); - - if (ffloor != NULL && ffloor->flags & FF_RENDERPLANES) - { - bool dotop = (ffloor->top.model == sec) && (ffloor->top.isceiling == h); - bool dobottom = (ffloor->bottom.model == sec) && (ffloor->bottom.isceiling == h); - - if (dotop || dobottom) - { - auto ndx = CreateIndexedSectorVertices(fsec, plane, false, verts[fsec->Index()]); - if (dotop) ffloor->top.vindex = ndx; - if (dobottom) ffloor->bottom.vindex = ndx; - } - } - } - sec->vbocount[h] = vbo_shadowdata.Size() - sec->vboindex[h]; - return sec->iboindex[h]; -} - - -//========================================================================== -// -// -// -//========================================================================== - -void FFlatVertexBuffer::CreateIndexedFlatVertices(TArray §ors) -{ - auto verts = BuildVertices(sectors); - - int i = 0; - /* - for (auto &vert : verts) - { - Printf(PRINT_LOG, "Sector %d\n", i); - Printf(PRINT_LOG, "%d vertices, %d indices\n", vert.vertices.Size(), vert.indices.Size()); - int j = 0; - for (auto &v : vert.vertices) - { - Printf(PRINT_LOG, " %d: (%2.3f, %2.3f)\n", j++, v.vertex->fX(), v.vertex->fY()); - } - for (unsigned i=0;iXFloor.ffloors) - { - if (ff->top.model == &sec) - { - ff->top.vindex = sec.iboindex[ff->top.isceiling]; - } - if (ff->bottom.model == &sec) - { - ff->bottom.vindex = sec.iboindex[ff->top.isceiling]; - } - } - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane) -{ - int startvt = sec->vboindex[plane]; - int countvt = sec->vbocount[plane]; - secplane_t &splane = sec->GetSecPlane(plane); - FFlatVertex *vt = &vbo_shadowdata[startvt]; - FFlatVertex *mapvt = GetBuffer(startvt); - for(int i=0; iz = (float)splane.ZatPoint(vt->x, vt->y); - if (plane == sector_t::floor && sec->transdoor) vt->z -= 1; - mapvt->z = vt->z; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FFlatVertexBuffer::CreateVertices(TArray §ors) -{ - vbo_shadowdata.Resize(NUM_RESERVED); - CreateIndexedFlatVertices(sectors); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FFlatVertexBuffer::CheckPlanes(sector_t *sector) -{ - if (sector->GetPlaneTexZ(sector_t::ceiling) != sector->vboheight[sector_t::ceiling]) - { - UpdatePlaneVertices(sector, sector_t::ceiling); - sector->vboheight[sector_t::ceiling] = sector->GetPlaneTexZ(sector_t::ceiling); - } - if (sector->GetPlaneTexZ(sector_t::floor) != sector->vboheight[sector_t::floor]) - { - UpdatePlaneVertices(sector, sector_t::floor); - sector->vboheight[sector_t::floor] = sector->GetPlaneTexZ(sector_t::floor); - } -} - -//========================================================================== -// -// checks the validity of all planes attached to this sector -// and updates them if possible. -// -//========================================================================== - -void FFlatVertexBuffer::CheckUpdate(sector_t *sector) -{ - CheckPlanes(sector); - sector_t *hs = sector->GetHeightSec(); - if (hs != NULL) CheckPlanes(hs); - for (unsigned i = 0; i < sector->e->XFloor.ffloors.Size(); i++) - CheckPlanes(sector->e->XFloor.ffloors[i]->model); -} - -//========================================================================== -// -// -// -//========================================================================== - -std::pair FFlatVertexBuffer::AllocVertices(unsigned int count) -{ - FFlatVertex *p = GetBuffer(); - auto index = mCurIndex.fetch_add(count); - auto offset = index; - if (index + count >= BUFFER_SIZE_TO_USE) - { - // If a single scene needs 2'000'000 vertices there must be something very wrong. - I_FatalError("Out of vertex memory. Tried to allocate more than %u vertices for a single frame", index + count); - } - return std::make_pair(p, index); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FFlatVertexBuffer::Copy(int start, int count) -{ - Map(); - memcpy(GetBuffer(start), &vbo_shadowdata[0], count * sizeof(FFlatVertex)); - Unmap(); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FFlatVertexBuffer::CreateVBO(TArray §ors) -{ - vbo_shadowdata.Resize(mNumReserved); - FFlatVertexBuffer::CreateVertices(sectors); - mCurIndex = mIndex = vbo_shadowdata.Size(); - Copy(0, mIndex); - mIndexBuffer->SetData(ibo_data.Size() * sizeof(uint32_t), &ibo_data[0]); -} diff --git a/src/rendering/hwrenderer/data/flatvertices.h b/src/rendering/hwrenderer/data/flatvertices.h deleted file mode 100644 index 6161cea292a..00000000000 --- a/src/rendering/hwrenderer/data/flatvertices.h +++ /dev/null @@ -1,135 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#ifndef _HW__VERTEXBUFFER_H -#define _HW__VERTEXBUFFER_H - -#include "tarray.h" -#include "hwrenderer/data/buffers.h" -#include "hw_vertexbuilder.h" -#include -#include - -class FRenderState; -struct secplane_t; -struct subsector_t; - -struct FFlatVertex -{ - float x, z, y; // world position - float u, v; // texture coordinates - - void SetFlatVertex(vertex_t *vt, const secplane_t &plane); - void Set(float xx, float zz, float yy, float uu, float vv) - { - x = xx; - z = zz; - y = yy; - u = uu; - v = vv; - } -}; - -class FFlatVertexBuffer -{ - TArray vbo_shadowdata; - TArray ibo_data; - - IVertexBuffer *mVertexBuffer; - IIndexBuffer *mIndexBuffer; - - unsigned int mIndex; - std::atomic mCurIndex; - unsigned int mNumReserved; - - - static const unsigned int BUFFER_SIZE = 2000000; - static const unsigned int BUFFER_SIZE_TO_USE = 1999500; - -public: - enum - { - QUAD_INDEX = 0, - FULLSCREEN_INDEX = 4, - PRESENT_INDEX = 8, - STENCILTOP_INDEX = 12, - STENCILBOTTOM_INDEX = 16, - - NUM_RESERVED = 20 - }; - - FFlatVertexBuffer(int width, int height); - ~FFlatVertexBuffer(); - - void OutputResized(int width, int height); - std::pair GetBufferObjects() const - { - return std::make_pair(mVertexBuffer, mIndexBuffer); - } - - void CreateVBO(TArray §ors); - void Copy(int start, int count); - - FFlatVertex *GetBuffer(int index) const - { - FFlatVertex *ff = (FFlatVertex*)mVertexBuffer->Memory(); - return &ff[index]; - } - - FFlatVertex *GetBuffer() const - { - return GetBuffer(mCurIndex); - } - - std::pair AllocVertices(unsigned int count); - - void Reset() - { - mCurIndex = mIndex; - } - - void Map() - { - mVertexBuffer->Map(); - } - - void Unmap() - { - mVertexBuffer->Unmap(); - } - -private: - int CreateIndexedSectionVertices(subsector_t *sub, const secplane_t &plane, int floor, VertexContainer &cont); - int CreateIndexedSectorVertices(sector_t *sec, const secplane_t &plane, int floor, VertexContainer &cont); - int CreateIndexedVertices(int h, sector_t *sec, const secplane_t &plane, int floor, VertexContainers &cont); - void CreateIndexedFlatVertices(TArray §ors); - - void UpdatePlaneVertices(sector_t *sec, int plane); -protected: - void CreateVertices(TArray §ors); - void CheckPlanes(sector_t *sector); -public: - void CheckUpdate(sector_t *sector); - -}; - -#endif diff --git a/src/rendering/hwrenderer/data/hw_vertexbuilder.cpp b/src/rendering/hwrenderer/data/hw_vertexbuilder.cpp deleted file mode 100644 index a21b3c78f1c..00000000000 --- a/src/rendering/hwrenderer/data/hw_vertexbuilder.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015-2018 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - - - -#include "g_levellocals.h" -#include "hw_vertexbuilder.h" -#include "earcut.hpp" - - -//============================================================================= -// -// Creates vertex meshes for sector planes -// -//============================================================================= - -//============================================================================= -// -// -// -//============================================================================= - -static void CreateVerticesForSubsector(subsector_t *sub, VertexContainer &gen, int qualifier) -{ - if (sub->numlines < 3) return; - - uint32_t startindex = gen.indices.Size(); - - if ((sub->flags & SSECF_HOLE) && sub->numlines > 3) - { - // Hole filling "subsectors" are not necessarily convex so they require real triangulation. - // These things are extremely rare so performance is secondary here. - - using Point = std::pair; - std::vector> polygon; - std::vector *curPoly; - - polygon.resize(1); - curPoly = &polygon.back(); - curPoly->resize(sub->numlines); - - for (unsigned i = 0; i < sub->numlines; i++) - { - (*curPoly)[i] = { sub->firstline[i].v1->fX(), sub->firstline[i].v1->fY() }; - } - auto indices = mapbox::earcut(polygon); - for (auto vti : indices) - { - gen.AddIndexForVertex(sub->firstline[vti].v1, qualifier); - } - } - else - { - int firstndx = gen.AddVertex(sub->firstline[0].v1, qualifier); - int secondndx = gen.AddVertex(sub->firstline[1].v1, qualifier); - for (unsigned int k = 2; k < sub->numlines; k++) - { - gen.AddIndex(firstndx); - gen.AddIndex(secondndx); - auto ndx = gen.AddVertex(sub->firstline[k].v1, qualifier); - gen.AddIndex(ndx); - secondndx = ndx; - } - } -} - -//============================================================================= -// -// -// -//============================================================================= - -static void TriangulateSection(FSection §, VertexContainer &gen, int qualifier) -{ - if (sect.segments.Size() < 3) return; - - // todo -} - -//============================================================================= -// -// -// -//============================================================================= - - -static void CreateVerticesForSection(FSection §ion, VertexContainer &gen, bool useSubsectors) -{ - section.vertexindex = gen.indices.Size(); - - if (useSubsectors) - { - for (auto sub : section.subsectors) - { - CreateVerticesForSubsector(sub, gen, -1); - } - } - else - { - TriangulateSection(section, gen, -1); - } - section.vertexcount = gen.indices.Size() - section.vertexindex; -} - -//========================================================================== -// -// Creates the vertices for one plane in one subsector -// -//========================================================================== - -static void CreateVerticesForSector(sector_t *sec, VertexContainer &gen) -{ - auto sections = sec->Level->sections.SectionsForSector(sec); - for (auto §ion :sections) - { - CreateVerticesForSection( section, gen, true); - } -} - - -TArray BuildVertices(TArray §ors) -{ - TArray verticesPerSector(sectors.Size(), true); - for (unsigned i=0; i< sectors.Size(); i++) - { - CreateVerticesForSector(§ors[i], verticesPerSector[i]); - } - return verticesPerSector; -} diff --git a/src/rendering/hwrenderer/data/hw_viewpointbuffer.cpp b/src/rendering/hwrenderer/data/hw_viewpointbuffer.cpp deleted file mode 100644 index 268bd4902cd..00000000000 --- a/src/rendering/hwrenderer/data/hw_viewpointbuffer.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2018 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_viewpointbuffer.cpp -** Buffer data maintenance for per viewpoint uniform data -** -**/ - -#include "hwrenderer/data/shaderuniforms.h" -#include "hwrenderer/scene/hw_viewpointuniforms.h" -#include "hwrenderer/scene/hw_drawinfo.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include "hw_viewpointbuffer.h" - -static const int INITIAL_BUFFER_SIZE = 100; // 100 viewpoints per frame should nearly always be enough - -HWViewpointBuffer::HWViewpointBuffer() -{ - mBufferSize = INITIAL_BUFFER_SIZE; - mBlockAlign = ((sizeof(HWViewpointUniforms) / screen->uniformblockalignment) + 1) * screen->uniformblockalignment; - mByteSize = mBufferSize * mBlockAlign; - mBuffer = screen->CreateDataBuffer(VIEWPOINT_BINDINGPOINT, false, true); - mBuffer->SetData(mByteSize, nullptr, false); - Clear(); - mLastMappedIndex = UINT_MAX; - mClipPlaneInfo.Push(0); -} - -HWViewpointBuffer::~HWViewpointBuffer() -{ - delete mBuffer; -} - - -void HWViewpointBuffer::CheckSize() -{ - if (mUploadIndex >= mBufferSize) - { - mBufferSize *= 2; - mByteSize *= 2; - mBuffer->Resize(mByteSize); - m2DHeight = m2DWidth = -1; - } -} - -int HWViewpointBuffer::Bind(FRenderState &di, unsigned int index) -{ - if (index != mLastMappedIndex) - { - mLastMappedIndex = index; - mBuffer->BindRange(&di, index * mBlockAlign, mBlockAlign); - di.EnableClipDistance(0, mClipPlaneInfo[index]); - } - return index; -} - -void HWViewpointBuffer::Set2D(FRenderState &di, int width, int height) -{ - if (width != m2DWidth || height != m2DHeight) - { - HWViewpointUniforms matrices; - matrices.SetDefaults(nullptr); - matrices.mProjectionMatrix.ortho(0, (float)width, (float)height, 0, -1.0f, 1.0f); - matrices.CalcDependencies(); - mBuffer->Map(); - memcpy(mBuffer->Memory(), &matrices, sizeof(matrices)); - mBuffer->Unmap(); - m2DWidth = width; - m2DHeight = height; - mLastMappedIndex = -1; - } - Bind(di, 0); -} - -int HWViewpointBuffer::SetViewpoint(FRenderState &di, HWViewpointUniforms *vp) -{ - CheckSize(); - mBuffer->Map(); - memcpy(((char*)mBuffer->Memory()) + mUploadIndex * mBlockAlign, vp, sizeof(*vp)); - mBuffer->Unmap(); - - mClipPlaneInfo.Push(vp->mClipHeightDirection != 0.f || vp->mClipLine.X > -10000000.0f); - return Bind(di, mUploadIndex++); -} - -void HWViewpointBuffer::Clear() -{ - // Index 0 is reserved for the 2D projection. - mUploadIndex = 1; - mClipPlaneInfo.Resize(1); -} - diff --git a/src/rendering/hwrenderer/data/hw_viewpointbuffer.h b/src/rendering/hwrenderer/data/hw_viewpointbuffer.h deleted file mode 100644 index 01389e01a47..00000000000 --- a/src/rendering/hwrenderer/data/hw_viewpointbuffer.h +++ /dev/null @@ -1,35 +0,0 @@ - -#include "tarray.h" -#include "hwrenderer/data/buffers.h" - -struct HWViewpointUniforms; -class FRenderState; - -class HWViewpointBuffer -{ - IDataBuffer *mBuffer; - - unsigned int mBufferSize; - unsigned int mBlockAlign; - unsigned int mUploadIndex; - unsigned int mLastMappedIndex; - unsigned int mByteSize; - TArray mClipPlaneInfo; - - int m2DWidth = -1, m2DHeight = -1; - - unsigned int mBlockSize; - - void CheckSize(); - -public: - - HWViewpointBuffer(); - ~HWViewpointBuffer(); - void Clear(); - int Bind(FRenderState &di, unsigned int index); - void Set2D(FRenderState &di, int width, int height); - int SetViewpoint(FRenderState &di, HWViewpointUniforms *vp); - unsigned int GetBlockSize() const { return mBlockSize; } -}; - diff --git a/src/rendering/hwrenderer/doom_aabbtree.cpp b/src/rendering/hwrenderer/doom_aabbtree.cpp new file mode 100644 index 00000000000..718040b8e31 --- /dev/null +++ b/src/rendering/hwrenderer/doom_aabbtree.cpp @@ -0,0 +1,273 @@ +// +//--------------------------------------------------------------------------- +// AABB-tree used for ray testing +// Copyright(C) 2017 Magnus Norddahl +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + + + +#include "doom_aabbtree.h" +#include "g_levellocals.h" + +using namespace hwrenderer; + +DoomLevelAABBTree::DoomLevelAABBTree(FLevelLocals *lev) +{ + Level = lev; + // Calculate the center of all lines + TArray centroids; + for (unsigned int i = 0; i < Level->lines.Size(); i++) + { + FVector2 v1 = { (float)Level->lines[i].v1->fX(), (float)Level->lines[i].v1->fY() }; + FVector2 v2 = { (float)Level->lines[i].v2->fX(), (float)Level->lines[i].v2->fY() }; + centroids.Push((v1 + v2) * 0.5f); + } + + // Create the static subtree + if (!GenerateTree(¢roids[0], false)) + return; + + int staticroot = nodes.Size() - 1; + + dynamicStartNode = nodes.Size(); + dynamicStartLine = treelines.Size(); + + // Create the dynamic subtree + if (GenerateTree(¢roids[0], true)) + { + int dynamicroot = nodes.Size() - 1; + + // Create a shared root node + FVector2 aabb_min, aabb_max; + const auto &left = nodes[staticroot]; + const auto &right = nodes[dynamicroot]; + aabb_min.X = min(left.aabb_left, right.aabb_left); + aabb_min.Y = min(left.aabb_top, right.aabb_top); + aabb_max.X = max(left.aabb_right, right.aabb_right); + aabb_max.Y = max(left.aabb_bottom, right.aabb_bottom); + nodes.Push({ aabb_min, aabb_max, staticroot, dynamicroot }); + } + + // Add the lines referenced by the leaf nodes + treelines.Resize(mapLines.Size()); + for (unsigned int i = 0; i < mapLines.Size(); i++) + { + const auto &line = Level->lines[mapLines[i]]; + auto &treeline = treelines[i]; + + treeline.x = (float)line.v1->fX(); + treeline.y = (float)line.v1->fY(); + treeline.dx = (float)line.v2->fX() - treeline.x; + treeline.dy = (float)line.v2->fY() - treeline.y; + } +} + +bool DoomLevelAABBTree::GenerateTree(const FVector2 *centroids, bool dynamicsubtree) +{ + // Create a list of level lines we want to add: + TArray line_elements; + auto &maplines = Level->lines; + for (unsigned int i = 0; i < maplines.Size(); i++) + { + if (!maplines[i].backsector) + { + bool isPolyLine = maplines[i].sidedef[0] && (maplines[i].sidedef[0]->Flags & WALLF_POLYOBJ); + if (isPolyLine && dynamicsubtree) + { + line_elements.Push(mapLines.Size()); + mapLines.Push(i); + } + else if (!isPolyLine && !dynamicsubtree) + { + line_elements.Push(mapLines.Size()); + mapLines.Push(i); + } + } + } + + if (line_elements.Size() == 0) + return false; + + // GenerateTreeNode needs a buffer where it can store line indices temporarily when sorting lines into the left and right child AABB buckets + TArray work_buffer; + work_buffer.Resize(line_elements.Size() * 2); + + // Generate the AABB tree + GenerateTreeNode(&line_elements[0], (int)line_elements.Size(), centroids, &work_buffer[0]); + return true; +} + +bool DoomLevelAABBTree::Update() +{ + bool modified = false; + for (unsigned int i = dynamicStartLine; i < mapLines.Size(); i++) + { + const auto &line = Level->lines[mapLines[i]]; + + AABBTreeLine treeline; + treeline.x = (float)line.v1->fX(); + treeline.y = (float)line.v1->fY(); + treeline.dx = (float)line.v2->fX() - treeline.x; + treeline.dy = (float)line.v2->fY() - treeline.y; + + if (memcmp(&treelines[i], &treeline, sizeof(AABBTreeLine))) + { + TArray path = FindNodePath(i, nodes.Size() - 1); + if (path.Size()) + { + float x1 = (float)line.v1->fX(); + float y1 = (float)line.v1->fY(); + float x2 = (float)line.v2->fX(); + float y2 = (float)line.v2->fY(); + + int nodeIndex = path[0]; + nodes[nodeIndex].aabb_left = min(x1, x2); + nodes[nodeIndex].aabb_right = max(x1, x2); + nodes[nodeIndex].aabb_top = min(y1, y2); + nodes[nodeIndex].aabb_bottom = max(y1, y2); + + for (unsigned int j = 1; j < path.Size(); j++) + { + auto &cur = nodes[path[j]]; + const auto &left = nodes[cur.left_node]; + const auto &right = nodes[cur.right_node]; + cur.aabb_left = min(left.aabb_left, right.aabb_left); + cur.aabb_top = min(left.aabb_top, right.aabb_top); + cur.aabb_right = max(left.aabb_right, right.aabb_right); + cur.aabb_bottom = max(left.aabb_bottom, right.aabb_bottom); + } + + treelines[i] = treeline; + modified = true; + } + } + } + return modified; +} + + +int DoomLevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *centroids, int *work_buffer) +{ + if (num_lines == 0) + return -1; + + // Find bounding box and median of the lines + FVector2 median = FVector2(0.0f, 0.0f); + FVector2 aabb_min, aabb_max; + auto &maplines = Level->lines; + aabb_min.X = (float)maplines[mapLines[lines[0]]].v1->fX(); + aabb_min.Y = (float)maplines[mapLines[lines[0]]].v1->fY(); + aabb_max = aabb_min; + for (int i = 0; i < num_lines; i++) + { + float x1 = (float)maplines[mapLines[lines[i]]].v1->fX(); + float y1 = (float)maplines[mapLines[lines[i]]].v1->fY(); + float x2 = (float)maplines[mapLines[lines[i]]].v2->fX(); + float y2 = (float)maplines[mapLines[lines[i]]].v2->fY(); + + aabb_min.X = min(aabb_min.X, x1); + aabb_min.X = min(aabb_min.X, x2); + aabb_min.Y = min(aabb_min.Y, y1); + aabb_min.Y = min(aabb_min.Y, y2); + aabb_max.X = max(aabb_max.X, x1); + aabb_max.X = max(aabb_max.X, x2); + aabb_max.Y = max(aabb_max.Y, y1); + aabb_max.Y = max(aabb_max.Y, y2); + + median += centroids[mapLines[lines[i]]]; + } + median /= (float)num_lines; + + if (num_lines == 1) // Leaf node + { + nodes.Push(AABBTreeNode(aabb_min, aabb_max, lines[0])); + return (int)nodes.Size() - 1; + } + + // Find the longest axis + float axis_lengths[2] = + { + aabb_max.X - aabb_min.X, + aabb_max.Y - aabb_min.Y + }; + int axis_order[2] = { 0, 1 }; + FVector2 axis_plane[2] = { FVector2(1.0f, 0.0f), FVector2(0.0f, 1.0f) }; + std::sort(axis_order, axis_order + 2, [&](int a, int b) { return axis_lengths[a] > axis_lengths[b]; }); + + // Try sort at longest axis, then if that fails then the other one. + // We place the sorted lines into work_buffer and then move the result back to the lines list when done. + int left_count, right_count; + for (int attempt = 0; attempt < 2; attempt++) + { + // Find the sort plane for axis + FVector2 axis = axis_plane[axis_order[attempt]]; + FVector3 plane(axis, -(median | axis)); + + // Sort lines into two based ib whether the line center is on the front or back side of a plane + left_count = 0; + right_count = 0; + for (int i = 0; i < num_lines; i++) + { + int line_index = lines[i]; + + float side = FVector3(centroids[mapLines[lines[i]]], 1.0f) | plane; + if (side >= 0.0f) + { + work_buffer[left_count] = line_index; + left_count++; + } + else + { + work_buffer[num_lines + right_count] = line_index; + right_count++; + } + } + + if (left_count != 0 && right_count != 0) + break; + } + + // Check if something went wrong when sorting and do a random sort instead + if (left_count == 0 || right_count == 0) + { + left_count = num_lines / 2; + right_count = num_lines - left_count; + } + else + { + // Move result back into lines list: + for (int i = 0; i < left_count; i++) + lines[i] = work_buffer[i]; + for (int i = 0; i < right_count; i++) + lines[i + left_count] = work_buffer[num_lines + i]; + } + + // Create child nodes: + int left_index = -1; + int right_index = -1; + if (left_count > 0) + left_index = GenerateTreeNode(lines, left_count, centroids, work_buffer); + if (right_count > 0) + right_index = GenerateTreeNode(lines + left_count, right_count, centroids, work_buffer); + + // Store resulting node and return its index + nodes.Push(AABBTreeNode(aabb_min, aabb_max, left_index, right_index)); + return (int)nodes.Size() - 1; +} + diff --git a/src/rendering/hwrenderer/doom_aabbtree.h b/src/rendering/hwrenderer/doom_aabbtree.h new file mode 100644 index 00000000000..37afb8cace2 --- /dev/null +++ b/src/rendering/hwrenderer/doom_aabbtree.h @@ -0,0 +1,23 @@ +#pragma once +#include "hw_aabbtree.h" + +struct FLevelLocals; + +// Axis aligned bounding box tree used for ray testing treelines. +class DoomLevelAABBTree : public hwrenderer::LevelAABBTree +{ +public: + // Constructs a tree for the current level + DoomLevelAABBTree(FLevelLocals *lev); + bool Update() override; + +private: + bool GenerateTree(const FVector2 *centroids, bool dynamicsubtree); + + // Generate a tree node and its children recursively + int GenerateTreeNode(int *treelines, int num_lines, const FVector2 *centroids, int *work_buffer); + + TArray mapLines; + FLevelLocals *Level; +}; + diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp new file mode 100644 index 00000000000..ea8aa314d24 --- /dev/null +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -0,0 +1,387 @@ + +#include "templates.h" +#include "doom_levelmesh.h" +#include "g_levellocals.h" +#include "texturemanager.h" + +DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap) +{ + for (unsigned int i = 0; i < doomMap.sides.Size(); i++) + { + CreateSideSurfaces(doomMap, &doomMap.sides[i]); + } + + CreateSubsectorSurfaces(doomMap); + + for (size_t i = 0; i < Surfaces.Size(); i++) + { + const Surface &s = Surfaces[i]; + int numVerts = s.numVerts; + unsigned int pos = s.startVertIndex; + FVector3* verts = &MeshVertices[pos]; + + for (int j = 0; j < numVerts; j++) + { + MeshUVIndex.Push(j); + } + + if (s.type == ST_FLOOR || s.type == ST_CEILING) + { + for (int j = 2; j < numVerts; j++) + { + if (!IsDegenerate(verts[0], verts[j - 1], verts[j])) + { + MeshElements.Push(pos); + MeshElements.Push(pos + j - 1); + MeshElements.Push(pos + j); + MeshSurfaces.Push((int)i); + } + } + } + else if (s.type == ST_MIDDLEWALL || s.type == ST_UPPERWALL || s.type == ST_LOWERWALL) + { + if (!IsDegenerate(verts[0], verts[1], verts[2])) + { + MeshElements.Push(pos + 0); + MeshElements.Push(pos + 1); + MeshElements.Push(pos + 2); + MeshSurfaces.Push((int)i); + } + if (!IsDegenerate(verts[1], verts[2], verts[3])) + { + MeshElements.Push(pos + 3); + MeshElements.Push(pos + 2); + MeshElements.Push(pos + 1); + MeshSurfaces.Push((int)i); + } + } + } +} + +void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side) +{ + sector_t *front; + sector_t *back; + + front = side->sector; + back = (side->linedef->frontsector == front) ? side->linedef->backsector : side->linedef->frontsector; + + if (IsControlSector(front)) + return; + + FVector2 v1 = ToFVector2(side->V1()->fPos()); + FVector2 v2 = ToFVector2(side->V2()->fPos()); + + float v1Top = (float)front->ceilingplane.ZatPoint(v1); + float v1Bottom = (float)front->floorplane.ZatPoint(v1); + float v2Top = (float)front->ceilingplane.ZatPoint(v2); + float v2Bottom = (float)front->floorplane.ZatPoint(v2); + + int typeIndex = side->Index(); + + FVector2 dx(v2.X - v1.X, v2.Y - v1.Y); + float distance = dx.Length(); + + if (back) + { + for (unsigned int j = 0; j < front->e->XFloor.ffloors.Size(); j++) + { + F3DFloor *xfloor = front->e->XFloor.ffloors[j]; + + // Don't create a line when both sectors have the same 3d floor + bool bothSides = false; + for (unsigned int k = 0; k < back->e->XFloor.ffloors.Size(); k++) + { + if (back->e->XFloor.ffloors[k] == xfloor) + { + bothSides = true; + break; + } + } + if (bothSides) + continue; + + Surface surf; + surf.type = ST_MIDDLEWALL; + surf.typeIndex = typeIndex; + surf.controlSector = xfloor->model; + + FVector3 verts[4]; + verts[0].X = verts[2].X = v2.X; + verts[0].Y = verts[2].Y = v2.Y; + verts[1].X = verts[3].X = v1.X; + verts[1].Y = verts[3].Y = v1.Y; + verts[0].Z = (float)xfloor->model->floorplane.ZatPoint(v2); + verts[1].Z = (float)xfloor->model->floorplane.ZatPoint(v1); + verts[2].Z = (float)xfloor->model->ceilingplane.ZatPoint(v2); + verts[3].Z = (float)xfloor->model->ceilingplane.ZatPoint(v1); + + surf.startVertIndex = MeshVertices.Size(); + surf.numVerts = 4; + MeshVertices.Push(verts[0]); + MeshVertices.Push(verts[1]); + MeshVertices.Push(verts[2]); + MeshVertices.Push(verts[3]); + + surf.plane = ToPlane(verts[0], verts[1], verts[2]); + Surfaces.Push(surf); + } + + float v1TopBack = (float)back->ceilingplane.ZatPoint(v1); + float v1BottomBack = (float)back->floorplane.ZatPoint(v1); + float v2TopBack = (float)back->ceilingplane.ZatPoint(v2); + float v2BottomBack = (float)back->floorplane.ZatPoint(v2); + + if (v1Top == v1TopBack && v1Bottom == v1BottomBack && v2Top == v2TopBack && v2Bottom == v2BottomBack) + { + return; + } + + // bottom seg + if (v1Bottom < v1BottomBack || v2Bottom < v2BottomBack) + { + if (IsBottomSideVisible(side)) + { + Surface surf; + + FVector3 verts[4]; + verts[0].X = verts[2].X = v1.X; + verts[0].Y = verts[2].Y = v1.Y; + verts[1].X = verts[3].X = v2.X; + verts[1].Y = verts[3].Y = v2.Y; + verts[0].Z = v1Bottom; + verts[1].Z = v2Bottom; + verts[2].Z = v1BottomBack; + verts[3].Z = v2BottomBack; + + surf.startVertIndex = MeshVertices.Size(); + surf.numVerts = 4; + MeshVertices.Push(verts[0]); + MeshVertices.Push(verts[1]); + MeshVertices.Push(verts[2]); + MeshVertices.Push(verts[3]); + + surf.plane = ToPlane(verts[0], verts[1], verts[2]); + surf.type = ST_LOWERWALL; + surf.typeIndex = typeIndex; + surf.controlSector = nullptr; + + Surfaces.Push(surf); + } + + v1Bottom = v1BottomBack; + v2Bottom = v2BottomBack; + } + + // top seg + if (v1Top > v1TopBack || v2Top > v2TopBack) + { + bool bSky = IsTopSideSky(front, back, side); + if (bSky || IsTopSideVisible(side)) + { + Surface surf; + + FVector3 verts[4]; + verts[0].X = verts[2].X = v1.X; + verts[0].Y = verts[2].Y = v1.Y; + verts[1].X = verts[3].X = v2.X; + verts[1].Y = verts[3].Y = v2.Y; + verts[0].Z = v1TopBack; + verts[1].Z = v2TopBack; + verts[2].Z = v1Top; + verts[3].Z = v2Top; + + surf.startVertIndex = MeshVertices.Size(); + surf.numVerts = 4; + MeshVertices.Push(verts[0]); + MeshVertices.Push(verts[1]); + MeshVertices.Push(verts[2]); + MeshVertices.Push(verts[3]); + + surf.plane = ToPlane(verts[0], verts[1], verts[2]); + surf.type = ST_UPPERWALL; + surf.typeIndex = typeIndex; + surf.bSky = bSky; + surf.controlSector = nullptr; + + Surfaces.Push(surf); + } + + v1Top = v1TopBack; + v2Top = v2TopBack; + } + } + + // middle seg + if (back == nullptr) + { + Surface surf; + + FVector3 verts[4]; + verts[0].X = verts[2].X = v1.X; + verts[0].Y = verts[2].Y = v1.Y; + verts[1].X = verts[3].X = v2.X; + verts[1].Y = verts[3].Y = v2.Y; + verts[0].Z = v1Bottom; + verts[1].Z = v2Bottom; + verts[2].Z = v1Top; + verts[3].Z = v2Top; + + surf.startVertIndex = MeshVertices.Size(); + surf.numVerts = 4; + MeshVertices.Push(verts[0]); + MeshVertices.Push(verts[1]); + MeshVertices.Push(verts[2]); + MeshVertices.Push(verts[3]); + + surf.plane = ToPlane(verts[0], verts[1], verts[2]); + surf.type = ST_MIDDLEWALL; + surf.typeIndex = typeIndex; + surf.controlSector = nullptr; + + Surfaces.Push(surf); + } +} + +void DoomLevelMesh::CreateFloorSurface(FLevelLocals &doomMap, subsector_t *sub, sector_t *sector, int typeIndex, bool is3DFloor) +{ + Surface surf; + + if (!is3DFloor) + { + surf.plane = sector->floorplane; + } + else + { + surf.plane = sector->ceilingplane; + surf.plane.FlipVert(); + } + + surf.numVerts = sub->numlines; + surf.startVertIndex = MeshVertices.Size(); + MeshVertices.Resize(surf.startVertIndex + surf.numVerts); + FVector3* verts = &MeshVertices[surf.startVertIndex]; + + for (int j = 0; j < surf.numVerts; j++) + { + seg_t *seg = &sub->firstline[(surf.numVerts - 1) - j]; + FVector2 v1 = ToFVector2(seg->v1->fPos()); + + verts[j].X = v1.X; + verts[j].Y = v1.Y; + verts[j].Z = (float)surf.plane.ZatPoint(verts[j]); + } + + surf.type = ST_FLOOR; + surf.typeIndex = typeIndex; + surf.controlSector = is3DFloor ? sector : nullptr; + + Surfaces.Push(surf); +} + +void DoomLevelMesh::CreateCeilingSurface(FLevelLocals &doomMap, subsector_t *sub, sector_t *sector, int typeIndex, bool is3DFloor) +{ + Surface surf; + surf.bSky = IsSkySector(sector); + + if (!is3DFloor) + { + surf.plane = sector->ceilingplane; + } + else + { + surf.plane = sector->floorplane; + surf.plane.FlipVert(); + } + + surf.numVerts = sub->numlines; + surf.startVertIndex = MeshVertices.Size(); + MeshVertices.Resize(surf.startVertIndex + surf.numVerts); + FVector3* verts = &MeshVertices[surf.startVertIndex]; + + for (int j = 0; j < surf.numVerts; j++) + { + seg_t *seg = &sub->firstline[j]; + FVector2 v1 = ToFVector2(seg->v1->fPos()); + + verts[j].X = v1.X; + verts[j].Y = v1.Y; + verts[j].Z = (float)surf.plane.ZatPoint(verts[j]); + } + + surf.type = ST_CEILING; + surf.typeIndex = typeIndex; + surf.controlSector = is3DFloor ? sector : nullptr; + + Surfaces.Push(surf); +} + +void DoomLevelMesh::CreateSubsectorSurfaces(FLevelLocals &doomMap) +{ + for (unsigned int i = 0; i < doomMap.subsectors.Size(); i++) + { + subsector_t *sub = &doomMap.subsectors[i]; + + if (sub->numlines < 3) + { + continue; + } + + sector_t *sector = sub->sector; + if (!sector || IsControlSector(sector)) + continue; + + CreateFloorSurface(doomMap, sub, sector, i, false); + CreateCeilingSurface(doomMap, sub, sector, i, false); + + for (unsigned int j = 0; j < sector->e->XFloor.ffloors.Size(); j++) + { + CreateFloorSurface(doomMap, sub, sector->e->XFloor.ffloors[j]->model, i, true); + CreateCeilingSurface(doomMap, sub, sector->e->XFloor.ffloors[j]->model, i, true); + } + } +} + +bool DoomLevelMesh::IsTopSideSky(sector_t* frontsector, sector_t* backsector, side_t* side) +{ + return IsSkySector(frontsector) && IsSkySector(backsector); +} + +bool DoomLevelMesh::IsTopSideVisible(side_t* side) +{ + auto tex = TexMan.GetGameTexture(side->GetTexture(side_t::top), true); + return tex && tex->isValid(); +} + +bool DoomLevelMesh::IsBottomSideVisible(side_t* side) +{ + auto tex = TexMan.GetGameTexture(side->GetTexture(side_t::bottom), true); + return tex && tex->isValid(); +} + +bool DoomLevelMesh::IsSkySector(sector_t* sector) +{ + return sector->GetTexture(sector_t::ceiling) == skyflatnum; +} + +bool DoomLevelMesh::IsControlSector(sector_t* sector) +{ + //return sector->controlsector; + return false; +} + +bool DoomLevelMesh::IsDegenerate(const FVector3 &v0, const FVector3 &v1, const FVector3 &v2) +{ + // A degenerate triangle has a zero cross product for two of its sides. + float ax = v1.X - v0.X; + float ay = v1.Y - v0.Y; + float az = v1.Z - v0.Z; + float bx = v2.X - v0.X; + float by = v2.Y - v0.Y; + float bz = v2.Z - v0.Z; + float crossx = ay * bz - az * by; + float crossy = az * bx - ax * bz; + float crossz = ax * by - ay * bx; + float crosslengthsqr = crossx * crossx + crossy * crossy + crossz * crossz; + return crosslengthsqr <= 1.e-6f; +} diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h new file mode 100644 index 00000000000..73dc1a5bfab --- /dev/null +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -0,0 +1,55 @@ + +#pragma once + +#include "hw_levelmesh.h" +#include "tarray.h" +#include "vectors.h" +#include "r_defs.h" + +struct FLevelLocals; + +struct Surface +{ + SurfaceType type; + int typeIndex; + int numVerts; + unsigned int startVertIndex; + secplane_t plane; + sector_t *controlSector; + bool bSky; +}; + +class DoomLevelMesh : public hwrenderer::LevelMesh +{ +public: + DoomLevelMesh(FLevelLocals &doomMap); + + TArray Surfaces; + +private: + void CreateSubsectorSurfaces(FLevelLocals &doomMap); + void CreateCeilingSurface(FLevelLocals &doomMap, subsector_t *sub, sector_t *sector, int typeIndex, bool is3DFloor); + void CreateFloorSurface(FLevelLocals &doomMap, subsector_t *sub, sector_t *sector, int typeIndex, bool is3DFloor); + void CreateSideSurfaces(FLevelLocals &doomMap, side_t *side); + + static bool IsTopSideSky(sector_t* frontsector, sector_t* backsector, side_t* side); + static bool IsTopSideVisible(side_t* side); + static bool IsBottomSideVisible(side_t* side); + static bool IsSkySector(sector_t* sector); + static bool IsControlSector(sector_t* sector); + + static secplane_t ToPlane(const FVector3& pt1, const FVector3& pt2, const FVector3& pt3) + { + FVector3 n = ((pt2 - pt1) ^ (pt3 - pt2)).Unit(); + float d = pt1 | n; + secplane_t p; + p.set(n.X, n.Y, n.Z, d); + return p; + } + + static FVector2 ToFVector2(const DVector2& v) { return FVector2((float)v.X, (float)v.Y); } + static FVector3 ToFVector3(const DVector3& v) { return FVector3((float)v.X, (float)v.Y, (float)v.Z); } + static FVector4 ToFVector4(const DVector4& v) { return FVector4((float)v.X, (float)v.Y, (float)v.Z, (float)v.W); } + + static bool IsDegenerate(const FVector3 &v0, const FVector3 &v1, const FVector3 &v2); +}; diff --git a/src/rendering/hwrenderer/dynlights/hw_aabbtree.cpp b/src/rendering/hwrenderer/dynlights/hw_aabbtree.cpp deleted file mode 100644 index a0c36574045..00000000000 --- a/src/rendering/hwrenderer/dynlights/hw_aabbtree.cpp +++ /dev/null @@ -1,410 +0,0 @@ -// -//--------------------------------------------------------------------------- -// AABB-tree used for ray testing -// Copyright(C) 2017 Magnus Norddahl -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#include "r_state.h" -#include "g_levellocals.h" -#include "hw_aabbtree.h" - -namespace hwrenderer -{ - -LevelAABBTree::LevelAABBTree(FLevelLocals *lev) -{ - Level = lev; - // Calculate the center of all lines - TArray centroids; - for (unsigned int i = 0; i < Level->lines.Size(); i++) - { - FVector2 v1 = { (float)Level->lines[i].v1->fX(), (float)Level->lines[i].v1->fY() }; - FVector2 v2 = { (float)Level->lines[i].v2->fX(), (float)Level->lines[i].v2->fY() }; - centroids.Push((v1 + v2) * 0.5f); - } - - // Create the static subtree - if (!GenerateTree(¢roids[0], false)) - return; - - int staticroot = nodes.Size() - 1; - - dynamicStartNode = nodes.Size(); - dynamicStartLine = treelines.Size(); - - // Create the dynamic subtree - if (GenerateTree(¢roids[0], true)) - { - int dynamicroot = nodes.Size() - 1; - - // Create a shared root node - FVector2 aabb_min, aabb_max; - const auto &left = nodes[staticroot]; - const auto &right = nodes[dynamicroot]; - aabb_min.X = MIN(left.aabb_left, right.aabb_left); - aabb_min.Y = MIN(left.aabb_top, right.aabb_top); - aabb_max.X = MAX(left.aabb_right, right.aabb_right); - aabb_max.Y = MAX(left.aabb_bottom, right.aabb_bottom); - nodes.Push({ aabb_min, aabb_max, staticroot, dynamicroot }); - } - - // Add the lines referenced by the leaf nodes - treelines.Resize(mapLines.Size()); - for (unsigned int i = 0; i < mapLines.Size(); i++) - { - const auto &line = Level->lines[mapLines[i]]; - auto &treeline = treelines[i]; - - treeline.x = (float)line.v1->fX(); - treeline.y = (float)line.v1->fY(); - treeline.dx = (float)line.v2->fX() - treeline.x; - treeline.dy = (float)line.v2->fY() - treeline.y; - } -} - -bool LevelAABBTree::GenerateTree(const FVector2 *centroids, bool dynamicsubtree) -{ - // Create a list of level lines we want to add: - TArray line_elements; - auto &maplines = Level->lines; - for (unsigned int i = 0; i < maplines.Size(); i++) - { - if (!maplines[i].backsector) - { - bool isPolyLine = maplines[i].sidedef[0] && (maplines[i].sidedef[0]->Flags & WALLF_POLYOBJ); - if (isPolyLine && dynamicsubtree) - { - line_elements.Push(mapLines.Size()); - mapLines.Push(i); - } - else if (!isPolyLine && !dynamicsubtree) - { - line_elements.Push(mapLines.Size()); - mapLines.Push(i); - } - } - } - - if (line_elements.Size() == 0) - return false; - - // GenerateTreeNode needs a buffer where it can store line indices temporarily when sorting lines into the left and right child AABB buckets - TArray work_buffer; - work_buffer.Resize(line_elements.Size() * 2); - - // Generate the AABB tree - GenerateTreeNode(&line_elements[0], (int)line_elements.Size(), centroids, &work_buffer[0]); - return true; -} - -bool LevelAABBTree::Update() -{ - bool modified = false; - for (unsigned int i = dynamicStartLine; i < mapLines.Size(); i++) - { - const auto &line = Level->lines[mapLines[i]]; - - AABBTreeLine treeline; - treeline.x = (float)line.v1->fX(); - treeline.y = (float)line.v1->fY(); - treeline.dx = (float)line.v2->fX() - treeline.x; - treeline.dy = (float)line.v2->fY() - treeline.y; - - if (memcmp(&treelines[i], &treeline, sizeof(AABBTreeLine))) - { - TArray path = FindNodePath(i, nodes.Size() - 1); - if (path.Size()) - { - float x1 = (float)line.v1->fX(); - float y1 = (float)line.v1->fY(); - float x2 = (float)line.v2->fX(); - float y2 = (float)line.v2->fY(); - - int nodeIndex = path[0]; - nodes[nodeIndex].aabb_left = MIN(x1, x2); - nodes[nodeIndex].aabb_right = MAX(x1, x2); - nodes[nodeIndex].aabb_top = MIN(y1, y2); - nodes[nodeIndex].aabb_bottom = MAX(y1, y2); - - for (unsigned int j = 1; j < path.Size(); j++) - { - auto &cur = nodes[path[j]]; - const auto &left = nodes[cur.left_node]; - const auto &right = nodes[cur.right_node]; - cur.aabb_left = MIN(left.aabb_left, right.aabb_left); - cur.aabb_top = MIN(left.aabb_top, right.aabb_top); - cur.aabb_right = MAX(left.aabb_right, right.aabb_right); - cur.aabb_bottom = MAX(left.aabb_bottom, right.aabb_bottom); - } - - treelines[i] = treeline; - modified = true; - } - } - } - return modified; -} - -TArray LevelAABBTree::FindNodePath(unsigned int line, unsigned int node) -{ - const AABBTreeNode &n = nodes[node]; - - if (n.aabb_left > treelines[line].x || n.aabb_right < treelines[line].x || - n.aabb_top > treelines[line].y || n.aabb_bottom < treelines[line].y) - { - return {}; - } - - TArray path; - if (n.line_index == -1) - { - path = FindNodePath(line, n.left_node); - if (path.Size() == 0) - path = FindNodePath(line, n.right_node); - - if (path.Size()) - path.Push(node); - } - else if (n.line_index == (int)line) - { - path.Push(node); - } - return path; -} - -double LevelAABBTree::RayTest(const DVector3 &ray_start, const DVector3 &ray_end) -{ - // Precalculate some of the variables used by the ray/line intersection test - DVector2 raydelta = ray_end - ray_start; - double raydist2 = raydelta | raydelta; - DVector2 raynormal = DVector2(raydelta.Y, -raydelta.X); - double rayd = raynormal | ray_start; - if (raydist2 < 1.0) - return 1.0f; - - double hit_fraction = 1.0; - - // Walk the tree nodes - int stack[32]; - int stack_pos = 1; - stack[0] = nodes.Size() - 1; // root node is the last node in the list - while (stack_pos > 0) - { - int node_index = stack[stack_pos - 1]; - - if (!OverlapRayAABB(ray_start, ray_end, nodes[node_index])) - { - // If the ray doesn't overlap this node's AABB we're done for this subtree - stack_pos--; - } - else if (nodes[node_index].line_index != -1) // isLeaf(node_index) - { - // We reached a leaf node. Do a ray/line intersection test to see if we hit the line. - hit_fraction = MIN(IntersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), hit_fraction); - stack_pos--; - } - else if (stack_pos == 32) - { - stack_pos--; // stack overflow - tree is too deep! - } - else - { - // The ray overlaps the node's AABB. Examine its child nodes. - stack[stack_pos - 1] = nodes[node_index].left_node; - stack[stack_pos] = nodes[node_index].right_node; - stack_pos++; - } - } - - return hit_fraction; -} - -bool LevelAABBTree::OverlapRayAABB(const DVector2 &ray_start2d, const DVector2 &ray_end2d, const AABBTreeNode &node) -{ - // To do: simplify test to use a 2D test - DVector3 ray_start = DVector3(ray_start2d, 0.0); - DVector3 ray_end = DVector3(ray_end2d, 0.0); - DVector3 aabb_min = DVector3(node.aabb_left, node.aabb_top, -1.0); - DVector3 aabb_max = DVector3(node.aabb_right, node.aabb_bottom, 1.0); - - // Standard 3D ray/AABB overlapping test. - // The details for the math here can be found in Real-Time Rendering, 3rd Edition. - // We could use a 2D test here instead, which would probably simplify the math. - - DVector3 c = (ray_start + ray_end) * 0.5f; - DVector3 w = ray_end - c; - DVector3 h = (aabb_max - aabb_min) * 0.5f; // aabb.extents(); - - c -= (aabb_max + aabb_min) * 0.5f; // aabb.center(); - - DVector3 v = DVector3(fabs(w.X), fabs(w.Y), fabs(w.Z)); - - if (fabs(c.X) > v.X + h.X || fabs(c.Y) > v.Y + h.Y || fabs(c.Z) > v.Z + h.Z) - return false; // disjoint; - - if (fabs(c.Y * w.Z - c.Z * w.Y) > h.Y * v.Z + h.Z * v.Y || - fabs(c.X * w.Z - c.Z * w.X) > h.X * v.Z + h.Z * v.X || - fabs(c.X * w.Y - c.Y * w.X) > h.X * v.Y + h.Y * v.X) - return false; // disjoint; - - return true; // overlap; -} - -double LevelAABBTree::IntersectRayLine(const DVector2 &ray_start, const DVector2 &ray_end, int line_index, const DVector2 &raydelta, double rayd, double raydist2) -{ - // Check if two line segments intersects (the ray and the line). - // The math below does this by first finding the fractional hit for an infinitely long ray line. - // If that hit is within the line segment (0 to 1 range) then it calculates the fractional hit for where the ray would hit. - // - // This algorithm is homemade - I would not be surprised if there's a much faster method out there. - - const double epsilon = 0.0000001; - const AABBTreeLine &line = treelines[line_index]; - - DVector2 raynormal = DVector2(raydelta.Y, -raydelta.X); - - DVector2 line_pos(line.x, line.y); - DVector2 line_delta(line.dx, line.dy); - - double den = raynormal | line_delta; - if (fabs(den) > epsilon) - { - double t_line = (rayd - (raynormal | line_pos)) / den; - if (t_line >= 0.0 && t_line <= 1.0) - { - DVector2 linehitdelta = line_pos + line_delta * t_line - ray_start; - double t = (raydelta | linehitdelta) / raydist2; - return t > 0.0 ? t : 1.0; - } - } - - return 1.0; -} - -int LevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *centroids, int *work_buffer) -{ - if (num_lines == 0) - return -1; - - // Find bounding box and median of the lines - FVector2 median = FVector2(0.0f, 0.0f); - FVector2 aabb_min, aabb_max; - auto &maplines = Level->lines; - aabb_min.X = (float)maplines[mapLines[lines[0]]].v1->fX(); - aabb_min.Y = (float)maplines[mapLines[lines[0]]].v1->fY(); - aabb_max = aabb_min; - for (int i = 0; i < num_lines; i++) - { - float x1 = (float)maplines[mapLines[lines[i]]].v1->fX(); - float y1 = (float)maplines[mapLines[lines[i]]].v1->fY(); - float x2 = (float)maplines[mapLines[lines[i]]].v2->fX(); - float y2 = (float)maplines[mapLines[lines[i]]].v2->fY(); - - aabb_min.X = MIN(aabb_min.X, x1); - aabb_min.X = MIN(aabb_min.X, x2); - aabb_min.Y = MIN(aabb_min.Y, y1); - aabb_min.Y = MIN(aabb_min.Y, y2); - aabb_max.X = MAX(aabb_max.X, x1); - aabb_max.X = MAX(aabb_max.X, x2); - aabb_max.Y = MAX(aabb_max.Y, y1); - aabb_max.Y = MAX(aabb_max.Y, y2); - - median += centroids[mapLines[lines[i]]]; - } - median /= (float)num_lines; - - if (num_lines == 1) // Leaf node - { - nodes.Push(AABBTreeNode(aabb_min, aabb_max, lines[0])); - return (int)nodes.Size() - 1; - } - - // Find the longest axis - float axis_lengths[2] = - { - aabb_max.X - aabb_min.X, - aabb_max.Y - aabb_min.Y - }; - int axis_order[2] = { 0, 1 }; - FVector2 axis_plane[2] = { FVector2(1.0f, 0.0f), FVector2(0.0f, 1.0f) }; - std::sort(axis_order, axis_order + 2, [&](int a, int b) { return axis_lengths[a] > axis_lengths[b]; }); - - // Try sort at longest axis, then if that fails then the other one. - // We place the sorted lines into work_buffer and then move the result back to the lines list when done. - int left_count, right_count; - for (int attempt = 0; attempt < 2; attempt++) - { - // Find the sort plane for axis - FVector2 axis = axis_plane[axis_order[attempt]]; - FVector3 plane(axis, -(median | axis)); - - // Sort lines into two based ib whether the line center is on the front or back side of a plane - left_count = 0; - right_count = 0; - for (int i = 0; i < num_lines; i++) - { - int line_index = lines[i]; - - float side = FVector3(centroids[mapLines[lines[i]]], 1.0f) | plane; - if (side >= 0.0f) - { - work_buffer[left_count] = line_index; - left_count++; - } - else - { - work_buffer[num_lines + right_count] = line_index; - right_count++; - } - } - - if (left_count != 0 && right_count != 0) - break; - } - - // Check if something went wrong when sorting and do a random sort instead - if (left_count == 0 || right_count == 0) - { - left_count = num_lines / 2; - right_count = num_lines - left_count; - } - else - { - // Move result back into lines list: - for (int i = 0; i < left_count; i++) - lines[i] = work_buffer[i]; - for (int i = 0; i < right_count; i++) - lines[i + left_count] = work_buffer[num_lines + i]; - } - - // Create child nodes: - int left_index = -1; - int right_index = -1; - if (left_count > 0) - left_index = GenerateTreeNode(lines, left_count, centroids, work_buffer); - if (right_count > 0) - right_index = GenerateTreeNode(lines + left_count, right_count, centroids, work_buffer); - - // Store resulting node and return its index - nodes.Push(AABBTreeNode(aabb_min, aabb_max, left_index, right_index)); - return (int)nodes.Size() - 1; -} - - -} diff --git a/src/rendering/hwrenderer/dynlights/hw_shadowmap.cpp b/src/rendering/hwrenderer/dynlights/hw_shadowmap.cpp deleted file mode 100644 index aba51140a8b..00000000000 --- a/src/rendering/hwrenderer/dynlights/hw_shadowmap.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// -//--------------------------------------------------------------------------- -// 1D dynamic shadow maps (API independent part) -// Copyright(C) 2017 Magnus Norddahl -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#include "hwrenderer/dynlights/hw_shadowmap.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/data/buffers.h" -#include "hwrenderer/data/shaderuniforms.h" -#include "stats.h" -#include "g_levellocals.h" -#include "v_video.h" - -/* - The 1D shadow maps are stored in a 1024x1024 texture as float depth values (R32F). - - Each line in the texture is assigned to a single light. For example, to grab depth values for light 20 - the fragment shader (main.fp) needs to sample from row 20. That is, the V texture coordinate needs - to be 20.5/1024. - - The texel row for each light is split into four parts. One for each direction, like a cube texture, - but then only in 2D where this reduces itself to a square. When main.fp samples from the shadow map - it first decides in which direction the fragment is (relative to the light), like cubemap sampling does - for 3D, but once again just for the 2D case. - - Texels 0-255 is Y positive, 256-511 is X positive, 512-767 is Y negative and 768-1023 is X negative. - - Generating the shadow map itself is done by FShadowMap::Update(). The shadow map texture's FBO is - bound and then a screen quad is drawn to make a fragment shader cover all texels. For each fragment - it shoots a ray and collects the distance to what it hit. - - The shadowmap.fp shader knows which light and texel it is processing by mapping gl_FragCoord.y back - to the light index, and it knows which direction to ray trace by looking at gl_FragCoord.x. For - example, if gl_FragCoord.y is 20.5, then it knows its processing light 20, and if gl_FragCoord.x is - 127.5, then it knows we are shooting straight ahead for the Y positive direction. - - Ray testing is done by uploading two GPU storage buffers - one holding AABB tree nodes, and one with - the line segments at the leaf nodes of the tree. The fragment shader then performs a test same way - as on the CPU, except everything uses indexes as pointers are not allowed in GLSL. -*/ - -cycle_t IShadowMap::UpdateCycles; -int IShadowMap::LightsProcessed; -int IShadowMap::LightsShadowmapped; - -ADD_STAT(shadowmap) -{ - FString out; - out.Format("upload=%04.2f ms lights=%d shadowmapped=%d", IShadowMap::UpdateCycles.TimeMS(), IShadowMap::LightsProcessed, IShadowMap::LightsShadowmapped); - return out; -} - -CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - switch (self) - { - case 128: - case 256: - case 512: - case 1024: - break; - default: - self = 128; - break; - } -} - -CUSTOM_CVAR (Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (!self) for (auto Level : AllLevels()) - { - auto light = Level->lights; - while (light) - { - light->mShadowmapIndex = 1024; - light = light->next; - } - } -} - -bool IShadowMap::ShadowTest(FDynamicLight *light, const DVector3 &pos) -{ - if (light->shadowmapped && light->GetRadius() > 0.0 && IsEnabled() && mAABBTree) - return mAABBTree->RayTest(light->Pos, pos) >= 1.0f; - else - return true; -} - -bool IShadowMap::IsEnabled() const -{ - return gl_light_shadowmap && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER); -} - -void IShadowMap::CollectLights() -{ - if (mLights.Size() != 1024 * 4) mLights.Resize(1024 * 4); - int lightindex = 0; - auto Level = &level; - - // Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred. - for (auto light = Level->lights; light; light = light->next) - { - LightsProcessed++; - if (light->shadowmapped && light->IsActive() && lightindex < 1024 * 4) - { - LightsShadowmapped++; - - light->mShadowmapIndex = lightindex >> 2; - - mLights[lightindex] = (float)light->X(); - mLights[lightindex+1] = (float)light->Y(); - mLights[lightindex+2] = (float)light->Z(); - mLights[lightindex+3] = light->GetRadius(); - lightindex += 4; - } - else - { - light->mShadowmapIndex = 1024; - } - - } - - for (; lightindex < 1024 * 4; lightindex++) - { - mLights[lightindex] = 0; - } -} - -bool IShadowMap::ValidateAABBTree(FLevelLocals *Level) -{ - // Just comparing the level info is not enough. If two MAPINFO-less levels get played after each other, - // they can both refer to the same default level info. - if (Level->info != mLastLevel && (Level->nodes.Size() != mLastNumNodes || Level->segs.Size() != mLastNumSegs)) - { - mAABBTree.reset(); - - mLastLevel = Level->info; - mLastNumNodes = Level->nodes.Size(); - mLastNumSegs = Level->segs.Size(); - } - - if (mAABBTree) - return true; - - mAABBTree.reset(new hwrenderer::LevelAABBTree(Level)); - return false; -} - -bool IShadowMap::PerformUpdate() -{ - UpdateCycles.Reset(); - - LightsProcessed = 0; - LightsShadowmapped = 0; - - if (IsEnabled()) - { - UpdateCycles.Clock(); - UploadAABBTree(); - UploadLights(); - return true; - } - return false; -} - -void IShadowMap::UploadLights() -{ - CollectLights(); - - if (mLightList == nullptr) - mLightList = screen->CreateDataBuffer(LIGHTLIST_BINDINGPOINT, true, false); - - mLightList->SetData(sizeof(float) * mLights.Size(), &mLights[0]); -} - - -void IShadowMap::UploadAABBTree() -{ - if (!ValidateAABBTree(&level)) - { - if (!mNodesBuffer) - mNodesBuffer = screen->CreateDataBuffer(LIGHTNODES_BINDINGPOINT, true, false); - mNodesBuffer->SetData(mAABBTree->NodesSize(), mAABBTree->Nodes()); - - if (!mLinesBuffer) - mLinesBuffer = screen->CreateDataBuffer(LIGHTLINES_BINDINGPOINT, true, false); - mLinesBuffer->SetData(mAABBTree->LinesSize(), mAABBTree->Lines()); - } - else if (mAABBTree->Update()) - { - mNodesBuffer->SetSubData(mAABBTree->DynamicNodesOffset(), mAABBTree->DynamicNodesSize(), mAABBTree->DynamicNodes()); - mLinesBuffer->SetSubData(mAABBTree->DynamicLinesOffset(), mAABBTree->DynamicLinesSize(), mAABBTree->DynamicLines()); - } -} - -void IShadowMap::Reset() -{ - delete mLightList; mLightList = nullptr; - delete mNodesBuffer; mNodesBuffer = nullptr; - delete mLinesBuffer; mLinesBuffer = nullptr; -} - -IShadowMap::~IShadowMap() -{ - Reset(); -} - diff --git a/src/rendering/hwrenderer/dynlights/hw_shadowmap.h b/src/rendering/hwrenderer/dynlights/hw_shadowmap.h deleted file mode 100644 index bc11f99ba14..00000000000 --- a/src/rendering/hwrenderer/dynlights/hw_shadowmap.h +++ /dev/null @@ -1,76 +0,0 @@ - -#pragma once - -#include "hw_aabbtree.h" -#include "stats.h" -#include - -struct FDynamicLight; -struct level_info_t; -class IDataBuffer; -struct FLevelLocals; - -class IShadowMap -{ -public: - IShadowMap() { } - virtual ~IShadowMap(); - - void Reset(); - - // Test if a world position is in shadow relative to the specified light and returns false if it is - bool ShadowTest(FDynamicLight *light, const DVector3 &pos); - - // Returns true if gl_light_shadowmap is enabled and supported by the hardware - bool IsEnabled() const; - - static cycle_t UpdateCycles; - static int LightsProcessed; - static int LightsShadowmapped; - - bool PerformUpdate(); - void FinishUpdate() - { - UpdateCycles.Clock(); - } - - unsigned int NodesCount() const - { - assert(mAABBTree); - return mAABBTree->NodesCount(); - } - -protected: - void CollectLights(); - bool ValidateAABBTree(FLevelLocals *lev); - - // Upload the AABB-tree to the GPU - void UploadAABBTree(); - - // Upload light list to the GPU - void UploadLights(); - - // Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame - TArray mLights; - - // Used to detect when a level change requires the AABB tree to be regenerated - level_info_t *mLastLevel = nullptr; - unsigned mLastNumNodes = 0; - unsigned mLastNumSegs = 0; - - // AABB-tree of the level, used for ray tests - std::unique_ptr mAABBTree; - - IShadowMap(const IShadowMap &) = delete; - IShadowMap &operator=(IShadowMap &) = delete; - - // OpenGL storage buffer with the list of lights in the shadow map texture - // These buffers need to be accessed by the OpenGL backend directly so that they can be bound. -public: - IDataBuffer *mLightList = nullptr; - - // OpenGL storage buffers for the AABB tree - IDataBuffer *mNodesBuffer = nullptr; - IDataBuffer *mLinesBuffer = nullptr; - -}; diff --git a/src/rendering/hwrenderer/dynlights/hw_dynlightdata.cpp b/src/rendering/hwrenderer/hw_dynlightdata.cpp similarity index 84% rename from src/rendering/hwrenderer/dynlights/hw_dynlightdata.cpp rename to src/rendering/hwrenderer/hw_dynlightdata.cpp index 5139b545d76..044d34d3d59 100644 --- a/src/rendering/hwrenderer/dynlights/hw_dynlightdata.cpp +++ b/src/rendering/hwrenderer/hw_dynlightdata.cpp @@ -26,8 +26,11 @@ **/ #include "actorinlines.h" - +#include "a_dynlight.h" #include "hw_dynlightdata.h" +#include"hw_cvars.h" +#include "v_video.h" +#include "hwrenderer/scene/hw_drawstructs.h" // If we want to share the array to avoid constant allocations it needs to be thread local unless it'd be littered with expensive synchronization. thread_local FDynLightData lightdata; @@ -48,7 +51,7 @@ CVAR (Bool, gl_light_particles, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); // Sets up the parameters to render one dynamic light onto one plane // //========================================================================== -bool FDynLightData::GetLight(int group, Plane & p, FDynamicLight * light, bool checkside) +bool GetLight(FDynLightData& dld, int group, Plane & p, FDynamicLight * light, bool checkside) { DVector3 pos = light->PosRelative(group); float radius = (light->GetRadius()); @@ -62,7 +65,7 @@ bool FDynLightData::GetLight(int group, Plane & p, FDynamicLight * light, bool c return false; } - AddLightToList(group, light, false); + AddLightToList(dld, group, light, false); return true; } @@ -71,7 +74,7 @@ bool FDynLightData::GetLight(int group, Plane & p, FDynamicLight * light, bool c // Add one dynamic light to the light data list // //========================================================================== -void FDynLightData::AddLightToList(int group, FDynamicLight * light, bool forceAttenuate) +void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool forceAttenuate) { int i = 0; @@ -104,9 +107,13 @@ void FDynLightData::AddLightToList(int group, FDynamicLight * light, bool forceA i = 1; } - float shadowIndex = light->mShadowmapIndex + 1.0f; - - // Store attenuate flag in the sign bit of the float. + float shadowIndex; + if (screen->mShadowMap.Enabled()) // note: with shadowmaps switched off, we cannot rely on properly set indices anymore. + { + shadowIndex = light->mShadowmapIndex + 1.0f; + } + else shadowIndex = 1025.f; + // Store attenuate flag in the sign bit of the float. if (light->IsAttenuated() || forceAttenuate) shadowIndex = -shadowIndex; float lightType = 0.0f; @@ -129,7 +136,7 @@ void FDynLightData::AddLightToList(int group, FDynamicLight * light, bool forceA spotDirZ = float(-Angle.Sin() * xzLen); } - float *data = &arrays[i][arrays[i].Reserve(16)]; + float *data = &dld.arrays[i][dld.arrays[i].Reserve(16)]; data[0] = float(pos.X); data[1] = float(pos.Z); data[2] = float(pos.Y); diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp new file mode 100644 index 00000000000..bfa0d8b1ce5 --- /dev/null +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -0,0 +1,412 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2004-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_scene.cpp +** manages the rendering of the player's view +** +*/ + +#include "gi.h" +#include "a_dynlight.h" +#include "m_png.h" +#include "doomstat.h" +#include "r_data/r_interpolate.h" +#include "r_utility.h" +#include "d_player.h" +#include "i_time.h" +#include "swrenderer/r_swscene.h" +#include "swrenderer/r_renderer.h" +#include "hw_dynlightdata.h" +#include "hw_clock.h" +#include "flatvertices.h" +#include "v_palette.h" +#include "d_main.h" +#include "g_cvars.h" +#include "v_draw.h" + +#include "hw_lightbuffer.h" +#include "hw_bonebuffer.h" +#include "hw_cvars.h" +#include "hwrenderer/data/hw_viewpointbuffer.h" +#include "hwrenderer/scene/hw_fakeflat.h" +#include "hwrenderer/scene/hw_clipper.h" +#include "hwrenderer/scene/hw_portal.h" +#include "hw_vrmodes.h" + +EXTERN_CVAR(Bool, cl_capfps) +extern bool NoInterpolateView; + +static SWSceneDrawer *swdrawer; + +void CleanSWDrawer() +{ + if (swdrawer) delete swdrawer; + swdrawer = nullptr; +} + +#include "g_levellocals.h" +#include "a_dynlight.h" + + +void CollectLights(FLevelLocals* Level) +{ + IShadowMap* sm = &screen->mShadowMap; + int lightindex = 0; + + // Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred. + for (auto light = Level->lights; light; light = light->next) + { + IShadowMap::LightsProcessed++; + if (light->shadowmapped && light->IsActive() && lightindex < 1024) + { + IShadowMap::LightsShadowmapped++; + + light->mShadowmapIndex = lightindex; + sm->SetLight(lightindex, (float)light->X(), (float)light->Y(), (float)light->Z(), light->GetRadius()); + lightindex++; + } + else + { + light->mShadowmapIndex = 1024; + } + + } + + for (; lightindex < 1024; lightindex++) + { + sm->SetLight(lightindex, 0, 0, 0, 0); + } +} + + +//----------------------------------------------------------------------------- +// +// Renders one viewpoint in a scene +// +//----------------------------------------------------------------------------- + +sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen) +{ + auto& RenderState = *screen->RenderState(); + + R_SetupFrame(mainvp, r_viewwindow, camera); + + if (mainview && toscreen && !(camera->Level->flags3 & LEVEL3_NOSHADOWMAP) && camera->Level->HasDynamicLights && gl_light_shadowmap && screen->allowSSBO() && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER)) + { + screen->SetAABBTree(camera->Level->aabbTree); + screen->mShadowMap.SetCollectLights([=] { + CollectLights(camera->Level); + }); + screen->UpdateShadowMap(); + } + else + { + // null all references to the level if we do not need a shadowmap. This will shortcut all internal calculations without further checks. + screen->SetAABBTree(nullptr); + screen->mShadowMap.SetCollectLights(nullptr); + } + + screen->SetLevelMesh(camera->Level->levelMesh); + + // Update the attenuation flag of all light defaults for each viewpoint. + // This function will only do something if the setting differs. + FLightDefaults::SetAttenuationForLevel(!!(camera->Level->flags3 & LEVEL3_ATTENUATE)); + + // Render (potentially) multiple views for stereo 3d + // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. + auto vrmode = VRMode::GetVRMode(mainview && toscreen); + const int eyeCount = vrmode->mEyeCount; + screen->FirstEye(); + for (int eye_ix = 0; eye_ix < eyeCount; ++eye_ix) + { + const auto& eye = vrmode->mEyes[eye_ix]; + screen->SetViewportRects(bounds); + + if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao + { + bool useSSAO = (gl_ssao != 0); + screen->SetSceneRenderTarget(useSSAO); + RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); + RenderState.EnableDrawBuffers(RenderState.GetPassDrawBufferCount(), true); + } + + auto di = HWDrawInfo::StartDrawInfo(mainvp.ViewLevel, nullptr, mainvp, nullptr); + auto& vp = di->Viewpoint; + + di->Set3DViewport(RenderState); + di->SetViewArea(); + auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr); + float flash = 1.f; + + // Only used by the GLES2 renderer + RenderState.SetSpecialColormap(cm, flash); + + di->Viewpoint.FieldOfView = DAngle::fromDeg(fov); // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint) + + // Stereo mode specific perspective projection + float inv_iso_dist = 1.0f; + bool iso_ortho = (camera->ViewPos != NULL) && (camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC); + if (iso_ortho && (camera->ViewPos->Offset.Length() > 0)) inv_iso_dist = 1.0/camera->ViewPos->Offset.Length(); + di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio * inv_iso_dist, iso_ortho); + + // Stereo mode specific viewpoint adjustment + vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees()); + di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); + + di->ProcessScene(toscreen); + + if (mainview) + { + PostProcess.Clock(); + if (toscreen) di->EndDrawScene(mainvp.sector, RenderState); // do not call this for camera textures. + + if (RenderState.GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers + { + RenderState.SetPassType(NORMAL_PASS); + RenderState.EnableDrawBuffers(1); + } + + screen->PostProcessScene(false, cm, flash, [&]() { di->DrawEndScene2D(mainvp.sector, RenderState); }); + PostProcess.Unclock(); + } + // Reset colormap so 2D drawing isn't affected + RenderState.SetSpecialColormap(CM_DEFAULT, 1); + + di->EndDrawInfo(); + if (eyeCount - eye_ix > 1) + screen->NextEye(eyeCount); + } + + return mainvp.sector; +} + +void DoWriteSavePic(FileWriter* file, ESSType ssformat, uint8_t* scr, int width, int height, sector_t* viewsector, bool upsidedown) +{ + PalEntry palette[256]; + PalEntry modulateColor; + auto blend = V_CalcBlend(viewsector, &modulateColor); + int pixelsize = 1; + // Apply the screen blend, because the renderer does not provide this. + if (ssformat == SS_RGB) + { + int numbytes = width * height * 3; + pixelsize = 3; + if (modulateColor != 0xffffffff) + { + float r = modulateColor.r / 255.f; + float g = modulateColor.g / 255.f; + float b = modulateColor.b / 255.f; + for (int i = 0; i < numbytes; i += 3) + { + scr[i] = uint8_t(scr[i] * r); + scr[i + 1] = uint8_t(scr[i + 1] * g); + scr[i + 2] = uint8_t(scr[i + 2] * b); + } + } + float iblendfac = 1.f - blend.W; + blend.X *= blend.W; + blend.Y *= blend.W; + blend.Z *= blend.W; + for (int i = 0; i < numbytes; i += 3) + { + scr[i] = uint8_t(scr[i] * iblendfac + blend.X); + scr[i + 1] = uint8_t(scr[i + 1] * iblendfac + blend.Y); + scr[i + 2] = uint8_t(scr[i + 2] * iblendfac + blend.Z); + } + } + else + { + // Apply the screen blend to the palette. The colormap related parts get skipped here because these are already part of the image. + DoBlending(GPalette.BaseColors, palette, 256, uint8_t(blend.X), uint8_t(blend.Y), uint8_t(blend.Z), uint8_t(blend.W * 255)); + } + + int pitch = width * pixelsize; + if (upsidedown) + { + scr += ((height - 1) * width * pixelsize); + pitch *= -1; + } + + M_CreatePNG(file, scr, ssformat == SS_PAL ? palette : nullptr, ssformat, width, height, pitch, vid_gamma); +} + +//=========================================================================== +// +// Render the view to a savegame picture +// +//=========================================================================== + +void WriteSavePic(player_t* player, FileWriter* file, int width, int height) +{ + if (!V_IsHardwareRenderer()) + { + SWRenderer->WriteSavePic(player, file, width, height); + } + else + { + IntRect bounds; + bounds.left = 0; + bounds.top = 0; + bounds.width = width; + bounds.height = height; + auto& RenderState = *screen->RenderState(); + + // we must be sure the GPU finished reading from the buffer before we fill it with new data. + screen->WaitForCommands(false); + + // Switch to render buffers dimensioned for the savepic + screen->SetSaveBuffers(true); + screen->ImageTransitionScene(true); + + hw_postprocess.SetTonemapMode(level.info ? level.info->tonemap : ETonemapMode::None); + hw_ClearFakeFlat(); + screen->mVertexData->Reset(); + RenderState.SetVertexBuffer(screen->mVertexData); + screen->mLights->Clear(); + screen->mBones->Clear(); + screen->mViewpoints->Clear(); + + // This shouldn't overwrite the global viewpoint even for a short time. + FRenderViewpoint savevp; + sector_t* viewsector = RenderViewpoint(savevp, players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees(), 1.6f, 1.6f, true, false); + RenderState.EnableStencil(false); + RenderState.SetNoSoftLightLevel(); + + TArray scr(width * height * 3, true); + screen->CopyScreenToBuffer(width, height, scr.Data()); + + DoWriteSavePic(file, SS_RGB, scr.Data(), width, height, viewsector, screen->FlipSavePic()); + + // Switch back the screen render buffers + screen->SetViewportRects(nullptr); + screen->SetSaveBuffers(false); + } +} + +//=========================================================================== +// +// Renders the main view +// +//=========================================================================== + +static void CheckTimer(FRenderState &state, uint64_t ShaderStartTime) +{ + // if firstFrame is not yet initialized, initialize it to current time + // if we're going to overflow a float (after ~4.6 hours, or 24 bits), re-init to regain precision + if ((state.firstFrame == 0) || (screen->FrameTime - state.firstFrame >= 1 << 24) || ShaderStartTime >= state.firstFrame) + state.firstFrame = screen->FrameTime - 1; +} + + +sector_t* RenderView(player_t* player) +{ + auto RenderState = screen->RenderState(); + RenderState->SetVertexBuffer(screen->mVertexData); + screen->mVertexData->Reset(); + hw_postprocess.SetTonemapMode(level.info ? level.info->tonemap : ETonemapMode::None); + + sector_t* retsec; + if (!V_IsHardwareRenderer()) + { + screen->SetActiveRenderTarget(); // only relevant for Vulkan + + if (!swdrawer) swdrawer = new SWSceneDrawer; + retsec = swdrawer->RenderView(player); + } + else + { + hw_ClearFakeFlat(); + + iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; + + checkBenchActive(); + + // reset statistics counters + ResetProfilingData(); + + // Get this before everything else + if (cl_capfps || r_NoInterpolate) r_viewpoint.TicFrac = 1.; + else r_viewpoint.TicFrac = I_GetTimeFrac(); + + screen->mLights->Clear(); + screen->mBones->Clear(); + screen->mViewpoints->Clear(); + + // NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below. + bool saved_niv = NoInterpolateView; + NoInterpolateView = false; + + // Shader start time does not need to be handled per level. Just use the one from the camera to render from. + if (player->camera) + CheckTimer(*RenderState, player->camera->Level->ShaderStartTime); + + // Draw all canvases that changed + for (FCanvas* canvas : AllCanvases) + { + if (canvas->Tex->CheckNeedsUpdate()) + { + screen->RenderTextureView(canvas->Tex, [=](IntRect& bounds) + { + screen->SetViewportRects(&bounds); + Draw2D(&canvas->Drawer, *screen->RenderState(), 0, 0, canvas->Tex->GetWidth(), canvas->Tex->GetHeight()); + canvas->Drawer.Clear(); + }); + canvas->Tex->SetUpdated(true); + } + } + + // prepare all camera textures that have been used in the last frame. + // This must be done for all levels, not just the primary one! + for (auto Level : AllLevels()) + { + Level->canvasTextureInfo.UpdateAll([&](AActor* camera, FCanvasTexture* camtex, double fov) + { + screen->RenderTextureView(camtex, [=](IntRect& bounds) + { + FRenderViewpoint texvp; + float ratio = camtex->aspectRatio / Level->info->pixelstretch; + RenderViewpoint(texvp, camera, &bounds, fov, ratio, ratio, false, false); + }); + }); + } + NoInterpolateView = saved_niv; + + // now render the main view + float fovratio; + float ratio = r_viewwindow.WidescreenRatio; + if (r_viewwindow.WidescreenRatio >= 1.3f) + { + fovratio = 1.333333f; + } + else + { + fovratio = ratio; + } + + screen->ImageTransitionScene(true); // Only relevant for Vulkan. + + retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees(), ratio, fovratio, true, true); + } + All.Unclock(); + return retsec; +} + diff --git a/src/rendering/hwrenderer/hw_models.cpp b/src/rendering/hwrenderer/hw_models.cpp new file mode 100644 index 00000000000..06ce5942e90 --- /dev/null +++ b/src/rendering/hwrenderer/hw_models.cpp @@ -0,0 +1,155 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2005-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_models.cpp +** +** hardware renderer model handling code +** +**/ + +#include "filesystem.h" +#include "g_game.h" +#include "doomstat.h" +#include "g_level.h" +#include "r_state.h" +#include "d_player.h" +#include "g_levellocals.h" +#include "i_time.h" +#include "cmdlib.h" +#include "hw_material.h" +#include "hwrenderer/data/buffers.h" +#include "flatvertices.h" +#include "hwrenderer/scene/hw_drawinfo.h" +#include "hw_renderstate.h" +#include "hwrenderer/scene/hw_portal.h" +#include "hw_bonebuffer.h" +#include "hw_models.h" + +CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE) + +VSMatrix FHWModelRenderer::GetViewToWorldMatrix() +{ + VSMatrix objectToWorldMatrix; + di->VPUniforms.mViewMatrix.inverseMatrix(objectToWorldMatrix); + return objectToWorldMatrix; +} + +void FHWModelRenderer::BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) +{ + state.SetDepthFunc(DF_LEqual); + state.EnableTexture(true); + // [BB] In case the model should be rendered translucent, do back face culling. + // This solves a few of the problems caused by the lack of depth sorting. + // [Nash] Don't do back face culling if explicitly specified in MODELDEF + // TO-DO: Implement proper depth sorting. + if ((smf_flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf_flags & MDL_DONTCULLBACKFACES))) + { + state.SetCulling((mirrored ^ portalState.isMirrored()) ? Cull_CCW : Cull_CW); + } + + state.mModelMatrix = objectToWorldMatrix; + state.EnableModelMatrix(true); +} + +void FHWModelRenderer::EndDrawModel(FRenderStyle style, int smf_flags) +{ + state.SetBoneIndexBase(-1); + state.EnableModelMatrix(false); + state.SetDepthFunc(DF_Less); + if ((smf_flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf_flags & MDL_DONTCULLBACKFACES))) + state.SetCulling(Cull_None); +} + +void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) +{ + state.SetDepthFunc(DF_LEqual); + state.SetDepthClamp(true); + + // [BB] In case the model should be rendered translucent, do back face culling. + // This solves a few of the problems caused by the lack of depth sorting. + // TO-DO: Implement proper depth sorting. + if (!(style == DefaultRenderStyle()) || (smf_flags & MDL_FORCECULLBACKFACES)) + { + state.SetCulling((mirrored ^ portalState.isMirrored()) ? Cull_CW : Cull_CCW); + } + + state.mModelMatrix = objectToWorldMatrix; + state.EnableModelMatrix(true); +} + +void FHWModelRenderer::EndDrawHUDModel(FRenderStyle style, int smf_flags) +{ + state.SetBoneIndexBase(-1); + state.EnableModelMatrix(false); + + state.SetDepthFunc(DF_Less); + if (!(style == DefaultRenderStyle()) || (smf_flags & MDL_FORCECULLBACKFACES)) + state.SetCulling(Cull_None); +} + +IModelVertexBuffer *FHWModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe) +{ + return new FModelVertexBuffer(needindex, singleframe); +} + +void FHWModelRenderer::SetInterpolation(double inter) +{ + state.SetInterpolationFactor((float)inter); +} + +void FHWModelRenderer::SetMaterial(FGameTexture *skin, bool clampNoFilter, FTranslationID translation) +{ + state.SetMaterial(skin, UF_Skin, 0, clampNoFilter ? CLAMP_NOFILTER : CLAMP_NONE, translation, -1); + state.SetLightIndex(modellightindex); +} + +void FHWModelRenderer::DrawArrays(int start, int count) +{ + state.Draw(DT_Triangles, start, count); +} + +void FHWModelRenderer::DrawElements(int numIndices, size_t offset) +{ + state.DrawIndexed(DT_Triangles, int(offset / sizeof(unsigned int)), numIndices); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +int FHWModelRenderer::SetupFrame(FModel *model, unsigned int frame1, unsigned int frame2, unsigned int size, const TArray& bones, int boneStartIndex) +{ + auto mdbuff = static_cast(model->GetVertexBuffer(GetType())); + screen->mBones->Map(); + boneIndexBase = boneStartIndex >= 0 ? boneStartIndex : screen->mBones->UploadBones(bones); + screen->mBones->Unmap(); + state.SetBoneIndexBase(boneIndexBase); + if (mdbuff) + { + state.SetVertexBuffer(mdbuff->vertexBuffer(), frame1, frame2); + if (mdbuff->indexBuffer()) state.SetIndexBuffer(mdbuff->indexBuffer()); + } + return boneIndexBase; +} + diff --git a/src/rendering/hwrenderer/hw_models.h b/src/rendering/hwrenderer/hw_models.h new file mode 100644 index 00000000000..c3e5125da68 --- /dev/null +++ b/src/rendering/hwrenderer/hw_models.h @@ -0,0 +1,62 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2005-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#pragma once + +#include "tarray.h" +#include "p_pspr.h" +#include "voxels.h" +#include "models.h" +#include "hwrenderer/data/buffers.h" +#include "hw_modelvertexbuffer.h" +#include "modelrenderer.h" + +class HWSprite; +struct HWDrawInfo; +class FRenderState; + + +class FHWModelRenderer : public FModelRenderer +{ + friend class FModelVertexBuffer; + int modellightindex = -1; + int boneIndexBase = -1; + HWDrawInfo *di; + FRenderState &state; +public: + FHWModelRenderer(HWDrawInfo *d, FRenderState &st, int mli) : modellightindex(mli), di(d), state(st) + {} + ModelRendererType GetType() const override { return GLModelRendererType; } + void BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) override; + void EndDrawModel(FRenderStyle style, int smf_flags) override; + IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override; + VSMatrix GetViewToWorldMatrix() override; + void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) override; + void EndDrawHUDModel(FRenderStyle style, int smf_flags) override; + void SetInterpolation(double interpolation) override; + void SetMaterial(FGameTexture *skin, bool clampNoFilter, FTranslationID translation) override; + void DrawArrays(int start, int count) override; + void DrawElements(int numIndices, size_t offset) override; + int SetupFrame(FModel *model, unsigned int frame1, unsigned int frame2, unsigned int size, const TArray& bones, int boneStartIndex) override; + +}; + diff --git a/src/rendering/hwrenderer/hw_precache.cpp b/src/rendering/hwrenderer/hw_precache.cpp new file mode 100644 index 00000000000..d6837252d6e --- /dev/null +++ b/src/rendering/hwrenderer/hw_precache.cpp @@ -0,0 +1,335 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2004-2016 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** Texture precaching +** +*/ + +#include "c_cvars.h" +#include "filesystem.h" +#include "r_data/r_translate.h" +#include "c_dispatch.h" +#include "r_state.h" +#include "actor.h" +#include "models.h" +#include "skyboxtexture.h" +#include "hw_material.h" +#include "image.h" +#include "v_video.h" +#include "v_font.h" +#include "texturemanager.h" +#include "modelrenderer.h" +#include "hw_models.h" +#include "d_main.h" + +EXTERN_CVAR(Bool, gl_precache) + +//========================================================================== +// +// DFrameBuffer :: PrecacheTexture +// +//========================================================================== + +static void PrecacheTexture(FGameTexture *tex, int cache) +{ + if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) + { + int scaleflags = 0; + if (shouldUpscale(tex, UF_Texture)) scaleflags |= CTF_Upscale; + + FMaterial * gltex = FMaterial::ValidateTexture(tex, scaleflags); + if (gltex) screen->PrecacheMaterial(gltex, 0); + } +} + +//=========================================================================== +// +// +// +//=========================================================================== +static void PrecacheList(FMaterial *gltex, SpriteHits& translations) +{ + SpriteHits::Iterator it(translations); + SpriteHits::Pair* pair; + while (it.NextPair(pair)) screen->PrecacheMaterial(gltex, pair->Key); +} + +//========================================================================== +// +// DFrameBuffer :: PrecacheSprite +// +//========================================================================== + +static void PrecacheSprite(FGameTexture *tex, SpriteHits &hits) +{ + int scaleflags = CTF_Expand; + if (shouldUpscale(tex, UF_Sprite)) scaleflags |= CTF_Upscale; + + FMaterial * gltex = FMaterial::ValidateTexture(tex, scaleflags); + if (gltex) PrecacheList(gltex, hits); +} + + +//========================================================================== +// +// DFrameBuffer :: Precache +// +//========================================================================== + +void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitlist) +{ + TMap allTextures; + TArray layers; + + // First collect the potential max. texture set + for (int i = 1; i < TexMan.NumTextures(); i++) + { + auto gametex = TexMan.GameByIndex(i); + if (gametex && gametex->isValid() && + gametex->GetTexture()->GetImage() && // only image textures are subject to precaching + gametex->GetUseType() != ETextureType::FontChar && // We do not want to delete font characters here as they are very likely to be needed constantly. + gametex->GetUseType() < ETextureType::Special) // Any texture marked as 'special' is also out. + { + gametex->GetLayers(layers); + for (auto layer : layers) + { + allTextures.Insert(layer, true); + layer->CleanPrecacheMarker(); + } + } + + // Mark the faces of a skybox as used. + // This isn't done by the main code so it needs to be done here. + // MBF sky transfers are being checked by the calling code to add HIT_Sky for them. + if (texhitlist[i] & (FTextureManager::HIT_Sky)) + { + auto tex = TexMan.GameByIndex(i); + auto sb = dynamic_cast(tex->GetTexture()); + if (sb) + { + for (int i = 0; i < 6; i++) + { + if (sb->faces[i]) + { + int index = sb->faces[i]->GetID().GetIndex(); + texhitlist[index] |= FTextureManager::HIT_Flat; + } + } + } + } + } + + SpriteHits *spritelist = new SpriteHits[sprites.Size()]; + SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()]; + TMap::Iterator it(actorhitlist); + TMap::Pair *pair; + uint8_t *modellist = new uint8_t[Models.Size()]; + memset(modellist, 0, Models.Size()); + memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures()); + + // Check all used actors. + // 1. mark all sprites associated with its states + // 2. mark all model data and skins associated with its states + while (it.NextPair(pair)) + { + PClassActor *cls = pair->Key; + auto remap = GPalette.TranslationToTable(GetDefaultByType(cls)->Translation.index()); + int gltrans = remap == nullptr ? 0 : remap->Index; + + for (unsigned i = 0; i < cls->GetStateCount(); i++) + { + auto &state = cls->GetStates()[i]; + spritelist[state.sprite].Insert(gltrans, true); + FSpriteModelFrame * smf = FindModelFrameRaw(cls, state.sprite, state.Frame, false); + if (smf != NULL) + { + for (int i = 0; i < smf->modelsAmount; i++) + { + if (smf->skinIDs[i].isValid()) + { + texhitlist[smf->skinIDs[i].GetIndex()] |= FTextureManager::HIT_Flat; + } + else if (smf->modelIDs[i] != -1) + { + Models[smf->modelIDs[i]]->AddSkins(texhitlist, (unsigned)(i * MD3_MAX_SURFACES) < smf->surfaceskinIDs.Size()? &smf->surfaceskinIDs[i * MD3_MAX_SURFACES] : nullptr); + } + if (smf->modelIDs[i] != -1) + { + modellist[smf->modelIDs[i]] = 1; + } + } + } + } + } + + // mark all sprite textures belonging to the marked sprites. + for (int i = (int)(sprites.Size() - 1); i >= 0; i--) + { + if (spritelist[i].CountUsed()) + { + int j, k; + for (j = 0; j < sprites[i].numframes; j++) + { + const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j]; + + for (k = 0; k < 16; k++) + { + FTextureID pic = frame->Texture[k]; + if (pic.isValid()) + { + spritehitlist[pic.GetIndex()] = &spritelist[i]; + } + } + } + } + } + + // delete everything unused before creating any new resources to avoid memory usage peaks. + + // delete unused models + for (unsigned i = 0; i < Models.Size(); i++) + { + if (!modellist[i]) Models[i]->DestroyVertexBuffer(); + } + + TMap usedTextures, usedSprites; + + screen->StartPrecaching(); + int cnt = TexMan.NumTextures(); + + // prepare the textures for precaching. First mark all used layer textures so that we know which ones should not be deleted. + for (int i = cnt - 1; i >= 0; i--) + { + auto tex = TexMan.GameByIndex(i); + if (tex != nullptr) + { + if (texhitlist[i] & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) + { + int scaleflags = 0; + if (shouldUpscale(tex, UF_Texture)) scaleflags |= CTF_Upscale; + + FMaterial* mat = FMaterial::ValidateTexture(tex, scaleflags, true); + if (mat != nullptr) + { + for (auto &layer : mat->GetLayerArray()) + { + if (layer.layerTexture) layer.layerTexture->MarkForPrecache(0, layer.scaleFlags); + } + } + } + if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) + { + int scaleflags = CTF_Expand; + if (shouldUpscale(tex, UF_Sprite)) scaleflags |= CTF_Upscale; + + FMaterial *mat = FMaterial::ValidateTexture(tex, true, true); + if (mat != nullptr) + { + SpriteHits::Iterator it(*spritehitlist[i]); + SpriteHits::Pair* pair; + while (it.NextPair(pair)) + { + for (auto& layer : mat->GetLayerArray()) + { + if (layer.layerTexture) layer.layerTexture->MarkForPrecache(pair->Key, layer.scaleFlags); + } + } + } + } + } + } + + // delete unused hardware textures (i.e. those which didn't get referenced by any material in the cache list.) + decltype(allTextures)::Iterator ita(allTextures); + decltype(allTextures)::Pair* paira; + while (ita.NextPair(paira)) + { + paira->Key->CleanUnused(); + } + + if (gl_precache) + { + cycle_t precache; + precache.Reset(); + precache.Clock(); + + FImageSource::BeginPrecaching(); + + // cache all used images + for (int i = cnt - 1; i >= 0; i--) + { + auto gtex = TexMan.GameByIndex(i); + auto tex = gtex->GetTexture(); + if (tex != nullptr && tex->GetImage() != nullptr) + { + if (texhitlist[i] & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) + { + int flags = shouldUpscale(gtex, UF_Texture); + if (tex->GetImage() && tex->GetHardwareTexture(0, flags) == nullptr) + { + FImageSource::RegisterForPrecache(tex->GetImage(), V_IsTrueColor()); + } + } + + // Only register untranslated sprite images. Translated ones are very unlikely to require data that can be reused so they can just be created on demand. + if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CheckKey(0)) + { + FImageSource::RegisterForPrecache(tex->GetImage(), V_IsTrueColor()); + } + } + } + + // cache all used textures + for (int i = cnt - 1; i >= 0; i--) + { + auto gtex = TexMan.GameByIndex(i); + if (gtex != nullptr) + { + PrecacheTexture(gtex, texhitlist[i]); + if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) + { + PrecacheSprite(gtex, *spritehitlist[i]); + } + } + } + + + FImageSource::EndPrecaching(); + + // cache all used models + FModelRenderer* renderer = new FHWModelRenderer(nullptr, *screen->RenderState(), -1); + for (unsigned i = 0; i < Models.Size(); i++) + { + if (modellist[i]) + Models[i]->BuildVertexBuffer(renderer); + } + delete renderer; + + precache.Unclock(); + DPrintf(DMSG_NOTIFY, "Textures precached in %.3f ms\n", precache.TimeMS()); + } + + delete[] spritehitlist; + delete[] spritelist; + delete[] modellist; +} + diff --git a/src/rendering/hwrenderer/hw_vertexbuilder.cpp b/src/rendering/hwrenderer/hw_vertexbuilder.cpp new file mode 100644 index 00000000000..718528afe1f --- /dev/null +++ b/src/rendering/hwrenderer/hw_vertexbuilder.cpp @@ -0,0 +1,497 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2015-2018 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + + + +#include "g_levellocals.h" +#include "hw_vertexbuilder.h" +#include "flatvertices.h" +#include "earcut.hpp" +#include "v_video.h" + +//============================================================================= +// +// Creates vertex meshes for sector planes +// +//============================================================================= + +//============================================================================= +// +// +// +//============================================================================= + +static void CreateVerticesForSubsector(subsector_t *sub, VertexContainer &gen, int qualifier) +{ + if (sub->numlines < 3) return; + + uint32_t startindex = gen.indices.Size(); + + if ((sub->flags & SSECF_HOLE) && sub->numlines > 3) + { + // Hole filling "subsectors" are not necessarily convex so they require real triangulation. + // These things are extremely rare so performance is secondary here. + + using Point = std::pair; + std::vector> polygon; + std::vector *curPoly; + + polygon.resize(1); + curPoly = &polygon.back(); + curPoly->resize(sub->numlines); + + for (unsigned i = 0; i < sub->numlines; i++) + { + (*curPoly)[i] = { sub->firstline[i].v1->fX(), sub->firstline[i].v1->fY() }; + } + auto indices = mapbox::earcut(polygon); + for (auto vti : indices) + { + gen.AddIndexForVertex(sub->firstline[vti].v1, qualifier); + } + } + else + { + int firstndx = gen.AddVertex(sub->firstline[0].v1, qualifier); + int secondndx = gen.AddVertex(sub->firstline[1].v1, qualifier); + for (unsigned int k = 2; k < sub->numlines; k++) + { + gen.AddIndex(firstndx); + gen.AddIndex(secondndx); + auto ndx = gen.AddVertex(sub->firstline[k].v1, qualifier); + gen.AddIndex(ndx); + secondndx = ndx; + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + +static void TriangulateSection(FSection §, VertexContainer &gen, int qualifier) +{ + if (sect.segments.Size() < 3) return; + + // todo +} + +//============================================================================= +// +// +// +//============================================================================= + + +static void CreateVerticesForSection(FSection §ion, VertexContainer &gen, bool useSubsectors) +{ + section.vertexindex = gen.indices.Size(); + + if (useSubsectors) + { + for (auto sub : section.subsectors) + { + CreateVerticesForSubsector(sub, gen, -1); + } + } + else + { + TriangulateSection(section, gen, -1); + } + section.vertexcount = gen.indices.Size() - section.vertexindex; +} + +//========================================================================== +// +// Creates the vertices for one plane in one subsector +// +//========================================================================== + +static void CreateVerticesForSector(sector_t *sec, VertexContainer &gen) +{ + auto sections = sec->Level->sections.SectionsForSector(sec); + for (auto §ion :sections) + { + CreateVerticesForSection( section, gen, true); + } +} + + +TArray BuildVertices(TArray §ors) +{ + TArray verticesPerSector(sectors.Size(), true); + for (unsigned i=0; i< sectors.Size(); i++) + { + CreateVerticesForSector(§ors[i], verticesPerSector[i]); + } + return verticesPerSector; +} + +//========================================================================== +// +// Creates the vertices for one plane in one subsector +// +//========================================================================== + +//========================================================================== +// +// Find a 3D floor +// +//========================================================================== + +static F3DFloor *Find3DFloor(sector_t* target, sector_t* model, int &ffloorIndex) +{ + for (unsigned i = 0; i < target->e->XFloor.ffloors.Size(); i++) + { + F3DFloor* ffloor = target->e->XFloor.ffloors[i]; + if (ffloor->model == model && !(ffloor->flags & FF_THISINSIDE)) + { + ffloorIndex = i; + return ffloor; + } + } + ffloorIndex = -1; + return NULL; +} + +//========================================================================== +// +// Initialize a single vertex +// +//========================================================================== + +static void SetFlatVertex(FFlatVertex& ffv, vertex_t* vt, const secplane_t& plane) +{ + ffv.x = (float)vt->fX(); + ffv.y = (float)vt->fY(); + ffv.z = (float)plane.ZatPoint(vt); + ffv.u = (float)vt->fX() / 64.f; + ffv.v = -(float)vt->fY() / 64.f; + ffv.lindex = -1.0f; +} + +static void SetFlatVertex(FFlatVertex& ffv, vertex_t* vt, const secplane_t& plane, float llu, float llv, int llindex) +{ + ffv.x = (float)vt->fX(); + ffv.y = (float)vt->fY(); + ffv.z = (float)plane.ZatPoint(vt); + ffv.u = (float)vt->fX() / 64.f; + ffv.v = -(float)vt->fY() / 64.f; + ffv.lu = llu; + ffv.lv = llv; + ffv.lindex = (float)llindex; +} + +//========================================================================== +// +// Creates the vertices for one plane in one subsector w/lightmap support. +// Sectors with lightmaps cannot share subsector vertices. +// +//========================================================================== + +static int CreateIndexedSectorVerticesLM(FFlatVertexBuffer* fvb, sector_t* sec, const secplane_t& plane, int floor, int h, int lightmapIndex) +{ + int i, pos; + float diff; + + auto& ibo_data = fvb->ibo_data; + + int rt = ibo_data.Size(); + if (sec->transdoor && floor) diff = -1.f; + else diff = 0.f; + + // Allocate space + for (i = 0, pos = 0; i < sec->subsectorcount; i++) + { + pos += sec->subsectors[i]->numlines; + } + + auto& vbo_shadowdata = fvb->vbo_shadowdata; + int vi = vbo_shadowdata.Reserve(pos); + int idx = ibo_data.Reserve((pos - 2 * sec->subsectorcount) * 3); + + // Create the actual vertices. + for (i = 0, pos = 0; i < sec->subsectorcount; i++) + { + subsector_t* sub = sec->subsectors[i]; + LightmapSurface* lightmap = &sub->lightmap[h][lightmapIndex]; + if (lightmap->Type != ST_NULL) + { + float* luvs = lightmap->TexCoords; + int lindex = lightmap->LightmapNum; + for (unsigned int j = 0; j < sub->numlines; j++) + { + SetFlatVertex(vbo_shadowdata[vi + pos], sub->firstline[j].v1, plane, luvs[j * 2], luvs[j * 2 + 1], lindex); + vbo_shadowdata[vi + pos].z += diff; + pos++; + } + } + else + { + for (unsigned int j = 0; j < sub->numlines; j++) + { + SetFlatVertex(vbo_shadowdata[vi + pos], sub->firstline[j].v1, plane); + vbo_shadowdata[vi + pos].z += diff; + pos++; + } + } + } + + // Create the indices for the subsectors + for (i = 0, pos = 0; i < sec->subsectorcount; i++) + { + subsector_t* sub = sec->subsectors[i]; + int firstndx = vi + pos; + for (unsigned int k = 2; k < sub->numlines; k++) + { + ibo_data[idx++] = firstndx; + ibo_data[idx++] = firstndx + k - 1; + ibo_data[idx++] = firstndx + k; + } + pos += sec->subsectors[i]->numlines; + } + + sec->ibocount = ibo_data.Size() - rt; + return rt; +} + +static int CreateIndexedSectorVertices(FFlatVertexBuffer* fvb, sector_t* sec, const secplane_t& plane, int floor, VertexContainer& verts, int h, int lightmapIndex) +{ + if (sec->HasLightmaps && lightmapIndex != -1) + return CreateIndexedSectorVerticesLM(fvb, sec, plane, floor, h, lightmapIndex); + + auto& vbo_shadowdata = fvb->vbo_shadowdata; + unsigned vi = vbo_shadowdata.Reserve(verts.vertices.Size()); + float diff; + + // Create the actual vertices. + if (sec->transdoor && floor) diff = -1.f; + else diff = 0.f; + for (unsigned i = 0; i < verts.vertices.Size(); i++) + { + SetFlatVertex(vbo_shadowdata[vi + i], verts.vertices[i].vertex, plane); + vbo_shadowdata[vi + i].z += diff; + } + + auto& ibo_data = fvb->ibo_data; + unsigned rt = ibo_data.Reserve(verts.indices.Size()); + for (unsigned i = 0; i < verts.indices.Size(); i++) + { + ibo_data[rt + i] = vi + verts.indices[i]; + } + return (int)rt; +} + +//========================================================================== +// +// +// +//========================================================================== + +static int CreateIndexedVertices(FFlatVertexBuffer* fvb, int h, sector_t* sec, const secplane_t& plane, int floor, VertexContainers& verts) +{ + auto& vbo_shadowdata = fvb->vbo_shadowdata; + sec->vboindex[h] = vbo_shadowdata.Size(); + // First calculate the vertices for the sector itself + for (int n = 0; n < screen->mPipelineNbr; n++) + sec->vboheight[n][h] = sec->GetPlaneTexZ(h); + sec->ibocount = verts[sec->Index()].indices.Size(); + sec->iboindex[h] = CreateIndexedSectorVertices(fvb, sec, plane, floor, verts[sec->Index()], h, 0); + + // Next are all sectors using this one as heightsec + TArray& fakes = sec->e->FakeFloor.Sectors; + for (unsigned g = 0; g < fakes.Size(); g++) + { + sector_t* fsec = fakes[g]; + fsec->iboindex[2 + h] = CreateIndexedSectorVertices(fvb, fsec, plane, false, verts[fsec->Index()], h, -1); + } + + // and finally all attached 3D floors + TArray& xf = sec->e->XFloor.attached; + for (unsigned g = 0; g < xf.Size(); g++) + { + sector_t* fsec = xf[g]; + int ffloorIndex; + F3DFloor* ffloor = Find3DFloor(fsec, sec, ffloorIndex); + + if (ffloor != NULL && ffloor->flags & FF_RENDERPLANES) + { + bool dotop = (ffloor->top.model == sec) && (ffloor->top.isceiling == h); + bool dobottom = (ffloor->bottom.model == sec) && (ffloor->bottom.isceiling == h); + + if (dotop || dobottom) + { + auto ndx = CreateIndexedSectorVertices(fvb, fsec, plane, false, verts[fsec->Index()], h, ffloorIndex + 1); + if (dotop) ffloor->top.vindex = ndx; + if (dobottom) ffloor->bottom.vindex = ndx; + } + } + } + sec->vbocount[h] = vbo_shadowdata.Size() - sec->vboindex[h]; + return sec->iboindex[h]; +} + + +//========================================================================== +// +// +// +//========================================================================== + +static void CreateIndexedFlatVertices(FFlatVertexBuffer* fvb, TArray& sectors) +{ + auto verts = BuildVertices(sectors); + + int i = 0; + /* + for (auto &vert : verts) + { + Printf(PRINT_LOG, "Sector %d\n", i); + Printf(PRINT_LOG, "%d vertices, %d indices\n", vert.vertices.Size(), vert.indices.Size()); + int j = 0; + for (auto &v : vert.vertices) + { + Printf(PRINT_LOG, " %d: (%2.3f, %2.3f)\n", j++, v.vertex->fX(), v.vertex->fY()); + } + for (unsigned i=0;iXFloor.ffloors) + { + if (ff->top.model == &sec) + { + ff->top.vindex = sec.iboindex[ff->top.isceiling]; + } + if (ff->bottom.model == &sec) + { + ff->bottom.vindex = sec.iboindex[ff->top.isceiling]; + } + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +static void UpdatePlaneVertices(FFlatVertexBuffer *fvb, sector_t* sec, int plane) +{ + int startvt = sec->vboindex[plane]; + int countvt = sec->vbocount[plane]; + secplane_t& splane = sec->GetSecPlane(plane); + FFlatVertex* vt = &fvb->vbo_shadowdata[startvt]; + FFlatVertex* mapvt = fvb->GetBuffer(startvt); + for (int i = 0; i < countvt; i++, vt++, mapvt++) + { + vt->z = (float)splane.ZatPoint(vt->x, vt->y); + if (plane == sector_t::floor && sec->transdoor) vt->z -= 1; + mapvt->z = vt->z; + } + + fvb->mVertexBuffer->Upload(startvt * sizeof(FFlatVertex), countvt * sizeof(FFlatVertex)); +} + +//========================================================================== +// +// +// +//========================================================================== + +static void CreateVertices(FFlatVertexBuffer* fvb, TArray& sectors) +{ + fvb->vbo_shadowdata.Resize(FFlatVertexBuffer::NUM_RESERVED); + CreateIndexedFlatVertices(fvb, sectors); +} + +//========================================================================== +// +// +// +//========================================================================== + +static void CheckPlanes(FFlatVertexBuffer* fvb, sector_t* sector) +{ + if (sector->GetPlaneTexZ(sector_t::ceiling) != sector->vboheight[screen->mVertexData->GetPipelinePos()][sector_t::ceiling]) + { + UpdatePlaneVertices(fvb, sector, sector_t::ceiling); + sector->vboheight[screen->mVertexData->GetPipelinePos()][sector_t::ceiling] = sector->GetPlaneTexZ(sector_t::ceiling); + } + if (sector->GetPlaneTexZ(sector_t::floor) != sector->vboheight[screen->mVertexData->GetPipelinePos()][sector_t::floor]) + { + UpdatePlaneVertices(fvb, sector, sector_t::floor); + sector->vboheight[screen->mVertexData->GetPipelinePos()][sector_t::floor] = sector->GetPlaneTexZ(sector_t::floor); + } +} + +//========================================================================== +// +// checks the validity of all planes attached to this sector +// and updates them if possible. +// +//========================================================================== + +void CheckUpdate(FFlatVertexBuffer* fvb, sector_t* sector) +{ + CheckPlanes(fvb, sector); + sector_t* hs = sector->GetHeightSec(); + if (hs != NULL) CheckPlanes(fvb, hs); + for (unsigned i = 0; i < sector->e->XFloor.ffloors.Size(); i++) + CheckPlanes(fvb, sector->e->XFloor.ffloors[i]->model); +} + +//========================================================================== +// +// +// +//========================================================================== + +void CreateVBO(FFlatVertexBuffer* fvb, TArray& sectors) +{ + fvb->vbo_shadowdata.Resize(fvb->mNumReserved); + CreateVertices(fvb, sectors); + fvb->mCurIndex = fvb->mIndex = fvb->vbo_shadowdata.Size(); + fvb->Copy(0, fvb->mIndex); + fvb->mIndexBuffer->SetData(fvb->ibo_data.Size() * sizeof(uint32_t), &fvb->ibo_data[0], BufferUsageType::Static); +} diff --git a/src/rendering/hwrenderer/data/hw_vertexbuilder.h b/src/rendering/hwrenderer/hw_vertexbuilder.h similarity index 89% rename from src/rendering/hwrenderer/data/hw_vertexbuilder.h rename to src/rendering/hwrenderer/hw_vertexbuilder.h index 8ab7d21d861..0444613be69 100644 --- a/src/rendering/hwrenderer/data/hw_vertexbuilder.h +++ b/src/rendering/hwrenderer/hw_vertexbuilder.h @@ -1,5 +1,6 @@ - +#pragma once #include "tarray.h" +#include "r_defs.h" struct vertex_t; struct FQualifiedVertex @@ -66,4 +67,7 @@ using VertexContainers = TArray; VertexContainers BuildVertices(TArray §ors); +class FFlatVertexBuffer; +void CheckUpdate(FFlatVertexBuffer* fvb, sector_t* sector); +void CreateVBO(FFlatVertexBuffer* fvb, TArray& sectors); diff --git a/src/rendering/hwrenderer/models/hw_models.cpp b/src/rendering/hwrenderer/models/hw_models.cpp deleted file mode 100644 index e3353d01a4e..00000000000 --- a/src/rendering/hwrenderer/models/hw_models.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_models.cpp -** -** hardware renderer model handling code -** -**/ - -#include "w_wad.h" -#include "g_game.h" -#include "doomstat.h" -#include "g_level.h" -#include "r_state.h" -#include "d_player.h" -#include "g_levellocals.h" -#include "i_time.h" -#include "cmdlib.h" -#include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/data/buffers.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/scene/hw_drawinfo.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include "hwrenderer/scene/hw_portal.h" -#include "hw_models.h" - -CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE) - -VSMatrix FHWModelRenderer::GetViewToWorldMatrix() -{ - VSMatrix objectToWorldMatrix; - di->VPUniforms.mViewMatrix.inverseMatrix(objectToWorldMatrix); - return objectToWorldMatrix; -} - -void FHWModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) -{ - state.SetDepthFunc(DF_LEqual); - state.EnableTexture(true); - // [BB] In case the model should be rendered translucent, do back face culling. - // This solves a few of the problems caused by the lack of depth sorting. - // [Nash] Don't do back face culling if explicitly specified in MODELDEF - // TO-DO: Implement proper depth sorting. - if (!(actor->RenderStyle == DefaultRenderStyle()) && !(smf->flags & MDL_DONTCULLBACKFACES)) - { - state.SetCulling((mirrored ^ screen->mPortalState->isMirrored()) ? Cull_CCW : Cull_CW); - } - - state.mModelMatrix = objectToWorldMatrix; - state.EnableModelMatrix(true); -} - -void FHWModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf) -{ - state.EnableModelMatrix(false); - state.SetDepthFunc(DF_Less); - if (!(actor->RenderStyle == DefaultRenderStyle()) && !(smf->flags & MDL_DONTCULLBACKFACES)) - state.SetCulling(Cull_None); -} - -void FHWModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) -{ - state.SetDepthFunc(DF_LEqual); - - // [BB] In case the model should be rendered translucent, do back face culling. - // This solves a few of the problems caused by the lack of depth sorting. - // TO-DO: Implement proper depth sorting. - if (!(actor->RenderStyle == DefaultRenderStyle())) - { - state.SetCulling((mirrored ^ screen->mPortalState->isMirrored()) ? Cull_CW : Cull_CCW); - } - - state.mModelMatrix = objectToWorldMatrix; - state.EnableModelMatrix(true); -} - -void FHWModelRenderer::EndDrawHUDModel(AActor *actor) -{ - state.EnableModelMatrix(false); - - state.SetDepthFunc(DF_Less); - if (!(actor->RenderStyle == DefaultRenderStyle())) - state.SetCulling(Cull_None); -} - -IModelVertexBuffer *FHWModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe) -{ - return new FModelVertexBuffer(needindex, singleframe); -} - -void FHWModelRenderer::SetInterpolation(double inter) -{ - state.SetInterpolationFactor((float)inter); -} - -void FHWModelRenderer::SetMaterial(FTexture *skin, bool clampNoFilter, int translation) -{ - FMaterial * tex = FMaterial::ValidateTexture(skin, false); - state.SetMaterial(tex, clampNoFilter ? CLAMP_NOFILTER : CLAMP_NONE, translation, -1); - state.SetLightIndex(modellightindex); -} - -void FHWModelRenderer::DrawArrays(int start, int count) -{ - state.Draw(DT_Triangles, start, count); -} - -void FHWModelRenderer::DrawElements(int numIndices, size_t offset) -{ - state.DrawIndexed(DT_Triangles, int(offset / sizeof(unsigned int)), numIndices); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -FModelVertexBuffer::FModelVertexBuffer(bool needindex, bool singleframe) -{ - mVertexBuffer = screen->CreateVertexBuffer(); - mIndexBuffer = needindex ? screen->CreateIndexBuffer() : nullptr; - - static const FVertexBufferAttribute format[] = { - { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FModelVertex, x) }, - { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FModelVertex, u) }, - { 0, VATTR_NORMAL, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) }, - { 1, VATTR_VERTEX2, VFmt_Float3, (int)myoffsetof(FModelVertex, x) }, - { 1, VATTR_NORMAL2, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) } - }; - mVertexBuffer->SetFormat(2, 5, sizeof(FModelVertex), format); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -FModelVertexBuffer::~FModelVertexBuffer() -{ - if (mIndexBuffer) delete mIndexBuffer; - delete mVertexBuffer; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -FModelVertex *FModelVertexBuffer::LockVertexBuffer(unsigned int size) -{ - return static_cast(mVertexBuffer->Lock(size * sizeof(FModelVertex))); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FModelVertexBuffer::UnlockVertexBuffer() -{ - mVertexBuffer->Unlock(); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -unsigned int *FModelVertexBuffer::LockIndexBuffer(unsigned int size) -{ - if (mIndexBuffer) return static_cast(mIndexBuffer->Lock(size * sizeof(unsigned int))); - else return nullptr; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FModelVertexBuffer::UnlockIndexBuffer() -{ - if (mIndexBuffer) mIndexBuffer->Unlock(); -} - - -//=========================================================================== -// -// -// -//=========================================================================== - -void FModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) -{ - auto &state = static_cast(renderer)->state; - state.SetVertexBuffer(mVertexBuffer, frame1, frame2); - if (mIndexBuffer) state.SetIndexBuffer(mIndexBuffer); -} diff --git a/src/rendering/hwrenderer/models/hw_models.h b/src/rendering/hwrenderer/models/hw_models.h deleted file mode 100644 index a3de32e6009..00000000000 --- a/src/rendering/hwrenderer/models/hw_models.h +++ /dev/null @@ -1,75 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#pragma once - -#include "tarray.h" -#include "p_pspr.h" -#include "r_data/voxels.h" -#include "r_data/models/models.h" -#include "hwrenderer/data/buffers.h" - -class HWSprite; -struct HWDrawInfo; -class FRenderState; - -class FModelVertexBuffer : public IModelVertexBuffer -{ - IVertexBuffer *mVertexBuffer; - IIndexBuffer *mIndexBuffer; - -public: - - FModelVertexBuffer(bool needindex, bool singleframe); - ~FModelVertexBuffer(); - - FModelVertex *LockVertexBuffer(unsigned int size) override; - void UnlockVertexBuffer() override; - - unsigned int *LockIndexBuffer(unsigned int size) override; - void UnlockIndexBuffer() override; - - void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override; -}; - -class FHWModelRenderer : public FModelRenderer -{ - friend class FModelVertexBuffer; - int modellightindex = -1; - HWDrawInfo *di; - FRenderState &state; -public: - FHWModelRenderer(HWDrawInfo *d, FRenderState &st, int mli) : modellightindex(mli), di(d), state(st) - {} - ModelRendererType GetType() const override { return GLModelRendererType; } - void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override; - void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override; - IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override; - VSMatrix GetViewToWorldMatrix() override; - void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) override; - void EndDrawHUDModel(AActor *actor) override; - void SetInterpolation(double interpolation) override; - void SetMaterial(FTexture *skin, bool clampNoFilter, int translation) override; - void DrawArrays(int start, int count) override; - void DrawElements(int numIndices, size_t offset) override; -}; - diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp b/src/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp deleted file mode 100644 index 16eea4c133c..00000000000 --- a/src/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* -** Postprocessing framework -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "vm.h" -#include "d_player.h" -#include "hw_postprocessshader.h" -#include "g_levellocals.h" - -TArray PostProcessShaders; - - -static bool IsConsolePlayer(player_t *player) -{ - AActor *activator = player ? player->mo : nullptr; - if (activator == nullptr || activator->player == nullptr) - return false; - return activator->player == activator->Level->GetConsolePlayer(); -} - -static void ShaderSetEnabled(player_t *player, const FString &shaderName, bool value) -{ - if (IsConsolePlayer(player)) - { - for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) - { - PostProcessShader &shader = PostProcessShaders[i]; - if (shader.Name == shaderName) - shader.Enabled = value; - } - } -} - -DEFINE_ACTION_FUNCTION_NATIVE(_Shader, SetEnabled, ShaderSetEnabled) -{ - PARAM_PROLOGUE; - PARAM_POINTER(player, player_t); - PARAM_STRING(shaderName); - PARAM_BOOL(value); - ShaderSetEnabled(player, shaderName, value); - - return 0; -} - -static void ShaderSetUniform1f(player_t *player, const FString &shaderName, const FString &uniformName, double value) -{ - if (IsConsolePlayer(player)) - { - for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) - { - PostProcessShader &shader = PostProcessShaders[i]; - if (shader.Name == shaderName) - { - double *vec4 = shader.Uniforms[uniformName].Values; - vec4[0] = value; - vec4[1] = 0.0; - vec4[2] = 0.0; - vec4[3] = 1.0; - } - } - } -} - -DEFINE_ACTION_FUNCTION_NATIVE(_Shader, SetUniform1f, ShaderSetUniform1f) -{ - PARAM_PROLOGUE; - PARAM_POINTER(player, player_t); - PARAM_STRING(shaderName); - PARAM_STRING(uniformName); - PARAM_FLOAT(value); - ShaderSetUniform1f(player, shaderName, uniformName, value); - return 0; -} - -DEFINE_ACTION_FUNCTION(_Shader, SetUniform2f) -{ - PARAM_PROLOGUE; - PARAM_POINTER(player, player_t); - PARAM_STRING(shaderName); - PARAM_STRING(uniformName); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - - if (IsConsolePlayer(player)) - { - for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) - { - PostProcessShader &shader = PostProcessShaders[i]; - if (shader.Name == shaderName) - { - double *vec4 = shader.Uniforms[uniformName].Values; - vec4[0] = x; - vec4[1] = y; - vec4[2] = 0.0; - vec4[3] = 1.0; - } - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(_Shader, SetUniform3f) -{ - PARAM_PROLOGUE; - PARAM_POINTER(player, player_t); - PARAM_STRING(shaderName); - PARAM_STRING(uniformName); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_FLOAT(z); - - if (IsConsolePlayer(player)) - { - for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) - { - PostProcessShader &shader = PostProcessShaders[i]; - if (shader.Name == shaderName) - { - double *vec4 = shader.Uniforms[uniformName].Values; - vec4[0] = x; - vec4[1] = y; - vec4[2] = z; - vec4[3] = 1.0; - } - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(_Shader, SetUniform1i) -{ - PARAM_PROLOGUE; - PARAM_POINTER(player, player_t); - PARAM_STRING(shaderName); - PARAM_STRING(uniformName); - PARAM_INT(value); - - if (IsConsolePlayer(player)) - { - for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) - { - PostProcessShader &shader = PostProcessShaders[i]; - if (shader.Name == shaderName) - { - double *vec4 = shader.Uniforms[uniformName].Values; - vec4[0] = (double)value; - vec4[1] = 0.0; - vec4[2] = 0.0; - vec4[3] = 1.0; - } - } - } - return 0; -} diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index 54ea30c0af5..fafa680d47f 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -33,13 +33,16 @@ #include "po_man.h" #include "m_fixed.h" #include "ctpl.h" +#include "texturemanager.h" #include "hwrenderer/scene/hw_fakeflat.h" #include "hwrenderer/scene/hw_clipper.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/data/flatvertices.h" +#include "hw_clock.h" +#include "flatvertices.h" +#include "hw_vertexbuilder.h" +#include "hw_walldispatcher.h" #ifdef ARCH_IA32 #include @@ -47,10 +50,25 @@ CVAR(Bool, gl_multithread, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +EXTERN_CVAR(Float, r_actorspriteshadowdist) +EXTERN_CVAR(Bool, r_radarclipper) +EXTERN_CVAR(Bool, r_dithertransparency) + thread_local bool isWorkerThread; ctpl::thread_pool renderPool(1); bool inited = false; +const int MAXDITHERACTORS = 20; // Maximum number of enemies that can set dither-transparency flags +AActor* RenderedTargets[MAXDITHERACTORS]; +int RTnum; + +void ClearDitherTargets() +{ + RTnum = 0; // Number of rendered enemies/targets + for (int ii = 0; ii < MAXDITHERACTORS; ii++) + RenderedTargets[ii] = nullptr; +} + struct RenderJob { enum @@ -101,6 +119,7 @@ static RenderJobQueue jobQueue; // One static queue is sufficient here. This cod void HWDrawInfo::WorkerThread() { sector_t *front, *back; + HWWallDispatcher disp(this); WTTotal.Clock(); isWorkerThread = true; // for adding asserts in GL API code. The worker thread may never call any GL API. @@ -140,20 +159,32 @@ void HWDrawInfo::WorkerThread() front = hw_FakeFlat(job->sub->sector, in_area, false); auto seg = job->seg; - if (seg->backsector) + auto backsector = seg->backsector; + if (!backsector && seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0]) // For one-sided portals use the portal's destination sector as backsector. + { + auto portal = seg->linedef->getPortal(); + backsector = portal->mDestination->frontsector; + back = hw_FakeFlat(backsector, in_area, true); + if (front->floorplane.isSlope() || front->ceilingplane.isSlope() || back->floorplane.isSlope() || back->ceilingplane.isSlope()) + { + // Having a one-sided portal like this with slopes is too messy so let's ignore that case. + back = nullptr; + } + } + else if (backsector) { - if (front->sectornum == seg->backsector->sectornum || (seg->sidedef->Flags & WALLF_POLYOBJ)) + if (front->sectornum == backsector->sectornum || (seg->sidedef->Flags & WALLF_POLYOBJ)) { back = front; } else { - back = hw_FakeFlat(seg->backsector, in_area, true); + back = hw_FakeFlat(backsector, in_area, true); } } else back = nullptr; - wall.Process(this, job->seg, front, back); + wall.Process(&disp, job->seg, front, back); rendered_lines++; SetupWall.Unclock(); break; @@ -251,6 +282,20 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) auto &clipper = *mClipper; angle_t startAngle = clipper.GetClipAngle(seg->v2); angle_t endAngle = clipper.GetClipAngle(seg->v1); + auto &clipperr = *rClipper; + angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY()); + angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY()); + + if(r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && (startAngleR - endAngleR >= ANGLE_180)) + { + if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR, endAngleR); + else if((seg->sidedef != nullptr) && !uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ) && (currentsector->sectornum != seg->backsector->sectornum)) + { + if (in_area == area_default) in_area = hw_CheckViewArea(seg->v2, seg->v1, seg->frontsector, seg->backsector); + backsector = hw_FakeFlat(seg->backsector, in_area, true); + if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR, endAngleR); + } + } // Back side, i.e. backface culling - read: endAngle >= startAngle! if (startAngle-endAngleflags & SSECMF_DRAWN)) { - if (clipper.SafeCheckRange(startAngle, endAngle)) + if (clipper.SafeCheckRange(startAngle, endAngle) && (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR))) { - currentsubsector->flags |= SSECMF_DRAWN; + currentsubsector->flags |= SSECMF_DRAWN; + } + if ((r_radarclipper || !(Level->flags3 & LEVEL3_NOFOGOFWAR)) && clipperr.SafeCheckRange(startAngleR, endAngleR)) + { + currentsubsector->flags |= SSECMF_DRAWN; } } return; } - if (!clipper.SafeCheckRange(startAngle, endAngle)) + if (!clipper.SafeCheckRange(startAngle, endAngle)) + { + return; + } + + auto &clipperv = *vClipper; + angle_t startPitch = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), currentsector->floorplane.ZatPoint(seg->v1)); + angle_t endPitch = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), currentsector->ceilingplane.ZatPoint(seg->v1)); + angle_t startPitch2 = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), currentsector->floorplane.ZatPoint(seg->v2)); + angle_t endPitch2 = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), currentsector->ceilingplane.ZatPoint(seg->v2)); + angle_t temp; + // Wall can be tilted from viewpoint perspective. Find vertical extent on screen in psuedopitch units (0 to 2, bottom to top) + if(int(startPitch) > int(startPitch2)) // Handle zero crossing + { + temp = startPitch; startPitch = startPitch2; startPitch2 = temp; // exchange + } + if(int(endPitch) > int(endPitch2)) // Handle zero crossing + { + temp = endPitch; endPitch = endPitch2; endPitch2 = temp; // exchange + } + + if (!clipperv.SafeCheckRange(startPitch, endPitch2)) { return; } - currentsubsector->flags |= SSECMF_DRAWN; + + if (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || clipperr.SafeCheckRange(startAngleR, endAngleR)) + currentsubsector->flags |= SSECMF_DRAWN; uint8_t ispoly = uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ); if (!seg->backsector) { - clipper.SafeAddClipRange(startAngle, endAngle); + if(!Viewpoint.IsAllowedOoB()) + if (!(seg->sidedef->Flags & WALLF_DITHERTRANS)) clipper.SafeAddClipRange(startAngle, endAngle); } else if (!ispoly) // Two-sided polyobjects never obstruct the view { @@ -288,7 +361,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) { if (!seg->linedef->isVisualPortal()) { - FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::mid), true); + auto tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::mid), true); if (!tex || !tex->isValid()) { // nothing to do here! @@ -307,7 +380,8 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) if (hw_CheckClip(seg->sidedef, currentsector, backsector)) { - clipper.SafeAddClipRange(startAngle, endAngle); + if(!Viewpoint.IsAllowedOoB() && !(seg->sidedef->Flags & WALLF_DITHERTRANS)) + clipper.SafeAddClipRange(startAngle, endAngle); } } } @@ -332,9 +406,10 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) else { HWWall wall; + HWWallDispatcher disp(this); SetupWall.Clock(); wall.sub = seg->Subsector; - wall.Process(this, seg, currentsector, backsector); + wall.Process(&disp, seg, currentsector, backsector); rendered_lines++; SetupWall.Unclock(); } @@ -413,11 +488,6 @@ void HWDrawInfo::AddPolyobjs(subsector_t *sub) if (sub->BSP == nullptr || sub->BSP->bDirty) { sub->BuildPolyBSP(); - for (unsigned i = 0; i < sub->BSP->Segs.Size(); i++) - { - sub->BSP->Segs[i].Subsector = sub; - sub->BSP->Segs[i].PartnerSeg = nullptr; - } } if (sub->BSP->Nodes.Size() == 0) { @@ -474,13 +544,13 @@ void HWDrawInfo::AddLines(subsector_t * sub, sector_t * sector) // //========================================================================== -inline bool PointOnLine(const DVector2 &pos, const line_t *line) +inline bool PointOnLine(const DVector2 &pos, const linebase_t *line) { double v = (pos.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pos.X) * line->Delta().Y; return fabs(v) <= EQUAL_EPSILON; } -void HWDrawInfo::AddSpecialPortalLines(subsector_t * sub, sector_t * sector, line_t *line) +void HWDrawInfo::AddSpecialPortalLines(subsector_t * sub, sector_t * sector, linebase_t *line) { currentsector = sector; currentsubsector = sub; @@ -512,13 +582,14 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector) { sector_t * sec=sub->sector; // Handle all things in sector. - const auto &vp = Viewpoint; + const auto &vp = Viewpoint; for (auto p = sec->touching_renderthings; p != nullptr; p = p->m_snext) { auto thing = p->m_thing; if (thing->validcount == validcount) continue; thing->validcount = validcount; + if(Viewpoint.IsAllowedOoB() && thing->Sector->isSecret() && thing->Sector->wasSecret() && !r_radarclipper) continue; // This covers things that are touching non-secret sectors FIntCVar *cvar = thing->GetInfo()->distancecheck; if (cvar != nullptr && *cvar >= 0) { @@ -533,6 +604,18 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector) if (CurrentMapSections[thing->subsector->mapsection]) { HWSprite sprite; + + // [Nash] draw sprite shadow + if (R_ShouldDrawSpriteShadow(thing)) + { + double dist = (thing->Pos() - vp.Pos).LengthSquared(); + double check = r_actorspriteshadowdist; + if (dist <= check * check) + { + sprite.Process(this, thing, sector, in_area, false, true); + } + } + sprite.Process(this, thing, sector, in_area, false); } } @@ -552,6 +635,18 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector) } HWSprite sprite; + + // [Nash] draw sprite shadow + if (R_ShouldDrawSpriteShadow(thing)) + { + double dist = (thing->Pos() - vp.Pos).LengthSquared(); + double check = r_actorspriteshadowdist; + if (dist <= check * check) + { + sprite.Process(this, thing, sector, in_area, true, true); + } + } + sprite.Process(this, thing, sector, in_area, true); } } @@ -559,16 +654,31 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector) void HWDrawInfo::RenderParticles(subsector_t *sub, sector_t *front) { SetupSprite.Clock(); + for (uint32_t i = 0; i < sub->sprites.Size(); i++) + { + DVisualThinker *sp = sub->sprites[i]; + if (!sp || sp->ObjectFlags & OF_EuthanizeMe) + continue; + if (mClipPortal) + { + int clipres = mClipPortal->ClipPoint(sp->PT.Pos.XY()); + if (clipres == PClip_InFront) continue; + } + + assert(sp->spr); + + sp->spr->ProcessParticle(this, &sp->PT, front, sp); + } for (int i = Level->ParticlesInSubsec[sub->Index()]; i != NO_PARTICLE; i = Level->Particles[i].snext) { if (mClipPortal) { - int clipres = mClipPortal->ClipPoint(Level->Particles[i].Pos); + int clipres = mClipPortal->ClipPoint(Level->Particles[i].Pos.XY()); if (clipres == PClip_InFront) continue; } HWSprite sprite; - sprite.ProcessParticle(this, &Level->Particles[i], front); + sprite.ProcessParticle(this, &Level->Particles[i], front, nullptr); } SetupSprite.Unclock(); } @@ -613,12 +723,57 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) fakesector=hw_FakeFlat(sector, in_area, false); + if(Viewpoint.IsAllowedOoB() && sector->isSecret() && sector->wasSecret() && !r_radarclipper) return; + + // cull everything if subsector outside vertical clipper + if ((sub->polys == nullptr) && (!Viewpoint.IsOrtho() || !((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper))) + { + auto &clipper = *mClipper; + auto &clipperv = *vClipper; + auto &clipperr = *rClipper; + int count = sub->numlines; + seg_t * seg = sub->firstline; + bool anglevisible = false; + bool pitchvisible = false; + bool radarvisible = false; + angle_t pitchtemp; + angle_t pitchmin = ANGLE_90; + angle_t pitchmax = 0; + + while (count--) + { + if((seg->v1 != nullptr) && (seg->v2 != nullptr)) + { + angle_t startAngle = clipper.GetClipAngle(seg->v2); + angle_t endAngle = clipper.GetClipAngle(seg->v1); + if (startAngle-endAngle >= ANGLE_180) anglevisible |= clipper.SafeCheckRange(startAngle, endAngle); + angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY()); + angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY()); + if (startAngleR-endAngleR >= ANGLE_180) + radarvisible |= (clipperr.SafeCheckRange(startAngleR, endAngleR) || (Level->flags3 & LEVEL3_NOFOGOFWAR) || ((sub->flags & SSECMF_DRAWN) && !deathmatch)); + pitchmin = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->floorplane.ZatPoint(seg->v1)); + pitchmax = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->ceilingplane.ZatPoint(seg->v1)); + pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax); + if (pitchvisible && anglevisible && radarvisible) break; + pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->floorplane.ZatPoint(seg->v2)); + if (int(pitchmin) > int(pitchtemp)) pitchmin = pitchtemp; + pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->ceilingplane.ZatPoint(seg->v2)); + if (int(pitchmax) < int(pitchtemp)) pitchmax = pitchtemp; + pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax); + if (pitchvisible && anglevisible && radarvisible) break; + } + seg++; + } + // Skip subsector if outside vertical or horizontal clippers or is in unexplored territory (fog of war) + if(!pitchvisible || !anglevisible || (!radarvisible && r_radarclipper)) return; + } + if (mClipPortal) { int clipres = mClipPortal->ClipSubsector(sub); if (clipres == PClip_InFront) { - line_t *line = mClipPortal->ClipLine(); + auto line = mClipPortal->ClipLine(); // The subsector is out of range, but we still have to check lines that lie directly on the boundary and may expose their upper or lower parts. if (line) AddSpecialPortalLines(sub, fakesector, line); return; @@ -627,11 +782,11 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) if (sector->validcount != validcount) { - screen->mVertexData->CheckUpdate(sector); + CheckUpdate(screen->mVertexData, sector); } // [RH] Add particles - if (gl_render_things && Level->ParticlesInSubsec[sub->Index()] != NO_PARTICLE) + if (gl_render_things && (sub->sprites.Size() > 0 || Level->ParticlesInSubsec[sub->Index()] != NO_PARTICLE)) { if (multithread) { @@ -670,6 +825,20 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) SetupSprite.Unclock(); } } + if (r_dithertransparency && Viewpoint.IsAllowedOoB() && (RTnum < MAXDITHERACTORS)) + { + // [DVR] Not parallelizable due to variables RTnum and RenderedTargets[] + for (auto p = sector->touching_renderthings; p != nullptr; p = p->m_snext) + { + auto thing = p->m_thing; + if (thing->validcount == validcount) continue; // Don't double count + if (((thing->flags3 & MF3_ISMONSTER) && !(thing->flags & MF_CORPSE)) || (thing->flags & MF_MISSILE)) + { + if (RTnum < MAXDITHERACTORS) RenderedTargets[RTnum++] = thing; + else break; + } + } + } } if (gl_render_flats) @@ -790,19 +959,62 @@ void HWDrawInfo::RenderBSPNode (void *node) if (!(no_renderflags[bsp->Index()] & SSRF_SEEN)) return; } + if (Viewpoint.IsOrtho()) + { + if (!vClipper->CheckBoxOrthoPitch(bsp->bbox[side])) + { + if (!(no_renderflags[bsp->Index()] & SSRF_SEEN)) + return; + } + } node = bsp->children[side]; } DoSubsector ((subsector_t *)((uint8_t *)node - 1)); } +// No need for clipping inside frustum if no fog of war (How is this faster!) +void HWDrawInfo::RenderOrthoNoFog() +{ + if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) + { + double vxdbl = Viewpoint.camera->X(); + double vydbl = Viewpoint.camera->Y(); + double ext = Viewpoint.camera->ViewPos->Offset.Length() ? + 3.0 * Viewpoint.camera->ViewPos->Offset.Length() : 100.0; + FBoundingBox viewbox(vxdbl, vydbl, ext); + + for (unsigned int kk = 0; kk < Level->subsectors.Size(); kk++) + { + if (Level->subsectors[kk].bbox.CheckOverlap(viewbox)) + { + DoSubsector (&Level->subsectors[kk]); + } + } + } +} + void HWDrawInfo::RenderBSP(void *node, bool drawpsprites) { + ClearDitherTargets(); Bsp.Clock(); // Give the DrawInfo the viewpoint in fixed point because that's what the nodes are. viewx = FLOAT2FIXED(Viewpoint.Pos.X); viewy = FLOAT2FIXED(Viewpoint.Pos.Y); + if (r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && Viewpoint.IsAllowedOoB() && (Viewpoint.camera->ViewPos->Flags & VPSF_ABSOLUTEOFFSET)) + { + if (Viewpoint.camera->tracer != NULL) + { + viewx = FLOAT2FIXED(Viewpoint.camera->tracer->X()); + viewy = FLOAT2FIXED(Viewpoint.camera->tracer->Y()); + } + else + { + viewx = FLOAT2FIXED(Viewpoint.camera->X()); + viewy = FLOAT2FIXED(Viewpoint.camera->Y()); + } + } validcount++; // used for processing sidedefs only once by the renderer. @@ -813,7 +1025,8 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites) auto future = renderPool.push([&](int id) { WorkerThread(); }); - RenderBSPNode(node); + if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) RenderOrthoNoFog(); + else RenderBSPNode(node); jobQueue.AddJob(RenderJob::TerminateJob, nullptr, nullptr); Bsp.Unclock(); @@ -823,9 +1036,21 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites) } else { - RenderBSPNode(node); + if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) RenderOrthoNoFog(); + else RenderBSPNode(node); Bsp.Unclock(); } + + // Make rendered targets set dither transparency flags on level geometry for next pass + // Can't do this inside DoSubsector() because both Trace() and P_CheckSight() affect 'validcount' global variable + for (int ii = 0; ii < MAXDITHERACTORS; ii++) + { + if ( RenderedTargets[ii] && P_CheckSight(players[consoleplayer].mo, RenderedTargets[ii], 0) ) + { + SetDitherTransFlags(RenderedTargets[ii]); + } + } + // Process all the sprites on the current portal's back side which touch the portal. if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this); diff --git a/src/rendering/hwrenderer/scene/hw_clipper.cpp b/src/rendering/hwrenderer/scene/hw_clipper.cpp index 85646f84c1b..94713f107d5 100644 --- a/src/rendering/hwrenderer/scene/hw_clipper.cpp +++ b/src/rendering/hwrenderer/scene/hw_clipper.cpp @@ -37,6 +37,7 @@ #include "hw_clipper.h" #include "g_levellocals.h" +#include "basics.h" unsigned Clipper::starttime; @@ -192,7 +193,7 @@ void Clipper::AddClipRange(angle_t start, angle_t end) if (node->end < end) { - node->end = end; + node->end = end; // [DVR] This never triggers because of previous while loop. Remove? } ClipNode *node2 = node->next; @@ -360,6 +361,17 @@ angle_t Clipper::AngleToPseudo(angle_t ang) return xs_Fix<30>::ToFix(result); } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +angle_t Clipper::PitchToPseudo(double ang) +{ + return AngleToPseudo(DAngle::fromDeg(90.0-ang).BAMs()); // Pitch is positive when looking down +} + //----------------------------------------------------------------------------- // // ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the @@ -377,11 +389,28 @@ angle_t Clipper::PointToPseudoAngle(double x, double y) { double vecx = x - viewpoint->Pos.X; double vecy = y - viewpoint->Pos.Y; + if ((viewpoint->camera != NULL) && amRadar) + { + if (viewpoint->camera->tracer != NULL) + { + vecx = x - viewpoint->camera->tracer->X(); + vecy = y - viewpoint->camera->tracer->Y(); + } + else + { + vecx = x - viewpoint->camera->X(); + vecy = y - viewpoint->camera->Y(); + } + } if (vecx == 0 && vecy == 0) { return 0; } + else if (!amRadar && viewpoint->IsOrtho()) + { + return PointToPseudoOrthoAngle(x, y); + } else { double result = vecy / (fabs(vecx) + fabs(vecy)); @@ -394,6 +423,78 @@ angle_t Clipper::PointToPseudoAngle(double x, double y) } +angle_t Clipper::PointToPseudoPitch(double x, double y, double z) +{ + double vecx = x - viewpoint->Pos.X; + double vecy = y - viewpoint->Pos.Y; + double vecz = z - viewpoint->Pos.Z; + double result = 0; + + if (vecx == 0 && vecy == 0 && vecz == 0) + { + return 0; + } + else if (viewpoint->IsOrtho()) + { + return PointToPseudoOrthoPitch(x, y, z); + } + else + { + double result = vecz / (g_sqrt(vecx*vecx + vecy*vecy) + fabs(vecz)); // -ffast-math compile flag applies to this file, yes? + if ((vecx * viewpoint->TanCos + vecy * viewpoint->TanSin) <= 0.0) // Point is behind viewpoint + { + result = 2.0 - result; + } + return xs_Fix<30>::ToFix(result + 1.0); // range to 0 to 2 to 4 (bottom to top to suplex) + } +} + + +angle_t Clipper::PointToPseudoOrthoAngle(double x, double y) +{ + DVector3 disp = DVector3( x, y, 0 ) - viewpoint->camera->Pos(); + if (viewpoint->camera->ViewPos->Offset.XY().Length() == 0) + { + return AngleToPseudo( viewpoint->Angles.Yaw.BAMs() ); + } + else + { + angle_t af = viewpoint->FrustAngle; + double xproj = disp.XY().Length() * deltaangle(disp.Angle(), viewpoint->Angles.Yaw).Sin(); + xproj *= viewpoint->ScreenProj; + if (fabs(xproj) < 2.0) + { + return AngleToPseudo( viewpoint->Angles.Yaw.BAMs() - xproj * 0.5 * af ); + } + else + { + return (xproj > 0.0 ? AngleToPseudo( viewpoint->Angles.Yaw.BAMs() - af ) : AngleToPseudo( viewpoint->Angles.Yaw.BAMs() + af )); + } + } +} + + +angle_t Clipper::PointToPseudoOrthoPitch(double x, double y, double z) +{ + DVector3 disp = DVector3( x, y, z ) - viewpoint->camera->Pos(); + if (viewpoint->camera->ViewPos->Offset.XY().Length() > 0) + { + double yproj = viewpoint->PitchSin * disp.XY().Length() * deltaangle(disp.Angle(), viewpoint->Angles.Yaw).Cos(); + yproj += viewpoint->PitchCos * disp.Z; + yproj *= viewpoint->ScreenProj; + if (fabs(yproj) <= 1.5) + { + return PitchToPseudo(viewpoint->Angles.Pitch.Degrees() - yproj * 0.5 * viewpoint->FieldOfView.Degrees() ); + } + else + { + double a2 = 0.75*viewpoint->FieldOfView.Degrees(); + a2 *= ( yproj > 0.0 ? -1.0 : 1.0 ); + return PitchToPseudo(viewpoint->Angles.Pitch.Degrees() + a2 ); + } + } + else return PitchToPseudo(viewpoint->Angles.Pitch.Degrees()); +} //----------------------------------------------------------------------------- // @@ -427,7 +528,7 @@ bool Clipper::CheckBox(const float *bspcoord) // Find the corners of the box // that define the edges from current viewpoint. - auto &vp = viewpoint; + auto &vp = viewpoint; boxpos = (vp->Pos.X <= bspcoord[BOXLEFT] ? 0 : vp->Pos.X < bspcoord[BOXRIGHT ] ? 1 : 2) + (vp->Pos.Y >= bspcoord[BOXTOP ] ? 0 : vp->Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8); @@ -436,7 +537,47 @@ bool Clipper::CheckBox(const float *bspcoord) check = checkcoord[boxpos]; angle1 = PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]); angle2 = PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[3]]); + + if (vp->IsOrtho()) + { + if (angle2 != angle1) return true; + switch (boxpos) // Check if the closer corner is poking into the view area + { + case 0: + case 10: + if ( angle1 != PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[1]]) ) return true; + break; + case 2: + case 8: + if ( angle1 != PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[3]]) ) return true; + break; + default: + break; + } + } return SafeCheckRange(angle2, angle1); } +bool Clipper::CheckBoxOrthoPitch(const float *bspcoord) +{ + angle_t pitchmin, pitchmax; + auto &vp = viewpoint; + if (!vp->IsOrtho()) return true; + + angle_t pitchtemp; + double padding = 1.0/viewpoint->ScreenProj/viewpoint->PitchCos; + double camz = vp->camera->Pos().Z - padding; + pitchmin = PointToPseudoPitch (bspcoord[BOXLEFT], bspcoord[BOXTOP], camz); + pitchmax = PointToPseudoPitch (bspcoord[BOXLEFT], bspcoord[BOXTOP], camz + 2.0*padding); + for (int yi = BOXTOP; yi <= BOXBOTTOM; yi++) + for (int xi = BOXLEFT; xi <= BOXRIGHT; xi++) + { + pitchtemp = PointToPseudoPitch (bspcoord[xi], bspcoord[yi], camz); + if (pitchmin - pitchtemp < ANGLE_180) pitchmin = pitchtemp; + pitchtemp = PointToPseudoPitch (bspcoord[xi], bspcoord[yi], camz + 2.0*padding); + if (pitchtemp - pitchmax < ANGLE_180) pitchmax = pitchtemp; + } + + return (pitchmax != pitchmin); // SafeCheckRange(pitchmin, pitchmax); +} diff --git a/src/rendering/hwrenderer/scene/hw_clipper.h b/src/rendering/hwrenderer/scene/hw_clipper.h index e8da8172cf6..c2643efd389 100644 --- a/src/rendering/hwrenderer/scene/hw_clipper.h +++ b/src/rendering/hwrenderer/scene/hw_clipper.h @@ -29,10 +29,11 @@ class Clipper ClipNode * clipnodes = nullptr; ClipNode * cliphead = nullptr; ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called - const FRenderViewpoint *viewpoint = nullptr; + FRenderViewpoint *viewpoint = nullptr; bool blocked = false; static angle_t AngleToPseudo(angle_t ang); + static angle_t PitchToPseudo(double ang); bool IsRangeVisible(angle_t startangle, angle_t endangle); void RemoveRange(ClipNode * cn); void AddClipRange(angle_t startangle, angle_t endangle); @@ -41,6 +42,7 @@ class Clipper public: + bool amRadar = false; Clipper(); void Clear(); @@ -72,7 +74,7 @@ class Clipper return c; } - void SetViewpoint(const FRenderViewpoint &vp) + void SetViewpoint(FRenderViewpoint &vp) { viewpoint = &vp; } @@ -116,6 +118,10 @@ class Clipper SafeAddClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle)); } + void SafeAddClipRangeDegPitches(double startpitch, double endpitch) + { + SafeAddClipRange(PitchToPseudo(startpitch), PitchToPseudo(endpitch)); + } void SafeRemoveClipRange(angle_t startangle, angle_t endangle) { @@ -146,10 +152,14 @@ class Clipper { return blocked; } - - angle_t PointToPseudoAngle(double x, double y); + + angle_t PointToPseudoAngle(double x, double y); + angle_t PointToPseudoPitch(double x, double y, double z); + angle_t PointToPseudoOrthoAngle(double x, double y); + angle_t PointToPseudoOrthoPitch(double x, double y, double z); bool CheckBox(const float *bspcoord); + bool CheckBoxOrthoPitch(const float *bspcoord); // Used to speed up angle calculations during clipping inline angle_t GetClipAngle(vertex_t *v) diff --git a/src/rendering/hwrenderer/scene/hw_decal.cpp b/src/rendering/hwrenderer/scene/hw_decal.cpp index ec5343cc516..1e28cdd5fae 100644 --- a/src/rendering/hwrenderer/scene/hw_decal.cpp +++ b/src/rendering/hwrenderer/scene/hw_decal.cpp @@ -29,14 +29,15 @@ #include "a_sharedglobal.h" #include "r_utility.h" #include "g_levellocals.h" -#include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/utility/hw_cvars.h" +#include "hw_material.h" +#include "hw_cvars.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawinfo.h" -#include "hwrenderer/utility/hw_lighting.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/data/flatvertices.h" +#include "hw_lighting.h" +#include "hw_clock.h" +#include "flatvertices.h" #include "hw_renderstate.h" +#include "texturemanager.h" //========================================================================== // @@ -46,28 +47,36 @@ void HWDecal::DrawDecal(HWDrawInfo *di, FRenderState &state) { - auto tex = gltexture; - - // calculate dynamic light effect. - if (di->Level->HasDynamicLights && !di->isFullbrightScene() && gl_light_sprites) + PalEntry DecalColor; + // alpha color only has an effect when using an alpha texture. + if (decal->RenderStyle.Flags & (STYLEF_RedIsAlpha | STYLEF_ColorIsFixed)) { - // Note: This should be replaced with proper shader based lighting. - double x, y; - float out[3]; - decal->GetXY(decal->Side, x, y); - di->GetDynSpriteLight(nullptr, x, y, zcenter, decal->Side->lighthead, decal->Side->sector->PortalGroup, out); - state.SetDynLight(out[0], out[1], out[2]); + DecalColor = decal->AlphaColor | 0xff000000; } + else + DecalColor = 0xffffffff; - // alpha color only has an effect when using an alpha texture. - if (decal->RenderStyle.Flags & (STYLEF_RedIsAlpha | STYLEF_ColorIsFixed)) + if (!di->isFullbrightScene()) DecalColor = DecalColor.Modulate(frontsector->SpecialColors[sector_t::sprites]); + + state.SetObjectColor(DecalColor); + + state.SetLightIndex(dynlightindex); + + // add light probe contribution + if (di->Level->LightProbes.Size() > 0) { - state.SetObjectColor(decal->AlphaColor | 0xff000000); + double x, y; + decal->GetXY(decal->Side, x, y); + LightProbe *probe = FindLightProbe(di->Level, x, y, decal->GetRealZ(decal->Side) * 0.5); + if (probe) + { + state.SetDynLight(probe->Red, probe->Green, probe->Blue); + } } state.SetTextureMode(decal->RenderStyle); state.SetRenderStyle(decal->RenderStyle); - state.SetMaterial(tex, CLAMP_XY, decal->Translation, -1); + state.SetMaterial(texture, UF_Sprite, 0, CLAMP_XY, decal->Translation, -1); // If srcalpha is one it looks better with a higher alpha threshold @@ -75,7 +84,7 @@ void HWDecal::DrawDecal(HWDrawInfo *di, FRenderState &state) else state.AlphaFunc(Alpha_Greater, 0.f); - di->SetColor(state, lightlevel, rellight, di->isFullbrightScene(), Colormap, alpha); + SetColor(state, di->Level, di->lightmode, lightlevel, rellight, di->isFullbrightScene(), Colormap, alpha); // for additively drawn decals we must temporarily set the fog color to black. PalEntry fc = state.GetFogColor(); if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One) @@ -105,11 +114,11 @@ void HWDecal::DrawDecal(HWDrawInfo *di, FRenderState &state) int thisll = lightlist[k].caster != nullptr ? hw_ClampLight(*lightlist[k].p_lightlevel) : lightlevel; FColormap thiscm; thiscm.FadeColor = Colormap.FadeColor; - thiscm.CopyFrom3DLight(&lightlist[k]); - di->SetColor(state, thisll, rellight, di->isFullbrightScene(), thiscm, alpha); + CopyFrom3DLight(thiscm, &lightlist[k]); + SetColor(state, di->Level, di->lightmode, thisll, rellight, di->isFullbrightScene(), thiscm, alpha); if (di->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) thiscm.Decolorize(); - di->SetFog(state, thisll, rellight, di->isFullbrightScene(), &thiscm, false); - state.SetSplitPlanes(lightlist[k].plane, lowplane); + SetFog(state, di->Level, di->lightmode, thisll, rellight, di->isFullbrightScene(), &thiscm, false); + SetSplitPlanes(state, lightlist[k].plane, lowplane); state.Draw(DT_TriangleStrip, vertindex, 4); } @@ -133,8 +142,8 @@ void HWDrawInfo::DrawDecals(FRenderState &state, TArray &decals) { side_t *wall = nullptr; state.SetDepthMask(false); + state.SetTextureClamp(true); state.SetDepthBias(-1, -128); - state.SetLightIndex(-1); for (auto gldecal : decals) { if (gldecal->decal->Side != wall) @@ -147,7 +156,7 @@ void HWDrawInfo::DrawDecals(FRenderState &state, TArray &decals) else { state.EnableSplit(false); - SetFog(state, gldecal->lightlevel, gldecal->rellight, isFullbrightScene(), &gldecal->Colormap, false); + SetFog(state, Level, lightmode, gldecal->lightlevel, gldecal->rellight, isFullbrightScene(), &gldecal->Colormap, false); } } gldecal->DrawDecal(this, state); @@ -156,6 +165,7 @@ void HWDrawInfo::DrawDecals(FRenderState &state, TArray &decals) state.ClearDepthBias(); state.SetTextureMode(TM_NORMAL); state.SetDepthMask(true); + state.SetTextureClamp(false); } //========================================================================== @@ -168,8 +178,7 @@ void HWWall::DrawDecalsForMirror(HWDrawInfo *di, FRenderState &state, TArraySetFog(state, lightlevel, rellight + getExtraLight(), di->isFullbrightScene(), &Colormap, false); + SetFog(state, di->Level, di->lightmode, lightlevel, rellight + getExtraLight(), di->isFullbrightScene(), &Colormap, false); for (auto gldecal : decals) { if (gldecal->decal->Side == seg->sidedef) @@ -199,7 +208,7 @@ void HWWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor if (decal->RenderFlags & RF_INVISIBLE) return; - if (type == RENDERWALL_FFBLOCK && gltexture->isMasked()) return; // No decals on 3D floors with transparent textures. + if (type == RENDERWALL_FFBLOCK && texture->isMasked()) return; // No decals on 3D floors with transparent textures. if (seg == nullptr) return; @@ -208,7 +217,7 @@ void HWWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor flipy = !!(decal->RenderFlags & RF_YFLIP); - FTexture *texture = TexMan.GetTexture(decalTile); + auto texture = TexMan.GetGameTexture(decalTile); if (texture == NULL) return; @@ -264,14 +273,13 @@ void HWWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } } - FMaterial *tex = FMaterial::ValidateTexture(texture, false); // now clip the decal to the actual polygon - float decalwidth = tex->TextureWidth() * decal->ScaleX; - float decalheight = tex->TextureHeight() * decal->ScaleY; - float decallefto = tex->GetLeftOffset() * decal->ScaleX; - float decaltopo = tex->GetTopOffset() * decal->ScaleY; + float decalwidth = texture->GetDisplayWidth() * decal->ScaleX; + float decalheight = texture->GetDisplayHeight() * decal->ScaleY; + float decallefto = texture->GetDisplayLeftOffset() * decal->ScaleX; + float decaltopo = texture->GetDisplayTopOffset() * decal->ScaleY; float leftedge = glseg.fracleft * side->TexelLength; float linelength = glseg.fracright * side->TexelLength - leftedge; @@ -328,11 +336,12 @@ void HWWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor dv[UL].z = dv[UR].z = zpos; dv[LL].z = dv[LR].z = dv[UL].z - decalheight; - dv[UL].v = dv[UR].v = tex->GetVT(); + dv[UL].v = dv[UR].v = 0.f; - dv[UL].u = dv[LL].u = tex->GetU(lefttex / decal->ScaleX); - dv[LR].u = dv[UR].u = tex->GetU(righttex / decal->ScaleX); - dv[LL].v = dv[LR].v = tex->GetVB(); + float decalscale = float(decal->ScaleX * texture->GetDisplayWidth()); + dv[UL].u = dv[LL].u = lefttex / decalscale; + dv[LR].u = dv[UR].u = righttex / decalscale; + dv[LL].v = dv[LR].v = 1.f; // now clip to the top plane float vzt = (ztop[UL] - ztop[LL]) / linelength; @@ -375,28 +384,28 @@ void HWWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor if (flipx) { - float ur = tex->GetUR(); - for (i = 0; i < 4; i++) dv[i].u = ur - dv[i].u; + for (i = 0; i < 4; i++) dv[i].u = 1.f - dv[i].u; } if (flipy) { - float vb = tex->GetVB(); - for (i = 0; i < 4; i++) dv[i].v = vb - dv[i].v; + for (i = 0; i < 4; i++) dv[i].v = 1.f - dv[i].v; } HWDecal *gldecal = di->AddDecal(type == RENDERWALL_MIRRORSURFACE); - gldecal->gltexture = tex; + gldecal->texture = texture; gldecal->decal = decal; if (decal->RenderFlags & RF_FULLBRIGHT) { gldecal->lightlevel = 255; gldecal->rellight = 0; + gldecal->dynlightindex = -1; } else { gldecal->lightlevel = lightlevel; gldecal->rellight = rellight + getExtraLight(); + gldecal->dynlightindex = dynlightindex; } gldecal->Colormap = Colormap; diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index db74848b200..b7c02a84148 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -35,18 +35,32 @@ #include "hw_renderstate.h" #include "hw_drawinfo.h" #include "po_man.h" -#include "r_data/models/models.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" -#include "hwrenderer/utility/hw_vrmodes.h" +#include "models.h" +#include "hw_clock.h" +#include "hw_cvars.h" +#include "hw_viewpointbuffer.h" +#include "flatvertices.h" +#include "hw_lightbuffer.h" +#include "hw_bonebuffer.h" +#include "hw_vrmodes.h" #include "hw_clipper.h" +#include "v_draw.h" +#include "a_corona.h" +#include "texturemanager.h" +#include "actorinlines.h" +#include "g_levellocals.h" EXTERN_CVAR(Float, r_visibility) CVAR(Bool, gl_bandedswlight, false, CVAR_ARCHIVE) CVAR(Bool, gl_sort_textures, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, gl_no_skyclear, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, gl_enhanced_nv_stealth, 3, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + +CVAR(Bool, gl_texture, true, 0) +CVAR(Float, gl_mask_threshold, 0.5f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Float, gl_mask_sprite_threshold, 0.5f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + +CVAR(Bool, gl_coronas, true, CVAR_ARCHIVE); sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back); @@ -90,7 +104,6 @@ HWDrawInfo *FDrawInfoList::GetNew() void FDrawInfoList::Release(HWDrawInfo * di) { - di->DrawScene = nullptr; di->ClearBuffers(); di->Level = nullptr; mList.Push(di); @@ -105,7 +118,6 @@ void FDrawInfoList::Release(HWDrawInfo * di) HWDrawInfo *HWDrawInfo::StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms) { HWDrawInfo *di = di_list.GetNew(); - if (parent) di->DrawScene = parent->DrawScene; di->Level = lev; di->StartScene(parentvp, uniforms); return di; @@ -119,15 +131,23 @@ HWDrawInfo *HWDrawInfo::StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRe //========================================================================== static Clipper staticClipper; // Since all scenes are processed sequentially we only need one clipper. +static Clipper staticVClipper; // Another clipper to clip vertically (used if (VPSF_ALLOWOUTOFBOUNDS & camera->viewpos->Flags)). +static Clipper staticRClipper; // Another clipper for radar (doesn't actually clip. Changes SSECMF_DRAWN setting). static HWDrawInfo * gl_drawinfo; // This is a linked list of all active DrawInfos and needed to free the memory arena after the last one goes out of scope. void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms) { staticClipper.Clear(); + staticVClipper.Clear(); + staticRClipper.Clear(); mClipper = &staticClipper; + vClipper = &staticVClipper; + rClipper = &staticRClipper; + rClipper->amRadar = true; Viewpoint = parentvp; - lightmode = Level->lightMode; + lightmode = getRealLightmode(Level, true); + if (uniforms) { VPUniforms = *uniforms; @@ -135,13 +155,35 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni VPUniforms.mClipLine.X = -1000001.f; VPUniforms.mClipHeight = 0; } - else VPUniforms.SetDefaults(this); + else + { + VPUniforms.mProjectionMatrix.loadIdentity(); + VPUniforms.mViewMatrix.loadIdentity(); + VPUniforms.mNormalViewMatrix.loadIdentity(); + VPUniforms.mViewHeight = viewheight; + if (lightmode == ELightMode::Build) + { + VPUniforms.mGlobVis = 1 / 64.f; + VPUniforms.mPalLightLevels = 32 | (static_cast(gl_fogmode) << 8) | ((int)lightmode << 16); + } + else + { + VPUniforms.mGlobVis = (float)R_GetGlobVis(r_viewwindow, r_visibility) / 32.f; + VPUniforms.mPalLightLevels = static_cast(gl_bandedswlight) | (static_cast(gl_fogmode) << 8) | ((int)lightmode << 16); + } + VPUniforms.mClipLine.X = -10000000.0f; + VPUniforms.mShadowmapFilter = gl_shadowmap_filter; + VPUniforms.mLightBlendMode = (level.info ? (int)level.info->lightblendmode : 0); + } mClipper->SetViewpoint(Viewpoint); + vClipper->SetViewpoint(Viewpoint); + rClipper->SetViewpoint(Viewpoint); ClearBuffers(); for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset(); hudsprites.Clear(); +// Coronas.Clear(); vpIndex = 0; // Fullbright information needs to be propagated from the main view. @@ -224,7 +266,9 @@ void HWDrawInfo::ClearBuffers() void HWDrawInfo::UpdateCurrentMapSection() { - const int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection; + int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection; + if (Viewpoint.IsAllowedOoB()) + mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection; CurrentMapSections.Set(mapsection); } @@ -237,9 +281,11 @@ void HWDrawInfo::UpdateCurrentMapSection() void HWDrawInfo::SetViewArea() { - auto &vp = Viewpoint; + auto &vp = Viewpoint; // The render_sector is better suited to represent the current position in GL vp.sector = Level->PointInRenderSubsector(vp.Pos)->render_sector; + if (Viewpoint.IsAllowedOoB()) + vp.sector = Level->PointInRenderSubsector(vp.camera->Pos())->render_sector; // Get the heightsec state from the render sector, not the current one! if (vp.sector->GetHeightSec()) @@ -271,7 +317,7 @@ int HWDrawInfo::SetFullbrightFlags(player_t *player) int cm = CM_DEFAULT; if (cplayer->extralight == INT_MIN) { - cm = CM_FIRSTSPECIALCOLORMAP + INVERSECOLORMAP; + cm = CM_FIRSTSPECIALCOLORMAP + REALINVERSECOLORMAP; Viewpoint.extralight = 0; FullbrightFlags = Fullbright; // This does never set stealth vision. @@ -318,16 +364,21 @@ int HWDrawInfo::SetFullbrightFlags(player_t *player) angle_t HWDrawInfo::FrustumAngle() { - float tilt = fabs(Viewpoint.HWAngles.Pitch.Degrees); - - // If the pitch is larger than this you can look all around at a FOV of 90° - if (tilt > 46.0f) return 0xffffffff; - - // ok, this is a gross hack that barely works... - // but at least it doesn't overestimate too much... - double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio) / 90.0; - angle_t a1 = DAngle(floatangle).BAMs(); - if (a1 >= ANGLE_180) return 0xffffffff; + // If pitch is larger than this you can look all around at an FOV of 90 degrees + if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 89.0) return 0xffffffff; + int aspMult = AspectMultiplier(r_viewwindow.WidescreenRatio); // 48 == square window + double absPitch = fabs(Viewpoint.HWAngles.Pitch.Degrees()); + // Smaller aspect ratios still clip too much. Need a better solution + if (aspMult > 36 && absPitch > 30.0) return 0xffffffff; + else if (aspMult > 40 && absPitch > 25.0) return 0xffffffff; + else if (aspMult > 45 && absPitch > 20.0) return 0xffffffff; + else if (aspMult > 47 && absPitch > 10.0) return 0xffffffff; + + double xratio = r_viewwindow.FocalTangent / Viewpoint.PitchCos; + double floatangle = 0.05 + atan ( xratio ) * 48.0 / aspMult; // this is radians + angle_t a1 = DAngle::fromRad(floatangle).BAMs(); + + if (a1 >= ANGLE_90) return 0xffffffff; return a1; } @@ -343,9 +394,9 @@ void HWDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float float planemult = planemirror ? -Level->info->pixelstretch : Level->info->pixelstretch; VPUniforms.mViewMatrix.loadIdentity(); - VPUniforms.mViewMatrix.rotate(angles.Roll.Degrees, 0.0f, 0.0f, 1.0f); - VPUniforms.mViewMatrix.rotate(angles.Pitch.Degrees, 1.0f, 0.0f, 0.0f); - VPUniforms.mViewMatrix.rotate(angles.Yaw.Degrees, 0.0f, mult, 0.0f); + VPUniforms.mViewMatrix.rotate(angles.Roll.Degrees(), 0.0f, 0.0f, 1.0f); + VPUniforms.mViewMatrix.rotate(angles.Pitch.Degrees(), 1.0f, 0.0f, 0.0f); + VPUniforms.mViewMatrix.rotate(angles.Yaw.Degrees(), 0.0f, mult, 0.0f); VPUniforms.mViewMatrix.translate(vx * mult, -vz * planemult, -vy); VPUniforms.mViewMatrix.scale(-mult, planemult, 1); } @@ -387,26 +438,6 @@ HWPortal * HWDrawInfo::FindPortal(const void * src) // //----------------------------------------------------------------------------- -void HWViewpointUniforms::SetDefaults(HWDrawInfo *drawInfo) -{ - mProjectionMatrix.loadIdentity(); - mViewMatrix.loadIdentity(); - mNormalViewMatrix.loadIdentity(); - mViewHeight = viewheight; - mGlobVis = (float)R_GetGlobVis(r_viewwindow, r_visibility) / 32.f; - const int lightMode = drawInfo == nullptr ? static_cast(*gl_lightmode) : static_cast(drawInfo->lightmode); - mPalLightLevels = static_cast(gl_bandedswlight) | (static_cast(gl_fogmode) << 8) | (lightMode << 16); - mClipLine.X = -10000000.0f; - mShadowmapFilter = gl_shadowmap_filter; - -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - HWDecal *HWDrawInfo::AddDecal(bool onmirror) { auto decal = (HWDecal*)RenderDataAllocator.Alloc(sizeof(HWDecal)); @@ -425,17 +456,25 @@ HWDecal *HWDrawInfo::AddDecal(bool onmirror) void HWDrawInfo::CreateScene(bool drawpsprites) { const auto &vp = Viewpoint; - angle_t a1 = FrustumAngle(); + angle_t a1 = FrustumAngle(); // horizontally clip the back of the viewport mClipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + a1, vp.Angles.Yaw.BAMs() - a1); + Viewpoint.FrustAngle = a1; + if (Viewpoint.IsAllowedOoB()) // No need for vertical clipper if viewpoint not allowed out of bounds + { + double a2 = 20.0 + 0.5*Viewpoint.FieldOfView.Degrees(); // FrustumPitch for vertical clipping + if (a2 > 179.0) a2 = 179.0; + vClipper->SafeAddClipRangeDegPitches(vp.HWAngles.Pitch.Degrees() - a2, vp.HWAngles.Pitch.Degrees() + a2); // clip the suplex range + } // reset the portal manager - screen->mPortalState->StartFrame(); + portalState.StartFrame(); ProcessAll.Clock(); // clip the scene and fill the drawlists screen->mVertexData->Map(); screen->mLights->Map(); + screen->mBones->Map(); RenderBSP(Level->HeadNode(), drawpsprites); @@ -448,6 +487,7 @@ void HWDrawInfo::CreateScene(bool drawpsprites) PrepareUnhandledMissingTextures(); DispatchRenderHacks(); screen->mLights->Unmap(); + screen->mBones->Unmap(); screen->mVertexData->Unmap(); ProcessAll.Unclock(); @@ -566,6 +606,207 @@ void HWDrawInfo::RenderPortal(HWPortal *p, FRenderState &state, bool usestencil) } +void HWDrawInfo::DrawCorona(FRenderState& state, ACorona* corona, double dist) +{ +#if 0 + spriteframe_t* sprframe = &SpriteFrames[sprites[corona->sprite].spriteframes + (size_t)corona->SpawnState->GetFrame()]; + FTextureID patch = sprframe->Texture[0]; + if (!patch.isValid()) return; + auto tex = TexMan.GetGameTexture(patch, false); + if (!tex || !tex->isValid()) return; + + // Project the corona sprite center + FVector4 worldPos((float)corona->X(), (float)corona->Z(), (float)corona->Y(), 1.0f); + FVector4 viewPos, clipPos; + VPUniforms.mViewMatrix.multMatrixPoint(&worldPos[0], &viewPos[0]); + VPUniforms.mProjectionMatrix.multMatrixPoint(&viewPos[0], &clipPos[0]); + if (clipPos.W < -1.0f) return; // clip z nearest + float halfViewportWidth = screen->GetWidth() * 0.5f; + float halfViewportHeight = screen->GetHeight() * 0.5f; + float invW = 1.0f / clipPos.W; + float screenX = halfViewportWidth + clipPos.X * invW * halfViewportWidth; + float screenY = halfViewportHeight - clipPos.Y * invW * halfViewportHeight; + + float alpha = corona->CoronaFade * float(corona->Alpha); + + // distance-based fade - looks better IMO + float distNearFadeStart = float(corona->RenderRadius()) * 0.1f; + float distFarFadeStart = float(corona->RenderRadius()) * 0.5f; + float distFade = 1.0f; + + if (float(dist) < distNearFadeStart) + distFade -= abs(((float(dist) - distNearFadeStart) / distNearFadeStart)); + else if (float(dist) >= distFarFadeStart) + distFade -= (float(dist) - distFarFadeStart) / distFarFadeStart; + + alpha *= distFade; + + state.SetColorAlpha(0xffffff, alpha, 0); + if (isSoftwareLighting()) state.SetSoftLightLevel(255); + else state.SetNoSoftLightLevel(); + + state.SetLightIndex(-1); + state.SetRenderStyle(corona->RenderStyle); + state.SetTextureMode(corona->RenderStyle); + + state.SetMaterial(tex, UF_Sprite, CTF_Expand, CLAMP_XY_NOMIP, 0, 0); + + float scale = screen->GetHeight() / 1000.0f; + float tileWidth = corona->Scale.X * tex->GetDisplayWidth() * scale; + float tileHeight = corona->Scale.Y * tex->GetDisplayHeight() * scale; + float x0 = screenX - tileWidth, y0 = screenY - tileHeight; + float x1 = screenX + tileWidth, y1 = screenY + tileHeight; + + float u0 = 0.0f, v0 = 0.0f; + float u1 = 1.0f, v1 = 1.0f; + + auto vert = screen->mVertexData->AllocVertices(4); + auto vp = vert.first; + unsigned int vertexindex = vert.second; + + vp[0].Set(x0, y0, 1.0f, u0, v0); + vp[1].Set(x1, y0, 1.0f, u1, v0); + vp[2].Set(x0, y1, 1.0f, u0, v1); + vp[3].Set(x1, y1, 1.0f, u1, v1); + + state.Draw(DT_TriangleStrip, vertexindex, 4); +#endif +} + +//========================================================================== +// +// TraceCallbackForDitherTransparency +// Toggles dither flag on anything that occludes the actor's +// position from viewpoint. +// +//========================================================================== + +static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* userdata) +{ + int* count = (int*)userdata; + double bf, bc; + (*count)++; + switch(res.HitType) + { + case TRACE_HitWall: + if (!(res.Line->sidedef[res.Side]->Flags & WALLF_DITHERTRANS)) + { + bf = res.Line->sidedef[res.Side]->sector->floorplane.ZatPoint(res.HitPos.XY()); + bc = res.Line->sidedef[res.Side]->sector->ceilingplane.ZatPoint(res.HitPos.XY()); + if ((res.HitPos.Z <= bc) && (res.HitPos.Z >= bf)) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS; + } + break; + case TRACE_HitFloor: + res.Sector->floorplane.dithertransflag = true; + break; + case TRACE_HitCeiling: + res.Sector->ceilingplane.dithertransflag = true; + break; + case TRACE_HitActor: + default: + break; + } + + return TRACE_ContinueOutOfBounds; +} + + +void HWDrawInfo::SetDitherTransFlags(AActor* actor) +{ + if (actor && actor->Sector) + { + FTraceResults results; + double horix = Viewpoint.Sin * actor->radius; + double horiy = Viewpoint.Cos * actor->radius; + DVector3 actorpos = actor->Pos(); + DVector3 vvec = actorpos - Viewpoint.Pos; + if (Viewpoint.IsOrtho()) + { + vvec += Viewpoint.camera->Pos() - actorpos; + vvec *= 5.0; // Should be 4.0? (since zNear is behind screen by 3*dist in VREyeInfo::GetProjection()) + } + double distance = vvec.Length() - actor->radius; + DVector3 campos = actorpos - vvec; + sector_t* startsec; + int count = 0; + + vvec = vvec.Unit(); + campos.X -= horix; campos.Y += horiy; campos.Z += actor->Height * 0.25; + for (int iter = 0; iter < 3; iter++) + { + startsec = Level->PointInRenderSubsector(campos)->sector; + Trace(campos, startsec, vvec, distance, + 0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count); + campos.Z += actor->Height * 0.5; + Trace(campos, startsec, vvec, distance, + 0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count); + campos.Z -= actor->Height * 0.5; + campos.X += horix; campos.Y -= horiy; + } + } +} + +static ETraceStatus CheckForViewpointActor(FTraceResults& res, void* userdata) +{ + FRenderViewpoint* data = (FRenderViewpoint*)userdata; + if (res.HitType == TRACE_HitActor && res.Actor && res.Actor == data->ViewActor) + { + return TRACE_Skip; + } + + return TRACE_Stop; +} + + +void HWDrawInfo::DrawCoronas(FRenderState& state) +{ + state.EnableDepthTest(false); + state.SetDepthMask(false); + + HWViewpointUniforms vp = VPUniforms; + vp.mViewMatrix.loadIdentity(); + vp.mProjectionMatrix = VRMode::GetVRMode(true)->GetHUDSpriteProjection(); + screen->mViewpoints->SetViewpoint(state, &vp); + + float timeElapsed = (screen->FrameTime - LastFrameTime) / 1000.0f; + LastFrameTime = screen->FrameTime; + +#if 0 + for (ACorona* corona : Coronas) + { + auto cPos = corona->Vec3Offset(0., 0., corona->Height * 0.5); + DVector3 direction = Viewpoint.Pos - cPos; + double dist = direction.Length(); + + // skip coronas that are too far + if (dist > corona->RenderRadius()) + continue; + + static const float fadeSpeed = 9.0f; + + direction.MakeUnit(); + FTraceResults results; + if (!Trace(cPos, corona->Sector, direction, dist, MF_SOLID, ML_BLOCKEVERYTHING, corona, results, 0, CheckForViewpointActor, &Viewpoint)) + { + corona->CoronaFade = std::min(corona->CoronaFade + timeElapsed * fadeSpeed, 1.0f); + } + else + { + corona->CoronaFade = std::max(corona->CoronaFade - timeElapsed * fadeSpeed, 0.0f); + } + + if (corona->CoronaFade > 0.0f) + DrawCorona(state, corona, dist); + } +#endif + + state.SetTextureMode(TM_NORMAL); + screen->mViewpoints->Bind(state, vpIndex); + state.EnableDepthTest(true); + state.SetDepthMask(true); +} + + //----------------------------------------------------------------------------- // // Draws player sprites and color blend @@ -577,6 +818,11 @@ void HWDrawInfo::EndDrawScene(sector_t * viewsector, FRenderState &state) { state.EnableFog(false); + /*if (gl_coronas && Coronas.Size() > 0) + { + DrawCoronas(state); + }*/ + // [BB] HUD models need to be rendered here. const bool renderHUDModel = IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player); if (renderHUDModel) @@ -642,20 +888,88 @@ void HWDrawInfo::Set3DViewport(FRenderState &state) state.SetStencil(0, SOP_Keep, SF_AllOn); } +//----------------------------------------------------------------------------- +// +// gl_drawscene - this function renders the scene from the current +// viewpoint, including mirrors and skyboxes and other portals +// It is assumed that the HWPortal::EndFrame returns with the +// stencil, z-buffer and the projection matrix intact! +// +//----------------------------------------------------------------------------- + +void HWDrawInfo::DrawScene(int drawmode) +{ + static int recursion = 0; + static int ssao_portals_available = 0; + auto& vp = Viewpoint; + + bool applySSAO = false; + if (drawmode == DM_MAINVIEW) + { + ssao_portals_available = gl_ssao_portals; + applySSAO = true; + if (r_dithertransparency && vp.IsAllowedOoB()) + { + vp.camera->tracer ? SetDitherTransFlags(vp.camera->tracer) : SetDitherTransFlags(players[consoleplayer].mo); + } + } + else if (drawmode == DM_OFFSCREEN) + { + ssao_portals_available = 0; + } + else if (drawmode == DM_PORTAL && ssao_portals_available > 0) + { + applySSAO = (mCurrentPortal->AllowSSAO() || Level->flags3&LEVEL3_SKYBOXAO); + ssao_portals_available--; + } + + if (vp.camera != nullptr) + { + ActorRenderFlags savedflags = vp.camera->renderflags; + CreateScene(drawmode == DM_MAINVIEW); + vp.camera->renderflags = savedflags; + } + else + { + CreateScene(false); + } + auto& RenderState = *screen->RenderState(); + + RenderState.SetDepthMask(true); + if (!gl_no_skyclear) portalState.RenderFirstSkyPortal(recursion, this, RenderState); + + RenderScene(RenderState); + + if (applySSAO && RenderState.GetPassType() == GBUFFER_PASS) + { + screen->AmbientOccludeScene(VPUniforms.mProjectionMatrix.get()[5]); + screen->mViewpoints->Bind(RenderState, vpIndex); + } + + // Handle all portals after rendering the opaque objects but before + // doing all translucent stuff + recursion++; + portalState.EndFrame(this, RenderState); + recursion--; + RenderTranslucent(RenderState); +} + + //----------------------------------------------------------------------------- // // R_RenderView - renders one view - either the screen or a camera texture // //----------------------------------------------------------------------------- -void HWDrawInfo::ProcessScene(bool toscreen, const std::function &drawScene) +void HWDrawInfo::ProcessScene(bool toscreen) { - screen->mPortalState->BeginScene(); + portalState.BeginScene(); int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection; + if (Viewpoint.IsAllowedOoB()) + mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection; CurrentMapSections.Set(mapsection); - DrawScene = drawScene; - DrawScene(this, toscreen ? DM_MAINVIEW : DM_OFFSCREEN); + DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN); } @@ -670,7 +984,7 @@ void HWDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *ptg, subsector_t *sub) auto portal = FindPortal(ptg); if (!portal) { - portal = new HWSectorStackPortal(screen->mPortalState, ptg); + portal = new HWSectorStackPortal(&portalState, ptg); Portals.Push(portal); } auto ptl = static_cast(portal); diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index 1a81a4a949a..ce848e29710 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -29,6 +29,7 @@ class IShadowMap; struct particle_t; struct FDynLightData; struct HUDSprite; +class ACorona; class Clipper; class HWPortal; class FFlatVertexBuffer; @@ -145,11 +146,15 @@ struct HWDrawInfo HWPortal *mCurrentPortal; //FRotator mAngles; Clipper *mClipper; + Clipper *vClipper; // Vertical clipper + Clipper *rClipper; // Radar clipper FRenderViewpoint Viewpoint; HWViewpointUniforms VPUniforms; // per-viewpoint uniform state TArray Portals; TArray Decals[2]; // the second slot is for mirrors which get rendered in a separate pass. TArray hudsprites; // These may just be stored by value. + //TArray Coronas; + uint64_t LastFrameTime = 0; TArray MissingUpperTextures; TArray MissingLowerTextures; @@ -179,8 +184,6 @@ struct HWDrawInfo fixed_t viewx, viewy; // since the nodes are still fixed point, keeping the view position also fixed point for node traversal is faster. bool multithread; - std::function DrawScene = nullptr; - private: // For ProcessLowerMiniseg bool inview; @@ -199,7 +202,7 @@ struct HWDrawInfo void RenderPolyBSPNode(void *node); void AddPolyobjs(subsector_t *sub); void AddLines(subsector_t * sub, sector_t * sector); - void AddSpecialPortalLines(subsector_t * sub, sector_t * sector, line_t *line); + void AddSpecialPortalLines(subsector_t * sub, sector_t * sector, linebase_t *line); public: void RenderThings(subsector_t * sub, sector_t * sector); void RenderParticles(subsector_t *sub, sector_t *front); @@ -207,14 +210,10 @@ struct HWDrawInfo int SetupLightsForOtherPlane(subsector_t * sub, FDynLightData &lightdata, const secplane_t *plane); int CreateOtherPlaneVertices(subsector_t *sub, const secplane_t *plane); void DrawPSprite(HUDSprite *huds, FRenderState &state); - void SetColor(FRenderState &state, int sectorlightlevel, int rellight, bool fullbright, const FColormap &cm, float alpha, bool weapon = false); - void SetFog(FRenderState &state, int lightlevel, int rellight, bool fullbright, const FColormap *cmap, bool isadditive); - void SetShaderLight(FRenderState &state, float level, float olight); - int CalcLightLevel(int lightlevel, int rellight, bool weapon, int blendfactor); - PalEntry CalcLightColor(int light, PalEntry pe, int blendfactor); - float GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor); - bool CheckFog(sector_t *frontsector, sector_t *backsector); WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &pos, int cm, area_t in_area, const DVector3 &playerpos); + + void PreparePlayerSprites2D(sector_t * viewsector, area_t in_area); + void PreparePlayerSprites3D(sector_t * viewsector, area_t in_area); public: void SetCameraPos(const DVector3 &pos) @@ -237,6 +236,7 @@ struct HWDrawInfo HWPortal * FindPortal(const void * src); void RenderBSPNode(void *node); + void RenderOrthoNoFog(); void RenderBSP(void *node, bool drawpsprites); static HWDrawInfo *StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms); @@ -246,6 +246,7 @@ struct HWDrawInfo void SetViewArea(); int SetFullbrightFlags(player_t *player); + void DrawScene(int drawmode); void CreateScene(bool drawpsprites); void RenderScene(FRenderState &state); void RenderTranslucent(FRenderState &state); @@ -253,7 +254,7 @@ struct HWDrawInfo void EndDrawScene(sector_t * viewsector, FRenderState &state); void DrawEndScene2D(sector_t * viewsector, FRenderState &state); void Set3DViewport(FRenderState &state); - void ProcessScene(bool toscreen, const std::function &drawScene); + void ProcessScene(bool toscreen); bool DoOneSectorUpper(subsector_t * subsec, float planez, area_t in_area); bool DoOneSectorLower(subsector_t * subsec, float planez, area_t in_area); @@ -292,7 +293,7 @@ struct HWDrawInfo void GetDynSpriteLight(AActor *thing, particle_t *particle, float *out); void PreparePlayerSprites(sector_t * viewsector, area_t in_area); - void PrepareTargeterSprites(); + void PrepareTargeterSprites(double ticfrac); void UpdateCurrentMapSection(); void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror); @@ -301,6 +302,10 @@ struct HWDrawInfo void DrawDecals(FRenderState &state, TArray &decals); void DrawPlayerSprites(bool hudModelStep, FRenderState &state); + void DrawCoronas(FRenderState& state); + void DrawCorona(FRenderState& state, ACorona* corona, double dist); + + void SetDitherTransFlags(AActor* actor); void ProcessLowerMinisegs(TArray &lowersegs); void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub); @@ -313,16 +318,6 @@ struct HWDrawInfo HWDecal *AddDecal(bool onmirror); - bool isSoftwareLighting() const - { - return lightmode >= ELightMode::ZDoomSoftware; - } - - bool isDarkLightMode() const - { - return !!((int)lightmode & (int)ELightMode::Doom); - } - void SetFallbackLightMode() { lightmode = ELightMode::Doom; @@ -330,3 +325,36 @@ struct HWDrawInfo }; +void CleanSWDrawer(); +sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen); +void WriteSavePic(player_t* player, FileWriter* file, int width, int height); +sector_t* RenderView(player_t* player); + + +inline bool isSoftwareLighting(ELightMode lightmode) +{ + return lightmode == ELightMode::ZDoomSoftware || lightmode == ELightMode::DoomSoftware || lightmode == ELightMode::Build; +} + +inline bool isBuildSoftwareLighting(ELightMode lightmode) +{ + return lightmode == ELightMode::Build; +} + +inline bool isDoomSoftwareLighting(ELightMode lightmode) +{ + return lightmode == ELightMode::ZDoomSoftware || lightmode == ELightMode::DoomSoftware; +} + +inline bool isDarkLightMode(ELightMode lightmode) +{ + return lightmode == ELightMode::Doom || lightmode == ELightMode::DoomDark; +} + +int CalcLightLevel(ELightMode lightmode, int lightlevel, int rellight, bool weapon, int blendfactor); +PalEntry CalcLightColor(ELightMode lightmode, int light, PalEntry pe, int blendfactor); +float GetFogDensity(FLevelLocals* Level, ELightMode lightmode, int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor); +bool CheckFog(FLevelLocals* Level, sector_t* frontsector, sector_t* backsector, ELightMode lightmode); +void SetColor(FRenderState& state, FLevelLocals* Level, ELightMode lightmode, int sectorlightlevel, int rellight, bool fullbright, const FColormap& cm, float alpha, bool weapon = false); +void SetShaderLight(FRenderState& state, FLevelLocals* Level, float level, float olight); +void SetFog(FRenderState& state, FLevelLocals* Level, ELightMode lightmode, int lightlevel, int rellight, bool fullbright, const FColormap* cmap, bool isadditive); diff --git a/src/rendering/hwrenderer/scene/hw_drawlist.cpp b/src/rendering/hwrenderer/scene/hw_drawlist.cpp index 37ff4006be2..26f64f04d3e 100644 --- a/src/rendering/hwrenderer/scene/hw_drawlist.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawlist.cpp @@ -32,11 +32,12 @@ #include "g_levellocals.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawlist.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/utility/hw_clock.h" +#include "flatvertices.h" +#include "hw_clock.h" #include "hw_renderstate.h" #include "hw_drawinfo.h" #include "hw_fakeflat.h" +#include "hw_walldispatcher.h" FMemArena RenderDataAllocator(1024*1024); // Use large blocks to reduce allocation time. @@ -268,7 +269,7 @@ void HWDrawList::SortPlaneIntoPlane(SortNode * head,SortNode * sort) // // //========================================================================== -void HWDrawList::SortWallIntoPlane(SortNode * head, SortNode * sort) +void HWDrawList::SortWallIntoPlane(HWDrawInfo* di, SortNode * head, SortNode * sort) { HWFlat * fh = flats[drawitems[head->itemindex].index]; HWWall * ws = walls[drawitems[sort->itemindex].index]; @@ -287,6 +288,7 @@ void HWDrawList::SortWallIntoPlane(SortNode * head, SortNode * sort) { ws->vertcount = 0; // invalidate current vertices. float newtexv = ws->tcs[HWWall::UPLFT].v + ((ws->tcs[HWWall::LOLFT].v - ws->tcs[HWWall::UPLFT].v) / (ws->zbottom[0] - ws->ztop[0])) * (fh->z - ws->ztop[0]); + float newlmv = ws->lightuv[HWWall::UPLFT].v + ((ws->lightuv[HWWall::LOLFT].v - ws->lightuv[HWWall::UPLFT].v) / (ws->zbottom[0] - ws->ztop[0])) * (fh->z - ws->ztop[0]); // I make the very big assumption here that translucent walls in sloped sectors // and 3D-floors never coexist in the same level - If that were the case this @@ -295,12 +297,16 @@ void HWDrawList::SortWallIntoPlane(SortNode * head, SortNode * sort) { ws->ztop[1] = w->zbottom[1] = ws->ztop[0] = w->zbottom[0] = fh->z; ws->tcs[HWWall::UPRGT].v = w->tcs[HWWall::LORGT].v = ws->tcs[HWWall::UPLFT].v = w->tcs[HWWall::LOLFT].v = newtexv; + ws->lightuv[HWWall::UPRGT].v = w->lightuv[HWWall::LORGT].v = ws->lightuv[HWWall::UPLFT].v = w->lightuv[HWWall::LOLFT].v = newlmv; } else { w->ztop[1] = ws->zbottom[1] = w->ztop[0] = ws->zbottom[0] = fh->z; w->tcs[HWWall::UPLFT].v = ws->tcs[HWWall::LOLFT].v = w->tcs[HWWall::UPRGT].v = ws->tcs[HWWall::LORGT].v = newtexv; + w->lightuv[HWWall::UPLFT].v = ws->lightuv[HWWall::LOLFT].v = w->lightuv[HWWall::UPRGT].v = ws->lightuv[HWWall::LORGT].v = newlmv; } + w->MakeVertices(false); + ws->MakeVertices(false); } SortNode * sort2 = SortNodes.GetNew(); @@ -431,6 +437,7 @@ void HWDrawList::SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sor float ix=(float)(ws->glseg.x1+r*(ws->glseg.x2-ws->glseg.x1)); float iy=(float)(ws->glseg.y1+r*(ws->glseg.y2-ws->glseg.y1)); float iu=(float)(ws->tcs[HWWall::UPLFT].u + r * (ws->tcs[HWWall::UPRGT].u - ws->tcs[HWWall::UPLFT].u)); + float ilmu=(float)(ws->lightuv[HWWall::UPLFT].u + r * (ws->lightuv[HWWall::UPRGT].u - ws->lightuv[HWWall::UPLFT].u)); float izt=(float)(ws->ztop[0]+r*(ws->ztop[1]-ws->ztop[0])); float izb=(float)(ws->zbottom[0]+r*(ws->zbottom[1]-ws->zbottom[0])); @@ -444,8 +451,9 @@ void HWDrawList::SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sor w->ztop[0]=ws->ztop[1]=izt; w->zbottom[0]=ws->zbottom[1]=izb; w->tcs[HWWall::LOLFT].u = w->tcs[HWWall::UPLFT].u = ws->tcs[HWWall::LORGT].u = ws->tcs[HWWall::UPRGT].u = iu; - ws->MakeVertices(di, false); - w->MakeVertices(di, false); + w->lightuv[HWWall::LOLFT].u = w->lightuv[HWWall::UPLFT].u = ws->lightuv[HWWall::LORGT].u = ws->lightuv[HWWall::UPRGT].u = iu; + ws->MakeVertices(false); + w->MakeVertices(false); SortNode * sort2=SortNodes.GetNew(); memset(sort2,0,sizeof(SortNode)); @@ -472,6 +480,7 @@ void HWDrawList::SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sor //========================================================================== EXTERN_CVAR(Int, gl_billboard_mode) EXTERN_CVAR(Bool, gl_billboard_faces_camera) +EXTERN_CVAR(Bool, hw_force_cambbpref) EXTERN_CVAR(Bool, gl_billboard_particles) inline double CalcIntersectionVertex(HWSprite *s, HWWall * w2) @@ -515,7 +524,10 @@ void HWDrawList::SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * s const bool drawWithXYBillboard = ((ss->particle && gl_billboard_particles) || (!(ss->actor && ss->actor->renderflags & RF_FORCEYBILLBOARD) && (gl_billboard_mode == 1 || (ss->actor && ss->actor->renderflags & RF_FORCEXYBILLBOARD)))); - const bool drawBillboardFacingCamera = gl_billboard_faces_camera; + const bool drawBillboardFacingCamera = hw_force_cambbpref ? gl_billboard_faces_camera : + (gl_billboard_faces_camera && (ss->actor && !(ss->actor->renderflags2 & RF2_BILLBOARDNOFACECAMERA))) + || (ss->actor && ss->actor->renderflags2 & RF2_BILLBOARDFACECAMERA); + // [Nash] has +ROLLSPRITE const bool rotated = (ss->actor != nullptr && ss->actor->renderflags & (RF_ROLLSPRITE | RF_WALLSPRITE | RF_FLATSPRITE)); @@ -647,7 +659,7 @@ SortNode * HWDrawList::DoSort(HWDrawInfo *di, SortNode * head) break; case DrawType_WALL: - SortWallIntoPlane(head,node); + SortWallIntoPlane(di,head,node); break; case DrawType_SPRITE: @@ -722,7 +734,7 @@ void HWDrawList::SortWalls() HWWall * w1 = walls[a.index]; HWWall * w2 = walls[b.index]; - if (w1->gltexture != w2->gltexture) return w1->gltexture < w2->gltexture; + if (w1->texture != w2->texture) return w1->texture < w2->texture; return (w1->flags & 3) < (w2->flags & 3); }); @@ -737,7 +749,7 @@ void HWDrawList::SortFlats() { HWFlat * w1 = flats[a.index]; HWFlat* w2 = flats[b.index]; - return w1->gltexture < w2->gltexture; + return w1->texture < w2->texture; }); } } @@ -801,8 +813,9 @@ void HWDrawList::DoDraw(HWDrawInfo *di, FRenderState &state, bool translucent, i case DrawType_WALL: { HWWall * w= walls[drawitems[i].index]; + HWWallDispatcher dis(di); RenderWall.Clock(); - w->DrawWall(di, state, translucent); + w->DrawWall(&dis, state, translucent); RenderWall.Unclock(); } break; @@ -838,10 +851,11 @@ void HWDrawList::Draw(HWDrawInfo *di, FRenderState &state, bool translucent) //========================================================================== void HWDrawList::DrawWalls(HWDrawInfo *di, FRenderState &state, bool translucent) { + HWWallDispatcher dis(di); RenderWall.Clock(); for (auto &item : drawitems) { - walls[item.index]->DrawWall(di, state, translucent); + walls[item.index]->DrawWall(&dis, state, translucent); } RenderWall.Unclock(); } diff --git a/src/rendering/hwrenderer/scene/hw_drawlist.h b/src/rendering/hwrenderer/scene/hw_drawlist.h index eaa0c471c25..ee00ad91bbc 100644 --- a/src/rendering/hwrenderer/scene/hw_drawlist.h +++ b/src/rendering/hwrenderer/scene/hw_drawlist.h @@ -31,6 +31,7 @@ struct HWDrawItem HWDrawItemType rendertype; int index; + HWDrawItem() = default; // we need this for dynamic arrays. HWDrawItem(HWDrawItemType _rendertype,int _index) : rendertype(_rendertype),index(_index) {} }; @@ -99,7 +100,7 @@ struct HWDrawList SortNode * FindSortPlane(SortNode * head); SortNode * FindSortWall(SortNode * head); void SortPlaneIntoPlane(SortNode * head,SortNode * sort); - void SortWallIntoPlane(SortNode * head,SortNode * sort); + void SortWallIntoPlane(HWDrawInfo* di, SortNode * head,SortNode * sort); void SortSpriteIntoPlane(SortNode * head,SortNode * sort); void SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort); void SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort); diff --git a/src/rendering/hwrenderer/scene/hw_drawlistadd.cpp b/src/rendering/hwrenderer/scene/hw_drawlistadd.cpp index 167802b95dc..dc0cd210d1b 100644 --- a/src/rendering/hwrenderer/scene/hw_drawlistadd.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawlistadd.cpp @@ -20,12 +20,14 @@ //-------------------------------------------------------------------------- // -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" +#include "hw_dynlightdata.h" +#include "hw_cvars.h" +#include "hw_lightbuffer.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawinfo.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_material.h" +#include "actor.h" +#include "g_levellocals.h" EXTERN_CVAR(Bool, gl_seamless) @@ -44,10 +46,10 @@ void HWDrawInfo::AddWall(HWWall *wall) } else { - bool masked = HWWall::passflag[wall->type] == 1 ? false : (wall->gltexture && wall->gltexture->isMasked()); + bool masked = HWWall::passflag[wall->type] == 1 ? false : (wall->texture && wall->texture->isMasked()); int list; - if ((wall->flags & HWWall::HWF_SKYHACK && wall->type == RENDERWALL_M2S)) + if (wall->flags & HWWall::HWF_SKYHACK && wall->type == RENDERWALL_M2S) { list = GLDL_MASKEDWALLSOFS; } @@ -79,8 +81,15 @@ void HWDrawInfo::AddMirrorSurface(HWWall *w) auto tcs = newwall->tcs; tcs[HWWall::LOLFT].u = tcs[HWWall::LORGT].u = tcs[HWWall::UPLFT].u = tcs[HWWall::UPRGT].u = v.X; tcs[HWWall::LOLFT].v = tcs[HWWall::LORGT].v = tcs[HWWall::UPLFT].v = tcs[HWWall::UPRGT].v = v.Z; - newwall->MakeVertices(this, false); + newwall->MakeVertices(false); + + bool hasDecals = newwall->seg->sidedef && newwall->seg->sidedef->AttachedDecals; + if (hasDecals && Level->HasDynamicLights && !isFullbrightScene()) + { + newwall->SetupLights(this, lightdata); + } newwall->ProcessDecals(this); + newwall->dynlightindex = -1; // the environment map should not be affected by lights - only the decals. } //========================================================================== @@ -96,12 +105,12 @@ void HWDrawInfo::AddFlat(HWFlat *flat, bool fog) { int list; - if (flat->renderstyle != STYLE_Translucent || flat->alpha < 1.f - FLT_EPSILON || fog || flat->gltexture == nullptr) + if (flat->renderstyle != STYLE_Translucent || flat->alpha < 1.f - FLT_EPSILON || fog || flat->texture == nullptr) { // translucent 3D floors go into the regular translucent list, translucent portals go into the translucent border list. list = (flat->renderflags&SSRF_RENDER3DPLANES) ? GLDL_TRANSLUCENT : GLDL_TRANSLUCENTBORDER; } - else if (flat->gltexture->tex->GetTranslucency()) + else if (flat->texture->GetTranslucency()) { if (flat->stack) { @@ -118,7 +127,7 @@ void HWDrawInfo::AddFlat(HWFlat *flat, bool fog) } else //if (flat->hacktype != SSRF_FLOODHACK) // The flood hack may later need different treatment but with the current setup can go into the existing render list. { - bool masked = flat->gltexture->isMasked() && ((flat->renderflags&SSRF_RENDER3DPLANES) || flat->stack); + bool masked = flat->texture->isMasked() && ((flat->renderflags&SSRF_RENDER3DPLANES) || flat->stack); list = masked ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS; } auto newflat = drawlists[list].NewFlat(); diff --git a/src/rendering/hwrenderer/scene/hw_drawstructs.h b/src/rendering/hwrenderer/scene/hw_drawstructs.h index 4c973084407..b364128de4b 100644 --- a/src/rendering/hwrenderer/scene/hw_drawstructs.h +++ b/src/rendering/hwrenderer/scene/hw_drawstructs.h @@ -5,14 +5,16 @@ // //========================================================================== #include "r_defs.h" -#include "r_data/renderstyle.h" -#include "textures/textures.h" +#include "renderstyle.h" +#include "textures.h" #include "r_data/colormaps.h" #ifdef _MSC_VER #pragma warning(disable:4244) #endif +bool CheckFog(FLevelLocals* Level, sector_t* frontsector, sector_t* backsector, ELightMode lightmode); + struct HWHorizonInfo; struct HWSkyInfo; struct F3DFloor; @@ -84,7 +86,7 @@ struct HWSectorPlane Offs.Y = (float)sec->GetYOffset(ceiling); Scale.X = (float)sec->GetXScale(ceiling); Scale.Y = (float)sec->GetYScale(ceiling); - Angle = (float)sec->GetAngle(ceiling).Degrees; + Angle = (float)sec->GetAngle(ceiling).Degrees(); texture = sec->GetTexture(ceiling); plane = sec->GetSecPlane(ceiling); Texheight = (float)((ceiling == sector_t::ceiling)? plane.fD() : -plane.fD()); @@ -113,6 +115,11 @@ struct texcoord }; struct HWDrawInfo; +class HWWall; + +// this only exists to keep HWWallDispatcher trivial + +struct HWWallDispatcher; class HWWall { @@ -121,14 +128,15 @@ class HWWall enum { - HWF_CLAMPX=1, - HWF_CLAMPY=2, - HWF_SKYHACK=4, - HWF_GLOW=8, // illuminated by glowing flats - HWF_NOSPLITUPPER=16, - HWF_NOSPLITLOWER=32, - HWF_NOSPLIT=64, - HWF_TRANSLUCENT = 128 + HWF_CLAMPX = 1, + HWF_CLAMPY = 2, + HWF_SKYHACK = 4, + HWF_GLOW = 8, // illuminated by glowing flats + HWF_NOSPLITUPPER = 16, + HWF_NOSPLITLOWER = 32, + HWF_NOSPLIT = 64, + HWF_TRANSLUCENT = 128, + HWF_NOSLICE = 256 }; enum @@ -150,23 +158,26 @@ class HWWall friend struct HWDrawList; friend class HWPortal; - vertex_t * vertexes[2]; // required for polygon splitting - FMaterial *gltexture; - TArray *lightlist; + vertex_t* vertexes[2]; // required for polygon splitting + FGameTexture* texture; + TArray* lightlist; + LightmapSurface* lightmap; HWSeg glseg; - float ztop[2],zbottom[2]; + float ztop[2], zbottom[2]; texcoord tcs[4]; + texcoord lightuv[4]; + float lindex; float alpha; FColormap Colormap; ERenderStyle RenderStyle; - + float ViewDistance; - int lightlevel; + short lightlevel; + uint16_t flags; uint8_t type; - uint8_t flags; short rellight; float topglowcolor[4]; @@ -177,12 +188,17 @@ class HWWall union { // it's either one of them but never more! - FSectorPortal *secportal; // sector portal (formerly skybox) - HWSkyInfo * sky; // for normal sky - HWHorizonInfo * horizon; // for horizon information - FSectorPortalGroup * portal; // stacked sector portals - secplane_t * planemirror; // for plane mirrors - FLinePortalSpan *lineportal; // line-to-line portals + FSectorPortal* secportal; // sector portal (formerly skybox) + HWSkyInfo* sky; // for normal sky + HWHorizonInfo* horizon; // for horizon information + FSectorPortalGroup* portal; // stacked sector portals + secplane_t* planemirror; // for plane mirrors + FLinePortalSpan* lineportal; // line-to-line portals + struct + { + int portaltype; // for the mesh builder. Real portals can only be assigned when being rendered. + int portalplane; + }; }; @@ -195,92 +211,92 @@ class HWWall unsigned int vertcount; public: - seg_t * seg; // this gives the easiest access to all other structs involved - subsector_t * sub; // For polyobjects - sector_t *frontsector, *backsector; -//private: - - void PutWall(HWDrawInfo *di, bool translucent); - void PutPortal(HWDrawInfo *di, int ptype, int plane); - void CheckTexturePosition(FTexCoordInfo *tci); - - void Put3DWall(HWDrawInfo *di, lightlist_t * lightlist, bool translucent); - bool SplitWallComplex(HWDrawInfo *di, sector_t * frontsector, bool translucent, float& maplightbottomleft, float& maplightbottomright); - void SplitWall(HWDrawInfo *di, sector_t * frontsector, bool translucent); - - void SetupLights(HWDrawInfo *di, FDynLightData &lightdata); - - void MakeVertices(HWDrawInfo *di, bool nosplit); - - void SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowmirror); - void SkyLine(HWDrawInfo *di, sector_t *sec, line_t *line); - void SkyNormal(HWDrawInfo *di, sector_t * fs,vertex_t * v1,vertex_t * v2); - void SkyTop(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2); - void SkyBottom(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2); - - bool DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2); - - bool SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float ceilingrefheight, - float topleft, float topright, float bottomleft, float bottomright, float t_ofs); - - void DoTexture(HWDrawInfo *di, int type,seg_t * seg,int peg, - float ceilingrefheight, float floorrefheight, - float CeilingHeightstart,float CeilingHeightend, - float FloorHeightstart,float FloorHeightend, - float v_offset); - - void DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, - sector_t * front, sector_t * back, - sector_t * realfront, sector_t * realback, - float fch1, float fch2, float ffh1, float ffh2, - float bch1, float bch2, float bfh1, float bfh2); - - void GetPlanePos(F3DFloor::planeref * planeref, float & left, float & right); - - void BuildFFBlock(HWDrawInfo *di, seg_t * seg, F3DFloor * rover, - float ff_topleft, float ff_topright, - float ff_bottomleft, float ff_bottomright); - void InverseFloors(HWDrawInfo *di, seg_t * seg, sector_t * frontsector, - float topleft, float topright, - float bottomleft, float bottomright); - void ClipFFloors(HWDrawInfo *di, seg_t * seg, F3DFloor * ffloor, sector_t * frontsector, - float topleft, float topright, - float bottomleft, float bottomright); - void DoFFloorBlocks(HWDrawInfo *di, seg_t * seg, sector_t * frontsector, sector_t * backsector, - float fch1, float fch2, float ffh1, float ffh2, - float bch1, float bch2, float bfh1, float bfh2); - - void ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &normal); - void ProcessDecals(HWDrawInfo *di); - - int CreateVertices(FFlatVertex *&ptr, bool nosplit); - void SplitLeftEdge (FFlatVertex *&ptr); - void SplitRightEdge(FFlatVertex *&ptr); - void SplitUpperEdge(FFlatVertex *&ptr); - void SplitLowerEdge(FFlatVertex *&ptr); - - void CountLeftEdge (unsigned &ptr); - void CountRightEdge(unsigned &ptr); + seg_t* seg; // this gives the easiest access to all other structs involved + subsector_t* sub; // For polyobjects + sector_t* frontsector, * backsector; + //private: + + void PutWall(HWWallDispatcher* di, bool translucent); + void PutPortal(HWWallDispatcher* di, int ptype, int plane); + void CheckTexturePosition(FTexCoordInfo* tci); + + void Put3DWall(HWWallDispatcher* di, lightlist_t* lightlist, bool translucent); + bool SplitWallComplex(HWWallDispatcher* di, sector_t* frontsector, bool translucent, float& maplightbottomleft, float& maplightbottomright); + void SplitWall(HWWallDispatcher* di, sector_t* frontsector, bool translucent); + + void SetupLights(HWDrawInfo* di, FDynLightData& lightdata); + + void MakeVertices(bool nosplit); + + void SkyPlane(HWWallDispatcher* di, sector_t* sector, int plane, bool allowmirror); + void SkyLine(HWWallDispatcher* di, sector_t* sec, line_t* line); + void SkyNormal(HWWallDispatcher* di, sector_t* fs, vertex_t* v1, vertex_t* v2); + void SkyTop(HWWallDispatcher* di, seg_t* seg, sector_t* fs, sector_t* bs, vertex_t* v1, vertex_t* v2); + void SkyBottom(HWWallDispatcher* di, seg_t* seg, sector_t* fs, sector_t* bs, vertex_t* v1, vertex_t* v2); + + bool DoHorizon(HWWallDispatcher* di, seg_t* seg, sector_t* fs, vertex_t* v1, vertex_t* v2); + + bool SetWallCoordinates(seg_t* seg, FTexCoordInfo* tci, float ceilingrefheight, + float topleft, float topright, float bottomleft, float bottomright, float t_ofs, float skew); + + void DoTexture(HWWallDispatcher* di, int type, seg_t* seg, int peg, + float ceilingrefheight, float floorrefheight, + float CeilingHeightstart, float CeilingHeightend, + float FloorHeightstart, float FloorHeightend, + float v_offset, float skew); + + void DoMidTexture(HWWallDispatcher* di, seg_t* seg, bool drawfogboundary, + sector_t* front, sector_t* back, + sector_t* realfront, sector_t* realback, + float fch1, float fch2, float ffh1, float ffh2, + float bch1, float bch2, float bfh1, float bfh2, float zalign, float skew); + + void GetPlanePos(F3DFloor::planeref* planeref, float& left, float& right); + + void BuildFFBlock(HWWallDispatcher* di, seg_t* seg, F3DFloor* rover, int roverIndex, + float ff_topleft, float ff_topright, + float ff_bottomleft, float ff_bottomright); + void InverseFloors(HWWallDispatcher* di, seg_t* seg, sector_t* frontsector, + float topleft, float topright, + float bottomleft, float bottomright); + void ClipFFloors(HWWallDispatcher* di, seg_t* seg, F3DFloor* ffloor, int ffloorIndex, sector_t* frontsector, + float topleft, float topright, + float bottomleft, float bottomright); + void DoFFloorBlocks(HWWallDispatcher* di, seg_t* seg, sector_t* frontsector, sector_t* backsector, + float fch1, float fch2, float ffh1, float ffh2, + float bch1, float bch2, float bfh1, float bfh2); + + void ProcessDecal(HWDrawInfo* di, DBaseDecal* decal, const FVector3& normal); + void ProcessDecals(HWDrawInfo* di); + + int CreateVertices(FFlatVertex*& ptr, bool nosplit); + void SplitLeftEdge(FFlatVertex*& ptr); + void SplitRightEdge(FFlatVertex*& ptr); + void SplitUpperEdge(FFlatVertex*& ptr); + void SplitLowerEdge(FFlatVertex*& ptr); + + void CountLeftEdge(unsigned& ptr); + void CountRightEdge(unsigned& ptr); int CountVertices(); - void RenderWall(HWDrawInfo *di, FRenderState &state, int textured); - void RenderFogBoundary(HWDrawInfo *di, FRenderState &state); - void RenderMirrorSurface(HWDrawInfo *di, FRenderState &state); - void RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags); - void RenderTranslucentWall(HWDrawInfo *di, FRenderState &state); - void DrawDecalsForMirror(HWDrawInfo *di, FRenderState &state, TArray &decals); + void RenderWall(FRenderState& state, int textured); + void RenderFogBoundary(HWWallDispatcher* di, FRenderState& state); + void RenderMirrorSurface(HWWallDispatcher* di, FRenderState& state); + void RenderTexturedWall(HWWallDispatcher* di, FRenderState& state, int rflags); + void RenderTranslucentWall(HWWallDispatcher* di, FRenderState& state); + void DrawDecalsForMirror(HWDrawInfo* di, FRenderState& state, TArray& decals); public: - void Process(HWDrawInfo *di, seg_t *seg, sector_t *frontsector, sector_t *backsector); - void ProcessLowerMiniseg(HWDrawInfo *di, seg_t *seg, sector_t *frontsector, sector_t *backsector); + void Process(HWWallDispatcher* di, seg_t* seg, sector_t* frontsector, sector_t* backsector); + void ProcessLowerMiniseg(HWWallDispatcher* di, seg_t* seg, sector_t* frontsector, sector_t* backsector); - float PointOnSide(float x,float y) + float PointOnSide(float x, float y) { - return -((y-glseg.y1)*(glseg.x2-glseg.x1)-(x-glseg.x1)*(glseg.y2-glseg.y1)); + return -((y - glseg.y1) * (glseg.x2 - glseg.x1) - (x - glseg.x1) * (glseg.y2 - glseg.y1)); } - void DrawWall(HWDrawInfo *di, FRenderState &state, bool translucent); + void DrawWall(HWWallDispatcher* di, FRenderState& state, bool translucent); }; @@ -295,7 +311,7 @@ class HWFlat public: sector_t * sector; FSection *section; - FMaterial *gltexture; + FGameTexture *texture; TextureManipulation* TextureFx; float z; // the z position of the flat (only valid for non-sloped planes) @@ -349,10 +365,11 @@ class HWSprite PalEntry ThingColor; // thing's own color FColormap Colormap; FSpriteModelFrame * modelframe; + int modelframeflags; FRenderStyle RenderStyle; int OverrideShader; - int translation; + FTranslationID translation; int index; float depth; int vertexindex; @@ -366,15 +383,17 @@ class HWSprite float vt,vb; float x1,y1,z1; float x2,y2,z2; + float offx, offy; float trans; int dynlightindex; - FMaterial *gltexture; + FGameTexture *texture; AActor * actor; particle_t * particle; TArray *lightlist; DRotator Angles; + bool nomipmap; // force the sprite to have no mipmaps (ensures tiny sprites in the distance stay crisp) void SplitSprite(HWDrawInfo *di, sector_t * frontsector, bool translucent); void PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, float spriteheight); @@ -384,8 +403,9 @@ class HWSprite void CreateVertices(HWDrawInfo *di); void PutSprite(HWDrawInfo *di, bool translucent); - void Process(HWDrawInfo *di, AActor* thing,sector_t * sector, area_t in_area, int thruportal = false); - void ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *sector);//, int shade, int fakeside) + void Process(HWDrawInfo *di, AActor* thing,sector_t * sector, area_t in_area, int thruportal = false, bool isSpriteShadow = false); + void ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *sector, class DVisualThinker *spr);//, int shade, int fakeside) + void AdjustVisualThinker(HWDrawInfo *di, DVisualThinker *spr, sector_t *sector); void DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent); }; @@ -401,7 +421,7 @@ struct DecalVertex struct HWDecal { - FMaterial *gltexture; + FGameTexture *texture; TArray *lightlist; DBaseDecal *decal; DecalVertex dv[4]; @@ -413,6 +433,7 @@ struct HWDecal int rellight; float alpha; FColormap Colormap; + int dynlightindex; sector_t *frontsector; FVector3 Normal; @@ -426,7 +447,14 @@ inline float Dist2(float x1,float y1,float x2,float y2) return sqrtf((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } -bool hw_SetPlaneTextureRotation(const HWSectorPlane * secplane, FMaterial * gltexture, VSMatrix &mat); +bool hw_SetPlaneTextureRotation(const HWSectorPlane * secplane, FGameTexture * gltexture, VSMatrix &mat); void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata); +LightProbe* FindLightProbe(FLevelLocals* level, float x, float y, float z); extern const float LARGE_VALUE; + +struct FDynLightData; +struct FDynamicLight; +bool GetLight(FDynLightData& dld, int group, Plane& p, FDynamicLight* light, bool checkside); +void AddLightToList(FDynLightData &dld, int group, FDynamicLight* light, bool forceAttenuate); +void SetSplitPlanes(FRenderState& state, const secplane_t& top, const secplane_t& bottom); diff --git a/src/rendering/hwrenderer/scene/hw_fakeflat.cpp b/src/rendering/hwrenderer/scene/hw_fakeflat.cpp index b37d8b67f03..d56e9926e37 100644 --- a/src/rendering/hwrenderer/scene/hw_fakeflat.cpp +++ b/src/rendering/hwrenderer/scene/hw_fakeflat.cpp @@ -33,8 +33,9 @@ #include "r_sky.h" #include "hw_fakeflat.h" #include "hw_drawinfo.h" -#include "hwrenderer/utility/hw_cvars.h" +#include "hw_cvars.h" #include "r_utility.h" +#include "texturemanager.h" static sector_t **fakesectorbuffer; @@ -117,7 +118,7 @@ bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto // now check for closed sectors! if (bs_ceilingheight1 <= fs_floorheight1 && bs_ceilingheight2 <= fs_floorheight2) { - FTexture * tex = TexMan.GetTexture(sidedef->GetTexture(side_t::top), true); + auto tex = TexMan.GetGameTexture(sidedef->GetTexture(side_t::top), true); if (!tex || !tex->isValid()) return false; if (backsector->GetTexture(sector_t::ceiling) == skyflatnum && frontsector->GetTexture(sector_t::ceiling) == skyflatnum) return false; @@ -126,7 +127,7 @@ bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto if (fs_ceilingheight1 <= bs_floorheight1 && fs_ceilingheight2 <= bs_floorheight2) { - FTexture * tex = TexMan.GetTexture(sidedef->GetTexture(side_t::bottom), true); + auto tex = TexMan.GetGameTexture(sidedef->GetTexture(side_t::bottom), true); if (!tex || !tex->isValid()) return false; // properly render skies (consider door "open" if both floors are sky): @@ -140,12 +141,12 @@ bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto // preserve a kind of transparent door/lift special effect: if (bs_ceilingheight1 < fs_ceilingheight1 || bs_ceilingheight2 < fs_ceilingheight2) { - FTexture * tex = TexMan.GetTexture(sidedef->GetTexture(side_t::top), true); + auto tex = TexMan.GetGameTexture(sidedef->GetTexture(side_t::top), true); if (!tex || !tex->isValid()) return false; } if (bs_floorheight1 > fs_floorheight1 || bs_floorheight2 > fs_floorheight2) { - FTexture * tex = TexMan.GetTexture(sidedef->GetTexture(side_t::bottom), true); + auto tex = TexMan.GetGameTexture(sidedef->GetTexture(side_t::bottom), true); if (!tex || !tex->isValid()) return false; } if (backsector->GetTexture(sector_t::ceiling) == skyflatnum && @@ -223,9 +224,9 @@ sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *loca if (fakesectorbuffer && fakesectorbuffer[sec->sectornum]) return fakesectorbuffer[sec->sectornum]; auto dest = localcopy? localcopy : allocateSector(sec); *dest = *sec; - dest->ceilingplane = sec->floorplane; - dest->ceilingplane.FlipVert(); - dest->planes[sector_t::ceiling].TexZ = dest->planes[sector_t::floor].TexZ; + dest->floorplane = sec->ceilingplane; + dest->floorplane.FlipVert(); + dest->planes[sector_t::floor].TexZ = dest->planes[sector_t::ceiling].TexZ; dest->ClearPortal(sector_t::ceiling); dest->ClearPortal(sector_t::floor); return dest; @@ -265,7 +266,8 @@ sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *loca dest->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false); dest->SetPlaneTexZQuick(sector_t::floor, s->GetPlaneTexZ(sector_t::floor)); dest->iboindex[sector_t::floor] = sec->iboindex[sector_t::vbo_fakefloor]; - dest->vboheight[sector_t::floor] = s->vboheight[sector_t::floor]; + for (int n = 0; n < screen->mPipelineNbr; n++) + dest->vboheight[n][sector_t::floor] = s->vboheight[n][sector_t::floor]; } else if (s->MoreFlags & SECMF_FAKEFLOORONLY) { @@ -291,7 +293,8 @@ sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *loca dest->floorplane = s->floorplane; dest->iboindex[sector_t::floor] = sec->iboindex[sector_t::vbo_fakefloor]; - dest->vboheight[sector_t::floor] = s->vboheight[sector_t::floor]; + for (int n = 0; n < screen->mPipelineNbr; n++) + dest->vboheight[n][sector_t::floor] = s->vboheight[n][sector_t::floor]; } if (!(s->MoreFlags&SECMF_FAKEFLOORONLY)) @@ -303,7 +306,8 @@ sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *loca dest->SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false); dest->SetPlaneTexZQuick(sector_t::ceiling, s->GetPlaneTexZ(sector_t::ceiling)); dest->iboindex[sector_t::ceiling] = sec->iboindex[sector_t::vbo_fakeceiling]; - dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::ceiling]; + for (int n = 0; n < screen->mPipelineNbr; n++) + dest->vboheight[n][sector_t::ceiling] = s->vboheight[n][sector_t::ceiling]; } } else @@ -311,7 +315,8 @@ sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *loca dest->ceilingplane = s->ceilingplane; dest->SetPlaneTexZQuick(sector_t::ceiling, s->GetPlaneTexZ(sector_t::ceiling)); dest->iboindex[sector_t::ceiling] = sec->iboindex[sector_t::vbo_fakeceiling]; - dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::ceiling]; + for (int n = 0; n < screen->mPipelineNbr; n++) + dest->vboheight[n][sector_t::ceiling] = s->vboheight[n][sector_t::ceiling]; } } @@ -325,10 +330,12 @@ sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *loca dest->ceilingplane.FlipVert(); dest->iboindex[sector_t::floor] = sec->iboindex[sector_t::floor]; - dest->vboheight[sector_t::floor] = sec->vboheight[sector_t::floor]; + for (int n = 0; n < screen->mPipelineNbr; n++) + dest->vboheight[n][sector_t::floor] = sec->vboheight[n][sector_t::floor]; dest->iboindex[sector_t::ceiling] = sec->iboindex[sector_t::vbo_fakefloor]; - dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::floor]; + for (int n = 0; n < screen->mPipelineNbr; n++) + dest->vboheight[n][sector_t::ceiling] = s->vboheight[n][sector_t::floor]; dest->ClearPortal(sector_t::ceiling); @@ -378,10 +385,12 @@ sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *loca dest->floorplane.FlipVert(); dest->iboindex[sector_t::floor] = sec->iboindex[sector_t::vbo_fakeceiling]; - dest->vboheight[sector_t::floor] = s->vboheight[sector_t::ceiling]; + for (int n = 0; n < screen->mPipelineNbr; n++) + dest->vboheight[n][sector_t::floor] = sec->vboheight[n][sector_t::ceiling]; dest->iboindex[sector_t::ceiling] = sec->iboindex[sector_t::ceiling]; - dest->vboheight[sector_t::ceiling] = sec->vboheight[sector_t::ceiling]; + for (int n = 0; n < screen->mPipelineNbr; n++) + dest->vboheight[n][sector_t::ceiling] = s->vboheight[n][sector_t::ceiling]; dest->ClearPortal(sector_t::floor); diff --git a/src/rendering/hwrenderer/scene/hw_flats.cpp b/src/rendering/hwrenderer/scene/hw_flats.cpp index 79a9db8e532..f423c73fce5 100644 --- a/src/rendering/hwrenderer/scene/hw_flats.cpp +++ b/src/rendering/hwrenderer/scene/hw_flats.cpp @@ -26,6 +26,7 @@ */ #include "a_sharedglobal.h" +#include "a_dynlight.h" #include "r_defs.h" #include "r_sky.h" #include "r_utility.h" @@ -35,16 +36,17 @@ #include "actorinlines.h" #include "p_lnspec.h" #include "matrix.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_lighting.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_dynlightdata.h" +#include "hw_cvars.h" +#include "hw_clock.h" +#include "hw_lighting.h" +#include "hw_material.h" #include "hwrenderer/scene/hw_drawinfo.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" +#include "flatvertices.h" +#include "hw_lightbuffer.h" #include "hw_drawstructs.h" #include "hw_renderstate.h" +#include "texturemanager.h" #ifdef _DEBUG CVAR(Int, gl_breaksec, -1, 0) @@ -56,28 +58,28 @@ CVAR(Int, gl_breaksec, -1, 0) // //========================================================================== -bool hw_SetPlaneTextureRotation(const HWSectorPlane * secplane, FMaterial * gltexture, VSMatrix &dest) +bool hw_SetPlaneTextureRotation(const HWSectorPlane * secplane, FGameTexture * gltexture, VSMatrix &dest) { // only manipulate the texture matrix if needed. if (!secplane->Offs.isZero() || secplane->Scale.X != 1. || secplane->Scale.Y != 1 || secplane->Angle != 0 || - gltexture->TextureWidth() != 64 || - gltexture->TextureHeight() != 64) + gltexture->GetDisplayWidth() != 64 || + gltexture->GetDisplayHeight() != 64) { - float uoffs = secplane->Offs.X / gltexture->TextureWidth(); - float voffs = secplane->Offs.Y / gltexture->TextureHeight(); + float uoffs = secplane->Offs.X / gltexture->GetDisplayWidth(); + float voffs = secplane->Offs.Y / gltexture->GetDisplayHeight(); float xscale1 = secplane->Scale.X; float yscale1 = secplane->Scale.Y; - if (gltexture->hasCanvas()) + if (gltexture->isHardwareCanvas()) { yscale1 = 0 - yscale1; } float angle = -secplane->Angle; - float xscale2 = 64.f / gltexture->TextureWidth(); - float yscale2 = 64.f / gltexture->TextureHeight(); + float xscale2 = 64.f / gltexture->GetDisplayWidth(); + float yscale2 = 64.f / gltexture->GetDisplayHeight(); dest.loadIdentity(); dest.scale(xscale1, yscale1, 1.0f); @@ -89,6 +91,15 @@ bool hw_SetPlaneTextureRotation(const HWSectorPlane * secplane, FMaterial * glte return false; } +void SetPlaneTextureRotation(FRenderState &state, HWSectorPlane* plane, FGameTexture* texture) +{ + if (hw_SetPlaneTextureRotation(plane, texture, state.mTextureMatrix)) + { + state.EnableTextureMatrix(true); + } +} + + //========================================================================== // @@ -150,7 +161,7 @@ void HWFlat::SetupLights(HWDrawInfo *di, FLightNode * node, FDynLightData &light { FDynamicLight * light = node->lightsource; - if (!light->IsActive()) + if (!light->IsActive() || light->DontLightMap()) { node = node->nextLight; continue; @@ -167,7 +178,7 @@ void HWFlat::SetupLights(HWDrawInfo *di, FLightNode * node, FDynLightData &light } p.Set(plane.plane.Normal(), plane.plane.fD()); - draw_dlightf += lightdata.GetLight(portalgroup, p, light, false); + draw_dlightf += GetLight(lightdata, portalgroup, p, light, false); node = node->nextLight; } @@ -203,7 +214,7 @@ void HWFlat::DrawSubsectors(HWDrawInfo *di, FRenderState &state) void HWFlat::DrawOtherPlanes(HWDrawInfo *di, FRenderState &state) { - state.SetMaterial(gltexture, CLAMP_NONE, 0, -1); + state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, NO_TRANSLATION, -1); // Draw the subsectors assigned to it due to missing textures auto pNode = (renderflags&SSRF_RENDERFLOOR) ? @@ -235,7 +246,7 @@ void HWFlat::DrawFloodPlanes(HWDrawInfo *di, FRenderState &state) // This requires a stencil because the projected plane interferes with // the depth buffer - state.SetMaterial(gltexture, CLAMP_NONE, 0, -1); + state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, NO_TRANSLATION, -1); // Draw the subsectors assigned to it due to missing textures auto pNode = (renderflags&SSRF_RENDERFLOOR) ? @@ -304,12 +315,12 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) state.SetNormal(plane.plane.Normal().X, plane.plane.Normal().Z, plane.plane.Normal().Y); - di->SetColor(state, lightlevel, rel, di->isFullbrightScene(), Colormap, alpha); - di->SetFog(state, lightlevel, rel, di->isFullbrightScene(), &Colormap, false); + SetColor(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), Colormap, alpha); + SetFog(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), &Colormap, false); state.SetObjectColor(FlatColor | 0xff000000); state.SetAddColor(AddColor | 0xff000000); state.ApplyTextureManipulation(TextureFx); - + if (plane.plane.dithertransflag) state.SetEffect(EFF_DITHERTRANS); if (hacktype & SSRF_PLANEHACK) { @@ -323,14 +334,14 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) { if (sector->special != GLSector_Skybox) { - state.SetMaterial(gltexture, CLAMP_NONE, 0, -1); - state.SetPlaneTextureRotation(&plane, gltexture); + state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, NO_TRANSLATION, -1); + SetPlaneTextureRotation(state, &plane, texture); DrawSubsectors(di, state); state.EnableTextureMatrix(false); } else if (!hacktype) { - state.SetMaterial(gltexture, CLAMP_XY, 0, -1); + state.SetMaterial(texture, UF_Texture, 0, CLAMP_XY, NO_TRANSLATION, -1); state.SetLightIndex(dynlightindex); state.Draw(DT_TriangleStrip,iboindex, 4); flatvertices += 4; @@ -340,7 +351,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) else { state.SetRenderStyle(renderstyle); - if (!gltexture) + if (!texture || !texture->isValid()) { state.AlphaFunc(Alpha_GEqual, 0.f); state.EnableTexture(false); @@ -349,10 +360,10 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) } else { - if (!gltexture->tex->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + if (!texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); else state.AlphaFunc(Alpha_GEqual, 0.f); - state.SetMaterial(gltexture, CLAMP_NONE, 0, -1); - state.SetPlaneTextureRotation(&plane, gltexture); + state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, NO_TRANSLATION, -1); + SetPlaneTextureRotation(state, &plane, texture); DrawSubsectors(di, state); state.EnableTextureMatrix(false); } @@ -361,6 +372,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) state.SetObjectColor(0xffffffff); state.SetAddColor(0); state.ApplyTextureManipulation(nullptr); + if (plane.plane.dithertransflag) state.SetEffect(EFF_NONE); } //========================================================================== @@ -379,7 +391,7 @@ inline void HWFlat::PutFlat(HWDrawInfo *di, bool fog) } else if (!screen->BuffersArePersistent()) { - if (di->Level->HasDynamicLights && gltexture != nullptr && !di->isFullbrightScene() && !(hacktype & (SSRF_PLANEHACK|SSRF_FLOODHACK)) ) + if (di->Level->HasDynamicLights && texture != nullptr && !di->isFullbrightScene() && !(hacktype & (SSRF_PLANEHACK|SSRF_FLOODHACK)) ) { SetupLights(di, section->lighthead, lightdata, sector->PortalGroup); } @@ -397,6 +409,8 @@ inline void HWFlat::PutFlat(HWDrawInfo *di, bool fog) void HWFlat::Process(HWDrawInfo *di, sector_t * model, int whichplane, bool fog) { plane.GetFromSector(model, whichplane); + model->ceilingplane.dithertransflag = false; // Resetting this every frame + model->floorplane.dithertransflag = false; // Resetting this every frame if (whichplane != int(ceiling)) { // Flip the normal if the source plane has a different orientation than what we are about to render. @@ -405,9 +419,9 @@ void HWFlat::Process(HWDrawInfo *di, sector_t * model, int whichplane, bool fog) if (!fog) { - gltexture=FMaterial::ValidateTexture(plane.texture, false, true); - if (!gltexture) return; - if (gltexture->tex->isFullbright()) + texture = TexMan.GetGameTexture(plane.texture, true); + if (!texture || !texture->isValid()) return; + if (texture->isFullbright()) { Colormap.MakeWhite(); lightlevel=255; @@ -415,7 +429,7 @@ void HWFlat::Process(HWDrawInfo *di, sector_t * model, int whichplane, bool fog) } else { - gltexture = NULL; + texture = NULL; lightlevel = abs(lightlevel); } @@ -455,7 +469,7 @@ void HWFlat::SetFrom3DFloor(F3DFloor *rover, bool top, bool underside) } else { - Colormap.CopyFrom3DLight(light); + CopyFrom3DLight(Colormap, light); FlatColor = plane.model->SpecialColors[plane.isceiling]; AddColor = plane.model->AdditiveColors[plane.isceiling]; TextureFx = &plane.model->planes[plane.isceiling].TextureFx; @@ -495,7 +509,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) uint8_t sink; uint8_t &srf = hacktype? sink : di->section_renderflags[di->Level->sections.SectionIndex(section)]; - const auto &vp = di->Viewpoint; + auto &vp = di->Viewpoint; // // @@ -504,7 +518,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) // // // - if ((which & SSRF_RENDERFLOOR) && frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERFLOOR))) + if (((which & SSRF_RENDERFLOOR) && frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERFLOOR)))&& !(vp.IsOrtho() && (vp.PitchSin < 0.0))) { // process the original floor first. @@ -548,7 +562,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) lightlevel = hw_ClampLight(*light->p_lightlevel); } - Colormap.CopyFrom3DLight(light); + CopyFrom3DLight(Colormap, light); } renderstyle = STYLE_Translucent; Process(di, frontsector, sector_t::floor, false); @@ -562,7 +576,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) // // // - if ((which & SSRF_RENDERCEILING) && frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERCEILING))) + if (((which & SSRF_RENDERCEILING) && frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERCEILING))) && !(vp.IsOrtho() && (vp.PitchSin > 0.0))) { // process the original ceiling first. @@ -604,7 +618,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) { lightlevel = hw_ClampLight(*light->p_lightlevel); } - Colormap.CopyFrom3DLight(light); + CopyFrom3DLight(Colormap, light); } renderstyle = STYLE_Translucent; Process(di, frontsector, sector_t::ceiling, false); diff --git a/src/rendering/hwrenderer/utility/hw_lighting.cpp b/src/rendering/hwrenderer/scene/hw_lighting.cpp similarity index 89% rename from src/rendering/hwrenderer/utility/hw_lighting.cpp rename to src/rendering/hwrenderer/scene/hw_lighting.cpp index e1845b51a97..16fca87bbbf 100644 --- a/src/rendering/hwrenderer/utility/hw_lighting.cpp +++ b/src/rendering/hwrenderer/scene/hw_lighting.cpp @@ -70,26 +70,19 @@ CUSTOM_CVAR(Int, gl_distfog, 70, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } -CUSTOM_CVAR(Int,gl_fogmode,1,CVAR_ARCHIVE|CVAR_NOINITCALL) -{ - if (self>2) self=2; - if (self<0) self=0; -} - - //========================================================================== // // Get current light level // //========================================================================== -int HWDrawInfo::CalcLightLevel(int lightlevel, int rellight, bool weapon, int blendfactor) +int CalcLightLevel(ELightMode lightmode, int lightlevel, int rellight, bool weapon, int blendfactor) { int light; if (lightlevel <= 0) return 0; - bool darklightmode = (isDarkLightMode()) || (isSoftwareLighting() && blendfactor > 0); + bool darklightmode = (isDarkLightMode(lightmode)) || (isSoftwareLighting(lightmode) && blendfactor > 0); if (darklightmode && lightlevel < 192 && !weapon) { @@ -126,13 +119,13 @@ int HWDrawInfo::CalcLightLevel(int lightlevel, int rellight, bool weapon, int bl // //========================================================================== -PalEntry HWDrawInfo::CalcLightColor(int light, PalEntry pe, int blendfactor) +PalEntry CalcLightColor(ELightMode lightmode, int light, PalEntry pe, int blendfactor) { int r,g,b; if (blendfactor == 0) { - if (isSoftwareLighting()) + if (isSoftwareLighting(lightmode)) { return pe; } @@ -172,12 +165,12 @@ PalEntry HWDrawInfo::CalcLightColor(int light, PalEntry pe, int blendfactor) // //========================================================================== -float HWDrawInfo::GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor) +float GetFogDensity(FLevelLocals* Level, ELightMode lightmode, int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor) { float density; auto oldlightmode = lightmode; - if (isSoftwareLighting() && blendfactor > 0) lightmode = ELightMode::Doom; // The blendfactor feature does not work with software-style lighting. + if (isSoftwareLighting(lightmode) && blendfactor > 0) lightmode = ELightMode::Doom; // The blendfactor feature does not work with software-style lighting. if (lightmode == ELightMode::DoomLegacy) { @@ -192,7 +185,7 @@ float HWDrawInfo::GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfog else if ((fogcolor.d & 0xffffff) == 0) { // case 2: black fog - if ((!isSoftwareLighting() || blendfactor > 0) && !(Level->flags3 & LEVEL3_NOLIGHTFADE)) + if ((!isDoomSoftwareLighting(lightmode) || blendfactor > 0) && !(Level->flags3 & LEVEL3_NOLIGHTFADE)) { density = distfogtable[lightmode != ELightMode::LinearStandard][hw_ClampLight(lightlevel)]; } @@ -234,7 +227,7 @@ float HWDrawInfo::GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfog // //========================================================================== -bool HWDrawInfo::CheckFog(sector_t *frontsector, sector_t *backsector) +bool CheckFog(FLevelLocals* Level, sector_t *frontsector, sector_t *backsector, ELightMode lightmode) { if (frontsector == backsector) return false; // there can't be a boundary if both sides are in the same sector. diff --git a/src/rendering/hwrenderer/utility/hw_lighting.h b/src/rendering/hwrenderer/scene/hw_lighting.h similarity index 92% rename from src/rendering/hwrenderer/utility/hw_lighting.h rename to src/rendering/hwrenderer/scene/hw_lighting.h index 2fd972b885f..f4cc443808b 100644 --- a/src/rendering/hwrenderer/utility/hw_lighting.h +++ b/src/rendering/hwrenderer/scene/hw_lighting.h @@ -2,7 +2,7 @@ #include "c_cvars.h" #include "v_palette.h" -#include "templates.h" + #include "r_utility.h" struct Colormap; diff --git a/src/rendering/hwrenderer/scene/hw_portal.cpp b/src/rendering/hwrenderer/scene/hw_portal.cpp index d68a9fa3ab6..b0ea3a8c9bc 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.cpp +++ b/src/rendering/hwrenderer/scene/hw_portal.cpp @@ -33,13 +33,16 @@ #include "r_sky.h" #include "g_levellocals.h" #include "hw_renderstate.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_lighting.h" +#include "flatvertices.h" +#include "hw_clock.h" +#include "hw_lighting.h" +#include "texturemanager.h" EXTERN_CVAR(Int, r_mirror_recursions) EXTERN_CVAR(Bool, gl_portals) +void SetPlaneTextureRotation(FRenderState& state, HWSectorPlane* plane, FGameTexture* texture); + //----------------------------------------------------------------------------- // // StartFrame @@ -70,6 +73,7 @@ CCMD(gl_portalinfo) } static FString indent; +FPortalSceneState portalState; //----------------------------------------------------------------------------- // @@ -103,7 +107,7 @@ void FPortalSceneState::EndFrame(HWDrawInfo *di, FRenderState &state) if (gl_portalinfo) { - indent.Truncate(long(indent.Len()-2)); + indent.Truncate(indent.Len()-2); Printf("%s}\n", indent.GetChars()); if (indent.Len() == 0) gl_portalinfo = false; } @@ -119,7 +123,6 @@ void FPortalSceneState::EndFrame(HWDrawInfo *di, FRenderState &state) //----------------------------------------------------------------------------- bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di, FRenderState &state) { - HWPortal * p; HWPortal * best = nullptr; unsigned bestindex = 0; @@ -129,7 +132,7 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di auto &portals = outer_di->Portals; for (int i = portals.Size() - 1; i >= 0; --i) { - p = portals[i]; + auto p = portals[i]; if (p->lines.Size() > 0 && p->IsSky()) { // Cannot clear the depth buffer inside a portal recursion @@ -412,7 +415,7 @@ void HWScenePortalBase::ClearClipper(HWDrawInfo *di, Clipper *clipper) DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - outer_di->Viewpoint.Pos).Angle() + angleOffset; DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - outer_di->Viewpoint.Pos).Angle() + angleOffset; - if (deltaangle(endAngle, startAngle) < 0) + if (deltaangle(endAngle, startAngle) < nullAngle) { clipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs()); } @@ -444,7 +447,7 @@ int HWLinePortal::ClipSeg(seg_t *seg, const DVector3 &viewpos) { return PClip_Inside; // should be handled properly. } - return P_ClipLineToPortal(linedef, line(), viewpos) ? PClip_InFront : PClip_Inside; + return P_ClipLineToPortal(linedef, this, viewpos.XY()) ? PClip_InFront : PClip_Inside; } int HWLinePortal::ClipSubsector(subsector_t *sub) @@ -452,14 +455,14 @@ int HWLinePortal::ClipSubsector(subsector_t *sub) // this seg is completely behind the mirror for (unsigned int i = 0; inumlines; i++) { - if (P_PointOnLineSidePrecise(sub->firstline[i].v1->fPos(), line()) == 0) return PClip_Inside; + if (P_PointOnLineSidePrecise(sub->firstline[i].v1->fPos(), this) == 0) return PClip_Inside; } return PClip_InFront; } int HWLinePortal::ClipPoint(const DVector2 &pos) { - if (P_PointOnLineSidePrecise(pos, line())) + if (P_PointOnLineSidePrecise(pos, this)) { return PClip_InFront; } @@ -560,7 +563,8 @@ bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe angle_t af = di->FrustumAngle(); if (af < ANGLE_180) clipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + af, vp.Angles.Yaw.BAMs() - af); - clipper->SafeAddClipRange(linedef->v1, linedef->v2); + if(!di->Viewpoint.IsAllowedOoB()) + clipper->SafeAddClipRange(linedef->v1, linedef->v2); return true; } @@ -714,6 +718,7 @@ void HWSkyboxPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) } const char *HWSkyboxPortal::GetName() { return "Skybox"; } +bool HWSkyboxPortal::AllowSSAO() { return false; } // [MK] sector skyboxes don't allow SSAO by default //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -775,6 +780,11 @@ void HWSectorStackPortal::SetupCoverage(HWDrawInfo *di) bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) { auto state = mState; + if (state->renderdepth > 100) // energency abort in case a map manages to set up a recursion. + { + return false; + } + FSectorPortalGroup *portal = origin; auto &vp = di->Viewpoint; @@ -947,12 +957,12 @@ void HWHorizonPortal::DrawContents(HWDrawInfo *di, FRenderState &state) { Clocker c(PortalAll); - FMaterial * gltexture; HWSectorPlane * sp = &origin->plane; auto &vp = di->Viewpoint; - gltexture = FMaterial::ValidateTexture(sp->texture, false, true); - if (!gltexture) + auto texture = TexMan.GetGameTexture(sp->texture, true); + + if (!texture || !texture->isValid()) { state.ClearScreen(); return; @@ -960,24 +970,25 @@ void HWHorizonPortal::DrawContents(HWDrawInfo *di, FRenderState &state) di->SetCameraPos(vp.Pos); - if (gltexture && gltexture->tex->isFullbright()) + if (texture->isFullbright()) { // glowing textures are always drawn full bright without color - di->SetColor(state, 255, 0, false, origin->colormap, 1.f); - di->SetFog(state, 255, 0, false, &origin->colormap, false); + SetColor(state, di->Level, di->lightmode, 255, 0, false, origin->colormap, 1.f); + SetFog(state, di->Level, di->lightmode, 255, 0, false, &origin->colormap, false); } else { int rel = getExtraLight(); - di->SetColor(state, origin->lightlevel, rel, di->isFullbrightScene(), origin->colormap, 1.0f); - di->SetFog(state, origin->lightlevel, rel, di->isFullbrightScene(), &origin->colormap, false); + SetColor(state, di->Level, di->lightmode, origin->lightlevel, rel, di->isFullbrightScene(), origin->colormap, 1.0f); + SetFog(state, di->Level, di->lightmode, origin->lightlevel, rel, di->isFullbrightScene(), &origin->colormap, false); } - state.SetMaterial(gltexture, CLAMP_NONE, 0, -1); + state.EnableBrightmap(true); + state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, NO_TRANSLATION, -1); state.SetObjectColor(origin->specialcolor); - state.SetPlaneTextureRotation(sp, gltexture); + SetPlaneTextureRotation(state, sp, texture); state.AlphaFunc(Alpha_GEqual, 0.f); state.SetRenderStyle(STYLE_Source); @@ -1019,7 +1030,7 @@ void HWEEHorizonPortal::DrawContents(HWDrawInfo *di, FRenderState &state) sector->GetTexture(sector_t::ceiling) == skyflatnum) { HWSkyInfo skyinfo; - skyinfo.init(di, sector->sky, 0); + skyinfo.init(di, sector, sector_t::ceiling, sector->skytransfer, 0); HWSkyPortal sky(screen->mSkyData, mState, &skyinfo, true); sky.DrawContents(di, state); } diff --git a/src/rendering/hwrenderer/scene/hw_portal.h b/src/rendering/hwrenderer/scene/hw_portal.h index 39ea64db251..29481f9e32d 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.h +++ b/src/rendering/hwrenderer/scene/hw_portal.h @@ -2,18 +2,20 @@ #include "tarray.h" #include "r_utility.h" +#include "r_sections.h" #include "actor.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hw_renderstate.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_material.h" +class FSkyBox; struct HWSkyInfo { float x_offset[2]; float y_offset; // doubleskies don't have a y-offset - FMaterial * texture[2]; + FGameTexture * texture[2]; FTextureID skytexno1; bool mirrored; bool doublesky; @@ -28,7 +30,7 @@ struct HWSkyInfo { return !!memcmp(this, &inf, sizeof(*this)); } - void init(HWDrawInfo *di, int sky1, PalEntry fadecolor); + void init(HWDrawInfo *di, sector_t* sec, int skypos, int sky1, PalEntry fadecolor); }; struct HWHorizonInfo @@ -72,9 +74,10 @@ class HWPortal virtual int ClipSeg(seg_t *seg, const DVector3 &viewpos) { return PClip_Inside; } virtual int ClipSubsector(subsector_t *sub) { return PClip_Inside; } virtual int ClipPoint(const DVector2 &pos) { return PClip_Inside; } - virtual line_t *ClipLine() { return nullptr; } + virtual linebase_t *ClipLine() { return nullptr; } virtual void * GetSource() const = 0; // GetSource MUST be implemented! virtual const char *GetName() = 0; + virtual bool AllowSSAO() { return true; } virtual bool IsSky() { return false; } virtual bool NeedCap() { return true; } virtual bool NeedDepthBuffer() { return true; } @@ -127,6 +130,8 @@ struct FPortalSceneState void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil, HWDrawInfo *outer_di); }; +extern FPortalSceneState portalState; + class HWScenePortalBase : public HWPortal { @@ -142,7 +147,7 @@ class HWScenePortalBase : public HWPortal { if (Setup(di, state, di->mClipper)) { - di->DrawScene(di, DM_PORTAL); + di->DrawScene(DM_PORTAL); Shutdown(di, state); } else state.ClearScreen(); @@ -151,12 +156,8 @@ class HWScenePortalBase : public HWPortal virtual void Shutdown(HWDrawInfo *di, FRenderState &rstate) {} }; -struct HWLinePortal : public HWScenePortalBase +struct HWLinePortal : public HWScenePortalBase, public linebase_t { - // this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal. - vertex_t *v1, *v2; // vertices, from v1 to v2 - DVector2 delta; // precalculated v2 - v1 for side checking - angle_t angv1, angv2; // for quick comparisons with a line or subsector HWLinePortal(FPortalSceneState *state, line_t *line) : HWScenePortalBase(state) @@ -189,12 +190,6 @@ struct HWLinePortal : public HWScenePortalBase delta = v2->fPos() - v1->fPos(); } - line_t *line() - { - vertex_t **pv = &v1; - return reinterpret_cast(pv); - } - int ClipSeg(seg_t *seg, const DVector3 &viewpos) override; int ClipSubsector(subsector_t *sub) override; int ClipPoint(const DVector2 &pos); @@ -229,7 +224,7 @@ struct HWLineToLinePortal : public HWLinePortal bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override; virtual void * GetSource() const override { return glport; } virtual const char *GetName() override; - virtual line_t *ClipLine() override { return line(); } + virtual linebase_t *ClipLine() override { return this; } virtual void RenderAttached(HWDrawInfo *di) override; public: @@ -254,6 +249,7 @@ struct HWSkyboxPortal : public HWScenePortalBase virtual void * GetSource() const { return portal; } virtual bool IsSky() { return true; } virtual const char *GetName(); + virtual bool AllowSSAO() override; public: @@ -357,10 +353,6 @@ struct HWSkyPortal : public HWPortal FSkyVertexBuffer *vertexBuffer; friend struct HWEEHorizonPortal; - void RenderRow(HWDrawInfo *di, FRenderState &state, EDrawType prim, int row, bool apply = true); - void RenderBox(HWDrawInfo *di, FRenderState &state, FTextureID texno, FMaterial * gltex, float x_offset, bool sky2); - void RenderDome(HWDrawInfo *di, FRenderState &state, FMaterial * tex, float x_offset, float y_offset, bool mirror, int mode); - protected: virtual void DrawContents(HWDrawInfo *di, FRenderState &state); virtual void * GetSource() const { return origin; } diff --git a/src/rendering/hwrenderer/scene/hw_renderhacks.cpp b/src/rendering/hwrenderer/scene/hw_renderhacks.cpp index 201b6a907cb..6cb22175240 100644 --- a/src/rendering/hwrenderer/scene/hw_renderhacks.cpp +++ b/src/rendering/hwrenderer/scene/hw_renderhacks.cpp @@ -26,19 +26,22 @@ */ #include "a_sharedglobal.h" +#include "a_dynlight.h" #include "r_utility.h" #include "r_sky.h" #include "g_levellocals.h" #include "a_dynlight.h" +#include "texturemanager.h" #include "hw_drawinfo.h" #include "hw_drawstructs.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" +#include "hw_clock.h" +#include "hw_dynlightdata.h" +#include "flatvertices.h" +#include "hw_lightbuffer.h" #include "hwrenderer/scene/hw_portal.h" #include "hw_fakeflat.h" +#include "hw_walldispatcher.h" //========================================================================== // @@ -127,7 +130,7 @@ int HWDrawInfo::SetupLightsForOtherPlane(subsector_t * sub, FDynLightData &light iter_dlightf++; p.Set(plane->Normal(), plane->fD()); - draw_dlightf += lightdata.GetLight(sub->sector->PortalGroup, p, light, true); + draw_dlightf += GetLight(lightdata, sub->sector->PortalGroup, p, light, true); node = node->nextLight; } @@ -350,7 +353,7 @@ bool HWDrawInfo::DoOneSectorUpper(subsector_t * subsec, float Planez, area_t in_ if (sec->GetPlaneTexZ(sector_t::ceiling) == Planez) { // If there's a texture abort - FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::top)); + auto tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::top)); if (!tex || !tex->isValid()) continue; else return false; } @@ -408,7 +411,7 @@ bool HWDrawInfo::DoOneSectorLower(subsector_t * subsec, float Planez, area_t in_ if (sec->GetPlaneTexZ(sector_t::floor) == Planez) { // If there's a texture abort - FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::bottom)); + auto tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::bottom)); if (!tex || !tex->isValid()) continue; else return false; } @@ -1115,7 +1118,8 @@ void HWDrawInfo::ProcessLowerMinisegs(TArray &lowersegs) { seg_t * seg=lowersegs[j]; HWWall wall; - wall.ProcessLowerMiniseg(this, seg, seg->Subsector->render_sector, seg->PartnerSeg->Subsector->render_sector); + HWWallDispatcher disp(this); + wall.ProcessLowerMiniseg(&disp, seg, seg->Subsector->render_sector, seg->PartnerSeg->Subsector->render_sector); rendered_lines++; } } diff --git a/src/rendering/hwrenderer/scene/hw_renderstate.cpp b/src/rendering/hwrenderer/scene/hw_renderstate.cpp deleted file mode 100644 index 60fad5dbb0a..00000000000 --- a/src/rendering/hwrenderer/scene/hw_renderstate.cpp +++ /dev/null @@ -1,167 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2000-2018 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** hw_renderstate.cpp -** hardware independent part of render state. -** -*/ - -#include "hw_renderstate.h" -#include "hw_drawstructs.h" -#include "hw_portal.h" -#include "hwrenderer/utility/hw_lighting.h" -#include "hwrenderer/utility/hw_cvars.h" - - -//========================================================================== -// -// set current light color -// -//========================================================================== -void HWDrawInfo::SetColor(FRenderState &state, int sectorlightlevel, int rellight, bool fullbright, const FColormap &cm, float alpha, bool weapon) -{ - if (fullbright) - { - state.SetColorAlpha(0xffffff, alpha, 0); - if (isSoftwareLighting()) state.SetSoftLightLevel(255); - else state.SetNoSoftLightLevel(); - } - else - { - int hwlightlevel = CalcLightLevel(sectorlightlevel, rellight, weapon, cm.BlendFactor); - PalEntry pe = CalcLightColor(hwlightlevel, cm.LightColor, cm.BlendFactor); - state.SetColorAlpha(pe, alpha, cm.Desaturation); - if (isSoftwareLighting()) state.SetSoftLightLevel(hw_ClampLight(sectorlightlevel + rellight), cm.BlendFactor); - else state.SetNoSoftLightLevel(); - } -} - -//========================================================================== -// -// Lighting stuff -// -//========================================================================== - -void HWDrawInfo::SetShaderLight(FRenderState &state, float level, float olight) -{ - const float MAXDIST = 256.f; - const float THRESHOLD = 96.f; - const float FACTOR = 0.75f; - - if (level > 0) - { - float lightdist, lightfactor; - - if (olight < THRESHOLD) - { - lightdist = (MAXDIST / 2) + (olight * MAXDIST / THRESHOLD / 2); - olight = THRESHOLD; - } - else lightdist = MAXDIST; - - lightfactor = 1.f + ((olight / level) - 1.f) * FACTOR; - if (lightfactor == 1.f) lightdist = 0.f; // save some code in the shader - state.SetLightParms(lightfactor, lightdist); - } - else - { - state.SetLightParms(1.f, 0.f); - } -} - - -//========================================================================== -// -// Sets the fog for the current polygon -// -//========================================================================== - -void HWDrawInfo::SetFog(FRenderState &state, int lightlevel, int rellight, bool fullbright, const FColormap *cmap, bool isadditive) -{ - PalEntry fogcolor; - float fogdensity; - - if (Level->flags&LEVEL_HASFADETABLE) - { - fogdensity = 70; - fogcolor = 0x808080; - } - else if (cmap != NULL && !fullbright) - { - fogcolor = cmap->FadeColor; - fogdensity = GetFogDensity(lightlevel, fogcolor, cmap->FogDensity, cmap->BlendFactor); - fogcolor.a = 0; - } - else - { - fogcolor = 0; - fogdensity = 0; - } - - // Make fog a little denser when inside a skybox - if (screen->mPortalState->inskybox) fogdensity += fogdensity / 2; - - - // no fog in enhanced vision modes! - if (fogdensity == 0 || gl_fogmode == 0) - { - state.EnableFog(false); - state.SetFog(0, 0); - } - else - { - if ((lightmode == ELightMode::Doom || (isSoftwareLighting() && cmap->BlendFactor > 0)) && fogcolor == 0) - { - float light = (float)CalcLightLevel(lightlevel, rellight, false, cmap->BlendFactor); - SetShaderLight(state, light, lightlevel); - } - else - { - state.SetLightParms(1.f, 0.f); - } - - // For additive rendering using the regular fog color here would mean applying it twice - // so always use black - if (isadditive) - { - fogcolor = 0; - } - - state.EnableFog(true); - state.SetFog(fogcolor, fogdensity); - - // Korshun: fullbright fog like in software renderer. - if (isSoftwareLighting() && cmap->BlendFactor == 0 && Level->brightfog && fogdensity != 0 && fogcolor != 0) - { - state.SetSoftLightLevel(255); - } - } -} - - -void FRenderState::CheckTimer(uint64_t ShaderStartTime) -{ - // if firstFrame is not yet initialized, initialize it to current time - // if we're going to overflow a float (after ~4.6 hours, or 24 bits), re-init to regain precision - if ((firstFrame == 0) || (screen->FrameTime - firstFrame >= 1 << 24) || ShaderStartTime >= firstFrame) - firstFrame = screen->FrameTime; -} diff --git a/src/rendering/hwrenderer/scene/hw_setcolor.cpp b/src/rendering/hwrenderer/scene/hw_setcolor.cpp new file mode 100644 index 00000000000..15af68d760f --- /dev/null +++ b/src/rendering/hwrenderer/scene/hw_setcolor.cpp @@ -0,0 +1,164 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2000-2018 Christoph Oelckers +// All rights reserved. +// +// This program 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, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** hw_renderstate.cpp +** hardware independent part of render state. +** +*/ + +#include "g_levellocals.h" +#include "hw_renderstate.h" +#include "hw_drawstructs.h" +#include "hw_portal.h" +#include "hw_lighting.h" +#include "hw_cvars.h" + + +//========================================================================== +// +// set current light color +// +//========================================================================== +void SetColor(FRenderState &state, FLevelLocals* Level, ELightMode lightmode, int sectorlightlevel, int rellight, bool fullbright, const FColormap &cm, float alpha, bool weapon) +{ + if (fullbright) + { + state.SetColorAlpha(0xffffff, alpha, 0); + if (isSoftwareLighting(lightmode)) state.SetSoftLightLevel(255); + else state.SetNoSoftLightLevel(); + } + else + { + int hwlightlevel = CalcLightLevel(lightmode, sectorlightlevel, rellight, weapon, cm.BlendFactor); + PalEntry pe = CalcLightColor(lightmode, hwlightlevel, cm.LightColor, cm.BlendFactor); + state.SetColorAlpha(pe, alpha, cm.Desaturation); + if (isSoftwareLighting(lightmode)) state.SetSoftLightLevel(hw_ClampLight(sectorlightlevel + rellight), cm.BlendFactor); + else state.SetNoSoftLightLevel(); + } +} + +//========================================================================== +// +// Lighting stuff +// +//========================================================================== + +void SetShaderLight(FRenderState &state, FLevelLocals* Level, float level, float olight) +{ + const float MAXDIST = 256.f; + const float THRESHOLD = 96.f; + const float FACTOR = 0.75f; + + if (level > 0) + { + float lightdist, lightfactor; + + if (olight < THRESHOLD) + { + lightdist = (MAXDIST / 2) + (olight * MAXDIST / THRESHOLD / 2); + olight = THRESHOLD; + } + else lightdist = MAXDIST; + + lightfactor = 1.f + ((olight / level) - 1.f) * FACTOR; + if (lightfactor == 1.f) lightdist = 0.f; // save some code in the shader + state.SetLightParms(lightfactor, lightdist); + } + else + { + state.SetLightParms(1.f, 0.f); + } +} + + +//========================================================================== +// +// Sets the fog for the current polygon +// +//========================================================================== + +void SetFog(FRenderState &state, FLevelLocals* Level, ELightMode lightmode, int lightlevel, int rellight, bool fullbright, const FColormap *cmap, bool isadditive) +{ + PalEntry fogcolor; + float fogdensity; + + if (Level->flags&LEVEL_HASFADETABLE) + { + fogdensity = 70; + fogcolor = 0x808080; + } + else if (cmap != nullptr && !fullbright) + { + fogcolor = cmap->FadeColor; + fogdensity = GetFogDensity(Level, lightmode, lightlevel, fogcolor, cmap->FogDensity, cmap->BlendFactor); + fogcolor.a = 0; + } + else + { + fogcolor = 0; + fogdensity = 0; + } + + // Make fog a little denser when inside a skybox + if (portalState.inskybox) fogdensity += fogdensity / 2; + + + // no fog in enhanced vision modes! + if (fogdensity == 0 || gl_fogmode == 0) + { + state.EnableFog(false); + state.SetFog(0, 0); + } + else + { + if ((lightmode == ELightMode::Doom || (isSoftwareLighting(lightmode) && cmap && cmap->BlendFactor > 0)) && fogcolor == 0) + { + float light = (float)CalcLightLevel(lightmode, lightlevel, rellight, false, cmap->BlendFactor); + SetShaderLight(state, Level, light, lightlevel); + } + else if (lightmode == ELightMode::Build) + { + state.SetLightParms(0.2f * fogdensity, 1.f / 31.f); + } + else + { + state.SetLightParms(1.f, 0.f); + } + + // For additive rendering using the regular fog color here would mean applying it twice + // so always use black + if (isadditive) + { + fogcolor = 0; + } + + state.EnableFog(true); + state.SetFog(fogcolor, fogdensity); + + // Korshun: fullbright fog like in software renderer. + if (isSoftwareLighting(lightmode) && cmap && cmap->BlendFactor == 0 && Level->brightfog && fogdensity != 0 && fogcolor != 0) + { + state.SetSoftLightLevel(255); + } + } +} + diff --git a/src/rendering/hwrenderer/scene/hw_sky.cpp b/src/rendering/hwrenderer/scene/hw_sky.cpp index 94fb097d4b6..6d77a275d5d 100644 --- a/src/rendering/hwrenderer/scene/hw_sky.cpp +++ b/src/rendering/hwrenderer/scene/hw_sky.cpp @@ -27,21 +27,36 @@ #include "doomdata.h" #include "g_levellocals.h" #include "p_lnspec.h" +#include "texturemanager.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/utility/hw_lighting.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_lighting.h" +#include "hw_material.h" +#include "hw_walldispatcher.h" CVAR(Bool,gl_noskyboxes, false, 0) +//=========================================================================== +// +// +// +//=========================================================================== + +FTextureID GetSkyTexture(sector_t* sec, int plane, int second) +{ + auto tex = sec->planes[plane].skytexture[second]; + if (tex.isValid()) return tex; + return second ? sec->Level->skytexture2 : sec->Level->skytexture1; +} + //========================================================================== // // Set up the skyinfo struct // //========================================================================== -void HWSkyInfo::init(HWDrawInfo *di, int sky1, PalEntry FadeColor) +void HWSkyInfo::init(HWDrawInfo *di, sector_t* sec, int skypos, int sky1, PalEntry FadeColor) { memset(this, 0, sizeof(*this)); if ((sky1 & PL_SKYFLAT) && (sky1 & (PL_SKYFLAT - 1))) @@ -60,8 +75,9 @@ void HWSkyInfo::init(HWDrawInfo *di, int sky1, PalEntry FadeColor) } FTextureID texno = s->GetTexture(pos); - texture[0] = FMaterial::ValidateTexture(texno, false, true); - if (!texture[0] || !texture[0]->tex->isValid()) goto normalsky; + auto tex = TexMan.GetGameTexture(texno, true); + if (!tex || !tex->isValid()) goto normalsky; + texture[0] = tex; skytexno1 = texno; x_offset[0] = s->GetTextureXOffset(pos) * (360.f/65536.f); y_offset = s->GetTextureYOffset(pos); @@ -70,24 +86,27 @@ void HWSkyInfo::init(HWDrawInfo *di, int sky1, PalEntry FadeColor) else { normalsky: + auto skytex1 = GetSkyTexture(sec, skypos, false); + auto skytex2 = GetSkyTexture(sec, skypos, true); if (di->Level->flags&LEVEL_DOUBLESKY) { - texture[1] = FMaterial::ValidateTexture(di->Level->skytexture1, false, true); + auto tex1 = TexMan.GetGameTexture(skytex1); + texture[1] = tex1; x_offset[1] = di->Level->hw_sky1pos; doublesky = true; } if ((di->Level->flags&LEVEL_SWAPSKIES || (sky1 == PL_SKYFLAT) || (di->Level->flags&LEVEL_DOUBLESKY)) && - di->Level->skytexture2 != di->Level->skytexture1) // If both skies are equal use the scroll offset of the first! + skytex2 != skytex1) // If both skies are equal use the scroll offset of the first! { - texture[0] = FMaterial::ValidateTexture(di->Level->skytexture2, false, true); - skytexno1 = di->Level->skytexture2; + texture[0] = TexMan.GetGameTexture(skytex2, true); + skytexno1 = skytex2; sky2 = true; x_offset[0] = di->Level->hw_sky2pos; } else if (!doublesky) { - texture[0] = FMaterial::ValidateTexture(di->Level->skytexture1, false, true); + texture[0] = TexMan.GetGameTexture(skytex1, true); skytexno1 = di->Level->skytexture1; x_offset[0] = di->Level->hw_sky1pos; } @@ -108,9 +127,10 @@ void HWSkyInfo::init(HWDrawInfo *di, int sky1, PalEntry FadeColor) // //========================================================================== -void HWWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowreflect) +void HWWall::SkyPlane(HWWallDispatcher *di, sector_t *sector, int plane, bool allowreflect) { int ptype = -1; + if (di->di && di->di->Viewpoint.IsAllowedOoB()) return; // Couldn't prevent sky portal occlusion. Skybox is bad in ortho too. FSectorPortal *sportal = sector->ValidatePortal(plane); if (sportal != nullptr && sportal->mFlags & PORTSF_INSKYBOX) sportal = nullptr; // no recursions, delete it here to simplify the following code @@ -119,9 +139,12 @@ void HWWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref if ((sportal == nullptr && sector->GetTexture(plane) == skyflatnum) || (gl_noskyboxes && sportal != nullptr && sportal->mType == PORTS_SKYVIEWPOINT)) { HWSkyInfo skyinfo; - skyinfo.init(di, sector->sky, Colormap.FadeColor); - ptype = PORTALTYPE_SKY; - sky = &skyinfo; + if (di->di) + { + skyinfo.init(di->di, sector, plane, sector->skytransfer, Colormap.FadeColor); + ptype = PORTALTYPE_SKY; + sky = &skyinfo; + } PutPortal(di, ptype, plane); } else if (sportal != nullptr) @@ -137,7 +160,7 @@ void HWWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref { if (sector->PortalBlocksView(plane)) return; - if (screen->instack[1 - plane]) return; + if (di->di && screen->instack[1 - plane]) return; ptype = PORTALTYPE_SECTORSTACK; portal = glport; } @@ -152,13 +175,16 @@ void HWWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref break; } } - else if (allowreflect && sector->GetReflect(plane) > 0) + else if (allowreflect && sector->GetReflect(plane) > 0 && !(di->Level->ib_compatflags & BCOMPATF_NOMIRRORS)) { - auto vpz = di->Viewpoint.Pos.Z; - if ((plane == sector_t::ceiling && vpz > sector->ceilingplane.fD()) || - (plane == sector_t::floor && vpz < -sector->floorplane.fD())) return; + if (di->di) + { + auto vpz = di->di->Viewpoint.Pos.Z; + if ((plane == sector_t::ceiling && vpz > sector->ceilingplane.fD()) || + (plane == sector_t::floor && vpz < -sector->floorplane.fD())) return; + planemirror = plane == sector_t::ceiling ? §or->ceilingplane : §or->floorplane; + } ptype = PORTALTYPE_PLANEMIRROR; - planemirror = plane == sector_t::ceiling ? §or->ceilingplane : §or->floorplane; } if (ptype != -1) { @@ -173,7 +199,7 @@ void HWWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref // //========================================================================== -void HWWall::SkyLine(HWDrawInfo *di, sector_t *fs, line_t *line) +void HWWall::SkyLine(HWWallDispatcher *di, sector_t *fs, line_t *line) { FSectorPortal *secport = line->GetTransferredPortal(); HWSkyInfo skyinfo; @@ -189,7 +215,7 @@ void HWWall::SkyLine(HWDrawInfo *di, sector_t *fs, line_t *line) } else { - skyinfo.init(di, fs->sky, Colormap.FadeColor); + if (di->di) skyinfo.init(di->di, fs, sector_t::ceiling, fs->skytransfer, Colormap.FadeColor); ptype = PORTALTYPE_SKY; sky = &skyinfo; } @@ -207,7 +233,7 @@ void HWWall::SkyLine(HWDrawInfo *di, sector_t *fs, line_t *line) // //========================================================================== -void HWWall::SkyNormal(HWDrawInfo *di, sector_t * fs,vertex_t * v1,vertex_t * v2) +void HWWall::SkyNormal(HWWallDispatcher *di, sector_t * fs,vertex_t * v1,vertex_t * v2) { ztop[0]=ztop[1]=32768.0f; zbottom[0]=zceil[0]; @@ -226,7 +252,7 @@ void HWWall::SkyNormal(HWDrawInfo *di, sector_t * fs,vertex_t * v1,vertex_t * v2 // //========================================================================== -void HWWall::SkyTop(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2) +void HWWall::SkyTop(HWWallDispatcher *di, seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2) { if (fs->GetTexture(sector_t::ceiling)==skyflatnum) { @@ -243,13 +269,13 @@ void HWWall::SkyTop(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vert { if (bs->GetPlaneTexZ(sector_t::floor)==fs->GetPlaneTexZ(sector_t::floor)+1.) { - FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::bottom), true); + auto tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::bottom), true); if (!tex || !tex->isValid()) return; // very, very, very ugly special case (See Icarus MAP14) // It is VERY important that this is only done for a floor height difference of 1 // or it will cause glitches elsewhere. - tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::mid), true); + tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::mid), true); if (tex != NULL && !(seg->linedef->flags & ML_DONTPEGTOP) && seg->sidedef->GetTextureYOffset(side_t::mid) > 0) { @@ -265,7 +291,7 @@ void HWWall::SkyTop(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vert ztop[0]=ztop[1]=32768.0f; - FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::top), true); + auto tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::top), true); if (bs->GetTexture(sector_t::ceiling) != skyflatnum) { @@ -320,12 +346,12 @@ void HWWall::SkyTop(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vert // //========================================================================== -void HWWall::SkyBottom(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2) +void HWWall::SkyBottom(HWWallDispatcher *di, seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2) { if (fs->GetTexture(sector_t::floor)==skyflatnum) { if (bs->special == GLSector_NoSkyDraw || (bs->MoreFlags & SECMF_NOSKYWALLS) != 0 || (seg->linedef->flags & ML_NOSKYWALLS) != 0) return; - FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::bottom), true); + auto tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::bottom), true); // For lower skies the normal logic only applies to walls with no lower texture. if (!tex->isValid()) @@ -340,8 +366,8 @@ void HWWall::SkyBottom(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,v } else { - // Special hack for Vrack2b - if (bs->floorplane.ZatPoint(di->Viewpoint.Pos) > di->Viewpoint.Pos.Z) return; + // Special hack for Vrack2b. For mesh based rendering this check needs to be done in the actual render pass! + if (di->di && bs->floorplane.ZatPoint(di->di->Viewpoint.Pos) > di->di->Viewpoint.Pos.Z) return; } } zbottom[0]=zbottom[1]=-32768.0f; diff --git a/src/rendering/hwrenderer/scene/hw_skydome.cpp b/src/rendering/hwrenderer/scene/hw_skydome.cpp deleted file mode 100644 index 262ded1ed17..00000000000 --- a/src/rendering/hwrenderer/scene/hw_skydome.cpp +++ /dev/null @@ -1,327 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2003-2018 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** -** Draws the sky. Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky. -** -** for FSkyVertexBuffer::SkyVertex only: -**--------------------------------------------------------------------------- -** Copyright 2003 Tim Stump -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ -#include "doomtype.h" -#include "g_level.h" -#include "w_wad.h" -#include "r_state.h" -#include "r_utility.h" -#include "g_levellocals.h" -#include "r_sky.h" -#include "cmdlib.h" - -#include "textures/skyboxtexture.h" -#include "hwrenderer/textures/hw_material.h" -#include "hw_skydome.h" -#include "hw_renderstate.h" -#include "hw_drawinfo.h" -#include "hwrenderer/data/buffers.h" - -//----------------------------------------------------------------------------- -// -// Shamelessly lifted from Doomsday (written by Jaakko Ker�nen) -// also shamelessly lifted from ZDoomGL! ;) -// -//----------------------------------------------------------------------------- -EXTERN_CVAR(Float, skyoffset) - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -FSkyVertexBuffer::FSkyVertexBuffer() -{ - CreateDome(); - mVertexBuffer = screen->CreateVertexBuffer(); - - static const FVertexBufferAttribute format[] = { - { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FSkyVertex, x) }, - { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FSkyVertex, u) }, - { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(FSkyVertex, color) } - }; - mVertexBuffer->SetFormat(1, 3, sizeof(FSkyVertex), format); - mVertexBuffer->SetData(mVertices.Size() * sizeof(FSkyVertex), &mVertices[0], true); -} - -FSkyVertexBuffer::~FSkyVertexBuffer() -{ - delete mVertexBuffer; -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip) -{ - static const FAngle maxSideAngle = 60.f; - static const float scale = 10000.; - - FAngle topAngle = (c / (float)mColumns * 360.f); - FAngle sideAngle = maxSideAngle * float(mRows - r) / float(mRows); - float height = sideAngle.Sin(); - float realRadius = scale * sideAngle.Cos(); - FVector2 pos = topAngle.ToVector(realRadius); - float z = (!zflip) ? scale * height : -scale * height; - - FSkyVertex vert; - - vert.color = r == 0 ? 0xffffff : 0xffffffff; - - // And the texture coordinates. - if (!zflip) // Flipped Y is for the lower hemisphere. - { - vert.u = (-c / (float)mColumns); - vert.v = (r / (float)mRows); - } - else - { - vert.u = (-c / (float)mColumns); - vert.v = 1.0f + ((mRows - r) / (float)mRows); - } - - if (r != 4) z += 300; - // And finally the vertex. - vert.x = -pos.X; // Doom mirrors the sky vertically! - vert.y = z - 1.f; - vert.z = pos.Y; - - mVertices.Push(vert); -} - - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void FSkyVertexBuffer::CreateSkyHemisphere(int hemi) -{ - int r, c; - bool zflip = !!(hemi & SKYHEMI_LOWER); - - mPrimStart.Push(mVertices.Size()); - - for (c = 0; c < mColumns; c++) - { - SkyVertex(1, c, zflip); - } - - // The total number of triangles per hemisphere can be calculated - // as follows: rows * columns * 2 + 2 (for the top cap). - for (r = 0; r < mRows; r++) - { - mPrimStart.Push(mVertices.Size()); - for (c = 0; c <= mColumns; c++) - { - SkyVertex(r + zflip, c, zflip); - SkyVertex(r + 1 - zflip, c, zflip); - } - } -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void FSkyVertexBuffer::CreateDome() -{ - // the first thing we put into the buffer is the fog layer object which is just 4 triangles around the viewpoint. - - mVertices.Reserve(12); - mVertices[0].Set(1.0f, 1.0f, -1.0f); - mVertices[1].Set(1.0f, -1.0f, -1.0f); - mVertices[2].Set(-1.0f, 0.0f, -1.0f); - - mVertices[3].Set(1.0f, 1.0f, -1.0f); - mVertices[4].Set(1.0f, -1.0f, -1.0f); - mVertices[5].Set(0.0f, 0.0f, 1.0f); - - mVertices[6].Set(-1.0f, 0.0f, -1.0f); - mVertices[7].Set(1.0f, 1.0f, -1.0f); - mVertices[8].Set(0.0f, 0.0f, 1.0f); - - mVertices[9].Set(1.0f, -1.0f, -1.0f); - mVertices[10].Set(-1.0f, 0.0f, -1.0f); - mVertices[11].Set(0.0f, 0.0f, 1.0f); - - mColumns = 128; - mRows = 4; - CreateSkyHemisphere(SKYHEMI_UPPER); - CreateSkyHemisphere(SKYHEMI_LOWER); - mPrimStart.Push(mVertices.Size()); - - mSideStart = mVertices.Size(); - mFaceStart[0] = mSideStart + 10; - mFaceStart[1] = mFaceStart[0] + 4; - mFaceStart[2] = mFaceStart[1] + 4; - mFaceStart[3] = mFaceStart[2] + 4; - mFaceStart[4] = mFaceStart[3] + 4; - mFaceStart[5] = mFaceStart[4] + 4; - mFaceStart[6] = mFaceStart[5] + 4; - mVertices.Reserve(10 + 7*4); - FSkyVertex *ptr = &mVertices[mSideStart]; - - // all sides - ptr[0].SetXYZ(128.f, 128.f, -128.f, 0, 0); - ptr[1].SetXYZ(128.f, -128.f, -128.f, 0, 1); - ptr[2].SetXYZ(-128.f, 128.f, -128.f, 0.25f, 0); - ptr[3].SetXYZ(-128.f, -128.f, -128.f, 0.25f, 1); - ptr[4].SetXYZ(-128.f, 128.f, 128.f, 0.5f, 0); - ptr[5].SetXYZ(-128.f, -128.f, 128.f, 0.5f, 1); - ptr[6].SetXYZ(128.f, 128.f, 128.f, 0.75f, 0); - ptr[7].SetXYZ(128.f, -128.f, 128.f, 0.75f, 1); - ptr[8].SetXYZ(128.f, 128.f, -128.f, 1, 0); - ptr[9].SetXYZ(128.f, -128.f, -128.f, 1, 1); - - // north face - ptr[10].SetXYZ(128.f, 128.f, -128.f, 0, 0); - ptr[11].SetXYZ(-128.f, 128.f, -128.f, 1, 0); - ptr[12].SetXYZ(128.f, -128.f, -128.f, 0, 1); - ptr[13].SetXYZ(-128.f, -128.f, -128.f, 1, 1); - - // east face - ptr[14].SetXYZ(-128.f, 128.f, -128.f, 0, 0); - ptr[15].SetXYZ(-128.f, 128.f, 128.f, 1, 0); - ptr[16].SetXYZ(-128.f, -128.f, -128.f, 0, 1); - ptr[17].SetXYZ(-128.f, -128.f, 128.f, 1, 1); - - // south face - ptr[18].SetXYZ(-128.f, 128.f, 128.f, 0, 0); - ptr[19].SetXYZ(128.f, 128.f, 128.f, 1, 0); - ptr[20].SetXYZ(-128.f, -128.f, 128.f, 0, 1); - ptr[21].SetXYZ(128.f, -128.f, 128.f, 1, 1); - - // west face - ptr[22].SetXYZ(128.f, 128.f, 128.f, 0, 0); - ptr[23].SetXYZ(128.f, 128.f, -128.f, 1, 0); - ptr[24].SetXYZ(128.f, -128.f, 128.f, 0, 1); - ptr[25].SetXYZ(128.f, -128.f, -128.f, 1, 1); - - // bottom face - ptr[26].SetXYZ(128.f, -128.f, -128.f, 0, 0); - ptr[27].SetXYZ(-128.f, -128.f, -128.f, 1, 0); - ptr[28].SetXYZ(128.f, -128.f, 128.f, 0, 1); - ptr[29].SetXYZ(-128.f, -128.f, 128.f, 1, 1); - - // top face - ptr[30].SetXYZ(128.f, 128.f, -128.f, 0, 0); - ptr[31].SetXYZ(-128.f, 128.f, -128.f, 1, 0); - ptr[32].SetXYZ(128.f, 128.f, 128.f, 0, 1); - ptr[33].SetXYZ(-128.f, 128.f, 128.f, 1, 1); - - // top face flipped - ptr[34].SetXYZ(128.f, 128.f, -128.f, 0, 1); - ptr[35].SetXYZ(-128.f, 128.f, -128.f, 1, 1); - ptr[36].SetXYZ(128.f, 128.f, 128.f, 0, 0); - ptr[37].SetXYZ(-128.f, 128.f, 128.f, 1, 0); -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void FSkyVertexBuffer::SetupMatrices(HWDrawInfo *di, FMaterial *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelMatrix, VSMatrix &textureMatrix) -{ - int texw = tex->TextureWidth(); - int texh = tex->TextureHeight(); - - modelMatrix.loadIdentity(); - modelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f); - - float xscale = texw < 1024.f ? floor(1024.f / float(texw)) : 1.f; - float yscale = 1.f; - if (texh <= 128 && (di->Level->flags & LEVEL_FORCETILEDSKY)) - { - modelMatrix.translate(0.f, (-40 + tex->tex->GetSkyOffset() + skyoffset)*skyoffsetfactor, 0.f); - modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); - yscale = 240.f / texh; - } - else if (texh < 128) - { - // smaller sky textures must be tiled. We restrict it to 128 sky pixels, though - modelMatrix.translate(0.f, -1250.f, 0.f); - modelMatrix.scale(1.f, 128 / 230.f, 1.f); - yscale = float(128 / texh); // intentionally left as integer. - } - else if (texh < 200) - { - modelMatrix.translate(0.f, -1250.f, 0.f); - modelMatrix.scale(1.f, texh / 230.f, 1.f); - } - else if (texh <= 240) - { - modelMatrix.translate(0.f, (200 - texh + tex->tex->GetSkyOffset() + skyoffset)*skyoffsetfactor, 0.f); - modelMatrix.scale(1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f, 1.f); - } - else - { - modelMatrix.translate(0.f, (-40 + tex->tex->GetSkyOffset() + skyoffset)*skyoffsetfactor, 0.f); - modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); - yscale = 240.f / texh; - } - textureMatrix.loadIdentity(); - textureMatrix.scale(mirror ? -xscale : xscale, yscale, 1.f); - textureMatrix.translate(1.f, y_offset / texh, 1.f); -} diff --git a/src/rendering/hwrenderer/scene/hw_skydome.h b/src/rendering/hwrenderer/scene/hw_skydome.h deleted file mode 100644 index 4084ef96f38..00000000000 --- a/src/rendering/hwrenderer/scene/hw_skydome.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include "v_palette.h" -#include "matrix.h" -#include "hwrenderer/data/buffers.h" - -class FMaterial; -class FRenderState; -class IVertexBuffer; -struct HWSkyPortal; -struct HWDrawInfo; - -struct FSkyVertex -{ - float x, y, z, u, v; - PalEntry color; - - void Set(float xx, float zz, float yy, float uu=0, float vv=0, PalEntry col=0xffffffff) - { - x = xx; - z = zz; - y = yy; - u = uu; - v = vv; - color = col; - } - - void SetXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0, PalEntry col = 0xffffffff) - { - x = xx; - y = yy; - z = zz; - u = uu; - v = vv; - color = col; - } - -}; - -class FSkyVertexBuffer -{ - friend struct HWSkyPortal; -public: - static const int SKYHEMI_UPPER = 1; - static const int SKYHEMI_LOWER = 2; - - enum - { - SKYMODE_MAINLAYER = 0, - SKYMODE_SECONDLAYER = 1, - SKYMODE_FOGLAYER = 2 - }; - - IVertexBuffer *mVertexBuffer; - - TArray mVertices; - TArray mPrimStart; - - int mRows, mColumns; - - // indices for sky cubemap faces - int mFaceStart[7]; - int mSideStart; - - void SkyVertex(int r, int c, bool yflip); - void CreateSkyHemisphere(int hemi); - void CreateDome(); - -public: - - FSkyVertexBuffer(); - ~FSkyVertexBuffer(); - void SetupMatrices(HWDrawInfo *di, FMaterial *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelmatrix, VSMatrix &textureMatrix); - std::pair GetBufferObjects() const - { - return std::make_pair(mVertexBuffer, nullptr); - } - - int FaceStart(int i) - { - if (i >= 0 && i < 7) return mFaceStart[i]; - else return mSideStart; - } - -}; diff --git a/src/rendering/hwrenderer/scene/hw_skyportal.cpp b/src/rendering/hwrenderer/scene/hw_skyportal.cpp index bba4b60eeac..656b9dd164d 100644 --- a/src/rendering/hwrenderer/scene/hw_skyportal.cpp +++ b/src/rendering/hwrenderer/scene/hw_skyportal.cpp @@ -22,136 +22,14 @@ #include "doomtype.h" #include "g_level.h" -#include "w_wad.h" +#include "filesystem.h" #include "r_state.h" #include "r_utility.h" #include "g_levellocals.h" -#include "hwrenderer/scene/hw_skydome.h" +#include "hw_skydome.h" #include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include "textures/skyboxtexture.h" - - - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void HWSkyPortal::RenderRow(HWDrawInfo *di, FRenderState &state, EDrawType prim, int row, bool apply) -{ - state.Draw(prim, vertexBuffer->mPrimStart[row], vertexBuffer->mPrimStart[row + 1] - vertexBuffer->mPrimStart[row]); -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void HWSkyPortal::RenderDome(HWDrawInfo *di, FRenderState &state, FMaterial * tex, float x_offset, float y_offset, bool mirror, int mode) -{ - if (tex) - { - state.SetMaterial(tex, CLAMP_NONE, 0, -1); - state.EnableModelMatrix(true); - state.EnableTextureMatrix(true); - - vertexBuffer->SetupMatrices(di, tex, x_offset, y_offset, mirror, mode, state.mModelMatrix, state.mTextureMatrix); - } - - int rc = vertexBuffer->mRows + 1; - - // The caps only get drawn for the main layer but not for the overlay. - if (mode == FSkyVertexBuffer::SKYMODE_MAINLAYER && tex != NULL) - { - PalEntry pe = tex->tex->GetSkyCapColor(false); - state.SetObjectColor(pe); - state.EnableTexture(false); - RenderRow(di, state, DT_TriangleFan, 0); - - pe = tex->tex->GetSkyCapColor(true); - state.SetObjectColor(pe); - RenderRow(di, state, DT_TriangleFan, rc); - state.EnableTexture(true); - } - state.SetObjectColor(0xffffffff); - for (int i = 1; i <= vertexBuffer->mRows; i++) - { - RenderRow(di, state, DT_TriangleStrip, i, i == 1); - RenderRow(di, state, DT_TriangleStrip, rc + i, false); - } - - state.EnableTextureMatrix(false); - state.EnableModelMatrix(false); -} - - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void HWSkyPortal::RenderBox(HWDrawInfo *di, FRenderState &state, FTextureID texno, FMaterial * gltex, float x_offset, bool sky2) -{ - FSkyBox * sb = static_cast(gltex->tex); - int faces; - FMaterial * tex; - - state.EnableModelMatrix(true); - state.mModelMatrix.loadIdentity(); - - if (!sky2) - state.mModelMatrix.rotate(-180.0f+x_offset, di->Level->info->skyrotatevector.X, di->Level->info->skyrotatevector.Z, di->Level->info->skyrotatevector.Y); - else - state.mModelMatrix.rotate(-180.0f+x_offset, di->Level->info->skyrotatevector2.X, di->Level->info->skyrotatevector2.Z, di->Level->info->skyrotatevector2.Y); - - if (sb->faces[5]) - { - faces=4; - - // north - tex = FMaterial::ValidateTexture(sb->faces[0], false); - state.SetMaterial(tex, CLAMP_XY, 0, -1); - state.Draw(DT_TriangleStrip, vertexBuffer->FaceStart(0), 4); - - // east - tex = FMaterial::ValidateTexture(sb->faces[1], false); - state.SetMaterial(tex, CLAMP_XY, 0, -1); - state.Draw(DT_TriangleStrip, vertexBuffer->FaceStart(1), 4); - - // south - tex = FMaterial::ValidateTexture(sb->faces[2], false); - state.SetMaterial(tex, CLAMP_XY, 0, -1); - state.Draw(DT_TriangleStrip, vertexBuffer->FaceStart(2), 4); - - // west - tex = FMaterial::ValidateTexture(sb->faces[3], false); - state.SetMaterial(tex, CLAMP_XY, 0, -1); - state.Draw(DT_TriangleStrip, vertexBuffer->FaceStart(3), 4); - } - else - { - faces=1; - tex = FMaterial::ValidateTexture(sb->faces[0], false); - state.SetMaterial(tex, CLAMP_XY, 0, -1); - state.Draw(DT_TriangleStrip, vertexBuffer->FaceStart(-1), 10); - } - - // top - tex = FMaterial::ValidateTexture(sb->faces[faces], false); - state.SetMaterial(tex, CLAMP_XY, 0, -1); - state.Draw(DT_TriangleStrip, vertexBuffer->FaceStart(sb->fliptop ? 6 : 5), 4); - - // bottom - tex = FMaterial::ValidateTexture(sb->faces[faces+1], false); - state.SetMaterial(tex, CLAMP_XY, 0, -1); - state.Draw(DT_TriangleStrip, vertexBuffer->FaceStart(4), 4); - - state.EnableModelMatrix(false); -} +#include "hw_renderstate.h" +#include "skyboxtexture.h" //----------------------------------------------------------------------------- // @@ -165,7 +43,7 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state) // We have no use for Doom lighting special handling here, so disable it for this function. auto oldlightmode = di->lightmode; - if (di->isSoftwareLighting()) + if (isSoftwareLighting(oldlightmode)) { di->SetFallbackLightMode(); state.SetNoSoftLightLevel(); @@ -181,9 +59,10 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state) di->SetupView(state, 0, 0, 0, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1)); state.SetVertexBuffer(vertexBuffer); - if (origin->texture[0] && origin->texture[0]->tex->isSkybox()) + auto skybox = origin->texture[0] ? dynamic_cast(origin->texture[0]->GetTexture()) : nullptr; + if (skybox) { - RenderBox(di, state, origin->skytexno1, origin->texture[0], origin->x_offset[0], origin->sky2); + vertexBuffer->RenderBox(state, skybox, origin->x_offset[0], origin->sky2, di->Level->info->pixelstretch, di->Level->info->skyrotatevector, di->Level->info->skyrotatevector2); } else { @@ -192,7 +71,7 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state) if (origin->texture[0]) { state.SetTextureMode(TM_OPAQUE); - RenderDome(di, state, origin->texture[0], origin->x_offset[0], origin->y_offset, origin->mirrored, FSkyVertexBuffer::SKYMODE_MAINLAYER); + vertexBuffer->RenderDome(state, origin->texture[0], origin->x_offset[0], origin->y_offset, origin->mirrored, FSkyVertexBuffer::SKYMODE_MAINLAYER, !!(di->Level->flags & LEVEL_FORCETILEDSKY)); state.SetTextureMode(TM_NORMAL); } @@ -200,7 +79,7 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state) if (origin->doublesky && origin->texture[1]) { - RenderDome(di, state, origin->texture[1], origin->x_offset[1], origin->y_offset, false, FSkyVertexBuffer::SKYMODE_SECONDLAYER); + vertexBuffer->RenderDome(state, origin->texture[1], origin->x_offset[1], origin->y_offset, false, FSkyVertexBuffer::SKYMODE_SECONDLAYER, !!(di->Level->flags & LEVEL_FORCETILEDSKY)); } if (di->Level->skyfog>0 && !di->isFullbrightScene() && (origin->fadecolor & 0xffffff) != 0) diff --git a/src/rendering/hwrenderer/scene/hw_spritelight.cpp b/src/rendering/hwrenderer/scene/hw_spritelight.cpp index a8bc1f849de..f9998398aa8 100644 --- a/src/rendering/hwrenderer/scene/hw_spritelight.cpp +++ b/src/rendering/hwrenderer/scene/hw_spritelight.cpp @@ -26,15 +26,18 @@ */ #include "c_dispatch.h" +#include "a_dynlight.h" #include "p_local.h" #include "p_effect.h" #include "g_level.h" #include "g_levellocals.h" #include "actorinlines.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/dynlights/hw_shadowmap.h" +#include "hw_dynlightdata.h" +#include "hw_shadowmap.h" #include "hwrenderer/scene/hw_drawinfo.h" -#include "r_data/models/models.h" +#include "hwrenderer/scene/hw_drawstructs.h" +#include "models.h" +#include // needed for std::floor on mac template T smoothstep(const T edge0, const T edge1, const T x) @@ -43,6 +46,61 @@ T smoothstep(const T edge0, const T edge1, const T x) return t * t * (3.0 - 2.0 * t); } +LightProbe* FindLightProbe(FLevelLocals* level, float x, float y, float z) +{ + LightProbe* foundprobe = nullptr; + if (level->LightProbes.Size() > 0) + { +#if 1 + double rcpCellSize = 1.0 / level->LPCellSize; + int gridCenterX = (int)std::floor(x * rcpCellSize) - level->LPMinX; + int gridCenterY = (int)std::floor(y * rcpCellSize) - level->LPMinY; + int gridWidth = level->LPWidth; + int gridHeight = level->LPHeight; + float lastdist = 0.0f; + for (int gridY = gridCenterY - 1; gridY <= gridCenterY + 1; gridY++) + { + for (int gridX = gridCenterX - 1; gridX <= gridCenterX + 1; gridX++) + { + if (gridX >= 0 && gridY >= 0 && gridX < gridWidth && gridY < gridHeight) + { + const LightProbeCell& cell = level->LPCells[gridX + (size_t)gridY * gridWidth]; + for (int i = 0; i < cell.NumProbes; i++) + { + LightProbe* probe = cell.FirstProbe + i; + float dx = probe->X - x; + float dy = probe->Y - y; + float dz = probe->Z - z; + float dist = dx * dx + dy * dy + dz * dz; + if (!foundprobe || dist < lastdist) + { + foundprobe = probe; + lastdist = dist; + } + } + } + } + } +#else + float lastdist = 0.0f; + for (unsigned int i = 0; i < level->LightProbes.Size(); i++) + { + LightProbe *probe = &level->LightProbes[i]; + float dx = probe->X - x; + float dy = probe->Y - y; + float dz = probe->Z - z; + float dist = dx * dx + dy * dy + dz * dz; + if (i == 0 || dist < lastdist) + { + foundprobe = probe; + lastdist = dist; + } + } +#endif + } + return foundprobe; +} + //========================================================================== // // Sets a single light value from all dynamic lights affecting the specified location @@ -56,6 +114,15 @@ void HWDrawInfo::GetDynSpriteLight(AActor *self, float x, float y, float z, FLig float radius; out[0] = out[1] = out[2] = 0.f; + + LightProbe* probe = FindLightProbe(Level, x, y, z); + if (probe) + { + out[0] = probe->Red; + out[1] = probe->Green; + out[2] = probe->Blue; + } + // Go through both light lists while (node) { @@ -104,7 +171,7 @@ void HWDrawInfo::GetDynSpriteLight(AActor *self, float x, float y, float z, FLig frac *= (float)smoothstep(light->pSpotOuterAngle->Cos(), light->pSpotInnerAngle->Cos(), cosDir); } - if (frac > 0 && (!light->shadowmapped || screen->mShadowMap.ShadowTest(light, { x, y, z }))) + if (frac > 0 && (!light->shadowmapped || (light->GetRadius() > 0 && screen->mShadowMap.ShadowTest(light->Pos, { x, y, z })))) { lr = light->GetRed() / 255.0f; lg = light->GetGreen() / 255.0f; @@ -182,7 +249,7 @@ void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata) { if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector { - modellightdata.AddLightToList(group, light, true); + AddLightToList(modellightdata, group, light, true); addedLights.Push(light); } } diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 4d44f29ef20..ba4b6798331 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -33,38 +33,65 @@ #include "r_sky.h" #include "r_utility.h" #include "a_pickups.h" +#include "a_corona.h" #include "d_player.h" #include "g_levellocals.h" #include "events.h" #include "actorinlines.h" #include "r_data/r_vanillatrans.h" #include "matrix.h" -#include "r_data/models/models.h" +#include "models.h" #include "vectors.h" +#include "texturemanager.h" +#include "basics.h" -#include "hwrenderer/models/hw_models.h" +#include "hw_models.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_fakeflat.h" #include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_lighting.h" -#include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" +#include "flatvertices.h" +#include "hw_cvars.h" +#include "hw_clock.h" +#include "hw_lighting.h" +#include "hw_material.h" +#include "hw_dynlightdata.h" +#include "hw_lightbuffer.h" #include "hw_renderstate.h" +#include "quaternion.h" extern TArray sprites; extern TArray SpriteFrames; extern uint32_t r_renderercaps; const float LARGE_VALUE = 1e19f; +const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2) EXTERN_CVAR(Bool, r_debug_disable_vis_filter) EXTERN_CVAR(Float, transsouls) +EXTERN_CVAR(Float, r_actorspriteshadowalpha) +EXTERN_CVAR(Float, r_actorspriteshadowfadeheight) +//========================================================================== +// +// Sprite CVARs +// +//========================================================================== + +CVAR(Bool, gl_usecolorblending, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, gl_sprite_blend, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Int, gl_spriteclip, 1, CVAR_ARCHIVE) +CVAR(Float, gl_sclipthreshold, 10.0, CVAR_ARCHIVE) +CVAR(Float, gl_sclipfactor, 1.8f, CVAR_ARCHIVE) +CVAR(Int, gl_particles_style, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 0 = square, 1 = round, 2 = smooth +CVAR(Int, gl_billboard_mode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, gl_billboard_faces_camera, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, hw_force_cambbpref, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, gl_billboard_particles, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, gl_fuzztype, 0, CVAR_ARCHIVE) +{ + if (self < 0 || self > 8) self = 0; +} //========================================================================== // @@ -77,7 +104,7 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) bool additivefog = false; bool foglayer = false; int rel = fullbright ? 0 : getExtraLight(); - auto &vp = di->Viewpoint; + auto &vp = di->Viewpoint; if (translucent) { @@ -92,7 +119,7 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) // Optionally use STYLE_ColorBlend in place of STYLE_Add for fullbright items. if (RenderStyle == LegacyRenderStyles[STYLE_Add] && trans > 1.f - FLT_EPSILON && gl_usecolorblending && !di->isFullbrightScene() && actor && - fullbright && gltexture && !gltexture->tex->GetTranslucency()) + fullbright && texture && !texture->GetTranslucency()) { RenderStyle = LegacyRenderStyles[STYLE_ColorAdd]; } @@ -104,7 +131,7 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) { state.AlphaFunc(Alpha_GEqual, 0.f); } - else if (!gltexture || !gltexture->tex->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); + else if (!texture || !texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); else state.AlphaFunc(Alpha_Greater, 0.f); if (RenderStyle.BlendOp == STYLEOP_Shadow) @@ -116,7 +143,7 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) if (!Colormap.FadeColor.isBlack()) { float dist = Dist2(vp.Pos.X, vp.Pos.Y, x, y); - int fogd = di->GetFogDensity(lightlevel, Colormap.FadeColor, Colormap.FogDensity, Colormap.BlendFactor); + int fogd = GetFogDensity(di->Level, di->lightmode, lightlevel, Colormap.FadeColor, Colormap.FogDensity, Colormap.BlendFactor); // this value was determined by trial and error and is scale dependent! float factor = 0.05f + exp(-fogd * dist / 62500.f); @@ -161,7 +188,7 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) state.SetObjectColor(finalcol); state.SetAddColor(cursec->AdditiveColors[sector_t::sprites] | 0xff000000); } - di->SetColor(state, lightlevel, rel, di->isFullbrightScene(), Colormap, trans); + SetColor(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), Colormap, trans); } @@ -188,14 +215,17 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) else RenderStyle.BlendOp = STYLEOP_Fuzz; // subtractive with models is not going to work. } - if (!foglayer) di->SetFog(state, foglevel, rel, di->isFullbrightScene(), &Colormap, additivefog); + if (!foglayer) SetFog(state, di->Level, di->lightmode, foglevel, rel, di->isFullbrightScene(), &Colormap, additivefog); else { state.EnableFog(false); state.SetFog(0, 0); } - if (gltexture) state.SetMaterial(gltexture, CLAMP_XY, translation, OverrideShader); + int clampmode = nomipmap ? CLAMP_XY_NOMIP : CLAMP_XY; + + uint32_t spritetype = actor? uint32_t(actor->renderflags & RF_SPRITETYPEMASK) : 0; + if (texture) state.SetMaterial(texture, UF_Sprite, (spritetype == RF_FACESPRITE) ? CTF_Expand : 0, clampmode, translation, OverrideShader); else if (!modelframe) state.EnableTexture(false); //SetColor(lightlevel, rel, Colormap, trans); @@ -217,28 +247,27 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) // set up the light slice secplane_t *topplane = i == 0 ? &topp : &(*lightlist)[i].plane; secplane_t *lowplane = i == (*lightlist).Size() - 1 ? &bottomp : &(*lightlist)[i + 1].plane; - int thislight = (*lightlist)[i].caster != nullptr ? hw_ClampLight(*(*lightlist)[i].p_lightlevel) : lightlevel; int thisll = actor == nullptr ? thislight : (uint8_t)actor->Sector->CheckSpriteGlow(thislight, actor->InterpolatedPosition(vp.TicFrac)); FColormap thiscm; thiscm.CopyFog(Colormap); - thiscm.CopyFrom3DLight(&(*lightlist)[i]); + CopyFrom3DLight(thiscm, &(*lightlist)[i]); if (di->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) { thiscm.Decolorize(); } - di->SetColor(state, thisll, rel, di->isFullbrightScene(), thiscm, trans); + SetColor(state, di->Level, di->lightmode, thisll, rel, di->isFullbrightScene(), thiscm, trans); if (!foglayer) { - di->SetFog(state, thislight, rel, di->isFullbrightScene(), &thiscm, additivefog); + SetFog(state, di->Level, di->lightmode, thislight, rel, di->isFullbrightScene(), &thiscm, additivefog); } - state.SetSplitPlanes(*topplane, *lowplane); + SetSplitPlanes(state, *topplane, *lowplane); } else if (clipping) { - state.SetSplitPlanes(topp, bottomp); + SetSplitPlanes(state, topp, bottomp); } if (!modelframe) @@ -260,7 +289,7 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) if (foglayer) { // If we get here we know that we have colored fog and no fixed colormap. - di->SetFog(state, foglevel, rel, false, &Colormap, additivefog); + SetFog(state, di->Level, di->lightmode, foglevel, rel, false, &Colormap, additivefog); state.SetTextureMode(TM_FOGLAYER); state.SetRenderStyle(STYLE_Translucent); state.Draw(DT_TriangleStrip, vertexindex, 4); @@ -269,8 +298,15 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) } else { + if (actor && di->Level->LightProbes.Size() > 0) + { + LightProbe* probe = FindLightProbe(di->Level, actor->X(), actor->Y(), actor->Center()); + if (probe) + state.SetDynLight(probe->Red, probe->Green, probe->Blue); + } + FHWModelRenderer renderer(di, state, dynlightindex); - renderer.RenderModel(x, y, z, modelframe, actor, di->Viewpoint.TicFrac); + RenderModel(&renderer, x, y, z, modelframe, actor, di->Viewpoint.TicFrac); state.SetVertexBuffer(screen->mVertexData); } } @@ -307,38 +343,50 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) // //========================================================================== -bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) +void HandleSpriteOffsets(Matrix3x4 *mat, const FRotator *HW, FVector2 *offset, bool XYBillboard) +{ + FAngle zero = FAngle::fromDeg(0); + FAngle pitch = (XYBillboard) ? HW->Pitch : zero; + FAngle yaw = FAngle::fromDeg(270.) - HW->Yaw; + + FQuaternion quat = FQuaternion::FromAngles(yaw, pitch, zero); + FVector3 sideVec = quat * FVector3(0, 1, 0); + FVector3 upVec = quat * FVector3(0, 0, 1); + FVector3 res = sideVec * offset->X + upVec * offset->Y; + mat->Translate(res.X, res.Z, res.Y); +} + +bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) { - const auto &HWAngles = di->Viewpoint.HWAngles; + float pixelstretch = di->Level->pixelstretch; + + FVector3 center = FVector3((x1 + x2) * 0.5, (y1 + y2) * 0.5, (z1 + z2) * 0.5); + const auto& HWAngles = di->Viewpoint.HWAngles; + Matrix3x4 mat; if (actor != nullptr && (actor->renderflags & RF_SPRITETYPEMASK) == RF_FLATSPRITE) { - Matrix3x4 mat; - mat.MakeIdentity(); - // [MC] Rotate around the center or offsets given to the sprites. // Counteract any existing rotations, then rotate the angle. // Tilt the actor up or down based on pitch (increase 'somersaults' forward). // Then counteract the roll and DO A BARREL ROLL. - FAngle pitch = (float)-Angles.Pitch.Degrees; + mat.MakeIdentity(); + FAngle pitch = FAngle::fromDeg(-Angles.Pitch.Degrees()); pitch.Normalized180(); mat.Translate(x, z, y); - mat.Rotate(0, 1, 0, 270. - Angles.Yaw.Degrees); - mat.Rotate(1, 0, 0, pitch.Degrees); + mat.Rotate(0, 1, 0, 270. - Angles.Yaw.Degrees()); + mat.Rotate(1, 0, 0, pitch.Degrees()); if (actor->renderflags & RF_ROLLCENTER) { - float cx = (x1 + x2) * 0.5; - float cy = (y1 + y2) * 0.5; - - mat.Translate(cx - x, 0, cy - y); - mat.Rotate(0, 1, 0, - Angles.Roll.Degrees); - mat.Translate(-cx, -z, -cy); + mat.Translate(center.X - x, 0, center.Y - y); + mat.Rotate(0, 1, 0, - Angles.Roll.Degrees()); + mat.Translate(-center.X, -z, -center.Y); } else { - mat.Rotate(0, 1, 0, - Angles.Roll.Degrees); + mat.Rotate(0, 1, 0, - Angles.Roll.Degrees()); mat.Translate(-x, -z, -y); } v[0] = mat * FVector3(x2, z, y2); @@ -350,78 +398,81 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) } // [BB] Billboard stuff - const bool drawWithXYBillboard = ((particle && gl_billboard_particles) || (!(actor && actor->renderflags & RF_FORCEYBILLBOARD) + const bool drawWithXYBillboard = ((particle && gl_billboard_particles && !(particle->flags & SPF_NO_XY_BILLBOARD)) || (!(actor && actor->renderflags & RF_FORCEYBILLBOARD) //&& di->mViewActor != nullptr && (gl_billboard_mode == 1 || (actor && actor->renderflags & RF_FORCEXYBILLBOARD)))); - const bool drawBillboardFacingCamera = gl_billboard_faces_camera; + const bool drawBillboardFacingCamera = hw_force_cambbpref ? gl_billboard_faces_camera : + gl_billboard_faces_camera + && ((actor && (!(actor->renderflags2 & RF2_BILLBOARDNOFACECAMERA) || (actor->renderflags2 & RF2_BILLBOARDFACECAMERA))) + || (particle && particle->texture.isValid() && (!(particle->flags & SPF_NOFACECAMERA) || (particle->flags & SPF_FACECAMERA)))); + // [Nash] has +ROLLSPRITE const bool drawRollSpriteActor = (actor != nullptr && actor->renderflags & RF_ROLLSPRITE); - + const bool drawRollParticle = (particle != nullptr && particle->flags & SPF_ROLL); + const bool doRoll = (drawRollSpriteActor || drawRollParticle); // [fgsfds] check sprite type mask uint32_t spritetype = (uint32_t)-1; if (actor != nullptr) spritetype = actor->renderflags & RF_SPRITETYPEMASK; // [Nash] is a flat sprite - const bool isFlatSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE || spritetype == RF_FLATSPRITE); - const bool useOffsets = (actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER); + const bool isWallSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE); + const bool useOffsets = ((actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER)) || (particle && !(particle->flags & SPF_ROLLCENTER)); + FVector2 offset = FVector2( offx, offy ); + float xx = -center.X + x; + float yy = -center.Y + y; + float zz = -center.Z + z; // [Nash] check for special sprite drawing modes - if (drawWithXYBillboard || drawBillboardFacingCamera || drawRollSpriteActor || isFlatSprite) + if (drawWithXYBillboard || isWallSprite) { - // Compute center of sprite - float xcenter = (x1 + x2)*0.5; - float ycenter = (y1 + y2)*0.5; - float zcenter = (z1 + z2)*0.5; - float xx = -xcenter + x; - float zz = -zcenter + z; - float yy = -ycenter + y; - Matrix3x4 mat; mat.MakeIdentity(); - mat.Translate(xcenter, zcenter, ycenter); // move to sprite center + mat.Translate(center.X, center.Z, center.Y); // move to sprite center + mat.Scale(1.0, 1.0/pixelstretch, 1.0); // unstretch sprite by level aspect ratio + + // [MC] Sprite offsets. + if (!offset.isZero()) + HandleSpriteOffsets(&mat, &HWAngles, &offset, true); - // Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down). - if (drawBillboardFacingCamera && !isFlatSprite) + // Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down). + if (drawBillboardFacingCamera && !isWallSprite) { // [CMB] Rotate relative to camera XY position, not just camera direction, // which is nicer in VR - float xrel = xcenter - vp->X; - float yrel = ycenter - vp->Y; - float absAngleDeg = RAD2DEG(atan2(-yrel, xrel)); - float counterRotationDeg = 270. - HWAngles.Yaw.Degrees; // counteracts existing sprite rotation + float xrel = center.X - vp->X; + float yrel = center.Y - vp->Y; + float absAngleDeg = atan2(-yrel, xrel) * (180 / M_PI); + float counterRotationDeg = 270. - HWAngles.Yaw.Degrees(); // counteracts existing sprite rotation float relAngleDeg = counterRotationDeg + absAngleDeg; mat.Rotate(0, 1, 0, relAngleDeg); } // [fgsfds] calculate yaw vectors - float yawvecX = 0, yawvecY = 0, rollDegrees = 0; - float angleRad = (270. - HWAngles.Yaw).Radians(); - if (actor) rollDegrees = Angles.Roll.Degrees; - if (isFlatSprite) - { - yawvecX = Angles.Yaw.Cos(); - yawvecY = Angles.Yaw.Sin(); - } + float rollDegrees = doRoll ? Angles.Roll.Degrees() : 0; + float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians(); // [fgsfds] Rotate the sprite about the sight vector (roll) - if (spritetype == RF_WALLSPRITE) + if (isWallSprite) { + float yawvecX = Angles.Yaw.Cos(); + float yawvecY = Angles.Yaw.Sin(); mat.Rotate(0, 1, 0, 0); if (drawRollSpriteActor) { - if (useOffsets) mat.Translate(xx, zz, yy); + + if (useOffsets) mat.Translate(xx, zz, yy); mat.Rotate(yawvecX, 0, yawvecY, rollDegrees); if (useOffsets) mat.Translate(-xx, -zz, -yy); } } - else if (drawRollSpriteActor) + else if (doRoll) { if (useOffsets) mat.Translate(xx, zz, yy); if (drawWithXYBillboard) { - mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees); + mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees()); } mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); if (useOffsets) mat.Translate(-xx, -zz, -yy); @@ -431,10 +482,12 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) // Rotate the sprite about the vector starting at the center of the sprite // triangle strip and with direction orthogonal to where the player is looking // in the x/y plane. - mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees); + mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees()); } - mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center + mat.Scale(1.0, pixelstretch, 1.0); // stretch sprite by level aspect ratio + mat.Translate(-center.X, -center.Z, -center.Y); // retreat from sprite center + v[0] = mat * FVector3(x1, z1, y1); v[1] = mat * FVector3(x2, z1, y2); v[2] = mat * FVector3(x1, z2, y1); @@ -442,10 +495,52 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) } else // traditional "Y" billboard mode { - v[0] = FVector3(x1, z1, y1); - v[1] = FVector3(x2, z1, y2); - v[2] = FVector3(x1, z2, y1); - v[3] = FVector3(x2, z2, y2); + if (doRoll || !offset.isZero() || (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES))) + { + mat.MakeIdentity(); + + if (!offset.isZero()) + HandleSpriteOffsets(&mat, &HWAngles, &offset, false); + + if (doRoll) + { + // Compute center of sprite + float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians(); + float rollDegrees = Angles.Roll.Degrees(); + + mat.Translate(center.X, center.Z, center.Y); + mat.Scale(1.0, 1.0/pixelstretch, 1.0); // unstretch sprite by level aspect ratio + if (useOffsets) mat.Translate(xx, zz, yy); + mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); + if (useOffsets) mat.Translate(-xx, -zz, -yy); + mat.Scale(1.0, pixelstretch, 1.0); // stretch sprite by level aspect ratio + mat.Translate(-center.X, -center.Z, -center.Y); + } + + if (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES) && di->Viewpoint.IsOrtho()) + { + float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians(); + mat.Translate(center.X, center.Z, center.Y); + mat.Translate(0.0, z2 - center.Z, 0.0); + mat.Rotate(-sin(angleRad), 0, cos(angleRad), -actor->isotheta); + mat.Translate(0.0, center.Z - z2, 0.0); + mat.Translate(-center.X, -center.Z, -center.Y); + } + + v[0] = mat * FVector3(x1, z1, y1); + v[1] = mat * FVector3(x2, z1, y2); + v[2] = mat * FVector3(x1, z2, y1); + v[3] = mat * FVector3(x2, z2, y2); + + } + else + { + v[0] = FVector3(x1, z1, y1); + v[1] = FVector3(x2, z1, y2); + v[2] = FVector3(x1, z2, y1); + v[3] = FVector3(x2, z2, y2); + } + } return false; } @@ -459,7 +554,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) inline void HWSprite::PutSprite(HWDrawInfo *di, bool translucent) { // That's a lot of checks... - if (modelframe && !modelframe->isVoxel && RenderStyle.BlendOp != STYLEOP_Shadow && gl_light_sprites && di->Level->HasDynamicLights && !di->isFullbrightScene() && !fullbright) + if (modelframe && !modelframe->isVoxel && !(modelframeflags & MDL_NOPERPIXELLIGHTING) && RenderStyle.BlendOp != STYLEOP_Shadow && gl_light_sprites && di->Level->HasDynamicLights && !di->isFullbrightScene() && !fullbright) { hw_GetDynModelLight(actor, lightdata); dynlightindex = screen->mLights->UploadLights(lightdata); @@ -560,7 +655,7 @@ void HWSprite::PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingp const float NO_VAL = 100000000.0f; bool clipthing = (thing->player || thing->flags3&MF3_ISMONSTER || thing->IsKindOf(NAME_Inventory)) && (thing->flags&MF_ICECORPSE || !(thing->flags&MF_CORPSE)); bool smarterclip = !clipthing && gl_spriteclip == 3; - if (clipthing || gl_spriteclip > 1) + if ((clipthing || gl_spriteclip > 1) && !(thing->flags2 & MF2_FLOATBOB)) { float btm = NO_VAL; @@ -655,7 +750,7 @@ void HWSprite::PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingp // //========================================================================== -void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t in_area, int thruportal) +void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t in_area, int thruportal, bool isSpriteShadow) { sector_t rs; sector_t * rendersector; @@ -672,7 +767,15 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t return; } - const auto &vp = di->Viewpoint; +#if 0 + if (thing->IsKindOf(NAME_Corona)) + { + di->Coronas.Push(static_cast(thing)); + return; + } +#endif + + const auto &vp = di->Viewpoint; AActor *camera = vp.camera; if (thing->renderflags & RF_INVISIBLE || !thing->RenderStyle.IsVisible(thing->Alpha)) @@ -681,6 +784,8 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t return; } + nomipmap = (thing->renderflags2 & RF2_NOMIPMAP); + // check renderrequired vs ~r_rendercaps, if anything matches we don't support that feature, // check renderhidden vs r_rendercaps, if anything matches we do support that feature and should hide it. if ((!r_debug_disable_vis_filter && !!(thing->RenderRequired & ~r_renderercaps)) || @@ -688,7 +793,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t return; int spritenum = thing->sprite; - DVector2 sprscale = thing->Scale; + DVector2 sprscale(thing->Scale.X, thing->Scale.Y); if (thing->player != nullptr) { P_CheckPlayerSprite(thing, spritenum, sprscale); @@ -698,33 +803,57 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t DVector3 thingpos = thing->InterpolatedPosition(vp.TicFrac); if (thruportal == 1) thingpos += di->Level->Displacements.getOffset(thing->Sector->PortalGroup, sector->PortalGroup); + AActor *viewmaster = thing; + if ((thing->flags8 & MF8_MASTERNOSEE) && thing->master != nullptr) + { + viewmaster = thing->master; + } + + // [Nash] filter visibility in mirrors + bool isInMirror = di->mCurrentPortal && (di->mCurrentPortal->mState->MirrorFlag > 0 || di->mCurrentPortal->mState->PlaneMirrorFlag > 0); + if (thing->renderflags2 & RF2_INVISIBLEINMIRRORS && isInMirror) + { + return; + } + else if (thing->renderflags2 & RF2_ONLYVISIBLEINMIRRORS && !isInMirror) + { + return; + } // Some added checks if the camera actor is not supposed to be seen. It can happen that some portal setup has this actor in view in which case it may not be skipped here - if (thing == camera && !vp.showviewer) + if (viewmaster == camera && !vp.showviewer) { - DVector3 thingorigin = thing->Pos(); - if (thruportal == 1) thingorigin += di->Level->Displacements.getOffset(thing->Sector->PortalGroup, sector->PortalGroup); - if (fabs(thingorigin.X - vp.ActorPos.X) < 2 && fabs(thingorigin.Y - vp.ActorPos.Y) < 2) return; + if (vp.bForceNoViewer || (viewmaster->player && viewmaster->player->crossingPortal)) return; + DVector3 vieworigin = viewmaster->Pos(); + if (thruportal == 1) vieworigin += di->Level->Displacements.getOffset(viewmaster->Sector->PortalGroup, sector->PortalGroup); + if (fabs(vieworigin.X - vp.ActorPos.X) < 2 && fabs(vieworigin.Y - vp.ActorPos.Y) < 2) return; + + // Necessary in order to prevent sprite pop-ins with viewpos and models. + auto* sec = viewmaster->Sector; + if (sec && !sec->PortalBlocksMovement(sector_t::ceiling)) + { + double zh = sec->GetPortalPlaneZ(sector_t::ceiling); + double top = (viewmaster->player ? max(viewmaster->player->viewz, viewmaster->Top()) + 1 : viewmaster->Top()); + if (viewmaster->Z() < zh && top >= zh) + return; + } } // Thing is invisible if close to the camera. - if (thing->renderflags & RF_MAYBEINVISIBLE) + if (viewmaster->renderflags & RF_MAYBEINVISIBLE) { - if (fabs(thingpos.X - vp.Pos.X) < 32 && fabs(thingpos.Y - vp.Pos.Y) < 32) return; + DVector3 viewpos = viewmaster->InterpolatedPosition(vp.TicFrac); + if (thruportal == 1) viewpos += di->Level->Displacements.getOffset(viewmaster->Sector->PortalGroup, sector->PortalGroup); + if (fabs(viewpos.X - vp.Pos.X) < 32 && fabs(viewpos.Y - vp.Pos.Y) < 32) return; } + modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing, spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); + modelframeflags = modelframe ? modelframe->getFlags(thing->modelData) : 0; + // Too close to the camera. This doesn't look good if it is a sprite. - if (fabs(thingpos.X - vp.Pos.X) < 2 && fabs(thingpos.Y - vp.Pos.Y) < 2) + if (fabs(thingpos.X - vp.Pos.X) < 2 && fabs(thingpos.Y - vp.Pos.Y) < 2 + && vp.Pos.Z >= thingpos.Z - 2 && vp.Pos.Z <= thingpos.Z + thing->Height + 2 + && !thing->Vel.isZero() && !modelframe) // exclude vertically moving objects from this check. { - if (vp.Pos.Z >= thingpos.Z - 2 && vp.Pos.Z <= thingpos.Z + thing->Height + 2) - { - // exclude vertically moving objects from this check. - if (!thing->Vel.isZero()) - { - if (!FindModelFrame(thing->GetClass(), spritenum, thing->frame, false)) - { - return; - } - } - } + return; } // don't draw first frame of a player missile @@ -744,7 +873,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (thruportal != 2 && di->mClipPortal != nullptr) { - int clipres = di->mClipPortal->ClipPoint(thingpos); + int clipres = di->mClipPortal->ClipPoint(thingpos.XY()); if (clipres == PClip_InFront) return; } // disabled because almost none of the actual game code is even remotely prepared for this. If desired, use the INTERPOLATE flag. @@ -753,8 +882,6 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t else Angles = thing->Angles; - FloatRect r; - if (sector->sectornum != thing->Sector->sectornum && !thruportal) { // This cannot create a copy in the fake sector cache because it'd interfere with the main thread, so provide a local buffer for the copy. @@ -769,32 +896,69 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t bottomclip = rendersector->PortalBlocksMovement(sector_t::floor) ? -LARGE_VALUE : rendersector->GetPortalPlaneZ(sector_t::floor); uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK); - x = thingpos.X; - z = thingpos.Z; - y = thingpos.Y; + x = thingpos.X + thing->WorldOffset.X; + z = thingpos.Z + thing->WorldOffset.Z; + y = thingpos.Y + thing->WorldOffset.Y; if (spritetype == RF_FACESPRITE) z -= thing->Floorclip; // wall and flat sprites are to be considered di->Level-> geometry so this may not apply. + // snap shadow Z to the floor + if (isSpriteShadow) + { + z = thing->floorz; + } // [RH] Make floatbobbing a renderer-only effect. - if (thing->flags2 & MF2_FLOATBOB) + else { float fz = thing->GetBobOffset(vp.TicFrac); z += fz; } - modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); + // don't bother drawing sprite shadows if this is a model (it will never look right) + if (modelframe && isSpriteShadow) + { + return; + } if (!modelframe) { - bool mirror; + bool mirror = false; DAngle ang = (thingpos - vp.Pos).Angle(); + if (di->Viewpoint.IsOrtho()) ang = vp.Angles.Yaw; FTextureID patch; // [ZZ] add direct picnum override if (isPicnumOverride) { // Animate picnum overrides. - auto tex = TexMan.GetTexture(thing->picnum, true); + auto tex = TexMan.GetGameTexture(thing->picnum, true); if (tex == nullptr) return; + + if (tex->GetRotations() != 0xFFFF) + { + // choose a different rotation based on player view + spriteframe_t* sprframe = &SpriteFrames[tex->GetRotations()]; + DAngle sprang = thing->GetSpriteAngle(ang, vp.TicFrac); + angle_t rot; + if (sprframe->Texture[0] == sprframe->Texture[1]) + { + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + DAngle::fromDeg(45.0 / 2 * 9)).BAMs() >> 28; + else + rot = (sprang - (thing->Angles.Yaw + thing->SpriteRotation) + DAngle::fromDeg(45.0 / 2 * 9)).BAMs() >> 28; + } + else + { + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + DAngle::fromDeg(45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + else + rot = (sprang - (thing->Angles.Yaw + thing->SpriteRotation) + DAngle::fromDeg(45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + } + auto picnum = sprframe->Texture[rot]; + if (sprframe->Flip & (1 << rot)) + { + mirror = true; + } + } + patch = tex->GetID(); - mirror = false; } else { @@ -808,7 +972,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t else { // Flat sprites cannot rotate in a predictable manner. - sprangle = 0.; + sprangle = nullAngle; rot = 0; } patch = sprites[spritenum].GetSpriteFrame(thing->frame, rot, sprangle, &mirror, !!(thing->renderflags & RF_SPRITEFLIP)); @@ -816,15 +980,18 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (!patch.isValid()) return; int type = thing->renderflags & RF_SPRITETYPEMASK; - gltexture = FMaterial::ValidateTexture(patch, (type == RF_FACESPRITE), false); - if (!gltexture) - return; + auto tex = TexMan.GetGameTexture(patch, false); + if (!tex || !tex->isValid()) return; + auto& spi = tex->GetSpritePositioning(type == RF_FACESPRITE); - vt = gltexture->GetSpriteVT(); - vb = gltexture->GetSpriteVB(); + offx = (float)thing->GetSpriteOffset(false); + offy = (float)thing->GetSpriteOffset(true); + + vt = spi.GetSpriteVT(); + vb = spi.GetSpriteVB(); if (thing->renderflags & RF_YFLIP) std::swap(vt, vb); - gltexture->GetSpriteRect(&r); + auto r = spi.GetSpriteRect(); // [SP] SpriteFlip if (thing->renderflags & RF_SPRITEFLIP) @@ -833,60 +1000,102 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (mirror ^ !!(thing->renderflags & RF_XFLIP)) { r.left = -r.width - r.left; // mirror the sprite's x-offset - ul = gltexture->GetSpriteUL(); - ur = gltexture->GetSpriteUR(); + ul = spi.GetSpriteUL(); + ur = spi.GetSpriteUR(); } else { - ul = gltexture->GetSpriteUR(); - ur = gltexture->GetSpriteUL(); + ul = spi.GetSpriteUR(); + ur = spi.GetSpriteUL(); } + texture = tex; + if (!texture || !texture->isValid()) + return; + if (thing->renderflags & RF_SPRITEFLIP) // [SP] Flip back thing->renderflags ^= RF_XFLIP; - r.Scale(sprscale.X, sprscale.Y); + // If sprite is isometric, do both vertical scaling and partial rotation to face the camera to compensate for Y-billboarding. + // Using just rotation (about z=0) might cause tall+slender (high aspect ratio) sprites to clip out of collision box + // at the top and clip into whatever is behind them from the viewpoint's perspective. - [DVR] + thing->isoscaleY = 1.0; + thing->isotheta = vp.HWAngles.Pitch.Degrees(); + if (thing->renderflags2 & RF2_ISOMETRICSPRITES) + { + float floordist = thing->radius * vp.floordistfact; + floordist -= 0.5 * r.width * vp.cotfloor; + float sineisotheta = floordist / r.height; + double scl = g_sqrt( 1.0 + sineisotheta * sineisotheta - 2.0 * vp.PitchSin * sineisotheta ); + if ((thing->radius > 0.0) && (scl > fabs(vp.PitchCos))) + { + thing->isoscaleY = scl / ( fabs(vp.PitchCos) > 0.01 ? fabs(vp.PitchCos) : 0.01 ); + thing->isotheta = 180.0 * asin( sineisotheta / thing->isoscaleY ) / M_PI; + } + } + + r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 * thing->isoscaleY : sprscale.Y * thing->isoscaleY); + + if (thing->renderflags & (RF_ROLLSPRITE|RF_FLATSPRITE)) + { + double ps = di->Level->pixelstretch; + double mult = 1.0 / sqrt(ps); // shrink slightly + r.Scale(mult * ps, mult); + } float rightfac = -r.left; float leftfac = rightfac - r.width; - float bottomfac = -r.top; - float topfac = bottomfac - r.height; z1 = z - r.top; z2 = z1 - r.height; - float spriteheight = sprscale.Y * r.height; + float spriteheight = sprscale.Y * r.height * thing->isoscaleY; // Tests show that this doesn't look good for many decorations and corpses if (spriteheight > 0 && gl_spriteclip > 0 && (thing->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE) { - PerformSpriteClipAdjustment(thing, thingpos, spriteheight); + PerformSpriteClipAdjustment(thing, thingpos.XY(), spriteheight); } - float viewvecX; - float viewvecY; switch (spritetype) { case RF_FACESPRITE: - viewvecX = vp.ViewVector.X; - viewvecY = vp.ViewVector.Y; + { + float viewvecX = vp.ViewVector.X; + float viewvecY = vp.ViewVector.Y; x1 = x - viewvecY*leftfac; x2 = x - viewvecY*rightfac; y1 = y + viewvecX*leftfac; y2 = y + viewvecX*rightfac; + if (thing->renderflags2 & RF2_ISOMETRICSPRITES) // If sprites are drawn from an isometric perspective + { + x1 -= viewvecX * thing->radius * MY_SQRT2; + x2 -= viewvecX * thing->radius * MY_SQRT2; + y1 -= viewvecY * thing->radius * MY_SQRT2; + y2 -= viewvecY * thing->radius * MY_SQRT2; + } break; - + } case RF_FLATSPRITE: { + float bottomfac = -r.top; + float topfac = bottomfac - r.height; + x1 = x + leftfac; x2 = x + rightfac; y1 = y - topfac; y2 = y - bottomfac; + // [MC] Counteract in case of any potential problems. Tests so far haven't + // shown any outstanding issues but that doesn't mean they won't appear later + // when more features are added. + z1 += offy; + z2 += offy; + break; } - break; case RF_WALLSPRITE: - viewvecX = Angles.Yaw.Cos(); - viewvecY = Angles.Yaw.Sin(); + { + float viewvecX = Angles.Yaw.Cos(); + float viewvecY = Angles.Yaw.Sin(); x1 = x + viewvecY*leftfac; x2 = x + viewvecY*rightfac; @@ -894,16 +1103,19 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t y2 = y - viewvecX*rightfac; break; } + } } else { x1 = x2 = x; y1 = y2 = y; z1 = z2 = z; - gltexture = nullptr; + texture = nullptr; } depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin); + if(thing->renderflags2 & RF2_ISOMETRICSPRITES) depth = depth * vp.PitchCos - vp.PitchSin * z2; // Helps with stacking actors with small xy offsets + if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite. // light calculation @@ -912,12 +1124,12 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t // allow disabling of the fullbright flag by a brightmap definition // (e.g. to do the gun flashes of Doom's zombies correctly. fullbright = (thing->flags5 & MF5_BRIGHT) || - ((thing->renderflags & RF_FULLBRIGHT) && (!gltexture || !gltexture->tex->isFullbrightDisabled())); + ((thing->renderflags & RF_FULLBRIGHT) && (!texture || !texture->isFullbrightDisabled())); + + if (fullbright) lightlevel = 255; + else lightlevel = hw_ClampLight(thing->GetLightLevel(rendersector)); - lightlevel = fullbright ? 255 : - hw_ClampLight(rendersector->GetTexture(sector_t::ceiling) == skyflatnum ? - rendersector->GetCeilingLight() : rendersector->GetFloorLight()); - foglevel = (uint8_t)clamp(rendersector->lightlevel, 0, 255); + foglevel = (uint8_t)clamp(rendersector->lightlevel, 0, 255); // this *must* use the sector's light level or the fog will just look bad. lightlevel = rendersector->CheckSpriteGlow(lightlevel, thingpos); @@ -1019,7 +1231,11 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t // This is a non-translucent sprite (i.e. STYLE_Normal or equivalent) trans = 1.f; - if (!gl_sprite_blend || modelframe || (thing->renderflags & (RF_FLATSPRITE | RF_WALLSPRITE)) || gl_billboard_faces_camera) + if (!gl_sprite_blend || modelframe || + (thing->renderflags & (RF_FLATSPRITE | RF_WALLSPRITE)) || + (hw_force_cambbpref ? gl_billboard_faces_camera : + (gl_billboard_faces_camera && !(thing->renderflags2 & RF2_BILLBOARDNOFACECAMERA)) || + thing->renderflags2 & RF2_BILLBOARDFACECAMERA)) { RenderStyle.SrcAlpha = STYLEALPHA_One; RenderStyle.DestAlpha = STYLEALPHA_Zero; @@ -1031,7 +1247,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t RenderStyle.DestAlpha = STYLEALPHA_InvSrc; } } - if ((gltexture && gltexture->tex->GetTranslucency()) || (RenderStyle.Flags & STYLEF_RedIsAlpha) || (modelframe && thing->RenderStyle != DefaultRenderStyle())) + if ((texture && texture->GetTranslucency()) || (RenderStyle.Flags & STYLEF_RedIsAlpha) || (modelframe && thing->RenderStyle != DefaultRenderStyle())) { if (hw_styleflags == STYLEHW_Solid) { @@ -1058,12 +1274,34 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t } } + // for sprite shadow, use a translucent stencil renderstyle + if (isSpriteShadow) + { + RenderStyle = STYLE_Stencil; + ThingColor = MAKEARGB(255, 0, 0, 0); + // fade shadow progressively as the thing moves higher away from the floor + if (r_actorspriteshadowfadeheight > 0.0) { + trans *= clamp(0.0f, float(r_actorspriteshadowalpha - (thingpos.Z - thing->floorz) * (1.0 / r_actorspriteshadowfadeheight)), float(r_actorspriteshadowalpha)); + } else { + trans *= r_actorspriteshadowalpha; + } + hw_styleflags = STYLEHW_NoAlphaTest; + } + if (trans == 0.0f) return; // end of light calculation actor = thing; index = thing->SpawnOrder; + + // sprite shadows should have a fixed index of -1 (ensuring they're drawn behind particles which have index 0) + // sorting should be irrelevant since they're always translucent + if (isSpriteShadow) + { + index = -1; + } + particle = nullptr; const bool drawWithXYBillboard = (!(actor->renderflags & RF_FORCEYBILLBOARD) @@ -1097,7 +1335,6 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t { lightlist = nullptr; } - PutSprite(di, hw_styleflags != STYLEHW_Solid); rendered_sprites++; } @@ -1109,19 +1346,34 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t // //========================================================================== -void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *sector)//, int shade, int fakeside) +void HWSprite::ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *sector, DVisualThinker *spr)//, int shade, int fakeside) { - if (particle->alpha==0) return; + if (!particle || particle->alpha <= 0) + return; - lightlevel = hw_ClampLight(sector->GetTexture(sector_t::ceiling) == skyflatnum ? - sector->GetCeilingLight() : sector->GetFloorLight()); + if (spr && spr->PT.texture.isNull()) + return; + + lightlevel = hw_ClampLight(spr ? spr->GetLightLevel(sector) : sector->GetSpriteLight()); foglevel = (uint8_t)clamp(sector->lightlevel, 0, 255); + trans = particle->alpha; + OverrideShader = 0; + modelframe = nullptr; + texture = nullptr; + topclip = LARGE_VALUE; + bottomclip = -LARGE_VALUE; + index = 0; + actor = nullptr; + this->particle = particle; + fullbright = particle->flags & SPF_FULLBRIGHT; + nomipmap = particle->flags & SPF_NOMIPMAP; + if (di->isFullbrightScene()) { Colormap.Clear(); } - else if (!particle->bright) + else if (!(particle->flags & SPF_FULLBRIGHT)) { TArray & lightlist=sector->e->XFloor.lightlist; double lightbottom; @@ -1151,84 +1403,117 @@ void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t * Colormap.ClearColor(); } - trans=particle->alpha; - RenderStyle = STYLE_Translucent; - OverrideShader = 0; + if(particle->style != STYLE_None) + { + RenderStyle = particle->style; + } + else + { + RenderStyle = STYLE_Translucent; + } ThingColor = particle->color; ThingColor.a = 255; + const auto& vp = di->Viewpoint; - modelframe=nullptr; - gltexture=nullptr; - topclip = LARGE_VALUE; - bottomclip = -LARGE_VALUE; - index = 0; + double timefrac = vp.TicFrac; + if (paused || (di->Level->isFrozen() && !(particle->flags & SPF_NOTIMEFREEZE))) + timefrac = 0.; - // [BB] Load the texture for round or smooth particles - if (gl_particles_style) + if (spr) { - FTextureID lump; - if (gl_particles_style == 1) - { - lump = TexMan.glPart2; - } - else if (gl_particles_style == 2) - { - lump = TexMan.glPart; - } - else lump.SetNull(); + AdjustVisualThinker(di, spr, sector); + } + else + { + bool has_texture = particle->texture.isValid(); + bool custom_animated_texture = (particle->flags & SPF_LOCAL_ANIM) && particle->animData.ok; + + int particle_style = has_texture ? 2 : gl_particles_style; // Treat custom texture the same as smooth particles - if (lump.isValid()) + // [BB] Load the texture for round or smooth particles + if (particle_style) { - gltexture = FMaterial::ValidateTexture(lump, true, false); - translation = 0; - - ul = gltexture->GetUL(); - ur = gltexture->GetUR(); - vt = gltexture->GetVT(); - vb = gltexture->GetVB(); - FloatRect r; - gltexture->GetSpriteRect(&r); + FTextureID lump; + if (particle_style == 1) + { + lump = TexMan.glPart2; + } + else if (particle_style == 2) + { + if(custom_animated_texture) + { + lump = TexAnim.UpdateStandaloneAnimation(particle->animData, di->Level->maptime + timefrac); + } + else if(has_texture) + { + lump = particle->texture; + } + else + { + lump = TexMan.glPart; + } + } + else + { + lump.SetNull(); + } + + if (lump.isValid()) + { + translation = NO_TRANSLATION; + + ul = vt = 0; + ur = vb = 1; + + texture = TexMan.GetGameTexture(lump, !custom_animated_texture); + } } - } - const auto &vp = di->Viewpoint; - double timefrac = vp.TicFrac; - if (paused || di->Level->isFrozen()) - timefrac = 0.; - float xvf = (particle->Vel.X) * timefrac; - float yvf = (particle->Vel.Y) * timefrac; - float zvf = (particle->Vel.Z) * timefrac; - x = float(particle->Pos.X) + xvf; - y = float(particle->Pos.Y) + yvf; - z = float(particle->Pos.Z) + zvf; + float xvf = (particle->Vel.X) * timefrac; + float yvf = (particle->Vel.Y) * timefrac; + float zvf = (particle->Vel.Z) * timefrac; + + offx = 0.f; + offy = 0.f; + + x = float(particle->Pos.X) + xvf; + y = float(particle->Pos.Y) + yvf; + z = float(particle->Pos.Z) + zvf; + + if(particle->flags & SPF_ROLL) + { + float rvf = (particle->RollVel) * timefrac; + Angles.Roll = TAngle::fromDeg(particle->Roll + rvf); + } - float factor; - if (gl_particles_style == 1) factor = 1.3f / 7.f; - else if (gl_particles_style == 2) factor = 2.5f / 7.f; - else factor = 1 / 7.f; - float scalefac=particle->size * factor; + float factor; + if (particle_style == 1) factor = 1.3f / 7.f; + else if (particle_style == 2) factor = 2.5f / 7.f; + else factor = 1 / 7.f; + float scalefac=particle->size * factor; - float viewvecX = vp.ViewVector.X; - float viewvecY = vp.ViewVector.Y; + float ps = di->Level->pixelstretch; + + scalefac /= sqrt(ps); // shrink it slightly to account for the stretch - x1=x+viewvecY*scalefac; - x2=x-viewvecY*scalefac; - y1=y-viewvecX*scalefac; - y2=y+viewvecX*scalefac; - z1=z-scalefac; - z2=z+scalefac; + float viewvecX = vp.ViewVector.X * scalefac * ps; + float viewvecY = vp.ViewVector.Y * scalefac; - depth = FloatToFixed((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin); + x1=x+viewvecY; + x2=x-viewvecY; + y1=y-viewvecX; + y2=y+viewvecX; + z1=z-scalefac; + z2=z+scalefac; - actor=nullptr; - this->particle=particle; - fullbright = !!particle->bright; + depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin); - // [BB] Translucent particles have to be rendered without the alpha test. - if (gl_particles_style != 2 && trans>=1.0f-FLT_EPSILON) hw_styleflags = STYLEHW_Solid; - else hw_styleflags = STYLEHW_NoAlphaTest; + // [BB] Translucent particles have to be rendered without the alpha test. + if (particle_style != 2 && trans>=1.0f-FLT_EPSILON) hw_styleflags = STYLEHW_Solid; + else hw_styleflags = STYLEHW_NoAlphaTest; + } if (sector->e->XFloor.lightlist.Size() != 0 && !di->isFullbrightScene() && !fullbright) lightlist = §or->e->XFloor.lightlist; @@ -1239,6 +1524,82 @@ void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t * rendered_sprites++; } +// [MC] VisualThinkers are to be rendered akin to actor sprites. The reason this whole system +// is hitching a ride on particle_t is because of the large number of checks with +// HWSprite elsewhere in the draw lists. +void HWSprite::AdjustVisualThinker(HWDrawInfo* di, DVisualThinker* spr, sector_t* sector) +{ + translation = spr->Translation; + + const auto& vp = di->Viewpoint; + double timefrac = vp.TicFrac; + + if (paused || spr->isFrozen()) + timefrac = 0.; + + bool custom_anim = ((spr->PT.flags & SPF_LOCAL_ANIM) && spr->PT.animData.ok); + + texture = TexMan.GetGameTexture( + custom_anim + ? TexAnim.UpdateStandaloneAnimation(spr->PT.animData, di->Level->maptime + timefrac) + : spr->PT.texture, !custom_anim); + + if (spr->bDontInterpolate) + timefrac = 0.; + + FVector3 interp = spr->InterpolatedPosition(timefrac); + x = interp.X; + y = interp.Y; + z = interp.Z; + + offx = (float)spr->GetOffset(false); + offy = (float)spr->GetOffset(true); + + if (spr->PT.flags & SPF_ROLL) + Angles.Roll = TAngle::fromDeg(spr->InterpolatedRoll(timefrac)); + + auto& spi = texture->GetSpritePositioning(0); + + vt = spi.GetSpriteVT(); + vb = spi.GetSpriteVB(); + ul = spi.GetSpriteUR(); + ur = spi.GetSpriteUL(); + + auto r = spi.GetSpriteRect(); + r.Scale(spr->Scale.X, spr->Scale.Y); + + if (spr->PT.flags & SPF_ROLL) + { + double ps = di->Level->pixelstretch; + double mult = 1.0 / sqrt(ps); // shrink slightly + r.Scale(mult * ps, mult); + } + + if (spr->bXFlip) + { + std::swap(ul,ur); + r.left = -r.width - r.left; // mirror the sprite's x-offset + } + if (spr->bYFlip) std::swap(vt,vb); + + float viewvecX = vp.ViewVector.X; + float viewvecY = vp.ViewVector.Y; + float rightfac = -r.left; + float leftfac = rightfac - r.width; + + x1 = x - viewvecY * leftfac; + x2 = x - viewvecY * rightfac; + y1 = y + viewvecX * leftfac; + y2 = y + viewvecX * rightfac; + z1 = z - r.top; + z2 = z1 - r.height; + + depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin); + + // [BB] Translucent particles have to be rendered without the alpha test. + hw_styleflags = STYLEHW_NoAlphaTest; +} + //========================================================================== // // @@ -1274,11 +1635,33 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area) DVector3 newpos = savedpos; sector_t fakesector; - if (!vp.showviewer && th == vp.camera) + if (!vp.showviewer) { - if (fabs(savedpos.X - vp.ActorPos.X) < 2 && fabs(savedpos.Y - vp.ActorPos.Y) < 2) + AActor *viewmaster = th; + if ((th->flags8 & MF8_MASTERNOSEE) && th->master != nullptr) { - continue; + viewmaster = th->master; + } + + if (viewmaster == vp.camera) + { + DVector3 vieworigin = viewmaster->Pos(); + + if (fabs(vieworigin.X - vp.ActorPos.X) < 2 && fabs(vieworigin.Y - vp.ActorPos.Y) < 2) + { + // Same as the original position + continue; + } + + P_TranslatePortalXY(line, vieworigin.X, vieworigin.Y); + P_TranslatePortalZ(line, vieworigin.Z); + + if (fabs(vieworigin.X - vp.ActorPos.X) < 2 && fabs(vieworigin.Y - vp.ActorPos.Y) < 2) + { + // Same as the translated position + // (This is required for MASTERNOSEE actors with 3D models) + continue; + } } } @@ -1289,6 +1672,13 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area) th->Prev += newpos - savedpos; HWSprite spr; + + // [Nash] draw sprite shadow + if (R_ShouldDrawSpriteShadow(th)) + { + spr.Process(this, th, hw_FakeFlat(th->Sector, in_area, false, &fakesector), in_area, 2, true); + } + // This is called from the worker thread and must not alter the fake sector cache. spr.Process(this, th, hw_FakeFlat(th->Sector, in_area, false, &fakesector), in_area, 2); th->Angles.Yaw = savedangle; diff --git a/src/rendering/hwrenderer/scene/hw_walldispatcher.h b/src/rendering/hwrenderer/scene/hw_walldispatcher.h new file mode 100644 index 00000000000..23d9345348b --- /dev/null +++ b/src/rendering/hwrenderer/scene/hw_walldispatcher.h @@ -0,0 +1,80 @@ +#pragma once + +struct HWMissing +{ + side_t* side; + subsector_t* sub; + double plane; +}; + +struct HWMeshHelper +{ + TArray list; + TArray translucent; + TArray portals; + TArray lower; + TArray upper; +}; + + +struct HWWallDispatcher +{ + FLevelLocals* Level; + HWDrawInfo* di; + HWMeshHelper* mh; + ELightMode lightmode; + + HWWallDispatcher(HWDrawInfo* info) + { + Level = info->Level; + di = info; + mh = nullptr; + lightmode = info->lightmode; + } + + HWWallDispatcher(FLevelLocals* lev, HWMeshHelper* help, ELightMode lm) + { + Level = lev; + di = nullptr; + mh = help; + lightmode = lm; + } + + void AddUpperMissingTexture(side_t* side, subsector_t* sub, float height) + { + if (di) di->AddUpperMissingTexture(side, sub, height); + else + { + mh->upper.Reserve(1); + mh->upper.Last() = { side, sub, height }; + } + } + void AddLowerMissingTexture(side_t* side, subsector_t* sub, float height) + { + if (di) di->AddLowerMissingTexture(side, sub, height); + else + { + mh->lower.Reserve(1); + mh->lower.Last() = { side, sub, height }; + } + } + + bool isFullbrightScene() + { + // The mesh builder cannot know this and must treat everything as not fullbright. + return di && di->isFullbrightScene(); + } + + void AddWall(HWWall* wal) + { + if (di) di->AddWall(wal); + else if (!(wal->flags & HWWall::HWF_TRANSLUCENT)) mh->list.Push(*wal); + else mh->translucent.Push(*wal); + } + + void AddPortal(HWWall* wal) + { + mh->portals.Push(*wal); + } + +}; diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index ac456487c79..5c5e357d559 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -22,6 +22,7 @@ #include "p_local.h" #include "p_lnspec.h" +#include "a_dynlight.h" #include "a_sharedglobal.h" #include "r_defs.h" #include "r_sky.h" @@ -30,17 +31,48 @@ #include "doomdata.h" #include "g_levellocals.h" #include "actorinlines.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_lighting.h" +#include "texturemanager.h" +#include "hw_dynlightdata.h" +#include "hw_material.h" +#include "hw_cvars.h" +#include "hw_clock.h" +#include "hw_lighting.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" +#include "hw_lightbuffer.h" #include "hw_renderstate.h" #include "hw_skydome.h" +#include "hw_walldispatcher.h" + + +void SetGlowPlanes(FRenderState &state, const secplane_t& top, const secplane_t& bottom) +{ + auto& tn = top.Normal(); + auto& bn = bottom.Normal(); + FVector4 tp = { (float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD() }; + FVector4 bp = { (float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD() }; + state.SetGlowPlanes(tp, bp); +} + +void SetGradientPlanes(FRenderState& state, const secplane_t& top, const secplane_t& bottom) +{ + auto& tn = top.Normal(); + auto& bn = bottom.Normal(); + FVector4 tp = { (float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD() }; + FVector4 bp = { (float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD() }; + state.SetGradientPlanes(tp, bp); +} + +void SetSplitPlanes(FRenderState& state, const secplane_t& top, const secplane_t& bottom) +{ + auto& tn = top.Normal(); + auto& bn = bottom.Normal(); + FVector4 tp = { (float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD() }; + FVector4 bp = { (float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD() }; + state.SetSplitPlanes(tp, bp); +} + //========================================================================== // @@ -49,12 +81,18 @@ // //========================================================================== -void HWWall::RenderWall(HWDrawInfo *di, FRenderState &state, int textured) +void HWWall::RenderWall(FRenderState &state, int textured) { + if (seg->sidedef->Flags & WALLF_DITHERTRANS) state.SetEffect(EFF_DITHERTRANS); assert(vertcount > 0); state.SetLightIndex(dynlightindex); state.Draw(DT_TriangleFan, vertindex, vertcount); vertexcount += vertcount; + if (seg->sidedef->Flags & WALLF_DITHERTRANS) + { + state.SetEffect(EFF_NONE); + seg->sidedef->Flags &= ~WALLF_DITHERTRANS; // reset this every frame + } } //========================================================================== @@ -63,17 +101,17 @@ void HWWall::RenderWall(HWDrawInfo *di, FRenderState &state, int textured) // //========================================================================== -void HWWall::RenderFogBoundary(HWDrawInfo *di, FRenderState &state) +void HWWall::RenderFogBoundary(HWWallDispatcher*di, FRenderState &state) { if (gl_fogmode && !di->isFullbrightScene()) { int rel = rellight + getExtraLight(); state.EnableDrawBufferAttachments(false); - di->SetFog(state, lightlevel, rel, false, &Colormap, false); + SetFog(state, di->Level, di->lightmode, lightlevel, rel, false, &Colormap, false); state.SetEffect(EFF_FOGBOUNDARY); state.AlphaFunc(Alpha_GEqual, 0.f); state.SetDepthBias(-1, -128); - RenderWall(di, state, HWWall::RWF_BLANK); + RenderWall(state, HWWall::RWF_BLANK); state.ClearDepthBias(); state.SetEffect(EFF_NONE); state.EnableDrawBufferAttachments(true); @@ -86,7 +124,7 @@ void HWWall::RenderFogBoundary(HWDrawInfo *di, FRenderState &state) // // //========================================================================== -void HWWall::RenderMirrorSurface(HWDrawInfo *di, FRenderState &state) +void HWWall::RenderMirrorSurface(HWWallDispatcher*di, FRenderState &state) { if (!TexMan.mirrorTexture.isValid()) return; @@ -97,16 +135,16 @@ void HWWall::RenderMirrorSurface(HWDrawInfo *di, FRenderState &state) // Use sphere mapping for this state.SetEffect(EFF_SPHEREMAP); - di->SetColor(state, lightlevel, 0, di->isFullbrightScene(), Colormap, 0.1f); - di->SetFog(state, lightlevel, 0, di->isFullbrightScene(), &Colormap, true); + SetColor(state, di->Level, di->lightmode, lightlevel, 0, di->isFullbrightScene(), Colormap, 0.1f); + SetFog(state, di->Level, di->lightmode, lightlevel, 0, di->isFullbrightScene(), &Colormap, true); state.SetRenderStyle(STYLE_Add); state.AlphaFunc(Alpha_Greater, 0); - FMaterial * pat = FMaterial::ValidateTexture(TexMan.mirrorTexture, false, false); - state.SetMaterial(pat, CLAMP_NONE, 0, -1); + auto tex = TexMan.GetGameTexture(TexMan.mirrorTexture, false); + state.SetMaterial(tex, UF_None, 0, CLAMP_NONE, NO_TRANSLATION, -1); // do not upscale the mirror texture. flags &= ~HWWall::HWF_GLOW; - RenderWall(di, state, HWWall::RWF_BLANK); + RenderWall(state, HWWall::RWF_BLANK); state.EnableTextureMatrix(false); state.SetEffect(EFF_NONE); @@ -117,9 +155,9 @@ void HWWall::RenderMirrorSurface(HWDrawInfo *di, FRenderState &state) // This is drawn in the translucent pass which is done after the decal pass // As a result the decals have to be drawn here, right after the wall they are on, // because the depth buffer won't get set by translucent items. - if (seg->sidedef->AttachedDecals) + if (di->di && seg->sidedef->AttachedDecals) { - DrawDecalsForMirror(di, state, di->Decals[1]); + DrawDecalsForMirror(di->di, state, di->di->Decals[1]); } state.SetRenderStyle(STYLE_Translucent); } @@ -144,7 +182,11 @@ static const uint8_t renderwalltotier[] = side_t::mid, }; -void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) +#ifdef NPOT_EMULATION +CVAR(Bool, hw_npottest, false, 0) +#endif + +void HWWall::RenderTexturedWall(HWWallDispatcher*di, FRenderState &state, int rflags) { int tmode = state.GetTextureMode(); int rel = rellight + getExtraLight(); @@ -153,17 +195,34 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) { state.EnableGlow(true); state.SetGlowParams(topglowcolor, bottomglowcolor); - state.SetGlowPlanes(frontsector->ceilingplane, frontsector->floorplane); + SetGlowPlanes(state, frontsector->ceilingplane, frontsector->floorplane); + } + state.SetMaterial(texture, UF_Texture, 0, flags & 3, NO_TRANSLATION, -1); +#ifdef NPOT_EMULATION + // Test code, could be reactivated as a compatibility option in the unlikely event that some old vanilla map eve needs it. + if (hw_npottest) + { + int32_t size = xs_CRoundToInt(texture->GetDisplayHeight()); + int32_t size2; + for (size2 = 1; size2 < size; size2 += size2) {} + if (size == size2) + state.SetNpotEmulation(0.f, 0.f); + else + { + float xOffset = 1.f / texture->GetDisplayWidth(); + state.SetNpotEmulation((1.f * size2) / size, xOffset); + } + } +#endif + + if (flags & HWWall::HWF_CLAMPY && (type == RENDERWALL_M2S || type == RENDERWALL_M2SNF) && !texture->isWarped()) + { + state.SetTextureClamp(true); } - state.SetMaterial(gltexture, flags & 3, 0, -1); if (type == RENDERWALL_M2SNF) { - if (flags & HWWall::HWF_CLAMPY) - { - if (tmode == TM_NORMAL) state.SetTextureMode(TM_CLAMPY); - } - di->SetFog(state, 255, 0, di->isFullbrightScene(), nullptr, false); + SetFog(state, di->Level, di->lightmode, 255, 0, di->isFullbrightScene(), nullptr, false); } if (type != RENDERWALL_COLOR && seg->sidedef != nullptr) { @@ -189,20 +248,20 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) { if (tierndx == side_t::top) { - state.SetGradientPlanes(frontsector->ceilingplane, backsector->ceilingplane); + SetGradientPlanes(state, frontsector->ceilingplane, backsector->ceilingplane); } else if (tierndx == side_t::mid) { - state.SetGradientPlanes(backsector->ceilingplane, backsector->floorplane); + SetGradientPlanes(state, backsector->ceilingplane, backsector->floorplane); } else // side_t::bottom: { - state.SetGradientPlanes(backsector->floorplane, frontsector->floorplane); + SetGradientPlanes(state, backsector->floorplane, frontsector->floorplane); } } else { - state.SetGradientPlanes(frontsector->ceilingplane, frontsector->floorplane); + SetGradientPlanes(state, frontsector->ceilingplane, frontsector->floorplane); } } } @@ -211,9 +270,9 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) float absalpha = fabsf(alpha); if (lightlist == nullptr) { - if (type != RENDERWALL_M2SNF) di->SetFog(state, lightlevel, rel, di->isFullbrightScene(), &Colormap, RenderStyle == STYLE_Add); - di->SetColor(state, lightlevel, rel, di->isFullbrightScene(), Colormap, absalpha); - RenderWall(di, state, rflags); + if (type != RENDERWALL_M2SNF) SetFog(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), &Colormap, RenderStyle == STYLE_Add); + SetColor(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), Colormap, absalpha); + RenderWall(state, rflags); } else { @@ -232,21 +291,23 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) FColormap thiscm; thiscm.FadeColor = Colormap.FadeColor; thiscm.FogDensity = Colormap.FogDensity; - thiscm.CopyFrom3DLight(&(*lightlist)[i]); - di->SetColor(state, thisll, rel, false, thiscm, absalpha); - if (type != RENDERWALL_M2SNF) di->SetFog(state, thisll, rel, false, &thiscm, RenderStyle == STYLE_Add); - state.SetSplitPlanes((*lightlist)[i].plane, lowplane); - RenderWall(di, state, rflags); + CopyFrom3DLight(thiscm, &(*lightlist)[i]); + SetColor(state, di->Level, di->lightmode, thisll, rel, false, thiscm, absalpha); + if (type != RENDERWALL_M2SNF) SetFog(state, di->Level, di->lightmode, thisll, rel, false, &thiscm, RenderStyle == STYLE_Add); + SetSplitPlanes(state, (*lightlist)[i].plane, lowplane); + RenderWall(state, rflags); } if (low1 <= zbottom[0] && low2 <= zbottom[1]) break; } state.EnableSplit(false); } + state.SetNpotEmulation(0.f, 0.f); state.SetObjectColor(0xffffffff); state.SetObjectColor2(0); state.SetAddColor(0); state.SetTextureMode(tmode); + state.SetTextureClamp(false); state.EnableGlow(false); state.EnableGradient(false); state.ApplyTextureManipulation(nullptr); @@ -258,22 +319,22 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) // //========================================================================== -void HWWall::RenderTranslucentWall(HWDrawInfo *di, FRenderState &state) +void HWWall::RenderTranslucentWall(HWWallDispatcher*di, FRenderState &state) { state.SetRenderStyle(RenderStyle); - if (gltexture) + if (texture) { - if (!gltexture->tex->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + if (!texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); else state.AlphaFunc(Alpha_GEqual, 0.f); RenderTexturedWall(di, state, HWWall::RWF_TEXTURED | HWWall::RWF_NOSPLIT); } else { state.AlphaFunc(Alpha_GEqual, 0.f); - di->SetColor(state, lightlevel, 0, false, Colormap, fabsf(alpha)); - di->SetFog(state, lightlevel, 0, false, &Colormap, RenderStyle == STYLE_Add); + SetColor(state, di->Level, di->lightmode, lightlevel, 0, false, Colormap, fabsf(alpha)); + SetFog(state, di->Level, di->lightmode, lightlevel, 0, false, &Colormap, RenderStyle == STYLE_Add); state.EnableTexture(false); - RenderWall(di, state, HWWall::RWF_NOSPLIT); + RenderWall(state, HWWall::RWF_NOSPLIT); state.EnableTexture(true); } state.SetRenderStyle(STYLE_Translucent); @@ -284,15 +345,15 @@ void HWWall::RenderTranslucentWall(HWDrawInfo *di, FRenderState &state) // // //========================================================================== -void HWWall::DrawWall(HWDrawInfo *di, FRenderState &state, bool translucent) +void HWWall::DrawWall(HWWallDispatcher*di, FRenderState &state, bool translucent) { if (screen->BuffersArePersistent()) { - if (di->Level->HasDynamicLights && !di->isFullbrightScene() && gltexture != nullptr) + if (di->di && di->Level->HasDynamicLights && !di->isFullbrightScene() && texture != nullptr) { - SetupLights(di, lightdata); + SetupLights(di->di, lightdata); } - MakeVertices(di, !!(flags & HWWall::HWF_TRANSLUCENT)); + MakeVertices(!!(flags & HWWall::HWF_TRANSLUCENT)); } state.SetNormal(glseg.Normal()); @@ -325,7 +386,7 @@ void HWWall::DrawWall(HWDrawInfo *di, FRenderState &state, bool translucent) // //========================================================================== -void HWWall::SetupLights(HWDrawInfo *di, FDynLightData &lightdata) +void HWWall::SetupLights(HWDrawInfo*di, FDynLightData &lightdata) { lightdata.Clear(); @@ -366,7 +427,7 @@ void HWWall::SetupLights(HWDrawInfo *di, FDynLightData &lightdata) // Iterate through all dynamic lights which touch this wall and render them while (node) { - if (node->lightsource->IsActive()) + if (node->lightsource->IsActive() && !node->lightsource->DontLightMap()) { iter_dlight++; @@ -411,7 +472,7 @@ void HWWall::SetupLights(HWDrawInfo *di, FDynLightData &lightdata) } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { - draw_dlight += lightdata.GetLight(seg->frontsector->PortalGroup, p, node->lightsource, true); + draw_dlight += GetLight(lightdata, seg->frontsector->PortalGroup, p, node->lightsource, true); } } } @@ -439,43 +500,69 @@ const char HWWall::passflag[] = { // // //========================================================================== -void HWWall::PutWall(HWDrawInfo *di, bool translucent) +void HWWall::PutWall(HWWallDispatcher *di, bool translucent) { - if (gltexture && gltexture->tex->GetTranslucency() && passflag[type] == 2) + if (texture && texture->GetTranslucency() && passflag[type] == 2) { translucent = true; } + + auto ddi = di->di; if (translucent) { flags |= HWF_TRANSLUCENT; - ViewDistance = (di->Viewpoint.Pos - (seg->linedef->v1->fPos() + seg->linedef->Delta() / 2)).XY().LengthSquared(); } - - if (di->isFullbrightScene()) - { - // light planes don't get drawn with fullbright rendering - if (gltexture == NULL) return; - Colormap.Clear(); - } - - if (di->isFullbrightScene() || (Colormap.LightColor.isWhite() && lightlevel == 255)) - flags &= ~HWF_GLOW; - - if (!screen->BuffersArePersistent()) + + if (di->di) { - if (di->Level->HasDynamicLights && !di->isFullbrightScene() && gltexture != nullptr) + if (translucent) { - SetupLights(di, lightdata); + ViewDistance = (ddi->Viewpoint.Pos - (seg->linedef->v1->fPos() + seg->linedef->Delta() / 2)).XY().LengthSquared(); } - MakeVertices(di, translucent); - } + if (ddi->isFullbrightScene()) + { + // light planes don't get drawn with fullbright rendering + if (texture == NULL) return; + Colormap.Clear(); + } + + if (ddi->isFullbrightScene() || (Colormap.LightColor.isWhite() && lightlevel == 255)) + { + flags &= ~HWF_GLOW; + } + + if (!screen->BuffersArePersistent()) + { + if (ddi->Level->HasDynamicLights && !ddi->isFullbrightScene() && texture != nullptr) + { + SetupLights(ddi, lightdata); + } + MakeVertices(translucent); + } + + + + bool solid; + if (passflag[type] == 1) solid = true; + else if (type == RENDERWALL_FFBLOCK) solid = texture && !texture->isMasked(); + else solid = false; + + bool hasDecals = solid && seg->sidedef && seg->sidedef->AttachedDecals; + if (hasDecals) + { + // If we want to use the light infos for the decal we cannot delay the creation until the render pass. + if (screen->BuffersArePersistent()) + { + if (ddi->Level->HasDynamicLights && !ddi->isFullbrightScene() && texture != nullptr) + { + SetupLights(ddi, lightdata); + } + } + ProcessDecals(ddi); + } + } - bool solid; - if (passflag[type] == 1) solid = true; - else if (type == RENDERWALL_FFBLOCK) solid = gltexture && !gltexture->isMasked(); - else solid = false; - if (solid) ProcessDecals(di); di->AddWall(this); @@ -492,114 +579,123 @@ void HWWall::PutWall(HWDrawInfo *di, bool translucent) // //========================================================================== -void HWWall::PutPortal(HWDrawInfo *di, int ptype, int plane) +void HWWall::PutPortal(HWWallDispatcher *di, int ptype, int plane) { - auto pstate = screen->mPortalState; HWPortal * portal = nullptr; - MakeVertices(di, false); - switch (ptype) + auto ddi = di->di; + if (ddi) { - // portals don't go into the draw list. - // Instead they are added to the portal manager - case PORTALTYPE_HORIZON: - horizon = pstate->UniqueHorizons.Get(horizon); - portal = di->FindPortal(horizon); - if (!portal) + MakeVertices(false); + switch (ptype) { - portal = new HWHorizonPortal(pstate, horizon, di->Viewpoint); - di->Portals.Push(portal); - } - portal->AddLine(this); - break; + // portals don't go into the draw list. + // Instead they are added to the portal manager + case PORTALTYPE_HORIZON: + horizon = portalState.UniqueHorizons.Get(horizon); + portal = ddi->FindPortal(horizon); + if (!portal) + { + portal = new HWHorizonPortal(&portalState, horizon, ddi->Viewpoint); + ddi->Portals.Push(portal); + } + portal->AddLine(this); + break; - case PORTALTYPE_SKYBOX: - portal = di->FindPortal(secportal); - if (!portal) - { - // either a regular skybox or an Eternity-style horizon - if (secportal->mType != PORTS_SKYVIEWPOINT) portal = new HWEEHorizonPortal(pstate, secportal); - else + case PORTALTYPE_SKYBOX: + portal = ddi->FindPortal(secportal); + if (!portal) { - portal = new HWSkyboxPortal(pstate, secportal); - di->Portals.Push(portal); + // either a regular skybox or an Eternity-style horizon + if (secportal->mType != PORTS_SKYVIEWPOINT) portal = new HWEEHorizonPortal(&portalState, secportal); + else + { + portal = new HWSkyboxPortal(&portalState, secportal); + ddi->Portals.Push(portal); + } } - } - portal->AddLine(this); - break; + portal->AddLine(this); + break; - case PORTALTYPE_SECTORSTACK: - portal = di->FindPortal(this->portal); - if (!portal) - { - portal = new HWSectorStackPortal(pstate, this->portal); - di->Portals.Push(portal); - } - portal->AddLine(this); - break; + case PORTALTYPE_SECTORSTACK: + portal = ddi->FindPortal(this->portal); + if (!portal) + { + portal = new HWSectorStackPortal(&portalState, this->portal); + ddi->Portals.Push(portal); + } + portal->AddLine(this); + break; - case PORTALTYPE_PLANEMIRROR: - if (pstate->PlaneMirrorMode * planemirror->fC() <= 0) - { - planemirror = pstate->UniquePlaneMirrors.Get(planemirror); - portal = di->FindPortal(planemirror); + case PORTALTYPE_PLANEMIRROR: + if (portalState.PlaneMirrorMode * planemirror->fC() <= 0) + { + planemirror = portalState.UniquePlaneMirrors.Get(planemirror); + portal = ddi->FindPortal(planemirror); + if (!portal) + { + portal = new HWPlaneMirrorPortal(&portalState, planemirror); + ddi->Portals.Push(portal); + } + portal->AddLine(this); + } + break; + + case PORTALTYPE_MIRROR: + portal = ddi->FindPortal(seg->linedef); if (!portal) { - portal = new HWPlaneMirrorPortal(pstate, planemirror); - di->Portals.Push(portal); + portal = new HWMirrorPortal(&portalState, seg->linedef); + ddi->Portals.Push(portal); } portal->AddLine(this); - } - break; + if (gl_mirror_envmap) + { + // draw a reflective layer over the mirror + ddi->AddMirrorSurface(this); + } + break; - case PORTALTYPE_MIRROR: - portal = di->FindPortal(seg->linedef); - if (!portal) - { - portal = new HWMirrorPortal(pstate, seg->linedef); - di->Portals.Push(portal); - } - portal->AddLine(this); - if (gl_mirror_envmap) - { - // draw a reflective layer over the mirror - di->AddMirrorSurface(this); - } - break; + case PORTALTYPE_LINETOLINE: + if (!lineportal) + return; + portal = ddi->FindPortal(lineportal); + if (!portal) + { + line_t* otherside = lineportal->lines[0]->mDestination; + if (otherside != nullptr && otherside->portalindex < ddi->Level->linePortals.Size()) + { + ddi->ProcessActorsInPortal(otherside->getPortal()->mGroup, ddi->in_area); + } + portal = new HWLineToLinePortal(&portalState, lineportal); + ddi->Portals.Push(portal); + } + portal->AddLine(this); + break; - case PORTALTYPE_LINETOLINE: - if (!lineportal) - return; - portal = di->FindPortal(lineportal); - if (!portal) - { - line_t *otherside = lineportal->lines[0]->mDestination; - if (otherside != nullptr && otherside->portalindex < di->Level->linePortals.Size()) + case PORTALTYPE_SKY: + sky = portalState.UniqueSkies.Get(sky); + portal = ddi->FindPortal(sky); + if (!portal) { - di->ProcessActorsInPortal(otherside->getPortal()->mGroup, di->in_area); + portal = new HWSkyPortal(screen->mSkyData, &portalState, sky); + ddi->Portals.Push(portal); } - portal = new HWLineToLinePortal(pstate, lineportal); - di->Portals.Push(portal); + portal->AddLine(this); + break; } - portal->AddLine(this); - break; + vertcount = 0; - case PORTALTYPE_SKY: - sky = pstate->UniqueSkies.Get(sky); - portal = di->FindPortal(sky); - if (!portal) + if (plane != -1 && portal) { - portal = new HWSkyPortal(screen->mSkyData, pstate, sky); - di->Portals.Push(portal); + portal->planesused |= (1 << plane); } - portal->AddLine(this); - break; } - vertcount = 0; - - if (plane != -1 && portal) + else { - portal->planesused |= (1<AddPortal(this); } } @@ -609,7 +705,7 @@ void HWWall::PutPortal(HWDrawInfo *di, int ptype, int plane) // //========================================================================== -void HWWall::Put3DWall(HWDrawInfo *di, lightlist_t * lightlist, bool translucent) +void HWWall::Put3DWall(HWWallDispatcher *di, lightlist_t * lightlist, bool translucent) { // only modify the light di->Level-> if it doesn't originate from the seg's frontsector. This is to account for light transferring effects if (lightlist->p_lightlevel != &seg->sidedef->sector->lightlevel) @@ -618,7 +714,7 @@ void HWWall::Put3DWall(HWDrawInfo *di, lightlist_t * lightlist, bool translucent } // relative light won't get changed here. It is constant across the entire wall. - Colormap.CopyFrom3DLight(lightlist); + CopyFrom3DLight(Colormap, lightlist); PutWall(di, translucent); } @@ -629,13 +725,13 @@ void HWWall::Put3DWall(HWDrawInfo *di, lightlist_t * lightlist, bool translucent // //========================================================================== -bool HWWall::SplitWallComplex(HWDrawInfo *di, sector_t * frontsector, bool translucent, float& maplightbottomleft, float& maplightbottomright) +bool HWWall::SplitWallComplex(HWWallDispatcher *di, sector_t * frontsector, bool translucent, float& maplightbottomleft, float& maplightbottomright) { // check for an intersection with the upper plane if ((maplightbottomleftztop[1]) || (maplightbottomleft>ztop[0] && maplightbottomright(fabsf(glseg.x2 - glseg.x1), fabsf(glseg.y2 - glseg.y1)); + float clen = max(fabsf(glseg.x2 - glseg.x1), fabsf(glseg.y2 - glseg.y1)); float dch = ztop[1] - ztop[0]; float dfh = maplightbottomright - maplightbottomleft; @@ -664,6 +760,10 @@ bool HWWall::SplitWallComplex(HWDrawInfo *di, sector_t * frontsector, bool trans copyWall1.tcs[UPRGT].v = copyWall2.tcs[UPLFT].v = tcs[UPLFT].v + coeff * (tcs[UPRGT].v - tcs[UPLFT].v); copyWall1.tcs[LORGT].u = copyWall2.tcs[LOLFT].u = tcs[LOLFT].u + coeff * (tcs[LORGT].u - tcs[LOLFT].u); copyWall1.tcs[LORGT].v = copyWall2.tcs[LOLFT].v = tcs[LOLFT].v + coeff * (tcs[LORGT].v - tcs[LOLFT].v); + copyWall1.lightuv[UPRGT].u = copyWall2.lightuv[UPLFT].u = lightuv[UPLFT].u + coeff * (lightuv[UPRGT].u - lightuv[UPLFT].u); + copyWall1.lightuv[UPRGT].v = copyWall2.lightuv[UPLFT].v = lightuv[UPLFT].v + coeff * (lightuv[UPRGT].v - lightuv[UPLFT].v); + copyWall1.lightuv[LORGT].u = copyWall2.lightuv[LOLFT].u = lightuv[LOLFT].u + coeff * (lightuv[LORGT].u - lightuv[LOLFT].u); + copyWall1.lightuv[LORGT].v = copyWall2.lightuv[LOLFT].v = lightuv[LOLFT].v + coeff * (lightuv[LORGT].v - lightuv[LOLFT].v); copyWall1.SplitWall(di, frontsector, translucent); copyWall2.SplitWall(di, frontsector, translucent); @@ -675,7 +775,7 @@ bool HWWall::SplitWallComplex(HWDrawInfo *di, sector_t * frontsector, bool trans if ((maplightbottomleftzbottom[1]) || (maplightbottomleft>zbottom[0] && maplightbottomright(fabsf(glseg.x2 - glseg.x1), fabsf(glseg.y2 - glseg.y1)); + float clen = max(fabsf(glseg.x2 - glseg.x1), fabsf(glseg.y2 - glseg.y1)); float dch = zbottom[1] - zbottom[0]; float dfh = maplightbottomright - maplightbottomleft; @@ -705,6 +805,10 @@ bool HWWall::SplitWallComplex(HWDrawInfo *di, sector_t * frontsector, bool trans copyWall1.tcs[UPRGT].v = copyWall2.tcs[UPLFT].v = tcs[UPLFT].v + coeff * (tcs[UPRGT].v - tcs[UPLFT].v); copyWall1.tcs[LORGT].u = copyWall2.tcs[LOLFT].u = tcs[LOLFT].u + coeff * (tcs[LORGT].u - tcs[LOLFT].u); copyWall1.tcs[LORGT].v = copyWall2.tcs[LOLFT].v = tcs[LOLFT].v + coeff * (tcs[LORGT].v - tcs[LOLFT].v); + copyWall1.lightuv[UPRGT].u = copyWall2.lightuv[UPLFT].u = lightuv[UPLFT].u + coeff * (lightuv[UPRGT].u - lightuv[UPLFT].u); + copyWall1.lightuv[UPRGT].v = copyWall2.lightuv[UPLFT].v = lightuv[UPLFT].v + coeff * (lightuv[UPRGT].v - lightuv[UPLFT].v); + copyWall1.lightuv[LORGT].u = copyWall2.lightuv[LOLFT].u = lightuv[LOLFT].u + coeff * (lightuv[LORGT].u - lightuv[LOLFT].u); + copyWall1.lightuv[LORGT].v = copyWall2.lightuv[LOLFT].v = lightuv[LOLFT].v + coeff * (lightuv[LORGT].v - lightuv[LOLFT].v); copyWall1.SplitWall(di, frontsector, translucent); copyWall2.SplitWall(di, frontsector, translucent); @@ -715,7 +819,7 @@ bool HWWall::SplitWallComplex(HWDrawInfo *di, sector_t * frontsector, bool trans return false; } -void HWWall::SplitWall(HWDrawInfo *di, sector_t * frontsector, bool translucent) +void HWWall::SplitWall(HWWallDispatcher *di, sector_t * frontsector, bool translucent) { float maplightbottomleft; float maplightbottomright; @@ -800,6 +904,10 @@ void HWWall::SplitWall(HWDrawInfo *di, sector_t * frontsector, bool translucent) (maplightbottomleft-copyWall1.ztop[0])*(copyWall1.tcs[LOLFT].v-copyWall1.tcs[UPLFT].v)/(zbottom[0]-copyWall1.ztop[0]); tcs[UPRGT].v=copyWall1.tcs[LORGT].v=copyWall1.tcs[UPRGT].v+ (maplightbottomright-copyWall1.ztop[1])*(copyWall1.tcs[LORGT].v-copyWall1.tcs[UPRGT].v)/(zbottom[1]-copyWall1.ztop[1]); + lightuv[UPLFT].v=copyWall1.lightuv[LOLFT].v=copyWall1.lightuv[UPLFT].v+ + (maplightbottomleft-copyWall1.ztop[0])*(copyWall1.lightuv[LOLFT].v-copyWall1.lightuv[UPLFT].v)/(zbottom[0]-copyWall1.ztop[0]); + lightuv[UPRGT].v=copyWall1.lightuv[LORGT].v=copyWall1.lightuv[UPRGT].v+ + (maplightbottomright-copyWall1.ztop[1])*(copyWall1.lightuv[LORGT].v-copyWall1.lightuv[UPRGT].v)/(zbottom[1]-copyWall1.ztop[1]); copyWall1.Put3DWall(di, &lightlist[i], translucent); } if (ztop[0]==zbottom[0] && ztop[1]==zbottom[1]) @@ -826,7 +934,7 @@ void HWWall::SplitWall(HWDrawInfo *di, sector_t * frontsector, bool translucent) // // //========================================================================== -bool HWWall::DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2) +bool HWWall::DoHorizon(HWWallDispatcher *di, seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2) { HWHorizonInfo hi; lightlist_t * light; @@ -835,75 +943,86 @@ bool HWWall::DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1, ztop[1] = ztop[0] = fs->GetPlaneTexZ(sector_t::ceiling); zbottom[1] = zbottom[0] = fs->GetPlaneTexZ(sector_t::floor); - auto vpz = di->Viewpoint.Pos.Z; - if (vpz < fs->GetPlaneTexZ(sector_t::ceiling)) + auto ddi = di->di; + if (ddi) { - if (vpz > fs->GetPlaneTexZ(sector_t::floor)) - zbottom[1] = zbottom[0] = vpz; - - if (fs->GetTexture(sector_t::ceiling) == skyflatnum) - { - SkyPlane(di, fs, sector_t::ceiling, false); - } - else + auto vpz = ddi->Viewpoint.Pos.Z; + if (vpz < fs->GetPlaneTexZ(sector_t::ceiling)) { - hi.plane.GetFromSector(fs, sector_t::ceiling); - hi.lightlevel = hw_ClampLight(fs->GetCeilingLight()); - hi.colormap = fs->Colormap; - hi.specialcolor = fs->SpecialColors[sector_t::ceiling]; + if (vpz > fs->GetPlaneTexZ(sector_t::floor)) + zbottom[1] = zbottom[0] = vpz; - if (fs->e->XFloor.ffloors.Size()) + if (fs->GetTexture(sector_t::ceiling) == skyflatnum) { - light = P_GetPlaneLight(fs, &fs->ceilingplane, true); - - if(!(fs->GetFlags(sector_t::ceiling)&PLANEF_ABSLIGHTING)) hi.lightlevel = hw_ClampLight(*light->p_lightlevel); - hi.colormap.CopyLight(light->extra_colormap); + SkyPlane(di, fs, sector_t::ceiling, false); } + else + { + hi.plane.GetFromSector(fs, sector_t::ceiling); + hi.lightlevel = hw_ClampLight(fs->GetCeilingLight()); + hi.colormap = fs->Colormap; + hi.specialcolor = fs->SpecialColors[sector_t::ceiling]; - if (di->isFullbrightScene()) hi.colormap.Clear(); - horizon = &hi; - PutPortal(di, PORTALTYPE_HORIZON, -1); - } - ztop[1] = ztop[0] = zbottom[0]; - } + if (fs->e->XFloor.ffloors.Size()) + { + light = P_GetPlaneLight(fs, &fs->ceilingplane, true); - if (vpz > fs->GetPlaneTexZ(sector_t::floor)) - { - zbottom[1] = zbottom[0] = fs->GetPlaneTexZ(sector_t::floor); - if (fs->GetTexture(sector_t::floor) == skyflatnum) - { - SkyPlane(di, fs, sector_t::floor, false); + if (!(fs->GetFlags(sector_t::ceiling) & PLANEF_ABSLIGHTING)) hi.lightlevel = hw_ClampLight(*light->p_lightlevel); + hi.colormap.CopyLight(light->extra_colormap); + } + + if (ddi->isFullbrightScene()) hi.colormap.Clear(); + horizon = &hi; + PutPortal(di, PORTALTYPE_HORIZON, -1); + } + ztop[1] = ztop[0] = zbottom[0]; } - else - { - hi.plane.GetFromSector(fs, sector_t::floor); - hi.lightlevel = hw_ClampLight(fs->GetFloorLight()); - hi.colormap = fs->Colormap; - hi.specialcolor = fs->SpecialColors[sector_t::floor]; - if (fs->e->XFloor.ffloors.Size()) + if (vpz > fs->GetPlaneTexZ(sector_t::floor)) + { + zbottom[1] = zbottom[0] = fs->GetPlaneTexZ(sector_t::floor); + if (fs->GetTexture(sector_t::floor) == skyflatnum) { - light = P_GetPlaneLight(fs, &fs->floorplane, false); - - if(!(fs->GetFlags(sector_t::floor)&PLANEF_ABSLIGHTING)) hi.lightlevel = hw_ClampLight(*light->p_lightlevel); - hi.colormap.CopyLight(light->extra_colormap); + SkyPlane(di, fs, sector_t::floor, false); } + else + { + hi.plane.GetFromSector(fs, sector_t::floor); + hi.lightlevel = hw_ClampLight(fs->GetFloorLight()); + hi.colormap = fs->Colormap; + hi.specialcolor = fs->SpecialColors[sector_t::floor]; + + if (fs->e->XFloor.ffloors.Size()) + { + light = P_GetPlaneLight(fs, &fs->floorplane, false); - if (di->isFullbrightScene()) hi.colormap.Clear(); - horizon = &hi; - PutPortal(di, PORTALTYPE_HORIZON, -1); + if (!(fs->GetFlags(sector_t::floor) & PLANEF_ABSLIGHTING)) hi.lightlevel = hw_ClampLight(*light->p_lightlevel); + hi.colormap.CopyLight(light->extra_colormap); + } + + if (ddi->isFullbrightScene()) hi.colormap.Clear(); + horizon = &hi; + PutPortal(di, PORTALTYPE_HORIZON, -1); + } } } + else + { + // we cannot build the real portal yet, the mesh builder just needs a generic 'horizon' portal that needs to be filled in in the render pass. + PutPortal(di, PORTALTYPE_HORIZON, -1); + } return true; } +static float ZeroLightmapUVs[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + //========================================================================== // // // //========================================================================== bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float texturetop, - float topleft, float topright, float bottomleft, float bottomright, float t_ofs) + float topleft, float topright, float bottomleft, float bottomright, float t_ofs, float skew) { // // @@ -913,7 +1032,7 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto float l_ul; float texlength; - if (gltexture) + if (texture) { float length = seg->sidedef ? seg->sidedef->TexelLength : Dist2(glseg.x1, glseg.y1, glseg.x2, glseg.y2); @@ -927,6 +1046,17 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto texlength = 0; } + texcoord* srclightuv; + if (lightmap && lightmap->Type != ST_NULL) + { + srclightuv = (texcoord*)lightmap->TexCoords; + lindex = (float)lightmap->LightmapNum; + } + else + { + srclightuv = (texcoord*)ZeroLightmapUVs; + lindex = -1.0f; + } // // @@ -944,6 +1074,9 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto tcs[UPLFT].v = tci->FloatToTexV(-ztop[0] + texturetop); tcs[LOLFT].v = tci->FloatToTexV(-zbottom[0] + texturetop); } + + lightuv[UPLFT].v = srclightuv[UPLFT].v; + lightuv[LOLFT].v = srclightuv[LOLFT].v; } else { @@ -964,6 +1097,9 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto { tcs[LOLFT].v = tcs[UPLFT].v = tci->FloatToTexV(-ztop[0] + texturetop); } + + lightuv[UPLFT].v = srclightuv[UPLFT].v + inter_x * (srclightuv[UPRGT].v - srclightuv[UPLFT].v); + lightuv[LOLFT].v = srclightuv[LOLFT].v + inter_x * (srclightuv[LORGT].v - srclightuv[LOLFT].v); } // @@ -979,9 +1115,12 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto if (tci) { - tcs[UPRGT].v = tci->FloatToTexV(-ztop[1] + texturetop); - tcs[LORGT].v = tci->FloatToTexV(-zbottom[1] + texturetop); + tcs[UPRGT].v = tci->FloatToTexV(-ztop[1] + texturetop + skew); + tcs[LORGT].v = tci->FloatToTexV(-zbottom[1] + texturetop + skew); } + + lightuv[UPRGT].v = srclightuv[UPRGT].v; + lightuv[LORGT].v = srclightuv[LORGT].v; } else { @@ -999,17 +1138,25 @@ bool HWWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto zbottom[1] = ztop[1] = inter_y; if (tci) { - tcs[LORGT].v = tcs[UPRGT].v = tci->FloatToTexV(-ztop[1] + texturetop); + tcs[LORGT].v = tcs[UPRGT].v = tci->FloatToTexV(-ztop[1] + texturetop + skew); } + + lightuv[UPRGT].v = srclightuv[UPRGT].v + inter_x * (srclightuv[UPRGT].v - srclightuv[UPLFT].v); + lightuv[LORGT].v = srclightuv[LORGT].v + inter_x * (srclightuv[LORGT].v - srclightuv[LOLFT].v); } tcs[UPLFT].u = tcs[LOLFT].u = l_ul + texlength * glseg.fracleft; tcs[UPRGT].u = tcs[LORGT].u = l_ul + texlength * glseg.fracright; - if (gltexture != NULL) + lightuv[UPLFT].u = srclightuv[UPLFT].u + (srclightuv[UPRGT].u - srclightuv[UPLFT].u) * glseg.fracleft; + lightuv[LOLFT].u = srclightuv[LOLFT].u + (srclightuv[LORGT].u - srclightuv[LOLFT].u) * glseg.fracleft; + lightuv[UPRGT].u = srclightuv[UPLFT].u + (srclightuv[UPRGT].u - srclightuv[UPLFT].u) * glseg.fracright; + lightuv[LORGT].u = srclightuv[LOLFT].u + (srclightuv[LORGT].u - srclightuv[LOLFT].u) * glseg.fracright; + + if (texture != NULL) { bool normalize = false; - if (gltexture->tex->isHardwareCanvas()) normalize = true; + if (texture->isHardwareCanvas()) normalize = true; else if (flags & HWF_CLAMPY) { // for negative scales we can get negative coordinates here. @@ -1038,7 +1185,7 @@ void HWWall::CheckTexturePosition(FTexCoordInfo *tci) { float sub; - if (gltexture->tex->isHardwareCanvas()) return; + if (texture->isHardwareCanvas()) return; // clamp texture coordinates to a reasonable range. // Extremely large values can cause visual problems @@ -1103,9 +1250,9 @@ void HWWall::CheckTexturePosition(FTexCoordInfo *tci) } -static void GetTexCoordInfo(FMaterial *tex, FTexCoordInfo *tci, side_t *side, int texpos) +static void GetTexCoordInfo(FGameTexture *tex, FTexCoordInfo *tci, side_t *side, int texpos) { - tci->GetFromTexture(tex->tex, (float)side->GetTextureXScale(texpos), (float)side->GetTextureYScale(texpos), !!(side->GetLevel()->flags3 & LEVEL3_FORCEWORLDPANNING)); + tci->GetFromTexture(tex, (float)side->GetTextureXScale(texpos), (float)side->GetTextureYScale(texpos), !!(side->GetLevel()->flags3 & LEVEL3_FORCEWORLDPANNING)); } //========================================================================== @@ -1113,11 +1260,11 @@ static void GetTexCoordInfo(FMaterial *tex, FTexCoordInfo *tci, side_t *side, in // Handle one sided walls, upper and lower texture // //========================================================================== -void HWWall::DoTexture(HWDrawInfo *di, int _type,seg_t * seg, int peg, +void HWWall::DoTexture(HWWallDispatcher *di, int _type,seg_t * seg, int peg, float ceilingrefheight,float floorrefheight, float topleft,float topright, float bottomleft,float bottomright, - float v_offset) + float v_offset, float skew) { if (topleft<=bottomleft && topright<=bottomright) return; @@ -1142,17 +1289,26 @@ void HWWall::DoTexture(HWDrawInfo *di, int _type,seg_t * seg, int peg, FTexCoordInfo tci; - GetTexCoordInfo(gltexture, &tci, seg->sidedef, texpos); + GetTexCoordInfo(texture, &tci, seg->sidedef, texpos); type = _type; + if (seg->sidedef->lightmap && type >= RENDERWALL_TOP && type <= RENDERWALL_BOTTOM) + { + lightmap = &seg->sidedef->lightmap[type - RENDERWALL_TOP]; + } + else + { + lightmap = nullptr; + } + float floatceilingref = ceilingrefheight + tci.RowOffset(seg->sidedef->GetTextureYOffset(texpos)); if (peg) floatceilingref += tci.mRenderHeight - flh - v_offset; if (!SetWallCoordinates(seg, &tci, floatceilingref, topleft, topright, bottomleft, bottomright, - seg->sidedef->GetTextureXOffset(texpos))) return; + seg->sidedef->GetTextureXOffset(texpos), skew)) return; - if (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S && gl_mirrors) + if (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S && gl_mirrors && !(di->Level->ib_compatflags & BCOMPATF_NOMIRRORS)) { PutPortal(di, PORTALTYPE_MIRROR, -1); } @@ -1163,7 +1319,7 @@ void HWWall::DoTexture(HWDrawInfo *di, int _type,seg_t * seg, int peg, // Add this wall to the render list sector_t * sec = sub ? sub->sector : seg->frontsector; - if (sec->e->XFloor.lightlist.Size()==0 || di->isFullbrightScene()) PutWall(di, false); + if (sec->e->XFloor.lightlist.Size()==0 || di->isFullbrightScene()) PutWall(di, false); else SplitWall(di, sec, false); } @@ -1178,11 +1334,11 @@ void HWWall::DoTexture(HWDrawInfo *di, int _type,seg_t * seg, int peg, // //========================================================================== -void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, +void HWWall::DoMidTexture(HWWallDispatcher *di, seg_t * seg, bool drawfogboundary, sector_t * front, sector_t * back, sector_t * realfront, sector_t * realback, float fch1, float fch2, float ffh1, float ffh2, - float bch1, float bch2, float bfh1, float bfh2) + float bch1, float bch2, float bfh1, float bfh2, float zalign, float skew) { FTexCoordInfo tci; @@ -1198,12 +1354,12 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // Get the base coordinates for the texture // // - if (gltexture) + if (texture) { // Align the texture to the ORIGINAL sector's height!! // At this point slopes don't matter because they don't affect the texture's z-position - GetTexCoordInfo(gltexture, &tci, seg->sidedef, side_t::mid); + GetTexCoordInfo(texture, &tci, seg->sidedef, side_t::mid); if (tci.mRenderHeight < 0) { mirrory = true; @@ -1213,12 +1369,12 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, rowoffset = tci.RowOffset(seg->sidedef->GetTextureYOffset(side_t::mid)); if ((seg->linedef->flags & ML_DONTPEGBOTTOM) >0) { - texturebottom = MAX(realfront->GetPlaneTexZ(sector_t::floor), realback->GetPlaneTexZ(sector_t::floor)) + rowoffset; + texturebottom = max(realfront->GetPlaneTexZ(sector_t::floor), realback->GetPlaneTexZ(sector_t::floor) + zalign) + rowoffset; texturetop = texturebottom + tci.mRenderHeight; } else { - texturetop = MIN(realfront->GetPlaneTexZ(sector_t::ceiling), realback->GetPlaneTexZ(sector_t::ceiling)) + rowoffset; + texturetop = min(realfront->GetPlaneTexZ(sector_t::ceiling), realback->GetPlaneTexZ(sector_t::ceiling) + zalign) + rowoffset; texturebottom = texturetop - tci.mRenderHeight; } } @@ -1237,7 +1393,7 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // Set up the top // // - FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::top), true); + auto tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::top), true); if (!tex || !tex->isValid()) { if (front->GetTexture(sector_t::ceiling) == skyflatnum && @@ -1249,8 +1405,8 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, else { // texture is missing - use the higher plane - topleft = MAX(bch1,fch1); - topright = MAX(bch2,fch2); + topleft = max(bch1,fch1); + topright = max(bch2,fch2); } } else if ((bch1>fch1 || bch2>fch2) && @@ -1264,8 +1420,8 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, else { // But not if there can be visual artifacts. - topleft = MIN(bch1,fch1); - topright = MIN(bch2,fch2); + topleft = min(bch1,fch1); + topright = min(bch2,fch2); } // @@ -1273,12 +1429,12 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // Set up the bottom // // - tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::bottom), true); + tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::bottom), true); if (!tex || !tex->isValid()) { // texture is missing - use the lower plane - bottomleft = MIN(bfh1,ffh1); - bottomright = MIN(bfh2,ffh2); + bottomleft = min(bfh1,ffh1); + bottomright = min(bfh2,ffh2); } else if (bfh1=ffh1 && bfh2>=ffh2))) { @@ -1290,8 +1446,8 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, else { // normal case - use the higher plane - bottomleft = MAX(bfh1,ffh1); - bottomright = MAX(bfh2,ffh2); + bottomleft = max(bfh1,ffh1); + bottomright = max(bfh2,ffh2); } // @@ -1299,10 +1455,10 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // if we don't need a fog sheet let's clip away some unnecessary parts of the polygon // // - if (!drawfogboundary && !wrap) + if (!drawfogboundary && !wrap && skew == 0) { - if (texturetopbottomleft && texturebottom>bottomright) bottomleft=bottomright=texturebottom; + if (texturetop < topleft && texturetop < topright) topleft = topright = texturetop; + if (texturebottom > bottomleft && texturebottom > bottomright) bottomleft = bottomright = texturebottom; } } else @@ -1315,8 +1471,10 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // unwanted side effects. // // - topleft=topright=texturetop; - bottomleft=bottomright=texturebottom; + topleft = texturetop; + topright = texturetop + skew; + bottomleft = texturebottom; + bottomright = texturebottom + skew; } // nothing visible - skip the rest @@ -1330,7 +1488,7 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // float t_ofs = seg->sidedef->GetTextureXOffset(side_t::mid); - if (gltexture) + if (texture) { // First adjust the texture offset so that the left edge of the linedef is inside the range [0..1]. float texwidth = tci.TextureAdjustWidth(); @@ -1372,8 +1530,14 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, { tci.mRenderHeight = -tci.mRenderHeight; tci.mScale.Y = -tci.mScale.Y; + flags |= HWF_NOSLICE; + } + if (seg->linedef->isVisualPortal()) + { + // mid textures on portal lines need the same offsetting as mid textures on sky lines + flags |= HWF_SKYHACK; } - SetWallCoordinates(seg, &tci, texturetop, topleft, topright, bottomleft, bottomright, t_ofs); + SetWallCoordinates(seg, &tci, texturetop, topleft, topright, bottomleft, bottomright, t_ofs, skew); // // @@ -1384,15 +1548,15 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, { flags |= HWF_NOSPLITUPPER|HWF_NOSPLITLOWER; type=RENDERWALL_FOGBOUNDARY; - FMaterial *savetex = gltexture; - gltexture = NULL; + auto savetex = texture; + texture = NULL; PutWall(di, true); if (!savetex) { flags &= ~(HWF_NOSPLITUPPER|HWF_NOSPLITLOWER); return; } - gltexture = savetex; + texture = savetex; type=RENDERWALL_M2SNF; } else type=RENDERWALL_M2S; @@ -1411,7 +1575,7 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, case 0: RenderStyle=STYLE_Translucent; alpha = seg->linedef->alpha; - translucent =alpha < 1. || (gltexture && gltexture->tex->GetTranslucency()); + translucent =alpha < 1. || (texture && texture->GetTranslucency()); break; case ML_ADDTRANS: @@ -1430,16 +1594,16 @@ void HWWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // // FloatRect *splitrect; - int v = gltexture->GetAreas(&splitrect); + int v = texture->GetAreas(&splitrect); if (seg->frontsector == seg->backsector) flags |= HWF_NOSPLIT; // we don't need to do vertex splits if a line has both sides in the same sector - if (v>0 && !drawfogboundary && !(seg->linedef->flags&ML_WRAP_MIDTEX)) + if (v>0 && !drawfogboundary && !(seg->linedef->flags&ML_WRAP_MIDTEX) && !(flags & HWF_NOSLICE) && skew == 0) { // split the poly! int i,t=0; float v_factor=(zbottom[0]-ztop[0])/(tcs[LOLFT].v-tcs[UPLFT].v); // only split the vertical area of the polygon that does not contain slopes. - float splittopv = MAX(tcs[UPLFT].v, tcs[UPRGT].v); - float splitbotv = MIN(tcs[LOLFT].v, tcs[LORGT].v); + float splittopv = max(tcs[UPLFT].v, tcs[UPRGT].v); + float splitbotv = min(tcs[LOLFT].v, tcs[LORGT].v); // this is split vertically into sections. for(i=0;isidedef == seg->linedef->sidedef[0]) + lightmap = seg->linedef->sidedef[1]->lightmap; + else + lightmap = seg->linedef->sidedef[0]->lightmap; + + if (lightmap) + lightmap += 4 + roverIndex; + if (rover->flags&FF_FOG) { if (!di->isFullbrightScene()) @@ -1531,7 +1704,7 @@ void HWWall::BuildFFBlock(HWDrawInfo *di, seg_t * seg, F3DFloor * rover, Colormap.LightColor = light->extra_colormap.FadeColor; // the fog plane defines the light di->Level->, not the front sector lightlevel = hw_ClampLight(*light->p_lightlevel); - gltexture = NULL; + texture = NULL; type = RENDERWALL_FFBLOCK; } else return; @@ -1541,21 +1714,21 @@ void HWWall::BuildFFBlock(HWDrawInfo *di, seg_t * seg, F3DFloor * rover, if (rover->flags&FF_UPPERTEXTURE) { - gltexture = FMaterial::ValidateTexture(seg->sidedef->GetTexture(side_t::top), false, true); - if (!gltexture) return; - GetTexCoordInfo(gltexture, &tci, seg->sidedef, side_t::top); + texture = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::top), true); + if (!texture || !texture->isValid()) return; + GetTexCoordInfo(texture, &tci, seg->sidedef, side_t::top); } else if (rover->flags&FF_LOWERTEXTURE) { - gltexture = FMaterial::ValidateTexture(seg->sidedef->GetTexture(side_t::bottom), false, true); - if (!gltexture) return; - GetTexCoordInfo(gltexture, &tci, seg->sidedef, side_t::bottom); + texture = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::bottom), true); + if (!texture || !texture->isValid()) return; + GetTexCoordInfo(texture, &tci, seg->sidedef, side_t::bottom); } else { - gltexture = FMaterial::ValidateTexture(mastersd->GetTexture(side_t::mid), false, true); - if (!gltexture) return; - GetTexCoordInfo(gltexture, &tci, mastersd, side_t::mid); + texture = TexMan.GetGameTexture(mastersd->GetTexture(side_t::mid), true); + if (!texture || !texture->isValid()) return; + GetTexCoordInfo(texture, &tci, mastersd, side_t::mid); } to = (rover->flags&(FF_UPPERTEXTURE | FF_LOWERTEXTURE)) ? 0 : tci.TextureOffset(mastersd->GetTextureXOffset(side_t::mid)); @@ -1579,6 +1752,28 @@ void HWWall::BuildFFBlock(HWDrawInfo *di, seg_t * seg, F3DFloor * rover, tcs[LORGT].v = tci.FloatToTexV(to - ff_bottomright); type = RENDERWALL_FFBLOCK; CheckTexturePosition(&tci); + + texcoord* srclightuv; + if (lightmap && lightmap->Type != ST_NULL) + { + srclightuv = (texcoord*)lightmap->TexCoords; + lindex = (float)lightmap->LightmapNum; + } + else + { + srclightuv = (texcoord*)ZeroLightmapUVs; + lindex = -1.0f; + } + + lightuv[UPLFT].u = srclightuv[UPLFT].u + (srclightuv[UPRGT].u - srclightuv[UPLFT].u) * glseg.fracleft; + lightuv[LOLFT].u = srclightuv[LOLFT].u + (srclightuv[LORGT].u - srclightuv[LOLFT].u) * glseg.fracleft; + lightuv[UPRGT].u = srclightuv[UPLFT].u + (srclightuv[UPRGT].u - srclightuv[UPLFT].u) * glseg.fracright; + lightuv[LORGT].u = srclightuv[LOLFT].u + (srclightuv[LORGT].u - srclightuv[LOLFT].u) * glseg.fracright; + + lightuv[UPLFT].v = srclightuv[UPLFT].v; + lightuv[UPRGT].v = srclightuv[UPRGT].v; + lightuv[LOLFT].v = srclightuv[LOLFT].v; + lightuv[LORGT].v = srclightuv[LORGT].v; } ztop[0] = ff_topleft; @@ -1591,7 +1786,7 @@ void HWWall::BuildFFBlock(HWDrawInfo *di, seg_t * seg, F3DFloor * rover, alpha = rover->alpha / 255.0f; RenderStyle = (rover->flags&FF_ADDITIVETRANS) ? STYLE_Add : STYLE_Translucent; translucent = true; - type = gltexture ? RENDERWALL_M2S : RENDERWALL_COLOR; + type = texture ? RENDERWALL_M2S : RENDERWALL_COLOR; } else { @@ -1609,6 +1804,7 @@ void HWWall::BuildFFBlock(HWDrawInfo *di, seg_t * seg, F3DFloor * rover, lightlevel = savelight; Colormap = savecolor; flags &= ~HWF_CLAMPY; + RenderStyle = STYLE_Normal; } @@ -1629,7 +1825,7 @@ __forceinline void HWWall::GetPlanePos(F3DFloor::planeref *planeref, float &left // // //========================================================================== -void HWWall::InverseFloors(HWDrawInfo *di, seg_t * seg, sector_t * frontsector, +void HWWall::InverseFloors(HWWallDispatcher *di, seg_t * seg, sector_t * frontsector, float topleft, float topright, float bottomleft, float bottomright) { @@ -1667,7 +1863,7 @@ void HWWall::InverseFloors(HWDrawInfo *di, seg_t * seg, sector_t * frontsector, } if (ff_topleft < ff_bottomleft || ff_topright < ff_bottomright) continue; - BuildFFBlock(di, seg, rover, ff_topleft, ff_topright, ff_bottomleft, ff_bottomright); + BuildFFBlock(di, seg, rover, i, ff_topleft, ff_topright, ff_bottomleft, ff_bottomright); topleft = ff_bottomleft; topright = ff_bottomright; @@ -1680,7 +1876,7 @@ void HWWall::InverseFloors(HWDrawInfo *di, seg_t * seg, sector_t * frontsector, // // //========================================================================== -void HWWall::ClipFFloors(HWDrawInfo *di, seg_t * seg, F3DFloor * ffloor, sector_t * frontsector, +void HWWall::ClipFFloors(HWWallDispatcher *di, seg_t * seg, F3DFloor * ffloor, int ffloorIndex, sector_t * frontsector, float topleft, float topright, float bottomleft, float bottomright) { @@ -1731,7 +1927,7 @@ void HWWall::ClipFFloors(HWDrawInfo *di, seg_t * seg, F3DFloor * ffloor, sector_ } else if (ff_topleft <= topleft && ff_topright <= topright) { - BuildFFBlock(di, seg, ffloor, topleft, topright, ff_topleft, ff_topright); + BuildFFBlock(di, seg, ffloor, ffloorIndex, topleft, topright, ff_topleft, ff_topright); if (ff_bottomleft <= bottomleft && ff_bottomright <= bottomright) return; topleft = ff_bottomleft; topright = ff_bottomright; @@ -1746,7 +1942,7 @@ void HWWall::ClipFFloors(HWDrawInfo *di, seg_t * seg, F3DFloor * ffloor, sector_ done: // if the program reaches here there is one block left to draw - BuildFFBlock(di, seg, ffloor, topleft, topright, bottomleft, bottomright); + BuildFFBlock(di, seg, ffloor, ffloorIndex, topleft, topright, bottomleft, bottomright); } //========================================================================== @@ -1754,7 +1950,7 @@ void HWWall::ClipFFloors(HWDrawInfo *di, seg_t * seg, F3DFloor * ffloor, sector_ // // //========================================================================== -void HWWall::DoFFloorBlocks(HWDrawInfo *di, seg_t * seg, sector_t * frontsector, sector_t * backsector, +void HWWall::DoFFloorBlocks(HWWallDispatcher *di, seg_t * seg, sector_t * frontsector, sector_t * backsector, float fch1, float fch2, float ffh1, float ffh2, float bch1, float bch2, float bfh1, float bfh2) @@ -1820,9 +2016,9 @@ void HWWall::DoFFloorBlocks(HWDrawInfo *di, seg_t * seg, sector_t * frontsector, // if translucent or liquid clip away adjoining parts of the same type of FFloors on the other side if (rover->flags&(FF_SWIMMABLE | FF_TRANSLUCENT)) - ClipFFloors(di, seg, rover, frontsector, ff_topleft, ff_topright, ff_bottomleft, ff_bottomright); + ClipFFloors(di, seg, rover, i, frontsector, ff_topleft, ff_topright, ff_bottomleft, ff_bottomright); else - BuildFFBlock(di, seg, rover, ff_topleft, ff_topright, ff_bottomleft, ff_bottomright); + BuildFFBlock(di, seg, rover, i, ff_topleft, ff_topright, ff_bottomleft, ff_bottomright); topleft = ff_bottomleft; topright = ff_bottomright; @@ -1837,13 +2033,33 @@ void HWWall::DoFFloorBlocks(HWDrawInfo *di, seg_t * seg, sector_t * frontsector, InverseFloors(di, seg, frontsector, topleft, topright, bottomleft, bottomright); } } - + +inline int CalcRelLight(int lightlevel, int orglightlevel, int rel) +{ + if (orglightlevel >= 253) // with the software renderer fake contrast won't be visible above this. + { + return 0; + } + else if (lightlevel - rel > 256) // the brighter part of fake contrast will be clamped so also clamp the darker part by the same amount for better looks + { + return 256 - lightlevel + rel; + } + else + { + return rel; + } +} + +CVAR(Int, topskew, 0, 0) +CVAR(Int, midskew, 0, 0) +CVAR(Int, bottomskew, 0, 0) + //========================================================================== // // // //========================================================================== -void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_t * backsector) +void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, sector_t * backsector) { vertex_t * v1, *v2; float fch1; @@ -1857,12 +2073,14 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ sector_t * segback; #ifdef _DEBUG - if (seg->linedef->Index() == 14454) + if (seg->linedef->Index() == 759) { int a = 0; } #endif + lightmap = nullptr; + // note: we always have a valid sidedef and linedef reference when getting here. this->seg = seg; @@ -1942,23 +2160,10 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ int rel = 0; int orglightlevel = hw_ClampLight(frontsector->lightlevel); bool foggy = (!Colormap.FadeColor.isBlack() || di->Level->flags&LEVEL_HASFADETABLE); // fog disables fake contrast - lightlevel = hw_ClampLight(seg->sidedef->GetLightLevel(foggy, orglightlevel, false, &rel)); - if (orglightlevel >= 253) // with the software renderer fake contrast won't be visible above this. - { - rellight = 0; - } - else if (lightlevel - rel > 256) // the brighter part of fake contrast will be clamped so also clamp the darker part by the same amount for better looks - { - rellight = 256 - lightlevel + rel; - } - else - { - rellight = rel; - } alpha = 1.0f; RenderStyle = STYLE_Normal; - gltexture = NULL; + texture = NULL; if (frontsector->GetWallGlow(topglowcolor, bottomglowcolor)) flags |= HWF_GLOW; @@ -1975,14 +2180,18 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ return; } + bool isportal = seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0]; + // Don't render portal insides if in orthographic mode + if (di->di) isportal &= !(di->di->Viewpoint.IsOrtho()); + //return; // [GZ] 3D middle textures are necessarily two-sided, even if they lack the explicit two-sided flag - if (!backsector || !(seg->linedef->flags&(ML_TWOSIDED | ML_3DMIDTEX))) // one sided + if (!backsector || (!(seg->linedef->flags&(ML_TWOSIDED | ML_3DMIDTEX)) && !isportal)) // one sided { // sector's sky SkyNormal(di, frontsector, v1, v2); - if (seg->linedef->isVisualPortal()) + if (isportal) { lineportal = seg->linedef->getPortal()->mGroup; ztop[0] = zceil[0]; @@ -1998,12 +2207,19 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ else { // normal texture - gltexture = FMaterial::ValidateTexture(seg->sidedef->GetTexture(side_t::mid), false, true); - if (gltexture) + lightlevel = hw_ClampLight(seg->sidedef->GetLightLevel(foggy, orglightlevel, side_t::mid, false, &rel)); + rellight = CalcRelLight(lightlevel, orglightlevel, rel); + texture = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::mid), true); + if (texture && texture->isValid()) { + int skewflag = seg->sidedef->textures[side_t::mid].skew; + if (skewflag == 0) skewflag = midskew; + float skew = + skewflag == side_t::skew_front_ceiling ? fch2 - fch1 : + skewflag == side_t::skew_front_floor ? ffh2 - ffh1 : 0.; DoTexture(di, RENDERWALL_M1S, seg, (seg->linedef->flags & ML_DONTPEGBOTTOM) > 0, crefz, frefz, // must come from the original! - fch1, fch2, ffh1, ffh2, 0); + fch1, fch2, ffh1, ffh2, 0, skew); } } } @@ -2013,9 +2229,42 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ float bfh2 = segback->floorplane.ZatPoint(v2); float bch1 = segback->ceilingplane.ZatPoint(v1); float bch2 = segback->ceilingplane.ZatPoint(v2); + float zalign = 0.f; - SkyTop(di, seg, frontsector, backsector, v1, v2); - SkyBottom(di, seg, frontsector, backsector, v1, v2); + + if (isportal && seg->backsector == nullptr) + { + SkyNormal(di, frontsector, v1, v2); // For sky rendering purposes this needs to be treated as a one-sided wall. + + // If this is a one-sided portal and we got floor or ceiling alignment, the upper/lower texture position needs to be adjusted for that. + // (We assume that this portal won't involve slopes!) + switch (seg->linedef->getPortalAlignment()) + { + case PORG_FLOOR: + zalign = ffh1 - bfh1; + bch1 += zalign; + bch2 += zalign; + bfh1 += zalign; + bfh2 += zalign; + return; + + case PORG_CEILING: + zalign = fch1 - bch1; + bch1 += zalign; + bch2 += zalign; + bfh1 += zalign; + bfh2 += zalign; + return; + + default: + break; + } + } + else + { + SkyTop(di, seg, frontsector, backsector, v1, v2); + SkyBottom(di, seg, frontsector, backsector, v1, v2); + } // upper texture if (frontsector->GetTexture(sector_t::ceiling) != skyflatnum || backsector->GetTexture(sector_t::ceiling) != skyflatnum) @@ -2033,12 +2282,36 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ if (bch1a < fch1 || bch2a < fch2) { - gltexture = FMaterial::ValidateTexture(seg->sidedef->GetTexture(side_t::top), false, true); - if (gltexture) + lightlevel = hw_ClampLight(seg->sidedef->GetLightLevel(foggy, orglightlevel, side_t::top, false, &rel)); + rellight = CalcRelLight(lightlevel, orglightlevel, rel); + texture = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::top), true); + if (texture && texture->isValid()) { + int skewflag = seg->sidedef->textures[side_t::top].skew; + float skew; + if (skewflag == 0) skewflag = topskew; + + switch (skewflag) + { + default: + skew = 0; + break; + case side_t::skew_front_ceiling: + skew = fch2 - fch1; + break; + case side_t::skew_back_ceiling: + skew = bch2 - bch1; + break; + case side_t::skew_front_floor: + skew = ffh2 - ffh1; + break; + case side_t::skew_back_floor: + skew = bfh2 - bfh1; + break; + } DoTexture(di, RENDERWALL_TOP, seg, (seg->linedef->flags & (ML_DONTPEGTOP)) == 0, crefz, realback->GetPlaneTexZ(sector_t::ceiling), - fch1, fch2, bch1a, bch2a, 0); + fch1, fch2, bch1a, bch2a, 0, skew); } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { @@ -2046,12 +2319,12 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ frontsector->GetTexture(sector_t::ceiling) != skyflatnum && backsector->GetTexture(sector_t::ceiling) != skyflatnum) { - gltexture = FMaterial::ValidateTexture(frontsector->GetTexture(sector_t::ceiling), false, true); - if (gltexture) + texture = TexMan.GetGameTexture(frontsector->GetTexture(sector_t::ceiling), true); + if (texture && texture->isValid()) { DoTexture(di, RENDERWALL_TOP, seg, (seg->linedef->flags & (ML_DONTPEGTOP)) == 0, crefz, realback->GetPlaneTexZ(sector_t::ceiling), - fch1, fch2, bch1a, bch2a, 0); + fch1, fch2, bch1a, bch2a, 0, 0); } } else @@ -2068,25 +2341,44 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ /* mid texture */ - bool isportal = seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0]; sector_t *backsec = isportal? seg->linedef->getPortalDestination()->frontsector : backsector; - bool drawfogboundary = !di->isFullbrightScene() && di->CheckFog(frontsector, backsec); - FTexture *tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::mid), true); - if (tex != NULL) + bool drawfogboundary = !di->isFullbrightScene() && CheckFog(di->Level, frontsector, backsec, di->lightmode); + auto tex = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::mid), true); + if (tex != NULL && tex->isValid()) { if (di->Level->i_compatflags & COMPATF_MASKEDMIDTEX) { - tex = tex->GetRawTexture(); + auto rawtexid = TexMan.GetRawTexture(tex->GetID()); + auto rawtex = TexMan.GetGameTexture(rawtexid); + if (rawtex) tex = rawtex; } - gltexture = FMaterial::ValidateTexture(tex, false); + texture = tex; } - else gltexture = NULL; + else texture = nullptr; + lightlevel = hw_ClampLight(seg->sidedef->GetLightLevel(foggy, orglightlevel, side_t::mid, false, &rel)); + rellight = CalcRelLight(lightlevel, orglightlevel, rel); - if (gltexture || drawfogboundary) + float skew; + int skewflag = seg->sidedef->textures[side_t::mid].skew; + if (skewflag == 0) skewflag = midskew; + switch (skewflag) { - DoMidTexture(di, seg, drawfogboundary, frontsector, backsector, realfront, realback, - fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2); + default: + skew = 0; + break; + case side_t::skew_front_ceiling: + skew = fch2 - fch1; + break; + case side_t::skew_back_ceiling: + skew = bch2 - bch1; + break; + case side_t::skew_front_floor: + skew = ffh2 - ffh1; + break; + case side_t::skew_back_floor: + skew = bfh2 - bfh1; + break; } if (isportal) @@ -2097,14 +2389,33 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ zbottom[0] = bfh1; zbottom[1] = bfh2; PutPortal(di, PORTALTYPE_LINETOLINE, -1); + + if (texture && seg->backsector != nullptr) + { + DoMidTexture(di, seg, drawfogboundary, frontsector, backsector, realfront, realback, + fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2, zalign, skew); + } } - else if (backsector->e->XFloor.ffloors.Size() || frontsector->e->XFloor.ffloors.Size()) + else { - DoFFloorBlocks(di, seg, frontsector, backsector, fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2); + + if (texture || drawfogboundary) + { + DoMidTexture(di, seg, drawfogboundary, frontsector, backsector, realfront, realback, + fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2, zalign, skew); + } + + if (backsector->e->XFloor.ffloors.Size() || frontsector->e->XFloor.ffloors.Size()) + { + lightlevel = hw_ClampLight(seg->sidedef->GetLightLevel(foggy, orglightlevel, side_t::top, false, &rel)); + rellight = CalcRelLight(lightlevel, orglightlevel, rel); + DoFFloorBlocks(di, seg, frontsector, backsector, fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2); + } } /* bottom texture */ // the back sector's ceiling obstructs part of this wall (specially important for sky sectors) + float bfh1a = bfh1, bfh2a = bfh2; if (fch1 < bfh1 && fch2 < bfh2 && (seg->linedef->flags & ML_DRAWFULLHEIGHT) == 0) { bfh1 = fch1; @@ -2113,15 +2424,39 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ if (bfh1 > ffh1 || bfh2 > ffh2) { - gltexture = FMaterial::ValidateTexture(seg->sidedef->GetTexture(side_t::bottom), false, true); - if (gltexture) + lightlevel = hw_ClampLight(seg->sidedef->GetLightLevel(foggy, orglightlevel, side_t::bottom, false, &rel)); + rellight = CalcRelLight(lightlevel, orglightlevel, rel); + texture = TexMan.GetGameTexture(seg->sidedef->GetTexture(side_t::bottom), true); + if (texture && texture->isValid()) { + int skewflag = seg->sidedef->textures[side_t::bottom].skew; + if (skewflag == 0) skewflag = bottomskew; + float skew; + switch (skewflag) + { + default: + skew = 0; + break; + case side_t::skew_front_ceiling: + skew = fch2 - fch1; + break; + case side_t::skew_back_ceiling: + skew = bch2 - bch1; + break; + case side_t::skew_front_floor: + skew = ffh2 - ffh1; + break; + case side_t::skew_back_floor: + skew = bfh2a - bfh1a; + break; + } + DoTexture(di, RENDERWALL_BOTTOM, seg, (seg->linedef->flags & ML_DONTPEGBOTTOM) > 0, realback->GetPlaneTexZ(sector_t::floor), frefz, bfh1, bfh2, ffh1, ffh2, frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum ? frefz - realback->GetPlaneTexZ(sector_t::ceiling) : - frefz - crefz); + frefz - crefz, skew); } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { @@ -2132,12 +2467,12 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ // render it anyway with the sector's floor texture. With a background sky // there are ugly holes otherwise and slopes are simply not precise enough // to mach in any case. - gltexture = FMaterial::ValidateTexture(frontsector->GetTexture(sector_t::floor), false, true); - if (gltexture) + texture = TexMan.GetGameTexture(frontsector->GetTexture(sector_t::floor), true); + if (texture && texture->isValid()) { DoTexture(di, RENDERWALL_BOTTOM, seg, (seg->linedef->flags & ML_DONTPEGBOTTOM) > 0, realback->GetPlaneTexZ(sector_t::floor), frefz, - bfh1, bfh2, ffh1, ffh2, frefz - crefz); + bfh1, bfh2, ffh1, ffh2, frefz - crefz, 0); } } else if (backsector->GetTexture(sector_t::floor) != skyflatnum) @@ -2158,7 +2493,7 @@ void HWWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ // // //========================================================================== -void HWWall::ProcessLowerMiniseg(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_t * backsector) +void HWWall::ProcessLowerMiniseg(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, sector_t * backsector) { if (frontsector->GetTexture(sector_t::floor) == skyflatnum) return; lightlist = NULL; @@ -2174,6 +2509,7 @@ void HWWall::ProcessLowerMiniseg(HWDrawInfo *di, seg_t *seg, sector_t * frontsec this->frontsector = frontsector; this->backsector = backsector; this->sub = NULL; + this->lightmap = nullptr; vertex_t * v1 = seg->v1; vertex_t * v2 = seg->v2; @@ -2202,14 +2538,14 @@ void HWWall::ProcessLowerMiniseg(HWDrawInfo *di, seg_t *seg, sector_t * frontsec zfloor[0] = zfloor[1] = ffh; - gltexture = FMaterial::ValidateTexture(frontsector->GetTexture(sector_t::floor), false, true); + texture = TexMan.GetGameTexture(frontsector->GetTexture(sector_t::floor), true); - if (gltexture) + if (texture && texture->isValid()) { FTexCoordInfo tci; type = RENDERWALL_BOTTOM; - tci.GetFromTexture(gltexture->tex, 1, 1, false); - SetWallCoordinates(seg, &tci, bfh, bfh, bfh, ffh, ffh, 0); + tci.GetFromTexture(texture, 1, 1, false); + SetWallCoordinates(seg, &tci, bfh, bfh, bfh, ffh, ffh, 0, 0); PutWall(di, false); } } diff --git a/src/rendering/hwrenderer/scene/hw_walls_vertex.cpp b/src/rendering/hwrenderer/scene/hw_walls_vertex.cpp index 81a2582778a..86af3218878 100644 --- a/src/rendering/hwrenderer/scene/hw_walls_vertex.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls_vertex.cpp @@ -22,7 +22,7 @@ #include "r_defs.h" -#include "hwrenderer/data/flatvertices.h" +#include "flatvertices.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_drawstructs.h" @@ -43,6 +43,8 @@ void HWWall::SplitUpperEdge(FFlatVertex *&ptr) float fact = (ztop[1] - ztop[0]) / polyw; float facc = (zceil[1] - zceil[0]) / polyw; float facf = (zfloor[1] - zfloor[0]) / polyw; + float faclu = (lightuv[UPRGT].u - lightuv[UPLFT].u) / polyw; + float faclv = (lightuv[UPRGT].v - lightuv[UPLFT].v) / polyw; for (int i = 0; i < sidedef->numsegs - 1; i++) { @@ -58,6 +60,9 @@ void HWWall::SplitUpperEdge(FFlatVertex *&ptr) ptr->z = ztop[0] + fact * fracfac; ptr->u = tcs[UPLFT].u + facu * fracfac; ptr->v = tcs[UPLFT].v + facv * fracfac; + ptr->lu = lightuv[UPLFT].u + faclu * fracfac; + ptr->lv = lightuv[UPLFT].v + faclv * fracfac; + ptr->lindex = lindex; ptr++; } } @@ -77,6 +82,8 @@ void HWWall::SplitLowerEdge(FFlatVertex *&ptr) float facb = (zbottom[1] - zbottom[0]) / polyw; float facc = (zceil[1] - zceil[0]) / polyw; float facf = (zfloor[1] - zfloor[0]) / polyw; + float faclu = (lightuv[LORGT].u - lightuv[LOLFT].u) / polyw; + float faclv = (lightuv[LORGT].v - lightuv[LOLFT].v) / polyw; for (int i = sidedef->numsegs - 2; i >= 0; i--) { @@ -92,6 +99,9 @@ void HWWall::SplitLowerEdge(FFlatVertex *&ptr) ptr->z = zbottom[0] + facb * fracfac; ptr->u = tcs[LOLFT].u + facu * fracfac; ptr->v = tcs[LOLFT].v + facv * fracfac; + ptr->lu = lightuv[LOLFT].u + faclu * fracfac; + ptr->lv = lightuv[LOLFT].v + faclv * fracfac; + ptr->lindex = lindex; ptr++; } } @@ -115,6 +125,8 @@ void HWWall::SplitLeftEdge(FFlatVertex *&ptr) float polyh1 = ztop[0] - zbottom[0]; float factv1 = polyh1 ? (tcs[UPLFT].v - tcs[LOLFT].v) / polyh1 : 0; float factu1 = polyh1 ? (tcs[UPLFT].u - tcs[LOLFT].u) / polyh1 : 0; + float factlv1 = polyh1 ? (lightuv[UPLFT].v - lightuv[LOLFT].v) / polyh1 : 0; + float factlu1 = polyh1 ? (lightuv[UPLFT].u - lightuv[LOLFT].u) / polyh1 : 0; while (inumheights && vi->heightlist[i] <= zbottom[0]) i++; while (inumheights && vi->heightlist[i] < ztop[0]) @@ -124,6 +136,9 @@ void HWWall::SplitLeftEdge(FFlatVertex *&ptr) ptr->z = vi->heightlist[i]; ptr->u = factu1*(vi->heightlist[i] - ztop[0]) + tcs[UPLFT].u; ptr->v = factv1*(vi->heightlist[i] - ztop[0]) + tcs[UPLFT].v; + ptr->lu = factlu1 * (vi->heightlist[i] - ztop[0]) + lightuv[UPLFT].u; + ptr->lv = factlv1 * (vi->heightlist[i] - ztop[0]) + lightuv[UPLFT].v; + ptr->lindex = lindex; ptr++; i++; } @@ -149,6 +164,8 @@ void HWWall::SplitRightEdge(FFlatVertex *&ptr) float polyh2 = ztop[1] - zbottom[1]; float factv2 = polyh2 ? (tcs[UPRGT].v - tcs[LORGT].v) / polyh2 : 0; float factu2 = polyh2 ? (tcs[UPRGT].u - tcs[LORGT].u) / polyh2 : 0; + float factlv2 = polyh2 ? (lightuv[UPRGT].v - lightuv[LORGT].v) / polyh2 : 0; + float factlu2 = polyh2 ? (lightuv[UPRGT].u - lightuv[LORGT].u) / polyh2 : 0; while (i>0 && vi->heightlist[i] >= ztop[1]) i--; while (i>0 && vi->heightlist[i] > zbottom[1]) @@ -158,6 +175,9 @@ void HWWall::SplitRightEdge(FFlatVertex *&ptr) ptr->z = vi->heightlist[i]; ptr->u = factu2*(vi->heightlist[i] - ztop[1]) + tcs[UPRGT].u; ptr->v = factv2*(vi->heightlist[i] - ztop[1]) + tcs[UPRGT].v; + ptr->lu = factlu2 * (vi->heightlist[i] - ztop[1]) + lightuv[UPRGT].u; + ptr->lv = factlv2 * (vi->heightlist[i] - ztop[1]) + lightuv[UPRGT].v; + ptr->lindex = lindex; ptr++; i--; } @@ -173,16 +193,16 @@ void HWWall::SplitRightEdge(FFlatVertex *&ptr) int HWWall::CreateVertices(FFlatVertex *&ptr, bool split) { auto oo = ptr; - ptr->Set(glseg.x1, zbottom[0], glseg.y1, tcs[LOLFT].u, tcs[LOLFT].v); + ptr->Set(glseg.x1, zbottom[0], glseg.y1, tcs[LOLFT].u, tcs[LOLFT].v, lightuv[LOLFT].u, lightuv[LOLFT].v, lindex); ptr++; if (split && glseg.fracleft == 0) SplitLeftEdge(ptr); - ptr->Set(glseg.x1, ztop[0], glseg.y1, tcs[UPLFT].u, tcs[UPLFT].v); + ptr->Set(glseg.x1, ztop[0], glseg.y1, tcs[UPLFT].u, tcs[UPLFT].v, lightuv[UPLFT].u, lightuv[UPLFT].v, lindex); ptr++; if (split && !(flags & HWF_NOSPLITUPPER && seg->sidedef->numsegs > 1)) SplitUpperEdge(ptr); - ptr->Set(glseg.x2, ztop[1], glseg.y2, tcs[UPRGT].u, tcs[UPRGT].v); + ptr->Set(glseg.x2, ztop[1], glseg.y2, tcs[UPRGT].u, tcs[UPRGT].v, lightuv[UPRGT].u, lightuv[UPRGT].v, lindex); ptr++; if (split && glseg.fracright == 1) SplitRightEdge(ptr); - ptr->Set(glseg.x2, zbottom[1], glseg.y2, tcs[LORGT].u, tcs[LORGT].v); + ptr->Set(glseg.x2, zbottom[1], glseg.y2, tcs[LORGT].u, tcs[LORGT].v, lightuv[LORGT].u, lightuv[LORGT].v, lindex); ptr++; if (split && !(flags & HWF_NOSPLITLOWER) && seg->sidedef->numsegs > 1) SplitLowerEdge(ptr); return int(ptr - oo); @@ -262,7 +282,7 @@ int HWWall::CountVertices() // //========================================================================== -void HWWall::MakeVertices(HWDrawInfo *di, bool nosplit) +void HWWall::MakeVertices(bool nosplit) { if (vertcount == 0) { diff --git a/src/rendering/hwrenderer/scene/hw_weapon.cpp b/src/rendering/hwrenderer/scene/hw_weapon.cpp index 8eec8a13a8e..207f9fb6968 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.cpp +++ b/src/rendering/hwrenderer/scene/hw_weapon.cpp @@ -31,21 +31,24 @@ #include "doomstat.h" #include "d_player.h" #include "g_levellocals.h" -#include "r_data/models/models.h" +#include "models.h" #include "hw_weapon.h" #include "hw_fakeflat.h" +#include "texturemanager.h" -#include "hwrenderer/models/hw_models.h" -#include "hwrenderer/dynlights/hw_dynlightdata.h" -#include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/utility/hw_lighting.h" -#include "hwrenderer/utility/hw_cvars.h" +#include "hw_models.h" +#include "hw_dynlightdata.h" +#include "hw_material.h" +#include "hw_lighting.h" +#include "hw_cvars.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_drawstructs.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" +#include "flatvertices.h" +#include "hw_lightbuffer.h" #include "hw_renderstate.h" +#include "vm.h" + EXTERN_CVAR(Float, transsouls) EXTERN_CVAR(Int, gl_fuzztype) EXTERN_CVAR(Bool, r_drawplayersprites) @@ -66,7 +69,7 @@ void HWDrawInfo::DrawPSprite(HUDSprite *huds, FRenderState &state) } else { - SetColor(state, huds->lightlevel, 0, isFullbrightScene(), huds->cm, huds->alpha, true); + SetColor(state, Level, lightmode, huds->lightlevel, 0, isFullbrightScene(), huds->cm, huds->alpha, true); } state.SetLightIndex(-1); state.SetRenderStyle(huds->RenderStyle); @@ -88,14 +91,16 @@ void HWDrawInfo::DrawPSprite(HUDSprite *huds, FRenderState &state) state.AlphaFunc(Alpha_GEqual, 0); FHWModelRenderer renderer(this, state, huds->lightindex); - renderer.RenderHUDModel(huds->weapon, huds->mx, huds->my); + RenderHUDModel(&renderer, huds->weapon, huds->translation, huds->rotation + FVector3(huds->mx / 4., (huds->my - WEAPONTOP) / -4., 0), huds->pivot, huds->mframe); state.SetVertexBuffer(screen->mVertexData); } else { - float thresh = (huds->tex->tex->GetTranslucency() || huds->OverrideShader != -1) ? 0.f : gl_mask_sprite_threshold; + float thresh = (huds->texture->GetTranslucency() || huds->OverrideShader != -1) ? 0.f : gl_mask_sprite_threshold; state.AlphaFunc(Alpha_GEqual, thresh); - state.SetMaterial(huds->tex, CLAMP_XY_NOMIP, (huds->weapon->Flags & PSPF_PLAYERTRANSLATED) ? huds->owner->Translation : 0, huds->OverrideShader); + FTranslationID trans = huds->weapon->GetTranslation(); + if ((huds->weapon->Flags & PSPF_PLAYERTRANSLATED)) trans = huds->owner->Translation; + state.SetMaterial(huds->texture, UF_Sprite, CTF_Expand, CLAMP_XY_NOMIP, trans, huds->OverrideShader); state.Draw(DT_TriangleStrip, huds->mx, 4); } @@ -116,7 +121,7 @@ void HWDrawInfo::DrawPSprite(HUDSprite *huds, FRenderState &state) void HWDrawInfo::DrawPlayerSprites(bool hudModelStep, FRenderState &state) { auto oldlightmode = lightmode; - if (!hudModelStep && isSoftwareLighting()) SetFallbackLightMode(); // Software lighting cannot handle 2D content. + if (!hudModelStep && isSoftwareLighting(oldlightmode)) SetFallbackLightMode(); // Software lighting cannot handle 2D content. for (auto &hudsprite : hudsprites) { if ((!!hudsprite.mframe) == hudModelStep) @@ -137,10 +142,10 @@ static bool isBright(DPSprite *psp) if (psp != nullptr && psp->GetState() != nullptr) { bool disablefullbright = false; - FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., nullptr); + FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, nullAngle, nullptr); if (lump.isValid()) { - FTexture * tex = TexMan.GetTexture(lump, true); + auto tex = TexMan.GetGameTexture(lump, true); if (tex) disablefullbright = tex->isFullbrightDisabled(); } return psp->GetState()->GetFullbright() && !disablefullbright; @@ -154,9 +159,9 @@ static bool isBright(DPSprite *psp) // //========================================================================== -static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac) +static WeaponPosition2D GetWeaponPosition2D(player_t *player, double ticFrac) { - WeaponPosition w; + WeaponPosition2D w; P_BobWeapon(player, &w.bobx, &w.boby, ticFrac); // Interpolate the main weapon layer once so as to be able to add it to other layers. @@ -181,19 +186,60 @@ static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac) return w; } +static WeaponPosition3D GetWeaponPosition3D(player_t *player, double ticFrac) +{ + WeaponPosition3D w; + P_BobWeapon3D(player, &w.translation, &w.rotation, ticFrac); + + // Interpolate the main weapon layer once so as to be able to add it to other layers. + if ((w.weapon = player->FindPSprite(PSP_WEAPON)) != nullptr) + { + if (w.weapon->firstTic) + { + w.wx = (float)w.weapon->x; + w.wy = (float)w.weapon->y; + } + else + { + w.wx = (float)(w.weapon->oldx + (w.weapon->x - w.weapon->oldx) * ticFrac); + w.wy = (float)(w.weapon->oldy + (w.weapon->y - w.weapon->oldy) * ticFrac); + } + + auto weaponActor = w.weapon->GetCaller(); + + if (weaponActor && weaponActor->IsKindOf(NAME_Weapon)) + { + DVector3 *dPivot = (DVector3*) weaponActor->ScriptVar(NAME_BobPivot3D, nullptr); + w.pivot.X = (float) dPivot->X; + w.pivot.Y = (float) dPivot->Y; + w.pivot.Z = (float) dPivot->Z; + } + else + { + w.pivot = FVector3(0,0,0); + } + } + else + { + w.wx = 0; + w.wy = 0; + w.pivot = FVector3(0,0,0); + } + return w; +} + //========================================================================== // // Bobbing // //========================================================================== -static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp, double ticFrac) +static FVector2 BobWeapon2D(WeaponPosition2D &weap, DPSprite *psp, double ticFrac) { if (psp->firstTic) { // Can't interpolate the first tic. psp->firstTic = false; - psp->oldx = psp->x; - psp->oldy = psp->y; + psp->ResetInterpolation(); } float sx = float(psp->oldx + (psp->x - psp->oldx) * ticFrac); @@ -213,6 +259,46 @@ static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp, double ticFrac) return { sx, sy }; } +static FVector2 BobWeapon3D(WeaponPosition3D &weap, DPSprite *psp, FVector3 &translation, FVector3 &rotation, FVector3 &pivot, double ticFrac) +{ + if (psp->firstTic) + { // Can't interpolate the first tic. + psp->firstTic = false; + psp->ResetInterpolation(); + } + + float sx = float(psp->oldx + (psp->x - psp->oldx) * ticFrac); + float sy = float(psp->oldy + (psp->y - psp->oldy) * ticFrac); + float sz = 0; + + if (psp->Flags & PSPF_ADDBOB) + { + if (psp->Flags & PSPF_MIRROR) + { + translation = FVector3(-weap.translation.X, weap.translation.Y, weap.translation.Z); + rotation = FVector3(-weap.rotation.X, weap.rotation.Y, weap.rotation.Z); + pivot = FVector3(-weap.pivot.X, weap.pivot.Y, weap.pivot.Z); + } + else + { + translation = weap.translation ; + rotation = weap.rotation ; + pivot = weap.pivot ; + } + } + else + { + translation = rotation = pivot = FVector3(0,0,0); + } + + if (psp->Flags & PSPF_ADDWEAPON && psp->GetID() != PSP_WEAPON) + { + sx += weap.wx; + sy += weap.wy; + } + return { sx, sy }; +} + //========================================================================== // // Lighting @@ -267,9 +353,9 @@ WeaponLighting HWDrawInfo::GetWeaponLighting(sector_t *viewsector, const DVector if (Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) l.cm.ClearColor(); } - l.lightlevel = CalcLightLevel(l.lightlevel, getExtraLight(), true, 0); + l.lightlevel = CalcLightLevel(lightmode, l.lightlevel, getExtraLight(), true, 0); - if (isSoftwareLighting() || l.lightlevel < 92) + if (isSoftwareLighting(lightmode) || l.lightlevel < 92) { // Korshun: the way based on max possible light level for sector like in software renderer. double min_L = 36.0 / 31.0 - ((l.lightlevel / 255.0) * (63.0 / 31.0)); // Lightlevel in range 0-63 @@ -404,75 +490,179 @@ bool HUDSprite::GetWeaponRenderStyle(DPSprite *psp, AActor *playermo, sector_t * // //========================================================================== -bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, player_t *player) +bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, player_t *player, double ticfrac) { float tx; float scale; float scalex; + float ftextureadj; float ftexturemid; // decide which patch to use bool mirror; - FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., &mirror); + FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, nullAngle, &mirror); if (!lump.isValid()) return false; - FMaterial * tex = FMaterial::ValidateTexture(lump, true, false); - if (!tex) return false; + auto tex = TexMan.GetGameTexture(lump, false); + if (!tex || !tex->isValid()) return false; + auto& spi = tex->GetSpritePositioning(1); float vw = (float)viewwidth; float vh = (float)viewheight; - FloatRect r; - tex->GetSpriteRect(&r); + FloatRect r = spi.GetSpriteRect(); // calculate edges of the shape - scalex = (320.0f / (240.0f * r_viewwindow.WidescreenRatio)) * vw / 320; + scalex = psp->baseScale.X * (320.0f / (240.0f * r_viewwindow.WidescreenRatio)) * (vw / 320); float x1, y1, x2, y2, u1, v1, u2, v2; tx = (psp->Flags & PSPF_MIRROR) ? ((160 - r.width) - (sx + r.left)) : (sx - (160 - r.left)); x1 = tx * scalex + vw / 2; - if (x1 > vw) return false; // off the right side + // [MC] Disabled these because vertices can be manipulated now. + //if (x1 > vw) return false; // off the right side x1 += viewwindowx; tx += r.width; x2 = tx * scalex + vw / 2; - if (x2 < 0) return false; // off the left side + //if (x2 < 0) return false; // off the left side x2 += viewwindowx; // killough 12/98: fix psprite positioning problem - ftexturemid = 100.f - sy - r.top - psp->GetYAdjust(screenblocks >= 11); + ftextureadj = (120.0f / psp->baseScale.Y) - 100.0f; // [XA] scale relative to weapon baseline + ftexturemid = 100.f - sy - r.top - psp->GetYAdjust(screenblocks >= 11) - ftextureadj; - scale = (SCREENHEIGHT*vw) / (SCREENWIDTH * 200.0f); + // [XA] note: Doom's native 1.2x aspect ratio was originally + // handled here by multiplying SCREENWIDTH by 200 instead of + // 240, but now the baseScale var defines this from now on. + scale = psp->baseScale.Y * (SCREENHEIGHT*vw) / (SCREENWIDTH * 240.0f); y1 = viewwindowy + vh / 2 - (ftexturemid * scale); y2 = y1 + (r.height * scale) + 1; - - if (!(mirror) != !(psp->Flags & (PSPF_FLIP))) + const bool flip = (psp->Flags & PSPF_FLIP); + if (!(mirror) != !(flip)) { - u2 = tex->GetSpriteUL(); - v1 = tex->GetSpriteVT(); - u1 = tex->GetSpriteUR(); - v2 = tex->GetSpriteVB(); + u2 = spi.GetSpriteUL(); + v1 = spi.GetSpriteVT(); + u1 = spi.GetSpriteUR(); + v2 = spi.GetSpriteVB(); } else { - u1 = tex->GetSpriteUL(); - v1 = tex->GetSpriteVT(); - u2 = tex->GetSpriteUR(); - v2 = tex->GetSpriteVB(); + u1 = spi.GetSpriteUL(); + v1 = spi.GetSpriteVT(); + u2 = spi.GetSpriteUR(); + v2 = spi.GetSpriteVB(); + } + + // [MC] Code copied from DTA_Rotate. + // Big thanks to IvanDobrovski who helped me modify this. + + WeaponInterp Vert; + Vert.v[0] = FVector2(x1, y1); + Vert.v[1] = FVector2(x1, y2); + Vert.v[2] = FVector2(x2, y1); + Vert.v[3] = FVector2(x2, y2); + + for (int i = 0; i < 4; i++) + { + const float cx = (flip) ? -psp->Coord[i].X : psp->Coord[i].X; + Vert.v[i] += FVector2(cx * scalex, psp->Coord[i].Y * scale); + } + if (psp->rotation != nullAngle || !psp->scale.isZero()) + { + // [MC] Sets up the alignment for starting the pivot at, in a corner. + float anchorx, anchory; + switch (psp->VAlign) + { + default: + case PSPA_TOP: anchory = 0.0; break; + case PSPA_CENTER: anchory = 0.5; break; + case PSPA_BOTTOM: anchory = 1.0; break; + } + + switch (psp->HAlign) + { + default: + case PSPA_LEFT: anchorx = 0.0; break; + case PSPA_CENTER: anchorx = 0.5; break; + case PSPA_RIGHT: anchorx = 1.0; break; + } + // Handle PSPF_FLIP. + if (flip) anchorx = 1.0 - anchorx; + + FAngle rot = FAngle::fromDeg(float((flip) ? -psp->rotation.Degrees() : psp->rotation.Degrees())); + const float cosang = rot.Cos(); + const float sinang = rot.Sin(); + + float xcenter, ycenter; + const float width = x2 - x1; + const float height = y2 - y1; + const float px = float((flip) ? -psp->pivot.X : psp->pivot.X); + const float py = float(psp->pivot.Y); + + // Set up the center and offset accordingly. PivotPercent changes it to be a range [0.0, 1.0] + // instead of pixels and is enabled by default. + if (psp->Flags & PSPF_PIVOTPERCENT) + { + xcenter = x1 + (width * anchorx + width * px); + ycenter = y1 + (height * anchory + height * py); + } + else + { + xcenter = x1 + (width * anchorx + scalex * px); + ycenter = y1 + (height * anchory + scale * py); + } + + // Now adjust the position, rotation and scale of the image based on the latter two. + for (int i = 0; i < 4; i++) + { + Vert.v[i] -= {xcenter, ycenter}; + const float xx = xcenter + psp->scale.X * (Vert.v[i].X * cosang + Vert.v[i].Y * sinang); + const float yy = ycenter - psp->scale.Y * (Vert.v[i].X * sinang - Vert.v[i].Y * cosang); + Vert.v[i] = {xx, yy}; + } } + psp->Vert = Vert; + + if (psp->scale.X == 0.0 || psp->scale.Y == 0.0) + return false; + + const bool interp = (psp->InterpolateTic || psp->Flags & PSPF_INTERPOLATE); + + for (int i = 0; i < 4; i++) + { + FVector2 t = Vert.v[i]; + if (interp) + t = psp->Prev.v[i] + (psp->Vert.v[i] - psp->Prev.v[i]) * ticfrac; + Vert.v[i] = t; + } + + // [MC] If this is absolutely necessary, uncomment it. It just checks if all the vertices + // are all off screen either to the right or left, but is it honestly needed? + /* + if (( + Vert.v[0].X > 0.0 && + Vert.v[1].X > 0.0 && + Vert.v[2].X > 0.0 && + Vert.v[3].X > 0.0) || ( + Vert.v[0].X < vw && + Vert.v[1].X < vw && + Vert.v[2].X < vw && + Vert.v[3].X < vw)) + return false; + */ auto verts = screen->mVertexData->AllocVertices(4); mx = verts.second; - verts.first[0].Set(x1, y1, 0, u1, v1); - verts.first[1].Set(x1, y2, 0, u1, v2); - verts.first[2].Set(x2, y1, 0, u2, v1); - verts.first[3].Set(x2, y2, 0, u2, v2); + verts.first[0].Set(Vert.v[0].X, Vert.v[0].Y, 0, u1, v1); + verts.first[1].Set(Vert.v[1].X, Vert.v[1].Y, 0, u1, v2); + verts.first[2].Set(Vert.v[2].X, Vert.v[2].Y, 0, u2, v1); + verts.first[3].Set(Vert.v[3].X, Vert.v[3].Y, 0, u2, v2); - this->tex = tex; + texture = tex; return true; } @@ -481,82 +671,226 @@ bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, // R_DrawPlayerSprites // //========================================================================== +void HWDrawInfo::PreparePlayerSprites2D(sector_t * viewsector, area_t in_area) +{ + static PClass * wpCls = PClass::FindClass("Weapon"); + static unsigned ModifyBobLayerVIndex = GetVirtualIndex(wpCls, "ModifyBobLayer"); + static VMFunction * ModifyBobLayerOrigFunc = wpCls->Virtuals.Size() > ModifyBobLayerVIndex ? wpCls->Virtuals[ModifyBobLayerVIndex] : nullptr; + + AActor * playermo = players[consoleplayer].camera; + player_t * player = playermo->player; -void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area) + const auto &vp = Viewpoint; + + AActor *camera = vp.camera; + + WeaponPosition2D weap = GetWeaponPosition2D(camera->player, vp.TicFrac); + WeaponLighting light = GetWeaponLighting(viewsector, vp.Pos, isFullbrightScene(), in_area, camera->Pos()); + + VMFunction * ModifyBobLayer = nullptr; + DVector2 bobxy = DVector2(weap.bobx , weap.boby); + + if(weap.weapon && weap.weapon->GetCaller()) + { + PClass * cls = weap.weapon->GetCaller()->GetClass(); + ModifyBobLayer = cls->Virtuals.Size() > ModifyBobLayerVIndex ? cls->Virtuals[ModifyBobLayerVIndex] : nullptr; + + if( ModifyBobLayer == ModifyBobLayerOrigFunc) ModifyBobLayer = nullptr; + } + + // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change + // light mode here to draw the weapon sprite. + auto oldlightmode = lightmode; + if (isSoftwareLighting(oldlightmode)) SetFallbackLightMode(); + + for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) + { + if (!psp->GetState()) continue; + + FSpriteModelFrame *smf = FindModelFrame(psp->Caller, psp->GetSprite(), psp->GetFrame(), false); + + // This is an 'either-or' proposition. This maybe needs some work to allow overlays with weapon models but as originally implemented this just won't work. + if (smf) continue; + + HUDSprite hudsprite; + hudsprite.owner = playermo; + hudsprite.mframe = smf; + hudsprite.weapon = psp; + + if (!hudsprite.GetWeaponRenderStyle(psp, camera, viewsector, light)) continue; + + if(ModifyBobLayer && (psp->Flags & PSPF_ADDBOB)) + { + DVector2 out; + VMValue param[] = { weap.weapon->GetCaller() , bobxy.X , bobxy.Y , psp->GetID() , vp.TicFrac }; + VMReturn ret(&out); + + VMCall(ModifyBobLayer, param, 5, &ret, 1); + + weap.bobx = out.X; + weap.boby = out.Y; + } + + FVector2 spos = BobWeapon2D(weap, psp, vp.TicFrac); + + hudsprite.dynrgb[0] = hudsprite.dynrgb[1] = hudsprite.dynrgb[2] = 0; + hudsprite.lightindex = -1; + // set the lighting parameters + if (hudsprite.RenderStyle.BlendOp != STYLEOP_Shadow && Level->HasDynamicLights && !isFullbrightScene() && gl_light_sprites) + { + GetDynSpriteLight(playermo, nullptr, hudsprite.dynrgb); + } + + if (!hudsprite.GetWeaponRect(this, psp, spos.X, spos.Y, player, vp.TicFrac)) continue; + hudsprites.Push(hudsprite); + } + lightmode = oldlightmode; +} + +void HWDrawInfo::PreparePlayerSprites3D(sector_t * viewsector, area_t in_area) { + static PClass * wpCls = PClass::FindClass("Weapon"); + + static unsigned ModifyBobLayer3DVIndex = GetVirtualIndex(wpCls, "ModifyBobLayer3D"); + static unsigned ModifyBobPivotLayer3DVIndex = GetVirtualIndex(wpCls, "ModifyBobPivotLayer3D"); - bool brightflash = false; + static VMFunction * ModifyBobLayer3DOrigFunc = wpCls->Virtuals.Size() > ModifyBobLayer3DVIndex ? wpCls->Virtuals[ModifyBobLayer3DVIndex] : nullptr; + static VMFunction * ModifyBobPivotLayer3DOrigFunc = wpCls->Virtuals.Size() > ModifyBobPivotLayer3DVIndex ? wpCls->Virtuals[ModifyBobPivotLayer3DVIndex] : nullptr; + AActor * playermo = players[consoleplayer].camera; player_t * player = playermo->player; - - const auto &vp = Viewpoint; - AActor *camera = vp.camera; + const auto &vp = Viewpoint; - // this is the same as the software renderer - if (!player || - !r_drawplayersprites || - !camera->player || - (player->cheats & CF_CHASECAM) || - (r_deathcamera && camera->health <= 0)) - return; + AActor *camera = vp.camera; - const bool hudModelStep = IsHUDModelForPlayerAvailable(camera->player); - WeaponPosition weap = GetWeaponPosition(camera->player, vp.TicFrac); + WeaponPosition3D weap = GetWeaponPosition3D(camera->player, vp.TicFrac); WeaponLighting light = GetWeaponLighting(viewsector, vp.Pos, isFullbrightScene(), in_area, camera->Pos()); + VMFunction * ModifyBobLayer3D = nullptr; + VMFunction * ModifyBobPivotLayer3D = nullptr; + + DVector3 translation = DVector3(weap.translation); + DVector3 rotation = DVector3(weap.rotation); + DVector3 pivot = DVector3(weap.pivot); + + if(weap.weapon && weap.weapon->GetCaller()) + { + PClass * cls = weap.weapon->GetCaller()->GetClass(); + ModifyBobLayer3D = cls->Virtuals.Size() > ModifyBobLayer3DVIndex ? cls->Virtuals[ModifyBobLayer3DVIndex] : nullptr; + ModifyBobPivotLayer3D = cls->Virtuals.Size() > ModifyBobPivotLayer3DVIndex ? cls->Virtuals[ModifyBobPivotLayer3DVIndex] : nullptr; + + if( ModifyBobLayer3D == ModifyBobLayer3DOrigFunc) ModifyBobLayer3D = nullptr; + if( ModifyBobPivotLayer3D == ModifyBobPivotLayer3DOrigFunc) ModifyBobPivotLayer3D = nullptr; + } + // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change // light mode here to draw the weapon sprite. auto oldlightmode = lightmode; - if (isSoftwareLighting()) SetFallbackLightMode(); + if (isSoftwareLighting(oldlightmode)) SetFallbackLightMode(); for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) { if (!psp->GetState()) continue; - FSpriteModelFrame *smf = playermo->player->ReadyWeapon ? FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr; + FSpriteModelFrame *smf = FindModelFrame(psp->Caller, psp->GetSprite(), psp->GetFrame(), false); + // This is an 'either-or' proposition. This maybe needs some work to allow overlays with weapon models but as originally implemented this just won't work. - if (smf && !hudModelStep) continue; - if (!smf && hudModelStep) continue; + if (!smf) continue; HUDSprite hudsprite; hudsprite.owner = playermo; hudsprite.mframe = smf; hudsprite.weapon = psp; + if(ModifyBobLayer3D && (psp->Flags & PSPF_ADDBOB)) + { + DVector3 t, r; + + VMReturn returns[2]; + + returns[0].Vec3At(&t); + returns[1].Vec3At(&r); + + VMValue param[] = { weap.weapon->GetCaller() , translation.X, translation.Y, translation.Z, rotation.X, rotation.Y, rotation.Z, psp->GetID() , vp.TicFrac }; + VMCall(ModifyBobLayer3D, param, 9, returns, 2); + + weap.translation = FVector3(t); + weap.rotation = FVector3(r); + } + + if(ModifyBobPivotLayer3D && (psp->Flags & PSPF_ADDBOB)) + { + DVector3 p; + + VMReturn ret(&p); + + VMValue param[] = { weap.weapon->GetCaller() , pivot.X, pivot.Y, pivot.Z, psp->GetID() , vp.TicFrac }; + VMCall(ModifyBobPivotLayer3D, param, 6, &ret, 1); + + weap.pivot = FVector3(p); + } + if (!hudsprite.GetWeaponRenderStyle(psp, camera, viewsector, light)) continue; - FVector2 spos = BobWeapon(weap, psp, vp.TicFrac); + //FVector2 spos = BobWeapon3D(weap, psp, hudsprite.translation, hudsprite.rotation, hudsprite.pivot, vp.TicFrac); + + FVector2 spos = BobWeapon3D(weap, psp, hudsprite.translation, hudsprite.rotation, hudsprite.pivot, vp.TicFrac); hudsprite.dynrgb[0] = hudsprite.dynrgb[1] = hudsprite.dynrgb[2] = 0; hudsprite.lightindex = -1; // set the lighting parameters if (hudsprite.RenderStyle.BlendOp != STYLEOP_Shadow && Level->HasDynamicLights && !isFullbrightScene() && gl_light_sprites) { - if (!hudModelStep) - { - GetDynSpriteLight(playermo, nullptr, hudsprite.dynrgb); - } - else + hw_GetDynModelLight(playermo, lightdata); + hudsprite.lightindex = screen->mLights->UploadLights(lightdata); + LightProbe* probe = FindLightProbe(playermo->Level, playermo->X(), playermo->Y(), playermo->Center()); + if (probe) { - hw_GetDynModelLight(playermo, lightdata); - hudsprite.lightindex = screen->mLights->UploadLights(lightdata); + hudsprite.dynrgb[0] = probe->Red; + hudsprite.dynrgb[1] = probe->Green; + hudsprite.dynrgb[2] = probe->Blue; } } // [BB] In the HUD model step we just render the model and break out. - if (hudModelStep) - { - hudsprite.mx = spos.X; - hudsprite.my = spos.Y; - } - else - { - if (!hudsprite.GetWeaponRect(this, psp, spos.X, spos.Y, player)) continue; - } + hudsprite.mx = spos.X; + hudsprite.my = spos.Y; + hudsprites.Push(hudsprite); } lightmode = oldlightmode; - PrepareTargeterSprites(); +} + +void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area) +{ + + AActor * playermo = players[consoleplayer].camera; + player_t * player = playermo->player; + + const auto &vp = Viewpoint; + + AActor *camera = vp.camera; + + // this is the same as the software renderer + if (!player || + !r_drawplayersprites || + !camera->player || + (player->cheats & CF_CHASECAM) || + (r_deathcamera && camera->health <= 0)) + return; + + const bool hudModelStep = IsHUDModelForPlayerAvailable(camera->player); + + if(hudModelStep) + { + PreparePlayerSprites3D(viewsector,in_area); + } + else + { + PreparePlayerSprites2D(viewsector,in_area); + } + + PrepareTargeterSprites(vp.TicFrac); } @@ -566,7 +900,7 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area) // //========================================================================== -void HWDrawInfo::PrepareTargeterSprites() +void HWDrawInfo::PrepareTargeterSprites(double ticfrac) { AActor * playermo = players[consoleplayer].camera; player_t * player = playermo->player; @@ -598,7 +932,8 @@ void HWDrawInfo::PrepareTargeterSprites() if (psp->GetState() != nullptr && (psp->GetID() != PSP_TARGETCENTER || CrosshairImage == nullptr)) { hudsprite.weapon = psp; - if (hudsprite.GetWeaponRect(this, psp, psp->x, psp->y, player)) + + if (hudsprite.GetWeaponRect(this, psp, psp->x, psp->y, player, ticfrac)) { hudsprites.Push(hudsprite); } diff --git a/src/rendering/hwrenderer/scene/hw_weapon.h b/src/rendering/hwrenderer/scene/hw_weapon.h index 62c5a70a04e..97f39ad8eab 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.h +++ b/src/rendering/hwrenderer/scene/hw_weapon.h @@ -8,16 +8,28 @@ class AActor; enum area_t : int; struct FSpriteModelFrame; struct HWDrawInfo; -class FMaterial; +class FGameTexture; -struct WeaponPosition +struct WeaponPosition2D { float wx, wy; float bobx, boby; DPSprite *weapon; }; +struct WeaponPosition3D +{ + float wx, + wy; + + FVector3 translation, + rotation, + pivot; + + DPSprite *weapon; +}; + struct WeaponLighting { FColormap cm; @@ -29,7 +41,7 @@ struct HUDSprite { AActor *owner; DPSprite *weapon; - FMaterial *tex; + FGameTexture *texture; FSpriteModelFrame *mframe; FColormap cm; @@ -43,10 +55,12 @@ struct HUDSprite float mx, my; float dynrgb[3]; + FVector3 rotation, translation, pivot; + int lightindex; void SetBright(bool isbelow); bool GetWeaponRenderStyle(DPSprite *psp, AActor *playermo, sector_t *viewsector, WeaponLighting &light); - bool GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, player_t *player); + bool GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, player_t *player, double ticfrac); }; diff --git a/src/rendering/hwrenderer/textures/hw_material.cpp b/src/rendering/hwrenderer/textures/hw_material.cpp deleted file mode 100644 index a70d749fdd5..00000000000 --- a/src/rendering/hwrenderer/textures/hw_material.cpp +++ /dev/null @@ -1,494 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2004-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - -#include "w_wad.h" -#include "m_png.h" -#include "sbar.h" -#include "stats.h" -#include "r_utility.h" -#include "c_dispatch.h" -#include "hw_ihwtexture.h" -#include "hw_material.h" - -//=========================================================================== -// -// Quick'n dirty image rescaling. -// -// This will only be used when the source texture is larger than -// what the hardware can manage (extremely rare in Doom) -// -// Code taken from wxWidgets -// -//=========================================================================== - -struct BoxPrecalc -{ - int boxStart; - int boxEnd; -}; - -static void ResampleBoxPrecalc(TArray& boxes, int oldDim) -{ - int newDim = boxes.Size(); - const double scale_factor_1 = double(oldDim) / newDim; - const int scale_factor_2 = (int)(scale_factor_1 / 2); - - for (int dst = 0; dst < newDim; ++dst) - { - // Source pixel in the Y direction - const int src_p = int(dst * scale_factor_1); - - BoxPrecalc& precalc = boxes[dst]; - precalc.boxStart = clamp(int(src_p - scale_factor_1 / 2.0 + 1), 0, oldDim - 1); - precalc.boxEnd = clamp(MAX(precalc.boxStart + 1, int(src_p + scale_factor_2)), 0, oldDim - 1); - } -} - -void IHardwareTexture::Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data) -{ - - // This function implements a simple pre-blur/box averaging method for - // downsampling that gives reasonably smooth results To scale the image - // down we will need to gather a grid of pixels of the size of the scale - // factor in each direction and then do an averaging of the pixels. - - TArray vPrecalcs(height, true); - TArray hPrecalcs(width, true); - - ResampleBoxPrecalc(vPrecalcs, sheight); - ResampleBoxPrecalc(hPrecalcs, swidth); - - int averaged_pixels, averaged_alpha, src_pixel_index; - double sum_r, sum_g, sum_b, sum_a; - - for (int y = 0; y < height; y++) // Destination image - Y direction - { - // Source pixel in the Y direction - const BoxPrecalc& vPrecalc = vPrecalcs[y]; - - for (int x = 0; x < width; x++) // Destination image - X direction - { - // Source pixel in the X direction - const BoxPrecalc& hPrecalc = hPrecalcs[x]; - - // Box of pixels to average - averaged_pixels = 0; - averaged_alpha = 0; - sum_r = sum_g = sum_b = sum_a = 0.0; - - for (int j = vPrecalc.boxStart; j <= vPrecalc.boxEnd; ++j) - { - for (int i = hPrecalc.boxStart; i <= hPrecalc.boxEnd; ++i) - { - // Calculate the actual index in our source pixels - src_pixel_index = j * swidth + i; - - int a = src_data[src_pixel_index * 4 + 3]; - if (a > 0) // do not use color from fully transparent pixels - { - sum_r += src_data[src_pixel_index * 4 + 0]; - sum_g += src_data[src_pixel_index * 4 + 1]; - sum_b += src_data[src_pixel_index * 4 + 2]; - sum_a += a; - averaged_pixels++; - } - averaged_alpha++; - - } - } - - // Calculate the average from the sum and number of averaged pixels - dst_data[0] = (unsigned char)xs_CRoundToInt(sum_r / averaged_pixels); - dst_data[1] = (unsigned char)xs_CRoundToInt(sum_g / averaged_pixels); - dst_data[2] = (unsigned char)xs_CRoundToInt(sum_b / averaged_pixels); - dst_data[3] = (unsigned char)xs_CRoundToInt(sum_a / averaged_alpha); - dst_data += 4; - } - } -} - -//=========================================================================== -// -// Constructor -// -//=========================================================================== - -FMaterial::FMaterial(FTexture * tx, bool expanded) -{ - mShaderIndex = SHADER_Default; - sourcetex = tex = tx; - - if (tx->UseType == ETextureType::SWCanvas && static_cast(tx)->GetColorFormat() == 0) - { - mShaderIndex = SHADER_Paletted; - } - else if (tx->isWarped()) - { - mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2 - } - else if (tx->isHardwareCanvas()) - { - if (tx->shaderindex >= FIRST_USER_SHADER) - { - mShaderIndex = tx->shaderindex; - } - // no brightmap for cameratexture - } - else - { - if (tx->Normal && tx->Specular) - { - for (auto &texture : { tx->Normal, tx->Specular }) - { - mTextureLayers.Push(texture); - } - mShaderIndex = SHADER_Specular; - } - else if (tx->Normal && tx->Metallic && tx->Roughness && tx->AmbientOcclusion) - { - for (auto &texture : { tx->Normal, tx->Metallic, tx->Roughness, tx->AmbientOcclusion }) - { - mTextureLayers.Push(texture); - } - mShaderIndex = SHADER_PBR; - } - - tx->CreateDefaultBrightmap(); - if (tx->Brightmap) - { - mTextureLayers.Push(tx->Brightmap); - if (mShaderIndex == SHADER_Specular) - mShaderIndex = SHADER_SpecularBrightmap; - else if (mShaderIndex == SHADER_PBR) - mShaderIndex = SHADER_PBRBrightmap; - else - mShaderIndex = SHADER_Brightmap; - } - - if (tx->shaderindex >= FIRST_USER_SHADER) - { - const UserShaderDesc &usershader = usershaders[tx->shaderindex - FIRST_USER_SHADER]; - if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material - { - for (auto &texture : tx->CustomShaderTextures) - { - if (texture == nullptr) continue; - mTextureLayers.Push(texture); - } - mShaderIndex = tx->shaderindex; - } - } - } - mWidth = tx->GetWidth(); - mHeight = tx->GetHeight(); - mLeftOffset = tx->GetLeftOffset(0); // These only get used by decals and decals should not use renderer-specific offsets. - mTopOffset = tx->GetTopOffset(0); - mRenderWidth = tx->GetScaledWidth(); - mRenderHeight = tx->GetScaledHeight(); - mSpriteU[0] = mSpriteV[0] = 0.f; - mSpriteU[1] = mSpriteV[1] = 1.f; - - mExpanded = expanded; - if (expanded) - { - int oldwidth = mWidth; - int oldheight = mHeight; - - mTrimResult = TrimBorders(trim); // get the trim size before adding the empty frame - mWidth += 2; - mHeight += 2; - mRenderWidth = mRenderWidth * mWidth / oldwidth; - mRenderHeight = mRenderHeight * mHeight / oldheight; - - } - SetSpriteRect(); - - mTextureLayers.ShrinkToFit(); - tx->Material[expanded] = this; - if (tx->isHardwareCanvas()) tx->bTranslucent = 0; -} - -//=========================================================================== -// -// Destructor -// -//=========================================================================== - -FMaterial::~FMaterial() -{ -} - -//=========================================================================== -// -// Set the sprite rectangle -// -//=========================================================================== - -void FMaterial::SetSpriteRect() -{ - auto leftOffset = tex->GetLeftOffsetHW(); - auto topOffset = tex->GetTopOffsetHW(); - - float fxScale = (float)tex->Scale.X; - float fyScale = (float)tex->Scale.Y; - - // mSpriteRect is for positioning the sprite in the scene. - mSpriteRect.left = -leftOffset / fxScale; - mSpriteRect.top = -topOffset / fyScale; - mSpriteRect.width = mWidth / fxScale; - mSpriteRect.height = mHeight / fyScale; - - if (mExpanded) - { - // a little adjustment to make sprites look better with texture filtering: - // create a 1 pixel wide empty frame around them. - - int oldwidth = mWidth - 2; - int oldheight = mHeight - 2; - - leftOffset += 1; - topOffset += 1; - - // Reposition the sprite with the frame considered - mSpriteRect.left = -leftOffset / fxScale; - mSpriteRect.top = -topOffset / fyScale; - mSpriteRect.width = mWidth / fxScale; - mSpriteRect.height = mHeight / fyScale; - - if (mTrimResult) - { - mSpriteRect.left += trim[0] / fxScale; - mSpriteRect.top += trim[1] / fyScale; - - mSpriteRect.width -= (oldwidth - trim[2]) / fxScale; - mSpriteRect.height -= (oldheight - trim[3]) / fyScale; - - mSpriteU[0] = trim[0] / (float)mWidth; - mSpriteV[0] = trim[1] / (float)mHeight; - mSpriteU[1] -= (oldwidth - trim[0] - trim[2]) / (float)mWidth; - mSpriteV[1] -= (oldheight - trim[1] - trim[3]) / (float)mHeight; - } - } -} - - -//=========================================================================== -// -// Finds empty space around the texture. -// Used for sprites that got placed into a huge empty frame. -// -//=========================================================================== - -bool FMaterial::TrimBorders(uint16_t *rect) -{ - - auto texbuffer = sourcetex->CreateTexBuffer(0); - int w = texbuffer.mWidth; - int h = texbuffer.mHeight; - auto Buffer = texbuffer.mBuffer; - - if (texbuffer.mBuffer == nullptr) - { - return false; - } - if (w != mWidth || h != mHeight) - { - // external Hires replacements cannot be trimmed. - return false; - } - - int size = w*h; - if (size == 1) - { - // nothing to be done here. - rect[0] = 0; - rect[1] = 0; - rect[2] = 1; - rect[3] = 1; - return true; - } - int first, last; - - for(first = 0; first < size; first++) - { - if (Buffer[first*4+3] != 0) break; - } - if (first >= size) - { - // completely empty - rect[0] = 0; - rect[1] = 0; - rect[2] = 1; - rect[3] = 1; - return true; - } - - for(last = size-1; last >= first; last--) - { - if (Buffer[last*4+3] != 0) break; - } - - rect[1] = first / w; - rect[3] = 1 + last/w - rect[1]; - - rect[0] = 0; - rect[2] = w; - - unsigned char *bufferoff = Buffer + (rect[1] * w * 4); - h = rect[3]; - - for(int x = 0; x < w; x++) - { - for(int y = 0; y < h; y++) - { - if (bufferoff[(x+y*w)*4+3] != 0) goto outl; - } - rect[0]++; - } -outl: - rect[2] -= rect[0]; - - for(int x = w-1; rect[2] > 1; x--) - { - for(int y = 0; y < h; y++) - { - if (bufferoff[(x+y*w)*4+3] != 0) - { - return true; - } - } - rect[2]--; - } - return true; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -IHardwareTexture *FMaterial::GetLayer(int i, int translation, FTexture **pLayer) -{ - FTexture *layer = i == 0 ? tex : mTextureLayers[i - 1]; - if (pLayer) *pLayer = layer; - - if (layer && layer->UseType!=ETextureType::Null) - { - IHardwareTexture *hwtex = layer->SystemTextures.GetHardwareTexture(translation, mExpanded); - if (hwtex == nullptr) - { - hwtex = screen->CreateHardwareTexture(); - layer->SystemTextures.AddHardwareTexture(translation, mExpanded, hwtex); - } - return hwtex; - } - return nullptr; -} - -//=========================================================================== -// -// -// -//=========================================================================== -void FMaterial::Precache() -{ - screen->PrecacheMaterial(this, 0); -} - -//=========================================================================== -// -// -// -//=========================================================================== -void FMaterial::PrecacheList(SpriteHits &translations) -{ - tex->SystemTextures.CleanUnused(translations, mExpanded); - SpriteHits::Iterator it(translations); - SpriteHits::Pair *pair; - while(it.NextPair(pair)) screen->PrecacheMaterial(this, pair->Key); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -int FMaterial::GetAreas(FloatRect **pAreas) const -{ - if (mShaderIndex == SHADER_Default) // texture splitting can only be done if there's no attached effects - { - *pAreas = sourcetex->areas; - return sourcetex->areacount; - } - else - { - return 0; - } -} - -//========================================================================== -// -// Gets a texture from the texture manager and checks its validity for -// GL rendering. -// -//========================================================================== - -FMaterial * FMaterial::ValidateTexture(FTexture * tex, bool expand, bool create) -{ -again: - if (tex && tex->isValid()) - { - if (tex->bNoExpand) expand = false; - - FMaterial *hwtex = tex->Material[expand]; - if (hwtex == NULL && create) - { - if (expand) - { - if (tex->isWarped() || tex->isHardwareCanvas() || tex->shaderindex >= FIRST_USER_SHADER || (tex->shaderindex >= SHADER_Specular && tex->shaderindex <= SHADER_PBRBrightmap)) - { - tex->bNoExpand = true; - goto again; - } - if (tex->Brightmap != NULL && - (tex->GetWidth() != tex->Brightmap->GetWidth() || - tex->GetHeight() != tex->Brightmap->GetHeight()) - ) - { - // do not expand if the brightmap's size differs. - tex->bNoExpand = true; - goto again; - } - } - hwtex = new FMaterial(tex, expand); - } - return hwtex; - } - return NULL; -} - -FMaterial * FMaterial::ValidateTexture(FTextureID no, bool expand, bool translate, bool create) -{ - return ValidateTexture(TexMan.GetTexture(no, translate), expand, create); -} diff --git a/src/rendering/hwrenderer/textures/hw_material.h b/src/rendering/hwrenderer/textures/hw_material.h deleted file mode 100644 index 98a0ebffe36..00000000000 --- a/src/rendering/hwrenderer/textures/hw_material.h +++ /dev/null @@ -1,147 +0,0 @@ - -#ifndef __GL_MATERIAL_H -#define __GL_MATERIAL_H - -#include "m_fixed.h" -#include "textures/textures.h" - -#include "r_defs.h" - -EXTERN_CVAR(Bool, gl_precache) - -struct FRemapTable; -class FTextureShader; -class IHardwareTexture; - -enum -{ - CLAMP_NONE = 0, - CLAMP_X = 1, - CLAMP_Y = 2, - CLAMP_XY = 3, - CLAMP_XY_NOMIP = 4, - CLAMP_NOFILTER = 5, - CLAMP_CAMTEX = 6, -}; - - -//=========================================================================== -// -// this is the material class for OpenGL. -// -//=========================================================================== - -class FMaterial -{ - TArray mTextureLayers; - int mShaderIndex; - - short mLeftOffset; - short mTopOffset; - short mWidth; - short mHeight; - short mRenderWidth; - short mRenderHeight; - bool mExpanded; - bool mTrimResult; - uint16_t trim[4]; - - float mSpriteU[2], mSpriteV[2]; - FloatRect mSpriteRect; - - bool TrimBorders(uint16_t *rect); - -public: - FTexture *tex; - FTexture *sourcetex; // in case of redirection this is different from tex. - - FMaterial(FTexture *tex, bool forceexpand); - ~FMaterial(); - void SetSpriteRect(); - void Precache(); - void PrecacheList(SpriteHits &translations); - int GetShaderIndex() const { return mShaderIndex; } - void AddTextureLayer(FTexture *tex) - { - ValidateTexture(tex, false); - mTextureLayers.Push(tex); - } - bool isMasked() const - { - return sourcetex->bMasked; - } - bool isExpanded() const - { - return mExpanded; - } - - int GetLayers() const - { - return mTextureLayers.Size() + 1; - } - - bool hasCanvas() - { - return tex->isHardwareCanvas(); - } - - IHardwareTexture *GetLayer(int i, int translation, FTexture **pLayer = nullptr); - - // Patch drawing utilities - - void GetSpriteRect(FloatRect * r) const - { - *r = mSpriteRect; - } - - // This is scaled size in integer units as needed by walls and flats - int TextureHeight() const { return mRenderHeight; } - int TextureWidth() const { return mRenderWidth; } - - int GetAreas(FloatRect **pAreas) const; - - int GetWidth() const - { - return mWidth; - } - - int GetHeight() const - { - return mHeight; - } - - int GetLeftOffset() const - { - return mLeftOffset; - } - - int GetTopOffset() const - { - return mTopOffset; - } - - // Get right/bottom UV coordinates for patch drawing - float GetUL() const { return 0; } - float GetVT() const { return 0; } - float GetUR() const { return 1; } - float GetVB() const { return 1; } - float GetU(float upix) const { return upix/(float)mWidth; } - float GetV(float vpix) const { return vpix/(float)mHeight; } - - float GetSpriteUL() const { return mSpriteU[0]; } - float GetSpriteVT() const { return mSpriteV[0]; } - float GetSpriteUR() const { return mSpriteU[1]; } - float GetSpriteVB() const { return mSpriteV[1]; } - - - static FMaterial *ValidateTexture(FTexture * tex, bool expand, bool create = true); - static FMaterial *ValidateTexture(FTextureID no, bool expand, bool trans, bool create = true); - const TArray &GetLayerArray() const - { - return mTextureLayers; - } -}; - -#endif - - diff --git a/src/rendering/hwrenderer/textures/hw_precache.cpp b/src/rendering/hwrenderer/textures/hw_precache.cpp deleted file mode 100644 index ed024e77e7a..00000000000 --- a/src/rendering/hwrenderer/textures/hw_precache.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2004-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** Texture precaching -** -*/ - -#include "c_cvars.h" -#include "w_wad.h" -#include "r_data/r_translate.h" -#include "c_dispatch.h" -#include "r_state.h" -#include "actor.h" -#include "r_data/models/models.h" -#include "textures/skyboxtexture.h" -#include "hwrenderer/textures/hw_material.h" -#include "image.h" -#include "v_video.h" -#include "v_font.h" - - -//========================================================================== -// -// DFrameBuffer :: PrecacheTexture -// -//========================================================================== - -static void PrecacheTexture(FTexture *tex, int cache) -{ - if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) - { - FMaterial * gltex = FMaterial::ValidateTexture(tex, false); - if (gltex) gltex->Precache(); - } -} - -//========================================================================== -// -// DFrameBuffer :: PrecacheSprite -// -//========================================================================== - -static void PrecacheSprite(FTexture *tex, SpriteHits &hits) -{ - FMaterial * gltex = FMaterial::ValidateTexture(tex, true); - if (gltex) gltex->PrecacheList(hits); -} - -//========================================================================== -// -// DFrameBuffer :: Precache -// -//========================================================================== - -void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitlist) -{ - SpriteHits *spritelist = new SpriteHits[sprites.Size()]; - SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()]; - TMap::Iterator it(actorhitlist); - TMap::Pair *pair; - uint8_t *modellist = new uint8_t[Models.Size()]; - memset(modellist, 0, Models.Size()); - memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures()); - - // this isn't done by the main code so it needs to be done here first: - // check skybox textures and mark the separate faces as used - for (int i = 0; iisSkybox()) - { - FSkyBox *sb = static_cast(tex); - for (int i = 0; i<6; i++) - { - if (sb->faces[i]) - { - int index = sb->faces[i]->GetID().GetIndex(); - texhitlist[index] |= FTextureManager::HIT_Flat; - } - } - } - } - } - - // Check all used actors. - // 1. mark all sprites associated with its states - // 2. mark all model data and skins associated with its states - while (it.NextPair(pair)) - { - PClassActor *cls = pair->Key; - auto remap = TranslationToTable(GetDefaultByType(cls)->Translation); - int gltrans = remap == nullptr ? 0 : remap->GetUniqueIndex(); - - for (unsigned i = 0; i < cls->GetStateCount(); i++) - { - auto &state = cls->GetStates()[i]; - spritelist[state.sprite].Insert(gltrans, true); - FSpriteModelFrame * smf = FindModelFrame(cls, state.sprite, state.Frame, false); - if (smf != NULL) - { - for (int i = 0; i < MAX_MODELS_PER_FRAME; i++) - { - if (smf->skinIDs[i].isValid()) - { - texhitlist[smf->skinIDs[i].GetIndex()] |= FTextureManager::HIT_Flat; - } - else if (smf->modelIDs[i] != -1) - { - Models[smf->modelIDs[i]]->PushSpriteMDLFrame(smf, i); - Models[smf->modelIDs[i]]->AddSkins(texhitlist); - } - if (smf->modelIDs[i] != -1) - { - modellist[smf->modelIDs[i]] = 1; - } - } - } - } - } - - // mark all sprite textures belonging to the marked sprites. - for (int i = (int)(sprites.Size() - 1); i >= 0; i--) - { - if (spritelist[i].CountUsed()) - { - int j, k; - for (j = 0; j < sprites[i].numframes; j++) - { - const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j]; - - for (k = 0; k < 16; k++) - { - FTextureID pic = frame->Texture[k]; - if (pic.isValid()) - { - spritehitlist[pic.GetIndex()] = &spritelist[i]; - } - } - } - } - } - - // delete everything unused before creating any new resources to avoid memory usage peaks. - - // delete unused models - for (unsigned i = 0; i < Models.Size(); i++) - { - if (!modellist[i]) Models[i]->DestroyVertexBuffer(); - } - - TMap usedTextures, usedSprites; - - screen->StartPrecaching(); - int cnt = TexMan.NumTextures(); - - // prepare the textures for precaching. First collect all used layer textures so that we know which ones should not be deleted. - for (int i = cnt - 1; i >= 0; i--) - { - FTexture *tex = TexMan.ByIndex(i); - if (tex != nullptr) - { - FMaterial *mat = FMaterial::ValidateTexture(tex, false, false); - if (mat != nullptr) - { - for (auto ftex : mat->GetLayerArray()) - { - usedTextures.Insert(ftex, true); - } - } - if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) - { - FMaterial *mat = FMaterial::ValidateTexture(tex, true, false); - if (mat != nullptr) - { - for (auto ftex : mat->GetLayerArray()) - { - usedSprites.Insert(ftex, true); - } - } - } - } - } - - // delete unused textures (i.e. those which didn't get referenced by any material in the cache list. - for (int i = cnt - 1; i >= 0; i--) - { - FTexture *tex = TexMan.ByIndex(i); - if (tex != nullptr && tex->GetUseType() != ETextureType::FontChar) - { - if (usedTextures.CheckKey(tex) == nullptr) - { - tex->SystemTextures.Clean(true, false); - } - if (usedSprites.CheckKey(tex) == nullptr) - { - tex->SystemTextures.Clean(false, true); - } - } - } - - if (gl_precache) - { - cycle_t precache; - precache.Reset(); - precache.Clock(); - - FImageSource::BeginPrecaching(); - - // cache all used textures - for (int i = cnt - 1; i >= 0; i--) - { - FTexture *tex = TexMan.ByIndex(i); - if (tex != nullptr && tex->GetImage() != nullptr) - { - if (texhitlist[i] & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) - { - if (tex->GetImage() && tex->SystemTextures.GetHardwareTexture(0, false) == nullptr) - { - FImageSource::RegisterForPrecache(tex->GetImage()); - } - } - - // Only register untranslated sprites. Translated ones are very unlikely to require data that can be reused. - if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CheckKey(0)) - { - FImageSource::RegisterForPrecache(tex->GetImage()); - } - } - } - - // cache all used textures - for (int i = cnt - 1; i >= 0; i--) - { - FTexture *tex = TexMan.ByIndex(i); - if (tex != nullptr) - { - PrecacheTexture(tex, texhitlist[i]); - if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) - { - PrecacheSprite(tex, *spritehitlist[i]); - } - } - } - - - FImageSource::EndPrecaching(); - - // cache all used models - FModelRenderer *renderer = screen->CreateModelRenderer(-1); - for (unsigned i = 0; i < Models.Size(); i++) - { - if (modellist[i]) - Models[i]->BuildVertexBuffer(renderer); - } - delete renderer; - - precache.Unclock(); - DPrintf(DMSG_NOTIFY, "Textures precached in %.3f ms\n", precache.TimeMS()); - } - - delete[] spritehitlist; - delete[] spritelist; - delete[] modellist; -} - diff --git a/src/rendering/hwrenderer/textures/hw_texcontainer.h b/src/rendering/hwrenderer/textures/hw_texcontainer.h deleted file mode 100644 index 87abb95ae4f..00000000000 --- a/src/rendering/hwrenderer/textures/hw_texcontainer.h +++ /dev/null @@ -1,140 +0,0 @@ -#pragma once - -#include "tarray.h" -#include "hwrenderer/textures/hw_ihwtexture.h" - -struct FTextureBuffer; -class IHardwareTexture; - -class FHardwareTextureContainer -{ -public: - enum - { - MAX_TEXTURES = 16 - }; - -private: - struct TranslatedTexture - { - IHardwareTexture *hwTexture = nullptr; - int translation = 0; - - void Delete() - { - if (hwTexture) delete hwTexture; - hwTexture = nullptr; - } - - void DeleteDescriptors() - { - if (hwTexture) hwTexture->DeleteDescriptors(); - } - - ~TranslatedTexture() - { - Delete(); - } - }; - -private: - - TranslatedTexture hwDefTex[2]; - TArray hwTex_Translated; - - TranslatedTexture * GetTexID(int translation, bool expanded) - { - translation = TranslationToIndex(translation); - if (translation == 0) - { - return &hwDefTex[expanded]; - } - - if (expanded) translation = -translation; - // normally there aren't more than very few different - // translations here so this isn't performance critical. - unsigned index = hwTex_Translated.FindEx([=](auto &element) - { - return element.translation == translation; - }); - if (index < hwTex_Translated.Size()) - { - return &hwTex_Translated[index]; - } - - int add = hwTex_Translated.Reserve(1); - auto item = &hwTex_Translated[add]; - item->translation = translation; - return item; - } - -public: - - void Clean(bool cleannormal, bool cleanexpanded) - { - if (cleannormal) hwDefTex[0].Delete(); - if (cleanexpanded) hwDefTex[1].Delete(); - hwDefTex[0].DeleteDescriptors(); - hwDefTex[1].DeleteDescriptors(); - for (int i = hwTex_Translated.Size() - 1; i >= 0; i--) - { - if (cleannormal && hwTex_Translated[i].translation > 0) hwTex_Translated.Delete(i); - else if (cleanexpanded && hwTex_Translated[i].translation < 0) hwTex_Translated.Delete(i); - - for (unsigned int j = 0; j < hwTex_Translated.Size(); j++) - hwTex_Translated[j].DeleteDescriptors(); - } - } - - IHardwareTexture * GetHardwareTexture(int translation, bool expanded) - { - auto tt = GetTexID(translation, expanded); - return tt->hwTexture; - } - - void AddHardwareTexture(int translation, bool expanded, IHardwareTexture *tex) - { - auto tt = GetTexID(translation, expanded); - tt->Delete(); - tt->hwTexture =tex; - } - - //=========================================================================== - // - // Deletes all allocated resources and considers translations - // This will only be called for sprites - // - //=========================================================================== - - void CleanUnused(SpriteHits &usedtranslations, bool expanded) - { - if (usedtranslations.CheckKey(0) == nullptr) - { - hwDefTex[expanded].Delete(); - } - int fac = expanded ? -1 : 1; - for (int i = hwTex_Translated.Size()-1; i>= 0; i--) - { - if (usedtranslations.CheckKey(hwTex_Translated[i].translation * fac) == nullptr) - { - hwTex_Translated.Delete(i); - } - } - } - - static int TranslationToIndex(int translation) - { - auto remap = TranslationToTable(translation); - return remap == nullptr ? 0 : remap->GetUniqueIndex(); - } - - template - void Iterate(T callback) - { - for (auto & t : hwDefTex) if (t.hwTexture) callback(t.hwTexture); - for (auto & t : hwTex_Translated) if (t.hwTexture) callback(t.hwTexture); - } - - -}; - diff --git a/src/rendering/hwrenderer/utility/hw_cvars.cpp b/src/rendering/hwrenderer/utility/hw_cvars.cpp deleted file mode 100644 index 18adec82683..00000000000 --- a/src/rendering/hwrenderer/utility/hw_cvars.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2005-2016 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// - - -#include "c_cvars.h" -#include "c_dispatch.h" -#include "v_video.h" -#include "hw_cvars.h" -#include "hwrenderer/textures/hw_material.h" -#include "menu/menu.h" - - - -// OpenGL stuff moved here -// GL related CVARs -CVAR(Bool, gl_portals, true, 0) -CVAR(Bool, gl_noquery, false, 0) -CVAR(Bool,gl_mirrors,true,0) // This is for debugging only! -CVAR(Bool,gl_mirror_envmap, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) -CVAR(Bool, gl_seamless, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -CUSTOM_CVAR(Int, r_mirror_recursions,4,CVAR_GLOBALCONFIG|CVAR_ARCHIVE) -{ - if (self<0) self=0; - if (self>10) self=10; -} -bool gl_plane_reflection_i; // This is needed in a header that cannot include the CVAR stuff... -CUSTOM_CVAR(Bool, gl_plane_reflection, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) -{ - gl_plane_reflection_i = self; -} - -CUSTOM_CVAR(Bool, gl_render_precise, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - gl_seamless=self; -} - -CVAR (Float, vid_brightness, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, vid_contrast, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Float, vid_saturation, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR(Int, gl_satformula, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); - -//========================================================================== -// -// Texture CVARs -// -//========================================================================== -CUSTOM_CVAR(Float,gl_texture_filter_anisotropic,8.0f,CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) -{ - screen->TextureFilterChanged(); -} - -CCMD(gl_flush) -{ - TexMan.FlushAll(); -} - -CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) -{ - if (self < 0 || self > 6) self=4; - screen->TextureFilterChanged(); -} - -CVAR(Bool, gl_precache, false, CVAR_ARCHIVE) - -//========================================================================== -// -// Sprite CVARs -// -//========================================================================== - -CVAR(Bool, gl_usecolorblending, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR(Bool, gl_sprite_blend, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -CVAR(Int, gl_spriteclip, 1, CVAR_ARCHIVE) -CVAR(Float, gl_sclipthreshold, 10.0, CVAR_ARCHIVE) -CVAR(Float, gl_sclipfactor, 1.8f, CVAR_ARCHIVE) -CVAR(Int, gl_particles_style, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 0 = square, 1 = round, 2 = smooth -CVAR(Int, gl_billboard_mode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, gl_billboard_faces_camera, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, gl_billboard_particles, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Int, gl_enhanced_nv_stealth, 3, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CUSTOM_CVAR(Int, gl_fuzztype, 0, CVAR_ARCHIVE) -{ - if (self < 0 || self > 8) self = 0; -} - -CUSTOM_CVAR(Int, gl_shadowmap_filter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (self < 0 || self > 8) self = 1; -} diff --git a/src/rendering/hwrenderer/utility/hw_draw2d.cpp b/src/rendering/hwrenderer/utility/hw_draw2d.cpp deleted file mode 100644 index d34742c031e..00000000000 --- a/src/rendering/hwrenderer/utility/hw_draw2d.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2018 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** 2d drawer -** Renderer interface -** -*/ - -#include "doomstat.h" -#include "v_video.h" -#include "cmdlib.h" -#include "r_defs.h" -#include "hwrenderer/data/buffers.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include "r_videoscale.h" - - -//=========================================================================== -// -// Vertex buffer for 2D drawer -// -//=========================================================================== - -class F2DVertexBuffer -{ - IVertexBuffer *mVertexBuffer; - IIndexBuffer *mIndexBuffer; - - -public: - - F2DVertexBuffer() - { - mVertexBuffer = screen->CreateVertexBuffer(); - mIndexBuffer = screen->CreateIndexBuffer(); - - static const FVertexBufferAttribute format[] = { - { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(F2DDrawer::TwoDVertex, x) }, - { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(F2DDrawer::TwoDVertex, u) }, - { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(F2DDrawer::TwoDVertex, color0) } - }; - mVertexBuffer->SetFormat(1, 3, sizeof(F2DDrawer::TwoDVertex), format); - } - ~F2DVertexBuffer() - { - delete mIndexBuffer; - delete mVertexBuffer; - } - - void UploadData(F2DDrawer::TwoDVertex *vertices, int vertcount, int *indices, int indexcount) - { - mVertexBuffer->SetData(vertcount * sizeof(*vertices), vertices, false); - mIndexBuffer->SetData(indexcount * sizeof(unsigned int), indices, false); - } - - std::pair GetBufferObjects() const - { - return std::make_pair(mVertexBuffer, mIndexBuffer); - } -}; - -//=========================================================================== -// -// Draws the 2D stuff. This is the version for OpenGL 3 and later. -// -//=========================================================================== - -CVAR(Bool, gl_aalines, false, CVAR_ARCHIVE) - -void Draw2D(F2DDrawer *drawer, FRenderState &state) -{ - twoD.Clock(); - - const auto &mScreenViewport = screen->mScreenViewport; - state.SetViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); - screen->mViewpoints->Set2D(state, screen->GetWidth(), screen->GetHeight()); - - state.EnableDepthTest(false); - state.EnableMultisampling(false); - state.EnableLineSmooth(gl_aalines); - - auto &vertices = drawer->mVertices; - auto &indices = drawer->mIndices; - auto &commands = drawer->mData; - - if (commands.Size() == 0) - { - twoD.Unclock(); - return; - } - - if (drawer->mIsFirstPass) - { - for (auto &v : vertices) - { - // Change from BGRA to RGBA - std::swap(v.color0.r, v.color0.b); - } - } - F2DVertexBuffer vb; - vb.UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size()); - state.SetVertexBuffer(&vb); - state.EnableFog(false); - - for(auto &cmd : commands) - { - - int gltrans = -1; - state.SetRenderStyle(cmd.mRenderStyle); - state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed)); - state.EnableFog(2); // Special 2D mode 'fog'. - - state.SetTextureMode(cmd.mDrawMode); - - int sciX, sciY, sciW, sciH; - if (cmd.mFlags & F2DDrawer::DTF_Scissor) - { - // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates - // Note that the origin here is the lower left corner! - sciX = screen->ScreenToWindowX(cmd.mScissor[0]); - sciY = screen->ScreenToWindowY(cmd.mScissor[3]); - sciW = screen->ScreenToWindowX(cmd.mScissor[2]) - sciX; - sciH = screen->ScreenToWindowY(cmd.mScissor[1]) - sciY; - } - else - { - sciX = sciY = sciW = sciH = -1; - } - state.SetScissor(sciX, sciY, sciW, sciH); - - if (cmd.mSpecialColormap[0].a != 0) - { - state.SetTextureMode(TM_FIXEDCOLORMAP); - state.SetObjectColor(cmd.mSpecialColormap[0]); - state.SetAddColor(cmd.mSpecialColormap[1]); - } - state.SetFog(cmd.mColor1, 0); - state.SetColor(1, 1, 1, 1, cmd.mDesaturate); - - state.AlphaFunc(Alpha_GEqual, 0.f); - - if (cmd.mTexture != nullptr) - { - auto mat = FMaterial::ValidateTexture(cmd.mTexture, false); - if (mat == nullptr) continue; - - state.SetMaterial(mat, cmd.mFlags & F2DDrawer::DTF_Wrap ? CLAMP_NONE : CLAMP_XY_NOMIP, cmd.mTranslationId, -1); - state.EnableTexture(true); - - // Canvas textures are stored upside down - if (cmd.mTexture->isHardwareCanvas()) - { - state.mTextureMatrix.loadIdentity(); - state.mTextureMatrix.scale(1.f, -1.f, 1.f); - state.mTextureMatrix.translate(0.f, 1.f, 0.0f); - state.EnableTextureMatrix(true); - } - if (cmd.mFlags & F2DDrawer::DTF_Burn) - { - state.SetEffect(EFF_BURN); - } - } - else - { - state.EnableTexture(false); - } - - switch (cmd.mType) - { - case F2DDrawer::DrawTypeTriangles: - state.DrawIndexed(DT_Triangles, cmd.mIndexIndex, cmd.mIndexCount); - break; - - case F2DDrawer::DrawTypeLines: - state.Draw(DT_Lines, cmd.mVertIndex, cmd.mVertCount); - break; - - case F2DDrawer::DrawTypePoints: - state.Draw(DT_Points, cmd.mVertIndex, cmd.mVertCount); - break; - - } - state.SetObjectColor(0xffffffff); - state.SetObjectColor2(0); - state.SetAddColor(0); - state.EnableTextureMatrix(false); - state.SetEffect(EFF_NONE); - - } - state.SetScissor(-1, -1, -1, -1); - - state.SetRenderStyle(STYLE_Translucent); - state.SetVertexBuffer(screen->mVertexData); - state.EnableTexture(true); - state.EnableBrightmap(true); - state.SetTextureMode(TM_NORMAL); - state.EnableFog(false); - state.ResetColor(); - drawer->mIsFirstPass = false; - twoD.Unclock(); -} diff --git a/src/rendering/hwrenderer/utility/hw_shaderpatcher.cpp b/src/rendering/hwrenderer/utility/hw_shaderpatcher.cpp deleted file mode 100644 index bdbaa50b4ae..00000000000 --- a/src/rendering/hwrenderer/utility/hw_shaderpatcher.cpp +++ /dev/null @@ -1,295 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2004-2018 Christoph Oelckers -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** hw_shaderpatcher.cpp -** -** Modifies shader source to account for different syntax versions or engine changes. -** -*/ - - -#include "hw_shaderpatcher.h" - - -static bool IsGlslWhitespace(char c) -{ - switch (c) - { - case ' ': - case '\r': - case '\n': - case '\t': - case '\f': - return true; - default: - return false; - } -} - -static FString NextGlslToken(const char *chars, long len, long &pos) -{ - // Eat whitespace - long tokenStart = pos; - while (tokenStart != len && IsGlslWhitespace(chars[tokenStart])) - tokenStart++; - - // Find token end - long tokenEnd = tokenStart; - while (tokenEnd != len && !IsGlslWhitespace(chars[tokenEnd]) && chars[tokenEnd] != ';') - tokenEnd++; - - pos = tokenEnd; - return FString(chars + tokenStart, tokenEnd - tokenStart); -} - -static bool isShaderType(const char *name) -{ - return !strcmp(name, "sampler1D") || !strcmp(name, "sampler2D") || !strcmp(name, "sampler3D") || !strcmp(name, "samplerCube") || !strcmp(name, "sampler2DMS"); -} - -FString RemoveLegacyUserUniforms(FString code) -{ - // User shaders must declare their uniforms via the GLDEFS file. - - code.Substitute("uniform sampler2D tex;", " "); - code.Substitute("uniform float timer;", " "); - - // The following code searches for legacy uniform declarations in the shader itself and replaces them with whitespace. - - long len = (long)code.Len(); - char *chars = code.LockBuffer(); - - long startIndex = 0; - while (true) - { - long matchIndex = code.IndexOf("uniform", startIndex); - if (matchIndex == -1) - break; - - bool isLegacyUniformName = false; - - bool isKeywordStart = matchIndex == 0 || IsGlslWhitespace(chars[matchIndex - 1]); - bool isKeywordEnd = matchIndex + 7 == len || IsGlslWhitespace(chars[matchIndex + 7]); - if (isKeywordStart && isKeywordEnd) - { - long pos = matchIndex + 7; - FString type = NextGlslToken(chars, len, pos); - FString identifier = NextGlslToken(chars, len, pos); - - isLegacyUniformName = type.Compare("float") == 0 && identifier.Compare("timer") == 0; - } - - if (isLegacyUniformName) - { - long statementEndIndex = code.IndexOf(';', matchIndex + 7); - if (statementEndIndex == -1) - statementEndIndex = len; - for (long i = matchIndex; i <= statementEndIndex; i++) - { - if (!IsGlslWhitespace(chars[i])) - chars[i] = ' '; - } - startIndex = statementEndIndex; - } - else - { - startIndex = matchIndex + 7; - } - } - - // Also remove all occurences of the token 'texture2d'. Some shaders may still use this deprecated function to access a sampler. - // Modern GLSL only allows use of 'texture'. - while (true) - { - long matchIndex = code.IndexOf("texture2d", startIndex); - if (matchIndex == -1) - break; - - // Check if this is a real token. - bool isKeywordStart = matchIndex == 0 || !isalnum(chars[matchIndex - 1] & 255); - bool isKeywordEnd = matchIndex + 9 == len || !isalnum(chars[matchIndex + 9] & 255); - if (isKeywordStart && isKeywordEnd) - { - chars[matchIndex + 7] = chars[matchIndex + 8] = ' '; - } - startIndex = matchIndex + 9; - } - - code.UnlockBuffer(); - - return code; -} - -FString RemoveSamplerBindings(FString code, TArray> &samplerstobind) -{ - long len = (long)code.Len(); - char *chars = code.LockBuffer(); - - long startIndex = 0; - long startpos, endpos; - while (true) - { - long matchIndex = code.IndexOf("layout(binding", startIndex); - if (matchIndex == -1) - break; - - bool isSamplerUniformName = false; - - bool isKeywordStart = matchIndex == 0 || IsGlslWhitespace(chars[matchIndex - 1]); - bool isKeywordEnd = matchIndex + 14 == len || IsGlslWhitespace(chars[matchIndex + 14]) || chars[matchIndex + 14] == '='; - if (isKeywordStart && isKeywordEnd) - { - long pos = matchIndex + 14; - startpos = matchIndex; - while (IsGlslWhitespace(chars[pos])) pos++; - if (chars[pos] == '=') - { - char *p; - pos++; - auto val = strtol(&chars[pos], &p, 0); - if (p != &chars[pos]) - { - pos = long(p - chars); - while (IsGlslWhitespace(chars[pos])) pos++; - if (chars[pos] == ')') - { - endpos = ++pos; - FString uniform = NextGlslToken(chars, len, pos); - FString type = NextGlslToken(chars, len, pos); - FString identifier = NextGlslToken(chars, len, pos); - - isSamplerUniformName = uniform.Compare("uniform") == 0 && isShaderType(type); - if (isSamplerUniformName) - { - samplerstobind.Push(std::make_pair(identifier, val)); - for (auto pos = startpos; pos < endpos; pos++) - { - if (!IsGlslWhitespace(chars[pos])) - chars[pos] = ' '; - } - } - } - } - } - } - - if (isSamplerUniformName) - { - startIndex = endpos; - } - else - { - startIndex = matchIndex + 7; - } - } - - code.UnlockBuffer(); - - return code; -} - -FString RemoveLayoutLocationDecl(FString code, const char *inoutkeyword) -{ - long len = (long)code.Len(); - char *chars = code.LockBuffer(); - - long startIndex = 0; - while (true) - { - long matchIndex = code.IndexOf("layout(location", startIndex); - if (matchIndex == -1) - break; - - long endIndex = matchIndex; - - // Find end of layout declaration - while (chars[endIndex] != ')' && chars[endIndex] != 0) - endIndex++; - - if (chars[endIndex] == ')') - endIndex++; - else if (chars[endIndex] == 0) - break; - - // Skip whitespace - while (IsGlslWhitespace(chars[endIndex])) - endIndex++; - - // keyword following the declaration? - bool keywordFound = true; - long i; - for (i = 0; inoutkeyword[i] != 0; i++) - { - if (chars[endIndex + i] != inoutkeyword[i]) - { - keywordFound = false; - break; - } - } - if (keywordFound && IsGlslWhitespace(chars[endIndex + i])) - { - // yes - replace declaration with spaces - for (long i = matchIndex; i < endIndex; i++) - chars[i] = ' '; - } - - startIndex = endIndex; - } - - code.UnlockBuffer(); - - return code; -} - -///////////////////////////////////////////////////////////////////////////// - -// Note: the MaterialShaderIndex enum in gl_shader.h needs to be updated whenever this array is modified. -const FDefaultShader defaultshaders[] = -{ - {"Default", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", ""}, - {"Warp 1", "shaders/glsl/func_warp1.fp", "shaders/glsl/material_normal.fp", ""}, - {"Warp 2", "shaders/glsl/func_warp2.fp", "shaders/glsl/material_normal.fp", ""}, - {"Brightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_normal.fp", "#define BRIGHTMAP\n"}, - {"Specular", "shaders/glsl/func_spec.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"}, - {"SpecularBrightmap", "shaders/glsl/func_spec.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n#define BRIGHTMAP\n"}, - {"PBR","shaders/glsl/func_pbr.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"}, - {"PBRBrightmap","shaders/glsl/func_pbr.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n#define BRIGHTMAP\n"}, - {"Paletted", "shaders/glsl/func_paletted.fp", "shaders/glsl/material_nolight.fp", ""}, - {"No Texture", "shaders/glsl/func_notexture.fp", "shaders/glsl/material_normal.fp", ""}, - {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", "shaders/glsl/material_normal.fp", ""}, - {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp", "shaders/glsl/material_normal.fp", ""}, - {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp", "shaders/glsl/material_normal.fp", ""}, - {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp", "shaders/glsl/material_normal.fp", ""}, - {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp", "shaders/glsl/material_normal.fp", ""}, - {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp", "shaders/glsl/material_normal.fp", ""}, - {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp", "shaders/glsl/material_normal.fp", ""}, - {"Software Fuzz", "shaders/glsl/fuzz_software.fp", "shaders/glsl/material_normal.fp", ""}, - {nullptr,nullptr,nullptr,nullptr} -}; - -const FEffectShader effectshaders[] = -{ - { "fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", nullptr, nullptr, "#define NO_ALPHATEST\n" }, - { "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" }, - { "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, - { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, -}; diff --git a/src/rendering/hwrenderer/utility/hw_vrmodes.cpp b/src/rendering/hwrenderer/utility/hw_vrmodes.cpp deleted file mode 100644 index ebb2aad9fd9..00000000000 --- a/src/rendering/hwrenderer/utility/hw_vrmodes.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program 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, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_stereo_leftright.cpp -** Offsets for left and right eye views -** -*/ - -#include "vectors.h" // RAD2DEG -#include "doomtype.h" // M_PI -#include "hwrenderer/utility/hw_cvars.h" -#include "hw_vrmodes.h" -#include "v_video.h" - -// Set up 3D-specific console variables: -CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG) - -// switch left and right eye views -CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG) - -// intraocular distance in meters -CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS - -// distance between viewer and the display screen -CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS - -// default conversion between (vertical) DOOM units and meters -CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS - - -#define isqrt2 0.7071067812f -static VRMode vrmi_mono = { 1, 1.f, 1.f, 1.f,{ { 0.f, 1.f },{ 0.f, 0.f } } }; -static VRMode vrmi_stereo = { 2, 1.f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; -static VRMode vrmi_sbsfull = { 2, .5f, 1.f, 2.f,{ { -.5f, .5f },{ .5f, .5f } } }; -static VRMode vrmi_sbssquished = { 2, .5f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; -static VRMode vrmi_lefteye = { 1, 1.f, 1.f, 1.f, { { -.5f, 1.f },{ 0.f, 0.f } } }; -static VRMode vrmi_righteye = { 1, 1.f, 1.f, 1.f,{ { .5f, 1.f },{ 0.f, 0.f } } }; -static VRMode vrmi_topbottom = { 2, 1.f, .5f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; -static VRMode vrmi_checker = { 2, isqrt2, isqrt2, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; - -const VRMode *VRMode::GetVRMode(bool toscreen) -{ - switch (toscreen && vid_rendermode == 4 ? vr_mode : 0) - { - default: - case VR_MONO: - return &vrmi_mono; - - case VR_GREENMAGENTA: - case VR_REDCYAN: - case VR_QUADSTEREO: - case VR_AMBERBLUE: - return &vrmi_stereo; - - case VR_SIDEBYSIDESQUISHED: - case VR_COLUMNINTERLEAVED: - return &vrmi_sbssquished; - - case VR_SIDEBYSIDEFULL: - return &vrmi_sbsfull; - - case VR_TOPBOTTOM: - case VR_ROWINTERLEAVED: - return &vrmi_topbottom; - - case VR_LEFTEYEVIEW: - return &vrmi_lefteye; - - case VR_RIGHTEYEVIEW: - return &vrmi_righteye; - - case VR_CHECKERINTERLEAVED: - return &vrmi_checker; - } -} - -void VRMode::AdjustViewport(DFrameBuffer *screen) const -{ - screen->mSceneViewport.height = (int)(screen->mSceneViewport.height * mVerticalViewportScale); - screen->mSceneViewport.top = (int)(screen->mSceneViewport.top * mVerticalViewportScale); - screen->mSceneViewport.width = (int)(screen->mSceneViewport.width * mHorizontalViewportScale); - screen->mSceneViewport.left = (int)(screen->mSceneViewport.left * mHorizontalViewportScale); - - screen->mScreenViewport.height = (int)(screen->mScreenViewport.height * mVerticalViewportScale); - screen->mScreenViewport.top = (int)(screen->mScreenViewport.top * mVerticalViewportScale); - screen->mScreenViewport.width = (int)(screen->mScreenViewport.width * mHorizontalViewportScale); - screen->mScreenViewport.left = (int)(screen->mScreenViewport.left * mHorizontalViewportScale); -} - -VSMatrix VRMode::GetHUDSpriteProjection() const -{ - VSMatrix mat; - int w = screen->GetWidth(); - int h = screen->GetHeight(); - float scaled_w = w / mWeaponProjectionScale; - float left_ofs = (w - scaled_w) / 2.f; - mat.ortho(left_ofs, left_ofs + scaled_w, (float)h, 0, -1.0f, 1.0f); - return mat; -} - -float VREyeInfo::getShift() const -{ - auto res = mShiftFactor * vr_ipd; - return vr_swap_eyes ? -res : res; -} - -VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio) const -{ - VSMatrix result; - - if (mShiftFactor == 0) - { - float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio))); - result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar()); - return result; - } - else - { - double zNear = screen->GetZNear(); - double zFar = screen->GetZFar(); - - // For stereo 3D, use asymmetric frustum shift in projection matrix - // Q: shouldn't shift vary with roll angle, at least for desktop display? - // A: No. (lab) roll is not measured on desktop display (yet) - double frustumShift = zNear * getShift() / vr_screendist; // meters cancel, leaving doom units - // double frustumShift = 0; // Turning off shift for debugging - double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio; - double fW = fH * aspectRatio * mScaleFactor; - double left = -fW - frustumShift; - double right = fW - frustumShift; - double bottom = -fH; - double top = fH; - - VSMatrix result(1); - result.frustum((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar); - return result; - } -} - - - -/* virtual */ -DVector3 VREyeInfo::GetViewShift(float yaw) const -{ - if (mShiftFactor == 0) - { - // pass-through for Mono view - return { 0,0,0 }; - } - else - { - double dx = -cos(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift(); - double dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift(); - return { dx, dy, 0 }; - } -} - diff --git a/src/rendering/i_video.h b/src/rendering/i_video.h deleted file mode 100644 index d9a9b97019d..00000000000 --- a/src/rendering/i_video.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __I_VIDEO_H__ -#define __I_VIDEO_H__ - -#include - -class DFrameBuffer; - - -class IVideo -{ -public: - virtual ~IVideo() {} - - virtual DFrameBuffer *CreateFrameBuffer() = 0; - - bool SetResolution(); - - virtual void DumpAdapters(); -}; - -void I_InitGraphics(); -void I_ShutdownGraphics(); - -extern IVideo *Video; - -void I_PolyPresentInit(); -uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch); -void I_PolyPresentUnlock(int x, int y, int w, int h); -void I_PolyPresentDeinit(); - - -// Pause a bit. -// [RH] Despite the name, it apparently never waited for the VBL, even in -// the original DOS version (if the Heretic/Hexen source is any indicator). -void I_WaitVBL(int count); - - -#endif // __I_VIDEO_H__ diff --git a/src/rendering/polyrenderer/backend/poly_buffers.cpp b/src/rendering/polyrenderer/backend/poly_buffers.cpp deleted file mode 100644 index fdbac72b8cd..00000000000 --- a/src/rendering/polyrenderer/backend/poly_buffers.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* -** Softpoly backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "poly_buffers.h" -#include "poly_framebuffer.h" -#include "poly_renderstate.h" -#include "rendering/polyrenderer/drawers/poly_thread.h" -#include "doomerrors.h" - -PolyBuffer *PolyBuffer::First = nullptr; - -PolyBuffer::PolyBuffer() -{ - Next = First; - First = this; - if (Next) Next->Prev = this; -} - -PolyBuffer::~PolyBuffer() -{ - if (Next) Next->Prev = Prev; - if (Prev) Prev->Next = Next; - else First = Next; - - auto fb = GetPolyFrameBuffer(); - if (fb && !mData.empty()) - fb->FrameDeleteList.Buffers.push_back(std::move(mData)); -} - -void PolyBuffer::ResetAll() -{ - for (PolyBuffer *cur = PolyBuffer::First; cur; cur = cur->Next) - cur->Reset(); -} - -void PolyBuffer::Reset() -{ -} - -void PolyBuffer::SetData(size_t size, const void *data, bool staticdata) -{ - mData.resize(size); - map = mData.data(); - if (data) - memcpy(map, data, size); - buffersize = size; -} - -void PolyBuffer::SetSubData(size_t offset, size_t size, const void *data) -{ - memcpy(static_cast(map) + offset, data, size); -} - -void PolyBuffer::Resize(size_t newsize) -{ - mData.resize(newsize); - buffersize = newsize; - map = mData.data(); -} - -void PolyBuffer::Map() -{ -} - -void PolyBuffer::Unmap() -{ -} - -void *PolyBuffer::Lock(unsigned int size) -{ - if (mData.size() < (size_t)size) - Resize(size); - return map; -} - -void PolyBuffer::Unlock() -{ -} - -///////////////////////////////////////////////////////////////////////////// - -void PolyVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) -{ - VertexFormat = GetPolyFrameBuffer()->GetRenderState()->GetVertexFormat(numBindingPoints, numAttributes, stride, attrs); -} - -///////////////////////////////////////////////////////////////////////////// - -void PolyVertexInputAssembly::Load(PolyTriangleThreadData *thread, const void *vertices, int index) -{ - const uint8_t *vertex = static_cast(vertices) + mStride * index; - const float *attrVertex = reinterpret_cast(vertex + mOffsets[VATTR_VERTEX]); - const float *attrTexcoord = reinterpret_cast(vertex + mOffsets[VATTR_TEXCOORD]); - const uint8_t *attrColor = reinterpret_cast(vertex + mOffsets[VATTR_COLOR]); - const uint32_t* attrNormal = reinterpret_cast(vertex + mOffsets[VATTR_NORMAL]); - const uint32_t* attrNormal2 = reinterpret_cast(vertex + mOffsets[VATTR_NORMAL2]); - - thread->mainVertexShader.aPosition = { attrVertex[0], attrVertex[1], attrVertex[2], 1.0f }; - thread->mainVertexShader.aTexCoord = { attrTexcoord[0], attrTexcoord[1] }; - - if ((UseVertexData & 1) == 0) - { - const auto &c = thread->mainVertexShader.Data.uVertexColor; - thread->mainVertexShader.aColor.X = c.X; - thread->mainVertexShader.aColor.Y = c.Y; - thread->mainVertexShader.aColor.Z = c.Z; - thread->mainVertexShader.aColor.W = c.W; - } - else - { - thread->mainVertexShader.aColor.X = attrColor[0] * (1.0f / 255.0f); - thread->mainVertexShader.aColor.Y = attrColor[1] * (1.0f / 255.0f); - thread->mainVertexShader.aColor.Z = attrColor[2] * (1.0f / 255.0f); - thread->mainVertexShader.aColor.W = attrColor[3] * (1.0f / 255.0f); - } - - if ((UseVertexData & 2) == 0) - { - const auto &n = thread->mainVertexShader.Data.uVertexNormal; - thread->mainVertexShader.aNormal = FVector4(n.X, n.Y, n.Z, 1.0); - thread->mainVertexShader.aNormal2 = thread->mainVertexShader.aNormal; - } - else - { - int n = *attrNormal; - int n2 = *attrNormal2; - float x = ((n << 22) >> 22) / 512.0f; - float y = ((n << 12) >> 22) / 512.0f; - float z = ((n << 2) >> 22) / 512.0f; - float x2 = ((n2 << 22) >> 22) / 512.0f; - float y2 = ((n2 << 12) >> 22) / 512.0f; - float z2 = ((n2 << 2) >> 22) / 512.0f; - thread->mainVertexShader.aNormal = FVector4(x, y, z, 0.0f); - thread->mainVertexShader.aNormal2 = FVector4(x2, y2, z2, 0.0f); - } -} - -///////////////////////////////////////////////////////////////////////////// - -void PolyDataBuffer::BindRange(FRenderState *state, size_t start, size_t length) -{ - static_cast(state)->Bind(this, (uint32_t)start, (uint32_t)length); -} diff --git a/src/rendering/polyrenderer/backend/poly_buffers.h b/src/rendering/polyrenderer/backend/poly_buffers.h deleted file mode 100644 index 681bacb2f42..00000000000 --- a/src/rendering/polyrenderer/backend/poly_buffers.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include "hwrenderer/data/buffers.h" -#include "polyrenderer/drawers/poly_triangle.h" -#include "utility/tarray.h" -#include - -#ifdef _MSC_VER -// silence bogus warning C4250: 'PolyVertexBuffer': inherits 'PolyBuffer::PolyBuffer::SetData' via dominance -// According to internet infos, the warning is erroneously emitted in this case. -#pragma warning(disable:4250) -#endif - -class PolyBuffer : virtual public IBuffer -{ -public: - PolyBuffer(); - ~PolyBuffer(); - - static void ResetAll(); - void Reset(); - - void SetData(size_t size, const void *data, bool staticdata) override; - void SetSubData(size_t offset, size_t size, const void *data) override; - void Resize(size_t newsize) override; - - void Map() override; - void Unmap() override; - - void *Lock(unsigned int size) override; - void Unlock() override; - -private: - static PolyBuffer *First; - PolyBuffer *Prev = nullptr; - PolyBuffer *Next = nullptr; - std::vector mData; -}; - -class PolyVertexInputAssembly final : public PolyInputAssembly -{ -public: - size_t mOffsets[VATTR_MAX] = {}; - size_t mStride = 0; - - int NumBindingPoints; - size_t Stride; - std::vector Attrs; - int UseVertexData; - - void Load(PolyTriangleThreadData *thread, const void *vertices, int index) override; -}; - -class PolyVertexBuffer : public IVertexBuffer, public PolyBuffer -{ -public: - PolyVertexBuffer() { } - void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override; - - PolyVertexInputAssembly *VertexFormat = nullptr; -}; - -class PolyIndexBuffer : public IIndexBuffer, public PolyBuffer -{ -public: - PolyIndexBuffer() { } -}; - -class PolyDataBuffer : public IDataBuffer, public PolyBuffer -{ -public: - PolyDataBuffer(int bindingpoint, bool ssbo, bool needresize) : bindingpoint(bindingpoint) - { - } - - void BindRange(FRenderState *state, size_t start, size_t length) override; - - int bindingpoint; -}; diff --git a/src/rendering/polyrenderer/backend/poly_framebuffer.cpp b/src/rendering/polyrenderer/backend/poly_framebuffer.cpp deleted file mode 100644 index f9e7adb08a9..00000000000 --- a/src/rendering/polyrenderer/backend/poly_framebuffer.cpp +++ /dev/null @@ -1,676 +0,0 @@ -/* -** Softpoly backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "v_video.h" -#include "m_png.h" -#include "templates.h" -#include "r_videoscale.h" -#include "actor.h" -#include "i_time.h" -#include "g_game.h" -#include "gamedata/fonts/v_text.h" - -#include "rendering/i_video.h" - -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/models/hw_models.h" -#include "hwrenderer/scene/hw_skydome.h" -#include "hwrenderer/scene/hw_fakeflat.h" -#include "hwrenderer/scene/hw_drawinfo.h" -#include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/data/shaderuniforms.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" -#include "hwrenderer/postprocessing/hw_postprocess.h" - -#include "swrenderer/r_swscene.h" - -#include "poly_framebuffer.h" -#include "poly_buffers.h" -#include "poly_renderstate.h" -#include "poly_hwtexture.h" -#include "doomerrors.h" - -void Draw2D(F2DDrawer *drawer, FRenderState &state); -void DoWriteSavePic(FileWriter *file, ESSType ssformat, uint8_t *scr, int width, int height, sector_t *viewsector, bool upsidedown); - -EXTERN_CVAR(Bool, r_drawvoxels) -EXTERN_CVAR(Int, gl_tonemap) -EXTERN_CVAR(Int, screenblocks) -EXTERN_CVAR(Bool, cl_capfps) -EXTERN_CVAR(Bool, gl_no_skyclear) - -extern bool NoInterpolateView; -extern int rendered_commandbuffers; -extern int current_rendered_commandbuffers; - -extern bool gpuStatActive; -extern bool keepGpuStatActive; -extern FString gpuStatOutput; - -PolyFrameBuffer::PolyFrameBuffer(void *hMonitor, bool fullscreen) : Super(hMonitor, fullscreen) -{ - I_PolyPresentInit(); -} - -PolyFrameBuffer::~PolyFrameBuffer() -{ - // screen is already null at this point, but PolyHardwareTexture::ResetAll needs it during clean up. Is there a better way we can do this? - auto tmp = screen; - screen = this; - - PolyHardwareTexture::ResetAll(); - PolyBuffer::ResetAll(); - PPResource::ResetAll(); - - delete mScreenQuad.VertexBuffer; - delete mScreenQuad.IndexBuffer; - - delete mVertexData; - delete mSkyData; - delete mViewpoints; - delete mLights; - mShadowMap.Reset(); - - screen = tmp; - - I_PolyPresentDeinit(); -} - -void PolyFrameBuffer::InitializeState() -{ - vendorstring = "Poly"; - hwcaps = RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE; - glslversion = 4.50f; - uniformblockalignment = 1; - maxuniformblock = 0x7fffffff; - - mRenderState.reset(new PolyRenderState()); - - mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight()); - mSkyData = new FSkyVertexBuffer; - mViewpoints = new HWViewpointBuffer; - mLights = new FLightBuffer(); - - static const FVertexBufferAttribute format[] = - { - { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(ScreenQuadVertex, x) }, - { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(ScreenQuadVertex, u) }, - { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(ScreenQuadVertex, color0) } - }; - - uint32_t indices[6] = { 0, 1, 2, 1, 3, 2 }; - - mScreenQuad.VertexBuffer = screen->CreateVertexBuffer(); - mScreenQuad.VertexBuffer->SetFormat(1, 3, sizeof(ScreenQuadVertex), format); - - mScreenQuad.IndexBuffer = screen->CreateIndexBuffer(); - mScreenQuad.IndexBuffer->SetData(6 * sizeof(uint32_t), indices, false); - - CheckCanvas(); -} - -void PolyFrameBuffer::CheckCanvas() -{ - if (!mCanvas || mCanvas->GetWidth() != GetWidth() || mCanvas->GetHeight() != GetHeight()) - { - FlushDrawCommands(); - DrawerThreads::WaitForWorkers(); - - mCanvas.reset(new DCanvas(0, 0, true)); - mCanvas->Resize(GetWidth(), GetHeight(), false); - mDepthStencil.reset(); - mDepthStencil.reset(new PolyDepthStencil(GetWidth(), GetHeight())); - - mRenderState->SetRenderTarget(GetCanvas(), GetDepthStencil(), true); - } -} - -PolyCommandBuffer *PolyFrameBuffer::GetDrawCommands() -{ - if (!mDrawCommands) - { - mDrawCommands.reset(new PolyCommandBuffer(&mFrameMemory)); - mDrawCommands->SetLightBuffer(mLightBuffer->Memory()); - } - return mDrawCommands.get(); -} - -void PolyFrameBuffer::FlushDrawCommands() -{ - mRenderState->EndRenderPass(); - if (mDrawCommands) - { - mDrawCommands->Submit(); - mDrawCommands.reset(); - } -} - -void PolyFrameBuffer::Update() -{ - twoD.Reset(); - Flush3D.Reset(); - - Flush3D.Clock(); - - Draw2D(); - Clear2D(); - - Flush3D.Unclock(); - - FlushDrawCommands(); - - if (mCanvas) - { - int w = mCanvas->GetWidth(); - int h = mCanvas->GetHeight(); - int pixelsize = 4; - const uint8_t *src = (const uint8_t*)mCanvas->GetPixels(); - int pitch = 0; - uint8_t *dst = I_PolyPresentLock(w, h, cur_vsync, pitch); - if (dst) - { -#if 1 - auto copyqueue = std::make_shared(&mFrameMemory); - copyqueue->Push(dst, pitch / pixelsize, src, w, h, w, pixelsize); - DrawerThreads::Execute(copyqueue); -#else - for (int y = 0; y < h; y++) - { - memcpy(dst + y * pitch, src + y * w * pixelsize, w * pixelsize); - } -#endif - - DrawerThreads::WaitForWorkers(); - I_PolyPresentUnlock(mOutputLetterbox.left, mOutputLetterbox.top, mOutputLetterbox.width, mOutputLetterbox.height); - } - FPSLimit(); - } - - DrawerThreads::WaitForWorkers(); - mFrameMemory.Clear(); - FrameDeleteList.Buffers.clear(); - FrameDeleteList.Images.clear(); - - CheckCanvas(); - - Super::Update(); -} - - -void PolyFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height) -{ - if (!V_IsHardwareRenderer()) - { - Super::WriteSavePic(player, file, width, height); - } - else - { - } -} - -sector_t *PolyFrameBuffer::RenderView(player_t *player) -{ - // To do: this is virtually identical to FGLRenderer::RenderView and should be merged. - - mRenderState->SetVertexBuffer(mVertexData); - mVertexData->Reset(); - - sector_t *retsec; - if (!V_IsHardwareRenderer()) - { - if (!swdrawer) swdrawer.reset(new SWSceneDrawer); - retsec = swdrawer->RenderView(player); - } - else - { - hw_ClearFakeFlat(); - - iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; - - checkBenchActive(); - - // reset statistics counters - ResetProfilingData(); - - // Get this before everything else - if (cl_capfps || r_NoInterpolate) r_viewpoint.TicFrac = 1.; - else r_viewpoint.TicFrac = I_GetTimeFrac(); - - mLights->Clear(); - mViewpoints->Clear(); - - // NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below. - bool saved_niv = NoInterpolateView; - NoInterpolateView = false; - - // Shader start time does not need to be handled per level. Just use the one from the camera to render from. - if (player->camera) - GetRenderState()->CheckTimer(player->camera->Level->ShaderStartTime); - // prepare all camera textures that have been used in the last frame. - // This must be done for all levels, not just the primary one! - for (auto Level : AllLevels()) - { - Level->canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov) - { - RenderTextureView(camtex, camera, fov); - }); - } - NoInterpolateView = saved_niv; - - // now render the main view - float fovratio; - float ratio = r_viewwindow.WidescreenRatio; - if (r_viewwindow.WidescreenRatio >= 1.3f) - { - fovratio = 1.333333f; - } - else - { - fovratio = ratio; - } - - retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true); - } - All.Unclock(); - return retsec; -} - -sector_t *PolyFrameBuffer::RenderViewpoint(FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen) -{ - // To do: this is virtually identical to FGLRenderer::RenderViewpoint and should be merged. - - R_SetupFrame(mainvp, r_viewwindow, camera); - - if (mainview && toscreen) - UpdateShadowMap(); - - // Update the attenuation flag of all light defaults for each viewpoint. - // This function will only do something if the setting differs. - FLightDefaults::SetAttenuationForLevel(!!(camera->Level->flags3 & LEVEL3_ATTENUATE)); - - // Render (potentially) multiple views for stereo 3d - // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. - auto vrmode = VRMode::GetVRMode(mainview && toscreen); - for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix) - { - const auto &eye = vrmode->mEyes[eye_ix]; - SetViewportRects(bounds); - - if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao - { - //mRenderState->SetRenderTarget(GetBuffers()->SceneColor.View.get(), GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), Poly_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); - bool useSSAO = (gl_ssao != 0); - GetRenderState()->SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); - GetRenderState()->EnableDrawBuffers(GetRenderState()->GetPassDrawBufferCount()); - } - - auto di = HWDrawInfo::StartDrawInfo(mainvp.ViewLevel, nullptr, mainvp, nullptr); - auto &vp = di->Viewpoint; - - di->Set3DViewport(*GetRenderState()); - di->SetViewArea(); - auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr); - di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint) - - // Stereo mode specific perspective projection - di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio); - // Stereo mode specific viewpoint adjustment - vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees); - di->SetupView(*GetRenderState(), vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); - - // std::function until this can be done better in a cross-API fashion. - di->ProcessScene(toscreen, [&](HWDrawInfo *di, int mode) { - DrawScene(di, mode); - }); - - if (mainview) - { - PostProcess.Clock(); - if (toscreen) di->EndDrawScene(mainvp.sector, *GetRenderState()); // do not call this for camera textures. - - if (GetRenderState()->GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers - { - GetRenderState()->SetPassType(NORMAL_PASS); - GetRenderState()->EnableDrawBuffers(1); - } - - //mPostprocess->BlitSceneToPostprocess(); // Copy the resulting scene to the current post process texture - - PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector, *GetRenderState()); }); - - PostProcess.Unclock(); - } - di->EndDrawInfo(); - -#if 0 - if (vrmode->mEyeCount > 1) - mBuffers->BlitToEyeTexture(eye_ix); -#endif - } - - return mainvp.sector; -} - -void PolyFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) -{ - // This doesn't need to clear the fake flat cache. It can be shared between camera textures and the main view of a scene. - FMaterial *mat = FMaterial::ValidateTexture(tex, false); - auto BaseLayer = static_cast(mat->GetLayer(0, 0)); - - int width = mat->TextureWidth(); - int height = mat->TextureHeight(); - DCanvas *image = BaseLayer->GetImage(tex, 0, 0); - PolyDepthStencil *depthStencil = BaseLayer->GetDepthStencil(tex); - mRenderState->SetRenderTarget(image, depthStencil, false); - - IntRect bounds; - bounds.left = bounds.top = 0; - bounds.width = MIN(mat->GetWidth(), image->GetWidth()); - bounds.height = MIN(mat->GetHeight(), image->GetHeight()); - - FRenderViewpoint texvp; - RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false); - - FlushDrawCommands(); - DrawerThreads::WaitForWorkers(); - mRenderState->SetRenderTarget(GetCanvas(), GetDepthStencil(), true); - - tex->SetUpdated(true); -} - -void PolyFrameBuffer::DrawScene(HWDrawInfo *di, int drawmode) -{ - // To do: this is virtually identical to FGLRenderer::DrawScene and should be merged. - - static int recursion = 0; - static int ssao_portals_available = 0; - const auto &vp = di->Viewpoint; - - bool applySSAO = false; - if (drawmode == DM_MAINVIEW) - { - ssao_portals_available = gl_ssao_portals; - applySSAO = true; - } - else if (drawmode == DM_OFFSCREEN) - { - ssao_portals_available = 0; - } - else if (drawmode == DM_PORTAL && ssao_portals_available > 0) - { - applySSAO = true; - ssao_portals_available--; - } - - if (vp.camera != nullptr) - { - ActorRenderFlags savedflags = vp.camera->renderflags; - di->CreateScene(drawmode == DM_MAINVIEW); - vp.camera->renderflags = savedflags; - } - else - { - di->CreateScene(false); - } - - GetRenderState()->SetDepthMask(true); - if (!gl_no_skyclear) mPortalState->RenderFirstSkyPortal(recursion, di, *GetRenderState()); - - di->RenderScene(*GetRenderState()); - - if (applySSAO && GetRenderState()->GetPassType() == GBUFFER_PASS) - { - //mPostprocess->AmbientOccludeScene(di->VPUniforms.mProjectionMatrix.get()[5]); - //mViewpoints->Bind(*GetRenderState(), di->vpIndex); - } - - // Handle all portals after rendering the opaque objects but before - // doing all translucent stuff - recursion++; - mPortalState->EndFrame(di, *GetRenderState()); - recursion--; - di->RenderTranslucent(*GetRenderState()); -} - -static uint8_t ToIntColorComponent(float v) -{ - return clamp((int)(v * 255.0f + 0.5f), 0, 255); -} - -void PolyFrameBuffer::PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) -{ - afterBloomDrawEndScene2D(); - - if (fixedcm >= CM_FIRSTSPECIALCOLORMAP && fixedcm < CM_MAXCOLORMAP) - { - FSpecialColormap* scm = &SpecialColormaps[fixedcm - CM_FIRSTSPECIALCOLORMAP]; - - mRenderState->SetViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); - screen->mViewpoints->Set2D(*mRenderState, screen->GetWidth(), screen->GetHeight()); - - ScreenQuadVertex vertices[4] = - { - { 0.0f, 0.0f, 0.0f, 0.0f }, - { (float)mScreenViewport.width, 0.0f, 1.0f, 0.0f }, - { 0.0f, (float)mScreenViewport.height, 0.0f, 1.0f }, - { (float)mScreenViewport.width, (float)mScreenViewport.height, 1.0f, 1.0f } - }; - mScreenQuad.VertexBuffer->SetData(4 * sizeof(ScreenQuadVertex), vertices, false); - - mRenderState->SetVertexBuffer(mScreenQuad.VertexBuffer, 0, 0); - mRenderState->SetIndexBuffer(mScreenQuad.IndexBuffer); - - mRenderState->SetObjectColor(PalEntry(255, int(scm->ColorizeStart[0] * 127.5f), int(scm->ColorizeStart[1] * 127.5f), int(scm->ColorizeStart[2] * 127.5f))); - mRenderState->SetAddColor(PalEntry(255, int(scm->ColorizeEnd[0] * 127.5f), int(scm->ColorizeEnd[1] * 127.5f), int(scm->ColorizeEnd[2] * 127.5f))); - - mRenderState->EnableDepthTest(false); - mRenderState->EnableMultisampling(false); - mRenderState->SetCulling(Cull_None); - - mRenderState->SetScissor(-1, -1, -1, -1); - mRenderState->SetColor(1, 1, 1, 1); - mRenderState->AlphaFunc(Alpha_GEqual, 0.f); - mRenderState->EnableTexture(false); - mRenderState->SetColormapShader(true); - mRenderState->DrawIndexed(DT_Triangles, 0, 6); - mRenderState->SetColormapShader(false); - mRenderState->SetObjectColor(0xffffffff); - mRenderState->SetAddColor(0); - mRenderState->SetVertexBuffer(screen->mVertexData); - mRenderState->EnableTexture(true); - mRenderState->ResetColor(); - } -} - -uint32_t PolyFrameBuffer::GetCaps() -{ - if (!V_IsHardwareRenderer()) - return Super::GetCaps(); - - // describe our basic feature set - ActorRenderFeatureFlags FlagSet = RFF_FLATSPRITES | RFF_MODELS | RFF_SLOPE3DFLOORS | - RFF_TILTPITCH | RFF_ROLLSPRITES | RFF_POLYGONAL | RFF_MATSHADER | RFF_POSTSHADER | RFF_BRIGHTMAP; - if (r_drawvoxels) - FlagSet |= RFF_VOXELS; - - if (gl_tonemap != 5) // not running palette tonemap shader - FlagSet |= RFF_TRUECOLOR; - - return (uint32_t)FlagSet; -} - -void PolyFrameBuffer::SetVSync(bool vsync) -{ - cur_vsync = vsync; -} - -void PolyFrameBuffer::CleanForRestart() -{ - // force recreation of the SW scene drawer to ensure it gets a new set of resources. - swdrawer.reset(); -} - -void PolyFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) -{ - auto tex = mat->tex; - if (tex->isSWCanvas()) return; - - int flags = mat->isExpanded() ? CTF_Expand : 0; - auto base = static_cast(mat->GetLayer(0, translation)); - - base->Precache(mat, translation, flags); -} - -IHardwareTexture *PolyFrameBuffer::CreateHardwareTexture() -{ - return new PolyHardwareTexture(); -} - -FModelRenderer *PolyFrameBuffer::CreateModelRenderer(int mli) -{ - return new FHWModelRenderer(nullptr, *GetRenderState(), mli); -} - -IVertexBuffer *PolyFrameBuffer::CreateVertexBuffer() -{ - return new PolyVertexBuffer(); -} - -IIndexBuffer *PolyFrameBuffer::CreateIndexBuffer() -{ - return new PolyIndexBuffer(); -} - -IDataBuffer *PolyFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) -{ - IDataBuffer *buffer = new PolyDataBuffer(bindingpoint, ssbo, needsresize); - if (bindingpoint == LIGHTBUF_BINDINGPOINT) - mLightBuffer = buffer; - return buffer; -} - -void PolyFrameBuffer::SetTextureFilterMode() -{ - TextureFilterChanged(); -} - -void PolyFrameBuffer::TextureFilterChanged() -{ -} - -void PolyFrameBuffer::StartPrecaching() -{ -} - -void PolyFrameBuffer::BlurScene(float amount) -{ -} - -void PolyFrameBuffer::UpdatePalette() -{ -} - -FTexture *PolyFrameBuffer::WipeStartScreen() -{ - SetViewportRects(nullptr); - - auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1); - auto systex = static_cast(tex->GetSystemTexture()); - - systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeStartScreen"); - - return tex; -} - -FTexture *PolyFrameBuffer::WipeEndScreen() -{ - Draw2D(); - Clear2D(); - - auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1); - auto systex = static_cast(tex->GetSystemTexture()); - - systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeEndScreen"); - - return tex; -} - -TArray PolyFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) -{ - int w = SCREENWIDTH; - int h = SCREENHEIGHT; - - TArray ScreenshotBuffer(w * h * 3, true); - const uint8_t* pixels = GetCanvas()->GetPixels(); - int dindex = 0; - - // Convert to RGB - for (int y = 0; y < h; y++) - { - int sindex = y * w * 4; - - for (int x = 0; x < w; x++) - { - ScreenshotBuffer[dindex ] = pixels[sindex + 2]; - ScreenshotBuffer[dindex + 1] = pixels[sindex + 1]; - ScreenshotBuffer[dindex + 2] = pixels[sindex ]; - dindex += 3; - sindex += 4; - } - } - - pitch = w * 3; - color_type = SS_RGB; - gamma = 1.0f; - return ScreenshotBuffer; -} - -void PolyFrameBuffer::BeginFrame() -{ - SetViewportRects(nullptr); - CheckCanvas(); - - swrenderer::R_InitFuzzTable(GetCanvas()->GetPitch()); - static int next_random = 0; - swrenderer::fuzzpos = (swrenderer::fuzzpos + swrenderer::fuzz_random_x_offset[next_random] * FUZZTABLE / 100) % FUZZTABLE; - next_random++; - if (next_random == FUZZ_RANDOM_X_SIZE) - next_random = 0; -} - -void PolyFrameBuffer::Draw2D() -{ - ::Draw2D(&m2DDrawer, *mRenderState); -} - -unsigned int PolyFrameBuffer::GetLightBufferBlockSize() const -{ - return mLights->GetBlockSize(); -} - -void PolyFrameBuffer::UpdateShadowMap() -{ -} diff --git a/src/rendering/polyrenderer/backend/poly_framebuffer.h b/src/rendering/polyrenderer/backend/poly_framebuffer.h deleted file mode 100644 index 2e06d69062a..00000000000 --- a/src/rendering/polyrenderer/backend/poly_framebuffer.h +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include "gl_sysfb.h" -#include "rendering/swrenderer/r_memory.h" -#include "rendering/swrenderer/drawers/r_thread.h" -#include "rendering/polyrenderer/drawers/poly_triangle.h" - -struct FRenderViewpoint; -class PolyDataBuffer; -class PolyRenderState; -class SWSceneDrawer; - -class PolyFrameBuffer : public SystemBaseFrameBuffer -{ - typedef SystemBaseFrameBuffer Super; - -public: - RenderMemory *GetFrameMemory() { return &mFrameMemory; } - PolyRenderState *GetRenderState() { return mRenderState.get(); } - DCanvas *GetCanvas() override { return mCanvas.get(); } - PolyDepthStencil *GetDepthStencil() { return mDepthStencil.get(); } - PolyCommandBuffer *GetDrawCommands(); - void FlushDrawCommands(); - - unsigned int GetLightBufferBlockSize() const; - - std::unique_ptr swdrawer; - - PolyFrameBuffer(void *hMonitor, bool fullscreen); - ~PolyFrameBuffer(); - - void Update(); - - bool IsPoly() override { return true; } - - void InitializeState() override; - - void CleanForRestart() override; - void PrecacheMaterial(FMaterial *mat, int translation) override; - void UpdatePalette() override; - uint32_t GetCaps() override; - void WriteSavePic(player_t *player, FileWriter *file, int width, int height) override; - sector_t *RenderView(player_t *player) override; - void SetTextureFilterMode() override; - void TextureFilterChanged() override; - void StartPrecaching() override; - void BeginFrame() override; - void BlurScene(float amount) override; - void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) override; - - IHardwareTexture *CreateHardwareTexture() override; - FModelRenderer *CreateModelRenderer(int mli) override; - IVertexBuffer *CreateVertexBuffer() override; - IIndexBuffer *CreateIndexBuffer() override; - IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override; - - FTexture *WipeStartScreen() override; - FTexture *WipeEndScreen() override; - - TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override; - - void SetVSync(bool vsync) override; - void Draw2D() override; - - struct DeleteList - { - std::vector> Buffers; - std::vector> Images; - } FrameDeleteList; - -private: - sector_t *RenderViewpoint(FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen); - void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV); - void DrawScene(HWDrawInfo *di, int drawmode); - void UpdateShadowMap(); - - void CheckCanvas(); - - IDataBuffer *mLightBuffer = nullptr; - - std::unique_ptr mRenderState; - std::unique_ptr mCanvas; - std::unique_ptr mDepthStencil; - std::unique_ptr mDrawCommands; - RenderMemory mFrameMemory; - - struct ScreenQuadVertex - { - float x, y, z; - float u, v; - PalEntry color0; - - ScreenQuadVertex() = default; - ScreenQuadVertex(float x, float y, float u, float v) : x(x), y(y), z(1.0f), u(u), v(v), color0(0xffffffff) { } - }; - - struct ScreenQuad - { - IVertexBuffer* VertexBuffer = nullptr; - IIndexBuffer* IndexBuffer = nullptr; - } mScreenQuad; - - bool cur_vsync = false; -}; - -inline PolyFrameBuffer *GetPolyFrameBuffer() { return static_cast(screen); } diff --git a/src/rendering/polyrenderer/backend/poly_hwtexture.cpp b/src/rendering/polyrenderer/backend/poly_hwtexture.cpp deleted file mode 100644 index ffac7f54731..00000000000 --- a/src/rendering/polyrenderer/backend/poly_hwtexture.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* -** Softpoly backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "templates.h" -#include "c_cvars.h" -#include "r_data/colormaps.h" -#include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include "poly_framebuffer.h" -#include "poly_hwtexture.h" - -PolyHardwareTexture *PolyHardwareTexture::First = nullptr; - -PolyHardwareTexture::PolyHardwareTexture() -{ - Next = First; - First = this; - if (Next) Next->Prev = this; -} - -PolyHardwareTexture::~PolyHardwareTexture() -{ - if (Next) Next->Prev = Prev; - if (Prev) Prev->Next = Next; - else First = Next; - - Reset(); -} - -void PolyHardwareTexture::ResetAll() -{ - for (PolyHardwareTexture *cur = PolyHardwareTexture::First; cur; cur = cur->Next) - cur->Reset(); -} - -void PolyHardwareTexture::Reset() -{ - if (auto fb = GetPolyFrameBuffer()) - { - auto &deleteList = fb->FrameDeleteList; - if (mCanvas) deleteList.Images.push_back(std::move(mCanvas)); - } -} - -void PolyHardwareTexture::Precache(FMaterial *mat, int translation, int flags) -{ - int numLayers = mat->GetLayers(); - GetImage(mat->tex, translation, flags); - for (int i = 1; i < numLayers; i++) - { - FTexture *layer; - auto systex = static_cast(mat->GetLayer(i, 0, &layer)); - systex->GetImage(layer, 0, mat->isExpanded() ? CTF_Expand : 0); - } -} - -DCanvas *PolyHardwareTexture::GetImage(const FMaterialState &state) -{ - FTexture *tex = state.mMaterial->tex; - if (tex->isHardwareCanvas()) static_cast(tex)->NeedUpdate(); - - if (!mCanvas) - { - FMaterial *mat = state.mMaterial; - int clampmode = state.mClampMode; - int translation = state.mTranslation; - - if (tex->UseType == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; - if (tex->isHardwareCanvas()) clampmode = CLAMP_CAMTEX; - else if ((tex->isWarped() || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; - - int flags = state.mMaterial->isExpanded() ? CTF_Expand : 0; - - return GetImage(tex, translation, flags); - } - - return mCanvas.get(); -} - -DCanvas *PolyHardwareTexture::GetImage(FTexture *tex, int translation, int flags) -{ - if (!mCanvas) - CreateImage(tex, translation, flags); - return mCanvas.get(); -} - -PolyDepthStencil *PolyHardwareTexture::GetDepthStencil(FTexture *tex) -{ - if (!mDepthStencil) - { - int w = tex->GetWidth(); - int h = tex->GetHeight(); - mDepthStencil.reset(new PolyDepthStencil(w, h)); - } - return mDepthStencil.get(); -} - -void PolyHardwareTexture::AllocateBuffer(int w, int h, int texelsize) -{ - if (!mCanvas || mCanvas->GetWidth() != w || mCanvas->GetHeight() != h) - { - mCanvas.reset(new DCanvas(0, 0, texelsize == 4)); - mCanvas->Resize(w, h, false); - bufferpitch = mCanvas->GetPitch(); - } -} - -uint8_t *PolyHardwareTexture::MapBuffer() -{ - return mCanvas->GetPixels(); -} - -unsigned int PolyHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) -{ - return 0; -} - -void PolyHardwareTexture::CreateWipeTexture(int w, int h, const char *name) -{ - if (!mCanvas || mCanvas->GetWidth() != w || mCanvas->GetHeight() != h) - { - mCanvas.reset(new DCanvas(0, 0, true)); - mCanvas->Resize(w, h, false); - } - - auto fb = static_cast(screen); - - fb->FlushDrawCommands(); - DrawerThreads::WaitForWorkers(); - - uint32_t* dest = (uint32_t*)mCanvas->GetPixels(); - uint32_t* src = (uint32_t*)fb->GetCanvas()->GetPixels(); - int dpitch = mCanvas->GetPitch(); - int spitch = fb->GetCanvas()->GetPitch(); - int pixelsize = 4; - - for (int y = 0; y < h; y++) - { - memcpy(dest + dpitch * (h - 1 - y), src + spitch * y, w * pixelsize); - } -} - -void PolyHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) -{ - mCanvas.reset(new DCanvas(0, 0, true)); - - if (!tex->isHardwareCanvas()) - { - auto remap = TranslationToTable(translation); - translation = remap == nullptr ? 0 : remap->GetUniqueIndex(); - - FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); - mCanvas->Resize(texbuffer.mWidth, texbuffer.mHeight, false); - memcpy(mCanvas->GetPixels(), texbuffer.mBuffer, texbuffer.mWidth * texbuffer.mHeight * 4); - } - else - { - int w = tex->GetWidth(); - int h = tex->GetHeight(); - mCanvas->Resize(w, h, false); - } -} diff --git a/src/rendering/polyrenderer/backend/poly_hwtexture.h b/src/rendering/polyrenderer/backend/poly_hwtexture.h deleted file mode 100644 index d88604c66ae..00000000000 --- a/src/rendering/polyrenderer/backend/poly_hwtexture.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#ifdef LoadImage -#undef LoadImage -#endif - -#define SHADED_TEXTURE -1 -#define DIRECT_PALETTE -2 - -#include "tarray.h" -#include "hwrenderer/textures/hw_ihwtexture.h" -#include "volk/volk.h" - -struct FMaterialState; -class PolyBuffer; - -class PolyHardwareTexture : public IHardwareTexture -{ -public: - PolyHardwareTexture(); - ~PolyHardwareTexture(); - - static void ResetAll(); - void Reset(); - - void Precache(FMaterial *mat, int translation, int flags); - - DCanvas *GetImage(const FMaterialState &state); - DCanvas *GetImage(FTexture *tex, int translation, int flags); - PolyDepthStencil *GetDepthStencil(FTexture *tex); - - // Software renderer stuff - void AllocateBuffer(int w, int h, int texelsize) override; - uint8_t *MapBuffer() override; - unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) override; - - // Wipe screen - void CreateWipeTexture(int w, int h, const char *name); - -private: - void CreateImage(FTexture *tex, int translation, int flags); - - static PolyHardwareTexture *First; - PolyHardwareTexture *Prev = nullptr; - PolyHardwareTexture *Next = nullptr; - std::unique_ptr mCanvas; - std::unique_ptr mDepthStencil; -}; diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.cpp b/src/rendering/polyrenderer/backend/poly_renderstate.cpp deleted file mode 100644 index 1d19460ec64..00000000000 --- a/src/rendering/polyrenderer/backend/poly_renderstate.cpp +++ /dev/null @@ -1,445 +0,0 @@ -/* -** Softpoly backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "polyrenderer/backend/poly_renderstate.h" -#include "polyrenderer/backend/poly_framebuffer.h" -#include "polyrenderer/backend/poly_hwtexture.h" -#include "templates.h" -#include "doomstat.h" -#include "r_data/colormaps.h" -#include "hwrenderer/scene/hw_skydome.h" -#include "hwrenderer/scene/hw_viewpointuniforms.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "hwrenderer/data/shaderuniforms.h" -#include "swrenderer/r_swcolormaps.h" - -static PolyDrawMode dtToDrawMode[] = -{ - PolyDrawMode::Points, - PolyDrawMode::Lines, - PolyDrawMode::Triangles, - PolyDrawMode::TriangleFan, - PolyDrawMode::TriangleStrip, -}; - -PolyRenderState::PolyRenderState() -{ - mIdentityMatrix.loadIdentity(); - Reset(); -} - -void PolyRenderState::ClearScreen() -{ - screen->mViewpoints->Set2D(*this, SCREENWIDTH, SCREENHEIGHT); - SetColor(0, 0, 0); - Draw(DT_TriangleStrip, FFlatVertexBuffer::FULLSCREEN_INDEX, 4, true); -} - -void PolyRenderState::Draw(int dt, int index, int count, bool apply) -{ - if (apply || mNeedApply) - Apply(); - - mDrawCommands->Draw(index, count, dtToDrawMode[dt]); -} - -void PolyRenderState::DrawIndexed(int dt, int index, int count, bool apply) -{ - if (apply || mNeedApply) - Apply(); - - mDrawCommands->DrawIndexed(index, count, dtToDrawMode[dt]); -} - -bool PolyRenderState::SetDepthClamp(bool on) -{ - bool lastValue = mDepthClamp; - mDepthClamp = on; - mNeedApply = true; - return lastValue; -} - -void PolyRenderState::SetDepthMask(bool on) -{ - mDepthMask = on; - mNeedApply = true; -} - -void PolyRenderState::SetDepthFunc(int func) -{ - mDepthFunc = func; - mNeedApply = true; -} - -void PolyRenderState::SetDepthRange(float min, float max) -{ - mDepthRangeMin = min; - mDepthRangeMax = max; - mNeedApply = true; -} - -void PolyRenderState::SetColorMask(bool r, bool g, bool b, bool a) -{ - mColorMask[0] = r; - mColorMask[1] = g; - mColorMask[2] = b; - mColorMask[3] = a; - mNeedApply = true; -} - -void PolyRenderState::SetStencil(int offs, int op, int flags) -{ - mStencilValue = screen->stencilValue + offs; - mStencilOp = op; - mNeedApply = true; - - if (flags != -1) - { - bool cmon = !(flags & SF_ColorMaskOff); - SetColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer - SetDepthMask(!(flags & SF_DepthMaskOff)); - } -} - -void PolyRenderState::SetCulling(int mode) -{ - mCulling = mode; - mNeedApply = true; -} - -void PolyRenderState::EnableClipDistance(int num, bool state) -{ -} - -void PolyRenderState::Clear(int targets) -{ - if (mNeedApply) - Apply(); - - //if (targets & CT_Color) - // mDrawCommands->ClearColor(); - if (targets & CT_Depth) - mDrawCommands->ClearDepth(65535.0f); - if (targets & CT_Stencil) - mDrawCommands->ClearStencil(0); -} - -void PolyRenderState::EnableStencil(bool on) -{ - mStencilEnabled = on; - mNeedApply = true; -} - -void PolyRenderState::SetScissor(int x, int y, int w, int h) -{ - if (w < 0) - { - x = 0; - y = 0; - w = mRenderTarget.Canvas->GetWidth(); - h = mRenderTarget.Canvas->GetHeight(); - } - mScissor.x = x; - mScissor.y = mRenderTarget.Canvas->GetHeight() - y - h; - mScissor.width = w; - mScissor.height = h; - mNeedApply = true; -} - -void PolyRenderState::SetViewport(int x, int y, int w, int h) -{ - auto fb = GetPolyFrameBuffer(); - if (w < 0) - { - x = 0; - y = 0; - w = mRenderTarget.Canvas->GetWidth(); - h = mRenderTarget.Canvas->GetHeight(); - } - mViewport.x = x; - mViewport.y = mRenderTarget.Canvas->GetHeight() - y - h; - mViewport.width = w; - mViewport.height = h; - mNeedApply = true; -} - -void PolyRenderState::EnableDepthTest(bool on) -{ - mDepthTest = on; - mNeedApply = true; -} - -void PolyRenderState::EnableMultisampling(bool on) -{ -} - -void PolyRenderState::EnableLineSmooth(bool on) -{ -} - -void PolyRenderState::EnableDrawBuffers(int count) -{ -} - -void PolyRenderState::SetColormapShader(bool enable) -{ - mNeedApply = true; - mColormapShader = enable; -} - -void PolyRenderState::EndRenderPass() -{ - mDrawCommands = nullptr; - mNeedApply = true; - mFirstMatrixApply = true; -} - -void PolyRenderState::Apply() -{ - drawcalls.Clock(); - - if (!mDrawCommands) - { - mDrawCommands = GetPolyFrameBuffer()->GetDrawCommands(); - } - - if (mNeedApply) - { - mDrawCommands->SetViewport(mViewport.x, mViewport.y, mViewport.width, mViewport.height, mRenderTarget.Canvas, mRenderTarget.DepthStencil, mRenderTarget.TopDown); - mDrawCommands->SetScissor(mScissor.x, mScissor.y, mScissor.width, mScissor.height); - mDrawCommands->SetViewpointUniforms(mViewpointUniforms); - mDrawCommands->SetDepthClamp(mDepthClamp); - mDrawCommands->SetDepthMask(mDepthTest && mDepthMask); - mDrawCommands->SetDepthFunc(mDepthTest ? mDepthFunc : DF_Always); - mDrawCommands->SetDepthRange(mDepthRangeMin, mDepthRangeMax); - mDrawCommands->SetStencil(mStencilValue, mStencilOp); - mDrawCommands->EnableStencil(mStencilEnabled); - mDrawCommands->SetCulling(mCulling); - mDrawCommands->SetColorMask(mColorMask[0], mColorMask[1], mColorMask[2], mColorMask[3]); - mNeedApply = false; - } - - int fogset = 0; - if (mFogEnabled) - { - if (mFogEnabled == 2) - { - fogset = -3; // 2D rendering with 'foggy' overlay. - } - else if ((GetFogColor() & 0xffffff) == 0) - { - fogset = gl_fogmode; - } - else - { - fogset = -gl_fogmode; - } - } - - ApplyMaterial(); - - if (mVertexBuffer) mDrawCommands->SetVertexBuffer(mVertexBuffer->Memory()); - if (mIndexBuffer) mDrawCommands->SetIndexBuffer(mIndexBuffer->Memory()); - mDrawCommands->SetInputAssembly(static_cast(mVertexBuffer)->VertexFormat); - mDrawCommands->SetRenderStyle(mRenderStyle); - - if (mColormapShader) - { - mDrawCommands->SetShader(EFF_NONE, 0, false, true); - } - else if (mSpecialEffect > EFF_NONE) - { - mDrawCommands->SetShader(mSpecialEffect, 0, false, false); - } - else - { - int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0); - mDrawCommands->SetShader(EFF_NONE, mTextureEnabled ? effectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, false); - } - - if (mMaterial.mMaterial && mMaterial.mMaterial->tex) - mStreamData.timer = static_cast((double)(screen->FrameTime - firstFrame) * (double)mMaterial.mMaterial->tex->shaderspeed / 1000.); - else - mStreamData.timer = 0.0f; - - PolyPushConstants constants; - constants.uFogEnabled = fogset; - constants.uTextureMode = mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode; - constants.uLightDist = mLightParms[0]; - constants.uLightFactor = mLightParms[1]; - constants.uFogDensity = mLightParms[2]; - constants.uLightLevel = mLightParms[3]; - constants.uAlphaThreshold = mAlphaThreshold; - constants.uClipSplit = { mClipSplit[0], mClipSplit[1] }; - constants.uLightIndex = mLightIndex; - - mDrawCommands->PushStreamData(mStreamData, constants); - ApplyMatrices(); - - if (mBias.mChanged) - { - mDrawCommands->SetDepthBias(mBias.mUnits, mBias.mFactor); - mBias.mChanged = false; - } - - drawcalls.Unclock(); -} - -void PolyRenderState::ApplyMaterial() -{ - if (mMaterial.mChanged && mMaterial.mMaterial) - { - mTempTM = mMaterial.mMaterial->tex->isHardwareCanvas() ? TM_OPAQUE : TM_NORMAL; - - auto base = static_cast(mMaterial.mMaterial->GetLayer(0, mMaterial.mTranslation)); - if (base) - { - DCanvas *texcanvas = base->GetImage(mMaterial); - mDrawCommands->SetTexture(0, texcanvas->GetPixels(), texcanvas->GetWidth(), texcanvas->GetHeight(), texcanvas->IsBgra()); - - int numLayers = mMaterial.mMaterial->GetLayers(); - for (int i = 1; i < numLayers; i++) - { - FTexture* layer; - auto systex = static_cast(mMaterial.mMaterial->GetLayer(i, 0, &layer)); - - texcanvas = systex->GetImage(layer, 0, mMaterial.mMaterial->isExpanded() ? CTF_Expand : 0); - mDrawCommands->SetTexture(i, texcanvas->GetPixels(), texcanvas->GetWidth(), texcanvas->GetHeight(), texcanvas->IsBgra()); - } - } - - mMaterial.mChanged = false; - } -} - -template -static void BufferedSet(bool &modified, T &dst, const T &src) -{ - if (dst == src) - return; - dst = src; - modified = true; -} - -static void BufferedSet(bool &modified, VSMatrix &dst, const VSMatrix &src) -{ - if (memcmp(dst.get(), src.get(), sizeof(FLOATTYPE) * 16) == 0) - return; - dst = src; - modified = true; -} - -void PolyRenderState::ApplyMatrices() -{ - bool modified = mFirstMatrixApply; - if (mTextureMatrixEnabled) - { - BufferedSet(modified, mMatrices.TextureMatrix, mTextureMatrix); - } - else - { - BufferedSet(modified, mMatrices.TextureMatrix, mIdentityMatrix); - } - - if (mModelMatrixEnabled) - { - BufferedSet(modified, mMatrices.ModelMatrix, mModelMatrix); - if (modified) - mMatrices.NormalModelMatrix.computeNormalMatrix(mModelMatrix); - } - else - { - BufferedSet(modified, mMatrices.ModelMatrix, mIdentityMatrix); - BufferedSet(modified, mMatrices.NormalModelMatrix, mIdentityMatrix); - } - - if (modified) - { - mFirstMatrixApply = false; - mDrawCommands->PushMatrices(mMatrices.ModelMatrix, mMatrices.NormalModelMatrix, mMatrices.TextureMatrix); - } -} - -void PolyRenderState::SetRenderTarget(DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown) -{ - mRenderTarget.Canvas = canvas; - mRenderTarget.DepthStencil = depthStencil; - mRenderTarget.TopDown = topdown; -} - -void PolyRenderState::Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length) -{ - if (buffer->bindingpoint == VIEWPOINT_BINDINGPOINT) - { - mViewpointUniforms = reinterpret_cast(static_cast(buffer->Memory()) + offset); - mNeedApply = true; - } -} - -PolyVertexInputAssembly *PolyRenderState::GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) -{ - for (size_t i = 0; i < mVertexFormats.size(); i++) - { - auto f = mVertexFormats[i].get(); - if (f->Attrs.size() == (size_t)numAttributes && f->NumBindingPoints == numBindingPoints && f->Stride == stride) - { - bool matches = true; - for (int j = 0; j < numAttributes; j++) - { - if (memcmp(&f->Attrs[j], &attrs[j], sizeof(FVertexBufferAttribute)) != 0) - { - matches = false; - break; - } - } - - if (matches) - return f; - } - } - - auto fmt = std::make_unique(); - fmt->NumBindingPoints = numBindingPoints; - fmt->Stride = stride; - fmt->UseVertexData = 0; - for (int j = 0; j < numAttributes; j++) - { - if (attrs[j].location == VATTR_COLOR) - fmt->UseVertexData |= 1; - else if (attrs[j].location == VATTR_NORMAL) - fmt->UseVertexData |= 2; - fmt->Attrs.push_back(attrs[j]); - } - - for (int j = 0; j < numAttributes; j++) - { - fmt->mOffsets[attrs[j].location] = attrs[j].offset; - } - fmt->mStride = stride; - - mVertexFormats.push_back(std::move(fmt)); - return mVertexFormats.back().get(); -} diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.h b/src/rendering/polyrenderer/backend/poly_renderstate.h deleted file mode 100644 index 6adea290436..00000000000 --- a/src/rendering/polyrenderer/backend/poly_renderstate.h +++ /dev/null @@ -1,100 +0,0 @@ - -#pragma once - -#include "polyrenderer/backend/poly_buffers.h" -#include "rendering/polyrenderer/drawers/poly_triangle.h" - -#include "name.h" - -#include "hwrenderer/scene/hw_drawstructs.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include "hwrenderer/textures/hw_material.h" - -struct HWViewpointUniforms; - -class PolyRenderState final : public FRenderState -{ -public: - PolyRenderState(); - - // Draw commands - void ClearScreen() override; - void Draw(int dt, int index, int count, bool apply = true) override; - void DrawIndexed(int dt, int index, int count, bool apply = true) override; - - // Immediate render state change commands. These only change infrequently and should not clutter the render state. - bool SetDepthClamp(bool on) override; - void SetDepthMask(bool on) override; - void SetDepthFunc(int func) override; - void SetDepthRange(float min, float max) override; - void SetColorMask(bool r, bool g, bool b, bool a) override; - void SetStencil(int offs, int op, int flags = -1) override; - void SetCulling(int mode) override; - void EnableClipDistance(int num, bool state) override; - void Clear(int targets) override; - void EnableStencil(bool on) override; - void SetScissor(int x, int y, int w, int h) override; - void SetViewport(int x, int y, int w, int h) override; - void EnableDepthTest(bool on) override; - void EnableMultisampling(bool on) override; - void EnableLineSmooth(bool on) override; - void EnableDrawBuffers(int count) override; - - void SetRenderTarget(DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown); - void Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length); - PolyVertexInputAssembly *GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs); - void EndRenderPass(); - - void SetColormapShader(bool enable); - -private: - void Apply(); - void ApplyMaterial(); - void ApplyMatrices(); - - struct Matrices - { - VSMatrix ModelMatrix; - VSMatrix NormalModelMatrix; - VSMatrix TextureMatrix; - } mMatrices; - VSMatrix mIdentityMatrix; - bool mFirstMatrixApply = true; - - HWViewpointUniforms *mViewpointUniforms = nullptr; - std::vector> mVertexFormats; - - bool mDepthClamp = true; - int mTempTM = TM_NORMAL; - - struct RenderTarget - { - DCanvas *Canvas = nullptr; - PolyDepthStencil *DepthStencil = nullptr; - bool TopDown = true; - } mRenderTarget; - - struct Rect - { - int x = 0; - int y = 0; - int width = 0; - int height = 0; - } mScissor, mViewport; - - bool mNeedApply = true; - - bool mDepthTest = false; - bool mDepthMask = false; - int mDepthFunc = DF_Always; - float mDepthRangeMin = 0.0f; - float mDepthRangeMax = 1.0f; - bool mStencilEnabled = false; - int mStencilValue = 0; - int mStencilOp = SOP_Keep; - int mCulling = Cull_None; - bool mColorMask[4] = { true, true, true, true }; - bool mColormapShader = false; - - PolyCommandBuffer* mDrawCommands = nullptr; -}; diff --git a/src/rendering/polyrenderer/drawers/poly_thread.cpp b/src/rendering/polyrenderer/drawers/poly_thread.cpp deleted file mode 100644 index 91d1ef1ca27..00000000000 --- a/src/rendering/polyrenderer/drawers/poly_thread.cpp +++ /dev/null @@ -1,822 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include -#include "templates.h" -#include "doomdef.h" - -#include "w_wad.h" -#include "v_video.h" -#include "doomstat.h" -#include "st_stuff.h" -#include "g_game.h" -#include "g_level.h" -#include "r_data/r_translate.h" -#include "r_data/models/models.h" -#include "v_palette.h" -#include "r_data/colormaps.h" -#include "poly_thread.h" -#include "swrenderer/drawers/r_draw_rgba.h" -#include "screen_triangle.h" -#include "x86.h" - -PolyTriangleThreadData::PolyTriangleThreadData(int32_t core, int32_t num_cores, int32_t numa_node, int32_t num_numa_nodes, int numa_start_y, int numa_end_y) - : core(core), num_cores(num_cores), numa_node(numa_node), num_numa_nodes(num_numa_nodes), numa_start_y(numa_start_y), numa_end_y(numa_end_y) -{ -} - -void PolyTriangleThreadData::ClearDepth(float value) -{ - int width = depthstencil->Width(); - int height = depthstencil->Height(); - float *data = depthstencil->DepthValues(); - - int skip = skipped_by_thread(0); - int count = count_for_thread(0, height); - - data += skip * width; - for (int i = 0; i < count; i++) - { - for (int x = 0; x < width; x++) - data[x] = value; - data += num_cores * width; - } -} - -void PolyTriangleThreadData::ClearStencil(uint8_t value) -{ - int width = depthstencil->Width(); - int height = depthstencil->Height(); - uint8_t *data = depthstencil->StencilValues(); - - int skip = skipped_by_thread(0); - int count = count_for_thread(0, height); - - data += skip * width; - for (int i = 0; i < count; i++) - { - memset(data, value, width); - data += num_cores * width; - } -} - -void PolyTriangleThreadData::SetViewport(int x, int y, int width, int height, uint8_t *new_dest, int new_dest_width, int new_dest_height, int new_dest_pitch, bool new_dest_bgra, PolyDepthStencil *new_depthstencil, bool new_topdown) -{ - viewport_x = x; - viewport_y = y; - viewport_width = width; - viewport_height = height; - dest = new_dest; - dest_width = new_dest_width; - dest_height = new_dest_height; - dest_pitch = new_dest_pitch; - dest_bgra = new_dest_bgra; - depthstencil = new_depthstencil; - topdown = new_topdown; - UpdateClip(); -} - -void PolyTriangleThreadData::SetScissor(int x, int y, int w, int h) -{ - scissor.left = x; - scissor.right = x + w; - scissor.top = y; - scissor.bottom = y + h; - UpdateClip(); -} - -void PolyTriangleThreadData::UpdateClip() -{ - clip.left = MAX(MAX(viewport_x, scissor.left), 0); - clip.top = MAX(MAX(viewport_y, scissor.top), 0); - clip.right = MIN(MIN(viewport_x + viewport_width, scissor.right), dest_width); - clip.bottom = MIN(MIN(viewport_y + viewport_height, scissor.bottom), dest_height); -} - -void PolyTriangleThreadData::PushStreamData(const StreamData &data, const PolyPushConstants &constants) -{ - mainVertexShader.Data = data; - mainVertexShader.uClipSplit = constants.uClipSplit; - - PushConstants = &constants; - - AlphaThreshold = clamp((int)(PushConstants->uAlphaThreshold * 255.0f + 0.5f), 0, 255) << 24; - - numPolyLights = 0; - if (constants.uLightIndex >= 0) - { - const FVector4 &lightRange = lights[constants.uLightIndex]; - static_assert(sizeof(FVector4) == 16, "sizeof(FVector4) is not 16 bytes"); - if (lightRange.Y > lightRange.X) - { - int start = constants.uLightIndex + 1; - int modulatedStart = static_cast(lightRange.X) + start; - int modulatedEnd = static_cast(lightRange.Y) + start; - for (int i = modulatedStart; i < modulatedEnd; i += 4) - { - if (numPolyLights == maxPolyLights) - break; - - auto &lightpos = lights[i]; - auto &lightcolor = lights[i + 1]; - //auto &lightspot1 = lights[i + 2]; - //auto &lightspot2 = lights[i + 3]; - uint32_t r = (int)clamp(lightcolor.X * 255.0f, 0.0f, 255.0f); - uint32_t g = (int)clamp(lightcolor.Y * 255.0f, 0.0f, 255.0f); - uint32_t b = (int)clamp(lightcolor.Z * 255.0f, 0.0f, 255.0f); - - auto& polylight = polyLights[numPolyLights++]; - polylight.x = lightpos.X; - polylight.y = lightpos.Y; - polylight.z = lightpos.Z; - polylight.radius = 256.0f / lightpos.W; - polylight.color = (r << 16) | (g << 8) | b; - if (lightcolor.W < 0.0f) - polylight.radius = -polylight.radius; - } - } - } -} - -void PolyTriangleThreadData::PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix) -{ - mainVertexShader.ModelMatrix = modelMatrix; - mainVertexShader.NormalModelMatrix = normalModelMatrix; - mainVertexShader.TextureMatrix = textureMatrix; -} - -void PolyTriangleThreadData::SetViewpointUniforms(const HWViewpointUniforms *uniforms) -{ - mainVertexShader.Viewpoint = uniforms; -} - -void PolyTriangleThreadData::SetDepthClamp(bool on) -{ -} - -void PolyTriangleThreadData::SetDepthMask(bool on) -{ - WriteDepth = on; -} - -void PolyTriangleThreadData::SetDepthFunc(int func) -{ - if (func == DF_LEqual || func == DF_Less) - { - DepthTest = true; - } - else // if (func == DF_Always) - { - DepthTest = false; - } -} - -void PolyTriangleThreadData::SetDepthRange(float min, float max) -{ - // The only two variants used by hwrenderer layer - if (min == 0.0f && max == 1.0f) - { - } - else if (min == 1.0f && max == 1.0f) - { - } -} - -void PolyTriangleThreadData::SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor) -{ - depthbias = (float)(depthBiasConstantFactor / 2500.0); -} - -void PolyTriangleThreadData::SetColorMask(bool r, bool g, bool b, bool a) -{ - WriteColor = r; -} - -void PolyTriangleThreadData::SetStencil(int stencilRef, int op) -{ - StencilTestValue = stencilRef; - if (op == SOP_Increment) - { - WriteStencil = StencilTest; - StencilWriteValue = MIN(stencilRef + 1, (int)255); - } - else if (op == SOP_Decrement) - { - WriteStencil = StencilTest; - StencilWriteValue = MAX(stencilRef - 1, (int)0); - } - else // SOP_Keep - { - WriteStencil = false; - StencilWriteValue = stencilRef; - } -} - -void PolyTriangleThreadData::SetCulling(int mode) -{ - SetTwoSided(mode == Cull_None); - SetCullCCW(mode == Cull_CCW); -} - -void PolyTriangleThreadData::EnableStencil(bool on) -{ - StencilTest = on; - WriteStencil = on && (StencilTestValue != StencilWriteValue); -} - -void PolyTriangleThreadData::SetRenderStyle(FRenderStyle style) -{ - RenderStyle = style; -} - -void PolyTriangleThreadData::SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader) -{ - SpecialEffect = specialEffect; - EffectState = effectState; - AlphaTest = alphaTest; - ColormapShader = colormapShader; -} - -void PolyTriangleThreadData::SetTexture(int unit, const void *pixels, int width, int height, bool bgra) -{ - textures[unit].pixels = pixels; - textures[unit].width = width; - textures[unit].height = height; - textures[unit].bgra = bgra; -} - -void PolyTriangleThreadData::DrawIndexed(int index, int vcount, PolyDrawMode drawmode) -{ - if (vcount < 3) - return; - - elements += index; - - ShadedTriVertex vertbuffer[3]; - ShadedTriVertex *vert[3] = { &vertbuffer[0], &vertbuffer[1], &vertbuffer[2] }; - if (drawmode == PolyDrawMode::Triangles) - { - for (int i = 0; i < vcount / 3; i++) - { - for (int j = 0; j < 3; j++) - *vert[j] = ShadeVertex(*(elements++)); - DrawShadedTriangle(vert, ccw); - } - } - else if (drawmode == PolyDrawMode::TriangleFan) - { - *vert[0] = ShadeVertex(*(elements++)); - *vert[1] = ShadeVertex(*(elements++)); - for (int i = 2; i < vcount; i++) - { - *vert[2] = ShadeVertex(*(elements++)); - DrawShadedTriangle(vert, ccw); - std::swap(vert[1], vert[2]); - } - } - else if (drawmode == PolyDrawMode::TriangleStrip) - { - bool toggleccw = ccw; - *vert[0] = ShadeVertex(*(elements++)); - *vert[1] = ShadeVertex(*(elements++)); - for (int i = 2; i < vcount; i++) - { - *vert[2] = ShadeVertex(*(elements++)); - DrawShadedTriangle(vert, toggleccw); - ShadedTriVertex *vtmp = vert[0]; - vert[0] = vert[1]; - vert[1] = vert[2]; - vert[2] = vtmp; - toggleccw = !toggleccw; - } - } - else if (drawmode == PolyDrawMode::Lines) - { - for (int i = 0; i < vcount / 2; i++) - { - *vert[0] = ShadeVertex(*(elements++)); - *vert[1] = ShadeVertex(*(elements++)); - DrawShadedLine(vert); - } - } - else if (drawmode == PolyDrawMode::Points) - { - for (int i = 0; i < vcount; i++) - { - *vert[0] = ShadeVertex(*(elements++)); - DrawShadedPoint(vert); - } - } -} - -void PolyTriangleThreadData::Draw(int index, int vcount, PolyDrawMode drawmode) -{ - if (vcount < 3) - return; - - int vinput = index; - - ShadedTriVertex vertbuffer[3]; - ShadedTriVertex *vert[3] = { &vertbuffer[0], &vertbuffer[1], &vertbuffer[2] }; - if (drawmode == PolyDrawMode::Triangles) - { - for (int i = 0; i < vcount / 3; i++) - { - for (int j = 0; j < 3; j++) - *vert[j] = ShadeVertex(vinput++); - DrawShadedTriangle(vert, ccw); - } - } - else if (drawmode == PolyDrawMode::TriangleFan) - { - *vert[0] = ShadeVertex(vinput++); - *vert[1] = ShadeVertex(vinput++); - for (int i = 2; i < vcount; i++) - { - *vert[2] = ShadeVertex(vinput++); - DrawShadedTriangle(vert, ccw); - std::swap(vert[1], vert[2]); - } - } - else if (drawmode == PolyDrawMode::TriangleStrip) - { - bool toggleccw = ccw; - *vert[0] = ShadeVertex(vinput++); - *vert[1] = ShadeVertex(vinput++); - for (int i = 2; i < vcount; i++) - { - *vert[2] = ShadeVertex(vinput++); - DrawShadedTriangle(vert, toggleccw); - ShadedTriVertex *vtmp = vert[0]; - vert[0] = vert[1]; - vert[1] = vert[2]; - vert[2] = vtmp; - toggleccw = !toggleccw; - } - } - else if (drawmode == PolyDrawMode::Lines) - { - for (int i = 0; i < vcount / 2; i++) - { - *vert[0] = ShadeVertex(vinput++); - *vert[1] = ShadeVertex(vinput++); - DrawShadedLine(vert); - } - } - else if (drawmode == PolyDrawMode::Points) - { - for (int i = 0; i < vcount; i++) - { - *vert[0] = ShadeVertex(vinput++); - DrawShadedPoint(vert); - } - } -} - -ShadedTriVertex PolyTriangleThreadData::ShadeVertex(int index) -{ - inputAssembly->Load(this, vertices, index); - mainVertexShader.SIMPLE = (SpecialEffect == EFF_BURN) || (SpecialEffect == EFF_STENCIL); - mainVertexShader.SPHEREMAP = (SpecialEffect == EFF_SPHEREMAP); - mainVertexShader.main(); - return mainVertexShader; -} - -bool PolyTriangleThreadData::IsDegenerate(const ShadedTriVertex *const* vert) -{ - // A degenerate triangle has a zero cross product for two of its sides. - float ax = vert[1]->gl_Position.X - vert[0]->gl_Position.X; - float ay = vert[1]->gl_Position.Y - vert[0]->gl_Position.Y; - float az = vert[1]->gl_Position.W - vert[0]->gl_Position.W; - float bx = vert[2]->gl_Position.X - vert[0]->gl_Position.X; - float by = vert[2]->gl_Position.Y - vert[0]->gl_Position.Y; - float bz = vert[2]->gl_Position.W - vert[0]->gl_Position.W; - float crossx = ay * bz - az * by; - float crossy = az * bx - ax * bz; - float crossz = ax * by - ay * bx; - float crosslengthsqr = crossx * crossx + crossy * crossy + crossz * crossz; - return crosslengthsqr <= 1.e-8f; -} - -bool PolyTriangleThreadData::IsFrontfacing(TriDrawTriangleArgs *args) -{ - float a = - args->v1->x * args->v2->y - args->v2->x * args->v1->y + - args->v2->x * args->v3->y - args->v3->x * args->v2->y + - args->v3->x * args->v1->y - args->v1->x * args->v3->y; - return a <= 0.0f; -} - -void PolyTriangleThreadData::DrawShadedPoint(const ShadedTriVertex *const* vertex) -{ -} - -void PolyTriangleThreadData::DrawShadedLine(const ShadedTriVertex *const* vert) -{ - static const int numclipdistances = 9; - float clipdistance[numclipdistances * 2]; - float *clipd = clipdistance; - for (int i = 0; i < 2; i++) - { - const auto &v = *vert[i]; - clipd[0] = v.gl_Position.X + v.gl_Position.W; - clipd[1] = v.gl_Position.W - v.gl_Position.X; - clipd[2] = v.gl_Position.Y + v.gl_Position.W; - clipd[3] = v.gl_Position.W - v.gl_Position.Y; - clipd[4] = v.gl_Position.Z + v.gl_Position.W; - clipd[5] = v.gl_Position.W - v.gl_Position.Z; - clipd[6] = v.gl_ClipDistance[0]; - clipd[7] = v.gl_ClipDistance[1]; - clipd[8] = v.gl_ClipDistance[2]; - clipd += numclipdistances; - } - - float t1 = 0.0f; - float t2 = 1.0f; - for (int p = 0; p < numclipdistances; p++) - { - float clipdistance1 = clipdistance[0 * numclipdistances + p]; - float clipdistance2 = clipdistance[1 * numclipdistances + p]; - if (clipdistance1 < 0.0f) t1 = MAX(-clipdistance1 / (clipdistance2 - clipdistance1), t1); - if (clipdistance2 < 0.0f) t2 = MIN(1.0f + clipdistance2 / (clipdistance1 - clipdistance2), t2); - if (t1 >= t2) - return; - } - - float weights[] = { 1.0f - t1, t1, 1.0f - t2, t2 }; - - ScreenTriVertex clippedvert[2]; - for (int i = 0; i < 2; i++) - { - auto &v = clippedvert[i]; - memset(&v, 0, sizeof(ScreenTriVertex)); - for (int w = 0; w < 2; w++) - { - float weight = weights[i * 2 + w]; - v.x += vert[w]->gl_Position.X * weight; - v.y += vert[w]->gl_Position.Y * weight; - v.z += vert[w]->gl_Position.Z * weight; - v.w += vert[w]->gl_Position.W * weight; - } - - // Calculate normalized device coordinates: - v.w = 1.0f / v.w; - v.x *= v.w; - v.y *= v.w; - v.z *= v.w; - - // Apply viewport scale to get screen coordinates: - v.x = viewport_x + viewport_width * (1.0f + v.x) * 0.5f; - if (topdown) - v.y = viewport_y + viewport_height * (1.0f - v.y) * 0.5f; - else - v.y = viewport_y + viewport_height * (1.0f + v.y) * 0.5f; - } - - uint32_t vColorA = (int)(vert[0]->vColor.W * 255.0f + 0.5f); - uint32_t vColorR = (int)(vert[0]->vColor.X * 255.0f + 0.5f); - uint32_t vColorG = (int)(vert[0]->vColor.Y * 255.0f + 0.5f); - uint32_t vColorB = (int)(vert[0]->vColor.Z * 255.0f + 0.5f); - uint32_t color = MAKEARGB(vColorA, vColorR, vColorG, vColorB); - - // Slow and naive implementation. Hopefully fast enough.. - - float x1 = clippedvert[0].x; - float y1 = clippedvert[0].y; - float x2 = clippedvert[1].x; - float y2 = clippedvert[1].y; - float dx = x2 - x1; - float dy = y2 - y1; - float step = (abs(dx) >= abs(dy)) ? abs(dx) : abs(dy); - dx /= step; - dy /= step; - float x = x1; - float y = y1; - int istep = (int)step; - int pixelsize = dest_bgra ? 4 : 1; - for (int i = 0; i <= istep; i++) - { - int scrx = (int)x; - int scry = (int)y; - if (scrx >= clip.left && scrx < clip.right && scry >= clip.top && scry < clip.bottom && !line_skipped_by_thread(scry)) - { - uint8_t *destpixel = dest + (scrx + scry * dest_width) * pixelsize; - if (pixelsize == 4) - { - *reinterpret_cast(destpixel) = color; - } - else - { - *destpixel = color; - } - } - x += dx; - y += dy; - } -} - -void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* vert, bool ccw) -{ - // Reject triangle if degenerate - if (IsDegenerate(vert)) - return; - - // Cull, clip and generate additional vertices as needed - ScreenTriVertex clippedvert[max_additional_vertices]; - int numclipvert = ClipEdge(vert); - - // Convert barycentric weights to actual vertices - for (int i = 0; i < numclipvert; i++) - { - auto &v = clippedvert[i]; - memset(&v, 0, sizeof(ScreenTriVertex)); - for (int w = 0; w < 3; w++) - { - float weight = weights[i * 3 + w]; - v.x += vert[w]->gl_Position.X * weight; - v.y += vert[w]->gl_Position.Y * weight; - v.z += vert[w]->gl_Position.Z * weight; - v.w += vert[w]->gl_Position.W * weight; - v.u += vert[w]->vTexCoord.X * weight; - v.v += vert[w]->vTexCoord.Y * weight; - v.worldX += vert[w]->pixelpos.X * weight; - v.worldY += vert[w]->pixelpos.Y * weight; - v.worldZ += vert[w]->pixelpos.Z * weight; - v.a += vert[w]->vColor.W * weight; - v.r += vert[w]->vColor.X * weight; - v.g += vert[w]->vColor.Y * weight; - v.b += vert[w]->vColor.Z * weight; - v.gradientdistZ += vert[w]->gradientdist.Z * weight; - } - } - -#ifdef NO_SSE - // Map to 2D viewport: - for (int j = 0; j < numclipvert; j++) - { - auto &v = clippedvert[j]; - - // Calculate normalized device coordinates: - v.w = 1.0f / v.w; - v.x *= v.w; - v.y *= v.w; - v.z *= v.w; - - // Apply viewport scale to get screen coordinates: - v.x = viewport_x + viewport_width * (1.0f + v.x) * 0.5f; - if (topdown) - v.y = viewport_y + viewport_height * (1.0f - v.y) * 0.5f; - else - v.y = viewport_y + viewport_height * (1.0f + v.y) * 0.5f; - } -#else - // Map to 2D viewport: - __m128 mviewport_x = _mm_set1_ps((float)viewport_x); - __m128 mviewport_y = _mm_set1_ps((float)viewport_y); - __m128 mviewport_halfwidth = _mm_set1_ps(viewport_width * 0.5f); - __m128 mviewport_halfheight = _mm_set1_ps(viewport_height * 0.5f); - __m128 mone = _mm_set1_ps(1.0f); - int sse_length = (numclipvert + 3) / 4 * 4; - for (int j = 0; j < sse_length; j += 4) - { - __m128 vx = _mm_loadu_ps(&clippedvert[j].x); - __m128 vy = _mm_loadu_ps(&clippedvert[j + 1].x); - __m128 vz = _mm_loadu_ps(&clippedvert[j + 2].x); - __m128 vw = _mm_loadu_ps(&clippedvert[j + 3].x); - _MM_TRANSPOSE4_PS(vx, vy, vz, vw); - - // Calculate normalized device coordinates: - vw = _mm_div_ps(mone, vw); - vx = _mm_mul_ps(vx, vw); - vy = _mm_mul_ps(vy, vw); - vz = _mm_mul_ps(vz, vw); - - // Apply viewport scale to get screen coordinates: - vx = _mm_add_ps(mviewport_x, _mm_mul_ps(mviewport_halfwidth, _mm_add_ps(mone, vx))); - if (topdown) - vy = _mm_add_ps(mviewport_y, _mm_mul_ps(mviewport_halfheight, _mm_sub_ps(mone, vy))); - else - vy = _mm_add_ps(mviewport_y, _mm_mul_ps(mviewport_halfheight, _mm_add_ps(mone, vy))); - - _MM_TRANSPOSE4_PS(vx, vy, vz, vw); - _mm_storeu_ps(&clippedvert[j].x, vx); - _mm_storeu_ps(&clippedvert[j + 1].x, vy); - _mm_storeu_ps(&clippedvert[j + 2].x, vz); - _mm_storeu_ps(&clippedvert[j + 3].x, vw); - } -#endif - - if (!topdown) ccw = !ccw; - - TriDrawTriangleArgs args; - - if (twosided && numclipvert > 2) - { - args.v1 = &clippedvert[0]; - args.v2 = &clippedvert[1]; - args.v3 = &clippedvert[2]; - ccw = !IsFrontfacing(&args); - } - - // Draw screen triangles - if (ccw) - { - for (int i = numclipvert - 1; i > 1; i--) - { - args.v1 = &clippedvert[numclipvert - 1]; - args.v2 = &clippedvert[i - 1]; - args.v3 = &clippedvert[i - 2]; - if (IsFrontfacing(&args) == ccw && args.CalculateGradients()) - { - ScreenTriangle::Draw(&args, this); - } - } - } - else - { - for (int i = 2; i < numclipvert; i++) - { - args.v1 = &clippedvert[0]; - args.v2 = &clippedvert[i - 1]; - args.v3 = &clippedvert[i]; - if (IsFrontfacing(&args) != ccw && args.CalculateGradients()) - { - ScreenTriangle::Draw(&args, this); - } - } - } -} - -int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *const* verts) -{ - // use barycentric weights for clipped vertices - weights = weightsbuffer; - for (int i = 0; i < 3; i++) - { - weights[i * 3 + 0] = 0.0f; - weights[i * 3 + 1] = 0.0f; - weights[i * 3 + 2] = 0.0f; - weights[i * 3 + i] = 1.0f; - } - - // Clip and cull so that the following is true for all vertices: - // -v.w <= v.x <= v.w - // -v.w <= v.y <= v.w - // -v.w <= v.z <= v.w - - // halfspace clip distances - static const int numclipdistances = 9; -#ifdef NO_SSE - float clipdistance[numclipdistances * 3]; - bool needsclipping = false; - float *clipd = clipdistance; - for (int i = 0; i < 3; i++) - { - const auto &v = *verts[i]; - clipd[0] = v.gl_Position.X + v.gl_Position.W; - clipd[1] = v.gl_Position.W - v.gl_Position.X; - clipd[2] = v.gl_Position.Y + v.gl_Position.W; - clipd[3] = v.gl_Position.W - v.gl_Position.Y; - clipd[4] = v.gl_Position.Z + v.gl_Position.W; - clipd[5] = v.gl_Position.W - v.gl_Position.Z; - clipd[6] = v.gl_ClipDistance[0]; - clipd[7] = v.gl_ClipDistance[1]; - clipd[8] = v.gl_ClipDistance[2]; - for (int j = 0; j < 9; j++) - needsclipping = needsclipping || clipd[i]; - clipd += numclipdistances; - } - - // If all halfspace clip distances are positive then the entire triangle is visible. Skip the expensive clipping step. - if (!needsclipping) - { - return 3; - } -#else - __m128 mx = _mm_loadu_ps(&verts[0]->gl_Position.X); - __m128 my = _mm_loadu_ps(&verts[1]->gl_Position.X); - __m128 mz = _mm_loadu_ps(&verts[2]->gl_Position.X); - __m128 mw = _mm_setzero_ps(); - _MM_TRANSPOSE4_PS(mx, my, mz, mw); - __m128 clipd0 = _mm_add_ps(mx, mw); - __m128 clipd1 = _mm_sub_ps(mw, mx); - __m128 clipd2 = _mm_add_ps(my, mw); - __m128 clipd3 = _mm_sub_ps(mw, my); - __m128 clipd4 = _mm_add_ps(mz, mw); - __m128 clipd5 = _mm_sub_ps(mw, mz); - __m128 clipd6 = _mm_setr_ps(verts[0]->gl_ClipDistance[0], verts[1]->gl_ClipDistance[0], verts[2]->gl_ClipDistance[0], 0.0f); - __m128 clipd7 = _mm_setr_ps(verts[0]->gl_ClipDistance[1], verts[1]->gl_ClipDistance[1], verts[2]->gl_ClipDistance[1], 0.0f); - __m128 clipd8 = _mm_setr_ps(verts[0]->gl_ClipDistance[2], verts[1]->gl_ClipDistance[2], verts[2]->gl_ClipDistance[2], 0.0f); - __m128 mneedsclipping = _mm_cmplt_ps(clipd0, _mm_setzero_ps()); - mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd1, _mm_setzero_ps())); - mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd2, _mm_setzero_ps())); - mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd3, _mm_setzero_ps())); - mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd4, _mm_setzero_ps())); - mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd5, _mm_setzero_ps())); - mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd6, _mm_setzero_ps())); - mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd7, _mm_setzero_ps())); - mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd8, _mm_setzero_ps())); - if (_mm_movemask_ps(mneedsclipping) == 0) - { - return 3; - } - float clipdistance[numclipdistances * 4]; - _mm_storeu_ps(clipdistance, clipd0); - _mm_storeu_ps(clipdistance + 4, clipd1); - _mm_storeu_ps(clipdistance + 8, clipd2); - _mm_storeu_ps(clipdistance + 12, clipd3); - _mm_storeu_ps(clipdistance + 16, clipd4); - _mm_storeu_ps(clipdistance + 20, clipd5); - _mm_storeu_ps(clipdistance + 24, clipd6); - _mm_storeu_ps(clipdistance + 28, clipd7); - _mm_storeu_ps(clipdistance + 32, clipd8); -#endif - - // Clip against each halfspace - float *input = weights; - float *output = weights + max_additional_vertices * 3; - int inputverts = 3; - for (int p = 0; p < numclipdistances; p++) - { - // Clip each edge - int outputverts = 0; - for (int i = 0; i < inputverts; i++) - { - int j = (i + 1) % inputverts; -#ifdef NO_SSE - float clipdistance1 = - clipdistance[0 * numclipdistances + p] * input[i * 3 + 0] + - clipdistance[1 * numclipdistances + p] * input[i * 3 + 1] + - clipdistance[2 * numclipdistances + p] * input[i * 3 + 2]; - - float clipdistance2 = - clipdistance[0 * numclipdistances + p] * input[j * 3 + 0] + - clipdistance[1 * numclipdistances + p] * input[j * 3 + 1] + - clipdistance[2 * numclipdistances + p] * input[j * 3 + 2]; -#else - float clipdistance1 = - clipdistance[0 + p * 4] * input[i * 3 + 0] + - clipdistance[1 + p * 4] * input[i * 3 + 1] + - clipdistance[2 + p * 4] * input[i * 3 + 2]; - - float clipdistance2 = - clipdistance[0 + p * 4] * input[j * 3 + 0] + - clipdistance[1 + p * 4] * input[j * 3 + 1] + - clipdistance[2 + p * 4] * input[j * 3 + 2]; -#endif - - // Clip halfspace - if ((clipdistance1 >= 0.0f || clipdistance2 >= 0.0f) && outputverts + 1 < max_additional_vertices) - { - float t1 = (clipdistance1 < 0.0f) ? MAX(-clipdistance1 / (clipdistance2 - clipdistance1), 0.0f) : 0.0f; - float t2 = (clipdistance2 < 0.0f) ? MIN(1.0f + clipdistance2 / (clipdistance1 - clipdistance2), 1.0f) : 1.0f; - - // add t1 vertex - for (int k = 0; k < 3; k++) - output[outputverts * 3 + k] = input[i * 3 + k] * (1.0f - t1) + input[j * 3 + k] * t1; - outputverts++; - - if (t2 != 1.0f && t2 > t1) - { - // add t2 vertex - for (int k = 0; k < 3; k++) - output[outputverts * 3 + k] = input[i * 3 + k] * (1.0f - t2) + input[j * 3 + k] * t2; - outputverts++; - } - } - } - std::swap(input, output); - inputverts = outputverts; - if (inputverts == 0) - break; - } - - weights = input; - return inputverts; -} - -PolyTriangleThreadData *PolyTriangleThreadData::Get(DrawerThread *thread) -{ - if (!thread->poly) - thread->poly = std::make_shared(thread->core, thread->num_cores, thread->numa_node, thread->num_numa_nodes, thread->numa_start_y, thread->numa_end_y); - return thread->poly.get(); -} diff --git a/src/rendering/polyrenderer/drawers/poly_thread.h b/src/rendering/polyrenderer/drawers/poly_thread.h deleted file mode 100644 index 4ce764e10fe..00000000000 --- a/src/rendering/polyrenderer/drawers/poly_thread.h +++ /dev/null @@ -1,197 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#pragma once - -#include "poly_triangle.h" - -struct PolyLight -{ - uint32_t color; - float x, y, z; - float radius; -}; - -class PolyTriangleThreadData -{ -public: - PolyTriangleThreadData(int32_t core, int32_t num_cores, int32_t numa_node, int32_t num_numa_nodes, int numa_start_y, int numa_end_y); - - void ClearDepth(float value); - void ClearStencil(uint8_t value); - void SetViewport(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra, PolyDepthStencil *depthstencil, bool topdown); - - void SetCullCCW(bool value) { ccw = value; } - void SetTwoSided(bool value) { twosided = value; } - - void SetInputAssembly(PolyInputAssembly *input) { inputAssembly = input; } - void SetVertexBuffer(const void *data) { vertices = data; } - void SetIndexBuffer(const void *data) { elements = (const unsigned int *)data; } - void SetLightBuffer(const void *data) { lights = (const FVector4 *)data; } - void SetViewpointUniforms(const HWViewpointUniforms *uniforms); - void SetDepthClamp(bool on); - void SetDepthMask(bool on); - void SetDepthFunc(int func); - void SetDepthRange(float min, float max); - void SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor); - void SetColorMask(bool r, bool g, bool b, bool a); - void SetStencil(int stencilRef, int op); - void SetCulling(int mode); - void EnableStencil(bool on); - void SetScissor(int x, int y, int w, int h); - void SetRenderStyle(FRenderStyle style); - void SetTexture(int unit, const void *pixels, int width, int height, bool bgra); - void SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader); - - void UpdateClip(); - - void PushStreamData(const StreamData &data, const PolyPushConstants &constants); - void PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix); - - void DrawIndexed(int index, int count, PolyDrawMode mode); - void Draw(int index, int vcount, PolyDrawMode mode); - - int32_t core; - int32_t num_cores; - int32_t numa_node; - int32_t num_numa_nodes; - - int numa_start_y; - int numa_end_y; - - bool line_skipped_by_thread(int line) - { - return line < numa_start_y || line >= numa_end_y || line % num_cores != core; - } - - int skipped_by_thread(int first_line) - { - int clip_first_line = MAX(first_line, numa_start_y); - int core_skip = (num_cores - (clip_first_line - core) % num_cores) % num_cores; - return clip_first_line + core_skip - first_line; - } - - int count_for_thread(int first_line, int count) - { - count = MIN(count, numa_end_y - first_line); - int c = (count - skipped_by_thread(first_line) + num_cores - 1) / num_cores; - return MAX(c, 0); - } - - struct Scanline - { - float W[MAXWIDTH]; - uint16_t U[MAXWIDTH]; - uint16_t V[MAXWIDTH]; - float WorldX[MAXWIDTH]; - float WorldY[MAXWIDTH]; - float WorldZ[MAXWIDTH]; - uint8_t vColorA[MAXWIDTH]; - uint8_t vColorR[MAXWIDTH]; - uint8_t vColorG[MAXWIDTH]; - uint8_t vColorB[MAXWIDTH]; - float GradientdistZ[MAXWIDTH]; - uint32_t FragColor[MAXWIDTH]; - uint32_t lightarray[MAXWIDTH]; - uint8_t discard[MAXWIDTH]; - } scanline; - - static PolyTriangleThreadData *Get(DrawerThread *thread); - - int dest_pitch = 0; - int dest_width = 0; - int dest_height = 0; - bool dest_bgra = false; - uint8_t *dest = nullptr; - PolyDepthStencil *depthstencil = nullptr; - bool topdown = true; - - float depthbias = 0.0f; - - int viewport_y = 0; - - struct ClipRect - { - int left = 0; - int top = 0; - int right = 0; - int bottom = 0; - } clip, scissor; - - FRenderStyle RenderStyle; - int SpecialEffect = EFF_NONE; - int EffectState = 0; - bool AlphaTest = false; - bool ColormapShader = false; - uint32_t AlphaThreshold = 0x7f000000; - const PolyPushConstants* PushConstants = nullptr; - - const void *vertices = nullptr; - const unsigned int *elements = nullptr; - const FVector4 *lights = nullptr; - - enum { maxPolyLights = 16 }; - PolyLight polyLights[maxPolyLights]; - int numPolyLights = 0; - - PolyMainVertexShader mainVertexShader; - - struct TextureUnit - { - const void* pixels = nullptr; - int width = 0; - int height = 0; - bool bgra = true; - } textures[16]; - - bool DepthTest = false; - bool StencilTest = true; - bool WriteStencil = true; - bool WriteColor = true; - bool WriteDepth = true; - uint8_t StencilTestValue = 0; - uint8_t StencilWriteValue = 0; - - void (*FragmentShader)(int x0, int x1, PolyTriangleThreadData* thread) = nullptr; - void (*WriteColorFunc)(int y, int x0, int x1, PolyTriangleThreadData* thread) = nullptr; - -private: - ShadedTriVertex ShadeVertex(int index); - void DrawShadedPoint(const ShadedTriVertex *const* vertex); - void DrawShadedLine(const ShadedTriVertex *const* vertices); - void DrawShadedTriangle(const ShadedTriVertex *const* vertices, bool ccw); - static bool IsDegenerate(const ShadedTriVertex *const* vertices); - static bool IsFrontfacing(TriDrawTriangleArgs *args); - - int ClipEdge(const ShadedTriVertex *const* verts); - - int viewport_x = 0; - int viewport_width = 0; - int viewport_height = 0; - bool ccw = true; - bool twosided = true; - PolyInputAssembly *inputAssembly = nullptr; - - enum { max_additional_vertices = 16 }; - float weightsbuffer[max_additional_vertices * 3 * 2]; - float *weights = nullptr; -}; diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.cpp b/src/rendering/polyrenderer/drawers/poly_triangle.cpp deleted file mode 100644 index 86311380381..00000000000 --- a/src/rendering/polyrenderer/drawers/poly_triangle.cpp +++ /dev/null @@ -1,476 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include -#include "templates.h" -#include "doomdef.h" - -#include "w_wad.h" -#include "v_video.h" -#include "doomstat.h" -#include "st_stuff.h" -#include "g_game.h" -#include "g_level.h" -#include "r_data/r_translate.h" -#include "r_data/models/models.h" -#include "v_palette.h" -#include "r_data/colormaps.h" -#include "poly_triangle.h" -#include "poly_thread.h" -#include "swrenderer/drawers/r_draw_rgba.h" -#include "screen_triangle.h" -#include "x86.h" - -///////////////////////////////////////////////////////////////////////////// - -class PolyDrawerCommand : public DrawerCommand -{ -public: -}; - -class PolySetDepthClampCommand : public PolyDrawerCommand -{ -public: - PolySetDepthClampCommand(bool on) : on(on) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthClamp(on); } - -private: - bool on; -}; - -class PolySetDepthMaskCommand : public PolyDrawerCommand -{ -public: - PolySetDepthMaskCommand(bool on) : on(on) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthMask(on); } - -private: - bool on; -}; - -class PolySetDepthFuncCommand : public PolyDrawerCommand -{ -public: - PolySetDepthFuncCommand(int func) : func(func) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthFunc(func); } - -private: - int func; -}; - -class PolySetDepthRangeCommand : public PolyDrawerCommand -{ -public: - PolySetDepthRangeCommand(float min, float max) : min(min), max(max) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthRange(min, max); } - -private: - float min; - float max; -}; - -class PolySetDepthBiasCommand : public PolyDrawerCommand -{ -public: - PolySetDepthBiasCommand(float depthBiasConstantFactor, float depthBiasSlopeFactor) : depthBiasConstantFactor(depthBiasConstantFactor), depthBiasSlopeFactor(depthBiasSlopeFactor) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthBias(depthBiasConstantFactor, depthBiasSlopeFactor); } - -private: - float depthBiasConstantFactor; - float depthBiasSlopeFactor; -}; - -class PolySetColorMaskCommand : public PolyDrawerCommand -{ -public: - PolySetColorMaskCommand(bool r, bool g, bool b, bool a) : r(r), g(g), b(b), a(a) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetColorMask(r, g, b, a); } - -private: - bool r; - bool g; - bool b; - bool a; -}; - -class PolySetStencilCommand : public PolyDrawerCommand -{ -public: - PolySetStencilCommand(int stencilRef, int op) : stencilRef(stencilRef), op(op) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetStencil(stencilRef, op); } - -private: - int stencilRef; - int op; -}; - -class PolySetCullingCommand : public PolyDrawerCommand -{ -public: - PolySetCullingCommand(int mode) : mode(mode) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetCulling(mode); } - -private: - int mode; -}; - -class PolyEnableStencilCommand : public PolyDrawerCommand -{ -public: - PolyEnableStencilCommand(bool on) : on(on) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->EnableStencil(on); } - -private: - bool on; -}; - -class PolySetScissorCommand : public PolyDrawerCommand -{ -public: - PolySetScissorCommand(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetScissor(x, y, w, h); } - -private: - int x; - int y; - int w; - int h; -}; - -class PolySetRenderStyleCommand : public PolyDrawerCommand -{ -public: - PolySetRenderStyleCommand(FRenderStyle style) : style(style) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetRenderStyle(style); } - -private: - FRenderStyle style; -}; - -class PolySetTextureCommand : public PolyDrawerCommand -{ -public: - PolySetTextureCommand(int unit, void* pixels, int width, int height, bool bgra) : unit(unit), pixels(pixels), width(width), height(height), bgra(bgra) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetTexture(unit, pixels, width, height, bgra); } - -private: - int unit; - void* pixels; - int width; - int height; - bool bgra; -}; - -class PolySetShaderCommand : public PolyDrawerCommand -{ -public: - PolySetShaderCommand(int specialEffect, int effectState, bool alphaTest, bool colormapShader) : specialEffect(specialEffect), effectState(effectState), alphaTest(alphaTest), colormapShader(colormapShader) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetShader(specialEffect, effectState, alphaTest, colormapShader); } - -private: - int specialEffect; - int effectState; - bool alphaTest; - bool colormapShader; -}; - -class PolySetVertexBufferCommand : public PolyDrawerCommand -{ -public: - PolySetVertexBufferCommand(const void* vertices) : vertices(vertices) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetVertexBuffer(vertices); } - -private: - const void* vertices; -}; - -class PolySetIndexBufferCommand : public PolyDrawerCommand -{ -public: - PolySetIndexBufferCommand(const void* indices) : indices(indices) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetIndexBuffer(indices); } - -private: - const void* indices; -}; - -class PolySetLightBufferCommand : public PolyDrawerCommand -{ -public: - PolySetLightBufferCommand(const void* lights) : lights(lights) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetLightBuffer(lights); } - -private: - const void* lights; -}; - -class PolySetInputAssemblyCommand : public PolyDrawerCommand -{ -public: - PolySetInputAssemblyCommand(PolyInputAssembly* input) : input(input) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetInputAssembly(input); } - -private: - PolyInputAssembly* input; -}; - -class PolyClearDepthCommand : public PolyDrawerCommand -{ -public: - PolyClearDepthCommand(float value) : value(value) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->ClearDepth(value); } - -private: - float value; -}; - -class PolyClearStencilCommand : public PolyDrawerCommand -{ -public: - PolyClearStencilCommand(uint8_t value) : value(value) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->ClearStencil(value); } - -private: - uint8_t value; -}; - -class PolySetViewportCommand : public PolyDrawerCommand -{ -public: - PolySetViewportCommand(int x, int y, int width, int height, uint8_t* dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra, PolyDepthStencil* depthstencil, bool topdown) - : x(x), y(y), width(width), height(height), dest(dest), dest_width(dest_width), dest_height(dest_height), dest_pitch(dest_pitch), dest_bgra(dest_bgra), depthstencil(depthstencil), topdown(topdown) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetViewport(x, y, width, height, dest, dest_width, dest_height, dest_pitch, dest_bgra, depthstencil, topdown); } - -private: - int x; - int y; - int width; - int height; - uint8_t* dest; - int dest_width; - int dest_height; - int dest_pitch; - bool dest_bgra; - PolyDepthStencil* depthstencil; - bool topdown; -}; - -class PolySetViewpointUniformsCommand : public PolyDrawerCommand -{ -public: - PolySetViewpointUniformsCommand(const HWViewpointUniforms* uniforms) : uniforms(uniforms) {} - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetViewpointUniforms(uniforms); } - -private: - const HWViewpointUniforms* uniforms; -}; - -class PolyPushMatricesCommand : public PolyDrawerCommand -{ -public: - PolyPushMatricesCommand(const VSMatrix& modelMatrix, const VSMatrix& normalModelMatrix, const VSMatrix& textureMatrix) - : modelMatrix(modelMatrix), normalModelMatrix(normalModelMatrix), textureMatrix(textureMatrix) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->PushMatrices(modelMatrix, normalModelMatrix, textureMatrix); } - -private: - VSMatrix modelMatrix; - VSMatrix normalModelMatrix; - VSMatrix textureMatrix; -}; - -class PolyPushStreamDataCommand : public PolyDrawerCommand -{ -public: - PolyPushStreamDataCommand(const StreamData& data, const PolyPushConstants& constants) : data(data), constants(constants) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->PushStreamData(data, constants); } - -private: - StreamData data; - PolyPushConstants constants; -}; - -class PolyDrawCommand : public PolyDrawerCommand -{ -public: - PolyDrawCommand(int index, int count, PolyDrawMode mode) : index(index), count(count), mode(mode) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->Draw(index, count, mode); } - -private: - int index; - int count; - PolyDrawMode mode; -}; - -class PolyDrawIndexedCommand : public PolyDrawerCommand -{ -public: - PolyDrawIndexedCommand(int index, int count, PolyDrawMode mode) : index(index), count(count), mode(mode) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->DrawIndexed(index, count, mode); } - -private: - int index; - int count; - PolyDrawMode mode; -}; - -///////////////////////////////////////////////////////////////////////////// - -PolyCommandBuffer::PolyCommandBuffer(RenderMemory* frameMemory) -{ - mQueue = std::make_shared(frameMemory); -} - -void PolyCommandBuffer::SetViewport(int x, int y, int width, int height, DCanvas *canvas, PolyDepthStencil *depthstencil, bool topdown) -{ - uint8_t *dest = (uint8_t*)canvas->GetPixels(); - int dest_width = canvas->GetWidth(); - int dest_height = canvas->GetHeight(); - int dest_pitch = canvas->GetPitch(); - bool dest_bgra = canvas->IsBgra(); - - mQueue->Push(x, y, width, height, dest, dest_width, dest_height, dest_pitch, dest_bgra, depthstencil, topdown); -} - -void PolyCommandBuffer::SetInputAssembly(PolyInputAssembly *input) -{ - mQueue->Push(input); -} - -void PolyCommandBuffer::SetVertexBuffer(const void *vertices) -{ - mQueue->Push(vertices); -} - -void PolyCommandBuffer::SetIndexBuffer(const void *elements) -{ - mQueue->Push(elements); -} - -void PolyCommandBuffer::SetLightBuffer(const void *lights) -{ - mQueue->Push(lights); -} - -void PolyCommandBuffer::SetDepthClamp(bool on) -{ - mQueue->Push(on); -} - -void PolyCommandBuffer::SetDepthMask(bool on) -{ - mQueue->Push(on); -} - -void PolyCommandBuffer::SetDepthFunc(int func) -{ - mQueue->Push(func); -} - -void PolyCommandBuffer::SetDepthRange(float min, float max) -{ - mQueue->Push(min, max); -} - -void PolyCommandBuffer::SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor) -{ - mQueue->Push(depthBiasConstantFactor, depthBiasSlopeFactor); -} - -void PolyCommandBuffer::SetColorMask(bool r, bool g, bool b, bool a) -{ - mQueue->Push(r, g, b, a); -} - -void PolyCommandBuffer::SetStencil(int stencilRef, int op) -{ - mQueue->Push(stencilRef, op); -} - -void PolyCommandBuffer::SetCulling(int mode) -{ - mQueue->Push(mode); -} - -void PolyCommandBuffer::EnableStencil(bool on) -{ - mQueue->Push(on); -} - -void PolyCommandBuffer::SetScissor(int x, int y, int w, int h) -{ - mQueue->Push(x, y, w, h); -} - -void PolyCommandBuffer::SetRenderStyle(FRenderStyle style) -{ - mQueue->Push(style); -} - -void PolyCommandBuffer::SetTexture(int unit, void *pixels, int width, int height, bool bgra) -{ - mQueue->Push(unit, pixels, width, height, bgra); -} - -void PolyCommandBuffer::SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader) -{ - mQueue->Push(specialEffect, effectState, alphaTest, colormapShader); -} - -void PolyCommandBuffer::PushStreamData(const StreamData &data, const PolyPushConstants &constants) -{ - mQueue->Push(data, constants); -} - -void PolyCommandBuffer::PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix) -{ - mQueue->Push(modelMatrix, normalModelMatrix, textureMatrix); -} - -void PolyCommandBuffer::SetViewpointUniforms(const HWViewpointUniforms *uniforms) -{ - mQueue->Push(uniforms); -} - -void PolyCommandBuffer::ClearDepth(float value) -{ - mQueue->Push(value); -} - -void PolyCommandBuffer::ClearStencil(uint8_t value) -{ - mQueue->Push(value); -} - -void PolyCommandBuffer::Draw(int index, int vcount, PolyDrawMode mode) -{ - mQueue->Push(index, vcount, mode); -} - -void PolyCommandBuffer::DrawIndexed(int index, int count, PolyDrawMode mode) -{ - mQueue->Push(index, count, mode); -} - -void PolyCommandBuffer::Submit() -{ - DrawerThreads::Execute(mQueue); -} diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.h b/src/rendering/polyrenderer/drawers/poly_triangle.h deleted file mode 100644 index ffee6201e45..00000000000 --- a/src/rendering/polyrenderer/drawers/poly_triangle.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#pragma once - -#include "swrenderer/drawers/r_draw.h" -#include "swrenderer/drawers/r_thread.h" -#include "polyrenderer/drawers/screen_triangle.h" -#include "polyrenderer/drawers/poly_vertex_shader.h" - -class DCanvas; -class RenderMemory; -class PolyDrawerCommand; -class PolyInputAssembly; -class PolyDepthStencil; -struct PolyPushConstants; - -enum class PolyDrawMode -{ - Points, - Lines, - Triangles, - TriangleFan, - TriangleStrip -}; - -class PolyCommandBuffer -{ -public: - PolyCommandBuffer(RenderMemory* frameMemory); - - void SetViewport(int x, int y, int width, int height, DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown); - void SetInputAssembly(PolyInputAssembly *input); - void SetVertexBuffer(const void *vertices); - void SetIndexBuffer(const void *elements); - void SetLightBuffer(const void *lights); - void SetViewpointUniforms(const HWViewpointUniforms *uniforms); - void SetDepthClamp(bool on); - void SetDepthMask(bool on); - void SetDepthFunc(int func); - void SetDepthRange(float min, float max); - void SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor); - void SetColorMask(bool r, bool g, bool b, bool a); - void SetStencil(int stencilRef, int op); - void SetCulling(int mode); - void EnableStencil(bool on); - void SetScissor(int x, int y, int w, int h); - void SetRenderStyle(FRenderStyle style); - void SetTexture(int unit, void *pixels, int width, int height, bool bgra); - void SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader); - void PushStreamData(const StreamData &data, const PolyPushConstants &constants); - void PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix); - void ClearDepth(float value); - void ClearStencil(uint8_t value); - void Draw(int index, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles); - void DrawIndexed(int index, int count, PolyDrawMode mode = PolyDrawMode::Triangles); - void Submit(); - -private: - std::shared_ptr mQueue; -}; - -class PolyDepthStencil -{ -public: - PolyDepthStencil(int width, int height) : width(width), height(height), depthbuffer(width * height), stencilbuffer(width * height) { } - - int Width() const { return width; } - int Height() const { return height; } - float *DepthValues() { return depthbuffer.data(); } - uint8_t *StencilValues() { return stencilbuffer.data(); } - -private: - int width; - int height; - std::vector depthbuffer; - std::vector stencilbuffer; -}; - -struct PolyPushConstants -{ - int uTextureMode; - float uAlphaThreshold; - FVector2 uClipSplit; - - // Lighting + Fog - float uLightLevel; - float uFogDensity; - float uLightFactor; - float uLightDist; - int uFogEnabled; - - // dynamic lights - int uLightIndex; -}; - -class PolyInputAssembly -{ -public: - virtual void Load(PolyTriangleThreadData *thread, const void *vertices, int index) = 0; -}; diff --git a/src/rendering/polyrenderer/drawers/poly_vertex_shader.h b/src/rendering/polyrenderer/drawers/poly_vertex_shader.h deleted file mode 100644 index 5b531376348..00000000000 --- a/src/rendering/polyrenderer/drawers/poly_vertex_shader.h +++ /dev/null @@ -1,194 +0,0 @@ - -#pragma once - -#include "hwrenderer/scene/hw_viewpointuniforms.h" -#include "hwrenderer/scene/hw_renderstate.h" - -#ifndef NO_SSE -#include -#endif - -class ShadedTriVertex -{ -public: - FVector4 gl_Position; - float gl_ClipDistance[5]; - FVector4 vTexCoord; - FVector4 vColor; - FVector4 pixelpos; - //FVector3 glowdist; - FVector3 gradientdist; - //FVector4 vEyeNormal; - FVector4 vWorldNormal; -}; - -class PolyMainVertexShader : public ShadedTriVertex -{ -public: - // Input - FVector4 aPosition; - FVector2 aTexCoord; - FVector4 aColor; - FVector4 aVertex2; - FVector4 aNormal; - FVector4 aNormal2; - - // Defines - bool SIMPLE = false; - bool SPHEREMAP = false; - - // Uniforms - VSMatrix ModelMatrix; - VSMatrix NormalModelMatrix; - VSMatrix TextureMatrix; - StreamData Data; - FVector2 uClipSplit; - const HWViewpointUniforms *Viewpoint = nullptr; - - void main() - { - FVector2 parmTexCoord = aTexCoord; - FVector4 parmPosition = aPosition; - - FVector4 worldcoord; - if (SIMPLE) - worldcoord = mul(ModelMatrix, mix(parmPosition, aVertex2, Data.uInterpolationFactor)); - else - worldcoord = mul(ModelMatrix, parmPosition); - - FVector4 eyeCoordPos = mul(Viewpoint->mViewMatrix, worldcoord); - - vColor = aColor; - - if (!SIMPLE) - { - pixelpos.X = worldcoord.X; - pixelpos.Y = worldcoord.Y; - pixelpos.Z = worldcoord.Z; - pixelpos.W = -eyeCoordPos.Z / eyeCoordPos.W; - - /*if (Data.uGlowTopColor.W > 0 || Data.uGlowBottomColor.W > 0) - { - float topatpoint = (Data.uGlowTopPlane.W + Data.uGlowTopPlane.X * worldcoord.X + Data.uGlowTopPlane.Y * worldcoord.Z) * Data.uGlowTopPlane.Z; - float bottomatpoint = (Data.uGlowBottomPlane.W + Data.uGlowBottomPlane.X * worldcoord.X + Data.uGlowBottomPlane.Y * worldcoord.Z) * Data.uGlowBottomPlane.Z; - glowdist.X = topatpoint - worldcoord.Y; - glowdist.Y = worldcoord.Y - bottomatpoint; - glowdist.Z = clamp(glowdist.X / (topatpoint - bottomatpoint), 0.0f, 1.0f); - }*/ - - if (Data.uObjectColor2.a != 0) - { - float topatpoint = (Data.uGradientTopPlane.W + Data.uGradientTopPlane.X * worldcoord.X + Data.uGradientTopPlane.Y * worldcoord.Z) * Data.uGradientTopPlane.Z; - float bottomatpoint = (Data.uGradientBottomPlane.W + Data.uGradientBottomPlane.X * worldcoord.X + Data.uGradientBottomPlane.Y * worldcoord.Z) * Data.uGradientBottomPlane.Z; - gradientdist.X = topatpoint - worldcoord.Y; - gradientdist.Y = worldcoord.Y - bottomatpoint; - gradientdist.Z = clamp(gradientdist.X / (topatpoint - bottomatpoint), 0.0f, 1.0f); - } - - if (Data.uSplitBottomPlane.Z != 0.0f) - { - gl_ClipDistance[3] = ((Data.uSplitTopPlane.W + Data.uSplitTopPlane.X * worldcoord.X + Data.uSplitTopPlane.Y * worldcoord.Z) * Data.uSplitTopPlane.Z) - worldcoord.Y; - gl_ClipDistance[4] = worldcoord.Y - ((Data.uSplitBottomPlane.W + Data.uSplitBottomPlane.X * worldcoord.X + Data.uSplitBottomPlane.Y * worldcoord.Z) * Data.uSplitBottomPlane.Z); - } - - vWorldNormal = mul(NormalModelMatrix, FVector4(normalize(mix3(aNormal, aNormal2, Data.uInterpolationFactor)), 1.0f)); - //vEyeNormal = mul(Viewpoint->mNormalViewMatrix, vWorldNormal); - } - - if (!SPHEREMAP) - { - vTexCoord = mul(TextureMatrix, FVector4(parmTexCoord.X, parmTexCoord.Y, 0.0f, 1.0f)); - } - else - { - FVector3 u = normalize3(eyeCoordPos); - FVector3 n = normalize3(mul(Viewpoint->mNormalViewMatrix, FVector4(parmTexCoord.X, 0.0f, parmTexCoord.Y, 0.0f))); - FVector3 r = reflect(u, n); - float m = 2.0f * sqrt(r.X*r.X + r.Y*r.Y + (r.Z + 1.0f)*(r.Z + 1.0f)); - vTexCoord.X = r.X / m + 0.5f; - vTexCoord.Y = r.Y / m + 0.5f; - } - - gl_Position = mul(Viewpoint->mProjectionMatrix, eyeCoordPos); - - if (Viewpoint->mClipHeightDirection != 0.0f) // clip planes used for reflective flats - { - gl_ClipDistance[0] = (worldcoord.Y - Viewpoint->mClipHeight) * Viewpoint->mClipHeightDirection; - } - else if (Viewpoint->mClipLine.X > -1000000.0f) // and for line portals - this will never be active at the same time as the reflective planes clipping so it can use the same hardware clip plane. - { - gl_ClipDistance[0] = -((worldcoord.Z - Viewpoint->mClipLine.Y) * Viewpoint->mClipLine.Z + (Viewpoint->mClipLine.X - worldcoord.X) * Viewpoint->mClipLine.W) + 1.0f / 32768.0f; // allow a tiny bit of imprecisions for colinear linedefs. - } - else - { - gl_ClipDistance[0] = 1.0f; - } - - // clip planes used for translucency splitting - gl_ClipDistance[1] = worldcoord.Y - uClipSplit.X; - gl_ClipDistance[2] = uClipSplit.Y - worldcoord.Y; - - if (Data.uSplitTopPlane == FVector4(0.0f, 0.0f, 0.0f, 0.0f)) - { - gl_ClipDistance[3] = 1.0f; - gl_ClipDistance[4] = 1.0f; - } - } - -private: - static FVector3 normalize(const FVector3 &a) - { - float rcplen = 1.0f / sqrt(a.X * a.X + a.Y * a.Y + a.Z * a.Z); - return FVector3(a.X * rcplen, a.Y * rcplen, a.Z * rcplen); - } - - static FVector3 normalize3(const FVector4 &a) - { - float rcplen = 1.0f / sqrt(a.X * a.X + a.Y * a.Y + a.Z * a.Z); - return FVector3(a.X * rcplen, a.Y * rcplen, a.Z * rcplen); - } - - static FVector4 mix(const FVector4 &a, const FVector4 &b, float t) - { - float invt = 1.0f - t; - return FVector4(a.X * invt + b.X * t, a.Y * invt + b.Y * t, a.Z * invt + b.Z * t, a.W * invt + b.W * t); - } - - static FVector3 mix3(const FVector4 &a, const FVector4 &b, float t) - { - float invt = 1.0f - t; - return FVector3(a.X * invt + b.X * t, a.Y * invt + b.Y * t, a.Z * invt + b.Z * t); - } - - static FVector3 reflect(const FVector3 &u, const FVector3 &n) - { - float d = 2.0f * (n.X * u.X + n.Y * u.Y + n.Z * u.Z); - return FVector3(u.X - d * n.X, u.Y - d * n.Y, u.Z - d * n.Z); - } - - static FVector4 mul(const VSMatrix &mat, const FVector4 &v) - { - const float *m = mat.get(); - - FVector4 result; -#ifdef NO_SSE - result.X = m[0 * 4 + 0] * v.X + m[1 * 4 + 0] * v.Y + m[2 * 4 + 0] * v.Z + m[3 * 4 + 0] * v.W; - result.Y = m[0 * 4 + 1] * v.X + m[1 * 4 + 1] * v.Y + m[2 * 4 + 1] * v.Z + m[3 * 4 + 1] * v.W; - result.Z = m[0 * 4 + 2] * v.X + m[1 * 4 + 2] * v.Y + m[2 * 4 + 2] * v.Z + m[3 * 4 + 2] * v.W; - result.W = m[0 * 4 + 3] * v.X + m[1 * 4 + 3] * v.Y + m[2 * 4 + 3] * v.Z + m[3 * 4 + 3] * v.W; -#else - __m128 m0 = _mm_loadu_ps(m); - __m128 m1 = _mm_loadu_ps(m + 4); - __m128 m2 = _mm_loadu_ps(m + 8); - __m128 m3 = _mm_loadu_ps(m + 12); - __m128 mv = _mm_loadu_ps(&v.X); - m0 = _mm_mul_ps(m0, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(0, 0, 0, 0))); - m1 = _mm_mul_ps(m1, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(1, 1, 1, 1))); - m2 = _mm_mul_ps(m2, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(2, 2, 2, 2))); - m3 = _mm_mul_ps(m3, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(3, 3, 3, 3))); - mv = _mm_add_ps(_mm_add_ps(_mm_add_ps(m0, m1), m2), m3); - _mm_storeu_ps(&result.X, mv); -#endif - return result; - } -}; diff --git a/src/rendering/polyrenderer/drawers/screen_blend.cpp b/src/rendering/polyrenderer/drawers/screen_blend.cpp deleted file mode 100644 index a8a7d1a8d2a..00000000000 --- a/src/rendering/polyrenderer/drawers/screen_blend.cpp +++ /dev/null @@ -1,615 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "screen_blend.h" - -static const int shiftTable[] = { - 0, 0, 0, 0, // STYLEALPHA_Zero - 0, 0, 0, 0, // STYLEALPHA_One - 24, 24, 24, 24, // STYLEALPHA_Src - 24, 24, 24, 24, // STYLEALPHA_InvSrc - 24, 16, 8, 0, // STYLEALPHA_SrcCol - 24, 16, 8, 0, // STYLEALPHA_InvSrcCol - 24, 16, 8, 0, // STYLEALPHA_DstCol - 24, 16, 8, 0 // STYLEALPHA_InvDstCol -}; - -#if 1 //#ifndef USE_AVX2 -template -void BlendColor(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - FRenderStyle style = thread->RenderStyle; - - bool invsrc = style.SrcAlpha & 1; - bool invdst = style.DestAlpha & 1; - - const int* shiftsrc = shiftTable + (style.SrcAlpha << 2); - const int* shiftdst = shiftTable + (style.DestAlpha << 2); - - uint32_t* dest = (uint32_t*)thread->dest; - uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int srcSelect = style.SrcAlpha <= STYLEALPHA_One ? 0 : (style.SrcAlpha >= STYLEALPHA_DstCol ? 1 : 2); - int dstSelect = style.DestAlpha <= STYLEALPHA_One ? 0 : (style.DestAlpha >= STYLEALPHA_DstCol ? 1 : 2); - - uint32_t inputs[3]; - inputs[0] = 0; - - for (int x = x0; x < x1; x++) - { - inputs[1] = line[x]; - inputs[2] = fragcolor[x]; - - uint32_t srcinput = inputs[srcSelect]; - uint32_t dstinput = inputs[dstSelect]; - - uint32_t out[4]; - for (int i = 0; i < 4; i++) - { - // Grab component for scale factors - int32_t src = (srcinput >> shiftsrc[i]) & 0xff; - int32_t dst = (dstinput >> shiftdst[i]) & 0xff; - - // Inverse if needed - if (invsrc) src = 0xff - src; - if (invdst) dst = 0xff - dst; - - // Rescale 0-255 to 0-256 - src = src + (src >> 7); - dst = dst + (dst >> 7); - - // Multiply with input - src = src * ((inputs[2] >> (24 - (i << 3))) & 0xff); - dst = dst * ((inputs[1] >> (24 - (i << 3))) & 0xff); - - // Apply blend operator - int32_t val; - if (OptT::Flags & SWBLEND_Sub) - { - val = src - dst; - } - else if (OptT::Flags & SWBLEND_RevSub) - { - val = dst - src; - } - else - { - val = src + dst; - } - out[i] = clamp((val + 127) >> 8, 0, 255); - } - - line[x] = MAKEARGB(out[0], out[1], out[2], out[3]); - } -} -#else -template -void BlendColor(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - FRenderStyle style = thread->RenderStyle; - - bool invsrc = style.SrcAlpha & 1; - bool invdst = style.DestAlpha & 1; - - __m128i shiftsrc = _mm_loadu_si128((const __m128i*)(shiftTable + (style.SrcAlpha << 2))); - __m128i shiftdst = _mm_loadu_si128((const __m128i*)(shiftTable + (style.DestAlpha << 2))); - - uint32_t* dest = (uint32_t*)thread->dest; - uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int srcSelect = style.SrcAlpha <= STYLEALPHA_One ? 0 : (style.SrcAlpha >= STYLEALPHA_DstCol ? 1 : 2); - int dstSelect = style.DestAlpha <= STYLEALPHA_One ? 0 : (style.DestAlpha >= STYLEALPHA_DstCol ? 1 : 2); - - uint32_t inputs[3]; - inputs[0] = 0; - - __m128i shiftmul = _mm_set_epi32(24, 16, 8, 0); - - for (int x = x0; x < x1; x++) - { - inputs[1] = line[x]; - inputs[2] = fragcolor[x]; - - __m128i srcinput = _mm_set1_epi32(inputs[srcSelect]); - __m128i dstinput = _mm_set1_epi32(inputs[dstSelect]); - - // Grab component for scale factors - __m128i src = _mm_and_si128(_mm_srlv_epi32(srcinput, shiftsrc), _mm_set1_epi32(0xff)); - __m128i dst = _mm_and_si128(_mm_srlv_epi32(dstinput, shiftdst), _mm_set1_epi32(0xff)); - - // Inverse if needed - if (invsrc) src = _mm_sub_epi32(_mm_set1_epi32(0xff), src); - if (invdst) dst = _mm_sub_epi32(_mm_set1_epi32(0xff), dst); - - // Rescale 0-255 to 0-256 - src = _mm_add_epi32(src, _mm_srli_epi32(src, 7)); - dst = _mm_add_epi32(dst, _mm_srli_epi32(dst, 7)); - - // Multiply with input - __m128i mulsrc = _mm_and_si128(_mm_srlv_epi32(_mm_set1_epi32(inputs[2]), shiftmul), _mm_set1_epi32(0xff)); - __m128i muldst = _mm_and_si128(_mm_srlv_epi32(_mm_set1_epi32(inputs[1]), shiftmul), _mm_set1_epi32(0xff)); - __m128i mulresult = _mm_mullo_epi16(_mm_packs_epi32(src, dst), _mm_packs_epi32(mulsrc, muldst)); - src = _mm_unpacklo_epi16(mulresult, _mm_setzero_si128()); - dst = _mm_unpackhi_epi16(mulresult, _mm_setzero_si128()); - - // Apply blend operator - __m128i val; - if (OptT::Flags & SWBLEND_Sub) - { - val = _mm_sub_epi32(src, dst); - } - else if (OptT::Flags & SWBLEND_RevSub) - { - val = _mm_sub_epi32(dst, src); - } - else - { - val = _mm_add_epi32(src, dst); - } - - __m128i out = _mm_srli_epi32(_mm_add_epi32(val, _mm_set1_epi32(127)), 8); - out = _mm_packs_epi32(out, out); - out = _mm_packus_epi16(out, out); - line[x] = _mm_cvtsi128_si32(out); - } -} -#endif - -#ifdef NO_SSE -void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* dest = (uint32_t*)thread->dest; - uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - memcpy(line + x0, fragcolor + x0, (x1 - x0) * sizeof(uint32_t)); -} -#else -void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* dest = (uint32_t*)thread->dest; - uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int ssecount = ((x1 - x0) & ~3); - int sseend = x0 + ssecount; - - for (int x = x0; x < sseend; x += 4) - { - __m128i v = _mm_loadu_si128((__m128i*) & fragcolor[x]); - _mm_storeu_si128((__m128i*) & line[x], v); - } - - for (int x = sseend; x < x1; x++) - { - line[x] = fragcolor[x]; - } -} -#endif - -void BlendColorAdd_Src_InvSrc(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int sseend = x0; - -#ifndef NO_SSE - int ssecount = ((x1 - x0) & ~1); - sseend = x0 + ssecount; - for (int x = x0; x < sseend; x += 2) - { - __m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)&line[x]), _mm_setzero_si128()); - __m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)&fragcolor[x]), _mm_setzero_si128()); - - __m128i srcscale = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); - srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7)); - __m128i dstscale = _mm_sub_epi16(_mm_set1_epi16(256), srcscale); - - __m128i out = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_mullo_epi16(dst, dstscale)), _mm_set1_epi16(127)), 8); - _mm_storel_epi64((__m128i*)&line[x], _mm_packus_epi16(out, out)); - } -#endif - - for (int x = sseend; x < x1; x++) - { - uint32_t dst = line[x]; - uint32_t src = fragcolor[x]; - - uint32_t srcscale = APART(src); - srcscale += srcscale >> 7; - uint32_t dstscale = 256 - srcscale; - - uint32_t a = ((APART(src) * srcscale + APART(dst) * dstscale) + 127) >> 8; - uint32_t r = ((RPART(src) * srcscale + RPART(dst) * dstscale) + 127) >> 8; - uint32_t g = ((GPART(src) * srcscale + GPART(dst) * dstscale) + 127) >> 8; - uint32_t b = ((BPART(src) * srcscale + BPART(dst) * dstscale) + 127) >> 8; - - line[x] = MAKEARGB(a, r, g, b); - } -} - -void BlendColorAdd_SrcCol_InvSrcCol(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int sseend = x0; - -#ifndef NO_SSE - int ssecount = ((x1 - x0) & ~1); - sseend = x0 + ssecount; - for (int x = x0; x < sseend; x += 2) - { - __m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128()); - __m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128()); - - __m128i srcscale = src; - srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7)); - __m128i dstscale = _mm_sub_epi16(_mm_set1_epi16(256), srcscale); - - __m128i out = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_mullo_epi16(dst, dstscale)), _mm_set1_epi16(127)), 8); - _mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out)); - } -#endif - - for (int x = sseend; x < x1; x++) - { - uint32_t dst = line[x]; - uint32_t src = fragcolor[x]; - - uint32_t srcscale_a = APART(src); - uint32_t srcscale_r = RPART(src); - uint32_t srcscale_g = GPART(src); - uint32_t srcscale_b = BPART(src); - srcscale_a += srcscale_a >> 7; - srcscale_r += srcscale_r >> 7; - srcscale_g += srcscale_g >> 7; - srcscale_b += srcscale_b >> 7; - uint32_t dstscale_a = 256 - srcscale_a; - uint32_t dstscale_r = 256 - srcscale_r; - uint32_t dstscale_g = 256 - srcscale_g; - uint32_t dstscale_b = 256 - srcscale_b; - - uint32_t a = ((APART(src) * srcscale_a + APART(dst) * dstscale_a) + 127) >> 8; - uint32_t r = ((RPART(src) * srcscale_r + RPART(dst) * dstscale_r) + 127) >> 8; - uint32_t g = ((GPART(src) * srcscale_g + GPART(dst) * dstscale_g) + 127) >> 8; - uint32_t b = ((BPART(src) * srcscale_b + BPART(dst) * dstscale_b) + 127) >> 8; - - line[x] = MAKEARGB(a, r, g, b); - } -} - -void BlendColorAdd_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int sseend = x0; - -#ifndef NO_SSE - int ssecount = ((x1 - x0) & ~1); - sseend = x0 + ssecount; - for (int x = x0; x < sseend; x += 2) - { - __m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128()); - __m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128()); - - __m128i srcscale = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); - srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7)); - - __m128i out = _mm_add_epi16(_mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8), dst); - _mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out)); - } -#endif - - for (int x = sseend; x < x1; x++) - { - uint32_t dst = line[x]; - uint32_t src = fragcolor[x]; - - uint32_t srcscale = APART(src); - srcscale += srcscale >> 7; - - uint32_t a = MIN((((APART(src) * srcscale) + 127) >> 8) + APART(dst), 255); - uint32_t r = MIN((((RPART(src) * srcscale) + 127) >> 8) + RPART(dst), 255); - uint32_t g = MIN((((GPART(src) * srcscale) + 127) >> 8) + GPART(dst), 255); - uint32_t b = MIN((((BPART(src) * srcscale) + 127) >> 8) + BPART(dst), 255); - - line[x] = MAKEARGB(a, r, g, b); - } -} - -void BlendColorAdd_SrcCol_One(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int sseend = x0; - -#ifndef NO_SSE - int ssecount = ((x1 - x0) & ~1); - sseend = x0 + ssecount; - for (int x = x0; x < sseend; x += 2) - { - __m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128()); - __m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128()); - - __m128i srcscale = src; - srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7)); - - __m128i out = _mm_add_epi16(_mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8), dst); - _mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out)); - } -#endif - - for (int x = sseend; x < x1; x++) - { - uint32_t dst = line[x]; - uint32_t src = fragcolor[x]; - - uint32_t srcscale_a = APART(src); - uint32_t srcscale_r = RPART(src); - uint32_t srcscale_g = GPART(src); - uint32_t srcscale_b = BPART(src); - srcscale_a += srcscale_a >> 7; - srcscale_r += srcscale_r >> 7; - srcscale_g += srcscale_g >> 7; - srcscale_b += srcscale_b >> 7; - - uint32_t a = MIN((((APART(src) * srcscale_a) + 127) >> 8) + APART(dst), 255); - uint32_t r = MIN((((RPART(src) * srcscale_r) + 127) >> 8) + RPART(dst), 255); - uint32_t g = MIN((((GPART(src) * srcscale_g) + 127) >> 8) + GPART(dst), 255); - uint32_t b = MIN((((BPART(src) * srcscale_b) + 127) >> 8) + BPART(dst), 255); - - line[x] = MAKEARGB(a, r, g, b); - } -} - -void BlendColorAdd_DstCol_Zero(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int sseend = x0; - -#ifndef NO_SSE - int ssecount = ((x1 - x0) & ~1); - sseend = x0 + ssecount; - for (int x = x0; x < sseend; x += 2) - { - __m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128()); - __m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128()); - - __m128i srcscale = dst; - srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7)); - - __m128i out = _mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8); - _mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out)); - } -#endif - - for (int x = sseend; x < x1; x++) - { - uint32_t dst = line[x]; - uint32_t src = fragcolor[x]; - - uint32_t srcscale_a = APART(dst); - uint32_t srcscale_r = RPART(dst); - uint32_t srcscale_g = GPART(dst); - uint32_t srcscale_b = BPART(dst); - srcscale_a += srcscale_a >> 7; - srcscale_r += srcscale_r >> 7; - srcscale_g += srcscale_g >> 7; - srcscale_b += srcscale_b >> 7; - - uint32_t a = (((APART(src) * srcscale_a) + 127) >> 8); - uint32_t r = (((RPART(src) * srcscale_r) + 127) >> 8); - uint32_t g = (((GPART(src) * srcscale_g) + 127) >> 8); - uint32_t b = (((BPART(src) * srcscale_b) + 127) >> 8); - - line[x] = MAKEARGB(a, r, g, b); - } -} - -void BlendColorAdd_InvDstCol_Zero(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int sseend = x0; - -#ifndef NO_SSE - int ssecount = ((x1 - x0) & ~1); - sseend = x0 + ssecount; - for (int x = x0; x < sseend; x += 2) - { - __m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128()); - __m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128()); - - __m128i srcscale = _mm_sub_epi16(_mm_set1_epi16(255), dst); - srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7)); - - __m128i out = _mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8); - _mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out)); - } -#endif - - for (int x = sseend; x < x1; x++) - { - uint32_t dst = line[x]; - uint32_t src = fragcolor[x]; - - uint32_t srcscale_a = 255 - APART(dst); - uint32_t srcscale_r = 255 - RPART(dst); - uint32_t srcscale_g = 255 - GPART(dst); - uint32_t srcscale_b = 255 - BPART(dst); - srcscale_a += srcscale_a >> 7; - srcscale_r += srcscale_r >> 7; - srcscale_g += srcscale_g >> 7; - srcscale_b += srcscale_b >> 7; - - uint32_t a = (((APART(src) * srcscale_a) + 127) >> 8); - uint32_t r = (((RPART(src) * srcscale_r) + 127) >> 8); - uint32_t g = (((GPART(src) * srcscale_g) + 127) >> 8); - uint32_t b = (((BPART(src) * srcscale_b) + 127) >> 8); - - line[x] = MAKEARGB(a, r, g, b); - } -} - -void BlendColorRevSub_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; - uint32_t* fragcolor = thread->scanline.FragColor; - - int sseend = x0; - -#ifndef NO_SSE - int ssecount = ((x1 - x0) & ~1); - sseend = x0 + ssecount; - for (int x = x0; x < sseend; x += 2) - { - __m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128()); - __m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128()); - - __m128i srcscale = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); - srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7)); - - __m128i out = _mm_sub_epi16(dst, _mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8)); - _mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out)); - } -#endif - - for (int x = sseend; x < x1; x++) - { - uint32_t dst = line[x]; - uint32_t src = fragcolor[x]; - - uint32_t srcscale = APART(src); - srcscale += srcscale >> 7; - - uint32_t a = MAX(APART(dst) - (((APART(src) * srcscale) + 127) >> 8), 0); - uint32_t r = MAX(RPART(dst) - (((RPART(src) * srcscale) + 127) >> 8), 0); - uint32_t g = MAX(GPART(dst) - (((GPART(src) * srcscale) + 127) >> 8), 0); - uint32_t b = MAX(BPART(dst) - (((BPART(src) * srcscale) + 127) >> 8), 0); - - line[x] = MAKEARGB(a, r, g, b); - } -} - -void BlendColorColormap(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; - - uint32_t startR = (int)((thread->mainVertexShader.Data.uObjectColor.r) * 255.0f); - uint32_t startG = (int)((thread->mainVertexShader.Data.uObjectColor.g) * 255.0f); - uint32_t startB = (int)((thread->mainVertexShader.Data.uObjectColor.b) * 255.0f); - uint32_t rangeR = (int)((thread->mainVertexShader.Data.uAddColor.r) * 255.0f) - startR; - uint32_t rangeG = (int)((thread->mainVertexShader.Data.uAddColor.g) * 255.0f) - startG; - uint32_t rangeB = (int)((thread->mainVertexShader.Data.uAddColor.b) * 255.0f) - startB; - - int sseend = x0; - for (int x = sseend; x < x1; x++) - { - uint32_t dst = line[x]; - - uint32_t a = APART(dst); - uint32_t r = RPART(dst); - uint32_t g = GPART(dst); - uint32_t b = BPART(dst); - - uint32_t gray = (r * 77 + g * 143 + b * 37) >> 8; - gray += (gray >> 7); // gray*=256/255 - - r = (startR + ((gray * rangeR) >> 8)) << 1; - g = (startG + ((gray * rangeG) >> 8)) << 1; - b = (startB + ((gray * rangeB) >> 8)) << 1; - - r = MIN(r, (uint32_t)255); - g = MIN(g, (uint32_t)255); - b = MIN(b, (uint32_t)255); - - line[x] = MAKEARGB(a, r, g, b); - } -} - -void SelectWriteColorFunc(PolyTriangleThreadData* thread) -{ - FRenderStyle style = thread->RenderStyle; - if (thread->ColormapShader) - { - thread->WriteColorFunc = &BlendColorColormap; - } - else if (style.BlendOp == STYLEOP_Add) - { - if (style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero) - { - thread->WriteColorFunc = &BlendColorOpaque; - } - else if (style.SrcAlpha == STYLEALPHA_Src && style.DestAlpha == STYLEALPHA_InvSrc) - { - thread->WriteColorFunc = &BlendColorAdd_Src_InvSrc; - } - else if (style.SrcAlpha == STYLEALPHA_SrcCol && style.DestAlpha == STYLEALPHA_InvSrcCol) - { - thread->WriteColorFunc = &BlendColorAdd_SrcCol_InvSrcCol; - } - else if (style.SrcAlpha == STYLEALPHA_Src && style.DestAlpha == STYLEALPHA_One) - { - thread->WriteColorFunc = &BlendColorAdd_Src_One; - } - else if (style.SrcAlpha == STYLEALPHA_SrcCol && style.DestAlpha == STYLEALPHA_One) - { - thread->WriteColorFunc = &BlendColorAdd_SrcCol_One; - } - else if (style.SrcAlpha == STYLEALPHA_DstCol && style.DestAlpha == STYLEALPHA_Zero) - { - thread->WriteColorFunc = &BlendColorAdd_DstCol_Zero; - } - else if (style.SrcAlpha == STYLEALPHA_InvDstCol && style.DestAlpha == STYLEALPHA_Zero) - { - thread->WriteColorFunc = &BlendColorAdd_InvDstCol_Zero; - } - else - { - thread->WriteColorFunc = &BlendColor; - } - } - else if (style.BlendOp == STYLEOP_Sub) - { - thread->WriteColorFunc = &BlendColor; - } - else // if (style.BlendOp == STYLEOP_RevSub) - { - if (style.SrcAlpha == STYLEALPHA_Src && style.DestAlpha == STYLEALPHA_One) - { - thread->WriteColorFunc = &BlendColorRevSub_Src_One; - } - else - { - thread->WriteColorFunc = &BlendColor; - } - } -} diff --git a/src/rendering/polyrenderer/drawers/screen_blend.h b/src/rendering/polyrenderer/drawers/screen_blend.h deleted file mode 100644 index 101c151b0dc..00000000000 --- a/src/rendering/polyrenderer/drawers/screen_blend.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#pragma once - -class PolyTriangleThreadData; - -enum SWBlendColor -{ - SWBLEND_Sub = 1, - SWBLEND_RevSub = 2 -}; - -struct BlendColorOpt_Add { static const int Flags = 0; }; -struct BlendColorOpt_Sub { static const int Flags = 1; }; -struct BlendColorOpt_RevSub { static const int Flags = 2; }; - -template -void BlendColor(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorAdd_Src_InvSrc(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorAdd_SrcCol_InvSrcCol(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorAdd_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorAdd_SrcCol_One(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorAdd_DstCol_Zero(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorAdd_InvDstCol_Zero(int y, int x0, int x1, PolyTriangleThreadData* thread); -void BlendColorRevSub_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thread); - -void SelectWriteColorFunc(PolyTriangleThreadData* thread); diff --git a/src/rendering/polyrenderer/drawers/screen_scanline_setup.cpp b/src/rendering/polyrenderer/drawers/screen_scanline_setup.cpp deleted file mode 100644 index 7567901a9f4..00000000000 --- a/src/rendering/polyrenderer/drawers/screen_scanline_setup.cpp +++ /dev/null @@ -1,541 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include -#include "templates.h" -#include "doomdef.h" -#include "poly_thread.h" -#include "screen_scanline_setup.h" -#include "x86.h" -#include - -#ifdef NO_SSE -void WriteW(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) -{ - float startX = x0 + (0.5f - args->v1->x); - float startY = y + (0.5f - args->v1->y); - - float posW = args->v1->w + args->gradientX.W * startX + args->gradientY.W * startY; - float stepW = args->gradientX.W; - float* w = thread->scanline.W; - for (int x = x0; x < x1; x++) - { - w[x] = 1.0f / posW; - posW += stepW; - } -} -#else -void WriteW(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) -{ - float startX = x0 + (0.5f - args->v1->x); - float startY = y + (0.5f - args->v1->y); - - float posW = args->v1->w + args->gradientX.W * startX + args->gradientY.W * startY; - float stepW = args->gradientX.W; - float* w = thread->scanline.W; - - int ssecount = ((x1 - x0) & ~3); - int sseend = x0 + ssecount; - - __m128 mstepW = _mm_set1_ps(stepW * 4.0f); - __m128 mposW = _mm_setr_ps(posW, posW + stepW, posW + stepW + stepW, posW + stepW + stepW + stepW); - - for (int x = x0; x < sseend; x += 4) - { - // One Newton-Raphson iteration for 1/posW - __m128 res = _mm_rcp_ps(mposW); - __m128 muls = _mm_mul_ps(mposW, _mm_mul_ps(res, res)); - _mm_storeu_ps(w + x, _mm_sub_ps(_mm_add_ps(res, res), muls)); - mposW = _mm_add_ps(mposW, mstepW); - } - - posW += ssecount * stepW; - for (int x = sseend; x < x1; x++) - { - w[x] = 1.0f / posW; - posW += stepW; - } -} -#endif - -static void WriteDynLightArray(int x0, int x1, PolyTriangleThreadData* thread) -{ - int num_lights = thread->numPolyLights; - PolyLight* lights = thread->polyLights; - - float worldnormalX = thread->mainVertexShader.vWorldNormal.X; - float worldnormalY = thread->mainVertexShader.vWorldNormal.Y; - float worldnormalZ = thread->mainVertexShader.vWorldNormal.Z; - - uint32_t* lightarray = thread->scanline.lightarray; - float* worldposX = thread->scanline.WorldX; - float* worldposY = thread->scanline.WorldY; - float* worldposZ = thread->scanline.WorldZ; - - int sseend = x0; - -#ifndef NO_SSE - int ssecount = ((x1 - x0) & ~3); - sseend = x0 + ssecount; - - __m128 mworldnormalX = _mm_set1_ps(worldnormalX); - __m128 mworldnormalY = _mm_set1_ps(worldnormalY); - __m128 mworldnormalZ = _mm_set1_ps(worldnormalZ); - - for (int x = x0; x < sseend; x += 4) - { - __m128i lit = _mm_loadu_si128((__m128i*)&lightarray[x]); - __m128i litlo = _mm_unpacklo_epi8(lit, _mm_setzero_si128()); - __m128i lithi = _mm_unpackhi_epi8(lit, _mm_setzero_si128()); - - for (int i = 0; i < num_lights; i++) - { - __m128 lightposX = _mm_set1_ps(lights[i].x); - __m128 lightposY = _mm_set1_ps(lights[i].y); - __m128 lightposZ = _mm_set1_ps(lights[i].z); - __m128 light_radius = _mm_set1_ps(lights[i].radius); - __m128i light_color = _mm_shuffle_epi32(_mm_unpacklo_epi8(_mm_cvtsi32_si128(lights[i].color), _mm_setzero_si128()), _MM_SHUFFLE(1, 0, 1, 0)); - - __m128 is_attenuated = _mm_cmplt_ps(light_radius, _mm_setzero_ps()); - light_radius = _mm_andnot_ps(_mm_set1_ps(-0.0f), light_radius); // clear sign bit - - // L = light-pos - // dist = sqrt(dot(L, L)) - // distance_attenuation = 1 - MIN(dist * (1/radius), 1) - __m128 Lx = _mm_sub_ps(lightposX, _mm_loadu_ps(&worldposX[x])); - __m128 Ly = _mm_sub_ps(lightposY, _mm_loadu_ps(&worldposY[x])); - __m128 Lz = _mm_sub_ps(lightposZ, _mm_loadu_ps(&worldposZ[x])); - __m128 dist2 = _mm_add_ps(_mm_mul_ps(Lx, Lx), _mm_add_ps(_mm_mul_ps(Ly, Ly), _mm_mul_ps(Lz, Lz))); - __m128 rcp_dist = _mm_rsqrt_ps(dist2); - __m128 dist = _mm_mul_ps(dist2, rcp_dist); - __m128 distance_attenuation = _mm_sub_ps(_mm_set1_ps(256.0f), _mm_min_ps(_mm_mul_ps(dist, light_radius), _mm_set1_ps(256.0f))); - - // The simple light type - __m128 simple_attenuation = distance_attenuation; - - // The point light type - // diffuse = max(dot(N,normalize(L)),0) * attenuation - Lx = _mm_mul_ps(Lx, rcp_dist); - Ly = _mm_mul_ps(Ly, rcp_dist); - Lz = _mm_mul_ps(Lz, rcp_dist); - __m128 dotNL = _mm_add_ps(_mm_add_ps(_mm_mul_ps(mworldnormalX, Lx), _mm_mul_ps(mworldnormalY, Ly)), _mm_mul_ps(mworldnormalZ, Lz)); - __m128 point_attenuation = _mm_mul_ps(_mm_max_ps(dotNL, _mm_setzero_ps()), distance_attenuation); - - __m128i attenuation = _mm_cvtps_epi32(_mm_or_ps(_mm_and_ps(is_attenuated, point_attenuation), _mm_andnot_ps(is_attenuated, simple_attenuation))); - - attenuation = _mm_shufflehi_epi16(_mm_shufflelo_epi16(attenuation, _MM_SHUFFLE(2, 2, 0, 0)), _MM_SHUFFLE(2, 2, 0, 0)); - __m128i attenlo = _mm_shuffle_epi32(attenuation, _MM_SHUFFLE(1, 1, 0, 0)); - __m128i attenhi = _mm_shuffle_epi32(attenuation, _MM_SHUFFLE(3, 3, 2, 2)); - - litlo = _mm_add_epi16(litlo, _mm_srli_epi16(_mm_mullo_epi16(light_color, attenlo), 8)); - lithi = _mm_add_epi16(lithi, _mm_srli_epi16(_mm_mullo_epi16(light_color, attenhi), 8)); - } - - _mm_storeu_si128((__m128i*)&lightarray[x], _mm_packus_epi16(litlo, lithi)); - } -#endif - - for (int x = sseend; x < x1; x++) - { - uint32_t lit_a = APART(lightarray[x]); - uint32_t lit_r = RPART(lightarray[x]); - uint32_t lit_g = GPART(lightarray[x]); - uint32_t lit_b = BPART(lightarray[x]); - - for (int i = 0; i < num_lights; i++) - { - float lightposX = lights[i].x; - float lightposY = lights[i].y; - float lightposZ = lights[i].z; - float light_radius = lights[i].radius; - uint32_t light_color = lights[i].color; - - bool is_attenuated = light_radius < 0.0f; - if (is_attenuated) - light_radius = -light_radius; - - // L = light-pos - // dist = sqrt(dot(L, L)) - // distance_attenuation = 1 - MIN(dist * (1/radius), 1) - float Lx = lightposX - worldposX[x]; - float Ly = lightposY - worldposY[x]; - float Lz = lightposZ - worldposZ[x]; - float dist2 = Lx * Lx + Ly * Ly + Lz * Lz; -#ifdef NO_SSE - //float rcp_dist = 1.0f / sqrt(dist2); - float rcp_dist = 1.0f / (dist2 * 0.01f); -#else - float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(dist2))); -#endif - float dist = dist2 * rcp_dist; - float distance_attenuation = 256.0f - MIN(dist * light_radius, 256.0f); - - // The simple light type - float simple_attenuation = distance_attenuation; - - // The point light type - // diffuse = max(dot(N,normalize(L)),0) * attenuation - Lx *= rcp_dist; - Ly *= rcp_dist; - Lz *= rcp_dist; - float dotNL = worldnormalX * Lx + worldnormalY * Ly + worldnormalZ * Lz; - float point_attenuation = MAX(dotNL, 0.0f) * distance_attenuation; - - uint32_t attenuation = (uint32_t)(is_attenuated ? (int32_t)point_attenuation : (int32_t)simple_attenuation); - - lit_r += (RPART(light_color) * attenuation) >> 8; - lit_g += (GPART(light_color) * attenuation) >> 8; - lit_b += (BPART(light_color) * attenuation) >> 8; - } - - lit_r = MIN(lit_r, 255); - lit_g = MIN(lit_g, 255); - lit_b = MIN(lit_b, 255); - lightarray[x] = MAKEARGB(lit_a, lit_r, lit_g, lit_b); - - // Palette version: - // dynlights[x] = RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)]; - } -} - -static void WriteLightArray(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) -{ - auto constants = thread->PushConstants; - - auto vColorR = thread->scanline.vColorR; - auto vColorG = thread->scanline.vColorG; - auto vColorB = thread->scanline.vColorB; - auto vColorA = thread->scanline.vColorA; - - if (thread->PushConstants->uLightLevel >= 0.0f) - { - float startX = x0 + (0.5f - args->v1->x); - float startY = y + (0.5f - args->v1->y); - float posW = args->v1->w + args->gradientX.W * startX + args->gradientY.W * startY; - float stepW = args->gradientX.W; - - float globVis = thread->mainVertexShader.Viewpoint->mGlobVis; - - uint32_t light = (int)(constants->uLightLevel * 255.0f); - fixed_t shade = (fixed_t)((2.0f - (light + 12.0f) / 128.0f) * (float)FRACUNIT); - fixed_t lightpos = (fixed_t)(globVis * posW * (float)FRACUNIT); - fixed_t lightstep = (fixed_t)(globVis * stepW * (float)FRACUNIT); - - fixed_t maxvis = 24 * FRACUNIT / 32; - fixed_t maxlight = 31 * FRACUNIT / 32; - - fixed_t lightend = lightpos + lightstep * (x1 - x0); - if (lightpos < maxvis && shade >= lightpos && shade - lightpos <= maxlight && - lightend < maxvis && shade >= lightend && shade - lightend <= maxlight) - { - lightpos += FRACUNIT - shade; - uint32_t* lightarray = thread->scanline.lightarray; - for (int x = x0; x < x1; x++) - { - uint32_t l = MIN(lightpos >> 8, 256); - - uint32_t r = vColorR[x]; - uint32_t g = vColorG[x]; - uint32_t b = vColorB[x]; - uint32_t a = vColorA[x]; - - lightarray[x] = MAKEARGB(a, (r * l) >> 8, (g * l) >> 8, (b * l) >> 8); - lightpos += lightstep; - } - } - else - { - uint32_t* lightarray = thread->scanline.lightarray; - for (int x = x0; x < x1; x++) - { - uint32_t l = MIN((FRACUNIT - clamp(shade - MIN(maxvis, lightpos), 0, maxlight)) >> 8, 256); - uint32_t r = vColorR[x]; - uint32_t g = vColorG[x]; - uint32_t b = vColorB[x]; - uint32_t a = vColorA[x]; - - lightarray[x] = MAKEARGB(a, (r * l) >> 8, (g * l) >> 8, (b * l) >> 8); - lightpos += lightstep; - } - } - } - else if (constants->uFogEnabled > 0) - { - float uLightDist = constants->uLightDist; - float uLightFactor = constants->uLightFactor; - float* w = thread->scanline.W; - uint32_t* lightarray = thread->scanline.lightarray; - for (int x = x0; x < x1; x++) - { - uint32_t a = thread->scanline.vColorA[x]; - uint32_t r = thread->scanline.vColorR[x]; - uint32_t g = thread->scanline.vColorG[x]; - uint32_t b = thread->scanline.vColorB[x]; - - float fogdist = MAX(16.0f, w[x]); - float fogfactor = std::exp2(constants->uFogDensity * fogdist); - - // brightening around the player for light mode 2: - if (fogdist < uLightDist) - { - uint32_t l = (int)((uLightFactor - (fogdist / uLightDist) * (uLightFactor - 1.0)) * 256.0f); - r = (r * l) >> 8; - g = (g * l) >> 8; - b = (b * l) >> 8; - } - - // apply light diminishing through fog equation: mix(vec3(0.0, 0.0, 0.0), lightshade.rgb, fogfactor) - uint32_t t = (int)(fogfactor * 256.0f); - r = (r * t) >> 8; - g = (g * t) >> 8; - b = (b * t) >> 8; - - lightarray[x] = MAKEARGB(a, r, g, b); - } - } - else - { - uint32_t* lightarray = thread->scanline.lightarray; - for (int x = x0; x < x1; x++) - { - uint32_t a = thread->scanline.vColorA[x]; - uint32_t r = thread->scanline.vColorR[x]; - uint32_t g = thread->scanline.vColorG[x]; - uint32_t b = thread->scanline.vColorB[x]; - lightarray[x] = MAKEARGB(a, r, g, b); - } - } -} - -#ifdef NO_SSE -static void WriteVarying(float pos, float step, int x0, int x1, const float* w, float* varying) -{ - for (int x = x0; x < x1; x++) - { - varying[x] = pos * w[x]; - pos += step; - } -} -#else -static void WriteVarying(float pos, float step, int x0, int x1, const float* w, float* varying) -{ - int ssecount = ((x1 - x0) & ~3); - int sseend = x0 + ssecount; - - __m128 mstep = _mm_set1_ps(step * 4.0f); - __m128 mpos = _mm_setr_ps(pos, pos + step, pos + step + step, pos + step + step + step); - - for (int x = x0; x < sseend; x += 4) - { - _mm_storeu_ps(varying + x, _mm_mul_ps(mpos, _mm_loadu_ps(w + x))); - mpos = _mm_add_ps(mpos, mstep); - } - - pos += ssecount * step; - for (int x = sseend; x < x1; x++) - { - varying[x] = pos * w[x]; - pos += step; - } -} -#endif - -#ifdef NO_SSE -static void WriteVaryingWrap(float pos, float step, int x0, int x1, const float* w, uint16_t* varying) -{ - for (int x = x0; x < x1; x++) - { - float value = pos * w[x]; - value = value - std::floor(value); - varying[x] = static_cast(static_cast(value * static_cast(0x1000'0000)) << 4) >> 16; - pos += step; - } -} -#else -static void WriteVaryingWrap(float pos, float step, int x0, int x1, const float* w, uint16_t* varying) -{ - int ssecount = ((x1 - x0) & ~3); - int sseend = x0 + ssecount; - - __m128 mstep = _mm_set1_ps(step * 4.0f); - __m128 mpos = _mm_setr_ps(pos, pos + step, pos + step + step, pos + step + step + step); - - for (int x = x0; x < sseend; x += 4) - { - __m128 value = _mm_mul_ps(mpos, _mm_loadu_ps(w + x)); - __m128 f = value; - __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f)); - __m128 r = _mm_sub_ps(t, _mm_and_ps(_mm_cmplt_ps(f, t), _mm_set1_ps(1.0f))); - value = _mm_sub_ps(f, r); - - __m128i ivalue = _mm_srli_epi32(_mm_slli_epi32(_mm_cvttps_epi32(_mm_mul_ps(value, _mm_set1_ps(static_cast(0x1000'0000)))), 4), 17); - _mm_storel_epi64((__m128i*)(varying + x), _mm_slli_epi16(_mm_packs_epi32(ivalue, ivalue), 1)); - mpos = _mm_add_ps(mpos, mstep); - } - - pos += ssecount * step; - for (int x = sseend; x < x1; x++) - { - float value = pos * w[x]; - __m128 f = _mm_set_ss(value); - __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f)); - __m128 r = _mm_sub_ss(t, _mm_and_ps(_mm_cmplt_ps(f, t), _mm_set_ss(1.0f))); - value = _mm_cvtss_f32(_mm_sub_ss(f, r)); - - varying[x] = static_cast(static_cast(value * static_cast(0x1000'0000)) << 4) >> 16; - pos += step; - } -} -#endif - -static void WriteVaryingWarp1(float posU, float posV, float stepU, float stepV, int x0, int x1, PolyTriangleThreadData* thread) -{ - float pi2 = 3.14159265358979323846f * 2.0f; - float timer = thread->mainVertexShader.Data.timer * 0.125f; - - const float* w = thread->scanline.W; - uint16_t* scanlineU = thread->scanline.U; - uint16_t* scanlineV = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - float u = posU * w[x]; - float v = posV * w[x]; - - v += g_sin(pi2 * (u + timer)) * 0.1f; - u += g_sin(pi2 * (v + timer)) * 0.1f; - - u = u - std::floor(u); - v = v - std::floor(v); - scanlineU[x] = static_cast(static_cast(u * static_cast(0x1000'0000)) << 4) >> 16; - scanlineV[x] = static_cast(static_cast(v * static_cast(0x1000'0000)) << 4) >> 16; - - posU += stepU; - posV += stepV; - } -} - -static void WriteVaryingWarp2(float posU, float posV, float stepU, float stepV, int x0, int x1, PolyTriangleThreadData* thread) -{ - float pi2 = 3.14159265358979323846f * 2.0f; - float timer = thread->mainVertexShader.Data.timer; - - const float* w = thread->scanline.W; - uint16_t* scanlineU = thread->scanline.U; - uint16_t* scanlineV = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - float u = posU * w[x]; - float v = posV * w[x]; - - v += (0.5f + g_sin(pi2 * (v + timer * 0.61f + 900.f/8192.f)) + g_sin(pi2 * (u * 2.0f + timer * 0.36f + 300.0f/8192.0f))) * 0.025f; - u += (0.5f + g_sin(pi2 * (v + timer * 0.49f + 700.f/8192.f)) + g_sin(pi2 * (u * 2.0f + timer * 0.49f + 1200.0f/8192.0f))) * 0.025f; - - u = u - std::floor(u); - v = v - std::floor(v); - scanlineU[x] = static_cast(static_cast(u * static_cast(0x1000'0000)) << 4) >> 16; - scanlineV[x] = static_cast(static_cast(v * static_cast(0x1000'0000)) << 4) >> 16; - - posU += stepU; - posV += stepV; - } -} - -#ifdef NO_SSE -static void WriteVaryingColor(float pos, float step, int x0, int x1, const float* w, uint8_t* varying) -{ - for (int x = x0; x < x1; x++) - { - varying[x] = clamp(static_cast(pos * w[x] * 255.0f), 0, 255); - pos += step; - } -} -#else -static void WriteVaryingColor(float pos, float step, int x0, int x1, const float* w, uint8_t* varying) -{ - int ssecount = ((x1 - x0) & ~3); - int sseend = x0 + ssecount; - - __m128 mstep = _mm_set1_ps(step * 4.0f); - __m128 mpos = _mm_setr_ps(pos, pos + step, pos + step + step, pos + step + step + step); - - for (int x = x0; x < sseend; x += 4) - { - __m128i value = _mm_cvttps_epi32(_mm_mul_ps(_mm_mul_ps(mpos, _mm_loadu_ps(w + x)), _mm_set1_ps(255.0f))); - value = _mm_packs_epi32(value, value); - value = _mm_packus_epi16(value, value); - *(uint32_t*)(varying + x) = _mm_cvtsi128_si32(value); - mpos = _mm_add_ps(mpos, mstep); - } - - pos += ssecount * step; - for (int x = sseend; x < x1; x++) - { - varying[x] = clamp(static_cast(pos * w[x] * 255.0f), 0, 255); - pos += step; - } -} -#endif - -void WriteVaryings(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) -{ - float startX = x0 + (0.5f - args->v1->x); - float startY = y + (0.5f - args->v1->y); - - void (*useShader)(float posU, float posV, float stepU, float stepV, int x0, int x1, PolyTriangleThreadData* thread) = nullptr; - - if (thread->EffectState == SHADER_Warp1) - useShader = &WriteVaryingWarp1; - else if (thread->EffectState == SHADER_Warp2) - useShader = &WriteVaryingWarp2; - - if (useShader) - { - useShader( - args->v1->u * args->v1->w + args->gradientX.U * startX + args->gradientY.U * startY, - args->v1->v * args->v1->w + args->gradientX.V * startX + args->gradientY.V * startY, - args->gradientX.U, - args->gradientX.V, - x0, x1, - thread); - } - else - { - WriteVaryingWrap(args->v1->u * args->v1->w + args->gradientX.U * startX + args->gradientY.U * startY, args->gradientX.U, x0, x1, thread->scanline.W, thread->scanline.U); - WriteVaryingWrap(args->v1->v * args->v1->w + args->gradientX.V * startX + args->gradientY.V * startY, args->gradientX.V, x0, x1, thread->scanline.W, thread->scanline.V); - } - WriteVarying(args->v1->worldX * args->v1->w + args->gradientX.WorldX * startX + args->gradientY.WorldX * startY, args->gradientX.WorldX, x0, x1, thread->scanline.W, thread->scanline.WorldX); - WriteVarying(args->v1->worldY * args->v1->w + args->gradientX.WorldY * startX + args->gradientY.WorldY * startY, args->gradientX.WorldY, x0, x1, thread->scanline.W, thread->scanline.WorldY); - WriteVarying(args->v1->worldZ * args->v1->w + args->gradientX.WorldZ * startX + args->gradientY.WorldZ * startY, args->gradientX.WorldZ, x0, x1, thread->scanline.W, thread->scanline.WorldZ); - WriteVarying(args->v1->gradientdistZ * args->v1->w + args->gradientX.GradientdistZ * startX + args->gradientY.GradientdistZ * startY, args->gradientX.GradientdistZ, x0, x1, thread->scanline.W, thread->scanline.GradientdistZ); - WriteVaryingColor(args->v1->a * args->v1->w + args->gradientX.A * startX + args->gradientY.A * startY, args->gradientX.A, x0, x1, thread->scanline.W, thread->scanline.vColorA); - WriteVaryingColor(args->v1->r * args->v1->w + args->gradientX.R * startX + args->gradientY.R * startY, args->gradientX.R, x0, x1, thread->scanline.W, thread->scanline.vColorR); - WriteVaryingColor(args->v1->g * args->v1->w + args->gradientX.G * startX + args->gradientY.G * startY, args->gradientX.G, x0, x1, thread->scanline.W, thread->scanline.vColorG); - WriteVaryingColor(args->v1->b * args->v1->w + args->gradientX.B * startX + args->gradientY.B * startY, args->gradientX.B, x0, x1, thread->scanline.W, thread->scanline.vColorB); - - if (thread->PushConstants->uFogEnabled != -3 && thread->PushConstants->uTextureMode != TM_FOGLAYER) - WriteLightArray(y, x0, x1, args, thread); - - if (thread->numPolyLights > 0) - WriteDynLightArray(x0, x1, thread); -} diff --git a/src/rendering/polyrenderer/drawers/screen_scanline_setup.h b/src/rendering/polyrenderer/drawers/screen_scanline_setup.h deleted file mode 100644 index 5ea66cf9687..00000000000 --- a/src/rendering/polyrenderer/drawers/screen_scanline_setup.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#pragma once - -struct TriDrawTriangleArgs; -class PolyTriangleThreadData; - -void WriteW(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread); -void WriteVaryings(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread); diff --git a/src/rendering/polyrenderer/drawers/screen_shader.cpp b/src/rendering/polyrenderer/drawers/screen_shader.cpp deleted file mode 100644 index af23172a6c8..00000000000 --- a/src/rendering/polyrenderer/drawers/screen_shader.cpp +++ /dev/null @@ -1,632 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include -#include "templates.h" -#include "doomdef.h" -#include "poly_thread.h" -#include "screen_scanline_setup.h" -#include "x86.h" -#include - -static uint32_t SampleTexture(uint32_t u, uint32_t v, const void* texPixels, int texWidth, int texHeight, bool texBgra) -{ - int texelX = (u * texWidth) >> 16; - int texelY = (v * texHeight) >> 16; - int texelOffset = texelX + texelY * texWidth; - if (texBgra) - { - return static_cast(texPixels)[texelOffset]; - } - else - { - uint32_t c = static_cast(texPixels)[texelOffset]; - return (c << 16) | 0xff000000; - } -} - -static void EffectFogBoundary(int x0, int x1, PolyTriangleThreadData* thread) -{ - float uFogDensity = thread->PushConstants->uFogDensity; - uint32_t fogcolor = MAKEARGB( - 0, - static_cast(clamp(thread->mainVertexShader.Data.uFogColor.r, 0.0f, 1.0f) * 255.0f), - static_cast(clamp(thread->mainVertexShader.Data.uFogColor.g, 0.0f, 1.0f) * 255.0f), - static_cast(clamp(thread->mainVertexShader.Data.uFogColor.b, 0.0f, 1.0f) * 255.0f)); - - uint32_t* fragcolor = thread->scanline.FragColor; - for (int x = x0; x < x1; x++) - { - float fogdist = thread->scanline.W[x]; - float fogfactor = std::exp2(uFogDensity * fogdist); - - // FragColor = vec4(uFogColor.rgb, 1.0 - fogfactor): - uint32_t alpha = static_cast(clamp(1.0f - (1.0f / 255.0f), 0.0f, 1.0f) * 255.0f); - fragcolor[x] = fogcolor | alpha; - } -} - -static void EffectBurn(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - - int tex2Width = thread->textures[1].width; - int tex2Height = thread->textures[1].height; - const void* tex2Pixels = thread->textures[1].pixels; - bool tex2Bgra = thread->textures[1].bgra; - - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - for (int x = x0; x < x1; x++) - { - uint32_t frag_r = thread->scanline.vColorR[x]; - uint32_t frag_g = thread->scanline.vColorG[x]; - uint32_t frag_b = thread->scanline.vColorB[x]; - uint32_t frag_a = thread->scanline.vColorA[x]; - frag_r += frag_r >> 7; // 255 -> 256 - frag_g += frag_g >> 7; // 255 -> 256 - frag_b += frag_b >> 7; // 255 -> 256 - frag_a += frag_a >> 7; // 255 -> 256 - - uint32_t t1 = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); - uint32_t t2 = SampleTexture(u[x], 0xffff - v[x], tex2Pixels, tex2Width, tex2Height, tex2Bgra); - - uint32_t r = (frag_r * RPART(t1)) >> 8; - uint32_t g = (frag_g * GPART(t1)) >> 8; - uint32_t b = (frag_b * BPART(t1)) >> 8; - uint32_t a = (frag_a * APART(t2)) >> 8; - - fragcolor[x] = MAKEARGB(a, r, g, b); - } -} - -static void EffectStencil(int x0, int x1, PolyTriangleThreadData* thread) -{ - /*for (int x = x0; x < x1; x++) - { - fragcolor[x] = 0x00ffffff; - }*/ -} - -static void FuncPaletted(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - const uint32_t* lut = (const uint32_t*)thread->textures[1].pixels; - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - fragcolor[x] = lut[RPART(SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra))] | 0xff000000; - } -} - -static void FuncNoTexture(int x0, int x1, PolyTriangleThreadData* thread) -{ - auto& streamdata = thread->mainVertexShader.Data; - uint32_t a = (int)(streamdata.uObjectColor.a * 255.0f); - uint32_t r = (int)(streamdata.uObjectColor.r * 255.0f); - uint32_t g = (int)(streamdata.uObjectColor.g * 255.0f); - uint32_t b = (int)(streamdata.uObjectColor.b * 255.0f); - uint32_t texel = MAKEARGB(a, r, g, b); - - if (streamdata.uDesaturationFactor > 0.0f) - { - uint32_t t = (int)(streamdata.uDesaturationFactor * 256.0f); - uint32_t inv_t = 256 - t; - uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8; - texel = MAKEARGB( - APART(texel), - (RPART(texel) * inv_t + gray * t + 127) >> 8, - (GPART(texel) * inv_t + gray * t + 127) >> 8, - (BPART(texel) * inv_t + gray * t + 127) >> 8); - } - - uint32_t* fragcolor = thread->scanline.FragColor; - for (int x = x0; x < x1; x++) - { - fragcolor[x] = texel; - } -} - -static void FuncNormal(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); - fragcolor[x] = texel; - } -} - -static void FuncNormal_Stencil(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); - fragcolor[x] = texel | 0x00ffffff; - } -} - -static void FuncNormal_Opaque(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); - fragcolor[x] = texel | 0xff000000; - } -} - -static void FuncNormal_Inverse(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); - fragcolor[x] = MAKEARGB(APART(texel), 0xff - RPART(texel), 0xff - BPART(texel), 0xff - GPART(texel)); - } -} - -static void FuncNormal_AlphaTexture(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); - uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8; - uint32_t alpha = APART(texel); - alpha += alpha >> 7; - alpha = (alpha * gray + 127) >> 8; - texel = (alpha << 24) | 0x00ffffff; - fragcolor[x] = texel; - } -} - -static void FuncNormal_ClampY(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - fragcolor[x] = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); - if (v[x] < 0.0 || v[x] > 1.0) - fragcolor[x] &= 0x00ffffff; - } -} - -static void FuncNormal_InvertOpaque(int x0, int x1, PolyTriangleThreadData* thread) -{ - int texWidth = thread->textures[0].width; - int texHeight = thread->textures[0].height; - const void* texPixels = thread->textures[0].pixels; - bool texBgra = thread->textures[0].bgra; - uint32_t* fragcolor = thread->scanline.FragColor; - uint16_t* u = thread->scanline.U; - uint16_t* v = thread->scanline.V; - - for (int x = x0; x < x1; x++) - { - uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); - fragcolor[x] = MAKEARGB(0xff, 0xff - RPART(texel), 0xff - BPART(texel), 0xff - GPART(texel)); - } -} - -static void FuncNormal_AddColor(int x0, int x1, PolyTriangleThreadData* thread) -{ - auto& streamdata = thread->mainVertexShader.Data; - uint32_t r = (int)(streamdata.uAddColor.r * 255.0f); - uint32_t g = (int)(streamdata.uAddColor.g * 255.0f); - uint32_t b = (int)(streamdata.uAddColor.b * 255.0f); - uint32_t* fragcolor = thread->scanline.FragColor; - for (int x = x0; x < x1; x++) - { - uint32_t texel = fragcolor[x]; - fragcolor[x] = MAKEARGB( - APART(texel), - MIN(r + RPART(texel), (uint32_t)255), - MIN(g + GPART(texel), (uint32_t)255), - MIN(b + BPART(texel), (uint32_t)255)); - } -} - -static void FuncNormal_AddObjectColor(int x0, int x1, PolyTriangleThreadData* thread) -{ - auto& streamdata = thread->mainVertexShader.Data; - uint32_t r = (int)(streamdata.uObjectColor.r * 256.0f); - uint32_t g = (int)(streamdata.uObjectColor.g * 256.0f); - uint32_t b = (int)(streamdata.uObjectColor.b * 256.0f); - uint32_t* fragcolor = thread->scanline.FragColor; - for (int x = x0; x < x1; x++) - { - uint32_t texel = fragcolor[x]; - fragcolor[x] = MAKEARGB( - APART(texel), - MIN((r * RPART(texel)) >> 8, (uint32_t)255), - MIN((g * GPART(texel)) >> 8, (uint32_t)255), - MIN((b * BPART(texel)) >> 8, (uint32_t)255)); - } -} - -static void FuncNormal_AddObjectColor2(int x0, int x1, PolyTriangleThreadData* thread) -{ - auto& streamdata = thread->mainVertexShader.Data; - float* gradientdistZ = thread->scanline.GradientdistZ; - uint32_t* fragcolor = thread->scanline.FragColor; - for (int x = x0; x < x1; x++) - { - float t = gradientdistZ[x]; - float inv_t = 1.0f - t; - uint32_t r = (int)((streamdata.uObjectColor.r * inv_t + streamdata.uObjectColor2.r * t) * 256.0f); - uint32_t g = (int)((streamdata.uObjectColor.g * inv_t + streamdata.uObjectColor2.g * t) * 256.0f); - uint32_t b = (int)((streamdata.uObjectColor.b * inv_t + streamdata.uObjectColor2.b * t) * 256.0f); - - uint32_t texel = fragcolor[x]; - fragcolor[x] = MAKEARGB( - APART(texel), - MIN((r * RPART(texel)) >> 8, (uint32_t)255), - MIN((g * GPART(texel)) >> 8, (uint32_t)255), - MIN((b * BPART(texel)) >> 8, (uint32_t)255)); - } -} - -static void FuncNormal_DesaturationFactor(int x0, int x1, PolyTriangleThreadData* thread) -{ - auto& streamdata = thread->mainVertexShader.Data; - uint32_t* fragcolor = thread->scanline.FragColor; - uint32_t t = (int)(streamdata.uDesaturationFactor * 256.0f); - uint32_t inv_t = 256 - t; - for (int x = x0; x < x1; x++) - { - uint32_t texel = fragcolor[x]; - uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8; - fragcolor[x] = MAKEARGB( - APART(texel), - (RPART(texel) * inv_t + gray * t + 127) >> 8, - (GPART(texel) * inv_t + gray * t + 127) >> 8, - (BPART(texel) * inv_t + gray * t + 127) >> 8); - } -} - -static void RunAlphaTest(int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t alphaThreshold = thread->AlphaThreshold; - uint32_t* fragcolor = thread->scanline.FragColor; - uint8_t* discard = thread->scanline.discard; - for (int x = x0; x < x1; x++) - { - discard[x] = fragcolor[x] <= alphaThreshold; - } -} - -static void ProcessMaterial(int x0, int x1, PolyTriangleThreadData* thread) -{ - if (thread->EffectState == SHADER_Paletted) // func_paletted - { - FuncPaletted(x0, x1, thread); - } - else if (thread->EffectState == SHADER_NoTexture) // func_notexture - { - FuncNoTexture(x0, x1, thread); - } - else // func_normal - { - auto constants = thread->PushConstants; - - switch (constants->uTextureMode) - { - default: - case TM_NORMAL: - case TM_FOGLAYER: FuncNormal(x0, x1, thread); break; - case TM_STENCIL: FuncNormal_Stencil(x0, x1, thread); break; - case TM_OPAQUE: FuncNormal_Opaque(x0, x1, thread); break; - case TM_INVERSE: FuncNormal_Inverse(x0, x1, thread); break; - case TM_ALPHATEXTURE: FuncNormal_AlphaTexture(x0, x1, thread); break; - case TM_CLAMPY: FuncNormal_ClampY(x0, x1, thread); break; - case TM_INVERTOPAQUE: FuncNormal_InvertOpaque(x0, x1, thread); break; - } - - if (constants->uTextureMode != TM_FOGLAYER) - { - auto& streamdata = thread->mainVertexShader.Data; - - if (streamdata.uAddColor.r != 0.0f || streamdata.uAddColor.g != 0.0f || streamdata.uAddColor.b != 0.0f) - { - FuncNormal_AddColor(x0, x1, thread); - } - - if (streamdata.uObjectColor2.a == 0.0f) - { - if (streamdata.uObjectColor.r != 1.0f || streamdata.uObjectColor.g != 1.0f || streamdata.uObjectColor.b != 1.0f) - { - FuncNormal_AddObjectColor(x0, x1, thread); - } - } - else - { - FuncNormal_AddObjectColor2(x0, x1, thread); - } - - if (streamdata.uDesaturationFactor > 0.0f) - { - FuncNormal_DesaturationFactor(x0, x1, thread); - } - } - } -} - -static void GetLightColor(int x0, int x1, PolyTriangleThreadData* thread) -{ - uint32_t* fragcolor = thread->scanline.FragColor; - uint32_t* lightarray = thread->scanline.lightarray; - - if (thread->PushConstants->uFogEnabled >= 0) - { - for (int x = x0; x < x1; x++) - { - uint32_t fg = fragcolor[x]; - uint32_t lightshade = lightarray[x]; - - uint32_t mulA = APART(lightshade); - uint32_t mulR = RPART(lightshade); - uint32_t mulG = GPART(lightshade); - uint32_t mulB = BPART(lightshade); - mulA += mulA >> 7; - mulR += mulR >> 7; - mulG += mulG >> 7; - mulB += mulB >> 7; - - uint32_t a = (APART(fg) * mulA + 127) >> 8; - uint32_t r = (RPART(fg) * mulR + 127) >> 8; - uint32_t g = (GPART(fg) * mulG + 127) >> 8; - uint32_t b = (BPART(fg) * mulB + 127) >> 8; - - fragcolor[x] = MAKEARGB(a, r, g, b); - } - } - else - { - uint32_t fogR = (int)((thread->mainVertexShader.Data.uFogColor.r) * 255.0f); - uint32_t fogG = (int)((thread->mainVertexShader.Data.uFogColor.g) * 255.0f); - uint32_t fogB = (int)((thread->mainVertexShader.Data.uFogColor.b) * 255.0f); - float uFogDensity = thread->PushConstants->uFogDensity; - - float* w = thread->scanline.W; - for (int x = x0; x < x1; x++) - { - uint32_t fg = fragcolor[x]; - uint32_t lightshade = lightarray[x]; - - uint32_t mulA = APART(lightshade); - uint32_t mulR = RPART(lightshade); - uint32_t mulG = GPART(lightshade); - uint32_t mulB = BPART(lightshade); - mulA += mulA >> 7; - mulR += mulR >> 7; - mulG += mulG >> 7; - mulB += mulB >> 7; - - float fogdist = MAX(16.0f, w[x]); - float fogfactor = std::exp2(uFogDensity * fogdist); - - uint32_t a = (APART(fg) * mulA + 127) >> 8; - uint32_t r = (RPART(fg) * mulR + 127) >> 8; - uint32_t g = (GPART(fg) * mulG + 127) >> 8; - uint32_t b = (BPART(fg) * mulB + 127) >> 8; - - uint32_t t = (int)(fogfactor * 256.0f); - uint32_t inv_t = 256 - t; - r = (fogR * inv_t + r * t + 127) >> 8; - g = (fogG * inv_t + g * t + 127) >> 8; - b = (fogB * inv_t + b * t + 127) >> 8; - - fragcolor[x] = MAKEARGB(a, r, g, b); - } - } -} - -static void MainFP(int x0, int x1, PolyTriangleThreadData* thread) -{ - ProcessMaterial(x0, x1, thread); - - if (thread->AlphaTest) - RunAlphaTest(x0, x1, thread); - - auto constants = thread->PushConstants; - if (constants->uFogEnabled != -3) - { - if (constants->uTextureMode != TM_FOGLAYER) - { - GetLightColor(x0, x1, thread); - } - else - { - /*float fogdist = 0.0f; - float fogfactor = 0.0f; - if (constants->uFogEnabled != 0) - { - fogdist = MAX(16.0f, w[x]); - fogfactor = std::exp2(constants->uFogDensity * fogdist); - } - frag = vec4(uFogColor.rgb, (1.0 - fogfactor) * frag.a * 0.75 * vColor.a);*/ - } - } - else // simple 2D (uses the fog color to add a color overlay) - { - uint32_t fogR = (int)((thread->mainVertexShader.Data.uFogColor.r) * 255.0f); - uint32_t fogG = (int)((thread->mainVertexShader.Data.uFogColor.g) * 255.0f); - uint32_t fogB = (int)((thread->mainVertexShader.Data.uFogColor.b) * 255.0f); - - auto vColorR = thread->scanline.vColorR; - auto vColorG = thread->scanline.vColorG; - auto vColorB = thread->scanline.vColorB; - auto vColorA = thread->scanline.vColorA; - uint32_t* fragcolor = thread->scanline.FragColor; - - if (constants->uTextureMode == TM_FIXEDCOLORMAP) - { - // float gray = grayscale(frag); - // vec4 cm = (uObjectColor + gray * (uAddColor - uObjectColor)) * 2; - // frag = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a); - // frag = frag * vColor; - // frag.rgb = frag.rgb + uFogColor.rgb; - - uint32_t startR = (int)((thread->mainVertexShader.Data.uObjectColor.r) * 255.0f); - uint32_t startG = (int)((thread->mainVertexShader.Data.uObjectColor.g) * 255.0f); - uint32_t startB = (int)((thread->mainVertexShader.Data.uObjectColor.b) * 255.0f); - uint32_t rangeR = (int)((thread->mainVertexShader.Data.uAddColor.r) * 255.0f) - startR; - uint32_t rangeG = (int)((thread->mainVertexShader.Data.uAddColor.g) * 255.0f) - startG; - uint32_t rangeB = (int)((thread->mainVertexShader.Data.uAddColor.b) * 255.0f) - startB; - - for (int x = x0; x < x1; x++) - { - uint32_t a = APART(fragcolor[x]); - uint32_t r = RPART(fragcolor[x]); - uint32_t g = GPART(fragcolor[x]); - uint32_t b = BPART(fragcolor[x]); - - uint32_t gray = (r * 77 + g * 143 + b * 37) >> 8; - gray += (gray >> 7); // gray*=256/255 - - r = (startR + ((gray * rangeR) >> 8)) << 1; - g = (startG + ((gray * rangeG) >> 8)) << 1; - b = (startB + ((gray * rangeB) >> 8)) << 1; - - r = MIN(r, (uint32_t)255); - g = MIN(g, (uint32_t)255); - b = MIN(b, (uint32_t)255); - - fragcolor[x] = MAKEARGB(a, r, g, b); - } - } - else - { - for (int x = x0; x < x1; x++) - { - uint32_t a = vColorA[x]; - uint32_t r = vColorR[x]; - uint32_t g = vColorG[x]; - uint32_t b = vColorB[x]; - a += a >> 7; - r += r >> 7; - g += g >> 7; - b += b >> 7; - - // frag = frag * vColor; - a = (APART(fragcolor[x]) * a + 127) >> 8; - r = (RPART(fragcolor[x]) * r + 127) >> 8; - g = (GPART(fragcolor[x]) * g + 127) >> 8; - b = (BPART(fragcolor[x]) * b + 127) >> 8; - - // frag.rgb = frag.rgb + uFogColor.rgb; - r = MIN(r + fogR, (uint32_t)255); - g = MIN(g + fogG, (uint32_t)255); - b = MIN(b + fogB, (uint32_t)255); - - fragcolor[x] = MAKEARGB(a, r, g, b); - } - } - } -} - -void ColormapFP(int x0, int x1, PolyTriangleThreadData* thread) -{ - // This is implemented in BlendColorColormap. -} - -void SelectFragmentShader(PolyTriangleThreadData* thread) -{ - void (*fragshader)(int x0, int x1, PolyTriangleThreadData * thread); - - if (thread->ColormapShader) - { - fragshader = &ColormapFP; - } - else if (thread->SpecialEffect == EFF_FOGBOUNDARY) // fogboundary.fp - { - fragshader = &EffectFogBoundary; - } - else if (thread->SpecialEffect == EFF_BURN) // burn.fp - { - fragshader = &EffectBurn; - } - else if (thread->SpecialEffect == EFF_STENCIL) // stencil.fp - { - fragshader = &EffectStencil; - } - else - { - fragshader = &MainFP; - } - - thread->FragmentShader = fragshader; -} diff --git a/src/rendering/polyrenderer/drawers/screen_shader.h b/src/rendering/polyrenderer/drawers/screen_shader.h deleted file mode 100644 index 567b4d6c965..00000000000 --- a/src/rendering/polyrenderer/drawers/screen_shader.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#pragma once - -class PolyTriangleThreadData; - -void SelectFragmentShader(PolyTriangleThreadData* thread); diff --git a/src/rendering/polyrenderer/drawers/screen_triangle.cpp b/src/rendering/polyrenderer/drawers/screen_triangle.cpp deleted file mode 100644 index c286b8c65a5..00000000000 --- a/src/rendering/polyrenderer/drawers/screen_triangle.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include -#include "templates.h" -#include "doomdef.h" - -#include "w_wad.h" -#include "v_video.h" -#include "doomstat.h" -#include "st_stuff.h" -#include "g_game.h" -#include "g_level.h" -#include "r_data/r_translate.h" -#include "v_palette.h" -#include "r_data/colormaps.h" -#include "poly_triangle.h" -#include "swrenderer/drawers/r_draw_rgba.h" -#include "screen_triangle.h" -#include "screen_blend.h" -#include "screen_scanline_setup.h" -#include "screen_shader.h" -#include "x86.h" -#include - -static void WriteDepth(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - size_t pitch = thread->depthstencil->Width(); - float* line = thread->depthstencil->DepthValues() + pitch * y; - float* w = thread->scanline.W; - for (int x = x0; x < x1; x++) - { - line[x] = w[x]; - } -} - -static void WriteStencil(int y, int x0, int x1, PolyTriangleThreadData* thread) -{ - size_t pitch = thread->depthstencil->Width(); - uint8_t* line = thread->depthstencil->StencilValues() + pitch * y; - uint8_t value = thread->StencilWriteValue; - for (int x = x0; x < x1; x++) - { - line[x] = value; - } -} - -static void DrawSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) -{ - WriteVaryings(y, x0, x1, args, thread); - - thread->FragmentShader(x0, x1, thread); - - if (!thread->AlphaTest) - { - if (thread->WriteColor) - thread->WriteColorFunc(y, x0, x1, thread); - if (thread->WriteDepth) - WriteDepth(y, x0, x1, thread); - if (thread->WriteStencil) - WriteStencil(y, x0, x1, thread); - } - else - { - uint8_t* discard = thread->scanline.discard; - while (x0 < x1) - { - int xstart = x0; - while (!discard[x0] && x0 < x1) x0++; - - if (xstart < x0) - { - if (thread->WriteColor) - thread->WriteColorFunc(y, xstart, x0, thread); - if (thread->WriteDepth) - WriteDepth(y, xstart, x0, thread); - if (thread->WriteStencil) - WriteStencil(y, xstart, x0, thread); - } - - while (discard[x0] && x0 < x1) x0++; - } - } -} - -template -static void TestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) -{ - WriteW(y, x0, x1, args, thread); - - if ((OptT::Flags & SWTRI_DepthTest) || (OptT::Flags & SWTRI_StencilTest)) - { - size_t pitch = thread->depthstencil->Width(); - - uint8_t* stencilbuffer; - uint8_t* stencilLine; - uint8_t stencilTestValue; - if (OptT::Flags & SWTRI_StencilTest) - { - stencilbuffer = thread->depthstencil->StencilValues(); - stencilLine = stencilbuffer + pitch * y; - stencilTestValue = thread->StencilTestValue; - } - - float* zbuffer; - float* zbufferLine; - float* w; - float depthbias; - if (OptT::Flags & SWTRI_DepthTest) - { - zbuffer = thread->depthstencil->DepthValues(); - zbufferLine = zbuffer + pitch * y; - w = thread->scanline.W; - depthbias = thread->depthbias; - } - - int x = x0; - int xend = x1; - while (x < xend) - { - int xstart = x; - - if ((OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_StencilTest)) - { - while (zbufferLine[x] >= w[x] + depthbias && stencilLine[x] == stencilTestValue && x < xend) - x++; - } - else if (OptT::Flags & SWTRI_DepthTest) - { - while (zbufferLine[x] >= w[x] + depthbias && x < xend) - x++; - } - else if (OptT::Flags & SWTRI_StencilTest) - { - while (stencilLine[x] == stencilTestValue && x < xend) - x++; - } - else - { - x = xend; - } - - if (x > xstart) - { - DrawSpan(y, xstart, x, args, thread); - } - - if ((OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_StencilTest)) - { - while ((zbufferLine[x] < w[x] + depthbias || stencilLine[x] != stencilTestValue) && x < xend) - x++; - } - else if (OptT::Flags & SWTRI_DepthTest) - { - while (zbufferLine[x] < w[x] + depthbias && x < xend) - x++; - } - else if (OptT::Flags & SWTRI_StencilTest) - { - while (stencilLine[x] != stencilTestValue && x < xend) - x++; - } - } - } - else - { - DrawSpan(y, x0, x1, args, thread); - } -} - -static void SortVertices(const TriDrawTriangleArgs* args, ScreenTriVertex** sortedVertices) -{ - sortedVertices[0] = args->v1; - sortedVertices[1] = args->v2; - sortedVertices[2] = args->v3; - - if (sortedVertices[1]->y < sortedVertices[0]->y) - std::swap(sortedVertices[0], sortedVertices[1]); - if (sortedVertices[2]->y < sortedVertices[0]->y) - std::swap(sortedVertices[0], sortedVertices[2]); - if (sortedVertices[2]->y < sortedVertices[1]->y) - std::swap(sortedVertices[1], sortedVertices[2]); -} - -void ScreenTriangle::Draw(const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) -{ - // Sort vertices by Y position - ScreenTriVertex* sortedVertices[3]; - SortVertices(args, sortedVertices); - - int clipleft = thread->clip.left; - int cliptop = MAX(thread->clip.top, thread->numa_start_y); - int clipright = thread->clip.right; - int clipbottom = MIN(thread->clip.bottom, thread->numa_end_y); - - int topY = (int)(sortedVertices[0]->y + 0.5f); - int midY = (int)(sortedVertices[1]->y + 0.5f); - int bottomY = (int)(sortedVertices[2]->y + 0.5f); - - topY = MAX(topY, cliptop); - midY = MIN(midY, clipbottom); - bottomY = MIN(bottomY, clipbottom); - - if (topY >= bottomY) - return; - - SelectFragmentShader(thread); - SelectWriteColorFunc(thread); - - void(*testfunc)(int y, int x0, int x1, const TriDrawTriangleArgs * args, PolyTriangleThreadData * thread); - - int opt = 0; - if (thread->DepthTest) opt |= SWTRI_DepthTest; - if (thread->StencilTest) opt |= SWTRI_StencilTest; - testfunc = ScreenTriangle::TestSpanOpts[opt]; - - topY += thread->skipped_by_thread(topY); - int num_cores = thread->num_cores; - - // Find start/end X positions for each line covered by the triangle: - - int y = topY; - - float longDX = sortedVertices[2]->x - sortedVertices[0]->x; - float longDY = sortedVertices[2]->y - sortedVertices[0]->y; - float longStep = longDX / longDY; - float longPos = sortedVertices[0]->x + longStep * (y + 0.5f - sortedVertices[0]->y) + 0.5f; - longStep *= num_cores; - - if (y < midY) - { - float shortDX = sortedVertices[1]->x - sortedVertices[0]->x; - float shortDY = sortedVertices[1]->y - sortedVertices[0]->y; - float shortStep = shortDX / shortDY; - float shortPos = sortedVertices[0]->x + shortStep * (y + 0.5f - sortedVertices[0]->y) + 0.5f; - shortStep *= num_cores; - - while (y < midY) - { - int x0 = (int)shortPos; - int x1 = (int)longPos; - if (x1 < x0) std::swap(x0, x1); - x0 = clamp(x0, clipleft, clipright); - x1 = clamp(x1, clipleft, clipright); - - testfunc(y, x0, x1, args, thread); - - shortPos += shortStep; - longPos += longStep; - y += num_cores; - } - } - - if (y < bottomY) - { - float shortDX = sortedVertices[2]->x - sortedVertices[1]->x; - float shortDY = sortedVertices[2]->y - sortedVertices[1]->y; - float shortStep = shortDX / shortDY; - float shortPos = sortedVertices[1]->x + shortStep * (y + 0.5f - sortedVertices[1]->y) + 0.5f; - shortStep *= num_cores; - - while (y < bottomY) - { - int x0 = (int)shortPos; - int x1 = (int)longPos; - if (x1 < x0) std::swap(x0, x1); - x0 = clamp(x0, clipleft, clipright); - x1 = clamp(x1, clipleft, clipright); - - testfunc(y, x0, x1, args, thread); - - shortPos += shortStep; - longPos += longStep; - y += num_cores; - } - } -} - -void(*ScreenTriangle::TestSpanOpts[])(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) = -{ - &TestSpan, - &TestSpan, - &TestSpan, - &TestSpan -}; diff --git a/src/rendering/polyrenderer/drawers/screen_triangle.h b/src/rendering/polyrenderer/drawers/screen_triangle.h deleted file mode 100644 index 40674ab1431..00000000000 --- a/src/rendering/polyrenderer/drawers/screen_triangle.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#pragma once - -#include -#include -#include "r_data/renderstyle.h" -#include "rendering/swrenderer/drawers/r_draw.h" - -class FString; -class PolyTriangleThreadData; - -struct ScreenTriVertex -{ - float x, y, z, w; - float u, v; - float worldX, worldY, worldZ; - float a, r, g, b; - float gradientdistZ; -}; - -struct ScreenTriangleStepVariables -{ - float W, U, V; - float WorldX, WorldY, WorldZ; - float A, R, G, B; - float GradientdistZ; -}; - -struct TriDrawTriangleArgs -{ - ScreenTriVertex *v1; - ScreenTriVertex *v2; - ScreenTriVertex *v3; - ScreenTriangleStepVariables gradientX; - ScreenTriangleStepVariables gradientY; - - bool CalculateGradients() - { - float bottomX = (v2->x - v3->x) * (v1->y - v3->y) - (v1->x - v3->x) * (v2->y - v3->y); - float bottomY = (v1->x - v3->x) * (v2->y - v3->y) - (v2->x - v3->x) * (v1->y - v3->y); - if ((bottomX >= -FLT_EPSILON && bottomX <= FLT_EPSILON) || (bottomY >= -FLT_EPSILON && bottomY <= FLT_EPSILON)) - return false; - - gradientX.W = FindGradientX(bottomX, 1.0f, 1.0f, 1.0f); - gradientX.U = FindGradientX(bottomX, v1->u, v2->u, v3->u); - gradientX.V = FindGradientX(bottomX, v1->v, v2->v, v3->v); - gradientX.WorldX = FindGradientX(bottomX, v1->worldX, v2->worldX, v3->worldX); - gradientX.WorldY = FindGradientX(bottomX, v1->worldY, v2->worldY, v3->worldY); - gradientX.WorldZ = FindGradientX(bottomX, v1->worldZ, v2->worldZ, v3->worldZ); - gradientX.A = FindGradientX(bottomX, v1->a, v2->a, v3->a); - gradientX.R = FindGradientX(bottomX, v1->r, v2->r, v3->r); - gradientX.G = FindGradientX(bottomX, v1->g, v2->g, v3->g); - gradientX.B = FindGradientX(bottomX, v1->b, v2->b, v3->b); - gradientX.GradientdistZ = FindGradientX(bottomX, v1->gradientdistZ, v2->gradientdistZ, v3->gradientdistZ); - - gradientY.W = FindGradientY(bottomY, 1.0f, 1.0f, 1.0f); - gradientY.U = FindGradientY(bottomY, v1->u, v2->u, v3->u); - gradientY.V = FindGradientY(bottomY, v1->v, v2->v, v3->v); - gradientY.WorldX = FindGradientY(bottomY, v1->worldX, v2->worldX, v3->worldX); - gradientY.WorldY = FindGradientY(bottomY, v1->worldY, v2->worldY, v3->worldY); - gradientY.WorldZ = FindGradientY(bottomY, v1->worldZ, v2->worldZ, v3->worldZ); - gradientY.A = FindGradientY(bottomY, v1->a, v2->a, v3->a); - gradientY.R = FindGradientY(bottomY, v1->r, v2->r, v3->r); - gradientY.G = FindGradientY(bottomY, v1->g, v2->g, v3->g); - gradientY.B = FindGradientY(bottomY, v1->b, v2->b, v3->b); - gradientY.GradientdistZ = FindGradientY(bottomY, v1->gradientdistZ, v2->gradientdistZ, v3->gradientdistZ); - - return true; - } - -private: - float FindGradientX(float bottomX, float c0, float c1, float c2) - { - c0 *= v1->w; - c1 *= v2->w; - c2 *= v3->w; - return ((c1 - c2) * (v1->y - v3->y) - (c0 - c2) * (v2->y - v3->y)) / bottomX; - } - - float FindGradientY(float bottomY, float c0, float c1, float c2) - { - c0 *= v1->w; - c1 *= v2->w; - c2 *= v3->w; - return ((c1 - c2) * (v1->x - v3->x) - (c0 - c2) * (v2->x - v3->x)) / bottomY; - } -}; - -class ScreenTriangle -{ -public: - static void Draw(const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread); - -private: - static void(*TestSpanOpts[])(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread); -}; - -enum SWTestSpan -{ - SWTRI_DepthTest = 1, - SWTRI_StencilTest = 2 -}; - -struct TestSpanOpt0 { static const int Flags = 0; }; -struct TestSpanOpt1 { static const int Flags = 1; }; -struct TestSpanOpt2 { static const int Flags = 2; }; -struct TestSpanOpt3 { static const int Flags = 3; }; diff --git a/src/rendering/polyrenderer/poly_all.cpp b/src/rendering/polyrenderer/poly_all.cpp deleted file mode 100644 index 97fda79d1a8..00000000000 --- a/src/rendering/polyrenderer/poly_all.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "../swrenderer/textures/r_swtexture.h" -#include "drawers/poly_triangle.cpp" -#include "drawers/poly_thread.cpp" -#include "drawers/screen_triangle.cpp" -#include "drawers/screen_scanline_setup.cpp" -#include "drawers/screen_shader.cpp" -#include "drawers/screen_blend.cpp" diff --git a/src/rendering/r_sky.cpp b/src/rendering/r_sky.cpp index 1c34c9c32d3..4d9e2a5cf46 100644 --- a/src/rendering/r_sky.cpp +++ b/src/rendering/r_sky.cpp @@ -38,6 +38,9 @@ #include "r_utility.h" #include "v_text.h" #include "g_levellocals.h" +#include "texturemanager.h" +#include "palentry.h" +#include "bitmap.h" // // sky mapping @@ -51,8 +54,6 @@ CUSTOM_CVAR (Int, r_skymode, 2, CVAR_ARCHIVE|CVAR_NOINITCALL) R_InitSkyMap (); } -CVAR(Float, skyoffset, 0, 0) // for testing - //========================================================================== // // R_InitSkyMap @@ -63,8 +64,7 @@ CVAR(Float, skyoffset, 0, 0) // for testing void InitSkyMap(FLevelLocals *Level) { - int skyheight; - FTexture *skytex1, *skytex2; + FGameTexture *skytex1, *skytex2; // Do not allow the null texture which has no bitmap and will crash. if (Level->skytexture1.isNull()) @@ -75,11 +75,15 @@ void InitSkyMap(FLevelLocals *Level) { Level->skytexture2 = TexMan.CheckForTexture("-noflat-", ETextureType::Any); } + if (Level->flags & LEVEL_DOUBLESKY) + { + Level->skytexture1 = TexMan.GetFrontSkyLayer(Level->skytexture1); + } - skytex1 = TexMan.GetTexture(Level->skytexture1, false); - skytex2 = TexMan.GetTexture(Level->skytexture2, false); + skytex1 = TexMan.GetGameTexture(Level->skytexture1, false); + skytex2 = TexMan.GetGameTexture(Level->skytexture2, false); - if (skytex1 == nullptr) + if (skytex1 == nullptr || skytex2 == nullptr) return; if ((Level->flags & LEVEL_DOUBLESKY) && skytex1->GetDisplayHeight() != skytex2->GetDisplayHeight()) @@ -102,7 +106,7 @@ void InitSkyMap(FLevelLocals *Level) // the screen when looking fully up. // h > 200: Unstretched, but the baseline is shifted down so that the top // of the texture is at the top of the screen when looking fully up. - skyheight = skytex1->GetDisplayHeight(); + auto skyheight = skytex1->GetDisplayHeight(); Level->skystretch = (r_skymode == 1 && skyheight >= 128 && skyheight <= 256 diff --git a/src/rendering/r_sky.h b/src/rendering/r_sky.h index 9d80740c95a..5d7236dc811 100644 --- a/src/rendering/r_sky.h +++ b/src/rendering/r_sky.h @@ -28,7 +28,9 @@ #ifndef __R_SKY_H__ #define __R_SKY_H__ -#include "textures/textures.h" +#include +#include +#include "textureid.h" struct FLevelLocals; @@ -42,11 +44,5 @@ void InitSkyMap(FLevelLocals *Level); void R_InitSkyMap(); void R_UpdateSky (uint64_t mstime); -// 57 world units roughly represent one sky texel for the glTranslate call. -enum -{ - skyoffsetfactor = 57 -}; - #endif //__R_SKY_H__ diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index 3445c7ac38b..3e40c3a0c60 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -32,7 +32,7 @@ #include #include -#include "templates.h" + #include "doomdef.h" #include "d_net.h" #include "doomstat.h" @@ -64,7 +64,11 @@ #include "actorinlines.h" #include "g_game.h" #include "i_system.h" +#include "v_draw.h" +#include "i_interface.h" +#include "d_main.h" +const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2) // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern bool DrawFSHUD; // [RH] Defined in d_main.cpp @@ -76,12 +80,15 @@ struct InterpolationViewer { struct instance { - DVector3 Pos; + DVector3 Pos, ViewPos; DRotator Angles; + DRotator ViewAngles; }; - AActor *ViewActor; - int otic; + AActor* ViewActor; + DVector3 ViewOffset, RelativeViewOffset; // This has to be a separate field since it needs the real-time mouse angles. + DRotator AngleOffsets; + int prevTic; instance Old, New; }; @@ -98,12 +105,43 @@ CVAR (Bool, r_deathcamera, false, CVAR_ARCHIVE) CVAR (Int, r_clearbuffer, 0, 0) CVAR (Bool, r_drawvoxels, true, 0) CVAR (Bool, r_drawplayersprites, true, 0) // [RH] Draw player sprites? +CVARD (Bool, r_radarclipper, false, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "Use the horizontal clipper from camera->tracer's perspective") +CVARD (Bool, r_dithertransparency, false, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "Use dithered-transparency shading for actor-occluding level geometry") CUSTOM_CVAR(Float, r_quakeintensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (self < 0.f) self = 0.f; else if (self > 1.f) self = 1.f; } +CUSTOM_CVARD(Int, r_actorspriteshadow, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "render actor sprite shadows. 0 = off, 1 = default, 2 = always on") +{ + if (self < 0) + self = 0; + else if (self > 2) + self = 2; +} +CUSTOM_CVARD(Float, r_actorspriteshadowdist, 1500.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "how far sprite shadows should be rendered") +{ + if (self < 0.f) + self = 0.f; + else if (self > 8192.f) + self = 8192.f; +} +CUSTOM_CVARD(Float, r_actorspriteshadowalpha, 0.5, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "maximum sprite shadow opacity, only effective with hardware renderers (0.0 = fully transparent, 1.0 = opaque)") +{ + if (self < 0.f) + self = 0.f; + else if (self > 1.f) + self = 1.f; +} +CUSTOM_CVARD(Float, r_actorspriteshadowfadeheight, 0.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "distance over which sprite shadows should fade, only effective with hardware renderers (0 = infinite)") +{ + if (self < 0.f) + self = 0.f; + else if (self > 8192.f) + self = 8192.f; +} + int viewwindowx; int viewwindowy; int viewwidth; @@ -114,16 +152,21 @@ FRenderViewpoint::FRenderViewpoint() player = nullptr; Pos = { 0.0, 0.0, 0.0 }; ActorPos = { 0.0, 0.0, 0.0 }; - Angles = { 0.0, 0.0, 0.0 }; + Angles = { nullAngle, nullAngle, nullAngle }; Path[0] = { 0.0, 0.0, 0.0 }; Path[1] = { 0.0, 0.0, 0.0 }; Cos = 0.0; Sin = 0.0; TanCos = 0.0; TanSin = 0.0; + PitchCos = 0.0; + PitchSin = 0.0; + floordistfact = 0.0; + cotfloor = 0.0; camera = nullptr; sector = nullptr; - FieldOfView = 90.; // Angles in the SCREENWIDTH wide window + FieldOfView = DAngle::fromDeg(90.); // Angles in the SCREENWIDTH wide window + ScreenProj = 0.0; TicFrac = 0.0; FrameTime = 0; extralight = 0; @@ -140,7 +183,6 @@ int LocalViewPitch; bool LocalKeyboardTurner; int setblocks; -bool setsizeneeded; unsigned int R_OldBlend = ~0; int validcount = 1; // increment every time a check is made @@ -165,8 +207,8 @@ DEFINE_GLOBAL(LocalViewPitch); void R_SetFOV (FRenderViewpoint &viewpoint, DAngle fov) { - if (fov < 5.) fov = 5.; - else if (fov > 170.) fov = 170.; + if (fov < DAngle::fromDeg(5.)) fov = DAngle::fromDeg(5.); + else if (fov > DAngle::fromDeg(170.)) fov = DAngle::fromDeg(170.); if (fov != viewpoint.FieldOfView) { viewpoint.FieldOfView = fov; @@ -247,8 +289,8 @@ void R_SetWindow (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, int wind // screen that would be visible on a 4:3 display has the requested FOV. if (viewwindow.centerxwide != viewwindow.centerx) { // centerxwide is what centerx would be if the display was not widescreen - fov = DAngle::ToDegrees(2 * atan(viewwindow.centerx * tan(fov.Radians()/2) / double(viewwindow.centerxwide))); - if (fov > 170.) fov = 170.; + fov = DAngle::fromRad(2 * atan(viewwindow.centerx * tan(fov.Radians()/2) / double(viewwindow.centerxwide))); + if (fov > DAngle::fromDeg(170.)) fov = DAngle::fromDeg(170.); } viewwindow.FocalTangent = tan(fov.Radians() / 2); } @@ -368,7 +410,7 @@ CUSTOM_CVAR (Int, screenblocks, 10, CVAR_ARCHIVE) //========================================================================== FRenderer *CreateSWRenderer(); - +FRenderer* SWRenderer; //========================================================================== // @@ -378,7 +420,6 @@ FRenderer *CreateSWRenderer(); void R_Init () { - StartScreen->Progress(); R_InitTranslationTables (); R_SetViewSize (screenblocks); @@ -404,155 +445,224 @@ void R_Shutdown () //========================================================================== // -// R_InterpolateView +// P_NoInterpolation // //========================================================================== //CVAR (Int, tf, 0, 0) -EXTERN_CVAR (Bool, cl_noprediction) -void R_InterpolateView (FRenderViewpoint &viewpoint, player_t *player, double Frac, InterpolationViewer *iview) +bool P_NoInterpolation(player_t const *player, AActor const *actor) +{ + return player != nullptr + && !(player->cheats & CF_INTERPVIEW) + && player - players == consoleplayer + && actor == player->mo + && !demoplayback + && !(player->cheats & (CF_TOTALLYFROZEN | CF_FROZEN)) + && player->playerstate == PST_LIVE + && player->mo->reactiontime == 0 + && !NoInterpolateView + && !paused + && !LocalKeyboardTurner; +} + +//========================================================================== +// +// R_InterpolateView +// +//========================================================================== + +void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player, const double ticFrac, InterpolationViewer* const iView) { if (NoInterpolateView) { InterpolationPath.Clear(); NoInterpolateView = false; - iview->Old = iview->New; + iView->Old = iView->New; } - auto Level = viewpoint.ViewLevel; - int oldgroup = Level->PointInRenderSubsector(iview->Old.Pos)->sector->PortalGroup; - int newgroup = Level->PointInRenderSubsector(iview->New.Pos)->sector->PortalGroup; - DAngle oviewangle = iview->Old.Angles.Yaw; - DAngle nviewangle = iview->New.Angles.Yaw; + const double inverseTicFrac = 1.0 - ticFrac; + const auto viewLvl = viewPoint.ViewLevel; + + DAngle prevYaw = iView->Old.Angles.Yaw; + DAngle curYaw = iView->New.Angles.Yaw; if (!cl_capfps) { - if ((iview->Old.Pos.X != iview->New.Pos.X || iview->Old.Pos.Y != iview->New.Pos.Y) && InterpolationPath.Size() > 0) + if ((iView->Old.Pos.X != iView->New.Pos.X || iView->Old.Pos.Y != iView->New.Pos.Y) && InterpolationPath.Size() > 0) { - DVector3 view = iview->New.Pos; - // Interpolating through line portals is a messy affair. // What needs be done is to store the portal transitions of the camera actor as waypoints // and then find out on which part of the path the current view lies. - // Needless to say, this doesn't work for chasecam mode. - if (!viewpoint.showviewer) + double totalPathLength = 0.0; + double totalZDiff = 0.0; + DAngle totalYawDiff = nullAngle; + DVector3a oldPos = { { iView->Old.Pos.X, iView->Old.Pos.Y, 0.0 }, nullAngle }; + DVector3a newPos = { { iView->New.Pos.X, iView->New.Pos.Y, 0.0 }, nullAngle }; + InterpolationPath.Push(newPos); // Add this to the array to simplify the loops below. + + for (size_t i = 0u; i < InterpolationPath.Size(); i += 2u) + { + const DVector3a& start = !i ? oldPos : InterpolationPath[i - 1u]; + const DVector3a& end = InterpolationPath[i]; + totalPathLength += (end.pos - start.pos).Length(); + totalZDiff += start.pos.Z; + totalYawDiff += start.angle; + } + + double interpolatedLength = totalPathLength * ticFrac; + double zDiff = 0.0; + DAngle yawDiff = nullAngle; + double prevViewZ = iView->Old.Pos.Z; + double curViewZ = iView->New.Pos.Z; + for (size_t i = 0u; i < InterpolationPath.Size(); i += 2u) { - double pathlen = 0; - double zdiff = 0; - double totalzdiff = 0; - DAngle adiff = 0.; - DAngle totaladiff = 0.; - double oviewz = iview->Old.Pos.Z; - double nviewz = iview->New.Pos.Z; - DVector3a oldpos = { { iview->Old.Pos.X, iview->Old.Pos.Y, 0 }, 0. }; - DVector3a newpos = { { iview->New.Pos.X, iview->New.Pos.Y, 0 }, 0. }; - InterpolationPath.Push(newpos); // add this to the array to simplify the loops below - - for (unsigned i = 0; i < InterpolationPath.Size(); i += 2) + const DVector3a& start = !i ? oldPos : InterpolationPath[i - 1u]; + const DVector3a& end = InterpolationPath[i]; + const double fragmentLength = (end.pos - start.pos).Length(); + zDiff += start.pos.Z; + yawDiff += start.angle; + + if (fragmentLength <= interpolatedLength) { - DVector3a &start = i == 0 ? oldpos : InterpolationPath[i - 1]; - DVector3a &end = InterpolationPath[i]; - pathlen += (end.pos - start.pos).Length(); - totalzdiff += start.pos.Z; - totaladiff += start.angle; + interpolatedLength -= fragmentLength; } - double interpolatedlen = Frac * pathlen; - - for (unsigned i = 0; i < InterpolationPath.Size(); i += 2) + else { - DVector3a &start = i == 0 ? oldpos : InterpolationPath[i - 1]; - DVector3a &end = InterpolationPath[i]; - double fraglen = (end.pos - start.pos).Length(); - zdiff += start.pos.Z; - adiff += start.angle; - if (fraglen <= interpolatedlen) - { - interpolatedlen -= fraglen; - } - else - { - double fragfrac = interpolatedlen / fraglen; - oviewz += zdiff; - nviewz -= totalzdiff - zdiff; - oviewangle += adiff; - nviewangle -= totaladiff - adiff; - DVector2 viewpos = start.pos + (fragfrac * (end.pos - start.pos)); - viewpoint.Pos = { viewpos, oviewz + Frac * (nviewz - oviewz) }; - break; - } + prevViewZ += zDiff; + curViewZ -= totalZDiff - zDiff; + prevYaw += yawDiff; + curYaw -= totalYawDiff - yawDiff; + + const DVector2 viewPos = start.pos.XY() + ((interpolatedLength / fragmentLength) * (end.pos - start.pos).XY()); + viewPoint.Pos = { viewPos, prevViewZ * inverseTicFrac + curViewZ * ticFrac }; + break; } - InterpolationPath.Pop(); - viewpoint.Path[0] = iview->Old.Pos; - viewpoint.Path[1] = viewpoint.Path[0] + (InterpolationPath[0].pos - viewpoint.Path[0]).XY().MakeResize(pathlen); } + + InterpolationPath.Pop(); + viewPoint.Path[0] = iView->Old.Pos; + viewPoint.Path[1] = viewPoint.Path[0] + (InterpolationPath[0].pos - viewPoint.Path[0]).XY().MakeResize(totalPathLength); } else { - DVector2 disp = viewpoint.ViewLevel->Displacements.getOffset(oldgroup, newgroup); - viewpoint.Pos = iview->Old.Pos + (iview->New.Pos - iview->Old.Pos - disp) * Frac; - viewpoint.Path[0] = viewpoint.Path[1] = iview->New.Pos; + const int prevPortalGroup = viewLvl->PointInRenderSubsector(iView->Old.Pos)->sector->PortalGroup; + const int curPortalGroup = viewLvl->PointInRenderSubsector(iView->New.Pos)->sector->PortalGroup; + + const DVector2 portalOffset = viewLvl->Displacements.getOffset(prevPortalGroup, curPortalGroup); + viewPoint.Pos = iView->Old.Pos * inverseTicFrac + (iView->New.Pos - portalOffset) * ticFrac; + viewPoint.Path[0] = viewPoint.Path[1] = iView->New.Pos; } } else { - viewpoint.Pos = iview->New.Pos; - viewpoint.Path[0] = viewpoint.Path[1] = iview->New.Pos; + viewPoint.Pos = iView->New.Pos; + viewPoint.Path[0] = viewPoint.Path[1] = iView->New.Pos; + } + + // Due to interpolation this is not necessarily the same as the sector the camera is in. + viewPoint.sector = viewLvl->PointInRenderSubsector(viewPoint.Pos)->sector; + if (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer()) + { + bool moved = false; + while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling)) + { + if (viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling)) + { + const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::ceiling); + viewPoint.Pos += offset; + viewPoint.ActorPos += offset; + viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination; + moved = true; + } + else + { + break; + } + } + + if (!moved) + { + while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor)) + { + if (viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor)) + { + const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::floor); + viewPoint.Pos += offset; + viewPoint.ActorPos += offset; + viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination; + } + else + { + break; + } + } + } } - if (player != NULL && - !(player->cheats & CF_INTERPVIEW) && - player - players == consoleplayer && - viewpoint.camera == player->mo && - !demoplayback && - iview->New.Pos.X == viewpoint.camera->X() && - iview->New.Pos.Y == viewpoint.camera->Y() && - !(player->cheats & (CF_TOTALLYFROZEN|CF_FROZEN)) && - player->playerstate == PST_LIVE && - player->mo->reactiontime == 0 && - !NoInterpolateView && - !paused && - (!netgame || !cl_noprediction) && - !LocalKeyboardTurner) + + if (P_NoInterpolation(player, viewPoint.camera)) { - viewpoint.Angles.Yaw = (nviewangle + AngleToFloat(LocalViewAngle & 0xFFFF0000)).Normalized180(); - DAngle delta = player->centering ? DAngle(0.) : AngleToFloat(int(LocalViewPitch & 0xFFFF0000)); - viewpoint.Angles.Pitch = clamp((iview->New.Angles.Pitch - delta).Normalized180(), player->MinPitch, player->MaxPitch); - viewpoint.Angles.Roll = iview->New.Angles.Roll.Normalized180(); + viewPoint.Angles.Yaw = curYaw + DAngle::fromBam(LocalViewAngle); + const DAngle delta = player->centering ? nullAngle : DAngle::fromBam(LocalViewPitch); + viewPoint.Angles.Pitch = clamp((iView->New.Angles.Pitch - delta).Normalized180(), player->MinPitch, player->MaxPitch); + viewPoint.Angles.Roll = iView->New.Angles.Roll; } else { - viewpoint.Angles.Pitch = (iview->Old.Angles.Pitch + deltaangle(iview->Old.Angles.Pitch, iview->New.Angles.Pitch) * Frac).Normalized180(); - viewpoint.Angles.Yaw = (oviewangle + deltaangle(oviewangle, nviewangle) * Frac).Normalized180(); - viewpoint.Angles.Roll = (iview->Old.Angles.Roll + deltaangle(iview->Old.Angles.Roll, iview->New.Angles.Roll) * Frac).Normalized180(); + viewPoint.Angles.Pitch = iView->Old.Angles.Pitch + deltaangle(iView->Old.Angles.Pitch, iView->New.Angles.Pitch) * ticFrac; + viewPoint.Angles.Yaw = prevYaw + deltaangle(prevYaw, curYaw) * ticFrac; + viewPoint.Angles.Roll = iView->Old.Angles.Roll + deltaangle(iView->Old.Angles.Roll, iView->New.Angles.Roll) * ticFrac; } - - // Due to interpolation this is not necessarily the same as the sector the camera is in. - viewpoint.sector = Level->PointInRenderSubsector(viewpoint.Pos)->sector; - bool moved = false; - while (!viewpoint.sector->PortalBlocksMovement(sector_t::ceiling)) + + // Now that the base position and angles are set, add offsets. + + const DViewPosition* const vPos = iView->ViewActor->ViewPos; + if (vPos != nullptr && !(vPos->Flags & VPSF_ABSOLUTEPOS) + && (player == nullptr || gamestate == GS_TITLELEVEL || (!(player->cheats & CF_CHASECAM) && (!r_deathcamera || !(iView->ViewActor->flags6 & MF6_KILLED))))) { - if (viewpoint.Pos.Z > viewpoint.sector->GetPortalPlaneZ(sector_t::ceiling)) - { - viewpoint.Pos += viewpoint.sector->GetPortalDisplacement(sector_t::ceiling); - viewpoint.ActorPos += viewpoint.sector->GetPortalDisplacement(sector_t::ceiling); - viewpoint.sector = Level->PointInRenderSubsector(viewpoint.Pos)->sector; - moved = true; - } - else break; + DVector3 vOfs = {}; + if (player == nullptr || !(player->cheats & CF_NOVIEWPOSINTERP)) + vOfs = iView->Old.ViewPos * inverseTicFrac + iView->New.ViewPos * ticFrac; + else + vOfs = iView->New.ViewPos; + + if (vPos->Flags & VPSF_ABSOLUTEOFFSET) + iView->ViewOffset += vOfs; + else + iView->RelativeViewOffset += vOfs; } - if (!moved) + + DVector3 posOfs = iView->ViewOffset; + if (!iView->RelativeViewOffset.isZero()) + posOfs += DQuaternion::FromAngles(viewPoint.Angles.Yaw, viewPoint.Angles.Pitch, viewPoint.Angles.Roll) * iView->RelativeViewOffset; + + // Now that we have the current interpolated position, offset from that directly (for view offset + chase cam). + if (!posOfs.isZero()) { - while (!viewpoint.sector->PortalBlocksMovement(sector_t::floor)) + const double distance = posOfs.Length(); + posOfs /= distance; + R_OffsetView(viewPoint, posOfs, distance); + } + + viewPoint.Angles += iView->AngleOffsets; + + // [MR] Apply the view angles as an offset if ABSVIEWANGLES isn't specified. + if (!(viewPoint.camera->flags8 & MF8_ABSVIEWANGLES)) + { + if (player == nullptr || (player->cheats & CF_INTERPVIEWANGLES)) { - if (viewpoint.Pos.Z < viewpoint.sector->GetPortalPlaneZ(sector_t::floor)) - { - viewpoint.Pos += viewpoint.sector->GetPortalDisplacement(sector_t::floor); - viewpoint.ActorPos += viewpoint.sector->GetPortalDisplacement(sector_t::floor); - viewpoint.sector = Level->PointInRenderSubsector(viewpoint.Pos)->sector; - moved = true; - } - else break; + viewPoint.Angles.Yaw += iView->Old.ViewAngles.Yaw + deltaangle(iView->Old.ViewAngles.Yaw, iView->New.ViewAngles.Yaw) * ticFrac; + viewPoint.Angles.Pitch += iView->Old.ViewAngles.Pitch + deltaangle(iView->Old.ViewAngles.Pitch, iView->New.ViewAngles.Pitch) * ticFrac; + viewPoint.Angles.Roll += iView->Old.ViewAngles.Roll + deltaangle(iView->Old.ViewAngles.Roll, iView->New.ViewAngles.Roll) * ticFrac; + } + else + { + viewPoint.Angles += iView->New.ViewAngles; } } + + viewPoint.Angles.Yaw = viewPoint.Angles.Yaw.Normalized180(); + viewPoint.Angles.Pitch = viewPoint.Angles.Pitch.Normalized180(); + viewPoint.Angles.Roll = viewPoint.Angles.Roll.Normalized180(); } //========================================================================== @@ -569,24 +679,59 @@ void R_ResetViewInterpolation () //========================================================================== // -// R_SetViewAngle -// sets all values derived from the view angle. +// R_SetViewAngle +// sets all values derived from the view yaw. // //========================================================================== -void FRenderViewpoint::SetViewAngle (const FViewWindow &viewwindow) +void FRenderViewpoint::SetViewAngle(const FViewWindow& viewWindow) { Sin = Angles.Yaw.Sin(); Cos = Angles.Yaw.Cos(); - TanSin = viewwindow.FocalTangent * Sin; - TanCos = viewwindow.FocalTangent * Cos; + TanSin = viewWindow.FocalTangent * Sin; + TanCos = viewWindow.FocalTangent * Cos; + + PitchSin = Angles.Pitch.Sin(); + PitchCos = Angles.Pitch.Cos(); + + floordistfact = MY_SQRT2 + ( fabs(Cos) > fabs(Sin) ? 1.0/fabs(Cos) : 1.0/fabs(Sin) ); + cotfloor = ( fabs(Cos) > fabs(Sin) ? fabs(Sin/Cos) : fabs(Cos/Sin) ); - DVector2 v = Angles.Yaw.ToVector(); + const DVector2 v = Angles.Yaw.ToVector(); ViewVector.X = v.X; ViewVector.Y = v.Y; - HWAngles.Yaw = float(270.0 - Angles.Yaw.Degrees); + HWAngles.Yaw = FAngle::fromDeg(270.0 - Angles.Yaw.Degrees()); + + if (IsOrtho() && (camera->ViewPos->Offset.XY().Length() > 0.0)) + ScreenProj = 1.34396 / camera->ViewPos->Offset.Length(); // [DVR] Estimated. +/-1 should be top/bottom of screen. + +} + +//========================================================================== +// +// R_IsAllowedOoB() +// Checks if camera actor exists, has viewpos, +// and viewpos has VPSF_ALLOWOUTOFBOUNDS flag set. +// +//========================================================================== + +bool FRenderViewpoint::IsAllowedOoB() +{ + return (camera && camera->ViewPos && (camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS)); +} +//========================================================================== +// +// R_IsOrtho() +// Checks if camera actor exists, has viewpos, +// and viewpos has VPSF_ORTHOGRAPHIC flag set. +// +//========================================================================== + +bool FRenderViewpoint::IsOrtho() +{ + return (camera && camera->ViewPos && (camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC)); } //========================================================================== @@ -609,7 +754,7 @@ static InterpolationViewer *FindPastViewer (AActor *actor) InterpolationViewer iview; memset(&iview, 0, sizeof(iview)); iview.ViewActor = actor; - iview.otic = -1; + iview.prevTic = -1; InterpolationPath.Clear(); return &PastViewers[PastViewers.Push (iview)]; } @@ -731,271 +876,281 @@ static double QuakePower(double factor, double intensity, double offset) //========================================================================== // -// R_SetupFrame +// R_DoActorTickerAngleChanges // //========================================================================== -void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor *actor) +static void R_DoActorTickerAngleChanges(player_t* const player, DRotator& angles, const double scale) { - if (actor == NULL) + for (unsigned i = 0; i < 3; i++) { - I_Error ("Tried to render from a NULL actor."); + if (fabs(player->angleOffsetTargets[i].Degrees()) >= EQUAL_EPSILON) + angles[i] += player->angleOffsetTargets[i] * scale; } - viewpoint.ViewLevel = actor->Level; +} - player_t *player = actor->player; - unsigned int newblend; - InterpolationViewer *iview; - bool unlinked = false; +//========================================================================== +// +// R_SetupFrame +// +//========================================================================== - if (player != NULL && player->mo == actor) - { // [RH] Use camera instead of viewplayer - viewpoint.camera = player->camera; - if (viewpoint.camera == NULL) - { - viewpoint.camera = player->camera = player->mo; - } - } - else - { - viewpoint.camera = actor; - } +EXTERN_CVAR(Float, chase_dist) +EXTERN_CVAR(Float, chase_height) - if (viewpoint.camera == NULL) - { - I_Error ("You lost your body. Bad dehacked work is likely to blame."); - } +void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AActor* const actor) +{ + viewPoint.TicFrac = I_GetTimeFrac(); + if (cl_capfps || r_NoInterpolate) + viewPoint.TicFrac = 1.0; - iview = FindPastViewer (viewpoint.camera); + const int curTic = I_GetTime(); - int nowtic = I_GetTime (); - if (iview->otic != -1 && nowtic > iview->otic) - { - iview->otic = nowtic; - iview->Old = iview->New; - } + if (actor == nullptr) + I_Error("Tried to render from a null actor."); - if (player != NULL && gamestate != GS_TITLELEVEL && - ((player->cheats & CF_CHASECAM) || (r_deathcamera && viewpoint.camera->health <= 0))) + viewPoint.ViewLevel = actor->Level; + + player_t* player = actor->player; + if (player != nullptr && player->mo == actor) { - sector_t *oldsector = viewpoint.ViewLevel->PointInRenderSubsector(iview->Old.Pos)->sector; - // [RH] Use chasecam view - DVector3 campos; - DAngle camangle; - P_AimCamera (viewpoint.camera, campos, camangle, viewpoint.sector, unlinked); // fixme: This needs to translate the angle, too. - iview->New.Pos = campos; - iview->New.Angles.Yaw = camangle; - - viewpoint.showviewer = true; - // Interpolating this is a very complicated thing because nothing keeps track of the aim camera's movement, so whenever we detect a portal transition - // it's probably best to just reset the interpolation for this move. - // Note that this can still cause problems with unusually linked portals - if (viewpoint.sector->PortalGroup != oldsector->PortalGroup || (unlinked && ((iview->New.Pos.XY() - iview->Old.Pos.XY()).LengthSquared()) > 256*256)) - { - iview->otic = nowtic; - iview->Old = iview->New; - r_NoInterpolate = true; - } - viewpoint.ActorPos = campos; + if (player->camera == nullptr) + player->camera = player->mo; + + viewPoint.camera = player->camera; // [RH] Use camera instead of view player. } else { - viewpoint.ActorPos = iview->New.Pos = { viewpoint.camera->Pos().XY(), viewpoint.camera->player ? viewpoint.camera->player->viewz : viewpoint.camera->Z() + viewpoint.camera->GetCameraHeight() }; - viewpoint.sector = viewpoint.camera->Sector; - viewpoint.showviewer = false; - } - iview->New.Angles = viewpoint.camera->Angles; - if (viewpoint.camera->player != 0) - { - player = viewpoint.camera->player; + viewPoint.camera = actor; } - if (iview->otic == -1 || r_NoInterpolate || (viewpoint.camera->renderflags & RF_NOINTERPOLATEVIEW)) - { - viewpoint.camera->renderflags &= ~RF_NOINTERPOLATEVIEW; - R_ResetViewInterpolation (); - iview->otic = nowtic; - } + if (viewPoint.camera == nullptr) + I_Error("You lost your body. Bad dehacked work is likely to blame."); - viewpoint.TicFrac = I_GetTimeFrac (); - if (cl_capfps || r_NoInterpolate) + InterpolationViewer* const iView = FindPastViewer(viewPoint.camera); + // Always reset these back to zero. + iView->ViewOffset.Zero(); + iView->RelativeViewOffset.Zero(); + iView->AngleOffsets.Zero(); + if (iView->prevTic != -1 && curTic > iView->prevTic) { - viewpoint.TicFrac = 1.; + iView->prevTic = curTic; + iView->Old = iView->New; } - R_InterpolateView (viewpoint, player, viewpoint.TicFrac, iview); - viewpoint.SetViewAngle (viewwindow); - - // Keep the view within the sector's floor and ceiling - if (viewpoint.sector->PortalBlocksMovement(sector_t::ceiling)) + const auto& mainView = r_viewpoint; + AActor* const client = players[consoleplayer].mo; + const bool matchPlayer = gamestate != GS_TITLELEVEL && viewPoint.camera->player == nullptr && (viewPoint.camera->renderflags2 & RF2_CAMFOLLOWSPLAYER); + const bool usePawn = matchPlayer ? mainView.camera != client : false; + //============================================================================================== + // Sets up the view position offset. { - double theZ = viewpoint.sector->ceilingplane.ZatPoint(viewpoint.Pos) - 4; - if (viewpoint.Pos.Z > theZ) + AActor* const mo = viewPoint.camera; + const DViewPosition* const viewOffset = mo->ViewPos; + DVector3 camPos; + if (matchPlayer) { - viewpoint.Pos.Z = theZ; + if (usePawn) + { + camPos = DVector3(client->Pos().XY(), client->player->viewz); + const DViewPosition* const pawnVP = client->ViewPos; + if (pawnVP != nullptr) + { + // Add these directly to the view position offset (not 100% accurate but close enough). + if (pawnVP->Flags & VPSF_ABSOLUTEPOS) + camPos = pawnVP->Offset; + else if (pawnVP->Flags & VPSF_ABSOLUTEOFFSET) + iView->ViewOffset = pawnVP->Offset; + else + iView->ViewOffset = DQuaternion::FromAngles(client->Angles.Yaw, client->Angles.Pitch, client->Angles.Roll) * pawnVP->Offset; + } + } + else + { + camPos = mainView.Pos; + } } - } - - if (viewpoint.sector->PortalBlocksMovement(sector_t::floor)) - { - double theZ = viewpoint.sector->floorplane.ZatPoint(viewpoint.Pos) + 4; - if (viewpoint.Pos.Z < theZ) + else { - viewpoint.Pos.Z = theZ; + camPos = { mo->Pos().XY(), mo->player != nullptr ? mo->player->viewz : mo->Z() + mo->GetCameraHeight() }; } - } - if (!paused) - { - FQuakeJiggers jiggers; + viewPoint.showviewer = false; + viewPoint.bForceNoViewer = matchPlayer; - memset(&jiggers, 0, sizeof(jiggers)); - if (DEarthquake::StaticGetQuakeIntensities(viewpoint.TicFrac, viewpoint.camera, jiggers) > 0) + if (player != nullptr && gamestate != GS_TITLELEVEL + && ((player->cheats & CF_CHASECAM) || (r_deathcamera && (viewPoint.camera->flags6 & MF6_KILLED)))) { - double quakefactor = r_quakeintensity; - DVector3 pos; pos.Zero(); - if (jiggers.RollIntensity != 0 || jiggers.RollWave != 0) - { - viewpoint.Angles.Roll += QuakePower(quakefactor, jiggers.RollIntensity, jiggers.RollWave); - } - if (jiggers.RelIntensity.X != 0 || jiggers.RelOffset.X != 0) - { - pos.X += QuakePower(quakefactor, jiggers.RelIntensity.X, jiggers.RelOffset.X); - } - if (jiggers.RelIntensity.Y != 0 || jiggers.RelOffset.Y != 0) - { - pos.Y += QuakePower(quakefactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y); - } - if (jiggers.RelIntensity.Z != 0 || jiggers.RelOffset.Z != 0) - { - pos.Z += QuakePower(quakefactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z); - } - // [MC] Tremendous thanks to Marisa Kirisame for helping me with this. - // Use a rotation matrix to make the view relative. - if (!pos.isZero()) - { - DAngle yaw = viewpoint.camera->Angles.Yaw; - DAngle pitch = viewpoint.camera->Angles.Pitch; - DAngle roll = viewpoint.camera->Angles.Roll; - DVector3 relx, rely, relz; - DMatrix3x3 rot = - DMatrix3x3(DVector3(0., 0., 1.), yaw.Cos(), yaw.Sin()) * - DMatrix3x3(DVector3(0., 1., 0.), pitch.Cos(), pitch.Sin()) * - DMatrix3x3(DVector3(1., 0., 0.), roll.Cos(), roll.Sin()); - relx = DVector3(1., 0., 0.)*rot; - rely = DVector3(0., 1., 0.)*rot; - relz = DVector3(0., 0., 1.)*rot; - viewpoint.Pos += relx * pos.X + rely * pos.Y + relz * pos.Z; - } + // The cam Actor should probably be visible in third person. + viewPoint.showviewer = true; + camPos.Z = mo->Top() - mo->Floorclip; + iView->ViewOffset.Z = clamp(chase_height, -1000.0, 1000.0); + iView->RelativeViewOffset.X = -clamp(chase_dist, 0.0, 30000.0); + } - if (jiggers.Intensity.X != 0 || jiggers.Offset.X != 0) - { - viewpoint.Pos.X += QuakePower(quakefactor, jiggers.Intensity.X, jiggers.Offset.X); - } - if (jiggers.Intensity.Y != 0 || jiggers.Offset.Y != 0) + if (viewOffset != nullptr) + { + // No chase/death cam, so use the view offset. + if (!viewPoint.bForceNoViewer) + viewPoint.bForceNoViewer = (viewOffset->Flags & VPSF_ABSOLUTEPOS) || !viewOffset->Offset.isZero(); + + if (viewOffset->Flags & VPSF_ABSOLUTEPOS) { - viewpoint.Pos.Y += QuakePower(quakefactor, jiggers.Intensity.Y, jiggers.Offset.Y); + iView->New.ViewPos.Zero(); + if (!matchPlayer) + camPos = viewOffset->Offset; } - if (jiggers.Intensity.Z != 0 || jiggers.Offset.Z != 0) + else { - viewpoint.Pos.Z += QuakePower(quakefactor, jiggers.Intensity.Z, jiggers.Offset.Z); + iView->New.ViewPos = viewOffset->Offset; } } + + viewPoint.ActorPos = iView->New.Pos = camPos; + viewPoint.sector = viewPoint.ViewLevel->PointInRenderSubsector(camPos)->sector; + } + + if (!paused) + { + FQuakeJiggers jiggers; + if (DEarthquake::StaticGetQuakeIntensities(viewPoint.TicFrac, viewPoint.camera, jiggers) > 0) + { + const double quakeFactor = r_quakeintensity; + if (jiggers.RollIntensity || jiggers.RollWave) + iView->AngleOffsets.Roll = DAngle::fromDeg(QuakePower(quakeFactor, jiggers.RollIntensity, jiggers.RollWave)); + + if (jiggers.RelIntensity.X || jiggers.RelOffset.X) + iView->RelativeViewOffset.X += QuakePower(quakeFactor, jiggers.RelIntensity.X, jiggers.RelOffset.X); + if (jiggers.RelIntensity.Y || jiggers.RelOffset.Y) + iView->RelativeViewOffset.Y += QuakePower(quakeFactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y); + if (jiggers.RelIntensity.Z || jiggers.RelOffset.Z) + iView->RelativeViewOffset.Z += QuakePower(quakeFactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z); + + if (jiggers.Intensity.X || jiggers.Offset.X) + iView->ViewOffset.X += QuakePower(quakeFactor, jiggers.Intensity.X, jiggers.Offset.X); + if (jiggers.Intensity.Y || jiggers.Offset.Y) + iView->ViewOffset.Y += QuakePower(quakeFactor, jiggers.Intensity.Y, jiggers.Offset.Y); + if (jiggers.Intensity.Z || jiggers.Offset.Z) + iView->ViewOffset.Z += QuakePower(quakeFactor, jiggers.Intensity.Z, jiggers.Offset.Z); + } + } + + // [MR] Apply view angles as the viewpoint angles if asked to do so. + if (matchPlayer) + iView->New.Angles = usePawn ? (client->flags8 & MF8_ABSVIEWANGLES ? client->ViewAngles : client->Angles + client->ViewAngles) : mainView.Angles; + else + iView->New.Angles = !(viewPoint.camera->flags8 & MF8_ABSVIEWANGLES) ? viewPoint.camera->Angles : viewPoint.camera->ViewAngles; + + iView->New.ViewAngles = viewPoint.camera->ViewAngles; + // [MR] Process player angle changes if permitted to do so. + if (player != nullptr && (player->cheats & CF_SCALEDNOLERP) && P_NoInterpolation(player, viewPoint.camera)) + R_DoActorTickerAngleChanges(player, iView->New.Angles, viewPoint.TicFrac); + + // If currently tracking the player's real view, don't do any sort of interpolating. + if (matchPlayer && !usePawn) + viewPoint.camera->renderflags |= RF_NOINTERPOLATEVIEW; + + if (viewPoint.camera->player != nullptr) + player = viewPoint.camera->player; + + if (iView->prevTic == -1 || r_NoInterpolate || (viewPoint.camera->renderflags & RF_NOINTERPOLATEVIEW)) + { + viewPoint.camera->renderflags &= ~RF_NOINTERPOLATEVIEW; + R_ResetViewInterpolation(); + iView->prevTic = curTic; } - viewpoint.extralight = viewpoint.camera->player ? viewpoint.camera->player->extralight : 0; + R_InterpolateView(viewPoint, player, viewPoint.TicFrac, iView); + + viewPoint.SetViewAngle(viewWindow); + + // Keep the view within the sector's floor and ceiling + // But allow VPSF_ALLOWOUTOFBOUNDS camera viewpoints to go out of bounds when using hardware renderer + if (viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer())) + { + const double z = viewPoint.sector->ceilingplane.ZatPoint(viewPoint.Pos) - 4.0; + if (viewPoint.Pos.Z > z) + viewPoint.Pos.Z = z; + } + + if (viewPoint.sector->PortalBlocksMovement(sector_t::floor) && (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer())) + { + const double z = viewPoint.sector->floorplane.ZatPoint(viewPoint.Pos) + 4.0; + if (viewPoint.Pos.Z < z) + viewPoint.Pos.Z = z; + } + + viewPoint.extralight = viewPoint.camera->player != nullptr ? viewPoint.camera->player->extralight : 0; // killough 3/20/98, 4/4/98: select colormap based on player status // [RH] Can also select a blend - newblend = 0; - - TArray &lightlist = viewpoint.sector->e->XFloor.lightlist; + unsigned int newBlend = 0u; + const TArray& lightlist = viewPoint.sector->e->XFloor.lightlist; if (lightlist.Size() > 0) { - for(unsigned int i = 0; i < lightlist.Size(); i++) + for (size_t i = 0u; i < lightlist.Size(); ++i) { - secplane_t *plane; - int viewside; - plane = (i < lightlist.Size()-1) ? &lightlist[i+1].plane : &viewpoint.sector->floorplane; - viewside = plane->PointOnSide(viewpoint.Pos); + const secplane_t& plane = (i < lightlist.Size() - 1u) ? lightlist[i + 1u].plane : viewPoint.sector->floorplane; + int viewSide = plane.PointOnSide(viewPoint.Pos); + // Reverse the direction of the test if the plane was downward facing. // We want to know if the view is above it, whatever its orientation may be. - if (plane->fC() < 0) - viewside = -viewside; - if (viewside > 0) + if (plane.fC() < 0.0) + viewSide = -viewSide; + + if (viewSide > 0) { - // 3d floor 'fog' is rendered as a blending value - PalEntry blendv = lightlist[i].blend; + // 3d floor 'fog' is rendered as a blending value. + PalEntry blend = lightlist[i].blend; + + // If no alpha is set, use 50%. + if (!blend.a && blend != 0) + blend.a = 128u; - // If no alpha is set, use 50% - if (blendv.a==0 && blendv!=0) blendv.a=128; - newblend = blendv.d; + newBlend = blend.d; break; } } } else { - const sector_t *s = viewpoint.sector->GetHeightSec(); - if (s != NULL) + const sector_t* const sec = viewPoint.sector->GetHeightSec(); + if (sec != nullptr) { - newblend = s->floorplane.PointOnSide(viewpoint.Pos) < 0 - ? s->bottommap - : s->ceilingplane.PointOnSide(viewpoint.Pos) < 0 - ? s->topmap - : s->midmap; - if (APART(newblend) == 0 && newblend >= fakecmaps.Size()) - newblend = 0; + newBlend = sec->floorplane.PointOnSide(viewPoint.Pos) < 0 + ? sec->bottommap + : sec->ceilingplane.PointOnSide(viewPoint.Pos) < 0 + ? sec->topmap + : sec->midmap; + + if (APART(newBlend) == 0u && newBlend >= fakecmaps.Size()) + newBlend = 0u; } } // [RH] Don't override testblend unless entering a sector with a // blend different from the previous sector's. Same goes with // NormalLight's maps pointer. - if (R_OldBlend != newblend) - { - R_OldBlend = newblend; - if (APART(newblend)) - { - BaseBlendR = RPART(newblend); - BaseBlendG = GPART(newblend); - BaseBlendB = BPART(newblend); - BaseBlendA = APART(newblend) / 255.f; - } - else - { - BaseBlendR = BaseBlendG = BaseBlendB = 0; - BaseBlendA = 0.f; - } - } + if (R_OldBlend != newBlend) + R_OldBlend = newBlend; - validcount++; + ++validcount; if (r_clearbuffer != 0) { - int color; + int color = 0; int hom = r_clearbuffer; - if (hom == 3) - { hom = ((screen->FrameTime / 128) & 1) + 1; - } if (hom == 1) - { color = GPalette.BlackIndex; - } else if (hom == 2) - { color = GPalette.WhiteIndex; - } else if (hom == 4) - { color = (screen->FrameTime / 32) & 255; - } else - { color = pr_hom(); - } + screen->SetClearColor(color); SWRenderer->SetClearColor(color); } @@ -1009,59 +1164,69 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor // Scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1. // However, to set up a projection matrix this needs to be adjusted. - double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians(); - double angx = cos(radPitch); - double angy = sin(radPitch) * actor->Level->info->pixelstretch; - double alen = sqrt(angx*angx + angy*angy); - viewpoint.HWAngles.Pitch = RAD2DEG((float)asin(angy / alen)); - - viewpoint.HWAngles.Roll.Degrees = (float)viewpoint.Angles.Roll.Degrees; // copied for convenience. + const double radPitch = viewPoint.Angles.Pitch.Normalized180().Radians(); + const double angx = cos(radPitch); + const double angy = sin(radPitch) * actor->Level->info->pixelstretch; + const double alen = sqrt(angx*angx + angy*angy); + + viewPoint.HWAngles.Pitch = FAngle::fromRad((float)asin(angy / alen)); + viewPoint.HWAngles.Roll = FAngle::fromDeg(viewPoint.Angles.Roll.Degrees()); - // ViewActor only gets set, if the camera actor should not be rendered - if (actor->player && actor->player - players == consoleplayer && - ((actor->player->cheats & CF_CHASECAM) || (r_deathcamera && actor->health <= 0)) && actor == actor->player->mo) - { - viewpoint.ViewActor = nullptr; - } - else + // ViewActor only gets set if the camera actor shouldn't be rendered. + viewPoint.ViewActor = viewPoint.showviewer ? nullptr : actor; +} + + +CUSTOM_CVAR(Float, maxviewpitch, 90.f, CVAR_ARCHIVE | CVAR_SERVERINFO) +{ + if (self>90.f) self = 90.f; + else if (self<-90.f) self = -90.f; + if (usergame) { - viewpoint.ViewActor = actor; + // [SP] Update pitch limits to the netgame/gamesim. + players[consoleplayer].SendPitchLimits(); } - } - //========================================================================== // -// CVAR transsouls -// -// How translucent things drawn with STYLE_SoulTrans are. Normally, only -// Lost Souls have this render style. -// Values less than 0.25 will automatically be set to -// 0.25 to ensure some degree of visibility. Likewise, values above 1.0 will -// be set to 1.0, because anything higher doesn't make sense. +// R_ShouldDrawSpriteShadow // //========================================================================== -CUSTOM_CVAR(Float, transsouls, 0.75f, CVAR_ARCHIVE) +bool R_ShouldDrawSpriteShadow(AActor *thing) { - if (self < 0.25f) - { - self = 0.25f; - } - else if (self > 1.f) + int rf = thing->renderflags; + // for wall and flat sprites the shadow math does not work so these must be unconditionally skipped. + if (rf & (RF_FLATSPRITE | RF_WALLSPRITE)) return false; + + bool doit = false; + switch (r_actorspriteshadow) { - self = 1.f; + case 1: + doit = (rf & RF_CASTSPRITESHADOW); + break; + + case 2: + doit = (rf & RF_CASTSPRITESHADOW) || (!(rf & RF_NOSPRITESHADOW) && ((thing->flags3 & MF3_ISMONSTER) || thing->player != nullptr)); + break; + + default: + break; } -} -CUSTOM_CVAR(Float, maxviewpitch, 90.f, CVAR_ARCHIVE | CVAR_SERVERINFO) -{ - if (self>90.f) self = 90.f; - else if (self<-90.f) self = -90.f; - if (usergame) + if (doit) { - // [SP] Update pitch limits to the netgame/gamesim. - players[consoleplayer].SendPitchLimits(); + auto rs = thing->RenderStyle; + rs.CheckFuzz(); + // For non-standard render styles, draw no shadows. This will always look weird. However, if the sprite forces shadows, render them anyway. + if (!(rf & RF_CASTSPRITESHADOW)) + { + if (rs.BlendOp != STYLEOP_Add && rs.BlendOp != STYLEOP_Shadow) return false; + if (rs.DestAlpha != STYLEALPHA_Zero && rs.DestAlpha != STYLEALPHA_InvSrc) return false; + } } + return doit; + + } diff --git a/src/rendering/r_utility.h b/src/rendering/r_utility.h index bdc9aea1715..ca6d84b8c8f 100644 --- a/src/rendering/r_utility.h +++ b/src/rendering/r_utility.h @@ -33,19 +33,26 @@ struct FRenderViewpoint double Sin; // sin(Angles.Yaw) double TanCos; // FocalTangent * cos(Angles.Yaw) double TanSin; // FocalTangent * sin(Angles.Yaw) + double PitchCos; // cos(Angles.Pitch) + double PitchSin; // sin(Angles.Pitch) + double floordistfact; // used for isometric sprites Y-billboarding compensation in hw_sprites.cpp + double cotfloor; // used for isometric sprites Y-billboarding compensation in hw_sprites.cpp + angle_t FrustAngle; // FrustumAngle() result AActor *camera; // camera actor sector_t *sector; // [RH] keep track of sector viewing from DAngle FieldOfView; // current field of view + double ScreenProj; // Screen projection factor for orthographic projection double TicFrac; // fraction of tic for interpolation uint32_t FrameTime; // current frame's time in tics. int extralight; // extralight to be added to this viewpoint bool showviewer; // show the camera actor? - - - void SetViewAngle(const FViewWindow &viewwindow); + bool bForceNoViewer; // Never show the camera Actor. + void SetViewAngle(const FViewWindow& viewWindow); + bool IsAllowedOoB(); // Checks if camera actor exists, has viewpos, and viewpos has VPSF_ALLOWOUTOFBOUNDS flag set + bool IsOrtho(); // Checks if camera actor exists, has viewpos, and viewpos has VPSF_ORTHOGRAPHIC flag set }; @@ -91,17 +98,17 @@ const double r_Yaspect = 200.0; // Why did I make this a variable? It's never // //========================================================================== -inline int R_PointOnSide (fixed_t x, fixed_t y, const node_t *node) +inline constexpr int R_PointOnSide (fixed_t x, fixed_t y, const node_t *node) { - return DMulScale32 (y-node->y, node->dx, node->x-x, node->dy) > 0; + return DMulScale (y-node->y, node->dx, node->x-x, node->dy, 32) > 0; } inline int R_PointOnSide(double x, double y, const node_t *node) { - return DMulScale32(FLOAT2FIXED(y) - node->y, node->dx, node->x - FLOAT2FIXED(x), node->dy) > 0; + return DMulScale(FLOAT2FIXED(y) - node->y, node->dx, node->x - FLOAT2FIXED(x), node->dy, 32) > 0; } inline int R_PointOnSide(const DVector2 &pos, const node_t *node) { - return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0; + return DMulScale(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy, 32) > 0; } // Used for interpolation waypoints. @@ -118,7 +125,7 @@ void R_ClearInterpolationPath(); void R_AddInterpolationPoint(const DVector3a &vec); void R_SetViewSize (int blocks); void R_SetFOV (FRenderViewpoint &viewpoint, DAngle fov); -void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor * camera); +void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AActor* const camera); void R_SetViewAngle (FRenderViewpoint &viewpoint, const FViewWindow &viewwindow); // Called by startup code. @@ -135,5 +142,6 @@ double R_ClampVisibility(double vis); extern void R_FreePastViewers (); extern void R_ClearPastViewer (AActor *actor); +bool R_ShouldDrawSpriteShadow(AActor *thing); #endif diff --git a/src/rendering/swrenderer/drawers/r_draw.cpp b/src/rendering/swrenderer/drawers/r_draw.cpp index f4e3735fa88..4e8a6673246 100644 --- a/src/rendering/swrenderer/drawers/r_draw.cpp +++ b/src/rendering/swrenderer/drawers/r_draw.cpp @@ -33,11 +33,12 @@ */ #include +#include + -#include "templates.h" #include "doomdef.h" -#include "w_wad.h" +#include "filesystem.h" #include "v_video.h" #include "doomstat.h" #include "st_stuff.h" @@ -52,10 +53,9 @@ #include "r_thread.h" #include "swrenderer/scene/r_light.h" #include "playsim/a_dynlight.h" -#include "polyrenderer/drawers/poly_thread.h" -CVAR(Bool, r_dynlights, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); -CVAR(Bool, r_fuzzscale, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, r_dynlights, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, r_fuzzscale, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); namespace swrenderer { @@ -108,7 +108,7 @@ namespace swrenderer for (int k = 0; k < 256; ++k) { uint8_t v = (((k + 2) * a) + 256) >> 14; - table[k] = MIN(v, 64); + table[k] = min(v, 64); } table += 256; } @@ -195,7 +195,7 @@ namespace swrenderer void R_UpdateFuzzPosFrameStart() { - if (r_fuzzscale || V_IsPolyRenderer()) + if (r_fuzzscale) { static int next_random = 0; @@ -209,10 +209,10 @@ namespace swrenderer void R_UpdateFuzzPos(const SpriteDrawerArgs &args) { - if (!r_fuzzscale && !V_IsPolyRenderer()) + if (!r_fuzzscale) { - int yl = MAX(args.FuzzY1(), 1); - int yh = MIN(args.FuzzY2(), fuzzviewheight); + int yl = max(args.FuzzY1(), 1); + int yh = min(args.FuzzY2(), fuzzviewheight); if (yl <= yh) fuzzpos = (fuzzpos + yh - yl + 1) % FUZZTABLE; } @@ -220,280 +220,7 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////// - DrawWallCommand::DrawWallCommand(const WallDrawerArgs& args) : wallargs(args) - { - } - - void DrawWallCommand::Execute(DrawerThread* thread) - { - if (!thread->columndrawer) - thread->columndrawer = std::make_shared(); - - WallColumnDrawerArgs& drawerargs = *thread->columndrawer.get(); - drawerargs.wallargs = &wallargs; - - bool haslights = r_dynlights && wallargs.lightlist; - if (haslights) - { - float dx = wallargs.WallC.tright.X - wallargs.WallC.tleft.X; - float dy = wallargs.WallC.tright.Y - wallargs.WallC.tleft.Y; - float length = sqrt(dx * dx + dy * dy); - drawerargs.dc_normal.X = dy / length; - drawerargs.dc_normal.Y = -dx / length; - drawerargs.dc_normal.Z = 0.0f; - } - - drawerargs.SetTextureFracBits(wallargs.fracbits); - - float curlight = wallargs.lightpos; - float lightstep = wallargs.lightstep; - int shade = wallargs.Shade(); - - if (wallargs.fixedlight) - { - curlight = wallargs.FixedLight(); - lightstep = 0; - } - - float upos = wallargs.texcoords.upos, ustepX = wallargs.texcoords.ustepX, ustepY = wallargs.texcoords.ustepY; - float vpos = wallargs.texcoords.vpos, vstepX = wallargs.texcoords.vstepX, vstepY = wallargs.texcoords.vstepY; - float wpos = wallargs.texcoords.wpos, wstepX = wallargs.texcoords.wstepX, wstepY = wallargs.texcoords.wstepY; - float startX = wallargs.texcoords.startX; - - int x1 = wallargs.x1; - int x2 = wallargs.x2; - - upos += ustepX * (x1 + 0.5f - startX); - vpos += vstepX * (x1 + 0.5f - startX); - wpos += wstepX * (x1 + 0.5f - startX); - - float centerY = wallargs.CenterY; - centerY -= 0.5f; - - auto uwal = wallargs.uwal; - auto dwal = wallargs.dwal; - for (int x = x1; x < x2; x++) - { - int y1 = uwal[x]; - int y2 = dwal[x]; - if (y2 > y1) - { - drawerargs.SetLight(curlight, shade); - if (haslights) - SetLights(drawerargs, x, y1); - else - drawerargs.dc_num_lights = 0; - - float dy = (y1 - centerY); - float u = upos + ustepY * dy; - float v = vpos + vstepY * dy; - float w = wpos + wstepY * dy; - float scaleU = ustepX; - float scaleV = vstepY; - w = 1.0f / w; - u *= w; - v *= w; - scaleU *= w; - scaleV *= w; - - uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL); - uint32_t texelY = (uint32_t)(int64_t)((v - std::floor(v)) * 0x1'0000'0000LL); - uint32_t texelStepX = (uint32_t)(int64_t)(scaleU * 0x1'0000'0000LL); - uint32_t texelStepY = (uint32_t)(int64_t)(scaleV * 0x1'0000'0000LL); - - if (wallargs.fracbits != 32) - DrawWallColumn8(thread, drawerargs, x, y1, y2, texelX, texelY, texelStepY); - else - DrawWallColumn32(thread, drawerargs, x, y1, y2, texelX, texelY, texelStepX, texelStepY); - } - - upos += ustepX; - vpos += vstepX; - wpos += wstepX; - curlight += lightstep; - } - - if (r_modelscene) - { - for (int x = x1; x < x2; x++) - { - int y1 = uwal[x]; - int y2 = dwal[x]; - if (y2 > y1) - { - int count = y2 - y1; - - float w1 = 1.0f / wallargs.WallC.sz1; - float w2 = 1.0f / wallargs.WallC.sz2; - float t = (x - wallargs.WallC.sx1 + 0.5f) / (wallargs.WallC.sx2 - wallargs.WallC.sx1); - float wcol = w1 * (1.0f - t) + w2 * t; - float zcol = 1.0f / wcol; - float zbufferdepth = 1.0f / (zcol / wallargs.FocalTangent); - - drawerargs.SetDest(x, y1); - drawerargs.SetCount(count); - DrawDepthColumn(thread, drawerargs, zbufferdepth); - } - } - } - } - - void DrawWallCommand::DrawWallColumn32(DrawerThread* thread, WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepX, uint32_t texelStepY) - { - int texwidth = wallargs.texwidth; - int texheight = wallargs.texheight; - - double xmagnitude = fabs(static_cast(texelStepX)* (1.0 / 0x1'0000'0000LL)); - double ymagnitude = fabs(static_cast(texelStepY)* (1.0 / 0x1'0000'0000LL)); - double magnitude = MAX(ymagnitude, xmagnitude); - double min_lod = -1000.0; - double lod = MAX(log2(magnitude) + r_lod_bias, min_lod); - bool magnifying = lod < 0.0f; - - int mipmap_offset = 0; - int mip_width = texwidth; - int mip_height = texheight; - if (wallargs.mipmapped && mip_width > 1 && mip_height > 1) - { - int level = (int)lod; - while (level > 0 && mip_width > 1 && mip_height > 1) - { - mipmap_offset += mip_width * mip_height; - level--; - mip_width = MAX(mip_width >> 1, 1); - mip_height = MAX(mip_height >> 1, 1); - } - } - - const uint32_t* pixels = static_cast(wallargs.texpixels) + mipmap_offset; - fixed_t xxoffset = (texelX >> 16)* mip_width; - - const uint8_t* source; - const uint8_t* source2; - uint32_t texturefracx; - bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter); - if (filter_nearest) - { - int tx = (xxoffset >> FRACBITS) % mip_width; - source = (uint8_t*)(pixels + tx * mip_height); - source2 = nullptr; - texturefracx = 0; - } - else - { - xxoffset -= FRACUNIT / 2; - int tx0 = (xxoffset >> FRACBITS) % mip_width; - if (tx0 < 0) - tx0 += mip_width; - int tx1 = (tx0 + 1) % mip_width; - source = (uint8_t*)(pixels + tx0 * mip_height); - source2 = (uint8_t*)(pixels + tx1 * mip_height); - texturefracx = (xxoffset >> (FRACBITS - 4)) & 15; - } - - int count = y2 - y1; - drawerargs.SetDest(x, y1); - drawerargs.SetCount(count); - drawerargs.SetTexture(source, source2, mip_height); - drawerargs.SetTextureUPos(texturefracx); - drawerargs.SetTextureVPos(texelY); - drawerargs.SetTextureVStep(texelStepY); - DrawColumn(thread, drawerargs); - } - - void DrawWallCommand::DrawWallColumn8(DrawerThread* thread, WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepY) - { - int texwidth = wallargs.texwidth; - int texheight = wallargs.texheight; - int fracbits = wallargs.fracbits; - uint32_t uv_max = texheight << fracbits; - - const uint8_t* pixels = static_cast(wallargs.texpixels) + (((texelX >> 16)* texwidth) >> 16)* texheight; - - texelY = (static_cast(texelY)* texheight) >> (32 - fracbits); - texelStepY = (static_cast(texelStepY)* texheight) >> (32 - fracbits); - - drawerargs.SetTexture(pixels, nullptr, texheight); - drawerargs.SetTextureVStep(texelStepY); - - if (uv_max == 0 || texelStepY == 0) // power of two - { - int count = y2 - y1; - - drawerargs.SetDest(x, y1); - drawerargs.SetCount(count); - drawerargs.SetTextureVPos(texelY); - DrawColumn(thread, drawerargs); - } - else - { - uint32_t left = y2 - y1; - int y = y1; - while (left > 0) - { - uint32_t available = uv_max - texelY; - uint32_t next_uv_wrap = available / texelStepY; - if (available % texelStepY != 0) - next_uv_wrap++; - uint32_t count = MIN(left, next_uv_wrap); - - drawerargs.SetDest(x, y); - drawerargs.SetCount(count); - drawerargs.SetTextureVPos(texelY); - DrawColumn(thread, drawerargs); - - y += count; - left -= count; - texelY += texelStepY * count; - if (texelY >= uv_max) - texelY -= uv_max; - } - } - } - - void DrawWallCommand::DrawDepthColumn(DrawerThread* thread, const WallColumnDrawerArgs& args, float idepth) - { - int x, y, count; - - auto rendertarget = args.Viewport()->RenderTarget; - if (rendertarget->IsBgra()) - { - uint32_t* destorg = (uint32_t*)rendertarget->GetPixels(); - destorg += viewwindowx + viewwindowy * rendertarget->GetPitch(); - uint32_t* dest = (uint32_t*)args.Dest(); - int offset = (int)(ptrdiff_t)(dest - destorg); - x = offset % rendertarget->GetPitch(); - y = offset / rendertarget->GetPitch(); - } - else - { - uint8_t* destorg = rendertarget->GetPixels(); - destorg += viewwindowx + viewwindowy * rendertarget->GetPitch(); - uint8_t* dest = (uint8_t*)args.Dest(); - int offset = (int)(ptrdiff_t)(dest - destorg); - x = offset % rendertarget->GetPitch(); - y = offset / rendertarget->GetPitch(); - } - count = args.Count(); - - auto zbuffer = PolyTriangleThreadData::Get(thread)->depthstencil; - int pitch = zbuffer->Width(); - float* values = zbuffer->DepthValues() + y * pitch + x; - int cnt = count; - - values = thread->dest_for_thread(y, pitch, values); - cnt = thread->count_for_thread(y, cnt); - pitch *= thread->num_cores; - - float depth = idepth; - for (int i = 0; i < cnt; i++) - { - *values = depth; - values += pitch; - } - } - - void DrawWallCommand::SetLights(WallColumnDrawerArgs& drawerargs, int x, int y1) + void SWPixelFormatDrawers::SetLights(WallColumnDrawerArgs& drawerargs, int x, int y1, const WallDrawerArgs& wallargs) { bool mirror = !!(wallargs.PortalMirrorFlags & RF_XFLIP); int tx = x; @@ -557,132 +284,4 @@ namespace swrenderer } } - ///////////////////////////////////////////////////////////////////////// - - class DepthSkyColumnCommand : public DrawerCommand - { - public: - DepthSkyColumnCommand(const SkyDrawerArgs &args, float idepth) : idepth(idepth) - { - auto rendertarget = args.Viewport()->RenderTarget; - if (rendertarget->IsBgra()) - { - uint32_t *destorg = (uint32_t*)rendertarget->GetPixels(); - destorg += viewwindowx + viewwindowy * rendertarget->GetPitch(); - uint32_t *dest = (uint32_t*)args.Dest(); - int offset = (int)(ptrdiff_t)(dest - destorg); - x = offset % rendertarget->GetPitch(); - y = offset / rendertarget->GetPitch(); - } - else - { - uint8_t *destorg = rendertarget->GetPixels(); - destorg += viewwindowx + viewwindowy * rendertarget->GetPitch(); - uint8_t *dest = (uint8_t*)args.Dest(); - int offset = (int)(ptrdiff_t)(dest - destorg); - x = offset % rendertarget->GetPitch(); - y = offset / rendertarget->GetPitch(); - } - count = args.Count(); - } - - void Execute(DrawerThread *thread) override - { - auto zbuffer = PolyTriangleThreadData::Get(thread)->depthstencil; - int pitch = zbuffer->Width(); - float *values = zbuffer->DepthValues() + y * pitch + x; - int cnt = count; - - values = thread->dest_for_thread(y, pitch, values); - cnt = thread->count_for_thread(y, cnt); - pitch *= thread->num_cores; - - float depth = idepth; - for (int i = 0; i < cnt; i++) - { - *values = depth; - values += pitch; - } - } - - private: - int x, y, count; - float idepth; - }; - - // #define DEPTH_DEBUG - - class DepthSpanCommand : public DrawerCommand - { - public: - DepthSpanCommand(const SpanDrawerArgs &args, float idepth1, float idepth2) : idepth1(idepth1), idepth2(idepth2) - { - y = args.DestY(); - x1 = args.DestX1(); - x2 = args.DestX2(); - #ifdef DEPTH_DEBUG - dest = (uint32_t*)args.Viewport()->GetDest(0, args.DestY()); - #endif - } - - void Execute(DrawerThread *thread) override - { - if (thread->skipped_by_thread(y)) - return; - - auto zbuffer = PolyTriangleThreadData::Get(thread)->depthstencil; - int pitch = zbuffer->Width(); - float *values = zbuffer->DepthValues() + y * pitch; - int end = x2; - - if (idepth1 == idepth2) - { - float depth = idepth1; - #ifdef DEPTH_DEBUG - uint32_t gray = clamp((int32_t)(1.0f / depth / 4.0f), 0, 255); - uint32_t color = MAKEARGB(255, gray, gray, gray); - #endif - for (int x = x1; x <= end; x++) - { - values[x] = depth; - #ifdef DEPTH_DEBUG - dest[x] = color; - #endif - } - } - else - { - float depth = idepth1; - float step = (idepth2 - idepth1) / (x2 - x1 + 1); - for (int x = x1; x <= end; x++) - { - #ifdef DEPTH_DEBUG - uint32_t gray = clamp((int32_t)(1.0f / depth / 4.0f), 0, 255); - uint32_t color = MAKEARGB(255, gray, gray, gray); - dest[x] = color; - #endif - - values[x] = depth; - depth += step; - } - } - } - - private: - int y, x1, x2; - float idepth1, idepth2; - #ifdef DEPTH_DEBUG - uint32_t *dest; - #endif - }; - - void SWPixelFormatDrawers::DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth) - { - Queue->Push(args, idepth); - } - - void SWPixelFormatDrawers::DrawDepthSpan(const SpanDrawerArgs &args, float idepth1, float idepth2) - { - Queue->Push(args, idepth1, idepth2); - } } diff --git a/src/rendering/swrenderer/drawers/r_draw.h b/src/rendering/swrenderer/drawers/r_draw.h index 32eba2db07e..133c2b18202 100644 --- a/src/rendering/swrenderer/drawers/r_draw.h +++ b/src/rendering/swrenderer/drawers/r_draw.h @@ -19,14 +19,12 @@ EXTERN_CVAR(Float, transsouls); EXTERN_CVAR(Bool, r_dynlights); EXTERN_CVAR(Bool, r_fuzzscale); -class DrawerCommandQueue; -typedef std::shared_ptr DrawerCommandQueuePtr; - namespace swrenderer { class DrawerArgs; class SkyDrawerArgs; class WallDrawerArgs; + class WallColumnDrawerArgs; class SpanDrawerArgs; class SpriteDrawerArgs; class VoxelBlock; @@ -55,8 +53,8 @@ namespace swrenderer class SWPixelFormatDrawers { public: - SWPixelFormatDrawers(DrawerCommandQueuePtr queue) : Queue(queue) { } - virtual ~SWPixelFormatDrawers() { } + SWPixelFormatDrawers(RenderThread* thread) : thread(thread) { } + virtual ~SWPixelFormatDrawers() = default; virtual void DrawWall(const WallDrawerArgs &args) = 0; virtual void DrawWallMasked(const WallDrawerArgs &args) = 0; virtual void DrawWallAdd(const WallDrawerArgs &args) = 0; @@ -94,11 +92,11 @@ namespace swrenderer virtual void DrawTiltedSpan(const SpanDrawerArgs &args, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap) = 0; virtual void DrawColoredSpan(const SpanDrawerArgs &args) = 0; virtual void DrawFogBoundaryLine(const SpanDrawerArgs &args) = 0; + virtual void DrawParticleColumn(int x, int yl, int ycount, uint32_t fg, uint32_t alpha, uint32_t fracposx) = 0; + + void SetLights(WallColumnDrawerArgs& drawerargs, int x, int y1, const WallDrawerArgs& wallargs); - void DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth); - void DrawDepthSpan(const SpanDrawerArgs &args, float idepth1, float idepth2); - - DrawerCommandQueuePtr Queue; + RenderThread* thread = nullptr; }; void R_InitShadeMaps(); diff --git a/src/rendering/swrenderer/drawers/r_draw_pal.cpp b/src/rendering/swrenderer/drawers/r_draw_pal.cpp index af42a7f352e..9f1b197ef1a 100644 --- a/src/rendering/swrenderer/drawers/r_draw_pal.cpp +++ b/src/rendering/swrenderer/drawers/r_draw_pal.cpp @@ -36,7 +36,7 @@ #ifndef NO_SSE #include #endif -#include "templates.h" + #include "doomtype.h" #include "doomdef.h" #include "r_defs.h" @@ -93,7 +93,7 @@ EXTERN_CVAR(Int, gl_particles_style) namespace swrenderer { - uint8_t PalWall1Command::AddLights(const DrawerLight *lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material) + uint8_t SWPalDrawers::AddLightsColumn(const DrawerLight *lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material) { uint32_t lit_r = 0; uint32_t lit_g = 0; @@ -107,7 +107,7 @@ namespace swrenderer // L = light-pos // dist = sqrt(dot(L, L)) - // distance_attenuation = 1 - MIN(dist * (1/radius), 1) + // distance_attenuation = 1 - min(dist * (1/radius), 1) float Lxy2 = lights[i].x; // L.x*L.x + L.y*L.y float Lz = lights[i].z - viewpos_z; float dist2 = Lxy2 + Lz * Lz; @@ -117,7 +117,7 @@ namespace swrenderer float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(dist2))); #endif float dist = dist2 * rcp_dist; - float distance_attenuation = (256.0f - MIN(dist * lights[i].radius, 256.0f)); + float distance_attenuation = (256.0f - min(dist * lights[i].radius, 256.0f)); // The simple light type float simple_attenuation = distance_attenuation; @@ -139,19 +139,23 @@ namespace swrenderer uint32_t material_g = GPalette.BaseColors[material].g; uint32_t material_b = GPalette.BaseColors[material].b; - lit_r = MIN(GPalette.BaseColors[fg].r + ((lit_r * material_r) >> 8), 255); - lit_g = MIN(GPalette.BaseColors[fg].g + ((lit_g * material_g) >> 8), 255); - lit_b = MIN(GPalette.BaseColors[fg].b + ((lit_b * material_b) >> 8), 255); + lit_r = min(GPalette.BaseColors[fg].r + ((lit_r * material_r) >> 8), 255); + lit_g = min(GPalette.BaseColors[fg].g + ((lit_g * material_g) >> 8), 255); + lit_b = min(GPalette.BaseColors[fg].b + ((lit_b * material_b) >> 8), 255); return RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)]; } - void DrawWall1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) + template<> + void SWPalDrawers::DrawWallColumn(const WallColumnDrawerArgs& args) { + int count = args.Count(); + if (count <= 0) + return; + uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); uint8_t *colormap = args.Colormap(args.Viewport()); - int count = args.Count(); const uint8_t *source = args.TexturePixels(); uint8_t *dest = args.Dest(); int bits = args.TextureFracBits(); @@ -161,15 +165,6 @@ namespace swrenderer float viewpos_z = args.dc_viewpos.Z; float step_viewpos_z = args.dc_viewpos_step.Z; - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - if (num_dynlights == 0) { do @@ -184,12 +179,9 @@ namespace swrenderer float viewpos_z = args.dc_viewpos.Z; float step_viewpos_z = args.dc_viewpos_step.Z; - viewpos_z += step_viewpos_z * thread->skipped_by_thread(args.DestY()); - step_viewpos_z *= thread->num_cores; - do { - *dest = AddLights(dynlights, num_dynlights, viewpos_z, colormap[source[frac >> bits]], source[frac >> bits]); + *dest = AddLightsColumn(dynlights, num_dynlights, viewpos_z, colormap[source[frac >> bits]], source[frac >> bits]); viewpos_z += step_viewpos_z; frac += fracstep; dest += pitch; @@ -197,12 +189,16 @@ namespace swrenderer } } - void DrawWallMasked1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) + template<> + void SWPalDrawers::DrawWallColumn(const WallColumnDrawerArgs& args) { + int count = args.Count(); + if (count <= 0) + return; + uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); uint8_t *colormap = args.Colormap(args.Viewport()); - int count = args.Count(); const uint8_t *source = args.TexturePixels(); uint8_t *dest = args.Dest(); int bits = args.TextureFracBits(); @@ -212,15 +208,6 @@ namespace swrenderer float viewpos_z = args.dc_viewpos.Z; float step_viewpos_z = args.dc_viewpos_step.Z; - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - if (num_dynlights == 0) { do @@ -239,15 +226,12 @@ namespace swrenderer float viewpos_z = args.dc_viewpos.Z; float step_viewpos_z = args.dc_viewpos_step.Z; - viewpos_z += step_viewpos_z * thread->skipped_by_thread(args.DestY()); - step_viewpos_z *= thread->num_cores; - do { uint8_t pix = source[frac >> bits]; if (pix != 0) { - *dest = AddLights(dynlights, num_dynlights, viewpos_z, colormap[pix], pix); + *dest = AddLightsColumn(dynlights, num_dynlights, viewpos_z, colormap[pix], pix); } viewpos_z += step_viewpos_z; frac += fracstep; @@ -256,12 +240,16 @@ namespace swrenderer } } - void DrawWallAdd1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) + template<> + void SWPalDrawers::DrawWallColumn(const WallColumnDrawerArgs& args) { + int count = args.Count(); + if (count <= 0) + return; + uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); uint8_t *colormap = args.Colormap(args.Viewport()); - int count = args.Count(); const uint8_t *source = args.TexturePixels(); uint8_t *dest = args.Dest(); int bits = args.TextureFracBits(); @@ -270,15 +258,6 @@ namespace swrenderer uint32_t *fg2rgb = args.SrcBlend(); uint32_t *bg2rgb = args.DestBlend(); - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - if (!r_blendmethod) { do @@ -307,9 +286,9 @@ namespace swrenderer { uint8_t lit = colormap[pix]; - uint32_t r = MIN(GPalette.BaseColors[lit].r + GPalette.BaseColors[*dest].r, 255); - uint32_t g = MIN(GPalette.BaseColors[lit].g + GPalette.BaseColors[*dest].g, 255); - uint32_t b = MIN(GPalette.BaseColors[lit].b + GPalette.BaseColors[*dest].b, 255); + uint32_t r = min(GPalette.BaseColors[lit].r + GPalette.BaseColors[*dest].r, 255); + uint32_t g = min(GPalette.BaseColors[lit].g + GPalette.BaseColors[*dest].g, 255); + uint32_t b = min(GPalette.BaseColors[lit].b + GPalette.BaseColors[*dest].b, 255); *dest = RGB256k.RGB[r>>2][g>>2][b>>2]; } frac += fracstep; @@ -318,12 +297,16 @@ namespace swrenderer } } - void DrawWallAddClamp1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) + template<> + void SWPalDrawers::DrawWallColumn(const WallColumnDrawerArgs& args) { + int count = args.Count(); + if (count <= 0) + return; + uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); uint8_t *colormap = args.Colormap(args.Viewport()); - int count = args.Count(); const uint8_t *source = args.TexturePixels(); uint8_t *dest = args.Dest(); int bits = args.TextureFracBits(); @@ -336,17 +319,6 @@ namespace swrenderer uint32_t *fg2rgb = args.SrcBlend(); uint32_t *bg2rgb = args.DestBlend(); - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - viewpos_z += step_viewpos_z * thread->skipped_by_thread(args.DestY()); - step_viewpos_z *= thread->num_cores; - if (!r_blendmethod) { do @@ -354,7 +326,7 @@ namespace swrenderer uint8_t pix = source[frac >> bits]; if (pix != 0) { - uint8_t lit = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; + uint8_t lit = num_dynlights != 0 ? AddLightsColumn(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; uint32_t a = fg2rgb[lit] + bg2rgb[*dest]; uint32_t b = a; @@ -378,11 +350,11 @@ namespace swrenderer uint8_t pix = source[frac >> bits]; if (pix != 0) { - uint8_t lit = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; + uint8_t lit = num_dynlights != 0 ? AddLightsColumn(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; - uint32_t r = MIN(GPalette.BaseColors[lit].r + GPalette.BaseColors[*dest].r, 255); - uint32_t g = MIN(GPalette.BaseColors[lit].g + GPalette.BaseColors[*dest].g, 255); - uint32_t b = MIN(GPalette.BaseColors[lit].b + GPalette.BaseColors[*dest].b, 255); + uint32_t r = min(GPalette.BaseColors[lit].r + GPalette.BaseColors[*dest].r, 255); + uint32_t g = min(GPalette.BaseColors[lit].g + GPalette.BaseColors[*dest].g, 255); + uint32_t b = min(GPalette.BaseColors[lit].b + GPalette.BaseColors[*dest].b, 255); *dest = RGB256k.RGB[r>>2][g>>2][b>>2]; } viewpos_z += step_viewpos_z; @@ -392,12 +364,16 @@ namespace swrenderer } } - void DrawWallSubClamp1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) + template<> + void SWPalDrawers::DrawWallColumn(const WallColumnDrawerArgs& args) { + int count = args.Count(); + if (count <= 0) + return; + uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); uint8_t *colormap = args.Colormap(args.Viewport()); - int count = args.Count(); const uint8_t *source = args.TexturePixels(); uint8_t *dest = args.Dest(); int bits = args.TextureFracBits(); @@ -410,17 +386,6 @@ namespace swrenderer uint32_t *fg2rgb = args.SrcBlend(); uint32_t *bg2rgb = args.DestBlend(); - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - viewpos_z += step_viewpos_z * thread->skipped_by_thread(args.DestY()); - step_viewpos_z *= thread->num_cores; - if (!r_blendmethod) { do @@ -428,7 +393,7 @@ namespace swrenderer uint8_t pix = source[frac >> bits]; if (pix != 0) { - uint8_t lit = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; + uint8_t lit = num_dynlights != 0 ? AddLightsColumn(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; uint32_t a = (fg2rgb[lit] | 0x40100400) - bg2rgb[*dest]; uint32_t b = a; @@ -451,7 +416,7 @@ namespace swrenderer uint8_t pix = source[frac >> bits]; if (pix != 0) { - uint8_t lit = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; + uint8_t lit = num_dynlights != 0 ? AddLightsColumn(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; int r = clamp(-GPalette.BaseColors[lit].r + GPalette.BaseColors[*dest].r, 0, 255); int g = clamp(-GPalette.BaseColors[lit].g + GPalette.BaseColors[*dest].g, 0, 255); @@ -465,12 +430,16 @@ namespace swrenderer } } - void DrawWallRevSubClamp1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) + template<> + void SWPalDrawers::DrawWallColumn(const WallColumnDrawerArgs& args) { + int count = args.Count(); + if (count <= 0) + return; + uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); uint8_t *colormap = args.Colormap(args.Viewport()); - int count = args.Count(); const uint8_t *source = args.TexturePixels(); uint8_t *dest = args.Dest(); int bits = args.TextureFracBits(); @@ -483,17 +452,6 @@ namespace swrenderer uint32_t *fg2rgb = args.SrcBlend(); uint32_t *bg2rgb = args.DestBlend(); - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - viewpos_z += step_viewpos_z * thread->skipped_by_thread(args.DestY()); - step_viewpos_z *= thread->num_cores; - if (!r_blendmethod) { do @@ -501,7 +459,7 @@ namespace swrenderer uint8_t pix = source[frac >> bits]; if (pix != 0) { - uint8_t lit = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; + uint8_t lit = num_dynlights != 0 ? AddLightsColumn(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; uint32_t a = (bg2rgb[*dest] | 0x40100400) - fg2rgb[lit]; uint32_t b = a; @@ -524,7 +482,7 @@ namespace swrenderer uint8_t pix = source[frac >> bits]; if (pix != 0) { - uint8_t lit = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; + uint8_t lit = num_dynlights != 0 ? AddLightsColumn(dynlights, num_dynlights, viewpos_z, colormap[pix], pix) : colormap[pix]; int r = clamp(GPalette.BaseColors[lit].r - GPalette.BaseColors[*dest].r, 0, 255); int g = clamp(GPalette.BaseColors[lit].g - GPalette.BaseColors[*dest].g, 0, 255); @@ -540,11 +498,7 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////// - PalSkyCommand::PalSkyCommand(const SkyDrawerArgs &args) : args(args) - { - } - - void DrawSingleSky1PalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawSingleSkyColumn(const SkyDrawerArgs& args) { uint8_t *dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); @@ -554,31 +508,10 @@ namespace swrenderer int32_t frac = args.TextureVPos(); int32_t fracstep = args.TextureVStep(); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); - int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; - - // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: - int start_fade = 2; // How fast it should fade out - int fade_length = (1 << (24 - start_fade)); - int start_fadetop_y = (-frac) / fracstep; - int end_fadetop_y = (fade_length - frac) / fracstep; - int start_fadebottom_y = ((2 << 24) - fade_length - frac) / fracstep; - int end_fadebottom_y = ((2 << 24) - frac) / fracstep; - start_fadetop_y = clamp(start_fadetop_y, 0, count); - end_fadetop_y = clamp(end_fadetop_y, 0, count); - start_fadebottom_y = clamp(start_fadebottom_y, 0, count); - end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * skipped; - fracstep *= num_cores; - pitch *= num_cores; + int count = args.Count(); if (!args.FadeSky()) { - count = thread->count_for_thread(args.DestY(), args.Count()); - for (int index = 0; index < count; index++) { uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; @@ -590,6 +523,18 @@ namespace swrenderer return; } + // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: + int start_fade = 2; // How fast it should fade out + int fade_length = (1 << (24 - start_fade)); + int start_fadetop_y = (-frac) / fracstep; + int end_fadetop_y = (fade_length - frac) / fracstep; + int start_fadebottom_y = ((2 << 24) - fade_length - frac) / fracstep; + int end_fadebottom_y = ((2 << 24) - frac) / fracstep; + start_fadetop_y = clamp(start_fadetop_y, 0, count); + end_fadetop_y = clamp(end_fadetop_y, 0, count); + start_fadebottom_y = clamp(start_fadebottom_y, 0, count); + end_fadebottom_y = clamp(end_fadebottom_y, 0, count); + uint32_t solid_top = args.SolidTopColor(); uint32_t solid_bottom = args.SolidBottomColor(); @@ -604,7 +549,7 @@ namespace swrenderer const uint32_t *palette = (const uint32_t *)GPalette.BaseColors; - int index = skipped; + int index = 0; // Top solid color: while (index < start_fadetop_y) @@ -612,7 +557,7 @@ namespace swrenderer *dest = solid_top_fill; dest += pitch; frac += fracstep; - index += num_cores; + index++; } // Top fade: @@ -622,7 +567,7 @@ namespace swrenderer uint8_t fg = source0[sample_index]; uint32_t c = palette[fg]; - int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0); + int alpha_top = max(min(frac >> (16 - start_fade), 256), 0); int inv_alpha_top = 256 - alpha_top; int c_red = RPART(c); int c_green = GPART(c); @@ -634,7 +579,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Textured center: @@ -645,7 +590,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Fade bottom: @@ -655,7 +600,7 @@ namespace swrenderer uint8_t fg = source0[sample_index]; uint32_t c = palette[fg]; - int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + int alpha_bottom = max(min(((2 << 24) - frac) >> (16 - start_fade), 256), 0); int inv_alpha_bottom = 256 - alpha_bottom; int c_red = RPART(c); int c_green = GPART(c); @@ -667,7 +612,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Bottom solid color: @@ -675,11 +620,11 @@ namespace swrenderer { *dest = solid_bottom_fill; dest += pitch; - index += num_cores; + index++; } } - void DrawDoubleSky1PalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawDoubleSkyColumn(const SkyDrawerArgs& args) { uint8_t *dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); @@ -691,38 +636,16 @@ namespace swrenderer int32_t frac = args.TextureVPos(); int32_t fracstep = args.TextureVStep(); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); - int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; - - // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: - int start_fade = 2; // How fast it should fade out - int fade_length = (1 << (24 - start_fade)); - int start_fadetop_y = (-frac) / fracstep; - int end_fadetop_y = (fade_length - frac) / fracstep; - int start_fadebottom_y = ((2 << 24) - fade_length - frac) / fracstep; - int end_fadebottom_y = ((2 << 24) - frac) / fracstep; - start_fadetop_y = clamp(start_fadetop_y, 0, count); - end_fadetop_y = clamp(end_fadetop_y, 0, count); - start_fadebottom_y = clamp(start_fadebottom_y, 0, count); - end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * skipped; - fracstep *= num_cores; - pitch *= num_cores; - + int count = args.Count(); if (!args.FadeSky()) { - count = thread->count_for_thread(args.DestY(), count); - for (int index = 0; index < count; index++) { uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint8_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } @@ -734,6 +657,18 @@ namespace swrenderer return; } + // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: + int start_fade = 2; // How fast it should fade out + int fade_length = (1 << (24 - start_fade)); + int start_fadetop_y = (-frac) / fracstep; + int end_fadetop_y = (fade_length - frac) / fracstep; + int start_fadebottom_y = ((2 << 24) - fade_length - frac) / fracstep; + int end_fadebottom_y = ((2 << 24) - frac) / fracstep; + start_fadetop_y = clamp(start_fadetop_y, 0, count); + end_fadetop_y = clamp(end_fadetop_y, 0, count); + start_fadebottom_y = clamp(start_fadebottom_y, 0, count); + end_fadebottom_y = clamp(end_fadebottom_y, 0, count); + uint32_t solid_top = args.SolidTopColor(); uint32_t solid_bottom = args.SolidBottomColor(); @@ -748,7 +683,7 @@ namespace swrenderer const uint32_t *palette = (const uint32_t *)GPalette.BaseColors; - int index = skipped; + int index = 0; // Top solid color: while (index < start_fadetop_y) @@ -756,7 +691,7 @@ namespace swrenderer *dest = solid_top_fill; dest += pitch; frac += fracstep; - index += num_cores; + index++; } // Top fade: @@ -766,12 +701,12 @@ namespace swrenderer uint8_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } uint32_t c = palette[fg]; - int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0); + int alpha_top = max(min(frac >> (16 - start_fade), 256), 0); int inv_alpha_top = 256 - alpha_top; int c_red = RPART(c); int c_green = GPART(c); @@ -783,7 +718,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Textured center: @@ -793,14 +728,14 @@ namespace swrenderer uint8_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } *dest = fg; frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Fade bottom: @@ -810,12 +745,12 @@ namespace swrenderer uint8_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } uint32_t c = palette[fg]; - int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + int alpha_bottom = max(min(((2 << 24) - frac) >> (16 - start_fade), 256), 0); int inv_alpha_bottom = 256 - alpha_bottom; int c_red = RPART(c); int c_green = GPART(c); @@ -827,7 +762,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Bottom solid color: @@ -835,17 +770,13 @@ namespace swrenderer { *dest = solid_bottom_fill; dest += pitch; - index += num_cores; + index++; } } ///////////////////////////////////////////////////////////////////////// - PalColumnCommand::PalColumnCommand(const SpriteDrawerArgs &args) : args(args) - { - } - - uint8_t PalColumnCommand::AddLights(uint8_t fg, uint8_t material, uint32_t lit_r, uint32_t lit_g, uint32_t lit_b) + uint8_t SWPalDrawers::AddLights(uint8_t fg, uint8_t material, uint32_t lit_r, uint32_t lit_g, uint32_t lit_b) { if (lit_r == 0 && lit_g == 0 && lit_b == 0) return fg; @@ -854,14 +785,14 @@ namespace swrenderer uint32_t material_g = GPalette.BaseColors[material].g; uint32_t material_b = GPalette.BaseColors[material].b; - lit_r = MIN(GPalette.BaseColors[fg].r + ((lit_r * material_r) >> 8), 255); - lit_g = MIN(GPalette.BaseColors[fg].g + ((lit_g * material_g) >> 8), 255); - lit_b = MIN(GPalette.BaseColors[fg].b + ((lit_b * material_b) >> 8), 255); + lit_r = min(GPalette.BaseColors[fg].r + ((lit_r * material_r) >> 8), 255); + lit_g = min(GPalette.BaseColors[fg].g + ((lit_g * material_g) >> 8), 255); + lit_b = min(GPalette.BaseColors[fg].b + ((lit_b * material_b) >> 8), 255); return RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)]; } - void DrawColumnPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawColumn(const SpriteDrawerArgs& args) { int count; uint8_t *dest; @@ -869,6 +800,8 @@ namespace swrenderer fixed_t fracstep; count = args.Count(); + if (count <= 0) + return; // Framebuffer destination address. dest = args.Dest(); @@ -878,15 +811,7 @@ namespace swrenderer fracstep = args.TextureVStep(); frac = args.TextureVPos(); - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; // [RH] Get local copies of these variables so that the compiler // has a better chance of optimizing this well. @@ -911,9 +836,9 @@ namespace swrenderer uint32_t lit_g = GPART(dynlight); uint32_t lit_b = BPART(dynlight); uint32_t light = 256 - (args.Light() >> (FRACBITS - 8)); - lit_r = MIN(light + lit_r, 256); - lit_g = MIN(light + lit_g, 256); - lit_b = MIN(light + lit_b, 256); + lit_r = min(light + lit_r, 256); + lit_g = min(light + lit_g, 256); + lit_b = min(light + lit_b, 256); lit_r = lit_r - light; lit_g = lit_g - light; lit_b = lit_b - light; @@ -931,21 +856,15 @@ namespace swrenderer } } - void FillColumnPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::FillColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - - count = args.Count(); - dest = args.Dest(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); + int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - pitch *= thread->num_cores; uint8_t color = args.SolidColor(); do @@ -955,26 +874,17 @@ namespace swrenderer } while (--count); } - void FillColumnAddPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::FillAddColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - - count = args.Count(); - dest = args.Dest(); - uint32_t *bg2rgb; - uint32_t fg; - - bg2rgb = args.DestBlend(); - fg = args.SrcColorIndex(); - int pitch = args.Viewport()->RenderTarget->GetPitch(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - pitch *= thread->num_cores; + uint8_t* dest = args.Dest(); + int pitch = args.Viewport()->RenderTarget->GetPitch(); + + uint32_t *bg2rgb = args.DestBlend(); + uint32_t fg = args.SrcColorIndex(); const PalEntry* pal = GPalette.BaseColors; @@ -1007,12 +917,14 @@ namespace swrenderer } } - void FillColumnAddClampPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::FillAddClampColumn(const SpriteDrawerArgs& args) { int count; uint8_t *dest; count = args.Count(); + if (count <= 0) + return; dest = args.Dest(); uint32_t *bg2rgb; @@ -1022,13 +934,6 @@ namespace swrenderer fg = args.SrcColorIndex(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - pitch *= thread->num_cores; - const PalEntry* pal = GPalette.BaseColors; if (!r_blendmethod) @@ -1066,26 +971,18 @@ namespace swrenderer } } - void FillColumnSubClampPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::FillSubClampColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; + int count = args.Count(); + if (count <= 0) + return; - count = args.Count(); + uint8_t* dest = args.Dest(); + int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = args.Dest(); uint32_t *bg2rgb = args.DestBlend(); uint32_t fg = args.SrcColorIndex(); - int pitch = args.Viewport()->RenderTarget->GetPitch(); - - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - pitch *= thread->num_cores; - const PalEntry* palette = GPalette.BaseColors; if (!r_blendmethod) @@ -1114,9 +1011,9 @@ namespace swrenderer int src_g = ((srccolor >> 0) & 0xff) * srcalpha; int src_b = ((srccolor >> 8) & 0xff) * srcalpha; int bg = *dest; - int r = MAX((-src_r + palette[bg].r * destalpha)>>18, 0); - int g = MAX((-src_g + palette[bg].g * destalpha)>>18, 0); - int b = MAX((-src_b + palette[bg].b * destalpha)>>18, 0); + int r = max((-src_r + palette[bg].r * destalpha)>>18, 0); + int g = max((-src_g + palette[bg].g * destalpha)>>18, 0); + int b = max((-src_b + palette[bg].b * destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; dest += pitch; @@ -1124,27 +1021,17 @@ namespace swrenderer } } - void FillColumnRevSubClampPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::FillRevSubClampColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - - count = args.Count(); + int count = args.Count(); if (count <= 0) return; - dest = args.Dest(); - uint32_t *bg2rgb = args.DestBlend(); - uint32_t fg = args.SrcColorIndex(); - + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - count = thread->count_for_thread(args.DestY(), count); - if (count <= 0) - return; - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - pitch *= thread->num_cores; + uint32_t *bg2rgb = args.DestBlend(); + uint32_t fg = args.SrcColorIndex(); const PalEntry *palette = GPalette.BaseColors; @@ -1174,9 +1061,9 @@ namespace swrenderer int src_g = ((srccolor >> 0) & 0xff) * srcalpha; int src_b = ((srccolor >> 8) & 0xff) * srcalpha; int bg = *dest; - int r = MAX((src_r - palette[bg].r * destalpha)>>18, 0); - int g = MAX((src_g - palette[bg].g * destalpha)>>18, 0); - int b = MAX((src_b - palette[bg].b * destalpha)>>18, 0); + int r = max((src_r - palette[bg].r * destalpha)>>18, 0); + int g = max((src_g - palette[bg].g * destalpha)>>18, 0); + int b = max((src_b - palette[bg].b * destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; dest += pitch; @@ -1184,28 +1071,17 @@ namespace swrenderer } } - void DrawColumnAddPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawAddColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); uint32_t *fg2rgb = args.SrcBlend(); uint32_t *bg2rgb = args.DestBlend(); @@ -1237,9 +1113,9 @@ namespace swrenderer { uint32_t fg = colormap[source[frac >> FRACBITS]]; uint32_t bg = *dest; - uint32_t r = MIN((palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 63); - uint32_t g = MIN((palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 63); - uint32_t b = MIN((palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 63); + uint32_t r = min((palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 63); + uint32_t g = min((palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 63); + uint32_t b = min((palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 63); *dest = RGB256k.RGB[r][g][b]; dest += pitch; frac += fracstep; @@ -1247,29 +1123,17 @@ namespace swrenderer } } - void DrawColumnTranslatedPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawTranslatedColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t* dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); // [RH] Local copies of global vars to improve compiler optimizations const uint8_t *colormap = args.Colormap(args.Viewport()); @@ -1285,28 +1149,17 @@ namespace swrenderer } while (--count); } - void DrawColumnTlatedAddPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawTranslatedAddColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); uint32_t *fg2rgb = args.SrcBlend(); uint32_t *bg2rgb = args.DestBlend(); @@ -1339,9 +1192,9 @@ namespace swrenderer { uint32_t fg = colormap[translation[source[frac >> FRACBITS]]]; uint32_t bg = *dest; - uint32_t r = MIN((palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 63); - uint32_t g = MIN((palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 63); - uint32_t b = MIN((palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 63); + uint32_t r = min((palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 63); + uint32_t g = min((palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 63); + uint32_t b = min((palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 63); *dest = RGB256k.RGB[r][g][b]; dest += pitch; frac += fracstep; @@ -1349,27 +1202,17 @@ namespace swrenderer } } - void DrawColumnShadedPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawShadedColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac, fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); const uint8_t *source = args.TexturePixels(); const uint8_t *colormap = args.Colormap(args.Viewport()); @@ -1413,27 +1256,17 @@ namespace swrenderer } } - void DrawColumnAddClampShadedPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawAddClampShadedColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac, fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); const uint8_t *source = args.TexturePixels(); const uint8_t *colormap = args.Colormap(args.Viewport()); @@ -1455,28 +1288,17 @@ namespace swrenderer } while (--count); } - void DrawColumnAddClampPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawAddClampColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); const uint8_t *colormap = args.Colormap(args.Viewport()); const uint8_t *source = args.TexturePixels(); @@ -1509,9 +1331,9 @@ namespace swrenderer { int fg = colormap[source[frac >> FRACBITS]]; int bg = *dest; - int r = MIN((palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 63); - int g = MIN((palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 63); - int b = MIN((palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 63); + int r = min((palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 63); + int g = min((palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 63); + int b = min((palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 63); *dest = RGB256k.RGB[r][g][b]; dest += pitch; frac += fracstep; @@ -1519,28 +1341,17 @@ namespace swrenderer } } - void DrawColumnAddClampTranslatedPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawAddClampTranslatedColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); const uint8_t *translation = args.TranslationMap(); const uint8_t *colormap = args.Colormap(args.Viewport()); @@ -1574,9 +1385,9 @@ namespace swrenderer { int fg = colormap[translation[source[frac >> FRACBITS]]]; int bg = *dest; - int r = MIN((palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 63); - int g = MIN((palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 63); - int b = MIN((palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 63); + int r = min((palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 63); + int g = min((palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 63); + int b = min((palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 63); *dest = RGB256k.RGB[r][g][b]; dest += pitch; frac += fracstep; @@ -1584,28 +1395,17 @@ namespace swrenderer } } - void DrawColumnSubClampPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawSubClampColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); const uint8_t *colormap = args.Colormap(args.Viewport()); const uint8_t *source = args.TexturePixels(); @@ -1637,9 +1437,9 @@ namespace swrenderer { int fg = colormap[source[frac >> FRACBITS]]; int bg = *dest; - int r = MAX((palette[fg].r * srcalpha - palette[bg].r * destalpha)>>18, 0); - int g = MAX((palette[fg].g * srcalpha - palette[bg].g * destalpha)>>18, 0); - int b = MAX((palette[fg].b * srcalpha - palette[bg].b * destalpha)>>18, 0); + int r = max((palette[fg].r * srcalpha - palette[bg].r * destalpha)>>18, 0); + int g = max((palette[fg].g * srcalpha - palette[bg].g * destalpha)>>18, 0); + int b = max((palette[fg].b * srcalpha - palette[bg].b * destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; dest += pitch; frac += fracstep; @@ -1647,28 +1447,17 @@ namespace swrenderer } } - void DrawColumnSubClampTranslatedPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawSubClampTranslatedColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); const uint8_t *translation = args.TranslationMap(); const uint8_t *colormap = args.Colormap(args.Viewport()); @@ -1701,9 +1490,9 @@ namespace swrenderer { int fg = colormap[translation[source[frac >> FRACBITS]]]; int bg = *dest; - int r = MAX((palette[fg].r * srcalpha - palette[bg].r * destalpha)>>18, 0); - int g = MAX((palette[fg].g * srcalpha - palette[bg].g * destalpha)>>18, 0); - int b = MAX((palette[fg].b * srcalpha - palette[bg].b * destalpha)>>18, 0); + int r = max((palette[fg].r * srcalpha - palette[bg].r * destalpha)>>18, 0); + int g = max((palette[fg].g * srcalpha - palette[bg].g * destalpha)>>18, 0); + int b = max((palette[fg].b * srcalpha - palette[bg].b * destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; dest += pitch; frac += fracstep; @@ -1711,28 +1500,17 @@ namespace swrenderer } } - void DrawColumnRevSubClampPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawRevSubClampColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); const uint8_t *colormap = args.Colormap(args.Viewport()); const uint8_t *source = args.TexturePixels(); @@ -1764,9 +1542,9 @@ namespace swrenderer { int fg = colormap[source[frac >> FRACBITS]]; int bg = *dest; - int r = MAX((-palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 0); - int g = MAX((-palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 0); - int b = MAX((-palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 0); + int r = max((-palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 0); + int g = max((-palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 0); + int b = max((-palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; dest += pitch; frac += fracstep; @@ -1774,28 +1552,17 @@ namespace swrenderer } } - void DrawColumnRevSubClampTranslatedPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawRevSubClampTranslatedColumn(const SpriteDrawerArgs& args) { - int count; - uint8_t *dest; - fixed_t frac; - fixed_t fracstep; - - count = args.Count(); - dest = args.Dest(); - - fracstep = args.TextureVStep(); - frac = args.TextureVPos(); - - count = thread->count_for_thread(args.DestY(), count); + int count = args.Count(); if (count <= 0) return; + uint8_t* dest = args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * thread->skipped_by_thread(args.DestY()); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + + fixed_t fracstep = args.TextureVStep(); + fixed_t frac = args.TextureVPos(); const uint8_t *translation = args.TranslationMap(); const uint8_t *colormap = args.Colormap(args.Viewport()); @@ -1828,9 +1595,9 @@ namespace swrenderer { int fg = colormap[translation[source[frac >> FRACBITS]]]; int bg = *dest; - int r = MAX((-palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 0); - int g = MAX((-palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 0); - int b = MAX((-palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 0); + int r = max((-palette[fg].r * srcalpha + palette[bg].r * destalpha)>>18, 0); + int g = max((-palette[fg].g * srcalpha + palette[bg].g * destalpha)>>18, 0); + int b = max((-palette[fg].b * srcalpha + palette[bg].b * destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; dest += pitch; frac += fracstep; @@ -1840,24 +1607,21 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - DrawScaledFuzzColumnPalCommand::DrawScaledFuzzColumnPalCommand(const SpriteDrawerArgs &drawerargs) + void SWPalDrawers::DrawScaledFuzzColumn(const SpriteDrawerArgs& args) { - _x = drawerargs.FuzzX(); - _yl = drawerargs.FuzzY1(); - _yh = drawerargs.FuzzY2(); - _destorg = drawerargs.Viewport()->GetDest(0, 0); - _pitch = drawerargs.Viewport()->RenderTarget->GetPitch(); - _fuzzpos = fuzzpos; - _fuzzviewheight = fuzzviewheight; - } + int _yl = args.FuzzY1(); + int _yh = args.FuzzY2(); + int _x = args.FuzzX(); + uint8_t* _destorg = args.Viewport()->GetDest(0, 0); + int _pitch = args.Viewport()->RenderTarget->GetPitch(); + int _fuzzpos = fuzzpos; + int _fuzzviewheight = fuzzviewheight; - void DrawScaledFuzzColumnPalCommand::Execute(DrawerThread *thread) - { int x = _x; - int yl = MAX(_yl, 1); - int yh = MIN(_yh, _fuzzviewheight); + int yl = max(_yl, 1); + int yh = min(_yh, _fuzzviewheight); - int count = thread->count_for_thread(yl, yh - yl + 1); + int count = yh - yl + 1; if (count <= 0) return; int pitch = _pitch; @@ -1868,14 +1632,7 @@ namespace swrenderer fixed_t fuzzstep = (200 << FRACBITS) / _fuzzviewheight; fixed_t fuzzcount = FUZZTABLE << FRACBITS; - fixed_t fuzz = (fuzz_x << FRACBITS) + yl * fuzzstep; - - dest = thread->dest_for_thread(yl, pitch, dest); - pitch *= thread->num_cores; - - fuzz += fuzzstep * thread->skipped_by_thread(yl); - fuzz %= fuzzcount; - fuzzstep *= thread->num_cores; + fixed_t fuzz = ((fuzz_x << FRACBITS) + yl * fuzzstep) % fuzzcount; uint8_t *map = NormalLight.Maps; @@ -1894,34 +1651,30 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////// - DrawFuzzColumnPalCommand::DrawFuzzColumnPalCommand(const SpriteDrawerArgs &args) + void SWPalDrawers::DrawUnscaledFuzzColumn(const SpriteDrawerArgs& args) { - _yl = args.FuzzY1(); - _yh = args.FuzzY2(); - _x = args.FuzzX(); - _destorg = args.Viewport()->GetDest(0, 0); - _pitch = args.Viewport()->RenderTarget->GetPitch(); - _fuzzpos = fuzzpos; - _fuzzviewheight = fuzzviewheight; - } + int _yl = args.FuzzY1(); + int _yh = args.FuzzY2(); + int _x = args.FuzzX(); + uint8_t* _destorg = args.Viewport()->GetDest(0, 0); + int _pitch = args.Viewport()->RenderTarget->GetPitch(); + int _fuzzpos = fuzzpos; + int _fuzzviewheight = fuzzviewheight; - void DrawFuzzColumnPalCommand::Execute(DrawerThread *thread) - { - int yl = MAX(_yl, 1); - int yh = MIN(_yh, _fuzzviewheight); + int yl = max(_yl, 1); + int yh = min(_yh, _fuzzviewheight); - int count = thread->count_for_thread(yl, yh - yl + 1); + int count = yh - yl + 1; // Zero length. if (count <= 0) return; int pitch = _pitch; - uint8_t *dest = thread->dest_for_thread(yl, pitch, yl * pitch + _x + _destorg); + uint8_t *dest = yl * pitch + _x + _destorg; - pitch = pitch * thread->num_cores; - int fuzzstep = thread->num_cores; - int fuzz = (_fuzzpos + thread->skipped_by_thread(yl)) % FUZZTABLE; + int fuzzstep = 1; + int fuzz = _fuzzpos % FUZZTABLE; #ifndef ORIGINAL_FUZZ @@ -1934,7 +1687,7 @@ namespace swrenderer if (available % fuzzstep != 0) next_wrap++; - int cnt = MIN(count, next_wrap); + int cnt = min(count, next_wrap); count -= cnt; do { @@ -1952,8 +1705,6 @@ namespace swrenderer uint8_t *map = &NormalLight.Maps[6 * 256]; - yl += thread->skipped_by_thread(yl); - // Handle the case where we would go out of bounds at the top: if (yl < fuzzstep) { @@ -1982,7 +1733,7 @@ namespace swrenderer if (available % fuzzstep != 0) next_wrap++; - int cnt = MIN(count, next_wrap); + int cnt = min(count, next_wrap); count -= cnt; do { @@ -2010,32 +1761,7 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////// - PalSpanCommand::PalSpanCommand(const SpanDrawerArgs &args) - { - _source = args.TexturePixels(); - _colormap = args.Colormap(args.Viewport()); - _xfrac = args.TextureUPos(); - _yfrac = args.TextureVPos(); - _y = args.DestY(); - _x1 = args.DestX1(); - _x2 = args.DestX2(); - _dest = args.Viewport()->GetDest(_x1, _y); - _xstep = args.TextureUStep(); - _ystep = args.TextureVStep(); - _srcwidth = args.TextureWidth(); - _srcheight = args.TextureHeight(); - _srcblend = args.SrcBlend(); - _destblend = args.DestBlend(); - _color = args.SolidColor(); - _srcalpha = args.SrcAlpha(); - _destalpha = args.DestAlpha(); - _dynlights = args.dc_lights; - _num_dynlights = args.dc_num_lights; - _viewpos_x = args.dc_viewpos.X; - _step_viewpos_x = args.dc_viewpos_step.X; - } - - uint8_t PalSpanCommand::AddLights(const DrawerLight *lights, int num_lights, float viewpos_x, uint8_t fg, uint8_t material) + uint8_t SWPalDrawers::AddLightsSpan(const DrawerLight *lights, int num_lights, float viewpos_x, uint8_t fg, uint8_t material) { uint32_t lit_r = 0; uint32_t lit_g = 0; @@ -2049,7 +1775,7 @@ namespace swrenderer // L = light-pos // dist = sqrt(dot(L, L)) - // attenuation = 1 - MIN(dist * (1/radius), 1) + // attenuation = 1 - min(dist * (1/radius), 1) float Lyz2 = lights[i].y; // L.y*L.y + L.z*L.z float Lx = lights[i].x - viewpos_x; float dist2 = Lyz2 + Lx * Lx; @@ -2059,7 +1785,7 @@ namespace swrenderer float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2))); #endif float dist = dist2 * rcp_dist; - float distance_attenuation = (256.0f - MIN(dist * lights[i].radius, 256.0f)); + float distance_attenuation = (256.0f - min(dist * lights[i].radius, 256.0f)); // The simple light type float simple_attenuation = distance_attenuation; @@ -2081,17 +1807,103 @@ namespace swrenderer uint32_t material_g = GPalette.BaseColors[material].g; uint32_t material_b = GPalette.BaseColors[material].b; - lit_r = MIN(GPalette.BaseColors[fg].r + ((lit_r * material_r) >> 8), 255); - lit_g = MIN(GPalette.BaseColors[fg].g + ((lit_g * material_g) >> 8), 255); - lit_b = MIN(GPalette.BaseColors[fg].b + ((lit_b * material_b) >> 8), 255); + lit_r = min(GPalette.BaseColors[fg].r + ((lit_r * material_r) >> 8), 255); + lit_g = min(GPalette.BaseColors[fg].g + ((lit_g * material_g) >> 8), 255); + lit_b = min(GPalette.BaseColors[fg].b + ((lit_b * material_b) >> 8), 255); return RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)]; } - void DrawSpanPalCommand::Execute(DrawerThread *thread) + uint8_t SWPalDrawers::AddLightsTilted(const DrawerLight* lights, int num_lights, float viewpos_x, float viewpos_y, float viewpos_z, float nx, float ny, float nz, uint8_t fg, uint8_t material) { - if (thread->line_skipped_by_thread(_y)) - return; + uint32_t lit_r = 0; + uint32_t lit_g = 0; + uint32_t lit_b = 0; + + // Screen space to view space + viewpos_z = 1.0f / viewpos_z; + viewpos_x *= viewpos_z; + viewpos_y *= viewpos_z; + + for (int i = 0; i < num_lights; i++) + { + uint32_t light_color_r = RPART(lights[i].color); + uint32_t light_color_g = GPART(lights[i].color); + uint32_t light_color_b = BPART(lights[i].color); + + // L = light-pos + // dist = sqrt(dot(L, L)) + // attenuation = 1 - min(dist * (1/radius), 1) + float Lx = lights[i].x - viewpos_x; + float Ly = lights[i].y - viewpos_y; + float Lz = lights[i].z - viewpos_z; + float dist2 = Lx * Lx + Ly * Ly + Lz * Lz; +#ifdef NO_SSE + float rcp_dist = 1.0f / (dist2 * 0.01f); +#else + float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2))); +#endif + Lx *= rcp_dist; + Ly *= rcp_dist; + Lz *= rcp_dist; + float dist = dist2 * rcp_dist; + float radius = lights[i].radius; + bool simpleType = radius < 0.0f; + if (simpleType) + radius = -radius; + float distance_attenuation = (256.0f - min(dist * radius, 256.0f)); + + // The simple light type + float simple_attenuation = distance_attenuation; + + // The point light type + // diffuse = dot(N,L) * attenuation + float dotNL = max(nx * Lx + ny * Ly + nz * Lz, 0.0f); + float point_attenuation = dotNL * distance_attenuation; + uint32_t attenuation = (uint32_t)(simpleType ? simple_attenuation : point_attenuation); + + lit_r += (light_color_r * attenuation) >> 8; + lit_g += (light_color_g * attenuation) >> 8; + lit_b += (light_color_b * attenuation) >> 8; + } + + if (lit_r == 0 && lit_g == 0 && lit_b == 0) + return fg; + + uint32_t material_r = GPalette.BaseColors[material].r; + uint32_t material_g = GPalette.BaseColors[material].g; + uint32_t material_b = GPalette.BaseColors[material].b; + + lit_r = min(GPalette.BaseColors[fg].r + ((lit_r * material_r) >> 8), 255); + lit_g = min(GPalette.BaseColors[fg].g + ((lit_g * material_g) >> 8), 255); + lit_b = min(GPalette.BaseColors[fg].b + ((lit_b * material_b) >> 8), 255); + + return RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)]; + } + + void SWPalDrawers::DrawSpan(const SpanDrawerArgs& args) + { + const uint8_t* _source = args.TexturePixels(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint32_t _xfrac = args.TextureUPos(); + uint32_t _yfrac = args.TextureVPos(); + int _y = args.DestY(); + int _x1 = args.DestX1(); + int _x2 = args.DestX2(); + uint8_t* _dest = args.Viewport()->GetDest(_x1, _y); + uint32_t _xstep = args.TextureUStep(); + uint32_t _ystep = args.TextureVStep(); + int _srcwidth = args.TextureWidth(); + int _srcheight = args.TextureHeight(); + uint32_t* _srcblend = args.SrcBlend(); + uint32_t* _destblend = args.DestBlend(); + int _color = args.SolidColor(); + fixed_t _srcalpha = args.SrcAlpha(); + fixed_t _destalpha = args.DestAlpha(); + DrawerLight* _dynlights = args.dc_lights; + int _num_dynlights = args.dc_num_lights; + float _viewpos_x = args.dc_viewpos.X; + float _step_viewpos_x = args.dc_viewpos_step.X; uint32_t xfrac; uint32_t yfrac; @@ -2145,7 +1957,7 @@ namespace swrenderer // Lookup pixel from flat texture tile, // re-index using light/colormap. - *dest++ = AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]); + *dest++ = AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]); // Next step in u,v. xfrac += xstep; @@ -2165,7 +1977,7 @@ namespace swrenderer // Lookup pixel from flat texture tile, // re-index using light/colormap. - *dest++ = AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]); + *dest++ = AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]); // Next step in u,v. xfrac += xstep; @@ -2175,10 +1987,29 @@ namespace swrenderer } } - void DrawSpanMaskedPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawSpanMasked(const SpanDrawerArgs& args) { - if (thread->line_skipped_by_thread(_y)) - return; + const uint8_t* _source = args.TexturePixels(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint32_t _xfrac = args.TextureUPos(); + uint32_t _yfrac = args.TextureVPos(); + int _y = args.DestY(); + int _x1 = args.DestX1(); + int _x2 = args.DestX2(); + uint8_t* _dest = args.Viewport()->GetDest(_x1, _y); + uint32_t _xstep = args.TextureUStep(); + uint32_t _ystep = args.TextureVStep(); + int _srcwidth = args.TextureWidth(); + int _srcheight = args.TextureHeight(); + uint32_t* _srcblend = args.SrcBlend(); + uint32_t* _destblend = args.DestBlend(); + int _color = args.SolidColor(); + fixed_t _srcalpha = args.SrcAlpha(); + fixed_t _destalpha = args.DestAlpha(); + DrawerLight* _dynlights = args.dc_lights; + int _num_dynlights = args.dc_num_lights; + float _viewpos_x = args.dc_viewpos.X; + float _step_viewpos_x = args.dc_viewpos_step.X; uint32_t xfrac; uint32_t yfrac; @@ -2216,7 +2047,7 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - *dest = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + *dest = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; } dest++; xfrac += xstep; @@ -2237,7 +2068,7 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - *dest = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + *dest = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; } dest++; xfrac += xstep; @@ -2247,10 +2078,29 @@ namespace swrenderer } } - void DrawSpanTranslucentPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawSpanTranslucent(const SpanDrawerArgs& args) { - if (thread->line_skipped_by_thread(_y)) - return; + const uint8_t* _source = args.TexturePixels(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint32_t _xfrac = args.TextureUPos(); + uint32_t _yfrac = args.TextureVPos(); + int _y = args.DestY(); + int _x1 = args.DestX1(); + int _x2 = args.DestX2(); + uint8_t* _dest = args.Viewport()->GetDest(_x1, _y); + uint32_t _xstep = args.TextureUStep(); + uint32_t _ystep = args.TextureVStep(); + int _srcwidth = args.TextureWidth(); + int _srcheight = args.TextureHeight(); + uint32_t* _srcblend = args.SrcBlend(); + uint32_t* _destblend = args.DestBlend(); + int _color = args.SolidColor(); + fixed_t _srcalpha = args.SrcAlpha(); + fixed_t _destalpha = args.DestAlpha(); + DrawerLight* _dynlights = args.dc_lights; + int _num_dynlights = args.dc_num_lights; + float _viewpos_x = args.dc_viewpos.X; + float _step_viewpos_x = args.dc_viewpos_step.X; uint32_t xfrac; uint32_t yfrac; @@ -2289,7 +2139,7 @@ namespace swrenderer do { spot = ((xfrac >> (32 - 6 - 6))&(63 * 64)) + (yfrac >> (32 - 6)); - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; uint32_t bg = *dest; fg = fg2rgb[fg]; bg = bg2rgb[bg]; @@ -2308,7 +2158,7 @@ namespace swrenderer do { spot = (((xfrac >> 16) * srcwidth) >> 16) * srcheight + (((yfrac >> 16) * srcheight) >> 16); - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; uint32_t bg = *dest; fg = fg2rgb[fg]; bg = bg2rgb[bg]; @@ -2328,11 +2178,11 @@ namespace swrenderer do { spot = ((xfrac >> (32 - 6 - 6))&(63 * 64)) + (yfrac >> (32 - 6)); - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; uint32_t bg = *dest; - int r = MAX((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); - int g = MAX((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); - int b = MAX((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); + int r = max((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); + int g = max((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); + int b = max((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); *dest++ = RGB256k.RGB[r][g][b]; xfrac += xstep; @@ -2348,11 +2198,11 @@ namespace swrenderer do { spot = (((xfrac >> 16) * srcwidth) >> 16) * srcheight + (((yfrac >> 16) * srcheight) >> 16); - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; uint32_t bg = *dest; - int r = MAX((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); - int g = MAX((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); - int b = MAX((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); + int r = max((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); + int g = max((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); + int b = max((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); *dest++ = RGB256k.RGB[r][g][b]; xfrac += xstep; @@ -2363,10 +2213,29 @@ namespace swrenderer } } - void DrawSpanMaskedTranslucentPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawSpanMaskedTranslucent(const SpanDrawerArgs& args) { - if (thread->line_skipped_by_thread(_y)) - return; + const uint8_t* _source = args.TexturePixels(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint32_t _xfrac = args.TextureUPos(); + uint32_t _yfrac = args.TextureVPos(); + int _y = args.DestY(); + int _x1 = args.DestX1(); + int _x2 = args.DestX2(); + uint8_t* _dest = args.Viewport()->GetDest(_x1, _y); + uint32_t _xstep = args.TextureUStep(); + uint32_t _ystep = args.TextureVStep(); + int _srcwidth = args.TextureWidth(); + int _srcheight = args.TextureHeight(); + uint32_t* _srcblend = args.SrcBlend(); + uint32_t* _destblend = args.DestBlend(); + int _color = args.SolidColor(); + fixed_t _srcalpha = args.SrcAlpha(); + fixed_t _destalpha = args.DestAlpha(); + DrawerLight* _dynlights = args.dc_lights; + int _num_dynlights = args.dc_num_lights; + float _viewpos_x = args.dc_viewpos.X; + float _step_viewpos_x = args.dc_viewpos_step.X; uint32_t xfrac; uint32_t yfrac; @@ -2410,7 +2279,7 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; uint32_t bg = *dest; fg = fg2rgb[fg]; bg = bg2rgb[bg]; @@ -2436,7 +2305,7 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; uint32_t bg = *dest; fg = fg2rgb[fg]; bg = bg2rgb[bg]; @@ -2463,11 +2332,11 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; uint32_t bg = *dest; - int r = MAX((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); - int g = MAX((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); - int b = MAX((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); + int r = max((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); + int g = max((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); + int b = max((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; } dest++; @@ -2489,11 +2358,11 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; uint32_t bg = *dest; - int r = MAX((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); - int g = MAX((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); - int b = MAX((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); + int r = max((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); + int g = max((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); + int b = max((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; } dest++; @@ -2505,10 +2374,29 @@ namespace swrenderer } } - void DrawSpanAddClampPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawSpanAddClamp(const SpanDrawerArgs& args) { - if (thread->line_skipped_by_thread(_y)) - return; + const uint8_t* _source = args.TexturePixels(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint32_t _xfrac = args.TextureUPos(); + uint32_t _yfrac = args.TextureVPos(); + int _y = args.DestY(); + int _x1 = args.DestX1(); + int _x2 = args.DestX2(); + uint8_t* _dest = args.Viewport()->GetDest(_x1, _y); + uint32_t _xstep = args.TextureUStep(); + uint32_t _ystep = args.TextureVStep(); + int _srcwidth = args.TextureWidth(); + int _srcheight = args.TextureHeight(); + uint32_t* _srcblend = args.SrcBlend(); + uint32_t* _destblend = args.DestBlend(); + int _color = args.SolidColor(); + fixed_t _srcalpha = args.SrcAlpha(); + fixed_t _destalpha = args.DestAlpha(); + DrawerLight* _dynlights = args.dc_lights; + int _num_dynlights = args.dc_num_lights; + float _viewpos_x = args.dc_viewpos.X; + float _step_viewpos_x = args.dc_viewpos_step.X; uint32_t xfrac; uint32_t yfrac; @@ -2546,7 +2434,7 @@ namespace swrenderer do { spot = ((xfrac >> (32 - 6 - 6))&(63 * 64)) + (yfrac >> (32 - 6)); - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; uint32_t a = fg2rgb[fg] + bg2rgb[*dest]; uint32_t b = a; @@ -2569,7 +2457,7 @@ namespace swrenderer do { spot = (((xfrac >> 16) * srcwidth) >> 16) * srcheight + (((yfrac >> 16) * srcheight) >> 16); - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; uint32_t a = fg2rgb[fg] + bg2rgb[*dest]; uint32_t b = a; @@ -2593,11 +2481,11 @@ namespace swrenderer do { spot = ((xfrac >> (32 - 6 - 6))&(63 * 64)) + (yfrac >> (32 - 6)); - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; uint32_t bg = *dest; - int r = MAX((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); - int g = MAX((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); - int b = MAX((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); + int r = max((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); + int g = max((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); + int b = max((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); *dest++ = RGB256k.RGB[r][g][b]; xfrac += xstep; @@ -2613,11 +2501,11 @@ namespace swrenderer do { spot = (((xfrac >> 16) * srcwidth) >> 16) * srcheight + (((yfrac >> 16) * srcheight) >> 16); - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[source[spot]], source[spot]) : colormap[source[spot]]; uint32_t bg = *dest; - int r = MAX((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); - int g = MAX((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); - int b = MAX((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); + int r = max((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); + int g = max((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); + int b = max((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); *dest++ = RGB256k.RGB[r][g][b]; xfrac += xstep; @@ -2628,10 +2516,29 @@ namespace swrenderer } } - void DrawSpanMaskedAddClampPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawSpanMaskedAddClamp(const SpanDrawerArgs& args) { - if (thread->line_skipped_by_thread(_y)) - return; + const uint8_t* _source = args.TexturePixels(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint32_t _xfrac = args.TextureUPos(); + uint32_t _yfrac = args.TextureVPos(); + int _y = args.DestY(); + int _x1 = args.DestX1(); + int _x2 = args.DestX2(); + uint8_t* _dest = args.Viewport()->GetDest(_x1, _y); + uint32_t _xstep = args.TextureUStep(); + uint32_t _ystep = args.TextureVStep(); + int _srcwidth = args.TextureWidth(); + int _srcheight = args.TextureHeight(); + uint32_t* _srcblend = args.SrcBlend(); + uint32_t* _destblend = args.DestBlend(); + int _color = args.SolidColor(); + fixed_t _srcalpha = args.SrcAlpha(); + fixed_t _destalpha = args.DestAlpha(); + DrawerLight* _dynlights = args.dc_lights; + int _num_dynlights = args.dc_num_lights; + float _viewpos_x = args.dc_viewpos.X; + float _step_viewpos_x = args.dc_viewpos_step.X; uint32_t xfrac; uint32_t yfrac; @@ -2674,7 +2581,7 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; uint32_t a = fg2rgb[fg] + bg2rgb[*dest]; uint32_t b = a; @@ -2704,7 +2611,7 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; uint32_t a = fg2rgb[fg] + bg2rgb[*dest]; uint32_t b = a; @@ -2735,11 +2642,11 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; uint32_t bg = *dest; - int r = MAX((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); - int g = MAX((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); - int b = MAX((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); + int r = max((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); + int g = max((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); + int b = max((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; } dest++; @@ -2761,11 +2668,11 @@ namespace swrenderer texdata = source[spot]; if (texdata != 0) { - uint32_t fg = num_dynlights != 0 ? AddLights(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; + uint32_t fg = num_dynlights != 0 ? AddLightsSpan(dynlights, num_dynlights, viewpos_x, colormap[texdata], texdata) : colormap[texdata]; uint32_t bg = *dest; - int r = MAX((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); - int g = MAX((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); - int b = MAX((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); + int r = max((palette[fg].r * _srcalpha + palette[bg].r * _destalpha)>>18, 0); + int g = max((palette[fg].g * _srcalpha + palette[bg].g * _destalpha)>>18, 0); + int b = max((palette[fg].b * _srcalpha + palette[bg].b * _destalpha)>>18, 0); *dest = RGB256k.RGB[r][g][b]; } dest++; @@ -2777,37 +2684,49 @@ namespace swrenderer } } - void FillSpanPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::FillSpan(const SpanDrawerArgs& args) { - if (thread->line_skipped_by_thread(_y)) - return; + const uint8_t* _source = args.TexturePixels(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint32_t _xfrac = args.TextureUPos(); + uint32_t _yfrac = args.TextureVPos(); + int _y = args.DestY(); + int _x1 = args.DestX1(); + int _x2 = args.DestX2(); + uint8_t* _dest = args.Viewport()->GetDest(_x1, _y); + uint32_t _xstep = args.TextureUStep(); + uint32_t _ystep = args.TextureVStep(); + int _srcwidth = args.TextureWidth(); + int _srcheight = args.TextureHeight(); + uint32_t* _srcblend = args.SrcBlend(); + uint32_t* _destblend = args.DestBlend(); + int _color = args.SolidColor(); + fixed_t _srcalpha = args.SrcAlpha(); + fixed_t _destalpha = args.DestAlpha(); + DrawerLight* _dynlights = args.dc_lights; + int _num_dynlights = args.dc_num_lights; + float _viewpos_x = args.dc_viewpos.X; + float _step_viewpos_x = args.dc_viewpos_step.X; memset(_dest, _color, _x2 - _x1 + 1); } ///////////////////////////////////////////////////////////////////////// - DrawTiltedSpanPalCommand::DrawTiltedSpanPalCommand(const SpanDrawerArgs &args, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap) - : plane_sz(plane_sz), plane_su(plane_su), plane_sv(plane_sv), plane_shade(plane_shade), planeshade(planeshade), planelightfloat(planelightfloat), pviewx(pviewx), pviewy(pviewy) + void SWPalDrawers::DrawTiltedSpan(const SpanDrawerArgs& args, const FVector3& plane_sz, const FVector3& plane_su, const FVector3& plane_sv, bool is_planeshaded, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap* basecolormap) { - y = args.DestY(); - x1 = args.DestX1(); - x2 = args.DestX2(); - viewport = args.Viewport(); - _colormap = args.Colormap(args.Viewport()); - _dest = args.Viewport()->GetDest(x1, y); - _ybits = args.TextureHeightBits(); - _xbits = args.TextureWidthBits(); - _source = args.TexturePixels(); - basecolormapdata = basecolormap->Maps; - } - - void DrawTiltedSpanPalCommand::Execute(DrawerThread *thread) - { - if (thread->line_skipped_by_thread(y)) - return; - - const uint8_t **tiltlighting = thread->tiltlighting; + int y = args.DestY(); + int x1 = args.DestX1(); + int x2 = args.DestX2(); + RenderViewport* viewport = args.Viewport(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint8_t* _dest = args.Viewport()->GetDest(x1, y); + int _ybits = args.TextureHeightBits(); + int _xbits = args.TextureWidthBits(); + const uint8_t* _source = args.TexturePixels(); + uint8_t* basecolormapdata = basecolormap->Maps; + + const uint8_t **tiltlighting = this->tiltlighting; int width = x2 - x1; double iz, uz, vz; @@ -2818,11 +2737,11 @@ namespace swrenderer iz = plane_sz[2] + plane_sz[1] * (viewport->viewwindow.centery - y) + plane_sz[0] * (x1 - viewport->viewwindow.centerx); // Lighting is simple. It's just linear interpolation from start to end - if (plane_shade) + if (is_planeshaded) { uz = (iz + plane_sz[0] * width) * planelightfloat; vz = iz * planelightfloat; - CalcTiltedLighting(vz, uz, width, thread); + CalcTiltedLighting(vz, uz, width, planeshade, basecolormapdata); } else { @@ -2876,61 +2795,138 @@ namespace swrenderer x1 = 0; width++; - while (width >= SPANSIZE) + if (args.dc_num_lights == 0) { - iz += izstep; - uz += uzstep; - vz += vzstep; + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; - double endz = 1.f / iz; - double endu = uz*endz; - double endv = vz*endz; - uint32_t stepu = (uint32_t)int64_t((endu - startu) * INVSPAN); - uint32_t stepv = (uint32_t)int64_t((endv - startv) * INVSPAN); - u = (uint32_t)(int64_t(startu) + pviewx); - v = (uint32_t)(int64_t(startv) + pviewy); + double endz = 1.f / iz; + double endu = uz * endz; + double endv = vz * endz; + uint32_t stepu = (uint32_t)int64_t((endu - startu) * INVSPAN); + uint32_t stepv = (uint32_t)int64_t((endv - startv) * INVSPAN); + u = (uint32_t)(int64_t(startu) + pviewx); + v = (uint32_t)(int64_t(startv) + pviewy); - for (i = SPANSIZE - 1; i >= 0; i--) + for (i = SPANSIZE - 1; i >= 0; i--) + { + fb[x1] = *(tiltlighting[x1] + _source[(v >> vshift) | ((u >> ushift) & umask)]); + x1++; + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) { - fb[x1] = *(tiltlighting[x1] + _source[(v >> vshift) | ((u >> ushift) & umask)]); - x1++; - u += stepu; - v += stepv; + if (width == 1) + { + u = (uint32_t)int64_t(startu); + v = (uint32_t)int64_t(startv); + fb[x1] = *(tiltlighting[x1] + _source[(v >> vshift) | ((u >> ushift) & umask)]); + } + else + { + double left = width; + iz += plane_sz[0] * left; + uz += plane_su[0] * left; + vz += plane_sv[0] * left; + + double endz = 1.f / iz; + double endu = uz * endz; + double endv = vz * endz; + left = 1.f / left; + uint32_t stepu = (uint32_t)int64_t((endu - startu) * left); + uint32_t stepv = (uint32_t)int64_t((endv - startv) * left); + u = (uint32_t)(int64_t(startu) + pviewx); + v = (uint32_t)(int64_t(startv) + pviewy); + + for (; width != 0; width--) + { + fb[x1] = *(tiltlighting[x1] + _source[(v >> vshift) | ((u >> ushift) & umask)]); + x1++; + u += stepu; + v += stepv; + } + } } - startu = endu; - startv = endv; - width -= SPANSIZE; } - if (width > 0) + else { - if (width == 1) - { - u = (uint32_t)int64_t(startu); - v = (uint32_t)int64_t(startv); - fb[x1] = *(tiltlighting[x1] + _source[(v >> vshift) | ((u >> ushift) & umask)]); - } - else + auto lights = args.dc_lights; + auto num_lights = args.dc_num_lights; + auto normal = args.dc_normal; + auto viewpos = args.dc_viewpos; + auto viewpos_step = args.dc_viewpos_step; + while (width >= SPANSIZE) { - double left = width; - iz += plane_sz[0] * left; - uz += plane_su[0] * left; - vz += plane_sv[0] * left; + iz += izstep; + uz += uzstep; + vz += vzstep; double endz = 1.f / iz; - double endu = uz*endz; - double endv = vz*endz; - left = 1.f / left; - uint32_t stepu = (uint32_t)int64_t((endu - startu) * left); - uint32_t stepv = (uint32_t)int64_t((endv - startv) * left); + double endu = uz * endz; + double endv = vz * endz; + uint32_t stepu = (uint32_t)int64_t((endu - startu) * INVSPAN); + uint32_t stepv = (uint32_t)int64_t((endv - startv) * INVSPAN); u = (uint32_t)(int64_t(startu) + pviewx); v = (uint32_t)(int64_t(startv) + pviewy); - for (; width != 0; width--) + for (i = SPANSIZE - 1; i >= 0; i--) { - fb[x1] = *(tiltlighting[x1] + _source[(v >> vshift) | ((u >> ushift) & umask)]); + uint8_t material = _source[(v >> vshift) | ((u >> ushift) & umask)]; + uint8_t fg = *(tiltlighting[x1] + material); + fb[x1] = AddLightsTilted(lights, num_lights, viewpos.X, viewpos.Y, viewpos.Z, normal.X, normal.Y, normal.Z, fg, material); x1++; u += stepu; v += stepv; + viewpos += viewpos_step; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (uint32_t)int64_t(startu); + v = (uint32_t)int64_t(startv); + uint8_t material = _source[(v >> vshift) | ((u >> ushift) & umask)]; + uint8_t fg = *(tiltlighting[x1] + material); + fb[x1] = AddLightsTilted(lights, num_lights, viewpos.X, viewpos.Y, viewpos.Z, normal.X, normal.Y, normal.Z, fg, material); + } + else + { + double left = width; + iz += plane_sz[0] * left; + uz += plane_su[0] * left; + vz += plane_sv[0] * left; + + double endz = 1.f / iz; + double endu = uz * endz; + double endv = vz * endz; + left = 1.f / left; + uint32_t stepu = (uint32_t)int64_t((endu - startu) * left); + uint32_t stepv = (uint32_t)int64_t((endv - startv) * left); + u = (uint32_t)(int64_t(startu) + pviewx); + v = (uint32_t)(int64_t(startv) + pviewy); + + for (; width != 0; width--) + { + uint8_t material = _source[(v >> vshift) | ((u >> ushift) & umask)]; + uint8_t fg = *(tiltlighting[x1] + material); + fb[x1] = AddLightsTilted(lights, num_lights, viewpos.X, viewpos.Y, viewpos.Z, normal.X, normal.Y, normal.Z, fg, material); + x1++; + u += stepu; + v += stepv; + viewpos += viewpos_step; + } } } } @@ -2939,9 +2935,9 @@ namespace swrenderer // Calculates the lighting for one row of a tilted plane. If the definition // of GETPALOOKUP changes, this needs to change, too. - void DrawTiltedSpanPalCommand::CalcTiltedLighting(double lstart, double lend, int width, DrawerThread *thread) + void SWPalDrawers::CalcTiltedLighting(double lstart, double lend, int width, int planeshade, uint8_t* basecolormapdata) { - const uint8_t **tiltlighting = thread->tiltlighting; + const uint8_t **tiltlighting = this->tiltlighting; uint8_t *lightstart = basecolormapdata + (GETPALOOKUP(lstart, planeshade) << COLORMAPSHIFT); uint8_t *lightend = basecolormapdata + (GETPALOOKUP(lend, planeshade) << COLORMAPSHIFT); @@ -2967,38 +2963,25 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////// - DrawColoredSpanPalCommand::DrawColoredSpanPalCommand(const SpanDrawerArgs &args) : PalSpanCommand(args) - { - y = args.DestY(); - x1 = args.DestX1(); - x2 = args.DestX2(); - color = args.SolidColor(); - dest = args.Viewport()->GetDest(x1, y); - } - - void DrawColoredSpanPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawColoredSpan(const SpanDrawerArgs& args) { - if (thread->line_skipped_by_thread(y)) - return; - + int y = args.DestY(); + int x1 = args.DestX1(); + int x2 = args.DestX2(); + int color = args.SolidColor(); + uint8_t* _dest = args.Viewport()->GetDest(0, y); memset(_dest, color, x2 - x1 + 1); } ///////////////////////////////////////////////////////////////////////// - DrawFogBoundaryLinePalCommand::DrawFogBoundaryLinePalCommand(const SpanDrawerArgs &args) : PalSpanCommand(args) + void SWPalDrawers::DrawFogBoundaryLine(const SpanDrawerArgs& args) { - y = args.DestY(); - x1 = args.DestX1(); - x2 = args.DestX2(); - _colormap = args.Colormap(args.Viewport()); - _dest = args.Viewport()->GetDest(0, y); - } - - void DrawFogBoundaryLinePalCommand::Execute(DrawerThread *thread) - { - if (thread->line_skipped_by_thread(y)) - return; + int y = args.DestY(); + int x1 = args.DestX1(); + int x2 = args.DestX2(); + const uint8_t* _colormap = args.Colormap(args.Viewport()); + uint8_t* _dest = args.Viewport()->GetDest(0, y); const uint8_t *colormap = _colormap; uint8_t *dest = _dest; @@ -3011,34 +2994,21 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - DrawParticleColumnPalCommand::DrawParticleColumnPalCommand(uint8_t *dest, int dest_y, int pitch, int count, uint32_t fg, uint32_t alpha, uint32_t fracposx) + void SWPalDrawers::DrawParticleColumn(int x, int _dest_y, int _count, uint32_t _fg, uint32_t _alpha, uint32_t _fracposx) { - _dest = dest; - _pitch = pitch; - _count = count; - _fg = fg; - _alpha = alpha; - _fracposx = fracposx; - _dest_y = dest_y; - } + uint8_t* dest = thread->Viewport->GetDest(x, _dest_y); + int pitch = thread->Viewport->RenderTarget->GetPitch(); - void DrawParticleColumnPalCommand::Execute(DrawerThread *thread) - { - int count = thread->count_for_thread(_dest_y, _count); + int count = _count; if (count <= 0) return; - int pitch = _pitch; - uint8_t *dest = thread->dest_for_thread(_dest_y, pitch, _dest); - pitch = pitch * thread->num_cores; - - int particle_texture_index = MIN(gl_particles_style, NUM_PARTICLE_TEXTURES - 1); + int particle_texture_index = min(gl_particles_style, NUM_PARTICLE_TEXTURES - 1); const uint32_t *source = &particle_texture[particle_texture_index][(_fracposx >> FRACBITS) * PARTICLE_TEXTURE_SIZE]; uint32_t particle_alpha = _alpha; uint32_t fracstep = PARTICLE_TEXTURE_SIZE * FRACUNIT / _count; - uint32_t fracpos = fracstep * thread->skipped_by_thread(_dest_y) + fracstep / 2; - fracstep *= thread->num_cores; + uint32_t fracpos = fracstep / 2; uint32_t fg_red = (_fg >> 16) & 0xff; uint32_t fg_green = (_fg >> 8) & 0xff; @@ -3066,11 +3036,7 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - DrawVoxelBlocksPalCommand::DrawVoxelBlocksPalCommand(const SpriteDrawerArgs &args, const VoxelBlock *blocks, int blockcount) : args(args), blocks(blocks), blockcount(blockcount) - { - } - - void DrawVoxelBlocksPalCommand::Execute(DrawerThread *thread) + void SWPalDrawers::DrawVoxelBlocks(const SpriteDrawerArgs& args, const VoxelBlock* blocks, int blockcount) { int destpitch = args.Viewport()->RenderTarget->GetPitch(); uint8_t *destorig = args.Viewport()->RenderTarget->GetPixels(); @@ -3089,12 +3055,6 @@ namespace swrenderer int pitch = destpitch; uint8_t *dest = destorig + (block.x + block.y * pitch); - count = thread->count_for_thread(block.y, count); - dest = thread->dest_for_thread(block.y, pitch, dest); - fracpos += iscale * thread->skipped_by_thread(block.y); - iscale *= thread->num_cores; - pitch *= thread->num_cores; - if (width == 1) { while (count > 0) @@ -3161,4 +3121,140 @@ namespace swrenderer } } } + + template + void SWPalDrawers::DrawWallColumns(const WallDrawerArgs& wallargs) + { + wallcolargs.wallargs = &wallargs; + + bool haslights = r_dynlights && wallargs.lightlist; + if (haslights) + { + float dx = wallargs.WallC.tright.X - wallargs.WallC.tleft.X; + float dy = wallargs.WallC.tright.Y - wallargs.WallC.tleft.Y; + float length = sqrt(dx * dx + dy * dy); + wallcolargs.dc_normal.X = dy / length; + wallcolargs.dc_normal.Y = -dx / length; + wallcolargs.dc_normal.Z = 0.0f; + } + + wallcolargs.SetTextureFracBits(wallargs.fracbits); + + float curlight = wallargs.lightpos; + float lightstep = wallargs.lightstep; + int shade = wallargs.Shade(); + + if (wallargs.fixedlight) + { + curlight = wallargs.FixedLight(); + lightstep = 0; + } + + float upos = wallargs.texcoords.upos, ustepX = wallargs.texcoords.ustepX, ustepY = wallargs.texcoords.ustepY; + float vpos = wallargs.texcoords.vpos, vstepX = wallargs.texcoords.vstepX, vstepY = wallargs.texcoords.vstepY; + float wpos = wallargs.texcoords.wpos, wstepX = wallargs.texcoords.wstepX, wstepY = wallargs.texcoords.wstepY; + float startX = wallargs.texcoords.startX; + + int x1 = wallargs.x1; + int x2 = wallargs.x2; + + upos += ustepX * (x1 + 0.5f - startX); + vpos += vstepX * (x1 + 0.5f - startX); + wpos += wstepX * (x1 + 0.5f - startX); + + float centerY = wallargs.CenterY; + centerY -= 0.5f; + + auto uwal = wallargs.uwal; + auto dwal = wallargs.dwal; + for (int x = x1; x < x2; x++) + { + int y1 = uwal[x]; + int y2 = dwal[x]; + if (y2 > y1) + { + wallcolargs.SetLight(curlight, shade); + if (haslights) + SetLights(wallcolargs, x, y1, wallargs); + else + wallcolargs.dc_num_lights = 0; + + float dy = (y1 - centerY); + float u = upos + ustepY * dy; + float v = vpos + vstepY * dy; + float w = wpos + wstepY * dy; + float scaleU = ustepX; + float scaleV = vstepY; + w = 1.0f / w; + u *= w; + v *= w; + scaleU *= w; + scaleV *= w; + + uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL); + uint32_t texelY = (uint32_t)(int64_t)((v - std::floor(v)) * 0x1'0000'0000LL); + uint32_t texelStepX = (uint32_t)(int64_t)(scaleU * 0x1'0000'0000LL); + uint32_t texelStepY = (uint32_t)(int64_t)(scaleV * 0x1'0000'0000LL); + + DrawWallColumn8(wallcolargs, x, y1, y2, texelX, texelY, texelStepY); + } + + upos += ustepX; + vpos += vstepX; + wpos += wstepX; + curlight += lightstep; + } + } + + template + void SWPalDrawers::DrawWallColumn8(WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepY) + { + auto& wallargs = *drawerargs.wallargs; + int texwidth = wallargs.texwidth; + int texheight = wallargs.texheight; + int fracbits = wallargs.fracbits; + uint32_t uv_max = texheight << fracbits; + + const uint8_t* pixels = static_cast(wallargs.texpixels) + (((texelX >> 16) * texwidth) >> 16) * texheight; + + texelY = (static_cast(texelY) * texheight) >> (32 - fracbits); + texelStepY = (static_cast(texelStepY) * texheight) >> (32 - fracbits); + + drawerargs.SetTexture(pixels, nullptr, texheight); + drawerargs.SetTextureVStep(texelStepY); + + if (uv_max == 0 || texelStepY == 0) // power of two + { + int count = y2 - y1; + + drawerargs.SetDest(x, y1); + drawerargs.SetCount(count); + drawerargs.SetTextureVPos(texelY); + DrawWallColumn(drawerargs); + } + else + { + uint32_t left = y2 - y1; + int y = y1; + while (left > 0) + { + uint32_t available = uv_max - texelY; + uint32_t next_uv_wrap = available / texelStepY; + if (available % texelStepY != 0) + next_uv_wrap++; + uint32_t count = min(left, next_uv_wrap); + + drawerargs.SetDest(x, y); + drawerargs.SetCount(count); + drawerargs.SetTextureVPos(texelY); + DrawWallColumn(drawerargs); + + y += count; + left -= count; + texelY += texelStepY * count; + if (texelY >= uv_max) + texelY -= uv_max; + } + } + } } diff --git a/src/rendering/swrenderer/drawers/r_draw_pal.h b/src/rendering/swrenderer/drawers/r_draw_pal.h index 14b1e3bc204..b3c54be184c 100644 --- a/src/rendering/swrenderer/drawers/r_draw_pal.h +++ b/src/rendering/swrenderer/drawers/r_draw_pal.h @@ -107,289 +107,82 @@ namespace swrenderer int mShade = 0; }; - class DrawWallCommand : public DrawerCommand - { - public: - DrawWallCommand(const WallDrawerArgs& args); - void Execute(DrawerThread* thread) override; - - protected: - virtual void DrawColumn(DrawerThread* thread, const WallColumnDrawerArgs& args) = 0; - - private: - void DrawWallColumn32(DrawerThread* thread, WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepX, uint32_t texelStepY); - void DrawWallColumn8(DrawerThread* thread, WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepY); - void DrawDepthColumn(DrawerThread* thread, const WallColumnDrawerArgs& args, float idepth); - void SetLights(WallColumnDrawerArgs& drawerargs, int x, int y1); - - WallDrawerArgs wallargs; - }; - - class PalWall1Command : public DrawWallCommand - { - public: - PalWall1Command(const WallDrawerArgs &args) : DrawWallCommand(args) { } - - protected: - inline static uint8_t AddLights(const DrawerLight *lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material); - }; - - class DrawWall1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; }; - class DrawWallMasked1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; }; - class DrawWallAdd1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; }; - class DrawWallAddClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; }; - class DrawWallSubClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; }; - class DrawWallRevSubClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; }; - - class PalSkyCommand : public DrawerCommand - { - public: - PalSkyCommand(const SkyDrawerArgs &args); - - protected: - SkyDrawerArgs args; - }; - - class DrawSingleSky1PalCommand : public PalSkyCommand { public: using PalSkyCommand::PalSkyCommand; void Execute(DrawerThread *thread) override; }; - class DrawDoubleSky1PalCommand : public PalSkyCommand { public: using PalSkyCommand::PalSkyCommand; void Execute(DrawerThread *thread) override; }; - - class PalColumnCommand : public DrawerCommand - { - public: - PalColumnCommand(const SpriteDrawerArgs &args); - - SpriteDrawerArgs args; - - protected: - uint8_t AddLights(uint8_t fg, uint8_t material, uint32_t lit_r, uint32_t lit_g, uint32_t lit_b); - }; - - class DrawColumnPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class FillColumnPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class FillColumnAddPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class FillColumnAddClampPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class FillColumnSubClampPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class FillColumnRevSubClampPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnAddPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnTranslatedPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnTlatedAddPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnShadedPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnAddClampShadedPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnAddClampPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnAddClampTranslatedPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnSubClampPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnSubClampTranslatedPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnRevSubClampPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - class DrawColumnRevSubClampTranslatedPalCommand : public PalColumnCommand { public: using PalColumnCommand::PalColumnCommand; void Execute(DrawerThread *thread) override; }; - - class DrawFuzzColumnPalCommand : public DrawerCommand - { - public: - DrawFuzzColumnPalCommand(const SpriteDrawerArgs &args); - void Execute(DrawerThread *thread) override; - - private: - int _yl; - int _yh; - int _x; - uint8_t *_destorg; - int _pitch; - int _fuzzpos; - int _fuzzviewheight; - }; - - class DrawScaledFuzzColumnPalCommand : public DrawerCommand - { - public: - DrawScaledFuzzColumnPalCommand(const SpriteDrawerArgs &drawerargs); - void Execute(DrawerThread *thread) override; - - private: - int _x; - int _yl; - int _yh; - uint8_t *_destorg; - int _pitch; - int _fuzzpos; - int _fuzzviewheight; - }; - - class PalSpanCommand : public DrawerCommand - { - public: - PalSpanCommand(const SpanDrawerArgs &args); - - protected: - inline static uint8_t AddLights(const DrawerLight *lights, int num_lights, float viewpos_x, uint8_t fg, uint8_t material); - - const uint8_t *_source; - const uint8_t *_colormap; - uint32_t _xfrac; - uint32_t _yfrac; - int _y; - int _x1; - int _x2; - uint8_t *_dest; - uint32_t _xstep; - uint32_t _ystep; - int _srcwidth; - int _srcheight; - uint32_t *_srcblend; - uint32_t *_destblend; - int _color; - fixed_t _srcalpha; - fixed_t _destalpha; - DrawerLight *_dynlights; - int _num_dynlights; - float _viewpos_x; - float _step_viewpos_x; - }; - - class DrawSpanPalCommand : public PalSpanCommand { public: using PalSpanCommand::PalSpanCommand; void Execute(DrawerThread *thread) override; }; - class DrawSpanMaskedPalCommand : public PalSpanCommand { public: using PalSpanCommand::PalSpanCommand; void Execute(DrawerThread *thread) override; }; - class DrawSpanTranslucentPalCommand : public PalSpanCommand { public: using PalSpanCommand::PalSpanCommand; void Execute(DrawerThread *thread) override; }; - class DrawSpanMaskedTranslucentPalCommand : public PalSpanCommand { public: using PalSpanCommand::PalSpanCommand; void Execute(DrawerThread *thread) override; }; - class DrawSpanAddClampPalCommand : public PalSpanCommand { public: using PalSpanCommand::PalSpanCommand; void Execute(DrawerThread *thread) override; }; - class DrawSpanMaskedAddClampPalCommand : public PalSpanCommand { public: using PalSpanCommand::PalSpanCommand; void Execute(DrawerThread *thread) override; }; - class FillSpanPalCommand : public PalSpanCommand { public: using PalSpanCommand::PalSpanCommand; void Execute(DrawerThread *thread) override; }; - - class DrawTiltedSpanPalCommand : public DrawerCommand - { - public: - DrawTiltedSpanPalCommand(const SpanDrawerArgs &args, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap); - void Execute(DrawerThread *thread) override; - - private: - void CalcTiltedLighting(double lval, double lend, int width, DrawerThread *thread); - - int y; - int x1; - int x2; - FVector3 plane_sz; - FVector3 plane_su; - FVector3 plane_sv; - bool plane_shade; - int planeshade; - float planelightfloat; - fixed_t pviewx; - fixed_t pviewy; - - const uint8_t *_colormap; - uint8_t *_dest; - int _ybits; - int _xbits; - const uint8_t *_source; - uint8_t *basecolormapdata; - RenderViewport *viewport; - }; - - class DrawColoredSpanPalCommand : public PalSpanCommand - { - public: - DrawColoredSpanPalCommand(const SpanDrawerArgs &args); - void Execute(DrawerThread *thread) override; - - private: - int y; - int x1; - int x2; - int color; - uint8_t *dest; - }; - - class DrawFogBoundaryLinePalCommand : public PalSpanCommand - { - public: - DrawFogBoundaryLinePalCommand(const SpanDrawerArgs &args); - void Execute(DrawerThread *thread) override; - - private: - int y, x1, x2; - const uint8_t *_colormap; - uint8_t *_dest; - }; - - class DrawParticleColumnPalCommand : public DrawerCommand - { - public: - DrawParticleColumnPalCommand(uint8_t *dest, int dest_y, int pitch, int count, uint32_t fg, uint32_t alpha, uint32_t fracposx); - void Execute(DrawerThread *thread) override; - - private: - uint8_t *_dest; - int _dest_y; - int _pitch; - int _count; - uint32_t _fg; - uint32_t _alpha; - uint32_t _fracposx; - }; - - class DrawVoxelBlocksPalCommand : public DrawerCommand - { - public: - DrawVoxelBlocksPalCommand(const SpriteDrawerArgs &args, const VoxelBlock *blocks, int blockcount); - void Execute(DrawerThread *thread) override; - - private: - SpriteDrawerArgs args; - const VoxelBlock *blocks; - int blockcount; - }; + struct DrawWallModeNormal; + struct DrawWallModeMasked; + struct DrawWallModeAdd; + struct DrawWallModeAddClamp; + struct DrawWallModeSubClamp; + struct DrawWallModeRevSubClamp; class SWPalDrawers : public SWPixelFormatDrawers { public: using SWPixelFormatDrawers::SWPixelFormatDrawers; - void DrawWall(const WallDrawerArgs &args) override { Queue->Push(args); } - void DrawWallMasked(const WallDrawerArgs &args) override { Queue->Push(args); } - void DrawWallAdd(const WallDrawerArgs &args) override { Queue->Push(args); } - void DrawWallAddClamp(const WallDrawerArgs &args) override { Queue->Push(args); } - void DrawWallSubClamp(const WallDrawerArgs &args) override { Queue->Push(args); } - void DrawWallRevSubClamp(const WallDrawerArgs &args) override { Queue->Push(args); } - void DrawSingleSkyColumn(const SkyDrawerArgs &args) override { Queue->Push(args); } - void DrawDoubleSkyColumn(const SkyDrawerArgs &args) override { Queue->Push(args); } - void DrawColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void FillColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void FillAddColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void FillAddClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void FillSubClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void FillRevSubClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } + void DrawWall(const WallDrawerArgs &args) override { DrawWallColumns(args); } + void DrawWallMasked(const WallDrawerArgs &args) override { DrawWallColumns(args); } + void DrawWallAdd(const WallDrawerArgs &args) override { DrawWallColumns(args); } + void DrawWallAddClamp(const WallDrawerArgs &args) override { DrawWallColumns(args); } + void DrawWallSubClamp(const WallDrawerArgs &args) override { DrawWallColumns(args); } + void DrawWallRevSubClamp(const WallDrawerArgs &args) override { DrawWallColumns(args); } + void DrawSingleSkyColumn(const SkyDrawerArgs& args) override; + void DrawDoubleSkyColumn(const SkyDrawerArgs& args) override; + void DrawColumn(const SpriteDrawerArgs& args) override; + void FillColumn(const SpriteDrawerArgs& args) override; + void FillAddColumn(const SpriteDrawerArgs& args) override; + void FillAddClampColumn(const SpriteDrawerArgs& args) override; + void FillSubClampColumn(const SpriteDrawerArgs& args) override; + void FillRevSubClampColumn(const SpriteDrawerArgs& args) override; void DrawFuzzColumn(const SpriteDrawerArgs &args) override { if (r_fuzzscale) - Queue->Push(args); + DrawScaledFuzzColumn(args); else - Queue->Push(args); + DrawUnscaledFuzzColumn(args); R_UpdateFuzzPos(args); } - void DrawAddColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawTranslatedColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawTranslatedAddColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawShadedColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawAddClampShadedColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawAddClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawAddClampTranslatedColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawSubClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawSubClampTranslatedColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawRevSubClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawRevSubClampTranslatedColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawVoxelBlocks(const SpriteDrawerArgs &args, const VoxelBlock *blocks, int blockcount) override { Queue->Push(args, blocks, blockcount); } - void DrawSpan(const SpanDrawerArgs &args) override { Queue->Push(args); } - void DrawSpanMasked(const SpanDrawerArgs &args) override { Queue->Push(args); } - void DrawSpanTranslucent(const SpanDrawerArgs &args) override { Queue->Push(args); } - void DrawSpanMaskedTranslucent(const SpanDrawerArgs &args) override { Queue->Push(args); } - void DrawSpanAddClamp(const SpanDrawerArgs &args) override { Queue->Push(args); } - void DrawSpanMaskedAddClamp(const SpanDrawerArgs &args) override { Queue->Push(args); } - void FillSpan(const SpanDrawerArgs &args) override { Queue->Push(args); } - - void DrawTiltedSpan(const SpanDrawerArgs &args, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap) override - { - Queue->Push(args, plane_sz, plane_su, plane_sv, plane_shade, planeshade, planelightfloat, pviewx, pviewy, basecolormap); - } - - void DrawColoredSpan(const SpanDrawerArgs &args) override { Queue->Push(args); } - void DrawFogBoundaryLine(const SpanDrawerArgs &args) override { Queue->Push(args); } + void DrawAddColumn(const SpriteDrawerArgs& args) override; + void DrawTranslatedColumn(const SpriteDrawerArgs& args) override; + void DrawTranslatedAddColumn(const SpriteDrawerArgs& args) override; + void DrawShadedColumn(const SpriteDrawerArgs& args) override; + void DrawAddClampShadedColumn(const SpriteDrawerArgs& args) override; + void DrawAddClampColumn(const SpriteDrawerArgs& args) override; + void DrawAddClampTranslatedColumn(const SpriteDrawerArgs& args) override; + void DrawSubClampColumn(const SpriteDrawerArgs& args) override; + void DrawSubClampTranslatedColumn(const SpriteDrawerArgs& args) override; + void DrawRevSubClampColumn(const SpriteDrawerArgs& args) override; + void DrawRevSubClampTranslatedColumn(const SpriteDrawerArgs& args) override; + void DrawVoxelBlocks(const SpriteDrawerArgs& args, const VoxelBlock* blocks, int blockcount) override; + void DrawSpan(const SpanDrawerArgs& args) override; + void DrawSpanMasked(const SpanDrawerArgs& args) override; + void DrawSpanTranslucent(const SpanDrawerArgs& args) override; + void DrawSpanMaskedTranslucent(const SpanDrawerArgs& args) override; + void DrawSpanAddClamp(const SpanDrawerArgs& args) override; + void DrawSpanMaskedAddClamp(const SpanDrawerArgs& args) override; + void FillSpan(const SpanDrawerArgs& args) override; + void DrawTiltedSpan(const SpanDrawerArgs& args, const FVector3& plane_sz, const FVector3& plane_su, const FVector3& plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap* basecolormap) override; + void DrawColoredSpan(const SpanDrawerArgs& args) override; + void DrawFogBoundaryLine(const SpanDrawerArgs& args) override; + + void DrawParticleColumn(int x, int yl, int ycount, uint32_t fg, uint32_t alpha, uint32_t fracposx) override; + + void DrawScaledFuzzColumn(const SpriteDrawerArgs& args); + void DrawUnscaledFuzzColumn(const SpriteDrawerArgs& args); + + inline static uint8_t AddLightsColumn(const DrawerLight* lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material); + inline static uint8_t AddLightsSpan(const DrawerLight* lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material); + inline static uint8_t AddLightsTilted(const DrawerLight* lights, int num_lights, float viewpos_x, float viewpos_y, float viewpos_z, float nx, float ny, float nz, uint8_t fg, uint8_t material); + inline static uint8_t AddLights(uint8_t fg, uint8_t material, uint32_t lit_r, uint32_t lit_g, uint32_t lit_b); + + void CalcTiltedLighting(double lstart, double lend, int width, int planeshade, uint8_t* basecolormapdata); + + template void DrawWallColumns(const WallDrawerArgs& args); + template void DrawWallColumn8(WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepY); + template void DrawWallColumn(const WallColumnDrawerArgs& args); + + // Working buffer used by the tilted (sloped) span drawer + const uint8_t* tiltlighting[MAXWIDTH]; + + WallColumnDrawerArgs wallcolargs; }; } diff --git a/src/rendering/swrenderer/drawers/r_draw_rgba.cpp b/src/rendering/swrenderer/drawers/r_draw_rgba.cpp index a50221b3d85..7c484ac85dd 100644 --- a/src/rendering/swrenderer/drawers/r_draw_rgba.cpp +++ b/src/rendering/swrenderer/drawers/r_draw_rgba.cpp @@ -34,10 +34,10 @@ */ #include -#include "templates.h" + #include "doomdef.h" -#include "w_wad.h" +#include "filesystem.h" #include "v_video.h" #include "doomstat.h" #include "st_stuff.h" @@ -63,9 +63,9 @@ #include "gi.h" #include "stats.h" -#include "x86.h" #include +; // Use linear filtering when scaling up CVAR(Bool, r_magfilter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); @@ -82,193 +82,185 @@ namespace swrenderer { void SWTruecolorDrawers::DrawWall(const WallDrawerArgs &args) { - Queue->Push(args); + DrawWallColumns(args); } void SWTruecolorDrawers::DrawWallMasked(const WallDrawerArgs &args) { - Queue->Push(args); + DrawWallColumns(args); } void SWTruecolorDrawers::DrawWallAdd(const WallDrawerArgs &args) { - Queue->Push(args); + DrawWallColumns(args); } void SWTruecolorDrawers::DrawWallAddClamp(const WallDrawerArgs &args) { - Queue->Push(args); + DrawWallColumns(args); } void SWTruecolorDrawers::DrawWallSubClamp(const WallDrawerArgs &args) { - Queue->Push(args); + DrawWallColumns(args); } void SWTruecolorDrawers::DrawWallRevSubClamp(const WallDrawerArgs &args) { - Queue->Push(args); + DrawWallColumns(args); } void SWTruecolorDrawers::DrawColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSprite32Command::DrawColumn(args); } void SWTruecolorDrawers::FillColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + FillSprite32Command::DrawColumn(args); } void SWTruecolorDrawers::FillAddColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + FillSpriteAddClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::FillAddClampColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + FillSpriteAddClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::FillSubClampColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + FillSpriteSubClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::FillRevSubClampColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + FillSpriteRevSubClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawFuzzColumn(const SpriteDrawerArgs &args) { if (r_fuzzscale) - Queue->Push(args); + DrawScaledFuzzColumn(args); else - Queue->Push(args); + DrawUnscaledFuzzColumn(args); R_UpdateFuzzPos(args); } void SWTruecolorDrawers::DrawAddColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteAddClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawTranslatedColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteTranslated32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawTranslatedAddColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteTranslatedAddClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawShadedColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteShaded32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawAddClampShadedColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteAddClampShaded32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawAddClampColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteAddClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawAddClampTranslatedColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteTranslatedAddClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSubClampColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteSubClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSubClampTranslatedColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteTranslatedSubClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawRevSubClampColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + DrawSpriteRevSubClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawRevSubClampTranslatedColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); - } - - void SWTruecolorDrawers::DrawVoxelBlocks(const SpriteDrawerArgs &args, const VoxelBlock *blocks, int blockcount) - { - Queue->Push(args, blocks, blockcount); + DrawSpriteTranslatedRevSubClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSpan(const SpanDrawerArgs &args) { - Queue->Push(args); + DrawSpan32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSpanMasked(const SpanDrawerArgs &args) { - Queue->Push(args); + DrawSpanMasked32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSpanTranslucent(const SpanDrawerArgs &args) { - Queue->Push(args); + DrawSpanTranslucent32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSpanMaskedTranslucent(const SpanDrawerArgs &args) { - Queue->Push(args); + DrawSpanAddClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSpanAddClamp(const SpanDrawerArgs &args) { - Queue->Push(args); + DrawSpanTranslucent32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSpanMaskedAddClamp(const SpanDrawerArgs &args) { - Queue->Push(args); + DrawSpanAddClamp32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawSingleSkyColumn(const SkyDrawerArgs &args) { - Queue->Push(args); + DrawSkySingle32Command::DrawColumn(args); } void SWTruecolorDrawers::DrawDoubleSkyColumn(const SkyDrawerArgs &args) { - Queue->Push(args); + DrawSkyDouble32Command::DrawColumn(args); } ///////////////////////////////////////////////////////////////////////////// - DrawScaledFuzzColumnRGBACommand::DrawScaledFuzzColumnRGBACommand(const SpriteDrawerArgs &drawerargs) + void SWTruecolorDrawers::DrawScaledFuzzColumn(const SpriteDrawerArgs& drawerargs) { - _x = drawerargs.FuzzX(); - _yl = drawerargs.FuzzY1(); - _yh = drawerargs.FuzzY2(); - _destorg = drawerargs.Viewport()->GetDest(0, 0); - _pitch = drawerargs.Viewport()->RenderTarget->GetPitch(); - _fuzzpos = fuzzpos; - _fuzzviewheight = fuzzviewheight; - } + int _x = drawerargs.FuzzX(); + int _yl = drawerargs.FuzzY1(); + int _yh = drawerargs.FuzzY2(); + uint8_t* RESTRICT _destorg = drawerargs.Viewport()->GetDest(0, 0); + int _pitch = drawerargs.Viewport()->RenderTarget->GetPitch(); + int _fuzzpos = fuzzpos; + int _fuzzviewheight = fuzzviewheight; - void DrawScaledFuzzColumnRGBACommand::Execute(DrawerThread *thread) - { int x = _x; - int yl = MAX(_yl, 1); - int yh = MIN(_yh, _fuzzviewheight); + int yl = max(_yl, 1); + int yh = min(_yh, _fuzzviewheight); - int count = thread->count_for_thread(yl, yh - yl + 1); + int count = yh - yl + 1; if (count <= 0) return; int pitch = _pitch; @@ -279,14 +271,7 @@ namespace swrenderer fixed_t fuzzstep = (200 << FRACBITS) / _fuzzviewheight; fixed_t fuzzcount = FUZZTABLE << FRACBITS; - fixed_t fuzz = (fuzz_x << FRACBITS) + yl * fuzzstep; - - dest = thread->dest_for_thread(yl, pitch, dest); - pitch *= thread->num_cores; - - fuzz += fuzzstep * thread->skipped_by_thread(yl); - fuzz %= fuzzcount; - fuzzstep *= thread->num_cores; + fixed_t fuzz = ((fuzz_x << FRACBITS) + yl * fuzzstep) % fuzzcount; while (count > 0) { @@ -309,33 +294,30 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - DrawFuzzColumnRGBACommand::DrawFuzzColumnRGBACommand(const SpriteDrawerArgs &drawerargs) + void SWTruecolorDrawers::DrawUnscaledFuzzColumn(const SpriteDrawerArgs& drawerargs) { - _x = drawerargs.FuzzX(); - _yl = drawerargs.FuzzY1(); - _yh = drawerargs.FuzzY2(); - _destorg = drawerargs.Viewport()->GetDest(0, 0); - _pitch = drawerargs.Viewport()->RenderTarget->GetPitch(); - _fuzzpos = fuzzpos; - _fuzzviewheight = fuzzviewheight; - } + int _x = drawerargs.FuzzX(); + int _yl = drawerargs.FuzzY1(); + int _yh = drawerargs.FuzzY2(); + uint8_t* RESTRICT _destorg = drawerargs.Viewport()->GetDest(0, 0); + int _pitch = drawerargs.Viewport()->RenderTarget->GetPitch(); + int _fuzzpos = fuzzpos; + int _fuzzviewheight = fuzzviewheight; - void DrawFuzzColumnRGBACommand::Execute(DrawerThread *thread) - { - int yl = MAX(_yl, 1); - int yh = MIN(_yh, _fuzzviewheight); + int yl = max(_yl, 1); + int yh = min(_yh, _fuzzviewheight); - int count = thread->count_for_thread(yl, yh - yl + 1); + int count = yh - yl + 1; // Zero length. if (count <= 0) return; - uint32_t *dest = thread->dest_for_thread(yl, _pitch, _pitch * yl + _x + (uint32_t*)_destorg); - int pitch = _pitch * thread->num_cores; + uint32_t *dest = _pitch * yl + _x + (uint32_t*)_destorg; + int pitch = _pitch; - int fuzzstep = thread->num_cores; - int fuzz = (_fuzzpos + thread->skipped_by_thread(yl)) % FUZZTABLE; + int fuzzstep = 1; + int fuzz = _fuzzpos % FUZZTABLE; #ifndef ORIGINAL_FUZZ @@ -346,7 +328,7 @@ namespace swrenderer if (available % fuzzstep != 0) next_wrap++; - int cnt = MIN(count, next_wrap); + int cnt = min(count, next_wrap); count -= cnt; do { @@ -367,8 +349,6 @@ namespace swrenderer #else - yl += thread->skipped_by_thread(yl); - // Handle the case where we would go out of bounds at the top: if (yl < fuzzstep) { @@ -403,7 +383,7 @@ namespace swrenderer if (available % fuzzstep != 0) next_wrap++; - int cnt = MIN(count, next_wrap); + int cnt = min(count, next_wrap); count -= cnt; do { @@ -443,20 +423,14 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - FillSpanRGBACommand::FillSpanRGBACommand(const SpanDrawerArgs &drawerargs) - { - _x1 = drawerargs.DestX1(); - _x2 = drawerargs.DestX2(); - _y = drawerargs.DestY(); - _dest = drawerargs.Viewport()->GetDest(_x1, _y); - _light = drawerargs.Light(); - _color = drawerargs.SolidColor(); - } - - void FillSpanRGBACommand::Execute(DrawerThread *thread) + void SWTruecolorDrawers::FillSpan(const SpanDrawerArgs& drawerargs) { - if (thread->line_skipped_by_thread(_y)) - return; + int _x1 = drawerargs.DestX1(); + int _x2 = drawerargs.DestX2(); + int _y = drawerargs.DestY(); + uint8_t* RESTRICT _dest = drawerargs.Viewport()->GetDest(_x1, _y); + fixed_t _light = drawerargs.Light(); + int _color = drawerargs.SolidColor(); uint32_t *dest = (uint32_t*)_dest; int count = (_x2 - _x1 + 1); @@ -468,20 +442,14 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - DrawFogBoundaryLineRGBACommand::DrawFogBoundaryLineRGBACommand(const SpanDrawerArgs &drawerargs) - { - _y = drawerargs.DestY(); - _x = drawerargs.DestX1(); - _x2 = drawerargs.DestX2(); - _line = drawerargs.Viewport()->GetDest(0, _y); - _light = drawerargs.Light(); - _shade_constants = drawerargs.ColormapConstants(); - } - - void DrawFogBoundaryLineRGBACommand::Execute(DrawerThread *thread) + void SWTruecolorDrawers::DrawFogBoundaryLine(const SpanDrawerArgs& drawerargs) { - if (thread->line_skipped_by_thread(_y)) - return; + int _y = drawerargs.DestY(); + int _x = drawerargs.DestX1(); + int _x2 = drawerargs.DestX2(); + uint8_t* RESTRICT _line = drawerargs.Viewport()->GetDest(0, _y); + fixed_t _light = drawerargs.Light(); + ShadeConstants constants = drawerargs.ColormapConstants(); int y = _y; int x = _x; @@ -490,7 +458,6 @@ namespace swrenderer uint32_t *dest = (uint32_t*)_line; uint32_t light = LightBgra::calc_light_multiplier(_light); - ShadeConstants constants = _shade_constants; do { @@ -530,32 +497,87 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - DrawTiltedSpanRGBACommand::DrawTiltedSpanRGBACommand(const SpanDrawerArgs &drawerargs, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy) - { - _x1 = drawerargs.DestX1(); - _x2 = drawerargs.DestX2(); - _y = drawerargs.DestY(); - _dest = drawerargs.Viewport()->GetDest(_x1, _y); - _light = drawerargs.Light(); - _shade_constants = drawerargs.ColormapConstants(); - _plane_sz = plane_sz; - _plane_su = plane_su; - _plane_sv = plane_sv; - _plane_shade = plane_shade; - _planeshade = planeshade; - _planelightfloat = planelightfloat; - _pviewx = pviewx; - _pviewy = pviewy; - _source = (const uint32_t*)drawerargs.TexturePixels(); - _xbits = drawerargs.TextureWidthBits(); - _ybits = drawerargs.TextureHeightBits(); - viewport = drawerargs.Viewport(); - } - - void DrawTiltedSpanRGBACommand::Execute(DrawerThread *thread) - { - if (thread->line_skipped_by_thread(_y)) - return; + FORCEINLINE static BgraColor AddTiltedLights(BgraColor material, BgraColor fgcolor, const DrawerLight* lights, int num_lights, float viewpos_x, float viewpos_y, float viewpos_z, float nx, float ny, float nz) + { + using namespace DrawSpan32TModes; + + BgraColor lit; + lit.r = 0; + lit.g = 0; + lit.b = 0; + + // Screen space to view space + viewpos_z = 1.0f / viewpos_z; + viewpos_x *= viewpos_z; + viewpos_y *= viewpos_z; + + for (int i = 0; i != num_lights; i++) + { + float light_x = lights[i].x; + float light_y = lights[i].y; + float light_z = lights[i].z; + float light_radius = lights[i].radius; + + // L = light-pos + // dist = sqrt(dot(L, L)) + // attenuation = 1 - min(dist * (1/radius), 1) + float Lx = lights[i].x - viewpos_x; + float Ly = lights[i].y - viewpos_y; + float Lz = lights[i].z - viewpos_z; + float dist2 = Lx * Lx + Ly * Ly + Lz * Lz; +#ifdef NO_SSE + float rcp_dist = 1.0f / (dist2 * 0.01f); +#else + float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2))); +#endif + Lx *= rcp_dist; + Ly *= rcp_dist; + Lz *= rcp_dist; + float dist = dist2 * rcp_dist; + float radius = lights[i].radius; + bool simpleType = radius < 0.0f; + if (simpleType) + radius = -radius; + float distance_attenuation = (256.0f - min(dist * radius, 256.0f)); + + // The simple light type + float simple_attenuation = distance_attenuation; + + // The point light type + // diffuse = dot(N,L) * attenuation + float dotNL = max(nx * Lx + ny * Ly + nz * Lz, 0.0f); + float point_attenuation = dotNL * distance_attenuation; + uint32_t attenuation = (uint32_t)(simpleType ? simple_attenuation : point_attenuation); + + BgraColor light_color = lights[i].color; + + lit.r += (light_color.r * attenuation) >> 8; + lit.g += (light_color.g * attenuation) >> 8; + lit.b += (light_color.b * attenuation) >> 8; + } + + lit.r = min(lit.r, 256); + lit.g = min(lit.g, 256); + lit.b = min(lit.b, 256); + + fgcolor.r = min(fgcolor.r + ((material.r * lit.r) >> 8), 255); + fgcolor.g = min(fgcolor.g + ((material.g * lit.g) >> 8), 255); + fgcolor.b = min(fgcolor.b + ((material.b * lit.b) >> 8), 255); + return fgcolor; + } + + void SWTruecolorDrawers::DrawTiltedSpan(const SpanDrawerArgs& drawerargs, const FVector3& _plane_sz, const FVector3& _plane_su, const FVector3& _plane_sv, bool _plane_shade, int _planeshade, float _planelightfloat, fixed_t _pviewx, fixed_t _pviewy, FDynamicColormap* _basecolormap) + { + int _x1 = drawerargs.DestX1(); + int _x2 = drawerargs.DestX2(); + int _y = drawerargs.DestY(); + uint8_t* _dest = drawerargs.Viewport()->GetDest(_x1, _y); + fixed_t _light = drawerargs.Light(); + ShadeConstants _shade_constants = drawerargs.ColormapConstants(); + const uint32_t* _source = (const uint32_t*)drawerargs.TexturePixels(); + int _xbits = drawerargs.TextureWidthBits(); + int _ybits = drawerargs.TextureHeightBits(); + RenderViewport* viewport = drawerargs.Viewport(); //#define SPANSIZE 32 //#define INVSPAN 0.03125f @@ -597,23 +619,52 @@ namespace swrenderer double uzstep = _plane_su[0] * SPANSIZE; double vzstep = _plane_sv[0] * SPANSIZE; - // Linear interpolate in sizes of SPANSIZE to increase speed - while (count >= SPANSIZE) + if (drawerargs.dc_num_lights == 0) { - iz += izstep; - uz += uzstep; - vz += vzstep; - - double endz = 1.f / iz; - double endu = uz*endz; - double endv = vz*endz; - uint32_t stepu = (uint32_t)(int64_t((endu - startu) * INVSPAN)); - uint32_t stepv = (uint32_t)(int64_t((endv - startv) * INVSPAN)); - uint32_t u = (uint32_t)(int64_t(startu) + _pviewx); - uint32_t v = (uint32_t)(int64_t(startv) + _pviewy); - - for (int i = 0; i < SPANSIZE; i++) + // Linear interpolate in sizes of SPANSIZE to increase speed + while (count >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + double endz = 1.f / iz; + double endu = uz * endz; + double endv = vz * endz; + uint32_t stepu = (uint32_t)(int64_t((endu - startu) * INVSPAN)); + uint32_t stepv = (uint32_t)(int64_t((endv - startv) * INVSPAN)); + uint32_t u = (uint32_t)(int64_t(startu) + _pviewx); + uint32_t v = (uint32_t)(int64_t(startv) + _pviewy); + + for (int i = 0; i < SPANSIZE; i++) + { + uint32_t sx = ((u >> 16) * source_width) >> 16; + uint32_t sy = ((v >> 16) * source_height) >> 16; + uint32_t fg = _source[sy + sx * source_height]; + + if (_shade_constants.simple_shade) + *(dest++) = LightBgra::shade_bgra_simple(fg, LightBgra::calc_light_multiplier(light)); + else + *(dest++) = LightBgra::shade_bgra(fg, LightBgra::calc_light_multiplier(light), _shade_constants); + + u += stepu; + v += stepv; + light += steplight; + } + startu = endu; + startv = endv; + count -= SPANSIZE; + } + + // The last few pixels at the end + while (count > 0) { + double endz = 1.f / iz; + startu = uz * endz; + startv = vz * endz; + uint32_t u = (uint32_t)(int64_t(startu) + _pviewx); + uint32_t v = (uint32_t)(int64_t(startv) + _pviewy); + uint32_t sx = ((u >> 16) * source_width) >> 16; uint32_t sy = ((v >> 16) * source_height) >> 16; uint32_t fg = _source[sy + sx * source_height]; @@ -623,57 +674,101 @@ namespace swrenderer else *(dest++) = LightBgra::shade_bgra(fg, LightBgra::calc_light_multiplier(light), _shade_constants); - u += stepu; - v += stepv; + iz += _plane_sz[0]; + uz += _plane_su[0]; + vz += _plane_sv[0]; light += steplight; + count--; } - startu = endu; - startv = endv; - count -= SPANSIZE; } - - // The last few pixels at the end - while (count > 0) + else { - double endz = 1.f / iz; - startu = uz*endz; - startv = vz*endz; - uint32_t u = (uint32_t)(int64_t(startu) + _pviewx); - uint32_t v = (uint32_t)(int64_t(startv) + _pviewy); - - uint32_t sx = ((u >> 16) * source_width) >> 16; - uint32_t sy = ((v >> 16) * source_height) >> 16; - uint32_t fg = _source[sy + sx * source_height]; - - if (_shade_constants.simple_shade) - *(dest++) = LightBgra::shade_bgra_simple(fg, LightBgra::calc_light_multiplier(light)); - else - *(dest++) = LightBgra::shade_bgra(fg, LightBgra::calc_light_multiplier(light), _shade_constants); + auto lights = drawerargs.dc_lights; + auto num_lights = drawerargs.dc_num_lights; + auto normal = drawerargs.dc_normal; + auto viewpos = drawerargs.dc_viewpos; + auto viewpos_step = drawerargs.dc_viewpos_step; + + // Linear interpolate in sizes of SPANSIZE to increase speed + while (count >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + double endz = 1.f / iz; + double endu = uz * endz; + double endv = vz * endz; + uint32_t stepu = (uint32_t)(int64_t((endu - startu) * INVSPAN)); + uint32_t stepv = (uint32_t)(int64_t((endv - startv) * INVSPAN)); + uint32_t u = (uint32_t)(int64_t(startu) + _pviewx); + uint32_t v = (uint32_t)(int64_t(startv) + _pviewy); + + for (int i = 0; i < SPANSIZE; i++) + { + uint32_t sx = ((u >> 16) * source_width) >> 16; + uint32_t sy = ((v >> 16) * source_height) >> 16; + uint32_t material = _source[sy + sx * source_height]; + + uint32_t fg; + if (_shade_constants.simple_shade) + fg = LightBgra::shade_bgra_simple(material, LightBgra::calc_light_multiplier(light)); + else + fg = LightBgra::shade_bgra(material, LightBgra::calc_light_multiplier(light), _shade_constants); + + *(dest++) = AddTiltedLights(material, fg, lights, num_lights, viewpos.X, viewpos.Y, viewpos.Z, normal.X, normal.Y, normal.Z); + + u += stepu; + v += stepv; + light += steplight; + viewpos += viewpos_step; + } + startu = endu; + startv = endv; + count -= SPANSIZE; + } - iz += _plane_sz[0]; - uz += _plane_su[0]; - vz += _plane_sv[0]; - light += steplight; - count--; + // The last few pixels at the end + while (count > 0) + { + double endz = 1.f / iz; + startu = uz * endz; + startv = vz * endz; + uint32_t u = (uint32_t)(int64_t(startu) + _pviewx); + uint32_t v = (uint32_t)(int64_t(startv) + _pviewy); + + uint32_t sx = ((u >> 16) * source_width) >> 16; + uint32_t sy = ((v >> 16) * source_height) >> 16; + uint32_t material = _source[sy + sx * source_height]; + + uint32_t fg; + if (_shade_constants.simple_shade) + fg = LightBgra::shade_bgra_simple(material, LightBgra::calc_light_multiplier(light)); + else + fg = LightBgra::shade_bgra(material, LightBgra::calc_light_multiplier(light), _shade_constants); + + *(dest++) = AddTiltedLights(material, fg, lights, num_lights, viewpos.X, viewpos.Y, viewpos.Z, normal.X, normal.Y, normal.Z); + + iz += _plane_sz[0]; + uz += _plane_su[0]; + vz += _plane_sv[0]; + light += steplight; + viewpos += viewpos_step; + count--; + } } } ///////////////////////////////////////////////////////////////////////////// - DrawColoredSpanRGBACommand::DrawColoredSpanRGBACommand(const SpanDrawerArgs &drawerargs) - { - _y = drawerargs.DestY(); - _x1 = drawerargs.DestX1(); - _x2 = drawerargs.DestX2(); - _dest = drawerargs.Viewport()->GetDest(_x1, _y); - _light = drawerargs.Light(); - _color = drawerargs.SolidColor(); - } - - void DrawColoredSpanRGBACommand::Execute(DrawerThread *thread) + void SWTruecolorDrawers::DrawColoredSpan(const SpanDrawerArgs& drawerargs) { - if (thread->line_skipped_by_thread(_y)) - return; + int _y = drawerargs.DestY(); + int _x1 = drawerargs.DestX1(); + int _x2 = drawerargs.DestX2(); + uint8_t* RESTRICT _dest = drawerargs.Viewport()->GetDest(_x1, _y); + fixed_t _light = drawerargs.Light(); + int _color = drawerargs.SolidColor(); int y = _y; int x1 = _x1; @@ -690,12 +785,13 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// #if 0 - ApplySpecialColormapRGBACommand::ApplySpecialColormapRGBACommand(FSpecialColormap *colormap, DFrameBuffer *screen) +#ifdef NO_SSE + void SWTruecolorDrawers::ApplySpecialColormap(FSpecialColormap* colormap, DFrameBuffer* screen) { - buffer = screen->GetBuffer(); - pitch = screen->GetPitch(); - width = screen->GetWidth(); - height = screen->GetHeight(); + uint8_t* buffer = screen->GetBuffer(); + int pitch = screen->GetPitch(); + int width = screen->GetWidth(); + int height = screen->GetHeight(); start_red = (int)(colormap->ColorizeStart[0] * 255); start_green = (int)(colormap->ColorizeStart[1] * 255); @@ -703,13 +799,9 @@ namespace swrenderer end_red = (int)(colormap->ColorizeEnd[0] * 255); end_green = (int)(colormap->ColorizeEnd[1] * 255); end_blue = (int)(colormap->ColorizeEnd[2] * 255); - } -#ifdef NO_SSE - void ApplySpecialColormapRGBACommand::Execute(DrawerThread *thread) - { - int y = thread->skipped_by_thread(0); - int count = thread->count_for_thread(0, height); + int y = 0; + int count = height; while (count > 0) { uint8_t *pixels = buffer + y * pitch * 4; @@ -734,15 +826,27 @@ namespace swrenderer pixels += 4; } - y += thread->num_cores; + y++; count--; } } #else - void ApplySpecialColormapRGBACommand::Execute(DrawerThread *thread) + void SWTruecolorDrawers::ApplySpecialColormap(FSpecialColormap* colormap, DFrameBuffer* screen) { - int y = thread->skipped_by_thread(0); - int count = thread->count_for_thread(0, height); + uint8_t* buffer = screen->GetBuffer(); + int pitch = screen->GetPitch(); + int width = screen->GetWidth(); + int height = screen->GetHeight(); + + start_red = (int)(colormap->ColorizeStart[0] * 255); + start_green = (int)(colormap->ColorizeStart[1] * 255); + start_blue = (int)(colormap->ColorizeStart[2] * 255); + end_red = (int)(colormap->ColorizeEnd[0] * 255); + end_green = (int)(colormap->ColorizeEnd[1] * 255); + end_blue = (int)(colormap->ColorizeEnd[2] * 255); + + int y = 0; + int count = height; __m128i gray_weight = _mm_set_epi16(256, 77, 143, 37, 256, 77, 143, 37); __m128i start_end = _mm_set_epi16(255, start_red, start_green, start_blue, 255, end_red, end_green, end_blue); while (count > 0) @@ -836,7 +940,7 @@ namespace swrenderer pixels += 4; } - y += thread->num_cores; + y++; count--; } } @@ -845,33 +949,21 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - DrawParticleColumnRGBACommand::DrawParticleColumnRGBACommand(uint32_t *dest, int dest_y, int pitch, int count, uint32_t fg, uint32_t alpha, uint32_t fracposx) + void SWTruecolorDrawers::DrawParticleColumn(int x, int _dest_y, int _count, uint32_t _fg, uint32_t _alpha, uint32_t _fracposx) { - _dest = dest; - _pitch = pitch; - _count = count; - _fg = fg; - _alpha = alpha; - _fracposx = fracposx; - _dest_y = dest_y; - } + uint32_t* dest = (uint32_t*)thread->Viewport->GetDest(x, _dest_y); + int pitch = thread->Viewport->RenderTarget->GetPitch(); - void DrawParticleColumnRGBACommand::Execute(DrawerThread *thread) - { - int count = thread->count_for_thread(_dest_y, _count); + int count = _count; if (count <= 0) return; - uint32_t *dest = thread->dest_for_thread(_dest_y, _pitch, _dest); - int pitch = _pitch * thread->num_cores; - - int particle_texture_index = MIN(gl_particles_style, NUM_PARTICLE_TEXTURES - 1); + int particle_texture_index = min(gl_particles_style, NUM_PARTICLE_TEXTURES - 1); const uint32_t *source = &particle_texture[particle_texture_index][(_fracposx >> FRACBITS) * PARTICLE_TEXTURE_SIZE]; uint32_t particle_alpha = _alpha; uint32_t fracstep = PARTICLE_TEXTURE_SIZE * FRACUNIT / _count; - uint32_t fracpos = fracstep * thread->skipped_by_thread(_dest_y) + fracstep / 2; - fracstep *= thread->num_cores; + uint32_t fracpos = fracstep / 2; uint32_t fg_red = (_fg >> 16) & 0xff; uint32_t fg_green = (_fg >> 8) & 0xff; @@ -898,37 +990,184 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - DrawVoxelBlocksRGBACommand::DrawVoxelBlocksRGBACommand(const SpriteDrawerArgs &args, const VoxelBlock *blocks, int blockcount) : args(args), blocks(blocks), blockcount(blockcount) - { - } - - void DrawVoxelBlocksRGBACommand::Execute(DrawerThread *thread) + void SWTruecolorDrawers::DrawVoxelBlocks(const SpriteDrawerArgs& args, const VoxelBlock* blocks, int blockcount) { int pitch = args.Viewport()->RenderTarget->GetPitch(); uint8_t *destorig = args.Viewport()->RenderTarget->GetPixels(); - DrawSprite32Command drawer(args); - drawer.args.dc_texturefracx = 0; - drawer.args.dc_source2 = 0; + SpriteDrawerArgs drawerargs = args; + drawerargs.dc_texturefracx = 0; + drawerargs.dc_source2 = 0; for (int i = 0; i < blockcount; i++) { const VoxelBlock &block = blocks[i]; double v = block.vPos / (double)block.voxelsCount / FRACUNIT; double vstep = block.vStep / (double)block.voxelsCount / FRACUNIT; - drawer.args.dc_texturefrac = (int)(v * (1 << 30)); - drawer.args.dc_iscale = (int)(vstep * (1 << 30)); - drawer.args.dc_source = block.voxels; - drawer.args.dc_textureheight = block.voxelsCount; - drawer.args.dc_count = block.height; - drawer.args.dc_dest_y = block.y; - drawer.args.dc_dest = destorig + (block.x + block.y * pitch) * 4; + drawerargs.dc_texturefrac = (int)(v * (1 << 30)); + drawerargs.dc_iscale = (int)(vstep * (1 << 30)); + drawerargs.dc_source = block.voxels; + drawerargs.dc_textureheight = block.voxelsCount; + drawerargs.dc_count = block.height; + drawerargs.dc_dest_y = block.y; + drawerargs.dc_dest = destorig + (block.x + block.y * pitch) * 4; for (int j = 0; j < block.width; j++) { - drawer.Execute(thread); - drawer.args.dc_dest += 4; + DrawSprite32Command::DrawColumn(drawerargs); + drawerargs.dc_dest += 4; } } } + + ///////////////////////////////////////////////////////////////////////////// + + template + void SWTruecolorDrawers::DrawWallColumns(const WallDrawerArgs& wallargs) + { + wallcolargs.wallargs = &wallargs; + + bool haslights = r_dynlights && wallargs.lightlist; + if (haslights) + { + float dx = wallargs.WallC.tright.X - wallargs.WallC.tleft.X; + float dy = wallargs.WallC.tright.Y - wallargs.WallC.tleft.Y; + float length = sqrt(dx * dx + dy * dy); + wallcolargs.dc_normal.X = dy / length; + wallcolargs.dc_normal.Y = -dx / length; + wallcolargs.dc_normal.Z = 0.0f; + } + + wallcolargs.SetTextureFracBits(wallargs.fracbits); + + float curlight = wallargs.lightpos; + float lightstep = wallargs.lightstep; + int shade = wallargs.Shade(); + + if (wallargs.fixedlight) + { + curlight = wallargs.FixedLight(); + lightstep = 0; + } + + float upos = wallargs.texcoords.upos, ustepX = wallargs.texcoords.ustepX, ustepY = wallargs.texcoords.ustepY; + float vpos = wallargs.texcoords.vpos, vstepX = wallargs.texcoords.vstepX, vstepY = wallargs.texcoords.vstepY; + float wpos = wallargs.texcoords.wpos, wstepX = wallargs.texcoords.wstepX, wstepY = wallargs.texcoords.wstepY; + float startX = wallargs.texcoords.startX; + + int x1 = wallargs.x1; + int x2 = wallargs.x2; + + upos += ustepX * (x1 + 0.5f - startX); + vpos += vstepX * (x1 + 0.5f - startX); + wpos += wstepX * (x1 + 0.5f - startX); + + float centerY = wallargs.CenterY; + centerY -= 0.5f; + + auto uwal = wallargs.uwal; + auto dwal = wallargs.dwal; + for (int x = x1; x < x2; x++) + { + int y1 = uwal[x]; + int y2 = dwal[x]; + if (y2 > y1) + { + wallcolargs.SetLight(curlight, shade); + if (haslights) + SetLights(wallcolargs, x, y1, wallargs); + else + wallcolargs.dc_num_lights = 0; + + float dy = (y1 - centerY); + float u = upos + ustepY * dy; + float v = vpos + vstepY * dy; + float w = wpos + wstepY * dy; + float scaleU = ustepX; + float scaleV = vstepY; + w = 1.0f / w; + u *= w; + v *= w; + scaleU *= w; + scaleV *= w; + + uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL); + uint32_t texelY = (uint32_t)(int64_t)((v - std::floor(v)) * 0x1'0000'0000LL); + uint32_t texelStepX = (uint32_t)(int64_t)(scaleU * 0x1'0000'0000LL); + uint32_t texelStepY = (uint32_t)(int64_t)(scaleV * 0x1'0000'0000LL); + + DrawWallColumn32(wallcolargs, x, y1, y2, texelX, texelY, texelStepX, texelStepY); + } + + upos += ustepX; + vpos += vstepX; + wpos += wstepX; + curlight += lightstep; + } + } + + template + void SWTruecolorDrawers::DrawWallColumn32(WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepX, uint32_t texelStepY) + { + auto& wallargs = *drawerargs.wallargs; + int texwidth = wallargs.texwidth; + int texheight = wallargs.texheight; + + double xmagnitude = fabs(static_cast(texelStepX) * (1.0 / 0x1'0000'0000LL)); + double ymagnitude = fabs(static_cast(texelStepY) * (1.0 / 0x1'0000'0000LL)); + double magnitude = max(ymagnitude, xmagnitude); + double min_lod = -1000.0; + double lod = max(log2(magnitude) + r_lod_bias, min_lod); + bool magnifying = lod < 0.0f; + + int mipmap_offset = 0; + int mip_width = texwidth; + int mip_height = texheight; + if (wallargs.mipmapped && mip_width > 1 && mip_height > 1) + { + int level = (int)lod; + while (level > 0 && mip_width > 1 && mip_height > 1) + { + mipmap_offset += mip_width * mip_height; + level--; + mip_width = max(mip_width >> 1, 1); + mip_height = max(mip_height >> 1, 1); + } + } + + const uint32_t* pixels = static_cast(wallargs.texpixels) + mipmap_offset; + fixed_t xxoffset = (texelX >> 16) * mip_width; + + const uint8_t* source; + const uint8_t* source2; + uint32_t texturefracx; + bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter); + if (filter_nearest) + { + int tx = (xxoffset >> FRACBITS) % mip_width; + source = (uint8_t*)(pixels + tx * mip_height); + source2 = nullptr; + texturefracx = 0; + } + else + { + xxoffset -= FRACUNIT / 2; + int tx0 = (xxoffset >> FRACBITS) % mip_width; + if (tx0 < 0) + tx0 += mip_width; + int tx1 = (tx0 + 1) % mip_width; + source = (uint8_t*)(pixels + tx0 * mip_height); + source2 = (uint8_t*)(pixels + tx1 * mip_height); + texturefracx = (xxoffset >> (FRACBITS - 4)) & 15; + } + + int count = y2 - y1; + drawerargs.SetDest(x, y1); + drawerargs.SetCount(count); + drawerargs.SetTexture(source, source2, mip_height); + drawerargs.SetTextureUPos(texturefracx); + drawerargs.SetTextureVPos(texelY); + drawerargs.SetTextureVStep(texelStepY); + DrawerT::DrawColumn(drawerargs); + } } diff --git a/src/rendering/swrenderer/drawers/r_draw_rgba.h b/src/rendering/swrenderer/drawers/r_draw_rgba.h index 2182909eed9..0babc563b9d 100644 --- a/src/rendering/swrenderer/drawers/r_draw_rgba.h +++ b/src/rendering/swrenderer/drawers/r_draw_rgba.h @@ -25,6 +25,7 @@ #include "r_draw.h" #include "v_palette.h" #include "r_thread.h" +#include "r_draw_pal.h" #include "swrenderer/viewport/r_skydrawer.h" #include "swrenderer/viewport/r_spandrawer.h" #include "swrenderer/viewport/r_walldrawer.h" @@ -70,125 +71,6 @@ namespace swrenderer #define VECTORCALL #endif - class DrawFuzzColumnRGBACommand : public DrawerCommand - { - int _x; - int _yl; - int _yh; - uint8_t * RESTRICT _destorg; - int _pitch; - int _fuzzpos; - int _fuzzviewheight; - - public: - DrawFuzzColumnRGBACommand(const SpriteDrawerArgs &drawerargs); - void Execute(DrawerThread *thread) override; - }; - - class DrawScaledFuzzColumnRGBACommand : public DrawerCommand - { - int _x; - int _yl; - int _yh; - uint8_t * RESTRICT _destorg; - int _pitch; - int _fuzzpos; - int _fuzzviewheight; - - public: - DrawScaledFuzzColumnRGBACommand(const SpriteDrawerArgs &drawerargs); - void Execute(DrawerThread *thread) override; - }; - - class FillSpanRGBACommand : public DrawerCommand - { - int _x1; - int _x2; - int _y; - uint8_t * RESTRICT _dest; - fixed_t _light; - int _color; - - public: - FillSpanRGBACommand(const SpanDrawerArgs &drawerargs); - void Execute(DrawerThread *thread) override; - }; - - class DrawFogBoundaryLineRGBACommand : public DrawerCommand - { - int _y; - int _x; - int _x2; - uint8_t * RESTRICT _line; - fixed_t _light; - ShadeConstants _shade_constants; - - public: - DrawFogBoundaryLineRGBACommand(const SpanDrawerArgs &drawerargs); - void Execute(DrawerThread *thread) override; - }; - - class DrawTiltedSpanRGBACommand : public DrawerCommand - { - int _x1; - int _x2; - int _y; - uint8_t * RESTRICT _dest; - fixed_t _light; - ShadeConstants _shade_constants; - FVector3 _plane_sz; - FVector3 _plane_su; - FVector3 _plane_sv; - bool _plane_shade; - int _planeshade; - float _planelightfloat; - fixed_t _pviewx; - fixed_t _pviewy; - int _xbits; - int _ybits; - const uint32_t * RESTRICT _source; - RenderViewport *viewport; - - public: - DrawTiltedSpanRGBACommand(const SpanDrawerArgs &drawerargs, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy); - void Execute(DrawerThread *thread) override; - }; - - class DrawColoredSpanRGBACommand : public DrawerCommand - { - int _y; - int _x1; - int _x2; - uint8_t * RESTRICT _dest; - fixed_t _light; - int _color; - - public: - DrawColoredSpanRGBACommand(const SpanDrawerArgs &drawerargs); - - void Execute(DrawerThread *thread) override; - }; - -#if 0 - class ApplySpecialColormapRGBACommand : public DrawerCommand - { - uint8_t *buffer; - int pitch; - int width; - int height; - int start_red; - int start_green; - int start_blue; - int end_red; - int end_green; - int end_blue; - - public: - ApplySpecialColormapRGBACommand(FSpecialColormap *colormap, DFrameBuffer *screen); - void Execute(DrawerThread *thread) override; - }; -#endif - template class DrawerBlendCommand : public CommandType { @@ -207,38 +89,6 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// - class DrawParticleColumnRGBACommand : public DrawerCommand - { - public: - DrawParticleColumnRGBACommand(uint32_t *dest, int dest_y, int pitch, int count, uint32_t fg, uint32_t alpha, uint32_t fracposx); - void Execute(DrawerThread *thread) override; - - private: - uint32_t *_dest; - int _dest_y; - int _pitch; - int _count; - uint32_t _fg; - uint32_t _alpha; - uint32_t _fracposx; - }; - - ///////////////////////////////////////////////////////////////////////////// - - class DrawVoxelBlocksRGBACommand : public DrawerCommand - { - public: - DrawVoxelBlocksRGBACommand(const SpriteDrawerArgs &args, const VoxelBlock *blocks, int blockcount); - void Execute(DrawerThread *thread) override; - - private: - SpriteDrawerArgs args; - const VoxelBlock *blocks; - int blockcount; - }; - - ///////////////////////////////////////////////////////////////////////////// - class SWTruecolorDrawers : public SWPixelFormatDrawers { public: @@ -277,15 +127,19 @@ namespace swrenderer void DrawSpanMaskedTranslucent(const SpanDrawerArgs &args) override; void DrawSpanAddClamp(const SpanDrawerArgs &args) override; void DrawSpanMaskedAddClamp(const SpanDrawerArgs &args) override; - void FillSpan(const SpanDrawerArgs &args) override { Queue->Push(args); } + void FillSpan(const SpanDrawerArgs& args) override; + void DrawTiltedSpan(const SpanDrawerArgs& args, const FVector3& plane_sz, const FVector3& plane_su, const FVector3& plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap* basecolormap) override; + void DrawColoredSpan(const SpanDrawerArgs& args) override; + void DrawFogBoundaryLine(const SpanDrawerArgs& args) override; + void DrawParticleColumn(int x, int yl, int ycount, uint32_t fg, uint32_t alpha, uint32_t fracposx) override; - void DrawTiltedSpan(const SpanDrawerArgs &args, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap) override - { - Queue->Push(args, plane_sz, plane_su, plane_sv, plane_shade, planeshade, planelightfloat, pviewx, pviewy); - } + void DrawScaledFuzzColumn(const SpriteDrawerArgs& args); + void DrawUnscaledFuzzColumn(const SpriteDrawerArgs& args); + + template void DrawWallColumns(const WallDrawerArgs& args); + template void DrawWallColumn32(WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepX, uint32_t texelStepY); - void DrawColoredSpan(const SpanDrawerArgs &args) override { Queue->Push(args); } - void DrawFogBoundaryLine(const SpanDrawerArgs &args) override { Queue->Push(args); } + WallColumnDrawerArgs wallcolargs; }; ///////////////////////////////////////////////////////////////////////////// diff --git a/src/rendering/swrenderer/drawers/r_draw_sky32.h b/src/rendering/swrenderer/drawers/r_draw_sky32.h index bc65e41e270..ea9dff4f724 100644 --- a/src/rendering/swrenderer/drawers/r_draw_sky32.h +++ b/src/rendering/swrenderer/drawers/r_draw_sky32.h @@ -27,16 +27,10 @@ namespace swrenderer { - - class DrawSkySingle32Command : public DrawerCommand + class DrawSkySingle32Command { - protected: - SkyDrawerArgs args; - public: - DrawSkySingle32Command(const SkyDrawerArgs &args) : args(args) { } - - void Execute(DrawerThread *thread) override + static void DrawColumn(const SkyDrawerArgs& args) { uint32_t *dest = (uint32_t *)args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); @@ -50,9 +44,7 @@ namespace swrenderer uint32_t solid_bottom = args.SolidBottomColor(); bool fadeSky = args.FadeSky(); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); - int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; + int count = args.Count(); // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: int start_fade = 2; // How fast it should fade out @@ -66,15 +58,8 @@ namespace swrenderer start_fadebottom_y = clamp(start_fadebottom_y, 0, count); end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * skipped; - fracstep *= num_cores; - pitch *= num_cores; - if (!fadeSky) { - int count = thread->count_for_thread(args.DestY(), args.Count()); - for (int index = 0; index < count; index++) { uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; @@ -89,7 +74,7 @@ namespace swrenderer BgraColor solid_top_fill = solid_top; BgraColor solid_bottom_fill = solid_bottom; - int index = skipped; + int index = 0; // Top solid color: while (index < start_fadetop_y) @@ -97,7 +82,7 @@ namespace swrenderer *dest = solid_top; dest += pitch; frac += fracstep; - index += num_cores; + index++; } // Top fade: @@ -106,7 +91,7 @@ namespace swrenderer uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint32_t fg = source0[sample_index]; - uint32_t alpha = MAX(MIN(frac >> (16 - start_fade), 256), 0); + uint32_t alpha = max(min(frac >> (16 - start_fade), 256), 0); uint32_t inv_alpha = 256 - alpha; BgraColor c = fg; @@ -117,7 +102,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Textured center: @@ -128,7 +113,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Fade bottom: @@ -137,7 +122,7 @@ namespace swrenderer uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint32_t fg = source0[sample_index]; - uint32_t alpha = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + uint32_t alpha = max(min(((2 << 24) - frac) >> (16 - start_fade), 256), 0); uint32_t inv_alpha = 256 - alpha; BgraColor c = fg; @@ -148,7 +133,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Bottom solid color: @@ -156,20 +141,15 @@ namespace swrenderer { *dest = solid_bottom; dest += pitch; - index += num_cores; + index++; } } }; - class DrawSkyDouble32Command : public DrawerCommand + class DrawSkyDouble32Command { - protected: - SkyDrawerArgs args; - public: - DrawSkyDouble32Command(const SkyDrawerArgs &args) : args(args) { } - - void Execute(DrawerThread *thread) override + static void DrawColumn(const SkyDrawerArgs& args) { uint32_t *dest = (uint32_t *)args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); @@ -181,9 +161,7 @@ namespace swrenderer int32_t frac = args.TextureVPos(); int32_t fracstep = args.TextureVStep(); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); - int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; + int count = args.Count(); uint32_t solid_top = args.SolidTopColor(); uint32_t solid_bottom = args.SolidBottomColor(); @@ -201,22 +179,15 @@ namespace swrenderer start_fadebottom_y = clamp(start_fadebottom_y, 0, count); end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * skipped; - fracstep *= num_cores; - pitch *= num_cores; - if (!fadeSky) { - count = thread->count_for_thread(args.DestY(), count); - for (int index = 0; index < count; index++) { uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint32_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } @@ -231,7 +202,7 @@ namespace swrenderer BgraColor solid_top_fill = solid_top; BgraColor solid_bottom_fill = solid_bottom; - int index = skipped; + int index = 0; // Top solid color: while (index < start_fadetop_y) @@ -239,7 +210,7 @@ namespace swrenderer *dest = solid_top; dest += pitch; frac += fracstep; - index += num_cores; + index++; } // Top fade: @@ -249,11 +220,11 @@ namespace swrenderer uint32_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } - uint32_t alpha = MAX(MIN(frac >> (16 - start_fade), 256), 0); + uint32_t alpha = max(min(frac >> (16 - start_fade), 256), 0); uint32_t inv_alpha = 256 - alpha; BgraColor c = fg; @@ -262,7 +233,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Textured center: @@ -272,14 +243,14 @@ namespace swrenderer uint32_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } *dest = fg; frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Fade bottom: @@ -289,11 +260,11 @@ namespace swrenderer uint32_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } - uint32_t alpha = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + uint32_t alpha = max(min(((2 << 24) - frac) >> (16 - start_fade), 256), 0); uint32_t inv_alpha = 256 - alpha; BgraColor c = fg; @@ -302,7 +273,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Bottom solid color: @@ -310,7 +281,7 @@ namespace swrenderer { *dest = solid_bottom; dest += pitch; - index += num_cores; + index++; } } }; diff --git a/src/rendering/swrenderer/drawers/r_draw_sky32_sse2.h b/src/rendering/swrenderer/drawers/r_draw_sky32_sse2.h index 64afca87ac6..bc2411b835c 100644 --- a/src/rendering/swrenderer/drawers/r_draw_sky32_sse2.h +++ b/src/rendering/swrenderer/drawers/r_draw_sky32_sse2.h @@ -27,15 +27,10 @@ namespace swrenderer { - class DrawSkySingle32Command : public DrawerCommand + class DrawSkySingle32Command { - protected: - SkyDrawerArgs args; - public: - DrawSkySingle32Command(const SkyDrawerArgs &args) : args(args) { } - - void Execute(DrawerThread *thread) override + static void DrawColumn(const SkyDrawerArgs& args) { uint32_t *dest = (uint32_t *)args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); @@ -49,9 +44,7 @@ namespace swrenderer uint32_t solid_bottom = args.SolidBottomColor(); bool fadeSky = args.FadeSky(); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); - int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; + int count = args.Count(); // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: int start_fade = 2; // How fast it should fade out @@ -65,15 +58,8 @@ namespace swrenderer start_fadebottom_y = clamp(start_fadebottom_y, 0, count); end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * skipped; - fracstep *= num_cores; - pitch *= num_cores; - if (!fadeSky) { - int count = thread->count_for_thread(args.DestY(), args.Count()); - for (int index = 0; index < count; index++) { uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; @@ -88,7 +74,7 @@ namespace swrenderer __m128i solid_top_fill = _mm_unpacklo_epi8(_mm_cvtsi32_si128(solid_top), _mm_setzero_si128()); __m128i solid_bottom_fill = _mm_unpacklo_epi8(_mm_cvtsi32_si128(solid_bottom), _mm_setzero_si128()); - int index = skipped; + int index = 0; // Top solid color: while (index < start_fadetop_y) @@ -96,7 +82,7 @@ namespace swrenderer *dest = solid_top; dest += pitch; frac += fracstep; - index += num_cores; + index++; } // Top fade: @@ -105,7 +91,7 @@ namespace swrenderer uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint32_t fg = source0[sample_index]; - __m128i alpha = _mm_set1_epi16(MAX(MIN(frac >> (16 - start_fade), 256), 0)); + __m128i alpha = _mm_set1_epi16(max(min(frac >> (16 - start_fade), 256), 0)); __m128i inv_alpha = _mm_sub_epi16(_mm_set1_epi16(256), alpha); __m128i c = _mm_unpacklo_epi8(_mm_cvtsi32_si128(fg), _mm_setzero_si128()); @@ -114,7 +100,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Textured center: @@ -125,7 +111,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Fade bottom: @@ -134,7 +120,7 @@ namespace swrenderer uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint32_t fg = source0[sample_index]; - __m128i alpha = _mm_set1_epi16(MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0)); + __m128i alpha = _mm_set1_epi16(max(min(((2 << 24) - frac) >> (16 - start_fade), 256), 0)); __m128i inv_alpha = _mm_sub_epi16(_mm_set1_epi16(256), alpha); __m128i c = _mm_unpacklo_epi8(_mm_cvtsi32_si128(fg), _mm_setzero_si128()); @@ -143,7 +129,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Bottom solid color: @@ -151,20 +137,15 @@ namespace swrenderer { *dest = solid_bottom; dest += pitch; - index += num_cores; + index++; } } }; - class DrawSkyDouble32Command : public DrawerCommand + class DrawSkyDouble32Command { - protected: - SkyDrawerArgs args; - public: - DrawSkyDouble32Command(const SkyDrawerArgs &args) : args(args) { } - - void Execute(DrawerThread *thread) override + static void DrawColumn(const SkyDrawerArgs& args) { uint32_t *dest = (uint32_t *)args.Dest(); int pitch = args.Viewport()->RenderTarget->GetPitch(); @@ -176,42 +157,21 @@ namespace swrenderer int32_t frac = args.TextureVPos(); int32_t fracstep = args.TextureVStep(); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); - int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; + int count = args.Count(); uint32_t solid_top = args.SolidTopColor(); uint32_t solid_bottom = args.SolidBottomColor(); bool fadeSky = args.FadeSky(); - - // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: - int start_fade = 2; // How fast it should fade out - int fade_length = (1 << (24 - start_fade)); - int start_fadetop_y = (-frac) / fracstep; - int end_fadetop_y = (fade_length - frac) / fracstep; - int start_fadebottom_y = ((2 << 24) - fade_length - frac) / fracstep; - int end_fadebottom_y = ((2 << 24) - frac) / fracstep; - start_fadetop_y = clamp(start_fadetop_y, 0, count); - end_fadetop_y = clamp(end_fadetop_y, 0, count); - start_fadebottom_y = clamp(start_fadebottom_y, 0, count); - end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - - dest = thread->dest_for_thread(args.DestY(), pitch, dest); - frac += fracstep * skipped; - fracstep *= num_cores; - pitch *= num_cores; if (!fadeSky) { - count = thread->count_for_thread(args.DestY(), count); - for (int index = 0; index < count; index++) { uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint32_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } @@ -223,10 +183,22 @@ namespace swrenderer return; } + // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: + int start_fade = 2; // How fast it should fade out + int fade_length = (1 << (24 - start_fade)); + int start_fadetop_y = (-frac) / fracstep; + int end_fadetop_y = (fade_length - frac) / fracstep; + int start_fadebottom_y = ((2 << 24) - fade_length - frac) / fracstep; + int end_fadebottom_y = ((2 << 24) - frac) / fracstep; + start_fadetop_y = clamp(start_fadetop_y, 0, count); + end_fadetop_y = clamp(end_fadetop_y, 0, count); + start_fadebottom_y = clamp(start_fadebottom_y, 0, count); + end_fadebottom_y = clamp(end_fadebottom_y, 0, count); + __m128i solid_top_fill = _mm_unpacklo_epi8(_mm_cvtsi32_si128(solid_top), _mm_setzero_si128()); __m128i solid_bottom_fill = _mm_unpacklo_epi8(_mm_cvtsi32_si128(solid_bottom), _mm_setzero_si128()); - int index = skipped; + int index = 0; // Top solid color: while (index < start_fadetop_y) @@ -234,7 +206,7 @@ namespace swrenderer *dest = solid_top; dest += pitch; frac += fracstep; - index += num_cores; + index++; } // Top fade: @@ -244,11 +216,11 @@ namespace swrenderer uint32_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } - __m128i alpha = _mm_set1_epi16(MAX(MIN(frac >> (16 - start_fade), 256), 0)); + __m128i alpha = _mm_set1_epi16(max(min(frac >> (16 - start_fade), 256), 0)); __m128i inv_alpha = _mm_sub_epi16(_mm_set1_epi16(256), alpha); __m128i c = _mm_unpacklo_epi8(_mm_cvtsi32_si128(fg), _mm_setzero_si128()); @@ -257,7 +229,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Textured center: @@ -267,14 +239,14 @@ namespace swrenderer uint32_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } *dest = fg; frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Fade bottom: @@ -284,11 +256,11 @@ namespace swrenderer uint32_t fg = source0[sample_index]; if (fg == 0) { - uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + uint32_t sample_index2 = min(sample_index, maxtextureheight1); fg = source1[sample_index2]; } - __m128i alpha = _mm_set1_epi16(MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0)); + __m128i alpha = _mm_set1_epi16(max(min(((2 << 24) - frac) >> (16 - start_fade), 256), 0)); __m128i inv_alpha = _mm_sub_epi16(_mm_set1_epi16(256), alpha); __m128i c = _mm_unpacklo_epi8(_mm_cvtsi32_si128(fg), _mm_setzero_si128()); @@ -297,7 +269,7 @@ namespace swrenderer frac += fracstep; dest += pitch; - index += num_cores; + index++; } // Bottom solid color: @@ -305,7 +277,7 @@ namespace swrenderer { *dest = solid_bottom; dest += pitch; - index += num_cores; + index++; } } }; diff --git a/src/rendering/swrenderer/drawers/r_draw_span32.h b/src/rendering/swrenderer/drawers/r_draw_span32.h index f0b83c79670..1c1e3e55dec 100644 --- a/src/rendering/swrenderer/drawers/r_draw_span32.h +++ b/src/rendering/swrenderer/drawers/r_draw_span32.h @@ -51,14 +51,9 @@ namespace swrenderer } template - class DrawSpan32T : public DrawerCommand + class DrawSpan32T { - protected: - SpanDrawerArgs args; - public: - DrawSpan32T(const SpanDrawerArgs &drawerargs) : args(drawerargs) { } - struct TextureData { uint32_t width; @@ -72,12 +67,10 @@ namespace swrenderer const uint32_t *source; }; - void Execute(DrawerThread *thread) override + static void DrawColumn(const SpanDrawerArgs& args) { using namespace DrawSpan32TModes; - if (thread->line_skipped_by_thread(args.DestY())) return; - TextureData texdata; texdata.width = args.TextureWidth(); texdata.height = args.TextureHeight(); @@ -101,8 +94,8 @@ namespace swrenderer break; texdata.source += texdata.width * texdata.height; - texdata.width = MAX(texdata.width / 2, 1); - texdata.height = MAX(texdata.height / 2, 1); + texdata.width = max(texdata.width / 2, 1); + texdata.height = max(texdata.height / 2, 1); level--; } } @@ -119,16 +112,16 @@ namespace swrenderer if (is_nearest_filter) { if (is_64x64) - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); else - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); } else { if (is_64x64) - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); else - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); } } else @@ -136,22 +129,22 @@ namespace swrenderer if (is_nearest_filter) { if (is_64x64) - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); else - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); } else { if (is_64x64) - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); else - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); } } } template - FORCEINLINE void Loop(DrawerThread *thread, TextureData texdata, ShadeConstants shade_constants) + FORCEINLINE static void Loop(const SpanDrawerArgs& args, TextureData texdata, ShadeConstants shade_constants) { using namespace DrawSpan32TModes; @@ -229,7 +222,7 @@ namespace swrenderer } template - FORCEINLINE uint32_t Sample(uint32_t width, uint32_t height, uint32_t xone, uint32_t yone, uint32_t xstep, uint32_t ystep, uint32_t xfrac, uint32_t yfrac, const uint32_t *source) + FORCEINLINE static uint32_t Sample(uint32_t width, uint32_t height, uint32_t xone, uint32_t yone, uint32_t xstep, uint32_t ystep, uint32_t xfrac, uint32_t yfrac, const uint32_t *source) { using namespace DrawSpan32TModes; @@ -291,7 +284,7 @@ namespace swrenderer } template - FORCEINLINE BgraColor Shade(BgraColor fgcolor, uint32_t light, uint32_t desaturate, uint32_t inv_desaturate, BgraColor shade_fade, BgraColor shade_light, const DrawerLight *lights, int num_lights, float viewpos_x) + FORCEINLINE static BgraColor Shade(BgraColor fgcolor, uint32_t light, uint32_t desaturate, uint32_t inv_desaturate, BgraColor shade_fade, BgraColor shade_light, const DrawerLight *lights, int num_lights, float viewpos_x) { using namespace DrawSpan32TModes; @@ -313,7 +306,7 @@ namespace swrenderer return AddLights(material, fgcolor, lights, num_lights, viewpos_x); } - FORCEINLINE BgraColor AddLights(BgraColor material, BgraColor fgcolor, const DrawerLight *lights, int num_lights, float viewpos_x) + FORCEINLINE static BgraColor AddLights(BgraColor material, BgraColor fgcolor, const DrawerLight *lights, int num_lights, float viewpos_x) { using namespace DrawSpan32TModes; @@ -331,13 +324,13 @@ namespace swrenderer // L = light-pos // dist = sqrt(dot(L, L)) - // distance_attenuation = 1 - MIN(dist * (1/radius), 1) + // distance_attenuation = 1 - min(dist * (1/radius), 1) float Lyz2 = light_y; // L.y*L.y + L.z*L.z float Lx = light_x - viewpos_x; float dist2 = Lyz2 + Lx * Lx; float rcp_dist = 1.f/sqrt(dist2); float dist = dist2 * rcp_dist; - float distance_attenuation = 256.0f - MIN(dist * light_radius, 256.0f); + float distance_attenuation = 256.0f - min(dist * light_radius, 256.0f); // The simple light type float simple_attenuation = distance_attenuation; @@ -355,17 +348,17 @@ namespace swrenderer lit.b += (light_color.b * attenuation) >> 8; } - lit.r = MIN(lit.r, 256); - lit.g = MIN(lit.g, 256); - lit.b = MIN(lit.b, 256); + lit.r = min(lit.r, 256); + lit.g = min(lit.g, 256); + lit.b = min(lit.b, 256); - fgcolor.r = MIN(fgcolor.r + ((material.r * lit.r) >> 8), 255); - fgcolor.g = MIN(fgcolor.g + ((material.g * lit.g) >> 8), 255); - fgcolor.b = MIN(fgcolor.b + ((material.b * lit.b) >> 8), 255); + fgcolor.r = min(fgcolor.r + ((material.r * lit.r) >> 8), 255); + fgcolor.g = min(fgcolor.g + ((material.g * lit.g) >> 8), 255); + fgcolor.b = min(fgcolor.b + ((material.b * lit.b) >> 8), 255); return fgcolor; } - FORCEINLINE BgraColor Blend(BgraColor fgcolor, BgraColor bgcolor, uint32_t srcalpha, uint32_t destalpha, unsigned int ifgcolor) + FORCEINLINE static BgraColor Blend(BgraColor fgcolor, BgraColor bgcolor, uint32_t srcalpha, uint32_t destalpha, unsigned int ifgcolor) { using namespace DrawSpan32TModes; @@ -388,9 +381,9 @@ namespace swrenderer bgcolor.b = bgcolor.b * destalpha; BgraColor outcolor; - outcolor.r = MIN((fgcolor.r + bgcolor.r) >> 8, 255); - outcolor.g = MIN((fgcolor.g + bgcolor.g) >> 8, 255); - outcolor.b = MIN((fgcolor.b + bgcolor.b) >> 8, 255); + outcolor.r = min((fgcolor.r + bgcolor.r) >> 8, 255); + outcolor.g = min((fgcolor.g + bgcolor.g) >> 8, 255); + outcolor.b = min((fgcolor.b + bgcolor.b) >> 8, 255); return outcolor; } else @@ -412,21 +405,21 @@ namespace swrenderer BgraColor outcolor; if (BlendT::Mode == (int)SpanBlendModes::AddClamp) { - outcolor.r = MIN((fgcolor.r + bgcolor.r) >> 8, 255); - outcolor.g = MIN((fgcolor.g + bgcolor.g) >> 8, 255); - outcolor.b = MIN((fgcolor.b + bgcolor.b) >> 8, 255); + outcolor.r = min((fgcolor.r + bgcolor.r) >> 8, 255); + outcolor.g = min((fgcolor.g + bgcolor.g) >> 8, 255); + outcolor.b = min((fgcolor.b + bgcolor.b) >> 8, 255); } else if (BlendT::Mode == (int)SpanBlendModes::SubClamp) { - outcolor.r = MAX(int32_t(fgcolor.r - bgcolor.r) >> 8, 0); - outcolor.g = MAX(int32_t(fgcolor.g - bgcolor.g) >> 8, 0); - outcolor.b = MAX(int32_t(fgcolor.b - bgcolor.b) >> 8, 0); + outcolor.r = max(int32_t(fgcolor.r - bgcolor.r) >> 8, 0); + outcolor.g = max(int32_t(fgcolor.g - bgcolor.g) >> 8, 0); + outcolor.b = max(int32_t(fgcolor.b - bgcolor.b) >> 8, 0); } else if (BlendT::Mode == (int)SpanBlendModes::RevSubClamp) { - outcolor.r = MAX(int32_t(bgcolor.r - fgcolor.r) >> 8, 0); - outcolor.g = MAX(int32_t(bgcolor.g - fgcolor.g) >> 8, 0); - outcolor.b = MAX(int32_t(bgcolor.b - fgcolor.b) >> 8, 0); + outcolor.r = max(int32_t(bgcolor.r - fgcolor.r) >> 8, 0); + outcolor.g = max(int32_t(bgcolor.g - fgcolor.g) >> 8, 0); + outcolor.b = max(int32_t(bgcolor.b - fgcolor.b) >> 8, 0); } outcolor.a = 255; return outcolor; diff --git a/src/rendering/swrenderer/drawers/r_draw_span32_sse2.h b/src/rendering/swrenderer/drawers/r_draw_span32_sse2.h index f5823a3eb7f..230ba8c134a 100644 --- a/src/rendering/swrenderer/drawers/r_draw_span32_sse2.h +++ b/src/rendering/swrenderer/drawers/r_draw_span32_sse2.h @@ -51,14 +51,9 @@ namespace swrenderer } template - class DrawSpan32T : public DrawerCommand + class DrawSpan32T { - protected: - SpanDrawerArgs args; - public: - DrawSpan32T(const SpanDrawerArgs &drawerargs) : args(drawerargs) { } - struct TextureData { uint32_t width; @@ -72,12 +67,10 @@ namespace swrenderer const uint32_t *source; }; - void Execute(DrawerThread *thread) override + static void DrawColumn(const SpanDrawerArgs& args) { using namespace DrawSpan32TModes; - if (thread->line_skipped_by_thread(args.DestY())) return; - TextureData texdata; texdata.width = args.TextureWidth(); texdata.height = args.TextureHeight(); @@ -101,8 +94,8 @@ namespace swrenderer break; texdata.source += texdata.width * texdata.height; - texdata.width = MAX(texdata.width / 2, 1); - texdata.height = MAX(texdata.height / 2, 1); + texdata.width = max(texdata.width / 2, 1); + texdata.height = max(texdata.height / 2, 1); level--; } } @@ -119,16 +112,16 @@ namespace swrenderer if (is_nearest_filter) { if (is_64x64) - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); else - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); } else { if (is_64x64) - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); else - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); } } else @@ -136,22 +129,22 @@ namespace swrenderer if (is_nearest_filter) { if (is_64x64) - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); else - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); } else { if (is_64x64) - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); else - Loop(thread, texdata, shade_constants); + Loop(args, texdata, shade_constants); } } } template - FORCEINLINE void VECTORCALL Loop(DrawerThread *thread, TextureData texdata, ShadeConstants shade_constants) + FORCEINLINE static void VECTORCALL Loop(const SpanDrawerArgs& args, TextureData texdata, ShadeConstants shade_constants) { using namespace DrawSpan32TModes; @@ -263,7 +256,7 @@ namespace swrenderer } template - FORCEINLINE unsigned int VECTORCALL Sample(uint32_t width, uint32_t height, uint32_t xone, uint32_t yone, uint32_t xstep, uint32_t ystep, uint32_t xfrac, uint32_t yfrac, const uint32_t *source) + FORCEINLINE static unsigned int VECTORCALL Sample(uint32_t width, uint32_t height, uint32_t xone, uint32_t yone, uint32_t xstep, uint32_t ystep, uint32_t xfrac, uint32_t yfrac, const uint32_t *source) { using namespace DrawSpan32TModes; @@ -325,7 +318,7 @@ namespace swrenderer } template - FORCEINLINE __m128i VECTORCALL Shade(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light, const DrawerLight *lights, int num_lights, __m128 viewpos_x) + FORCEINLINE static __m128i VECTORCALL Shade(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light, const DrawerLight *lights, int num_lights, __m128 viewpos_x) { using namespace DrawSpan32TModes; @@ -357,7 +350,7 @@ namespace swrenderer return AddLights(material, fgcolor, lights, num_lights, viewpos_x); } - FORCEINLINE __m128i VECTORCALL AddLights(__m128i material, __m128i fgcolor, const DrawerLight *lights, int num_lights, __m128 viewpos_x) + FORCEINLINE static __m128i VECTORCALL AddLights(__m128i material, __m128i fgcolor, const DrawerLight *lights, int num_lights, __m128 viewpos_x) { using namespace DrawSpan32TModes; @@ -373,7 +366,7 @@ namespace swrenderer // L = light-pos // dist = sqrt(dot(L, L)) - // distance_attenuation = 1 - MIN(dist * (1/radius), 1) + // distance_attenuation = 1 - min(dist * (1/radius), 1) __m128 Lyz2 = light_y; // L.y*L.y + L.z*L.z __m128 Lx = _mm_sub_ps(light_x, viewpos_x); __m128 dist2 = _mm_add_ps(Lyz2, _mm_mul_ps(Lx, Lx)); @@ -406,7 +399,7 @@ namespace swrenderer return fgcolor; } - FORCEINLINE __m128i VECTORCALL Blend(__m128i fgcolor, __m128i bgcolor, uint32_t srcalpha, uint32_t destalpha, unsigned int ifgcolor0, unsigned int ifgcolor1) + FORCEINLINE static __m128i VECTORCALL Blend(__m128i fgcolor, __m128i bgcolor, uint32_t srcalpha, uint32_t destalpha, unsigned int ifgcolor0, unsigned int ifgcolor1) { using namespace DrawSpan32TModes; diff --git a/src/rendering/swrenderer/drawers/r_draw_sprite32.h b/src/rendering/swrenderer/drawers/r_draw_sprite32.h index e4026468978..6ae563dc6e6 100644 --- a/src/rendering/swrenderer/drawers/r_draw_sprite32.h +++ b/src/rendering/swrenderer/drawers/r_draw_sprite32.h @@ -54,14 +54,10 @@ namespace swrenderer } template - class DrawSprite32T : public DrawerCommand + class DrawSprite32T { public: - SpriteDrawerArgs args; - - DrawSprite32T(const SpriteDrawerArgs &drawerargs) : args(drawerargs) { } - - void Execute(DrawerThread *thread) override + static void DrawColumn(const SpriteDrawerArgs& args) { using namespace DrawSprite32TModes; @@ -74,33 +70,33 @@ namespace swrenderer if (shade_constants.simple_shade) { if (is_nearest_filter) - Loop(thread, shade_constants); + Loop(args, shade_constants); else - Loop(thread, shade_constants); + Loop(args, shade_constants); } else { if (is_nearest_filter) - Loop(thread, shade_constants); + Loop(args, shade_constants); else - Loop(thread, shade_constants); + Loop(args, shade_constants); } } else // no linear filtering for translated, shaded or fill { if (shade_constants.simple_shade) { - Loop(thread, shade_constants); + Loop(args, shade_constants); } else { - Loop(thread, shade_constants); + Loop(args, shade_constants); } } } template - FORCEINLINE void Loop(DrawerThread *thread, ShadeConstants shade_constants) + FORCEINLINE static void Loop(const SpriteDrawerArgs& args, ShadeConstants shade_constants) { using namespace DrawSprite32TModes; @@ -147,9 +143,9 @@ namespace swrenderer shade_light.g = shade_constants.light_green; shade_light.b = shade_constants.light_blue; desaturate = shade_constants.desaturate; - lightcontrib.r = MIN(light + dynlight.r, 256) - light; - lightcontrib.g = MIN(light + dynlight.g, 256) - light; - lightcontrib.b = MIN(light + dynlight.b, 256) - light; + lightcontrib.r = min(light + dynlight.r, 256) - light; + lightcontrib.g = min(light + dynlight.g, 256) - light; + lightcontrib.b = min(light + dynlight.b, 256) - light; mlight.r = light; mlight.g = light; mlight.b = light; @@ -165,12 +161,14 @@ namespace swrenderer shade_light.b = 0; desaturate = 0; lightcontrib = 0; - mlight.r = MIN(light + dynlight.r, 256); - mlight.g = MIN(light + dynlight.g, 256); - mlight.b = MIN(light + dynlight.b, 256); + mlight.r = min(light + dynlight.r, 256); + mlight.g = min(light + dynlight.g, 256); + mlight.b = min(light + dynlight.b, 256); } int count = args.Count(); + if (count <= 0) return; + int pitch = args.Viewport()->RenderTarget->GetPitch(); uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); @@ -178,13 +176,6 @@ namespace swrenderer uint32_t *dest = (uint32_t*)args.Dest(); int dest_y = args.DestY(); - count = thread->count_for_thread(dest_y, count); - if (count <= 0) return; - frac += thread->skipped_by_thread(dest_y) * fracstep; - dest = thread->dest_for_thread(dest_y, pitch, dest); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - if (FilterModeT::Mode == (int)FilterModes::Linear) { frac -= one / 2; @@ -220,7 +211,7 @@ namespace swrenderer } template - FORCEINLINE BgraColor Sample(uint32_t frac, const uint32_t *source, const uint32_t *source2, const uint32_t *translation, int textureheight, uint32_t one, uint32_t texturefracx, uint32_t color, uint32_t srccolor) + FORCEINLINE static BgraColor Sample(uint32_t frac, const uint32_t *source, const uint32_t *source2, const uint32_t *translation, int textureheight, uint32_t one, uint32_t texturefracx, uint32_t color, uint32_t srccolor) { using namespace DrawSprite32TModes; @@ -269,7 +260,7 @@ namespace swrenderer } } - FORCEINLINE uint32_t SampleShade(uint32_t frac, const uint32_t *source, const uint8_t *colormap) + FORCEINLINE static uint32_t SampleShade(uint32_t frac, const uint32_t *source, const uint8_t *colormap) { using namespace DrawSprite32TModes; @@ -286,7 +277,7 @@ namespace swrenderer } template - FORCEINLINE BgraColor Shade(BgraColor fgcolor, BgraColor mlight, uint32_t desaturate, uint32_t inv_desaturate, BgraColor shade_fade, BgraColor shade_light, BgraColor lightcontrib) + FORCEINLINE static BgraColor Shade(BgraColor fgcolor, BgraColor mlight, uint32_t desaturate, uint32_t inv_desaturate, BgraColor shade_fade, BgraColor shade_light, BgraColor lightcontrib) { using namespace DrawSprite32TModes; @@ -309,14 +300,14 @@ namespace swrenderer fgcolor.g = (((shade_fade.g + ((fgcolor.g * inv_desaturate + intensity) >> 8) * mlight.g) >> 8) * shade_light.g) >> 8; fgcolor.b = (((shade_fade.b + ((fgcolor.b * inv_desaturate + intensity) >> 8) * mlight.b) >> 8) * shade_light.b) >> 8; - fgcolor.r = MIN(fgcolor.r + lit_dynlight.r, 255); - fgcolor.g = MIN(fgcolor.g + lit_dynlight.g, 255); - fgcolor.b = MIN(fgcolor.b + lit_dynlight.b, 255); + fgcolor.r = min(fgcolor.r + lit_dynlight.r, 255); + fgcolor.g = min(fgcolor.g + lit_dynlight.g, 255); + fgcolor.b = min(fgcolor.b + lit_dynlight.b, 255); return fgcolor; } } - FORCEINLINE BgraColor Blend(BgraColor fgcolor, BgraColor bgcolor, uint32_t ifgcolor, uint32_t ifgshade, uint32_t srcalpha, uint32_t destalpha) + FORCEINLINE static BgraColor Blend(BgraColor fgcolor, BgraColor bgcolor, uint32_t ifgcolor, uint32_t ifgshade, uint32_t srcalpha, uint32_t destalpha) { using namespace DrawSprite32TModes; @@ -341,9 +332,9 @@ namespace swrenderer { uint32_t alpha = ifgshade; BgraColor outcolor; - outcolor.r = MIN(((fgcolor.r * alpha) >> 8) + bgcolor.r, 255); - outcolor.g = MIN(((fgcolor.g * alpha) >> 8) + bgcolor.g, 255); - outcolor.b = MIN(((fgcolor.b * alpha) >> 8) + bgcolor.b, 255); + outcolor.r = min(((fgcolor.r * alpha) >> 8) + bgcolor.r, 255); + outcolor.g = min(((fgcolor.g * alpha) >> 8) + bgcolor.g, 255); + outcolor.b = min(((fgcolor.b * alpha) >> 8) + bgcolor.b, 255); outcolor.a = 255; return outcolor; } @@ -366,21 +357,21 @@ namespace swrenderer BgraColor outcolor; if (BlendT::Mode == (int)SpriteBlendModes::AddClamp) { - outcolor.r = MIN((fgcolor.r + bgcolor.r) >> 8, 255); - outcolor.g = MIN((fgcolor.g + bgcolor.g) >> 8, 255); - outcolor.b = MIN((fgcolor.b + bgcolor.b) >> 8, 255); + outcolor.r = min((fgcolor.r + bgcolor.r) >> 8, 255); + outcolor.g = min((fgcolor.g + bgcolor.g) >> 8, 255); + outcolor.b = min((fgcolor.b + bgcolor.b) >> 8, 255); } else if (BlendT::Mode == (int)SpriteBlendModes::SubClamp) { - outcolor.r = MAX(int32_t(fgcolor.r - bgcolor.r) >> 8, 0); - outcolor.g = MAX(int32_t(fgcolor.g - bgcolor.g) >> 8, 0); - outcolor.b = MAX(int32_t(fgcolor.b - bgcolor.b) >> 8, 0); + outcolor.r = max(int32_t(fgcolor.r - bgcolor.r) >> 8, 0); + outcolor.g = max(int32_t(fgcolor.g - bgcolor.g) >> 8, 0); + outcolor.b = max(int32_t(fgcolor.b - bgcolor.b) >> 8, 0); } else if (BlendT::Mode == (int)SpriteBlendModes::RevSubClamp) { - outcolor.r = MAX(int32_t(bgcolor.r - fgcolor.r) >> 8, 0); - outcolor.g = MAX(int32_t(bgcolor.g - fgcolor.g) >> 8, 0); - outcolor.b = MAX(int32_t(bgcolor.b - fgcolor.b) >> 8, 0); + outcolor.r = max(int32_t(bgcolor.r - fgcolor.r) >> 8, 0); + outcolor.g = max(int32_t(bgcolor.g - fgcolor.g) >> 8, 0); + outcolor.b = max(int32_t(bgcolor.b - fgcolor.b) >> 8, 0); } outcolor.a = 255; return outcolor; diff --git a/src/rendering/swrenderer/drawers/r_draw_sprite32_sse2.h b/src/rendering/swrenderer/drawers/r_draw_sprite32_sse2.h index d07dbc5859e..d59f1d204d3 100644 --- a/src/rendering/swrenderer/drawers/r_draw_sprite32_sse2.h +++ b/src/rendering/swrenderer/drawers/r_draw_sprite32_sse2.h @@ -54,14 +54,10 @@ namespace swrenderer } template - class DrawSprite32T : public DrawerCommand + class DrawSprite32T { public: - SpriteDrawerArgs args; - - DrawSprite32T(const SpriteDrawerArgs &drawerargs) : args(drawerargs) { } - - void Execute(DrawerThread *thread) override + static void DrawColumn(const SpriteDrawerArgs& args) { using namespace DrawSprite32TModes; @@ -74,33 +70,33 @@ namespace swrenderer if (shade_constants.simple_shade) { if (is_nearest_filter) - Loop(thread, shade_constants); + Loop(args, shade_constants); else - Loop(thread, shade_constants); + Loop(args, shade_constants); } else { if (is_nearest_filter) - Loop(thread, shade_constants); + Loop(args, shade_constants); else - Loop(thread, shade_constants); + Loop(args, shade_constants); } } else // no linear filtering for translated, shaded or fill { if (shade_constants.simple_shade) { - Loop(thread, shade_constants); + Loop(args, shade_constants); } else { - Loop(thread, shade_constants); + Loop(args, shade_constants); } } } template - FORCEINLINE void VECTORCALL Loop(DrawerThread *thread, ShadeConstants shade_constants) + FORCEINLINE static void VECTORCALL Loop(const SpriteDrawerArgs& args, ShadeConstants shade_constants) { using namespace DrawSprite32TModes; @@ -162,6 +158,7 @@ namespace swrenderer } int count = args.Count(); + if (count <= 0) return; int pitch = args.Viewport()->RenderTarget->GetPitch(); uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); @@ -169,13 +166,6 @@ namespace swrenderer uint32_t *dest = (uint32_t*)args.Dest(); int dest_y = args.DestY(); - count = thread->count_for_thread(dest_y, count); - if (count <= 0) return; - frac += thread->skipped_by_thread(dest_y) * fracstep; - dest = thread->dest_for_thread(dest_y, pitch, dest); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - if (FilterModeT::Mode == (int)FilterModes::Linear) { frac -= one / 2; @@ -255,7 +245,7 @@ namespace swrenderer } template - FORCEINLINE unsigned int VECTORCALL Sample(uint32_t frac, const uint32_t *source, const uint32_t *source2, const uint32_t *translation, int textureheight, uint32_t one, uint32_t texturefracx, uint32_t color, uint32_t srccolor) + FORCEINLINE static unsigned int VECTORCALL Sample(uint32_t frac, const uint32_t *source, const uint32_t *source2, const uint32_t *translation, int textureheight, uint32_t one, uint32_t texturefracx, uint32_t color, uint32_t srccolor) { using namespace DrawSprite32TModes; @@ -304,7 +294,7 @@ namespace swrenderer } } - FORCEINLINE unsigned int VECTORCALL SampleShade(uint32_t frac, const uint32_t *source, const uint8_t *colormap) + FORCEINLINE static unsigned int VECTORCALL SampleShade(uint32_t frac, const uint32_t *source, const uint8_t *colormap) { using namespace DrawSprite32TModes; @@ -321,7 +311,7 @@ namespace swrenderer } template - FORCEINLINE __m128i VECTORCALL Shade(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light, __m128i lightcontrib) + FORCEINLINE static __m128i VECTORCALL Shade(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light, __m128i lightcontrib) { using namespace DrawSprite32TModes; @@ -360,7 +350,7 @@ namespace swrenderer } } - FORCEINLINE __m128i VECTORCALL Blend(__m128i fgcolor, __m128i bgcolor, unsigned int ifgcolor0, unsigned int ifgcolor1, unsigned int ifgshade0, unsigned int ifgshade1, uint32_t srcalpha, uint32_t destalpha) + FORCEINLINE static __m128i VECTORCALL Blend(__m128i fgcolor, __m128i bgcolor, unsigned int ifgcolor0, unsigned int ifgcolor1, unsigned int ifgshade0, unsigned int ifgshade1, uint32_t srcalpha, uint32_t destalpha) { using namespace DrawSprite32TModes; diff --git a/src/rendering/swrenderer/drawers/r_draw_wall32.h b/src/rendering/swrenderer/drawers/r_draw_wall32.h index 2f40129017b..92056a9b734 100644 --- a/src/rendering/swrenderer/drawers/r_draw_wall32.h +++ b/src/rendering/swrenderer/drawers/r_draw_wall32.h @@ -47,12 +47,10 @@ namespace swrenderer } template - class DrawWall32T : public DrawWallCommand + class DrawWall32T { public: - DrawWall32T(const WallDrawerArgs &drawerargs) : DrawWallCommand(drawerargs) { } - - void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override + static void DrawColumn(const WallColumnDrawerArgs& args) { using namespace DrawWall32TModes; @@ -62,24 +60,27 @@ namespace swrenderer if (shade_constants.simple_shade) { if (is_nearest_filter) - Loop(thread, args, shade_constants); + Loop(args, shade_constants); else - Loop(thread, args, shade_constants); + Loop(args, shade_constants); } else { if (is_nearest_filter) - Loop(thread, args, shade_constants); + Loop(args, shade_constants); else - Loop(thread, args, shade_constants); + Loop(args, shade_constants); } } template - FORCEINLINE void Loop(DrawerThread *thread, const WallColumnDrawerArgs& args, ShadeConstants shade_constants) + FORCEINLINE static void Loop(const WallColumnDrawerArgs& args, ShadeConstants shade_constants) { using namespace DrawWall32TModes; + int count = args.Count(); + if (count <= 0) return; + const uint32_t *source = (const uint32_t*)args.TexturePixels(); const uint32_t *source2 = (const uint32_t*)args.TexturePixels2(); int textureheight = args.TextureHeight(); @@ -115,7 +116,6 @@ namespace swrenderer desaturate = 0; } - int count = args.Count(); int pitch = args.Viewport()->RenderTarget->GetPitch(); uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); @@ -125,15 +125,8 @@ namespace swrenderer auto lights = args.dc_lights; auto num_lights = args.dc_num_lights; - float viewpos_z = args.dc_viewpos.Z + args.dc_viewpos_step.Z * thread->skipped_by_thread(dest_y); - float step_viewpos_z = args.dc_viewpos_step.Z * thread->num_cores; - - count = thread->count_for_thread(dest_y, count); - if (count <= 0) return; - frac += thread->skipped_by_thread(dest_y) * fracstep; - dest = thread->dest_for_thread(dest_y, pitch, dest); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + float viewpos_z = args.dc_viewpos.Z; + float step_viewpos_z = args.dc_viewpos_step.Z; if (FilterModeT::Mode == (int)FilterModes::Linear) { @@ -167,7 +160,7 @@ namespace swrenderer } template - FORCEINLINE BgraColor Sample(uint32_t frac, const uint32_t *source, const uint32_t *source2, int textureheight, uint32_t one, uint32_t texturefracx) + FORCEINLINE static BgraColor Sample(uint32_t frac, const uint32_t *source, const uint32_t *source2, int textureheight, uint32_t one, uint32_t texturefracx) { using namespace DrawWall32TModes; @@ -203,7 +196,7 @@ namespace swrenderer } template - FORCEINLINE BgraColor Shade(BgraColor fgcolor, uint32_t light, uint32_t desaturate, uint32_t inv_desaturate, BgraColor shade_fade, BgraColor shade_light, const DrawerLight *lights, int num_lights, float viewpos_z) + FORCEINLINE static BgraColor Shade(BgraColor fgcolor, uint32_t light, uint32_t desaturate, uint32_t inv_desaturate, BgraColor shade_fade, BgraColor shade_light, const DrawerLight *lights, int num_lights, float viewpos_z) { using namespace DrawWall32TModes; @@ -225,7 +218,7 @@ namespace swrenderer return AddLights(material, fgcolor, lights, num_lights, viewpos_z); } - FORCEINLINE BgraColor AddLights(BgraColor material, BgraColor fgcolor, const DrawerLight *lights, int num_lights, float viewpos_z) + FORCEINLINE static BgraColor AddLights(BgraColor material, BgraColor fgcolor, const DrawerLight *lights, int num_lights, float viewpos_z) { using namespace DrawWall32TModes; @@ -243,13 +236,13 @@ namespace swrenderer // L = light-pos // dist = sqrt(dot(L, L)) - // distance_attenuation = 1 - MIN(dist * (1/radius), 1) + // distance_attenuation = 1 - min(dist * (1/radius), 1) float Lxy2 = light_x; // L.x*L.x + L.y*L.y float Lz = light_z - viewpos_z; float dist2 = Lxy2 + Lz * Lz; float rcp_dist = 1.f/sqrt(dist2); float dist = dist2 * rcp_dist; - float distance_attenuation = 256.0f - MIN(dist * light_radius, 256.0f); + float distance_attenuation = 256.0f - min(dist * light_radius, 256.0f); // The simple light type float simple_attenuation = distance_attenuation; @@ -267,17 +260,17 @@ namespace swrenderer lit.b += (light_color.b * attenuation) >> 8; } - lit.r = MIN(lit.r, 256); - lit.g = MIN(lit.g, 256); - lit.b = MIN(lit.b, 256); + lit.r = min(lit.r, 256); + lit.g = min(lit.g, 256); + lit.b = min(lit.b, 256); - fgcolor.r = MIN(fgcolor.r + ((material.r * lit.r) >> 8), 255); - fgcolor.g = MIN(fgcolor.g + ((material.g * lit.g) >> 8), 255); - fgcolor.b = MIN(fgcolor.b + ((material.b * lit.b) >> 8), 255); + fgcolor.r = min(fgcolor.r + ((material.r * lit.r) >> 8), 255); + fgcolor.g = min(fgcolor.g + ((material.g * lit.g) >> 8), 255); + fgcolor.b = min(fgcolor.b + ((material.b * lit.b) >> 8), 255); return fgcolor; } - FORCEINLINE BgraColor Blend(BgraColor fgcolor, BgraColor bgcolor, unsigned int ifgcolor, uint32_t srcalpha, uint32_t destalpha) + FORCEINLINE static BgraColor Blend(BgraColor fgcolor, BgraColor bgcolor, unsigned int ifgcolor, uint32_t srcalpha, uint32_t destalpha) { using namespace DrawWall32TModes; @@ -309,21 +302,21 @@ namespace swrenderer BgraColor outcolor; if (BlendT::Mode == (int)WallBlendModes::AddClamp) { - outcolor.r = MIN((fgcolor.r + bgcolor.r) >> 8, 255); - outcolor.g = MIN((fgcolor.g + bgcolor.g) >> 8, 255); - outcolor.b = MIN((fgcolor.b + bgcolor.b) >> 8, 255); + outcolor.r = min((fgcolor.r + bgcolor.r) >> 8, 255); + outcolor.g = min((fgcolor.g + bgcolor.g) >> 8, 255); + outcolor.b = min((fgcolor.b + bgcolor.b) >> 8, 255); } else if (BlendT::Mode == (int)WallBlendModes::SubClamp) { - outcolor.r = MAX(int32_t(fgcolor.r - bgcolor.r) >> 8, 0); - outcolor.g = MAX(int32_t(fgcolor.g - bgcolor.g) >> 8, 0); - outcolor.b = MAX(int32_t(fgcolor.b - bgcolor.b) >> 8, 0); + outcolor.r = max(int32_t(fgcolor.r - bgcolor.r) >> 8, 0); + outcolor.g = max(int32_t(fgcolor.g - bgcolor.g) >> 8, 0); + outcolor.b = max(int32_t(fgcolor.b - bgcolor.b) >> 8, 0); } else if (BlendT::Mode == (int)WallBlendModes::RevSubClamp) { - outcolor.r = MAX(int32_t(bgcolor.r - fgcolor.r) >> 8, 0); - outcolor.g = MAX(int32_t(bgcolor.g - fgcolor.g) >> 8, 0); - outcolor.b = MAX(int32_t(bgcolor.b - fgcolor.b) >> 8, 0); + outcolor.r = max(int32_t(bgcolor.r - fgcolor.r) >> 8, 0); + outcolor.g = max(int32_t(bgcolor.g - fgcolor.g) >> 8, 0); + outcolor.b = max(int32_t(bgcolor.b - fgcolor.b) >> 8, 0); } outcolor.a = 255; return outcolor; diff --git a/src/rendering/swrenderer/drawers/r_draw_wall32_sse2.h b/src/rendering/swrenderer/drawers/r_draw_wall32_sse2.h index 5316a9e0308..1860ba66735 100644 --- a/src/rendering/swrenderer/drawers/r_draw_wall32_sse2.h +++ b/src/rendering/swrenderer/drawers/r_draw_wall32_sse2.h @@ -47,12 +47,10 @@ namespace swrenderer } template - class DrawWall32T : public DrawWallCommand + class DrawWall32T { public: - DrawWall32T(const WallDrawerArgs &drawerargs) : DrawWallCommand(drawerargs) { } - - void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override + static void DrawColumn(const WallColumnDrawerArgs& args) { using namespace DrawWall32TModes; @@ -62,21 +60,21 @@ namespace swrenderer if (shade_constants.simple_shade) { if (is_nearest_filter) - Loop(thread, args, shade_constants); + Loop(args, shade_constants); else - Loop(thread, args, shade_constants); + Loop(args, shade_constants); } else { if (is_nearest_filter) - Loop(thread, args, shade_constants); + Loop(args, shade_constants); else - Loop(thread, args, shade_constants); + Loop(args, shade_constants); } } template - FORCEINLINE void VECTORCALL Loop(DrawerThread *thread, const WallColumnDrawerArgs& args, ShadeConstants shade_constants) + FORCEINLINE static void VECTORCALL Loop(const WallColumnDrawerArgs& args, ShadeConstants shade_constants) { using namespace DrawWall32TModes; @@ -110,6 +108,8 @@ namespace swrenderer } int count = args.Count(); + if (count <= 0) return; + int pitch = args.Viewport()->RenderTarget->GetPitch(); uint32_t fracstep = args.TextureVStep(); uint32_t frac = args.TextureVPos(); @@ -119,18 +119,11 @@ namespace swrenderer auto lights = args.dc_lights; auto num_lights = args.dc_num_lights; - float vpz = args.dc_viewpos.Z + args.dc_viewpos_step.Z * thread->skipped_by_thread(dest_y); - float stepvpz = args.dc_viewpos_step.Z * thread->num_cores; + float vpz = args.dc_viewpos.Z; + float stepvpz = args.dc_viewpos_step.Z; __m128 viewpos_z = _mm_setr_ps(vpz, vpz + stepvpz, 0.0f, 0.0f); __m128 step_viewpos_z = _mm_set1_ps(stepvpz * 2.0f); - count = thread->count_for_thread(dest_y, count); - if (count <= 0) return; - frac += thread->skipped_by_thread(dest_y) * fracstep; - dest = thread->dest_for_thread(dest_y, pitch, dest); - fracstep *= thread->num_cores; - pitch *= thread->num_cores; - if (FilterModeT::Mode == (int)FilterModes::Linear) { frac -= one / 2; @@ -203,7 +196,7 @@ namespace swrenderer } template - FORCEINLINE unsigned int VECTORCALL Sample(uint32_t frac, const uint32_t *source, const uint32_t *source2, int textureheight, uint32_t one, uint32_t texturefracx) + FORCEINLINE static unsigned int VECTORCALL Sample(uint32_t frac, const uint32_t *source, const uint32_t *source2, int textureheight, uint32_t one, uint32_t texturefracx) { using namespace DrawWall32TModes; @@ -239,7 +232,7 @@ namespace swrenderer } template - FORCEINLINE __m128i VECTORCALL Shade(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light, const DrawerLight *lights, int num_lights, __m128 viewpos_z) + FORCEINLINE static __m128i VECTORCALL Shade(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light, const DrawerLight *lights, int num_lights, __m128 viewpos_z) { using namespace DrawWall32TModes; @@ -271,7 +264,7 @@ namespace swrenderer return AddLights(material, fgcolor, lights, num_lights, viewpos_z); } - FORCEINLINE __m128i VECTORCALL AddLights(__m128i material, __m128i fgcolor, const DrawerLight *lights, int num_lights, __m128 viewpos_z) + FORCEINLINE static __m128i VECTORCALL AddLights(__m128i material, __m128i fgcolor, const DrawerLight *lights, int num_lights, __m128 viewpos_z) { using namespace DrawWall32TModes; @@ -287,7 +280,7 @@ namespace swrenderer // L = light-pos // dist = sqrt(dot(L, L)) - // distance_attenuation = 1 - MIN(dist * (1/radius), 1) + // distance_attenuation = 1 - min(dist * (1/radius), 1) __m128 Lxy2 = light_x; // L.x*L.x + L.y*L.y __m128 Lz = _mm_sub_ps(light_z, viewpos_z); __m128 dist2 = _mm_add_ps(Lxy2, _mm_mul_ps(Lz, Lz)); @@ -320,7 +313,7 @@ namespace swrenderer return fgcolor; } - FORCEINLINE __m128i VECTORCALL Blend(__m128i fgcolor, __m128i bgcolor, unsigned int ifgcolor0, unsigned int ifgcolor1, uint32_t srcalpha, uint32_t destalpha) + FORCEINLINE static __m128i VECTORCALL Blend(__m128i fgcolor, __m128i bgcolor, unsigned int ifgcolor0, unsigned int ifgcolor1, uint32_t srcalpha, uint32_t destalpha) { using namespace DrawWall32TModes; diff --git a/src/rendering/swrenderer/line/r_farclip_line.cpp b/src/rendering/swrenderer/line/r_farclip_line.cpp index 9e094768a52..fd662952e70 100644 --- a/src/rendering/swrenderer/line/r_farclip_line.cpp +++ b/src/rendering/swrenderer/line/r_farclip_line.cpp @@ -20,7 +20,7 @@ #include #include -#include "templates.h" + #include "doomdef.h" #include "doomstat.h" @@ -30,7 +30,7 @@ #include "r_sky.h" #include "v_video.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "stats.h" #include "a_sharedglobal.h" #include "d_net.h" @@ -40,7 +40,7 @@ #include "v_palette.h" #include "r_utility.h" #include "r_data/colormaps.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/scene/r_opaque_pass.h" #include "swrenderer/scene/r_3dfloors.h" #include "swrenderer/scene/r_portal.h" @@ -93,7 +93,7 @@ namespace swrenderer // reject lines that aren't seen from the portal (if any) // [ZZ] 10.01.2016: lines inside a skybox shouldn't be clipped, although this imposes some limitations on portals in skyboxes. - if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos)) + if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos.XY())) return; mFrontCeilingZ1 = mFrontSector->ceilingplane.ZatPoint(line->v1); @@ -155,7 +155,7 @@ namespace swrenderer for (int x = x1; x < x2; ++x) { short top = (clip3d->fakeFloor && m3DFloor.type == Fake3DOpaque::FakeCeiling) ? clip3d->fakeFloor->ceilingclip[x] : ceilingclip[x]; - short bottom = MIN(walltop.ScreenY[x], floorclip[x]); + short bottom = min(walltop.ScreenY[x], floorclip[x]); if (top < bottom) { mCeilingPlane->top[x] = top; @@ -177,7 +177,7 @@ namespace swrenderer for (int x = x1; x < x2; ++x) { - short top = MAX(wallbottom.ScreenY[x], ceilingclip[x]); + short top = max(wallbottom.ScreenY[x], ceilingclip[x]); short bottom = (clip3d->fakeFloor && m3DFloor.type == Fake3DOpaque::FakeFloor) ? clip3d->fakeFloor->floorclip[x] : floorclip[x]; if (top < bottom) { diff --git a/src/rendering/swrenderer/line/r_fogboundary.cpp b/src/rendering/swrenderer/line/r_fogboundary.cpp index 09a6bce20a6..ca8438bbb6e 100644 --- a/src/rendering/swrenderer/line/r_fogboundary.cpp +++ b/src/rendering/swrenderer/line/r_fogboundary.cpp @@ -22,9 +22,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -45,7 +45,7 @@ #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/line/r_fogboundary.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/scene/r_light.h" #ifdef _MSC_VER @@ -110,13 +110,13 @@ namespace swrenderer { if (fake_dc_colormap != basecolormapdata) { - stop = MIN(t1, b2); + stop = min(t1, b2); while (t2 < stop) { int y = t2++; drawerargs.DrawFogBoundaryLine(thread, y, xr, spanend[y]); } - stop = MAX(b1, t2); + stop = max(b1, t2); while (b2 > stop) { int y = --b2; @@ -125,16 +125,16 @@ namespace swrenderer } else { - t2 = MAX(t2, MIN(t1, b2)); - b2 = MIN(b2, MAX(b1, t2)); + t2 = max(t2, min(t1, b2)); + b2 = min(b2, max(b1, t2)); } - stop = MIN(t2, b1); + stop = min(t2, b1); while (t1 < stop) { spanend[t1++] = x; } - stop = MAX(b2, t2); + stop = max(b2, t2); while (b1 > stop) { spanend[--b1] = x; diff --git a/src/rendering/swrenderer/line/r_line.cpp b/src/rendering/swrenderer/line/r_line.cpp index 56557c8eb18..c09801d5ac9 100644 --- a/src/rendering/swrenderer/line/r_line.cpp +++ b/src/rendering/swrenderer/line/r_line.cpp @@ -22,8 +22,8 @@ #include #include -#include "templates.h" -#include "doomerrors.h" + +#include "engineerrors.h" #include "doomdef.h" #include "doomstat.h" #include "doomdata.h" @@ -32,7 +32,7 @@ #include "r_sky.h" #include "v_video.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "stats.h" #include "a_sharedglobal.h" #include "d_net.h" @@ -42,7 +42,8 @@ #include "v_palette.h" #include "r_utility.h" #include "r_data/colormaps.h" -#include "swrenderer/r_memory.h" +#include "texturemanager.h" +#include "r_memory.h" #include "swrenderer/scene/r_opaque_pass.h" #include "swrenderer/scene/r_3dfloors.h" #include "swrenderer/scene/r_portal.h" @@ -105,7 +106,7 @@ namespace swrenderer // reject lines that aren't seen from the portal (if any) // [ZZ] 10.01.2016: lines inside a skybox shouldn't be clipped, although this imposes some limitations on portals in skyboxes. - if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos)) + if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos.XY())) return; mFrontCeilingZ1 = mFrontSector->ceilingplane.ZatPoint(line->v1); @@ -313,8 +314,6 @@ namespace swrenderer if (markportal) { - draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip); - draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, Thread->OpaquePass->floorclip); draw_segment->drawsegclip.silhouette = SIL_BOTH; } else if (!mBackSector) @@ -388,8 +387,7 @@ namespace swrenderer if (mLineSegment->linedef->alpha > 0.0f && sidedef->GetTexture(side_t::mid).isValid()) { - FTexture* tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); - FSoftwareTexture* pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; + auto pic = GetPalettedSWTexture(sidedef->GetTexture(side_t::mid), true); if (pic) { draw_segment->SetHasTranslucentMidTexture(); @@ -686,10 +684,9 @@ namespace swrenderer // No top texture for skyhack lines if (mFrontSector->GetTexture(sector_t::ceiling) == skyflatnum && mBackSector->GetTexture(sector_t::ceiling) == skyflatnum) return; - FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::top), true); - if (!tex || !tex->isValid()) return; - - mTopTexture = tex->GetSoftwareTexture(); + auto tex = GetPalettedSWTexture(sidedef->GetTexture(side_t::top), true); + if (!tex) return; + mTopTexture = tex; } void SWRenderLine::SetMiddleTexture() @@ -701,10 +698,9 @@ namespace swrenderer if (linedef->isVisualPortal()) return; if (linedef->special == Line_Horizon) return; - auto tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); - if (!tex || !tex->isValid()) return; - - mMiddleTexture = tex->GetSoftwareTexture(); + auto tex = GetPalettedSWTexture(sidedef->GetTexture(side_t::mid), true); + if (!tex) return; + mMiddleTexture = tex; } void SWRenderLine::SetBottomTexture() @@ -712,10 +708,9 @@ namespace swrenderer side_t *sidedef = mLineSegment->sidedef; line_t *linedef = mLineSegment->linedef; - FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::bottom), true); - if (!tex || !tex->isValid()) return; - - mBottomTexture = tex->GetSoftwareTexture(); + auto tex = GetPalettedSWTexture(sidedef->GetTexture(side_t::bottom), true); + if (!tex) return; + mBottomTexture = tex; } bool SWRenderLine::IsFogBoundary(sector_t *front, sector_t *back) const @@ -757,7 +752,7 @@ namespace swrenderer for (int x = x1; x < x2; ++x) { short top = (clip3d->fakeFloor && m3DFloor.type == Fake3DOpaque::FakeCeiling) ? clip3d->fakeFloor->ceilingclip[x] : ceilingclip[x]; - short bottom = MIN(walltop.ScreenY[x], floorclip[x]); + short bottom = min(walltop.ScreenY[x], floorclip[x]); if (top < bottom) { mCeilingPlane->top[x] = top; @@ -779,7 +774,7 @@ namespace swrenderer for (int x = x1; x < x2; ++x) { - short top = MAX(wallbottom.ScreenY[x], ceilingclip[x]); + short top = max(wallbottom.ScreenY[x], ceilingclip[x]); short bottom = (clip3d->fakeFloor && m3DFloor.type == Fake3DOpaque::FakeFloor) ? clip3d->fakeFloor->floorclip[x] : floorclip[x]; if (top < bottom) { @@ -809,7 +804,7 @@ namespace swrenderer { for (int x = x1; x < x2; ++x) { - walllower.ScreenY[x] = MIN(MAX(walllower.ScreenY[x], ceilingclip[x]), wallbottom.ScreenY[x]); + walllower.ScreenY[x] = min(max(walllower.ScreenY[x], ceilingclip[x]), wallbottom.ScreenY[x]); } memcpy(clip3d->fakeFloor->floorclip + x1, walllower.ScreenY + x1, (x2 - x1) * sizeof(short)); } @@ -821,7 +816,7 @@ namespace swrenderer { for (int x = x1; x < x2; ++x) { - wallupper.ScreenY[x] = MAX(MIN(wallupper.ScreenY[x], floorclip[x]), walltop.ScreenY[x]); + wallupper.ScreenY[x] = max(min(wallupper.ScreenY[x], floorclip[x]), walltop.ScreenY[x]); } memcpy(clip3d->fakeFloor->ceilingclip + x1, wallupper.ScreenY + x1, (x2 - x1) * sizeof(short)); } @@ -844,7 +839,7 @@ namespace swrenderer { // top wall for (int x = x1; x < x2; ++x) { - wallupper.ScreenY[x] = MAX(MIN(wallupper.ScreenY[x], floorclip[x]), walltop.ScreenY[x]); + wallupper.ScreenY[x] = max(min(wallupper.ScreenY[x], floorclip[x]), walltop.ScreenY[x]); } memcpy(ceilingclip + x1, wallupper.ScreenY + x1, (x2 - x1) * sizeof(short)); } @@ -857,7 +852,7 @@ namespace swrenderer { // bottom wall for (int x = x1; x < x2; ++x) { - walllower.ScreenY[x] = MIN(MAX(walllower.ScreenY[x], ceilingclip[x]), wallbottom.ScreenY[x]); + walllower.ScreenY[x] = min(max(walllower.ScreenY[x], ceilingclip[x]), wallbottom.ScreenY[x]); } memcpy(floorclip + x1, walllower.ScreenY + x1, (x2 - x1) * sizeof(short)); } @@ -878,7 +873,7 @@ namespace swrenderer texcoords.ProjectTop(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC, mTopTexture); RenderWallPart renderWallpart(Thread); - renderWallpart.Render(mFrontSector, mLineSegment, WallC, mTopTexture, x1, x2, walltop.ScreenY, wallupper.ScreenY, texcoords, false, false, OPAQUE); + renderWallpart.Render(mFrontSector, mLineSegment, side_t::top, WallC, mTopTexture, x1, x2, walltop.ScreenY, wallupper.ScreenY, texcoords, false, false, OPAQUE); } void SWRenderLine::RenderMiddleTexture(int x1, int x2) @@ -890,7 +885,7 @@ namespace swrenderer texcoords.ProjectMid(Thread->Viewport.get(), mFrontSector, mLineSegment, WallC, mMiddleTexture); RenderWallPart renderWallpart(Thread); - renderWallpart.Render(mFrontSector, mLineSegment, WallC, mMiddleTexture, x1, x2, walltop.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE); + renderWallpart.Render(mFrontSector, mLineSegment, side_t::mid, WallC, mMiddleTexture, x1, x2, walltop.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE); } void SWRenderLine::RenderBottomTexture(int x1, int x2) @@ -903,6 +898,6 @@ namespace swrenderer texcoords.ProjectBottom(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC, mBottomTexture); RenderWallPart renderWallpart(Thread); - renderWallpart.Render(mFrontSector, mLineSegment, WallC, mBottomTexture, x1, x2, walllower.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE); + renderWallpart.Render(mFrontSector, mLineSegment, side_t::bottom, WallC, mBottomTexture, x1, x2, walllower.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE); } } diff --git a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp index 2fac2a8ef38..ba89086ed77 100644 --- a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp @@ -21,7 +21,7 @@ // #include -#include "templates.h" + #include "doomdef.h" #include "m_bbox.h" @@ -38,7 +38,8 @@ #include "po_man.h" #include "r_data/colormaps.h" #include "d_net.h" -#include "swrenderer/r_memory.h" +#include "texturemanager.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" #include "swrenderer/drawers/r_draw.h" #include "swrenderer/scene/r_3dfloors.h" @@ -90,13 +91,7 @@ namespace swrenderer auto viewport = Thread->Viewport.get(); Clip3DFloors *clip3d = Thread->Clip3D.get(); - FTexture *ttex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::mid), true); - if (curline->GetLevel()->i_compatflags & COMPATF_MASKEDMIDTEX) - { - ttex = ttex->GetRawTexture(); - } - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); - + auto tex = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::mid), true, !!(curline->GetLevel()->i_compatflags & COMPATF_MASKEDMIDTEX)); const short *mfloorclip = ds->drawsegclip.sprbottomclip; const short *mceilingclip = ds->drawsegclip.sprtopclip; @@ -127,20 +122,20 @@ namespace swrenderer top -= Thread->Viewport->viewpoint.Pos.Z; bot -= Thread->Viewport->viewpoint.Pos.Z; - ceilZ = MIN(ceilZ, top); - floorZ = MAX(floorZ, bot); + ceilZ = min(ceilZ, top); + floorZ = max(floorZ, bot); } // Clip wall by the current 3D floor render range. if (m3DFloor.clipTop) { double clipZ = m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z; - ceilZ = MIN(ceilZ, clipZ); + ceilZ = min(ceilZ, clipZ); } if (m3DFloor.clipBottom) { double clipZ = m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z; - floorZ = MAX(floorZ, clipZ); + floorZ = max(floorZ, clipZ); } wallupper.Project(Thread->Viewport.get(), ceilZ, &ds->WallC); @@ -196,11 +191,11 @@ namespace swrenderer sector_t tempsec; const sector_t* lightsector = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0); - fixed_t alpha = FLOAT2FIXED((float)MIN(curline->linedef->alpha, 1.)); + fixed_t alpha = FLOAT2FIXED((float)min(curline->linedef->alpha, 1.)); bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0; RenderWallPart renderWallpart(Thread); - renderWallpart.Render(lightsector, curline, ds->WallC, tex, x1, x2, mceilingclip, mfloorclip, ds->texcoords, true, additive, alpha); + renderWallpart.Render(lightsector, curline, side_t::mid, ds->WallC, tex, x1, x2, mceilingclip, mfloorclip, ds->texcoords, true, additive, alpha); } void RenderDrawSegment::Render3DFloorWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic) @@ -221,7 +216,7 @@ namespace swrenderer walltexcoords.Project3DFloor(Thread->Viewport.get(), rover, curline, ds->WallC, rw_pic); RenderWallPart renderWallpart(Thread); - renderWallpart.Render(lightsector, curline, ds->WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, walltexcoords, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha); + renderWallpart.Render(lightsector, curline, side_t::top, ds->WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, walltexcoords, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha); RenderDecal::RenderDecals(Thread, ds, curline, lightsector, wallupper.ScreenY, walllower.ScreenY, true); } @@ -332,20 +327,18 @@ namespace swrenderer } else { - FTexture *rw_tex = nullptr; if (fover->flags & FF_UPPERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (fover->flags & FF_LOWERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_tex = TexMan.GetPalettedTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_pic = GetPalettedSWTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); } - rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } } else if (frontsector->e->XFloor.ffloors.Size()) @@ -394,20 +387,18 @@ namespace swrenderer if (!rw_pic && !swimmable_found) { fover = nullptr; - FTexture *rw_tex; if (rover->flags & FF_UPPERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (rover->flags & FF_LOWERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_tex = TexMan.GetPalettedTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_pic = GetPalettedSWTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); } - rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } if (rw_pic && !swimmable_found) @@ -486,20 +477,18 @@ namespace swrenderer } else { - FTexture *rw_tex; if (fover->flags & FF_UPPERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (fover->flags & FF_LOWERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_tex = TexMan.GetPalettedTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_pic = GetPalettedSWTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); } - rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } } else if (frontsector->e->XFloor.ffloors.Size()) @@ -545,20 +534,18 @@ namespace swrenderer if (!rw_pic && !swimmable_found) { fover = nullptr; - FTexture *rw_tex; if (rover->flags & FF_UPPERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (rover->flags & FF_LOWERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_tex = TexMan.GetPalettedTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_pic = GetPalettedSWTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); } - rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } if (rw_pic && !swimmable_found) @@ -593,7 +580,7 @@ namespace swrenderer const sector_t* lightsector = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0); ProjectedWallLight walllight; - walllight.SetColormap(lightsector, curline); + walllight.SetColormap(lightsector, curline, side_t::mid); walllight.SetLightLeft(Thread, ds->WallC); RenderFogBoundary renderfog; @@ -627,27 +614,27 @@ namespace swrenderer double frontfz1 = ds->curline->frontsector->floorplane.ZatPoint(ds->curline->v1); double frontcz2 = ds->curline->frontsector->ceilingplane.ZatPoint(ds->curline->v2); double frontfz2 = ds->curline->frontsector->floorplane.ZatPoint(ds->curline->v2); - top = MAX(frontcz1, frontcz2); - bot = MIN(frontfz1, frontfz2); + top = max(frontcz1, frontcz2); + bot = min(frontfz1, frontfz2); if (m3DFloor.clipTop) { - top = MIN(top, m3DFloor.sclipTop); + top = min(top, m3DFloor.sclipTop); } if (m3DFloor.clipBottom) { - bot = MAX(bot, m3DFloor.sclipBottom); + bot = max(bot, m3DFloor.sclipBottom); } } void RenderDrawSegment::GetNoWrapMidTextureZ(DrawSegment* ds, FSoftwareTexture* tex, double& ceilZ, double& floorZ) { - double texheight = tex->GetScaledHeightDouble() / fabs(curline->sidedef->GetTextureYScale(side_t::mid)); + double texheight = tex->GetScaledHeight() / fabs(curline->sidedef->GetTextureYScale(side_t::mid)); double texturemid; if (curline->linedef->flags & ML_DONTPEGBOTTOM) - texturemid = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight; + texturemid = max(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight; else - texturemid = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling)); + texturemid = min(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling)); double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid); if (tex->useWorldPanning(curline->GetLevel())) rowoffset /= fabs(tex->GetScale().Y * curline->sidedef->GetTextureYScale(side_t::mid)); diff --git a/src/rendering/swrenderer/line/r_walldraw.cpp b/src/rendering/swrenderer/line/r_walldraw.cpp index 022854ddd63..bd7ae48c4a9 100644 --- a/src/rendering/swrenderer/line/r_walldraw.cpp +++ b/src/rendering/swrenderer/line/r_walldraw.cpp @@ -50,7 +50,7 @@ #include "swrenderer/line/r_walldraw.h" #include "swrenderer/line/r_wallsetup.h" #include "swrenderer/r_renderthread.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor) @@ -61,7 +61,7 @@ namespace swrenderer Thread = thread; } - void RenderWallPart::Render(const sector_t* lightsector, seg_t* curline, const FWallCoords& WallC, FSoftwareTexture* pic, int x1, int x2, const short* walltop, const short* wallbottom, const ProjectedWallTexcoords& texcoords, bool mask, bool additive, fixed_t alpha) + void RenderWallPart::Render(const sector_t* lightsector, seg_t* curline, int tier, const FWallCoords& WallC, FSoftwareTexture* pic, int x1, int x2, const short* walltop, const short* wallbottom, const ProjectedWallTexcoords& texcoords, bool mask, bool additive, fixed_t alpha) { if (pic == nullptr) return; @@ -70,6 +70,7 @@ namespace swrenderer this->x2 = x2; this->lightsector = lightsector; this->curline = curline; + this->tier = tier; this->WallC = WallC; this->pic = pic; this->mask = mask; @@ -78,11 +79,9 @@ namespace swrenderer light_list = GetLightList(); - mLight.SetColormap(lightsector, curline); + mLight.SetColormap(lightsector, curline, tier); mLight.SetLightLeft(Thread, WallC); - Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here. - CameraLight* cameraLight = CameraLight::Instance(); if (cameraLight->FixedColormap() || cameraLight->FixedLightLevel() >= 0 || !(lightsector->e && lightsector->e->XFloor.lightlist.Size())) { @@ -109,14 +108,14 @@ namespace swrenderer { for (int j = x1; j < x2; ++j) { - down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]); + down[j] = max(min(most3.ScreenY[j], up[j]), dwal[j]); // this cannot use clamp due to failing range checks. } ProcessNormalWall(up, down, texcoords); up = down; down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY; } - mLight.SetColormap(lightsector, curline, &lightsector->e->XFloor.lightlist[i]); + mLight.SetColormap(lightsector, curline, tier, &lightsector->e->XFloor.lightlist[i]); } ProcessNormalWall(up, dwal, texcoords); @@ -130,7 +129,7 @@ namespace swrenderer WallDrawerArgs drawerargs; // Textures that aren't masked can use the faster opaque drawer - if (!pic->GetTexture()->isMasked() && mask && alpha >= OPAQUE && !additive) + if (!pic->isMasked() && mask && alpha >= OPAQUE && !additive) { drawerargs.SetStyle(true, false, OPAQUE, light_list); } diff --git a/src/rendering/swrenderer/line/r_walldraw.h b/src/rendering/swrenderer/line/r_walldraw.h index 250f0de27c2..4088e792e61 100644 --- a/src/rendering/swrenderer/line/r_walldraw.h +++ b/src/rendering/swrenderer/line/r_walldraw.h @@ -25,7 +25,6 @@ #include "swrenderer/viewport/r_walldrawer.h" #include "r_line.h" -class FTexture; struct FLightNode; struct seg_t; struct FLightNode; @@ -48,6 +47,7 @@ namespace swrenderer void Render( const sector_t *lightsector, seg_t *curline, + int tier, const FWallCoords &WallC, FSoftwareTexture *pic, int x1, @@ -71,6 +71,7 @@ namespace swrenderer FSoftwareTexture *pic = nullptr; const sector_t *lightsector = nullptr; seg_t *curline = nullptr; + int tier; FWallCoords WallC; ProjectedWallLight mLight; diff --git a/src/rendering/swrenderer/line/r_wallsetup.cpp b/src/rendering/swrenderer/line/r_wallsetup.cpp index 8dbef53009f..c2359325d1b 100644 --- a/src/rendering/swrenderer/line/r_wallsetup.cpp +++ b/src/rendering/swrenderer/line/r_wallsetup.cpp @@ -22,7 +22,7 @@ #include #include -#include "templates.h" + #include "doomdef.h" #include "doomstat.h" @@ -31,7 +31,7 @@ #include "r_sky.h" #include "v_video.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "stats.h" #include "a_sharedglobal.h" #include "d_net.h" @@ -40,7 +40,7 @@ #include "v_palette.h" #include "r_data/colormaps.h" #include "r_walldraw.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/line/r_line.h" #include "swrenderer/scene/r_scene.h" #include "swrenderer/scene/r_light.h" @@ -54,6 +54,8 @@ namespace swrenderer auto viewport = thread->Viewport.get(); RenderPortal* renderportal = thread->Portal.get(); + // Rotate to view direction: + tleft.X = float(pt1.X * viewport->viewpoint.Sin - pt1.Y * viewport->viewpoint.Cos); tright.X = float(pt2.X * viewport->viewpoint.Sin - pt2.Y * viewport->viewpoint.Cos); @@ -65,9 +67,11 @@ namespace swrenderer float t = -tleft.X; tleft.X = -tright.X; tright.X = t; - swapvalues(tleft.Y, tright.Y); + std::swap(tleft.Y, tright.Y); } + // Edge clip: + float fsx1, fsz1, fsx2, fsz2; if (tleft.X >= -tleft.Y) @@ -112,23 +116,20 @@ namespace swrenderer if (fsz2 < TOO_CLOSE_Z) return true; + // Find screen range covered by the line: + sx1 = xs_RoundToInt(fsx1); sx2 = xs_RoundToInt(fsx2); - float delta = fsx2 - fsx1; - float t1 = (sx1 + 0.5f - fsx1) / delta; - float t2 = (sx2 + 0.5f - fsx1) / delta; - float invZ1 = 1.0f / fsz1; - float invZ2 = 1.0f / fsz2; - sz1 = 1.0f / (invZ1 * (1.0f - t1) + invZ2 * t1); - sz2 = 1.0f / (invZ1 * (1.0f - t2) + invZ2 * t2); - if (sx2 <= sx1) return true; + // Remap texture coordinates to the part covered by the line segment: + if (lineseg && lineseg->linedef) { line_t* line = lineseg->linedef; + float t1, t2; if (fabs(line->delta.X) > fabs(line->delta.Y)) { t1 = (lineseg->v1->fX() - line->v1->fX()) / line->delta.X; @@ -150,6 +151,23 @@ namespace swrenderer tx2 = t1 + tx2 * (t2 - t1); } + // Calculate screen depths for the start and end points (resulting values are at the pixel center): + + float delta = fsx2 - fsx1; + float t1 = (sx1 + 0.5f - fsx1) / delta; + float t2 = (sx2 + 0.5f - fsx1) / delta; + float invZ1 = 1.0f / fsz1; + float invZ2 = 1.0f / fsz2; + sz1 = 1.0f / (invZ1 * (1.0f - t1) + invZ2 * t1); + sz2 = 1.0f / (invZ1 * (1.0f - t2) + invZ2 * t2); + + // Adjust texture coordinates to also be at the pixel centers: + + float ftx1 = tx1 * invZ1; + float ftx2 = tx2 * invZ2; + tx1 = (ftx1 * (1.0f - t1) + ftx2 * t1) * sz1; + tx2 = (ftx1 * (1.0f - t2) + ftx2 * t2) * sz2; + return false; } @@ -287,7 +305,7 @@ namespace swrenderer { for (int i = x1; i < x2; i++) { - ScreenY[i] = std::min(ScreenY[i], clip.sprbottomclip[i]); + ScreenY[i] = min(ScreenY[i], clip.sprbottomclip[i]); } } @@ -423,8 +441,8 @@ namespace swrenderer float yscale = GetYScale(sidedef, pic, side_t::mid); double cameraZ = viewport->viewpoint.Pos.Z; - double texZFloor = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)); - double texZCeiling = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling)); + double texZFloor = max(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)); + double texZCeiling = min(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling)); double texturemid; if (yscale >= 0) @@ -483,7 +501,7 @@ namespace swrenderer double rowoffset = lineseg->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid); double planez = rover->model->GetPlaneTexZ(sector_t::ceiling); - fixed_t xoffset = FLOAT2FIXED(lineseg->sidedef->GetTextureXOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureXOffset(side_t::mid)); + fixed_t xoffset = xs_Fix<16>::ToFix(lineseg->sidedef->GetTextureXOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureXOffset(side_t::mid)); if (rowoffset < 0) { rowoffset += pic->GetHeight(); @@ -615,7 +633,7 @@ namespace swrenderer fixed_t ProjectedWallTexcoords::GetXOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart) { - fixed_t TextureOffsetU = FLOAT2FIXED(lineseg->sidedef->GetTextureXOffset(texpart)); + fixed_t TextureOffsetU = xs_Fix<16>::ToFix(lineseg->sidedef->GetTextureXOffset(texpart)); double xscale = GetXScale(lineseg->sidedef, tex, texpart); fixed_t xoffset; @@ -669,7 +687,7 @@ namespace swrenderer } } - void ProjectedWallLight::SetColormap(const sector_t *frontsector, seg_t *lineseg, lightlist_t *lit) + void ProjectedWallLight::SetColormap(const sector_t *frontsector, seg_t *lineseg, int tier, lightlist_t *lit) { if (!lit) { @@ -677,7 +695,7 @@ namespace swrenderer foggy = frontsector->Level->fadeto || frontsector->Colormap.FadeColor || (frontsector->Level->flags & LEVEL_HASFADETABLE); if (!(lineseg->sidedef->Flags & WALLF_POLYOBJ)) - lightlevel = lineseg->sidedef->GetLightLevel(foggy, frontsector->lightlevel); + lightlevel = lineseg->sidedef->GetLightLevel(foggy, frontsector->lightlevel, tier); else lightlevel = frontsector->GetLightLevel(); } @@ -685,7 +703,7 @@ namespace swrenderer { basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]); foggy = frontsector->Level->fadeto || basecolormap->Fade || (frontsector->Level->flags & LEVEL_HASFADETABLE); - lightlevel = lineseg->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != nullptr); + lightlevel = lineseg->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, tier, lit->lightsource != nullptr); } } } diff --git a/src/rendering/swrenderer/line/r_wallsetup.h b/src/rendering/swrenderer/line/r_wallsetup.h index 4eadd311a87..07b07f0f539 100644 --- a/src/rendering/swrenderer/line/r_wallsetup.h +++ b/src/rendering/swrenderer/line/r_wallsetup.h @@ -119,7 +119,7 @@ namespace swrenderer float GetLightStep() const { return lightstep; } bool IsSpriteLight() const { return spritelight; } - void SetColormap(const sector_t *frontsector, seg_t *lineseg, lightlist_t *lit = nullptr); + void SetColormap(const sector_t *frontsector, seg_t *lineseg, int tier, lightlist_t *lit = nullptr); void SetLightLeft(RenderThread *thread, const FWallCoords &wallc); void SetSpriteLight() { lightleft = 0.0f; lightstep = 0.0f; spritelight = true; } diff --git a/src/rendering/swrenderer/plane/r_flatplane.cpp b/src/rendering/swrenderer/plane/r_flatplane.cpp index 278fe3e148d..639e28d516c 100644 --- a/src/rendering/swrenderer/plane/r_flatplane.cpp +++ b/src/rendering/swrenderer/plane/r_flatplane.cpp @@ -22,9 +22,9 @@ #include #include -#include "templates.h" -#include "doomerrors.h" -#include "w_wad.h" + +#include "engineerrors.h" +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -50,7 +50,7 @@ #include "swrenderer/scene/r_light.h" #include "swrenderer/plane/r_visibleplane.h" #include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" namespace swrenderer @@ -92,7 +92,7 @@ namespace swrenderer pviewy = _yscale * pviewy; // left to right mapping - planeang += (Thread->Viewport->viewpoint.Angles.Yaw - 90).Radians(); + planeang += (Thread->Viewport->viewpoint.Angles.Yaw - DAngle::fromDeg(90)).Radians(); auto viewport = Thread->Viewport.get(); @@ -178,9 +178,9 @@ namespace swrenderer double distance2 = viewport->PlaneDepth(y + 1, planeheight); double xmagnitude = fabs(ystepscale * (distance2 - distance) * viewport->FocalLengthX); double ymagnitude = fabs(xstepscale * (distance2 - distance) * viewport->FocalLengthX); - double magnitude = MAX(ymagnitude, xmagnitude); + double magnitude = max(ymagnitude, xmagnitude); double min_lod = -1000.0; - drawerargs.SetTextureLOD(MAX(log2(magnitude) + r_lod_bias, min_lod)); + drawerargs.SetTextureLOD(max(log2(magnitude) + r_lod_bias, min_lod)); } if (plane_shade) @@ -270,8 +270,6 @@ namespace swrenderer drawerargs.SetDestX2(x2); drawerargs.DrawSpan(Thread); - if (r_modelscene) - drawerargs.DrawDepthSpan(Thread, zbufferdepth, zbufferdepth); } ///////////////////////////////////////////////////////////////////////// diff --git a/src/rendering/swrenderer/plane/r_planerenderer.cpp b/src/rendering/swrenderer/plane/r_planerenderer.cpp index 5a07a319ad2..9875fe0fe50 100644 --- a/src/rendering/swrenderer/plane/r_planerenderer.cpp +++ b/src/rendering/swrenderer/plane/r_planerenderer.cpp @@ -23,9 +23,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -65,14 +65,14 @@ namespace swrenderer int stop; // Draw any spans that have just closed - stop = MIN(t1, b2); + stop = min(t1, b2); while (t2 < stop) { int y = t2++; int x2 = spanend[y]; RenderLine(y, xr, x2); } - stop = MAX(b1, t2); + stop = max(b1, t2); while (b2 > stop) { int y = --b2; @@ -81,12 +81,12 @@ namespace swrenderer } // Mark any spans that have just opened - stop = MIN(t2, b1); + stop = min(t2, b1); while (t1 < stop) { spanend[t1++] = x; } - stop = MAX(b2, t2); + stop = max(b2, t2); while (b1 > stop) { spanend[--b1] = x; diff --git a/src/rendering/swrenderer/plane/r_skyplane.cpp b/src/rendering/swrenderer/plane/r_skyplane.cpp index 7df7cc3813b..9020b76a7e0 100644 --- a/src/rendering/swrenderer/plane/r_skyplane.cpp +++ b/src/rendering/swrenderer/plane/r_skyplane.cpp @@ -22,9 +22,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -35,6 +35,7 @@ #include "cmdlib.h" #include "d_net.h" #include "g_level.h" +#include "texturemanager.h" #include "swrenderer/scene/r_opaque_pass.h" #include "r_skyplane.h" #include "swrenderer/scene/r_3dfloors.h" @@ -50,7 +51,7 @@ #include "swrenderer/scene/r_scene.h" #include "swrenderer/scene/r_light.h" #include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" #include "g_levellocals.h" @@ -62,10 +63,7 @@ namespace swrenderer { static FSoftwareTexture *GetSWTex(FTextureID texid, bool allownull = true) { - auto tex = TexMan.GetPalettedTexture(texid, true); - if (tex == nullptr) return nullptr; - if (!allownull && !tex->isValid()) return nullptr; - return tex->GetSoftwareTexture(); + return GetPalettedSWTexture(texid, true, false, true); } RenderSkyPlane::RenderSkyPlane(RenderThread *thread) @@ -73,16 +71,14 @@ namespace swrenderer Thread = thread; auto Level = Thread->Viewport->Level(); - auto skytex1 = TexMan.GetPalettedTexture(Level->skytexture1, true); - auto skytex2 = TexMan.GetPalettedTexture(Level->skytexture2, true); + auto sskytex1 = GetPalettedSWTexture(Level->skytexture1, true, false, true); + auto sskytex2 = GetPalettedSWTexture(Level->skytexture2, true, false, true); - if (skytex1 == nullptr) + if (sskytex1 == nullptr || sskytex2 == nullptr) return; - FSoftwareTexture *sskytex1 = skytex1->GetSoftwareTexture(); - FSoftwareTexture *sskytex2 = skytex2->GetSoftwareTexture(); skytexturemid = 0; - int skyheight = skytex1->GetDisplayHeight(); + int skyheight = sskytex1->GetScaledHeight(); skyoffset = cl_oldfreelooklimit? 0 : skyheight == 256? 166 : skyheight >= 240? 150 : skyheight >= 200? 110 : 138; if (skyheight >= 128 && skyheight < 200) { @@ -90,7 +86,7 @@ namespace swrenderer } else if (skyheight >= 200) { - skytexturemid = (200 - skyheight) * sskytex1->GetScale().Y + ((r_skymode == 2 && !(Level->flags & LEVEL_FORCETILEDSKY)) ? skytex1->GetSkyOffset() : 0); + skytexturemid = (200 - skyheight) * sskytex1->GetScale().Y + ((r_skymode == 2 && !(Level->flags & LEVEL_FORCETILEDSKY)) ? sskytex1->GetSkyOffset() : 0); } if (viewwidth != 0 && viewheight != 0) @@ -98,8 +94,8 @@ namespace swrenderer skyiscale = float(r_Yaspect / freelookviewheight); skyscale = freelookviewheight / r_Yaspect; - skyiscale *= float(thread->Viewport->viewpoint.FieldOfView.Degrees / 90.); - skyscale *= float(90. / thread->Viewport->viewpoint.FieldOfView.Degrees); + skyiscale *= float(thread->Viewport->viewpoint.FieldOfView.Degrees() / 90.); + skyscale *= float(90. / thread->Viewport->viewpoint.FieldOfView.Degrees()); } if (Level->skystretch) @@ -113,8 +109,8 @@ namespace swrenderer // giving a total sky width of 1024 pixels. So if the sky texture is no wider than 1024, // we map it to a cylinder with circumfrence 1024. For larger ones, we use the width of // the texture as the cylinder's circumfrence. - sky1cyl = MAX(sskytex1->GetWidth(), fixed_t(sskytex1->GetScale().X * 1024)); - sky2cyl = MAX(sskytex2->GetWidth(), fixed_t(sskytex2->GetScale().Y * 1024)); + sky1cyl = max(sskytex1->GetWidth(), fixed_t(sskytex1->GetScale().X * 1024)); + sky2cyl = max(sskytex2->GetWidth(), fixed_t(sskytex2->GetScale().Y * 1024)); } void RenderSkyPlane::Render(VisiblePlane *pl) @@ -190,7 +186,7 @@ namespace swrenderer // to allow sky rotation as well as careful positioning. // However, the offset is scaled very small, so that it // allows a long-period of sky rotation. - skyangle += FLOAT2FIXED(s->GetTextureXOffset(pos)); + skyangle += xs_Fix<16>::ToFix(s->GetTextureXOffset(pos)); // Vertical offset allows careful sky positioning. skymid = s->GetTextureYOffset(pos) - 28.0; @@ -203,10 +199,10 @@ namespace swrenderer skyflip = l->args[2] ? 0u : ~0u; int frontxscale = int(frontskytex->GetScale().X * 1024); - frontcyl = MAX(frontskytex->GetWidth(), frontxscale); + frontcyl = max(frontskytex->GetWidth(), frontxscale); if (Level->skystretch) { - skymid = skymid * frontskytex->GetScaledHeightDouble() / (SKYSTRETCH_HEIGHT + skyoffset); + skymid = skymid * frontskytex->GetScaledHeight() / (SKYSTRETCH_HEIGHT + skyoffset); } } } @@ -218,12 +214,11 @@ namespace swrenderer drawerargs.SetStyle(); - Thread->PrepareTexture(frontskytex, DefaultRenderStyle()); - Thread->PrepareTexture(backskytex, DefaultRenderStyle()); - DrawSky(pl); } + static uint32_t UMulScale16(uint32_t a, uint32_t b) { return (uint32_t)(((uint64_t)a * b) >> 16); } + void RenderSkyPlane::DrawSkyColumnStripe(int start_x, int y1, int y2, double scale, double texturemid, double yrepeat) { RenderPortal *renderportal = Thread->Portal.get(); @@ -255,6 +250,8 @@ namespace swrenderer angle1 = UMulScale16(ang, frontcyl) + frontpos; angle2 = UMulScale16(ang, backcyl) + backpos; + auto skycapcolors = Thread->GetSkyCapColor(frontskytex); + drawerargs.SetFrontTexture(Thread, frontskytex, angle1); drawerargs.SetBackTexture(Thread, backskytex, angle2); drawerargs.SetTextureVStep(uv_step); @@ -262,16 +259,14 @@ namespace swrenderer drawerargs.SetDest(viewport, start_x, y1); drawerargs.SetCount(y2 - y1); drawerargs.SetFadeSky(r_skymode == 2 && !(Level->flags & LEVEL_FORCETILEDSKY)); - drawerargs.SetSolidTop(frontskytex->GetSkyCapColor(false)); - drawerargs.SetSolidBottom(frontskytex->GetSkyCapColor(true)); + drawerargs.SetSolidTop(skycapcolors.first); + drawerargs.SetSolidBottom(skycapcolors.second); if (!backskytex) drawerargs.DrawSingleSkyColumn(Thread); else drawerargs.DrawDoubleSkyColumn(Thread); - if (r_modelscene) - drawerargs.DrawDepthSkyColumn(Thread, 1.0f / 65536.0f); } void RenderSkyPlane::DrawSkyColumn(int start_x, int y1, int y2) diff --git a/src/rendering/swrenderer/plane/r_slopeplane.cpp b/src/rendering/swrenderer/plane/r_slopeplane.cpp index e2249a30f85..0a13c11ebd7 100644 --- a/src/rendering/swrenderer/plane/r_slopeplane.cpp +++ b/src/rendering/swrenderer/plane/r_slopeplane.cpp @@ -22,9 +22,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -50,7 +50,7 @@ #include "swrenderer/scene/r_light.h" #include "swrenderer/viewport/r_viewport.h" #include "swrenderer/plane/r_visibleplane.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" #ifdef _MSC_VER @@ -88,12 +88,18 @@ namespace swrenderer auto viewport = Thread->Viewport.get(); - DVector3 worldNormal = pl->height.Normal(); - planeNormal.X = worldNormal.X * viewport->viewpoint.Sin - worldNormal.Y * viewport->viewpoint.Cos; - planeNormal.Y = worldNormal.X * viewport->viewpoint.Cos + worldNormal.Y * viewport->viewpoint.Sin; - planeNormal.Z = worldNormal.Z; - planeD = -planeNormal.Z * (pl->height.ZatPoint(viewport->viewpoint.Pos.X, viewport->viewpoint.Pos.Y) - viewport->viewpoint.Pos.Z); + // Stupid way of doing it, but at least it works + DVector3 worldP0(viewport->viewpoint.Pos.XY(), pl->height.ZatPoint(viewport->viewpoint.Pos)); + DVector3 worldP1 = worldP0 + pl->height.Normal(); + DVector3 viewP0 = viewport->PointWorldToView(worldP0); + DVector3 viewP1 = viewport->PointWorldToView(worldP1); + planeNormal = viewP1 - viewP0; + planeD = -(viewP0 | planeNormal); + + if (Thread->Portal->MirrorFlags & RF_XFLIP) + planeNormal.X = -planeNormal.X; + light_list = pl->lights; drawerargs.SetSolidColor(3); drawerargs.SetTexture(Thread, texture); @@ -204,23 +210,77 @@ namespace swrenderer void RenderSlopePlane::RenderLine(int y, int x1, int x2) { - drawerargs.DrawTiltedSpan(Thread, y, x1, x2, plane_sz, plane_su, plane_sv, plane_shade, lightlevel, foggy, planelightfloat, pviewx, pviewy, basecolormap); - - if (r_modelscene) + if (r_dynlights) { - double viewZ = 1.0; - double viewX1 = Thread->Viewport->ScreenToViewX(x1, viewZ); - double viewX2 = Thread->Viewport->ScreenToViewX(x2 + 1, viewZ); - double viewY = Thread->Viewport->ScreenToViewY(y, viewZ); - - // Find depth values for the span - float zbufferdepth1 = (float)(-planeD / (planeNormal | DVector3(viewX1, viewZ, viewY))); - float zbufferdepth2 = (float)(-planeD / (planeNormal | DVector3(viewX2, viewZ, viewY))); - - drawerargs.SetDestX1(x1); - drawerargs.SetDestX2(x2); - drawerargs.SetDestY(Thread->Viewport.get(), y); - drawerargs.DrawDepthSpan(Thread, 1.0f / zbufferdepth1, 1.0f / zbufferdepth2); + // Find row position in view space + DVector3 viewposX1 = Thread->Viewport->ScreenToViewPos(x1, y, planeNormal, planeD); + DVector3 viewposX2 = Thread->Viewport->ScreenToViewPos(x2, y, planeNormal, planeD); + + // Convert to screen space + viewposX1.Z = 1.0 / viewposX1.Z; + viewposX1.X *= viewposX1.Z; + viewposX1.Y *= viewposX1.Z; + viewposX2.Z = 1.0 / viewposX2.Z; + viewposX2.X *= viewposX2.Z; + viewposX2.Y *= viewposX2.Z; + + drawerargs.dc_viewpos.X = viewposX1.X; + drawerargs.dc_viewpos.Y = viewposX1.Y; + drawerargs.dc_viewpos.Z = viewposX1.Z; + drawerargs.dc_viewpos_step.X = (viewposX2.X - viewposX1.X) / (x2 - x1); + drawerargs.dc_viewpos_step.Y = (viewposX2.Y - viewposX1.Y) / (x2 - x1); + drawerargs.dc_viewpos_step.Z = (viewposX2.Z - viewposX1.Z) / (x2 - x1); + + // Plane normal + drawerargs.dc_normal.X = planeNormal.X; + drawerargs.dc_normal.Y = planeNormal.Y; + drawerargs.dc_normal.Z = planeNormal.Z; + + // Calculate max lights that can touch the row so we can allocate memory for the list + int max_lights = 0; + VisiblePlaneLight* cur_node = light_list; + while (cur_node) + { + if (cur_node->lightsource->IsActive()) + max_lights++; + cur_node = cur_node->next; + } + + drawerargs.dc_num_lights = 0; + drawerargs.dc_lights = Thread->FrameMemory->AllocMemory(max_lights); + + // Setup lights for row + cur_node = light_list; + while (cur_node) + { + if (cur_node->lightsource->IsActive()) + { + DVector3 lightPos = Thread->Viewport->PointWorldToView(cur_node->lightsource->Pos); + + uint32_t red = cur_node->lightsource->GetRed(); + uint32_t green = cur_node->lightsource->GetGreen(); + uint32_t blue = cur_node->lightsource->GetBlue(); + + auto& light = drawerargs.dc_lights[drawerargs.dc_num_lights++]; + light.x = lightPos.X; + light.y = lightPos.Y; + light.z = lightPos.Z; + light.radius = 256.0f / cur_node->lightsource->GetRadius(); + light.color = (red << 16) | (green << 8) | blue; + + bool is_point_light = cur_node->lightsource->IsAttenuated(); + if (is_point_light) + light.radius = -light.radius; + } + + cur_node = cur_node->next; + } } + else + { + drawerargs.dc_num_lights = 0; + } + + drawerargs.DrawTiltedSpan(Thread, y, x1, x2, plane_sz, plane_su, plane_sv, plane_shade, lightlevel, foggy, planelightfloat, pviewx, pviewy, basecolormap); } } diff --git a/src/rendering/swrenderer/plane/r_slopeplane.h b/src/rendering/swrenderer/plane/r_slopeplane.h index b074492fc9e..b237237278f 100644 --- a/src/rendering/swrenderer/plane/r_slopeplane.h +++ b/src/rendering/swrenderer/plane/r_slopeplane.h @@ -52,5 +52,6 @@ namespace swrenderer DVector3 planeNormal; double planeD; + VisiblePlaneLight* light_list; }; } diff --git a/src/rendering/swrenderer/plane/r_visibleplane.cpp b/src/rendering/swrenderer/plane/r_visibleplane.cpp index 828f15bab81..c8517cac42a 100644 --- a/src/rendering/swrenderer/plane/r_visibleplane.cpp +++ b/src/rendering/swrenderer/plane/r_visibleplane.cpp @@ -23,9 +23,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -37,7 +37,8 @@ #include "d_net.h" #include "g_level.h" #include "a_dynlight.h" -#include "swrenderer/r_memory.h" +#include "texturemanager.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" #include "swrenderer/scene/r_opaque_pass.h" #include "swrenderer/scene/r_3dfloors.h" @@ -113,14 +114,9 @@ namespace swrenderer } else // regular flat { - FTexture *ttex = TexMan.GetPalettedTexture(picnum, true); - - if (!ttex->isValid()) - { + auto tex = GetPalettedSWTexture(picnum, true); + if (tex == nullptr) return; - } - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); - if (!masked && !additive) { // If we're not supposed to see through this plane, draw it opaque. alpha = OPAQUE; diff --git a/src/rendering/swrenderer/plane/r_visibleplane.h b/src/rendering/swrenderer/plane/r_visibleplane.h index afb493cfd4d..fcb5c6786c3 100644 --- a/src/rendering/swrenderer/plane/r_visibleplane.h +++ b/src/rendering/swrenderer/plane/r_visibleplane.h @@ -25,7 +25,7 @@ #include #include "r_defs.h" #include "r_state.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" struct FDynamicLight; struct FLightNode; @@ -70,7 +70,7 @@ namespace swrenderer int extralight = 0; double visibility = 0.0; DVector3 viewpos = { 0.0, 0.0, 0.0 }; - DAngle viewangle = { 0.0 }; + DAngle viewangle = nullAngle; fixed_t Alpha = 0; bool Additive = false; diff --git a/src/rendering/swrenderer/plane/r_visibleplanelist.cpp b/src/rendering/swrenderer/plane/r_visibleplanelist.cpp index d157bc42a72..bddc4f232e1 100644 --- a/src/rendering/swrenderer/plane/r_visibleplanelist.cpp +++ b/src/rendering/swrenderer/plane/r_visibleplanelist.cpp @@ -23,9 +23,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -37,7 +37,7 @@ #include "d_net.h" #include "g_level.h" #include "a_dynlight.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/scene/r_opaque_pass.h" #include "swrenderer/scene/r_3dfloors.h" #include "swrenderer/scene/r_portal.h" @@ -121,7 +121,7 @@ namespace swrenderer xform = &nulltransform; nulltransform.xOffs = nulltransform.yOffs = nulltransform.baseyOffs = 0; nulltransform.xScale = nulltransform.yScale = 1; - nulltransform.Angle = nulltransform.baseAngle = 0.0; + nulltransform.Angle = nulltransform.baseAngle = nullAngle; additive = false; // [RH] Map floor skies and ceiling skies to separate visplanes. This isn't // always necessary, but it is needed if a floor and ceiling sky are in the diff --git a/src/rendering/swrenderer/r_all.cpp b/src/rendering/swrenderer/r_all.cpp index c1dc53734c2..66179cb46ed 100644 --- a/src/rendering/swrenderer/r_all.cpp +++ b/src/rendering/swrenderer/r_all.cpp @@ -1,12 +1,10 @@ #include "textures/r_swtexture.h" -#include "r_memory.cpp" #include "r_renderthread.cpp" #include "r_swrenderer.cpp" #include "r_swcolormaps.cpp" #include "drawers/r_draw.cpp" #include "drawers/r_draw_pal.cpp" #include "drawers/r_draw_rgba.cpp" -#include "drawers/r_thread.cpp" #include "line/r_fogboundary.cpp" #include "line/r_line.cpp" #include "line/r_farclip_line.cpp" @@ -36,7 +34,6 @@ #include "things/r_visiblespritelist.cpp" #include "things/r_voxel.cpp" #include "things/r_wallsprite.cpp" -#include "things/r_model.cpp" #include "viewport/r_drawerargs.cpp" #include "viewport/r_skydrawer.cpp" #include "viewport/r_spandrawer.cpp" diff --git a/src/rendering/swrenderer/r_memory.cpp b/src/rendering/swrenderer/r_memory.cpp deleted file mode 100644 index 4177e562110..00000000000 --- a/src/rendering/swrenderer/r_memory.cpp +++ /dev/null @@ -1,115 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1999-2016 Randy Heit -// Copyright 2016 Magnus Norddahl -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- - -#include -#include "templates.h" -#include "doomdef.h" -#include "m_bbox.h" - -#include "p_lnspec.h" -#include "p_setup.h" -#include "swrenderer/drawers/r_draw.h" -#include "swrenderer/plane/r_visibleplane.h" -#include "a_sharedglobal.h" -#include "g_level.h" -#include "p_effect.h" -#include "doomstat.h" -#include "r_state.h" -#include "v_palette.h" -#include "r_sky.h" -#include "po_man.h" -#include "r_data/colormaps.h" -#include "r_memory.h" -#include - -void *RenderMemory::AllocBytes(int size) -{ - size = (size + 15) / 16 * 16; // 16-byte align - - if (UsedBlocks.empty() || UsedBlocks.back()->Position + size > BlockSize) - { - if (!FreeBlocks.empty()) - { - auto block = std::move(FreeBlocks.back()); - block->Position = 0; - FreeBlocks.pop_back(); - UsedBlocks.push_back(std::move(block)); - } - else - { - UsedBlocks.push_back(std::unique_ptr(new MemoryBlock())); - } - } - - auto &block = UsedBlocks.back(); - void *data = block->Data + block->Position; - block->Position += size; - - return data; -} - -void RenderMemory::Clear() -{ - while (!UsedBlocks.empty()) - { - auto block = std::move(UsedBlocks.back()); - UsedBlocks.pop_back(); - FreeBlocks.push_back(std::move(block)); - } -} - -static void* Aligned_Alloc(size_t alignment, size_t size) -{ - void* ptr; -#if defined (_MSC_VER) || defined (__MINGW32__) - ptr = _aligned_malloc(size, alignment); - if (!ptr) - throw std::bad_alloc(); -#else - // posix_memalign required alignment to be a min of sizeof(void *) - if (alignment < sizeof(void*)) - alignment = sizeof(void*); - - if (posix_memalign((void**)&ptr, alignment, size)) - throw std::bad_alloc(); -#endif - return ptr; -} - -static void Aligned_Free(void* ptr) -{ - if (ptr) - { -#if defined _MSC_VER - _aligned_free(ptr); -#else - free(ptr); -#endif - } -} - -RenderMemory::MemoryBlock::MemoryBlock() : Data(static_cast(Aligned_Alloc(16, BlockSize))), Position(0) -{ -} - -RenderMemory::MemoryBlock::~MemoryBlock() -{ - Aligned_Free(Data); -} diff --git a/src/rendering/swrenderer/r_renderer.h b/src/rendering/swrenderer/r_renderer.h index 1f3dec14588..7d873f5f0bb 100644 --- a/src/rendering/swrenderer/r_renderer.h +++ b/src/rendering/swrenderer/r_renderer.h @@ -7,14 +7,13 @@ struct FRenderer; extern FRenderer *SWRenderer; class FSerializer; -class FTexture; class AActor; class player_t; struct sector_t; class FCanvasTexture; -class FileWriter; class DCanvas; struct FLevelLocals; +class PClassActor; struct FRenderer { diff --git a/src/rendering/swrenderer/r_renderthread.cpp b/src/rendering/swrenderer/r_renderthread.cpp index 036e2973078..19f016ef93f 100644 --- a/src/rendering/swrenderer/r_renderthread.cpp +++ b/src/rendering/swrenderer/r_renderthread.cpp @@ -21,7 +21,7 @@ */ #include -#include "templates.h" + #include "doomdef.h" #include "m_bbox.h" @@ -47,13 +47,15 @@ #include "swrenderer/plane/r_visibleplanelist.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/segments/r_clipsegment.h" -#include "swrenderer/drawers/r_thread.h" +#include "r_thread.h" #include "swrenderer/drawers/r_draw.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "swrenderer/drawers/r_draw_pal.h" #include "swrenderer/viewport/r_viewport.h" #include "r_memory.h" +std::pair& R_GetSkyCapColor(FGameTexture* tex); + namespace swrenderer { RenderThread::RenderThread(RenderScene *scene, bool mainThread) @@ -63,7 +65,6 @@ namespace swrenderer FrameMemory.reset(new RenderMemory()); Viewport.reset(new RenderViewport()); Light.reset(new LightVisibility()); - DrawQueue.reset(new DrawerCommandQueue(FrameMemory.get())); OpaquePass.reset(new RenderOpaquePass(this)); TranslucentPass.reset(new RenderTranslucentPass(this)); SpriteList.reset(new VisibleSpriteList()); @@ -73,8 +74,8 @@ namespace swrenderer PlaneList.reset(new VisiblePlaneList(this)); DrawSegments.reset(new DrawSegmentList(this)); ClipSegments.reset(new RenderClipSegment()); - tc_drawers.reset(new SWTruecolorDrawers(DrawQueue)); - pal_drawers.reset(new SWPalDrawers(DrawQueue)); + tc_drawers.reset(new SWTruecolorDrawers(this)); + pal_drawers.reset(new SWPalDrawers(this)); } RenderThread::~RenderThread() @@ -89,33 +90,13 @@ namespace swrenderer return pal_drawers.get(); } - static std::mutex loadmutex; - void RenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style) { - if (texture == nullptr) - return; - - // Textures may not have loaded/refreshed yet. The shared code doing - // this is not thread safe. By calling GetPixels in a mutex lock we - // make sure that only one thread is loading a texture at any given - // time. - // - // It is critical that this function is called before any direct - // calls to GetPixels for this to work. + std::mutex loadmutex; + std::pair RenderThread::GetSkyCapColor(FSoftwareTexture* tex) + { std::unique_lock lock(loadmutex); - - const FSoftwareTextureSpan *spans; - if (Viewport->RenderTarget->IsBgra()) - { - texture->GetPixelsBgra(); - texture->GetColumnBgra(0, &spans); - } - else - { - bool alpha = !!(style.Flags & STYLEF_RedIsAlpha); - texture->GetPixels(alpha); - texture->GetColumn(alpha, 0, &spans); - } + std::pair colors = R_GetSkyCapColor(tex->GetTexture()); + return colors; } static std::mutex polyobjmutex; diff --git a/src/rendering/swrenderer/r_renderthread.h b/src/rendering/swrenderer/r_renderthread.h index 5e7b4f818e4..344b8ee5349 100644 --- a/src/rendering/swrenderer/r_renderthread.h +++ b/src/rendering/swrenderer/r_renderthread.h @@ -25,13 +25,10 @@ #include #include -class DrawerCommandQueue; -typedef std::shared_ptr DrawerCommandQueuePtr; class RenderMemory; struct FDynamicLight; EXTERN_CVAR(Bool, r_models); -extern bool r_modelscene; namespace swrenderer { @@ -51,6 +48,7 @@ namespace swrenderer class SWPixelFormatDrawers; class SWTruecolorDrawers; class SWPalDrawers; + class WallColumnDrawerArgs; class RenderThread { @@ -75,7 +73,6 @@ namespace swrenderer std::unique_ptr ClipSegments; std::unique_ptr Viewport; std::unique_ptr Light; - DrawerCommandQueuePtr DrawQueue; TArray AddedLightsArray; @@ -87,11 +84,11 @@ namespace swrenderer SWPixelFormatDrawers *Drawers(RenderViewport *viewport); - // Make sure texture can accessed safely - void PrepareTexture(FSoftwareTexture *texture, FRenderStyle style); - // Setup poly object in a threadsafe manner void PreparePolyObject(subsector_t *sub); + + // Retrieve skycap color in a threadsafe way + std::pair GetSkyCapColor(FSoftwareTexture* tex); private: std::unique_ptr tc_drawers; diff --git a/src/rendering/swrenderer/r_swcolormaps.cpp b/src/rendering/swrenderer/r_swcolormaps.cpp index e312930a0ff..1ff95c8b31b 100644 --- a/src/rendering/swrenderer/r_swcolormaps.cpp +++ b/src/rendering/swrenderer/r_swcolormaps.cpp @@ -39,20 +39,19 @@ #include #include "i_system.h" -#include "w_wad.h" +#include "filesystem.h" #include "doomdef.h" #include "r_sky.h" #include "c_dispatch.h" #include "sc_man.h" #include "v_text.h" -#include "st_start.h" #include "doomstat.h" #include "v_palette.h" #include "colormatcher.h" #include "r_data/colormaps.h" #include "r_swcolormaps.h" #include "v_video.h" -#include "templates.h" + #include "r_utility.h" #include "swrenderer/r_renderer.h" #include @@ -347,14 +346,14 @@ void SetDefaultColormap (const char *name) uint8_t unremap[256]; uint8_t remap[256]; - lump = Wads.CheckNumForFullName (name, true, ns_colormaps); + lump = fileSystem.CheckNumForFullName (name, true, FileSys::ns_colormaps); if (lump == -1) - lump = Wads.CheckNumForName (name, ns_global); + lump = fileSystem.CheckNumForName (name, FileSys::ns_global); // [RH] If using BUILD's palette, generate the colormap - if (lump == -1 || Wads.CheckNumForFullName("palette.dat") >= 0 || Wads.CheckNumForFullName("blood.pal") >= 0) + if (lump == -1 || fileSystem.CheckNumForFullName("palette.dat") >= 0 || fileSystem.CheckNumForFullName("blood.pal") >= 0) { - Printf ("Make colormap\n"); + DPrintf (DMSG_NOTIFY, "Make colormap\n"); FDynamicColormap foo; foo.Color = 0xFFFFFF; @@ -366,7 +365,7 @@ void SetDefaultColormap (const char *name) } else { - auto lumpr = Wads.OpenLumpReader (lump); + auto lumpr = fileSystem.OpenFileReader (lump); // [RH] The colormap may not have been designed for the specific // palette we are using, so remap it to match the current palette. @@ -404,7 +403,7 @@ static void InitBoomColormaps () // This is a really rough hack, but it's better than // not doing anything with them at all (right?) - uint32_t NumLumps = Wads.GetNumLumps(); + uint32_t NumLumps = fileSystem.GetNumEntries(); realcolormaps.Maps = new uint8_t[256*NUMCOLORMAPS*fakecmaps.Size()]; SetDefaultColormap ("COLORMAP"); @@ -424,10 +423,10 @@ static void InitBoomColormaps () remap[0] = 0; for (j = 1; j < fakecmaps.Size(); j++) { - if (Wads.LumpLength (fakecmaps[j].lump) >= (NUMCOLORMAPS+1)*256) + if (fileSystem.FileLength (fakecmaps[j].lump) >= (NUMCOLORMAPS+1)*256) { int k, r; - auto lump = Wads.OpenLumpReader (fakecmaps[j].lump); + auto lump = fileSystem.OpenFileReader (fakecmaps[j].lump); uint8_t *const map = realcolormaps.Maps + NUMCOLORMAPS*256*j; for (k = 0; k < NUMCOLORMAPS; ++k) @@ -516,11 +515,11 @@ CCMD (testfade) { if ( !(colorstring = V_GetColorStringByName (argv[1])).IsEmpty() ) { - color = V_GetColorFromString (NULL, colorstring); + color = V_GetColorFromString (colorstring.GetChars()); } else { - color = V_GetColorFromString (NULL, argv[1]); + color = V_GetColorFromString (argv[1]); } for (auto Level : AllLevels()) { @@ -550,11 +549,11 @@ CCMD (testcolor) { if ( !(colorstring = V_GetColorStringByName (argv[1])).IsEmpty() ) { - color = V_GetColorFromString (NULL, colorstring); + color = V_GetColorFromString (colorstring.GetChars()); } else { - color = V_GetColorFromString (NULL, argv[1]); + color = V_GetColorFromString (argv[1]); } if (argv.argc() > 2) { diff --git a/src/rendering/swrenderer/r_swrenderer.cpp b/src/rendering/swrenderer/r_swrenderer.cpp index f0d2830d373..bb7340ef4be 100644 --- a/src/rendering/swrenderer/r_swrenderer.cpp +++ b/src/rendering/swrenderer/r_swrenderer.cpp @@ -45,15 +45,17 @@ #include "scene/r_opaque_pass.h" #include "scene/r_3dfloors.h" #include "scene/r_portal.h" -#include "textures/textures.h" -#include "r_data/voxels.h" +#include "textures.h" +#include "voxels.h" #include "drawers/r_draw_rgba.h" #include "p_setup.h" #include "g_levellocals.h" #include "image.h" #include "imagehelpers.h" +#include "texturemanager.h" +#include "d_main.h" -// [BB] Use ZDoom's freelook limit for the sotfware renderer. +// [BB] Use ZDoom's freelook limit for the software renderer. // Note: ZDoom's limit is chosen such that the sky is rendered properly. CUSTOM_CVAR (Bool, cl_oldfreelooklimit, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { @@ -81,13 +83,13 @@ FRenderer *CreateSWRenderer() return new FSoftwareRenderer; } -void FSoftwareRenderer::PreparePrecache(FTexture *ttex, int cache) +void FSoftwareRenderer::PreparePrecache(FGameTexture *ttex, int cache) { bool isbgra = V_IsTrueColor(); - if (ttex != nullptr && ttex->isValid() && !ttex->isCanvas()) + if (ttex != nullptr && ttex->isValid() && !ttex->isSoftwareCanvas()) { - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); + FSoftwareTexture *tex = GetSoftwareTexture(ttex); if (tex->CheckPixels()) { @@ -95,18 +97,18 @@ void FSoftwareRenderer::PreparePrecache(FTexture *ttex, int cache) } else if (cache != 0) { - FImageSource::RegisterForPrecache(ttex->GetImage()); + FImageSource::RegisterForPrecache(ttex->GetTexture()->GetImage(), V_IsTrueColor()); } } } -void FSoftwareRenderer::PrecacheTexture(FTexture *ttex, int cache) +void FSoftwareRenderer::PrecacheTexture(FGameTexture *ttex, int cache) { bool isbgra = V_IsTrueColor(); - if (ttex != nullptr && ttex->isValid() && !ttex->isCanvas()) + if (ttex != nullptr && ttex->isValid() && !ttex->isSoftwareCanvas()) { - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); + FSoftwareTexture *tex = GetSoftwareTexture(ttex); if (cache & FTextureManager::HIT_Columnmode) { const FSoftwareTextureSpan *spanp; @@ -172,12 +174,12 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap & FImageSource::BeginPrecaching(); for (int i = cnt - 1; i >= 0; i--) { - PreparePrecache(TexMan.ByIndex(i), texhitlist[i]); + PreparePrecache(TexMan.GameByIndex(i), texhitlist[i]); } for (int i = cnt - 1; i >= 0; i--) { - PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]); + PrecacheTexture(TexMan.GameByIndex(i), texhitlist[i]); } FImageSource::EndPrecaching(); } @@ -226,6 +228,8 @@ void FSoftwareRenderer::SetClearColor(int color) mScene.SetClearColor(color); } +FSWCanvasTexture* GetSWCamTex(FCanvasTexture* camtex); + void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewpoint, double fov) { auto renderTarget = mScene.MainThread()->Viewport->RenderTarget; @@ -236,7 +240,8 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewp cameraViewpoint = r_viewpoint; cameraViewwindow = r_viewwindow; - auto tex = static_cast(camtex->GetSoftwareTexture()); + auto tex = GetSWCamTex(camtex); + if (!tex) return; DCanvas *Canvas = renderTarget->IsBgra() ? tex->GetCanvasBgra() : tex->GetCanvas(); @@ -245,7 +250,7 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewp CameraLight savedCameraLight = *CameraLight::Instance(); DAngle savedfov = cameraViewpoint.FieldOfView; - R_SetFOV (cameraViewpoint, fov); + R_SetFOV (cameraViewpoint, DAngle::fromDeg(fov)); mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate); @@ -266,9 +271,13 @@ void FSoftwareRenderer::SetColormap(FLevelLocals *Level) NormalLight.Maps = realcolormaps.Maps; NormalLight.ChangeColor(PalEntry(255, 255, 255), 0); NormalLight.ChangeFade(Level->fadeto); - if (Level->fadeto == 0) + if(Level->globalcolormap != 0) // this deliberately ignores the translated value and goes directly to the source. + { + SetDefaultColormap(Level->info->CustomColorMap.GetChars()); + } + else if (Level->fadeto == 0) { - SetDefaultColormap(Level->info->FadeTable); + SetDefaultColormap(Level->info->FadeTable.GetChars()); } } diff --git a/src/rendering/swrenderer/r_swrenderer.h b/src/rendering/swrenderer/r_swrenderer.h index 7ab3c050800..1e26a6a060c 100644 --- a/src/rendering/swrenderer/r_swrenderer.h +++ b/src/rendering/swrenderer/r_swrenderer.h @@ -27,8 +27,8 @@ struct FSoftwareRenderer : public FRenderer void Init() override; private: - void PreparePrecache(FTexture *tex, int cache); - void PrecacheTexture(FTexture *tex, int cache); + void PreparePrecache(FGameTexture *tex, int cache); + void PrecacheTexture(FGameTexture *tex, int cache); swrenderer::RenderScene mScene; }; diff --git a/src/rendering/swrenderer/r_swscene.cpp b/src/rendering/swrenderer/r_swscene.cpp index 7e432fb525b..0aad9245393 100644 --- a/src/rendering/swrenderer/r_swscene.cpp +++ b/src/rendering/swrenderer/r_swscene.cpp @@ -25,22 +25,19 @@ ** */ -#include "hwrenderer/textures/hw_ihwtexture.h" -#include "hwrenderer/textures/hw_material.h" +#include "hw_ihwtexture.h" +#include "hw_material.h" #include "swrenderer/r_renderer.h" #include "r_swscene.h" -#include "w_wad.h" +#include "filesystem.h" #include "d_player.h" -#include "textures/bitmap.h" +#include "bitmap.h" #include "swrenderer/scene/r_light.h" #include "image.h" -#include "doomerrors.h" - -// [RH] Base blending values (for e.g. underwater) -int BaseBlendR, BaseBlendG, BaseBlendB; -float BaseBlendA; - - +#include "engineerrors.h" +#include "texturemanager.h" +#include "d_main.h" +#include "v_draw.h" class FSWPaletteTexture : public FImageSource { @@ -51,7 +48,7 @@ class FSWPaletteTexture : public FImageSource Height = 1; } - int CopyPixels(FBitmap *bmp, int conversion) override + int CopyPixels(FBitmap *bmp, int conversion, int frame = 0) override { PalEntry *pe = (PalEntry*)bmp->GetPixels(); for (int i = 0; i < 256; i++) @@ -74,10 +71,11 @@ SWSceneDrawer::SWSceneDrawer() auto texid = TexMan.CheckForTexture("@@palette@@", ETextureType::Any); if (!texid.Exists()) { - auto tex = new FImageTexture(new FSWPaletteTexture, "@@palette@@"); - texid = TexMan.AddTexture(tex); + // We need to wrap this in a game texture object to have it managed by the texture manager, even though it will never be used as a material. + auto tex = MakeGameTexture(new FImageTexture(new FSWPaletteTexture), "@@palette@@", ETextureType::Special); + texid = TexMan.AddGameTexture(tex); } - PaletteTexture = TexMan.GetTexture(texid); + PaletteTexture = TexMan.GetGameTexture(texid)->GetTexture(); } SWSceneDrawer::~SWSceneDrawer() @@ -92,36 +90,38 @@ sector_t *SWSceneDrawer::RenderView(player_t *player) FBTextureIndex = (FBTextureIndex + 1) % 2; auto &fbtex = FBTexture[FBTextureIndex]; - if (fbtex == nullptr || fbtex->GetSystemTexture() == nullptr || - fbtex->GetDisplayWidth() != screen->GetWidth() || - fbtex->GetDisplayHeight() != screen->GetHeight() || - (V_IsTrueColor() ? 1:0) != fbtex->GetColorFormat()) + auto GetSystemTexture = [&]() { return fbtex->GetTexture()->GetHardwareTexture(0, 0); }; + + if (fbtex == nullptr || GetSystemTexture() == nullptr || + fbtex->GetTexelWidth() != screen->GetWidth() || + fbtex->GetTexelHeight() != screen->GetHeight() || + (V_IsTrueColor() ? 1:0) != static_cast(fbtex->GetTexture())->GetColorFormat()) { // This manually constructs its own material here. fbtex.reset(); - fbtex.reset(new FWrapperTexture(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor())); - fbtex->GetSystemTexture()->AllocateBuffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor() ? 4 : 1); + fbtex.reset(MakeGameTexture(new FWrapperTexture(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor()), nullptr, ETextureType::SWCanvas)); + GetSystemTexture()->AllocateBuffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor() ? 4 : 1); auto mat = FMaterial::ValidateTexture(fbtex.get(), false); - mat->AddTextureLayer(PaletteTexture); + mat->AddTextureLayer(PaletteTexture, false); Canvas.reset(); Canvas.reset(new DCanvas(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor())); } - IHardwareTexture *systemTexture = fbtex->GetSystemTexture(); + IHardwareTexture *systemTexture = GetSystemTexture(); auto buf = systemTexture->MapBuffer(); if (!buf) I_FatalError("Unable to map buffer for software rendering"); SWRenderer->RenderView(player, Canvas.get(), buf, systemTexture->GetBufferPitch()); - systemTexture->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer"); + systemTexture->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, "swbuffer"); auto map = swrenderer::CameraLight::Instance()->ShaderColormap(); - screen->DrawTexture(fbtex.get(), 0, 0, DTA_SpecialColormap, map, TAG_DONE); + DrawTexture(twod, fbtex.get(), 0, 0, DTA_SpecialColormap, map, TAG_DONE); screen->Draw2D(); - screen->Clear2D(); - screen->PostProcessScene(CM_DEFAULT, [&]() { + twod->Clear(); + screen->PostProcessScene(true, CM_DEFAULT, 1.f, [&]() { SWRenderer->DrawRemainingPlayerSprites(); screen->Draw2D(); - screen->Clear2D(); + twod->Clear(); }); } else @@ -134,11 +134,11 @@ sector_t *SWSceneDrawer::RenderView(player_t *player) int cm = CM_DEFAULT; auto map = swrenderer::CameraLight::Instance()->ShaderColormap(); if (map) cm = (int)(ptrdiff_t)(map - SpecialColormaps.Data()) + CM_FIRSTSPECIALCOLORMAP; - screen->PostProcessScene(cm, [&]() { }); + screen->PostProcessScene(true, cm, 1.f, [&]() { }); SWRenderer->DrawRemainingPlayerSprites(); screen->Draw2D(); - screen->Clear2D(); + twod->Clear(); } return r_viewpoint.sector; diff --git a/src/rendering/swrenderer/r_swscene.h b/src/rendering/swrenderer/r_swscene.h index 7dc12488d06..cff2eb7a559 100644 --- a/src/rendering/swrenderer/r_swscene.h +++ b/src/rendering/swrenderer/r_swscene.h @@ -9,11 +9,12 @@ #include class FWrapperTexture; +class DCanvas; class SWSceneDrawer { FTexture *PaletteTexture; - std::unique_ptr FBTexture[2]; + std::unique_ptr FBTexture[2]; int FBTextureIndex = 0; bool FBIsTruecolor = false; std::unique_ptr Canvas; diff --git a/src/rendering/swrenderer/scene/r_3dfloors.cpp b/src/rendering/swrenderer/scene/r_3dfloors.cpp index d468c9611e6..c8e9a452118 100644 --- a/src/rendering/swrenderer/scene/r_3dfloors.cpp +++ b/src/rendering/swrenderer/scene/r_3dfloors.cpp @@ -32,7 +32,7 @@ ** */ -#include "templates.h" + #include "doomdef.h" #include "p_local.h" #include "c_dispatch.h" @@ -41,9 +41,9 @@ #include "r_3dfloors.h" #include "r_utility.h" #include "swrenderer/r_renderthread.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" -CVAR(Int, r_3dfloors, true, 0); +CVAR(Int, r_3dfloors, 1, 0); namespace swrenderer { diff --git a/src/rendering/swrenderer/scene/r_light.cpp b/src/rendering/swrenderer/scene/r_light.cpp index 0f4914ff6db..2e6046ffbcf 100644 --- a/src/rendering/swrenderer/scene/r_light.cpp +++ b/src/rendering/swrenderer/scene/r_light.cpp @@ -23,9 +23,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -36,6 +36,7 @@ #include "c_dispatch.h" #include "cmdlib.h" #include "d_net.h" +#include "v_draw.h" #include "g_level.h" #include "r_utility.h" #include "d_player.h" @@ -87,7 +88,7 @@ namespace swrenderer // [RH] Inverse light for shooting the Sigil if (fixedcolormap == nullptr && viewpoint.extralight == INT_MIN) { - fixedcolormap = &SpecialSWColormaps[INVERSECOLORMAP]; + fixedcolormap = &SpecialSWColormaps[REALINVERSECOLORMAP]; viewpoint.extralight = 0; } } @@ -148,7 +149,7 @@ namespace swrenderer bool nolightfade = !foggy && ((viewport->Level()->flags3 & LEVEL3_NOLIGHTFADE)); if (nolightfade) { - return (MAX(255 - lightlevel, 0) * NUMCOLORMAPS) << (FRACBITS - 8); + return (max(255 - lightlevel, 0) * NUMCOLORMAPS) << (FRACBITS - 8); } else { diff --git a/src/rendering/swrenderer/scene/r_light.h b/src/rendering/swrenderer/scene/r_light.h index d14c73b5560..8f1d6adccb0 100644 --- a/src/rendering/swrenderer/scene/r_light.h +++ b/src/rendering/swrenderer/scene/r_light.h @@ -43,12 +43,12 @@ // Convert a shade and visibility to a clamped colormap index. // Result is not fixed point. // Change R_CalcTiltedLighting() when this changes. -#define GETPALOOKUP(vis,shade) (clamp (((shade)-FLOAT2FIXED(MIN(MAXLIGHTVIS,double(vis))))>>FRACBITS, 0, NUMCOLORMAPS-1)) +#define GETPALOOKUP(vis,shade) (clamp (((shade)-FLOAT2FIXED(min(MAXLIGHTVIS,double(vis))))>>FRACBITS, 0, NUMCOLORMAPS-1)) // Calculate the light multiplier for dc_light/ds_light // This is used instead of GETPALOOKUP when ds_colormap/dc_colormap is set to the base colormap // Returns a value between 0 and 1 in fixed point -#define LIGHTSCALE(vis,shade) FLOAT2FIXED(clamp((FIXED2DBL(shade) - (MIN(MAXLIGHTVIS,double(vis)))) / NUMCOLORMAPS, 0.0, (NUMCOLORMAPS-1)/(double)NUMCOLORMAPS)) +#define LIGHTSCALE(vis,shade) FLOAT2FIXED(clamp((FIXED2DBL(shade) - (min(MAXLIGHTVIS,double(vis)))) / NUMCOLORMAPS, 0.0, (NUMCOLORMAPS-1)/(double)NUMCOLORMAPS)) struct FSWColormap; @@ -82,7 +82,7 @@ namespace swrenderer // The vis value to pass into the GETPALOOKUP or LIGHTSCALE macros double WallVis(double screenZ, bool foggy) const { return WallGlobVis(foggy) / screenZ; } - double SpriteVis(double screenZ, bool foggy) const { return SpriteGlobVis(foggy) / MAX(screenZ, MINZ); } + double SpriteVis(double screenZ, bool foggy) const { return SpriteGlobVis(foggy) / max(screenZ, MINZ); } double FlatPlaneVis(int screenY, double planeheight, bool foggy, RenderViewport *viewport) const { return FlatPlaneGlobVis(foggy) / planeheight * fabs(viewport->CenterY - screenY); } double SlopePlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : TiltVisibility; } diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.cpp b/src/rendering/swrenderer/scene/r_opaque_pass.cpp index 2674e782d79..f9424464417 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.cpp +++ b/src/rendering/swrenderer/scene/r_opaque_pass.cpp @@ -28,15 +28,16 @@ #include -#include "templates.h" + #include "doomdef.h" #include "m_bbox.h" -#include "doomerrors.h" +#include "engineerrors.h" #include "p_lnspec.h" #include "p_setup.h" +#include "texturemanager.h" #include "swrenderer/drawers/r_draw.h" #include "swrenderer/plane/r_visibleplane.h" @@ -45,7 +46,6 @@ #include "swrenderer/things/r_wallsprite.h" #include "swrenderer/things/r_voxel.h" #include "swrenderer/things/r_particle.h" -#include "swrenderer/things/r_model.h" #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/line/r_wallsetup.h" #include "swrenderer/line/r_farclip_line.h" @@ -78,13 +78,15 @@ extern uint32_t r_renderercaps; double model_distance_cull = 1e16; +EXTERN_CVAR(Float, r_actorspriteshadowdist) + namespace { double sprite_distance_cull = 1e16; double line_distance_cull = 1e16; } -CUSTOM_CVAR(Float, r_sprite_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, r_sprite_distance_cull, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (r_sprite_distance_cull > 0.0) { @@ -96,7 +98,7 @@ CUSTOM_CVAR(Float, r_sprite_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } -CUSTOM_CVAR(Float, r_line_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, r_line_distance_cull, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (r_line_distance_cull > 0.0) { @@ -108,7 +110,7 @@ CUSTOM_CVAR(Float, r_line_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } -CUSTOM_CVAR(Float, r_model_distance_cull, 1024, 0/*CVAR_ARCHIVE | CVAR_GLOBALCONFIG*/) // Experimental for the moment until a good default is chosen +CUSTOM_CVAR(Float, r_model_distance_cull, 1024.f, 0/*CVAR_ARCHIVE | CVAR_GLOBALCONFIG*/) // Experimental for the moment until a good default is chosen { if (r_model_distance_cull > 0.0) { @@ -399,7 +401,7 @@ namespace swrenderer double t = -rx1; rx1 = -rx2; rx2 = t; - swapvalues(ry1, ry2); + std::swap(ry1, ry2); } auto viewport = Thread->Viewport.get(); @@ -553,7 +555,7 @@ namespace swrenderer frontsector->GetAlpha(sector_t::ceiling), !!(frontsector->GetFlags(sector_t::ceiling) & PLANEF_ADDITIVE), frontsector->planes[sector_t::ceiling].xform, - frontsector->sky, + frontsector->skytransfer, portal, basecolormap, Fake3DOpaque::Normal, @@ -593,7 +595,7 @@ namespace swrenderer frontsector->GetAlpha(sector_t::floor), !!(frontsector->GetFlags(sector_t::floor) & PLANEF_ADDITIVE), frontsector->planes[sector_t::floor].xform, - frontsector->sky, + frontsector->skytransfer, portal, basecolormap, Fake3DOpaque::Normal, @@ -603,12 +605,6 @@ namespace swrenderer } Add3DFloorPlanes(sub, frontsector, basecolormap, foggy, adjusted_ceilinglightlevel, adjusted_floorlightlevel); - - // killough 9/18/98: Fix underwater slowdown, by passing real sector - // instead of fake one. Improve sprite lighting by basing sprite - // lightlevels on floor & ceiling lightlevels in the surrounding area. - // [RH] Handle sprite lighting like Duke 3D: If the ceiling is a sky, sprites are lit by - // it, otherwise they are lit by the floor. auto nc = !!(frontsector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); AddSprites(sub->sector, frontsector->GetTexture(sector_t::ceiling) == skyflatnum ? ceilinglightlevel : floorlightlevel, FakeSide, foggy, GetSpriteColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::sprites], nc)); @@ -697,7 +693,7 @@ namespace swrenderer if (!(clip3d->fakeFloor->fakeFloor->flags & FF_RENDERPLANES)) continue; if (clip3d->fakeFloor->fakeFloor->alpha == 0) continue; if (clip3d->fakeFloor->fakeFloor->flags & FF_THISINSIDE && clip3d->fakeFloor->fakeFloor->flags & FF_INVERTSECTOR) continue; - fixed_t fakeAlpha = MIN(Scale(clip3d->fakeFloor->fakeFloor->alpha, OPAQUE, 255), OPAQUE); + fixed_t fakeAlpha = min(Scale(clip3d->fakeFloor->fakeFloor->alpha, OPAQUE, 255), OPAQUE); if (clip3d->fakeFloor->validcount != validcount) { clip3d->fakeFloor->validcount = validcount; @@ -736,7 +732,7 @@ namespace swrenderer tempsec.GetAlpha(sector_t::floor), !!(clip3d->fakeFloor->fakeFloor->flags & FF_ADDITIVETRANS), tempsec.planes[position].xform, - tempsec.sky, + tempsec.skytransfer, nullptr, basecolormap, Fake3DOpaque::FakeFloor, @@ -761,7 +757,7 @@ namespace swrenderer if (!(clip3d->fakeFloor->fakeFloor->flags & FF_RENDERPLANES)) continue; if (clip3d->fakeFloor->fakeFloor->alpha == 0) continue; if (!(clip3d->fakeFloor->fakeFloor->flags & FF_THISINSIDE) && (clip3d->fakeFloor->fakeFloor->flags & (FF_SWIMMABLE | FF_INVERTSECTOR)) == (FF_SWIMMABLE | FF_INVERTSECTOR)) continue; - fixed_t fakeAlpha = MIN(Scale(clip3d->fakeFloor->fakeFloor->alpha, OPAQUE, 255), OPAQUE); + fixed_t fakeAlpha = min(Scale(clip3d->fakeFloor->fakeFloor->alpha, OPAQUE, 255), OPAQUE); if (clip3d->fakeFloor->validcount != validcount) { @@ -804,7 +800,7 @@ namespace swrenderer tempsec.GetAlpha(sector_t::ceiling), !!(clip3d->fakeFloor->fakeFloor->flags & FF_ADDITIVETRANS), tempsec.planes[position].xform, - tempsec.sky, + tempsec.skytransfer, nullptr, basecolormap, Fake3DOpaque::FakeCeiling, @@ -857,7 +853,7 @@ namespace swrenderer node_t *bsp = (node_t *)node; // Decide which side the view point is on. - int side = R_PointOnSide(Thread->Viewport->viewpoint.Pos, bsp); + int side = R_PointOnSide(Thread->Viewport->viewpoint.Pos.XY(), bsp); // Recursively divide front space (toward the viewer). RenderBSPNode(bsp->children[side]); @@ -936,13 +932,7 @@ namespace swrenderer ThingSprite sprite; int spritenum = thing->sprite; bool isPicnumOverride = thing->picnum.isValid(); - FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); - if (r_modelscene && modelframe && (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared() < model_distance_cull) - { - DVector3 pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac); - RenderModel::Project(Thread, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing); - } - else if (GetThingSprite(thing, sprite)) + if (GetThingSprite(thing, sprite)) { FDynamicColormap *thingColormap = basecolormap; int thinglightlevel = lightlevel; @@ -950,8 +940,18 @@ namespace swrenderer { thinglightlevel = thing->Sector->GetTexture(sector_t::ceiling) == skyflatnum ? thing->Sector->GetCeilingLight() : thing->Sector->GetFloorLight(); auto nc = !!(thing->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); - thingColormap = GetSpriteColorTable(thing->Sector->Colormap, thing->Sector->SpecialColors[sector_t::sprites], nc); } + thingColormap = GetSpriteColorTable(thing->Sector->Colormap, thing->Sector->SpecialColors[sector_t::sprites], nc); + } + if (thing->LightLevel > -1) + { + thinglightlevel = thing->LightLevel; + if (thing->flags8 & MF8_ADDLIGHTLEVEL) + { + thinglightlevel += thing->Sector->GetTexture(sector_t::ceiling) == skyflatnum ? thing->Sector->GetCeilingLight() : thing->Sector->GetFloorLight(); + thinglightlevel = clamp(thinglightlevel, 0, 255); + } + } if ((sprite.renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) { RenderWallSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, thinglightlevel, foggy, thingColormap); @@ -963,6 +963,25 @@ namespace swrenderer else { RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thinglightlevel, foggy, thingColormap); + + // [Nash] draw sprite shadow + if (R_ShouldDrawSpriteShadow(thing)) + { + double dist = (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared(); + double distCheck = r_actorspriteshadowdist; + if (dist <= distCheck * distCheck) + { + // squash Y scale + DVector2 shadowScale = sprite.spriteScale; + shadowScale.Y *= 0.15; + + // snap to floor Z + DVector3 shadowPos = sprite.pos; + shadowPos.Z = thing->floorz; + + RenderSprite::Project(Thread, thing, shadowPos, sprite.tex, shadowScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thinglightlevel, foggy, thingColormap, true); + } + } } } } @@ -974,6 +993,7 @@ namespace swrenderer // Don't waste time projecting sprites that are definitely not visible. if (thing == nullptr || (thing->renderflags & RF_INVISIBLE) || + (thing->renderflags & RF_MAYBEINVISIBLE) || !thing->RenderStyle.IsVisible(thing->Alpha) || !thing->IsVisibleToPlayer() || !thing->IsInsideVisibleAngles()) @@ -981,6 +1001,16 @@ namespace swrenderer return false; } + if ((thing->flags8 & MF8_MASTERNOSEE) && thing->master != nullptr) + { + // Make MASTERNOSEE actors invisible if their master + // is invisible due to viewpoint shenanigans. + if (thing->master->renderflags & RF_MAYBEINVISIBLE) + { + return false; + } + } + // check renderrequired vs ~r_rendercaps, if anything matches we don't support that feature, // check renderhidden vs r_rendercaps, if anything matches we do support that feature and should hide it. if ((!r_debug_disable_vis_filter && !!(thing->RenderRequired & ~r_renderercaps)) || @@ -993,6 +1023,17 @@ namespace swrenderer if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && !!P_PointOnLineSidePrecise(thing->Pos(), renderportal->CurrentPortal->dst)) return false; + // [Nash] filter visibility in mirrors + bool isInMirror = renderportal != nullptr && renderportal->IsInMirrorRecursively; + if (thing->renderflags2 & RF2_INVISIBLEINMIRRORS && isInMirror) + { + return false; + } + else if (thing->renderflags2 & RF2_ONLYVISIBLEINMIRRORS && !isInMirror) + { + return false; + } + double distanceSquared = (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared(); if (distanceSquared > sprite_distance_cull) return false; @@ -1002,13 +1043,14 @@ namespace swrenderer bool RenderOpaquePass::GetThingSprite(AActor *thing, ThingSprite &sprite) { + // The X offsetting (SpriteOffset.X) is performed in r_sprite.cpp, in RenderSprite::Project(). sprite.pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac); - sprite.pos.Z += thing->GetBobOffset(Thread->Viewport->viewpoint.TicFrac); - + sprite.pos += thing->WorldOffset; + sprite.pos.Z += thing->GetBobOffset(Thread->Viewport->viewpoint.TicFrac) + thing->GetSpriteOffset(true); sprite.spritenum = thing->sprite; sprite.tex = nullptr; sprite.voxel = nullptr; - sprite.spriteScale = thing->Scale; + sprite.spriteScale = DVector2(thing->Scale.X, thing->Scale.Y); sprite.renderflags = thing->renderflags; if (thing->player != nullptr) @@ -1020,11 +1062,8 @@ namespace swrenderer { sprite.picnum = thing->picnum; - sprite.tex = TexMan.GetPalettedTexture(sprite.picnum, true); - if (!sprite.tex->isValid()) - { - return false; - } + sprite.tex = GetPalettedSWTexture(sprite.picnum, true); + if (!sprite.tex) return false; if (sprite.tex->GetRotations() != 0xFFFF) { @@ -1035,23 +1074,24 @@ namespace swrenderer if (sprframe->Texture[0] == sprframe->Texture[1]) { if (thing->flags7 & MF7_SPRITEANGLE) - rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28; + rot = (thing->SpriteAngle + DAngle::fromDeg(45.0 / 2 * 9)).BAMs() >> 28; else - rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28; + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + DAngle::fromDeg(45.0 / 2 * 9)).BAMs() >> 28; } else { if (thing->flags7 & MF7_SPRITEANGLE) - rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + rot = (thing->SpriteAngle + DAngle::fromDeg(45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; else - rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + DAngle::fromDeg(45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; } sprite.picnum = sprframe->Texture[rot]; if (sprframe->Flip & (1 << rot)) { sprite.renderflags ^= RF_XFLIP; } - sprite.tex = TexMan.GetPalettedTexture(sprite.picnum, false); // Do not animate the rotation + sprite.tex = GetPalettedSWTexture(sprite.picnum, false); // Do not animate the rotation + if (!sprite.tex) return false; } } else @@ -1081,7 +1121,7 @@ namespace swrenderer { sprite.renderflags ^= RF_XFLIP; } - sprite.tex = TexMan.GetPalettedTexture(tex, false); // Do not animate the rotation + sprite.tex = GetPalettedSWTexture(tex, false); // Do not animate the rotation } if (r_drawvoxels) @@ -1093,7 +1133,7 @@ namespace swrenderer return false; } - if (sprite.voxel == nullptr && (sprite.tex == nullptr || !sprite.tex->isValid())) + if (sprite.voxel == nullptr && sprite.tex == nullptr) { return false; } diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.h b/src/rendering/swrenderer/scene/r_opaque_pass.h index d834327d569..d9d20c972cb 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.h +++ b/src/rendering/swrenderer/scene/r_opaque_pass.h @@ -51,7 +51,7 @@ namespace swrenderer { DVector3 pos; int spritenum; - FTexture *tex; + FSoftwareTexture *tex; FVoxelDef *voxel; FTextureID picnum; DVector2 spriteScale; diff --git a/src/rendering/swrenderer/scene/r_portal.cpp b/src/rendering/swrenderer/scene/r_portal.cpp index a39340c4d3e..6135c3f6148 100644 --- a/src/rendering/swrenderer/scene/r_portal.cpp +++ b/src/rendering/swrenderer/scene/r_portal.cpp @@ -24,7 +24,7 @@ #include #include -#include "templates.h" + #include "doomdef.h" #include "d_net.h" #include "doomstat.h" @@ -46,7 +46,6 @@ #include "v_palette.h" #include "po_man.h" #include "p_effect.h" -#include "st_start.h" #include "v_font.h" #include "r_data/colormaps.h" #include "p_maputl.h" @@ -65,7 +64,7 @@ #include "swrenderer/scene/r_scene.h" #include "swrenderer/scene/r_light.h" #include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" CVAR(Int, r_portal_recursions, 4, CVAR_ARCHIVE) @@ -330,9 +329,9 @@ namespace swrenderer DAngle startang = viewpoint.Angles.Yaw; DVector3 startpos = viewpoint.Pos; DVector3 savedpath[2] = { viewpoint.Path[0], viewpoint.Path[1] }; - ActorRenderFlags savedvisibility = viewpoint.camera ? viewpoint.camera->renderflags & RF_INVISIBLE : ActorRenderFlags::FromInt(0); + ActorRenderFlags savedvisibility = viewpoint.camera ? viewpoint.camera->renderflags & RF_MAYBEINVISIBLE : ActorRenderFlags::FromInt(0); - viewpoint.camera->renderflags &= ~RF_INVISIBLE; + viewpoint.camera->renderflags &= ~RF_MAYBEINVISIBLE; CurrentPortalUniq++; @@ -340,6 +339,8 @@ namespace swrenderer if (pds->mirror) { + IsInMirrorRecursively = true; + //vertex_t *v1 = ds->curline->v1; vertex_t *v1 = pds->src->v1; @@ -389,7 +390,7 @@ namespace swrenderer if (dist1 + dist2 < distp + 1) { - viewpoint.camera->renderflags |= RF_INVISIBLE; + viewpoint.camera->renderflags |= RF_MAYBEINVISIBLE; } } } @@ -436,7 +437,7 @@ namespace swrenderer Thread->OpaquePass->RenderScene(Thread->Viewport->Level()); Thread->Clip3D->ResetClip(); // reset clips (floor/ceiling) - if (!savedvisibility && viewpoint.camera) viewpoint.camera->renderflags &= ~RF_INVISIBLE; + if (!savedvisibility && viewpoint.camera) viewpoint.camera->renderflags &= ~RF_MAYBEINVISIBLE; Thread->PlaneList->Render(); RenderPlanePortals(); @@ -466,6 +467,7 @@ namespace swrenderer CurrentPortal = prevpds; MirrorFlags = prevmf; + IsInMirrorRecursively = false; viewpoint.Angles.Yaw = startang; viewpoint.Pos = startpos; viewpoint.Path[0] = savedpath[0]; diff --git a/src/rendering/swrenderer/scene/r_portal.h b/src/rendering/swrenderer/scene/r_portal.h index 34a49a4ffaf..cf1f075d58b 100644 --- a/src/rendering/swrenderer/scene/r_portal.h +++ b/src/rendering/swrenderer/scene/r_portal.h @@ -48,6 +48,10 @@ namespace swrenderer int WindowRight = 0; uint16_t MirrorFlags = 0; + // [Nash] this is set when first entering a mirror portal, and is unset when leaving the final mirror portal recursion + // Used for the RF2_INVISIBLEINMIRRORS and RF2_ONLYVISIBLEINMIRRORS features + bool IsInMirrorRecursively = false; + PortalDrawseg* CurrentPortal = nullptr; int CurrentPortalUniq = 0; bool CurrentPortalInSkybox = false; diff --git a/src/rendering/swrenderer/scene/r_scene.cpp b/src/rendering/swrenderer/scene/r_scene.cpp index a5d3a29f251..56aa725609e 100644 --- a/src/rendering/swrenderer/scene/r_scene.cpp +++ b/src/rendering/swrenderer/scene/r_scene.cpp @@ -22,9 +22,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" +#include "v_draw.h" +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -53,27 +53,21 @@ #include "swrenderer/viewport/r_viewport.h" #include "swrenderer/drawers/r_draw.h" #include "swrenderer/drawers/r_draw_rgba.h" -#include "swrenderer/drawers/r_thread.h" -#include "swrenderer/r_memory.h" +#include "r_thread.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" #include "swrenderer/things/r_playersprite.h" #include -#ifdef WIN32 -void PeekThreadedErrorPane(); -#endif - EXTERN_CVAR(Int, r_clearbuffer) EXTERN_CVAR(Int, r_debug_draw) -CVAR(Int, r_scene_multithreaded, 0, 0); +CVAR(Int, r_scene_multithreaded, 1, 0); CVAR(Bool, r_models, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); -bool r_modelscene = false; - namespace swrenderer { - cycle_t WallCycles, PlaneCycles, MaskedCycles, DrawerWaitCycles; + cycle_t WallCycles, PlaneCycles, MaskedCycles; RenderScene::RenderScene() { @@ -104,18 +98,6 @@ namespace swrenderer ActiveRatio(width, height, &trueratio); viewport->SetViewport(player->camera->Level, MainThread(), width, height, trueratio); - /*r_modelscene = r_models && Models.Size() > 0; - if (r_modelscene) - { - if (!DepthStencil || DepthStencil->Width() != viewport->RenderTarget->GetWidth() || DepthStencil->Height() != viewport->RenderTarget->GetHeight()) - { - DepthStencil.reset(); - DepthStencil.reset(new PolyDepthStencil(viewport->RenderTarget->GetWidth(), viewport->RenderTarget->GetHeight())); - } - PolyTriangleDrawer::SetViewport(MainThread()->DrawQueue, 0, 0, viewport->RenderTarget->GetWidth(), viewport->RenderTarget->GetHeight(), viewport->RenderTarget, DepthStencil.get()); - PolyTriangleDrawer::ClearStencil(MainThread()->DrawQueue, 0); - }*/ - if (r_clearbuffer != 0 || r_debug_draw != 0) { if (!viewport->RenderTarget->IsBgra()) @@ -131,7 +113,6 @@ namespace swrenderer for (int i = 0; i < size; i++) dest[i] = bgracolor.d; } - DrawerThreads::ResetDebugDrawPos(); } RenderActorView(player->mo, true, false); @@ -141,11 +122,8 @@ namespace swrenderer auto copyqueue = std::make_shared(MainThread()->FrameMemory.get()); copyqueue->Push(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1); DrawerThreads::Execute(copyqueue); + DrawerThreads::WaitForWorkers(); } - - DrawerWaitCycles.Clock(); - DrawerThreads::WaitForWorkers(); - DrawerWaitCycles.Unclock(); } void RenderScene::RenderActorView(AActor *actor, bool renderPlayerSprites, bool dontmaplines) @@ -153,7 +131,6 @@ namespace swrenderer WallCycles.Reset(); PlaneCycles.Reset(); MaskedCycles.Reset(); - DrawerWaitCycles.Reset(); R_SetupFrame(MainThread()->Viewport->viewpoint, MainThread()->Viewport->viewwindow, actor); @@ -167,24 +144,19 @@ namespace swrenderer R_UpdateFuzzPosFrameStart(); - if (r_modelscene) - MainThread()->Viewport->SetupPolyViewport(MainThread()); - FRenderViewpoint origviewpoint = MainThread()->Viewport->viewpoint; ActorRenderFlags savedflags = MainThread()->Viewport->viewpoint.camera->renderflags; // Never draw the player unless in chasecam mode if (!MainThread()->Viewport->viewpoint.showviewer) { - MainThread()->Viewport->viewpoint.camera->renderflags |= RF_INVISIBLE; + MainThread()->Viewport->viewpoint.camera->renderflags |= RF_MAYBEINVISIBLE; } RenderThreadSlices(); // Mirrors fail to restore the original viewpoint -- we need it for the HUD weapon to draw correctly. MainThread()->Viewport->viewpoint = origviewpoint; - if (r_modelscene) - MainThread()->Viewport->SetupPolyViewport(MainThread()); if (renderPlayerSprites) RenderPSprites(); @@ -194,14 +166,7 @@ namespace swrenderer void RenderScene::RenderPSprites() { - // Player sprites needs to be rendered after all the slices because they may be hardware accelerated. - // If they are not hardware accelerated the drawers must run after all sliced drawers finished. - DrawerWaitCycles.Clock(); - DrawerThreads::WaitForWorkers(); - DrawerWaitCycles.Unclock(); - MainThread()->DrawQueue->Clear(); MainThread()->PlayerSprites->Render(); - DrawerThreads::Execute(MainThread()->DrawQueue); } void RenderScene::RenderThreadSlices() @@ -231,6 +196,7 @@ namespace swrenderer Threads[i]->X2 = viewwidth * (i + 1) / numThreads; } run_id++; + FSoftwareTexture::CurrentUpdate = run_id; start_lock.unlock(); // Notify threads to run @@ -250,12 +216,7 @@ namespace swrenderer finished_threads++; if (!end_condition.wait_for(end_lock, 5s, [&]() { return finished_threads == Threads.size(); })) { -#ifdef WIN32 - PeekThreadedErrorPane(); -#endif - // Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing - int *threadCrashed = nullptr; - *threadCrashed = 0xdeadbeef; + I_FatalError("Render threads did not finish within 5 seconds!"); } finished_threads = 0; } @@ -267,7 +228,6 @@ namespace swrenderer void RenderScene::RenderThreadSlice(RenderThread *thread) { - thread->DrawQueue->Clear(); thread->FrameMemory->Clear(); thread->Clip3D->Cleanup(); thread->Clip3D->ResetClip(); // reset clips (floor/ceiling) @@ -280,12 +240,6 @@ namespace swrenderer thread->OpaquePass->ResetFakingUnderwater(); // [RH] Hack to make windows into underwater areas possible thread->Portal->SetMainPortal(); - /*if (r_modelscene && thread->MainThread) - PolyTriangleDrawer::ClearStencil(MainThread()->DrawQueue, 0); - - PolyTriangleDrawer::SetViewport(thread->DrawQueue, viewwindowx, viewwindowy, viewwidth, viewheight, thread->Viewport->RenderTarget, DepthStencil.get()); - PolyTriangleDrawer::SetScissor(thread->DrawQueue, viewwindowx, viewwindowy, viewwidth, viewheight);*/ - // Cull things outside the range seen by this thread VisibleSegmentRenderer visitor; if (thread->X1 > 0) @@ -306,7 +260,37 @@ namespace swrenderer thread->TranslucentPass->Render(); } - DrawerThreads::Execute(thread->DrawQueue); +#if 0 // shows the render slice edges + if (thread->Viewport->RenderTarget->IsBgra()) + { + uint32_t* left = (uint32_t*)thread->Viewport->GetDest(thread->X1, 0); + uint32_t* right = (uint32_t*)thread->Viewport->GetDest(thread->X2 - 1, 0); + int pitch = thread->Viewport->RenderTarget->GetPitch(); + uint32_t c = MAKEARGB(255, 0, 0, 0); + for (int i = 0; i < viewheight; i++) + { + *left = c; + *right = c; + left += pitch; + right += pitch; + } + } + else + { + uint8_t* left = (uint8_t*)thread->Viewport->GetDest(thread->X1, 0); + uint8_t* right = (uint8_t*)thread->Viewport->GetDest(thread->X2 - 1, 0); + int pitch = thread->Viewport->RenderTarget->GetPitch(); + int r = 0, g = 0, b = 0; + uint8_t c = RGB32k.RGB[(r >> 3)][(g >> 3)][(b >> 3)]; + for (int i = 0; i < viewheight; i++) + { + *left = c; + *right = c; + left += pitch; + right += pitch; + } + } +#endif } void RenderScene::StartThreads(size_t numThreads) @@ -379,20 +363,9 @@ namespace swrenderer viewwindowy = y; viewactive = true; viewport->SetViewport(actor->Level, MainThread(), width, height, MainThread()->Viewport->viewwindow.WidescreenRatio); - if (r_modelscene) - { - if (!DepthStencil || DepthStencil->Width() != viewport->RenderTarget->GetWidth() || DepthStencil->Height() != viewport->RenderTarget->GetHeight()) - { - DepthStencil.reset(); - DepthStencil.reset(new PolyDepthStencil(viewport->RenderTarget->GetWidth(), viewport->RenderTarget->GetHeight())); - } - } // Render: RenderActorView(actor, false, dontmaplines); - DrawerWaitCycles.Clock(); - DrawerThreads::WaitForWorkers(); - DrawerWaitCycles.Unclock(); viewport->RenderingToCanvas = false; @@ -415,28 +388,27 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////// - ADD_STAT(fps) + ADD_STAT(swfps) { FString out; - out.Format("frame=%04.1f ms walls=%04.1f ms planes=%04.1f ms masked=%04.1f ms drawers=%04.1f ms", - FrameCycles.TimeMS(), WallCycles.TimeMS(), PlaneCycles.TimeMS(), MaskedCycles.TimeMS(), DrawerWaitCycles.TimeMS()); + out.Format("frame=%04.1f ms walls=%04.1f ms planes=%04.1f ms masked=%04.1f ms", + FrameCycles.TimeMS(), WallCycles.TimeMS(), PlaneCycles.TimeMS(), MaskedCycles.TimeMS()); return out; } - static double f_acc, w_acc, p_acc, m_acc, drawer_acc; + static double f_acc, w_acc, p_acc, m_acc; static int acc_c; - ADD_STAT(fps_accumulated) + ADD_STAT(swfps_accumulated) { f_acc += FrameCycles.TimeMS(); w_acc += WallCycles.TimeMS(); p_acc += PlaneCycles.TimeMS(); m_acc += MaskedCycles.TimeMS(); - drawer_acc += DrawerWaitCycles.TimeMS(); acc_c++; FString out; - out.Format("frame=%04.1f ms walls=%04.1f ms planes=%04.1f ms masked=%04.1f ms drawers=%04.1f ms %d counts", - f_acc / acc_c, w_acc / acc_c, p_acc / acc_c, m_acc / acc_c, drawer_acc / acc_c, acc_c); + out.Format("frame=%04.1f ms walls=%04.1f ms planes=%04.1f ms masked=%04.1f ms %d counts", + f_acc / acc_c, w_acc / acc_c, p_acc / acc_c, m_acc / acc_c, acc_c); Printf(PRINT_LOG, "%s\n", out.GetChars()); return out; } diff --git a/src/rendering/swrenderer/scene/r_scene.h b/src/rendering/swrenderer/scene/r_scene.h index c5fa8e95990..035d1213370 100644 --- a/src/rendering/swrenderer/scene/r_scene.h +++ b/src/rendering/swrenderer/scene/r_scene.h @@ -32,8 +32,6 @@ extern cycle_t FrameCycles; -class PolyDepthStencil; - namespace swrenderer { extern cycle_t WallCycles, PlaneCycles, MaskedCycles, DrawerWaitCycles; @@ -69,7 +67,6 @@ namespace swrenderer bool dontmaplines = false; int clearcolor = 0; - std::unique_ptr DepthStencil; std::vector> Threads; std::mutex start_mutex; std::condition_variable start_condition; diff --git a/src/rendering/swrenderer/scene/r_translucent_pass.cpp b/src/rendering/swrenderer/scene/r_translucent_pass.cpp index bcc91ac39c6..101f53ef7a7 100644 --- a/src/rendering/swrenderer/scene/r_translucent_pass.cpp +++ b/src/rendering/swrenderer/scene/r_translucent_pass.cpp @@ -23,11 +23,11 @@ #include #include #include "p_lnspec.h" -#include "templates.h" + #include "doomdef.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "g_levellocals.h" #include "p_maputl.h" #include "swrenderer/things/r_visiblesprite.h" @@ -44,7 +44,7 @@ #include "swrenderer/plane/r_visibleplanelist.h" #include "swrenderer/line/r_renderdrawsegment.h" #include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" EXTERN_CVAR(Int, r_drawfuzz) diff --git a/src/rendering/swrenderer/segments/r_clipsegment.cpp b/src/rendering/swrenderer/segments/r_clipsegment.cpp index 3afb4bab397..b08cab770c1 100644 --- a/src/rendering/swrenderer/segments/r_clipsegment.cpp +++ b/src/rendering/swrenderer/segments/r_clipsegment.cpp @@ -20,7 +20,7 @@ //----------------------------------------------------------------------------- #include -#include "templates.h" + #include "doomdef.h" #include "m_bbox.h" diff --git a/src/rendering/swrenderer/segments/r_drawsegment.cpp b/src/rendering/swrenderer/segments/r_drawsegment.cpp index f90f8db55c0..6905ebf4441 100644 --- a/src/rendering/swrenderer/segments/r_drawsegment.cpp +++ b/src/rendering/swrenderer/segments/r_drawsegment.cpp @@ -20,7 +20,7 @@ //----------------------------------------------------------------------------- #include -#include "templates.h" + #include "doomdef.h" #include "m_bbox.h" @@ -36,7 +36,7 @@ #include "po_man.h" #include "r_data/colormaps.h" #include "d_net.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/drawers/r_draw.h" #include "swrenderer/scene/r_3dfloors.h" #include "swrenderer/scene/r_opaque_pass.h" @@ -104,21 +104,21 @@ namespace swrenderer DrawSegmentGroup group; group.BeginIndex = index; - group.EndIndex = MIN(index + groupSize, SegmentsCount()); + group.EndIndex = min(index + groupSize, SegmentsCount()); group.x1 = ds->x1; group.x2 = ds->x2; - group.neardepth = MIN(ds->WallC.sz1, ds->WallC.sz2); - group.fardepth = MAX(ds->WallC.sz1, ds->WallC.sz2); + group.neardepth = min(ds->WallC.sz1, ds->WallC.sz2); + group.fardepth = max(ds->WallC.sz1, ds->WallC.sz2); for (unsigned int groupIndex = group.BeginIndex + 1; groupIndex < group.EndIndex; groupIndex++) { ds = Segment(groupIndex); - group.x1 = MIN(group.x1, ds->x1); - group.x2 = MAX(group.x2, ds->x2); - group.neardepth = MIN(group.neardepth, ds->WallC.sz1); - group.neardepth = MIN(group.neardepth, ds->WallC.sz2); - group.fardepth = MAX(ds->WallC.sz1, group.fardepth); - group.fardepth = MAX(ds->WallC.sz2, group.fardepth); + group.x1 = min(group.x1, ds->x1); + group.x2 = max(group.x2, ds->x2); + group.neardepth = min(group.neardepth, ds->WallC.sz1); + group.neardepth = min(group.neardepth, ds->WallC.sz2); + group.fardepth = max(ds->WallC.sz1, group.fardepth); + group.fardepth = max(ds->WallC.sz2, group.fardepth); } for (int x = group.x1; x < group.x2; x++) diff --git a/src/rendering/swrenderer/segments/r_portalsegment.cpp b/src/rendering/swrenderer/segments/r_portalsegment.cpp index 983921533d3..dbdd7892d4d 100644 --- a/src/rendering/swrenderer/segments/r_portalsegment.cpp +++ b/src/rendering/swrenderer/segments/r_portalsegment.cpp @@ -20,7 +20,7 @@ //----------------------------------------------------------------------------- #include -#include "templates.h" + #include "doomdef.h" #include "m_bbox.h" @@ -39,7 +39,7 @@ #include "po_man.h" #include "r_data/colormaps.h" #include "swrenderer/segments/r_portalsegment.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" namespace swrenderer @@ -55,18 +55,6 @@ namespace swrenderer memcpy(ceilingclip, topclip + x1, len * sizeof(short)); memcpy(floorclip, bottomclip + x1, len * sizeof(short)); - for (int i = 0; i < x2 - x1; i++) - { - if (ceilingclip[i] < 0) - ceilingclip[i] = 0; - if (ceilingclip[i] >= viewheight) - ceilingclip[i] = viewheight - 1; - if (floorclip[i] < 0) - floorclip[i] = 0; - if (floorclip[i] >= viewheight) - floorclip[i] = viewheight - 1; - } - mirror = linedef->special == Line_Mirror; } } diff --git a/src/rendering/swrenderer/textures/r_swtexture.cpp b/src/rendering/swrenderer/textures/r_swtexture.cpp index b5aee3f0119..1336abfd2e6 100644 --- a/src/rendering/swrenderer/textures/r_swtexture.cpp +++ b/src/rendering/swrenderer/textures/r_swtexture.cpp @@ -38,35 +38,45 @@ #include "bitmap.h" #include "m_alloc.h" #include "imagehelpers.h" +#include "texturemanager.h" +#include - -FSoftwareTexture *FTexture::GetSoftwareTexture() +inline EUpscaleFlags scaleFlagFromUseType(ETextureType useType) { - if (!SoftwareTexture) + switch (useType) { - if (bHasCanvas) SoftwareTexture = new FSWCanvasTexture(this); - else if (bWarped) SoftwareTexture = new FWarpTexture(this, bWarped); - else SoftwareTexture = new FSoftwareTexture(this); + case ETextureType::Sprite: + case ETextureType::SkinSprite: + return UF_Sprite; + + case ETextureType::FontChar: + return UF_Font; + + default: + return UF_Texture; } - return SoftwareTexture; } - //========================================================================== // // // //========================================================================== -FSoftwareTexture::FSoftwareTexture(FTexture *tex) +FSoftwareTexture::FSoftwareTexture(FGameTexture *tex) { mTexture = tex; - mSource = tex; + mSource = tex->GetTexture(); mBufferFlags = CTF_ProcessData; - auto info = tex->CreateTexBuffer(0, CTF_CheckOnly| mBufferFlags); + + if (shouldUpscale(tex, scaleFlagFromUseType(tex->GetUseType()))) mBufferFlags |= CTF_Upscale; + // calculate the real size after running the scaler. + auto info = mSource->CreateTexBuffer(0, CTF_CheckOnly| mBufferFlags); mPhysicalWidth = info.mWidth; - mPhysicalHeight = info.mHeight; - mPhysicalScale = tex->Width > 0? mPhysicalWidth / tex->Width : mPhysicalWidth; + mPhysicalHeight = info.mHeight; + mPhysicalScale = tex->GetTexelWidth() > 0 ? mPhysicalWidth / tex->GetTexelWidth() : mPhysicalWidth; + Scale.X = (double)tex->GetTexelWidth() / tex->GetDisplayWidth(); + Scale.Y = (double)tex->GetTexelHeight() / tex->GetDisplayHeight(); CalcBitSize(); } @@ -109,7 +119,7 @@ void FSoftwareTexture::CalcBitSize () // //========================================================================== -const uint8_t *FSoftwareTexture::GetPixels(int style) +const uint8_t *FSoftwareTexture::GetPixelsLocked(int style) { if (Pixels.Size() == 0 || CheckModified(style)) { @@ -119,7 +129,8 @@ const uint8_t *FSoftwareTexture::GetPixels(int style) } else { - auto tempbuffer = mTexture->CreateTexBuffer(0, mBufferFlags); + auto f = mBufferFlags; + auto tempbuffer = mSource->CreateTexBuffer(0, f); Pixels.Resize(GetPhysicalWidth()*GetPhysicalHeight()); PalEntry *pe = (PalEntry*)tempbuffer.mBuffer; if (!style) @@ -147,24 +158,18 @@ const uint8_t *FSoftwareTexture::GetPixels(int style) return Pixels.Data(); } -//========================================================================== -// -// -// -//========================================================================== - -const uint32_t *FSoftwareTexture::GetPixelsBgra() +const uint32_t *FSoftwareTexture::GetPixelsBgraLocked() { if (PixelsBgra.Size() == 0 || CheckModified(2)) { if (mPhysicalScale == 1) { - FBitmap bitmap = mTexture->GetBgraBitmap(nullptr); + FBitmap bitmap = mSource->GetBgraBitmap(nullptr); GenerateBgraFromBitmap(bitmap); } else { - auto tempbuffer = mTexture->CreateTexBuffer(0, mBufferFlags); + auto tempbuffer = mSource->CreateTexBuffer(0, mBufferFlags); CreatePixelsBgraWithMipmaps(); PalEntry *pe = (PalEntry*)tempbuffer.mBuffer; for (int y = 0; y < GetPhysicalHeight(); y++) @@ -186,60 +191,31 @@ const uint32_t *FSoftwareTexture::GetPixelsBgra() // //========================================================================== -const uint8_t *FSoftwareTexture::GetColumn(int index, unsigned int column, const FSoftwareTextureSpan **spans_out) -{ - auto Pixeldata = GetPixels(index); - if ((unsigned)column >= (unsigned)GetPhysicalWidth()) - { - if (WidthMask + 1 == GetPhysicalWidth()) - { - column &= WidthMask; - } - else - { - column %= GetPhysicalWidth(); - } - } - if (spans_out != nullptr) - { - if (Spandata[index] == nullptr) - { - Spandata[index] = CreateSpans(Pixeldata); - } - *spans_out = Spandata[index][column]; - } - return Pixeldata + column * GetPhysicalHeight(); -} - -//========================================================================== -// -// -// -//========================================================================== +int FSoftwareTexture::CurrentUpdate = 0; +namespace swrenderer { extern std::mutex loadmutex; } -const uint32_t *FSoftwareTexture::GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out) +void FSoftwareTexture::UpdatePixels(int index) { - auto Pixeldata = GetPixelsBgra(); - if ((unsigned)column >= (unsigned)GetPhysicalWidth()) + std::unique_lock lock(swrenderer::loadmutex); + if (Unlockeddata[index].LastUpdate != CurrentUpdate) { - if (WidthMask + 1 == GetPhysicalWidth()) + if (index != 2) { - column &= WidthMask; + const uint8_t* Pixeldata = GetPixelsLocked(index); + if (Spandata[index] == nullptr) + Spandata[index] = CreateSpans(Pixeldata); + Unlockeddata[index].Pixels = Pixeldata; + Unlockeddata[index].LastUpdate = CurrentUpdate; } else { - column %= GetPhysicalWidth(); + const uint32_t* Pixeldata = GetPixelsBgraLocked(); + if (Spandata[index] == nullptr) + Spandata[index] = CreateSpans(Pixeldata); + Unlockeddata[index].Pixels = Pixeldata; + Unlockeddata[index].LastUpdate = CurrentUpdate; } } - if (spans_out != nullptr) - { - if (Spandata[2] == nullptr) - { - Spandata[2] = CreateSpans(Pixeldata); - } - *spans_out = Spandata[2][column]; - } - return Pixeldata + column * GetPhysicalHeight(); } //========================================================================== @@ -388,8 +364,8 @@ void FSoftwareTexture::CreatePixelsBgraWithMipmaps() int buffersize = 0; for (int i = 0; i < levels; i++) { - int w = MAX(GetPhysicalWidth() >> i, 1); - int h = MAX(GetPhysicalHeight() >> i, 1); + int w = max(GetPhysicalWidth() >> i, 1); + int h = max(GetPhysicalHeight() >> i, 1); buffersize += w * h; } PixelsBgra.Resize(buffersize); @@ -403,7 +379,7 @@ int FSoftwareTexture::MipmapLevels() int heightbits = 0; while ((GetPhysicalHeight() >> heightbits) != 0) heightbits++; - return MAX(widthbits, heightbits); + return max(widthbits, heightbits); } //========================================================================== @@ -454,20 +430,20 @@ void FSoftwareTexture::GenerateBgraMipmaps() Color4f *dest = src + GetPhysicalWidth() * GetPhysicalHeight(); for (int i = 1; i < levels; i++) { - int srcw = MAX(GetPhysicalWidth() >> (i - 1), 1); - int srch = MAX(GetPhysicalHeight() >> (i - 1), 1); - int w = MAX(GetPhysicalWidth() >> i, 1); - int h = MAX(GetPhysicalHeight() >> i, 1); + int srcw = max(GetPhysicalWidth() >> (i - 1), 1); + int srch = max(GetPhysicalHeight() >> (i - 1), 1); + int w = max(GetPhysicalWidth() >> i, 1); + int h = max(GetPhysicalHeight() >> i, 1); // Downscale for (int x = 0; x < w; x++) { int sx0 = x * 2; - int sx1 = MIN((x + 1) * 2, srcw - 1); + int sx1 = min((x + 1) * 2, srcw - 1); for (int y = 0; y < h; y++) { int sy0 = y * 2; - int sy1 = MIN((y + 1) * 2, srch - 1); + int sy1 = min((y + 1) * 2, srch - 1); Color4f src00 = src[sy0 + sx0 * srch]; Color4f src01 = src[sy1 + sx0 * srch]; @@ -517,14 +493,14 @@ void FSoftwareTexture::GenerateBgraMipmaps() uint32_t *dest = PixelsBgra.Data() + GetPhysicalWidth() * GetPhysicalHeight(); for (int i = 1; i < levels; i++) { - int w = MAX(GetPhysicalWidth() >> i, 1); - int h = MAX(GetPhysicalHeight() >> i, 1); + int w = max(GetPhysicalWidth() >> i, 1); + int h = max(GetPhysicalHeight() >> i, 1); for (int j = 0; j < w * h; j++) { - uint32_t a = (uint32_t)clamp(powf(MAX(src[j].a, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); - uint32_t r = (uint32_t)clamp(powf(MAX(src[j].r, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); - uint32_t g = (uint32_t)clamp(powf(MAX(src[j].g, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); - uint32_t b = (uint32_t)clamp(powf(MAX(src[j].b, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); + uint32_t a = (uint32_t)clamp(powf(max(src[j].a, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); + uint32_t r = (uint32_t)clamp(powf(max(src[j].r, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); + uint32_t g = (uint32_t)clamp(powf(max(src[j].g, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); + uint32_t b = (uint32_t)clamp(powf(max(src[j].b, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); dest[j] = (a << 24) | (r << 16) | (g << 8) | b; } src += w * h; @@ -535,66 +511,62 @@ void FSoftwareTexture::GenerateBgraMipmaps() //========================================================================== // -// +// // //========================================================================== -void FSoftwareTexture::GenerateBgraMipmapsFast() +void FSoftwareTexture::FreeAllSpans() { - uint32_t *src = PixelsBgra.Data(); - uint32_t *dest = src + GetPhysicalWidth() * GetPhysicalHeight(); - int levels = MipmapLevels(); - for (int i = 1; i < levels; i++) + for(int i = 0; i < 3; i++) { - int srcw = MAX(GetPhysicalWidth() >> (i - 1), 1); - int srch = MAX(GetPhysicalHeight() >> (i - 1), 1); - int w = MAX(GetPhysicalWidth() >> i, 1); - int h = MAX(GetPhysicalHeight() >> i, 1); - - for (int x = 0; x < w; x++) + if (Spandata[i] != nullptr) { - int sx0 = x * 2; - int sx1 = MIN((x + 1) * 2, srcw - 1); - - for (int y = 0; y < h; y++) - { - int sy0 = y * 2; - int sy1 = MIN((y + 1) * 2, srch - 1); - - uint32_t src00 = src[sy0 + sx0 * srch]; - uint32_t src01 = src[sy1 + sx0 * srch]; - uint32_t src10 = src[sy0 + sx1 * srch]; - uint32_t src11 = src[sy1 + sx1 * srch]; + FreeSpans (Spandata[i]); + Spandata[i] = nullptr; + } + } +} - uint32_t alpha = (APART(src00) + APART(src01) + APART(src10) + APART(src11) + 2) / 4; - uint32_t red = (RPART(src00) + RPART(src01) + RPART(src10) + RPART(src11) + 2) / 4; - uint32_t green = (GPART(src00) + GPART(src01) + GPART(src10) + GPART(src11) + 2) / 4; - uint32_t blue = (BPART(src00) + BPART(src01) + BPART(src10) + BPART(src11) + 2) / 4; +// Note: this function needs to be thread safe +FSoftwareTexture* GetSoftwareTexture(FGameTexture* tex) +{ + FSoftwareTexture* SoftwareTexture = static_cast(tex->GetSoftwareTexture()); + if (!SoftwareTexture) + { + static std::mutex loadmutex; + std::unique_lock lock(loadmutex); - dest[y + x * h] = (alpha << 24) | (red << 16) | (green << 8) | blue; - } + SoftwareTexture = static_cast(tex->GetSoftwareTexture()); + if (!SoftwareTexture) + { + if (tex->isSoftwareCanvas()) SoftwareTexture = new FSWCanvasTexture(tex); + else if (tex->isWarped()) SoftwareTexture = new FWarpTexture(tex, tex->isWarped()); + else SoftwareTexture = new FSoftwareTexture(tex); + tex->SetSoftwareTexture(SoftwareTexture); } - - src = dest; - dest += w * h; } + return SoftwareTexture; } -//========================================================================== -// -// -// -//========================================================================== -void FSoftwareTexture::FreeAllSpans() +CUSTOM_CVAR(Bool, vid_nopalsubstitutions, false, CVAR_ARCHIVE | CVAR_NOINITCALL) { - for(int i = 0; i < 3; i++) + // This is in case the sky texture has been substituted. + R_InitSkyMap(); +} + +// Note: this function needs to be thread safe +FSoftwareTexture* GetPalettedSWTexture(FTextureID texid, bool animate, bool checkcompat, bool allownull) +{ + bool needpal = !vid_nopalsubstitutions && !V_IsTrueColor(); + auto tex = TexMan.GetPalettedTexture(texid, true, needpal); + if (tex == nullptr || (!allownull && !tex->isValid())) return nullptr; + if (checkcompat) { - if (Spandata[i] != nullptr) - { - FreeSpans (Spandata[i]); - Spandata[i] = nullptr; - } + auto rawtexid = TexMan.GetRawTexture(tex->GetID()); + auto rawtex = TexMan.GetGameTexture(rawtexid); + if (rawtex) tex = rawtex; } + return GetSoftwareTexture(tex); } diff --git a/src/rendering/swrenderer/textures/r_swtexture.h b/src/rendering/swrenderer/textures/r_swtexture.h index d01ee6f02a9..54597d0c6de 100644 --- a/src/rendering/swrenderer/textures/r_swtexture.h +++ b/src/rendering/swrenderer/textures/r_swtexture.h @@ -1,7 +1,8 @@ #pragma once -#include "textures/textures.h" +#include "textures.h" #include "v_video.h" #include "g_levellocals.h" +#include "d_main.h" struct FSoftwareTextureSpan @@ -12,14 +13,20 @@ struct FSoftwareTextureSpan // For now this is just a minimal wrapper around FTexture. Once the software renderer no longer accesses FTexture directly, it is time for cleaning up. -class FSoftwareTexture +class FSoftwareTexture : public ISoftwareTexture { protected: - FTexture *mTexture; + FGameTexture *mTexture; FTexture *mSource; TArray Pixels; TArray PixelsBgra; + struct + { + const void* Pixels = nullptr; + int LastUpdate = -1; + } Unlockeddata[3]; FSoftwareTextureSpan **Spandata[3] = { }; + DVector2 Scale; uint8_t WidthBits = 0, HeightBits = 0; uint16_t WidthMask = 0; int mPhysicalWidth, mPhysicalHeight; @@ -32,14 +39,14 @@ class FSoftwareTexture void CalcBitSize(); public: - FSoftwareTexture(FTexture *tex); + FSoftwareTexture(FGameTexture *tex); virtual ~FSoftwareTexture() { FreeAllSpans(); } - FTexture *GetTexture() const + FGameTexture *GetTexture() const { return mTexture; } @@ -47,34 +54,32 @@ class FSoftwareTexture // The feature from hell... :( bool useWorldPanning(FLevelLocals *Level) const { - return mTexture->bWorldPanning || (Level->flags3 & LEVEL3_FORCEWORLDPANNING); + return mTexture->useWorldPanning() || (Level->flags3 & LEVEL3_FORCEWORLDPANNING); } bool isMasked() { - return mTexture->bMasked; + return mTexture->isMasked(); + } + + uint16_t GetRotations() const + { + return mTexture->GetRotations(); } int GetSkyOffset() const { return mTexture->GetSkyOffset(); } - PalEntry GetSkyCapColor(bool bottom) const { return mTexture->GetSkyCapColor(bottom); } - int GetWidth () { return mTexture->GetWidth(); } - int GetHeight () { return mTexture->GetHeight(); } + int GetWidth () { return mTexture->GetTexelWidth(); } + int GetHeight () { return mTexture->GetTexelHeight(); } int GetWidthBits() { return WidthBits; } int GetHeightBits() { return HeightBits; } - int GetScaledWidth () { return mTexture->GetScaledWidth(); } - int GetScaledHeight () { return mTexture->GetScaledHeight(); } - double GetScaledWidthDouble () { return mTexture->GetScaledWidthDouble(); } - double GetScaledHeightDouble () { return mTexture->GetScaledHeightDouble(); } - + double GetScaledWidth () { return mTexture->GetDisplayWidth(); } + double GetScaledHeight () { return mTexture->GetDisplayHeight(); } + // Now with improved offset adjustment. - int GetLeftOffset(int adjusted) { return mTexture->GetLeftOffset(adjusted); } - int GetTopOffset(int adjusted) { return mTexture->GetTopOffset(adjusted); } - int GetScaledLeftOffset (int adjusted) { return mTexture->GetScaledLeftOffset(adjusted); } - int GetScaledTopOffset (int adjusted) { return mTexture->GetScaledTopOffset(adjusted); } - double GetScaledLeftOffsetDouble(int adjusted) { return mTexture->GetScaledLeftOffsetDouble(adjusted); } - double GetScaledTopOffsetDouble(int adjusted) { return mTexture->GetScaledTopOffsetDouble(adjusted); } + int GetLeftOffset(int adjusted) { return mTexture->GetTexelLeftOffset(adjusted); } + int GetTopOffset(int adjusted) { return mTexture->GetTexelTopOffset(adjusted); } // Interfaces for the different renderers. Everything that needs to check renderer-dependent offsets // should use these, so that if changes are needed, this is the only place to edit. @@ -82,16 +87,10 @@ class FSoftwareTexture // For the original software renderer int GetLeftOffsetSW() { return GetLeftOffset(r_spriteadjustSW); } int GetTopOffsetSW() { return GetTopOffset(r_spriteadjustSW); } - int GetScaledLeftOffsetSW() { return GetScaledLeftOffset(r_spriteadjustSW); } - int GetScaledTopOffsetSW() { return GetScaledTopOffset(r_spriteadjustSW); } + double GetScaledLeftOffsetSW() { return mTexture->GetDisplayLeftOffset(r_spriteadjustSW); } + double GetScaledTopOffsetSW() { return mTexture->GetDisplayTopOffset(r_spriteadjustSW); } - // For the softpoly renderer, in case it wants adjustment - int GetLeftOffsetPo() { return GetLeftOffset(r_spriteadjustSW); } - int GetTopOffsetPo() { return GetTopOffset(r_spriteadjustSW); } - int GetScaledLeftOffsetPo() { return GetScaledLeftOffset(r_spriteadjustSW); } - int GetScaledTopOffsetPo() { return GetScaledTopOffset(r_spriteadjustSW); } - - DVector2 GetScale() const { return mTexture->Scale; } + DVector2 GetScale() const { return Scale; } int GetPhysicalWidth() { return mPhysicalWidth; } int GetPhysicalHeight() { return mPhysicalHeight; } int GetPhysicalScale() const { return mPhysicalScale; } @@ -100,6 +99,7 @@ class FSoftwareTexture { Pixels.Reset(); PixelsBgra.Reset(); + for (auto& d : Unlockeddata) d = {}; } // Returns true if the next call to GetPixels() will return an image different from the @@ -110,23 +110,75 @@ class FSoftwareTexture void GenerateBgraFromBitmap(const FBitmap &bitmap); void CreatePixelsBgraWithMipmaps(); void GenerateBgraMipmaps(); - void GenerateBgraMipmapsFast(); int MipmapLevels(); // Returns true if GetPixelsBgra includes mipmaps virtual bool Mipmapped() { return true; } // Returns a single column of the texture - virtual const uint8_t *GetColumn(int style, unsigned int column, const FSoftwareTextureSpan **spans_out); + const uint8_t* GetColumn(int style, unsigned int column, const FSoftwareTextureSpan** spans_out) + { + column = WrapColumn(column); + const uint8_t* pixels = GetPixels(style); + if (spans_out) + *spans_out = Spandata[style][column]; + return pixels + column * GetPhysicalHeight(); + } // Returns a single column of the texture, in BGRA8 format - virtual const uint32_t *GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out); + const uint32_t* GetColumnBgra(unsigned int column, const FSoftwareTextureSpan** spans_out) + { + column = WrapColumn(column); + const uint32_t* pixels = GetPixelsBgra(); + if (spans_out) + *spans_out = Spandata[2][column]; + return pixels + column * GetPhysicalHeight(); + } + + unsigned int WrapColumn(unsigned int column) + { + if ((unsigned)column >= (unsigned)GetPhysicalWidth()) + { + if (WidthMask + 1 == GetPhysicalWidth()) + { + column &= WidthMask; + } + else + { + column %= GetPhysicalWidth(); + } + } + return column; + } // Returns the whole texture, stored in column-major order, in BGRA8 format - virtual const uint32_t *GetPixelsBgra(); + const uint32_t* GetPixelsBgra() + { + int style = 2; + if (Unlockeddata[2].LastUpdate == CurrentUpdate) + { + return static_cast(Unlockeddata[style].Pixels); + } + else + { + UpdatePixels(style); + return static_cast(Unlockeddata[style].Pixels); + } + } // Returns the whole texture, stored in column-major order - virtual const uint8_t *GetPixels(int style); + const uint8_t* GetPixels(int style) + { + if (Unlockeddata[style].LastUpdate == CurrentUpdate) + { + return static_cast(Unlockeddata[style].Pixels); + } + else + { + UpdatePixels(style); + return static_cast(Unlockeddata[style].Pixels); + } + } const uint8_t *GetPixels(FRenderStyle style) { @@ -146,6 +198,11 @@ class FSoftwareTexture return GetColumn(alpha, column, spans_out); } + static int CurrentUpdate; + void UpdatePixels(int style); + + virtual const uint32_t* GetPixelsBgraLocked(); + virtual const uint8_t* GetPixelsLocked(int style); }; // A texture that returns a wiggly version of another texture. @@ -159,10 +216,10 @@ class FWarpTexture : public FSoftwareTexture int WidthOffsetMultiplier, HeightOffsetMultiplier; // [mxd] public: - FWarpTexture (FTexture *source, int warptype); + FWarpTexture (FGameTexture *source, int warptype); - const uint32_t *GetPixelsBgra() override; - const uint8_t *GetPixels(int style) override; + const uint32_t *GetPixelsBgraLocked() override; + const uint8_t *GetPixelsLocked(int style) override; bool CheckModified (int which) override; void GenerateBgraMipmapsFast(); @@ -182,12 +239,12 @@ class FSWCanvasTexture : public FSoftwareTexture public: - FSWCanvasTexture(FTexture *source) : FSoftwareTexture(source) {} + FSWCanvasTexture(FGameTexture* source); ~FSWCanvasTexture(); // Returns the whole texture, stored in column-major order - const uint32_t *GetPixelsBgra() override; - const uint8_t *GetPixels(int style) override; + const uint32_t *GetPixelsBgraLocked() override; + const uint8_t *GetPixelsLocked(int style) override; virtual void Unload() override; void UpdatePixels(bool truecolor); @@ -197,3 +254,6 @@ class FSWCanvasTexture : public FSoftwareTexture bool Mipmapped() override { return false; } }; + +FSoftwareTexture* GetSoftwareTexture(FGameTexture* tex); +FSoftwareTexture* GetPalettedSWTexture(FTextureID texid, bool animate, bool checkcompat = false, bool allownull = false); diff --git a/src/rendering/swrenderer/textures/swcanvastexture.cpp b/src/rendering/swrenderer/textures/swcanvastexture.cpp index c3d12e33ee1..91385fe0cd0 100644 --- a/src/rendering/swrenderer/textures/swcanvastexture.cpp +++ b/src/rendering/swrenderer/textures/swcanvastexture.cpp @@ -39,6 +39,21 @@ #include "m_alloc.h" #include "imagehelpers.h" +static TMap canvasMap; + +FSWCanvasTexture* GetSWCamTex(FCanvasTexture* camtex) +{ + auto p = canvasMap.CheckKey(camtex); + return p ? *p : nullptr; +} + +FSWCanvasTexture::FSWCanvasTexture(FGameTexture* source) : FSoftwareTexture(source) +{ + // The SW renderer needs to link the canvas textures, but let's do that outside the texture manager. + auto camtex = static_cast(source->GetTexture()); + canvasMap.Insert(camtex, this); +} + FSWCanvasTexture::~FSWCanvasTexture() { @@ -62,9 +77,9 @@ FSWCanvasTexture::~FSWCanvasTexture() // //========================================================================== -const uint8_t *FSWCanvasTexture::GetPixels(int style) +const uint8_t *FSWCanvasTexture::GetPixelsLocked(int style) { - static_cast(mTexture)->NeedUpdate(); + static_cast(mSource)->NeedUpdate(); if (Canvas == nullptr) { MakeTexture(); @@ -79,9 +94,9 @@ const uint8_t *FSWCanvasTexture::GetPixels(int style) // //========================================================================== -const uint32_t *FSWCanvasTexture::GetPixelsBgra() +const uint32_t *FSWCanvasTexture::GetPixelsBgraLocked() { - static_cast(mTexture)->NeedUpdate(); + static_cast(mSource)->NeedUpdate(); if (CanvasBgra == nullptr) { MakeTextureBgra(); @@ -181,5 +196,5 @@ void FSWCanvasTexture::UpdatePixels(bool truecolor) ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), Canvas->GetPixels(), GetWidth(), GetHeight(), Canvas->GetPitch(), GPalette.Remap); } - static_cast(mTexture)->SetUpdated(false); + static_cast(mSource)->SetUpdated(false); } \ No newline at end of file diff --git a/src/rendering/swrenderer/textures/warpbuffer.h b/src/rendering/swrenderer/textures/warpbuffer.h index 62b0db13db8..bbff5d9e725 100644 --- a/src/rendering/swrenderer/textures/warpbuffer.h +++ b/src/rendering/swrenderer/textures/warpbuffer.h @@ -31,8 +31,10 @@ **--------------------------------------------------------------------------- ** */ +#pragma once -#include "textures/textures.h" +#include "textures.h" +#include "texturemanager.h" template void WarpBuffer(TYPE *Pixels, const TYPE *source, int width, int height, int xmul, int ymul, uint64_t time, float Speed, int warptype) @@ -42,7 +44,7 @@ void WarpBuffer(TYPE *Pixels, const TYPE *source, int width, int height, int xmu if (warptype == 1) { - TYPE *buffer = (TYPE *)alloca(sizeof(TYPE) * MAX(width, height)); + TArray buffer(max(width, height), true); // [mxd] Rewrote to fix animation for NPo2 textures unsigned timebase = unsigned(time * Speed * 32 / 28); for (y = height - 1; y >= 0; y--) @@ -62,10 +64,10 @@ void WarpBuffer(TYPE *Pixels, const TYPE *source, int width, int height, int xmu if (yf < 0) yf += height; int yt = yf; const TYPE *sourcep = Pixels + (x + ymask * x); - TYPE *dest = buffer; + TYPE *dest = buffer.data(); for (yt = height; yt; yt--, yf = (yf + 1) % height) *dest++ = sourcep[yf]; - memcpy(Pixels + (x + ymask*x), buffer, height * sizeof(TYPE)); + memcpy(Pixels + (x + ymask*x), buffer.data(), height * sizeof(TYPE)); } } else if (warptype == 2) diff --git a/src/rendering/swrenderer/textures/warptexture.cpp b/src/rendering/swrenderer/textures/warptexture.cpp index 23a15529af3..10e51ddb0bf 100644 --- a/src/rendering/swrenderer/textures/warptexture.cpp +++ b/src/rendering/swrenderer/textures/warptexture.cpp @@ -44,7 +44,7 @@ EXTERN_CVAR(Int, gl_texture_hqresizemult) EXTERN_CVAR(Int, gl_texture_hqresizemode) EXTERN_CVAR(Int, gl_texture_hqresize_targets) -FWarpTexture::FWarpTexture (FTexture *source, int warptype) +FWarpTexture::FWarpTexture (FGameTexture *source, int warptype) : FSoftwareTexture (source) { if (warptype == 2) SetupMultipliers(256, 128); @@ -57,7 +57,7 @@ bool FWarpTexture::CheckModified (int style) return screen->FrameTime != GenTime[style]; } -const uint32_t *FWarpTexture::GetPixelsBgra() +const uint32_t *FWarpTexture::GetPixelsBgraLocked() { uint64_t time = screen->FrameTime; uint64_t resizeMult = gl_texture_hqresizemult; @@ -67,9 +67,9 @@ const uint32_t *FWarpTexture::GetPixelsBgra() if (gl_texture_hqresizemode == 0 || gl_texture_hqresizemult < 1 || !(gl_texture_hqresize_targets & 1)) resizeMult = 1; - auto otherpix = FSoftwareTexture::GetPixelsBgra(); + auto otherpix = FSoftwareTexture::GetPixelsBgraLocked(); WarpedPixelsRgba.Resize(unsigned(GetWidth() * GetHeight() * resizeMult * resizeMult * 4 / 3 + 1)); - WarpBuffer(WarpedPixelsRgba.Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped); + WarpBuffer(WarpedPixelsRgba.Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->GetShaderSpeed(), bWarped); GenerateBgraMipmapsFast(); FreeAllSpans(); GenTime[2] = time; @@ -78,7 +78,7 @@ const uint32_t *FWarpTexture::GetPixelsBgra() } -const uint8_t *FWarpTexture::GetPixels(int index) +const uint8_t *FWarpTexture::GetPixelsLocked(int index) { uint64_t time = screen->FrameTime; uint64_t resizeMult = gl_texture_hqresizemult; @@ -88,9 +88,9 @@ const uint8_t *FWarpTexture::GetPixels(int index) if (gl_texture_hqresizemode == 0 || gl_texture_hqresizemult < 1 || !(gl_texture_hqresize_targets & 1)) resizeMult = 1; - const uint8_t *otherpix = FSoftwareTexture::GetPixels(index); + const uint8_t *otherpix = FSoftwareTexture::GetPixelsLocked(index); WarpedPixels[index].Resize(unsigned(GetWidth() * GetHeight() * resizeMult * resizeMult)); - WarpBuffer(WarpedPixels[index].Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped); + WarpBuffer(WarpedPixels[index].Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->GetShaderSpeed(), bWarped); FreeAllSpans(); GenTime[index] = time; } @@ -126,20 +126,20 @@ void FWarpTexture::GenerateBgraMipmapsFast() int levels = MipmapLevels(); for (int i = 1; i < levels; i++) { - int srcw = MAX(GetPhysicalWidth() >> (i - 1), 1); - int srch = MAX(GetPhysicalHeight() >> (i - 1), 1); - int w = MAX(GetPhysicalWidth() >> i, 1); - int h = MAX(GetPhysicalHeight() >> i, 1); + int srcw = max(GetPhysicalWidth() >> (i - 1), 1); + int srch = max(GetPhysicalHeight() >> (i - 1), 1); + int w = max(GetPhysicalWidth() >> i, 1); + int h = max(GetPhysicalHeight() >> i, 1); for (int x = 0; x < w; x++) { int sx0 = x * 2; - int sx1 = MIN((x + 1) * 2, srcw - 1); + int sx1 = min((x + 1) * 2, srcw - 1); for (int y = 0; y < h; y++) { int sy0 = y * 2; - int sy1 = MIN((y + 1) * 2, srch - 1); + int sy1 = min((y + 1) * 2, srch - 1); uint32_t src00 = src[sy0 + sx0 * srch]; uint32_t src01 = src[sy1 + sx0 * srch]; diff --git a/src/rendering/swrenderer/things/r_decal.cpp b/src/rendering/swrenderer/things/r_decal.cpp index 263b86d3a14..533b8876caf 100644 --- a/src/rendering/swrenderer/things/r_decal.cpp +++ b/src/rendering/swrenderer/things/r_decal.cpp @@ -21,7 +21,7 @@ #include #include -#include "templates.h" + #include "doomdef.h" #include "doomstat.h" @@ -30,7 +30,7 @@ #include "r_sky.h" #include "v_video.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "stats.h" #include "a_sharedglobal.h" #include "d_net.h" @@ -41,6 +41,7 @@ #include "swrenderer/drawers/r_draw.h" #include "v_palette.h" #include "r_data/colormaps.h" +#include "texturemanager.h" #include "swrenderer/line/r_wallsetup.h" #include "swrenderer/line/r_walldraw.h" #include "swrenderer/segments/r_drawsegment.h" @@ -50,7 +51,7 @@ #include "swrenderer/things/r_wallsprite.h" #include "swrenderer/viewport/r_viewport.h" #include "swrenderer/viewport/r_spritedrawer.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" namespace swrenderer @@ -122,13 +123,11 @@ namespace swrenderer } } - FTexture *tex = TexMan.GetPalettedTexture(decal->PicNum, true); - - if (tex == NULL || !tex->isValid()) + FSoftwareTexture *WallSpriteTile = GetPalettedSWTexture(decal->PicNum, true); + if (WallSpriteTile == NULL) { return; } - FSoftwareTexture *WallSpriteTile = tex->GetSoftwareTexture(); // Determine left and right edges of sprite. Since this sprite is bound // to a wall, we use the wall's angle instead of the decal's. This is @@ -158,6 +157,8 @@ namespace swrenderer if (x1 >= clipper->x2 || x2 <= clipper->x1) return; + int tier = side_t::mid; + if (drawsegPass) { uint32_t clipMode = decal->RenderFlags & RF_CLIPMASK; @@ -204,6 +205,7 @@ namespace swrenderer break; case RF_CLIPUPPER: + tier = side_t::top; mceilingclip = walltop; mfloorclip = thread->OpaquePass->ceilingclip; break; @@ -212,6 +214,7 @@ namespace swrenderer return; case RF_CLIPLOWER: + tier = side_t::bottom; mceilingclip = thread->OpaquePass->floorclip; mfloorclip = wallbottom; break; @@ -220,7 +223,7 @@ namespace swrenderer // Prepare lighting ProjectedWallLight light; - light.SetColormap(lightsector, curline); + light.SetColormap(lightsector, curline, tier); light.SetLightLeft(thread, WallC); usecolormap = light.GetBaseColormap(); @@ -241,7 +244,6 @@ namespace swrenderer bool visible = drawerargs.SetStyle(thread->Viewport.get(), decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor, cmlight); if (visible) { - thread->PrepareTexture(WallSpriteTile, decal->RenderStyle); drawerargs.DrawMasked(thread, zpos + WallSpriteTile->GetTopOffset(0) * decal->ScaleY, decal->ScaleY, decal->RenderFlags & RF_XFLIP, decal->RenderFlags & RF_YFLIP, WallC, clipper->x1, clipper->x2, light, WallSpriteTile, mfloorclip, mceilingclip, decal->RenderStyle); } diff --git a/src/rendering/swrenderer/things/r_model.cpp b/src/rendering/swrenderer/things/r_model.cpp deleted file mode 100644 index 38356f30d72..00000000000 --- a/src/rendering/swrenderer/things/r_model.cpp +++ /dev/null @@ -1,440 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include -#include "templates.h" -#include "doomdef.h" -#include "sbar.h" -#include "r_data/r_translate.h" -#include "r_model.h" -#include "r_data/r_vanillatrans.h" -#include "actorinlines.h" -#include "i_time.h" -#include "swrenderer/r_memory.h" -#include "swrenderer/r_swcolormaps.h" -#include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/scene/r_light.h" - -namespace swrenderer -{ - void RenderModel::Project(RenderThread *thread, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor) - { - // transform the origin point - double tr_x = x - thread->Viewport->viewpoint.Pos.X; - double tr_y = y - thread->Viewport->viewpoint.Pos.Y; - double tz = tr_x * thread->Viewport->viewpoint.TanCos + tr_y * thread->Viewport->viewpoint.TanSin; - - // thing is behind view plane? - if (tz < MINZ) - return; - - double tx = tr_x * thread->Viewport->viewpoint.Sin - tr_y * thread->Viewport->viewpoint.Cos; - - // Flip for mirrors - if (thread->Portal->MirrorFlags & RF_XFLIP) - { - tx = viewwidth - tx - 1; - } - - // too far off the side? - if (fabs(tx / 64) > fabs(tz)) - return; - - RenderModel *vis = thread->FrameMemory->NewObject(x, y, z, smf, actor, float(1 / tz)); - vis->CurrentPortalUniq = thread->Portal->CurrentPortalUniq; - vis->WorldToClip = thread->Viewport->WorldToClip; - vis->MirrorWorldToClip = !!(thread->Portal->MirrorFlags & RF_XFLIP); - thread->SpriteList->Push(vis); - } - - RenderModel::RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, float idepth) : x(x), y(y), z(z), smf(smf), actor(actor) - { - gpos = { x, y, z }; - this->idepth = idepth; - } - - void RenderModel::Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) - { -#if 0 - SWModelRenderer renderer(thread, clip3DFloor, &WorldToClip, MirrorWorldToClip); - - renderer.sector = actor->Sector; - renderer.RenderStyle = actor->RenderStyle; - renderer.RenderAlpha = (float)actor->Alpha; - if (!renderer.RenderStyle.IsVisible(renderer.RenderAlpha)) - return; - - bool foggy = false; - int actualextralight = foggy ? 0 : thread->Viewport->viewpoint.extralight << 4; - bool fullbrightSprite = ((actor->renderflags & RF_FULLBRIGHT) || (actor->flags5 & MF5_BRIGHT)); - renderer.lightlevel = fullbrightSprite ? 255 : actor->Sector->lightlevel + actualextralight; - renderer.visibility = thread->Light->SpriteGlobVis(foggy); - - renderer.fillcolor = actor->fillcolor; - renderer.Translation = actor->Translation; - - renderer.AddLights(actor); - renderer.RenderModel(x, y, z, smf, actor, r_viewpoint.TicFrac); - PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f); -#endif - } - - ///////////////////////////////////////////////////////////////////////////// - - static bool isBright(DPSprite *psp) - { - if (psp != nullptr && psp->GetState() != nullptr) - { - bool disablefullbright = false; - FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., nullptr); - if (lump.isValid()) - { - FTexture * tex = TexMan.GetTexture(lump, true); - if (tex) disablefullbright = tex->isFullbrightDisabled(); - } - return psp->GetState()->GetFullbright() && !disablefullbright; - } - return false; - } - - void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy) - { -#if 0 - SWModelRenderer renderer(thread, Fake3DTranslucent(), &thread->Viewport->WorldToClip, false); - - AActor *playermo = players[consoleplayer].camera; - auto rs = psp->GetRenderStyle(playermo->RenderStyle, playermo->Alpha); - renderer.sector = playermo->Sector; - renderer.RenderStyle = rs.first; - renderer.RenderAlpha = rs.second; - if (psp->Flags & PSPF_FORCEALPHA) renderer.RenderAlpha = 0.0f; - if (!renderer.RenderStyle.IsVisible(renderer.RenderAlpha)) - return; - - bool foggy = false; - int actualextralight = foggy ? 0 : thread->Viewport->viewpoint.extralight << 4; - bool fullbrightSprite = isBright(psp); - renderer.lightlevel = fullbrightSprite ? 255 : playermo->Sector->lightlevel + actualextralight; - renderer.visibility = thread->Light->SpriteGlobVis(foggy); - - PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff; - ThingColor.a = 255; - - renderer.fillcolor = fullbrightSprite ? ThingColor : ThingColor.Modulate(playermo->Sector->SpecialColors[sector_t::sprites]); - renderer.Translation = 0xffffffff;// playermo->Translation; - - renderer.RenderHUDModel(psp, ofsx, ofsy); - PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f); -#endif - } - - ///////////////////////////////////////////////////////////////////////////// - -#if 0 - SWModelRenderer::SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip) - : Thread(thread), Clip3DFloor(clip3DFloor), WorldToClip(worldToClip), MirrorWorldToClip(mirrorWorldToClip) - { - static PolySWInputAssembly input; - PolyTriangleDrawer::SetInputAssembly(thread->DrawQueue, &input); - } - - void SWModelRenderer::AddLights(AActor *actor) - { - if (r_dynlights && actor) - { - auto &addedLights = Thread->AddedLightsArray; - - addedLights.Clear(); - - float x = (float)actor->X(); - float y = (float)actor->Y(); - float z = (float)actor->Center(); - float actorradius = (float)actor->RenderRadius(); - float radiusSquared = actorradius * actorradius; - - BSPWalkCircle(actor->Level, x, y, radiusSquared, [&](subsector_t *subsector) // Iterate through all subsectors potentially touched by actor - { - FLightNode * node = subsector->section->lighthead; - while (node) // check all lights touching a subsector - { - FDynamicLight *light = node->lightsource; - if (light->ShouldLightActor(actor)) - { - int group = subsector->sector->PortalGroup; - DVector3 pos = light->PosRelative(group); - float radius = (float)(light->GetRadius() + actorradius); - double dx = pos.X - x; - double dy = pos.Y - y; - double dz = pos.Z - z; - double distSquared = dx * dx + dy * dy + dz * dz; - if (distSquared < radius * radius) // Light and actor touches - { - if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector - { - addedLights.Push(light); - } - } - } - node = node->nextLight; - } - }); - - NumLights = addedLights.Size(); - Lights = Thread->FrameMemory->AllocMemory(NumLights); - for (int i = 0; i < NumLights; i++) - { - FDynamicLight *lightsource = addedLights[i]; - - bool is_point_light = lightsource->IsAttenuated(); - - uint32_t red = lightsource->GetRed(); - uint32_t green = lightsource->GetGreen(); - uint32_t blue = lightsource->GetBlue(); - - PolyLight &light = Lights[i]; - light.x = (float)lightsource->X(); - light.y = (float)lightsource->Y(); - light.z = (float)lightsource->Z(); - light.radius = 256.0f / lightsource->GetRadius(); - light.color = (red << 16) | (green << 8) | blue; - if (is_point_light) - light.radius = -light.radius; - } - } - } - - void SWModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) - { - const_cast(objectToWorldMatrix).copy(ObjectToWorld.Matrix); - - ClipTop = {}; - ClipBottom = {}; - if (Clip3DFloor.clipTop || Clip3DFloor.clipBottom) - { - // Convert 3d floor clipping planes from world to object space - - VSMatrix inverseMat; - const_cast(objectToWorldMatrix).inverseMatrix(inverseMat); - Mat4f worldToObject; - inverseMat.copy(worldToObject.Matrix); - - // Note: Y and Z is swapped here - - Vec4f one = worldToObject * Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - Vec4f zero = worldToObject * Vec4f(0.0f, 0.0f, 0.0f, 1.0f); - Vec4f up = { one.X - zero.X, one.Y - zero.Y, one.Z - zero.Z }; - - if (Clip3DFloor.clipTop) - { - Vec4f p = worldToObject * Vec4f(0.0f, Clip3DFloor.sclipTop, 0.0f, 1.0f); - float d = up.X * p.X + up.Y * p.Y + up.Z * p.Z; - ClipTop = { -up.X, -up.Y, -up.Z, d }; - } - - if (Clip3DFloor.clipBottom) - { - Vec4f p = worldToObject * Vec4f(0.0f, Clip3DFloor.sclipBottom, 0.0f, 1.0f); - float d = up.X * p.X + up.Y * p.Y + up.Z * p.Z; - ClipBottom = { up.X, up.Y, up.Z, -d }; - } - } - - SetTransform(); - - if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES)) - PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true); - PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !(mirrored ^ MirrorWorldToClip)); - } - - void SWModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf) - { - if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES)) - PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, false); - PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, true); - } - - IModelVertexBuffer *SWModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe) - { - return new SWModelVertexBuffer(needindex, singleframe); - } - - VSMatrix SWModelRenderer::GetViewToWorldMatrix() - { - // Calculate the WorldToView matrix as it would have looked like without yshearing: - const auto &Viewpoint = Thread->Viewport->viewpoint; - auto Level = Thread->Viewport->Level(); - const auto &Viewwindow = Thread->Viewport->viewwindow; - double radPitch = Viewpoint.Angles.Pitch.Normalized180().Radians(); - double angx = cos(radPitch); - double angy = sin(radPitch) * Level->info->pixelstretch; - double alen = sqrt(angx*angx + angy*angy); - float adjustedPitch = (float)asin(angy / alen); - float adjustedViewAngle = (float)(Viewpoint.Angles.Yaw - 90).Radians(); - float ratio = Viewwindow.WidescreenRatio; - float fovratio = (Viewwindow.WidescreenRatio >= 1.3f) ? 1.333333f : ratio; - float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(Viewpoint.FieldOfView.Radians() / 2) / fovratio)).Degrees); - Mat4f altWorldToView = - Mat4f::Rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) * - Mat4f::Rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) * - Mat4f::Scale(1.0f, Level->info->pixelstretch, 1.0f) * - Mat4f::SwapYZ() * - Mat4f::Translate((float)-Viewpoint.Pos.X, (float)-Viewpoint.Pos.Y, (float)-Viewpoint.Pos.Z); - - Mat4f swapYZ = Mat4f::Null(); - swapYZ.Matrix[0 + 0 * 4] = 1.0f; - swapYZ.Matrix[1 + 2 * 4] = 1.0f; - swapYZ.Matrix[2 + 1 * 4] = 1.0f; - swapYZ.Matrix[3 + 3 * 4] = 1.0f; - - VSMatrix worldToView; - worldToView.loadMatrix((altWorldToView * swapYZ).Matrix); - - VSMatrix objectToWorld; - worldToView.inverseMatrix(objectToWorld); - return objectToWorld; - } - - void SWModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) - { - const_cast(objectToWorldMatrix).copy(ObjectToWorld.Matrix); - ClipTop = {}; - ClipBottom = {}; - SetTransform(); - PolyTriangleDrawer::SetWeaponScene(Thread->DrawQueue, true); - - if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) - PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true); - PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !(mirrored ^ MirrorWorldToClip)); - } - - void SWModelRenderer::EndDrawHUDModel(AActor *actor) - { - PolyTriangleDrawer::SetWeaponScene(Thread->DrawQueue, false); - - if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) - PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, false); - PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, true); - } - - void SWModelRenderer::SetInterpolation(double interpolation) - { - InterpolationFactor = (float)interpolation; - } - - void SWModelRenderer::SetMaterial(FTexture *skin, bool clampNoFilter, int translation) - { - SkinTexture = skin; - } - - void SWModelRenderer::SetTransform() - { - Mat4f swapYZ = Mat4f::Null(); - swapYZ.Matrix[0 + 0 * 4] = 1.0f; - swapYZ.Matrix[1 + 2 * 4] = 1.0f; - swapYZ.Matrix[2 + 1 * 4] = 1.0f; - swapYZ.Matrix[3 + 3 * 4] = 1.0f; - ObjectToWorld = swapYZ * ObjectToWorld; - - PolyTriangleDrawer::SetTransform(Thread->DrawQueue, Thread->FrameMemory->NewObject((*WorldToClip) * ObjectToWorld), Thread->FrameMemory->NewObject(ObjectToWorld)); - } - - void SWModelRenderer::DrawArrays(int start, int count) - { - PolyDrawArgs args; - auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); - args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); - args.SetLights(Lights, NumLights); - args.SetNormal(FVector3(0.0f, 0.0f, 0.0f)); - args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite); - args.SetDepthTest(true); - args.SetWriteDepth(true); - args.SetWriteStencil(false); - args.SetClipPlane(0, PolyClipPlane()); - args.SetClipPlane(1, ClipTop); - args.SetClipPlane(2, ClipBottom); - - PolyTriangleDrawer::PushDrawArgs(Thread->DrawQueue, args); - PolyTriangleDrawer::Draw(Thread->DrawQueue, start, count); - } - - void SWModelRenderer::DrawElements(int numIndices, size_t offset) - { - PolyDrawArgs args; - auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); - args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); - args.SetLights(Lights, NumLights); - args.SetNormal(FVector3(0.0f, 0.0f, 0.0f)); - args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite); - args.SetDepthTest(true); - args.SetWriteDepth(true); - args.SetWriteStencil(false); - args.SetClipPlane(0, PolyClipPlane()); - args.SetClipPlane(1, ClipTop); - args.SetClipPlane(2, ClipBottom); - - PolyTriangleDrawer::PushDrawArgs(Thread->DrawQueue, args); - PolyTriangleDrawer::DrawIndexed(Thread->DrawQueue, static_cast(offset / sizeof(unsigned int)), numIndices); - } - - ///////////////////////////////////////////////////////////////////////////// - - SWModelVertexBuffer::SWModelVertexBuffer(bool needindex, bool singleframe) - { - } - - SWModelVertexBuffer::~SWModelVertexBuffer() - { - } - - FModelVertex *SWModelVertexBuffer::LockVertexBuffer(unsigned int size) - { - mVertexBuffer.Resize(size); - return &mVertexBuffer[0]; - } - - void SWModelVertexBuffer::UnlockVertexBuffer() - { - } - - unsigned int *SWModelVertexBuffer::LockIndexBuffer(unsigned int size) - { - mIndexBuffer.Resize(size); - return &mIndexBuffer[0]; - } - - void SWModelVertexBuffer::UnlockIndexBuffer() - { - } - - void SWModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) - { - SWModelRenderer *swrenderer = (SWModelRenderer *)renderer; - - if (mVertexBuffer.Size() > 0) - PolyTriangleDrawer::SetVertexBuffer(swrenderer->Thread->DrawQueue, &mVertexBuffer[0]); - if (mIndexBuffer.Size() > 0) - PolyTriangleDrawer::SetIndexBuffer(swrenderer->Thread->DrawQueue, &mIndexBuffer[0]); - - PolyTriangleDrawer::SetModelVertexShader(swrenderer->Thread->DrawQueue, frame1, frame2, swrenderer->InterpolationFactor); - } -#endif -} diff --git a/src/rendering/swrenderer/things/r_model.h b/src/rendering/swrenderer/things/r_model.h deleted file mode 100644 index 28fa38f5414..00000000000 --- a/src/rendering/swrenderer/things/r_model.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -** Polygon Doom software renderer -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#pragma once - -#include "polyrenderer/drawers/poly_triangle.h" -#include "matrix.h" -#include "r_data/models/models.h" -#include "swrenderer/r_renderthread.h" -#include "swrenderer/things/r_visiblesprite.h" - -struct PolyLight; - -namespace swrenderer -{ - void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy); - - class RenderModel : public VisibleSprite - { - public: - RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, float idepth); - - static void Project(RenderThread *thread, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor); - - protected: - void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override; - bool IsModel() const override { return true; } - - private: - float x, y, z; - FSpriteModelFrame *smf; - AActor *actor; - VSMatrix WorldToClip; - bool MirrorWorldToClip; - }; - -#if 0 - class SWModelRenderer : public FModelRenderer - { - public: - SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip); - - void AddLights(AActor *actor); - - ModelRendererType GetType() const override { return SWModelRendererType; } - - void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override; - void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override; - IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override; - VSMatrix GetViewToWorldMatrix() override; - void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) override; - void EndDrawHUDModel(AActor *actor) override; - void SetInterpolation(double interpolation) override; - void SetMaterial(FTexture *skin, bool clampNoFilter, int translation) override; - void DrawArrays(int start, int count) override; - void DrawElements(int numIndices, size_t offset) override; - - void SetTransform(); - - RenderThread *Thread = nullptr; - Fake3DTranslucent Clip3DFloor; - - FRenderStyle RenderStyle; - float RenderAlpha; - sector_t *sector; - bool fullbrightSprite; - int lightlevel; - double visibility; - uint32_t fillcolor; - uint32_t Translation; - - Mat4f ObjectToWorld; - PolyClipPlane ClipTop, ClipBottom; - FTexture *SkinTexture = nullptr; - float InterpolationFactor = 0.0; - Mat4f *WorldToClip = nullptr; - bool MirrorWorldToClip = false; - PolyLight *Lights = nullptr; - int NumLights = 0; - }; - - class SWModelVertexBuffer : public IModelVertexBuffer - { - public: - SWModelVertexBuffer(bool needindex, bool singleframe); - ~SWModelVertexBuffer(); - - FModelVertex *LockVertexBuffer(unsigned int size) override; - void UnlockVertexBuffer() override; - - unsigned int *LockIndexBuffer(unsigned int size) override; - void UnlockIndexBuffer() override; - - void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override; - - private: - TArray mVertexBuffer; - TArray mIndexBuffer; - }; -#endif -} diff --git a/src/rendering/swrenderer/things/r_particle.cpp b/src/rendering/swrenderer/things/r_particle.cpp index 0d9755a6533..ccd2fe064c5 100644 --- a/src/rendering/swrenderer/things/r_particle.cpp +++ b/src/rendering/swrenderer/things/r_particle.cpp @@ -23,11 +23,12 @@ #include #include #include "p_lnspec.h" -#include "templates.h" + #include "doomdef.h" #include "m_swap.h" +#include "i_interface.h" -#include "w_wad.h" +#include "filesystem.h" #include "c_console.h" #include "c_cvars.h" #include "c_dispatch.h" @@ -47,7 +48,7 @@ #include "v_palette.h" #include "r_data/r_translate.h" #include "r_data/colormaps.h" -#include "r_data/voxels.h" +#include "voxels.h" #include "p_local.h" #include "p_maputl.h" #include "r_voxel.h" @@ -62,7 +63,7 @@ #include "swrenderer/viewport/r_viewport.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "swrenderer/drawers/r_draw_pal.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); @@ -89,7 +90,7 @@ namespace swrenderer RenderPortal *renderportal = thread->Portal.get(); // [ZZ] Particle not visible through the portal plane - if (renderportal->CurrentPortal && !!P_PointOnLineSide(particle->Pos, renderportal->CurrentPortal->dst)) + if (renderportal->CurrentPortal && !!P_PointOnLineSide(particle->Pos.XY(), renderportal->CurrentPortal->dst)) return; // transform the origin point @@ -120,8 +121,8 @@ namespace swrenderer // calculate edges of the shape double psize = particle->size / 8.0; - x1 = MAX(renderportal->WindowLeft, thread->Viewport->viewwindow.centerx + xs_RoundToInt((tx - psize) * xscale)); - x2 = MIN(renderportal->WindowRight, thread->Viewport->viewwindow.centerx + xs_RoundToInt((tx + psize) * xscale)); + x1 = max(renderportal->WindowLeft, thread->Viewport->viewwindow.centerx + xs_RoundToInt((tx - psize) * xscale)); + x2 = min(renderportal->WindowRight, thread->Viewport->viewwindow.centerx + xs_RoundToInt((tx + psize) * xscale)); if (x1 >= x2) return; @@ -222,7 +223,7 @@ namespace swrenderer vis->floorclip = 0; vis->foggy = foggy; - vis->Light.SetColormap(thread, tz, lightlevel, foggy, map, particle->bright != 0, false, false, false, true); + vis->Light.SetColormap(thread, tz, lightlevel, foggy, map, particle->flags & SPF_FULLBRIGHT, false, false, false, true); thread->SpriteList->Push(vis); } @@ -231,7 +232,6 @@ namespace swrenderer { auto vis = this; - int spacing; uint8_t color = vis->Light.BaseColormap->Maps[vis->startfrac]; int yl = vis->y1; int ycount = vis->y2 - yl + 1; @@ -250,33 +250,18 @@ namespace swrenderer uint32_t alpha = fglevel * 256 / FRACUNIT; auto viewport = thread->Viewport.get(); - - spacing = viewport->RenderTarget->GetPitch(); + auto drawers = thread->Drawers(viewport); uint32_t fracstepx = PARTICLE_TEXTURE_SIZE * FRACUNIT / countbase; uint32_t fracposx = fracstepx / 2; RenderTranslucentPass *translucentPass = thread->TranslucentPass.get(); - if (viewport->RenderTarget->IsBgra()) - { - for (int x = x1; x < (x1 + countbase); x++, fracposx += fracstepx) - { - if (translucentPass->ClipSpriteColumnWithPortals(x, vis)) - continue; - uint32_t *dest = (uint32_t*)viewport->GetDest(x, yl); - thread->DrawQueue->Push(dest, yl, spacing, ycount, fg, alpha, fracposx); - } - } - else + for (int x = x1; x < (x1 + countbase); x++, fracposx += fracstepx) { - for (int x = x1; x < (x1 + countbase); x++, fracposx += fracstepx) - { - if (translucentPass->ClipSpriteColumnWithPortals(x, vis)) - continue; - uint8_t *dest = viewport->GetDest(x, yl); - thread->DrawQueue->Push(dest, yl, spacing, ycount, fg, alpha, fracposx); - } + if (translucentPass->ClipSpriteColumnWithPortals(x, vis)) + continue; + drawers->DrawParticleColumn(x, yl, ycount, fg, alpha, fracposx); } } @@ -301,7 +286,7 @@ namespace swrenderer if (ds->drawsegclip.CurrentPortalUniq == CurrentPortalUniq) { RenderDrawSegment renderer(thread); - renderer.Render(ds, MAX(ds->x1, x1), MIN(ds->x2, x2), clip3DFloor); + renderer.Render(ds, max(ds->x1, x1), min(ds->x2, x2), clip3DFloor); } } } diff --git a/src/rendering/swrenderer/things/r_playersprite.cpp b/src/rendering/swrenderer/things/r_playersprite.cpp index d12495bbd22..4e81554d32d 100644 --- a/src/rendering/swrenderer/things/r_playersprite.cpp +++ b/src/rendering/swrenderer/things/r_playersprite.cpp @@ -23,11 +23,11 @@ #include #include #include "p_lnspec.h" -#include "templates.h" + #include "doomdef.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "swrenderer/things/r_playersprite.h" #include "c_console.h" #include "c_cvars.h" @@ -52,19 +52,21 @@ #include "v_palette.h" #include "r_data/r_translate.h" #include "r_data/colormaps.h" -#include "r_data/voxels.h" +#include "voxels.h" #include "p_local.h" #include "p_maputl.h" #include "r_voxel.h" +#include "texturemanager.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/scene/r_portal.h" #include "swrenderer/scene/r_scene.h" #include "swrenderer/scene/r_light.h" #include "swrenderer/things/r_sprite.h" #include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" #include "g_levellocals.h" +#include "v_draw.h" EXTERN_CVAR(Bool, r_drawplayersprites) EXTERN_CVAR(Bool, r_deathcamera) @@ -95,8 +97,6 @@ namespace swrenderer (r_deathcamera && Thread->Viewport->viewpoint.camera->health <= 0)) return; - renderHUDModel = r_modelscene && IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player); - FDynamicColormap *basecolormap; CameraLight *cameraLight = CameraLight::Instance(); auto nc = !!(Thread->Viewport->Level()->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); @@ -207,7 +207,7 @@ namespace swrenderer spriteframe_t* sprframe; FTextureID picnum; uint16_t flip; - FTexture* tex; + FGameTexture* tex; bool noaccel; double alpha = owner->Alpha; @@ -227,7 +227,7 @@ namespace swrenderer picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; - tex = TexMan.GetTexture(picnum); + tex = TexMan.GetGameTexture(picnum); if (!tex->isValid()) return; @@ -254,19 +254,14 @@ namespace swrenderer sy += wy; } - if (renderHUDModel) - { - RenderHUDModel(Thread, pspr, (float)sx, (float)sy); - return; - } - auto viewport = Thread->Viewport.get(); double pspritexscale = viewport->viewwindow.centerxwide / 160.0; - double pspriteyscale = pspritexscale * viewport->BaseYaspectMul * ((double)SCREENHEIGHT / SCREENWIDTH) * r_viewwindow.WidescreenRatio; + double pspriteyscale = pspritexscale * pspr->baseScale.Y * ((double)SCREENHEIGHT / SCREENWIDTH) * r_viewwindow.WidescreenRatio; + pspritexscale *= pspr->baseScale.X; // [XA] don't accidentally apply this to the Y calculation above; math be weird double pspritexiscale = 1 / pspritexscale; - int tleft = tex->GetDisplayLeftOffset(); + int tleft = tex->GetDisplayLeftOffset(0); int twidth = tex->GetDisplayWidth(); // calculate edges of the shape @@ -289,8 +284,9 @@ namespace swrenderer vis.renderflags = owner->renderflags; - FSoftwareTexture *stex = tex->GetSoftwareTexture(); - vis.texturemid = (BASEYCENTER - sy) * stex->GetScale().Y + stex->GetTopOffset(0); + FSoftwareTexture* stex = GetSoftwareTexture(tex); + double textureadj = (120.0f / pspr->baseScale.Y) - BASEYCENTER; // [XA] scale relative to weapon baseline + vis.texturemid = (BASEYCENTER - sy - textureadj) * stex->GetScale().Y + stex->GetTopOffset(0); // Force it to use software rendering when drawing to a canvas texture. bool renderToCanvas = viewport->RenderingToCanvas; @@ -311,6 +307,10 @@ namespace swrenderer vis.yscale = float(pspriteyscale / stex->GetScale().Y); vis.pic = stex; + auto itrans = pspr->GetTranslation(); + if ((pspr->Flags & PSPF_PLAYERTRANSLATED)) itrans = owner->Translation; + vis.Translation = itrans; + // If flip is used, provided that it's not already flipped (that would just invert itself) // (It's an XOR...) if (!(flip) != !(pspr->Flags & PSPF_FLIP)) @@ -377,7 +377,7 @@ namespace swrenderer if (visstyle.Invert) { - vis.Light.BaseColormap = &SpecialSWColormaps[INVERSECOLORMAP]; + vis.Light.BaseColormap = &SpecialSWColormaps[REALINVERSECOLORMAP]; vis.Light.ColormapNum = 0; noaccel = true; } @@ -432,6 +432,8 @@ namespace swrenderer accelSprite.x1 = x1; accelSprite.flip = vis.xiscale < 0; + accelSprite.Translation = itrans; + if (vis.Light.BaseColormap >= &SpecialSWColormaps[0] && vis.Light.BaseColormap < &SpecialSWColormaps[SpecialColormaps.Size()]) { @@ -461,12 +463,12 @@ namespace swrenderer { for (const HWAccelPlayerSprite &sprite : AcceleratedSprites) { - screen->DrawTexture(sprite.pic->GetTexture(), + DrawTexture(twod, sprite.pic->GetTexture(), viewwindowx + sprite.x1, viewwindowy + viewheight / 2 - sprite.texturemid * sprite.yscale - 0.5, DTA_DestWidthF, FIXED2DBL(sprite.pic->GetWidth() * sprite.xscale), DTA_DestHeightF, sprite.pic->GetHeight() * sprite.yscale, - DTA_TranslationIndex, sprite.Translation, + DTA_TranslationIndex, sprite.Translation.index(), DTA_FlipX, sprite.flip, DTA_TopOffset, 0, DTA_LeftOffset, 0, diff --git a/src/rendering/swrenderer/things/r_playersprite.h b/src/rendering/swrenderer/things/r_playersprite.h index 494e693f2cd..23408d6afc8 100644 --- a/src/rendering/swrenderer/things/r_playersprite.h +++ b/src/rendering/swrenderer/things/r_playersprite.h @@ -23,6 +23,7 @@ #include "r_visiblesprite.h" #include "r_data/colormaps.h" +#include "palettecontainer.h" class DPSprite; @@ -46,7 +47,7 @@ namespace swrenderer float Alpha = 0.0f; FRenderStyle RenderStyle; - uint32_t Translation = 0; + FTranslationID Translation = NO_TRANSLATION; uint32_t FillColor = 0; ColormapLight Light; @@ -66,7 +67,7 @@ namespace swrenderer float Alpha = 0.0f; FRenderStyle RenderStyle; - uint32_t Translation = 0; + FTranslationID Translation = NO_TRANSLATION; // this gets passed to the 2D code which works with high level IDs. uint32_t FillColor = 0; FDynamicColormap *basecolormap = nullptr; @@ -92,11 +93,10 @@ namespace swrenderer private: void RenderSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int lightlevel, FDynamicColormap *basecolormap, bool foggy); - enum { BASEXCENTER = 160 }; - enum { BASEYCENTER = 100 }; + static constexpr int BASEXCENTER = 160; + static constexpr int BASEYCENTER = 100; TArray AcceleratedSprites; sector_t tempsec; - bool renderHUDModel = false; }; } diff --git a/src/rendering/swrenderer/things/r_sprite.cpp b/src/rendering/swrenderer/things/r_sprite.cpp index dca8dcff394..b05a6744801 100644 --- a/src/rendering/swrenderer/things/r_sprite.cpp +++ b/src/rendering/swrenderer/things/r_sprite.cpp @@ -23,11 +23,11 @@ #include #include #include "p_lnspec.h" -#include "templates.h" + #include "doomdef.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "swrenderer/things/r_wallsprite.h" #include "c_console.h" #include "c_cvars.h" @@ -53,7 +53,7 @@ #include "v_palette.h" #include "r_data/r_translate.h" #include "r_data/colormaps.h" -#include "r_data/voxels.h" +#include "voxels.h" #include "p_local.h" #include "r_voxel.h" #include "swrenderer/segments/r_drawsegment.h" @@ -62,7 +62,7 @@ #include "swrenderer/scene/r_light.h" #include "swrenderer/things/r_sprite.h" #include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" #include "a_dynlight.h" #include "r_data/r_vanillatrans.h" @@ -74,17 +74,18 @@ EXTERN_CVAR(Int, gl_texture_hqresize_targets) namespace swrenderer { - void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ttex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap) + void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap, bool isSpriteShadow) { - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); - auto viewport = thread->Viewport.get(); const double thingxscalemul = spriteScale.X / tex->GetScale().X; // Calculate billboard line for the sprite + double SpriteOffX = (thing) ? -thing->GetSpriteOffset(false) : 0.; DVector2 dir = { viewport->viewpoint.Sin, -viewport->viewpoint.Cos }; - DVector2 pt1 = pos.XY() - viewport->viewpoint.Pos.XY() - dir * (((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->GetLeftOffsetSW() - 1) : tex->GetLeftOffsetSW()) * thingxscalemul); + DVector2 trs = pos.XY() - viewport->viewpoint.Pos.XY(); + trs = { trs.X + SpriteOffX * dir.X, trs.Y + SpriteOffX * dir.Y }; + DVector2 pt1 = trs - dir * (((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->GetLeftOffsetSW() - 1) : tex->GetLeftOffsetSW()) * thingxscalemul); DVector2 pt2 = pt1 + dir * (tex->GetWidth() * thingxscalemul); FWallCoords wallc; @@ -92,8 +93,8 @@ namespace swrenderer return; // [RH] Added scaling - int scaled_to = tex->GetScaledTopOffsetSW(); - int scaled_bo = scaled_to - tex->GetScaledHeight(); + double scaled_to = tex->GetScaledTopOffsetSW(); + double scaled_bo = scaled_to - tex->GetScaledHeight(); double gzt = pos.Z + spriteScale.Y * scaled_to; double gzb = pos.Z + spriteScale.Y * scaled_bo; @@ -194,7 +195,14 @@ namespace swrenderer bool fullbright = !vis->foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); bool fadeToBlack = (vis->RenderStyle.Flags & STYLEF_FadeToBlack) != 0; - + + if (isSpriteShadow) + { + vis->RenderStyle = LegacyRenderStyles[STYLE_TranslucentStencil]; + vis->FillColor = 0; + vis->Alpha *= 0.5; + } + if (r_dynlights && gl_light_sprites) { float lit_red = 0; @@ -261,8 +269,7 @@ namespace swrenderer { RenderTranslucentPass *translucentPass = thread->TranslucentPass.get(); short portalfloorclip[MAXWIDTH]; - int x2 = wallc.sx2; - for (int x = wallc.sx1; x < x2; x++) + for (int x = x1; x < x2; x++) { if (translucentPass->ClipSpriteColumnWithPortals(x, this)) portalfloorclip[x] = mceilingclip[x]; @@ -270,12 +277,9 @@ namespace swrenderer portalfloorclip[x] = mfloorclip[x]; } - thread->PrepareTexture(pic, RenderStyle); - ProjectedWallLight mlight; mlight.SetSpriteLight(); - drawerargs.SetBaseColormap(Light.BaseColormap); drawerargs.DrawMasked(thread, gzt - floorclip, SpriteScale, renderflags & RF_XFLIP, renderflags & RF_YFLIP, wallc, x1, x2, mlight, pic, portalfloorclip, mceilingclip, RenderStyle); } } diff --git a/src/rendering/swrenderer/things/r_sprite.h b/src/rendering/swrenderer/things/r_sprite.h index 0e7d97bcbc5..8f08df086b0 100644 --- a/src/rendering/swrenderer/things/r_sprite.h +++ b/src/rendering/swrenderer/things/r_sprite.h @@ -7,7 +7,7 @@ namespace swrenderer class RenderSprite : public VisibleSprite { public: - static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap); + static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap, bool isSpriteShadow = false); protected: void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override; @@ -16,7 +16,7 @@ namespace swrenderer FWallCoords wallc; double SpriteScale; - uint32_t Translation = 0; + FTranslationID Translation = NO_TRANSLATION; uint32_t FillColor = 0; uint32_t dynlightcolor = 0; diff --git a/src/rendering/swrenderer/things/r_visiblesprite.cpp b/src/rendering/swrenderer/things/r_visiblesprite.cpp index 53596f7c77a..a91b851a45d 100644 --- a/src/rendering/swrenderer/things/r_visiblesprite.cpp +++ b/src/rendering/swrenderer/things/r_visiblesprite.cpp @@ -23,11 +23,11 @@ #include #include #include "p_lnspec.h" -#include "templates.h" + #include "doomdef.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "g_levellocals.h" #include "p_maputl.h" #include "swrenderer/things/r_visiblesprite.h" @@ -42,7 +42,7 @@ #include "swrenderer/scene/r_portal.h" #include "swrenderer/scene/r_light.h" #include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); @@ -61,8 +61,8 @@ namespace swrenderer DrawSegment *ds = segmentlist->TranslucentSegment(index); if (ds->drawsegclip.SubsectorDepth >= SubsectorDepth && ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq) { - int r1 = MAX(ds->x1, 0); - int r2 = MIN(ds->x2, viewwidth - 1); + int r1 = max(ds->x1, 0); + int r2 = min(ds->x2, viewwidth - 1); RenderDrawSegment renderer(thread); renderer.Render(ds, r1, r2, clip3DFloor); @@ -193,57 +193,56 @@ namespace swrenderer { // only things in specially marked sectors if (spr->FakeFlatStat != WaterFakeSide::AboveCeiling) { - double hz = spr->heightsec->floorplane.ZatPoint(spr->gpos); + double hz = spr->heightsec->floorplane.ZatPoint(spr->gpos.XY()); int h = xs_RoundToInt(viewport->CenterY - (hz - viewport->viewpoint.Pos.Z) * scale); if (spr->FakeFlatStat == WaterFakeSide::BelowFloor) { // seen below floor: clip top if (!spr->IsVoxel() && h > topclip) { - topclip = short(MIN(h, viewheight)); + topclip = short(min(h, viewheight)); } - hzt = MIN(hzt, hz); + hzt = min(hzt, hz); } else { // seen in the middle: clip bottom if (!spr->IsVoxel() && h < botclip) { - botclip = MAX(0, h); + botclip = max(0, h); } - hzb = MAX(hzb, hz); + hzb = max(hzb, hz); } } if (spr->FakeFlatStat != WaterFakeSide::BelowFloor && !(spr->heightsec->MoreFlags & SECMF_FAKEFLOORONLY)) { - double hz = spr->heightsec->ceilingplane.ZatPoint(spr->gpos); + double hz = spr->heightsec->ceilingplane.ZatPoint(spr->gpos.XY()); int h = xs_RoundToInt(viewport->CenterY - (hz - viewport->viewpoint.Pos.Z) * scale); if (spr->FakeFlatStat == WaterFakeSide::AboveCeiling) { // seen above ceiling: clip bottom if (!spr->IsVoxel() && h < botclip) { - botclip = MAX(0, h); + botclip = max(0, h); } - hzb = MAX(hzb, hz); + hzb = max(hzb, hz); } else { // seen in the middle: clip top if (!spr->IsVoxel() && h > topclip) { - topclip = MIN(h, viewheight); + topclip = min(h, viewheight); } - hzt = MIN(hzt, hz); + hzt = min(hzt, hz); } } } // killough 3/27/98: end special clipping for deep water / fake ceilings else if (!spr->IsVoxel() && spr->floorclip) { // [RH] Move floorclip stuff from R_DrawVisSprite to here - //int clip = ((FLOAT2FIXED(CenterY) - FixedMul (spr->texturemid - (spr->pic->GetHeight() << FRACBITS) + spr->floorclip, spr->yscale)) >> FRACBITS); int clip = xs_RoundToInt(viewport->CenterY - (spr->texturemid - spr->pic->GetHeight() + spr->floorclip) * spr->yscale); if (clip < botclip) { - botclip = MAX(0, clip); + botclip = max(0, clip); } } @@ -263,10 +262,10 @@ namespace swrenderer int h = xs_RoundToInt(viewport->CenterY - (hz - viewport->viewpoint.Pos.Z) * scale); if (h < botclip) { - botclip = MAX(0, h); + botclip = max(0, h); } } - hzb = MAX(hzb, clip3DFloor.sclipBottom); + hzb = max(hzb, clip3DFloor.sclipBottom); } if (clip3DFloor.clipTop) { @@ -284,12 +283,15 @@ namespace swrenderer int h = xs_RoundToInt(viewport->CenterY - (hz - viewport->viewpoint.Pos.Z) * scale); if (h > topclip) { - topclip = short(MIN(h, viewheight)); + topclip = short(min(h, viewheight)); } } - hzt = MIN(hzt, clip3DFloor.sclipTop); + hzt = min(hzt, clip3DFloor.sclipTop); } + // Make sure bottom clipping stays within the view size + botclip = min(botclip, viewheight); + if (topclip >= botclip) { spr->Light.BaseColormap = colormap; @@ -314,24 +316,6 @@ namespace swrenderer DrawSegmentList *segmentlist = thread->DrawSegments.get(); RenderPortal *renderportal = thread->Portal.get(); - // Render draw segments behind sprite - if (r_modelscene) - { - int subsectordepth = spr->SubsectorDepth; - for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) - { - DrawSegment *ds = segmentlist->TranslucentSegment(index); - if (ds->drawsegclip.SubsectorDepth >= subsectordepth && ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq) - { - int r1 = MAX(ds->x1, 0); - int r2 = MIN(ds->x2, viewwidth - 1); - - RenderDrawSegment renderer(thread); - renderer.Render(ds, r1, r2, clip3DFloor); - } - } - } - else { for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) { @@ -342,8 +326,8 @@ namespace swrenderer continue; } - float neardepth = MIN(ds->WallC.sz1, ds->WallC.sz2); - float fardepth = MAX(ds->WallC.sz1, ds->WallC.sz2); + float neardepth = min(ds->WallC.sz1, ds->WallC.sz2); + float fardepth = max(ds->WallC.sz1, ds->WallC.sz2); // Check if sprite is in front of draw seg: if ((!spr->IsWallSprite() && neardepth > spr->depth) || ((spr->IsWallSprite() || fardepth > spr->depth) && @@ -352,8 +336,8 @@ namespace swrenderer { if (ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq) { - int r1 = MAX(ds->x1, x1); - int r2 = MIN(ds->x2, x2); + int r1 = max(ds->x1, x1); + int r2 = min(ds->x2, x2); RenderDrawSegment renderer(thread); renderer.Render(ds, r1, r2, clip3DFloor); @@ -371,8 +355,8 @@ namespace swrenderer if (group.fardepth < spr->depth) { - int r1 = MAX(group.x1, x1); - int r2 = MIN(group.x2, x2); + int r1 = max(group.x1, x1); + int r2 = min(group.x2, x2); // Clip bottom short *clip1 = clipbot + r1; @@ -411,11 +395,11 @@ namespace swrenderer continue; } - int r1 = MAX(ds->x1, x1); - int r2 = MIN(ds->x2, x2); + int r1 = max(ds->x1, x1); + int r2 = min(ds->x2, x2); - float neardepth = MIN(ds->WallC.sz1, ds->WallC.sz2); - float fardepth = MAX(ds->WallC.sz1, ds->WallC.sz2); + float neardepth = min(ds->WallC.sz1, ds->WallC.sz2); + float fardepth = max(ds->WallC.sz1, ds->WallC.sz2); // Check if sprite is in front of draw seg: if ((!spr->IsWallSprite() && neardepth > spr->depth) || ((spr->IsWallSprite() || fardepth > spr->depth) && diff --git a/src/rendering/swrenderer/things/r_visiblespritelist.cpp b/src/rendering/swrenderer/things/r_visiblespritelist.cpp index 95a4dfaca90..fb25bb5eac3 100644 --- a/src/rendering/swrenderer/things/r_visiblespritelist.cpp +++ b/src/rendering/swrenderer/things/r_visiblespritelist.cpp @@ -23,16 +23,16 @@ #include #include #include "p_lnspec.h" -#include "templates.h" + #include "doomdef.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "g_levellocals.h" #include "p_maputl.h" #include "swrenderer/things/r_visiblesprite.h" #include "swrenderer/things/r_visiblespritelist.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" namespace swrenderer { @@ -83,23 +83,6 @@ namespace swrenderer SortedSprites[i] = Sprites[first + count - i - 1]; } - if (r_modelscene) - { - for (unsigned int i = 0; i < count; i++) - { - FVector2 worldPos = SortedSprites[i]->WorldPos().XY(); - SortedSprites[i]->SubsectorDepth = FindSubsectorDepth(thread, { worldPos.X, worldPos.Y }); - } - - std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool - { - if (a->SubsectorDepth != b->SubsectorDepth) - return a->SubsectorDepth < b->SubsectorDepth; - else - return a->SortDist() > b->SortDist(); - }); - } - else { std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool { diff --git a/src/rendering/swrenderer/things/r_voxel.cpp b/src/rendering/swrenderer/things/r_voxel.cpp index 662fd1bc3d9..a75b66e31bf 100644 --- a/src/rendering/swrenderer/things/r_voxel.cpp +++ b/src/rendering/swrenderer/things/r_voxel.cpp @@ -32,19 +32,19 @@ // the GNU General Public License v3.0. #include -#include "templates.h" + #include "doomdef.h" #include "sbar.h" #include "r_data/r_translate.h" #include "r_data/colormaps.h" -#include "r_data/voxels.h" +#include "voxels.h" #include "r_data/sprites.h" #include "d_net.h" #include "po_man.h" #include "r_utility.h" #include "i_time.h" #include "swrenderer/drawers/r_draw.h" -#include "swrenderer/drawers/r_thread.h" +#include "r_thread.h" #include "swrenderer/things/r_visiblesprite.h" #include "swrenderer/things/r_voxel.h" #include "swrenderer/scene/r_portal.h" @@ -53,7 +53,7 @@ #include "swrenderer/scene/r_light.h" #include "swrenderer/viewport/r_viewport.h" #include "swrenderer/viewport/r_spritedrawer.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor) @@ -135,12 +135,12 @@ namespace swrenderer int voxelspin = (thing->flags & MF_DROPPED) ? voxel->DroppedSpin : voxel->PlacedSpin; if (voxelspin != 0) { - DAngle ang = double(screen->FrameTime) * voxelspin / 1000; + DAngle ang = DAngle::fromDeg((screen->FrameTime) * voxelspin / 1000.); vis->Angle -= ang; } vis->pa.vpos = { (float)thread->Viewport->viewpoint.Pos.X, (float)thread->Viewport->viewpoint.Pos.Y, (float)thread->Viewport->viewpoint.Pos.Z }; - vis->pa.vang = FAngle((float)thread->Viewport->viewpoint.Angles.Yaw.Degrees); + vis->pa.vang = FAngle::fromDeg(((float)thread->Viewport->viewpoint.Angles.Yaw.Degrees())); // killough 3/27/98: save sector for special clipping later vis->heightsec = heightsec; @@ -148,6 +148,9 @@ namespace swrenderer vis->depth = (float)tz; vis->gpos = { (float)pos.X, (float)pos.Y, (float)pos.Z }; + vis->gpos.X += (float)voxel->xoffset; + vis->gpos.Y += (float)voxel->yoffset; + vis->gpos.Z += (float)voxel->zoffset; vis->gzb = (float)gzb; // [RH] use gzb, not thing->z vis->gzt = (float)gzt; // killough 3/27/98 vis->deltax = float(pos.X - thread->Viewport->viewpoint.Pos.X); @@ -323,8 +326,8 @@ namespace swrenderer sprsinang = FLOAT2FIXED(-dasprang.Sin()) >> 2; // Select mip level - i = abs(DMulScale6(dasprx - globalposx, cosang, daspry - globalposy, sinang)); - i = DivScale6(i, MIN(daxscale, dayscale)); + i = abs(DMulScale(dasprx - globalposx, cosang, daspry - globalposy, sinang, 6)); + i = DivScale(i, min(daxscale, dayscale), 6); j = xs_Fix<13>::ToFix(viewport->FocalLengthX); for (k = 0; i >= j && k < voxobj->NumMips; ++k) { @@ -338,10 +341,10 @@ namespace swrenderer maxslabz >>= k; daxscale <<= (k + 8); dayscale <<= (k + 8); - dazscale = FixedDiv(dayscale, FLOAT2FIXED(viewport->BaseYaspectMul)); + dazscale = DivScale(dayscale, FLOAT2FIXED(viewport->BaseYaspectMul), 16); daxscale = fixed_t(daxscale / viewport->YaspectMul); daxscale = Scale(daxscale, xdimenscale, viewport->viewwindow.centerxwide << 9); - dayscale = Scale(dayscale, FixedMul(xdimenscale, viewport->viewingrangerecip), viewport->viewwindow.centerxwide << 9); + dayscale = Scale(dayscale, MulScale(xdimenscale, viewport->viewingrangerecip, 16), viewport->viewwindow.centerxwide << 9); daxscalerecip = (1 << 30) / daxscale; dayscalerecip = (1 << 30) / dayscale; @@ -350,38 +353,38 @@ namespace swrenderer fixed_t piv_y = fixed_t(mip->Pivot.Y*256.); fixed_t piv_z = fixed_t(mip->Pivot.Z*256.); - x = FixedMul(globalposx - dasprx, daxscalerecip); - y = FixedMul(globalposy - daspry, daxscalerecip); - backx = (DMulScale10(x, sprcosang, y, sprsinang) + piv_x) >> 8; - backy = (DMulScale10(y, sprcosang, x, -sprsinang) + piv_y) >> 8; + x = MulScale(globalposx - dasprx, daxscalerecip, 16); + y = MulScale(globalposy - daspry, daxscalerecip, 16); + backx = (DMulScale(x, sprcosang, y, sprsinang, 10) + piv_x) >> 8; + backy = (DMulScale(y, sprcosang, x, -sprsinang, 10) + piv_y) >> 8; cbackx = clamp(backx, 0, mip->SizeX - 1); cbacky = clamp(backy, 0, mip->SizeY - 1); - sprcosang = MulScale14(daxscale, sprcosang); - sprsinang = MulScale14(daxscale, sprsinang); + sprcosang = MulScale(daxscale, sprcosang, 14); + sprsinang = MulScale(daxscale, sprsinang, 14); - x = (dasprx - globalposx) - DMulScale18(piv_x, sprcosang, piv_y, -sprsinang); - y = (daspry - globalposy) - DMulScale18(piv_y, sprcosang, piv_x, sprsinang); + x = (dasprx - globalposx) - DMulScale(piv_x, sprcosang, piv_y, -sprsinang, 18); + y = (daspry - globalposy) - DMulScale(piv_y, sprcosang, piv_x, sprsinang, 18); - cosang = FixedMul(cosang, dayscalerecip); - sinang = FixedMul(sinang, dayscalerecip); + cosang = MulScale(cosang, dayscalerecip, 16); + sinang = MulScale(sinang, dayscalerecip, 16); gxstart = y*cosang - x*sinang; gystart = x*cosang + y*sinang; - gxinc = DMulScale10(sprsinang, cosang, sprcosang, -sinang); - gyinc = DMulScale10(sprcosang, cosang, sprsinang, sinang); + gxinc = DMulScale(sprsinang, cosang, sprcosang, -sinang, 10); + gyinc = DMulScale(sprcosang, cosang, sprsinang, sinang, 10); if ((abs(globalposz - dasprz) >> 10) >= abs(dazscale)) return; - x = 0; y = 0; j = MAX(mip->SizeX, mip->SizeY); - fixed_t *ggxinc = (fixed_t *)alloca((j + 1) * sizeof(fixed_t) * 2); - fixed_t *ggyinc = ggxinc + (j + 1); + x = 0; y = 0; j = max(mip->SizeX, mip->SizeY); + TArray ggxinc((j + 1) * 2); + fixed_t *ggyinc = ggxinc.data() + (j + 1); for (i = 0; i <= j; i++) { ggxinc[i] = x; x += gxinc; ggyinc[i] = y; y += gyinc; } - syoff = DivScale21(globalposz - dasprz, FixedMul(dazscale, 0xE800)) + (piv_z << 7); + syoff = DivScale(globalposz - dasprz, MulScale(dazscale, 0xE800, 16), 21) + (piv_z << 7); yoff = (abs(gxinc) + abs(gyinc)) >> 1; bool useSlabDataBgra = !drawerargs.DrawerNeedsPalInput() && viewport->RenderTarget->IsBgra(); @@ -446,12 +449,12 @@ namespace swrenderer uint8_t oand16 = oand + 16; uint8_t oand32 = oand + 32; - if (yi > 0) { dagxinc = gxinc; dagyinc = FixedMul(gyinc, viewport->viewingrangerecip); } - else { dagxinc = -gxinc; dagyinc = -FixedMul(gyinc, viewport->viewingrangerecip); } + if (yi > 0) { dagxinc = gxinc; dagyinc = MulScale(gyinc, viewport->viewingrangerecip, 16); } + else { dagxinc = -gxinc; dagyinc = -MulScale(gyinc, viewport->viewingrangerecip, 16); } /* Fix for non 90 degree viewing ranges */ - nxoff = FixedMul(x2 - x1, viewport->viewingrangerecip); - x1 = FixedMul(x1, viewport->viewingrangerecip); + nxoff = MulScale(x2 - x1, viewport->viewingrangerecip, 16); + x1 = MulScale(x1, viewport->viewingrangerecip, 16); ggxstart = gxstart + ggyinc[ys]; ggystart = gystart - ggxinc[ys]; @@ -462,7 +465,7 @@ namespace swrenderer uint8_t *slabxoffs = &SlabData[mip->OffsetX[x]]; short *xyoffs = &mip->OffsetXY[x * (mip->SizeY + 1)]; - nx = FixedMul(ggxstart + ggxinc[x], viewport->viewingrangerecip) + x1; + nx = MulScale(ggxstart + ggxinc[x], viewport->viewingrangerecip, 16) + x1; ny = ggystart + ggyinc[x]; for (y = ys; y != ye; y += yi, nx += dagyinc, ny -= dagxinc) { @@ -487,8 +490,8 @@ namespace swrenderer if (flags & DVF_FIND_X1X2) { - coverageX1 = MIN(coverageX1, lx); - coverageX2 = MAX(coverageX2, rx); + coverageX1 = min(coverageX1, lx); + coverageX2 = max(coverageX2, rx); continue; } @@ -522,20 +525,20 @@ namespace swrenderer if (k < 0) { if ((voxptr->backfacecull & oand32) == 0) continue; - z2 = MulScale32(l2, k) + viewport->viewwindow.centery; /* Below slab */ + z2 = MulScale(l2, k, 32) + viewport->viewwindow.centery; /* Below slab */ } else { if ((voxptr->backfacecull & oand) == 0) continue; /* Middle of slab */ - z2 = MulScale32(l1, k) + viewport->viewwindow.centery; + z2 = MulScale(l1, k, 32) + viewport->viewwindow.centery; } - z1 = MulScale32(l1, j) + viewport->viewwindow.centery; + z1 = MulScale(l1, j, 32) + viewport->viewwindow.centery; } else { if ((voxptr->backfacecull & oand16) == 0) continue; - z1 = MulScale32(l2, j) + viewport->viewwindow.centery; /* Above slab */ - z2 = MulScale32(l1, j + (zleng << 15)) + viewport->viewwindow.centery; + z1 = MulScale(l2, j, 32) + viewport->viewwindow.centery; /* Above slab */ + z2 = MulScale(l1, j + (zleng << 15), 32) + viewport->viewwindow.centery; } if (z2 <= z1) continue; @@ -546,13 +549,13 @@ namespace swrenderer } else { - if (z2 - z1 >= 1024) yinc = FixedDiv(zleng, z2 - z1); + if (z2 - z1 >= 1024) yinc = DivScale(zleng, z2 - z1, 16); else yinc = (((1 << 24) - 1) / (z2 - z1)) * zleng >> 8; } // [RH] Clip each column separately, not just by the first one. - for (int stripwidth = MIN(countof(z1a), rx - lx), lxt = lx; + for (int stripwidth = min(countof(z1a), rx - lx), lxt = lx; lxt < rx; - (lxt += countof(z1a)), stripwidth = MIN(countof(z1a), rx - lxt)) + (lxt += countof(z1a)), stripwidth = min(countof(z1a), rx - lxt)) { // Calculate top and bottom pixels locations for (int xxx = 0; xxx < stripwidth; ++xxx) @@ -560,7 +563,7 @@ namespace swrenderer if (zleng == 1) { yplc[xxx] = 0; - z1a[xxx] = MAX(z1, daumost[lxt + xxx]); + z1a[xxx] = max(z1, daumost[lxt + xxx]); } else { @@ -575,7 +578,7 @@ namespace swrenderer z1a[xxx] = z1; } } - z2a[xxx] = MIN(z2, dadmost[lxt + xxx]); + z2a[xxx] = min(z2, dadmost[lxt + xxx]); } const uint8_t *columnColors = col; @@ -991,8 +994,8 @@ namespace swrenderer int ztop = slab->ztop; int zbottom = ztop + slab->zleng; - //ztop = MAX(ztop, minZ); - //zbottom = MIN(zbottom, maxZ); + //ztop = max(ztop, minZ); + //zbottom = min(zbottom, maxZ); for (int z = ztop; z < zbottom; z++) { @@ -1023,10 +1026,10 @@ namespace swrenderer DVector3 screenPos = viewport->PointViewToScreen(viewPos); DVector2 screenExtent = viewport->ScaleViewToScreen({ extentX, extentY }, viewPos.Z, pixelstretch); - int x1 = MAX((int)(screenPos.X - screenExtent.X), 0); - int x2 = MIN((int)(screenPos.X + screenExtent.X + 0.5f), viewwidth - 1); - int y1 = MAX((int)(screenPos.Y - screenExtent.Y), 0); - int y2 = MIN((int)(screenPos.Y + screenExtent.Y + 0.5f), viewheight - 1); + int x1 = max((int)(screenPos.X - screenExtent.X), 0); + int x2 = min((int)(screenPos.X + screenExtent.X + 0.5f), viewwidth - 1); + int y1 = max((int)(screenPos.Y - screenExtent.Y), 0); + int y2 = min((int)(screenPos.Y + screenExtent.Y + 0.5f), viewheight - 1); int pixelsize = viewport->RenderTarget->IsBgra() ? 4 : 1; @@ -1034,8 +1037,8 @@ namespace swrenderer { for (int x = x1; x < x2; x++) { - int columnY1 = MAX(y1, (int)cliptop[x]); - int columnY2 = MIN(y2, (int)clipbottom[x]); + int columnY1 = max(y1, (int)cliptop[x]); + int columnY2 = min(y2, (int)clipbottom[x]); if (columnY1 < columnY2) { drawerargs.SetDest(x, columnY1); diff --git a/src/rendering/swrenderer/things/r_voxel.h b/src/rendering/swrenderer/things/r_voxel.h index d9164899b54..24b3dfc3e11 100644 --- a/src/rendering/swrenderer/things/r_voxel.h +++ b/src/rendering/swrenderer/things/r_voxel.h @@ -70,7 +70,7 @@ namespace swrenderer struct posang { FVector3 vpos = { 0.0f, 0.0f, 0.0f }; // view origin - FAngle vang = { 0.0f }; // view angle + FAngle vang = nullFAngle; // view angle }; struct VoxelBlockEntry @@ -80,12 +80,12 @@ namespace swrenderer }; posang pa; - DAngle Angle = { 0.0 }; + DAngle Angle = nullAngle; fixed_t xscale = 0; FVoxel *voxel = nullptr; bool bInMirror = false; - uint32_t Translation = 0; + FTranslationID Translation = NO_TRANSLATION; uint32_t FillColor = 0; enum { DVF_OFFSCREEN = 1, DVF_SPANSONLY = 2, DVF_MIRRORED = 4, DVF_FIND_X1X2 = 8 }; diff --git a/src/rendering/swrenderer/things/r_wallsprite.cpp b/src/rendering/swrenderer/things/r_wallsprite.cpp index b5ee7ba143f..b4dcc9bf239 100644 --- a/src/rendering/swrenderer/things/r_wallsprite.cpp +++ b/src/rendering/swrenderer/things/r_wallsprite.cpp @@ -23,11 +23,11 @@ #include #include #include "p_lnspec.h" -#include "templates.h" + #include "doomdef.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "swrenderer/things/r_wallsprite.h" #include "c_console.h" #include "c_cvars.h" @@ -53,7 +53,7 @@ #include "v_palette.h" #include "r_data/r_translate.h" #include "r_data/colormaps.h" -#include "r_data/voxels.h" +#include "voxels.h" #include "p_local.h" #include "p_maputl.h" #include "r_voxel.h" @@ -64,19 +64,18 @@ #include "swrenderer/line/r_wallsetup.h" #include "swrenderer/line/r_walldraw.h" #include "swrenderer/viewport/r_viewport.h" -#include "swrenderer/r_memory.h" +#include "r_memory.h" #include "swrenderer/r_renderthread.h" namespace swrenderer { - void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ppic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap) + void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *pic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap) { - FSoftwareTexture *pic = ppic->GetSoftwareTexture(); FWallCoords wallc; double x1, x2; DVector2 left, right; double gzb, gzt, tz; - DAngle ang = thing->Angles.Yaw + 90; + DAngle ang = thing->Angles.Yaw + DAngle::fromDeg(90); double angcos = ang.Cos(); double angsin = ang.Sin(); @@ -106,8 +105,8 @@ namespace swrenderer // but right now, I just want to get them drawing. tz = (pos.X - thread->Viewport->viewpoint.Pos.X) * thread->Viewport->viewpoint.TanCos + (pos.Y - thread->Viewport->viewpoint.Pos.Y) * thread->Viewport->viewpoint.TanSin; - int scaled_to = pic->GetScaledTopOffsetSW(); - int scaled_bo = scaled_to - pic->GetScaledHeight(); + double scaled_to = pic->GetScaledTopOffsetSW(); + double scaled_bo = scaled_to - pic->GetScaledHeight(); gzt = pos.Z + scale.Y * scaled_to; gzb = pos.Z + scale.Y * scaled_bo; @@ -160,34 +159,23 @@ namespace swrenderer { auto spr = this; - int x1 = MAX(spr->x1, spr->wallc.sx1); - int x2 = MIN(spr->x2, spr->wallc.sx2); + int x1 = max(spr->x1, spr->wallc.sx1); + int x2 = min(spr->x2, spr->wallc.sx2); if (x1 >= x2) return; - // Prepare lighting - - // Decals that are added to the scene must fade to black. - ColormapLight cmlight; - if (spr->RenderStyle == LegacyRenderStyles[STYLE_Add] && cmlight.BaseColormap->Fade != 0) - { - cmlight.BaseColormap = GetSpecialLights(cmlight.BaseColormap->Color, 0, cmlight.BaseColormap->Desaturate); - } - SpriteDrawerArgs drawerargs; - bool visible = drawerargs.SetStyle(thread->Viewport.get(), spr->RenderStyle, spr->Alpha, spr->Translation, spr->FillColor, cmlight); + bool visible = drawerargs.SetStyle(thread->Viewport.get(), spr->RenderStyle, spr->Alpha, spr->Translation, spr->FillColor, Light); if (!visible) return; ProjectedWallLight mlight; - mlight.SetLightLeft(thread, wallc); + mlight.SetSpriteLight(); // Draw it auto WallSpriteTile = spr->pic; - thread->PrepareTexture(WallSpriteTile, spr->RenderStyle); - RenderTranslucentPass* translucentPass = thread->TranslucentPass.get(); short floorclip[MAXWIDTH]; for (int x = x1; x < x2; x++) diff --git a/src/rendering/swrenderer/things/r_wallsprite.h b/src/rendering/swrenderer/things/r_wallsprite.h index 2851ec2b560..09384b474c3 100644 --- a/src/rendering/swrenderer/things/r_wallsprite.h +++ b/src/rendering/swrenderer/things/r_wallsprite.h @@ -10,7 +10,7 @@ namespace swrenderer class RenderWallSprite : public VisibleSprite { public: - static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *pic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap); + static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *pic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap); protected: bool IsWallSprite() const override { return true; } @@ -18,7 +18,7 @@ namespace swrenderer private: FWallCoords wallc; - uint32_t Translation = 0; + FTranslationID Translation = NO_TRANSLATION; uint32_t FillColor = 0; }; } diff --git a/src/rendering/swrenderer/viewport/r_drawerargs.cpp b/src/rendering/swrenderer/viewport/r_drawerargs.cpp index cf12dc41fbe..9591b4498f0 100644 --- a/src/rendering/swrenderer/viewport/r_drawerargs.cpp +++ b/src/rendering/swrenderer/viewport/r_drawerargs.cpp @@ -81,7 +81,7 @@ namespace swrenderer shadeConstants.fade_green = mBaseColormap->Fade.g; shadeConstants.fade_blue = mBaseColormap->Fade.b; shadeConstants.fade_alpha = mBaseColormap->Fade.a; - shadeConstants.desaturate = MIN(abs(mBaseColormap->Desaturate), 255) * 255 / 256; + shadeConstants.desaturate = min(abs(mBaseColormap->Desaturate), 255) * 255 / 256; shadeConstants.simple_shade = (mBaseColormap->Color.d == 0x00ffffff && mBaseColormap->Fade.d == 0x00000000 && mBaseColormap->Desaturate == 0); } else diff --git a/src/rendering/swrenderer/viewport/r_drawerargs.h b/src/rendering/swrenderer/viewport/r_drawerargs.h index 0cd5d3d20f7..339e00e5541 100644 --- a/src/rendering/swrenderer/viewport/r_drawerargs.h +++ b/src/rendering/swrenderer/viewport/r_drawerargs.h @@ -1,7 +1,7 @@ #pragma once -#include "templates.h" + #include "doomtype.h" #include "doomdef.h" #include "r_defs.h" diff --git a/src/rendering/swrenderer/viewport/r_skydrawer.cpp b/src/rendering/swrenderer/viewport/r_skydrawer.cpp index 0089034987f..87088fead40 100644 --- a/src/rendering/swrenderer/viewport/r_skydrawer.cpp +++ b/src/rendering/swrenderer/viewport/r_skydrawer.cpp @@ -25,11 +25,6 @@ namespace swrenderer { - void SkyDrawerArgs::DrawDepthSkyColumn(RenderThread *thread, float idepth) - { - thread->Drawers(dc_viewport)->DrawDepthSkyColumn(*this, idepth); - } - void SkyDrawerArgs::DrawSingleSkyColumn(RenderThread *thread) { thread->Drawers(dc_viewport)->DrawSingleSkyColumn(*this); diff --git a/src/rendering/swrenderer/viewport/r_spandrawer.cpp b/src/rendering/swrenderer/viewport/r_spandrawer.cpp index 51da4fb4630..59b298cd35c 100644 --- a/src/rendering/swrenderer/viewport/r_spandrawer.cpp +++ b/src/rendering/swrenderer/viewport/r_spandrawer.cpp @@ -32,8 +32,6 @@ namespace swrenderer void SpanDrawerArgs::SetTexture(RenderThread *thread, FSoftwareTexture *tex) { - thread->PrepareTexture(tex, DefaultRenderStyle()); - ds_texwidth = tex->GetPhysicalWidth(); ds_texheight = tex->GetPhysicalHeight(); ds_xbits = tex->GetWidthBits(); @@ -123,11 +121,6 @@ namespace swrenderer } } - void SpanDrawerArgs::DrawDepthSpan(RenderThread *thread, float idepth1, float idepth2) - { - thread->Drawers(ds_viewport)->DrawDepthSpan(*this, idepth1, idepth2); - } - void SpanDrawerArgs::DrawSpan(RenderThread *thread) { (thread->Drawers(ds_viewport)->*spanfunc)(*this); diff --git a/src/rendering/swrenderer/viewport/r_spritedrawer.cpp b/src/rendering/swrenderer/viewport/r_spritedrawer.cpp index 7d3af54ec8f..b40ddd8b4b3 100644 --- a/src/rendering/swrenderer/viewport/r_spritedrawer.cpp +++ b/src/rendering/swrenderer/viewport/r_spritedrawer.cpp @@ -70,11 +70,8 @@ namespace swrenderer iscale = -iscale; float vstepY = iscale / WallC.sz1 / (viewport->InvZtoScale / WallC.sz1); - wpos += wstepX * 0.5f; - upos += ustepX * 0.5f; - - int x1 = MAX(WallC.sx1, clipx1); - int x2 = MIN(WallC.sx2, clipx2); + int x1 = max(WallC.sx1, clipx1); + int x2 = min(WallC.sx2, clipx2); if (x1 >= x2) return; @@ -130,10 +127,10 @@ namespace swrenderer void SpriteDrawerArgs::DrawMasked2D(RenderThread* thread, double x0, double x1, double y0, double y1, FSoftwareTexture* tex, FRenderStyle style) { - int sx0 = MAX((int)x0, 0); - int sx1 = MIN((int)x1, viewwidth); - int sy0 = MAX((int)y0, 0); - int sy1 = MIN((int)y1, viewheight); + int sx0 = max((int)x0, 0); + int sx1 = min((int)x1, viewwidth); + int sy0 = max((int)y0, 0); + int sy1 = min((int)y1, viewheight); if (sx0 >= sx1 || sy0 >= sy1) return; @@ -165,16 +162,16 @@ namespace swrenderer } } - void SpriteDrawerArgs::DrawMaskedColumn(RenderThread* thread, int x, int y1, int cliptop, int clipbottom, uint32_t texelX, uint32_t texelStepX, uint32_t texelStepY, float scaleV, bool flipY, FSoftwareTexture* tex, int texwidth, int texheight, bool bgra, FRenderStyle style) + void SpriteDrawerArgs::DrawMaskedColumn(RenderThread* thread, int x, float y1, int cliptop, int clipbottom, uint32_t texelX, uint32_t texelStepX, uint32_t texelStepY, float scaleV, bool flipY, FSoftwareTexture* tex, int texwidth, int texheight, bool bgra, FRenderStyle style) { const FSoftwareTextureSpan* span; if (bgra) { double xmagnitude = fabs(static_cast(texelStepX)* (1.0 / 0x1'0000'0000LL)); double ymagnitude = fabs(static_cast(texelStepY)* (1.0 / 0x1'0000'0000LL)); - double magnitude = MAX(ymagnitude, xmagnitude); + double magnitude = max(ymagnitude, xmagnitude); double min_lod = -1000.0; - double lod = MAX(log2(magnitude) + r_lod_bias, min_lod); + double lod = max(log2(magnitude) + r_lod_bias, min_lod); bool magnifying = lod < 0.0f; int mipmap_offset = 0; @@ -187,8 +184,8 @@ namespace swrenderer { mipmap_offset += mip_width * mip_height; level--; - mip_width = MAX(mip_width >> 1, 1); - mip_height = MAX(mip_height >> 1, 1); + mip_width = max(mip_width >> 1, 1); + mip_height = max(mip_height >> 1, 1); } } @@ -198,7 +195,7 @@ namespace swrenderer bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter); if (filter_nearest) { - xoffset = MAX(MIN(xoffset, (mip_width << FRACBITS) - 1), 0); + xoffset = max(min(xoffset, (mip_width << FRACBITS) - 1), 0); int tx = xoffset >> FRACBITS; dc_source = (uint8_t*)(pixels + tx * mip_height); @@ -208,10 +205,10 @@ namespace swrenderer } else { - xoffset = MAX(MIN(xoffset - (FRACUNIT / 2), (mip_width << FRACBITS) - 1), 0); + xoffset = max(min(xoffset - (FRACUNIT / 2), (mip_width << FRACBITS) - 1), 0); int tx0 = xoffset >> FRACBITS; - int tx1 = MIN(tx0 + 1, mip_width - 1); + int tx1 = min(tx0 + 1, mip_width - 1); dc_source = (uint8_t*)(pixels + tx0 * mip_height); dc_source2 = (uint8_t*)(pixels + tx1 * mip_height); dc_textureheight = mip_height; @@ -230,14 +227,14 @@ namespace swrenderer const int top = span->TopOffset; // calculate unclipped screen coordinates for post - dc_yl = (int)(y1 + top / scaleV + 0.5f); - dc_yh = (int)(y1 + (top + length) / scaleV + 0.5f); + dc_yl = xs_RoundToInt(y1 + top / scaleV); + dc_yh = xs_RoundToInt(y1 + (top + length) / scaleV); if (flipY) std::swap(dc_yl, dc_yh); - dc_yl = std::max(dc_yl, cliptop); - dc_yh = std::min(dc_yh, clipbottom); + dc_yl = max(dc_yl, cliptop); + dc_yh = min(dc_yh, clipbottom); if (dc_yl <= dc_yh) { @@ -268,14 +265,14 @@ namespace swrenderer const int top = span->TopOffset; // calculate unclipped screen coordinates for post - dc_yl = (int)(y1 + top / scaleV + 0.5f); - dc_yh = (int)(y1 + (top + length) / scaleV + 0.5f); + dc_yl = xs_RoundToInt(y1 + top / scaleV); + dc_yh = xs_RoundToInt(y1 + (top + length) / scaleV); if (flipY) std::swap(dc_yl, dc_yh); - dc_yl = std::max(dc_yl, cliptop); - dc_yh = std::min(dc_yh, clipbottom); + dc_yl = max(dc_yl, cliptop); + dc_yh = min(dc_yh, clipbottom); if (dc_yl < dc_yh) { @@ -285,12 +282,12 @@ namespace swrenderer dc_yl--; fixed_t maxfrac = ((top + length) << FRACBITS) - 1; - dc_texturefrac = MAX(dc_texturefrac, 0); - dc_texturefrac = MIN(dc_texturefrac, maxfrac); + dc_texturefrac = max(dc_texturefrac, 0); + dc_texturefrac = min(dc_texturefrac, maxfrac); if (dc_iscale > 0) - dc_count = MIN(dc_count, (maxfrac - dc_texturefrac + dc_iscale - 1) / dc_iscale); + dc_count = min(dc_count, (maxfrac - dc_texturefrac + dc_iscale - 1) / dc_iscale); else if (dc_iscale < 0) - dc_count = MIN(dc_count, (dc_texturefrac - dc_iscale) / (-dc_iscale)); + dc_count = min(dc_count, (dc_texturefrac - dc_iscale) / (-dc_iscale)); (thread->Drawers(dc_viewport)->*colfunc)(*this); } @@ -435,7 +432,7 @@ namespace swrenderer } } - bool SpriteDrawerArgs::SetStyle(RenderViewport *viewport, FRenderStyle style, fixed_t alpha, int translation, uint32_t color, const ColormapLight &light) + bool SpriteDrawerArgs::SetStyle(RenderViewport *viewport, FRenderStyle style, fixed_t alpha, FTranslationID translation, uint32_t color, const ColormapLight &light) { if (light.BaseColormap) SetLight(light); @@ -469,19 +466,16 @@ namespace swrenderer alpha = clamp(alpha, 0, OPAQUE); } - if (translation != -1) + SetTranslationMap(nullptr); + if (translation != NO_TRANSLATION) { - SetTranslationMap(nullptr); - if (translation != 0) + FRemapTable *table = GPalette.TranslationToTable(translation); + if (table != NULL) { - FRemapTable *table = TranslationToTable(translation); - if (table != NULL && !table->Inactive) - { - if (viewport->RenderTarget->IsBgra()) - SetTranslationMap((uint8_t*)table->Palette); - else - SetTranslationMap(table->Remap); - } + if (viewport->RenderTarget->IsBgra()) + SetTranslationMap((uint8_t*)table->Palette); + else + SetTranslationMap(table->Remap); } } @@ -550,7 +544,7 @@ namespace swrenderer return SpriteDrawerArgs::SetBlendFunc(style.BlendOp, fglevel, bglevel, style.Flags); } - bool SpriteDrawerArgs::SetStyle(RenderViewport *viewport, FRenderStyle style, float alpha, int translation, uint32_t color, const ColormapLight &light) + bool SpriteDrawerArgs::SetStyle(RenderViewport *viewport, FRenderStyle style, float alpha, FTranslationID translation, uint32_t color, const ColormapLight &light) { return SetStyle(viewport, style, FLOAT2FIXED(alpha), translation, color, light); } diff --git a/src/rendering/swrenderer/viewport/r_spritedrawer.h b/src/rendering/swrenderer/viewport/r_spritedrawer.h index f233d2c032a..85d87f3299c 100644 --- a/src/rendering/swrenderer/viewport/r_spritedrawer.h +++ b/src/rendering/swrenderer/viewport/r_spritedrawer.h @@ -28,8 +28,8 @@ namespace swrenderer public: SpriteDrawerArgs(); - bool SetStyle(RenderViewport *viewport, FRenderStyle style, fixed_t alpha, int translation, uint32_t color, const ColormapLight &light); - bool SetStyle(RenderViewport *viewport, FRenderStyle style, float alpha, int translation, uint32_t color, const ColormapLight &light); + bool SetStyle(RenderViewport *viewport, FRenderStyle style, fixed_t alpha, FTranslationID translation, uint32_t color, const ColormapLight &light); + bool SetStyle(RenderViewport *viewport, FRenderStyle style, float alpha, FTranslationID translation, uint32_t color, const ColormapLight &light); void SetSolidColor(int color) { dc_color = color; dc_color_bgra = GPalette.BaseColors[color]; } void SetDynamicLight(uint32_t color) { dynlightcolor = color; } @@ -69,7 +69,7 @@ namespace swrenderer RenderViewport *Viewport() const { return dc_viewport; } private: - void DrawMaskedColumn(RenderThread* thread, int x, int y1, int cliptop, int clipbottom, uint32_t texelX, uint32_t texelStepX, uint32_t texelStepY, float scaleV, bool flipY, FSoftwareTexture* tex, int texwidth, int texheight, bool bgra, FRenderStyle style); + void DrawMaskedColumn(RenderThread* thread, int x, float y1, int cliptop, int clipbottom, uint32_t texelX, uint32_t texelStepX, uint32_t texelStepY, float scaleV, bool flipY, FSoftwareTexture* tex, int texwidth, int texheight, bool bgra, FRenderStyle style); void SetDest(RenderViewport* viewport, int x, int y); void SetCount(int count) { dc_count = count; } @@ -111,7 +111,7 @@ namespace swrenderer RenderViewport *dc_viewport = nullptr; - friend class DrawVoxelBlocksRGBACommand; - friend class DrawVoxelBlocksPalCommand; + friend class SWTruecolorDrawers; + friend class SWPalDrawers; }; } diff --git a/src/rendering/swrenderer/viewport/r_viewport.cpp b/src/rendering/swrenderer/viewport/r_viewport.cpp index 42ef5be7064..5778951c5e9 100644 --- a/src/rendering/swrenderer/viewport/r_viewport.cpp +++ b/src/rendering/swrenderer/viewport/r_viewport.cpp @@ -22,9 +22,9 @@ #include #include -#include "templates.h" -#include "w_wad.h" + +#include "filesystem.h" #include "doomdef.h" #include "doomstat.h" #include "r_sky.h" @@ -43,6 +43,7 @@ #include "swrenderer/plane/r_flatplane.h" #include "swrenderer/drawers/r_draw_pal.h" #include "swrenderer/drawers/r_draw_rgba.h" +#include "v_draw.h" CVAR(String, r_viewsize, "", CVAR_NOSET) @@ -133,7 +134,7 @@ namespace swrenderer mysnprintf(temp, countof(temp), "%d x %d", viewwidth, viewheight); value.String = temp; - r_viewsize.ForceSet(value, CVAR_String); + r_viewsize->ForceSet(value, CVAR_String); } fuzzviewheight = viewheight - 2; // Maximum row the fuzzer can draw to @@ -171,6 +172,9 @@ namespace swrenderer WallTMapScale2 = IYaspectMul / CenterX * 1.2 / ypixelstretch; + // [RicardoLuis0] adjust IYaspectMul for map stretch -- fixes slope rendering on maps that define pixelratio + IYaspectMul *= 1.2 / ypixelstretch; + // thing clipping fillshort(screenheightarray, viewwidth, (short)viewheight); @@ -250,7 +254,7 @@ namespace swrenderer double translatedY = worldPos.Y - viewpoint.Pos.Y; return { translatedX * viewpoint.Sin - translatedY * viewpoint.Cos, - translatedX * viewpoint.TanCos + translatedY * viewpoint.TanSin + translatedX * viewpoint.Cos + translatedY * viewpoint.Sin }; } @@ -262,7 +266,7 @@ namespace swrenderer return { translatedX * viewpoint.Sin - translatedY * viewpoint.Cos, translatedZ, - translatedX * viewpoint.TanCos + translatedY * viewpoint.TanSin + translatedX * viewpoint.Cos + translatedY * viewpoint.Sin }; } diff --git a/src/rendering/swrenderer/viewport/r_viewport.h b/src/rendering/swrenderer/viewport/r_viewport.h index 3b5c89993eb..2a38b00867b 100644 --- a/src/rendering/swrenderer/viewport/r_viewport.h +++ b/src/rendering/swrenderer/viewport/r_viewport.h @@ -7,12 +7,10 @@ #include "r_defs.h" #include "r_utility.h" #include "actorinlines.h" -#include "utility/matrix.h" +#include "matrix.h" #define MINZ double((2048*4) / double(1 << 20)) -class PolyDepthStencil; - namespace swrenderer { class RenderThread; @@ -84,6 +82,12 @@ namespace swrenderer return (CenterY - screenY - 0.5) / FocalLengthY * viewZ; } + DVector3 ScreenToViewPos(int screenX, int screenY, const DVector3& plane, double planeD) + { + double viewZ = -planeD / ((screenX + 0.5 - CenterX) / FocalLengthX * plane.X + (CenterY - screenY - 0.5) / FocalLengthY * plane.Y + plane.Z); + return DVector3(ScreenToViewX(screenX, viewZ), ScreenToViewY(screenY, viewZ), viewZ); + } + FLevelLocals *Level() { return viewpoint.ViewLevel; diff --git a/src/rendering/v_framebuffer.cpp b/src/rendering/v_framebuffer.cpp deleted file mode 100644 index eeea50f36a5..00000000000 --- a/src/rendering/v_framebuffer.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/* -** The base framebuffer class -** -**--------------------------------------------------------------------------- -** Copyright 1999-2016 Randy Heit -** Copyright 2005-2018 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include - - -#include "x86.h" -#include "actor.h" - -#include "v_video.h" - -#include "c_dispatch.h" -#include "sbar.h" -#include "hardware.h" -#include "r_utility.h" -#include "swrenderer/r_renderer.h" -#include "vm.h" -#include "r_videoscale.h" -#include "i_time.h" -#include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/data/flatvertices.h" - -#include -#include - - -CVAR(Bool, gl_scale_viewport, true, CVAR_ARCHIVE); -CVAR(Bool, vid_fps, false, 0) -CVAR(Int, vid_showpalette, 0, 0) - -EXTERN_CVAR(Bool, ticker) -EXTERN_CVAR(Float, vid_brightness) -EXTERN_CVAR(Float, vid_contrast) -EXTERN_CVAR(Int, vid_maxfps) -EXTERN_CVAR(Bool, cl_capfps) -EXTERN_CVAR(Int, screenblocks) - -//========================================================================== -// -// DCanvas :: CalcGamma -// -//========================================================================== - -void DFrameBuffer::CalcGamma (float gamma, uint8_t gammalookup[256]) -{ - // I found this formula on the web at - // , - // but that page no longer exits. - double invgamma = 1.f / gamma; - int i; - - for (i = 0; i < 256; i++) - { - gammalookup[i] = (uint8_t)(255.0 * pow (i / 255.0, invgamma) + 0.5); - } -} - -//========================================================================== -// -// DFrameBuffer Constructor -// -// A frame buffer canvas is the most common and represents the image that -// gets drawn to the screen. -// -//========================================================================== - -DFrameBuffer::DFrameBuffer (int width, int height) -{ - SetSize(width, height); - mPortalState = new FPortalSceneState; -} - -DFrameBuffer::~DFrameBuffer() -{ - delete mPortalState; -} - -void DFrameBuffer::SetSize(int width, int height) -{ - Width = ViewportScaledWidth(width, height); - Height = ViewportScaledHeight(width, height); -} - -//========================================================================== -// -// -// -//========================================================================== - -void V_DrawPaletteTester(int paletteno) -{ - int blocksize = screen->GetHeight() / 50; - - int t = paletteno; - int k = 0; - for (int i = 0; i < 16; ++i) - { - for (int j = 0; j < 16; ++j) - { - int palindex = (t > 1) ? translationtables[TRANSLATION_Standard][t - 2]->Remap[k] : k; - PalEntry pe = GPalette.BaseColors[palindex]; - k++; - screen->Dim(pe, 1.f, j*blocksize, i*blocksize, blocksize, blocksize); - } - } -} - -//========================================================================== -// -// DFrameBuffer :: DrawRateStuff -// -// Draws the fps counter, dot ticker, and palette debug. -// -//========================================================================== - -void DFrameBuffer::DrawRateStuff () -{ - // Draws frame time and cumulative fps - if (vid_fps) - { - uint64_t ms = screen->FrameTime; - uint64_t howlong = ms - LastMS; - if ((signed)howlong >= 0) - { - char fpsbuff[40]; - int chars; - int rate_x; - - int textScale = active_con_scale(); - - chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2llu ms (%3llu fps)", (unsigned long long)howlong, (unsigned long long)LastCount); - rate_x = Width / textScale - NewConsoleFont->StringWidth(&fpsbuff[0]); - Clear (rate_x * textScale, 0, Width, NewConsoleFont->GetHeight() * textScale, GPalette.BlackIndex, 0); - DrawText (NewConsoleFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], - DTA_VirtualWidth, screen->GetWidth() / textScale, - DTA_VirtualHeight, screen->GetHeight() / textScale, - DTA_KeepRatio, true, TAG_DONE); - - uint32_t thisSec = (uint32_t)(ms/1000); - if (LastSec < thisSec) - { - LastCount = FrameCount / (thisSec - LastSec); - LastSec = thisSec; - FrameCount = 0; - } - FrameCount++; - } - LastMS = ms; - } - - // draws little dots on the bottom of the screen - if (ticker) - { - int64_t t = I_GetTime(); - int64_t tics = t - LastTic; - - LastTic = t; - if (tics > 20) tics = 20; - - int i; - for (i = 0; i < tics*2; i += 2) Clear(i, Height-1, i+1, Height, 255, 0); - for ( ; i < 20*2; i += 2) Clear(i, Height-1, i+1, Height, 0, 0); - } - - // draws the palette for debugging - if (vid_showpalette) - { - V_DrawPaletteTester(vid_showpalette); - } -} - -//========================================================================== -// -// Palette stuff. -// -//========================================================================== - -void DFrameBuffer::Update() -{ - CheckBench(); - - int initialWidth = GetClientWidth(); - int initialHeight = GetClientHeight(); - int clientWidth = ViewportScaledWidth(initialWidth, initialHeight); - int clientHeight = ViewportScaledHeight(initialWidth, initialHeight); - if (clientWidth < VID_MIN_WIDTH) clientWidth = VID_MIN_WIDTH; - if (clientHeight < VID_MIN_HEIGHT) clientHeight = VID_MIN_HEIGHT; - if (clientWidth > 0 && clientHeight > 0 && (GetWidth() != clientWidth || GetHeight() != clientHeight)) - { - SetVirtualSize(clientWidth, clientHeight); - V_OutputResized(clientWidth, clientHeight); - mVertexData->OutputResized(clientWidth, clientHeight); - } -} - -void DFrameBuffer::SetClearColor(int color) -{ - PalEntry pe = GPalette.BaseColors[color]; - mSceneClearColor[0] = pe.r / 255.f; - mSceneClearColor[1] = pe.g / 255.f; - mSceneClearColor[2] = pe.b / 255.f; - mSceneClearColor[3] = 1.f; -} - -//========================================================================== -// -// DFrameBuffer :: SetVSync -// -// Turns vertical sync on and off, if supported. -// -//========================================================================== - -void DFrameBuffer::SetVSync (bool vsync) -{ -} - -//========================================================================== -// -// DFrameBuffer :: WipeStartScreen -// -// Grabs a copy of the screen currently displayed to serve as the initial -// frame of a screen wipe. Also determines which screenwipe will be -// performed. -// -//========================================================================== - -FTexture *DFrameBuffer::WipeStartScreen() -{ - return nullptr; -} - -//========================================================================== -// -// DFrameBuffer :: WipeEndScreen -// -// Grabs a copy of the most-recently drawn, but not yet displayed, screen -// to serve as the final frame of a screen wipe. -// -//========================================================================== - -FTexture *DFrameBuffer::WipeEndScreen() -{ - return nullptr; -} - -//========================================================================== -// -// DFrameBuffer :: GetCaps -// -//========================================================================== - -EXTERN_CVAR(Bool, r_drawvoxels) - -uint32_t DFrameBuffer::GetCaps() -{ - ActorRenderFeatureFlags FlagSet = 0; - - if (V_IsPolyRenderer()) - FlagSet |= RFF_POLYGONAL | RFF_TILTPITCH | RFF_SLOPE3DFLOORS; - else - { - FlagSet |= RFF_UNCLIPPEDTEX; - if (r_drawvoxels) - FlagSet |= RFF_VOXELS; - } - - if (V_IsTrueColor()) - FlagSet |= RFF_TRUECOLOR; - else - FlagSet |= RFF_COLORMAP; - - return (uint32_t)FlagSet; -} - -void DFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height) -{ - SWRenderer->WriteSavePic(player, file, width, height); -} - - -//========================================================================== -// -// Calculates the viewport values needed for 2D and 3D operations -// -//========================================================================== - -void DFrameBuffer::SetViewportRects(IntRect *bounds) -{ - if (bounds) - { - mSceneViewport = *bounds; - mScreenViewport = *bounds; - mOutputLetterbox = *bounds; - return; - } - - // Special handling so the view with a visible status bar displays properly - int height, width; - if (screenblocks >= 10) - { - height = GetHeight(); - width = GetWidth(); - } - else - { - height = (screenblocks*GetHeight() / 10) & ~7; - width = (screenblocks*GetWidth() / 10); - } - - // Back buffer letterbox for the final output - int clientWidth = GetClientWidth(); - int clientHeight = GetClientHeight(); - if (clientWidth == 0 || clientHeight == 0) - { - // When window is minimized there may not be any client area. - // Pretend to the rest of the render code that we just have a very small window. - clientWidth = 160; - clientHeight = 120; - } - int screenWidth = GetWidth(); - int screenHeight = GetHeight(); - float scaleX, scaleY; - scaleX = MIN(clientWidth / (float)screenWidth, clientHeight / ((float)screenHeight * ViewportPixelAspect())); - scaleY = scaleX * ViewportPixelAspect(); - mOutputLetterbox.width = (int)round(screenWidth * scaleX); - mOutputLetterbox.height = (int)round(screenHeight * scaleY); - mOutputLetterbox.left = (clientWidth - mOutputLetterbox.width) / 2; - mOutputLetterbox.top = (clientHeight - mOutputLetterbox.height) / 2; - - // The entire renderable area, including the 2D HUD - mScreenViewport.left = 0; - mScreenViewport.top = 0; - mScreenViewport.width = screenWidth; - mScreenViewport.height = screenHeight; - - // Viewport for the 3D scene - mSceneViewport.left = viewwindowx; - mSceneViewport.top = screenHeight - (height + viewwindowy - ((height - viewheight) / 2)); - mSceneViewport.width = viewwidth; - mSceneViewport.height = height; - - // Scale viewports to fit letterbox - bool notScaled = ((mScreenViewport.width == ViewportScaledWidth(mScreenViewport.width, mScreenViewport.height)) && - (mScreenViewport.width == ViewportScaledHeight(mScreenViewport.width, mScreenViewport.height)) && - (ViewportPixelAspect() == 1.0)); - if (gl_scale_viewport && !IsFullscreen() && notScaled) - { - mScreenViewport.width = mOutputLetterbox.width; - mScreenViewport.height = mOutputLetterbox.height; - mSceneViewport.left = (int)round(mSceneViewport.left * scaleX); - mSceneViewport.top = (int)round(mSceneViewport.top * scaleY); - mSceneViewport.width = (int)round(mSceneViewport.width * scaleX); - mSceneViewport.height = (int)round(mSceneViewport.height * scaleY); - } -} - -//=========================================================================== -// -// Calculates the OpenGL window coordinates for a zdoom screen position -// -//=========================================================================== - -int DFrameBuffer::ScreenToWindowX(int x) -{ - return mScreenViewport.left + (int)round(x * mScreenViewport.width / (float)GetWidth()); -} - -int DFrameBuffer::ScreenToWindowY(int y) -{ - return mScreenViewport.top + mScreenViewport.height - (int)round(y * mScreenViewport.height / (float)GetHeight()); -} - -void DFrameBuffer::ScaleCoordsFromWindow(int16_t &x, int16_t &y) -{ - int letterboxX = mOutputLetterbox.left; - int letterboxY = mOutputLetterbox.top; - int letterboxWidth = mOutputLetterbox.width; - int letterboxHeight = mOutputLetterbox.height; - - x = int16_t((x - letterboxX) * Width / letterboxWidth); - y = int16_t((y - letterboxY) * Height / letterboxHeight); -} - -void DFrameBuffer::FPSLimit() -{ - using namespace std::chrono; - using namespace std::this_thread; - - if (vid_maxfps <= 0 || cl_capfps) - return; - - uint64_t targetWakeTime = fpsLimitTime + 1'000'000 / vid_maxfps; - - while (true) - { - fpsLimitTime = duration_cast(steady_clock::now().time_since_epoch()).count(); - int64_t timeToWait = targetWakeTime - fpsLimitTime; - - if (timeToWait > 1'000'000 || timeToWait <= 0) - { - break; - } - - if (timeToWait <= 2'000) - { - // We are too close to the deadline. OS sleep is not precise enough to wake us before it elapses. - // Yield execution and check time again. - sleep_for(nanoseconds(0)); - } - else - { - // Sleep, but try to wake before deadline. - sleep_for(microseconds(timeToWait - 2'000)); - } - } -} diff --git a/src/rendering/v_video.cpp b/src/rendering/v_video.cpp deleted file mode 100644 index 9b61eb24384..00000000000 --- a/src/rendering/v_video.cpp +++ /dev/null @@ -1,794 +0,0 @@ -/* -** Video basics and init code. -** -**--------------------------------------------------------------------------- -** Copyright 1999-2016 Randy Heit -** Copyright 2005-2016 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - - -#include - -#include "i_system.h" -#include "c_cvars.h" -#include "x86.h" -#include "i_video.h" -#include "r_state.h" -#include "am_map.h" - -#include "doomstat.h" - -#include "c_console.h" -#include "hu_stuff.h" - -#include "m_argv.h" - -#include "v_video.h" -#include "v_text.h" -#include "sc_man.h" - -#include "w_wad.h" - -#include "c_dispatch.h" -#include "cmdlib.h" -#include "sbar.h" -#include "hardware.h" -#include "m_png.h" -#include "r_utility.h" -#include "swrenderer/r_renderer.h" -#include "menu/menu.h" -#include "vm.h" -#include "r_videoscale.h" -#include "i_time.h" -#include "version.h" -#include "g_levellocals.h" -#include "am_map.h" - -EXTERN_CVAR(Int, menu_resolution_custom_width) -EXTERN_CVAR(Int, menu_resolution_custom_height) - -CVAR(Int, win_x, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Int, win_y, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Int, win_w, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Int, win_h, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, win_maximized, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) - -CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (vid_maxfps < TICRATE && vid_maxfps != 0) - { - vid_maxfps = TICRATE; - } - else if (vid_maxfps > 1000) - { - vid_maxfps = 1000; - } -} - -CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - if (self < 0 || self > 4) - { - self = 4; - } - else if (self == 2 || self == 3) - { - self = self - 2; // softpoly to software - } - - if (usergame) - { - // [SP] Update pitch limits to the netgame/gamesim. - players[consoleplayer].SendPitchLimits(); - } - screen->SetTextureFilterMode(); - - // No further checks needed. All this changes now is which scene drawer the render backend calls. -} - -CUSTOM_CVAR(Int, vid_preferbackend, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - // [SP] This may seem pointless - but I don't want to implement live switching just - // yet - I'm pretty sure it's going to require a lot of reinits and destructions to - // do it right without memory leaks - - switch(self) - { - case 2: - Printf("Selecting SoftPoly backend...\n"); - break; -#ifdef HAVE_VULKAN - case 1: - Printf("Selecting Vulkan backend...\n"); - break; -#endif - default: - Printf("Selecting OpenGL backend...\n"); - } - - Printf("Changing the video backend requires a restart for " GAMENAME ".\n"); -} - -CVAR(Int, vid_renderer, 1, 0) // for some stupid mods which threw caution out of the window... - - -EXTERN_CVAR(Bool, r_blendmethod) - -int active_con_scale(); - -FRenderer *SWRenderer; - -#define DBGBREAK assert(0) - -class DDummyFrameBuffer : public DFrameBuffer -{ - typedef DFrameBuffer Super; -public: - DDummyFrameBuffer (int width, int height) - : DFrameBuffer (0, 0) - { - SetVirtualSize(width, height); - } - // These methods should never be called. - void Update() { DBGBREAK; } - bool IsFullscreen() { DBGBREAK; return 0; } - int GetClientWidth() { DBGBREAK; return 0; } - int GetClientHeight() { DBGBREAK; return 0; } - void InitializeState() override {} - - float Gamma; -}; - -int DisplayWidth, DisplayHeight; - -FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont, *OriginalSmallFont, *AlternativeSmallFont, *OriginalBigFont; - - -// [RH] The framebuffer is no longer a mere byte array. -// There's also only one, not four. -DFrameBuffer *screen; - -CVAR (Int, vid_defwidth, 640, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Int, vid_defheight, 480, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, ticker, false, 0) - -CUSTOM_CVAR (Bool, vid_vsync, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (screen != NULL) - { - screen->SetVSync (*self); - } -} - -// [RH] Set true when vid_setmode command has been executed -bool setmodeneeded = false; - -//========================================================================== -// -// DCanvas Constructor -// -//========================================================================== - -DCanvas::DCanvas (int _width, int _height, bool _bgra) -{ - // Init member vars - Width = _width; - Height = _height; - Bgra = _bgra; - Resize(_width, _height); -} - -//========================================================================== -// -// DCanvas Destructor -// -//========================================================================== - -DCanvas::~DCanvas () -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -void DCanvas::Resize(int width, int height, bool optimizepitch) -{ - Width = width; - Height = height; - - // Making the pitch a power of 2 is very bad for performance - // Try to maximize the number of cache lines that can be filled - // for each column drawing operation by making the pitch slightly - // longer than the width. The values used here are all based on - // empirical evidence. - - if (width <= 640 || !optimizepitch) - { - // For low resolutions, just keep the pitch the same as the width. - // Some speedup can be seen using the technique below, but the speedup - // is so marginal that I don't consider it worthwhile. - Pitch = width; - } - else - { - // If we couldn't figure out the CPU's L1 cache line size, assume - // it's 32 bytes wide. - if (CPU.DataL1LineSize == 0) - { - CPU.DataL1LineSize = 32; - } - // The Athlon and P3 have very different caches, apparently. - // I am going to generalize the Athlon's performance to all AMD - // processors and the P3's to all non-AMD processors. I don't know - // how smart that is, but I don't have a vast plethora of - // processors to test with. - if (CPU.bIsAMD) - { - Pitch = width + CPU.DataL1LineSize; - } - else - { - Pitch = width + MAX(0, CPU.DataL1LineSize - 8); - } - } - int bytes_per_pixel = Bgra ? 4 : 1; - Pixels.Resize(Pitch * height * bytes_per_pixel); - memset (Pixels.Data(), 0, Pixels.Size()); -} - - -//========================================================================== -// -// V_GetColorFromString -// -// Passed a string of the form "#RGB", "#RRGGBB", "R G B", or "RR GG BB", -// returns a number representing that color. If palette is non-NULL, the -// index of the best match in the palette is returned, otherwise the -// RRGGBB value is returned directly. -// -//========================================================================== - -int V_GetColorFromString (const uint32_t *palette, const char *cstr, FScriptPosition *sc) -{ - int c[3], i, p; - char val[3]; - - val[2] = '\0'; - - // Check for HTML-style #RRGGBB or #RGB color string - if (cstr[0] == '#') - { - size_t len = strlen (cstr); - - if (len == 7) - { - // Extract each eight-bit component into c[]. - for (i = 0; i < 3; ++i) - { - val[0] = cstr[1 + i*2]; - val[1] = cstr[2 + i*2]; - c[i] = ParseHex (val, sc); - } - } - else if (len == 4) - { - // Extract each four-bit component into c[], expanding to eight bits. - for (i = 0; i < 3; ++i) - { - val[1] = val[0] = cstr[1 + i]; - c[i] = ParseHex (val, sc); - } - } - else - { - // Bad HTML-style; pretend it's black. - c[2] = c[1] = c[0] = 0; - } - } - else - { - if (strlen(cstr) == 6) - { - char *p; - int color = strtol(cstr, &p, 16); - if (*p == 0) - { - // RRGGBB string - c[0] = (color & 0xff0000) >> 16; - c[1] = (color & 0xff00) >> 8; - c[2] = (color & 0xff); - } - else goto normal; - } - else - { -normal: - // Treat it as a space-delimited hexadecimal string - for (i = 0; i < 3; ++i) - { - // Skip leading whitespace - while (*cstr <= ' ' && *cstr != '\0') - { - cstr++; - } - // Extract a component and convert it to eight-bit - for (p = 0; *cstr > ' '; ++p, ++cstr) - { - if (p < 2) - { - val[p] = *cstr; - } - } - if (p == 0) - { - c[i] = 0; - } - else - { - if (p == 1) - { - val[1] = val[0]; - } - c[i] = ParseHex (val, sc); - } - } - } - } - if (palette) - return ColorMatcher.Pick (c[0], c[1], c[2]); - else - return MAKERGB(c[0], c[1], c[2]); -} - -//========================================================================== -// -// V_GetColorStringByName -// -// Searches for the given color name in x11r6rgb.txt and returns an -// HTML-ish "#RRGGBB" string for it if found or the empty string if not. -// -//========================================================================== - -FString V_GetColorStringByName (const char *name, FScriptPosition *sc) -{ - FMemLump rgbNames; - char *rgbEnd; - char *rgb, *endp; - int rgblump; - int c[3], step; - size_t namelen; - - if (Wads.GetNumLumps()==0) return FString(); - - rgblump = Wads.CheckNumForName ("X11R6RGB"); - if (rgblump == -1) - { - if (!sc) Printf ("X11R6RGB lump not found\n"); - else sc->Message(MSG_WARNING, "X11R6RGB lump not found"); - return FString(); - } - - rgbNames = Wads.ReadLump (rgblump); - rgb = (char *)rgbNames.GetMem(); - rgbEnd = rgb + Wads.LumpLength (rgblump); - step = 0; - namelen = strlen (name); - - while (rgb < rgbEnd) - { - // Skip white space - if (*rgb <= ' ') - { - do - { - rgb++; - } while (rgb < rgbEnd && *rgb <= ' '); - } - else if (step == 0 && *rgb == '!') - { // skip comment lines - do - { - rgb++; - } while (rgb < rgbEnd && *rgb != '\n'); - } - else if (step < 3) - { // collect RGB values - c[step++] = strtoul (rgb, &endp, 10); - if (endp == rgb) - { - break; - } - rgb = endp; - } - else - { // Check color name - endp = rgb; - // Find the end of the line - while (endp < rgbEnd && *endp != '\n') - endp++; - // Back up over any whitespace - while (endp > rgb && *endp <= ' ') - endp--; - if (endp == rgb) - { - break; - } - size_t checklen = ++endp - rgb; - if (checklen == namelen && strnicmp (rgb, name, checklen) == 0) - { - FString descr; - descr.Format ("#%02x%02x%02x", c[0], c[1], c[2]); - return descr; - } - rgb = endp; - step = 0; - } - } - if (rgb < rgbEnd) - { - if (!sc) Printf ("X11R6RGB lump is corrupt\n"); - else sc->Message(MSG_WARNING, "X11R6RGB lump is corrupt"); - } - return FString(); -} - -//========================================================================== -// -// V_GetColor -// -// Works like V_GetColorFromString(), but also understands X11 color names. -// -//========================================================================== - -int V_GetColor (const uint32_t *palette, const char *str, FScriptPosition *sc) -{ - FString string = V_GetColorStringByName (str, sc); - int res; - - if (!string.IsEmpty()) - { - res = V_GetColorFromString (palette, string, sc); - } - else - { - res = V_GetColorFromString (palette, str, sc); - } - return res; -} - -int V_GetColor(const uint32_t *palette, FScanner &sc) -{ - FScriptPosition scc = sc; - return V_GetColor(palette, sc.String, &scc); -} - -CCMD(clean) -{ - Printf ("CleanXfac: %d\nCleanYfac: %d\n", CleanXfac, CleanYfac); -} - - -void V_UpdateModeSize (int width, int height) -{ - // This calculates the menu scale. - // The optimal scale will always be to fit a virtual 640 pixel wide display onto the screen. - // Exceptions are made for a few ranges where the available virtual width is > 480. - - // This reference size is being used so that on 800x450 (small 16:9) a scale of 2 gets used. - - CleanXfac = std::max(std::min(screen->GetWidth() / 400, screen->GetHeight() / 240), 1); - if (CleanXfac >= 4) CleanXfac--; // Otherwise we do not have enough space for the episode/skill menus in some languages. - CleanYfac = CleanXfac; - CleanWidth = screen->GetWidth() / CleanXfac; - CleanHeight = screen->GetHeight() / CleanYfac; - - int w = screen->GetWidth(); - int factor; - if (w < 640) factor = 1; - else if (w >= 1024 && w < 1280) factor = 2; - else if (w >= 1600 && w < 1920) factor = 3; - else factor = w / 640; - - if (w < 1360) factor = 1; - else if (w < 1920) factor = 2; - else factor = int(factor * 0.7); - - CleanYfac_1 = CleanXfac_1 = factor;// MAX(1, int(factor * 0.7)); - CleanWidth_1 = width / CleanXfac_1; - CleanHeight_1 = height / CleanYfac_1; - - DisplayWidth = width; - DisplayHeight = height; - - R_OldBlend = ~0; -} - -void V_OutputResized (int width, int height) -{ - V_UpdateModeSize(width, height); - setsizeneeded = true; - if (StatusBar != NULL) - { - StatusBar->CallScreenSizeChanged(); - } - C_NewModeAdjust(); - // Reload crosshair if transitioned to a different size - ST_LoadCrosshair(true); - if (primaryLevel && primaryLevel->automap) - primaryLevel->automap->NewResolution(); -} - -void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *_cx1, int *_cx2) -{ - if (designheight < 240 && realheight >= 480) designheight = 240; - *cleanx = *cleany = std::min(realwidth / designwidth, realheight / designheight); -} - -bool IVideo::SetResolution () -{ - DFrameBuffer *buff = CreateFrameBuffer(); - - if (buff == NULL) // this cannot really happen - { - return false; - } - - screen = buff; - screen->InitializeState(); - screen->SetGamma(); - - V_UpdateModeSize(screen->GetWidth(), screen->GetHeight()); - - return true; -} - -// -// V_Init -// - -void V_InitScreenSize () -{ - const char *i; - int width, height, bits; - - width = height = bits = 0; - - if ( (i = Args->CheckValue ("-width")) ) - width = atoi (i); - - if ( (i = Args->CheckValue ("-height")) ) - height = atoi (i); - - if (width == 0) - { - if (height == 0) - { - width = vid_defwidth; - height = vid_defheight; - } - else - { - width = (height * 8) / 6; - } - } - else if (height == 0) - { - height = (width * 6) / 8; - } - // Remember the passed arguments for the next time the game starts up windowed. - vid_defwidth = width; - vid_defheight = height; -} - -void V_InitScreen() -{ - screen = new DDummyFrameBuffer (vid_defwidth, vid_defheight); -} - -void V_Init2() -{ - float gamma = static_cast(screen)->Gamma; - - { - DFrameBuffer *s = screen; - screen = NULL; - delete s; - } - - UCVarValue val; - - val.Bool = !!Args->CheckParm("-devparm"); - ticker.SetGenericRepDefault(val, CVAR_Bool); - - - I_InitGraphics(); - - Video->SetResolution(); // this only fails via exceptions. - Printf ("Resolution: %d x %d\n", SCREENWIDTH, SCREENHEIGHT); - - // init these for the scaling menu - menu_resolution_custom_width = SCREENWIDTH; - menu_resolution_custom_height = SCREENHEIGHT; - - screen->SetVSync(vid_vsync); - screen->SetGamma (); - FBaseCVar::ResetColors (); - C_NewModeAdjust(); - setsizeneeded = true; -} - -CUSTOM_CVAR (Int, vid_aspect, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) -{ - setsizeneeded = true; - if (StatusBar != NULL) - { - StatusBar->CallScreenSizeChanged(); - } -} - -// Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none. -int ActiveFakeRatio(int width, int height) -{ - int fakeratio = -1; - if ((vid_aspect >= 1) && (vid_aspect <= 6)) - { - // [SP] User wants to force aspect ratio; let them. - fakeratio = int(vid_aspect); - if (fakeratio == 3) - { - fakeratio = 0; - } - else if (fakeratio == 5) - { - fakeratio = 3; - } - } - return fakeratio; -} - -// Active screen ratio based on cvars and size -float ActiveRatio(int width, int height, float *trueratio) -{ - static float forcedRatioTypes[] = - { - 4 / 3.0f, - 16 / 9.0f, - 16 / 10.0f, - 17 / 10.0f, - 5 / 4.0f, - 17 / 10.0f, - 21 / 9.0f - }; - - float ratio = width / (float)height; - int fakeratio = ActiveFakeRatio(width, height); - - if (trueratio) - *trueratio = ratio; - return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : (ratio / ViewportPixelAspect()); -} - -DEFINE_ACTION_FUNCTION(_Screen, GetAspectRatio) -{ - ACTION_RETURN_FLOAT(ActiveRatio(screen->GetWidth(), screen->GetHeight(), nullptr)); -} - -int AspectBaseWidth(float aspect) -{ - return (int)round(240.0f * aspect * 3.0f); -} - -int AspectBaseHeight(float aspect) -{ - if (!AspectTallerThanWide(aspect)) - return (int)round(200.0f * (320.0f / (AspectBaseWidth(aspect) / 3.0f)) * 3.0f); - else - return (int)round((200.0f * (4.0f / 3.0f)) / aspect * 3.0f); -} - -double AspectPspriteOffset(float aspect) -{ - if (!AspectTallerThanWide(aspect)) - return 0.0; - else - return ((4.0 / 3.0) / aspect - 1.0) * 97.5; -} - -int AspectMultiplier(float aspect) -{ - if (!AspectTallerThanWide(aspect)) - return (int)round(320.0f / (AspectBaseWidth(aspect) / 3.0f) * 48.0f); - else - return (int)round(200.0f / (AspectBaseHeight(aspect) / 3.0f) * 48.0f); -} - -bool AspectTallerThanWide(float aspect) -{ - return aspect < 1.333f; -} - -CCMD(vid_setsize) -{ - if (argv.argc() < 3) - { - Printf("Usage: vid_setsize width height\n"); - } - else - { - screen->SetWindowSize((int)strtol(argv[1], nullptr, 0), (int)strtol(argv[2], nullptr, 0)); - V_OutputResized(screen->GetClientWidth(), screen->GetClientHeight()); - } -} - - -void IVideo::DumpAdapters () -{ - Printf("Multi-monitor support unavailable.\n"); -} - -CUSTOM_CVAR(Bool, fullscreen, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - setmodeneeded = true; -} - -CUSTOM_CVAR(Bool, vid_hdr, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - Printf("This won't take effect until " GAMENAME " is restarted.\n"); -} - -CCMD(vid_listadapters) -{ - if (Video != NULL) - Video->DumpAdapters(); -} - -bool vid_hdr_active = false; - -DEFINE_GLOBAL(SmallFont) -DEFINE_GLOBAL(SmallFont2) -DEFINE_GLOBAL(BigFont) -DEFINE_GLOBAL(ConFont) -DEFINE_GLOBAL(NewConsoleFont) -DEFINE_GLOBAL(NewSmallFont) -DEFINE_GLOBAL(AlternativeSmallFont) -DEFINE_GLOBAL(OriginalSmallFont) -DEFINE_GLOBAL(OriginalBigFont) -DEFINE_GLOBAL(IntermissionFont) -DEFINE_GLOBAL(CleanXfac) -DEFINE_GLOBAL(CleanYfac) -DEFINE_GLOBAL(CleanWidth) -DEFINE_GLOBAL(CleanHeight) -DEFINE_GLOBAL(CleanXfac_1) -DEFINE_GLOBAL(CleanYfac_1) -DEFINE_GLOBAL(CleanWidth_1) -DEFINE_GLOBAL(CleanHeight_1) -DEFINE_GLOBAL(generic_ui) diff --git a/src/rendering/v_video.h b/src/rendering/v_video.h deleted file mode 100644 index 285d8d4c6a0..00000000000 --- a/src/rendering/v_video.h +++ /dev/null @@ -1,691 +0,0 @@ -/* -** v_video.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __V_VIDEO_H__ -#define __V_VIDEO_H__ - -#include -#include "doomtype.h" -#include "vectors.h" - -#include "doomdef.h" -#include "dobject.h" -#include "r_data/renderstyle.h" -#include "c_cvars.h" -#include "r_data/v_colortables.h" -#include "v_2ddrawer.h" -#include "hwrenderer/dynlights/hw_shadowmap.h" - -static const int VID_MIN_WIDTH = 320; -static const int VID_MIN_HEIGHT = 200; - -static const int VID_MIN_UI_WIDTH = 640; -static const int VID_MIN_UI_HEIGHT = 400; - -struct sector_t; -class FTexture; -struct FPortalSceneState; -class FSkyVertexBuffer; -class IIndexBuffer; -class IVertexBuffer; -class IDataBuffer; -class FFlatVertexBuffer; -class HWViewpointBuffer; -class FLightBuffer; -struct HWDrawInfo; - -enum EHWCaps -{ - // [BB] Added texture compression flags. - RFL_TEXTURE_COMPRESSION = 1, - RFL_TEXTURE_COMPRESSION_S3TC = 2, - - RFL_SHADER_STORAGE_BUFFER = 4, - RFL_BUFFER_STORAGE = 8, - - RFL_NO_CLIP_PLANES = 32, - - RFL_INVALIDATE_BUFFER = 64, - RFL_DEBUG = 128, -}; - - -struct IntRect -{ - int left, top; - int width, height; - - - void Offset(int xofs, int yofs) - { - left += xofs; - top += yofs; - } - - void AddToRect(int x, int y) - { - if (x < left) - left = x; - if (x > left + width) - width = x - left; - - if (y < top) - top = y; - if (y > top + height) - height = y - top; - } - - -}; - - - - - -extern int CleanWidth, CleanHeight, CleanXfac, CleanYfac; -extern int CleanWidth_1, CleanHeight_1, CleanXfac_1, CleanYfac_1; -extern int DisplayWidth, DisplayHeight; - -void V_UpdateModeSize (int width, int height); -void V_OutputResized (int width, int height); -void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *cx1=NULL, int *cx2=NULL); - -EXTERN_CVAR(Int, vid_rendermode) -EXTERN_CVAR(Bool, fullscreen) -EXTERN_CVAR(Int, win_x) -EXTERN_CVAR(Int, win_y) -EXTERN_CVAR(Int, win_w) -EXTERN_CVAR(Int, win_h) -EXTERN_CVAR(Bool, win_maximized) - - -inline bool V_IsHardwareRenderer() -{ - return vid_rendermode == 4; -} - -inline bool V_IsSoftwareRenderer() -{ - return vid_rendermode < 2; -} - -inline bool V_IsPolyRenderer() -{ - return vid_rendermode == 2 || vid_rendermode == 3; -} - -inline bool V_IsTrueColor() -{ - return vid_rendermode == 1 || vid_rendermode == 3 || vid_rendermode == 4; -} - - -class FTexture; -struct FColormap; -class FileWriter; -enum FTextureFormat : uint32_t; -class FModelRenderer; -struct SamplerUniform; - -// TagItem definitions for DrawTexture. As far as I know, tag lists -// originated on the Amiga. -// -// Think of TagItems as an array of the following structure: -// -// struct TagItem { -// uint32_t ti_Tag; -// uint32_t ti_Data; -// }; - -#define TAG_DONE (0) /* Used to indicate the end of the Tag list */ -#define TAG_END (0) /* Ditto */ - /* list pointed to in ti_Data */ - -#define TAG_USER ((uint32_t)(1u<<30)) - -enum -{ - DTA_Base = TAG_USER + 5000, - DTA_DestWidth, // width of area to draw to - DTA_DestHeight, // height of area to draw to - DTA_Alpha, // alpha value for translucency - DTA_FillColor, // color to stencil onto the destination - DTA_TranslationIndex, // translation table to recolor the source - DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor - DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac - DTA_320x200, // bool: scale texture size and position to fit on a virtual 320x200 screen - DTA_Bottom320x200, // bool: same as DTA_320x200 but centers virtual screen on bottom for 1280x1024 targets - DTA_CleanNoMove, // bool: like DTA_Clean but does not reposition output position - DTA_CleanNoMove_1, // bool: like DTA_CleanNoMove, but uses Clean[XY]fac_1 instead - DTA_FlipX, // bool: flip image horizontally //FIXME: Does not work with DTA_Window(Left|Right) - DTA_ShadowColor, // color of shadow - DTA_ShadowAlpha, // alpha of shadow - DTA_Shadow, // set shadow color and alphas to defaults - DTA_VirtualWidth, // pretend the canvas is this wide - DTA_VirtualHeight, // pretend the canvas is this tall - DTA_TopOffset, // override texture's top offset - DTA_LeftOffset, // override texture's left offset - DTA_CenterOffset, // bool: override texture's left and top offsets and set them for the texture's middle - DTA_CenterBottomOffset,// bool: override texture's left and top offsets and set them for the texture's bottom middle - DTA_WindowLeft, // don't draw anything left of this column (on source, not dest) - DTA_WindowRight, // don't draw anything at or to the right of this column (on source, not dest) - DTA_ClipTop, // don't draw anything above this row (on dest, not source) - DTA_ClipBottom, // don't draw anything at or below this row (on dest, not source) - DTA_ClipLeft, // don't draw anything to the left of this column (on dest, not source) - DTA_ClipRight, // don't draw anything at or to the right of this column (on dest, not source) - DTA_Masked, // true(default)=use masks from texture, false=ignore masks - DTA_HUDRules, // use fullscreen HUD rules to position and size textures - DTA_HUDRulesC, // only used internally for marking HUD_HorizCenter - DTA_KeepRatio, // doesn't adjust screen size for DTA_Virtual* if the aspect ratio is not 4:3 - DTA_RenderStyle, // same as render style for actors - DTA_ColorOverlay, // uint32_t: ARGB to overlay on top of image; limited to black for software - DTA_BilinearFilter, // bool: apply bilinear filtering to the image - DTA_SpecialColormap,// pointer to FSpecialColormapParameters - DTA_Desaturate, // explicit desaturation factor (does not do anything in Legacy OpenGL) - DTA_Fullscreen, // Draw image fullscreen (same as DTA_VirtualWidth/Height with graphics size.) - - // floating point duplicates of some of the above: - DTA_DestWidthF, - DTA_DestHeightF, - DTA_TopOffsetF, - DTA_LeftOffsetF, - DTA_VirtualWidthF, - DTA_VirtualHeightF, - DTA_WindowLeftF, - DTA_WindowRightF, - - // For DrawText calls: - DTA_TextLen, // stop after this many characters, even if \0 not hit - DTA_CellX, // horizontal size of character cell - DTA_CellY, // vertical size of character cell - - // New additions. - DTA_Color, - DTA_FlipY, // bool: flip image vertically - DTA_SrcX, // specify a source rectangle (this supersedes the poorly implemented DTA_WindowLeft/Right - DTA_SrcY, - DTA_SrcWidth, - DTA_SrcHeight, - DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle - DTA_Burn, // activates the burn shader for this element - DTA_Spacing, // Strings only: Additional spacing between characters - DTA_Monospace, // Fonts only: Use a fixed distance between characters. - - DTA_FullscreenEx, -}; - -enum EMonospacing : int -{ - Off = 0, - CellLeft = 1, - CellCenter = 2, - CellRight = 3 -}; - -enum -{ - HUD_Normal, - HUD_HorizCenter -}; - - -class FFont; -struct FRemapTable; -class player_t; -typedef uint32_t angle_t; - -struct DrawParms -{ - double x, y; - double texwidth; - double texheight; - double destwidth; - double destheight; - double virtWidth; - double virtHeight; - double windowleft; - double windowright; - int cleanmode; - int dclip; - int uclip; - int lclip; - int rclip; - double top; - double left; - float Alpha; - PalEntry fillcolor; - int TranslationId; - PalEntry colorOverlay; - PalEntry color; - INTBOOL alphaChannel; - INTBOOL flipX; - INTBOOL flipY; - //float shadowAlpha; - int shadowColor; - INTBOOL keepratio; - INTBOOL masked; - INTBOOL bilinear; - FRenderStyle style; - struct FSpecialColormap *specialcolormap; - int desaturate; - int scalex, scaley; - int cellx, celly; - int monospace; - int spacing; - int maxstrlen; - bool fortext; - bool virtBottom; - bool burn; - uint8_t fsscalemode; - double srcx, srcy; - double srcwidth, srcheight; -}; - -struct Va_List -{ - va_list list; -}; - -struct VMVa_List -{ - VMValue *args; - int curindex; - int numargs; - const uint8_t *reginfo; -}; -// -// VIDEO -// -// -class DCanvas -{ -public: - DCanvas (int width, int height, bool bgra); - ~DCanvas (); - void Resize(int width, int height, bool optimizepitch = true); - - // Member variable access - inline uint8_t *GetPixels () const { return Pixels.Data(); } - inline int GetWidth () const { return Width; } - inline int GetHeight () const { return Height; } - inline int GetPitch () const { return Pitch; } - inline bool IsBgra() const { return Bgra; } - -protected: - TArray Pixels; - int Width; - int Height; - int Pitch; - bool Bgra; -}; - -class FUniquePalette; -class IHardwareTexture; -class FTexture; - - -class DFrameBuffer -{ -protected: - - void DrawTextureV(FTexture *img, double x, double y, uint32_t tag, va_list tags) = delete; - void DrawTextureParms(FTexture *img, DrawParms &parms); - - template - bool ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, T& tags, DrawParms *parms, bool fortext) const; - template - void DrawTextCommon(FFont *font, int normalcolor, double x, double y, const T *string, DrawParms &parms); - - F2DDrawer m2DDrawer; -private: - int Width = 0; - int Height = 0; -protected: - int clipleft = 0, cliptop = 0, clipwidth = -1, clipheight = -1; - -public: - // Hardware render state that needs to be exposed to the API independent part of the renderer. For ease of access this is stored in the base class. - int hwcaps = 0; // Capability flags - float glslversion = 0; // This is here so that the differences between old OpenGL and new OpenGL/Vulkan can be handled by platform independent code. - int instack[2] = { 0,0 }; // this is globally maintained state for portal recursion avoidance. - int stencilValue = 0; // Global stencil test value - unsigned int uniformblockalignment = 256; // Hardware dependent uniform buffer alignment. - unsigned int maxuniformblock = 65536; - const char *vendorstring; // We have to account for some issues with particular vendors. - FPortalSceneState *mPortalState; // global portal state. - FSkyVertexBuffer *mSkyData = nullptr; // the sky vertex buffer - FFlatVertexBuffer *mVertexData = nullptr; // Global vertex data - HWViewpointBuffer *mViewpoints = nullptr; // Viewpoint render data. - FLightBuffer *mLights = nullptr; // Dynamic lights - IShadowMap mShadowMap; - - IntRect mScreenViewport; - IntRect mSceneViewport; - IntRect mOutputLetterbox; - float mSceneClearColor[4]; - - -public: - DFrameBuffer (int width=1, int height=1); - virtual ~DFrameBuffer(); - virtual void InitializeState() = 0; // For stuff that needs 'screen' set. - virtual bool IsVulkan() { return false; } - virtual bool IsPoly() { return false; } - - virtual DCanvas* GetCanvas() { return nullptr; } - - void SetSize(int width, int height); - void SetVirtualSize(int width, int height) - { - Width = width; - Height = height; - } - inline int GetWidth() const { return Width; } - inline int GetHeight() const { return Height; } - - FVector2 SceneScale() const - { - return { mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height }; - } - - FVector2 SceneOffset() const - { - return { mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height }; - } - - // Make the surface visible. - virtual void Update (); - - // Stores the palette with flash blended in into 256 dwords - // Mark the palette as changed. It will be updated on the next Update(). - virtual void UpdatePalette() {} - - virtual void SetGamma() {} - - // Returns true if running fullscreen. - virtual bool IsFullscreen () = 0; - virtual void ToggleFullscreen(bool yes) {} - - // Changes the vsync setting, if supported by the device. - virtual void SetVSync (bool vsync); - - // Delete any resources that need to be deleted after restarting with a different IWAD - virtual void CleanForRestart() {} - virtual void SetTextureFilterMode() {} - virtual IHardwareTexture *CreateHardwareTexture() { return nullptr; } - virtual void PrecacheMaterial(FMaterial *mat, int translation) {} - virtual FModelRenderer *CreateModelRenderer(int mli) { return nullptr; } - virtual void TextureFilterChanged() {} - virtual void BeginFrame() {} - virtual void SetWindowSize(int w, int h) {} - virtual void StartPrecaching() {} - - virtual int GetClientWidth() = 0; - virtual int GetClientHeight() = 0; - virtual void BlurScene(float amount) {} - - // Interface to hardware rendering resources - virtual IVertexBuffer *CreateVertexBuffer() { return nullptr; } - virtual IIndexBuffer *CreateIndexBuffer() { return nullptr; } - virtual IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) { return nullptr; } - bool BuffersArePersistent() { return !!(hwcaps & RFL_BUFFER_STORAGE); } - - // Begin/End 2D drawing operations. - void Begin2D() { isIn2D = true; } - void End2D() { isIn2D = false; } - - void End2DAndUpdate() - { - DrawRateStuff(); - End2D(); - Update(); - } - - - // Returns true if Begin2D has been called and 2D drawing is now active - bool HasBegun2D() { return isIn2D; } - - // This is overridable in case Vulkan does it differently. - virtual bool RenderTextureIsFlipped() const - { - return true; - } - - // Report a game restart - void SetClearColor(int color); - virtual uint32_t GetCaps(); - virtual int Backend() { return 0; } - virtual const char* DeviceName() const { return "Unknown"; } - virtual void WriteSavePic(player_t *player, FileWriter *file, int width, int height); - virtual sector_t *RenderView(player_t *player) { return nullptr; } - - // Screen wiping - virtual FTexture *WipeStartScreen(); - virtual FTexture *WipeEndScreen(); - - virtual void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) { if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D(); } - - void ScaleCoordsFromWindow(int16_t &x, int16_t &y); - - uint64_t GetLastFPS() const { return LastCount; } - - // 2D Texture drawing - void ClearClipRect() { clipleft = cliptop = 0; clipwidth = clipheight = -1; } - void SetClipRect(int x, int y, int w, int h); - void GetClipRect(int *x, int *y, int *w, int *h); - - virtual void Draw2D() {} - void Clear2D() { m2DDrawer.Clear(); } - - // Dim part of the canvas - void Dim(PalEntry color, float amount, int x1, int y1, int w, int h, FRenderStyle *style = nullptr); - void DoDim(PalEntry color, float amount, int x1, int y1, int w, int h, FRenderStyle *style = nullptr); - FVector4 CalcBlend(sector_t * viewsector, PalEntry *modulateColor); - void DrawBlend(sector_t * viewsector); - - // Fill an area with a texture - void FlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin = false); - - // Fill a simple polygon with a texture - void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, - double originx, double originy, double scalex, double scaley, DAngle rotation, - const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip, uint32_t *indices, size_t indexcount); - - // Set an area to a specified color - void Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color); - - // Draws a line - void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32_t realcolor, uint8_t alpha = 255); - - // Draws a line with thickness - void DrawThickLine(int x0, int y0, int x1, int y1, double thickness, uint32_t realcolor, uint8_t alpha = 255); - - // Draws a single pixel - void DrawPixel(int x, int y, int palcolor, uint32_t rgbcolor); - - - bool SetTextureParms(DrawParms *parms, FTexture *img, double x, double y) const; - void DrawTexture(FTexture *img, double x, double y, int tags, ...); - void DrawTexture(FTexture *img, double x, double y, VMVa_List &); - void DrawShape(FTexture *img, DShape2D *shape, int tags, ...); - void DrawShape(FTexture *img, DShape2D *shape, VMVa_List &); - void FillBorder(FTexture *img); // Fills the border around a 4:3 part of the screen on non-4:3 displays - void VirtualToRealCoords(double &x, double &y, double &w, double &h, double vwidth, double vheight, bool vbottom = false, bool handleaspect = true) const; - - // Code that uses these (i.e. SBARINFO) should probably be evaluated for using doubles all around instead. - void VirtualToRealCoordsInt(int &x, int &y, int &w, int &h, int vwidth, int vheight, bool vbottom = false, bool handleaspect = true) const; - - // Text drawing functions ----------------------------------------------- - -#ifdef DrawText -#undef DrawText // See WinUser.h for the definition of DrawText as a macro -#endif - // 2D Text drawing - void DrawText(FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...); - void DrawText(FFont *font, int normalcolor, double x, double y, const char *string, VMVa_List &args); - void DrawChar(FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...); - void DrawChar(FFont *font, int normalcolor, double x, double y, int character, VMVa_List &args); - void DrawText(FFont *font, int normalcolor, double x, double y, const char32_t *string, int tag_first, ...); - - void DrawFrame(int left, int top, int width, int height); - void DrawBorder(FTextureID, int x1, int y1, int x2, int y2); - - // Calculate gamma table - void CalcGamma(float gamma, uint8_t gammalookup[256]); - - virtual void SetViewportRects(IntRect *bounds); - int ScreenToWindowX(int x); - int ScreenToWindowY(int y); - - void FPSLimit(); - - // Retrieves a buffer containing image data for a screenshot. - // Hint: Pitch can be negative for upside-down images, in which case buffer - // points to the last row in the buffer, which will be the first row output. - virtual TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) { return TArray(); } - - static float GetZNear() { return 5.f; } - static float GetZFar() { return 65536.f; } - - // The original size of the framebuffer as selected in the video menu. - uint64_t FrameTime = 0; - -protected: - void DrawRateStuff (); - -private: - uint64_t fpsLimitTime = 0; - - uint64_t LastMS = 0, LastSec = 0, FrameCount = 0, LastCount = 0, LastTic = 0; - - bool isIn2D = false; -}; - - -// This is the screen updated by I_FinishUpdate. -extern DFrameBuffer *screen; - -#define SCREENWIDTH (screen->GetWidth ()) -#define SCREENHEIGHT (screen->GetHeight ()) -#define SCREENPITCH (screen->GetPitch ()) - -EXTERN_CVAR (Float, Gamma) - - -// Allocates buffer screens, call before R_Init. -void V_InitScreenSize(); -void V_InitScreen(); - -// Initializes graphics mode for the first time. -void V_Init2 (); - -void V_Shutdown (); - -class FScanner; -struct FScriptPosition; -// Returns the closest color to the one desired. String -// should be of the form "rr gg bb". -int V_GetColorFromString (const uint32_t *palette, const char *colorstring, FScriptPosition *sc = nullptr); -// Scans through the X11R6RGB lump for a matching color -// and returns a color string suitable for V_GetColorFromString. -FString V_GetColorStringByName (const char *name, FScriptPosition *sc = nullptr); - -// Tries to get color by name, then by string -int V_GetColor (const uint32_t *palette, const char *str, FScriptPosition *sc = nullptr); -int V_GetColor(const uint32_t *palette, FScanner &sc); - -inline bool IsRatioWidescreen(int ratio) { return (ratio & 3) != 0; } - -float ActiveRatio (int width, int height, float *trueratio = NULL); -static inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); } - -int AspectBaseWidth(float aspect); -int AspectBaseHeight(float aspect); -double AspectPspriteOffset(float aspect); -int AspectMultiplier(float aspect); -bool AspectTallerThanWide(float aspect); - -int GetUIScale(int altval); -int GetConScale(int altval); - -EXTERN_CVAR(Int, uiscale); -EXTERN_CVAR(Int, con_scaletext); -EXTERN_CVAR(Int, con_scale); - -inline int active_con_scaletext(bool newconfont = false) -{ - return newconfont? GetConScale(con_scaletext) : GetUIScale(con_scaletext); -} - -inline int active_con_scale() -{ - return GetConScale(con_scale); -} - - -class ScaleOverrider -{ - int savedxfac, savedyfac, savedwidth, savedheight; - -public: - // This is to allow certain elements to use an optimal fullscreen scale which for the menu would be too large. - // The old code contained far too much mess to compensate for the menus which negatively affected everything else. - // However, for compatibility reasons the currently used variables cannot be changed so they have to be overridden temporarily. - // This class provides a safe interface for this because it ensures that the values get restored afterward. - // Currently, the intermission and the level summary screen use this. - ScaleOverrider() - { - savedxfac = CleanXfac; - savedyfac = CleanYfac; - savedwidth = CleanWidth; - savedheight = CleanHeight; - - if (screen) - { - V_CalcCleanFacs(320, 200, screen->GetWidth(), screen->GetHeight(), &CleanXfac, &CleanYfac); - CleanWidth = screen->GetWidth() / CleanXfac; - CleanHeight = screen->GetHeight() / CleanYfac; - } - } - - ~ScaleOverrider() - { - CleanXfac = savedxfac; - CleanYfac = savedyfac; - CleanWidth = savedwidth; - CleanHeight = savedheight; - } -}; - - -#endif // __V_VIDEO_H__ diff --git a/src/rendering/vulkan/renderer/vk_postprocess.cpp b/src/rendering/vulkan/renderer/vk_postprocess.cpp deleted file mode 100644 index b85d69a912f..00000000000 --- a/src/rendering/vulkan/renderer/vk_postprocess.cpp +++ /dev/null @@ -1,817 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_postprocess.h" -#include "vk_renderbuffers.h" -#include "vulkan/shaders/vk_shader.h" -#include "vulkan/system/vk_builders.h" -#include "vulkan/system/vk_framebuffer.h" -#include "vulkan/system/vk_buffers.h" -#include "vulkan/system/vk_swapchain.h" -#include "vulkan/renderer/vk_renderstate.h" -#include "vulkan/textures/vk_imagetransition.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/postprocessing/hw_postprocess.h" -#include "hwrenderer/postprocessing/hw_postprocess_cvars.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "hwrenderer/data/flatvertices.h" -#include "r_videoscale.h" -#include "w_wad.h" - -EXTERN_CVAR(Int, gl_dither_bpc) - -VkPostprocess::VkPostprocess() -{ -} - -VkPostprocess::~VkPostprocess() -{ -} - -void VkPostprocess::SetActiveRenderTarget() -{ - auto fb = GetVulkanFrameBuffer(); - auto buffers = fb->GetBuffers(); - - VkImageTransition imageTransition; - imageTransition.addImage(&buffers->PipelineImage[mCurrentPipelineImage], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false); - imageTransition.execute(fb->GetDrawCommands()); - - fb->GetRenderState()->SetRenderTarget(&buffers->PipelineImage[mCurrentPipelineImage], nullptr, buffers->GetWidth(), buffers->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_1_BIT); -} - -void VkPostprocess::PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) -{ - auto fb = GetVulkanFrameBuffer(); - int sceneWidth = fb->GetBuffers()->GetSceneWidth(); - int sceneHeight = fb->GetBuffers()->GetSceneHeight(); - - VkPPRenderState renderstate; - - hw_postprocess.Pass1(&renderstate, fixedcm, sceneWidth, sceneHeight); - SetActiveRenderTarget(); - afterBloomDrawEndScene2D(); - hw_postprocess.Pass2(&renderstate, fixedcm, sceneWidth, sceneHeight); -} - -void VkPostprocess::BlitSceneToPostprocess() -{ - auto fb = GetVulkanFrameBuffer(); - - fb->GetRenderState()->EndRenderPass(); - - auto buffers = fb->GetBuffers(); - auto cmdbuffer = fb->GetDrawCommands(); - - mCurrentPipelineImage = 0; - - VkImageTransition imageTransition; - imageTransition.addImage(&buffers->SceneColor, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false); - imageTransition.addImage(&buffers->PipelineImage[mCurrentPipelineImage], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true); - imageTransition.execute(fb->GetDrawCommands()); - - if (buffers->GetSceneSamples() != VK_SAMPLE_COUNT_1_BIT) - { - auto sceneColor = buffers->SceneColor.Image.get(); - VkImageResolve resolve = {}; - resolve.srcOffset = { 0, 0, 0 }; - resolve.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - resolve.srcSubresource.mipLevel = 0; - resolve.srcSubresource.baseArrayLayer = 0; - resolve.srcSubresource.layerCount = 1; - resolve.dstOffset = { 0, 0, 0 }; - resolve.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - resolve.dstSubresource.mipLevel = 0; - resolve.dstSubresource.baseArrayLayer = 0; - resolve.dstSubresource.layerCount = 1; - resolve.extent = { (uint32_t)sceneColor->width, (uint32_t)sceneColor->height, 1 }; - cmdbuffer->resolveImage( - sceneColor->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - buffers->PipelineImage[mCurrentPipelineImage].Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &resolve); - } - else - { - auto sceneColor = buffers->SceneColor.Image.get(); - VkImageBlit blit = {}; - blit.srcOffsets[0] = { 0, 0, 0 }; - blit.srcOffsets[1] = { sceneColor->width, sceneColor->height, 1 }; - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.mipLevel = 0; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = 1; - blit.dstOffsets[0] = { 0, 0, 0 }; - blit.dstOffsets[1] = { sceneColor->width, sceneColor->height, 1 }; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.mipLevel = 0; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = 1; - cmdbuffer->blitImage( - sceneColor->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - buffers->PipelineImage[mCurrentPipelineImage].Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit, VK_FILTER_NEAREST); - } -} - -void VkPostprocess::ImageTransitionScene(bool undefinedSrcLayout) -{ - auto fb = GetVulkanFrameBuffer(); - auto buffers = fb->GetBuffers(); - - VkImageTransition imageTransition; - imageTransition.addImage(&buffers->SceneColor, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, undefinedSrcLayout); - imageTransition.addImage(&buffers->SceneFog, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, undefinedSrcLayout); - imageTransition.addImage(&buffers->SceneNormal, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, undefinedSrcLayout); - imageTransition.addImage(&buffers->SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, undefinedSrcLayout); - imageTransition.execute(fb->GetDrawCommands()); -} - -void VkPostprocess::BlitCurrentToImage(VkTextureImage *dstimage, VkImageLayout finallayout) -{ - auto fb = GetVulkanFrameBuffer(); - - fb->GetRenderState()->EndRenderPass(); - - auto srcimage = &fb->GetBuffers()->PipelineImage[mCurrentPipelineImage]; - auto cmdbuffer = fb->GetDrawCommands(); - - VkImageTransition imageTransition0; - imageTransition0.addImage(srcimage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false); - imageTransition0.addImage(dstimage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true); - imageTransition0.execute(cmdbuffer); - - VkImageBlit blit = {}; - blit.srcOffsets[0] = { 0, 0, 0 }; - blit.srcOffsets[1] = { srcimage->Image->width, srcimage->Image->height, 1 }; - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.mipLevel = 0; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = 1; - blit.dstOffsets[0] = { 0, 0, 0 }; - blit.dstOffsets[1] = { dstimage->Image->width, dstimage->Image->height, 1 }; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.mipLevel = 0; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = 1; - cmdbuffer->blitImage( - srcimage->Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dstimage->Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit, VK_FILTER_NEAREST); - - VkImageTransition imageTransition1; - imageTransition1.addImage(dstimage, finallayout, false); - imageTransition1.execute(cmdbuffer); -} - -void VkPostprocess::DrawPresentTexture(const IntRect &box, bool applyGamma, bool screenshot) -{ - auto fb = GetVulkanFrameBuffer(); - - VkPPRenderState renderstate; - - if (!screenshot) // Already applied as we are actually copying the last frame here (GetScreenshotBuffer is called after swap) - hw_postprocess.customShaders.Run(&renderstate, "screen"); - - PresentUniforms uniforms; - if (!applyGamma) - { - uniforms.InvGamma = 1.0f; - uniforms.Contrast = 1.0f; - uniforms.Brightness = 0.0f; - uniforms.Saturation = 1.0f; - } - else - { - uniforms.InvGamma = 1.0f / clamp(Gamma, 0.1f, 4.f); - uniforms.Contrast = clamp(vid_contrast, 0.1f, 3.f); - uniforms.Brightness = clamp(vid_brightness, -0.8f, 0.8f); - uniforms.Saturation = clamp(vid_saturation, -15.0f, 15.f); - uniforms.GrayFormula = static_cast(gl_satformula); - } - uniforms.ColorScale = (gl_dither_bpc == -1) ? 255.0f : (float)((1 << gl_dither_bpc) - 1); - - if (screenshot) - { - uniforms.Scale = { screen->mScreenViewport.width / (float)fb->GetBuffers()->GetWidth(), screen->mScreenViewport.height / (float)fb->GetBuffers()->GetHeight() }; - uniforms.Offset = { 0.0f, 0.0f }; - } - else - { - uniforms.Scale = { screen->mScreenViewport.width / (float)fb->GetBuffers()->GetWidth(), -screen->mScreenViewport.height / (float)fb->GetBuffers()->GetHeight() }; - uniforms.Offset = { 0.0f, 1.0f }; - } - - if (applyGamma && fb->swapChain->IsHdrModeActive() && !screenshot) - { - uniforms.HdrMode = 1; - } - else - { - uniforms.HdrMode = 0; - } - - renderstate.Clear(); - renderstate.Shader = &hw_postprocess.present.Present; - renderstate.Uniforms.Set(uniforms); - renderstate.Viewport = box; - renderstate.SetInputCurrent(0, ViewportLinearScale() ? PPFilterMode::Linear : PPFilterMode::Nearest); - renderstate.SetInputTexture(1, &hw_postprocess.present.Dither, PPFilterMode::Nearest, PPWrapMode::Repeat); - if (screenshot) - renderstate.SetOutputNext(); - else - renderstate.SetOutputSwapChain(); - renderstate.SetNoBlend(); - renderstate.Draw(); -} - -void VkPostprocess::AmbientOccludeScene(float m5) -{ - auto fb = GetVulkanFrameBuffer(); - int sceneWidth = fb->GetBuffers()->GetSceneWidth(); - int sceneHeight = fb->GetBuffers()->GetSceneHeight(); - - VkPPRenderState renderstate; - hw_postprocess.ssao.Render(&renderstate, m5, sceneWidth, sceneHeight); - - ImageTransitionScene(false); -} - -void VkPostprocess::BlurScene(float gameinfobluramount) -{ - auto fb = GetVulkanFrameBuffer(); - int sceneWidth = fb->GetBuffers()->GetSceneWidth(); - int sceneHeight = fb->GetBuffers()->GetSceneHeight(); - - VkPPRenderState renderstate; - - auto vrmode = VRMode::GetVRMode(true); - int eyeCount = vrmode->mEyeCount; - for (int i = 0; i < eyeCount; ++i) - { - hw_postprocess.bloom.RenderBlur(&renderstate, sceneWidth, sceneHeight, gameinfobluramount); - if (eyeCount - i > 1) NextEye(eyeCount); - } -} - -void VkPostprocess::ClearTonemapPalette() -{ - hw_postprocess.tonemap.ClearTonemapPalette(); -} - -void VkPostprocess::UpdateShadowMap() -{ - if (screen->mShadowMap.PerformUpdate()) - { - VkPPRenderState renderstate; - hw_postprocess.shadowmap.Update(&renderstate); - - auto fb = GetVulkanFrameBuffer(); - auto buffers = fb->GetBuffers(); - - VkImageTransition imageTransition; - imageTransition.addImage(&buffers->Shadowmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); - imageTransition.execute(fb->GetDrawCommands()); - - screen->mShadowMap.FinishUpdate(); - } -} - -std::unique_ptr VkPostprocess::AllocateDescriptorSet(VulkanDescriptorSetLayout *layout) -{ - if (mDescriptorPool) - { - auto descriptors = mDescriptorPool->tryAllocate(layout); - if (descriptors) - return descriptors; - - GetVulkanFrameBuffer()->FrameDeleteList.DescriptorPools.push_back(std::move(mDescriptorPool)); - } - - DescriptorPoolBuilder builder; - builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 200); - builder.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4); - builder.setMaxSets(100); - mDescriptorPool = builder.create(GetVulkanFrameBuffer()->device); - mDescriptorPool->SetDebugName("VkPostprocess.mDescriptorPool"); - - return mDescriptorPool->allocate(layout); -} - -void VkPostprocess::RenderBuffersReset() -{ - mRenderPassSetup.clear(); -} - -VulkanSampler *VkPostprocess::GetSampler(PPFilterMode filter, PPWrapMode wrap) -{ - int index = (((int)filter) << 1) | (int)wrap; - auto &sampler = mSamplers[index]; - if (sampler) - return sampler.get(); - - SamplerBuilder builder; - builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST); - builder.setMinFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR); - builder.setMagFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR); - builder.setAddressMode(wrap == PPWrapMode::Clamp ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE : VK_SAMPLER_ADDRESS_MODE_REPEAT); - sampler = builder.create(GetVulkanFrameBuffer()->device); - sampler->SetDebugName("VkPostprocess.mSamplers"); - return sampler.get(); -} - -void VkPostprocess::NextEye(int eyeCount) -{ -} - -///////////////////////////////////////////////////////////////////////////// - -VkPPTexture::VkPPTexture(PPTexture *texture) -{ - auto fb = GetVulkanFrameBuffer(); - - VkFormat format; - int pixelsize; - switch (texture->Format) - { - default: - case PixelFormat::Rgba8: format = VK_FORMAT_R8G8B8A8_UNORM; pixelsize = 4; break; - case PixelFormat::Rgba16f: format = VK_FORMAT_R16G16B16A16_SFLOAT; pixelsize = 8; break; - case PixelFormat::R32f: format = VK_FORMAT_R32_SFLOAT; pixelsize = 4; break; - case PixelFormat::Rg16f: format = VK_FORMAT_R16G16_SFLOAT; pixelsize = 4; break; - case PixelFormat::Rgba16_snorm: format = VK_FORMAT_R16G16B16A16_SNORM; pixelsize = 8; break; - } - - ImageBuilder imgbuilder; - imgbuilder.setFormat(format); - imgbuilder.setSize(texture->Width, texture->Height); - if (texture->Data) - imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - else - imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - if (!imgbuilder.isFormatSupported(fb->device)) - I_FatalError("Vulkan device does not support the image format required by a postprocess texture\n"); - TexImage.Image = imgbuilder.create(fb->device); - TexImage.Image->SetDebugName("VkPPTexture"); - Format = format; - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(TexImage.Image.get(), format); - TexImage.View = viewbuilder.create(fb->device); - TexImage.View->SetDebugName("VkPPTextureView"); - - if (texture->Data) - { - size_t totalsize = texture->Width * texture->Height * pixelsize; - BufferBuilder stagingbuilder; - stagingbuilder.setSize(totalsize); - stagingbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - Staging = stagingbuilder.create(fb->device); - Staging->SetDebugName("VkPPTextureStaging"); - - VkImageTransition barrier0; - barrier0.addImage(&TexImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true); - barrier0.execute(fb->GetTransferCommands()); - - void *data = Staging->Map(0, totalsize); - memcpy(data, texture->Data.get(), totalsize); - Staging->Unmap(); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = 1; - region.imageExtent.depth = 1; - region.imageExtent.width = texture->Width; - region.imageExtent.height = texture->Height; - fb->GetTransferCommands()->copyBufferToImage(Staging->buffer, TexImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - VkImageTransition barrier1; - barrier1.addImage(&TexImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); - barrier1.execute(fb->GetTransferCommands()); - } - else - { - VkImageTransition barrier; - barrier.addImage(&TexImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - barrier.execute(fb->GetTransferCommands()); - } -} - -VkPPTexture::~VkPPTexture() -{ - if (auto fb = GetVulkanFrameBuffer()) - { - if (TexImage.Image) fb->FrameDeleteList.Images.push_back(std::move(TexImage.Image)); - if (TexImage.View) fb->FrameDeleteList.ImageViews.push_back(std::move(TexImage.View)); - if (TexImage.DepthOnlyView) fb->FrameDeleteList.ImageViews.push_back(std::move(TexImage.DepthOnlyView)); - if (TexImage.PPFramebuffer) fb->FrameDeleteList.Framebuffers.push_back(std::move(TexImage.PPFramebuffer)); - if (Staging) fb->FrameDeleteList.Buffers.push_back(std::move(Staging)); - } -} - -///////////////////////////////////////////////////////////////////////////// - -VkPPShader::VkPPShader(PPShader *shader) -{ - auto fb = GetVulkanFrameBuffer(); - - FString prolog; - if (!shader->Uniforms.empty()) - prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, -1); - prolog += shader->Defines; - - ShaderBuilder vertbuilder; - vertbuilder.setVertexShader(LoadShaderCode(shader->VertexShader, "", shader->Version)); - VertexShader = vertbuilder.create(shader->VertexShader.GetChars(), fb->device); - VertexShader->SetDebugName(shader->VertexShader.GetChars()); - - ShaderBuilder fragbuilder; - fragbuilder.setFragmentShader(LoadShaderCode(shader->FragmentShader, prolog, shader->Version)); - FragmentShader = fragbuilder.create(shader->FragmentShader.GetChars(), fb->device); - FragmentShader->SetDebugName(shader->FragmentShader.GetChars()); -} - -FString VkPPShader::LoadShaderCode(const FString &lumpName, const FString &defines, int version) -{ - int lump = Wads.CheckNumForFullName(lumpName); - if (lump == -1) I_FatalError("Unable to load '%s'", lumpName.GetChars()); - FString code = Wads.ReadLump(lump).GetString().GetChars(); - - FString patchedCode; - patchedCode.AppendFormat("#version %d\n", 450); - patchedCode << defines; - patchedCode << "#line 1\n"; - patchedCode << code; - return patchedCode; -} - -///////////////////////////////////////////////////////////////////////////// - -void VkPPRenderState::PushGroup(const FString &name) -{ - GetVulkanFrameBuffer()->PushGroup(name); -} - -void VkPPRenderState::PopGroup() -{ - GetVulkanFrameBuffer()->PopGroup(); -} - -void VkPPRenderState::Draw() -{ - auto fb = GetVulkanFrameBuffer(); - auto pp = fb->GetPostprocess(); - - fb->GetRenderState()->EndRenderPass(); - - VkPPRenderPassKey key; - key.BlendMode = BlendMode; - key.InputTextures = Textures.Size(); - key.Uniforms = Uniforms.Data.Size(); - key.Shader = GetVkShader(Shader); - key.SwapChain = (Output.Type == PPTextureType::SwapChain); - key.ShadowMapBuffers = ShadowMapBuffers; - if (Output.Type == PPTextureType::PPTexture) - key.OutputFormat = GetVkTexture(Output.Texture)->Format; - else if (Output.Type == PPTextureType::SwapChain) - key.OutputFormat = GetVulkanFrameBuffer()->swapChain->swapChainFormat.format; - else if (Output.Type == PPTextureType::ShadowMap) - key.OutputFormat = VK_FORMAT_R32_SFLOAT; - else - key.OutputFormat = VK_FORMAT_R16G16B16A16_SFLOAT; - - if (Output.Type == PPTextureType::SceneColor) - { - key.StencilTest = 1; - key.Samples = fb->GetBuffers()->GetSceneSamples(); - } - else - { - key.StencilTest = 0; - key.Samples = VK_SAMPLE_COUNT_1_BIT; - } - - auto &passSetup = pp->mRenderPassSetup[key]; - if (!passSetup) - passSetup.reset(new VkPPRenderPassSetup(key)); - - int framebufferWidth = 0, framebufferHeight = 0; - VulkanDescriptorSet *input = GetInput(passSetup.get(), Textures, ShadowMapBuffers); - VulkanFramebuffer *output = GetOutput(passSetup.get(), Output, key.StencilTest, framebufferWidth, framebufferHeight); - - RenderScreenQuad(passSetup.get(), input, output, framebufferWidth, framebufferHeight, Viewport.left, Viewport.top, Viewport.width, Viewport.height, Uniforms.Data.Data(), Uniforms.Data.Size(), key.StencilTest); - - // Advance to next PP texture if our output was sent there - if (Output.Type == PPTextureType::NextPipelineTexture) - { - pp->mCurrentPipelineImage = (pp->mCurrentPipelineImage + 1) % VkRenderBuffers::NumPipelineImages; - } -} - -void VkPPRenderState::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest) -{ - auto fb = GetVulkanFrameBuffer(); - auto cmdbuffer = fb->GetDrawCommands(); - - VkViewport viewport = { }; - viewport.x = x; - viewport.y = y; - viewport.width = width; - viewport.height = height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = { }; - scissor.offset.x = 0; - scissor.offset.y = 0; - scissor.extent.width = framebufferWidth; - scissor.extent.height = framebufferHeight; - - RenderPassBegin beginInfo; - beginInfo.setRenderPass(passSetup->RenderPass.get()); - beginInfo.setRenderArea(0, 0, framebufferWidth, framebufferHeight); - beginInfo.setFramebuffer(framebuffer); - beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - VkBuffer vertexBuffers[] = { static_cast(screen->mVertexData->GetBufferObjects().first)->mBuffer->buffer }; - VkDeviceSize offsets[] = { 0 }; - - cmdbuffer->beginRenderPass(beginInfo); - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->Pipeline.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->PipelineLayout.get(), 0, descriptorSet); - cmdbuffer->bindVertexBuffers(0, 1, vertexBuffers, offsets); - cmdbuffer->setViewport(0, 1, &viewport); - cmdbuffer->setScissor(0, 1, &scissor); - if (stencilTest) - cmdbuffer->setStencilReference(VK_STENCIL_FRONT_AND_BACK, screen->stencilValue); - if (pushConstantsSize > 0) - cmdbuffer->pushConstants(passSetup->PipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, pushConstantsSize, pushConstants); - cmdbuffer->draw(4, 1, FFlatVertexBuffer::PRESENT_INDEX, 0); - cmdbuffer->endRenderPass(); -} - -VulkanDescriptorSet *VkPPRenderState::GetInput(VkPPRenderPassSetup *passSetup, const TArray &textures, bool bindShadowMapBuffers) -{ - auto fb = GetVulkanFrameBuffer(); - auto pp = fb->GetPostprocess(); - auto descriptors = pp->AllocateDescriptorSet(passSetup->DescriptorLayout.get()); - descriptors->SetDebugName("VkPostprocess.descriptors"); - - WriteDescriptors write; - VkImageTransition imageTransition; - - for (unsigned int index = 0; index < textures.Size(); index++) - { - const PPTextureInput &input = textures[index]; - VulkanSampler *sampler = pp->GetSampler(input.Filter, input.Wrap); - VkTextureImage *tex = GetTexture(input.Type, input.Texture); - - write.addCombinedImageSampler(descriptors.get(), index, tex->DepthOnlyView ? tex->DepthOnlyView.get() : tex->View.get(), sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - imageTransition.addImage(tex, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); - } - - if (bindShadowMapBuffers) - { - write.addBuffer(descriptors.get(), LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightNodes->mBuffer.get()); - write.addBuffer(descriptors.get(), LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightLines->mBuffer.get()); - write.addBuffer(descriptors.get(), LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightList->mBuffer.get()); - } - - write.updateSets(fb->device); - imageTransition.execute(fb->GetDrawCommands()); - - VulkanDescriptorSet *set = descriptors.get(); - fb->FrameDeleteList.Descriptors.push_back(std::move(descriptors)); - return set; -} - -VulkanFramebuffer *VkPPRenderState::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight) -{ - auto fb = GetVulkanFrameBuffer(); - - VkTextureImage *tex = GetTexture(output.Type, output.Texture); - - VkImageView view; - std::unique_ptr *framebufferptr = nullptr; - int w, h; - if (tex) - { - VkImageTransition imageTransition; - imageTransition.addImage(tex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, output.Type == PPTextureType::NextPipelineTexture); - if (stencilTest) - imageTransition.addImage(&fb->GetBuffers()->SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false); - imageTransition.execute(fb->GetDrawCommands()); - - view = tex->View->view; - w = tex->Image->width; - h = tex->Image->height; - framebufferptr = &tex->PPFramebuffer; - } - else - { - view = fb->swapChain->swapChainImageViews[fb->presentImageIndex]; - framebufferptr = &fb->swapChain->framebuffers[fb->presentImageIndex]; - w = fb->swapChain->actualExtent.width; - h = fb->swapChain->actualExtent.height; - } - - auto &framebuffer = *framebufferptr; - if (!framebuffer) - { - FramebufferBuilder builder; - builder.setRenderPass(passSetup->RenderPass.get()); - builder.setSize(w, h); - builder.addAttachment(view); - if (stencilTest) - builder.addAttachment(fb->GetBuffers()->SceneDepthStencil.View.get()); - framebuffer = builder.create(GetVulkanFrameBuffer()->device); - } - - framebufferWidth = w; - framebufferHeight = h; - return framebuffer.get(); -} - -VkTextureImage *VkPPRenderState::GetTexture(const PPTextureType &type, PPTexture *pptexture) -{ - auto fb = GetVulkanFrameBuffer(); - - if (type == PPTextureType::CurrentPipelineTexture || type == PPTextureType::NextPipelineTexture) - { - int idx = fb->GetPostprocess()->mCurrentPipelineImage; - if (type == PPTextureType::NextPipelineTexture) - idx = (idx + 1) % VkRenderBuffers::NumPipelineImages; - - return &fb->GetBuffers()->PipelineImage[idx]; - } - else if (type == PPTextureType::PPTexture) - { - auto vktex = GetVkTexture(pptexture); - return &vktex->TexImage; - } - else if (type == PPTextureType::SceneColor) - { - return &fb->GetBuffers()->SceneColor; - } - else if (type == PPTextureType::SceneNormal) - { - return &fb->GetBuffers()->SceneNormal; - } - else if (type == PPTextureType::SceneFog) - { - return &fb->GetBuffers()->SceneFog; - } - else if (type == PPTextureType::SceneDepth) - { - return &fb->GetBuffers()->SceneDepthStencil; - } - else if (type == PPTextureType::ShadowMap) - { - return &fb->GetBuffers()->Shadowmap; - } - else if (type == PPTextureType::SwapChain) - { - return nullptr; - } - else - { - I_FatalError("VkPPRenderState::GetTexture not implemented yet for this texture type"); - return nullptr; - } -} - -VkPPShader *VkPPRenderState::GetVkShader(PPShader *shader) -{ - if (!shader->Backend) - shader->Backend = std::make_unique(shader); - return static_cast(shader->Backend.get()); -} - -VkPPTexture *VkPPRenderState::GetVkTexture(PPTexture *texture) -{ - if (!texture->Backend) - texture->Backend = std::make_unique(texture); - return static_cast(texture->Backend.get()); -} - -///////////////////////////////////////////////////////////////////////////// - -VkPPRenderPassSetup::VkPPRenderPassSetup(const VkPPRenderPassKey &key) -{ - CreateDescriptorLayout(key); - CreatePipelineLayout(key); - CreateRenderPass(key); - CreatePipeline(key); -} - -void VkPPRenderPassSetup::CreateDescriptorLayout(const VkPPRenderPassKey &key) -{ - DescriptorSetLayoutBuilder builder; - for (int i = 0; i < key.InputTextures; i++) - builder.addBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - if (key.ShadowMapBuffers) - { - builder.addBinding(LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.addBinding(LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.addBinding(LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - } - DescriptorLayout = builder.create(GetVulkanFrameBuffer()->device); - DescriptorLayout->SetDebugName("VkPPRenderPassSetup.DescriptorLayout"); -} - -void VkPPRenderPassSetup::CreatePipelineLayout(const VkPPRenderPassKey &key) -{ - PipelineLayoutBuilder builder; - builder.addSetLayout(DescriptorLayout.get()); - if (key.Uniforms > 0) - builder.addPushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0, key.Uniforms); - PipelineLayout = builder.create(GetVulkanFrameBuffer()->device); - PipelineLayout->SetDebugName("VkPPRenderPassSetup.PipelineLayout"); -} - -void VkPPRenderPassSetup::CreatePipeline(const VkPPRenderPassKey &key) -{ - GraphicsPipelineBuilder builder; - builder.addVertexShader(key.Shader->VertexShader.get()); - builder.addFragmentShader(key.Shader->FragmentShader.get()); - - builder.addVertexBufferBinding(0, sizeof(FFlatVertex)); - builder.addVertexAttribute(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(FFlatVertex, x)); - builder.addVertexAttribute(1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(FFlatVertex, u)); - builder.addDynamicState(VK_DYNAMIC_STATE_VIEWPORT); - builder.addDynamicState(VK_DYNAMIC_STATE_SCISSOR); - // Note: the actual values are ignored since we use dynamic viewport+scissor states - builder.setViewport(0.0f, 0.0f, 320.0f, 200.0f); - builder.setScissor(0.0f, 0.0f, 320.0f, 200.0f); - if (key.StencilTest) - { - builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE); - builder.setDepthStencilEnable(false, false, true); - builder.setStencil(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0); - } - builder.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); - builder.setBlendMode(key.BlendMode); - builder.setRasterizationSamples(key.Samples); - builder.setLayout(PipelineLayout.get()); - builder.setRenderPass(RenderPass.get()); - Pipeline = builder.create(GetVulkanFrameBuffer()->device); - Pipeline->SetDebugName("VkPPRenderPassSetup.Pipeline"); -} - -void VkPPRenderPassSetup::CreateRenderPass(const VkPPRenderPassKey &key) -{ - RenderPassBuilder builder; - if (key.SwapChain) - builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - else - builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - if (key.StencilTest) - { - builder.addDepthStencilAttachment( - GetVulkanFrameBuffer()->GetBuffers()->SceneDepthStencilFormat, key.Samples, - VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - } - - builder.addSubpass(); - builder.addSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - if (key.StencilTest) - { - builder.addSubpassDepthStencilAttachmentRef(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - builder.addExternalSubpassDependency( - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT); - } - else - { - builder.addExternalSubpassDependency( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT); - } - - RenderPass = builder.create(GetVulkanFrameBuffer()->device); - RenderPass->SetDebugName("VkPPRenderPassSetup.RenderPass"); -} diff --git a/src/rendering/vulkan/renderer/vk_postprocess.h b/src/rendering/vulkan/renderer/vk_postprocess.h deleted file mode 100644 index 53390e00e6e..00000000000 --- a/src/rendering/vulkan/renderer/vk_postprocess.h +++ /dev/null @@ -1,133 +0,0 @@ - -#pragma once - -#include -#include -#include - -#include "hwrenderer/postprocessing/hw_postprocess.h" -#include "vulkan/system/vk_objects.h" -#include "vulkan/system/vk_builders.h" -#include "vulkan/textures/vk_imagetransition.h" - -class FString; - -class VkPPShader; -class VkPPTexture; -class VkPPRenderPassSetup; -class PipelineBarrier; - -class VkPPRenderPassKey -{ -public: - VkPPShader *Shader; - int Uniforms; - int InputTextures; - PPBlendMode BlendMode; - VkFormat OutputFormat; - int SwapChain; - int ShadowMapBuffers; - int StencilTest; - VkSampleCountFlagBits Samples; - - bool operator<(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) < 0; } - bool operator==(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) == 0; } - bool operator!=(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) != 0; } -}; - -class VkPostprocess -{ -public: - VkPostprocess(); - ~VkPostprocess(); - - void RenderBuffersReset(); - - void SetActiveRenderTarget(); - void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D); - - void AmbientOccludeScene(float m5); - void BlurScene(float gameinfobluramount); - void ClearTonemapPalette(); - - void UpdateShadowMap(); - - void ImageTransitionScene(bool undefinedSrcLayout); - - void BlitSceneToPostprocess(); - void BlitCurrentToImage(VkTextureImage *image, VkImageLayout finallayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - void DrawPresentTexture(const IntRect &box, bool applyGamma, bool screenshot); - -private: - void NextEye(int eyeCount); - - std::unique_ptr AllocateDescriptorSet(VulkanDescriptorSetLayout *layout); - VulkanSampler *GetSampler(PPFilterMode filter, PPWrapMode wrap); - - std::array, 4> mSamplers; - std::map> mRenderPassSetup; - std::unique_ptr mDescriptorPool; - int mCurrentPipelineImage = 0; - - friend class VkPPRenderState; -}; - -class VkPPShader : public PPShaderBackend -{ -public: - VkPPShader(PPShader *shader); - - std::unique_ptr VertexShader; - std::unique_ptr FragmentShader; - -private: - FString LoadShaderCode(const FString &lumpname, const FString &defines, int version); -}; - -class VkPPTexture : public PPTextureBackend -{ -public: - VkPPTexture(PPTexture *texture); - ~VkPPTexture(); - - VkTextureImage TexImage; - std::unique_ptr Staging; - VkFormat Format; -}; - -class VkPPRenderPassSetup -{ -public: - VkPPRenderPassSetup(const VkPPRenderPassKey &key); - - std::unique_ptr DescriptorLayout; - std::unique_ptr PipelineLayout; - std::unique_ptr RenderPass; - std::unique_ptr Pipeline; - -private: - void CreateDescriptorLayout(const VkPPRenderPassKey &key); - void CreatePipelineLayout(const VkPPRenderPassKey &key); - void CreatePipeline(const VkPPRenderPassKey &key); - void CreateRenderPass(const VkPPRenderPassKey &key); -}; - -class VkPPRenderState : public PPRenderState -{ -public: - void PushGroup(const FString &name) override; - void PopGroup() override; - - void Draw() override; - -private: - void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest); - - VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray &textures, bool bindShadowMapBuffers); - VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight); - - VkPPShader *GetVkShader(PPShader *shader); - VkPPTexture *GetVkTexture(PPTexture *texture); - - VkTextureImage *GetTexture(const PPTextureType &type, PPTexture *tex); -}; diff --git a/src/rendering/vulkan/renderer/vk_renderbuffers.cpp b/src/rendering/vulkan/renderer/vk_renderbuffers.cpp deleted file mode 100644 index 80e619fe7b8..00000000000 --- a/src/rendering/vulkan/renderer/vk_renderbuffers.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_renderbuffers.h" -#include "vk_renderpass.h" -#include "vk_postprocess.h" -#include "vulkan/shaders/vk_shader.h" -#include "vulkan/system/vk_builders.h" -#include "vulkan/system/vk_framebuffer.h" -#include "hwrenderer/utility/hw_cvars.h" - -VkRenderBuffers::VkRenderBuffers() -{ -} - -VkRenderBuffers::~VkRenderBuffers() -{ -} - -VkSampleCountFlagBits VkRenderBuffers::GetBestSampleCount() -{ - auto fb = GetVulkanFrameBuffer(); - const auto &limits = fb->device->PhysicalDevice.Properties.limits; - VkSampleCountFlags deviceSampleCounts = limits.sampledImageColorSampleCounts & limits.sampledImageDepthSampleCounts & limits.sampledImageStencilSampleCounts; - - int requestedSamples = clamp((int)gl_multisample, 0, 64); - - int samples = 1; - VkSampleCountFlags bit = VK_SAMPLE_COUNT_1_BIT; - VkSampleCountFlags best = bit; - while (samples < requestedSamples) - { - if (deviceSampleCounts & bit) - { - best = bit; - } - samples <<= 1; - bit <<= 1; - } - return (VkSampleCountFlagBits)best; -} - -void VkRenderBuffers::BeginFrame(int width, int height, int sceneWidth, int sceneHeight) -{ - VkSampleCountFlagBits samples = GetBestSampleCount(); - - if (width != mWidth || height != mHeight || mSamples != samples) - { - auto fb = GetVulkanFrameBuffer(); - fb->GetRenderPassManager()->RenderBuffersReset(); - fb->GetPostprocess()->RenderBuffersReset(); - } - - if (width != mWidth || height != mHeight) - CreatePipeline(width, height); - - if (width != mWidth || height != mHeight || mSamples != samples) - CreateScene(width, height, samples); - - CreateShadowmap(); - - mWidth = width; - mHeight = height; - mSamples = samples; - mSceneWidth = sceneWidth; - mSceneHeight = sceneHeight; -} - -void VkRenderBuffers::CreatePipeline(int width, int height) -{ - auto fb = GetVulkanFrameBuffer(); - - for (int i = 0; i < NumPipelineImages; i++) - { - PipelineImage[i].reset(); - } - - VkImageTransition barrier; - for (int i = 0; i < NumPipelineImages; i++) - { - ImageBuilder builder; - builder.setSize(width, height); - builder.setFormat(VK_FORMAT_R16G16B16A16_SFLOAT); - builder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - PipelineImage[i].Image = builder.create(fb->device); - PipelineImage[i].Image->SetDebugName("VkRenderBuffers.PipelineImage"); - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(PipelineImage[i].Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT); - PipelineImage[i].View = viewbuilder.create(fb->device); - PipelineImage[i].View->SetDebugName("VkRenderBuffers.PipelineView"); - - barrier.addImage(&PipelineImage[i], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - } - barrier.execute(fb->GetDrawCommands()); -} - -void VkRenderBuffers::CreateScene(int width, int height, VkSampleCountFlagBits samples) -{ - auto fb = GetVulkanFrameBuffer(); - - SceneColor.reset(); - SceneDepthStencil.reset(); - SceneNormal.reset(); - SceneFog.reset(); - - CreateSceneColor(width, height, samples); - CreateSceneDepthStencil(width, height, samples); - CreateSceneNormal(width, height, samples); - CreateSceneFog(width, height, samples); - - VkImageTransition barrier; - barrier.addImage(&SceneColor, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - barrier.addImage(&SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true); - barrier.addImage(&SceneNormal, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - barrier.addImage(&SceneFog, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - barrier.execute(fb->GetDrawCommands()); -} - -void VkRenderBuffers::CreateSceneColor(int width, int height, VkSampleCountFlagBits samples) -{ - auto fb = GetVulkanFrameBuffer(); - - ImageBuilder builder; - builder.setSize(width, height); - builder.setSamples(samples); - builder.setFormat(VK_FORMAT_R16G16B16A16_SFLOAT); - builder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - SceneColor.Image = builder.create(fb->device); - SceneColor.Image->SetDebugName("VkRenderBuffers.SceneColor"); - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(SceneColor.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT); - SceneColor.View = viewbuilder.create(fb->device); - SceneColor.View->SetDebugName("VkRenderBuffers.SceneColorView"); -} - -void VkRenderBuffers::CreateSceneDepthStencil(int width, int height, VkSampleCountFlagBits samples) -{ - auto fb = GetVulkanFrameBuffer(); - - ImageBuilder builder; - builder.setSize(width, height); - builder.setSamples(samples); - builder.setFormat(SceneDepthStencilFormat); - builder.setUsage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - if (!builder.isFormatSupported(fb->device)) - { - SceneDepthStencilFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; - builder.setFormat(SceneDepthStencilFormat); - if (!builder.isFormatSupported(fb->device)) - { - I_FatalError("This device does not support any of the required depth stencil image formats."); - } - } - SceneDepthStencil.Image = builder.create(fb->device); - SceneDepthStencil.Image->SetDebugName("VkRenderBuffers.SceneDepthStencil"); - SceneDepthStencil.AspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(SceneDepthStencil.Image.get(), SceneDepthStencilFormat, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); - SceneDepthStencil.View = viewbuilder.create(fb->device); - SceneDepthStencil.View->SetDebugName("VkRenderBuffers.SceneDepthStencilView"); - - viewbuilder.setImage(SceneDepthStencil.Image.get(), SceneDepthStencilFormat, VK_IMAGE_ASPECT_DEPTH_BIT); - SceneDepthStencil.DepthOnlyView = viewbuilder.create(fb->device); - SceneDepthStencil.DepthOnlyView->SetDebugName("VkRenderBuffers.SceneDepthView"); -} - -void VkRenderBuffers::CreateSceneFog(int width, int height, VkSampleCountFlagBits samples) -{ - auto fb = GetVulkanFrameBuffer(); - - ImageBuilder builder; - builder.setSize(width, height); - builder.setSamples(samples); - builder.setFormat(VK_FORMAT_R8G8B8A8_UNORM); - builder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - SceneFog.Image = builder.create(fb->device); - SceneFog.Image->SetDebugName("VkRenderBuffers.SceneFog"); - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(SceneFog.Image.get(), VK_FORMAT_R8G8B8A8_UNORM); - SceneFog.View = viewbuilder.create(fb->device); - SceneFog.View->SetDebugName("VkRenderBuffers.SceneFogView"); -} - -void VkRenderBuffers::CreateSceneNormal(int width, int height, VkSampleCountFlagBits samples) -{ - auto fb = GetVulkanFrameBuffer(); - - ImageBuilder builder; - builder.setSize(width, height); - builder.setSamples(samples); - builder.setFormat(VK_FORMAT_A2R10G10B10_UNORM_PACK32); - builder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - SceneNormal.Image = builder.create(fb->device); - SceneNormal.Image->SetDebugName("VkRenderBuffers.SceneNormal"); - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(SceneNormal.Image.get(), VK_FORMAT_A2R10G10B10_UNORM_PACK32); - SceneNormal.View = viewbuilder.create(fb->device); - SceneNormal.View->SetDebugName("VkRenderBuffers.SceneNormalView"); -} - -void VkRenderBuffers::CreateShadowmap() -{ - if (Shadowmap.Image && Shadowmap.Image->width == gl_shadowmap_quality) - return; - - Shadowmap.reset(); - - auto fb = GetVulkanFrameBuffer(); - - ImageBuilder builder; - builder.setSize(gl_shadowmap_quality, 1024); - builder.setFormat(VK_FORMAT_R32_SFLOAT); - builder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - Shadowmap.Image = builder.create(fb->device); - Shadowmap.Image->SetDebugName("VkRenderBuffers.Shadowmap"); - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(Shadowmap.Image.get(), VK_FORMAT_R32_SFLOAT); - Shadowmap.View = viewbuilder.create(fb->device); - Shadowmap.View->SetDebugName("VkRenderBuffers.ShadowmapView"); - - VkImageTransition barrier; - barrier.addImage(&Shadowmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true); - barrier.execute(fb->GetDrawCommands()); - - if (!ShadowmapSampler) - { - SamplerBuilder builder; - builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST); - builder.setMinFilter(VK_FILTER_NEAREST); - builder.setMagFilter(VK_FILTER_NEAREST); - builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); - ShadowmapSampler = builder.create(fb->device); - ShadowmapSampler->SetDebugName("VkRenderBuffers.ShadowmapSampler"); - } -} diff --git a/src/rendering/vulkan/renderer/vk_renderbuffers.h b/src/rendering/vulkan/renderer/vk_renderbuffers.h deleted file mode 100644 index b1df96b021f..00000000000 --- a/src/rendering/vulkan/renderer/vk_renderbuffers.h +++ /dev/null @@ -1,49 +0,0 @@ - -#pragma once - -#include "vulkan/system/vk_objects.h" -#include "vulkan/textures/vk_imagetransition.h" - -class VkRenderBuffers -{ -public: - VkRenderBuffers(); - ~VkRenderBuffers(); - - void BeginFrame(int width, int height, int sceneWidth, int sceneHeight); - - int GetWidth() const { return mWidth; } - int GetHeight() const { return mHeight; } - int GetSceneWidth() const { return mSceneWidth; } - int GetSceneHeight() const { return mSceneHeight; } - VkSampleCountFlagBits GetSceneSamples() const { return mSamples; } - - VkTextureImage SceneColor; - VkTextureImage SceneDepthStencil; - VkTextureImage SceneNormal; - VkTextureImage SceneFog; - - VkFormat SceneDepthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT; - - static const int NumPipelineImages = 2; - VkTextureImage PipelineImage[NumPipelineImages]; - - VkTextureImage Shadowmap; - std::unique_ptr ShadowmapSampler; - -private: - void CreatePipeline(int width, int height); - void CreateScene(int width, int height, VkSampleCountFlagBits samples); - void CreateSceneColor(int width, int height, VkSampleCountFlagBits samples); - void CreateSceneDepthStencil(int width, int height, VkSampleCountFlagBits samples); - void CreateSceneFog(int width, int height, VkSampleCountFlagBits samples); - void CreateSceneNormal(int width, int height, VkSampleCountFlagBits samples); - void CreateShadowmap(); - VkSampleCountFlagBits GetBestSampleCount(); - - int mWidth = 0; - int mHeight = 0; - int mSceneWidth = 0; - int mSceneHeight = 0; - VkSampleCountFlagBits mSamples = VK_SAMPLE_COUNT_1_BIT; -}; diff --git a/src/rendering/vulkan/renderer/vk_renderpass.cpp b/src/rendering/vulkan/renderer/vk_renderpass.cpp deleted file mode 100644 index a5d1d9c80fb..00000000000 --- a/src/rendering/vulkan/renderer/vk_renderpass.cpp +++ /dev/null @@ -1,433 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_renderpass.h" -#include "vk_renderbuffers.h" -#include "vk_renderstate.h" -#include "vulkan/textures/vk_samplers.h" -#include "vulkan/shaders/vk_shader.h" -#include "vulkan/system/vk_builders.h" -#include "vulkan/system/vk_framebuffer.h" -#include "vulkan/system/vk_buffers.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/scene/hw_viewpointuniforms.h" -#include "rendering/2d/v_2ddrawer.h" - -VkRenderPassManager::VkRenderPassManager() -{ -} - -VkRenderPassManager::~VkRenderPassManager() -{ - DynamicSet.reset(); // Needed since it must come before destruction of DynamicDescriptorPool -} - -void VkRenderPassManager::Init() -{ - CreateDynamicSetLayout(); - CreateDescriptorPool(); - CreateDynamicSet(); - CreateNullTexture(); -} - -void VkRenderPassManager::RenderBuffersReset() -{ - RenderPassSetup.clear(); -} - -void VkRenderPassManager::TextureSetPoolReset() -{ - if (auto fb = GetVulkanFrameBuffer()) - { - auto &deleteList = fb->FrameDeleteList; - - for (auto &desc : TextureDescriptorPools) - { - deleteList.DescriptorPools.push_back(std::move(desc)); - } - } - NullTextureDescriptorSet.reset(); - TextureDescriptorPools.clear(); - TextureDescriptorSetsLeft = 0; - TextureDescriptorsLeft = 0; -} - -VkRenderPassSetup *VkRenderPassManager::GetRenderPass(const VkRenderPassKey &key) -{ - auto &item = RenderPassSetup[key]; - if (!item) - item.reset(new VkRenderPassSetup(key)); - return item.get(); -} - -int VkRenderPassManager::GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) -{ - for (size_t i = 0; i < VertexFormats.size(); i++) - { - const auto &f = VertexFormats[i]; - if (f.Attrs.size() == (size_t)numAttributes && f.NumBindingPoints == numBindingPoints && f.Stride == stride) - { - bool matches = true; - for (int j = 0; j < numAttributes; j++) - { - if (memcmp(&f.Attrs[j], &attrs[j], sizeof(FVertexBufferAttribute)) != 0) - { - matches = false; - break; - } - } - - if (matches) - return (int)i; - } - } - - VkVertexFormat fmt; - fmt.NumBindingPoints = numBindingPoints; - fmt.Stride = stride; - fmt.UseVertexData = 0; - for (int j = 0; j < numAttributes; j++) - { - if (attrs[j].location == VATTR_COLOR) - fmt.UseVertexData |= 1; - else if (attrs[j].location == VATTR_NORMAL) - fmt.UseVertexData |= 2; - fmt.Attrs.push_back(attrs[j]); - } - VertexFormats.push_back(fmt); - return (int)VertexFormats.size() - 1; -} - -VkVertexFormat *VkRenderPassManager::GetVertexFormat(int index) -{ - return &VertexFormats[index]; -} - -void VkRenderPassManager::CreateDynamicSetLayout() -{ - DescriptorSetLayoutBuilder builder; - builder.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); - builder.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.addBinding(2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); - builder.addBinding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); - builder.addBinding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - DynamicSetLayout = builder.create(GetVulkanFrameBuffer()->device); - DynamicSetLayout->SetDebugName("VkRenderPassManager.DynamicSetLayout"); -} - -VulkanDescriptorSetLayout *VkRenderPassManager::GetTextureSetLayout(int numLayers) -{ - if (TextureSetLayouts.size() < (size_t)numLayers) - TextureSetLayouts.resize(numLayers); - - auto &layout = TextureSetLayouts[numLayers - 1]; - if (layout) - return layout.get(); - - DescriptorSetLayoutBuilder builder; - for (int i = 0; i < numLayers; i++) - { - builder.addBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - } - layout = builder.create(GetVulkanFrameBuffer()->device); - layout->SetDebugName("VkRenderPassManager.TextureSetLayout"); - return layout.get(); -} - -VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(int numLayers) -{ - if (PipelineLayouts.size() <= (size_t)numLayers) - PipelineLayouts.resize(numLayers + 1); - - auto &layout = PipelineLayouts[numLayers]; - if (layout) - return layout.get(); - - PipelineLayoutBuilder builder; - builder.addSetLayout(DynamicSetLayout.get()); - if (numLayers != 0) - builder.addSetLayout(GetTextureSetLayout(numLayers)); - builder.addPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants)); - layout = builder.create(GetVulkanFrameBuffer()->device); - layout->SetDebugName("VkRenderPassManager.PipelineLayout"); - return layout.get(); -} - -void VkRenderPassManager::CreateDescriptorPool() -{ - DescriptorPoolBuilder builder; - builder.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 3); - builder.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); - builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1); - builder.setMaxSets(1); - DynamicDescriptorPool = builder.create(GetVulkanFrameBuffer()->device); - DynamicDescriptorPool->SetDebugName("VkRenderPassManager.DynamicDescriptorPool"); -} - -void VkRenderPassManager::CreateDynamicSet() -{ - DynamicSet = DynamicDescriptorPool->allocate(DynamicSetLayout.get()); - if (!DynamicSet) - I_FatalError("CreateDynamicSet failed.\n"); -} - -void VkRenderPassManager::CreateNullTexture() -{ - auto fb = GetVulkanFrameBuffer(); - - ImageBuilder imgbuilder; - imgbuilder.setFormat(VK_FORMAT_R8G8B8A8_UNORM); - imgbuilder.setSize(1, 1); - imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT); - NullTexture = imgbuilder.create(fb->device); - NullTexture->SetDebugName("VkRenderPassManager.NullTexture"); - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(NullTexture.get(), VK_FORMAT_R8G8B8A8_UNORM); - NullTextureView = viewbuilder.create(fb->device); - NullTextureView->SetDebugName("VkRenderPassManager.NullTextureView"); - - PipelineBarrier barrier; - barrier.addImage(NullTexture.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT); - barrier.execute(fb->GetTransferCommands(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); -} - -VulkanDescriptorSet* VkRenderPassManager::GetNullTextureDescriptorSet() -{ - if (!NullTextureDescriptorSet) - { - NullTextureDescriptorSet = AllocateTextureDescriptorSet(1); - - auto fb = GetVulkanFrameBuffer(); - WriteDescriptors update; - update.addCombinedImageSampler(NullTextureDescriptorSet.get(), 0, NullTextureView.get(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - update.updateSets(fb->device); - } - - return NullTextureDescriptorSet.get(); -} - -void VkRenderPassManager::UpdateDynamicSet() -{ - auto fb = GetVulkanFrameBuffer(); - - // In some rare cases drawing commands may already have been created before VulkanFrameBuffer::BeginFrame is called. - // Make sure there there are no active command buffers using DynamicSet when we update it: - fb->GetRenderState()->EndRenderPass(); - fb->WaitForCommands(false); - - WriteDescriptors update; - update.addBuffer(DynamicSet.get(), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->ViewpointUBO->mBuffer.get(), 0, sizeof(HWViewpointUniforms)); - update.addBuffer(DynamicSet.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightBufferSSO->mBuffer.get()); - update.addBuffer(DynamicSet.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->MatrixBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(MatricesUBO)); - update.addBuffer(DynamicSet.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->StreamBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(StreamUBO)); - update.addCombinedImageSampler(DynamicSet.get(), 4, fb->GetBuffers()->Shadowmap.View.get(), fb->GetBuffers()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - update.updateSets(fb->device); -} - -std::unique_ptr VkRenderPassManager::AllocateTextureDescriptorSet(int numLayers) -{ - if (TextureDescriptorSetsLeft == 0 || TextureDescriptorsLeft < numLayers) - { - TextureDescriptorSetsLeft = 1000; - TextureDescriptorsLeft = 2000; - - DescriptorPoolBuilder builder; - builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, TextureDescriptorsLeft); - builder.setMaxSets(TextureDescriptorSetsLeft); - TextureDescriptorPools.push_back(builder.create(GetVulkanFrameBuffer()->device)); - TextureDescriptorPools.back()->SetDebugName("VkRenderPassManager.TextureDescriptorPool"); - } - - TextureDescriptorSetsLeft--; - TextureDescriptorsLeft -= numLayers; - return TextureDescriptorPools.back()->allocate(GetTextureSetLayout(numLayers)); -} - -///////////////////////////////////////////////////////////////////////////// - -VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key) : PassKey(key) -{ -} - -std::unique_ptr VkRenderPassSetup::CreateRenderPass(int clearTargets) -{ - auto buffers = GetVulkanFrameBuffer()->GetBuffers(); - - VkFormat drawBufferFormats[] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_A2R10G10B10_UNORM_PACK32 }; - - RenderPassBuilder builder; - - builder.addAttachment( - PassKey.DrawBufferFormat, (VkSampleCountFlagBits)PassKey.Samples, - (clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - for (int i = 1; i < PassKey.DrawBuffers; i++) - { - builder.addAttachment( - drawBufferFormats[i], buffers->GetSceneSamples(), - (clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } - if (PassKey.DepthStencil) - { - builder.addDepthStencilAttachment( - buffers->SceneDepthStencilFormat, PassKey.DrawBufferFormat == VK_FORMAT_R8G8B8A8_UNORM ? VK_SAMPLE_COUNT_1_BIT : buffers->GetSceneSamples(), - (clearTargets & CT_Depth) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - (clearTargets & CT_Stencil) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - } - builder.addSubpass(); - for (int i = 0; i < PassKey.DrawBuffers; i++) - builder.addSubpassColorAttachmentRef(i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - if (PassKey.DepthStencil) - { - builder.addSubpassDepthStencilAttachmentRef(PassKey.DrawBuffers, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - builder.addExternalSubpassDependency( - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); - } - else - { - builder.addExternalSubpassDependency( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); - } - auto renderpass = builder.create(GetVulkanFrameBuffer()->device); - renderpass->SetDebugName("VkRenderPassSetup.RenderPass"); - return renderpass; -} - -VulkanRenderPass *VkRenderPassSetup::GetRenderPass(int clearTargets) -{ - if (!RenderPasses[clearTargets]) - RenderPasses[clearTargets] = CreateRenderPass(clearTargets); - return RenderPasses[clearTargets].get(); -} - -VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key) -{ - auto &item = Pipelines[key]; - if (!item) - item = CreatePipeline(key); - return item.get(); -} - -std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key) -{ - auto fb = GetVulkanFrameBuffer(); - GraphicsPipelineBuilder builder; - - VkShaderProgram *program; - if (key.SpecialEffect != EFF_NONE) - { - program = fb->GetShaderManager()->GetEffect(key.SpecialEffect, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); - } - else - { - program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); - } - builder.addVertexShader(program->vert.get()); - builder.addFragmentShader(program->frag.get()); - - const VkVertexFormat &vfmt = *fb->GetRenderPassManager()->GetVertexFormat(key.VertexFormat); - - for (int i = 0; i < vfmt.NumBindingPoints; i++) - builder.addVertexBufferBinding(i, vfmt.Stride); - - const static VkFormat vkfmts[] = { - VK_FORMAT_R32G32B32A32_SFLOAT, - VK_FORMAT_R32G32B32_SFLOAT, - VK_FORMAT_R32G32_SFLOAT, - VK_FORMAT_R32_SFLOAT, - VK_FORMAT_R8G8B8A8_UNORM, - VK_FORMAT_A2B10G10R10_SNORM_PACK32 - }; - - bool inputLocations[6] = { false, false, false, false, false, false }; - - for (size_t i = 0; i < vfmt.Attrs.size(); i++) - { - const auto &attr = vfmt.Attrs[i]; - builder.addVertexAttribute(attr.location, attr.binding, vkfmts[attr.format], attr.offset); - inputLocations[attr.location] = true; - } - - // Vulkan requires an attribute binding for each location specified in the shader - for (int i = 0; i < 6; i++) - { - if (!inputLocations[i]) - builder.addVertexAttribute(i, 0, VK_FORMAT_R32G32B32_SFLOAT, 0); - } - - builder.addDynamicState(VK_DYNAMIC_STATE_VIEWPORT); - builder.addDynamicState(VK_DYNAMIC_STATE_SCISSOR); - // builder.addDynamicState(VK_DYNAMIC_STATE_LINE_WIDTH); - builder.addDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS); - // builder.addDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS); - // builder.addDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS); - // builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK); - // builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); - builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE); - - // Note: the actual values are ignored since we use dynamic viewport+scissor states - builder.setViewport(0.0f, 0.0f, 320.0f, 200.0f); - builder.setScissor(0, 0, 320.0f, 200.0f); - - static const VkPrimitiveTopology vktopology[] = { - VK_PRIMITIVE_TOPOLOGY_POINT_LIST, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP - }; - - static const VkStencilOp op2vk[] = { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_DECREMENT_AND_CLAMP }; - static const VkCompareOp depthfunc2vk[] = { VK_COMPARE_OP_LESS, VK_COMPARE_OP_LESS_OR_EQUAL, VK_COMPARE_OP_ALWAYS }; - - builder.setTopology(vktopology[key.DrawType]); - builder.setDepthStencilEnable(key.DepthTest, key.DepthWrite, key.StencilTest); - builder.setDepthFunc(depthfunc2vk[key.DepthFunc]); - builder.setDepthClampEnable(key.DepthClamp); - builder.setDepthBias(key.DepthBias, 0.0f, 0.0f, 0.0f); - - // Note: CCW and CW is intentionally swapped here because the vulkan and opengl coordinate systems differ. - // main.vp addresses this by patching up gl_Position.z, which has the side effect of flipping the sign of the front face calculations. - builder.setCull(key.CullMode == Cull_None ? VK_CULL_MODE_NONE : VK_CULL_MODE_BACK_BIT, key.CullMode == Cull_CW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE); - - builder.setColorWriteMask((VkColorComponentFlags)key.ColorMask); - builder.setStencil(VK_STENCIL_OP_KEEP, op2vk[key.StencilPassOp], VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0); - builder.setBlendMode(key.RenderStyle); - builder.setSubpassColorAttachmentCount(PassKey.DrawBuffers); - builder.setRasterizationSamples((VkSampleCountFlagBits)PassKey.Samples); - - builder.setLayout(fb->GetRenderPassManager()->GetPipelineLayout(key.NumTextureLayers)); - builder.setRenderPass(GetRenderPass(0)); - auto pipeline = builder.create(fb->device); - pipeline->SetDebugName("VkRenderPassSetup.Pipeline"); - return pipeline; -} diff --git a/src/rendering/vulkan/renderer/vk_renderpass.h b/src/rendering/vulkan/renderer/vk_renderpass.h deleted file mode 100644 index 47b21769a0c..00000000000 --- a/src/rendering/vulkan/renderer/vk_renderpass.h +++ /dev/null @@ -1,122 +0,0 @@ - -#pragma once - -#include "vulkan/system/vk_objects.h" -#include "r_data/renderstyle.h" -#include "hwrenderer/data/buffers.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include -#include - -class VKDataBuffer; - -class VkPipelineKey -{ -public: - FRenderStyle RenderStyle; - int SpecialEffect; - int EffectState; - int AlphaTest; - int DepthWrite; - int DepthTest; - int DepthFunc; - int DepthClamp; - int DepthBias; - int StencilTest; - int StencilPassOp; - int ColorMask; - int CullMode; - int VertexFormat; - int DrawType; - int NumTextureLayers; - - bool operator<(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) < 0; } - bool operator==(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) == 0; } - bool operator!=(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) != 0; } -}; - -class VkRenderPassKey -{ -public: - int DepthStencil; - int Samples; - int DrawBuffers; - VkFormat DrawBufferFormat; - - bool operator<(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) < 0; } - bool operator==(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) == 0; } - bool operator!=(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) != 0; } -}; - -class VkRenderPassSetup -{ -public: - VkRenderPassSetup(const VkRenderPassKey &key); - - VulkanRenderPass *GetRenderPass(int clearTargets); - VulkanPipeline *GetPipeline(const VkPipelineKey &key); - - VkRenderPassKey PassKey; - std::unique_ptr RenderPasses[8]; - std::map> Pipelines; - -private: - std::unique_ptr CreateRenderPass(int clearTargets); - std::unique_ptr CreatePipeline(const VkPipelineKey &key); -}; - -class VkVertexFormat -{ -public: - int NumBindingPoints; - size_t Stride; - std::vector Attrs; - int UseVertexData; -}; - -class VkRenderPassManager -{ -public: - VkRenderPassManager(); - ~VkRenderPassManager(); - - void Init(); - void RenderBuffersReset(); - void UpdateDynamicSet(); - void TextureSetPoolReset(); - - VkRenderPassSetup *GetRenderPass(const VkRenderPassKey &key); - int GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs); - - VkVertexFormat *GetVertexFormat(int index); - - std::unique_ptr AllocateTextureDescriptorSet(int numLayers); - VulkanPipelineLayout* GetPipelineLayout(int numLayers); - - VulkanDescriptorSet* GetNullTextureDescriptorSet(); - - std::unique_ptr DynamicSetLayout; - std::map> RenderPassSetup; - - std::unique_ptr DynamicSet; - -private: - void CreateDynamicSetLayout(); - void CreateDescriptorPool(); - void CreateDynamicSet(); - void CreateNullTexture(); - - VulkanDescriptorSetLayout *GetTextureSetLayout(int numLayers); - - int TextureDescriptorSetsLeft = 0; - int TextureDescriptorsLeft = 0; - std::vector> TextureDescriptorPools; - std::unique_ptr DynamicDescriptorPool; - std::vector> TextureSetLayouts; - std::vector> PipelineLayouts; - std::vector VertexFormats; - - std::unique_ptr NullTexture; - std::unique_ptr NullTextureView; - std::unique_ptr NullTextureDescriptorSet; -}; diff --git a/src/rendering/vulkan/renderer/vk_streambuffer.cpp b/src/rendering/vulkan/renderer/vk_streambuffer.cpp deleted file mode 100644 index b393867c395..00000000000 --- a/src/rendering/vulkan/renderer/vk_streambuffer.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_renderstate.h" -#include "vulkan/system/vk_framebuffer.h" -#include "vulkan/system/vk_builders.h" -#include "vulkan/renderer/vk_streambuffer.h" - -VkStreamBuffer::VkStreamBuffer(size_t structSize, size_t count) -{ - mBlockSize = static_cast((structSize + screen->uniformblockalignment - 1) / screen->uniformblockalignment * screen->uniformblockalignment); - - UniformBuffer = (VKDataBuffer*)GetVulkanFrameBuffer()->CreateDataBuffer(-1, false, false); - UniformBuffer->SetData(mBlockSize * count, nullptr, false); -} - -VkStreamBuffer::~VkStreamBuffer() -{ - delete UniformBuffer; -} - -uint32_t VkStreamBuffer::NextStreamDataBlock() -{ - mStreamDataOffset += mBlockSize; - if (mStreamDataOffset + (size_t)mBlockSize >= UniformBuffer->Size()) - { - mStreamDataOffset = 0; - return 0xffffffff; - } - return mStreamDataOffset; -} - -///////////////////////////////////////////////////////////////////////////// - -VkStreamBufferWriter::VkStreamBufferWriter() -{ - mBuffer = GetVulkanFrameBuffer()->StreamBuffer; -} - -bool VkStreamBufferWriter::Write(const StreamData& data) -{ - mDataIndex++; - if (mDataIndex == MAX_STREAM_DATA) - { - mDataIndex = 0; - mStreamDataOffset = mBuffer->NextStreamDataBlock(); - if (mStreamDataOffset == 0xffffffff) - return false; - } - uint8_t* ptr = (uint8_t*)mBuffer->UniformBuffer->Memory(); - memcpy(ptr + mStreamDataOffset + sizeof(StreamData) * mDataIndex, &data, sizeof(StreamData)); - return true; -} - -void VkStreamBufferWriter::Reset() -{ - mDataIndex = MAX_STREAM_DATA - 1; - mStreamDataOffset = 0; - mBuffer->Reset(); -} - -///////////////////////////////////////////////////////////////////////////// - -VkMatrixBufferWriter::VkMatrixBufferWriter() -{ - mBuffer = GetVulkanFrameBuffer()->MatrixBuffer; - mIdentityMatrix.loadIdentity(); -} - -template -static void BufferedSet(bool& modified, T& dst, const T& src) -{ - if (dst == src) - return; - dst = src; - modified = true; -} - -static void BufferedSet(bool& modified, VSMatrix& dst, const VSMatrix& src) -{ - if (memcmp(dst.get(), src.get(), sizeof(FLOATTYPE) * 16) == 0) - return; - dst = src; - modified = true; -} - -bool VkMatrixBufferWriter::Write(const VSMatrix& modelMatrix, bool modelMatrixEnabled, const VSMatrix& textureMatrix, bool textureMatrixEnabled) -{ - bool modified = (mOffset == 0); // always modified first call - - if (modelMatrixEnabled) - { - BufferedSet(modified, mMatrices.ModelMatrix, modelMatrix); - if (modified) - mMatrices.NormalModelMatrix.computeNormalMatrix(modelMatrix); - } - else - { - BufferedSet(modified, mMatrices.ModelMatrix, mIdentityMatrix); - BufferedSet(modified, mMatrices.NormalModelMatrix, mIdentityMatrix); - } - - if (textureMatrixEnabled) - { - BufferedSet(modified, mMatrices.TextureMatrix, textureMatrix); - } - else - { - BufferedSet(modified, mMatrices.TextureMatrix, mIdentityMatrix); - } - - if (modified) - { - mOffset = mBuffer->NextStreamDataBlock(); - if (mOffset == 0xffffffff) - return false; - - uint8_t* ptr = (uint8_t*)mBuffer->UniformBuffer->Memory(); - memcpy(ptr + mOffset, &mMatrices, sizeof(MatricesUBO)); - } - - return true; -} - -void VkMatrixBufferWriter::Reset() -{ - mOffset = 0; - mBuffer->Reset(); -} diff --git a/src/rendering/vulkan/renderer/vk_streambuffer.h b/src/rendering/vulkan/renderer/vk_streambuffer.h deleted file mode 100644 index 21c15867a23..00000000000 --- a/src/rendering/vulkan/renderer/vk_streambuffer.h +++ /dev/null @@ -1,58 +0,0 @@ - -#pragma once - -#include "vulkan/system/vk_buffers.h" -#include "vulkan/shaders/vk_shader.h" - -class VkStreamBuffer; -class VkMatrixBuffer; - -class VkStreamBufferWriter -{ -public: - VkStreamBufferWriter(); - - bool Write(const StreamData& data); - void Reset(); - - uint32_t DataIndex() const { return mDataIndex; } - uint32_t StreamDataOffset() const { return mStreamDataOffset; } - -private: - VkStreamBuffer* mBuffer; - uint32_t mDataIndex = MAX_STREAM_DATA - 1; - uint32_t mStreamDataOffset = 0; -}; - -class VkMatrixBufferWriter -{ -public: - VkMatrixBufferWriter(); - - bool Write(const VSMatrix& modelMatrix, bool modelMatrixEnabled, const VSMatrix& textureMatrix, bool textureMatrixEnabled); - void Reset(); - - uint32_t Offset() const { return mOffset; } - -private: - VkStreamBuffer* mBuffer; - MatricesUBO mMatrices = {}; - VSMatrix mIdentityMatrix; - uint32_t mOffset = 0; -}; - -class VkStreamBuffer -{ -public: - VkStreamBuffer(size_t structSize, size_t count); - ~VkStreamBuffer(); - - uint32_t NextStreamDataBlock(); - void Reset() { mStreamDataOffset = 0; } - - VKDataBuffer* UniformBuffer = nullptr; - -private: - uint32_t mBlockSize = 0; - uint32_t mStreamDataOffset = 0; -}; diff --git a/src/rendering/vulkan/shaders/vk_shader.cpp b/src/rendering/vulkan/shaders/vk_shader.cpp deleted file mode 100644 index 32e13c2dfff..00000000000 --- a/src/rendering/vulkan/shaders/vk_shader.cpp +++ /dev/null @@ -1,360 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_shader.h" -#include "vulkan/system/vk_builders.h" -#include "hwrenderer/utility/hw_shaderpatcher.h" -#include "w_wad.h" -#include "doomerrors.h" -#include - -VkShaderManager::VkShaderManager(VulkanDevice *device) : device(device) -{ - ShInitialize(); - - const char *mainvp = "shaders/glsl/main.vp"; - const char *mainfp = "shaders/glsl/main.fp"; - - for (int j = 0; j < MAX_PASS_TYPES; j++) - { - bool gbufferpass = j; - for (int i = 0; defaultshaders[i].ShaderName != nullptr; i++) - { - VkShaderProgram prog; - prog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines); - prog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, gbufferpass); - mMaterialShaders[j].push_back(std::move(prog)); - - if (i < SHADER_NoTexture) - { - VkShaderProgram natprog; - natprog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines); - natprog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, gbufferpass); - mMaterialShadersNAT[j].push_back(std::move(natprog)); - } - } - - for (unsigned i = 0; i < usershaders.Size(); i++) - { - FString name = ExtractFileBase(usershaders[i].shader); - FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines; - - VkShaderProgram prog; - prog.vert = LoadVertShader(name, mainvp, defines); - prog.frag = LoadFragShader(name, mainfp, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, gbufferpass); - mMaterialShaders[j].push_back(std::move(prog)); - } - - for (int i = 0; i < MAX_EFFECTS; i++) - { - VkShaderProgram prog; - prog.vert = LoadVertShader(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].defines); - prog.frag = LoadFragShader(effectshaders[i].ShaderName, effectshaders[i].fp1, effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines, true, gbufferpass); - mEffectShaders[j].push_back(std::move(prog)); - } - } -} - -VkShaderManager::~VkShaderManager() -{ - ShFinalize(); -} - -VkShaderProgram *VkShaderManager::GetEffect(int effect, EPassType passType) -{ - if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[passType][effect].frag) - { - return &mEffectShaders[passType][effect]; - } - return nullptr; -} - -VkShaderProgram *VkShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) -{ - // indices 0-2 match the warping modes, 3 is brightmap, 4 no texture, the following are custom - if (!alphateston && eff <= 3) - { - return &mMaterialShadersNAT[passType][eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway - } - else if (eff < (unsigned int)mMaterialShaders[passType].size()) - { - return &mMaterialShaders[passType][eff]; - } - return nullptr; -} - -static const char *shaderBindings = R"( - - // This must match the HWViewpointUniforms struct - layout(set = 0, binding = 0, std140) uniform ViewpointUBO { - mat4 ProjectionMatrix; - mat4 ViewMatrix; - mat4 NormalViewMatrix; - - vec4 uCameraPos; - vec4 uClipLine; - - float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 - int uPalLightLevels; - int uViewHeight; // Software fuzz scaling - float uClipHeight; - float uClipHeightDirection; - int uShadowmapFilter; - }; - - // light buffers - layout(set = 0, binding = 1, std430) buffer LightBufferSSO - { - vec4 lights[]; - }; - - layout(set = 0, binding = 2, std140) uniform MatricesUBO { - mat4 ModelMatrix; - mat4 NormalModelMatrix; - mat4 TextureMatrix; - }; - - struct StreamData - { - vec4 uObjectColor; - vec4 uObjectColor2; - vec4 uDynLightColor; - vec4 uAddColor; - vec4 uTextureAddColor; - vec4 uTextureModulateColor; - vec4 uTextureBlendColor; - vec4 uFogColor; - float uDesaturationFactor; - float uInterpolationFactor; - float timer; // timer data for material shaders - int useVertexData; - vec4 uVertexColor; - vec4 uVertexNormal; - - vec4 uGlowTopPlane; - vec4 uGlowTopColor; - vec4 uGlowBottomPlane; - vec4 uGlowBottomColor; - - vec4 uGradientTopPlane; - vec4 uGradientBottomPlane; - - vec4 uSplitTopPlane; - vec4 uSplitBottomPlane; - }; - - layout(set = 0, binding = 3, std140) uniform StreamUBO { - StreamData data[MAX_STREAM_DATA]; - }; - - layout(set = 0, binding = 4) uniform sampler2D ShadowMap; - - // textures - layout(set = 1, binding = 0) uniform sampler2D tex; - layout(set = 1, binding = 1) uniform sampler2D texture2; - layout(set = 1, binding = 2) uniform sampler2D texture3; - layout(set = 1, binding = 3) uniform sampler2D texture4; - layout(set = 1, binding = 4) uniform sampler2D texture5; - layout(set = 1, binding = 5) uniform sampler2D texture6; - - // This must match the PushConstants struct - layout(push_constant) uniform PushConstants - { - int uTextureMode; - float uAlphaThreshold; - vec2 uClipSplit; - - // Lighting + Fog - float uLightLevel; - float uFogDensity; - float uLightFactor; - float uLightDist; - int uFogEnabled; - - // dynamic lights - int uLightIndex; - - // Blinn glossiness and specular level - vec2 uSpecularMaterial; - - int uDataIndex; - int padding1, padding2, padding3; - }; - - // material types - #if defined(SPECULAR) - #define normaltexture texture2 - #define speculartexture texture3 - #define brighttexture texture4 - #elif defined(PBR) - #define normaltexture texture2 - #define metallictexture texture3 - #define roughnesstexture texture4 - #define aotexture texture5 - #define brighttexture texture6 - #else - #define brighttexture texture2 - #endif - - #define uObjectColor data[uDataIndex].uObjectColor - #define uObjectColor2 data[uDataIndex].uObjectColor2 - #define uDynLightColor data[uDataIndex].uDynLightColor - #define uAddColor data[uDataIndex].uAddColor - #define uTextureBlendColor data[uDataIndex].uTextureBlendColor - #define uTextureModulateColor data[uDataIndex].uTextureModulateColor - #define uTextureAddColor data[uDataIndex].uTextureAddColor - #define uFogColor data[uDataIndex].uFogColor - #define uDesaturationFactor data[uDataIndex].uDesaturationFactor - #define uInterpolationFactor data[uDataIndex].uInterpolationFactor - #define timer data[uDataIndex].timer - #define useVertexData data[uDataIndex].useVertexData - #define uVertexColor data[uDataIndex].uVertexColor - #define uVertexNormal data[uDataIndex].uVertexNormal - #define uGlowTopPlane data[uDataIndex].uGlowTopPlane - #define uGlowTopColor data[uDataIndex].uGlowTopColor - #define uGlowBottomPlane data[uDataIndex].uGlowBottomPlane - #define uGlowBottomColor data[uDataIndex].uGlowBottomColor - #define uGradientTopPlane data[uDataIndex].uGradientTopPlane - #define uGradientBottomPlane data[uDataIndex].uGradientBottomPlane - #define uSplitTopPlane data[uDataIndex].uSplitTopPlane - #define uSplitBottomPlane data[uDataIndex].uSplitBottomPlane - - #define SUPPORTS_SHADOWMAPS - #define VULKAN_COORDINATE_SYSTEM - #define HAS_UNIFORM_VERTEX_DATA - - // GLSL spec 4.60, 8.15. Noise Functions - // https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf - // "The noise functions noise1, noise2, noise3, and noise4 have been deprecated starting with version 4.4 of GLSL. - // When not generating SPIR-V they are defined to return the value 0.0 or a vector whose components are all 0.0. - // When generating SPIR-V the noise functions are not declared and may not be used." - // However, we need to support mods with custom shaders created for OpenGL renderer - float noise1(float) { return 0; } - vec2 noise2(vec2) { return vec2(0); } - vec3 noise3(vec3) { return vec3(0); } - vec4 noise4(vec4) { return vec4(0); } -)"; - -std::unique_ptr VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *defines) -{ - FString code = GetTargetGlslVersion(); - code << defines; - code << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n"; - code << shaderBindings; - if (!device->UsedDeviceFeatures.shaderClipDistance) code << "#define NO_CLIPDISTANCE_SUPPORT\n"; - code << "#line 1\n"; - code << LoadPrivateShaderLump(vert_lump).GetChars() << "\n"; - - ShaderBuilder builder; - builder.setVertexShader(code); - return builder.create(shadername.GetChars(), device); -} - -std::unique_ptr VkShaderManager::LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines, bool alphatest, bool gbufferpass) -{ - FString code = GetTargetGlslVersion(); - code << defines; - code << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n"; - code << shaderBindings; - - if (!device->UsedDeviceFeatures.shaderClipDistance) code << "#define NO_CLIPDISTANCE_SUPPORT\n"; - if (!alphatest) code << "#define NO_ALPHATEST\n"; - if (gbufferpass) code << "#define GBUFFER_PASS\n"; - - code << "\n#line 1\n"; - code << LoadPrivateShaderLump(frag_lump).GetChars() << "\n"; - - if (material_lump) - { - if (material_lump[0] != '#') - { - FString pp_code = LoadPublicShaderLump(material_lump); - - if (pp_code.IndexOf("ProcessMaterial") < 0) - { - // this looks like an old custom hardware shader. - // add ProcessMaterial function that calls the older ProcessTexel function - code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultmat.fp").GetChars() << "\n"; - - if (pp_code.IndexOf("ProcessTexel") < 0) - { - // this looks like an even older custom hardware shader. - // We need to replace the ProcessTexel call to make it work. - - code.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));"); - } - - if (pp_code.IndexOf("ProcessLight") >= 0) - { - // The ProcessLight signatured changed. Forward to the old one. - code << "\nvec4 ProcessLight(vec4 color);\n"; - code << "\nvec4 ProcessLight(Material material, vec4 color) { return ProcessLight(color); }\n"; - } - } - - code << "\n#line 1\n"; - code << RemoveLegacyUserUniforms(pp_code).GetChars(); - code.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders. - - if (pp_code.IndexOf("ProcessLight") < 0) - { - code << "\n" << LoadPrivateShaderLump("shaders/glsl/func_defaultlight.fp").GetChars() << "\n"; - } - } - else - { - // material_lump is not a lump name but the source itself (from generated shaders) - code << (material_lump + 1) << "\n"; - } - } - - if (light_lump) - { - code << "\n#line 1\n"; - code << LoadPrivateShaderLump(light_lump).GetChars(); - } - - ShaderBuilder builder; - builder.setFragmentShader(code); - return builder.create(shadername.GetChars(), device); -} - -FString VkShaderManager::GetTargetGlslVersion() -{ - return "#version 450 core\n"; -} - -FString VkShaderManager::LoadPublicShaderLump(const char *lumpname) -{ - int lump = Wads.CheckNumForFullName(lumpname); - if (lump == -1) I_Error("Unable to load '%s'", lumpname); - FMemLump data = Wads.ReadLump(lump); - return data.GetString(); -} - -FString VkShaderManager::LoadPrivateShaderLump(const char *lumpname) -{ - int lump = Wads.CheckNumForFullName(lumpname, 0); - if (lump == -1) I_Error("Unable to load '%s'", lumpname); - FMemLump data = Wads.ReadLump(lump); - return data.GetString(); -} diff --git a/src/rendering/vulkan/shaders/vk_shader.h b/src/rendering/vulkan/shaders/vk_shader.h deleted file mode 100644 index c170e5a7744..00000000000 --- a/src/rendering/vulkan/shaders/vk_shader.h +++ /dev/null @@ -1,80 +0,0 @@ - -#pragma once - -#include - -#include "utility/vectors.h" -#include "matrix.h" -#include "name.h" -#include "hwrenderer/scene/hw_renderstate.h" - -class VulkanDevice; -class VulkanShader; - -struct MatricesUBO -{ - VSMatrix ModelMatrix; - VSMatrix NormalModelMatrix; - VSMatrix TextureMatrix; -}; - -#define MAX_STREAM_DATA ((int)(65536 / sizeof(StreamData))) - -struct StreamUBO -{ - StreamData data[MAX_STREAM_DATA]; -}; - -struct PushConstants -{ - int uTextureMode; - float uAlphaThreshold; - FVector2 uClipSplit; - - // Lighting + Fog - float uLightLevel; - float uFogDensity; - float uLightFactor; - float uLightDist; - int uFogEnabled; - - // dynamic lights - int uLightIndex; - - // Blinn glossiness and specular level - FVector2 uSpecularMaterial; - - int uDataIndex; - int padding1, padding2, padding3; -}; - -class VkShaderProgram -{ -public: - std::unique_ptr vert; - std::unique_ptr frag; -}; - -class VkShaderManager -{ -public: - VkShaderManager(VulkanDevice *device); - ~VkShaderManager(); - - VkShaderProgram *GetEffect(int effect, EPassType passType); - VkShaderProgram *Get(unsigned int eff, bool alphateston, EPassType passType); - -private: - std::unique_ptr LoadVertShader(FString shadername, const char *vert_lump, const char *defines); - std::unique_ptr LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines, bool alphatest, bool gbufferpass); - - FString GetTargetGlslVersion(); - FString LoadPublicShaderLump(const char *lumpname); - FString LoadPrivateShaderLump(const char *lumpname); - - VulkanDevice *device; - - std::vector mMaterialShaders[MAX_PASS_TYPES]; - std::vector mMaterialShadersNAT[MAX_PASS_TYPES]; - std::vector mEffectShaders[MAX_PASS_TYPES]; -}; diff --git a/src/rendering/vulkan/system/vk_buffers.cpp b/src/rendering/vulkan/system/vk_buffers.cpp deleted file mode 100644 index 36c606b5b7a..00000000000 --- a/src/rendering/vulkan/system/vk_buffers.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_buffers.h" -#include "vk_builders.h" -#include "vk_framebuffer.h" -#include "vulkan/renderer/vk_renderstate.h" -#include "vulkan/renderer/vk_renderpass.h" -#include "doomerrors.h" - -VKBuffer *VKBuffer::First = nullptr; - -VKBuffer::VKBuffer() -{ - Next = First; - First = this; - if (Next) Next->Prev = this; -} - -VKBuffer::~VKBuffer() -{ - if (Next) Next->Prev = Prev; - if (Prev) Prev->Next = Next; - else First = Next; - - if (mBuffer && map) - mBuffer->Unmap(); - - auto fb = GetVulkanFrameBuffer(); - if (fb && mBuffer) - fb->FrameDeleteList.Buffers.push_back(std::move(mBuffer)); -} - -void VKBuffer::ResetAll() -{ - for (VKBuffer *cur = VKBuffer::First; cur; cur = cur->Next) - cur->Reset(); -} - -void VKBuffer::Reset() -{ - if (mBuffer && map) - mBuffer->Unmap(); - mBuffer.reset(); - mStaging.reset(); -} - -void VKBuffer::SetData(size_t size, const void *data, bool staticdata) -{ - auto fb = GetVulkanFrameBuffer(); - - if (staticdata) - { - mPersistent = false; - - { - BufferBuilder builder; - builder.setUsage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | mBufferType, VMA_MEMORY_USAGE_GPU_ONLY); - builder.setSize(size); - mBuffer = builder.create(fb->device); - } - - { - BufferBuilder builder; - builder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - builder.setSize(size); - mStaging = builder.create(fb->device); - } - - void *dst = mStaging->Map(0, size); - memcpy(dst, data, size); - mStaging->Unmap(); - - fb->GetTransferCommands()->copyBuffer(mStaging.get(), mBuffer.get()); - } - else - { - mPersistent = screen->BuffersArePersistent(); - - BufferBuilder builder; - builder.setUsage(mBufferType, VMA_MEMORY_USAGE_UNKNOWN, mPersistent ? VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT : 0); - builder.setMemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - builder.setSize(size); - mBuffer = builder.create(fb->device); - - if (mPersistent) - { - map = mBuffer->Map(0, size); - if (data) - memcpy(map, data, size); - } - else if (data) - { - void *dst = mBuffer->Map(0, size); - memcpy(dst, data, size); - mBuffer->Unmap(); - } - } - buffersize = size; -} - -void VKBuffer::SetSubData(size_t offset, size_t size, const void *data) -{ - auto fb = GetVulkanFrameBuffer(); - if (mStaging) - { - void *dst = mStaging->Map(offset, size); - memcpy(dst, data, size); - mStaging->Unmap(); - - fb->GetTransferCommands()->copyBuffer(mStaging.get(), mBuffer.get(), offset, offset, size); - } - else - { - void *dst = mBuffer->Map(offset, size); - memcpy(dst, data, size); - mBuffer->Unmap(); - } -} - -void VKBuffer::Resize(size_t newsize) -{ - auto fb = GetVulkanFrameBuffer(); - - // Grab old buffer - size_t oldsize = buffersize; - std::unique_ptr oldBuffer = std::move(mBuffer); - oldBuffer->Unmap(); - map = nullptr; - - // Create new buffer - BufferBuilder builder; - builder.setUsage(mBufferType, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); - builder.setMemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - builder.setSize(newsize); - mBuffer = builder.create(fb->device); - buffersize = newsize; - - // Transfer data from old to new - fb->GetTransferCommands()->copyBuffer(oldBuffer.get(), mBuffer.get(), 0, 0, oldsize); - fb->WaitForCommands(false); - - // Fetch pointer to new buffer - map = mBuffer->Map(0, newsize); - - // Old buffer may be part of the dynamic set - fb->GetRenderPassManager()->UpdateDynamicSet(); -} - -void VKBuffer::Map() -{ - if (!mPersistent) - map = mBuffer->Map(0, mBuffer->size); -} - -void VKBuffer::Unmap() -{ - if (!mPersistent) - { - mBuffer->Unmap(); - map = nullptr; - } -} - -void *VKBuffer::Lock(unsigned int size) -{ - if (!mBuffer) - { - // The model mesh loaders lock multiple non-persistent buffers at the same time. This is not allowed in vulkan. - // VkDeviceMemory can only be mapped once and multiple non-persistent buffers may come from the same device memory object. - mStaticUpload.Resize(size); - map = mStaticUpload.Data(); - } - else if (!mPersistent) - { - map = mBuffer->Map(0, size); - } - return map; -} - -void VKBuffer::Unlock() -{ - if (!mBuffer) - { - map = nullptr; - SetData(mStaticUpload.Size(), mStaticUpload.Data(), true); - mStaticUpload.Clear(); - } - else if (!mPersistent) - { - mBuffer->Unmap(); - map = nullptr; - } -} - -///////////////////////////////////////////////////////////////////////////// - -void VKVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) -{ - VertexFormat = GetVulkanFrameBuffer()->GetRenderPassManager()->GetVertexFormat(numBindingPoints, numAttributes, stride, attrs); -} - -///////////////////////////////////////////////////////////////////////////// - - -void VKDataBuffer::BindRange(FRenderState* state, size_t start, size_t length) -{ - static_cast(state)->Bind(bindingpoint, (uint32_t)start); -} - diff --git a/src/rendering/vulkan/system/vk_buffers.h b/src/rendering/vulkan/system/vk_buffers.h deleted file mode 100644 index e162c23672e..00000000000 --- a/src/rendering/vulkan/system/vk_buffers.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "hwrenderer/data/buffers.h" -#include "vk_objects.h" -#include "utility/tarray.h" - -#ifdef _MSC_VER -// silence bogus warning C4250: 'VKVertexBuffer': inherits 'VKBuffer::VKBuffer::SetData' via dominance -// According to internet infos, the warning is erroneously emitted in this case. -#pragma warning(disable:4250) -#endif - -class VKBuffer : virtual public IBuffer -{ -public: - VKBuffer(); - ~VKBuffer(); - - static void ResetAll(); - void Reset(); - - void SetData(size_t size, const void *data, bool staticdata) override; - void SetSubData(size_t offset, size_t size, const void *data) override; - void Resize(size_t newsize) override; - - void Map() override; - void Unmap() override; - - void *Lock(unsigned int size) override; - void Unlock() override; - - VkBufferUsageFlags mBufferType = 0; - std::unique_ptr mBuffer; - std::unique_ptr mStaging; - bool mPersistent = false; - TArray mStaticUpload; - -private: - static VKBuffer *First; - VKBuffer *Prev = nullptr; - VKBuffer *Next = nullptr; -}; - -class VKVertexBuffer : public IVertexBuffer, public VKBuffer -{ -public: - VKVertexBuffer() { mBufferType = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; } - void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override; - - int VertexFormat = -1; -}; - -class VKIndexBuffer : public IIndexBuffer, public VKBuffer -{ -public: - VKIndexBuffer() { mBufferType = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; } -}; - -class VKDataBuffer : public IDataBuffer, public VKBuffer -{ -public: - VKDataBuffer(int bindingpoint, bool ssbo, bool needresize) : bindingpoint(bindingpoint) - { - mBufferType = ssbo ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - if (needresize) - { - mBufferType |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - } - } - - void BindRange(FRenderState *state, size_t start, size_t length) override; - - int bindingpoint; -}; diff --git a/src/rendering/vulkan/system/vk_builders.cpp b/src/rendering/vulkan/system/vk_builders.cpp deleted file mode 100644 index 08a9f41b651..00000000000 --- a/src/rendering/vulkan/system/vk_builders.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_builders.h" -#include "doomerrors.h" -#include "r_data/renderstyle.h" -#include -#include - -static const TBuiltInResource DefaultTBuiltInResource = { - /* .MaxLights = */ 32, - /* .MaxClipPlanes = */ 6, - /* .MaxTextureUnits = */ 32, - /* .MaxTextureCoords = */ 32, - /* .MaxVertexAttribs = */ 64, - /* .MaxVertexUniformComponents = */ 4096, - /* .MaxVaryingFloats = */ 64, - /* .MaxVertexTextureImageUnits = */ 32, - /* .MaxCombinedTextureImageUnits = */ 80, - /* .MaxTextureImageUnits = */ 32, - /* .MaxFragmentUniformComponents = */ 4096, - /* .MaxDrawBuffers = */ 32, - /* .MaxVertexUniformVectors = */ 128, - /* .MaxVaryingVectors = */ 8, - /* .MaxFragmentUniformVectors = */ 16, - /* .MaxVertexOutputVectors = */ 16, - /* .MaxFragmentInputVectors = */ 15, - /* .MinProgramTexelOffset = */ -8, - /* .MaxProgramTexelOffset = */ 7, - /* .MaxClipDistances = */ 8, - /* .MaxComputeWorkGroupCountX = */ 65535, - /* .MaxComputeWorkGroupCountY = */ 65535, - /* .MaxComputeWorkGroupCountZ = */ 65535, - /* .MaxComputeWorkGroupSizeX = */ 1024, - /* .MaxComputeWorkGroupSizeY = */ 1024, - /* .MaxComputeWorkGroupSizeZ = */ 64, - /* .MaxComputeUniformComponents = */ 1024, - /* .MaxComputeTextureImageUnits = */ 16, - /* .MaxComputeImageUniforms = */ 8, - /* .MaxComputeAtomicCounters = */ 8, - /* .MaxComputeAtomicCounterBuffers = */ 1, - /* .MaxVaryingComponents = */ 60, - /* .MaxVertexOutputComponents = */ 64, - /* .MaxGeometryInputComponents = */ 64, - /* .MaxGeometryOutputComponents = */ 128, - /* .MaxFragmentInputComponents = */ 128, - /* .MaxImageUnits = */ 8, - /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, - /* .MaxCombinedShaderOutputResources = */ 8, - /* .MaxImageSamples = */ 0, - /* .MaxVertexImageUniforms = */ 0, - /* .MaxTessControlImageUniforms = */ 0, - /* .MaxTessEvaluationImageUniforms = */ 0, - /* .MaxGeometryImageUniforms = */ 0, - /* .MaxFragmentImageUniforms = */ 8, - /* .MaxCombinedImageUniforms = */ 8, - /* .MaxGeometryTextureImageUnits = */ 16, - /* .MaxGeometryOutputVertices = */ 256, - /* .MaxGeometryTotalOutputComponents = */ 1024, - /* .MaxGeometryUniformComponents = */ 1024, - /* .MaxGeometryVaryingComponents = */ 64, - /* .MaxTessControlInputComponents = */ 128, - /* .MaxTessControlOutputComponents = */ 128, - /* .MaxTessControlTextureImageUnits = */ 16, - /* .MaxTessControlUniformComponents = */ 1024, - /* .MaxTessControlTotalOutputComponents = */ 4096, - /* .MaxTessEvaluationInputComponents = */ 128, - /* .MaxTessEvaluationOutputComponents = */ 128, - /* .MaxTessEvaluationTextureImageUnits = */ 16, - /* .MaxTessEvaluationUniformComponents = */ 1024, - /* .MaxTessPatchComponents = */ 120, - /* .MaxPatchVertices = */ 32, - /* .MaxTessGenLevel = */ 64, - /* .MaxViewports = */ 16, - /* .MaxVertexAtomicCounters = */ 0, - /* .MaxTessControlAtomicCounters = */ 0, - /* .MaxTessEvaluationAtomicCounters = */ 0, - /* .MaxGeometryAtomicCounters = */ 0, - /* .MaxFragmentAtomicCounters = */ 8, - /* .MaxCombinedAtomicCounters = */ 8, - /* .MaxAtomicCounterBindings = */ 1, - /* .MaxVertexAtomicCounterBuffers = */ 0, - /* .MaxTessControlAtomicCounterBuffers = */ 0, - /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, - /* .MaxGeometryAtomicCounterBuffers = */ 0, - /* .MaxFragmentAtomicCounterBuffers = */ 1, - /* .MaxCombinedAtomicCounterBuffers = */ 1, - /* .MaxAtomicCounterBufferSize = */ 16384, - /* .MaxTransformFeedbackBuffers = */ 4, - /* .MaxTransformFeedbackInterleavedComponents = */ 64, - /* .MaxCullDistances = */ 8, - /* .MaxCombinedClipAndCullDistances = */ 8, - /* .MaxSamples = */ 4, - /* .maxMeshOutputVerticesNV = */ 256, - /* .maxMeshOutputPrimitivesNV = */ 512, - /* .maxMeshWorkGroupSizeX_NV = */ 32, - /* .maxMeshWorkGroupSizeY_NV = */ 1, - /* .maxMeshWorkGroupSizeZ_NV = */ 1, - /* .maxTaskWorkGroupSizeX_NV = */ 32, - /* .maxTaskWorkGroupSizeY_NV = */ 1, - /* .maxTaskWorkGroupSizeZ_NV = */ 1, - /* .maxMeshViewCountNV = */ 4, - - /* .limits = */ { - /* .nonInductiveForLoops = */ 1, - /* .whileLoops = */ 1, - /* .doWhileLoops = */ 1, - /* .generalUniformIndexing = */ 1, - /* .generalAttributeMatrixVectorIndexing = */ 1, - /* .generalVaryingIndexing = */ 1, - /* .generalSamplerIndexing = */ 1, - /* .generalVariableIndexing = */ 1, - /* .generalConstantMatrixVectorIndexing = */ 1, - } -}; - -ShaderBuilder::ShaderBuilder() -{ -} - -void ShaderBuilder::setVertexShader(const FString &c) -{ - code = c; - stage = EShLanguage::EShLangVertex; -} - -void ShaderBuilder::setFragmentShader(const FString &c) -{ - code = c; - stage = EShLanguage::EShLangFragment; -} - -std::unique_ptr ShaderBuilder::create(const char *shadername, VulkanDevice *device) -{ - EShLanguage stage = (EShLanguage)this->stage; - const char *sources[] = { code.GetChars() }; - - TBuiltInResource resources = DefaultTBuiltInResource; - - glslang::TShader shader(stage); - shader.setStrings(sources, 1); - shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100); - shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); - shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); - bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules); - if (!compileSuccess) - { - I_FatalError("Shader '%s' could not be compiled:\n%s\n", shadername, shader.getInfoLog()); - } - - glslang::TProgram program; - program.addShader(&shader); - bool linkSuccess = program.link(EShMsgDefault); - if (!linkSuccess) - { - I_FatalError("Shader '%s' could not be linked:\n%s\n", shadername, program.getInfoLog()); - } - - glslang::TIntermediate *intermediate = program.getIntermediate(stage); - if (!intermediate) - { - I_FatalError("Internal shader compiler error while processing '%s'\n", shadername); - } - - glslang::SpvOptions spvOptions; - spvOptions.generateDebugInfo = false; - spvOptions.disableOptimizer = false; - spvOptions.optimizeSize = true; - - std::vector spirv; - spv::SpvBuildLogger logger; - glslang::GlslangToSpv(*intermediate, spirv, &logger, &spvOptions); - - VkShaderModuleCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = spirv.size() * sizeof(unsigned int); - createInfo.pCode = spirv.data(); - - VkShaderModule shaderModule; - VkResult result = vkCreateShaderModule(device->device, &createInfo, nullptr, &shaderModule); - if (result != VK_SUCCESS) - { - FString msg; - msg.Format("Could not create vulkan shader module for '%s': %s", shadername, VkResultToString(result).GetChars()); - VulkanError(msg.GetChars()); - } - - return std::make_unique(device, shaderModule); -} - -///////////////////////////////////////////////////////////////////////////// - -void GraphicsPipelineBuilder::setBlendMode(const FRenderStyle &style) -{ - // Just in case Vulkan doesn't do this optimization itself - if (style.BlendOp == STYLEOP_Add && style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero && style.Flags == 0) - { - colorBlendAttachment.blendEnable = VK_FALSE; - return; - } - - static const int blendstyles[] = { - VK_BLEND_FACTOR_ZERO, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_SRC_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - VK_BLEND_FACTOR_SRC_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, - VK_BLEND_FACTOR_DST_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, - }; - - static const int renderops[] = { - 0, VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - int srcblend = blendstyles[style.SrcAlpha%STYLEALPHA_MAX]; - int dstblend = blendstyles[style.DestAlpha%STYLEALPHA_MAX]; - int blendequation = renderops[style.BlendOp & 15]; - - if (blendequation == -1) // This was a fuzz style. - { - srcblend = VK_BLEND_FACTOR_DST_COLOR; - dstblend = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blendequation = VK_BLEND_OP_ADD; - } - - setBlendMode((VkBlendOp)blendequation, (VkBlendFactor)srcblend, (VkBlendFactor)dstblend); -} diff --git a/src/rendering/vulkan/system/vk_builders.h b/src/rendering/vulkan/system/vk_builders.h deleted file mode 100644 index 7eca4c6a1f4..00000000000 --- a/src/rendering/vulkan/system/vk_builders.h +++ /dev/null @@ -1,1375 +0,0 @@ -#pragma once - -#include "vk_objects.h" -#include "zstring.h" -#include - -template -class FixedSizeVector -{ -public: - const T *data() const { return mItems; } - T *data() { return mItems; } - - size_t size() const { return mCount; } - - const T &back() const { return mItems[mCount - 1]; } - T &back() { return mItems[mCount - 1]; } - - void push_back(T && value) - { - assert(mCount != maxsize && "FixedSizeVector is too small"); - mItems[mCount++] = std::move(value); - } - - void push_back(const T &value) - { - assert(mCount != maxsize && "FixedSizeVector is too small"); - mItems[mCount++] = value; - } - -private: - T mItems[maxsize]; - size_t mCount = 0; -}; - -class ImageBuilder -{ -public: - ImageBuilder(); - - void setSize(int width, int height, int miplevels = 1); - void setSamples(VkSampleCountFlagBits samples); - void setFormat(VkFormat format); - void setUsage(VkImageUsageFlags imageUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0); - void setMemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0); - void setLinearTiling(); - - bool isFormatSupported(VulkanDevice *device); - - std::unique_ptr create(VulkanDevice *device, VkDeviceSize* allocatedBytes = nullptr); - std::unique_ptr tryCreate(VulkanDevice *device); - -private: - VkImageCreateInfo imageInfo = {}; - VmaAllocationCreateInfo allocInfo = {}; -}; - -class ImageViewBuilder -{ -public: - ImageViewBuilder(); - - void setImage(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkImageViewCreateInfo viewInfo = {}; -}; - -class SamplerBuilder -{ -public: - SamplerBuilder(); - - void setAddressMode(VkSamplerAddressMode addressMode); - void setAddressMode(VkSamplerAddressMode u, VkSamplerAddressMode v, VkSamplerAddressMode w); - void setMinFilter(VkFilter minFilter); - void setMagFilter(VkFilter magFilter); - void setMipmapMode(VkSamplerMipmapMode mode); - void setAnisotropy(float maxAnisotropy); - void setMaxLod(float value); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkSamplerCreateInfo samplerInfo = {}; -}; - -class BufferBuilder -{ -public: - BufferBuilder(); - - void setSize(size_t size); - void setUsage(VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0); - void setMemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkBufferCreateInfo bufferInfo = {}; - VmaAllocationCreateInfo allocInfo = {}; -}; - -class ShaderBuilder -{ -public: - ShaderBuilder(); - - void setVertexShader(const FString &code); - void setFragmentShader(const FString &code); - - std::unique_ptr create(const char *shadername, VulkanDevice *device); - -private: - FString code; - int stage; -}; - -class ComputePipelineBuilder -{ -public: - ComputePipelineBuilder(); - - void setLayout(VulkanPipelineLayout *layout); - void setComputeShader(VulkanShader *shader); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkComputePipelineCreateInfo pipelineInfo = {}; - VkPipelineShaderStageCreateInfo stageInfo = {}; -}; - -class DescriptorSetLayoutBuilder -{ -public: - DescriptorSetLayoutBuilder(); - - void addBinding(int binding, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkDescriptorSetLayoutCreateInfo layoutInfo = {}; - FixedSizeVector bindings; -}; - -class DescriptorPoolBuilder -{ -public: - DescriptorPoolBuilder(); - - void setMaxSets(int value); - void addPoolSize(VkDescriptorType type, int count); - - std::unique_ptr create(VulkanDevice *device); - -private: - FixedSizeVector poolSizes; - VkDescriptorPoolCreateInfo poolInfo = {}; -}; - -class QueryPoolBuilder -{ -public: - QueryPoolBuilder(); - - void setQueryType(VkQueryType type, int count, VkQueryPipelineStatisticFlags pipelineStatistics = 0); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkQueryPoolCreateInfo poolInfo = {}; -}; - -class FramebufferBuilder -{ -public: - FramebufferBuilder(); - - void setRenderPass(VulkanRenderPass *renderPass); - void addAttachment(VulkanImageView *view); - void addAttachment(VkImageView view); - void setSize(int width, int height, int layers = 1); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkFramebufferCreateInfo framebufferInfo = {}; - FixedSizeVector attachments; -}; - -union FRenderStyle; - -class GraphicsPipelineBuilder -{ -public: - GraphicsPipelineBuilder(); - - void setSubpass(int subpass); - void setLayout(VulkanPipelineLayout *layout); - void setRenderPass(VulkanRenderPass *renderPass); - void setTopology(VkPrimitiveTopology topology); - void setViewport(float x, float y, float width, float height, float minDepth = 0.0f, float maxDepth = 1.0f); - void setScissor(int x, int y, int width, int height); - void setRasterizationSamples(VkSampleCountFlagBits samples); - - void setCull(VkCullModeFlags cullMode, VkFrontFace frontFace); - void setDepthStencilEnable(bool test, bool write, bool stencil); - void setDepthFunc(VkCompareOp func); - void setDepthClampEnable(bool value); - void setDepthBias(bool enable, float biasConstantFactor, float biasClamp, float biasSlopeFactor); - void setColorWriteMask(VkColorComponentFlags mask); - void setStencil(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp, uint32_t compareMask, uint32_t writeMask, uint32_t reference); - - void setAdditiveBlendMode(); - void setAlphaBlendMode(); - void setBlendMode(const FRenderStyle &style); - void setBlendMode(VkBlendOp op, VkBlendFactor src, VkBlendFactor dst); - void setSubpassColorAttachmentCount(int count); - - void addVertexShader(VulkanShader *shader); - void addFragmentShader(VulkanShader *shader); - - void addVertexBufferBinding(int index, size_t stride); - void addVertexAttribute(int location, int binding, VkFormat format, size_t offset); - - void addDynamicState(VkDynamicState state); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkGraphicsPipelineCreateInfo pipelineInfo = { }; - VkPipelineVertexInputStateCreateInfo vertexInputInfo = { }; - VkPipelineInputAssemblyStateCreateInfo inputAssembly = { }; - VkViewport viewport = { }; - VkRect2D scissor = { }; - VkPipelineViewportStateCreateInfo viewportState = { }; - VkPipelineRasterizationStateCreateInfo rasterizer = { }; - VkPipelineMultisampleStateCreateInfo multisampling = { }; - VkPipelineColorBlendAttachmentState colorBlendAttachment = { }; - VkPipelineColorBlendStateCreateInfo colorBlending = { }; - VkPipelineDepthStencilStateCreateInfo depthStencil = { }; - VkPipelineDynamicStateCreateInfo dynamicState = {}; - - std::vector shaderStages; - std::vector colorBlendAttachments; - std::vector vertexInputBindings; - std::vector vertexInputAttributes; - std::vector dynamicStates; -}; - -class PipelineLayoutBuilder -{ -public: - PipelineLayoutBuilder(); - - void addSetLayout(VulkanDescriptorSetLayout *setLayout); - void addPushConstantRange(VkShaderStageFlags stageFlags, size_t offset, size_t size); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; - std::vector setLayouts; - std::vector pushConstantRanges; -}; - -class RenderPassBuilder -{ -public: - RenderPassBuilder(); - - void addAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkImageLayout initialLayout, VkImageLayout finalLayout); - void addDepthStencilAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkAttachmentLoadOp stencilLoad, VkAttachmentStoreOp stencilStore, VkImageLayout initialLayout, VkImageLayout finalLayout); - - void addExternalSubpassDependency(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); - - void addSubpass(); - void addSubpassColorAttachmentRef(uint32_t index, VkImageLayout layout); - void addSubpassDepthStencilAttachmentRef(uint32_t index, VkImageLayout layout); - - std::unique_ptr create(VulkanDevice *device); - -private: - VkRenderPassCreateInfo renderPassInfo = { }; - - FixedSizeVector attachments; - FixedSizeVector dependencies; - FixedSizeVector subpasses; - - struct SubpassData - { - FixedSizeVector colorRefs; - VkAttachmentReference depthRef = { }; - }; - - FixedSizeVector, 8> subpassData; -}; - -class PipelineBarrier -{ -public: - void addMemory(VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); - void addBuffer(VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); - void addBuffer(VulkanBuffer *buffer, VkDeviceSize offset, VkDeviceSize size, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); - void addImage(VulkanImage *image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1); - void addImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1); - void addQueueTransfer(int srcFamily, int dstFamily, VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); - void addQueueTransfer(int srcFamily, int dstFamily, VulkanImage *image, VkImageLayout layout, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1); - - void execute(VulkanCommandBuffer *commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags = 0); - -private: - FixedSizeVector memoryBarriers; - FixedSizeVector bufferMemoryBarriers; - FixedSizeVector imageMemoryBarriers; -}; - -class QueueSubmit -{ -public: - QueueSubmit(); - - void addCommandBuffer(VulkanCommandBuffer *buffer); - void addWait(VkPipelineStageFlags waitStageMask, VulkanSemaphore *semaphore); - void addSignal(VulkanSemaphore *semaphore); - void execute(VulkanDevice *device, VkQueue queue, VulkanFence *fence = nullptr); - -private: - VkSubmitInfo submitInfo = {}; - FixedSizeVector waitSemaphores; - FixedSizeVector waitStages; - FixedSizeVector signalSemaphores; - FixedSizeVector commandBuffers; -}; - -class WriteDescriptors -{ -public: - void addBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer); - void addBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer, size_t offset, size_t range); - void addStorageImage(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VkImageLayout imageLayout); - void addCombinedImageSampler(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VulkanSampler *sampler, VkImageLayout imageLayout); - - void updateSets(VulkanDevice *device); - -private: - struct WriteExtra - { - VkDescriptorImageInfo imageInfo; - VkDescriptorBufferInfo bufferInfo; - VkBufferView bufferView; - }; - - std::vector writes; - std::vector> writeExtras; -}; - -///////////////////////////////////////////////////////////////////////////// - -inline ImageBuilder::ImageBuilder() -{ - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.depth = 1; - imageInfo.arrayLayers = 1; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Note: must either be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.flags = 0; -} - -inline void ImageBuilder::setSize(int width, int height, int mipLevels) -{ - imageInfo.extent.width = width; - imageInfo.extent.height = height; - imageInfo.mipLevels = mipLevels; -} - -inline void ImageBuilder::setSamples(VkSampleCountFlagBits samples) -{ - imageInfo.samples = samples; -} - -inline void ImageBuilder::setFormat(VkFormat format) -{ - imageInfo.format = format; -} - -inline void ImageBuilder::setLinearTiling() -{ - imageInfo.tiling = VK_IMAGE_TILING_LINEAR; -} - -inline void ImageBuilder::setUsage(VkImageUsageFlags usage, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocFlags) -{ - imageInfo.usage = usage; - allocInfo.usage = memoryUsage; - allocInfo.flags = allocFlags; -} - -inline void ImageBuilder::setMemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits) -{ - allocInfo.requiredFlags = requiredFlags; - allocInfo.preferredFlags = preferredFlags; - allocInfo.memoryTypeBits = memoryTypeBits; -} - -inline bool ImageBuilder::isFormatSupported(VulkanDevice *device) -{ - VkImageFormatProperties properties = { }; - VkResult result = vkGetPhysicalDeviceImageFormatProperties(device->PhysicalDevice.Device, imageInfo.format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage, imageInfo.flags, &properties); - if (result != VK_SUCCESS) return false; - if (imageInfo.extent.width > properties.maxExtent.width) return false; - if (imageInfo.extent.height > properties.maxExtent.height) return false; - if (imageInfo.extent.depth > properties.maxExtent.depth) return false; - if (imageInfo.mipLevels > properties.maxMipLevels) return false; - if (imageInfo.arrayLayers > properties.maxArrayLayers) return false; - if ((imageInfo.samples & properties.sampleCounts) != imageInfo.samples) return false; - return true; -} - -inline std::unique_ptr ImageBuilder::create(VulkanDevice *device, VkDeviceSize* allocatedBytes) -{ - VkImage image; - VmaAllocation allocation; - - VkResult result = vmaCreateImage(device->allocator, &imageInfo, &allocInfo, &image, &allocation, nullptr); - CheckVulkanError(result, "Could not create vulkan image"); - - if (allocatedBytes != nullptr) - { - VmaAllocationInfo allocatedInfo; - vmaGetAllocationInfo(device->allocator, allocation, &allocatedInfo); - - *allocatedBytes = allocatedInfo.size; - } - - return std::make_unique(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels); -} - -inline std::unique_ptr ImageBuilder::tryCreate(VulkanDevice *device) -{ - VkImage image; - VmaAllocation allocation; - - VkResult result = vmaCreateImage(device->allocator, &imageInfo, &allocInfo, &image, &allocation, nullptr); - if (result != VK_SUCCESS) - return nullptr; - - return std::make_unique(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels); -} - -///////////////////////////////////////////////////////////////////////////// - -inline ImageViewBuilder::ImageViewBuilder() -{ - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -} - -inline void ImageViewBuilder::setImage(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask) -{ - viewInfo.image = image->image; - viewInfo.format = format; - viewInfo.subresourceRange.levelCount = image->mipLevels; - viewInfo.subresourceRange.aspectMask = aspectMask; -} - -inline std::unique_ptr ImageViewBuilder::create(VulkanDevice *device) -{ - VkImageView view; - VkResult result = vkCreateImageView(device->device, &viewInfo, nullptr, &view); - CheckVulkanError(result, "Could not create texture image view"); - - return std::make_unique(device, view); -} - -///////////////////////////////////////////////////////////////////////////// - -inline SamplerBuilder::SamplerBuilder() -{ - samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.magFilter = VK_FILTER_LINEAR; - samplerInfo.minFilter = VK_FILTER_LINEAR; - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.anisotropyEnable = VK_FALSE; - samplerInfo.maxAnisotropy = 1.0f; - samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - samplerInfo.unnormalizedCoordinates = VK_FALSE; - samplerInfo.compareEnable = VK_FALSE; - samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerInfo.mipLodBias = 0.0f; - samplerInfo.minLod = 0.0f; - samplerInfo.maxLod = 100.0f; -} - -inline void SamplerBuilder::setAddressMode(VkSamplerAddressMode addressMode) -{ - samplerInfo.addressModeU = addressMode; - samplerInfo.addressModeV = addressMode; - samplerInfo.addressModeW = addressMode; -} - -inline void SamplerBuilder::setAddressMode(VkSamplerAddressMode u, VkSamplerAddressMode v, VkSamplerAddressMode w) -{ - samplerInfo.addressModeU = u; - samplerInfo.addressModeV = v; - samplerInfo.addressModeW = w; -} - -inline void SamplerBuilder::setMinFilter(VkFilter minFilter) -{ - samplerInfo.minFilter = minFilter; -} - -inline void SamplerBuilder::setMagFilter(VkFilter magFilter) -{ - samplerInfo.magFilter = magFilter; -} - -inline void SamplerBuilder::setMipmapMode(VkSamplerMipmapMode mode) -{ - samplerInfo.mipmapMode = mode; -} - -inline void SamplerBuilder::setAnisotropy(float maxAnisotropy) -{ - samplerInfo.anisotropyEnable = VK_TRUE; - samplerInfo.maxAnisotropy = maxAnisotropy; -} - -inline void SamplerBuilder::setMaxLod(float value) -{ - samplerInfo.maxLod = value; -} - -inline std::unique_ptr SamplerBuilder::create(VulkanDevice *device) -{ - VkSampler sampler; - VkResult result = vkCreateSampler(device->device, &samplerInfo, nullptr, &sampler); - CheckVulkanError(result, "Could not create texture sampler"); - return std::make_unique(device, sampler); -} - -///////////////////////////////////////////////////////////////////////////// - -inline BufferBuilder::BufferBuilder() -{ - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; -} - -inline void BufferBuilder::setSize(size_t size) -{ - bufferInfo.size = size; -} - -inline void BufferBuilder::setUsage(VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocFlags) -{ - bufferInfo.usage = bufferUsage; - allocInfo.usage = memoryUsage; - allocInfo.flags = allocFlags; -} - -inline void BufferBuilder::setMemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits) -{ - allocInfo.requiredFlags = requiredFlags; - allocInfo.preferredFlags = preferredFlags; - allocInfo.memoryTypeBits = memoryTypeBits; -} - -inline std::unique_ptr BufferBuilder::create(VulkanDevice *device) -{ - VkBuffer buffer; - VmaAllocation allocation; - - VkResult result = vmaCreateBuffer(device->allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); - CheckVulkanError(result, "Could not allocate memory for vulkan buffer"); - - return std::make_unique(device, buffer, allocation, bufferInfo.size); -} - -///////////////////////////////////////////////////////////////////////////// - -inline ComputePipelineBuilder::ComputePipelineBuilder() -{ - pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; -} - -inline void ComputePipelineBuilder::setLayout(VulkanPipelineLayout *layout) -{ - pipelineInfo.layout = layout->layout; -} - -inline void ComputePipelineBuilder::setComputeShader(VulkanShader *shader) -{ - stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; - stageInfo.module = shader->module; - stageInfo.pName = "main"; - - pipelineInfo.stage = stageInfo; -} - -inline std::unique_ptr ComputePipelineBuilder::create(VulkanDevice *device) -{ - VkPipeline pipeline; - vkCreateComputePipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline); - return std::make_unique(device, pipeline); -} - -///////////////////////////////////////////////////////////////////////////// - -inline DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder() -{ - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; -} - -inline void DescriptorSetLayoutBuilder::addBinding(int index, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags) -{ - VkDescriptorSetLayoutBinding binding = { }; - binding.binding = index; - binding.descriptorType = type; - binding.descriptorCount = arrayCount; - binding.stageFlags = stageFlags; - binding.pImmutableSamplers = nullptr; - bindings.push_back(binding); - - layoutInfo.bindingCount = (uint32_t)bindings.size(); - layoutInfo.pBindings = bindings.data(); -} - -inline std::unique_ptr DescriptorSetLayoutBuilder::create(VulkanDevice *device) -{ - VkDescriptorSetLayout layout; - VkResult result = vkCreateDescriptorSetLayout(device->device, &layoutInfo, nullptr, &layout); - CheckVulkanError(result, "Could not create descriptor set layout"); - return std::make_unique(device, layout); -} - -///////////////////////////////////////////////////////////////////////////// - -inline DescriptorPoolBuilder::DescriptorPoolBuilder() -{ - poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.maxSets = 1; - poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; -} - -inline void DescriptorPoolBuilder::setMaxSets(int value) -{ - poolInfo.maxSets = value; -} - -inline void DescriptorPoolBuilder::addPoolSize(VkDescriptorType type, int count) -{ - VkDescriptorPoolSize size; - size.type = type; - size.descriptorCount = count; - poolSizes.push_back(size); - - poolInfo.poolSizeCount = (uint32_t)poolSizes.size(); - poolInfo.pPoolSizes = poolSizes.data(); -} - -inline std::unique_ptr DescriptorPoolBuilder::create(VulkanDevice *device) -{ - VkDescriptorPool descriptorPool; - VkResult result = vkCreateDescriptorPool(device->device, &poolInfo, nullptr, &descriptorPool); - CheckVulkanError(result, "Could not create descriptor pool"); - return std::make_unique(device, descriptorPool); -} - -///////////////////////////////////////////////////////////////////////////// - -inline QueryPoolBuilder::QueryPoolBuilder() -{ - poolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; -} - -inline void QueryPoolBuilder::setQueryType(VkQueryType type, int count, VkQueryPipelineStatisticFlags pipelineStatistics) -{ - poolInfo.queryType = type; - poolInfo.queryCount = count; - poolInfo.pipelineStatistics = pipelineStatistics; -} - -inline std::unique_ptr QueryPoolBuilder::create(VulkanDevice *device) -{ - VkQueryPool queryPool; - VkResult result = vkCreateQueryPool(device->device, &poolInfo, nullptr, &queryPool); - CheckVulkanError(result, "Could not create query pool"); - return std::make_unique(device, queryPool); -} - -///////////////////////////////////////////////////////////////////////////// - -inline FramebufferBuilder::FramebufferBuilder() -{ - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; -} - -inline void FramebufferBuilder::setRenderPass(VulkanRenderPass *renderPass) -{ - framebufferInfo.renderPass = renderPass->renderPass; -} - -inline void FramebufferBuilder::addAttachment(VulkanImageView *view) -{ - attachments.push_back(view->view); - - framebufferInfo.attachmentCount = (uint32_t)attachments.size(); - framebufferInfo.pAttachments = attachments.data(); -} - -inline void FramebufferBuilder::addAttachment(VkImageView view) -{ - attachments.push_back(view); - - framebufferInfo.attachmentCount = (uint32_t)attachments.size(); - framebufferInfo.pAttachments = attachments.data(); -} - -inline void FramebufferBuilder::setSize(int width, int height, int layers) -{ - framebufferInfo.width = width; - framebufferInfo.height = height; - framebufferInfo.layers = 1; -} - -inline std::unique_ptr FramebufferBuilder::create(VulkanDevice *device) -{ - VkFramebuffer framebuffer = 0; - VkResult result = vkCreateFramebuffer(device->device, &framebufferInfo, nullptr, &framebuffer); - CheckVulkanError(result, "Could not create framebuffer"); - return std::make_unique(device, framebuffer); -} - -///////////////////////////////////////////////////////////////////////////// - -inline GraphicsPipelineBuilder::GraphicsPipelineBuilder() -{ - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.pVertexInputState = &vertexInputInfo; - pipelineInfo.pInputAssemblyState = &inputAssembly; - pipelineInfo.pViewportState = &viewportState; - pipelineInfo.pRasterizationState = &rasterizer; - pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pDepthStencilState = &depthStencil; - pipelineInfo.pColorBlendState = &colorBlending; - pipelineInfo.pDynamicState = &dynamicState; - pipelineInfo.subpass = 0; - pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - pipelineInfo.basePipelineIndex = -1; - - vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputInfo.vertexBindingDescriptionCount = 0; - vertexInputInfo.pVertexBindingDescriptions = nullptr; - vertexInputInfo.vertexAttributeDescriptionCount = 0; - vertexInputInfo.pVertexAttributeDescriptions = nullptr; - - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - inputAssembly.primitiveRestartEnable = VK_FALSE; - - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - - depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; - depthStencil.depthBoundsTestEnable = VK_FALSE; - depthStencil.minDepthBounds = 0.0f; - depthStencil.maxDepthBounds = 1.0f; - depthStencil.stencilTestEnable = VK_FALSE; - depthStencil.front = {}; - depthStencil.back = {}; - - rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling.minSampleShading = 1.0f; - multisampling.pSampleMask = nullptr; - multisampling.alphaToCoverageEnable = VK_FALSE; - multisampling.alphaToOneEnable = VK_FALSE; - - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorBlendAttachment.blendEnable = VK_FALSE; - colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; - - colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlending.logicOpEnable = VK_FALSE; - colorBlending.logicOp = VK_LOGIC_OP_COPY; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; - colorBlending.blendConstants[0] = 0.0f; - colorBlending.blendConstants[1] = 0.0f; - colorBlending.blendConstants[2] = 0.0f; - colorBlending.blendConstants[3] = 0.0f; - - dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; -} - -inline void GraphicsPipelineBuilder::setRasterizationSamples(VkSampleCountFlagBits samples) -{ - multisampling.rasterizationSamples = samples; -} - -inline void GraphicsPipelineBuilder::setSubpass(int subpass) -{ - pipelineInfo.subpass = subpass; -} - -inline void GraphicsPipelineBuilder::setLayout(VulkanPipelineLayout *layout) -{ - pipelineInfo.layout = layout->layout; -} - -inline void GraphicsPipelineBuilder::setRenderPass(VulkanRenderPass *renderPass) -{ - pipelineInfo.renderPass = renderPass->renderPass; -} - -inline void GraphicsPipelineBuilder::setTopology(VkPrimitiveTopology topology) -{ - inputAssembly.topology = topology; -} - -inline void GraphicsPipelineBuilder::setViewport(float x, float y, float width, float height, float minDepth, float maxDepth) -{ - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = width; - viewport.height = height; - viewport.minDepth = minDepth; - viewport.maxDepth = maxDepth; - - viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; -} - -inline void GraphicsPipelineBuilder::setScissor(int x, int y, int width, int height) -{ - scissor.offset.x = x; - scissor.offset.y = y; - scissor.extent.width = width; - scissor.extent.height = height; - - viewportState.scissorCount = 1; - viewportState.pScissors = &scissor; -} - -inline void GraphicsPipelineBuilder::setCull(VkCullModeFlags cullMode, VkFrontFace frontFace) -{ - rasterizer.cullMode = cullMode; - rasterizer.frontFace = frontFace; -} - -inline void GraphicsPipelineBuilder::setDepthStencilEnable(bool test, bool write, bool stencil) -{ - depthStencil.depthTestEnable = test ? VK_TRUE : VK_FALSE; - depthStencil.depthWriteEnable = write ? VK_TRUE : VK_FALSE; - depthStencil.stencilTestEnable = stencil ? VK_TRUE : VK_FALSE; -} - -inline void GraphicsPipelineBuilder::setStencil(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp, uint32_t compareMask, uint32_t writeMask, uint32_t reference) -{ - depthStencil.front.failOp = failOp; - depthStencil.front.passOp = passOp; - depthStencil.front.depthFailOp = depthFailOp; - depthStencil.front.compareOp = compareOp; - depthStencil.front.compareMask = compareMask; - depthStencil.front.writeMask = writeMask; - depthStencil.front.reference = reference; - - depthStencil.back.failOp = failOp; - depthStencil.back.passOp = passOp; - depthStencil.back.depthFailOp = depthFailOp; - depthStencil.back.compareOp = compareOp; - depthStencil.back.compareMask = compareMask; - depthStencil.back.writeMask = writeMask; - depthStencil.back.reference = reference; -} - -inline void GraphicsPipelineBuilder::setDepthFunc(VkCompareOp func) -{ - depthStencil.depthCompareOp = func; -} - -inline void GraphicsPipelineBuilder::setDepthClampEnable(bool value) -{ - rasterizer.depthClampEnable = value ? VK_TRUE : VK_FALSE; -} - -inline void GraphicsPipelineBuilder::setDepthBias(bool enable, float biasConstantFactor, float biasClamp, float biasSlopeFactor) -{ - rasterizer.depthBiasEnable = enable ? VK_TRUE : VK_FALSE; - rasterizer.depthBiasConstantFactor = biasConstantFactor; - rasterizer.depthBiasClamp = biasClamp; - rasterizer.depthBiasSlopeFactor = biasSlopeFactor; -} - -inline void GraphicsPipelineBuilder::setColorWriteMask(VkColorComponentFlags mask) -{ - colorBlendAttachment.colorWriteMask = mask; -} - -inline void GraphicsPipelineBuilder::setAdditiveBlendMode() -{ - colorBlendAttachment.blendEnable = VK_TRUE; - colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; -} - -inline void GraphicsPipelineBuilder::setAlphaBlendMode() -{ - colorBlendAttachment.blendEnable = VK_TRUE; - colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; -} - -inline void GraphicsPipelineBuilder::setBlendMode(VkBlendOp op, VkBlendFactor src, VkBlendFactor dst) -{ - colorBlendAttachment.blendEnable = VK_TRUE; - colorBlendAttachment.srcColorBlendFactor = src; - colorBlendAttachment.dstColorBlendFactor = dst; - colorBlendAttachment.colorBlendOp = op; - colorBlendAttachment.srcAlphaBlendFactor = src; - colorBlendAttachment.dstAlphaBlendFactor = dst; - colorBlendAttachment.alphaBlendOp = op; -} - -inline void GraphicsPipelineBuilder::setSubpassColorAttachmentCount(int count) -{ - colorBlendAttachments.resize(count, colorBlendAttachment); - colorBlending.pAttachments = colorBlendAttachments.data(); - colorBlending.attachmentCount = (uint32_t)colorBlendAttachments.size(); -} - -inline void GraphicsPipelineBuilder::addVertexShader(VulkanShader *shader) -{ - VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; - vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; - vertShaderStageInfo.module = shader->module; - vertShaderStageInfo.pName = "main"; - shaderStages.push_back(vertShaderStageInfo); - - pipelineInfo.stageCount = (uint32_t)shaderStages.size(); - pipelineInfo.pStages = shaderStages.data(); -} - -inline void GraphicsPipelineBuilder::addFragmentShader(VulkanShader *shader) -{ - VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; - fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - fragShaderStageInfo.module = shader->module; - fragShaderStageInfo.pName = "main"; - shaderStages.push_back(fragShaderStageInfo); - - pipelineInfo.stageCount = (uint32_t)shaderStages.size(); - pipelineInfo.pStages = shaderStages.data(); -} - -inline void GraphicsPipelineBuilder::addVertexBufferBinding(int index, size_t stride) -{ - VkVertexInputBindingDescription desc = {}; - desc.binding = index; - desc.stride = (uint32_t)stride; - desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - vertexInputBindings.push_back(desc); - - vertexInputInfo.vertexBindingDescriptionCount = (uint32_t)vertexInputBindings.size(); - vertexInputInfo.pVertexBindingDescriptions = vertexInputBindings.data(); -} - -inline void GraphicsPipelineBuilder::addVertexAttribute(int location, int binding, VkFormat format, size_t offset) -{ - VkVertexInputAttributeDescription desc = { }; - desc.location = location; - desc.binding = binding; - desc.format = format; - desc.offset = (uint32_t)offset; - vertexInputAttributes.push_back(desc); - - vertexInputInfo.vertexAttributeDescriptionCount = (uint32_t)vertexInputAttributes.size(); - vertexInputInfo.pVertexAttributeDescriptions = vertexInputAttributes.data(); -} - -inline void GraphicsPipelineBuilder::addDynamicState(VkDynamicState state) -{ - dynamicStates.push_back(state); - dynamicState.dynamicStateCount = (uint32_t)dynamicStates.size(); - dynamicState.pDynamicStates = dynamicStates.data(); -} - -inline std::unique_ptr GraphicsPipelineBuilder::create(VulkanDevice *device) -{ - VkPipeline pipeline = 0; - VkResult result = vkCreateGraphicsPipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline); - CheckVulkanError(result, "Could not create graphics pipeline"); - return std::make_unique(device, pipeline); -} - -///////////////////////////////////////////////////////////////////////////// - -inline PipelineLayoutBuilder::PipelineLayoutBuilder() -{ - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; -} - -inline void PipelineLayoutBuilder::addSetLayout(VulkanDescriptorSetLayout *setLayout) -{ - setLayouts.push_back(setLayout->layout); - pipelineLayoutInfo.setLayoutCount = (uint32_t)setLayouts.size(); - pipelineLayoutInfo.pSetLayouts = setLayouts.data(); -} - -inline void PipelineLayoutBuilder::addPushConstantRange(VkShaderStageFlags stageFlags, size_t offset, size_t size) -{ - VkPushConstantRange range = { }; - range.stageFlags = stageFlags; - range.offset = (uint32_t)offset; - range.size = (uint32_t)size; - pushConstantRanges.push_back(range); - pipelineLayoutInfo.pushConstantRangeCount = (uint32_t)pushConstantRanges.size(); - pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data(); -} - -inline std::unique_ptr PipelineLayoutBuilder::create(VulkanDevice *device) -{ - VkPipelineLayout pipelineLayout; - VkResult result = vkCreatePipelineLayout(device->device, &pipelineLayoutInfo, nullptr, &pipelineLayout); - CheckVulkanError(result, "Could not create pipeline layout"); - return std::make_unique(device, pipelineLayout); -} - -///////////////////////////////////////////////////////////////////////////// - -inline RenderPassBuilder::RenderPassBuilder() -{ - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; -} - -inline void RenderPassBuilder::addAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkImageLayout initialLayout, VkImageLayout finalLayout) -{ - VkAttachmentDescription attachment = {}; - attachment.format = format; - attachment.samples = samples; - attachment.loadOp = load; - attachment.storeOp = store; - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment.initialLayout = initialLayout; - attachment.finalLayout = finalLayout; - attachments.push_back(attachment); - renderPassInfo.pAttachments = attachments.data(); - renderPassInfo.attachmentCount = (uint32_t)attachments.size(); -} - -inline void RenderPassBuilder::addDepthStencilAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkAttachmentLoadOp stencilLoad, VkAttachmentStoreOp stencilStore, VkImageLayout initialLayout, VkImageLayout finalLayout) -{ - VkAttachmentDescription attachment = {}; - attachment.format = format; - attachment.samples = samples; - attachment.loadOp = load; - attachment.storeOp = store; - attachment.stencilLoadOp = stencilLoad; - attachment.stencilStoreOp = stencilStore; - attachment.initialLayout = initialLayout; - attachment.finalLayout = finalLayout; - attachments.push_back(attachment); - renderPassInfo.pAttachments = attachments.data(); - renderPassInfo.attachmentCount = (uint32_t)attachments.size(); -} - -inline void RenderPassBuilder::addExternalSubpassDependency(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) -{ - VkSubpassDependency dependency = {}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = srcStageMask; - dependency.srcAccessMask = srcAccessMask; - dependency.dstStageMask = dstStageMask; - dependency.dstAccessMask = dstAccessMask; - - dependencies.push_back(dependency); - renderPassInfo.pDependencies = dependencies.data(); - renderPassInfo.dependencyCount = (uint32_t)dependencies.size(); -} - -inline void RenderPassBuilder::addSubpass() -{ - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - - subpasses.push_back(subpass); - renderPassInfo.pSubpasses = subpasses.data(); - renderPassInfo.subpassCount = (uint32_t)subpasses.size(); - - subpassData.push_back(std::make_unique()); -} - -inline void RenderPassBuilder::addSubpassColorAttachmentRef(uint32_t index, VkImageLayout layout) -{ - VkAttachmentReference colorAttachmentRef = {}; - colorAttachmentRef.attachment = index; - colorAttachmentRef.layout = layout; - - subpassData.back()->colorRefs.push_back(colorAttachmentRef); - subpasses.back().pColorAttachments = subpassData.back()->colorRefs.data(); - subpasses.back().colorAttachmentCount = (uint32_t)subpassData.back()->colorRefs.size(); -} - -inline void RenderPassBuilder::addSubpassDepthStencilAttachmentRef(uint32_t index, VkImageLayout layout) -{ - VkAttachmentReference &depthAttachmentRef = subpassData.back()->depthRef; - depthAttachmentRef.attachment = index; - depthAttachmentRef.layout = layout; - - VkSubpassDescription &subpass = subpasses.back(); - subpass.pDepthStencilAttachment = &depthAttachmentRef; -} - -inline std::unique_ptr RenderPassBuilder::create(VulkanDevice *device) -{ - VkRenderPass renderPass = 0; - VkResult result = vkCreateRenderPass(device->device, &renderPassInfo, nullptr, &renderPass); - CheckVulkanError(result, "Could not create render pass"); - return std::make_unique(device, renderPass); -} - -///////////////////////////////////////////////////////////////////////////// - -inline void PipelineBarrier::addMemory(VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) -{ - VkMemoryBarrier barrier = { }; - barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; - barrier.srcAccessMask = srcAccessMask; - barrier.dstAccessMask = dstAccessMask; - memoryBarriers.push_back(barrier); -} - -inline void PipelineBarrier::addBuffer(VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) -{ - addBuffer(buffer, 0, buffer->size, srcAccessMask, dstAccessMask); -} - -inline void PipelineBarrier::addBuffer(VulkanBuffer *buffer, VkDeviceSize offset, VkDeviceSize size, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) -{ - VkBufferMemoryBarrier barrier = { }; - barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - barrier.srcAccessMask = srcAccessMask; - barrier.dstAccessMask = dstAccessMask; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.buffer = buffer->buffer; - barrier.offset = offset; - barrier.size = size; - bufferMemoryBarriers.push_back(barrier); -} - -inline void PipelineBarrier::addImage(VulkanImage *image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount) -{ - addImage(image->image, oldLayout, newLayout, srcAccessMask, dstAccessMask, aspectMask, baseMipLevel, levelCount); -} - -inline void PipelineBarrier::addImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount) -{ - VkImageMemoryBarrier barrier = { }; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.srcAccessMask = srcAccessMask; - barrier.dstAccessMask = dstAccessMask; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = aspectMask; - barrier.subresourceRange.baseMipLevel = baseMipLevel; - barrier.subresourceRange.levelCount = levelCount; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - imageMemoryBarriers.push_back(barrier); -} - -inline void PipelineBarrier::addQueueTransfer(int srcFamily, int dstFamily, VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) -{ - VkBufferMemoryBarrier barrier = { }; - barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - barrier.srcAccessMask = srcAccessMask; - barrier.dstAccessMask = dstAccessMask; - barrier.srcQueueFamilyIndex = srcFamily; - barrier.dstQueueFamilyIndex = dstFamily; - barrier.buffer = buffer->buffer; - barrier.offset = 0; - barrier.size = buffer->size; - bufferMemoryBarriers.push_back(barrier); -} - -inline void PipelineBarrier::addQueueTransfer(int srcFamily, int dstFamily, VulkanImage *image, VkImageLayout layout, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount) -{ - VkImageMemoryBarrier barrier = { }; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = layout; - barrier.newLayout = layout; - barrier.srcQueueFamilyIndex = srcFamily; - barrier.dstQueueFamilyIndex = dstFamily; - barrier.image = image->image; - barrier.subresourceRange.aspectMask = aspectMask; - barrier.subresourceRange.baseMipLevel = baseMipLevel; - barrier.subresourceRange.levelCount = levelCount; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - imageMemoryBarriers.push_back(barrier); -} - -inline void PipelineBarrier::execute(VulkanCommandBuffer *commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags) -{ - commandBuffer->pipelineBarrier( - srcStageMask, dstStageMask, dependencyFlags, - (uint32_t)memoryBarriers.size(), memoryBarriers.data(), - (uint32_t)bufferMemoryBarriers.size(), bufferMemoryBarriers.data(), - (uint32_t)imageMemoryBarriers.size(), imageMemoryBarriers.data()); -} - -///////////////////////////////////////////////////////////////////////////// - -inline QueueSubmit::QueueSubmit() -{ - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; -} - -inline void QueueSubmit::addCommandBuffer(VulkanCommandBuffer *buffer) -{ - commandBuffers.push_back(buffer->buffer); - submitInfo.pCommandBuffers = commandBuffers.data(); - submitInfo.commandBufferCount = (uint32_t)commandBuffers.size(); -} - -inline void QueueSubmit::addWait(VkPipelineStageFlags waitStageMask, VulkanSemaphore *semaphore) -{ - waitStages.push_back(waitStageMask); - waitSemaphores.push_back(semaphore->semaphore); - - submitInfo.pWaitDstStageMask = waitStages.data(); - submitInfo.pWaitSemaphores = waitSemaphores.data(); - submitInfo.waitSemaphoreCount = (uint32_t)waitSemaphores.size(); -} - -inline void QueueSubmit::addSignal(VulkanSemaphore *semaphore) -{ - signalSemaphores.push_back(semaphore->semaphore); - submitInfo.pSignalSemaphores = signalSemaphores.data(); - submitInfo.signalSemaphoreCount = (uint32_t)signalSemaphores.size(); -} - -inline void QueueSubmit::execute(VulkanDevice *device, VkQueue queue, VulkanFence *fence) -{ - VkResult result = vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, fence ? fence->fence : VK_NULL_HANDLE); - CheckVulkanError(result, "Could not submit command buffer"); -} - -///////////////////////////////////////////////////////////////////////////// - -inline void WriteDescriptors::addBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer) -{ - addBuffer(descriptorSet, binding, type, buffer, 0, buffer->size); -} - -inline void WriteDescriptors::addBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer, size_t offset, size_t range) -{ - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = buffer->buffer; - bufferInfo.offset = offset; - bufferInfo.range = range; - - auto extra = std::make_unique(); - extra->bufferInfo = bufferInfo; - - VkWriteDescriptorSet descriptorWrite = {}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = descriptorSet->set; - descriptorWrite.dstBinding = binding; - descriptorWrite.dstArrayElement = 0; - descriptorWrite.descriptorType = type; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pBufferInfo = &extra->bufferInfo; - writes.push_back(descriptorWrite); - writeExtras.push_back(std::move(extra)); -} - -inline void WriteDescriptors::addStorageImage(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VkImageLayout imageLayout) -{ - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageView = view->view; - imageInfo.imageLayout = imageLayout; - - auto extra = std::make_unique(); - extra->imageInfo = imageInfo; - - VkWriteDescriptorSet descriptorWrite = {}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = descriptorSet->set; - descriptorWrite.dstBinding = binding; - descriptorWrite.dstArrayElement = 0; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pImageInfo = &extra->imageInfo; - writes.push_back(descriptorWrite); - writeExtras.push_back(std::move(extra)); -} - -inline void WriteDescriptors::addCombinedImageSampler(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VulkanSampler *sampler, VkImageLayout imageLayout) -{ - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageView = view->view; - imageInfo.sampler = sampler->sampler; - imageInfo.imageLayout = imageLayout; - - auto extra = std::make_unique(); - extra->imageInfo = imageInfo; - - VkWriteDescriptorSet descriptorWrite = {}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = descriptorSet->set; - descriptorWrite.dstBinding = binding; - descriptorWrite.dstArrayElement = 0; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pImageInfo = &extra->imageInfo; - writes.push_back(descriptorWrite); - writeExtras.push_back(std::move(extra)); -} - -inline void WriteDescriptors::updateSets(VulkanDevice *device) -{ - vkUpdateDescriptorSets(device->device, (uint32_t)writes.size(), writes.data(), 0, nullptr); -} diff --git a/src/rendering/vulkan/system/vk_device.cpp b/src/rendering/vulkan/system/vk_device.cpp deleted file mode 100644 index f2f018c6f7a..00000000000 --- a/src/rendering/vulkan/system/vk_device.cpp +++ /dev/null @@ -1,572 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "volk/volk.h" - -#ifdef _WIN32 -#undef max -#undef min -#endif - -#include -#include -#include -#include -#include - -#include "vk_device.h" -#include "vk_swapchain.h" -#include "vk_objects.h" -#include "c_cvars.h" -#include "c_dispatch.h" -#include "i_system.h" -#include "version.h" -#include "doomerrors.h" -#include "gamedata/fonts/v_text.h" - -bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names); -bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface); - -FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames); - -// Physical device info -static std::vector AvailableDevices; -static std::vector SupportedDevices; - -CUSTOM_CVAR(Bool, vk_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - Printf("This won't take effect until " GAMENAME " is restarted.\n"); -} - -CVAR(Bool, vk_debug_callstack, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - -CUSTOM_CVAR(Int, vk_device, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - Printf("This won't take effect until " GAMENAME " is restarted.\n"); -} - -CCMD(vk_listdevices) -{ - for (size_t i = 0; i < SupportedDevices.size(); i++) - { - Printf("#%d - %s\n", (int)i, SupportedDevices[i].device->Properties.deviceName); - } -} - -VulkanDevice::VulkanDevice() -{ - try - { - InitVolk(); - CreateInstance(); - CreateSurface(); - SelectPhysicalDevice(); - SelectFeatures(); - CreateDevice(); - CreateAllocator(); - } - catch (...) - { - ReleaseResources(); - throw; - } -} - -VulkanDevice::~VulkanDevice() -{ - ReleaseResources(); -} - -void VulkanDevice::SelectFeatures() -{ - UsedDeviceFeatures.samplerAnisotropy = PhysicalDevice.Features.samplerAnisotropy; - UsedDeviceFeatures.fragmentStoresAndAtomics = PhysicalDevice.Features.fragmentStoresAndAtomics; - UsedDeviceFeatures.depthClamp = PhysicalDevice.Features.depthClamp; - UsedDeviceFeatures.shaderClipDistance = PhysicalDevice.Features.shaderClipDistance; -} - -bool VulkanDevice::CheckRequiredFeatures(const VkPhysicalDeviceFeatures &f) -{ - return - f.samplerAnisotropy == VK_TRUE && - f.fragmentStoresAndAtomics == VK_TRUE && - f.depthClamp == VK_TRUE; -} - -void VulkanDevice::SelectPhysicalDevice() -{ - AvailableDevices = GetPhysicalDevices(instance); - if (AvailableDevices.empty()) - VulkanError("No Vulkan devices found. Either the graphics card has no vulkan support or the driver is too old."); - - for (size_t idx = 0; idx < AvailableDevices.size(); idx++) - { - const auto &info = AvailableDevices[idx]; - - if (!CheckRequiredFeatures(info.Features)) - continue; - - std::set requiredExtensionSearch(EnabledDeviceExtensions.begin(), EnabledDeviceExtensions.end()); - for (const auto &ext : info.Extensions) - requiredExtensionSearch.erase(ext.extensionName); - if (!requiredExtensionSearch.empty()) - continue; - - VulkanCompatibleDevice dev; - dev.device = &AvailableDevices[idx]; - - // Figure out what can present - for (int i = 0; i < (int)info.QueueFamilies.size(); i++) - { - VkBool32 presentSupport = false; - VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(info.Device, i, surface, &presentSupport); - if (result == VK_SUCCESS && info.QueueFamilies[i].queueCount > 0 && presentSupport) - { - dev.presentFamily = i; - break; - } - } - - // The vulkan spec states that graphics and compute queues can always do transfer. - // Furthermore the spec states that graphics queues always can do compute. - // Last, the spec makes it OPTIONAL whether the VK_QUEUE_TRANSFER_BIT is set for such queues, but they MUST support transfer. - // - // In short: pick the first graphics queue family for everything. - for (int i = 0; i < (int)info.QueueFamilies.size(); i++) - { - const auto &queueFamily = info.QueueFamilies[i]; - if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)) - { - dev.graphicsFamily = i; - dev.graphicsTimeQueries = queueFamily.timestampValidBits != 0; - break; - } - } - - if (dev.graphicsFamily != -1 && dev.presentFamily != -1) - { - SupportedDevices.push_back(dev); - } - } - - if (SupportedDevices.empty()) - VulkanError("No Vulkan device supports the minimum requirements of this application"); - - // The device order returned by Vulkan can be anything. Prefer discrete > integrated > virtual gpu > cpu > other - std::stable_sort(SupportedDevices.begin(), SupportedDevices.end(), [&](const auto &a, const auto b) { - - // Sort by GPU type first. This will ensure the "best" device is most likely to map to vk_device 0 - static const int typeSort[] = { 4, 1, 0, 2, 3 }; - int sortA = a.device->Properties.deviceType < 5 ? typeSort[a.device->Properties.deviceType] : (int)a.device->Properties.deviceType; - int sortB = b.device->Properties.deviceType < 5 ? typeSort[b.device->Properties.deviceType] : (int)b.device->Properties.deviceType; - if (sortA != sortB) - return sortA < sortB; - - // Then sort by the device's unique ID so that vk_device uses a consistent order - int sortUUID = memcmp(a.device->Properties.pipelineCacheUUID, b.device->Properties.pipelineCacheUUID, VK_UUID_SIZE); - return sortUUID < 0; - }); - - size_t selected = vk_device; - if (selected >= SupportedDevices.size()) - selected = 0; - - // Enable optional extensions we are interested in, if they are available on this device - for (const auto &ext : SupportedDevices[selected].device->Extensions) - { - for (const auto &opt : OptionalDeviceExtensions) - { - if (strcmp(ext.extensionName, opt) == 0) - { - EnabledDeviceExtensions.push_back(opt); - } - } - } - - PhysicalDevice = *SupportedDevices[selected].device; - graphicsFamily = SupportedDevices[selected].graphicsFamily; - presentFamily = SupportedDevices[selected].presentFamily; - graphicsTimeQueries = SupportedDevices[selected].graphicsTimeQueries; -} - -bool VulkanDevice::SupportsDeviceExtension(const char *ext) const -{ - return std::find(EnabledDeviceExtensions.begin(), EnabledDeviceExtensions.end(), ext) != EnabledDeviceExtensions.end(); -} - -void VulkanDevice::CreateAllocator() -{ - VmaAllocatorCreateInfo allocinfo = {}; - if (SupportsDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) && SupportsDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) - allocinfo.flags = VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - allocinfo.physicalDevice = PhysicalDevice.Device; - allocinfo.device = device; - allocinfo.preferredLargeHeapBlockSize = 64 * 1024 * 1024; - if (vmaCreateAllocator(&allocinfo, &allocator) != VK_SUCCESS) - VulkanError("Unable to create allocator"); -} - -void VulkanDevice::CreateDevice() -{ - float queuePriority = 1.0f; - std::vector queueCreateInfos; - - std::set neededFamilies; - neededFamilies.insert(graphicsFamily); - neededFamilies.insert(presentFamily); - - for (int index : neededFamilies) - { - VkDeviceQueueCreateInfo queueCreateInfo = {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = index; - queueCreateInfo.queueCount = 1; - queueCreateInfo.pQueuePriorities = &queuePriority; - queueCreateInfos.push_back(queueCreateInfo); - } - - VkDeviceCreateInfo deviceCreateInfo = {}; - deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceCreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size(); - deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data(); - deviceCreateInfo.pEnabledFeatures = &UsedDeviceFeatures; - deviceCreateInfo.enabledExtensionCount = (uint32_t)EnabledDeviceExtensions.size(); - deviceCreateInfo.ppEnabledExtensionNames = EnabledDeviceExtensions.data(); - deviceCreateInfo.enabledLayerCount = 0; - - VkResult result = vkCreateDevice(PhysicalDevice.Device, &deviceCreateInfo, nullptr, &device); - CheckVulkanError(result, "Could not create vulkan device"); - - volkLoadDevice(device); - - vkGetDeviceQueue(device, graphicsFamily, 0, &graphicsQueue); - vkGetDeviceQueue(device, presentFamily, 0, &presentQueue); -} - -void VulkanDevice::CreateSurface() -{ - if (!I_CreateVulkanSurface(instance, &surface)) - { - VulkanError("Could not create vulkan surface"); - } -} - -void VulkanDevice::CreateInstance() -{ - AvailableLayers = GetAvailableLayers(); - Extensions = GetExtensions(); - EnabledExtensions = GetPlatformExtensions(); - - std::string debugLayer = "VK_LAYER_LUNARG_standard_validation"; - bool wantDebugLayer = vk_debug; - bool debugLayerFound = false; - for (const VkLayerProperties &layer : AvailableLayers) - { - if (layer.layerName == debugLayer && wantDebugLayer) - { - EnabledValidationLayers.push_back(debugLayer.c_str()); - EnabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - debugLayerFound = true; - } - } - - // Enable optional instance extensions we are interested in - for (const auto &ext : Extensions) - { - for (const auto &opt : OptionalExtensions) - { - if (strcmp(ext.extensionName, opt) == 0) - { - EnabledExtensions.push_back(opt); - } - } - } - - VkApplicationInfo appInfo = {}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "GZDoom"; - appInfo.applicationVersion = VK_MAKE_VERSION(VER_MAJOR, VER_MINOR, VER_REVISION); - appInfo.pEngineName = "GZDoom"; - appInfo.engineVersion = VK_MAKE_VERSION(ENG_MAJOR, ENG_MINOR, ENG_REVISION); - appInfo.apiVersion = VK_API_VERSION_1_0; - - VkInstanceCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pApplicationInfo = &appInfo; - createInfo.enabledExtensionCount = (uint32_t)EnabledExtensions.size(); - createInfo.enabledLayerCount = (uint32_t)EnabledValidationLayers.size(); - createInfo.ppEnabledLayerNames = EnabledValidationLayers.data(); - createInfo.ppEnabledExtensionNames = EnabledExtensions.data(); - - VkResult result = vkCreateInstance(&createInfo, nullptr, &instance); - CheckVulkanError(result, "Could not create vulkan instance"); - - volkLoadInstance(instance); - - if (debugLayerFound) - { - VkDebugUtilsMessengerCreateInfoEXT createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - createInfo.messageSeverity = - //VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - //VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - createInfo.messageType = - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - createInfo.pfnUserCallback = DebugCallback; - createInfo.pUserData = this; - result = vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger); - CheckVulkanError(result, "vkCreateDebugUtilsMessengerEXT failed"); - - DebugLayerActive = true; - } -} - -VkBool32 VulkanDevice::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData) -{ - VulkanDevice *device = (VulkanDevice*)userData; - - static std::mutex mtx; - static std::set seenMessages; - static int totalMessages; - - std::unique_lock lock(mtx); - - FString msg = callbackData->pMessage; - - // For patent-pending reasons the validation layer apparently can't do this itself.. - for (uint32_t i = 0; i < callbackData->objectCount; i++) - { - if (callbackData->pObjects[i].pObjectName) - { - FString hexname; - hexname.Format("0x%llx", callbackData->pObjects[i].objectHandle); - msg.Substitute(hexname.GetChars(), callbackData->pObjects[i].pObjectName); - } - } - - bool found = seenMessages.find(msg) != seenMessages.end(); - if (!found) - { - if (totalMessages < 20) - { - totalMessages++; - seenMessages.insert(msg); - - const char *typestr; - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) - { - typestr = "vulkan error"; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) - { - typestr = "vulkan warning"; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) - { - typestr = "vulkan info"; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) - { - typestr = "vulkan verbose"; - } - else - { - typestr = "vulkan"; - } - - Printf("\n"); - Printf(TEXTCOLOR_RED "[%s] ", typestr); - Printf(TEXTCOLOR_WHITE "%s\n", msg.GetChars()); - - if (vk_debug_callstack) - { - FString callstack = JitCaptureStackTrace(0, true); - if (!callstack.IsEmpty()) - Printf("%s\n", callstack.GetChars()); - } - } - } - - return VK_FALSE; -} - -std::vector VulkanDevice::GetAvailableLayers() -{ - uint32_t layerCount; - VkResult result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr); - - std::vector availableLayers(layerCount); - result = vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); - return availableLayers; -} - -std::vector VulkanDevice::GetExtensions() -{ - uint32_t extensionCount = 0; - VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); - - std::vector extensions(extensionCount); - result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); - return extensions; -} - -std::vector VulkanDevice::GetPhysicalDevices(VkInstance instance) -{ - uint32_t deviceCount = 0; - VkResult result = vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); - if (result == VK_ERROR_INITIALIZATION_FAILED) // Some drivers return this when a card does not support vulkan - return {}; - CheckVulkanError(result, "vkEnumeratePhysicalDevices failed"); - if (deviceCount == 0) - return {}; - - std::vector devices(deviceCount); - result = vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); - CheckVulkanError(result, "vkEnumeratePhysicalDevices failed (2)"); - - std::vector devinfo(deviceCount); - for (size_t i = 0; i < devices.size(); i++) - { - auto &dev = devinfo[i]; - dev.Device = devices[i]; - - vkGetPhysicalDeviceMemoryProperties(dev.Device, &dev.MemoryProperties); - vkGetPhysicalDeviceProperties(dev.Device, &dev.Properties); - vkGetPhysicalDeviceFeatures(dev.Device, &dev.Features); - - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(dev.Device, &queueFamilyCount, nullptr); - dev.QueueFamilies.resize(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(dev.Device, &queueFamilyCount, dev.QueueFamilies.data()); - - uint32_t deviceExtensionCount = 0; - vkEnumerateDeviceExtensionProperties(dev.Device, nullptr, &deviceExtensionCount, nullptr); - dev.Extensions.resize(deviceExtensionCount); - vkEnumerateDeviceExtensionProperties(dev.Device, nullptr, &deviceExtensionCount, dev.Extensions.data()); - } - return devinfo; -} - -std::vector VulkanDevice::GetPlatformExtensions() -{ - uint32_t extensionCount = 0; - if (!I_GetVulkanPlatformExtensions(&extensionCount, nullptr)) - VulkanError("Cannot obtain number of Vulkan extensions"); - - std::vector extensions(extensionCount); - if (!I_GetVulkanPlatformExtensions(&extensionCount, extensions.data())) - VulkanError("Cannot obtain list of Vulkan extensions"); - return extensions; -} - -void VulkanDevice::InitVolk() -{ - if (volkInitialize() != VK_SUCCESS) - { - VulkanError("Unable to find Vulkan"); - } - auto iver = volkGetInstanceVersion(); - if (iver == 0) - { - VulkanError("Vulkan not supported"); - } -} - -void VulkanDevice::ReleaseResources() -{ - if (device) - vkDeviceWaitIdle(device); - - if (allocator) - vmaDestroyAllocator(allocator); - - if (device) - vkDestroyDevice(device, nullptr); - device = nullptr; - - if (surface) - vkDestroySurfaceKHR(instance, surface, nullptr); - surface = 0; - - if (debugMessenger) - vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); - - if (instance) - vkDestroyInstance(instance, nullptr); - instance = nullptr; -} - -uint32_t VulkanDevice::FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) -{ - for (uint32_t i = 0; i < PhysicalDevice.MemoryProperties.memoryTypeCount; i++) - { - if ((typeFilter & (1 << i)) && (PhysicalDevice.MemoryProperties.memoryTypes[i].propertyFlags & properties) == properties) - return i; - } - - VulkanError("failed to find suitable memory type!"); - return 0; -} - -FString VkResultToString(VkResult result) -{ - switch (result) - { - case VK_SUCCESS: return "success"; - case VK_NOT_READY: return "not ready"; - case VK_TIMEOUT: return "timeout"; - case VK_EVENT_SET: return "event set"; - case VK_EVENT_RESET: return "event reset"; - case VK_INCOMPLETE: return "incomplete"; - case VK_ERROR_OUT_OF_HOST_MEMORY: return "out of host memory"; - case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "out of device memory"; - case VK_ERROR_INITIALIZATION_FAILED: return "initialization failed"; - case VK_ERROR_DEVICE_LOST: return "device lost"; - case VK_ERROR_MEMORY_MAP_FAILED: return "memory map failed"; - case VK_ERROR_LAYER_NOT_PRESENT: return "layer not present"; - case VK_ERROR_EXTENSION_NOT_PRESENT: return "extension not present"; - case VK_ERROR_FEATURE_NOT_PRESENT: return "feature not present"; - case VK_ERROR_INCOMPATIBLE_DRIVER: return "incompatible driver"; - case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects"; - case VK_ERROR_FORMAT_NOT_SUPPORTED: return "format not supported"; - case VK_ERROR_FRAGMENTED_POOL: return "fragmented pool"; - case VK_ERROR_OUT_OF_POOL_MEMORY: return "out of pool memory"; - case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "invalid external handle"; - case VK_ERROR_SURFACE_LOST_KHR: return "surface lost"; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "native window in use"; - case VK_SUBOPTIMAL_KHR: return "suboptimal"; - case VK_ERROR_OUT_OF_DATE_KHR: return "out of date"; - case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "incompatible display"; - case VK_ERROR_VALIDATION_FAILED_EXT: return "validation failed"; - case VK_ERROR_INVALID_SHADER_NV: return "invalid shader"; - case VK_ERROR_FRAGMENTATION_EXT: return "fragmentation"; - case VK_ERROR_NOT_PERMITTED_EXT: return "not permitted"; - default: break; - } - FString res; - res.Format("vkResult %d", (int)result); - return result; -} diff --git a/src/rendering/vulkan/system/vk_device.h b/src/rendering/vulkan/system/vk_device.h deleted file mode 100644 index 43185bd5057..00000000000 --- a/src/rendering/vulkan/system/vk_device.h +++ /dev/null @@ -1,121 +0,0 @@ -#pragma once - -#include "volk/volk.h" -#include "vk_mem_alloc/vk_mem_alloc.h" -#include "utility/doomerrors.h" -#include -#include -#include -#include - -class VulkanSwapChain; -class VulkanSemaphore; -class VulkanFence; - -class VulkanPhysicalDevice -{ -public: - VkPhysicalDevice Device = VK_NULL_HANDLE; - - std::vector Extensions; - std::vector QueueFamilies; - VkPhysicalDeviceProperties Properties = {}; - VkPhysicalDeviceFeatures Features = {}; - VkPhysicalDeviceMemoryProperties MemoryProperties = {}; -}; - -class VulkanCompatibleDevice -{ -public: - VulkanPhysicalDevice *device = nullptr; - int graphicsFamily = -1; - int presentFamily = -1; - bool graphicsTimeQueries = false; -}; - -class VulkanDevice -{ -public: - VulkanDevice(); - ~VulkanDevice(); - - void SetDebugObjectName(const char *name, uint64_t handle, VkObjectType type) - { - if (!DebugLayerActive) return; - - VkDebugUtilsObjectNameInfoEXT info = {}; - info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - info.objectHandle = handle; - info.objectType = type; - info.pObjectName = name; - vkSetDebugUtilsObjectNameEXT(device, &info); - } - - uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); - - // Instance setup - std::vector AvailableLayers; - std::vector Extensions; - std::vector EnabledExtensions; - std::vector OptionalExtensions = { VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME }; - std::vector EnabledValidationLayers; - - // Device setup - VkPhysicalDeviceFeatures UsedDeviceFeatures = {}; - std::vector EnabledDeviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; - std::vector OptionalDeviceExtensions = { VK_EXT_HDR_METADATA_EXTENSION_NAME, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME }; - VulkanPhysicalDevice PhysicalDevice; - bool DebugLayerActive = false; - - VkInstance instance = VK_NULL_HANDLE; - VkSurfaceKHR surface = VK_NULL_HANDLE; - VkDevice device = VK_NULL_HANDLE; - VmaAllocator allocator = VK_NULL_HANDLE; - - VkQueue graphicsQueue = VK_NULL_HANDLE; - VkQueue presentQueue = VK_NULL_HANDLE; - - int graphicsFamily = -1; - int presentFamily = -1; - bool graphicsTimeQueries = false; - -private: - void CreateInstance(); - void CreateSurface(); - void SelectPhysicalDevice(); - void SelectFeatures(); - void CreateDevice(); - void CreateAllocator(); - void ReleaseResources(); - - bool SupportsDeviceExtension(const char *ext) const; - - static bool CheckRequiredFeatures(const VkPhysicalDeviceFeatures &f); - - VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; - - static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); - - static void InitVolk(); - static std::vector GetAvailableLayers(); - static std::vector GetExtensions(); - static std::vector GetPlatformExtensions(); - static std::vector GetPhysicalDevices(VkInstance instance); -}; - -FString VkResultToString(VkResult result); - -inline void VulkanError(const char *text) -{ - throw CVulkanError(text); -} - -inline void CheckVulkanError(VkResult result, const char *text) -{ - if (result >= VK_SUCCESS) - return; - - FString msg; - msg.Format("%s: %s", text, VkResultToString(result).GetChars()); - throw CVulkanError(msg.GetChars()); -} diff --git a/src/rendering/vulkan/system/vk_framebuffer.cpp b/src/rendering/vulkan/system/vk_framebuffer.cpp deleted file mode 100644 index eb5cf096032..00000000000 --- a/src/rendering/vulkan/system/vk_framebuffer.cpp +++ /dev/null @@ -1,990 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "volk/volk.h" - -#include "v_video.h" -#include "m_png.h" -#include "templates.h" -#include "r_videoscale.h" -#include "actor.h" -#include "i_time.h" -#include "g_game.h" -#include "gamedata/fonts/v_text.h" - -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/models/hw_models.h" -#include "hwrenderer/scene/hw_skydome.h" -#include "hwrenderer/scene/hw_fakeflat.h" -#include "hwrenderer/scene/hw_drawinfo.h" -#include "hwrenderer/scene/hw_portal.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "hwrenderer/data/flatvertices.h" -#include "hwrenderer/data/shaderuniforms.h" -#include "hwrenderer/dynlights/hw_lightbuffer.h" - -#include "swrenderer/r_swscene.h" - -#include "vk_framebuffer.h" -#include "vk_buffers.h" -#include "vulkan/renderer/vk_renderstate.h" -#include "vulkan/renderer/vk_renderpass.h" -#include "vulkan/renderer/vk_streambuffer.h" -#include "vulkan/renderer/vk_postprocess.h" -#include "vulkan/renderer/vk_renderbuffers.h" -#include "vulkan/shaders/vk_shader.h" -#include "vulkan/textures/vk_samplers.h" -#include "vulkan/textures/vk_hwtexture.h" -#include "vulkan/system/vk_builders.h" -#include "vulkan/system/vk_swapchain.h" -#include "doomerrors.h" - -void Draw2D(F2DDrawer *drawer, FRenderState &state); -void DoWriteSavePic(FileWriter *file, ESSType ssformat, uint8_t *scr, int width, int height, sector_t *viewsector, bool upsidedown); - -EXTERN_CVAR(Bool, r_drawvoxels) -EXTERN_CVAR(Int, gl_tonemap) -EXTERN_CVAR(Int, screenblocks) -EXTERN_CVAR(Bool, cl_capfps) -EXTERN_CVAR(Bool, gl_no_skyclear) - -extern bool NoInterpolateView; -extern int rendered_commandbuffers; -int current_rendered_commandbuffers; - -extern bool gpuStatActive; -extern bool keepGpuStatActive; -extern FString gpuStatOutput; - -VulkanFrameBuffer::VulkanFrameBuffer(void *hMonitor, bool fullscreen, VulkanDevice *dev) : - Super(hMonitor, fullscreen) -{ - device = dev; - - swapChain = std::make_unique(device); - mSwapChainImageAvailableSemaphore.reset(new VulkanSemaphore(device)); - mRenderFinishedSemaphore.reset(new VulkanSemaphore(device)); - - for (auto &semaphore : mSubmitSemaphore) - semaphore.reset(new VulkanSemaphore(device)); - - for (auto &fence : mSubmitFence) - fence.reset(new VulkanFence(device)); - - for (int i = 0; i < maxConcurrentSubmitCount; i++) - mSubmitWaitFences[i] = mSubmitFence[i]->fence; -} - -VulkanFrameBuffer::~VulkanFrameBuffer() -{ - vkDeviceWaitIdle(device->device); // make sure the GPU is no longer using any objects before RAII tears them down - - // screen is already null at this point, but VkHardwareTexture::ResetAll needs it during clean up. Is there a better way we can do this? - auto tmp = screen; - screen = this; - - // All descriptors must be destroyed before the descriptor pool in renderpass manager is destroyed - VkHardwareTexture::ResetAll(); - VKBuffer::ResetAll(); - PPResource::ResetAll(); - - delete MatrixBuffer; - delete StreamBuffer; - delete mVertexData; - delete mSkyData; - delete mViewpoints; - delete mLights; - mShadowMap.Reset(); - - screen = tmp; - - DeleteFrameObjects(); -} - -void VulkanFrameBuffer::InitializeState() -{ - static bool first = true; - if (first) - { - PrintStartupLog(); - first = false; - } - - // Use the same names here as OpenGL returns. - switch (device->PhysicalDevice.Properties.vendorID) - { - case 0x1002: vendorstring = "ATI Technologies Inc."; break; - case 0x10DE: vendorstring = "NVIDIA Corporation"; break; - case 0x8086: vendorstring = "Intel"; break; - default: vendorstring = "Unknown"; break; - } - - hwcaps = RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE; - glslversion = 4.50f; - uniformblockalignment = (unsigned int)device->PhysicalDevice.Properties.limits.minUniformBufferOffsetAlignment; - maxuniformblock = device->PhysicalDevice.Properties.limits.maxUniformBufferRange; - - mCommandPool.reset(new VulkanCommandPool(device, device->graphicsFamily)); - - mScreenBuffers.reset(new VkRenderBuffers()); - mSaveBuffers.reset(new VkRenderBuffers()); - mActiveRenderBuffers = mScreenBuffers.get(); - - mPostprocess.reset(new VkPostprocess()); - mRenderPassManager.reset(new VkRenderPassManager()); - - mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight()); - mSkyData = new FSkyVertexBuffer; - mViewpoints = new HWViewpointBuffer; - mLights = new FLightBuffer(); - - CreateFanToTrisIndexBuffer(); - - // To do: move this to HW renderer interface maybe? - MatrixBuffer = new VkStreamBuffer(sizeof(MatricesUBO), 50000); - StreamBuffer = new VkStreamBuffer(sizeof(StreamUBO), 300); - - mShaderManager.reset(new VkShaderManager(device)); - mSamplerManager.reset(new VkSamplerManager(device)); - mRenderPassManager->Init(); -#ifdef __APPLE__ - mRenderState.reset(new VkRenderStateMolten()); -#else - mRenderState.reset(new VkRenderState()); -#endif - - if (device->graphicsTimeQueries) - { - QueryPoolBuilder querybuilder; - querybuilder.setQueryType(VK_QUERY_TYPE_TIMESTAMP, MaxTimestampQueries); - mTimestampQueryPool = querybuilder.create(device); - - GetDrawCommands()->resetQueryPool(mTimestampQueryPool.get(), 0, MaxTimestampQueries); - } -} - -void VulkanFrameBuffer::Update() -{ - twoD.Reset(); - Flush3D.Reset(); - - Flush3D.Clock(); - - GetPostprocess()->SetActiveRenderTarget(); - - Draw2D(); - Clear2D(); - - mRenderState->EndRenderPass(); - mRenderState->EndFrame(); - - Flush3D.Unclock(); - - WaitForCommands(true); - UpdateGpuStats(); - - Super::Update(); -} - -void VulkanFrameBuffer::DeleteFrameObjects() -{ - FrameDeleteList.Images.clear(); - FrameDeleteList.ImageViews.clear(); - FrameDeleteList.Framebuffers.clear(); - FrameDeleteList.Buffers.clear(); - FrameDeleteList.Descriptors.clear(); - FrameDeleteList.DescriptorPools.clear(); - FrameDeleteList.CommandBuffers.clear(); -} - -void VulkanFrameBuffer::FlushCommands(VulkanCommandBuffer **commands, size_t count, bool finish, bool lastsubmit) -{ - int currentIndex = mNextSubmit % maxConcurrentSubmitCount; - - if (mNextSubmit >= maxConcurrentSubmitCount) - { - vkWaitForFences(device->device, 1, &mSubmitFence[currentIndex]->fence, VK_TRUE, std::numeric_limits::max()); - vkResetFences(device->device, 1, &mSubmitFence[currentIndex]->fence); - } - - QueueSubmit submit; - - for (size_t i = 0; i < count; i++) - submit.addCommandBuffer(commands[i]); - - if (mNextSubmit > 0) - submit.addWait(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, mSubmitSemaphore[(mNextSubmit - 1) % maxConcurrentSubmitCount].get()); - - if (finish && presentImageIndex != 0xffffffff) - { - submit.addWait(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, mSwapChainImageAvailableSemaphore.get()); - submit.addSignal(mRenderFinishedSemaphore.get()); - } - - if (!lastsubmit) - submit.addSignal(mSubmitSemaphore[currentIndex].get()); - - submit.execute(device, device->graphicsQueue, mSubmitFence[currentIndex].get()); - mNextSubmit++; -} - -void VulkanFrameBuffer::FlushCommands(bool finish, bool lastsubmit) -{ - mRenderState->EndRenderPass(); - - if (mDrawCommands || mTransferCommands) - { - VulkanCommandBuffer *commands[2]; - size_t count = 0; - - if (mTransferCommands) - { - mTransferCommands->end(); - commands[count++] = mTransferCommands.get(); - FrameDeleteList.CommandBuffers.push_back(std::move(mTransferCommands)); - } - - if (mDrawCommands) - { - mDrawCommands->end(); - commands[count++] = mDrawCommands.get(); - FrameDeleteList.CommandBuffers.push_back(std::move(mDrawCommands)); - } - - FlushCommands(commands, count, finish, lastsubmit); - - current_rendered_commandbuffers += (int)count; - } -} - -void VulkanFrameBuffer::WaitForCommands(bool finish) -{ - if (finish) - { - Finish.Reset(); - Finish.Clock(); - - presentImageIndex = swapChain->AcquireImage(GetClientWidth(), GetClientHeight(), mSwapChainImageAvailableSemaphore.get()); - if (presentImageIndex != 0xffffffff) - mPostprocess->DrawPresentTexture(mOutputLetterbox, true, false); - } - - FlushCommands(finish, true); - - if (finish) - { - FPSLimit(); - - if (presentImageIndex != 0xffffffff) - swapChain->QueuePresent(presentImageIndex, mRenderFinishedSemaphore.get()); - } - - int numWaitFences = MIN(mNextSubmit, (int)maxConcurrentSubmitCount); - - if (numWaitFences > 0) - { - vkWaitForFences(device->device, numWaitFences, mSubmitWaitFences, VK_TRUE, std::numeric_limits::max()); - vkResetFences(device->device, numWaitFences, mSubmitWaitFences); - } - - DeleteFrameObjects(); - mNextSubmit = 0; - - if (finish) - { - Finish.Unclock(); - rendered_commandbuffers = current_rendered_commandbuffers; - current_rendered_commandbuffers = 0; - } -} - -void VulkanFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height) -{ - if (!V_IsHardwareRenderer()) - { - Super::WriteSavePic(player, file, width, height); - } - else - { - IntRect bounds; - bounds.left = 0; - bounds.top = 0; - bounds.width = width; - bounds.height = height; - - // we must be sure the GPU finished reading from the buffer before we fill it with new data. - WaitForCommands(false); - - // Switch to render buffers dimensioned for the savepic - mActiveRenderBuffers = mSaveBuffers.get(); - - mPostprocess->ImageTransitionScene(true); - - hw_ClearFakeFlat(); - GetRenderState()->SetVertexBuffer(screen->mVertexData); - screen->mVertexData->Reset(); - screen->mLights->Clear(); - screen->mViewpoints->Clear(); - - // This shouldn't overwrite the global viewpoint even for a short time. - FRenderViewpoint savevp; - sector_t *viewsector = RenderViewpoint(savevp, players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false); - GetRenderState()->EnableStencil(false); - GetRenderState()->SetNoSoftLightLevel(); - - int numpixels = width * height; - uint8_t * scr = (uint8_t *)M_Malloc(numpixels * 3); - CopyScreenToBuffer(width, height, scr); - - DoWriteSavePic(file, SS_RGB, scr, width, height, viewsector, false); - M_Free(scr); - - // Switch back the screen render buffers - screen->SetViewportRects(nullptr); - mActiveRenderBuffers = mScreenBuffers.get(); - } -} - -sector_t *VulkanFrameBuffer::RenderView(player_t *player) -{ - // To do: this is virtually identical to FGLRenderer::RenderView and should be merged. - - mRenderState->SetVertexBuffer(screen->mVertexData); - screen->mVertexData->Reset(); - - sector_t *retsec; - if (!V_IsHardwareRenderer()) - { - mPostprocess->SetActiveRenderTarget(); - - if (!swdrawer) swdrawer.reset(new SWSceneDrawer); - retsec = swdrawer->RenderView(player); - } - else - { - hw_ClearFakeFlat(); - - iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; - - checkBenchActive(); - - // reset statistics counters - ResetProfilingData(); - - // Get this before everything else - if (cl_capfps || r_NoInterpolate) r_viewpoint.TicFrac = 1.; - else r_viewpoint.TicFrac = I_GetTimeFrac(); - - screen->mLights->Clear(); - screen->mViewpoints->Clear(); - - // NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below. - bool saved_niv = NoInterpolateView; - NoInterpolateView = false; - - // Shader start time does not need to be handled per level. Just use the one from the camera to render from. - if (player->camera) - GetRenderState()->CheckTimer(player->camera->Level->ShaderStartTime); - // prepare all camera textures that have been used in the last frame. - // This must be done for all levels, not just the primary one! - for (auto Level : AllLevels()) - { - Level->canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov) - { - RenderTextureView(camtex, camera, fov); - }); - } - NoInterpolateView = saved_niv; - - // now render the main view - float fovratio; - float ratio = r_viewwindow.WidescreenRatio; - if (r_viewwindow.WidescreenRatio >= 1.3f) - { - fovratio = 1.333333f; - } - else - { - fovratio = ratio; - } - - mPostprocess->ImageTransitionScene(true); // This is the only line that differs compared to FGLRenderer::RenderView - - retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true); - } - All.Unclock(); - return retsec; -} - -sector_t *VulkanFrameBuffer::RenderViewpoint(FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen) -{ - // To do: this is virtually identical to FGLRenderer::RenderViewpoint and should be merged. - - R_SetupFrame(mainvp, r_viewwindow, camera); - - if (mainview && toscreen) - UpdateShadowMap(); - - // Update the attenuation flag of all light defaults for each viewpoint. - // This function will only do something if the setting differs. - FLightDefaults::SetAttenuationForLevel(!!(camera->Level->flags3 & LEVEL3_ATTENUATE)); - - // Render (potentially) multiple views for stereo 3d - // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. - auto vrmode = VRMode::GetVRMode(mainview && toscreen); - for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix) - { - const auto &eye = vrmode->mEyes[eye_ix]; - screen->SetViewportRects(bounds); - - if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao - { - mRenderState->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); - bool useSSAO = (gl_ssao != 0); - GetRenderState()->SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); - GetRenderState()->EnableDrawBuffers(GetRenderState()->GetPassDrawBufferCount()); - } - - auto di = HWDrawInfo::StartDrawInfo(mainvp.ViewLevel, nullptr, mainvp, nullptr); - auto &vp = di->Viewpoint; - - di->Set3DViewport(*GetRenderState()); - di->SetViewArea(); - auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr); - di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint) - - // Stereo mode specific perspective projection - di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio); - // Stereo mode specific viewpoint adjustment - vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees); - di->SetupView(*GetRenderState(), vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); - - // std::function until this can be done better in a cross-API fashion. - di->ProcessScene(toscreen, [&](HWDrawInfo *di, int mode) { - DrawScene(di, mode); - }); - - if (mainview) - { - PostProcess.Clock(); - if (toscreen) di->EndDrawScene(mainvp.sector, *GetRenderState()); // do not call this for camera textures. - - if (GetRenderState()->GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers - { - GetRenderState()->SetPassType(NORMAL_PASS); - GetRenderState()->EnableDrawBuffers(1); - } - - mPostprocess->BlitSceneToPostprocess(); // Copy the resulting scene to the current post process texture - - PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector, *GetRenderState()); }); - - PostProcess.Unclock(); - } - di->EndDrawInfo(); - -#if 0 - if (vrmode->mEyeCount > 1) - mBuffers->BlitToEyeTexture(eye_ix); -#endif - } - - return mainvp.sector; -} - -void VulkanFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) -{ - // This doesn't need to clear the fake flat cache. It can be shared between camera textures and the main view of a scene. - FMaterial *mat = FMaterial::ValidateTexture(tex, false); - auto BaseLayer = static_cast(mat->GetLayer(0, 0)); - - int width = mat->TextureWidth(); - int height = mat->TextureHeight(); - VkTextureImage *image = BaseLayer->GetImage(tex, 0, 0); - VkTextureImage *depthStencil = BaseLayer->GetDepthStencil(tex); - - mRenderState->EndRenderPass(); - - VkImageTransition barrier0; - barrier0.addImage(image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - barrier0.execute(GetDrawCommands()); - - mRenderState->SetRenderTarget(image, depthStencil->View.get(), image->Image->width, image->Image->height, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT); - - IntRect bounds; - bounds.left = bounds.top = 0; - bounds.width = MIN(mat->GetWidth(), image->Image->width); - bounds.height = MIN(mat->GetHeight(), image->Image->height); - - FRenderViewpoint texvp; - RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false); - - mRenderState->EndRenderPass(); - - VkImageTransition barrier1; - barrier1.addImage(image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); - barrier1.execute(GetDrawCommands()); - - mRenderState->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); - - tex->SetUpdated(true); -} - -void VulkanFrameBuffer::DrawScene(HWDrawInfo *di, int drawmode) -{ - // To do: this is virtually identical to FGLRenderer::DrawScene and should be merged. - - static int recursion = 0; - static int ssao_portals_available = 0; - const auto &vp = di->Viewpoint; - - bool applySSAO = false; - if (drawmode == DM_MAINVIEW) - { - ssao_portals_available = gl_ssao_portals; - applySSAO = true; - } - else if (drawmode == DM_OFFSCREEN) - { - ssao_portals_available = 0; - } - else if (drawmode == DM_PORTAL && ssao_portals_available > 0) - { - applySSAO = true; - ssao_portals_available--; - } - - if (vp.camera != nullptr) - { - ActorRenderFlags savedflags = vp.camera->renderflags; - di->CreateScene(drawmode == DM_MAINVIEW); - vp.camera->renderflags = savedflags; - } - else - { - di->CreateScene(false); - } - - GetRenderState()->SetDepthMask(true); - if (!gl_no_skyclear) screen->mPortalState->RenderFirstSkyPortal(recursion, di, *GetRenderState()); - - di->RenderScene(*GetRenderState()); - - if (applySSAO && GetRenderState()->GetPassType() == GBUFFER_PASS) - { - mPostprocess->AmbientOccludeScene(di->VPUniforms.mProjectionMatrix.get()[5]); - screen->mViewpoints->Bind(*GetRenderState(), di->vpIndex); - } - - // Handle all portals after rendering the opaque objects but before - // doing all translucent stuff - recursion++; - screen->mPortalState->EndFrame(di, *GetRenderState()); - recursion--; - di->RenderTranslucent(*GetRenderState()); -} - -void VulkanFrameBuffer::PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) -{ - mPostprocess->PostProcessScene(fixedcm, afterBloomDrawEndScene2D); -} - -uint32_t VulkanFrameBuffer::GetCaps() -{ - if (!V_IsHardwareRenderer()) - return Super::GetCaps(); - - // describe our basic feature set - ActorRenderFeatureFlags FlagSet = RFF_FLATSPRITES | RFF_MODELS | RFF_SLOPE3DFLOORS | - RFF_TILTPITCH | RFF_ROLLSPRITES | RFF_POLYGONAL | RFF_MATSHADER | RFF_POSTSHADER | RFF_BRIGHTMAP; - if (r_drawvoxels) - FlagSet |= RFF_VOXELS; - - if (gl_tonemap != 5) // not running palette tonemap shader - FlagSet |= RFF_TRUECOLOR; - - return (uint32_t)FlagSet; -} - -const char* VulkanFrameBuffer::DeviceName() const -{ - const auto &props = device->PhysicalDevice.Properties; - return props.deviceName; -} - - -void VulkanFrameBuffer::SetVSync(bool vsync) -{ - // This is handled in VulkanSwapChain::AcquireImage. - cur_vsync = vsync; -} - -void VulkanFrameBuffer::CleanForRestart() -{ - // force recreation of the SW scene drawer to ensure it gets a new set of resources. - swdrawer.reset(); -} - -void VulkanFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) -{ - auto tex = mat->tex; - if (tex->isSWCanvas()) return; - - // Textures that are already scaled in the texture lump will not get replaced by hires textures. - int flags = mat->isExpanded() ? CTF_Expand : 0; - auto base = static_cast(mat->GetLayer(0, translation)); - - base->Precache(mat, translation, flags); -} - -IHardwareTexture *VulkanFrameBuffer::CreateHardwareTexture() -{ - return new VkHardwareTexture(); -} - -FModelRenderer *VulkanFrameBuffer::CreateModelRenderer(int mli) -{ - return new FHWModelRenderer(nullptr, *GetRenderState(), mli); -} - -IVertexBuffer *VulkanFrameBuffer::CreateVertexBuffer() -{ - return new VKVertexBuffer(); -} - -IIndexBuffer *VulkanFrameBuffer::CreateIndexBuffer() -{ - return new VKIndexBuffer(); -} - -IDataBuffer *VulkanFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) -{ - auto buffer = new VKDataBuffer(bindingpoint, ssbo, needsresize); - - auto fb = GetVulkanFrameBuffer(); - switch (bindingpoint) - { - case LIGHTBUF_BINDINGPOINT: LightBufferSSO = buffer; break; - case VIEWPOINT_BINDINGPOINT: ViewpointUBO = buffer; break; - case LIGHTNODES_BINDINGPOINT: LightNodes = buffer; break; - case LIGHTLINES_BINDINGPOINT: LightLines = buffer; break; - case LIGHTLIST_BINDINGPOINT: LightList = buffer; break; - case POSTPROCESS_BINDINGPOINT: break; - default: break; - } - - return buffer; -} - -void VulkanFrameBuffer::SetTextureFilterMode() -{ - TextureFilterChanged(); -} - -void VulkanFrameBuffer::TextureFilterChanged() -{ - if (mSamplerManager) - { - // Destroy the texture descriptors as they used the old samplers - VkHardwareTexture::ResetAllDescriptors(); - - mSamplerManager->SetTextureFilterMode(); - } -} - -void VulkanFrameBuffer::StartPrecaching() -{ - // Destroy the texture descriptors to avoid problems with potentially stale textures. - VkHardwareTexture::ResetAllDescriptors(); -} - -void VulkanFrameBuffer::BlurScene(float amount) -{ - if (mPostprocess) - mPostprocess->BlurScene(amount); -} - -void VulkanFrameBuffer::UpdatePalette() -{ - if (mPostprocess) - mPostprocess->ClearTonemapPalette(); -} - -FTexture *VulkanFrameBuffer::WipeStartScreen() -{ - SetViewportRects(nullptr); - - auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1); - auto systex = static_cast(tex->GetSystemTexture()); - - systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeStartScreen"); - - return tex; -} - -FTexture *VulkanFrameBuffer::WipeEndScreen() -{ - GetPostprocess()->SetActiveRenderTarget(); - Draw2D(); - Clear2D(); - - auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1); - auto systex = static_cast(tex->GetSystemTexture()); - - systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeEndScreen"); - - return tex; -} - -void VulkanFrameBuffer::CopyScreenToBuffer(int w, int h, void *data) -{ - VkTextureImage image; - - // Convert from rgba16f to rgba8 using the GPU: - ImageBuilder imgbuilder; - imgbuilder.setFormat(VK_FORMAT_R8G8B8A8_UNORM); - imgbuilder.setUsage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - imgbuilder.setSize(w, h); - image.Image = imgbuilder.create(device); - GetPostprocess()->BlitCurrentToImage(&image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - - // Staging buffer for download - BufferBuilder bufbuilder; - bufbuilder.setSize(w * h * 4); - bufbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU); - auto staging = bufbuilder.create(device); - - // Copy from image to buffer - VkBufferImageCopy region = {}; - region.imageExtent.width = w; - region.imageExtent.height = h; - region.imageExtent.depth = 1; - region.imageSubresource.layerCount = 1; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - GetDrawCommands()->copyImageToBuffer(image.Image->image, image.Layout, staging->buffer, 1, ®ion); - - // Submit command buffers and wait for device to finish the work - WaitForCommands(false); - - // Map and convert from rgba8 to rgb8 - uint8_t *dest = (uint8_t*)data; - uint8_t *pixels = (uint8_t*)staging->Map(0, w * h * 4); - int dindex = 0; - for (int y = 0; y < h; y++) - { - int sindex = (h - y - 1) * w * 4; - for (int x = 0; x < w; x++) - { - dest[dindex] = pixels[sindex]; - dest[dindex + 1] = pixels[sindex + 1]; - dest[dindex + 2] = pixels[sindex + 2]; - dindex += 3; - sindex += 4; - } - } - staging->Unmap(); -} - -TArray VulkanFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) -{ - int w = SCREENWIDTH; - int h = SCREENHEIGHT; - - IntRect box; - box.left = 0; - box.top = 0; - box.width = w; - box.height = h; - mPostprocess->DrawPresentTexture(box, true, true); - - TArray ScreenshotBuffer(w * h * 3, true); - CopyScreenToBuffer(w, h, ScreenshotBuffer.Data()); - - pitch = w * 3; - color_type = SS_RGB; - gamma = 1.0f; - return ScreenshotBuffer; -} - -void VulkanFrameBuffer::BeginFrame() -{ - SetViewportRects(nullptr); - mScreenBuffers->BeginFrame(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height); - mSaveBuffers->BeginFrame(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT); - mRenderState->BeginFrame(); - mRenderPassManager->UpdateDynamicSet(); - - if (mNextTimestampQuery > 0) - { - GetDrawCommands()->resetQueryPool(mTimestampQueryPool.get(), 0, mNextTimestampQuery); - mNextTimestampQuery = 0; - } -} - -void VulkanFrameBuffer::PushGroup(const FString &name) -{ - if (!gpuStatActive) - return; - - if (mNextTimestampQuery < VulkanFrameBuffer::MaxTimestampQueries && device->graphicsTimeQueries) - { - TimestampQuery q; - q.name = name; - q.startIndex = mNextTimestampQuery++; - q.endIndex = 0; - GetDrawCommands()->writeTimestamp(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, mTimestampQueryPool.get(), q.startIndex); - mGroupStack.push_back(timeElapsedQueries.size()); - timeElapsedQueries.push_back(q); - } -} - -void VulkanFrameBuffer::PopGroup() -{ - if (!gpuStatActive || mGroupStack.empty()) - return; - - TimestampQuery &q = timeElapsedQueries[mGroupStack.back()]; - mGroupStack.pop_back(); - - if (mNextTimestampQuery < VulkanFrameBuffer::MaxTimestampQueries && device->graphicsTimeQueries) - { - q.endIndex = mNextTimestampQuery++; - GetDrawCommands()->writeTimestamp(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, mTimestampQueryPool.get(), q.endIndex); - } -} - -void VulkanFrameBuffer::UpdateGpuStats() -{ - uint64_t timestamps[MaxTimestampQueries]; - if (mNextTimestampQuery > 0) - mTimestampQueryPool->getResults(0, mNextTimestampQuery, sizeof(uint64_t) * mNextTimestampQuery, timestamps, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); - - double timestampPeriod = device->PhysicalDevice.Properties.limits.timestampPeriod; - - gpuStatOutput = ""; - for (auto &q : timeElapsedQueries) - { - if (q.endIndex <= q.startIndex) - continue; - - int64_t timeElapsed = std::max(static_cast(timestamps[q.endIndex] - timestamps[q.startIndex]), (int64_t)0); - double timeNS = timeElapsed * timestampPeriod; - - FString out; - out.Format("%s=%04.2f ms\n", q.name.GetChars(), timeNS / 1000000.0f); - gpuStatOutput += out; - } - timeElapsedQueries.clear(); - mGroupStack.clear(); - - gpuStatActive = keepGpuStatActive; - keepGpuStatActive = false; -} - -void VulkanFrameBuffer::Draw2D() -{ - ::Draw2D(&m2DDrawer, *mRenderState); -} - -VulkanCommandBuffer *VulkanFrameBuffer::GetTransferCommands() -{ - if (!mTransferCommands) - { - mTransferCommands = mCommandPool->createBuffer(); - mTransferCommands->SetDebugName("VulkanFrameBuffer.mTransferCommands"); - mTransferCommands->begin(); - } - return mTransferCommands.get(); -} - -VulkanCommandBuffer *VulkanFrameBuffer::GetDrawCommands() -{ - if (!mDrawCommands) - { - mDrawCommands = mCommandPool->createBuffer(); - mDrawCommands->SetDebugName("VulkanFrameBuffer.mDrawCommands"); - mDrawCommands->begin(); - } - return mDrawCommands.get(); -} - -unsigned int VulkanFrameBuffer::GetLightBufferBlockSize() const -{ - return mLights->GetBlockSize(); -} - -void VulkanFrameBuffer::PrintStartupLog() -{ - const auto &props = device->PhysicalDevice.Properties; - - FString deviceType; - switch (props.deviceType) - { - case VK_PHYSICAL_DEVICE_TYPE_OTHER: deviceType = "other"; break; - case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: deviceType = "integrated gpu"; break; - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: deviceType = "discrete gpu"; break; - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: deviceType = "virtual gpu"; break; - case VK_PHYSICAL_DEVICE_TYPE_CPU: deviceType = "cpu"; break; - default: deviceType.Format("%d", (int)props.deviceType); break; - } - - FString apiVersion, driverVersion; - apiVersion.Format("%d.%d.%d", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion)); - driverVersion.Format("%d.%d.%d", VK_VERSION_MAJOR(props.driverVersion), VK_VERSION_MINOR(props.driverVersion), VK_VERSION_PATCH(props.driverVersion)); - - Printf("Vulkan device: " TEXTCOLOR_ORANGE "%s\n", props.deviceName); - Printf("Vulkan device type: %s\n", deviceType.GetChars()); - Printf("Vulkan version: %s (api) %s (driver)\n", apiVersion.GetChars(), driverVersion.GetChars()); - - Printf(PRINT_LOG, "Vulkan extensions:"); - for (const VkExtensionProperties &p : device->PhysicalDevice.Extensions) - { - Printf(PRINT_LOG, " %s", p.extensionName); - } - Printf(PRINT_LOG, "\n"); - - const auto &limits = props.limits; - Printf("Max. texture size: %d\n", limits.maxImageDimension2D); - Printf("Max. uniform buffer range: %d\n", limits.maxUniformBufferRange); - Printf("Min. uniform buffer offset alignment: %llu\n", limits.minUniformBufferOffsetAlignment); -} - -void VulkanFrameBuffer::CreateFanToTrisIndexBuffer() -{ - TArray data; - for (int i = 2; i < 1000; i++) - { - data.Push(0); - data.Push(i - 1); - data.Push(i); - } - - FanToTrisIndexBuffer.reset(CreateIndexBuffer()); - FanToTrisIndexBuffer->SetData(sizeof(uint32_t) * data.Size(), data.Data()); -} - -void VulkanFrameBuffer::UpdateShadowMap() -{ - mPostprocess->UpdateShadowMap(); -} diff --git a/src/rendering/vulkan/system/vk_framebuffer.h b/src/rendering/vulkan/system/vk_framebuffer.h deleted file mode 100644 index 64dfa3e7bd0..00000000000 --- a/src/rendering/vulkan/system/vk_framebuffer.h +++ /dev/null @@ -1,160 +0,0 @@ -#pragma once - -#include "gl_sysfb.h" -#include "vk_device.h" -#include "vk_objects.h" - -struct FRenderViewpoint; -class VkSamplerManager; -class VkShaderManager; -class VkRenderPassManager; -class VkRenderState; -class VkStreamBuffer; -class VKDataBuffer; -class VkHardwareTexture; -class VkRenderBuffers; -class VkPostprocess; -class SWSceneDrawer; - -class VulkanFrameBuffer : public SystemBaseFrameBuffer -{ - typedef SystemBaseFrameBuffer Super; - - -public: - VulkanDevice *device; - std::unique_ptr swapChain; - uint32_t presentImageIndex = 0xffffffff; - bool cur_vsync; - - VulkanCommandBuffer *GetTransferCommands(); - VulkanCommandBuffer *GetDrawCommands(); - VkShaderManager *GetShaderManager() { return mShaderManager.get(); } - VkSamplerManager *GetSamplerManager() { return mSamplerManager.get(); } - VkRenderPassManager *GetRenderPassManager() { return mRenderPassManager.get(); } - VkRenderState *GetRenderState() { return mRenderState.get(); } - VkPostprocess *GetPostprocess() { return mPostprocess.get(); } - VkRenderBuffers *GetBuffers() { return mActiveRenderBuffers; } - - void FlushCommands(bool finish, bool lastsubmit = false); - - unsigned int GetLightBufferBlockSize() const; - - VKDataBuffer *ViewpointUBO = nullptr; - VKDataBuffer *LightBufferSSO = nullptr; - VkStreamBuffer *MatrixBuffer = nullptr; - VkStreamBuffer *StreamBuffer = nullptr; - - VKDataBuffer *LightNodes = nullptr; - VKDataBuffer *LightLines = nullptr; - VKDataBuffer *LightList = nullptr; - - std::unique_ptr FanToTrisIndexBuffer; - - class DeleteList - { - public: - std::vector> Images; - std::vector> ImageViews; - std::vector> Framebuffers; - std::vector> Buffers; - std::vector> Descriptors; - std::vector> DescriptorPools; - std::vector> CommandBuffers; - } FrameDeleteList; - - std::unique_ptr swdrawer; - - VulkanFrameBuffer(void *hMonitor, bool fullscreen, VulkanDevice *dev); - ~VulkanFrameBuffer(); - bool IsVulkan() override { return true; } - - void Update(); - - void InitializeState() override; - - void CleanForRestart() override; - void PrecacheMaterial(FMaterial *mat, int translation) override; - void UpdatePalette() override; - uint32_t GetCaps() override; - const char* DeviceName() const override; - int Backend() override { return 1; } - void WriteSavePic(player_t *player, FileWriter *file, int width, int height) override; - sector_t *RenderView(player_t *player) override; - void SetTextureFilterMode() override; - void TextureFilterChanged() override; - void StartPrecaching() override; - void BeginFrame() override; - void BlurScene(float amount) override; - void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) override; - - IHardwareTexture *CreateHardwareTexture() override; - FModelRenderer *CreateModelRenderer(int mli) override; - IVertexBuffer *CreateVertexBuffer() override; - IIndexBuffer *CreateIndexBuffer() override; - IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override; - - FTexture *WipeStartScreen() override; - FTexture *WipeEndScreen() override; - - TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override; - - void SetVSync(bool vsync) override; - - void Draw2D() override; - - void WaitForCommands(bool finish); - - void PushGroup(const FString &name); - void PopGroup(); - void UpdateGpuStats(); - -private: - sector_t *RenderViewpoint(FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen); - void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV); - void DrawScene(HWDrawInfo *di, int drawmode); - void PrintStartupLog(); - void CreateFanToTrisIndexBuffer(); - void CopyScreenToBuffer(int w, int h, void *data); - void UpdateShadowMap(); - void DeleteFrameObjects(); - void FlushCommands(VulkanCommandBuffer **commands, size_t count, bool finish, bool lastsubmit); - - std::unique_ptr mShaderManager; - std::unique_ptr mSamplerManager; - std::unique_ptr mScreenBuffers; - std::unique_ptr mSaveBuffers; - std::unique_ptr mPostprocess; - std::unique_ptr mRenderPassManager; - std::unique_ptr mCommandPool; - std::unique_ptr mTransferCommands; - std::unique_ptr mRenderState; - - std::unique_ptr mDrawCommands; - - enum { maxConcurrentSubmitCount = 8}; - std::unique_ptr mSubmitSemaphore[maxConcurrentSubmitCount]; - std::unique_ptr mSubmitFence[maxConcurrentSubmitCount]; - VkFence mSubmitWaitFences[maxConcurrentSubmitCount]; - int mNextSubmit = 0; - - std::unique_ptr mSwapChainImageAvailableSemaphore; - std::unique_ptr mRenderFinishedSemaphore; - - VkRenderBuffers *mActiveRenderBuffers = nullptr; - - struct TimestampQuery - { - FString name; - uint32_t startIndex; - uint32_t endIndex; - }; - - enum { MaxTimestampQueries = 100 }; - std::unique_ptr mTimestampQueryPool; - int mNextTimestampQuery = 0; - std::vector mGroupStack; - std::vector timeElapsedQueries; -}; - -inline VulkanFrameBuffer *GetVulkanFrameBuffer() { return static_cast(screen); } diff --git a/src/rendering/vulkan/system/vk_objects.h b/src/rendering/vulkan/system/vk_objects.h deleted file mode 100644 index 4c6a7ace4fb..00000000000 --- a/src/rendering/vulkan/system/vk_objects.h +++ /dev/null @@ -1,1066 +0,0 @@ -#pragma once - -#include "vk_device.h" -#include "doomerrors.h" - -class VulkanCommandPool; -class VulkanDescriptorPool; - -class VulkanSemaphore -{ -public: - VulkanSemaphore(VulkanDevice *device); - ~VulkanSemaphore(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)semaphore, VK_OBJECT_TYPE_SEMAPHORE); } - - VulkanDevice *device = nullptr; - VkSemaphore semaphore = VK_NULL_HANDLE; - -private: - VulkanSemaphore(const VulkanSemaphore &) = delete; - VulkanSemaphore &operator=(const VulkanSemaphore &) = delete; -}; - -class VulkanFence -{ -public: - VulkanFence(VulkanDevice *device); - ~VulkanFence(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)fence, VK_OBJECT_TYPE_FENCE); } - - VulkanDevice *device = nullptr; - VkFence fence = VK_NULL_HANDLE; - -private: - VulkanFence(const VulkanFence &) = delete; - VulkanFence &operator=(const VulkanFence &) = delete; -}; - -class VulkanBuffer -{ -public: - VulkanBuffer(VulkanDevice *device, VkBuffer buffer, VmaAllocation allocation, size_t size); - ~VulkanBuffer(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER); } - - VulkanDevice *device = nullptr; - - VkBuffer buffer; - VmaAllocation allocation; - size_t size = 0; - - void *Map(size_t offset, size_t size); - void Unmap(); - -private: - VulkanBuffer(const VulkanBuffer &) = delete; - VulkanBuffer &operator=(const VulkanBuffer &) = delete; -}; - -class VulkanFramebuffer -{ -public: - VulkanFramebuffer(VulkanDevice *device, VkFramebuffer framebuffer); - ~VulkanFramebuffer(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)framebuffer, VK_OBJECT_TYPE_FRAMEBUFFER); } - - VulkanDevice *device; - VkFramebuffer framebuffer; - -private: - VulkanFramebuffer(const VulkanFramebuffer &) = delete; - VulkanFramebuffer &operator=(const VulkanFramebuffer &) = delete; -}; - -class VulkanImage -{ -public: - VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels); - ~VulkanImage(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)image, VK_OBJECT_TYPE_IMAGE); } - - VkImage image = VK_NULL_HANDLE; - int width = 0; - int height = 0; - int mipLevels = 1; - - void *Map(size_t offset, size_t size); - void Unmap(); - -private: - VulkanDevice *device = nullptr; - VmaAllocation allocation; - - VulkanImage(const VulkanImage &) = delete; - VulkanImage &operator=(const VulkanImage &) = delete; -}; - -class VulkanImageView -{ -public: - VulkanImageView(VulkanDevice *device, VkImageView view); - ~VulkanImageView(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)view, VK_OBJECT_TYPE_IMAGE_VIEW); } - - VkImageView view = VK_NULL_HANDLE; - -private: - VulkanImageView(const VulkanImageView &) = delete; - VulkanImageView &operator=(const VulkanImageView &) = delete; - - VulkanDevice *device = nullptr; -}; - -class VulkanSampler -{ -public: - VulkanSampler(VulkanDevice *device, VkSampler sampler); - ~VulkanSampler(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)sampler, VK_OBJECT_TYPE_SAMPLER); } - - VkSampler sampler = VK_NULL_HANDLE; - -private: - VulkanSampler(const VulkanSampler &) = delete; - VulkanSampler &operator=(const VulkanSampler &) = delete; - - VulkanDevice *device = nullptr; -}; - -class VulkanShader -{ -public: - VulkanShader(VulkanDevice *device, VkShaderModule module); - ~VulkanShader(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)module, VK_OBJECT_TYPE_SHADER_MODULE); } - - VkShaderModule module = VK_NULL_HANDLE; - -private: - VulkanDevice *device = nullptr; - - VulkanShader(const VulkanShader &) = delete; - VulkanShader &operator=(const VulkanShader &) = delete; -}; - -class VulkanDescriptorSetLayout -{ -public: - VulkanDescriptorSetLayout(VulkanDevice *device, VkDescriptorSetLayout layout); - ~VulkanDescriptorSetLayout(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)layout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT); } - - VulkanDevice *device; - VkDescriptorSetLayout layout; - -private: - VulkanDescriptorSetLayout(const VulkanDescriptorSetLayout &) = delete; - VulkanDescriptorSetLayout &operator=(const VulkanDescriptorSetLayout &) = delete; -}; - -class VulkanDescriptorSet -{ -public: - VulkanDescriptorSet(VulkanDevice *device, VulkanDescriptorPool *pool, VkDescriptorSet set); - ~VulkanDescriptorSet(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)set, VK_OBJECT_TYPE_DESCRIPTOR_SET); } - - VulkanDevice *device; - VulkanDescriptorPool *pool; - VkDescriptorSet set; - -private: - VulkanDescriptorSet(const VulkanDescriptorSet &) = delete; - VulkanDescriptorSet &operator=(const VulkanDescriptorSet &) = delete; -}; - -class VulkanDescriptorPool -{ -public: - VulkanDescriptorPool(VulkanDevice *device, VkDescriptorPool pool); - ~VulkanDescriptorPool(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_DESCRIPTOR_POOL); } - - std::unique_ptr tryAllocate(VulkanDescriptorSetLayout *layout); - std::unique_ptr allocate(VulkanDescriptorSetLayout *layout); - - VulkanDevice *device; - VkDescriptorPool pool; - -private: - VulkanDescriptorPool(const VulkanDescriptorPool &) = delete; - VulkanDescriptorPool &operator=(const VulkanDescriptorPool &) = delete; -}; - -class VulkanQueryPool -{ -public: - VulkanQueryPool(VulkanDevice *device, VkQueryPool pool); - ~VulkanQueryPool(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_QUERY_POOL); } - - bool getResults(uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *data, VkDeviceSize stride, VkQueryResultFlags flags); - - VulkanDevice *device = nullptr; - VkQueryPool pool = VK_NULL_HANDLE; - -private: - VulkanQueryPool(const VulkanQueryPool &) = delete; - VulkanQueryPool &operator=(const VulkanQueryPool &) = delete; -}; - -class VulkanPipeline -{ -public: - VulkanPipeline(VulkanDevice *device, VkPipeline pipeline); - ~VulkanPipeline(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)pipeline, VK_OBJECT_TYPE_PIPELINE); } - - VulkanDevice *device; - VkPipeline pipeline; - -private: - VulkanPipeline(const VulkanPipeline &) = delete; - VulkanPipeline &operator=(const VulkanPipeline &) = delete; -}; - -class VulkanPipelineLayout -{ -public: - VulkanPipelineLayout(VulkanDevice *device, VkPipelineLayout layout); - ~VulkanPipelineLayout(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT); } - - VulkanDevice *device; - VkPipelineLayout layout; - -private: - VulkanPipelineLayout(const VulkanPipelineLayout &) = delete; - VulkanPipelineLayout &operator=(const VulkanPipelineLayout &) = delete; -}; - -class VulkanRenderPass -{ -public: - VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass); - ~VulkanRenderPass(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)renderPass, VK_OBJECT_TYPE_RENDER_PASS); } - - VulkanDevice *device; - VkRenderPass renderPass; - -private: - VulkanRenderPass(const VulkanRenderPass &) = delete; - VulkanRenderPass &operator=(const VulkanRenderPass &) = delete; -}; - -class RenderPassBegin -{ -public: - RenderPassBegin(); - - void setRenderPass(VulkanRenderPass *renderpass); - void setRenderArea(int x, int y, int width, int height); - void setFramebuffer(VulkanFramebuffer *framebuffer); - void addClearColor(float r, float g, float b, float a); - void addClearDepth(float value); - void addClearStencil(int value); - void addClearDepthStencil(float depthValue, int stencilValue); - - VkRenderPassBeginInfo renderPassInfo = {}; - -private: - std::vector clearValues; -}; - -class VulkanCommandBuffer -{ -public: - VulkanCommandBuffer(VulkanCommandPool *pool); - ~VulkanCommandBuffer(); - - void SetDebugName(const char *name); - - void begin(); - void end(); - - void bindPipeline(VkPipelineBindPoint pipelineBindPoint, VulkanPipeline *pipeline); - void bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); - void setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); - void setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); - void setLineWidth(float lineWidth); - void setDepthBias(float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); - void setBlendConstants(const float blendConstants[4]); - void setDepthBounds(float minDepthBounds, float maxDepthBounds); - void setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t compareMask); - void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t writeMask); - void setStencilReference(VkStencilFaceFlags faceMask, uint32_t reference); - void bindDescriptorSet(VkPipelineBindPoint pipelineBindPoint, VulkanPipelineLayout *layout, uint32_t setIndex, VulkanDescriptorSet *descriptorSet, uint32_t dynamicOffsetCount = 0, const uint32_t* pDynamicOffsets = nullptr); - void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); - void bindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); - void bindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); - void draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); - void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); - void drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); - void drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); - void dispatch(uint32_t x, uint32_t y, uint32_t z); - void dispatchIndirect(VkBuffer buffer, VkDeviceSize offset); - void copyBuffer(VulkanBuffer *srcBuffer, VulkanBuffer *dstBuffer, VkDeviceSize srcOffset = 0, VkDeviceSize dstOffset = 0, VkDeviceSize size = VK_WHOLE_SIZE); - void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); - void copyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); - void blitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); - void copyBufferToImage(VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); - void copyImageToBuffer(VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); - void updateBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); - void fillBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); - void clearColorImage(VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); - void clearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); - void clearAttachments(uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); - void resolveImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); - void setEvent(VkEvent event, VkPipelineStageFlags stageMask); - void resetEvent(VkEvent event, VkPipelineStageFlags stageMask); - void waitEvents(uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); - void pipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); - void beginQuery(VulkanQueryPool *queryPool, uint32_t query, VkQueryControlFlags flags); - void beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); - void endQuery(VulkanQueryPool *queryPool, uint32_t query); - void endQuery(VkQueryPool queryPool, uint32_t query); - void resetQueryPool(VulkanQueryPool *queryPool, uint32_t firstQuery, uint32_t queryCount); - void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); - void writeTimestamp(VkPipelineStageFlagBits pipelineStage, VulkanQueryPool *queryPool, uint32_t query); - void writeTimestamp(VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); - void copyQueryPoolResults(VulkanQueryPool *queryPool, uint32_t firstQuery, uint32_t queryCount, VulkanBuffer *dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); - void copyQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); - void pushConstants(VulkanPipelineLayout *layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); - void pushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); - void beginRenderPass(const RenderPassBegin &renderPassBegin, VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE); - void beginRenderPass(const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); - void nextSubpass(VkSubpassContents contents); - void endRenderPass(); - void executeCommands(uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); - - void debugFullPipelineBarrier(); - - VkCommandBuffer buffer = nullptr; - -private: - VulkanCommandPool *pool = nullptr; - - VulkanCommandBuffer(const VulkanCommandBuffer &) = delete; - VulkanCommandBuffer &operator=(const VulkanCommandBuffer &) = delete; -}; - -class VulkanCommandPool -{ -public: - VulkanCommandPool(VulkanDevice *device, int queueFamilyIndex); - ~VulkanCommandPool(); - - void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_COMMAND_POOL); } - - std::unique_ptr createBuffer(); - - VkCommandPool pool = VK_NULL_HANDLE; - -private: - VulkanDevice *device = nullptr; - - VulkanCommandPool(const VulkanCommandPool &) = delete; - VulkanCommandPool &operator=(const VulkanCommandPool &) = delete; - - friend class VulkanCommandBuffer; -}; - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanSemaphore::VulkanSemaphore(VulkanDevice *device) : device(device) -{ - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - VkResult result = vkCreateSemaphore(device->device, &semaphoreInfo, nullptr, &semaphore); - CheckVulkanError(result, "Could not create semaphore"); -} - -inline VulkanSemaphore::~VulkanSemaphore() -{ - vkDestroySemaphore(device->device, semaphore, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanFence::VulkanFence(VulkanDevice *device) : device(device) -{ - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - VkResult result = vkCreateFence(device->device, &fenceInfo, nullptr, &fence); - CheckVulkanError(result, "Could not create fence!"); -} - -inline VulkanFence::~VulkanFence() -{ - vkDestroyFence(device->device, fence, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanBuffer::VulkanBuffer(VulkanDevice *device, VkBuffer buffer, VmaAllocation allocation, size_t size) : device(device), buffer(buffer), allocation(allocation), size(size) -{ -} - -inline VulkanBuffer::~VulkanBuffer() -{ - vmaDestroyBuffer(device->allocator, buffer, allocation); -} - -inline void *VulkanBuffer::Map(size_t offset, size_t size) -{ - void *data; - VkResult result = vmaMapMemory(device->allocator, allocation, &data); - return (result == VK_SUCCESS) ? ((uint8_t*)data) + offset : nullptr; -} - -inline void VulkanBuffer::Unmap() -{ - vmaUnmapMemory(device->allocator, allocation); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanCommandPool::VulkanCommandPool(VulkanDevice *device, int queueFamilyIndex) : device(device) -{ - VkCommandPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.queueFamilyIndex = queueFamilyIndex; - poolInfo.flags = 0; - - VkResult result = vkCreateCommandPool(device->device, &poolInfo, nullptr, &pool); - CheckVulkanError(result, "Could not create command pool"); -} - -inline VulkanCommandPool::~VulkanCommandPool() -{ - vkDestroyCommandPool(device->device, pool, nullptr); -} - -inline std::unique_ptr VulkanCommandPool::createBuffer() -{ - return std::make_unique(this); -} - -///////////////////////////////////////////////////////////////////////////// - -inline RenderPassBegin::RenderPassBegin() -{ - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; -} - -inline void RenderPassBegin::setRenderPass(VulkanRenderPass *renderPass) -{ - renderPassInfo.renderPass = renderPass->renderPass; -} - -inline void RenderPassBegin::setRenderArea(int x, int y, int width, int height) -{ - renderPassInfo.renderArea.offset.x = x; - renderPassInfo.renderArea.offset.y = y; - renderPassInfo.renderArea.extent.width = width; - renderPassInfo.renderArea.extent.height = height; -} - -inline void RenderPassBegin::setFramebuffer(VulkanFramebuffer *framebuffer) -{ - renderPassInfo.framebuffer = framebuffer->framebuffer; -} - -inline void RenderPassBegin::addClearColor(float r, float g, float b, float a) -{ - VkClearValue clearValue = { }; - clearValue.color = { {r, g, b, a} }; - clearValues.push_back(clearValue); - - renderPassInfo.clearValueCount = (uint32_t)clearValues.size(); - renderPassInfo.pClearValues = clearValues.data(); -} - -inline void RenderPassBegin::addClearDepth(float value) -{ - VkClearValue clearValue = { }; - clearValue.depthStencil.depth = value; - clearValues.push_back(clearValue); - - renderPassInfo.clearValueCount = (uint32_t)clearValues.size(); - renderPassInfo.pClearValues = clearValues.data(); -} - -inline void RenderPassBegin::addClearStencil(int value) -{ - VkClearValue clearValue = { }; - clearValue.depthStencil.stencil = value; - clearValues.push_back(clearValue); - - renderPassInfo.clearValueCount = (uint32_t)clearValues.size(); - renderPassInfo.pClearValues = clearValues.data(); -} - -inline void RenderPassBegin::addClearDepthStencil(float depthValue, int stencilValue) -{ - VkClearValue clearValue = { }; - clearValue.depthStencil.depth = depthValue; - clearValue.depthStencil.stencil = stencilValue; - clearValues.push_back(clearValue); - - renderPassInfo.clearValueCount = (uint32_t)clearValues.size(); - renderPassInfo.pClearValues = clearValues.data(); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanCommandBuffer::VulkanCommandBuffer(VulkanCommandPool *pool) : pool(pool) -{ - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = pool->pool; - allocInfo.commandBufferCount = 1; - - VkResult result = vkAllocateCommandBuffers(pool->device->device, &allocInfo, &buffer); - CheckVulkanError(result, "Could not create command buffer"); -} - -inline VulkanCommandBuffer::~VulkanCommandBuffer() -{ - vkFreeCommandBuffers(pool->device->device, pool->pool, 1, &buffer); -} - -inline void VulkanCommandBuffer::begin() -{ - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - beginInfo.pInheritanceInfo = nullptr; - - VkResult result = vkBeginCommandBuffer(buffer, &beginInfo); - CheckVulkanError(result, "Could not begin recording command buffer"); -} - -inline void VulkanCommandBuffer::end() -{ - VkResult result = vkEndCommandBuffer(buffer); - CheckVulkanError(result, "Could not end command buffer recording"); -} - -inline void VulkanCommandBuffer::debugFullPipelineBarrier() -{ - VkMemoryBarrier barrier = { }; - barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; - barrier.srcAccessMask = - VK_ACCESS_INDIRECT_COMMAND_READ_BIT | - VK_ACCESS_INDEX_READ_BIT | - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - VK_ACCESS_UNIFORM_READ_BIT | - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | - VK_ACCESS_SHADER_READ_BIT | - VK_ACCESS_SHADER_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_TRANSFER_READ_BIT | - VK_ACCESS_TRANSFER_WRITE_BIT | - VK_ACCESS_HOST_READ_BIT | - VK_ACCESS_HOST_WRITE_BIT; - barrier.dstAccessMask = - VK_ACCESS_INDIRECT_COMMAND_READ_BIT | - VK_ACCESS_INDEX_READ_BIT | - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - VK_ACCESS_UNIFORM_READ_BIT | - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | - VK_ACCESS_SHADER_READ_BIT | - VK_ACCESS_SHADER_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_TRANSFER_READ_BIT | - VK_ACCESS_TRANSFER_WRITE_BIT | - VK_ACCESS_HOST_READ_BIT | - VK_ACCESS_HOST_WRITE_BIT; - - vkCmdPipelineBarrier(buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); -} - -inline void VulkanCommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint, VulkanPipeline *pipeline) -{ - bindPipeline(pipelineBindPoint, pipeline->pipeline); -} - -inline void VulkanCommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) -{ - vkCmdBindPipeline(buffer, pipelineBindPoint, pipeline); -} - -inline void VulkanCommandBuffer::setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports) -{ - vkCmdSetViewport(buffer, firstViewport, viewportCount, pViewports); -} - -inline void VulkanCommandBuffer::setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors) -{ - vkCmdSetScissor(buffer, firstScissor, scissorCount, pScissors); -} - -inline void VulkanCommandBuffer::setLineWidth(float lineWidth) -{ - vkCmdSetLineWidth(buffer, lineWidth); -} - -inline void VulkanCommandBuffer::setDepthBias(float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) -{ - vkCmdSetDepthBias(buffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor); -} - -inline void VulkanCommandBuffer::setBlendConstants(const float blendConstants[4]) -{ - vkCmdSetBlendConstants(buffer, blendConstants); -} - -inline void VulkanCommandBuffer::setDepthBounds(float minDepthBounds, float maxDepthBounds) -{ - vkCmdSetDepthBounds(buffer, minDepthBounds, maxDepthBounds); -} - -inline void VulkanCommandBuffer::setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t compareMask) -{ - vkCmdSetStencilCompareMask(buffer, faceMask, compareMask); -} - -inline void VulkanCommandBuffer::setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t writeMask) -{ - vkCmdSetStencilWriteMask(buffer, faceMask, writeMask); -} - -inline void VulkanCommandBuffer::setStencilReference(VkStencilFaceFlags faceMask, uint32_t reference) -{ - vkCmdSetStencilReference(buffer, faceMask, reference); -} - -inline void VulkanCommandBuffer::bindDescriptorSet(VkPipelineBindPoint pipelineBindPoint, VulkanPipelineLayout *layout, uint32_t setIndex, VulkanDescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets) -{ - bindDescriptorSets(pipelineBindPoint, layout->layout, setIndex, 1, &descriptorSet->set, dynamicOffsetCount, pDynamicOffsets); -} - -inline void VulkanCommandBuffer::bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets) -{ - vkCmdBindDescriptorSets(buffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); -} - -inline void VulkanCommandBuffer::bindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) -{ - vkCmdBindIndexBuffer(this->buffer, buffer, offset, indexType); -} - -inline void VulkanCommandBuffer::bindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) -{ - vkCmdBindVertexBuffers(buffer, firstBinding, bindingCount, pBuffers, pOffsets); -} - -inline void VulkanCommandBuffer::draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) -{ - vkCmdDraw(buffer, vertexCount, instanceCount, firstVertex, firstInstance); -} - -inline void VulkanCommandBuffer::drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) -{ - vkCmdDrawIndexed(buffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); -} - -inline void VulkanCommandBuffer::drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) -{ - vkCmdDrawIndirect(this->buffer, buffer, offset, drawCount, stride); -} - -inline void VulkanCommandBuffer::drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) -{ - vkCmdDrawIndexedIndirect(this->buffer, buffer, offset, drawCount, stride); -} - -inline void VulkanCommandBuffer::dispatch(uint32_t x, uint32_t y, uint32_t z) -{ - vkCmdDispatch(buffer, x, y, z); -} - -inline void VulkanCommandBuffer::dispatchIndirect(VkBuffer buffer, VkDeviceSize offset) -{ - vkCmdDispatchIndirect(this->buffer, buffer, offset); -} - -inline void VulkanCommandBuffer::copyBuffer(VulkanBuffer *srcBuffer, VulkanBuffer *dstBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size) -{ - VkBufferCopy region = { }; - region.srcOffset = srcOffset; - region.dstOffset = dstOffset; - region.size = (size == VK_WHOLE_SIZE) ? dstBuffer->size : size; - copyBuffer(srcBuffer->buffer, dstBuffer->buffer, 1, ®ion); -} - -inline void VulkanCommandBuffer::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions) -{ - vkCmdCopyBuffer(buffer, srcBuffer, dstBuffer, regionCount, pRegions); -} - -inline void VulkanCommandBuffer::copyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions) -{ - vkCmdCopyImage(buffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); -} - -inline void VulkanCommandBuffer::blitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter) -{ - vkCmdBlitImage(buffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter); -} - -inline void VulkanCommandBuffer::copyBufferToImage(VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions) -{ - vkCmdCopyBufferToImage(buffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions); -} - -inline void VulkanCommandBuffer::copyImageToBuffer(VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions) -{ - vkCmdCopyImageToBuffer(buffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions); -} - -inline void VulkanCommandBuffer::updateBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData) -{ - vkCmdUpdateBuffer(buffer, dstBuffer, dstOffset, dataSize, pData); -} - -inline void VulkanCommandBuffer::fillBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) -{ - vkCmdFillBuffer(buffer, dstBuffer, dstOffset, size, data); -} - -inline void VulkanCommandBuffer::clearColorImage(VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) -{ - vkCmdClearColorImage(buffer, image, imageLayout, pColor, rangeCount, pRanges); -} - -inline void VulkanCommandBuffer::clearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) -{ - vkCmdClearDepthStencilImage(buffer, image, imageLayout, pDepthStencil, rangeCount, pRanges); -} - -inline void VulkanCommandBuffer::clearAttachments(uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects) -{ - vkCmdClearAttachments(buffer, attachmentCount, pAttachments, rectCount, pRects); -} - -inline void VulkanCommandBuffer::resolveImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions) -{ - vkCmdResolveImage(buffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); -} - -inline void VulkanCommandBuffer::setEvent(VkEvent event, VkPipelineStageFlags stageMask) -{ - vkCmdSetEvent(buffer, event, stageMask); -} - -inline void VulkanCommandBuffer::resetEvent(VkEvent event, VkPipelineStageFlags stageMask) -{ - vkCmdResetEvent(buffer, event, stageMask); -} - -inline void VulkanCommandBuffer::waitEvents(uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) -{ - vkCmdWaitEvents(buffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); -} - -inline void VulkanCommandBuffer::pipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) -{ - vkCmdPipelineBarrier(buffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); -} - -inline void VulkanCommandBuffer::beginQuery(VulkanQueryPool *queryPool, uint32_t query, VkQueryControlFlags flags) -{ - beginQuery(queryPool->pool, query, flags); -} - -inline void VulkanCommandBuffer::beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags) -{ - vkCmdBeginQuery(buffer, queryPool, query, flags); -} - -inline void VulkanCommandBuffer::endQuery(VulkanQueryPool *queryPool, uint32_t query) -{ - endQuery(queryPool->pool, query); -} - -inline void VulkanCommandBuffer::endQuery(VkQueryPool queryPool, uint32_t query) -{ - vkCmdEndQuery(buffer, queryPool, query); -} - -inline void VulkanCommandBuffer::resetQueryPool(VulkanQueryPool *queryPool, uint32_t firstQuery, uint32_t queryCount) -{ - resetQueryPool(queryPool->pool, firstQuery, queryCount); -} - -inline void VulkanCommandBuffer::resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) -{ - vkCmdResetQueryPool(buffer, queryPool, firstQuery, queryCount); -} - -inline void VulkanCommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipelineStage, VulkanQueryPool *queryPool, uint32_t query) -{ - writeTimestamp(pipelineStage, queryPool->pool, query); -} - -inline void VulkanCommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query) -{ - vkCmdWriteTimestamp(buffer, pipelineStage, queryPool, query); -} - -inline void VulkanCommandBuffer::copyQueryPoolResults(VulkanQueryPool *queryPool, uint32_t firstQuery, uint32_t queryCount, VulkanBuffer *dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) -{ - copyQueryPoolResults(queryPool->pool, firstQuery, queryCount, dstBuffer->buffer, dstOffset, stride, flags); -} - -inline void VulkanCommandBuffer::copyQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) -{ - vkCmdCopyQueryPoolResults(buffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride, flags); -} - -inline void VulkanCommandBuffer::pushConstants(VulkanPipelineLayout *layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues) -{ - pushConstants(layout->layout, stageFlags, offset, size, pValues); -} - -inline void VulkanCommandBuffer::pushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues) -{ - vkCmdPushConstants(buffer, layout, stageFlags, offset, size, pValues); -} - -inline void VulkanCommandBuffer::beginRenderPass(const RenderPassBegin &renderPassBegin, VkSubpassContents contents) -{ - beginRenderPass(&renderPassBegin.renderPassInfo, contents); -} - -inline void VulkanCommandBuffer::beginRenderPass(const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) -{ - vkCmdBeginRenderPass(buffer, pRenderPassBegin, contents); -} - -inline void VulkanCommandBuffer::nextSubpass(VkSubpassContents contents) -{ - vkCmdNextSubpass(buffer, contents); -} - -inline void VulkanCommandBuffer::endRenderPass() -{ - vkCmdEndRenderPass(buffer); -} - -inline void VulkanCommandBuffer::executeCommands(uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) -{ - vkCmdExecuteCommands(buffer, commandBufferCount, pCommandBuffers); -} - -inline void VulkanCommandBuffer::SetDebugName(const char *name) -{ - pool->device->SetDebugObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_COMMAND_BUFFER); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanShader::VulkanShader(VulkanDevice *device, VkShaderModule module) : module(module), device(device) -{ -} - -inline VulkanShader::~VulkanShader() -{ - vkDestroyShaderModule(device->device, module, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(VulkanDevice *device, VkDescriptorSetLayout layout) : device(device), layout(layout) -{ -} - -inline VulkanDescriptorSetLayout::~VulkanDescriptorSetLayout() -{ - vkDestroyDescriptorSetLayout(device->device, layout, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanDescriptorSet::VulkanDescriptorSet(VulkanDevice *device, VulkanDescriptorPool *pool, VkDescriptorSet set) : device(device), pool(pool), set(set) -{ -} - -inline VulkanDescriptorSet::~VulkanDescriptorSet() -{ - vkFreeDescriptorSets(device->device, pool->pool, 1, &set); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanDescriptorPool::VulkanDescriptorPool(VulkanDevice *device, VkDescriptorPool pool) : device(device), pool(pool) -{ -} - -inline VulkanDescriptorPool::~VulkanDescriptorPool() -{ - vkDestroyDescriptorPool(device->device, pool, nullptr); -} - -inline std::unique_ptr VulkanDescriptorPool::tryAllocate(VulkanDescriptorSetLayout *layout) -{ - VkDescriptorSetAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = pool; - allocInfo.descriptorSetCount = 1; - allocInfo.pSetLayouts = &layout->layout; - - VkDescriptorSet descriptorSet; - VkResult result = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet); - if (result != VK_SUCCESS) - return nullptr; - - return std::make_unique(device, this, descriptorSet); -} - -inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout *layout) -{ - VkDescriptorSetAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = pool; - allocInfo.descriptorSetCount = 1; - allocInfo.pSetLayouts = &layout->layout; - - VkDescriptorSet descriptorSet; - VkResult result = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet); - CheckVulkanError(result, "Could not allocate descriptor sets"); - - return std::make_unique(device, this, descriptorSet); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanQueryPool::VulkanQueryPool(VulkanDevice *device, VkQueryPool pool) : device(device), pool(pool) -{ -} - -inline VulkanQueryPool::~VulkanQueryPool() -{ - vkDestroyQueryPool(device->device, pool, nullptr); -} - -inline bool VulkanQueryPool::getResults(uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *data, VkDeviceSize stride, VkQueryResultFlags flags) -{ - VkResult result = vkGetQueryPoolResults(device->device, pool, firstQuery, queryCount, dataSize, data, stride, flags); - CheckVulkanError(result, "vkGetQueryPoolResults failed"); - return result == VK_SUCCESS; -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanFramebuffer::VulkanFramebuffer(VulkanDevice *device, VkFramebuffer framebuffer) : device(device), framebuffer(framebuffer) -{ -} - -inline VulkanFramebuffer::~VulkanFramebuffer() -{ - vkDestroyFramebuffer(device->device, framebuffer, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanImage::VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels) : image(image), width(width), height(height), mipLevels(mipLevels), device(device), allocation(allocation) -{ -} - -inline VulkanImage::~VulkanImage() -{ - vmaDestroyImage(device->allocator, image, allocation); -} - -inline void *VulkanImage::Map(size_t offset, size_t size) -{ - void *data; - VkResult result = vmaMapMemory(device->allocator, allocation, &data); - return (result == VK_SUCCESS) ? ((uint8_t*)data) + offset : nullptr; -} - -inline void VulkanImage::Unmap() -{ - vmaUnmapMemory(device->allocator, allocation); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanImageView::VulkanImageView(VulkanDevice *device, VkImageView view) : view(view), device(device) -{ -} - -inline VulkanImageView::~VulkanImageView() -{ - vkDestroyImageView(device->device, view, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanSampler::VulkanSampler(VulkanDevice *device, VkSampler sampler) : sampler(sampler), device(device) -{ -} - -inline VulkanSampler::~VulkanSampler() -{ - vkDestroySampler(device->device, sampler, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanPipeline::VulkanPipeline(VulkanDevice *device, VkPipeline pipeline) : device(device), pipeline(pipeline) -{ -} - -inline VulkanPipeline::~VulkanPipeline() -{ - vkDestroyPipeline(device->device, pipeline, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanPipelineLayout::VulkanPipelineLayout(VulkanDevice *device, VkPipelineLayout layout) : device(device), layout(layout) -{ -} - -inline VulkanPipelineLayout::~VulkanPipelineLayout() -{ - vkDestroyPipelineLayout(device->device, layout, nullptr); -} - -///////////////////////////////////////////////////////////////////////////// - -inline VulkanRenderPass::VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass) : device(device), renderPass(renderPass) -{ -} - -inline VulkanRenderPass::~VulkanRenderPass() -{ - vkDestroyRenderPass(device->device, renderPass, nullptr); -} diff --git a/src/rendering/vulkan/system/vk_swapchain.cpp b/src/rendering/vulkan/system/vk_swapchain.cpp deleted file mode 100644 index dcacd16206a..00000000000 --- a/src/rendering/vulkan/system/vk_swapchain.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_swapchain.h" -#include "vk_objects.h" -#include "c_cvars.h" -#include "version.h" -#include "v_video.h" -#include "vk_framebuffer.h" - - -CVAR(Bool, vk_hdr, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); - -void I_GetVulkanDrawableSize(int *width, int *height); - -VulkanSwapChain::VulkanSwapChain(VulkanDevice *device) : device(device) -{ -} - -VulkanSwapChain::~VulkanSwapChain() -{ - ReleaseResources(); -} - -uint32_t VulkanSwapChain::AcquireImage(int width, int height, VulkanSemaphore *semaphore, VulkanFence *fence) -{ - auto vsync = static_cast(screen)->cur_vsync; - if (lastSwapWidth != width || lastSwapHeight != height || lastVsync != vsync || lastHdr != vk_hdr || !swapChain) - { - Recreate(); - lastSwapWidth = width; - lastSwapHeight = height; - lastVsync = vsync; - lastHdr = vk_hdr; - } - - uint32_t imageIndex; - while (true) - { - if (!swapChain) - { - imageIndex = 0xffffffff; - break; - } - - VkResult result = vkAcquireNextImageKHR(device->device, swapChain, 1'000'000'000, semaphore ? semaphore->semaphore : VK_NULL_HANDLE, fence ? fence->fence : VK_NULL_HANDLE, &imageIndex); - if (result == VK_SUCCESS) - { - break; - } - else if (result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_SURFACE_LOST_KHR) - { - // Force the recreate to happen next frame. - // The spec is not very clear about what happens to the semaphore or the acquired image if the swapchain is recreated before the image is released with a call to vkQueuePresentKHR. - lastSwapWidth = 0; - lastSwapHeight = 0; - break; - } - else if (result == VK_ERROR_OUT_OF_DATE_KHR) - { - Recreate(); - } - else if (result == VK_NOT_READY || result == VK_TIMEOUT) - { - imageIndex = 0xffffffff; - break; - } - else if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY) - { - VulkanError("vkAcquireNextImageKHR failed: out of memory"); - } - else if (result == VK_ERROR_DEVICE_LOST) - { - VulkanError("vkAcquireNextImageKHR failed: device lost"); - } - else - { - VulkanError("vkAcquireNextImageKHR failed"); - } - } - return imageIndex; -} - -void VulkanSwapChain::QueuePresent(uint32_t imageIndex, VulkanSemaphore *semaphore) -{ - VkPresentInfoKHR presentInfo = {}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.waitSemaphoreCount = semaphore ? 1 : 0; - presentInfo.pWaitSemaphores = semaphore ? &semaphore->semaphore : VK_NULL_HANDLE; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &swapChain; - presentInfo.pImageIndices = &imageIndex; - presentInfo.pResults = nullptr; - VkResult result = vkQueuePresentKHR(device->presentQueue, &presentInfo); - if (result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_ERROR_SURFACE_LOST_KHR) - { - lastSwapWidth = 0; - lastSwapHeight = 0; - } - else if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY) - { - // The spec says we can recover from this. - // However, if we are out of memory it is better to crash now than in some other weird place further away from the source of the problem. - - VulkanError("vkQueuePresentKHR failed: out of memory"); - } - else if (result == VK_ERROR_DEVICE_LOST) - { - VulkanError("vkQueuePresentKHR failed: device lost"); - } - else if (result != VK_SUCCESS) - { - VulkanError("vkQueuePresentKHR failed"); - } -} - -void VulkanSwapChain::Recreate() -{ - ReleaseViews(); - swapChainImages.clear(); - - VkSwapchainKHR oldSwapChain = swapChain; - CreateSwapChain(oldSwapChain); - if (oldSwapChain) - vkDestroySwapchainKHR(device->device, oldSwapChain, nullptr); - - if (swapChain) - { - GetImages(); - CreateViews(); - } -} - -bool VulkanSwapChain::CreateSwapChain(VkSwapchainKHR oldSwapChain) -{ - SelectFormat(); - SelectPresentMode(); - - int width, height; - I_GetVulkanDrawableSize(&width, &height); - - VkSurfaceCapabilitiesKHR surfaceCapabilities = GetSurfaceCapabilities(); - - actualExtent = { static_cast(width), static_cast(height) }; - actualExtent.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, actualExtent.width)); - actualExtent.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, actualExtent.height)); - if (actualExtent.width == 0 || actualExtent.height == 0) - { - swapChain = VK_NULL_HANDLE; - return false; - } - - uint32_t imageCount = surfaceCapabilities.minImageCount + 1; - if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) - imageCount = surfaceCapabilities.maxImageCount; - - // When vsync is on we only want two images. This creates a slight performance penalty in exchange for reduced input latency (less mouse lag). - // When vsync is off we want three images as it allows us to generate new images even during the vertical blanking period where one entry is being used by the presentation engine. - if (swapChainPresentMode == VK_PRESENT_MODE_MAILBOX_KHR || swapChainPresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) - imageCount = std::min(imageCount, (uint32_t)3); - else - imageCount = std::min(imageCount, (uint32_t)2); - - VkSwapchainCreateInfoKHR swapChainCreateInfo = {}; - swapChainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapChainCreateInfo.surface = device->surface; - swapChainCreateInfo.minImageCount = imageCount; - swapChainCreateInfo.imageFormat = swapChainFormat.format; - swapChainCreateInfo.imageColorSpace = swapChainFormat.colorSpace; - swapChainCreateInfo.imageExtent = actualExtent; - swapChainCreateInfo.imageArrayLayers = 1; - swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - - uint32_t queueFamilyIndices[] = { (uint32_t)device->graphicsFamily, (uint32_t)device->presentFamily }; - if (device->graphicsFamily != device->presentFamily) - { - swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - swapChainCreateInfo.queueFamilyIndexCount = 2; - swapChainCreateInfo.pQueueFamilyIndices = queueFamilyIndices; - } - else - { - swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapChainCreateInfo.queueFamilyIndexCount = 0; - swapChainCreateInfo.pQueueFamilyIndices = nullptr; - } - - swapChainCreateInfo.preTransform = surfaceCapabilities.currentTransform; - swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // If alpha channel is passed on to the DWM or not - swapChainCreateInfo.presentMode = swapChainPresentMode; - swapChainCreateInfo.clipped = VK_TRUE; - swapChainCreateInfo.oldSwapchain = oldSwapChain; - - VkResult result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapChain); - if (result != VK_SUCCESS) - { - swapChain = VK_NULL_HANDLE; - return false; - } - - return true; -} - -void VulkanSwapChain::CreateViews() -{ - framebuffers.resize(swapChainImages.size()); - swapChainImageViews.reserve(swapChainImages.size()); - for (size_t i = 0; i < swapChainImages.size(); i++) - { - device->SetDebugObjectName("SwapChainImage", (uint64_t)swapChainImages[i], VK_OBJECT_TYPE_IMAGE); - - VkImageViewCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.image = swapChainImages[i]; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = swapChainFormat.format; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - - VkImageView view; - VkResult result = vkCreateImageView(device->device, &createInfo, nullptr, &view); - CheckVulkanError(result, "Could not create image view for swapchain image"); - - device->SetDebugObjectName("SwapChainImageView", (uint64_t)view, VK_OBJECT_TYPE_IMAGE_VIEW); - - swapChainImageViews.push_back(view); - } -} - -bool VulkanSwapChain::IsHdrModeActive() const -{ - return swapChainFormat.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT || swapChainFormat.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT; -} - -void VulkanSwapChain::SelectFormat() -{ - std::vector surfaceFormats = GetSurfaceFormats(); - if (surfaceFormats.empty()) - VulkanError("No surface formats supported"); - - if (surfaceFormats.size() == 1 && surfaceFormats.front().format == VK_FORMAT_UNDEFINED) - { - swapChainFormat.format = VK_FORMAT_B8G8R8A8_UNORM; - swapChainFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - return; - } - - if (vk_hdr) - { - for (const auto& format : surfaceFormats) - { - if (format.format == VK_FORMAT_R16G16B16A16_SFLOAT && format.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) - { - swapChainFormat = format; - return; - } - } - - // For older drivers that reported the wrong colorspace - for (const auto &format : surfaceFormats) - { - if (format.format == VK_FORMAT_R16G16B16A16_SFLOAT && format.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) - { - swapChainFormat = format; - return; - } - } - } - - for (const auto &format : surfaceFormats) - { - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) - { - swapChainFormat = format; - return; - } - } - - swapChainFormat = surfaceFormats.front(); -} - -void VulkanSwapChain::SelectPresentMode() -{ - std::vector presentModes = GetPresentModes(); - - if (presentModes.empty()) - VulkanError("No surface present modes supported"); - - swapChainPresentMode = VK_PRESENT_MODE_FIFO_KHR; - auto vsync = static_cast(screen)->cur_vsync; - if (vsync) - { - bool supportsFifoRelaxed = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != presentModes.end(); - if (supportsFifoRelaxed) - swapChainPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; - } - else - { - bool supportsMailbox = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != presentModes.end(); - bool supportsImmediate = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != presentModes.end(); - if (supportsMailbox) - swapChainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; - else if (supportsImmediate) - swapChainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; - } -} - -void VulkanSwapChain::GetImages() -{ - uint32_t imageCount; - VkResult result = vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, nullptr); - CheckVulkanError(result, "vkGetSwapchainImagesKHR failed"); - - swapChainImages.resize(imageCount); - result = vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, swapChainImages.data()); - CheckVulkanError(result, "vkGetSwapchainImagesKHR failed (2)"); -} - -void VulkanSwapChain::ReleaseViews() -{ - framebuffers.clear(); - for (auto &view : swapChainImageViews) - { - vkDestroyImageView(device->device, view, nullptr); - } - swapChainImageViews.clear(); -} - -void VulkanSwapChain::ReleaseResources() -{ - ReleaseViews(); - if (swapChain) - vkDestroySwapchainKHR(device->device, swapChain, nullptr); -} - -VkSurfaceCapabilitiesKHR VulkanSwapChain::GetSurfaceCapabilities() -{ - VkSurfaceCapabilitiesKHR surfaceCapabilities; - VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->PhysicalDevice.Device, device->surface, &surfaceCapabilities); - CheckVulkanError(result, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed"); - return surfaceCapabilities; -} - -std::vector VulkanSwapChain::GetSurfaceFormats() -{ - uint32_t surfaceFormatCount = 0; - VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->surface, &surfaceFormatCount, nullptr); - CheckVulkanError(result, "vkGetPhysicalDeviceSurfaceFormatsKHR failed"); - if (surfaceFormatCount == 0) - return {}; - - std::vector surfaceFormats(surfaceFormatCount); - result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->surface, &surfaceFormatCount, surfaceFormats.data()); - CheckVulkanError(result, "vkGetPhysicalDeviceSurfaceFormatsKHR failed"); - return surfaceFormats; -} - -std::vector VulkanSwapChain::GetPresentModes() -{ - uint32_t presentModeCount = 0; - VkResult result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->surface, &presentModeCount, nullptr); - CheckVulkanError(result, "vkGetPhysicalDeviceSurfacePresentModesKHR failed"); - if (presentModeCount == 0) - return {}; - - std::vector presentModes(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->surface, &presentModeCount, presentModes.data()); - CheckVulkanError(result, "vkGetPhysicalDeviceSurfacePresentModesKHR failed"); - return presentModes; -} diff --git a/src/rendering/vulkan/system/vk_swapchain.h b/src/rendering/vulkan/system/vk_swapchain.h deleted file mode 100644 index 51de648673b..00000000000 --- a/src/rendering/vulkan/system/vk_swapchain.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "vk_device.h" - -class VulkanSemaphore; -class VulkanFence; -class VulkanFramebuffer; - -class VulkanSwapChain -{ -public: - VulkanSwapChain(VulkanDevice *device); - ~VulkanSwapChain(); - - uint32_t AcquireImage(int width, int height, VulkanSemaphore *semaphore = nullptr, VulkanFence *fence = nullptr); - void QueuePresent(uint32_t imageIndex, VulkanSemaphore *semaphore = nullptr); - - void Recreate(); - - bool IsHdrModeActive() const; - - VkSwapchainKHR swapChain = VK_NULL_HANDLE; - VkSurfaceFormatKHR swapChainFormat; - VkPresentModeKHR swapChainPresentMode; - - std::vector swapChainImages; - std::vector swapChainImageViews; - std::vector> framebuffers; - - VkExtent2D actualExtent; - -private: - void SelectFormat(); - void SelectPresentMode(); - bool CreateSwapChain(VkSwapchainKHR oldSwapChain = VK_NULL_HANDLE); - void CreateViews(); - void GetImages(); - void ReleaseResources(); - void ReleaseViews(); - - VkSurfaceCapabilitiesKHR GetSurfaceCapabilities(); - std::vector GetSurfaceFormats(); - std::vector GetPresentModes(); - - VulkanDevice *device = nullptr; - - int lastSwapWidth = 0; - int lastSwapHeight = 0; - bool lastVsync = false; - bool lastHdr = false; - - VulkanSwapChain(const VulkanSwapChain &) = delete; - VulkanSwapChain &operator=(const VulkanSwapChain &) = delete; -}; diff --git a/src/rendering/vulkan/textures/vk_hwtexture.cpp b/src/rendering/vulkan/textures/vk_hwtexture.cpp deleted file mode 100644 index 90180776b23..00000000000 --- a/src/rendering/vulkan/textures/vk_hwtexture.cpp +++ /dev/null @@ -1,404 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "templates.h" -#include "c_cvars.h" -#include "r_data/colormaps.h" -#include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/utility/hw_cvars.h" -#include "hwrenderer/scene/hw_renderstate.h" -#include "vulkan/system/vk_objects.h" -#include "vulkan/system/vk_builders.h" -#include "vulkan/system/vk_framebuffer.h" -#include "vulkan/textures/vk_samplers.h" -#include "vulkan/renderer/vk_renderpass.h" -#include "vulkan/renderer/vk_postprocess.h" -#include "vulkan/renderer/vk_renderbuffers.h" -#include "vk_hwtexture.h" - -VkHardwareTexture *VkHardwareTexture::First = nullptr; - -VkHardwareTexture::VkHardwareTexture() -{ - Next = First; - First = this; - if (Next) Next->Prev = this; -} - -VkHardwareTexture::~VkHardwareTexture() -{ - if (Next) Next->Prev = Prev; - if (Prev) Prev->Next = Next; - else First = Next; - - Reset(); -} - -void VkHardwareTexture::ResetAll() -{ - for (VkHardwareTexture *cur = VkHardwareTexture::First; cur; cur = cur->Next) - cur->Reset(); -} - -void VkHardwareTexture::Reset() -{ - if (auto fb = GetVulkanFrameBuffer()) - { - ResetDescriptors(); - - if (mappedSWFB) - { - mImage.Image->Unmap(); - mappedSWFB = nullptr; - } - - auto &deleteList = fb->FrameDeleteList; - if (mImage.Image) deleteList.Images.push_back(std::move(mImage.Image)); - if (mImage.View) deleteList.ImageViews.push_back(std::move(mImage.View)); - for (auto &it : mImage.RSFramebuffers) deleteList.Framebuffers.push_back(std::move(it.second)); - if (mDepthStencil.Image) deleteList.Images.push_back(std::move(mDepthStencil.Image)); - if (mDepthStencil.View) deleteList.ImageViews.push_back(std::move(mDepthStencil.View)); - for (auto &it : mDepthStencil.RSFramebuffers) deleteList.Framebuffers.push_back(std::move(it.second)); - mImage.reset(); - mDepthStencil.reset(); - } -} - -void VkHardwareTexture::ResetDescriptors() -{ - if (auto fb = GetVulkanFrameBuffer()) - { - auto &deleteList = fb->FrameDeleteList; - - for (auto &it : mDescriptorSets) - { - deleteList.Descriptors.push_back(std::move(it.descriptor)); - } - } - - mDescriptorSets.clear(); -} - -void VkHardwareTexture::ResetAllDescriptors() -{ - for (VkHardwareTexture *cur = First; cur; cur = cur->Next) - cur->ResetDescriptors(); - - auto fb = GetVulkanFrameBuffer(); - if (fb) - fb->GetRenderPassManager()->TextureSetPoolReset(); -} - -void VkHardwareTexture::Precache(FMaterial *mat, int translation, int flags) -{ - int numLayers = mat->GetLayers(); - GetImage(mat->tex, translation, flags); - for (int i = 1; i < numLayers; i++) - { - FTexture *layer; - auto systex = static_cast(mat->GetLayer(i, 0, &layer)); - systex->GetImage(layer, 0, mat->isExpanded() ? CTF_Expand : 0); - } -} - -VulkanDescriptorSet *VkHardwareTexture::GetDescriptorSet(const FMaterialState &state) -{ - FMaterial *mat = state.mMaterial; - FTexture *tex = state.mMaterial->tex; - int clampmode = state.mClampMode; - int translation = state.mTranslation; - - if (tex->UseType == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; - if (tex->isHardwareCanvas()) clampmode = CLAMP_CAMTEX; - else if ((tex->isWarped() || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; - - // Textures that are already scaled in the texture lump will not get replaced by hires textures. - int flags = state.mMaterial->isExpanded() ? CTF_Expand : 0; - - if (tex->isHardwareCanvas()) static_cast(tex)->NeedUpdate(); - - for (auto &set : mDescriptorSets) - { - if (set.descriptor && set.clampmode == clampmode && set.flags == flags) return set.descriptor.get(); - } - - int numLayers = mat->GetLayers(); - - auto fb = GetVulkanFrameBuffer(); - auto descriptor = fb->GetRenderPassManager()->AllocateTextureDescriptorSet(numLayers); - - descriptor->SetDebugName("VkHardwareTexture.mDescriptorSets"); - - VulkanSampler *sampler = fb->GetSamplerManager()->Get(clampmode); - - WriteDescriptors update; - update.addCombinedImageSampler(descriptor.get(), 0, GetImage(tex, translation, flags)->View.get(), sampler, mImage.Layout); - for (int i = 1; i < numLayers; i++) - { - FTexture *layer; - auto systex = static_cast(mat->GetLayer(i, 0, &layer)); - update.addCombinedImageSampler(descriptor.get(), i, systex->GetImage(layer, 0, mat->isExpanded() ? CTF_Expand : 0)->View.get(), sampler, systex->mImage.Layout); - } - update.updateSets(fb->device); - mDescriptorSets.emplace_back(clampmode, flags, std::move(descriptor)); - return mDescriptorSets.back().descriptor.get(); -} - -VkTextureImage *VkHardwareTexture::GetImage(FTexture *tex, int translation, int flags) -{ - if (!mImage.Image) - { - CreateImage(tex, translation, flags); - } - return &mImage; -} - -VkTextureImage *VkHardwareTexture::GetDepthStencil(FTexture *tex) -{ - if (!mDepthStencil.View) - { - auto fb = GetVulkanFrameBuffer(); - - VkFormat format = fb->GetBuffers()->SceneDepthStencilFormat; - int w = tex->GetWidth(); - int h = tex->GetHeight(); - - ImageBuilder builder; - builder.setSize(w, h); - builder.setSamples(VK_SAMPLE_COUNT_1_BIT); - builder.setFormat(format); - builder.setUsage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - mDepthStencil.Image = builder.create(fb->device); - mDepthStencil.Image->SetDebugName("VkHardwareTexture.DepthStencil"); - mDepthStencil.AspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(mDepthStencil.Image.get(), format, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); - mDepthStencil.View = viewbuilder.create(fb->device); - mDepthStencil.View->SetDebugName("VkHardwareTexture.DepthStencilView"); - - VkImageTransition barrier; - barrier.addImage(&mDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true); - barrier.execute(fb->GetTransferCommands()); - } - return &mDepthStencil; -} - -void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) -{ - if (!tex->isHardwareCanvas()) - { - auto remap = TranslationToTable(translation); - translation = remap == nullptr ? 0 : remap->GetUniqueIndex(); - - FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); - CreateTexture(texbuffer.mWidth, texbuffer.mHeight, 4, VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer); - } - else - { - auto fb = GetVulkanFrameBuffer(); - - VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; - int w = tex->GetWidth(); - int h = tex->GetHeight(); - - ImageBuilder imgbuilder; - imgbuilder.setFormat(format); - imgbuilder.setSize(w, h); - imgbuilder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - mImage.Image = imgbuilder.create(fb->device); - mImage.Image->SetDebugName("VkHardwareTexture.mImage"); - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(mImage.Image.get(), format); - mImage.View = viewbuilder.create(fb->device); - mImage.View->SetDebugName("VkHardwareTexture.mImageView"); - - auto cmdbuffer = fb->GetTransferCommands(); - - VkImageTransition imageTransition; - imageTransition.addImage(&mImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true); - imageTransition.execute(cmdbuffer); - } -} - -void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels) -{ - auto fb = GetVulkanFrameBuffer(); - - int totalSize = w * h * pixelsize; - - BufferBuilder bufbuilder; - bufbuilder.setSize(totalSize); - bufbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - std::unique_ptr stagingBuffer = bufbuilder.create(fb->device); - stagingBuffer->SetDebugName("VkHardwareTexture.mStagingBuffer"); - - uint8_t *data = (uint8_t*)stagingBuffer->Map(0, totalSize); - memcpy(data, pixels, totalSize); - stagingBuffer->Unmap(); - - ImageBuilder imgbuilder; - imgbuilder.setFormat(format); - imgbuilder.setSize(w, h, GetMipLevels(w, h)); - imgbuilder.setUsage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - mImage.Image = imgbuilder.create(fb->device); - mImage.Image->SetDebugName("VkHardwareTexture.mImage"); - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(mImage.Image.get(), format); - mImage.View = viewbuilder.create(fb->device); - mImage.View->SetDebugName("VkHardwareTexture.mImageView"); - - auto cmdbuffer = fb->GetTransferCommands(); - - VkImageTransition imageTransition; - imageTransition.addImage(&mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true); - imageTransition.execute(cmdbuffer); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = 1; - region.imageExtent.depth = 1; - region.imageExtent.width = w; - region.imageExtent.height = h; - cmdbuffer->copyBufferToImage(stagingBuffer->buffer, mImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - fb->FrameDeleteList.Buffers.push_back(std::move(stagingBuffer)); - - mImage.GenerateMipmaps(cmdbuffer); -} - -int VkHardwareTexture::GetMipLevels(int w, int h) -{ - int levels = 1; - while (w > 1 || h > 1) - { - w = std::max(w >> 1, 1); - h = std::max(h >> 1, 1); - levels++; - } - return levels; -} - -void VkHardwareTexture::AllocateBuffer(int w, int h, int texelsize) -{ - if (mImage.Image && (mImage.Image->width != w || mImage.Image->height != h || mTexelsize != texelsize)) - { - Reset(); - } - - if (!mImage.Image) - { - auto fb = GetVulkanFrameBuffer(); - - VkFormat format = texelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM; - - ImageBuilder imgbuilder; - VkDeviceSize allocatedBytes = 0; - imgbuilder.setFormat(format); - imgbuilder.setSize(w, h); - imgbuilder.setLinearTiling(); - imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); - imgbuilder.setMemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - mImage.Image = imgbuilder.create(fb->device, &allocatedBytes); - mImage.Image->SetDebugName("VkHardwareTexture.mImage"); - mTexelsize = texelsize; - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(mImage.Image.get(), format); - mImage.View = viewbuilder.create(fb->device); - mImage.View->SetDebugName("VkHardwareTexture.mImageView"); - - auto cmdbuffer = fb->GetTransferCommands(); - - VkImageTransition imageTransition; - imageTransition.addImage(&mImage, VK_IMAGE_LAYOUT_GENERAL, true); - imageTransition.execute(cmdbuffer); - - bufferpitch = int(allocatedBytes / h / texelsize); - } -} - -uint8_t *VkHardwareTexture::MapBuffer() -{ - if (!mappedSWFB) - mappedSWFB = (uint8_t*)mImage.Image->Map(0, mImage.Image->width * mImage.Image->height * mTexelsize); - return mappedSWFB; -} - -unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) -{ - return 0; -} - -void VkHardwareTexture::CreateWipeTexture(int w, int h, const char *name) -{ - auto fb = GetVulkanFrameBuffer(); - - VkFormat format = VK_FORMAT_B8G8R8A8_UNORM; - - ImageBuilder imgbuilder; - imgbuilder.setFormat(format); - imgbuilder.setSize(w, h); - imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY); - mImage.Image = imgbuilder.create(fb->device); - mImage.Image->SetDebugName(name); - mTexelsize = 4; - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(mImage.Image.get(), format); - mImage.View = viewbuilder.create(fb->device); - mImage.View->SetDebugName(name); - - if (fb->GetBuffers()->GetWidth() > 0 && fb->GetBuffers()->GetHeight() > 0) - { - fb->GetPostprocess()->BlitCurrentToImage(&mImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - } - else - { - // hwrenderer asked image data from a frame buffer that was never written into. Let's give it that.. - // (ideally the hwrenderer wouldn't do this, but the calling code is too complex for me to fix) - - VkImageTransition transition0; - transition0.addImage(&mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true); - transition0.execute(fb->GetTransferCommands()); - - VkImageSubresourceRange range = {}; - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - range.layerCount = 1; - range.levelCount = 1; - - VkClearColorValue value = {}; - value.float32[0] = 0.0f; - value.float32[1] = 0.0f; - value.float32[2] = 0.0f; - value.float32[3] = 1.0f; - fb->GetTransferCommands()->clearColorImage(mImage.Image->image, mImage.Layout, &value, 1, &range); - - VkImageTransition transition1; - transition1.addImage(&mImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); - transition1.execute(fb->GetTransferCommands()); - } -} diff --git a/src/rendering/vulkan/textures/vk_hwtexture.h b/src/rendering/vulkan/textures/vk_hwtexture.h deleted file mode 100644 index 9770cb1c013..00000000000 --- a/src/rendering/vulkan/textures/vk_hwtexture.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#ifdef LoadImage -#undef LoadImage -#endif - -#define SHADED_TEXTURE -1 -#define DIRECT_PALETTE -2 - -#include "tarray.h" -#include "hwrenderer/textures/hw_ihwtexture.h" -#include "volk/volk.h" -#include "vk_imagetransition.h" - -struct FMaterialState; -class VulkanDescriptorSet; -class VulkanImage; -class VulkanImageView; -class VulkanBuffer; - -class VkHardwareTexture : public IHardwareTexture -{ -public: - VkHardwareTexture(); - ~VkHardwareTexture(); - - static void ResetAll(); - void Reset(); - - void Precache(FMaterial *mat, int translation, int flags); - - VulkanDescriptorSet *GetDescriptorSet(const FMaterialState &state); - - // Software renderer stuff - void AllocateBuffer(int w, int h, int texelsize) override; - uint8_t *MapBuffer() override; - unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) override; - - // Wipe screen - void CreateWipeTexture(int w, int h, const char *name); - - void DeleteDescriptors() override { ResetDescriptors(); } - - VkTextureImage *GetImage(FTexture *tex, int translation, int flags); - VkTextureImage *GetDepthStencil(FTexture *tex); - - static void ResetAllDescriptors(); - -private: - void CreateImage(FTexture *tex, int translation, int flags); - - void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels); - static int GetMipLevels(int w, int h); - - void ResetDescriptors(); - - static VkHardwareTexture *First; - VkHardwareTexture *Prev = nullptr; - VkHardwareTexture *Next = nullptr; - - struct DescriptorEntry - { - int clampmode; - int flags; - std::unique_ptr descriptor; - - DescriptorEntry(int cm, int f, std::unique_ptr &&d) - { - clampmode = cm; - flags = f; - descriptor = std::move(d); - } - }; - - std::vector mDescriptorSets; - VkTextureImage mImage; - int mTexelsize = 4; - - VkTextureImage mDepthStencil; - - uint8_t* mappedSWFB = nullptr; -}; diff --git a/src/rendering/vulkan/textures/vk_imagetransition.cpp b/src/rendering/vulkan/textures/vk_imagetransition.cpp deleted file mode 100644 index a135a3f0ffc..00000000000 --- a/src/rendering/vulkan/textures/vk_imagetransition.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "vk_imagetransition.h" - -void VkImageTransition::addImage(VkTextureImage *image, VkImageLayout targetLayout, bool undefinedSrcLayout) -{ - if (image->Layout == targetLayout) - return; - - VkAccessFlags srcAccess = 0; - VkAccessFlags dstAccess = 0; - VkImageAspectFlags aspectMask = image->AspectMask; - - switch (image->Layout) - { - case VK_IMAGE_LAYOUT_UNDEFINED: - srcAccess = 0; - srcStageMask |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - srcAccess = VK_ACCESS_TRANSFER_READ_BIT; - srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - srcAccess = VK_ACCESS_SHADER_READ_BIT; - srcStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - srcAccess = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - srcAccess = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - srcAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - srcStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - default: - I_FatalError("Unimplemented src image layout transition\n"); - } - - switch (targetLayout) - { - case VK_IMAGE_LAYOUT_GENERAL: - dstAccess = 0; - dstStageMask |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - dstAccess = VK_ACCESS_TRANSFER_READ_BIT; - dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - dstAccess = VK_ACCESS_SHADER_READ_BIT; - dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - dstAccess = VK_ACCESS_TRANSFER_WRITE_BIT; - dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - dstAccess = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dstStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - srcAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - srcStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - default: - I_FatalError("Unimplemented dst image layout transition\n"); - } - - barrier.addImage(image->Image.get(), undefinedSrcLayout ? VK_IMAGE_LAYOUT_UNDEFINED : image->Layout, targetLayout, srcAccess, dstAccess, aspectMask); - needbarrier = true; - image->Layout = targetLayout; -} - -void VkImageTransition::execute(VulkanCommandBuffer *cmdbuffer) -{ - if (needbarrier) - barrier.execute(cmdbuffer, srcStageMask, dstStageMask); -} - -///////////////////////////////////////////////////////////////////////////// - -void VkTextureImage::GenerateMipmaps(VulkanCommandBuffer *cmdbuffer) -{ - int mipWidth = Image->width; - int mipHeight = Image->height; - int i; - for (i = 1; mipWidth > 1 || mipHeight > 1; i++) - { - PipelineBarrier barrier0; - barrier0.addImage(Image.get(), Layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, i - 1); - barrier0.addImage(Image.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, i); - barrier0.execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - Layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - - int nextWidth = std::max(mipWidth >> 1, 1); - int nextHeight = std::max(mipHeight >> 1, 1); - - VkImageBlit blit = {}; - blit.srcOffsets[0] = { 0, 0, 0 }; - blit.srcOffsets[1] = { mipWidth, mipHeight, 1 }; - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = 1; - blit.dstOffsets[0] = { 0, 0, 0 }; - blit.dstOffsets[1] = { nextWidth, nextHeight, 1 }; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = 1; - cmdbuffer->blitImage(Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); - - PipelineBarrier barrier1; - barrier1.addImage(Image.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, i - 1); - barrier1.execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - mipWidth = nextWidth; - mipHeight = nextHeight; - } - - PipelineBarrier barrier2; - barrier2.addImage(Image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, i - 1); - barrier2.execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - Layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; -} diff --git a/src/rendering/vulkan/textures/vk_imagetransition.h b/src/rendering/vulkan/textures/vk_imagetransition.h deleted file mode 100644 index 916f20c2487..00000000000 --- a/src/rendering/vulkan/textures/vk_imagetransition.h +++ /dev/null @@ -1,44 +0,0 @@ - -#pragma once - -#include "vulkan/system/vk_objects.h" -#include "vulkan/system/vk_builders.h" -#include "vulkan/renderer/vk_renderpass.h" - -class VkTextureImage -{ -public: - void reset() - { - AspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - Layout = VK_IMAGE_LAYOUT_UNDEFINED; - PPFramebuffer.reset(); - RSFramebuffers.clear(); - DepthOnlyView.reset(); - View.reset(); - Image.reset(); - } - - void GenerateMipmaps(VulkanCommandBuffer *cmdbuffer); - - std::unique_ptr Image; - std::unique_ptr View; - std::unique_ptr DepthOnlyView; - VkImageLayout Layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkImageAspectFlags AspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - std::unique_ptr PPFramebuffer; - std::map> RSFramebuffers; -}; - -class VkImageTransition -{ -public: - void addImage(VkTextureImage *image, VkImageLayout targetLayout, bool undefinedSrcLayout); - void execute(VulkanCommandBuffer *cmdbuffer); - -private: - PipelineBarrier barrier; - VkPipelineStageFlags srcStageMask = 0; - VkPipelineStageFlags dstStageMask = 0; - bool needbarrier = false; -}; diff --git a/src/rendering/vulkan/textures/vk_samplers.cpp b/src/rendering/vulkan/textures/vk_samplers.cpp deleted file mode 100644 index 7dd32b87843..00000000000 --- a/src/rendering/vulkan/textures/vk_samplers.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -** Vulkan backend -** Copyright (c) 2016-2020 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include "volk/volk.h" -#include "c_cvars.h" -#include "v_video.h" - -#include "hwrenderer/utility/hw_cvars.h" -#include "vulkan/system/vk_device.h" -#include "vulkan/system/vk_builders.h" -#include "vk_samplers.h" -#include "hwrenderer/textures/hw_material.h" - -struct VkTexFilter -{ - VkFilter minFilter; - VkFilter magFilter; - VkSamplerMipmapMode mipfilter; - bool mipmapping; -} ; - -VkTexFilter TexFilter[]={ - {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, false}, - {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, true}, - {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, false}, - {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, true}, - {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}, - {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}, - {VK_FILTER_LINEAR, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}, -}; - -struct VkTexClamp -{ - VkSamplerAddressMode clamp_u; - VkSamplerAddressMode clamp_v; -}; - -VkTexClamp TexClamp[] ={ - { VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT }, - { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT }, - { VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, - { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, - { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, - { VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT }, - { VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT } -}; - -VkSamplerManager::VkSamplerManager(VulkanDevice *dev) -{ - vDevice = dev; - Create(); -} - -VkSamplerManager::~VkSamplerManager() -{ - Destroy(); -} - -void VkSamplerManager::SetTextureFilterMode() -{ - Destroy(); - Create(); -} - -void VkSamplerManager::Create() -{ - int filter = V_IsHardwareRenderer() ? gl_texture_filter : 0; - - for(int i = 0; i < 7; i++) - { - SamplerBuilder builder; - builder.setMagFilter(TexFilter[filter].magFilter); - builder.setMinFilter(TexFilter[filter].minFilter); - builder.setAddressMode(TexClamp[i].clamp_u, TexClamp[i].clamp_v, VK_SAMPLER_ADDRESS_MODE_REPEAT); - builder.setMipmapMode(TexFilter[filter].mipfilter); - if (i <= CLAMP_XY && TexFilter[filter].mipmapping) - { - builder.setAnisotropy(gl_texture_filter_anisotropic); - builder.setMaxLod(100.0f); // According to the spec this value is clamped so something high makes it usable for all textures. - } - else - { - builder.setMaxLod(0.25f); - } - mSamplers[i] = builder.create(vDevice); - mSamplers[i]->SetDebugName("VkSamplerManager.mSamplers"); - } -} - -void VkSamplerManager::Destroy() -{ - for (int i = 0; i < 7; i++) - mSamplers[i].reset(); -} diff --git a/src/rendering/vulkan/textures/vk_samplers.h b/src/rendering/vulkan/textures/vk_samplers.h deleted file mode 100644 index 0a088cf74c3..00000000000 --- a/src/rendering/vulkan/textures/vk_samplers.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __VK_SAMPLERS_H -#define __VK_SAMPLERS_H - -#include "rendering/vulkan/system/vk_objects.h" - -class VulkanDevice; - -class VkSamplerManager -{ - VulkanDevice *vDevice; - std::unique_ptr mSamplers[7]; - - //void UnbindAll(); - - void Create(); - void Destroy(); - -public: - - VkSamplerManager(VulkanDevice *dev); - ~VkSamplerManager(); - - //uint8_t Bind(int texunit, int num, int lastval); - void SetTextureFilterMode(); - - VulkanSampler *Get(int no) const { return mSamplers[no].get(); } - -}; - - -#endif - diff --git a/src/rendering/vulkan/thirdparty/vk_mem_alloc/vk_mem_alloc.cpp b/src/rendering/vulkan/thirdparty/vk_mem_alloc/vk_mem_alloc.cpp deleted file mode 100644 index 7edacfe8263..00000000000 --- a/src/rendering/vulkan/thirdparty/vk_mem_alloc/vk_mem_alloc.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "volk/volk.h" -#define VMA_IMPLEMENTATION -#define VMA_STATIC_VULKAN_FUNCTIONS 1 - -#include "vk_mem_alloc.h" diff --git a/src/rendering/vulkan/thirdparty/vk_mem_alloc/vk_mem_alloc.h b/src/rendering/vulkan/thirdparty/vk_mem_alloc/vk_mem_alloc.h deleted file mode 100644 index 53ce163bfbb..00000000000 --- a/src/rendering/vulkan/thirdparty/vk_mem_alloc/vk_mem_alloc.h +++ /dev/null @@ -1,9365 +0,0 @@ -// -// Copyright (c) 2017-2018 Advanced Micro Devices, Inc. All rights reserved. -// -// 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. -// - -#ifndef AMD_VULKAN_MEMORY_ALLOCATOR_H -#define AMD_VULKAN_MEMORY_ALLOCATOR_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** \mainpage Vulkan Memory Allocator - -Version 2.0.0 (2018-03-19) - -Copyright (c) 2017-2018 Advanced Micro Devices, Inc. All rights reserved. \n -License: MIT - -Documentation of all members: vk_mem_alloc.h - -\section main_table_of_contents Table of contents - -- User guide - - \subpage quick_start - - [Project setup](@ref quick_start_project_setup) - - [Initialization](@ref quick_start_initialization) - - [Resource allocation](@ref quick_start_resource_allocation) - - \subpage choosing_memory_type - - [Usage](@ref choosing_memory_type_usage) - - [Required and preferred flags](@ref choosing_memory_type_required_preferred_flags) - - [Explicit memory types](@ref choosing_memory_type_explicit_memory_types) - - [Custom memory pools](@ref choosing_memory_type_custom_memory_pools) - - \subpage memory_mapping - - [Mapping functions](@ref memory_mapping_mapping_functions) - - [Persistently mapped memory](@ref memory_mapping_persistently_mapped_memory) - - [Cache control](@ref memory_mapping_cache_control) - - [Finding out if memory is mappable](@ref memory_mapping_finding_if_memory_mappable) - - \subpage custom_memory_pools - - [Choosing memory type index](@ref custom_memory_pools_MemTypeIndex) - - \subpage defragmentation - - \subpage lost_allocations - - \subpage statistics - - [Numeric statistics](@ref statistics_numeric_statistics) - - [JSON dump](@ref statistics_json_dump) - - \subpage allocation_annotation - - [Allocation user data](@ref allocation_user_data) - - [Allocation names](@ref allocation_names) -- \subpage usage_patterns - - [Simple patterns](@ref usage_patterns_simple) - - [Advanced patterns](@ref usage_patterns_advanced) -- \subpage configuration - - [Pointers to Vulkan functions](@ref config_Vulkan_functions) - - [Custom host memory allocator](@ref custom_memory_allocator) - - [Device memory allocation callbacks](@ref allocation_callbacks) - - [Device heap memory limit](@ref heap_memory_limit) - - \subpage vk_khr_dedicated_allocation -- \subpage general_considerations - - [Thread safety](@ref general_considerations_thread_safety) - - [Allocation algorithm](@ref general_considerations_allocation_algorithm) - - [Features not supported](@ref general_considerations_features_not_supported) - -\section main_see_also See also - -- [Product page on GPUOpen](https://gpuopen.com/gaming-product/vulkan-memory-allocator/) -- [Source repository on GitHub](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) - - - - -\page quick_start Quick start - -\section quick_start_project_setup Project setup - -Vulkan Memory Allocator comes in form of a single header file. -You don't need to build it as a separate library project. -You can add this file directly to your project and submit it to code repository next to your other source files. - -"Single header" doesn't mean that everything is contained in C/C++ declarations, -like it tends to be in case of inline functions or C++ templates. -It means that implementation is bundled with interface in a single file and needs to be extracted using preprocessor macro. -If you don't do it properly, you will get linker errors. - -To do it properly: - --# Include "vk_mem_alloc.h" file in each CPP file where you want to use the library. - This includes declarations of all members of the library. --# In exacly one CPP file define following macro before this include. - It enables also internal definitions. - -\code -#define VMA_IMPLEMENTATION -#include "vk_mem_alloc.h" -\endcode - -It may be a good idea to create dedicated CPP file just for this purpose. - -\section quick_start_initialization Initialization - -At program startup: - --# Initialize Vulkan to have `VkPhysicalDevice` and `VkDevice` object. --# Fill VmaAllocatorCreateInfo structure and create #VmaAllocator object by - calling vmaCreateAllocator(). - -\code -VmaAllocatorCreateInfo allocatorInfo = {}; -allocatorInfo.physicalDevice = physicalDevice; -allocatorInfo.device = device; - -VmaAllocator allocator; -vmaCreateAllocator(&allocatorInfo, &allocator); -\endcode - -\section quick_start_resource_allocation Resource allocation - -When you want to create a buffer or image: - --# Fill `VkBufferCreateInfo` / `VkImageCreateInfo` structure. --# Fill VmaAllocationCreateInfo structure. --# Call vmaCreateBuffer() / vmaCreateImage() to get `VkBuffer`/`VkImage` with memory - already allocated and bound to it. - -\code -VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufferInfo.size = 65536; -bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -\endcode - -Don't forget to destroy your objects when no longer needed: - -\code -vmaDestroyBuffer(allocator, buffer, allocation); -vmaDestroyAllocator(allocator); -\endcode - - -\page choosing_memory_type Choosing memory type - -Physical devices in Vulkan support various combinations of memory heaps and -types. Help with choosing correct and optimal memory type for your specific -resource is one of the key features of this library. You can use it by filling -appropriate members of VmaAllocationCreateInfo structure, as described below. -You can also combine multiple methods. - --# If you just want to find memory type index that meets your requirements, you - can use function vmaFindMemoryTypeIndex(). --# If you want to allocate a region of device memory without association with any - specific image or buffer, you can use function vmaAllocateMemory(). Usage of - this function is not recommended and usually not needed. --# If you already have a buffer or an image created, you want to allocate memory - for it and then you will bind it yourself, you can use function - vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(). - For binding you should use functions: vmaBindBufferMemory(), vmaBindImageMemory(). --# If you want to create a buffer or an image, allocate memory for it and bind - them together, all in one call, you can use function vmaCreateBuffer(), - vmaCreateImage(). This is the recommended way to use this library. - -When using 3. or 4., the library internally queries Vulkan for memory types -supported for that buffer or image (function `vkGetBufferMemoryRequirements()`) -and uses only one of these types. - -If no memory type can be found that meets all the requirements, these functions -return `VK_ERROR_FEATURE_NOT_PRESENT`. - -You can leave VmaAllocationCreateInfo structure completely filled with zeros. -It means no requirements are specified for memory type. -It is valid, although not very useful. - -\section choosing_memory_type_usage Usage - -The easiest way to specify memory requirements is to fill member -VmaAllocationCreateInfo::usage using one of the values of enum #VmaMemoryUsage. -It defines high level, common usage types. -For more details, see description of this enum. - -For example, if you want to create a uniform buffer that will be filled using -transfer only once or infrequently and used for rendering every frame, you can -do it using following code: - -\code -VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufferInfo.size = 65536; -bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -\endcode - -\section choosing_memory_type_required_preferred_flags Required and preferred flags - -You can specify more detailed requirements by filling members -VmaAllocationCreateInfo::requiredFlags and VmaAllocationCreateInfo::preferredFlags -with a combination of bits from enum `VkMemoryPropertyFlags`. For example, -if you want to create a buffer that will be persistently mapped on host (so it -must be `HOST_VISIBLE`) and preferably will also be `HOST_COHERENT` and `HOST_CACHED`, -use following code: - -\code -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; -allocInfo.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; -allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -\endcode - -A memory type is chosen that has all the required flags and as many preferred -flags set as possible. - -If you use VmaAllocationCreateInfo::usage, it is just internally converted to -a set of required and preferred flags. - -\section choosing_memory_type_explicit_memory_types Explicit memory types - -If you inspected memory types available on the physical device and you have -a preference for memory types that you want to use, you can fill member -VmaAllocationCreateInfo::memoryTypeBits. It is a bit mask, where each bit set -means that a memory type with that index is allowed to be used for the -allocation. Special value 0, just like `UINT32_MAX`, means there are no -restrictions to memory type index. - -Please note that this member is NOT just a memory type index. -Still you can use it to choose just one, specific memory type. -For example, if you already determined that your buffer should be created in -memory type 2, use following code: - -\code -uint32_t memoryTypeIndex = 2; - -VmaAllocationCreateInfo allocInfo = {}; -allocInfo.memoryTypeBits = 1u << memoryTypeIndex; - -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); -\endcode - -\section choosing_memory_type_custom_memory_pools Custom memory pools - -If you allocate from custom memory pool, all the ways of specifying memory -requirements described above are not applicable and the aforementioned members -of VmaAllocationCreateInfo structure are ignored. Memory type is selected -explicitly when creating the pool and then used to make all the allocations from -that pool. For further details, see \ref custom_memory_pools. - - -\page memory_mapping Memory mapping - -To "map memory" in Vulkan means to obtain a CPU pointer to `VkDeviceMemory`, -to be able to read from it or write to it in CPU code. -Mapping is possible only of memory allocated from a memory type that has -`VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. -Functions `vkMapMemory()`, `vkUnmapMemory()` are designed for this purpose. -You can use them directly with memory allocated by this library, -but it is not recommended because of following issue: -Mapping the same `VkDeviceMemory` block multiple times is illegal - only one mapping at a time is allowed. -This includes mapping disjoint regions. Mapping is not reference-counted internally by Vulkan. -Because of this, Vulkan Memory Allocator provides following facilities: - -\section memory_mapping_mapping_functions Mapping functions - -The library provides following functions for mapping of a specific #VmaAllocation: vmaMapMemory(), vmaUnmapMemory(). -They are safer and more convenient to use than standard Vulkan functions. -You can map an allocation multiple times simultaneously - mapping is reference-counted internally. -You can also map different allocations simultaneously regardless of whether they use the same `VkDeviceMemory` block. -They way it's implemented is that the library always maps entire memory block, not just region of the allocation. -For further details, see description of vmaMapMemory() function. -Example: - -\code -// Having these objects initialized: - -struct ConstantBuffer -{ - ... -}; -ConstantBuffer constantBufferData; - -VmaAllocator allocator; -VmaBuffer constantBuffer; -VmaAllocation constantBufferAllocation; - -// You can map and fill your buffer using following code: - -void* mappedData; -vmaMapMemory(allocator, constantBufferAllocation, &mappedData); -memcpy(mappedData, &constantBufferData, sizeof(constantBufferData)); -vmaUnmapMemory(allocator, constantBufferAllocation); -\endcode - -\section memory_mapping_persistently_mapped_memory Persistently mapped memory - -Kepping your memory persistently mapped is generally OK in Vulkan. -You don't need to unmap it before using its data on the GPU. -The library provides a special feature designed for that: -Allocations made with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag set in -VmaAllocationCreateInfo::flags stay mapped all the time, -so you can just access CPU pointer to it any time -without a need to call any "map" or "unmap" function. -Example: - -\code -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = sizeof(ConstantBuffer); -bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; -allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); - -// Buffer is already mapped. You can access its memory. -memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); -\endcode - -There are some exceptions though, when you should consider mapping memory only for a short period of time: - -- When operating system is Windows 7 or 8.x (Windows 10 is not affected because it uses WDDM2), - device is discrete AMD GPU, - and memory type is the special 256 MiB pool of `DEVICE_LOCAL + HOST_VISIBLE` memory - (selected when you use #VMA_MEMORY_USAGE_CPU_TO_GPU), - then whenever a memory block allocated from this memory type stays mapped - for the time of any call to `vkQueueSubmit()` or `vkQueuePresentKHR()`, this - block is migrated by WDDM to system RAM, which degrades performance. It doesn't - matter if that particular memory block is actually used by the command buffer - being submitted. -- Keeping many large memory blocks mapped may impact performance or stability of some debugging tools. - -\section memory_mapping_cache_control Cache control - -Memory in Vulkan doesn't need to be unmapped before using it on GPU, -but unless a memory types has `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` flag set, -you need to manually invalidate cache before reading of mapped pointer -using function `vkvkInvalidateMappedMemoryRanges()` -and flush cache after writing to mapped pointer -using function `vkFlushMappedMemoryRanges()`. -Example: - -\code -memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); - -VkMemoryPropertyFlags memFlags; -vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &memFlags); -if((memFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) -{ - VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; - memRange.memory = allocInfo.deviceMemory; - memRange.offset = allocInfo.offset; - memRange.size = allocInfo.size; - vkFlushMappedMemoryRanges(device, 1, &memRange); -} -\endcode - -Please note that memory allocated with #VMA_MEMORY_USAGE_CPU_ONLY is guaranteed to be host coherent. - -Also, Windows drivers from all 3 PC GPU vendors (AMD, Intel, NVIDIA) -currently provide `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` flag on all memory types that are -`VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, so on this platform you may not need to bother. - -\section memory_mapping_finding_if_memory_mappable Finding out if memory is mappable - -It may happen that your allocation ends up in memory that is `HOST_VISIBLE` (available for mapping) -despite it wasn't explicitly requested. -For example, application may work on integrated graphics with unified memory (like Intel) or -allocation from video memory might have failed, so the library chose system memory as fallback. - -You can detect this case and map such allocation to access its memory on CPU directly, -instead of launching a transfer operation. -In order to do that: inspect `allocInfo.memoryType`, call vmaGetMemoryTypeProperties(), -and look for `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag in properties of that memory type. - -\code -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = sizeof(ConstantBuffer); -bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); - -VkMemoryPropertyFlags memFlags; -vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &memFlags); -if((memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) -{ - // Allocation ended up in mappable memory. You can map it and access it directly. - void* mappedData; - vmaMapMemory(allocator, alloc, &mappedData); - memcpy(mappedData, &constantBufferData, sizeof(constantBufferData)); - vmaUnmapMemory(allocator, alloc); -} -else -{ - // Allocation ended up in non-mappable memory. - // You need to create CPU-side buffer in VMA_MEMORY_USAGE_CPU_ONLY and make a transfer. -} -\endcode - -You can even use #VMA_ALLOCATION_CREATE_MAPPED_BIT flag while creating allocations -that are not necessarily `HOST_VISIBLE` (e.g. using #VMA_MEMORY_USAGE_GPU_ONLY). -If the allocation ends up in memory type that is `HOST_VISIBLE`, it will be persistently mapped and you can use it directly. -If not, the flag is just ignored. -Example: - -\code -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = sizeof(ConstantBuffer); -bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; -allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); - -if(allocInfo.pUserData != nullptr) -{ - // Allocation ended up in mappable memory. - // It's persistently mapped. You can access it directly. - memcpy(allocInfo.pMappedData, &constantBufferData, sizeof(constantBufferData)); -} -else -{ - // Allocation ended up in non-mappable memory. - // You need to create CPU-side buffer in VMA_MEMORY_USAGE_CPU_ONLY and make a transfer. -} -\endcode - - -\page custom_memory_pools Custom memory pools - -A memory pool contains a number of `VkDeviceMemory` blocks. -The library automatically creates and manages default pool for each memory type available on the device. -Default memory pool automatically grows in size. -Size of allocated blocks is also variable and managed automatically. - -You can create custom pool and allocate memory out of it. -It can be useful if you want to: - -- Keep certain kind of allocations separate from others. -- Enforce particular, fixed size of Vulkan memory blocks. -- Limit maximum amount of Vulkan memory allocated for that pool. -- Reserve minimum or fixed amount of Vulkan memory always preallocated for that pool. - -To use custom memory pools: - --# Fill VmaPoolCreateInfo structure. --# Call vmaCreatePool() to obtain #VmaPool handle. --# When making an allocation, set VmaAllocationCreateInfo::pool to this handle. - You don't need to specify any other parameters of this structure, like usage. - -Example: - -\code -// Create a pool that can have at most 2 blocks, 128 MiB each. -VmaPoolCreateInfo poolCreateInfo = {}; -poolCreateInfo.memoryTypeIndex = ... -poolCreateInfo.blockSize = 128ull * 1024 * 1024; -poolCreateInfo.maxBlockCount = 2; - -VmaPool pool; -vmaCreatePool(allocator, &poolCreateInfo, &pool); - -// Allocate a buffer out of it. -VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -bufCreateInfo.size = 1024; -bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.pool = pool; - -VkBuffer buf; -VmaAllocation alloc; -VmaAllocationInfo allocInfo; -vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo); -\endcode - -You have to free all allocations made from this pool before destroying it. - -\code -vmaDestroyBuffer(allocator, buf, alloc); -vmaDestroyPool(allocator, pool); -\endcode - -\section custom_memory_pools_MemTypeIndex Choosing memory type index - -When creating a pool, you must explicitly specify memory type index. -To find the one suitable for your buffers or images, you can use helper functions -vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo(). -You need to provide structures with example parameters of buffers or images -that you are going to create in that pool. - -\code -VkBufferCreateInfo exampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -exampleBufCreateInfo.size = 1024; // Whatever. -exampleBufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; // Change if needed. - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; // Change if needed. - -uint32_t memTypeIndex; -vmaFindMemoryTypeIndexForBufferInfo(allocator, &exampleBufCreateInfo, &allocCreateInfo, &memTypeIndex); - -VmaPoolCreateInfo poolCreateInfo = {}; -poolCreateInfo.memoryTypeIndex = memTypeIndex; -// ... -\endcode - -When creating buffers/images allocated in that pool, provide following parameters: - -- `VkBufferCreateInfo`: Prefer to pass same parameters as above. - Otherwise you risk creating resources in a memory type that is not suitable for them, which may result in undefined behavior. - Using different `VK_BUFFER_USAGE_` flags may work, but you shouldn't create images in a pool intended for buffers - or the other way around. -- VmaAllocationCreateInfo: You don't need to pass same parameters. Fill only `pool` member. - Other members are ignored anyway. - - -\page defragmentation Defragmentation - -Interleaved allocations and deallocations of many objects of varying size can -cause fragmentation, which can lead to a situation where the library is unable -to find a continuous range of free memory for a new allocation despite there is -enough free space, just scattered across many small free ranges between existing -allocations. - -To mitigate this problem, you can use vmaDefragment(). Given set of allocations, -this function can move them to compact used memory, ensure more continuous free -space and possibly also free some `VkDeviceMemory`. It can work only on -allocations made from memory type that is `HOST_VISIBLE`. Allocations are -modified to point to the new `VkDeviceMemory` and offset. Data in this memory is -also `memmove`-ed to the new place. However, if you have images or buffers bound -to these allocations (and you certainly do), you need to destroy, recreate, and -bind them to the new place in memory. - -For further details and example code, see documentation of function -vmaDefragment(). - -\page lost_allocations Lost allocations - -If your game oversubscribes video memory, if may work OK in previous-generation -graphics APIs (DirectX 9, 10, 11, OpenGL) because resources are automatically -paged to system RAM. In Vulkan you can't do it because when you run out of -memory, an allocation just fails. If you have more data (e.g. textures) that can -fit into VRAM and you don't need it all at once, you may want to upload them to -GPU on demand and "push out" ones that are not used for a long time to make room -for the new ones, effectively using VRAM (or a cartain memory pool) as a form of -cache. Vulkan Memory Allocator can help you with that by supporting a concept of -"lost allocations". - -To create an allocation that can become lost, include #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT -flag in VmaAllocationCreateInfo::flags. Before using a buffer or image bound to -such allocation in every new frame, you need to query it if it's not lost. -To check it, call vmaTouchAllocation(). -If the allocation is lost, you should not use it or buffer/image bound to it. -You mustn't forget to destroy this allocation and this buffer/image. -vmaGetAllocationInfo() can also be used for checking status of the allocation. -Allocation is lost when returned VmaAllocationInfo::deviceMemory == `VK_NULL_HANDLE`. - -To create an allocation that can make some other allocations lost to make room -for it, use #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag. You will -usually use both flags #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT and -#VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT at the same time. - -Warning! Current implementation uses quite naive, brute force algorithm, -which can make allocation calls that use #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT -flag quite slow. A new, more optimal algorithm and data structure to speed this -up is planned for the future. - -Q: When interleaving creation of new allocations with usage of existing ones, -how do you make sure that an allocation won't become lost while it's used in the -current frame? - -It is ensured because vmaTouchAllocation() / vmaGetAllocationInfo() not only returns allocation -status/parameters and checks whether it's not lost, but when it's not, it also -atomically marks it as used in the current frame, which makes it impossible to -become lost in that frame. It uses lockless algorithm, so it works fast and -doesn't involve locking any internal mutex. - -Q: What if my allocation may still be in use by the GPU when it's rendering a -previous frame while I already submit new frame on the CPU? - -You can make sure that allocations "touched" by vmaTouchAllocation() / vmaGetAllocationInfo() will not -become lost for a number of additional frames back from the current one by -specifying this number as VmaAllocatorCreateInfo::frameInUseCount (for default -memory pool) and VmaPoolCreateInfo::frameInUseCount (for custom pool). - -Q: How do you inform the library when new frame starts? - -You need to call function vmaSetCurrentFrameIndex(). - -Example code: - -\code -struct MyBuffer -{ - VkBuffer m_Buf = nullptr; - VmaAllocation m_Alloc = nullptr; - - // Called when the buffer is really needed in the current frame. - void EnsureBuffer(); -}; - -void MyBuffer::EnsureBuffer() -{ - // Buffer has been created. - if(m_Buf != VK_NULL_HANDLE) - { - // Check if its allocation is not lost + mark it as used in current frame. - if(vmaTouchAllocation(allocator, m_Alloc)) - { - // It's all OK - safe to use m_Buf. - return; - } - } - - // Buffer not yet exists or lost - destroy and recreate it. - - vmaDestroyBuffer(allocator, m_Buf, m_Alloc); - - VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufCreateInfo.size = 1024; - bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - - VmaAllocationCreateInfo allocCreateInfo = {}; - allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT | - VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT; - - vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &m_Buf, &m_Alloc, nullptr); -} -\endcode - -When using lost allocations, you may see some Vulkan validation layer warnings -about overlapping regions of memory bound to different kinds of buffers and -images. This is still valid as long as you implement proper handling of lost -allocations (like in the example above) and don't use them. - -You can create an allocation that is already in lost state from the beginning using function -vmaCreateLostAllocation(). It may be useful if you need a "dummy" allocation that is not null. - -You can call function vmaMakePoolAllocationsLost() to set all eligible allocations -in a specified custom pool to lost state. -Allocations that have been "touched" in current frame or VmaPoolCreateInfo::frameInUseCount frames back -cannot become lost. - - -\page statistics Statistics - -This library contains functions that return information about its internal state, -especially the amount of memory allocated from Vulkan. -Please keep in mind that these functions need to traverse all internal data structures -to gather these information, so they may be quite time-consuming. -Don't call them too often. - -\section statistics_numeric_statistics Numeric statistics - -You can query for overall statistics of the allocator using function vmaCalculateStats(). -Information are returned using structure #VmaStats. -It contains #VmaStatInfo - number of allocated blocks, number of allocations -(occupied ranges in these blocks), number of unused (free) ranges in these blocks, -number of bytes used and unused (but still allocated from Vulkan) and other information. -They are summed across memory heaps, memory types and total for whole allocator. - -You can query for statistics of a custom pool using function vmaGetPoolStats(). -Information are returned using structure #VmaPoolStats. - -You can query for information about specific allocation using function vmaGetAllocationInfo(). -It fill structure #VmaAllocationInfo. - -\section statistics_json_dump JSON dump - -You can dump internal state of the allocator to a string in JSON format using function vmaBuildStatsString(). -The result is guaranteed to be correct JSON. -It uses ANSI encoding. -Any strings provided by user (see [Allocation names](@ref allocation_names)) -are copied as-is and properly escaped for JSON, so if they use UTF-8, ISO-8859-2 or any other encoding, -this JSON string can be treated as using this encoding. -It must be freed using function vmaFreeStatsString(). - -The format of this JSON string is not part of official documentation of the library, -but it will not change in backward-incompatible way without increasing library major version number -and appropriate mention in changelog. - -The JSON string contains all the data that can be obtained using vmaCalculateStats(). -It can also contain detailed map of allocated memory blocks and their regions - -free and occupied by allocations. -This allows e.g. to visualize the memory or assess fragmentation. - - -\page allocation_annotation Allocation names and user data - -\section allocation_user_data Allocation user data - -You can annotate allocations with your own information, e.g. for debugging purposes. -To do that, fill VmaAllocationCreateInfo::pUserData field when creating -an allocation. It's an opaque `void*` pointer. You can use it e.g. as a pointer, -some handle, index, key, ordinal number or any other value that would associate -the allocation with your custom metadata. - -\code -VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; -// Fill bufferInfo... - -MyBufferMetadata* pMetadata = CreateBufferMetadata(); - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; -allocCreateInfo.pUserData = pMetadata; - -VkBuffer buffer; -VmaAllocation allocation; -vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, nullptr); -\endcode - -The pointer may be later retrieved as VmaAllocationInfo::pUserData: - -\code -VmaAllocationInfo allocInfo; -vmaGetAllocationInfo(allocator, allocation, &allocInfo); -MyBufferMetadata* pMetadata = (MyBufferMetadata*)allocInfo.pUserData; -\endcode - -It can also be changed using function vmaSetAllocationUserData(). - -Values of (non-zero) allocations' `pUserData` are printed in JSON report created by -vmaBuildStatsString(), in hexadecimal form. - -\section allocation_names Allocation names - -There is alternative mode available where `pUserData` pointer is used to point to -a null-terminated string, giving a name to the allocation. To use this mode, -set #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT flag in VmaAllocationCreateInfo::flags. -Then `pUserData` passed as VmaAllocationCreateInfo::pUserData or argument to -vmaSetAllocationUserData() must be either null or pointer to a null-terminated string. -The library creates internal copy of the string, so the pointer you pass doesn't need -to be valid for whole lifetime of the allocation. You can free it after the call. - -\code -VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; -// Fill imageInfo... - -std::string imageName = "Texture: "; -imageName += fileName; - -VmaAllocationCreateInfo allocCreateInfo = {}; -allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; -allocCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT; -allocCreateInfo.pUserData = imageName.c_str(); - -VkImage image; -VmaAllocation allocation; -vmaCreateImage(allocator, &imageInfo, &allocCreateInfo, &image, &allocation, nullptr); -\endcode - -The value of `pUserData` pointer of the allocation will be different than the one -you passed when setting allocation's name - pointing to a buffer managed -internally that holds copy of the string. - -\code -VmaAllocationInfo allocInfo; -vmaGetAllocationInfo(allocator, allocation, &allocInfo); -const char* imageName = (const char*)allocInfo.pUserData; -printf("Image name: %s\n", imageName); -\endcode - -That string is also printed in JSON report created by vmaBuildStatsString(). - - -\page usage_patterns Recommended usage patterns - -\section usage_patterns_simple Simple patterns - -\subsection usage_patterns_simple_render_targets Render targets - -When: -Any resources that you frequently write and read on GPU, -e.g. images used as color attachments (aka "render targets"), depth-stencil attachments, -images/buffers used as storage image/buffer (aka "Unordered Access View (UAV)"). - -What to do: -Create them in video memory that is fastest to access from GPU using -#VMA_MEMORY_USAGE_GPU_ONLY. - -Consider using [VK_KHR_dedicated_allocation](@ref vk_khr_dedicated_allocation) extension -and/or manually creating them as dedicated allocations using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, -especially if they are large or if you plan to destroy and recreate them e.g. when -display resolution changes. -Prefer to create such resources first and all other GPU resources (like textures and vertex buffers) later. - -\subsection usage_patterns_simple_immutable_resources Immutable resources - -When: -Any resources that you fill on CPU only once (aka "immutable") or infrequently -and then read frequently on GPU, -e.g. textures, vertex and index buffers, constant buffers that don't change often. - -What to do: -Create them in video memory that is fastest to access from GPU using -#VMA_MEMORY_USAGE_GPU_ONLY. - -To initialize content of such resource, create a CPU-side (aka "staging") copy of it -in system memory - #VMA_MEMORY_USAGE_CPU_ONLY, map it, fill it, -and submit a transfer from it to the GPU resource. -You can keep the staging copy if you need it for another upload transfer in the future. -If you don't, you can destroy it or reuse this buffer for uploading different resource -after the transfer finishes. - -Prefer to create just buffers in system memory rather than images, even for uploading textures. -Use `vkCmdCopyBufferToImage()`. -Dont use images with `VK_IMAGE_TILING_LINEAR`. - -\subsection usage_patterns_dynamic_resources Dynamic resources - -When: -Any resources that change frequently (aka "dynamic"), e.g. every frame or every draw call, -written on CPU, read on GPU. - -What to do: -Create them using #VMA_MEMORY_USAGE_CPU_TO_GPU. -You can map it and write to it directly on CPU, as well as read from it on GPU. - -This is a more complex situation. Different solutions are possible, -and the best one depends on specific GPU type, but you can use this simple approach for the start. -Prefer to write to such resource sequentially (e.g. using `memcpy`). -Don't perform random access or any reads from it, as it may be very slow. - -\subsection usage_patterns_readback Readback - -When: -Resources that contain data written by GPU that you want to read back on CPU, -e.g. results of some computations. - -What to do: -Create them using #VMA_MEMORY_USAGE_GPU_TO_CPU. -You can write to them directly on GPU, as well as map and read them on CPU. - -\section usage_patterns_advanced Advanced patterns - -\subsection usage_patterns_integrated_graphics Detecting integrated graphics - -You can support integrated graphics (like Intel HD Graphics, AMD APU) better -by detecting it in Vulkan. -To do it, call `vkGetPhysicalDeviceProperties()`, inspect -`VkPhysicalDeviceProperties::deviceType` and look for `VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU`. -When you find it, you can assume that memory is unified and all memory types are equally fast -to access from GPU, regardless of `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. - -You can then sum up sizes of all available memory heaps and treat them as useful for -your GPU resources, instead of only `DEVICE_LOCAL` ones. -You can also prefer to create your resources in memory types that are `HOST_VISIBLE` to map them -directly instead of submitting explicit transfer (see below). - -\subsection usage_patterns_direct_vs_transfer Direct access versus transfer - -For resources that you frequently write on CPU and read on GPU, many solutions are possible: - --# Create one copy in video memory using #VMA_MEMORY_USAGE_GPU_ONLY, - second copy in system memory using #VMA_MEMORY_USAGE_CPU_ONLY and submit explicit tranfer each time. --# Create just single copy using #VMA_MEMORY_USAGE_CPU_TO_GPU, map it and fill it on CPU, - read it directly on GPU. --# Create just single copy using #VMA_MEMORY_USAGE_CPU_ONLY, map it and fill it on CPU, - read it directly on GPU. - -Which solution is the most efficient depends on your resource and especially on the GPU. -It is best to measure it and then make the decision. -Some general recommendations: - -- On integrated graphics use (2) or (3) to avoid unnecesary time and memory overhead - related to using a second copy. -- For small resources (e.g. constant buffers) use (2). - Discrete AMD cards have special 256 MiB pool of video memory that is directly mappable. - Even if the resource ends up in system memory, its data may be cached on GPU after first - fetch over PCIe bus. -- For larger resources (e.g. textures), decide between (1) and (2). - You may want to differentiate NVIDIA and AMD, e.g. by looking for memory type that is - both `DEVICE_LOCAL` and `HOST_VISIBLE`. When you find it, use (2), otherwise use (1). - -Similarly, for resources that you frequently write on GPU and read on CPU, multiple -solutions are possible: - --# Create one copy in video memory using #VMA_MEMORY_USAGE_GPU_ONLY, - second copy in system memory using #VMA_MEMORY_USAGE_GPU_TO_CPU and submit explicit tranfer each time. --# Create just single copy using #VMA_MEMORY_USAGE_GPU_TO_CPU, write to it directly on GPU, - map it and read it on CPU. - -You should take some measurements to decide which option is faster in case of your specific -resource. - -If you don't want to specialize your code for specific types of GPUs, yon can still make -an simple optimization for cases when your resource ends up in mappable memory to use it -directly in this case instead of creating CPU-side staging copy. -For details see [Finding out if memory is mappable](@ref memory_mapping_finding_if_memory_mappable). - - -\page configuration Configuration - -Please check "CONFIGURATION SECTION" in the code to find macros that you can define -before each include of this file or change directly in this file to provide -your own implementation of basic facilities like assert, `min()` and `max()` functions, -mutex, atomic etc. -The library uses its own implementation of containers by default, but you can switch to using -STL containers instead. - -\section config_Vulkan_functions Pointers to Vulkan functions - -The library uses Vulkan functions straight from the `vulkan.h` header by default. -If you want to provide your own pointers to these functions, e.g. fetched using -`vkGetInstanceProcAddr()` and `vkGetDeviceProcAddr()`: - --# Define `VMA_STATIC_VULKAN_FUNCTIONS 0`. --# Provide valid pointers through VmaAllocatorCreateInfo::pVulkanFunctions. - -\section custom_memory_allocator Custom host memory allocator - -If you use custom allocator for CPU memory rather than default operator `new` -and `delete` from C++, you can make this library using your allocator as well -by filling optional member VmaAllocatorCreateInfo::pAllocationCallbacks. These -functions will be passed to Vulkan, as well as used by the library itself to -make any CPU-side allocations. - -\section allocation_callbacks Device memory allocation callbacks - -The library makes calls to `vkAllocateMemory()` and `vkFreeMemory()` internally. -You can setup callbacks to be informed about these calls, e.g. for the purpose -of gathering some statistics. To do it, fill optional member -VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. - -\section heap_memory_limit Device heap memory limit - -If you want to test how your program behaves with limited amount of Vulkan device -memory available without switching your graphics card to one that really has -smaller VRAM, you can use a feature of this library intended for this purpose. -To do it, fill optional member VmaAllocatorCreateInfo::pHeapSizeLimit. - - - -\page vk_khr_dedicated_allocation VK_KHR_dedicated_allocation - -VK_KHR_dedicated_allocation is a Vulkan extension which can be used to improve -performance on some GPUs. It augments Vulkan API with possibility to query -driver whether it prefers particular buffer or image to have its own, dedicated -allocation (separate `VkDeviceMemory` block) for better efficiency - to be able -to do some internal optimizations. - -The extension is supported by this library. It will be used automatically when -enabled. To enable it: - -1 . When creating Vulkan device, check if following 2 device extensions are -supported (call `vkEnumerateDeviceExtensionProperties()`). -If yes, enable them (fill `VkDeviceCreateInfo::ppEnabledExtensionNames`). - -- VK_KHR_get_memory_requirements2 -- VK_KHR_dedicated_allocation - -If you enabled these extensions: - -2 . Use #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag when creating -your #VmaAllocator`to inform the library that you enabled required extensions -and you want the library to use them. - -\code -allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - -vmaCreateAllocator(&allocatorInfo, &allocator); -\endcode - -That's all. The extension will be automatically used whenever you create a -buffer using vmaCreateBuffer() or image using vmaCreateImage(). - -When using the extension together with Vulkan Validation Layer, you will receive -warnings like this: - - vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer. - -It is OK, you should just ignore it. It happens because you use function -`vkGetBufferMemoryRequirements2KHR()` instead of standard -`vkGetBufferMemoryRequirements()`, while the validation layer seems to be -unaware of it. - -To learn more about this extension, see: - -- [VK_KHR_dedicated_allocation in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VK_KHR_dedicated_allocation) -- [VK_KHR_dedicated_allocation unofficial manual](http://asawicki.info/articles/VK_KHR_dedicated_allocation.php5) - - - -\page general_considerations General considerations - -\section general_considerations_thread_safety Thread safety - -- The library has no global state, so separate #VmaAllocator objects can be used - independently. - There should be no need to create multiple such objects though - one per `VkDevice` is enough. -- By default, all calls to functions that take #VmaAllocator as first parameter - are safe to call from multiple threads simultaneously because they are - synchronized internally when needed. -- When the allocator is created with #VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT - flag, calls to functions that take such #VmaAllocator object must be - synchronized externally. -- Access to a #VmaAllocation object must be externally synchronized. For example, - you must not call vmaGetAllocationInfo() and vmaMapMemory() from different - threads at the same time if you pass the same #VmaAllocation object to these - functions. - -\section general_considerations_allocation_algorithm Allocation algorithm - -The library uses following algorithm for allocation, in order: - --# Try to find free range of memory in existing blocks. --# If failed, try to create a new block of `VkDeviceMemory`, with preferred block size. --# If failed, try to create such block with size/2, size/4, size/8. --# If failed and #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag was - specified, try to find space in existing blocks, possilby making some other - allocations lost. --# If failed, try to allocate separate `VkDeviceMemory` for this allocation, - just like when you use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. --# If failed, choose other memory type that meets the requirements specified in - VmaAllocationCreateInfo and go to point 1. --# If failed, return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. - -\section general_considerations_features_not_supported Features not supported - -Features deliberately excluded from the scope of this library: - -- Data transfer - issuing commands that transfer data between buffers or images, any usage of - `VkCommandList` or `VkCommandQueue` and related synchronization is responsibility of the user. -- Support for any programming languages other than C/C++. - Bindings to other languages are welcomed as external projects. - -*/ - -#include - -/** \struct VmaAllocator -\brief Represents main object of this library initialized. - -Fill structure VmaAllocatorCreateInfo and call function vmaCreateAllocator() to create it. -Call function vmaDestroyAllocator() to destroy it. - -It is recommended to create just one object of this type per `VkDevice` object, -right after Vulkan is initialized and keep it alive until before Vulkan device is destroyed. -*/ -VK_DEFINE_HANDLE(VmaAllocator) - -/// Callback function called after successful vkAllocateMemory. -typedef void (VKAPI_PTR *PFN_vmaAllocateDeviceMemoryFunction)( - VmaAllocator allocator, - uint32_t memoryType, - VkDeviceMemory memory, - VkDeviceSize size); -/// Callback function called before vkFreeMemory. -typedef void (VKAPI_PTR *PFN_vmaFreeDeviceMemoryFunction)( - VmaAllocator allocator, - uint32_t memoryType, - VkDeviceMemory memory, - VkDeviceSize size); - -/** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. - -Provided for informative purpose, e.g. to gather statistics about number of -allocations or total amount of memory allocated in Vulkan. - -Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. -*/ -typedef struct VmaDeviceMemoryCallbacks { - /// Optional, can be null. - PFN_vmaAllocateDeviceMemoryFunction pfnAllocate; - /// Optional, can be null. - PFN_vmaFreeDeviceMemoryFunction pfnFree; -} VmaDeviceMemoryCallbacks; - -/// Flags for created #VmaAllocator. -typedef enum VmaAllocatorCreateFlagBits { - /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. - - Using this flag may increase performance because internal mutexes are not used. - */ - VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, - /** \brief Enables usage of VK_KHR_dedicated_allocation extension. - - Using this extenion will automatically allocate dedicated blocks of memory for - some buffers and images instead of suballocating place for them out of bigger - memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT - flag) when it is recommended by the driver. It may improve performance on some - GPUs. - - You may set this flag only if you found out that following device extensions are - supported, you enabled them while creating Vulkan device passed as - VmaAllocatorCreateInfo::device, and you want them to be used internally by this - library: - - - VK_KHR_get_memory_requirements2 - - VK_KHR_dedicated_allocation - -When this flag is set, you can experience following warnings reported by Vulkan -validation layer. You can ignore them. - -> vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. - */ - VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, - - VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaAllocatorCreateFlagBits; -typedef VkFlags VmaAllocatorCreateFlags; - -/** \brief Pointers to some Vulkan functions - a subset used by the library. - -Used in VmaAllocatorCreateInfo::pVulkanFunctions. -*/ -typedef struct VmaVulkanFunctions { - PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; - PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; - PFN_vkAllocateMemory vkAllocateMemory; - PFN_vkFreeMemory vkFreeMemory; - PFN_vkMapMemory vkMapMemory; - PFN_vkUnmapMemory vkUnmapMemory; - PFN_vkBindBufferMemory vkBindBufferMemory; - PFN_vkBindImageMemory vkBindImageMemory; - PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; - PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; - PFN_vkCreateBuffer vkCreateBuffer; - PFN_vkDestroyBuffer vkDestroyBuffer; - PFN_vkCreateImage vkCreateImage; - PFN_vkDestroyImage vkDestroyImage; - PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; - PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; -} VmaVulkanFunctions; - -/// Description of a Allocator to be created. -typedef struct VmaAllocatorCreateInfo -{ - /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. - VmaAllocatorCreateFlags flags; - /// Vulkan physical device. - /** It must be valid throughout whole lifetime of created allocator. */ - VkPhysicalDevice physicalDevice; - /// Vulkan device. - /** It must be valid throughout whole lifetime of created allocator. */ - VkDevice device; - /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. - /** Set to 0 to use default, which is currently 256 MiB. */ - VkDeviceSize preferredLargeHeapBlockSize; - /// Custom CPU memory allocation callbacks. Optional. - /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ - const VkAllocationCallbacks* pAllocationCallbacks; - /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. - /** Optional, can be null. */ - const VmaDeviceMemoryCallbacks* pDeviceMemoryCallbacks; - /** \brief Maximum number of additional frames that are in use at the same time as current frame. - - This value is used only when you make allocations with - VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocation cannot become - lost if allocation.lastUseFrameIndex >= allocator.currentFrameIndex - frameInUseCount. - - For example, if you double-buffer your command buffers, so resources used for - rendering in previous frame may still be in use by the GPU at the moment you - allocate resources needed for the current frame, set this value to 1. - - If you want to allow any allocations other than used in the current frame to - become lost, set this value to 0. - */ - uint32_t frameInUseCount; - /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. - - If not NULL, it must be a pointer to an array of - `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on - maximum number of bytes that can be allocated out of particular Vulkan memory - heap. - - Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that - heap. This is also the default in case of `pHeapSizeLimit` = NULL. - - If there is a limit defined for a heap: - - - If user tries to allocate more memory from that heap using this allocator, - the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. - - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the - value of this limit will be reported instead when using vmaGetMemoryProperties(). - - Warning! Using this feature may not be equivalent to installing a GPU with - smaller amount of memory, because graphics driver doesn't necessary fail new - allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is - exceeded. It may return success and just silently migrate some device memory - blocks to system RAM. - */ - const VkDeviceSize* pHeapSizeLimit; - /** \brief Pointers to Vulkan functions. Can be null if you leave define `VMA_STATIC_VULKAN_FUNCTIONS 1`. - - If you leave define `VMA_STATIC_VULKAN_FUNCTIONS 1` in configuration section, - you can pass null as this member, because the library will fetch pointers to - Vulkan functions internally in a static way, like: - - vulkanFunctions.vkAllocateMemory = &vkAllocateMemory; - - Fill this member if you want to provide your own pointers to Vulkan functions, - e.g. fetched using `vkGetInstanceProcAddr()` and `vkGetDeviceProcAddr()`. - */ - const VmaVulkanFunctions* pVulkanFunctions; -} VmaAllocatorCreateInfo; - -/// Creates Allocator object. -VkResult vmaCreateAllocator( - const VmaAllocatorCreateInfo* pCreateInfo, - VmaAllocator* pAllocator); - -/// Destroys allocator object. -void vmaDestroyAllocator( - VmaAllocator allocator); - -/** -PhysicalDeviceProperties are fetched from physicalDevice by the allocator. -You can access it here, without fetching it again on your own. -*/ -void vmaGetPhysicalDeviceProperties( - VmaAllocator allocator, - const VkPhysicalDeviceProperties** ppPhysicalDeviceProperties); - -/** -PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. -You can access it here, without fetching it again on your own. -*/ -void vmaGetMemoryProperties( - VmaAllocator allocator, - const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties); - -/** -\brief Given Memory Type Index, returns Property Flags of this memory type. - -This is just a convenience function. Same information can be obtained using -vmaGetMemoryProperties(). -*/ -void vmaGetMemoryTypeProperties( - VmaAllocator allocator, - uint32_t memoryTypeIndex, - VkMemoryPropertyFlags* pFlags); - -/** \brief Sets index of the current frame. - -This function must be used if you make allocations with -#VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT and -#VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flags to inform the allocator -when a new frame begins. Allocations queried using vmaGetAllocationInfo() cannot -become lost in the current frame. -*/ -void vmaSetCurrentFrameIndex( - VmaAllocator allocator, - uint32_t frameIndex); - -/** \brief Calculated statistics of memory usage in entire allocator. -*/ -typedef struct VmaStatInfo -{ - /// Number of `VkDeviceMemory` Vulkan memory blocks allocated. - uint32_t blockCount; - /// Number of #VmaAllocation allocation objects allocated. - uint32_t allocationCount; - /// Number of free ranges of memory between allocations. - uint32_t unusedRangeCount; - /// Total number of bytes occupied by all allocations. - VkDeviceSize usedBytes; - /// Total number of bytes occupied by unused ranges. - VkDeviceSize unusedBytes; - VkDeviceSize allocationSizeMin, allocationSizeAvg, allocationSizeMax; - VkDeviceSize unusedRangeSizeMin, unusedRangeSizeAvg, unusedRangeSizeMax; -} VmaStatInfo; - -/// General statistics from current state of Allocator. -typedef struct VmaStats -{ - VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES]; - VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS]; - VmaStatInfo total; -} VmaStats; - -/// Retrieves statistics from current state of the Allocator. -void vmaCalculateStats( - VmaAllocator allocator, - VmaStats* pStats); - -#define VMA_STATS_STRING_ENABLED 1 - -#if VMA_STATS_STRING_ENABLED - -/// Builds and returns statistics as string in JSON format. -/** @param[out] ppStatsString Must be freed using vmaFreeStatsString() function. -*/ -void vmaBuildStatsString( - VmaAllocator allocator, - char** ppStatsString, - VkBool32 detailedMap); - -void vmaFreeStatsString( - VmaAllocator allocator, - char* pStatsString); - -#endif // #if VMA_STATS_STRING_ENABLED - -/** \struct VmaPool -\brief Represents custom memory pool - -Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. -Call function vmaDestroyPool() to destroy it. - -For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). -*/ -VK_DEFINE_HANDLE(VmaPool) - -typedef enum VmaMemoryUsage -{ - /** No intended memory usage specified. - Use other members of VmaAllocationCreateInfo to specify your requirements. - */ - VMA_MEMORY_USAGE_UNKNOWN = 0, - /** Memory will be used on device only, so fast access from the device is preferred. - It usually means device-local GPU (video) memory. - No need to be mappable on host. - It is roughly equivalent of `D3D12_HEAP_TYPE_DEFAULT`. - - Usage: - - - Resources written and read by device, e.g. images used as attachments. - - Resources transferred from host once (immutable) or infrequently and read by - device multiple times, e.g. textures to be sampled, vertex buffers, uniform - (constant) buffers, and majority of other types of resources used by device. - - Allocation may still end up in `HOST_VISIBLE` memory on some implementations. - In such case, you are free to map it. - You can use #VMA_ALLOCATION_CREATE_MAPPED_BIT with this usage type. - */ - VMA_MEMORY_USAGE_GPU_ONLY = 1, - /** Memory will be mappable on host. - It usually means CPU (system) memory. - Resources created in this pool may still be accessible to the device, but access to them can be slower. - Guarantees to be `HOST_VISIBLE` and `HOST_COHERENT`. - CPU read may be uncached. - It is roughly equivalent of `D3D12_HEAP_TYPE_UPLOAD`. - - Usage: Staging copy of resources used as transfer source. - */ - VMA_MEMORY_USAGE_CPU_ONLY = 2, - /** - Memory that is both mappable on host (guarantees to be `HOST_VISIBLE`) and preferably fast to access by GPU. - CPU reads may be uncached and very slow. - - Usage: Resources written frequently by host (dynamic), read by device. E.g. textures, vertex buffers, uniform buffers updated every frame or every draw call. - */ - VMA_MEMORY_USAGE_CPU_TO_GPU = 3, - /** Memory mappable on host (guarantees to be `HOST_VISIBLE`) and cached. - It is roughly equivalent of `D3D12_HEAP_TYPE_READBACK`. - - Usage: - - - Resources written by device, read by host - results of some computations, e.g. screen capture, average scene luminance for HDR tone mapping. - - Any resources read or accessed randomly on host, e.g. CPU-side copy of vertex buffer used as source of transfer, but also used for collision detection. - */ - VMA_MEMORY_USAGE_GPU_TO_CPU = 4, - VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF -} VmaMemoryUsage; - -/// Flags to be passed as VmaAllocationCreateInfo::flags. -typedef enum VmaAllocationCreateFlagBits { - /** \brief Set this flag if the allocation should have its own memory block. - - Use it for special, big resources, like fullscreen images used as attachments. - - This flag must also be used for host visible resources that you want to map - simultaneously because otherwise they might end up as regions of the same - `VkDeviceMemory`, while mapping same `VkDeviceMemory` multiple times - simultaneously is illegal. - - You should not use this flag if VmaAllocationCreateInfo::pool is not null. - */ - VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, - - /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. - - If new allocation cannot be placed in any of the existing blocks, allocation - fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. - - You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and - #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. - - If VmaAllocationCreateInfo::pool is not null, this flag is implied and ignored. */ - VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, - /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. - - Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. - - Is it valid to use this flag for allocation made from memory type that is not - `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is - useful if you need an allocation that is efficient to use on GPU - (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that - support it (e.g. Intel GPU). - - You should not use this flag together with #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT. - */ - VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, - /** Allocation created with this flag can become lost as a result of another - allocation with #VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT flag, so you - must check it before use. - - To check if allocation is not lost, call vmaGetAllocationInfo() and check if - VmaAllocationInfo::deviceMemory is not `VK_NULL_HANDLE`. - - For details about supporting lost allocations, see Lost Allocations - chapter of User Guide on Main Page. - - You should not use this flag together with #VMA_ALLOCATION_CREATE_MAPPED_BIT. - */ - VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT = 0x00000008, - /** While creating allocation using this flag, other allocations that were - created with flag #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT can become lost. - - For details about supporting lost allocations, see Lost Allocations - chapter of User Guide on Main Page. - */ - VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT = 0x00000010, - /** Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a - null-terminated string. Instead of copying pointer value, a local copy of the - string is made and stored in allocation's `pUserData`. The string is automatically - freed together with the allocation. It is also used in vmaBuildStatsString(). - */ - VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, - - VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaAllocationCreateFlagBits; -typedef VkFlags VmaAllocationCreateFlags; - -typedef struct VmaAllocationCreateInfo -{ - /// Use #VmaAllocationCreateFlagBits enum. - VmaAllocationCreateFlags flags; - /** \brief Intended usage of memory. - - You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n - If `pool` is not null, this member is ignored. - */ - VmaMemoryUsage usage; - /** \brief Flags that must be set in a Memory Type chosen for an allocation. - - Leave 0 if you specify memory requirements in other way. \n - If `pool` is not null, this member is ignored.*/ - VkMemoryPropertyFlags requiredFlags; - /** \brief Flags that preferably should be set in a memory type chosen for an allocation. - - Set to 0 if no additional flags are prefered. \n - If `pool` is not null, this member is ignored. */ - VkMemoryPropertyFlags preferredFlags; - /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. - - Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if - it meets other requirements specified by this structure, with no further - restrictions on memory type index. \n - If `pool` is not null, this member is ignored. - */ - uint32_t memoryTypeBits; - /** \brief Pool that this allocation should be created in. - - Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: - `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. - */ - VmaPool pool; - /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). - - If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either - null or pointer to a null-terminated string. The string will be then copied to - internal buffer, so it doesn't need to be valid after allocation call. - */ - void* pUserData; -} VmaAllocationCreateInfo; - -/** -\brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. - -This algorithm tries to find a memory type that: - -- Is allowed by memoryTypeBits. -- Contains all the flags from pAllocationCreateInfo->requiredFlags. -- Matches intended usage. -- Has as many flags from pAllocationCreateInfo->preferredFlags as possible. - -\return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result -from this function or any other allocating function probably means that your -device doesn't support any memory type with requested features for the specific -type of resource you want to use it for. Please check parameters of your -resource, like image layout (OPTIMAL versus LINEAR) or mip level count. -*/ -VkResult vmaFindMemoryTypeIndex( - VmaAllocator allocator, - uint32_t memoryTypeBits, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex); - -/** -\brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. - -It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. -It internally creates a temporary, dummy buffer that never has memory bound. -It is just a convenience function, equivalent to calling: - -- `vkCreateBuffer` -- `vkGetBufferMemoryRequirements` -- `vmaFindMemoryTypeIndex` -- `vkDestroyBuffer` -*/ -VkResult vmaFindMemoryTypeIndexForBufferInfo( - VmaAllocator allocator, - const VkBufferCreateInfo* pBufferCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex); - -/** -\brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. - -It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. -It internally creates a temporary, dummy image that never has memory bound. -It is just a convenience function, equivalent to calling: - -- `vkCreateImage` -- `vkGetImageMemoryRequirements` -- `vmaFindMemoryTypeIndex` -- `vkDestroyImage` -*/ -VkResult vmaFindMemoryTypeIndexForImageInfo( - VmaAllocator allocator, - const VkImageCreateInfo* pImageCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex); - -/// Flags to be passed as VmaPoolCreateInfo::flags. -typedef enum VmaPoolCreateFlagBits { - /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. - - This is na optional optimization flag. - - If you always allocate using vmaCreateBuffer(), vmaCreateImage(), - vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator - knows exact type of your allocations so it can handle Buffer-Image Granularity - in the optimal way. - - If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), - exact type of such allocations is not known, so allocator must be conservative - in handling Buffer-Image Granularity, which can lead to suboptimal allocation - (wasted memory). In that case, if you can make sure you always allocate only - buffers and linear images or only optimal images out of this pool, use this flag - to make allocator disregard Buffer-Image Granularity and so make allocations - more optimal. - */ - VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, - - VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaPoolCreateFlagBits; -typedef VkFlags VmaPoolCreateFlags; - -/** \brief Describes parameter of created #VmaPool. -*/ -typedef struct VmaPoolCreateInfo { - /** \brief Vulkan memory type index to allocate this pool from. - */ - uint32_t memoryTypeIndex; - /** \brief Use combination of #VmaPoolCreateFlagBits. - */ - VmaPoolCreateFlags flags; - /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. - - Optional. Leave 0 to use default. - */ - VkDeviceSize blockSize; - /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. - - Set to 0 to have no preallocated blocks and let the pool be completely empty. - */ - size_t minBlockCount; - /** \brief Maximum number of blocks that can be allocated in this pool. Optional. - - Optional. Set to 0 to use `SIZE_MAX`, which means no limit. - - Set to same value as minBlockCount to have fixed amount of memory allocated - throuout whole lifetime of this pool. - */ - size_t maxBlockCount; - /** \brief Maximum number of additional frames that are in use at the same time as current frame. - - This value is used only when you make allocations with - #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocation cannot become - lost if allocation.lastUseFrameIndex >= allocator.currentFrameIndex - frameInUseCount. - - For example, if you double-buffer your command buffers, so resources used for - rendering in previous frame may still be in use by the GPU at the moment you - allocate resources needed for the current frame, set this value to 1. - - If you want to allow any allocations other than used in the current frame to - become lost, set this value to 0. - */ - uint32_t frameInUseCount; -} VmaPoolCreateInfo; - -/** \brief Describes parameter of existing #VmaPool. -*/ -typedef struct VmaPoolStats { - /** \brief Total amount of `VkDeviceMemory` allocated from Vulkan for this pool, in bytes. - */ - VkDeviceSize size; - /** \brief Total number of bytes in the pool not used by any #VmaAllocation. - */ - VkDeviceSize unusedSize; - /** \brief Number of #VmaAllocation objects created from this pool that were not destroyed or lost. - */ - size_t allocationCount; - /** \brief Number of continuous memory ranges in the pool not used by any #VmaAllocation. - */ - size_t unusedRangeCount; - /** \brief Size of the largest continuous free memory region. - - Making a new allocation of that size is not guaranteed to succeed because of - possible additional margin required to respect alignment and buffer/image - granularity. - */ - VkDeviceSize unusedRangeSizeMax; -} VmaPoolStats; - -/** \brief Allocates Vulkan device memory and creates #VmaPool object. - -@param allocator Allocator object. -@param pCreateInfo Parameters of pool to create. -@param[out] pPool Handle to created pool. -*/ -VkResult vmaCreatePool( - VmaAllocator allocator, - const VmaPoolCreateInfo* pCreateInfo, - VmaPool* pPool); - -/** \brief Destroys #VmaPool object and frees Vulkan device memory. -*/ -void vmaDestroyPool( - VmaAllocator allocator, - VmaPool pool); - -/** \brief Retrieves statistics of existing #VmaPool object. - -@param allocator Allocator object. -@param pool Pool object. -@param[out] pPoolStats Statistics of specified pool. -*/ -void vmaGetPoolStats( - VmaAllocator allocator, - VmaPool pool, - VmaPoolStats* pPoolStats); - -/** \brief Marks all allocations in given pool as lost if they are not used in current frame or VmaPoolCreateInfo::frameInUseCount back from now. - -@param allocator Allocator object. -@param pool Pool. -@param[out] pLostAllocationCount Number of allocations marked as lost. Optional - pass null if you don't need this information. -*/ -void vmaMakePoolAllocationsLost( - VmaAllocator allocator, - VmaPool pool, - size_t* pLostAllocationCount); - -/** \struct VmaAllocation -\brief Represents single memory allocation. - -It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type -plus unique offset. - -There are multiple ways to create such object. -You need to fill structure VmaAllocationCreateInfo. -For more information see [Choosing memory type](@ref choosing_memory_type). - -Although the library provides convenience functions that create Vulkan buffer or image, -allocate memory for it and bind them together, -binding of the allocation to a buffer or an image is out of scope of the allocation itself. -Allocation object can exist without buffer/image bound, -binding can be done manually by the user, and destruction of it can be done -independently of destruction of the allocation. - -The object also remembers its size and some other information. -To retrieve this information, use function vmaGetAllocationInfo() and inspect -returned structure VmaAllocationInfo. - -Some kinds allocations can be in lost state. -For more information, see [Lost allocations](@ref lost_allocations). -*/ -VK_DEFINE_HANDLE(VmaAllocation) - -/** \brief Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). -*/ -typedef struct VmaAllocationInfo { - /** \brief Memory type index that this allocation was allocated from. - - It never changes. - */ - uint32_t memoryType; - /** \brief Handle to Vulkan memory object. - - Same memory object can be shared by multiple allocations. - - It can change after call to vmaDefragment() if this allocation is passed to the function, or if allocation is lost. - - If the allocation is lost, it is equal to `VK_NULL_HANDLE`. - */ - VkDeviceMemory deviceMemory; - /** \brief Offset into deviceMemory object to the beginning of this allocation, in bytes. (deviceMemory, offset) pair is unique to this allocation. - - It can change after call to vmaDefragment() if this allocation is passed to the function, or if allocation is lost. - */ - VkDeviceSize offset; - /** \brief Size of this allocation, in bytes. - - It never changes, unless allocation is lost. - */ - VkDeviceSize size; - /** \brief Pointer to the beginning of this allocation as mapped data. - - If the allocation hasn't been mapped using vmaMapMemory() and hasn't been - created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value null. - - It can change after call to vmaMapMemory(), vmaUnmapMemory(). - It can also change after call to vmaDefragment() if this allocation is passed to the function. - */ - void* pMappedData; - /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). - - It can change after call to vmaSetAllocationUserData() for this allocation. - */ - void* pUserData; -} VmaAllocationInfo; - -/** \brief General purpose memory allocation. - -@param[out] pAllocation Handle to allocated memory. -@param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - -You should free the memory using vmaFreeMemory(). - -It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), -vmaCreateBuffer(), vmaCreateImage() instead whenever possible. -*/ -VkResult vmaAllocateMemory( - VmaAllocator allocator, - const VkMemoryRequirements* pVkMemoryRequirements, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); - -/** -@param[out] pAllocation Handle to allocated memory. -@param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - -You should free the memory using vmaFreeMemory(). -*/ -VkResult vmaAllocateMemoryForBuffer( - VmaAllocator allocator, - VkBuffer buffer, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); - -/// Function similar to vmaAllocateMemoryForBuffer(). -VkResult vmaAllocateMemoryForImage( - VmaAllocator allocator, - VkImage image, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); - -/// Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). -void vmaFreeMemory( - VmaAllocator allocator, - VmaAllocation allocation); - -/** \brief Returns current information about specified allocation and atomically marks it as used in current frame. - -Current paramters of given allocation are returned in `pAllocationInfo`. - -This function also atomically "touches" allocation - marks it as used in current frame, -just like vmaTouchAllocation(). -If the allocation is in lost state, `pAllocationInfo->deviceMemory == VK_NULL_HANDLE`. - -Although this function uses atomics and doesn't lock any mutex, so it should be quite efficient, -you can avoid calling it too often. - -- You can retrieve same VmaAllocationInfo structure while creating your resource, from function - vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change - (e.g. due to defragmentation or allocation becoming lost). -- If you just want to check if allocation is not lost, vmaTouchAllocation() will work faster. -*/ -void vmaGetAllocationInfo( - VmaAllocator allocator, - VmaAllocation allocation, - VmaAllocationInfo* pAllocationInfo); - -/** \brief Returns `VK_TRUE` if allocation is not lost and atomically marks it as used in current frame. - -If the allocation has been created with #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag, -this function returns `VK_TRUE` if it's not in lost state, so it can still be used. -It then also atomically "touches" the allocation - marks it as used in current frame, -so that you can be sure it won't become lost in current frame or next `frameInUseCount` frames. - -If the allocation is in lost state, the function returns `VK_FALSE`. -Memory of such allocation, as well as buffer or image bound to it, should not be used. -Lost allocation and the buffer/image still need to be destroyed. - -If the allocation has been created without #VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag, -this function always returns `VK_TRUE`. -*/ -VkBool32 vmaTouchAllocation( - VmaAllocator allocator, - VmaAllocation allocation); - -/** \brief Sets pUserData in given allocation to new value. - -If the allocation was created with VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT, -pUserData must be either null, or pointer to a null-terminated string. The function -makes local copy of the string and sets it as allocation's `pUserData`. String -passed as pUserData doesn't need to be valid for whole lifetime of the allocation - -you can free it after this call. String previously pointed by allocation's -pUserData is freed from memory. - -If the flag was not used, the value of pointer `pUserData` is just copied to -allocation's `pUserData`. It is opaque, so you can use it however you want - e.g. -as a pointer, ordinal number or some handle to you own data. -*/ -void vmaSetAllocationUserData( - VmaAllocator allocator, - VmaAllocation allocation, - void* pUserData); - -/** \brief Creates new allocation that is in lost state from the beginning. - -It can be useful if you need a dummy, non-null allocation. - -You still need to destroy created object using vmaFreeMemory(). - -Returned allocation is not tied to any specific memory pool or memory type and -not bound to any image or buffer. It has size = 0. It cannot be turned into -a real, non-empty allocation. -*/ -void vmaCreateLostAllocation( - VmaAllocator allocator, - VmaAllocation* pAllocation); - -/** \brief Maps memory represented by given allocation and returns pointer to it. - -Maps memory represented by given allocation to make it accessible to CPU code. -When succeeded, `*ppData` contains pointer to first byte of this memory. -If the allocation is part of bigger `VkDeviceMemory` block, the pointer is -correctly offseted to the beginning of region assigned to this particular -allocation. - -Mapping is internally reference-counted and synchronized, so despite raw Vulkan -function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` -multiple times simultaneously, it is safe to call this function on allocations -assigned to the same memory block. Actual Vulkan memory will be mapped on first -mapping and unmapped on last unmapping. - -If the function succeeded, you must call vmaUnmapMemory() to unmap the -allocation when mapping is no longer needed or before freeing the allocation, at -the latest. - -It also safe to call this function multiple times on the same allocation. You -must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). - -It is also safe to call this function on allocation created with -#VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. -You must still call vmaUnmapMemory() same number of times as you called -vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the -"0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. - -This function fails when used on allocation made in memory type that is not -`HOST_VISIBLE`. - -This function always fails when called for allocation that was created with -#VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocations cannot be -mapped. -*/ -VkResult vmaMapMemory( - VmaAllocator allocator, - VmaAllocation allocation, - void** ppData); - -/** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). - -For details, see description of vmaMapMemory(). -*/ -void vmaUnmapMemory( - VmaAllocator allocator, - VmaAllocation allocation); - -/** \brief Optional configuration parameters to be passed to function vmaDefragment(). */ -typedef struct VmaDefragmentationInfo { - /** \brief Maximum total numbers of bytes that can be copied while moving allocations to different places. - - Default is `VK_WHOLE_SIZE`, which means no limit. - */ - VkDeviceSize maxBytesToMove; - /** \brief Maximum number of allocations that can be moved to different place. - - Default is `UINT32_MAX`, which means no limit. - */ - uint32_t maxAllocationsToMove; -} VmaDefragmentationInfo; - -/** \brief Statistics returned by function vmaDefragment(). */ -typedef struct VmaDefragmentationStats { - /// Total number of bytes that have been copied while moving allocations to different places. - VkDeviceSize bytesMoved; - /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects. - VkDeviceSize bytesFreed; - /// Number of allocations that have been moved to different places. - uint32_t allocationsMoved; - /// Number of empty `VkDeviceMemory` objects that have been released to the system. - uint32_t deviceMemoryBlocksFreed; -} VmaDefragmentationStats; - -/** \brief Compacts memory by moving allocations. - -@param pAllocations Array of allocations that can be moved during this compation. -@param allocationCount Number of elements in pAllocations and pAllocationsChanged arrays. -@param[out] pAllocationsChanged Array of boolean values that will indicate whether matching allocation in pAllocations array has been moved. This parameter is optional. Pass null if you don't need this information. -@param pDefragmentationInfo Configuration parameters. Optional - pass null to use default values. -@param[out] pDefragmentationStats Statistics returned by the function. Optional - pass null if you don't need this information. -@return VK_SUCCESS if completed, VK_INCOMPLETE if succeeded but didn't make all possible optimizations because limits specified in pDefragmentationInfo have been reached, negative error code in case of error. - -This function works by moving allocations to different places (different -`VkDeviceMemory` objects and/or different offsets) in order to optimize memory -usage. Only allocations that are in pAllocations array can be moved. All other -allocations are considered nonmovable in this call. Basic rules: - -- Only allocations made in memory types that have - `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag can be compacted. You may pass other - allocations but it makes no sense - these will never be moved. -- You may pass allocations made with #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT but - it makes no sense - they will never be moved. -- Both allocations made with or without #VMA_ALLOCATION_CREATE_MAPPED_BIT - flag can be compacted. If not persistently mapped, memory will be mapped - temporarily inside this function if needed. -- You must not pass same #VmaAllocation object multiple times in pAllocations array. - -The function also frees empty `VkDeviceMemory` blocks. - -After allocation has been moved, its VmaAllocationInfo::deviceMemory and/or -VmaAllocationInfo::offset changes. You must query them again using -vmaGetAllocationInfo() if you need them. - -If an allocation has been moved, data in memory is copied to new place -automatically, but if it was bound to a buffer or an image, you must destroy -that object yourself, create new one and bind it to the new memory pointed by -the allocation. You must use `vkDestroyBuffer()`, `vkDestroyImage()`, -`vkCreateBuffer()`, `vkCreateImage()` for that purpose and NOT vmaDestroyBuffer(), -vmaDestroyImage(), vmaCreateBuffer(), vmaCreateImage()! Example: - -\code -VkDevice device = ...; -VmaAllocator allocator = ...; -std::vector buffers = ...; -std::vector allocations = ...; - -std::vector allocationsChanged(allocations.size()); -vmaDefragment(allocator, allocations.data(), allocations.size(), allocationsChanged.data(), nullptr, nullptr); - -for(size_t i = 0; i < allocations.size(); ++i) -{ - if(allocationsChanged[i]) - { - VmaAllocationInfo allocInfo; - vmaGetAllocationInfo(allocator, allocations[i], &allocInfo); - - vkDestroyBuffer(device, buffers[i], nullptr); - - VkBufferCreateInfo bufferInfo = ...; - vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]); - - // You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning. - - vkBindBufferMemory(device, buffers[i], allocInfo.deviceMemory, allocInfo.offset); - } -} -\endcode - -Note: Please don't expect memory to be fully compacted after this call. -Algorithms inside are based on some heuristics that try to maximize number of Vulkan -memory blocks to make totally empty to release them, as well as to maximimze continuous -empty space inside remaining blocks, while minimizing the number and size of data that -needs to be moved. Some fragmentation still remains after this call. This is normal. - -Warning: This function is not 100% correct according to Vulkan specification. Use it -at your own risk. That's because Vulkan doesn't guarantee that memory -requirements (size and alignment) for a new buffer or image are consistent. They -may be different even for subsequent calls with the same parameters. It really -does happen on some platforms, especially with images. - -Warning: This function may be time-consuming, so you shouldn't call it too often -(like every frame or after every resource creation/destruction). -You can call it on special occasions (like when reloading a game level or -when you just destroyed a lot of objects). -*/ -VkResult vmaDefragment( - VmaAllocator allocator, - VmaAllocation* pAllocations, - size_t allocationCount, - VkBool32* pAllocationsChanged, - const VmaDefragmentationInfo *pDefragmentationInfo, - VmaDefragmentationStats* pDefragmentationStats); - -/** \brief Binds buffer to allocation. - -Binds specified buffer to region of memory represented by specified allocation. -Gets `VkDeviceMemory` handle and offset from the allocation. -If you want to create a buffer, allocate memory for it and bind them together separately, -you should use this function for binding instead of standard `vkBindBufferMemory()`, -because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple -allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously -(which is illegal in Vulkan). - -It is recommended to use function vmaCreateBuffer() instead of this one. -*/ -VkResult vmaBindBufferMemory( - VmaAllocator allocator, - VmaAllocation allocation, - VkBuffer buffer); - -/** \brief Binds image to allocation. - -Binds specified image to region of memory represented by specified allocation. -Gets `VkDeviceMemory` handle and offset from the allocation. -If you want to create an image, allocate memory for it and bind them together separately, -you should use this function for binding instead of standard `vkBindImageMemory()`, -because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple -allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously -(which is illegal in Vulkan). - -It is recommended to use function vmaCreateImage() instead of this one. -*/ -VkResult vmaBindImageMemory( - VmaAllocator allocator, - VmaAllocation allocation, - VkImage image); - -/** -@param[out] pBuffer Buffer that was created. -@param[out] pAllocation Allocation that was created. -@param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - -This function automatically: - --# Creates buffer. --# Allocates appropriate memory for it. --# Binds the buffer with the memory. - -If any of these operations fail, buffer and allocation are not created, -returned value is negative error code, *pBuffer and *pAllocation are null. - -If the function succeeded, you must destroy both buffer and allocation when you -no longer need them using either convenience function vmaDestroyBuffer() or -separately, using `vkDestroyBuffer()` and vmaFreeMemory(). - -If VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, -VK_KHR_dedicated_allocation extension is used internally to query driver whether -it requires or prefers the new buffer to have dedicated allocation. If yes, -and if dedicated allocation is possible (VmaAllocationCreateInfo::pool is null -and VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated -allocation for this buffer, just like when using -VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. -*/ -VkResult vmaCreateBuffer( - VmaAllocator allocator, - const VkBufferCreateInfo* pBufferCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkBuffer* pBuffer, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); - -/** \brief Destroys Vulkan buffer and frees allocated memory. - -This is just a convenience function equivalent to: - -\code -vkDestroyBuffer(device, buffer, allocationCallbacks); -vmaFreeMemory(allocator, allocation); -\endcode - -It it safe to pass null as buffer and/or allocation. -*/ -void vmaDestroyBuffer( - VmaAllocator allocator, - VkBuffer buffer, - VmaAllocation allocation); - -/// Function similar to vmaCreateBuffer(). -VkResult vmaCreateImage( - VmaAllocator allocator, - const VkImageCreateInfo* pImageCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkImage* pImage, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo); - -/** \brief Destroys Vulkan image and frees allocated memory. - -This is just a convenience function equivalent to: - -\code -vkDestroyImage(device, image, allocationCallbacks); -vmaFreeMemory(allocator, allocation); -\endcode - -It it safe to pass null as image and/or allocation. -*/ -void vmaDestroyImage( - VmaAllocator allocator, - VkImage image, - VmaAllocation allocation); - -#ifdef __cplusplus -} -#endif - -#endif // AMD_VULKAN_MEMORY_ALLOCATOR_H - -// For Visual Studio IntelliSense. -#ifdef __INTELLISENSE__ -#define VMA_IMPLEMENTATION -#endif - -#ifdef VMA_IMPLEMENTATION -#undef VMA_IMPLEMENTATION - -#include -#include -#include - -/******************************************************************************* -CONFIGURATION SECTION - -Define some of these macros before each #include of this header or change them -here if you need other then default behavior depending on your environment. -*/ - -/* -Define this macro to 1 to make the library fetch pointers to Vulkan functions -internally, like: - - vulkanFunctions.vkAllocateMemory = &vkAllocateMemory; - -Define to 0 if you are going to provide you own pointers to Vulkan functions via -VmaAllocatorCreateInfo::pVulkanFunctions. -*/ -#if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES) -#define VMA_STATIC_VULKAN_FUNCTIONS 1 -#endif - -// Define this macro to 1 to make the library use STL containers instead of its own implementation. -//#define VMA_USE_STL_CONTAINERS 1 - -/* Set this macro to 1 to make the library including and using STL containers: -std::pair, std::vector, std::list, std::unordered_map. - -Set it to 0 or undefined to make the library using its own implementation of -the containers. -*/ -#if VMA_USE_STL_CONTAINERS - #define VMA_USE_STL_VECTOR 1 - #define VMA_USE_STL_UNORDERED_MAP 1 - #define VMA_USE_STL_LIST 1 -#endif - -#if VMA_USE_STL_VECTOR - #include -#endif - -#if VMA_USE_STL_UNORDERED_MAP - #include -#endif - -#if VMA_USE_STL_LIST - #include -#endif - -/* -Following headers are used in this CONFIGURATION section only, so feel free to -remove them if not needed. -*/ -#include // for assert -#include // for min, max -#include // for std::mutex -#include // for std::atomic - -#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) - #include // for aligned_alloc() -#endif - -#ifndef VMA_NULL - // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0. - #define VMA_NULL nullptr -#endif - -#ifndef __MINGW32__ -#if defined(__APPLE__) || defined(__ANDROID__) || defined(__OpenBSD__) || (defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC)) -#include -void *aligned_alloc(size_t alignment, size_t size) -{ - // alignment must be >= sizeof(void*) - if(alignment < sizeof(void*)) - { - alignment = sizeof(void*); - } - - void *pointer; - if(posix_memalign(&pointer, alignment, size) == 0) - return pointer; - return VMA_NULL; -} -#endif -#endif - -// Normal assert to check for programmer's errors, especially in Debug configuration. -#ifndef VMA_ASSERT - #ifdef _DEBUG - #define VMA_ASSERT(expr) assert(expr) - #else - #define VMA_ASSERT(expr) - #endif -#endif - -// Assert that will be called very often, like inside data structures e.g. operator[]. -// Making it non-empty can make program slow. -#ifndef VMA_HEAVY_ASSERT - #ifdef _DEBUG - #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) - #else - #define VMA_HEAVY_ASSERT(expr) - #endif -#endif - -#ifndef VMA_ALIGN_OF - #define VMA_ALIGN_OF(type) (__alignof(type)) -#endif - -#ifndef VMA_SYSTEM_ALIGNED_MALLOC - #if defined(_WIN32) - #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (_aligned_malloc((size), (alignment))) - #else - #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (aligned_alloc((alignment), (size) )) - #endif -#endif - -#ifndef VMA_SYSTEM_FREE - #if defined(_WIN32) - #define VMA_SYSTEM_FREE(ptr) _aligned_free(ptr) - #else - #define VMA_SYSTEM_FREE(ptr) free(ptr) - #endif -#endif - -#ifndef VMA_MIN - #define VMA_MIN(v1, v2) (std::min((v1), (v2))) -#endif - -#ifndef VMA_MAX - #define VMA_MAX(v1, v2) (std::max((v1), (v2))) -#endif - -#ifndef VMA_SWAP - #define VMA_SWAP(v1, v2) std::swap((v1), (v2)) -#endif - -#ifndef VMA_SORT - #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) -#endif - -#ifndef VMA_DEBUG_LOG - #define VMA_DEBUG_LOG(format, ...) - /* - #define VMA_DEBUG_LOG(format, ...) do { \ - printf(format, __VA_ARGS__); \ - printf("\n"); \ - } while(false) - */ -#endif - -// Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString. -#if VMA_STATS_STRING_ENABLED - static inline void VmaUint32ToStr(char* outStr, size_t strLen, uint32_t num) - { - snprintf(outStr, strLen, "%u", static_cast(num)); - } - static inline void VmaUint64ToStr(char* outStr, size_t strLen, uint64_t num) - { - snprintf(outStr, strLen, "%llu", static_cast(num)); - } - static inline void VmaPtrToStr(char* outStr, size_t strLen, const void* ptr) - { - snprintf(outStr, strLen, "%p", ptr); - } -#endif - -#ifndef VMA_MUTEX - class VmaMutex - { - public: - VmaMutex() { } - ~VmaMutex() { } - void Lock() { m_Mutex.lock(); } - void Unlock() { m_Mutex.unlock(); } - private: - std::mutex m_Mutex; - }; - #define VMA_MUTEX VmaMutex -#endif - -/* -If providing your own implementation, you need to implement a subset of std::atomic: - -- Constructor(uint32_t desired) -- uint32_t load() const -- void store(uint32_t desired) -- bool compare_exchange_weak(uint32_t& expected, uint32_t desired) -*/ -#ifndef VMA_ATOMIC_UINT32 - #define VMA_ATOMIC_UINT32 std::atomic -#endif - -#ifndef VMA_BEST_FIT - /** - Main parameter for function assessing how good is a free suballocation for a new - allocation request. - - - Set to 1 to use Best-Fit algorithm - prefer smaller blocks, as close to the - size of requested allocations as possible. - - Set to 0 to use Worst-Fit algorithm - prefer larger blocks, as large as - possible. - - Experiments in special testing environment showed that Best-Fit algorithm is - better. - */ - #define VMA_BEST_FIT (1) -#endif - -#ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY - /** - Every allocation will have its own memory block. - Define to 1 for debugging purposes only. - */ - #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) -#endif - -#ifndef VMA_DEBUG_ALIGNMENT - /** - Minimum alignment of all suballocations, in bytes. - Set to more than 1 for debugging purposes only. Must be power of two. - */ - #define VMA_DEBUG_ALIGNMENT (1) -#endif - -#ifndef VMA_DEBUG_MARGIN - /** - Minimum margin between suballocations, in bytes. - Set nonzero for debugging purposes only. - */ - #define VMA_DEBUG_MARGIN (0) -#endif - -#ifndef VMA_DEBUG_GLOBAL_MUTEX - /** - Set this to 1 for debugging purposes only, to enable single mutex protecting all - entry calls to the library. Can be useful for debugging multithreading issues. - */ - #define VMA_DEBUG_GLOBAL_MUTEX (0) -#endif - -#ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY - /** - Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity. - Set to more than 1 for debugging purposes only. Must be power of two. - */ - #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) -#endif - -#ifndef VMA_SMALL_HEAP_MAX_SIZE - /// Maximum size of a memory heap in Vulkan to consider it "small". - #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) -#endif - -#ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE - /// Default size of a block allocated as single VkDeviceMemory from a "large" heap. - #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) -#endif - -static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX; - -/******************************************************************************* -END OF CONFIGURATION -*/ - -static VkAllocationCallbacks VmaEmptyAllocationCallbacks = { - VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL }; - -// Returns number of bits set to 1 in (v). -static inline uint32_t VmaCountBitsSet(uint32_t v) -{ - uint32_t c = v - ((v >> 1) & 0x55555555); - c = ((c >> 2) & 0x33333333) + (c & 0x33333333); - c = ((c >> 4) + c) & 0x0F0F0F0F; - c = ((c >> 8) + c) & 0x00FF00FF; - c = ((c >> 16) + c) & 0x0000FFFF; - return c; -} - -// Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16. -// Use types like uint32_t, uint64_t as T. -template -static inline T VmaAlignUp(T val, T align) -{ - return (val + align - 1) / align * align; -} - -// Division with mathematical rounding to nearest number. -template -inline T VmaRoundDiv(T x, T y) -{ - return (x + (y / (T)2)) / y; -} - -#ifndef VMA_SORT - -template -Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp) -{ - Iterator centerValue = end; --centerValue; - Iterator insertIndex = beg; - for(Iterator memTypeIndex = beg; memTypeIndex < centerValue; ++memTypeIndex) - { - if(cmp(*memTypeIndex, *centerValue)) - { - if(insertIndex != memTypeIndex) - { - VMA_SWAP(*memTypeIndex, *insertIndex); - } - ++insertIndex; - } - } - if(insertIndex != centerValue) - { - VMA_SWAP(*insertIndex, *centerValue); - } - return insertIndex; -} - -template -void VmaQuickSort(Iterator beg, Iterator end, Compare cmp) -{ - if(beg < end) - { - Iterator it = VmaQuickSortPartition(beg, end, cmp); - VmaQuickSort(beg, it, cmp); - VmaQuickSort(it + 1, end, cmp); - } -} - -#define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp) - -#endif // #ifndef VMA_SORT - -/* -Returns true if two memory blocks occupy overlapping pages. -ResourceA must be in less memory offset than ResourceB. - -Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)" -chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity". -*/ -static inline bool VmaBlocksOnSamePage( - VkDeviceSize resourceAOffset, - VkDeviceSize resourceASize, - VkDeviceSize resourceBOffset, - VkDeviceSize pageSize) -{ - VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0); - VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1; - VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1); - VkDeviceSize resourceBStart = resourceBOffset; - VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1); - return resourceAEndPage == resourceBStartPage; -} - -enum VmaSuballocationType -{ - VMA_SUBALLOCATION_TYPE_FREE = 0, - VMA_SUBALLOCATION_TYPE_UNKNOWN = 1, - VMA_SUBALLOCATION_TYPE_BUFFER = 2, - VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3, - VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4, - VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5, - VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF -}; - -/* -Returns true if given suballocation types could conflict and must respect -VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer -or linear image and another one is optimal image. If type is unknown, behave -conservatively. -*/ -static inline bool VmaIsBufferImageGranularityConflict( - VmaSuballocationType suballocType1, - VmaSuballocationType suballocType2) -{ - if(suballocType1 > suballocType2) - { - VMA_SWAP(suballocType1, suballocType2); - } - - switch(suballocType1) - { - case VMA_SUBALLOCATION_TYPE_FREE: - return false; - case VMA_SUBALLOCATION_TYPE_UNKNOWN: - return true; - case VMA_SUBALLOCATION_TYPE_BUFFER: - return - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; - case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN: - return - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN || - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR || - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; - case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR: - return - suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL; - case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL: - return false; - default: - VMA_ASSERT(0); - return true; - } -} - -// Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope). -struct VmaMutexLock -{ -public: - VmaMutexLock(VMA_MUTEX& mutex, bool useMutex) : - m_pMutex(useMutex ? &mutex : VMA_NULL) - { - if(m_pMutex) - { - m_pMutex->Lock(); - } - } - - ~VmaMutexLock() - { - if(m_pMutex) - { - m_pMutex->Unlock(); - } - } - -private: - VMA_MUTEX* m_pMutex; -}; - -#if VMA_DEBUG_GLOBAL_MUTEX - static VMA_MUTEX gDebugGlobalMutex; - #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); -#else - #define VMA_DEBUG_GLOBAL_MUTEX_LOCK -#endif - -// Minimum size of a free suballocation to register it in the free suballocation collection. -static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16; - -/* -Performs binary search and returns iterator to first element that is greater or -equal to (key), according to comparison (cmp). - -Cmp should return true if first argument is less than second argument. - -Returned value is the found element, if present in the collection or place where -new element with value (key) should be inserted. -*/ -template -static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, CmpT cmp) -{ - size_t down = 0, up = (end - beg); - while(down < up) - { - const size_t mid = (down + up) / 2; - if(cmp(*(beg+mid), key)) - { - down = mid + 1; - } - else - { - up = mid; - } - } - return beg + down; -} - -//////////////////////////////////////////////////////////////////////////////// -// Memory allocation - -static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment) -{ - if((pAllocationCallbacks != VMA_NULL) && - (pAllocationCallbacks->pfnAllocation != VMA_NULL)) - { - return (*pAllocationCallbacks->pfnAllocation)( - pAllocationCallbacks->pUserData, - size, - alignment, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - } - else - { - return VMA_SYSTEM_ALIGNED_MALLOC(size, alignment); - } -} - -static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr) -{ - if((pAllocationCallbacks != VMA_NULL) && - (pAllocationCallbacks->pfnFree != VMA_NULL)) - { - (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr); - } - else - { - VMA_SYSTEM_FREE(ptr); - } -} - -template -static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks) -{ - return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T)); -} - -template -static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count) -{ - return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T)); -} - -#define vma_new(allocator, type) new(VmaAllocate(allocator))(type) - -#define vma_new_array(allocator, type, count) new(VmaAllocateArray((allocator), (count)))(type) - -template -static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr) -{ - ptr->~T(); - VmaFree(pAllocationCallbacks, ptr); -} - -template -static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count) -{ - if(ptr != VMA_NULL) - { - for(size_t i = count; i--; ) - { - ptr[i].~T(); - } - VmaFree(pAllocationCallbacks, ptr); - } -} - -// STL-compatible allocator. -template -class VmaStlAllocator -{ -public: - const VkAllocationCallbacks* const m_pCallbacks; - typedef T value_type; - - VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { } - template VmaStlAllocator(const VmaStlAllocator& src) : m_pCallbacks(src.m_pCallbacks) { } - - T* allocate(size_t n) { return VmaAllocateArray(m_pCallbacks, n); } - void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); } - - template - bool operator==(const VmaStlAllocator& rhs) const - { - return m_pCallbacks == rhs.m_pCallbacks; - } - template - bool operator!=(const VmaStlAllocator& rhs) const - { - return m_pCallbacks != rhs.m_pCallbacks; - } - - VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete; -}; - -#if VMA_USE_STL_VECTOR - -#define VmaVector std::vector - -template -static void VmaVectorInsert(std::vector& vec, size_t index, const T& item) -{ - vec.insert(vec.begin() + index, item); -} - -template -static void VmaVectorRemove(std::vector& vec, size_t index) -{ - vec.erase(vec.begin() + index); -} - -#else // #if VMA_USE_STL_VECTOR - -/* Class with interface compatible with subset of std::vector. -T must be POD because constructors and destructors are not called and memcpy is -used for these objects. */ -template -class VmaVector -{ -public: - typedef T value_type; - - VmaVector(const AllocatorT& allocator) : - m_Allocator(allocator), - m_pArray(VMA_NULL), - m_Count(0), - m_Capacity(0) - { - } - - VmaVector(size_t count, const AllocatorT& allocator) : - m_Allocator(allocator), - m_pArray(count ? (T*)VmaAllocateArray(allocator.m_pCallbacks, count) : VMA_NULL), - m_Count(count), - m_Capacity(count) - { - } - - VmaVector(const VmaVector& src) : - m_Allocator(src.m_Allocator), - m_pArray(src.m_Count ? (T*)VmaAllocateArray(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL), - m_Count(src.m_Count), - m_Capacity(src.m_Count) - { - if(m_Count != 0) - { - memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T)); - } - } - - ~VmaVector() - { - VmaFree(m_Allocator.m_pCallbacks, m_pArray); - } - - VmaVector& operator=(const VmaVector& rhs) - { - if(&rhs != this) - { - resize(rhs.m_Count); - if(m_Count != 0) - { - memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T)); - } - } - return *this; - } - - bool empty() const { return m_Count == 0; } - size_t size() const { return m_Count; } - T* data() { return m_pArray; } - const T* data() const { return m_pArray; } - - T& operator[](size_t index) - { - VMA_HEAVY_ASSERT(index < m_Count); - return m_pArray[index]; - } - const T& operator[](size_t index) const - { - VMA_HEAVY_ASSERT(index < m_Count); - return m_pArray[index]; - } - - T& front() - { - VMA_HEAVY_ASSERT(m_Count > 0); - return m_pArray[0]; - } - const T& front() const - { - VMA_HEAVY_ASSERT(m_Count > 0); - return m_pArray[0]; - } - T& back() - { - VMA_HEAVY_ASSERT(m_Count > 0); - return m_pArray[m_Count - 1]; - } - const T& back() const - { - VMA_HEAVY_ASSERT(m_Count > 0); - return m_pArray[m_Count - 1]; - } - - void reserve(size_t newCapacity, bool freeMemory = false) - { - newCapacity = VMA_MAX(newCapacity, m_Count); - - if((newCapacity < m_Capacity) && !freeMemory) - { - newCapacity = m_Capacity; - } - - if(newCapacity != m_Capacity) - { - T* const newArray = newCapacity ? VmaAllocateArray(m_Allocator, newCapacity) : VMA_NULL; - if(m_Count != 0) - { - memcpy(newArray, m_pArray, m_Count * sizeof(T)); - } - VmaFree(m_Allocator.m_pCallbacks, m_pArray); - m_Capacity = newCapacity; - m_pArray = newArray; - } - } - - void resize(size_t newCount, bool freeMemory = false) - { - size_t newCapacity = m_Capacity; - if(newCount > m_Capacity) - { - newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8)); - } - else if(freeMemory) - { - newCapacity = newCount; - } - - if(newCapacity != m_Capacity) - { - T* const newArray = newCapacity ? VmaAllocateArray(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL; - const size_t elementsToCopy = VMA_MIN(m_Count, newCount); - if(elementsToCopy != 0) - { - memcpy(newArray, m_pArray, elementsToCopy * sizeof(T)); - } - VmaFree(m_Allocator.m_pCallbacks, m_pArray); - m_Capacity = newCapacity; - m_pArray = newArray; - } - - m_Count = newCount; - } - - void clear(bool freeMemory = false) - { - resize(0, freeMemory); - } - - void insert(size_t index, const T& src) - { - VMA_HEAVY_ASSERT(index <= m_Count); - const size_t oldCount = size(); - resize(oldCount + 1); - if(index < oldCount) - { - memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T)); - } - m_pArray[index] = src; - } - - void remove(size_t index) - { - VMA_HEAVY_ASSERT(index < m_Count); - const size_t oldCount = size(); - if(index < oldCount - 1) - { - memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T)); - } - resize(oldCount - 1); - } - - void push_back(const T& src) - { - const size_t newIndex = size(); - resize(newIndex + 1); - m_pArray[newIndex] = src; - } - - void pop_back() - { - VMA_HEAVY_ASSERT(m_Count > 0); - resize(size() - 1); - } - - void push_front(const T& src) - { - insert(0, src); - } - - void pop_front() - { - VMA_HEAVY_ASSERT(m_Count > 0); - remove(0); - } - - typedef T* iterator; - - iterator begin() { return m_pArray; } - iterator end() { return m_pArray + m_Count; } - -private: - AllocatorT m_Allocator; - T* m_pArray; - size_t m_Count; - size_t m_Capacity; -}; - -template -static void VmaVectorInsert(VmaVector& vec, size_t index, const T& item) -{ - vec.insert(index, item); -} - -template -static void VmaVectorRemove(VmaVector& vec, size_t index) -{ - vec.remove(index); -} - -#endif // #if VMA_USE_STL_VECTOR - -template -size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value) -{ - const size_t indexToInsert = VmaBinaryFindFirstNotLess( - vector.data(), - vector.data() + vector.size(), - value, - CmpLess()) - vector.data(); - VmaVectorInsert(vector, indexToInsert, value); - return indexToInsert; -} - -template -bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value) -{ - CmpLess comparator; - typename VectorT::iterator it = VmaBinaryFindFirstNotLess( - vector.begin(), - vector.end(), - value, - comparator); - if((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it)) - { - size_t indexToRemove = it - vector.begin(); - VmaVectorRemove(vector, indexToRemove); - return true; - } - return false; -} - -template -size_t VmaVectorFindSorted(const VectorT& vector, const typename VectorT::value_type& value) -{ - CmpLess comparator; - typename VectorT::iterator it = VmaBinaryFindFirstNotLess( - vector.data(), - vector.data() + vector.size(), - value, - comparator); - if(it != vector.size() && !comparator(*it, value) && !comparator(value, *it)) - { - return it - vector.begin(); - } - else - { - return vector.size(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// class VmaPoolAllocator - -/* -Allocator for objects of type T using a list of arrays (pools) to speed up -allocation. Number of elements that can be allocated is not bounded because -allocator can create multiple blocks. -*/ -template -class VmaPoolAllocator -{ -public: - VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, size_t itemsPerBlock); - ~VmaPoolAllocator(); - void Clear(); - T* Alloc(); - void Free(T* ptr); - -private: - union Item - { - uint32_t NextFreeIndex; - T Value; - }; - - struct ItemBlock - { - Item* pItems; - uint32_t FirstFreeIndex; - }; - - const VkAllocationCallbacks* m_pAllocationCallbacks; - size_t m_ItemsPerBlock; - VmaVector< ItemBlock, VmaStlAllocator > m_ItemBlocks; - - ItemBlock& CreateNewBlock(); -}; - -template -VmaPoolAllocator::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, size_t itemsPerBlock) : - m_pAllocationCallbacks(pAllocationCallbacks), - m_ItemsPerBlock(itemsPerBlock), - m_ItemBlocks(VmaStlAllocator(pAllocationCallbacks)) -{ - VMA_ASSERT(itemsPerBlock > 0); -} - -template -VmaPoolAllocator::~VmaPoolAllocator() -{ - Clear(); -} - -template -void VmaPoolAllocator::Clear() -{ - for(size_t i = m_ItemBlocks.size(); i--; ) - vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemsPerBlock); - m_ItemBlocks.clear(); -} - -template -T* VmaPoolAllocator::Alloc() -{ - for(size_t i = m_ItemBlocks.size(); i--; ) - { - ItemBlock& block = m_ItemBlocks[i]; - // This block has some free items: Use first one. - if(block.FirstFreeIndex != UINT32_MAX) - { - Item* const pItem = &block.pItems[block.FirstFreeIndex]; - block.FirstFreeIndex = pItem->NextFreeIndex; - return &pItem->Value; - } - } - - // No block has free item: Create new one and use it. - ItemBlock& newBlock = CreateNewBlock(); - Item* const pItem = &newBlock.pItems[0]; - newBlock.FirstFreeIndex = pItem->NextFreeIndex; - return &pItem->Value; -} - -template -void VmaPoolAllocator::Free(T* ptr) -{ - // Search all memory blocks to find ptr. - for(size_t i = 0; i < m_ItemBlocks.size(); ++i) - { - ItemBlock& block = m_ItemBlocks[i]; - - // Casting to union. - Item* pItemPtr; - memcpy(&pItemPtr, &ptr, sizeof(pItemPtr)); - - // Check if pItemPtr is in address range of this block. - if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + m_ItemsPerBlock)) - { - const uint32_t index = static_cast(pItemPtr - block.pItems); - pItemPtr->NextFreeIndex = block.FirstFreeIndex; - block.FirstFreeIndex = index; - return; - } - } - VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool."); -} - -template -typename VmaPoolAllocator::ItemBlock& VmaPoolAllocator::CreateNewBlock() -{ - ItemBlock newBlock = { - vma_new_array(m_pAllocationCallbacks, Item, m_ItemsPerBlock), 0 }; - - m_ItemBlocks.push_back(newBlock); - - // Setup singly-linked list of all free items in this block. - for(uint32_t i = 0; i < m_ItemsPerBlock - 1; ++i) - newBlock.pItems[i].NextFreeIndex = i + 1; - newBlock.pItems[m_ItemsPerBlock - 1].NextFreeIndex = UINT32_MAX; - return m_ItemBlocks.back(); -} - -//////////////////////////////////////////////////////////////////////////////// -// class VmaRawList, VmaList - -#if VMA_USE_STL_LIST - -#define VmaList std::list - -#else // #if VMA_USE_STL_LIST - -template -struct VmaListItem -{ - VmaListItem* pPrev; - VmaListItem* pNext; - T Value; -}; - -// Doubly linked list. -template -class VmaRawList -{ -public: - typedef VmaListItem ItemType; - - VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks); - ~VmaRawList(); - void Clear(); - - size_t GetCount() const { return m_Count; } - bool IsEmpty() const { return m_Count == 0; } - - ItemType* Front() { return m_pFront; } - const ItemType* Front() const { return m_pFront; } - ItemType* Back() { return m_pBack; } - const ItemType* Back() const { return m_pBack; } - - ItemType* PushBack(); - ItemType* PushFront(); - ItemType* PushBack(const T& value); - ItemType* PushFront(const T& value); - void PopBack(); - void PopFront(); - - // Item can be null - it means PushBack. - ItemType* InsertBefore(ItemType* pItem); - // Item can be null - it means PushFront. - ItemType* InsertAfter(ItemType* pItem); - - ItemType* InsertBefore(ItemType* pItem, const T& value); - ItemType* InsertAfter(ItemType* pItem, const T& value); - - void Remove(ItemType* pItem); - -private: - const VkAllocationCallbacks* const m_pAllocationCallbacks; - VmaPoolAllocator m_ItemAllocator; - ItemType* m_pFront; - ItemType* m_pBack; - size_t m_Count; - - // Declared not defined, to block copy constructor and assignment operator. - VmaRawList(const VmaRawList& src); - VmaRawList& operator=(const VmaRawList& rhs); -}; - -template -VmaRawList::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) : - m_pAllocationCallbacks(pAllocationCallbacks), - m_ItemAllocator(pAllocationCallbacks, 128), - m_pFront(VMA_NULL), - m_pBack(VMA_NULL), - m_Count(0) -{ -} - -template -VmaRawList::~VmaRawList() -{ - // Intentionally not calling Clear, because that would be unnecessary - // computations to return all items to m_ItemAllocator as free. -} - -template -void VmaRawList::Clear() -{ - if(IsEmpty() == false) - { - ItemType* pItem = m_pBack; - while(pItem != VMA_NULL) - { - ItemType* const pPrevItem = pItem->pPrev; - m_ItemAllocator.Free(pItem); - pItem = pPrevItem; - } - m_pFront = VMA_NULL; - m_pBack = VMA_NULL; - m_Count = 0; - } -} - -template -VmaListItem* VmaRawList::PushBack() -{ - ItemType* const pNewItem = m_ItemAllocator.Alloc(); - pNewItem->pNext = VMA_NULL; - if(IsEmpty()) - { - pNewItem->pPrev = VMA_NULL; - m_pFront = pNewItem; - m_pBack = pNewItem; - m_Count = 1; - } - else - { - pNewItem->pPrev = m_pBack; - m_pBack->pNext = pNewItem; - m_pBack = pNewItem; - ++m_Count; - } - return pNewItem; -} - -template -VmaListItem* VmaRawList::PushFront() -{ - ItemType* const pNewItem = m_ItemAllocator.Alloc(); - pNewItem->pPrev = VMA_NULL; - if(IsEmpty()) - { - pNewItem->pNext = VMA_NULL; - m_pFront = pNewItem; - m_pBack = pNewItem; - m_Count = 1; - } - else - { - pNewItem->pNext = m_pFront; - m_pFront->pPrev = pNewItem; - m_pFront = pNewItem; - ++m_Count; - } - return pNewItem; -} - -template -VmaListItem* VmaRawList::PushBack(const T& value) -{ - ItemType* const pNewItem = PushBack(); - pNewItem->Value = value; - return pNewItem; -} - -template -VmaListItem* VmaRawList::PushFront(const T& value) -{ - ItemType* const pNewItem = PushFront(); - pNewItem->Value = value; - return pNewItem; -} - -template -void VmaRawList::PopBack() -{ - VMA_HEAVY_ASSERT(m_Count > 0); - ItemType* const pBackItem = m_pBack; - ItemType* const pPrevItem = pBackItem->pPrev; - if(pPrevItem != VMA_NULL) - { - pPrevItem->pNext = VMA_NULL; - } - m_pBack = pPrevItem; - m_ItemAllocator.Free(pBackItem); - --m_Count; -} - -template -void VmaRawList::PopFront() -{ - VMA_HEAVY_ASSERT(m_Count > 0); - ItemType* const pFrontItem = m_pFront; - ItemType* const pNextItem = pFrontItem->pNext; - if(pNextItem != VMA_NULL) - { - pNextItem->pPrev = VMA_NULL; - } - m_pFront = pNextItem; - m_ItemAllocator.Free(pFrontItem); - --m_Count; -} - -template -void VmaRawList::Remove(ItemType* pItem) -{ - VMA_HEAVY_ASSERT(pItem != VMA_NULL); - VMA_HEAVY_ASSERT(m_Count > 0); - - if(pItem->pPrev != VMA_NULL) - { - pItem->pPrev->pNext = pItem->pNext; - } - else - { - VMA_HEAVY_ASSERT(m_pFront == pItem); - m_pFront = pItem->pNext; - } - - if(pItem->pNext != VMA_NULL) - { - pItem->pNext->pPrev = pItem->pPrev; - } - else - { - VMA_HEAVY_ASSERT(m_pBack == pItem); - m_pBack = pItem->pPrev; - } - - m_ItemAllocator.Free(pItem); - --m_Count; -} - -template -VmaListItem* VmaRawList::InsertBefore(ItemType* pItem) -{ - if(pItem != VMA_NULL) - { - ItemType* const prevItem = pItem->pPrev; - ItemType* const newItem = m_ItemAllocator.Alloc(); - newItem->pPrev = prevItem; - newItem->pNext = pItem; - pItem->pPrev = newItem; - if(prevItem != VMA_NULL) - { - prevItem->pNext = newItem; - } - else - { - VMA_HEAVY_ASSERT(m_pFront == pItem); - m_pFront = newItem; - } - ++m_Count; - return newItem; - } - else - return PushBack(); -} - -template -VmaListItem* VmaRawList::InsertAfter(ItemType* pItem) -{ - if(pItem != VMA_NULL) - { - ItemType* const nextItem = pItem->pNext; - ItemType* const newItem = m_ItemAllocator.Alloc(); - newItem->pNext = nextItem; - newItem->pPrev = pItem; - pItem->pNext = newItem; - if(nextItem != VMA_NULL) - { - nextItem->pPrev = newItem; - } - else - { - VMA_HEAVY_ASSERT(m_pBack == pItem); - m_pBack = newItem; - } - ++m_Count; - return newItem; - } - else - return PushFront(); -} - -template -VmaListItem* VmaRawList::InsertBefore(ItemType* pItem, const T& value) -{ - ItemType* const newItem = InsertBefore(pItem); - newItem->Value = value; - return newItem; -} - -template -VmaListItem* VmaRawList::InsertAfter(ItemType* pItem, const T& value) -{ - ItemType* const newItem = InsertAfter(pItem); - newItem->Value = value; - return newItem; -} - -template -class VmaList -{ -public: - class iterator - { - public: - iterator() : - m_pList(VMA_NULL), - m_pItem(VMA_NULL) - { - } - - T& operator*() const - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - return m_pItem->Value; - } - T* operator->() const - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - return &m_pItem->Value; - } - - iterator& operator++() - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - m_pItem = m_pItem->pNext; - return *this; - } - iterator& operator--() - { - if(m_pItem != VMA_NULL) - { - m_pItem = m_pItem->pPrev; - } - else - { - VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); - m_pItem = m_pList->Back(); - } - return *this; - } - - iterator operator++(int) - { - iterator result = *this; - ++*this; - return result; - } - iterator operator--(int) - { - iterator result = *this; - --*this; - return result; - } - - bool operator==(const iterator& rhs) const - { - VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); - return m_pItem == rhs.m_pItem; - } - bool operator!=(const iterator& rhs) const - { - VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); - return m_pItem != rhs.m_pItem; - } - - private: - VmaRawList* m_pList; - VmaListItem* m_pItem; - - iterator(VmaRawList* pList, VmaListItem* pItem) : - m_pList(pList), - m_pItem(pItem) - { - } - - friend class VmaList; - }; - - class const_iterator - { - public: - const_iterator() : - m_pList(VMA_NULL), - m_pItem(VMA_NULL) - { - } - - const_iterator(const iterator& src) : - m_pList(src.m_pList), - m_pItem(src.m_pItem) - { - } - - const T& operator*() const - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - return m_pItem->Value; - } - const T* operator->() const - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - return &m_pItem->Value; - } - - const_iterator& operator++() - { - VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); - m_pItem = m_pItem->pNext; - return *this; - } - const_iterator& operator--() - { - if(m_pItem != VMA_NULL) - { - m_pItem = m_pItem->pPrev; - } - else - { - VMA_HEAVY_ASSERT(!m_pList->IsEmpty()); - m_pItem = m_pList->Back(); - } - return *this; - } - - const_iterator operator++(int) - { - const_iterator result = *this; - ++*this; - return result; - } - const_iterator operator--(int) - { - const_iterator result = *this; - --*this; - return result; - } - - bool operator==(const const_iterator& rhs) const - { - VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); - return m_pItem == rhs.m_pItem; - } - bool operator!=(const const_iterator& rhs) const - { - VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); - return m_pItem != rhs.m_pItem; - } - - private: - const_iterator(const VmaRawList* pList, const VmaListItem* pItem) : - m_pList(pList), - m_pItem(pItem) - { - } - - const VmaRawList* m_pList; - const VmaListItem* m_pItem; - - friend class VmaList; - }; - - VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { } - - bool empty() const { return m_RawList.IsEmpty(); } - size_t size() const { return m_RawList.GetCount(); } - - iterator begin() { return iterator(&m_RawList, m_RawList.Front()); } - iterator end() { return iterator(&m_RawList, VMA_NULL); } - - const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); } - const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); } - - void clear() { m_RawList.Clear(); } - void push_back(const T& value) { m_RawList.PushBack(value); } - void erase(iterator it) { m_RawList.Remove(it.m_pItem); } - iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); } - -private: - VmaRawList m_RawList; -}; - -#endif // #if VMA_USE_STL_LIST - -//////////////////////////////////////////////////////////////////////////////// -// class VmaMap - -// Unused in this version. -#if 0 - -#if VMA_USE_STL_UNORDERED_MAP - -#define VmaPair std::pair - -#define VMA_MAP_TYPE(KeyT, ValueT) \ - std::unordered_map< KeyT, ValueT, std::hash, std::equal_to, VmaStlAllocator< std::pair > > - -#else // #if VMA_USE_STL_UNORDERED_MAP - -template -struct VmaPair -{ - T1 first; - T2 second; - - VmaPair() : first(), second() { } - VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { } -}; - -/* Class compatible with subset of interface of std::unordered_map. -KeyT, ValueT must be POD because they will be stored in VmaVector. -*/ -template -class VmaMap -{ -public: - typedef VmaPair PairType; - typedef PairType* iterator; - - VmaMap(const VmaStlAllocator& allocator) : m_Vector(allocator) { } - - iterator begin() { return m_Vector.begin(); } - iterator end() { return m_Vector.end(); } - - void insert(const PairType& pair); - iterator find(const KeyT& key); - void erase(iterator it); - -private: - VmaVector< PairType, VmaStlAllocator > m_Vector; -}; - -#define VMA_MAP_TYPE(KeyT, ValueT) VmaMap - -template -struct VmaPairFirstLess -{ - bool operator()(const VmaPair& lhs, const VmaPair& rhs) const - { - return lhs.first < rhs.first; - } - bool operator()(const VmaPair& lhs, const FirstT& rhsFirst) const - { - return lhs.first < rhsFirst; - } -}; - -template -void VmaMap::insert(const PairType& pair) -{ - const size_t indexToInsert = VmaBinaryFindFirstNotLess( - m_Vector.data(), - m_Vector.data() + m_Vector.size(), - pair, - VmaPairFirstLess()) - m_Vector.data(); - VmaVectorInsert(m_Vector, indexToInsert, pair); -} - -template -VmaPair* VmaMap::find(const KeyT& key) -{ - PairType* it = VmaBinaryFindFirstNotLess( - m_Vector.data(), - m_Vector.data() + m_Vector.size(), - key, - VmaPairFirstLess()); - if((it != m_Vector.end()) && (it->first == key)) - { - return it; - } - else - { - return m_Vector.end(); - } -} - -template -void VmaMap::erase(iterator it) -{ - VmaVectorRemove(m_Vector, it - m_Vector.begin()); -} - -#endif // #if VMA_USE_STL_UNORDERED_MAP - -#endif // #if 0 - -//////////////////////////////////////////////////////////////////////////////// - -class VmaDeviceMemoryBlock; - -struct VmaAllocation_T -{ -private: - static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80; - - enum FLAGS - { - FLAG_USER_DATA_STRING = 0x01, - }; - -public: - enum ALLOCATION_TYPE - { - ALLOCATION_TYPE_NONE, - ALLOCATION_TYPE_BLOCK, - ALLOCATION_TYPE_DEDICATED, - }; - - VmaAllocation_T(uint32_t currentFrameIndex, bool userDataString) : - m_Alignment(1), - m_Size(0), - m_pUserData(VMA_NULL), - m_LastUseFrameIndex(currentFrameIndex), - m_Type((uint8_t)ALLOCATION_TYPE_NONE), - m_SuballocationType((uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN), - m_MapCount(0), - m_Flags(userDataString ? (uint8_t)FLAG_USER_DATA_STRING : 0) - { - } - - ~VmaAllocation_T() - { - VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction."); - - // Check if owned string was freed. - VMA_ASSERT(m_pUserData == VMA_NULL); - } - - void InitBlockAllocation( - VmaPool hPool, - VmaDeviceMemoryBlock* block, - VkDeviceSize offset, - VkDeviceSize alignment, - VkDeviceSize size, - VmaSuballocationType suballocationType, - bool mapped, - bool canBecomeLost) - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); - VMA_ASSERT(block != VMA_NULL); - m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK; - m_Alignment = alignment; - m_Size = size; - m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0; - m_SuballocationType = (uint8_t)suballocationType; - m_BlockAllocation.m_hPool = hPool; - m_BlockAllocation.m_Block = block; - m_BlockAllocation.m_Offset = offset; - m_BlockAllocation.m_CanBecomeLost = canBecomeLost; - } - - void InitLost() - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); - VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST); - m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK; - m_BlockAllocation.m_hPool = VK_NULL_HANDLE; - m_BlockAllocation.m_Block = VMA_NULL; - m_BlockAllocation.m_Offset = 0; - m_BlockAllocation.m_CanBecomeLost = true; - } - - void ChangeBlockAllocation( - VmaAllocator hAllocator, - VmaDeviceMemoryBlock* block, - VkDeviceSize offset); - - // pMappedData not null means allocation is created with MAPPED flag. - void InitDedicatedAllocation( - uint32_t memoryTypeIndex, - VkDeviceMemory hMemory, - VmaSuballocationType suballocationType, - void* pMappedData, - VkDeviceSize size) - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE); - VMA_ASSERT(hMemory != VK_NULL_HANDLE); - m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED; - m_Alignment = 0; - m_Size = size; - m_SuballocationType = (uint8_t)suballocationType; - m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0; - m_DedicatedAllocation.m_MemoryTypeIndex = memoryTypeIndex; - m_DedicatedAllocation.m_hMemory = hMemory; - m_DedicatedAllocation.m_pMappedData = pMappedData; - } - - ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; } - VkDeviceSize GetAlignment() const { return m_Alignment; } - VkDeviceSize GetSize() const { return m_Size; } - bool IsUserDataString() const { return (m_Flags & FLAG_USER_DATA_STRING) != 0; } - void* GetUserData() const { return m_pUserData; } - void SetUserData(VmaAllocator hAllocator, void* pUserData); - VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; } - - VmaDeviceMemoryBlock* GetBlock() const - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); - return m_BlockAllocation.m_Block; - } - VkDeviceSize GetOffset() const; - VkDeviceMemory GetMemory() const; - uint32_t GetMemoryTypeIndex() const; - bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; } - void* GetMappedData() const; - bool CanBecomeLost() const; - VmaPool GetPool() const; - - uint32_t GetLastUseFrameIndex() const - { - return m_LastUseFrameIndex.load(); - } - bool CompareExchangeLastUseFrameIndex(uint32_t& expected, uint32_t desired) - { - return m_LastUseFrameIndex.compare_exchange_weak(expected, desired); - } - /* - - If hAllocation.LastUseFrameIndex + frameInUseCount < allocator.CurrentFrameIndex, - makes it lost by setting LastUseFrameIndex = VMA_FRAME_INDEX_LOST and returns true. - - Else, returns false. - - If hAllocation is already lost, assert - you should not call it then. - If hAllocation was not created with CAN_BECOME_LOST_BIT, assert. - */ - bool MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount); - - void DedicatedAllocCalcStatsInfo(VmaStatInfo& outInfo) - { - VMA_ASSERT(m_Type == ALLOCATION_TYPE_DEDICATED); - outInfo.blockCount = 1; - outInfo.allocationCount = 1; - outInfo.unusedRangeCount = 0; - outInfo.usedBytes = m_Size; - outInfo.unusedBytes = 0; - outInfo.allocationSizeMin = outInfo.allocationSizeMax = m_Size; - outInfo.unusedRangeSizeMin = UINT64_MAX; - outInfo.unusedRangeSizeMax = 0; - } - - void BlockAllocMap(); - void BlockAllocUnmap(); - VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData); - void DedicatedAllocUnmap(VmaAllocator hAllocator); - -private: - VkDeviceSize m_Alignment; - VkDeviceSize m_Size; - void* m_pUserData; - VMA_ATOMIC_UINT32 m_LastUseFrameIndex; - uint8_t m_Type; // ALLOCATION_TYPE - uint8_t m_SuballocationType; // VmaSuballocationType - // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT. - // Bits with mask 0x7F are reference counter for vmaMapMemory()/vmaUnmapMemory(). - uint8_t m_MapCount; - uint8_t m_Flags; // enum FLAGS - - // Allocation out of VmaDeviceMemoryBlock. - struct BlockAllocation - { - VmaPool m_hPool; // Null if belongs to general memory. - VmaDeviceMemoryBlock* m_Block; - VkDeviceSize m_Offset; - bool m_CanBecomeLost; - }; - - // Allocation for an object that has its own private VkDeviceMemory. - struct DedicatedAllocation - { - uint32_t m_MemoryTypeIndex; - VkDeviceMemory m_hMemory; - void* m_pMappedData; // Not null means memory is mapped. - }; - - union - { - // Allocation out of VmaDeviceMemoryBlock. - BlockAllocation m_BlockAllocation; - // Allocation for an object that has its own private VkDeviceMemory. - DedicatedAllocation m_DedicatedAllocation; - }; - - void FreeUserDataString(VmaAllocator hAllocator); -}; - -/* -Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as -allocated memory block or free. -*/ -struct VmaSuballocation -{ - VkDeviceSize offset; - VkDeviceSize size; - VmaAllocation hAllocation; - VmaSuballocationType type; -}; - -typedef VmaList< VmaSuballocation, VmaStlAllocator > VmaSuballocationList; - -// Cost of one additional allocation lost, as equivalent in bytes. -static const VkDeviceSize VMA_LOST_ALLOCATION_COST = 1048576; - -/* -Parameters of planned allocation inside a VmaDeviceMemoryBlock. - -If canMakeOtherLost was false: -- item points to a FREE suballocation. -- itemsToMakeLostCount is 0. - -If canMakeOtherLost was true: -- item points to first of sequence of suballocations, which are either FREE, - or point to VmaAllocations that can become lost. -- itemsToMakeLostCount is the number of VmaAllocations that need to be made lost for - the requested allocation to succeed. -*/ -struct VmaAllocationRequest -{ - VkDeviceSize offset; - VkDeviceSize sumFreeSize; // Sum size of free items that overlap with proposed allocation. - VkDeviceSize sumItemSize; // Sum size of items to make lost that overlap with proposed allocation. - VmaSuballocationList::iterator item; - size_t itemsToMakeLostCount; - - VkDeviceSize CalcCost() const - { - return sumItemSize + itemsToMakeLostCount * VMA_LOST_ALLOCATION_COST; - } -}; - -/* -Data structure used for bookkeeping of allocations and unused ranges of memory -in a single VkDeviceMemory block. -*/ -class VmaBlockMetadata -{ -public: - VmaBlockMetadata(VmaAllocator hAllocator); - ~VmaBlockMetadata(); - void Init(VkDeviceSize size); - - // Validates all data structures inside this object. If not valid, returns false. - bool Validate() const; - VkDeviceSize GetSize() const { return m_Size; } - size_t GetAllocationCount() const { return m_Suballocations.size() - m_FreeCount; } - VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; } - VkDeviceSize GetUnusedRangeSizeMax() const; - // Returns true if this block is empty - contains only single free suballocation. - bool IsEmpty() const; - - void CalcAllocationStatInfo(VmaStatInfo& outInfo) const; - void AddPoolStats(VmaPoolStats& inoutStats) const; - -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMap(class VmaJsonWriter& json) const; -#endif - - // Creates trivial request for case when block is empty. - void CreateFirstAllocationRequest(VmaAllocationRequest* pAllocationRequest); - - // Tries to find a place for suballocation with given parameters inside this block. - // If succeeded, fills pAllocationRequest and returns true. - // If failed, returns false. - bool CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - bool canMakeOtherLost, - VmaAllocationRequest* pAllocationRequest); - - bool MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest); - - uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount); - - // Makes actual allocation based on request. Request must already be checked and valid. - void Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation); - - // Frees suballocation assigned to given memory region. - void Free(const VmaAllocation allocation); - void FreeAtOffset(VkDeviceSize offset); - -private: - VkDeviceSize m_Size; - uint32_t m_FreeCount; - VkDeviceSize m_SumFreeSize; - VmaSuballocationList m_Suballocations; - // Suballocations that are free and have size greater than certain threshold. - // Sorted by size, ascending. - VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize; - - bool ValidateFreeSuballocationList() const; - - // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem. - // If yes, fills pOffset and returns true. If no, returns false. - bool CheckAllocation( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - VmaSuballocationList::const_iterator suballocItem, - bool canMakeOtherLost, - VkDeviceSize* pOffset, - size_t* itemsToMakeLostCount, - VkDeviceSize* pSumFreeSize, - VkDeviceSize* pSumItemSize) const; - // Given free suballocation, it merges it with following one, which must also be free. - void MergeFreeWithNext(VmaSuballocationList::iterator item); - // Releases given suballocation, making it free. - // Merges it with adjacent free suballocations if applicable. - // Returns iterator to new free suballocation at this place. - VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem); - // Given free suballocation, it inserts it into sorted list of - // m_FreeSuballocationsBySize if it's suitable. - void RegisterFreeSuballocation(VmaSuballocationList::iterator item); - // Given free suballocation, it removes it from sorted list of - // m_FreeSuballocationsBySize if it's suitable. - void UnregisterFreeSuballocation(VmaSuballocationList::iterator item); -}; - -/* -Represents a single block of device memory (`VkDeviceMemory`) with all the -data about its regions (aka suballocations, #VmaAllocation), assigned and free. - -Thread-safety: This class must be externally synchronized. -*/ -class VmaDeviceMemoryBlock -{ -public: - VmaBlockMetadata m_Metadata; - - VmaDeviceMemoryBlock(VmaAllocator hAllocator); - - ~VmaDeviceMemoryBlock() - { - VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped."); - VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); - } - - // Always call after construction. - void Init( - uint32_t newMemoryTypeIndex, - VkDeviceMemory newMemory, - VkDeviceSize newSize); - // Always call before destruction. - void Destroy(VmaAllocator allocator); - - VkDeviceMemory GetDeviceMemory() const { return m_hMemory; } - uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } - void* GetMappedData() const { return m_pMappedData; } - - // Validates all data structures inside this object. If not valid, returns false. - bool Validate() const; - - // ppData can be null. - VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData); - void Unmap(VmaAllocator hAllocator, uint32_t count); - - VkResult BindBufferMemory( - const VmaAllocator hAllocator, - const VmaAllocation hAllocation, - VkBuffer hBuffer); - VkResult BindImageMemory( - const VmaAllocator hAllocator, - const VmaAllocation hAllocation, - VkImage hImage); - -private: - uint32_t m_MemoryTypeIndex; - VkDeviceMemory m_hMemory; - - // Protects access to m_hMemory so it's not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory. - // Also protects m_MapCount, m_pMappedData. - VMA_MUTEX m_Mutex; - uint32_t m_MapCount; - void* m_pMappedData; -}; - -struct VmaPointerLess -{ - bool operator()(const void* lhs, const void* rhs) const - { - return lhs < rhs; - } -}; - -class VmaDefragmentator; - -/* -Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific -Vulkan memory type. - -Synchronized internally with a mutex. -*/ -struct VmaBlockVector -{ - VmaBlockVector( - VmaAllocator hAllocator, - uint32_t memoryTypeIndex, - VkDeviceSize preferredBlockSize, - size_t minBlockCount, - size_t maxBlockCount, - VkDeviceSize bufferImageGranularity, - uint32_t frameInUseCount, - bool isCustomPool); - ~VmaBlockVector(); - - VkResult CreateMinBlocks(); - - uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } - VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; } - VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; } - uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; } - - void GetPoolStats(VmaPoolStats* pStats); - - bool IsEmpty() const { return m_Blocks.empty(); } - - VkResult Allocate( - VmaPool hCurrentPool, - uint32_t currentFrameIndex, - const VkMemoryRequirements& vkMemReq, - const VmaAllocationCreateInfo& createInfo, - VmaSuballocationType suballocType, - VmaAllocation* pAllocation); - - void Free( - VmaAllocation hAllocation); - - // Adds statistics of this BlockVector to pStats. - void AddStats(VmaStats* pStats); - -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMap(class VmaJsonWriter& json); -#endif - - void MakePoolAllocationsLost( - uint32_t currentFrameIndex, - size_t* pLostAllocationCount); - - VmaDefragmentator* EnsureDefragmentator( - VmaAllocator hAllocator, - uint32_t currentFrameIndex); - - VkResult Defragment( - VmaDefragmentationStats* pDefragmentationStats, - VkDeviceSize& maxBytesToMove, - uint32_t& maxAllocationsToMove); - - void DestroyDefragmentator(); - -private: - friend class VmaDefragmentator; - - const VmaAllocator m_hAllocator; - const uint32_t m_MemoryTypeIndex; - const VkDeviceSize m_PreferredBlockSize; - const size_t m_MinBlockCount; - const size_t m_MaxBlockCount; - const VkDeviceSize m_BufferImageGranularity; - const uint32_t m_FrameInUseCount; - const bool m_IsCustomPool; - VMA_MUTEX m_Mutex; - // Incrementally sorted by sumFreeSize, ascending. - VmaVector< VmaDeviceMemoryBlock*, VmaStlAllocator > m_Blocks; - /* There can be at most one allocation that is completely empty - a - hysteresis to avoid pessimistic case of alternating creation and destruction - of a VkDeviceMemory. */ - bool m_HasEmptyBlock; - VmaDefragmentator* m_pDefragmentator; - - size_t CalcMaxBlockSize() const; - - // Finds and removes given block from vector. - void Remove(VmaDeviceMemoryBlock* pBlock); - - // Performs single step in sorting m_Blocks. They may not be fully sorted - // after this call. - void IncrementallySortBlocks(); - - VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex); -}; - -struct VmaPool_T -{ -public: - VmaBlockVector m_BlockVector; - - // Takes ownership. - VmaPool_T( - VmaAllocator hAllocator, - const VmaPoolCreateInfo& createInfo); - ~VmaPool_T(); - - VmaBlockVector& GetBlockVector() { return m_BlockVector; } - -#if VMA_STATS_STRING_ENABLED - //void PrintDetailedMap(class VmaStringBuilder& sb); -#endif -}; - -class VmaDefragmentator -{ - const VmaAllocator m_hAllocator; - VmaBlockVector* const m_pBlockVector; - uint32_t m_CurrentFrameIndex; - VkDeviceSize m_BytesMoved; - uint32_t m_AllocationsMoved; - - struct AllocationInfo - { - VmaAllocation m_hAllocation; - VkBool32* m_pChanged; - - AllocationInfo() : - m_hAllocation(VK_NULL_HANDLE), - m_pChanged(VMA_NULL) - { - } - }; - - struct AllocationInfoSizeGreater - { - bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const - { - return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize(); - } - }; - - // Used between AddAllocation and Defragment. - VmaVector< AllocationInfo, VmaStlAllocator > m_Allocations; - - struct BlockInfo - { - VmaDeviceMemoryBlock* m_pBlock; - bool m_HasNonMovableAllocations; - VmaVector< AllocationInfo, VmaStlAllocator > m_Allocations; - - BlockInfo(const VkAllocationCallbacks* pAllocationCallbacks) : - m_pBlock(VMA_NULL), - m_HasNonMovableAllocations(true), - m_Allocations(pAllocationCallbacks), - m_pMappedDataForDefragmentation(VMA_NULL) - { - } - - void CalcHasNonMovableAllocations() - { - const size_t blockAllocCount = m_pBlock->m_Metadata.GetAllocationCount(); - const size_t defragmentAllocCount = m_Allocations.size(); - m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount; - } - - void SortAllocationsBySizeDescecnding() - { - VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater()); - } - - VkResult EnsureMapping(VmaAllocator hAllocator, void** ppMappedData); - void Unmap(VmaAllocator hAllocator); - - private: - // Not null if mapped for defragmentation only, not originally mapped. - void* m_pMappedDataForDefragmentation; - }; - - struct BlockPointerLess - { - bool operator()(const BlockInfo* pLhsBlockInfo, const VmaDeviceMemoryBlock* pRhsBlock) const - { - return pLhsBlockInfo->m_pBlock < pRhsBlock; - } - bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const - { - return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock; - } - }; - - // 1. Blocks with some non-movable allocations go first. - // 2. Blocks with smaller sumFreeSize go first. - struct BlockInfoCompareMoveDestination - { - bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const - { - if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations) - { - return true; - } - if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations) - { - return false; - } - if(pLhsBlockInfo->m_pBlock->m_Metadata.GetSumFreeSize() < pRhsBlockInfo->m_pBlock->m_Metadata.GetSumFreeSize()) - { - return true; - } - return false; - } - }; - - typedef VmaVector< BlockInfo*, VmaStlAllocator > BlockInfoVector; - BlockInfoVector m_Blocks; - - VkResult DefragmentRound( - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove); - - static bool MoveMakesSense( - size_t dstBlockIndex, VkDeviceSize dstOffset, - size_t srcBlockIndex, VkDeviceSize srcOffset); - -public: - VmaDefragmentator( - VmaAllocator hAllocator, - VmaBlockVector* pBlockVector, - uint32_t currentFrameIndex); - - ~VmaDefragmentator(); - - VkDeviceSize GetBytesMoved() const { return m_BytesMoved; } - uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; } - - void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged); - - VkResult Defragment( - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove); -}; - -// Main allocator object. -struct VmaAllocator_T -{ - bool m_UseMutex; - bool m_UseKhrDedicatedAllocation; - VkDevice m_hDevice; - bool m_AllocationCallbacksSpecified; - VkAllocationCallbacks m_AllocationCallbacks; - VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks; - - // Number of bytes free out of limit, or VK_WHOLE_SIZE if not limit for that heap. - VkDeviceSize m_HeapSizeLimit[VK_MAX_MEMORY_HEAPS]; - VMA_MUTEX m_HeapSizeLimitMutex; - - VkPhysicalDeviceProperties m_PhysicalDeviceProperties; - VkPhysicalDeviceMemoryProperties m_MemProps; - - // Default pools. - VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES]; - - // Each vector is sorted by memory (handle value). - typedef VmaVector< VmaAllocation, VmaStlAllocator > AllocationVectorType; - AllocationVectorType* m_pDedicatedAllocations[VK_MAX_MEMORY_TYPES]; - VMA_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES]; - - VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo); - ~VmaAllocator_T(); - - const VkAllocationCallbacks* GetAllocationCallbacks() const - { - return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0; - } - const VmaVulkanFunctions& GetVulkanFunctions() const - { - return m_VulkanFunctions; - } - - VkDeviceSize GetBufferImageGranularity() const - { - return VMA_MAX( - static_cast(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY), - m_PhysicalDeviceProperties.limits.bufferImageGranularity); - } - - uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; } - uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; } - - uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const - { - VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount); - return m_MemProps.memoryTypes[memTypeIndex].heapIndex; - } - - void GetBufferMemoryRequirements( - VkBuffer hBuffer, - VkMemoryRequirements& memReq, - bool& requiresDedicatedAllocation, - bool& prefersDedicatedAllocation) const; - void GetImageMemoryRequirements( - VkImage hImage, - VkMemoryRequirements& memReq, - bool& requiresDedicatedAllocation, - bool& prefersDedicatedAllocation) const; - - // Main allocation function. - VkResult AllocateMemory( - const VkMemoryRequirements& vkMemReq, - bool requiresDedicatedAllocation, - bool prefersDedicatedAllocation, - VkBuffer dedicatedBuffer, - VkImage dedicatedImage, - const VmaAllocationCreateInfo& createInfo, - VmaSuballocationType suballocType, - VmaAllocation* pAllocation); - - // Main deallocation function. - void FreeMemory(const VmaAllocation allocation); - - void CalculateStats(VmaStats* pStats); - -#if VMA_STATS_STRING_ENABLED - void PrintDetailedMap(class VmaJsonWriter& json); -#endif - - VkResult Defragment( - VmaAllocation* pAllocations, - size_t allocationCount, - VkBool32* pAllocationsChanged, - const VmaDefragmentationInfo* pDefragmentationInfo, - VmaDefragmentationStats* pDefragmentationStats); - - void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo); - bool TouchAllocation(VmaAllocation hAllocation); - - VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool); - void DestroyPool(VmaPool pool); - void GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats); - - void SetCurrentFrameIndex(uint32_t frameIndex); - - void MakePoolAllocationsLost( - VmaPool hPool, - size_t* pLostAllocationCount); - - void CreateLostAllocation(VmaAllocation* pAllocation); - - VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory); - void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory); - - VkResult Map(VmaAllocation hAllocation, void** ppData); - void Unmap(VmaAllocation hAllocation); - - VkResult BindBufferMemory(VmaAllocation hAllocation, VkBuffer hBuffer); - VkResult BindImageMemory(VmaAllocation hAllocation, VkImage hImage); - -private: - VkDeviceSize m_PreferredLargeHeapBlockSize; - - VkPhysicalDevice m_PhysicalDevice; - VMA_ATOMIC_UINT32 m_CurrentFrameIndex; - - VMA_MUTEX m_PoolsMutex; - // Protected by m_PoolsMutex. Sorted by pointer value. - VmaVector > m_Pools; - - VmaVulkanFunctions m_VulkanFunctions; - - void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions); - - VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex); - - VkResult AllocateMemoryOfType( - const VkMemoryRequirements& vkMemReq, - bool dedicatedAllocation, - VkBuffer dedicatedBuffer, - VkImage dedicatedImage, - const VmaAllocationCreateInfo& createInfo, - uint32_t memTypeIndex, - VmaSuballocationType suballocType, - VmaAllocation* pAllocation); - - // Allocates and registers new VkDeviceMemory specifically for single allocation. - VkResult AllocateDedicatedMemory( - VkDeviceSize size, - VmaSuballocationType suballocType, - uint32_t memTypeIndex, - bool map, - bool isUserDataString, - void* pUserData, - VkBuffer dedicatedBuffer, - VkImage dedicatedImage, - VmaAllocation* pAllocation); - - // Tries to free pMemory as Dedicated Memory. Returns true if found and freed. - void FreeDedicatedMemory(VmaAllocation allocation); -}; - -//////////////////////////////////////////////////////////////////////////////// -// Memory allocation #2 after VmaAllocator_T definition - -static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment) -{ - return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment); -} - -static void VmaFree(VmaAllocator hAllocator, void* ptr) -{ - VmaFree(&hAllocator->m_AllocationCallbacks, ptr); -} - -template -static T* VmaAllocate(VmaAllocator hAllocator) -{ - return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T)); -} - -template -static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count) -{ - return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T)); -} - -template -static void vma_delete(VmaAllocator hAllocator, T* ptr) -{ - if(ptr != VMA_NULL) - { - ptr->~T(); - VmaFree(hAllocator, ptr); - } -} - -template -static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count) -{ - if(ptr != VMA_NULL) - { - for(size_t i = count; i--; ) - ptr[i].~T(); - VmaFree(hAllocator, ptr); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// VmaStringBuilder - -#if VMA_STATS_STRING_ENABLED - -class VmaStringBuilder -{ -public: - VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator(alloc->GetAllocationCallbacks())) { } - size_t GetLength() const { return m_Data.size(); } - const char* GetData() const { return m_Data.data(); } - - void Add(char ch) { m_Data.push_back(ch); } - void Add(const char* pStr); - void AddNewLine() { Add('\n'); } - void AddNumber(uint32_t num); - void AddNumber(uint64_t num); - void AddPointer(const void* ptr); - -private: - VmaVector< char, VmaStlAllocator > m_Data; -}; - -void VmaStringBuilder::Add(const char* pStr) -{ - const size_t strLen = strlen(pStr); - if(strLen > 0) - { - const size_t oldCount = m_Data.size(); - m_Data.resize(oldCount + strLen); - memcpy(m_Data.data() + oldCount, pStr, strLen); - } -} - -void VmaStringBuilder::AddNumber(uint32_t num) -{ - char buf[11]; - VmaUint32ToStr(buf, sizeof(buf), num); - Add(buf); -} - -void VmaStringBuilder::AddNumber(uint64_t num) -{ - char buf[21]; - VmaUint64ToStr(buf, sizeof(buf), num); - Add(buf); -} - -void VmaStringBuilder::AddPointer(const void* ptr) -{ - char buf[21]; - VmaPtrToStr(buf, sizeof(buf), ptr); - Add(buf); -} - -#endif // #if VMA_STATS_STRING_ENABLED - -//////////////////////////////////////////////////////////////////////////////// -// VmaJsonWriter - -#if VMA_STATS_STRING_ENABLED - -class VmaJsonWriter -{ -public: - VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb); - ~VmaJsonWriter(); - - void BeginObject(bool singleLine = false); - void EndObject(); - - void BeginArray(bool singleLine = false); - void EndArray(); - - void WriteString(const char* pStr); - void BeginString(const char* pStr = VMA_NULL); - void ContinueString(const char* pStr); - void ContinueString(uint32_t n); - void ContinueString(uint64_t n); - void ContinueString_Pointer(const void* ptr); - void EndString(const char* pStr = VMA_NULL); - - void WriteNumber(uint32_t n); - void WriteNumber(uint64_t n); - void WriteBool(bool b); - void WriteNull(); - -private: - static const char* const INDENT; - - enum COLLECTION_TYPE - { - COLLECTION_TYPE_OBJECT, - COLLECTION_TYPE_ARRAY, - }; - struct StackItem - { - COLLECTION_TYPE type; - uint32_t valueCount; - bool singleLineMode; - }; - - VmaStringBuilder& m_SB; - VmaVector< StackItem, VmaStlAllocator > m_Stack; - bool m_InsideString; - - void BeginValue(bool isString); - void WriteIndent(bool oneLess = false); -}; - -const char* const VmaJsonWriter::INDENT = " "; - -VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) : - m_SB(sb), - m_Stack(VmaStlAllocator(pAllocationCallbacks)), - m_InsideString(false) -{ -} - -VmaJsonWriter::~VmaJsonWriter() -{ - VMA_ASSERT(!m_InsideString); - VMA_ASSERT(m_Stack.empty()); -} - -void VmaJsonWriter::BeginObject(bool singleLine) -{ - VMA_ASSERT(!m_InsideString); - - BeginValue(false); - m_SB.Add('{'); - - StackItem item; - item.type = COLLECTION_TYPE_OBJECT; - item.valueCount = 0; - item.singleLineMode = singleLine; - m_Stack.push_back(item); -} - -void VmaJsonWriter::EndObject() -{ - VMA_ASSERT(!m_InsideString); - - WriteIndent(true); - m_SB.Add('}'); - - VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT); - m_Stack.pop_back(); -} - -void VmaJsonWriter::BeginArray(bool singleLine) -{ - VMA_ASSERT(!m_InsideString); - - BeginValue(false); - m_SB.Add('['); - - StackItem item; - item.type = COLLECTION_TYPE_ARRAY; - item.valueCount = 0; - item.singleLineMode = singleLine; - m_Stack.push_back(item); -} - -void VmaJsonWriter::EndArray() -{ - VMA_ASSERT(!m_InsideString); - - WriteIndent(true); - m_SB.Add(']'); - - VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY); - m_Stack.pop_back(); -} - -void VmaJsonWriter::WriteString(const char* pStr) -{ - BeginString(pStr); - EndString(); -} - -void VmaJsonWriter::BeginString(const char* pStr) -{ - VMA_ASSERT(!m_InsideString); - - BeginValue(true); - m_SB.Add('"'); - m_InsideString = true; - if(pStr != VMA_NULL && pStr[0] != '\0') - { - ContinueString(pStr); - } -} - -void VmaJsonWriter::ContinueString(const char* pStr) -{ - VMA_ASSERT(m_InsideString); - - const size_t strLen = strlen(pStr); - for(size_t i = 0; i < strLen; ++i) - { - char ch = pStr[i]; - if(ch == '\'') - { - m_SB.Add("\\\\"); - } - else if(ch == '"') - { - m_SB.Add("\\\""); - } - else if(ch >= 32) - { - m_SB.Add(ch); - } - else switch(ch) - { - case '\b': - m_SB.Add("\\b"); - break; - case '\f': - m_SB.Add("\\f"); - break; - case '\n': - m_SB.Add("\\n"); - break; - case '\r': - m_SB.Add("\\r"); - break; - case '\t': - m_SB.Add("\\t"); - break; - default: - VMA_ASSERT(0 && "Character not currently supported."); - break; - } - } -} - -void VmaJsonWriter::ContinueString(uint32_t n) -{ - VMA_ASSERT(m_InsideString); - m_SB.AddNumber(n); -} - -void VmaJsonWriter::ContinueString(uint64_t n) -{ - VMA_ASSERT(m_InsideString); - m_SB.AddNumber(n); -} - -void VmaJsonWriter::ContinueString_Pointer(const void* ptr) -{ - VMA_ASSERT(m_InsideString); - m_SB.AddPointer(ptr); -} - -void VmaJsonWriter::EndString(const char* pStr) -{ - VMA_ASSERT(m_InsideString); - if(pStr != VMA_NULL && pStr[0] != '\0') - { - ContinueString(pStr); - } - m_SB.Add('"'); - m_InsideString = false; -} - -void VmaJsonWriter::WriteNumber(uint32_t n) -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.AddNumber(n); -} - -void VmaJsonWriter::WriteNumber(uint64_t n) -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.AddNumber(n); -} - -void VmaJsonWriter::WriteBool(bool b) -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.Add(b ? "true" : "false"); -} - -void VmaJsonWriter::WriteNull() -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.Add("null"); -} - -void VmaJsonWriter::BeginValue(bool isString) -{ - if(!m_Stack.empty()) - { - StackItem& currItem = m_Stack.back(); - if(currItem.type == COLLECTION_TYPE_OBJECT && - currItem.valueCount % 2 == 0) - { - VMA_ASSERT(isString); - } - - if(currItem.type == COLLECTION_TYPE_OBJECT && - currItem.valueCount % 2 != 0) - { - m_SB.Add(": "); - } - else if(currItem.valueCount > 0) - { - m_SB.Add(", "); - WriteIndent(); - } - else - { - WriteIndent(); - } - ++currItem.valueCount; - } -} - -void VmaJsonWriter::WriteIndent(bool oneLess) -{ - if(!m_Stack.empty() && !m_Stack.back().singleLineMode) - { - m_SB.AddNewLine(); - - size_t count = m_Stack.size(); - if(count > 0 && oneLess) - { - --count; - } - for(size_t i = 0; i < count; ++i) - { - m_SB.Add(INDENT); - } - } -} - -#endif // #if VMA_STATS_STRING_ENABLED - -//////////////////////////////////////////////////////////////////////////////// - -void VmaAllocation_T::SetUserData(VmaAllocator hAllocator, void* pUserData) -{ - if(IsUserDataString()) - { - VMA_ASSERT(pUserData == VMA_NULL || pUserData != m_pUserData); - - FreeUserDataString(hAllocator); - - if(pUserData != VMA_NULL) - { - const char* const newStrSrc = (char*)pUserData; - const size_t newStrLen = strlen(newStrSrc); - char* const newStrDst = vma_new_array(hAllocator, char, newStrLen + 1); - memcpy(newStrDst, newStrSrc, newStrLen + 1); - m_pUserData = newStrDst; - } - } - else - { - m_pUserData = pUserData; - } -} - -void VmaAllocation_T::ChangeBlockAllocation( - VmaAllocator hAllocator, - VmaDeviceMemoryBlock* block, - VkDeviceSize offset) -{ - VMA_ASSERT(block != VMA_NULL); - VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); - - // Move mapping reference counter from old block to new block. - if(block != m_BlockAllocation.m_Block) - { - uint32_t mapRefCount = m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP; - if(IsPersistentMap()) - ++mapRefCount; - m_BlockAllocation.m_Block->Unmap(hAllocator, mapRefCount); - block->Map(hAllocator, mapRefCount, VMA_NULL); - } - - m_BlockAllocation.m_Block = block; - m_BlockAllocation.m_Offset = offset; -} - -VkDeviceSize VmaAllocation_T::GetOffset() const -{ - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - return m_BlockAllocation.m_Offset; - case ALLOCATION_TYPE_DEDICATED: - return 0; - default: - VMA_ASSERT(0); - return 0; - } -} - -VkDeviceMemory VmaAllocation_T::GetMemory() const -{ - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - return m_BlockAllocation.m_Block->GetDeviceMemory(); - case ALLOCATION_TYPE_DEDICATED: - return m_DedicatedAllocation.m_hMemory; - default: - VMA_ASSERT(0); - return VK_NULL_HANDLE; - } -} - -uint32_t VmaAllocation_T::GetMemoryTypeIndex() const -{ - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - return m_BlockAllocation.m_Block->GetMemoryTypeIndex(); - case ALLOCATION_TYPE_DEDICATED: - return m_DedicatedAllocation.m_MemoryTypeIndex; - default: - VMA_ASSERT(0); - return UINT32_MAX; - } -} - -void* VmaAllocation_T::GetMappedData() const -{ - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - if(m_MapCount != 0) - { - void* pBlockData = m_BlockAllocation.m_Block->GetMappedData(); - VMA_ASSERT(pBlockData != VMA_NULL); - return (char*)pBlockData + m_BlockAllocation.m_Offset; - } - else - { - return VMA_NULL; - } - break; - case ALLOCATION_TYPE_DEDICATED: - VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0)); - return m_DedicatedAllocation.m_pMappedData; - default: - VMA_ASSERT(0); - return VMA_NULL; - } -} - -bool VmaAllocation_T::CanBecomeLost() const -{ - switch(m_Type) - { - case ALLOCATION_TYPE_BLOCK: - return m_BlockAllocation.m_CanBecomeLost; - case ALLOCATION_TYPE_DEDICATED: - return false; - default: - VMA_ASSERT(0); - return false; - } -} - -VmaPool VmaAllocation_T::GetPool() const -{ - VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK); - return m_BlockAllocation.m_hPool; -} - -bool VmaAllocation_T::MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) -{ - VMA_ASSERT(CanBecomeLost()); - - /* - Warning: This is a carefully designed algorithm. - Do not modify unless you really know what you're doing :) - */ - uint32_t localLastUseFrameIndex = GetLastUseFrameIndex(); - for(;;) - { - if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST) - { - VMA_ASSERT(0); - return false; - } - else if(localLastUseFrameIndex + frameInUseCount >= currentFrameIndex) - { - return false; - } - else // Last use time earlier than current time. - { - if(CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, VMA_FRAME_INDEX_LOST)) - { - // Setting hAllocation.LastUseFrameIndex atomic to VMA_FRAME_INDEX_LOST is enough to mark it as LOST. - // Calling code just needs to unregister this allocation in owning VmaDeviceMemoryBlock. - return true; - } - } - } -} - -void VmaAllocation_T::FreeUserDataString(VmaAllocator hAllocator) -{ - VMA_ASSERT(IsUserDataString()); - if(m_pUserData != VMA_NULL) - { - char* const oldStr = (char*)m_pUserData; - const size_t oldStrLen = strlen(oldStr); - vma_delete_array(hAllocator, oldStr, oldStrLen + 1); - m_pUserData = VMA_NULL; - } -} - -void VmaAllocation_T::BlockAllocMap() -{ - VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK); - - if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F) - { - ++m_MapCount; - } - else - { - VMA_ASSERT(0 && "Allocation mapped too many times simultaneously."); - } -} - -void VmaAllocation_T::BlockAllocUnmap() -{ - VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK); - - if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0) - { - --m_MapCount; - } - else - { - VMA_ASSERT(0 && "Unmapping allocation not previously mapped."); - } -} - -VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData) -{ - VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); - - if(m_MapCount != 0) - { - if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F) - { - VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL); - *ppData = m_DedicatedAllocation.m_pMappedData; - ++m_MapCount; - return VK_SUCCESS; - } - else - { - VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously."); - return VK_ERROR_MEMORY_MAP_FAILED; - } - } - else - { - VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)( - hAllocator->m_hDevice, - m_DedicatedAllocation.m_hMemory, - 0, // offset - VK_WHOLE_SIZE, - 0, // flags - ppData); - if(result == VK_SUCCESS) - { - m_DedicatedAllocation.m_pMappedData = *ppData; - m_MapCount = 1; - } - return result; - } -} - -void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator) -{ - VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED); - - if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0) - { - --m_MapCount; - if(m_MapCount == 0) - { - m_DedicatedAllocation.m_pMappedData = VMA_NULL; - (*hAllocator->GetVulkanFunctions().vkUnmapMemory)( - hAllocator->m_hDevice, - m_DedicatedAllocation.m_hMemory); - } - } - else - { - VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped."); - } -} - -#if VMA_STATS_STRING_ENABLED - -// Correspond to values of enum VmaSuballocationType. -static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = { - "FREE", - "UNKNOWN", - "BUFFER", - "IMAGE_UNKNOWN", - "IMAGE_LINEAR", - "IMAGE_OPTIMAL", -}; - -static void VmaPrintStatInfo(VmaJsonWriter& json, const VmaStatInfo& stat) -{ - json.BeginObject(); - - json.WriteString("Blocks"); - json.WriteNumber(stat.blockCount); - - json.WriteString("Allocations"); - json.WriteNumber(stat.allocationCount); - - json.WriteString("UnusedRanges"); - json.WriteNumber(stat.unusedRangeCount); - - json.WriteString("UsedBytes"); - json.WriteNumber(stat.usedBytes); - - json.WriteString("UnusedBytes"); - json.WriteNumber(stat.unusedBytes); - - if(stat.allocationCount > 1) - { - json.WriteString("AllocationSize"); - json.BeginObject(true); - json.WriteString("Min"); - json.WriteNumber(stat.allocationSizeMin); - json.WriteString("Avg"); - json.WriteNumber(stat.allocationSizeAvg); - json.WriteString("Max"); - json.WriteNumber(stat.allocationSizeMax); - json.EndObject(); - } - - if(stat.unusedRangeCount > 1) - { - json.WriteString("UnusedRangeSize"); - json.BeginObject(true); - json.WriteString("Min"); - json.WriteNumber(stat.unusedRangeSizeMin); - json.WriteString("Avg"); - json.WriteNumber(stat.unusedRangeSizeAvg); - json.WriteString("Max"); - json.WriteNumber(stat.unusedRangeSizeMax); - json.EndObject(); - } - - json.EndObject(); -} - -#endif // #if VMA_STATS_STRING_ENABLED - -struct VmaSuballocationItemSizeLess -{ - bool operator()( - const VmaSuballocationList::iterator lhs, - const VmaSuballocationList::iterator rhs) const - { - return lhs->size < rhs->size; - } - bool operator()( - const VmaSuballocationList::iterator lhs, - VkDeviceSize rhsSize) const - { - return lhs->size < rhsSize; - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// class VmaBlockMetadata - -VmaBlockMetadata::VmaBlockMetadata(VmaAllocator hAllocator) : - m_Size(0), - m_FreeCount(0), - m_SumFreeSize(0), - m_Suballocations(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - m_FreeSuballocationsBySize(VmaStlAllocator(hAllocator->GetAllocationCallbacks())) -{ -} - -VmaBlockMetadata::~VmaBlockMetadata() -{ -} - -void VmaBlockMetadata::Init(VkDeviceSize size) -{ - m_Size = size; - m_FreeCount = 1; - m_SumFreeSize = size; - - VmaSuballocation suballoc = {}; - suballoc.offset = 0; - suballoc.size = size; - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - suballoc.hAllocation = VK_NULL_HANDLE; - - m_Suballocations.push_back(suballoc); - VmaSuballocationList::iterator suballocItem = m_Suballocations.end(); - --suballocItem; - m_FreeSuballocationsBySize.push_back(suballocItem); -} - -bool VmaBlockMetadata::Validate() const -{ - if(m_Suballocations.empty()) - { - return false; - } - - // Expected offset of new suballocation as calculates from previous ones. - VkDeviceSize calculatedOffset = 0; - // Expected number of free suballocations as calculated from traversing their list. - uint32_t calculatedFreeCount = 0; - // Expected sum size of free suballocations as calculated from traversing their list. - VkDeviceSize calculatedSumFreeSize = 0; - // Expected number of free suballocations that should be registered in - // m_FreeSuballocationsBySize calculated from traversing their list. - size_t freeSuballocationsToRegister = 0; - // True if previous visisted suballocation was free. - bool prevFree = false; - - for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin(); - suballocItem != m_Suballocations.cend(); - ++suballocItem) - { - const VmaSuballocation& subAlloc = *suballocItem; - - // Actual offset of this suballocation doesn't match expected one. - if(subAlloc.offset != calculatedOffset) - { - return false; - } - - const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE); - // Two adjacent free suballocations are invalid. They should be merged. - if(prevFree && currFree) - { - return false; - } - - if(currFree != (subAlloc.hAllocation == VK_NULL_HANDLE)) - { - return false; - } - - if(currFree) - { - calculatedSumFreeSize += subAlloc.size; - ++calculatedFreeCount; - if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - ++freeSuballocationsToRegister; - } - } - else - { - if(subAlloc.hAllocation->GetOffset() != subAlloc.offset) - { - return false; - } - if(subAlloc.hAllocation->GetSize() != subAlloc.size) - { - return false; - } - } - - calculatedOffset += subAlloc.size; - prevFree = currFree; - } - - // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't - // match expected one. - if(m_FreeSuballocationsBySize.size() != freeSuballocationsToRegister) - { - return false; - } - - VkDeviceSize lastSize = 0; - for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i) - { - VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i]; - - // Only free suballocations can be registered in m_FreeSuballocationsBySize. - if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE) - { - return false; - } - // They must be sorted by size ascending. - if(suballocItem->size < lastSize) - { - return false; - } - - lastSize = suballocItem->size; - } - - // Check if totals match calculacted values. - if(!ValidateFreeSuballocationList() || - (calculatedOffset != m_Size) || - (calculatedSumFreeSize != m_SumFreeSize) || - (calculatedFreeCount != m_FreeCount)) - { - return false; - } - - return true; -} - -VkDeviceSize VmaBlockMetadata::GetUnusedRangeSizeMax() const -{ - if(!m_FreeSuballocationsBySize.empty()) - { - return m_FreeSuballocationsBySize.back()->size; - } - else - { - return 0; - } -} - -bool VmaBlockMetadata::IsEmpty() const -{ - return (m_Suballocations.size() == 1) && (m_FreeCount == 1); -} - -void VmaBlockMetadata::CalcAllocationStatInfo(VmaStatInfo& outInfo) const -{ - outInfo.blockCount = 1; - - const uint32_t rangeCount = (uint32_t)m_Suballocations.size(); - outInfo.allocationCount = rangeCount - m_FreeCount; - outInfo.unusedRangeCount = m_FreeCount; - - outInfo.unusedBytes = m_SumFreeSize; - outInfo.usedBytes = m_Size - outInfo.unusedBytes; - - outInfo.allocationSizeMin = UINT64_MAX; - outInfo.allocationSizeMax = 0; - outInfo.unusedRangeSizeMin = UINT64_MAX; - outInfo.unusedRangeSizeMax = 0; - - for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin(); - suballocItem != m_Suballocations.cend(); - ++suballocItem) - { - const VmaSuballocation& suballoc = *suballocItem; - if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE) - { - outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size); - outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size); - } - else - { - outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size); - outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size); - } - } -} - -void VmaBlockMetadata::AddPoolStats(VmaPoolStats& inoutStats) const -{ - const uint32_t rangeCount = (uint32_t)m_Suballocations.size(); - - inoutStats.size += m_Size; - inoutStats.unusedSize += m_SumFreeSize; - inoutStats.allocationCount += rangeCount - m_FreeCount; - inoutStats.unusedRangeCount += m_FreeCount; - inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax()); -} - -#if VMA_STATS_STRING_ENABLED - -void VmaBlockMetadata::PrintDetailedMap(class VmaJsonWriter& json) const -{ - json.BeginObject(); - - json.WriteString("TotalBytes"); - json.WriteNumber(m_Size); - - json.WriteString("UnusedBytes"); - json.WriteNumber(m_SumFreeSize); - - json.WriteString("Allocations"); - json.WriteNumber((uint64_t)m_Suballocations.size() - m_FreeCount); - - json.WriteString("UnusedRanges"); - json.WriteNumber(m_FreeCount); - - json.WriteString("Suballocations"); - json.BeginArray(); - size_t i = 0; - for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin(); - suballocItem != m_Suballocations.cend(); - ++suballocItem, ++i) - { - json.BeginObject(true); - - json.WriteString("Type"); - json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[suballocItem->type]); - - json.WriteString("Size"); - json.WriteNumber(suballocItem->size); - - json.WriteString("Offset"); - json.WriteNumber(suballocItem->offset); - - if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE) - { - const void* pUserData = suballocItem->hAllocation->GetUserData(); - if(pUserData != VMA_NULL) - { - json.WriteString("UserData"); - if(suballocItem->hAllocation->IsUserDataString()) - { - json.WriteString((const char*)pUserData); - } - else - { - json.BeginString(); - json.ContinueString_Pointer(pUserData); - json.EndString(); - } - } - } - - json.EndObject(); - } - json.EndArray(); - - json.EndObject(); -} - -#endif // #if VMA_STATS_STRING_ENABLED - -/* -How many suitable free suballocations to analyze before choosing best one. -- Set to 1 to use First-Fit algorithm - first suitable free suballocation will - be chosen. -- Set to UINT32_MAX to use Best-Fit/Worst-Fit algorithm - all suitable free - suballocations will be analized and best one will be chosen. -- Any other value is also acceptable. -*/ -//static const uint32_t MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK = 8; - -void VmaBlockMetadata::CreateFirstAllocationRequest(VmaAllocationRequest* pAllocationRequest) -{ - VMA_ASSERT(IsEmpty()); - pAllocationRequest->offset = 0; - pAllocationRequest->sumFreeSize = m_SumFreeSize; - pAllocationRequest->sumItemSize = 0; - pAllocationRequest->item = m_Suballocations.begin(); - pAllocationRequest->itemsToMakeLostCount = 0; -} - -bool VmaBlockMetadata::CreateAllocationRequest( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - bool canMakeOtherLost, - VmaAllocationRequest* pAllocationRequest) -{ - VMA_ASSERT(allocSize > 0); - VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(pAllocationRequest != VMA_NULL); - VMA_HEAVY_ASSERT(Validate()); - - // There is not enough total free space in this block to fullfill the request: Early return. - if(canMakeOtherLost == false && m_SumFreeSize < allocSize) - { - return false; - } - - // New algorithm, efficiently searching freeSuballocationsBySize. - const size_t freeSuballocCount = m_FreeSuballocationsBySize.size(); - if(freeSuballocCount > 0) - { - if(VMA_BEST_FIT) - { - // Find first free suballocation with size not less than allocSize. - VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( - m_FreeSuballocationsBySize.data(), - m_FreeSuballocationsBySize.data() + freeSuballocCount, - allocSize, - VmaSuballocationItemSizeLess()); - size_t index = it - m_FreeSuballocationsBySize.data(); - for(; index < freeSuballocCount; ++index) - { - if(CheckAllocation( - currentFrameIndex, - frameInUseCount, - bufferImageGranularity, - allocSize, - allocAlignment, - allocType, - m_FreeSuballocationsBySize[index], - false, // canMakeOtherLost - &pAllocationRequest->offset, - &pAllocationRequest->itemsToMakeLostCount, - &pAllocationRequest->sumFreeSize, - &pAllocationRequest->sumItemSize)) - { - pAllocationRequest->item = m_FreeSuballocationsBySize[index]; - return true; - } - } - } - else - { - // Search staring from biggest suballocations. - for(size_t index = freeSuballocCount; index--; ) - { - if(CheckAllocation( - currentFrameIndex, - frameInUseCount, - bufferImageGranularity, - allocSize, - allocAlignment, - allocType, - m_FreeSuballocationsBySize[index], - false, // canMakeOtherLost - &pAllocationRequest->offset, - &pAllocationRequest->itemsToMakeLostCount, - &pAllocationRequest->sumFreeSize, - &pAllocationRequest->sumItemSize)) - { - pAllocationRequest->item = m_FreeSuballocationsBySize[index]; - return true; - } - } - } - } - - if(canMakeOtherLost) - { - // Brute-force algorithm. TODO: Come up with something better. - - pAllocationRequest->sumFreeSize = VK_WHOLE_SIZE; - pAllocationRequest->sumItemSize = VK_WHOLE_SIZE; - - VmaAllocationRequest tmpAllocRequest = {}; - for(VmaSuballocationList::iterator suballocIt = m_Suballocations.begin(); - suballocIt != m_Suballocations.end(); - ++suballocIt) - { - if(suballocIt->type == VMA_SUBALLOCATION_TYPE_FREE || - suballocIt->hAllocation->CanBecomeLost()) - { - if(CheckAllocation( - currentFrameIndex, - frameInUseCount, - bufferImageGranularity, - allocSize, - allocAlignment, - allocType, - suballocIt, - canMakeOtherLost, - &tmpAllocRequest.offset, - &tmpAllocRequest.itemsToMakeLostCount, - &tmpAllocRequest.sumFreeSize, - &tmpAllocRequest.sumItemSize)) - { - tmpAllocRequest.item = suballocIt; - - if(tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost()) - { - *pAllocationRequest = tmpAllocRequest; - } - } - } - } - - if(pAllocationRequest->sumItemSize != VK_WHOLE_SIZE) - { - return true; - } - } - - return false; -} - -bool VmaBlockMetadata::MakeRequestedAllocationsLost( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VmaAllocationRequest* pAllocationRequest) -{ - while(pAllocationRequest->itemsToMakeLostCount > 0) - { - if(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE) - { - ++pAllocationRequest->item; - } - VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end()); - VMA_ASSERT(pAllocationRequest->item->hAllocation != VK_NULL_HANDLE); - VMA_ASSERT(pAllocationRequest->item->hAllocation->CanBecomeLost()); - if(pAllocationRequest->item->hAllocation->MakeLost(currentFrameIndex, frameInUseCount)) - { - pAllocationRequest->item = FreeSuballocation(pAllocationRequest->item); - --pAllocationRequest->itemsToMakeLostCount; - } - else - { - return false; - } - } - - VMA_HEAVY_ASSERT(Validate()); - VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end()); - VMA_ASSERT(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE); - - return true; -} - -uint32_t VmaBlockMetadata::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) -{ - uint32_t lostAllocationCount = 0; - for(VmaSuballocationList::iterator it = m_Suballocations.begin(); - it != m_Suballocations.end(); - ++it) - { - if(it->type != VMA_SUBALLOCATION_TYPE_FREE && - it->hAllocation->CanBecomeLost() && - it->hAllocation->MakeLost(currentFrameIndex, frameInUseCount)) - { - it = FreeSuballocation(it); - ++lostAllocationCount; - } - } - return lostAllocationCount; -} - -void VmaBlockMetadata::Alloc( - const VmaAllocationRequest& request, - VmaSuballocationType type, - VkDeviceSize allocSize, - VmaAllocation hAllocation) -{ - VMA_ASSERT(request.item != m_Suballocations.end()); - VmaSuballocation& suballoc = *request.item; - // Given suballocation is a free block. - VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); - // Given offset is inside this suballocation. - VMA_ASSERT(request.offset >= suballoc.offset); - const VkDeviceSize paddingBegin = request.offset - suballoc.offset; - VMA_ASSERT(suballoc.size >= paddingBegin + allocSize); - const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize; - - // Unregister this free suballocation from m_FreeSuballocationsBySize and update - // it to become used. - UnregisterFreeSuballocation(request.item); - - suballoc.offset = request.offset; - suballoc.size = allocSize; - suballoc.type = type; - suballoc.hAllocation = hAllocation; - - // If there are any free bytes remaining at the end, insert new free suballocation after current one. - if(paddingEnd) - { - VmaSuballocation paddingSuballoc = {}; - paddingSuballoc.offset = request.offset + allocSize; - paddingSuballoc.size = paddingEnd; - paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - VmaSuballocationList::iterator next = request.item; - ++next; - const VmaSuballocationList::iterator paddingEndItem = - m_Suballocations.insert(next, paddingSuballoc); - RegisterFreeSuballocation(paddingEndItem); - } - - // If there are any free bytes remaining at the beginning, insert new free suballocation before current one. - if(paddingBegin) - { - VmaSuballocation paddingSuballoc = {}; - paddingSuballoc.offset = request.offset - paddingBegin; - paddingSuballoc.size = paddingBegin; - paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - const VmaSuballocationList::iterator paddingBeginItem = - m_Suballocations.insert(request.item, paddingSuballoc); - RegisterFreeSuballocation(paddingBeginItem); - } - - // Update totals. - m_FreeCount = m_FreeCount - 1; - if(paddingBegin > 0) - { - ++m_FreeCount; - } - if(paddingEnd > 0) - { - ++m_FreeCount; - } - m_SumFreeSize -= allocSize; -} - -void VmaBlockMetadata::Free(const VmaAllocation allocation) -{ - for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin(); - suballocItem != m_Suballocations.end(); - ++suballocItem) - { - VmaSuballocation& suballoc = *suballocItem; - if(suballoc.hAllocation == allocation) - { - FreeSuballocation(suballocItem); - VMA_HEAVY_ASSERT(Validate()); - return; - } - } - VMA_ASSERT(0 && "Not found!"); -} - -void VmaBlockMetadata::FreeAtOffset(VkDeviceSize offset) -{ - for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin(); - suballocItem != m_Suballocations.end(); - ++suballocItem) - { - VmaSuballocation& suballoc = *suballocItem; - if(suballoc.offset == offset) - { - FreeSuballocation(suballocItem); - return; - } - } - VMA_ASSERT(0 && "Not found!"); -} - -bool VmaBlockMetadata::ValidateFreeSuballocationList() const -{ - VkDeviceSize lastSize = 0; - for(size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i) - { - const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i]; - - if(it->type != VMA_SUBALLOCATION_TYPE_FREE) - { - VMA_ASSERT(0); - return false; - } - if(it->size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - VMA_ASSERT(0); - return false; - } - if(it->size < lastSize) - { - VMA_ASSERT(0); - return false; - } - - lastSize = it->size; - } - return true; -} - -bool VmaBlockMetadata::CheckAllocation( - uint32_t currentFrameIndex, - uint32_t frameInUseCount, - VkDeviceSize bufferImageGranularity, - VkDeviceSize allocSize, - VkDeviceSize allocAlignment, - VmaSuballocationType allocType, - VmaSuballocationList::const_iterator suballocItem, - bool canMakeOtherLost, - VkDeviceSize* pOffset, - size_t* itemsToMakeLostCount, - VkDeviceSize* pSumFreeSize, - VkDeviceSize* pSumItemSize) const -{ - VMA_ASSERT(allocSize > 0); - VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(suballocItem != m_Suballocations.cend()); - VMA_ASSERT(pOffset != VMA_NULL); - - *itemsToMakeLostCount = 0; - *pSumFreeSize = 0; - *pSumItemSize = 0; - - if(canMakeOtherLost) - { - if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE) - { - *pSumFreeSize = suballocItem->size; - } - else - { - if(suballocItem->hAllocation->CanBecomeLost() && - suballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex) - { - ++*itemsToMakeLostCount; - *pSumItemSize = suballocItem->size; - } - else - { - return false; - } - } - - // Remaining size is too small for this request: Early return. - if(m_Size - suballocItem->offset < allocSize) - { - return false; - } - - // Start from offset equal to beginning of this suballocation. - *pOffset = suballocItem->offset; - - // Apply VMA_DEBUG_MARGIN at the beginning. - if((VMA_DEBUG_MARGIN > 0) && suballocItem != m_Suballocations.cbegin()) - { - *pOffset += VMA_DEBUG_MARGIN; - } - - // Apply alignment. - const VkDeviceSize alignment = VMA_MAX(allocAlignment, static_cast(VMA_DEBUG_ALIGNMENT)); - *pOffset = VmaAlignUp(*pOffset, alignment); - - // Check previous suballocations for BufferImageGranularity conflicts. - // Make bigger alignment if necessary. - if(bufferImageGranularity > 1) - { - bool bufferImageGranularityConflict = false; - VmaSuballocationList::const_iterator prevSuballocItem = suballocItem; - while(prevSuballocItem != m_Suballocations.cbegin()) - { - --prevSuballocItem; - const VmaSuballocation& prevSuballoc = *prevSuballocItem; - if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) - { - bufferImageGranularityConflict = true; - break; - } - } - else - // Already on previous page. - break; - } - if(bufferImageGranularityConflict) - { - *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity); - } - } - - // Now that we have final *pOffset, check if we are past suballocItem. - // If yes, return false - this function should be called for another suballocItem as starting point. - if(*pOffset >= suballocItem->offset + suballocItem->size) - { - return false; - } - - // Calculate padding at the beginning based on current offset. - const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset; - - // Calculate required margin at the end if this is not last suballocation. - VmaSuballocationList::const_iterator next = suballocItem; - ++next; - const VkDeviceSize requiredEndMargin = - (next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0; - - const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin; - // Another early return check. - if(suballocItem->offset + totalSize > m_Size) - { - return false; - } - - // Advance lastSuballocItem until desired size is reached. - // Update itemsToMakeLostCount. - VmaSuballocationList::const_iterator lastSuballocItem = suballocItem; - if(totalSize > suballocItem->size) - { - VkDeviceSize remainingSize = totalSize - suballocItem->size; - while(remainingSize > 0) - { - ++lastSuballocItem; - if(lastSuballocItem == m_Suballocations.cend()) - { - return false; - } - if(lastSuballocItem->type == VMA_SUBALLOCATION_TYPE_FREE) - { - *pSumFreeSize += lastSuballocItem->size; - } - else - { - VMA_ASSERT(lastSuballocItem->hAllocation != VK_NULL_HANDLE); - if(lastSuballocItem->hAllocation->CanBecomeLost() && - lastSuballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex) - { - ++*itemsToMakeLostCount; - *pSumItemSize += lastSuballocItem->size; - } - else - { - return false; - } - } - remainingSize = (lastSuballocItem->size < remainingSize) ? - remainingSize - lastSuballocItem->size : 0; - } - } - - // Check next suballocations for BufferImageGranularity conflicts. - // If conflict exists, we must mark more allocations lost or fail. - if(bufferImageGranularity > 1) - { - VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem; - ++nextSuballocItem; - while(nextSuballocItem != m_Suballocations.cend()) - { - const VmaSuballocation& nextSuballoc = *nextSuballocItem; - if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) - { - VMA_ASSERT(nextSuballoc.hAllocation != VK_NULL_HANDLE); - if(nextSuballoc.hAllocation->CanBecomeLost() && - nextSuballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex) - { - ++*itemsToMakeLostCount; - } - else - { - return false; - } - } - } - else - { - // Already on next page. - break; - } - ++nextSuballocItem; - } - } - } - else - { - const VmaSuballocation& suballoc = *suballocItem; - VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE); - - *pSumFreeSize = suballoc.size; - - // Size of this suballocation is too small for this request: Early return. - if(suballoc.size < allocSize) - { - return false; - } - - // Start from offset equal to beginning of this suballocation. - *pOffset = suballoc.offset; - - // Apply VMA_DEBUG_MARGIN at the beginning. - if((VMA_DEBUG_MARGIN > 0) && suballocItem != m_Suballocations.cbegin()) - { - *pOffset += VMA_DEBUG_MARGIN; - } - - // Apply alignment. - const VkDeviceSize alignment = VMA_MAX(allocAlignment, static_cast(VMA_DEBUG_ALIGNMENT)); - *pOffset = VmaAlignUp(*pOffset, alignment); - - // Check previous suballocations for BufferImageGranularity conflicts. - // Make bigger alignment if necessary. - if(bufferImageGranularity > 1) - { - bool bufferImageGranularityConflict = false; - VmaSuballocationList::const_iterator prevSuballocItem = suballocItem; - while(prevSuballocItem != m_Suballocations.cbegin()) - { - --prevSuballocItem; - const VmaSuballocation& prevSuballoc = *prevSuballocItem; - if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType)) - { - bufferImageGranularityConflict = true; - break; - } - } - else - // Already on previous page. - break; - } - if(bufferImageGranularityConflict) - { - *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity); - } - } - - // Calculate padding at the beginning based on current offset. - const VkDeviceSize paddingBegin = *pOffset - suballoc.offset; - - // Calculate required margin at the end if this is not last suballocation. - VmaSuballocationList::const_iterator next = suballocItem; - ++next; - const VkDeviceSize requiredEndMargin = - (next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0; - - // Fail if requested size plus margin before and after is bigger than size of this suballocation. - if(paddingBegin + allocSize + requiredEndMargin > suballoc.size) - { - return false; - } - - // Check next suballocations for BufferImageGranularity conflicts. - // If conflict exists, allocation cannot be made here. - if(bufferImageGranularity > 1) - { - VmaSuballocationList::const_iterator nextSuballocItem = suballocItem; - ++nextSuballocItem; - while(nextSuballocItem != m_Suballocations.cend()) - { - const VmaSuballocation& nextSuballoc = *nextSuballocItem; - if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity)) - { - if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type)) - { - return false; - } - } - else - { - // Already on next page. - break; - } - ++nextSuballocItem; - } - } - } - - // All tests passed: Success. pOffset is already filled. - return true; -} - -void VmaBlockMetadata::MergeFreeWithNext(VmaSuballocationList::iterator item) -{ - VMA_ASSERT(item != m_Suballocations.end()); - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - - VmaSuballocationList::iterator nextItem = item; - ++nextItem; - VMA_ASSERT(nextItem != m_Suballocations.end()); - VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE); - - item->size += nextItem->size; - --m_FreeCount; - m_Suballocations.erase(nextItem); -} - -VmaSuballocationList::iterator VmaBlockMetadata::FreeSuballocation(VmaSuballocationList::iterator suballocItem) -{ - // Change this suballocation to be marked as free. - VmaSuballocation& suballoc = *suballocItem; - suballoc.type = VMA_SUBALLOCATION_TYPE_FREE; - suballoc.hAllocation = VK_NULL_HANDLE; - - // Update totals. - ++m_FreeCount; - m_SumFreeSize += suballoc.size; - - // Merge with previous and/or next suballocation if it's also free. - bool mergeWithNext = false; - bool mergeWithPrev = false; - - VmaSuballocationList::iterator nextItem = suballocItem; - ++nextItem; - if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE)) - { - mergeWithNext = true; - } - - VmaSuballocationList::iterator prevItem = suballocItem; - if(suballocItem != m_Suballocations.begin()) - { - --prevItem; - if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE) - { - mergeWithPrev = true; - } - } - - if(mergeWithNext) - { - UnregisterFreeSuballocation(nextItem); - MergeFreeWithNext(suballocItem); - } - - if(mergeWithPrev) - { - UnregisterFreeSuballocation(prevItem); - MergeFreeWithNext(prevItem); - RegisterFreeSuballocation(prevItem); - return prevItem; - } - else - { - RegisterFreeSuballocation(suballocItem); - return suballocItem; - } -} - -void VmaBlockMetadata::RegisterFreeSuballocation(VmaSuballocationList::iterator item) -{ - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(item->size > 0); - - // You may want to enable this validation at the beginning or at the end of - // this function, depending on what do you want to check. - VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); - - if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - if(m_FreeSuballocationsBySize.empty()) - { - m_FreeSuballocationsBySize.push_back(item); - } - else - { - VmaVectorInsertSorted(m_FreeSuballocationsBySize, item); - } - } - - //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); -} - - -void VmaBlockMetadata::UnregisterFreeSuballocation(VmaSuballocationList::iterator item) -{ - VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE); - VMA_ASSERT(item->size > 0); - - // You may want to enable this validation at the beginning or at the end of - // this function, depending on what do you want to check. - VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); - - if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess( - m_FreeSuballocationsBySize.data(), - m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(), - item, - VmaSuballocationItemSizeLess()); - for(size_t index = it - m_FreeSuballocationsBySize.data(); - index < m_FreeSuballocationsBySize.size(); - ++index) - { - if(m_FreeSuballocationsBySize[index] == item) - { - VmaVectorRemove(m_FreeSuballocationsBySize, index); - return; - } - VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found."); - } - VMA_ASSERT(0 && "Not found."); - } - - //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList()); -} - -//////////////////////////////////////////////////////////////////////////////// -// class VmaDeviceMemoryBlock - -VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) : - m_Metadata(hAllocator), - m_MemoryTypeIndex(UINT32_MAX), - m_hMemory(VK_NULL_HANDLE), - m_MapCount(0), - m_pMappedData(VMA_NULL) -{ -} - -void VmaDeviceMemoryBlock::Init( - uint32_t newMemoryTypeIndex, - VkDeviceMemory newMemory, - VkDeviceSize newSize) -{ - VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); - - m_MemoryTypeIndex = newMemoryTypeIndex; - m_hMemory = newMemory; - - m_Metadata.Init(newSize); -} - -void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator) -{ - // This is the most important assert in the entire library. - // Hitting it means you have some memory leak - unreleased VmaAllocation objects. - VMA_ASSERT(m_Metadata.IsEmpty() && "Some allocations were not freed before destruction of this memory block!"); - - VMA_ASSERT(m_hMemory != VK_NULL_HANDLE); - allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_Metadata.GetSize(), m_hMemory); - m_hMemory = VK_NULL_HANDLE; -} - -bool VmaDeviceMemoryBlock::Validate() const -{ - if((m_hMemory == VK_NULL_HANDLE) || - (m_Metadata.GetSize() == 0)) - { - return false; - } - - return m_Metadata.Validate(); -} - -VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData) -{ - if(count == 0) - { - return VK_SUCCESS; - } - - VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex); - if(m_MapCount != 0) - { - m_MapCount += count; - VMA_ASSERT(m_pMappedData != VMA_NULL); - if(ppData != VMA_NULL) - { - *ppData = m_pMappedData; - } - return VK_SUCCESS; - } - else - { - VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)( - hAllocator->m_hDevice, - m_hMemory, - 0, // offset - VK_WHOLE_SIZE, - 0, // flags - &m_pMappedData); - if(result == VK_SUCCESS) - { - if(ppData != VMA_NULL) - { - *ppData = m_pMappedData; - } - m_MapCount = count; - } - return result; - } -} - -void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count) -{ - if(count == 0) - { - return; - } - - VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex); - if(m_MapCount >= count) - { - m_MapCount -= count; - if(m_MapCount == 0) - { - m_pMappedData = VMA_NULL; - (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); - } - } - else - { - VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped."); - } -} - -VkResult VmaDeviceMemoryBlock::BindBufferMemory( - const VmaAllocator hAllocator, - const VmaAllocation hAllocation, - VkBuffer hBuffer) -{ - VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK && - hAllocation->GetBlock() == this); - // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads. - VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex); - return hAllocator->GetVulkanFunctions().vkBindBufferMemory( - hAllocator->m_hDevice, - hBuffer, - m_hMemory, - hAllocation->GetOffset()); -} - -VkResult VmaDeviceMemoryBlock::BindImageMemory( - const VmaAllocator hAllocator, - const VmaAllocation hAllocation, - VkImage hImage) -{ - VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK && - hAllocation->GetBlock() == this); - // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads. - VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex); - return hAllocator->GetVulkanFunctions().vkBindImageMemory( - hAllocator->m_hDevice, - hImage, - m_hMemory, - hAllocation->GetOffset()); -} - -static void InitStatInfo(VmaStatInfo& outInfo) -{ - memset(&outInfo, 0, sizeof(outInfo)); - outInfo.allocationSizeMin = UINT64_MAX; - outInfo.unusedRangeSizeMin = UINT64_MAX; -} - -// Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo. -static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo) -{ - inoutInfo.blockCount += srcInfo.blockCount; - inoutInfo.allocationCount += srcInfo.allocationCount; - inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount; - inoutInfo.usedBytes += srcInfo.usedBytes; - inoutInfo.unusedBytes += srcInfo.unusedBytes; - inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin); - inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax); - inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin); - inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax); -} - -static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo) -{ - inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ? - VmaRoundDiv(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0; - inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ? - VmaRoundDiv(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0; -} - -VmaPool_T::VmaPool_T( - VmaAllocator hAllocator, - const VmaPoolCreateInfo& createInfo) : - m_BlockVector( - hAllocator, - createInfo.memoryTypeIndex, - createInfo.blockSize, - createInfo.minBlockCount, - createInfo.maxBlockCount, - (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(), - createInfo.frameInUseCount, - true) // isCustomPool -{ -} - -VmaPool_T::~VmaPool_T() -{ -} - -#if VMA_STATS_STRING_ENABLED - -#endif // #if VMA_STATS_STRING_ENABLED - -VmaBlockVector::VmaBlockVector( - VmaAllocator hAllocator, - uint32_t memoryTypeIndex, - VkDeviceSize preferredBlockSize, - size_t minBlockCount, - size_t maxBlockCount, - VkDeviceSize bufferImageGranularity, - uint32_t frameInUseCount, - bool isCustomPool) : - m_hAllocator(hAllocator), - m_MemoryTypeIndex(memoryTypeIndex), - m_PreferredBlockSize(preferredBlockSize), - m_MinBlockCount(minBlockCount), - m_MaxBlockCount(maxBlockCount), - m_BufferImageGranularity(bufferImageGranularity), - m_FrameInUseCount(frameInUseCount), - m_IsCustomPool(isCustomPool), - m_Blocks(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - m_HasEmptyBlock(false), - m_pDefragmentator(VMA_NULL) -{ -} - -VmaBlockVector::~VmaBlockVector() -{ - VMA_ASSERT(m_pDefragmentator == VMA_NULL); - - for(size_t i = m_Blocks.size(); i--; ) - { - m_Blocks[i]->Destroy(m_hAllocator); - vma_delete(m_hAllocator, m_Blocks[i]); - } -} - -VkResult VmaBlockVector::CreateMinBlocks() -{ - for(size_t i = 0; i < m_MinBlockCount; ++i) - { - VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL); - if(res != VK_SUCCESS) - { - return res; - } - } - return VK_SUCCESS; -} - -void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats) -{ - pStats->size = 0; - pStats->unusedSize = 0; - pStats->allocationCount = 0; - pStats->unusedRangeCount = 0; - pStats->unusedRangeSizeMax = 0; - - VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex); - - for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) - { - const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pBlock); - VMA_HEAVY_ASSERT(pBlock->Validate()); - pBlock->m_Metadata.AddPoolStats(*pStats); - } -} - -static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32; - -VkResult VmaBlockVector::Allocate( - VmaPool hCurrentPool, - uint32_t currentFrameIndex, - const VkMemoryRequirements& vkMemReq, - const VmaAllocationCreateInfo& createInfo, - VmaSuballocationType suballocType, - VmaAllocation* pAllocation) -{ - const bool mapped = (createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0; - const bool isUserDataString = (createInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0; - - VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex); - - // 1. Search existing allocations. Try to allocate without making other allocations lost. - // Forward order in m_Blocks - prefer blocks with smallest amount of free space. - for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex ) - { - VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pCurrBlock); - VmaAllocationRequest currRequest = {}; - if(pCurrBlock->m_Metadata.CreateAllocationRequest( - currentFrameIndex, - m_FrameInUseCount, - m_BufferImageGranularity, - vkMemReq.size, - vkMemReq.alignment, - suballocType, - false, // canMakeOtherLost - &currRequest)) - { - // Allocate from pCurrBlock. - VMA_ASSERT(currRequest.itemsToMakeLostCount == 0); - - if(mapped) - { - VkResult res = pCurrBlock->Map(m_hAllocator, 1, VMA_NULL); - if(res != VK_SUCCESS) - { - return res; - } - } - - // We no longer have an empty Allocation. - if(pCurrBlock->m_Metadata.IsEmpty()) - { - m_HasEmptyBlock = false; - } - - *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString); - pCurrBlock->m_Metadata.Alloc(currRequest, suballocType, vkMemReq.size, *pAllocation); - (*pAllocation)->InitBlockAllocation( - hCurrentPool, - pCurrBlock, - currRequest.offset, - vkMemReq.alignment, - vkMemReq.size, - suballocType, - mapped, - (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0); - VMA_HEAVY_ASSERT(pCurrBlock->Validate()); - VMA_DEBUG_LOG(" Returned from existing allocation #%u", (uint32_t)blockIndex); - (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData); - return VK_SUCCESS; - } - } - - const bool canCreateNewBlock = - ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) && - (m_Blocks.size() < m_MaxBlockCount); - - // 2. Try to create new block. - if(canCreateNewBlock) - { - // Calculate optimal size for new block. - VkDeviceSize newBlockSize = m_PreferredBlockSize; - uint32_t newBlockSizeShift = 0; - const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3; - - // Allocating blocks of other sizes is allowed only in default pools. - // In custom pools block size is fixed. - if(m_IsCustomPool == false) - { - // Allocate 1/8, 1/4, 1/2 as first blocks. - const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize(); - for(uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i) - { - const VkDeviceSize smallerNewBlockSize = newBlockSize / 2; - if(smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= vkMemReq.size * 2) - { - newBlockSize = smallerNewBlockSize; - ++newBlockSizeShift; - } - else - { - break; - } - } - } - - size_t newBlockIndex = 0; - VkResult res = CreateBlock(newBlockSize, &newBlockIndex); - // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize. - if(m_IsCustomPool == false) - { - while(res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX) - { - const VkDeviceSize smallerNewBlockSize = newBlockSize / 2; - if(smallerNewBlockSize >= vkMemReq.size) - { - newBlockSize = smallerNewBlockSize; - ++newBlockSizeShift; - res = CreateBlock(newBlockSize, &newBlockIndex); - } - else - { - break; - } - } - } - - if(res == VK_SUCCESS) - { - VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex]; - VMA_ASSERT(pBlock->m_Metadata.GetSize() >= vkMemReq.size); - - if(mapped) - { - res = pBlock->Map(m_hAllocator, 1, VMA_NULL); - if(res != VK_SUCCESS) - { - return res; - } - } - - // Allocate from pBlock. Because it is empty, dstAllocRequest can be trivially filled. - VmaAllocationRequest allocRequest; - pBlock->m_Metadata.CreateFirstAllocationRequest(&allocRequest); - *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString); - pBlock->m_Metadata.Alloc(allocRequest, suballocType, vkMemReq.size, *pAllocation); - (*pAllocation)->InitBlockAllocation( - hCurrentPool, - pBlock, - allocRequest.offset, - vkMemReq.alignment, - vkMemReq.size, - suballocType, - mapped, - (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0); - VMA_HEAVY_ASSERT(pBlock->Validate()); - VMA_DEBUG_LOG(" Created new allocation Size=%llu", allocInfo.allocationSize); - (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData); - return VK_SUCCESS; - } - } - - const bool canMakeOtherLost = (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) != 0; - - // 3. Try to allocate from existing blocks with making other allocations lost. - if(canMakeOtherLost) - { - uint32_t tryIndex = 0; - for(; tryIndex < VMA_ALLOCATION_TRY_COUNT; ++tryIndex) - { - VmaDeviceMemoryBlock* pBestRequestBlock = VMA_NULL; - VmaAllocationRequest bestRequest = {}; - VkDeviceSize bestRequestCost = VK_WHOLE_SIZE; - - // 1. Search existing allocations. - // Forward order in m_Blocks - prefer blocks with smallest amount of free space. - for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex ) - { - VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pCurrBlock); - VmaAllocationRequest currRequest = {}; - if(pCurrBlock->m_Metadata.CreateAllocationRequest( - currentFrameIndex, - m_FrameInUseCount, - m_BufferImageGranularity, - vkMemReq.size, - vkMemReq.alignment, - suballocType, - canMakeOtherLost, - &currRequest)) - { - const VkDeviceSize currRequestCost = currRequest.CalcCost(); - if(pBestRequestBlock == VMA_NULL || - currRequestCost < bestRequestCost) - { - pBestRequestBlock = pCurrBlock; - bestRequest = currRequest; - bestRequestCost = currRequestCost; - - if(bestRequestCost == 0) - { - break; - } - } - } - } - - if(pBestRequestBlock != VMA_NULL) - { - if(mapped) - { - VkResult res = pBestRequestBlock->Map(m_hAllocator, 1, VMA_NULL); - if(res != VK_SUCCESS) - { - return res; - } - } - - if(pBestRequestBlock->m_Metadata.MakeRequestedAllocationsLost( - currentFrameIndex, - m_FrameInUseCount, - &bestRequest)) - { - // We no longer have an empty Allocation. - if(pBestRequestBlock->m_Metadata.IsEmpty()) - { - m_HasEmptyBlock = false; - } - // Allocate from this pBlock. - *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString); - pBestRequestBlock->m_Metadata.Alloc(bestRequest, suballocType, vkMemReq.size, *pAllocation); - (*pAllocation)->InitBlockAllocation( - hCurrentPool, - pBestRequestBlock, - bestRequest.offset, - vkMemReq.alignment, - vkMemReq.size, - suballocType, - mapped, - (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0); - VMA_HEAVY_ASSERT(pBestRequestBlock->Validate()); - VMA_DEBUG_LOG(" Returned from existing allocation #%u", (uint32_t)blockIndex); - (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData); - return VK_SUCCESS; - } - // else: Some allocations must have been touched while we are here. Next try. - } - else - { - // Could not find place in any of the blocks - break outer loop. - break; - } - } - /* Maximum number of tries exceeded - a very unlike event when many other - threads are simultaneously touching allocations making it impossible to make - lost at the same time as we try to allocate. */ - if(tryIndex == VMA_ALLOCATION_TRY_COUNT) - { - return VK_ERROR_TOO_MANY_OBJECTS; - } - } - - return VK_ERROR_OUT_OF_DEVICE_MEMORY; -} - -void VmaBlockVector::Free( - VmaAllocation hAllocation) -{ - VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL; - - // Scope for lock. - { - VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex); - - VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock(); - - if(hAllocation->IsPersistentMap()) - { - pBlock->Unmap(m_hAllocator, 1); - } - - pBlock->m_Metadata.Free(hAllocation); - VMA_HEAVY_ASSERT(pBlock->Validate()); - - VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", memTypeIndex); - - // pBlock became empty after this deallocation. - if(pBlock->m_Metadata.IsEmpty()) - { - // Already has empty Allocation. We don't want to have two, so delete this one. - if(m_HasEmptyBlock && m_Blocks.size() > m_MinBlockCount) - { - pBlockToDelete = pBlock; - Remove(pBlock); - } - // We now have first empty Allocation. - else - { - m_HasEmptyBlock = true; - } - } - // pBlock didn't become empty, but we have another empty block - find and free that one. - // (This is optional, heuristics.) - else if(m_HasEmptyBlock) - { - VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back(); - if(pLastBlock->m_Metadata.IsEmpty() && m_Blocks.size() > m_MinBlockCount) - { - pBlockToDelete = pLastBlock; - m_Blocks.pop_back(); - m_HasEmptyBlock = false; - } - } - - IncrementallySortBlocks(); - } - - // Destruction of a free Allocation. Deferred until this point, outside of mutex - // lock, for performance reason. - if(pBlockToDelete != VMA_NULL) - { - VMA_DEBUG_LOG(" Deleted empty allocation"); - pBlockToDelete->Destroy(m_hAllocator); - vma_delete(m_hAllocator, pBlockToDelete); - } -} - -size_t VmaBlockVector::CalcMaxBlockSize() const -{ - size_t result = 0; - for(size_t i = m_Blocks.size(); i--; ) - { - result = VMA_MAX((uint64_t)result, (uint64_t)m_Blocks[i]->m_Metadata.GetSize()); - if(result >= m_PreferredBlockSize) - { - break; - } - } - return result; -} - -void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock) -{ - for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) - { - if(m_Blocks[blockIndex] == pBlock) - { - VmaVectorRemove(m_Blocks, blockIndex); - return; - } - } - VMA_ASSERT(0); -} - -void VmaBlockVector::IncrementallySortBlocks() -{ - // Bubble sort only until first swap. - for(size_t i = 1; i < m_Blocks.size(); ++i) - { - if(m_Blocks[i - 1]->m_Metadata.GetSumFreeSize() > m_Blocks[i]->m_Metadata.GetSumFreeSize()) - { - VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]); - return; - } - } -} - -VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex) -{ - VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocInfo.memoryTypeIndex = m_MemoryTypeIndex; - allocInfo.allocationSize = blockSize; - VkDeviceMemory mem = VK_NULL_HANDLE; - VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem); - if(res < 0) - { - return res; - } - - // New VkDeviceMemory successfully created. - - // Create new Allocation for it. - VmaDeviceMemoryBlock* const pBlock = vma_new(m_hAllocator, VmaDeviceMemoryBlock)(m_hAllocator); - pBlock->Init( - m_MemoryTypeIndex, - mem, - allocInfo.allocationSize); - - m_Blocks.push_back(pBlock); - if(pNewBlockIndex != VMA_NULL) - { - *pNewBlockIndex = m_Blocks.size() - 1; - } - - return VK_SUCCESS; -} - -#if VMA_STATS_STRING_ENABLED - -void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json) -{ - VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex); - - json.BeginObject(); - - if(m_IsCustomPool) - { - json.WriteString("MemoryTypeIndex"); - json.WriteNumber(m_MemoryTypeIndex); - - json.WriteString("BlockSize"); - json.WriteNumber(m_PreferredBlockSize); - - json.WriteString("BlockCount"); - json.BeginObject(true); - if(m_MinBlockCount > 0) - { - json.WriteString("Min"); - json.WriteNumber((uint64_t)m_MinBlockCount); - } - if(m_MaxBlockCount < SIZE_MAX) - { - json.WriteString("Max"); - json.WriteNumber((uint64_t)m_MaxBlockCount); - } - json.WriteString("Cur"); - json.WriteNumber((uint64_t)m_Blocks.size()); - json.EndObject(); - - if(m_FrameInUseCount > 0) - { - json.WriteString("FrameInUseCount"); - json.WriteNumber(m_FrameInUseCount); - } - } - else - { - json.WriteString("PreferredBlockSize"); - json.WriteNumber(m_PreferredBlockSize); - } - - json.WriteString("Blocks"); - json.BeginArray(); - for(size_t i = 0; i < m_Blocks.size(); ++i) - { - m_Blocks[i]->m_Metadata.PrintDetailedMap(json); - } - json.EndArray(); - - json.EndObject(); -} - -#endif // #if VMA_STATS_STRING_ENABLED - -VmaDefragmentator* VmaBlockVector::EnsureDefragmentator( - VmaAllocator hAllocator, - uint32_t currentFrameIndex) -{ - if(m_pDefragmentator == VMA_NULL) - { - m_pDefragmentator = vma_new(m_hAllocator, VmaDefragmentator)( - hAllocator, - this, - currentFrameIndex); - } - - return m_pDefragmentator; -} - -VkResult VmaBlockVector::Defragment( - VmaDefragmentationStats* pDefragmentationStats, - VkDeviceSize& maxBytesToMove, - uint32_t& maxAllocationsToMove) -{ - if(m_pDefragmentator == VMA_NULL) - { - return VK_SUCCESS; - } - - VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex); - - // Defragment. - VkResult result = m_pDefragmentator->Defragment(maxBytesToMove, maxAllocationsToMove); - - // Accumulate statistics. - if(pDefragmentationStats != VMA_NULL) - { - const VkDeviceSize bytesMoved = m_pDefragmentator->GetBytesMoved(); - const uint32_t allocationsMoved = m_pDefragmentator->GetAllocationsMoved(); - pDefragmentationStats->bytesMoved += bytesMoved; - pDefragmentationStats->allocationsMoved += allocationsMoved; - VMA_ASSERT(bytesMoved <= maxBytesToMove); - VMA_ASSERT(allocationsMoved <= maxAllocationsToMove); - maxBytesToMove -= bytesMoved; - maxAllocationsToMove -= allocationsMoved; - } - - // Free empty blocks. - m_HasEmptyBlock = false; - for(size_t blockIndex = m_Blocks.size(); blockIndex--; ) - { - VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex]; - if(pBlock->m_Metadata.IsEmpty()) - { - if(m_Blocks.size() > m_MinBlockCount) - { - if(pDefragmentationStats != VMA_NULL) - { - ++pDefragmentationStats->deviceMemoryBlocksFreed; - pDefragmentationStats->bytesFreed += pBlock->m_Metadata.GetSize(); - } - - VmaVectorRemove(m_Blocks, blockIndex); - pBlock->Destroy(m_hAllocator); - vma_delete(m_hAllocator, pBlock); - } - else - { - m_HasEmptyBlock = true; - } - } - } - - return result; -} - -void VmaBlockVector::DestroyDefragmentator() -{ - if(m_pDefragmentator != VMA_NULL) - { - vma_delete(m_hAllocator, m_pDefragmentator); - m_pDefragmentator = VMA_NULL; - } -} - -void VmaBlockVector::MakePoolAllocationsLost( - uint32_t currentFrameIndex, - size_t* pLostAllocationCount) -{ - VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex); - size_t lostAllocationCount = 0; - for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) - { - VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pBlock); - lostAllocationCount += pBlock->m_Metadata.MakeAllocationsLost(currentFrameIndex, m_FrameInUseCount); - } - if(pLostAllocationCount != VMA_NULL) - { - *pLostAllocationCount = lostAllocationCount; - } -} - -void VmaBlockVector::AddStats(VmaStats* pStats) -{ - const uint32_t memTypeIndex = m_MemoryTypeIndex; - const uint32_t memHeapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(memTypeIndex); - - VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex); - - for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) - { - const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex]; - VMA_ASSERT(pBlock); - VMA_HEAVY_ASSERT(pBlock->Validate()); - VmaStatInfo allocationStatInfo; - pBlock->m_Metadata.CalcAllocationStatInfo(allocationStatInfo); - VmaAddStatInfo(pStats->total, allocationStatInfo); - VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo); - VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// VmaDefragmentator members definition - -VmaDefragmentator::VmaDefragmentator( - VmaAllocator hAllocator, - VmaBlockVector* pBlockVector, - uint32_t currentFrameIndex) : - m_hAllocator(hAllocator), - m_pBlockVector(pBlockVector), - m_CurrentFrameIndex(currentFrameIndex), - m_BytesMoved(0), - m_AllocationsMoved(0), - m_Allocations(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), - m_Blocks(VmaStlAllocator(hAllocator->GetAllocationCallbacks())) -{ -} - -VmaDefragmentator::~VmaDefragmentator() -{ - for(size_t i = m_Blocks.size(); i--; ) - { - vma_delete(m_hAllocator, m_Blocks[i]); - } -} - -void VmaDefragmentator::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) -{ - AllocationInfo allocInfo; - allocInfo.m_hAllocation = hAlloc; - allocInfo.m_pChanged = pChanged; - m_Allocations.push_back(allocInfo); -} - -VkResult VmaDefragmentator::BlockInfo::EnsureMapping(VmaAllocator hAllocator, void** ppMappedData) -{ - // It has already been mapped for defragmentation. - if(m_pMappedDataForDefragmentation) - { - *ppMappedData = m_pMappedDataForDefragmentation; - return VK_SUCCESS; - } - - // It is originally mapped. - if(m_pBlock->GetMappedData()) - { - *ppMappedData = m_pBlock->GetMappedData(); - return VK_SUCCESS; - } - - // Map on first usage. - VkResult res = m_pBlock->Map(hAllocator, 1, &m_pMappedDataForDefragmentation); - *ppMappedData = m_pMappedDataForDefragmentation; - return res; -} - -void VmaDefragmentator::BlockInfo::Unmap(VmaAllocator hAllocator) -{ - if(m_pMappedDataForDefragmentation != VMA_NULL) - { - m_pBlock->Unmap(hAllocator, 1); - } -} - -VkResult VmaDefragmentator::DefragmentRound( - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove) -{ - if(m_Blocks.empty()) - { - return VK_SUCCESS; - } - - size_t srcBlockIndex = m_Blocks.size() - 1; - size_t srcAllocIndex = SIZE_MAX; - for(;;) - { - // 1. Find next allocation to move. - // 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source". - // 1.2. Then start from last to first m_Allocations - they are sorted from largest to smallest. - while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size()) - { - if(m_Blocks[srcBlockIndex]->m_Allocations.empty()) - { - // Finished: no more allocations to process. - if(srcBlockIndex == 0) - { - return VK_SUCCESS; - } - else - { - --srcBlockIndex; - srcAllocIndex = SIZE_MAX; - } - } - else - { - srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1; - } - } - - BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex]; - AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex]; - - const VkDeviceSize size = allocInfo.m_hAllocation->GetSize(); - const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset(); - const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment(); - const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType(); - - // 2. Try to find new place for this allocation in preceding or current block. - for(size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex) - { - BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex]; - VmaAllocationRequest dstAllocRequest; - if(pDstBlockInfo->m_pBlock->m_Metadata.CreateAllocationRequest( - m_CurrentFrameIndex, - m_pBlockVector->GetFrameInUseCount(), - m_pBlockVector->GetBufferImageGranularity(), - size, - alignment, - suballocType, - false, // canMakeOtherLost - &dstAllocRequest) && - MoveMakesSense( - dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset)) - { - VMA_ASSERT(dstAllocRequest.itemsToMakeLostCount == 0); - - // Reached limit on number of allocations or bytes to move. - if((m_AllocationsMoved + 1 > maxAllocationsToMove) || - (m_BytesMoved + size > maxBytesToMove)) - { - return VK_INCOMPLETE; - } - - void* pDstMappedData = VMA_NULL; - VkResult res = pDstBlockInfo->EnsureMapping(m_hAllocator, &pDstMappedData); - if(res != VK_SUCCESS) - { - return res; - } - - void* pSrcMappedData = VMA_NULL; - res = pSrcBlockInfo->EnsureMapping(m_hAllocator, &pSrcMappedData); - if(res != VK_SUCCESS) - { - return res; - } - - // THE PLACE WHERE ACTUAL DATA COPY HAPPENS. - memcpy( - reinterpret_cast(pDstMappedData) + dstAllocRequest.offset, - reinterpret_cast(pSrcMappedData) + srcOffset, - static_cast(size)); - - pDstBlockInfo->m_pBlock->m_Metadata.Alloc(dstAllocRequest, suballocType, size, allocInfo.m_hAllocation); - pSrcBlockInfo->m_pBlock->m_Metadata.FreeAtOffset(srcOffset); - - allocInfo.m_hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlockInfo->m_pBlock, dstAllocRequest.offset); - - if(allocInfo.m_pChanged != VMA_NULL) - { - *allocInfo.m_pChanged = VK_TRUE; - } - - ++m_AllocationsMoved; - m_BytesMoved += size; - - VmaVectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex); - - break; - } - } - - // If not processed, this allocInfo remains in pBlockInfo->m_Allocations for next round. - - if(srcAllocIndex > 0) - { - --srcAllocIndex; - } - else - { - if(srcBlockIndex > 0) - { - --srcBlockIndex; - srcAllocIndex = SIZE_MAX; - } - else - { - return VK_SUCCESS; - } - } - } -} - -VkResult VmaDefragmentator::Defragment( - VkDeviceSize maxBytesToMove, - uint32_t maxAllocationsToMove) -{ - if(m_Allocations.empty()) - { - return VK_SUCCESS; - } - - // Create block info for each block. - const size_t blockCount = m_pBlockVector->m_Blocks.size(); - for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) - { - BlockInfo* pBlockInfo = vma_new(m_hAllocator, BlockInfo)(m_hAllocator->GetAllocationCallbacks()); - pBlockInfo->m_pBlock = m_pBlockVector->m_Blocks[blockIndex]; - m_Blocks.push_back(pBlockInfo); - } - - // Sort them by m_pBlock pointer value. - VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess()); - - // Move allocation infos from m_Allocations to appropriate m_Blocks[memTypeIndex].m_Allocations. - for(size_t blockIndex = 0, allocCount = m_Allocations.size(); blockIndex < allocCount; ++blockIndex) - { - AllocationInfo& allocInfo = m_Allocations[blockIndex]; - // Now as we are inside VmaBlockVector::m_Mutex, we can make final check if this allocation was not lost. - if(allocInfo.m_hAllocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST) - { - VmaDeviceMemoryBlock* pBlock = allocInfo.m_hAllocation->GetBlock(); - BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess()); - if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock) - { - (*it)->m_Allocations.push_back(allocInfo); - } - else - { - VMA_ASSERT(0); - } - } - } - m_Allocations.clear(); - - for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) - { - BlockInfo* pBlockInfo = m_Blocks[blockIndex]; - pBlockInfo->CalcHasNonMovableAllocations(); - pBlockInfo->SortAllocationsBySizeDescecnding(); - } - - // Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks. - VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination()); - - // Execute defragmentation rounds (the main part). - VkResult result = VK_SUCCESS; - for(size_t round = 0; (round < 2) && (result == VK_SUCCESS); ++round) - { - result = DefragmentRound(maxBytesToMove, maxAllocationsToMove); - } - - // Unmap blocks that were mapped for defragmentation. - for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex) - { - m_Blocks[blockIndex]->Unmap(m_hAllocator); - } - - return result; -} - -bool VmaDefragmentator::MoveMakesSense( - size_t dstBlockIndex, VkDeviceSize dstOffset, - size_t srcBlockIndex, VkDeviceSize srcOffset) -{ - if(dstBlockIndex < srcBlockIndex) - { - return true; - } - if(dstBlockIndex > srcBlockIndex) - { - return false; - } - if(dstOffset < srcOffset) - { - return true; - } - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// VmaAllocator_T - -VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : - m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0), - m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0), - m_hDevice(pCreateInfo->device), - m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), - m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ? - *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks), - m_PreferredLargeHeapBlockSize(0), - m_PhysicalDevice(pCreateInfo->physicalDevice), - m_CurrentFrameIndex(0), - m_Pools(VmaStlAllocator(GetAllocationCallbacks())) -{ - VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device); - - memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); - memset(&m_MemProps, 0, sizeof(m_MemProps)); - memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); - - memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors)); - memset(&m_pDedicatedAllocations, 0, sizeof(m_pDedicatedAllocations)); - - for(uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) - { - m_HeapSizeLimit[i] = VK_WHOLE_SIZE; - } - - if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) - { - m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate; - m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree; - } - - ImportVulkanFunctions(pCreateInfo->pVulkanFunctions); - - (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); - (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); - - m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ? - pCreateInfo->preferredLargeHeapBlockSize : static_cast(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE); - - if(pCreateInfo->pHeapSizeLimit != VMA_NULL) - { - for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) - { - const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex]; - if(limit != VK_WHOLE_SIZE) - { - m_HeapSizeLimit[heapIndex] = limit; - if(limit < m_MemProps.memoryHeaps[heapIndex].size) - { - m_MemProps.memoryHeaps[heapIndex].size = limit; - } - } - } - } - - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex); - - m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)( - this, - memTypeIndex, - preferredBlockSize, - 0, - SIZE_MAX, - GetBufferImageGranularity(), - pCreateInfo->frameInUseCount, - false); // isCustomPool - // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here, - // becase minBlockCount is 0. - m_pDedicatedAllocations[memTypeIndex] = vma_new(this, AllocationVectorType)(VmaStlAllocator(GetAllocationCallbacks())); - } -} - -VmaAllocator_T::~VmaAllocator_T() -{ - VMA_ASSERT(m_Pools.empty()); - - for(size_t i = GetMemoryTypeCount(); i--; ) - { - vma_delete(this, m_pDedicatedAllocations[i]); - vma_delete(this, m_pBlockVectors[i]); - } -} - -void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions) -{ -#if VMA_STATIC_VULKAN_FUNCTIONS == 1 - m_VulkanFunctions.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties; - m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties; - m_VulkanFunctions.vkAllocateMemory = vkAllocateMemory; - m_VulkanFunctions.vkFreeMemory = vkFreeMemory; - m_VulkanFunctions.vkMapMemory = vkMapMemory; - m_VulkanFunctions.vkUnmapMemory = vkUnmapMemory; - m_VulkanFunctions.vkBindBufferMemory = vkBindBufferMemory; - m_VulkanFunctions.vkBindImageMemory = vkBindImageMemory; - m_VulkanFunctions.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements; - m_VulkanFunctions.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements; - m_VulkanFunctions.vkCreateBuffer = vkCreateBuffer; - m_VulkanFunctions.vkDestroyBuffer = vkDestroyBuffer; - m_VulkanFunctions.vkCreateImage = vkCreateImage; - m_VulkanFunctions.vkDestroyImage = vkDestroyImage; - if(m_UseKhrDedicatedAllocation) - { - m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = - (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice, "vkGetBufferMemoryRequirements2KHR"); - m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = - (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice, "vkGetImageMemoryRequirements2KHR"); - } -#endif // #if VMA_STATIC_VULKAN_FUNCTIONS == 1 - -#define VMA_COPY_IF_NOT_NULL(funcName) \ - if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName; - - if(pVulkanFunctions != VMA_NULL) - { - VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties); - VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties); - VMA_COPY_IF_NOT_NULL(vkAllocateMemory); - VMA_COPY_IF_NOT_NULL(vkFreeMemory); - VMA_COPY_IF_NOT_NULL(vkMapMemory); - VMA_COPY_IF_NOT_NULL(vkUnmapMemory); - VMA_COPY_IF_NOT_NULL(vkBindBufferMemory); - VMA_COPY_IF_NOT_NULL(vkBindImageMemory); - VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements); - VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements); - VMA_COPY_IF_NOT_NULL(vkCreateBuffer); - VMA_COPY_IF_NOT_NULL(vkDestroyBuffer); - VMA_COPY_IF_NOT_NULL(vkCreateImage); - VMA_COPY_IF_NOT_NULL(vkDestroyImage); - VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR); - VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR); - } - -#undef VMA_COPY_IF_NOT_NULL - - // If these asserts are hit, you must either #define VMA_STATIC_VULKAN_FUNCTIONS 1 - // or pass valid pointers as VmaAllocatorCreateInfo::pVulkanFunctions. - VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL); - if(m_UseKhrDedicatedAllocation) - { - VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL); - VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL); - } -} - -VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex) -{ - const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); - const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; - const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE; - return isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize; -} - -VkResult VmaAllocator_T::AllocateMemoryOfType( - const VkMemoryRequirements& vkMemReq, - bool dedicatedAllocation, - VkBuffer dedicatedBuffer, - VkImage dedicatedImage, - const VmaAllocationCreateInfo& createInfo, - uint32_t memTypeIndex, - VmaSuballocationType suballocType, - VmaAllocation* pAllocation) -{ - VMA_ASSERT(pAllocation != VMA_NULL); - VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, Size=%llu", memTypeIndex, vkMemReq.size); - - VmaAllocationCreateInfo finalCreateInfo = createInfo; - - // If memory type is not HOST_VISIBLE, disable MAPPED. - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && - (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) - { - finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; - } - - VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex]; - VMA_ASSERT(blockVector); - - const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize(); - bool preferDedicatedMemory = - VMA_DEBUG_ALWAYS_DEDICATED_MEMORY || - dedicatedAllocation || - // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size. - vkMemReq.size > preferredBlockSize / 2; - - if(preferDedicatedMemory && - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 && - finalCreateInfo.pool == VK_NULL_HANDLE) - { - finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } - - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) - { - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) - { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - else - { - return AllocateDedicatedMemory( - vkMemReq.size, - suballocType, - memTypeIndex, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, - finalCreateInfo.pUserData, - dedicatedBuffer, - dedicatedImage, - pAllocation); - } - } - else - { - VkResult res = blockVector->Allocate( - VK_NULL_HANDLE, // hCurrentPool - m_CurrentFrameIndex.load(), - vkMemReq, - finalCreateInfo, - suballocType, - pAllocation); - if(res == VK_SUCCESS) - { - return res; - } - - // 5. Try dedicated memory. - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) - { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - else - { - res = AllocateDedicatedMemory( - vkMemReq.size, - suballocType, - memTypeIndex, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0, - (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0, - finalCreateInfo.pUserData, - dedicatedBuffer, - dedicatedImage, - pAllocation); - if(res == VK_SUCCESS) - { - // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here. - VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); - return VK_SUCCESS; - } - else - { - // Everything failed: Return error code. - VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); - return res; - } - } - } -} - -VkResult VmaAllocator_T::AllocateDedicatedMemory( - VkDeviceSize size, - VmaSuballocationType suballocType, - uint32_t memTypeIndex, - bool map, - bool isUserDataString, - void* pUserData, - VkBuffer dedicatedBuffer, - VkImage dedicatedImage, - VmaAllocation* pAllocation) -{ - VMA_ASSERT(pAllocation); - - VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocInfo.memoryTypeIndex = memTypeIndex; - allocInfo.allocationSize = size; - - VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; - if(m_UseKhrDedicatedAllocation) - { - if(dedicatedBuffer != VK_NULL_HANDLE) - { - VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE); - dedicatedAllocInfo.buffer = dedicatedBuffer; - allocInfo.pNext = &dedicatedAllocInfo; - } - else if(dedicatedImage != VK_NULL_HANDLE) - { - dedicatedAllocInfo.image = dedicatedImage; - allocInfo.pNext = &dedicatedAllocInfo; - } - } - - // Allocate VkDeviceMemory. - VkDeviceMemory hMemory = VK_NULL_HANDLE; - VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory); - if(res < 0) - { - VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); - return res; - } - - void* pMappedData = VMA_NULL; - if(map) - { - res = (*m_VulkanFunctions.vkMapMemory)( - m_hDevice, - hMemory, - 0, - VK_WHOLE_SIZE, - 0, - &pMappedData); - if(res < 0) - { - VMA_DEBUG_LOG(" vkMapMemory FAILED"); - FreeVulkanMemory(memTypeIndex, size, hMemory); - return res; - } - } - - *pAllocation = vma_new(this, VmaAllocation_T)(m_CurrentFrameIndex.load(), isUserDataString); - (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size); - (*pAllocation)->SetUserData(this, pUserData); - - // Register it in m_pDedicatedAllocations. - { - VmaMutexLock lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex); - AllocationVectorType* pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex]; - VMA_ASSERT(pDedicatedAllocations); - VmaVectorInsertSorted(*pDedicatedAllocations, *pAllocation); - } - - VMA_DEBUG_LOG(" Allocated DedicatedMemory MemoryTypeIndex=#%u", memTypeIndex); - - return VK_SUCCESS; -} - -void VmaAllocator_T::GetBufferMemoryRequirements( - VkBuffer hBuffer, - VkMemoryRequirements& memReq, - bool& requiresDedicatedAllocation, - bool& prefersDedicatedAllocation) const -{ - if(m_UseKhrDedicatedAllocation) - { - VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR }; - memReqInfo.buffer = hBuffer; - - VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR }; - - VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR }; - memReq2.pNext = &memDedicatedReq; - - (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2); - - memReq = memReq2.memoryRequirements; - requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); - prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); - } - else - { - (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq); - requiresDedicatedAllocation = false; - prefersDedicatedAllocation = false; - } -} - -void VmaAllocator_T::GetImageMemoryRequirements( - VkImage hImage, - VkMemoryRequirements& memReq, - bool& requiresDedicatedAllocation, - bool& prefersDedicatedAllocation) const -{ - if(m_UseKhrDedicatedAllocation) - { - VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR }; - memReqInfo.image = hImage; - - VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR }; - - VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR }; - memReq2.pNext = &memDedicatedReq; - - (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2); - - memReq = memReq2.memoryRequirements; - requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); - prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); - } - else - { - (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq); - requiresDedicatedAllocation = false; - prefersDedicatedAllocation = false; - } -} - -VkResult VmaAllocator_T::AllocateMemory( - const VkMemoryRequirements& vkMemReq, - bool requiresDedicatedAllocation, - bool prefersDedicatedAllocation, - VkBuffer dedicatedBuffer, - VkImage dedicatedImage, - const VmaAllocationCreateInfo& createInfo, - VmaSuballocationType suballocType, - VmaAllocation* pAllocation) -{ - if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && - (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) - { - VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && - (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0) - { - VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if(requiresDedicatedAllocation) - { - if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) - { - VMA_ASSERT(0 && "VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if(createInfo.pool != VK_NULL_HANDLE) - { - VMA_ASSERT(0 && "Pool specified while dedicated allocation is required."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - } - if((createInfo.pool != VK_NULL_HANDLE) && - ((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0)) - { - VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid."); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - - if(createInfo.pool != VK_NULL_HANDLE) - { - return createInfo.pool->m_BlockVector.Allocate( - createInfo.pool, - m_CurrentFrameIndex.load(), - vkMemReq, - createInfo, - suballocType, - pAllocation); - } - else - { - // Bit mask of memory Vulkan types acceptable for this allocation. - uint32_t memoryTypeBits = vkMemReq.memoryTypeBits; - uint32_t memTypeIndex = UINT32_MAX; - VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex); - if(res == VK_SUCCESS) - { - res = AllocateMemoryOfType( - vkMemReq, - requiresDedicatedAllocation || prefersDedicatedAllocation, - dedicatedBuffer, - dedicatedImage, - createInfo, - memTypeIndex, - suballocType, - pAllocation); - // Succeeded on first try. - if(res == VK_SUCCESS) - { - return res; - } - // Allocation from this memory type failed. Try other compatible memory types. - else - { - for(;;) - { - // Remove old memTypeIndex from list of possibilities. - memoryTypeBits &= ~(1u << memTypeIndex); - // Find alternative memTypeIndex. - res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex); - if(res == VK_SUCCESS) - { - res = AllocateMemoryOfType( - vkMemReq, - requiresDedicatedAllocation || prefersDedicatedAllocation, - dedicatedBuffer, - dedicatedImage, - createInfo, - memTypeIndex, - suballocType, - pAllocation); - // Allocation from this alternative memory type succeeded. - if(res == VK_SUCCESS) - { - return res; - } - // else: Allocation from this memory type failed. Try next one - next loop iteration. - } - // No other matching memory type index could be found. - else - { - // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once. - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - } - } - } - // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT. - else - return res; - } -} - -void VmaAllocator_T::FreeMemory(const VmaAllocation allocation) -{ - VMA_ASSERT(allocation); - - if(allocation->CanBecomeLost() == false || - allocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST) - { - switch(allocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaBlockVector* pBlockVector = VMA_NULL; - VmaPool hPool = allocation->GetPool(); - if(hPool != VK_NULL_HANDLE) - { - pBlockVector = &hPool->m_BlockVector; - } - else - { - const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); - pBlockVector = m_pBlockVectors[memTypeIndex]; - } - pBlockVector->Free(allocation); - } - break; - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - FreeDedicatedMemory(allocation); - break; - default: - VMA_ASSERT(0); - } - } - - allocation->SetUserData(this, VMA_NULL); - vma_delete(this, allocation); -} - -void VmaAllocator_T::CalculateStats(VmaStats* pStats) -{ - // Initialize. - InitStatInfo(pStats->total); - for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) - InitStatInfo(pStats->memoryType[i]); - for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) - InitStatInfo(pStats->memoryHeap[i]); - - // Process default pools. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; - VMA_ASSERT(pBlockVector); - pBlockVector->AddStats(pStats); - } - - // Process custom pools. - { - VmaMutexLock lock(m_PoolsMutex, m_UseMutex); - for(size_t poolIndex = 0, poolCount = m_Pools.size(); poolIndex < poolCount; ++poolIndex) - { - m_Pools[poolIndex]->GetBlockVector().AddStats(pStats); - } - } - - // Process dedicated allocations. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); - VmaMutexLock dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex); - AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex]; - VMA_ASSERT(pDedicatedAllocVector); - for(size_t allocIndex = 0, allocCount = pDedicatedAllocVector->size(); allocIndex < allocCount; ++allocIndex) - { - VmaStatInfo allocationStatInfo; - (*pDedicatedAllocVector)[allocIndex]->DedicatedAllocCalcStatsInfo(allocationStatInfo); - VmaAddStatInfo(pStats->total, allocationStatInfo); - VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo); - VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo); - } - } - - // Postprocess. - VmaPostprocessCalcStatInfo(pStats->total); - for(size_t i = 0; i < GetMemoryTypeCount(); ++i) - VmaPostprocessCalcStatInfo(pStats->memoryType[i]); - for(size_t i = 0; i < GetMemoryHeapCount(); ++i) - VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]); -} - -static const uint32_t VMA_VENDOR_ID_AMD = 4098; - -VkResult VmaAllocator_T::Defragment( - VmaAllocation* pAllocations, - size_t allocationCount, - VkBool32* pAllocationsChanged, - const VmaDefragmentationInfo* pDefragmentationInfo, - VmaDefragmentationStats* pDefragmentationStats) -{ - if(pAllocationsChanged != VMA_NULL) - { - memset(pAllocationsChanged, 0, sizeof(*pAllocationsChanged)); - } - if(pDefragmentationStats != VMA_NULL) - { - memset(pDefragmentationStats, 0, sizeof(*pDefragmentationStats)); - } - - const uint32_t currentFrameIndex = m_CurrentFrameIndex.load(); - - VmaMutexLock poolsLock(m_PoolsMutex, m_UseMutex); - - const size_t poolCount = m_Pools.size(); - - // Dispatch pAllocations among defragmentators. Create them in BlockVectors when necessary. - for(size_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex) - { - VmaAllocation hAlloc = pAllocations[allocIndex]; - VMA_ASSERT(hAlloc); - const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex(); - // DedicatedAlloc cannot be defragmented. - if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) && - // Only HOST_VISIBLE memory types can be defragmented. - ((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) && - // Lost allocation cannot be defragmented. - (hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)) - { - VmaBlockVector* pAllocBlockVector = VMA_NULL; - - const VmaPool hAllocPool = hAlloc->GetPool(); - // This allocation belongs to custom pool. - if(hAllocPool != VK_NULL_HANDLE) - { - pAllocBlockVector = &hAllocPool->GetBlockVector(); - } - // This allocation belongs to general pool. - else - { - pAllocBlockVector = m_pBlockVectors[memTypeIndex]; - } - - VmaDefragmentator* const pDefragmentator = pAllocBlockVector->EnsureDefragmentator(this, currentFrameIndex); - - VkBool32* const pChanged = (pAllocationsChanged != VMA_NULL) ? - &pAllocationsChanged[allocIndex] : VMA_NULL; - pDefragmentator->AddAllocation(hAlloc, pChanged); - } - } - - VkResult result = VK_SUCCESS; - - // ======== Main processing. - - VkDeviceSize maxBytesToMove = SIZE_MAX; - uint32_t maxAllocationsToMove = UINT32_MAX; - if(pDefragmentationInfo != VMA_NULL) - { - maxBytesToMove = pDefragmentationInfo->maxBytesToMove; - maxAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove; - } - - // Process standard memory. - for(uint32_t memTypeIndex = 0; - (memTypeIndex < GetMemoryTypeCount()) && (result == VK_SUCCESS); - ++memTypeIndex) - { - // Only HOST_VISIBLE memory types can be defragmented. - if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) - { - result = m_pBlockVectors[memTypeIndex]->Defragment( - pDefragmentationStats, - maxBytesToMove, - maxAllocationsToMove); - } - } - - // Process custom pools. - for(size_t poolIndex = 0; (poolIndex < poolCount) && (result == VK_SUCCESS); ++poolIndex) - { - result = m_Pools[poolIndex]->GetBlockVector().Defragment( - pDefragmentationStats, - maxBytesToMove, - maxAllocationsToMove); - } - - // ======== Destroy defragmentators. - - // Process custom pools. - for(size_t poolIndex = poolCount; poolIndex--; ) - { - m_Pools[poolIndex]->GetBlockVector().DestroyDefragmentator(); - } - - // Process standard memory. - for(uint32_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; ) - { - if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) - { - m_pBlockVectors[memTypeIndex]->DestroyDefragmentator(); - } - } - - return result; -} - -void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo) -{ - if(hAllocation->CanBecomeLost()) - { - /* - Warning: This is a carefully designed algorithm. - Do not modify unless you really know what you're doing :) - */ - uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load(); - uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex(); - for(;;) - { - if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST) - { - pAllocationInfo->memoryType = UINT32_MAX; - pAllocationInfo->deviceMemory = VK_NULL_HANDLE; - pAllocationInfo->offset = 0; - pAllocationInfo->size = hAllocation->GetSize(); - pAllocationInfo->pMappedData = VMA_NULL; - pAllocationInfo->pUserData = hAllocation->GetUserData(); - return; - } - else if(localLastUseFrameIndex == localCurrFrameIndex) - { - pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex(); - pAllocationInfo->deviceMemory = hAllocation->GetMemory(); - pAllocationInfo->offset = hAllocation->GetOffset(); - pAllocationInfo->size = hAllocation->GetSize(); - pAllocationInfo->pMappedData = VMA_NULL; - pAllocationInfo->pUserData = hAllocation->GetUserData(); - return; - } - else // Last use time earlier than current time. - { - if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex)) - { - localLastUseFrameIndex = localCurrFrameIndex; - } - } - } - } - else - { - pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex(); - pAllocationInfo->deviceMemory = hAllocation->GetMemory(); - pAllocationInfo->offset = hAllocation->GetOffset(); - pAllocationInfo->size = hAllocation->GetSize(); - pAllocationInfo->pMappedData = hAllocation->GetMappedData(); - pAllocationInfo->pUserData = hAllocation->GetUserData(); - } -} - -bool VmaAllocator_T::TouchAllocation(VmaAllocation hAllocation) -{ - // This is a stripped-down version of VmaAllocator_T::GetAllocationInfo. - if(hAllocation->CanBecomeLost()) - { - uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load(); - uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex(); - for(;;) - { - if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST) - { - return false; - } - else if(localLastUseFrameIndex == localCurrFrameIndex) - { - return true; - } - else // Last use time earlier than current time. - { - if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex)) - { - localLastUseFrameIndex = localCurrFrameIndex; - } - } - } - } - else - { - return true; - } -} - -VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool) -{ - VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u", pCreateInfo->memoryTypeIndex); - - VmaPoolCreateInfo newCreateInfo = *pCreateInfo; - - if(newCreateInfo.maxBlockCount == 0) - { - newCreateInfo.maxBlockCount = SIZE_MAX; - } - if(newCreateInfo.blockSize == 0) - { - newCreateInfo.blockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex); - } - - *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo); - - VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks(); - if(res != VK_SUCCESS) - { - vma_delete(this, *pPool); - *pPool = VMA_NULL; - return res; - } - - // Add to m_Pools. - { - VmaMutexLock lock(m_PoolsMutex, m_UseMutex); - VmaVectorInsertSorted(m_Pools, *pPool); - } - - return VK_SUCCESS; -} - -void VmaAllocator_T::DestroyPool(VmaPool pool) -{ - // Remove from m_Pools. - { - VmaMutexLock lock(m_PoolsMutex, m_UseMutex); - bool success = VmaVectorRemoveSorted(m_Pools, pool); - VMA_ASSERT(success && "Pool not found in Allocator."); - } - - vma_delete(this, pool); -} - -void VmaAllocator_T::GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats) -{ - pool->m_BlockVector.GetPoolStats(pPoolStats); -} - -void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex) -{ - m_CurrentFrameIndex.store(frameIndex); -} - -void VmaAllocator_T::MakePoolAllocationsLost( - VmaPool hPool, - size_t* pLostAllocationCount) -{ - hPool->m_BlockVector.MakePoolAllocationsLost( - m_CurrentFrameIndex.load(), - pLostAllocationCount); -} - -void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation) -{ - *pAllocation = vma_new(this, VmaAllocation_T)(VMA_FRAME_INDEX_LOST, false); - (*pAllocation)->InitLost(); -} - -VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory) -{ - const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex); - - VkResult res; - if(m_HeapSizeLimit[heapIndex] != VK_WHOLE_SIZE) - { - VmaMutexLock lock(m_HeapSizeLimitMutex, m_UseMutex); - if(m_HeapSizeLimit[heapIndex] >= pAllocateInfo->allocationSize) - { - res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory); - if(res == VK_SUCCESS) - { - m_HeapSizeLimit[heapIndex] -= pAllocateInfo->allocationSize; - } - } - else - { - res = VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - } - else - { - res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory); - } - - if(res == VK_SUCCESS && m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) - { - (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize); - } - - return res; -} - -void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory) -{ - if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL) - { - (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size); - } - - (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks()); - - const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memoryType); - if(m_HeapSizeLimit[heapIndex] != VK_WHOLE_SIZE) - { - VmaMutexLock lock(m_HeapSizeLimitMutex, m_UseMutex); - m_HeapSizeLimit[heapIndex] += size; - } -} - -VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) -{ - if(hAllocation->CanBecomeLost()) - { - return VK_ERROR_MEMORY_MAP_FAILED; - } - - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - char *pBytes = VMA_NULL; - VkResult res = pBlock->Map(this, 1, (void**)&pBytes); - if(res == VK_SUCCESS) - { - *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset(); - hAllocation->BlockAllocMap(); - } - return res; - } - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - return hAllocation->DedicatedAllocMap(this, ppData); - default: - VMA_ASSERT(0); - return VK_ERROR_MEMORY_MAP_FAILED; - } -} - -void VmaAllocator_T::Unmap(VmaAllocation hAllocation) -{ - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - hAllocation->BlockAllocUnmap(); - pBlock->Unmap(this, 1); - } - break; - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - hAllocation->DedicatedAllocUnmap(this); - break; - default: - VMA_ASSERT(0); - } -} - -VkResult VmaAllocator_T::BindBufferMemory(VmaAllocation hAllocation, VkBuffer hBuffer) -{ - VkResult res = VK_SUCCESS; - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - res = GetVulkanFunctions().vkBindBufferMemory( - m_hDevice, - hBuffer, - hAllocation->GetMemory(), - 0); //memoryOffset - break; - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock(); - VMA_ASSERT(pBlock && "Binding buffer to allocation that doesn't belong to any block. Is the allocation lost?"); - res = pBlock->BindBufferMemory(this, hAllocation, hBuffer); - break; - } - default: - VMA_ASSERT(0); - } - return res; -} - -VkResult VmaAllocator_T::BindImageMemory(VmaAllocation hAllocation, VkImage hImage) -{ - VkResult res = VK_SUCCESS; - switch(hAllocation->GetType()) - { - case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: - res = GetVulkanFunctions().vkBindImageMemory( - m_hDevice, - hImage, - hAllocation->GetMemory(), - 0); //memoryOffset - break; - case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock(); - VMA_ASSERT(pBlock && "Binding image to allocation that doesn't belong to any block. Is the allocation lost?"); - res = pBlock->BindImageMemory(this, hAllocation, hImage); - break; - } - default: - VMA_ASSERT(0); - } - return res; -} - -void VmaAllocator_T::FreeDedicatedMemory(VmaAllocation allocation) -{ - VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED); - - const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); - { - VmaMutexLock lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex); - AllocationVectorType* const pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex]; - VMA_ASSERT(pDedicatedAllocations); - bool success = VmaVectorRemoveSorted(*pDedicatedAllocations, allocation); - VMA_ASSERT(success); - } - - VkDeviceMemory hMemory = allocation->GetMemory(); - - if(allocation->GetMappedData() != VMA_NULL) - { - (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory); - } - - FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory); - - VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex); -} - -#if VMA_STATS_STRING_ENABLED - -void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json) -{ - bool dedicatedAllocationsStarted = false; - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - VmaMutexLock dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex); - AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex]; - VMA_ASSERT(pDedicatedAllocVector); - if(pDedicatedAllocVector->empty() == false) - { - if(dedicatedAllocationsStarted == false) - { - dedicatedAllocationsStarted = true; - json.WriteString("DedicatedAllocations"); - json.BeginObject(); - } - - json.BeginString("Type "); - json.ContinueString(memTypeIndex); - json.EndString(); - - json.BeginArray(); - - for(size_t i = 0; i < pDedicatedAllocVector->size(); ++i) - { - const VmaAllocation hAlloc = (*pDedicatedAllocVector)[i]; - json.BeginObject(true); - - json.WriteString("Type"); - json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[hAlloc->GetSuballocationType()]); - - json.WriteString("Size"); - json.WriteNumber(hAlloc->GetSize()); - - const void* pUserData = hAlloc->GetUserData(); - if(pUserData != VMA_NULL) - { - json.WriteString("UserData"); - if(hAlloc->IsUserDataString()) - { - json.WriteString((const char*)pUserData); - } - else - { - json.BeginString(); - json.ContinueString_Pointer(pUserData); - json.EndString(); - } - } - - json.EndObject(); - } - - json.EndArray(); - } - } - if(dedicatedAllocationsStarted) - { - json.EndObject(); - } - - { - bool allocationsStarted = false; - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) - { - if(m_pBlockVectors[memTypeIndex]->IsEmpty() == false) - { - if(allocationsStarted == false) - { - allocationsStarted = true; - json.WriteString("DefaultPools"); - json.BeginObject(); - } - - json.BeginString("Type "); - json.ContinueString(memTypeIndex); - json.EndString(); - - m_pBlockVectors[memTypeIndex]->PrintDetailedMap(json); - } - } - if(allocationsStarted) - { - json.EndObject(); - } - } - - { - VmaMutexLock lock(m_PoolsMutex, m_UseMutex); - const size_t poolCount = m_Pools.size(); - if(poolCount > 0) - { - json.WriteString("Pools"); - json.BeginArray(); - for(size_t poolIndex = 0; poolIndex < poolCount; ++poolIndex) - { - m_Pools[poolIndex]->m_BlockVector.PrintDetailedMap(json); - } - json.EndArray(); - } - } -} - -#endif // #if VMA_STATS_STRING_ENABLED - -static VkResult AllocateMemoryForImage( - VmaAllocator allocator, - VkImage image, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VmaSuballocationType suballocType, - VmaAllocation* pAllocation) -{ - VMA_ASSERT(allocator && (image != VK_NULL_HANDLE) && pAllocationCreateInfo && pAllocation); - - VkMemoryRequirements vkMemReq = {}; - bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; - allocator->GetImageMemoryRequirements(image, vkMemReq, - requiresDedicatedAllocation, prefersDedicatedAllocation); - - return allocator->AllocateMemory( - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - VK_NULL_HANDLE, // dedicatedBuffer - image, // dedicatedImage - *pAllocationCreateInfo, - suballocType, - pAllocation); -} - -//////////////////////////////////////////////////////////////////////////////// -// Public interface - -VkResult vmaCreateAllocator( - const VmaAllocatorCreateInfo* pCreateInfo, - VmaAllocator* pAllocator) -{ - VMA_ASSERT(pCreateInfo && pAllocator); - VMA_DEBUG_LOG("vmaCreateAllocator"); - *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo); - return VK_SUCCESS; -} - -void vmaDestroyAllocator( - VmaAllocator allocator) -{ - if(allocator != VK_NULL_HANDLE) - { - VMA_DEBUG_LOG("vmaDestroyAllocator"); - VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks; - vma_delete(&allocationCallbacks, allocator); - } -} - -void vmaGetPhysicalDeviceProperties( - VmaAllocator allocator, - const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties) -{ - VMA_ASSERT(allocator && ppPhysicalDeviceProperties); - *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties; -} - -void vmaGetMemoryProperties( - VmaAllocator allocator, - const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties) -{ - VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties); - *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps; -} - -void vmaGetMemoryTypeProperties( - VmaAllocator allocator, - uint32_t memoryTypeIndex, - VkMemoryPropertyFlags* pFlags) -{ - VMA_ASSERT(allocator && pFlags); - VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount()); - *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags; -} - -void vmaSetCurrentFrameIndex( - VmaAllocator allocator, - uint32_t frameIndex) -{ - VMA_ASSERT(allocator); - VMA_ASSERT(frameIndex != VMA_FRAME_INDEX_LOST); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - allocator->SetCurrentFrameIndex(frameIndex); -} - -void vmaCalculateStats( - VmaAllocator allocator, - VmaStats* pStats) -{ - VMA_ASSERT(allocator && pStats); - VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->CalculateStats(pStats); -} - -#if VMA_STATS_STRING_ENABLED - -void vmaBuildStatsString( - VmaAllocator allocator, - char** ppStatsString, - VkBool32 detailedMap) -{ - VMA_ASSERT(allocator && ppStatsString); - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - VmaStringBuilder sb(allocator); - { - VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb); - json.BeginObject(); - - VmaStats stats; - allocator->CalculateStats(&stats); - - json.WriteString("Total"); - VmaPrintStatInfo(json, stats.total); - - for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex) - { - json.BeginString("Heap "); - json.ContinueString(heapIndex); - json.EndString(); - json.BeginObject(); - - json.WriteString("Size"); - json.WriteNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size); - - json.WriteString("Flags"); - json.BeginArray(true); - if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0) - { - json.WriteString("DEVICE_LOCAL"); - } - json.EndArray(); - - if(stats.memoryHeap[heapIndex].blockCount > 0) - { - json.WriteString("Stats"); - VmaPrintStatInfo(json, stats.memoryHeap[heapIndex]); - } - - for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex) - { - if(allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex) - { - json.BeginString("Type "); - json.ContinueString(typeIndex); - json.EndString(); - - json.BeginObject(); - - json.WriteString("Flags"); - json.BeginArray(true); - VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags; - if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) - { - json.WriteString("DEVICE_LOCAL"); - } - if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) - { - json.WriteString("HOST_VISIBLE"); - } - if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0) - { - json.WriteString("HOST_COHERENT"); - } - if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0) - { - json.WriteString("HOST_CACHED"); - } - if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0) - { - json.WriteString("LAZILY_ALLOCATED"); - } - json.EndArray(); - - if(stats.memoryType[typeIndex].blockCount > 0) - { - json.WriteString("Stats"); - VmaPrintStatInfo(json, stats.memoryType[typeIndex]); - } - - json.EndObject(); - } - } - - json.EndObject(); - } - if(detailedMap == VK_TRUE) - { - allocator->PrintDetailedMap(json); - } - - json.EndObject(); - } - - const size_t len = sb.GetLength(); - char* const pChars = vma_new_array(allocator, char, len + 1); - if(len > 0) - { - memcpy(pChars, sb.GetData(), len); - } - pChars[len] = '\0'; - *ppStatsString = pChars; -} - -void vmaFreeStatsString( - VmaAllocator allocator, - char* pStatsString) -{ - if(pStatsString != VMA_NULL) - { - VMA_ASSERT(allocator); - size_t len = strlen(pStatsString); - vma_delete_array(allocator, pStatsString, len + 1); - } -} - -#endif // #if VMA_STATS_STRING_ENABLED - -/* -This function is not protected by any mutex because it just reads immutable data. -*/ -VkResult vmaFindMemoryTypeIndex( - VmaAllocator allocator, - uint32_t memoryTypeBits, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex) -{ - VMA_ASSERT(allocator != VK_NULL_HANDLE); - VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); - VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); - - if(pAllocationCreateInfo->memoryTypeBits != 0) - { - memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits; - } - - uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags; - uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags; - - // Convert usage to requiredFlags and preferredFlags. - switch(pAllocationCreateInfo->usage) - { - case VMA_MEMORY_USAGE_UNKNOWN: - break; - case VMA_MEMORY_USAGE_GPU_ONLY: - preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - break; - case VMA_MEMORY_USAGE_CPU_ONLY: - requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - break; - case VMA_MEMORY_USAGE_CPU_TO_GPU: - requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - break; - case VMA_MEMORY_USAGE_GPU_TO_CPU: - requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - preferredFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - break; - default: - break; - } - - *pMemoryTypeIndex = UINT32_MAX; - uint32_t minCost = UINT32_MAX; - for(uint32_t memTypeIndex = 0, memTypeBit = 1; - memTypeIndex < allocator->GetMemoryTypeCount(); - ++memTypeIndex, memTypeBit <<= 1) - { - // This memory type is acceptable according to memoryTypeBits bitmask. - if((memTypeBit & memoryTypeBits) != 0) - { - const VkMemoryPropertyFlags currFlags = - allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags; - // This memory type contains requiredFlags. - if((requiredFlags & ~currFlags) == 0) - { - // Calculate cost as number of bits from preferredFlags not present in this memory type. - uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags); - // Remember memory type with lowest cost. - if(currCost < minCost) - { - *pMemoryTypeIndex = memTypeIndex; - if(currCost == 0) - { - return VK_SUCCESS; - } - minCost = currCost; - } - } - } - } - return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT; -} - -VkResult vmaFindMemoryTypeIndexForBufferInfo( - VmaAllocator allocator, - const VkBufferCreateInfo* pBufferCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex) -{ - VMA_ASSERT(allocator != VK_NULL_HANDLE); - VMA_ASSERT(pBufferCreateInfo != VMA_NULL); - VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); - VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); - - const VkDevice hDev = allocator->m_hDevice; - VkBuffer hBuffer = VK_NULL_HANDLE; - VkResult res = allocator->GetVulkanFunctions().vkCreateBuffer( - hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer); - if(res == VK_SUCCESS) - { - VkMemoryRequirements memReq = {}; - allocator->GetVulkanFunctions().vkGetBufferMemoryRequirements( - hDev, hBuffer, &memReq); - - res = vmaFindMemoryTypeIndex( - allocator, - memReq.memoryTypeBits, - pAllocationCreateInfo, - pMemoryTypeIndex); - - allocator->GetVulkanFunctions().vkDestroyBuffer( - hDev, hBuffer, allocator->GetAllocationCallbacks()); - } - return res; -} - -VkResult vmaFindMemoryTypeIndexForImageInfo( - VmaAllocator allocator, - const VkImageCreateInfo* pImageCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - uint32_t* pMemoryTypeIndex) -{ - VMA_ASSERT(allocator != VK_NULL_HANDLE); - VMA_ASSERT(pImageCreateInfo != VMA_NULL); - VMA_ASSERT(pAllocationCreateInfo != VMA_NULL); - VMA_ASSERT(pMemoryTypeIndex != VMA_NULL); - - const VkDevice hDev = allocator->m_hDevice; - VkImage hImage = VK_NULL_HANDLE; - VkResult res = allocator->GetVulkanFunctions().vkCreateImage( - hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage); - if(res == VK_SUCCESS) - { - VkMemoryRequirements memReq = {}; - allocator->GetVulkanFunctions().vkGetImageMemoryRequirements( - hDev, hImage, &memReq); - - res = vmaFindMemoryTypeIndex( - allocator, - memReq.memoryTypeBits, - pAllocationCreateInfo, - pMemoryTypeIndex); - - allocator->GetVulkanFunctions().vkDestroyImage( - hDev, hImage, allocator->GetAllocationCallbacks()); - } - return res; -} - -VkResult vmaCreatePool( - VmaAllocator allocator, - const VmaPoolCreateInfo* pCreateInfo, - VmaPool* pPool) -{ - VMA_ASSERT(allocator && pCreateInfo && pPool); - - VMA_DEBUG_LOG("vmaCreatePool"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - return allocator->CreatePool(pCreateInfo, pPool); -} - -void vmaDestroyPool( - VmaAllocator allocator, - VmaPool pool) -{ - VMA_ASSERT(allocator); - - if(pool == VK_NULL_HANDLE) - { - return; - } - - VMA_DEBUG_LOG("vmaDestroyPool"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - allocator->DestroyPool(pool); -} - -void vmaGetPoolStats( - VmaAllocator allocator, - VmaPool pool, - VmaPoolStats* pPoolStats) -{ - VMA_ASSERT(allocator && pool && pPoolStats); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - allocator->GetPoolStats(pool, pPoolStats); -} - -void vmaMakePoolAllocationsLost( - VmaAllocator allocator, - VmaPool pool, - size_t* pLostAllocationCount) -{ - VMA_ASSERT(allocator && pool); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - allocator->MakePoolAllocationsLost(pool, pLostAllocationCount); -} - -VkResult vmaAllocateMemory( - VmaAllocator allocator, - const VkMemoryRequirements* pVkMemoryRequirements, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation); - - VMA_DEBUG_LOG("vmaAllocateMemory"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - VkResult result = allocator->AllocateMemory( - *pVkMemoryRequirements, - false, // requiresDedicatedAllocation - false, // prefersDedicatedAllocation - VK_NULL_HANDLE, // dedicatedBuffer - VK_NULL_HANDLE, // dedicatedImage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_UNKNOWN, - pAllocation); - - if(pAllocationInfo && result == VK_SUCCESS) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } - - return result; -} - -VkResult vmaAllocateMemoryForBuffer( - VmaAllocator allocator, - VkBuffer buffer, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation); - - VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - VkMemoryRequirements vkMemReq = {}; - bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; - allocator->GetBufferMemoryRequirements(buffer, vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation); - - VkResult result = allocator->AllocateMemory( - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - buffer, // dedicatedBuffer - VK_NULL_HANDLE, // dedicatedImage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_BUFFER, - pAllocation); - - if(pAllocationInfo && result == VK_SUCCESS) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } - - return result; -} - -VkResult vmaAllocateMemoryForImage( - VmaAllocator allocator, - VkImage image, - const VmaAllocationCreateInfo* pCreateInfo, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation); - - VMA_DEBUG_LOG("vmaAllocateMemoryForImage"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - VkResult result = AllocateMemoryForImage( - allocator, - image, - pCreateInfo, - VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN, - pAllocation); - - if(pAllocationInfo && result == VK_SUCCESS) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } - - return result; -} - -void vmaFreeMemory( - VmaAllocator allocator, - VmaAllocation allocation) -{ - VMA_ASSERT(allocator && allocation); - - VMA_DEBUG_LOG("vmaFreeMemory"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - allocator->FreeMemory(allocation); -} - -void vmaGetAllocationInfo( - VmaAllocator allocator, - VmaAllocation allocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && allocation && pAllocationInfo); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - allocator->GetAllocationInfo(allocation, pAllocationInfo); -} - -VkBool32 vmaTouchAllocation( - VmaAllocator allocator, - VmaAllocation allocation) -{ - VMA_ASSERT(allocator && allocation); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - return allocator->TouchAllocation(allocation); -} - -void vmaSetAllocationUserData( - VmaAllocator allocator, - VmaAllocation allocation, - void* pUserData) -{ - VMA_ASSERT(allocator && allocation); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - allocation->SetUserData(allocator, pUserData); -} - -void vmaCreateLostAllocation( - VmaAllocator allocator, - VmaAllocation* pAllocation) -{ - VMA_ASSERT(allocator && pAllocation); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK; - - allocator->CreateLostAllocation(pAllocation); -} - -VkResult vmaMapMemory( - VmaAllocator allocator, - VmaAllocation allocation, - void** ppData) -{ - VMA_ASSERT(allocator && allocation && ppData); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - return allocator->Map(allocation, ppData); -} - -void vmaUnmapMemory( - VmaAllocator allocator, - VmaAllocation allocation) -{ - VMA_ASSERT(allocator && allocation); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - allocator->Unmap(allocation); -} - -VkResult vmaDefragment( - VmaAllocator allocator, - VmaAllocation* pAllocations, - size_t allocationCount, - VkBool32* pAllocationsChanged, - const VmaDefragmentationInfo *pDefragmentationInfo, - VmaDefragmentationStats* pDefragmentationStats) -{ - VMA_ASSERT(allocator && pAllocations); - - VMA_DEBUG_LOG("vmaDefragment"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - return allocator->Defragment(pAllocations, allocationCount, pAllocationsChanged, pDefragmentationInfo, pDefragmentationStats); -} - -VkResult vmaBindBufferMemory( - VmaAllocator allocator, - VmaAllocation allocation, - VkBuffer buffer) -{ - VMA_ASSERT(allocator && allocation && buffer); - - VMA_DEBUG_LOG("vmaBindBufferMemory"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - return allocator->BindBufferMemory(allocation, buffer); -} - -VkResult vmaBindImageMemory( - VmaAllocator allocator, - VmaAllocation allocation, - VkImage image) -{ - VMA_ASSERT(allocator && allocation && image); - - VMA_DEBUG_LOG("vmaBindImageMemory"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - return allocator->BindImageMemory(allocation, image); -} - -VkResult vmaCreateBuffer( - VmaAllocator allocator, - const VkBufferCreateInfo* pBufferCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkBuffer* pBuffer, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation); - - VMA_DEBUG_LOG("vmaCreateBuffer"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - *pBuffer = VK_NULL_HANDLE; - *pAllocation = VK_NULL_HANDLE; - - // 1. Create VkBuffer. - VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( - allocator->m_hDevice, - pBufferCreateInfo, - allocator->GetAllocationCallbacks(), - pBuffer); - if(res >= 0) - { - // 2. vkGetBufferMemoryRequirements. - VkMemoryRequirements vkMemReq = {}; - bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; - allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, - requiresDedicatedAllocation, prefersDedicatedAllocation); - - // Make sure alignment requirements for specific buffer usages reported - // in Physical Device Properties are included in alignment reported by memory requirements. - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) != 0) - { - VMA_ASSERT(vkMemReq.alignment % - allocator->m_PhysicalDeviceProperties.limits.minTexelBufferOffsetAlignment == 0); - } - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0) - { - VMA_ASSERT(vkMemReq.alignment % - allocator->m_PhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment == 0); - } - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0) - { - VMA_ASSERT(vkMemReq.alignment % - allocator->m_PhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment == 0); - } - - // 3. Allocate memory using allocator. - res = allocator->AllocateMemory( - vkMemReq, - requiresDedicatedAllocation, - prefersDedicatedAllocation, - *pBuffer, // dedicatedBuffer - VK_NULL_HANDLE, // dedicatedImage - *pAllocationCreateInfo, - VMA_SUBALLOCATION_TYPE_BUFFER, - pAllocation); - if(res >= 0) - { - // 3. Bind buffer with memory. - res = allocator->BindBufferMemory(*pAllocation, *pBuffer); - if(res >= 0) - { - // All steps succeeded. - if(pAllocationInfo != VMA_NULL) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } - return VK_SUCCESS; - } - allocator->FreeMemory(*pAllocation); - *pAllocation = VK_NULL_HANDLE; - (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); - *pBuffer = VK_NULL_HANDLE; - return res; - } - (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks()); - *pBuffer = VK_NULL_HANDLE; - return res; - } - return res; -} - -void vmaDestroyBuffer( - VmaAllocator allocator, - VkBuffer buffer, - VmaAllocation allocation) -{ - if(buffer != VK_NULL_HANDLE) - { - VMA_ASSERT(allocator); - - VMA_DEBUG_LOG("vmaDestroyBuffer"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks()); - - allocator->FreeMemory(allocation); - } -} - -VkResult vmaCreateImage( - VmaAllocator allocator, - const VkImageCreateInfo* pImageCreateInfo, - const VmaAllocationCreateInfo* pAllocationCreateInfo, - VkImage* pImage, - VmaAllocation* pAllocation, - VmaAllocationInfo* pAllocationInfo) -{ - VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation); - - VMA_DEBUG_LOG("vmaCreateImage"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - *pImage = VK_NULL_HANDLE; - *pAllocation = VK_NULL_HANDLE; - - // 1. Create VkImage. - VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( - allocator->m_hDevice, - pImageCreateInfo, - allocator->GetAllocationCallbacks(), - pImage); - if(res >= 0) - { - VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ? - VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL : - VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR; - - // 2. Allocate memory using allocator. - res = AllocateMemoryForImage(allocator, *pImage, pAllocationCreateInfo, suballocType, pAllocation); - if(res >= 0) - { - // 3. Bind image with memory. - res = allocator->BindImageMemory(*pAllocation, *pImage); - if(res >= 0) - { - // All steps succeeded. - if(pAllocationInfo != VMA_NULL) - { - allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); - } - return VK_SUCCESS; - } - allocator->FreeMemory(*pAllocation); - *pAllocation = VK_NULL_HANDLE; - (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); - *pImage = VK_NULL_HANDLE; - return res; - } - (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks()); - *pImage = VK_NULL_HANDLE; - return res; - } - return res; -} - -void vmaDestroyImage( - VmaAllocator allocator, - VkImage image, - VmaAllocation allocation) -{ - if(image != VK_NULL_HANDLE) - { - VMA_ASSERT(allocator); - - VMA_DEBUG_LOG("vmaDestroyImage"); - - VMA_DEBUG_GLOBAL_MUTEX_LOCK - - (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks()); - - allocator->FreeMemory(allocation); - } -} - -#endif // #ifdef VMA_IMPLEMENTATION diff --git a/src/rendering/vulkan/thirdparty/volk/volk.c b/src/rendering/vulkan/thirdparty/volk/volk.c deleted file mode 100644 index bcaf541c315..00000000000 --- a/src/rendering/vulkan/thirdparty/volk/volk.c +++ /dev/null @@ -1,1516 +0,0 @@ -#ifdef _WIN32 -#define VK_USE_PLATFORM_WIN32_KHR -#endif - -#ifdef __APPLE__ -#define VK_USE_PLATFORM_MACOS_MVK -#define VK_USE_PLATFORM_METAL_EXT -#endif - - -/* This file is part of volk library; see volk.h for version/license details */ -#include "volk.h" - -#ifdef _WIN32 -# include -#else -# include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -static void volkGenLoadLoader(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); -static void volkGenLoadInstance(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); -static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*)); -static void volkGenLoadDeviceTable(struct VolkDeviceTable* table, void* context, PFN_vkVoidFunction (*load)(void*, const char*)); - -static PFN_vkVoidFunction vkGetInstanceProcAddrStub(void* context, const char* name) -{ - return vkGetInstanceProcAddr((VkInstance)context, name); -} - -static PFN_vkVoidFunction vkGetDeviceProcAddrStub(void* context, const char* name) -{ - return vkGetDeviceProcAddr((VkDevice)context, name); -} - -VkResult volkInitialize(void) -{ -#if defined(_WIN32) - HMODULE module = LoadLibraryA("vulkan-1.dll"); - if (!module) - return VK_ERROR_INITIALIZATION_FAILED; - - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(module, "vkGetInstanceProcAddr"); -#elif defined(__APPLE__) - void* module = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL); - if (!module) - module = dlopen("libvulkan.dylib.1", RTLD_NOW | RTLD_LOCAL); - if (!module) - module = dlopen("libMoltenVK.dylib", RTLD_NOW | RTLD_LOCAL); - if (!module) - return VK_ERROR_INITIALIZATION_FAILED; - - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); -#else - void* module = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); - if (!module) - module = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); - if (!module) - return VK_ERROR_INITIALIZATION_FAILED; - - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); -#endif - - volkGenLoadLoader(NULL, vkGetInstanceProcAddrStub); - - return VK_SUCCESS; -} - -void volkInitializeCustom(PFN_vkGetInstanceProcAddr handler) -{ - vkGetInstanceProcAddr = handler; - - volkGenLoadLoader(NULL, vkGetInstanceProcAddrStub); -} - -uint32_t volkGetInstanceVersion(void) -{ -#if defined(VK_VERSION_1_1) - uint32_t apiVersion = 0; - if (vkEnumerateInstanceVersion && vkEnumerateInstanceVersion(&apiVersion) == VK_SUCCESS) - return apiVersion; -#endif - - if (vkCreateInstance) - return VK_API_VERSION_1_0; - - return 0; -} - -void volkLoadInstance(VkInstance instance) -{ - volkGenLoadInstance(instance, vkGetInstanceProcAddrStub); - volkGenLoadDevice(instance, vkGetInstanceProcAddrStub); -} - -void volkLoadDevice(VkDevice device) -{ - volkGenLoadDevice(device, vkGetDeviceProcAddrStub); -} - -void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device) -{ - volkGenLoadDeviceTable(table, device, vkGetDeviceProcAddrStub); -} - -static void volkGenLoadLoader(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) -{ - /* VOLK_GENERATE_LOAD_LOADER */ -#if defined(VK_VERSION_1_0) - vkCreateInstance = (PFN_vkCreateInstance)load(context, "vkCreateInstance"); - vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)load(context, "vkEnumerateInstanceExtensionProperties"); - vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)load(context, "vkEnumerateInstanceLayerProperties"); -#endif /* defined(VK_VERSION_1_0) */ -#if defined(VK_VERSION_1_1) - vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)load(context, "vkEnumerateInstanceVersion"); -#endif /* defined(VK_VERSION_1_1) */ - /* VOLK_GENERATE_LOAD_LOADER */ -} - -static void volkGenLoadInstance(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) -{ - /* VOLK_GENERATE_LOAD_INSTANCE */ -#if defined(VK_VERSION_1_0) - vkCreateDevice = (PFN_vkCreateDevice)load(context, "vkCreateDevice"); - vkDestroyInstance = (PFN_vkDestroyInstance)load(context, "vkDestroyInstance"); - vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)load(context, "vkEnumerateDeviceExtensionProperties"); - vkEnumerateDeviceLayerProperties = (PFN_vkEnumerateDeviceLayerProperties)load(context, "vkEnumerateDeviceLayerProperties"); - vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)load(context, "vkEnumeratePhysicalDevices"); - vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)load(context, "vkGetDeviceProcAddr"); - vkGetPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)load(context, "vkGetPhysicalDeviceFeatures"); - vkGetPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)load(context, "vkGetPhysicalDeviceFormatProperties"); - vkGetPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties)load(context, "vkGetPhysicalDeviceImageFormatProperties"); - vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)load(context, "vkGetPhysicalDeviceMemoryProperties"); - vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)load(context, "vkGetPhysicalDeviceProperties"); - vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)load(context, "vkGetPhysicalDeviceQueueFamilyProperties"); - vkGetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties"); -#endif /* defined(VK_VERSION_1_0) */ -#if defined(VK_VERSION_1_1) - vkEnumeratePhysicalDeviceGroups = (PFN_vkEnumeratePhysicalDeviceGroups)load(context, "vkEnumeratePhysicalDeviceGroups"); - vkGetPhysicalDeviceExternalBufferProperties = (PFN_vkGetPhysicalDeviceExternalBufferProperties)load(context, "vkGetPhysicalDeviceExternalBufferProperties"); - vkGetPhysicalDeviceExternalFenceProperties = (PFN_vkGetPhysicalDeviceExternalFenceProperties)load(context, "vkGetPhysicalDeviceExternalFenceProperties"); - vkGetPhysicalDeviceExternalSemaphoreProperties = (PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)load(context, "vkGetPhysicalDeviceExternalSemaphoreProperties"); - vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)load(context, "vkGetPhysicalDeviceFeatures2"); - vkGetPhysicalDeviceFormatProperties2 = (PFN_vkGetPhysicalDeviceFormatProperties2)load(context, "vkGetPhysicalDeviceFormatProperties2"); - vkGetPhysicalDeviceImageFormatProperties2 = (PFN_vkGetPhysicalDeviceImageFormatProperties2)load(context, "vkGetPhysicalDeviceImageFormatProperties2"); - vkGetPhysicalDeviceMemoryProperties2 = (PFN_vkGetPhysicalDeviceMemoryProperties2)load(context, "vkGetPhysicalDeviceMemoryProperties2"); - vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)load(context, "vkGetPhysicalDeviceProperties2"); - vkGetPhysicalDeviceQueueFamilyProperties2 = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2)load(context, "vkGetPhysicalDeviceQueueFamilyProperties2"); - vkGetPhysicalDeviceSparseImageFormatProperties2 = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties2"); -#endif /* defined(VK_VERSION_1_1) */ -#if defined(VK_EXT_acquire_xlib_display) - vkAcquireXlibDisplayEXT = (PFN_vkAcquireXlibDisplayEXT)load(context, "vkAcquireXlibDisplayEXT"); - vkGetRandROutputDisplayEXT = (PFN_vkGetRandROutputDisplayEXT)load(context, "vkGetRandROutputDisplayEXT"); -#endif /* defined(VK_EXT_acquire_xlib_display) */ -#if defined(VK_EXT_calibrated_timestamps) - vkGetPhysicalDeviceCalibrateableTimeDomainsEXT = (PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)load(context, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT"); -#endif /* defined(VK_EXT_calibrated_timestamps) */ -#if defined(VK_EXT_debug_report) - vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)load(context, "vkCreateDebugReportCallbackEXT"); - vkDebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)load(context, "vkDebugReportMessageEXT"); - vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)load(context, "vkDestroyDebugReportCallbackEXT"); -#endif /* defined(VK_EXT_debug_report) */ -#if defined(VK_EXT_debug_utils) - vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)load(context, "vkCreateDebugUtilsMessengerEXT"); - vkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)load(context, "vkDestroyDebugUtilsMessengerEXT"); - vkSubmitDebugUtilsMessageEXT = (PFN_vkSubmitDebugUtilsMessageEXT)load(context, "vkSubmitDebugUtilsMessageEXT"); -#endif /* defined(VK_EXT_debug_utils) */ -#if defined(VK_EXT_direct_mode_display) - vkReleaseDisplayEXT = (PFN_vkReleaseDisplayEXT)load(context, "vkReleaseDisplayEXT"); -#endif /* defined(VK_EXT_direct_mode_display) */ -#if defined(VK_EXT_display_surface_counter) - vkGetPhysicalDeviceSurfaceCapabilities2EXT = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)load(context, "vkGetPhysicalDeviceSurfaceCapabilities2EXT"); -#endif /* defined(VK_EXT_display_surface_counter) */ -#if defined(VK_EXT_metal_surface) - vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT)load(context, "vkCreateMetalSurfaceEXT"); -#endif /* defined(VK_EXT_metal_surface) */ -#if defined(VK_EXT_sample_locations) - vkGetPhysicalDeviceMultisamplePropertiesEXT = (PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)load(context, "vkGetPhysicalDeviceMultisamplePropertiesEXT"); -#endif /* defined(VK_EXT_sample_locations) */ -#if defined(VK_FUCHSIA_imagepipe_surface) - vkCreateImagePipeSurfaceFUCHSIA = (PFN_vkCreateImagePipeSurfaceFUCHSIA)load(context, "vkCreateImagePipeSurfaceFUCHSIA"); -#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ -#if defined(VK_KHR_android_surface) - vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)load(context, "vkCreateAndroidSurfaceKHR"); -#endif /* defined(VK_KHR_android_surface) */ -#if defined(VK_KHR_device_group_creation) - vkEnumeratePhysicalDeviceGroupsKHR = (PFN_vkEnumeratePhysicalDeviceGroupsKHR)load(context, "vkEnumeratePhysicalDeviceGroupsKHR"); -#endif /* defined(VK_KHR_device_group_creation) */ -#if defined(VK_KHR_display) - vkCreateDisplayModeKHR = (PFN_vkCreateDisplayModeKHR)load(context, "vkCreateDisplayModeKHR"); - vkCreateDisplayPlaneSurfaceKHR = (PFN_vkCreateDisplayPlaneSurfaceKHR)load(context, "vkCreateDisplayPlaneSurfaceKHR"); - vkGetDisplayModePropertiesKHR = (PFN_vkGetDisplayModePropertiesKHR)load(context, "vkGetDisplayModePropertiesKHR"); - vkGetDisplayPlaneCapabilitiesKHR = (PFN_vkGetDisplayPlaneCapabilitiesKHR)load(context, "vkGetDisplayPlaneCapabilitiesKHR"); - vkGetDisplayPlaneSupportedDisplaysKHR = (PFN_vkGetDisplayPlaneSupportedDisplaysKHR)load(context, "vkGetDisplayPlaneSupportedDisplaysKHR"); - vkGetPhysicalDeviceDisplayPlanePropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)load(context, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"); - vkGetPhysicalDeviceDisplayPropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)load(context, "vkGetPhysicalDeviceDisplayPropertiesKHR"); -#endif /* defined(VK_KHR_display) */ -#if defined(VK_KHR_external_fence_capabilities) - vkGetPhysicalDeviceExternalFencePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)load(context, "vkGetPhysicalDeviceExternalFencePropertiesKHR"); -#endif /* defined(VK_KHR_external_fence_capabilities) */ -#if defined(VK_KHR_external_memory_capabilities) - vkGetPhysicalDeviceExternalBufferPropertiesKHR = (PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)load(context, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"); -#endif /* defined(VK_KHR_external_memory_capabilities) */ -#if defined(VK_KHR_external_semaphore_capabilities) - vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)load(context, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"); -#endif /* defined(VK_KHR_external_semaphore_capabilities) */ -#if defined(VK_KHR_get_display_properties2) - vkGetDisplayModeProperties2KHR = (PFN_vkGetDisplayModeProperties2KHR)load(context, "vkGetDisplayModeProperties2KHR"); - vkGetDisplayPlaneCapabilities2KHR = (PFN_vkGetDisplayPlaneCapabilities2KHR)load(context, "vkGetDisplayPlaneCapabilities2KHR"); - vkGetPhysicalDeviceDisplayPlaneProperties2KHR = (PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)load(context, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR"); - vkGetPhysicalDeviceDisplayProperties2KHR = (PFN_vkGetPhysicalDeviceDisplayProperties2KHR)load(context, "vkGetPhysicalDeviceDisplayProperties2KHR"); -#endif /* defined(VK_KHR_get_display_properties2) */ -#if defined(VK_KHR_get_physical_device_properties2) - vkGetPhysicalDeviceFeatures2KHR = (PFN_vkGetPhysicalDeviceFeatures2KHR)load(context, "vkGetPhysicalDeviceFeatures2KHR"); - vkGetPhysicalDeviceFormatProperties2KHR = (PFN_vkGetPhysicalDeviceFormatProperties2KHR)load(context, "vkGetPhysicalDeviceFormatProperties2KHR"); - vkGetPhysicalDeviceImageFormatProperties2KHR = (PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)load(context, "vkGetPhysicalDeviceImageFormatProperties2KHR"); - vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)load(context, "vkGetPhysicalDeviceMemoryProperties2KHR"); - vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2KHR)load(context, "vkGetPhysicalDeviceProperties2KHR"); - vkGetPhysicalDeviceQueueFamilyProperties2KHR = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)load(context, "vkGetPhysicalDeviceQueueFamilyProperties2KHR"); - vkGetPhysicalDeviceSparseImageFormatProperties2KHR = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR"); -#endif /* defined(VK_KHR_get_physical_device_properties2) */ -#if defined(VK_KHR_get_surface_capabilities2) - vkGetPhysicalDeviceSurfaceCapabilities2KHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"); - vkGetPhysicalDeviceSurfaceFormats2KHR = (PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)load(context, "vkGetPhysicalDeviceSurfaceFormats2KHR"); -#endif /* defined(VK_KHR_get_surface_capabilities2) */ -#if defined(VK_KHR_surface) - vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)load(context, "vkDestroySurfaceKHR"); - vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); - vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)load(context, "vkGetPhysicalDeviceSurfaceFormatsKHR"); - vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)load(context, "vkGetPhysicalDeviceSurfacePresentModesKHR"); - vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)load(context, "vkGetPhysicalDeviceSurfaceSupportKHR"); -#endif /* defined(VK_KHR_surface) */ -#if defined(VK_KHR_wayland_surface) - vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)load(context, "vkCreateWaylandSurfaceKHR"); - vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)load(context, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); -#endif /* defined(VK_KHR_wayland_surface) */ -#if defined(VK_KHR_win32_surface) - vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)load(context, "vkCreateWin32SurfaceKHR"); - vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)load(context, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); -#endif /* defined(VK_KHR_win32_surface) */ -#if defined(VK_KHR_xcb_surface) - vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)load(context, "vkCreateXcbSurfaceKHR"); - vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)load(context, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); -#endif /* defined(VK_KHR_xcb_surface) */ -#if defined(VK_KHR_xlib_surface) - vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)load(context, "vkCreateXlibSurfaceKHR"); - vkGetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)load(context, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); -#endif /* defined(VK_KHR_xlib_surface) */ -#if defined(VK_MVK_ios_surface) - vkCreateIOSSurfaceMVK = (PFN_vkCreateIOSSurfaceMVK)load(context, "vkCreateIOSSurfaceMVK"); -#endif /* defined(VK_MVK_ios_surface) */ -#if defined(VK_MVK_macos_surface) - vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)load(context, "vkCreateMacOSSurfaceMVK"); -#endif /* defined(VK_MVK_macos_surface) */ -#if defined(VK_NN_vi_surface) - vkCreateViSurfaceNN = (PFN_vkCreateViSurfaceNN)load(context, "vkCreateViSurfaceNN"); -#endif /* defined(VK_NN_vi_surface) */ -#if defined(VK_NVX_device_generated_commands) - vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX = (PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)load(context, "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX"); -#endif /* defined(VK_NVX_device_generated_commands) */ -#if defined(VK_NV_cooperative_matrix) - vkGetPhysicalDeviceCooperativeMatrixPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)load(context, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV"); -#endif /* defined(VK_NV_cooperative_matrix) */ -#if defined(VK_NV_external_memory_capabilities) - vkGetPhysicalDeviceExternalImageFormatPropertiesNV = (PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)load(context, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV"); -#endif /* defined(VK_NV_external_memory_capabilities) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) - vkGetPhysicalDevicePresentRectanglesKHR = (PFN_vkGetPhysicalDevicePresentRectanglesKHR)load(context, "vkGetPhysicalDevicePresentRectanglesKHR"); -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ - /* VOLK_GENERATE_LOAD_INSTANCE */ -} - -static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) -{ - /* VOLK_GENERATE_LOAD_DEVICE */ -#if defined(VK_VERSION_1_0) - vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers"); - vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets"); - vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory"); - vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer"); - vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory"); - vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory"); - vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery"); - vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass"); - vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets"); - vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer"); - vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline"); - vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers"); - vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage"); - vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments"); - vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage"); - vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage"); - vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer"); - vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage"); - vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage"); - vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer"); - vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults"); - vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch"); - vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect"); - vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw"); - vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed"); - vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect"); - vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect"); - vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery"); - vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass"); - vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands"); - vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer"); - vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass"); - vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier"); - vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants"); - vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent"); - vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool"); - vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage"); - vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants"); - vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias"); - vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds"); - vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent"); - vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth"); - vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor"); - vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask"); - vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference"); - vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask"); - vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport"); - vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer"); - vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents"); - vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp"); - vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer"); - vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView"); - vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool"); - vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines"); - vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool"); - vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout"); - vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent"); - vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence"); - vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer"); - vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines"); - vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage"); - vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView"); - vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache"); - vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout"); - vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool"); - vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass"); - vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler"); - vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore"); - vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule"); - vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer"); - vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView"); - vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool"); - vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool"); - vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout"); - vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice"); - vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent"); - vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence"); - vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer"); - vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage"); - vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView"); - vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline"); - vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache"); - vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout"); - vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool"); - vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass"); - vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler"); - vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore"); - vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule"); - vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle"); - vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer"); - vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges"); - vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers"); - vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets"); - vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory"); - vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements"); - vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment"); - vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue"); - vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus"); - vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus"); - vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements"); - vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements"); - vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout"); - vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData"); - vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults"); - vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity"); - vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges"); - vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory"); - vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches"); - vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse"); - vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit"); - vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle"); - vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer"); - vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool"); - vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool"); - vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent"); - vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences"); - vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent"); - vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory"); - vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets"); - vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences"); -#endif /* defined(VK_VERSION_1_0) */ -#if defined(VK_VERSION_1_1) - vkBindBufferMemory2 = (PFN_vkBindBufferMemory2)load(context, "vkBindBufferMemory2"); - vkBindImageMemory2 = (PFN_vkBindImageMemory2)load(context, "vkBindImageMemory2"); - vkCmdDispatchBase = (PFN_vkCmdDispatchBase)load(context, "vkCmdDispatchBase"); - vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask)load(context, "vkCmdSetDeviceMask"); - vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate)load(context, "vkCreateDescriptorUpdateTemplate"); - vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)load(context, "vkCreateSamplerYcbcrConversion"); - vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate)load(context, "vkDestroyDescriptorUpdateTemplate"); - vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)load(context, "vkDestroySamplerYcbcrConversion"); - vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2)load(context, "vkGetBufferMemoryRequirements2"); - vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport)load(context, "vkGetDescriptorSetLayoutSupport"); - vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures)load(context, "vkGetDeviceGroupPeerMemoryFeatures"); - vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2)load(context, "vkGetDeviceQueue2"); - vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)load(context, "vkGetImageMemoryRequirements2"); - vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2)load(context, "vkGetImageSparseMemoryRequirements2"); - vkTrimCommandPool = (PFN_vkTrimCommandPool)load(context, "vkTrimCommandPool"); - vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate)load(context, "vkUpdateDescriptorSetWithTemplate"); -#endif /* defined(VK_VERSION_1_1) */ -#if defined(VK_AMD_buffer_marker) - vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD)load(context, "vkCmdWriteBufferMarkerAMD"); -#endif /* defined(VK_AMD_buffer_marker) */ -#if defined(VK_AMD_draw_indirect_count) - vkCmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD)load(context, "vkCmdDrawIndexedIndirectCountAMD"); - vkCmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)load(context, "vkCmdDrawIndirectCountAMD"); -#endif /* defined(VK_AMD_draw_indirect_count) */ -#if defined(VK_AMD_shader_info) - vkGetShaderInfoAMD = (PFN_vkGetShaderInfoAMD)load(context, "vkGetShaderInfoAMD"); -#endif /* defined(VK_AMD_shader_info) */ -#if defined(VK_ANDROID_external_memory_android_hardware_buffer) - vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)load(context, "vkGetAndroidHardwareBufferPropertiesANDROID"); - vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID)load(context, "vkGetMemoryAndroidHardwareBufferANDROID"); -#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ -#if defined(VK_EXT_buffer_device_address) - vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)load(context, "vkGetBufferDeviceAddressEXT"); -#endif /* defined(VK_EXT_buffer_device_address) */ -#if defined(VK_EXT_calibrated_timestamps) - vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT)load(context, "vkGetCalibratedTimestampsEXT"); -#endif /* defined(VK_EXT_calibrated_timestamps) */ -#if defined(VK_EXT_conditional_rendering) - vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)load(context, "vkCmdBeginConditionalRenderingEXT"); - vkCmdEndConditionalRenderingEXT = (PFN_vkCmdEndConditionalRenderingEXT)load(context, "vkCmdEndConditionalRenderingEXT"); -#endif /* defined(VK_EXT_conditional_rendering) */ -#if defined(VK_EXT_debug_marker) - vkCmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)load(context, "vkCmdDebugMarkerBeginEXT"); - vkCmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)load(context, "vkCmdDebugMarkerEndEXT"); - vkCmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)load(context, "vkCmdDebugMarkerInsertEXT"); - vkDebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)load(context, "vkDebugMarkerSetObjectNameEXT"); - vkDebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)load(context, "vkDebugMarkerSetObjectTagEXT"); -#endif /* defined(VK_EXT_debug_marker) */ -#if defined(VK_EXT_debug_utils) - vkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)load(context, "vkCmdBeginDebugUtilsLabelEXT"); - vkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)load(context, "vkCmdEndDebugUtilsLabelEXT"); - vkCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)load(context, "vkCmdInsertDebugUtilsLabelEXT"); - vkQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)load(context, "vkQueueBeginDebugUtilsLabelEXT"); - vkQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)load(context, "vkQueueEndDebugUtilsLabelEXT"); - vkQueueInsertDebugUtilsLabelEXT = (PFN_vkQueueInsertDebugUtilsLabelEXT)load(context, "vkQueueInsertDebugUtilsLabelEXT"); - vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)load(context, "vkSetDebugUtilsObjectNameEXT"); - vkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)load(context, "vkSetDebugUtilsObjectTagEXT"); -#endif /* defined(VK_EXT_debug_utils) */ -#if defined(VK_EXT_discard_rectangles) - vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT)load(context, "vkCmdSetDiscardRectangleEXT"); -#endif /* defined(VK_EXT_discard_rectangles) */ -#if defined(VK_EXT_display_control) - vkDisplayPowerControlEXT = (PFN_vkDisplayPowerControlEXT)load(context, "vkDisplayPowerControlEXT"); - vkGetSwapchainCounterEXT = (PFN_vkGetSwapchainCounterEXT)load(context, "vkGetSwapchainCounterEXT"); - vkRegisterDeviceEventEXT = (PFN_vkRegisterDeviceEventEXT)load(context, "vkRegisterDeviceEventEXT"); - vkRegisterDisplayEventEXT = (PFN_vkRegisterDisplayEventEXT)load(context, "vkRegisterDisplayEventEXT"); -#endif /* defined(VK_EXT_display_control) */ -#if defined(VK_EXT_external_memory_host) - vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)load(context, "vkGetMemoryHostPointerPropertiesEXT"); -#endif /* defined(VK_EXT_external_memory_host) */ -#if defined(VK_EXT_hdr_metadata) - vkSetHdrMetadataEXT = (PFN_vkSetHdrMetadataEXT)load(context, "vkSetHdrMetadataEXT"); -#endif /* defined(VK_EXT_hdr_metadata) */ -#if defined(VK_EXT_image_drm_format_modifier) - vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)load(context, "vkGetImageDrmFormatModifierPropertiesEXT"); -#endif /* defined(VK_EXT_image_drm_format_modifier) */ -#if defined(VK_EXT_sample_locations) - vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT)load(context, "vkCmdSetSampleLocationsEXT"); -#endif /* defined(VK_EXT_sample_locations) */ -#if defined(VK_EXT_transform_feedback) - vkCmdBeginQueryIndexedEXT = (PFN_vkCmdBeginQueryIndexedEXT)load(context, "vkCmdBeginQueryIndexedEXT"); - vkCmdBeginTransformFeedbackEXT = (PFN_vkCmdBeginTransformFeedbackEXT)load(context, "vkCmdBeginTransformFeedbackEXT"); - vkCmdBindTransformFeedbackBuffersEXT = (PFN_vkCmdBindTransformFeedbackBuffersEXT)load(context, "vkCmdBindTransformFeedbackBuffersEXT"); - vkCmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)load(context, "vkCmdDrawIndirectByteCountEXT"); - vkCmdEndQueryIndexedEXT = (PFN_vkCmdEndQueryIndexedEXT)load(context, "vkCmdEndQueryIndexedEXT"); - vkCmdEndTransformFeedbackEXT = (PFN_vkCmdEndTransformFeedbackEXT)load(context, "vkCmdEndTransformFeedbackEXT"); -#endif /* defined(VK_EXT_transform_feedback) */ -#if defined(VK_EXT_validation_cache) - vkCreateValidationCacheEXT = (PFN_vkCreateValidationCacheEXT)load(context, "vkCreateValidationCacheEXT"); - vkDestroyValidationCacheEXT = (PFN_vkDestroyValidationCacheEXT)load(context, "vkDestroyValidationCacheEXT"); - vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT)load(context, "vkGetValidationCacheDataEXT"); - vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT)load(context, "vkMergeValidationCachesEXT"); -#endif /* defined(VK_EXT_validation_cache) */ -#if defined(VK_GOOGLE_display_timing) - vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE)load(context, "vkGetPastPresentationTimingGOOGLE"); - vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE)load(context, "vkGetRefreshCycleDurationGOOGLE"); -#endif /* defined(VK_GOOGLE_display_timing) */ -#if defined(VK_KHR_bind_memory2) - vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)load(context, "vkBindBufferMemory2KHR"); - vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)load(context, "vkBindImageMemory2KHR"); -#endif /* defined(VK_KHR_bind_memory2) */ -#if defined(VK_KHR_create_renderpass2) - vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR)load(context, "vkCmdBeginRenderPass2KHR"); - vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)load(context, "vkCmdEndRenderPass2KHR"); - vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)load(context, "vkCmdNextSubpass2KHR"); - vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)load(context, "vkCreateRenderPass2KHR"); -#endif /* defined(VK_KHR_create_renderpass2) */ -#if defined(VK_KHR_descriptor_update_template) - vkCreateDescriptorUpdateTemplateKHR = (PFN_vkCreateDescriptorUpdateTemplateKHR)load(context, "vkCreateDescriptorUpdateTemplateKHR"); - vkDestroyDescriptorUpdateTemplateKHR = (PFN_vkDestroyDescriptorUpdateTemplateKHR)load(context, "vkDestroyDescriptorUpdateTemplateKHR"); - vkUpdateDescriptorSetWithTemplateKHR = (PFN_vkUpdateDescriptorSetWithTemplateKHR)load(context, "vkUpdateDescriptorSetWithTemplateKHR"); -#endif /* defined(VK_KHR_descriptor_update_template) */ -#if defined(VK_KHR_device_group) - vkCmdDispatchBaseKHR = (PFN_vkCmdDispatchBaseKHR)load(context, "vkCmdDispatchBaseKHR"); - vkCmdSetDeviceMaskKHR = (PFN_vkCmdSetDeviceMaskKHR)load(context, "vkCmdSetDeviceMaskKHR"); - vkGetDeviceGroupPeerMemoryFeaturesKHR = (PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)load(context, "vkGetDeviceGroupPeerMemoryFeaturesKHR"); -#endif /* defined(VK_KHR_device_group) */ -#if defined(VK_KHR_display_swapchain) - vkCreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)load(context, "vkCreateSharedSwapchainsKHR"); -#endif /* defined(VK_KHR_display_swapchain) */ -#if defined(VK_KHR_draw_indirect_count) - vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)load(context, "vkCmdDrawIndexedIndirectCountKHR"); - vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)load(context, "vkCmdDrawIndirectCountKHR"); -#endif /* defined(VK_KHR_draw_indirect_count) */ -#if defined(VK_KHR_external_fence_fd) - vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)load(context, "vkGetFenceFdKHR"); - vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)load(context, "vkImportFenceFdKHR"); -#endif /* defined(VK_KHR_external_fence_fd) */ -#if defined(VK_KHR_external_fence_win32) - vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)load(context, "vkGetFenceWin32HandleKHR"); - vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR)load(context, "vkImportFenceWin32HandleKHR"); -#endif /* defined(VK_KHR_external_fence_win32) */ -#if defined(VK_KHR_external_memory_fd) - vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)load(context, "vkGetMemoryFdKHR"); - vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)load(context, "vkGetMemoryFdPropertiesKHR"); -#endif /* defined(VK_KHR_external_memory_fd) */ -#if defined(VK_KHR_external_memory_win32) - vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)load(context, "vkGetMemoryWin32HandleKHR"); - vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)load(context, "vkGetMemoryWin32HandlePropertiesKHR"); -#endif /* defined(VK_KHR_external_memory_win32) */ -#if defined(VK_KHR_external_semaphore_fd) - vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)load(context, "vkGetSemaphoreFdKHR"); - vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)load(context, "vkImportSemaphoreFdKHR"); -#endif /* defined(VK_KHR_external_semaphore_fd) */ -#if defined(VK_KHR_external_semaphore_win32) - vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)load(context, "vkGetSemaphoreWin32HandleKHR"); - vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR)load(context, "vkImportSemaphoreWin32HandleKHR"); -#endif /* defined(VK_KHR_external_semaphore_win32) */ -#if defined(VK_KHR_get_memory_requirements2) - vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)load(context, "vkGetBufferMemoryRequirements2KHR"); - vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)load(context, "vkGetImageMemoryRequirements2KHR"); - vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)load(context, "vkGetImageSparseMemoryRequirements2KHR"); -#endif /* defined(VK_KHR_get_memory_requirements2) */ -#if defined(VK_KHR_maintenance1) - vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR)load(context, "vkTrimCommandPoolKHR"); -#endif /* defined(VK_KHR_maintenance1) */ -#if defined(VK_KHR_maintenance3) - vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR)load(context, "vkGetDescriptorSetLayoutSupportKHR"); -#endif /* defined(VK_KHR_maintenance3) */ -#if defined(VK_KHR_push_descriptor) - vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)load(context, "vkCmdPushDescriptorSetKHR"); -#endif /* defined(VK_KHR_push_descriptor) */ -#if defined(VK_KHR_sampler_ycbcr_conversion) - vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR)load(context, "vkCreateSamplerYcbcrConversionKHR"); - vkDestroySamplerYcbcrConversionKHR = (PFN_vkDestroySamplerYcbcrConversionKHR)load(context, "vkDestroySamplerYcbcrConversionKHR"); -#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ -#if defined(VK_KHR_shared_presentable_image) - vkGetSwapchainStatusKHR = (PFN_vkGetSwapchainStatusKHR)load(context, "vkGetSwapchainStatusKHR"); -#endif /* defined(VK_KHR_shared_presentable_image) */ -#if defined(VK_KHR_swapchain) - vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR"); - vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR"); - vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR"); - vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR"); - vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR"); -#endif /* defined(VK_KHR_swapchain) */ -#if defined(VK_NVX_device_generated_commands) - vkCmdProcessCommandsNVX = (PFN_vkCmdProcessCommandsNVX)load(context, "vkCmdProcessCommandsNVX"); - vkCmdReserveSpaceForCommandsNVX = (PFN_vkCmdReserveSpaceForCommandsNVX)load(context, "vkCmdReserveSpaceForCommandsNVX"); - vkCreateIndirectCommandsLayoutNVX = (PFN_vkCreateIndirectCommandsLayoutNVX)load(context, "vkCreateIndirectCommandsLayoutNVX"); - vkCreateObjectTableNVX = (PFN_vkCreateObjectTableNVX)load(context, "vkCreateObjectTableNVX"); - vkDestroyIndirectCommandsLayoutNVX = (PFN_vkDestroyIndirectCommandsLayoutNVX)load(context, "vkDestroyIndirectCommandsLayoutNVX"); - vkDestroyObjectTableNVX = (PFN_vkDestroyObjectTableNVX)load(context, "vkDestroyObjectTableNVX"); - vkRegisterObjectsNVX = (PFN_vkRegisterObjectsNVX)load(context, "vkRegisterObjectsNVX"); - vkUnregisterObjectsNVX = (PFN_vkUnregisterObjectsNVX)load(context, "vkUnregisterObjectsNVX"); -#endif /* defined(VK_NVX_device_generated_commands) */ -#if defined(VK_NVX_image_view_handle) - vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)load(context, "vkGetImageViewHandleNVX"); -#endif /* defined(VK_NVX_image_view_handle) */ -#if defined(VK_NV_clip_space_w_scaling) - vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV)load(context, "vkCmdSetViewportWScalingNV"); -#endif /* defined(VK_NV_clip_space_w_scaling) */ -#if defined(VK_NV_device_diagnostic_checkpoints) - vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)load(context, "vkCmdSetCheckpointNV"); - vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV)load(context, "vkGetQueueCheckpointDataNV"); -#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ -#if defined(VK_NV_external_memory_win32) - vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV)load(context, "vkGetMemoryWin32HandleNV"); -#endif /* defined(VK_NV_external_memory_win32) */ -#if defined(VK_NV_mesh_shader) - vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV)load(context, "vkCmdDrawMeshTasksIndirectCountNV"); - vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV)load(context, "vkCmdDrawMeshTasksIndirectNV"); - vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV)load(context, "vkCmdDrawMeshTasksNV"); -#endif /* defined(VK_NV_mesh_shader) */ -#if defined(VK_NV_ray_tracing) - vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV)load(context, "vkBindAccelerationStructureMemoryNV"); - vkCmdBuildAccelerationStructureNV = (PFN_vkCmdBuildAccelerationStructureNV)load(context, "vkCmdBuildAccelerationStructureNV"); - vkCmdCopyAccelerationStructureNV = (PFN_vkCmdCopyAccelerationStructureNV)load(context, "vkCmdCopyAccelerationStructureNV"); - vkCmdTraceRaysNV = (PFN_vkCmdTraceRaysNV)load(context, "vkCmdTraceRaysNV"); - vkCmdWriteAccelerationStructuresPropertiesNV = (PFN_vkCmdWriteAccelerationStructuresPropertiesNV)load(context, "vkCmdWriteAccelerationStructuresPropertiesNV"); - vkCompileDeferredNV = (PFN_vkCompileDeferredNV)load(context, "vkCompileDeferredNV"); - vkCreateAccelerationStructureNV = (PFN_vkCreateAccelerationStructureNV)load(context, "vkCreateAccelerationStructureNV"); - vkCreateRayTracingPipelinesNV = (PFN_vkCreateRayTracingPipelinesNV)load(context, "vkCreateRayTracingPipelinesNV"); - vkDestroyAccelerationStructureNV = (PFN_vkDestroyAccelerationStructureNV)load(context, "vkDestroyAccelerationStructureNV"); - vkGetAccelerationStructureHandleNV = (PFN_vkGetAccelerationStructureHandleNV)load(context, "vkGetAccelerationStructureHandleNV"); - vkGetAccelerationStructureMemoryRequirementsNV = (PFN_vkGetAccelerationStructureMemoryRequirementsNV)load(context, "vkGetAccelerationStructureMemoryRequirementsNV"); - vkGetRayTracingShaderGroupHandlesNV = (PFN_vkGetRayTracingShaderGroupHandlesNV)load(context, "vkGetRayTracingShaderGroupHandlesNV"); -#endif /* defined(VK_NV_ray_tracing) */ -#if defined(VK_NV_scissor_exclusive) - vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV)load(context, "vkCmdSetExclusiveScissorNV"); -#endif /* defined(VK_NV_scissor_exclusive) */ -#if defined(VK_NV_shading_rate_image) - vkCmdBindShadingRateImageNV = (PFN_vkCmdBindShadingRateImageNV)load(context, "vkCmdBindShadingRateImageNV"); - vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV)load(context, "vkCmdSetCoarseSampleOrderNV"); - vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV)load(context, "vkCmdSetViewportShadingRatePaletteNV"); -#endif /* defined(VK_NV_shading_rate_image) */ -#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) - vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR)load(context, "vkCmdPushDescriptorSetWithTemplateKHR"); -#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) - vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)load(context, "vkGetDeviceGroupPresentCapabilitiesKHR"); - vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)load(context, "vkGetDeviceGroupSurfacePresentModesKHR"); -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) - vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR)load(context, "vkAcquireNextImage2KHR"); -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ - /* VOLK_GENERATE_LOAD_DEVICE */ -} - -static void volkGenLoadDeviceTable(struct VolkDeviceTable* table, void* context, PFN_vkVoidFunction (*load)(void*, const char*)) -{ - /* VOLK_GENERATE_LOAD_DEVICE_TABLE */ -#if defined(VK_VERSION_1_0) - table->vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers"); - table->vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets"); - table->vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory"); - table->vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer"); - table->vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory"); - table->vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory"); - table->vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery"); - table->vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass"); - table->vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets"); - table->vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer"); - table->vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline"); - table->vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers"); - table->vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage"); - table->vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments"); - table->vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage"); - table->vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage"); - table->vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer"); - table->vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage"); - table->vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage"); - table->vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer"); - table->vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults"); - table->vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch"); - table->vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect"); - table->vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw"); - table->vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed"); - table->vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect"); - table->vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect"); - table->vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery"); - table->vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass"); - table->vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands"); - table->vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer"); - table->vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass"); - table->vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier"); - table->vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants"); - table->vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent"); - table->vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool"); - table->vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage"); - table->vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants"); - table->vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias"); - table->vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds"); - table->vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent"); - table->vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth"); - table->vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor"); - table->vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask"); - table->vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference"); - table->vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask"); - table->vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport"); - table->vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer"); - table->vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents"); - table->vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp"); - table->vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer"); - table->vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView"); - table->vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool"); - table->vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines"); - table->vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool"); - table->vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout"); - table->vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent"); - table->vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence"); - table->vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer"); - table->vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines"); - table->vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage"); - table->vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView"); - table->vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache"); - table->vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout"); - table->vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool"); - table->vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass"); - table->vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler"); - table->vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore"); - table->vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule"); - table->vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer"); - table->vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView"); - table->vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool"); - table->vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool"); - table->vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout"); - table->vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice"); - table->vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent"); - table->vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence"); - table->vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer"); - table->vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage"); - table->vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView"); - table->vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline"); - table->vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache"); - table->vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout"); - table->vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool"); - table->vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass"); - table->vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler"); - table->vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore"); - table->vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule"); - table->vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle"); - table->vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer"); - table->vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges"); - table->vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers"); - table->vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets"); - table->vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory"); - table->vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements"); - table->vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment"); - table->vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue"); - table->vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus"); - table->vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus"); - table->vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements"); - table->vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements"); - table->vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout"); - table->vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData"); - table->vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults"); - table->vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity"); - table->vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges"); - table->vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory"); - table->vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches"); - table->vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse"); - table->vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit"); - table->vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle"); - table->vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer"); - table->vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool"); - table->vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool"); - table->vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent"); - table->vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences"); - table->vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent"); - table->vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory"); - table->vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets"); - table->vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences"); -#endif /* defined(VK_VERSION_1_0) */ -#if defined(VK_VERSION_1_1) - table->vkBindBufferMemory2 = (PFN_vkBindBufferMemory2)load(context, "vkBindBufferMemory2"); - table->vkBindImageMemory2 = (PFN_vkBindImageMemory2)load(context, "vkBindImageMemory2"); - table->vkCmdDispatchBase = (PFN_vkCmdDispatchBase)load(context, "vkCmdDispatchBase"); - table->vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask)load(context, "vkCmdSetDeviceMask"); - table->vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate)load(context, "vkCreateDescriptorUpdateTemplate"); - table->vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion)load(context, "vkCreateSamplerYcbcrConversion"); - table->vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate)load(context, "vkDestroyDescriptorUpdateTemplate"); - table->vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion)load(context, "vkDestroySamplerYcbcrConversion"); - table->vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2)load(context, "vkGetBufferMemoryRequirements2"); - table->vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport)load(context, "vkGetDescriptorSetLayoutSupport"); - table->vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures)load(context, "vkGetDeviceGroupPeerMemoryFeatures"); - table->vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2)load(context, "vkGetDeviceQueue2"); - table->vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)load(context, "vkGetImageMemoryRequirements2"); - table->vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2)load(context, "vkGetImageSparseMemoryRequirements2"); - table->vkTrimCommandPool = (PFN_vkTrimCommandPool)load(context, "vkTrimCommandPool"); - table->vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate)load(context, "vkUpdateDescriptorSetWithTemplate"); -#endif /* defined(VK_VERSION_1_1) */ -#if defined(VK_AMD_buffer_marker) - table->vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD)load(context, "vkCmdWriteBufferMarkerAMD"); -#endif /* defined(VK_AMD_buffer_marker) */ -#if defined(VK_AMD_draw_indirect_count) - table->vkCmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD)load(context, "vkCmdDrawIndexedIndirectCountAMD"); - table->vkCmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)load(context, "vkCmdDrawIndirectCountAMD"); -#endif /* defined(VK_AMD_draw_indirect_count) */ -#if defined(VK_AMD_shader_info) - table->vkGetShaderInfoAMD = (PFN_vkGetShaderInfoAMD)load(context, "vkGetShaderInfoAMD"); -#endif /* defined(VK_AMD_shader_info) */ -#if defined(VK_ANDROID_external_memory_android_hardware_buffer) - table->vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)load(context, "vkGetAndroidHardwareBufferPropertiesANDROID"); - table->vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID)load(context, "vkGetMemoryAndroidHardwareBufferANDROID"); -#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ -#if defined(VK_EXT_buffer_device_address) - table->vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT)load(context, "vkGetBufferDeviceAddressEXT"); -#endif /* defined(VK_EXT_buffer_device_address) */ -#if defined(VK_EXT_calibrated_timestamps) - table->vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT)load(context, "vkGetCalibratedTimestampsEXT"); -#endif /* defined(VK_EXT_calibrated_timestamps) */ -#if defined(VK_EXT_conditional_rendering) - table->vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT)load(context, "vkCmdBeginConditionalRenderingEXT"); - table->vkCmdEndConditionalRenderingEXT = (PFN_vkCmdEndConditionalRenderingEXT)load(context, "vkCmdEndConditionalRenderingEXT"); -#endif /* defined(VK_EXT_conditional_rendering) */ -#if defined(VK_EXT_debug_marker) - table->vkCmdDebugMarkerBeginEXT = (PFN_vkCmdDebugMarkerBeginEXT)load(context, "vkCmdDebugMarkerBeginEXT"); - table->vkCmdDebugMarkerEndEXT = (PFN_vkCmdDebugMarkerEndEXT)load(context, "vkCmdDebugMarkerEndEXT"); - table->vkCmdDebugMarkerInsertEXT = (PFN_vkCmdDebugMarkerInsertEXT)load(context, "vkCmdDebugMarkerInsertEXT"); - table->vkDebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)load(context, "vkDebugMarkerSetObjectNameEXT"); - table->vkDebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)load(context, "vkDebugMarkerSetObjectTagEXT"); -#endif /* defined(VK_EXT_debug_marker) */ -#if defined(VK_EXT_debug_utils) - table->vkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)load(context, "vkCmdBeginDebugUtilsLabelEXT"); - table->vkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)load(context, "vkCmdEndDebugUtilsLabelEXT"); - table->vkCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)load(context, "vkCmdInsertDebugUtilsLabelEXT"); - table->vkQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)load(context, "vkQueueBeginDebugUtilsLabelEXT"); - table->vkQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)load(context, "vkQueueEndDebugUtilsLabelEXT"); - table->vkQueueInsertDebugUtilsLabelEXT = (PFN_vkQueueInsertDebugUtilsLabelEXT)load(context, "vkQueueInsertDebugUtilsLabelEXT"); - table->vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)load(context, "vkSetDebugUtilsObjectNameEXT"); - table->vkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)load(context, "vkSetDebugUtilsObjectTagEXT"); -#endif /* defined(VK_EXT_debug_utils) */ -#if defined(VK_EXT_discard_rectangles) - table->vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT)load(context, "vkCmdSetDiscardRectangleEXT"); -#endif /* defined(VK_EXT_discard_rectangles) */ -#if defined(VK_EXT_display_control) - table->vkDisplayPowerControlEXT = (PFN_vkDisplayPowerControlEXT)load(context, "vkDisplayPowerControlEXT"); - table->vkGetSwapchainCounterEXT = (PFN_vkGetSwapchainCounterEXT)load(context, "vkGetSwapchainCounterEXT"); - table->vkRegisterDeviceEventEXT = (PFN_vkRegisterDeviceEventEXT)load(context, "vkRegisterDeviceEventEXT"); - table->vkRegisterDisplayEventEXT = (PFN_vkRegisterDisplayEventEXT)load(context, "vkRegisterDisplayEventEXT"); -#endif /* defined(VK_EXT_display_control) */ -#if defined(VK_EXT_external_memory_host) - table->vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT)load(context, "vkGetMemoryHostPointerPropertiesEXT"); -#endif /* defined(VK_EXT_external_memory_host) */ -#if defined(VK_EXT_hdr_metadata) - table->vkSetHdrMetadataEXT = (PFN_vkSetHdrMetadataEXT)load(context, "vkSetHdrMetadataEXT"); -#endif /* defined(VK_EXT_hdr_metadata) */ -#if defined(VK_EXT_image_drm_format_modifier) - table->vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)load(context, "vkGetImageDrmFormatModifierPropertiesEXT"); -#endif /* defined(VK_EXT_image_drm_format_modifier) */ -#if defined(VK_EXT_sample_locations) - table->vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT)load(context, "vkCmdSetSampleLocationsEXT"); -#endif /* defined(VK_EXT_sample_locations) */ -#if defined(VK_EXT_transform_feedback) - table->vkCmdBeginQueryIndexedEXT = (PFN_vkCmdBeginQueryIndexedEXT)load(context, "vkCmdBeginQueryIndexedEXT"); - table->vkCmdBeginTransformFeedbackEXT = (PFN_vkCmdBeginTransformFeedbackEXT)load(context, "vkCmdBeginTransformFeedbackEXT"); - table->vkCmdBindTransformFeedbackBuffersEXT = (PFN_vkCmdBindTransformFeedbackBuffersEXT)load(context, "vkCmdBindTransformFeedbackBuffersEXT"); - table->vkCmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)load(context, "vkCmdDrawIndirectByteCountEXT"); - table->vkCmdEndQueryIndexedEXT = (PFN_vkCmdEndQueryIndexedEXT)load(context, "vkCmdEndQueryIndexedEXT"); - table->vkCmdEndTransformFeedbackEXT = (PFN_vkCmdEndTransformFeedbackEXT)load(context, "vkCmdEndTransformFeedbackEXT"); -#endif /* defined(VK_EXT_transform_feedback) */ -#if defined(VK_EXT_validation_cache) - table->vkCreateValidationCacheEXT = (PFN_vkCreateValidationCacheEXT)load(context, "vkCreateValidationCacheEXT"); - table->vkDestroyValidationCacheEXT = (PFN_vkDestroyValidationCacheEXT)load(context, "vkDestroyValidationCacheEXT"); - table->vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT)load(context, "vkGetValidationCacheDataEXT"); - table->vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT)load(context, "vkMergeValidationCachesEXT"); -#endif /* defined(VK_EXT_validation_cache) */ -#if defined(VK_GOOGLE_display_timing) - table->vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE)load(context, "vkGetPastPresentationTimingGOOGLE"); - table->vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE)load(context, "vkGetRefreshCycleDurationGOOGLE"); -#endif /* defined(VK_GOOGLE_display_timing) */ -#if defined(VK_KHR_bind_memory2) - table->vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)load(context, "vkBindBufferMemory2KHR"); - table->vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)load(context, "vkBindImageMemory2KHR"); -#endif /* defined(VK_KHR_bind_memory2) */ -#if defined(VK_KHR_create_renderpass2) - table->vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR)load(context, "vkCmdBeginRenderPass2KHR"); - table->vkCmdEndRenderPass2KHR = (PFN_vkCmdEndRenderPass2KHR)load(context, "vkCmdEndRenderPass2KHR"); - table->vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR)load(context, "vkCmdNextSubpass2KHR"); - table->vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)load(context, "vkCreateRenderPass2KHR"); -#endif /* defined(VK_KHR_create_renderpass2) */ -#if defined(VK_KHR_descriptor_update_template) - table->vkCreateDescriptorUpdateTemplateKHR = (PFN_vkCreateDescriptorUpdateTemplateKHR)load(context, "vkCreateDescriptorUpdateTemplateKHR"); - table->vkDestroyDescriptorUpdateTemplateKHR = (PFN_vkDestroyDescriptorUpdateTemplateKHR)load(context, "vkDestroyDescriptorUpdateTemplateKHR"); - table->vkUpdateDescriptorSetWithTemplateKHR = (PFN_vkUpdateDescriptorSetWithTemplateKHR)load(context, "vkUpdateDescriptorSetWithTemplateKHR"); -#endif /* defined(VK_KHR_descriptor_update_template) */ -#if defined(VK_KHR_device_group) - table->vkCmdDispatchBaseKHR = (PFN_vkCmdDispatchBaseKHR)load(context, "vkCmdDispatchBaseKHR"); - table->vkCmdSetDeviceMaskKHR = (PFN_vkCmdSetDeviceMaskKHR)load(context, "vkCmdSetDeviceMaskKHR"); - table->vkGetDeviceGroupPeerMemoryFeaturesKHR = (PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)load(context, "vkGetDeviceGroupPeerMemoryFeaturesKHR"); -#endif /* defined(VK_KHR_device_group) */ -#if defined(VK_KHR_display_swapchain) - table->vkCreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)load(context, "vkCreateSharedSwapchainsKHR"); -#endif /* defined(VK_KHR_display_swapchain) */ -#if defined(VK_KHR_draw_indirect_count) - table->vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)load(context, "vkCmdDrawIndexedIndirectCountKHR"); - table->vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)load(context, "vkCmdDrawIndirectCountKHR"); -#endif /* defined(VK_KHR_draw_indirect_count) */ -#if defined(VK_KHR_external_fence_fd) - table->vkGetFenceFdKHR = (PFN_vkGetFenceFdKHR)load(context, "vkGetFenceFdKHR"); - table->vkImportFenceFdKHR = (PFN_vkImportFenceFdKHR)load(context, "vkImportFenceFdKHR"); -#endif /* defined(VK_KHR_external_fence_fd) */ -#if defined(VK_KHR_external_fence_win32) - table->vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)load(context, "vkGetFenceWin32HandleKHR"); - table->vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR)load(context, "vkImportFenceWin32HandleKHR"); -#endif /* defined(VK_KHR_external_fence_win32) */ -#if defined(VK_KHR_external_memory_fd) - table->vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)load(context, "vkGetMemoryFdKHR"); - table->vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)load(context, "vkGetMemoryFdPropertiesKHR"); -#endif /* defined(VK_KHR_external_memory_fd) */ -#if defined(VK_KHR_external_memory_win32) - table->vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)load(context, "vkGetMemoryWin32HandleKHR"); - table->vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)load(context, "vkGetMemoryWin32HandlePropertiesKHR"); -#endif /* defined(VK_KHR_external_memory_win32) */ -#if defined(VK_KHR_external_semaphore_fd) - table->vkGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)load(context, "vkGetSemaphoreFdKHR"); - table->vkImportSemaphoreFdKHR = (PFN_vkImportSemaphoreFdKHR)load(context, "vkImportSemaphoreFdKHR"); -#endif /* defined(VK_KHR_external_semaphore_fd) */ -#if defined(VK_KHR_external_semaphore_win32) - table->vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)load(context, "vkGetSemaphoreWin32HandleKHR"); - table->vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR)load(context, "vkImportSemaphoreWin32HandleKHR"); -#endif /* defined(VK_KHR_external_semaphore_win32) */ -#if defined(VK_KHR_get_memory_requirements2) - table->vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)load(context, "vkGetBufferMemoryRequirements2KHR"); - table->vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)load(context, "vkGetImageMemoryRequirements2KHR"); - table->vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)load(context, "vkGetImageSparseMemoryRequirements2KHR"); -#endif /* defined(VK_KHR_get_memory_requirements2) */ -#if defined(VK_KHR_maintenance1) - table->vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR)load(context, "vkTrimCommandPoolKHR"); -#endif /* defined(VK_KHR_maintenance1) */ -#if defined(VK_KHR_maintenance3) - table->vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR)load(context, "vkGetDescriptorSetLayoutSupportKHR"); -#endif /* defined(VK_KHR_maintenance3) */ -#if defined(VK_KHR_push_descriptor) - table->vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)load(context, "vkCmdPushDescriptorSetKHR"); -#endif /* defined(VK_KHR_push_descriptor) */ -#if defined(VK_KHR_sampler_ycbcr_conversion) - table->vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR)load(context, "vkCreateSamplerYcbcrConversionKHR"); - table->vkDestroySamplerYcbcrConversionKHR = (PFN_vkDestroySamplerYcbcrConversionKHR)load(context, "vkDestroySamplerYcbcrConversionKHR"); -#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ -#if defined(VK_KHR_shared_presentable_image) - table->vkGetSwapchainStatusKHR = (PFN_vkGetSwapchainStatusKHR)load(context, "vkGetSwapchainStatusKHR"); -#endif /* defined(VK_KHR_shared_presentable_image) */ -#if defined(VK_KHR_swapchain) - table->vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR"); - table->vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR"); - table->vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR"); - table->vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR"); - table->vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR"); -#endif /* defined(VK_KHR_swapchain) */ -#if defined(VK_NVX_device_generated_commands) - table->vkCmdProcessCommandsNVX = (PFN_vkCmdProcessCommandsNVX)load(context, "vkCmdProcessCommandsNVX"); - table->vkCmdReserveSpaceForCommandsNVX = (PFN_vkCmdReserveSpaceForCommandsNVX)load(context, "vkCmdReserveSpaceForCommandsNVX"); - table->vkCreateIndirectCommandsLayoutNVX = (PFN_vkCreateIndirectCommandsLayoutNVX)load(context, "vkCreateIndirectCommandsLayoutNVX"); - table->vkCreateObjectTableNVX = (PFN_vkCreateObjectTableNVX)load(context, "vkCreateObjectTableNVX"); - table->vkDestroyIndirectCommandsLayoutNVX = (PFN_vkDestroyIndirectCommandsLayoutNVX)load(context, "vkDestroyIndirectCommandsLayoutNVX"); - table->vkDestroyObjectTableNVX = (PFN_vkDestroyObjectTableNVX)load(context, "vkDestroyObjectTableNVX"); - table->vkRegisterObjectsNVX = (PFN_vkRegisterObjectsNVX)load(context, "vkRegisterObjectsNVX"); - table->vkUnregisterObjectsNVX = (PFN_vkUnregisterObjectsNVX)load(context, "vkUnregisterObjectsNVX"); -#endif /* defined(VK_NVX_device_generated_commands) */ -#if defined(VK_NVX_image_view_handle) - table->vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)load(context, "vkGetImageViewHandleNVX"); -#endif /* defined(VK_NVX_image_view_handle) */ -#if defined(VK_NV_clip_space_w_scaling) - table->vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV)load(context, "vkCmdSetViewportWScalingNV"); -#endif /* defined(VK_NV_clip_space_w_scaling) */ -#if defined(VK_NV_device_diagnostic_checkpoints) - table->vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)load(context, "vkCmdSetCheckpointNV"); - table->vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV)load(context, "vkGetQueueCheckpointDataNV"); -#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ -#if defined(VK_NV_external_memory_win32) - table->vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV)load(context, "vkGetMemoryWin32HandleNV"); -#endif /* defined(VK_NV_external_memory_win32) */ -#if defined(VK_NV_mesh_shader) - table->vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV)load(context, "vkCmdDrawMeshTasksIndirectCountNV"); - table->vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV)load(context, "vkCmdDrawMeshTasksIndirectNV"); - table->vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV)load(context, "vkCmdDrawMeshTasksNV"); -#endif /* defined(VK_NV_mesh_shader) */ -#if defined(VK_NV_ray_tracing) - table->vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV)load(context, "vkBindAccelerationStructureMemoryNV"); - table->vkCmdBuildAccelerationStructureNV = (PFN_vkCmdBuildAccelerationStructureNV)load(context, "vkCmdBuildAccelerationStructureNV"); - table->vkCmdCopyAccelerationStructureNV = (PFN_vkCmdCopyAccelerationStructureNV)load(context, "vkCmdCopyAccelerationStructureNV"); - table->vkCmdTraceRaysNV = (PFN_vkCmdTraceRaysNV)load(context, "vkCmdTraceRaysNV"); - table->vkCmdWriteAccelerationStructuresPropertiesNV = (PFN_vkCmdWriteAccelerationStructuresPropertiesNV)load(context, "vkCmdWriteAccelerationStructuresPropertiesNV"); - table->vkCompileDeferredNV = (PFN_vkCompileDeferredNV)load(context, "vkCompileDeferredNV"); - table->vkCreateAccelerationStructureNV = (PFN_vkCreateAccelerationStructureNV)load(context, "vkCreateAccelerationStructureNV"); - table->vkCreateRayTracingPipelinesNV = (PFN_vkCreateRayTracingPipelinesNV)load(context, "vkCreateRayTracingPipelinesNV"); - table->vkDestroyAccelerationStructureNV = (PFN_vkDestroyAccelerationStructureNV)load(context, "vkDestroyAccelerationStructureNV"); - table->vkGetAccelerationStructureHandleNV = (PFN_vkGetAccelerationStructureHandleNV)load(context, "vkGetAccelerationStructureHandleNV"); - table->vkGetAccelerationStructureMemoryRequirementsNV = (PFN_vkGetAccelerationStructureMemoryRequirementsNV)load(context, "vkGetAccelerationStructureMemoryRequirementsNV"); - table->vkGetRayTracingShaderGroupHandlesNV = (PFN_vkGetRayTracingShaderGroupHandlesNV)load(context, "vkGetRayTracingShaderGroupHandlesNV"); -#endif /* defined(VK_NV_ray_tracing) */ -#if defined(VK_NV_scissor_exclusive) - table->vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV)load(context, "vkCmdSetExclusiveScissorNV"); -#endif /* defined(VK_NV_scissor_exclusive) */ -#if defined(VK_NV_shading_rate_image) - table->vkCmdBindShadingRateImageNV = (PFN_vkCmdBindShadingRateImageNV)load(context, "vkCmdBindShadingRateImageNV"); - table->vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV)load(context, "vkCmdSetCoarseSampleOrderNV"); - table->vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV)load(context, "vkCmdSetViewportShadingRatePaletteNV"); -#endif /* defined(VK_NV_shading_rate_image) */ -#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) - table->vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR)load(context, "vkCmdPushDescriptorSetWithTemplateKHR"); -#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) - table->vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)load(context, "vkGetDeviceGroupPresentCapabilitiesKHR"); - table->vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)load(context, "vkGetDeviceGroupSurfacePresentModesKHR"); -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) - table->vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR)load(context, "vkAcquireNextImage2KHR"); -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ - /* VOLK_GENERATE_LOAD_DEVICE_TABLE */ -} - -#ifdef __GNUC__ -# pragma GCC visibility push(hidden) -#endif - -/* VOLK_GENERATE_PROTOTYPES_C */ -#if defined(VK_VERSION_1_0) -PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; -PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; -PFN_vkAllocateMemory vkAllocateMemory; -PFN_vkBeginCommandBuffer vkBeginCommandBuffer; -PFN_vkBindBufferMemory vkBindBufferMemory; -PFN_vkBindImageMemory vkBindImageMemory; -PFN_vkCmdBeginQuery vkCmdBeginQuery; -PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; -PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; -PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; -PFN_vkCmdBindPipeline vkCmdBindPipeline; -PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; -PFN_vkCmdBlitImage vkCmdBlitImage; -PFN_vkCmdClearAttachments vkCmdClearAttachments; -PFN_vkCmdClearColorImage vkCmdClearColorImage; -PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; -PFN_vkCmdCopyBuffer vkCmdCopyBuffer; -PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; -PFN_vkCmdCopyImage vkCmdCopyImage; -PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; -PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; -PFN_vkCmdDispatch vkCmdDispatch; -PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; -PFN_vkCmdDraw vkCmdDraw; -PFN_vkCmdDrawIndexed vkCmdDrawIndexed; -PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; -PFN_vkCmdDrawIndirect vkCmdDrawIndirect; -PFN_vkCmdEndQuery vkCmdEndQuery; -PFN_vkCmdEndRenderPass vkCmdEndRenderPass; -PFN_vkCmdExecuteCommands vkCmdExecuteCommands; -PFN_vkCmdFillBuffer vkCmdFillBuffer; -PFN_vkCmdNextSubpass vkCmdNextSubpass; -PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; -PFN_vkCmdPushConstants vkCmdPushConstants; -PFN_vkCmdResetEvent vkCmdResetEvent; -PFN_vkCmdResetQueryPool vkCmdResetQueryPool; -PFN_vkCmdResolveImage vkCmdResolveImage; -PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; -PFN_vkCmdSetDepthBias vkCmdSetDepthBias; -PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; -PFN_vkCmdSetEvent vkCmdSetEvent; -PFN_vkCmdSetLineWidth vkCmdSetLineWidth; -PFN_vkCmdSetScissor vkCmdSetScissor; -PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; -PFN_vkCmdSetStencilReference vkCmdSetStencilReference; -PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; -PFN_vkCmdSetViewport vkCmdSetViewport; -PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; -PFN_vkCmdWaitEvents vkCmdWaitEvents; -PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; -PFN_vkCreateBuffer vkCreateBuffer; -PFN_vkCreateBufferView vkCreateBufferView; -PFN_vkCreateCommandPool vkCreateCommandPool; -PFN_vkCreateComputePipelines vkCreateComputePipelines; -PFN_vkCreateDescriptorPool vkCreateDescriptorPool; -PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; -PFN_vkCreateDevice vkCreateDevice; -PFN_vkCreateEvent vkCreateEvent; -PFN_vkCreateFence vkCreateFence; -PFN_vkCreateFramebuffer vkCreateFramebuffer; -PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; -PFN_vkCreateImage vkCreateImage; -PFN_vkCreateImageView vkCreateImageView; -PFN_vkCreateInstance vkCreateInstance; -PFN_vkCreatePipelineCache vkCreatePipelineCache; -PFN_vkCreatePipelineLayout vkCreatePipelineLayout; -PFN_vkCreateQueryPool vkCreateQueryPool; -PFN_vkCreateRenderPass vkCreateRenderPass; -PFN_vkCreateSampler vkCreateSampler; -PFN_vkCreateSemaphore vkCreateSemaphore; -PFN_vkCreateShaderModule vkCreateShaderModule; -PFN_vkDestroyBuffer vkDestroyBuffer; -PFN_vkDestroyBufferView vkDestroyBufferView; -PFN_vkDestroyCommandPool vkDestroyCommandPool; -PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; -PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; -PFN_vkDestroyDevice vkDestroyDevice; -PFN_vkDestroyEvent vkDestroyEvent; -PFN_vkDestroyFence vkDestroyFence; -PFN_vkDestroyFramebuffer vkDestroyFramebuffer; -PFN_vkDestroyImage vkDestroyImage; -PFN_vkDestroyImageView vkDestroyImageView; -PFN_vkDestroyInstance vkDestroyInstance; -PFN_vkDestroyPipeline vkDestroyPipeline; -PFN_vkDestroyPipelineCache vkDestroyPipelineCache; -PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; -PFN_vkDestroyQueryPool vkDestroyQueryPool; -PFN_vkDestroyRenderPass vkDestroyRenderPass; -PFN_vkDestroySampler vkDestroySampler; -PFN_vkDestroySemaphore vkDestroySemaphore; -PFN_vkDestroyShaderModule vkDestroyShaderModule; -PFN_vkDeviceWaitIdle vkDeviceWaitIdle; -PFN_vkEndCommandBuffer vkEndCommandBuffer; -PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; -PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; -PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; -PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; -PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; -PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; -PFN_vkFreeCommandBuffers vkFreeCommandBuffers; -PFN_vkFreeDescriptorSets vkFreeDescriptorSets; -PFN_vkFreeMemory vkFreeMemory; -PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; -PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; -PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; -PFN_vkGetDeviceQueue vkGetDeviceQueue; -PFN_vkGetEventStatus vkGetEventStatus; -PFN_vkGetFenceStatus vkGetFenceStatus; -PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; -PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; -PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; -PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; -PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; -PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; -PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; -PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; -PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; -PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; -PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; -PFN_vkGetPipelineCacheData vkGetPipelineCacheData; -PFN_vkGetQueryPoolResults vkGetQueryPoolResults; -PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; -PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; -PFN_vkMapMemory vkMapMemory; -PFN_vkMergePipelineCaches vkMergePipelineCaches; -PFN_vkQueueBindSparse vkQueueBindSparse; -PFN_vkQueueSubmit vkQueueSubmit; -PFN_vkQueueWaitIdle vkQueueWaitIdle; -PFN_vkResetCommandBuffer vkResetCommandBuffer; -PFN_vkResetCommandPool vkResetCommandPool; -PFN_vkResetDescriptorPool vkResetDescriptorPool; -PFN_vkResetEvent vkResetEvent; -PFN_vkResetFences vkResetFences; -PFN_vkSetEvent vkSetEvent; -PFN_vkUnmapMemory vkUnmapMemory; -PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; -PFN_vkWaitForFences vkWaitForFences; -#endif /* defined(VK_VERSION_1_0) */ -#if defined(VK_VERSION_1_1) -PFN_vkBindBufferMemory2 vkBindBufferMemory2; -PFN_vkBindImageMemory2 vkBindImageMemory2; -PFN_vkCmdDispatchBase vkCmdDispatchBase; -PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; -PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; -PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; -PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; -PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; -PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; -PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups; -PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; -PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; -PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; -PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; -PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; -PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; -PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties; -PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties; -PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties; -PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; -PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2; -PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2; -PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; -PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; -PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2; -PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2; -PFN_vkTrimCommandPool vkTrimCommandPool; -PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; -#endif /* defined(VK_VERSION_1_1) */ -#if defined(VK_AMD_buffer_marker) -PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; -#endif /* defined(VK_AMD_buffer_marker) */ -#if defined(VK_AMD_draw_indirect_count) -PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; -PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; -#endif /* defined(VK_AMD_draw_indirect_count) */ -#if defined(VK_AMD_shader_info) -PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; -#endif /* defined(VK_AMD_shader_info) */ -#if defined(VK_ANDROID_external_memory_android_hardware_buffer) -PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; -PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; -#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ -#if defined(VK_EXT_acquire_xlib_display) -PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; -PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; -#endif /* defined(VK_EXT_acquire_xlib_display) */ -#if defined(VK_EXT_buffer_device_address) -PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; -#endif /* defined(VK_EXT_buffer_device_address) */ -#if defined(VK_EXT_calibrated_timestamps) -PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; -PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; -#endif /* defined(VK_EXT_calibrated_timestamps) */ -#if defined(VK_EXT_conditional_rendering) -PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; -PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; -#endif /* defined(VK_EXT_conditional_rendering) */ -#if defined(VK_EXT_debug_marker) -PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; -PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; -PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; -PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; -PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; -#endif /* defined(VK_EXT_debug_marker) */ -#if defined(VK_EXT_debug_report) -PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; -PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; -PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; -#endif /* defined(VK_EXT_debug_report) */ -#if defined(VK_EXT_debug_utils) -PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; -PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; -PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; -PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; -PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; -PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; -PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; -PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; -PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; -PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; -PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT; -#endif /* defined(VK_EXT_debug_utils) */ -#if defined(VK_EXT_direct_mode_display) -PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; -#endif /* defined(VK_EXT_direct_mode_display) */ -#if defined(VK_EXT_discard_rectangles) -PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; -#endif /* defined(VK_EXT_discard_rectangles) */ -#if defined(VK_EXT_display_control) -PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; -PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; -PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; -PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; -#endif /* defined(VK_EXT_display_control) */ -#if defined(VK_EXT_display_surface_counter) -PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT; -#endif /* defined(VK_EXT_display_surface_counter) */ -#if defined(VK_EXT_external_memory_host) -PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; -#endif /* defined(VK_EXT_external_memory_host) */ -#if defined(VK_EXT_hdr_metadata) -PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; -#endif /* defined(VK_EXT_hdr_metadata) */ -#if defined(VK_EXT_image_drm_format_modifier) -PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; -#endif /* defined(VK_EXT_image_drm_format_modifier) */ -#if defined(VK_EXT_metal_surface) -PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; -#endif /* defined(VK_EXT_metal_surface) */ -#if defined(VK_EXT_sample_locations) -PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; -PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT; -#endif /* defined(VK_EXT_sample_locations) */ -#if defined(VK_EXT_transform_feedback) -PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; -PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; -PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; -PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; -PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; -PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; -#endif /* defined(VK_EXT_transform_feedback) */ -#if defined(VK_EXT_validation_cache) -PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; -PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; -PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; -PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; -#endif /* defined(VK_EXT_validation_cache) */ -#if defined(VK_FUCHSIA_imagepipe_surface) -PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; -#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ -#if defined(VK_GOOGLE_display_timing) -PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; -PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; -#endif /* defined(VK_GOOGLE_display_timing) */ -#if defined(VK_KHR_android_surface) -PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; -#endif /* defined(VK_KHR_android_surface) */ -#if defined(VK_KHR_bind_memory2) -PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; -PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; -#endif /* defined(VK_KHR_bind_memory2) */ -#if defined(VK_KHR_create_renderpass2) -PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; -PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; -PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; -PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; -#endif /* defined(VK_KHR_create_renderpass2) */ -#if defined(VK_KHR_descriptor_update_template) -PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; -PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; -PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; -#endif /* defined(VK_KHR_descriptor_update_template) */ -#if defined(VK_KHR_device_group) -PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; -PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; -PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; -#endif /* defined(VK_KHR_device_group) */ -#if defined(VK_KHR_device_group_creation) -PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR; -#endif /* defined(VK_KHR_device_group_creation) */ -#if defined(VK_KHR_display) -PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; -PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; -PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; -PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; -PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; -PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; -PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; -#endif /* defined(VK_KHR_display) */ -#if defined(VK_KHR_display_swapchain) -PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; -#endif /* defined(VK_KHR_display_swapchain) */ -#if defined(VK_KHR_draw_indirect_count) -PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; -PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; -#endif /* defined(VK_KHR_draw_indirect_count) */ -#if defined(VK_KHR_external_fence_capabilities) -PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR vkGetPhysicalDeviceExternalFencePropertiesKHR; -#endif /* defined(VK_KHR_external_fence_capabilities) */ -#if defined(VK_KHR_external_fence_fd) -PFN_vkGetFenceFdKHR vkGetFenceFdKHR; -PFN_vkImportFenceFdKHR vkImportFenceFdKHR; -#endif /* defined(VK_KHR_external_fence_fd) */ -#if defined(VK_KHR_external_fence_win32) -PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; -PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; -#endif /* defined(VK_KHR_external_fence_win32) */ -#if defined(VK_KHR_external_memory_capabilities) -PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; -#endif /* defined(VK_KHR_external_memory_capabilities) */ -#if defined(VK_KHR_external_memory_fd) -PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; -PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; -#endif /* defined(VK_KHR_external_memory_fd) */ -#if defined(VK_KHR_external_memory_win32) -PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; -PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; -#endif /* defined(VK_KHR_external_memory_win32) */ -#if defined(VK_KHR_external_semaphore_capabilities) -PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR vkGetPhysicalDeviceExternalSemaphorePropertiesKHR; -#endif /* defined(VK_KHR_external_semaphore_capabilities) */ -#if defined(VK_KHR_external_semaphore_fd) -PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; -PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; -#endif /* defined(VK_KHR_external_semaphore_fd) */ -#if defined(VK_KHR_external_semaphore_win32) -PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; -PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; -#endif /* defined(VK_KHR_external_semaphore_win32) */ -#if defined(VK_KHR_get_display_properties2) -PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR; -PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR; -PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR; -PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR; -#endif /* defined(VK_KHR_get_display_properties2) */ -#if defined(VK_KHR_get_memory_requirements2) -PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; -PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; -PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; -#endif /* defined(VK_KHR_get_memory_requirements2) */ -#if defined(VK_KHR_get_physical_device_properties2) -PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; -PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; -PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; -PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; -PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; -PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; -PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; -#endif /* defined(VK_KHR_get_physical_device_properties2) */ -#if defined(VK_KHR_get_surface_capabilities2) -PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; -PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; -#endif /* defined(VK_KHR_get_surface_capabilities2) */ -#if defined(VK_KHR_maintenance1) -PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; -#endif /* defined(VK_KHR_maintenance1) */ -#if defined(VK_KHR_maintenance3) -PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; -#endif /* defined(VK_KHR_maintenance3) */ -#if defined(VK_KHR_push_descriptor) -PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; -#endif /* defined(VK_KHR_push_descriptor) */ -#if defined(VK_KHR_sampler_ycbcr_conversion) -PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; -PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; -#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ -#if defined(VK_KHR_shared_presentable_image) -PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; -#endif /* defined(VK_KHR_shared_presentable_image) */ -#if defined(VK_KHR_surface) -PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; -PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; -PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; -PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; -PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; -#endif /* defined(VK_KHR_surface) */ -#if defined(VK_KHR_swapchain) -PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; -PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; -PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; -PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; -PFN_vkQueuePresentKHR vkQueuePresentKHR; -#endif /* defined(VK_KHR_swapchain) */ -#if defined(VK_KHR_wayland_surface) -PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; -PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; -#endif /* defined(VK_KHR_wayland_surface) */ -#if defined(VK_KHR_win32_surface) -PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; -PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; -#endif /* defined(VK_KHR_win32_surface) */ -#if defined(VK_KHR_xcb_surface) -PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; -PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; -#endif /* defined(VK_KHR_xcb_surface) */ -#if defined(VK_KHR_xlib_surface) -PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; -PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; -#endif /* defined(VK_KHR_xlib_surface) */ -#if defined(VK_MVK_ios_surface) -PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK; -#endif /* defined(VK_MVK_ios_surface) */ -#if defined(VK_MVK_macos_surface) -PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; -#endif /* defined(VK_MVK_macos_surface) */ -#if defined(VK_NN_vi_surface) -PFN_vkCreateViSurfaceNN vkCreateViSurfaceNN; -#endif /* defined(VK_NN_vi_surface) */ -#if defined(VK_NVX_device_generated_commands) -PFN_vkCmdProcessCommandsNVX vkCmdProcessCommandsNVX; -PFN_vkCmdReserveSpaceForCommandsNVX vkCmdReserveSpaceForCommandsNVX; -PFN_vkCreateIndirectCommandsLayoutNVX vkCreateIndirectCommandsLayoutNVX; -PFN_vkCreateObjectTableNVX vkCreateObjectTableNVX; -PFN_vkDestroyIndirectCommandsLayoutNVX vkDestroyIndirectCommandsLayoutNVX; -PFN_vkDestroyObjectTableNVX vkDestroyObjectTableNVX; -PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX; -PFN_vkRegisterObjectsNVX vkRegisterObjectsNVX; -PFN_vkUnregisterObjectsNVX vkUnregisterObjectsNVX; -#endif /* defined(VK_NVX_device_generated_commands) */ -#if defined(VK_NVX_image_view_handle) -PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; -#endif /* defined(VK_NVX_image_view_handle) */ -#if defined(VK_NV_clip_space_w_scaling) -PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; -#endif /* defined(VK_NV_clip_space_w_scaling) */ -#if defined(VK_NV_cooperative_matrix) -PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; -#endif /* defined(VK_NV_cooperative_matrix) */ -#if defined(VK_NV_device_diagnostic_checkpoints) -PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; -PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; -#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ -#if defined(VK_NV_external_memory_capabilities) -PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV vkGetPhysicalDeviceExternalImageFormatPropertiesNV; -#endif /* defined(VK_NV_external_memory_capabilities) */ -#if defined(VK_NV_external_memory_win32) -PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; -#endif /* defined(VK_NV_external_memory_win32) */ -#if defined(VK_NV_mesh_shader) -PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; -PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; -PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; -#endif /* defined(VK_NV_mesh_shader) */ -#if defined(VK_NV_ray_tracing) -PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; -PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; -PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; -PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; -PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; -PFN_vkCompileDeferredNV vkCompileDeferredNV; -PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; -PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; -PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; -PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; -PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; -PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; -#endif /* defined(VK_NV_ray_tracing) */ -#if defined(VK_NV_scissor_exclusive) -PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; -#endif /* defined(VK_NV_scissor_exclusive) */ -#if defined(VK_NV_shading_rate_image) -PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; -PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; -PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; -#endif /* defined(VK_NV_shading_rate_image) */ -#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) -PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; -#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) -PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; -PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; -PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR; -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) -PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ -/* VOLK_GENERATE_PROTOTYPES_C */ - -#ifdef __GNUC__ -# pragma GCC visibility pop -#endif - -#ifdef __cplusplus -} -#endif diff --git a/src/rendering/vulkan/thirdparty/volk/volk.h b/src/rendering/vulkan/thirdparty/volk/volk.h deleted file mode 100644 index 143e8f331e5..00000000000 --- a/src/rendering/vulkan/thirdparty/volk/volk.h +++ /dev/null @@ -1,969 +0,0 @@ -/** - * volk - * - * Copyright (C) 2018-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) - * Report bugs and download new versions at https://github.com/zeux/volk - * - * This library is distributed under the MIT License. See notice at the end of this file. - */ -#ifndef VOLK_H_ -#define VOLK_H_ - -#if defined(VULKAN_H_) && !defined(VK_NO_PROTOTYPES) -# error To use volk, you need to define VK_NO_PROTOTYPES before including vulkan.h -#endif - -/* VOLK_GENERATE_VERSION */ -#define VOLK_HEADER_VERSION 102 -/* VOLK_GENERATE_VERSION */ - -#ifndef VK_NO_PROTOTYPES -# define VK_NO_PROTOTYPES -#endif - -#ifndef VULKAN_H_ -# include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct VolkDeviceTable; - -/** - * Initialize library by loading Vulkan loader; call this function before creating the Vulkan instance. - * - * Returns VK_SUCCESS on success and VK_ERROR_INITIALIZATION_FAILED otherwise. - */ -VkResult volkInitialize(void); - -/** - * Initialize library by providing a custom handler to load global symbols. - * - * This function can be used instead of volkInitialize. - * The handler function pointer will be asked to load global Vulkan symbols which require no instance - * (such as vkCreateInstance, vkEnumerateInstance* and vkEnumerateInstanceVersion if available). - */ -void volkInitializeCustom(PFN_vkGetInstanceProcAddr handler); - -/** - * Get Vulkan instance version supported by the Vulkan loader, or 0 if Vulkan isn't supported - * - * Returns 0 if volkInitialize wasn't called or failed. - */ -uint32_t volkGetInstanceVersion(void); - -/** - * Load global function pointers using application-created VkInstance; call this function after creating the Vulkan instance. - */ -void volkLoadInstance(VkInstance instance); - -/** - * Load global function pointers using application-created VkDevice; call this function after creating the Vulkan device. - * - * Note: this is not suitable for applications that want to use multiple VkDevice objects concurrently. - */ -void volkLoadDevice(VkDevice device); - -/** - * Load function pointers using application-created VkDevice into a table. - * Application should use function pointers from that table instead of using global function pointers. - */ -void volkLoadDeviceTable(struct VolkDeviceTable* table, VkDevice device); - -/** - * Device-specific function pointer table - */ -struct VolkDeviceTable -{ - /* VOLK_GENERATE_DEVICE_TABLE */ -#if defined(VK_VERSION_1_0) - PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; - PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; - PFN_vkAllocateMemory vkAllocateMemory; - PFN_vkBeginCommandBuffer vkBeginCommandBuffer; - PFN_vkBindBufferMemory vkBindBufferMemory; - PFN_vkBindImageMemory vkBindImageMemory; - PFN_vkCmdBeginQuery vkCmdBeginQuery; - PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; - PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; - PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; - PFN_vkCmdBindPipeline vkCmdBindPipeline; - PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; - PFN_vkCmdBlitImage vkCmdBlitImage; - PFN_vkCmdClearAttachments vkCmdClearAttachments; - PFN_vkCmdClearColorImage vkCmdClearColorImage; - PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; - PFN_vkCmdCopyBuffer vkCmdCopyBuffer; - PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; - PFN_vkCmdCopyImage vkCmdCopyImage; - PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; - PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; - PFN_vkCmdDispatch vkCmdDispatch; - PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; - PFN_vkCmdDraw vkCmdDraw; - PFN_vkCmdDrawIndexed vkCmdDrawIndexed; - PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; - PFN_vkCmdDrawIndirect vkCmdDrawIndirect; - PFN_vkCmdEndQuery vkCmdEndQuery; - PFN_vkCmdEndRenderPass vkCmdEndRenderPass; - PFN_vkCmdExecuteCommands vkCmdExecuteCommands; - PFN_vkCmdFillBuffer vkCmdFillBuffer; - PFN_vkCmdNextSubpass vkCmdNextSubpass; - PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; - PFN_vkCmdPushConstants vkCmdPushConstants; - PFN_vkCmdResetEvent vkCmdResetEvent; - PFN_vkCmdResetQueryPool vkCmdResetQueryPool; - PFN_vkCmdResolveImage vkCmdResolveImage; - PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; - PFN_vkCmdSetDepthBias vkCmdSetDepthBias; - PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; - PFN_vkCmdSetEvent vkCmdSetEvent; - PFN_vkCmdSetLineWidth vkCmdSetLineWidth; - PFN_vkCmdSetScissor vkCmdSetScissor; - PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; - PFN_vkCmdSetStencilReference vkCmdSetStencilReference; - PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; - PFN_vkCmdSetViewport vkCmdSetViewport; - PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; - PFN_vkCmdWaitEvents vkCmdWaitEvents; - PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; - PFN_vkCreateBuffer vkCreateBuffer; - PFN_vkCreateBufferView vkCreateBufferView; - PFN_vkCreateCommandPool vkCreateCommandPool; - PFN_vkCreateComputePipelines vkCreateComputePipelines; - PFN_vkCreateDescriptorPool vkCreateDescriptorPool; - PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; - PFN_vkCreateEvent vkCreateEvent; - PFN_vkCreateFence vkCreateFence; - PFN_vkCreateFramebuffer vkCreateFramebuffer; - PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; - PFN_vkCreateImage vkCreateImage; - PFN_vkCreateImageView vkCreateImageView; - PFN_vkCreatePipelineCache vkCreatePipelineCache; - PFN_vkCreatePipelineLayout vkCreatePipelineLayout; - PFN_vkCreateQueryPool vkCreateQueryPool; - PFN_vkCreateRenderPass vkCreateRenderPass; - PFN_vkCreateSampler vkCreateSampler; - PFN_vkCreateSemaphore vkCreateSemaphore; - PFN_vkCreateShaderModule vkCreateShaderModule; - PFN_vkDestroyBuffer vkDestroyBuffer; - PFN_vkDestroyBufferView vkDestroyBufferView; - PFN_vkDestroyCommandPool vkDestroyCommandPool; - PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; - PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; - PFN_vkDestroyDevice vkDestroyDevice; - PFN_vkDestroyEvent vkDestroyEvent; - PFN_vkDestroyFence vkDestroyFence; - PFN_vkDestroyFramebuffer vkDestroyFramebuffer; - PFN_vkDestroyImage vkDestroyImage; - PFN_vkDestroyImageView vkDestroyImageView; - PFN_vkDestroyPipeline vkDestroyPipeline; - PFN_vkDestroyPipelineCache vkDestroyPipelineCache; - PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; - PFN_vkDestroyQueryPool vkDestroyQueryPool; - PFN_vkDestroyRenderPass vkDestroyRenderPass; - PFN_vkDestroySampler vkDestroySampler; - PFN_vkDestroySemaphore vkDestroySemaphore; - PFN_vkDestroyShaderModule vkDestroyShaderModule; - PFN_vkDeviceWaitIdle vkDeviceWaitIdle; - PFN_vkEndCommandBuffer vkEndCommandBuffer; - PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; - PFN_vkFreeCommandBuffers vkFreeCommandBuffers; - PFN_vkFreeDescriptorSets vkFreeDescriptorSets; - PFN_vkFreeMemory vkFreeMemory; - PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; - PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; - PFN_vkGetDeviceQueue vkGetDeviceQueue; - PFN_vkGetEventStatus vkGetEventStatus; - PFN_vkGetFenceStatus vkGetFenceStatus; - PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; - PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; - PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; - PFN_vkGetPipelineCacheData vkGetPipelineCacheData; - PFN_vkGetQueryPoolResults vkGetQueryPoolResults; - PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; - PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; - PFN_vkMapMemory vkMapMemory; - PFN_vkMergePipelineCaches vkMergePipelineCaches; - PFN_vkQueueBindSparse vkQueueBindSparse; - PFN_vkQueueSubmit vkQueueSubmit; - PFN_vkQueueWaitIdle vkQueueWaitIdle; - PFN_vkResetCommandBuffer vkResetCommandBuffer; - PFN_vkResetCommandPool vkResetCommandPool; - PFN_vkResetDescriptorPool vkResetDescriptorPool; - PFN_vkResetEvent vkResetEvent; - PFN_vkResetFences vkResetFences; - PFN_vkSetEvent vkSetEvent; - PFN_vkUnmapMemory vkUnmapMemory; - PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; - PFN_vkWaitForFences vkWaitForFences; -#endif /* defined(VK_VERSION_1_0) */ -#if defined(VK_VERSION_1_1) - PFN_vkBindBufferMemory2 vkBindBufferMemory2; - PFN_vkBindImageMemory2 vkBindImageMemory2; - PFN_vkCmdDispatchBase vkCmdDispatchBase; - PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; - PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; - PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; - PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; - PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; - PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; - PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; - PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; - PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; - PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; - PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; - PFN_vkTrimCommandPool vkTrimCommandPool; - PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; -#endif /* defined(VK_VERSION_1_1) */ -#if defined(VK_AMD_buffer_marker) - PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; -#endif /* defined(VK_AMD_buffer_marker) */ -#if defined(VK_AMD_draw_indirect_count) - PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; - PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; -#endif /* defined(VK_AMD_draw_indirect_count) */ -#if defined(VK_AMD_shader_info) - PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; -#endif /* defined(VK_AMD_shader_info) */ -#if defined(VK_ANDROID_external_memory_android_hardware_buffer) - PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; - PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; -#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ -#if defined(VK_EXT_buffer_device_address) - PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; -#endif /* defined(VK_EXT_buffer_device_address) */ -#if defined(VK_EXT_calibrated_timestamps) - PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; -#endif /* defined(VK_EXT_calibrated_timestamps) */ -#if defined(VK_EXT_conditional_rendering) - PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; - PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; -#endif /* defined(VK_EXT_conditional_rendering) */ -#if defined(VK_EXT_debug_marker) - PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; - PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; - PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; - PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; - PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; -#endif /* defined(VK_EXT_debug_marker) */ -#if defined(VK_EXT_debug_utils) - PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; - PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; - PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; - PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; - PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; - PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; - PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; - PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; -#endif /* defined(VK_EXT_debug_utils) */ -#if defined(VK_EXT_discard_rectangles) - PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; -#endif /* defined(VK_EXT_discard_rectangles) */ -#if defined(VK_EXT_display_control) - PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; - PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; - PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; - PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; -#endif /* defined(VK_EXT_display_control) */ -#if defined(VK_EXT_external_memory_host) - PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; -#endif /* defined(VK_EXT_external_memory_host) */ -#if defined(VK_EXT_hdr_metadata) - PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; -#endif /* defined(VK_EXT_hdr_metadata) */ -#if defined(VK_EXT_image_drm_format_modifier) - PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; -#endif /* defined(VK_EXT_image_drm_format_modifier) */ -#if defined(VK_EXT_sample_locations) - PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; -#endif /* defined(VK_EXT_sample_locations) */ -#if defined(VK_EXT_transform_feedback) - PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; - PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; - PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; - PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; - PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; - PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; -#endif /* defined(VK_EXT_transform_feedback) */ -#if defined(VK_EXT_validation_cache) - PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; - PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; - PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; - PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; -#endif /* defined(VK_EXT_validation_cache) */ -#if defined(VK_GOOGLE_display_timing) - PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; - PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; -#endif /* defined(VK_GOOGLE_display_timing) */ -#if defined(VK_KHR_bind_memory2) - PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; - PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; -#endif /* defined(VK_KHR_bind_memory2) */ -#if defined(VK_KHR_create_renderpass2) - PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; - PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; - PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; - PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; -#endif /* defined(VK_KHR_create_renderpass2) */ -#if defined(VK_KHR_descriptor_update_template) - PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; - PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; - PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; -#endif /* defined(VK_KHR_descriptor_update_template) */ -#if defined(VK_KHR_device_group) - PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; - PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; - PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; -#endif /* defined(VK_KHR_device_group) */ -#if defined(VK_KHR_display_swapchain) - PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; -#endif /* defined(VK_KHR_display_swapchain) */ -#if defined(VK_KHR_draw_indirect_count) - PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; - PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; -#endif /* defined(VK_KHR_draw_indirect_count) */ -#if defined(VK_KHR_external_fence_fd) - PFN_vkGetFenceFdKHR vkGetFenceFdKHR; - PFN_vkImportFenceFdKHR vkImportFenceFdKHR; -#endif /* defined(VK_KHR_external_fence_fd) */ -#if defined(VK_KHR_external_fence_win32) - PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; - PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; -#endif /* defined(VK_KHR_external_fence_win32) */ -#if defined(VK_KHR_external_memory_fd) - PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; - PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; -#endif /* defined(VK_KHR_external_memory_fd) */ -#if defined(VK_KHR_external_memory_win32) - PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; - PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; -#endif /* defined(VK_KHR_external_memory_win32) */ -#if defined(VK_KHR_external_semaphore_fd) - PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; - PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; -#endif /* defined(VK_KHR_external_semaphore_fd) */ -#if defined(VK_KHR_external_semaphore_win32) - PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; - PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; -#endif /* defined(VK_KHR_external_semaphore_win32) */ -#if defined(VK_KHR_get_memory_requirements2) - PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; - PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; - PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; -#endif /* defined(VK_KHR_get_memory_requirements2) */ -#if defined(VK_KHR_maintenance1) - PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; -#endif /* defined(VK_KHR_maintenance1) */ -#if defined(VK_KHR_maintenance3) - PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; -#endif /* defined(VK_KHR_maintenance3) */ -#if defined(VK_KHR_push_descriptor) - PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; -#endif /* defined(VK_KHR_push_descriptor) */ -#if defined(VK_KHR_sampler_ycbcr_conversion) - PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; - PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; -#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ -#if defined(VK_KHR_shared_presentable_image) - PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; -#endif /* defined(VK_KHR_shared_presentable_image) */ -#if defined(VK_KHR_swapchain) - PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; - PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; - PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; - PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; - PFN_vkQueuePresentKHR vkQueuePresentKHR; -#endif /* defined(VK_KHR_swapchain) */ -#if defined(VK_NVX_device_generated_commands) - PFN_vkCmdProcessCommandsNVX vkCmdProcessCommandsNVX; - PFN_vkCmdReserveSpaceForCommandsNVX vkCmdReserveSpaceForCommandsNVX; - PFN_vkCreateIndirectCommandsLayoutNVX vkCreateIndirectCommandsLayoutNVX; - PFN_vkCreateObjectTableNVX vkCreateObjectTableNVX; - PFN_vkDestroyIndirectCommandsLayoutNVX vkDestroyIndirectCommandsLayoutNVX; - PFN_vkDestroyObjectTableNVX vkDestroyObjectTableNVX; - PFN_vkRegisterObjectsNVX vkRegisterObjectsNVX; - PFN_vkUnregisterObjectsNVX vkUnregisterObjectsNVX; -#endif /* defined(VK_NVX_device_generated_commands) */ -#if defined(VK_NVX_image_view_handle) - PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; -#endif /* defined(VK_NVX_image_view_handle) */ -#if defined(VK_NV_clip_space_w_scaling) - PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; -#endif /* defined(VK_NV_clip_space_w_scaling) */ -#if defined(VK_NV_device_diagnostic_checkpoints) - PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; - PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; -#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ -#if defined(VK_NV_external_memory_win32) - PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; -#endif /* defined(VK_NV_external_memory_win32) */ -#if defined(VK_NV_mesh_shader) - PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; - PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; - PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; -#endif /* defined(VK_NV_mesh_shader) */ -#if defined(VK_NV_ray_tracing) - PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; - PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; - PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; - PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; - PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; - PFN_vkCompileDeferredNV vkCompileDeferredNV; - PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; - PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; - PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; - PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; - PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; - PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; -#endif /* defined(VK_NV_ray_tracing) */ -#if defined(VK_NV_scissor_exclusive) - PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; -#endif /* defined(VK_NV_scissor_exclusive) */ -#if defined(VK_NV_shading_rate_image) - PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; - PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; - PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; -#endif /* defined(VK_NV_shading_rate_image) */ -#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) - PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; -#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) - PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; - PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) - PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ - /* VOLK_GENERATE_DEVICE_TABLE */ -}; - -/* VOLK_GENERATE_PROTOTYPES_H */ -#if defined(VK_VERSION_1_0) -extern PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; -extern PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; -extern PFN_vkAllocateMemory vkAllocateMemory; -extern PFN_vkBeginCommandBuffer vkBeginCommandBuffer; -extern PFN_vkBindBufferMemory vkBindBufferMemory; -extern PFN_vkBindImageMemory vkBindImageMemory; -extern PFN_vkCmdBeginQuery vkCmdBeginQuery; -extern PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; -extern PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; -extern PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; -extern PFN_vkCmdBindPipeline vkCmdBindPipeline; -extern PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; -extern PFN_vkCmdBlitImage vkCmdBlitImage; -extern PFN_vkCmdClearAttachments vkCmdClearAttachments; -extern PFN_vkCmdClearColorImage vkCmdClearColorImage; -extern PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; -extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; -extern PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; -extern PFN_vkCmdCopyImage vkCmdCopyImage; -extern PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; -extern PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; -extern PFN_vkCmdDispatch vkCmdDispatch; -extern PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; -extern PFN_vkCmdDraw vkCmdDraw; -extern PFN_vkCmdDrawIndexed vkCmdDrawIndexed; -extern PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; -extern PFN_vkCmdDrawIndirect vkCmdDrawIndirect; -extern PFN_vkCmdEndQuery vkCmdEndQuery; -extern PFN_vkCmdEndRenderPass vkCmdEndRenderPass; -extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands; -extern PFN_vkCmdFillBuffer vkCmdFillBuffer; -extern PFN_vkCmdNextSubpass vkCmdNextSubpass; -extern PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; -extern PFN_vkCmdPushConstants vkCmdPushConstants; -extern PFN_vkCmdResetEvent vkCmdResetEvent; -extern PFN_vkCmdResetQueryPool vkCmdResetQueryPool; -extern PFN_vkCmdResolveImage vkCmdResolveImage; -extern PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; -extern PFN_vkCmdSetDepthBias vkCmdSetDepthBias; -extern PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; -extern PFN_vkCmdSetEvent vkCmdSetEvent; -extern PFN_vkCmdSetLineWidth vkCmdSetLineWidth; -extern PFN_vkCmdSetScissor vkCmdSetScissor; -extern PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; -extern PFN_vkCmdSetStencilReference vkCmdSetStencilReference; -extern PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; -extern PFN_vkCmdSetViewport vkCmdSetViewport; -extern PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; -extern PFN_vkCmdWaitEvents vkCmdWaitEvents; -extern PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; -extern PFN_vkCreateBuffer vkCreateBuffer; -extern PFN_vkCreateBufferView vkCreateBufferView; -extern PFN_vkCreateCommandPool vkCreateCommandPool; -extern PFN_vkCreateComputePipelines vkCreateComputePipelines; -extern PFN_vkCreateDescriptorPool vkCreateDescriptorPool; -extern PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; -extern PFN_vkCreateDevice vkCreateDevice; -extern PFN_vkCreateEvent vkCreateEvent; -extern PFN_vkCreateFence vkCreateFence; -extern PFN_vkCreateFramebuffer vkCreateFramebuffer; -extern PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; -extern PFN_vkCreateImage vkCreateImage; -extern PFN_vkCreateImageView vkCreateImageView; -extern PFN_vkCreateInstance vkCreateInstance; -extern PFN_vkCreatePipelineCache vkCreatePipelineCache; -extern PFN_vkCreatePipelineLayout vkCreatePipelineLayout; -extern PFN_vkCreateQueryPool vkCreateQueryPool; -extern PFN_vkCreateRenderPass vkCreateRenderPass; -extern PFN_vkCreateSampler vkCreateSampler; -extern PFN_vkCreateSemaphore vkCreateSemaphore; -extern PFN_vkCreateShaderModule vkCreateShaderModule; -extern PFN_vkDestroyBuffer vkDestroyBuffer; -extern PFN_vkDestroyBufferView vkDestroyBufferView; -extern PFN_vkDestroyCommandPool vkDestroyCommandPool; -extern PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; -extern PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; -extern PFN_vkDestroyDevice vkDestroyDevice; -extern PFN_vkDestroyEvent vkDestroyEvent; -extern PFN_vkDestroyFence vkDestroyFence; -extern PFN_vkDestroyFramebuffer vkDestroyFramebuffer; -extern PFN_vkDestroyImage vkDestroyImage; -extern PFN_vkDestroyImageView vkDestroyImageView; -extern PFN_vkDestroyInstance vkDestroyInstance; -extern PFN_vkDestroyPipeline vkDestroyPipeline; -extern PFN_vkDestroyPipelineCache vkDestroyPipelineCache; -extern PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; -extern PFN_vkDestroyQueryPool vkDestroyQueryPool; -extern PFN_vkDestroyRenderPass vkDestroyRenderPass; -extern PFN_vkDestroySampler vkDestroySampler; -extern PFN_vkDestroySemaphore vkDestroySemaphore; -extern PFN_vkDestroyShaderModule vkDestroyShaderModule; -extern PFN_vkDeviceWaitIdle vkDeviceWaitIdle; -extern PFN_vkEndCommandBuffer vkEndCommandBuffer; -extern PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; -extern PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; -extern PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; -extern PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; -extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; -extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; -extern PFN_vkFreeCommandBuffers vkFreeCommandBuffers; -extern PFN_vkFreeDescriptorSets vkFreeDescriptorSets; -extern PFN_vkFreeMemory vkFreeMemory; -extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; -extern PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; -extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; -extern PFN_vkGetDeviceQueue vkGetDeviceQueue; -extern PFN_vkGetEventStatus vkGetEventStatus; -extern PFN_vkGetFenceStatus vkGetFenceStatus; -extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; -extern PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; -extern PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; -extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; -extern PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; -extern PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; -extern PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; -extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; -extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; -extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; -extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; -extern PFN_vkGetPipelineCacheData vkGetPipelineCacheData; -extern PFN_vkGetQueryPoolResults vkGetQueryPoolResults; -extern PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; -extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; -extern PFN_vkMapMemory vkMapMemory; -extern PFN_vkMergePipelineCaches vkMergePipelineCaches; -extern PFN_vkQueueBindSparse vkQueueBindSparse; -extern PFN_vkQueueSubmit vkQueueSubmit; -extern PFN_vkQueueWaitIdle vkQueueWaitIdle; -extern PFN_vkResetCommandBuffer vkResetCommandBuffer; -extern PFN_vkResetCommandPool vkResetCommandPool; -extern PFN_vkResetDescriptorPool vkResetDescriptorPool; -extern PFN_vkResetEvent vkResetEvent; -extern PFN_vkResetFences vkResetFences; -extern PFN_vkSetEvent vkSetEvent; -extern PFN_vkUnmapMemory vkUnmapMemory; -extern PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; -extern PFN_vkWaitForFences vkWaitForFences; -#endif /* defined(VK_VERSION_1_0) */ -#if defined(VK_VERSION_1_1) -extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; -extern PFN_vkBindImageMemory2 vkBindImageMemory2; -extern PFN_vkCmdDispatchBase vkCmdDispatchBase; -extern PFN_vkCmdSetDeviceMask vkCmdSetDeviceMask; -extern PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate; -extern PFN_vkCreateSamplerYcbcrConversion vkCreateSamplerYcbcrConversion; -extern PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate; -extern PFN_vkDestroySamplerYcbcrConversion vkDestroySamplerYcbcrConversion; -extern PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; -extern PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups; -extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; -extern PFN_vkGetDescriptorSetLayoutSupport vkGetDescriptorSetLayoutSupport; -extern PFN_vkGetDeviceGroupPeerMemoryFeatures vkGetDeviceGroupPeerMemoryFeatures; -extern PFN_vkGetDeviceQueue2 vkGetDeviceQueue2; -extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; -extern PFN_vkGetImageSparseMemoryRequirements2 vkGetImageSparseMemoryRequirements2; -extern PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties; -extern PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties; -extern PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties; -extern PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2; -extern PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2; -extern PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2; -extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; -extern PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2; -extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2; -extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2; -extern PFN_vkTrimCommandPool vkTrimCommandPool; -extern PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate; -#endif /* defined(VK_VERSION_1_1) */ -#if defined(VK_AMD_buffer_marker) -extern PFN_vkCmdWriteBufferMarkerAMD vkCmdWriteBufferMarkerAMD; -#endif /* defined(VK_AMD_buffer_marker) */ -#if defined(VK_AMD_draw_indirect_count) -extern PFN_vkCmdDrawIndexedIndirectCountAMD vkCmdDrawIndexedIndirectCountAMD; -extern PFN_vkCmdDrawIndirectCountAMD vkCmdDrawIndirectCountAMD; -#endif /* defined(VK_AMD_draw_indirect_count) */ -#if defined(VK_AMD_shader_info) -extern PFN_vkGetShaderInfoAMD vkGetShaderInfoAMD; -#endif /* defined(VK_AMD_shader_info) */ -#if defined(VK_ANDROID_external_memory_android_hardware_buffer) -extern PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; -extern PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; -#endif /* defined(VK_ANDROID_external_memory_android_hardware_buffer) */ -#if defined(VK_EXT_acquire_xlib_display) -extern PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; -extern PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; -#endif /* defined(VK_EXT_acquire_xlib_display) */ -#if defined(VK_EXT_buffer_device_address) -extern PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT; -#endif /* defined(VK_EXT_buffer_device_address) */ -#if defined(VK_EXT_calibrated_timestamps) -extern PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT; -extern PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; -#endif /* defined(VK_EXT_calibrated_timestamps) */ -#if defined(VK_EXT_conditional_rendering) -extern PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT; -extern PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT; -#endif /* defined(VK_EXT_conditional_rendering) */ -#if defined(VK_EXT_debug_marker) -extern PFN_vkCmdDebugMarkerBeginEXT vkCmdDebugMarkerBeginEXT; -extern PFN_vkCmdDebugMarkerEndEXT vkCmdDebugMarkerEndEXT; -extern PFN_vkCmdDebugMarkerInsertEXT vkCmdDebugMarkerInsertEXT; -extern PFN_vkDebugMarkerSetObjectNameEXT vkDebugMarkerSetObjectNameEXT; -extern PFN_vkDebugMarkerSetObjectTagEXT vkDebugMarkerSetObjectTagEXT; -#endif /* defined(VK_EXT_debug_marker) */ -#if defined(VK_EXT_debug_report) -extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; -extern PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; -extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; -#endif /* defined(VK_EXT_debug_report) */ -#if defined(VK_EXT_debug_utils) -extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; -extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; -extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; -extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; -extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; -extern PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT; -extern PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT; -extern PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT; -extern PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; -extern PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; -extern PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT; -#endif /* defined(VK_EXT_debug_utils) */ -#if defined(VK_EXT_direct_mode_display) -extern PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; -#endif /* defined(VK_EXT_direct_mode_display) */ -#if defined(VK_EXT_discard_rectangles) -extern PFN_vkCmdSetDiscardRectangleEXT vkCmdSetDiscardRectangleEXT; -#endif /* defined(VK_EXT_discard_rectangles) */ -#if defined(VK_EXT_display_control) -extern PFN_vkDisplayPowerControlEXT vkDisplayPowerControlEXT; -extern PFN_vkGetSwapchainCounterEXT vkGetSwapchainCounterEXT; -extern PFN_vkRegisterDeviceEventEXT vkRegisterDeviceEventEXT; -extern PFN_vkRegisterDisplayEventEXT vkRegisterDisplayEventEXT; -#endif /* defined(VK_EXT_display_control) */ -#if defined(VK_EXT_display_surface_counter) -extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT; -#endif /* defined(VK_EXT_display_surface_counter) */ -#if defined(VK_EXT_external_memory_host) -extern PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT; -#endif /* defined(VK_EXT_external_memory_host) */ -#if defined(VK_EXT_hdr_metadata) -extern PFN_vkSetHdrMetadataEXT vkSetHdrMetadataEXT; -#endif /* defined(VK_EXT_hdr_metadata) */ -#if defined(VK_EXT_image_drm_format_modifier) -extern PFN_vkGetImageDrmFormatModifierPropertiesEXT vkGetImageDrmFormatModifierPropertiesEXT; -#endif /* defined(VK_EXT_image_drm_format_modifier) */ -#if defined(VK_EXT_metal_surface) -extern PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; -#endif /* defined(VK_EXT_metal_surface) */ -#if defined(VK_EXT_sample_locations) -extern PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT; -extern PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT vkGetPhysicalDeviceMultisamplePropertiesEXT; -#endif /* defined(VK_EXT_sample_locations) */ -#if defined(VK_EXT_transform_feedback) -extern PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT; -extern PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; -extern PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; -extern PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT; -extern PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT; -extern PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; -#endif /* defined(VK_EXT_transform_feedback) */ -#if defined(VK_EXT_validation_cache) -extern PFN_vkCreateValidationCacheEXT vkCreateValidationCacheEXT; -extern PFN_vkDestroyValidationCacheEXT vkDestroyValidationCacheEXT; -extern PFN_vkGetValidationCacheDataEXT vkGetValidationCacheDataEXT; -extern PFN_vkMergeValidationCachesEXT vkMergeValidationCachesEXT; -#endif /* defined(VK_EXT_validation_cache) */ -#if defined(VK_FUCHSIA_imagepipe_surface) -extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; -#endif /* defined(VK_FUCHSIA_imagepipe_surface) */ -#if defined(VK_GOOGLE_display_timing) -extern PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; -extern PFN_vkGetRefreshCycleDurationGOOGLE vkGetRefreshCycleDurationGOOGLE; -#endif /* defined(VK_GOOGLE_display_timing) */ -#if defined(VK_KHR_android_surface) -extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; -#endif /* defined(VK_KHR_android_surface) */ -#if defined(VK_KHR_bind_memory2) -extern PFN_vkBindBufferMemory2KHR vkBindBufferMemory2KHR; -extern PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR; -#endif /* defined(VK_KHR_bind_memory2) */ -#if defined(VK_KHR_create_renderpass2) -extern PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR; -extern PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR; -extern PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR; -extern PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR; -#endif /* defined(VK_KHR_create_renderpass2) */ -#if defined(VK_KHR_descriptor_update_template) -extern PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; -extern PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; -extern PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; -#endif /* defined(VK_KHR_descriptor_update_template) */ -#if defined(VK_KHR_device_group) -extern PFN_vkCmdDispatchBaseKHR vkCmdDispatchBaseKHR; -extern PFN_vkCmdSetDeviceMaskKHR vkCmdSetDeviceMaskKHR; -extern PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR vkGetDeviceGroupPeerMemoryFeaturesKHR; -#endif /* defined(VK_KHR_device_group) */ -#if defined(VK_KHR_device_group_creation) -extern PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR; -#endif /* defined(VK_KHR_device_group_creation) */ -#if defined(VK_KHR_display) -extern PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; -extern PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; -extern PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; -extern PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; -extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; -extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; -extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; -#endif /* defined(VK_KHR_display) */ -#if defined(VK_KHR_display_swapchain) -extern PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; -#endif /* defined(VK_KHR_display_swapchain) */ -#if defined(VK_KHR_draw_indirect_count) -extern PFN_vkCmdDrawIndexedIndirectCountKHR vkCmdDrawIndexedIndirectCountKHR; -extern PFN_vkCmdDrawIndirectCountKHR vkCmdDrawIndirectCountKHR; -#endif /* defined(VK_KHR_draw_indirect_count) */ -#if defined(VK_KHR_external_fence_capabilities) -extern PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR vkGetPhysicalDeviceExternalFencePropertiesKHR; -#endif /* defined(VK_KHR_external_fence_capabilities) */ -#if defined(VK_KHR_external_fence_fd) -extern PFN_vkGetFenceFdKHR vkGetFenceFdKHR; -extern PFN_vkImportFenceFdKHR vkImportFenceFdKHR; -#endif /* defined(VK_KHR_external_fence_fd) */ -#if defined(VK_KHR_external_fence_win32) -extern PFN_vkGetFenceWin32HandleKHR vkGetFenceWin32HandleKHR; -extern PFN_vkImportFenceWin32HandleKHR vkImportFenceWin32HandleKHR; -#endif /* defined(VK_KHR_external_fence_win32) */ -#if defined(VK_KHR_external_memory_capabilities) -extern PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR vkGetPhysicalDeviceExternalBufferPropertiesKHR; -#endif /* defined(VK_KHR_external_memory_capabilities) */ -#if defined(VK_KHR_external_memory_fd) -extern PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; -extern PFN_vkGetMemoryFdPropertiesKHR vkGetMemoryFdPropertiesKHR; -#endif /* defined(VK_KHR_external_memory_fd) */ -#if defined(VK_KHR_external_memory_win32) -extern PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; -extern PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR; -#endif /* defined(VK_KHR_external_memory_win32) */ -#if defined(VK_KHR_external_semaphore_capabilities) -extern PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR vkGetPhysicalDeviceExternalSemaphorePropertiesKHR; -#endif /* defined(VK_KHR_external_semaphore_capabilities) */ -#if defined(VK_KHR_external_semaphore_fd) -extern PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; -extern PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; -#endif /* defined(VK_KHR_external_semaphore_fd) */ -#if defined(VK_KHR_external_semaphore_win32) -extern PFN_vkGetSemaphoreWin32HandleKHR vkGetSemaphoreWin32HandleKHR; -extern PFN_vkImportSemaphoreWin32HandleKHR vkImportSemaphoreWin32HandleKHR; -#endif /* defined(VK_KHR_external_semaphore_win32) */ -#if defined(VK_KHR_get_display_properties2) -extern PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR; -extern PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR; -extern PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR; -extern PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR; -#endif /* defined(VK_KHR_get_display_properties2) */ -#if defined(VK_KHR_get_memory_requirements2) -extern PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR; -extern PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR; -extern PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR; -#endif /* defined(VK_KHR_get_memory_requirements2) */ -#if defined(VK_KHR_get_physical_device_properties2) -extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; -extern PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR; -extern PFN_vkGetPhysicalDeviceImageFormatProperties2KHR vkGetPhysicalDeviceImageFormatProperties2KHR; -extern PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR; -extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; -extern PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR; -extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR vkGetPhysicalDeviceSparseImageFormatProperties2KHR; -#endif /* defined(VK_KHR_get_physical_device_properties2) */ -#if defined(VK_KHR_get_surface_capabilities2) -extern PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR; -extern PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR; -#endif /* defined(VK_KHR_get_surface_capabilities2) */ -#if defined(VK_KHR_maintenance1) -extern PFN_vkTrimCommandPoolKHR vkTrimCommandPoolKHR; -#endif /* defined(VK_KHR_maintenance1) */ -#if defined(VK_KHR_maintenance3) -extern PFN_vkGetDescriptorSetLayoutSupportKHR vkGetDescriptorSetLayoutSupportKHR; -#endif /* defined(VK_KHR_maintenance3) */ -#if defined(VK_KHR_push_descriptor) -extern PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR; -#endif /* defined(VK_KHR_push_descriptor) */ -#if defined(VK_KHR_sampler_ycbcr_conversion) -extern PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR; -extern PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR; -#endif /* defined(VK_KHR_sampler_ycbcr_conversion) */ -#if defined(VK_KHR_shared_presentable_image) -extern PFN_vkGetSwapchainStatusKHR vkGetSwapchainStatusKHR; -#endif /* defined(VK_KHR_shared_presentable_image) */ -#if defined(VK_KHR_surface) -extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; -extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; -extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; -extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; -extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; -#endif /* defined(VK_KHR_surface) */ -#if defined(VK_KHR_swapchain) -extern PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; -extern PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; -extern PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; -extern PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; -extern PFN_vkQueuePresentKHR vkQueuePresentKHR; -#endif /* defined(VK_KHR_swapchain) */ -#if defined(VK_KHR_wayland_surface) -extern PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; -extern PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; -#endif /* defined(VK_KHR_wayland_surface) */ -#if defined(VK_KHR_win32_surface) -extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; -extern PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; -#endif /* defined(VK_KHR_win32_surface) */ -#if defined(VK_KHR_xcb_surface) -extern PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; -extern PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; -#endif /* defined(VK_KHR_xcb_surface) */ -#if defined(VK_KHR_xlib_surface) -extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; -extern PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; -#endif /* defined(VK_KHR_xlib_surface) */ -#if defined(VK_MVK_ios_surface) -extern PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK; -#endif /* defined(VK_MVK_ios_surface) */ -#if defined(VK_MVK_macos_surface) -extern PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; -#endif /* defined(VK_MVK_macos_surface) */ -#if defined(VK_NN_vi_surface) -extern PFN_vkCreateViSurfaceNN vkCreateViSurfaceNN; -#endif /* defined(VK_NN_vi_surface) */ -#if defined(VK_NVX_device_generated_commands) -extern PFN_vkCmdProcessCommandsNVX vkCmdProcessCommandsNVX; -extern PFN_vkCmdReserveSpaceForCommandsNVX vkCmdReserveSpaceForCommandsNVX; -extern PFN_vkCreateIndirectCommandsLayoutNVX vkCreateIndirectCommandsLayoutNVX; -extern PFN_vkCreateObjectTableNVX vkCreateObjectTableNVX; -extern PFN_vkDestroyIndirectCommandsLayoutNVX vkDestroyIndirectCommandsLayoutNVX; -extern PFN_vkDestroyObjectTableNVX vkDestroyObjectTableNVX; -extern PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX; -extern PFN_vkRegisterObjectsNVX vkRegisterObjectsNVX; -extern PFN_vkUnregisterObjectsNVX vkUnregisterObjectsNVX; -#endif /* defined(VK_NVX_device_generated_commands) */ -#if defined(VK_NVX_image_view_handle) -extern PFN_vkGetImageViewHandleNVX vkGetImageViewHandleNVX; -#endif /* defined(VK_NVX_image_view_handle) */ -#if defined(VK_NV_clip_space_w_scaling) -extern PFN_vkCmdSetViewportWScalingNV vkCmdSetViewportWScalingNV; -#endif /* defined(VK_NV_clip_space_w_scaling) */ -#if defined(VK_NV_cooperative_matrix) -extern PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; -#endif /* defined(VK_NV_cooperative_matrix) */ -#if defined(VK_NV_device_diagnostic_checkpoints) -extern PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; -extern PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; -#endif /* defined(VK_NV_device_diagnostic_checkpoints) */ -#if defined(VK_NV_external_memory_capabilities) -extern PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV vkGetPhysicalDeviceExternalImageFormatPropertiesNV; -#endif /* defined(VK_NV_external_memory_capabilities) */ -#if defined(VK_NV_external_memory_win32) -extern PFN_vkGetMemoryWin32HandleNV vkGetMemoryWin32HandleNV; -#endif /* defined(VK_NV_external_memory_win32) */ -#if defined(VK_NV_mesh_shader) -extern PFN_vkCmdDrawMeshTasksIndirectCountNV vkCmdDrawMeshTasksIndirectCountNV; -extern PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV; -extern PFN_vkCmdDrawMeshTasksNV vkCmdDrawMeshTasksNV; -#endif /* defined(VK_NV_mesh_shader) */ -#if defined(VK_NV_ray_tracing) -extern PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV; -extern PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV; -extern PFN_vkCmdCopyAccelerationStructureNV vkCmdCopyAccelerationStructureNV; -extern PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV; -extern PFN_vkCmdWriteAccelerationStructuresPropertiesNV vkCmdWriteAccelerationStructuresPropertiesNV; -extern PFN_vkCompileDeferredNV vkCompileDeferredNV; -extern PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV; -extern PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV; -extern PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV; -extern PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV; -extern PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV; -extern PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV; -#endif /* defined(VK_NV_ray_tracing) */ -#if defined(VK_NV_scissor_exclusive) -extern PFN_vkCmdSetExclusiveScissorNV vkCmdSetExclusiveScissorNV; -#endif /* defined(VK_NV_scissor_exclusive) */ -#if defined(VK_NV_shading_rate_image) -extern PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; -extern PFN_vkCmdSetCoarseSampleOrderNV vkCmdSetCoarseSampleOrderNV; -extern PFN_vkCmdSetViewportShadingRatePaletteNV vkCmdSetViewportShadingRatePaletteNV; -#endif /* defined(VK_NV_shading_rate_image) */ -#if (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) -extern PFN_vkCmdPushDescriptorSetWithTemplateKHR vkCmdPushDescriptorSetWithTemplateKHR; -#endif /* (defined(VK_KHR_descriptor_update_template) && defined(VK_KHR_push_descriptor)) || (defined(VK_KHR_push_descriptor) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) -extern PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR; -extern PFN_vkGetDeviceGroupSurfacePresentModesKHR vkGetDeviceGroupSurfacePresentModesKHR; -extern PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR; -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ -#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) -extern PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR; -#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */ -/* VOLK_GENERATE_PROTOTYPES_H */ - -#ifdef __cplusplus -} -#endif - -#endif - -/** - * Copyright (c) 2018-2019 Arseny Kapoulkine - * - * 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/src/rendering/vulkan/thirdparty/vulkan/vk_icd.h b/src/rendering/vulkan/thirdparty/vulkan/vk_icd.h deleted file mode 100644 index a2d960a6324..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vk_icd.h +++ /dev/null @@ -1,175 +0,0 @@ -// -// File: vk_icd.h -// -/* - * Copyright (c) 2015-2016 The Khronos Group Inc. - * Copyright (c) 2015-2016 Valve Corporation - * Copyright (c) 2015-2016 LunarG, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef VKICD_H -#define VKICD_H - -#include "vulkan.h" -#include - -// Loader-ICD version negotiation API. Versions add the following features: -// Version 0 - Initial. Doesn't support vk_icdGetInstanceProcAddr -// or vk_icdNegotiateLoaderICDInterfaceVersion. -// Version 1 - Add support for vk_icdGetInstanceProcAddr. -// Version 2 - Add Loader/ICD Interface version negotiation -// via vk_icdNegotiateLoaderICDInterfaceVersion. -// Version 3 - Add ICD creation/destruction of KHR_surface objects. -// Version 4 - Add unknown physical device extension qyering via -// vk_icdGetPhysicalDeviceProcAddr. -// Version 5 - Tells ICDs that the loader is now paying attention to the -// application version of Vulkan passed into the ApplicationInfo -// structure during vkCreateInstance. This will tell the ICD -// that if the loader is older, it should automatically fail a -// call for any API version > 1.0. Otherwise, the loader will -// manually determine if it can support the expected version. -#define CURRENT_LOADER_ICD_INTERFACE_VERSION 5 -#define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0 -#define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4 -typedef VkResult(VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion); - -// This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this -// file directly, it won't be found. -#ifndef PFN_GetPhysicalDeviceProcAddr -typedef PFN_vkVoidFunction(VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char *pName); -#endif - -/* - * The ICD must reserve space for a pointer for the loader's dispatch - * table, at the start of . - * The ICD must initialize this variable using the SET_LOADER_MAGIC_VALUE macro. - */ - -#define ICD_LOADER_MAGIC 0x01CDC0DE - -typedef union { - uintptr_t loaderMagic; - void *loaderData; -} VK_LOADER_DATA; - -static inline void set_loader_magic_value(void *pNewObject) { - VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject; - loader_info->loaderMagic = ICD_LOADER_MAGIC; -} - -static inline bool valid_loader_magic_value(void *pNewObject) { - const VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject; - return (loader_info->loaderMagic & 0xffffffff) == ICD_LOADER_MAGIC; -} - -/* - * Windows and Linux ICDs will treat VkSurfaceKHR as a pointer to a struct that - * contains the platform-specific connection and surface information. - */ -typedef enum { - VK_ICD_WSI_PLATFORM_MIR, - VK_ICD_WSI_PLATFORM_WAYLAND, - VK_ICD_WSI_PLATFORM_WIN32, - VK_ICD_WSI_PLATFORM_XCB, - VK_ICD_WSI_PLATFORM_XLIB, - VK_ICD_WSI_PLATFORM_ANDROID, - VK_ICD_WSI_PLATFORM_MACOS, - VK_ICD_WSI_PLATFORM_IOS, - VK_ICD_WSI_PLATFORM_DISPLAY, - VK_ICD_WSI_PLATFORM_HEADLESS -} VkIcdWsiPlatform; - -typedef struct { - VkIcdWsiPlatform platform; -} VkIcdSurfaceBase; - -#ifdef VK_USE_PLATFORM_MIR_KHR -typedef struct { - VkIcdSurfaceBase base; - MirConnection *connection; - MirSurface *mirSurface; -} VkIcdSurfaceMir; -#endif // VK_USE_PLATFORM_MIR_KHR - -#ifdef VK_USE_PLATFORM_WAYLAND_KHR -typedef struct { - VkIcdSurfaceBase base; - struct wl_display *display; - struct wl_surface *surface; -} VkIcdSurfaceWayland; -#endif // VK_USE_PLATFORM_WAYLAND_KHR - -#ifdef VK_USE_PLATFORM_WIN32_KHR -typedef struct { - VkIcdSurfaceBase base; - HINSTANCE hinstance; - HWND hwnd; -} VkIcdSurfaceWin32; -#endif // VK_USE_PLATFORM_WIN32_KHR - -#ifdef VK_USE_PLATFORM_XCB_KHR -typedef struct { - VkIcdSurfaceBase base; - xcb_connection_t *connection; - xcb_window_t window; -} VkIcdSurfaceXcb; -#endif // VK_USE_PLATFORM_XCB_KHR - -#ifdef VK_USE_PLATFORM_XLIB_KHR -typedef struct { - VkIcdSurfaceBase base; - Display *dpy; - Window window; -} VkIcdSurfaceXlib; -#endif // VK_USE_PLATFORM_XLIB_KHR - -#ifdef VK_USE_PLATFORM_ANDROID_KHR -typedef struct { - VkIcdSurfaceBase base; - struct ANativeWindow *window; -} VkIcdSurfaceAndroid; -#endif // VK_USE_PLATFORM_ANDROID_KHR - -#ifdef VK_USE_PLATFORM_MACOS_MVK -typedef struct { - VkIcdSurfaceBase base; - const void *pView; -} VkIcdSurfaceMacOS; -#endif // VK_USE_PLATFORM_MACOS_MVK - -#ifdef VK_USE_PLATFORM_IOS_MVK -typedef struct { - VkIcdSurfaceBase base; - const void *pView; -} VkIcdSurfaceIOS; -#endif // VK_USE_PLATFORM_IOS_MVK - -typedef struct { - VkIcdSurfaceBase base; - VkDisplayModeKHR displayMode; - uint32_t planeIndex; - uint32_t planeStackIndex; - VkSurfaceTransformFlagBitsKHR transform; - float globalAlpha; - VkDisplayPlaneAlphaFlagBitsKHR alphaMode; - VkExtent2D imageExtent; -} VkIcdSurfaceDisplay; - -typedef struct { - VkIcdSurfaceBase base; -} VkIcdSurfaceHeadless; - -#endif // VKICD_H diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan.h deleted file mode 100644 index 5f853f9fc8e..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef VULKAN_H_ -#define VULKAN_H_ 1 - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include "vk_platform.h" -#include "vulkan_core.h" - -#ifdef VK_USE_PLATFORM_ANDROID_KHR -#include "vulkan_android.h" -#endif - -#ifdef VK_USE_PLATFORM_FUCHSIA -#include -#include "vulkan_fuchsia.h" -#endif - -#ifdef VK_USE_PLATFORM_IOS_MVK -#include "vulkan_ios.h" -#endif - - -#ifdef VK_USE_PLATFORM_MACOS_MVK -#include "vulkan_macos.h" -#endif - -#ifdef VK_USE_PLATFORM_METAL_EXT -#include "vulkan_metal.h" -#endif - -#ifdef VK_USE_PLATFORM_VI_NN -#include "vulkan_vi.h" -#endif - - -#ifdef VK_USE_PLATFORM_WAYLAND_KHR -#include -#include "vulkan_wayland.h" -#endif - - -#ifdef VK_USE_PLATFORM_WIN32_KHR -#include -#include "vulkan_win32.h" -#endif - - -#ifdef VK_USE_PLATFORM_XCB_KHR -#include -#include "vulkan_xcb.h" -#endif - - -#ifdef VK_USE_PLATFORM_XLIB_KHR -#include -#include "vulkan_xlib.h" -#endif - - -#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT -#include -#include -#include "vulkan_xlib_xrandr.h" -#endif - - -#ifdef VK_USE_PLATFORM_GGP -#include -#include "vulkan_ggp.h" -#endif - -#endif // VULKAN_H_ diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_android.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_android.h deleted file mode 100644 index 1861802411e..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_android.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef VULKAN_ANDROID_H_ -#define VULKAN_ANDROID_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_KHR_android_surface 1 -struct ANativeWindow; -#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 -#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" -typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; -typedef struct VkAndroidSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkAndroidSurfaceCreateFlagsKHR flags; - struct ANativeWindow* window; -} VkAndroidSurfaceCreateInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( - VkInstance instance, - const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - - -#define VK_ANDROID_external_memory_android_hardware_buffer 1 -struct AHardwareBuffer; -#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3 -#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" -typedef struct VkAndroidHardwareBufferUsageANDROID { - VkStructureType sType; - void* pNext; - uint64_t androidHardwareBufferUsage; -} VkAndroidHardwareBufferUsageANDROID; - -typedef struct VkAndroidHardwareBufferPropertiesANDROID { - VkStructureType sType; - void* pNext; - VkDeviceSize allocationSize; - uint32_t memoryTypeBits; -} VkAndroidHardwareBufferPropertiesANDROID; - -typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { - VkStructureType sType; - void* pNext; - VkFormat format; - uint64_t externalFormat; - VkFormatFeatureFlags formatFeatures; - VkComponentMapping samplerYcbcrConversionComponents; - VkSamplerYcbcrModelConversion suggestedYcbcrModel; - VkSamplerYcbcrRange suggestedYcbcrRange; - VkChromaLocation suggestedXChromaOffset; - VkChromaLocation suggestedYChromaOffset; -} VkAndroidHardwareBufferFormatPropertiesANDROID; - -typedef struct VkImportAndroidHardwareBufferInfoANDROID { - VkStructureType sType; - const void* pNext; - struct AHardwareBuffer* buffer; -} VkImportAndroidHardwareBufferInfoANDROID; - -typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID { - VkStructureType sType; - const void* pNext; - VkDeviceMemory memory; -} VkMemoryGetAndroidHardwareBufferInfoANDROID; - -typedef struct VkExternalFormatANDROID { - VkStructureType sType; - void* pNext; - uint64_t externalFormat; -} VkExternalFormatANDROID; - -typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID( - VkDevice device, - const struct AHardwareBuffer* buffer, - VkAndroidHardwareBufferPropertiesANDROID* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID( - VkDevice device, - const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, - struct AHardwareBuffer** pBuffer); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_core.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_core.h deleted file mode 100644 index 544f24fb695..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_core.h +++ /dev/null @@ -1,9563 +0,0 @@ -#ifndef VULKAN_CORE_H_ -#define VULKAN_CORE_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_VERSION_1_0 1 -#include "vk_platform.h" -#define VK_MAKE_VERSION(major, minor, patch) \ - (((major) << 22) | ((minor) << 12) | (patch)) - -// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. -//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0 - -// Vulkan 1.0 version number -#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)// Patch version should always be set to 0 - -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) -#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) -// Version of this file -#define VK_HEADER_VERSION 114 - - -#define VK_NULL_HANDLE 0 - - -#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; - - -#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) - #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; -#else - #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; -#endif -#endif - -typedef uint32_t VkFlags; -typedef uint32_t VkBool32; -typedef uint64_t VkDeviceSize; -typedef uint32_t VkSampleMask; -VK_DEFINE_HANDLE(VkInstance) -VK_DEFINE_HANDLE(VkPhysicalDevice) -VK_DEFINE_HANDLE(VkDevice) -VK_DEFINE_HANDLE(VkQueue) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) -VK_DEFINE_HANDLE(VkCommandBuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) -#define VK_LOD_CLAMP_NONE 1000.0f -#define VK_REMAINING_MIP_LEVELS (~0U) -#define VK_REMAINING_ARRAY_LAYERS (~0U) -#define VK_WHOLE_SIZE (~0ULL) -#define VK_ATTACHMENT_UNUSED (~0U) -#define VK_TRUE 1 -#define VK_FALSE 0 -#define VK_QUEUE_FAMILY_IGNORED (~0U) -#define VK_SUBPASS_EXTERNAL (~0U) -#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 -#define VK_UUID_SIZE 16 -#define VK_MAX_MEMORY_TYPES 32 -#define VK_MAX_MEMORY_HEAPS 16 -#define VK_MAX_EXTENSION_NAME_SIZE 256 -#define VK_MAX_DESCRIPTION_SIZE 256 - -typedef enum VkPipelineCacheHeaderVersion { - VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, - VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, - VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, - VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1), - VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF -} VkPipelineCacheHeaderVersion; - -typedef enum VkResult { - VK_SUCCESS = 0, - VK_NOT_READY = 1, - VK_TIMEOUT = 2, - VK_EVENT_SET = 3, - VK_EVENT_RESET = 4, - VK_INCOMPLETE = 5, - VK_ERROR_OUT_OF_HOST_MEMORY = -1, - VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, - VK_ERROR_INITIALIZATION_FAILED = -3, - VK_ERROR_DEVICE_LOST = -4, - VK_ERROR_MEMORY_MAP_FAILED = -5, - VK_ERROR_LAYER_NOT_PRESENT = -6, - VK_ERROR_EXTENSION_NOT_PRESENT = -7, - VK_ERROR_FEATURE_NOT_PRESENT = -8, - VK_ERROR_INCOMPATIBLE_DRIVER = -9, - VK_ERROR_TOO_MANY_OBJECTS = -10, - VK_ERROR_FORMAT_NOT_SUPPORTED = -11, - VK_ERROR_FRAGMENTED_POOL = -12, - VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000, - VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, - VK_ERROR_SURFACE_LOST_KHR = -1000000000, - VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, - VK_SUBOPTIMAL_KHR = 1000001003, - VK_ERROR_OUT_OF_DATE_KHR = -1000001004, - VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, - VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, - VK_ERROR_INVALID_SHADER_NV = -1000012000, - VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, - VK_ERROR_FRAGMENTATION_EXT = -1000161000, - VK_ERROR_NOT_PERMITTED_EXT = -1000174001, - VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = -1000244000, - VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, - VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, - VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, - VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL, - VK_RESULT_END_RANGE = VK_INCOMPLETE, - VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1), - VK_RESULT_MAX_ENUM = 0x7FFFFFFF -} VkResult; - -typedef enum VkStructureType { - VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, - VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, - VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, - VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, - VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, - VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, - VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, - VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, - VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, - VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, - VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, - VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, - VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, - VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, - VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, - VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, - VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, - VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, - VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000, - VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, - VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, - VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, - VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, - VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, - VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, - VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, - VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, - VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, - VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, - VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, - VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, - VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, - VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, - VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, - VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, - VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, - VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, - VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, - VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, - VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, - VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, - VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, - VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, - VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, - VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000, - VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001, - VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002, - VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, - VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, - VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, - VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, - VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, - VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, - VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = 1000082000, - VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, - VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000, - VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001, - VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002, - VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000, - VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, - VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001, - VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002, - VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, - VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, - VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, - VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = 1000108000, - VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = 1000108001, - VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = 1000108002, - VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = 1000108003, - VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = 1000109000, - VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = 1000109001, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = 1000109002, - VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = 1000109003, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = 1000109004, - VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = 1000109005, - VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = 1000109006, - VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, - VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, - VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, - VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, - VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000, - VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, - VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, - VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR = 1000121000, - VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001, - VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002, - VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR = 1000121003, - VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004, - VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000, - VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, - VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, - VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, - VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002, - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, - VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000, - VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001, - VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002, - VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, - VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, - VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000, - VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003, - VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, - VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, - VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, - VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, - VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, - VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, - VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, - VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, - VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, - VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, - VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = 1000161001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = 1000161002, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = 1000161003, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = 1000161004, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, - VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, - VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, - VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, - VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, - VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, - VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, - VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = 1000177000, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, - VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000, - VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, - VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, - VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, - VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000192000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = 1000197000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = 1000199000, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = 1000199001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = 1000203000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, - VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS2_FEATURES_INTEL = 1000209000, - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL = 1000210000, - VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL = 1000210001, - VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL = 1000210002, - VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL = 1000210003, - VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL = 1000210004, - VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL = 1000210005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, - VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, - VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, - VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, - VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, - VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = 1000221000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, - VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, - VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR = 1000239000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, - VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = 1000244001, - VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, - VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = 1000246000, - VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, - VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV = 1000250000, - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV = 1000250001, - VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV = 1000250002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = 1000253000, - VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, - VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, - VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = 1000261000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = 1000276000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = 1000281001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, - VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, - VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, - VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, - VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, - VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO, - VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, - VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, - VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, - VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1), - VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkStructureType; - -typedef enum VkSystemAllocationScope { - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, - VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, - VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, - VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, - VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, - VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, - VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1), - VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF -} VkSystemAllocationScope; - -typedef enum VkInternalAllocationType { - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, - VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, - VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, - VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1), - VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkInternalAllocationType; - -typedef enum VkFormat { - VK_FORMAT_UNDEFINED = 0, - VK_FORMAT_R4G4_UNORM_PACK8 = 1, - VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, - VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, - VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, - VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, - VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, - VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, - VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, - VK_FORMAT_R8_UNORM = 9, - VK_FORMAT_R8_SNORM = 10, - VK_FORMAT_R8_USCALED = 11, - VK_FORMAT_R8_SSCALED = 12, - VK_FORMAT_R8_UINT = 13, - VK_FORMAT_R8_SINT = 14, - VK_FORMAT_R8_SRGB = 15, - VK_FORMAT_R8G8_UNORM = 16, - VK_FORMAT_R8G8_SNORM = 17, - VK_FORMAT_R8G8_USCALED = 18, - VK_FORMAT_R8G8_SSCALED = 19, - VK_FORMAT_R8G8_UINT = 20, - VK_FORMAT_R8G8_SINT = 21, - VK_FORMAT_R8G8_SRGB = 22, - VK_FORMAT_R8G8B8_UNORM = 23, - VK_FORMAT_R8G8B8_SNORM = 24, - VK_FORMAT_R8G8B8_USCALED = 25, - VK_FORMAT_R8G8B8_SSCALED = 26, - VK_FORMAT_R8G8B8_UINT = 27, - VK_FORMAT_R8G8B8_SINT = 28, - VK_FORMAT_R8G8B8_SRGB = 29, - VK_FORMAT_B8G8R8_UNORM = 30, - VK_FORMAT_B8G8R8_SNORM = 31, - VK_FORMAT_B8G8R8_USCALED = 32, - VK_FORMAT_B8G8R8_SSCALED = 33, - VK_FORMAT_B8G8R8_UINT = 34, - VK_FORMAT_B8G8R8_SINT = 35, - VK_FORMAT_B8G8R8_SRGB = 36, - VK_FORMAT_R8G8B8A8_UNORM = 37, - VK_FORMAT_R8G8B8A8_SNORM = 38, - VK_FORMAT_R8G8B8A8_USCALED = 39, - VK_FORMAT_R8G8B8A8_SSCALED = 40, - VK_FORMAT_R8G8B8A8_UINT = 41, - VK_FORMAT_R8G8B8A8_SINT = 42, - VK_FORMAT_R8G8B8A8_SRGB = 43, - VK_FORMAT_B8G8R8A8_UNORM = 44, - VK_FORMAT_B8G8R8A8_SNORM = 45, - VK_FORMAT_B8G8R8A8_USCALED = 46, - VK_FORMAT_B8G8R8A8_SSCALED = 47, - VK_FORMAT_B8G8R8A8_UINT = 48, - VK_FORMAT_B8G8R8A8_SINT = 49, - VK_FORMAT_B8G8R8A8_SRGB = 50, - VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, - VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, - VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, - VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, - VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, - VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, - VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, - VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, - VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, - VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, - VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, - VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, - VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, - VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, - VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, - VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, - VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, - VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, - VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, - VK_FORMAT_R16_UNORM = 70, - VK_FORMAT_R16_SNORM = 71, - VK_FORMAT_R16_USCALED = 72, - VK_FORMAT_R16_SSCALED = 73, - VK_FORMAT_R16_UINT = 74, - VK_FORMAT_R16_SINT = 75, - VK_FORMAT_R16_SFLOAT = 76, - VK_FORMAT_R16G16_UNORM = 77, - VK_FORMAT_R16G16_SNORM = 78, - VK_FORMAT_R16G16_USCALED = 79, - VK_FORMAT_R16G16_SSCALED = 80, - VK_FORMAT_R16G16_UINT = 81, - VK_FORMAT_R16G16_SINT = 82, - VK_FORMAT_R16G16_SFLOAT = 83, - VK_FORMAT_R16G16B16_UNORM = 84, - VK_FORMAT_R16G16B16_SNORM = 85, - VK_FORMAT_R16G16B16_USCALED = 86, - VK_FORMAT_R16G16B16_SSCALED = 87, - VK_FORMAT_R16G16B16_UINT = 88, - VK_FORMAT_R16G16B16_SINT = 89, - VK_FORMAT_R16G16B16_SFLOAT = 90, - VK_FORMAT_R16G16B16A16_UNORM = 91, - VK_FORMAT_R16G16B16A16_SNORM = 92, - VK_FORMAT_R16G16B16A16_USCALED = 93, - VK_FORMAT_R16G16B16A16_SSCALED = 94, - VK_FORMAT_R16G16B16A16_UINT = 95, - VK_FORMAT_R16G16B16A16_SINT = 96, - VK_FORMAT_R16G16B16A16_SFLOAT = 97, - VK_FORMAT_R32_UINT = 98, - VK_FORMAT_R32_SINT = 99, - VK_FORMAT_R32_SFLOAT = 100, - VK_FORMAT_R32G32_UINT = 101, - VK_FORMAT_R32G32_SINT = 102, - VK_FORMAT_R32G32_SFLOAT = 103, - VK_FORMAT_R32G32B32_UINT = 104, - VK_FORMAT_R32G32B32_SINT = 105, - VK_FORMAT_R32G32B32_SFLOAT = 106, - VK_FORMAT_R32G32B32A32_UINT = 107, - VK_FORMAT_R32G32B32A32_SINT = 108, - VK_FORMAT_R32G32B32A32_SFLOAT = 109, - VK_FORMAT_R64_UINT = 110, - VK_FORMAT_R64_SINT = 111, - VK_FORMAT_R64_SFLOAT = 112, - VK_FORMAT_R64G64_UINT = 113, - VK_FORMAT_R64G64_SINT = 114, - VK_FORMAT_R64G64_SFLOAT = 115, - VK_FORMAT_R64G64B64_UINT = 116, - VK_FORMAT_R64G64B64_SINT = 117, - VK_FORMAT_R64G64B64_SFLOAT = 118, - VK_FORMAT_R64G64B64A64_UINT = 119, - VK_FORMAT_R64G64B64A64_SINT = 120, - VK_FORMAT_R64G64B64A64_SFLOAT = 121, - VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, - VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, - VK_FORMAT_D16_UNORM = 124, - VK_FORMAT_X8_D24_UNORM_PACK32 = 125, - VK_FORMAT_D32_SFLOAT = 126, - VK_FORMAT_S8_UINT = 127, - VK_FORMAT_D16_UNORM_S8_UINT = 128, - VK_FORMAT_D24_UNORM_S8_UINT = 129, - VK_FORMAT_D32_SFLOAT_S8_UINT = 130, - VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, - VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, - VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, - VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, - VK_FORMAT_BC2_UNORM_BLOCK = 135, - VK_FORMAT_BC2_SRGB_BLOCK = 136, - VK_FORMAT_BC3_UNORM_BLOCK = 137, - VK_FORMAT_BC3_SRGB_BLOCK = 138, - VK_FORMAT_BC4_UNORM_BLOCK = 139, - VK_FORMAT_BC4_SNORM_BLOCK = 140, - VK_FORMAT_BC5_UNORM_BLOCK = 141, - VK_FORMAT_BC5_SNORM_BLOCK = 142, - VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, - VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, - VK_FORMAT_BC7_UNORM_BLOCK = 145, - VK_FORMAT_BC7_SRGB_BLOCK = 146, - VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, - VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, - VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, - VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, - VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, - VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, - VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, - VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, - VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, - VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, - VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, - VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, - VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, - VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, - VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, - VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, - VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, - VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, - VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, - VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, - VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, - VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, - VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, - VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, - VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, - VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, - VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, - VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, - VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, - VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, - VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, - VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, - VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, - VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, - VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, - VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, - VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, - VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, - VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, - VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, - VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, - VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, - VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, - VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, - VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, - VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, - VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, - VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, - VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, - VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, - VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, - VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, - VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, - VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, - VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, - VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, - VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, - VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, - VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, - VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, - VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, - VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, - VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, - VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, - VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, - VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, - VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, - VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, - VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, - VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, - VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, - VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16, - VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16, - VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, - VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, - VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, - VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16, - VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16, - VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, - VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, - VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, - VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM, - VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, - VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, - VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, - VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED, - VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK, - VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1), - VK_FORMAT_MAX_ENUM = 0x7FFFFFFF -} VkFormat; - -typedef enum VkImageType { - VK_IMAGE_TYPE_1D = 0, - VK_IMAGE_TYPE_2D = 1, - VK_IMAGE_TYPE_3D = 2, - VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D, - VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D, - VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1), - VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkImageType; - -typedef enum VkImageTiling { - VK_IMAGE_TILING_OPTIMAL = 0, - VK_IMAGE_TILING_LINEAR = 1, - VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, - VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, - VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), - VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF -} VkImageTiling; - -typedef enum VkPhysicalDeviceType { - VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, - VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, - VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, - VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, - VK_PHYSICAL_DEVICE_TYPE_CPU = 4, - VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER, - VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU, - VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1), - VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkPhysicalDeviceType; - -typedef enum VkQueryType { - VK_QUERY_TYPE_OCCLUSION = 0, - VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, - VK_QUERY_TYPE_TIMESTAMP = 2, - VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, - VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, - VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, - VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, - VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), - VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkQueryType; - -typedef enum VkSharingMode { - VK_SHARING_MODE_EXCLUSIVE = 0, - VK_SHARING_MODE_CONCURRENT = 1, - VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE, - VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT, - VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1), - VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSharingMode; - -typedef enum VkImageLayout { - VK_IMAGE_LAYOUT_UNDEFINED = 0, - VK_IMAGE_LAYOUT_GENERAL = 1, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, - VK_IMAGE_LAYOUT_PREINITIALIZED = 8, - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, - VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, - VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = 1000164003, - VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED, - VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1), - VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF -} VkImageLayout; - -typedef enum VkImageViewType { - VK_IMAGE_VIEW_TYPE_1D = 0, - VK_IMAGE_VIEW_TYPE_2D = 1, - VK_IMAGE_VIEW_TYPE_3D = 2, - VK_IMAGE_VIEW_TYPE_CUBE = 3, - VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, - VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, - VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, - VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D, - VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, - VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1), - VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkImageViewType; - -typedef enum VkComponentSwizzle { - VK_COMPONENT_SWIZZLE_IDENTITY = 0, - VK_COMPONENT_SWIZZLE_ZERO = 1, - VK_COMPONENT_SWIZZLE_ONE = 2, - VK_COMPONENT_SWIZZLE_R = 3, - VK_COMPONENT_SWIZZLE_G = 4, - VK_COMPONENT_SWIZZLE_B = 5, - VK_COMPONENT_SWIZZLE_A = 6, - VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A, - VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1), - VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF -} VkComponentSwizzle; - -typedef enum VkVertexInputRate { - VK_VERTEX_INPUT_RATE_VERTEX = 0, - VK_VERTEX_INPUT_RATE_INSTANCE = 1, - VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX, - VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE, - VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1), - VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF -} VkVertexInputRate; - -typedef enum VkPrimitiveTopology { - VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, - VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, - VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, - VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, - VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1), - VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF -} VkPrimitiveTopology; - -typedef enum VkPolygonMode { - VK_POLYGON_MODE_FILL = 0, - VK_POLYGON_MODE_LINE = 1, - VK_POLYGON_MODE_POINT = 2, - VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, - VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL, - VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT, - VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1), - VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF -} VkPolygonMode; - -typedef enum VkFrontFace { - VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, - VK_FRONT_FACE_CLOCKWISE = 1, - VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE, - VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE, - VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1), - VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF -} VkFrontFace; - -typedef enum VkCompareOp { - VK_COMPARE_OP_NEVER = 0, - VK_COMPARE_OP_LESS = 1, - VK_COMPARE_OP_EQUAL = 2, - VK_COMPARE_OP_LESS_OR_EQUAL = 3, - VK_COMPARE_OP_GREATER = 4, - VK_COMPARE_OP_NOT_EQUAL = 5, - VK_COMPARE_OP_GREATER_OR_EQUAL = 6, - VK_COMPARE_OP_ALWAYS = 7, - VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER, - VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS, - VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1), - VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF -} VkCompareOp; - -typedef enum VkStencilOp { - VK_STENCIL_OP_KEEP = 0, - VK_STENCIL_OP_ZERO = 1, - VK_STENCIL_OP_REPLACE = 2, - VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, - VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, - VK_STENCIL_OP_INVERT = 5, - VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, - VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, - VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP, - VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP, - VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1), - VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF -} VkStencilOp; - -typedef enum VkLogicOp { - VK_LOGIC_OP_CLEAR = 0, - VK_LOGIC_OP_AND = 1, - VK_LOGIC_OP_AND_REVERSE = 2, - VK_LOGIC_OP_COPY = 3, - VK_LOGIC_OP_AND_INVERTED = 4, - VK_LOGIC_OP_NO_OP = 5, - VK_LOGIC_OP_XOR = 6, - VK_LOGIC_OP_OR = 7, - VK_LOGIC_OP_NOR = 8, - VK_LOGIC_OP_EQUIVALENT = 9, - VK_LOGIC_OP_INVERT = 10, - VK_LOGIC_OP_OR_REVERSE = 11, - VK_LOGIC_OP_COPY_INVERTED = 12, - VK_LOGIC_OP_OR_INVERTED = 13, - VK_LOGIC_OP_NAND = 14, - VK_LOGIC_OP_SET = 15, - VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR, - VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET, - VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1), - VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF -} VkLogicOp; - -typedef enum VkBlendFactor { - VK_BLEND_FACTOR_ZERO = 0, - VK_BLEND_FACTOR_ONE = 1, - VK_BLEND_FACTOR_SRC_COLOR = 2, - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, - VK_BLEND_FACTOR_DST_COLOR = 4, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, - VK_BLEND_FACTOR_SRC_ALPHA = 6, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, - VK_BLEND_FACTOR_DST_ALPHA = 8, - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, - VK_BLEND_FACTOR_CONSTANT_COLOR = 10, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, - VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, - VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, - VK_BLEND_FACTOR_SRC1_COLOR = 15, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, - VK_BLEND_FACTOR_SRC1_ALPHA = 17, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, - VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO, - VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, - VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1), - VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF -} VkBlendFactor; - -typedef enum VkBlendOp { - VK_BLEND_OP_ADD = 0, - VK_BLEND_OP_SUBTRACT = 1, - VK_BLEND_OP_REVERSE_SUBTRACT = 2, - VK_BLEND_OP_MIN = 3, - VK_BLEND_OP_MAX = 4, - VK_BLEND_OP_ZERO_EXT = 1000148000, - VK_BLEND_OP_SRC_EXT = 1000148001, - VK_BLEND_OP_DST_EXT = 1000148002, - VK_BLEND_OP_SRC_OVER_EXT = 1000148003, - VK_BLEND_OP_DST_OVER_EXT = 1000148004, - VK_BLEND_OP_SRC_IN_EXT = 1000148005, - VK_BLEND_OP_DST_IN_EXT = 1000148006, - VK_BLEND_OP_SRC_OUT_EXT = 1000148007, - VK_BLEND_OP_DST_OUT_EXT = 1000148008, - VK_BLEND_OP_SRC_ATOP_EXT = 1000148009, - VK_BLEND_OP_DST_ATOP_EXT = 1000148010, - VK_BLEND_OP_XOR_EXT = 1000148011, - VK_BLEND_OP_MULTIPLY_EXT = 1000148012, - VK_BLEND_OP_SCREEN_EXT = 1000148013, - VK_BLEND_OP_OVERLAY_EXT = 1000148014, - VK_BLEND_OP_DARKEN_EXT = 1000148015, - VK_BLEND_OP_LIGHTEN_EXT = 1000148016, - VK_BLEND_OP_COLORDODGE_EXT = 1000148017, - VK_BLEND_OP_COLORBURN_EXT = 1000148018, - VK_BLEND_OP_HARDLIGHT_EXT = 1000148019, - VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020, - VK_BLEND_OP_DIFFERENCE_EXT = 1000148021, - VK_BLEND_OP_EXCLUSION_EXT = 1000148022, - VK_BLEND_OP_INVERT_EXT = 1000148023, - VK_BLEND_OP_INVERT_RGB_EXT = 1000148024, - VK_BLEND_OP_LINEARDODGE_EXT = 1000148025, - VK_BLEND_OP_LINEARBURN_EXT = 1000148026, - VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027, - VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028, - VK_BLEND_OP_PINLIGHT_EXT = 1000148029, - VK_BLEND_OP_HARDMIX_EXT = 1000148030, - VK_BLEND_OP_HSL_HUE_EXT = 1000148031, - VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032, - VK_BLEND_OP_HSL_COLOR_EXT = 1000148033, - VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034, - VK_BLEND_OP_PLUS_EXT = 1000148035, - VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036, - VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037, - VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038, - VK_BLEND_OP_MINUS_EXT = 1000148039, - VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040, - VK_BLEND_OP_CONTRAST_EXT = 1000148041, - VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, - VK_BLEND_OP_RED_EXT = 1000148043, - VK_BLEND_OP_GREEN_EXT = 1000148044, - VK_BLEND_OP_BLUE_EXT = 1000148045, - VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD, - VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX, - VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1), - VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF -} VkBlendOp; - -typedef enum VkDynamicState { - VK_DYNAMIC_STATE_VIEWPORT = 0, - VK_DYNAMIC_STATE_SCISSOR = 1, - VK_DYNAMIC_STATE_LINE_WIDTH = 2, - VK_DYNAMIC_STATE_DEPTH_BIAS = 3, - VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, - VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, - VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, - VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, - VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, - VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, - VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, - VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, - VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, - VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, - VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, - VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1), - VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF -} VkDynamicState; - -typedef enum VkFilter { - VK_FILTER_NEAREST = 0, - VK_FILTER_LINEAR = 1, - VK_FILTER_CUBIC_IMG = 1000015000, - VK_FILTER_CUBIC_EXT = VK_FILTER_CUBIC_IMG, - VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST, - VK_FILTER_END_RANGE = VK_FILTER_LINEAR, - VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1), - VK_FILTER_MAX_ENUM = 0x7FFFFFFF -} VkFilter; - -typedef enum VkSamplerMipmapMode { - VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, - VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, - VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST, - VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR, - VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1), - VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSamplerMipmapMode; - -typedef enum VkSamplerAddressMode { - VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, - VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, - VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT, - VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, - VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), - VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSamplerAddressMode; - -typedef enum VkBorderColor { - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, - VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, - VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, - VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, - VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, - VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, - VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, - VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE, - VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1), - VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF -} VkBorderColor; - -typedef enum VkDescriptorType { - VK_DESCRIPTOR_TYPE_SAMPLER = 0, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, - VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, - VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, - VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, - VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, - VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, - VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), - VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorType; - -typedef enum VkAttachmentLoadOp { - VK_ATTACHMENT_LOAD_OP_LOAD = 0, - VK_ATTACHMENT_LOAD_OP_CLEAR = 1, - VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, - VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1), - VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentLoadOp; - -typedef enum VkAttachmentStoreOp { - VK_ATTACHMENT_STORE_OP_STORE = 0, - VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, - VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1), - VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentStoreOp; - -typedef enum VkPipelineBindPoint { - VK_PIPELINE_BIND_POINT_GRAPHICS = 0, - VK_PIPELINE_BIND_POINT_COMPUTE = 1, - VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000, - VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, - VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, - VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), - VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF -} VkPipelineBindPoint; - -typedef enum VkCommandBufferLevel { - VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, - VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, - VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY, - VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1), - VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferLevel; - -typedef enum VkIndexType { - VK_INDEX_TYPE_UINT16 = 0, - VK_INDEX_TYPE_UINT32 = 1, - VK_INDEX_TYPE_NONE_NV = 1000165000, - VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, - VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, - VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), - VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkIndexType; - -typedef enum VkSubpassContents { - VK_SUBPASS_CONTENTS_INLINE = 0, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, - VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE, - VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, - VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1), - VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF -} VkSubpassContents; - -typedef enum VkObjectType { - VK_OBJECT_TYPE_UNKNOWN = 0, - VK_OBJECT_TYPE_INSTANCE = 1, - VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2, - VK_OBJECT_TYPE_DEVICE = 3, - VK_OBJECT_TYPE_QUEUE = 4, - VK_OBJECT_TYPE_SEMAPHORE = 5, - VK_OBJECT_TYPE_COMMAND_BUFFER = 6, - VK_OBJECT_TYPE_FENCE = 7, - VK_OBJECT_TYPE_DEVICE_MEMORY = 8, - VK_OBJECT_TYPE_BUFFER = 9, - VK_OBJECT_TYPE_IMAGE = 10, - VK_OBJECT_TYPE_EVENT = 11, - VK_OBJECT_TYPE_QUERY_POOL = 12, - VK_OBJECT_TYPE_BUFFER_VIEW = 13, - VK_OBJECT_TYPE_IMAGE_VIEW = 14, - VK_OBJECT_TYPE_SHADER_MODULE = 15, - VK_OBJECT_TYPE_PIPELINE_CACHE = 16, - VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17, - VK_OBJECT_TYPE_RENDER_PASS = 18, - VK_OBJECT_TYPE_PIPELINE = 19, - VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20, - VK_OBJECT_TYPE_SAMPLER = 21, - VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22, - VK_OBJECT_TYPE_DESCRIPTOR_SET = 23, - VK_OBJECT_TYPE_FRAMEBUFFER = 24, - VK_OBJECT_TYPE_COMMAND_POOL = 25, - VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, - VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, - VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, - VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, - VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, - VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, - VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, - VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000, - VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001, - VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, - VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, - VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, - VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, - VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, - VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN, - VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL, - VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1), - VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkObjectType; - -typedef enum VkVendorId { - VK_VENDOR_ID_VIV = 0x10001, - VK_VENDOR_ID_VSI = 0x10002, - VK_VENDOR_ID_KAZAN = 0x10003, - VK_VENDOR_ID_BEGIN_RANGE = VK_VENDOR_ID_VIV, - VK_VENDOR_ID_END_RANGE = VK_VENDOR_ID_KAZAN, - VK_VENDOR_ID_RANGE_SIZE = (VK_VENDOR_ID_KAZAN - VK_VENDOR_ID_VIV + 1), - VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF -} VkVendorId; -typedef VkFlags VkInstanceCreateFlags; - -typedef enum VkFormatFeatureFlagBits { - VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, - VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, - VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, - VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, - VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, - VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, - VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, - VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000, - VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000, - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, - VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG, - VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFormatFeatureFlagBits; -typedef VkFlags VkFormatFeatureFlags; - -typedef enum VkImageUsageFlagBits { - VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, - VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, - VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, - VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, - VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00000100, - VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200, - VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageUsageFlagBits; -typedef VkFlags VkImageUsageFlags; - -typedef enum VkImageCreateFlagBits { - VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, - VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, - VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, - VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, - VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, - VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, - VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040, - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, - VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, - VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, - VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000, - VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, - VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000, - VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, - VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT, - VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT, - VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageCreateFlagBits; -typedef VkFlags VkImageCreateFlags; - -typedef enum VkSampleCountFlagBits { - VK_SAMPLE_COUNT_1_BIT = 0x00000001, - VK_SAMPLE_COUNT_2_BIT = 0x00000002, - VK_SAMPLE_COUNT_4_BIT = 0x00000004, - VK_SAMPLE_COUNT_8_BIT = 0x00000008, - VK_SAMPLE_COUNT_16_BIT = 0x00000010, - VK_SAMPLE_COUNT_32_BIT = 0x00000020, - VK_SAMPLE_COUNT_64_BIT = 0x00000040, - VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSampleCountFlagBits; -typedef VkFlags VkSampleCountFlags; - -typedef enum VkQueueFlagBits { - VK_QUEUE_GRAPHICS_BIT = 0x00000001, - VK_QUEUE_COMPUTE_BIT = 0x00000002, - VK_QUEUE_TRANSFER_BIT = 0x00000004, - VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, - VK_QUEUE_PROTECTED_BIT = 0x00000010, - VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueueFlagBits; -typedef VkFlags VkQueueFlags; - -typedef enum VkMemoryPropertyFlagBits { - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, - VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, - VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, - VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, - VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkMemoryPropertyFlagBits; -typedef VkFlags VkMemoryPropertyFlags; - -typedef enum VkMemoryHeapFlagBits { - VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, - VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkMemoryHeapFlagBits; -typedef VkFlags VkMemoryHeapFlags; -typedef VkFlags VkDeviceCreateFlags; - -typedef enum VkDeviceQueueCreateFlagBits { - VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, - VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDeviceQueueCreateFlagBits; -typedef VkFlags VkDeviceQueueCreateFlags; - -typedef enum VkPipelineStageFlagBits { - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, - VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, - VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, - VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, - VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, - VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, - VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, - VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, - VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000, - VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000, - VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = 0x00200000, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000, - VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000, - VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000, - VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, - VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkPipelineStageFlagBits; -typedef VkFlags VkPipelineStageFlags; -typedef VkFlags VkMemoryMapFlags; - -typedef enum VkImageAspectFlagBits { - VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, - VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, - VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, - VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, - VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, - VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, - VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, - VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, - VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, - VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, - VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400, - VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, - VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, - VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, - VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageAspectFlagBits; -typedef VkFlags VkImageAspectFlags; - -typedef enum VkSparseImageFormatFlagBits { - VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, - VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, - VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, - VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSparseImageFormatFlagBits; -typedef VkFlags VkSparseImageFormatFlags; - -typedef enum VkSparseMemoryBindFlagBits { - VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, - VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSparseMemoryBindFlagBits; -typedef VkFlags VkSparseMemoryBindFlags; - -typedef enum VkFenceCreateFlagBits { - VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, - VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFenceCreateFlagBits; -typedef VkFlags VkFenceCreateFlags; -typedef VkFlags VkSemaphoreCreateFlags; -typedef VkFlags VkEventCreateFlags; -typedef VkFlags VkQueryPoolCreateFlags; - -typedef enum VkQueryPipelineStatisticFlagBits { - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, - VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, - VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, - VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, - VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryPipelineStatisticFlagBits; -typedef VkFlags VkQueryPipelineStatisticFlags; - -typedef enum VkQueryResultFlagBits { - VK_QUERY_RESULT_64_BIT = 0x00000001, - VK_QUERY_RESULT_WAIT_BIT = 0x00000002, - VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, - VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, - VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryResultFlagBits; -typedef VkFlags VkQueryResultFlags; - -typedef enum VkBufferCreateFlagBits { - VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, - VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, - VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, - VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, - VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = 0x00000010, - VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkBufferCreateFlagBits; -typedef VkFlags VkBufferCreateFlags; - -typedef enum VkBufferUsageFlagBits { - VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, - VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, - VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, - VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, - VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, - VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, - VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, - VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, - VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = 0x00020000, - VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkBufferUsageFlagBits; -typedef VkFlags VkBufferUsageFlags; -typedef VkFlags VkBufferViewCreateFlags; - -typedef enum VkImageViewCreateFlagBits { - VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 0x00000001, - VK_IMAGE_VIEW_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageViewCreateFlagBits; -typedef VkFlags VkImageViewCreateFlags; -typedef VkFlags VkShaderModuleCreateFlags; -typedef VkFlags VkPipelineCacheCreateFlags; - -typedef enum VkPipelineCreateFlagBits { - VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, - VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, - VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, - VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010, - VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, - VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, - VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkPipelineCreateFlagBits; -typedef VkFlags VkPipelineCreateFlags; -typedef VkFlags VkPipelineShaderStageCreateFlags; - -typedef enum VkShaderStageFlagBits { - VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, - VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, - VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, - VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, - VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, - VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, - VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, - VK_SHADER_STAGE_ALL = 0x7FFFFFFF, - VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100, - VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400, - VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800, - VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000, - VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000, - VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040, - VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080, - VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkShaderStageFlagBits; -typedef VkFlags VkPipelineVertexInputStateCreateFlags; -typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; -typedef VkFlags VkPipelineTessellationStateCreateFlags; -typedef VkFlags VkPipelineViewportStateCreateFlags; -typedef VkFlags VkPipelineRasterizationStateCreateFlags; - -typedef enum VkCullModeFlagBits { - VK_CULL_MODE_NONE = 0, - VK_CULL_MODE_FRONT_BIT = 0x00000001, - VK_CULL_MODE_BACK_BIT = 0x00000002, - VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, - VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCullModeFlagBits; -typedef VkFlags VkCullModeFlags; -typedef VkFlags VkPipelineMultisampleStateCreateFlags; -typedef VkFlags VkPipelineDepthStencilStateCreateFlags; -typedef VkFlags VkPipelineColorBlendStateCreateFlags; - -typedef enum VkColorComponentFlagBits { - VK_COLOR_COMPONENT_R_BIT = 0x00000001, - VK_COLOR_COMPONENT_G_BIT = 0x00000002, - VK_COLOR_COMPONENT_B_BIT = 0x00000004, - VK_COLOR_COMPONENT_A_BIT = 0x00000008, - VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkColorComponentFlagBits; -typedef VkFlags VkColorComponentFlags; -typedef VkFlags VkPipelineDynamicStateCreateFlags; -typedef VkFlags VkPipelineLayoutCreateFlags; -typedef VkFlags VkShaderStageFlags; - -typedef enum VkSamplerCreateFlagBits { - VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001, - VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002, - VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSamplerCreateFlagBits; -typedef VkFlags VkSamplerCreateFlags; - -typedef enum VkDescriptorSetLayoutCreateFlagBits { - VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = 0x00000002, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorSetLayoutCreateFlagBits; -typedef VkFlags VkDescriptorSetLayoutCreateFlags; - -typedef enum VkDescriptorPoolCreateFlagBits { - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, - VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = 0x00000002, - VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorPoolCreateFlagBits; -typedef VkFlags VkDescriptorPoolCreateFlags; -typedef VkFlags VkDescriptorPoolResetFlags; - -typedef enum VkFramebufferCreateFlagBits { - VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = 0x00000001, - VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFramebufferCreateFlagBits; -typedef VkFlags VkFramebufferCreateFlags; -typedef VkFlags VkRenderPassCreateFlags; - -typedef enum VkAttachmentDescriptionFlagBits { - VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, - VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentDescriptionFlagBits; -typedef VkFlags VkAttachmentDescriptionFlags; - -typedef enum VkSubpassDescriptionFlagBits { - VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001, - VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002, - VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSubpassDescriptionFlagBits; -typedef VkFlags VkSubpassDescriptionFlags; - -typedef enum VkAccessFlagBits { - VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, - VK_ACCESS_INDEX_READ_BIT = 0x00000002, - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, - VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, - VK_ACCESS_SHADER_READ_BIT = 0x00000020, - VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, - VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, - VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, - VK_ACCESS_HOST_READ_BIT = 0x00002000, - VK_ACCESS_HOST_WRITE_BIT = 0x00004000, - VK_ACCESS_MEMORY_READ_BIT = 0x00008000, - VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, - VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, - VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, - VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000, - VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000, - VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, - VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000, - VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000, - VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000, - VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000, - VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkAccessFlagBits; -typedef VkFlags VkAccessFlags; - -typedef enum VkDependencyFlagBits { - VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, - VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, - VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, - VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT, - VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDependencyFlagBits; -typedef VkFlags VkDependencyFlags; - -typedef enum VkCommandPoolCreateFlagBits { - VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, - VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, - VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, - VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandPoolCreateFlagBits; -typedef VkFlags VkCommandPoolCreateFlags; - -typedef enum VkCommandPoolResetFlagBits { - VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, - VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandPoolResetFlagBits; -typedef VkFlags VkCommandPoolResetFlags; - -typedef enum VkCommandBufferUsageFlagBits { - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, - VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, - VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferUsageFlagBits; -typedef VkFlags VkCommandBufferUsageFlags; - -typedef enum VkQueryControlFlagBits { - VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, - VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryControlFlagBits; -typedef VkFlags VkQueryControlFlags; - -typedef enum VkCommandBufferResetFlagBits { - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, - VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferResetFlagBits; -typedef VkFlags VkCommandBufferResetFlags; - -typedef enum VkStencilFaceFlagBits { - VK_STENCIL_FACE_FRONT_BIT = 0x00000001, - VK_STENCIL_FACE_BACK_BIT = 0x00000002, - VK_STENCIL_FRONT_AND_BACK = 0x00000003, - VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkStencilFaceFlagBits; -typedef VkFlags VkStencilFaceFlags; -typedef struct VkApplicationInfo { - VkStructureType sType; - const void* pNext; - const char* pApplicationName; - uint32_t applicationVersion; - const char* pEngineName; - uint32_t engineVersion; - uint32_t apiVersion; -} VkApplicationInfo; - -typedef struct VkInstanceCreateInfo { - VkStructureType sType; - const void* pNext; - VkInstanceCreateFlags flags; - const VkApplicationInfo* pApplicationInfo; - uint32_t enabledLayerCount; - const char* const* ppEnabledLayerNames; - uint32_t enabledExtensionCount; - const char* const* ppEnabledExtensionNames; -} VkInstanceCreateInfo; - -typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( - void* pUserData, - size_t size, - size_t alignment, - VkSystemAllocationScope allocationScope); - -typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( - void* pUserData, - void* pOriginal, - size_t size, - size_t alignment, - VkSystemAllocationScope allocationScope); - -typedef void (VKAPI_PTR *PFN_vkFreeFunction)( - void* pUserData, - void* pMemory); - -typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( - void* pUserData, - size_t size, - VkInternalAllocationType allocationType, - VkSystemAllocationScope allocationScope); - -typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( - void* pUserData, - size_t size, - VkInternalAllocationType allocationType, - VkSystemAllocationScope allocationScope); - -typedef struct VkAllocationCallbacks { - void* pUserData; - PFN_vkAllocationFunction pfnAllocation; - PFN_vkReallocationFunction pfnReallocation; - PFN_vkFreeFunction pfnFree; - PFN_vkInternalAllocationNotification pfnInternalAllocation; - PFN_vkInternalFreeNotification pfnInternalFree; -} VkAllocationCallbacks; - -typedef struct VkPhysicalDeviceFeatures { - VkBool32 robustBufferAccess; - VkBool32 fullDrawIndexUint32; - VkBool32 imageCubeArray; - VkBool32 independentBlend; - VkBool32 geometryShader; - VkBool32 tessellationShader; - VkBool32 sampleRateShading; - VkBool32 dualSrcBlend; - VkBool32 logicOp; - VkBool32 multiDrawIndirect; - VkBool32 drawIndirectFirstInstance; - VkBool32 depthClamp; - VkBool32 depthBiasClamp; - VkBool32 fillModeNonSolid; - VkBool32 depthBounds; - VkBool32 wideLines; - VkBool32 largePoints; - VkBool32 alphaToOne; - VkBool32 multiViewport; - VkBool32 samplerAnisotropy; - VkBool32 textureCompressionETC2; - VkBool32 textureCompressionASTC_LDR; - VkBool32 textureCompressionBC; - VkBool32 occlusionQueryPrecise; - VkBool32 pipelineStatisticsQuery; - VkBool32 vertexPipelineStoresAndAtomics; - VkBool32 fragmentStoresAndAtomics; - VkBool32 shaderTessellationAndGeometryPointSize; - VkBool32 shaderImageGatherExtended; - VkBool32 shaderStorageImageExtendedFormats; - VkBool32 shaderStorageImageMultisample; - VkBool32 shaderStorageImageReadWithoutFormat; - VkBool32 shaderStorageImageWriteWithoutFormat; - VkBool32 shaderUniformBufferArrayDynamicIndexing; - VkBool32 shaderSampledImageArrayDynamicIndexing; - VkBool32 shaderStorageBufferArrayDynamicIndexing; - VkBool32 shaderStorageImageArrayDynamicIndexing; - VkBool32 shaderClipDistance; - VkBool32 shaderCullDistance; - VkBool32 shaderFloat64; - VkBool32 shaderInt64; - VkBool32 shaderInt16; - VkBool32 shaderResourceResidency; - VkBool32 shaderResourceMinLod; - VkBool32 sparseBinding; - VkBool32 sparseResidencyBuffer; - VkBool32 sparseResidencyImage2D; - VkBool32 sparseResidencyImage3D; - VkBool32 sparseResidency2Samples; - VkBool32 sparseResidency4Samples; - VkBool32 sparseResidency8Samples; - VkBool32 sparseResidency16Samples; - VkBool32 sparseResidencyAliased; - VkBool32 variableMultisampleRate; - VkBool32 inheritedQueries; -} VkPhysicalDeviceFeatures; - -typedef struct VkFormatProperties { - VkFormatFeatureFlags linearTilingFeatures; - VkFormatFeatureFlags optimalTilingFeatures; - VkFormatFeatureFlags bufferFeatures; -} VkFormatProperties; - -typedef struct VkExtent3D { - uint32_t width; - uint32_t height; - uint32_t depth; -} VkExtent3D; - -typedef struct VkImageFormatProperties { - VkExtent3D maxExtent; - uint32_t maxMipLevels; - uint32_t maxArrayLayers; - VkSampleCountFlags sampleCounts; - VkDeviceSize maxResourceSize; -} VkImageFormatProperties; - -typedef struct VkPhysicalDeviceLimits { - uint32_t maxImageDimension1D; - uint32_t maxImageDimension2D; - uint32_t maxImageDimension3D; - uint32_t maxImageDimensionCube; - uint32_t maxImageArrayLayers; - uint32_t maxTexelBufferElements; - uint32_t maxUniformBufferRange; - uint32_t maxStorageBufferRange; - uint32_t maxPushConstantsSize; - uint32_t maxMemoryAllocationCount; - uint32_t maxSamplerAllocationCount; - VkDeviceSize bufferImageGranularity; - VkDeviceSize sparseAddressSpaceSize; - uint32_t maxBoundDescriptorSets; - uint32_t maxPerStageDescriptorSamplers; - uint32_t maxPerStageDescriptorUniformBuffers; - uint32_t maxPerStageDescriptorStorageBuffers; - uint32_t maxPerStageDescriptorSampledImages; - uint32_t maxPerStageDescriptorStorageImages; - uint32_t maxPerStageDescriptorInputAttachments; - uint32_t maxPerStageResources; - uint32_t maxDescriptorSetSamplers; - uint32_t maxDescriptorSetUniformBuffers; - uint32_t maxDescriptorSetUniformBuffersDynamic; - uint32_t maxDescriptorSetStorageBuffers; - uint32_t maxDescriptorSetStorageBuffersDynamic; - uint32_t maxDescriptorSetSampledImages; - uint32_t maxDescriptorSetStorageImages; - uint32_t maxDescriptorSetInputAttachments; - uint32_t maxVertexInputAttributes; - uint32_t maxVertexInputBindings; - uint32_t maxVertexInputAttributeOffset; - uint32_t maxVertexInputBindingStride; - uint32_t maxVertexOutputComponents; - uint32_t maxTessellationGenerationLevel; - uint32_t maxTessellationPatchSize; - uint32_t maxTessellationControlPerVertexInputComponents; - uint32_t maxTessellationControlPerVertexOutputComponents; - uint32_t maxTessellationControlPerPatchOutputComponents; - uint32_t maxTessellationControlTotalOutputComponents; - uint32_t maxTessellationEvaluationInputComponents; - uint32_t maxTessellationEvaluationOutputComponents; - uint32_t maxGeometryShaderInvocations; - uint32_t maxGeometryInputComponents; - uint32_t maxGeometryOutputComponents; - uint32_t maxGeometryOutputVertices; - uint32_t maxGeometryTotalOutputComponents; - uint32_t maxFragmentInputComponents; - uint32_t maxFragmentOutputAttachments; - uint32_t maxFragmentDualSrcAttachments; - uint32_t maxFragmentCombinedOutputResources; - uint32_t maxComputeSharedMemorySize; - uint32_t maxComputeWorkGroupCount[3]; - uint32_t maxComputeWorkGroupInvocations; - uint32_t maxComputeWorkGroupSize[3]; - uint32_t subPixelPrecisionBits; - uint32_t subTexelPrecisionBits; - uint32_t mipmapPrecisionBits; - uint32_t maxDrawIndexedIndexValue; - uint32_t maxDrawIndirectCount; - float maxSamplerLodBias; - float maxSamplerAnisotropy; - uint32_t maxViewports; - uint32_t maxViewportDimensions[2]; - float viewportBoundsRange[2]; - uint32_t viewportSubPixelBits; - size_t minMemoryMapAlignment; - VkDeviceSize minTexelBufferOffsetAlignment; - VkDeviceSize minUniformBufferOffsetAlignment; - VkDeviceSize minStorageBufferOffsetAlignment; - int32_t minTexelOffset; - uint32_t maxTexelOffset; - int32_t minTexelGatherOffset; - uint32_t maxTexelGatherOffset; - float minInterpolationOffset; - float maxInterpolationOffset; - uint32_t subPixelInterpolationOffsetBits; - uint32_t maxFramebufferWidth; - uint32_t maxFramebufferHeight; - uint32_t maxFramebufferLayers; - VkSampleCountFlags framebufferColorSampleCounts; - VkSampleCountFlags framebufferDepthSampleCounts; - VkSampleCountFlags framebufferStencilSampleCounts; - VkSampleCountFlags framebufferNoAttachmentsSampleCounts; - uint32_t maxColorAttachments; - VkSampleCountFlags sampledImageColorSampleCounts; - VkSampleCountFlags sampledImageIntegerSampleCounts; - VkSampleCountFlags sampledImageDepthSampleCounts; - VkSampleCountFlags sampledImageStencilSampleCounts; - VkSampleCountFlags storageImageSampleCounts; - uint32_t maxSampleMaskWords; - VkBool32 timestampComputeAndGraphics; - float timestampPeriod; - uint32_t maxClipDistances; - uint32_t maxCullDistances; - uint32_t maxCombinedClipAndCullDistances; - uint32_t discreteQueuePriorities; - float pointSizeRange[2]; - float lineWidthRange[2]; - float pointSizeGranularity; - float lineWidthGranularity; - VkBool32 strictLines; - VkBool32 standardSampleLocations; - VkDeviceSize optimalBufferCopyOffsetAlignment; - VkDeviceSize optimalBufferCopyRowPitchAlignment; - VkDeviceSize nonCoherentAtomSize; -} VkPhysicalDeviceLimits; - -typedef struct VkPhysicalDeviceSparseProperties { - VkBool32 residencyStandard2DBlockShape; - VkBool32 residencyStandard2DMultisampleBlockShape; - VkBool32 residencyStandard3DBlockShape; - VkBool32 residencyAlignedMipSize; - VkBool32 residencyNonResidentStrict; -} VkPhysicalDeviceSparseProperties; - -typedef struct VkPhysicalDeviceProperties { - uint32_t apiVersion; - uint32_t driverVersion; - uint32_t vendorID; - uint32_t deviceID; - VkPhysicalDeviceType deviceType; - char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; - uint8_t pipelineCacheUUID[VK_UUID_SIZE]; - VkPhysicalDeviceLimits limits; - VkPhysicalDeviceSparseProperties sparseProperties; -} VkPhysicalDeviceProperties; - -typedef struct VkQueueFamilyProperties { - VkQueueFlags queueFlags; - uint32_t queueCount; - uint32_t timestampValidBits; - VkExtent3D minImageTransferGranularity; -} VkQueueFamilyProperties; - -typedef struct VkMemoryType { - VkMemoryPropertyFlags propertyFlags; - uint32_t heapIndex; -} VkMemoryType; - -typedef struct VkMemoryHeap { - VkDeviceSize size; - VkMemoryHeapFlags flags; -} VkMemoryHeap; - -typedef struct VkPhysicalDeviceMemoryProperties { - uint32_t memoryTypeCount; - VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; - uint32_t memoryHeapCount; - VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; -} VkPhysicalDeviceMemoryProperties; - -typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); -typedef struct VkDeviceQueueCreateInfo { - VkStructureType sType; - const void* pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueCount; - const float* pQueuePriorities; -} VkDeviceQueueCreateInfo; - -typedef struct VkDeviceCreateInfo { - VkStructureType sType; - const void* pNext; - VkDeviceCreateFlags flags; - uint32_t queueCreateInfoCount; - const VkDeviceQueueCreateInfo* pQueueCreateInfos; - uint32_t enabledLayerCount; - const char* const* ppEnabledLayerNames; - uint32_t enabledExtensionCount; - const char* const* ppEnabledExtensionNames; - const VkPhysicalDeviceFeatures* pEnabledFeatures; -} VkDeviceCreateInfo; - -typedef struct VkExtensionProperties { - char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; - uint32_t specVersion; -} VkExtensionProperties; - -typedef struct VkLayerProperties { - char layerName[VK_MAX_EXTENSION_NAME_SIZE]; - uint32_t specVersion; - uint32_t implementationVersion; - char description[VK_MAX_DESCRIPTION_SIZE]; -} VkLayerProperties; - -typedef struct VkSubmitInfo { - VkStructureType sType; - const void* pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore* pWaitSemaphores; - const VkPipelineStageFlags* pWaitDstStageMask; - uint32_t commandBufferCount; - const VkCommandBuffer* pCommandBuffers; - uint32_t signalSemaphoreCount; - const VkSemaphore* pSignalSemaphores; -} VkSubmitInfo; - -typedef struct VkMemoryAllocateInfo { - VkStructureType sType; - const void* pNext; - VkDeviceSize allocationSize; - uint32_t memoryTypeIndex; -} VkMemoryAllocateInfo; - -typedef struct VkMappedMemoryRange { - VkStructureType sType; - const void* pNext; - VkDeviceMemory memory; - VkDeviceSize offset; - VkDeviceSize size; -} VkMappedMemoryRange; - -typedef struct VkMemoryRequirements { - VkDeviceSize size; - VkDeviceSize alignment; - uint32_t memoryTypeBits; -} VkMemoryRequirements; - -typedef struct VkSparseImageFormatProperties { - VkImageAspectFlags aspectMask; - VkExtent3D imageGranularity; - VkSparseImageFormatFlags flags; -} VkSparseImageFormatProperties; - -typedef struct VkSparseImageMemoryRequirements { - VkSparseImageFormatProperties formatProperties; - uint32_t imageMipTailFirstLod; - VkDeviceSize imageMipTailSize; - VkDeviceSize imageMipTailOffset; - VkDeviceSize imageMipTailStride; -} VkSparseImageMemoryRequirements; - -typedef struct VkSparseMemoryBind { - VkDeviceSize resourceOffset; - VkDeviceSize size; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseMemoryBind; - -typedef struct VkSparseBufferMemoryBindInfo { - VkBuffer buffer; - uint32_t bindCount; - const VkSparseMemoryBind* pBinds; -} VkSparseBufferMemoryBindInfo; - -typedef struct VkSparseImageOpaqueMemoryBindInfo { - VkImage image; - uint32_t bindCount; - const VkSparseMemoryBind* pBinds; -} VkSparseImageOpaqueMemoryBindInfo; - -typedef struct VkImageSubresource { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t arrayLayer; -} VkImageSubresource; - -typedef struct VkOffset3D { - int32_t x; - int32_t y; - int32_t z; -} VkOffset3D; - -typedef struct VkSparseImageMemoryBind { - VkImageSubresource subresource; - VkOffset3D offset; - VkExtent3D extent; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseImageMemoryBind; - -typedef struct VkSparseImageMemoryBindInfo { - VkImage image; - uint32_t bindCount; - const VkSparseImageMemoryBind* pBinds; -} VkSparseImageMemoryBindInfo; - -typedef struct VkBindSparseInfo { - VkStructureType sType; - const void* pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore* pWaitSemaphores; - uint32_t bufferBindCount; - const VkSparseBufferMemoryBindInfo* pBufferBinds; - uint32_t imageOpaqueBindCount; - const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; - uint32_t imageBindCount; - const VkSparseImageMemoryBindInfo* pImageBinds; - uint32_t signalSemaphoreCount; - const VkSemaphore* pSignalSemaphores; -} VkBindSparseInfo; - -typedef struct VkFenceCreateInfo { - VkStructureType sType; - const void* pNext; - VkFenceCreateFlags flags; -} VkFenceCreateInfo; - -typedef struct VkSemaphoreCreateInfo { - VkStructureType sType; - const void* pNext; - VkSemaphoreCreateFlags flags; -} VkSemaphoreCreateInfo; - -typedef struct VkEventCreateInfo { - VkStructureType sType; - const void* pNext; - VkEventCreateFlags flags; -} VkEventCreateInfo; - -typedef struct VkQueryPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkQueryPoolCreateFlags flags; - VkQueryType queryType; - uint32_t queryCount; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkQueryPoolCreateInfo; - -typedef struct VkBufferCreateInfo { - VkStructureType sType; - const void* pNext; - VkBufferCreateFlags flags; - VkDeviceSize size; - VkBufferUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t* pQueueFamilyIndices; -} VkBufferCreateInfo; - -typedef struct VkBufferViewCreateInfo { - VkStructureType sType; - const void* pNext; - VkBufferViewCreateFlags flags; - VkBuffer buffer; - VkFormat format; - VkDeviceSize offset; - VkDeviceSize range; -} VkBufferViewCreateInfo; - -typedef struct VkImageCreateInfo { - VkStructureType sType; - const void* pNext; - VkImageCreateFlags flags; - VkImageType imageType; - VkFormat format; - VkExtent3D extent; - uint32_t mipLevels; - uint32_t arrayLayers; - VkSampleCountFlagBits samples; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t* pQueueFamilyIndices; - VkImageLayout initialLayout; -} VkImageCreateInfo; - -typedef struct VkSubresourceLayout { - VkDeviceSize offset; - VkDeviceSize size; - VkDeviceSize rowPitch; - VkDeviceSize arrayPitch; - VkDeviceSize depthPitch; -} VkSubresourceLayout; - -typedef struct VkComponentMapping { - VkComponentSwizzle r; - VkComponentSwizzle g; - VkComponentSwizzle b; - VkComponentSwizzle a; -} VkComponentMapping; - -typedef struct VkImageSubresourceRange { - VkImageAspectFlags aspectMask; - uint32_t baseMipLevel; - uint32_t levelCount; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceRange; - -typedef struct VkImageViewCreateInfo { - VkStructureType sType; - const void* pNext; - VkImageViewCreateFlags flags; - VkImage image; - VkImageViewType viewType; - VkFormat format; - VkComponentMapping components; - VkImageSubresourceRange subresourceRange; -} VkImageViewCreateInfo; - -typedef struct VkShaderModuleCreateInfo { - VkStructureType sType; - const void* pNext; - VkShaderModuleCreateFlags flags; - size_t codeSize; - const uint32_t* pCode; -} VkShaderModuleCreateInfo; - -typedef struct VkPipelineCacheCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineCacheCreateFlags flags; - size_t initialDataSize; - const void* pInitialData; -} VkPipelineCacheCreateInfo; - -typedef struct VkSpecializationMapEntry { - uint32_t constantID; - uint32_t offset; - size_t size; -} VkSpecializationMapEntry; - -typedef struct VkSpecializationInfo { - uint32_t mapEntryCount; - const VkSpecializationMapEntry* pMapEntries; - size_t dataSize; - const void* pData; -} VkSpecializationInfo; - -typedef struct VkPipelineShaderStageCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineShaderStageCreateFlags flags; - VkShaderStageFlagBits stage; - VkShaderModule module; - const char* pName; - const VkSpecializationInfo* pSpecializationInfo; -} VkPipelineShaderStageCreateInfo; - -typedef struct VkVertexInputBindingDescription { - uint32_t binding; - uint32_t stride; - VkVertexInputRate inputRate; -} VkVertexInputBindingDescription; - -typedef struct VkVertexInputAttributeDescription { - uint32_t location; - uint32_t binding; - VkFormat format; - uint32_t offset; -} VkVertexInputAttributeDescription; - -typedef struct VkPipelineVertexInputStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineVertexInputStateCreateFlags flags; - uint32_t vertexBindingDescriptionCount; - const VkVertexInputBindingDescription* pVertexBindingDescriptions; - uint32_t vertexAttributeDescriptionCount; - const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; -} VkPipelineVertexInputStateCreateInfo; - -typedef struct VkPipelineInputAssemblyStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineInputAssemblyStateCreateFlags flags; - VkPrimitiveTopology topology; - VkBool32 primitiveRestartEnable; -} VkPipelineInputAssemblyStateCreateInfo; - -typedef struct VkPipelineTessellationStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineTessellationStateCreateFlags flags; - uint32_t patchControlPoints; -} VkPipelineTessellationStateCreateInfo; - -typedef struct VkViewport { - float x; - float y; - float width; - float height; - float minDepth; - float maxDepth; -} VkViewport; - -typedef struct VkOffset2D { - int32_t x; - int32_t y; -} VkOffset2D; - -typedef struct VkExtent2D { - uint32_t width; - uint32_t height; -} VkExtent2D; - -typedef struct VkRect2D { - VkOffset2D offset; - VkExtent2D extent; -} VkRect2D; - -typedef struct VkPipelineViewportStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineViewportStateCreateFlags flags; - uint32_t viewportCount; - const VkViewport* pViewports; - uint32_t scissorCount; - const VkRect2D* pScissors; -} VkPipelineViewportStateCreateInfo; - -typedef struct VkPipelineRasterizationStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineRasterizationStateCreateFlags flags; - VkBool32 depthClampEnable; - VkBool32 rasterizerDiscardEnable; - VkPolygonMode polygonMode; - VkCullModeFlags cullMode; - VkFrontFace frontFace; - VkBool32 depthBiasEnable; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; - float lineWidth; -} VkPipelineRasterizationStateCreateInfo; - -typedef struct VkPipelineMultisampleStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineMultisampleStateCreateFlags flags; - VkSampleCountFlagBits rasterizationSamples; - VkBool32 sampleShadingEnable; - float minSampleShading; - const VkSampleMask* pSampleMask; - VkBool32 alphaToCoverageEnable; - VkBool32 alphaToOneEnable; -} VkPipelineMultisampleStateCreateInfo; - -typedef struct VkStencilOpState { - VkStencilOp failOp; - VkStencilOp passOp; - VkStencilOp depthFailOp; - VkCompareOp compareOp; - uint32_t compareMask; - uint32_t writeMask; - uint32_t reference; -} VkStencilOpState; - -typedef struct VkPipelineDepthStencilStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineDepthStencilStateCreateFlags flags; - VkBool32 depthTestEnable; - VkBool32 depthWriteEnable; - VkCompareOp depthCompareOp; - VkBool32 depthBoundsTestEnable; - VkBool32 stencilTestEnable; - VkStencilOpState front; - VkStencilOpState back; - float minDepthBounds; - float maxDepthBounds; -} VkPipelineDepthStencilStateCreateInfo; - -typedef struct VkPipelineColorBlendAttachmentState { - VkBool32 blendEnable; - VkBlendFactor srcColorBlendFactor; - VkBlendFactor dstColorBlendFactor; - VkBlendOp colorBlendOp; - VkBlendFactor srcAlphaBlendFactor; - VkBlendFactor dstAlphaBlendFactor; - VkBlendOp alphaBlendOp; - VkColorComponentFlags colorWriteMask; -} VkPipelineColorBlendAttachmentState; - -typedef struct VkPipelineColorBlendStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineColorBlendStateCreateFlags flags; - VkBool32 logicOpEnable; - VkLogicOp logicOp; - uint32_t attachmentCount; - const VkPipelineColorBlendAttachmentState* pAttachments; - float blendConstants[4]; -} VkPipelineColorBlendStateCreateInfo; - -typedef struct VkPipelineDynamicStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineDynamicStateCreateFlags flags; - uint32_t dynamicStateCount; - const VkDynamicState* pDynamicStates; -} VkPipelineDynamicStateCreateInfo; - -typedef struct VkGraphicsPipelineCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo* pStages; - const VkPipelineVertexInputStateCreateInfo* pVertexInputState; - const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; - const VkPipelineTessellationStateCreateInfo* pTessellationState; - const VkPipelineViewportStateCreateInfo* pViewportState; - const VkPipelineRasterizationStateCreateInfo* pRasterizationState; - const VkPipelineMultisampleStateCreateInfo* pMultisampleState; - const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; - const VkPipelineColorBlendStateCreateInfo* pColorBlendState; - const VkPipelineDynamicStateCreateInfo* pDynamicState; - VkPipelineLayout layout; - VkRenderPass renderPass; - uint32_t subpass; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkGraphicsPipelineCreateInfo; - -typedef struct VkComputePipelineCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineCreateFlags flags; - VkPipelineShaderStageCreateInfo stage; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkComputePipelineCreateInfo; - -typedef struct VkPushConstantRange { - VkShaderStageFlags stageFlags; - uint32_t offset; - uint32_t size; -} VkPushConstantRange; - -typedef struct VkPipelineLayoutCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineLayoutCreateFlags flags; - uint32_t setLayoutCount; - const VkDescriptorSetLayout* pSetLayouts; - uint32_t pushConstantRangeCount; - const VkPushConstantRange* pPushConstantRanges; -} VkPipelineLayoutCreateInfo; - -typedef struct VkSamplerCreateInfo { - VkStructureType sType; - const void* pNext; - VkSamplerCreateFlags flags; - VkFilter magFilter; - VkFilter minFilter; - VkSamplerMipmapMode mipmapMode; - VkSamplerAddressMode addressModeU; - VkSamplerAddressMode addressModeV; - VkSamplerAddressMode addressModeW; - float mipLodBias; - VkBool32 anisotropyEnable; - float maxAnisotropy; - VkBool32 compareEnable; - VkCompareOp compareOp; - float minLod; - float maxLod; - VkBorderColor borderColor; - VkBool32 unnormalizedCoordinates; -} VkSamplerCreateInfo; - -typedef struct VkDescriptorSetLayoutBinding { - uint32_t binding; - VkDescriptorType descriptorType; - uint32_t descriptorCount; - VkShaderStageFlags stageFlags; - const VkSampler* pImmutableSamplers; -} VkDescriptorSetLayoutBinding; - -typedef struct VkDescriptorSetLayoutCreateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorSetLayoutCreateFlags flags; - uint32_t bindingCount; - const VkDescriptorSetLayoutBinding* pBindings; -} VkDescriptorSetLayoutCreateInfo; - -typedef struct VkDescriptorPoolSize { - VkDescriptorType type; - uint32_t descriptorCount; -} VkDescriptorPoolSize; - -typedef struct VkDescriptorPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorPoolCreateFlags flags; - uint32_t maxSets; - uint32_t poolSizeCount; - const VkDescriptorPoolSize* pPoolSizes; -} VkDescriptorPoolCreateInfo; - -typedef struct VkDescriptorSetAllocateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorPool descriptorPool; - uint32_t descriptorSetCount; - const VkDescriptorSetLayout* pSetLayouts; -} VkDescriptorSetAllocateInfo; - -typedef struct VkDescriptorImageInfo { - VkSampler sampler; - VkImageView imageView; - VkImageLayout imageLayout; -} VkDescriptorImageInfo; - -typedef struct VkDescriptorBufferInfo { - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize range; -} VkDescriptorBufferInfo; - -typedef struct VkWriteDescriptorSet { - VkStructureType sType; - const void* pNext; - VkDescriptorSet dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - const VkDescriptorImageInfo* pImageInfo; - const VkDescriptorBufferInfo* pBufferInfo; - const VkBufferView* pTexelBufferView; -} VkWriteDescriptorSet; - -typedef struct VkCopyDescriptorSet { - VkStructureType sType; - const void* pNext; - VkDescriptorSet srcSet; - uint32_t srcBinding; - uint32_t srcArrayElement; - VkDescriptorSet dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; -} VkCopyDescriptorSet; - -typedef struct VkFramebufferCreateInfo { - VkStructureType sType; - const void* pNext; - VkFramebufferCreateFlags flags; - VkRenderPass renderPass; - uint32_t attachmentCount; - const VkImageView* pAttachments; - uint32_t width; - uint32_t height; - uint32_t layers; -} VkFramebufferCreateInfo; - -typedef struct VkAttachmentDescription { - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription; - -typedef struct VkAttachmentReference { - uint32_t attachment; - VkImageLayout layout; -} VkAttachmentReference; - -typedef struct VkSubpassDescription { - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t inputAttachmentCount; - const VkAttachmentReference* pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference* pColorAttachments; - const VkAttachmentReference* pResolveAttachments; - const VkAttachmentReference* pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t* pPreserveAttachments; -} VkSubpassDescription; - -typedef struct VkSubpassDependency { - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; -} VkSubpassDependency; - -typedef struct VkRenderPassCreateInfo { - VkStructureType sType; - const void* pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription* pAttachments; - uint32_t subpassCount; - const VkSubpassDescription* pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency* pDependencies; -} VkRenderPassCreateInfo; - -typedef struct VkCommandPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkCommandPoolCreateFlags flags; - uint32_t queueFamilyIndex; -} VkCommandPoolCreateInfo; - -typedef struct VkCommandBufferAllocateInfo { - VkStructureType sType; - const void* pNext; - VkCommandPool commandPool; - VkCommandBufferLevel level; - uint32_t commandBufferCount; -} VkCommandBufferAllocateInfo; - -typedef struct VkCommandBufferInheritanceInfo { - VkStructureType sType; - const void* pNext; - VkRenderPass renderPass; - uint32_t subpass; - VkFramebuffer framebuffer; - VkBool32 occlusionQueryEnable; - VkQueryControlFlags queryFlags; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkCommandBufferInheritanceInfo; - -typedef struct VkCommandBufferBeginInfo { - VkStructureType sType; - const void* pNext; - VkCommandBufferUsageFlags flags; - const VkCommandBufferInheritanceInfo* pInheritanceInfo; -} VkCommandBufferBeginInfo; - -typedef struct VkBufferCopy { - VkDeviceSize srcOffset; - VkDeviceSize dstOffset; - VkDeviceSize size; -} VkBufferCopy; - -typedef struct VkImageSubresourceLayers { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceLayers; - -typedef struct VkImageCopy { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageCopy; - -typedef struct VkImageBlit { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffsets[2]; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffsets[2]; -} VkImageBlit; - -typedef struct VkBufferImageCopy { - VkDeviceSize bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy; - -typedef union VkClearColorValue { - float float32[4]; - int32_t int32[4]; - uint32_t uint32[4]; -} VkClearColorValue; - -typedef struct VkClearDepthStencilValue { - float depth; - uint32_t stencil; -} VkClearDepthStencilValue; - -typedef union VkClearValue { - VkClearColorValue color; - VkClearDepthStencilValue depthStencil; -} VkClearValue; - -typedef struct VkClearAttachment { - VkImageAspectFlags aspectMask; - uint32_t colorAttachment; - VkClearValue clearValue; -} VkClearAttachment; - -typedef struct VkClearRect { - VkRect2D rect; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkClearRect; - -typedef struct VkImageResolve { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve; - -typedef struct VkMemoryBarrier { - VkStructureType sType; - const void* pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; -} VkMemoryBarrier; - -typedef struct VkBufferMemoryBarrier { - VkStructureType sType; - const void* pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize size; -} VkBufferMemoryBarrier; - -typedef struct VkImageMemoryBarrier { - VkStructureType sType; - const void* pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier; - -typedef struct VkRenderPassBeginInfo { - VkStructureType sType; - const void* pNext; - VkRenderPass renderPass; - VkFramebuffer framebuffer; - VkRect2D renderArea; - uint32_t clearValueCount; - const VkClearValue* pClearValues; -} VkRenderPassBeginInfo; - -typedef struct VkDispatchIndirectCommand { - uint32_t x; - uint32_t y; - uint32_t z; -} VkDispatchIndirectCommand; - -typedef struct VkDrawIndexedIndirectCommand { - uint32_t indexCount; - uint32_t instanceCount; - uint32_t firstIndex; - int32_t vertexOffset; - uint32_t firstInstance; -} VkDrawIndexedIndirectCommand; - -typedef struct VkDrawIndirectCommand { - uint32_t vertexCount; - uint32_t instanceCount; - uint32_t firstVertex; - uint32_t firstInstance; -} VkDrawIndirectCommand; - -typedef struct VkBaseOutStructure { - VkStructureType sType; - struct VkBaseOutStructure* pNext; -} VkBaseOutStructure; - -typedef struct VkBaseInStructure { - VkStructureType sType; - const struct VkBaseInStructure* pNext; -} VkBaseInStructure; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); -typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); -typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); -typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); -typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); -typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); -typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); -typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); -typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); -typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); -typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); -typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); -typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); -typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); -typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); -typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); -typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); -typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); -typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); -typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); -typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); -typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); -typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); -typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); -typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); -typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); -typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); -typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); -typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); -typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); -typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); -typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); -typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); -typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); -typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); -typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); -typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); -typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); -typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); -typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); -typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); -typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); -typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); -typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); -typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); -typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); -typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); -typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); -typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); -typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); -typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); -typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); -typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( - const VkInstanceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkInstance* pInstance); - -VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( - VkInstance instance, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( - VkInstance instance, - uint32_t* pPhysicalDeviceCount, - VkPhysicalDevice* pPhysicalDevices); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties* pFormatProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags, - VkImageFormatProperties* pImageFormatProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( - VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties* pQueueFamilyProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties* pMemoryProperties); - -VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( - VkInstance instance, - const char* pName); - -VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( - VkDevice device, - const char* pName); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( - VkPhysicalDevice physicalDevice, - const VkDeviceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDevice* pDevice); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( - VkDevice device, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( - const char* pLayerName, - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( - VkPhysicalDevice physicalDevice, - const char* pLayerName, - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( - uint32_t* pPropertyCount, - VkLayerProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkLayerProperties* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( - VkDevice device, - uint32_t queueFamilyIndex, - uint32_t queueIndex, - VkQueue* pQueue); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( - VkQueue queue, - uint32_t submitCount, - const VkSubmitInfo* pSubmits, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( - VkQueue queue); - -VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( - VkDevice device); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( - VkDevice device, - const VkMemoryAllocateInfo* pAllocateInfo, - const VkAllocationCallbacks* pAllocator, - VkDeviceMemory* pMemory); - -VKAPI_ATTR void VKAPI_CALL vkFreeMemory( - VkDevice device, - VkDeviceMemory memory, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - void** ppData); - -VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( - VkDevice device, - VkDeviceMemory memory); - -VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( - VkDevice device, - uint32_t memoryRangeCount, - const VkMappedMemoryRange* pMemoryRanges); - -VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( - VkDevice device, - uint32_t memoryRangeCount, - const VkMappedMemoryRange* pMemoryRanges); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize* pCommittedMemoryInBytes); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( - VkDevice device, - VkBuffer buffer, - VkDeviceMemory memory, - VkDeviceSize memoryOffset); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( - VkDevice device, - VkImage image, - VkDeviceMemory memory, - VkDeviceSize memoryOffset); - -VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( - VkDevice device, - VkBuffer buffer, - VkMemoryRequirements* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( - VkDevice device, - VkImage image, - VkMemoryRequirements* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( - VkDevice device, - VkImage image, - uint32_t* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements* pSparseMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkSampleCountFlagBits samples, - VkImageUsageFlags usage, - VkImageTiling tiling, - uint32_t* pPropertyCount, - VkSparseImageFormatProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( - VkQueue queue, - uint32_t bindInfoCount, - const VkBindSparseInfo* pBindInfo, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( - VkDevice device, - const VkFenceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR void VKAPI_CALL vkDestroyFence( - VkDevice device, - VkFence fence, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( - VkDevice device, - uint32_t fenceCount, - const VkFence* pFences); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( - VkDevice device, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( - VkDevice device, - uint32_t fenceCount, - const VkFence* pFences, - VkBool32 waitAll, - uint64_t timeout); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( - VkDevice device, - const VkSemaphoreCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSemaphore* pSemaphore); - -VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( - VkDevice device, - VkSemaphore semaphore, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( - VkDevice device, - const VkEventCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkEvent* pEvent); - -VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( - VkDevice device, - VkEvent event, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( - VkDevice device, - const VkQueryPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkQueryPool* pQueryPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( - VkDevice device, - VkQueryPool queryPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( - VkDevice device, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - size_t dataSize, - void* pData, - VkDeviceSize stride, - VkQueryResultFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( - VkDevice device, - const VkBufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBuffer* pBuffer); - -VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( - VkDevice device, - VkBuffer buffer, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( - VkDevice device, - const VkBufferViewCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBufferView* pView); - -VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( - VkDevice device, - VkBufferView bufferView, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( - VkDevice device, - const VkImageCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImage* pImage); - -VKAPI_ATTR void VKAPI_CALL vkDestroyImage( - VkDevice device, - VkImage image, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( - VkDevice device, - VkImage image, - const VkImageSubresource* pSubresource, - VkSubresourceLayout* pLayout); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( - VkDevice device, - const VkImageViewCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImageView* pView); - -VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( - VkDevice device, - VkImageView imageView, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( - VkDevice device, - const VkShaderModuleCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkShaderModule* pShaderModule); - -VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( - VkDevice device, - VkShaderModule shaderModule, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( - VkDevice device, - const VkPipelineCacheCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineCache* pPipelineCache); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( - VkDevice device, - VkPipelineCache pipelineCache, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( - VkDevice device, - VkPipelineCache pipelineCache, - size_t* pDataSize, - void* pData); - -VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( - VkDevice device, - VkPipelineCache dstCache, - uint32_t srcCacheCount, - const VkPipelineCache* pSrcCaches); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( - VkDevice device, - VkPipelineCache pipelineCache, - uint32_t createInfoCount, - const VkGraphicsPipelineCreateInfo* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( - VkDevice device, - VkPipelineCache pipelineCache, - uint32_t createInfoCount, - const VkComputePipelineCreateInfo* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( - VkDevice device, - VkPipeline pipeline, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( - VkDevice device, - const VkPipelineLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineLayout* pPipelineLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( - VkDevice device, - VkPipelineLayout pipelineLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( - VkDevice device, - const VkSamplerCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSampler* pSampler); - -VKAPI_ATTR void VKAPI_CALL vkDestroySampler( - VkDevice device, - VkSampler sampler, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorSetLayout* pSetLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( - VkDevice device, - VkDescriptorSetLayout descriptorSetLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( - VkDevice device, - const VkDescriptorPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorPool* pDescriptorPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool, - VkDescriptorPoolResetFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( - VkDevice device, - const VkDescriptorSetAllocateInfo* pAllocateInfo, - VkDescriptorSet* pDescriptorSets); - -VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( - VkDevice device, - VkDescriptorPool descriptorPool, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets); - -VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( - VkDevice device, - uint32_t descriptorWriteCount, - const VkWriteDescriptorSet* pDescriptorWrites, - uint32_t descriptorCopyCount, - const VkCopyDescriptorSet* pDescriptorCopies); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( - VkDevice device, - const VkFramebufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkFramebuffer* pFramebuffer); - -VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( - VkDevice device, - VkFramebuffer framebuffer, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( - VkDevice device, - const VkRenderPassCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkRenderPass* pRenderPass); - -VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( - VkDevice device, - VkRenderPass renderPass, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( - VkDevice device, - VkRenderPass renderPass, - VkExtent2D* pGranularity); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( - VkDevice device, - const VkCommandPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkCommandPool* pCommandPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( - VkDevice device, - VkCommandPool commandPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolResetFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( - VkDevice device, - const VkCommandBufferAllocateInfo* pAllocateInfo, - VkCommandBuffer* pCommandBuffers); - -VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( - VkDevice device, - VkCommandPool commandPool, - uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers); - -VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( - VkCommandBuffer commandBuffer, - const VkCommandBufferBeginInfo* pBeginInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( - VkCommandBuffer commandBuffer, - VkCommandBufferResetFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipeline pipeline); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( - VkCommandBuffer commandBuffer, - uint32_t firstViewport, - uint32_t viewportCount, - const VkViewport* pViewports); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( - VkCommandBuffer commandBuffer, - uint32_t firstScissor, - uint32_t scissorCount, - const VkRect2D* pScissors); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( - VkCommandBuffer commandBuffer, - float lineWidth); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( - VkCommandBuffer commandBuffer, - float depthBiasConstantFactor, - float depthBiasClamp, - float depthBiasSlopeFactor); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( - VkCommandBuffer commandBuffer, - const float blendConstants[4]); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( - VkCommandBuffer commandBuffer, - float minDepthBounds, - float maxDepthBounds); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t compareMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t writeMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t reference); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - uint32_t firstSet, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets, - uint32_t dynamicOffsetCount, - const uint32_t* pDynamicOffsets); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkIndexType indexType); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( - VkCommandBuffer commandBuffer, - uint32_t firstBinding, - uint32_t bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets); - -VKAPI_ATTR void VKAPI_CALL vkCmdDraw( - VkCommandBuffer commandBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( - VkCommandBuffer commandBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( - VkCommandBuffer commandBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( - VkCommandBuffer commandBuffer, - VkBuffer srcBuffer, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageBlit* pRegions, - VkFilter filter); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( - VkCommandBuffer commandBuffer, - VkBuffer srcBuffer, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkBufferImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( - VkCommandBuffer commandBuffer, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void* pData); - -VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( - VkCommandBuffer commandBuffer, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize size, - uint32_t data); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( - VkCommandBuffer commandBuffer, - VkImage image, - VkImageLayout imageLayout, - const VkClearColorValue* pColor, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( - VkCommandBuffer commandBuffer, - VkImage image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue* pDepthStencil, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( - VkCommandBuffer commandBuffer, - uint32_t attachmentCount, - const VkClearAttachment* pAttachments, - uint32_t rectCount, - const VkClearRect* pRects); - -VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageResolve* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( - VkCommandBuffer commandBuffer, - VkEvent event, - VkPipelineStageFlags stageMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( - VkCommandBuffer commandBuffer, - VkEvent event, - VkPipelineStageFlags stageMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents( - VkCommandBuffer commandBuffer, - uint32_t eventCount, - const VkEvent* pEvents, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers); - -VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier( - VkCommandBuffer commandBuffer, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t query, - VkQueryControlFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t query); - -VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount); - -VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( - VkCommandBuffer commandBuffer, - VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - uint32_t query); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize stride, - VkQueryResultFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( - VkCommandBuffer commandBuffer, - VkPipelineLayout layout, - VkShaderStageFlags stageFlags, - uint32_t offset, - uint32_t size, - const void* pValues); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( - VkCommandBuffer commandBuffer, - const VkRenderPassBeginInfo* pRenderPassBegin, - VkSubpassContents contents); - -VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( - VkCommandBuffer commandBuffer, - VkSubpassContents contents); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( - VkCommandBuffer commandBuffer, - uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers); -#endif - - -#define VK_VERSION_1_1 1 -// Vulkan 1.1 version number -#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)// Patch version should always be set to 0 - -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) -#define VK_MAX_DEVICE_GROUP_SIZE 32 -#define VK_LUID_SIZE 8 -#define VK_QUEUE_FAMILY_EXTERNAL (~0U-1) - -typedef enum VkPointClippingBehavior { - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, - VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - VK_POINT_CLIPPING_BEHAVIOR_END_RANGE = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, - VK_POINT_CLIPPING_BEHAVIOR_RANGE_SIZE = (VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES + 1), - VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF -} VkPointClippingBehavior; - -typedef enum VkTessellationDomainOrigin { - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_BEGIN_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_END_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_RANGE_SIZE = (VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT + 1), - VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF -} VkTessellationDomainOrigin; - -typedef enum VkSamplerYcbcrModelConversion { - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_BEGIN_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_END_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RANGE_SIZE = (VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY + 1), - VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF -} VkSamplerYcbcrModelConversion; - -typedef enum VkSamplerYcbcrRange { - VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, - VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, - VK_SAMPLER_YCBCR_RANGE_BEGIN_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, - VK_SAMPLER_YCBCR_RANGE_END_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, - VK_SAMPLER_YCBCR_RANGE_RANGE_SIZE = (VK_SAMPLER_YCBCR_RANGE_ITU_NARROW - VK_SAMPLER_YCBCR_RANGE_ITU_FULL + 1), - VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF -} VkSamplerYcbcrRange; - -typedef enum VkChromaLocation { - VK_CHROMA_LOCATION_COSITED_EVEN = 0, - VK_CHROMA_LOCATION_MIDPOINT = 1, - VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, - VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, - VK_CHROMA_LOCATION_BEGIN_RANGE = VK_CHROMA_LOCATION_COSITED_EVEN, - VK_CHROMA_LOCATION_END_RANGE = VK_CHROMA_LOCATION_MIDPOINT, - VK_CHROMA_LOCATION_RANGE_SIZE = (VK_CHROMA_LOCATION_MIDPOINT - VK_CHROMA_LOCATION_COSITED_EVEN + 1), - VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF -} VkChromaLocation; - -typedef enum VkDescriptorUpdateTemplateType { - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET + 1), - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorUpdateTemplateType; - -typedef enum VkSubgroupFeatureFlagBits { - VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, - VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, - VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, - VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, - VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, - VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, - VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, - VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, - VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, - VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSubgroupFeatureFlagBits; -typedef VkFlags VkSubgroupFeatureFlags; - -typedef enum VkPeerMemoryFeatureFlagBits { - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT, - VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkPeerMemoryFeatureFlagBits; -typedef VkFlags VkPeerMemoryFeatureFlags; - -typedef enum VkMemoryAllocateFlagBits { - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, - VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkMemoryAllocateFlagBits; -typedef VkFlags VkMemoryAllocateFlags; -typedef VkFlags VkCommandPoolTrimFlags; -typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; - -typedef enum VkExternalMemoryHandleTypeFlagBits { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 0x00000400, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalMemoryHandleTypeFlagBits; -typedef VkFlags VkExternalMemoryHandleTypeFlags; - -typedef enum VkExternalMemoryFeatureFlagBits { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalMemoryFeatureFlagBits; -typedef VkFlags VkExternalMemoryFeatureFlags; - -typedef enum VkExternalFenceHandleTypeFlagBits { - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalFenceHandleTypeFlagBits; -typedef VkFlags VkExternalFenceHandleTypeFlags; - -typedef enum VkExternalFenceFeatureFlagBits { - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalFenceFeatureFlagBits; -typedef VkFlags VkExternalFenceFeatureFlags; - -typedef enum VkFenceImportFlagBits { - VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, - VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT, - VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFenceImportFlagBits; -typedef VkFlags VkFenceImportFlags; - -typedef enum VkSemaphoreImportFlagBits { - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, - VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSemaphoreImportFlagBits; -typedef VkFlags VkSemaphoreImportFlags; - -typedef enum VkExternalSemaphoreHandleTypeFlagBits { - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalSemaphoreHandleTypeFlagBits; -typedef VkFlags VkExternalSemaphoreHandleTypeFlags; - -typedef enum VkExternalSemaphoreFeatureFlagBits { - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalSemaphoreFeatureFlagBits; -typedef VkFlags VkExternalSemaphoreFeatureFlags; -typedef struct VkPhysicalDeviceSubgroupProperties { - VkStructureType sType; - void* pNext; - uint32_t subgroupSize; - VkShaderStageFlags supportedStages; - VkSubgroupFeatureFlags supportedOperations; - VkBool32 quadOperationsInAllStages; -} VkPhysicalDeviceSubgroupProperties; - -typedef struct VkBindBufferMemoryInfo { - VkStructureType sType; - const void* pNext; - VkBuffer buffer; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; -} VkBindBufferMemoryInfo; - -typedef struct VkBindImageMemoryInfo { - VkStructureType sType; - const void* pNext; - VkImage image; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; -} VkBindImageMemoryInfo; - -typedef struct VkPhysicalDevice16BitStorageFeatures { - VkStructureType sType; - void* pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; -} VkPhysicalDevice16BitStorageFeatures; - -typedef struct VkMemoryDedicatedRequirements { - VkStructureType sType; - void* pNext; - VkBool32 prefersDedicatedAllocation; - VkBool32 requiresDedicatedAllocation; -} VkMemoryDedicatedRequirements; - -typedef struct VkMemoryDedicatedAllocateInfo { - VkStructureType sType; - const void* pNext; - VkImage image; - VkBuffer buffer; -} VkMemoryDedicatedAllocateInfo; - -typedef struct VkMemoryAllocateFlagsInfo { - VkStructureType sType; - const void* pNext; - VkMemoryAllocateFlags flags; - uint32_t deviceMask; -} VkMemoryAllocateFlagsInfo; - -typedef struct VkDeviceGroupRenderPassBeginInfo { - VkStructureType sType; - const void* pNext; - uint32_t deviceMask; - uint32_t deviceRenderAreaCount; - const VkRect2D* pDeviceRenderAreas; -} VkDeviceGroupRenderPassBeginInfo; - -typedef struct VkDeviceGroupCommandBufferBeginInfo { - VkStructureType sType; - const void* pNext; - uint32_t deviceMask; -} VkDeviceGroupCommandBufferBeginInfo; - -typedef struct VkDeviceGroupSubmitInfo { - VkStructureType sType; - const void* pNext; - uint32_t waitSemaphoreCount; - const uint32_t* pWaitSemaphoreDeviceIndices; - uint32_t commandBufferCount; - const uint32_t* pCommandBufferDeviceMasks; - uint32_t signalSemaphoreCount; - const uint32_t* pSignalSemaphoreDeviceIndices; -} VkDeviceGroupSubmitInfo; - -typedef struct VkDeviceGroupBindSparseInfo { - VkStructureType sType; - const void* pNext; - uint32_t resourceDeviceIndex; - uint32_t memoryDeviceIndex; -} VkDeviceGroupBindSparseInfo; - -typedef struct VkBindBufferMemoryDeviceGroupInfo { - VkStructureType sType; - const void* pNext; - uint32_t deviceIndexCount; - const uint32_t* pDeviceIndices; -} VkBindBufferMemoryDeviceGroupInfo; - -typedef struct VkBindImageMemoryDeviceGroupInfo { - VkStructureType sType; - const void* pNext; - uint32_t deviceIndexCount; - const uint32_t* pDeviceIndices; - uint32_t splitInstanceBindRegionCount; - const VkRect2D* pSplitInstanceBindRegions; -} VkBindImageMemoryDeviceGroupInfo; - -typedef struct VkPhysicalDeviceGroupProperties { - VkStructureType sType; - void* pNext; - uint32_t physicalDeviceCount; - VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; - VkBool32 subsetAllocation; -} VkPhysicalDeviceGroupProperties; - -typedef struct VkDeviceGroupDeviceCreateInfo { - VkStructureType sType; - const void* pNext; - uint32_t physicalDeviceCount; - const VkPhysicalDevice* pPhysicalDevices; -} VkDeviceGroupDeviceCreateInfo; - -typedef struct VkBufferMemoryRequirementsInfo2 { - VkStructureType sType; - const void* pNext; - VkBuffer buffer; -} VkBufferMemoryRequirementsInfo2; - -typedef struct VkImageMemoryRequirementsInfo2 { - VkStructureType sType; - const void* pNext; - VkImage image; -} VkImageMemoryRequirementsInfo2; - -typedef struct VkImageSparseMemoryRequirementsInfo2 { - VkStructureType sType; - const void* pNext; - VkImage image; -} VkImageSparseMemoryRequirementsInfo2; - -typedef struct VkMemoryRequirements2 { - VkStructureType sType; - void* pNext; - VkMemoryRequirements memoryRequirements; -} VkMemoryRequirements2; - -typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; - -typedef struct VkSparseImageMemoryRequirements2 { - VkStructureType sType; - void* pNext; - VkSparseImageMemoryRequirements memoryRequirements; -} VkSparseImageMemoryRequirements2; - -typedef struct VkPhysicalDeviceFeatures2 { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceFeatures features; -} VkPhysicalDeviceFeatures2; - -typedef struct VkPhysicalDeviceProperties2 { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceProperties properties; -} VkPhysicalDeviceProperties2; - -typedef struct VkFormatProperties2 { - VkStructureType sType; - void* pNext; - VkFormatProperties formatProperties; -} VkFormatProperties2; - -typedef struct VkImageFormatProperties2 { - VkStructureType sType; - void* pNext; - VkImageFormatProperties imageFormatProperties; -} VkImageFormatProperties2; - -typedef struct VkPhysicalDeviceImageFormatInfo2 { - VkStructureType sType; - const void* pNext; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; -} VkPhysicalDeviceImageFormatInfo2; - -typedef struct VkQueueFamilyProperties2 { - VkStructureType sType; - void* pNext; - VkQueueFamilyProperties queueFamilyProperties; -} VkQueueFamilyProperties2; - -typedef struct VkPhysicalDeviceMemoryProperties2 { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceMemoryProperties memoryProperties; -} VkPhysicalDeviceMemoryProperties2; - -typedef struct VkSparseImageFormatProperties2 { - VkStructureType sType; - void* pNext; - VkSparseImageFormatProperties properties; -} VkSparseImageFormatProperties2; - -typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { - VkStructureType sType; - const void* pNext; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; -} VkPhysicalDeviceSparseImageFormatInfo2; - -typedef struct VkPhysicalDevicePointClippingProperties { - VkStructureType sType; - void* pNext; - VkPointClippingBehavior pointClippingBehavior; -} VkPhysicalDevicePointClippingProperties; - -typedef struct VkInputAttachmentAspectReference { - uint32_t subpass; - uint32_t inputAttachmentIndex; - VkImageAspectFlags aspectMask; -} VkInputAttachmentAspectReference; - -typedef struct VkRenderPassInputAttachmentAspectCreateInfo { - VkStructureType sType; - const void* pNext; - uint32_t aspectReferenceCount; - const VkInputAttachmentAspectReference* pAspectReferences; -} VkRenderPassInputAttachmentAspectCreateInfo; - -typedef struct VkImageViewUsageCreateInfo { - VkStructureType sType; - const void* pNext; - VkImageUsageFlags usage; -} VkImageViewUsageCreateInfo; - -typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkTessellationDomainOrigin domainOrigin; -} VkPipelineTessellationDomainOriginStateCreateInfo; - -typedef struct VkRenderPassMultiviewCreateInfo { - VkStructureType sType; - const void* pNext; - uint32_t subpassCount; - const uint32_t* pViewMasks; - uint32_t dependencyCount; - const int32_t* pViewOffsets; - uint32_t correlationMaskCount; - const uint32_t* pCorrelationMasks; -} VkRenderPassMultiviewCreateInfo; - -typedef struct VkPhysicalDeviceMultiviewFeatures { - VkStructureType sType; - void* pNext; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; -} VkPhysicalDeviceMultiviewFeatures; - -typedef struct VkPhysicalDeviceMultiviewProperties { - VkStructureType sType; - void* pNext; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; -} VkPhysicalDeviceMultiviewProperties; - -typedef struct VkPhysicalDeviceVariablePointersFeatures { - VkStructureType sType; - void* pNext; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; -} VkPhysicalDeviceVariablePointersFeatures; - -typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; - -typedef struct VkPhysicalDeviceProtectedMemoryFeatures { - VkStructureType sType; - void* pNext; - VkBool32 protectedMemory; -} VkPhysicalDeviceProtectedMemoryFeatures; - -typedef struct VkPhysicalDeviceProtectedMemoryProperties { - VkStructureType sType; - void* pNext; - VkBool32 protectedNoFault; -} VkPhysicalDeviceProtectedMemoryProperties; - -typedef struct VkDeviceQueueInfo2 { - VkStructureType sType; - const void* pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueIndex; -} VkDeviceQueueInfo2; - -typedef struct VkProtectedSubmitInfo { - VkStructureType sType; - const void* pNext; - VkBool32 protectedSubmit; -} VkProtectedSubmitInfo; - -typedef struct VkSamplerYcbcrConversionCreateInfo { - VkStructureType sType; - const void* pNext; - VkFormat format; - VkSamplerYcbcrModelConversion ycbcrModel; - VkSamplerYcbcrRange ycbcrRange; - VkComponentMapping components; - VkChromaLocation xChromaOffset; - VkChromaLocation yChromaOffset; - VkFilter chromaFilter; - VkBool32 forceExplicitReconstruction; -} VkSamplerYcbcrConversionCreateInfo; - -typedef struct VkSamplerYcbcrConversionInfo { - VkStructureType sType; - const void* pNext; - VkSamplerYcbcrConversion conversion; -} VkSamplerYcbcrConversionInfo; - -typedef struct VkBindImagePlaneMemoryInfo { - VkStructureType sType; - const void* pNext; - VkImageAspectFlagBits planeAspect; -} VkBindImagePlaneMemoryInfo; - -typedef struct VkImagePlaneMemoryRequirementsInfo { - VkStructureType sType; - const void* pNext; - VkImageAspectFlagBits planeAspect; -} VkImagePlaneMemoryRequirementsInfo; - -typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { - VkStructureType sType; - void* pNext; - VkBool32 samplerYcbcrConversion; -} VkPhysicalDeviceSamplerYcbcrConversionFeatures; - -typedef struct VkSamplerYcbcrConversionImageFormatProperties { - VkStructureType sType; - void* pNext; - uint32_t combinedImageSamplerDescriptorCount; -} VkSamplerYcbcrConversionImageFormatProperties; - -typedef struct VkDescriptorUpdateTemplateEntry { - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - size_t offset; - size_t stride; -} VkDescriptorUpdateTemplateEntry; - -typedef struct VkDescriptorUpdateTemplateCreateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorUpdateTemplateCreateFlags flags; - uint32_t descriptorUpdateEntryCount; - const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries; - VkDescriptorUpdateTemplateType templateType; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout pipelineLayout; - uint32_t set; -} VkDescriptorUpdateTemplateCreateInfo; - -typedef struct VkExternalMemoryProperties { - VkExternalMemoryFeatureFlags externalMemoryFeatures; - VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlags compatibleHandleTypes; -} VkExternalMemoryProperties; - -typedef struct VkPhysicalDeviceExternalImageFormatInfo { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalImageFormatInfo; - -typedef struct VkExternalImageFormatProperties { - VkStructureType sType; - void* pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalImageFormatProperties; - -typedef struct VkPhysicalDeviceExternalBufferInfo { - VkStructureType sType; - const void* pNext; - VkBufferCreateFlags flags; - VkBufferUsageFlags usage; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalBufferInfo; - -typedef struct VkExternalBufferProperties { - VkStructureType sType; - void* pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalBufferProperties; - -typedef struct VkPhysicalDeviceIDProperties { - VkStructureType sType; - void* pNext; - uint8_t deviceUUID[VK_UUID_SIZE]; - uint8_t driverUUID[VK_UUID_SIZE]; - uint8_t deviceLUID[VK_LUID_SIZE]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; -} VkPhysicalDeviceIDProperties; - -typedef struct VkExternalMemoryImageCreateInfo { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryImageCreateInfo; - -typedef struct VkExternalMemoryBufferCreateInfo { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryBufferCreateInfo; - -typedef struct VkExportMemoryAllocateInfo { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExportMemoryAllocateInfo; - -typedef struct VkPhysicalDeviceExternalFenceInfo { - VkStructureType sType; - const void* pNext; - VkExternalFenceHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalFenceInfo; - -typedef struct VkExternalFenceProperties { - VkStructureType sType; - void* pNext; - VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; - VkExternalFenceHandleTypeFlags compatibleHandleTypes; - VkExternalFenceFeatureFlags externalFenceFeatures; -} VkExternalFenceProperties; - -typedef struct VkExportFenceCreateInfo { - VkStructureType sType; - const void* pNext; - VkExternalFenceHandleTypeFlags handleTypes; -} VkExportFenceCreateInfo; - -typedef struct VkExportSemaphoreCreateInfo { - VkStructureType sType; - const void* pNext; - VkExternalSemaphoreHandleTypeFlags handleTypes; -} VkExportSemaphoreCreateInfo; - -typedef struct VkPhysicalDeviceExternalSemaphoreInfo { - VkStructureType sType; - const void* pNext; - VkExternalSemaphoreHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalSemaphoreInfo; - -typedef struct VkExternalSemaphoreProperties { - VkStructureType sType; - void* pNext; - VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; - VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; - VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; -} VkExternalSemaphoreProperties; - -typedef struct VkPhysicalDeviceMaintenance3Properties { - VkStructureType sType; - void* pNext; - uint32_t maxPerSetDescriptors; - VkDeviceSize maxMemoryAllocationSize; -} VkPhysicalDeviceMaintenance3Properties; - -typedef struct VkDescriptorSetLayoutSupport { - VkStructureType sType; - void* pNext; - VkBool32 supported; -} VkDescriptorSetLayoutSupport; - -typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { - VkStructureType sType; - void* pNext; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceShaderDrawParametersFeatures; - -typedef VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; - -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t* pApiVersion); -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); -typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); -typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); -typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); -typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); -typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion( - uint32_t* pApiVersion); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2( - VkDevice device, - uint32_t bindInfoCount, - const VkBindBufferMemoryInfo* pBindInfos); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2( - VkDevice device, - uint32_t bindInfoCount, - const VkBindImageMemoryInfo* pBindInfos); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures( - VkDevice device, - uint32_t heapIndex, - uint32_t localDeviceIndex, - uint32_t remoteDeviceIndex, - VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask( - VkCommandBuffer commandBuffer, - uint32_t deviceMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBase( - VkCommandBuffer commandBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( - VkInstance instance, - uint32_t* pPhysicalDeviceGroupCount, - VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2( - VkDevice device, - const VkImageMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2( - VkDevice device, - const VkBufferMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2( - VkDevice device, - const VkImageSparseMemoryRequirementsInfo2* pInfo, - uint32_t* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties2* pFormatProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, - VkImageFormatProperties2* pImageFormatProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2( - VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties2* pQueueFamilyProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2* pMemoryProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, - uint32_t* pPropertyCount, - VkSparseImageFormatProperties2* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolTrimFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2( - VkDevice device, - const VkDeviceQueueInfo2* pQueueInfo, - VkQueue* pQueue); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion( - VkDevice device, - const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSamplerYcbcrConversion* pYcbcrConversion); - -VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversion( - VkDevice device, - VkSamplerYcbcrConversion ycbcrConversion, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate( - VkDevice device, - const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplate( - VkDevice device, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplate( - VkDevice device, - VkDescriptorSet descriptorSet, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const void* pData); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, - VkExternalBufferProperties* pExternalBufferProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, - VkExternalFenceProperties* pExternalFenceProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, - VkExternalSemaphoreProperties* pExternalSemaphoreProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - VkDescriptorSetLayoutSupport* pSupport); -#endif - - -#define VK_KHR_surface 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) -#define VK_KHR_SURFACE_SPEC_VERSION 25 -#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" - -typedef enum VkColorSpaceKHR { - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, - VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, - VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104003, - VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, - VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, - VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, - VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, - VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, - VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, - VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010, - VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, - VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, - VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, - VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, - VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, - VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, - VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1), - VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkColorSpaceKHR; - -typedef enum VkPresentModeKHR { - VK_PRESENT_MODE_IMMEDIATE_KHR = 0, - VK_PRESENT_MODE_MAILBOX_KHR = 1, - VK_PRESENT_MODE_FIFO_KHR = 2, - VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, - VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, - VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, - VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), - VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkPresentModeKHR; - -typedef enum VkSurfaceTransformFlagBitsKHR { - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, - VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, - VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, - VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, - VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, - VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSurfaceTransformFlagBitsKHR; -typedef VkFlags VkSurfaceTransformFlagsKHR; - -typedef enum VkCompositeAlphaFlagBitsKHR { - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, - VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkCompositeAlphaFlagBitsKHR; -typedef VkFlags VkCompositeAlphaFlagsKHR; -typedef struct VkSurfaceCapabilitiesKHR { - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; -} VkSurfaceCapabilitiesKHR; - -typedef struct VkSurfaceFormatKHR { - VkFormat format; - VkColorSpaceKHR colorSpace; -} VkSurfaceFormatKHR; - -typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( - VkInstance instance, - VkSurfaceKHR surface, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - VkSurfaceKHR surface, - VkBool32* pSupported); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pSurfaceFormatCount, - VkSurfaceFormatKHR* pSurfaceFormats); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pPresentModeCount, - VkPresentModeKHR* pPresentModes); -#endif - - -#define VK_KHR_swapchain 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) -#define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 -#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" - -typedef enum VkSwapchainCreateFlagBitsKHR { - VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001, - VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, - VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 0x00000004, - VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSwapchainCreateFlagBitsKHR; -typedef VkFlags VkSwapchainCreateFlagsKHR; - -typedef enum VkDeviceGroupPresentModeFlagBitsKHR { - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, - VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, - VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, - VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkDeviceGroupPresentModeFlagBitsKHR; -typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; -typedef struct VkSwapchainCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkSwapchainCreateFlagsKHR flags; - VkSurfaceKHR surface; - uint32_t minImageCount; - VkFormat imageFormat; - VkColorSpaceKHR imageColorSpace; - VkExtent2D imageExtent; - uint32_t imageArrayLayers; - VkImageUsageFlags imageUsage; - VkSharingMode imageSharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t* pQueueFamilyIndices; - VkSurfaceTransformFlagBitsKHR preTransform; - VkCompositeAlphaFlagBitsKHR compositeAlpha; - VkPresentModeKHR presentMode; - VkBool32 clipped; - VkSwapchainKHR oldSwapchain; -} VkSwapchainCreateInfoKHR; - -typedef struct VkPresentInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore* pWaitSemaphores; - uint32_t swapchainCount; - const VkSwapchainKHR* pSwapchains; - const uint32_t* pImageIndices; - VkResult* pResults; -} VkPresentInfoKHR; - -typedef struct VkImageSwapchainCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkSwapchainKHR swapchain; -} VkImageSwapchainCreateInfoKHR; - -typedef struct VkBindImageMemorySwapchainInfoKHR { - VkStructureType sType; - const void* pNext; - VkSwapchainKHR swapchain; - uint32_t imageIndex; -} VkBindImageMemorySwapchainInfoKHR; - -typedef struct VkAcquireNextImageInfoKHR { - VkStructureType sType; - const void* pNext; - VkSwapchainKHR swapchain; - uint64_t timeout; - VkSemaphore semaphore; - VkFence fence; - uint32_t deviceMask; -} VkAcquireNextImageInfoKHR; - -typedef struct VkDeviceGroupPresentCapabilitiesKHR { - VkStructureType sType; - const void* pNext; - uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE]; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupPresentCapabilitiesKHR; - -typedef struct VkDeviceGroupPresentInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t swapchainCount; - const uint32_t* pDeviceMasks; - VkDeviceGroupPresentModeFlagBitsKHR mode; -} VkDeviceGroupPresentInfoKHR; - -typedef struct VkDeviceGroupSwapchainCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupSwapchainCreateInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); -typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); -typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); -typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); -typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( - VkDevice device, - const VkSwapchainCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSwapchainKHR* pSwapchain); - -VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( - VkDevice device, - VkSwapchainKHR swapchain, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( - VkDevice device, - VkSwapchainKHR swapchain, - uint32_t* pSwapchainImageCount, - VkImage* pSwapchainImages); - -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( - VkDevice device, - VkSwapchainKHR swapchain, - uint64_t timeout, - VkSemaphore semaphore, - VkFence fence, - uint32_t* pImageIndex); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( - VkQueue queue, - const VkPresentInfoKHR* pPresentInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR( - VkDevice device, - VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR( - VkDevice device, - VkSurfaceKHR surface, - VkDeviceGroupPresentModeFlagsKHR* pModes); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pRectCount, - VkRect2D* pRects); - -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR( - VkDevice device, - const VkAcquireNextImageInfoKHR* pAcquireInfo, - uint32_t* pImageIndex); -#endif - - -#define VK_KHR_display 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) -#define VK_KHR_DISPLAY_SPEC_VERSION 21 -#define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" - -typedef enum VkDisplayPlaneAlphaFlagBitsKHR { - VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, - VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkDisplayPlaneAlphaFlagBitsKHR; -typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; -typedef VkFlags VkDisplayModeCreateFlagsKHR; -typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; -typedef struct VkDisplayPropertiesKHR { - VkDisplayKHR display; - const char* displayName; - VkExtent2D physicalDimensions; - VkExtent2D physicalResolution; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkBool32 planeReorderPossible; - VkBool32 persistentContent; -} VkDisplayPropertiesKHR; - -typedef struct VkDisplayModeParametersKHR { - VkExtent2D visibleRegion; - uint32_t refreshRate; -} VkDisplayModeParametersKHR; - -typedef struct VkDisplayModePropertiesKHR { - VkDisplayModeKHR displayMode; - VkDisplayModeParametersKHR parameters; -} VkDisplayModePropertiesKHR; - -typedef struct VkDisplayModeCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkDisplayModeCreateFlagsKHR flags; - VkDisplayModeParametersKHR parameters; -} VkDisplayModeCreateInfoKHR; - -typedef struct VkDisplayPlaneCapabilitiesKHR { - VkDisplayPlaneAlphaFlagsKHR supportedAlpha; - VkOffset2D minSrcPosition; - VkOffset2D maxSrcPosition; - VkExtent2D minSrcExtent; - VkExtent2D maxSrcExtent; - VkOffset2D minDstPosition; - VkOffset2D maxDstPosition; - VkExtent2D minDstExtent; - VkExtent2D maxDstExtent; -} VkDisplayPlaneCapabilitiesKHR; - -typedef struct VkDisplayPlanePropertiesKHR { - VkDisplayKHR currentDisplay; - uint32_t currentStackIndex; -} VkDisplayPlanePropertiesKHR; - -typedef struct VkDisplaySurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkDisplaySurfaceCreateFlagsKHR flags; - VkDisplayModeKHR displayMode; - uint32_t planeIndex; - uint32_t planeStackIndex; - VkSurfaceTransformFlagBitsKHR transform; - float globalAlpha; - VkDisplayPlaneAlphaFlagBitsKHR alphaMode; - VkExtent2D imageExtent; -} VkDisplaySurfaceCreateInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkDisplayPropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkDisplayPlanePropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( - VkPhysicalDevice physicalDevice, - uint32_t planeIndex, - uint32_t* pDisplayCount, - VkDisplayKHR* pDisplays); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - uint32_t* pPropertyCount, - VkDisplayModePropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - const VkDisplayModeCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDisplayModeKHR* pMode); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkDisplayModeKHR mode, - uint32_t planeIndex, - VkDisplayPlaneCapabilitiesKHR* pCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( - VkInstance instance, - const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - - -#define VK_KHR_display_swapchain 1 -#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9 -#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" -typedef struct VkDisplayPresentInfoKHR { - VkStructureType sType; - const void* pNext; - VkRect2D srcRect; - VkRect2D dstRect; - VkBool32 persistent; -} VkDisplayPresentInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( - VkDevice device, - uint32_t swapchainCount, - const VkSwapchainCreateInfoKHR* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkSwapchainKHR* pSwapchains); -#endif - - -#define VK_KHR_sampler_mirror_clamp_to_edge 1 -#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 -#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" - - -#define VK_KHR_multiview 1 -#define VK_KHR_MULTIVIEW_SPEC_VERSION 1 -#define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" -typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR; - -typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; - -typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR; - - - -#define VK_KHR_get_physical_device_properties2 1 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" -typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; - -typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR; - -typedef VkFormatProperties2 VkFormatProperties2KHR; - -typedef VkImageFormatProperties2 VkImageFormatProperties2KHR; - -typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; - -typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; - -typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR; - -typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; - -typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties2* pFormatProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, - VkImageFormatProperties2* pImageFormatProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( - VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties2* pQueueFamilyProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2* pMemoryProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, - uint32_t* pPropertyCount, - VkSparseImageFormatProperties2* pProperties); -#endif - - -#define VK_KHR_device_group 1 -#define VK_KHR_DEVICE_GROUP_SPEC_VERSION 3 -#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" -typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR; - -typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; - -typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR; - -typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; - -typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; - -typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR; - -typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR; - -typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR; - -typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR; - -typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR; - -typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR; - -typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); -typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR( - VkDevice device, - uint32_t heapIndex, - uint32_t localDeviceIndex, - uint32_t remoteDeviceIndex, - VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHR( - VkCommandBuffer commandBuffer, - uint32_t deviceMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR( - VkCommandBuffer commandBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); -#endif - - -#define VK_KHR_shader_draw_parameters 1 -#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 -#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" - - -#define VK_KHR_maintenance1 1 -#define VK_KHR_MAINTENANCE1_SPEC_VERSION 2 -#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" -typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; - -typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolTrimFlags flags); -#endif - - -#define VK_KHR_device_group_creation 1 -#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 -#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" -#define VK_MAX_DEVICE_GROUP_SIZE_KHR VK_MAX_DEVICE_GROUP_SIZE -typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; - -typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR( - VkInstance instance, - uint32_t* pPhysicalDeviceGroupCount, - VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); -#endif - - -#define VK_KHR_external_memory_capabilities 1 -#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" -#define VK_LUID_SIZE_KHR VK_LUID_SIZE -typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR; - -typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; - -typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR; - -typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; - -typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; - -typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR; - -typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; - -typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; - -typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR; - -typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, - VkExternalBufferProperties* pExternalBufferProperties); -#endif - - -#define VK_KHR_external_memory 1 -#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory" -#define VK_QUEUE_FAMILY_EXTERNAL_KHR VK_QUEUE_FAMILY_EXTERNAL -typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; - -typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; - -typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; - - - -#define VK_KHR_external_memory_fd 1 -#define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd" -typedef struct VkImportMemoryFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBits handleType; - int fd; -} VkImportMemoryFdInfoKHR; - -typedef struct VkMemoryFdPropertiesKHR { - VkStructureType sType; - void* pNext; - uint32_t memoryTypeBits; -} VkMemoryFdPropertiesKHR; - -typedef struct VkMemoryGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkDeviceMemory memory; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkMemoryGetFdInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd); -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR( - VkDevice device, - const VkMemoryGetFdInfoKHR* pGetFdInfo, - int* pFd); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR( - VkDevice device, - VkExternalMemoryHandleTypeFlagBits handleType, - int fd, - VkMemoryFdPropertiesKHR* pMemoryFdProperties); -#endif - - -#define VK_KHR_external_semaphore_capabilities 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" -typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR; - -typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; - -typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR; - -typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; - -typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR; - -typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, - VkExternalSemaphoreProperties* pExternalSemaphoreProperties); -#endif - - -#define VK_KHR_external_semaphore 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore" -typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR; - -typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; - -typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; - - - -#define VK_KHR_external_semaphore_fd 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd" -typedef struct VkImportSemaphoreFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - VkSemaphoreImportFlags flags; - VkExternalSemaphoreHandleTypeFlagBits handleType; - int fd; -} VkImportSemaphoreFdInfoKHR; - -typedef struct VkSemaphoreGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - VkExternalSemaphoreHandleTypeFlagBits handleType; -} VkSemaphoreGetFdInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); -typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHR( - VkDevice device, - const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR( - VkDevice device, - const VkSemaphoreGetFdInfoKHR* pGetFdInfo, - int* pFd); -#endif - - -#define VK_KHR_push_descriptor 1 -#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 -#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" -typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR { - VkStructureType sType; - void* pNext; - uint32_t maxPushDescriptors; -} VkPhysicalDevicePushDescriptorPropertiesKHR; - -typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites); -typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - uint32_t set, - uint32_t descriptorWriteCount, - const VkWriteDescriptorSet* pDescriptorWrites); - -VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( - VkCommandBuffer commandBuffer, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - VkPipelineLayout layout, - uint32_t set, - const void* pData); -#endif - - -#define VK_KHR_shader_float16_int8 1 -#define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 -#define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" -typedef struct VkPhysicalDeviceFloat16Int8FeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; -} VkPhysicalDeviceFloat16Int8FeaturesKHR; - - - -#define VK_KHR_16bit_storage 1 -#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 -#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" -typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; - - - -#define VK_KHR_incremental_present 1 -#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1 -#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" -typedef struct VkRectLayerKHR { - VkOffset2D offset; - VkExtent2D extent; - uint32_t layer; -} VkRectLayerKHR; - -typedef struct VkPresentRegionKHR { - uint32_t rectangleCount; - const VkRectLayerKHR* pRectangles; -} VkPresentRegionKHR; - -typedef struct VkPresentRegionsKHR { - VkStructureType sType; - const void* pNext; - uint32_t swapchainCount; - const VkPresentRegionKHR* pRegions; -} VkPresentRegionsKHR; - - - -#define VK_KHR_descriptor_update_template 1 -typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR; - -#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 -#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" -typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; - -typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR; - -typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR; - -typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR( - VkDevice device, - const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR( - VkDevice device, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR( - VkDevice device, - VkDescriptorSet descriptorSet, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const void* pData); -#endif - - -#define VK_KHR_imageless_framebuffer 1 -#define VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION 1 -#define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME "VK_KHR_imageless_framebuffer" -typedef struct VkPhysicalDeviceImagelessFramebufferFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 imagelessFramebuffer; -} VkPhysicalDeviceImagelessFramebufferFeaturesKHR; - -typedef struct VkFramebufferAttachmentImageInfoKHR { - VkStructureType sType; - const void* pNext; - VkImageCreateFlags flags; - VkImageUsageFlags usage; - uint32_t width; - uint32_t height; - uint32_t layerCount; - uint32_t viewFormatCount; - const VkFormat* pViewFormats; -} VkFramebufferAttachmentImageInfoKHR; - -typedef struct VkFramebufferAttachmentsCreateInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t attachmentImageInfoCount; - const VkFramebufferAttachmentImageInfoKHR* pAttachmentImageInfos; -} VkFramebufferAttachmentsCreateInfoKHR; - -typedef struct VkRenderPassAttachmentBeginInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t attachmentCount; - const VkImageView* pAttachments; -} VkRenderPassAttachmentBeginInfoKHR; - - - -#define VK_KHR_create_renderpass2 1 -#define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 -#define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" -typedef struct VkAttachmentDescription2KHR { - VkStructureType sType; - const void* pNext; - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription2KHR; - -typedef struct VkAttachmentReference2KHR { - VkStructureType sType; - const void* pNext; - uint32_t attachment; - VkImageLayout layout; - VkImageAspectFlags aspectMask; -} VkAttachmentReference2KHR; - -typedef struct VkSubpassDescription2KHR { - VkStructureType sType; - const void* pNext; - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t viewMask; - uint32_t inputAttachmentCount; - const VkAttachmentReference2KHR* pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference2KHR* pColorAttachments; - const VkAttachmentReference2KHR* pResolveAttachments; - const VkAttachmentReference2KHR* pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t* pPreserveAttachments; -} VkSubpassDescription2KHR; - -typedef struct VkSubpassDependency2KHR { - VkStructureType sType; - const void* pNext; - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; - int32_t viewOffset; -} VkSubpassDependency2KHR; - -typedef struct VkRenderPassCreateInfo2KHR { - VkStructureType sType; - const void* pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription2KHR* pAttachments; - uint32_t subpassCount; - const VkSubpassDescription2KHR* pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency2KHR* pDependencies; - uint32_t correlatedViewMaskCount; - const uint32_t* pCorrelatedViewMasks; -} VkRenderPassCreateInfo2KHR; - -typedef struct VkSubpassBeginInfoKHR { - VkStructureType sType; - const void* pNext; - VkSubpassContents contents; -} VkSubpassBeginInfoKHR; - -typedef struct VkSubpassEndInfoKHR { - VkStructureType sType; - const void* pNext; -} VkSubpassEndInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfoKHR* pSubpassBeginInfo); -typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo, const VkSubpassEndInfoKHR* pSubpassEndInfo); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2KHR( - VkDevice device, - const VkRenderPassCreateInfo2KHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkRenderPass* pRenderPass); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2KHR( - VkCommandBuffer commandBuffer, - const VkRenderPassBeginInfo* pRenderPassBegin, - const VkSubpassBeginInfoKHR* pSubpassBeginInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2KHR( - VkCommandBuffer commandBuffer, - const VkSubpassBeginInfoKHR* pSubpassBeginInfo, - const VkSubpassEndInfoKHR* pSubpassEndInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2KHR( - VkCommandBuffer commandBuffer, - const VkSubpassEndInfoKHR* pSubpassEndInfo); -#endif - - -#define VK_KHR_shared_presentable_image 1 -#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 -#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" -typedef struct VkSharedPresentSurfaceCapabilitiesKHR { - VkStructureType sType; - void* pNext; - VkImageUsageFlags sharedPresentSupportedUsageFlags; -} VkSharedPresentSurfaceCapabilitiesKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR( - VkDevice device, - VkSwapchainKHR swapchain); -#endif - - -#define VK_KHR_external_fence_capabilities 1 -#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" -typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR; - -typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; - -typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR; - -typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; - -typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR; - -typedef VkExternalFenceProperties VkExternalFencePropertiesKHR; - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, - VkExternalFenceProperties* pExternalFenceProperties); -#endif - - -#define VK_KHR_external_fence 1 -#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" -typedef VkFenceImportFlags VkFenceImportFlagsKHR; - -typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR; - -typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; - - - -#define VK_KHR_external_fence_fd 1 -#define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd" -typedef struct VkImportFenceFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkFence fence; - VkFenceImportFlags flags; - VkExternalFenceHandleTypeFlagBits handleType; - int fd; -} VkImportFenceFdInfoKHR; - -typedef struct VkFenceGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkFence fence; - VkExternalFenceHandleTypeFlagBits handleType; -} VkFenceGetFdInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo); -typedef VkResult (VKAPI_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceFdKHR( - VkDevice device, - const VkImportFenceFdInfoKHR* pImportFenceFdInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR( - VkDevice device, - const VkFenceGetFdInfoKHR* pGetFdInfo, - int* pFd); -#endif - - -#define VK_KHR_maintenance2 1 -#define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" -typedef VkPointClippingBehavior VkPointClippingBehaviorKHR; - -typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR; - -typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; - -typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; - -typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; - -typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; - -typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR; - - - -#define VK_KHR_get_surface_capabilities2 1 -#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 -#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" -typedef struct VkPhysicalDeviceSurfaceInfo2KHR { - VkStructureType sType; - const void* pNext; - VkSurfaceKHR surface; -} VkPhysicalDeviceSurfaceInfo2KHR; - -typedef struct VkSurfaceCapabilities2KHR { - VkStructureType sType; - void* pNext; - VkSurfaceCapabilitiesKHR surfaceCapabilities; -} VkSurfaceCapabilities2KHR; - -typedef struct VkSurfaceFormat2KHR { - VkStructureType sType; - void* pNext; - VkSurfaceFormatKHR surfaceFormat; -} VkSurfaceFormat2KHR; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, - VkSurfaceCapabilities2KHR* pSurfaceCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, - uint32_t* pSurfaceFormatCount, - VkSurfaceFormat2KHR* pSurfaceFormats); -#endif - - -#define VK_KHR_variable_pointers 1 -#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 -#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" -typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; - -typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; - - - -#define VK_KHR_get_display_properties2 1 -#define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1 -#define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2" -typedef struct VkDisplayProperties2KHR { - VkStructureType sType; - void* pNext; - VkDisplayPropertiesKHR displayProperties; -} VkDisplayProperties2KHR; - -typedef struct VkDisplayPlaneProperties2KHR { - VkStructureType sType; - void* pNext; - VkDisplayPlanePropertiesKHR displayPlaneProperties; -} VkDisplayPlaneProperties2KHR; - -typedef struct VkDisplayModeProperties2KHR { - VkStructureType sType; - void* pNext; - VkDisplayModePropertiesKHR displayModeProperties; -} VkDisplayModeProperties2KHR; - -typedef struct VkDisplayPlaneInfo2KHR { - VkStructureType sType; - const void* pNext; - VkDisplayModeKHR mode; - uint32_t planeIndex; -} VkDisplayPlaneInfo2KHR; - -typedef struct VkDisplayPlaneCapabilities2KHR { - VkStructureType sType; - void* pNext; - VkDisplayPlaneCapabilitiesKHR capabilities; -} VkDisplayPlaneCapabilities2KHR; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayProperties2KHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlaneProperties2KHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModeProperties2KHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModeProperties2KHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, VkDisplayPlaneCapabilities2KHR* pCapabilities); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayProperties2KHR( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkDisplayProperties2KHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlaneProperties2KHR( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkDisplayPlaneProperties2KHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModeProperties2KHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - uint32_t* pPropertyCount, - VkDisplayModeProperties2KHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilities2KHR( - VkPhysicalDevice physicalDevice, - const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, - VkDisplayPlaneCapabilities2KHR* pCapabilities); -#endif - - -#define VK_KHR_dedicated_allocation 1 -#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 -#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" -typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; - -typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; - - - -#define VK_KHR_storage_buffer_storage_class 1 -#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1 -#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class" - - -#define VK_KHR_relaxed_block_layout 1 -#define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 -#define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" - - -#define VK_KHR_get_memory_requirements2 1 -#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1 -#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" -typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR; - -typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR; - -typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR; - -typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; - -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR( - VkDevice device, - const VkImageMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR( - VkDevice device, - const VkBufferMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR( - VkDevice device, - const VkImageSparseMemoryRequirementsInfo2* pInfo, - uint32_t* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); -#endif - - -#define VK_KHR_image_format_list 1 -#define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 -#define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" -typedef struct VkImageFormatListCreateInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t viewFormatCount; - const VkFormat* pViewFormats; -} VkImageFormatListCreateInfoKHR; - - - -#define VK_KHR_sampler_ycbcr_conversion 1 -typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR; - -#define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1 -#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" -typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; - -typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; - -typedef VkChromaLocation VkChromaLocationKHR; - -typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; - -typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR; - -typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR; - -typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR; - -typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; - -typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); -typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR( - VkDevice device, - const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSamplerYcbcrConversion* pYcbcrConversion); - -VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR( - VkDevice device, - VkSamplerYcbcrConversion ycbcrConversion, - const VkAllocationCallbacks* pAllocator); -#endif - - -#define VK_KHR_bind_memory2 1 -#define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 -#define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" -typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; - -typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR( - VkDevice device, - uint32_t bindInfoCount, - const VkBindBufferMemoryInfo* pBindInfos); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR( - VkDevice device, - uint32_t bindInfoCount, - const VkBindImageMemoryInfo* pBindInfos); -#endif - - -#define VK_KHR_maintenance3 1 -#define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" -typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; - -typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; - -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - VkDescriptorSetLayoutSupport* pSupport); -#endif - - -#define VK_KHR_draw_indirect_count 1 -#define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 -#define VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_KHR_draw_indirect_count" -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountKHR( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountKHR( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); -#endif - - -#define VK_KHR_8bit_storage 1 -#define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 -#define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" -typedef struct VkPhysicalDevice8BitStorageFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; -} VkPhysicalDevice8BitStorageFeaturesKHR; - - - -#define VK_KHR_shader_atomic_int64 1 -#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 -#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" -typedef struct VkPhysicalDeviceShaderAtomicInt64FeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; -} VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; - - - -#define VK_KHR_driver_properties 1 -#define VK_MAX_DRIVER_NAME_SIZE_KHR 256 -#define VK_MAX_DRIVER_INFO_SIZE_KHR 256 -#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 -#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" - -typedef enum VkDriverIdKHR { - VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1, - VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2, - VK_DRIVER_ID_MESA_RADV_KHR = 3, - VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4, - VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5, - VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6, - VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7, - VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8, - VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9, - VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = 10, - VK_DRIVER_ID_GGP_PROPRIETARY_KHR = 11, - VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = 12, - VK_DRIVER_ID_BEGIN_RANGE_KHR = VK_DRIVER_ID_AMD_PROPRIETARY_KHR, - VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR, - VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1), - VK_DRIVER_ID_MAX_ENUM_KHR = 0x7FFFFFFF -} VkDriverIdKHR; -typedef struct VkConformanceVersionKHR { - uint8_t major; - uint8_t minor; - uint8_t subminor; - uint8_t patch; -} VkConformanceVersionKHR; - -typedef struct VkPhysicalDeviceDriverPropertiesKHR { - VkStructureType sType; - void* pNext; - VkDriverIdKHR driverID; - char driverName[VK_MAX_DRIVER_NAME_SIZE_KHR]; - char driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR]; - VkConformanceVersionKHR conformanceVersion; -} VkPhysicalDeviceDriverPropertiesKHR; - - - -#define VK_KHR_shader_float_controls 1 -#define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 1 -#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" -typedef struct VkPhysicalDeviceFloatControlsPropertiesKHR { - VkStructureType sType; - void* pNext; - VkBool32 separateDenormSettings; - VkBool32 separateRoundingModeSettings; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; -} VkPhysicalDeviceFloatControlsPropertiesKHR; - - - -#define VK_KHR_depth_stencil_resolve 1 -#define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 -#define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" - -typedef enum VkResolveModeFlagBitsKHR { - VK_RESOLVE_MODE_NONE_KHR = 0, - VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = 0x00000001, - VK_RESOLVE_MODE_AVERAGE_BIT_KHR = 0x00000002, - VK_RESOLVE_MODE_MIN_BIT_KHR = 0x00000004, - VK_RESOLVE_MODE_MAX_BIT_KHR = 0x00000008, - VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkResolveModeFlagBitsKHR; -typedef VkFlags VkResolveModeFlagsKHR; -typedef struct VkSubpassDescriptionDepthStencilResolveKHR { - VkStructureType sType; - const void* pNext; - VkResolveModeFlagBitsKHR depthResolveMode; - VkResolveModeFlagBitsKHR stencilResolveMode; - const VkAttachmentReference2KHR* pDepthStencilResolveAttachment; -} VkSubpassDescriptionDepthStencilResolveKHR; - -typedef struct VkPhysicalDeviceDepthStencilResolvePropertiesKHR { - VkStructureType sType; - void* pNext; - VkResolveModeFlagsKHR supportedDepthResolveModes; - VkResolveModeFlagsKHR supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; -} VkPhysicalDeviceDepthStencilResolvePropertiesKHR; - - - -#define VK_KHR_swapchain_mutable_format 1 -#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 -#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" - - -#define VK_KHR_vulkan_memory_model 1 -#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 3 -#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" -typedef struct VkPhysicalDeviceVulkanMemoryModelFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; -} VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; - - - -#define VK_KHR_surface_protected_capabilities 1 -#define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME "VK_KHR_surface_protected_capabilities" -typedef struct VkSurfaceProtectedCapabilitiesKHR { - VkStructureType sType; - const void* pNext; - VkBool32 supportsProtected; -} VkSurfaceProtectedCapabilitiesKHR; - - - -#define VK_KHR_uniform_buffer_standard_layout 1 -#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1 -#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout" -typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 uniformBufferStandardLayout; -} VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; - - - -#define VK_EXT_debug_report 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 -#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" - -typedef enum VkDebugReportObjectTypeEXT { - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, - VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, - VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, - VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, - VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, - VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, - VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, - VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, - VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, - VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, - VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, - VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, - VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, - VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28, - VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, - VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, - VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, - VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, - VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, - VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), - VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugReportObjectTypeEXT; - -typedef enum VkDebugReportFlagBitsEXT { - VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, - VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, - VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, - VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, - VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugReportFlagBitsEXT; -typedef VkFlags VkDebugReportFlagsEXT; -typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData); - -typedef struct VkDebugReportCallbackCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportFlagsEXT flags; - PFN_vkDebugReportCallbackEXT pfnCallback; - void* pUserData; -} VkDebugReportCallbackCreateInfoEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); -typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( - VkInstance instance, - const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDebugReportCallbackEXT* pCallback); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( - VkInstance instance, - VkDebugReportCallbackEXT callback, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( - VkInstance instance, - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage); -#endif - - -#define VK_NV_glsl_shader 1 -#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 -#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" - - -#define VK_EXT_depth_range_unrestricted 1 -#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 -#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted" - - -#define VK_IMG_filter_cubic 1 -#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 -#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" - - -#define VK_AMD_rasterization_order 1 -#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 -#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" - -typedef enum VkRasterizationOrderAMD { - VK_RASTERIZATION_ORDER_STRICT_AMD = 0, - VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, - VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD, - VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD, - VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1), - VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF -} VkRasterizationOrderAMD; -typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { - VkStructureType sType; - const void* pNext; - VkRasterizationOrderAMD rasterizationOrder; -} VkPipelineRasterizationStateRasterizationOrderAMD; - - - -#define VK_AMD_shader_trinary_minmax 1 -#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 -#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" - - -#define VK_AMD_shader_explicit_vertex_parameter 1 -#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 -#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" - - -#define VK_EXT_debug_marker 1 -#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 -#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" -typedef struct VkDebugMarkerObjectNameInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t object; - const char* pObjectName; -} VkDebugMarkerObjectNameInfoEXT; - -typedef struct VkDebugMarkerObjectTagInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t object; - uint64_t tagName; - size_t tagSize; - const void* pTag; -} VkDebugMarkerObjectTagInfoEXT; - -typedef struct VkDebugMarkerMarkerInfoEXT { - VkStructureType sType; - const void* pNext; - const char* pMarkerName; - float color[4]; -} VkDebugMarkerMarkerInfoEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT* pTagInfo); -typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT* pNameInfo); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT( - VkDevice device, - const VkDebugMarkerObjectTagInfoEXT* pTagInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT( - VkDevice device, - const VkDebugMarkerObjectNameInfoEXT* pNameInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT( - VkCommandBuffer commandBuffer, - const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT( - VkCommandBuffer commandBuffer, - const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); -#endif - - -#define VK_AMD_gcn_shader 1 -#define VK_AMD_GCN_SHADER_SPEC_VERSION 1 -#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" - - -#define VK_NV_dedicated_allocation 1 -#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 -#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" -typedef struct VkDedicatedAllocationImageCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationImageCreateInfoNV; - -typedef struct VkDedicatedAllocationBufferCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationBufferCreateInfoNV; - -typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { - VkStructureType sType; - const void* pNext; - VkImage image; - VkBuffer buffer; -} VkDedicatedAllocationMemoryAllocateInfoNV; - - - -#define VK_EXT_transform_feedback 1 -#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 -#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" -typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; -typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 transformFeedback; - VkBool32 geometryStreams; -} VkPhysicalDeviceTransformFeedbackFeaturesEXT; - -typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxTransformFeedbackStreams; - uint32_t maxTransformFeedbackBuffers; - VkDeviceSize maxTransformFeedbackBufferSize; - uint32_t maxTransformFeedbackStreamDataSize; - uint32_t maxTransformFeedbackBufferDataSize; - uint32_t maxTransformFeedbackBufferDataStride; - VkBool32 transformFeedbackQueries; - VkBool32 transformFeedbackStreamsLinesTriangles; - VkBool32 transformFeedbackRasterizationStreamSelect; - VkBool32 transformFeedbackDraw; -} VkPhysicalDeviceTransformFeedbackPropertiesEXT; - -typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPipelineRasterizationStateStreamCreateFlagsEXT flags; - uint32_t rasterizationStream; -} VkPipelineRasterizationStateStreamCreateInfoEXT; - -typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes); -typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); -typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); -typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); -typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT( - VkCommandBuffer commandBuffer, - uint32_t firstBinding, - uint32_t bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets, - const VkDeviceSize* pSizes); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT( - VkCommandBuffer commandBuffer, - uint32_t firstCounterBuffer, - uint32_t counterBufferCount, - const VkBuffer* pCounterBuffers, - const VkDeviceSize* pCounterBufferOffsets); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT( - VkCommandBuffer commandBuffer, - uint32_t firstCounterBuffer, - uint32_t counterBufferCount, - const VkBuffer* pCounterBuffers, - const VkDeviceSize* pCounterBufferOffsets); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t query, - VkQueryControlFlags flags, - uint32_t index); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t query, - uint32_t index); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT( - VkCommandBuffer commandBuffer, - uint32_t instanceCount, - uint32_t firstInstance, - VkBuffer counterBuffer, - VkDeviceSize counterBufferOffset, - uint32_t counterOffset, - uint32_t vertexStride); -#endif - - -#define VK_NVX_image_view_handle 1 -#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 1 -#define VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME "VK_NVX_image_view_handle" -typedef struct VkImageViewHandleInfoNVX { - VkStructureType sType; - const void* pNext; - VkImageView imageView; - VkDescriptorType descriptorType; - VkSampler sampler; -} VkImageViewHandleInfoNVX; - -typedef uint32_t (VKAPI_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice device, const VkImageViewHandleInfoNVX* pInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR uint32_t VKAPI_CALL vkGetImageViewHandleNVX( - VkDevice device, - const VkImageViewHandleInfoNVX* pInfo); -#endif - - -#define VK_AMD_draw_indirect_count 1 -#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 -#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); -#endif - - -#define VK_AMD_negative_viewport_height 1 -#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 -#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" - - -#define VK_AMD_gpu_shader_half_float 1 -#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 2 -#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" - - -#define VK_AMD_shader_ballot 1 -#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 -#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" - - -#define VK_AMD_texture_gather_bias_lod 1 -#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 -#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" -typedef struct VkTextureLODGatherFormatPropertiesAMD { - VkStructureType sType; - void* pNext; - VkBool32 supportsTextureGatherLODBiasAMD; -} VkTextureLODGatherFormatPropertiesAMD; - - - -#define VK_AMD_shader_info 1 -#define VK_AMD_SHADER_INFO_SPEC_VERSION 1 -#define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info" - -typedef enum VkShaderInfoTypeAMD { - VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, - VK_SHADER_INFO_TYPE_BINARY_AMD = 1, - VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, - VK_SHADER_INFO_TYPE_BEGIN_RANGE_AMD = VK_SHADER_INFO_TYPE_STATISTICS_AMD, - VK_SHADER_INFO_TYPE_END_RANGE_AMD = VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD, - VK_SHADER_INFO_TYPE_RANGE_SIZE_AMD = (VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD - VK_SHADER_INFO_TYPE_STATISTICS_AMD + 1), - VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF -} VkShaderInfoTypeAMD; -typedef struct VkShaderResourceUsageAMD { - uint32_t numUsedVgprs; - uint32_t numUsedSgprs; - uint32_t ldsSizePerLocalWorkGroup; - size_t ldsUsageSizeInBytes; - size_t scratchMemUsageInBytes; -} VkShaderResourceUsageAMD; - -typedef struct VkShaderStatisticsInfoAMD { - VkShaderStageFlags shaderStageMask; - VkShaderResourceUsageAMD resourceUsage; - uint32_t numPhysicalVgprs; - uint32_t numPhysicalSgprs; - uint32_t numAvailableVgprs; - uint32_t numAvailableSgprs; - uint32_t computeWorkGroupSize[3]; -} VkShaderStatisticsInfoAMD; - -typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t* pInfoSize, void* pInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderInfoAMD( - VkDevice device, - VkPipeline pipeline, - VkShaderStageFlagBits shaderStage, - VkShaderInfoTypeAMD infoType, - size_t* pInfoSize, - void* pInfo); -#endif - - -#define VK_AMD_shader_image_load_store_lod 1 -#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1 -#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod" - - -#define VK_NV_corner_sampled_image 1 -#define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 -#define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" -typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 cornerSampledImage; -} VkPhysicalDeviceCornerSampledImageFeaturesNV; - - - -#define VK_IMG_format_pvrtc 1 -#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 -#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" - - -#define VK_NV_external_memory_capabilities 1 -#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" - -typedef enum VkExternalMemoryHandleTypeFlagBitsNV { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkExternalMemoryHandleTypeFlagBitsNV; -typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; - -typedef enum VkExternalMemoryFeatureFlagBitsNV { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, - VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkExternalMemoryFeatureFlagBitsNV; -typedef VkFlags VkExternalMemoryFeatureFlagsNV; -typedef struct VkExternalImageFormatPropertiesNV { - VkImageFormatProperties imageFormatProperties; - VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; - VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; -} VkExternalImageFormatPropertiesNV; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags, - VkExternalMemoryHandleTypeFlagsNV externalHandleType, - VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); -#endif - - -#define VK_NV_external_memory 1 -#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 -#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" -typedef struct VkExternalMemoryImageCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExternalMemoryImageCreateInfoNV; - -typedef struct VkExportMemoryAllocateInfoNV { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExportMemoryAllocateInfoNV; - - - -#define VK_EXT_validation_flags 1 -#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1 -#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" - -typedef enum VkValidationCheckEXT { - VK_VALIDATION_CHECK_ALL_EXT = 0, - VK_VALIDATION_CHECK_SHADERS_EXT = 1, - VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT, - VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_SHADERS_EXT, - VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_SHADERS_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1), - VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF -} VkValidationCheckEXT; -typedef struct VkValidationFlagsEXT { - VkStructureType sType; - const void* pNext; - uint32_t disabledValidationCheckCount; - const VkValidationCheckEXT* pDisabledValidationChecks; -} VkValidationFlagsEXT; - - - -#define VK_EXT_shader_subgroup_ballot 1 -#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 -#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" - - -#define VK_EXT_shader_subgroup_vote 1 -#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 -#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" - - -#define VK_EXT_astc_decode_mode 1 -#define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 -#define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" -typedef struct VkImageViewASTCDecodeModeEXT { - VkStructureType sType; - const void* pNext; - VkFormat decodeMode; -} VkImageViewASTCDecodeModeEXT; - -typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 decodeModeSharedExponent; -} VkPhysicalDeviceASTCDecodeFeaturesEXT; - - - -#define VK_EXT_conditional_rendering 1 -#define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 1 -#define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" - -typedef enum VkConditionalRenderingFlagBitsEXT { - VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001, - VK_CONDITIONAL_RENDERING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkConditionalRenderingFlagBitsEXT; -typedef VkFlags VkConditionalRenderingFlagsEXT; -typedef struct VkConditionalRenderingBeginInfoEXT { - VkStructureType sType; - const void* pNext; - VkBuffer buffer; - VkDeviceSize offset; - VkConditionalRenderingFlagsEXT flags; -} VkConditionalRenderingBeginInfoEXT; - -typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 conditionalRendering; - VkBool32 inheritedConditionalRendering; -} VkPhysicalDeviceConditionalRenderingFeaturesEXT; - -typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 conditionalRenderingEnable; -} VkCommandBufferInheritanceConditionalRenderingInfoEXT; - -typedef void (VKAPI_PTR *PFN_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); -typedef void (VKAPI_PTR *PFN_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer commandBuffer); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdBeginConditionalRenderingEXT( - VkCommandBuffer commandBuffer, - const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndConditionalRenderingEXT( - VkCommandBuffer commandBuffer); -#endif - - -#define VK_NVX_device_generated_commands 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) -#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 -#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands" - -typedef enum VkIndirectCommandsTokenTypeNVX { - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX + 1), - VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkIndirectCommandsTokenTypeNVX; - -typedef enum VkObjectEntryTypeNVX { - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0, - VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1, - VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2, - VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3, - VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4, - VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX, - VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX, - VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX + 1), - VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkObjectEntryTypeNVX; - -typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX { - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkIndirectCommandsLayoutUsageFlagBitsNVX; -typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX; - -typedef enum VkObjectEntryUsageFlagBitsNVX { - VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001, - VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002, - VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkObjectEntryUsageFlagBitsNVX; -typedef VkFlags VkObjectEntryUsageFlagsNVX; -typedef struct VkDeviceGeneratedCommandsFeaturesNVX { - VkStructureType sType; - const void* pNext; - VkBool32 computeBindingPointSupport; -} VkDeviceGeneratedCommandsFeaturesNVX; - -typedef struct VkDeviceGeneratedCommandsLimitsNVX { - VkStructureType sType; - const void* pNext; - uint32_t maxIndirectCommandsLayoutTokenCount; - uint32_t maxObjectEntryCounts; - uint32_t minSequenceCountBufferOffsetAlignment; - uint32_t minSequenceIndexBufferOffsetAlignment; - uint32_t minCommandsTokenBufferOffsetAlignment; -} VkDeviceGeneratedCommandsLimitsNVX; - -typedef struct VkIndirectCommandsTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType; - VkBuffer buffer; - VkDeviceSize offset; -} VkIndirectCommandsTokenNVX; - -typedef struct VkIndirectCommandsLayoutTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType; - uint32_t bindingUnit; - uint32_t dynamicCount; - uint32_t divisor; -} VkIndirectCommandsLayoutTokenNVX; - -typedef struct VkIndirectCommandsLayoutCreateInfoNVX { - VkStructureType sType; - const void* pNext; - VkPipelineBindPoint pipelineBindPoint; - VkIndirectCommandsLayoutUsageFlagsNVX flags; - uint32_t tokenCount; - const VkIndirectCommandsLayoutTokenNVX* pTokens; -} VkIndirectCommandsLayoutCreateInfoNVX; - -typedef struct VkCmdProcessCommandsInfoNVX { - VkStructureType sType; - const void* pNext; - VkObjectTableNVX objectTable; - VkIndirectCommandsLayoutNVX indirectCommandsLayout; - uint32_t indirectCommandsTokenCount; - const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens; - uint32_t maxSequencesCount; - VkCommandBuffer targetCommandBuffer; - VkBuffer sequencesCountBuffer; - VkDeviceSize sequencesCountOffset; - VkBuffer sequencesIndexBuffer; - VkDeviceSize sequencesIndexOffset; -} VkCmdProcessCommandsInfoNVX; - -typedef struct VkCmdReserveSpaceForCommandsInfoNVX { - VkStructureType sType; - const void* pNext; - VkObjectTableNVX objectTable; - VkIndirectCommandsLayoutNVX indirectCommandsLayout; - uint32_t maxSequencesCount; -} VkCmdReserveSpaceForCommandsInfoNVX; - -typedef struct VkObjectTableCreateInfoNVX { - VkStructureType sType; - const void* pNext; - uint32_t objectCount; - const VkObjectEntryTypeNVX* pObjectEntryTypes; - const uint32_t* pObjectEntryCounts; - const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags; - uint32_t maxUniformBuffersPerDescriptor; - uint32_t maxStorageBuffersPerDescriptor; - uint32_t maxStorageImagesPerDescriptor; - uint32_t maxSampledImagesPerDescriptor; - uint32_t maxPipelineLayouts; -} VkObjectTableCreateInfoNVX; - -typedef struct VkObjectTableEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; -} VkObjectTableEntryNVX; - -typedef struct VkObjectTablePipelineEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipeline pipeline; -} VkObjectTablePipelineEntryNVX; - -typedef struct VkObjectTableDescriptorSetEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; -} VkObjectTableDescriptorSetEntryNVX; - -typedef struct VkObjectTableVertexBufferEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkBuffer buffer; -} VkObjectTableVertexBufferEntryNVX; - -typedef struct VkObjectTableIndexBufferEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkBuffer buffer; - VkIndexType indexType; -} VkObjectTableIndexBufferEntryNVX; - -typedef struct VkObjectTablePushConstantEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipelineLayout pipelineLayout; - VkShaderStageFlags stageFlags; -} VkObjectTablePushConstantEntryNVX; - -typedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); -typedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); -typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable); -typedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const* ppObjectTableEntries, const uint32_t* pObjectIndices); -typedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX( - VkDevice device, - const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX( - VkDevice device, - VkIndirectCommandsLayoutNVX indirectCommandsLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX( - VkDevice device, - const VkObjectTableCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkObjectTableNVX* pObjectTable); - -VKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX( - VkDevice device, - VkObjectTableNVX objectTable, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - uint32_t objectCount, - const VkObjectTableEntryNVX* const* ppObjectTableEntries, - const uint32_t* pObjectIndices); - -VKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - uint32_t objectCount, - const VkObjectEntryTypeNVX* pObjectEntryTypes, - const uint32_t* pObjectIndices); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX( - VkPhysicalDevice physicalDevice, - VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, - VkDeviceGeneratedCommandsLimitsNVX* pLimits); -#endif - - -#define VK_NV_clip_space_w_scaling 1 -#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 -#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" -typedef struct VkViewportWScalingNV { - float xcoeff; - float ycoeff; -} VkViewportWScalingNV; - -typedef struct VkPipelineViewportWScalingStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 viewportWScalingEnable; - uint32_t viewportCount; - const VkViewportWScalingNV* pViewportWScalings; -} VkPipelineViewportWScalingStateCreateInfoNV; - -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV( - VkCommandBuffer commandBuffer, - uint32_t firstViewport, - uint32_t viewportCount, - const VkViewportWScalingNV* pViewportWScalings); -#endif - - -#define VK_EXT_direct_mode_display 1 -#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 -#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" -typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display); -#endif - - -#define VK_EXT_display_surface_counter 1 -#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 -#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" - -typedef enum VkSurfaceCounterFlagBitsEXT { - VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001, - VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkSurfaceCounterFlagBitsEXT; -typedef VkFlags VkSurfaceCounterFlagsEXT; -typedef struct VkSurfaceCapabilities2EXT { - VkStructureType sType; - void* pNext; - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; - VkSurfaceCounterFlagsEXT supportedSurfaceCounters; -} VkSurfaceCapabilities2EXT; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - VkSurfaceCapabilities2EXT* pSurfaceCapabilities); -#endif - - -#define VK_EXT_display_control 1 -#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 -#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" - -typedef enum VkDisplayPowerStateEXT { - VK_DISPLAY_POWER_STATE_OFF_EXT = 0, - VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, - VK_DISPLAY_POWER_STATE_ON_EXT = 2, - VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT, - VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT, - VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1), - VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDisplayPowerStateEXT; - -typedef enum VkDeviceEventTypeEXT { - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, - VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, - VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, - VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1), - VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDeviceEventTypeEXT; - -typedef enum VkDisplayEventTypeEXT { - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, - VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, - VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, - VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1), - VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDisplayEventTypeEXT; -typedef struct VkDisplayPowerInfoEXT { - VkStructureType sType; - const void* pNext; - VkDisplayPowerStateEXT powerState; -} VkDisplayPowerInfoEXT; - -typedef struct VkDeviceEventInfoEXT { - VkStructureType sType; - const void* pNext; - VkDeviceEventTypeEXT deviceEvent; -} VkDeviceEventInfoEXT; - -typedef struct VkDisplayEventInfoEXT { - VkStructureType sType; - const void* pNext; - VkDisplayEventTypeEXT displayEvent; -} VkDisplayEventInfoEXT; - -typedef struct VkSwapchainCounterCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkSurfaceCounterFlagsEXT surfaceCounters; -} VkSwapchainCounterCreateInfoEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT( - VkDevice device, - VkDisplayKHR display, - const VkDisplayPowerInfoEXT* pDisplayPowerInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT( - VkDevice device, - const VkDeviceEventInfoEXT* pDeviceEventInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT( - VkDevice device, - VkDisplayKHR display, - const VkDisplayEventInfoEXT* pDisplayEventInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT( - VkDevice device, - VkSwapchainKHR swapchain, - VkSurfaceCounterFlagBitsEXT counter, - uint64_t* pCounterValue); -#endif - - -#define VK_GOOGLE_display_timing 1 -#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1 -#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing" -typedef struct VkRefreshCycleDurationGOOGLE { - uint64_t refreshDuration; -} VkRefreshCycleDurationGOOGLE; - -typedef struct VkPastPresentationTimingGOOGLE { - uint32_t presentID; - uint64_t desiredPresentTime; - uint64_t actualPresentTime; - uint64_t earliestPresentTime; - uint64_t presentMargin; -} VkPastPresentationTimingGOOGLE; - -typedef struct VkPresentTimeGOOGLE { - uint32_t presentID; - uint64_t desiredPresentTime; -} VkPresentTimeGOOGLE; - -typedef struct VkPresentTimesInfoGOOGLE { - VkStructureType sType; - const void* pNext; - uint32_t swapchainCount; - const VkPresentTimeGOOGLE* pTimes; -} VkPresentTimesInfoGOOGLE; - -typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE( - VkDevice device, - VkSwapchainKHR swapchain, - VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE( - VkDevice device, - VkSwapchainKHR swapchain, - uint32_t* pPresentationTimingCount, - VkPastPresentationTimingGOOGLE* pPresentationTimings); -#endif - - -#define VK_NV_sample_mask_override_coverage 1 -#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 -#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" - - -#define VK_NV_geometry_shader_passthrough 1 -#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 -#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" - - -#define VK_NV_viewport_array2 1 -#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1 -#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2" - - -#define VK_NVX_multiview_per_view_attributes 1 -#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1 -#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes" -typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { - VkStructureType sType; - void* pNext; - VkBool32 perViewPositionAllComponents; -} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; - - - -#define VK_NV_viewport_swizzle 1 -#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 -#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" - -typedef enum VkViewportCoordinateSwizzleNV { - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, - VK_VIEWPORT_COORDINATE_SWIZZLE_BEGIN_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV, - VK_VIEWPORT_COORDINATE_SWIZZLE_END_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV, - VK_VIEWPORT_COORDINATE_SWIZZLE_RANGE_SIZE_NV = (VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV + 1), - VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF -} VkViewportCoordinateSwizzleNV; -typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; -typedef struct VkViewportSwizzleNV { - VkViewportCoordinateSwizzleNV x; - VkViewportCoordinateSwizzleNV y; - VkViewportCoordinateSwizzleNV z; - VkViewportCoordinateSwizzleNV w; -} VkViewportSwizzleNV; - -typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkPipelineViewportSwizzleStateCreateFlagsNV flags; - uint32_t viewportCount; - const VkViewportSwizzleNV* pViewportSwizzles; -} VkPipelineViewportSwizzleStateCreateInfoNV; - - - -#define VK_EXT_discard_rectangles 1 -#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1 -#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" - -typedef enum VkDiscardRectangleModeEXT { - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, - VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, - VK_DISCARD_RECTANGLE_MODE_BEGIN_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT, - VK_DISCARD_RECTANGLE_MODE_END_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT, - VK_DISCARD_RECTANGLE_MODE_RANGE_SIZE_EXT = (VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT + 1), - VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDiscardRectangleModeEXT; -typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; -typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxDiscardRectangles; -} VkPhysicalDeviceDiscardRectanglePropertiesEXT; - -typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPipelineDiscardRectangleStateCreateFlagsEXT flags; - VkDiscardRectangleModeEXT discardRectangleMode; - uint32_t discardRectangleCount; - const VkRect2D* pDiscardRectangles; -} VkPipelineDiscardRectangleStateCreateInfoEXT; - -typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT( - VkCommandBuffer commandBuffer, - uint32_t firstDiscardRectangle, - uint32_t discardRectangleCount, - const VkRect2D* pDiscardRectangles); -#endif - - -#define VK_EXT_conservative_rasterization 1 -#define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1 -#define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" - -typedef enum VkConservativeRasterizationModeEXT { - VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, - VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, - VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, - VK_CONSERVATIVE_RASTERIZATION_MODE_BEGIN_RANGE_EXT = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT, - VK_CONSERVATIVE_RASTERIZATION_MODE_END_RANGE_EXT = VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT, - VK_CONSERVATIVE_RASTERIZATION_MODE_RANGE_SIZE_EXT = (VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT - VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT + 1), - VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkConservativeRasterizationModeEXT; -typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; -typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { - VkStructureType sType; - void* pNext; - float primitiveOverestimationSize; - float maxExtraPrimitiveOverestimationSize; - float extraPrimitiveOverestimationSizeGranularity; - VkBool32 primitiveUnderestimation; - VkBool32 conservativePointAndLineRasterization; - VkBool32 degenerateTrianglesRasterized; - VkBool32 degenerateLinesRasterized; - VkBool32 fullyCoveredFragmentShaderInputVariable; - VkBool32 conservativeRasterizationPostDepthCoverage; -} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; - -typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; - VkConservativeRasterizationModeEXT conservativeRasterizationMode; - float extraPrimitiveOverestimationSize; -} VkPipelineRasterizationConservativeStateCreateInfoEXT; - - - -#define VK_EXT_depth_clip_enable 1 -#define VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION 1 -#define VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME "VK_EXT_depth_clip_enable" -typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; -typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 depthClipEnable; -} VkPhysicalDeviceDepthClipEnableFeaturesEXT; - -typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; - VkBool32 depthClipEnable; -} VkPipelineRasterizationDepthClipStateCreateInfoEXT; - - - -#define VK_EXT_swapchain_colorspace 1 -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 4 -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" - - -#define VK_EXT_hdr_metadata 1 -#define VK_EXT_HDR_METADATA_SPEC_VERSION 1 -#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" -typedef struct VkXYColorEXT { - float x; - float y; -} VkXYColorEXT; - -typedef struct VkHdrMetadataEXT { - VkStructureType sType; - const void* pNext; - VkXYColorEXT displayPrimaryRed; - VkXYColorEXT displayPrimaryGreen; - VkXYColorEXT displayPrimaryBlue; - VkXYColorEXT whitePoint; - float maxLuminance; - float minLuminance; - float maxContentLightLevel; - float maxFrameAverageLightLevel; -} VkHdrMetadataEXT; - -typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT( - VkDevice device, - uint32_t swapchainCount, - const VkSwapchainKHR* pSwapchains, - const VkHdrMetadataEXT* pMetadata); -#endif - - -#define VK_EXT_external_memory_dma_buf 1 -#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 -#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf" - - -#define VK_EXT_queue_family_foreign 1 -#define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 -#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" -#define VK_QUEUE_FAMILY_FOREIGN_EXT (~0U-2) - - -#define VK_EXT_debug_utils 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) -#define VK_EXT_DEBUG_UTILS_SPEC_VERSION 1 -#define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" -typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; -typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; - -typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugUtilsMessageSeverityFlagBitsEXT; -typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; - -typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001, - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002, - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004, - VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugUtilsMessageTypeFlagBitsEXT; -typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; -typedef struct VkDebugUtilsObjectNameInfoEXT { - VkStructureType sType; - const void* pNext; - VkObjectType objectType; - uint64_t objectHandle; - const char* pObjectName; -} VkDebugUtilsObjectNameInfoEXT; - -typedef struct VkDebugUtilsObjectTagInfoEXT { - VkStructureType sType; - const void* pNext; - VkObjectType objectType; - uint64_t objectHandle; - uint64_t tagName; - size_t tagSize; - const void* pTag; -} VkDebugUtilsObjectTagInfoEXT; - -typedef struct VkDebugUtilsLabelEXT { - VkStructureType sType; - const void* pNext; - const char* pLabelName; - float color[4]; -} VkDebugUtilsLabelEXT; - -typedef struct VkDebugUtilsMessengerCallbackDataEXT { - VkStructureType sType; - const void* pNext; - VkDebugUtilsMessengerCallbackDataFlagsEXT flags; - const char* pMessageIdName; - int32_t messageIdNumber; - const char* pMessage; - uint32_t queueLabelCount; - const VkDebugUtilsLabelEXT* pQueueLabels; - uint32_t cmdBufLabelCount; - const VkDebugUtilsLabelEXT* pCmdBufLabels; - uint32_t objectCount; - const VkDebugUtilsObjectNameInfoEXT* pObjects; -} VkDebugUtilsMessengerCallbackDataEXT; - -typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageTypes, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData); - -typedef struct VkDebugUtilsMessengerCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugUtilsMessengerCreateFlagsEXT flags; - VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; - VkDebugUtilsMessageTypeFlagsEXT messageType; - PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback; - void* pUserData; -} VkDebugUtilsMessengerCreateInfoEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice device, const VkDebugUtilsObjectNameInfoEXT* pNameInfo); -typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice device, const VkDebugUtilsObjectTagInfoEXT* pTagInfo); -typedef void (VKAPI_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); -typedef void (VKAPI_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue); -typedef void (VKAPI_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); -typedef void (VKAPI_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); -typedef void (VKAPI_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger); -typedef void (VKAPI_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectNameEXT( - VkDevice device, - const VkDebugUtilsObjectNameInfoEXT* pNameInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectTagEXT( - VkDevice device, - const VkDebugUtilsObjectTagInfoEXT* pTagInfo); - -VKAPI_ATTR void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT( - VkQueue queue, - const VkDebugUtilsLabelEXT* pLabelInfo); - -VKAPI_ATTR void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT( - VkQueue queue); - -VKAPI_ATTR void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT( - VkQueue queue, - const VkDebugUtilsLabelEXT* pLabelInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginDebugUtilsLabelEXT( - VkCommandBuffer commandBuffer, - const VkDebugUtilsLabelEXT* pLabelInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndDebugUtilsLabelEXT( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR void VKAPI_CALL vkCmdInsertDebugUtilsLabelEXT( - VkCommandBuffer commandBuffer, - const VkDebugUtilsLabelEXT* pLabelInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( - VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDebugUtilsMessengerEXT* pMessenger); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT( - VkInstance instance, - VkDebugUtilsMessengerEXT messenger, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT( - VkInstance instance, - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageTypes, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); -#endif - - -#define VK_EXT_sampler_filter_minmax 1 -#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1 -#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" - -typedef enum VkSamplerReductionModeEXT { - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0, - VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1, - VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2, - VK_SAMPLER_REDUCTION_MODE_BEGIN_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT, - VK_SAMPLER_REDUCTION_MODE_END_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_MAX_EXT, - VK_SAMPLER_REDUCTION_MODE_RANGE_SIZE_EXT = (VK_SAMPLER_REDUCTION_MODE_MAX_EXT - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT + 1), - VK_SAMPLER_REDUCTION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkSamplerReductionModeEXT; -typedef struct VkSamplerReductionModeCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkSamplerReductionModeEXT reductionMode; -} VkSamplerReductionModeCreateInfoEXT; - -typedef struct VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT { - VkStructureType sType; - void* pNext; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; -} VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; - - - -#define VK_AMD_gpu_shader_int16 1 -#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 2 -#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16" - - -#define VK_AMD_mixed_attachment_samples 1 -#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1 -#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples" - - -#define VK_AMD_shader_fragment_mask 1 -#define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1 -#define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" - - -#define VK_EXT_inline_uniform_block 1 -#define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 -#define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" -typedef struct VkPhysicalDeviceInlineUniformBlockFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 inlineUniformBlock; - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; -} VkPhysicalDeviceInlineUniformBlockFeaturesEXT; - -typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxInlineUniformBlockSize; - uint32_t maxPerStageDescriptorInlineUniformBlocks; - uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; - uint32_t maxDescriptorSetInlineUniformBlocks; - uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; -} VkPhysicalDeviceInlineUniformBlockPropertiesEXT; - -typedef struct VkWriteDescriptorSetInlineUniformBlockEXT { - VkStructureType sType; - const void* pNext; - uint32_t dataSize; - const void* pData; -} VkWriteDescriptorSetInlineUniformBlockEXT; - -typedef struct VkDescriptorPoolInlineUniformBlockCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t maxInlineUniformBlockBindings; -} VkDescriptorPoolInlineUniformBlockCreateInfoEXT; - - - -#define VK_EXT_shader_stencil_export 1 -#define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 -#define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" - - -#define VK_EXT_sample_locations 1 -#define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1 -#define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations" -typedef struct VkSampleLocationEXT { - float x; - float y; -} VkSampleLocationEXT; - -typedef struct VkSampleLocationsInfoEXT { - VkStructureType sType; - const void* pNext; - VkSampleCountFlagBits sampleLocationsPerPixel; - VkExtent2D sampleLocationGridSize; - uint32_t sampleLocationsCount; - const VkSampleLocationEXT* pSampleLocations; -} VkSampleLocationsInfoEXT; - -typedef struct VkAttachmentSampleLocationsEXT { - uint32_t attachmentIndex; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkAttachmentSampleLocationsEXT; - -typedef struct VkSubpassSampleLocationsEXT { - uint32_t subpassIndex; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkSubpassSampleLocationsEXT; - -typedef struct VkRenderPassSampleLocationsBeginInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t attachmentInitialSampleLocationsCount; - const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations; - uint32_t postSubpassSampleLocationsCount; - const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations; -} VkRenderPassSampleLocationsBeginInfoEXT; - -typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 sampleLocationsEnable; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkPipelineSampleLocationsStateCreateInfoEXT; - -typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { - VkStructureType sType; - void* pNext; - VkSampleCountFlags sampleLocationSampleCounts; - VkExtent2D maxSampleLocationGridSize; - float sampleLocationCoordinateRange[2]; - uint32_t sampleLocationSubPixelBits; - VkBool32 variableSampleLocations; -} VkPhysicalDeviceSampleLocationsPropertiesEXT; - -typedef struct VkMultisamplePropertiesEXT { - VkStructureType sType; - void* pNext; - VkExtent2D maxSampleLocationGridSize; -} VkMultisamplePropertiesEXT; - -typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT* pSampleLocationsInfo); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT* pMultisampleProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEXT( - VkCommandBuffer commandBuffer, - const VkSampleLocationsInfoEXT* pSampleLocationsInfo); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMultisamplePropertiesEXT( - VkPhysicalDevice physicalDevice, - VkSampleCountFlagBits samples, - VkMultisamplePropertiesEXT* pMultisampleProperties); -#endif - - -#define VK_EXT_blend_operation_advanced 1 -#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 -#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" - -typedef enum VkBlendOverlapEXT { - VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, - VK_BLEND_OVERLAP_DISJOINT_EXT = 1, - VK_BLEND_OVERLAP_CONJOINT_EXT = 2, - VK_BLEND_OVERLAP_BEGIN_RANGE_EXT = VK_BLEND_OVERLAP_UNCORRELATED_EXT, - VK_BLEND_OVERLAP_END_RANGE_EXT = VK_BLEND_OVERLAP_CONJOINT_EXT, - VK_BLEND_OVERLAP_RANGE_SIZE_EXT = (VK_BLEND_OVERLAP_CONJOINT_EXT - VK_BLEND_OVERLAP_UNCORRELATED_EXT + 1), - VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF -} VkBlendOverlapEXT; -typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 advancedBlendCoherentOperations; -} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; - -typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t advancedBlendMaxColorAttachments; - VkBool32 advancedBlendIndependentBlend; - VkBool32 advancedBlendNonPremultipliedSrcColor; - VkBool32 advancedBlendNonPremultipliedDstColor; - VkBool32 advancedBlendCorrelatedOverlap; - VkBool32 advancedBlendAllOperations; -} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; - -typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 srcPremultiplied; - VkBool32 dstPremultiplied; - VkBlendOverlapEXT blendOverlap; -} VkPipelineColorBlendAdvancedStateCreateInfoEXT; - - - -#define VK_NV_fragment_coverage_to_color 1 -#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 -#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color" -typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; -typedef struct VkPipelineCoverageToColorStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkPipelineCoverageToColorStateCreateFlagsNV flags; - VkBool32 coverageToColorEnable; - uint32_t coverageToColorLocation; -} VkPipelineCoverageToColorStateCreateInfoNV; - - - -#define VK_NV_framebuffer_mixed_samples 1 -#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 -#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" - -typedef enum VkCoverageModulationModeNV { - VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, - VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, - VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, - VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, - VK_COVERAGE_MODULATION_MODE_BEGIN_RANGE_NV = VK_COVERAGE_MODULATION_MODE_NONE_NV, - VK_COVERAGE_MODULATION_MODE_END_RANGE_NV = VK_COVERAGE_MODULATION_MODE_RGBA_NV, - VK_COVERAGE_MODULATION_MODE_RANGE_SIZE_NV = (VK_COVERAGE_MODULATION_MODE_RGBA_NV - VK_COVERAGE_MODULATION_MODE_NONE_NV + 1), - VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF -} VkCoverageModulationModeNV; -typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; -typedef struct VkPipelineCoverageModulationStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkPipelineCoverageModulationStateCreateFlagsNV flags; - VkCoverageModulationModeNV coverageModulationMode; - VkBool32 coverageModulationTableEnable; - uint32_t coverageModulationTableCount; - const float* pCoverageModulationTable; -} VkPipelineCoverageModulationStateCreateInfoNV; - - - -#define VK_NV_fill_rectangle 1 -#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 -#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" - - -#define VK_NV_shader_sm_builtins 1 -#define VK_NV_SHADER_SM_BUILTINS_SPEC_VERSION 1 -#define VK_NV_SHADER_SM_BUILTINS_EXTENSION_NAME "VK_NV_shader_sm_builtins" -typedef struct VkPhysicalDeviceShaderSMBuiltinsPropertiesNV { - VkStructureType sType; - void* pNext; - uint32_t shaderSMCount; - uint32_t shaderWarpsPerSM; -} VkPhysicalDeviceShaderSMBuiltinsPropertiesNV; - -typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 shaderSMBuiltins; -} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; - - - -#define VK_EXT_post_depth_coverage 1 -#define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 -#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" - - -#define VK_EXT_image_drm_format_modifier 1 -#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 -#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" -typedef struct VkDrmFormatModifierPropertiesEXT { - uint64_t drmFormatModifier; - uint32_t drmFormatModifierPlaneCount; - VkFormatFeatureFlags drmFormatModifierTilingFeatures; -} VkDrmFormatModifierPropertiesEXT; - -typedef struct VkDrmFormatModifierPropertiesListEXT { - VkStructureType sType; - void* pNext; - uint32_t drmFormatModifierCount; - VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties; -} VkDrmFormatModifierPropertiesListEXT; - -typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT { - VkStructureType sType; - const void* pNext; - uint64_t drmFormatModifier; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t* pQueueFamilyIndices; -} VkPhysicalDeviceImageDrmFormatModifierInfoEXT; - -typedef struct VkImageDrmFormatModifierListCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t drmFormatModifierCount; - const uint64_t* pDrmFormatModifiers; -} VkImageDrmFormatModifierListCreateInfoEXT; - -typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint64_t drmFormatModifier; - uint32_t drmFormatModifierPlaneCount; - const VkSubresourceLayout* pPlaneLayouts; -} VkImageDrmFormatModifierExplicitCreateInfoEXT; - -typedef struct VkImageDrmFormatModifierPropertiesEXT { - VkStructureType sType; - void* pNext; - uint64_t drmFormatModifier; -} VkImageDrmFormatModifierPropertiesEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT( - VkDevice device, - VkImage image, - VkImageDrmFormatModifierPropertiesEXT* pProperties); -#endif - - -#define VK_EXT_validation_cache 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) -#define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 -#define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" - -typedef enum VkValidationCacheHeaderVersionEXT { - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, - VK_VALIDATION_CACHE_HEADER_VERSION_BEGIN_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT, - VK_VALIDATION_CACHE_HEADER_VERSION_END_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT, - VK_VALIDATION_CACHE_HEADER_VERSION_RANGE_SIZE_EXT = (VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT + 1), - VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF -} VkValidationCacheHeaderVersionEXT; -typedef VkFlags VkValidationCacheCreateFlagsEXT; -typedef struct VkValidationCacheCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkValidationCacheCreateFlagsEXT flags; - size_t initialDataSize; - const void* pInitialData; -} VkValidationCacheCreateInfoEXT; - -typedef struct VkShaderModuleValidationCacheCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkValidationCacheEXT validationCache; -} VkShaderModuleValidationCacheCreateInfoEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache); -typedef void (VKAPI_PTR *PFN_vkDestroyValidationCacheEXT)(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT* pSrcCaches); -typedef VkResult (VKAPI_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize, void* pData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateValidationCacheEXT( - VkDevice device, - const VkValidationCacheCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkValidationCacheEXT* pValidationCache); - -VKAPI_ATTR void VKAPI_CALL vkDestroyValidationCacheEXT( - VkDevice device, - VkValidationCacheEXT validationCache, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkMergeValidationCachesEXT( - VkDevice device, - VkValidationCacheEXT dstCache, - uint32_t srcCacheCount, - const VkValidationCacheEXT* pSrcCaches); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT( - VkDevice device, - VkValidationCacheEXT validationCache, - size_t* pDataSize, - void* pData); -#endif - - -#define VK_EXT_descriptor_indexing 1 -#define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 -#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" - -typedef enum VkDescriptorBindingFlagBitsEXT { - VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = 0x00000001, - VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = 0x00000002, - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = 0x00000004, - VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = 0x00000008, - VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDescriptorBindingFlagBitsEXT; -typedef VkFlags VkDescriptorBindingFlagsEXT; -typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t bindingCount; - const VkDescriptorBindingFlagsEXT* pBindingFlags; -} VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; - -typedef struct VkPhysicalDeviceDescriptorIndexingFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; -} VkPhysicalDeviceDescriptorIndexingFeaturesEXT; - -typedef struct VkPhysicalDeviceDescriptorIndexingPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; -} VkPhysicalDeviceDescriptorIndexingPropertiesEXT; - -typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t descriptorSetCount; - const uint32_t* pDescriptorCounts; -} VkDescriptorSetVariableDescriptorCountAllocateInfoEXT; - -typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupportEXT { - VkStructureType sType; - void* pNext; - uint32_t maxVariableDescriptorCount; -} VkDescriptorSetVariableDescriptorCountLayoutSupportEXT; - - - -#define VK_EXT_shader_viewport_index_layer 1 -#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 -#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" - - -#define VK_NV_shading_rate_image 1 -#define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 -#define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image" - -typedef enum VkShadingRatePaletteEntryNV { - VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV = 0, - VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV = 1, - VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV = 2, - VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV = 3, - VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV = 4, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV = 5, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV = 6, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV = 7, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, - VK_SHADING_RATE_PALETTE_ENTRY_BEGIN_RANGE_NV = VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV, - VK_SHADING_RATE_PALETTE_ENTRY_END_RANGE_NV = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV, - VK_SHADING_RATE_PALETTE_ENTRY_RANGE_SIZE_NV = (VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV - VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV + 1), - VK_SHADING_RATE_PALETTE_ENTRY_MAX_ENUM_NV = 0x7FFFFFFF -} VkShadingRatePaletteEntryNV; - -typedef enum VkCoarseSampleOrderTypeNV { - VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, - VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, - VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, - VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, - VK_COARSE_SAMPLE_ORDER_TYPE_BEGIN_RANGE_NV = VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV, - VK_COARSE_SAMPLE_ORDER_TYPE_END_RANGE_NV = VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV, - VK_COARSE_SAMPLE_ORDER_TYPE_RANGE_SIZE_NV = (VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV - VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV + 1), - VK_COARSE_SAMPLE_ORDER_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkCoarseSampleOrderTypeNV; -typedef struct VkShadingRatePaletteNV { - uint32_t shadingRatePaletteEntryCount; - const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries; -} VkShadingRatePaletteNV; - -typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 shadingRateImageEnable; - uint32_t viewportCount; - const VkShadingRatePaletteNV* pShadingRatePalettes; -} VkPipelineViewportShadingRateImageStateCreateInfoNV; - -typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 shadingRateImage; - VkBool32 shadingRateCoarseSampleOrder; -} VkPhysicalDeviceShadingRateImageFeaturesNV; - -typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV { - VkStructureType sType; - void* pNext; - VkExtent2D shadingRateTexelSize; - uint32_t shadingRatePaletteSize; - uint32_t shadingRateMaxCoarseSamples; -} VkPhysicalDeviceShadingRateImagePropertiesNV; - -typedef struct VkCoarseSampleLocationNV { - uint32_t pixelX; - uint32_t pixelY; - uint32_t sample; -} VkCoarseSampleLocationNV; - -typedef struct VkCoarseSampleOrderCustomNV { - VkShadingRatePaletteEntryNV shadingRate; - uint32_t sampleCount; - uint32_t sampleLocationCount; - const VkCoarseSampleLocationNV* pSampleLocations; -} VkCoarseSampleOrderCustomNV; - -typedef struct VkPipelineViewportCoarseSampleOrderStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkCoarseSampleOrderTypeNV sampleOrderType; - uint32_t customSampleOrderCount; - const VkCoarseSampleOrderCustomNV* pCustomSampleOrders; -} VkPipelineViewportCoarseSampleOrderStateCreateInfoNV; - -typedef void (VKAPI_PTR *PFN_vkCmdBindShadingRateImageNV)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV* pShadingRatePalettes); -typedef void (VKAPI_PTR *PFN_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdBindShadingRateImageNV( - VkCommandBuffer commandBuffer, - VkImageView imageView, - VkImageLayout imageLayout); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportShadingRatePaletteNV( - VkCommandBuffer commandBuffer, - uint32_t firstViewport, - uint32_t viewportCount, - const VkShadingRatePaletteNV* pShadingRatePalettes); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetCoarseSampleOrderNV( - VkCommandBuffer commandBuffer, - VkCoarseSampleOrderTypeNV sampleOrderType, - uint32_t customSampleOrderCount, - const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); -#endif - - -#define VK_NV_ray_tracing 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) -#define VK_NV_RAY_TRACING_SPEC_VERSION 3 -#define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" -#define VK_SHADER_UNUSED_NV (~0U) - -typedef enum VkRayTracingShaderGroupTypeNV { - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0, - VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1, - VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2, - VK_RAY_TRACING_SHADER_GROUP_TYPE_BEGIN_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV, - VK_RAY_TRACING_SHADER_GROUP_TYPE_END_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV, - VK_RAY_TRACING_SHADER_GROUP_TYPE_RANGE_SIZE_NV = (VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV + 1), - VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkRayTracingShaderGroupTypeNV; - -typedef enum VkGeometryTypeNV { - VK_GEOMETRY_TYPE_TRIANGLES_NV = 0, - VK_GEOMETRY_TYPE_AABBS_NV = 1, - VK_GEOMETRY_TYPE_BEGIN_RANGE_NV = VK_GEOMETRY_TYPE_TRIANGLES_NV, - VK_GEOMETRY_TYPE_END_RANGE_NV = VK_GEOMETRY_TYPE_AABBS_NV, - VK_GEOMETRY_TYPE_RANGE_SIZE_NV = (VK_GEOMETRY_TYPE_AABBS_NV - VK_GEOMETRY_TYPE_TRIANGLES_NV + 1), - VK_GEOMETRY_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkGeometryTypeNV; - -typedef enum VkAccelerationStructureTypeNV { - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1, - VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV, - VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV, - VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1), - VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkAccelerationStructureTypeNV; - -typedef enum VkCopyAccelerationStructureModeNV { - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1, - VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV, - VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV, - VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NV = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV + 1), - VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NV = 0x7FFFFFFF -} VkCopyAccelerationStructureModeNV; - -typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV + 1), - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkAccelerationStructureMemoryRequirementsTypeNV; - -typedef enum VkGeometryFlagBitsNV { - VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002, - VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkGeometryFlagBitsNV; -typedef VkFlags VkGeometryFlagsNV; - -typedef enum VkGeometryInstanceFlagBitsNV { - VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001, - VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002, - VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008, - VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkGeometryInstanceFlagBitsNV; -typedef VkFlags VkGeometryInstanceFlagsNV; - -typedef enum VkBuildAccelerationStructureFlagBitsNV { - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010, - VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkBuildAccelerationStructureFlagBitsNV; -typedef VkFlags VkBuildAccelerationStructureFlagsNV; -typedef struct VkRayTracingShaderGroupCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkRayTracingShaderGroupTypeNV type; - uint32_t generalShader; - uint32_t closestHitShader; - uint32_t anyHitShader; - uint32_t intersectionShader; -} VkRayTracingShaderGroupCreateInfoNV; - -typedef struct VkRayTracingPipelineCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo* pStages; - uint32_t groupCount; - const VkRayTracingShaderGroupCreateInfoNV* pGroups; - uint32_t maxRecursionDepth; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoNV; - -typedef struct VkGeometryTrianglesNV { - VkStructureType sType; - const void* pNext; - VkBuffer vertexData; - VkDeviceSize vertexOffset; - uint32_t vertexCount; - VkDeviceSize vertexStride; - VkFormat vertexFormat; - VkBuffer indexData; - VkDeviceSize indexOffset; - uint32_t indexCount; - VkIndexType indexType; - VkBuffer transformData; - VkDeviceSize transformOffset; -} VkGeometryTrianglesNV; - -typedef struct VkGeometryAABBNV { - VkStructureType sType; - const void* pNext; - VkBuffer aabbData; - uint32_t numAABBs; - uint32_t stride; - VkDeviceSize offset; -} VkGeometryAABBNV; - -typedef struct VkGeometryDataNV { - VkGeometryTrianglesNV triangles; - VkGeometryAABBNV aabbs; -} VkGeometryDataNV; - -typedef struct VkGeometryNV { - VkStructureType sType; - const void* pNext; - VkGeometryTypeNV geometryType; - VkGeometryDataNV geometry; - VkGeometryFlagsNV flags; -} VkGeometryNV; - -typedef struct VkAccelerationStructureInfoNV { - VkStructureType sType; - const void* pNext; - VkAccelerationStructureTypeNV type; - VkBuildAccelerationStructureFlagsNV flags; - uint32_t instanceCount; - uint32_t geometryCount; - const VkGeometryNV* pGeometries; -} VkAccelerationStructureInfoNV; - -typedef struct VkAccelerationStructureCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkDeviceSize compactedSize; - VkAccelerationStructureInfoNV info; -} VkAccelerationStructureCreateInfoNV; - -typedef struct VkBindAccelerationStructureMemoryInfoNV { - VkStructureType sType; - const void* pNext; - VkAccelerationStructureNV accelerationStructure; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - uint32_t deviceIndexCount; - const uint32_t* pDeviceIndices; -} VkBindAccelerationStructureMemoryInfoNV; - -typedef struct VkWriteDescriptorSetAccelerationStructureNV { - VkStructureType sType; - const void* pNext; - uint32_t accelerationStructureCount; - const VkAccelerationStructureNV* pAccelerationStructures; -} VkWriteDescriptorSetAccelerationStructureNV; - -typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { - VkStructureType sType; - const void* pNext; - VkAccelerationStructureMemoryRequirementsTypeNV type; - VkAccelerationStructureNV accelerationStructure; -} VkAccelerationStructureMemoryRequirementsInfoNV; - -typedef struct VkPhysicalDeviceRayTracingPropertiesNV { - VkStructureType sType; - void* pNext; - uint32_t shaderGroupHandleSize; - uint32_t maxRecursionDepth; - uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; - uint64_t maxGeometryCount; - uint64_t maxInstanceCount; - uint64_t maxTriangleCount; - uint32_t maxDescriptorSetAccelerationStructures; -} VkPhysicalDeviceRayTracingPropertiesNV; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure); -typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); -typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); -typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); -typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode); -typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); -typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData); -typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); -typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV( - VkDevice device, - const VkAccelerationStructureCreateInfoNV* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkAccelerationStructureNV* pAccelerationStructure); - -VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV( - VkDevice device, - VkAccelerationStructureNV accelerationStructure, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV( - VkDevice device, - const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, - VkMemoryRequirements2KHR* pMemoryRequirements); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV( - VkDevice device, - uint32_t bindInfoCount, - const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); - -VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV( - VkCommandBuffer commandBuffer, - const VkAccelerationStructureInfoNV* pInfo, - VkBuffer instanceData, - VkDeviceSize instanceOffset, - VkBool32 update, - VkAccelerationStructureNV dst, - VkAccelerationStructureNV src, - VkBuffer scratch, - VkDeviceSize scratchOffset); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV( - VkCommandBuffer commandBuffer, - VkAccelerationStructureNV dst, - VkAccelerationStructureNV src, - VkCopyAccelerationStructureModeNV mode); - -VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV( - VkCommandBuffer commandBuffer, - VkBuffer raygenShaderBindingTableBuffer, - VkDeviceSize raygenShaderBindingOffset, - VkBuffer missShaderBindingTableBuffer, - VkDeviceSize missShaderBindingOffset, - VkDeviceSize missShaderBindingStride, - VkBuffer hitShaderBindingTableBuffer, - VkDeviceSize hitShaderBindingOffset, - VkDeviceSize hitShaderBindingStride, - VkBuffer callableShaderBindingTableBuffer, - VkDeviceSize callableShaderBindingOffset, - VkDeviceSize callableShaderBindingStride, - uint32_t width, - uint32_t height, - uint32_t depth); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV( - VkDevice device, - VkPipelineCache pipelineCache, - uint32_t createInfoCount, - const VkRayTracingPipelineCreateInfoNV* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV( - VkDevice device, - VkPipeline pipeline, - uint32_t firstGroup, - uint32_t groupCount, - size_t dataSize, - void* pData); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV( - VkDevice device, - VkAccelerationStructureNV accelerationStructure, - size_t dataSize, - void* pData); - -VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV( - VkCommandBuffer commandBuffer, - uint32_t accelerationStructureCount, - const VkAccelerationStructureNV* pAccelerationStructures, - VkQueryType queryType, - VkQueryPool queryPool, - uint32_t firstQuery); - -VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV( - VkDevice device, - VkPipeline pipeline, - uint32_t shader); -#endif - - -#define VK_NV_representative_fragment_test 1 -#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1 -#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" -typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 representativeFragmentTest; -} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; - -typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 representativeFragmentTestEnable; -} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; - - - -#define VK_EXT_filter_cubic 1 -#define VK_EXT_FILTER_CUBIC_SPEC_VERSION 2 -#define VK_EXT_FILTER_CUBIC_EXTENSION_NAME "VK_EXT_filter_cubic" -typedef struct VkPhysicalDeviceImageViewImageFormatInfoEXT { - VkStructureType sType; - void* pNext; - VkImageViewType imageViewType; -} VkPhysicalDeviceImageViewImageFormatInfoEXT; - -typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { - VkStructureType sType; - void* pNext; - VkBool32 filterCubic; - VkBool32 filterCubicMinmax ; -} VkFilterCubicImageViewImageFormatPropertiesEXT; - - - -#define VK_EXT_global_priority 1 -#define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 -#define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" - -typedef enum VkQueueGlobalPriorityEXT { - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128, - VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256, - VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512, - VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024, - VK_QUEUE_GLOBAL_PRIORITY_BEGIN_RANGE_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT, - VK_QUEUE_GLOBAL_PRIORITY_END_RANGE_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT, - VK_QUEUE_GLOBAL_PRIORITY_RANGE_SIZE_EXT = (VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT + 1), - VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_EXT = 0x7FFFFFFF -} VkQueueGlobalPriorityEXT; -typedef struct VkDeviceQueueGlobalPriorityCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkQueueGlobalPriorityEXT globalPriority; -} VkDeviceQueueGlobalPriorityCreateInfoEXT; - - - -#define VK_EXT_external_memory_host 1 -#define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 -#define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" -typedef struct VkImportMemoryHostPointerInfoEXT { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBits handleType; - void* pHostPointer; -} VkImportMemoryHostPointerInfoEXT; - -typedef struct VkMemoryHostPointerPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t memoryTypeBits; -} VkMemoryHostPointerPropertiesEXT; - -typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { - VkStructureType sType; - void* pNext; - VkDeviceSize minImportedHostPointerAlignment; -} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void* pHostPointer, VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT( - VkDevice device, - VkExternalMemoryHandleTypeFlagBits handleType, - const void* pHostPointer, - VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); -#endif - - -#define VK_AMD_buffer_marker 1 -#define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 -#define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" -typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarkerAMD( - VkCommandBuffer commandBuffer, - VkPipelineStageFlagBits pipelineStage, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - uint32_t marker); -#endif - - -#define VK_EXT_calibrated_timestamps 1 -#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 -#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" - -typedef enum VkTimeDomainEXT { - VK_TIME_DOMAIN_DEVICE_EXT = 0, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, - VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, - VK_TIME_DOMAIN_BEGIN_RANGE_EXT = VK_TIME_DOMAIN_DEVICE_EXT, - VK_TIME_DOMAIN_END_RANGE_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT, - VK_TIME_DOMAIN_RANGE_SIZE_EXT = (VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT - VK_TIME_DOMAIN_DEVICE_EXT + 1), - VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF -} VkTimeDomainEXT; -typedef struct VkCalibratedTimestampInfoEXT { - VkStructureType sType; - const void* pNext; - VkTimeDomainEXT timeDomain; -} VkCalibratedTimestampInfoEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains); -typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( - VkPhysicalDevice physicalDevice, - uint32_t* pTimeDomainCount, - VkTimeDomainEXT* pTimeDomains); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT( - VkDevice device, - uint32_t timestampCount, - const VkCalibratedTimestampInfoEXT* pTimestampInfos, - uint64_t* pTimestamps, - uint64_t* pMaxDeviation); -#endif - - -#define VK_AMD_shader_core_properties 1 -#define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 -#define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" -typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { - VkStructureType sType; - void* pNext; - uint32_t shaderEngineCount; - uint32_t shaderArraysPerEngineCount; - uint32_t computeUnitsPerShaderArray; - uint32_t simdPerComputeUnit; - uint32_t wavefrontsPerSimd; - uint32_t wavefrontSize; - uint32_t sgprsPerSimd; - uint32_t minSgprAllocation; - uint32_t maxSgprAllocation; - uint32_t sgprAllocationGranularity; - uint32_t vgprsPerSimd; - uint32_t minVgprAllocation; - uint32_t maxVgprAllocation; - uint32_t vgprAllocationGranularity; -} VkPhysicalDeviceShaderCorePropertiesAMD; - - - -#define VK_AMD_memory_overallocation_behavior 1 -#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 -#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" - -typedef enum VkMemoryOverallocationBehaviorAMD { - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_BEGIN_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_END_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_RANGE_SIZE_AMD = (VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD + 1), - VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF -} VkMemoryOverallocationBehaviorAMD; -typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { - VkStructureType sType; - const void* pNext; - VkMemoryOverallocationBehaviorAMD overallocationBehavior; -} VkDeviceMemoryOverallocationCreateInfoAMD; - - - -#define VK_EXT_vertex_attribute_divisor 1 -#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 -#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" -typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxVertexAttribDivisor; -} VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT; - -typedef struct VkVertexInputBindingDivisorDescriptionEXT { - uint32_t binding; - uint32_t divisor; -} VkVertexInputBindingDivisorDescriptionEXT; - -typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t vertexBindingDivisorCount; - const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors; -} VkPipelineVertexInputDivisorStateCreateInfoEXT; - -typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 vertexAttributeInstanceRateDivisor; - VkBool32 vertexAttributeInstanceRateZeroDivisor; -} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; - - - -#define VK_EXT_pipeline_creation_feedback 1 -#define VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION 1 -#define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME "VK_EXT_pipeline_creation_feedback" - -typedef enum VkPipelineCreationFeedbackFlagBitsEXT { - VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = 0x00000001, - VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = 0x00000002, - VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = 0x00000004, - VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkPipelineCreationFeedbackFlagBitsEXT; -typedef VkFlags VkPipelineCreationFeedbackFlagsEXT; -typedef struct VkPipelineCreationFeedbackEXT { - VkPipelineCreationFeedbackFlagsEXT flags; - uint64_t duration; -} VkPipelineCreationFeedbackEXT; - -typedef struct VkPipelineCreationFeedbackCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPipelineCreationFeedbackEXT* pPipelineCreationFeedback; - uint32_t pipelineStageCreationFeedbackCount; - VkPipelineCreationFeedbackEXT* pPipelineStageCreationFeedbacks; -} VkPipelineCreationFeedbackCreateInfoEXT; - - - -#define VK_NV_shader_subgroup_partitioned 1 -#define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1 -#define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned" - - -#define VK_NV_compute_shader_derivatives 1 -#define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 -#define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" -typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 computeDerivativeGroupQuads; - VkBool32 computeDerivativeGroupLinear; -} VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; - - - -#define VK_NV_mesh_shader 1 -#define VK_NV_MESH_SHADER_SPEC_VERSION 1 -#define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" -typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 taskShader; - VkBool32 meshShader; -} VkPhysicalDeviceMeshShaderFeaturesNV; - -typedef struct VkPhysicalDeviceMeshShaderPropertiesNV { - VkStructureType sType; - void* pNext; - uint32_t maxDrawMeshTasksCount; - uint32_t maxTaskWorkGroupInvocations; - uint32_t maxTaskWorkGroupSize[3]; - uint32_t maxTaskTotalMemorySize; - uint32_t maxTaskOutputCount; - uint32_t maxMeshWorkGroupInvocations; - uint32_t maxMeshWorkGroupSize[3]; - uint32_t maxMeshTotalMemorySize; - uint32_t maxMeshOutputVertices; - uint32_t maxMeshOutputPrimitives; - uint32_t maxMeshMultiviewViewCount; - uint32_t meshOutputPerVertexGranularity; - uint32_t meshOutputPerPrimitiveGranularity; -} VkPhysicalDeviceMeshShaderPropertiesNV; - -typedef struct VkDrawMeshTasksIndirectCommandNV { - uint32_t taskCount; - uint32_t firstTask; -} VkDrawMeshTasksIndirectCommandNV; - -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksNV)(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksNV( - VkCommandBuffer commandBuffer, - uint32_t taskCount, - uint32_t firstTask); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectNV( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountNV( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); -#endif - - -#define VK_NV_fragment_shader_barycentric 1 -#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 -#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" -typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 fragmentShaderBarycentric; -} VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; - - - -#define VK_NV_shader_image_footprint 1 -#define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 1 -#define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" -typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 imageFootprint; -} VkPhysicalDeviceShaderImageFootprintFeaturesNV; - - - -#define VK_NV_scissor_exclusive 1 -#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 1 -#define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" -typedef struct VkPipelineViewportExclusiveScissorStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - uint32_t exclusiveScissorCount; - const VkRect2D* pExclusiveScissors; -} VkPipelineViewportExclusiveScissorStateCreateInfoNV; - -typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 exclusiveScissor; -} VkPhysicalDeviceExclusiveScissorFeaturesNV; - -typedef void (VKAPI_PTR *PFN_vkCmdSetExclusiveScissorNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D* pExclusiveScissors); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetExclusiveScissorNV( - VkCommandBuffer commandBuffer, - uint32_t firstExclusiveScissor, - uint32_t exclusiveScissorCount, - const VkRect2D* pExclusiveScissors); -#endif - - -#define VK_NV_device_diagnostic_checkpoints 1 -#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 -#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" -typedef struct VkQueueFamilyCheckpointPropertiesNV { - VkStructureType sType; - void* pNext; - VkPipelineStageFlags checkpointExecutionStageMask; -} VkQueueFamilyCheckpointPropertiesNV; - -typedef struct VkCheckpointDataNV { - VkStructureType sType; - void* pNext; - VkPipelineStageFlagBits stage; - void* pCheckpointMarker; -} VkCheckpointDataNV; - -typedef void (VKAPI_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer commandBuffer, const void* pCheckpointMarker); -typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointDataNV* pCheckpointData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetCheckpointNV( - VkCommandBuffer commandBuffer, - const void* pCheckpointMarker); - -VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointDataNV( - VkQueue queue, - uint32_t* pCheckpointDataCount, - VkCheckpointDataNV* pCheckpointData); -#endif - - -#define VK_INTEL_shader_integer_functions2 1 -#define VK_INTEL_SHADER_INTEGER_FUNCTIONS2_SPEC_VERSION 1 -#define VK_INTEL_SHADER_INTEGER_FUNCTIONS2_EXTENSION_NAME "VK_INTEL_shader_integer_functions2" -typedef struct VkPhysicalDeviceShaderIntegerFunctions2INTEL { - VkStructureType sType; - void* pNext; - VkBool32 shaderIntegerFunctions2; -} VkPhysicalDeviceShaderIntegerFunctions2INTEL; - - - -#define VK_INTEL_performance_query 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) -#define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 1 -#define VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME "VK_INTEL_performance_query" - -typedef enum VkPerformanceConfigurationTypeINTEL { - VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0, - VK_PERFORMANCE_CONFIGURATION_TYPE_BEGIN_RANGE_INTEL = VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL, - VK_PERFORMANCE_CONFIGURATION_TYPE_END_RANGE_INTEL = VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL, - VK_PERFORMANCE_CONFIGURATION_TYPE_RANGE_SIZE_INTEL = (VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL - VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL + 1), - VK_PERFORMANCE_CONFIGURATION_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF -} VkPerformanceConfigurationTypeINTEL; - -typedef enum VkQueryPoolSamplingModeINTEL { - VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0, - VK_QUERY_POOL_SAMPLING_MODE_BEGIN_RANGE_INTEL = VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL, - VK_QUERY_POOL_SAMPLING_MODE_END_RANGE_INTEL = VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL, - VK_QUERY_POOL_SAMPLING_MODE_RANGE_SIZE_INTEL = (VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL - VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL + 1), - VK_QUERY_POOL_SAMPLING_MODE_MAX_ENUM_INTEL = 0x7FFFFFFF -} VkQueryPoolSamplingModeINTEL; - -typedef enum VkPerformanceOverrideTypeINTEL { - VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL = 0, - VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1, - VK_PERFORMANCE_OVERRIDE_TYPE_BEGIN_RANGE_INTEL = VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL, - VK_PERFORMANCE_OVERRIDE_TYPE_END_RANGE_INTEL = VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL, - VK_PERFORMANCE_OVERRIDE_TYPE_RANGE_SIZE_INTEL = (VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL - VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL + 1), - VK_PERFORMANCE_OVERRIDE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF -} VkPerformanceOverrideTypeINTEL; - -typedef enum VkPerformanceParameterTypeINTEL { - VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL = 0, - VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1, - VK_PERFORMANCE_PARAMETER_TYPE_BEGIN_RANGE_INTEL = VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL, - VK_PERFORMANCE_PARAMETER_TYPE_END_RANGE_INTEL = VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL, - VK_PERFORMANCE_PARAMETER_TYPE_RANGE_SIZE_INTEL = (VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL - VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL + 1), - VK_PERFORMANCE_PARAMETER_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF -} VkPerformanceParameterTypeINTEL; - -typedef enum VkPerformanceValueTypeINTEL { - VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL = 0, - VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL = 1, - VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL = 2, - VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL = 3, - VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4, - VK_PERFORMANCE_VALUE_TYPE_BEGIN_RANGE_INTEL = VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL, - VK_PERFORMANCE_VALUE_TYPE_END_RANGE_INTEL = VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL, - VK_PERFORMANCE_VALUE_TYPE_RANGE_SIZE_INTEL = (VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL - VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL + 1), - VK_PERFORMANCE_VALUE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF -} VkPerformanceValueTypeINTEL; -typedef union VkPerformanceValueDataINTEL { - uint32_t value32; - uint64_t value64; - float valueFloat; - VkBool32 valueBool; - const char* valueString; -} VkPerformanceValueDataINTEL; - -typedef struct VkPerformanceValueINTEL { - VkPerformanceValueTypeINTEL type; - VkPerformanceValueDataINTEL data; -} VkPerformanceValueINTEL; - -typedef struct VkInitializePerformanceApiInfoINTEL { - VkStructureType sType; - const void* pNext; - void* pUserData; -} VkInitializePerformanceApiInfoINTEL; - -typedef struct VkQueryPoolCreateInfoINTEL { - VkStructureType sType; - const void* pNext; - VkQueryPoolSamplingModeINTEL performanceCountersSampling; -} VkQueryPoolCreateInfoINTEL; - -typedef struct VkPerformanceMarkerInfoINTEL { - VkStructureType sType; - const void* pNext; - uint64_t marker; -} VkPerformanceMarkerInfoINTEL; - -typedef struct VkPerformanceStreamMarkerInfoINTEL { - VkStructureType sType; - const void* pNext; - uint32_t marker; -} VkPerformanceStreamMarkerInfoINTEL; - -typedef struct VkPerformanceOverrideInfoINTEL { - VkStructureType sType; - const void* pNext; - VkPerformanceOverrideTypeINTEL type; - VkBool32 enable; - uint64_t parameter; -} VkPerformanceOverrideInfoINTEL; - -typedef struct VkPerformanceConfigurationAcquireInfoINTEL { - VkStructureType sType; - const void* pNext; - VkPerformanceConfigurationTypeINTEL type; -} VkPerformanceConfigurationAcquireInfoINTEL; - -typedef VkResult (VKAPI_PTR *PFN_vkInitializePerformanceApiINTEL)(VkDevice device, const VkInitializePerformanceApiInfoINTEL* pInitializeInfo); -typedef void (VKAPI_PTR *PFN_vkUninitializePerformanceApiINTEL)(VkDevice device); -typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL* pMarkerInfo); -typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceStreamMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo); -typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceOverrideINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL* pOverrideInfo); -typedef VkResult (VKAPI_PTR *PFN_vkAcquirePerformanceConfigurationINTEL)(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo, VkPerformanceConfigurationINTEL* pConfiguration); -typedef VkResult (VKAPI_PTR *PFN_vkReleasePerformanceConfigurationINTEL)(VkDevice device, VkPerformanceConfigurationINTEL configuration); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSetPerformanceConfigurationINTEL)(VkQueue queue, VkPerformanceConfigurationINTEL configuration); -typedef VkResult (VKAPI_PTR *PFN_vkGetPerformanceParameterINTEL)(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL* pValue); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkInitializePerformanceApiINTEL( - VkDevice device, - const VkInitializePerformanceApiInfoINTEL* pInitializeInfo); - -VKAPI_ATTR void VKAPI_CALL vkUninitializePerformanceApiINTEL( - VkDevice device); - -VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceMarkerINTEL( - VkCommandBuffer commandBuffer, - const VkPerformanceMarkerInfoINTEL* pMarkerInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceStreamMarkerINTEL( - VkCommandBuffer commandBuffer, - const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceOverrideINTEL( - VkCommandBuffer commandBuffer, - const VkPerformanceOverrideInfoINTEL* pOverrideInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkAcquirePerformanceConfigurationINTEL( - VkDevice device, - const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo, - VkPerformanceConfigurationINTEL* pConfiguration); - -VKAPI_ATTR VkResult VKAPI_CALL vkReleasePerformanceConfigurationINTEL( - VkDevice device, - VkPerformanceConfigurationINTEL configuration); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueSetPerformanceConfigurationINTEL( - VkQueue queue, - VkPerformanceConfigurationINTEL configuration); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPerformanceParameterINTEL( - VkDevice device, - VkPerformanceParameterTypeINTEL parameter, - VkPerformanceValueINTEL* pValue); -#endif - - -#define VK_EXT_pci_bus_info 1 -#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 -#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" -typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t pciDomain; - uint32_t pciBus; - uint32_t pciDevice; - uint32_t pciFunction; -} VkPhysicalDevicePCIBusInfoPropertiesEXT; - - - -#define VK_AMD_display_native_hdr 1 -#define VK_AMD_DISPLAY_NATIVE_HDR_SPEC_VERSION 1 -#define VK_AMD_DISPLAY_NATIVE_HDR_EXTENSION_NAME "VK_AMD_display_native_hdr" -typedef struct VkDisplayNativeHdrSurfaceCapabilitiesAMD { - VkStructureType sType; - void* pNext; - VkBool32 localDimmingSupport; -} VkDisplayNativeHdrSurfaceCapabilitiesAMD; - -typedef struct VkSwapchainDisplayNativeHdrCreateInfoAMD { - VkStructureType sType; - const void* pNext; - VkBool32 localDimmingEnable; -} VkSwapchainDisplayNativeHdrCreateInfoAMD; - -typedef void (VKAPI_PTR *PFN_vkSetLocalDimmingAMD)(VkDevice device, VkSwapchainKHR swapChain, VkBool32 localDimmingEnable); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkSetLocalDimmingAMD( - VkDevice device, - VkSwapchainKHR swapChain, - VkBool32 localDimmingEnable); -#endif - - -#define VK_EXT_fragment_density_map 1 -#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 1 -#define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" -typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 fragmentDensityMap; - VkBool32 fragmentDensityMapDynamic; - VkBool32 fragmentDensityMapNonSubsampledImages; -} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; - -typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { - VkStructureType sType; - void* pNext; - VkExtent2D minFragmentDensityTexelSize; - VkExtent2D maxFragmentDensityTexelSize; - VkBool32 fragmentDensityInvocations; -} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; - -typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkAttachmentReference fragmentDensityMapAttachment; -} VkRenderPassFragmentDensityMapCreateInfoEXT; - - - -#define VK_EXT_scalar_block_layout 1 -#define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 -#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" -typedef struct VkPhysicalDeviceScalarBlockLayoutFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 scalarBlockLayout; -} VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; - - - -#define VK_GOOGLE_hlsl_functionality1 1 -#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 1 -#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" - - -#define VK_GOOGLE_decorate_string 1 -#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 -#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" - - -#define VK_EXT_memory_budget 1 -#define VK_EXT_MEMORY_BUDGET_SPEC_VERSION 1 -#define VK_EXT_MEMORY_BUDGET_EXTENSION_NAME "VK_EXT_memory_budget" -typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { - VkStructureType sType; - void* pNext; - VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; - VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; -} VkPhysicalDeviceMemoryBudgetPropertiesEXT; - - - -#define VK_EXT_memory_priority 1 -#define VK_EXT_MEMORY_PRIORITY_SPEC_VERSION 1 -#define VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME "VK_EXT_memory_priority" -typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 memoryPriority; -} VkPhysicalDeviceMemoryPriorityFeaturesEXT; - -typedef struct VkMemoryPriorityAllocateInfoEXT { - VkStructureType sType; - const void* pNext; - float priority; -} VkMemoryPriorityAllocateInfoEXT; - - - -#define VK_NV_dedicated_allocation_image_aliasing 1 -#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION 1 -#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME "VK_NV_dedicated_allocation_image_aliasing" -typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 dedicatedAllocationImageAliasing; -} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; - - - -#define VK_EXT_buffer_device_address 1 -typedef uint64_t VkDeviceAddress; -#define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 -#define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" -typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; - -typedef VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; - -typedef struct VkBufferDeviceAddressInfoEXT { - VkStructureType sType; - const void* pNext; - VkBuffer buffer; -} VkBufferDeviceAddressInfoEXT; - -typedef struct VkBufferDeviceAddressCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkDeviceAddress deviceAddress; -} VkBufferDeviceAddressCreateInfoEXT; - -typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressEXT( - VkDevice device, - const VkBufferDeviceAddressInfoEXT* pInfo); -#endif - - -#define VK_EXT_separate_stencil_usage 1 -#define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 -#define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" -typedef struct VkImageStencilUsageCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkImageUsageFlags stencilUsage; -} VkImageStencilUsageCreateInfoEXT; - - - -#define VK_EXT_validation_features 1 -#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 1 -#define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" - -typedef enum VkValidationFeatureEnableEXT { - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, - VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, - VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, - VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1), - VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkValidationFeatureEnableEXT; - -typedef enum VkValidationFeatureDisableEXT { - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, - VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, - VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, - VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, - VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, - VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, - VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, - VK_VALIDATION_FEATURE_DISABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_ALL_EXT, - VK_VALIDATION_FEATURE_DISABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT, - VK_VALIDATION_FEATURE_DISABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT + 1), - VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkValidationFeatureDisableEXT; -typedef struct VkValidationFeaturesEXT { - VkStructureType sType; - const void* pNext; - uint32_t enabledValidationFeatureCount; - const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; - uint32_t disabledValidationFeatureCount; - const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; -} VkValidationFeaturesEXT; - - - -#define VK_NV_cooperative_matrix 1 -#define VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION 1 -#define VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_NV_cooperative_matrix" - -typedef enum VkComponentTypeNV { - VK_COMPONENT_TYPE_FLOAT16_NV = 0, - VK_COMPONENT_TYPE_FLOAT32_NV = 1, - VK_COMPONENT_TYPE_FLOAT64_NV = 2, - VK_COMPONENT_TYPE_SINT8_NV = 3, - VK_COMPONENT_TYPE_SINT16_NV = 4, - VK_COMPONENT_TYPE_SINT32_NV = 5, - VK_COMPONENT_TYPE_SINT64_NV = 6, - VK_COMPONENT_TYPE_UINT8_NV = 7, - VK_COMPONENT_TYPE_UINT16_NV = 8, - VK_COMPONENT_TYPE_UINT32_NV = 9, - VK_COMPONENT_TYPE_UINT64_NV = 10, - VK_COMPONENT_TYPE_BEGIN_RANGE_NV = VK_COMPONENT_TYPE_FLOAT16_NV, - VK_COMPONENT_TYPE_END_RANGE_NV = VK_COMPONENT_TYPE_UINT64_NV, - VK_COMPONENT_TYPE_RANGE_SIZE_NV = (VK_COMPONENT_TYPE_UINT64_NV - VK_COMPONENT_TYPE_FLOAT16_NV + 1), - VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkComponentTypeNV; - -typedef enum VkScopeNV { - VK_SCOPE_DEVICE_NV = 1, - VK_SCOPE_WORKGROUP_NV = 2, - VK_SCOPE_SUBGROUP_NV = 3, - VK_SCOPE_QUEUE_FAMILY_NV = 5, - VK_SCOPE_BEGIN_RANGE_NV = VK_SCOPE_DEVICE_NV, - VK_SCOPE_END_RANGE_NV = VK_SCOPE_QUEUE_FAMILY_NV, - VK_SCOPE_RANGE_SIZE_NV = (VK_SCOPE_QUEUE_FAMILY_NV - VK_SCOPE_DEVICE_NV + 1), - VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF -} VkScopeNV; -typedef struct VkCooperativeMatrixPropertiesNV { - VkStructureType sType; - void* pNext; - uint32_t MSize; - uint32_t NSize; - uint32_t KSize; - VkComponentTypeNV AType; - VkComponentTypeNV BType; - VkComponentTypeNV CType; - VkComponentTypeNV DType; - VkScopeNV scope; -} VkCooperativeMatrixPropertiesNV; - -typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 cooperativeMatrix; - VkBool32 cooperativeMatrixRobustBufferAccess; -} VkPhysicalDeviceCooperativeMatrixFeaturesNV; - -typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV { - VkStructureType sType; - void* pNext; - VkShaderStageFlags cooperativeMatrixSupportedStages; -} VkPhysicalDeviceCooperativeMatrixPropertiesNV; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesNV( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkCooperativeMatrixPropertiesNV* pProperties); -#endif - - -#define VK_NV_coverage_reduction_mode 1 -#define VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION 1 -#define VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME "VK_NV_coverage_reduction_mode" - -typedef enum VkCoverageReductionModeNV { - VK_COVERAGE_REDUCTION_MODE_MERGE_NV = 0, - VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1, - VK_COVERAGE_REDUCTION_MODE_BEGIN_RANGE_NV = VK_COVERAGE_REDUCTION_MODE_MERGE_NV, - VK_COVERAGE_REDUCTION_MODE_END_RANGE_NV = VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV, - VK_COVERAGE_REDUCTION_MODE_RANGE_SIZE_NV = (VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV - VK_COVERAGE_REDUCTION_MODE_MERGE_NV + 1), - VK_COVERAGE_REDUCTION_MODE_MAX_ENUM_NV = 0x7FFFFFFF -} VkCoverageReductionModeNV; -typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; -typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV { - VkStructureType sType; - void* pNext; - VkBool32 coverageReductionMode; -} VkPhysicalDeviceCoverageReductionModeFeaturesNV; - -typedef struct VkPipelineCoverageReductionStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkPipelineCoverageReductionStateCreateFlagsNV flags; - VkCoverageReductionModeNV coverageReductionMode; -} VkPipelineCoverageReductionStateCreateInfoNV; - -typedef struct VkFramebufferMixedSamplesCombinationNV { - VkStructureType sType; - void* pNext; - VkCoverageReductionModeNV coverageReductionMode; - VkSampleCountFlagBits rasterizationSamples; - VkSampleCountFlags depthStencilSamples; - VkSampleCountFlags colorSamples; -} VkFramebufferMixedSamplesCombinationNV; - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)(VkPhysicalDevice physicalDevice, uint32_t* pCombinationCount, VkFramebufferMixedSamplesCombinationNV* pCombinations); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV( - VkPhysicalDevice physicalDevice, - uint32_t* pCombinationCount, - VkFramebufferMixedSamplesCombinationNV* pCombinations); -#endif - - -#define VK_EXT_fragment_shader_interlock 1 -#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_SPEC_VERSION 1 -#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME "VK_EXT_fragment_shader_interlock" -typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 fragmentShaderSampleInterlock; - VkBool32 fragmentShaderPixelInterlock; - VkBool32 fragmentShaderShadingRateInterlock; -} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; - - - -#define VK_EXT_ycbcr_image_arrays 1 -#define VK_EXT_YCBCR_IMAGE_ARRAYS_SPEC_VERSION 1 -#define VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME "VK_EXT_ycbcr_image_arrays" -typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 ycbcrImageArrays; -} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; - - - -#define VK_EXT_headless_surface 1 -#define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 0 -#define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface" -typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; -typedef struct VkHeadlessSurfaceCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkHeadlessSurfaceCreateFlagsEXT flags; -} VkHeadlessSurfaceCreateInfoEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance instance, const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateHeadlessSurfaceEXT( - VkInstance instance, - const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - - -#define VK_EXT_host_query_reset 1 -#define VK_EXT_HOST_QUERY_RESET_SPEC_VERSION 1 -#define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME "VK_EXT_host_query_reset" -typedef struct VkPhysicalDeviceHostQueryResetFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 hostQueryReset; -} VkPhysicalDeviceHostQueryResetFeaturesEXT; - -typedef void (VKAPI_PTR *PFN_vkResetQueryPoolEXT)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkResetQueryPoolEXT( - VkDevice device, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount); -#endif - - -#define VK_EXT_shader_demote_to_helper_invocation 1 -#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION 1 -#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME "VK_EXT_shader_demote_to_helper_invocation" -typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 shaderDemoteToHelperInvocation; -} VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; - - - -#define VK_EXT_texel_buffer_alignment 1 -#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION 1 -#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME "VK_EXT_texel_buffer_alignment" -typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 texelBufferAlignment; -} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; - -typedef struct VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT { - VkStructureType sType; - void* pNext; - VkDeviceSize storageTexelBufferOffsetAlignmentBytes; - VkBool32 storageTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; - VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; -} VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_fuchsia.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_fuchsia.h deleted file mode 100644 index 4c62a7c2f76..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_fuchsia.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef VULKAN_FUCHSIA_H_ -#define VULKAN_FUCHSIA_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_FUCHSIA_imagepipe_surface 1 -#define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1 -#define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface" -typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; -typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA { - VkStructureType sType; - const void* pNext; - VkImagePipeSurfaceCreateFlagsFUCHSIA flags; - zx_handle_t imagePipeHandle; -} VkImagePipeSurfaceCreateInfoFUCHSIA; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateImagePipeSurfaceFUCHSIA)(VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateImagePipeSurfaceFUCHSIA( - VkInstance instance, - const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_ggp.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_ggp.h deleted file mode 100644 index 3d67c4b8c1e..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_ggp.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef VULKAN_GGP_H_ -#define VULKAN_GGP_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_GGP_stream_descriptor_surface 1 -#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION 1 -#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME "VK_GGP_stream_descriptor_surface" -typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; -typedef struct VkStreamDescriptorSurfaceCreateInfoGGP { - VkStructureType sType; - const void* pNext; - VkStreamDescriptorSurfaceCreateFlagsGGP flags; - GgpStreamDescriptor streamDescriptor; -} VkStreamDescriptorSurfaceCreateInfoGGP; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateStreamDescriptorSurfaceGGP)(VkInstance instance, const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateStreamDescriptorSurfaceGGP( - VkInstance instance, - const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - - -#define VK_GGP_frame_token 1 -#define VK_GGP_FRAME_TOKEN_SPEC_VERSION 1 -#define VK_GGP_FRAME_TOKEN_EXTENSION_NAME "VK_GGP_frame_token" -typedef struct VkPresentFrameTokenGGP { - VkStructureType sType; - const void* pNext; - GgpFrameToken frameToken; -} VkPresentFrameTokenGGP; - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_ios.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_ios.h deleted file mode 100644 index 1846df52d5e..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_ios.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef VULKAN_IOS_H_ -#define VULKAN_IOS_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_MVK_ios_surface 1 -#define VK_MVK_IOS_SURFACE_SPEC_VERSION 2 -#define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface" -typedef VkFlags VkIOSSurfaceCreateFlagsMVK; -typedef struct VkIOSSurfaceCreateInfoMVK { - VkStructureType sType; - const void* pNext; - VkIOSSurfaceCreateFlagsMVK flags; - const void* pView; -} VkIOSSurfaceCreateInfoMVK; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK( - VkInstance instance, - const VkIOSSurfaceCreateInfoMVK* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_macos.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_macos.h deleted file mode 100644 index dca623b042b..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_macos.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef VULKAN_MACOS_H_ -#define VULKAN_MACOS_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_MVK_macos_surface 1 -#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 2 -#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" -typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; -typedef struct VkMacOSSurfaceCreateInfoMVK { - VkStructureType sType; - const void* pNext; - VkMacOSSurfaceCreateFlagsMVK flags; - const void* pView; -} VkMacOSSurfaceCreateInfoMVK; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK( - VkInstance instance, - const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_metal.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_metal.h deleted file mode 100644 index 16505237dfa..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_metal.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef VULKAN_METAL_H_ -#define VULKAN_METAL_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_EXT_metal_surface 1 - -#ifdef __OBJC__ -@class CAMetalLayer; -#else -typedef void CAMetalLayer; -#endif - -#define VK_EXT_METAL_SURFACE_SPEC_VERSION 1 -#define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface" -typedef VkFlags VkMetalSurfaceCreateFlagsEXT; -typedef struct VkMetalSurfaceCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkMetalSurfaceCreateFlagsEXT flags; - const CAMetalLayer* pLayer; -} VkMetalSurfaceCreateInfoEXT; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateMetalSurfaceEXT)(VkInstance instance, const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateMetalSurfaceEXT( - VkInstance instance, - const VkMetalSurfaceCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_vi.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_vi.h deleted file mode 100644 index 50aa27dfb92..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_vi.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef VULKAN_VI_H_ -#define VULKAN_VI_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_NN_vi_surface 1 -#define VK_NN_VI_SURFACE_SPEC_VERSION 1 -#define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface" -typedef VkFlags VkViSurfaceCreateFlagsNN; -typedef struct VkViSurfaceCreateInfoNN { - VkStructureType sType; - const void* pNext; - VkViSurfaceCreateFlagsNN flags; - void* window; -} VkViSurfaceCreateInfoNN; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN( - VkInstance instance, - const VkViSurfaceCreateInfoNN* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_wayland.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_wayland.h deleted file mode 100644 index 12a5f045c1b..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_wayland.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef VULKAN_WAYLAND_H_ -#define VULKAN_WAYLAND_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_KHR_wayland_surface 1 -#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6 -#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" -typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; -typedef struct VkWaylandSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkWaylandSurfaceCreateFlagsKHR flags; - struct wl_display* display; - struct wl_surface* surface; -} VkWaylandSurfaceCreateInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR( - VkInstance instance, - const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); - -VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - struct wl_display* display); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_xcb.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_xcb.h deleted file mode 100644 index 7d6905d2d61..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_xcb.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef VULKAN_XCB_H_ -#define VULKAN_XCB_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_KHR_xcb_surface 1 -#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 -#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" -typedef VkFlags VkXcbSurfaceCreateFlagsKHR; -typedef struct VkXcbSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkXcbSurfaceCreateFlagsKHR flags; - xcb_connection_t* connection; - xcb_window_t window; -} VkXcbSurfaceCreateInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( - VkInstance instance, - const VkXcbSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); - -VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - xcb_connection_t* connection, - xcb_visualid_t visual_id); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_xlib.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_xlib.h deleted file mode 100644 index 7a05d297df0..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_xlib.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef VULKAN_XLIB_H_ -#define VULKAN_XLIB_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_KHR_xlib_surface 1 -#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 -#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" -typedef VkFlags VkXlibSurfaceCreateFlagsKHR; -typedef struct VkXlibSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkXlibSurfaceCreateFlagsKHR flags; - Display* dpy; - Window window; -} VkXlibSurfaceCreateInfoKHR; - -typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( - VkInstance instance, - const VkXlibSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); - -VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - Display* dpy, - VisualID visualID); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/rendering/vulkan/thirdparty/vulkan/vulkan_xlib_xrandr.h b/src/rendering/vulkan/thirdparty/vulkan/vulkan_xlib_xrandr.h deleted file mode 100644 index 3a209530834..00000000000 --- a/src/rendering/vulkan/thirdparty/vulkan/vulkan_xlib_xrandr.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef VULKAN_XLIB_XRANDR_H_ -#define VULKAN_XLIB_XRANDR_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2019 The Khronos Group Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - - -#define VK_EXT_acquire_xlib_display 1 -#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1 -#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display" -typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display); -typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT( - VkPhysicalDevice physicalDevice, - Display* dpy, - VkDisplayKHR display); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT( - VkPhysicalDevice physicalDevice, - Display* dpy, - RROutput rrOutput, - VkDisplayKHR* pDisplay); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/scripting/backend/codegen_doom.cpp b/src/scripting/backend/codegen_doom.cpp new file mode 100644 index 00000000000..0e52790d723 --- /dev/null +++ b/src/scripting/backend/codegen_doom.cpp @@ -0,0 +1,1333 @@ +/* +** codegen.cpp +** +** Compiler backend / code generation for ZScript and DECORATE +** +**--------------------------------------------------------------------------- +** Copyright 2008-2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "cmdlib.h" +#include "codegen.h" +#include "codegen_doom.h" +#include "v_text.h" +#include "filesystem.h" +#include "v_video.h" +#include "utf8.h" +#include "texturemanager.h" +#include "m_random.h" +#include "v_font.h" + +#include "actor.h" +#include "p_lnspec.h" +#include "g_levellocals.h" + +PFunction* FindBuiltinFunction(FName funcname); + +//========================================================================== +// +// +// +//========================================================================== + +bool ShouldAllowGameSpecificVirtual(FName name, unsigned index, PType* arg, PType* varg) +{ + return (name == NAME_Morph && index == 3u && arg->isClassPointer() && varg->isClassPointer() + && PType::toClassPointer(varg)->ClassRestriction->TypeName == NAME_Actor + && PType::toClassPointer(arg)->ClassRestriction->TypeName == NAME_MorphedMonster); +} + +//========================================================================== +// +// +// +//========================================================================== + +bool isActor(PContainerType *type) +{ + auto cls = PType::toClass(type); + return cls ? cls->Descriptor->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; +} + +//========================================================================== +// +// +// +//========================================================================== + +static FxExpression *CustomTypeCast(FxTypeCast *func, FCompileContext &ctx) +{ + if (func->ValueType == TypeStateLabel) + { + auto& basex = func->basex; + auto& ScriptPosition = func->ScriptPosition; + if (basex->ValueType == TypeNullPtr) + { + auto x = new FxConstant(0, ScriptPosition); + x->ValueType = TypeStateLabel; + delete func; + return x; + } + // Right now this only supports string constants. There should be an option to pass a string variable, too. + if (basex->isConstant() && (basex->ValueType == TypeString || basex->ValueType == TypeName)) + { + FString s= static_cast(basex)->GetValue().GetString(); + if (s.Len() == 0 && !ctx.FromDecorate) // DECORATE should never get here at all, but let's better be safe. + { + ScriptPosition.Message(MSG_ERROR, "State jump to empty label."); + delete func; + return nullptr; + } + FxExpression *x = new FxMultiNameState(s.GetChars(), basex->ScriptPosition); + x = x->Resolve(ctx); + basex = nullptr; + delete func; + return x; + } + else if (basex->IsNumeric() && basex->ValueType != TypeSound && basex->ValueType != TypeColor) + { + if (ctx.StateIndex < 0) + { + ScriptPosition.Message(MSG_ERROR, "State jumps with index can only be used in anonymous state functions."); + delete func; + return nullptr; + } + if (ctx.StateCount != 1) + { + ScriptPosition.Message(MSG_ERROR, "State jumps with index cannot be used on multistate definitions"); + delete func; + return nullptr; + } + if (basex->isConstant()) + { + int i = static_cast(basex)->GetValue().GetInt(); + if (i <= 0) + { + ScriptPosition.Message(MSG_ERROR, "State index must be positive"); + delete func; + return nullptr; + } + FxExpression *x = new FxStateByIndex(ctx.StateIndex + i, ScriptPosition); + x = x->Resolve(ctx); + basex = nullptr; + delete func; + return x; + } + else + { + FxExpression *x = new FxRuntimeStateIndex(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete func; + return x; + } + } + } + return func; +} + +//========================================================================== +// +// +// +//========================================================================== + +static bool CheckForCustomAddition(FxAddSub *func, FCompileContext &ctx) +{ + if (func->left->ValueType == TypeState && func->right->IsInteger() && func->Operator == '+' && !func->left->isConstant()) + { + // This is the only special case of pointer addition that will be accepted - because it is used quite often in the existing game code. + func->ValueType = TypeState; + func->right = new FxMulDiv('*', func->right, new FxConstant((int)sizeof(FState), func->ScriptPosition)); // multiply by size here, so that constants can be better optimized. + func->right = func->right->Resolve(ctx); + return true; + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +static FxExpression* CheckForDefault(FxIdentifier* func, FCompileContext& ctx) +{ + auto& ScriptPosition = func->ScriptPosition; + + if (func->Identifier == NAME_Default) + { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from constant declaration"); + delete func; + return nullptr; + } + if (ctx.Function->Variants[0].SelfClass == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from static function"); + delete func; + return nullptr; + } + if (!isActor(ctx.Function->Variants[0].SelfClass)) + { + ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); + delete func; + return nullptr; + } + + FxExpression* x = new FxClassDefaults(new FxSelf(ScriptPosition), ScriptPosition); + delete func; + return x->Resolve(ctx); + } + return func; +} + +static FxExpression* CheckForLineSpecial(FxIdentifier* func, FCompileContext& ctx) +{ + auto& ScriptPosition = func->ScriptPosition; + + // and line specials + int num; + if ((num = P_FindLineSpecial(func->Identifier.GetChars(), nullptr, nullptr))) + { + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", func->Identifier.GetChars(), num); + auto newex = new FxConstant(num, ScriptPosition); + delete func; + return newex? newex->Resolve(ctx) : nullptr; + } + return func; +} + +//========================================================================== +// +// +// +//========================================================================== + +static FxExpression *ResolveForDefault(FxIdentifier *expr, FxExpression*& object, PContainerType* objtype, FCompileContext &ctx) +{ + + if (expr->Identifier == NAME_Default) + { + if (!isActor(objtype)) + { + expr->ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); + delete object; + object = nullptr; + return nullptr; + } + + FxExpression * x = new FxClassDefaults(object, expr->ScriptPosition); + object = nullptr; + delete expr; + return x->Resolve(ctx); + } + return expr; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression* CheckForMemberDefault(FxStructMember *func, FCompileContext &ctx) +{ + auto& membervar = func->membervar; + auto& classx = func->classx; + auto& ScriptPosition = func->ScriptPosition; + + if (membervar->SymbolName == NAME_Default) + { + if (!classx->ValueType->isObjectPointer() + || !static_cast(classx->ValueType)->PointedClass()->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type"); + delete func; + return nullptr; + } + FxExpression * x = new FxClassDefaults(classx, ScriptPosition); + classx = nullptr; + delete func; + return x->Resolve(ctx); + } + return func; +} + +//========================================================================== +// +// FxVMFunctionCall :: UnravelVarArgAJump +// +// Converts A_Jump(chance, a, b, c, d) -> A_Jump(chance, RandomPick[cajump](a, b, c, d)) +// so that varargs are restricted to either text formatting or graphics drawing. +// +//========================================================================== +extern FRandom pr_cajump; + +static bool UnravelVarArgAJump(FxVMFunctionCall *func, FCompileContext &ctx) +{ + auto& ArgList = func->ArgList; + FArgumentList rplist; + + for (unsigned i = 1; i < ArgList.Size(); i++) + { + // This needs a bit of casting voodoo because RandomPick wants integer parameters. + auto x = new FxIntCast(new FxTypeCast(ArgList[i], TypeStateLabel, true, true), true, true); + rplist.Push(x->Resolve(ctx)); + ArgList[i] = nullptr; + if (rplist[i - 1] == nullptr) + { + return false; + } + } + FxExpression *x = new FxRandomPick(&pr_cajump, rplist, false, func->ScriptPosition, true); + x = x->Resolve(ctx); + // This cannot be done with a cast because that interprets the value as an index. + // All we want here is to take the literal value and change its type. + if (x) x->ValueType = TypeStateLabel; + ArgList[1] = x; + ArgList.Clamp(2); + return x != nullptr; +} + +static bool AJumpProcessing(FxVMFunctionCall *func, FCompileContext &ctx) +{ + // Unfortunately the PrintableName is the only safe thing to catch this special case here. + // [RL0] It's not valid to access Variant::Implementation on function pointer calls, so skip this + if (!func->FnPtrCall && stricmp(func->Function->Variants[0].Implementation->QualifiedName, "Actor.A_Jump") == 0) + { + // Unravel the varargs part of this function here so that the VM->native interface does not have to deal with it anymore. + if (func->ArgList.Size() > 2) + { + auto ret = UnravelVarArgAJump(func, ctx); + if (!ret) + { + return false; + } + } + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool CheckArgSize(FName fname, FArgumentList &args, int min, int max, FScriptPosition &sc); + +static FxExpression *ResolveGlobalCustomFunction(FxFunctionCall *func, FCompileContext &ctx) +{ + auto& ScriptPosition = func->ScriptPosition; + if (func->MethodName == NAME_GetDefaultByType) + { + if (CheckArgSize(NAME_GetDefaultByType, func->ArgList, 1, 1, ScriptPosition)) + { + auto newfunc = new FxGetDefaultByType(func->ArgList[0]); + func->ArgList[0] = nullptr; + delete func; + return newfunc->Resolve(ctx); + } + } + + int min, max, special; + if (func->MethodName == NAME_ACS_NamedExecuteWithResult || func->MethodName == NAME_CallACS) + { + special = -ACS_ExecuteWithResult; + min = 1; + max = 5; + } + else + { + // This alias is needed because Actor has a Teleport function. + if (func->MethodName == NAME_TeleportSpecial) func->MethodName = NAME_Teleport; + special = P_FindLineSpecial(func->MethodName.GetChars(), &min, &max); + } + if (special != 0 && min >= 0) + { + int paramcount = func->ArgList.Size(); + if (ctx.Function == nullptr || ctx.Class == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call action special %s from constant declaration", func->MethodName.GetChars()); + delete func; + return nullptr; + } + else if (paramcount < min) + { + ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)", + func->MethodName.GetChars(), min, paramcount); + delete func; + return nullptr; + } + else if (paramcount > max) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters for '%s' (expected %d, got %d)", + func->MethodName.GetChars(), max, paramcount); + delete func; + return nullptr; + } + FxExpression *self = (ctx.Function && (ctx.Function->Variants[0].Flags & VARF_Method) && isActor(ctx.Class)) ? new FxSelf(ScriptPosition) : (FxExpression*)new FxConstant(ScriptPosition); + FxExpression *x = new FxActionSpecialCall(self, special, func->ArgList, ScriptPosition); + delete func; + return x->Resolve(ctx); + } + return func; +} + + + +//========================================================================== +// +// FxActionSpecialCall +// +// If special is negative, then the first argument will be treated as a +// name for ACS_NamedExecuteWithResult. +// +//========================================================================== + +FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos) +: FxExpression(EFX_ActionSpecialCall, pos) +{ + Self = self; + Special = special; + ArgList = std::move(args); + while (ArgList.Size() < 5) + { + ArgList.Push(new FxConstant(0, ScriptPosition)); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FxActionSpecialCall::~FxActionSpecialCall() +{ + SAFE_DELETE(Self); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + bool failed = false; + + SAFE_RESOLVE_OPT(Self, ctx); + for (unsigned i = 0; i < ArgList.Size(); i++) + { + ArgList[i] = ArgList[i]->Resolve(ctx); + if (ArgList[i] == nullptr) + { + failed = true; + } + else if (Special < 0 && i == 0) + { + if (ArgList[i]->ValueType == TypeString) + { + ArgList[i] = new FxNameCast(ArgList[i]); + ArgList[i] = ArgList[i]->Resolve(ctx); + if (ArgList[i] == nullptr) + { + failed = true; + } + } + else if (ArgList[i]->ValueType != TypeName) + { + ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i); + failed = true; + } + } + else if (!ArgList[i]->IsInteger()) + { + if (ArgList[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */) + { + ArgList[i] = new FxIntCast(ArgList[i], ctx.FromDecorate); + ArgList[i] = ArgList[i]->Resolve(ctx); + if (ArgList[i] == nullptr) + { + delete this; + return nullptr; + } + } + else + { + ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i); + failed = true; + } + } + } + + + if (failed) + { + delete this; + return nullptr; + } + ValueType = TypeSInt32; + return this; +} + + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinCallLineSpecial(int special, AActor *activator, int arg1, int arg2, int arg3, int arg4, int arg5) +{ + return P_ExecuteSpecial(currentVMLevel , special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinCallLineSpecial, BuiltinCallLineSpecial) +{ + PARAM_PROLOGUE; + PARAM_INT(special); + PARAM_OBJECT(activator, AActor); + PARAM_INT(arg1); + PARAM_INT(arg2); + PARAM_INT(arg3); + PARAM_INT(arg4); + PARAM_INT(arg5); + + ACTION_RETURN_INT(P_ExecuteSpecial(currentVMLevel, special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5)); +} + +ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) +{ + unsigned i = 0; + + // Call the BuiltinCallLineSpecial function to perform the desired special. + auto sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial); + + assert(sym); + auto callfunc = sym->Variants[0].Implementation; + + FunctionCallEmitter emitters(callfunc); + + emitters.AddParameterIntConst(abs(Special)); // pass special number + emitters.AddParameter(build, Self); + + + for (; i < ArgList.Size(); ++i) + { + FxExpression *argex = ArgList[i]; + if (Special < 0 && i == 0) + { + assert(argex->ValueType == TypeName); + assert(argex->isConstant()); + emitters.AddParameterIntConst(-static_cast(argex)->GetValue().GetName().GetIndex()); + } + else + { + assert(argex->ValueType->GetRegType() == REGT_INT); + if (argex->isConstant()) + { + emitters.AddParameterIntConst(static_cast(argex)->GetValue().GetInt()); + } + else + { + emitters.AddParameter(build, argex); + } + } + } + ArgList.DeleteAndClear(); + ArgList.ShrinkToFit(); + + emitters.AddReturn(REGT_INT); + return emitters.EmitCall(build); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxClassDefaults::FxClassDefaults(FxExpression *X, const FScriptPosition &pos) + : FxExpression(EFX_ClassDefaults, pos) +{ + obj = X; +} + +FxClassDefaults::~FxClassDefaults() +{ + SAFE_DELETE(obj); +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxClassDefaults::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(obj, ctx); + assert(obj->ValueType->isRealPointer()); + ValueType = NewPointer(obj->ValueType->toPointer()->PointedType, true); + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) +{ + ExpEmit ob = obj->Emit(build); + ob.Free(build); + ExpEmit meta(build, REGT_POINTER); + build->Emit(OP_CLSS, meta.RegNum, ob.RegNum); + build->Emit(OP_LP, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + return meta; + +} + +//========================================================================== +// +// +//========================================================================== + +FxGetDefaultByType::FxGetDefaultByType(FxExpression *self) + :FxExpression(EFX_GetDefaultByType, self->ScriptPosition) +{ + Self = self; +} + +FxGetDefaultByType::~FxGetDefaultByType() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxGetDefaultByType::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + PClass *cls = nullptr; + + if (Self->ValueType == TypeString || Self->ValueType == TypeName) + { + if (Self->isConstant()) + { + cls = PClass::FindActor(static_cast(Self)->GetValue().GetName()); + if (cls == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type, but got %s", static_cast(Self)->GetValue().GetString().GetChars()); + delete this; + return nullptr; + } + Self = new FxConstant(cls, NewClassPointer(cls), ScriptPosition); + } + else + { + // this is the ugly case. We do not know what we have and cannot do proper type casting. + // For now error out and let this case require explicit handling on the user side. + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type, but got %s", static_cast(Self)->GetValue().GetString().GetChars()); + delete this; + return nullptr; + } + } + else + { + auto cp = PType::toClassPointer(Self->ValueType); + if (cp == nullptr || !cp->ClassRestriction->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type"); + delete this; + return nullptr; + } + cls = cp->ClassRestriction; + } + ValueType = NewPointer(cls, true); + return this; +} + +ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) +{ + ExpEmit op = Self->Emit(build); + op.Free(build); + ExpEmit to(build, REGT_POINTER); + if (op.Konst) + { + build->Emit(OP_LKP, to.RegNum, op.RegNum); + op = to; + } + build->Emit(OP_LP, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + return to; +} + + +//========================================================================== +// +// Symbolic state labels. +// Conversion will not happen inside the compiler anymore because it causes +// just too many problems. +// +//========================================================================== + +FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + ABORT(ctx.Class); + auto vclass = PType::toClass(ctx.Class); + assert(vclass != nullptr); + auto aclass = ValidateActor(vclass->Descriptor); + + // This expression type can only be used from actors, for everything else it has already produced a compile error. + assert(aclass != nullptr && aclass->GetStateCount() > 0); + + if (aclass->GetStateCount() <= index) + { + ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", + ctx.Class->TypeName.GetChars(), index); + delete this; + return nullptr; + } + int symlabel = StateLabels.AddPointer(aclass->GetStates() + index); + FxExpression *x = new FxConstant(symlabel, ScriptPosition); + x->ValueType = TypeStateLabel; + delete this; + return x; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) +: FxExpression(EFX_RuntimeStateIndex, index->ScriptPosition), Index(index) +{ + ValueType = TypeStateLabel; +} + +FxRuntimeStateIndex::~FxRuntimeStateIndex() +{ + SAFE_DELETE(Index); +} + +FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Index, ctx); + + if (!Index->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Index->isConstant()) + { + int index = static_cast(Index)->GetValue().GetInt(); + if (index < 0 || (index == 0 && !ctx.FromDecorate)) + { + ScriptPosition.Message(MSG_ERROR, "State index must be positive"); + delete this; + return nullptr; + } + else if (index == 0) + { + int symlabel = StateLabels.AddPointer(nullptr); + auto x = new FxConstant(symlabel, ScriptPosition); + delete this; + x->ValueType = TypeStateLabel; + return x; + } + else + { + auto x = new FxStateByIndex(ctx.StateIndex + index, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + } + else if (Index->ValueType->GetRegType() != REGT_INT) + { // Float. + Index = new FxIntCast(Index, ctx.FromDecorate); + SAFE_RESOLVE(Index, ctx); + } + + auto vclass = PType::toClass(ctx.Class); + assert(vclass != nullptr); + auto aclass = ValidateActor(vclass->Descriptor); + assert(aclass != nullptr && aclass->GetStateCount() > 0); + + symlabel = StateLabels.AddPointer(aclass->GetStates() + ctx.StateIndex); + ValueType = TypeStateLabel; + return this; +} + +ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) +{ + ExpEmit out = Index->Emit(build); + // out = (clamp(Index, 0, 32767) << 16) | symlabel | 0x80000000; 0x80000000 is here to make it negative. + build->Emit(OP_MAX_RK, out.RegNum, out.RegNum, build->GetConstantInt(0)); + build->Emit(OP_MIN_RK, out.RegNum, out.RegNum, build->GetConstantInt(32767)); + build->Emit(OP_SLL_RI, out.RegNum, out.RegNum, 16); + build->Emit(OP_OR_RK, out.RegNum, out.RegNum, build->GetConstantInt(symlabel|0x80000000)); + return out; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPosition &pos, PClassActor *checkclass) + :FxExpression(EFX_MultiNameState, pos) +{ + FName scopename = NAME_None; + FString statestring = _statestring; + auto scopeindex = statestring.IndexOf("::"); + + if (scopeindex >= 0) + { + scopename = FName(statestring.GetChars(), scopeindex, false); + statestring = statestring.Right((ptrdiff_t)statestring.Len() - scopeindex - 2); + } + names = MakeStateNameList(statestring.GetChars()); + names.Insert(0, scopename); + scope = checkclass; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + ABORT(ctx.Class); + int symlabel; + + auto vclass = PType::toClass(ctx.Class); + //assert(vclass != nullptr); + auto clstype = vclass == nullptr? nullptr : ValidateActor(vclass->Descriptor); + + if (names[0] == NAME_None) + { + scope = nullptr; + } + else if (clstype == nullptr) + { + // not in an actor, so any further checks are pointless. + ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); + delete this; + return nullptr; + } + else if (names[0] == NAME_Super) + { + scope = ValidateActor(clstype->ParentClass); + } + else + { + scope = PClass::FindActor(names[0]); + if (scope == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars()); + delete this; + return nullptr; + } + else if (!scope->IsAncestorOf(clstype)) + { + ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); + delete this; + return nullptr; + } + } + if (scope != nullptr) + { + FState *destination = nullptr; + // If the label is class specific we can resolve it right here + if (names[1] != NAME_None) + { + destination = scope->FindState(names.Size()-1, &names[1], false); + if (destination == nullptr) + { + ScriptPosition.Message(MSG_OPTERROR, "Unknown state jump destination"); + /* lax */ + return this; + } + } + symlabel = StateLabels.AddPointer(destination); + } + else + { + names.Delete(0); + symlabel = StateLabels.AddNames(names); + } + FxExpression *x = new FxConstant(symlabel, ScriptPosition); + x->ValueType = TypeStateLabel; + delete this; + return x; +} + + +//========================================================================== +// +// The CVAR is for finding places where thinkers are created. +// Those will require code changes in ZScript 4.0. +// +//========================================================================== +CVAR(Bool, vm_warnthinkercreation, false, 0) + +static DObject *BuiltinNewDoom(PClass *cls, int outerside, int backwardscompatible) +{ + if (cls == nullptr) + { + ThrowAbortException(X_OTHER, "New without a class"); + return nullptr; + } + if (cls->ConstructNative == nullptr) + { + ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); + return nullptr; + } + if (cls->bAbstract) + { + ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); + return nullptr; + } + // Creating actors here must be outright prohibited, + if (cls->IsDescendantOf(NAME_Actor)) + { + ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); + return nullptr; + } + if (cls->IsDescendantOf(NAME_VisualThinker)) // Same for VisualThinkers. + { + ThrowAbortException(X_OTHER, "Cannot create VisualThinker or inheriting classes with 'new'. Use 'VisualThinker.Spawn' instead."); + return nullptr; + } + if ((vm_warnthinkercreation || !backwardscompatible) && cls->IsDescendantOf(NAME_Thinker)) + { + // This must output a diagnostic warning + Printf("Using 'new' to create thinkers is deprecated."); + } + // [ZZ] validate readonly and between scope construction + if (outerside) FScopeBarrier::ValidateNew(cls, outerside - 1); + DObject *object; + if (!cls->IsDescendantOf(NAME_Thinker)) + { + object = cls->CreateNew(); + } + else + { + object = currentVMLevel->CreateThinker(cls); + } + return object; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinNewDoom, BuiltinNewDoom) +{ + PARAM_PROLOGUE; + PARAM_CLASS(cls, DObject); + PARAM_INT(outerside); + PARAM_INT(compatible); + ACTION_RETURN_OBJECT(BuiltinNewDoom(cls, outerside, compatible)); +} + + +void SetDoomCompileEnvironment() +{ + compileEnvironment.SpecialTypeCast = CustomTypeCast; + compileEnvironment.CheckForCustomAddition = CheckForCustomAddition; + compileEnvironment.CheckSpecialIdentifier = CheckForDefault; + compileEnvironment.CheckSpecialGlobalIdentifier = CheckForLineSpecial; + compileEnvironment.ResolveSpecialIdentifier = ResolveForDefault; + compileEnvironment.CheckSpecialMember = CheckForMemberDefault; + compileEnvironment.ResolveSpecialFunction = AJumpProcessing; + compileEnvironment.CheckCustomGlobalFunctions = ResolveGlobalCustomFunction; + compileEnvironment.CustomBuiltinNew = "BuiltinNewDoom"; +} + + +//========================================================================== +// +// FxCastForEachLoop +// +//========================================================================== + + +class FxCastForEachLoop : public FxTypedForEachLoop +{ +public: + using FxTypedForEachLoop::FxTypedForEachLoop; + + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself +}; + +FxExpression *FxCastForEachLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Expr, ctx); + + if(varName == NAME_None) + { + ScriptPosition.Message(MSG_ERROR, "missing var for foreach(Type var : it )"); + delete this; + return nullptr; + } + + PType * varType = nullptr; + PClass * itType = ((PObjectPointer*)Expr->ValueType)->PointedClass(); + + FName fieldName = NAME_None; + + if(itType->TypeName == NAME_ActorIterator) + { + fieldName = "Actor"; + } + else if(itType->TypeName == NAME_ThinkerIterator) + { + fieldName = "Thinker"; + } + else + { + ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be an actor or thinker iterator, but is a %s",Expr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + + if(className != NAME_None) + { + fieldName = className; + } + + PClass * varTypeClass = PClass::FindClass(fieldName); + varType = varTypeClass->VMType; + + if(!varType) + { + ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - could not find class '%s'",className.GetChars()); + delete this; + return nullptr; + } + + varType = NewPointer(varType, false); + + /* + { + CastType var; + ActorIterator|ThinkerIterator @it = expr; + while(var = CastType(@it.Next())) + body + } + */ + + auto block = new FxCompoundStatement(ScriptPosition); + + block->Add(new FxLocalVariableDeclaration(varType, varName, nullptr, 0, ScriptPosition)); + + block->Add(new FxLocalVariableDeclaration(Expr->ValueType, "@it", Expr, 0, ScriptPosition)); + + auto inner_block = new FxCompoundStatement(ScriptPosition); + + FxExpression * nextCallCast = new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition); + + if(className != NAME_None) + { + nextCallCast = new FxDynamicCast(varTypeClass, nextCallCast); + } + + block->Add(new FxWhileLoop(new FxAssign(new FxIdentifier(varName, ScriptPosition), nextCallCast), Code, ScriptPosition)); + + Expr = Code = nullptr; + delete this; + return block->Resolve(ctx); +} + + + +//========================================================================== +// +// FxBlockIteratorForEachLoop +// +//========================================================================== + +class FxBlockIteratorForEachLoop : public FxThreeArgForEachLoop +{ +public: + using FxThreeArgForEachLoop::FxThreeArgForEachLoop; + + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself +}; + +FxExpression *FxBlockIteratorForEachLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(BlockIteratorExpr, ctx); + + + if(!(BlockIteratorExpr->ValueType->isObjectPointer())) + { + ScriptPosition.Message(MSG_ERROR, "foreach( v, p, f : b ) - 'b' must be a block things or block lines iterator, but is a %s",BlockIteratorExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + else if(varVarName == NAME_None) + { + ScriptPosition.Message(MSG_ERROR, "missing var for foreach( v, p, f : b )"); + delete this; + return nullptr; + } + + PType * varType = nullptr; + PClass * itType = ((PObjectPointer*)BlockIteratorExpr->ValueType)->PointedClass(); + + FName fieldName = NAME_None; + + if(itType->TypeName == NAME_BlockThingsIterator) + { + fieldName = "Thing"; + } + else if(itType->TypeName == NAME_BlockLinesIterator) + { + fieldName = "CurLine"; + } + else + { + ScriptPosition.Message(MSG_ERROR, "foreach( t, p, f : b ) - 'b' must be a block things or block lines iterator, but is a %s",BlockIteratorExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + + auto var = itType->FindSymbol(fieldName, false); + if(var && var->IsKindOf(RUNTIME_CLASS(PField))) + { + varType = static_cast(var)->Type; + } + + /* + { + Line|Actor var; + Vector3 pos; + int flags; + BlockLinesIterator|BlockThingsIterator @it = expr; + while(@it.Next()) + { + var = @it.CurLine|@it.Thing; + pos = @it.position; + flags = @it.portalflags; + body + } + } + */ + + auto block = new FxCompoundStatement(ScriptPosition); + + block->Add(new FxLocalVariableDeclaration(varType, varVarName, nullptr, 0, ScriptPosition)); + if(posVarName != NAME_None) + { + block->Add(new FxLocalVariableDeclaration(TypeVector3, posVarName, nullptr, 0, ScriptPosition)); + } + if(flagsVarName != NAME_None) + { + block->Add(new FxLocalVariableDeclaration(TypeSInt32, flagsVarName, nullptr, 0, ScriptPosition)); + } + + block->Add(new FxLocalVariableDeclaration(BlockIteratorExpr->ValueType, "@it", BlockIteratorExpr, 0, ScriptPosition)); + + auto inner_block = new FxCompoundStatement(ScriptPosition); + + inner_block->Add(new FxAssign(new FxIdentifier(varVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), fieldName, ScriptPosition), true)); + if(posVarName != NAME_None) + { + inner_block->Add(new FxAssign(new FxIdentifier(posVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), "position", ScriptPosition), true)); + } + if(flagsVarName != NAME_None) + { + inner_block->Add(new FxAssign(new FxIdentifier(flagsVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), "portalflags", ScriptPosition), true)); + } + inner_block->Add(Code); + + block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition)); + + BlockIteratorExpr = Code = nullptr; + delete this; + return block->Resolve(ctx); +} + + + + + + + + + + +bool IsGameSpecificForEachLoop(FxForEachLoop * loop) +{ + auto * vt = loop->Array->ValueType; + return (vt->isObjectPointer() && ( + ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_BlockLinesIterator + || ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_BlockThingsIterator + || ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ActorIterator + || ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ThinkerIterator + )); +} + +FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop * loop) +{ + FName cname = ((PObjectPointer*)loop->Array->ValueType)->PointedClass()->TypeName; + assert(loop->Array->ValueType->isObjectPointer()); + if(cname == NAME_BlockLinesIterator || cname == NAME_BlockThingsIterator) + { + auto blockIt = new FxBlockIteratorForEachLoop(loop->loopVarName, NAME_None, NAME_None, loop->Array, loop->Code, loop->ScriptPosition); + loop->Array = loop->Code = nullptr; + delete loop; + return blockIt; + } + else if(cname == NAME_ActorIterator || cname == NAME_ThinkerIterator) + { + auto castIt = new FxCastForEachLoop(NAME_None, loop->loopVarName, loop->Array, loop->Code, loop->ScriptPosition); + loop->Array = loop->Code = nullptr; + delete loop; + return castIt; + } + else + { + delete loop; + return nullptr; + } +} + + +bool HasGameSpecificTwoArgForEachLoopTypeNames() +{ + return true; +} + +const char * GetGameSpecificTwoArgForEachLoopTypeNames() +{ + return "a BlockLinesIterator, a BlockThingsIterator,"; +} + +bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop * loop) +{ + return (loop->MapExpr->ValueType->isObjectPointer() + && (((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator + || ((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator)); +} + +FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop * loop) +{ + assert(loop->MapExpr->ValueType->isObjectPointer()); + assert(((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator); + + auto blockIt = new FxBlockIteratorForEachLoop(loop->keyVarName, loop->valueVarName, NAME_None, loop->MapExpr, loop->Code, loop->ScriptPosition); + loop->MapExpr = loop->Code = nullptr; + delete loop; + return blockIt; +} + + +bool HasGameSpecificThreeArgForEachLoopTypeNames() +{ + return true; +} + +const char * GetGameSpecificThreeArgForEachLoopTypeNames() +{ + return "a BlockLinesIterator or a BlockThingsIterator"; +} + +bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop * loop) +{ + return (loop->BlockIteratorExpr->ValueType->isObjectPointer() + && (((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator + || ((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator)); +} + +FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop * loop) +{ + assert(loop->BlockIteratorExpr->ValueType->isObjectPointer()); + assert(((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator); + + auto blockIt = new FxBlockIteratorForEachLoop(loop->varVarName, loop->posVarName, loop->flagsVarName, loop->BlockIteratorExpr, loop->Code, loop->ScriptPosition); + loop->BlockIteratorExpr = loop->Code = nullptr; + delete loop; + return blockIt; +} + + + + + +bool HasGameSpecificTypedForEachLoopTypeNames() +{ + return true; +} + +const char * GetGameSpecificTypedForEachLoopTypeNames() +{ + return "an ActorIterator or a ThinkerIterator"; +} + +bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop * loop) +{ + auto * vt = loop->Expr->ValueType; + return (vt->isObjectPointer() && ( + ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ActorIterator + || ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ThinkerIterator + )); +} + +FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop * loop) +{ + assert(loop->Expr->ValueType->isObjectPointer()); + assert(((PObjectPointer*)loop->Expr->ValueType)->PointedClass()->TypeName == NAME_ActorIterator || ((PObjectPointer*)loop->Expr->ValueType)->PointedClass()->TypeName == NAME_ThinkerIterator); + + FxExpression * castIt = new FxCastForEachLoop(loop->className, loop->varName, loop->Expr, loop->Code, loop->ScriptPosition); + loop->Expr = loop->Code = nullptr; + delete loop; + return castIt; +} \ No newline at end of file diff --git a/src/scripting/backend/codegen_doom.h b/src/scripting/backend/codegen_doom.h new file mode 100644 index 00000000000..eaa1f9e73be --- /dev/null +++ b/src/scripting/backend/codegen_doom.h @@ -0,0 +1,112 @@ +#pragma once +#include "codegen.h" +#include "actor.h" + +//========================================================================== +// +// FxActionSpecialCall +// +//========================================================================== + +class FxActionSpecialCall : public FxExpression +{ + int Special; + FxExpression *Self; + FArgumentList ArgList; + +public: + + FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos); + ~FxActionSpecialCall(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxClassDefaults +// +//========================================================================== + +class FxClassDefaults : public FxExpression +{ + FxExpression *obj; + +public: + FxClassDefaults(FxExpression *, const FScriptPosition &); + ~FxClassDefaults(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxGetDefaultByType +// +//========================================================================== + +class FxGetDefaultByType : public FxExpression +{ + FxExpression *Self; + +public: + + FxGetDefaultByType(FxExpression *self); + ~FxGetDefaultByType(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// Only used to resolve the old jump by index feature of DECORATE +// +//========================================================================== + +class FxStateByIndex : public FxExpression +{ + unsigned index; + +public: + + FxStateByIndex(int i, const FScriptPosition &pos) : FxExpression(EFX_StateByIndex, pos) + { + index = i; + } + FxExpression *Resolve(FCompileContext&); +}; + +//========================================================================== +// +// Same as above except for expressions which means it will have to be +// evaluated at runtime +// +//========================================================================== + +class FxRuntimeStateIndex : public FxExpression +{ + FxExpression *Index; + int symlabel; + +public: + FxRuntimeStateIndex(FxExpression *index); + ~FxRuntimeStateIndex(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// +// +//========================================================================== + +class FxMultiNameState : public FxExpression +{ + PClassActor *scope; + TArray names; +public: + + FxMultiNameState(const char *statestring, const FScriptPosition &pos, PClassActor *checkclass = nullptr); + FxExpression *Resolve(FCompileContext&); +}; diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 533a39e1a6c..82d40d34d21 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -41,7 +41,7 @@ #include "p_lnspec.h" #include "decallib.h" #include "thingdef.h" -#include "backend/codegen.h" +#include "codegen.h" // TYPES ------------------------------------------------------------------- @@ -113,7 +113,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) bag.fromDecorate = true; bag.Version = { 2, 0, 0 }; #ifdef _DEBUG - bag.ClassName = type->TypeName; + bag.ClassName = type->TypeName.GetChars(); #endif sc.MustGetStringName("{"); @@ -405,7 +405,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (sc.Compare ("Scale")) { sc.MustGetFloat (); - defaults->Scale.X = defaults->Scale.Y = sc.Float; + defaults->Scale.X = defaults->Scale.Y = float(sc.Float); } else if (sc.Compare ("RenderStyle")) { @@ -504,17 +504,17 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, sc.Compare ("DeathSound")) { sc.MustGetString (); - defaults->DeathSound = sc.String; + defaults->DeathSound = S_FindSound(sc.String); } else if (def == DEF_BreakableDecoration && sc.Compare ("BurnDeathSound")) { sc.MustGetString (); - defaults->ActiveSound = sc.String; + defaults->ActiveSound = S_FindSound(sc.String); } else if (def == DEF_Projectile && sc.Compare ("SpawnSound")) { sc.MustGetString (); - defaults->SeeSound = sc.String; + defaults->SeeSound = S_FindSound(sc.String); } else if (def == DEF_Projectile && sc.Compare ("DoomBounce")) { @@ -531,7 +531,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupSound")) { sc.MustGetString (); - defaults->IntVar(NAME_PickupSound) = FSoundID(sc.String); + defaults->IntVar(NAME_PickupSound) = S_FindSound(sc.String).index(); } else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 9b78a5f28de..1b27342be0f 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -42,9 +42,10 @@ #include "cmdlib.h" #include "a_pickups.h" #include "thingdef.h" -#include "backend/codegen.h" +#include "codegen.h" +#include "backend/codegen_doom.h" -FRandom pr_exrandom ("EX_Random"); +extern FRandom pr_exrandom; static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cls); static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor *cls); @@ -82,7 +83,7 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, PNamespace *spc) if (spc) { PClassType *vmtype = nullptr == cls ? nullptr : cls->VMType; - FCompileContext ctx(spc, vmtype, true); + FCompileContext ctx(spc, vmtype, true, MakeVersion(0,0)); data = data->Resolve(ctx); } @@ -476,7 +477,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) { FArgumentList args; args.Push(exp); - exp = new FxFunctionCall(NAME_ResolveState, NAME_None, args, sc); + exp = new FxFunctionCall(NAME_ResolveState, NAME_None, std::move(args), sc); } sc.MustGetToken(')'); return exp; @@ -486,7 +487,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) FName identifier = FName(sc.String); PFunction *func; - switch (identifier) + switch (identifier.GetIndex()) { case NAME_Random: case NAME_FRandom: @@ -511,7 +512,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) ParseFunctionParameters(sc, cls, args, func, "", nullptr); } // FxVMFunctionCall cannot be used here as it lacks some important checks - return new FxFunctionCall(identifier, NAME_None, args, sc); + return new FxFunctionCall(identifier, NAME_None, std::move(args), sc); } } @@ -519,7 +520,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) } if (sc.CheckToken('(')) { - switch (identifier) + switch (identifier.GetIndex()) { case NAME_Min: case NAME_Max: @@ -542,7 +543,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) while (sc.CheckToken(',')); sc.MustGetToken(')'); } - return new FxFunctionCall(identifier, NAME_None, args, sc); + return new FxFunctionCall(identifier, NAME_None, std::move(args), sc); } } else diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index a762c89810a..a1cc7702e96 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -43,8 +43,9 @@ #include "a_pickups.h" #include "thingdef.h" #include "a_morph.h" -#include "backend/codegen.h" -#include "w_wad.h" +#include "codegen.h" +#include "backend/codegen_doom.h" +#include "filesystem.h" #include "v_text.h" #include "m_argv.h" #include "v_video.h" @@ -77,7 +78,21 @@ PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FN { sc.Message(MSG_ERROR, "Parent class %s of %s not accessible to DECORATE", parent->TypeName.GetChars(), typeName.GetChars()); } - PClassActor *type = static_cast(parent->CreateDerivedClass(typeName, parent->Size)); + else + { + // [Player701] Parent class must not have abstract functions + for (auto v : parent->Virtuals) + { + if (v->VarFlags & VARF_Abstract) + { + sc.Message(MSG_ERROR, "Parent class %s of %s cannot have abstract functions.", parent->TypeName.GetChars(), typeName.GetChars()); + break; + } + } + } + + bool newlycreated; + PClassActor *type = static_cast(parent->CreateDerivedClass(typeName, parent->Size, &newlycreated)); if (type == nullptr) { FString newname = typeName.GetChars(); @@ -94,14 +109,15 @@ PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FN // Due to backwards compatibility issues this cannot be an unconditional error. sc.Message(MSG_WARNING, "Tried to define class '%s' more than once. Renaming class to '%s'", typeName.GetChars(), newname.GetChars()); } - type = static_cast(parent->CreateDerivedClass(newname, parent->Size)); + type = static_cast(parent->CreateDerivedClass(newname, parent->Size, &newlycreated)); if (type == nullptr) { // This we cannot handle cleanly anymore. Let's just abort and forget about the odd mod out that was this careless. sc.Message(MSG_FATAL, "Tried to define class '%s' more than twice in the same file.", typeName.GetChars()); } } - + if (newlycreated) type->InitializeDefaults(); + if (type != nullptr) { // [ZZ] DECORATE classes are always play @@ -128,7 +144,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type) if (type == TypeSound) { sc.MustGetString(); - x = new FxConstant(FSoundID(sc.String), sc); + x = new FxConstant(S_FindSound(sc.String), sc); } else if (type == TypeBool || type == TypeSInt32 || type == TypeFloat64) { @@ -174,7 +190,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type) } else { - int c = V_GetColor (NULL, sc); + int c = V_GetColor (sc); // 0 needs to be the default so we have to mark the color. v = MAKEARGB(1, RPART(c), GPART(c), BPART(c)); } @@ -442,7 +458,7 @@ static void ParseActorFlag (FScanner &sc, Baggage &bag, int mod) sc.MustGetString (); part2 = sc.String; } - HandleActorFlag(sc, bag, part1, part2, mod); + HandleActorFlag(sc, bag, part1.GetChars(), part2, mod); } //========================================================================== @@ -706,12 +722,12 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau case 'S': sc.MustGetString(); - conv.s = strings[strings.Reserve(1)] = sc.String; + conv.s = (strings[strings.Reserve(1)] = sc.String).GetChars(); break; case 'T': sc.MustGetString(); - conv.s = strings[strings.Reserve(1)] = strbin1(sc.String); + conv.s = (strings[strings.Reserve(1)] = strbin1(sc.String)).GetChars(); break; case 'C': @@ -731,7 +747,7 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau else { sc.MustGetString (); - conv.s = strings[strings.Reserve(1)] = sc.String; + conv.s = (strings[strings.Reserve(1)] = sc.String).GetChars(); pref.i = 1; } break; @@ -759,7 +775,7 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau do { sc.MustGetString (); - conv.s = strings[strings.Reserve(1)] = sc.String; + conv.s = (strings[strings.Reserve(1)] = sc.String).GetChars(); params.Push(conv); params[0].i++; } @@ -863,12 +879,12 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul else if (f->Type == TypeSound) { sc.MustGetString(); - *(FSoundID*)addr = sc.String; + *(FSoundID*)addr = S_FindSound(sc.String); } else if (f->Type == TypeColor) { if (sc.CheckNumber()) *(int*)addr = sc.Number; - else *(PalEntry*)addr = V_GetColor(nullptr, sc); + else *(PalEntry*)addr = V_GetColor(sc); } else if (f->Type->isIntCompatible()) { @@ -945,7 +961,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) sc.UnGet (); } - FPropertyInfo *prop = FindProperty(propname); + FPropertyInfo *prop = FindProperty(propname.GetChars()); if (prop != NULL) { @@ -960,9 +976,9 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) FScriptPosition::ErrorCounter++; } } - else if (MatchString(propname, statenames) != -1) + else if (MatchString(propname.GetChars(), statenames) != -1) { - bag.statedef.SetStateLabel(propname, CheckState (sc, bag.Info)); + bag.statedef.SetStateLabel(propname.GetChars(), CheckState (sc, bag.Info)); } else { @@ -1113,7 +1129,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) { PClassActor *info = CreateNewActor(sc, typeName, parentName); info->ActorInfo()->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; - info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); + info->SourceLumpName = fileSystem.GetFileFullPath(sc.LumpNum).c_str(); if (!info->SetReplacement(replaceName)) { @@ -1124,7 +1140,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) bag->Info = info; bag->Lumpnum = sc.LumpNum; #ifdef _DEBUG - bag->ClassName = typeName; + bag->ClassName = typeName.GetChars(); #endif return info; } @@ -1270,13 +1286,13 @@ void ParseDecorate (FScanner &sc, PNamespace *ns) { sc.MustGetString(); // This check needs to remain overridable for testing purposes. - if (Wads.GetLumpFile(sc.LumpNum) == 0 && !Args->CheckParm("-allowdecoratecrossincludes")) + if (fileSystem.GetFileContainer(sc.LumpNum) == 0 && !Args->CheckParm("-allowdecoratecrossincludes")) { - int includefile = Wads.GetLumpFile(Wads.CheckNumForFullName(sc.String, true)); + int includefile = fileSystem.GetFileContainer(fileSystem.CheckNumForFullName(sc.String, true)); if (includefile != 0) { I_FatalError("File %s is overriding core lump %s.", - Wads.GetWadFullName(includefile), sc.String); + fileSystem.GetResourceFileFullName(includefile), sc.String); } } FScanner newscanner; @@ -1329,6 +1345,7 @@ void ParseDecorate (FScanner &sc, PNamespace *ns) ParseDamageDefinition(sc); break; } + [[fallthrough]]; default: sc.RestorePos(pos); ParseOldDecoration(sc, DEF_Decoration, ns); @@ -1341,7 +1358,7 @@ void ParseAllDecorate() { int lastlump = 0, lump; - while ((lump = Wads.FindLump("DECORATE", &lastlump)) != -1) + while ((lump = fileSystem.FindLump("DECORATE", &lastlump)) != -1) { FScanner sc(lump); auto ns = Namespaces.NewNamespace(sc.LumpNum); diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index cede46bdde4..570905741a5 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -43,7 +43,8 @@ #include "p_lnspec.h" #include "p_local.h" #include "thingdef.h" -#include "backend/codegen.h" +#include "codegen.h" +#include "backend/codegen_doom.h" #ifndef _MSC_VER #include "i_system.h" // for strlwr() #endif // !_MSC_VER @@ -169,7 +170,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & statestring += '+'; statestring += sc.String; } - if (!bag.statedef.SetGotoLabel(statestring)) + if (!bag.statedef.SetGotoLabel(statestring.GetChars())) { sc.ScriptError("GOTO before first state"); } @@ -206,7 +207,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & { do { - bag.statedef.AddStateLabel(statestring); + bag.statedef.AddStateLabel(statestring.GetChars()); statestring = ParseStateString(sc); if (!statestring.CompareNoCase("GOTO")) { @@ -229,7 +230,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & } scp = sc; - state.sprite = GetSpriteIndex(statestring); + state.sprite = GetSpriteIndex(statestring.GetChars()); state.Misc1 = state.Misc2 = 0; sc.MustGetString(); statestring = sc.String; @@ -247,7 +248,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & sc.MustGetStringName(")"); if (min > max) { - swapvalues(min, max); + std::swap(min, max); } state.Tics = min; state.TicRange = max - min; @@ -333,7 +334,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & auto funcsym = CreateAnonymousFunction(actor->VMType, nullptr, state.UseFlags); state.ActionFunc = FunctionBuildList.AddFunction(bag.Namespace, bag.Version, funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum); } - int count = bag.statedef.AddStates(&state, statestring, scp); + int count = bag.statedef.AddStates(&state, statestring.GetChars(), scp); if (count < 0) { sc.ScriptError("Invalid frame character string '%s'", statestring.GetChars()); @@ -475,7 +476,7 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg // Otherwise, it's a sequence of actions. if (!sc.Compare("{")) { - FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag); + FxExpression *call = ParseAction(sc, state, statestring, bag); endswithret = true; return new FxReturnStatement(call, sc); } @@ -559,14 +560,12 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg // //========================================================================== -FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag) +FxExpression* ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag) { - FxVMFunctionCall *call; - // Make the action name lowercase strlwr (sc.String); - call = DoActionSpecials(sc, state, bag); + FxExpression *call = DoActionSpecials(sc, state, bag); if (call != NULL) { return call; @@ -579,7 +578,7 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B { FArgumentList args; ParseFunctionParameters(sc, bag.Info, args, afd, statestring, &bag.statedef); - call = new FxVMFunctionCall(new FxSelf(sc), afd, args, sc, false); + call = new FxFunctionCall(symname, NAME_None, std::move(args), sc); return call; } sc.ScriptError("Invalid parameter '%s'\n", sc.String); @@ -703,7 +702,7 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray StateSourceLines; static FScriptPosition unknownstatesource("unknown file", 0); +EXTERN_CVAR(Bool, strictdecorate); //========================================================================== // @@ -93,7 +96,7 @@ void FinalizeClass(PClass *ccls, FStateDefinitions &statedef) def->flags |= MF_SPECIAL; } - if (cls->IsDescendantOf(NAME_Weapon)) + if (cls->IsDescendantOf(NAME_Weapon) && !cls->bAbstract) { FState *ready = def->FindState(NAME_Ready); FState *select = def->FindState(NAME_Select); @@ -228,51 +231,6 @@ PFunction *CreateAnonymousFunction(PContainerType *containingclass, PType *retur return sym; } -//========================================================================== -// -// FindClassMemberFunction -// -// Looks for a name in a class's symbol table and outputs appropriate messages -// -//========================================================================== - -PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error, const VersionInfo &version, bool nodeprecated) -{ - // Skip ACS_NamedExecuteWithResult. Anything calling this should use the builtin instead. - if (name == NAME_ACS_NamedExecuteWithResult) return nullptr; - - PSymbolTable *symtable; - auto symbol = selfcls->Symbols.FindSymbolInTable(name, symtable); - auto funcsym = dyn_cast(symbol); - - if (symbol != nullptr) - { - auto cls_ctx = PType::toClass(funccls); - auto cls_target = funcsym ? PType::toClass(funcsym->OwningClass) : nullptr; - if (funcsym == nullptr) - { - if (PClass::FindClass(name)) return nullptr; // Special case when a class's member variable hides a global class name. This should still work. - sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars()); - } - else if ((funcsym->Variants[0].Flags & VARF_Private) && symtable != &funccls->Symbols) - { - // private access is only allowed if the symbol table belongs to the class in which the current function is being defined. - sc.Message(MSG_ERROR, "%s is declared private and not accessible", symbol->SymbolName.GetChars()); - } - else if ((funcsym->Variants[0].Flags & VARF_Protected) && symtable != &funccls->Symbols && (!cls_ctx || !cls_target || !cls_ctx->Descriptor->IsDescendantOf(cls_target->Descriptor))) - { - sc.Message(MSG_ERROR, "%s is declared protected and not accessible", symbol->SymbolName.GetChars()); - } - // ZScript will skip this because it prints its own message. - else if ((funcsym->Variants[0].Flags & VARF_Deprecated) && funcsym->mVersion <= version && !nodeprecated) - { - sc.Message(MSG_WARNING, "Call to deprecated function %s", symbol->SymbolName.GetChars()); - } - } - // return nullptr if the name cannot be found in the symbol table so that the calling code can do other checks. - return funcsym; -} - //========================================================================== // // CreateDamageFunction @@ -360,10 +318,16 @@ static void CheckLabel(PClassActor *obj, FStateLabel *slb, int useflag, FName st auto state = slb->State; if (state != nullptr) { + if (uintptr_t(state) <= 0xffff) + { + // can't do much here aside from printing a message and aborting. + I_Error("Bad state label %s in actor %s", slb->Label.GetChars(), obj->TypeName.GetChars()); + } + if (!(state->UseFlags & useflag)) { GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "%s references state %s as %s state, but this state is not flagged for use as %s.\n", - obj->TypeName.GetChars(), FState::StaticGetStateName(state).GetChars(), statename.GetChars(), descript); + obj->TypeName.GetChars(), FState::StaticGetStateName(state, obj).GetChars(), statename.GetChars(), descript); } } if (slb->Children != nullptr) @@ -414,7 +378,7 @@ static void CheckStates(PClassActor *obj) if (state->NextState && (state->UseFlags & state->NextState->UseFlags) != state->UseFlags) { GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "State %s links to a state with incompatible restrictions.\n", - FState::StaticGetStateName(state).GetChars()); + FState::StaticGetStateName(state, obj).GetChars()); } } } @@ -450,6 +414,35 @@ void CheckDropItems(const PClassActor *const obj) void ParseScripts(); void ParseAllDecorate(); void SynthesizeFlagFields(); +void SetDoomCompileEnvironment(); + +void ParseScripts() +{ + int lump, lastlump = 0; + FScriptPosition::ResetErrorCounter(); + + while ((lump = fileSystem.FindLump("ZSCRIPT", &lastlump)) != -1) + { + ZCCParseState state; + auto newns = ParseOneScript(lump, state); + PSymbolTable symtable; + + ZCCDoomCompiler cc(state, NULL, symtable, newns, lump, state.ParseVersion); + cc.Compile(); + + if (FScriptPosition::ErrorCounter > 0) + { + // Abort if the compiler produced any errors. Also do not compile further lumps, because they very likely miss some stuff. + I_Error("%d errors, %d warnings while compiling %s", FScriptPosition::ErrorCounter, FScriptPosition::WarnCounter, fileSystem.GetFileFullPath(lump).c_str()); + } + else if (FScriptPosition::WarnCounter > 0) + { + // If we got warnings, but no errors, print the information but continue. + Printf(TEXTCOLOR_ORANGE "%d warnings while compiling %s\n", FScriptPosition::WarnCounter, fileSystem.GetFileFullPath(lump).c_str()); + } + + } +} void LoadActors() { @@ -458,11 +451,12 @@ void LoadActors() timer.Reset(); timer.Clock(); FScriptPosition::ResetErrorCounter(); + SetDoomCompileEnvironment(); InitThingdef(); FScriptPosition::StrictErrors = true; ParseScripts(); - FScriptPosition::StrictErrors = false; + FScriptPosition::StrictErrors = strictdecorate; ParseAllDecorate(); SynthesizeFlagFields(); @@ -473,10 +467,11 @@ void LoadActors() I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter); } FScriptPosition::ResetErrorCounter(); - - for (int i = PClassActor::AllActorClasses.Size() - 1; i >= 0; i--) + // AllActorClasses hasn'T been set up yet. + for (int i = PClass::AllClasses.Size() - 1; i >= 0; i--) { - auto ti = PClassActor::AllActorClasses[i]; + auto ti = (PClassActor*)PClass::AllClasses[i]; + if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue; if (ti->Size == TentativeClass) { if (ti->bOptional) diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 4ab496c4152..34cd346667f 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -191,16 +191,12 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) // //========================================================================== -AFuncDesc *FindFunction(PContainerType *cls, const char * string); -FieldDesc *FindField(PContainerType *cls, const char * string); - - FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, PNamespace *resolvenspc = nullptr); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret); -class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); +FxExpression *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); FName CheckCastKludges(FName in); void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PContainerType *cls, uint32_t funcflags, int useflags); PFunction *CreateAnonymousFunction(PContainerType *containingclass, PType *returntype, int flags); @@ -232,6 +228,7 @@ enum DEPF_HEXENBOUNCE = 10, DEPF_DOOMBOUNCE = 11, DEPF_INTERHUBSTRIP = 12, + DEPF_HIGHERMPROB = 13, }; // Types of old style decorations @@ -244,9 +241,9 @@ enum EDefinitionType }; #if defined(_MSC_VER) -#pragma section(".greg$u",read) +#pragma section(SECTION_GREG,read) -#define MSVC_PSEG __declspec(allocate(".greg$u")) +#define MSVC_PSEG __declspec(allocate(SECTION_GREG)) #define GCC_PSEG #else #define MSVC_PSEG @@ -259,6 +256,7 @@ union FPropParam int i; double d; const char *s; + VMFunction* fu; FxExpression *exp; }; @@ -316,6 +314,9 @@ int MatchString (const char *in, const char **strings); #define PROP_STRING_PARM(var, no) \ const char *var = params[(no)+1].s; +#define PROP_NAME_PARM(var, no) \ + FName var = params[(no)+1].s; + #define PROP_EXP_PARM(var, no) \ FxExpression *var = params[(no)+1].exp; @@ -328,7 +329,10 @@ int MatchString (const char *in, const char **strings); #define PROP_DOUBLE_PARM(var, no) \ double var = params[(no)+1].d; -#define PROP_COLOR_PARM(var, no) \ - int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(NULL, params[(no)+2].s); +#define PROP_FUNC_PARM(var, no) \ + auto var = params[(no)+1].fu; + +#define PROP_COLOR_PARM(var, no, scriptpos) \ + int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(params[(no)+2].s, scriptpos); #endif diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 6b17a65f46b..3993cd745fc 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -49,14 +49,15 @@ #include "p_checkposition.h" #include "p_linetracedata.h" #include "v_font.h" -#include "menu/menu.h" +#include "menu.h" #include "teaminfo.h" #include "r_data/sprites.h" -#include "serializer.h" +#include "serializer_doom.h" #include "wi_stuff.h" #include "a_dynlight.h" #include "types.h" -#include "utility/dictionary.h" +#include "dictionary.h" +#include "events.h" static TArray properties; static TArray AFTable; @@ -81,7 +82,7 @@ extern float BackbuttonAlpha; // internal flags. These do not get exposed to actor definitions but scripts need to be able to access them as variables. static FFlagDef InternalActorFlagDefs[]= { - DEFINE_FLAG(MF, INCHASE, AActor, flags), + DEFINE_FLAG(MF7, INCHASE, AActor, flags7), DEFINE_FLAG(MF, UNMORPHED, AActor, flags), DEFINE_FLAG(MF2, FLY, AActor, flags2), DEFINE_FLAG(MF2, ONMOBJ, AActor, flags2), @@ -325,6 +326,33 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF8, NOFRICTIONBOUNCE, AActor, flags8), DEFINE_FLAG(MF8, RETARGETAFTERSLAM, AActor, flags8), DEFINE_FLAG(MF8, STOPRAILS, AActor, flags8), + DEFINE_FLAG(MF8, FALLDAMAGE, AActor, flags8), + DEFINE_FLAG(MF8, MINVISIBLE, AActor, flags8), + DEFINE_FLAG(MF8, MVISBLOCKED, AActor, flags8), + DEFINE_FLAG(MF8, ABSVIEWANGLES, AActor, flags8), + DEFINE_FLAG(MF8, ALLOWTHRUBITS, AActor, flags8), + DEFINE_FLAG(MF8, FULLVOLSEE, AActor, flags8), + DEFINE_FLAG(MF8, E1M8BOSS, AActor, flags8), + DEFINE_FLAG(MF8, E2M8BOSS, AActor, flags8), + DEFINE_FLAG(MF8, E3M8BOSS, AActor, flags8), + DEFINE_FLAG(MF8, E4M8BOSS, AActor, flags8), + DEFINE_FLAG(MF8, E4M6BOSS, AActor, flags8), + DEFINE_FLAG(MF8, MAP07BOSS1, AActor, flags8), + DEFINE_FLAG(MF8, MAP07BOSS2, AActor, flags8), + DEFINE_FLAG(MF8, AVOIDHAZARDS, AActor, flags8), + DEFINE_FLAG(MF8, STAYONLIFT, AActor, flags8), + DEFINE_FLAG(MF8, DONTFOLLOWPLAYERS, AActor, flags8), + DEFINE_FLAG(MF8, SEEFRIENDLYMONSTERS, AActor, flags8), + DEFINE_FLAG(MF8, CROSSLINECHECK, AActor, flags8), + DEFINE_FLAG(MF8, MASTERNOSEE, AActor, flags8), + DEFINE_FLAG(MF8, ADDLIGHTLEVEL, AActor, flags8), + DEFINE_FLAG(MF8, ONLYSLAMSOLID, AActor, flags8), + + DEFINE_FLAG(MF9, SHADOWAIM, AActor, flags9), + DEFINE_FLAG(MF9, DOSHADOWBLOCK, AActor, flags9), + DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9), + DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9), + DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), @@ -334,8 +362,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(RF, FORCEYBILLBOARD, AActor, renderflags), DEFINE_FLAG(RF, FORCEXYBILLBOARD, AActor, renderflags), DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard - // [fgsfds] Flat sprites - DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags), + DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags), // [fgsfds] Flat sprites DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags), DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags), DEFINE_FLAG(RF, ROLLCENTER, AActor, renderflags), @@ -348,6 +375,17 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(RF, DONTINTERPOLATE, AActor, renderflags), DEFINE_FLAG(RF, SPRITEFLIP, AActor, renderflags), DEFINE_FLAG(RF, ZDOOMTRANS, AActor, renderflags), + DEFINE_FLAG(RF, CASTSPRITESHADOW, AActor, renderflags), + DEFINE_FLAG(RF, NOSPRITESHADOW, AActor, renderflags), + DEFINE_FLAG(RF2, INVISIBLEINMIRRORS, AActor, renderflags2), + DEFINE_FLAG(RF2, ONLYVISIBLEINMIRRORS, AActor, renderflags2), + DEFINE_FLAG(RF2, BILLBOARDFACECAMERA, AActor, renderflags2), + DEFINE_FLAG(RF2, BILLBOARDNOFACECAMERA, AActor, renderflags2), + DEFINE_FLAG(RF2, FLIPSPRITEOFFSETX, AActor, renderflags2), + DEFINE_FLAG(RF2, FLIPSPRITEOFFSETY, AActor, renderflags2), + DEFINE_FLAG(RF2, CAMFOLLOWSPLAYER, AActor, renderflags2), + DEFINE_FLAG(RF2, NOMIPMAP, AActor, renderflags2), + DEFINE_FLAG(RF2, ISOMETRICSPRITES, AActor, renderflags2), // Bounce flags DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags), @@ -367,6 +405,8 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG2(BOUNCE_NotOnShootables, DONTBOUNCEONSHOOTABLES, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_BounceOnUnrips, BOUNCEONUNRIPPABLES, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_NotOnSky, DONTBOUNCEONSKY, AActor, BounceFlags), + + DEFINE_FLAG2(OF_Transient, NOSAVEGAME, AActor, ObjectFlags), }; // These won't be accessible through bitfield variables @@ -384,6 +424,7 @@ static FFlagDef MoreFlagDefs[] = DEFINE_DEPRECATED_FLAG(HERETICBOUNCE), DEFINE_DEPRECATED_FLAG(HEXENBOUNCE), DEFINE_DEPRECATED_FLAG(DOOMBOUNCE), + DEFINE_DEPRECATED_FLAG(HIGHERMPROB), // Deprecated flags with no more existing functionality. DEFINE_DUMMY_FLAG(FASTER, true), // obsolete, replaced by 'Fast' state flag @@ -590,107 +631,6 @@ FPropertyInfo *FindProperty(const char * string) return NULL; } -//========================================================================== -// -// -// -//========================================================================== - -template -static int CompareClassNames(const char* const aname, const Desc& b) -{ - // ++ to get past the prefix letter of the native class name, which gets omitted by the FName for the class. - const char* bname = b.ClassName; - if ('\0' != *bname) ++bname; - return stricmp(aname, bname); -} - -template -static int CompareClassNames(const Desc& a, const Desc& b) -{ - // ++ to get past the prefix letter of the native class name, which gets omitted by the FName for the class. - const char* aname = a.ClassName; - if ('\0' != *aname) ++aname; - return CompareClassNames(aname, b); -} - -//========================================================================== -// -// Find a function by name using a binary search -// -//========================================================================== - -AFuncDesc *FindFunction(PContainerType *cls, const char * string) -{ - int min = 0, max = AFTable.Size() - 1; - - while (min <= max) - { - int mid = (min + max) / 2; - int lexval = CompareClassNames(cls->TypeName.GetChars(), AFTable[mid]); - if (lexval == 0) lexval = stricmp(string, AFTable[mid].FuncName); - if (lexval == 0) - { - return &AFTable[mid]; - } - else if (lexval > 0) - { - min = mid + 1; - } - else - { - max = mid - 1; - } - } - return nullptr; -} - -//========================================================================== -// -// Find a function by name using a binary search -// -//========================================================================== - -FieldDesc *FindField(PContainerType *cls, const char * string) -{ - int min = 0, max = FieldTable.Size() - 1; - const char * cname = cls ? cls->TypeName.GetChars() : ""; - - while (min <= max) - { - int mid = (min + max) / 2; - int lexval = CompareClassNames(cname, FieldTable[mid]); - if (lexval == 0) lexval = stricmp(string, FieldTable[mid].FieldName); - if (lexval == 0) - { - return &FieldTable[mid]; - } - else if (lexval > 0) - { - min = mid + 1; - } - else - { - max = mid - 1; - } - } - return nullptr; -} - - -//========================================================================== -// -// Find an action function in AActor's table -// -//========================================================================== - -VMFunction *FindVMFunction(PClass *cls, const char *name) -{ - auto f = dyn_cast(cls->FindSymbol(name, true)); - return f == nullptr ? nullptr : f->Variants[0].Implementation; -} - - //========================================================================== // // Sorting helpers @@ -707,25 +647,21 @@ static int propcmp(const void * a, const void * b) return stricmp( (*(FPropertyInfo**)a)->name, (*(FPropertyInfo**)b)->name); } -static int funccmp(const void * a, const void * b) -{ - int res = CompareClassNames(*(AFuncDesc*)a, *(AFuncDesc*)b); - if (res == 0) res = stricmp(((AFuncDesc*)a)->FuncName, ((AFuncDesc*)b)->FuncName); - return res; -} - -static int fieldcmp(const void * a, const void * b) -{ - int res = CompareClassNames(*(FieldDesc*)a, *(FieldDesc*)b); - if (res == 0) res = stricmp(((FieldDesc*)a)->FieldName, ((FieldDesc*)b)->FieldName); - return res; -} - //========================================================================== // // Initialization // //========================================================================== +void InitImports(); + +struct UserInfoCVarNamePlayer +{ + FBaseCVar** addr; + FString name; + int pnum; +}; + +TArray LoadGameUserInfoCVars; void InitThingdef() { @@ -798,6 +734,10 @@ void InitThingdef() sectorportalstruct->Size = sizeof(FSectorPortal); sectorportalstruct->Align = alignof(FSectorPortal); + auto lineportalstruct = NewStruct("LinePortal", nullptr, true); + lineportalstruct->Size = sizeof(FLinePortal); + lineportalstruct->Align = alignof(FLinePortal); + auto playerclassstruct = NewStruct("PlayerClass", nullptr, true); playerclassstruct->Size = sizeof(FPlayerClass); playerclassstruct->Align = alignof(FPlayerClass); @@ -810,6 +750,10 @@ void InitThingdef() teamstruct->Size = sizeof(FTeam); teamstruct->Align = alignof(FTeam); + auto terraindefstruct = NewStruct("TerrainDef", nullptr, true); + terraindefstruct->Size = sizeof(FTerrainDef); + terraindefstruct->Align = alignof(FTerrainDef); + PStruct *pstruct = NewStruct("PlayerInfo", nullptr, true); pstruct->Size = sizeof(player_t); pstruct->Align = alignof(player_t); @@ -825,33 +769,16 @@ void InitThingdef() } ); - auto fontstruct = NewStruct("FFont", nullptr, true); - fontstruct->Size = sizeof(FFont); - fontstruct->Align = alignof(FFont); - NewPointer(fontstruct, false)->InstallHandlers( - [](FSerializer &ar, const char *key, const void *addr) - { - ar(key, *(FFont **)addr); - }, - [](FSerializer &ar, const char *key, void *addr) - { - Serialize(ar, key, *(FFont **)addr, nullptr); - return true; - } - ); - auto wbplayerstruct = NewStruct("WBPlayerStruct", nullptr, true); wbplayerstruct->Size = sizeof(wbplayerstruct_t); wbplayerstruct->Align = alignof(wbplayerstruct_t); - FAutoSegIterator probe(CRegHead, CRegTail); - - while (*++probe != NULL) + AutoSegs::TypeInfos.ForEach([](ClassReg* typeInfo) { - if (((ClassReg *)*probe)->InitNatives) - ((ClassReg *)*probe)->InitNatives(); - } - + if (typeInfo->InitNatives) + typeInfo->InitNatives(); + }); + // Sort the flag lists for (size_t i = 0; i < NUM_FLAG_LISTS; ++i) { @@ -861,34 +788,16 @@ void InitThingdef() // Create a sorted list of properties if (properties.Size() == 0) { - FAutoSegIterator probe(GRegHead, GRegTail); - - while (*++probe != NULL) + AutoSegs::Properties.ForEach([](FPropertyInfo* propertyInfo) { - properties.Push((FPropertyInfo *)*probe); - } + properties.Push(propertyInfo); + }); + properties.ShrinkToFit(); qsort(&properties[0], properties.Size(), sizeof(properties[0]), propcmp); } - // Create a sorted list of native action functions - AFTable.Clear(); - if (AFTable.Size() == 0) - { - FAutoSegIterator probe(ARegHead, ARegTail); - - while (*++probe != NULL) - { - AFuncDesc *afunc = (AFuncDesc *)*probe; - assert(afunc->VMPointer != NULL); - *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->FuncName); - (*(afunc->VMPointer))->PrintableName.Format("%s.%s [Native]", afunc->ClassName+1, afunc->FuncName); - (*(afunc->VMPointer))->DirectNativeCall = afunc->DirectNative; - AFTable.Push(*afunc); - } - AFTable.ShrinkToFit(); - qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); - } + InitImports(); // Add the constructor and destructor to FCheckPosition. auto fcp = NewStruct("FCheckPosition", nullptr); @@ -904,278 +813,115 @@ void InitThingdef() frp->Size = sizeof(FRailParams); frp->Align = alignof(FRailParams); + auto netcmdstruct = NewStruct("NetworkCommand", nullptr, true); + netcmdstruct->Size = sizeof(FNetworkCommand); + netcmdstruct->Align = alignof(FNetworkCommand); + auto fltd = NewStruct("FLineTraceData", nullptr); fltd->Size = sizeof(FLineTraceData); fltd->Align = alignof(FLineTraceData); - FieldTable.Clear(); - if (FieldTable.Size() == 0) - { - FAutoSegIterator probe(FRegHead, FRegTail); - - while (*++probe != NULL) - { - FieldDesc *afield = (FieldDesc *)*probe; - FieldTable.Push(*afield); - } - FieldTable.ShrinkToFit(); - qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); - } -} + auto fspp = NewStruct("FSpawnParticleParams", nullptr); + fspp->Size = sizeof(FSpawnParticleParams); + fspp->Align = alignof(FSpawnParticleParams); -void SynthesizeFlagFields() -{ - // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. - for (auto &fl : FlagLists) - { - auto cls = const_cast(*fl.Type); - if (fl.Use & 2) + auto cvst = NewStruct("CVar", nullptr, true); + NewPointer(cvst, false)->InstallHandlers( + [](FSerializer &arc, const char *key, const void *addr) { - for (int i = 0; i < fl.NumDefs; i++) + const FBaseCVar * self = *(const FBaseCVar**)addr; + + if(self) { - if (fl.Defs[i].structoffset > 0) // skip the deprecated entries in this list - { - cls->VMType->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); - } - } - } - } -} + arc.BeginObject(key); -DEFINE_ACTION_FUNCTION(DObject, BAM) -{ - PARAM_PROLOGUE; - PARAM_FLOAT(ang); - ACTION_RETURN_INT(DAngle(ang).BAMs()); -} -FString FStringFormat(VM_ARGS, int offset) -{ - PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array - assert(va_reginfo[offset] == REGT_STRING); - - FString fmtstring = param[offset].s().GetChars(); - - param += offset; - numparam -= offset; - va_reginfo += offset; - - // note: we don't need a real printf format parser. - // enough to simply find the subtitution tokens and feed them to the real printf after checking types. - // https://en.wikipedia.org/wiki/Printf_format_string#Format_placeholder_specification - FString output; - bool in_fmt = false; - FString fmt_current; - int argnum = 1; - int argauto = 1; - // % = starts - // [0-9], -, +, \s, 0, #, . continue - // %, s, d, i, u, fF, eE, gG, xX, o, c, p, aA terminate - // various type flags are not supported. not like stuff like 'hh' modifier is to be used in the VM. - // the only combination that is parsed locally is %n$... - bool haveargnums = false; - for (size_t i = 0; i < fmtstring.Len(); i++) - { - char c = fmtstring[i]; - if (in_fmt) - { - if (c == '*' && (fmt_current.Len() == 1 || (fmt_current.Len() == 2 && fmt_current[1] == '0'))) - { - fmt_current += c; - } - else if ((c >= '0' && c <= '9') || - c == '-' || c == '+' || (c == ' ' && fmt_current.Back() != ' ') || c == '#' || c == '.') - { - fmt_current += c; - } - else if (c == '$') // %number$format - { - if (!haveargnums && argauto > 1) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - FString argnumstr = fmt_current.Mid(1); - if (!argnumstr.IsInt()) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for argument number, got '%s'.", argnumstr.GetChars()); - auto argnum64 = argnumstr.ToLong(); - if (argnum64 < 1 || argnum64 >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format (tried to access argument %d, %d total).", argnum64, numparam); - fmt_current = "%"; - haveargnums = true; - argnum = int(argnum64); - } - else - { - fmt_current += c; - - switch (c) + if(self->pnum != -1) { - // string - case 's': - { - if (argnum < 0 && haveargnums) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - in_fmt = false; - // fail if something was found, but it's not a string - if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (va_reginfo[argnum] != REGT_STRING) ThrowAbortException(X_FORMAT_ERROR, "Expected a string for format %s.", fmt_current.GetChars()); - // append - output.AppendFormat(fmt_current.GetChars(), param[argnum].s().GetChars()); - if (!haveargnums) argnum = ++argauto; - else argnum = -1; - break; + int32_t pnum = self->pnum; + FName name = self->userinfoName; + arc("name", name); + arc("player", pnum); } - - // pointer - case 'p': + else { - if (argnum < 0 && haveargnums) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - in_fmt = false; - // fail if something was found, but it's not a string - if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (va_reginfo[argnum] != REGT_POINTER) ThrowAbortException(X_FORMAT_ERROR, "Expected a pointer for format %s.", fmt_current.GetChars()); - // append - output.AppendFormat(fmt_current.GetChars(), param[argnum].a); - if (!haveargnums) argnum = ++argauto; - else argnum = -1; - break; + FString name = self->GetName(); + arc("name", name); } - // int formats (including char) - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': - case 'o': - case 'c': - case 'B': - { - if (argnum < 0 && haveargnums) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - in_fmt = false; - // append - if (fmt_current[1] == '*' || fmt_current[2] == '*') - { - // fail if something was found, but it's not an int - if (argnum+1 >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (va_reginfo[argnum] != REGT_INT && - va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); - if (va_reginfo[argnum+1] != REGT_INT && - va_reginfo[argnum+1] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); - - output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt(va_reginfo[argnum]), param[argnum + 1].ToInt(va_reginfo[argnum + 1])); - argauto++; - } - else - { - // fail if something was found, but it's not an int - if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (va_reginfo[argnum] != REGT_INT && - va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); - output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt(va_reginfo[argnum])); - } - if (!haveargnums) argnum = ++argauto; - else argnum = -1; - break; - } + arc.EndObject(); + } + }, + [](FSerializer &arc, const char *key, void *addr) + { + FBaseCVar ** self = (FBaseCVar**)addr; - // double formats - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - case 'a': - case 'A': - { - if (argnum < 0 && haveargnums) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - in_fmt = false; - if (fmt_current[1] == '*' || fmt_current[2] == '*') - { - // fail if something was found, but it's not an int - if (argnum + 1 >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (va_reginfo[argnum] != REGT_INT && - va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); - if (va_reginfo[argnum + 1] != REGT_INT && - va_reginfo[argnum + 1] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); - - output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt(va_reginfo[argnum]), param[argnum + 1].ToDouble(va_reginfo[argnum + 1])); - argauto++; - } - else - { - // fail if something was found, but it's not a float - if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (va_reginfo[argnum] != REGT_INT && - va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); - // append - output.AppendFormat(fmt_current.GetChars(), param[argnum].ToDouble(va_reginfo[argnum])); - } - if (!haveargnums) argnum = ++argauto; - else argnum = -1; - break; - } + FString name; + arc.BeginObject(key); - default: - // invalid character - output += fmt_current; - in_fmt = false; - break; - } + arc("name", name); + + FBaseCVar * backing = FindCVar(name.GetChars(), nullptr); + if(!backing) + { + I_Error("Attempt to load pointer to inexisted CVar '%s'", name.GetChars()); } - } - else - { - if (c == '%') + else if((backing->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO) { - if (i + 1 < fmtstring.Len() && fmtstring[i + 1] == '%') - { - output += '%'; - i++; - } - else + if(int pnum; arc.ReadOptionalInt("player", pnum)) { - in_fmt = true; - fmt_current = "%"; + *self = nullptr; + LoadGameUserInfoCVars.Push({self, name, pnum}); // this needs to be done later, since userinfo isn't loaded yet + arc.EndObject(); + return true; } } - else - { - output += c; - } - } - } + + *self = backing; - return output; + arc.EndObject(); + + return true; + } + ); } -DEFINE_ACTION_FUNCTION(FStringStruct, Format) +void SetupLoadingCVars() { - PARAM_PROLOGUE; - FString s = FStringFormat(VM_ARGS_NAMES); - ACTION_RETURN_STRING(s); + LoadGameUserInfoCVars.Clear(); } -DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) +void FinishLoadingCVars() { - PARAM_SELF_STRUCT_PROLOGUE(FString); - // first parameter is the self pointer - FString s = FStringFormat(VM_ARGS_NAMES, 1); - (*self) += s; - return 0; + for(UserInfoCVarNamePlayer &cvar : LoadGameUserInfoCVars) + { + (*cvar.addr) = GetCVar(cvar.pnum, cvar.name.GetChars()); + } } -DEFINE_ACTION_FUNCTION(FStringStruct, AppendCharacter) +void SynthesizeFlagFields() { - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(c); - self->AppendCharacter(c); - return 0; + // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. + for (auto &fl : FlagLists) + { + auto cls = const_cast(*fl.Type); + if (fl.Use & 2) + { + for (int i = 0; i < fl.NumDefs; i++) + { + if (fl.Defs[i].structoffset > 0) // skip the deprecated entries in this list + { + cls->VMType->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); + } + } + } + } } -DEFINE_ACTION_FUNCTION(FStringStruct, DeleteLastCharacter) +DEFINE_ACTION_FUNCTION(DObject, BAM) { - PARAM_SELF_STRUCT_PROLOGUE(FString); - self->DeleteLastCharacter(); - return 0; + PARAM_PROLOGUE; + PARAM_ANGLE(ang); + ACTION_RETURN_INT(ang.BAMs()); } + diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 8f9916818d3..bedd66cd379 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -40,7 +40,7 @@ #include "gi.h" #include "d_player.h" -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" #include "p_lnspec.h" #include "decallib.h" @@ -50,12 +50,13 @@ #include "thingdef.h" #include "a_morph.h" #include "teaminfo.h" -#include "backend/vmbuilder.h" +#include "vmbuilder.h" #include "a_keys.h" #include "g_levellocals.h" #include "types.h" #include "a_dynlight.h" #include "v_video.h" +#include "texturemanager.h" //========================================================================== // @@ -151,18 +152,18 @@ bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printer if (actor != NULL) { auto Level = actor->Level; - const char *dot = strchr(flagname, '.'); + const char *dot = strchr(flagname.GetChars(), '.'); FFlagDef *fd; PClassActor *cls = actor->GetClass(); if (dot != NULL) { - FString part1(flagname.GetChars(), dot - flagname); - fd = FindFlag(cls, part1, dot + 1); + FString part1(flagname.GetChars(), dot - flagname.GetChars()); + fd = FindFlag(cls, part1.GetChars(), dot + 1); } else { - fd = FindFlag(cls, flagname, NULL); + fd = FindFlag(cls, flagname.GetChars(), NULL); } if (fd != NULL) @@ -244,7 +245,7 @@ INTBOOL CheckActorFlag(AActor *owner, const char *flagname, bool printerror) if (dot != NULL) { FString part1(flagname, dot-flagname); - fd = FindFlag (cls, part1, dot+1); + fd = FindFlag (cls, part1.GetChars(), dot+1); } else { @@ -324,6 +325,10 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in defaults->IntVar(NAME_InterHubAmount) = set ? 0 : 1; break; + case DEPF_HIGHERMPROB: + defaults->MinMissileChance = set ? 160 : 200; + break; + default: break; // silence GCC } @@ -383,6 +388,9 @@ bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index) case DEPF_INTERHUBSTRIP: return !(actor->IntVar(NAME_InterHubAmount)); + + case DEPF_HIGHERMPROB: + return actor->MinMissileChance <= 160; } return false; // Any entirely unknown flag is not set @@ -520,7 +528,9 @@ DEFINE_PROPERTY(skip_super, 0, Actor) return; } - *defaults = *GetDefault(); + // major hack job alert. This is only supposed to copy the parts that actually are defined by AActor itself. + memcpy(&defaults->snext, &GetDefault()->snext, (uint8_t*)&defaults[1] - (uint8_t*)&defaults->snext); + ResetBaggage (&bag, RUNTIME_CLASS(AActor)); static_cast(bag.Info)->ActorInfo()->SkipSuperSet = true; // ZScript processes the states later so this property must be flagged for later handling. } @@ -610,7 +620,7 @@ DEFINE_PROPERTY(damage, X, Actor) DEFINE_PROPERTY(scale, F, Actor) { PROP_DOUBLE_PARM(id, 0); - defaults->Scale.X = defaults->Scale.Y = id; + defaults->Scale.X = defaults->Scale.Y = float(id); } //========================================================================== @@ -737,8 +747,8 @@ DEFINE_PROPERTY(translation, L, Actor) for(int i = 1; i < PROP_PARM_COUNT; i++) { PROP_STRING_PARM(str, i); - int tnum; - if (i== 1 && PROP_PARM_COUNT == 2 && (tnum = R_FindCustomTranslation(str)) != -1) + FTranslationID tnum; + if (i== 1 && PROP_PARM_COUNT == 2 && (tnum = R_FindCustomTranslation(str)) != INVALID_TRANSLATION) { defaults->Translation = tnum; return; @@ -756,7 +766,7 @@ DEFINE_PROPERTY(translation, L, Actor) } } } - defaults->Translation = CurrentTranslation.StoreTranslation (TRANSLATION_Decorate); + defaults->Translation = GPalette.StoreTranslation (TRANSLATION_Decorate, &CurrentTranslation); } } @@ -765,7 +775,7 @@ DEFINE_PROPERTY(translation, L, Actor) //========================================================================== DEFINE_PROPERTY(stencilcolor, C, Actor) { - PROP_COLOR_PARM(color, 0); + PROP_COLOR_PARM(color, 0, &bag.ScriptPosition); defaults->fillcolor = color | (ColorMatcher.Pick (RPART(color), GPART(color), BPART(color)) << 24); } @@ -775,11 +785,11 @@ DEFINE_PROPERTY(stencilcolor, C, Actor) //========================================================================== DEFINE_PROPERTY(bloodcolor, C, Actor) { - PROP_COLOR_PARM(color, 0); + PROP_COLOR_PARM(color, 0, &bag.ScriptPosition); defaults->BloodColor = color; defaults->BloodColor.a = 255; // a should not be 0. - defaults->BloodTranslation = TRANSLATION(TRANSLATION_Blood, CreateBloodTranslation(color)); + defaults->BloodTranslation = CreateBloodTranslation(color); } //========================================================================== @@ -906,7 +916,7 @@ DEFINE_PROPERTY(damagefactor, ZF, Actor) DEFINE_PROPERTY(decal, S, Actor) { PROP_STRING_PARM(str, 0); - defaults->DecalGenerator = (FDecalBase *)intptr_t(int(FName(str))); + defaults->DecalGenerator = (FDecalBase *)(intptr_t)FName(str).GetIndex(); } //========================================================================== @@ -941,7 +951,7 @@ DEFINE_PROPERTY(gravity, F, Actor) { PROP_DOUBLE_PARM(i, 0); - if (i < 0) I_Error ("Gravity must not be negative."); + //if (i < 0) I_Error ("Gravity must not be negative."); defaults->Gravity = i; } @@ -951,7 +961,7 @@ DEFINE_PROPERTY(gravity, F, Actor) DEFINE_PROPERTY(spriteangle, F, Actor) { PROP_DOUBLE_PARM(i, 0); - defaults->SpriteAngle = i; + defaults->SpriteAngle = DAngle::fromDeg(i); } //========================================================================== @@ -978,6 +988,7 @@ DEFINE_PROPERTY(clearflags, 0, Actor) defaults->flags6 = 0; defaults->flags7 = 0; defaults->flags8 = 0; + defaults->flags9 = 0; } //========================================================================== @@ -1024,6 +1035,45 @@ DEFINE_PROPERTY(designatedteam, I, Actor) defaults->DesignatedTeam = val; } +//========================================================================== +// MBF21 +//========================================================================== +DEFINE_PROPERTY(infightinggroup, I, Actor) +{ + PROP_INT_PARM(i, 0); + if (i < 0) + { + I_Error("Infighting groups must be >= 0."); + } + info->ActorInfo()->infighting_group = i; +} + +//========================================================================== +// MBF21 +//========================================================================== +DEFINE_PROPERTY(projectilegroup, I, Actor) +{ + PROP_INT_PARM(i, 0); + if (i < -1) + { + I_Error("Projectile groups must be >= -1."); + } + info->ActorInfo()->projectile_group = i; +} + +//========================================================================== +// MBF21 +//========================================================================== +DEFINE_PROPERTY(splashgroup, I, Actor) +{ + PROP_INT_PARM(i, 0); + if (i < 0) + { + I_Error("Splash groups must be >= 0."); + } + info->ActorInfo()->splash_group = i; +} + //========================================================================== // [BB] //========================================================================== @@ -1125,7 +1175,7 @@ static void SetIcon(FTextureID &icon, Baggage &bag, const char *i) // Don't print warnings if the item is for another game or if this is a shareware IWAD. // Strife's teaser doesn't contain all the icon graphics of the full game. if ((bag.Info->ActorInfo()->GameFilter == GAME_Any || bag.Info->ActorInfo()->GameFilter & gameinfo.gametype) && - !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) + !(gameinfo.flags&GI_SHAREWARE) && fileSystem.GetFileContainer(bag.Lumpnum) != 0) { bag.ScriptPosition.Message(MSG_WARNING, "Icon '%s' for '%s' not found\n", i, bag.Info->TypeName.GetChars()); @@ -1244,7 +1294,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) *pBlendColor = MakeSpecialColormap(65535); return; } - color = V_GetColor(NULL, name, &bag.ScriptPosition); + color = V_GetColor(name, &bag.ScriptPosition); } if (PROP_PARM_COUNT > 2) { @@ -1276,7 +1326,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) PROP_FLOAT_PARM(r, 0); PROP_FLOAT_PARM(g, 1); PROP_FLOAT_PARM(b, 2); - BlendColor = MakeSpecialColormap(AddSpecialColormap(0, 0, 0, r, g, b)); + BlendColor = MakeSpecialColormap(AddSpecialColormap(GPalette.BaseColors, 0, 0, 0, r, g, b)); } else if (PROP_PARM_COUNT == 6) { @@ -1286,7 +1336,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) PROP_FLOAT_PARM(r2, 3); PROP_FLOAT_PARM(g2, 4); PROP_FLOAT_PARM(b2, 5); - BlendColor = MakeSpecialColormap(AddSpecialColormap(r1, g1, b1, r2, g2, b2)); + BlendColor = MakeSpecialColormap(AddSpecialColormap(GPalette.BaseColors, r1, g1, b1, r2, g2, b2)); } else { @@ -1327,7 +1377,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) { FString st; st.Format("%s%s", strnicmp(str, "power", 5) ? "Power" : "", str); - cls = FindClassTentative(st, pow); + cls = FindClassTentative(st.GetChars(), pow); } else { @@ -1400,7 +1450,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) PROP_INT_PARM(end, 1); if (start > end) - swapvalues (start, end); + std::swap (start, end); defaults->IntVar(NAME_ColorRangeStart) = start; defaults->IntVar(NAME_ColorRangeEnd) = end; @@ -1474,7 +1524,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) FPlayerColorSet color; color.Name = setname; - color.Lump = Wads.CheckNumForName(rangefile); + color.Lump = fileSystem.CheckNumForName(rangefile); color.RepresentativeColor = representative_color; color.NumExtraRanges = 0; @@ -1607,7 +1657,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, crouchsprite, S, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn) { - PROP_COLOR_PARM(c, 0); + PROP_COLOR_PARM(c, 0, &bag.ScriptPosition); PalEntry color = c; @@ -1764,6 +1814,15 @@ DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph) defaults->PointerVar(NAME_PlayerClass) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(monsterclass, S, PowerMorph) +{ + PROP_STRING_PARM(str, 0); + defaults->PointerVar(NAME_MonsterClass) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); +} + //========================================================================== // //========================================================================== diff --git a/src/scripting/types.cpp b/src/scripting/types.cpp deleted file mode 100644 index aee0b3b0aa6..00000000000 --- a/src/scripting/types.cpp +++ /dev/null @@ -1,2563 +0,0 @@ -/* -** types.cpp -** Implements the VM type hierarchy -** -**--------------------------------------------------------------------------- -** Copyright 2008-2016 Randy Heit -** Copyright 2016-2017 Cheistoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "vmintern.h" -#include "s_sound.h" -#include "dthinker.h" -#include "types.h" - - -FTypeTable TypeTable; - -PErrorType *TypeError; -PErrorType *TypeAuto; -PVoidType *TypeVoid; -PInt *TypeSInt8, *TypeUInt8; -PInt *TypeSInt16, *TypeUInt16; -PInt *TypeSInt32, *TypeUInt32; -PBool *TypeBool; -PFloat *TypeFloat32, *TypeFloat64; -PString *TypeString; -PName *TypeName; -PSound *TypeSound; -PColor *TypeColor; -PTextureID *TypeTextureID; -PSpriteID *TypeSpriteID; -PStatePointer *TypeState; -PPointer *TypeFont; -PStateLabel *TypeStateLabel; -PStruct *TypeVector2; -PStruct *TypeVector3; -PStruct *TypeColorStruct; -PStruct *TypeStringStruct; -PPointer *TypeNullPtr; -PPointer *TypeVoidPtr; - - -// CODE -------------------------------------------------------------------- - -void DumpTypeTable() -{ - int used = 0; - int min = INT_MAX; - int max = 0; - int all = 0; - int lens[10] = {0}; - for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) - { - int len = 0; - Printf("%4zu:", i); - for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) - { - Printf(" -> %s", ty->DescriptiveName()); - len++; - all++; - } - if (len != 0) - { - used++; - if (len < min) - min = len; - if (len > max) - max = len; - } - if (len < (int)countof(lens)) - { - lens[len]++; - } - Printf("\n"); - } - Printf("Used buckets: %d/%lu (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); - Printf("Min bucket size: %d\n", min); - Printf("Max bucket size: %d\n", max); - Printf("Avg bucket size: %.2f\n", double(all) / used); - int j,k; - for (k = countof(lens)-1; k > 0; --k) - if (lens[k]) - break; - for (j = 0; j <= k; ++j) - Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); -} - -/* PType ******************************************************************/ - -//========================================================================== -// -// PType Parameterized Constructor -// -//========================================================================== - -PType::PType(unsigned int size, unsigned int align) -: Size(size), Align(align), HashNext(nullptr) -{ - mDescriptiveName = "Type"; - loadOp = OP_NOP; - storeOp = OP_NOP; - moveOp = OP_NOP; - RegType = REGT_NIL; - RegCount = 1; -} - -//========================================================================== -// -// PType Destructor -// -//========================================================================== - -PType::~PType() -{ -} - -//========================================================================== -// -// PType :: WriteValue -// -//========================================================================== - -void PType::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - assert(0 && "Cannot write value for this type"); -} - -//========================================================================== -// -// PType :: ReadValue -// -//========================================================================== - -bool PType::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - assert(0 && "Cannot read value for this type"); - return false; -} - -//========================================================================== -// -// PType :: SetDefaultValue -// -//========================================================================== - -void PType::SetDefaultValue(void *base, unsigned offset, TArray *stroffs) -{ -} - -//========================================================================== -// -// PType :: SetDefaultValue -// -//========================================================================== - -void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) -{ -} - -void PType::SetPointerArray(void *base, unsigned offset, TArray *stroffs) -{ -} - -//========================================================================== -// -// PType :: InitializeValue -// -//========================================================================== - -void PType::InitializeValue(void *addr, const void *def) const -{ -} - -//========================================================================== -// -// PType :: DestroyValue -// -//========================================================================== - -void PType::DestroyValue(void *addr) const -{ -} - -//========================================================================== -// -// PType :: SetValue -// -//========================================================================== - -void PType::SetValue(void *addr, int val) -{ - assert(0 && "Cannot set int value for this type"); -} - -void PType::SetValue(void *addr, double val) -{ - assert(0 && "Cannot set float value for this type"); -} - -//========================================================================== -// -// PType :: GetValue -// -//========================================================================== - -int PType::GetValueInt(void *addr) const -{ - assert(0 && "Cannot get value for this type"); - return 0; -} - -double PType::GetValueFloat(void *addr) const -{ - assert(0 && "Cannot get value for this type"); - return 0; -} - -//========================================================================== -// -// PType :: IsMatch -// -//========================================================================== - -bool PType::IsMatch(intptr_t id1, intptr_t id2) const -{ - return false; -} - -//========================================================================== -// -// PType :: GetTypeIDs -// -//========================================================================== - -void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = 0; - id2 = 0; -} - -//========================================================================== -// -// PType :: GetTypeIDs -// -//========================================================================== - -const char *PType::DescriptiveName() const -{ - return mDescriptiveName.GetChars(); -} - -//========================================================================== -// -// PType :: StaticInit STATIC -// -//========================================================================== - -void PType::StaticInit() -{ - // Create types and add them type the type table. - TypeTable.AddType(TypeError = new PErrorType, NAME_None); - TypeTable.AddType(TypeAuto = new PErrorType(2), NAME_None); - TypeTable.AddType(TypeVoid = new PVoidType, NAME_Void); - TypeTable.AddType(TypeSInt8 = new PInt(1, false), NAME_Int); - TypeTable.AddType(TypeUInt8 = new PInt(1, true), NAME_Int); - TypeTable.AddType(TypeSInt16 = new PInt(2, false), NAME_Int); - TypeTable.AddType(TypeUInt16 = new PInt(2, true), NAME_Int); - TypeTable.AddType(TypeSInt32 = new PInt(4, false), NAME_Int); - TypeTable.AddType(TypeUInt32 = new PInt(4, true), NAME_Int); - TypeTable.AddType(TypeBool = new PBool, NAME_Bool); - TypeTable.AddType(TypeFloat32 = new PFloat(4), NAME_Float); - TypeTable.AddType(TypeFloat64 = new PFloat(8), NAME_Float); - TypeTable.AddType(TypeString = new PString, NAME_String); - TypeTable.AddType(TypeName = new PName, NAME_Name); - TypeTable.AddType(TypeSound = new PSound, NAME_Sound); - TypeTable.AddType(TypeColor = new PColor, NAME_Color); - TypeTable.AddType(TypeState = new PStatePointer, NAME_Pointer); - TypeTable.AddType(TypeStateLabel = new PStateLabel, NAME_Label); - TypeTable.AddType(TypeNullPtr = new PPointer, NAME_Pointer); - TypeTable.AddType(TypeSpriteID = new PSpriteID, NAME_SpriteID); - TypeTable.AddType(TypeTextureID = new PTextureID, NAME_TextureID); - - TypeVoidPtr = NewPointer(TypeVoid, false); - TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. - TypeStringStruct = NewStruct("Stringstruct", nullptr, true); - TypeFont = NewPointer(NewStruct("Font", nullptr, true)); -#ifdef __BIG_ENDIAN__ - TypeColorStruct->AddField(NAME_a, TypeUInt8); - TypeColorStruct->AddField(NAME_r, TypeUInt8); - TypeColorStruct->AddField(NAME_g, TypeUInt8); - TypeColorStruct->AddField(NAME_b, TypeUInt8); -#else - TypeColorStruct->AddField(NAME_b, TypeUInt8); - TypeColorStruct->AddField(NAME_g, TypeUInt8); - TypeColorStruct->AddField(NAME_r, TypeUInt8); - TypeColorStruct->AddField(NAME_a, TypeUInt8); -#endif - - TypeVector2 = new PStruct(NAME_Vector2, nullptr); - TypeVector2->AddField(NAME_X, TypeFloat64); - TypeVector2->AddField(NAME_Y, TypeFloat64); - TypeTable.AddType(TypeVector2, NAME_Struct); - TypeVector2->loadOp = OP_LV2; - TypeVector2->storeOp = OP_SV2; - TypeVector2->moveOp = OP_MOVEV2; - TypeVector2->RegType = REGT_FLOAT; - TypeVector2->RegCount = 2; - - TypeVector3 = new PStruct(NAME_Vector3, nullptr); - TypeVector3->AddField(NAME_X, TypeFloat64); - TypeVector3->AddField(NAME_Y, TypeFloat64); - TypeVector3->AddField(NAME_Z, TypeFloat64); - // allow accessing xy as a vector2. This is not supposed to be serialized so it's marked transient - TypeVector3->Symbols.AddSymbol(Create(NAME_XY, TypeVector2, VARF_Transient, 0)); - TypeTable.AddType(TypeVector3, NAME_Struct); - TypeVector3->loadOp = OP_LV3; - TypeVector3->storeOp = OP_SV3; - TypeVector3->moveOp = OP_MOVEV3; - TypeVector3->RegType = REGT_FLOAT; - TypeVector3->RegCount = 3; - - - - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_sByte, TypeSInt8)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Byte, TypeUInt8)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Short, TypeSInt16)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_uShort, TypeUInt16)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Int, TypeSInt32)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_uInt, TypeUInt32)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Bool, TypeBool)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Float, TypeFloat64)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Double, TypeFloat64)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Float32, TypeFloat32)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Float64, TypeFloat64)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_String, TypeString)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Name, TypeName)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Sound, TypeSound)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Color, TypeColor)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_State, TypeState)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Vector2, TypeVector2)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(Create(NAME_Vector3, TypeVector3)); -} - - -/* PBasicType *************************************************************/ - -//========================================================================== -// -// PBasicType Parameterized Constructor -// -//========================================================================== - -PBasicType::PBasicType(unsigned int size, unsigned int align) -: PType(size, align) -{ - mDescriptiveName = "BasicType"; - Flags |= TYPE_Scalar; -} - -/* PCompoundType **********************************************************/ - -//========================================================================== -// -// PBasicType Parameterized Constructor -// -//========================================================================== - -PCompoundType::PCompoundType(unsigned int size, unsigned int align) - : PType(size, align) -{ - mDescriptiveName = "CompoundType"; -} - -/* PContainerType *************************************************************/ - -//========================================================================== -// -// PContainerType :: IsMatch -// -//========================================================================== - -bool PContainerType::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PTypeBase *outer = (const PTypeBase *)id1; - FName name = (ENamedName)(intptr_t)id2; - - return Outer == outer && TypeName == name; -} - -//========================================================================== -// -// PContainerType :: GetTypeIDs -// -//========================================================================== - -void PContainerType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)Outer; - id2 = TypeName; -} - -/* PInt *******************************************************************/ - -//========================================================================== -// -// PInt Parameterized Constructor -// -//========================================================================== - -PInt::PInt(unsigned int size, bool unsign, bool compatible) -: PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible) -{ - mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size); - Flags |= TYPE_Int; - - MemberOnly = (size < 4); - if (!unsign) - { - int maxval = (1u << ((8 * size) - 1)) - 1; // compute as unsigned to prevent overflow before -1 - int minval = -maxval - 1; - Symbols.AddSymbol(Create(NAME_Min, this, minval)); - Symbols.AddSymbol(Create(NAME_Max, this, maxval)); - } - else - { - Symbols.AddSymbol(Create(NAME_Min, this, 0u)); - Symbols.AddSymbol(Create(NAME_Max, this, (1u << ((8 * size) - 1)))); - } - SetOps(); -} - -void PInt::SetOps() -{ - moveOp = OP_MOVE; - RegType = REGT_INT; - if (Size == 4) - { - storeOp = OP_SW; - loadOp = OP_LW; - } - else if (Size == 1) - { - storeOp = OP_SB; - loadOp = Unsigned ? OP_LBU : OP_LB; - } - else if (Size == 2) - { - storeOp = OP_SH; - loadOp = Unsigned ? OP_LHU : OP_LH; - } - else - { - assert(0 && "Unhandled integer size"); - storeOp = OP_NOP; - } -} - -//========================================================================== -// -// PInt :: WriteValue -// -//========================================================================== - -void PInt::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (Size == 8 && Unsigned) - { - // this is a special case that cannot be represented by an int64_t. - uint64_t val = *(uint64_t*)addr; - ar(key, val); - } - else - { - int64_t val; - switch (Size) - { - case 1: - val = Unsigned ? *(uint8_t*)addr : *(int8_t*)addr; - break; - - case 2: - val = Unsigned ? *(uint16_t*)addr : *(int16_t*)addr; - break; - - case 4: - val = Unsigned ? *(uint32_t*)addr : *(int32_t*)addr; - break; - - case 8: - val = *(int64_t*)addr; - break; - - default: - return; // something invalid - } - ar(key, val); - } -} - -//========================================================================== -// -// PInt :: ReadValue -// -//========================================================================== - -bool PInt::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - NumericValue val; - - ar(key, val); - if (val.type == NumericValue::NM_invalid) return false; // not found or usable - if (val.type == NumericValue::NM_float) val.signedval = (int64_t)val.floatval; - - // No need to check the unsigned state here. Downcasting to smaller types will yield the same result for both. - switch (Size) - { - case 1: - *(uint8_t*)addr = (uint8_t)val.signedval; - break; - - case 2: - *(uint16_t*)addr = (uint16_t)val.signedval; - break; - - case 4: - *(uint32_t*)addr = (uint32_t)val.signedval; - break; - - case 8: - *(uint64_t*)addr = (uint64_t)val.signedval; - break; - - default: - return false; // something invalid - } - - return true; -} - -//========================================================================== -// -// PInt :: SetValue -// -//========================================================================== - -void PInt::SetValue(void *addr, int val) -{ - assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); - if (Size == 4) - { - *(int *)addr = val; - } - else if (Size == 1) - { - *(uint8_t *)addr = val; - } - else if (Size == 2) - { - *(uint16_t *)addr = val; - } - else if (Size == 8) - { - *(uint64_t *)addr = val; - } - else - { - assert(0 && "Unhandled integer size"); - } -} - -void PInt::SetValue(void *addr, double val) -{ - SetValue(addr, (int)val); -} - -//========================================================================== -// -// PInt :: GetValueInt -// -//========================================================================== - -int PInt::GetValueInt(void *addr) const -{ - assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); - if (Size == 4) - { - return *(int *)addr; - } - else if (Size == 1) - { - return Unsigned ? *(uint8_t *)addr : *(int8_t *)addr; - } - else if (Size == 2) - { - return Unsigned ? *(uint16_t *)addr : *(int16_t *)addr; - } - else if (Size == 8) - { // truncated output - return (int)*(uint64_t *)addr; - } - else - { - assert(0 && "Unhandled integer size"); - return 0; - } -} - -//========================================================================== -// -// PInt :: GetValueFloat -// -//========================================================================== - -double PInt::GetValueFloat(void *addr) const -{ - return GetValueInt(addr); -} - -//========================================================================== -// -// PInt :: GetStoreOp -// -//========================================================================== - -/* PBool ******************************************************************/ - -//========================================================================== -// -// PInt :: SetValue -// -//========================================================================== - -void PBool::SetValue(void *addr, int val) -{ - *(bool*)addr = !!val; -} - -void PBool::SetValue(void *addr, double val) -{ - *(bool*)addr = val != 0.; -} - -int PBool::GetValueInt(void *addr) const -{ - return *(bool *)addr; -} - -double PBool::GetValueFloat(void *addr) const -{ - return *(bool *)addr; -} - -//========================================================================== -// -// PBool Default Constructor -// -//========================================================================== - -PBool::PBool() -: PInt(sizeof(bool), true) -{ - mDescriptiveName = "Bool"; - MemberOnly = false; - Flags |= TYPE_IntNotInt; -} - -/* PFloat *****************************************************************/ - -//========================================================================== -// -// PFloat Parameterized Constructor -// -//========================================================================== - -PFloat::PFloat(unsigned int size) -: PBasicType(size, size) -{ - mDescriptiveName.Format("Float%d", size); - Flags |= TYPE_Float; - if (size == 8) - { - if (sizeof(void*) == 4) - { - // Some ABIs for 32-bit platforms define alignment of double type as 4 bytes - // Intel POSIX (System V ABI) and PowerPC Macs are examples of those - struct AlignmentCheck { uint8_t i; double d; }; - Align = static_cast(offsetof(AlignmentCheck, d)); - } - - SetDoubleSymbols(); - } - else - { - assert(size == 4); - MemberOnly = true; - SetSingleSymbols(); - } - SetOps(); -} - -//========================================================================== -// -// PFloat :: SetDoubleSymbols -// -// Setup constant values for 64-bit floats. -// -//========================================================================== - -void PFloat::SetDoubleSymbols() -{ - static const SymbolInitF symf[] = - { - { NAME_Min_Normal, DBL_MIN }, - { NAME_Max, DBL_MAX }, - { NAME_Epsilon, DBL_EPSILON }, - { NAME_NaN, std::numeric_limits::quiet_NaN() }, - { NAME_Infinity, std::numeric_limits::infinity() }, - { NAME_Min_Denormal, std::numeric_limits::denorm_min() } - }; - static const SymbolInitI symi[] = - { - { NAME_Dig, DBL_DIG }, - { NAME_Min_Exp, DBL_MIN_EXP }, - { NAME_Max_Exp, DBL_MAX_EXP }, - { NAME_Mant_Dig, DBL_MANT_DIG }, - { NAME_Min_10_Exp, DBL_MIN_10_EXP }, - { NAME_Max_10_Exp, DBL_MAX_10_EXP } - }; - SetSymbols(symf, countof(symf)); - SetSymbols(symi, countof(symi)); -} - -//========================================================================== -// -// PFloat :: SetSingleSymbols -// -// Setup constant values for 32-bit floats. -// -//========================================================================== - -void PFloat::SetSingleSymbols() -{ - static const SymbolInitF symf[] = - { - { NAME_Min_Normal, FLT_MIN }, - { NAME_Max, FLT_MAX }, - { NAME_Epsilon, FLT_EPSILON }, - { NAME_NaN, std::numeric_limits::quiet_NaN() }, - { NAME_Infinity, std::numeric_limits::infinity() }, - { NAME_Min_Denormal, std::numeric_limits::denorm_min() } - }; - static const SymbolInitI symi[] = - { - { NAME_Dig, FLT_DIG }, - { NAME_Min_Exp, FLT_MIN_EXP }, - { NAME_Max_Exp, FLT_MAX_EXP }, - { NAME_Mant_Dig, FLT_MANT_DIG }, - { NAME_Min_10_Exp, FLT_MIN_10_EXP }, - { NAME_Max_10_Exp, FLT_MAX_10_EXP } - }; - SetSymbols(symf, countof(symf)); - SetSymbols(symi, countof(symi)); -} - -//========================================================================== -// -// PFloat :: SetSymbols -// -//========================================================================== - -void PFloat::SetSymbols(const PFloat::SymbolInitF *sym, size_t count) -{ - for (size_t i = 0; i < count; ++i) - { - Symbols.AddSymbol(Create(sym[i].Name, this, sym[i].Value)); - } -} - -void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count) -{ - for (size_t i = 0; i < count; ++i) - { - Symbols.AddSymbol(Create(sym[i].Name, this, sym[i].Value)); - } -} - -//========================================================================== -// -// PFloat :: WriteValue -// -//========================================================================== - -void PFloat::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (Size == 8) - { - ar(key, *(double*)addr); - } - else - { - ar(key, *(float*)addr); - } -} - -//========================================================================== -// -// PFloat :: ReadValue -// -//========================================================================== - -bool PFloat::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - NumericValue val; - - ar(key, val); - if (val.type == NumericValue::NM_invalid) return false; // not found or usable - else if (val.type == NumericValue::NM_signed) val.floatval = (double)val.signedval; - else if (val.type == NumericValue::NM_unsigned) val.floatval = (double)val.unsignedval; - - if (Size == 8) - { - *(double*)addr = val.floatval; - } - else - { - *(float*)addr = (float)val.floatval; - } - return true; -} - -//========================================================================== -// -// PFloat :: SetValue -// -//========================================================================== - -void PFloat::SetValue(void *addr, int val) -{ - return SetValue(addr, (double)val); -} - -void PFloat::SetValue(void *addr, double val) -{ - assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); - if (Size == 4) - { - *(float *)addr = (float)val; - } - else - { - assert(Size == 8); - *(double *)addr = val; - } -} - -//========================================================================== -// -// PFloat :: GetValueInt -// -//========================================================================== - -int PFloat::GetValueInt(void *addr) const -{ - return xs_ToInt(GetValueFloat(addr)); -} - -//========================================================================== -// -// PFloat :: GetValueFloat -// -//========================================================================== - -double PFloat::GetValueFloat(void *addr) const -{ - assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); - if (Size == 4) - { - return *(float *)addr; - } - else - { - assert(Size == 8); - return *(double *)addr; - } -} - -//========================================================================== -// -// PFloat :: GetStoreOp -// -//========================================================================== - -void PFloat::SetOps() -{ - if (Size == 4) - { - storeOp = OP_SSP; - loadOp = OP_LSP; - } - else - { - assert(Size == 8); - storeOp = OP_SDP; - loadOp = OP_LDP; - } - moveOp = OP_MOVEF; - RegType = REGT_FLOAT; -} - -/* PString ****************************************************************/ - -//========================================================================== -// -// PString Default Constructor -// -//========================================================================== - -PString::PString() -: PBasicType(sizeof(FString), alignof(FString)) -{ - mDescriptiveName = "String"; - storeOp = OP_SS; - loadOp = OP_LS; - moveOp = OP_MOVES; - RegType = REGT_STRING; - -} - -//========================================================================== -// -// PString :: WriteValue -// -//========================================================================== - -void PString::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - ar(key, *(FString*)addr); -} - -//========================================================================== -// -// PString :: ReadValue -// -//========================================================================== - -bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - const char *cptr; - ar.StringPtr(key, cptr); - if (cptr == nullptr) - { - return false; - } - else - { - *(FString*)addr = cptr; - return true; - } -} - -//========================================================================== -// -// PString :: SetDefaultValue -// -//========================================================================== - -void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) -{ - if (base != nullptr) new((uint8_t *)base + offset) FString; - if (special != nullptr) - { - special->Push(std::make_pair(this, offset)); - } -} - -//========================================================================== -// -// PString :: InitializeValue -// -//========================================================================== - -void PString::InitializeValue(void *addr, const void *def) const -{ - if (def != nullptr) - { - new(addr) FString(*(FString *)def); - } - else - { - new(addr) FString; - } -} - -//========================================================================== -// -// PString :: DestroyValue -// -//========================================================================== - -void PString::DestroyValue(void *addr) const -{ - ((FString *)addr)->~FString(); -} - -/* PName ******************************************************************/ - -//========================================================================== -// -// PName Default Constructor -// -//========================================================================== - -PName::PName() -: PInt(sizeof(FName), true, false) -{ - mDescriptiveName = "Name"; - Flags |= TYPE_IntNotInt; - assert(sizeof(FName) == alignof(FName)); -} - -//========================================================================== -// -// PName :: WriteValue -// -//========================================================================== - -void PName::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - const char *cptr = ((const FName*)addr)->GetChars(); - ar.StringPtr(key, cptr); -} - -//========================================================================== -// -// PName :: ReadValue -// -//========================================================================== - -bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - const char *cptr; - ar.StringPtr(key, cptr); - if (cptr == nullptr) - { - return false; - } - else - { - *(FName*)addr = FName(cptr); - return true; - } -} - -/* PSpriteID ******************************************************************/ - -//========================================================================== -// -// PName Default Constructor -// -//========================================================================== - -PSpriteID::PSpriteID() - : PInt(sizeof(int), true, true) -{ - Flags |= TYPE_IntNotInt; - mDescriptiveName = "SpriteID"; -} - -//========================================================================== -// -// PName :: WriteValue -// -//========================================================================== - -void PSpriteID::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - int32_t val = *(int*)addr; - ar.Sprite(key, val, nullptr); -} - -//========================================================================== -// -// PName :: ReadValue -// -//========================================================================== - -bool PSpriteID::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - int32_t val; - ar.Sprite(key, val, nullptr); - *(int*)addr = val; - return true; -} - -/* PTextureID ******************************************************************/ - -//========================================================================== -// -// PTextureID Default Constructor -// -//========================================================================== - -PTextureID::PTextureID() - : PInt(sizeof(FTextureID), true, false) -{ - mDescriptiveName = "TextureID"; - Flags |= TYPE_IntNotInt; - assert(sizeof(FTextureID) == alignof(FTextureID)); -} - -//========================================================================== -// -// PTextureID :: WriteValue -// -//========================================================================== - -void PTextureID::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - FTextureID val = *(FTextureID*)addr; - ar(key, val); -} - -//========================================================================== -// -// PTextureID :: ReadValue -// -//========================================================================== - -bool PTextureID::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - FTextureID val; - ar(key, val); - *(FTextureID*)addr = val; - return true; -} - -/* PSound *****************************************************************/ - -//========================================================================== -// -// PSound Default Constructor -// -//========================================================================== - -PSound::PSound() -: PInt(sizeof(FSoundID), true) -{ - mDescriptiveName = "Sound"; - Flags |= TYPE_IntNotInt; - assert(sizeof(FSoundID) == alignof(FSoundID)); -} - -//========================================================================== -// -// PSound :: WriteValue -// -//========================================================================== - -void PSound::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - const char *cptr = S_GetSoundName(*(const FSoundID *)addr); - ar.StringPtr(key, cptr); -} - -//========================================================================== -// -// PSound :: ReadValue -// -//========================================================================== - -bool PSound::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - const char *cptr; - ar.StringPtr(key, cptr); - if (cptr == nullptr) - { - return false; - } - else - { - *(FSoundID *)addr = FSoundID(cptr); - return true; - } -} - -/* PColor *****************************************************************/ - -//========================================================================== -// -// PColor Default Constructor -// -//========================================================================== - -PColor::PColor() -: PInt(sizeof(PalEntry), true) -{ - mDescriptiveName = "Color"; - Flags |= TYPE_IntNotInt; - assert(sizeof(PalEntry) == alignof(PalEntry)); -} - -/* PStateLabel *****************************************************************/ - -//========================================================================== -// -// PStateLabel Default Constructor -// -//========================================================================== - -PStateLabel::PStateLabel() - : PInt(sizeof(int), false, false) -{ - Flags |= TYPE_IntNotInt; - mDescriptiveName = "StateLabel"; -} - -/* PPointer ***************************************************************/ - -//========================================================================== -// -// PPointer - Default Constructor -// -//========================================================================== - -PPointer::PPointer() -: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) -{ - mDescriptiveName = "NullPointer"; - loadOp = OP_LP; - storeOp = OP_SP; - moveOp = OP_MOVEA; - RegType = REGT_POINTER; - Flags |= TYPE_Pointer; -} - -//========================================================================== -// -// PPointer - Parameterized Constructor -// -//========================================================================== - -PPointer::PPointer(PType *pointsat, bool isconst) -: PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) -{ - if (pointsat != nullptr) - { - mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst ? "readonly " : ""); - mVersion = pointsat->mVersion; - } - else - { - mDescriptiveName = "Pointer"; - mVersion = 0; - } - loadOp = OP_LP; - storeOp = OP_SP; - moveOp = OP_MOVEA; - RegType = REGT_POINTER; - Flags |= TYPE_Pointer; -} - -//========================================================================== -// -// PPointer :: IsMatch -// -//========================================================================== - -bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const -{ - assert(id2 == 0 || id2 == 1); - PType *pointat = (PType *)id1; - - return pointat == PointedType && (!!id2) == IsConst; -} - -//========================================================================== -// -// PPointer :: GetTypeIDs -// -//========================================================================== - -void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)PointedType; - id2 = 0; -} - -//========================================================================== -// -// PPointer :: WriteValue -// -//========================================================================== - -void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (writer != nullptr) - { - writer(ar, key, addr); - } - else - { - I_Error("Attempt to save pointer to unhandled type %s", PointedType->DescriptiveName()); - } -} - -//========================================================================== -// -// PPointer :: ReadValue -// -//========================================================================== - -bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - if (reader != nullptr) - { - return reader(ar, key, addr); - } - return false; -} - -/* PObjectPointer **********************************************************/ - -//========================================================================== -// -// PPointer :: GetStoreOp -// -//========================================================================== - -PObjectPointer::PObjectPointer(PClass *cls, bool isconst) - : PPointer(cls->VMType, isconst) -{ - loadOp = OP_LO; - Flags |= TYPE_ObjectPointer; - // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. - if (cls && !cls->IsDescendantOf(RUNTIME_CLASS(DThinker))) storeOp = OP_SO; -} - -//========================================================================== -// -// PPointer :: SetPointer -// -//========================================================================== - -void PObjectPointer::SetPointer(void *base, unsigned offset, TArray *special) -{ - // Add to the list of pointers for this class. - special->Push(offset); -} - -//========================================================================== -// -// PPointer :: WriteValue -// -//========================================================================== - -void PObjectPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - ar(key, *(DObject **)addr); -} - -//========================================================================== -// -// PPointer :: ReadValue -// -//========================================================================== - -bool PObjectPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - bool res; - ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); - return res; -} - -//========================================================================== -// -// NewPointer -// -// Returns a PPointer to an object of the specified type -// -//========================================================================== - -PPointer *NewPointer(PType *type, bool isconst) -{ - auto cp = PType::toClass(type); - if (cp) return NewPointer(cp->Descriptor, isconst); - - size_t bucket; - PType *ptype = TypeTable.FindType(NAME_Pointer, (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == nullptr) - { - ptype = new PPointer(type, isconst); - TypeTable.AddType(ptype, NAME_Pointer, (intptr_t)type, isconst ? 1 : 0, bucket); - } - return static_cast(ptype); -} - -PPointer *NewPointer(PClass *cls, bool isconst) -{ - assert(cls->VMType != nullptr); - - auto type = cls->VMType; - size_t bucket; - PType *ptype = TypeTable.FindType(NAME_Pointer, (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == nullptr) - { - ptype = new PObjectPointer(cls, isconst); - TypeTable.AddType(ptype, NAME_Pointer, (intptr_t)type, isconst ? 1 : 0, bucket); - } - return static_cast(ptype); -} - -/* PStatePointer **********************************************************/ - -//========================================================================== -// -// PStatePointer Default Constructor -// -//========================================================================== - -PStatePointer::PStatePointer() -{ - mDescriptiveName = "Pointer"; - PointedType = NewStruct(NAME_State, nullptr, true); - IsConst = true; -} - -//========================================================================== -// -// PStatePointer :: WriteValue -// -//========================================================================== - -void PStatePointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - ar(key, *(FState **)addr); -} - -//========================================================================== -// -// PStatePointer :: ReadValue -// -//========================================================================== - -bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - bool res = false; - ::Serialize(ar, key, *(FState **)addr, nullptr, &res); - return res; -} - - - -/* PClassPointer **********************************************************/ - -//========================================================================== -// -// PClassPointer - Parameterized Constructor -// -//========================================================================== - -PClassPointer::PClassPointer(PClass *restrict) -: PPointer(restrict->VMType), ClassRestriction(restrict) -{ - if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); - else mDescriptiveName = "ClassPointer"; - loadOp = OP_LP; - storeOp = OP_SP; - Flags |= TYPE_ClassPointer; - mVersion = restrict->VMType->mVersion; -} - -//========================================================================== -// -// PPointer :: WriteValue -// -//========================================================================== - -void PClassPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - ar(key, *(PClass **)addr); -} - -//========================================================================== -// -// PPointer :: ReadValue -// -//========================================================================== - -bool PClassPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); - return false; -} - -//========================================================================== -// -// PClassPointer - isCompatible -// -//========================================================================== - -bool PClassPointer::isCompatible(PType *type) -{ - auto other = PType::toClassPointer(type); - return (other != nullptr && other->ClassRestriction->IsDescendantOf(ClassRestriction)); -} - -//========================================================================== -// -// PClassPointer :: SetPointer -// -//========================================================================== - -void PClassPointer::SetPointer(void *base, unsigned offset, TArray *special) -{ -} - -//========================================================================== -// -// PClassPointer :: IsMatch -// -//========================================================================== - -bool PClassPointer::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PClass *classat = (const PClass *)id2; - return classat == ClassRestriction; -} - -//========================================================================== -// -// PClassPointer :: GetTypeIDs -// -//========================================================================== - -void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = 0; - id2 = (intptr_t)ClassRestriction; -} - -//========================================================================== -// -// NewClassPointer -// -// Returns a PClassPointer for the restricted type. -// -//========================================================================== - -PClassPointer *NewClassPointer(PClass *restrict) -{ - size_t bucket; - PType *ptype = TypeTable.FindType(NAME_Class, 0, (intptr_t)restrict, &bucket); - if (ptype == nullptr) - { - ptype = new PClassPointer(restrict); - TypeTable.AddType(ptype, NAME_Class, 0, (intptr_t)restrict, bucket); - } - return static_cast(ptype); -} - -/* PEnum ******************************************************************/ - -//========================================================================== -// -// PEnum - Parameterized Constructor -// -//========================================================================== - -PEnum::PEnum(FName name, PTypeBase *outer) -: PInt(4, false), Outer(outer), EnumName(name) -{ - Flags |= TYPE_IntNotInt; - mDescriptiveName.Format("Enum<%s>", name.GetChars()); -} - -//========================================================================== -// -// NewEnum -// -// Returns a PEnum for the given name and container, making sure not to -// create duplicates. -// -//========================================================================== - -PEnum *NewEnum(FName name, PTypeBase *outer) -{ - size_t bucket; - if (outer == nullptr) outer = Namespaces.GlobalNamespace; - PType *etype = TypeTable.FindType(NAME_Enum, (intptr_t)outer, (intptr_t)name, &bucket); - if (etype == nullptr) - { - etype = new PEnum(name, outer); - TypeTable.AddType(etype, NAME_Enum, (intptr_t)outer, (intptr_t)name, bucket); - } - return static_cast(etype); -} - -/* PArray *****************************************************************/ - -//========================================================================== -// -// PArray - Parameterized Constructor -// -//========================================================================== - -PArray::PArray(PType *etype, unsigned int ecount) -: ElementType(etype), ElementCount(ecount) -{ - mDescriptiveName.Format("Array<%s>[%d]", etype->DescriptiveName(), ecount); - - Align = etype->Align; - // Since we are concatenating elements together, the element size should - // also be padded to the nearest alignment. - ElementSize = (etype->Size + (etype->Align - 1)) & ~(etype->Align - 1); - Size = ElementSize * ecount; - Flags |= TYPE_Array; -} - -//========================================================================== -// -// PArray :: IsMatch -// -//========================================================================== - -bool PArray::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PType *elemtype = (const PType *)id1; - unsigned int count = (unsigned int)(intptr_t)id2; - - return elemtype == ElementType && count == ElementCount; -} - -//========================================================================== -// -// PArray :: GetTypeIDs -// -//========================================================================== - -void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)ElementType; - id2 = ElementCount; -} - -//========================================================================== -// -// PArray :: WriteValue -// -//========================================================================== - -void PArray::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (ar.BeginArray(key)) - { - const uint8_t *addrb = (const uint8_t *)addr; - for (unsigned i = 0; i < ElementCount; ++i) - { - ElementType->WriteValue(ar, nullptr, addrb); - addrb += ElementSize; - } - ar.EndArray(); - } -} - -//========================================================================== -// -// PArray :: ReadValue -// -//========================================================================== - -bool PArray::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - if (ar.BeginArray(key)) - { - bool readsomething = false; - unsigned count = ar.ArraySize(); - unsigned loop = MIN(count, ElementCount); - uint8_t *addrb = (uint8_t *)addr; - for(unsigned i=0;iReadValue(ar, nullptr, addrb); - addrb += ElementSize; - } - if (loop < count) - { - DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n", - count, ElementCount); - } - ar.EndArray(); - return readsomething; - } - return false; -} - -//========================================================================== -// -// PArray :: SetDefaultValue -// -//========================================================================== - -void PArray::SetDefaultValue(void *base, unsigned offset, TArray *special) -{ - for (unsigned i = 0; i < ElementCount; ++i) - { - ElementType->SetDefaultValue(base, offset + i*ElementSize, special); - } -} - -//========================================================================== -// -// PArray :: SetDefaultValue -// -//========================================================================== - -void PArray::SetPointer(void *base, unsigned offset, TArray *special) -{ - for (unsigned i = 0; i < ElementCount; ++i) - { - ElementType->SetPointer(base, offset + i*ElementSize, special); - } -} - -//========================================================================== -// -// PArray :: SetPointerArray -// -//========================================================================== - -void PArray::SetPointerArray(void *base, unsigned offset, TArray *special) -{ - if (ElementType->isStruct()) - { - for (unsigned int i = 0; i < ElementCount; ++i) - { - ElementType->SetPointerArray(base, offset + ElementSize * i, special); - } - } -} - -//========================================================================== -// -// NewArray -// -// Returns a PArray for the given type and size, making sure not to create -// duplicates. -// -//========================================================================== - -PArray *NewArray(PType *type, unsigned int count) -{ - size_t bucket; - PType *atype = TypeTable.FindType(NAME_Array, (intptr_t)type, count, &bucket); - if (atype == nullptr) - { - atype = new PArray(type, count); - TypeTable.AddType(atype, NAME_Array, (intptr_t)type, count, bucket); - } - return (PArray *)atype; -} - -/* PArray *****************************************************************/ - -//========================================================================== -// -// PArray - Parameterized Constructor -// -//========================================================================== - -PStaticArray::PStaticArray(PType *etype) - : PArray(etype, 0) -{ - mDescriptiveName.Format("ResizableArray<%s>", etype->DescriptiveName()); -} - -//========================================================================== -// -// PArray :: IsMatch -// -//========================================================================== - -bool PStaticArray::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PType *elemtype = (const PType *)id1; - unsigned int count = (unsigned int)(intptr_t)id2; - - return elemtype == ElementType && count == 0; -} - -//========================================================================== -// -// PArray :: GetTypeIDs -// -//========================================================================== - -void PStaticArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)ElementType; - id2 = 0; -} - -//========================================================================== -// -// NewStaticArray -// -// Returns a PArray for the given type and size, making sure not to create -// duplicates. -// -//========================================================================== - -PStaticArray *NewStaticArray(PType *type) -{ - size_t bucket; - PType *atype = TypeTable.FindType(NAME_StaticArray, (intptr_t)type, 0, &bucket); - if (atype == nullptr) - { - atype = new PStaticArray(type); - TypeTable.AddType(atype, NAME_StaticArray, (intptr_t)type, 0, bucket); - } - return (PStaticArray *)atype; -} - -/* PDynArray **************************************************************/ - -//========================================================================== -// -// PDynArray - Parameterized Constructor -// -//========================================================================== - -PDynArray::PDynArray(PType *etype,PStruct *backing) -: ElementType(etype), BackingType(backing) -{ - mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); - Size = sizeof(FArray); - Align = alignof(FArray); -} - -//========================================================================== -// -// PDynArray :: IsMatch -// -//========================================================================== - -bool PDynArray::IsMatch(intptr_t id1, intptr_t id2) const -{ - assert(id2 == 0); - const PType *elemtype = (const PType *)id1; - - return elemtype == ElementType; -} - -//========================================================================== -// -// PDynArray :: GetTypeIDs -// -//========================================================================== - -void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)ElementType; - id2 = 0; -} - -//========================================================================== -// -// PDynArray :: InitializeValue -// -//========================================================================== - -void PDynArray::InitializeValue(void *addr, const void *deff) const -{ - const FArray *def = (const FArray*)deff; - FArray *aray = (FArray*)addr; - - if (def == nullptr || def->Count == 0) - { - // Empty arrays do not need construction. - *aray = { nullptr, 0, 0 }; - } - else if (ElementType->GetRegType() != REGT_STRING) - { - // These are just integral values which can be done without any constructor hackery. - size_t blocksize = ElementType->Size * def->Count; - aray->Array = M_Malloc(blocksize); - memcpy(aray->Array, def->Array, blocksize); - aray->Most = aray->Count = def->Count; - } - else - { - // non-empty string arrays require explicit construction. - new(addr) TArray(*(TArray*)def); - } -} - -//========================================================================== -// -// PDynArray :: DestroyValue -// -//========================================================================== - -void PDynArray::DestroyValue(void *addr) const -{ - FArray *aray = (FArray*)addr; - - if (aray->Array != nullptr) - { - if (ElementType->GetRegType() != REGT_STRING) - { - M_Free(aray->Array); - } - else - { - // Damn those cursed strings again. :( - ((TArray*)addr)->~TArray(); - } - } - aray->Count = aray->Most = 0; - aray->Array = nullptr; -} - -//========================================================================== -// -// PDynArray :: SetDefaultValue -// -//========================================================================== - -void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) -{ - if (base != nullptr) memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array. - if (special != nullptr) - { - special->Push(std::make_pair(this, offset)); - } -} - -//========================================================================== -// -// PDynArray :: SetPointer -// -//========================================================================== - -void PDynArray::SetPointerArray(void *base, unsigned offset, TArray *special) -{ - if (ElementType->isObjectPointer()) - { - // Add to the list of pointer arrays for this class. - special->Push(offset); - } -} - -//========================================================================== -// -// PDynArray :: WriteValue -// -//========================================================================== - -void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - FArray *aray = (FArray*)addr; - // We may skip an empty array only if it gets stored under a named key. - // If no name is given, i.e. it's part of an outer array's element list, even empty arrays must be stored, - // because otherwise the array would lose its entry. - if (aray->Count > 0 || key == nullptr) - { - if (ar.BeginArray(key)) - { - const uint8_t *addrb = (const uint8_t *)aray->Array; - for (unsigned i = 0; i < aray->Count; ++i) - { - ElementType->WriteValue(ar, nullptr, addrb); - addrb += ElementType->Size; - } - ar.EndArray(); - } - } -} - -//========================================================================== -// -// PDynArray :: ReadValue -// -//========================================================================== - -bool PDynArray::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - FArray *aray = (FArray*)addr; - DestroyValue(addr); // note that even after calling this we still got a validly constructed empty array. - - if (ar.BeginArray(key)) - { - bool readsomething = false; - unsigned count = ar.ArraySize(); - - size_t blocksize = ElementType->Size * count; - aray->Array = M_Malloc(blocksize); - memset(aray->Array, 0, blocksize); - aray->Most = aray->Count = count; - - uint8_t *addrb = (uint8_t *)aray->Array; - for (unsigned i = 0; iGetRegType() == REGT_STRING) new(addrb) FString; - readsomething |= ElementType->ReadValue(ar, nullptr, addrb); - addrb += ElementType->Size; - } - ar.EndArray(); - return readsomething; - } - return false; -} - -//========================================================================== -// -// NewDynArray -// -// Creates a new DynArray of the given type, making sure not to create a -// duplicate. -// -//========================================================================== - -PDynArray *NewDynArray(PType *type) -{ - size_t bucket; - PType *atype = TypeTable.FindType(NAME_DynArray, (intptr_t)type, 0, &bucket); - if (atype == nullptr) - { - FString backingname; - - switch (type->GetRegType()) - { - case REGT_INT: - backingname.Format("DynArray_I%d", type->Size * 8); - break; - - case REGT_FLOAT: - backingname.Format("DynArray_F%d", type->Size * 8); - break; - - case REGT_STRING: - backingname = "DynArray_String"; - break; - - case REGT_POINTER: - if (type->isObjectPointer()) - backingname = "DynArray_Obj"; - else - backingname = "DynArray_Ptr"; - break; - - default: - I_Error("Unsupported dynamic array requested"); - break; - } - - auto backing = NewStruct(backingname, nullptr, true); - atype = new PDynArray(type, backing); - TypeTable.AddType(atype, NAME_DynArray, (intptr_t)type, 0, bucket); - } - return (PDynArray *)atype; -} - -/* PMap *******************************************************************/ - -//========================================================================== -// -// PMap - Parameterized Constructor -// -//========================================================================== - -PMap::PMap(PType *keytype, PType *valtype) -: KeyType(keytype), ValueType(valtype) -{ - mDescriptiveName.Format("Map<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName()); - Size = sizeof(FMap); - Align = alignof(FMap); -} - -//========================================================================== -// -// PMap :: IsMatch -// -//========================================================================== - -bool PMap::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PType *keyty = (const PType *)id1; - const PType *valty = (const PType *)id2; - - return keyty == KeyType && valty == ValueType; -} - -//========================================================================== -// -// PMap :: GetTypeIDs -// -//========================================================================== - -void PMap::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)KeyType; - id2 = (intptr_t)ValueType; -} - -//========================================================================== -// -// NewMap -// -// Returns a PMap for the given key and value types, ensuring not to create -// duplicates. -// -//========================================================================== - -PMap *NewMap(PType *keytype, PType *valuetype) -{ - size_t bucket; - PType *maptype = TypeTable.FindType(NAME_Map, (intptr_t)keytype, (intptr_t)valuetype, &bucket); - if (maptype == nullptr) - { - maptype = new PMap(keytype, valuetype); - TypeTable.AddType(maptype, NAME_Map, (intptr_t)keytype, (intptr_t)valuetype, bucket); - } - return (PMap *)maptype; -} - -/* PStruct ****************************************************************/ - -//========================================================================== -// -// PStruct - Parameterized Constructor -// -//========================================================================== - -PStruct::PStruct(FName name, PTypeBase *outer, bool isnative) -: PContainerType(name, outer) -{ - mDescriptiveName.Format("%sStruct<%s>", isnative? "Native" : "", name.GetChars()); - Size = 0; - isNative = isnative; -} - -//========================================================================== -// -// PStruct :: SetDefaultValue -// -//========================================================================== - -void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) -{ - auto it = Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - while (it.NextPair(pair)) - { - auto field = dyn_cast(pair->Value); - if (field && !(field->Flags & VARF_Transient)) - { - field->Type->SetDefaultValue(base, unsigned(offset + field->Offset), special); - } - } -} - -//========================================================================== -// -// PStruct :: SetPointer -// -//========================================================================== - -void PStruct::SetPointer(void *base, unsigned offset, TArray *special) -{ - auto it = Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - while (it.NextPair(pair)) - { - auto field = dyn_cast(pair->Value); - if (field && !(field->Flags & VARF_Transient)) - { - field->Type->SetPointer(base, unsigned(offset + field->Offset), special); - } - } -} - -//========================================================================== -// -// PStruct :: SetPointerArray -// -//========================================================================== - -void PStruct::SetPointerArray(void *base, unsigned offset, TArray *special) -{ - auto it = Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - while (it.NextPair(pair)) - { - auto field = dyn_cast(pair->Value); - if (field && !(field->Flags & VARF_Transient)) - { - field->Type->SetPointerArray(base, unsigned(offset + field->Offset), special); - } - } -} - -//========================================================================== -// -// PStruct :: WriteValue -// -//========================================================================== - -void PStruct::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (ar.BeginObject(key)) - { - Symbols.WriteFields(ar, addr); - ar.EndObject(); - } -} - -//========================================================================== -// -// PStruct :: ReadValue -// -//========================================================================== - -bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - if (ar.BeginObject(key)) - { - bool ret = Symbols.ReadFields(ar, addr, DescriptiveName()); - ar.EndObject(); - return ret; - } - return false; -} - -//========================================================================== -// -// PStruct :: AddField -// -// Appends a new field to the end of a struct. Returns either the new field -// or nullptr if a symbol by that name already exists. -// -//========================================================================== - -PField *PStruct::AddField(FName name, PType *type, uint32_t flags) -{ - assert(type->Size > 0); - return Symbols.AddField(name, type, flags, Size, &Align); -} - -//========================================================================== -// -// PStruct :: AddField -// -// Appends a new native field to the struct. Returns either the new field -// or nullptr if a symbol by that name already exists. -// -//========================================================================== - -PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) -{ - return Symbols.AddNativeField(name, type, address, flags, bitvalue); -} - -//========================================================================== -// -// NewStruct -// Returns a PStruct for the given name and container, making sure not to -// create duplicates. -// -//========================================================================== - -PStruct *NewStruct(FName name, PTypeBase *outer, bool native) -{ - size_t bucket; - if (outer == nullptr) outer = Namespaces.GlobalNamespace; - PType *stype = TypeTable.FindType(NAME_Struct, (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == nullptr) - { - stype = new PStruct(name, outer, native); - TypeTable.AddType(stype, NAME_Struct, (intptr_t)outer, (intptr_t)name, bucket); - } - return static_cast(stype); -} - - -/* PPrototype *************************************************************/ - -//========================================================================== -// -// PPrototype - Parameterized Constructor -// -//========================================================================== - -PPrototype::PPrototype(const TArray &rettypes, const TArray &argtypes) -: ArgumentTypes(argtypes), ReturnTypes(rettypes) -{ -} - -//========================================================================== -// -// PPrototype :: IsMatch -// -//========================================================================== - -bool PPrototype::IsMatch(intptr_t id1, intptr_t id2) const -{ - const TArray *args = (const TArray *)id1; - const TArray *rets = (const TArray *)id2; - - return *args == ArgumentTypes && *rets == ReturnTypes; -} - -//========================================================================== -// -// PPrototype :: GetTypeIDs -// -//========================================================================== - -void PPrototype::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)&ArgumentTypes; - id2 = (intptr_t)&ReturnTypes; -} - -//========================================================================== -// -// NewPrototype -// -// Returns a PPrototype for the given return and argument types, making sure -// not to create duplicates. -// -//========================================================================== - -PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes) -{ - size_t bucket; - PType *proto = TypeTable.FindType(NAME_Prototype, (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); - if (proto == nullptr) - { - proto = new PPrototype(rettypes, argtypes); - TypeTable.AddType(proto, NAME_Prototype, (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); - } - return static_cast(proto); -} - -/* PClass *****************************************************************/ - -//========================================================================== -// -// -// -//========================================================================== - -PClassType::PClassType(PClass *cls) -{ - assert(cls->VMType == nullptr); - Descriptor = cls; - TypeName = cls->TypeName; - if (cls->ParentClass != nullptr) - { - ParentType = cls->ParentClass->VMType; - assert(ParentType != nullptr); - Symbols.SetParentTable(&ParentType->Symbols); - ScopeFlags = ParentType->ScopeFlags; - } - cls->VMType = this; - mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); -} - -//========================================================================== -// -// PClass :: AddField -// -//========================================================================== - -PField *PClassType::AddField(FName name, PType *type, uint32_t flags) -{ - return Descriptor->AddField(name, type, flags); -} - -//========================================================================== -// -// PClass :: AddNativeField -// -//========================================================================== - -PField *PClassType::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) -{ - auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue); - if (field != nullptr) Descriptor->Fields.Push(field); - return field; -} - -//========================================================================== -// -// -// -//========================================================================== - -PClassType *NewClassType(PClass *cls) -{ - size_t bucket; - PType *ptype = TypeTable.FindType(NAME_Object, 0, (intptr_t)cls->TypeName, &bucket); - if (ptype == nullptr) - { - ptype = new PClassType(cls); - TypeTable.AddType(ptype, NAME_Object, 0, (intptr_t)cls->TypeName, bucket); - } - return static_cast(ptype); -} - - -/* FTypeTable **************************************************************/ - -//========================================================================== -// -// FTypeTable :: FindType -// -//========================================================================== - -PType *FTypeTable::FindType(FName type_name, intptr_t parm1, intptr_t parm2, size_t *bucketnum) -{ - size_t bucket = Hash(type_name, parm1, parm2) % HASH_SIZE; - if (bucketnum != nullptr) - { - *bucketnum = bucket; - } - for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) - { - if (type->TypeTableType == type_name && type->IsMatch(parm1, parm2)) - { - return type; - } - } - return nullptr; -} - -//========================================================================== -// -// FTypeTable :: AddType - Fully Parameterized Version -// -//========================================================================== - -void FTypeTable::AddType(PType *type, FName type_name, intptr_t parm1, intptr_t parm2, size_t bucket) -{ -#ifdef _DEBUG - size_t bucketcheck; - assert(FindType(type_name, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once"); - assert(bucketcheck == bucket && "Passed bucket was wrong"); -#endif - type->TypeTableType = type_name; - type->HashNext = TypeHash[bucket]; - TypeHash[bucket] = type; -} - -//========================================================================== -// -// FTypeTable :: AddType - Simple Version -// -//========================================================================== - -void FTypeTable::AddType(PType *type, FName type_name) -{ - intptr_t parm1, parm2; - size_t bucket; - - // Type table stuff id only needed to let all classes hash to the same group. For all other types this is pointless. - type->TypeTableType = type_name; - type->GetTypeIDs(parm1, parm2); - bucket = Hash(type_name, parm1, parm2) % HASH_SIZE; - assert(FindType(type_name, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once"); - - type->HashNext = TypeHash[bucket]; - TypeHash[bucket] = type; -} - -//========================================================================== -// -// FTypeTable :: Hash STATIC -// -//========================================================================== - -size_t FTypeTable::Hash(FName p1, intptr_t p2, intptr_t p3) -{ - size_t i1 = (size_t)p1; - - // Swap the high and low halves of i1. The compiler should be smart enough - // to transform this into a ROR or ROL. - i1 = (i1 >> (sizeof(size_t)*4)) | (i1 << (sizeof(size_t)*4)); - - if (p1 != NAME_Prototype) - { - size_t i2 = (size_t)p2; - size_t i3 = (size_t)p3; - return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime - } - else - { // Prototypes need to hash the TArrays at p2 and p3 - const TArray *a2 = (const TArray *)p2; - const TArray *a3 = (const TArray *)p3; - for (unsigned i = 0; i < a2->Size(); ++i) - { - i1 = (i1 * 961748927) + (size_t)((*a2)[i]); - } - for (unsigned i = 0; i < a3->Size(); ++i) - { - i1 = (i1 * 961748927) + (size_t)((*a3)[i]); - } - return i1; - } -} - -//========================================================================== -// -// FTypeTable :: Clear -// -//========================================================================== - -void FTypeTable::Clear() -{ - for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) - { - for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr;) - { - auto next = ty->HashNext; - delete ty; - ty = next; - } - } - memset(TypeHash, 0, sizeof(TypeHash)); -} - -#include "c_dispatch.h" -CCMD(typetable) -{ - DumpTypeTable(); -} - diff --git a/src/scripting/types.h b/src/scripting/types.h deleted file mode 100644 index 7d2f2341cce..00000000000 --- a/src/scripting/types.h +++ /dev/null @@ -1,645 +0,0 @@ -#pragma once - -#include "dobject.h" -#include "serializer.h" -#include "scripting/backend/scopebarrier.h" - -// Variable/parameter/field flags ------------------------------------------- - -// Making all these different storage types use a common set of flags seems -// like the simplest thing to do. - -enum -{ - VARF_Optional = (1<<0), // func param is optional - VARF_Method = (1<<1), // func has an implied self parameter - VARF_Action = (1<<2), // func has implied owner and state parameters - VARF_Native = (1<<3), // func is native code, field is natively defined - VARF_ReadOnly = (1<<4), // field is read only, do not write to it - VARF_Private = (1<<5), // field is private to containing class - VARF_Protected = (1<<6), // field is only accessible by containing class and children. - VARF_Deprecated = (1<<7), // Deprecated fields should output warnings when used. - VARF_Virtual = (1<<8), // function is virtual - VARF_Final = (1<<9), // Function may not be overridden in subclasses - VARF_In = (1<<10), - VARF_Out = (1<<11), - VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures) - VARF_Static = (1<<13), - VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. - VARF_Override = (1<<15), // overrides a virtual function from the parent class. - VARF_Ref = (1<<16), // argument is passed by reference. - VARF_Transient = (1<<17), // don't auto serialize field. - VARF_Meta = (1<<18), // static class data (by necessity read only.) - VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature - VARF_UI = (1<<20), // [ZZ] ui: object is ui-scope only (can't modify playsim) - VARF_Play = (1<<21), // [ZZ] play: object is playsim-scope only (can't access ui) - VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only) - VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data. -}; - -// Basic information shared by all types ------------------------------------ - -// Only one copy of a type is ever instantiated at one time. -// - Enums, classes, and structs are defined by their names and outer classes. -// - Pointers are uniquely defined by the type they point at. -// - ClassPointers are also defined by their class restriction. -// - Arrays are defined by their element type and count. -// - DynArrays are defined by their element type. -// - Maps are defined by their key and value types. -// - Prototypes are defined by the argument and return types. -// - Functions are defined by their names and outer objects. -// In table form: -// Outer Name Type Type2 Count -// Enum * * -// Class * * -// Struct * * -// Function * * -// Pointer * -// ClassPointer + * -// Array * * -// DynArray * -// Map * * -// Prototype *+ *+ - -class PContainerType; -class PPointer; -class PClassPointer; -class PArray; -class PStruct; -class PClassType; - -struct ZCC_ExprConstant; -class PType : public PTypeBase -{ -protected: - - enum ETypeFlags - { - TYPE_Scalar = 1, - TYPE_Container = 2, - TYPE_Int = 4, - TYPE_IntNotInt = 8, // catch-all for subtypes that are not being checked by type directly. - TYPE_Float = 16, - TYPE_Pointer = 32, - TYPE_ObjectPointer = 64, - TYPE_ClassPointer = 128, - TYPE_Array = 256, - - TYPE_IntCompatible = TYPE_Int | TYPE_IntNotInt, // must be the combination of all flags that are subtypes of int and can be cast to an int. - }; - -public: - FName TypeTableType; // The type to use for hashing into the type table - unsigned int Size; // this type's size - unsigned int Align; // this type's preferred alignment - unsigned int Flags = 0; // What is this type? - PType *HashNext; // next type in this type table - PSymbolTable Symbols; - bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument. - FString mDescriptiveName; - VersionInfo mVersion = { 0,0,0 }; - uint8_t loadOp, storeOp, moveOp, RegType, RegCount; - EScopeFlags ScopeFlags = (EScopeFlags)0; - - PType(unsigned int size = 1, unsigned int align = 1); - virtual ~PType(); - virtual bool isNumeric() { return false; } - - // Writes the value of a variable of this type at (addr) to an archive, preceded by - // a tag indicating its type. The tag is there so that variable types can be changed - // without completely breaking savegames, provided that the change isn't between - // totally unrelated types. - virtual void WriteValue(FSerializer &ar, const char *key,const void *addr) const; - - // Returns true if the stored value was compatible. False otherwise. - // If the value was incompatible, then the memory at *addr is unchanged. - virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const; - - // Sets the default value for this type at (base + offset) - // If the default value is binary 0, then this function doesn't need - // to do anything, because PClass::Extend() takes care of that. - // - // The stroffs array is so that types that need special initialization - // and destruction (e.g. strings) can add their offsets to it for special - // initialization when the object is created and destruction when the - // object is destroyed. - virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL); - virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL); - virtual void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL); - - // Initialize the value, if needed (e.g. strings) - virtual void InitializeValue(void *addr, const void *def) const; - - // Destroy the value, if needed (e.g. strings) - virtual void DestroyValue(void *addr) const; - - // Sets the value of a variable of this type at (addr) - virtual void SetValue(void *addr, int val); - virtual void SetValue(void *addr, double val); - - // Gets the value of a variable of this type at (addr) - virtual int GetValueInt(void *addr) const; - virtual double GetValueFloat(void *addr) const; - - // Gets the opcode to store from a register to memory - int GetStoreOp() const - { - return storeOp; - } - - // Gets the opcode to load from memory to a register - int GetLoadOp() const - { - return loadOp; - } - - // Gets the opcode to move from register to another register - int GetMoveOp() const - { - return moveOp; - } - - // Gets the register type for this type - int GetRegType() const - { - return RegType; - } - - int GetRegCount() const - { - return RegCount; - } - // Returns true if this type matches the two identifiers. Referring to the - // above table, any type is identified by at most two characteristics. Each - // type that implements this function will cast these to the appropriate type. - // It is up to the caller to make sure they are the correct types. There is - // only one prototype for this function in order to simplify type table - // management. - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - - // Get the type IDs used by IsMatch - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - - const char *DescriptiveName() const; - - static void StaticInit(); - - bool isScalar() const { return !!(Flags & TYPE_Scalar); } - bool isContainer() const { return !!(Flags & TYPE_Container); } - bool isInt() const { return (Flags & TYPE_IntCompatible) == TYPE_Int; } - bool isIntCompatible() const { return !!(Flags & TYPE_IntCompatible); } - bool isFloat() const { return !!(Flags & TYPE_Float); } - bool isPointer() const { return !!(Flags & TYPE_Pointer); } - bool isRealPointer() const { return (Flags & (TYPE_Pointer|TYPE_ClassPointer)) == TYPE_Pointer; } // This excludes class pointers which use their PointedType differently - bool isObjectPointer() const { return !!(Flags & TYPE_ObjectPointer); } - bool isClassPointer() const { return !!(Flags & TYPE_ClassPointer); } - bool isEnum() const { return TypeTableType == NAME_Enum; } - bool isArray() const { return !!(Flags & TYPE_Array); } - bool isStaticArray() const { return TypeTableType == NAME_StaticArray; } - bool isDynArray() const { return TypeTableType == NAME_DynArray; } - bool isStruct() const { return TypeTableType == NAME_Struct; } - bool isClass() const { return TypeTableType == NAME_Object; } - bool isPrototype() const { return TypeTableType == NAME_Prototype; } - - PContainerType *toContainer() { return isContainer() ? (PContainerType*)this : nullptr; } - PPointer *toPointer() { return isPointer() ? (PPointer*)this : nullptr; } - static PClassPointer *toClassPointer(PType *t) { return t && t->isClassPointer() ? (PClassPointer*)t : nullptr; } - static PClassType *toClass(PType *t) { return t && t->isClass() ? (PClassType*)t : nullptr; } -}; - -// Not-really-a-type types -------------------------------------------------- - -class PErrorType : public PType -{ -public: - PErrorType(int which = 1) : PType(0, which) {} -}; - -class PVoidType : public PType -{ -public: - PVoidType() : PType(0, 1) {} -}; - -// Some categorization typing ----------------------------------------------- - -class PBasicType : public PType -{ -protected: - PBasicType(unsigned int size = 1, unsigned int align = 1); -}; - -class PCompoundType : public PType -{ -protected: - PCompoundType(unsigned int size = 1, unsigned int align = 1); -}; - -class PContainerType : public PCompoundType -{ -public: - PTypeBase *Outer = nullptr; // object this type is contained within - FName TypeName = NAME_None; // this type's name - - PContainerType() - { - mDescriptiveName = "ContainerType"; - Flags |= TYPE_Container; - } - PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) - { - mDescriptiveName = name.GetChars(); - Flags |= TYPE_Container; - } - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - virtual PField *AddField(FName name, PType *type, uint32_t flags = 0) = 0; - virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) = 0; -}; - -// Basic types -------------------------------------------------------------- - -class PInt : public PBasicType -{ -public: - PInt(unsigned int size, bool unsign, bool compatible = true); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; - - virtual void SetValue(void *addr, int val); - virtual void SetValue(void *addr, double val); - virtual int GetValueInt(void *addr) const; - virtual double GetValueFloat(void *addr) const; - virtual bool isNumeric() override { return IntCompatible; } - - bool Unsigned; - bool IntCompatible; -protected: - void SetOps(); -}; - -class PBool : public PInt -{ -public: - PBool(); - virtual void SetValue(void *addr, int val); - virtual void SetValue(void *addr, double val); - virtual int GetValueInt(void *addr) const; - virtual double GetValueFloat(void *addr) const; -}; - -class PFloat : public PBasicType -{ -public: - PFloat(unsigned int size = 8); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; - - virtual void SetValue(void *addr, int val); - virtual void SetValue(void *addr, double val); - virtual int GetValueInt(void *addr) const; - virtual double GetValueFloat(void *addr) const; - virtual bool isNumeric() override { return true; } -protected: - void SetOps(); -private: - struct SymbolInitF - { - ENamedName Name; - double Value; - }; - struct SymbolInitI - { - ENamedName Name; - int Value; - }; - - void SetSingleSymbols(); - void SetDoubleSymbols(); - void SetSymbols(const SymbolInitF *syminit, size_t count); - void SetSymbols(const SymbolInitI *syminit, size_t count); -}; - -class PString : public PBasicType -{ -public: - PString(); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; - void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) override; - void InitializeValue(void *addr, const void *def) const override; - void DestroyValue(void *addr) const override; -}; - -// Variations of integer types ---------------------------------------------- - -class PName : public PInt -{ -public: - PName(); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; -}; - -class PSound : public PInt -{ -public: - PSound(); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; -}; - -class PSpriteID : public PInt -{ -public: - PSpriteID(); - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; -}; - -class PTextureID : public PInt -{ -public: - PTextureID(); - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; -}; - -class PColor : public PInt -{ -public: - PColor(); -}; - -class PStateLabel : public PInt -{ -public: - PStateLabel(); -}; - -// Pointers ----------------------------------------------------------------- - -class PPointer : public PBasicType -{ - -public: - typedef void(*WriteHandler)(FSerializer &ar, const char *key, const void *addr); - typedef bool(*ReadHandler)(FSerializer &ar, const char *key, void *addr); - - PPointer(); - PPointer(PType *pointsat, bool isconst = false); - - PType *PointedType; - bool IsConst; - - WriteHandler writer = nullptr; - ReadHandler reader = nullptr; - - void InstallHandlers(WriteHandler w, ReadHandler r) - { - writer = w; - reader = r; - } - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; - -protected: - void SetOps(); -}; - -class PStatePointer : public PPointer -{ -public: - PStatePointer(); - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; -}; - - -class PObjectPointer : public PPointer -{ -public: - PObjectPointer(PClass *pointedtype = nullptr, bool isconst = false); - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; - void SetPointer(void *base, unsigned offset, TArray *special = NULL) override; - PClass *PointedClass() const; -}; - - -class PClassPointer : public PPointer -{ -public: - PClassPointer(class PClass *restrict = nullptr); - - class PClass *ClassRestriction; - - bool isCompatible(PType *type); - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; - - void SetPointer(void *base, unsigned offset, TArray *special = NULL) override; - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -}; - -// Compound types ----------------------------------------------------------- - -class PEnum : public PInt -{ -public: - PEnum(FName name, PTypeBase *outer); - - PTypeBase *Outer; - FName EnumName; -}; - -class PArray : public PCompoundType -{ -public: - PArray(PType *etype, unsigned int ecount); - - PType *ElementType; - unsigned int ElementCount; - unsigned int ElementSize; - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; - - void SetDefaultValue(void *base, unsigned offset, TArray *special) override; - void SetPointer(void *base, unsigned offset, TArray *special) override; - void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) override; -}; - -class PStaticArray : public PArray -{ -public: - PStaticArray(PType *etype); - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -}; - -class PDynArray : public PCompoundType -{ -public: - PDynArray(PType *etype, PStruct *backing); - - PType *ElementType; - PStruct *BackingType; - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; - void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; - void InitializeValue(void *addr, const void *def) const override; - void DestroyValue(void *addr) const override; - void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) override; -}; - -class PMap : public PCompoundType -{ -public: - PMap(PType *keytype, PType *valtype); - - PType *KeyType; - PType *ValueType; - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -}; - -class PStruct : public PContainerType -{ -public: - PStruct(FName name, PTypeBase *outer, bool isnative = false); - - bool isNative; - // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it. - VMFunction *mConstructor = nullptr; - VMFunction *mDestructor = nullptr; - - virtual PField *AddField(FName name, PType *type, uint32_t flags=0); - virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; - void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; - void SetPointer(void *base, unsigned offset, TArray *specials) override; - void SetPointerArray(void *base, unsigned offset, TArray *special) override; -}; - -class PPrototype : public PCompoundType -{ -public: - PPrototype(const TArray &rettypes, const TArray &argtypes); - - TArray ArgumentTypes; - TArray ReturnTypes; - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -}; - - -// Meta-info for every class derived from DObject --------------------------- - -class PClassType : public PContainerType -{ -public: - PClass *Descriptor; - PClassType *ParentType; - - PClassType(PClass *cls = nullptr); - PField *AddField(FName name, PType *type, uint32_t flags = 0) override; - PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; -}; - - -inline PClass *PObjectPointer::PointedClass() const -{ - return static_cast(PointedType)->Descriptor; -} - -// Returns a type from the TypeTable. Will create one if it isn't present. -PMap *NewMap(PType *keytype, PType *valuetype); -PArray *NewArray(PType *type, unsigned int count); -PStaticArray *NewStaticArray(PType *type); -PDynArray *NewDynArray(PType *type); -PPointer *NewPointer(PType *type, bool isconst = false); -PPointer *NewPointer(PClass *type, bool isconst = false); -PClassPointer *NewClassPointer(PClass *restrict); -PEnum *NewEnum(FName name, PTypeBase *outer); -PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false); -PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); -PClassType *NewClassType(PClass *cls); - -// Built-in types ----------------------------------------------------------- - -extern PErrorType *TypeError; -extern PErrorType *TypeAuto; -extern PVoidType *TypeVoid; -extern PInt *TypeSInt8, *TypeUInt8; -extern PInt *TypeSInt16, *TypeUInt16; -extern PInt *TypeSInt32, *TypeUInt32; -extern PBool *TypeBool; -extern PFloat *TypeFloat32, *TypeFloat64; -extern PString *TypeString; -extern PName *TypeName; -extern PSound *TypeSound; -extern PColor *TypeColor; -extern PTextureID *TypeTextureID; -extern PSpriteID *TypeSpriteID; -extern PStruct *TypeVector2; -extern PStruct *TypeVector3; -extern PStruct *TypeColorStruct; -extern PStruct *TypeStringStruct; -extern PStatePointer *TypeState; -extern PPointer *TypeFont; -extern PStateLabel *TypeStateLabel; -extern PPointer *TypeNullPtr; -extern PPointer *TypeVoidPtr; - -inline FString &DObject::StringVar(FName field) -{ - return *(FString*)ScriptVar(field, TypeString); -} - -// Type tables -------------------------------------------------------------- - -struct FTypeTable -{ - enum { HASH_SIZE = 1021 }; - - PType *TypeHash[HASH_SIZE]; - - PType *FindType(FName type_name, intptr_t parm1, intptr_t parm2, size_t *bucketnum); - void AddType(PType *type, FName type_name, intptr_t parm1, intptr_t parm2, size_t bucket); - void AddType(PType *type, FName type_name); - void Clear(); - - static size_t Hash(FName p1, intptr_t p2, intptr_t p3); -}; - - -extern FTypeTable TypeTable; - diff --git a/src/scripting/vm/jit_load.cpp b/src/scripting/vm/jit_load.cpp deleted file mode 100644 index 0881cfd21cb..00000000000 --- a/src/scripting/vm/jit_load.cpp +++ /dev/null @@ -1,360 +0,0 @@ - -#include "jitintern.h" - -///////////////////////////////////////////////////////////////////////////// -// Load constants. - -void JitCompiler::EmitLI() -{ - cc.mov(regD[A], BCs); -} - -void JitCompiler::EmitLK() -{ - cc.mov(regD[A], konstd[BC]); -} - -void JitCompiler::EmitLKF() -{ - auto base = newTempIntPtr(); - cc.mov(base, asmjit::imm_ptr(konstf + BC)); - cc.movsd(regF[A], asmjit::x86::qword_ptr(base)); -} - -void JitCompiler::EmitLKS() -{ - auto call = CreateCall(&JitCompiler::CallAssignString); - call->setArg(0, regS[A]); - call->setArg(1, asmjit::imm_ptr(konsts + BC)); -} - -void JitCompiler::EmitLKP() -{ - cc.mov(regA[A], (int64_t)konsta[BC].v); -} - -void JitCompiler::EmitLK_R() -{ - auto base = newTempIntPtr(); - cc.mov(base, asmjit::imm_ptr(konstd + C)); - cc.mov(regD[A], asmjit::x86::ptr(base, regD[B], 2)); -} - -void JitCompiler::EmitLKF_R() -{ - auto base = newTempIntPtr(); - cc.mov(base, asmjit::imm_ptr(konstf + C)); - cc.movsd(regF[A], asmjit::x86::qword_ptr(base, regD[B], 3)); -} - -void JitCompiler::EmitLKS_R() -{ - auto base = newTempIntPtr(); - cc.mov(base, asmjit::imm_ptr(konsts + C)); - auto ptr = newTempIntPtr(); - if (cc.is64Bit()) - cc.lea(ptr, asmjit::x86::ptr(base, regD[B], 3)); - else - cc.lea(ptr, asmjit::x86::ptr(base, regD[B], 2)); - auto call = CreateCall(&JitCompiler::CallAssignString); - call->setArg(0, regS[A]); - call->setArg(1, ptr); -} - -void JitCompiler::EmitLKP_R() -{ - auto base = newTempIntPtr(); - cc.mov(base, asmjit::imm_ptr(konsta + C)); - if (cc.is64Bit()) - cc.mov(regA[A], asmjit::x86::ptr(base, regD[B], 3)); - else - cc.mov(regA[A], asmjit::x86::ptr(base, regD[B], 2)); -} - -void JitCompiler::EmitLFP() -{ - CheckVMFrame(); - cc.lea(regA[A], asmjit::x86::ptr(vmframe, offsetExtra)); -} - -void JitCompiler::EmitMETA() -{ - auto label = EmitThrowExceptionLabel(X_READ_NIL); - cc.test(regA[B], regA[B]); - cc.je(label); - - cc.mov(regA[A], asmjit::x86::qword_ptr(regA[B], myoffsetof(DObject, Class))); - cc.mov(regA[A], asmjit::x86::qword_ptr(regA[A], myoffsetof(PClass, Meta))); -} - -void JitCompiler::EmitCLSS() -{ - auto label = EmitThrowExceptionLabel(X_READ_NIL); - cc.test(regA[B], regA[B]); - cc.je(label); - cc.mov(regA[A], asmjit::x86::qword_ptr(regA[B], myoffsetof(DObject, Class))); -} - -///////////////////////////////////////////////////////////////////////////// -// Load from memory. rA = *(rB + rkC) - -void JitCompiler::EmitLB() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B], konstd[C])); -} - -void JitCompiler::EmitLB_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B], regD[C])); -} - -void JitCompiler::EmitLH() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movsx(regD[A], asmjit::x86::word_ptr(regA[B], konstd[C])); -} - -void JitCompiler::EmitLH_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movsx(regD[A], asmjit::x86::word_ptr(regA[B], regD[C])); -} - -void JitCompiler::EmitLW() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.mov(regD[A], asmjit::x86::dword_ptr(regA[B], konstd[C])); -} - -void JitCompiler::EmitLW_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.mov(regD[A], asmjit::x86::dword_ptr(regA[B], regD[C])); -} - -void JitCompiler::EmitLBU() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movzx(regD[A], asmjit::x86::byte_ptr(regA[B], konstd[C])); -} - -void JitCompiler::EmitLBU_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movzx(regD[A].r8Lo(), asmjit::x86::byte_ptr(regA[B], regD[C])); -} - -void JitCompiler::EmitLHU() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movzx(regD[A].r16(), asmjit::x86::word_ptr(regA[B], konstd[C])); -} - -void JitCompiler::EmitLHU_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movzx(regD[A].r16(), asmjit::x86::word_ptr(regA[B], regD[C])); -} - -void JitCompiler::EmitLSP() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.xorpd(regF[A], regF[A]); - cc.cvtss2sd(regF[A], asmjit::x86::dword_ptr(regA[B], konstd[C])); -} - -void JitCompiler::EmitLSP_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.xorpd(regF[A], regF[A]); - cc.cvtss2sd(regF[A], asmjit::x86::dword_ptr(regA[B], regD[C])); -} - -void JitCompiler::EmitLDP() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movsd(regF[A], asmjit::x86::qword_ptr(regA[B], konstd[C])); -} - -void JitCompiler::EmitLDP_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movsd(regF[A], asmjit::x86::qword_ptr(regA[B], regD[C])); -} - -void JitCompiler::EmitLS() -{ - EmitNullPointerThrow(B, X_READ_NIL); - auto ptr = newTempIntPtr(); - cc.lea(ptr, asmjit::x86::ptr(regA[B], konstd[C])); - auto call = CreateCall(&JitCompiler::CallAssignString); - call->setArg(0, regS[A]); - call->setArg(1, ptr); -} - -void JitCompiler::EmitLS_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - auto ptr = newTempIntPtr(); - cc.lea(ptr, asmjit::x86::ptr(regA[B], regD[C])); - auto call = CreateCall(&JitCompiler::CallAssignString); - call->setArg(0, regS[A]); - call->setArg(1, ptr); -} - -#if 1 // Inline read barrier impl - -void JitCompiler::EmitReadBarrier() -{ - auto isnull = cc.newLabel(); - cc.test(regA[A], regA[A]); - cc.je(isnull); - - auto mask = newTempIntPtr(); - cc.mov(mask.r32(), asmjit::x86::dword_ptr(regA[A], myoffsetof(DObject, ObjectFlags))); - cc.shl(mask, 63 - 5); // put OF_EuthanizeMe (1 << 5) in the highest bit - cc.sar(mask, 63); // sign extend so all bits are set if OF_EuthanizeMe was set - cc.not_(mask); - cc.and_(regA[A], mask); - - cc.bind(isnull); -} - -void JitCompiler::EmitLO() -{ - EmitNullPointerThrow(B, X_READ_NIL); - - cc.mov(regA[A], asmjit::x86::ptr(regA[B], konstd[C])); - EmitReadBarrier(); -} - -void JitCompiler::EmitLO_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - - cc.mov(regA[A], asmjit::x86::ptr(regA[B], regD[C])); - EmitReadBarrier(); -} - -#else - -static DObject *ReadBarrier(DObject *p) -{ - return GC::ReadBarrier(p); -} - -void JitCompiler::EmitLO() -{ - EmitNullPointerThrow(B, X_READ_NIL); - - auto ptr = newTempIntPtr(); - cc.mov(ptr, asmjit::x86::ptr(regA[B], konstd[C])); - - auto result = newResultIntPtr(); - auto call = CreateCall(ReadBarrier); - call->setRet(0, result); - call->setArg(0, ptr); - cc.mov(regA[A], result); -} - -void JitCompiler::EmitLO_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - - auto ptr = newTempIntPtr(); - cc.mov(ptr, asmjit::x86::ptr(regA[B], regD[C])); - - auto result = newResultIntPtr(); - auto call = CreateCall(ReadBarrier); - call->setRet(0, result); - call->setArg(0, ptr); - cc.mov(regA[A], result); -} - -#endif - -void JitCompiler::EmitLP() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.mov(regA[A], asmjit::x86::ptr(regA[B], konstd[C])); -} - -void JitCompiler::EmitLP_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.mov(regA[A], asmjit::x86::ptr(regA[B], regD[C])); -} - -void JitCompiler::EmitLV2() -{ - EmitNullPointerThrow(B, X_READ_NIL); - auto tmp = newTempIntPtr(); - cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], konstd[C])); - cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); - cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); -} - -void JitCompiler::EmitLV2_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - auto tmp = newTempIntPtr(); - cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], regD[C])); - cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); - cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); -} - -void JitCompiler::EmitLV3() -{ - EmitNullPointerThrow(B, X_READ_NIL); - auto tmp = newTempIntPtr(); - cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], konstd[C])); - cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); - cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); - cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); -} - -void JitCompiler::EmitLV3_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - auto tmp = newTempIntPtr(); - cc.lea(tmp, asmjit::x86::qword_ptr(regA[B], regD[C])); - cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp)); - cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8)); - cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); -} - -static void SetString(FString *to, char **from) -{ - *to = *from; -} - -void JitCompiler::EmitLCS() -{ - EmitNullPointerThrow(B, X_READ_NIL); - auto ptr = newTempIntPtr(); - cc.lea(ptr, asmjit::x86::ptr(regA[B], konstd[C])); - auto call = CreateCall(SetString); - call->setArg(0, regS[A]); - call->setArg(1, ptr); -} - -void JitCompiler::EmitLCS_R() -{ - EmitNullPointerThrow(B, X_READ_NIL); - auto ptr = newTempIntPtr(); - cc.lea(ptr, asmjit::x86::ptr(regA[B], regD[C])); - auto call = CreateCall(SetString); - call->setArg(0, regS[A]); - call->setArg(1, ptr); -} - -void JitCompiler::EmitLBIT() -{ - EmitNullPointerThrow(B, X_READ_NIL); - cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B])); - cc.and_(regD[A], C); - cc.cmp(regD[A], 0); - cc.setne(regD[A]); -} diff --git a/src/scripting/vm/jit_store.cpp b/src/scripting/vm/jit_store.cpp deleted file mode 100644 index 6dc1a45a923..00000000000 --- a/src/scripting/vm/jit_store.cpp +++ /dev/null @@ -1,176 +0,0 @@ - -#include "jitintern.h" - -void JitCompiler::EmitSB() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::byte_ptr(regA[A], konstd[C]), regD[B].r8Lo()); -} - -void JitCompiler::EmitSB_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::byte_ptr(regA[A], regD[C]), regD[B].r8Lo()); -} - -void JitCompiler::EmitSH() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::word_ptr(regA[A], konstd[C]), regD[B].r16()); -} - -void JitCompiler::EmitSH_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::word_ptr(regA[A], regD[C]), regD[B].r16()); -} - -void JitCompiler::EmitSW() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::dword_ptr(regA[A], konstd[C]), regD[B]); -} - -void JitCompiler::EmitSW_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::dword_ptr(regA[A], regD[C]), regD[B]); -} - -void JitCompiler::EmitSSP() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto tmp = newTempXmmSd(); - cc.xorpd(tmp, tmp); - cc.cvtsd2ss(tmp, regF[B]); - cc.movss(asmjit::x86::dword_ptr(regA[A], konstd[C]), tmp); -} - -void JitCompiler::EmitSSP_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto tmp = newTempXmmSd(); - cc.xorpd(tmp, tmp); - cc.cvtsd2ss(tmp, regF[B]); - cc.movss(asmjit::x86::dword_ptr(regA[A], regD[C]), tmp); -} - -void JitCompiler::EmitSDP() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.movsd(asmjit::x86::qword_ptr(regA[A], konstd[C]), regF[B]); -} - -void JitCompiler::EmitSDP_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.movsd(asmjit::x86::qword_ptr(regA[A], regD[C]), regF[B]); -} - -void JitCompiler::EmitSS() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto ptr = newTempIntPtr(); - cc.lea(ptr, asmjit::x86::ptr(regA[A], konstd[C])); - auto call = CreateCall(&JitCompiler::CallAssignString); - call->setArg(0, ptr); - call->setArg(1, regS[B]); -} - -void JitCompiler::EmitSS_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto ptr = newTempIntPtr(); - cc.lea(ptr, asmjit::x86::ptr(regA[A], regD[C])); - auto call = CreateCall(&JitCompiler::CallAssignString); - call->setArg(0, ptr); - call->setArg(1, regS[B]); -} - -void JitCompiler::EmitSO() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::ptr(regA[A], konstd[C]), regA[B]); - - typedef void(*FuncPtr)(DObject*); - auto call = CreateCall(static_cast(GC::WriteBarrier)); - call->setArg(0, regA[B]); -} - -void JitCompiler::EmitSO_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::ptr(regA[A], regD[C]), regA[B]); - - typedef void(*FuncPtr)(DObject*); - auto call = CreateCall(static_cast(GC::WriteBarrier)); - call->setArg(0, regA[B]); -} - -void JitCompiler::EmitSP() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::ptr(regA[A], konstd[C]), regA[B]); -} - -void JitCompiler::EmitSP_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - cc.mov(asmjit::x86::ptr(regA[A], regD[C]), regA[B]); -} - -void JitCompiler::EmitSV2() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto tmp = newTempIntPtr(); - cc.mov(tmp, regA[A]); - cc.add(tmp, konstd[C]); - cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); - cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); -} - -void JitCompiler::EmitSV2_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto tmp = newTempIntPtr(); - cc.mov(tmp, regA[A]); - cc.add(tmp, regD[C]); - cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); - cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); -} - -void JitCompiler::EmitSV3() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto tmp = newTempIntPtr(); - cc.mov(tmp, regA[A]); - cc.add(tmp, konstd[C]); - cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); - cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); - cc.movsd(asmjit::x86::qword_ptr(tmp, 16), regF[B + 2]); -} - -void JitCompiler::EmitSV3_R() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto tmp = newTempIntPtr(); - cc.mov(tmp, regA[A]); - cc.add(tmp, regD[C]); - cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]); - cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]); - cc.movsd(asmjit::x86::qword_ptr(tmp, 16), regF[B + 2]); -} - -void JitCompiler::EmitSBIT() -{ - EmitNullPointerThrow(A, X_WRITE_NIL); - auto tmp1 = newTempInt32(); - auto tmp2 = newTempInt32(); - cc.mov(tmp1, asmjit::x86::byte_ptr(regA[A])); - cc.mov(tmp2, tmp1); - cc.or_(tmp1, (int)C); - cc.and_(tmp2, ~(int)C); - cc.test(regD[B], regD[B]); - cc.cmove(tmp1, tmp2); - cc.mov(asmjit::x86::byte_ptr(regA[A]), tmp1); -} diff --git a/src/scripting/vmiterators.cpp b/src/scripting/vmiterators.cpp index e5f0d78e807..32d1ca1f876 100644 --- a/src/scripting/vmiterators.cpp +++ b/src/scripting/vmiterators.cpp @@ -123,7 +123,7 @@ IMPLEMENT_CLASS(DBlockLinesIterator, true, false); static DBlockLinesIterator *CreateBLI(AActor *origin, double radius) { - return Create(origin, radius); + return Create(PARAM_NULLCHECK(origin, origin), radius); } DEFINE_ACTION_FUNCTION_NATIVE(DBlockLinesIterator, Create, CreateBLI) @@ -198,7 +198,7 @@ IMPLEMENT_CLASS(DBlockThingsIterator, true, false); static DBlockThingsIterator *CreateBTI(AActor *origin, double radius, bool ignore) { - return Create(origin, radius, ignore); + return Create(PARAM_NULLCHECK(origin, origin), radius, ignore); } diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 719efae1639..4cc04884314 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -32,6 +32,7 @@ #include "vm.h" #include "r_defs.h" #include "g_levellocals.h" +#include "gamedata/g_mapinfo.h" #include "s_sound.h" #include "p_local.h" #include "v_font.h" @@ -49,333 +50,58 @@ #include "am_map.h" #include "v_video.h" #include "gi.h" +#include "utf8.h" #include "fontinternals.h" #include "intermission/intermission.h" +#include "menu.h" +#include "c_cvars.h" +#include "c_bind.h" +#include "c_dispatch.h" +#include "s_music.h" +#include "texturemanager.h" +#include "v_draw.h" DVector2 AM_GetPosition(); int Net_GetLatency(int *ld, int *ad); void PrintPickupMessage(bool localview, const FString &str); -//===================================================================================== -// -// FString exports -// -//===================================================================================== - -static void LocalizeString(const FString &label, bool prefixed, FString *result) -{ - if (!prefixed) *result = GStrings(label); - else if (label[0] != '$') *result = label; - else *result = GStrings(&label[1]); -} +void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov); -DEFINE_ACTION_FUNCTION_NATIVE(FStringTable, Localize, LocalizeString) +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCameraToTexture, SetCameraToTexture) { PARAM_PROLOGUE; - PARAM_STRING(label); - PARAM_BOOL(prefixed); - FString result; - LocalizeString(label, prefixed, &result); - ACTION_RETURN_STRING(result); -} - -static void StringReplace(FString *self, const FString &s1, const FString &s2) -{ - self->Substitute(s1, s2); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Replace, StringReplace) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_STRING(s1); - PARAM_STRING(s2); - self->Substitute(s1, s2); - return 0; -} - -static void StringMid(FString *self, unsigned pos, unsigned len, FString *result) -{ - *result = self->Mid(pos, len); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Mid, StringMid) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_UINT(pos); - PARAM_UINT(len); - FString s = self->Mid(pos, len); - ACTION_RETURN_STRING(s); -} - -static void StringLeft(FString *self, unsigned len, FString *result) -{ - *result = self->Left(len); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Left, StringLeft) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_UINT(len); - FString s = self->Left(len); - ACTION_RETURN_STRING(s); -} - -static void StringTruncate(FString *self, unsigned len) -{ - self->Truncate(len); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Truncate, StringTruncate) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_UINT(len); - self->Truncate(len); - return 0; -} - -static void StringRemove(FString *self, unsigned index, unsigned remlen) -{ - self->Remove(index, remlen); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Remove, StringRemove) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_UINT(index); - PARAM_UINT(remlen); - self->Remove(index, remlen); - return 0; -} - -static void StringCharAt(FString *self, int pos, FString *result) -{ - if ((unsigned)pos >= self->Len()) *result = ""; - else *result = FString((*self)[pos]); -} -// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CharAt, StringCharAt) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(pos); - FString result; - StringCharAt(self, pos, &result); - ACTION_RETURN_STRING(result); -} - -static int StringCharCodeAt(FString *self, int pos) -{ - if ((unsigned)pos >= self->Len()) return 0; - else return (*self)[pos]; -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CharCodeAt, StringCharCodeAt) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(pos); - ACTION_RETURN_INT(StringCharCodeAt(self, pos)); -} - -static int StringByteAt(FString *self, int pos) -{ - if ((unsigned)pos >= self->Len()) return 0; - else return (uint8_t)((*self)[pos]); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ByteAt, StringByteAt) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(pos); - ACTION_RETURN_INT(StringByteAt(self, pos)); -} - -static void StringFilter(FString *self, FString *result) -{ - *result = strbin1(*self); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Filter, StringFilter) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_STRING(strbin1(*self)); -} - -static int StringIndexOf(FString *self, const FString &substr, int startIndex) -{ - return self->IndexOf(substr, startIndex); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, IndexOf, StringIndexOf) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_STRING(substr); - PARAM_INT(startIndex); - ACTION_RETURN_INT(self->IndexOf(substr, startIndex)); -} - -static int StringLastIndexOf(FString *self, const FString &substr, int endIndex) -{ - return self->LastIndexOfBroken(substr, endIndex); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, LastIndexOf, StringLastIndexOf) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_STRING(substr); - PARAM_INT(endIndex); - ACTION_RETURN_INT(self->LastIndexOfBroken(substr, endIndex)); -} - -static int StringRightIndexOf(FString *self, const FString &substr, int endIndex) -{ - return self->LastIndexOf(substr, endIndex); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, RightIndexOf, StringRightIndexOf) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_STRING(substr); - PARAM_INT(endIndex); - ACTION_RETURN_INT(self->LastIndexOf(substr, endIndex)); -} - -static void StringToUpper(FString *self) -{ - self->ToUpper(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToUpper, StringToUpper) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - self->ToUpper(); - return 0; -} - -static void StringToLower(FString *self) -{ - self->ToLower(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToLower, StringToLower) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - self->ToLower(); + PARAM_OBJECT(viewpoint, AActor); + PARAM_STRING(texturename); // [ZZ] there is no point in having this as FTextureID because it's easier to refer to a cameratexture by name and it isn't executed too often to cache it. + PARAM_FLOAT(fov); + SetCameraToTexture(viewpoint, texturename, fov); return 0; } -static void StringMakeUpper(FString *self, FString *out) -{ - *out = self->MakeUpper(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, MakeUpper, StringMakeUpper) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_STRING(self->MakeUpper()); -} - -static void StringMakeLower(FString *self, FString *out) -{ - *out = self->MakeLower(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, MakeLower, StringMakeLower) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_STRING(self->MakeLower()); -} - -static int StringCharUpper(int ch) -{ - return ch >= 0 && ch < 65536 ? upperforlower[ch] : ch; -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CharUpper, StringCharUpper) -{ - PARAM_PROLOGUE; - PARAM_INT(ch); - ACTION_RETURN_INT(StringCharUpper(ch)); -} - -static int StringCharLower(int ch) +static void SetCameraTextureAspectRatio(const FString &texturename, double aspectScale, bool useTextureRatio) { - return ch >= 0 && ch < 65536 ? lowerforupper[ch] : ch; + FTextureID textureid = TexMan.CheckForTexture(texturename.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + if (textureid.isValid()) + { + // Only proceed if the texture actually has a canvas. + auto tex = TexMan.GetGameTexture(textureid); + if (tex && tex->isHardwareCanvas()) + { + static_cast(tex->GetTexture())->SetAspectRatio(aspectScale, useTextureRatio); + } + } } -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CharLower, StringCharLower) +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCameraTextureAspectRatio, SetCameraTextureAspectRatio) { PARAM_PROLOGUE; - PARAM_INT(ch); - ACTION_RETURN_INT(StringCharLower(ch)); -} - - -static int StringToInt(FString *self, int base) -{ - return (int)self->ToLong(base); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToInt, StringToInt) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(base); - ACTION_RETURN_INT((int)self->ToLong(base)); -} - -static double StringToDbl(FString *self) -{ - return self->ToDouble(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToDouble, StringToDbl) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_FLOAT(self->ToDouble()); -} - -static void StringSplit(FString *self, TArray *tokens, const FString &delimiter, int keepEmpty) -{ - self->Split(*tokens, delimiter, static_cast(keepEmpty)); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Split, StringSplit) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_POINTER(tokens, TArray); - PARAM_STRING(delimiter); - PARAM_INT(keepEmpty); - StringSplit(self, tokens, delimiter, keepEmpty); + PARAM_STRING(texturename); + PARAM_FLOAT(aspect); + PARAM_BOOL(useTextureRatio); + SetCameraTextureAspectRatio(texturename, aspect, useTextureRatio); return 0; } -static int StringCodePointCount(FString *self) -{ - return (int)self->CharacterCount(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, CodePointCount, StringCodePointCount) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_INT(StringCodePointCount(self)); -} - -static int StringNextCodePoint(FString *self, int inposition, int *position) -{ - int codepoint = self->GetNextCharacter(inposition); - if (position) *position = inposition; - return codepoint; -} - -DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, GetNextCodePoint, StringNextCodePoint) -{ - PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(pos); - if (numret > 0) ret[0].SetInt(self->GetNextCharacter(pos)); - if (numret > 1) ret[1].SetInt(pos); - return numret; -} - - //===================================================================================== // // sector_t exports @@ -744,6 +470,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, GetTerrain, GetTerrain) ACTION_RETURN_INT(GetTerrain(self, pos)); } +DEFINE_ACTION_FUNCTION_NATIVE(_Sector, GetFloorTerrain, GetFloorTerrain_S) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(pos); + ACTION_RETURN_POINTER(GetFloorTerrain_S(self, pos)); +} DEFINE_ACTION_FUNCTION_NATIVE(_Sector, CheckPortalPlane, CheckPortalPlane) { @@ -830,7 +562,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) PARAM_SELF_STRUCT_PROLOGUE(sector_t); PARAM_INT(pos); PARAM_FLOAT(o); - self->SetXOffset(pos, o); + self->SetYOffset(pos, o); return 0; } @@ -915,7 +647,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) static void SetAngle(sector_t *self, int pos, double o) { - self->SetAngle(pos, o); + self->SetAngle(pos, DAngle::fromDeg(o)); } DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetAngle, SetAngle) @@ -929,7 +661,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) static double GetAngle(sector_t *self, int pos, bool addbase) { - return self->GetAngle(pos, addbase).Degrees; + return self->GetAngle(pos, addbase).Degrees(); } DEFINE_ACTION_FUNCTION_NATIVE(_Sector, GetAngle, GetAngle) @@ -937,12 +669,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) PARAM_SELF_STRUCT_PROLOGUE(sector_t); PARAM_INT(pos); PARAM_BOOL(addbase); - ACTION_RETURN_FLOAT(self->GetAngle(pos, addbase).Degrees); + ACTION_RETURN_FLOAT(self->GetAngle(pos, addbase).Degrees()); } static void SetBase(sector_t *self, int pos, double o, double a) { - self->SetBase(pos, o, a); + self->SetBase(pos, o, DAngle::fromDeg(a)); } DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetBase, SetBase) @@ -1294,7 +1026,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) static void SetEnvironment(sector_t *self, const FString &env) { - self->Level->Zones[self->ZoneNumber].Environment = S_FindEnvironment(env); + self->Level->Zones[self->ZoneNumber].Environment = S_FindEnvironment(env.GetChars()); } DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetEnvironment, SetEnvironment) @@ -1407,6 +1139,29 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) ACTION_RETURN_INT(self->e->XFloor.attached.Size()); } + static int CountSectorTags(const sector_t *self) + { + return level.tagManager.CountSectorTags(self); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Sector, CountTags, CountSectorTags) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + ACTION_RETURN_INT(level.tagManager.CountSectorTags(self)); + } + + static int GetSectorTag(const sector_t *self, int index) + { + return level.tagManager.GetSectorTag(self, index); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Sector, GetTag, GetSectorTag) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(index); + ACTION_RETURN_INT(level.tagManager.GetSectorTag(self, index)); + } + static int Get3DFloorTexture(F3DFloor *self, int pos) { if ( pos ) @@ -1467,12 +1222,36 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) return self->getPortalAlignment(); } + DEFINE_ACTION_FUNCTION(_Line, getPortalFlags) + { + PARAM_SELF_STRUCT_PROLOGUE(line_t); + ACTION_RETURN_INT(self->getPortalFlags()); + } + DEFINE_ACTION_FUNCTION_NATIVE(_Line, getPortalAlignment, getPortalAlignment) { PARAM_SELF_STRUCT_PROLOGUE(line_t); ACTION_RETURN_INT(self->getPortalAlignment()); } + DEFINE_ACTION_FUNCTION(_Line, getPortalType) + { + PARAM_SELF_STRUCT_PROLOGUE(line_t); + ACTION_RETURN_INT(self->getPortalType()); + } + + DEFINE_ACTION_FUNCTION(_Line, getPortalDisplacement) + { + PARAM_SELF_STRUCT_PROLOGUE(line_t); + ACTION_RETURN_VEC2(self->getPortalDisplacement()); + } + + DEFINE_ACTION_FUNCTION(_Line, getPortalAngleDiff) + { + PARAM_SELF_STRUCT_PROLOGUE(line_t); + ACTION_RETURN_FLOAT(self->getPortalAngleDiff().Degrees()); + } + static int LineIndex(line_t *self) { return self->Index(); @@ -1484,6 +1263,29 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) ACTION_RETURN_INT(LineIndex(self)); } + static int CountLineIDs(const line_t *self) + { + return level.tagManager.CountLineIDs(self); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Line, CountIDs, CountLineIDs) + { + PARAM_SELF_STRUCT_PROLOGUE(line_t); + ACTION_RETURN_INT(level.tagManager.CountLineIDs(self)); + } + + static int GetLineID(const line_t *self, int index) + { + return level.tagManager.GetLineID(self, index); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Line, GetID, GetLineID) + { + PARAM_SELF_STRUCT_PROLOGUE(line_t); + PARAM_INT(index); + ACTION_RETURN_INT(level.tagManager.GetLineID(self, index)); + } + //=========================================================================== // // side_t exports @@ -1698,11 +1500,38 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) ACTION_RETURN_POINTER(self->V2()); } - static void SetSideSpecialColor(side_t *self, int tier, int position, int color) + static int GetTextureFlags(side_t* self, int tier) + { + return self->GetTextureFlags(tier); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Side, GetTextureFlags, GetTextureFlags) + { + PARAM_SELF_STRUCT_PROLOGUE(side_t); + PARAM_INT(tier); + ACTION_RETURN_INT(self->GetTextureFlags(tier)); +} + + static void ChangeTextureFlags(side_t* self, int tier, int And, int Or) + { + self->ChangeTextureFlags(tier, And, Or); + } + + DEFINE_ACTION_FUNCTION_NATIVE(_Side, ChangeTextureFlags, ChangeTextureFlags) + { + PARAM_SELF_STRUCT_PROLOGUE(side_t); + PARAM_INT(tier); + PARAM_INT(a); + PARAM_INT(o); + ChangeTextureFlags(self, tier, a, o); + return 0; + } + + static void SetSideSpecialColor(side_t *self, int tier, int position, int color, int useown) { if (tier >= 0 && tier < 3 && position >= 0 && position < 2) { - self->SetSpecialColor(tier, position, color); + self->SetSpecialColor(tier, position, color, useown); } } @@ -1712,7 +1541,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) PARAM_INT(tier); PARAM_INT(position); PARAM_COLOR(color); - SetSideSpecialColor(self, tier, position, color); + PARAM_BOOL(useown) + SetSideSpecialColor(self, tier, position, color, useown); return 0; } @@ -1885,7 +1715,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); PARAM_NAME(seq); PARAM_INT(state); - F_StartIntermission(seq, (uint8_t)state); + G_StartSlideshow(self, seq); return 0; } @@ -1893,7 +1723,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) // This is needed to convert the strings to char pointers. static void ReplaceTextures(FLevelLocals *self, const FString &from, const FString &to, int flags) { - self->ReplaceTextures(from, to, flags); + self->ReplaceTextures(from.GetChars(), to.GetChars(), flags); } DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, ReplaceTextures, ReplaceTextures) @@ -1902,23 +1732,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, ReplaceTextures, ReplaceTextures) PARAM_STRING(from); PARAM_STRING(to); PARAM_INT(flags); - self->ReplaceTextures(from, to, flags); - return 0; -} - -void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov); - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCameraToTexture, SetCameraToTexture) -{ - PARAM_PROLOGUE; - PARAM_OBJECT(viewpoint, AActor); - PARAM_STRING(texturename); // [ZZ] there is no point in having this as FTextureID because it's easier to refer to a cameratexture by name and it isn't executed too often to cache it. - PARAM_FLOAT(fov); - SetCameraToTexture(viewpoint, texturename, fov); + self->ReplaceTextures(from.GetChars(), to.GetChars(), flags); return 0; } - //===================================================================================== // // secplane_t exports @@ -2051,150 +1868,16 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Secplane, PointToDist, PointToDist) //===================================================================================== // -// FFont exports +// WeaponSlots exports // //===================================================================================== -static FFont *GetFont(int name) -{ - return V_GetFont(FName(ENamedName(name)).GetChars()); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetFont, GetFont) +static int LocateWeapon(FWeaponSlots *self, PClassActor *weap, int *pslot, int *pindex) { - PARAM_PROLOGUE; - PARAM_INT(name); - ACTION_RETURN_POINTER(GetFont(name)); + return self->LocateWeapon(weap, pslot, pindex); } -static FFont *FindFont(int name) -{ - return FFont::FindFont(FName(ENamedName(name))); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, FindFont, FindFont) -{ - PARAM_PROLOGUE; - PARAM_NAME(name); - ACTION_RETURN_POINTER(FFont::FindFont(name)); -} - -static int GetCharWidth(FFont *font, int code) -{ - return font->GetCharWidth(code); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetCharWidth, GetCharWidth) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - PARAM_INT(code); - ACTION_RETURN_INT(self->GetCharWidth(code)); -} - -static int GetHeight(FFont *font) -{ - return font->GetHeight(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetHeight, GetHeight) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - ACTION_RETURN_INT(self->GetHeight()); -} - -static int GetDisplacement(FFont* font) -{ - return font->GetDisplacement(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetDisplacement, GetDisplacement) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - ACTION_RETURN_INT(self->GetDisplacement()); -} - -double GetBottomAlignOffset(FFont *font, int c); -DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetBottomAlignOffset, GetBottomAlignOffset) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - PARAM_INT(code); - ACTION_RETURN_FLOAT(GetBottomAlignOffset(self, code)); -} - -static int StringWidth(FFont *font, const FString &str) -{ - const char *txt = str[0] == '$' ? GStrings(&str[1]) : str.GetChars(); - return font->StringWidth(txt); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, StringWidth, StringWidth) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - PARAM_STRING(str); - ACTION_RETURN_INT(StringWidth(self, str)); -} - -static int GetMaxAscender(FFont* font, const FString& str) -{ - const char* txt = str[0] == '$' ? GStrings(&str[1]) : str.GetChars(); - return font->GetMaxAscender(txt); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetMaxAscender, GetMaxAscender) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - PARAM_STRING(str); - ACTION_RETURN_INT(GetMaxAscender(self, str)); -} - -static int CanPrint(FFont *font, const FString &str) -{ - const char *txt = str[0] == '$' ? GStrings(&str[1]) : str.GetChars(); - return font->CanPrint(txt); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, CanPrint, CanPrint) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - PARAM_STRING(str); - ACTION_RETURN_INT(CanPrint(self, str)); -} - -static int FindFontColor(int name) -{ - return V_FindFontColor(ENamedName(name)); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, FindFontColor, FindFontColor) -{ - PARAM_PROLOGUE; - PARAM_NAME(code); - ACTION_RETURN_INT((int)V_FindFontColor(code)); -} - -static void GetCursor(FFont *font, FString *result) -{ - *result = font->GetCursor(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetCursor, GetCursor) -{ - PARAM_SELF_STRUCT_PROLOGUE(FFont); - ACTION_RETURN_STRING(FString(self->GetCursor())); -} - -//===================================================================================== -// -// WeaponSlots exports -// -//===================================================================================== - -static int LocateWeapon(FWeaponSlots *self, PClassActor *weap, int *pslot, int *pindex) -{ - return self->LocateWeapon(weap, pslot, pindex); -} - -DEFINE_ACTION_FUNCTION_NATIVE(FWeaponSlots, LocateWeapon, LocateWeapon) +DEFINE_ACTION_FUNCTION_NATIVE(FWeaponSlots, LocateWeapon, LocateWeapon) { PARAM_SELF_STRUCT_PROLOGUE(FWeaponSlots); PARAM_CLASS(weap, AActor); @@ -2203,7 +1886,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FWeaponSlots, LocateWeapon, LocateWeapon) if (numret >= 1) ret[0].SetInt(retv); if (numret >= 2) ret[1].SetInt(slot); if (numret >= 3) ret[2].SetInt(index); - return MIN(numret, 3); + return min(numret, 3); } static PClassActor *GetWeapon(FWeaponSlots *self, int slot, int index) @@ -2322,66 +2005,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(DSpotState, GetRandomSpot, GetRandomSpot) // //===================================================================================== -static void SBar_SetSize(DBaseStatusBar *self, int rt, int vw, int vh, int hvw, int hvh) -{ - self->SetSize(rt, vw, vh, hvw, hvh); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, SetSize, SBar_SetSize) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_INT(rt); - PARAM_INT(vw); - PARAM_INT(vh); - PARAM_INT(hvw); - PARAM_INT(hvh); - self->SetSize(rt, vw, vh, hvw, hvh); - return 0; -} - -static void SBar_GetHUDScale(DBaseStatusBar *self, DVector2 *result) -{ - *result = self->GetHUDScale(); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetHUDScale, SBar_GetHUDScale) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - ACTION_RETURN_VEC2(self->GetHUDScale()); -} - -static void BeginStatusBar(DBaseStatusBar *self, bool fs, int w, int h, int r) -{ - self->BeginStatusBar(w, h, r, fs); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, BeginStatusBar, BeginStatusBar) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_BOOL(fs); - PARAM_INT(w); - PARAM_INT(h); - PARAM_INT(r); - self->BeginStatusBar(w, h, r, fs); - return 0; -} - -static void BeginHUD(DBaseStatusBar *self, double a, bool fs, int w, int h) -{ - self->BeginHUD(w, h, a, fs); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, BeginHUD, BeginHUD) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_FLOAT(a); - PARAM_BOOL(fs); - PARAM_INT(w); - PARAM_INT(h); - self->BeginHUD(w, h, a, fs); - return 0; -} - static void UpdateScreenGeometry(DBaseStatusBar *) { setsizeneeded = true; @@ -2474,7 +2097,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, Draw, SBar_Draw) static void SetMugshotState(DBaseStatusBar *self, const FString &statename, bool wait, bool reset) { - self->mugshot.SetState(statename, wait, reset); + self->mugshot.SetState(statename.GetChars(), wait, reset); } DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, SetMugshotState, SetMugshotState) @@ -2483,7 +2106,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, SetMugshotState, SetMugshotState) PARAM_STRING(statename); PARAM_BOOL(wait); PARAM_BOOL(reset); - self->mugshot.SetState(statename, wait, reset); + self->mugshot.SetState(statename.GetChars(), wait, reset); return 0; } @@ -2499,30 +2122,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, ScreenSizeChanged, SBar_ScreenSize return 0; } -static double StatusbarToRealCoords(DBaseStatusBar *self, double x, double y, double w, double h, double *py, double *pw, double *ph) -{ - self->StatusbarToRealCoords(x, y, w, h); - *py = y; - *pw = w; - *ph = h; - return x; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, StatusbarToRealCoords, StatusbarToRealCoords) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_FLOAT(w); - PARAM_FLOAT(h); - self->StatusbarToRealCoords(x, y, w, h); - if (numret > 0) ret[0].SetFloat(x); - if (numret > 1) ret[1].SetFloat(y); - if (numret > 2) ret[2].SetFloat(w); - if (numret > 3) ret[3].SetFloat(h); - return MIN(4, numret); -} - static int GetTopOfStatusbar(DBaseStatusBar *self) { return self->GetTopOfStatusbar(); @@ -2534,131 +2133,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetTopOfStatusbar, GetTopOfStatusb ACTION_RETURN_INT(self->GetTopOfStatusbar()); } -void SBar_DrawTexture(DBaseStatusBar *self, int texid, double x, double y, int flags, double alpha, double w, double h, double scaleX, double scaleY) -{ - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - self->DrawGraphic(FSetTextureID(texid), x, y, flags, alpha, w, h, scaleX, scaleY); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, DrawTexture, SBar_DrawTexture) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_INT(texid); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_INT(flags); - PARAM_FLOAT(alpha); - PARAM_FLOAT(w); - PARAM_FLOAT(h); - PARAM_FLOAT(scaleX); - PARAM_FLOAT(scaleY); - SBar_DrawTexture(self, texid, x, y, flags, alpha, w, h, scaleX, scaleY); - return 0; -} - -void SBar_DrawImage(DBaseStatusBar *self, const FString &texid, double x, double y, int flags, double alpha, double w, double h, double scaleX, double scaleY) -{ - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - self->DrawGraphic(TexMan.CheckForTexture(texid, ETextureType::Any), x, y, flags, alpha, w, h, scaleX, scaleY); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, DrawImage, SBar_DrawImage) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_STRING(texid); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_INT(flags); - PARAM_FLOAT(alpha); - PARAM_FLOAT(w); - PARAM_FLOAT(h); - PARAM_FLOAT(scaleX); - PARAM_FLOAT(scaleY); - SBar_DrawImage(self, texid, x, y, flags, alpha, w, h, scaleX, scaleY); - return 0; -} - -void SBar_DrawString(DBaseStatusBar *self, DHUDFont *font, const FString &string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY); - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, DrawString, SBar_DrawString) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_POINTER_NOT_NULL(font, DHUDFont); - PARAM_STRING(string); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_INT(flags); - PARAM_INT(trans); - PARAM_FLOAT(alpha); - PARAM_INT(wrapwidth); - PARAM_INT(linespacing); - PARAM_FLOAT(scaleX); - PARAM_FLOAT(scaleY); - SBar_DrawString(self, font, string, x, y, flags, trans, alpha, wrapwidth, linespacing, scaleX, scaleY); - return 0; -} - -static double SBar_TransformRect(DBaseStatusBar *self, double x, double y, double w, double h, int flags, double *py, double *pw, double *ph) -{ - self->TransformRect(x, y, w, h, flags); - *py = y; - *pw = w; - *ph = h; - return x; -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, TransformRect, SBar_TransformRect) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_FLOAT(w); - PARAM_FLOAT(h); - PARAM_INT(flags); - self->TransformRect(x, y, w, h, flags); - if (numret > 0) ret[0].SetFloat(x); - if (numret > 1) ret[1].SetFloat(y); - if (numret > 2) ret[2].SetFloat(w); - if (numret > 3) ret[3].SetFloat(h); - return MIN(4, numret); -} - -static void SBar_Fill(DBaseStatusBar *self, int color, double x, double y, double w, double h, int flags) -{ - if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - self->Fill(color, x, y, w, h, flags); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, Fill, SBar_Fill) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_COLOR(color); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_FLOAT(w); - PARAM_FLOAT(h); - PARAM_INT(flags); - SBar_Fill(self, color, x, y, w, h, flags); - return 0; -} - -static void SBar_SetClipRect(DBaseStatusBar *self, double x, double y, double w, double h, int flags) -{ - self->SetClipRect(x, y, w, h, flags); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, SetClipRect, SBar_SetClipRect) -{ - PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - PARAM_FLOAT(w); - PARAM_FLOAT(h); - PARAM_INT(flags); - self->SetClipRect(x, y, w, h, flags); - return 0; -} - static void GetGlobalACSString(int index, FString *result) { *result = primaryLevel->Behaviors.LookupString(ACS_GlobalVars[index]); @@ -2713,21 +2187,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSArrayValue, GetGlobalA ACTION_RETURN_INT(ACS_GlobalArrays[arrayno][index]); } -void FormatNumber(int number, int minsize, int maxsize, int flags, const FString &prefix, FString *result); - -DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, FormatNumber, FormatNumber) -{ - PARAM_PROLOGUE; - PARAM_INT(number); - PARAM_INT(minsize); - PARAM_INT(maxsize); - PARAM_INT(flags); - PARAM_STRING(prefix); - FString fmt; - FormatNumber(number, minsize, maxsize, flags, prefix, &fmt); - ACTION_RETURN_STRING(fmt); -} - static void ReceivedWeapon(DBaseStatusBar *self) { self->mugshot.Grin(); @@ -2742,7 +2201,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, ReceivedWeapon, ReceivedWeapon) static int GetMugshot(DBaseStatusBar *self, int accuracy, int stateflags, const FString &def_face) { - auto tex = self->mugshot.GetFace(self->CPlayer, def_face, accuracy, (FMugShot::StateFlags)stateflags); + auto tex = self->mugshot.GetFace(self->CPlayer, def_face.GetChars(), accuracy, (FMugShot::StateFlags)stateflags); return (tex ? tex->GetID().GetIndex() : -1); } @@ -2764,32 +2223,9 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetInventoryIcon, GetInventoryIcon FTextureID icon = FSetTextureID(GetInventoryIcon(item, flags, &applyscale)); if (numret >= 1) ret[0].SetInt(icon.GetIndex()); if (numret >= 2) ret[1].SetInt(applyscale); - return MIN(numret, 2); + return min(numret, 2); } -//===================================================================================== -// -// -// -//===================================================================================== - -DHUDFont *CreateHudFont(FFont *fnt, int spac, int mono, int sx, int sy) -{ - return (Create(fnt, spac, EMonospacing(mono), sy, sy)); -} - -DEFINE_ACTION_FUNCTION_NATIVE(DHUDFont, Create, CreateHudFont) -{ - PARAM_PROLOGUE; - PARAM_POINTER(fnt, FFont); - PARAM_INT(spac); - PARAM_INT(mono); - PARAM_INT(sx); - PARAM_INT(sy); - ACTION_RETURN_POINTER(Create(fnt, spac, EMonospacing(mono), sy, sy)); -} - - //===================================================================================== // // @@ -2905,7 +2341,7 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GetChecksum) for (int j = 0; j < 16; ++j) { - sprintf(md5string + j * 2, "%02x", self->md5[j]); + snprintf(md5string + j * 2, 3, "%02x", self->md5[j]); } ACTION_RETURN_STRING((const char*)md5string); @@ -3053,6 +2489,29 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, Vec3Diff, Vec3Diff) ACTION_RETURN_VEC3(VecDiff(self, DVector3(x1, y1, z1), DVector3(x2, y2, z2))); } +DEFINE_ACTION_FUNCTION(FLevelLocals, GetDisplacement) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_INT(pg1); + PARAM_INT(pg2); + + DVector2 ofs(0, 0); + if (pg1 != pg2) + { + unsigned i = pg1 + self->Displacements.size * pg2; + if (i < self->Displacements.data.Size()) + ofs = self->Displacements.data[i].pos; + } + + ACTION_RETURN_VEC2(ofs); +} + +DEFINE_ACTION_FUNCTION(FLevelLocals, GetPortalGroupCount) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + ACTION_RETURN_INT(self->Displacements.size); +} + void SphericalCoords(FLevelLocals *self, double vpX, double vpY, double vpZ, double tX, double tY, double tZ, double viewYaw, double viewPitch, int absolute, DVector3 *result) { @@ -3061,8 +2520,8 @@ void SphericalCoords(FLevelLocals *self, double vpX, double vpY, double vpZ, dou auto vecTo = absolute ? target - viewpoint : VecDiff(self, viewpoint, target); *result = (DVector3( - deltaangle(vecTo.Angle(), viewYaw).Degrees, - deltaangle(vecTo.Pitch(), viewPitch).Degrees, + deltaangle(vecTo.Angle(), DAngle::fromDeg(viewYaw)).Degrees(), + deltaangle(vecTo.Pitch(), DAngle::fromDeg(viewPitch)).Degrees(), vecTo.Length() )); @@ -3084,6 +2543,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SphericalCoords, SphericalCoords) ACTION_RETURN_VEC3(result); } +static void LookupString(FLevelLocals *level, uint32_t index, FString *res) +{ + *res = level->Behaviors.LookupString(index); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, LookupString, LookupString) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_UINT(index); + FString res; + LookupString(self, index, &res); + ACTION_RETURN_STRING(res); +} static int isFrozen(FLevelLocals *self) { @@ -3115,20 +2587,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, setFrozen, setFrozen) // //===================================================================================== -static int GetRealTime() -{ - time_t now; - time(&now); - struct tm* timeinfo = localtime(&now); - return timeinfo ? timeinfo->tm_sec + timeinfo->tm_min * 60 + timeinfo->tm_hour * 3600 : 0; -} - -DEFINE_ACTION_FUNCTION_NATIVE(_AltHUD, GetRealTime, GetRealTime) -{ - PARAM_PROLOGUE; - ACTION_RETURN_INT(GetRealTime()); -} - DEFINE_ACTION_FUNCTION_NATIVE(_AltHUD, GetLatency, Net_GetLatency) { PARAM_PROLOGUE; @@ -3140,16 +2598,199 @@ DEFINE_ACTION_FUNCTION_NATIVE(_AltHUD, GetLatency, Net_GetLatency) return numret; } +DEFINE_ACTION_FUNCTION(_CVar, GetCVar) +{ + PARAM_PROLOGUE; + PARAM_NAME(name); + PARAM_POINTER(plyr, player_t); + ACTION_RETURN_POINTER(GetCVar(plyr ? int(plyr - players) : -1, name.GetChars())); +} + + +DEFINE_ACTION_FUNCTION(DObject, S_ChangeMusic) +{ + PARAM_PROLOGUE; + PARAM_STRING(music); + PARAM_INT(order); + PARAM_BOOL(looping); + PARAM_BOOL(force); + ACTION_RETURN_BOOL(S_ChangeMusic(music.GetChars(), order, looping, force)); +} + + +DEFINE_ACTION_FUNCTION(_Screen, GetViewWindow) +{ + PARAM_PROLOGUE; + if (numret > 0) ret[0].SetInt(viewwindowx); + if (numret > 1) ret[1].SetInt(viewwindowy); + if (numret > 2) ret[2].SetInt(viewwidth); + if (numret > 3) ret[3].SetInt(viewheight); + return min(numret, 4); +} + +DEFINE_ACTION_FUNCTION(_Console, MidPrint) +{ + PARAM_PROLOGUE; + PARAM_POINTER(fnt, FFont); + PARAM_STRING(text); + PARAM_BOOL(bold); + + const char* txt = text[0] == '$' ? GStrings.GetString(&text[1]) : text.GetChars(); + C_MidPrint(fnt, txt, bold); + return 0; +} + //========================================================================== // // // //========================================================================== + +static int isValid( level_info_t *info ) +{ + return info->isValid(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_LevelInfo, isValid, isValid) +{ + PARAM_SELF_STRUCT_PROLOGUE(level_info_t); + ACTION_RETURN_BOOL(isValid(self)); +} + +static void LookupLevelName( level_info_t *info, FString *result ) +{ + *result = info->LookupLevelName(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_LevelInfo, LookupLevelName, LookupLevelName) +{ + PARAM_SELF_STRUCT_PROLOGUE(level_info_t); + FString rets; + LookupLevelName(self,&rets); + ACTION_RETURN_STRING(rets); +} + +static int GetLevelInfoCount() +{ + return wadlevelinfos.Size(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_LevelInfo, GetLevelInfoCount, GetLevelInfoCount) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(GetLevelInfoCount()); +} + +static level_info_t* GetLevelInfo( unsigned int index ) +{ + if ( index >= wadlevelinfos.Size() ) + return nullptr; + return &wadlevelinfos[index]; +} + +DEFINE_ACTION_FUNCTION_NATIVE(_LevelInfo, GetLevelInfo, GetLevelInfo) +{ + PARAM_PROLOGUE; + PARAM_INT(index); + ACTION_RETURN_POINTER(GetLevelInfo(index)); +} + +static level_info_t* ZFindLevelInfo( const FString &mapname ) +{ + return FindLevelInfo(mapname.GetChars()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_LevelInfo, FindLevelInfo, ZFindLevelInfo) +{ + PARAM_PROLOGUE; + PARAM_STRING(mapname); + ACTION_RETURN_POINTER(ZFindLevelInfo(mapname)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_LevelInfo, FindLevelByNum, FindLevelByNum) +{ + PARAM_PROLOGUE; + PARAM_INT(num); + ACTION_RETURN_POINTER(FindLevelByNum(num)); +} + +static int MapExists( const FString &mapname ) +{ + return P_CheckMapData(mapname.GetChars()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_LevelInfo, MapExists, MapExists) +{ + PARAM_PROLOGUE; + PARAM_STRING(mapname); + ACTION_RETURN_BOOL(MapExists(mapname)); +} + +DEFINE_ACTION_FUNCTION(_LevelInfo, MapChecksum) +{ + PARAM_PROLOGUE; + PARAM_STRING(mapname); + char md5string[33] = ""; + MapData *map = P_OpenMapData(mapname.GetChars(), true); + if (map != nullptr) + { + uint8_t cksum[16]; + map->GetChecksum(cksum); + for (int j = 0; j < 16; ++j) + { + snprintf(md5string + j * 2, 3, "%02x", cksum[j]); + } + delete map; + } + ACTION_RETURN_STRING((const char *)md5string); +} + +//========================================================================== +// +// +// +//========================================================================== +DEFINE_FIELD_X(LevelInfo, level_info_t, levelnum) +DEFINE_FIELD_X(LevelInfo, level_info_t, MapName) +DEFINE_FIELD_X(LevelInfo, level_info_t, NextMap) +DEFINE_FIELD_X(LevelInfo, level_info_t, NextSecretMap) +DEFINE_FIELD_X(LevelInfo, level_info_t, SkyPic1) +DEFINE_FIELD_X(LevelInfo, level_info_t, SkyPic2) +DEFINE_FIELD_X(LevelInfo, level_info_t, F1Pic) +DEFINE_FIELD_X(LevelInfo, level_info_t, cluster) +DEFINE_FIELD_X(LevelInfo, level_info_t, partime) +DEFINE_FIELD_X(LevelInfo, level_info_t, sucktime) +DEFINE_FIELD_X(LevelInfo, level_info_t, flags) +DEFINE_FIELD_X(LevelInfo, level_info_t, flags2) +DEFINE_FIELD_X(LevelInfo, level_info_t, flags3) +DEFINE_FIELD_X(LevelInfo, level_info_t, Music) +DEFINE_FIELD_X(LevelInfo, level_info_t, LightningSound) +DEFINE_FIELD_X(LevelInfo, level_info_t, LevelName) +DEFINE_FIELD_X(LevelInfo, level_info_t, AuthorName) +DEFINE_FIELD_X(LevelInfo, level_info_t, musicorder) +DEFINE_FIELD_X(LevelInfo, level_info_t, skyspeed1) +DEFINE_FIELD_X(LevelInfo, level_info_t, skyspeed2) +DEFINE_FIELD_X(LevelInfo, level_info_t, cdtrack) +DEFINE_FIELD_X(LevelInfo, level_info_t, gravity) +DEFINE_FIELD_X(LevelInfo, level_info_t, aircontrol) +DEFINE_FIELD_X(LevelInfo, level_info_t, airsupply) +DEFINE_FIELD_X(LevelInfo, level_info_t, compatflags) +DEFINE_FIELD_X(LevelInfo, level_info_t, compatflags2) +DEFINE_FIELD_X(LevelInfo, level_info_t, deathsequence) +DEFINE_FIELD_X(LevelInfo, level_info_t, fogdensity) +DEFINE_FIELD_X(LevelInfo, level_info_t, outsidefogdensity) +DEFINE_FIELD_X(LevelInfo, level_info_t, skyfog) +DEFINE_FIELD_X(LevelInfo, level_info_t, pixelstretch) +DEFINE_FIELD_X(LevelInfo, level_info_t, RedirectType) +DEFINE_FIELD_X(LevelInfo, level_info_t, RedirectMapName) +DEFINE_FIELD_X(LevelInfo, level_info_t, teamdamage) + DEFINE_GLOBAL_NAMED(currentVMLevel, level) DEFINE_FIELD(FLevelLocals, sectors) DEFINE_FIELD(FLevelLocals, lines) DEFINE_FIELD(FLevelLocals, sides) DEFINE_FIELD(FLevelLocals, vertexes) +DEFINE_FIELD(FLevelLocals, linePortals) DEFINE_FIELD(FLevelLocals, sectorPortals) DEFINE_FIELD(FLevelLocals, time) DEFINE_FIELD(FLevelLocals, maptime) @@ -3167,6 +2808,7 @@ DEFINE_FIELD(FLevelLocals, NextSecretMap) DEFINE_FIELD(FLevelLocals, F1Pic) DEFINE_FIELD(FLevelLocals, AuthorName) DEFINE_FIELD(FLevelLocals, maptype) +DEFINE_FIELD(FLevelLocals, LightningSound) DEFINE_FIELD(FLevelLocals, Music) DEFINE_FIELD(FLevelLocals, musicorder) DEFINE_FIELD(FLevelLocals, skytexture1) @@ -3193,11 +2835,13 @@ DEFINE_FIELD(FLevelLocals, deathsequence) DEFINE_FIELD_BIT(FLevelLocals, frozenstate, frozen, 1) // still needed for backwards compatibility. DEFINE_FIELD_NAMED(FLevelLocals, i_compatflags, compatflags) DEFINE_FIELD_NAMED(FLevelLocals, i_compatflags2, compatflags2) +DEFINE_FIELD(FLevelLocals, info); DEFINE_FIELD_BIT(FLevelLocals, flags, noinventorybar, LEVEL_NOINVENTORYBAR) DEFINE_FIELD_BIT(FLevelLocals, flags, monsterstelefrag, LEVEL_MONSTERSTELEFRAG) DEFINE_FIELD_BIT(FLevelLocals, flags, actownspecial, LEVEL_ACTOWNSPECIAL) DEFINE_FIELD_BIT(FLevelLocals, flags, sndseqtotalctrl, LEVEL_SNDSEQTOTALCTRL) +DEFINE_FIELD_BIT(FLevelLocals, flags, useplayerstartz, LEVEL_USEPLAYERSTARTZ) DEFINE_FIELD_BIT(FLevelLocals, flags2, allmap, LEVEL2_ALLMAP) DEFINE_FIELD_BIT(FLevelLocals, flags2, missilesactivateimpact, LEVEL2_MISSILESACTIVATEIMPACT) DEFINE_FIELD_BIT(FLevelLocals, flags2, monsterfallingdamage, LEVEL2_MONSTERFALLINGDAMAGE) @@ -3219,7 +2863,7 @@ DEFINE_FIELD_X(Sector, sector_t, SoundTarget) DEFINE_FIELD_X(Sector, sector_t, special) DEFINE_FIELD_X(Sector, sector_t, lightlevel) DEFINE_FIELD_X(Sector, sector_t, seqType) -DEFINE_FIELD_X(Sector, sector_t, sky) +DEFINE_FIELD_NAMED_X(Sector, sector_t, skytransfer, sky) DEFINE_FIELD_X(Sector, sector_t, SeqName) DEFINE_FIELD_X(Sector, sector_t, centerspot) DEFINE_FIELD_X(Sector, sector_t, validcount) @@ -3264,6 +2908,7 @@ DEFINE_FIELD_X(Line, line_t, v1) DEFINE_FIELD_X(Line, line_t, v2) DEFINE_FIELD_X(Line, line_t, delta) DEFINE_FIELD_X(Line, line_t, flags) +DEFINE_FIELD_X(Line, line_t, flags2) DEFINE_FIELD_X(Line, line_t, activation) DEFINE_FIELD_X(Line, line_t, special) DEFINE_FIELD_X(Line, line_t, args) @@ -3298,24 +2943,14 @@ DEFINE_FIELD_X(F3DFloor, F3DFloor, alpha); DEFINE_FIELD_X(Vertex, vertex_t, p) -DEFINE_FIELD(DBaseStatusBar, RelTop); -DEFINE_FIELD(DBaseStatusBar, HorizontalResolution); -DEFINE_FIELD(DBaseStatusBar, VerticalResolution); DEFINE_FIELD(DBaseStatusBar, Centering); DEFINE_FIELD(DBaseStatusBar, FixedOrigin); -DEFINE_FIELD(DBaseStatusBar, CompleteBorder); DEFINE_FIELD(DBaseStatusBar, CrosshairSize); DEFINE_FIELD(DBaseStatusBar, Displacement); DEFINE_FIELD(DBaseStatusBar, CPlayer); DEFINE_FIELD(DBaseStatusBar, ShowLog); -DEFINE_FIELD(DBaseStatusBar, Alpha); -DEFINE_FIELD(DBaseStatusBar, drawOffset); -DEFINE_FIELD(DBaseStatusBar, drawClip); -DEFINE_FIELD(DBaseStatusBar, fullscreenOffsets); -DEFINE_FIELD(DBaseStatusBar, defaultScale); DEFINE_FIELD(DBaseStatusBar, artiflashTick); DEFINE_FIELD(DBaseStatusBar, itemflashFade); -DEFINE_FIELD(DHUDFont, mFont); DEFINE_GLOBAL(StatusBar); diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index b2943410f92..acf25380761 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -55,10 +55,12 @@ #include "actorinlines.h" #include "p_enemy.h" #include "gi.h" +#include "shadowinlines.h" DVector2 AM_GetPosition(); int Net_GetLatency(int *ld, int *ad); void PrintPickupMessage(bool localview, const FString &str); +bool P_CheckForResurrection(AActor* self, bool usevilestates, FState* state = nullptr, FSoundID sound = NO_SOUND); // FCheckPosition requires explicit construction and destruction when used in the VM @@ -172,7 +174,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SoundVolume, S_ChangeActorSoundVolume) DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_PlaySound, A_PlaySound) { PARAM_SELF_PROLOGUE(AActor); - PARAM_SOUND(soundid); + PARAM_INT(soundid); PARAM_INT(channel); PARAM_FLOAT(volume); PARAM_BOOL(looping); @@ -186,7 +188,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_PlaySound, A_PlaySound) DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StartSound, A_StartSound) { PARAM_SELF_PROLOGUE(AActor); - PARAM_SOUND(soundid); + PARAM_INT(soundid); PARAM_INT(channel); PARAM_INT(flags); PARAM_FLOAT(volume); @@ -197,7 +199,35 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StartSound, A_StartSound) return 0; } -DEFINE_ACTION_FUNCTION_NATIVE(AActor, IsActorPlayingSound, S_IsActorPlayingSomething) + +void A_StartSoundIfNotSame(AActor *self, int soundid, int checksoundid, int channel, int flags, double volume, double attenuation, double pitch, double startTime) +{ + if (!S_AreSoundsEquivalent (self, FSoundID::fromInt(soundid), FSoundID::fromInt(checksoundid))) + A_StartSound(self, soundid, channel, flags, volume, attenuation, pitch, startTime); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StartSoundIfNotSame, A_StartSoundIfNotSame) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(soundid); + PARAM_INT(checksoundid); + PARAM_INT(channel); + PARAM_INT(flags); + PARAM_FLOAT(volume); + PARAM_FLOAT(attenuation); + PARAM_FLOAT(pitch); + PARAM_FLOAT(startTime); + A_StartSoundIfNotSame(self, soundid, checksoundid, channel, flags, volume, attenuation, pitch, startTime); + return 0; +} + +// direct native scripting export. +static int S_IsActorPlayingSomethingID(AActor* actor, int channel, int sound_id) +{ + return S_IsActorPlayingSomething(actor, channel, FSoundID::fromInt(sound_id)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, IsActorPlayingSound, S_IsActorPlayingSomethingID) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(channel); @@ -216,7 +246,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckKeys, P_CheckKeys) static double deltaangleDbl(double a1, double a2) { - return deltaangle(DAngle(a1), DAngle(a2)).Degrees; + return deltaangle(DAngle::fromDeg(a1), DAngle::fromDeg(a2)).Degrees(); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, deltaangle, deltaangleDbl) // should this be global? @@ -224,12 +254,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, deltaangle, deltaangleDbl) // should this PARAM_PROLOGUE; PARAM_FLOAT(a1); PARAM_FLOAT(a2); - ACTION_RETURN_FLOAT(deltaangle(DAngle(a1), DAngle(a2)).Degrees); + ACTION_RETURN_FLOAT(deltaangle(DAngle::fromDeg(a1), DAngle::fromDeg(a2)).Degrees()); } static double absangleDbl(double a1, double a2) { - return absangle(DAngle(a1), DAngle(a2)).Degrees; + return absangle(DAngle::fromDeg(a1), DAngle::fromDeg(a2)).Degrees(); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, absangle, absangleDbl) // should this be global? @@ -237,7 +267,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, absangle, absangleDbl) // should this be g PARAM_PROLOGUE; PARAM_FLOAT(a1); PARAM_FLOAT(a2); - ACTION_RETURN_FLOAT(absangle(DAngle(a1), DAngle(a2)).Degrees); + ACTION_RETURN_FLOAT(absangle(DAngle::fromDeg(a1), DAngle::fromDeg(a2)).Degrees()); } static double Distance2DSquared(AActor *self, AActor *other) @@ -328,6 +358,18 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetDamage, SetDamage) return 0; } +static double PitchFromVel(AActor* self) +{ + return self->Vel.Pitch().Degrees(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, PitchFromVel, PitchFromVel) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(PitchFromVel(self)); +} + + // This combines all 3 variations of the internal function static void VelFromAngle(AActor *self, double speed, double angle) { @@ -344,7 +386,7 @@ static void VelFromAngle(AActor *self, double speed, double angle) } else { - self->VelFromAngle(speed, angle); + self->VelFromAngle(speed, DAngle::fromDeg(angle)); } } } @@ -360,7 +402,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, VelFromAngle, VelFromAngle) static void Vel3DFromAngle(AActor *self, double speed, double angle, double pitch) { - self->Vel3DFromAngle(angle, pitch, speed); + self->Vel3DFromAngle(DAngle::fromDeg(angle), DAngle::fromDeg(pitch), speed); } // This combines all 3 variations of the internal function @@ -389,7 +431,7 @@ static void Thrust(AActor *self, double speed, double angle) } else { - self->Thrust(angle, speed); + self->Thrust(DAngle::fromDeg(angle), speed); } } } @@ -405,7 +447,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, Thrust, Thrust) static double AngleTo(AActor *self, AActor *targ, bool absolute) { - return self->AngleTo(PARAM_NULLCHECK(targ, targ), absolute).Degrees; + return self->AngleTo(PARAM_NULLCHECK(targ, targ), absolute).Degrees(); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, AngleTo, AngleTo) @@ -413,12 +455,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, AngleTo, AngleTo) PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT_NOT_NULL(targ, AActor); PARAM_BOOL(absolute); - ACTION_RETURN_FLOAT(self->AngleTo(targ, absolute).Degrees); + ACTION_RETURN_FLOAT(self->AngleTo(targ, absolute).Degrees()); } static void AngleToVector(double angle, double length, DVector2 *result) { - *result = DAngle(angle).ToVector(length); + *result = DAngle::fromDeg(angle).ToVector(length); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, AngleToVector, AngleToVector) @@ -445,14 +487,14 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, RotateVector, RotateVector) static double Normalize180(double angle) { - return DAngle(angle).Normalized180().Degrees; + return DAngle::fromDeg(angle).Normalized180().Degrees(); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, Normalize180, Normalize180) { PARAM_PROLOGUE; PARAM_ANGLE(angle); - ACTION_RETURN_FLOAT(angle.Normalized180().Degrees); + ACTION_RETURN_FLOAT(angle.Normalized180().Degrees()); } static double DistanceBySpeed(AActor *self, AActor *targ, double speed) @@ -485,7 +527,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetXYZ, SetXYZ) static void Vec2Angle(AActor *self, double length, double angle, bool absolute, DVector2 *result) { - *result = self->Vec2Angle(length, angle, absolute); + *result = self->Vec2Angle(length, DAngle::fromDeg(angle), absolute); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, Vec2Angle, Vec2Angle) @@ -523,7 +565,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, Vec2To, Vec2To) static void Vec3Angle(AActor *self, double length, double angle, double z, bool absolute, DVector3 *result) { - *result = self->Vec3Angle(length, angle, z, absolute); + *result = self->Vec3Angle(length, DAngle::fromDeg(angle), z, absolute); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, Vec3Angle, Vec3Angle) @@ -675,6 +717,13 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearInterpolation, ClearInterpolation) return 0; } +DEFINE_ACTION_FUNCTION(AActor, ClearFOVInterpolation) +{ + PARAM_SELF_PROLOGUE(AActor); + self->ClearFOVInterpolation(); + return 0; +} + static int ApplyDamageFactors(PClassActor *itemcls, int damagetype, int damage, int defdamage) { DmgFactors &df = itemcls->ActorInfo()->DamageFactors; @@ -814,6 +863,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetTag, GetTag) ACTION_RETURN_STRING(res); } +static void GetCharacterName(AActor *self, FString *result) +{ + *result = self->GetCharacterName(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetCharacterName, GetCharacterName) +{ + PARAM_SELF_PROLOGUE(AActor); + FString res; + GetCharacterName(self, &res); + ACTION_RETURN_STRING(res); +} + static void SetTag(AActor *self, const FString &def) { if (def.IsEmpty()) self->Tag = nullptr; @@ -893,13 +955,13 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, isTeammate, isTeammate) static int GetSpecies(AActor *self) { - return self->GetSpecies(); + return self->GetSpecies().GetIndex(); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetSpecies, GetSpecies) { PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_INT(self->GetSpecies()); + ACTION_RETURN_INT(GetSpecies(self)); } static int isFriend(AActor *self, AActor *other) @@ -1102,7 +1164,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckMove, CheckMove) static double AimLineAttack(AActor *self, double angle, double distance, FTranslatedLineTarget *pLineTarget, double vrange, int flags, AActor *target, AActor *friender) { - return P_AimLineAttack(self, angle, distance, pLineTarget, vrange, flags, target, friender).Degrees; + flags &= ~ALF_IGNORENOAUTOAIM; // just to be safe. This flag is not supposed to be accesible to scripting. + return P_AimLineAttack(self, DAngle::fromDeg(angle), distance, pLineTarget, DAngle::fromDeg(vrange), flags, target, friender).Degrees(); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, AimLineAttack, AimLineAttack) @@ -1115,13 +1178,13 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, AimLineAttack, AimLineAttack) PARAM_INT(flags); PARAM_OBJECT(target, AActor); PARAM_OBJECT(friender, AActor); - ACTION_RETURN_FLOAT(P_AimLineAttack(self, angle, distance, pLineTarget, vrange, flags, target, friender).Degrees); + ACTION_RETURN_FLOAT(P_AimLineAttack(self, angle, distance, pLineTarget, vrange, flags, target, friender).Degrees()); } static AActor *ZS_LineAttack(AActor *self, double angle, double distance, double pitch, int damage, int damageType, PClassActor *puffType, int flags, FTranslatedLineTarget *victim, double offsetz, double offsetforward, double offsetside, int *actualdamage) { if (puffType == nullptr) puffType = PClass::FindActor(NAME_BulletPuff); // P_LineAttack does not work without a puff to take info from. - return P_LineAttack(self, angle, distance, pitch, damage, ENamedName(damageType), puffType, flags, victim, actualdamage, offsetz, offsetforward, offsetside); + return P_LineAttack(self, DAngle::fromDeg(angle), distance, DAngle::fromDeg(pitch), damage, ENamedName(damageType), puffType, flags, victim, actualdamage, offsetz, offsetforward, offsetside); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, LineAttack, ZS_LineAttack) @@ -1148,7 +1211,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, LineAttack, ZS_LineAttack) static int LineTrace(AActor *self, double angle, double distance, double pitch, int flags, double offsetz, double offsetforward, double offsetside, FLineTraceData *data) { - return P_LineTrace(self,angle,distance,pitch,flags,offsetz,offsetforward,offsetside,data); + return P_LineTrace(self,DAngle::fromDeg(angle),distance,DAngle::fromDeg(pitch),flags,offsetz,offsetforward,offsetside,data); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, LineTrace, LineTrace) @@ -1162,12 +1225,29 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, LineTrace, LineTrace) PARAM_FLOAT(offsetforward); PARAM_FLOAT(offsetside); PARAM_OUTPOINTER(data, FLineTraceData); - ACTION_RETURN_BOOL(P_LineTrace(self,angle,distance,pitch,flags,offsetz,offsetforward,offsetside,data)); + ACTION_RETURN_BOOL(P_LineTrace(self,DAngle::fromDeg(angle),distance,DAngle::fromDeg(pitch),flags,offsetz,offsetforward,offsetside,data)); } +DEFINE_ACTION_FUNCTION(AActor, PerformShadowChecks) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); //If this pointer is null, the trace uses the facing direction instead. + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + + double penaltyFactor = 0.0; + AActor* shadow = PerformShadowChecks(self, other, DVector3(x, y, z), penaltyFactor); + if (numret > 2) ret[2].SetFloat(penaltyFactor); + if (numret > 1) ret[1].SetObject(shadow); + if (numret > 0) ret[0].SetInt(bool(shadow)); + return numret; +} + + static void TraceBleedAngle(AActor *self, int damage, double angle, double pitch) { - P_TraceBleed(damage, self, angle, pitch); + P_TraceBleed(damage, self, DAngle::fromDeg(angle), DAngle::fromDeg(pitch)); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, TraceBleedAngle, TraceBleedAngle) @@ -1177,7 +1257,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, TraceBleedAngle, TraceBleedAngle) PARAM_FLOAT(angle); PARAM_FLOAT(pitch); - P_TraceBleed(damage, self, angle, pitch); + P_TraceBleed(damage, self, DAngle::fromDeg(angle), DAngle::fromDeg(pitch)); return 0; } @@ -1237,15 +1317,16 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetRadiusDamage, P_GetRadiusDamage) PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(thing, AActor); PARAM_INT(damage); - PARAM_INT(distance); - PARAM_INT(fulldmgdistance); + PARAM_FLOAT(distance); + PARAM_FLOAT(fulldmgdistance); PARAM_BOOL(oldradiusdmg); - ACTION_RETURN_INT(P_GetRadiusDamage(self, thing, damage, distance, fulldmgdistance, oldradiusdmg)); + PARAM_BOOL(circular); + ACTION_RETURN_INT(P_GetRadiusDamage(self, thing, damage, distance, fulldmgdistance, oldradiusdmg, circular)); } -static int RadiusAttack(AActor *self, AActor *bombsource, int bombdamage, int bombdistance, int damagetype, int flags, int fulldamagedistance) +static int RadiusAttack(AActor *self, AActor *bombsource, int bombdamage, double bombdistance, int damagetype, int flags, double fulldamagedistance, int species) { - return P_RadiusAttack(self, bombsource, bombdamage, bombdistance, ENamedName(damagetype), flags, fulldamagedistance); + return P_RadiusAttack(self, bombsource, bombdamage, bombdistance, ENamedName(damagetype), flags, fulldamagedistance, ENamedName(species)); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, RadiusAttack, RadiusAttack) @@ -1253,11 +1334,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, RadiusAttack, RadiusAttack) PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(bombsource, AActor); PARAM_INT(bombdamage); - PARAM_INT(bombdistance); + PARAM_FLOAT(bombdistance); PARAM_INT(damagetype); PARAM_INT(flags); - PARAM_INT(fulldamagedistance); - ACTION_RETURN_INT(RadiusAttack(self, bombsource, bombdamage, bombdistance, damagetype, flags, fulldamagedistance)); + PARAM_FLOAT(fulldamagedistance); + PARAM_INT(species); + ACTION_RETURN_INT(RadiusAttack(self, bombsource, bombdamage, bombdistance, damagetype, flags, fulldamagedistance, species)); } static int ZS_GetSpriteIndex(int sprt) @@ -1298,7 +1380,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetReplacee, ZS_GetReplacee) static void DrawSplash(AActor *self, int count, double angle, int kind) { - P_DrawSplash(self->Level, count, self->Pos(), angle, kind); + P_DrawSplash(self->Level, count, self->Pos(), DAngle::fromDeg(angle), kind); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, DrawSplash, DrawSplash) @@ -1307,7 +1389,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, DrawSplash, DrawSplash) PARAM_INT(count); PARAM_FLOAT(angle); PARAM_INT(kind); - P_DrawSplash(self->Level, count, self->Pos(), angle, kind); + P_DrawSplash(self->Level, count, self->Pos(), DAngle::fromDeg(angle), kind); return 0; } @@ -1359,7 +1441,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, RoughMonsterSearch, P_RoughMonsterSearch) PARAM_INT(distance); PARAM_BOOL(onlyseekable); PARAM_BOOL(frontonly); - ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable, frontonly)); + PARAM_FLOAT(fov); + ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable, frontonly, fov)); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckSight, P_CheckSight) @@ -1415,10 +1498,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, HitFriend, P_HitFriend) ACTION_RETURN_BOOL(P_HitFriend(self)); } -DEFINE_ACTION_FUNCTION_NATIVE(AActor, MonsterMove, P_Move) +DEFINE_ACTION_FUNCTION_NATIVE(AActor, MonsterMove, P_SmartMove) { PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_BOOL(P_Move(self)); + ACTION_RETURN_BOOL(P_SmartMove(self)); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, NewChaseDir, P_NewChaseDir) @@ -1474,20 +1557,21 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, LookForPlayers, P_LookForPlayers) ACTION_RETURN_BOOL(P_LookForPlayers(self, allaround, params)); } -static int CheckMonsterUseSpecials(AActor *self) +static int CheckMonsterUseSpecials(AActor *self, line_t *blocking) { spechit_t spec; int good = 0; if (!(self->flags6 & MF6_NOTRIGGER)) { + auto checkLine = blocking ? blocking : self->BlockingLine; while (spechit.Pop (spec)) { // [RH] let monsters push lines, as well as use them if (((self->flags4 & MF4_CANUSEWALLS) && P_ActivateLine (spec.line, self, 0, SPAC_Use)) || ((self->flags2 & MF2_PUSHWALL) && P_ActivateLine (spec.line, self, 0, SPAC_Push))) { - good |= spec.line == self->BlockingLine ? 1 : 2; + good |= spec.line == checkLine ? 1 : 2; } } } @@ -1499,8 +1583,9 @@ static int CheckMonsterUseSpecials(AActor *self) DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckMonsterUseSpecials, CheckMonsterUseSpecials) { PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(blocking, line_t); - ACTION_RETURN_INT(CheckMonsterUseSpecials(self)); + ACTION_RETURN_INT(CheckMonsterUseSpecials(self, blocking)); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_Wander, A_Wander) @@ -1562,20 +1647,22 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_ExtChase, A_ExtChase) return 0; } -int CheckForResurrection(AActor *self) +int CheckForResurrection(AActor *self, FState* state, int sound) { - return P_CheckForResurrection(self, false); + return P_CheckForResurrection(self, false, state, FSoundID::fromInt(sound)); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_CheckForResurrection, CheckForResurrection) { PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_BOOL(P_CheckForResurrection(self, false)); + PARAM_POINTER(state, FState); + PARAM_INT(sound); + ACTION_RETURN_BOOL(CheckForResurrection(self, state, sound)); } static void ZS_Face(AActor *self, AActor *faceto, double max_turn, double max_pitch, double ang_offset, double pitch_offset, int flags, double z_add) { - A_Face(self, faceto, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_add); + A_Face(self, faceto, DAngle::fromDeg(max_turn), DAngle::fromDeg(max_pitch), DAngle::fromDeg(ang_offset), DAngle::fromDeg(pitch_offset), flags, z_add); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_Face, ZS_Face) @@ -1606,12 +1693,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_BossDeath, A_BossDeath) return 0; } -DEFINE_ACTION_FUNCTION_NATIVE(AActor, Substitute, DObject::StaticPointerSubstitution) +DEFINE_ACTION_FUNCTION_NATIVE(AActor, MorphInto, MorphPointerSubstitution) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(replace, AActor); - DObject::StaticPointerSubstitution(self, replace); - return 0; + PARAM_OBJECT(to, AActor); + ACTION_RETURN_INT(MorphPointerSubstitution(self, to)); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetSpawnableType, P_GetSpawnableType) @@ -1667,6 +1753,27 @@ DEFINE_ACTION_FUNCTION_NATIVE(AInventory, PrintPickupMessage, PrintPickupMessage // //===================================================================================== +DEFINE_ACTION_FUNCTION_NATIVE(AKey, IsLockDefined, P_IsLockDefined) +{ + PARAM_PROLOGUE; + PARAM_INT(locknum); + ACTION_RETURN_BOOL(P_IsLockDefined(locknum)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AKey, GetMapColorForLock, P_GetMapColorForLock) +{ + PARAM_PROLOGUE; + PARAM_INT(locknum); + ACTION_RETURN_INT(P_GetMapColorForLock(locknum)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AKey, GetMapColorForKey, P_GetMapColorForKey) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(key, AActor); + ACTION_RETURN_INT(P_GetMapColorForKey(key)); +} + DEFINE_ACTION_FUNCTION_NATIVE(AKey, GetKeyTypeCount, P_GetKeyTypeCount) { PARAM_PROLOGUE; @@ -1711,6 +1818,60 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckFor3DCeilingHit, CheckFor3DCeilingHit ACTION_RETURN_BOOL(P_CheckFor3DCeilingHit(self, z, trigger)); } +//===================================================================================== +// +// Bounce exports +// +//===================================================================================== +DEFINE_ACTION_FUNCTION(AActor, BounceActor) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(blocking, AActor); + PARAM_BOOL(onTop); + + ACTION_RETURN_BOOL(P_BounceActor(self, blocking, onTop)); +} + +DEFINE_ACTION_FUNCTION(AActor, BounceWall) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(l, line_t); + + auto cur = self->BlockingLine; + if (l) + self->BlockingLine = l; + + bool res = P_BounceWall(self); + self->BlockingLine = cur; + + ACTION_RETURN_BOOL(res); +} + +DEFINE_ACTION_FUNCTION(AActor, BouncePlane) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(plane, secplane_t); + + ACTION_RETURN_BOOL(self->FloorBounceMissile(*plane)); +} + +DEFINE_ACTION_FUNCTION(AActor, PlayBounceSound) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL(onFloor); + + self->PlayBounceSound(onFloor); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, ReflectOffActor) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(blocking, AActor); + + ACTION_RETURN_BOOL(P_ReflectOffActor(self, blocking)); +} + static int isFrozen(AActor *self) @@ -1724,7 +1885,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, isFrozen, isFrozen) ACTION_RETURN_BOOL(isFrozen(self)); } - //=========================================================================== // // PlayerPawn functions @@ -1750,7 +1910,31 @@ DEFINE_ACTION_FUNCTION_NATIVE(APlayerPawn, GetPrintableDisplayName, GetPrintable ACTION_RETURN_STRING(type->GetDisplayName()); } +static void SetViewPos(AActor *self, double x, double y, double z, int flags) +{ + if (!self->ViewPos) + { + self->ViewPos = Create(); + } + + DVector3 pos = { x,y,z }; + self->ViewPos->Set(pos, flags); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetViewPos, SetViewPos) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_INT(flags); + SetViewPos(self, x, y, z, flags); + return 0; +} +IMPLEMENT_CLASS(DViewPosition, false, false); +DEFINE_FIELD_X(ViewPosition, DViewPosition, Offset) +DEFINE_FIELD_X(ViewPosition, DViewPosition, Flags) DEFINE_FIELD(DThinker, Level) DEFINE_FIELD(AActor, snext) @@ -1759,6 +1943,8 @@ DEFINE_FIELD_NAMED(AActor, __Pos, pos) DEFINE_FIELD_NAMED(AActor, __Pos.X, x) DEFINE_FIELD_NAMED(AActor, __Pos.Y, y) DEFINE_FIELD_NAMED(AActor, __Pos.Z, z) +DEFINE_FIELD(AActor, SpriteOffset) +DEFINE_FIELD(AActor, WorldOffset) DEFINE_FIELD(AActor, Prev) DEFINE_FIELD(AActor, SpriteAngle) DEFINE_FIELD(AActor, SpriteRotation) @@ -1837,6 +2023,7 @@ DEFINE_FIELD(AActor, special) DEFINE_FIELD(AActor, tid) DEFINE_FIELD(AActor, TIDtoHate) DEFINE_FIELD(AActor, waterlevel) +DEFINE_FIELD(AActor, waterdepth) DEFINE_FIELD(AActor, Score) DEFINE_FIELD(AActor, accuracy) DEFINE_FIELD(AActor, stamina) @@ -1871,9 +2058,11 @@ DEFINE_FIELD(AActor, lastbump) DEFINE_FIELD(AActor, DesignatedTeam) DEFINE_FIELD(AActor, BlockingMobj) DEFINE_FIELD(AActor, BlockingLine) +DEFINE_FIELD(AActor, MovementBlockingLine) DEFINE_FIELD(AActor, Blocking3DFloor) DEFINE_FIELD(AActor, BlockingCeiling) DEFINE_FIELD(AActor, BlockingFloor) +DEFINE_FIELD(AActor, freezetics) DEFINE_FIELD(AActor, PoisonDamage) DEFINE_FIELD(AActor, PoisonDamageType) DEFINE_FIELD(AActor, PoisonDuration) @@ -1898,6 +2087,7 @@ DEFINE_FIELD(AActor, WallBounceSound) DEFINE_FIELD(AActor, CrushPainSound) DEFINE_FIELD(AActor, MaxDropOffHeight) DEFINE_FIELD(AActor, MaxStepHeight) +DEFINE_FIELD(AActor, MaxSlopeSteepness) DEFINE_FIELD(AActor, PainChance) DEFINE_FIELD(AActor, PainType) DEFINE_FIELD(AActor, DeathType) @@ -1926,6 +2116,20 @@ DEFINE_FIELD(AActor, RenderRequired) DEFINE_FIELD(AActor, friendlyseeblocks) DEFINE_FIELD(AActor, SpawnTime) DEFINE_FIELD(AActor, InventoryID) +DEFINE_FIELD(AActor, ThruBits) +DEFINE_FIELD(AActor, ViewPos) +DEFINE_FIELD_NAMED(AActor, ViewAngles.Yaw, viewangle) +DEFINE_FIELD_NAMED(AActor, ViewAngles.Pitch, viewpitch) +DEFINE_FIELD_NAMED(AActor, ViewAngles.Roll, viewroll) +DEFINE_FIELD(AActor, LightLevel) +DEFINE_FIELD(AActor, ShadowAimFactor) +DEFINE_FIELD(AActor, ShadowPenaltyFactor) +DEFINE_FIELD(AActor, AutomapOffsets) +DEFINE_FIELD(AActor, LandingSpeed) +DEFINE_FIELD(AActor, UnmorphTime) +DEFINE_FIELD(AActor, MorphFlags) +DEFINE_FIELD(AActor, PremorphProperties) +DEFINE_FIELD(AActor, MorphExitFlash) DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing); DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos); @@ -1982,4 +2186,35 @@ DEFINE_FIELD_X(FLineTraceData, FLineTraceData, LinePart); DEFINE_FIELD_X(FLineTraceData, FLineTraceData, SectorPlane); DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitType); - +DEFINE_FIELD_NAMED_X(FSpawnParticleParams, FSpawnParticleParams, color, color1); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, texture); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, style); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, flags); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, lifetime); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, size); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, sizestep); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, pos); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, vel); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, accel); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, startalpha); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, fadestep); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, startroll); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, rollvel); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, rollacc); + +static void SpawnParticle(FLevelLocals *Level, FSpawnParticleParams *params) +{ + P_SpawnParticle(Level, params->pos, params->vel, params->accel, + params->color, params->startalpha, params->lifetime, + params->size, params->fadestep, params->sizestep, + params->flags, params->texture, ERenderStyle(params->style), + params->startroll, params->rollvel, params->rollacc); +} + +DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnParticle, SpawnParticle) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_POINTER(p, FSpawnParticleParams); + SpawnParticle(self, p); + return 0; +} diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp deleted file mode 100644 index 99453901d22..00000000000 --- a/src/scripting/zscript/ast.cpp +++ /dev/null @@ -1,981 +0,0 @@ -/* -** ast.cpp -** -**--------------------------------------------------------------------------- -** Copyright -2016 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "dobject.h" -#include "vmintern.h" -#include "types.h" -#include "zcc_parser.h" -#include "zcc-parse.h" - -class FLispString; -extern void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *); - -static const char *BuiltInTypeNames[] = -{ - "sint8", "uint8", - "sint16", "uint16", - "sint32", "uint32_t", - "intauto", - - "bool", - "float64", "floatauto", - "string", - "vector2", - "vector3", - "name", - - "color", - "state", - "sound", - - "usertype", - "nativetype", - "let", -}; - -class FLispString -{ -public: - operator FString &() { return Str; } - - FLispString() - { - NestDepth = Column = 0; - WrapWidth = 200; - NeedSpace = false; - ConsecOpens = 0; - } - - void Open(const char *label) - { - size_t labellen = label != NULL ? strlen(label) : 0; - CheckWrap(labellen + 1 + NeedSpace); - if (NeedSpace) - { - Str << ' '; - ConsecOpens = 0; - } - Str << '('; - ConsecOpens++; - if (label != NULL) - { - Str.AppendCStrPart(label, labellen); - } - Column += labellen + 1 + NeedSpace; - NestDepth++; - NeedSpace = (label != NULL); - } - void Close() - { - assert(NestDepth != 0); - Str << ')'; - Column++; - NestDepth--; - NeedSpace = true; - } - void Break() - { - // Don't break if not needed. - if (Column != NestDepth) - { - if (NeedSpace) - { - ConsecOpens = 0; - } - else - { // Move hanging ( characters to the new line - Str.Truncate(Str.Len() - ConsecOpens); - NestDepth -= ConsecOpens; - } - Str << '\n'; - Column = NestDepth; - NeedSpace = false; - if (NestDepth > 0) - { - Str.AppendFormat("%*s", (int)NestDepth, ""); - } - if (ConsecOpens > 0) - { - for (size_t i = 0; i < ConsecOpens; ++i) - { - Str << '('; - } - NestDepth += ConsecOpens; - } - } - } - bool CheckWrap(size_t len) - { - if (len + Column > WrapWidth) - { - Break(); - return true; - } - return false; - } - void Add(const char *str, size_t len) - { - CheckWrap(len + NeedSpace); - if (NeedSpace) - { - Str << ' '; - } - Str.AppendCStrPart(str, len); - Column += len + NeedSpace; - NeedSpace = true; - } - void Add(const char *str) - { - Add(str, strlen(str)); - } - void Add(FString &str) - { - Add(str.GetChars(), str.Len()); - } - void AddName(FName name) - { - size_t namelen = strlen(name.GetChars()); - CheckWrap(namelen + 2 + NeedSpace); - if (NeedSpace) - { - NeedSpace = false; - Str << ' '; - } - Str << '\'' << name.GetChars() << '\''; - Column += namelen + 2 + NeedSpace; - NeedSpace = true; - } - void AddChar(char c) - { - Add(&c, 1); - } - void AddInt(int i, bool un=false) - { - char buf[16]; - size_t len; - if (!un) - { - len = mysnprintf(buf, countof(buf), "%d", i); - } - else - { - len = mysnprintf(buf, countof(buf), "%uu", i); - } - Add(buf, len); - } - void AddHex(unsigned x) - { - char buf[10]; - size_t len = mysnprintf(buf, countof(buf), "%08x", x); - Add(buf, len); - } - void AddFloat(double f, bool single) - { - char buf[32]; - size_t len = mysnprintf(buf, countof(buf), "%.4f", f); - if (single) - { - buf[len++] = 'f'; - buf[len] = '\0'; - } - Add(buf, len); - } -private: - FString Str; - size_t NestDepth; - size_t Column; - size_t WrapWidth; - size_t ConsecOpens; - bool NeedSpace; -}; - -static void PrintNode(FLispString &out, ZCC_TreeNode *node) -{ - assert(TreeNodePrinter[NUM_AST_NODE_TYPES-1] != NULL); - if (node->NodeType >= 0 && node->NodeType < NUM_AST_NODE_TYPES) - { - TreeNodePrinter[node->NodeType](out, node); - } - else - { - out.Open("unknown-node-type"); - out.AddInt(node->NodeType); - out.Close(); - } -} - -static void PrintNodes(FLispString &out, ZCC_TreeNode *node, bool newlist=true, bool addbreaks=false) -{ - ZCC_TreeNode *p; - - if (node == NULL) - { - out.Add("nil", 3); - } - else - { - if (newlist) - { - out.Open(NULL); - } - p = node; - do - { - if (addbreaks) - { - out.Break(); - } - PrintNode(out, p); - p = p->SiblingNext; - } while (p != node); - if (newlist) - { - out.Close(); - } - } -} - -static void PrintBuiltInType(FLispString &out, EZCCBuiltinType type) -{ - assert(ZCC_NUM_BUILT_IN_TYPES == countof(BuiltInTypeNames)); - if (unsigned(type) >= unsigned(ZCC_NUM_BUILT_IN_TYPES)) - { - char buf[30]; - size_t len = mysnprintf(buf, countof(buf), "bad-type-%u", type); - out.Add(buf, len); - } - else - { - out.Add(BuiltInTypeNames[type]); - } -} - -static void PrintIdentifier(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Identifier *inode = (ZCC_Identifier *)node; - out.Open("identifier"); - out.AddName(inode->Id); - out.Close(); -} - -static void PrintStringConst(FLispString &out, FString str) -{ - FString outstr; - outstr << '"'; - for (size_t i = 0; i < str.Len(); ++i) - { - if (str[i] == '"') - { - outstr << "\""; - } - else if (str[i] == '\\') - { - outstr << "\\\\"; - } - else if (str[i] >= 32) - { - outstr << str[i]; - } - else - { - outstr.AppendFormat("\\x%02X", str[i]); - } - } - outstr << '"'; - out.Add(outstr); -} - -static void PrintClass(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Class *cnode = (ZCC_Class *)node; - out.Break(); - out.Open("class"); - out.AddName(cnode->NodeName); - PrintNodes(out, cnode->ParentName); - PrintNodes(out, cnode->Replaces); - out.AddHex(cnode->Flags); - PrintNodes(out, cnode->Body, false, true); - out.Close(); -} - -static void PrintStruct(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Struct *snode = (ZCC_Struct *)node; - out.Break(); - out.Open("struct"); - out.AddName(snode->NodeName); - PrintNodes(out, snode->Body, false, true); - out.Close(); -} - -static void PrintProperty(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Property *snode = (ZCC_Property *)node; - out.Break(); - out.Open("property"); - out.AddName(snode->NodeName); - PrintNodes(out, snode->Body, false, true); - out.Close(); -} - -static void PrintFlagDef(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_FlagDef *snode = (ZCC_FlagDef *)node; - out.Break(); - out.Open("flagdef"); - out.AddName(snode->NodeName); - out.AddName(snode->RefName); - out.AddInt(snode->BitValue); - out.Close(); -} - -static void PrintStaticArrayState(FLispString &out, ZCC_TreeNode *node) -{ - auto *snode = (ZCC_StaticArrayStatement *)node; - out.Break(); - out.Open("static-array"); - out.AddName(snode->Id); - PrintNodes(out, snode->Values, false, true); - out.Close(); -} - -static void PrintEnum(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Enum *enode = (ZCC_Enum *)node; - out.Break(); - out.Open("enum"); - out.AddName(enode->NodeName); - PrintBuiltInType(out, enode->EnumType); - out.Add(enode->Elements == NULL ? "nil" : "...", 3); - out.Close(); -} - -static void PrintEnumTerminator(FLispString &out, ZCC_TreeNode *node) -{ - out.Open("enum-term"); - out.Close(); -} - -static void PrintStates(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_States *snode = (ZCC_States *)node; - out.Break(); - out.Open("states"); - PrintNodes(out, snode->Flags, false, true); - PrintNodes(out, snode->Body, false, true); - out.Close(); -} - -static void PrintStatePart(FLispString &out, ZCC_TreeNode *node) -{ - out.Open("state-part"); - out.Close(); -} - -static void PrintStateLabel(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_StateLabel *snode = (ZCC_StateLabel *)node; - out.Open("state-label"); - out.AddName(snode->Label); - out.Close(); -} - -static void PrintStateStop(FLispString &out, ZCC_TreeNode *node) -{ - out.Open("state-stop"); - out.Close(); -} - -static void PrintStateWait(FLispString &out, ZCC_TreeNode *node) -{ - out.Open("state-wait"); - out.Close(); -} - -static void PrintStateFail(FLispString &out, ZCC_TreeNode *node) -{ - out.Open("state-fail"); - out.Close(); -} - -static void PrintStateLoop(FLispString &out, ZCC_TreeNode *node) -{ - out.Open("state-loop"); - out.Close(); -} - -static void PrintStateGoto(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_StateGoto *snode = (ZCC_StateGoto *)node; - out.Open("state-goto"); - PrintNodes(out, snode->Qualifier); - PrintNodes(out, snode->Label); - PrintNodes(out, snode->Offset); - out.Close(); -} - -static void PrintStateLine(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_StateLine *snode = (ZCC_StateLine *)node; - out.Open("state-line"); - out.Add(*(snode->Sprite)); - PrintNodes(out, snode->Duration); - if (snode->bNoDelay) out.Add("nodelay", 7); - if (snode->bBright) out.Add("bright", 6); - if (snode->bFast) out.Add("fast", 4); - if (snode->bSlow) out.Add("slow", 4); - if (snode->bCanRaise) out.Add("canraise", 8); - out.Add(*(snode->Frames)); - PrintNodes(out, snode->Offset); - PrintNodes(out, snode->Action, false); - out.Close(); -} - -static void PrintVarName(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_VarName *vnode = (ZCC_VarName *)node; - out.Open("var-name"); - PrintNodes(out, vnode->ArraySize); - out.AddName(vnode->Name); - out.Close(); -} - -static void PrintVarInit(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_VarInit *vnode = (ZCC_VarInit *)node; - out.Open("var-init"); - PrintNodes(out, vnode->ArraySize); - PrintNodes(out, vnode->Init); - if (vnode->InitIsArray) out.Add("array", 5); - out.AddName(vnode->Name); - out.Close(); -} - -static void PrintType(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Type *tnode = (ZCC_Type *)node; - out.Open("bad-type"); - PrintNodes(out, tnode->ArraySize); - out.Close(); -} - -static void PrintBasicType(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_BasicType *tnode = (ZCC_BasicType *)node; - out.Open("basic-type"); - PrintNodes(out, tnode->ArraySize); - PrintBuiltInType(out, tnode->Type); - if (tnode->Type == ZCC_UserType || tnode->Type == ZCC_NativeType) - { - if (tnode->Type == ZCC_NativeType) out.Add("@", 1); - PrintNodes(out, tnode->UserType, false); - } - out.Close(); -} - -static void PrintMapType(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_MapType *tnode = (ZCC_MapType *)node; - out.Open("map-type"); - PrintNodes(out, tnode->ArraySize); - PrintNodes(out, tnode->KeyType); - PrintNodes(out, tnode->ValueType); - out.Close(); -} - -static void PrintDynArrayType(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_DynArrayType *tnode = (ZCC_DynArrayType *)node; - out.Open("dyn-array-type"); - PrintNodes(out, tnode->ArraySize); - PrintNodes(out, tnode->ElementType); - out.Close(); -} - -static void PrintClassType(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ClassType *tnode = (ZCC_ClassType *)node; - out.Open("class-type"); - PrintNodes(out, tnode->ArraySize); - PrintNodes(out, tnode->Restriction); - out.Close(); -} - -static void OpenExprType(FLispString &out, EZCCExprType type) -{ - char buf[32]; - - if (unsigned(type) < PEX_COUNT_OF) - { - mysnprintf(buf, countof(buf), "expr %d", type); - } - else - { - mysnprintf(buf, countof(buf), "bad-pex-%u", type); - } - out.Open(buf); -} - -static void PrintExpression(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Expression *enode = (ZCC_Expression *)node; - OpenExprType(out, enode->Operation); - out.Close(); -} - -static void PrintExprID(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprID *enode = (ZCC_ExprID *)node; - assert(enode->Operation == PEX_ID); - out.Open("expr-id"); - out.AddName(enode->Identifier); - out.Close(); -} - -static void PrintExprTypeRef(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprTypeRef *enode = (ZCC_ExprTypeRef *)node; - assert(enode->Operation == PEX_TypeRef); - out.Open("expr-type-ref"); - if (enode->RefType == TypeSInt8) { out.Add("sint8"); } - else if (enode->RefType == TypeUInt8) { out.Add("uint8"); } - else if (enode->RefType == TypeSInt16) { out.Add("sint16"); } - else if (enode->RefType == TypeSInt32) { out.Add("sint32"); } - else if (enode->RefType == TypeFloat32) { out.Add("float32"); } - else if (enode->RefType == TypeFloat64) { out.Add("float64"); } - else if (enode->RefType == TypeString) { out.Add("string"); } - else if (enode->RefType == TypeName) { out.Add("name"); } - else if (enode->RefType == TypeColor) { out.Add("color"); } - else if (enode->RefType == TypeSound) { out.Add("sound"); } - else { out.Add("other"); } - out.Close(); -} - -static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprConstant *enode = (ZCC_ExprConstant *)node; - assert(enode->Operation == PEX_ConstValue); - out.Open("expr-const"); - if (enode->Type == TypeString) - { - PrintStringConst(out, *enode->StringVal); - } - else if (enode->Type == TypeFloat64) - { - out.AddFloat(enode->DoubleVal, false); - } - else if (enode->Type == TypeFloat32) - { - out.AddFloat(enode->DoubleVal, true); - } - else if (enode->Type == TypeName) - { - out.AddName(ENamedName(enode->IntVal)); - } - else if (enode->Type->isIntCompatible()) - { - out.AddInt(enode->IntVal, static_cast(enode->Type)->Unsigned); - } - out.Close(); -} - -static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprFuncCall *enode = (ZCC_ExprFuncCall *)node; - assert(enode->Operation == PEX_FuncCall); - out.Open("expr-func-call"); - PrintNodes(out, enode->Function); - PrintNodes(out, enode->Parameters, false); - out.Close(); -} - -static void PrintExprClassCast(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ClassCast *enode = (ZCC_ClassCast *)node; - assert(enode->Operation == PEX_ClassCast); - out.Open("expr-class-cast"); - out.AddName(enode->ClassName); - PrintNodes(out, enode->Parameters, false); - out.Close(); -} - -static void PrintStaticArray(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_StaticArrayStatement *enode = (ZCC_StaticArrayStatement *)node; - out.Open("static-array-stmt"); - PrintNodes(out, enode->Type, false); - out.AddName(enode->Id); - PrintNodes(out, enode->Values, false); - out.Close(); -} - -static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; - assert(enode->Operation == PEX_MemberAccess); - out.Open("expr-member-access"); - PrintNodes(out, enode->Left); - out.AddName(enode->Right); - out.Close(); -} - -static void PrintExprUnary(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprUnary *enode = (ZCC_ExprUnary *)node; - OpenExprType(out, enode->Operation); - PrintNodes(out, enode->Operand, false); - out.Close(); -} - -static void PrintExprBinary(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprBinary *enode = (ZCC_ExprBinary *)node; - OpenExprType(out, enode->Operation); - PrintNodes(out, enode->Left); - PrintNodes(out, enode->Right); - out.Close(); -} - -static void PrintExprTrinary(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExprTrinary *enode = (ZCC_ExprTrinary *)node; - OpenExprType(out, enode->Operation); - PrintNodes(out, enode->Test); - PrintNodes(out, enode->Left); - PrintNodes(out, enode->Right); - out.Close(); -} - -static void PrintVectorInitializer(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_VectorValue *enode = (ZCC_VectorValue *)node; - OpenExprType(out, enode->Operation); - PrintNodes(out, enode->X); - PrintNodes(out, enode->Y); - PrintNodes(out, enode->Z); - out.Close(); -} - -static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_FuncParm *pnode = (ZCC_FuncParm *)node; - out.Break(); - out.Open("func-parm"); - out.AddName(pnode->Label); - PrintNodes(out, pnode->Value, false); - out.Close(); -} - -static void PrintStatement(FLispString &out, ZCC_TreeNode *node) -{ - out.Open("statement"); - out.Close(); -} - -static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node; - out.Break(); - out.Open("compound-stmt"); - PrintNodes(out, snode->Content, false, true); - out.Close(); -} - -static void PrintDefault(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Default *snode = (ZCC_Default *)node; - out.Break(); - out.Open("default"); - PrintNodes(out, snode->Content, false, true); - out.Close(); -} - -static void PrintContinueStmt(FLispString &out, ZCC_TreeNode *node) -{ - out.Break(); - out.Open("continue-stmt"); - out.Close(); -} - -static void PrintBreakStmt(FLispString &out, ZCC_TreeNode *node) -{ - out.Break(); - out.Open("break-stmt"); - out.Close(); -} - -static void PrintReturnStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node; - out.Break(); - out.Open("return-stmt"); - PrintNodes(out, snode->Values, false); - out.Close(); -} - -static void PrintExpressionStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node; - out.Break(); - out.Open("expression-stmt"); - PrintNodes(out, snode->Expression, false); - out.Close(); -} - -static void PrintIterationStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_IterationStmt *snode = (ZCC_IterationStmt *)node; - out.Break(); - out.Open("iteration-stmt"); - out.Add((snode->CheckAt == ZCC_IterationStmt::Start) ? "start" : "end"); - out.Break(); - PrintNodes(out, snode->LoopCondition); - out.Break(); - PrintNodes(out, snode->LoopBumper); - out.Break(); - PrintNodes(out, snode->LoopStatement); - out.Close(); -} - -static void PrintIfStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_IfStmt *snode = (ZCC_IfStmt *)node; - out.Break(); - out.Open("if-stmt"); - PrintNodes(out, snode->Condition); - out.Break(); - PrintNodes(out, snode->TruePath); - out.Break(); - PrintNodes(out, snode->FalsePath); - out.Close(); -} - -static void PrintSwitchStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_SwitchStmt *snode = (ZCC_SwitchStmt *)node; - out.Break(); - out.Open("switch-stmt"); - PrintNodes(out, snode->Condition); - out.Break(); - PrintNodes(out, snode->Content, false); - out.Close(); -} - -static void PrintCaseStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node; - out.Break(); - out.Open("case-stmt"); - PrintNodes(out, snode->Condition, false); - out.Close(); -} - -static void BadAssignOp(FLispString &out, int op) -{ - char buf[32]; - size_t len = mysnprintf(buf, countof(buf), "assign-op-%d", op); - out.Add(buf, len); -} - -static void PrintAssignStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_AssignStmt *snode = (ZCC_AssignStmt *)node; - out.Open("assign-stmt"); - PrintNodes(out, snode->Dests); - PrintNodes(out, snode->Sources); - out.Close(); -} - -static void PrintLocalVarStmt(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node; - out.Open("local-var-stmt"); - PrintNodes(out, snode->Type); - PrintNodes(out, snode->Vars); - out.Close(); -} - -static void PrintFuncParamDecl(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_FuncParamDecl *dnode = (ZCC_FuncParamDecl *)node; - out.Break(); - out.Open("func-param-decl"); - PrintNodes(out, dnode->Type); - out.AddName(dnode->Name); - out.AddHex(dnode->Flags); - PrintNodes(out, dnode->Default); - out.Close(); -} - -static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node; - out.Break(); - out.Open("constant-def"); - out.AddName(dnode->NodeName); - PrintNodes(out, dnode->Value, false); - out.Close(); -} - -static void PrintDeclarator(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_Declarator *dnode = (ZCC_Declarator *)node; - out.Break(); - out.Open("declarator"); - out.AddHex(dnode->Flags); - PrintNodes(out, dnode->Type); - out.Close(); -} - -static void PrintVarDeclarator(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node; - out.Break(); - out.Open("var-declarator"); - out.AddHex(dnode->Flags); - PrintNodes(out, dnode->Type); - PrintNodes(out, dnode->Names); - out.Close(); -} - -static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node) -{ - ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node; - out.Break(); - out.Open("func-declarator"); - out.AddHex(dnode->Flags); - PrintNodes(out, dnode->UseFlags); - PrintNodes(out, dnode->Type); - out.AddName(dnode->Name); - PrintNodes(out, dnode->Params); - PrintNodes(out, dnode->Body, false); - out.Close(); -} - -static void PrintDeclFlags(FLispString &out, ZCC_TreeNode *node) -{ - auto dnode = (ZCC_DeclFlags *)node; - out.Break(); - out.Open("decl-flags"); - out.AddHex(dnode->Flags); - PrintNodes(out, dnode->Id); - out.Close(); -} - -static void PrintFlagStmt(FLispString &out, ZCC_TreeNode *node) -{ - auto dnode = (ZCC_FlagStmt *)node; - out.Break(); - out.Open("flag-stmt"); - PrintNodes(out, dnode->name, false); - out.AddInt(dnode->set); - out.Close(); -} - -static void PrintPropertyStmt(FLispString &out, ZCC_TreeNode *node) -{ - auto dnode = (ZCC_PropertyStmt *)node; - out.Break(); - out.Open("property-stmt"); - PrintNodes(out, dnode->Prop, false); - PrintNodes(out, dnode->Values, false); - out.Close(); -} - -void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *) = -{ - PrintIdentifier, - PrintClass, - PrintStruct, - PrintEnum, - PrintEnumTerminator, - PrintStates, - PrintStatePart, - PrintStateLabel, - PrintStateStop, - PrintStateWait, - PrintStateFail, - PrintStateLoop, - PrintStateGoto, - PrintStateLine, - PrintVarName, - PrintVarInit, - PrintType, - PrintBasicType, - PrintMapType, - PrintDynArrayType, - PrintClassType, - PrintExpression, - PrintExprID, - PrintExprTypeRef, - PrintExprConstant, - PrintExprFuncCall, - PrintExprMemberAccess, - PrintExprUnary, - PrintExprBinary, - PrintExprTrinary, - PrintFuncParam, - PrintStatement, - PrintCompoundStmt, - PrintContinueStmt, - PrintBreakStmt, - PrintReturnStmt, - PrintExpressionStmt, - PrintIterationStmt, - PrintIfStmt, - PrintSwitchStmt, - PrintCaseStmt, - PrintAssignStmt, - PrintLocalVarStmt, - PrintFuncParamDecl, - PrintConstantDef, - PrintDeclarator, - PrintVarDeclarator, - PrintFuncDeclarator, - PrintDefault, - PrintFlagStmt, - PrintPropertyStmt, - PrintVectorInitializer, - PrintDeclFlags, - PrintExprClassCast, - PrintStaticArrayState, - PrintProperty, - PrintFlagDef, -}; - -FString ZCC_PrintAST(ZCC_TreeNode *root) -{ - FLispString out; - PrintNodes(out, root); - return out; -} diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp deleted file mode 100644 index 26b4b73ca98..00000000000 --- a/src/scripting/zscript/zcc_compile.cpp +++ /dev/null @@ -1,4027 +0,0 @@ -/* -** zcc_compile.cpp -** -**--------------------------------------------------------------------------- -** Copyright -2016 Randy Heit -** Copyright 2016 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "a_pickups.h" -#include "thingdef.h" -#include "c_console.h" -#include "w_wad.h" -#include "zcc_parser.h" -#include "zcc-parse.h" -#include "zcc_compile.h" -#include "v_text.h" -#include "p_lnspec.h" -#include "v_video.h" - -FSharedStringArena VMStringConstants; -bool isActor(PContainerType *type); - - -static int GetIntConst(FxExpression *ex, FCompileContext &ctx) -{ - ex = new FxIntCast(ex, false); - ex = ex->Resolve(ctx); - return ex ? static_cast(ex)->GetValue().GetInt() : 0; -} - -static double GetFloatConst(FxExpression *ex, FCompileContext &ctx) -{ - ex = new FxFloatCast(ex); - ex = ex->Resolve(ctx); - return ex ? static_cast(ex)->GetValue().GetFloat() : 0; -} - -const char * ZCCCompiler::GetStringConst(FxExpression *ex, FCompileContext &ctx) -{ - ex = new FxStringCast(ex); - ex = ex->Resolve(ctx); - if (!ex) return ""; - // The string here must be stored in a persistent place that lasts long enough to have it processed. - return AST.Strings.Alloc(static_cast(ex)->GetValue().GetString())->GetChars(); -} - -int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls) -{ - FCompileContext ctx(OutNamespace, cls, false); - FxExpression *ex = new FxIntCast(ConvertNode(node), false); - ex = ex->Resolve(ctx); - if (ex == nullptr) return 0; - if (!ex->isConstant()) - { - ex->ScriptPosition.Message(MSG_ERROR, "Expression is not constant"); - return 0; - } - return static_cast(ex)->GetValue().GetInt(); -} - -FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls) -{ - FCompileContext ctx(OutNamespace, cls, false); - FxExpression *ex = new FxStringCast(ConvertNode(node)); - ex = ex->Resolve(ctx); - if (ex == nullptr) return ""; - if (!ex->isConstant()) - { - ex->ScriptPosition.Message(MSG_ERROR, "Expression is not constant"); - return ""; - } - return static_cast(ex)->GetValue().GetString(); -} - -ZCC_MixinDef *ZCCCompiler::ResolveMixinStmt(ZCC_MixinStmt *mixinStmt, EZCCMixinType type) -{ - for (auto mx : Mixins) - { - if (mx->mixin->NodeName == mixinStmt->MixinName) - { - if (mx->mixin->MixinType != type) - { - Error(mixinStmt, "Mixin %s is a %s mixin cannot be used here.", FName(mixinStmt->MixinName).GetChars(), GetMixinTypeString(type)); - return nullptr; - } - - return mx->mixin; - } - } - - Error(mixinStmt, "Mixin %s does not exist.", FName(mixinStmt->MixinName).GetChars()); - - return nullptr; -} - - -//========================================================================== -// -// ZCCCompiler :: ProcessClass -// -//========================================================================== - -void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) -{ - ZCC_ClassWork *cls = nullptr; - // If this is a class extension, put the new node directly into the existing class. - if (cnode->Flags == ZCC_Extension) - { - for (auto clss : Classes) - { - if (clss->NodeName() == cnode->NodeName) - { - cls = clss; - break; - } - } - if (cls == nullptr) - { - Error(cnode, "Class %s cannot be found in the current translation unit.", FName(cnode->NodeName).GetChars()); - return; - } - } - else - { - Classes.Push(new ZCC_ClassWork(static_cast(cnode), treenode)); - cls = Classes.Last(); - } - - auto node = cnode->Body; - PSymbolTreeNode *childnode; - ZCC_Enum *enumType = nullptr; - - // [pbeta] Handle mixins here for the sake of simplifying things. - if (node != nullptr) - { - bool mixinError = false; - TArray mixinStmts; - mixinStmts.Clear(); - - // Gather all mixin statement nodes. - do - { - if (node->NodeType == AST_MixinStmt) - { - mixinStmts.Push(static_cast(node)); - } - - node = node->SiblingNext; - } - while (node != cnode->Body); - - for (auto mixinStmt : mixinStmts) - { - ZCC_MixinDef *mixinDef = ResolveMixinStmt(mixinStmt, ZCC_Mixin_Class); - - if (mixinDef == nullptr) - { - mixinError = true; - continue; - } - - // Insert the mixin if there's a body. If not, just remove this node. - if (mixinDef->Body != nullptr) - { - auto newNode = TreeNodeDeepCopy(&AST, mixinDef->Body, true); - - if (mixinStmt->SiblingNext != mixinStmt && mixinStmt->SiblingPrev != mixinStmt) - { - auto prevSibling = mixinStmt->SiblingPrev; - auto nextSibling = mixinStmt->SiblingNext; - - auto newFirst = newNode; - auto newLast = newNode->SiblingPrev; - - newFirst->SiblingPrev = prevSibling; - newLast->SiblingNext = nextSibling; - - prevSibling->SiblingNext = newFirst; - nextSibling->SiblingPrev = newLast; - } - - if (cnode->Body == mixinStmt) - { - cnode->Body = newNode; - } - } - else - { - if (mixinStmt->SiblingNext != mixinStmt && mixinStmt->SiblingPrev != mixinStmt) - { - auto prevSibling = mixinStmt->SiblingPrev; - auto nextSibling = mixinStmt->SiblingNext; - - prevSibling->SiblingNext = nextSibling; - nextSibling->SiblingPrev = prevSibling; - - if (cnode->Body == mixinStmt) - { - cnode->Body = nextSibling; - } - } - else if (cnode->Body == mixinStmt) - { - cnode->Body = nullptr; - } - } - } - - mixinStmts.Clear(); - - if (mixinError) - { - return; - } - } - - node = cnode->Body; - - // Need to check if the class actually has a body. - if (node != nullptr) do - { - switch (node->NodeType) - { - case AST_MixinStmt: - assert(0 && "Unhandled mixin statement in class parsing loop. If this has been reached, something is seriously wrong"); - Error(node, "Internal mixin error."); - break; - - case AST_Struct: - case AST_ConstantDef: - case AST_Enum: - if ((childnode = AddTreeNode(static_cast(node)->NodeName, node, &cls->TreeNodes))) - { - switch (node->NodeType) - { - case AST_Enum: - enumType = static_cast(node); - cls->Enums.Push(enumType); - break; - - case AST_Struct: - if (static_cast(node)->Flags & VARF_Native) - { - Error(node, "Cannot define native structs inside classes"); - static_cast(node)->Flags &= ~VARF_Native; - } - ProcessStruct(static_cast(node), childnode, cls->cls); - break; - - case AST_ConstantDef: - cls->Constants.Push(static_cast(node)); - cls->Constants.Last()->Type = enumType; - break; - - default: - assert(0 && "Default case is just here to make GCC happy. It should never be reached"); - } - } - break; - - case AST_Property: - cls->Properties.Push(static_cast(node)); - break; - - case AST_FlagDef: - cls->FlagDefs.Push(static_cast(node)); - break; - - case AST_VarDeclarator: - cls->Fields.Push(static_cast(node)); - break; - - case AST_EnumTerminator: - enumType = nullptr; - break; - - case AST_States: - cls->States.Push(static_cast(node)); - break; - - case AST_FuncDeclarator: - cls->Functions.Push(static_cast(node)); - break; - - case AST_Default: - cls->Defaults.Push(static_cast(node)); - break; - - case AST_StaticArrayStatement: - if (AddTreeNode(static_cast(node)->Id, node, &cls->TreeNodes)) - { - cls->Arrays.Push(static_cast(node)); - } - break; - - default: - assert(0 && "Unhandled AST node type"); - break; - } - - node = node->SiblingNext; - } - while (node != cnode->Body); -} - -//========================================================================== -// -// ZCCCompiler :: ProcessMixin -// -//========================================================================== - -void ZCCCompiler::ProcessMixin(ZCC_MixinDef *cnode, PSymbolTreeNode *treenode) -{ - ZCC_MixinWork *cls = new ZCC_MixinWork(cnode, treenode); - - auto node = cnode->Body; - - // Need to check if the mixin actually has a body. - if (node != nullptr) do - { - if (cnode->MixinType == ZCC_Mixin_Class) - { - switch (node->NodeType) - { - case AST_Struct: - case AST_ConstantDef: - case AST_Enum: - case AST_Property: - case AST_FlagDef: - case AST_VarDeclarator: - case AST_EnumTerminator: - case AST_States: - case AST_FuncDeclarator: - case AST_Default: - case AST_StaticArrayStatement: - break; - - default: - assert(0 && "Unhandled AST node type"); - break; - } - } - - node = node->SiblingNext; - } while (node != cnode->Body); - - Mixins.Push(cls); -} - -//========================================================================== -// -// ZCCCompiler :: ProcessStruct -// -//========================================================================== - -void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZCC_Class *outer) -{ - Structs.Push(new ZCC_StructWork(static_cast(cnode), treenode, outer)); - ZCC_StructWork *cls = Structs.Last(); - - auto node = cnode->Body; - PSymbolTreeNode *childnode; - ZCC_Enum *enumType = nullptr; - - // Need to check if the struct actually has a body. - if (node != nullptr) do - { - switch (node->NodeType) - { - case AST_ConstantDef: - case AST_Enum: - if ((childnode = AddTreeNode(static_cast(node)->NodeName, node, &cls->TreeNodes))) - { - switch (node->NodeType) - { - case AST_Enum: - enumType = static_cast(node); - cls->Enums.Push(enumType); - break; - - case AST_ConstantDef: - cls->Constants.Push(static_cast(node)); - cls->Constants.Last()->Type = enumType; - break; - - default: - assert(0 && "Default case is just here to make GCC happy. It should never be reached"); - } - } - break; - - case AST_VarDeclarator: - cls->Fields.Push(static_cast(node)); - break; - - case AST_FuncDeclarator: - cls->Functions.Push(static_cast(node)); - break; - - case AST_EnumTerminator: - enumType = nullptr; - break; - - case AST_StaticArrayStatement: - if (AddTreeNode(static_cast(node)->Id, node, &cls->TreeNodes)) - { - cls->Arrays.Push(static_cast(node)); - } - break; - - default: - assert(0 && "Unhandled AST node type"); - break; - } - node = node->SiblingNext; - } - while (node != cnode->Body); -} - -//========================================================================== -// -// ZCCCompiler Constructor -// -//========================================================================== - -ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PNamespace *_outnamespc, int lumpnum, const VersionInfo &ver) - : mVersion(ver), Outer(_outer), ConvertClass(nullptr), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), Lump(lumpnum) -{ - FScriptPosition::ResetErrorCounter(); - // Group top-level nodes by type - if (ast.TopNode != NULL) - { - ZCC_TreeNode *node = ast.TopNode; - PSymbolTreeNode *tnode; - - // [pbeta] Anything that must be processed before classes, structs, etc. should go here. - do - { - switch (node->NodeType) - { - // [pbeta] Mixins must be processed before everything else. - case AST_MixinDef: - if ((tnode = AddTreeNode(static_cast(node)->NodeName, node, GlobalTreeNodes))) - { - ProcessMixin(static_cast(node), tnode); - break; - } - break; - - default: - break; // Shut GCC up. - } - node = node->SiblingNext; - } while (node != ast.TopNode); - - node = ast.TopNode; - PType *enumType = nullptr; - ZCC_Enum *zenumType = nullptr; - - do - { - switch (node->NodeType) - { - case AST_MixinDef: - // [pbeta] We already processed mixins, ignore them here. - break; - - case AST_Class: - // a class extension should not check the tree node symbols. - if (static_cast(node)->Flags == ZCC_Extension) - { - ProcessClass(static_cast(node), tnode); - break; - } - case AST_Struct: - case AST_ConstantDef: - case AST_Enum: - if ((tnode = AddTreeNode(static_cast(node)->NodeName, node, GlobalTreeNodes))) - { - switch (node->NodeType) - { - case AST_Enum: - zenumType = static_cast(node); - enumType = NewEnum(zenumType->NodeName, OutNamespace); - OutNamespace->Symbols.AddSymbol(Create(zenumType->NodeName, enumType)); - break; - - case AST_Class: - ProcessClass(static_cast(node), tnode); - break; - - case AST_Struct: - ProcessStruct(static_cast(node), tnode, nullptr); - break; - - case AST_ConstantDef: - Constants.Push(static_cast(node)); - Constants.Last()->Type = zenumType; - break; - - default: - assert(0 && "Default case is just here to make GCC happy. It should never be reached"); - } - } - break; - - case AST_EnumTerminator: - zenumType = nullptr; - break; - - default: - assert(0 && "Unhandled AST node type"); - break; - } - node = node->SiblingNext; - } while (node != ast.TopNode); - } -} - -ZCCCompiler::~ZCCCompiler() -{ - for (auto s : Structs) - { - delete s; - } - for (auto c : Classes) - { - delete c; - } - Structs.Clear(); - Classes.Clear(); -} - -//========================================================================== -// -// ZCCCompiler :: AddTreeNode -// -// Keeps track of definition nodes by their names. Ensures that all names -// in this scope are unique. -// -//========================================================================== - -PSymbolTreeNode *ZCCCompiler::AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents) -{ - PSymbol *check = treenodes->FindSymbol(name, searchparents); - if (check != NULL) - { - assert(check->IsA(RUNTIME_CLASS(PSymbolTreeNode))); - Error(node, "Attempt to redefine '%s'", name.GetChars()); - Error(static_cast(check)->Node, " Original definition is here"); - return nullptr; - } - else - { - auto sy = Create(name, node); - FString name; - treenodes->AddSymbol(sy); - return sy; - } -} - -//========================================================================== -// -// ZCCCompiler :: Warn -// -// Prints a warning message, and increments WarnCount. -// -//========================================================================== - -void ZCCCompiler::Warn(ZCC_TreeNode *node, const char *msg, ...) -{ - va_list argptr; - va_start(argptr, msg); - MessageV(node, TEXTCOLOR_ORANGE, msg, argptr); - va_end(argptr); - - FScriptPosition::WarnCounter++; -} - -//========================================================================== -// -// ZCCCompiler :: Error -// -// Prints an error message, and increments ErrorCount. -// -//========================================================================== - -void ZCCCompiler::Error(ZCC_TreeNode *node, const char *msg, ...) -{ - va_list argptr; - va_start(argptr, msg); - MessageV(node, TEXTCOLOR_RED, msg, argptr); - va_end(argptr); - - FScriptPosition::ErrorCounter++; -} - -//========================================================================== -// -// ZCCCompiler :: MessageV -// -// Prints a message, annotated with the source location for the tree node. -// -//========================================================================== - -void ZCCCompiler::MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr) -{ - FString composed; - - composed.Format("%s%s, line %d: ", txtcolor, node->SourceName->GetChars(), node->SourceLoc); - composed.VAppendFormat(msg, argptr); - composed += '\n'; - PrintString(PRINT_HIGH, composed); -} - -//========================================================================== -// -// ZCCCompiler :: Compile -// -// Compile everything defined at this level. -// -//========================================================================== - -int ZCCCompiler::Compile() -{ - CreateClassTypes(); - CreateStructTypes(); - CompileAllConstants(); - CompileAllFields(); - CompileAllProperties(); - InitDefaults(); - InitFunctions(); - CompileStates(); - return FScriptPosition::ErrorCounter; -} - -//========================================================================== -// -// ZCCCompiler :: CreateStructTypes -// -// Creates a PStruct for every struct. -// -//========================================================================== - -void ZCCCompiler::CreateStructTypes() -{ - for(auto s : Structs) - { - PTypeBase *outer; - PSymbolTable *syms; - - s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); - if (s->Outer) - { - outer = s->Outer->VMType; - syms = &s->Outer->VMType->Symbols; - } - else - { - outer = OutNamespace; - syms = &OutNamespace->Symbols; - } - - if (s->NodeName() == NAME__ && Wads.GetLumpFile(Lump) == 0) - { - // This is just a container for syntactic purposes. - s->strct->Type = nullptr; - continue; - } - else if (s->strct->Flags & ZCC_Native) - { - s->strct->Type = NewStruct(s->NodeName(), outer, true); - } - else - { - s->strct->Type = NewStruct(s->NodeName(), outer); - } - if (s->strct->Flags & ZCC_Version) - { - s->strct->Type->mVersion = s->strct->Version; - } - - auto &sf = s->Type()->ScopeFlags; - if (mVersion >= MakeVersion(2, 4, 0)) - { - if ((s->strct->Flags & (ZCC_UIFlag | ZCC_Play)) == (ZCC_UIFlag | ZCC_Play)) - { - Error(s->strct, "Struct %s has incompatible flags", s->NodeName().GetChars()); - } - - if (outer != OutNamespace) sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::SideFromObjectFlags(static_cast(outer)->ScopeFlags)); - else if (s->strct->Flags & ZCC_ClearScope) Warn(s->strct, "Useless 'ClearScope' on struct %s not inside a class", s->NodeName().GetChars()); - if (s->strct->Flags & ZCC_UIFlag) - sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::Side_UI); - if (s->strct->Flags & ZCC_Play) - sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::Side_Play); - if (s->strct->Flags & ZCC_ClearScope) - sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::Side_PlainData); // don't inherit the scope from the outer class - } - else - { - // old versions force 'play'. - sf = FScopeBarrier::ChangeSideInObjectFlags(sf, FScopeBarrier::Side_Play); - } - s->strct->Symbol = Create(s->NodeName(), s->Type()); - syms->AddSymbol(s->strct->Symbol); - - for (auto e : s->Enums) - { - auto etype = NewEnum(e->NodeName, s->Type()); - s->Type()->Symbols.AddSymbol(Create(e->NodeName, etype)); - } - } -} - -//========================================================================== -// -// ZCCCompiler :: CreateClassTypes -// -// Creates a PClass for every class so that we get access to the symbol table -// These will be created with unknown size because for that we need to -// process all fields first, but to do that we need the PClass and some -// other info depending on the PClass. -// -//========================================================================== - -void ZCCCompiler::CreateClassTypes() -{ - // we are going to sort the classes array so that entries are sorted in order of inheritance. - - auto OrigClasses = std::move(Classes); - Classes.Clear(); - bool donesomething = true; - while (donesomething) - { - donesomething = false; - for (unsigned i = 0; icls->ParentName; - - if (ParentName != nullptr && ParentName->SiblingNext == ParentName) parent = PClass::FindClass(ParentName->Id); - else if (ParentName == nullptr) parent = RUNTIME_CLASS(DObject); - else - { - // The parent is a dotted name which the type system currently does not handle. - // Once it does this needs to be implemented here. - auto p = ParentName; - FString build; - - do - { - if (build.IsNotEmpty()) build += '.'; - build += FName(p->Id); - p = static_cast(p->SiblingNext); - } while (p != ParentName); - Error(c->cls, "Qualified name '%s' for base class not supported in '%s'", build.GetChars(), FName(c->NodeName()).GetChars()); - parent = RUNTIME_CLASS(DObject); - } - - if (parent != nullptr && (parent->VMType != nullptr || c->NodeName() == NAME_Object)) - { - // The parent exists, we may create a type for this class - if (c->cls->Flags & ZCC_Native) - { - // If this is a native class, its own type must also already exist and not be a runtime class. - auto me = PClass::FindClass(c->NodeName()); - if (me == nullptr) - { - Error(c->cls, "Unknown native class %s", c->NodeName().GetChars()); - // Create a placeholder so that the compiler can continue looking for errors. - me = parent->FindClassTentative(c->NodeName()); - } - else if (me->bRuntimeClass) - { - Error(c->cls, "%s is not a native class", c->NodeName().GetChars()); - } - else - { - DPrintf(DMSG_SPAMMY, "Registered %s as native with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars()); - } - c->cls->Type = NewClassType(me); - me->SourceLumpName = *c->cls->SourceName; - } - else - { - // We will never get here if the name is a duplicate, so we can just do the assignment. - try - { - if (parent->VMType->mVersion > mVersion) - { - Error(c->cls, "Parent class %s of %s not accessible to ZScript version %d.%d.%d", parent->TypeName.GetChars(), c->NodeName().GetChars(), mVersion.major, mVersion.minor, mVersion.revision); - } - auto newclass = parent->CreateDerivedClass(c->NodeName(), TentativeClass); - if (newclass == nullptr) - { - Error(c->cls, "Class name %s already exists", c->NodeName().GetChars()); - } - else - { - c->cls->Type = NewClassType(newclass); - DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->ClassType()->ParentClass->TypeName.GetChars()); - } - } - catch (CRecoverableError &err) - { - Error(c->cls, "%s", err.GetMessage()); - c->cls->Type = nullptr; - } - } - if (c->Type() == nullptr) - { - // create a placeholder so that the compiler can continue looking for errors. - c->cls->Type = NewClassType(parent->FindClassTentative(c->NodeName())); - } - - if (c->cls->Flags & ZCC_Abstract) - c->ClassType()->bAbstract = true; - - if (c->cls->Flags & ZCC_Version) - { - c->Type()->mVersion = c->cls->Version; - } - // - if (mVersion >= MakeVersion(2, 4, 0)) - { - static int incompatible[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope }; - int incompatiblecnt = 0; - for (size_t k = 0; k < countof(incompatible); k++) - if (incompatible[k] & c->cls->Flags) incompatiblecnt++; - - if (incompatiblecnt > 1) - { - Error(c->cls, "Class %s has incompatible flags", c->NodeName().GetChars()); - } - - if (c->cls->Flags & ZCC_UIFlag) - c->Type()->ScopeFlags = EScopeFlags((c->Type()->ScopeFlags&~Scope_Play) | Scope_UI); - if (c->cls->Flags & ZCC_Play) - c->Type()->ScopeFlags = EScopeFlags((c->Type()->ScopeFlags&~Scope_UI) | Scope_Play); - if (parent->VMType->ScopeFlags & (Scope_UI | Scope_Play)) // parent is either ui or play - { - if (c->cls->Flags & (ZCC_UIFlag | ZCC_Play)) - { - Error(c->cls, "Can't change class scope in class %s", c->NodeName().GetChars()); - } - c->Type()->ScopeFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ScopeFlags, FScopeBarrier::SideFromObjectFlags(parent->VMType->ScopeFlags)); - } - } - else - { - c->Type()->ScopeFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ScopeFlags, FScopeBarrier::Side_Play); - } - - c->cls->Symbol = Create(c->NodeName(), c->Type()); - OutNamespace->Symbols.AddSymbol(c->cls->Symbol); - Classes.Push(c); - OrigClasses.Delete(i--); - donesomething = true; - } - else if (c->cls->ParentName != nullptr) - { - // No base class found. Now check if something in the unprocessed classes matches. - // If not, print an error. If something is found let's retry again in the next iteration. - bool found = false; - for (auto d : OrigClasses) - { - if (d->NodeName() == c->cls->ParentName->Id) - { - found = true; - break; - } - } - if (!found) - { - Error(c->cls, "Class %s has unknown base class %s", c->NodeName().GetChars(), FName(c->cls->ParentName->Id).GetChars()); - // create a placeholder so that the compiler can continue looking for errors. - c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName())); - c->cls->Symbol = Create(c->NodeName(), c->Type()); - OutNamespace->Symbols.AddSymbol(c->cls->Symbol); - Classes.Push(c); - OrigClasses.Delete(i--); - donesomething = true; - } - } - } - } - - // What's left refers to some other class in the list but could not be resolved. - // This normally means a circular reference. - for (auto c : OrigClasses) - { - Error(c->cls, "Class %s has circular inheritance", FName(c->NodeName()).GetChars()); - c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName())); - c->cls->Symbol = Create(c->NodeName(), c->Type()); - OutNamespace->Symbols.AddSymbol(c->cls->Symbol); - Classes.Push(c); - } - - // Last but not least: Now that all classes have been created, we can create the symbols for the internal enums and link the treenode symbol tables. - for (auto cd : Classes) - { - for (auto e : cd->Enums) - { - auto etype = NewEnum(e->NodeName, cd->Type()); - cd->Type()->Symbols.AddSymbol(Create(e->NodeName, etype)); - } - // Link the tree node tables. We only can do this after we know the class relations. - for (auto cc : Classes) - { - if (cc->ClassType() == cd->ClassType()->ParentClass) - { - cd->TreeNodes.SetParentTable(&cc->TreeNodes); - break; - } - } - } -} - -//========================================================================== -// -// ZCCCompiler :: AddConstants -// -// Helper for CompileAllConstants -// -//========================================================================== - -void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PContainerType *cls, PSymbolTable *ot) -{ - for (auto c : Constants) - { - dest.Push({ c, cls, ot }); - } -} - -//========================================================================== -// -// ZCCCompiler :: CompileAllConstants -// -// Make symbols from every constant defined at all levels. -// Since constants may only depend on other constants this can be done -// without any more involved processing of the AST as a first step. -// -//========================================================================== - -void ZCCCompiler::CompileAllConstants() -{ - // put all constants in one list to make resolving this easier. - TArray constantwork; - - CopyConstants(constantwork, Constants, nullptr, &OutNamespace->Symbols); - for (auto c : Classes) - { - CopyConstants(constantwork, c->Constants, c->Type(), &c->Type()->Symbols); - } - for (auto s : Structs) - { - if (s->Type() != nullptr) - CopyConstants(constantwork, s->Constants, s->Type(), &s->Type()->Symbols); - } - - // Before starting to resolve the list, let's create symbols for all already resolved ones first (i.e. all literal constants), to reduce work. - for (unsigned i = 0; iValue->NodeType == AST_ExprConstant) - { - AddConstant(constantwork[i]); - // Remove the constant from the list - constantwork.Delete(i); - i--; - } - } - bool donesomething = true; - // Now go through this list until no more constants can be resolved. The remaining ones will be non-constant values. - while (donesomething && constantwork.Size() > 0) - { - donesomething = false; - for (unsigned i = 0; i < constantwork.Size(); i++) - { - if (CompileConstant(&constantwork[i])) - { - AddConstant(constantwork[i]); - // Remove the constant from the list - constantwork.Delete(i); - i--; - donesomething = true; - } - } - } - for (unsigned i = 0; i < constantwork.Size(); i++) - { - Error(constantwork[i].node, "%s is not a constant", FName(constantwork[i].node->NodeName).GetChars()); - } - - - for (auto s : Structs) - { - CompileArrays(s); - } - for (auto c : Classes) - { - CompileArrays(c); - } -} - -//========================================================================== -// -// ZCCCompiler :: AddConstant -// -// Adds a constant to its assigned symbol table -// -//========================================================================== - -void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) -{ - auto def = constant.node; - auto val = def->Value; - ExpVal &c = constant.constval; - - // This is for literal constants. - if (val->NodeType == AST_ExprConstant) - { - ZCC_ExprConstant *cval = static_cast(val); - if (cval->Type == TypeString) - { - def->Symbol = Create(def->NodeName, *(cval->StringVal)); - } - else if (cval->Type->isInt()) - { - // How do we get an Enum type in here without screwing everything up??? - //auto type = def->Type != nullptr ? def->Type : cval->Type; - def->Symbol = Create(def->NodeName, cval->Type, cval->IntVal); - } - else if (cval->Type->isFloat()) - { - if (def->Type != nullptr) - { - Error(def, "Enum members must be integer values"); - } - def->Symbol = Create(def->NodeName, cval->Type, cval->DoubleVal); - } - else - { - Error(def->Value, "Bad type for constant definiton"); - def->Symbol = nullptr; - } - } - else - { - if (c.Type == TypeString) - { - def->Symbol = Create(def->NodeName, c.GetString()); - } - else if (c.Type->isInt()) - { - // How do we get an Enum type in here without screwing everything up??? - //auto type = def->Type != nullptr ? def->Type : cval->Type; - def->Symbol = Create(def->NodeName, c.Type, c.GetInt()); - } - else if (c.Type->isFloat()) - { - if (def->Type != nullptr) - { - Error(def, "Enum members must be integer values"); - } - def->Symbol = Create(def->NodeName, c.Type, c.GetFloat()); - } - else - { - Error(def->Value, "Bad type for constant definiton"); - def->Symbol = nullptr; - } - } - - if (def->Symbol == nullptr) - { - // Create a dummy constant so we don't make any undefined value warnings. - def->Symbol = Create(def->NodeName, TypeError, 0); - } - constant.Outputtable->ReplaceSymbol(def->Symbol); -} - -//========================================================================== -// -// ZCCCompiler :: CompileConstant -// -// For every constant definition, evaluate its value (which should result -// in a constant), and create a symbol for it. -// -//========================================================================== - -bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work) -{ - FCompileContext ctx(OutNamespace, work->cls, false); - FxExpression *exp = ConvertNode(work->node->Value); - try - { - FScriptPosition::errorout = true; - exp = exp->Resolve(ctx); - if (exp == nullptr) return false; - FScriptPosition::errorout = false; - if (!exp->isConstant()) - { - delete exp; - return false; - } - work->constval = static_cast(exp)->GetValue(); - delete exp; - return true; - } - catch (...) - { - // eat the reported error and treat this as a temorary failure. All unresolved contants will be reported at the end. - FScriptPosition::errorout = false; - return false; - } -} - - -void ZCCCompiler::CompileArrays(ZCC_StructWork *work) -{ - for(auto sas : work->Arrays) - { - PType *ztype = DetermineType(work->Type(), sas, sas->Id, sas->Type, false, true); - PType *ctype = ztype; - FArgumentList values; - - // Don't use narrow typea for casting. - if (ctype->isInt()) ctype = static_cast(ztype)->Unsigned ? TypeUInt32 : TypeSInt32; - else if (ctype == TypeFloat32) ctype = TypeFloat64; - - ConvertNodeList(values, sas->Values); - - bool fail = false; - FCompileContext ctx(OutNamespace, work->Type(), false); - - char *destmem = (char *)ClassDataAllocator.Alloc(values.Size() * ztype->Align); - memset(destmem, 0, values.Size() * ztype->Align); - char *copyp = destmem; - for (unsigned i = 0; i < values.Size(); i++) - { - values[i] = new FxTypeCast(values[i], ctype, false); - values[i] = values[i]->Resolve(ctx); - if (values[i] == nullptr) fail = true; - else if (!values[i]->isConstant()) - { - Error(sas, "Initializer must be constant"); - fail = true; - } - else - { - ExpVal val = static_cast(values[i])->GetValue(); - switch (ztype->GetRegType()) - { - default: - // should never happen - Error(sas, "Non-integral type in constant array"); - return; - - case REGT_INT: - ztype->SetValue(copyp, val.GetInt()); - break; - - case REGT_FLOAT: - ztype->SetValue(copyp, val.GetFloat()); - break; - - case REGT_POINTER: - *(void**)copyp = val.GetPointer(); - break; - - case REGT_STRING: - ::new(copyp) FString(val.GetString()); - break; - } - copyp += ztype->Align; - } - } - work->Type()->Symbols.AddSymbol(Create(sas->Id, NewArray(ztype, values.Size()), VARF_Static | VARF_ReadOnly, (size_t)destmem)); - } -} - -//========================================================================== -// -// ZCCCompiler :: NodeFromSymbol -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table) -{ - assert(sym != nullptr); - - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) - { - return NodeFromSymbolConst(static_cast(sym), source); - } - else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) - { - return NodeFromSymbolType(static_cast(sym), source); - } - return NULL; -} - -//========================================================================== -// -// ZCCCompiler :: NodeFromSymbolConst -// -// Returns a new AST constant node with the symbol's content. -// -//========================================================================== - -ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode) -{ - ZCC_ExprConstant *val = static_cast(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); - val->Operation = PEX_ConstValue; - if (sym == NULL) - { - val->Type = TypeError; - val->IntVal = 0; - } - else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) - { - val->StringVal = AST.Strings.Alloc(static_cast(sym)->Str); - val->Type = TypeString; - } - else - { - val->Type = sym->ValueType; - if (val->Type != TypeError) - { - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); - if (sym->ValueType->isIntCompatible()) - { - val->IntVal = static_cast(sym)->Value; - } - else - { - assert(sym->ValueType->isFloat()); - val->DoubleVal = static_cast(sym)->Float; - } - } - } - return val; -} - -//========================================================================== -// -// ZCCCompiler :: NodeFromSymbolType -// -// Returns a new AST type ref node with the symbol's content. -// -//========================================================================== - -ZCC_ExprTypeRef *ZCCCompiler::NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode) -{ - ZCC_ExprTypeRef *ref = static_cast(AST.InitNode(sizeof(*ref), AST_ExprTypeRef, idnode)); - ref->Operation = PEX_TypeRef; - ref->RefType = sym->Type; - ref->Type = NewClassPointer(RUNTIME_CLASS(DObject)); - return ref; -} - -//========================================================================== -// -// ZCCCompiler :: CompileAllFields -// -// builds the internal structure of all classes and structs -// -//========================================================================== -void AddActorInfo(PClass *cls); - -void ZCCCompiler::CompileAllFields() -{ - // Create copies of the arrays which can be altered - auto Classes = this->Classes; - auto Structs = this->Structs; - TMap HasNativeChildren; - - // first step: Look for native classes with native children. - // These may not have any variables added to them because it'd clash with the native definitions. - for (unsigned i = 0; i < Classes.Size(); i++) - { - auto c = Classes[i]; - - if (c->Type()->Size != TentativeClass && c->Fields.Size() > 0) - { - // We need to search the global class table here because not all children may have a scripted definition attached. - for (auto ac : PClass::AllClasses) - { - if (ac->ParentClass != nullptr && ac->ParentClass->VMType == c->Type() && ac->Size != TentativeClass) - { - // Only set a marker here, so that we can print a better message when the actual fields get added. - HasNativeChildren.Insert(c->Type()->TypeName, true); - break; - } - } - } - } - bool donesomething = true; - while (donesomething && (Structs.Size() > 0 || Classes.Size() > 0)) - { - donesomething = false; - for (unsigned i = 0; i < Structs.Size(); i++) - { - if (CompileFields(Structs[i]->Type(), Structs[i]->Fields, Structs[i]->Outer, Structs[i]->Type() == 0? GlobalTreeNodes : &Structs[i]->TreeNodes, true)) - { - // Remove from the list if all fields got compiled. - Structs.Delete(i--); - donesomething = true; - } - } - for (unsigned i = 0; i < Classes.Size(); i++) - { - auto type = Classes[i]->ClassType(); - - if (type->Size == TentativeClass) - { - if (type->ParentClass->Size == TentativeClass) - { - // we do not know the parent class's size yet, so skip this class for now. - continue; - } - else - { - // Inherit the size of the parent class - type->Size = Classes[i]->ClassType()->ParentClass->Size; - } - } - if (type->TypeName == NAME_Actor) - { - assert(type->MetaSize == 0); - AddActorInfo(type); // AActor needs the actor info manually added to its meta data before adding any scripted fields. - } - else if (Classes[i]->ClassType()->ParentClass) - type->MetaSize = Classes[i]->ClassType()->ParentClass->MetaSize; - else - type->MetaSize = 0; - - if (CompileFields(type->VMType, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type->TypeName))) - { - // Remove from the list if all fields got compiled. - Classes.Delete(i--); - donesomething = true; - } - } - } - // This really should never happen, but if it does, let's better print an error. - for (auto s : Structs) - { - Error(s->strct, "Unable to resolve all fields for struct %s", FName(s->NodeName()).GetChars()); - } - for (auto s : Classes) - { - Error(s->cls, "Unable to resolve all fields for class %s", FName(s->NodeName()).GetChars()); - } -} - -//========================================================================== -// -// ZCCCompiler :: CompileFields -// -// builds the internal structure of a single class or struct -// -//========================================================================== - -bool ZCCCompiler::CompileFields(PContainerType *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) -{ - while (Fields.Size() > 0) - { - auto field = Fields[0]; - FieldDesc *fd = nullptr; - - PType *fieldtype = DetermineType(type, field, field->Names->Name, field->Type, true, true); - - // For structs only allow 'deprecated', for classes exclude function qualifiers. - int notallowed = forstruct? - ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Meta | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope : - ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope; - - // Some internal fields need to be set to clearscope. - if (Wads.GetLumpFile(Lump) == 0) notallowed &= ~ZCC_ClearScope; - - if (field->Flags & notallowed) - { - Error(field, "Invalid qualifiers for %s (%s not allowed)", FName(field->Names->Name).GetChars(), FlagsToString(field->Flags & notallowed).GetChars()); - field->Flags &= notallowed; - } - uint32_t varflags = 0; - - // These map directly to implementation flags. - if (field->Flags & ZCC_Private) varflags |= VARF_Private; - if (field->Flags & ZCC_Protected) varflags |= VARF_Protected; - if (field->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; - if (field->Flags & ZCC_ReadOnly) varflags |= VARF_ReadOnly; - if (field->Flags & ZCC_Internal) varflags |= VARF_InternalAccess; - if (field->Flags & ZCC_Transient) varflags |= VARF_Transient; - if (mVersion >= MakeVersion(2, 4, 0)) - { - if (type != nullptr) - { - if (type->ScopeFlags & Scope_UI) - varflags |= VARF_UI; - if (type->ScopeFlags & Scope_Play) - varflags |= VARF_Play; - } - if (field->Flags & ZCC_UIFlag) - varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI); - if (field->Flags & ZCC_Play) - varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play); - if (field->Flags & ZCC_ClearScope) - varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData); - } - else - { - varflags |= VARF_Play; - } - - if (field->Flags & ZCC_Native) - { - varflags |= VARF_Native | VARF_Transient; - } - - static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope }; - int excludeflags = 0; - int fc = 0; - for (size_t i = 0; i < countof(excludescope); i++) - { - if (field->Flags & excludescope[i]) - { - fc++; - excludeflags |= excludescope[i]; - } - } - if (fc > 1) - { - Error(field, "Invalid combination of scope qualifiers %s on field %s", FlagsToString(excludeflags).GetChars(), FName(field->Names->Name).GetChars()); - varflags &= ~(VARF_UI | VARF_Play); // make plain data - } - - if (field->Flags & ZCC_Meta) - { - varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly - } - - if (field->Type->ArraySize != nullptr) - { - bool nosize; - fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, type, &nosize); - - if (nosize) - { - Error(field, "Must specify array size"); - } - } - - auto name = field->Names; - do - { - if (fieldtype->Size == 0 && !(varflags & VARF_Native)) // Size not known yet. - { - return false; - } - - if (AddTreeNode(name->Name, name, TreeNodes, !forstruct)) - { - auto thisfieldtype = fieldtype; - if (name->ArraySize != nullptr) - { - bool nosize; - thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, type, &nosize); - - if (nosize) - { - Error(field, "Must specify array size"); - } - } - - PField *f = nullptr; - - if (varflags & VARF_Native) - { - if (varflags & VARF_Meta) - { - Error(field, "Native meta variable %s not allowed", FName(name->Name).GetChars()); - } - else - { - fd = FindField(type, FName(name->Name).GetChars()); - if (fd == nullptr) - { - Error(field, "The member variable '%s.%s' has not been exported from the executable.", type == nullptr? "" : type->TypeName.GetChars(), FName(name->Name).GetChars()); - } - // For native structs a size check cannot be done because they normally have no size. But for a native reference they are still fine. - else if (thisfieldtype->Size != ~0u && fd->FieldSize != ~0u && thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0 && - (!thisfieldtype->isStruct() || !static_cast(thisfieldtype)->isNative)) - { - Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type == nullptr ? "" : type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); - } - // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. - else if (type != nullptr) - { - // for bit fields the type must point to the source variable. - if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; - f = type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); - } - else - { - - // This is a global variable. - if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; - f = Create(name->Name, thisfieldtype, varflags | VARF_Native | VARF_Static, fd->FieldOffset, fd->BitValue); - - if (OutNamespace->Symbols.AddSymbol(f) == nullptr) - { // name is already in use - f->Destroy(); - return false; - } - } - } - } - else if (hasnativechildren && !(varflags & VARF_Meta)) - { - Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change", FName(name->Name).GetChars(), type->TypeName.GetChars(), type->TypeName.GetChars()); - } - else if (type != nullptr) - { - f = type->AddField(name->Name, thisfieldtype, varflags); - } - else - { - Error(field, "Cannot declare non-native global variables. Tried to declare %s", FName(name->Name).GetChars()); - } - - if ((field->Flags & (ZCC_Version | ZCC_Deprecated)) && f != nullptr) - { - f->mVersion = field->Version; - - if (field->DeprecationMessage != nullptr) - { - f->DeprecationMessage = *field->DeprecationMessage; - } - } - } - name = static_cast(name->SiblingNext); - } while (name != field->Names); - Fields.Delete(0); - } - return Fields.Size() == 0; -} - -//========================================================================== -// -// ZCCCompiler :: CompileAllProperties -// -// builds the property lists of all actor classes -// -//========================================================================== - -void ZCCCompiler::CompileAllProperties() -{ - for (auto c : Classes) - { - if (c->Properties.Size() > 0) - CompileProperties(c->ClassType(), c->Properties, c->Type()->TypeName); - - if (c->FlagDefs.Size() > 0) - CompileFlagDefs(c->ClassType(), c->FlagDefs, c->Type()->TypeName); - - } -} - -//========================================================================== -// -// ZCCCompiler :: CompileProperties -// -// builds the internal structure of a single class or struct -// -//========================================================================== - -bool ZCCCompiler::CompileProperties(PClass *type, TArray &Properties, FName prefix) -{ - if (!type->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - Error(Properties[0], "Properties can only be defined for actors"); - return false; - } - for(auto p : Properties) - { - TArray fields; - ZCC_Identifier *id = (ZCC_Identifier *)p->Body; - - if (FName(p->NodeName) == FName("prefix") && Wads.GetLumpFile(Lump) == 0) - { - // only for internal definitions: Allow setting a prefix. This is only for compatiblity with the old DECORATE property parser, but not for general use. - prefix = id->Id; - } - else - { - do - { - auto f = dyn_cast(type->FindSymbol(id->Id, true)); - if (f == nullptr) - { - Error(id, "Variable %s not found in %s", FName(id->Id).GetChars(), type->TypeName.GetChars()); - } - fields.Push(f); - id = (ZCC_Identifier*)id->SiblingNext; - } while (id != p->Body); - - FString qualifiedname; - // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. - // All these will be removed from the symbol table after the compiler finishes to free up the allocated space. - FName name = FName(p->NodeName); - if (prefix == NAME_None) qualifiedname.Format("@property@%s", name.GetChars()); - else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars()); - - fields.ShrinkToFit(); - if (!type->VMType->Symbols.AddSymbol(Create(qualifiedname, fields))) - { - Error(id, "Unable to add property %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); - } - } - } - return true; -} - -//========================================================================== -// -// ZCCCompiler :: CompileProperties -// -// builds the internal structure of a single class or struct -// -//========================================================================== - -bool ZCCCompiler::CompileFlagDefs(PClass *type, TArray &Properties, FName prefix) -{ - if (!type->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - Error(Properties[0], "Flags can only be defined for actors"); - return false; - } - for (auto p : Properties) - { - PField *field; - FName referenced = FName(p->RefName); - - if (FName(p->NodeName) == FName("prefix") && Wads.GetLumpFile(Lump) == 0) - { - // only for internal definitions: Allow setting a prefix. This is only for compatiblity with the old DECORATE property parser, but not for general use. - prefix = referenced; - } - else - { - if (referenced != NAME_None) - { - field = dyn_cast(type->FindSymbol(referenced, true)); - if (field == nullptr) - { - Error(p, "Variable %s not found in %s", referenced.GetChars(), type->TypeName.GetChars()); - } - else if (!field->Type->isInt() || field->Type->Size != 4) - { - Error(p, "Variable %s in %s must have a size of 4 bytes for use as flag storage", referenced.GetChars(), type->TypeName.GetChars()); - } - } - else field = nullptr; - - - FString qualifiedname; - // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. - // All these will be removed from the symbol table after the compiler finishes to free up the allocated space. - FName name = FName(p->NodeName); - for (int i = 0; i < 2; i++) - { - if (i == 0) qualifiedname.Format("@flagdef@%s", name.GetChars()); - else - { - if (prefix == NAME_None) continue; - qualifiedname.Format("@flagdef@%s.%s", prefix.GetChars(), name.GetChars()); - } - - if (!type->VMType->Symbols.AddSymbol(Create(qualifiedname, field, p->BitValue, i == 0 && prefix != NAME_None))) - { - Error(p, "Unable to add flag definition %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); - } - } - - if (field != nullptr) - type->VMType->AddNativeField(FStringf("b%s", name.GetChars()), TypeSInt32, field->Offset, 0, 1 << p->BitValue); - } - } - return true; -} - -//========================================================================== -// -// ZCCCompiler :: FieldFlagsToString -// -// creates a string for a field's flags -// -//========================================================================== - -FString ZCCCompiler::FlagsToString(uint32_t flags) -{ - - const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "const", "abstract", "extend", "virtual", "override", "transient", "vararg", "ui", "play", "clearscope", "virtualscope" }; - FString build; - - for (size_t i = 0; i < countof(flagnames); i++) - { - if (flags & (1 << i)) - { - if (build.IsNotEmpty()) build += ", "; - build += flagnames[i]; - } - } - return build; -} - -//========================================================================== -// -// ZCCCompiler :: DetermineType -// -// retrieves the type for this field, for arrays the type of a single entry. -// -//========================================================================== - -PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember) -{ - PType *retval = TypeError; - if (!allowarraytypes && ztype->ArraySize != nullptr) - { - Error(field, "%s: Array type not allowed", name.GetChars()); - return TypeError; - } - switch (ztype->NodeType) - { - case AST_BasicType: - { - auto btype = static_cast(ztype); - switch (btype->Type) - { - case ZCC_SInt8: - retval = formember? TypeSInt8 : (PType*)TypeError; - break; - - case ZCC_UInt8: - retval = formember ? TypeUInt8 : (PType*)TypeError; - break; - - case ZCC_SInt16: - retval = formember ? TypeSInt16 : (PType*)TypeError; - break; - - case ZCC_UInt16: - retval = formember ? TypeUInt16 : (PType*)TypeError; - break; - - case ZCC_SInt32: - case ZCC_IntAuto: // todo: for enums, autoselect appropriately sized int - retval = TypeSInt32; - break; - - case ZCC_UInt32: - retval = TypeUInt32; - break; - - case ZCC_Bool: - retval = TypeBool; - break; - - case ZCC_FloatAuto: - retval = formember ? TypeFloat32 : TypeFloat64; - break; - - case ZCC_Float64: - retval = TypeFloat64; - break; - - case ZCC_String: - retval = TypeString; - break; - - case ZCC_Name: - retval = TypeName; - break; - - case ZCC_Vector2: - retval = TypeVector2; - break; - - case ZCC_Vector3: - retval = TypeVector3; - break; - - case ZCC_State: - retval = TypeState; - break; - - case ZCC_Color: - retval = TypeColor; - break; - - case ZCC_Sound: - retval = TypeSound; - break; - - case ZCC_Let: - retval = TypeAuto; - break; - - case ZCC_NativeType: - - // Creating an instance of a native struct is only allowed for internal definitions of native variables. - if (Wads.GetLumpFile(Lump) != 0 || !formember) - { - Error(field, "%s: @ not allowed for user scripts", name.GetChars()); - } - retval = ResolveUserType(btype, outertype? &outertype->Symbols : nullptr, true); - break; - - case ZCC_UserType: - // statelabel et.al. are not tokens - there really is no need to, it works just as well as an identifier. Maybe the same should be done for some other types, too? - switch (btype->UserType->Id) - { - case NAME_Voidptr: - retval = TypeVoidPtr; - break; - - case NAME_StateLabel: - retval = TypeStateLabel; - break; - - case NAME_SpriteID: - retval = TypeSpriteID; - break; - - case NAME_TextureID: - retval = TypeTextureID; - break; - - default: - retval = ResolveUserType(btype, outertype ? &outertype->Symbols : nullptr, false); - break; - } - break; - - default: - break; - } - break; - } - - case AST_MapType: - if (allowarraytypes) - { - Error(field, "%s: Map types not implemented yet", name.GetChars()); - // Todo: Decide what we allow here and if it makes sense to allow more complex constructs. - auto mtype = static_cast(ztype); - retval = NewMap(DetermineType(outertype, field, name, mtype->KeyType, false, false), DetermineType(outertype, field, name, mtype->ValueType, false, false)); - break; - } - break; - - case AST_DynArrayType: - { - auto atype = static_cast(ztype); - auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true); - if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1) - { - if (field->NodeType == AST_VarDeclarator && (static_cast(field)->Flags & ZCC_Native) && Wads.GetLumpFile(Lump) == 0) - { - // the internal definitions may declare native arrays to complex types. - // As long as they can be mapped to a static array type the VM can handle them, in a limited but sufficient fashion. - retval = NewPointer(NewStaticArray(ftype), false); - retval->Size = ~0u; // don't check for a size match, it's likely to fail anyway. - retval->Align = ~0u; - } - else - { - Error(field, "%s: Base type for dynamic array types must be integral, but got %s", name.GetChars(), ftype->DescriptiveName()); - } - } - else - { - retval = NewDynArray(ftype); - } - break; - } - case AST_ClassType: - { - auto ctype = static_cast(ztype); - if (ctype->Restriction == nullptr) - { - retval = NewClassPointer(RUNTIME_CLASS(DObject)); - } - else - { - // This doesn't check the class list directly but the current symbol table to ensure that - // this does not reference a type that got shadowed by a more local definition. - // We first look in the current class and its parents, and then in the current namespace and its parents. - auto sym = outertype ? outertype->Symbols.FindSymbol(ctype->Restriction->Id, true) : nullptr; - if (sym == nullptr) sym = OutNamespace->Symbols.FindSymbol(ctype->Restriction->Id, true); - if (sym == nullptr) - { - // A symbol with a given name cannot be reached from this definition point, so - // even if a class with the given name exists, it is not accessible. - Error(field, "%s: Unknown identifier", FName(ctype->Restriction->Id).GetChars()); - return TypeError; - } - auto typesym = dyn_cast(sym); - if (typesym == nullptr || !typesym->Type->isClass()) - { - Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars()); - return TypeError; - } - if (typesym->Type->mVersion > mVersion) - { - Error(field, "Class %s not accessible to ZScript version %d.%d.%d", FName(ctype->Restriction->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); - return TypeError; - } - retval = NewClassPointer(static_cast(typesym->Type)->Descriptor); - } - break; - } - - default: - break; - } - if (retval != TypeError && retval->MemberOnly && !formember) - { - Error(field, "Invalid type %s", retval->DescriptiveName()); - return TypeError; - } - return retval; -} - -//========================================================================== -// -// ZCCCompiler :: ResolveUserType -// -// resolves a user type and returns a matching PType -// -//========================================================================== - -PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, bool nativetype) -{ - // Check the symbol table for the identifier. - PSymbol *sym = nullptr; - - // We first look in the current class and its parents, and then in the current namespace and its parents. - if (symt != nullptr) sym = symt->FindSymbol(type->UserType->Id, true); - if (sym == nullptr) sym = OutNamespace->Symbols.FindSymbol(type->UserType->Id, true); - if (sym != nullptr && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) - { - auto ptype = static_cast(sym)->Type; - if (ptype->mVersion > mVersion) - { - Error(type, "Type %s not accessible to ZScript version %d.%d.%d", FName(type->UserType->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); - return TypeError; - } - - if (ptype->isEnum()) - { - if (!nativetype) return TypeSInt32; // hack this to an integer until we can resolve the enum mess. - } - else if (ptype->isClass()) // classes cannot be instantiated at all, they always get used as references. - { - return NewPointer(ptype, type->isconst); - } - else if (ptype->isStruct() && static_cast(ptype)->isNative) // native structs and classes cannot be instantiated, they always get used as reference. - { - if (!nativetype) return NewPointer(ptype, type->isconst); - return ptype; // instantiation of native structs. Only for internal use. - } - if (!nativetype) return ptype; - } - Error(type, "Unable to resolve %s%s as type.", nativetype? "@" : "", FName(type->UserType->Id).GetChars()); - return TypeError; -} - - -//========================================================================== -// -// ZCCCompiler :: ResolveArraySize -// -// resolves the array size and returns a matching type. -// -//========================================================================== - -PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls, bool *nosize) -{ - TArray indices; - - // Simplify is too broken to resolve this inside the ring list so unravel the list into an array before starting to simplify its components. - auto node = arraysize; - do - { - indices.Push(node); - node = static_cast(node->SiblingNext); - } while (node != arraysize); - - if (indices.Size() == 1 && indices [0]->Operation == PEX_Nil) - { - *nosize = true; - return baseType; - } - - if (mVersion >= MakeVersion(3, 7, 2)) - { - TArray fixedIndices; - for (auto node : indices) - { - fixedIndices.Insert (0, node); - } - - indices = std::move(fixedIndices); - } - - FCompileContext ctx(OutNamespace, cls, false); - for (auto node : indices) - { - // There is no float->int casting here. - FxExpression *ex = ConvertNode(node); - ex = ex->Resolve(ctx); - - if (ex == nullptr) return TypeError; - if (!ex->isConstant() || !ex->ValueType->isInt()) - { - Error(arraysize, "Array index must be an integer constant"); - return TypeError; - } - int size = static_cast(ex)->GetValue().GetInt(); - if (size < 1) - { - Error(arraysize, "Array size must be positive"); - return TypeError; - } - baseType = NewArray(baseType, size); - } - - *nosize = false; - return baseType; -} - -//========================================================================== -// -// Parses an actor property's parameters and calls the handler -// -//========================================================================== - -void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag) -{ - static TArray params; - static TArray strings; - - params.Clear(); - strings.Clear(); - params.Reserve(1); - params[0].i = 0; - if (prop->params[0] != '0') - { - if (property->Values == nullptr) - { - Error(property, "%s: arguments missing", prop->name); - return; - } - const char * p = prop->params; - auto exp = property->Values; - - FCompileContext ctx(OutNamespace, bag.Info->VMType, false); - while (true) - { - FPropParam conv; - FPropParam pref; - - FxExpression *ex = ConvertNode(exp); - ex = ex->Resolve(ctx); - if (ex == nullptr) - { - return; - } - else if (!ex->isConstant()) - { - // If we get TypeError, there has already been a message from deeper down so do not print another one. - if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->name); - return; - } - conv.s = nullptr; - pref.s = nullptr; - pref.i = -1; - switch ((*p) & 223) - { - - case 'X': // Expression in parentheses or number. We only support the constant here. The function will have to be handled by a separate property to get past the parser. - conv.i = GetIntConst(ex, ctx); - params.Push(conv); - conv.exp = nullptr; - break; - - case 'I': - case 'M': // special case for morph styles in DECORATE . This expression-aware parser will not need this. - case 'N': // special case for thing activations in DECORATE. This expression-aware parser will not need this. - conv.i = GetIntConst(ex, ctx); - break; - - case 'F': - conv.d = GetFloatConst(ex, ctx); - break; - - case 'Z': // an optional string. Does not allow any numeric value. - if (ex->ValueType != TypeString) - { - // apply this expression to the next argument on the list. - params.Push(conv); - params[0].i++; - p++; - continue; - } - conv.s = GetStringConst(ex, ctx); - break; - - case 'C': // this parser accepts colors only in string form. - pref.i = 1; - case 'S': - case 'T': // a filtered string (ZScript only parses filtered strings so there's nothing to do here.) - conv.s = GetStringConst(ex, ctx); - break; - - case 'L': // Either a number or a list of strings - if (ex->ValueType != TypeString) - { - pref.i = 0; - conv.i = GetIntConst(ex, ctx); - } - else - { - pref.i = 1; - params.Push(pref); - params[0].i++; - - do - { - conv.s = GetStringConst(ex, ctx); - if (conv.s != nullptr) - { - params.Push(conv); - params[0].i++; - } - exp = static_cast(exp->SiblingNext); - if (exp != property->Values) - { - ex = ConvertNode(exp); - ex = ex->Resolve(ctx); - if (ex == nullptr) return; - } - } while (exp != property->Values); - goto endofparm; - } - break; - - default: - assert(false); - break; - - } - if (pref.i != -1) - { - params.Push(pref); - params[0].i++; - } - params.Push(conv); - params[0].i++; - exp = static_cast(exp->SiblingNext); - endofparm: - p++; - // Skip the DECORATE 'no comma' marker - if (*p == '_') p++; - - if (*p == 0) - { - if (exp != property->Values) - { - Error(property, "Too many values for '%s'", prop->name); - return; - } - break; - } - else if (exp == property->Values) - { - if (*p < 'a') - { - Error(property, "Insufficient parameters for %s", prop->name); - return; - } - break; - } - } - } - // call the handler - try - { - prop->Handler(defaults, bag.Info, bag, ¶ms[0]); - } - catch (CRecoverableError &error) - { - Error(property, "%s", error.GetMessage()); - } -} - - -//========================================================================== -// -// Parses an actor property's parameters and calls the handler -// -//========================================================================== - -void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag) -{ - ZCC_ExprConstant one; - unsigned parmcount = 1; - ZCC_TreeNode *x = property->Values; - if (x == nullptr) - { - parmcount = 0; - } - else - { - while (x->SiblingNext != property->Values) - { - x = x->SiblingNext; - parmcount++; - } - } - if (parmcount == 0 && prop->Variables.Size() == 1 && prop->Variables[0]->Type == TypeBool) - { - // allow boolean properties to have the parameter omitted - memset(&one, 0, sizeof(one)); - one.SourceName = property->SourceName; // This may not be null! - one.Operation = PEX_ConstValue; - one.NodeType = AST_ExprConstant; - one.Type = TypeBool; - one.IntVal = 1; - property->Values = &one; - } - else if (parmcount != prop->Variables.Size()) - { - Error(x == nullptr? property : x, "Argument count mismatch: Got %u, expected %u", parmcount, prop->Variables.Size()); - return; - } - - auto exp = property->Values; - FCompileContext ctx(OutNamespace, bag.Info->VMType, false); - for (auto f : prop->Variables) - { - void *addr; - if (f == nullptr) - { - // This variable was missing. The error had been reported for the property itself already. - return; - } - - if (f->Flags & VARF_Meta) - { - addr = ((char*)bag.Info->Meta) + f->Offset; - } - else - { - addr = ((char*)defaults) + f->Offset; - } - - FxExpression *ex = ConvertNode(exp); - ex = ex->Resolve(ctx); - if (ex == nullptr) - { - return; - } - else if (!ex->isConstant()) - { - // If we get TypeError, there has already been a message from deeper down so do not print another one. - if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars()); - return; - } - - if (f->Type == TypeBool) - { - static_cast(f->Type)->SetValue(addr, !!GetIntConst(ex, ctx)); - } - else if (f->Type == TypeName) - { - *(FName*)addr = GetStringConst(ex, ctx); - } - else if (f->Type == TypeSound) - { - *(FSoundID*)addr = GetStringConst(ex, ctx); - } - else if (f->Type == TypeColor && ex->ValueType == TypeString) // colors can also be specified as ints. - { - *(PalEntry*)addr = V_GetColor(nullptr, GetStringConst(ex, ctx), &ex->ScriptPosition); - } - else if (f->Type->isIntCompatible()) - { - static_cast(f->Type)->SetValue(addr, GetIntConst(ex, ctx)); - } - else if (f->Type->isFloat()) - { - static_cast(f->Type)->SetValue(addr, GetFloatConst(ex, ctx)); - } - else if (f->Type == TypeString) - { - *(FString*)addr = GetStringConst(ex, ctx); - } - else if (f->Type->isClassPointer()) - { - auto clsname = GetStringConst(ex, ctx); - if (*clsname == 0 || !stricmp(clsname, "none")) - { - *(PClass**)addr = nullptr; - } - else - { - auto cls = PClass::FindClass(clsname); - auto cp = static_cast(f->Type); - if (cls == nullptr) - { - cls = cp->ClassRestriction->FindClassTentative(clsname); - } - else if (!cls->IsDescendantOf(cp->ClassRestriction)) - { - Error(property, "class %s is not compatible with property type %s", clsname, cp->ClassRestriction->TypeName.GetChars()); - } - *(PClass**)addr = cls; - } - } - else - { - Error(property, "unhandled property type %s", f->Type->DescriptiveName()); - } - exp->ToErrorNode(); // invalidate after processing. - exp = static_cast(exp->SiblingNext); - } -} - -//========================================================================== -// -// Parses an actor property -// -//========================================================================== - -void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *prop, Baggage &bag) -{ - auto namenode = prop->Prop; - FString propname; - - if (namenode->SiblingNext == namenode) - { - if (namenode->Id == NAME_DamageFunction) - { - auto x = ConvertNode(prop->Values); - CreateDamageFunction(OutNamespace, mVersion, cls, (AActor *)bag.Info->Defaults, x, false, Lump); - ((AActor *)bag.Info->Defaults)->DamageVal = -1; - return; - } - - // a one-name property - propname = FName(namenode->Id); - - } - else if (namenode->SiblingNext->SiblingNext == namenode) - { - // a two-name property - propname << FName(namenode->Id) << "." << FName(static_cast(namenode->SiblingNext)->Id); - } - else - { - Error(prop, "Property name may at most contain two parts"); - return; - } - - - FPropertyInfo *property = FindProperty(propname); - - if (property != nullptr && property->category != CAT_INFO) - { - auto pcls = PClass::FindActor(property->clsname); - if (cls->IsDescendantOf(pcls)) - { - DispatchProperty(property, prop, (AActor *)bag.Info->Defaults, bag); - } - else - { - Error(prop, "'%s' requires an actor of type '%s'\n", propname.GetChars(), pcls->TypeName.GetChars()); - } - } - else - { - propname.Insert(0, "@property@"); - FName name(propname, true); - if (name != NAME_None) - { - auto propp = dyn_cast(cls->FindSymbol(name, true)); - if (propp != nullptr) - { - DispatchScriptProperty(propp, prop, (AActor *)bag.Info->Defaults, bag); - return; - } - } - Error(prop, "'%s' is an unknown actor property\n", propname.GetChars()); - } -} - -//========================================================================== -// -// Finds a flag and sets or clears it -// -//========================================================================== - -void ZCCCompiler::ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg) -{ - auto namenode = flg->name; - const char *n1 = FName(namenode->Id).GetChars(), *n2; - - if (namenode->SiblingNext == namenode) - { - // a one-name flag - n2 = nullptr; - } - else if (namenode->SiblingNext->SiblingNext == namenode) - { - // a two-name flag - n2 = FName(static_cast(namenode->SiblingNext)->Id).GetChars(); - } - else - { - Error(flg, "Flag name may at most contain two parts"); - return; - } - - auto fd = FindFlag(cls, n1, n2, true); - if (fd != nullptr) - { - if (fd->varflags & VARF_Deprecated) - { - Warn(flg, "Deprecated flag '%s%s%s' used", n1, n2 ? "." : "", n2 ? n2 : ""); - } - if (fd->structoffset == -1) - { - HandleDeprecatedFlags((AActor*)cls->Defaults, cls, flg->set, fd->flagbit); - } - else - { - ModActorFlag((AActor*)cls->Defaults, fd, flg->set); - } - } - else - { - Error(flg, "Unknown flag '%s%s%s'", n1, n2 ? "." : "", n2 ? n2 : ""); - } -} - -//========================================================================== -// -// Parses the default list -// -//========================================================================== - -void ZCCCompiler::InitDefaults() -{ - for (auto c : Classes) - { - // This may be removed if the conditions change, but right now only subclasses of Actor can define a Default block. - if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->ClassType()->TypeName.GetChars()); - if (c->ClassType()->ParentClass) - { - auto ti = static_cast(c->ClassType()); - ti->InitializeDefaults(); - } - } - else - { - auto cls = c->ClassType(); - // This should never happen. - if (cls->Defaults != nullptr) - { - Error(c->cls, "%s already has defaults", cls->TypeName.GetChars()); - } - // This can only occur if a native parent is not initialized. In all other cases the sorting of the class list should prevent this from ever happening. - else if (cls->ParentClass->Defaults == nullptr && cls != RUNTIME_CLASS(AActor)) - { - Error(c->cls, "Parent class %s of %s is not initialized", cls->ParentClass->TypeName.GetChars(), cls->TypeName.GetChars()); - } - else - { - // Copy the parent's defaults and meta data. - auto ti = static_cast(cls); - - ti->InitializeDefaults(); - - // Replacements require that the meta data has been allocated by InitializeDefaults. - if (c->cls->Replaces != nullptr && !ti->SetReplacement(c->cls->Replaces->Id)) - { - Warn(c->cls, "Replaced type '%s' not found for %s", FName(c->cls->Replaces->Id).GetChars(), ti->TypeName.GetChars()); - } - - // We need special treatment for this one field in AActor's defaults which cannot be made visible to DECORATE as a property. - // It's better to do this here under controlled conditions than deeper down in the class type classes. - if (ti == RUNTIME_CLASS(AActor)) - { - ((AActor*)ti->Defaults)->ConversationRoot = 1; - } - - Baggage bag; - #ifdef _DEBUG - bag.ClassName = cls->TypeName; - #endif - bag.Version = mVersion; - bag.Namespace = OutNamespace; - bag.Info = ti; - bag.DropItemSet = false; - bag.StateSet = false; - bag.fromDecorate = false; - bag.CurrentState = 0; - bag.Lumpnum = c->cls->SourceLump; - bag.DropItemList = nullptr; - // The actual script position needs to be set per property. - - for (auto d : c->Defaults) - { - auto content = d->Content; - if (content != nullptr) do - { - switch (content->NodeType) - { - case AST_PropertyStmt: - bag.ScriptPosition.FileName = *content->SourceName; - bag.ScriptPosition.ScriptLine = content->SourceLoc; - ProcessDefaultProperty(ti, static_cast(content), bag); - break; - - case AST_FlagStmt: - ProcessDefaultFlag(ti, static_cast(content)); - break; - - default: - break; - } - content = static_cast(content->SiblingNext); - } while (content != d->Content); - } - if (bag.DropItemSet) - { - bag.Info->SetDropItems(bag.DropItemList); - } - } - } - } -} - - -void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass) -{ - TArray rets(1); - TArray args; - TArray argflags; - TArray argdefaults; - TArray argnames; - - rets.Clear(); - args.Clear(); - argflags.Clear(); - bool hasdefault = false; - // For the time being, let's not allow overloading. This may be reconsidered later but really just adds an unnecessary amount of complexity here. - if (AddTreeNode(f->Name, f, &c->TreeNodes, false)) - { - auto t = f->Type; - if (t != nullptr) - { - do - { - auto type = DetermineType(c->Type(), f, f->Name, t, false, false); - if (type->isContainer() && type != TypeVector2 && type != TypeVector3) - { - // structs and classes only get passed by pointer. - type = NewPointer(type); - } - else if (type->isDynArray()) - { - Error(f, "The return type of a function cannot be a dynamic array"); - break; - } - // TBD: disallow certain types? For now, let everything pass that isn't an array. - rets.Push(type); - t = static_cast(t->SiblingNext); - } while (t != f->Type); - } - - int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_Abstract | ZCC_Internal; - - if (f->Flags & notallowed) - { - Error(f, "Invalid qualifiers for %s (%s not allowed)", FName(f->Name).GetChars(), FlagsToString(f->Flags & notallowed).GetChars()); - f->Flags &= notallowed; - } - uint32_t varflags = VARF_Method; - int implicitargs = 1; - AFuncDesc *afd = nullptr; - int useflags = SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM; - if (f->UseFlags != nullptr) - { - useflags = 0; - auto p = f->UseFlags; - do - { - switch (p->Id) - { - case NAME_Actor: - useflags |= SUF_ACTOR; - break; - case NAME_Overlay: - useflags |= SUF_OVERLAY; - break; - case NAME_Weapon: - useflags |= SUF_WEAPON; - break; - case NAME_Item: - useflags |= SUF_ITEM; - break; - default: - Error(p, "Unknown Action qualifier %s", FName(p->Id).GetChars()); - break; - } - - p = static_cast(p->SiblingNext); - } while (p != f->UseFlags); - } - - // map to implementation flags. - if (f->Flags & ZCC_Private) varflags |= VARF_Private; - if (f->Flags & ZCC_Protected) varflags |= VARF_Protected; - if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; - if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual; - if (f->Flags & ZCC_Override) varflags |= VARF_Override; - if (f->Flags & ZCC_VarArg) varflags |= VARF_VarArg; - if (f->Flags & ZCC_FuncConst) varflags |= VARF_ReadOnly; // FuncConst method is internally marked as VARF_ReadOnly - if (mVersion >= MakeVersion(2, 4, 0)) - { - if (c->Type()->ScopeFlags & Scope_UI) - varflags |= VARF_UI; - if (c->Type()->ScopeFlags & Scope_Play) - varflags |= VARF_Play; - //if (f->Flags & ZCC_FuncConst) - // varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData); // const implies clearscope. this is checked a bit later to also not have ZCC_Play/ZCC_UIFlag. - if (f->Flags & ZCC_UIFlag) - varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI); - if (f->Flags & ZCC_Play) - varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play); - if (f->Flags & ZCC_ClearScope) - varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Clear); - if (f->Flags & ZCC_VirtualScope) - varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Virtual); - } - else - { - varflags |= VARF_Play; - } - - if ((f->Flags & ZCC_VarArg) && !(f->Flags & ZCC_Native)) - { - Error(f, "'VarArg' can only be used with native methods"); - } - if (f->Flags & ZCC_Action) - { - if (varflags & VARF_ReadOnly) - { - Error(f, "Action functions cannot be declared const"); - varflags &= ~VARF_ReadOnly; - } - if (varflags & VARF_UI) - { - Error(f, "Action functions cannot be declared UI"); - } - // Non-Actors cannot have action functions. - if (!isActor(c->Type())) - { - Error(f, "'Action' can only be used in child classes of Actor"); - } - - varflags |= VARF_Final; // Action implies Final. - if (useflags & (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) - { - varflags |= VARF_Action; - implicitargs = 3; - } - else - { - implicitargs = 1; - } - } - if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final. - - if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'. - // Only one of these flags may be used. - static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static }; - int excludeflags = 0; - int fc = 0; - for (size_t i = 0; i < countof(exclude); i++) - { - if (f->Flags & exclude[i]) - { - fc++; - excludeflags |= exclude[i]; - } - } - if (fc > 1) - { - Error(f, "Invalid combination of qualifiers %s on function %s", FlagsToString(excludeflags).GetChars(), FName(f->Name).GetChars()); - varflags |= VARF_Method; - } - if (varflags & VARF_Override) varflags |= VARF_Virtual; // Now that the flags are checked, make all override functions virtual as well. - - // [ZZ] this doesn't make sense either. - if ((varflags&(VARF_ReadOnly | VARF_Method)) == VARF_ReadOnly) // non-method const function - { - Error(f, "'Const' on a static method is not supported"); - } - - // [ZZ] neither this - if ((varflags&(VARF_VirtualScope | VARF_Method)) == VARF_VirtualScope) // non-method virtualscope function - { - Error(f, "'VirtualScope' on a static method is not supported"); - } - - static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope, ZCC_VirtualScope }; - excludeflags = 0; - fc = 0; - for (size_t i = 0; i < countof(excludescope); i++) - { - if (f->Flags & excludescope[i]) - { - fc++; - excludeflags |= excludescope[i]; - } - } - if (fc > 1) - { - Error(f, "Invalid combination of scope qualifiers %s on function %s", FlagsToString(excludeflags).GetChars(), FName(f->Name).GetChars()); - varflags &= ~(VARF_UI | VARF_Play); // make plain data - } - - if (f->Flags & ZCC_Native) - { - varflags |= VARF_Native; - afd = FindFunction(c->Type(), FName(f->Name).GetChars()); - if (afd == nullptr) - { - Error(f, "The function '%s.%s' has not been exported from the executable", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); - } - else - { - (*afd->VMPointer)->ImplicitArgs = uint8_t(implicitargs); - } - } - SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, useflags); - argdefaults.Resize(argnames.Size()); - auto p = f->Params; - bool hasoptionals = false; - if (p != nullptr) - { - bool overridemsg = false; - do - { - int elementcount = 1; - TypedVMValue vmval[3]; // default is REGT_NIL which means 'no default value' here. - if (p->Type != nullptr) - { - auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); - int flags = 0; - if ((type->isStruct() && type != TypeVector2 && type != TypeVector3) || type->isDynArray()) - { - // Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly. - type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/); - flags |= VARF_Ref; - } - else if (type->GetRegType() != REGT_NIL) - { - if (p->Flags & ZCC_Out) flags |= VARF_Out; - if (type == TypeVector2) - { - elementcount = 2; - } - else if (type == TypeVector3) - { - elementcount = 3; - } - } - if (type->GetRegType() == REGT_NIL && type != TypeVector2 && type != TypeVector3) - { - Error(p, "Invalid type %s for function parameter", type->DescriptiveName()); - } - else if (p->Default != nullptr) - { - if (flags & VARF_Out) - { - Error(p, "Out parameters cannot have default values"); - } - - flags |= VARF_Optional; - hasoptionals = true; - - if ((varflags & VARF_Override) && !overridemsg) - { - // This is illegal, but in older compilers wasn't checked, so there it has to be demoted to a warning. - // Virtual calls always need to get their defaults from the base virtual method. - if (mVersion >= MakeVersion(3, 3)) - { - Error(p, "Default values for parameter of virtual override not allowed"); - } - else - { - Warn(p, "Default values for parameter of virtual override will be ignored!"); - } - overridemsg = true; - } - - - FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false); - FCompileContext ctx(OutNamespace, c->Type(), false); - x = x->Resolve(ctx); - - if (x != nullptr) - { - // Vectors need special treatment because they use more than one entry in the Defaults and do not report as actual constants - if (type == TypeVector2 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(2)) - { - auto vx = static_cast(x); - vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); - vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); - } - else if (type == TypeVector3 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(3)) - { - auto vx = static_cast(x); - vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); - vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); - vmval[2] = static_cast(vx->xyz[2])->GetValue().GetFloat(); - } - else if (!x->isConstant()) - { - Error(p, "Default parameter %s is not constant in %s", FName(p->Name).GetChars(), FName(f->Name).GetChars()); - } - else if (x->ValueType != type) - { - Error(p, "Default parameter %s could not be converted to target type %s", FName(p->Name).GetChars(), c->Type()->TypeName.GetChars()); - } - else - { - auto cnst = static_cast(x); - switch (type->GetRegType()) - { - case REGT_INT: - vmval[0] = cnst->GetValue().GetInt(); - break; - - case REGT_FLOAT: - vmval[0] = cnst->GetValue().GetFloat(); - break; - - case REGT_POINTER: - if (type->isClassPointer()) - vmval[0] = (DObject*)cnst->GetValue().GetPointer(); - else - vmval[0] = cnst->GetValue().GetPointer(); - break; - - case REGT_STRING: - // We need a reference to something permanently stored here. - vmval[0] = VMStringConstants.Alloc(cnst->GetValue().GetString()); - break; - - default: - assert(0 && "no valid type for constant"); - break; - } - } - - hasdefault = true; - } - if (x != nullptr) delete x; - } - else if (hasoptionals) - { - Error(p, "All arguments after the first optional one need also be optional"); - } - // TBD: disallow certain types? For now, let everything pass that isn't an array. - args.Push(type); - argflags.Push(flags); - argnames.Push(p->Name); - - } - else - { - args.Push(nullptr); - argflags.Push(0); - argnames.Push(NAME_None); - } - for (int i = 0; i(p->SiblingNext); - } while (p != f->Params); - } - - PFunction *sym = Create(c->Type(), f->Name); - sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags); - c->Type()->Symbols.ReplaceSymbol(sym); - - if (f->DeprecationMessage != nullptr) - { - sym->Variants[0].DeprecationMessage = *f->DeprecationMessage; - } - - auto vcls = PType::toClass(c->Type()); - auto cls = vcls ? vcls->Descriptor : nullptr; - PFunction *virtsym = nullptr; - if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->VMType->Symbols.FindSymbol(FName(f->Name), true)); - unsigned vindex = ~0u; - if (virtsym != nullptr) - { - auto imp = virtsym->Variants[0].Implementation; - if (imp != nullptr) vindex = imp->VirtualIndex; - else Error(f, "Virtual base function %s not found in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars()); - } - if (f->Flags & (ZCC_Version | ZCC_Deprecated)) - { - sym->mVersion = f->Version; - if (varflags & VARF_Override) - { - Error(f, "Overridden function %s may not alter version restriction in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars()); - } - } - - VMFunction *newfunc = nullptr; - - if (!(f->Flags & ZCC_Native)) - { - if (f->Body == nullptr) - { - Error(f, "Empty function %s", FName(f->Name).GetChars()); - return; - } - else - { - auto code = ConvertAST(c->Type(), f->Body); - if (code != nullptr) - { - newfunc = FunctionBuildList.AddFunction(OutNamespace, mVersion, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); - } - } - } - if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time. - { - sym->Variants[0].Implementation->DefaultArgs = std::move(argdefaults); - } - - if (sym->Variants[0].Implementation != nullptr) - { - // [ZZ] unspecified virtual function inherits old scope. virtual function scope can't be changed. - sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags; - } - - PClass *clstype = forclass? static_cast(c->Type())->Descriptor : nullptr; - if (varflags & VARF_Virtual) - { - if (sym->Variants[0].Implementation == nullptr) - { - Error(f, "Virtual function %s.%s not present", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); - return; - } - - if (forclass) - { - auto parentfunc = clstype->ParentClass? dyn_cast(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)) : nullptr; - - int vindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], parentfunc); - // specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types. - if (varflags & VARF_Override) - { - if (vindex == -1) - { - Error(f, "Attempt to override non-existent virtual function %s", FName(f->Name).GetChars()); - } - else - { - auto oldfunc = clstype->Virtuals[vindex]; - if (parentfunc && parentfunc->mVersion > mVersion) - { - Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); - } - if (oldfunc->VarFlags & VARF_Final) - { - Error(f, "Attempt to override final function %s", FName(f->Name).GetChars()); - } - // you can't change ui/play/clearscope for a virtual method. - if (f->Flags & (ZCC_UIFlag|ZCC_Play|ZCC_ClearScope|ZCC_VirtualScope)) - { - Error(f, "Attempt to change scope for virtual function %s", FName(f->Name).GetChars()); - } - // you can't change const qualifier for a virtual method - if ((sym->Variants[0].Implementation->VarFlags & VARF_ReadOnly) && !(oldfunc->VarFlags & VARF_ReadOnly)) - { - Error(f, "Attempt to add const qualifier to virtual function %s", FName(f->Name).GetChars()); - } - // you can't change protected qualifier for a virtual method (i.e. putting private), because this cannot be reliably checked without runtime stuff - if (f->Flags & (ZCC_Private | ZCC_Protected)) - { - Error(f, "Attempt to change private/protected qualifiers for virtual function %s", FName(f->Name).GetChars()); - } - // inherit scope of original function if override not specified - sym->Variants[0].Flags = FScopeBarrier::ChangeSideInFlags(sym->Variants[0].Flags, FScopeBarrier::SideFromFlags(oldfunc->VarFlags)); - // inherit const from original function - if (oldfunc->VarFlags & VARF_ReadOnly) - sym->Variants[0].Flags |= VARF_ReadOnly; - if (oldfunc->VarFlags & VARF_Protected) - sym->Variants[0].Flags |= VARF_Protected; - - clstype->Virtuals[vindex] = sym->Variants[0].Implementation; - sym->Variants[0].Implementation->VirtualIndex = vindex; - sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags; - - // Defaults must be identical to parent class - if (parentfunc->Variants[0].Implementation->DefaultArgs.Size() > 0) - { - sym->Variants[0].Implementation->DefaultArgs = parentfunc->Variants[0].Implementation->DefaultArgs; - sym->Variants[0].ArgFlags = parentfunc->Variants[0].ArgFlags; - } - - // Update argument flags for VM function if needed as their list could be incomplete - // At the moment of function creation, arguments with default values were not copied yet from the parent function - if (newfunc != nullptr && sym->Variants[0].ArgFlags.Size() != newfunc->ArgFlags.Size()) - { - for (unsigned i = newfunc->ArgFlags.Size(), count = sym->Variants[0].ArgFlags.Size(); i < count; ++i) - { - newfunc->ArgFlags.Push(sym->Variants[0].ArgFlags[i]); - } - } - } - } - else - { - if (vindex != -1) - { - Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); - } - sym->Variants[0].Implementation->VirtualIndex = clstype->Virtuals.Push(sym->Variants[0].Implementation); - } - } - else - { - Error(p, "Virtual functions can only be defined for classes"); - } - } - else if (forclass) - { - int vindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], nullptr); - if (vindex != -1) - { - Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); - } - } - } -} - -//========================================================================== -// -// Parses the functions list -// -//========================================================================== - -void ZCCCompiler::InitFunctions() -{ - for (auto s : Structs) - { - for (auto f : s->Functions) - { - CompileFunction(s, f, false); - } - } - - for (auto c : Classes) - { - // cannot be done earlier because it requires the parent class to be processed by this code, too. - if (c->ClassType()->ParentClass != nullptr) - { - c->ClassType()->Virtuals = c->ClassType()->ParentClass->Virtuals; - } - for (auto f : c->Functions) - { - CompileFunction(c, f, true); - } - } -} - -//========================================================================== -// -// very complicated check for random duration. -// -//========================================================================== - -static bool CheckRandom(ZCC_Expression *duration) -{ - if (duration->NodeType != AST_ExprFuncCall) return false; - auto func = static_cast(duration); - if (func->Function == nullptr) return false; - if (func->Function->NodeType != AST_ExprID) return false; - auto f2 = static_cast(func->Function); - return f2->Identifier == NAME_Random; -} - -//========================================================================== -// -// Sets up the action function call -// -//========================================================================== -FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, int StateFlags) -{ - // We have 3 cases to consider here: - // 1. A function without parameters. This can be called directly - // 2. A functon with parameters. This needs to be wrapped into a helper function to set everything up. - // 3. An anonymous function. - - // 1. and 2. are exposed through AST_ExprFunctionCall - if (af->NodeType == AST_ExprFuncCall) - { - auto fc = static_cast(af); - assert(fc->Function->NodeType == AST_ExprID); - auto id = static_cast(fc->Function); - - // We must skip ACS_NamedExecuteWithResult here, because this name both exists as an action function and as a builtin. - // The code which gets called from here can easily make use of the builtin, so let's just pass this name without any checks. - // The actual action function is still needed by DECORATE: - if (id->Identifier != NAME_ACS_NamedExecuteWithResult) - { - PFunction *afd = dyn_cast(cls->VMType->Symbols.FindSymbol(id->Identifier, true)); - if (afd != nullptr) - { - if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual)) - { - FArgumentList argumentlist; - // We can use this function directly without wrapping it in a caller. - assert(PType::toClass(afd->Variants[0].SelfClass) != nullptr); // non classes are not supposed to get here. - - int comboflags = afd->Variants[0].UseFlags & StateFlags; - if (comboflags == StateFlags) // the function must satisfy all the flags the state requires - { - if ((afd->Variants[0].Flags & VARF_Private) && afd->OwningClass != cls->VMType) - { - Error(af, "%s is declared private and not accessible", FName(id->Identifier).GetChars()); - } - - return new FxVMFunctionCall(new FxSelf(*af), afd, argumentlist, *af, false); - } - else - { - Error(af, "Cannot use non-action function %s here.", FName(id->Identifier).GetChars()); - } - } - } - else - { - // it may also be an action special so check that first before printing an error. - if (!P_FindLineSpecial(FName(id->Identifier).GetChars())) - { - Error(af, "%s: action function not found in %s", FName(id->Identifier).GetChars(), cls->TypeName.GetChars()); - return nullptr; - } - // Action specials fall through to the code generator. - } - } - } - return ConvertAST(cls->VMType, af); -} - -//========================================================================== -// -// Compile the states -// -//========================================================================== - -void ZCCCompiler::CompileStates() -{ - for (auto c : Classes) - { - - if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - if (c->States.Size()) Error(c->cls, "%s: States can only be defined for actors.", c->Type()->TypeName.GetChars()); - continue; - } - - FString statename; // The state builder wants the label as one complete string, not separated into tokens. - FStateDefinitions statedef; - - if (static_cast(c->ClassType())->ActorInfo()->SkipSuperSet) - { - // SKIP_SUPER'ed actors only get the base states from AActor. - statedef.MakeStateDefines(RUNTIME_CLASS(AActor)); - } - else - { - statedef.MakeStateDefines(ValidateActor(c->ClassType()->ParentClass)); - } - - - int numframes = 0; - - for (auto s : c->States) - { - int flags; - if (s->Flags != nullptr) - { - flags = 0; - auto p = s->Flags; - do - { - switch (p->Id) - { - case NAME_Actor: - flags |= SUF_ACTOR; - break; - case NAME_Overlay: - flags |= SUF_OVERLAY; - break; - case NAME_Weapon: - flags |= SUF_WEAPON; - break; - case NAME_Item: - flags |= SUF_ITEM; - break; - default: - Error(p, "Unknown States qualifier %s", FName(p->Id).GetChars()); - break; - } - - p = static_cast(p->SiblingNext); - } while (p != s->Flags); - } - else - { - flags = static_cast(c->ClassType())->ActorInfo()->DefaultStateUsage; - } - auto st = s->Body; - if (st != nullptr) do - { - switch (st->NodeType) - { - case AST_StateLabel: - { - auto sl = static_cast(st); - statename = FName(sl->Label); - statedef.AddStateLabel(statename); - break; - } - case AST_StateLine: - { - auto sl = static_cast(st); - FState state; - memset(&state, 0, sizeof(state)); - state.UseFlags = flags; - if (sl->Sprite->Len() != 4) - { - Error(sl, "Sprite name must be exactly 4 characters. Found '%s'", sl->Sprite->GetChars()); - } - else - { - state.sprite = GetSpriteIndex(sl->Sprite->GetChars()); - } - FCompileContext ctx(OutNamespace, c->Type(), false); - if (CheckRandom(sl->Duration)) - { - auto func = static_cast(sl->Duration); - if (func->Parameters == func->Parameters->SiblingNext || func->Parameters != func->Parameters->SiblingNext->SiblingNext) - { - Error(sl, "Random duration requires exactly 2 parameters"); - } - int v1 = IntConstFromNode(func->Parameters->Value, c->Type()); - int v2 = IntConstFromNode(static_cast(func->Parameters->SiblingNext)->Value, c->Type()); - if (v1 > v2) std::swap(v1, v2); - state.Tics = (int16_t)clamp(v1, 0, INT16_MAX); - state.TicRange = (uint16_t)clamp(v2 - v1, 0, UINT16_MAX); - } - else - { - state.Tics = (int16_t)IntConstFromNode(sl->Duration, c->Type()); - state.TicRange = 0; - } - if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT; - if (sl->bFast) state.StateFlags |= STF_FAST; - if (sl->bSlow) state.StateFlags |= STF_SLOW; - if (sl->bCanRaise) state.StateFlags |= STF_CANRAISE; - if (sl->bNoDelay) state.StateFlags |= STF_NODELAY; - if (sl->bNoDelay) - { - if (statedef.GetStateLabelIndex(NAME_Spawn) != statedef.GetStateCount()) - { - Warn(sl, "NODELAY only has an effect on the first state after 'Spawn:'"); - } - } - if (sl->Offset != nullptr) - { - state.Misc1 = IntConstFromNode(sl->Offset, c->Type()); - state.Misc2 = IntConstFromNode(static_cast(sl->Offset->SiblingNext), c->Type()); - } - - if (sl->Lights != nullptr) - { - auto l = sl->Lights; - do - { - AddStateLight(&state, StringConstFromNode(l, c->Type())); - l = static_cast(l->SiblingNext); - } while (l != sl->Lights); - } - - if (sl->Action != nullptr) - { - auto code = SetupActionFunction(static_cast(c->ClassType()), sl->Action, state.UseFlags); - if (code != nullptr) - { - auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags); - state.ActionFunc = FunctionBuildList.AddFunction(OutNamespace, mVersion, funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump); - } - } - - int count = statedef.AddStates(&state, sl->Frames->GetChars(), *sl); - if (count < 0) - { - Error(sl, "Invalid frame character string '%s'", sl->Frames->GetChars()); - count = -count; - } - break; - } - case AST_StateGoto: - { - auto sg = static_cast(st); - statename = ""; - if (sg->Qualifier != nullptr) - { - statename << FName(sg->Qualifier->Id) << "::"; - } - auto part = sg->Label; - do - { - statename << FName(part->Id) << '.'; - part = static_cast(part->SiblingNext); - } while (part != sg->Label); - statename.Truncate(statename.Len() - 1); // remove the last '.' in the label name - if (sg->Offset != nullptr) - { - int offset = IntConstFromNode(sg->Offset, c->Type()); - if (offset < 0) - { - Error(sg, "GOTO offset must be positive"); - offset = 0; - } - if (offset > 0) - { - statename.AppendFormat("+%d", offset); - } - } - if (!statedef.SetGotoLabel(statename)) - { - Error(sg, "GOTO before first state"); - } - break; - } - case AST_StateFail: - case AST_StateWait: - if (!statedef.SetWait()) - { - Error(st, "%s before first state", st->NodeType == AST_StateFail ? "Fail" : "Wait"); - } - break; - - case AST_StateLoop: - if (!statedef.SetLoop()) - { - Error(st, "LOOP before first state"); - } - break; - - case AST_StateStop: - if (!statedef.SetStop()) - { - Error(st, "STOP before first state"); - } - break; - - default: - assert(0 && "Bad AST node in state"); - } - st = static_cast(st->SiblingNext); - } while (st != s->Body); - } - try - { - FinalizeClass(c->ClassType(), statedef); - } - catch (CRecoverableError &err) - { - Error(c->cls, "%s", err.GetMessage()); - } - } -} - -//========================================================================== -// -// Convert the AST data for the code generator. -// -//========================================================================== - -FxExpression *ZCCCompiler::ConvertAST(PContainerType *cls, ZCC_TreeNode *ast) -{ - ConvertClass = cls; - // there are two possibilities here: either a single function call or a compound statement. For a compound statement we also need to check if the last thing added was a return. - if (ast->NodeType == AST_ExprFuncCall) - { - auto cp = new FxCompoundStatement(*ast); - cp->Add(new FxReturnStatement(ConvertNode(ast), *ast)); - return cp; - } - else - { - // This must be done here so that we can check for a trailing return statement. - auto x = new FxCompoundStatement(*ast); - auto compound = static_cast(ast); - //bool isreturn = false; - auto node = compound->Content; - if (node != nullptr) do - { - x->Add(ConvertNode(node)); - //isreturn = node->NodeType == AST_ReturnStmt; - node = static_cast(node->SiblingNext); - } while (node != compound->Content); - //if (!isreturn) x->Add(new FxReturnStatement(nullptr, *ast)); - return x; - } -} - - -#define xx(a,z) z, -static int Pex2Tok[] = { -#include "zcc_exprlist.h" -}; - -//========================================================================== -// -// Helper for modify/assign operators -// -//========================================================================== - -static FxExpression *ModifyAssign(FxBinary *operation, FxExpression *left) -{ - auto assignself = static_cast(operation->left); - auto assignment = new FxAssign(left, operation, true); - assignself->Assignment = assignment; - return assignment; -} - - -//========================================================================== -// -// Convert an AST node and its children -// -//========================================================================== - -FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute) -{ - if (ast == nullptr) return nullptr; - - switch (ast->NodeType) - { - case AST_ExprFuncCall: - { - auto fcall = static_cast(ast); - - // function names can either be - // - plain identifiers - // - class members - // - array syntax for random() calls. - // Everything else coming here is a syntax error. - FArgumentList args; - switch (fcall->Function->NodeType) - { - case AST_ExprID: - // The function name is a simple identifier. - return new FxFunctionCall(static_cast(fcall->Function)->Identifier, NAME_None, ConvertNodeList(args, fcall->Parameters), *ast); - - case AST_ExprMemberAccess: - { - auto ema = static_cast(fcall->Function); - return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, ConvertNodeList(args, fcall->Parameters), *ast); - } - - case AST_ExprBinary: - // Array syntax for randoms. They are internally stored as ExprBinary with both an identifier on the left and right side. - if (fcall->Function->Operation == PEX_ArrayAccess) - { - auto binary = static_cast(fcall->Function); - if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID) - { - return new FxFunctionCall(static_cast(binary->Left)->Identifier, static_cast(binary->Right)->Identifier, ConvertNodeList(args, fcall->Parameters), *ast); - } - } - // fall through if this isn't an array access node. - - default: - Error(fcall, "Invalid function identifier"); - return new FxNop(*ast); // return something so that the compiler can continue. - } - break; - } - - case AST_ClassCast: - { - auto cc = static_cast(ast); - if (cc->Parameters == nullptr || cc->Parameters->SiblingNext != cc->Parameters) - { - Error(cc, "Class type cast requires exactly one parameter"); - return new FxNop(*ast); // return something so that the compiler can continue. - } - auto cls = PClass::FindClass(cc->ClassName); - if (cls == nullptr || cls->VMType == nullptr) - { - Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars()); - return new FxNop(*ast); // return something so that the compiler can continue. - } - return new FxClassPtrCast(cls, ConvertNode(cc->Parameters)); - } - - case AST_StaticArrayStatement: - { - auto sas = static_cast(ast); - PType *ztype = DetermineType(ConvertClass, sas, sas->Id, sas->Type, false, false); - FArgumentList args; - ConvertNodeList(args, sas->Values); - // This has to let the code generator resolve the constants, not the Simplifier, which lacks all the necessary type info. - return new FxStaticArray(ztype, sas->Id, args, *ast); - } - - case AST_ExprMemberAccess: - { - auto memaccess = static_cast(ast); - return new FxMemberIdentifier(ConvertNode(memaccess->Left), memaccess->Right, *ast); - } - - case AST_FuncParm: - { - auto fparm = static_cast(ast); - auto node = ConvertNode(fparm->Value); - if (fparm->Label != NAME_None) node = new FxNamedNode(fparm->Label, node, *ast); - return node; - } - - case AST_ExprID: - { - auto id = static_cast(ast)->Identifier; - if (id == NAME_LevelLocals && substitute) id = NAME_Level; // All static methods of FLevelLocals are now non-static so remap the name right here before passing it to the backend. - return new FxIdentifier(id, *ast); - } - - case AST_ExprConstant: - { - auto cnst = static_cast(ast); - if (cnst->Type == TypeName) - { - return new FxConstant(FName(ENamedName(cnst->IntVal)), *ast); - } - else if (cnst->Type->isInt()) - { - return new FxConstant(cnst->IntVal, *ast); - } - else if (cnst->Type == TypeBool) - { - return new FxConstant(!!cnst->IntVal, *ast); - } - else if (cnst->Type->isFloat()) - { - return new FxConstant(cnst->DoubleVal, *ast); - } - else if (cnst->Type == TypeString) - { - return new FxConstant(*cnst->StringVal, *ast); - } - else if (cnst->Type == TypeNullPtr) - { - return new FxConstant(*ast); - } - else - { - // can there be other types? - Error(cnst, "Unknown constant type %s", cnst->Type->DescriptiveName()); - return new FxConstant(0, *ast); - } - } - - case AST_ExprUnary: - { - auto unary = static_cast(ast); - auto operand = ConvertNode(unary->Operand); - auto op = unary->Operation; - switch (op) - { - case PEX_PostDec: - case PEX_PostInc: - return new FxPostIncrDecr(operand, Pex2Tok[op]); - - case PEX_PreDec: - case PEX_PreInc: - return new FxPreIncrDecr(operand, Pex2Tok[op]); - - case PEX_Negate: - return new FxMinusSign(operand); - - case PEX_AntiNegate: - return new FxPlusSign(operand); - - case PEX_BitNot: - return new FxUnaryNotBitwise(operand); - - case PEX_BoolNot: - return new FxUnaryNotBoolean(operand); - - case PEX_SizeOf: - case PEX_AlignOf: - return new FxSizeAlign(operand, Pex2Tok[op]); - - default: - assert(0 && "Unknown unary operator."); // should never happen - Error(unary, "Unknown unary operator ID #%d", op); - return new FxNop(*ast); - } - break; - } - - - case AST_ExprBinary: - { - auto binary = static_cast(ast); - auto left = ConvertNode(binary->Left); - auto right = ConvertNode(binary->Right); - auto op = binary->Operation; - auto tok = Pex2Tok[op]; - switch (op) - { - case PEX_Add: - case PEX_Sub: - return new FxAddSub(tok, left, right); - - case PEX_Mul: - case PEX_Div: - case PEX_Mod: - return new FxMulDiv(tok, left, right); - - case PEX_Pow: - return new FxPow(left, right); - - case PEX_LeftShift: - case PEX_RightShift: - case PEX_URightShift: - return new FxShift(tok, left, right); - - case PEX_BitAnd: - case PEX_BitOr: - case PEX_BitXor: - return new FxBitOp(tok, left, right); - - case PEX_BoolOr: - case PEX_BoolAnd: - return new FxBinaryLogical(tok, left, right); - - case PEX_LT: - case PEX_LTEQ: - case PEX_GT: - case PEX_GTEQ: - return new FxCompareRel(tok, left, right); - - case PEX_EQEQ: - case PEX_NEQ: - case PEX_APREQ: - return new FxCompareEq(tok, left, right); - - case PEX_Assign: - return new FxAssign(left, right); - - case PEX_AddAssign: - case PEX_SubAssign: - return ModifyAssign(new FxAddSub(tok, new FxAssignSelf(*ast), right), left); - - case PEX_MulAssign: - case PEX_DivAssign: - case PEX_ModAssign: - return ModifyAssign(new FxMulDiv(tok, new FxAssignSelf(*ast), right), left); - - case PEX_LshAssign: - case PEX_RshAssign: - case PEX_URshAssign: - return ModifyAssign(new FxShift(tok, new FxAssignSelf(*ast), right), left); - - case PEX_AndAssign: - case PEX_OrAssign: - case PEX_XorAssign: - return ModifyAssign(new FxBitOp(tok, new FxAssignSelf(*ast), right), left); - - case PEX_LTGTEQ: - return new FxLtGtEq(left, right); - - case PEX_ArrayAccess: - return new FxArrayElement(left, right); - - case PEX_CrossProduct: - case PEX_DotProduct: - return new FxDotCross(tok, left, right); - - case PEX_Is: - return new FxTypeCheck(left, right); - - case PEX_Concat: - return new FxConcat(left, right); - - default: - I_Error("Binary operator %d not implemented yet", op); - } - break; - } - - case AST_ExprTrinary: - { - auto trinary = static_cast(ast); - auto condition = ConvertNode(trinary->Test); - auto left = ConvertNode(trinary->Left); - auto right = ConvertNode(trinary->Right); - - return new FxConditional(condition, left, right); - } - - case AST_VectorValue: - { - auto vecini = static_cast(ast); - auto xx = ConvertNode(vecini->X); - auto yy = ConvertNode(vecini->Y); - auto zz = ConvertNode(vecini->Z); - return new FxVectorValue(xx, yy, zz, *ast); - } - - case AST_LocalVarStmt: - { - auto loc = static_cast(ast); - auto node = loc->Vars; - FxSequence *list = new FxSequence(*ast); - - PType *ztype = DetermineType(ConvertClass, node, node->Name, loc->Type, true, false); - - if (loc->Type->ArraySize != nullptr) - { - bool nosize; - ztype = ResolveArraySize(ztype, loc->Type->ArraySize, ConvertClass, &nosize); - - if (nosize) - { - Error(node, "Must specify array size"); - } - } - - do - { - PType *type; - - bool nosize = false; - if (node->ArraySize != nullptr) - { - type = ResolveArraySize(ztype, node->ArraySize, ConvertClass, &nosize); - - if (nosize && !node->InitIsArray) - { - Error(node, "Must specify array size for non-initialized arrays"); - } - } - else - { - type = ztype; - } - - if (node->InitIsArray && (type->isArray() || type->isDynArray() || nosize)) - { - auto arrtype = static_cast(type); - if (!nosize && (arrtype->ElementType->isArray() || arrtype->ElementType->isDynArray())) - { - Error(node, "Compound initializer not implemented yet for multi-dimensional arrays"); - } - FArgumentList args; - ConvertNodeList(args, node->Init); - - if (nosize) - { - type = NewArray(type, args.Size()); - } - list->Add(new FxLocalArrayDeclaration(type, node->Name, args, 0, *node)); - } - else - { - FxExpression *val = node->Init ? ConvertNode(node->Init) : nullptr; - list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar. - } - - node = static_cast(node->SiblingNext); - } while (node != loc->Vars); - return list; - } - - case AST_Expression: - { - auto ret = static_cast(ast); - if (ret->Operation == PEX_Super) - { - return new FxSuper(*ast); - } - break; - } - - case AST_ExpressionStmt: - return ConvertNode(static_cast(ast)->Expression); - - case AST_ReturnStmt: - { - auto ret = static_cast(ast); - FArgumentList args; - ConvertNodeList(args, ret->Values); - if (args.Size() == 0) - { - return new FxReturnStatement(nullptr, *ast); - } - else - { - return new FxReturnStatement(args, *ast); - } - } - - case AST_BreakStmt: - case AST_ContinueStmt: - return new FxJumpStatement(ast->NodeType == AST_BreakStmt ? TK_Break : TK_Continue, *ast); - - case AST_IfStmt: - { - auto iff = static_cast(ast); - FxExpression *const truePath = ConvertImplicitScopeNode(ast, iff->TruePath); - FxExpression *const falsePath = ConvertImplicitScopeNode(ast, iff->FalsePath); - return new FxIfStatement(ConvertNode(iff->Condition), truePath, falsePath, *ast); - } - - case AST_IterationStmt: - { - auto iter = static_cast(ast); - if (iter->CheckAt == ZCC_IterationStmt::End) - { - assert(iter->LoopBumper == nullptr); - FxExpression *const loop = ConvertImplicitScopeNode(ast, iter->LoopStatement); - return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), loop, *ast); - } - else if (iter->LoopBumper != nullptr) - { - FArgumentList bumper; - ConvertNodeList(bumper, iter->LoopBumper); - FxCompoundStatement *bumps = new FxCompoundStatement(*ast); - for (auto &ex : bumper) - { - bumps->Add(ex); - ex = nullptr; - } - return new FxForLoop(nullptr, ConvertNode(iter->LoopCondition), bumps, ConvertNode(iter->LoopStatement), *ast); - } - else - { - FxExpression *const loop = ConvertImplicitScopeNode(ast, iter->LoopStatement); - return new FxWhileLoop(ConvertNode(iter->LoopCondition), loop, *ast); - } - } - - // not yet done - case AST_SwitchStmt: - { - auto swtch = static_cast(ast); - if (swtch->Content->NodeType != AST_CompoundStmt) - { - Error(ast, "Expecting { after 'switch'"); - return new FxNop(*ast); // allow compiler to continue looking for errors. - } - else - { - // The switch content is wrapped into a compound statement which needs to be unraveled here. - auto cmpnd = static_cast(swtch->Content); - FArgumentList args; - return new FxSwitchStatement(ConvertNode(swtch->Condition), ConvertNodeList(args, cmpnd->Content), *ast); - } - } - - case AST_CaseStmt: - { - auto cases = static_cast(ast); - return new FxCaseStatement(ConvertNode(cases->Condition), *ast); - } - - case AST_CompoundStmt: - { - auto x = new FxCompoundStatement(*ast); - auto compound = static_cast(ast); - auto node = compound->Content; - if (node != nullptr) do - { - x->Add(ConvertNode(node)); - node = static_cast(node->SiblingNext); - } while (node != compound->Content); - return x; - } - - case AST_AssignStmt: - { - auto ass = static_cast(ast); - FArgumentList args; - ConvertNodeList(args, ass->Dests); - assert(ass->Sources->SiblingNext == ass->Sources); // right side should be a single function call - nothing else - if (ass->Sources->NodeType != AST_ExprFuncCall) - { - // don't let this through to the code generator. This node is only used to assign multiple returns of a function to more than one variable. - Error(ass, "Right side of multi-assignment must be a function call"); - return new FxNop(*ast); // allow compiler to continue looking for errors. - } - return new FxMultiAssign(args, ConvertNode(ass->Sources), *ast); - } - - default: - break; - } - // only for development. I_Error is more convenient here than a normal error. - I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType); - return nullptr; -} - -//========================================================================== -// -// Wrapper around ConvertNode() that adds a scope (a compound statement) -// when needed to avoid leaking of variable or contant to an outer scope: -// -// if (true) int i; else bool b[1]; -// while (false) readonly a; -// do static const float f[] = {0}; while (false); -// -// Accessing such variables outside of their statements is now an error -// -//========================================================================== - -FxExpression *ZCCCompiler::ConvertImplicitScopeNode(ZCC_TreeNode *node, ZCC_Statement *nested) -{ - assert(nullptr != node); - - if (nullptr == nested) - { - return nullptr; - } - - FxExpression *nestedExpr = ConvertNode(nested); - assert(nullptr != nestedExpr); - - const EZCCTreeNodeType nestedType = nested->NodeType; - const bool needScope = AST_LocalVarStmt == nestedType || AST_StaticArrayStatement == nestedType; - - if (needScope) - { - FxCompoundStatement *implicitCompound = new FxCompoundStatement(*node); - implicitCompound->Add(nestedExpr); - - nestedExpr = implicitCompound; - } - - return nestedExpr; -} - - -FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *head) -{ - if (head != nullptr) - { - auto node = head; - do - { - args.Push(ConvertNode(node)); - node = node->SiblingNext; - } while (node != head); - } - return args; -} diff --git a/src/scripting/zscript/zcc_compile_doom.cpp b/src/scripting/zscript/zcc_compile_doom.cpp new file mode 100644 index 00000000000..4becfc4fe1a --- /dev/null +++ b/src/scripting/zscript/zcc_compile_doom.cpp @@ -0,0 +1,1282 @@ +/* +** zcc_compile_doom.cpp +** +** contains the Doom specific parts of the script parser, i.e. +** actor property definitions and associated content. +** +**--------------------------------------------------------------------------- +** Copyright 2016-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "a_pickups.h" +#include "thingdef.h" +#include "c_console.h" +#include "filesystem.h" +#include "zcc_parser.h" +#include "zcc-parse.h" +#include "zcc_compile_doom.h" +#include "v_text.h" +#include "p_lnspec.h" +#include "v_video.h" + + +bool isActor(PContainerType *type); +void AddActorInfo(PClass *cls); +int GetIntConst(FxExpression* ex, FCompileContext& ctx); +double GetFloatConst(FxExpression* ex, FCompileContext& ctx); +VMFunction* GetFuncConst(FxExpression* ex, FCompileContext& ctx); + +//========================================================================== +// +// ZCCCompiler :: Compile +// +// Compile everything defined at this level. +// +//========================================================================== + +int ZCCDoomCompiler::Compile() +{ + CreateClassTypes(); + CreateStructTypes(); + CompileAllConstants(); + CompileAllFields(); + CompileAllProperties(); + InitDefaults(); + InitFunctions(); + CompileStates(); + InitDefaultFunctionPointers(); + return FScriptPosition::ErrorCounter; +} + + +//========================================================================== +// +// ZCCCompiler :: CompileAllProperties +// +// builds the property lists of all actor classes +// +//========================================================================== + +void ZCCDoomCompiler::CompileAllProperties() +{ + for (auto c : Classes) + { + if (c->Properties.Size() > 0) + CompileProperties(c->ClassType(), c->Properties, c->Type()->TypeName); + + if (c->FlagDefs.Size() > 0) + CompileFlagDefs(c->ClassType(), c->FlagDefs, c->Type()->TypeName); + + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileProperties +// +// builds the internal structure of a single class or struct +// +//========================================================================== + +bool ZCCDoomCompiler::CompileProperties(PClass *type, TArray &Properties, FName prefix) +{ + if (!type->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + Error(Properties[0], "Properties can only be defined for actors"); + return false; + } + for(auto p : Properties) + { + TArray fields; + ZCC_Identifier *id = (ZCC_Identifier *)p->Body; + + if (FName(p->NodeName) == FName("prefix") && fileSystem.GetFileContainer(Lump) == 0) + { + // only for internal definitions: Allow setting a prefix. This is only for compatiblity with the old DECORATE property parser, but not for general use. + prefix = id->Id; + } + else + { + do + { + auto f = dyn_cast(type->FindSymbol(id->Id, true)); + if (f == nullptr) + { + Error(id, "Variable %s not found in %s", FName(id->Id).GetChars(), type->TypeName.GetChars()); + } + fields.Push(f); + id = (ZCC_Identifier*)id->SiblingNext; + } while (id != p->Body); + + FString qualifiedname; + // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. + // All these will be removed from the symbol table after the compiler finishes to free up the allocated space. + FName name = FName(p->NodeName); + if (prefix == NAME_None) qualifiedname.Format("@property@%s", name.GetChars()); + else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars()); + + fields.ShrinkToFit(); + if (!type->VMType->Symbols.AddSymbol(Create(qualifiedname, fields))) + { + Error(id, "Unable to add property %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); + } + } + } + return true; +} + +//========================================================================== +// +// ZCCCompiler :: CompileProperties +// +// builds the internal structure of a single class or struct +// +//========================================================================== + +bool ZCCDoomCompiler::CompileFlagDefs(PClass *type, TArray &Properties, FName prefix) +{ + if (!type->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + Error(Properties[0], "Flags can only be defined for actors"); + return false; + } + for (auto p : Properties) + { + PField *field; + FName referenced = FName(p->RefName); + + if (FName(p->NodeName) == FName("prefix") && fileSystem.GetFileContainer(Lump) == 0) + { + // only for internal definitions: Allow setting a prefix. This is only for compatiblity with the old DECORATE property parser, but not for general use. + prefix = referenced; + } + else + { + if (referenced != NAME_None) + { + field = dyn_cast(type->FindSymbol(referenced, true)); + if (field == nullptr) + { + Error(p, "Variable %s not found in %s", referenced.GetChars(), type->TypeName.GetChars()); + } + else if (!field->Type->isInt() || field->Type->Size != 4) + { + Error(p, "Variable %s in %s must have a size of 4 bytes for use as flag storage", referenced.GetChars(), type->TypeName.GetChars()); + } + } + else field = nullptr; + + + FString qualifiedname; + // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. + // All these will be removed from the symbol table after the compiler finishes to free up the allocated space. + FName name = FName(p->NodeName); + for (int i = 0; i < 2; i++) + { + if (i == 0) qualifiedname.Format("@flagdef@%s", name.GetChars()); + else + { + if (prefix == NAME_None) continue; + qualifiedname.Format("@flagdef@%s.%s", prefix.GetChars(), name.GetChars()); + } + + if (!type->VMType->Symbols.AddSymbol(Create(qualifiedname, field, p->BitValue, i == 0 && prefix != NAME_None))) + { + Error(p, "Unable to add flag definition %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); + } + } + + if (field != nullptr) + type->VMType->AddNativeField(FStringf("b%s", name.GetChars()), TypeSInt32, field->Offset, 0, 1 << p->BitValue); + } + } + return true; +} + +//========================================================================== +// +// Parses an actor property's parameters and calls the handler +// +//========================================================================== + +void ZCCDoomCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag) +{ + static TArray params; + static TArray strings; + + params.Clear(); + strings.Clear(); + params.Reserve(1); + params[0].i = 0; + if (prop->params[0] != '0') + { + if (property->Values == nullptr) + { + Error(property, "%s: arguments missing", prop->name); + return; + } + const char * p = prop->params; + auto exp = property->Values; + + FCompileContext ctx(OutNamespace, bag.Info->VMType, false, mVersion); + while (true) + { + FPropParam conv; + FPropParam pref; + + FxExpression *ex = ConvertNode(exp); + ex = ex->Resolve(ctx); + if (ex == nullptr) + { + return; + } + else if (!ex->isConstant()) + { + // If we get TypeError, there has already been a message from deeper down so do not print another one. + if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->name); + return; + } + conv.s = nullptr; + pref.s = nullptr; + pref.i = -1; + switch ((*p) & 223) + { + + case 'X': // Expression in parentheses or number. We only support the constant here. The function will have to be handled by a separate property to get past the parser. + conv.i = GetIntConst(ex, ctx); + params.Push(conv); + conv.exp = nullptr; + break; + + case 'I': + case 'M': // special case for morph styles in DECORATE . This expression-aware parser will not need this. + case 'N': // special case for thing activations in DECORATE. This expression-aware parser will not need this. + conv.i = GetIntConst(ex, ctx); + break; + + case 'F': + conv.d = GetFloatConst(ex, ctx); + break; + + case 'G': + conv.fu = GetFuncConst(ex, ctx); + break; + + case 'Z': // an optional string. Does not allow any numeric value. + if (ex->ValueType != TypeString) + { + // apply this expression to the next argument on the list. + params.Push(conv); + params[0].i++; + p++; + continue; + } + conv.s = GetStringConst(ex, ctx); + break; + + case 'C': // this parser accepts colors only in string form. + pref.i = 1; + [[fallthrough]]; + case 'S': + case 'T': // a filtered string (ZScript only parses filtered strings so there's nothing to do here.) + conv.s = GetStringConst(ex, ctx); + break; + + case 'L': // Either a number or a list of strings + if (ex->ValueType != TypeString) + { + pref.i = 0; + conv.i = GetIntConst(ex, ctx); + } + else + { + pref.i = 1; + params.Push(pref); + params[0].i++; + + do + { + conv.s = GetStringConst(ex, ctx); + if (conv.s != nullptr) + { + params.Push(conv); + params[0].i++; + } + exp = static_cast(exp->SiblingNext); + if (exp != property->Values) + { + ex = ConvertNode(exp); + ex = ex->Resolve(ctx); + if (ex == nullptr) return; + } + } while (exp != property->Values); + goto endofparm; + } + break; + + default: + assert(false); + break; + + } + if (pref.i != -1) + { + params.Push(pref); + params[0].i++; + } + params.Push(conv); + params[0].i++; + exp = static_cast(exp->SiblingNext); + endofparm: + p++; + // Skip the DECORATE 'no comma' marker + if (*p == '_') p++; + + if (*p == 0) + { + if (exp != property->Values) + { + Error(property, "Too many values for '%s'", prop->name); + return; + } + break; + } + else if (exp == property->Values) + { + if (*p < 'a') + { + Error(property, "Insufficient parameters for %s", prop->name); + return; + } + break; + } + } + } + // call the handler + try + { + prop->Handler(defaults, bag.Info, bag, ¶ms[0]); + } + catch (CRecoverableError &error) + { + Error(property, "%s", error.GetMessage()); + } +} + + +//========================================================================== +// +// Parses an actor property's parameters and calls the handler +// +//========================================================================== + +PFunction * FindFunctionPointer(PClass * cls, int fn_name); +PFunction *NativeFunctionPointerCast(PFunction *from, const PFunctionPointer *to); + +struct FunctionPointerProperties +{ + ZCC_PropertyStmt *prop; + PClass * cls; + FName name; + const PFunctionPointer * type; + PFunction ** addr; +}; + +TArray DefaultFunctionPointers; + +void ZCCDoomCompiler::InitDefaultFunctionPointers() +{ + for(auto &d : DefaultFunctionPointers) + { + PFunction * fn = FindFunctionPointer(d.cls, d.name.GetIndex()); + if(!fn) + { + Error(d.prop, "Could not find function '%s' in class '%s'",d.name.GetChars(), d.cls->TypeName.GetChars()); + } + else + { + PFunction * casted = NativeFunctionPointerCast(fn,d.type); + if(!casted) + { + FString fn_proto_name = PFunctionPointer::GenerateNameForError(fn); + Error(d.prop, "Function has incompatible types, cannot convert from '%s' to '%s'",fn_proto_name.GetChars(), d.type->DescriptiveName()); + } + else + { + (*d.addr) = casted; + } + } + } + DefaultFunctionPointers.Clear(); +} + +void ZCCDoomCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag) +{ + ZCC_ExprConstant one; + unsigned parmcount = 1; + ZCC_TreeNode *x = property->Values; + if (x == nullptr) + { + parmcount = 0; + } + else + { + while (x->SiblingNext != property->Values) + { + x = x->SiblingNext; + parmcount++; + } + } + if (parmcount == 0 && prop->Variables.Size() == 1 && prop->Variables[0]->Type == TypeBool) + { + // allow boolean properties to have the parameter omitted + memset(&one, 0, sizeof(one)); + one.SourceName = property->SourceName; // This may not be null! + one.Operation = PEX_ConstValue; + one.NodeType = AST_ExprConstant; + one.Type = TypeBool; + one.IntVal = 1; + property->Values = &one; + } + else if (parmcount != prop->Variables.Size()) + { + Error(x == nullptr? property : x, "Argument count mismatch: Got %u, expected %u", parmcount, prop->Variables.Size()); + return; + } + + auto exp = property->Values; + FCompileContext ctx(OutNamespace, bag.Info->VMType, false, mVersion); + for (auto f : prop->Variables) + { + void *addr; + if (f == nullptr) + { + // This variable was missing. The error had been reported for the property itself already. + return; + } + + if (f->Flags & VARF_Meta) + { + addr = ((char*)bag.Info->Meta) + f->Offset; + } + else + { + addr = ((char*)defaults) + f->Offset; + } + + FxExpression *ex = ConvertNode(exp); + ex = ex->Resolve(ctx); + if (ex == nullptr) + { + return; + } + else if (!ex->isConstant()) + { + if (ex->ExprType == EFX_VectorValue && ex->ValueType == f->Type) + { + auto v = static_cast(ex); + if (f->Type == TypeVector2) + { + if(!v->isConstVector(2)) + { + Error(exp, "%s: non-constant Vector2 parameter", prop->SymbolName.GetChars()); + return; + } + (*(DVector2*)addr) = DVector2( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat() + ); + goto vector_ok; + } + else if (f->Type == TypeFVector2) + { + if(!v->isConstVector(2)) + { + Error(exp, "%s: non-constant FVector2 parameter", prop->SymbolName.GetChars()); + return; + } + (*(FVector2*)addr) = FVector2( + float(static_cast(v->xyzw[0])->GetValue().GetFloat()), + float(static_cast(v->xyzw[1])->GetValue().GetFloat()) + ); + goto vector_ok; + } + else if (f->Type == TypeVector3) + { + if(!v->isConstVector(3)) + { + Error(exp, "%s: non-constant Vector3 parameter", prop->SymbolName.GetChars()); + return; + } + (*(DVector3*)addr) = DVector3( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat(), + static_cast(v->xyzw[2])->GetValue().GetFloat() + ); + goto vector_ok; + } + else if (f->Type == TypeFVector3) + { + if(!v->isConstVector(3)) + { + Error(exp, "%s: non-constant FVector3 parameter", prop->SymbolName.GetChars()); + return; + } + (*(FVector3*)addr) = FVector3( + float(static_cast(v->xyzw[0])->GetValue().GetFloat()), + float(static_cast(v->xyzw[1])->GetValue().GetFloat()), + float(static_cast(v->xyzw[2])->GetValue().GetFloat()) + ); + goto vector_ok; + } + else if (f->Type == TypeVector4) + { + if(!v->isConstVector(4)) + { + Error(exp, "%s: non-constant Vector4 parameter", prop->SymbolName.GetChars()); + return; + } + (*(DVector4*)addr) = DVector4( + static_cast(v->xyzw[0])->GetValue().GetFloat(), + static_cast(v->xyzw[1])->GetValue().GetFloat(), + static_cast(v->xyzw[2])->GetValue().GetFloat(), + static_cast(v->xyzw[3])->GetValue().GetFloat() + ); + goto vector_ok; + } + else if (f->Type == TypeFVector4) + { + if(!v->isConstVector(4)) + { + Error(exp, "%s: non-constant FVector4 parameter", prop->SymbolName.GetChars()); + return; + } + (*(FVector4*)addr) = FVector4( + float(static_cast(v->xyzw[0])->GetValue().GetFloat()), + float(static_cast(v->xyzw[1])->GetValue().GetFloat()), + float(static_cast(v->xyzw[2])->GetValue().GetFloat()), + float(static_cast(v->xyzw[3])->GetValue().GetFloat()) + ); + goto vector_ok; + } + else + { + Error(exp, "%s: invalid vector parameter", prop->SymbolName.GetChars()); + return; + } + } + else + { + if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars()); + return; + } + // If we get TypeError, there has already been a message from deeper down so do not print another one. + } + + if (f->Type == TypeBool) + { + static_cast(f->Type)->SetValue(addr, !!GetIntConst(ex, ctx)); + } + else if (f->Type == TypeName) + { + *(FName*)addr = GetStringConst(ex, ctx); + } + else if (f->Type == TypeSound) + { + *(FSoundID*)addr = S_FindSound(GetStringConst(ex, ctx)); + } + else if (f->Type == TypeColor && ex->ValueType == TypeString) // colors can also be specified as ints. + { + *(PalEntry*)addr = V_GetColor(GetStringConst(ex, ctx), &ex->ScriptPosition); + } + else if (f->Type->isIntCompatible()) + { + static_cast(f->Type)->SetValue(addr, GetIntConst(ex, ctx)); + } + else if (f->Type->isFloat()) + { + static_cast(f->Type)->SetValue(addr, GetFloatConst(ex, ctx)); + } + else if (f->Type == TypeString) + { + *(FString*)addr = GetStringConst(ex, ctx); + } + else if (f->Type->isClassPointer()) + { + auto clsname = GetStringConst(ex, ctx); + if (*clsname == 0 || !stricmp(clsname, "none")) + { + *(PClass**)addr = nullptr; + } + else + { + auto cls = PClass::FindClass(clsname); + auto cp = static_cast(f->Type); + if (cls == nullptr) + { + cls = cp->ClassRestriction->FindClassTentative(clsname); + } + else if (!cls->IsDescendantOf(cp->ClassRestriction)) + { + Error(property, "class %s is not compatible with property type %s", clsname, cp->ClassRestriction->TypeName.GetChars()); + } + *(PClass**)addr = cls; + } + } + else if (f->Type->isFunctionPointer()) + { + const char * fn_str = GetStringConst(ex, ctx); + if (*fn_str == 0 || !stricmp(fn_str, "none")) + { + *(PFunction**)addr = nullptr; + } + else + { + TArray fn_info(FString(fn_str).Split("::", FString::TOK_SKIPEMPTY)); + if(fn_info.Size() != 2) + { + Error(property, "Malformed function pointer property \"%s\", must be \"Class::Function\"",fn_str); + } + PClass * cls = PClass::FindClass(fn_info[0]); + if(!cls) + { + Error(property, "Could not find class '%s'",fn_info[0].GetChars()); + *(PFunction**)addr = nullptr; + } + else + { + FName fn_name(fn_info[1], true); + if(fn_name.GetIndex() == 0) + { + Error(property, "Could not find function '%s' in class '%s'",fn_info[1].GetChars(),fn_info[0].GetChars()); + *(PFunction**)addr = nullptr; + } + else + { + DefaultFunctionPointers.Push({property, cls, fn_name, static_cast(f->Type), (PFunction**)addr}); + *(PFunction**)addr = nullptr; + } + + } + } + + } + else + { + Error(property, "unhandled property type %s", f->Type->DescriptiveName()); + } +vector_ok: + exp->ToErrorNode(); // invalidate after processing. + exp = static_cast(exp->SiblingNext); + } +} + +//========================================================================== +// +// Parses an actor property +// +//========================================================================== + +void ZCCDoomCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *prop, Baggage &bag) +{ + auto namenode = prop->Prop; + FString propname; + + if (namenode->SiblingNext == namenode) + { + if (namenode->Id == NAME_DamageFunction) + { + auto x = ConvertNode(prop->Values); + CreateDamageFunction(OutNamespace, mVersion, cls, (AActor *)bag.Info->Defaults, x, false, Lump); + ((AActor *)bag.Info->Defaults)->DamageVal = -1; + return; + } + + // a one-name property + propname = FName(namenode->Id).GetChars(); + + } + else if (namenode->SiblingNext->SiblingNext == namenode) + { + // a two-name property + propname << FName(namenode->Id).GetChars() << "." << FName(static_cast(namenode->SiblingNext)->Id).GetChars(); + } + else + { + Error(prop, "Property name may at most contain two parts"); + return; + } + + + FPropertyInfo *property = FindProperty(propname.GetChars()); + + if (property != nullptr && property->category != CAT_INFO) + { + auto pcls = PClass::FindActor(property->clsname); + if (cls->IsDescendantOf(pcls)) + { + DispatchProperty(property, prop, (AActor *)bag.Info->Defaults, bag); + } + else + { + Error(prop, "'%s' requires an actor of type '%s'\n", propname.GetChars(), pcls->TypeName.GetChars()); + } + } + else + { + propname.Insert(0, "@property@"); + FName name(propname, true); + if (name != NAME_None) + { + auto propp = dyn_cast(cls->FindSymbol(name, true)); + if (propp != nullptr) + { + DispatchScriptProperty(propp, prop, (AActor *)bag.Info->Defaults, bag); + return; + } + } + Error(prop, "'%s' is an unknown actor property\n", propname.GetChars()); + } +} + +//========================================================================== +// +// Finds a flag and sets or clears it +// +//========================================================================== + +void ZCCDoomCompiler::ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg) +{ + auto namenode = flg->name; + const char *n1 = FName(namenode->Id).GetChars(), *n2; + + if (namenode->SiblingNext == namenode) + { + // a one-name flag + n2 = nullptr; + } + else if (namenode->SiblingNext->SiblingNext == namenode) + { + // a two-name flag + n2 = FName(static_cast(namenode->SiblingNext)->Id).GetChars(); + } + else + { + Error(flg, "Flag name may at most contain two parts"); + return; + } + + auto fd = FindFlag(cls, n1, n2, true); + if (fd != nullptr) + { + if (fd->varflags & VARF_Deprecated) + { + Warn(flg, "Deprecated flag '%s%s%s' used", n1, n2 ? "." : "", n2 ? n2 : ""); + } + if (fd->structoffset == -1) + { + HandleDeprecatedFlags((AActor*)cls->Defaults, cls, flg->set, fd->flagbit); + } + else + { + ModActorFlag((AActor*)cls->Defaults, fd, flg->set); + } + } + else + { + Error(flg, "Unknown flag '%s%s%s'", n1, n2 ? "." : "", n2 ? n2 : ""); + } +} + +//========================================================================== +// +// Parses the default list +// +//========================================================================== + +void ZCCDoomCompiler::InitDefaults() +{ + for (auto c : Classes) + { + // This may be removed if the conditions change, but right now only subclasses of Actor can define a Default block. + if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->ClassType()->TypeName.GetChars()); + if (c->ClassType()->ParentClass) + { + auto ti = c->ClassType(); + ti->InitializeDefaults(); + } + } + else + { + auto cls = c->ClassType(); + // This should never happen. + if (cls->Defaults != nullptr) + { + Error(c->cls, "%s already has defaults", cls->TypeName.GetChars()); + } + // This can only occur if a native parent is not initialized. In all other cases the sorting of the class list should prevent this from ever happening. + else if (cls->ParentClass->Defaults == nullptr && cls != RUNTIME_CLASS(AActor)) + { + Error(c->cls, "Parent class %s of %s is not initialized", cls->ParentClass->TypeName.GetChars(), cls->TypeName.GetChars()); + } + else + { + // Copy the parent's defaults and meta data. + auto ti = static_cast(cls); + + ti->InitializeDefaults(); + + // Replacements require that the meta data has been allocated by InitializeDefaults. + if (c->cls->Replaces != nullptr && !ti->SetReplacement(c->cls->Replaces->Id)) + { + Warn(c->cls, "Replaced type '%s' not found for %s", FName(c->cls->Replaces->Id).GetChars(), ti->TypeName.GetChars()); + } + + // We need special treatment for this one field in AActor's defaults which cannot be made visible to DECORATE as a property. + // It's better to do this here under controlled conditions than deeper down in the class type classes. + if (ti == RUNTIME_CLASS(AActor)) + { + ((AActor*)ti->Defaults)->ConversationRoot = 1; + } + + Baggage bag; + #ifdef _DEBUG + bag.ClassName = cls->TypeName.GetChars(); + #endif + bag.Version = mVersion; + bag.Namespace = OutNamespace; + bag.Info = ti; + bag.DropItemSet = false; + bag.StateSet = false; + bag.fromDecorate = false; + bag.CurrentState = 0; + bag.Lumpnum = c->cls->SourceLump; + bag.DropItemList = nullptr; + // The actual script position needs to be set per property. + + for (auto d : c->Defaults) + { + auto content = d->Content; + if (content != nullptr) do + { + switch (content->NodeType) + { + case AST_PropertyStmt: + bag.ScriptPosition.FileName = *content->SourceName; + bag.ScriptPosition.ScriptLine = content->SourceLoc; + ProcessDefaultProperty(ti, static_cast(content), bag); + break; + + case AST_FlagStmt: + ProcessDefaultFlag(ti, static_cast(content)); + break; + + default: + break; + } + content = static_cast(content->SiblingNext); + } while (content != d->Content); + } + if (bag.DropItemSet) + { + bag.Info->SetDropItems(bag.DropItemList); + } + } + } + } +} + +//========================================================================== +// +// very complicated check for random duration. +// +//========================================================================== + +static bool CheckRandom(ZCC_Expression *duration) +{ + if (duration->NodeType != AST_ExprFuncCall) return false; + auto func = static_cast(duration); + if (func->Function == nullptr) return false; + if (func->Function->NodeType != AST_ExprID) return false; + auto f2 = static_cast(func->Function); + return f2->Identifier == NAME_Random; +} + +//========================================================================== +// +// Sets up the action function call +// +//========================================================================== +FxExpression *ZCCDoomCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, int StateFlags) +{ + // We have 3 cases to consider here: + // 1. A function without parameters. This can be called directly + // 2. A functon with parameters. This needs to be wrapped into a helper function to set everything up. + // 3. An anonymous function. + + // 1. and 2. are exposed through AST_ExprFunctionCall + if (af->NodeType == AST_ExprFuncCall) + { + auto fc = static_cast(af); + assert(fc->Function->NodeType == AST_ExprID); + auto id = static_cast(fc->Function); + + // We must skip ACS_NamedExecuteWithResult here, because this name both exists as an action function and as a builtin. + // The code which gets called from here can easily make use of the builtin, so let's just pass this name without any checks. + // The actual action function is still needed by DECORATE: + if (id->Identifier != NAME_ACS_NamedExecuteWithResult) + { + PFunction *afd = dyn_cast(cls->VMType->Symbols.FindSymbol(id->Identifier, true)); + if (afd != nullptr) + { + if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual)) + { + FArgumentList argumentlist; + // We can use this function directly without wrapping it in a caller. + assert(PType::toClass(afd->Variants[0].SelfClass) != nullptr); // non classes are not supposed to get here. + + int comboflags = afd->Variants[0].UseFlags & StateFlags; + if (comboflags == StateFlags) // the function must satisfy all the flags the state requires + { + if ((afd->Variants[0].Flags & VARF_Private) && afd->OwningClass != cls->VMType) + { + Error(af, "%s is declared private and not accessible", FName(id->Identifier).GetChars()); + } + + return new FxVMFunctionCall(new FxSelf(*af), afd, argumentlist, *af, false); + } + else + { + Error(af, "Cannot use non-action function %s here.", FName(id->Identifier).GetChars()); + } + } + } + else + { + // it may also be an action special so check that first before printing an error. + if (!P_FindLineSpecial(FName(id->Identifier).GetChars())) + { + Error(af, "%s: action function not found in %s", FName(id->Identifier).GetChars(), cls->TypeName.GetChars()); + return nullptr; + } + // Action specials fall through to the code generator. + } + } + } + return ConvertAST(cls->VMType, af); +} + +//========================================================================== +// +// Compile the states +// +//========================================================================== + +void ZCCDoomCompiler::CompileStates() +{ + for (auto c : Classes) + { + + if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + if (c->States.Size()) Error(c->cls, "%s: States can only be defined for actors.", c->Type()->TypeName.GetChars()); + continue; + } + + FString statename; // The state builder wants the label as one complete string, not separated into tokens. + FStateDefinitions statedef; + + if (static_cast(c->ClassType())->ActorInfo()->SkipSuperSet) + { + // SKIP_SUPER'ed actors only get the base states from AActor. + statedef.MakeStateDefines(RUNTIME_CLASS(AActor)); + } + else + { + statedef.MakeStateDefines(ValidateActor(c->ClassType()->ParentClass)); + } + + + int numframes = 0; + + for (auto s : c->States) + { + int flags; + if (s->Flags != nullptr) + { + flags = 0; + auto p = s->Flags; + do + { + switch (p->Id) + { + case NAME_Actor: + flags |= SUF_ACTOR; + break; + case NAME_Overlay: + flags |= SUF_OVERLAY; + break; + case NAME_Weapon: + flags |= SUF_WEAPON; + break; + case NAME_Item: + flags |= SUF_ITEM; + break; + default: + Error(p, "Unknown States qualifier %s", FName(p->Id).GetChars()); + break; + } + + p = static_cast(p->SiblingNext); + } while (p != s->Flags); + } + else + { + flags = static_cast(c->ClassType())->ActorInfo()->DefaultStateUsage; + } + auto st = s->Body; + if (st != nullptr) do + { + switch (st->NodeType) + { + case AST_StateLabel: + { + auto sl = static_cast(st); + statename = FName(sl->Label).GetChars(); + statedef.AddStateLabel(statename.GetChars()); + break; + } + case AST_StateLine: + { + auto sl = static_cast(st); + FState state; + memset(&state, 0, sizeof(state)); + state.UseFlags = flags; + if (sl->Sprite->Len() != 4) + { + Error(sl, "Sprite name must be exactly 4 characters. Found '%s'", sl->Sprite->GetChars()); + } + else + { + state.sprite = GetSpriteIndex(sl->Sprite->GetChars()); + } + FCompileContext ctx(OutNamespace, c->Type(), false, mVersion); + if (CheckRandom(sl->Duration)) + { + auto func = static_cast(sl->Duration); + if (func->Parameters == func->Parameters->SiblingNext || func->Parameters != func->Parameters->SiblingNext->SiblingNext) + { + Error(sl, "Random duration requires exactly 2 parameters"); + } + int v1 = IntConstFromNode(func->Parameters->Value, c->Type()); + int v2 = IntConstFromNode(static_cast(func->Parameters->SiblingNext)->Value, c->Type()); + if (v1 > v2) std::swap(v1, v2); + state.Tics = (int16_t)clamp(v1, 0, INT16_MAX); + state.TicRange = (uint16_t)clamp(v2 - v1, 0, UINT16_MAX); + } + else + { + state.Tics = (int16_t)IntConstFromNode(sl->Duration, c->Type()); + state.TicRange = 0; + } + if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT; + if (sl->bFast) state.StateFlags |= STF_FAST; + if (sl->bSlow) state.StateFlags |= STF_SLOW; + if (sl->bCanRaise) state.StateFlags |= STF_CANRAISE; + if (sl->bNoDelay) state.StateFlags |= STF_NODELAY; + if (sl->bNoDelay) + { + if (statedef.GetStateLabelIndex(NAME_Spawn) != statedef.GetStateCount()) + { + Warn(sl, "NODELAY only has an effect on the first state after 'Spawn:'"); + } + } + if (sl->Offset != nullptr) + { + state.Misc1 = IntConstFromNode(sl->Offset, c->Type()); + state.Misc2 = IntConstFromNode(static_cast(sl->Offset->SiblingNext), c->Type()); + } + + if (sl->Lights != nullptr) + { + auto l = sl->Lights; + do + { + AddStateLight(&state, StringConstFromNode(l, c->Type()).GetChars()); + l = static_cast(l->SiblingNext); + } while (l != sl->Lights); + } + + if (sl->Action != nullptr) + { + auto code = SetupActionFunction(static_cast(c->ClassType()), sl->Action, state.UseFlags); + if (code != nullptr) + { + auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags); + state.ActionFunc = FunctionBuildList.AddFunction(OutNamespace, mVersion, funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump); + } + } + + int count = statedef.AddStates(&state, sl->Frames->GetChars(), *sl); + if (count < 0) + { + Error(sl, "Invalid frame character string '%s'", sl->Frames->GetChars()); + count = -count; + } + break; + } + case AST_StateGoto: + { + auto sg = static_cast(st); + statename = ""; + if (sg->Qualifier != nullptr) + { + statename << FName(sg->Qualifier->Id).GetChars() << "::"; + } + auto part = sg->Label; + do + { + statename << FName(part->Id).GetChars() << '.'; + part = static_cast(part->SiblingNext); + } while (part != sg->Label); + statename.Truncate(statename.Len() - 1); // remove the last '.' in the label name + if (sg->Offset != nullptr) + { + int offset = IntConstFromNode(sg->Offset, c->Type()); + if (offset < 0) + { + Error(sg, "GOTO offset must be positive"); + offset = 0; + } + if (offset > 0) + { + statename.AppendFormat("+%d", offset); + } + } + if (!statedef.SetGotoLabel(statename.GetChars())) + { + Error(sg, "GOTO before first state"); + } + break; + } + case AST_StateFail: + case AST_StateWait: + if (!statedef.SetWait()) + { + Error(st, "%s before first state", st->NodeType == AST_StateFail ? "Fail" : "Wait"); + } + break; + + case AST_StateLoop: + if (!statedef.SetLoop()) + { + Error(st, "LOOP before first state"); + } + break; + + case AST_StateStop: + if (!statedef.SetStop()) + { + Error(st, "STOP before first state"); + } + break; + + default: + assert(0 && "Bad AST node in state"); + } + st = static_cast(st->SiblingNext); + } while (st != s->Body); + } + try + { + FinalizeClass(c->ClassType(), statedef); + } + catch (CRecoverableError &err) + { + Error(c->cls, "%s", err.GetMessage()); + } + } +} + +//========================================================================== +// +// 'action' is a Doom specific keyword. The default implementation just +// errors out on it +// +//========================================================================== + +int ZCCDoomCompiler::CheckActionKeyword(ZCC_FuncDeclarator* f, uint32_t &varflags, int useflags, ZCC_StructWork *c) +{ + if (varflags & VARF_ReadOnly) + { + Error(f, "Action functions cannot be declared const"); + varflags &= ~VARF_ReadOnly; + } + if (varflags & VARF_UI) + { + Error(f, "Action functions cannot be declared UI"); + } + // Non-Actors cannot have action functions. + if (!isActor(c->Type())) + { + Error(f, "'Action' can only be used in child classes of Actor"); + } + + varflags |= VARF_Final; // Action implies Final. + if (useflags & (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) + { + varflags |= VARF_Action; + return 3; + } + else + { + return 1; + } +} + +//========================================================================== +// +// AActor needs the actor info manually added to its meta data +// before adding any scripted fields. +// +//========================================================================== + +bool ZCCDoomCompiler::PrepareMetaData(PClass *type) +{ + if (type->TypeName == NAME_Actor) + { + assert(type->MetaSize == 0); + AddActorInfo(type); + return true; + } + return false; +} + diff --git a/src/scripting/zscript/zcc_compile_doom.h b/src/scripting/zscript/zcc_compile_doom.h new file mode 100644 index 00000000000..1fb8943728c --- /dev/null +++ b/src/scripting/zscript/zcc_compile_doom.h @@ -0,0 +1,35 @@ +#pragma once +#include "zcc_compile.h" + +void SetImplicitArgs(TArray* args, TArray* argflags, TArray* argnames, PContainerType* cls, uint32_t funcflags, int useflags); + +class ZCCDoomCompiler : public ZCCCompiler +{ +public: + ZCCDoomCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PNamespace *outnamespace, int lumpnum, const VersionInfo & ver) + : ZCCCompiler(tree, outer, symbols, outnamespace, lumpnum, ver) + {} + int Compile() override; +protected: + bool PrepareMetaData(PClass *type) override; + void SetImplicitArgs(TArray* args, TArray* argflags, TArray* argnames, PContainerType* cls, uint32_t funcflags, int useflags) override + { + ::SetImplicitArgs(args, argflags, argnames, cls, funcflags, useflags); + } +private: + void CompileAllProperties(); + bool CompileProperties(PClass *type, TArray &Properties, FName prefix); + bool CompileFlagDefs(PClass *type, TArray &Properties, FName prefix); + void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag); + void DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag); + void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *prop, Baggage &bag); + void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg); + void InitDefaults() override final; + void InitDefaultFunctionPointers(); + FxExpression *SetupActionFunction(PClass *cls, ZCC_TreeNode *af, int StateFlags); + void CompileStates(); + int CheckActionKeyword(ZCC_FuncDeclarator *f, uint32_t &varflags, int useflags, ZCC_StructWork *c); + +}; + + diff --git a/src/serializer.cpp b/src/serializer.cpp deleted file mode 100644 index cd9b5b8f22b..00000000000 --- a/src/serializer.cpp +++ /dev/null @@ -1,2294 +0,0 @@ -/* -** serializer.cpp -** Savegame wrapper around RapidJSON -** -**--------------------------------------------------------------------------- -** Copyright 2016 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 // disable this insanity which is bound to make the code break over time. -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 -#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 -#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag - -#include -#include "rapidjson/rapidjson.h" -#include "rapidjson/writer.h" -#include "rapidjson/prettywriter.h" -#include "rapidjson/document.h" -#include "serializer.h" -#include "r_data/r_interpolate.h" -#include "r_state.h" -#include "p_lnspec.h" -#include "w_wad.h" -#include "p_terrain.h" -#include "p_setup.h" -#include "p_conversation.h" -#include "dsectoreffect.h" -#include "d_player.h" -#include "a_sharedglobal.h" -#include "po_man.h" -#include "v_font.h" -#include "doomerrors.h" -#include "v_text.h" -#include "cmdlib.h" -#include "g_levellocals.h" -#include "utf8.h" - -bool save_full = false; // for testing. Should be removed afterward. - -//========================================================================== -// -// This will double-encode already existing UTF-8 content. -// The reason for this behavior is to preserve any original data coming through here, no matter what it is. -// If these are script-based strings, exact preservation in the serializer is very important. -// -//========================================================================== - -static TArray out; -static const char *StringToUnicode(const char *cc, int size = -1) -{ - int ch; - const uint8_t *c = (const uint8_t*)cc; - int count = 0; - int count1 = 0; - out.Clear(); - while ((ch = (*c++) & 255)) - { - count1++; - if (ch >= 128) count += 2; - else count++; - if (count1 == size && size > 0) break; - } - if (count == count1) return cc; // string is pure ASCII. - // we need to convert - out.Resize(count + 1); - out.Last() = 0; - c = (const uint8_t*)cc; - int i = 0; - while ((ch = (*c++))) - { - utf8_encode(ch, (uint8_t*)&out[i], &count1); - i += count1; - } - return &out[0]; -} - -static const char *UnicodeToString(const char *cc) -{ - out.Resize((unsigned)strlen(cc) + 1); - int ndx = 0; - while (*cc != 0) - { - int size; - int c = utf8_decode((const uint8_t*)cc, &size); - if (c < 0 || c > 255) c = '?'; // This should never happen because all content was encoded with StringToUnicode which only produces code points 0-255. - out[ndx++] = c; - cc += size; - } - out[ndx] = 0; - return &out[0]; -} - -//========================================================================== -// -// -// -//========================================================================== - -struct FJSONObject -{ - rapidjson::Value *mObject; - rapidjson::Value::MemberIterator mIterator; - int mIndex; - - FJSONObject(rapidjson::Value *v) - { - mObject = v; - if (v->IsObject()) mIterator = v->MemberBegin(); - else if (v->IsArray()) - { - mIndex = 0; - } - } -}; - -//========================================================================== -// -// some wrapper stuff to keep the RapidJSON dependencies out of the global headers. -// FSerializer should not expose any of this. -// -//========================================================================== - -struct FWriter -{ - typedef rapidjson::Writer > Writer; - typedef rapidjson::PrettyWriter > PrettyWriter; - - Writer *mWriter1; - PrettyWriter *mWriter2; - TArray mInObject; - rapidjson::StringBuffer mOutString; - TArray mDObjects; - TMap mObjectMap; - - FWriter(bool pretty) - { - if (!pretty) - { - mWriter1 = new Writer(mOutString); - mWriter2 = nullptr; - } - else - { - mWriter1 = nullptr; - mWriter2 = new PrettyWriter(mOutString); - } - } - - ~FWriter() - { - if (mWriter1) delete mWriter1; - if (mWriter2) delete mWriter2; - } - - - bool inObject() const - { - return mInObject.Size() > 0 && mInObject.Last(); - } - - void StartObject() - { - if (mWriter1) mWriter1->StartObject(); - else if (mWriter2) mWriter2->StartObject(); - } - - void EndObject() - { - if (mWriter1) mWriter1->EndObject(); - else if (mWriter2) mWriter2->EndObject(); - } - - void StartArray() - { - if (mWriter1) mWriter1->StartArray(); - else if (mWriter2) mWriter2->StartArray(); - } - - void EndArray() - { - if (mWriter1) mWriter1->EndArray(); - else if (mWriter2) mWriter2->EndArray(); - } - - void Key(const char *k) - { - if (mWriter1) mWriter1->Key(k); - else if (mWriter2) mWriter2->Key(k); - } - - void Null() - { - if (mWriter1) mWriter1->Null(); - else if (mWriter2) mWriter2->Null(); - } - - void StringU(const char *k, bool encode) - { - if (encode) k = StringToUnicode(k); - if (mWriter1) mWriter1->String(k); - else if (mWriter2) mWriter2->String(k); - } - - void String(const char *k) - { - k = StringToUnicode(k); - if (mWriter1) mWriter1->String(k); - else if (mWriter2) mWriter2->String(k); - } - - void String(const char *k, int size) - { - k = StringToUnicode(k, size); - if (mWriter1) mWriter1->String(k); - else if (mWriter2) mWriter2->String(k); - } - - void Bool(bool k) - { - if (mWriter1) mWriter1->Bool(k); - else if (mWriter2) mWriter2->Bool(k); - } - - void Int(int32_t k) - { - if (mWriter1) mWriter1->Int(k); - else if (mWriter2) mWriter2->Int(k); - } - - void Int64(int64_t k) - { - if (mWriter1) mWriter1->Int64(k); - else if (mWriter2) mWriter2->Int64(k); - } - - void Uint(uint32_t k) - { - if (mWriter1) mWriter1->Uint(k); - else if (mWriter2) mWriter2->Uint(k); - } - - void Uint64(int64_t k) - { - if (mWriter1) mWriter1->Uint64(k); - else if (mWriter2) mWriter2->Uint64(k); - } - - void Double(double k) - { - if (mWriter1) - { - mWriter1->Double(k); - } - else if (mWriter2) - { - mWriter2->Double(k); - } - } - -}; - -//========================================================================== -// -// -// -//========================================================================== - -struct FReader -{ - TArray mObjects; - rapidjson::Document mDoc; - TArray mDObjects; - rapidjson::Value *mKeyValue = nullptr; - bool mObjectsRead = false; - - FReader(const char *buffer, size_t length) - { - mDoc.Parse(buffer, length); - mObjects.Push(FJSONObject(&mDoc)); - } - - rapidjson::Value *FindKey(const char *key) - { - FJSONObject &obj = mObjects.Last(); - - if (obj.mObject->IsObject()) - { - if (key == nullptr) - { - // we are performing an iteration of the object through GetKey. - auto p = mKeyValue; - mKeyValue = nullptr; - return p; - } - else - { - // Find the given key by name; - auto it = obj.mObject->FindMember(key); - if (it == obj.mObject->MemberEnd()) return nullptr; - return &it->value; - } - } - else if (obj.mObject->IsArray() && (unsigned)obj.mIndex < obj.mObject->Size()) - { - return &(*obj.mObject)[obj.mIndex++]; - } - return nullptr; - } -}; - - -//========================================================================== -// -// -// -//========================================================================== - -bool FSerializer::OpenWriter(bool pretty) -{ - if (w != nullptr || r != nullptr) return false; - - mErrors = 0; - w = new FWriter(pretty); - BeginObject(nullptr); - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FSerializer::OpenReader(const char *buffer, size_t length) -{ - if (w != nullptr || r != nullptr) return false; - - mErrors = 0; - r = new FReader(buffer, length); - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FSerializer::OpenReader(FCompressedBuffer *input) -{ - if (input->mSize <= 0 || input->mBuffer == nullptr) return false; - if (w != nullptr || r != nullptr) return false; - - mErrors = 0; - if (input->mMethod == METHOD_STORED) - { - r = new FReader((char*)input->mBuffer, input->mSize); - } - else - { - TArray unpacked(input->mSize); - input->Decompress(unpacked.Data()); - r = new FReader(unpacked.Data(), input->mSize); - } - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FSerializer::Close() -{ - if (w == nullptr && r == nullptr) return; // double close? This should skip the I_Error at the bottom. - - if (w != nullptr) - { - delete w; - w = nullptr; - } - if (r != nullptr) - { - // we must explicitly delete all thinkers in the array which did not get linked into the thinker lists. - // Otherwise these objects may survive a level deletion and point to incorrect data. - for (auto obj : r->mDObjects) - { - auto think = dyn_cast(obj); - if (think != nullptr) - { - if (think->NextThinker == nullptr || think->PrevThinker == nullptr) - { - think->Destroy(); - } - } - } - - delete r; - r = nullptr; - } - if (mErrors > 0) - { - I_Error("%d errors parsing JSON", mErrors); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -unsigned FSerializer::ArraySize() -{ - if (r != nullptr && r->mObjects.Last().mObject->IsArray()) - { - return r->mObjects.Last().mObject->Size(); - } - else - { - return 0; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FSerializer::canSkip() const -{ - return isWriting() && w->inObject(); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FSerializer::WriteKey(const char *key) -{ - if (isWriting() && w->inObject()) - { - assert(key != nullptr); - if (key == nullptr) - { - I_Error("missing element name"); - } - w->Key(key); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FSerializer::BeginObject(const char *name) -{ - if (isWriting()) - { - WriteKey(name); - w->StartObject(); - w->mInObject.Push(true); - } - else - { - auto val = r->FindKey(name); - if (val != nullptr) - { - assert(val->IsObject()); - if (val->IsObject()) - { - r->mObjects.Push(FJSONObject(val)); - } - else - { - Printf(TEXTCOLOR_RED "Object expected for '%s'\n", name); - mErrors++; - return false; - } - } - else - { - return false; - } - } - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FSerializer::EndObject() -{ - if (isWriting()) - { - if (w->inObject()) - { - w->EndObject(); - w->mInObject.Pop(); - } - else - { - assert(false && "EndObject call not inside an object"); - I_Error("EndObject call not inside an object"); - } - } - else - { - r->mObjects.Pop(); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FSerializer::BeginArray(const char *name) -{ - if (isWriting()) - { - WriteKey(name); - w->StartArray(); - w->mInObject.Push(false); - } - else - { - auto val = r->FindKey(name); - if (val != nullptr) - { - assert(val->IsArray()); - if (val->IsArray()) - { - r->mObjects.Push(FJSONObject(val)); - } - else - { - Printf(TEXTCOLOR_RED "Array expected for '%s'\n", name); - mErrors++; - return false; - } - } - else - { - return false; - } - } - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FSerializer::EndArray() -{ - if (isWriting()) - { - if (!w->inObject()) - { - w->EndArray(); - w->mInObject.Pop(); - } - else - { - assert(false && "EndArray call not inside an array"); - I_Error("EndArray call not inside an array"); - } - } - else - { - r->mObjects.Pop(); - } -} - -//========================================================================== -// -// Special handler for args (because ACS specials' arg0 needs special treatment.) -// -//========================================================================== - -FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int special) -{ - if (isWriting()) - { - if (w->inObject() && defargs != nullptr && !memcmp(args, defargs, 5 * sizeof(int))) - { - return *this; - } - - WriteKey(key); - w->StartArray(); - for (int i = 0; i < 5; i++) - { - if (i == 0 && args[i] < 0 && P_IsACSSpecial(special)) - { - w->String(FName(ENamedName(-args[i])).GetChars()); - } - else - { - w->Int(args[i]); - } - } - w->EndArray(); - } - else - { - auto val = r->FindKey(key); - if (val != nullptr) - { - if (val->IsArray()) - { - unsigned int cnt = MIN(val->Size(), 5); - for (unsigned int i = 0; i < cnt; i++) - { - const rapidjson::Value &aval = (*val)[i]; - if (aval.IsInt()) - { - args[i] = aval.GetInt(); - } - else if (i == 0 && aval.IsString()) - { - args[i] = -FName(UnicodeToString(aval.GetString())); - } - else - { - assert(false && "Integer expected"); - Printf(TEXTCOLOR_RED "Integer expected for '%s[%d]'\n", key, i); - mErrors++; - } - } - } - else - { - assert(false && "array expected"); - Printf(TEXTCOLOR_RED "array expected for '%s'\n", key); - mErrors++; - } - } - } - return *this; -} - -//========================================================================== -// -// Special handler for script numbers -// -//========================================================================== - -FSerializer &FSerializer::ScriptNum(const char *key, int &num) -{ - if (isWriting()) - { - WriteKey(key); - if (num < 0) - { - w->String(FName(ENamedName(-num)).GetChars()); - } - else - { - w->Int(num); - } - } - else - { - auto val = r->FindKey(key); - if (val != nullptr) - { - if (val->IsInt()) - { - num = val->GetInt(); - } - else if (val->IsString()) - { - num = -FName(UnicodeToString(val->GetString())); - } - else - { - assert(false && "Integer expected"); - Printf(TEXTCOLOR_RED "Integer expected for '%s'\n", key); - mErrors++; - } - } - } - return *this; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &FSerializer::Terrain(const char *key, int &terrain, int *def) -{ - if (isWriting() && def != nullptr && terrain == *def) - { - return *this; - } - FName terr = P_GetTerrainName(terrain); - Serialize(*this, key, terr, nullptr); - if (isReading()) - { - terrain = P_FindTerrain(terr); - } - return *this; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *def) -{ - if (isWriting()) - { - if (w->inObject() && def != nullptr && *def == spritenum) return *this; - WriteKey(key); - w->String(sprites[spritenum].name, 4); - } - else - { - auto val = r->FindKey(key); - if (val != nullptr) - { - if (val->IsString()) - { - uint32_t name = *reinterpret_cast(UnicodeToString(val->GetString())); - for (auto hint = NumStdSprites; hint-- != 0; ) - { - if (sprites[hint].dwName == name) - { - spritenum = hint; - break; - } - } - } - } - } - return *this; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr) -{ - if (isWriting()) - { - WriteKey(key); - if (charptr != nullptr) - w->String(charptr); - else - w->Null(); - } - else - { - auto val = r->FindKey(key); - if (val != nullptr) - { - if (val->IsString()) - { - charptr = UnicodeToString(val->GetString()); - } - else - { - charptr = nullptr; - } - } - } - return *this; -} - -//========================================================================== -// -// Adds a string literal. This won't get double encoded, like a serialized string. -// -//========================================================================== - -FSerializer &FSerializer::AddString(const char *key, const char *charptr) -{ - if (isWriting()) - { - WriteKey(key); - w->StringU(MakeUTF8(charptr), false); - } - return *this; -} - -//========================================================================== -// -// Reads back a string without any processing. -// -//========================================================================== - -const char *FSerializer::GetString(const char *key) -{ - auto val = r->FindKey(key); - if (val != nullptr) - { - if (val->IsString()) - { - return val->GetString(); - } - else - { - } - } - return nullptr; -} - -//========================================================================== -// -// -// -//========================================================================== - -unsigned FSerializer::GetSize(const char *group) -{ - if (isWriting()) return -1; // we do not know this when writing. - - const rapidjson::Value *val = r->FindKey(group); - if (!val) return 0; - if (!val->IsArray()) return -1; - return val->Size(); -} - -//========================================================================== -// -// gets the key pointed to by the iterator, caches its value -// and returns the key string. -// -//========================================================================== - -const char *FSerializer::GetKey() -{ - if (isWriting()) return nullptr; // we do not know this when writing. - if (!r->mObjects.Last().mObject->IsObject()) return nullptr; // non-objects do not have keys. - auto &it = r->mObjects.Last().mIterator; - if (it == r->mObjects.Last().mObject->MemberEnd()) return nullptr; - r->mKeyValue = &it->value; - return (it++)->name.GetString(); -} - -//========================================================================== -// -// Writes out all collected objects -// -//========================================================================== - -void FSerializer::WriteObjects() -{ - if (isWriting() && w->mDObjects.Size()) - { - BeginArray("objects"); - // we cannot use the C++11 shorthand syntax here because the array may grow while being processed. - for (unsigned i = 0; i < w->mDObjects.Size(); i++) - { - auto obj = w->mDObjects[i]; - - BeginObject(nullptr); - w->Key("classtype"); - w->String(obj->GetClass()->TypeName.GetChars()); - - obj->SerializeUserVars(*this); - obj->Serialize(*this); - obj->CheckIfSerialized(); - EndObject(); - } - EndArray(); - } -} - -//========================================================================== -// -// Writes out all collected objects -// -//========================================================================== - -void FSerializer::ReadObjects(bool hubtravel) -{ - bool founderrors = false; - - if (isReading() && BeginArray("objects")) - { - // Do not link any thinker that's being created here. This will be done by deserializing the thinker list later. - try - { - r->mDObjects.Resize(ArraySize()); - for (auto &p : r->mDObjects) - { - p = nullptr; - } - - // First iteration: create all the objects but do nothing with them yet. - for (unsigned i = 0; i < r->mDObjects.Size(); i++) - { - if (BeginObject(nullptr)) - { - FString clsname; // do not deserialize the class type directly so that we can print appropriate errors. - int pindex = -1; - - Serialize(*this, "classtype", clsname, nullptr); - PClass *cls = PClass::FindClass(clsname); - if (cls == nullptr) - { - Printf(TEXTCOLOR_RED "Unknown object class '%s' in savegame\n", clsname.GetChars()); - founderrors = true; - r->mDObjects[i] = RUNTIME_CLASS(AActor)->CreateNew(); // make sure we got at least a valid pointer for the duration of the loading process. - r->mDObjects[i]->Destroy(); // but we do not want to keep this around, so destroy it right away. - } - else - { - r->mDObjects[i] = cls->CreateNew(); - } - EndObject(); - } - } - // Now that everything has been created and we can retrieve the pointers we can deserialize it. - r->mObjectsRead = true; - - if (!founderrors) - { - // Reset to start; - r->mObjects.Last().mIndex = 0; - - for (unsigned i = 0; i < r->mDObjects.Size(); i++) - { - auto obj = r->mDObjects[i]; - if (BeginObject(nullptr)) - { - if (obj != nullptr) - { - int pindex = -1; - try - { - obj->SerializeUserVars(*this); - obj->Serialize(*this); - } - catch (CRecoverableError &err) - { - // In case something in here throws an error, let's continue and deal with it later. - Printf(TEXTCOLOR_RED "'%s'\n while restoring %s\n", err.GetMessage(), obj ? obj->GetClass()->TypeName.GetChars() : "invalid object"); - mErrors++; - } - } - EndObject(); - } - } - } - EndArray(); - - assert(!founderrors); - if (founderrors) - { - Printf(TEXTCOLOR_RED "Failed to restore all objects in savegame\n"); - mErrors++; - } - } - catch(...) - { - // nuke all objects we created here. - for (auto obj : r->mDObjects) - { - if (obj != nullptr && !(obj->ObjectFlags & OF_EuthanizeMe)) obj->Destroy(); - } - r->mDObjects.Clear(); - - // make sure this flag gets unset, even if something in here throws an error. - throw; - } - } -} - -//========================================================================== -// -// -// -//========================================================================== - -const char *FSerializer::GetOutput(unsigned *len) -{ - if (isReading()) return nullptr; - WriteObjects(); - EndObject(); - if (len != nullptr) - { - *len = (unsigned)w->mOutString.GetSize(); - } - return w->mOutString.GetString(); -} - -//========================================================================== -// -// -// -//========================================================================== - -FCompressedBuffer FSerializer::GetCompressedOutput() -{ - if (isReading()) return{ 0,0,0,0,0,nullptr }; - FCompressedBuffer buff; - WriteObjects(); - EndObject(); - buff.mSize = (unsigned)w->mOutString.GetSize(); - buff.mZipFlags = 0; - buff.mCRC32 = crc32(0, (const Bytef*)w->mOutString.GetString(), buff.mSize); - - uint8_t *compressbuf = new uint8_t[buff.mSize+1]; - - z_stream stream; - int err; - - stream.next_in = (Bytef *)w->mOutString.GetString(); - stream.avail_in = buff.mSize; - stream.next_out = (Bytef*)compressbuf; - stream.avail_out = buff.mSize; - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - // create output in zip-compatible form as required by FCompressedBuffer - err = deflateInit2(&stream, 8, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY); - if (err != Z_OK) - { - goto error; - } - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) - { - deflateEnd(&stream); - goto error; - } - buff.mCompressedSize = stream.total_out; - - err = deflateEnd(&stream); - if (err == Z_OK) - { - buff.mBuffer = new char[buff.mCompressedSize]; - buff.mMethod = METHOD_DEFLATE; - memcpy(buff.mBuffer, compressbuf, buff.mCompressedSize); - delete[] compressbuf; - return buff; - } - -error: - memcpy(compressbuf, w->mOutString.GetString(), buff.mSize + 1); - buff.mCompressedSize = buff.mSize; - buff.mMethod = METHOD_STORED; - return buff; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - arc.WriteKey(key); - arc.w->Bool(value); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsBool()); - if (val->IsBool()) - { - value = val->GetBool(); - } - else - { - Printf(TEXTCOLOR_RED "boolean type expected for '%s'\n", key); - arc.mErrors++; - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_t *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - arc.WriteKey(key); - arc.w->Int64(value); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsInt64()); - if (val->IsInt64()) - { - value = val->GetInt64(); - } - else - { - Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); - arc.mErrors++; - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint64_t *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - arc.WriteKey(key); - arc.w->Uint64(value); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsUint64()); - if (val->IsUint64()) - { - value = val->GetUint64(); - } - else - { - Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); - arc.mErrors++; - } - } - } - return arc; -} - - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value, int32_t *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - arc.WriteKey(key); - arc.w->Int(value); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsInt()); - if (val->IsInt()) - { - value = val->GetInt(); - } - else - { - Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); - arc.mErrors++; - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint32_t *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - arc.WriteKey(key); - arc.w->Uint(value); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsUint()); - if (val->IsUint()) - { - value = val->GetUint(); - } - else - { - Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); - arc.mErrors++; - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, int8_t &value, int8_t *defval) -{ - int32_t vv = value; - int32_t vvd = defval? *defval : value-1; - Serialize(arc, key, vv, &vvd); - value = (int8_t)vv; - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, uint8_t &value, uint8_t *defval) -{ - uint32_t vv = value; - uint32_t vvd = defval ? *defval : value - 1; - Serialize(arc, key, vv, &vvd); - value = (uint8_t)vv; - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, int16_t &value, int16_t *defval) -{ - int32_t vv = value; - int32_t vvd = defval ? *defval : value - 1; - Serialize(arc, key, vv, &vvd); - value = (int16_t)vv; - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, uint16_t &value, uint16_t *defval) -{ - uint32_t vv = value; - uint32_t vvd = defval ? *defval : value - 1; - Serialize(arc, key, vv, &vvd); - value = (uint16_t)vv; - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - arc.WriteKey(key); - arc.w->Double(value); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsDouble()); - if (val->IsDouble()) - { - value = val->GetDouble(); - } - else - { - Printf(TEXTCOLOR_RED "float type expected for '%s'\n", key); - arc.mErrors++; - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *defval) -{ - double vv = value; - double vvd = defval ? *defval : value - 1; - Serialize(arc, key, vv, &vvd); - value = (float)vv; - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -template -FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T **defval, T *base) -{ - assert(base != nullptr); - if (arc.isReading() || !arc.w->inObject() || defval == nullptr || value != *defval) - { - int64_t vv = value == nullptr ? -1 : value - base; - Serialize(arc, key, vv, nullptr); - value = vv < 0 ? nullptr : base + vv; - } - return arc; -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj *&value, FPolyObj **defval) -{ - if (arc.Level == nullptr) I_Error("Trying to serialize polyobject without a valid level"); - return SerializePointer(arc, key, value, defval, arc.Level->Polyobjects.Data()); -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, const FPolyObj *&value, const FPolyObj **defval) -{ - if (arc.Level == nullptr) I_Error("Trying to serialize polyobject without a valid level"); - return SerializePointer(arc, key, value, defval, arc.Level->Polyobjects.Data()); -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&value, side_t **defval) -{ - if (arc.Level == nullptr) I_Error("Trying to serialize SIDEDEF without a valid level"); - return SerializePointer(arc, key, value, defval, &arc.Level->sides[0]); -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value, sector_t **defval) -{ - if (arc.Level == nullptr) I_Error("Trying to serialize sector without a valid level"); - return SerializePointer(arc, key, value, defval, &arc.Level->sectors[0]); -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, const sector_t *&value, const sector_t **defval) -{ - if (arc.Level == nullptr) I_Error("Trying to serialize sector without a valid level"); - return SerializePointer(arc, key, value, defval, &arc.Level->sectors[0]); -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value, player_t **defval) -{ - return SerializePointer(arc, key, value, defval, players); -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, line_t *&value, line_t **defval) -{ - if (arc.Level == nullptr) I_Error("Trying to serialize linedef without a valid level"); - return SerializePointer(arc, key, value, defval, &arc.Level->lines[0]); -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, vertex_t *&value, vertex_t **defval) -{ - if (arc.Level == nullptr) I_Error("Trying to serialize verte without a valid level"); - return SerializePointer(arc, key, value, defval, &arc.Level->vertexes[0]); -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - if (!value.Exists()) - { - arc.WriteKey(key); - arc.w->Null(); - return arc; - } - if (value.isNull()) - { - // save 'no texture' in a more space saving way - arc.WriteKey(key); - arc.w->Int(0); - return arc; - } - FTextureID chk = value; - if (chk.GetIndex() >= TexMan.NumTextures()) chk.SetNull(); - FTexture *pic = TexMan.GetTexture(chk); - const char *name; - - if (Wads.GetLinkedTexture(pic->SourceLump) == pic) - { - name = Wads.GetLumpFullName(pic->SourceLump); - } - else - { - name = pic->Name; - } - arc.WriteKey(key); - arc.w->StartArray(); - arc.w->String(name); - arc.w->Int(static_cast(pic->UseType)); - arc.w->EndArray(); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - if (val->IsArray()) - { - const rapidjson::Value &nameval = (*val)[0]; - const rapidjson::Value &typeval = (*val)[1]; - assert(nameval.IsString() && typeval.IsInt()); - if (nameval.IsString() && typeval.IsInt()) - { - value = TexMan.GetTextureID(UnicodeToString(nameval.GetString()), static_cast(typeval.GetInt())); - } - else - { - Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'\n", key); - value.SetNull(); - arc.mErrors++; - } - } - else if (val->IsNull()) - { - value.SetInvalid(); - } - else if (val->IsInt() && val->GetInt() == 0) - { - value.SetNull(); - } - else - { - assert(false && "not a texture"); - Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'\n", key); - value.SetNull(); - arc.mErrors++; - } - } - } - return arc; -} - -//========================================================================== -// -// This never uses defval and instead uses 'null' as default -// because object pointers cannot be safely defaulted to anything else. -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode) -{ - if (retcode) *retcode = true; - if (arc.isWriting()) - { - if (value != nullptr && !(value->ObjectFlags & (OF_EuthanizeMe | OF_Transient))) - { - int ndx; - if (value == WP_NOCHANGE) - { - ndx = -1; - } - else - { - int *pndx = arc.w->mObjectMap.CheckKey(value); - if (pndx != nullptr) - { - ndx = *pndx; - } - else - { - ndx = arc.w->mDObjects.Push(value); - arc.w->mObjectMap[value] = ndx; - } - } - Serialize(arc, key, ndx, nullptr); - } - else if (!arc.w->inObject()) - { - arc.w->Null(); - } - } - else - { - if (!arc.r->mObjectsRead) - { - // If you want to read objects, you MUST call ReadObjects first, even if there's only nullptr's. - assert(false && "Attempt to read object reference without calling ReadObjects first"); - I_Error("Attempt to read object reference without calling ReadObjects first"); - } - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - if (val->IsNull()) - { - value = nullptr; - return arc; - } - else if (val->IsInt()) - { - int index = val->GetInt(); - if (index == -1) - { - value = WP_NOCHANGE; - } - else - { - assert(index >= 0 && index < (int)arc.r->mDObjects.Size()); - if (index >= 0 && index < (int)arc.r->mDObjects.Size()) - { - value = arc.r->mDObjects[index]; - } - else - { - assert(false && "invalid object reference"); - Printf(TEXTCOLOR_RED "Invalid object reference for '%s'\n", key); - value = nullptr; - arc.mErrors++; - if (retcode) *retcode = false; - } - } - return arc; - } - } - if (!retcode) - { - value = nullptr; - } - else - { - *retcode = false; - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - arc.WriteKey(key); - arc.w->String(value.GetChars()); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsString()); - if (val->IsString()) - { - value = UnicodeToString(val->GetString()); - } - else - { - Printf(TEXTCOLOR_RED "String expected for '%s'\n", key); - arc.mErrors++; - value = NAME_None; - } - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || def == nullptr || sid != *def) - { - arc.WriteKey(key); - const char *sn = S_GetSoundName(sid); - if (sn != nullptr) arc.w->String(sn); - else arc.w->Null(); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsString() || val->IsNull()); - if (val->IsString()) - { - sid = UnicodeToString(val->GetString()); - } - else if (val->IsNull()) - { - sid = 0; - } - else - { - Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); - sid = 0; - arc.mErrors++; - } - } - } - return arc; - -} - -//========================================================================== -// -// -// -//========================================================================== - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor *&clst, PClassActor **def) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || def == nullptr || clst != *def) - { - arc.WriteKey(key); - if (clst == nullptr) - { - arc.w->Null(); - } - else - { - arc.w->String(clst->TypeName.GetChars()); - } - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsString() || val->IsNull()); - if (val->IsString()) - { - clst = PClass::FindActor(UnicodeToString(val->GetString())); - } - else if (val->IsNull()) - { - clst = nullptr; - } - else - { - Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); - clst = nullptr; - arc.mErrors++; - } - } - } - return arc; - -} - -//========================================================================== -// -// almost, but not quite the same as the above. -// -//========================================================================== - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&clst, PClass **def) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || def == nullptr || clst != *def) - { - arc.WriteKey(key); - if (clst == nullptr) - { - arc.w->Null(); - } - else - { - arc.w->String(clst->TypeName.GetChars()); - } - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - if (val->IsString()) - { - clst = PClass::FindClass(UnicodeToString(val->GetString())); - } - else if (val->IsNull()) - { - clst = nullptr; - } - else - { - Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); - clst = nullptr; - arc.mErrors++; - } - } - } - return arc; - -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode) -{ - if (retcode) *retcode = false; - if (arc.isWriting()) - { - if (!arc.w->inObject() || def == nullptr || state != *def) - { - if (retcode) *retcode = true; - arc.WriteKey(key); - if (state == nullptr) - { - arc.w->Null(); - } - else - { - PClassActor *info = FState::StaticFindStateOwner(state); - - if (info != NULL) - { - arc.w->StartArray(); - arc.w->String(info->TypeName.GetChars()); - arc.w->Uint((uint32_t)(state - info->GetStates())); - arc.w->EndArray(); - } - else - { - arc.w->Null(); - } - } - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - if (val->IsNull()) - { - if (retcode) *retcode = true; - state = nullptr; - } - else if (val->IsArray()) - { - if (retcode) *retcode = true; - const rapidjson::Value &cls = (*val)[0]; - const rapidjson::Value &ndx = (*val)[1]; - - state = nullptr; - assert(cls.IsString() && ndx.IsUint()); - if (cls.IsString() && ndx.IsUint()) - { - PClassActor *clas = PClass::FindActor(UnicodeToString(cls.GetString())); - if (clas && ndx.GetUint() < (unsigned)clas->GetStateCount()) - { - state = clas->GetStates() + ndx.GetUint(); - } - else - { - // this can actually happen by changing the DECORATE so treat it as a warning, not an error. - state = nullptr; - Printf(TEXTCOLOR_ORANGE "Invalid state '%s+%d' for '%s'\n", cls.GetString(), ndx.GetInt(), key); - } - } - else - { - assert(false && "not a state"); - Printf(TEXTCOLOR_RED "data does not represent a state for '%s'\n", key); - arc.mErrors++; - } - } - else if (!retcode) - { - assert(false && "not an array"); - Printf(TEXTCOLOR_RED "array type expected for '%s'\n", key); - arc.mErrors++; - } - } - } - return arc; - -} - -//========================================================================== -// -// -// -//========================================================================== - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node, FStrifeDialogueNode **def) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || def == nullptr || node != *def) - { - arc.WriteKey(key); - if (node == nullptr) - { - arc.w->Null(); - } - else - { - arc.w->Uint(node->ThisNodeNum); - } - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsUint() || val->IsNull()); - if (val->IsNull()) - { - node = nullptr; - } - else if (val->IsUint()) - { - if (val->GetUint() >= arc.Level->StrifeDialogues.Size()) - { - node = nullptr; - } - else - { - node = arc.Level->StrifeDialogues[val->GetUint()]; - } - } - else - { - Printf(TEXTCOLOR_RED "integer expected for '%s'\n", key); - arc.mErrors++; - node = nullptr; - } - } - } - return arc; - -} - -//========================================================================== -// -// -// -//========================================================================== - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr, FString **def) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || def == nullptr || pstr != *def) - { - arc.WriteKey(key); - if (pstr == nullptr) - { - arc.w->Null(); - } - else - { - arc.w->String(pstr->GetChars()); - } - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsNull() || val->IsString()); - if (val->IsNull()) - { - pstr = nullptr; - } - else if (val->IsString()) - { - pstr = AActor::mStringPropertyData.Alloc(UnicodeToString(val->GetString())); - } - else - { - Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); - pstr = nullptr; - arc.mErrors++; - } - } - } - return arc; - -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString *def) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || def == nullptr || pstr.Compare(*def) != 0) - { - arc.WriteKey(key); - arc.w->String(pstr.GetChars()); - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsNull() || val->IsString()); - if (val->IsNull()) - { - pstr = ""; - } - else if (val->IsString()) - { - pstr = UnicodeToString(val->GetString()); - } - else - { - Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); - pstr = ""; - arc.mErrors++; - } - } - } - return arc; - -} - -//========================================================================== -// -// -// -//========================================================================== - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || def == nullptr || strcmp(pstr, *def)) - { - arc.WriteKey(key); - if (pstr == nullptr) - { - arc.w->Null(); - } - else - { - arc.w->String(pstr); - } - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsNull() || val->IsString()); - if (val->IsNull()) - { - pstr = nullptr; - } - else if (val->IsString()) - { - pstr = copystring(UnicodeToString(val->GetString())); - } - else - { - Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); - pstr = nullptr; - arc.mErrors++; - } - } - } - return arc; -} - -//========================================================================== -// -// This is a bit of a cheat because it never actually writes out the pointer. -// The rules for levels are that they must be self-contained. -// No level and no pbject that is part of a level may reference a different one. -// -// When writing, this merely checks if the rules are obeyed and if not errors out. -// When reading, it assumes that the object was properly written and restores -// the reference from the owning level -// -// The only exception are null pointers which are allowed -// -//========================================================================== - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FLevelLocals *&lev, FLevelLocals **def) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || lev == nullptr) - { - arc.WriteKey(key); - if (lev == nullptr) - { - arc.w->Null(); - } - else - { - // This MUST be the currently serialized level, anything else will error out here as a sanity check. - if (arc.Level == nullptr || lev != arc.Level) - { - I_Error("Attempt to serialize invalid level reference"); - } - if (!arc.w->inObject()) - { - arc.w->Bool(true); // In the unlikely case this is used in an array, write a filler. - } - } - } - } - else - { - auto val = arc.r->FindKey(key); - if (val != nullptr) - { - assert(val->IsNull() || val->IsBool()); - if (val->IsNull()) - { - lev = nullptr; - } - else - { - lev = arc.Level; - } - } - else lev = arc.Level; - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def) -{ - if (arc.isWriting()) - { - FName n = font? font->GetName() : NAME_None; - return arc(key, n); - } - else - { - FName n = NAME_None; - arc(key, n); - font = n == NAME_None? nullptr : V_GetFont(n); - return arc; - } - -} - -//========================================================================== -// -// Dictionary -// -//========================================================================== - -FString DictionaryToString(const Dictionary &dict) -{ - Dictionary::ConstPair *pair; - Dictionary::ConstIterator i { dict.Map }; - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - writer.StartObject(); - - while (i.NextPair(pair)) - { - writer.Key(pair->Key); - writer.String(pair->Value); - } - - writer.EndObject(); - - FString contents { buffer.GetString(), buffer.GetSize() }; - return contents; -} - -Dictionary *DictionaryFromString(const FString &string) -{ - if (string.Compare("null") == 0) - { - return nullptr; - } - - Dictionary *const dict = Create(); - - if (string.IsEmpty()) - { - return dict; - } - - rapidjson::Document doc; - doc.Parse(string.GetChars(), string.Len()); - - if (doc.GetType() != rapidjson::Type::kObjectType) - { - I_Error("Dictionary is expected to be a JSON object."); - return dict; - } - - for (auto i = doc.MemberBegin(); i != doc.MemberEnd(); ++i) - { - if (i->value.GetType() != rapidjson::Type::kStringType) - { - I_Error("Dictionary value is expected to be a JSON string."); - return dict; - } - - dict->Map.Insert(i->name.GetString(), i->value.GetString()); - } - - return dict; -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary *&dict, Dictionary **) -{ - if (arc.isWriting()) - { - FString contents { dict ? DictionaryToString(*dict) : "null" }; - return arc(key, contents); - } - else - { - FString contents; - arc(key, contents); - dict = DictionaryFromString(contents); - return arc; - } -} - -//========================================================================== -// -// Handler to retrieve a numeric value of any kind. -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &value, NumericValue *defval) -{ - if (arc.isWriting()) - { - if (!arc.w->inObject() || defval == nullptr || value != *defval) - { - arc.WriteKey(key); - switch (value.type) - { - case NumericValue::NM_signed: - arc.w->Int64(value.signedval); - break; - case NumericValue::NM_unsigned: - arc.w->Uint64(value.unsignedval); - break; - case NumericValue::NM_float: - arc.w->Double(value.floatval); - break; - default: - arc.w->Null(); - break; - } - } - } - else - { - auto val = arc.r->FindKey(key); - value.signedval = 0; - value.type = NumericValue::NM_invalid; - if (val != nullptr) - { - if (val->IsUint64()) - { - value.unsignedval = val->GetUint64(); - value.type = NumericValue::NM_unsigned; - } - else if (val->IsInt64()) - { - value.signedval = val->GetInt64(); - value.type = NumericValue::NM_signed; - } - else if (val->IsDouble()) - { - value.floatval = val->GetDouble(); - value.type = NumericValue::NM_float; - } - } - } - return arc; -} diff --git a/src/serializer.h b/src/serializer.h deleted file mode 100644 index 71f8f76e11c..00000000000 --- a/src/serializer.h +++ /dev/null @@ -1,319 +0,0 @@ -#ifndef __SERIALIZER_H -#define __SERIALIZER_H - -#include -#include -#include "tarray.h" -#include "r_defs.h" -#include "resourcefiles/file_zip.h" -#include "tflags.h" -#include "utility/dictionary.h" - -extern bool save_full; - -struct ticcmd_t; -struct usercmd_t; - -struct FWriter; -struct FReader; -class PClass; -class PClassActor; -struct FStrifeDialogueNode; -class FFont; -struct FState; -struct FDoorAnimation; -class FSoundID; -struct FPolyObj; -union FRenderStyle; -struct FInterpolator; - -inline bool nullcmp(const void *buffer, size_t length) -{ - const char *p = (const char *)buffer; - for (; length > 0; length--) - { - if (*p++ != 0) return false; - } - return true; -} - -struct NumericValue -{ - enum EType - { - NM_invalid, - NM_signed, - NM_unsigned, - NM_float - } type; - - union - { - int64_t signedval; - uint64_t unsignedval; - double floatval; - }; - - bool operator !=(const NumericValue &other) - { - return type != other.type || signedval != other.signedval; - } -}; - - -class FSerializer -{ - -public: - FWriter *w = nullptr; - FReader *r = nullptr; - FLevelLocals *Level; - - unsigned ArraySize(); - void WriteKey(const char *key); - void WriteObjects(); - -public: - - FSerializer(FLevelLocals *l) : Level(l) - {} - - ~FSerializer() - { - mErrors = 0; // The destructor may not throw an exception so silence the error checker. - Close(); - } - bool OpenWriter(bool pretty = true); - bool OpenReader(const char *buffer, size_t length); - bool OpenReader(FCompressedBuffer *input); - void Close(); - void ReadObjects(bool hubtravel); - bool BeginObject(const char *name); - void EndObject(); - bool BeginArray(const char *name); - void EndArray(); - unsigned GetSize(const char *group); - const char *GetKey(); - const char *GetOutput(unsigned *len = nullptr); - FCompressedBuffer GetCompressedOutput(); - FSerializer &Args(const char *key, int *args, int *defargs, int special); - FSerializer &Terrain(const char *key, int &terrain, int *def = nullptr); - FSerializer &Sprite(const char *key, int32_t &spritenum, int32_t *def); - FSerializer &StringPtr(const char *key, const char *&charptr); // This only retrieves the address but creates no permanent copy of the string unlike the regular char* serializer. - FSerializer &AddString(const char *key, const char *charptr); - const char *GetString(const char *key); - FSerializer &ScriptNum(const char *key, int &num); - bool isReading() const - { - return r != nullptr; - } - - bool isWriting() const - { - return w != nullptr; - } - - bool canSkip() const; - - template - FSerializer &operator()(const char *key, T &obj) - { - return Serialize(*this, key, obj, (T*)nullptr); - } - - template - FSerializer &operator()(const char *key, T &obj, T &def) - { - return Serialize(*this, key, obj, save_full? nullptr : &def); - } - - template - FSerializer &Array(const char *key, T *obj, int count, bool fullcompare = false) - { - if (!save_full && fullcompare && isWriting() && nullcmp(obj, count * sizeof(T))) - { - return *this; - } - - if (BeginArray(key)) - { - if (isReading()) - { - int max = ArraySize(); - if (max < count) count = max; - } - for (int i = 0; i < count; i++) - { - Serialize(*this, nullptr, obj[i], (T*)nullptr); - } - EndArray(); - } - return *this; - } - - template - FSerializer &Array(const char *key, T *obj, T *def, int count, bool fullcompare = false) - { - if (!save_full && fullcompare && isWriting() && def != nullptr && !memcmp(obj, def, count * sizeof(T))) - { - return *this; - } - if (BeginArray(key)) - { - if (isReading()) - { - int max = ArraySize(); - if (max < count) count = max; - } - for (int i = 0; i < count; i++) - { - Serialize(*this, nullptr, obj[i], def ? &def[i] : nullptr); - } - EndArray(); - } - return *this; - } - - template - FSerializer &Enum(const char *key, T &obj) - { - auto val = (typename std::underlying_type::type)obj; - Serialize(*this, key, val, nullptr); - obj = (T)val; - return *this; - } - - int mErrors = 0; -}; - -FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_t *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint64_t *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value, int32_t *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint32_t *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, int8_t &value, int8_t *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, uint8_t &value, uint8_t *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, int16_t &value, int16_t *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, uint16_t &value, uint16_t *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode = nullptr); -FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *defval); -FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def); -FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def); -FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def); -FSerializer &Serialize(FSerializer &arc, const char *key, ticcmd_t &sid, ticcmd_t *def); -FSerializer &Serialize(FSerializer &arc, const char *key, usercmd_t &cmd, usercmd_t *def); -FSerializer &Serialize(FSerializer &arc, const char *key, FInterpolator &rs, FInterpolator *def); - -template -FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) -{ - DObject *v = static_cast(value); - Serialize(arc, key, v, nullptr); - value = static_cast(v); - return arc; -} - -template -FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, TObjPtr *) -{ - Serialize(arc, key, value.o, nullptr); - return arc; -} - -template -FSerializer &Serialize(FSerializer &arc, const char *key, TObjPtr &value, T *) -{ - Serialize(arc, key, value.o, nullptr); - return arc; -} - -template -FSerializer &Serialize(FSerializer &arc, const char *key, TArray &value, TArray *def) -{ - if (arc.isWriting()) - { - if (value.Size() == 0) return arc; // do not save empty arrays - } - bool res = arc.BeginArray(key); - if (arc.isReading()) - { - if (!res) - { - value.Clear(); - return arc; - } - value.Resize(arc.ArraySize()); - } - for (unsigned i = 0; i < value.Size(); i++) - { - Serialize(arc, nullptr, value[i], def? &(*def)[i] : nullptr); - } - arc.EndArray(); - return arc; -} - -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj *&value, FPolyObj **defval); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value, sector_t **defval); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, const FPolyObj *&value, const FPolyObj **defval); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, const sector_t *&value, const sector_t **defval); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value, player_t **defval); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, line_t *&value, line_t **defval); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&value, side_t **defval); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, vertex_t *&value, vertex_t **defval); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor *&clst, PClassActor **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&clst, PClass **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node, FStrifeDialogueNode **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr, FString **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimation *&pstr, FDoorAnimation **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, FLevelLocals *&font, FLevelLocals **def); -template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary *&dict, Dictionary **def); - -FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode); -template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) -{ - return Serialize(arc, key, state, def, nullptr); -} - - -inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector3 &p, DVector3 *def) -{ - return arc.Array(key, &p[0], def? &(*def)[0] : nullptr, 3, true); -} - -inline FSerializer &Serialize(FSerializer &arc, const char *key, DRotator &p, DRotator *def) -{ - return arc.Array(key, &p[0], def? &(*def)[0] : nullptr, 3, true); -} - -inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector2 &p, DVector2 *def) -{ - return arc.Array(key, &p[0], def? &(*def)[0] : nullptr, 2, true); -} - -inline FSerializer &Serialize(FSerializer &arc, const char *key, DAngle &p, DAngle *def) -{ - return Serialize(arc, key, p.Degrees, def? &def->Degrees : nullptr); -} - -inline FSerializer &Serialize(FSerializer &arc, const char *key, PalEntry &pe, PalEntry *def) -{ - return Serialize(arc, key, pe.d, def? &def->d : nullptr); -} - -FSerializer &Serialize(FSerializer &arc, const char *key, FRenderStyle &style, FRenderStyle *def); - -template -FSerializer &Serialize(FSerializer &arc, const char *key, TFlags &flags, TFlags *def) -{ - return Serialize(arc, key, flags.Value, def? &def->Value : nullptr); -} - -FString DictionaryToString(const Dictionary &dict); -Dictionary *DictionaryFromString(const FString &string); - -#endif diff --git a/src/serializer_doom.cpp b/src/serializer_doom.cpp new file mode 100644 index 00000000000..2ec1c8b8616 --- /dev/null +++ b/src/serializer_doom.cpp @@ -0,0 +1,634 @@ +/* +** serializer.cpp +** Savegame wrapper around RapidJSON +** +**--------------------------------------------------------------------------- +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +// The #defines here *MUST* match serializer.cpp, or we will get countless strange errors. +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 // disable this insanity which is bound to make the code break over time. +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag + +#include +#include "rapidjson/rapidjson.h" +#include "rapidjson/writer.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/document.h" +#include "serializer_doom.h" +#include "actor.h" +#include "r_defs.h" +#include "printf.h" +#include "p_lnspec.h" +#include "utf8.h" +#include "g_levellocals.h" +#include "p_conversation.h" +#include "p_terrain.h" + +#include "serializer_internal.h" + +//========================================================================== +// +// we must explicitly delete all thinkers in the array which did not get linked into the thinker lists. +// Otherwise these objects may survive a level deletion and point to incorrect data. +// +//========================================================================== + +void FDoomSerializer::CloseReaderCustom() +{ + for (auto obj : r->mDObjects) + { + auto think = dyn_cast(obj); + if (think != nullptr) + { + if (think->NextThinker == nullptr || think->PrevThinker == nullptr) + { + think->Destroy(); + } + } + } +} + + +//========================================================================== +// +// Special handler for args (because ACS specials' arg0 needs special treatment.) +// +//========================================================================== + +FSerializer &SerializeArgs(FSerializer& arc, const char *key, int *args, int *defargs, int special) +{ + if (arc.isWriting()) + { + auto &w = arc.w; + if (w->inObject() && defargs != nullptr && !memcmp(args, defargs, 5 * sizeof(int))) + { + return arc; + } + + arc.WriteKey(key); + w->StartArray(); + for (int i = 0; i < 5; i++) + { + if (i == 0 && args[i] < 0 && P_IsACSSpecial(special)) + { + w->String(FName(ENamedName(-args[i])).GetChars()); + } + else + { + w->Int(args[i]); + } + } + w->EndArray(); + } + else + { + auto &r = arc.r; + auto val = r->FindKey(key); + if (val != nullptr) + { + if (val->IsArray()) + { + unsigned int cnt = min(val->Size(), 5); + for (unsigned int i = 0; i < cnt; i++) + { + const rapidjson::Value &aval = (*val)[i]; + if (aval.IsInt()) + { + args[i] = aval.GetInt(); + } + else if (i == 0 && aval.IsString()) + { + args[i] = -FName(UnicodeToString(aval.GetString())).GetIndex(); + } + else + { + assert(false && "Integer expected"); + Printf(TEXTCOLOR_RED "Integer expected for '%s[%d]'\n", key, i); + arc.mErrors++; + } + } + } + else + { + assert(false && "array expected"); + Printf(TEXTCOLOR_RED "array expected for '%s'\n", key); + arc.mErrors++; + } + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &SerializeTerrain(FSerializer &arc, const char *key, int &terrain, int *def) +{ + if (arc.isWriting() && def != nullptr && terrain == *def) + { + return arc; + } + FName terr = P_GetTerrainName(terrain); + Serialize(arc, key, terr, nullptr); + if (arc.isReading()) + { + terrain = P_FindTerrain(terr); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &FDoomSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *def) +{ + if (isWriting()) + { + if (w->inObject() && def != nullptr && *def == spritenum) return *this; + WriteKey(key); + w->String(sprites[spritenum].name, 4); + } + else + { + auto val = r->FindKey(key); + if (val != nullptr) + { + if (val->IsString()) + { + uint32_t name = *reinterpret_cast(UnicodeToString(val->GetString())); + for (auto hint = NumStdSprites; hint-- != 0; ) + { + if (sprites[hint].dwName == name) + { + spritenum = hint; + break; + } + } + } + } + } + return *this; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer& FDoomSerializer::StatePointer(const char* key, void* ptraddr, bool *res) +{ + if (isWriting()) + { + if (res) *res = true; + (*this)(key, *(FState**)ptraddr); + } + else + { + ::Serialize(*this, key, *(FState**)ptraddr, nullptr, res); + } + return *this; +} + + + +template<> FSerializer &Serialize(FSerializer &ar, const char *key, FPolyObj *&value, FPolyObj **defval) +{ + auto arc = dynamic_cast(&ar); + if (!arc || arc->Level == nullptr) I_Error("Trying to serialize polyobject without a valid level"); + return SerializePointer(*arc, key, value, defval, arc->Level->Polyobjects); +} + +template<> FSerializer &Serialize(FSerializer &ar, const char *key, side_t *&value, side_t **defval) +{ + auto arc = dynamic_cast(&ar); + if (!arc || arc->Level == nullptr) I_Error("Trying to serialize SIDEDEF without a valid level"); + return SerializePointer(*arc, key, value, defval, arc->Level->sides); +} + +template<> FSerializer &Serialize(FSerializer &ar, const char *key, sector_t *&value, sector_t **defval) +{ + auto arc = dynamic_cast(&ar); + if (!arc || arc->Level == nullptr) I_Error("Trying to serialize sector without a valid level"); + return SerializePointer(*arc, key, value, defval, arc->Level->sectors); +} + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value, player_t **defval) +{ + return SerializePointer(arc, key, value, defval, players, MAXPLAYERS); +} + +template<> FSerializer &Serialize(FSerializer &ar, const char *key, line_t *&value, line_t **defval) +{ + auto arc = dynamic_cast(&ar); + if (!arc || arc->Level == nullptr) I_Error("Trying to serialize linedef without a valid level"); + return SerializePointer(*arc, key, value, defval, arc->Level->lines); +} + +template<> FSerializer &Serialize(FSerializer &ar, const char *key, vertex_t *&value, vertex_t **defval) +{ + auto arc = dynamic_cast(&ar); + if (!arc || arc->Level == nullptr) I_Error("Trying to serialize vertex without a valid level"); + return SerializePointer(*arc, key, value, defval, arc->Level->vertexes); +} + +//========================================================================== +// +// +// +//========================================================================== + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor *&clst, PClassActor **def) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || clst != *def) + { + arc.WriteKey(key); + if (clst == nullptr) + { + arc.w->Null(); + } + else + { + arc.w->String(clst->TypeName.GetChars()); + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsString() || val->IsNull()); + if (val->IsString()) + { + clst = PClass::FindActor(UnicodeToString(val->GetString())); + } + else if (val->IsNull()) + { + clst = nullptr; + } + else + { + Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); + clst = nullptr; + arc.mErrors++; + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode) +{ + if (retcode) *retcode = false; + if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || state != *def) + { + if (retcode) *retcode = true; + arc.WriteKey(key); + if (state == nullptr) + { + arc.w->Null(); + } + else + { + PClassActor *info = FState::StaticFindStateOwner(state); + + if (info != NULL) + { + arc.w->StartArray(); + arc.w->String(info->TypeName.GetChars()); + arc.w->Uint((uint32_t)(state - info->GetStates())); + arc.w->EndArray(); + } + else if (state->DehIndex >= 0) + { + arc.w->StartArray(); + arc.w->String("@DehExtraState@"); + arc.w->Uint(state->DehIndex); + arc.w->EndArray(); + } + else + { + arc.w->Null(); + } + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + if (val->IsNull()) + { + if (retcode) *retcode = true; + state = nullptr; + } + else if (val->IsArray()) + { + if (retcode) *retcode = true; + const rapidjson::Value &cls = (*val)[0]; + const rapidjson::Value &ndx = (*val)[1]; + + state = nullptr; + assert(cls.IsString() && ndx.IsUint()); + if (cls.IsString() && ndx.IsUint()) + { + auto str = UnicodeToString(cls.GetString()); + PClassActor *clas = PClass::FindActor(str); + if (clas && ndx.GetUint() < (unsigned)clas->GetStateCount()) + { + state = clas->GetStates() + ndx.GetUint(); + } + else if (!strcmp(str, "@DehExtraState@")) + { + state = nullptr; + auto pState = dehExtStates.CheckKey(ndx.GetInt()); + if (pState) state = *pState; + } + else + { + // this can actually happen by changing the DECORATE so treat it as a warning, not an error. + state = nullptr; + Printf(TEXTCOLOR_ORANGE "Invalid state '%s+%d' for '%s'\n", cls.GetString(), ndx.GetInt(), key); + } + } + else + { + assert(false && "not a state"); + Printf(TEXTCOLOR_RED "data does not represent a state for '%s'\n", key); + arc.mErrors++; + } + } + else if (!retcode) + { + assert(false && "not an array"); + Printf(TEXTCOLOR_RED "array type expected for '%s'\n", key); + arc.mErrors++; + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node, FStrifeDialogueNode **def) +{ + auto doomarc = static_cast(&arc); + if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || node != *def) + { + arc.WriteKey(key); + if (node == nullptr) + { + arc.w->Null(); + } + else + { + arc.w->Uint(node->ThisNodeNum); + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsUint() || val->IsNull()); + if (val->IsNull()) + { + node = nullptr; + } + else if (val->IsUint()) + { + if (val->GetUint() >= doomarc->Level->StrifeDialogues.Size()) + { + node = nullptr; + } + else + { + node = doomarc->Level->StrifeDialogues[val->GetUint()]; + } + } + else + { + Printf(TEXTCOLOR_RED "integer expected for '%s'\n", key); + arc.mErrors++; + node = nullptr; + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr, FString **def) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || pstr != *def) + { + arc.WriteKey(key); + if (pstr == nullptr) + { + arc.w->Null(); + } + else + { + arc.w->String(pstr->GetChars()); + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsNull() || val->IsString()); + if (val->IsNull()) + { + pstr = nullptr; + } + else if (val->IsString()) + { + pstr = AActor::mStringPropertyData.Alloc(UnicodeToString(val->GetString())); + } + else + { + Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); + pstr = nullptr; + arc.mErrors++; + } + } + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def) +{ + if (arc.isWriting()) + { + if (!arc.w->inObject() || def == nullptr || strcmp(pstr, *def)) + { + arc.WriteKey(key); + if (pstr == nullptr) + { + arc.w->Null(); + } + else + { + arc.w->String(pstr); + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsNull() || val->IsString()); + if (val->IsNull()) + { + pstr = nullptr; + } + else if (val->IsString()) + { + pstr = copystring(UnicodeToString(val->GetString())); + } + else + { + Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); + pstr = nullptr; + arc.mErrors++; + } + } + } + return arc; +} + +//========================================================================== +// +// This is a bit of a cheat because it never actually writes out the pointer. +// The rules for levels are that they must be self-contained. +// No level and no object that is part of a level may reference a different one. +// +// When writing, this merely checks if the rules are obeyed and if not errors out. +// When reading, it assumes that the object was properly written and restores +// the reference from the owning level +// +// The only exception are null pointers which are allowed +// +//========================================================================== + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FLevelLocals *&lev, FLevelLocals **def) +{ + auto doomarc = static_cast(&arc); + if (arc.isWriting()) + { + if (!arc.w->inObject() || lev == nullptr) + { + arc.WriteKey(key); + if (lev == nullptr) + { + arc.w->Null(); + } + else + { + // This MUST be the currently serialized level, anything else will error out here as a sanity check. + if (doomarc->Level == nullptr || lev != doomarc->Level) + { + I_Error("Attempt to serialize invalid level reference"); + } + if (!arc.w->inObject()) + { + arc.w->Bool(true); // In the unlikely case this is used in an array, write a filler. + } + } + } + } + else + { + auto val = arc.r->FindKey(key); + if (val != nullptr) + { + assert(val->IsNull() || val->IsBool()); + if (val->IsNull()) + { + lev = nullptr; + } + else + { + lev = doomarc->Level; + } + } + else lev = doomarc->Level; + } + return arc; +} + diff --git a/src/serializer_doom.h b/src/serializer_doom.h new file mode 100644 index 00000000000..b399568c282 --- /dev/null +++ b/src/serializer_doom.h @@ -0,0 +1,64 @@ +#pragma once + +#include "serializer.h" + +class player_t; +struct sector_t; +struct line_t; +struct side_t; +struct vertex_t; +struct ticcmd_t; +struct usercmd_t; +class PClassActor; +struct FStrifeDialogueNode; +struct FState; +struct FDoorAnimation; +struct FPolyObj; +struct FInterpolator; +struct FLevelLocals; + +class FDoomSerializer : public FSerializer +{ + + void CloseReaderCustom() override; + +public: + FLevelLocals* Level; + + FDoomSerializer(FLevelLocals *l) : Level(l) + { + SetUniqueSoundNames(); + } + + FSerializer &Sprite(const char *key, int32_t &spritenum, int32_t *def) override; + FSerializer& StatePointer(const char* key, void* ptraddr, bool *res) override; + +}; + +FSerializer &SerializeArgs(FSerializer &arc, const char *key, int *args, int *defargs, int special); +FSerializer &SerializeTerrain(FSerializer &arc, const char *key, int &terrain, int *def = nullptr); + +FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval); +FSerializer &Serialize(FSerializer &arc, const char *key, ticcmd_t &sid, ticcmd_t *def); +FSerializer &Serialize(FSerializer &arc, const char *key, usercmd_t &cmd, usercmd_t *def); +FSerializer &Serialize(FSerializer &arc, const char *key, FInterpolator &rs, FInterpolator *def); + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj *&value, FPolyObj **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value, sector_t **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, const FPolyObj *&value, const FPolyObj **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, const sector_t *&value, const sector_t **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value, player_t **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, line_t *&value, line_t **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&value, side_t **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, vertex_t *&value, vertex_t **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor *&clst, PClassActor **def); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node, FStrifeDialogueNode **def); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr, FString **def); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimation *&pstr, FDoorAnimation **def); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, FLevelLocals *&font, FLevelLocals **def); +FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode); +template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) +{ + return Serialize(arc, key, state, def, nullptr); +} diff --git a/src/sound/backend/oalsound.h b/src/sound/backend/oalsound.h deleted file mode 100644 index 952b8776e25..00000000000 --- a/src/sound/backend/oalsound.h +++ /dev/null @@ -1,287 +0,0 @@ -#ifndef OALSOUND_H -#define OALSOUND_H - -#include -#include -#include -#include -#include - -#include "i_sound.h" -#include "s_sound.h" - -#ifndef NO_OPENAL - -#ifdef DYN_OPENAL -#define AL_NO_PROTOTYPES -#include "thirdparty/al.h" -#include "thirdparty/alc.h" -#else -#include "al.h" -#include "alc.h" -#endif - -#include "efx.h" - -#ifndef ALC_ENUMERATE_ALL_EXT -#define ALC_ENUMERATE_ALL_EXT 1 -#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 -#define ALC_ALL_DEVICES_SPECIFIER 0x1013 -#endif - -#ifndef ALC_EXT_disconnect -#define ALC_EXT_disconnect 1 -#define ALC_CONNECTED 0x313 -#endif - -#ifndef ALC_SOFT_HRTF -#define ALC_SOFT_HRTF 1 -#define ALC_HRTF_SOFT 0x1992 -#define ALC_DONT_CARE_SOFT 0x0002 -#define ALC_HRTF_STATUS_SOFT 0x1993 -#define ALC_HRTF_DISABLED_SOFT 0x0000 -#define ALC_HRTF_ENABLED_SOFT 0x0001 -#define ALC_HRTF_DENIED_SOFT 0x0002 -#define ALC_HRTF_REQUIRED_SOFT 0x0003 -#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 -#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 -#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 -#define ALC_HRTF_SPECIFIER_SOFT 0x1995 -#define ALC_HRTF_ID_SOFT 0x1996 -typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); -typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); -ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); -#endif -#endif - -#ifndef AL_EXT_source_distance_model -#define AL_EXT_source_distance_model 1 -#define AL_SOURCE_DISTANCE_MODEL 0x200 -#endif - -#ifndef AL_SOFT_loop_points -#define AL_SOFT_loop_points 1 -#define AL_LOOP_POINTS_SOFT 0x2015 -#endif - -#ifndef AL_EXT_float32 -#define AL_EXT_float32 1 -#define AL_FORMAT_MONO_FLOAT32 0x10010 -#define AL_FORMAT_STEREO_FLOAT32 0x10011 -#endif - -#ifndef AL_EXT_MCFORMATS -#define AL_EXT_MCFORMATS 1 -#define AL_FORMAT_QUAD8 0x1204 -#define AL_FORMAT_QUAD16 0x1205 -#define AL_FORMAT_QUAD32 0x1206 -#define AL_FORMAT_REAR8 0x1207 -#define AL_FORMAT_REAR16 0x1208 -#define AL_FORMAT_REAR32 0x1209 -#define AL_FORMAT_51CHN8 0x120A -#define AL_FORMAT_51CHN16 0x120B -#define AL_FORMAT_51CHN32 0x120C -#define AL_FORMAT_61CHN8 0x120D -#define AL_FORMAT_61CHN16 0x120E -#define AL_FORMAT_61CHN32 0x120F -#define AL_FORMAT_71CHN8 0x1210 -#define AL_FORMAT_71CHN16 0x1211 -#define AL_FORMAT_71CHN32 0x1212 -#endif - -#ifndef AL_EXT_SOURCE_RADIUS -#define AL_EXT_SOURCE_RADIUS 1 -#define AL_SOURCE_RADIUS 0x1031 -#endif - -#ifndef AL_SOFT_source_resampler -#define AL_SOFT_source_resampler 1 -#define AL_NUM_RESAMPLERS_SOFT 0x1210 -#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 -#define AL_SOURCE_RESAMPLER_SOFT 0x1212 -#define AL_RESAMPLER_NAME_SOFT 0x1213 -typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); -#ifdef AL_ALEXT_PROTOTYPES -AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); -#endif -#endif - -#ifndef AL_SOFT_source_spatialize -#define AL_SOFT_source_spatialize -#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 -#define AL_AUTO_SOFT 0x0002 -#endif - - -class OpenALSoundStream; - -class OpenALSoundRenderer : public SoundRenderer -{ -public: - OpenALSoundRenderer(); - virtual ~OpenALSoundRenderer(); - - virtual void SetSfxVolume(float volume); - virtual void SetMusicVolume(float volume); - virtual SoundHandle LoadSound(uint8_t *sfxdata, int length); - virtual SoundHandle LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1); - virtual void UnloadSound(SoundHandle sfx); - virtual unsigned int GetMSLength(SoundHandle sfx); - virtual unsigned int GetSampleLength(SoundHandle sfx); - virtual float GetOutputRate(); - - // Streaming sounds. - virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata); - - // Starts a sound. - virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan, float startTime); - virtual FISoundChannel *StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime); - - // Changes a channel's volume. - virtual void ChannelVolume(FISoundChannel *chan, float volume); - - // Changes a channel's pitch. - virtual void ChannelPitch(FISoundChannel *chan, float pitch); - - // Stops a sound channel. - virtual void StopChannel(FISoundChannel *chan); - - // Returns position of sound on this channel, in samples. - virtual unsigned int GetPosition(FISoundChannel *chan); - - // Synchronizes following sound startups. - virtual void Sync(bool sync); - - // Pauses or resumes all sound effect channels. - virtual void SetSfxPaused(bool paused, int slot); - - // Pauses or resumes *every* channel, including environmental reverb. - virtual void SetInactive(SoundRenderer::EInactiveState inactive); - - // Updates the volume, separation, and pitch of a sound channel. - virtual void UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel); - - virtual void UpdateListener(SoundListener *); - virtual void UpdateSounds(); - - virtual void MarkStartTime(FISoundChannel*, float startTime); - virtual float GetAudibility(FISoundChannel*); - - - virtual bool IsValid(); - virtual void PrintStatus(); - virtual void PrintDriversList(); - virtual FString GatherStats(); - -private: - struct { - bool EXT_EFX; - bool EXT_disconnect; - bool SOFT_HRTF; - bool SOFT_pause_device; - } ALC; - struct { - bool EXT_source_distance_model; - bool EXT_SOURCE_RADIUS; - bool SOFT_deferred_updates; - bool SOFT_loop_points; - bool SOFT_source_resampler; - bool SOFT_source_spatialize; - } AL; - - // EFX Extension function pointer variables. Loaded after context creation - // if EFX is supported. These pointers may be context- or device-dependant, - // thus can't be static - // Effect objects - LPALGENEFFECTS alGenEffects; - LPALDELETEEFFECTS alDeleteEffects; - LPALISEFFECT alIsEffect; - LPALEFFECTI alEffecti; - LPALEFFECTIV alEffectiv; - LPALEFFECTF alEffectf; - LPALEFFECTFV alEffectfv; - LPALGETEFFECTI alGetEffecti; - LPALGETEFFECTIV alGetEffectiv; - LPALGETEFFECTF alGetEffectf; - LPALGETEFFECTFV alGetEffectfv; - // Filter objects - LPALGENFILTERS alGenFilters; - LPALDELETEFILTERS alDeleteFilters; - LPALISFILTER alIsFilter; - LPALFILTERI alFilteri; - LPALFILTERIV alFilteriv; - LPALFILTERF alFilterf; - LPALFILTERFV alFilterfv; - LPALGETFILTERI alGetFilteri; - LPALGETFILTERIV alGetFilteriv; - LPALGETFILTERF alGetFilterf; - LPALGETFILTERFV alGetFilterfv; - // Auxiliary slot objects - LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots; - LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots; - LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot; - LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti; - LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv; - LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf; - LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv; - LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti; - LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; - LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; - LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; - - ALvoid (AL_APIENTRY*alDeferUpdatesSOFT)(void); - ALvoid (AL_APIENTRY*alProcessUpdatesSOFT)(void); - - LPALGETSTRINGISOFT alGetStringiSOFT; - - void (ALC_APIENTRY*alcDevicePauseSOFT)(ALCdevice *device); - void (ALC_APIENTRY*alcDeviceResumeSOFT)(ALCdevice *device); - - void BackgroundProc(); - void AddStream(OpenALSoundStream *stream); - void RemoveStream(OpenALSoundStream *stream); - - void LoadReverb(const ReverbContainer *env); - void PurgeStoppedSources(); - static FSoundChan *FindLowestChannel(); - - std::thread StreamThread; - std::mutex StreamLock; - std::condition_variable StreamWake; - std::atomic QuitThread; - - ALCdevice *Device; - ALCcontext *Context; - - TArray Sources; - - ALfloat SfxVolume; - ALfloat MusicVolume; - - int SFXPaused; - TArray FreeSfx; - TArray PausableSfx; - TArray ReverbSfx; - TArray SfxGroup; - - const ReverbContainer *PrevEnvironment; - - typedef TMap EffectMap; - typedef TMapIterator EffectMapIter; - ALuint EnvSlot; - ALuint EnvFilters[2]; - EffectMap EnvEffects; - - bool WasInWater; - - TArray Streams; - friend class OpenALSoundStream; - - ALCdevice *InitDevice(); -}; - -#endif // NO_OPENAL - -#endif diff --git a/src/sound/s_advsound.cpp b/src/sound/s_advsound.cpp index 8fbd7b86d99..f48e6855e4a 100644 --- a/src/sound/s_advsound.cpp +++ b/src/sound/s_advsound.cpp @@ -34,10 +34,10 @@ // HEADER FILES ------------------------------------------------------------ -#include "templates.h" + #include "actor.h" #include "c_dispatch.h" -#include "w_wad.h" +#include "filesystem.h" #include "gi.h" #include "i_sound.h" #include "d_netinf.h" @@ -49,6 +49,9 @@ #include "vm.h" #include "i_system.h" #include "s_music.h" +#include "i_music.h" + +using namespace FileSys; // MACROS ------------------------------------------------------------------ @@ -70,28 +73,38 @@ struct FPlayerClassLookup // a particular class and gender. class FPlayerSoundHashTable { + TMap map; public: - FPlayerSoundHashTable(); - FPlayerSoundHashTable(const FPlayerSoundHashTable &other); - ~FPlayerSoundHashTable(); - void AddSound (int player_sound_id, int sfx_id); - int LookupSound (int player_sound_id); - FPlayerSoundHashTable &operator= (const FPlayerSoundHashTable &other); - void MarkUsed(); + void AddSound(FSoundID player_sound_id, FSoundID sfx_id) + { + map.Insert(player_sound_id.index(), sfx_id); + } + FSoundID LookupSound(FSoundID player_sound_id) + { + auto v = map.CheckKey(player_sound_id.index()); + return v ? *v : NO_SOUND; + } + void MarkUsed() + { + decltype(map)::Iterator it(map); + decltype(map)::Pair* pair; + + while (it.NextPair(pair)) + { + soundEngine->MarkUsed(pair->Value); + } + } protected: struct Entry { - Entry *Next; - int PlayerSoundID; - int SfxID; + Entry* Next; + FSoundID PlayerSoundID; + FSoundID SfxID; }; enum { NUM_BUCKETS = 23 }; - Entry *Buckets[NUM_BUCKETS]; - - void Init (); - void Free (); + Entry* Buckets[NUM_BUCKETS]; }; struct FAmbientSound @@ -122,6 +135,7 @@ enum SICommands SI_Registered, SI_ArchivePath, SI_MusicVolume, + SI_Replaygain, SI_MidiDevice, SI_IfDoom, SI_IfHeretic, @@ -132,6 +146,7 @@ enum SICommands SI_MusicAlias, SI_EDFOverride, SI_Attenuation, + SI_PitchSet, }; // Blood was a cool game. If Monolith ever releases the source for it, @@ -147,27 +162,19 @@ struct FBloodSFX char RawName[9]; // name of RAW resource }; -// music volume multipliers -struct FMusicVolume -{ - FMusicVolume *Next; - float Volume; - char MusicName[1]; -}; - // This is used to recreate the skin sounds after reloading SNDINFO due to a changed local one. struct FSavedPlayerSoundInfo { FName pclass; int gender; - int refid; + FSoundID refid; int lumpnum; bool alias; }; // This specifies whether Timidity or Windows playback is preferred for a certain song (only useful for Windows.) MusicAliasMap MusicAliases; -MidiDeviceMap MidiDevices; +static bool sndinfo_locked; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -178,18 +185,18 @@ extern bool IsFloat (const char *str); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static int SortPlayerClasses (const void *a, const void *b); -static int S_DupPlayerSound (const char *pclass, int gender, int refid, int aliasref); -static void S_SavePlayerSound (const char *pclass, int gender, int refid, int lumpnum, bool alias); +static FSoundID S_DupPlayerSound (const char *pclass, int gender, FSoundID refid, FSoundID aliasref); +static void S_SavePlayerSound (const char *pclass, int gender, FSoundID refid, int lumpnum, bool alias); static void S_RestorePlayerSounds(); static int S_AddPlayerClass (const char *name); static int S_AddPlayerGender (int classnum, int gender); static int S_FindPlayerClass (const char *name); -static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid); -static void S_ParsePlayerSoundCommon (FScanner &sc, FString &pclass, int &gender, int &refid); +static FSoundID S_LookupPlayerSound (int classidx, int gender, FSoundID refid); +static void S_ParsePlayerSoundCommon (FScanner &sc, FString &pclass, int &gender, FSoundID &refid); static void S_AddSNDINFO (int lumpnum); static void S_AddBloodSFX (int lumpnum); static void S_AddStrifeVoice (int lumpnum); -static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc=NULL); +static FSoundID S_AddSound (const char *logicalname, int lumpnum, FScanner *sc=NULL); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- @@ -217,6 +224,7 @@ static const char *SICommandStrings[] = "$registered", "$archivepath", "$musicvolume", + "$replaygain", "$mididevice", "$ifdoom", "$ifheretic", @@ -227,10 +235,10 @@ static const char *SICommandStrings[] = "$musicalias", "$edfoverride", "$attenuation", + "$pitchset", NULL }; -static FMusicVolume *MusicVolumes; static TArray SavedPlayerSounds; static int NumPlayerReserves; @@ -247,28 +255,6 @@ static uint8_t CurrentPitchMask; // CODE -------------------------------------------------------------------- -//========================================================================== -// -// S_GetMusicVolume -// -// Gets the relative volume for the given music track -//========================================================================== - -float S_GetMusicVolume (const char *music) -{ - FMusicVolume *musvol = MusicVolumes; - - while (musvol != NULL) - { - if (!stricmp (music, musvol->MusicName)) - { - return musvol->Volume; - } - musvol = musvol->Next; - } - return 1.f; -} - //========================================================================== // // S_CheckIntegrity @@ -278,12 +264,11 @@ float S_GetMusicVolume (const char *music) static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArray &chain) { - auto &S_sfx = soundEngine->GetSounds(); sfxinfo_t *me = sfx; bool success = true; unsigned siz = chain.Size(); - if (sfx->bPlayerReserve) + if (sfx->UserData[0] & SND_PlayerReserve) { return true; } @@ -301,7 +286,7 @@ static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArrayResolveRandomSound(me); for (unsigned i = 0; i < list->Choices.Size(); ++i) { - auto rsfx = &S_sfx[list->Choices[i]]; + auto rsfx = soundEngine->GetWritableSfx(list->Choices[i]); if (rsfx == startsfx) { Printf(TEXTCOLOR_RED "recursive sound $random found for %s:\n", startsfx->name.GetChars()); @@ -319,7 +304,7 @@ static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArraylink != sfxinfo_t::NO_LINK) { - me = &S_sfx[me->link]; + me = soundEngine->GetWritableSfx(me->link); if (me == startsfx) { Printf(TEXTCOLOR_RED "recursive sound $alias found for %s:\n", startsfx->name.GetChars()); @@ -344,22 +329,21 @@ void S_CheckIntegrity() TArray chain; TArray broken; - auto &S_sfx = soundEngine->GetSounds(); - broken.Resize(S_sfx.Size()); - memset(&broken[0], 0, sizeof(bool)*S_sfx.Size()); - for (unsigned i = 0; i < S_sfx.Size(); i++) + broken.Resize(soundEngine->GetNumSounds()); + memset(&broken[0], 0, sizeof(bool) * soundEngine->GetNumSounds()); + for (unsigned i = 0; i < soundEngine->GetNumSounds(); i++) { - auto &sfx = S_sfx[i]; + auto &sfx = *soundEngine->GetWritableSfx(FSoundID::fromInt(i)); broken[i] = !S_CheckSound(&sfx, &sfx, chain); } - for (unsigned i = 0; i < S_sfx.Size(); i++) + for (unsigned i = 0; i < soundEngine->GetNumSounds(); i++) { if (broken[i]) { - auto &sfx = S_sfx[i]; + auto& sfx = *soundEngine->GetWritableSfx(FSoundID::fromInt(i)); Printf(TEXTCOLOR_RED "Sound %s has been disabled\n", sfx.name.GetChars()); sfx.bRandomHeader = false; - sfx.link = 0; // link to the empty sound. + sfx.link = NO_SOUND; // link to the empty sound. } } } @@ -375,20 +359,15 @@ void S_CheckIntegrity() unsigned int S_GetMSLength(FSoundID sound) { - auto &S_sfx = soundEngine->GetSounds(); - if ((unsigned int)sound >= S_sfx.Size()) - { - return 0; - } - - sfxinfo_t *sfx = &S_sfx[sound]; + sfxinfo_t* sfx = soundEngine->GetWritableSfx(sound); + if (!sfx) return 0; // Resolve player sounds, random sounds, and aliases if (sfx->link != sfxinfo_t::NO_LINK) { - if (sfx->bPlayerReserve) + if (sfx->UserData[0] & SND_PlayerReserve) { - sfx = &S_sfx[S_FindSkinnedSound (NULL, sound)]; + sfx = soundEngine->GetWritableSfx(S_FindSkinnedSound(NULL, sound)); } else if (sfx->bRandomHeader) { @@ -409,7 +388,7 @@ unsigned int S_GetMSLength(FSoundID sound) } else { - sfx = &S_sfx[sfx->link]; + sfx = soundEngine->GetWritableSfx(sfx->link); } } @@ -433,24 +412,21 @@ DEFINE_ACTION_FUNCTION(DObject,S_GetLength) // lump. Otherwise, adds the new mapping by using S_AddSoundLump(). //========================================================================== -int S_AddSound (const char *logicalname, const char *lumpname, FScanner *sc) +FSoundID S_AddSound (const char *logicalname, const char *lumpname, FScanner *sc) { - int lump = Wads.CheckNumForFullName (lumpname, true, ns_sounds); + int lump = fileSystem.CheckNumForFullName (lumpname, true, ns_sounds); return S_AddSound (logicalname, lump); } -static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc) +static FSoundID S_AddSound (const char *logicalname, int lumpnum, FScanner *sc) { - auto &S_sfx = soundEngine->GetSounds(); - int sfxid; + FSoundID sfxid = soundEngine->FindSoundNoHash (logicalname); - sfxid = soundEngine->FindSoundNoHash (logicalname); - - if (sfxid > 0) + if (sfxid.isvalid()) { // If the sound has already been defined, change the old definition - sfxinfo_t *sfx = &S_sfx[sfxid]; + auto sfx = soundEngine->GetWritableSfx(sfxid); - if (sfx->bPlayerReserve) + if (sfx->UserData[0] & SND_PlayerReserve) { if (sc != NULL) { @@ -462,15 +438,15 @@ static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc) } } // Redefining a player compatibility sound will redefine the target instead. - if (sfx->bPlayerCompat) + if (sfx->UserData[0] & SND_PlayerCompat) { - sfx = &S_sfx[sfx->link]; + sfx = soundEngine->GetWritableSfx(sfx->link); } if (sfx->bRandomHeader) { FRandomSoundList* rnd = soundEngine->ResolveRandomSound(sfx); rnd->Choices.Reset(); - rnd->Owner = 0; + rnd->Owner = NO_SOUND; } sfx->lumpnum = lumpnum; sfx->bRandomHeader = false; @@ -498,36 +474,37 @@ static int S_AddSound (const char *logicalname, int lumpnum, FScanner *sc) // Adds the given sound lump to the player sound lists. //========================================================================== -int S_AddPlayerSound (const char *pclass, int gender, int refid, - const char *lumpname) +FSoundID S_AddPlayerSound (const char *pclass, int gender, FSoundID refid, const char *lumpname) { int lump=-1; if (lumpname) { - lump = Wads.CheckNumForFullName (lumpname, true, ns_sounds); + lump = fileSystem.CheckNumForFullName (lumpname, true, ns_sounds); } return S_AddPlayerSound (pclass, gender, refid, lump); } -int S_AddPlayerSound (const char *pclass, int gender, int refid, int lumpnum, bool fromskin) +FSoundID S_AddPlayerSound (const char *pclass, int gender, FSoundID refid, int lumpnum, bool fromskin) { - auto &S_sfx = soundEngine->GetSounds(); FString fakename; - int id; + FSoundID id; + + auto sfx = soundEngine->GetSfx(refid); + if (refid == NO_SOUND || !sfx) return NO_SOUND; fakename = pclass; fakename += '"'; fakename += '0' + gender; fakename += '"'; - fakename += S_sfx[refid].name; + fakename += sfx->name.GetChars(); - id = soundEngine->AddSoundLump (fakename, lumpnum, CurrentPitchMask); + id = soundEngine->AddSoundLump (fakename.GetChars(), lumpnum, CurrentPitchMask); int classnum = S_AddPlayerClass (pclass); int soundlist = S_AddPlayerGender (classnum, gender); - PlayerSounds[soundlist].AddSound (S_sfx[refid].link, id); + PlayerSounds[soundlist].AddSound (sfx->link, id); if (fromskin) S_SavePlayerSound(pclass, gender, refid, lumpnum, false); @@ -541,16 +518,16 @@ int S_AddPlayerSound (const char *pclass, int gender, int refid, int lumpnum, bo // Adds the player sound as an alias to an existing sound. //========================================================================== -int S_AddPlayerSoundExisting (const char *pclass, int gender, int refid, - int aliasto, bool fromskin) +FSoundID S_AddPlayerSoundExisting (const char *pclass, int gender, FSoundID refid, FSoundID aliasto, bool fromskin) { int classnum = S_AddPlayerClass (pclass); int soundlist = S_AddPlayerGender (classnum, gender); + auto sfx = soundEngine->GetSfx(refid); + if (refid == NO_SOUND || !sfx) return NO_SOUND; - auto &S_sfx = soundEngine->GetSounds(); - PlayerSounds[soundlist].AddSound (S_sfx[refid].link, aliasto); + PlayerSounds[soundlist].AddSound (sfx->link, aliasto); - if (fromskin) S_SavePlayerSound(pclass, gender, refid, aliasto, true); + if (fromskin) S_SavePlayerSound(pclass, gender, refid, aliasto.index(), true); return aliasto; } @@ -562,173 +539,12 @@ int S_AddPlayerSoundExisting (const char *pclass, int gender, int refid, // Adds a player sound that uses the same sound as an existing player sound. //========================================================================== -int S_DupPlayerSound (const char *pclass, int gender, int refid, int aliasref) +FSoundID S_DupPlayerSound (const char *pclass, int gender, FSoundID refid, FSoundID aliasref) { - int aliasto = S_LookupPlayerSound (pclass, gender, aliasref); + auto aliasto = S_LookupPlayerSound (pclass, gender, aliasref); return S_AddPlayerSoundExisting (pclass, gender, refid, aliasto); } -//========================================================================== -// -// FPlayerSoundHashTable constructor -// -//========================================================================== - -FPlayerSoundHashTable::FPlayerSoundHashTable () -{ - Init(); -} - -//========================================================================== -// -// FPlayerSoundHashTable copy constructor -// -//========================================================================== - -FPlayerSoundHashTable::FPlayerSoundHashTable (const FPlayerSoundHashTable &other) -{ - Init(); - *this = other; -} - -//========================================================================== -// -// FPlayerSoundHashTable destructor -// -//========================================================================== - -FPlayerSoundHashTable::~FPlayerSoundHashTable () -{ - Free (); -} - -//========================================================================== -// -// FPlayerSoundHashTable :: Init -// -//========================================================================== - -void FPlayerSoundHashTable::Init () -{ - for (int i = 0; i < NUM_BUCKETS; ++i) - { - Buckets[i] = NULL; - } -} - -//========================================================================== -// -// FPlayerSoundHashTable :: Free -// -//========================================================================== - -void FPlayerSoundHashTable::Free () -{ - for (int i = 0; i < NUM_BUCKETS; ++i) - { - Entry *entry, *next; - - for (entry = Buckets[i]; entry != NULL; ) - { - next = entry->Next; - delete entry; - entry = next; - } - Buckets[i] = NULL; - } -} - -//========================================================================== -// -// FPlayerSoundHashTable :: operator= -// -//========================================================================== - -FPlayerSoundHashTable &FPlayerSoundHashTable::operator= (const FPlayerSoundHashTable &other) -{ - Free (); - for (int i = 0; i < NUM_BUCKETS; ++i) - { - Entry *entry; - - for (entry = other.Buckets[i]; entry != NULL; entry = entry->Next) - { - AddSound (entry->PlayerSoundID, entry->SfxID); - } - } - return *this; -} - -//========================================================================== -// -// FPlayerSoundHashTable :: AddSound -// -//========================================================================== - -void FPlayerSoundHashTable::AddSound (int player_sound_id, int sfx_id) -{ - Entry *entry; - unsigned bucket_num = (unsigned)player_sound_id % NUM_BUCKETS; - - // See if the entry exists already. - for (entry = Buckets[bucket_num]; - entry != NULL && entry->PlayerSoundID != player_sound_id; - entry = entry->Next) - { } - - if (entry != NULL) - { // If the player sound is already present, redefine it. - entry->SfxID = sfx_id; - } - else - { // Otherwise, add it to the start of its bucket. - entry = new Entry; - entry->Next = Buckets[bucket_num]; - entry->PlayerSoundID = player_sound_id; - entry->SfxID = sfx_id; - Buckets[bucket_num] = entry; - } -} - -//========================================================================== -// -// FPlayerSoundHashTable :: LookupSound -// -//========================================================================== - -int FPlayerSoundHashTable::LookupSound (int player_sound_id) -{ - Entry *entry; - unsigned bucket_num = (unsigned)player_sound_id % NUM_BUCKETS; - - // See if the entry exists already. - for (entry = Buckets[bucket_num]; - entry != NULL && entry->PlayerSoundID != player_sound_id; - entry = entry->Next) - { } - - return entry != NULL ? entry->SfxID : 0; -} - -//========================================================================== -// -// FPlayerSoundHashTable :: Mark -// -// Marks all sounds defined for this class/gender as used. -// -//========================================================================== - -void FPlayerSoundHashTable::MarkUsed() -{ - for (size_t i = 0; i < NUM_BUCKETS; ++i) - { - for (Entry *probe = Buckets[i]; probe != NULL; probe = probe->Next) - { - soundEngine->MarkUsed(probe->SfxID); - } - } -} - //========================================================================== // // S_ClearSoundData @@ -744,12 +560,7 @@ void S_ClearSoundData() soundEngine->Clear(); Ambients.Clear(); - while (MusicVolumes != NULL) - { - FMusicVolume *me = MusicVolumes; - MusicVolumes = me->Next; - M_Free(me); - } + MusicVolumes.Clear(); NumPlayerReserves = 0; PlayerClassesIsSorted = false; @@ -772,29 +583,27 @@ void S_ClearSoundData() void S_ParseSndInfo (bool redefine) { - auto &S_sfx = soundEngine->GetSounds(); int lump; - if (!redefine) SavedPlayerSounds.Clear(); // clear skin sounds only for initial parsing. + if (redefine && sndinfo_locked) return; + + SavedPlayerSounds.Clear(); // clear skin sounds only for initial parsing. + S_ClearSoundData(); // remove old sound data first! CurrentPitchMask = 0; S_AddSound ("{ no sound }", "DSEMPTY"); // Sound 0 is no sound at all - for (lump = 0; lump < Wads.GetNumLumps(); ++lump) + for (lump = 0; lump < fileSystem.GetNumEntries(); ++lump) { - switch (Wads.GetLumpNamespace (lump)) + switch (fileSystem.GetFileNamespace (lump)) { case ns_global: - if (Wads.CheckLumpName (lump, "SNDINFO")) + if (fileSystem.CheckFileName (lump, "SNDINFO")) { S_AddSNDINFO (lump); } break; - case ns_bloodsfx: - S_AddBloodSFX (lump); - break; - case ns_strifevoices: S_AddStrifeVoice (lump); break; @@ -805,10 +614,14 @@ void S_ParseSndInfo (bool redefine) S_ShrinkPlayerSoundLists (); - sfx_empty = Wads.CheckNumForName ("dsempty", ns_sounds); S_CheckIntegrity(); } +void S_LockLocalSndinfo() +{ + sndinfo_locked = true; +} + //========================================================================== // // Adds a level specific SNDINFO lump @@ -817,6 +630,11 @@ void S_ParseSndInfo (bool redefine) void S_AddLocalSndInfo(int lump) { + if (sndinfo_locked) + { + Printf("Local SNDINFO cannot be combined with DSDHacked sounds!"); + return; + } S_AddSNDINFO(lump); soundEngine->HashSounds (); @@ -834,9 +652,9 @@ void S_AddLocalSndInfo(int lump) static void S_AddSNDINFO (int lump) { - auto &S_sfx = soundEngine->GetSounds(); bool skipToEndIf; - TArray list; + TArray list; + int wantassigns = -1; FScanner sc(lump); skipToEndIf = false; @@ -869,7 +687,7 @@ static void S_AddSNDINFO (int lump) ambient->periodmax = 0; ambient->volume = 0; ambient->attenuation = 0; - ambient->sound = 0; + ambient->sound = NO_SOUND; sc.MustGetString (); ambient->sound = FSoundID(soundEngine->FindSoundTentative(sc.String)); @@ -973,13 +791,14 @@ static void S_AddSNDINFO (int lump) case SI_PlayerSound: { // $playersound FString pclass; - int gender, refid, sfxnum; + int gender; + FSoundID refid, sfxnum; - S_ParsePlayerSoundCommon (sc, pclass, gender, refid); - sfxnum = S_AddPlayerSound (pclass, gender, refid, sc.String); + S_ParsePlayerSoundCommon(sc, pclass, gender, refid); + sfxnum = S_AddPlayerSound(pclass.GetChars(), gender, refid, sc.String); if (0 == stricmp(sc.String, "dsempty")) { - S_sfx[sfxnum].bPlayerSilent = true; + soundEngine->GetWritableSfx(sfxnum)->UserData[0] |= SND_PlayerSilent; } } break; @@ -987,93 +806,121 @@ static void S_AddSNDINFO (int lump) case SI_PlayerSoundDup: { // $playersounddup FString pclass; - int gender, refid, targid; + int gender; + FSoundID refid, targid; S_ParsePlayerSoundCommon (sc, pclass, gender, refid); targid = soundEngine->FindSoundNoHash (sc.String); - if (!S_sfx[targid].bPlayerReserve) + auto sfx = soundEngine->GetWritableSfx(targid); + if (!sfx || !(sfx->UserData[0] & SND_PlayerReserve)) { - sc.ScriptError ("%s is not a player sound", sc.String); + sc.ScriptError("%s is not a player sound", sc.String); } - S_DupPlayerSound (pclass, gender, refid, targid); + S_DupPlayerSound (pclass.GetChars(), gender, refid, targid); } break; case SI_PlayerCompat: { // $playercompat FString pclass; - int gender, refid; - int sfxfrom, aliasto; + int gender; + FSoundID refid; + FSoundID sfxfrom, aliasto; S_ParsePlayerSoundCommon (sc, pclass, gender, refid); sfxfrom = S_AddSound (sc.String, -1, &sc); - aliasto = S_LookupPlayerSound (pclass, gender, refid); - S_sfx[sfxfrom].link = aliasto; - S_sfx[sfxfrom].bPlayerCompat = true; + aliasto = S_LookupPlayerSound (pclass.GetChars(), gender, refid); + auto sfx = soundEngine->GetWritableSfx(sfxfrom); + sfx->link = aliasto; + sfx->UserData[0] |= SND_PlayerCompat; } break; case SI_PlayerAlias: { // $playeralias FString pclass; - int gender, refid; - int soundnum; + int gender; + FSoundID refid, soundnum; S_ParsePlayerSoundCommon (sc, pclass, gender, refid); soundnum = soundEngine->FindSoundTentative (sc.String); - S_AddPlayerSoundExisting (pclass, gender, refid, soundnum); + S_AddPlayerSoundExisting (pclass.GetChars(), gender, refid, soundnum); } break; case SI_Alias: { // $alias - int sfxfrom; + FSoundID sfxfrom; sc.MustGetString (); sfxfrom = S_AddSound (sc.String, -1, &sc); sc.MustGetString (); - if (S_sfx[sfxfrom].bPlayerCompat) + auto sfx = soundEngine->GetWritableSfx(sfxfrom); + if (sfx->UserData[0] & SND_PlayerCompat) { - sfxfrom = S_sfx[sfxfrom].link; + sfxfrom = sfx->link; } - S_sfx[sfxfrom].link = soundEngine->FindSoundTentative (sc.String); - S_sfx[sfxfrom].NearLimit = -1; // Aliases must use the original sound's limit. + sfx->link = soundEngine->FindSoundTentative (sc.String); + sfx->NearLimit = -1; // Aliases must use the original sound's limit. } break; case SI_Limit: { // $limit [] - int sfx; + FSoundID sfxfrom; sc.MustGetString (); - sfx = soundEngine->FindSoundTentative (sc.String); + sfxfrom = soundEngine->FindSoundTentative (sc.String); sc.MustGetNumber (); - S_sfx[sfx].NearLimit = MIN(MAX(sc.Number, 0), 255); + auto sfx = soundEngine->GetWritableSfx(sfxfrom); + sfx->NearLimit = min(max(sc.Number, 0), 255); if (sc.CheckFloat()) { - S_sfx[sfx].LimitRange = float(sc.Float * sc.Float); + sfx->LimitRange = float(sc.Float * sc.Float); } } break; case SI_Singular: { // $singular - int sfx; + FSoundID sfx; sc.MustGetString (); sfx = soundEngine->FindSoundTentative (sc.String); - S_sfx[sfx].bSingular = true; + auto sfxp = soundEngine->GetWritableSfx(sfx); + sfxp->bSingular = true; } break; case SI_PitchShift: { // $pitchshift - int sfx; + FSoundID sfx; sc.MustGetString (); sfx = soundEngine->FindSoundTentative (sc.String); sc.MustGetNumber (); - S_sfx[sfx].PitchMask = (1 << clamp (sc.Number, 0, 7)) - 1; + auto sfxp = soundEngine->GetWritableSfx(sfx); + sfxp->PitchMask = (1 << clamp (sc.Number, 0, 7)) - 1; + } + break; + + case SI_PitchSet: { + // $pitchset [range maximum] + FSoundID sfx; + + sc.MustGetString(); + sfx = soundEngine->FindSoundTentative(sc.String); + sc.MustGetFloat(); + auto sfxp = soundEngine->GetWritableSfx(sfx); + sfxp->DefPitch = (float)sc.Float; + if (sc.CheckFloat()) + { + sfxp->DefPitchMax = (float)sc.Float; + } + else + { + sfxp->DefPitchMax = 0; + } } break; @@ -1085,23 +932,25 @@ static void S_AddSNDINFO (int lump) case SI_Volume: { // $volume - int sfx; + FSoundID sfx; sc.MustGetString(); sfx = soundEngine->FindSoundTentative(sc.String); sc.MustGetFloat(); - S_sfx[sfx].Volume = (float)sc.Float; + auto sfxp = soundEngine->GetWritableSfx(sfx); + sfxp->Volume = (float)sc.Float; } break; case SI_Attenuation: { // $attenuation - int sfx; + FSoundID sfx; sc.MustGetString(); sfx = soundEngine->FindSoundTentative(sc.String); sc.MustGetFloat(); - S_sfx[sfx].Attenuation = (float)sc.Float; + auto sfxp = soundEngine->GetWritableSfx(sfx); + sfxp->Attenuation = (float)sc.Float; } break; @@ -1110,18 +959,19 @@ static void S_AddSNDINFO (int lump) // Using * for the name makes it the default for sounds that don't specify otherwise. FRolloffInfo *rolloff; int type; - int sfx; + FSoundID sfx; sc.MustGetString(); if (sc.Compare("*")) { - sfx = -1; + sfx = INVALID_SOUND; rolloff = &soundEngine->GlobalRolloff(); } else { sfx = soundEngine->FindSoundTentative(sc.String); - rolloff = &S_sfx[sfx].Rolloff; + auto sfxp = soundEngine->GetWritableSfx(sfx); + rolloff = &sfxp->Rolloff; } type = ROLLOFF_Doom; if (!sc.CheckFloat()) @@ -1157,11 +1007,11 @@ static void S_AddSNDINFO (int lump) list.Clear (); sc.MustGetString (); - uint32_t Owner = S_AddSound (sc.String, -1, &sc); + FSoundID Owner = S_AddSound (sc.String, -1, &sc); sc.MustGetStringName ("{"); while (sc.GetString () && !sc.Compare ("}")) { - uint32_t sfxto = soundEngine->FindSoundTentative (sc.String); + FSoundID sfxto = soundEngine->FindSoundTentative (sc.String); if (sfxto == random.Owner) { Printf("Definition of random sound '%s' refers to itself recursively.\n", sc.String); @@ -1171,8 +1021,9 @@ static void S_AddSNDINFO (int lump) } if (list.Size() == 1) { // Only one sound: treat as $alias - S_sfx[Owner].link = list[0]; - S_sfx[Owner].NearLimit = -1; + auto sfxp = soundEngine->GetWritableSfx(Owner); + sfxp->link = list[0]; + sfxp->NearLimit = -1; } else if (list.Size() > 1) { // Only add non-empty random lists @@ -1183,25 +1034,30 @@ static void S_AddSNDINFO (int lump) case SI_MusicVolume: { sc.MustGetString(); - FString musname (sc.String); - sc.MustGetFloat(); - FMusicVolume *mv = (FMusicVolume *)M_Malloc (sizeof(*mv) + musname.Len()); - mv->Volume = (float)sc.Float; - strcpy (mv->MusicName, musname); - mv->Next = MusicVolumes; - MusicVolumes = mv; + int lumpnum = mus_cb.FindMusic(sc.String); + if (!sc.CheckFloat()) + { + sc.MustGetString(); + char* p; + double f = strtod(sc.String, &p); + if (!stricmp(p, "db")) sc.Float = dBToAmplitude((float)sc.Float); + else sc.ScriptError("Bad value for music volume: %s", sc.String); + } + if (lumpnum >= 0) MusicVolumes[lumpnum] = (float)sc.Float; } break; case SI_MusicAlias: { sc.MustGetString(); - int lump = Wads.CheckNumForName(sc.String, ns_music); + int lump = fileSystem.CheckNumForName(sc.String, ns_music); if (lump >= 0) { // do not set the alias if a later WAD defines its own music of this name - int file = Wads.GetLumpFile(lump); - int sndifile = Wads.GetLumpFile(sc.LumpNum); - if (file > sndifile) + // internal files (up to and including iwads) can always be set for musicalias + int file = fileSystem.GetFileContainer(lump); + int sndifile = fileSystem.GetFileContainer(sc.LumpNum); + if ( (file > sndifile) && + !(sndifile <= fileSystem.GetIwadNum() && file <= fileSystem.GetIwadNum()) ) { sc.MustGetString(); continue; @@ -1212,7 +1068,7 @@ static void S_AddSNDINFO (int lump) FName mapped = sc.String; // only set the alias if the lump it maps to exists. - if (mapped == NAME_None || Wads.CheckNumForFullName(sc.String, true, ns_music) >= 0) + if (mapped == NAME_None || fileSystem.CheckNumForFullName(sc.String, true, ns_music) >= 0) { MusicAliases[alias] = mapped; } @@ -1221,7 +1077,7 @@ static void S_AddSNDINFO (int lump) case SI_MidiDevice: { sc.MustGetString(); - FName nm = sc.String; + int lumpnum = mus_cb.FindMusic(sc.String); FScanner::SavedPos save = sc.SavePos(); sc.SetCMode(true); @@ -1253,7 +1109,7 @@ static void S_AddSNDINFO (int lump) sc.RestorePos(save); sc.MustGetString(); } - MidiDevices[nm] = devset; + if (lumpnum >= 0) MidiDevices[lumpnum] = devset; } break; @@ -1268,57 +1124,18 @@ static void S_AddSNDINFO (int lump) else { // Got a logical sound mapping FString name (sc.String); - sc.MustGetString (); - S_AddSound (name, sc.String, &sc); - } - } -} - -//========================================================================== -// -// S_AddBloodSFX -// -// Registers a new sound with the name ".sfx" -// Actual sound data is searched for in the ns_bloodraw namespace. -// -//========================================================================== - -static void S_AddBloodSFX (int lumpnum) -{ - FMemLump sfxlump = Wads.ReadLump(lumpnum); - const FBloodSFX *sfx = (FBloodSFX *)sfxlump.GetMem(); - int rawlump = Wads.CheckNumForName(sfx->RawName, ns_bloodraw); - int sfxnum; + if (wantassigns == -1) + { + wantassigns = sc.CheckString("="); + } + else if (wantassigns) + { + sc.MustGetStringName("="); + } - if (rawlump != -1) - { - auto &S_sfx = soundEngine->GetSounds(); - const char *name = Wads.GetLumpFullName(lumpnum); - sfxnum = S_AddSound(name, rawlump); - if (sfx->Format < 5 || sfx->Format > 12) - { // [0..4] + invalid formats - S_sfx[sfxnum].RawRate = 11025; - } - else if (sfx->Format < 9) - { // [5..8] - S_sfx[sfxnum].RawRate = 22050; - } - else - { // [9..12] - S_sfx[sfxnum].RawRate = 44100; + sc.MustGetString (); + S_AddSound (name.GetChars(), sc.String, &sc); } - S_sfx[sfxnum].bLoadRAW = true; - S_sfx[sfxnum].LoopStart = LittleLong(sfx->LoopStart); - // Make an ambient sound out of it, whether it has a loop point - // defined or not. (Because none of the standard Blood ambient - // sounds are explicitly defined as looping.) - FAmbientSound *ambient = &Ambients[Wads.GetLumpIndexNum(lumpnum)]; - ambient->type = CONTINUOUS; - ambient->periodmin = 0; - ambient->periodmax = 0; - ambient->volume = 1; - ambient->attenuation = 1; - ambient->sound = FSoundID(sfxnum); } } @@ -1333,7 +1150,7 @@ static void S_AddBloodSFX (int lumpnum) static void S_AddStrifeVoice (int lumpnum) { char name[16] = "svox/"; - Wads.GetLumpName (name+5, lumpnum); + strcpy(name + 5, fileSystem.GetFileShortName (lumpnum)); S_AddSound (name, lumpnum); } @@ -1345,7 +1162,7 @@ static void S_AddStrifeVoice (int lumpnum) // (player class, gender, and ref id) //========================================================================== -static void S_ParsePlayerSoundCommon (FScanner &sc, FString &pclass, int &gender, int &refid) +static void S_ParsePlayerSoundCommon (FScanner &sc, FString &pclass, int &gender, FSoundID &refid) { sc.MustGetString (); pclass = sc.String; @@ -1353,21 +1170,22 @@ static void S_ParsePlayerSoundCommon (FScanner &sc, FString &pclass, int &gender gender = D_GenderToInt (sc.String); sc.MustGetString (); refid = soundEngine->FindSoundNoHash (sc.String); - auto &S_sfx = soundEngine->GetSounds(); - if (refid != 0 && !S_sfx[refid].bPlayerReserve && !S_sfx[refid].bTentative) + auto sfx = soundEngine->GetWritableSfx(refid); + if (refid.isvalid() && sfx && !(sfx->UserData[0] & SND_PlayerReserve) && !sfx->bTentative) { sc.ScriptError ("%s has already been used for a non-player sound.", sc.String); } - if (refid == 0) + if (refid == NO_SOUND) { refid = S_AddSound (sc.String, -1, &sc); - S_sfx[refid].bTentative = true; + sfx = soundEngine->GetWritableSfx(refid); + sfx->bTentative = true; } - if (S_sfx[refid].bTentative) + if (sfx->bTentative) { - S_sfx[refid].link = NumPlayerReserves++; - S_sfx[refid].bTentative = false; - S_sfx[refid].bPlayerReserve = true; + sfx->link = FSoundID::fromInt(NumPlayerReserves++); + sfx->bTentative = false; + sfx->UserData[0] |= SND_PlayerReserve; } sc.MustGetString (); } @@ -1418,7 +1236,7 @@ static int S_FindPlayerClass (const char *name) for (i = 0; i < PlayerClassLookups.Size(); ++i) { - if (stricmp (name, PlayerClassLookups[i].Name) == 0) + if (stricmp (name, PlayerClassLookups[i].Name.GetChars()) == 0) { return (int)i; } @@ -1432,7 +1250,7 @@ static int S_FindPlayerClass (const char *name) while (min <= max) { int mid = (min + max) / 2; - int lexx = stricmp (PlayerClassLookups[mid].Name, name); + int lexx = stricmp (PlayerClassLookups[mid].Name.GetChars(), name); if (lexx == 0) { return mid; @@ -1487,13 +1305,13 @@ void S_ShrinkPlayerSoundLists () qsort (&PlayerClassLookups[0], PlayerClassLookups.Size(), sizeof(FPlayerClassLookup), SortPlayerClasses); PlayerClassesIsSorted = true; - DefPlayerClass = S_FindPlayerClass (DefPlayerClassName); + DefPlayerClass = S_FindPlayerClass (DefPlayerClassName.GetChars()); } static int SortPlayerClasses (const void *a, const void *b) { - return stricmp (((const FPlayerClassLookup *)a)->Name, - ((const FPlayerClassLookup *)b)->Name); + return stricmp (((const FPlayerClassLookup *)a)->Name.GetChars(), + ((const FPlayerClassLookup *)b)->Name.GetChars()); } //========================================================================== @@ -1503,20 +1321,11 @@ static int SortPlayerClasses (const void *a, const void *b) // Returns the sound for the given player class, gender, and sound name. //========================================================================== -int S_LookupPlayerSound (const char *pclass, int gender, const char *name) +FSoundID S_LookupPlayerSound (const char *pclass, int gender, FSoundID refid) { - int refid = S_FindSound (name); - if (refid != 0) - { - refid = S_LookupPlayerSound (pclass, gender, refid); - } - return refid; -} + auto sfxp = soundEngine->GetWritableSfx(refid); -int S_LookupPlayerSound (const char *pclass, int gender, FSoundID refid) -{ - auto &S_sfx = soundEngine->GetSounds(); - if (!S_sfx[refid].bPlayerReserve) + if (sfxp && !(sfxp->UserData[0] & SND_PlayerReserve)) { // Not a player sound, so just return this sound return refid; } @@ -1524,9 +1333,8 @@ int S_LookupPlayerSound (const char *pclass, int gender, FSoundID refid) return S_LookupPlayerSound (S_FindPlayerClass (pclass), gender, refid); } -static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid) +static FSoundID S_LookupPlayerSound (int classidx, int gender, FSoundID refid) { - auto &S_sfx = soundEngine->GetSounds(); int ingender = gender; if (classidx == -1) @@ -1550,19 +1358,22 @@ static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid) { return S_LookupPlayerSound (DefPlayerClass, gender, refid); } - return 0; + return NO_SOUND; } gender = g; } + auto sfxp = soundEngine->GetWritableSfx(refid); + if (!sfxp) return NO_SOUND; - int sndnum = PlayerSounds[listidx].LookupSound (S_sfx[refid].link); + FSoundID sndnum = PlayerSounds[listidx].LookupSound (sfxp->link); + sfxp = soundEngine->GetWritableSfx(sndnum); // If we're not done parsing SNDINFO yet, assume that the target sound is valid if (PlayerClassesIsSorted && - (sndnum == 0 || - ((S_sfx[sndnum].lumpnum == -1 || S_sfx[sndnum].lumpnum == sfx_empty) && - S_sfx[sndnum].link == sfxinfo_t::NO_LINK && - !S_sfx[sndnum].bPlayerSilent))) + (!sfxp || sndnum == NO_SOUND || + ((sfxp->lumpnum == -1 || sfxp->lumpnum == sfx_empty) && + sfxp->link == sfxinfo_t::NO_LINK && + !(sfxp->UserData[0] & SND_PlayerSilent)))) { // This sound is unavailable. if (ingender != 0) { // Try "male" @@ -1586,7 +1397,7 @@ static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid) // //========================================================================== -static void S_SavePlayerSound (const char *pclass, int gender, int refid, int lumpnum, bool alias) +static void S_SavePlayerSound (const char *pclass, int gender, FSoundID refid, int lumpnum, bool alias) { FSavedPlayerSoundInfo spi; @@ -1605,11 +1416,11 @@ static void S_RestorePlayerSounds() FSavedPlayerSoundInfo * spi = &SavedPlayerSounds[i]; if (spi->alias) { - S_AddPlayerSoundExisting(spi->pclass, spi->gender, spi->refid, spi->lumpnum); + S_AddPlayerSoundExisting(spi->pclass.GetChars(), spi->gender, spi->refid, FSoundID::fromInt(spi->lumpnum)); } else { - S_AddPlayerSound(spi->pclass, spi->gender, spi->refid, spi->lumpnum); + S_AddPlayerSound(spi->pclass.GetChars(), spi->gender, spi->refid, spi->lumpnum); } } } @@ -1621,28 +1432,22 @@ static void S_RestorePlayerSounds() // Returns true if two sounds are essentially the same thing //========================================================================== -bool S_AreSoundsEquivalent (AActor *actor, const char *name1, const char *name2) -{ - return S_AreSoundsEquivalent (actor, S_FindSound (name1), S_FindSound (name2)); -} - -bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2) +bool S_AreSoundsEquivalent (AActor *actor, FSoundID id1, FSoundID id2) { sfxinfo_t *sfx; - auto &S_sfx = soundEngine->GetSounds(); if (id1 == id2) { return true; } - if (id1 == 0 || id2 == 0) + if (!id1.isvalid() || !id2.isvalid()) { return false; } // Dereference aliases, but not random or player sounds - while ((sfx = &S_sfx[id1])->link != sfxinfo_t::NO_LINK) + while (sfx = soundEngine->GetWritableSfx(id1), sfx->link != sfxinfo_t::NO_LINK) { - if (sfx->bPlayerReserve) + if (sfx->UserData[0] & SND_PlayerReserve) { id1 = S_FindSkinnedSound (actor, id1); } @@ -1655,9 +1460,9 @@ bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2) id1 = sfx->link; } } - while ((sfx = &S_sfx[id2])->link != sfxinfo_t::NO_LINK) + while (sfx = soundEngine->GetWritableSfx(id2), sfx->link != sfxinfo_t::NO_LINK) { - if (sfx->bPlayerReserve) + if (sfx->UserData[0] & SND_PlayerReserve) { id2 = S_FindSkinnedSound (actor, id2); } @@ -1679,19 +1484,20 @@ bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2) // //=========================================================================== -static const char *GetSoundClass(AActor *pp) +const char *S_GetSoundClass(AActor *pp) { auto player = pp->player; + const char *defaultsoundclass = pp->NameVar(NAME_SoundClass) == NAME_None ? "player" : pp->NameVar(NAME_SoundClass).GetChars(); if (player != nullptr && (player->mo == nullptr || !(player->mo->flags4 &MF4_NOSKIN)) && (unsigned int)player->userinfo.GetSkin() >= PlayerClasses.Size() && - (unsigned)player->userinfo.GetSkin() < Skins.Size()) + (unsigned)player->userinfo.GetSkin() < Skins.Size() && + player->SoundClass.IsEmpty()) { return Skins[player->userinfo.GetSkin()].Name.GetChars(); } - auto sclass = player? pp->NameVar(NAME_SoundClass) : NAME_None; - - return sclass != NAME_None ? sclass.GetChars() : "player"; + + return (!player || player->SoundClass.IsEmpty()) ? defaultsoundclass : player->SoundClass.GetChars(); } //========================================================================== @@ -1701,15 +1507,15 @@ static const char *GetSoundClass(AActor *pp) // Calls S_LookupPlayerSound, deducing the class and gender from actor. //========================================================================== -int S_FindSkinnedSound (AActor *actor, FSoundID refid) +FSoundID S_FindSkinnedSound (AActor *actor, FSoundID refid) { const char *pclass; int gender = 0; - if (actor != nullptr) + if (actor != nullptr && actor->player != nullptr) { - pclass = GetSoundClass (actor); - if (actor->player != nullptr) gender = actor->player->userinfo.GetGender(); + pclass = S_GetSoundClass(actor); + gender = actor->player->userinfo.GetGender(); } else { @@ -1726,7 +1532,7 @@ int S_FindSkinnedSound (AActor *actor, FSoundID refid) // Tries looking for both "name-extendedname" and "name" in that order. //========================================================================== -int S_FindSkinnedSoundEx (AActor *actor, const char *name, const char *extendedname) +FSoundID S_FindSkinnedSoundEx (AActor *actor, const char *name, const char *extendedname) { FString fullname; @@ -1734,28 +1540,15 @@ int S_FindSkinnedSoundEx (AActor *actor, const char *name, const char *extendedn fullname = name; fullname += '-'; fullname += extendedname; - FSoundID id = fullname; + FSoundID id = S_FindSound(fullname); - if (id == 0) + if (!id.isvalid()) { // Look for "name" - id = name; + id = S_FindSound(name); } return S_FindSkinnedSound (actor, id); } -//========================================================================== -// -// sfxinfo_t :: MarkUsed -// -// Marks this sound for precaching. -// -//========================================================================== - -void sfxinfo_t::MarkUsed() -{ - bUsed = true; -} - //========================================================================== // // S_MarkPlayerSounds @@ -1766,7 +1559,7 @@ void sfxinfo_t::MarkUsed() void S_MarkPlayerSounds (AActor *player) { - const char *playerclass = GetSoundClass(player); + const char *playerclass = S_GetSoundClass(player); int classidx = S_FindPlayerClass(playerclass); if (classidx < 0) { @@ -1780,6 +1573,7 @@ void S_MarkPlayerSounds (AActor *player) PlayerSounds[listidx].MarkUsed(); } } + } //========================================================================== @@ -1790,18 +1584,17 @@ void S_MarkPlayerSounds (AActor *player) CCMD (soundlinks) { - auto &S_sfx = soundEngine->GetSounds(); unsigned int i; - for (i = 0; i < S_sfx.Size (); i++) + for (i = 0; i < soundEngine->GetNumSounds(); i++) { - const sfxinfo_t *sfx = &S_sfx[i]; + const sfxinfo_t* sfx = soundEngine->GetSfx(FSoundID::fromInt(i)); if (sfx->link != sfxinfo_t::NO_LINK && !sfx->bRandomHeader && - !sfx->bPlayerReserve) + !(sfx->UserData[0] & SND_PlayerReserve)) { - Printf ("%s -> %s\n", sfx->name.GetChars(), S_sfx[sfx->link].name.GetChars()); + Printf ("%s -> %s\n", sfx->name.GetChars(), soundEngine->GetSfx(sfx->link)->name.GetChars()); } } } @@ -1814,19 +1607,19 @@ CCMD (soundlinks) CCMD (playersounds) { - auto &S_sfx = soundEngine->GetSounds(); const char *reserveNames[256]; unsigned int i; int j, k, l; // Find names for the player sounds memset (reserveNames, 0, sizeof(reserveNames)); - for (i = j = 0; j < NumPlayerReserves && i < S_sfx.Size(); ++i) + for (i = j = 0; j < NumPlayerReserves && i < soundEngine->GetNumSounds(); ++i) { - if (S_sfx[i].bPlayerReserve) + auto sfx = soundEngine->GetSfx(FSoundID::fromInt(i)); + if (sfx->UserData[0] & SND_PlayerReserve) { ++j; - reserveNames[S_sfx[i].link] = S_sfx[i].name; + reserveNames[sfx->link.index()] = sfx->name.GetChars(); } } @@ -1839,7 +1632,9 @@ CCMD (playersounds) Printf ("\n%s, %s:\n", PlayerClassLookups[i].Name.GetChars(), GenderNames[j]); for (k = 0; k < NumPlayerReserves; ++k) { - Printf (" %-16s%s\n", reserveNames[k], S_sfx[PlayerSounds[l].LookupSound (k)].name.GetChars()); + auto sndid = PlayerSounds[l].LookupSound(FSoundID::fromInt(k)); + auto sfx = soundEngine->GetSfx(sndid); + Printf (" %-16s%s\n", reserveNames[k], sfx->name.GetChars()); } } } @@ -1922,7 +1717,7 @@ DEFINE_ACTION_FUNCTION(AAmbientSound, Tick) loop = CHANF_LOOP; } - if (ambient->sound != FSoundID(0)) + if (ambient->sound != NO_SOUND) { // The second argument scales the ambient sound's volume. // 0 and 100 are normal volume. The maximum volume level @@ -1991,7 +1786,7 @@ DEFINE_ACTION_FUNCTION(AAmbientSound, Activate) { if ((amb->type & 3) == 0 && amb->periodmin == 0) { - if (amb->sound == 0) + if (!amb->sound.isvalid()) { self->Destroy (); return 0; @@ -2047,7 +1842,7 @@ void S_ParseMusInfo() { int lastlump = 0, lump; - while ((lump = Wads.FindLump ("MUSINFO", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("MUSINFO", &lastlump)) != -1) { FScanner sc(lump); diff --git a/src/sound/s_doomsound.cpp b/src/sound/s_doomsound.cpp index 48f094f81d7..33604ce61fd 100644 --- a/src/sound/s_doomsound.cpp +++ b/src/sound/s_doomsound.cpp @@ -49,7 +49,7 @@ #include "s_playlist.h" #include "c_dispatch.h" #include "m_random.h" -#include "w_wad.h" +#include "filesystem.h" #include "p_local.h" #include "doomstat.h" #include "cmdlib.h" @@ -59,24 +59,18 @@ #include "gstrings.h" #include "gi.h" #include "po_man.h" -#include "serializer.h" +#include "serializer_doom.h" #include "d_player.h" #include "g_levellocals.h" #include "vm.h" #include "g_game.h" #include "s_music.h" +#include "v_draw.h" +#include "m_argv.h" // PUBLIC DATA DEFINITIONS ------------------------------------------------- -FBoolCVar noisedebug("noise", false, 0); // [RH] Print sound debugging info? -CUSTOM_CVAR(Int, snd_channels, 128, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // number of channels available -{ - if (self < 64) self = 64; -} -CVAR(Bool, snd_waterreverb, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - - static FString LastLocalSndInfo; static FString LastLocalSndSeq; void S_AddLocalSndInfo(int lump); @@ -88,8 +82,23 @@ class DoomSoundEngine : public SoundEngine void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID soundid, FVector3* pos, FVector3* vel, FSoundChan *) override; bool ValidatePosVel(int sourcetype, const void* source, const FVector3& pos, const FVector3& vel); TArray ReadSound(int lumpnum); - int PickReplacement(int refid); + FSoundID PickReplacement(FSoundID refid); FSoundID ResolveSound(const void *ent, int type, FSoundID soundid, float &attenuation) override; + void CacheSound(sfxinfo_t* sfx) override; + void StopChannel(FSoundChan* chan) override; + FSoundID AddSoundLump(const char* logicalname, int lump, int CurrentPitchMask, int resid = -1, int nearlimit = 2) override + { + auto ndx = SoundEngine::AddSoundLump(logicalname, lump, CurrentPitchMask, resid, nearlimit); + S_sfx[ndx.index()].UserData.Resize(1); + S_sfx[ndx.index()].UserData[0] = 0; + return ndx; + } + bool CheckSoundLimit(sfxinfo_t* sfx, const FVector3& pos, int near_limit, float limit_range, int sourcetype, const void* actor, int channel, float attenuation) override + { + if (sourcetype != SOURCE_Actor) actor = nullptr; //ZDoom did this. + return SoundEngine::CheckSoundLimit(sfx, pos, near_limit, limit_range, sourcetype, actor, channel, attenuation); + } + public: DoomSoundEngine() = default; @@ -97,6 +106,90 @@ class DoomSoundEngine : public SoundEngine void PrintSoundList(); }; + +//========================================================================== +// +// LookupMusic +// +// resolves aliases and special names +// +//========================================================================== + +static FString LookupMusic(const char* musicname, int& order) +{ + // allow specifying "*" as a placeholder to play the level's default music. + if (musicname != nullptr && !strcmp(musicname, "*")) + { + if (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL) + { + musicname = primaryLevel->Music.GetChars(); + order = primaryLevel->musicorder; + } + else + { + musicname = nullptr; + } + } + + if (musicname == nullptr || musicname[0] == 0) + { + // got nothing, return nothing. + return ""; + } + + if (strnicmp(musicname, ",CD,", 4) == 0) + { + static bool warned = false; + if (!warned) + Printf(TEXTCOLOR_RED "CD Audio no longer supported\n"); + warned = true; + return ""; + } + + if (*musicname == '/') musicname++; + + FString DEH_Music; + if (musicname[0] == '$') + { + // handle dehacked replacement. + // Any music name defined this way needs to be prefixed with 'D_' because + // Doom.exe does not contain the prefix so these strings don't either. + const char* mus_string = GStrings.CheckString(musicname + 1); + if (mus_string != nullptr) + { + DEH_Music << "D_" << mus_string; + musicname = DEH_Music.GetChars(); + } + } + + FName* aliasp = MusicAliases.CheckKey(musicname); + if (aliasp != nullptr) + { + if (*aliasp == NAME_None) + { + order = -1; + return ""; // flagged to be ignored + } + musicname = aliasp->GetChars(); + } + return musicname; +} + +//========================================================================== +// +// FindMusic +// +// loops up a music resource according to the engine's rules +// +//========================================================================== + +static int FindMusic(const char* musicname) +{ + int lumpnum = fileSystem.CheckNumForFullName(musicname); + if (lumpnum == -1) lumpnum = fileSystem.CheckNumForName(musicname, FileSys::ns_music); + return lumpnum; +} + //========================================================================== // // S_Init @@ -107,6 +200,10 @@ class DoomSoundEngine : public SoundEngine void S_Init() { + // Hook up the music player with the engine specific customizations. + static MusicCallbacks cb = { LookupMusic, FindMusic }; + S_SetMusicCallbacks(&cb); + // Must be up before I_InitSound. if (!soundEngine) { @@ -114,13 +211,15 @@ void S_Init() } I_InitSound(); + I_InitMusic(Args->CheckParm("-nomusic") || Args->CheckParm("-nosound")); // Heretic and Hexen have sound curve lookup tables. Doom does not. - int curvelump = Wads.CheckNumForName("SNDCURVE"); + int curvelump = fileSystem.CheckNumForName("SNDCURVE"); TArray curve; if (curvelump >= 0) { - curve = Wads.ReadLumpIntoArray(curvelump); + curve.Resize(fileSystem.FileLength(curvelump)); + fileSystem.ReadFile(curvelump, curve.Data()); } soundEngine->Init(curve); } @@ -196,7 +295,7 @@ void S_Start() if (LocalSndInfo.IsNotEmpty()) { // Now parse the local SNDINFO - int j = Wads.CheckNumForFullName(LocalSndInfo, true); + int j = fileSystem.CheckNumForFullName(LocalSndInfo.GetChars(), true); if (j >= 0) S_AddLocalSndInfo(j); } @@ -210,7 +309,7 @@ void S_Start() if (parse_ss) { - S_ParseSndSeq(LocalSndSeq.IsNotEmpty() ? Wads.CheckNumForFullName(LocalSndSeq, true) : -1); + S_ParseSndSeq(LocalSndSeq.IsNotEmpty() ? fileSystem.CheckNumForFullName(LocalSndSeq.GetChars(), true) : -1); } LastLocalSndInfo = LocalSndInfo; @@ -316,6 +415,17 @@ DEFINE_ACTION_FUNCTION(DObject, S_StartSound) } +//========================================================================== +// +// +// +//========================================================================== + +void DoomSoundEngine::CacheSound(sfxinfo_t* sfx) +{ + if (!(sfx->UserData[0] & SND_PlayerReserve)) SoundEngine::CacheSound(sfx); +} + //========================================================================== // // @@ -324,7 +434,8 @@ DEFINE_ACTION_FUNCTION(DObject, S_StartSound) FSoundID DoomSoundEngine::ResolveSound(const void * ent, int type, FSoundID soundid, float &attenuation) { - if (isPlayerReserve(soundid)) + auto sfx = &S_sfx[soundid.index()]; + if (sfx->UserData[0] & SND_PlayerReserve) { AActor *src; if (type != SOURCE_Actor) src = nullptr; @@ -342,7 +453,8 @@ FSoundID DoomSoundEngine::ResolveSound(const void * ent, int type, FSoundID soun static bool VerifyActorSound(AActor* ent, FSoundID& sound_id, int& channel, EChanFlags flags) { - if (ent == nullptr || ent->Sector->Flags & SECF_SILENT || ent->Level != primaryLevel) + if (ent == nullptr || ent->ObjectFlags & OF_EuthanizeMe || ent->Sector->Flags & SECF_SILENT || + ent->Level != primaryLevel) return false; if ((flags & CHANF_MAYBE_LOCAL) && (compatflags & COMPATF_SILENTPICKUP)) @@ -360,6 +472,21 @@ static bool VerifyActorSound(AActor* ent, FSoundID& sound_id, int& channel, ECha return true; } +//========================================================================== +// +// Common checking code for the actor sound functions +// +//========================================================================== + +void DoomSoundEngine::StopChannel(FSoundChan* chan) +{ + if (chan && chan->SysChannel != NULL && !(chan->ChanFlags & CHANF_EVICTED) && chan->SourceType == SOURCE_Actor) + { + chan->Source = NULL; + } + SoundEngine::StopChannel(chan); +} + //========================================================================== // @@ -476,7 +603,7 @@ void S_PlaySound(AActor *a, int chan, EChanFlags flags, FSoundID sid, float vol, void A_StartSound(AActor *self, int soundid, int channel, int flags, double volume, double attenuation, double pitch, double startTime) { - S_PlaySoundPitch(self, channel, EChanFlags::FromInt(flags), soundid, (float)volume, (float)attenuation, (float)pitch, (float)startTime); + S_PlaySoundPitch(self, channel, EChanFlags::FromInt(flags), FSoundID::fromInt(soundid), (float)volume, (float)attenuation, (float)pitch, (float)startTime); } void A_PlaySound(AActor* self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch) @@ -583,17 +710,17 @@ void S_ChangeActorSoundPitch(AActor *actor, int channel, double pitch) // Is a sound being played by a specific emitter? //========================================================================== -bool S_GetSoundPlayingInfo (const AActor *actor, int sound_id) +bool S_GetSoundPlayingInfo (const AActor *actor, FSoundID sound_id) { return soundEngine->GetSoundPlayingInfo(SOURCE_Actor, actor, sound_id); } -bool S_GetSoundPlayingInfo (const sector_t *sec, int sound_id) +bool S_GetSoundPlayingInfo (const sector_t *sec, FSoundID sound_id) { return soundEngine->GetSoundPlayingInfo(SOURCE_Sector, sec, sound_id); } -bool S_GetSoundPlayingInfo (const FPolyObj *poly, int sound_id) +bool S_GetSoundPlayingInfo (const FPolyObj *poly, FSoundID sound_id) { return soundEngine->GetSoundPlayingInfo(SOURCE_Polyobj, poly, sound_id); } @@ -604,7 +731,7 @@ bool S_GetSoundPlayingInfo (const FPolyObj *poly, int sound_id) // //========================================================================== -int S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id) +bool S_IsActorPlayingSomething (AActor *actor, int channel, FSoundID sound_id) { if (compatflags & COMPATF_MAGICSILENCE) { @@ -697,6 +824,8 @@ static FSerializer &Serialize(FSerializer &arc, const char *key, FSoundChan &cha ("rolloffmax", chan.Rolloff.MaxDistance) ("limitrange", chan.LimitRange); + if (SaveVersion < 4560) chan.Pitch /= 128.f; + switch (chan.SourceType) { case SOURCE_None: break; @@ -773,51 +902,6 @@ void S_SerializeSounds(FSerializer &arc) GSnd->UpdateSounds(); } -//========================================================================== -// -// S_SetSoundPaused -// -// Called with state non-zero when the app is active, zero when it isn't. -// -//========================================================================== - -void S_SetSoundPaused(int state) -{ - if (state) - { - if (paused == 0) - { - S_ResumeSound(true); - if (GSnd != nullptr) - { - GSnd->SetInactive(SoundRenderer::INACTIVE_Active); - } - } - } - else - { - if (paused == 0) - { - S_PauseSound(false, true); - if (GSnd != nullptr) - { - GSnd->SetInactive(gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL ? - SoundRenderer::INACTIVE_Complete : - SoundRenderer::INACTIVE_Mute); - } - } - } - if (!netgame -#ifdef _DEBUG - && !demoplayback -#endif - ) - { - pauseext = !state; - } -} - - //========================================================================== // // CalcSectorSoundOrg @@ -843,7 +927,7 @@ static void CalcSectorSoundOrg(const DVector3& listenpos, const sector_t* sec, i // Find the closest point on the sector's boundary lines and use // that as the perceived origin of the sound. DVector2 xy; - sec->ClosestPoint(listenpos, xy); + sec->ClosestPoint(listenpos.XY(), xy); pos.X = (float)xy.X; pos.Z = (float)xy.Y; } @@ -857,11 +941,11 @@ static void CalcSectorSoundOrg(const DVector3& listenpos, const sector_t* sec, i // Set sound vertical position based on channel. if (channum == CHAN_FLOOR) { - pos.Y = (float)MIN(sec->floorplane.ZatPoint(listenpos), listenpos.Z); + pos.Y = (float)min(sec->floorplane.ZatPoint(listenpos), listenpos.Z); } else if (channum == CHAN_CEILING) { - pos.Y = (float)MAX(sec->ceilingplane.ZatPoint(listenpos), listenpos.Z); + pos.Y = (float)max(sec->ceilingplane.ZatPoint(listenpos), listenpos.Z); } else if (channum == CHAN_INTERIOR) { @@ -886,7 +970,7 @@ static void CalcPolyobjSoundOrg(const DVector3& listenpos, const FPolyObj* poly, sector_t* sec; DVector2 ppos; - poly->ClosestPoint(listenpos, ppos, &side); + poly->ClosestPoint(listenpos.XY(), ppos, &side); pos.X = (float)ppos.X; pos.Z = (float)ppos.Y; sec = side->sector; @@ -1059,14 +1143,17 @@ bool DoomSoundEngine::ValidatePosVel(int sourcetype, const void* source, const F //========================================================================== // -// This is to avoid hardscoding the dependency on Wads into the sound engine +// This is to avoid hardscoding the dependency on the file system into the sound engine // //========================================================================== TArray DoomSoundEngine::ReadSound(int lumpnum) { - auto wlump = Wads.OpenLumpReader(lumpnum); - return wlump.Read(); + auto wlump = fileSystem.OpenFileReader(lumpnum); + TArray buffer(wlump.GetLength(), true); + auto len = wlump.Read(buffer.data(), buffer.size()); + buffer.Resize(len); + return buffer; } //========================================================================== @@ -1078,11 +1165,11 @@ TArray DoomSoundEngine::ReadSound(int lumpnum) //========================================================================== static FRandom pr_randsound("RandSound"); -int DoomSoundEngine::PickReplacement(int refid) +FSoundID DoomSoundEngine::PickReplacement(FSoundID refid) { - while (S_sfx[refid].bRandomHeader) + while (S_sfx[refid.index()].bRandomHeader) { - const FRandomSoundList* list = &S_rnd[S_sfx[refid].link]; + const FRandomSoundList* list = &S_rnd[S_sfx[refid.index()].link.index()]; refid = list->Choices[pr_randsound(list->Choices.Size())]; } return refid; @@ -1103,20 +1190,20 @@ void DoomSoundEngine::NoiseDebug() int y, color; y = 32 * CleanYfac; - screen->DrawText(NewConsoleFont, CR_YELLOW, 0, y, "*** SOUND DEBUG INFO ***", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_YELLOW, 0, y, "*** SOUND DEBUG INFO ***", TAG_DONE); y += NewConsoleFont->GetHeight(); - screen->DrawText(NewConsoleFont, CR_GOLD, 0, y, "name", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 70, y, "x", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 120, y, "y", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 170, y, "z", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 220, y, "vol", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 260, y, "dist", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 300, y, "chan", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 340, y, "pri", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 380, y, "flags", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 460, y, "aud", TAG_DONE); - screen->DrawText(NewConsoleFont, CR_GOLD, 520, y, "pos", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 0, y, "name", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 70, y, "x", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 120, y, "y", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 170, y, "z", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 220, y, "vol", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 260, y, "dist", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 300, y, "chan", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 340, y, "pri", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 380, y, "flags", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 460, y, "aud", TAG_DONE); + DrawText(twod, NewConsoleFont, CR_GOLD, 520, y, "pos", TAG_DONE); y += NewConsoleFont->GetHeight(); if (Channels == nullptr) @@ -1131,7 +1218,7 @@ void DoomSoundEngine::NoiseDebug() for (chan = Channels; chan->NextChan != nullptr; chan = chan->NextChan) { } - while (y < SCREENHEIGHT - 16) + while (y < twod->GetHeight() - 16) { char temp[32]; @@ -1139,54 +1226,53 @@ void DoomSoundEngine::NoiseDebug() color = (chan->ChanFlags & CHANF_LOOP) ? CR_BROWN : CR_GREY; // Name - Wads.GetLumpName(temp, S_sfx[chan->SoundID].lumpnum); - temp[8] = 0; - screen->DrawText(NewConsoleFont, color, 0, y, temp, TAG_DONE); + auto tname = fileSystem.GetFileShortName(S_sfx[chan->SoundID.index()].lumpnum); + DrawText(twod, NewConsoleFont, color, 0, y, tname, TAG_DONE); if (!(chan->ChanFlags & CHANF_IS3D)) { - screen->DrawText(NewConsoleFont, color, 70, y, "---", TAG_DONE); // X - screen->DrawText(NewConsoleFont, color, 120, y, "---", TAG_DONE); // Y - screen->DrawText(NewConsoleFont, color, 170, y, "---", TAG_DONE); // Z - screen->DrawText(NewConsoleFont, color, 260, y, "---", TAG_DONE); // Distance + DrawText(twod, NewConsoleFont, color, 70, y, "---", TAG_DONE); // X + DrawText(twod, NewConsoleFont, color, 120, y, "---", TAG_DONE); // Y + DrawText(twod, NewConsoleFont, color, 170, y, "---", TAG_DONE); // Z + DrawText(twod, NewConsoleFont, color, 260, y, "---", TAG_DONE); // Distance } else { // X coordinate mysnprintf(temp, countof(temp), "%.0f", origin.X); - screen->DrawText(NewConsoleFont, color, 70, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 70, y, temp, TAG_DONE); // Y coordinate mysnprintf(temp, countof(temp), "%.0f", origin.Z); - screen->DrawText(NewConsoleFont, color, 120, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 120, y, temp, TAG_DONE); // Z coordinate mysnprintf(temp, countof(temp), "%.0f", origin.Y); - screen->DrawText(NewConsoleFont, color, 170, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 170, y, temp, TAG_DONE); // Distance if (chan->DistanceScale > 0) { mysnprintf(temp, countof(temp), "%.0f", (origin - listener).Length()); - screen->DrawText(NewConsoleFont, color, 260, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 260, y, temp, TAG_DONE); } else { - screen->DrawText(NewConsoleFont, color, 260, y, "---", TAG_DONE); + DrawText(twod, NewConsoleFont, color, 260, y, "---", TAG_DONE); } } // Volume mysnprintf(temp, countof(temp), "%.2g", chan->Volume); - screen->DrawText(NewConsoleFont, color, 220, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 220, y, temp, TAG_DONE); // Channel mysnprintf(temp, countof(temp), "%d", chan->EntChannel); - screen->DrawText(NewConsoleFont, color, 300, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 300, y, temp, TAG_DONE); // Priority mysnprintf(temp, countof(temp), "%d", chan->Priority); - screen->DrawText(NewConsoleFont, color, 340, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 340, y, temp, TAG_DONE); // Flags mysnprintf(temp, countof(temp), "%s3%sZ%sU%sM%sN%sA%sL%sE%sV", @@ -1199,15 +1285,15 @@ void DoomSoundEngine::NoiseDebug() (chan->ChanFlags & CHANF_LOOP) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, (chan->ChanFlags & CHANF_EVICTED) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK, (chan->ChanFlags & CHANF_VIRTUAL) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK); - screen->DrawText(NewConsoleFont, color, 380, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 380, y, temp, TAG_DONE); // Audibility mysnprintf(temp, countof(temp), "%.4f", GSnd->GetAudibility(chan)); - screen->DrawText(NewConsoleFont, color, 460, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 460, y, temp, TAG_DONE); // Position mysnprintf(temp, countof(temp), "%u", GSnd->GetPosition(chan)); - screen->DrawText(NewConsoleFont, color, 520, y, temp, TAG_DONE); + DrawText(twod, NewConsoleFont, color, 520, y, temp, TAG_DONE); y += NewConsoleFont->GetHeight(); @@ -1219,9 +1305,10 @@ void DoomSoundEngine::NoiseDebug() } } -void S_NoiseDebug(void) +ADD_STAT(sounddebug) { static_cast(soundEngine)->NoiseDebug(); + return ""; } @@ -1233,36 +1320,32 @@ void S_NoiseDebug(void) void DoomSoundEngine::PrintSoundList() { - auto &S_sfx = soundEngine->GetSounds(); - char lumpname[9]; unsigned int i; - lumpname[8] = 0; - for (i = 0; i < S_sfx.Size(); i++) + for (i = 0; i < soundEngine->GetNumSounds(); i++) { - const sfxinfo_t* sfx = &S_sfx[i]; + const sfxinfo_t* sfx = soundEngine->GetSfx(FSoundID::fromInt(i)); if (sfx->bRandomHeader) { - Printf("%3d. %s -> #%d {", i, sfx->name.GetChars(), sfx->link); - const FRandomSoundList* list = &S_rnd[sfx->link]; + Printf("%3d. %s -> #%d {", i, sfx->name.GetChars(), sfx->link.index()); + const FRandomSoundList* list = &S_rnd[sfx->link.index()]; for (auto& me : list->Choices) { - Printf(" %s ", S_sfx[me].name.GetChars()); + Printf(" %s ", S_sfx[me.index()].name.GetChars()); } Printf("}\n"); } - else if (sfx->bPlayerReserve) + else if (sfx->UserData[0] & SND_PlayerReserve) { - Printf("%3d. %s <>\n", i, sfx->name.GetChars(), sfx->link); + Printf("%3d. %s <>\n", i, sfx->name.GetChars(), sfx->link.index()); } else if (S_sfx[i].lumpnum != -1) { - Wads.GetLumpName(lumpname, sfx->lumpnum); - Printf("%3d. %s (%s)\n", i, sfx->name.GetChars(), lumpname); + Printf("%3d. %s (%s)\n", i, sfx->name.GetChars(), fileSystem.GetFileShortName(sfx->lumpnum)); } else if (S_sfx[i].link != sfxinfo_t::NO_LINK) { - Printf("%3d. %s -> %s\n", i, sfx->name.GetChars(), S_sfx[sfx->link].name.GetChars()); + Printf("%3d. %s -> %s\n", i, sfx->name.GetChars(), S_sfx[sfx->link.index()].name.GetChars()); } else { @@ -1287,8 +1370,8 @@ CCMD (playsound) { if (argv.argc() > 1) { - FSoundID id = argv[1]; - if (id == 0) + FSoundID id = S_FindSound(argv[1]); + if (!id.isvalid()) { Printf("'%s' is not a sound\n", argv[1]); } @@ -1309,8 +1392,8 @@ CCMD (loopsound) { if (players[consoleplayer].mo != nullptr && !netgame && argv.argc() > 1) { - FSoundID id = argv[1]; - if (id == 0) + FSoundID id = S_FindSound(argv[1]); + if (!id.isvalid()) { Printf("'%s' is not a sound\n", argv[1]); } @@ -1325,117 +1408,8 @@ CCMD (loopsound) } } -//========================================================================== -// -// CCMD cachesound -// -//========================================================================== - -CCMD (cachesound) -{ - if (argv.argc() < 2) - { - Printf ("Usage: cachesound ...\n"); - return; - } - for (int i = 1; i < argv.argc(); ++i) - { - FSoundID sfxnum = argv[i]; - if (sfxnum != FSoundID(0)) - { - soundEngine->CacheSound(sfxnum); - } - } -} - - -CCMD(listsoundchannels) -{ - Printf("%s", soundEngine->ListSoundChannels().GetChars()); -} - -// intentionally moved here to keep the s_music include out of the rest of the file. - -//========================================================================== -// -// S_PauseSound -// -// Stop music and sound effects, during game PAUSE. -//========================================================================== -#include "s_music.h" - -void S_PauseSound (bool notmusic, bool notsfx) -{ - if (!notmusic) - { - S_PauseMusic(); - } - if (!notsfx) - { - soundEngine->SetPaused(true); - GSnd->SetSfxPaused (true, 0); - } -} - -DEFINE_ACTION_FUNCTION(DObject, S_PauseSound) -{ - PARAM_PROLOGUE; - PARAM_BOOL(notmusic); - PARAM_BOOL(notsfx); - S_PauseSound(notmusic, notsfx); - return 0; -} - -//========================================================================== -// -// S_ResumeSound -// -// Resume music and sound effects, after game PAUSE. -//========================================================================== - -void S_ResumeSound (bool notsfx) -{ - S_ResumeMusic(); - if (!notsfx) - { - soundEngine->SetPaused(false); - GSnd->SetSfxPaused (false, 0); - } -} - -DEFINE_ACTION_FUNCTION(DObject, S_ResumeSound) -{ - PARAM_PROLOGUE; - PARAM_BOOL(notsfx); - S_ResumeSound(notsfx); - return 0; -} - - - -CCMD (snd_status) -{ - GSnd->PrintStatus (); -} - -CCMD (snd_reset) +CCMD(snd_reset) { S_SoundReset(); } -void S_SoundReset() -{ - S_StopMusic(true); - soundEngine->Reset(); - S_RestartMusic(); -} - -CCMD (snd_listdrivers) -{ - GSnd->PrintDriversList (); -} - -ADD_STAT (sound) -{ - return GSnd->GatherStats (); -} diff --git a/src/sound/s_doomsound.h b/src/sound/s_doomsound.h index 2ea833dc003..3dab94ace88 100644 --- a/src/sound/s_doomsound.h +++ b/src/sound/s_doomsound.h @@ -11,16 +11,27 @@ void S_Start(); void S_Shutdown(); void S_UpdateSounds(AActor* listenactor); -void S_SetSoundPaused(int state); void S_PrecacheLevel(FLevelLocals* l); // Start sound for thing at void S_Sound(int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation); +inline void S_Sound(int channel, EChanFlags flags, const char* sfxid, float volume, float attenuation) +{ + S_Sound(channel, flags, S_FindSound(sfxid), volume, attenuation); +} +inline void S_Sound(int channel, EChanFlags flags, const FString& sfxid, float volume, float attenuation) +{ + S_Sound(channel, flags, S_FindSound(sfxid), volume, attenuation); +} void S_SoundPitch(int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation, float pitch, float startTime = 0.f); void S_Sound (AActor *ent, int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation); +inline void S_Sound(AActor* ent, int channel, EChanFlags flags, const char* sfxid, float volume, float attenuation) +{ + S_Sound(ent, channel, flags, S_FindSound(sfxid), volume, attenuation); +} void S_SoundMinMaxDist (AActor *ent, int channel, EChanFlags flags, FSoundID sfxid, float volume, float mindist, float maxdist); void S_Sound (const FPolyObj *poly, int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation); void S_Sound (const sector_t *sec, int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation); @@ -41,11 +52,11 @@ void S_StopActorSounds(AActor *actor, int chanmin, int chanmax); void S_RelinkSound (AActor *from, AActor *to); // Is the sound playing on one of the emitter's channels? -bool S_GetSoundPlayingInfo (const AActor *actor, int sound_id); -bool S_GetSoundPlayingInfo (const sector_t *sector, int sound_id); -bool S_GetSoundPlayingInfo (const FPolyObj *poly, int sound_id); +bool S_GetSoundPlayingInfo (const AActor *actor, FSoundID sound_id = INVALID_SOUND); +bool S_GetSoundPlayingInfo (const sector_t *sector, FSoundID sound_id = INVALID_SOUND); +bool S_GetSoundPlayingInfo (const FPolyObj *poly, FSoundID sound_id = INVALID_SOUND); -int S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id); +bool S_IsActorPlayingSomething (AActor *actor, int channel, FSoundID sound_id = INVALID_SOUND); // Change a playing sound's volume void S_ChangeActorSoundVolume(AActor *actor, int channel, double volume); @@ -56,6 +67,7 @@ void S_ChangeActorSoundPitch(AActor *actor, int channel, double pitch); // Stores/retrieves playing channel information in an archive. void S_SerializeSounds(FSerializer &arc); +// these must retain their integer sound IDs because they are direct native functions for ZScript. void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch); void A_StartSound(AActor* self, int soundid, int channel, int flags, double volume, double attenuation, double pitch, double startTime = 0.); static void S_SetListener(AActor *listenactor); @@ -79,12 +91,3 @@ inline const char* S_GetSoundName(FSoundID id) return soundEngine->GetSoundName(id); } -inline int S_FindSound(const char* logicalname) -{ - return soundEngine->FindSound(logicalname); -} - -inline int S_FindSoundByResID(int rid) -{ - return soundEngine->FindSoundByResID(rid); -} diff --git a/src/sound/s_music.cpp b/src/sound/s_music.cpp deleted file mode 100644 index 7c023e15121..00000000000 --- a/src/sound/s_music.cpp +++ /dev/null @@ -1,847 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// Copyright 2002-2016 Christoph Oelckers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// DESCRIPTION: none -// -//----------------------------------------------------------------------------- - -/* For code that originates from ZDoom the following applies: -** -**--------------------------------------------------------------------------- -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#ifdef _WIN32 -#include -#endif - -#include "i_system.h" -#include "i_sound.h" -#include "i_music.h" - -#include "s_sound.h" -#include "s_sndseq.h" -#include "s_playlist.h" -#include "c_dispatch.h" -#include "m_random.h" -#include "w_wad.h" -#include "p_local.h" -#include "doomstat.h" -#include "cmdlib.h" -#include "v_video.h" -#include "v_text.h" -#include "a_sharedglobal.h" -#include "gstrings.h" -#include "gi.h" -#include "po_man.h" -#include "serializer.h" -#include "d_player.h" -#include "g_levellocals.h" -#include "vm.h" -#include "g_game.h" -#include "s_music.h" -#include "filereadermusicinterface.h" -#include - -// MACROS ------------------------------------------------------------------ - - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -extern float S_GetMusicVolume (const char *music); - -static void S_ActivatePlayList(bool goBack); - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static bool MusicPaused; // whether music is paused -MusPlayingInfo mus_playing; // music currently being played -static FPlayList PlayList; -float relative_volume = 1.f; -float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function - -DEFINE_GLOBAL_NAMED(mus_playing, musplaying); -DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, name); -DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, baseorder); -DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, loop); - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// -// -// Create a sound system stream for the currently playing song -//========================================================================== - -static std::unique_ptr musicStream; - -static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata) -{ - bool written = ZMusic_FillStream(mus_playing.handle, buff, len); - - if (!written) - { - memset((char*)buff, 0, len); - return false; - } - return true; -} - - -void S_CreateStream() -{ - if (!mus_playing.handle) return; - SoundStreamInfo fmt; - ZMusic_GetStreamInfo(mus_playing.handle, &fmt); - if (fmt.mBufferSize > 0) // if buffer size is 0 the library will play the song itself (e.g. Windows system synth.) - { - int flags = fmt.mNumChannels < 0 ? 0 : SoundStream::Float; - if (abs(fmt.mNumChannels) < 2) flags |= SoundStream::Mono; - - musicStream.reset(GSnd->CreateStream(FillStream, fmt.mBufferSize, flags, fmt.mSampleRate, nullptr)); - if (musicStream) musicStream->Play(true, 1); - } -} - -void S_PauseStream(bool paused) -{ - if (musicStream) musicStream->SetPaused(paused); -} - -void S_StopStream() -{ - if (musicStream) - { - musicStream->Stop(); - musicStream.reset(); - } -} - - -//========================================================================== -// -// starts playing this song -// -//========================================================================== - -static bool S_StartMusicPlaying(ZMusic_MusicStream song, bool loop, float rel_vol, int subsong) -{ - if (rel_vol > 0.f) - { - float factor = relative_volume / saved_relative_volume; - saved_relative_volume = rel_vol; - I_SetRelativeVolume(saved_relative_volume * factor); - } - ZMusic_Stop(song); - if (!ZMusic_Start(song, subsong, loop)) - { - return false; - } - - // Notify the sound system of the changed relative volume - snd_musicvolume.Callback(); - return true; -} - - -//========================================================================== -// -// S_PauseSound -// -// Stop music and sound effects, during game PAUSE. -//========================================================================== - -void S_PauseMusic () -{ - if (mus_playing.handle && !MusicPaused) - { - ZMusic_Pause(mus_playing.handle); - S_PauseStream(true); - MusicPaused = true; - } -} - -//========================================================================== -// -// S_ResumeSound -// -// Resume music and sound effects, after game PAUSE. -//========================================================================== - -void S_ResumeMusic () -{ - if (mus_playing.handle && MusicPaused) - { - ZMusic_Resume(mus_playing.handle); - S_PauseStream(false); - MusicPaused = false; - } -} - -//========================================================================== -// -// S_UpdateSound -// -//========================================================================== - -void S_UpdateMusic () -{ - if (mus_playing.handle != nullptr) - { - ZMusic_Update(mus_playing.handle); - - // [RH] Update music and/or playlist. IsPlaying() must be called - // to attempt to reconnect to broken net streams and to advance the - // playlist when the current song finishes. - if (!ZMusic_IsPlaying(mus_playing.handle)) - { - if (PlayList.GetNumSongs()) - { - PlayList.Advance(); - S_ActivatePlayList(false); - } - else - { - S_StopMusic(true); - } - } - } -} - -//========================================================================== -// -// S_Start -// -// Per level startup code. Kills playing sounds at start of level -// and starts new music. -//========================================================================== - -void S_StartMusic () -{ - // stop the old music if it has been paused. - // This ensures that the new music is started from the beginning - // if it's the same as the last one and it has been paused. - if (MusicPaused) S_StopMusic(true); - - // start new music for the level - MusicPaused = false; - - // Don't start the music if loading a savegame, because the music is stored there. - // Don't start the music if revisiting a level in a hub for the same reason. - if (!primaryLevel->IsReentering()) - { - primaryLevel->SetMusic(); - } -} - - -//========================================================================== -// -// S_ActivatePlayList -// -// Plays the next song in the playlist. If no songs in the playlist can be -// played, then it is deleted. -//========================================================================== - -void S_ActivatePlayList (bool goBack) -{ - int startpos, pos; - - startpos = pos = PlayList.GetPosition (); - S_StopMusic (true); - while (!S_ChangeMusic (PlayList.GetSong (pos), 0, false, true)) - { - pos = goBack ? PlayList.Backup () : PlayList.Advance (); - if (pos == startpos) - { - PlayList.Clear(); - Printf ("Cannot play anything in the playlist.\n"); - return; - } - } -} - -//========================================================================== -// -// S_StartMusic -// -// Starts some music with the given name. -//========================================================================== - -bool S_StartMusic (const char *m_id) -{ - return S_ChangeMusic (m_id, 0, false); -} - -//========================================================================== -// -// S_ChangeMusic -// -// Starts playing a music, possibly looping. -// -// [RH] If music is a MOD, starts it at position order. If name is of the -// format ",CD,,[cd id]" song is a CD track, and if [cd id] is -// specified, it will only be played if the specified CD is in a drive. -//========================================================================== - -bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) -{ - if (nomusic) return false; // skip the entire procedure if music is globally disabled. - if (!force && PlayList.GetNumSongs()) - { // Don't change if a playlist is active - return false; - } - - // allow specifying "*" as a placeholder to play the level's default music. - if (musicname != nullptr && !strcmp(musicname, "*")) - { - if (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL) - { - musicname = primaryLevel->Music; - order = primaryLevel->musicorder; - } - else - { - musicname = nullptr; - } - } - - if (musicname == nullptr || musicname[0] == 0) - { - // Don't choke if the map doesn't have a song attached - S_StopMusic (true); - mus_playing.name = ""; - mus_playing.LastSong = ""; - return true; - } - - FString DEH_Music; - if (musicname[0] == '$') - { - // handle dehacked replacement. - // Any music name defined this way needs to be prefixed with 'D_' because - // Doom.exe does not contain the prefix so these strings don't either. - const char * mus_string = GStrings[musicname+1]; - if (mus_string != nullptr) - { - DEH_Music << "D_" << mus_string; - musicname = DEH_Music; - } - } - - FName *aliasp = MusicAliases.CheckKey(musicname); - if (aliasp != nullptr) - { - if (*aliasp == NAME_None) - { - return true; // flagged to be ignored - } - musicname = aliasp->GetChars(); - } - - if (!mus_playing.name.IsEmpty() && - mus_playing.handle != nullptr && - stricmp (mus_playing.name, musicname) == 0 && - ZMusic_IsLooping(mus_playing.handle) == zmusic_bool(looping)) - { - if (order != mus_playing.baseorder) - { - if (ZMusic_SetSubsong(mus_playing.handle, order)) - { - mus_playing.baseorder = order; - } - } - else if (!ZMusic_IsPlaying(mus_playing.handle)) - { - if (!ZMusic_Start(mus_playing.handle, order, looping)) - { - Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); - } - S_CreateStream(); - - } - return true; - } - - if (strnicmp (musicname, ",CD,", 4) == 0) - { - static bool warned = false; - if (!warned) - Printf(TEXTCOLOR_RED "CD Audio no longer supported\n"); - warned = true; - return false; - } - else - { - int lumpnum = -1; - int length = 0; - ZMusic_MusicStream handle = nullptr; - MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname); - - // Strip off any leading file:// component. - if (strncmp(musicname, "file://", 7) == 0) - { - musicname += 7; - } - - FileReader reader; - if (!FileExists (musicname)) - { - if ((lumpnum = Wads.CheckNumForFullName (musicname, true, ns_music)) == -1) - { - Printf ("Music \"%s\" not found\n", musicname); - return false; - } - if (handle == nullptr) - { - if (Wads.LumpLength (lumpnum) == 0) - { - return false; - } - reader = Wads.ReopenLumpReader(lumpnum); - } - } - else - { - // Load an external file. - if (!reader.OpenFile(musicname)) - { - return false; - } - } - - // shutdown old music - S_StopMusic (true); - - // Just record it if volume is 0 - if (snd_musicvolume <= 0) - { - mus_playing.loop = looping; - mus_playing.name = musicname; - mus_playing.baseorder = order; - mus_playing.LastSong = musicname; - return true; - } - - // load & register it - if (handle != nullptr) - { - mus_playing.handle = handle; - } - else - { - auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper. - mus_playing.handle = ZMusic_OpenSong(mreader, devp? (EMidiDevice)devp->device : MDEV_DEFAULT, devp? devp->args.GetChars() : ""); - if (mus_playing.handle == nullptr) - { - Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); - } - } - } - - mus_playing.loop = looping; - mus_playing.name = musicname; - mus_playing.baseorder = 0; - mus_playing.LastSong = ""; - - if (mus_playing.handle != 0) - { // play it - if (!S_StartMusicPlaying(mus_playing.handle, looping, S_GetMusicVolume(musicname), order)) - { - Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); - return false; - } - S_CreateStream(); - mus_playing.baseorder = order; - return true; - } - return false; -} - -DEFINE_ACTION_FUNCTION(DObject, S_ChangeMusic) -{ - PARAM_PROLOGUE; - PARAM_STRING(music); - PARAM_INT(order); - PARAM_BOOL(looping); - PARAM_BOOL(force); - ACTION_RETURN_BOOL(S_ChangeMusic(music, order, looping, force)); -} - - -//========================================================================== -// -// S_RestartMusic -// -// Must only be called from snd_reset in i_sound.cpp! -//========================================================================== - -void S_RestartMusic () -{ - if (!mus_playing.LastSong.IsEmpty()) - { - FString song = mus_playing.LastSong; - mus_playing.LastSong = ""; - S_ChangeMusic (song, mus_playing.baseorder, mus_playing.loop, true); - } -} - -//========================================================================== -// -// S_MIDIDeviceChanged -// -//========================================================================== - - -void S_MIDIDeviceChanged(int newdev) -{ - auto song = mus_playing.handle; - if (song != nullptr && ZMusic_IsMIDI(song) && ZMusic_IsPlaying(song)) - { - // Reload the song to change the device - auto mi = mus_playing; - S_StopMusic(true); - S_ChangeMusic(mi.name, mi.baseorder, mi.loop); - } -} - -//========================================================================== -// -// S_GetMusic -// -//========================================================================== - -int S_GetMusic (const char **name) -{ - int order; - - if (mus_playing.name.IsNotEmpty()) - { - *name = mus_playing.name; - order = mus_playing.baseorder; - } - else - { - *name = nullptr; - order = 0; - } - return order; -} - -//========================================================================== -// -// S_StopMusic -// -//========================================================================== - -void S_StopMusic (bool force) -{ - try - { - // [RH] Don't stop if a playlist is active. - if ((force || PlayList.GetNumSongs() == 0) && !mus_playing.name.IsEmpty()) - { - if (mus_playing.handle != nullptr) - { - S_ResumeMusic(); - S_StopStream(); - ZMusic_Stop(mus_playing.handle); - auto h = mus_playing.handle; - mus_playing.handle = nullptr; - ZMusic_Close(h); - } - mus_playing.LastSong = std::move(mus_playing.name); - } - } - catch (const std::runtime_error& ) - { - //Printf("Unable to stop %s: %s\n", mus_playing.name.GetChars(), err.what()); - if (mus_playing.handle != nullptr) - { - auto h = mus_playing.handle; - mus_playing.handle = nullptr; - ZMusic_Close(h); - } - mus_playing.name = ""; - } -} - -//========================================================================== -// -// CCMD idmus -// -//========================================================================== - -CCMD (idmus) -{ - level_info_t *info; - FString map; - int l; - - if (!nomusic) - { - if (argv.argc() > 1) - { - if (gameinfo.flags & GI_MAPxx) - { - l = atoi (argv[1]); - if (l <= 99) - { - map = CalcMapName (0, l); - } - else - { - Printf ("%s\n", GStrings("STSTR_NOMUS")); - return; - } - } - else - { - map = CalcMapName (argv[1][0] - '0', argv[1][1] - '0'); - } - - if ( (info = FindLevelInfo (map)) ) - { - if (info->Music.IsNotEmpty()) - { - S_ChangeMusic (info->Music, info->musicorder); - Printf ("%s\n", GStrings("STSTR_MUS")); - } - } - else - { - Printf ("%s\n", GStrings("STSTR_NOMUS")); - } - } - } - else - { - Printf("Music is disabled\n"); - } -} - -//========================================================================== -// -// CCMD changemus -// -//========================================================================== - -CCMD (changemus) -{ - if (!nomusic) - { - if (argv.argc() > 1) - { - PlayList.Clear(); - S_ChangeMusic (argv[1], argv.argc() > 2 ? atoi (argv[2]) : 0); - } - else - { - const char *currentmus = mus_playing.name.GetChars(); - if(currentmus != nullptr && *currentmus != 0) - { - Printf ("currently playing %s\n", currentmus); - } - else - { - Printf ("no music playing\n"); - } - } - } - else - { - Printf("Music is disabled\n"); - } -} - -//========================================================================== -// -// CCMD stopmus -// -//========================================================================== - -CCMD (stopmus) -{ - PlayList.Clear(); - S_StopMusic (false); - mus_playing.LastSong = ""; // forget the last played song so that it won't get restarted if some volume changes occur -} - -//========================================================================== -// -// CCMD playlist -// -//========================================================================== - -UNSAFE_CCMD (playlist) -{ - int argc = argv.argc(); - - if (argc < 2 || argc > 3) - { - Printf ("playlist [|shuffle]\n"); - } - else - { - if (PlayList.GetNumSongs() > 0) - { - PlayList.ChangeList (argv[1]); - } - else - { - PlayList.ChangeList(argv[1]); - } - if (PlayList.GetNumSongs () > 0) - { - if (argc == 3) - { - if (stricmp (argv[2], "shuffle") == 0) - { - PlayList.Shuffle (); - } - else - { - PlayList.SetPosition (atoi (argv[2])); - } - } - S_ActivatePlayList (false); - } - } -} - -//========================================================================== -// -// CCMD playlistpos -// -//========================================================================== - -static bool CheckForPlaylist () -{ - if (PlayList.GetNumSongs() == 0) - { - Printf ("No playlist is playing.\n"); - return false; - } - return true; -} - -CCMD (playlistpos) -{ - if (CheckForPlaylist() && argv.argc() > 1) - { - PlayList.SetPosition (atoi (argv[1]) - 1); - S_ActivatePlayList (false); - } -} - -//========================================================================== -// -// CCMD playlistnext -// -//========================================================================== - -CCMD (playlistnext) -{ - if (CheckForPlaylist()) - { - PlayList.Advance (); - S_ActivatePlayList (false); - } -} - -//========================================================================== -// -// CCMD playlistprev -// -//========================================================================== - -CCMD (playlistprev) -{ - if (CheckForPlaylist()) - { - PlayList.Backup (); - S_ActivatePlayList (true); - } -} - -//========================================================================== -// -// CCMD playliststatus -// -//========================================================================== - -CCMD (playliststatus) -{ - if (CheckForPlaylist ()) - { - Printf ("Song %d of %d:\n%s\n", - PlayList.GetPosition () + 1, - PlayList.GetNumSongs (), - PlayList.GetSong (PlayList.GetPosition ())); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -CCMD(currentmusic) -{ - if (mus_playing.name.IsNotEmpty()) - { - Printf("Currently playing music '%s'\n", mus_playing.name.GetChars()); - } - else - { - Printf("Currently no music playing\n"); - } -} diff --git a/src/sound/s_music.h b/src/sound/s_music.h deleted file mode 100644 index b1118822616..00000000000 --- a/src/sound/s_music.h +++ /dev/null @@ -1,93 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// Copyright 2002-2016 Christoph Oelckers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// The not so system specific sound interface. -// -//----------------------------------------------------------------------------- - - -#ifndef __S_MUSIC__ -#define __S_MUSIC__ - -#include -#include "doomtype.h" -#include "i_soundinternal.h" - - -void S_ParseMusInfo(); - - -// -void S_InitMusic (); -void S_StartMusic (); - - -// Start music using -bool S_StartMusic (const char *music_name); - -// Start music using , and set whether looping -bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false); - -void S_RestartMusic (); -void S_MIDIDeviceChanged(int newdev); - -int S_GetMusic (const char **name); - -// Stops the music for sure. -void S_StopMusic (bool force); - -// Stop and resume music, during game PAUSE. -void S_PauseMusic (); -void S_ResumeMusic (); - -// -// Updates music & sounds -// -void S_UpdateMusic (); - -struct MidiDeviceSetting -{ - int device; - FString args; -}; - -typedef TMap MusicAliasMap; -typedef TMap MidiDeviceMap; - -extern MusicAliasMap MusicAliases; -extern MidiDeviceMap MidiDevices; - -struct MusPlayingInfo -{ - FString name; - ZMusic_MusicStream handle; - int baseorder; - bool loop; - FString LastSong; // last music that was played -}; - -extern MusPlayingInfo mus_playing; - -extern float relative_volume, saved_relative_volume; - - -#endif diff --git a/src/sound/s_sndseq.cpp b/src/sound/s_sndseq.cpp index 4ed82903ab5..99b58a8f9b4 100644 --- a/src/sound/s_sndseq.cpp +++ b/src/sound/s_sndseq.cpp @@ -28,15 +28,17 @@ #include "m_random.h" #include "s_sound.h" #include "s_sndseq.h" -#include "w_wad.h" +#include "filesystem.h" #include "cmdlib.h" #include "p_local.h" #include "po_man.h" #include "gi.h" #include "c_dispatch.h" +#include "i_interface.h" #include "g_level.h" -#include "serializer.h" +#include "serializer_doom.h" +#include "serialize_obj.h" #include "d_player.h" #include "g_levellocals.h" #include "vm.h" @@ -47,10 +49,13 @@ #define GetData(a) (int32_t(a) >> 8 ) #define GetFloatData(a) float((int32_t(a) >> 8 )/65536.f) #define MakeCommand(a,b) ((a) | ((b) << 8)) -#define HexenPlatSeq(a) (a) -#define HexenDoorSeq(a) ((a) | 0x40) -#define HexenEnvSeq(a) ((a) | 0x80) -#define HexenLastSeq (0xff) +#define HexenPlatSeqStart (0) +#define HexenDoorSeqStart (MAX_SNDSEQS) +#define HexenEnvSeqStart (MAX_SNDSEQS << 1) +#define HexenPlatSeq(a) ((a) | (HexenPlatSeqStart)) +#define HexenDoorSeq(a) ((a) | (HexenDoorSeqStart)) +#define HexenEnvSeq(a) ((a) | (HexenEnvSeqStart)) +#define HexenLastSeq ((MAX_SNDSEQS << 2) - 1) // TYPES ------------------------------------------------------------------- @@ -105,7 +110,7 @@ typedef enum struct hexenseq_t { ENamedName Name; - uint8_t Seqs[4]; + uint16_t Seqs[4]; }; class DSeqActorNode : public DSeqNode @@ -150,7 +155,7 @@ class DSeqPolyNode : public DSeqNode } bool IsPlaying() { - return S_GetSoundPlayingInfo (m_Poly, m_CurrentSoundID); + return m_CurrentSoundID.isvalid() && S_GetSoundPlayingInfo (m_Poly, m_CurrentSoundID); } void *Source() { @@ -179,7 +184,7 @@ class DSeqSectorNode : public DSeqNode } bool IsPlaying() { - return S_GetSoundPlayingInfo (m_Sector, m_CurrentSoundID); + return m_CurrentSoundID.isvalid() && S_GetSoundPlayingInfo (m_Sector, m_CurrentSoundID); } void *Source() { @@ -281,7 +286,7 @@ static const hexenseq_t HexenSequences[] = { { NAME_None, {0} } }; -static int SeqTrans[64*3]; +static int SeqTrans[MAX_SNDSEQS*3]; static FRandom pr_sndseq ("SndSeq"); @@ -308,7 +313,7 @@ void DSeqNode::Serialize(FSerializer &arc) unsigned int i; FName seqName = NAME_None; int delayTics = 0; - FSoundID id = 0; + FSoundID id = NO_SOUND; float volume; float atten = ATTN_NORM; int seqnum; @@ -391,7 +396,7 @@ void DSeqNode::OnDestroy() m_ParentSeqNode->m_ChildSeqNode = nullptr; m_ParentSeqNode = nullptr; } - if (Level->SequenceListHead == this) + if (Level && Level->SequenceListHead == this) { Level->SequenceListHead = m_Next; GC::WriteBarrier(m_Next); @@ -429,7 +434,7 @@ void DSeqNode::AddChoice (int seqnum, seqtype_t type) DEFINE_ACTION_FUNCTION(DSeqNode, AddChoice) { PARAM_SELF_PROLOGUE(DSeqNode); - PARAM_NAME(seq); + PARAM_INT(seq); PARAM_INT(mode); self->AddChoice(seq, seqtype_t(mode)); return 0; @@ -490,7 +495,7 @@ static void AssignTranslations (FScanner &sc, int seq, seqtype_t type) { if (IsNum(sc.String)) { - SeqTrans[(atoi(sc.String) & 63) + type * 64] = seq; + SeqTrans[(atoi(sc.String) & (MAX_SNDSEQS - 1)) + type * MAX_SNDSEQS] = seq; } } sc.UnGet(); @@ -510,7 +515,7 @@ static void AssignHexenTranslations (void) { for (seq = 0; seq < Sequences.Size(); seq++) { - if (Sequences[seq] != NULL && HexenSequences[i].Name == Sequences[seq]->SeqName) + if (Sequences[seq] != NULL && Sequences[seq]->SeqName == HexenSequences[i].Name) break; } if (seq == Sequences.Size()) @@ -520,16 +525,16 @@ static void AssignHexenTranslations (void) { int trans; - if (HexenSequences[i].Seqs[j] & 0x40) + if (HexenSequences[i].Seqs[j] & HexenDoorSeqStart) { - trans = 64 * SEQ_DOOR; + trans = MAX_SNDSEQS * SEQ_DOOR; } - else if (HexenSequences[i].Seqs[j] & 0x80) - trans = 64 * SEQ_ENVIRONMENT; + else if (HexenSequences[i].Seqs[j] & HexenEnvSeqStart) + trans = MAX_SNDSEQS * SEQ_ENVIRONMENT; else - trans = 64 * SEQ_PLATFORM; + trans = MAX_SNDSEQS * SEQ_PLATFORM; - SeqTrans[trans + (HexenSequences[i].Seqs[j] & 0x3f)] = seq; + SeqTrans[trans + (HexenSequences[i].Seqs[j] & (MAX_SNDSEQS - 1))] = seq; } } } @@ -565,7 +570,7 @@ void S_ParseSndSeq (int levellump) char seqtype = ':'; FName seqname = NAME_None; FName slot = NAME_None; - int stopsound; + FSoundID stopsound; int delaybase; float volumebase; int curseq = -1; @@ -576,12 +581,12 @@ void S_ParseSndSeq (int levellump) S_ClearSndSeq(); // be gone, compiler warnings - stopsound = 0; + stopsound = NO_SOUND; memset (SeqTrans, -1, sizeof(SeqTrans)); lastlump = 0; - while (((lump = Wads.FindLump ("SNDSEQ", &lastlump)) != -1 || levellump != -1) && levellump != -2) + while (((lump = fileSystem.FindLump ("SNDSEQ", &lastlump)) != -1 || levellump != -1) && levellump != -2) { if (lump == -1) { @@ -613,7 +618,7 @@ void S_ParseSndSeq (int levellump) Sequences.Push (NULL); } ScriptTemp.Clear(); - stopsound = 0; + stopsound = NO_SOUND; slot = NAME_None; if (seqtype == '[') { @@ -631,7 +636,7 @@ void S_ParseSndSeq (int levellump) if (sc.String[0] == ']') { // End of this definition ScriptTemp[0] = MakeCommand(SS_CMD_SELECT, (ScriptTemp.Size()-1)/2); - AddSequence (curseq, seqname, slot, stopsound, ScriptTemp); + AddSequence (curseq, seqname, slot, stopsound.index(), ScriptTemp); curseq = -1; sc.SetCMode (false); } @@ -642,7 +647,7 @@ void S_ParseSndSeq (int levellump) { ScriptTemp.Push (sc.Number); sc.MustGetString(); - ScriptTemp.Push (FName(sc.String)); + ScriptTemp.Push (FName(sc.String).GetIndex()); } else { @@ -656,30 +661,30 @@ void S_ParseSndSeq (int levellump) { case SS_STRING_PLAYUNTILDONE: sc.MustGetString (); - ScriptTemp.Push(MakeCommand(SS_CMD_PLAY, S_FindSound (sc.String))); + ScriptTemp.Push(MakeCommand(SS_CMD_PLAY, S_FindSound (sc.String).index())); ScriptTemp.Push(MakeCommand(SS_CMD_WAITUNTILDONE, 0)); break; case SS_STRING_PLAY: sc.MustGetString (); - ScriptTemp.Push(MakeCommand(SS_CMD_PLAY, S_FindSound (sc.String))); + ScriptTemp.Push(MakeCommand(SS_CMD_PLAY, S_FindSound (sc.String).index())); break; case SS_STRING_PLAYTIME: sc.MustGetString (); - ScriptTemp.Push(MakeCommand(SS_CMD_PLAY, S_FindSound (sc.String))); + ScriptTemp.Push(MakeCommand(SS_CMD_PLAY, S_FindSound (sc.String).index())); sc.MustGetNumber (); ScriptTemp.Push(MakeCommand(SS_CMD_DELAY, sc.Number)); break; case SS_STRING_PLAYREPEAT: sc.MustGetString (); - ScriptTemp.Push(MakeCommand (SS_CMD_PLAYREPEAT, S_FindSound (sc.String))); + ScriptTemp.Push(MakeCommand (SS_CMD_PLAYREPEAT, S_FindSound (sc.String).index())); break; case SS_STRING_PLAYLOOP: sc.MustGetString (); - ScriptTemp.Push(MakeCommand (SS_CMD_PLAYLOOP, S_FindSound (sc.String))); + ScriptTemp.Push(MakeCommand (SS_CMD_PLAYLOOP, S_FindSound (sc.String).index())); sc.MustGetNumber (); ScriptTemp.Push(sc.Number); break; @@ -700,7 +705,7 @@ void S_ParseSndSeq (int levellump) delaybase = sc.Number; ScriptTemp.Push(MakeCommand(SS_CMD_DELAYRAND, sc.Number)); sc.MustGetNumber (); - ScriptTemp.Push(MAX(1, sc.Number - delaybase + 1)); + ScriptTemp.Push(max(1, sc.Number - delaybase + 1)); break; case SS_STRING_VOLUME: // volume is in range 0..100 @@ -728,7 +733,7 @@ void S_ParseSndSeq (int levellump) break; case SS_STRING_NOSTOPCUTOFF: - stopsound = -1; + stopsound = INVALID_SOUND; ScriptTemp.Push(MakeCommand(SS_CMD_STOPSOUND, 0)); break; @@ -754,7 +759,7 @@ void S_ParseSndSeq (int levellump) break; case SS_STRING_END: - AddSequence (curseq, seqname, slot, stopsound, ScriptTemp); + AddSequence (curseq, seqname, slot, stopsound.index(), ScriptTemp); curseq = -1; break; @@ -791,13 +796,13 @@ static void AddSequence (int curseq, FName seqname, FName slot, int stopsound, c Sequences[curseq] = (FSoundSequence *)M_Malloc (sizeof(FSoundSequence) + sizeof(uint32_t)*ScriptTemp.Size()); Sequences[curseq]->SeqName = seqname; Sequences[curseq]->Slot = slot; - Sequences[curseq]->StopSound = FSoundID(stopsound); + Sequences[curseq]->StopSound = FSoundID::fromInt(stopsound); memcpy (Sequences[curseq]->Script, &ScriptTemp[0], sizeof(uint32_t)*ScriptTemp.Size()); Sequences[curseq]->Script[ScriptTemp.Size()] = MakeCommand(SS_CMD_END, 0); } DSeqNode::DSeqNode (FLevelLocals *l, int sequence, int modenum) -: m_CurrentSoundID(0), m_ModeNum(modenum), m_SequenceChoices(0) +: m_CurrentSoundID(NO_SOUND), m_ModeNum(modenum), m_SequenceChoices(0) { Level = l; ActivateSequence (sequence); @@ -823,15 +828,15 @@ void DSeqNode::ActivateSequence (int sequence) m_Sequence = sequence; m_DelayTics = 0; m_StopSound = Sequences[sequence]->StopSound; - m_CurrentSoundID = 0; + m_CurrentSoundID = NO_SOUND; m_Volume = 1; // Start at max volume... m_Atten = ATTN_IDLE; // ...and idle attenuation } -DSeqActorNode::DSeqActorNode (AActor *actor, int sequence, int modenum) - : DSeqNode (actor->Level, sequence, modenum), - m_Actor (actor) +DSeqActorNode::DSeqActorNode(AActor* actor, int sequence, int modenum) + : DSeqNode(actor->Level, sequence, modenum) { + m_Actor = actor; } DSeqPolyNode::DSeqPolyNode (FPolyObj *poly, int sequence, int modenum) @@ -859,9 +864,9 @@ static bool TwiddleSeqNum (int &sequence, seqtype_t type) { // [GrafZahl] Needs some range checking: // Sector_ChangeSound doesn't do it so this makes invalid sequences play nothing. - if (sequence >= 0 && sequence < 64) + if (sequence >= 0 && sequence < MAX_SNDSEQS) { - sequence = SeqTrans[sequence + type * 64]; + sequence = SeqTrans[sequence + type * MAX_SNDSEQS]; } else { @@ -1122,27 +1127,27 @@ void SN_DoStop (FLevelLocals *Level, void *source) void DSeqActorNode::OnDestroy () { - if (m_StopSound >= 0) + if (m_StopSound != INVALID_SOUND) S_StopSound (m_Actor, CHAN_BODY); - if (m_StopSound >= 1) + if (m_StopSound.isvalid()) MakeSound (0, m_StopSound); Super::OnDestroy(); } void DSeqSectorNode::OnDestroy () { - if (m_StopSound >= 0) + if (m_StopSound != INVALID_SOUND) S_StopSound (m_Sector, Channel & 7); - if (m_StopSound >= 1) + if (m_StopSound.isvalid()) MakeSound (0, m_StopSound); Super::OnDestroy(); } void DSeqPolyNode::OnDestroy () { - if (m_StopSound >= 0) + if (m_StopSound != INVALID_SOUND) S_StopSound (m_Poly, CHAN_BODY); - if (m_StopSound >= 1) + if (m_StopSound.isvalid()) MakeSound (0, m_StopSound); Super::OnDestroy(); } @@ -1199,7 +1204,7 @@ void DSeqNode::Tick () case SS_CMD_PLAY: if (!IsPlaying()) { - m_CurrentSoundID = FSoundID(GetData(*m_SequencePtr)); + m_CurrentSoundID = FSoundID::fromInt(GetData(*m_SequencePtr)); MakeSound (0, m_CurrentSoundID); } m_SequencePtr++; @@ -1209,7 +1214,7 @@ void DSeqNode::Tick () if (!IsPlaying()) { m_SequencePtr++; - m_CurrentSoundID = 0; + m_CurrentSoundID = NO_SOUND; } else { @@ -1221,7 +1226,7 @@ void DSeqNode::Tick () if (!IsPlaying()) { // Does not advance sequencePtr, so it will repeat as necessary. - m_CurrentSoundID = FSoundID(GetData(*m_SequencePtr)); + m_CurrentSoundID = FSoundID::fromInt(GetData(*m_SequencePtr)); MakeSound (CHANF_LOOP, m_CurrentSoundID); } return; @@ -1229,7 +1234,7 @@ void DSeqNode::Tick () case SS_CMD_PLAYLOOP: // Like SS_CMD_PLAYREPEAT, sequencePtr is not advanced, so this // command will repeat until the sequence is stopped. - m_CurrentSoundID = FSoundID(GetData(m_SequencePtr[0])); + m_CurrentSoundID = FSoundID::fromInt(GetData(m_SequencePtr[0])); MakeSound (0, m_CurrentSoundID); m_DelayTics = m_SequencePtr[1]; return; @@ -1268,13 +1273,13 @@ void DSeqNode::Tick () case SS_CMD_DELAY: m_DelayTics = GetData(*m_SequencePtr); m_SequencePtr++; - m_CurrentSoundID = 0; + m_CurrentSoundID = NO_SOUND; return; case SS_CMD_DELAYRAND: m_DelayTics = GetData(m_SequencePtr[0]) + pr_sndseq(m_SequencePtr[1]); m_SequencePtr += 2; - m_CurrentSoundID = 0; + m_CurrentSoundID = NO_SOUND; return; case SS_CMD_VOLUME: @@ -1378,7 +1383,7 @@ void SN_StopAllSequences (FLevelLocals *Level) for (node = Level->SequenceListHead; node; ) { DSeqNode *next = node->NextSequence(); - node->m_StopSound = 0; // don't play any stop sounds + node->m_StopSound = NO_SOUND; // don't play any stop sounds node->Destroy (); node = next; } @@ -1439,7 +1444,7 @@ void SN_MarkPrecacheSounds(int sequence, seqtype_t type) int cmd = GetCommand(seq->Script[i]); if (cmd == SS_CMD_PLAY || cmd == SS_CMD_PLAYREPEAT || cmd == SS_CMD_PLAYLOOP) { - soundEngine->MarkUsed(GetData(seq->Script[i])); + soundEngine->MarkUsed(FSoundID::fromInt(GetData(seq->Script[i]))); } } } @@ -1463,7 +1468,7 @@ DEFINE_ACTION_FUNCTION(DSeqNode, MarkPrecacheSounds) //========================================================================== void SN_ChangeNodeData (FLevelLocals *Level, int nodeNum, int seqOffset, int delayTics, float volume, - int currentSoundID) + FSoundID currentSoundID) { int i; DSeqNode *node; diff --git a/src/sound/s_sndseq.h b/src/sound/s_sndseq.h index 77c0209fdba..11c5d68e17d 100644 --- a/src/sound/s_sndseq.h +++ b/src/sound/s_sndseq.h @@ -5,6 +5,8 @@ #include "dobject.h" #include "s_sound.h" +#define MAX_SNDSEQS (4096) + enum { // Sound channel aliases for sound sequences. @@ -54,7 +56,7 @@ class DSeqNode : public DObject int m_Sequence; FSoundID m_CurrentSoundID; - int m_StopSound; + FSoundID m_StopSound; int m_DelayTics; float m_Volume; float m_Atten; diff --git a/src/sound/s_sound.h b/src/sound/s_sound.h index b821958494a..216f5829ebd 100644 --- a/src/sound/s_sound.h +++ b/src/sound/s_sound.h @@ -37,27 +37,45 @@ struct FLevelLocals; #include "s_soundinternal.h" #include "s_doomsound.h" +#include "name.h" +#include "tarray.h" + +enum SndUserFlags +{ + SND_PlayerReserve = 1, + SND_PlayerCompat = 2, + SND_PlayerSilent = 4 +}; + +enum // This cannot be remain as this, but for now it has to suffice. +{ + SOURCE_Actor = SOURCE_None+1, // Sound is coming from an actor. + SOURCE_Sector, // Sound is coming from a sector. + SOURCE_Polyobj, // Sound is coming from a polyobject. +}; // Per level startup code. // Kills playing sounds at start of level and starts new music. // +typedef TMap MusicAliasMap; +extern MusicAliasMap MusicAliases; // Called after a level is loaded. Ensures that most sounds are loaded. // [RH] S_sfx "maintenance" routines void S_ClearSoundData(); void S_ParseSndInfo (bool redefine); +void S_LockLocalSndinfo(); -bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2); -bool S_AreSoundsEquivalent (AActor *actor, const char *name1, const char *name2); -int S_LookupPlayerSound (const char *playerclass, int gender, const char *logicalname); -int S_LookupPlayerSound (const char *playerclass, int gender, FSoundID refid); -int S_FindSkinnedSound (AActor *actor, FSoundID refid); -int S_FindSkinnedSoundEx (AActor *actor, const char *logicalname, const char *extendedname); -int S_AddSound (const char *logicalname, const char *lumpname, FScanner *sc=NULL); // Add sound by lumpname -int S_AddPlayerSound (const char *playerclass, const int gender, int refid, const char *lumpname); -int S_AddPlayerSound (const char *playerclass, const int gender, int refid, int lumpnum, bool fromskin=false); -int S_AddPlayerSoundExisting (const char *playerclass, const int gender, int refid, int aliasto, bool fromskin=false); +bool S_AreSoundsEquivalent (AActor *actor, FSoundID id1, FSoundID id2); +FSoundID S_LookupPlayerSound (const char *playerclass, int gender, FSoundID refid); +const char *S_GetSoundClass(AActor *pp); +FSoundID S_FindSkinnedSound (AActor *actor, FSoundID refid); +FSoundID S_FindSkinnedSoundEx (AActor *actor, const char *logicalname, const char *extendedname); +FSoundID S_AddSound (const char *logicalname, const char *lumpname, FScanner *sc=NULL); // Add sound by lumpname +FSoundID S_AddPlayerSound (const char *playerclass, const int gender, FSoundID refid, const char *lumpname); +FSoundID S_AddPlayerSound (const char *playerclass, const int gender, FSoundID refid, int lumpnum, bool fromskin=false); +FSoundID S_AddPlayerSoundExisting (const char *playerclass, const int gender, FSoundID refid, FSoundID aliasto, bool fromskin=false); void S_MarkPlayerSounds (AActor *player); void S_ShrinkPlayerSoundLists (); unsigned int S_GetMSLength(FSoundID sound); diff --git a/src/sound/s_soundinternal.h b/src/sound/s_soundinternal.h deleted file mode 100644 index e3647b9c7cb..00000000000 --- a/src/sound/s_soundinternal.h +++ /dev/null @@ -1,427 +0,0 @@ -#pragma once - -#include "i_sound.h" - -struct FRandomSoundList -{ - TArray Choices; - uint32_t Owner = 0; -}; - -extern int sfx_empty; - -// -// SoundFX struct. -// -struct sfxinfo_t -{ - // Next field is for use by the system sound interface. - // A non-null data means the sound has been loaded. - SoundHandle data; - - FString name; // [RH] Sound name defined in SNDINFO - int lumpnum; // lump number of sfx - - unsigned int next, index; // [RH] For hashing - float Volume; - - int ResourceId; // Resource ID as implemented by Blood. Not used by Doom but added for completeness. - uint8_t PitchMask; - int16_t NearLimit; // 0 means unlimited - float LimitRange; // Range for sound limiting (squared for faster computations) - - unsigned bRandomHeader:1; - unsigned bLoadRAW:1; - unsigned b16bit:1; - unsigned bUsed:1; - unsigned bSingular:1; - - unsigned bTentative:1; - unsigned bPlayerReserve : 1; - unsigned bPlayerCompat : 1; - unsigned bPlayerSilent:1; // This player sound is intentionally silent. - - int RawRate; // Sample rate to use when bLoadRAW is true - - int LoopStart; // -1 means no specific loop defined - - unsigned int link; - enum { NO_LINK = 0xffffffff }; - - FRolloffInfo Rolloff; - float Attenuation; // Multiplies the attenuation passed to S_Sound. - - void MarkUsed(); // Marks this sound as used. - - void Clear() - { - data.Clear(); - lumpnum = -1; // lump number of sfx - next = -1; - index = 0; // [RH] For hashing - Volume = 1.f; - ResourceId = -1; - PitchMask = 0; - NearLimit = 4; // 0 means unlimited - LimitRange = 256*256; - - bRandomHeader = false; - bLoadRAW = false; - b16bit= false; - bUsed = false; - bSingular = false; - - bTentative = true; - - RawRate = 0; // Sample rate to use when bLoadRAW is true - - LoopStart = 0; // -1 means no specific loop defined - - link = NO_LINK; - - Rolloff = {}; - Attenuation = 1.f; - } -}; - -// Rolloff types -enum -{ - ROLLOFF_Doom, // Linear rolloff with a logarithmic volume scale - ROLLOFF_Linear, // Linear rolloff with a linear volume scale - ROLLOFF_Log, // Logarithmic rolloff (standard hardware type) - ROLLOFF_Custom // Lookup volume from SNDCURVE -}; - -int S_FindSound(const char *logicalname); -int S_FindSoundByResID(int snd_id); - -// An index into the S_sfx[] array. -class FSoundID -{ -public: - FSoundID() = default; - - static FSoundID byResId(int ndx) - { - return FSoundID(S_FindSoundByResID(ndx)); - } - FSoundID(int id) - { - ID = id; - } - FSoundID(const char *name) - { - ID = S_FindSound(name); - } - FSoundID(const FString &name) - { - ID = S_FindSound(name.GetChars()); - } - FSoundID(const FSoundID &other) = default; - FSoundID &operator=(const FSoundID &other) = default; - FSoundID &operator=(const char *name) - { - ID = S_FindSound(name); - return *this; - } - FSoundID &operator=(const FString &name) - { - ID = S_FindSound(name.GetChars()); - return *this; - } - bool operator !=(FSoundID other) const - { - return ID != other.ID; - } - bool operator !=(int other) const - { - return ID != other; - } - operator int() const - { - return ID; - } -private: - int ID; -protected: - enum EDummy { NoInit }; - FSoundID(EDummy) {} -}; - - class FSoundIDNoInit : public FSoundID -{ -public: - FSoundIDNoInit() : FSoundID(NoInit) {} - using FSoundID::operator=; -}; - - - -struct FSoundChan : public FISoundChannel -{ - FSoundChan *NextChan; // Next channel in this list. - FSoundChan **PrevChan; // Previous channel in this list. - FSoundID SoundID; // Sound ID of playing sound. - FSoundID OrgID; // Sound ID of sound used to start this channel. - float Volume; - int EntChannel; // Actor's sound channel. - int16_t Pitch; // Pitch variation. - int16_t NearLimit; - int8_t Priority; - uint8_t SourceType; - float LimitRange; - union - { - const void *Source; - float Point[3]; // Sound is not attached to any source. - }; -}; - - -// sound channels -// channel 0 never willingly overrides -// other channels (1-7) always override a playing sound on that channel -// -// CHAN_AUTO searches down from channel 7 until it finds a channel not in use -// CHAN_WEAPON is for weapons -// CHAN_VOICE is for oof, sight, or other voice sounds -// CHAN_ITEM is for small things and item pickup -// CHAN_BODY is for generic body sounds - -enum EChannel -{ - CHAN_AUTO = 0, - CHAN_WEAPON = 1, - CHAN_VOICE = 2, - CHAN_ITEM = 3, - CHAN_BODY = 4, - CHAN_5 = 5, - CHAN_6 = 6, - CHAN_7 = 7, -}; - - - -// sound attenuation values -#define ATTN_NONE 0.f // full volume the entire level -#define ATTN_NORM 1.f -#define ATTN_IDLE 1.001f -#define ATTN_STATIC 3.f // diminish very rapidly with distance - -enum // This cannot be remain as this, but for now it has to suffice. -{ - SOURCE_Any = -1, // Input for check functions meaning 'any source' - SOURCE_None, // Sound is always on top of the listener. - SOURCE_Actor, // Sound is coming from an actor. - SOURCE_Sector, // Sound is coming from a sector. - SOURCE_Polyobj, // Sound is coming from a polyobject. - SOURCE_Unattached, // Sound is not attached to any particular emitter. -}; - - -extern ReverbContainer *Environments; -extern ReverbContainer *DefaultEnvironments[26]; - -void S_ParseReverbDef (); -void S_UnloadReverbDef (); -void S_SetEnvironment (const ReverbContainer *settings); -ReverbContainer *S_FindEnvironment (const char *name); -ReverbContainer *S_FindEnvironment (int id); -void S_AddEnvironment (ReverbContainer *settings); - -class SoundEngine -{ -protected: - bool SoundPaused = false; // whether sound is paused - int RestartEvictionsAt = 0; // do not restart evicted channels before this time - SoundListener listener{}; - - FSoundChan* Channels = nullptr; - FSoundChan* FreeChannels = nullptr; - - // the complete set of sound effects - TArray S_sfx; - FRolloffInfo S_Rolloff; - TArray S_SoundCurve; - TMap ResIdMap; - TArray S_rnd; - -private: - void LinkChannel(FSoundChan* chan, FSoundChan** head); - void UnlinkChannel(FSoundChan* chan); - void ReturnChannel(FSoundChan* chan); - void RestartChannel(FSoundChan* chan); - void RestoreEvictedChannel(FSoundChan* chan); - - bool IsChannelUsed(int sourcetype, const void* actor, int channel, int* seen); - // This is the actual sound positioning logic which needs to be provided by the client. - virtual void CalcPosVel(int type, const void* source, const float pt[3], int channel, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan *chan) = 0; - // This can be overridden by the clent to provide some diagnostics. The default lets everything pass. - virtual bool ValidatePosVel(int sourcetype, const void* source, const FVector3& pos, const FVector3& vel) { return true; } - - bool ValidatePosVel(const FSoundChan* const chan, const FVector3& pos, const FVector3& vel); - - // Checks if a copy of this sound is already playing. - bool CheckSingular(int sound_id); - bool CheckSoundLimit(sfxinfo_t* sfx, const FVector3& pos, int near_limit, float limit_range, int sourcetype, const void* actor, int channel); - virtual TArray ReadSound(int lumpnum) = 0; -protected: - virtual FSoundID ResolveSound(const void *ent, int srctype, FSoundID soundid, float &attenuation); - -public: - virtual ~SoundEngine() = default; - void EvictAllChannels(); - - void StopChannel(FSoundChan* chan); - sfxinfo_t* LoadSound(sfxinfo_t* sfx); - - // Initializes sound stuff, including volume - // Sets channels, SFX and music volume, - // allocates channel buffer, sets S_sfx lookup. - // - void Init(TArray &sndcurve); - void InitData(); - void Clear(); - void Shutdown(); - - void StopAllChannels(void); - void SetPitch(FSoundChan* chan, float dpitch); - void SetVolume(FSoundChan* chan, float vol); - - FSoundChan* GetChannel(void* syschan); - void RestoreEvictedChannels(); - void CalcPosVel(FSoundChan* chan, FVector3* pos, FVector3* vel); - - // Loads a sound, including any random sounds it might reference. - void CacheSound(sfxinfo_t* sfx); - void CacheSound(int sfx) { CacheSound(&S_sfx[sfx]); } - void UnloadSound(sfxinfo_t* sfx); - - void UpdateSounds(int time); - - FSoundChan* StartSound(int sourcetype, const void* source, - const FVector3* pt, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, FRolloffInfo* rolloff = nullptr, float spitch = 0.0f, float startTime = 0.0f); - - // Stops an origin-less sound from playing from this channel. - void StopSoundID(int sound_id); - void StopSound(int channel, int sound_id = -1); - void StopSound(int sourcetype, const void* actor, int channel, int sound_id = -1); - void StopActorSounds(int sourcetype, const void* actor, int chanmin, int chanmax); - - void RelinkSound(int sourcetype, const void* from, const void* to, const FVector3* optpos); - void ChangeSoundVolume(int sourcetype, const void* source, int channel, double dvolume); - void ChangeSoundPitch(int sourcetype, const void* source, int channel, double pitch, int sound_id = -1); - bool IsSourcePlayingSomething(int sourcetype, const void* actor, int channel, int sound_id = -1); - - // Stop and resume music, during game PAUSE. - int GetSoundPlayingInfo(int sourcetype, const void* source, int sound_id); - void UnloadAllSounds(); - void Reset(); - void MarkUsed(int num); - void CacheMarkedSounds(); - TArray AllActiveChannels(); - - void MarkAllUnused() - { - for (auto & s: S_sfx) s.bUsed = false; - } - - bool isListener(const void* object) const - { - return object && listener.ListenerObject == object; - } - bool isPlayerReserve(int snd_id) - { - return S_sfx[snd_id].bPlayerReserve; // Later this needs to be abstracted out of the engine itself. Right now that cannot be done. - } - void SetListener(SoundListener& l) - { - listener = l; - } - void SetRestartTime(int time) - { - RestartEvictionsAt = time; - } - void SetPaused(bool on) - { - SoundPaused = on; - } - FSoundChan* GetChannels() - { - return Channels; - } - const char *GetSoundName(FSoundID id) - { - return id == 0 ? "" : S_sfx[id].name.GetChars(); - } - TArray &GetSounds() //This should only be used for constructing the sound list or for diagnostics code prinring information about the sound list. - { - return S_sfx; - } - FRolloffInfo& GlobalRolloff() // like GetSounds this is meant for sound list generators, not for gaining cheap access to the sound engine's innards. - { - return S_Rolloff; - } - FRandomSoundList *ResolveRandomSound(sfxinfo_t* sfx) - { - return &S_rnd[sfx->link]; - } - void ClearRandoms() - { - S_rnd.Clear(); - } - bool isValidSoundId(int id) - { - return id > 0 && id < (int)S_sfx.Size() && !S_sfx[id].bTentative && S_sfx[id].lumpnum != sfx_empty; - } - - template bool EnumerateChannels(func callback) - { - for (FSoundChan* chan = Channels; chan; chan = chan->NextChan) - { - int res = callback(chan); - if (res) return res > 0; - } - return false; - } - - void SetDefaultRolloff(FRolloffInfo* ro) - { - S_Rolloff = *ro; - } - - void ChannelVirtualChanged(FISoundChannel* ichan, bool is_virtual); - FString ListSoundChannels(); - - // Allow this to be overridden for special needs. - virtual float GetRolloff(const FRolloffInfo* rolloff, float distance); - virtual void ChannelEnded(FISoundChannel* ichan); // allows the client to do bookkeeping on the sound. - - // Lookup utilities. - int FindSound(const char* logicalname); - int FindSoundByResID(int rid); - int FindSoundNoHash(const char* logicalname); - int FindSoundByLump(int lump); - int AddSoundLump(const char* logicalname, int lump, int CurrentPitchMask, int resid = -1, int nearlimit = 2); - int AddSfx(sfxinfo_t &sfx); - int FindSoundTentative(const char* name); - void CacheRandomSound(sfxinfo_t* sfx); - unsigned int GetMSLength(FSoundID sound); - int PickReplacement(int refid); - void HashSounds(); - void AddRandomSound(int Owner, TArray list); -}; - - -extern SoundEngine* soundEngine; - -struct FReverbField -{ - int Min, Max; - float REVERB_PROPERTIES::* Float; - int REVERB_PROPERTIES::* Int; - unsigned int Flag; -}; - - diff --git a/src/sound/thirdparty/alext.h b/src/sound/thirdparty/alext.h deleted file mode 100644 index 7d2a95274a7..00000000000 --- a/src/sound/thirdparty/alext.h +++ /dev/null @@ -1,400 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2008 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#ifndef AL_ALEXT_H -#define AL_ALEXT_H - -#include -/* Define int64_t and uint64_t types */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -/* Fallback if nothing above works */ -#include -#endif - -#include "alc.h" -#include "al.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef AL_LOKI_IMA_ADPCM_format -#define AL_LOKI_IMA_ADPCM_format 1 -#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 -#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 -#endif - -#ifndef AL_LOKI_WAVE_format -#define AL_LOKI_WAVE_format 1 -#define AL_FORMAT_WAVE_EXT 0x10002 -#endif - -#ifndef AL_EXT_vorbis -#define AL_EXT_vorbis 1 -#define AL_FORMAT_VORBIS_EXT 0x10003 -#endif - -#ifndef AL_LOKI_quadriphonic -#define AL_LOKI_quadriphonic 1 -#define AL_FORMAT_QUAD8_LOKI 0x10004 -#define AL_FORMAT_QUAD16_LOKI 0x10005 -#endif - -#ifndef AL_EXT_float32 -#define AL_EXT_float32 1 -#define AL_FORMAT_MONO_FLOAT32 0x10010 -#define AL_FORMAT_STEREO_FLOAT32 0x10011 -#endif - -#ifndef AL_EXT_double -#define AL_EXT_double 1 -#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 -#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 -#endif - -#ifndef AL_EXT_MULAW -#define AL_EXT_MULAW 1 -#define AL_FORMAT_MONO_MULAW_EXT 0x10014 -#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 -#endif - -#ifndef AL_EXT_ALAW -#define AL_EXT_ALAW 1 -#define AL_FORMAT_MONO_ALAW_EXT 0x10016 -#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 -#endif - -#ifndef ALC_LOKI_audio_channel -#define ALC_LOKI_audio_channel 1 -#define ALC_CHAN_MAIN_LOKI 0x500001 -#define ALC_CHAN_PCM_LOKI 0x500002 -#define ALC_CHAN_CD_LOKI 0x500003 -#endif - -#ifndef AL_EXT_MCFORMATS -#define AL_EXT_MCFORMATS 1 -#define AL_FORMAT_QUAD8 0x1204 -#define AL_FORMAT_QUAD16 0x1205 -#define AL_FORMAT_QUAD32 0x1206 -#define AL_FORMAT_REAR8 0x1207 -#define AL_FORMAT_REAR16 0x1208 -#define AL_FORMAT_REAR32 0x1209 -#define AL_FORMAT_51CHN8 0x120A -#define AL_FORMAT_51CHN16 0x120B -#define AL_FORMAT_51CHN32 0x120C -#define AL_FORMAT_61CHN8 0x120D -#define AL_FORMAT_61CHN16 0x120E -#define AL_FORMAT_61CHN32 0x120F -#define AL_FORMAT_71CHN8 0x1210 -#define AL_FORMAT_71CHN16 0x1211 -#define AL_FORMAT_71CHN32 0x1212 -#endif - -#ifndef AL_EXT_MULAW_MCFORMATS -#define AL_EXT_MULAW_MCFORMATS 1 -#define AL_FORMAT_MONO_MULAW 0x10014 -#define AL_FORMAT_STEREO_MULAW 0x10015 -#define AL_FORMAT_QUAD_MULAW 0x10021 -#define AL_FORMAT_REAR_MULAW 0x10022 -#define AL_FORMAT_51CHN_MULAW 0x10023 -#define AL_FORMAT_61CHN_MULAW 0x10024 -#define AL_FORMAT_71CHN_MULAW 0x10025 -#endif - -#ifndef AL_EXT_IMA4 -#define AL_EXT_IMA4 1 -#define AL_FORMAT_MONO_IMA4 0x1300 -#define AL_FORMAT_STEREO_IMA4 0x1301 -#endif - -#ifndef AL_EXT_STATIC_BUFFER -#define AL_EXT_STATIC_BUFFER 1 -typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); -#endif -#endif - -#ifndef ALC_EXT_EFX -#define ALC_EXT_EFX 1 -#include "efx.h" -#endif - -#ifndef ALC_EXT_disconnect -#define ALC_EXT_disconnect 1 -#define ALC_CONNECTED 0x313 -#endif - -#ifndef ALC_EXT_thread_local_context -#define ALC_EXT_thread_local_context 1 -typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); -typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); -ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); -#endif -#endif - -#ifndef AL_EXT_source_distance_model -#define AL_EXT_source_distance_model 1 -#define AL_SOURCE_DISTANCE_MODEL 0x200 -#endif - -#ifndef AL_SOFT_buffer_sub_data -#define AL_SOFT_buffer_sub_data 1 -#define AL_BYTE_RW_OFFSETS_SOFT 0x1031 -#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 -typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); -#endif -#endif - -#ifndef AL_SOFT_loop_points -#define AL_SOFT_loop_points 1 -#define AL_LOOP_POINTS_SOFT 0x2015 -#endif - -#ifndef AL_EXT_FOLDBACK -#define AL_EXT_FOLDBACK 1 -#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" -#define AL_FOLDBACK_EVENT_BLOCK 0x4112 -#define AL_FOLDBACK_EVENT_START 0x4111 -#define AL_FOLDBACK_EVENT_STOP 0x4113 -#define AL_FOLDBACK_MODE_MONO 0x4101 -#define AL_FOLDBACK_MODE_STEREO 0x4102 -typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); -typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); -typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); -AL_API void AL_APIENTRY alRequestFoldbackStop(void); -#endif -#endif - -#ifndef ALC_EXT_DEDICATED -#define ALC_EXT_DEDICATED 1 -#define AL_DEDICATED_GAIN 0x0001 -#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 -#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 -#endif - -#ifndef AL_SOFT_buffer_samples -#define AL_SOFT_buffer_samples 1 -/* Channel configurations */ -#define AL_MONO_SOFT 0x1500 -#define AL_STEREO_SOFT 0x1501 -#define AL_REAR_SOFT 0x1502 -#define AL_QUAD_SOFT 0x1503 -#define AL_5POINT1_SOFT 0x1504 -#define AL_6POINT1_SOFT 0x1505 -#define AL_7POINT1_SOFT 0x1506 - -/* Sample types */ -#define AL_BYTE_SOFT 0x1400 -#define AL_UNSIGNED_BYTE_SOFT 0x1401 -#define AL_SHORT_SOFT 0x1402 -#define AL_UNSIGNED_SHORT_SOFT 0x1403 -#define AL_INT_SOFT 0x1404 -#define AL_UNSIGNED_INT_SOFT 0x1405 -#define AL_FLOAT_SOFT 0x1406 -#define AL_DOUBLE_SOFT 0x1407 -#define AL_BYTE3_SOFT 0x1408 -#define AL_UNSIGNED_BYTE3_SOFT 0x1409 - -/* Storage formats */ -#define AL_MONO8_SOFT 0x1100 -#define AL_MONO16_SOFT 0x1101 -#define AL_MONO32F_SOFT 0x10010 -#define AL_STEREO8_SOFT 0x1102 -#define AL_STEREO16_SOFT 0x1103 -#define AL_STEREO32F_SOFT 0x10011 -#define AL_QUAD8_SOFT 0x1204 -#define AL_QUAD16_SOFT 0x1205 -#define AL_QUAD32F_SOFT 0x1206 -#define AL_REAR8_SOFT 0x1207 -#define AL_REAR16_SOFT 0x1208 -#define AL_REAR32F_SOFT 0x1209 -#define AL_5POINT1_8_SOFT 0x120A -#define AL_5POINT1_16_SOFT 0x120B -#define AL_5POINT1_32F_SOFT 0x120C -#define AL_6POINT1_8_SOFT 0x120D -#define AL_6POINT1_16_SOFT 0x120E -#define AL_6POINT1_32F_SOFT 0x120F -#define AL_7POINT1_8_SOFT 0x1210 -#define AL_7POINT1_16_SOFT 0x1211 -#define AL_7POINT1_32F_SOFT 0x1212 - -/* Buffer attributes */ -#define AL_INTERNAL_FORMAT_SOFT 0x2008 -#define AL_BYTE_LENGTH_SOFT 0x2009 -#define AL_SAMPLE_LENGTH_SOFT 0x200A -#define AL_SEC_LENGTH_SOFT 0x200B - -typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); -typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); -#endif -#endif - -#ifndef AL_SOFT_direct_channels -#define AL_SOFT_direct_channels 1 -#define AL_DIRECT_CHANNELS_SOFT 0x1033 -#endif - -#ifndef ALC_SOFT_loopback -#define ALC_SOFT_loopback 1 -#define ALC_FORMAT_CHANNELS_SOFT 0x1990 -#define ALC_FORMAT_TYPE_SOFT 0x1991 - -/* Sample types */ -#define ALC_BYTE_SOFT 0x1400 -#define ALC_UNSIGNED_BYTE_SOFT 0x1401 -#define ALC_SHORT_SOFT 0x1402 -#define ALC_UNSIGNED_SHORT_SOFT 0x1403 -#define ALC_INT_SOFT 0x1404 -#define ALC_UNSIGNED_INT_SOFT 0x1405 -#define ALC_FLOAT_SOFT 0x1406 - -/* Channel configurations */ -#define ALC_MONO_SOFT 0x1500 -#define ALC_STEREO_SOFT 0x1501 -#define ALC_QUAD_SOFT 0x1503 -#define ALC_5POINT1_SOFT 0x1504 -#define ALC_6POINT1_SOFT 0x1505 -#define ALC_7POINT1_SOFT 0x1506 - -typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); -typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); -typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); -ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); -ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); -#endif -#endif - -#ifndef AL_EXT_STEREO_ANGLES -#define AL_EXT_STEREO_ANGLES 1 -#define AL_STEREO_ANGLES 0x1030 -#endif - -#ifndef AL_EXT_SOURCE_RADIUS -#define AL_EXT_SOURCE_RADIUS 1 -#define AL_SOURCE_RADIUS 0x1031 -#endif - -#ifndef AL_SOFT_source_latency -#define AL_SOFT_source_latency 1 -#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 -#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 -typedef int64_t ALint64SOFT; -typedef uint64_t ALuint64SOFT; -typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); -typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); -typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); -typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); -typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); -typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); -AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); -AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); -AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); -#endif -#endif - -#ifndef ALC_EXT_DEFAULT_FILTER_ORDER -#define ALC_EXT_DEFAULT_FILTER_ORDER 1 -#define ALC_DEFAULT_FILTER_ORDER 0x1100 -#endif - -#ifndef AL_SOFT_deferred_updates -#define AL_SOFT_deferred_updates 1 -#define AL_DEFERRED_UPDATES_SOFT 0xC002 -typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); -typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); -#ifdef AL_ALEXT_PROTOTYPES -AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void); -AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void); -#endif -#endif - -#ifndef AL_SOFT_block_alignment -#define AL_SOFT_block_alignment 1 -#define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C -#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D -#endif - -#ifndef AL_SOFT_MSADPCM -#define AL_SOFT_MSADPCM 1 -#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302 -#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303 -#endif - -#ifndef AL_SOFT_source_length -#define AL_SOFT_source_length 1 -/*#define AL_BYTE_LENGTH_SOFT 0x2009*/ -/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/ -/*#define AL_SEC_LENGTH_SOFT 0x200B*/ -#endif - -#ifndef ALC_SOFT_pause_device -#define ALC_SOFT_pause_device 1 -typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device); -typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device); -ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/st_start.h b/src/st_start.h deleted file mode 100644 index 8e53b0e4f07..00000000000 --- a/src/st_start.h +++ /dev/null @@ -1,184 +0,0 @@ -#pragma once -/* -** st_start.h -** Interface for the startup screen. -** -**--------------------------------------------------------------------------- -** Copyright 2006-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** The startup screen interface is based on a mix of Heretic and Hexen. -** Actual implementation is system-specific. -*/ -#include - -class FStartupScreen -{ -public: - static FStartupScreen *CreateInstance(int max_progress); - - FStartupScreen(int max_progress); - virtual ~FStartupScreen(); - - virtual void Progress(); - virtual void LoadingStatus(const char *message, int colors); // Used by Heretic only - virtual void AppendStatusLine(const char *status); // Used by Heretic only - - virtual void NetInit(const char *message, int num_players); - virtual void NetProgress(int count); - virtual void NetMessage(const char *format, ...); // cover for printf - virtual void NetDone(); - virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata); -protected: - int MaxPos, CurPos, NotchPos; -}; - -class FBasicStartupScreen : public FStartupScreen -{ -public: - FBasicStartupScreen(int max_progress, bool show_bar); - ~FBasicStartupScreen(); - - void Progress(); - void NetInit(const char* message, int num_players); - void NetProgress(int count); - void NetMessage(const char* format, ...); // cover for printf - void NetDone(); - bool NetLoop(bool (*timer_callback)(void*), void* userdata); -protected: - long long NetMarqueeMode; - int NetMaxPos, NetCurPos; -}; - -class FGraphicalStartupScreen : public FBasicStartupScreen -{ -public: - FGraphicalStartupScreen(int max_progress); - ~FGraphicalStartupScreen(); -}; - -class FHereticStartupScreen : public FGraphicalStartupScreen -{ -public: - FHereticStartupScreen(int max_progress, long &hr); - - void Progress(); - void LoadingStatus(const char *message, int colors); - void AppendStatusLine(const char *status); -protected: - void SetWindowSize(); - - int ThermX, ThermY, ThermWidth, ThermHeight; - int HMsgY, SMsgX; -}; - -class FHexenStartupScreen : public FGraphicalStartupScreen -{ -public: - FHexenStartupScreen(int max_progress, long &hr); - ~FHexenStartupScreen(); - - void Progress(); - void NetProgress(int count); - void NetDone(); - void SetWindowSize(); - - // Hexen's notch graphics, converted to chunky pixels. - uint8_t * NotchBits; - uint8_t * NetNotchBits; -}; - -class FStrifeStartupScreen : public FGraphicalStartupScreen -{ -public: - FStrifeStartupScreen(int max_progress, long &hr); - ~FStrifeStartupScreen(); - - void Progress(); -protected: - void DrawStuff(int old_laser, int new_laser); - void SetWindowSize(); - - uint8_t *StartupPics[4+2+1]; -}; - - - -extern FStartupScreen *StartScreen; - -void DeleteStartupScreen(); -extern void ST_Endoom(); - -// The entire set of functions here uses native Windows types. These are recreations of those types so that the code doesn't need to be changed more than necessary - -struct BitmapInfoHeader -{ - uint32_t biSize; - int32_t biWidth; - int32_t biHeight; - uint16_t biPlanes; - uint16_t biBitCount; - uint32_t biCompression; - uint32_t biSizeImage; - int32_t biXPelsPerMeter; - int32_t biYPelsPerMeter; - uint32_t biClrUsed; - uint32_t biClrImportant; -}; - -struct RgbQuad -{ - uint8_t rgbBlue; - uint8_t rgbGreen; - uint8_t rgbRed; - uint8_t rgbReserved; -}; - - -struct BitmapInfo -{ - BitmapInfoHeader bmiHeader; - RgbQuad bmiColors[1]; -}; - -extern BitmapInfo* StartupBitmap; - - -void ST_Util_PlanarToChunky4(uint8_t* dest, const uint8_t* src, int width, int height); -void ST_Util_DrawBlock(BitmapInfo* bitmap_info, const uint8_t* src, int x, int y, int bytewidth, int height); -void ST_Util_ClearBlock(BitmapInfo* bitmap_info, uint8_t fill, int x, int y, int bytewidth, int height); -BitmapInfo* ST_Util_CreateBitmap(int width, int height, int color_bits); -uint8_t* ST_Util_BitsForBitmap(BitmapInfo* bitmap_info); -void ST_Util_FreeBitmap(BitmapInfo* bitmap_info); -void ST_Util_BitmapColorsFromPlaypal(BitmapInfo* bitmap_info); -uint8_t* ST_Util_LoadFont(const char* filename); -void ST_Util_FreeFont(uint8_t* font); -BitmapInfo* ST_Util_AllocTextBitmap(const uint8_t* font); -void ST_Util_DrawTextScreen(BitmapInfo* bitmap_info, const uint8_t* text_screen, const uint8_t* font); -void ST_Util_DrawChar(BitmapInfo* screen, const uint8_t* font, int x, int y, uint8_t charnum, uint8_t attrib); -void ST_Util_UpdateTextBlink(BitmapInfo* bitmap_info, const uint8_t* text_screen, const uint8_t* font, bool on); - diff --git a/src/st_stuff.cpp b/src/st_stuff.cpp index 59e28d5907c..b56eb25e8f1 100644 --- a/src/st_stuff.cpp +++ b/src/st_stuff.cpp @@ -35,9 +35,9 @@ #include "doomstat.h" #include "g_level.h" #include "g_levellocals.h" +#include "d_main.h" EXTERN_CVAR (Bool, ticker); -EXTERN_CVAR (Bool, noisedebug); EXTERN_CVAR (Int, am_cheat); EXTERN_CVAR (Int, cl_blockcheats); @@ -439,8 +439,8 @@ static bool CheatAddKey (cheatseq_t *cheat, uint8_t key, bool *eat) static bool Cht_Generic (cheatseq_t *cheat) { - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (cheat->Args[0]); + Net_WriteInt8 (DEM_GENERICCHEAT); + Net_WriteInt8 (cheat->Args[0]); return true; } @@ -456,7 +456,7 @@ static bool Cht_Music (cheatseq_t *cheat) static bool Cht_BeholdMenu (cheatseq_t *cheat) { - Printf ("%s\n", GStrings("STSTR_BEHOLD")); + Printf ("%s\n", GStrings.GetString("STSTR_BEHOLD")); return false; } @@ -518,13 +518,12 @@ static bool Cht_MyPos (cheatseq_t *cheat) static bool Cht_Ticker (cheatseq_t *cheat) { ticker = !ticker; - Printf ("%s\n", GStrings(ticker ? "TXT_CHEATTICKERON" : "TXT_CHEATTICKEROFF")); + Printf ("%s\n", GStrings.GetString(ticker ? "TXT_CHEATTICKERON" : "TXT_CHEATTICKEROFF")); return true; } static bool Cht_Sound (cheatseq_t *cheat) { - noisedebug = !noisedebug; - Printf ("%s\n", GStrings(noisedebug ? "TXT_CHEATSOUNDON" : "TXT_CHEATSOUNDOFF")); + AddCommandString("stat sounddebug"); return true; } diff --git a/src/st_stuff.h b/src/st_stuff.h index cb40988048b..fed2dc796de 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -5,8 +5,4 @@ struct event_t; bool ST_Responder(event_t* ev); -// [RH] Base blending values (for e.g. underwater) -extern int BaseBlendR, BaseBlendG, BaseBlendB; -extern float BaseBlendA; - #endif diff --git a/src/utility/basictypes.h b/src/utility/basictypes.h deleted file mode 100644 index 989b6a764b6..00000000000 --- a/src/utility/basictypes.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __BASICTYPES_H -#define __BASICTYPES_H - -#include -#include - -typedef uint32_t BITFIELD; -typedef int INTBOOL; - -// -// fixed point, 32bit as 16.16. -// -#define FRACBITS 16 -#define FRACUNIT (1< -char(&_ArraySizeHelper(T(&array)[N]))[N]; - -#define countof( array ) (sizeof( _ArraySizeHelper( array ) )) - - -#ifndef MAKE_ID -#ifndef __BIG_ENDIAN__ -#define MAKE_ID(a,b,c,d) ((uint32_t)((a)|((b)<<8)|((c)<<16)|((d)<<24))) -#else -#define MAKE_ID(a,b,c,d) ((uint32_t)((d)|((c)<<8)|((b)<<16)|((a)<<24))) -#endif -#endif - -#endif diff --git a/src/utility/cmdlib.cpp b/src/utility/cmdlib.cpp deleted file mode 100644 index d882d2caf98..00000000000 --- a/src/utility/cmdlib.cpp +++ /dev/null @@ -1,971 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1996 id Software -// Copyright 1999-2016 Randy Heit -// Copyright 2002-2016 Christoph Oelckers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// - -// cmdlib.c (mostly borrowed from the Q2 source) - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#include -#if !defined(__sun) -#include -#endif -#endif -#include "cmdlib.h" -#include "i_system.h" - -#include -#include -#include - -/* -progdir will hold the path up to the game directory, including the slash - - f:\quake\ - /raid/quake/ - -gamedir will hold progdir + the game directory (id1, id2, etc) - - */ - -FString progdir; - -//========================================================================== -// -// IsSeperator -// -// Returns true if the character is a path seperator. -// -//========================================================================== - -static inline bool IsSeperator (int c) -{ - if (c == '/') - return true; -#ifdef WIN32 - if (c == '\\' || c == ':') - return true; -#endif - return false; -} - -//========================================================================== -// -// FixPathSeperator -// -// Convert backslashes to forward slashes. -// -//========================================================================== - -void FixPathSeperator (char *path) -{ - while (*path) - { - if (*path == '\\') - *path = '/'; - path++; - } -} - -//========================================================================== -// -// copystring -// -// Replacement for strdup that uses new instead of malloc. -// -//========================================================================== - -char *copystring (const char *s) -{ - char *b; - if (s) - { - size_t len = strlen (s) + 1; - b = new char[len]; - memcpy (b, s, len); - } - else - { - b = new char[1]; - b[0] = '\0'; - } - return b; -} - -//========================================================================== -// -// ReplaceString -// -// Do not use in new code. -// -//========================================================================== - -void ReplaceString (char **ptr, const char *str) -{ - if (*ptr) - { - if (*ptr == str) - return; - delete[] *ptr; - } - *ptr = copystring (str); -} - -/* -============================================================================= - - MISC FUNCTIONS - -============================================================================= -*/ - - -//========================================================================== -// -// FileExists -// -// Returns true if the given path exists and is a readable file. -// -//========================================================================== - -bool FileExists (const char *filename) -{ - bool isdir; - bool res = DirEntryExists(filename, &isdir); - return res && !isdir; -} - -//========================================================================== -// -// DirExists -// -// Returns true if the given path exists and is a directory. -// -//========================================================================== - -bool DirExists(const char *filename) -{ - bool isdir; - bool res = DirEntryExists(filename, &isdir); - return res && isdir; -} - -//========================================================================== -// -// DirEntryExists -// -// Returns true if the given path exists, be it a directory or a file. -// -//========================================================================== - -bool DirEntryExists(const char *pathname, bool *isdir) -{ - if (isdir) *isdir = false; - if (pathname == NULL || *pathname == 0) - return false; - -#ifndef _WIN32 - struct stat info; - bool res = stat(pathname, &info) == 0; -#else - // Windows must use the wide version of stat to preserve non-standard paths. - auto wstr = WideString(pathname); - struct _stat64 info; - bool res = _wstat64(wstr.c_str(), &info) == 0; -#endif - if (isdir) *isdir = !!(info.st_mode & S_IFDIR); - return res; -} - -//========================================================================== -// -// DirEntryExists -// -// Returns true if the given path exists, be it a directory or a file. -// -//========================================================================== - -bool GetFileInfo(const char* pathname, size_t *size, time_t *time) -{ - if (pathname == NULL || *pathname == 0) - return false; - -#ifndef _WIN32 - struct stat info; - bool res = stat(pathname, &info) == 0; -#else - // Windows must use the wide version of stat to preserve non-standard paths. - auto wstr = WideString(pathname); - struct _stat64 info; - bool res = _wstat64(wstr.c_str(), &info) == 0; -#endif - if (!res || (info.st_mode & S_IFDIR)) return false; - if (size) *size = info.st_size; - if (time) *time = info.st_mtime; - return res; -} - -//========================================================================== -// -// DefaultExtension -- FString version -// -// Appends the extension to a pathname if it does not already have one. -// -//========================================================================== - -void DefaultExtension (FString &path, const char *extension) -{ - const char *src = &path[int(path.Len())-1]; - - while (src != &path[0] && !IsSeperator(*src)) - { - if (*src == '.') - return; // it has an extension - src--; - } - - path += extension; -} - - -//========================================================================== -// -// ExtractFilePath -// -// Returns the directory part of a pathname. -// -// FIXME: should include the slash, otherwise -// backing to an empty path will be wrong when appending a slash -// -//========================================================================== - -FString ExtractFilePath (const char *path) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && !IsSeperator(*(src-1))) - src--; - - return FString(path, src - path); -} - -//========================================================================== -// -// ExtractFileBase -// -// Returns the file part of a pathname, optionally including the extension. -// -//========================================================================== - -FString ExtractFileBase (const char *path, bool include_extension) -{ - const char *src, *dot; - - src = path + strlen(path) - 1; - - if (src >= path) - { - // back up until a / or the start - while (src != path && !IsSeperator(*(src-1))) - src--; - - // Check for files with drive specification but no path -#if defined(_WIN32) - if (src == path && src[0] != 0) - { - if (src[1] == ':') - src += 2; - } -#endif - - if (!include_extension) - { - dot = src; - while (*dot && *dot != '.') - { - dot++; - } - return FString(src, dot - src); - } - else - { - return FString(src); - } - } - return FString(); -} - - -//========================================================================== -// -// IsNum -// -// [RH] Returns true if the specified string is a valid decimal number -// -//========================================================================== - -bool IsNum (const char *str) -{ - while (*str) - { - if (((*str < '0') || (*str > '9')) && (*str != '-')) - { - return false; - } - str++; - } - return true; -} - -//========================================================================== -// -// CheckWildcards -// -// [RH] Checks if text matches the wildcard pattern using ? or * -// -//========================================================================== - -bool CheckWildcards (const char *pattern, const char *text) -{ - if (pattern == NULL || text == NULL) - return true; - - while (*pattern) - { - if (*pattern == '*') - { - char stop = tolower (*++pattern); - while (*text && tolower(*text) != stop) - { - text++; - } - if (*text && tolower(*text) == stop) - { - if (CheckWildcards (pattern, text++)) - { - return true; - } - pattern--; - } - } - else if (*pattern == '?' || tolower(*pattern) == tolower(*text)) - { - pattern++; - text++; - } - else - { - return false; - } - } - return (*pattern | *text) == 0; -} - -//========================================================================== -// -// FormatGUID -// -// [RH] Print a GUID to a text buffer using the standard format. -// -//========================================================================== - -void FormatGUID (char *buffer, size_t buffsize, const GUID &guid) -{ - snprintf (buffer, buffsize, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - (uint32_t)guid.Data1, guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], - guid.Data4[2], guid.Data4[3], - guid.Data4[4], guid.Data4[5], - guid.Data4[6], guid.Data4[7]); -} - -//========================================================================== -// -// myasctime -// -// [RH] Returns the current local time as ASCII, even if it's too early -// -//========================================================================== - -const char *myasctime () -{ - static char readabletime[50]; - time_t clock; - struct tm *lt; - - time (&clock); - lt = localtime (&clock); - if (lt != NULL) - { - strftime(readabletime, 50, "%F %T", lt); - return readabletime; - } - else - { - return "Unknown\n"; - } -} - -//========================================================================== -// -// CreatePath -// -// Creates a directory including all levels necessary -// -//========================================================================== -#ifdef _WIN32 -void DoCreatePath(const char *fn) -{ - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - _splitpath_s(fn, drive, sizeof drive, dir, sizeof dir, nullptr, 0, nullptr, 0); - - if ('\0' == *dir) - { - // Root/current/parent directory always exists - return; - } - - char path[_MAX_PATH]; - _makepath_s(path, sizeof path, drive, dir, nullptr, nullptr); - - if ('\0' == *path) - { - // No need to process empty relative path - return; - } - - // Remove trailing path separator(s) - for (size_t i = strlen(path); 0 != i; --i) - { - char& lastchar = path[i - 1]; - - if ('/' == lastchar || '\\' == lastchar) - { - lastchar = '\0'; - } - else - { - break; - } - } - - // Create all directories for given path - if ('\0' != *path) - { - DoCreatePath(path); -#ifdef _WIN32 - auto wpath = WideString(path); - _wmkdir(wpath.c_str()); -#else - _mkdir(path); -#endif - } -} - -void CreatePath(const char *fn) -{ - char c = fn[strlen(fn)-1]; - - if (c != '\\' && c != '/') - { - FString name(fn); - name += '/'; - DoCreatePath(name); - } - else - { - DoCreatePath(fn); - } -} -#else -void CreatePath(const char *fn) -{ - char *copy, *p; - - if (fn[0] == '/' && fn[1] == '\0') - { - return; - } - p = copy = strdup(fn); - do - { - p = strchr(p + 1, '/'); - if (p != NULL) - { - *p = '\0'; - } - if (!DirEntryExists(copy) && mkdir(copy, 0755) == -1) - { - // failed - free(copy); - return; - } - if (p != NULL) - { - *p = '/'; - } - } while (p); - free(copy); -} -#endif - -//========================================================================== -// -// strbin -- In-place version -// -// [RH] Replaces the escape sequences in a string with actual escaped characters. -// This operation is done in-place. The result is the new length of the string. -// -//========================================================================== - -int strbin (char *str) -{ - char *start = str; - char *p = str, c; - int i; - - while ( (c = *p++) ) { - if (c != '\\') { - *str++ = c; - } else { - switch (*p) { - case 'a': - *str++ = '\a'; - break; - case 'b': - *str++ = '\b'; - break; - case 'c': - *str++ = '\034'; // TEXTCOLOR_ESCAPE - break; - case 'f': - *str++ = '\f'; - break; - case 'n': - *str++ = '\n'; - break; - case 't': - *str++ = '\t'; - break; - case 'r': - *str++ = '\r'; - break; - case 'v': - *str++ = '\v'; - break; - case '?': - *str++ = '\?'; - break; - case '\n': - break; - case 'x': - case 'X': - c = 0; - for (i = 0; i < 2; i++) - { - p++; - if (*p >= '0' && *p <= '9') - c = (c << 4) + *p-'0'; - else if (*p >= 'a' && *p <= 'f') - c = (c << 4) + 10 + *p-'a'; - else if (*p >= 'A' && *p <= 'F') - c = (c << 4) + 10 + *p-'A'; - else - { - p--; - break; - } - } - *str++ = c; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - c = *p - '0'; - for (i = 0; i < 2; i++) - { - p++; - if (*p >= '0' && *p <= '7') - c = (c << 3) + *p - '0'; - else - { - p--; - break; - } - } - *str++ = c; - break; - default: - *str++ = *p; - break; - } - p++; - } - } - *str = 0; - return int(str - start); -} - -//========================================================================== -// -// strbin1 -- String-creating version -// -// [RH] Replaces the escape sequences in a string with actual escaped characters. -// The result is a new string. -// -//========================================================================== - -FString strbin1 (const char *start) -{ - FString result; - const char *p = start; - char c; - int i; - - while ( (c = *p++) ) { - if (c != '\\') { - result << c; - } else { - switch (*p) { - case 'a': - result << '\a'; - break; - case 'b': - result << '\b'; - break; - case 'c': - result << '\034'; // TEXTCOLOR_ESCAPE - break; - case 'f': - result << '\f'; - break; - case 'n': - result << '\n'; - break; - case 't': - result << '\t'; - break; - case 'r': - result << '\r'; - break; - case 'v': - result << '\v'; - break; - case '?': - result << '\?'; - break; - case '\n': - break; - case 'x': - case 'X': - c = 0; - for (i = 0; i < 2; i++) - { - p++; - if (*p >= '0' && *p <= '9') - c = (c << 4) + *p-'0'; - else if (*p >= 'a' && *p <= 'f') - c = (c << 4) + 10 + *p-'a'; - else if (*p >= 'A' && *p <= 'F') - c = (c << 4) + 10 + *p-'A'; - else - { - p--; - break; - } - } - result << c; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - c = *p - '0'; - for (i = 0; i < 2; i++) - { - p++; - if (*p >= '0' && *p <= '7') - c = (c << 3) + *p - '0'; - else - { - p--; - break; - } - } - result << c; - break; - default: - result << *p; - break; - } - p++; - } - } - return result; -} - -//========================================================================== -// -// ExpandEnvVars -// -// Expands environment variable references in a string. Intended primarily -// for use with IWAD search paths in config files. -// -//========================================================================== - -FString ExpandEnvVars(const char *searchpathstring) -{ - static const char envvarnamechars[] = - "01234567890" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "_" - "abcdefghijklmnopqrstuvwxyz"; - - if (searchpathstring == NULL) - return FString(""); - - const char *dollar = strchr(searchpathstring, '$'); - if (dollar == NULL) - { - return FString(searchpathstring); - } - - const char *nextchars = searchpathstring; - FString out = FString(searchpathstring, dollar - searchpathstring); - while ( (dollar != NULL) && (*nextchars != 0) ) - { - size_t length = strspn(dollar + 1, envvarnamechars); - if (length != 0) - { - FString varname = FString(dollar + 1, length); - if (stricmp(varname, "progdir") == 0) - { - out += progdir; - } - else - { - char *varvalue = getenv(varname); - if ( (varvalue != NULL) && (strlen(varvalue) != 0) ) - { - out += varvalue; - } - } - } - else - { - out += '$'; - } - nextchars = dollar + length + 1; - dollar = strchr(nextchars, '$'); - if (dollar != NULL) - { - out += FString(nextchars, dollar - nextchars); - } - } - if (*nextchars != 0) - { - out += nextchars; - } - return out; -} - -//========================================================================== -// -// NicePath -// -// Handles paths with leading ~ characters on Unix as well as environment -// variable substitution. On Windows, this is identical to ExpandEnvVars. -// -//========================================================================== - -FString NicePath(const char *path) -{ -#ifdef _WIN32 - return ExpandEnvVars(path); -#else - if (path == NULL || *path == '\0') - { - return FString(""); - } - if (*path != '~') - { - return ExpandEnvVars(path); - } - - passwd *pwstruct; - const char *slash; - - if (path[1] == '/' || path[1] == '\0') - { // Get my home directory - pwstruct = getpwuid(getuid()); - slash = path + 1; - } - else - { // Get somebody else's home directory - slash = strchr(path, '/'); - if (slash == NULL) - { - slash = path + strlen(path); - } - FString who(path, slash - path); - pwstruct = getpwnam(who); - } - if (pwstruct == NULL) - { - return ExpandEnvVars(path); - } - FString where(pwstruct->pw_dir); - if (*slash != '\0') - { - where += ExpandEnvVars(slash); - } - return where; -#endif -} - - -//========================================================================== -// -// ScanDirectory -// -//========================================================================== - -bool ScanDirectory(TArray &list, const char *dirpath) -{ - findstate_t find; - FString dirmatch; - - dirmatch << dirpath << "*"; - - auto handle = I_FindFirst(dirmatch.GetChars(), &find); - if (handle == ((void*)(-1))) - { - return false; - } - else - { - do - { - auto attr = I_FindAttr(&find); - if (attr & FA_HIDDEN) - { - // Skip hidden files and directories. (Prevents SVN bookkeeping - // info from being included.) - continue; - } - auto fn = I_FindName(&find); - - if (attr & FA_DIREC) - { - if (fn[0] == '.' && - (fn[1] == '\0' || - (fn[1] == '.' && fn[2] == '\0'))) - { - // Do not record . and .. directories. - continue; - } - - FFileList* fl = &list[list.Reserve(1)]; - fl->Filename << dirpath << fn; - fl->isDirectory = true; - FString newdir = fl->Filename; - newdir << "/"; - ScanDirectory(list, newdir); - } - else - { - FFileList* fl = &list[list.Reserve(1)]; - fl->Filename << dirpath << fn; - fl->isDirectory = false; - } - } - while (I_FindNext(handle, &find) == 0); - I_FindClose(handle); - } - return true; -} - - -//========================================================================== -// -// -// -//========================================================================== - -bool IsAbsPath(const char *name) -{ - if (IsSeperator(name[0])) return true; -#ifdef _WIN32 - /* [A-Za-z]: (for Windows) */ - if (isalpha(name[0]) && name[1] == ':') return true; -#endif /* _WIN32 */ - return 0; -} - -// -// M_ZlibError -// -FString M_ZLibError(int zerr) -{ - if (zerr >= 0) - { - return "OK"; - } - else if (zerr < -6) - { - FString out; - out.Format("%d", zerr); - return out; - } - else - { - static const char* errs[6] = - { - "Errno", - "Stream Error", - "Data Error", - "Memory Error", - "Buffer Error", - "Version Error" - }; - return errs[-zerr - 1]; - } -} diff --git a/src/utility/cmdlib.h b/src/utility/cmdlib.h deleted file mode 100644 index 823b07fde53..00000000000 --- a/src/utility/cmdlib.h +++ /dev/null @@ -1,78 +0,0 @@ -// cmdlib.h - -#ifndef __CMDLIB__ -#define __CMDLIB__ - - -#include -#include -#include -#include -#include -#include -#include -#include "zstring.h" - -#if !defined(GUID_DEFINED) -#define GUID_DEFINED -typedef struct _GUID -{ - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; -} GUID; -#endif - - -// the dec offsetof macro doesnt work very well... -#define myoffsetof(type,identifier) ((size_t)&((type *)alignof(type))->identifier - alignof(type)) - -bool FileExists (const char *filename); -bool DirExists(const char *filename); -bool DirEntryExists (const char *pathname, bool *isdir = nullptr); -bool GetFileInfo(const char* pathname, size_t* size, time_t* time); - -extern FString progdir; - -void FixPathSeperator (char *path); -static void inline FixPathSeperator (FString &path) { path.ReplaceChars('\\', '/'); } - -void DefaultExtension (FString &path, const char *extension); - -FString ExtractFilePath (const char *path); -FString ExtractFileBase (const char *path, bool keep_extension=false); - -struct FScriptPosition; -bool IsNum (const char *str); // [RH] added - -char *copystring(const char *s); -void ReplaceString (char **ptr, const char *str); - -bool CheckWildcards (const char *pattern, const char *text); - -void FormatGUID (char *buffer, size_t buffsize, const GUID &guid); - -const char *myasctime (); - -int strbin (char *str); -FString strbin1 (const char *start); - -void CreatePath(const char * fn); - -FString ExpandEnvVars(const char *searchpathstring); -FString NicePath(const char *path); - -struct FFileList -{ - FString Filename; - bool isDirectory; -}; - -bool ScanDirectory(TArray &list, const char *dirpath); -bool IsAbsPath(const char*); - -FString M_ZLibError(int zerrnum); - - -#endif diff --git a/src/utility/doomerrors.h b/src/utility/doomerrors.h deleted file mode 100644 index fc04ee0016c..00000000000 --- a/src/utility/doomerrors.h +++ /dev/null @@ -1,123 +0,0 @@ -/* -** doomerrors.h -** Contains error classes that can be thrown around -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __ERRORS_H__ -#define __ERRORS_H__ - -#include -#include -#include -#include -#include "doomtype.h" - -#define MAX_ERRORTEXT 1024 - -class CDoomError : public std::exception -{ -public: - CDoomError () - { - m_Message[0] = '\0'; - } - CDoomError (const char *message) - { - SetMessage (message); - } - void SetMessage (const char *message) - { - strncpy (m_Message, message, MAX_ERRORTEXT-1); - m_Message[MAX_ERRORTEXT-1] = '\0'; - } - void AppendMessage(const char *message) - { - size_t len = strlen(m_Message); - strncpy(m_Message + len, message, MAX_ERRORTEXT - 1 - len); - m_Message[MAX_ERRORTEXT - 1] = '\0'; - } - const char *GetMessage (void) const - { - if (m_Message[0] != '\0') - return (const char *)m_Message; - else - return NULL; - } - char const *what() const noexcept override - { - return m_Message; - } - - -protected: - char m_Message[MAX_ERRORTEXT]; -}; - - -class CRecoverableError : public CDoomError -{ -public: - CRecoverableError() : CDoomError() {} - CRecoverableError(const char *message) : CDoomError(message) {} -}; - -class CFatalError : public CDoomError -{ -public: - CFatalError() : CDoomError() {} - CFatalError(const char *message) : CDoomError(message) {} -}; - -class CVulkanError : public CDoomError -{ -public: - CVulkanError() : CDoomError() {} - CVulkanError(const char *message) : CDoomError(message) {} -}; - -class CExitEvent : public std::exception -{ - int m_reason; -public: - CExitEvent(int reason) { m_reason = reason; } - char const *what() const noexcept override - { - return "The game wants to exit"; - } - int Reason() const { return m_reason; } -}; - -void I_ShowFatalError(const char *message); -void I_Error (const char *error, ...) GCCPRINTF(1,2); -void I_FatalError (const char *error, ...) GCCPRINTF(1,2); - -#endif //__ERRORS_H__ diff --git a/src/utility/filereadermusicinterface.h b/src/utility/filereadermusicinterface.h deleted file mode 100644 index 70fc3b1071a..00000000000 --- a/src/utility/filereadermusicinterface.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include "files.h" - - -inline ZMusicCustomReader *GetMusicReader(FileReader& fr) -{ - auto zcr = new ZMusicCustomReader; - - zcr->handle = fr.GetInterface(); - zcr->gets = [](ZMusicCustomReader* zr, char* buff, int n) { return reinterpret_cast(zr->handle)->Gets(buff, n); }; - zcr->read = [](ZMusicCustomReader* zr, void* buff, int32_t size) { return reinterpret_cast(zr->handle)->Read(buff, (long)size); }; - zcr->seek = [](ZMusicCustomReader* zr, long offset, int whence) { return reinterpret_cast(zr->handle)->Seek(offset, whence); }; - zcr->tell = [](ZMusicCustomReader* zr) { return reinterpret_cast(zr->handle)->Tell(); }; - zcr->close = [](ZMusicCustomReader* zr) - { - delete reinterpret_cast(zr->handle); - delete zr; - }; - return zcr; -} \ No newline at end of file diff --git a/src/utility/files.cpp b/src/utility/files.cpp deleted file mode 100644 index e5a17dd4f45..00000000000 --- a/src/utility/files.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* -** files.cpp -** Implements classes for reading from files or memory blocks -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** Copyright 2005-2008 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "files.h" -#include "templates.h" - - -FILE *myfopen(const char *filename, const char *flags) -{ -#ifndef _WIN32 - return fopen(filename, flags); -#else - auto widename = WideString(filename); - auto wideflags = WideString(flags); - return _wfopen(widename.c_str(), wideflags.c_str()); -#endif -} - - -//========================================================================== -// -// StdFileReader -// -// reads data from an stdio FILE* or part of it. -// -//========================================================================== - -class StdFileReader : public FileReaderInterface -{ - FILE *File = nullptr; - long StartPos = 0; - long FilePos = 0; - -public: - StdFileReader() - {} - - ~StdFileReader() - { - if (File != nullptr) - { - fclose(File); - } - File = nullptr; - } - - bool Open(const char *filename, long startpos = 0, long len = -1) - { - File = myfopen(filename, "rb"); - if (File == nullptr) return false; - FilePos = startpos; - StartPos = startpos; - Length = CalcFileLen(); - if (len >= 0 && len < Length) Length = len; - if (startpos > 0) Seek(0, SEEK_SET); - return true; - } - - long Tell() const override - { - return FilePos - StartPos; - } - - long Seek(long offset, int origin) override - { - if (origin == SEEK_SET) - { - offset += StartPos; - } - else if (origin == SEEK_CUR) - { - offset += FilePos; - } - else if (origin == SEEK_END) - { - offset += StartPos + Length; - } - if (offset < StartPos || offset > StartPos + Length) return -1; // out of scope - - if (0 == fseek(File, offset, SEEK_SET)) - { - FilePos = offset; - return 0; - } - return -1; - } - - long Read(void *buffer, long len) override - { - assert(len >= 0); - if (len <= 0) return 0; - if (FilePos + len > StartPos + Length) - { - len = Length - FilePos + StartPos; - } - len = (long)fread(buffer, 1, len, File); - FilePos += len; - return len; - } - - char *Gets(char *strbuf, int len) override - { - if (len <= 0 || FilePos >= StartPos + Length) return NULL; - char *p = fgets(strbuf, len, File); - if (p != NULL) - { - int old = FilePos; - FilePos = ftell(File); - if (FilePos - StartPos > Length) - { - strbuf[Length - old + StartPos] = 0; - } - } - return p; - } - -private: - long CalcFileLen() const - { - long endpos; - - fseek(File, 0, SEEK_END); - endpos = ftell(File); - fseek(File, 0, SEEK_SET); - return endpos; - } -}; - -//========================================================================== -// -// FileReaderRedirect -// -// like the above, but uses another File reader as its backing data -// -//========================================================================== - -class FileReaderRedirect : public FileReaderInterface -{ - FileReader *mReader = nullptr; - long StartPos = 0; - long FilePos = 0; - -public: - FileReaderRedirect(FileReader &parent, long start, long length) - { - mReader = &parent; - FilePos = start; - StartPos = start; - Length = length; - Seek(0, SEEK_SET); - } - - virtual long Tell() const override - { - return FilePos - StartPos; - } - - virtual long Seek(long offset, int origin) - { - switch (origin) - { - case SEEK_SET: - offset += StartPos; - break; - - case SEEK_END: - offset += StartPos + Length; - break; - - case SEEK_CUR: - offset += (long)mReader->Tell(); - break; - } - if (offset < StartPos || offset > StartPos + Length) return -1; // out of scope - if (mReader->Seek(offset, FileReader::SeekSet) == 0) - { - FilePos = offset; - return 0; - } - return -1; - } - - virtual long Read(void *buffer, long len) - { - assert(len >= 0); - if (len <= 0) return 0; - if (FilePos + len > StartPos + Length) - { - len = Length - FilePos + StartPos; - } - len = (long)mReader->Read(buffer, len); - FilePos += len; - return len; - } - - virtual char *Gets(char *strbuf, int len) - { - if (len <= 0 || FilePos >= StartPos + Length) return NULL; - char *p = mReader->Gets(strbuf, len); - if (p != NULL) - { - int old = FilePos; - FilePos = (long)mReader->Tell(); - if (FilePos - StartPos > Length) - { - strbuf[Length - old + StartPos] = 0; - } - } - return p; - } - -}; - -//========================================================================== -// -// MemoryReader -// -// reads data from a block of memory -// -//========================================================================== - -long MemoryReader::Tell() const -{ - return FilePos; -} - -long MemoryReader::Seek(long offset, int origin) -{ - switch (origin) - { - case SEEK_CUR: - offset += FilePos; - break; - - case SEEK_END: - offset += Length; - break; - - } - if (offset < 0 || offset > Length) return -1; - FilePos = clamp(offset, 0, Length); - return 0; -} - -long MemoryReader::Read(void *buffer, long len) -{ - if (len>Length - FilePos) len = Length - FilePos; - if (len<0) len = 0; - memcpy(buffer, bufptr + FilePos, len); - FilePos += len; - return len; -} - -char *MemoryReader::Gets(char *strbuf, int len) -{ - if (len>Length - FilePos) len = Length - FilePos; - if (len <= 0) return NULL; - - char *p = strbuf; - while (len > 1) - { - if (bufptr[FilePos] == 0) - { - FilePos++; - break; - } - if (bufptr[FilePos] != '\r') - { - *p++ = bufptr[FilePos]; - len--; - if (bufptr[FilePos] == '\n') - { - FilePos++; - break; - } - } - FilePos++; - } - if (p == strbuf) return NULL; - *p++ = 0; - return strbuf; -} - -//========================================================================== -// -// MemoryArrayReader -// -// reads data from an array of memory -// -//========================================================================== - -class MemoryArrayReader : public MemoryReader -{ - TArray buf; - -public: - MemoryArrayReader(const char *buffer, long length) - { - if (length > 0) - { - buf.Resize(length); - memcpy(&buf[0], buffer, length); - } - UpdateBuffer(); - } - - TArray &GetArray() { return buf; } - - void UpdateBuffer() - { - bufptr = (const char*)&buf[0]; - FilePos = 0; - Length = buf.Size(); - } -}; - - - -//========================================================================== -// -// FileReader -// -// this wraps the different reader types in an object with value semantics. -// -//========================================================================== - -bool FileReader::OpenFile(const char *filename, FileReader::Size start, FileReader::Size length) -{ - auto reader = new StdFileReader; - if (!reader->Open(filename, (long)start, (long)length)) - { - delete reader; - return false; - } - Close(); - mReader = reader; - return true; -} - -bool FileReader::OpenFilePart(FileReader &parent, FileReader::Size start, FileReader::Size length) -{ - auto reader = new FileReaderRedirect(parent, (long)start, (long)length); - Close(); - mReader = reader; - return true; -} - -bool FileReader::OpenMemory(const void *mem, FileReader::Size length) -{ - Close(); - mReader = new MemoryReader((const char *)mem, (long)length); - return true; -} - -bool FileReader::OpenMemoryArray(const void *mem, FileReader::Size length) -{ - Close(); - mReader = new MemoryArrayReader((const char *)mem, (long)length); - return true; -} - -bool FileReader::OpenMemoryArray(std::function&)> getter) -{ - auto reader = new MemoryArrayReader(nullptr, 0); - if (getter(reader->GetArray())) - { - Close(); - reader->UpdateBuffer(); - mReader = reader; - return true; - } - else - { - // This will keep the old buffer, if one existed - delete reader; - return false; - } -} - - -//========================================================================== -// -// FileWriter (the motivation here is to have a buffer writing subclass) -// -//========================================================================== - -bool FileWriter::OpenDirect(const char *filename) -{ - File = myfopen(filename, "wb"); - return (File != NULL); -} - -FileWriter *FileWriter::Open(const char *filename) -{ - FileWriter *fwrit = new FileWriter(); - if (fwrit->OpenDirect(filename)) - { - return fwrit; - } - delete fwrit; - return NULL; -} - -size_t FileWriter::Write(const void *buffer, size_t len) -{ - if (File != NULL) - { - return fwrite(buffer, 1, len, File); - } - else - { - return 0; - } -} - -long FileWriter::Tell() -{ - if (File != NULL) - { - return ftell(File); - } - else - { - return 0; - } -} - -long FileWriter::Seek(long offset, int mode) -{ - if (File != NULL) - { - return fseek(File, offset, mode); - } - else - { - return 0; - } -} - -size_t FileWriter::Printf(const char *fmt, ...) -{ - va_list ap; - FString out; - - va_start(ap, fmt); - out.VFormat(fmt, ap); - va_end(ap); - return Write(out.GetChars(), out.Len()); -} - -size_t BufferWriter::Write(const void *buffer, size_t len) -{ - unsigned int ofs = mBuffer.Reserve((unsigned)len); - memcpy(&mBuffer[ofs], buffer, len); - return len; -} diff --git a/src/utility/files.h b/src/utility/files.h deleted file mode 100644 index ec4b15223d7..00000000000 --- a/src/utility/files.h +++ /dev/null @@ -1,360 +0,0 @@ -/* -** files.h -** Implements classes for reading from files or memory blocks -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** Copyright 2005-2008 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef FILES_H -#define FILES_H - -#include -#include -#include -#include -#include "basictypes.h" -#include "m_swap.h" -#include "tarray.h" - -// Zip compression methods, extended by some internal types to be passed to OpenDecompressor -enum -{ - METHOD_STORED = 0, - METHOD_SHRINK = 1, - METHOD_IMPLODE = 6, - METHOD_DEFLATE = 8, - METHOD_BZIP2 = 12, - METHOD_LZMA = 14, - METHOD_PPMD = 98, - METHOD_LZSS = 1337, // not used in Zips - this is for Console Doom compression - METHOD_ZLIB = 1338, // Zlib stream with header, used by compressed nodes. - METHOD_TRANSFEROWNER = 0x8000, -}; - -class FileReader; - -class FileReaderInterface -{ -public: - long Length = -1; - virtual ~FileReaderInterface() {} - virtual long Tell () const = 0; - virtual long Seek (long offset, int origin) = 0; - virtual long Read (void *buffer, long len) = 0; - virtual char *Gets(char *strbuf, int len) = 0; - virtual const char *GetBuffer() const { return nullptr; } - long GetLength () const { return Length; } -}; - -class MemoryReader : public FileReaderInterface -{ -protected: - const char * bufptr = nullptr; - long FilePos = 0; - - MemoryReader() - {} - -public: - MemoryReader(const char *buffer, long length) - { - bufptr = buffer; - Length = length; - FilePos = 0; - } - - long Tell() const override; - long Seek(long offset, int origin) override; - long Read(void *buffer, long len) override; - char *Gets(char *strbuf, int len) override; - virtual const char *GetBuffer() const override { return bufptr; } -}; - - -struct FResourceLump; - -class FileReader -{ - friend struct FResourceLump; // needs access to the private constructor. - - FileReaderInterface *mReader = nullptr; - - FileReader(const FileReader &r) = delete; - FileReader &operator=(const FileReader &r) = delete; - -public: - - explicit FileReader(FileReaderInterface *r) - { - mReader = r; - } - - enum ESeek - { - SeekSet = SEEK_SET, - SeekCur = SEEK_CUR, - SeekEnd = SEEK_END - }; - - typedef ptrdiff_t Size; // let's not use 'long' here. - - FileReader() {} - - FileReader(FileReader &&r) - { - mReader = r.mReader; - r.mReader = nullptr; - } - - FileReader& operator =(FileReader &&r) - { - Close(); - mReader = r.mReader; - r.mReader = nullptr; - return *this; - } - - // This is for wrapping the actual reader for custom access where a managed FileReader won't work. - FileReaderInterface* GetInterface() - { - auto i = mReader; - mReader = nullptr; - return i; - } - - - ~FileReader() - { - Close(); - } - - bool isOpen() const - { - return mReader != nullptr; - } - - void Close() - { - if (mReader != nullptr) delete mReader; - mReader = nullptr; - } - - bool OpenFile(const char *filename, Size start = 0, Size length = -1); - bool OpenFilePart(FileReader &parent, Size start, Size length); - bool OpenMemory(const void *mem, Size length); // read directly from the buffer - bool OpenMemoryArray(const void *mem, Size length); // read from a copy of the buffer. - bool OpenMemoryArray(std::function&)> getter); // read contents to a buffer and return a reader to it - bool OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, const std::function& cb); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used. - - Size Tell() const - { - return mReader->Tell(); - } - - Size Seek(Size offset, ESeek origin) - { - return mReader->Seek((long)offset, origin); - } - - Size Read(void *buffer, Size len) - { - return mReader->Read(buffer, (long)len); - } - - TArray Read(size_t len) - { - TArray buffer((int)len, true); - Size length = mReader->Read(&buffer[0], (long)len); - buffer.Clamp((int)length); - return buffer; - } - - TArray Read() - { - TArray buffer(mReader->Length, true); - Size length = mReader->Read(&buffer[0], mReader->Length); - if (length < mReader->Length) buffer.Clear(); - return buffer; - } - - TArray ReadPadded(int padding) - { - TArray buffer(mReader->Length + padding, true); - Size length = mReader->Read(&buffer[0], mReader->Length); - if (length < mReader->Length) buffer.Clear(); - else memset(buffer.Data() + mReader->Length, 0, padding); - return buffer; - } - - char *Gets(char *strbuf, Size len) - { - return mReader->Gets(strbuf, (int)len); - } - - const char *GetBuffer() - { - return mReader->GetBuffer(); - } - - Size GetLength() const - { - return mReader->GetLength(); - } - - uint8_t ReadUInt8() - { - uint8_t v = 0; - Read(&v, 1); - return v; - } - - int8_t ReadInt8() - { - int8_t v = 0; - Read(&v, 1); - return v; - } - - uint16_t ReadUInt16() - { - uint16_t v = 0; - Read(&v, 2); - return LittleShort(v); - } - - int16_t ReadInt16() - { - uint16_t v = 0; - Read(&v, 2); - return LittleShort(v); - } - - int16_t ReadInt16BE() - { - uint16_t v = 0; - Read(&v, 2); - return BigShort(v); - } - - uint32_t ReadUInt32() - { - uint32_t v = 0; - Read(&v, 4); - return LittleLong(v); - } - - int32_t ReadInt32() - { - uint32_t v = 0; - Read(&v, 4); - return LittleLong(v); - } - - uint32_t ReadUInt32BE() - { - uint32_t v = 0; - Read(&v, 4); - return BigLong(v); - } - - int32_t ReadInt32BE() - { - uint32_t v = 0; - Read(&v, 4); - return BigLong(v); - } - - - friend class FWadCollection; -}; - -class DecompressorBase : public FileReaderInterface -{ - std::function ErrorCallback = nullptr; -public: - // These do not work but need to be defined to satisfy the FileReaderInterface. - // They will just error out when called. - long Tell() const override; - long Seek(long offset, int origin) override; - char *Gets(char *strbuf, int len) override; - void DecompressionError(const char* error, ...) const; - void SetErrorCallback(const std::function& cb) - { - ErrorCallback = cb; - } -}; - - - - -class FileWriter -{ -protected: - bool OpenDirect(const char *filename); - - FileWriter() - { - File = NULL; - } -public: - virtual ~FileWriter() - { - if (File != NULL) fclose(File); - } - - static FileWriter *Open(const char *filename); - - virtual size_t Write(const void *buffer, size_t len); - virtual long Tell(); - virtual long Seek(long offset, int mode); - size_t Printf(const char *fmt, ...) GCCPRINTF(2,3); - -protected: - - FILE *File; - -protected: - bool CloseOnDestruct; -}; - -class BufferWriter : public FileWriter -{ -protected: - TArray mBuffer; -public: - - BufferWriter() {} - virtual size_t Write(const void *buffer, size_t len) override; - TArray *GetBuffer() { return &mBuffer; } -}; - - -#endif diff --git a/src/utility/files_decompress.cpp b/src/utility/files_decompress.cpp deleted file mode 100644 index 03be66b7aed..00000000000 --- a/src/utility/files_decompress.cpp +++ /dev/null @@ -1,638 +0,0 @@ -/* -** files.cpp -** Implements classes for reading from files or memory blocks -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** Copyright 2005-2008 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// This also pulls in windows.h -#include "LzmaDec.h" -#include -#include - -#include "files.h" -#include "templates.h" -#include "cmdlib.h" - - -//========================================================================== -// -// I_Error -// -// Throw an error that will send us to the console if we are far enough -// along in the startup process. -// -//========================================================================== - -void DecompressorBase::DecompressionError(const char *error, ...) const -{ - const int MAX_ERRORTEXT = 300; - va_list argptr; - char errortext[MAX_ERRORTEXT]; - - va_start(argptr, error); - vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); - va_end(argptr); - - if (ErrorCallback != nullptr) ErrorCallback(errortext); - else throw std::runtime_error(errortext); -} - -long DecompressorBase::Tell () const -{ - DecompressionError("Cannot get position of decompressor stream"); - return 0; -} -long DecompressorBase::Seek (long offset, int origin) -{ - DecompressionError("Cannot seek in decompressor stream"); - return 0; -} -char *DecompressorBase::Gets(char *strbuf, int len) -{ - DecompressionError("Cannot use Gets on decompressor stream"); - return nullptr; -} - -//========================================================================== -// -// DecompressorZ -// -// The zlib wrapper -// reads data from a ZLib compressed stream -// -//========================================================================== - -class DecompressorZ : public DecompressorBase -{ - enum { BUFF_SIZE = 4096 }; - - FileReader &File; - bool SawEOF; - z_stream Stream; - uint8_t InBuff[BUFF_SIZE]; - -public: - DecompressorZ (FileReader &file, bool zip, const std::function& cb) - : File(file), SawEOF(false) - { - int err; - - SetErrorCallback(cb); - FillBuffer (); - - Stream.zalloc = Z_NULL; - Stream.zfree = Z_NULL; - - if (!zip) err = inflateInit (&Stream); - else err = inflateInit2 (&Stream, -MAX_WBITS); - - if (err != Z_OK) - { - DecompressionError ("DecompressorZ: inflateInit failed: %s\n", M_ZLibError(err).GetChars()); - } - } - - ~DecompressorZ () - { - inflateEnd (&Stream); - } - - long Read (void *buffer, long len) override - { - int err; - - Stream.next_out = (Bytef *)buffer; - Stream.avail_out = len; - - do - { - err = inflate (&Stream, Z_SYNC_FLUSH); - if (Stream.avail_in == 0 && !SawEOF) - { - FillBuffer (); - } - } while (err == Z_OK && Stream.avail_out != 0); - - if (err != Z_OK && err != Z_STREAM_END) - { - DecompressionError ("Corrupt zlib stream"); - } - - if (Stream.avail_out != 0) - { - DecompressionError ("Ran out of data in zlib stream"); - } - - return len - Stream.avail_out; - } - - void FillBuffer () - { - auto numread = File.Read (InBuff, BUFF_SIZE); - - if (numread < BUFF_SIZE) - { - SawEOF = true; - } - Stream.next_in = InBuff; - Stream.avail_in = (uInt)numread; - } -}; - - -//========================================================================== -// -// DecompressorZ -// -// The bzip2 wrapper -// reads data from a libbzip2 compressed stream -// -//========================================================================== - -class DecompressorBZ2; -static DecompressorBZ2 * stupidGlobal; // Why does that dumb global error callback not pass the decompressor state? - // Thanks to that brain-dead interface we have to use a global variable to get the error to the proper handler. - -class DecompressorBZ2 : public DecompressorBase -{ - enum { BUFF_SIZE = 4096 }; - - FileReader &File; - bool SawEOF; - bz_stream Stream; - uint8_t InBuff[BUFF_SIZE]; - -public: - DecompressorBZ2 (FileReader &file, const std::function& cb) - : File(file), SawEOF(false) - { - int err; - - SetErrorCallback(cb); - stupidGlobal = this; - FillBuffer (); - - Stream.bzalloc = NULL; - Stream.bzfree = NULL; - Stream.opaque = NULL; - - err = BZ2_bzDecompressInit(&Stream, 0, 0); - - if (err != BZ_OK) - { - DecompressionError ("DecompressorBZ2: bzDecompressInit failed: %d\n", err); - } - } - - ~DecompressorBZ2 () - { - stupidGlobal = this; - BZ2_bzDecompressEnd (&Stream); - } - - long Read (void *buffer, long len) override - { - int err; - - stupidGlobal = this; - Stream.next_out = (char *)buffer; - Stream.avail_out = len; - - do - { - err = BZ2_bzDecompress(&Stream); - if (Stream.avail_in == 0 && !SawEOF) - { - FillBuffer (); - } - } while (err == BZ_OK && Stream.avail_out != 0); - - if (err != BZ_OK && err != BZ_STREAM_END) - { - DecompressionError ("Corrupt bzip2 stream"); - } - - if (Stream.avail_out != 0) - { - DecompressionError ("Ran out of data in bzip2 stream"); - } - - return len - Stream.avail_out; - } - - void FillBuffer () - { - auto numread = File.Read(InBuff, BUFF_SIZE); - - if (numread < BUFF_SIZE) - { - SawEOF = true; - } - Stream.next_in = (char *)InBuff; - Stream.avail_in = (unsigned)numread; - } - -}; - -//========================================================================== -// -// bz_internal_error -// -// libbzip2 wants this, since we build it with BZ_NO_STDIO set. -// -//========================================================================== - -extern "C" void bz_internal_error (int errcode) -{ - if (stupidGlobal) stupidGlobal->DecompressionError("libbzip2: internal error number %d\n", errcode); - else std::terminate(); -} - -//========================================================================== -// -// DecompressorLZMA -// -// The lzma wrapper -// reads data from a LZMA compressed stream -// -//========================================================================== - -static void *SzAlloc(ISzAllocPtr, size_t size) { return malloc(size); } -static void SzFree(ISzAllocPtr, void *address) { free(address); } -ISzAlloc g_Alloc = { SzAlloc, SzFree }; - -// Wraps around a Decompressor to decompress a lzma stream -class DecompressorLZMA : public DecompressorBase -{ - enum { BUFF_SIZE = 4096 }; - - FileReader &File; - bool SawEOF; - CLzmaDec Stream; - size_t Size; - size_t InPos, InSize; - size_t OutProcessed; - uint8_t InBuff[BUFF_SIZE]; - -public: - - DecompressorLZMA (FileReader &file, size_t uncompressed_size, const std::function& cb) - : File(file), SawEOF(false) - { - uint8_t header[4 + LZMA_PROPS_SIZE]; - int err; - SetErrorCallback(cb); - - Size = uncompressed_size; - OutProcessed = 0; - - // Read zip LZMA properties header - if (File.Read(header, sizeof(header)) < (long)sizeof(header)) - { - DecompressionError("DecompressorLZMA: File too short\n"); - } - if (header[2] + header[3] * 256 != LZMA_PROPS_SIZE) - { - DecompressionError("DecompressorLZMA: LZMA props size is %d (expected %d)\n", - header[2] + header[3] * 256, LZMA_PROPS_SIZE); - } - - FillBuffer(); - - LzmaDec_Construct(&Stream); - err = LzmaDec_Allocate(&Stream, header + 4, LZMA_PROPS_SIZE, &g_Alloc); - - if (err != SZ_OK) - { - DecompressionError("DecompressorLZMA: LzmaDec_Allocate failed: %d\n", err); - } - - LzmaDec_Init(&Stream); - } - - ~DecompressorLZMA () - { - LzmaDec_Free(&Stream, &g_Alloc); - } - - long Read (void *buffer, long len) override - { - int err; - Byte *next_out = (Byte *)buffer; - - do - { - ELzmaFinishMode finish_mode = LZMA_FINISH_ANY; - ELzmaStatus status; - size_t out_processed = len; - size_t in_processed = InSize; - - err = LzmaDec_DecodeToBuf(&Stream, next_out, &out_processed, InBuff + InPos, &in_processed, finish_mode, &status); - InPos += in_processed; - InSize -= in_processed; - next_out += out_processed; - len = (long)(len - out_processed); - if (err != SZ_OK) - { - DecompressionError ("Corrupt LZMA stream"); - } - if (in_processed == 0 && out_processed == 0) - { - if (status != LZMA_STATUS_FINISHED_WITH_MARK) - { - DecompressionError ("Corrupt LZMA stream"); - } - } - if (InSize == 0 && !SawEOF) - { - FillBuffer (); - } - } while (err == SZ_OK && len != 0); - - if (err != Z_OK && err != Z_STREAM_END) - { - DecompressionError ("Corrupt LZMA stream"); - } - - if (len != 0) - { - DecompressionError ("Ran out of data in LZMA stream"); - } - - return (long)(next_out - (Byte *)buffer); - } - - void FillBuffer () - { - auto numread = File.Read(InBuff, BUFF_SIZE); - - if (numread < BUFF_SIZE) - { - SawEOF = true; - } - InPos = 0; - InSize = numread; - } - -}; - -//========================================================================== -// -// Console Doom LZSS wrapper. -// -//========================================================================== - -class DecompressorLZSS : public DecompressorBase -{ - enum { BUFF_SIZE = 4096, WINDOW_SIZE = 4096, INTERNAL_BUFFER_SIZE = 128 }; - - FileReader &File; - bool SawEOF; - uint8_t InBuff[BUFF_SIZE]; - - enum StreamState - { - STREAM_EMPTY, - STREAM_BITS, - STREAM_FLUSH, - STREAM_FINAL - }; - struct - { - StreamState State; - - uint8_t *In; - unsigned int AvailIn; - unsigned int InternalOut; - - uint8_t CFlags, Bits; - - uint8_t Window[WINDOW_SIZE+INTERNAL_BUFFER_SIZE]; - const uint8_t *WindowData; - uint8_t *InternalBuffer; - } Stream; - - void FillBuffer() - { - if(Stream.AvailIn) - memmove(InBuff, Stream.In, Stream.AvailIn); - - auto numread = File.Read(InBuff+Stream.AvailIn, BUFF_SIZE-Stream.AvailIn); - - if (numread < BUFF_SIZE) - { - SawEOF = true; - } - Stream.In = InBuff; - Stream.AvailIn = (unsigned)numread+Stream.AvailIn; - } - - // Reads a flag byte. - void PrepareBlocks() - { - assert(Stream.InternalBuffer == Stream.WindowData); - Stream.CFlags = *Stream.In++; - --Stream.AvailIn; - Stream.Bits = 0xFF; - Stream.State = STREAM_BITS; - } - - // Reads the next chunk in the block. Returns true if successful and - // returns false if it ran out of input data. - bool UncompressBlock() - { - if(Stream.CFlags & 1) - { - // Check to see if we have enough input - if(Stream.AvailIn < 2) - return false; - Stream.AvailIn -= 2; - - uint16_t pos = BigShort(*(uint16_t*)Stream.In); - uint8_t len = (pos & 0xF)+1; - pos >>= 4; - Stream.In += 2; - if(len == 1) - { - // We've reached the end of the stream. - Stream.State = STREAM_FINAL; - return true; - } - - const uint8_t* copyStart = Stream.InternalBuffer-pos-1; - - // Complete overlap: Single byte repeated - if(pos == 0) - memset(Stream.InternalBuffer, *copyStart, len); - // No overlap: One copy - else if(pos >= len) - memcpy(Stream.InternalBuffer, copyStart, len); - else - { - // Partial overlap: Copy in 2 or 3 chunks. - do - { - unsigned int copy = MIN(len, pos+1); - memcpy(Stream.InternalBuffer, copyStart, copy); - Stream.InternalBuffer += copy; - Stream.InternalOut += copy; - len -= copy; - pos += copy; // Increase our position since we can copy twice as much the next round. - } - while(len); - } - - Stream.InternalOut += len; - Stream.InternalBuffer += len; - } - else - { - // Uncompressed byte. - *Stream.InternalBuffer++ = *Stream.In++; - --Stream.AvailIn; - ++Stream.InternalOut; - } - - Stream.CFlags >>= 1; - Stream.Bits >>= 1; - - // If we're done with this block, flush the output - if(Stream.Bits == 0) - Stream.State = STREAM_FLUSH; - - return true; - } - -public: - DecompressorLZSS(FileReader &file, const std::function& cb) : File(file), SawEOF(false) - { - SetErrorCallback(cb); - Stream.State = STREAM_EMPTY; - Stream.WindowData = Stream.InternalBuffer = Stream.Window+WINDOW_SIZE; - Stream.InternalOut = 0; - Stream.AvailIn = 0; - - FillBuffer(); - } - - ~DecompressorLZSS() - { - } - - long Read(void *buffer, long len) override - { - - uint8_t *Out = (uint8_t*)buffer; - long AvailOut = len; - - do - { - while(Stream.AvailIn) - { - if(Stream.State == STREAM_EMPTY) - PrepareBlocks(); - else if(Stream.State == STREAM_BITS && !UncompressBlock()) - break; - else - break; - } - - unsigned int copy = MIN(Stream.InternalOut, AvailOut); - if(copy > 0) - { - memcpy(Out, Stream.WindowData, copy); - Out += copy; - AvailOut -= copy; - - // Slide our window - memmove(Stream.Window, Stream.Window+copy, WINDOW_SIZE+INTERNAL_BUFFER_SIZE-copy); - Stream.InternalBuffer -= copy; - Stream.InternalOut -= copy; - } - - if(Stream.State == STREAM_FINAL) - break; - - if(Stream.InternalOut == 0 && Stream.State == STREAM_FLUSH) - Stream.State = STREAM_EMPTY; - - if(Stream.AvailIn < 2) - FillBuffer(); - } - while(AvailOut && Stream.State != STREAM_FINAL); - - assert(AvailOut == 0); - return (long)(Out - (uint8_t*)buffer); - } -}; - - -bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, const std::function& cb) -{ - DecompressorBase *dec = nullptr; - switch (method) - { - case METHOD_DEFLATE: - case METHOD_ZLIB: - dec = new DecompressorZ(parent, method == METHOD_DEFLATE, cb); - break; - - case METHOD_BZIP2: - dec = new DecompressorBZ2(parent, cb); - break; - - case METHOD_LZMA: - dec = new DecompressorLZMA(parent, length, cb); - break; - - case METHOD_LZSS: - dec = new DecompressorLZSS(parent, cb); - break; - - // todo: METHOD_IMPLODE, METHOD_SHRINK - default: - return false; - } - dec->Length = (long)length; - if (!seekable) - { - Close(); - mReader = dec; - return true; - } - else - { - // todo: create a wrapper. for now this fails - delete dec; - return false; - } -} diff --git a/src/utility/i_time.cpp b/src/utility/i_time.cpp deleted file mode 100644 index a4177e191cc..00000000000 --- a/src/utility/i_time.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* -** i_time.cpp -** Implements the timer -** -**--------------------------------------------------------------------------- -** Copyright 1998-2016 Randy Heit -** Copyright 2017 Magnus Norddahl -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#include "i_time.h" - -//========================================================================== -// -// Tick time functions -// -//========================================================================== - -static uint64_t FirstFrameStartTime; -static uint64_t CurrentFrameStartTime; -static uint64_t FreezeTime; -int GameTicRate; - -double TimeScale = 1.0; - -static uint64_t GetClockTimeNS() -{ - using namespace std::chrono; - return (uint64_t)((duration_cast(steady_clock::now().time_since_epoch()).count()) * (uint64_t)(TimeScale * 1000)); -} - -static uint64_t MSToNS(unsigned int ms) -{ - return static_cast(ms) * 1'000'000; -} - -static uint64_t NSToMS(uint64_t ns) -{ - return static_cast(ns / 1'000'000); -} - -static int NSToTic(uint64_t ns) -{ - return static_cast(ns * GameTicRate / 1'000'000'000); -} - -static uint64_t TicToNS(int tic) -{ - return static_cast(tic) * 1'000'000'000 / GameTicRate; -} - -void I_SetFrameTime() -{ - // Must only be called once per frame/swapbuffers. - // - // Caches all timing information for the current rendered frame so that any - // calls to I_GetTime or I_GetTimeFrac will return - // the same time. - - if (FreezeTime == 0) - { - CurrentFrameStartTime = GetClockTimeNS(); - if (FirstFrameStartTime == 0) - FirstFrameStartTime = CurrentFrameStartTime; - } -} - -void I_WaitVBL(int count) -{ - // I_WaitVBL is never used to actually synchronize to the vertical blank. - // Instead, it's used for delay purposes. Doom used a 70 Hz display mode, - // so that's what we use to determine how long to wait for. - - std::this_thread::sleep_for(std::chrono::milliseconds(1000 * count / 70)); - I_SetFrameTime(); -} - -int I_WaitForTic(int prevtic) -{ - // Waits until the current tic is greater than prevtic. Time must not be frozen. - - int time; - while ((time = I_GetTime()) <= prevtic) - { - // Windows-specific note: - // The minimum amount of time a thread can sleep is controlled by timeBeginPeriod. - // We set this to 1 ms in DoMain. - - const uint64_t next = FirstFrameStartTime + TicToNS(prevtic + 1); - const uint64_t now = I_nsTime(); - - if (next > now) - { - const uint64_t sleepTime = NSToMS(next - now); - - if (sleepTime > 2) - { - std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime - 2)); - } - } - - I_SetFrameTime(); - } - - return time; -} - -uint64_t I_nsTime() -{ - return GetClockTimeNS(); -} - -uint64_t I_msTime() -{ - return NSToMS(I_nsTime()); -} - -uint64_t I_msTimeFS() // from "start" -{ - return (FirstFrameStartTime == 0) ? 0 : NSToMS(I_nsTime() - FirstFrameStartTime); -} - -int I_GetTime() -{ - return NSToTic(CurrentFrameStartTime - FirstFrameStartTime); -} - -double I_GetTimeFrac() -{ - int currentTic = NSToTic(CurrentFrameStartTime - FirstFrameStartTime); - uint64_t ticStartTime = FirstFrameStartTime + TicToNS(currentTic); - uint64_t ticNextTime = FirstFrameStartTime + TicToNS(currentTic + 1); - - return (CurrentFrameStartTime - ticStartTime) / (double)(ticNextTime - ticStartTime); -} - -void I_FreezeTime(bool frozen) -{ - if (frozen) - { - assert(FreezeTime == 0); - FreezeTime = GetClockTimeNS(); - } - else - { - assert(FreezeTime != 0); - FirstFrameStartTime += GetClockTimeNS() - FreezeTime; - FreezeTime = 0; - I_SetFrameTime(); - } -} - diff --git a/src/utility/i_time.h b/src/utility/i_time.h deleted file mode 100644 index 47d726de7b0..00000000000 --- a/src/utility/i_time.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -extern int GameTicRate; -extern double TimeScale; - -// Called by D_DoomLoop, sets the time for the current frame -void I_SetFrameTime(); - -// Called by D_DoomLoop, returns current time in tics. -int I_GetTime(); - -double I_GetTimeFrac(); - -// like I_GetTime, except it waits for a new tic before returning -int I_WaitForTic(int); - -// Freezes tic counting temporarily. While frozen, calls to I_GetTime() -// will always return the same value. -// You must also not call I_WaitForTic() while freezing time, since the -// tic will never arrive (unless it's the current one). -void I_FreezeTime(bool frozen); - -// [RH] Returns millisecond-accurate time -uint64_t I_msTime(); - -// [SP] Returns millisecond-accurate time from start -uint64_t I_msTimeFS(); - -// Nanosecond-accurate time -uint64_t I_nsTime(); diff --git a/src/utility/lists.h b/src/utility/lists.h deleted file mode 100644 index a244aa22f6b..00000000000 --- a/src/utility/lists.h +++ /dev/null @@ -1,146 +0,0 @@ -/* -** lists.h -** Essentially, Amiga Exec lists and nodes -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __LISTS_H__ -#define __LISTS_H__ - -struct Node -{ - Node *Succ, *Pred; - - void Insert (Node *putAfter) - { - Succ = putAfter->Succ; - Pred = putAfter; - putAfter->Succ = this; - Succ->Pred = this; - } - - void InsertBefore (Node *putBefore) - { - Succ = putBefore; - Pred = putBefore->Pred; - putBefore->Pred = this; - Pred->Succ = this; - } - - void Remove () - { - Pred->Succ = Succ; - Succ->Pred = Pred; - } -}; - -struct List -{ - Node *Head; - const Node *const Tail; - Node *TailPred; - - List () : Head ((Node *)&Tail), Tail (NULL), TailPred ((Node *)&Head) - { - } - - bool IsEmpty () const - { - return TailPred == (Node *)this; - } - - void MakeEmpty () - { - Head = (Node *)&Tail; - TailPred = (Node *)&Head; - } - - void AddHead (Node *node) - { - node->Succ = Head; - node->Pred = (Node *)&Head; - Head->Pred = node; - Head = node; - } - - void AddTail (Node *node) - { - node->Pred = TailPred; - node->Succ = (Node *)&Tail; - TailPred->Succ = node; - TailPred = node; - } - - Node *RemHead () - { - Node *node = Head; - if (node->Succ == NULL) - { - return NULL; - } - Head = node->Succ; - Head->Pred = (Node *)&Head; - return node; - } - - Node *RemHeadQ () // Only use if list is definitely not empty - { - Node *node = Head; - Head = node->Succ; - Head->Pred = (Node *)&Head; - return node; - } - - Node *RemTail () - { - Node *node = TailPred; - if (node->Pred == NULL) - { - return NULL; - } - TailPred = node->Pred; - TailPred->Succ = (Node *)&Tail; - return node; - } - - Node *RemTailQ () // Only use if list is definitely not empty - { - Node *node = TailPred; - TailPred = node->Pred; - TailPred->Succ = (Node *)&Tail; - return node; - } - -private: - List &operator= (const List&) { return *this; } -}; - -#endif //__LISTS_H__ diff --git a/src/utility/m_alloc.cpp b/src/utility/m_alloc.cpp deleted file mode 100644 index 99f1b0657fb..00000000000 --- a/src/utility/m_alloc.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* -** m_alloc.cpp -** Wrappers for the malloc family of functions that count used bytes. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 defined(__FreeBSD__) -#include -#include -#elif defined(__APPLE__) -#include -#include -#elif defined(__OpenBSD__) -#include -#else -#include -#endif - -#include "doomerrors.h" -#include "dobject.h" - -#ifndef _MSC_VER -#define _NORMAL_BLOCK 0 -#define _malloc_dbg(s,b,f,l) malloc(s) -#define _realloc_dbg(p,s,b,f,l) realloc(p,s) -#endif -#if defined(__APPLE__) -#define _msize(p) malloc_size(p) -#elif defined(__solaris__) || defined(__OpenBSD__) -#define _msize(p) (*((size_t*)(p)-1)) -#elif !defined(_WIN32) -#define _msize(p) malloc_usable_size(p) // from glibc/FreeBSD -#endif - -#ifndef _DEBUG -#if !defined(__solaris__) && !defined(__OpenBSD__) -void *M_Malloc(size_t size) -{ - void *block = malloc(size); - - if (block == NULL) - I_FatalError("Could not malloc %zu bytes", size); - - GC::AllocBytes += _msize(block); - return block; -} - -void *M_Realloc(void *memblock, size_t size) -{ - if (memblock != NULL) - { - GC::AllocBytes -= _msize(memblock); - } - void *block = realloc(memblock, size); - if (block == NULL) - { - I_FatalError("Could not realloc %zu bytes", size); - } - GC::AllocBytes += _msize(block); - return block; -} -#else -void *M_Malloc(size_t size) -{ - void *block = malloc(size+sizeof(size_t)); - - if (block == NULL) - I_FatalError("Could not malloc %zu bytes", size); - - size_t *sizeStore = (size_t *) block; - *sizeStore = size; - block = sizeStore+1; - - GC::AllocBytes += _msize(block); - return block; -} - -void *M_Realloc(void *memblock, size_t size) -{ - if(memblock == NULL) - return M_Malloc(size); - - if (memblock != NULL) - { - GC::AllocBytes -= _msize(memblock); - } - void *block = realloc(((size_t*) memblock)-1, size+sizeof(size_t)); - if (block == NULL) - { - I_FatalError("Could not realloc %zu bytes", size); - } - - size_t *sizeStore = (size_t *) block; - *sizeStore = size; - block = sizeStore+1; - - GC::AllocBytes += _msize(block); - return block; -} -#endif -#else -#ifdef _MSC_VER -#include -#endif - -#if !defined(__solaris__) && !defined(__OpenBSD__) -void *M_Malloc_Dbg(size_t size, const char *file, int lineno) -{ - void *block = _malloc_dbg(size, _NORMAL_BLOCK, file, lineno); - - if (block == NULL) - I_FatalError("Could not malloc %zu bytes", size); - - GC::AllocBytes += _msize(block); - return block; -} - -void *M_Realloc_Dbg(void *memblock, size_t size, const char *file, int lineno) -{ - if (memblock != NULL) - { - GC::AllocBytes -= _msize(memblock); - } - void *block = _realloc_dbg(memblock, size, _NORMAL_BLOCK, file, lineno); - if (block == NULL) - { - I_FatalError("Could not realloc %zu bytes", size); - } - GC::AllocBytes += _msize(block); - return block; -} -#else -void *M_Malloc_Dbg(size_t size, const char *file, int lineno) -{ - void *block = _malloc_dbg(size+sizeof(size_t), _NORMAL_BLOCK, file, lineno); - - if (block == NULL) - I_FatalError("Could not malloc %zu bytes", size); - - size_t *sizeStore = (size_t *) block; - *sizeStore = size; - block = sizeStore+1; - - GC::AllocBytes += _msize(block); - return block; -} - -void *M_Realloc_Dbg(void *memblock, size_t size, const char *file, int lineno) -{ - if(memblock == NULL) - return M_Malloc_Dbg(size, file, lineno); - - if (memblock != NULL) - { - GC::AllocBytes -= _msize(memblock); - } - void *block = _realloc_dbg(((size_t*) memblock)-1, size+sizeof(size_t), _NORMAL_BLOCK, file, lineno); - - if (block == NULL) - { - I_FatalError("Could not realloc %zu bytes", size); - } - - size_t *sizeStore = (size_t *) block; - *sizeStore = size; - block = sizeStore+1; - - GC::AllocBytes += _msize(block); - return block; -} -#endif -#endif - -#if !defined(__solaris__) && !defined(__OpenBSD__) -void M_Free (void *block) -{ - if (block != NULL) - { - GC::AllocBytes -= _msize(block); - free(block); - } -} -#else -void M_Free (void *block) -{ - if(block != NULL) - { - GC::AllocBytes -= _msize(block); - free(((size_t*) block)-1); - } -} -#endif - diff --git a/src/utility/m_argv.cpp b/src/utility/m_argv.cpp deleted file mode 100644 index ed2b08f1ca5..00000000000 --- a/src/utility/m_argv.cpp +++ /dev/null @@ -1,422 +0,0 @@ -/* -** m_argv.cpp -** Manages command line arguments -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include "m_argv.h" -#include "i_system.h" - -//=========================================================================== -// -// FArgs Default Constructor -// -//=========================================================================== - -FArgs::FArgs() -{ -} - -//=========================================================================== -// -// FArgs Copy Constructor -// -//=========================================================================== - -FArgs::FArgs(const FArgs &other) -: Argv(other.Argv) -{ -} - -//=========================================================================== -// -// FArgs Argv Constructor -// -//=========================================================================== - -FArgs::FArgs(int argc, char **argv) -{ - SetArgs(argc, argv); -} - -//=========================================================================== -// -// FArgs String Argv Constructor -// -//=========================================================================== - -FArgs::FArgs(int argc, FString *argv) -{ - AppendArgs(argc, argv); -} - - - -//=========================================================================== -// -// FArgs Copy Operator -// -//=========================================================================== - -FArgs &FArgs::operator=(const FArgs &other) -{ - Argv = other.Argv; - return *this; -} - -//=========================================================================== -// -// FArgs :: SetArgs -// -//=========================================================================== - -void FArgs::SetArgs(int argc, char **argv) -{ - Argv.Resize(argc); - for (int i = 0; i < argc; ++i) - { - Argv[i] = argv[i]; - } -} - -//=========================================================================== -// -// FArgs :: FlushArgs -// -//=========================================================================== - -void FArgs::FlushArgs() -{ - Argv.Clear(); -} - -//=========================================================================== -// -// FArgs :: CheckParm -// -// Checks for the given parameter in the program's command line arguments. -// Returns the argument number (1 to argc-1) or 0 if not present -// -//=========================================================================== - -int FArgs::CheckParm(const char *check, int start) const -{ - for (unsigned i = start; i < Argv.Size(); ++i) - { - if (0 == stricmp(check, Argv[i])) - { - return i; - } - } - return 0; -} - -//=========================================================================== -// -// FArgs :: CheckParmList -// -// Returns the number of arguments after the parameter (if found) and also -// returns a pointer to the first argument. -// -//=========================================================================== - -int FArgs::CheckParmList(const char *check, FString **strings, int start) const -{ - unsigned int i, parmat = CheckParm(check, start); - - if (parmat == 0) - { - if (strings != NULL) - { - *strings = NULL; - } - return 0; - } - for (i = ++parmat; i < Argv.Size(); ++i) - { - if (Argv[i][0] == '-' || Argv[i][1] == '+') - { - break; - } - } - if (strings != NULL) - { - *strings = &Argv[parmat]; - } - return i - parmat; -} - -//=========================================================================== -// -// FArgs :: CheckValue -// -// Like CheckParm, but it also checks that the parameter has a value after -// it and returns that or NULL if not present. -// -//=========================================================================== - -const char *FArgs::CheckValue(const char *check) const -{ - int i = CheckParm(check); - - if (i > 0 && i < (int)Argv.Size() - 1) - { - i++; - return Argv[i][0] != '+' && Argv[i][0] != '-' ? Argv[i].GetChars() : NULL; - } - else - { - return NULL; - } -} - -//=========================================================================== -// -// FArgs :: TakeValue -// -// Like CheckValue, except it also removes the parameter and its argument -// (if present) from argv. -// -//=========================================================================== - -FString FArgs::TakeValue(const char *check) -{ - int i = CheckParm(check); - FString out; - - if (i > 0 && i < (int)Argv.Size()) - { - if (i < (int)Argv.Size() - 1 && Argv[i+1][0] != '+' && Argv[i+1][0] != '-') - { - out = Argv[i+1]; - Argv.Delete(i, 2); // Delete the parm and its value. - } - else - { - Argv.Delete(i); // Just delete the parm, since it has no value. - } - } - return out; -} - -//=========================================================================== -// -// FArgs :: RemoveArg -// -//=========================================================================== - -void FArgs::RemoveArgs(const char *check) -{ - int i = CheckParm(check); - - if (i > 0 && i < (int)Argv.Size() - 1) - { - do - { - RemoveArg(i); - } - while (Argv[i][0] != '+' && Argv[i][0] != '-' && i < (int)Argv.Size() - 1); - } -} - -//=========================================================================== -// -// FArgs :: GetArg -// -// Gets the argument at a particular position. -// -//=========================================================================== - -const char *FArgs::GetArg(int arg) const -{ - return ((unsigned)arg < Argv.Size()) ? Argv[arg].GetChars() : NULL; -} - -//=========================================================================== -// -// FArgs :: GetArgList -// -// Returns a pointer to the FString at a particular position. -// -//=========================================================================== - -FString *FArgs::GetArgList(int arg) const -{ - return ((unsigned)arg < Argv.Size()) ? &Argv[arg] : NULL; -} - -//=========================================================================== -// -// FArgs :: NumArgs -// -//=========================================================================== - -int FArgs::NumArgs() const -{ - return (int)Argv.Size(); -} - -//=========================================================================== -// -// FArgs :: AppendArg -// -// Adds another argument to argv. Invalidates any previous results from -// GetArgList(). -// -//=========================================================================== - -void FArgs::AppendArg(FString arg) -{ - Argv.Push(arg); -} - -//=========================================================================== -// -// FArgs :: AppendArgs -// -// Adds an array of FStrings to argv. -// -//=========================================================================== - -void FArgs::AppendArgs(int argc, const FString *argv) -{ - if (argv != NULL && argc > 0) - { - Argv.Grow(argc); - for (int i = 0; i < argc; ++i) - { - Argv.Push(argv[i]); - } - } -} - -//=========================================================================== -// -// FArgs :: RemoveArg -// -// Removes a single argument from argv. -// -//=========================================================================== - -void FArgs::RemoveArg(int argindex) -{ - Argv.Delete(argindex); -} - -//=========================================================================== -// -// FArgs :: CollectFiles -// -// Takes all arguments after any instance of -param and any arguments before -// all switches that end in .extension and combines them into a single -// -switch block at the end of the arguments. If extension is NULL, then -// every parameter before the first switch is added after this -param. -// -//=========================================================================== - -void FArgs::CollectFiles(const char *param, const char *extension) -{ - TArray work; - unsigned int i; - size_t extlen = extension == NULL ? 0 : strlen(extension); - - // Step 1: Find suitable arguments before the first switch. - i = 1; - while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+') - { - bool useit; - - if (extlen > 0) - { // Argument's extension must match. - size_t len = Argv[i].Len(); - useit = (len >= extlen && stricmp(&Argv[i][len - extlen], extension) == 0); - } - else - { // Anything will do so long as it's before the first switch. - useit = true; - } - if (useit) - { - work.Push(Argv[i]); - Argv.Delete(i); - } - else - { - i++; - } - } - - // Step 2: Find each occurence of -param and add its arguments to work. - while ((i = CheckParm(param, i)) > 0) - { - Argv.Delete(i); - while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+') - { - work.Push(Argv[i]); - Argv.Delete(i); - } - } - - // Optional: Replace short path names with long path names -#ifdef _WIN32 - for (i = 0; i < work.Size(); ++i) - { - work[i] = I_GetLongPathName(work[i]); - } -#endif - - // Step 3: Add work back to Argv, as long as it's non-empty. - if (work.Size() > 0) - { - Argv.Push(param); - AppendArgs(work.Size(), &work[0]); - } -} - -//=========================================================================== -// -// FArgs :: GatherFiles -// -// Returns all the arguments after the first instance of -param. If you want -// to combine more than one or get switchless stuff included, you need to -// call CollectFiles first. -// -//=========================================================================== - -FArgs *FArgs::GatherFiles(const char *param) const -{ - FString *files; - int filecount; - - filecount = CheckParmList(param, &files); - return new FArgs(filecount, files); -} diff --git a/src/utility/m_argv.h b/src/utility/m_argv.h deleted file mode 100644 index 31df56ad8ee..00000000000 --- a/src/utility/m_argv.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -** m_argv.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __M_ARGV_H__ -#define __M_ARGV_H__ - -#include "dobject.h" -#include "zstring.h" - -// -// MISC -// -class FArgs -{ -public: - FArgs(); - FArgs(const FArgs &args); - FArgs(int argc, char **argv); - FArgs(int argc, FString *argv); - - FArgs &operator=(const FArgs &other); - - void AppendArg(FString arg); - void AppendArgs(int argc, const FString *argv); - void RemoveArg(int argindex); - void RemoveArgs(const char *check); - void SetArgs(int argc, char **argv); - void CollectFiles(const char *param, const char *extension); - FArgs *GatherFiles(const char *param) const; - void SetArg(int argnum, const char *arg); - - int CheckParm(const char *check, int start=1) const; // Returns the position of the given parameter in the arg list (0 if not found). - int CheckParmList(const char *check, FString **strings, int start=1) const; - const char *CheckValue(const char *check) const; - const char *GetArg(int arg) const; - FString *GetArgList(int arg) const; - FString TakeValue(const char *check); - int NumArgs() const; - void FlushArgs(); - -private: - TArray Argv; -}; - -extern FArgs *Args; - -#endif //__M_ARGV_H__ diff --git a/src/utility/m_bbox.cpp b/src/utility/m_bbox.cpp deleted file mode 100644 index 1fb6ca14235..00000000000 --- a/src/utility/m_bbox.cpp +++ /dev/null @@ -1,97 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// Copyright 2002-2016 Christoph Oelckers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// bounding box class -// -//----------------------------------------------------------------------------- - -#include "m_bbox.h" -#include "p_local.h" -#include "p_maputl.h" - -//========================================================================== -// -// -// -//========================================================================== - -void FBoundingBox::AddToBox (const DVector2 &pos) -{ - if (pos.X < m_Box[BOXLEFT]) - m_Box[BOXLEFT] = pos.X; - if (pos.X > m_Box[BOXRIGHT]) - m_Box[BOXRIGHT] = pos.X; - - if (pos.Y < m_Box[BOXBOTTOM]) - m_Box[BOXBOTTOM] = pos.Y; - if (pos.Y > m_Box[BOXTOP]) - m_Box[BOXTOP] = pos.Y; -} - -//========================================================================== -// -// FBoundingBox :: BoxOnLineSide -// -// Considers the line to be infinite -// Returns side 0 or 1, -1 if box crosses the line. -// -//========================================================================== - -int FBoundingBox::BoxOnLineSide (const line_t *ld) const -{ - int p1; - int p2; - - if (ld->Delta().X == 0) - { // ST_VERTICAL - p1 = m_Box[BOXRIGHT] < ld->v1->fX(); - p2 = m_Box[BOXLEFT] < ld->v1->fX(); - if (ld->Delta().Y < 0) - { - p1 ^= 1; - p2 ^= 1; - } - } - else if (ld->Delta().Y == 0) - { // ST_HORIZONTAL: - p1 = m_Box[BOXTOP] > ld->v1->fY(); - p2 = m_Box[BOXBOTTOM] > ld->v1->fY(); - if (ld->Delta().X < 0) - { - p1 ^= 1; - p2 ^= 1; - } - } - else if ((ld->Delta().X * ld->Delta().Y) >= 0) - { // ST_POSITIVE: - p1 = P_PointOnLineSide (m_Box[BOXLEFT], m_Box[BOXTOP], ld); - p2 = P_PointOnLineSide (m_Box[BOXRIGHT], m_Box[BOXBOTTOM], ld); - } - else - { // ST_NEGATIVE: - p1 = P_PointOnLineSide (m_Box[BOXRIGHT], m_Box[BOXTOP], ld); - p2 = P_PointOnLineSide (m_Box[BOXLEFT], m_Box[BOXBOTTOM], ld); - } - - return (p1 == p2) ? p1 : -1; -} - diff --git a/src/utility/m_bbox.h b/src/utility/m_bbox.h deleted file mode 100644 index e19f179d75f..00000000000 --- a/src/utility/m_bbox.h +++ /dev/null @@ -1,100 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// Copyright 2002-2016 Christoph Oelckers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// Nil. -// -//----------------------------------------------------------------------------- - -#ifndef __M_BBOX_H__ -#define __M_BBOX_H__ - -#include -#include "vectors.h" -#include "m_fixed.h" - -struct line_t; -struct node_t; - -class FBoundingBox -{ -public: - FBoundingBox() - { - ClearBox(); - } - - FBoundingBox(double left, double bottom, double right, double top) - { - m_Box[BOXTOP] = top; - m_Box[BOXLEFT] = left; - m_Box[BOXRIGHT] = right; - m_Box[BOXBOTTOM] = bottom; - } - - FBoundingBox(double x, double y, double radius) - { - setBox(x, y, radius); - } - - - void setBox(double x, double y, double radius) - { - m_Box[BOXTOP] = y + radius; - m_Box[BOXLEFT] = x - radius; - m_Box[BOXRIGHT] = x + radius; - m_Box[BOXBOTTOM] = y - radius; - } - - void ClearBox () - { - m_Box[BOXTOP] = m_Box[BOXRIGHT] = -FLT_MAX; - m_Box[BOXBOTTOM] = m_Box[BOXLEFT] = FLT_MAX; - } - - // Returns a bounding box that encloses both bounding boxes - FBoundingBox operator | (const FBoundingBox &box2) const - { - return FBoundingBox(m_Box[BOXLEFT] < box2.m_Box[BOXLEFT] ? m_Box[BOXLEFT] : box2.m_Box[BOXLEFT], - m_Box[BOXBOTTOM] < box2.m_Box[BOXBOTTOM] ? m_Box[BOXBOTTOM] : box2.m_Box[BOXBOTTOM], - m_Box[BOXRIGHT] > box2.m_Box[BOXRIGHT] ? m_Box[BOXRIGHT] : box2.m_Box[BOXRIGHT], - m_Box[BOXTOP] > box2.m_Box[BOXTOP] ? m_Box[BOXTOP] : box2.m_Box[BOXTOP]); - } - - void AddToBox(const DVector2 &pos); - - inline double Top () const { return m_Box[BOXTOP]; } - inline double Bottom () const { return m_Box[BOXBOTTOM]; } - inline double Left () const { return m_Box[BOXLEFT]; } - inline double Right () const { return m_Box[BOXRIGHT]; } - - bool inRange(const line_t *ld) const; - - int BoxOnLineSide (const line_t *ld) const; - - void Set(int index, double value) {m_Box[index] = value;} - -protected: - double m_Box[4]; -}; - - -#endif //__M_BBOX_H__ diff --git a/src/utility/m_fixed.h b/src/utility/m_fixed.h deleted file mode 100644 index 8bbb2dbf977..00000000000 --- a/src/utility/m_fixed.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef __M_FIXED__ -#define __M_FIXED__ - -#include -#include "doomtype.h" - -// Unfortunately, the Scale function still gets badly handled on 32 bit x86 platforms so it's the last remaining piece of inline assembly - -// GCC inlines -#if defined(__GNUC__) && defined(__i386__) && !defined(__clang__) && !defined(__PIC__) -#ifndef alloca -// MinGW does not seem to come with alloca defined. -#define alloca __builtin_alloca -#endif - -static inline int32_t Scale(int32_t a, int32_t b, int32_t c) -{ - int32_t result, dummy; - - asm volatile - ("imull %3\n\t" - "idivl %4" - : "=a,a,a,a,a,a" (result), - "=&d,&d,&d,&d,d,d" (dummy) - : "a,a,a,a,a,a" (a), - "m,r,m,r,d,d" (b), - "r,r,m,m,r,m" (c) - : "cc" - ); - - return result; -} - -// MSVC inlines -#elif defined(_MSC_VER) && defined(_M_IX86) -#pragma warning (disable: 4035) - -__forceinline int32_t Scale(int32_t a, int32_t b, int32_t c) -{ - __asm mov eax, a - __asm imul b - __asm idiv c -} - -#pragma warning (default: 4035) -#else - -static __forceinline int32_t Scale(int32_t a, int32_t b, int32_t c) -{ - return (int32_t)(((int64_t)a*b) / c); -} - -#endif - -// Modern compilers are smart enough to do these multiplications intelligently. -__forceinline int32_t MulScale14(int32_t a, int32_t b) { return (int32_t)(((int64_t)a * b) >> 14); } // only used by R_DrawVoxel -__forceinline int32_t MulScale30(int32_t a, int32_t b) { return (int32_t)(((int64_t)a * b) >> 30); } // only used once in the node builder -__forceinline int32_t MulScale32(int32_t a, int32_t b) { return (int32_t)(((int64_t)a * b) >> 32); } // only used by R_DrawVoxel - -__forceinline uint32_t UMulScale16(uint32_t a, uint32_t b) { return (uint32_t)(((uint64_t)a * b) >> 16); } // used for sky drawing - -__forceinline int32_t DMulScale3(int32_t a, int32_t b, int32_t c, int32_t d) { return (int32_t)(((int64_t)a*b + (int64_t)c*d) >> 3); } // used for setting up slopes for Build maps -__forceinline int32_t DMulScale6(int32_t a, int32_t b, int32_t c, int32_t d) { return (int32_t)(((int64_t)a*b + (int64_t)c*d) >> 6); } // only used by R_DrawVoxel -__forceinline int32_t DMulScale10(int32_t a, int32_t b, int32_t c, int32_t d) { return (int32_t)(((int64_t)a*b + (int64_t)c*d) >> 10); } // only used by R_DrawVoxel -__forceinline int32_t DMulScale18(int32_t a, int32_t b, int32_t c, int32_t d) { return (int32_t)(((int64_t)a*b + (int64_t)c*d) >> 18); } // only used by R_DrawVoxel -__forceinline int32_t DMulScale32(int32_t a, int32_t b, int32_t c, int32_t d) { return (int32_t)(((int64_t)a*b + (int64_t)c*d) >> 32); } // used by R_PointOnSide. - -// Sadly, for divisions this is not true but these are so infrequently used that the C versions are just fine, despite not being fully optimal. -__forceinline int32_t DivScale6(int32_t a, int32_t b) { return (int32_t)(((int64_t)a << 6) / b); } // only used by R_DrawVoxel -__forceinline int32_t DivScale21(int32_t a, int32_t b) { return (int32_t)(((int64_t)a << 21) / b); } // only used by R_DrawVoxel -__forceinline int32_t DivScale30(int32_t a, int32_t b) { return (int32_t)(((int64_t)a << 30) / b); } // only used once in the node builder - -__forceinline void fillshort(void *buff, unsigned int count, uint16_t clear) -{ - int16_t *b2 = (int16_t *)buff; - for (unsigned int i = 0; i != count; ++i) - { - b2[i] = clear; - } -} - -#include "xs_Float.h" - -inline int32_t FixedDiv (int32_t a, int32_t b) -{ - if ((uint32_t)abs(a) >> (31-16) >= (uint32_t)abs (b)) - return (a^b)<0 ? FIXED_MIN : FIXED_MAX; - - return (int32_t)(((int64_t)a << 16) / b); -} - -__forceinline int32_t FixedMul(int32_t a, int32_t b) -{ - return (int32_t)(((int64_t)a * b) >> 16); -} - -inline fixed_t FloatToFixed(double f) -{ - return xs_Fix<16>::ToFix(f); -} - -inline double FixedToFloat(fixed_t f) -{ - return f / 65536.; -} - -inline unsigned FloatToAngle(double f) -{ - return xs_CRoundToInt((f)* (0x40000000 / 90.)); -} - -inline double AngleToFloat(unsigned f) -{ - return f * (90. / 0x40000000); -} - -inline double AngleToFloat(int f) -{ - return f * (90. / 0x40000000); -} - -#define FLOAT2FIXED(f) FloatToFixed(f) -#define FIXED2FLOAT(f) float(FixedToFloat(f)) -#define FIXED2DBL(f) FixedToFloat(f) - -#define ANGLE2DBL(f) AngleToFloat(f) - -#endif diff --git a/src/utility/namedef.h b/src/utility/namedef.h deleted file mode 100644 index 9aa0e4cc52e..00000000000 --- a/src/utility/namedef.h +++ /dev/null @@ -1,1098 +0,0 @@ -// 'None' must always be the first name. -xx(None) -xx(Null) -xx(_) - -xx(Super) -xx(Object) -xx(Actor) -xx(Class) -xx(Thinker) - -xx(Untranslated) - -xx(Doom) -xx(Heretic) -xx(Hexen) -xx(Strife) -xx(Raven) - -// blood spawning -xx(Blood) -xx(BloodSplatter) -xx(AxeBlood) -xx(Spray) - -// Invulnerability types -xx(Ghost) -xx(Reflective) - -// Invisibility types -xx(Additive) -xx(Cumulative) -xx(Fuzzy) -xx(Opaque) -xx(Stencil) -xx(AddStencil) - -// Render styles -xx(Normal) -xx(SoulTrans) -xx(OptFuzzy) -xx(Add) -xx(Shaded) -xx(AddShaded) -xx(TranslucentStencil) -xx(Shadow) -xx(Subtract) -xx(Subtractive) -xx(FillColor) -xx(ColorBlend) -xx(ColorAdd) -xx(Multiply) - -// Healingradius types -xx(Mana) -xx(Armor) - -// Per-actor sound channels -xx(Auto) -xx(Weapon) -xx(Voice) -xx(Item) -xx(Body) -xx(SoundSlot5) -xx(SoundSlot6) -xx(SoundSlot7) - -// Hexen sound sequence names -xx(Platform) -xx(PlatformMetal) -xx(Silence) -xx(Lava) -xx(Water) -xx(Ice) -xx(Earth) -xx(PlatformMetal2) -xx(DoorNormal) -xx(DoorHeavy) -xx(DoorMetal) -xx(DoorCreak) -xx(DoorMetal2) -xx(Wind) - -xx(PointPusher) -xx(PointPuller) - -xx(UpperStackLookOnly) -xx(LowerStackLookOnly) -xx(StackPoint) -xx(SkyCamCompat) - -xx(BasicArmorBonus) -xx(BasicArmorPickup) -xx(SaveAmount) -xx(SavePercent) -xx(MaxAbsorb) -xx(MaxFullAbsorb) -xx(MaxAmount) -xx(ActualSaveAmount) -xx(ArmorType) -xx(HexenArmor) -xx(Slots) -xx(SlotsIncrement) -xx(InterHubAmount) -xx(Icon) -xx(AltHUDIcon) -xx(PickupFlash) - -xx(BulletPuff) -xx(StrifePuff) -xx(MaulerPuff) - -// Special bosses A_BossDeath knows about -xx(Fatso) -xx(Arachnotron) -xx(BaronOfHell) -xx(Cyberdemon) -xx(SpiderMastermind) -xx(Ironlich) -xx(Minotaur) -xx(Sorcerer2) - -// Bots check this -xx(Megasphere) - -// Standard player classes -xx(DoomPlayer) -xx(HereticPlayer) -xx(StrifePlayer) -xx(FighterPlayer) -xx(ClericPlayer) -xx(MagePlayer) -xx(ChexPlayer) -xx(ChickenPlayer) -xx(PigPlayer) - -// Flechette names for the different Hexen player classes -xx(ArtiPoisonBag1) -xx(ArtiPoisonBag2) -xx(ArtiPoisonBag3) - -// Strife quests -xx(QuestItem) -xx(Sigil) -xx(ScriptedMarine) -xx(GiveSigilPiece) -xx(SetWeapon) -xx(SetSprite) - -// Armor -xx(BasicArmor) - -// The Wings of Wrath -xx(ArtiFly) - -// Doom ammo types -xx(Clip) -xx(Shell) -xx(RocketAmmo) -xx(Cell) - -// Hexen Mana -xx(Mana1) -xx(Mana2) - -// Hexen's fourth weapons -xx(FWeapQuietus) -xx(CWeapWraithverge) -xx(MWeapBloodscourge) - -// Misc Hexen classes -xx(LightningZap) - -// Ammo and weapon names for the Strife status bar -xx(ClipOfBullets) -xx(PoisonBolts) -xx(ElectricBolts) -xx(HEGrenadeRounds) -xx(PhosphorusGrenadeRounds) -xx(MiniMissiles) -xx(EnergyPod) - -xx(StrifeCrossbow) -xx(AssaultGun) -xx(FlameThrower) -xx(MiniMissileLauncher) -xx(StrifeGrenadeLauncher) -xx(Mauler) -xx(BackpackItem) -xx(PuzzleItem) -xx(PuzzleItemNumber) -xx(HealthPickup) -xx(autousemode) -xx(Ammo) -xx(WeaponGiver) -xx(DehackedPickup) -xx(PowerTargeter) -xx(PowerInvulnerable) -xx(PowerStrength) -xx(PowerInvisibility) -xx(PowerIronFeet) -xx(PowerLightAmp) -xx(PowerWeaponLevel2) -xx(PowerFlight) -xx(PowerSpeed) -xx(PowerTorch) -xx(PowerHighJump) -xx(PowerReflection) -xx(PowerDrain) -xx(Reflection) -xx(CustomInventory) -xx(Inventory) -xx(StateProvider) -xx(CallTryPickup) -xx(QuestItem25) -xx(QuestItem28) -xx(QuestItem29) -xx(PowerDoubleFiringSpeed) -xx(PowerInfiniteAmmo) -xx(PowerBuddha) - -xx(AcolyteBlue) -xx(SpectralLightningV1) -xx(SpectralLightningV2) -xx(TeleportDest) -xx(TeleportDest2) - -// Strife's spectres -xx(AlienSpectre1) -xx(AlienSpectre2) -xx(AlienSpectre3) -xx(AlienSpectre4) -xx(AlienSpectre5) -xx(Oracle) - -xx(Chicken) -xx(Pig) - -// Standard animator names. -xx(Spawn) -xx(See) -xx(Pain) -xx(Melee) -xx(Missile) -xx(Crash) -xx(Death) -xx(Raise) -xx(Wound) -xx(Heal) -xx(Crush) -xx(Yes) -xx(No) -xx(Greetings) -xx(Idle) -xx(GenericFreezeDeath) -xx(GenericCrush) - -// Bounce state names -xx(Bounce) -xx(Wall) -xx(Floor) -xx(Ceiling) -xx(Creature) - -// Compatible death names for the decorate parser. -xx(XDeath) -xx(Burn) -//xx(Ice) // already defined above -xx(Disintegrate) -xx(Smash) - -// Weapon animator names. -xx(Select) -xx(Deselect) -xx(DeadLowered) -xx(Ready) -xx(Fire) -xx(Hold) -xx(AltFire) -xx(AltHold) -xx(Flash) -xx(AltFlash) -xx(Reload) -xx(Zoom) -xx(User1) -xx(User2) -xx(User3) -xx(User4) - -// State names used by ASwitchableDecoration -xx(Active) -xx(Inactive) - -// State names used by ACustomInventory -xx(Pickup) -xx(Use) -xx(Drop) - -xx(Fist) -//xx(Berserk) -xx(Chainsaw) -xx(Pistol) -xx(Shotgun) -xx(SSG) -xx(Chaingun) -xx(Rocket) -xx(Plasma) -xx(BFG) -//xx(Railgun) -xx(Dagger) - -// Damage types -//xx(Fire) already defined above -//xx(Ice) -//xx(Disintegrate) -xx(Drowning) -xx(Slime) -//xx(Crush) -xx(Telefrag) -xx(Falling) -xx(Suicide) -xx(Exit) -xx(Railgun) -xx(Poison) -xx(Electric) -xx(BFGSplash) -xx(DrainLife) // A weapon like the Sigil that drains your life away. -xx(Massacre) // For death by a cheater! -//(Melee) already defined above, so don't define it again -xx(InstantDeath) // Strife "instant death" -xx(PoisonCloud) // makes monsters howl. -xx(Hitscan) // for normal guns and the like -xx(Quake) - -// Special death name for getting killed excessively. Could be used as -// a damage type if you wanted to force an extreme death. -xx(Extreme) -xx(MDK) -xx(Cast) // 'damage type' for the cast call - -// Special names for thingdef_exp.cpp -xx(Random) -xx(FRandom) -xx(Random2) -xx(RandomPick) -xx(FRandomPick) -xx(SetRandomSeed) -xx(BuiltinRandomSeed) -xx(BuiltinNew) -xx(GetClass) -xx(GetParentClass) -xx(GetClassName) -xx(GetDefaultByType) -xx(Exp) -xx(Log10) -xx(Ceil) -xx(ACos) -xx(ASin) -xx(ATan) -xx(Cos) -xx(Sin) -xx(Tan) -xx(CosH) -xx(SinH) -xx(TanH) -xx(Round) -xx(ATan2) -xx(VectorAngle) -xx(New) -xx(Alpha) -xx(Angle) -xx(Args) -xx(CeilingZ) -xx(FloorZ) -xx(Health) -xx(Pitch) -xx(SpecialName) -xx(Special) -xx(TID) -xx(TIDtoHate) -xx(WaterLevel) -xx(X) -xx(Y) -xx(Z) -xx(XY) -xx(MomX) -xx(MomY) -xx(MomZ) -xx(Threshold) -xx(DefThreshold) -xx(Abs) -xx(TeleportSpecial) -xx(Teleport) -xx(ACS_NamedExecuteWithResult) -xx(CallACS) -xx(Sqrt) -xx(CheckClass) -xx(IsPointerEqual) -xx(Pick) -xx(Mass) -xx(VelX) -xx(VelY) -xx(VelZ) -xx(Accuracy) -xx(Stamina) -xx(Radius) -xx(ReactionTime) -xx(MeleeRange) -xx(Speed) -xx(FastSpeed) -xx(HowlSound) -xx(Clamp) -xx(VisibleStartAngle) -xx(VisibleStartPitch) -xx(VisibleEndAngle) -xx(VisibleEndPitch) -xx(Format) -xx(PickupMsg) -xx(Respawnable) -xx(ExplosionDamage) -xx(ExplosionRadius) -xx(DontHurtShooter) - -// Various actor names which are used internally -xx(MapSpot) -xx(PatrolPoint) -xx(PatrolSpecial) -xx(Communicator) -xx(PowerScanner) - -// Textmap properties -//xx(X) -//xx(Y) -xx(ZFloor) -xx(ZCeiling) -xx(Height) -//xx(Tid) -//xx(Angle) -xx(Type) -//xx(Special) -xx(Arg0) -xx(Arg1) -xx(Arg2) -xx(Arg3) -xx(Arg4) -xx(Arg0Str) -xx(Arg1Str) -xx(Id) -xx(MoreIds) -xx(V1) -xx(V2) - -xx(Sidefront) -xx(Sideback) -xx(Offsetx) -xx(Offsety) -xx(Texturetop) -xx(Texturebottom) -xx(Texturemiddle) -xx(Sector) -xx(Heightfloor) -xx(Heightceiling) -xx(Lightlevel) -xx(Texturefloor) -xx(Textureceiling) -xx(Nodecals) - -xx(Skill1) -xx(Skill2) -xx(Skill3) -xx(Skill4) -xx(Skill5) -xx(Skill6) -xx(Skill7) -xx(Skill8) -xx(Skill9) -xx(Skill10) -xx(Skill11) -xx(Skill12) -xx(Skill13) -xx(Skill14) -xx(Skill15) -xx(Skill16) -xx(Medium) -xx(Hard) -xx(Ambush) -xx(Dormant) -xx(Class0) -xx(Class1) -xx(Class2) -xx(Class3) -xx(Class4) -xx(Class5) -xx(Class6) -xx(Class7) -xx(Class8) -xx(Class9) -xx(Class10) -xx(Class11) -xx(Class12) -xx(Class13) -xx(Class14) -xx(Class15) -xx(Class16) -xx(Single) -xx(Coop) -xx(Dm) -xx(Translucent) -xx(Invisible) -xx(Friend) -xx(Strifeally) -xx(Standing) -xx(Countsecret) -xx(Score) -xx(Roll) -xx(Scale) -xx(ScaleX) -xx(ScaleY) -xx(FriendlySeeBlocks) -xx(Floatbobphase) -xx(Floatbobstrength) -xx(Target) -xx(Master) -xx(Tracer) - -xx(Blocking) -xx(Blockmonsters) -xx(Twosided) -xx(Dontpegtop) -xx(Dontpegbottom) -xx(Secret) -xx(Blocksound) -xx(Dontdraw) -xx(Mapped) -xx(Monsteractivate) -xx(Blockplayers) -xx(Blockeverything) -xx(Zoneboundary) -xx(Jumpover) -xx(Blockfloaters) -xx(Clipmidtex) -xx(Wrapmidtex) -xx(Midtex3d) -xx(Checkswitchrange) -xx(Firstsideonly) -xx(Transparent) -xx(Passuse) -xx(Repeatspecial) -xx(Conversation) -xx(Locknumber) -xx(Midtex3dimpassible) -xx(Revealed) -xx(AutomapStyle) -xx(DrawFullHeight) - -xx(Playercross) -xx(Playeruse) -xx(Playeruseback) -xx(Monstercross) -xx(Impact) -xx(Playerpush) -xx(Missilecross) -xx(Anycross) -xx(Monsteruse) -xx(Monsterpush) - -xx(ZDoom) -xx(ZDoomTranslated) -xx(Vavoom) -xx(GZDoom) - -xx(Xpanningfloor) -xx(Ypanningfloor) -xx(Xpanningceiling) -xx(Ypanningceiling) -xx(Xscalefloor) -xx(Yscalefloor) -xx(Xscaleceiling) -xx(Yscaleceiling) -xx(Rotationfloor) -xx(Rotationceiling) -xx(Lightfloor) -xx(Lightceiling) -xx(Lightfloorabsolute) -xx(Lightceilingabsolute) -xx(Gravity) -xx(Lightcolor) -xx(Fadecolor) -xx(Color_Floor) -xx(Color_Ceiling) -xx(Color_Walltop) -xx(Color_Wallbottom) -xx(Color_Sprites) -xx(ColorAdd_Floor) -xx(ColorAdd_Ceiling) -xx(ColorAdd_Sprites) -xx(ColorAdd_Walls) -xx(NoSkyWalls) -xx(Desaturation) -xx(SoundSequence) -xx(Silent) -xx(Nofallingdamage) -xx(Dropactors) -xx(NoRespawn) -xx(Alphafloor) -xx(Alphaceiling) -xx(Renderstylefloor) -xx(Renderstyleceiling) -xx(Waterzone) -xx(portal_ceil_blocksound) -xx(portal_ceil_disabled) -xx(portal_ceil_nopass) -xx(portal_ceil_norender) -xx(portal_ceil_overlaytype) -xx(portal_ceil_useglobaltex) -xx(portal_floor_blocksound) -xx(portal_floor_disabled) -xx(portal_floor_nopass) -xx(portal_floor_norender) -xx(portal_floor_overlaytype) -xx(portal_floor_useglobaltex) -xx(scroll_ceil_x) -xx(scroll_ceil_y) -xx(scroll_ceil_type) -xx(scroll_floor_x) -xx(scroll_floor_y) -xx(scroll_floor_type) - -xx(offsetx_top) -xx(offsety_top) -xx(offsetx_mid) -xx(offsety_mid) -xx(offsetx_bottom) -xx(offsety_bottom) -xx(scalex_top) -xx(scaley_top) -xx(scalex_mid) -xx(scaley_mid) -xx(scalex_bottom) -xx(scaley_bottom) -xx(light) -xx(lightabsolute) -xx(lightfog) -xx(nofakecontrast) -xx(smoothlighting) -xx(blockprojectiles) -xx(blockuse) -xx(hidden) -xx(blocksight) -xx(blockhitscan) - -xx(nogradient_top) -xx(flipgradient_top) -xx(clampgradient_top) -xx(useowncolors_top) -xx(uppercolor_top) -xx(lowercolor_top) -xx(nogradient_mid) -xx(flipgradient_mid) -xx(clampgradient_mid) -xx(useowncolors_mid) -xx(uppercolor_mid) -xx(lowercolor_mid) -xx(nogradient_bottom) -xx(flipgradient_bottom) -xx(clampgradient_bottom) -xx(useowncolors_bottom) -xx(uppercolor_bottom) -xx(lowercolor_bottom) -xx(useowncoloradd_top) -xx(coloradd_top) -xx(useowncoloradd_mid) -xx(coloradd_mid) -xx(useowncoloradd_bottom) -xx(coloradd_bottom) -xx(colorization_top) -xx(colorization_mid) -xx(colorization_bottom) -xx(colorization_floor) -xx(colorization_ceiling) - -xx(Renderstyle) - -xx(ceilingplane_a) -xx(ceilingplane_b) -xx(ceilingplane_c) -xx(ceilingplane_d) -xx(floorplane_a) -xx(floorplane_b) -xx(floorplane_c) -xx(floorplane_d) -xx(damageamount) -xx(damagetype) -xx(damageinterval) -xx(leakiness) -xx(damageterraineffect) -xx(damagehazard) -xx(floorterrain) -xx(ceilingterrain) -xx(floor_reflect) -xx(ceiling_reflect) -xx(floorglowcolor) -xx(floorglowheight) -xx(ceilingglowcolor) -xx(ceilingglowheight) -xx(fogdensity) -xx(Static) -xx(Staticconst) -xx(DeathmatchStatusScreen) -xx(CoopStatusScreen) -xx(RavenStatusScreen) -xx(StatusbarWidget) -xx(StatusbarHead) -xx(StatusbarCondition) -xx(Next) -xx(Prev) -xx(Children) -xx(Owner) - -xx(HealthFloor) -xx(HealthCeiling) -xx(Health3D) -xx(DamageSpecial) -xx(DeathSpecial) -xx(HealthFloorGroup) -xx(HealthCeilingGroup) -xx(Health3DGroup) -xx(HealthGroup) - -// USDF keywords -xx(Amount) -xx(Text) -xx(Displaycost) -xx(Yesmessage) -xx(Nomessage) -xx(Log) -xx(Giveitem) -xx(Nextpage) -xx(Closedialog) -xx(Cost) -xx(Page) -xx(Count) -xx(Name) -xx(Panel) -xx(Dialog) -xx(Ifitem) -xx(Choice) -xx(Link) -xx(Goodbye) -xx(Require) -xx(Exclude) -xx(Userstring) -xx(Sky) -xx(Pagename) - -// Special menus -xx(Mainmenu) -xx(MainmenuTextOnly) -xx(Episodemenu) -xx(Playerclassmenu) -xx(HexenDefaultPlayerclassmenu) -xx(Skillmenu) -xx(Startgame) -xx(StartgameConfirm) -xx(StartgameConfirmed) -xx(Loadgamemenu) -xx(Savegamemenu) -xx(Readthismenu) -xx(Optionsmenu) -xx(Quitmenu) -xx(Savemenu) -xx(Playermenu) -xx(EndGameMenu) - -xx(Playerbox) -xx(Team) -xx(Color) -xx(Red) -xx(Green) -xx(Blue) -xx(Skin) -xx(Gender) -xx(Autoaim) -xx(Switch) -xx(Playerdisplay) -xx(Controlmessage) -xx(Crosshairs) -xx(Colorpickermenu) -xx(Mididevices) -xx(Aldevices) -xx(Alresamplers) -xx(CustomizeControls) -xx(MessageOptions) -xx(AutomapOptions) -xx(ScoreboardOptions) -xx(MapColorMenu) -xx(GameplayOptions) -xx(CompatibilityOptions) -xx(MouseOptions) -xx(JoystickOptions) -xx(SoundOptions) -xx(AdvSoundOptions) -xx(ModReplayerOptions) -xx(VideoOptions) -xx(JoystickConfigMenu) -xx(VMEnterText) -xx(VMTestText) -xx(VideoModeMenu) -xx(res_0) -xx(res_1) -xx(res_2) -xx(res_3) -xx(res_4) -xx(res_5) -xx(res_6) -xx(res_7) -xx(res_8) -xx(res_9) -xx(AlwaysRun) - -// end sequences -xx(Inter_Chess) -xx(Inter_Strife) -xx(Inter_Strife_Good) -xx(Inter_Strife_Sad) -xx(Inter_Strife_Bad) -xx(Inter_Strife_Lose) -xx(Inter_Strife_MAP03) -xx(Inter_Strife_MAP10) -xx(Multiplayer) - -// more stuff -xx(ColorSet) -xx(NeverSwitchOnPickup) -xx(MoveBob) -xx(StillBob) -xx(ClassicFlight) -xx(WBobSpeed) -xx(PlayerClass) -xx(MonsterClass) -xx(MorphedMonster) -xx(Wi_NoAutostartMap) - -xx(Duration) -xx(MorphStyle) -xx(MorphFlash) -xx(UnMorphFlash) -xx(Powerup) -xx(EffectTics) -xx(PowerupGiver) -xx(BlendColor) -xx(Strength) -xx(Mode) -xx(PowerupType) -xx(PlayerPawn) -xx(Key) - -// Decorate compatibility functions -xx(BuiltinTypeCheck) -xx(BuiltinRandom) -xx(BuiltinRandom2) -xx(BuiltinFRandom) -xx(BuiltinCallLineSpecial) -xx(BuiltinNameToClass) -xx(BuiltinFindMultiNameState) -xx(BuiltinFindSingleNameState) -xx(BuiltinHandleRuntimeState) -xx(BuiltinGetDefault) -xx(BuiltinClassCast) -xx(BuiltinFormat) -xx(Damage) -xx(Noattack) - -// basic type names -xx(Default) -xx(sByte) -xx(Byte) -xx(Short) -xx(uShort) -xx(Int) -xx(uInt) -xx(Bool) -xx(uint8) -xx(int8) -xx(uint16) -xx(int16) -xx(Float) -xx(Float32) -xx(Float64) -xx(Double) -xx(String) -xx(Vector) -xx(Map) -xx(Array) -xx(Include) -xx(Sound) -xx(State) -xx(Fixed) -xx(Vector2) -xx(Vector3) -xx(let) - -xx(Min) -xx(Max) -xx(Min_Normal) -xx(Min_Denormal) -xx(Epsilon) -xx(NaN) -xx(Infinity) -xx(Dig) -xx(Min_Exp) -xx(Max_Exp) -xx(Mant_Dig) -xx(Min_10_Exp) -xx(Max_10_Exp) - -// implicit function parameters -xx(self) -xx(invoker) -xx(stateinfo) - -xx(__decorate_internal_int__) -xx(__decorate_internal_bool__) -xx(__decorate_internal_float__) -xx(ResolveState) - -xx(DamageFunction) -xx(Length) -xx(Unit) -xx(Size) -xx(Push) -xx(Insert) -xx(Copy) -xx(Move) -xx(Voidptr) -xx(StateLabel) -xx(SpriteID) -xx(TextureID) -xx(Overlay) -xx(IsValid) -xx(IsNull) -xx(Exists) -xx(SetInvalid) -xx(SetNull) - -xx(A_Punch) -xx(A_FirePistol) -xx(A_FireShotgun) -xx(A_FireShotgun2) -xx(A_FireCGun) -xx(A_FireMissile) -xx(A_Saw) -xx(A_FirePlasma) -xx(A_FireBFG) -xx(A_FireOldBFG) -xx(A_FireRailgun) - -// color channels -xx(a) -xx(r) -xx(g) -xx(b) - -// Special translation names -xx(RainPillar1) -xx(RainPillar2) -xx(RainPillar3) -xx(RainPillar4) -xx(RainPillar5) -xx(RainPillar6) -xx(RainPillar7) -xx(RainPillar8) - -xx(Player1) -xx(Player2) -xx(Player3) -xx(Player4) -xx(Player5) -xx(Player6) -xx(Player7) -xx(Player8) -xx(PlayerChunk) -xx(RestrictedToPlayerClass) -xx(ForbiddenToPlayerClass) - -xx(Prototype) -xx(Void) -xx(Label) -xx(Pointer) -xx(Enum) -xx(StaticArray) -xx(DynArray) -xx(Struct) -xx(ReflectType) -xx(MessageBoxMenu) - -xx(Both) -xx(Physical) -xx(Visual) - -xx(OptionMenuItemSubmenu) -xx(OptionMenuItemCommand) -xx(OptionMenuItemControlBase) -xx(OptionMenuItemOptionBase) -xx(OptionMenuSliderBase) -xx(OptionMenuFieldBase) -xx(OptionMenuItemColorPicker) -xx(OptionMenuItemStaticText) -xx(OptionMenuItemStaticTextSwitchable) - -// blacklisted former CVARs -xx(snd_waterlp) -xx(snd_output) -xx(snd_output_format) -xx(snd_speakermode) -xx(snd_resampler) - -// ScriptUtil entry points -xx(ScriptUtil) -xx(SetMarineWeapon) -xx(SetMarineSprite) -xx(GiveInventory) -xx(TakeInventory) -xx(ClearInventory) - -// Weapon member fields that need direct access -xx(Ammo1) -xx(Ammo2) -xx(AmmoType1) -xx(AmmoType2) -xx(AmmoGive1) -xx(AmmoGive2) -xx(AmmoUse1) -xx(SisterWeapon) -xx(BobStyle) -xx(Kickback) -xx(MinSelAmmo1) -xx(bDehAmmo) -xx(FOVScale) -xx(LookScale) -xx(YAdjust) -xx(Crosshair) -xx(WeaponFlags) -xx(DropTime) -xx(PickupSound) - -// PlayerPawn member fields -xx(ColorRangeStart) -xx(ColorRangeEnd) -xx(InvFirst) -xx(ForwardMove1) -xx(ForwardMove2) -xx(SideMove1) -xx(SideMove2) -xx(Face) -xx(Slot) -xx(SoundClass) -xx(ViewBob) -xx(DamageFade) -xx(MaxHealth) -xx(crouchsprite) -xx(UseRange) -xx(AttackZOffset) -xx(SpawnMask) -xx(ScoreIcon) -xx(ViewHeight) -xx(FallingScreamMinSpeed) -xx(FallingScreamMaxSpeed) -xx(GruntSpeed) -xx(JumpZ) -xx(MugShotMaxHealth) -xx(BonusHealth) -xx(PlayerFlags) -xx(InvSel) -xx(FullHeight) - -xx(BlueCard) -xx(YellowCard) -xx(RedCard) -xx(BlueSkull) -xx(YellowSkull) -xx(RedSkull) -xx(DynamicLight) -xx(SpotInnerAngle) -xx(SpotOuterAngle) -xx(lightflags) -xx(lighttype) -xx(InternalDynamicLight) -xx(_a_chase_default) -xx(MapMarker) -xx(Spawn2) -xx(LevelLocals) -xx(Level) -xx(PlayerTeam) -xx(PlayerColors) -xx(PlayerSkin) -xx(NewPlayerMenu) -xx(AltHud) diff --git a/src/utility/nodebuilder/nodebuild.cpp b/src/utility/nodebuilder/nodebuild.cpp index 8955060ff4c..58b20f62595 100644 --- a/src/utility/nodebuilder/nodebuild.cpp +++ b/src/utility/nodebuilder/nodebuild.cpp @@ -150,10 +150,10 @@ int FNodeBuilder::CreateNode (uint32_t set, unsigned int count, fixed_t bbox[4]) D(PrintSet (2, set2)); node.intchildren[0] = CreateNode (set1, count1, node.nb_bbox[0]); node.intchildren[1] = CreateNode (set2, count2, node.nb_bbox[1]); - bbox[BOXTOP] = MAX (node.nb_bbox[0][BOXTOP], node.nb_bbox[1][BOXTOP]); - bbox[BOXBOTTOM] = MIN (node.nb_bbox[0][BOXBOTTOM], node.nb_bbox[1][BOXBOTTOM]); - bbox[BOXLEFT] = MIN (node.nb_bbox[0][BOXLEFT], node.nb_bbox[1][BOXLEFT]); - bbox[BOXRIGHT] = MAX (node.nb_bbox[0][BOXRIGHT], node.nb_bbox[1][BOXRIGHT]); + bbox[BOXTOP] = max (node.nb_bbox[0][BOXTOP], node.nb_bbox[1][BOXTOP]); + bbox[BOXBOTTOM] = min (node.nb_bbox[0][BOXBOTTOM], node.nb_bbox[1][BOXBOTTOM]); + bbox[BOXLEFT] = min (node.nb_bbox[0][BOXLEFT], node.nb_bbox[1][BOXLEFT]); + bbox[BOXRIGHT] = max (node.nb_bbox[0][BOXRIGHT], node.nb_bbox[1][BOXRIGHT]); return (int)Nodes.Push (node); } else @@ -392,7 +392,7 @@ bool FNodeBuilder::CheckSubsectorOverlappingSegs (uint32_t set, node_t &node, ui { if (Segs[seg2].linedef == -1) { // Do not put minisegs into a new subsector. - swapvalues (seg1, seg2); + std::swap (seg1, seg2); } D(Printf(PRINT_LOG, "Need to synthesize a splitter for set %d on seg %d (ov)\n", set, seg2)); splitseg = UINT_MAX; @@ -496,8 +496,9 @@ int FNodeBuilder::SelectSplitter (uint32_t set, node_t &node, uint32_t &splitseg } if (bestseg == UINT_MAX) - { // No lines split any others into two sets, so this is a convex region. - D(Printf (PRINT_LOG, "set %d, step %d, nosplit %d has no good splitter (%d)\n", set, step, nosplit, nosplitters)); + { + // No lines split any others into two sets, so this is a convex region. + D(Printf (PRINT_LOG, "set %d, step %d, nosplit %d has no good splitter (%d)\n", set, step, nosplit, nosplitters)); return nosplitters ? -1 : 0; } @@ -643,7 +644,7 @@ int FNodeBuilder::Heuristic (node_t &node, uint32_t set, bool honorNoSplit) frac = 1 - frac; } int penalty = int(1 / frac); - score = MAX(score - penalty, 1); + score = std::max(score - penalty, 1); D(Printf ("Penalized splitter by %d for being near endpt of seg %d (%f).\n", penalty, i, frac)); } @@ -752,6 +753,54 @@ int FNodeBuilder::Heuristic (node_t &node, uint32_t set, bool honorNoSplit) return score; } +void FNodeBuilder::DoGLSegSplit (uint32_t set, node_t &node, uint32_t splitseg, uint32_t &outset0, uint32_t &outset1, int side, int sidev0, int sidev1, bool hack) +{ + FPrivSeg *seg = &Segs[set]; + + if (side >= 0 && GLNodes) + { + if (sidev0 == 0) + { + double dist1 = AddIntersection (node, seg->v1); + if (sidev1 == 0) + { + double dist2 = AddIntersection (node, seg->v2); + FSplitSharer share = { dist1, set, dist2 > dist1 }; + SplitSharers.Push (share); + } + } + else if (sidev1 == 0) + { + AddIntersection (node, seg->v2); + } + } + + if (hack && GLNodes) + { + uint32_t newback, newfront; + + newback = AddMiniseg (seg->v2, seg->v1, UINT_MAX, set, splitseg); + if (HackMate == UINT_MAX) + { + newfront = AddMiniseg (Segs[set].v1, Segs[set].v2, newback, set, splitseg); + Segs[newfront].next = outset0; + outset0 = newfront; + } + else + { + newfront = HackMate; + Segs[newfront].partner = newback; + Segs[newback].partner = newfront; + } + Segs[newback].frontsector = Segs[newback].backsector = + Segs[newfront].frontsector = Segs[newfront].backsector = + Segs[set].frontsector; + + Segs[newback].next = outset1; + outset1 = newback; + } +} + void FNodeBuilder::SplitSegs (uint32_t set, node_t &node, uint32_t splitseg, uint32_t &outset0, uint32_t &outset1, unsigned int &count0, unsigned int &count1) { unsigned int _count0 = 0; @@ -760,14 +809,15 @@ void FNodeBuilder::SplitSegs (uint32_t set, node_t &node, uint32_t splitseg, uin outset1 = UINT_MAX; Events.DeleteAll (); + UnsetSegs.Clear (); SplitSharers.Clear (); while (set != UINT_MAX) { + bool unset = false; bool hack; FPrivSeg *seg = &Segs[set]; int next = seg->next; - int sidev[2], side; if (HackSeg == set) @@ -844,73 +894,61 @@ void FNodeBuilder::SplitSegs (uint32_t set, node_t &node, uint32_t splitseg, uin } else { - // all that matters here is to prevent a crash so we must make sure that we do not end up with all segs being sorted to the same side - even if this may not be correct. - // But if we do not do that this code would not be able to move on. Just discarding the seg is also not an option because it won't guarantee that we achieve an actual split. - if (_count0 == 0) - { - side = 0; - seg->next = outset0; - outset0 = set; - _count0++; - } - else - { - side = 1; - seg->next = outset1; - outset1 = set; - _count1++; - } + // Sal May 28 2023 + // If all of the worst stars align: + // - The very first seg in the list doesn't know which side it should go to and makes it here. 0 are in front, so it goes to front. + // - Literally every other seg in the list all want to go to the front side from the other metrics + // - Oops! Now there's nothing in the back side! + // So we need to collect these now and do them later, otherwise the crash prevention fails. + UnsetSegs.Push(set); + unset = true; } break; } - if (side >= 0 && GLNodes) + if (unset == false) { - if (sidev[0] == 0) - { - double dist1 = AddIntersection (node, seg->v1); - if (sidev[1] == 0) - { - double dist2 = AddIntersection (node, seg->v2); - FSplitSharer share = { dist1, set, dist2 > dist1 }; - SplitSharers.Push (share); - } - } - else if (sidev[1] == 0) - { - AddIntersection (node, seg->v2); - } + DoGLSegSplit (set, node, splitseg, outset0, outset1, side, sidev[0], sidev[1], hack); } - if (hack && GLNodes) - { - uint32_t newback, newfront; + set = next; + } - newback = AddMiniseg (seg->v2, seg->v1, UINT_MAX, set, splitseg); - if (HackMate == UINT_MAX) - { - newfront = AddMiniseg (Segs[set].v1, Segs[set].v2, newback, set, splitseg); - Segs[newfront].next = outset0; - outset0 = newfront; - } - else - { - newfront = HackMate; - Segs[newfront].partner = newback; - Segs[newback].partner = newfront; - } - Segs[newback].frontsector = Segs[newback].backsector = - Segs[newfront].frontsector = Segs[newfront].backsector = - Segs[set].frontsector; + for (unsigned int i = 0; i < UnsetSegs.Size(); ++i) + { + uint32_t unsetID = UnsetSegs[i]; + FPrivSeg *seg = &Segs[unsetID]; + int sidev[2], side; + + side = ClassifyLine (node, &Vertices[seg->v1], &Vertices[seg->v2], sidev); - Segs[newback].next = outset1; - outset1 = newback; + // all that matters here is to prevent a crash so we must make sure that we do not end up with all segs being sorted to the same side - even if this may not be correct. + // But if we do not do that this code would not be able to move on. Just discarding the seg is also not an option because it won't guarantee that we achieve an actual split. + + if (_count0 == 0) + { + side = 0; + seg->next = outset0; + outset0 = unsetID; + _count0++; } - set = next; + else + { + side = 1; + seg->next = outset1; + outset1 = unsetID; + _count1++; + } + + DoGLSegSplit (unsetID, node, splitseg, outset0, outset1, side, sidev[0], sidev[1], false); } + FixSplitSharers (node); if (GLNodes) { AddMinisegs (node, splitseg, outset0, outset1); } + + assert(_count0 != 0 && _count1 != 0); + count0 = _count0; count1 = _count1; } diff --git a/src/utility/nodebuilder/nodebuild.h b/src/utility/nodebuilder/nodebuild.h index 0618f72477f..1f5ef566cb2 100644 --- a/src/utility/nodebuilder/nodebuild.h +++ b/src/utility/nodebuilder/nodebuild.h @@ -173,8 +173,8 @@ class FNodeBuilder fixed64_t MinX, MinY, MaxX, MaxY; int BlocksWide, BlocksTall; - enum { BLOCK_SHIFT = 8 + FRACBITS }; - enum { BLOCK_SIZE = 1 << BLOCK_SHIFT }; + static constexpr int BLOCK_SHIFT = 8 + FRACBITS; + static constexpr int BLOCK_SIZE = 1 << BLOCK_SHIFT; int InsertVertex (FPrivVert &vert); inline int GetBlock (fixed64_t x, fixed64_t y) @@ -269,6 +269,7 @@ class FNodeBuilder TArray Colinear; // Loops with edges colinear to a splitter FEventTree Events; // Vertices intersected by the current splitter + TArray UnsetSegs; // Segs with no definitive side in current splitter TArray SplitSharers; // Segs colinear with the current splitter uint32_t HackSeg; // Seg to force to back of splitter @@ -294,7 +295,9 @@ class FNodeBuilder void CreateSubsectorsForReal (); bool CheckSubsector (uint32_t set, node_t &node, uint32_t &splitseg); bool CheckSubsectorOverlappingSegs (uint32_t set, node_t &node, uint32_t &splitseg); - bool ShoveSegBehind (uint32_t set, node_t &node, uint32_t seg, uint32_t mate); int SelectSplitter (uint32_t set, node_t &node, uint32_t &splitseg, int step, bool nosplit); + bool ShoveSegBehind (uint32_t set, node_t &node, uint32_t seg, uint32_t mate); + int SelectSplitter (uint32_t set, node_t &node, uint32_t &splitseg, int step, bool nosplit); + void DoGLSegSplit (uint32_t set, node_t &node, uint32_t splitseg, uint32_t &outset0, uint32_t &outset1, int side, int sidev0, int sidev1, bool hack); void SplitSegs (uint32_t set, node_t &node, uint32_t splitseg, uint32_t &outset0, uint32_t &outset1, unsigned int &count0, unsigned int &count1); uint32_t SplitSeg (uint32_t segnum, int splitvert, int v1InFront); int Heuristic (node_t &node, uint32_t set, bool honorNoSplit); diff --git a/src/utility/nodebuilder/nodebuild_events.cpp b/src/utility/nodebuilder/nodebuild_events.cpp index 84e187081e2..3ac42a6c21a 100644 --- a/src/utility/nodebuilder/nodebuild_events.cpp +++ b/src/utility/nodebuilder/nodebuild_events.cpp @@ -218,7 +218,7 @@ void FEventTree::PrintTree (const FEvent *event) const if (event != &Nil) { PrintTree(event->Left); - sprintf(buff, " Distance %g, vertex %d, seg %u\n", + snprintf(buff, sizeof(buff), " Distance %g, vertex %d, seg %u\n", g_sqrt(event->Distance/4294967296.0), event->Info.Vertex, (unsigned)event->Info.FrontSeg); Printf(PRINT_LOG, "%s", buff); PrintTree(event->Right); diff --git a/src/utility/nodebuilder/nodebuild_gl.cpp b/src/utility/nodebuilder/nodebuild_gl.cpp index d2b987e0488..6e9074210fb 100644 --- a/src/utility/nodebuilder/nodebuild_gl.cpp +++ b/src/utility/nodebuilder/nodebuild_gl.cpp @@ -99,7 +99,7 @@ void FNodeBuilder::FixSplitSharers (const node_t &node) // Use the CRT's printf so the formatting matches ZDBSP's D(char buff[200]); - D(sprintf(buff, "Considering events on seg %d(%d[%d,%d]->%d[%d,%d]) [%g:%g]\n", seg, + D(snprintf(buff, sizeof(buff), "Considering events on seg %d(%d[%d,%d]->%d[%d,%d]) [%g:%g]\n", seg, Segs[seg].v1, Vertices[Segs[seg].v1].x>>16, Vertices[Segs[seg].v1].y>>16, diff --git a/src/utility/nodebuilder/nodebuild_utility.cpp b/src/utility/nodebuilder/nodebuild_utility.cpp index ffd5f61e8c3..de3e32759ac 100644 --- a/src/utility/nodebuilder/nodebuild_utility.cpp +++ b/src/utility/nodebuilder/nodebuild_utility.cpp @@ -453,14 +453,14 @@ void FNodeBuilder::FindPolyContainers (TArray &spots, TArrayx, v1->y, dx, dy) <= 0) { - fixed_t t = DivScale30 (center.fixY() - v1->y, dy); - fixed_t sx = v1->x + MulScale30 (dx, t); + fixed_t t = DivScale (center.fixY() - v1->y, dy, 30); + fixed_t sx = v1->x + MulScale(dx, t, 30); fixed_t dist = sx - spot->x; if (dist < closestdist && dist >= 0) { closestdist = dist; - closestseg = (long)j; + closestseg = j; } } } @@ -698,10 +698,10 @@ int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert) // If a vertex is near a block boundary, then it will be inserted on // both sides of the boundary so that SelectVertexClose can find // it by checking in only one block. - fixed64_t minx = MAX (MinX, fixed64_t(vert.x) - VERTEX_EPSILON); - fixed64_t maxx = MIN (MaxX, fixed64_t(vert.x) + VERTEX_EPSILON); - fixed64_t miny = MAX (MinY, fixed64_t(vert.y) - VERTEX_EPSILON); - fixed64_t maxy = MIN (MaxY, fixed64_t(vert.y) + VERTEX_EPSILON); + fixed64_t minx = max (MinX, fixed64_t(vert.x) - VERTEX_EPSILON); + fixed64_t maxx = min (MaxX, fixed64_t(vert.x) + VERTEX_EPSILON); + fixed64_t miny = max (MinY, fixed64_t(vert.y) - VERTEX_EPSILON); + fixed64_t maxy = min (MaxY, fixed64_t(vert.y) + VERTEX_EPSILON); int blk[4] = { diff --git a/src/utility/palentry.h b/src/utility/palentry.h deleted file mode 100644 index 8f4bfa6d8b1..00000000000 --- a/src/utility/palentry.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include - -struct PalEntry -{ - PalEntry() = default; - PalEntry (uint32_t argb) { d = argb; } - operator uint32_t () const { return d; } - void SetRGB(PalEntry other) - { - d = other.d & 0xffffff; - } - PalEntry Modulate(PalEntry other) const - { - if (isWhite()) - { - return other; - } - else if (other.isWhite()) - { - return *this; - } - else - { - other.r = (r * other.r) / 255; - other.g = (g * other.g) / 255; - other.b = (b * other.b) / 255; - return other; - } - } - int Luminance() const - { - return (r * 77 + g * 143 + b * 37) >> 8; - } - - void Decolorize() // this for 'nocoloredspritelighting' and not the same as desaturation. The normal formula results in a value that's too dark. - { - int v = (r + g + b); - r = g = b = ((255*3) + v + v) / 9; - } - bool isBlack() const - { - return (d & 0xffffff) == 0; - } - bool isWhite() const - { - return (d & 0xffffff) == 0xffffff; - } - PalEntry &operator= (const PalEntry &other) = default; - PalEntry &operator= (uint32_t other) { d = other; return *this; } - PalEntry InverseColor() const { PalEntry nc; nc.a = a; nc.r = 255 - r; nc.g = 255 - g; nc.b = 255 - b; return nc; } -#ifdef __BIG_ENDIAN__ - PalEntry (uint8_t ir, uint8_t ig, uint8_t ib) : a(0), r(ir), g(ig), b(ib) {} - PalEntry (uint8_t ia, uint8_t ir, uint8_t ig, uint8_t ib) : a(ia), r(ir), g(ig), b(ib) {} - union - { - struct - { - uint8_t a,r,g,b; - }; - uint32_t d; - }; -#else - PalEntry (uint8_t ir, uint8_t ig, uint8_t ib) : b(ib), g(ig), r(ir), a(0) {} - PalEntry (uint8_t ia, uint8_t ir, uint8_t ig, uint8_t ib) : b(ib), g(ig), r(ir), a(ia) {} - union - { - struct - { - uint8_t b,g,r,a; - }; - uint32_t d; - }; -#endif -}; - -inline int Luminance(int r, int g, int b) -{ - return (r * 77 + g * 143 + b * 37) >> 8; -} - diff --git a/src/utility/palette.cpp b/src/utility/palette.cpp deleted file mode 100644 index e79e68a545f..00000000000 --- a/src/utility/palette.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/* -** palette.cpp -** Palette and color utility functions -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "palette.h" -#include "palentry.h" - -/****************************/ -/* Palette management stuff */ -/****************************/ - -int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num) -{ - const PalEntry *pal = (const PalEntry *)pal_in; - int bestcolor = first; - int bestdist = 257 * 257 + 257 * 257 + 257 * 257; - - for (int color = first; color < num; color++) - { - int x = r - pal[color].r; - int y = g - pal[color].g; - int z = b - pal[color].b; - int dist = x*x + y*y + z*z; - if (dist < bestdist) - { - if (dist == 0) - return color; - - bestdist = dist; - bestcolor = color; - } - } - return bestcolor; -} - - -// [SP] Re-implemented BestColor for more precision rather than speed. This function is only ever called once until the game palette is changed. - -int PTM_BestColor (const uint32_t *pal_in, int r, int g, int b, bool reverselookup, float powtable_val, int first, int num) -{ - const PalEntry *pal = (const PalEntry *)pal_in; - static double powtable[256]; - static bool firstTime = true; - static float trackpowtable = 0.; - - double fbestdist = DBL_MAX, fdist; - int bestcolor = 0; - - if (firstTime || trackpowtable != powtable_val) - { - auto pt = powtable_val; - trackpowtable = pt; - firstTime = false; - for (int x = 0; x < 256; x++) powtable[x] = pow((double)x/255, (double)pt); - } - - for (int color = first; color < num; color++) - { - double x = powtable[abs(r-pal[color].r)]; - double y = powtable[abs(g-pal[color].g)]; - double z = powtable[abs(b-pal[color].b)]; - fdist = x + y + z; - if (color == first || (reverselookup?(fdist <= fbestdist):(fdist < fbestdist))) - { - if (fdist == 0 && !reverselookup) - return color; - - fbestdist = fdist; - bestcolor = color; - } - } - return bestcolor; -} - -#if defined(_M_X64) || defined(_M_IX86) || defined(__i386__) || defined(__amd64__) - -#ifdef _MSC_VER -#include -#endif -#include - -static void DoBlending_SSE2(const PalEntry *from, PalEntry *to, int count, int r, int g, int b, int a) -{ - __m128i blendcolor; - __m128i blendalpha; - __m128i zero; - __m128i blending256; - __m128i color1; - __m128i color2; - size_t unaligned; - - unaligned = ((size_t)from | (size_t)to) & 0xF; - -#if defined(__amd64__) || defined(_M_X64) - int64_t color; - - blending256 = _mm_set_epi64x(0x10001000100ll, 0x10001000100ll); - - color = ((int64_t)r << 32) | (g << 16) | b; - blendcolor = _mm_set_epi64x(color, color); - - color = ((int64_t)a << 32) | (a << 16) | a; - blendalpha = _mm_set_epi64x(color, color); -#else - int color; - - blending256 = _mm_set_epi32(0x100, 0x1000100, 0x100, 0x1000100); - - color = (g << 16) | b; - blendcolor = _mm_set_epi32(r, color, r, color); - - color = (a << 16) | a; - blendalpha = _mm_set_epi32(a, color, a, color); -#endif - - blendcolor = _mm_mullo_epi16(blendcolor, blendalpha); // premultiply blend by alpha - blendalpha = _mm_subs_epu16(blending256, blendalpha); // one minus alpha - - zero = _mm_setzero_si128(); - - if (unaligned) - { - for (count >>= 2; count > 0; --count) - { - color1 = _mm_loadu_si128((__m128i *)from); - from += 4; - color2 = _mm_unpackhi_epi8(color1, zero); - color1 = _mm_unpacklo_epi8(color1, zero); - color1 = _mm_mullo_epi16(blendalpha, color1); - color2 = _mm_mullo_epi16(blendalpha, color2); - color1 = _mm_adds_epu16(blendcolor, color1); - color2 = _mm_adds_epu16(blendcolor, color2); - color1 = _mm_srli_epi16(color1, 8); - color2 = _mm_srli_epi16(color2, 8); - _mm_storeu_si128((__m128i *)to, _mm_packus_epi16(color1, color2)); - to += 4; - } - } - else - { - for (count >>= 2; count > 0; --count) - { - color1 = _mm_load_si128((__m128i *)from); - from += 4; - color2 = _mm_unpackhi_epi8(color1, zero); - color1 = _mm_unpacklo_epi8(color1, zero); - color1 = _mm_mullo_epi16(blendalpha, color1); - color2 = _mm_mullo_epi16(blendalpha, color2); - color1 = _mm_adds_epu16(blendcolor, color1); - color2 = _mm_adds_epu16(blendcolor, color2); - color1 = _mm_srli_epi16(color1, 8); - color2 = _mm_srli_epi16(color2, 8); - _mm_store_si128((__m128i *)to, _mm_packus_epi16(color1, color2)); - to += 4; - } - } -} -#endif - -void DoBlending (const PalEntry *from, PalEntry *to, int count, int r, int g, int b, int a) -{ - if (a == 0) - { - if (from != to) - { - memcpy (to, from, count * sizeof(uint32_t)); - } - return; - } - else if (a == 256) - { - uint32_t t = MAKERGB(r,g,b); - int i; - - for (i = 0; i < count; i++) - { - to[i] = t; - } - return; - } -#if defined(_M_X64) || defined(_M_IX86) || defined(__i386__) || defined(__amd64__) - else if (count >= 4) - { - int not3count = count & ~3; - DoBlending_SSE2 (from, to, not3count, r, g, b, a); - count &= 3; - if (count <= 0) - { - return; - } - from += not3count; - to += not3count; - } -#endif - int i, ia; - - ia = 256 - a; - r *= a; - g *= a; - b *= a; - - for (i = count; i > 0; i--, to++, from++) - { - to->r = (r + from->r * ia) >> 8; - to->g = (g + from->g * ia) >> 8; - to->b = (b + from->b * ia) >> 8; - } -} - -/****** Colorspace Conversion Functions ******/ - -// Code from http://www.cs.rit.edu/~yxv4997/t_convert.html - -// r,g,b values are from 0 to 1 -// h = [0,360], s = [0,1], v = [0,1] -// if s == 0, then h = -1 (undefined) - -// Green Doom guy colors: -// RGB - 0: { .46 1 .429 } 7: { .254 .571 .206 } 15: { .0317 .0794 .0159 } -// HSV - 0: { 116.743 .571 1 } 7: { 112.110 .639 .571 } 15: { 105.071 .800 .0794 } -void RGBtoHSV (float r, float g, float b, float *h, float *s, float *v) -{ - float min, max, delta, foo; - - if (r == g && g == b) - { - *h = 0; - *s = 0; - *v = r; - return; - } - - foo = r < g ? r : g; - min = (foo < b) ? foo : b; - foo = r > g ? r : g; - max = (foo > b) ? foo : b; - - *v = max; // v - - delta = max - min; - - *s = delta / max; // s - - if (r == max) - *h = (g - b) / delta; // between yellow & magenta - else if (g == max) - *h = 2 + (b - r) / delta; // between cyan & yellow - else - *h = 4 + (r - g) / delta; // between magenta & cyan - - *h *= 60; // degrees - if (*h < 0) - *h += 360; -} - -void HSVtoRGB (float *r, float *g, float *b, float h, float s, float v) -{ - int i; - float f, p, q, t; - - if (s == 0) - { // achromatic (grey) - *r = *g = *b = v; - return; - } - - h /= 60; // sector 0 to 5 - i = (int)floor (h); - f = h - i; // factorial part of h - p = v * (1 - s); - q = v * (1 - s * f); - t = v * (1 - s * (1 - f)); - - switch (i) - { - case 0: *r = v; *g = t; *b = p; break; - case 1: *r = q; *g = v; *b = p; break; - case 2: *r = p; *g = v; *b = t; break; - case 3: *r = p; *g = q; *b = v; break; - case 4: *r = t; *g = p; *b = v; break; - default: *r = v; *g = p; *b = q; break; - } -} - diff --git a/src/utility/palette.h b/src/utility/palette.h deleted file mode 100644 index 3e7c2f5ebae..00000000000 --- a/src/utility/palette.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -struct PalEntry; - -#define MAKERGB(r,g,b) uint32_t(((r)<<16)|((g)<<8)|(b)) -#define MAKEARGB(a,r,g,b) uint32_t(((a)<<24)|((r)<<16)|((g)<<8)|(b)) - -#define APART(c) (((c)>>24)&0xff) -#define RPART(c) (((c)>>16)&0xff) -#define GPART(c) (((c)>>8)&0xff) -#define BPART(c) ((c)&0xff) - -int BestColor(const uint32_t* pal, int r, int g, int b, int first = 1, int num = 255); -int PTM_BestColor(const uint32_t* pal_in, int r, int g, int b, bool reverselookup, float powtable, int first = 1, int num = 255); -void DoBlending(const PalEntry* from, PalEntry* to, int count, int r, int g, int b, int a); -// Colorspace conversion RGB <-> HSV -void RGBtoHSV (float r, float g, float b, float *h, float *s, float *v); -void HSVtoRGB (float *r, float *g, float *b, float h, float s, float v); diff --git a/src/utility/rapidjson/allocators.h b/src/utility/rapidjson/allocators.h deleted file mode 100644 index 98affe03fbf..00000000000 --- a/src/utility/rapidjson/allocators.h +++ /dev/null @@ -1,271 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ALLOCATORS_H_ -#define RAPIDJSON_ALLOCATORS_H_ - -#include "rapidjson.h" - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Allocator - -/*! \class rapidjson::Allocator - \brief Concept for allocating, resizing and freeing memory block. - - Note that Malloc() and Realloc() are non-static but Free() is static. - - So if an allocator need to support Free(), it needs to put its pointer in - the header of memory block. - -\code -concept Allocator { - static const bool kNeedFree; //!< Whether this allocator needs to call Free(). - - // Allocate a memory block. - // \param size of the memory block in bytes. - // \returns pointer to the memory block. - void* Malloc(size_t size); - - // Resize a memory block. - // \param originalPtr The pointer to current memory block. Null pointer is permitted. - // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) - // \param newSize the new size in bytes. - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); - - // Free a memory block. - // \param pointer to the memory block. Null pointer is permitted. - static void Free(void *ptr); -}; -\endcode -*/ - -/////////////////////////////////////////////////////////////////////////////// -// CrtAllocator - -//! C-runtime library allocator. -/*! This class is just wrapper for standard C library memory routines. - \note implements Allocator concept -*/ -class CrtAllocator { -public: - static const bool kNeedFree = true; - void* Malloc(size_t size) { - if (size) // behavior of malloc(0) is implementation defined. - return std::malloc(size); - else - return NULL; // standardize to returning NULL. - } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - (void)originalSize; - if (newSize == 0) { - std::free(originalPtr); - return NULL; - } - return std::realloc(originalPtr, newSize); - } - static void Free(void *ptr) { std::free(ptr); } -}; - -/////////////////////////////////////////////////////////////////////////////// -// MemoryPoolAllocator - -//! Default memory allocator used by the parser and DOM. -/*! This allocator allocate memory blocks from pre-allocated memory chunks. - - It does not free memory blocks. And Realloc() only allocate new memory. - - The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. - - User may also supply a buffer as the first chunk. - - If the user-buffer is full then additional chunks are allocated by BaseAllocator. - - The user-buffer is not deallocated by this allocator. - - \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. - \note implements Allocator concept -*/ -template -class MemoryPoolAllocator { -public: - static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) - - //! Constructor with chunkSize. - /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) - { - } - - //! Constructor with user-supplied buffer. - /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. - - The user buffer will not be deallocated when this allocator is destructed. - - \param buffer User supplied buffer. - \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). - \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) - { - RAPIDJSON_ASSERT(buffer != 0); - RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); - chunkHead_ = reinterpret_cast(buffer); - chunkHead_->capacity = size - sizeof(ChunkHeader); - chunkHead_->size = 0; - chunkHead_->next = 0; - } - - //! Destructor. - /*! This deallocates all memory chunks, excluding the user-supplied buffer. - */ - ~MemoryPoolAllocator() { - Clear(); - RAPIDJSON_DELETE(ownBaseAllocator_); - } - - //! Deallocates all memory chunks, excluding the user-supplied buffer. - void Clear() { - while (chunkHead_ && chunkHead_ != userBuffer_) { - ChunkHeader* next = chunkHead_->next; - baseAllocator_->Free(chunkHead_); - chunkHead_ = next; - } - if (chunkHead_ && chunkHead_ == userBuffer_) - chunkHead_->size = 0; // Clear user buffer - } - - //! Computes the total capacity of allocated memory chunks. - /*! \return total capacity in bytes. - */ - size_t Capacity() const { - size_t capacity = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) - capacity += c->capacity; - return capacity; - } - - //! Computes the memory blocks allocated. - /*! \return total used bytes. - */ - size_t Size() const { - size_t size = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) - size += c->size; - return size; - } - - //! Allocates a memory block. (concept Allocator) - void* Malloc(size_t size) { - if (!size) - return NULL; - - size = RAPIDJSON_ALIGN(size); - if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) - if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) - return NULL; - - void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; - chunkHead_->size += size; - return buffer; - } - - //! Resizes a memory block (concept Allocator) - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - if (originalPtr == 0) - return Malloc(newSize); - - if (newSize == 0) - return NULL; - - originalSize = RAPIDJSON_ALIGN(originalSize); - newSize = RAPIDJSON_ALIGN(newSize); - - // Do not shrink if new size is smaller than original - if (originalSize >= newSize) - return originalPtr; - - // Simply expand it if it is the last allocation and there is sufficient space - if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { - size_t increment = static_cast(newSize - originalSize); - if (chunkHead_->size + increment <= chunkHead_->capacity) { - chunkHead_->size += increment; - return originalPtr; - } - } - - // Realloc process: allocate and copy memory, do not free original buffer. - if (void* newBuffer = Malloc(newSize)) { - if (originalSize) - std::memcpy(newBuffer, originalPtr, originalSize); - return newBuffer; - } - else - return NULL; - } - - //! Frees a memory block (concept Allocator) - static void Free(void *ptr) { (void)ptr; } // Do nothing - -private: - //! Copy constructor is not permitted. - MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; - //! Copy assignment operator is not permitted. - MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; - - //! Creates a new chunk. - /*! \param capacity Capacity of the chunk in bytes. - \return true if success. - */ - bool AddChunk(size_t capacity) { - if (!baseAllocator_) - ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); - if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { - chunk->capacity = capacity; - chunk->size = 0; - chunk->next = chunkHead_; - chunkHead_ = chunk; - return true; - } - else - return false; - } - - static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. - - //! Chunk header for perpending to each chunk. - /*! Chunks are stored as a singly linked list. - */ - struct ChunkHeader { - size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). - size_t size; //!< Current size of allocated memory in bytes. - ChunkHeader *next; //!< Next chunk in the linked list. - }; - - ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. - size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. - void *userBuffer_; //!< User supplied buffer. - BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. - BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. -}; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/src/utility/rapidjson/error/en.h b/src/utility/rapidjson/error/en.h deleted file mode 100644 index 2db838bff23..00000000000 --- a/src/utility/rapidjson/error/en.h +++ /dev/null @@ -1,74 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ERROR_EN_H_ -#define RAPIDJSON_ERROR_EN_H_ - -#include "error.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(covered-switch-default) -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Maps error code of parsing into error message. -/*! - \ingroup RAPIDJSON_ERRORS - \param parseErrorCode Error code obtained in parsing. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. -*/ -inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { - switch (parseErrorCode) { - case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - - case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); - case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); - - case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); - - case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); - case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); - case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); - - case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); - - case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); - case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); - case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); - case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); - case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); - - case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); - case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); - case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); - - case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); - case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); - - default: return RAPIDJSON_ERROR_STRING("Unknown error."); - } -} - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/src/utility/rapidjson/error/error.h b/src/utility/rapidjson/error/error.h deleted file mode 100644 index 95cb31a72fe..00000000000 --- a/src/utility/rapidjson/error/error.h +++ /dev/null @@ -1,155 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ERROR_ERROR_H_ -#define RAPIDJSON_ERROR_ERROR_H_ - -#include "../rapidjson.h" - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -/*! \file error.h */ - -/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ERROR_CHARTYPE - -//! Character type of error messages. -/*! \ingroup RAPIDJSON_ERRORS - The default character type is \c char. - On Windows, user can define this macro as \c TCHAR for supporting both - unicode/non-unicode settings. -*/ -#ifndef RAPIDJSON_ERROR_CHARTYPE -#define RAPIDJSON_ERROR_CHARTYPE char -#endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_ERROR_STRING - -//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. -/*! \ingroup RAPIDJSON_ERRORS - By default this conversion macro does nothing. - On Windows, user can define this macro as \c _T(x) for supporting both - unicode/non-unicode settings. -*/ -#ifndef RAPIDJSON_ERROR_STRING -#define RAPIDJSON_ERROR_STRING(x) x -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// ParseErrorCode - -//! Error code of parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericReader::Parse, GenericReader::GetParseErrorCode -*/ -enum ParseErrorCode { - kParseErrorNone = 0, //!< No error. - - kParseErrorDocumentEmpty, //!< The document is empty. - kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. - - kParseErrorValueInvalid, //!< Invalid value. - - kParseErrorObjectMissName, //!< Missing a name for object member. - kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. - kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. - - kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. - - kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. - kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. - kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. - kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. - kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. - - kParseErrorNumberTooBig, //!< Number too big to be stored in double. - kParseErrorNumberMissFraction, //!< Miss fraction part in number. - kParseErrorNumberMissExponent, //!< Miss exponent in number. - - kParseErrorTermination, //!< Parsing was terminated. - kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. -}; - -//! Result of parsing (wraps ParseErrorCode) -/*! - \ingroup RAPIDJSON_ERRORS - \code - Document doc; - ParseResult ok = doc.Parse("[42]"); - if (!ok) { - fprintf(stderr, "JSON parse error: %s (%u)", - GetParseError_En(ok.Code()), ok.Offset()); - exit(EXIT_FAILURE); - } - \endcode - \see GenericReader::Parse, GenericDocument::Parse -*/ -struct ParseResult { -public: - //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0) {} - //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} - - //! Get the error code. - ParseErrorCode Code() const { return code_; } - //! Get the error offset, if \ref IsError(), 0 otherwise. - size_t Offset() const { return offset_; } - - //! Conversion to \c bool, returns \c true, iff !\ref IsError(). - operator bool() const { return !IsError(); } - //! Whether the result is an error. - bool IsError() const { return code_ != kParseErrorNone; } - - bool operator==(const ParseResult& that) const { return code_ == that.code_; } - bool operator==(ParseErrorCode code) const { return code_ == code; } - friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } - - //! Reset error code. - void Clear() { Set(kParseErrorNone); } - //! Update error code and offset. - void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } - -private: - ParseErrorCode code_; - size_t offset_; -}; - -//! Function pointer type of GetParseError(). -/*! \ingroup RAPIDJSON_ERRORS - - This is the prototype for \c GetParseError_X(), where \c X is a locale. - User can dynamically change locale in runtime, e.g.: -\code - GetParseErrorFunc GetParseError = GetParseError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); -\endcode -*/ -typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); - -RAPIDJSON_NAMESPACE_END - -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/src/utility/rapidjson/internal/strfunc.h b/src/utility/rapidjson/internal/strfunc.h deleted file mode 100644 index de41d8f9cc6..00000000000 --- a/src/utility/rapidjson/internal/strfunc.h +++ /dev/null @@ -1,58 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ -#define RAPIDJSON_INTERNAL_STRFUNC_H_ - -#include "../stream.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -//! Custom strlen() which works on different character types. -/*! \tparam Ch Character type (e.g. char, wchar_t, short) - \param s Null-terminated input string. - \return Number of characters in the string. - \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. -*/ -template -inline SizeType StrLen(const Ch* s) { - RAPIDJSON_ASSERT(s != 0); - const Ch* p = s; - while (*p) ++p; - return SizeType(p - s); -} - -//! Returns number of code points in a encoded string. -template -bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { - RAPIDJSON_ASSERT(s != 0); - RAPIDJSON_ASSERT(outCount != 0); - GenericStringStream is(s); - const typename Encoding::Ch* end = s + length; - SizeType count = 0; - while (is.src_ < end) { - unsigned codepoint; - if (!Encoding::Decode(is, &codepoint)) - return false; - count++; - } - *outCount = count; - return true; -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/src/utility/rapidjson/internal/strtod.h b/src/utility/rapidjson/internal/strtod.h deleted file mode 100644 index 289c413b07b..00000000000 --- a/src/utility/rapidjson/internal/strtod.h +++ /dev/null @@ -1,269 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_STRTOD_ -#define RAPIDJSON_STRTOD_ - -#include "ieee754.h" -#include "biginteger.h" -#include "diyfp.h" -#include "pow10.h" - -RAPIDJSON_NAMESPACE_BEGIN -namespace internal { - -inline double FastPath(double significand, int exp) { - if (exp < -308) - return 0.0; - else if (exp >= 0) - return significand * internal::Pow10(exp); - else - return significand / internal::Pow10(-exp); -} - -inline double StrtodNormalPrecision(double d, int p) { - if (p < -308) { - // Prevent expSum < -308, making Pow10(p) = 0 - d = FastPath(d, -308); - d = FastPath(d, p + 308); - } - else - d = FastPath(d, p); - return d; -} - -template -inline T Min3(T a, T b, T c) { - T m = a; - if (m > b) m = b; - if (m > c) m = c; - return m; -} - -inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { - const Double db(b); - const uint64_t bInt = db.IntegerSignificand(); - const int bExp = db.IntegerExponent(); - const int hExp = bExp - 1; - - int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; - - // Adjust for decimal exponent - if (dExp >= 0) { - dS_Exp2 += dExp; - dS_Exp5 += dExp; - } - else { - bS_Exp2 -= dExp; - bS_Exp5 -= dExp; - hS_Exp2 -= dExp; - hS_Exp5 -= dExp; - } - - // Adjust for binary exponent - if (bExp >= 0) - bS_Exp2 += bExp; - else { - dS_Exp2 -= bExp; - hS_Exp2 -= bExp; - } - - // Adjust for half ulp exponent - if (hExp >= 0) - hS_Exp2 += hExp; - else { - dS_Exp2 -= hExp; - bS_Exp2 -= hExp; - } - - // Remove common power of two factor from all three scaled values - int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); - dS_Exp2 -= common_Exp2; - bS_Exp2 -= common_Exp2; - hS_Exp2 -= common_Exp2; - - BigInteger dS = d; - dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); - - BigInteger bS(bInt); - bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); - - BigInteger hS(1); - hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); - - BigInteger delta(0); - dS.Difference(bS, &delta); - - return delta.Compare(hS); -} - -inline bool StrtodFast(double d, int p, double* result) { - // Use fast path for string-to-double conversion if possible - // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - if (p > 22 && p < 22 + 16) { - // Fast Path Cases In Disguise - d *= internal::Pow10(p - 22); - p = 22; - } - - if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 - *result = FastPath(d, p); - return true; - } - else - return false; -} - -// Compute an approximation and see if it is within 1/2 ULP -inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { - uint64_t significand = 0; - size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 - for (; i < length; i++) { - if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || - (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) - break; - significand = significand * 10u + static_cast(decimals[i] - '0'); - } - - if (i < length && decimals[i] >= '5') // Rounding - significand++; - - size_t remaining = length - i; - const unsigned kUlpShift = 3; - const unsigned kUlp = 1 << kUlpShift; - int64_t error = (remaining == 0) ? 0 : kUlp / 2; - - DiyFp v(significand, 0); - v = v.Normalize(); - error <<= -v.e; - - const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; - - int actualExp; - DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); - if (actualExp != dExp) { - static const DiyFp kPow10[] = { - DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 - DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 - DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 - DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 - DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 - DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 - DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 - }; - int adjustment = dExp - actualExp - 1; - RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); - v = v * kPow10[adjustment]; - if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit - error += kUlp / 2; - } - - v = v * cachedPower; - - error += kUlp + (error == 0 ? 0 : 1); - - const int oldExp = v.e; - v = v.Normalize(); - error <<= oldExp - v.e; - - const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); - unsigned precisionSize = 64 - effectiveSignificandSize; - if (precisionSize + kUlpShift >= 64) { - unsigned scaleExp = (precisionSize + kUlpShift) - 63; - v.f >>= scaleExp; - v.e += scaleExp; - error = (error >> scaleExp) + 1 + static_cast(kUlp); - precisionSize -= scaleExp; - } - - DiyFp rounded(v.f >> precisionSize, v.e + static_cast(precisionSize)); - const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; - const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; - if (precisionBits >= halfWay + static_cast(error)) { - rounded.f++; - if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) - rounded.f >>= 1; - rounded.e++; - } - } - - *result = rounded.ToDouble(); - - return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); -} - -inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { - const BigInteger dInt(decimals, length); - const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; - Double a(approx); - int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); - if (cmp < 0) - return a.Value(); // within half ULP - else if (cmp == 0) { - // Round towards even - if (a.Significand() & 1) - return a.NextPositiveDouble(); - else - return a.Value(); - } - else // adjustment - return a.NextPositiveDouble(); -} - -inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { - RAPIDJSON_ASSERT(d >= 0.0); - RAPIDJSON_ASSERT(length >= 1); - - double result; - if (StrtodFast(d, p, &result)) - return result; - - // Trim leading zeros - while (*decimals == '0' && length > 1) { - length--; - decimals++; - decimalPosition--; - } - - // Trim trailing zeros - while (decimals[length - 1] == '0' && length > 1) { - length--; - decimalPosition--; - exp++; - } - - // Trim right-most digits - const int kMaxDecimalDigit = 780; - if (static_cast(length) > kMaxDecimalDigit) { - int delta = (static_cast(length) - kMaxDecimalDigit); - exp += delta; - decimalPosition -= static_cast(delta); - length = kMaxDecimalDigit; - } - - // If too small, underflow to zero - if (int(length) + exp < -324) - return 0.0; - - if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) - return result; - - // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison - return StrtodBigInteger(result, decimals, length, decimalPosition, exp); -} - -} // namespace internal -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_STRTOD_ diff --git a/src/utility/rapidjson/istreamwrapper.h b/src/utility/rapidjson/istreamwrapper.h deleted file mode 100644 index f5fe28977eb..00000000000 --- a/src/utility/rapidjson/istreamwrapper.h +++ /dev/null @@ -1,115 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available. -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// http://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ -#define RAPIDJSON_ISTREAMWRAPPER_H_ - -#include "stream.h" -#include - -#ifdef __clang__ -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(padded) -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. -/*! - The classes can be wrapped including but not limited to: - - - \c std::istringstream - - \c std::stringstream - - \c std::wistringstream - - \c std::wstringstream - - \c std::ifstream - - \c std::fstream - - \c std::wifstream - - \c std::wfstream - - \tparam StreamType Class derived from \c std::basic_istream. -*/ - -template -class BasicIStreamWrapper { -public: - typedef typename StreamType::char_type Ch; - BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} - - Ch Peek() const { - typename StreamType::int_type c = stream_.peek(); - return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : '\0'; - } - - Ch Take() { - typename StreamType::int_type c = stream_.get(); - if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { - count_++; - return static_cast(c); - } - else - return '\0'; - } - - // tellg() may return -1 when failed. So we count by ourself. - size_t Tell() const { return count_; } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - // For encoding detection only. - const Ch* Peek4() const { - RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. - int i; - bool hasError = false; - for (i = 0; i < 4; ++i) { - typename StreamType::int_type c = stream_.get(); - if (c == StreamType::traits_type::eof()) { - hasError = true; - stream_.clear(); - break; - } - peekBuffer_[i] = static_cast(c); - } - for (--i; i >= 0; --i) - stream_.putback(peekBuffer_[i]); - return !hasError ? peekBuffer_ : 0; - } - -private: - BasicIStreamWrapper(const BasicIStreamWrapper&); - BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); - - StreamType& stream_; - size_t count_; //!< Number of characters read. Note: - mutable Ch peekBuffer_[4]; -}; - -typedef BasicIStreamWrapper IStreamWrapper; -typedef BasicIStreamWrapper WIStreamWrapper; - -#if defined(__clang__) || defined(_MSC_VER) -RAPIDJSON_DIAG_POP -#endif - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/src/utility/rapidjson/schema.h b/src/utility/rapidjson/schema.h deleted file mode 100644 index 8497d303155..00000000000 --- a/src/utility/rapidjson/schema.h +++ /dev/null @@ -1,2006 +0,0 @@ -// Tencent is pleased to support the open source community by making RapidJSON available-> -// -// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> -// -// Licensed under the MIT License (the "License"); you may not use this file except -// in compliance with the License-> You may obtain a copy of the License at -// -// http://opensource->org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied-> See the License for the -// specific language governing permissions and limitations under the License-> - -#ifndef RAPIDJSON_SCHEMA_H_ -#define RAPIDJSON_SCHEMA_H_ - -#include "document.h" -#include "pointer.h" -#include // abs, floor - -#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 -#endif - -#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) -#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 -#endif - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX -#include "internal/regex.h" -#elif RAPIDJSON_SCHEMA_USE_STDREGEX -#include -#endif - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX -#define RAPIDJSON_SCHEMA_HAS_REGEX 1 -#else -#define RAPIDJSON_SCHEMA_HAS_REGEX 0 -#endif - -#ifndef RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_VERBOSE 0 -#endif - -#if RAPIDJSON_SCHEMA_VERBOSE -#include "stringbuffer.h" -#endif - -RAPIDJSON_DIAG_PUSH - -#if defined(__GNUC__) -RAPIDJSON_DIAG_OFF(effc++) -#endif - -#ifdef __clang__ -RAPIDJSON_DIAG_OFF(weak-vtables) -RAPIDJSON_DIAG_OFF(exit-time-destructors) -RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) -RAPIDJSON_DIAG_OFF(variadic-macros) -#endif - -#ifdef _MSC_VER -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - -RAPIDJSON_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// -// Verbose Utilities - -#if RAPIDJSON_SCHEMA_VERBOSE - -namespace internal { - -inline void PrintInvalidKeyword(const char* keyword) { - printf("Fail keyword: %s\n", keyword); -} - -inline void PrintInvalidKeyword(const wchar_t* keyword) { - wprintf(L"Fail keyword: %ls\n", keyword); -} - -inline void PrintInvalidDocument(const char* document) { - printf("Fail document: %s\n\n", document); -} - -inline void PrintInvalidDocument(const wchar_t* document) { - wprintf(L"Fail document: %ls\n\n", document); -} - -inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { - printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); -} - -inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { - wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); -} - -} // namespace internal - -#endif // RAPIDJSON_SCHEMA_VERBOSE - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_INVALID_KEYWORD_RETURN - -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) -#else -#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) -#endif - -#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ -RAPIDJSON_MULTILINEMACRO_BEGIN\ - context.invalidKeyword = keyword.GetString();\ - RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ - return false;\ -RAPIDJSON_MULTILINEMACRO_END - -/////////////////////////////////////////////////////////////////////////////// -// Forward declarations - -template -class GenericSchemaDocument; - -namespace internal { - -template -class Schema; - -/////////////////////////////////////////////////////////////////////////////// -// ISchemaValidator - -class ISchemaValidator { -public: - virtual ~ISchemaValidator() {} - virtual bool IsValid() const = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// ISchemaStateFactory - -template -class ISchemaStateFactory { -public: - virtual ~ISchemaStateFactory() {} - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; - virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; - virtual void* CreateHasher() = 0; - virtual uint64_t GetHashCode(void* hasher) = 0; - virtual void DestroryHasher(void* hasher) = 0; - virtual void* MallocState(size_t size) = 0; - virtual void FreeState(void* p) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Hasher - -// For comparison of compound value -template -class Hasher { -public: - typedef typename Encoding::Ch Ch; - - Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} - - bool Null() { return WriteType(kNullType); } - bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } - bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } - bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } - bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Double(double d) { - Number n; - if (d < 0) n.u.i = static_cast(d); - else n.u.u = static_cast(d); - n.d = d; - return WriteNumber(n); - } - - bool RawNumber(const Ch* str, SizeType len, bool) { - WriteBuffer(kNumberType, str, len * sizeof(Ch)); - return true; - } - - bool String(const Ch* str, SizeType len, bool) { - WriteBuffer(kStringType, str, len * sizeof(Ch)); - return true; - } - - bool StartObject() { return true; } - bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } - bool EndObject(SizeType memberCount) { - uint64_t h = Hash(0, kObjectType); - uint64_t* kv = stack_.template Pop(memberCount * 2); - for (SizeType i = 0; i < memberCount; i++) - h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive - *stack_.template Push() = h; - return true; - } - - bool StartArray() { return true; } - bool EndArray(SizeType elementCount) { - uint64_t h = Hash(0, kArrayType); - uint64_t* e = stack_.template Pop(elementCount); - for (SizeType i = 0; i < elementCount; i++) - h = Hash(h, e[i]); // Use hash to achieve element order sensitive - *stack_.template Push() = h; - return true; - } - - bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } - - uint64_t GetHashCode() const { - RAPIDJSON_ASSERT(IsValid()); - return *stack_.template Top(); - } - -private: - static const size_t kDefaultSize = 256; - struct Number { - union U { - uint64_t u; - int64_t i; - }u; - double d; - }; - - bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } - - bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } - - bool WriteBuffer(Type type, const void* data, size_t len) { - // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ - uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); - const unsigned char* d = static_cast(data); - for (size_t i = 0; i < len; i++) - h = Hash(h, d[i]); - *stack_.template Push() = h; - return true; - } - - static uint64_t Hash(uint64_t h, uint64_t d) { - static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); - h ^= d; - h *= kPrime; - return h; - } - - Stack stack_; -}; - -/////////////////////////////////////////////////////////////////////////////// -// SchemaValidationContext - -template -struct SchemaValidationContext { - typedef Schema SchemaType; - typedef ISchemaStateFactory SchemaValidatorFactoryType; - typedef typename SchemaType::ValueType ValueType; - typedef typename ValueType::Ch Ch; - - enum PatternValidatorType { - kPatternValidatorOnly, - kPatternValidatorWithProperty, - kPatternValidatorWithAdditionalProperty - }; - - SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : - factory(f), - schema(s), - valueSchema(), - invalidKeyword(), - hasher(), - arrayElementHashCodes(), - validators(), - validatorCount(), - patternPropertiesValidators(), - patternPropertiesValidatorCount(), - patternPropertiesSchemas(), - patternPropertiesSchemaCount(), - valuePatternValidatorType(kPatternValidatorOnly), - propertyExist(), - inArray(false), - valueUniqueness(false), - arrayUniqueness(false) - { - } - - ~SchemaValidationContext() { - if (hasher) - factory.DestroryHasher(hasher); - if (validators) { - for (SizeType i = 0; i < validatorCount; i++) - factory.DestroySchemaValidator(validators[i]); - factory.FreeState(validators); - } - if (patternPropertiesValidators) { - for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) - factory.DestroySchemaValidator(patternPropertiesValidators[i]); - factory.FreeState(patternPropertiesValidators); - } - if (patternPropertiesSchemas) - factory.FreeState(patternPropertiesSchemas); - if (propertyExist) - factory.FreeState(propertyExist); - } - - SchemaValidatorFactoryType& factory; - const SchemaType* schema; - const SchemaType* valueSchema; - const Ch* invalidKeyword; - void* hasher; // Only validator access - void* arrayElementHashCodes; // Only validator access this - ISchemaValidator** validators; - SizeType validatorCount; - ISchemaValidator** patternPropertiesValidators; - SizeType patternPropertiesValidatorCount; - const SchemaType** patternPropertiesSchemas; - SizeType patternPropertiesSchemaCount; - PatternValidatorType valuePatternValidatorType; - PatternValidatorType objectPatternValidatorType; - SizeType arrayElementIndex; - bool* propertyExist; - bool inArray; - bool valueUniqueness; - bool arrayUniqueness; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Schema - -template -class Schema { -public: - typedef typename SchemaDocumentType::ValueType ValueType; - typedef typename SchemaDocumentType::AllocatorType AllocatorType; - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - typedef SchemaValidationContext Context; - typedef Schema SchemaType; - typedef GenericValue SValue; - friend class GenericSchemaDocument; - - Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : - allocator_(allocator), - enum_(), - enumCount_(), - not_(), - type_((1 << kTotalSchemaType) - 1), // typeless - validatorCount_(), - properties_(), - additionalPropertiesSchema_(), - patternProperties_(), - patternPropertyCount_(), - propertyCount_(), - minProperties_(), - maxProperties_(SizeType(~0)), - additionalProperties_(true), - hasDependencies_(), - hasRequired_(), - hasSchemaDependencies_(), - additionalItemsSchema_(), - itemsList_(), - itemsTuple_(), - itemsTupleCount_(), - minItems_(), - maxItems_(SizeType(~0)), - additionalItems_(true), - uniqueItems_(false), - pattern_(), - minLength_(0), - maxLength_(~SizeType(0)), - exclusiveMinimum_(false), - exclusiveMaximum_(false) - { - typedef typename SchemaDocumentType::ValueType ValueType; - typedef typename ValueType::ConstValueIterator ConstValueIterator; - typedef typename ValueType::ConstMemberIterator ConstMemberIterator; - - if (!value.IsObject()) - return; - - if (const ValueType* v = GetMember(value, GetTypeString())) { - type_ = 0; - if (v->IsString()) - AddType(*v); - else if (v->IsArray()) - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) - AddType(*itr); - } - - if (const ValueType* v = GetMember(value, GetEnumString())) - if (v->IsArray() && v->Size() > 0) { - enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { - typedef Hasher > EnumHasherType; - char buffer[256 + 24]; - MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); - EnumHasherType h(&hasherAllocator, 256); - itr->Accept(h); - enum_[enumCount_++] = h.GetHashCode(); - } - } - - if (schemaDocument) { - AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); - AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); - AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); - } - - if (const ValueType* v = GetMember(value, GetNotString())) { - schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); - notValidatorIndex_ = validatorCount_; - validatorCount_++; - } - - // Object - - const ValueType* properties = GetMember(value, GetPropertiesString()); - const ValueType* required = GetMember(value, GetRequiredString()); - const ValueType* dependencies = GetMember(value, GetDependenciesString()); - { - // Gather properties from properties/required/dependencies - SValue allProperties(kArrayType); - - if (properties && properties->IsObject()) - for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) - AddUniqueElement(allProperties, itr->name); - - if (required && required->IsArray()) - for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) - if (itr->IsString()) - AddUniqueElement(allProperties, *itr); - - if (dependencies && dependencies->IsObject()) - for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { - AddUniqueElement(allProperties, itr->name); - if (itr->value.IsArray()) - for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) - if (i->IsString()) - AddUniqueElement(allProperties, *i); - } - - if (allProperties.Size() > 0) { - propertyCount_ = allProperties.Size(); - properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); - for (SizeType i = 0; i < propertyCount_; i++) { - new (&properties_[i]) Property(); - properties_[i].name = allProperties[i]; - properties_[i].schema = GetTypeless(); - } - } - } - - if (properties && properties->IsObject()) { - PointerType q = p.Append(GetPropertiesString(), allocator_); - for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { - SizeType index; - if (FindPropertyIndex(itr->name, &index)) - schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); - } - } - - if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { - PointerType q = p.Append(GetPatternPropertiesString(), allocator_); - patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); - patternPropertyCount_ = 0; - - for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { - new (&patternProperties_[patternPropertyCount_]) PatternProperty(); - patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); - schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); - patternPropertyCount_++; - } - } - - if (required && required->IsArray()) - for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) - if (itr->IsString()) { - SizeType index; - if (FindPropertyIndex(*itr, &index)) { - properties_[index].required = true; - hasRequired_ = true; - } - } - - if (dependencies && dependencies->IsObject()) { - PointerType q = p.Append(GetDependenciesString(), allocator_); - hasDependencies_ = true; - for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { - SizeType sourceIndex; - if (FindPropertyIndex(itr->name, &sourceIndex)) { - if (itr->value.IsArray()) { - properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); - std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); - for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { - SizeType targetIndex; - if (FindPropertyIndex(*targetItr, &targetIndex)) - properties_[sourceIndex].dependencies[targetIndex] = true; - } - } - else if (itr->value.IsObject()) { - hasSchemaDependencies_ = true; - schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); - properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; - validatorCount_++; - } - } - } - } - - if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { - if (v->IsBool()) - additionalProperties_ = v->GetBool(); - else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); - } - - AssignIfExist(minProperties_, value, GetMinPropertiesString()); - AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); - - // Array - if (const ValueType* v = GetMember(value, GetItemsString())) { - PointerType q = p.Append(GetItemsString(), allocator_); - if (v->IsObject()) // List validation - schemaDocument->CreateSchema(&itemsList_, q, *v, document); - else if (v->IsArray()) { // Tuple validation - itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); - SizeType index = 0; - for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) - schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); - } - } - - AssignIfExist(minItems_, value, GetMinItemsString()); - AssignIfExist(maxItems_, value, GetMaxItemsString()); - - if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { - if (v->IsBool()) - additionalItems_ = v->GetBool(); - else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); - } - - AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); - - // String - AssignIfExist(minLength_, value, GetMinLengthString()); - AssignIfExist(maxLength_, value, GetMaxLengthString()); - - if (const ValueType* v = GetMember(value, GetPatternString())) - pattern_ = CreatePattern(*v); - - // Number - if (const ValueType* v = GetMember(value, GetMinimumString())) - if (v->IsNumber()) - minimum_.CopyFrom(*v, *allocator_); - - if (const ValueType* v = GetMember(value, GetMaximumString())) - if (v->IsNumber()) - maximum_.CopyFrom(*v, *allocator_); - - AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); - AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); - - if (const ValueType* v = GetMember(value, GetMultipleOfString())) - if (v->IsNumber() && v->GetDouble() > 0.0) - multipleOf_.CopyFrom(*v, *allocator_); - } - - ~Schema() { - if (allocator_) { - allocator_->Free(enum_); - } - if (properties_) { - for (SizeType i = 0; i < propertyCount_; i++) - properties_[i].~Property(); - AllocatorType::Free(properties_); - } - if (patternProperties_) { - for (SizeType i = 0; i < patternPropertyCount_; i++) - patternProperties_[i].~PatternProperty(); - AllocatorType::Free(patternProperties_); - } - AllocatorType::Free(itemsTuple_); -#if RAPIDJSON_SCHEMA_HAS_REGEX - if (pattern_) { - pattern_->~RegexType(); - allocator_->Free(pattern_); - } -#endif - } - - bool BeginValue(Context& context) const { - if (context.inArray) { - if (uniqueItems_) - context.valueUniqueness = true; - - if (itemsList_) - context.valueSchema = itemsList_; - else if (itemsTuple_) { - if (context.arrayElementIndex < itemsTupleCount_) - context.valueSchema = itemsTuple_[context.arrayElementIndex]; - else if (additionalItemsSchema_) - context.valueSchema = additionalItemsSchema_; - else if (additionalItems_) - context.valueSchema = GetTypeless(); - else - RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); - } - else - context.valueSchema = GetTypeless(); - - context.arrayElementIndex++; - } - return true; - } - - RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { - if (context.patternPropertiesValidatorCount > 0) { - bool otherValid = false; - SizeType count = context.patternPropertiesValidatorCount; - if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) - otherValid = context.patternPropertiesValidators[--count]->IsValid(); - - bool patternValid = true; - for (SizeType i = 0; i < count; i++) - if (!context.patternPropertiesValidators[i]->IsValid()) { - patternValid = false; - break; - } - - if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { - if (!patternValid) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); - } - else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { - if (!patternValid || !otherValid) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); - } - else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); - } - - if (enum_) { - const uint64_t h = context.factory.GetHashCode(context.hasher); - for (SizeType i = 0; i < enumCount_; i++) - if (enum_[i] == h) - goto foundEnum; - RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); - foundEnum:; - } - - if (allOf_.schemas) - for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) - if (!context.validators[i]->IsValid()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); - - if (anyOf_.schemas) { - for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) - if (context.validators[i]->IsValid()) - goto foundAny; - RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); - foundAny:; - } - - if (oneOf_.schemas) { - bool oneValid = false; - for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) - if (context.validators[i]->IsValid()) { - if (oneValid) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); - else - oneValid = true; - } - if (!oneValid) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); - } - - if (not_ && context.validators[notValidatorIndex_]->IsValid()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); - - return true; - } - - bool Null(Context& context) const { - if (!(type_ & (1 << kNullSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - return CreateParallelValidator(context); - } - - bool Bool(Context& context, bool) const { - if (!(type_ & (1 << kBooleanSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - return CreateParallelValidator(context); - } - - bool Int(Context& context, int i) const { - if (!CheckInt(context, i)) - return false; - return CreateParallelValidator(context); - } - - bool Uint(Context& context, unsigned u) const { - if (!CheckUint(context, u)) - return false; - return CreateParallelValidator(context); - } - - bool Int64(Context& context, int64_t i) const { - if (!CheckInt(context, i)) - return false; - return CreateParallelValidator(context); - } - - bool Uint64(Context& context, uint64_t u) const { - if (!CheckUint(context, u)) - return false; - return CreateParallelValidator(context); - } - - bool Double(Context& context, double d) const { - if (!(type_ & (1 << kNumberSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) - return false; - - if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) - return false; - - if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) - return false; - - return CreateParallelValidator(context); - } - - bool String(Context& context, const Ch* str, SizeType length, bool) const { - if (!(type_ & (1 << kStringSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (minLength_ != 0 || maxLength_ != SizeType(~0)) { - SizeType count; - if (internal::CountStringCodePoint(str, length, &count)) { - if (count < minLength_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); - if (count > maxLength_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); - } - } - - if (pattern_ && !IsPatternMatch(pattern_, str, length)) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); - - return CreateParallelValidator(context); - } - - bool StartObject(Context& context) const { - if (!(type_ & (1 << kObjectSchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (hasDependencies_ || hasRequired_) { - context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); - std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); - } - - if (patternProperties_) { // pre-allocate schema array - SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType - context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); - context.patternPropertiesSchemaCount = 0; - std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); - } - - return CreateParallelValidator(context); - } - - bool Key(Context& context, const Ch* str, SizeType len, bool) const { - if (patternProperties_) { - context.patternPropertiesSchemaCount = 0; - for (SizeType i = 0; i < patternPropertyCount_; i++) - if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; - } - - SizeType index; - if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { - if (context.patternPropertiesSchemaCount > 0) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; - context.valueSchema = GetTypeless(); - context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; - } - else - context.valueSchema = properties_[index].schema; - - if (context.propertyExist) - context.propertyExist[index] = true; - - return true; - } - - if (additionalPropertiesSchema_) { - if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { - context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; - context.valueSchema = GetTypeless(); - context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; - } - else - context.valueSchema = additionalPropertiesSchema_; - return true; - } - else if (additionalProperties_) { - context.valueSchema = GetTypeless(); - return true; - } - - if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties - RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); - - return true; - } - - bool EndObject(Context& context, SizeType memberCount) const { - if (hasRequired_) - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].required) - if (!context.propertyExist[index]) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); - - if (memberCount < minProperties_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); - - if (memberCount > maxProperties_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); - - if (hasDependencies_) { - for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) - if (context.propertyExist[sourceIndex]) { - if (properties_[sourceIndex].dependencies) { - for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) - if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); - } - else if (properties_[sourceIndex].dependenciesSchema) - if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); - } - } - - return true; - } - - bool StartArray(Context& context) const { - if (!(type_ & (1 << kArraySchemaType))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - context.arrayElementIndex = 0; - context.inArray = true; - - return CreateParallelValidator(context); - } - - bool EndArray(Context& context, SizeType elementCount) const { - context.inArray = false; - - if (elementCount < minItems_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); - - if (elementCount > maxItems_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); - - return true; - } - - // Generate functions for string literal according to Ch -#define RAPIDJSON_STRING_(name, ...) \ - static const ValueType& Get##name##String() {\ - static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ - return v;\ - } - - RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') - RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') - RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') - RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') - RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') - RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') - RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') - RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') - RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') - RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') - RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') - RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') - RAPIDJSON_STRING_(Not, 'n', 'o', 't') - RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') - RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') - RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') - RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') - RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') - RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') - RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') - RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') - RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') - -#undef RAPIDJSON_STRING_ - -private: - enum SchemaValueType { - kNullSchemaType, - kBooleanSchemaType, - kObjectSchemaType, - kArraySchemaType, - kStringSchemaType, - kNumberSchemaType, - kIntegerSchemaType, - kTotalSchemaType - }; - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - typedef internal::GenericRegex RegexType; -#elif RAPIDJSON_SCHEMA_USE_STDREGEX - typedef std::basic_regex RegexType; -#else - typedef char RegexType; -#endif - - struct SchemaArray { - SchemaArray() : schemas(), count() {} - ~SchemaArray() { AllocatorType::Free(schemas); } - const SchemaType** schemas; - SizeType begin; // begin index of context.validators - SizeType count; - }; - - static const SchemaType* GetTypeless() { - static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); - return &typeless; - } - - template - void AddUniqueElement(V1& a, const V2& v) { - for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) - if (*itr == v) - return; - V1 c(v, *allocator_); - a.PushBack(c, *allocator_); - } - - static const ValueType* GetMember(const ValueType& value, const ValueType& name) { - typename ValueType::ConstMemberIterator itr = value.FindMember(name); - return itr != value.MemberEnd() ? &(itr->value) : 0; - } - - static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { - if (const ValueType* v = GetMember(value, name)) - if (v->IsBool()) - out = v->GetBool(); - } - - static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { - if (const ValueType* v = GetMember(value, name)) - if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) - out = static_cast(v->GetUint64()); - } - - void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { - if (const ValueType* v = GetMember(value, name)) { - if (v->IsArray() && v->Size() > 0) { - PointerType q = p.Append(name, allocator_); - out.count = v->Size(); - out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); - memset(out.schemas, 0, sizeof(Schema*)* out.count); - for (SizeType i = 0; i < out.count; i++) - schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); - out.begin = validatorCount_; - validatorCount_ += out.count; - } - } - } - -#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - template - RegexType* CreatePattern(const ValueType& value) { - if (value.IsString()) { - RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); - if (!r->IsValid()) { - r->~RegexType(); - AllocatorType::Free(r); - r = 0; - } - return r; - } - return 0; - } - - static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { - return pattern->Search(str); - } -#elif RAPIDJSON_SCHEMA_USE_STDREGEX - template - RegexType* CreatePattern(const ValueType& value) { - if (value.IsString()) - try { - return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); - } - catch (const std::regex_error&) { - } - return 0; - } - - static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { - std::match_results r; - return std::regex_search(str, str + length, r, *pattern); - } -#else - template - RegexType* CreatePattern(const ValueType&) { return 0; } - - static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } -#endif // RAPIDJSON_SCHEMA_USE_STDREGEX - - void AddType(const ValueType& type) { - if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; - else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; - else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; - else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; - else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; - else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; - else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); - } - - bool CreateParallelValidator(Context& context) const { - if (enum_ || context.arrayUniqueness) - context.hasher = context.factory.CreateHasher(); - - if (validatorCount_) { - RAPIDJSON_ASSERT(context.validators == 0); - context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); - context.validatorCount = validatorCount_; - - if (allOf_.schemas) - CreateSchemaValidators(context, allOf_); - - if (anyOf_.schemas) - CreateSchemaValidators(context, anyOf_); - - if (oneOf_.schemas) - CreateSchemaValidators(context, oneOf_); - - if (not_) - context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); - - if (hasSchemaDependencies_) { - for (SizeType i = 0; i < propertyCount_; i++) - if (properties_[i].dependenciesSchema) - context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); - } - } - - return true; - } - - void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { - for (SizeType i = 0; i < schemas.count; i++) - context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); - } - - // O(n) - bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { - SizeType len = name.GetStringLength(); - const Ch* str = name.GetString(); - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].name.GetStringLength() == len && - (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) - { - *outIndex = index; - return true; - } - return false; - } - - bool CheckInt(Context& context, int64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (!minimum_.IsNull()) { - if (minimum_.IsInt64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); - } - else if (minimum_.IsUint64()) { - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() - } - else if (!CheckDoubleMinimum(context, static_cast(i))) - return false; - } - - if (!maximum_.IsNull()) { - if (maximum_.IsInt64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); - } - else if (maximum_.IsUint64()) - /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64() - else if (!CheckDoubleMaximum(context, static_cast(i))) - return false; - } - - if (!multipleOf_.IsNull()) { - if (multipleOf_.IsUint64()) { - if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); - } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) - return false; - } - - return true; - } - - bool CheckUint(Context& context, uint64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); - - if (!minimum_.IsNull()) { - if (minimum_.IsUint64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); - } - else if (minimum_.IsInt64()) - /* do nothing */; // i >= 0 > minimum.Getint64() - else if (!CheckDoubleMinimum(context, static_cast(i))) - return false; - } - - if (!maximum_.IsNull()) { - if (maximum_.IsUint64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); - } - else if (maximum_.IsInt64()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ - else if (!CheckDoubleMaximum(context, static_cast(i))) - return false; - } - - if (!multipleOf_.IsNull()) { - if (multipleOf_.IsUint64()) { - if (i % multipleOf_.GetUint64() != 0) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); - } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) - return false; - } - - return true; - } - - bool CheckDoubleMinimum(Context& context, double d) const { - if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); - return true; - } - - bool CheckDoubleMaximum(Context& context, double d) const { - if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); - return true; - } - - bool CheckDoubleMultipleOf(Context& context, double d) const { - double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); - double q = std::floor(a / b); - double r = a - q * b; - if (r > 0.0) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); - return true; - } - - struct Property { - Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} - ~Property() { AllocatorType::Free(dependencies); } - SValue name; - const SchemaType* schema; - const SchemaType* dependenciesSchema; - SizeType dependenciesValidatorIndex; - bool* dependencies; - bool required; - }; - - struct PatternProperty { - PatternProperty() : schema(), pattern() {} - ~PatternProperty() { - if (pattern) { - pattern->~RegexType(); - AllocatorType::Free(pattern); - } - } - const SchemaType* schema; - RegexType* pattern; - }; - - AllocatorType* allocator_; - uint64_t* enum_; - SizeType enumCount_; - SchemaArray allOf_; - SchemaArray anyOf_; - SchemaArray oneOf_; - const SchemaType* not_; - unsigned type_; // bitmask of kSchemaType - SizeType validatorCount_; - SizeType notValidatorIndex_; - - Property* properties_; - const SchemaType* additionalPropertiesSchema_; - PatternProperty* patternProperties_; - SizeType patternPropertyCount_; - SizeType propertyCount_; - SizeType minProperties_; - SizeType maxProperties_; - bool additionalProperties_; - bool hasDependencies_; - bool hasRequired_; - bool hasSchemaDependencies_; - - const SchemaType* additionalItemsSchema_; - const SchemaType* itemsList_; - const SchemaType** itemsTuple_; - SizeType itemsTupleCount_; - SizeType minItems_; - SizeType maxItems_; - bool additionalItems_; - bool uniqueItems_; - - RegexType* pattern_; - SizeType minLength_; - SizeType maxLength_; - - SValue minimum_; - SValue maximum_; - SValue multipleOf_; - bool exclusiveMinimum_; - bool exclusiveMaximum_; -}; - -template -struct TokenHelper { - RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { - *documentStack.template Push() = '/'; - char buffer[21]; - size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); - for (size_t i = 0; i < length; i++) - *documentStack.template Push() = buffer[i]; - } -}; - -// Partial specialized version for char to prevent buffer copying. -template -struct TokenHelper { - RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { - if (sizeof(SizeType) == 4) { - char *buffer = documentStack.template Push(1 + 10); // '/' + uint - *buffer++ = '/'; - const char* end = internal::u32toa(index, buffer); - documentStack.template Pop(static_cast(10 - (end - buffer))); - } - else { - char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 - *buffer++ = '/'; - const char* end = internal::u64toa(index, buffer); - documentStack.template Pop(static_cast(20 - (end - buffer))); - } - } -}; - -} // namespace internal - -/////////////////////////////////////////////////////////////////////////////// -// IGenericRemoteSchemaDocumentProvider - -template -class IGenericRemoteSchemaDocumentProvider { -public: - typedef typename SchemaDocumentType::Ch Ch; - - virtual ~IGenericRemoteSchemaDocumentProvider() {} - virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// GenericSchemaDocument - -//! JSON schema document. -/*! - A JSON schema document is a compiled version of a JSON schema. - It is basically a tree of internal::Schema. - - \note This is an immutable class (i.e. its instance cannot be modified after construction). - \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. - \tparam Allocator Allocator type for allocating memory of this document. -*/ -template -class GenericSchemaDocument { -public: - typedef ValueT ValueType; - typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; - typedef Allocator AllocatorType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - typedef internal::Schema SchemaType; - typedef GenericPointer PointerType; - friend class internal::Schema; - template - friend class GenericSchemaValidator; - - //! Constructor. - /*! - Compile a JSON document into schema document. - - \param document A JSON document as source. - \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. - \param allocator An optional allocator instance for allocating memory. Can be null. - */ - explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : - remoteProvider_(remoteProvider), - allocator_(allocator), - ownAllocator_(), - root_(), - schemaMap_(allocator, kInitialSchemaMapSize), - schemaRef_(allocator, kInitialSchemaRefSize) - { - if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); - - // Generate root schema, it will call CreateSchema() to create sub-schemas, - // And call AddRefSchema() if there are $ref. - CreateSchemaRecursive(&root_, PointerType(), document, document); - - // Resolve $ref - while (!schemaRef_.Empty()) { - SchemaRefEntry* refEntry = schemaRef_.template Pop(1); - if (const SchemaType* s = GetSchema(refEntry->target)) { - if (refEntry->schema) - *refEntry->schema = s; - - // Create entry in map if not exist - if (!GetSchema(refEntry->source)) { - new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); - } - } - refEntry->~SchemaRefEntry(); - } - - RAPIDJSON_ASSERT(root_ != 0); - - schemaRef_.ShrinkToFit(); // Deallocate all memory for ref - } - -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : - remoteProvider_(rhs.remoteProvider_), - allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - root_(rhs.root_), - schemaMap_(std::move(rhs.schemaMap_)), - schemaRef_(std::move(rhs.schemaRef_)) - { - rhs.remoteProvider_ = 0; - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - } -#endif - - //! Destructor - ~GenericSchemaDocument() { - while (!schemaMap_.Empty()) - schemaMap_.template Pop(1)->~SchemaEntry(); - - RAPIDJSON_DELETE(ownAllocator_); - } - - //! Get the root schema. - const SchemaType& GetRoot() const { return *root_; } - -private: - //! Prohibit copying - GenericSchemaDocument(const GenericSchemaDocument&); - //! Prohibit assignment - GenericSchemaDocument& operator=(const GenericSchemaDocument&); - - struct SchemaRefEntry { - SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} - PointerType source; - PointerType target; - const SchemaType** schema; - }; - - struct SchemaEntry { - SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} - ~SchemaEntry() { - if (owned) { - schema->~SchemaType(); - Allocator::Free(schema); - } - } - PointerType pointer; - SchemaType* schema; - bool owned; - }; - - void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { - if (schema) - *schema = SchemaType::GetTypeless(); - - if (v.GetType() == kObjectType) { - const SchemaType* s = GetSchema(pointer); - if (!s) - CreateSchema(schema, pointer, v, document); - - for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) - CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); - } - else if (v.GetType() == kArrayType) - for (SizeType i = 0; i < v.Size(); i++) - CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); - } - - void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { - RAPIDJSON_ASSERT(pointer.IsValid()); - if (v.IsObject()) { - if (!HandleRefSchema(pointer, schema, v, document)) { - SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); - new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); - if (schema) - *schema = s; - } - } - } - - bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { - static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; - static const ValueType kRefValue(kRefString, 4); - - typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); - if (itr == v.MemberEnd()) - return false; - - if (itr->value.IsString()) { - SizeType len = itr->value.GetStringLength(); - if (len > 0) { - const Ch* s = itr->value.GetString(); - SizeType i = 0; - while (i < len && s[i] != '#') // Find the first # - i++; - - if (i > 0) { // Remote reference, resolve immediately - if (remoteProvider_) { - if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { - PointerType pointer(&s[i], len - i, allocator_); - if (pointer.IsValid()) { - if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { - if (schema) - *schema = sc; - return true; - } - } - } - } - } - else if (s[i] == '#') { // Local reference, defer resolution - PointerType pointer(&s[i], len - i, allocator_); - if (pointer.IsValid()) { - if (const ValueType* nv = pointer.Get(document)) - if (HandleRefSchema(source, schema, *nv, document)) - return true; - - new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); - return true; - } - } - } - } - return false; - } - - const SchemaType* GetSchema(const PointerType& pointer) const { - for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) - if (pointer == target->pointer) - return target->schema; - return 0; - } - - PointerType GetPointer(const SchemaType* schema) const { - for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) - if (schema == target->schema) - return target->pointer; - return PointerType(); - } - - static const size_t kInitialSchemaMapSize = 64; - static const size_t kInitialSchemaRefSize = 64; - - IRemoteSchemaDocumentProviderType* remoteProvider_; - Allocator *allocator_; - Allocator *ownAllocator_; - const SchemaType* root_; //!< Root schema. - internal::Stack schemaMap_; // Stores created Pointer -> Schemas - internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref -}; - -//! GenericSchemaDocument using Value type. -typedef GenericSchemaDocument SchemaDocument; -//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. -typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; - -/////////////////////////////////////////////////////////////////////////////// -// GenericSchemaValidator - -//! JSON Schema Validator. -/*! - A SAX style JSON schema validator. - It uses a \c GenericSchemaDocument to validate SAX events. - It delegates the incoming SAX events to an output handler. - The default output handler does nothing. - It can be reused multiple times by calling \c Reset(). - - \tparam SchemaDocumentType Type of schema document. - \tparam OutputHandler Type of output handler. Default handler does nothing. - \tparam StateAllocator Allocator for storing the internal validation states. -*/ -template < - typename SchemaDocumentType, - typename OutputHandler = BaseReaderHandler, - typename StateAllocator = CrtAllocator> -class GenericSchemaValidator : - public internal::ISchemaStateFactory, - public internal::ISchemaValidator -{ -public: - typedef typename SchemaDocumentType::SchemaType SchemaType; - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename SchemaType::EncodingType EncodingType; - typedef typename EncodingType::Ch Ch; - - //! Constructor without output handler. - /*! - \param schemaDocument The schema document to conform to. - \param allocator Optional allocator for storing internal validation states. - \param schemaStackCapacity Optional initial capacity of schema path stack. - \param documentStackCapacity Optional initial capacity of document path stack. - */ - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(schemaDocument.GetRoot()), - outputHandler_(GetNullHandler()), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - valid_(true) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(0) -#endif - { - } - - //! Constructor with output handler. - /*! - \param schemaDocument The schema document to conform to. - \param allocator Optional allocator for storing internal validation states. - \param schemaStackCapacity Optional initial capacity of schema path stack. - \param documentStackCapacity Optional initial capacity of document path stack. - */ - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - OutputHandler& outputHandler, - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(schemaDocument.GetRoot()), - outputHandler_(outputHandler), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - valid_(true) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(0) -#endif - { - } - - //! Destructor. - ~GenericSchemaValidator() { - Reset(); - RAPIDJSON_DELETE(ownStateAllocator_); - } - - //! Reset the internal states. - void Reset() { - while (!schemaStack_.Empty()) - PopSchema(); - documentStack_.Clear(); - valid_ = true; - } - - //! Checks whether the current state is valid. - // Implementation of ISchemaValidator - virtual bool IsValid() const { return valid_; } - - //! Gets the JSON pointer pointed to the invalid schema. - PointerType GetInvalidSchemaPointer() const { - return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); - } - - //! Gets the keyword of invalid schema. - const Ch* GetInvalidSchemaKeyword() const { - return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; - } - - //! Gets the JSON pointer pointed to the invalid value. - PointerType GetInvalidDocumentPointer() const { - return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); - } - -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ -RAPIDJSON_MULTILINEMACRO_BEGIN\ - *documentStack_.template Push() = '\0';\ - documentStack_.template Pop(1);\ - internal::PrintInvalidDocument(documentStack_.template Bottom());\ -RAPIDJSON_MULTILINEMACRO_END -#else -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() -#endif - -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ - if (!valid_) return false; \ - if (!BeginValue() || !CurrentSchema().method arg1) {\ - RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ - return valid_ = false;\ - } - -#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ - for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ - if (context->hasher)\ - static_cast(context->hasher)->method arg2;\ - if (context->validators)\ - for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ - static_cast(context->validators[i_])->method arg2;\ - if (context->patternPropertiesValidators)\ - for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ - static_cast(context->patternPropertiesValidators[i_])->method arg2;\ - } - -#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ - return valid_ = EndValue() && outputHandler_.method arg2 - -#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ - RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ - RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) - - bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } - bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } - bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } - bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } - bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } - bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } - bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } - bool RawNumber(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } - bool String(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } - - bool StartObject() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); - return valid_ = outputHandler_.StartObject(); - } - - bool Key(const Ch* str, SizeType len, bool copy) { - if (!valid_) return false; - AppendToken(str, len); - if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); - return valid_ = outputHandler_.Key(str, len, copy); - } - - bool EndObject(SizeType memberCount) { - if (!valid_) return false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); - if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); - } - - bool StartArray() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); - return valid_ = outputHandler_.StartArray(); - } - - bool EndArray(SizeType elementCount) { - if (!valid_) return false; - RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); - if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; - RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); - } - -#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ -#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ -#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ -#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ - - // Implementation of ISchemaStateFactory - virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { - return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, -#if RAPIDJSON_SCHEMA_VERBOSE - depth_ + 1, -#endif - &GetStateAllocator()); - } - - virtual void DestroySchemaValidator(ISchemaValidator* validator) { - GenericSchemaValidator* v = static_cast(validator); - v->~GenericSchemaValidator(); - StateAllocator::Free(v); - } - - virtual void* CreateHasher() { - return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); - } - - virtual uint64_t GetHashCode(void* hasher) { - return static_cast(hasher)->GetHashCode(); - } - - virtual void DestroryHasher(void* hasher) { - HasherType* h = static_cast(hasher); - h->~HasherType(); - StateAllocator::Free(h); - } - - virtual void* MallocState(size_t size) { - return GetStateAllocator().Malloc(size); - } - - virtual void FreeState(void* p) { - return StateAllocator::Free(p); - } - -private: - typedef typename SchemaType::Context Context; - typedef GenericValue, StateAllocator> HashCodeArray; - typedef internal::Hasher HasherType; - - GenericSchemaValidator( - const SchemaDocumentType& schemaDocument, - const SchemaType& root, -#if RAPIDJSON_SCHEMA_VERBOSE - unsigned depth, -#endif - StateAllocator* allocator = 0, - size_t schemaStackCapacity = kDefaultSchemaStackCapacity, - size_t documentStackCapacity = kDefaultDocumentStackCapacity) - : - schemaDocument_(&schemaDocument), - root_(root), - outputHandler_(GetNullHandler()), - stateAllocator_(allocator), - ownStateAllocator_(0), - schemaStack_(allocator, schemaStackCapacity), - documentStack_(allocator, documentStackCapacity), - valid_(true) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(depth) -#endif - { - } - - StateAllocator& GetStateAllocator() { - if (!stateAllocator_) - stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator()); - return *stateAllocator_; - } - - bool BeginValue() { - if (schemaStack_.Empty()) - PushSchema(root_); - else { - if (CurrentContext().inArray) - internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); - - if (!CurrentSchema().BeginValue(CurrentContext())) - return false; - - SizeType count = CurrentContext().patternPropertiesSchemaCount; - const SchemaType** sa = CurrentContext().patternPropertiesSchemas; - typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; - bool valueUniqueness = CurrentContext().valueUniqueness; - if (CurrentContext().valueSchema) - PushSchema(*CurrentContext().valueSchema); - - if (count > 0) { - CurrentContext().objectPatternValidatorType = patternValidatorType; - ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; - SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; - va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); - for (SizeType i = 0; i < count; i++) - va[validatorCount++] = CreateSchemaValidator(*sa[i]); - } - - CurrentContext().arrayUniqueness = valueUniqueness; - } - return true; - } - - bool EndValue() { - if (!CurrentSchema().EndValue(CurrentContext())) - return false; - -#if RAPIDJSON_SCHEMA_VERBOSE - GenericStringBuffer sb; - schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); - - *documentStack_.template Push() = '\0'; - documentStack_.template Pop(1); - internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); -#endif - - uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; - - PopSchema(); - - if (!schemaStack_.Empty()) { - Context& context = CurrentContext(); - if (context.valueUniqueness) { - HashCodeArray* a = static_cast(context.arrayElementHashCodes); - if (!a) - CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); - for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) - if (itr->GetUint64() == h) - RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); - a->PushBack(h, GetStateAllocator()); - } - } - - // Remove the last token of document pointer - while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') - ; - - return true; - } - - void AppendToken(const Ch* str, SizeType len) { - documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters - *documentStack_.template PushUnsafe() = '/'; - for (SizeType i = 0; i < len; i++) { - if (str[i] == '~') { - *documentStack_.template PushUnsafe() = '~'; - *documentStack_.template PushUnsafe() = '0'; - } - else if (str[i] == '/') { - *documentStack_.template PushUnsafe() = '~'; - *documentStack_.template PushUnsafe() = '1'; - } - else - *documentStack_.template PushUnsafe() = str[i]; - } - } - - RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, &schema); } - - RAPIDJSON_FORCEINLINE void PopSchema() { - Context* c = schemaStack_.template Pop(1); - if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { - a->~HashCodeArray(); - StateAllocator::Free(a); - } - c->~Context(); - } - - const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } - Context& CurrentContext() { return *schemaStack_.template Top(); } - const Context& CurrentContext() const { return *schemaStack_.template Top(); } - - static OutputHandler& GetNullHandler() { - static OutputHandler nullHandler; - return nullHandler; - } - - static const size_t kDefaultSchemaStackCapacity = 1024; - static const size_t kDefaultDocumentStackCapacity = 256; - const SchemaDocumentType* schemaDocument_; - const SchemaType& root_; - OutputHandler& outputHandler_; - StateAllocator* stateAllocator_; - StateAllocator* ownStateAllocator_; - internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) - internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) - bool valid_; -#if RAPIDJSON_SCHEMA_VERBOSE - unsigned depth_; -#endif -}; - -typedef GenericSchemaValidator SchemaValidator; - -/////////////////////////////////////////////////////////////////////////////// -// SchemaValidatingReader - -//! A helper class for parsing with validation. -/*! - This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). - - \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept. - \tparam SourceEncoding Encoding of the input stream. - \tparam SchemaDocumentType Type of schema document. - \tparam StackAllocator Allocator type for stack. -*/ -template < - unsigned parseFlags, - typename InputStream, - typename SourceEncoding, - typename SchemaDocumentType = SchemaDocument, - typename StackAllocator = CrtAllocator> -class SchemaValidatingReader { -public: - typedef typename SchemaDocumentType::PointerType PointerType; - typedef typename InputStream::Ch Ch; - - //! Constructor - /*! - \param is Input stream. - \param sd Schema document. - */ - SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {} - - template - bool operator()(Handler& handler) { - GenericReader reader; - GenericSchemaValidator validator(sd_, handler); - parseResult_ = reader.template Parse(is_, validator); - - isValid_ = validator.IsValid(); - if (isValid_) { - invalidSchemaPointer_ = PointerType(); - invalidSchemaKeyword_ = 0; - invalidDocumentPointer_ = PointerType(); - } - else { - invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); - invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); - invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); - } - - return parseResult_; - } - - const ParseResult& GetParseResult() const { return parseResult_; } - bool IsValid() const { return isValid_; } - const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } - const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } - const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } - -private: - InputStream& is_; - const SchemaDocumentType& sd_; - - ParseResult parseResult_; - PointerType invalidSchemaPointer_; - const Ch* invalidSchemaKeyword_; - PointerType invalidDocumentPointer_; - bool isValid_; -}; - -RAPIDJSON_NAMESPACE_END -RAPIDJSON_DIAG_POP - -#endif // RAPIDJSON_SCHEMA_H_ diff --git a/src/utility/sc_man.h b/src/utility/sc_man.h deleted file mode 100644 index 908089b8eec..00000000000 --- a/src/utility/sc_man.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef __SC_MAN_H__ -#define __SC_MAN_H__ - -#include "doomtype.h" - -class FScanner -{ -public: - struct SavedPos - { - const char *SavedScriptPtr; - int SavedScriptLine; - }; - - // Methods ------------------------------------------------------ - FScanner(); - FScanner(const FScanner &other); - FScanner(int lumpnum); - ~FScanner(); - - FScanner &operator=(const FScanner &other); - - void Open(const char *lumpname); - bool OpenFile(const char *filename); - void OpenMem(const char *name, const char *buffer, int size); - void OpenMem(const char *name, const TArray &buffer) - { - OpenMem(name, (const char*)buffer.Data(), buffer.Size()); - } - void OpenString(const char *name, FString buffer); - void OpenLumpNum(int lump); - void Close(); - void SetParseVersion(VersionInfo ver) - { - ParseVersion = ver; - } - - void SetCMode(bool cmode); - void SetEscape(bool esc); - void SetStateMode(bool stately); - void DisableStateOptions(); - const SavedPos SavePos(); - void RestorePos(const SavedPos &pos); - - static FString TokenName(int token, const char *string=NULL); - - bool GetString(); - void MustGetString(); - void MustGetStringName(const char *name); - bool CheckString(const char *name); - - bool GetToken(); - void MustGetAnyToken(); - void TokenMustBe(int token); - void MustGetToken(int token); - bool CheckToken(int token); - bool CheckTokenId(ENamedName id); - - bool GetNumber(); - void MustGetNumber(); - bool CheckNumber(); - - bool GetFloat(); - void MustGetFloat(); - bool CheckFloat(); - - // Token based variant - bool CheckValue(bool allowfloat); - void MustGetValue(bool allowfloat); - bool CheckBoolToken(); - void MustGetBoolToken(); - - void UnGet(); - - bool Compare(const char *text); - int MatchString(const char * const *strings, size_t stride = sizeof(char*)); - int MustMatchString(const char * const *strings, size_t stride = sizeof(char*)); - int GetMessageLine(); - - void ScriptError(const char *message, ...) GCCPRINTF(2,3); - void ScriptMessage(const char *message, ...) GCCPRINTF(2,3); - - bool isText(); - - // Members ------------------------------------------------------ - char *String; - int StringLen; - int TokenType; - int Number; - int64_t BigNumber; - double Float; - int Line; - bool End; - bool Crossed; - int LumpNum; - FString ScriptName; - -protected: - void PrepareScript(); - void CheckOpen(); - bool ScanString(bool tokens); - - // Strings longer than this minus one will be dynamically allocated. - static const int MAX_STRING_SIZE = 128; - - bool ScriptOpen; - FString ScriptBuffer; - const char *ScriptPtr; - const char *ScriptEndPtr; - char StringBuffer[MAX_STRING_SIZE]; - FString BigStringBuffer; - bool AlreadyGot; - int AlreadyGotLine; - bool LastGotToken; - const char *LastGotPtr; - int LastGotLine; - bool CMode; - uint8_t StateMode; - bool StateOptions; - bool Escape; - VersionInfo ParseVersion = { 0, 0, 0 }; // no ZScript extensions by default - - - bool ScanValue(bool allowfloat); -}; - -enum -{ - TK_SequenceStart = 256, -#define xx(sym,str) sym, -#include "sc_man_tokens.h" - TK_LastToken -}; - - -//========================================================================== -// -// -// -//========================================================================== - -enum -{ - MSG_WARNING, - MSG_FATAL, - MSG_ERROR, - MSG_OPTERROR, - MSG_DEBUGERROR, - MSG_DEBUGWARN, - MSG_DEBUGMSG, - MSG_LOG, - MSG_DEBUGLOG, - MSG_MESSAGE -}; - -//========================================================================== -// -// a class that remembers a parser position -// -//========================================================================== - -struct FScriptPosition -{ - static int WarnCounter; - static int ErrorCounter; - static bool StrictErrors; - static bool errorout; - FName FileName; - int ScriptLine; - - FScriptPosition() - { - FileName = NAME_None; - ScriptLine=0; - } - FScriptPosition(const FScriptPosition &other) = default; - FScriptPosition(FString fname, int line); - FScriptPosition(FScanner &sc); - FScriptPosition &operator=(const FScriptPosition &other) = default; - FScriptPosition &operator=(FScanner &sc); - void Message(int severity, const char *message,...) const GCCPRINTF(3,4); - static void ResetErrorCounter() - { - WarnCounter = 0; - ErrorCounter = 0; - } -}; - -int ParseHex(const char* hex, FScriptPosition* sc); - - -#endif //__SC_MAN_H__ diff --git a/src/utility/stats.h b/src/utility/stats.h deleted file mode 100644 index ec963f5342e..00000000000 --- a/src/utility/stats.h +++ /dev/null @@ -1,261 +0,0 @@ -/* -** stats.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __STATS_H__ -#define __STATS_H__ - -#include "zstring.h" - -#if !defined _WIN32 && !defined __APPLE__ - -#ifdef NO_CLOCK_GETTIME -class cycle_t -{ -public: - cycle_t &operator= (const cycle_t &o) { return *this; } - void Reset() {} - void Clock() {} - void Unclock() {} - double Time() { return 0; } - double TimeMS() { return 0; } -}; - -#else - -#include - -class cycle_t -{ -public: - void Reset() - { - Sec = 0; - } - - void Clock() - { - timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - Sec -= ts.tv_sec + ts.tv_nsec * 1e-9; - } - - void Unclock() - { - timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - Sec += ts.tv_sec + ts.tv_nsec * 1e-9; - } - - double Time() - { - return Sec; - } - - double TimeMS() - { - return Sec * 1e3; - } - -private: - double Sec; -}; - -#endif - -#else - -// Windows and macOS -#include "x86.h" - -extern double PerfToSec, PerfToMillisec; - -#ifdef _MSC_VER -// Trying to include intrin.h here results in some bizarre errors, so I'm just -// going to duplicate the function prototype instead. -//#include -extern "C" unsigned __int64 __rdtsc(void); -#pragma intrinsic(__rdtsc) -inline unsigned __int64 rdtsc() -{ - return __rdtsc(); -} -#elif defined __APPLE__ && (defined __i386__ || defined __x86_64__) -inline uint64_t rdtsc() -{ - return __builtin_ia32_rdtsc(); -} -#else -inline uint64_t rdtsc() -{ -#ifdef __amd64__ - uint64_t tsc; - asm volatile ("rdtsc; shlq $32, %%rdx; orq %%rdx, %%rax" : "=a" (tsc) :: "%rdx"); - return tsc; -#elif defined __ppc__ - unsigned int lower, upper, temp; - do - { - asm volatile ("mftbu %0 \n mftb %1 \n mftbu %2 \n" - : "=r"(upper), "=r"(lower), "=r"(temp)); - } - while (upper != temp); - return (static_cast(upper) << 32) | lower; -#else // i386 - if (CPU.bRDTSC) - { - uint64_t tsc; - asm volatile ("\trdtsc\n" : "=A" (tsc)); - return tsc; - } - return 0; -#endif // __amd64__ -} -#endif - -class cycle_t -{ -public: - void Reset() - { - Counter = 0; - } - - void Clock() - { - int64_t time = rdtsc(); - Counter -= time; - } - - void Unclock(bool checkvar = true) - { - int64_t time = rdtsc(); - Counter += time; - } - - double Time() - { - return Counter * PerfToSec; - } - - double TimeMS() - { - return Counter * PerfToMillisec; - } - - int64_t GetRawCounter() - { - return Counter; - } - -private: - int64_t Counter; -}; - -#endif - -class glcycle_t : public cycle_t -{ -public: - static bool active; - void Clock() - { - if (active) cycle_t::Clock(); - } - - void Unclock() - { - if (active) cycle_t::Unclock(); - } -}; - -// Helper for code that uses a timer and has multiple exit points. -class Clocker -{ -public: - - explicit Clocker(glcycle_t& clck) - : clock(clck) - { - clock.Clock(); - } - - ~Clocker() - { // unlock - clock.Unclock(); - } - - Clocker(const Clocker&) = delete; - Clocker& operator=(const Clocker&) = delete; -private: - glcycle_t & clock; -}; - - - -class FStat -{ -public: - FStat (const char *name); - virtual ~FStat (); - - virtual FString GetStats () = 0; - - void ToggleStat (); - bool isActive() const - { - return m_Active; - } - - static void PrintStat (); - static FStat *FindStat (const char *name); - static void ToggleStat (const char *name); - static void DumpRegisteredStats (); - -private: - FStat *m_Next; - const char *m_Name; - bool m_Active; - - static FStat *FirstStat; -}; - -#define ADD_STAT(n) \ - static class Stat_##n : public FStat { \ - public: \ - Stat_##n () : FStat (#n) {} \ - FString GetStats (); } Istaticstat##n; \ - FString Stat_##n::GetStats () - -#endif //__STATS_H__ diff --git a/src/utility/superfasthash.h b/src/utility/superfasthash.h deleted file mode 100644 index d6b7dae0c55..00000000000 --- a/src/utility/superfasthash.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -extern unsigned int MakeKey (const char *s); -extern unsigned int MakeKey (const char *s, size_t len); -extern unsigned int SuperFastHash (const char *data, size_t len); diff --git a/src/utility/tarray.h b/src/utility/tarray.h deleted file mode 100644 index 32ccc50ce23..00000000000 --- a/src/utility/tarray.h +++ /dev/null @@ -1,1588 +0,0 @@ -#pragma once -/* -** tarray.h -** Templated, automatically resizing array -** -**--------------------------------------------------------------------------- -** Copyright 1998-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** NOTE: TArray takes advantage of the assumption that the contained type is -** able to be trivially moved. The definition of trivially movable by the C++ -** standard is more strict than the actual set of types that can be moved with -** memmove. For example, FString uses non-trivial constructors/destructor in -** order to maintain the reference count, but can be "safely" by passed if the -** opaque destructor call is avoided. Similarly types like TArray itself which -** only null the owning pointers when moving which can be skipped if the -** destructor is not called. -** -** It is possible that with LTO TArray could be made safe for non-trivial types, -** but we don't wish to rely on LTO to reach expected performance. The set of -** types which can not be contained by TArray as a result of this choice is -** actually extremely small. -** -*/ - - -#include -#include -#include -#include -#include -#include - -#if !defined(_WIN32) -#include // for intptr_t -#else -#include // for mingw -#endif - -#include "m_alloc.h" - -template class TIterator : public std::iterator -{ -public: - typedef typename TIterator::value_type value_type; - typedef typename TIterator::difference_type difference_type; - typedef typename TIterator::pointer pointer; - typedef typename TIterator::reference reference; - typedef typename TIterator::iterator_category iterator_category; - - TIterator(T* ptr = nullptr) { m_ptr = ptr; } - - // Comparison operators - bool operator==(const TIterator &other) const { return m_ptr == other.m_ptr; } - bool operator!=(const TIterator &other) const { return m_ptr != other.m_ptr; } - bool operator< (const TIterator &other) const { return m_ptr < other.m_ptr; } - bool operator<=(const TIterator &other) const { return m_ptr <= other.m_ptr; } - bool operator> (const TIterator &other) const { return m_ptr > other.m_ptr; } - bool operator>=(const TIterator &other) const { return m_ptr >= other.m_ptr; } - - // Arithmetic operators - TIterator &operator++() { ++m_ptr; return *this; } - TIterator operator++(int) { pointer tmp = m_ptr; ++*this; return TIterator(tmp); } - TIterator &operator--() { --m_ptr; return *this; } - TIterator operator--(int) { pointer tmp = m_ptr; --*this; return TIterator(tmp); } - TIterator &operator+=(difference_type offset) { m_ptr += offset; return *this; } - TIterator operator+(difference_type offset) const { return TIterator(m_ptr + offset); } - friend TIterator operator+(difference_type offset, const TIterator &other) { return TIterator(offset + other.m_ptr); } - TIterator &operator-=(difference_type offset) { m_ptr -= offset; return *this; } - TIterator operator-(difference_type offset) const { return TIterator(m_ptr - offset); } - difference_type operator-(const TIterator &other) const { return m_ptr - other.m_ptr; } - - // Random access operators - T& operator[](difference_type i) { return m_ptr[i]; } - const T& operator[](difference_type i) const { return m_ptr[i]; } - - T &operator*() { return *m_ptr; } - const T &operator*() const { return *m_ptr; } - T* operator->() { return m_ptr; } - -protected: - T* m_ptr; -}; - - -// TArray ------------------------------------------------------------------- - -// Must match TArray's layout. -struct FArray -{ - void *Array; - unsigned int Count; - unsigned int Most; -}; - -// T is the type stored in the array. -// TT is the type returned by operator(). -template -class TArray -{ -public: - - typedef TIterator iterator; - typedef TIterator const_iterator; - typedef T value_type; - - iterator begin() - { - return &Array[0]; - } - const_iterator begin() const - { - return &Array[0]; - } - const_iterator cbegin() const - { - return &Array[0]; - } - - iterator end() - { - return &Array[Count]; - } - const_iterator end() const - { - return &Array[Count]; - } - const_iterator cend() const - { - return &Array[Count]; - } - - - - //////// - // This is a dummy constructor that does nothing. The purpose of this - // is so you can create a global TArray in the data segment that gets - // used by code before startup without worrying about the constructor - // resetting it after it's already been used. You MUST NOT use it for - // heap- or stack-allocated TArrays. - enum ENoInit - { - NoInit - }; - TArray (ENoInit dummy) - { - } - //////// - TArray () - { - Most = 0; - Count = 0; - Array = NULL; - } - explicit TArray (size_t max, bool reserve = false) - { - Most = (unsigned)max; - Count = (unsigned)(reserve? max : 0); - Array = (T *)M_Malloc (sizeof(T)*max); - if (reserve && Count > 0) - { - ConstructEmpty(0, Count - 1); - } - } - TArray (const TArray &other) - { - DoCopy (other); - } - TArray (TArray &&other) - { - Array = other.Array; other.Array = NULL; - Most = other.Most; other.Most = 0; - Count = other.Count; other.Count = 0; - } - TArray &operator= (const TArray &other) - { - if (&other != this) - { - if (Array != NULL) - { - if (Count > 0) - { - DoDelete (0, Count-1); - } - M_Free (Array); - } - DoCopy (other); - } - return *this; - } - TArray &operator= (TArray &&other) - { - if (Array) - { - if (Count > 0) - { - DoDelete (0, Count-1); - } - M_Free (Array); - } - Array = other.Array; other.Array = NULL; - Most = other.Most; other.Most = 0; - Count = other.Count; other.Count = 0; - return *this; - } - ~TArray () - { - if (Array) - { - if (Count > 0) - { - DoDelete (0, Count-1); - } - M_Free (Array); - Array = NULL; - Count = 0; - Most = 0; - } - } - // Check equality of two arrays - bool operator==(const TArray &other) const - { - if (Count != other.Count) - { - return false; - } - for (unsigned int i = 0; i < Count; ++i) - { - if (Array[i] != other.Array[i]) - { - return false; - } - } - return true; - } - // Return a reference to an element - T &operator[] (size_t index) const - { - return Array[index]; - } - // Returns the value of an element - TT operator() (size_t index) const - { - return Array[index]; - } - // Returns a reference to the last element - T &Last() const - { - return Array[Count-1]; - } - - // returns address of first element - T *Data() const - { - return &Array[0]; - } - - unsigned int Find(const T& item) const - { - unsigned int i; - for(i = 0;i < Count;++i) - { - if(Array[i] == item) - break; - } - return i; - } - - template - unsigned int FindEx(Func compare) const - { - unsigned int i; - for (i = 0; i < Count; ++i) - { - if (compare(Array[i])) - break; - } - return i; - } - - unsigned int Push (const T &item) - { - Grow (1); - ::new((void*)&Array[Count]) T(item); - return Count++; - } - - unsigned int Push(T &&item) - { - Grow(1); - ::new((void*)&Array[Count]) T(std::move(item)); - return Count++; - } - - unsigned Append(const TArray &item) - { - unsigned start = Count; - - Grow(item.Size()); - Count += item.Size(); - - for (unsigned i = 0; i < item.Size(); i++) - { - new(&Array[start + i]) T(item[i]); - } - return start; - } - - unsigned Append(TArray &&item) - { - unsigned start = Count; - - Grow(item.Size()); - Count += item.Size(); - - for (unsigned i = 0; i < item.Size(); i++) - { - new(&Array[start + i]) T(std::move(item[i])); - } - return start; - } - - bool Pop () - { - if (Count > 0) - { - Array[--Count].~T(); - return true; - } - return false; - } - bool Pop (T &item) - { - if (Count > 0) - { - item = Array[--Count]; - Array[Count].~T(); - return true; - } - return false; - } - void Delete (unsigned int index) - { - if (index < Count) - { - Array[index].~T(); - if (index < --Count) - { - // Cast to void to assume trivial move - memmove ((void*)&Array[index], (const void*)&Array[index+1], sizeof(T)*(Count - index)); - } - } - } - - void Delete (unsigned int index, int deletecount) - { - if (index + deletecount > Count) - { - deletecount = Count - index; - } - if (deletecount > 0) - { - for (int i = 0; i < deletecount; i++) - { - Array[index + i].~T(); - } - Count -= deletecount; - if (index < Count) - { - // Cast to void to assume trivial move - memmove ((void*)&Array[index], (const void*)&Array[index+deletecount], sizeof(T)*(Count - index)); - } - } - } - - // Inserts an item into the array, shifting elements as needed - void Insert (unsigned int index, const T &item) - { - if (index >= Count) - { - // Inserting somewhere past the end of the array, so we can - // just add it without moving things. - Resize (index + 1); - ::new ((void *)&Array[index]) T(item); - } - else - { - // Inserting somewhere in the middle of the array, - // so make room for it - Resize (Count + 1); - - // Now move items from the index and onward out of the way - // Cast to void to assume trivial move - memmove ((void*)&Array[index+1], (const void*)&Array[index], sizeof(T)*(Count - index - 1)); - - // And put the new element in - ::new ((void *)&Array[index]) T(item); - } - } - - void ShrinkToFit () - { - if (Most > Count) - { - Most = Count; - if (Most == 0) - { - if (Array != NULL) - { - M_Free (Array); - Array = NULL; - } - } - else - { - DoResize (); - } - } - } - // Grow Array to be large enough to hold amount more entries without - // further growing. - void Grow (unsigned int amount) - { - if (Count + amount > Most) - { - const unsigned int choicea = Count + amount; - const unsigned int choiceb = Most = (Most >= 16) ? Most + Most / 2 : 16; - Most = (choicea > choiceb ? choicea : choiceb); - DoResize (); - } - } - // Resize Array so that it has exactly amount entries in use. - void Resize (unsigned int amount) - { - if (Count < amount) - { - // Adding new entries - Grow (amount - Count); - ConstructEmpty(Count, amount - 1); - } - else if (Count != amount) - { - // Deleting old entries - DoDelete (amount, Count - 1); - } - Count = amount; - } - // Ensures that the array has at most amount entries. - // Useful in cases where the initial allocation may be larger than the final result. - // Resize would create a lot of unneeded code in those cases. - void Clamp(unsigned int amount) - { - if (Count > amount) - { - // Deleting old entries - DoDelete(amount, Count - 1); - Count = amount; - } - } - void Alloc(unsigned int amount) - { - // first destroys all content and then rebuilds the array. - if (Count > 0) DoDelete(0, Count - 1); - Count = 0; - Resize(amount); - ShrinkToFit(); - } - // Reserves amount entries at the end of the array, but does nothing - // with them. - unsigned int Reserve (size_t amount) - { - Grow ((unsigned)amount); - unsigned int place = Count; - Count += (unsigned)amount; - if (Count > 0) ConstructEmpty(place, Count - 1); - return place; - } - unsigned int Size () const - { - return Count; - } - unsigned int Max () const - { - return Most; - } - void Clear () - { - if (Count > 0) - { - DoDelete (0, Count-1); - Count = 0; - } - } - void Reset() - { - Clear(); - Most = 0; - if (Array != nullptr) - { - M_Free(Array); - Array = nullptr; - } - } - - void Swap(TArray &other) - { - std::swap(Array, other.Array); - std::swap(Count, other.Count); - std::swap(Most, other.Most); - } - -private: - T *Array; - unsigned int Count; - unsigned int Most; - - void DoCopy (const TArray &other) - { - Most = Count = other.Count; - if (Count != 0) - { - Array = (T *)M_Malloc (sizeof(T)*Most); - for (unsigned int i = 0; i < Count; ++i) - { - ::new(&Array[i]) T(other.Array[i]); - } - } - else - { - Array = NULL; - } - } - - void DoResize () - { - size_t allocsize = sizeof(T)*Most; - Array = (T *)M_Realloc (Array, allocsize); - } - - void DoDelete (unsigned int first, unsigned int last) - { - assert (last != ~0u); - for (unsigned int i = first; i <= last; ++i) - { - Array[i].~T(); - } - } - - void ConstructEmpty(unsigned int first, unsigned int last) - { - assert(last != ~0u); - for (unsigned int i = first; i <= last; ++i) - { - ::new(&Array[i]) T; - } - } -}; - -// TDeletingArray ----------------------------------------------------------- -// An array that deletes its elements when it gets deleted. -template -class TDeletingArray : public TArray -{ -public: - TDeletingArray() : TArray() {} - TDeletingArray(TDeletingArray &&other) : TArray(std::move(other)) {} - TDeletingArray &operator=(TDeletingArray &&other) - { - TArray::operator=(std::move(other)); - return *this; - } - - ~TDeletingArray () - { - for (unsigned int i = 0; i < TArray::Size(); ++i) - { - if ((*this)[i] != NULL) - delete (*this)[i]; - } - } - void DeleteAndClear() - { - for (unsigned int i = 0; i < TArray::Size(); ++i) - { - if ((*this)[i] != NULL) - delete (*this)[i]; - } - this->Clear(); - } -}; - -// This is only used for exposing the sector's Lines array to ZScript. -// Unlike TArrayView, its members are public as needed by the map loader. - -template -class TStaticPointedArray -{ -public: - - typedef TIterator iterator; - typedef TIterator const_iterator; - typedef T value_type; - - iterator begin() - { - return &Array[0]; - } - const_iterator begin() const - { - return &Array[0]; - } - const_iterator cbegin() const - { - return &Array[0]; - } - - iterator end() - { - return &Array[Count]; - } - const_iterator end() const - { - return &Array[Count]; - } - const_iterator cend() const - { - return &Array[Count]; - } - - void Init(T *ptr, unsigned cnt) - { - Array = ptr; - Count = cnt; - } - // Return a reference to an element - T &operator[] (size_t index) const - { - return Array[index]; - } - T &At(size_t index) const - { - return Array[index]; - } - unsigned int Size() const - { - return Count; - } - // Some code needs to access these directly so they cannot be private. - T *Array; - unsigned int Count; -}; - -// TAutoGrowArray ----------------------------------------------------------- -// An array with accessors that automatically grow the array as needed. -// It can still be used as a normal TArray if needed. ACS uses this for -// world and global arrays. - -template -class TAutoGrowArray : public TArray -{ -public: - T GetVal (unsigned int index) - { - if (index >= this->Size()) - { - return 0; - } - return (*this)[index]; - } - void SetVal (unsigned int index, T val) - { - if ((int)index < 0) return; // These always result in an out of memory condition. - - if (index >= this->Size()) - { - this->Resize (index + 1); - } - (*this)[index] = val; - } -}; - -// TMap --------------------------------------------------------------------- -// An associative array, similar in concept to the STL extension -// class hash_map. It is implemented using Lua's table algorithm: -/* -** Hash uses a mix of chained scatter table with Brent's variation. -** A main invariant of these tables is that, if an element is not -** in its main position (i.e. the `original' position that its hash gives -** to it), then the colliding element is in its own main position. -** Hence even when the load factor reaches 100%, performance remains good. -*/ -/****************************************************************************** -* Copyright (C) 1994-2006 Lua.org, PUC-Rio. All rights reserved. -* -* 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. -******************************************************************************/ - -typedef unsigned int hash_t; - -template struct THashTraits -{ - // Returns the hash value for a key. - hash_t Hash(const KT key) { return (hash_t)(intptr_t)key; } - hash_t Hash(double key) - { - hash_t keyhash[2]; - memcpy(&keyhash, &key, sizeof(keyhash)); - return keyhash[0] ^ keyhash[1]; - } - - // Compares two keys, returning zero if they are the same. - int Compare(const KT left, const KT right) { return left != right; } -}; - -template<> struct THashTraits -{ - // Use all bits when hashing singles instead of converting them to ints. - hash_t Hash(float key) - { - hash_t keyhash; - memcpy(&keyhash, &key, sizeof(keyhash)); - return keyhash; - } - int Compare(float left, float right) { return left != right; } -}; - -template<> struct THashTraits -{ - // Use all bits when hashing doubles instead of converting them to ints. - hash_t Hash(double key) - { - hash_t keyhash[2]; - memcpy(&keyhash, &key, sizeof(keyhash)); - return keyhash[0] ^ keyhash[1]; - } - int Compare(double left, double right) { return left != right; } -}; - -template struct TValueTraits -{ - // Initializes a value for TMap. If a regular constructor isn't - // good enough, you can override it. - void Init(VT &value) - { - ::new(&value) VT; - } -}; - -// Must match layout of TMap -struct FMap -{ - void *Nodes; - void *LastFree; - hash_t Size; - hash_t NumUsed; -}; - - -template class TMapIterator; -template class TMapConstIterator; - -template, class ValueTraits=TValueTraits > -class TMap -{ - template friend class TMapIterator; - template friend class TMapConstIterator; - -public: - typedef class TMap MyType; - typedef class TMapIterator Iterator; - typedef class TMapConstIterator ConstIterator; - typedef struct { const KT Key; VT Value; } Pair; - typedef const Pair ConstPair; - - TMap() { NumUsed = 0; SetNodeVector(1); } - TMap(hash_t size) { NumUsed = 0; SetNodeVector(size); } - ~TMap() { ClearNodeVector(); } - - TMap(const TMap &o) - { - NumUsed = 0; - SetNodeVector(o.CountUsed()); - CopyNodes(o.Nodes, o.Size); - } - - TMap &operator= (const TMap &o) - { - NumUsed = 0; - ClearNodeVector(); - SetNodeVector(o.CountUsed()); - CopyNodes(o.Nodes, o.Size); - return *this; - } - - //======================================================================= - // - // TransferFrom - // - // Moves the contents from one TMap to another, leaving the TMap moved - // from empty. - // - //======================================================================= - - void TransferFrom(TMap &o) - { - // Clear all our nodes. - NumUsed = 0; - ClearNodeVector(); - - // Copy all of o's nodes. - Nodes = o.Nodes; - LastFree = o.LastFree; - Size = o.Size; - NumUsed = o.NumUsed; - - // Tell o it doesn't have any nodes. - o.Nodes = NULL; - o.Size = 0; - o.LastFree = NULL; - o.NumUsed = 0; - - // Leave o functional with one empty node. - o.SetNodeVector(1); - } - - //======================================================================= - // - // Clear - // - // Empties out the table and resizes it with room for count entries. - // - //======================================================================= - - void Clear(hash_t count=1) - { - ClearNodeVector(); - SetNodeVector(count); - } - - //======================================================================= - // - // CountUsed - // - // Returns the number of entries in use in the table. - // - //======================================================================= - - hash_t CountUsed() const - { -#ifdef _DEBUG - hash_t used = 0; - hash_t ct = Size; - for (Node *n = Nodes; ct-- > 0; ++n) - { - if (!n->IsNil()) - { - ++used; - } - } - assert (used == NumUsed); -#endif - return NumUsed; - } - - //======================================================================= - // - // operator[] - // - // Returns a reference to the value associated with a particular key, - // creating the pair if the key isn't already in the table. - // - //======================================================================= - - VT &operator[] (const KT key) - { - return GetNode(key)->Pair.Value; - } - - const VT &operator[] (const KT key) const - { - return GetNode(key)->Pair.Value; - } - - //======================================================================= - // - // CheckKey - // - // Returns a pointer to the value associated with a particular key, or - // NULL if the key isn't in the table. - // - //======================================================================= - - VT *CheckKey (const KT key) - { - Node *n = FindKey(key); - return n != NULL ? &n->Pair.Value : NULL; - } - - const VT *CheckKey (const KT key) const - { - const Node *n = FindKey(key); - return n != NULL ? &n->Pair.Value : NULL; - } - - //======================================================================= - // - // Insert - // - // Adds a key/value pair to the table if key isn't in the table, or - // replaces the value for the existing pair if the key is in the table. - // - // This is functionally equivalent to (*this)[key] = value; but can be - // slightly faster if the pair needs to be created because it doesn't run - // the constructor on the value part twice. - // - //======================================================================= - - VT &Insert(const KT key, const VT &value) - { - Node *n = FindKey(key); - if (n != NULL) - { - n->Pair.Value = value; - } - else - { - n = NewKey(key); - ::new(&n->Pair.Value) VT(value); - } - return n->Pair.Value; - } - - VT &Insert(const KT key, VT &&value) - { - Node *n = FindKey(key); - if (n != NULL) - { - n->Pair.Value = value; - } - else - { - n = NewKey(key); - ::new(&n->Pair.Value) VT(value); - } - return n->Pair.Value; - } - - VT &InsertNew(const KT key) - { - Node *n = FindKey(key); - if (n != NULL) - { - n->Pair.Value.~VT(); - } - else - { - n = NewKey(key); - } - ::new(&n->Pair.Value) VT; - return n->Pair.Value; - } - - //======================================================================= - // - // Remove - // - // Removes the key/value pair for a particular key if it is in the table. - // - //======================================================================= - - void Remove(const KT key) - { - DelKey(key); - } - - void Swap(MyType &other) - { - std::swap(Nodes, other.Nodes); - std::swap(LastFree, other.LastFree); - std::swap(Size, other.Size); - std::swap(NumUsed, other.NumUsed); - } - -protected: - struct IPair // This must be the same as Pair above, but with a - { // non-const Key. - KT Key; - VT Value; - }; - struct Node - { - Node *Next; - IPair Pair; - void SetNil() - { - Next = (Node *)1; - } - bool IsNil() const - { - return Next == (Node *)1; - } - }; - - /* This is used instead of memcpy, because Node is likely to be small, - * such that the time spent calling a function would eclipse the time - * spent copying. */ - struct NodeSizedStruct { unsigned char Pads[sizeof(Node)]; }; - - Node *Nodes; - Node *LastFree; /* any free position is before this position */ - hash_t Size; /* must be a power of 2 */ - hash_t NumUsed; - - const Node *MainPosition(const KT k) const - { - HashTraits Traits; - return &Nodes[Traits.Hash(k) & (Size - 1)]; - } - - Node *MainPosition(const KT k) - { - HashTraits Traits; - return &Nodes[Traits.Hash(k) & (Size - 1)]; - } - - void SetNodeVector(hash_t size) - { - // Round size up to nearest power of 2 - for (Size = 1; Size < size; Size <<= 1) - { } - Nodes = (Node *)M_Malloc(Size * sizeof(Node)); - LastFree = &Nodes[Size]; /* all positions are free */ - for (hash_t i = 0; i < Size; ++i) - { - Nodes[i].SetNil(); - } - } - - void ClearNodeVector() - { - for (hash_t i = 0; i < Size; ++i) - { - if (!Nodes[i].IsNil()) - { - Nodes[i].~Node(); - } - } - M_Free(Nodes); - Nodes = NULL; - Size = 0; - LastFree = NULL; - NumUsed = 0; - } - - void Resize(hash_t nhsize) - { - hash_t i, oldhsize = Size; - Node *nold = Nodes; - /* create new hash part with appropriate size */ - SetNodeVector(nhsize); - /* re-insert elements from hash part */ - NumUsed = 0; - for (i = 0; i < oldhsize; ++i) - { - if (!nold[i].IsNil()) - { - Node *n = NewKey(nold[i].Pair.Key); - ::new(&n->Pair.Value) VT(std::move(nold[i].Pair.Value)); - nold[i].~Node(); - } - } - M_Free(nold); - } - - void Rehash() - { - Resize (Size << 1); - } - - Node *GetFreePos() - { - while (LastFree-- > Nodes) - { - if (LastFree->IsNil()) - { - return LastFree; - } - } - return NULL; /* could not find a free place */ - } - - /* - ** Inserts a new key into a hash table; first, check whether key's main - ** position is free. If not, check whether colliding node is in its main - ** position or not: if it is not, move colliding node to an empty place and - ** put new key in its main position; otherwise (colliding node is in its main - ** position), new key goes to an empty position. - ** - ** The Value field is left unconstructed. - */ - Node *NewKey(const KT key) - { - Node *mp = MainPosition(key); - if (!mp->IsNil()) - { - Node *othern; - Node *n = GetFreePos(); /* get a free place */ - if (n == NULL) /* cannot find a free place? */ - { - Rehash(); /* grow table */ - return NewKey(key); /* re-insert key into grown table */ - } - othern = MainPosition(mp->Pair.Key); - if (othern != mp) /* is colliding node out of its main position? */ - { /* yes; move colliding node into free position */ - while (othern->Next != mp) /* find previous */ - { - othern = othern->Next; - } - othern->Next = n; /* redo the chain with 'n' in place of 'mp' */ - CopyNode(n, mp); /* copy colliding node into free pos. (mp->Next also goes) */ - mp->Next = NULL; /* now 'mp' is free */ - } - else /* colliding node is in its own main position */ - { /* new node will go into free position */ - n->Next = mp->Next; /* chain new position */ - mp->Next = n; - mp = n; - } - } - else - { - mp->Next = NULL; - } - ++NumUsed; - ::new(&mp->Pair.Key) KT(key); - return mp; - } - - void DelKey(const KT key) - { - Node *mp = MainPosition(key), **mpp; - HashTraits Traits; - - if (mp->IsNil()) - { - /* the key is definitely not present, because there is nothing at its main position */ - } - else if (!Traits.Compare(mp->Pair.Key, key)) /* the key is in its main position */ - { - if (mp->Next != NULL) /* move next node to its main position */ - { - Node *n = mp->Next; - mp->~Node(); /* deconstruct old node */ - CopyNode(mp, n); /* copy next node */ - n->SetNil(); /* next node is now nil */ - } - else - { - mp->~Node(); - mp->SetNil(); /* there is no chain, so main position is nil */ - } - --NumUsed; - } - else /* the key is either not present or not in its main position */ - { - for (mpp = &mp->Next, mp = *mpp; mp != NULL && Traits.Compare(mp->Pair.Key, key); mpp = &mp->Next, mp = *mpp) - { } /* look for the key */ - if (mp != NULL) /* found it */ - { - *mpp = mp->Next; /* rechain so this node is skipped */ - mp->~Node(); - mp->SetNil(); /* because this node is now nil */ - --NumUsed; - } - } - } - - Node *FindKey(const KT key) - { - HashTraits Traits; - Node *n = MainPosition(key); - while (n != NULL && !n->IsNil() && Traits.Compare(n->Pair.Key, key)) - { - n = n->Next; - } - return n == NULL || n->IsNil() ? NULL : n; - } - - const Node *FindKey(const KT key) const - { - HashTraits Traits; - const Node *n = MainPosition(key); - while (n != NULL && !n->IsNil() && Traits.Compare(n->Pair.Key, key)) - { - n = n->Next; - } - return n == NULL || n->IsNil() ? NULL : n; - } - - Node *GetNode(const KT key) - { - Node *n = FindKey(key); - if (n != NULL) - { - return n; - } - n = NewKey(key); - ValueTraits traits; - traits.Init(n->Pair.Value); - return n; - } - - /* Perform a bit-wise copy of the node. Used when relocating a node in the table. */ - void CopyNode(Node *dst, const Node *src) - { - *(NodeSizedStruct *)dst = *(const NodeSizedStruct *)src; - } - - /* Copy all nodes in the node vector to this table. */ - void CopyNodes(const Node *nodes, hash_t numnodes) - { - for (; numnodes-- > 0; ++nodes) - { - if (!nodes->IsNil()) - { - Node *n = NewKey(nodes->Pair.Key); - ::new(&n->Pair.Value) VT(nodes->Pair.Value); - } - } - } -}; - -// TMapIterator ------------------------------------------------------------- -// A class to iterate over all the pairs in a TMap. - -template > -class TMapIterator -{ -public: - TMapIterator(MapType &map) - : Map(map), Position(0) - { - } - - //======================================================================= - // - // NextPair - // - // Returns false if there are no more entries in the table. Otherwise, it - // returns true, and pair is filled with a pointer to the pair in the - // table. - // - //======================================================================= - - bool NextPair(typename MapType::Pair *&pair) - { - if (Position >= Map.Size) - { - return false; - } - do - { - if (!Map.Nodes[Position].IsNil()) - { - pair = reinterpret_cast(&Map.Nodes[Position].Pair); - Position += 1; - return true; - } - } while (++Position < Map.Size); - return false; - } - - //======================================================================= - // - // Reset - // - // Restarts the iteration so you can do it all over again. - // - //======================================================================= - - void Reset() - { - Position = 0; - } - -protected: - MapType ⤅ - hash_t Position; -}; - -// TMapConstIterator -------------------------------------------------------- -// Exactly the same as TMapIterator, but it works with a const TMap. - -template > -class TMapConstIterator -{ -public: - TMapConstIterator(const MapType &map) - : Map(map), Position(0) - { - } - - bool NextPair(typename MapType::ConstPair *&pair) - { - if (Position >= Map.Size) - { - return false; - } - do - { - if (!Map.Nodes[Position].IsNil()) - { - pair = reinterpret_cast(&Map.Nodes[Position].Pair); - Position += 1; - return true; - } - } while (++Position < Map.Size); - return false; - } - -protected: - const MapType ⤅ - hash_t Position; -}; - - - -//========================================================================== -// -// an array to hold a small number of unique entries -// -//========================================================================== - -template class UniqueList -{ - TArray Array; - -public: - - T * Get(T * t) - { - for (unsigned i = 0; i bytes; - unsigned size; - -public: - void Resize(unsigned elem) - { - bytes.Resize((elem + 7) / 8); - size = elem; - } - - BitArray() : size(0) - { - } - - BitArray(const BitArray & arr) - { - bytes = arr.bytes; - size = arr.size; - } - - BitArray &operator=(const BitArray & arr) - { - bytes = arr.bytes; - size = arr.size; - return *this; - } - - BitArray(BitArray && arr) - { - bytes = std::move(arr.bytes); - size = arr.size; - arr.size = 0; - } - - BitArray &operator=(BitArray && arr) - { - bytes = std::move(arr.bytes); - size = arr.size; - arr.size = 0; - return *this; - } - - bool operator[](size_t index) const - { - return !!(bytes[index >> 3] & (1 << (index & 7))); - } - - void Set(size_t index) - { - bytes[index >> 3] |= (1 << (index & 7)); - } - - void Clear(size_t index) - { - bytes[index >> 3] &= ~(1 << (index & 7)); - } - - unsigned Size() const - { - return size; - } - - void Zero() - { - memset(&bytes[0], 0, bytes.Size()); - } -}; - - -// A wrapper to externally stored data. -// I would have expected something for this in the stl, but std::span is only in C++20. -template -class TArrayView -{ -public: - - typedef TIterator iterator; - typedef TIterator const_iterator; - typedef T value_type; - - iterator begin() - { - return &Array[0]; - } - const_iterator begin() const - { - return &Array[0]; - } - const_iterator cbegin() const - { - return &Array[0]; - } - - iterator end() - { - return &Array[Count]; - } - const_iterator end() const - { - return &Array[Count]; - } - const_iterator cend() const - { - return &Array[Count]; - } - - - //////// - TArrayView() = default; // intended to keep this type trivial. - TArrayView(T *data, unsigned count = 0) - { - Count = count; - Array = data; - } - TArrayView(const TArrayView &other) = default; - TArrayView &operator= (const TArrayView &other) = default; - - // Check equality of two arrays - bool operator==(const TArrayView &other) const - { - if (Count != other.Count) - { - return false; - } - for (unsigned int i = 0; i < Count; ++i) - { - if (Array[i] != other.Array[i]) - { - return false; - } - } - return true; - } - // Return a reference to an element - T &operator[] (size_t index) const - { - return Array[index]; - } - // Returns a reference to the last element - T &Last() const - { - return Array[Count - 1]; - } - - // returns address of first element - T *Data() const - { - return &Array[0]; - } - - unsigned Size() const - { - return Count; - } - - unsigned int Find(const T& item) const - { - unsigned int i; - for (i = 0; i < Count; ++i) - { - if (Array[i] == item) - break; - } - return i; - } - - void Set(T *data, unsigned count) - { - Array = data; - Count = count; - } - - void Clear() - { - Count = 0; - Array = nullptr; - } -private: - T *Array; - unsigned int Count; -}; diff --git a/src/utility/templates.h b/src/utility/templates.h deleted file mode 100644 index 0737fc4e91a..00000000000 --- a/src/utility/templates.h +++ /dev/null @@ -1,211 +0,0 @@ -/* -** templates.h -** Some useful template functions -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifndef __TEMPLATES_H__ -#define __TEMPLATES_H__ - -#ifdef _MSC_VER -#pragma once -#endif - -#include -#include - -//========================================================================== -// -// BinarySearch -// -// Searches an array sorted in ascending order for an element matching -// the desired key. -// -// Template parameters: -// ClassType - The class to be searched -// KeyType - The type of the key contained in the class -// -// Function parameters: -// first - Pointer to the first element in the array -// max - The number of elements in the array -// keyptr - Pointer to the key member of ClassType -// key - The key value to look for -// -// Returns: -// A pointer to the element with a matching key or NULL if none found. -//========================================================================== - -template -inline -const ClassType *BinarySearch (const ClassType *first, int max, - const KeyType ClassType::*keyptr, const KeyType key) -{ - int min = 0; - --max; - - while (min <= max) - { - int mid = (min + max) / 2; - const ClassType *probe = &first[mid]; - const KeyType &seekey = probe->*keyptr; - if (seekey == key) - { - return probe; - } - else if (seekey < key) - { - min = mid + 1; - } - else - { - max = mid - 1; - } - } - return NULL; -} - -//========================================================================== -// -// BinarySearchFlexible -// -// THIS DOES NOT WORK RIGHT WITH VISUAL C++ -// ONLY ONE COMPTYPE SEEMS TO BE USED FOR ANY INSTANCE OF THIS FUNCTION -// IN A DEBUG BUILD. RELEASE MIGHT BE DIFFERENT--I DIDN'T BOTHER TRYING. -// -// Similar to BinarySearch, except another function is used to copmare -// items in the array. -// -// Template parameters: -// IndexType - The type used to index the array (int, size_t, etc.) -// KeyType - The type of the key -// CompType - A class with a static DoCompare(IndexType, KeyType) method. -// -// Function parameters: -// max - The number of elements in the array -// key - The key value to look for -// noIndex - The value to return if no matching element is found. -// -// Returns: -// The index of the matching element or noIndex. -//========================================================================== - -template -inline -IndexType BinarySearchFlexible (IndexType max, const KeyType key, IndexType noIndex) -{ - IndexType min = 0; - --max; - - while (min <= max) - { - IndexType mid = (min + max) / 2; - int lexx = CompType::DoCompare (mid, key); - if (lexx == 0) - { - return mid; - } - else if (lexx < 0) - { - min = mid + 1; - } - else - { - max = mid - 1; - } - } - return noIndex; -} - -//========================================================================== -// -// MIN -// -// Returns the minimum of a and b. -//========================================================================== - -#ifdef MIN -#undef MIN -#endif - -template -inline -const T MIN (const T a, const T b) -{ - return a < b ? a : b; -} - -//========================================================================== -// -// MAX -// -// Returns the maximum of a and b. -//========================================================================== - -#ifdef MAX -#undef MAX -#endif - -template -inline -const T MAX (const T a, const T b) -{ - return a > b ? a : b; -} - -//========================================================================== -// -// clamp -// -// Clamps in to the range [min,max]. -//========================================================================== - -template -inline -T clamp (const T in, const T min, const T max) -{ - return in <= min ? min : in >= max ? max : in; -} - -//========================================================================== -// -// swapvalues -// -// Swaps the values of a and b. -//========================================================================== - -template -inline -void swapvalues (T &a, T &b) -{ - T temp = std::move(a); a = std::move(b); b = std::move(temp); -} - -#endif //__TEMPLATES_H__ diff --git a/src/utility/tflags.h b/src/utility/tflags.h deleted file mode 100644 index 18c2becafa8..00000000000 --- a/src/utility/tflags.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -** tflags.h -** -**--------------------------------------------------------------------------- -** Copyright 2015 Teemu Piippo -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#pragma once -#include "doomtype.h" - -/* - * TFlags - * - * A Qt-inspired type-safe flagset type. - * - * T is the enum type of individual flags, - * TT is the underlying integer type used (defaults to uint32_t) - */ -template -class TFlags -{ - struct ZeroDummy {}; - -public: - typedef TFlags Self; - typedef T EnumType; - typedef TT IntType; - - TFlags() = default; - TFlags(const Self& other) = default; - TFlags (T value) : Value (static_cast (value)) {} - - // This allows initializing the flagset with 0, as 0 implicitly converts into a null pointer. - TFlags (ZeroDummy*) : Value (0) {} - - // Relation operators - Self operator| (Self other) const { return Self::FromInt (Value | other.GetValue()); } - Self operator& (Self other) const { return Self::FromInt (Value & other.GetValue()); } - Self operator^ (Self other) const { return Self::FromInt (Value ^ other.GetValue()); } - Self operator| (T value) const { return Self::FromInt (Value | value); } - Self operator& (T value) const { return Self::FromInt (Value & value); } - Self operator^ (T value) const { return Self::FromInt (Value ^ value); } - Self operator~() const { return Self::FromInt (~Value); } - - // Assignment operators - Self& operator= (Self other) { Value = other.GetValue(); return *this; } - Self& operator|= (Self other) { Value |= other.GetValue(); return *this; } - Self& operator&= (Self other) { Value &= other.GetValue(); return *this; } - Self& operator^= (Self other) { Value ^= other.GetValue(); return *this; } - Self& operator= (T value) { Value = value; return *this; } - Self& operator|= (T value) { Value |= value; return *this; } - Self& operator&= (T value) { Value &= value; return *this; } - Self& operator^= (T value) { Value ^= value; return *this; } - - // Access the value of the flagset - TT GetValue() const { return Value; } - operator TT() const { return Value; } - - // Set the value of the flagset manually with an integer. - // Please think twice before using this. - static Self FromInt (TT value) { return Self (static_cast (value)); } - -private: - template Self operator| (X value) const { return Self::FromInt (Value | value); } - template Self operator& (X value) const { return Self::FromInt (Value & value); } - template Self operator^ (X value) const { return Self::FromInt (Value ^ value); } - -public: // to be removed. - TT Value; -}; - -/* - * Additional operators for TFlags types. - */ -#define DEFINE_TFLAGS_OPERATORS(T) \ -inline T operator| (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) | T::IntType (b)); } \ -inline T operator& (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) & T::IntType (b)); } \ -inline T operator^ (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) ^ T::IntType (b)); } \ -inline T operator| (T::EnumType a, T b) { return T::FromInt (T::IntType (a) | T::IntType (b)); } \ -inline T operator& (T::EnumType a, T b) { return T::FromInt (T::IntType (a) & T::IntType (b)); } \ -inline T operator^ (T::EnumType a, T b) { return T::FromInt (T::IntType (a) ^ T::IntType (b)); } \ -inline T operator~ (T::EnumType a) { return T::FromInt (~T::IntType (a)); } - diff --git a/src/utility/utf8.cpp b/src/utility/utf8.cpp deleted file mode 100644 index ca2a4733a44..00000000000 --- a/src/utility/utf8.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* -** utf8.cpp -** UTF-8 utilities -** -**--------------------------------------------------------------------------- -** Copyright 2019 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ -#include -#include "tarray.h" - - -//========================================================================== -// -// -// -//========================================================================== - -int utf8_encode(int32_t codepoint, uint8_t *buffer, int *size) -{ - if (codepoint < 0) - return -1; - else if (codepoint < 0x80) - { - buffer[0] = (char)codepoint; - *size = 1; - } - else if (codepoint < 0x800) - { - buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); - buffer[1] = 0x80 + ((codepoint & 0x03F)); - *size = 2; - } - else if (codepoint < 0x10000) - { - buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); - buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); - buffer[2] = 0x80 + ((codepoint & 0x003F)); - *size = 3; - } - else if (codepoint <= 0x10FFFF) - { - buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); - buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); - buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); - buffer[3] = 0x80 + ((codepoint & 0x00003F)); - *size = 4; - } - else - return -1; - - return 0; -} - -//========================================================================== -// -// -// -//========================================================================== - -int utf8_decode(const uint8_t *src, int *size) -{ - int c = src[0]; - int r; - - *size = 1; - if ((c & 0x80) == 0) - { - return c; - } - - int c1 = src[1]; - if (c1 < 0x80 || c1 >= 0xc0) return -1; - c1 &= 0x3f; - - if ((c & 0xE0) == 0xC0) - { - r = ((c & 0x1F) << 6) | c1; - if (r >= 128) - { - *size = 2; - return r; - } - return -1; - } - - int c2 = src[2]; - if (c2 < 0x80 || c2 >= 0xc0) return -1; - c2 &= 0x3f; - - if ((c & 0xF0) == 0xE0) - { - r = ((c & 0x0F) << 12) | (c1 << 6) | c2; - if (r >= 2048 && (r < 55296 || r > 57343)) - { - *size = 3; - return r; - } - return -1; - } - - int c3 = src[3]; - if (c3 < 0x80 || c1 >= 0xc0) return -1; - c3 &= 0x3f; - - if ((c & 0xF8) == 0xF0) - { - r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; - if (r >= 65536 && r <= 1114111) - { - *size = 4; - return r; - } - } - return -1; -} - -//========================================================================== -// -// Unicode mapping for the 0x80-0x9f range of the Windows 1252 code page -// -//========================================================================== - -uint16_t win1252map[] = { - 0x20AC, - 0x81 , - 0x201A, - 0x0192, - 0x201E, - 0x2026, - 0x2020, - 0x2021, - 0x02C6, - 0x2030, - 0x0160, - 0x2039, - 0x0152, - 0x8d , - 0x017D, - 0x8f , - 0x90 , - 0x2018, - 0x2019, - 0x201C, - 0x201D, - 0x2022, - 0x2013, - 0x2014, - 0x02DC, - 0x2122, - 0x0161, - 0x203A, - 0x0153, - 0x9d , - 0x017E, - 0x0178, -}; - -//========================================================================== -// -// reads one character from the string. -// This can handle both ISO 8859-1/Windows-1252 and UTF-8, as well as mixed strings -// between both encodings, which may happen if inconsistent encoding is -// used between different files in a mod. -// -//========================================================================== - -int GetCharFromString(const uint8_t *&string) -{ - int z; - - z = *string; - - if (z < 192) - { - string++; - - // Handle Windows 1252 characters - if (z >= 128 && z < 160) - { - return win1252map[z - 128]; - } - return z; - } - else - { - int size = 0; - auto chr = utf8_decode(string, &size); - if (chr >= 0) - { - string += size; - return chr; - } - string++; - return z; - } -} - -//========================================================================== -// -// convert a potentially mixed-encoded string to pure UTF-8 -// this returns a pointer to a static buffer, -// assuming that its caller will immediately process the result. -// -//========================================================================== - -static TArray UTF8String; - -const char *MakeUTF8(const char *outline, int *numchars = nullptr) -{ - UTF8String.Clear(); - const uint8_t *in = (const uint8_t*)outline; - - if (numchars) *numchars = 0; - while (int chr = GetCharFromString(in)) - { - int size = 0; - uint8_t encode[4]; - if (!utf8_encode(chr, encode, &size)) - { - for (int i = 0; i < size; i++) - { - UTF8String.Push(encode[i]); - } - } - if (numchars) *numchars++; - } - UTF8String.Push(0); - return UTF8String.Data(); -} - -const char *MakeUTF8(int codepoint, int *psize) -{ - int size = 0; - UTF8String.Resize(5); - utf8_encode(codepoint, (uint8_t*)UTF8String.Data(), &size); - UTF8String[size] = 0; - if (psize) *psize = size; - return UTF8String.Data(); -} diff --git a/src/utility/utf8.h b/src/utility/utf8.h deleted file mode 100644 index ab457753395..00000000000 --- a/src/utility/utf8.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -int utf8_encode(int32_t codepoint, uint8_t *buffer, int *size); -int utf8_decode(const uint8_t *src, int *size); -int GetCharFromString(const uint8_t *&string); -inline int GetCharFromString(const char32_t *&string) -{ - return *string++; -} -const char *MakeUTF8(const char *outline, int *numchars = nullptr); // returns a pointer to a static buffer, assuming that its caller will immediately process the result. -const char *MakeUTF8(int codepoint, int *psize = nullptr); - -extern uint16_t win1252map[]; diff --git a/src/utility/vectors.h b/src/utility/vectors.h deleted file mode 100644 index ac4b97642c7..00000000000 --- a/src/utility/vectors.h +++ /dev/null @@ -1,1678 +0,0 @@ -/* -** vectors.h -** Vector math routines. -** -**--------------------------------------------------------------------------- -** Copyright 2005-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** Since C++ doesn't let me add completely new operators, the following two -** are overloaded for vectors: -** -** | dot product -** ^ cross product -*/ - -#ifndef VECTORS_H -#define VECTORS_H - -#include -#include -#include -#include "xs_Float.h" -#include "math/cmath.h" - - -#define EQUAL_EPSILON (1/65536.) - -// make this a local inline function to avoid any dependencies on other headers and not pollute the global namespace -namespace pi -{ - inline double pi() { return 3.14159265358979323846; } -} - - - -template struct TVector3; -template struct TRotator; -template struct TAngle; - -template -struct TVector2 -{ - vec_t X, Y; - - TVector2() = default; - - TVector2 (vec_t a, vec_t b) - : X(a), Y(b) - { - } - - TVector2(const TVector2 &other) = default; - - TVector2 (const TVector3 &other) // Copy the X and Y from the 3D vector and discard the Z - : X(other.X), Y(other.Y) - { - } - - void Zero() - { - Y = X = 0; - } - - bool isZero() const - { - return X == 0 && Y == 0; - } - - TVector2 &operator= (const TVector2 &other) = default; - - // Access X and Y as an array - vec_t &operator[] (int index) - { - return index == 0 ? X : Y; - } - - const vec_t &operator[] (int index) const - { - return index == 0 ? X : Y; - } - - // Test for equality - bool operator== (const TVector2 &other) const - { - return X == other.X && Y == other.Y; - } - - // Test for inequality - bool operator!= (const TVector2 &other) const - { - return X != other.X || Y != other.Y; - } - - // Test for approximate equality - bool ApproximatelyEquals (const TVector2 &other) const - { - return fabs(X - other.X) < EQUAL_EPSILON && fabs(Y - other.Y) < EQUAL_EPSILON; - } - - // Test for approximate inequality - bool DoesNotApproximatelyEqual (const TVector2 &other) const - { - return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON; - } - - // Unary negation - TVector2 operator- () const - { - return TVector2(-X, -Y); - } - - // Scalar addition - TVector2 &operator+= (double scalar) - { - X += scalar, Y += scalar; - return *this; - } - - friend TVector2 operator+ (const TVector2 &v, vec_t scalar) - { - return TVector2(v.X + scalar, v.Y + scalar); - } - - friend TVector2 operator+ (vec_t scalar, const TVector2 &v) - { - return TVector2(v.X + scalar, v.Y + scalar); - } - - // Scalar subtraction - TVector2 &operator-= (vec_t scalar) - { - X -= scalar, Y -= scalar; - return *this; - } - - TVector2 operator- (vec_t scalar) const - { - return TVector2(X - scalar, Y - scalar); - } - - // Scalar multiplication - TVector2 &operator*= (vec_t scalar) - { - X *= scalar, Y *= scalar; - return *this; - } - - friend TVector2 operator* (const TVector2 &v, vec_t scalar) - { - return TVector2(v.X * scalar, v.Y * scalar); - } - - friend TVector2 operator* (vec_t scalar, const TVector2 &v) - { - return TVector2(v.X * scalar, v.Y * scalar); - } - - // Scalar division - TVector2 &operator/= (vec_t scalar) - { - scalar = 1 / scalar, X *= scalar, Y *= scalar; - return *this; - } - - TVector2 operator/ (vec_t scalar) const - { - scalar = 1 / scalar; - return TVector2(X * scalar, Y * scalar); - } - - // Vector addition - TVector2 &operator+= (const TVector2 &other) - { - X += other.X, Y += other.Y; - return *this; - } - - TVector2 operator+ (const TVector2 &other) const - { - return TVector2(X + other.X, Y + other.Y); - } - - // Vector subtraction - TVector2 &operator-= (const TVector2 &other) - { - X -= other.X, Y -= other.Y; - return *this; - } - - TVector2 operator- (const TVector2 &other) const - { - return TVector2(X - other.X, Y - other.Y); - } - - // Vector length - vec_t Length() const - { - return (vec_t)g_sqrt (X*X + Y*Y); - } - - vec_t LengthSquared() const - { - return X*X + Y*Y; - } - - // Return a unit vector facing the same direction as this one - TVector2 Unit() const - { - vec_t len = Length(); - if (len != 0) len = 1 / len; - return *this * len; - } - - // Scales this vector into a unit vector. Returns the old length - vec_t MakeUnit() - { - vec_t len, ilen; - len = ilen = Length(); - if (ilen != 0) ilen = 1 / ilen; - *this *= ilen; - return len; - } - - // Resizes this vector to be the specified length (if it is not 0) - TVector2 &MakeResize(double len) - { - double scale = len / Length(); - X = vec_t(X * scale); - Y = vec_t(Y * scale); - return *this; - } - - - // Dot product - vec_t operator | (const TVector2 &other) const - { - return X*other.X + Y*other.Y; - } - - // Returns the angle that the ray (0,0)-(X,Y) faces - TAngle Angle() const; - - // Returns a rotated vector. angle is in degrees. - TVector2 Rotated (double angle) - { - double cosval = g_cosdeg (angle); - double sinval = g_sindeg (angle); - return TVector2(X*cosval - Y*sinval, Y*cosval + X*sinval); - } - - // Returns a rotated vector. angle is in degrees. - template - TVector2 Rotated(TAngle angle) - { - double cosval = angle.Cos(); - double sinval = angle.Sin(); - return TVector2(X*cosval - Y*sinval, Y*cosval + X*sinval); - } - - // Returns a vector rotated 90 degrees clockwise. - TVector2 Rotated90CW() - { - return TVector2(Y, -X); - } - - // Returns a vector rotated 90 degrees counterclockwise. - TVector2 Rotated90CCW() - { - return TVector2(-Y, X); - } -}; - -template -struct TVector3 -{ - typedef TVector2 Vector2; - - vec_t X, Y, Z; - - TVector3() = default; - - TVector3 (vec_t a, vec_t b, vec_t c) - : X(a), Y(b), Z(c) - { - } - - TVector3(vec_t *o) - : X(o[0]), Y(o[1]), Z(o[2]) - { - } - - TVector3(const TVector3 &other) = default; - - TVector3 (const Vector2 &xy, vec_t z) - : X(xy.X), Y(xy.Y), Z(z) - { - } - - TVector3 (const TRotator &rot); - - void Zero() - { - Z = Y = X = 0; - } - - bool isZero() const - { - return X == 0 && Y == 0 && Z == 0; - } - - TVector3 &operator= (const TVector3 &other) = default; - - // Access X and Y and Z as an array - vec_t &operator[] (int index) - { - return index == 0 ? X : index == 1 ? Y : Z; - } - - const vec_t &operator[] (int index) const - { - return index == 0 ? X : index == 1 ? Y : Z; - } - - // Test for equality - bool operator== (const TVector3 &other) const - { - return X == other.X && Y == other.Y && Z == other.Z; - } - - // Test for inequality - bool operator!= (const TVector3 &other) const - { - return X != other.X || Y != other.Y || Z != other.Z; - } - - // Test for approximate equality - bool ApproximatelyEquals (const TVector3 &other) const - { - return fabs(X - other.X) < EQUAL_EPSILON && fabs(Y - other.Y) < EQUAL_EPSILON && fabs(Z - other.Z) < EQUAL_EPSILON; - } - - // Test for approximate inequality - bool DoesNotApproximatelyEqual (const TVector3 &other) const - { - return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON || fabs(Z - other.Z) >= EQUAL_EPSILON; - } - - // Unary negation - TVector3 operator- () const - { - return TVector3(-X, -Y, -Z); - } - - // Scalar addition - TVector3 &operator+= (vec_t scalar) - { - X += scalar, Y += scalar, Z += scalar; - return *this; - } - - friend TVector3 operator+ (const TVector3 &v, vec_t scalar) - { - return TVector3(v.X + scalar, v.Y + scalar, v.Z + scalar); - } - - friend TVector3 operator+ (vec_t scalar, const TVector3 &v) - { - return TVector3(v.X + scalar, v.Y + scalar, v.Z + scalar); - } - - // Scalar subtraction - TVector3 &operator-= (vec_t scalar) - { - X -= scalar, Y -= scalar, Z -= scalar; - return *this; - } - - TVector3 operator- (vec_t scalar) const - { - return TVector3(X - scalar, Y - scalar, Z - scalar); - } - - // Scalar multiplication - TVector3 &operator*= (vec_t scalar) - { - X = vec_t(X *scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar); - return *this; - } - - friend TVector3 operator* (const TVector3 &v, vec_t scalar) - { - return TVector3(v.X * scalar, v.Y * scalar, v.Z * scalar); - } - - friend TVector3 operator* (vec_t scalar, const TVector3 &v) - { - return TVector3(v.X * scalar, v.Y * scalar, v.Z * scalar); - } - - // Scalar division - TVector3 &operator/= (vec_t scalar) - { - scalar = 1 / scalar, X = vec_t(X * scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar); - return *this; - } - - TVector3 operator/ (vec_t scalar) const - { - scalar = 1 / scalar; - return TVector3(X * scalar, Y * scalar, Z * scalar); - } - - // Vector addition - TVector3 &operator+= (const TVector3 &other) - { - X += other.X, Y += other.Y, Z += other.Z; - return *this; - } - - TVector3 operator+ (const TVector3 &other) const - { - return TVector3(X + other.X, Y + other.Y, Z + other.Z); - } - - // Vector subtraction - TVector3 &operator-= (const TVector3 &other) - { - X -= other.X, Y -= other.Y, Z -= other.Z; - return *this; - } - - TVector3 operator- (const TVector3 &other) const - { - return TVector3(X - other.X, Y - other.Y, Z - other.Z); - } - - // Add a 2D vector to this 3D vector, leaving Z unchanged. - TVector3 &operator+= (const Vector2 &other) - { - X += other.X, Y += other.Y; - return *this; - } - - // Subtract a 2D vector from this 3D vector, leaving Z unchanged. - TVector3 &operator-= (const Vector2 &other) - { - X -= other.X, Y -= other.Y; - return *this; - } - - // returns the XY fields as a 2D-vector. - Vector2 XY() const - { - return{ X, Y }; - } - - // Add a 3D vector and a 2D vector. - friend TVector3 operator+ (const TVector3 &v3, const Vector2 &v2) - { - return TVector3(v3.X + v2.X, v3.Y + v2.Y, v3.Z); - } - - friend TVector3 operator- (const TVector3 &v3, const Vector2 &v2) - { - return TVector3(v3.X - v2.X, v3.Y - v2.Y, v3.Z); - } - - friend Vector2 operator+ (const Vector2 &v2, const TVector3 &v3) - { - return Vector2(v2.X + v3.X, v2.Y + v3.Y); - } - - // Subtract a 3D vector and a 2D vector. - // Discards the Z component of the 3D vector and returns a 2D vector. - friend Vector2 operator- (const TVector2 &v2, const TVector3 &v3) - { - return Vector2(v2.X - v3.X, v2.Y - v3.Y); - } - - void GetRightUp(TVector3 &right, TVector3 &up) - { - TVector3 n(X, Y, Z); - TVector3 fn(fabs(n.X), fabs(n.Y), fabs(n.Z)); - int major = 0; - - if (fn[1] > fn[major]) major = 1; - if (fn[2] > fn[major]) major = 2; - - // build right vector by hand - if (fabs(fn[0] - 1.0f) < FLT_EPSILON || fabs(fn[1] - 1.0f) < FLT_EPSILON || fabs(fn[2] - 1.0f) < FLT_EPSILON) - { - if (major == 0 && n[0] > 0.f) - { - right = { 0.f, 0.f, -1.f }; - } - else if (major == 0) - { - right = { 0.f, 0.f, 1.f }; - } - else if (major == 1 || (major == 2 && n[2] > 0.f)) - { - right = { 1.f, 0.f, 0.f }; - } - // Unconditional to ease static analysis - else // major == 2 && n[2] <= 0.0f - { - right = { -1.f, 0.f, 0.f }; - } - } - else - { - static TVector3 axis[3] = - { - { 1.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f } - }; - - right = axis[major] ^ n; - } - - up = n ^right; - right.MakeUnit();; - up.MakeUnit(); - } - - - // Returns the angle (in radians) that the ray (0,0)-(X,Y) faces - TAngle Angle() const; - TAngle Pitch() const; - - // Vector length - double Length() const - { - return g_sqrt (X*X + Y*Y + Z*Z); - } - - double LengthSquared() const - { - return X*X + Y*Y + Z*Z; - } - - // Return a unit vector facing the same direction as this one - TVector3 Unit() const - { - double len = Length(); - if (len != 0) len = 1 / len; - return *this * (vec_t)len; - } - - // Scales this vector into a unit vector - void MakeUnit() - { - double len = Length(); - if (len != 0) len = 1 / len; - *this *= (vec_t)len; - } - - // Resizes this vector to be the specified length (if it is not 0) - TVector3 &MakeResize(double len) - { - double vlen = Length(); - if (vlen != 0.) - { - double scale = len / vlen; - X = vec_t(X * scale); - Y = vec_t(Y * scale); - Z = vec_t(Z * scale); - } - return *this; - } - - TVector3 Resized(double len) - { - double vlen = Length(); - if (vlen != 0.) - { - double scale = len / vlen; - return{ vec_t(X * scale), vec_t(Y * scale), vec_t(Z * scale) }; - } - else - { - return *this; - } - } - - // Dot product - vec_t operator | (const TVector3 &other) const - { - return X*other.X + Y*other.Y + Z*other.Z; - } - - // Cross product - TVector3 operator ^ (const TVector3 &other) const - { - return TVector3(Y*other.Z - Z*other.Y, - Z*other.X - X*other.Z, - X*other.Y - Y*other.X); - } - - TVector3 &operator ^= (const TVector3 &other) - { - *this = *this ^ other; - return *this; - } -}; - -template -struct TVector4 -{ - typedef TVector3 Vector3; - - vec_t X, Y, Z, W; - - TVector4() = default; - - TVector4(vec_t a, vec_t b, vec_t c, vec_t d) - : X(a), Y(b), Z(c), W(d) - { - } - - TVector4(vec_t *o) - : X(o[0]), Y(o[1]), Z(o[2]), W(o[3]) - { - } - - TVector4(const TVector4 &other) = default; - - TVector4(const Vector3 &xyz, vec_t w) - : X(xyz.X), Y(xyz.Y), Z(xyz.Z), W(w) - { - } - - void Zero() - { - Z = Y = X = W = 0; - } - - bool isZero() const - { - return X == 0 && Y == 0 && Z == 0 && W == 0; - } - - TVector4 &operator= (const TVector4 &other) = default; - - // Access X and Y and Z as an array - vec_t &operator[] (int index) - { - return (&X)[index]; - } - - const vec_t &operator[] (int index) const - { - return (&X)[index]; - } - - // Test for equality - bool operator== (const TVector4 &other) const - { - return X == other.X && Y == other.Y && Z == other.Z && W == other.W; - } - - // Test for inequality - bool operator!= (const TVector4 &other) const - { - return X != other.X || Y != other.Y || Z != other.Z || W != other.W; - } - - // Test for approximate equality - bool ApproximatelyEquals(const TVector4 &other) const - { - return fabs(X - other.X) < EQUAL_EPSILON && fabs(Y - other.Y) < EQUAL_EPSILON && fabs(Z - other.Z) < EQUAL_EPSILON && fabs(W - other.W) < EQUAL_EPSILON; - } - - // Test for approximate inequality - bool DoesNotApproximatelyEqual(const TVector4 &other) const - { - return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON || fabs(Z - other.Z) >= EQUAL_EPSILON || fabs(W - other.W) >= EQUAL_EPSILON; - } - - // Unary negation - TVector4 operator- () const - { - return TVector4(-X, -Y, -Z, -W); - } - - // Scalar addition - TVector4 &operator+= (vec_t scalar) - { - X += scalar, Y += scalar, Z += scalar; W += scalar; - return *this; - } - - friend TVector4 operator+ (const TVector4 &v, vec_t scalar) - { - return TVector4(v.X + scalar, v.Y + scalar, v.Z + scalar, v.W + scalar); - } - - friend TVector4 operator+ (vec_t scalar, const TVector4 &v) - { - return TVector4(v.X + scalar, v.Y + scalar, v.Z + scalar, v.W + scalar); - } - - // Scalar subtraction - TVector4 &operator-= (vec_t scalar) - { - X -= scalar, Y -= scalar, Z -= scalar, W -= scalar; - return *this; - } - - TVector4 operator- (vec_t scalar) const - { - return TVector4(X - scalar, Y - scalar, Z - scalar, W - scalar); - } - - // Scalar multiplication - TVector4 &operator*= (vec_t scalar) - { - X = vec_t(X *scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar), W = vec_t(W * scalar); - return *this; - } - - friend TVector4 operator* (const TVector4 &v, vec_t scalar) - { - return TVector4(v.X * scalar, v.Y * scalar, v.Z * scalar, v.W * scalar); - } - - friend TVector4 operator* (vec_t scalar, const TVector4 &v) - { - return TVector4(v.X * scalar, v.Y * scalar, v.Z * scalar, v.W * scalar); - } - - // Scalar division - TVector4 &operator/= (vec_t scalar) - { - scalar = 1 / scalar, X = vec_t(X * scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar), W = vec_t(W * scalar); - return *this; - } - - TVector4 operator/ (vec_t scalar) const - { - scalar = 1 / scalar; - return TVector4(X * scalar, Y * scalar, Z * scalar, W * scalar); - } - - // Vector addition - TVector4 &operator+= (const TVector4 &other) - { - X += other.X, Y += other.Y, Z += other.Z, W += other.W; - return *this; - } - - TVector4 operator+ (const TVector4 &other) const - { - return TVector4(X + other.X, Y + other.Y, Z + other.Z, W + other.W); - } - - // Vector subtraction - TVector4 &operator-= (const TVector4 &other) - { - X -= other.X, Y -= other.Y, Z -= other.Z, W -= other.W; - return *this; - } - - TVector4 operator- (const TVector4 &other) const - { - return TVector4(X - other.X, Y - other.Y, Z - other.Z, W - other.W); - } - - // Add a 3D vector to this 4D vector, leaving W unchanged. - TVector4 &operator+= (const Vector3 &other) - { - X += other.X, Y += other.Y, Z += other.Z; - return *this; - } - - // Subtract a 3D vector from this 4D vector, leaving W unchanged. - TVector4 &operator-= (const Vector3 &other) - { - X -= other.X, Y -= other.Y, Z -= other.Z; - return *this; - } - - // returns the XYZ fields as a 3D-vector. - Vector3 XYZ() const - { - return{ X, Y, Z }; - } - - // Add a 4D vector and a 3D vector. - friend TVector4 operator+ (const TVector4 &v4, const Vector3 &v3) - { - return TVector4(v4.X + v3.X, v4.Y + v3.Y, v4.Z + v3.Z, v4.W); - } - - friend TVector4 operator- (const TVector4 &v4, const Vector3 &v3) - { - return TVector4(v4.X - v3.X, v4.Y - v3.Y, v4.Z - v3.Z, v4.W); - } - - friend Vector3 operator+ (const Vector3 &v3, const TVector4 &v4) - { - return Vector3(v3.X + v4.X, v3.Y + v4.Y, v3.Z + v4.Z); - } - - // Subtract a 4D vector and a 3D vector. - // Discards the W component of the 4D vector and returns a 3D vector. - friend Vector3 operator- (const TVector3 &v3, const TVector4 &v4) - { - return Vector3(v3.X - v4.X, v3.Y - v4.Y, v3.Z - v4.Z); - } - - // Vector length - double Length() const - { - return g_sqrt(X*X + Y*Y + Z*Z + W*W); - } - - double LengthSquared() const - { - return X*X + Y*Y + Z*Z + W*W; - } - - // Return a unit vector facing the same direction as this one - TVector4 Unit() const - { - double len = Length(); - if (len != 0) len = 1 / len; - return *this * (vec_t)len; - } - - // Scales this vector into a unit vector - void MakeUnit() - { - double len = Length(); - if (len != 0) len = 1 / len; - *this *= (vec_t)len; - } - - // Resizes this vector to be the specified length (if it is not 0) - TVector4 &MakeResize(double len) - { - double vlen = Length(); - if (vlen != 0.) - { - double scale = len / vlen; - X = vec_t(X * scale); - Y = vec_t(Y * scale); - Z = vec_t(Z * scale); - W = vec_t(W * scale); - } - return *this; - } - - TVector4 Resized(double len) - { - double vlen = Length(); - if (vlen != 0.) - { - double scale = len / vlen; - return{ vec_t(X * scale), vec_t(Y * scale), vec_t(Z * scale), vec_t(W * scale) }; - } - else - { - return *this; - } - } - - // Dot product - vec_t operator | (const TVector4 &other) const - { - return X*other.X + Y*other.Y + Z*other.Z + W*other.W; - } -}; - -template -struct TMatrix3x3 -{ - typedef TVector3 Vector3; - - vec_t Cells[3][3]; - - TMatrix3x3() = default; - TMatrix3x3(const TMatrix3x3 &other) = default; - - TMatrix3x3(const Vector3 &row1, const Vector3 &row2, const Vector3 &row3) - { - (*this)[0] = row1; - (*this)[1] = row2; - (*this)[2] = row3; - } - - // Construct a rotation matrix about an arbitrary axis. - // (The axis vector must be normalized.) - TMatrix3x3(const Vector3 &axis, double radians) - { - double c = g_cos(radians), s = g_sin(radians), t = 1 - c; -/* In comments: A more readable version of the matrix setup. -This was found in Diana Gruber's article "The Mathematics of the -3D Rotation Matrix" at and is -attributed to Graphics Gems (Glassner, Academic Press, 1990). - - Cells[0][0] = t*axis.X*axis.X + c; - Cells[0][1] = t*axis.X*axis.Y - s*axis.Z; - Cells[0][2] = t*axis.X*axis.Z + s*axis.Y; - - Cells[1][0] = t*axis.Y*axis.X + s*axis.Z; - Cells[1][1] = t*axis.Y*axis.Y + c; - Cells[1][2] = t*axis.Y*axis.Z - s*axis.X; - - Cells[2][0] = t*axis.Z*axis.X - s*axis.Y; - Cells[2][1] = t*axis.Z*axis.Y + s*axis.X; - Cells[2][2] = t*axis.Z*axis.Z + c; - -Outside comments: A faster version with only 10 (not 24) multiplies. -*/ - double sx = s*axis.X, sy = s*axis.Y, sz = s*axis.Z; - double tx, ty, txx, tyy, u, v; - - tx = t*axis.X; - Cells[0][0] = vec_t( (txx=tx*axis.X) + c ); - Cells[0][1] = vec_t( (u=tx*axis.Y) - sz); - Cells[0][2] = vec_t( (v=tx*axis.Z) + sy); - - ty = t*axis.Y; - Cells[1][0] = vec_t( u + sz); - Cells[1][1] = vec_t( (tyy=ty*axis.Y) + c ); - Cells[1][2] = vec_t( (u=ty*axis.Z) - sx); - - Cells[2][0] = vec_t( v - sy); - Cells[2][1] = vec_t( u + sx); - Cells[2][2] = vec_t( (t-txx-tyy) + c ); - } - - TMatrix3x3(const Vector3 &axis, double c/*cosine*/, double s/*sine*/) - { - double t = 1 - c; - double sx = s*axis.X, sy = s*axis.Y, sz = s*axis.Z; - double tx, ty, txx, tyy, u, v; - - tx = t*axis.X; - Cells[0][0] = vec_t( (txx=tx*axis.X) + c ); - Cells[0][1] = vec_t( (u=tx*axis.Y) - sz); - Cells[0][2] = vec_t( (v=tx*axis.Z) + sy); - - ty = t*axis.Y; - Cells[1][0] = vec_t( u + sz); - Cells[1][1] = vec_t( (tyy=ty*axis.Y) + c ); - Cells[1][2] = vec_t( (u=ty*axis.Z) - sx); - - Cells[2][0] = vec_t( v - sy); - Cells[2][1] = vec_t( u + sx); - Cells[2][2] = vec_t( (t-txx-tyy) + c ); - } - - TMatrix3x3(const Vector3 &axis, TAngle degrees); - - static TMatrix3x3 Rotate2D(double radians) - { - double c = g_cos(radians); - double s = g_sin(radians); - TMatrix3x3 ret; - ret.Cells[0][0] = c; ret.Cells[0][1] = -s; ret.Cells[0][2] = 0; - ret.Cells[1][0] = s; ret.Cells[1][1] = c; ret.Cells[1][2] = 0; - ret.Cells[2][0] = 0; ret.Cells[2][1] = 0; ret.Cells[2][2] = 1; - return ret; - } - - static TMatrix3x3 Scale2D(TVector2 scaleVec) - { - TMatrix3x3 ret; - ret.Cells[0][0] = scaleVec.X; ret.Cells[0][1] = 0; ret.Cells[0][2] = 0; - ret.Cells[1][0] = 0; ret.Cells[1][1] = scaleVec.Y; ret.Cells[1][2] = 0; - ret.Cells[2][0] = 0; ret.Cells[2][1] = 0; ret.Cells[2][2] = 1; - return ret; - } - - static TMatrix3x3 Translate2D(TVector2 translateVec) - { - TMatrix3x3 ret; - ret.Cells[0][0] = 1; ret.Cells[0][1] = 0; ret.Cells[0][2] = translateVec.X; - ret.Cells[1][0] = 0; ret.Cells[1][1] = 1; ret.Cells[1][2] = translateVec.Y; - ret.Cells[2][0] = 0; ret.Cells[2][1] = 0; ret.Cells[2][2] = 1; - return ret; - } - - void Zero() - { - memset (this, 0, sizeof *this); - } - - void Identity() - { - Cells[0][0] = 1; Cells[0][1] = 0; Cells[0][2] = 0; - Cells[1][0] = 0; Cells[1][1] = 1; Cells[1][2] = 0; - Cells[2][0] = 0; Cells[2][1] = 0; Cells[2][2] = 1; - } - - Vector3 &operator[] (int index) - { - return *((Vector3 *)&Cells[index]); - } - - const Vector3 &operator[] (int index) const - { - return *((Vector3 *)&Cells[index]); - } - - // Multiply a scalar - TMatrix3x3 &operator*= (double scalar) - { - (*this)[0] *= scalar; - (*this)[1] *= scalar; - (*this)[2] *= scalar; - return *this; - } - - friend TMatrix3x3 operator* (double s, const TMatrix3x3 &m) - { - return TMatrix3x3(m[0]*s, m[1]*s, m[2]*s); - } - - TMatrix3x3 operator* (double s) const - { - return TMatrix3x3((*this)[0]*s, (*this)[1]*s, (*this)[2]*s); - } - - // Divide a scalar - TMatrix3x3 &operator/= (double scalar) - { - return *this *= 1 / scalar; - } - - TMatrix3x3 operator/ (double s) const - { - return *this * (1 / s); - } - - // Add two 3x3 matrices together - TMatrix3x3 &operator+= (const TMatrix3x3 &o) - { - (*this)[0] += o[0]; - (*this)[1] += o[1]; - (*this)[2] += o[2]; - return *this; - } - - TMatrix3x3 operator+ (const TMatrix3x3 &o) const - { - return TMatrix3x3((*this)[0] + o[0], (*this)[1] + o[1], (*this)[2] + o[2]); - } - - // Subtract two 3x3 matrices - TMatrix3x3 &operator-= (const TMatrix3x3 &o) - { - (*this)[0] -= o[0]; - (*this)[1] -= o[1]; - (*this)[2] -= o[2]; - return *this; - } - - TMatrix3x3 operator- (const TMatrix3x3 &o) const - { - return TMatrix3x3((*this)[0] - o[0], (*this)[1] - o[1], (*this)[2] - o[2]); - } - - // Concatenate two 3x3 matrices - TMatrix3x3 &operator*= (const TMatrix3x3 &o) - { - return *this = *this * o; - } - - TMatrix3x3 operator* (const TMatrix3x3 &o) const - { - return TMatrix3x3( - Vector3(Cells[0][0]*o[0][0] + Cells[0][1]*o[1][0] + Cells[0][2]*o[2][0], - Cells[0][0]*o[0][1] + Cells[0][1]*o[1][1] + Cells[0][2]*o[2][1], - Cells[0][0]*o[0][2] + Cells[0][1]*o[1][2] + Cells[0][2]*o[2][2]), - Vector3(Cells[1][0]*o[0][0] + Cells[1][1]*o[1][0] + Cells[1][2]*o[2][0], - Cells[1][0]*o[0][1] + Cells[1][1]*o[1][1] + Cells[1][2]*o[2][1], - Cells[1][0]*o[0][2] + Cells[1][1]*o[1][2] + Cells[1][2]*o[2][2]), - Vector3(Cells[2][0]*o[0][0] + Cells[2][1]*o[1][0] + Cells[2][2]*o[2][0], - Cells[2][0]*o[0][1] + Cells[2][1]*o[1][1] + Cells[2][2]*o[2][1], - Cells[2][0]*o[0][2] + Cells[2][1]*o[1][2] + Cells[2][2]*o[2][2])); - } - - // Multiply a 3D vector by a rotation matrix - friend Vector3 operator* (const Vector3 &v, const TMatrix3x3 &m) - { - return Vector3(m[0] | v, m[1] | v, m[2] | v); - } - - friend Vector3 operator* (const TMatrix3x3 &m, const Vector3 &v) - { - return Vector3(m[0] | v, m[1] | v, m[2] | v); - } -}; - -#define BAM_FACTOR (90. / 0x40000000) - -template -struct TAngle -{ - vec_t Degrees; - - // This is to catch any accidental attempt to assign an angle_t to this type. Any explicit exception will require a type cast. - TAngle(int) = delete; - TAngle(unsigned int) = delete; - TAngle(long) = delete; - TAngle(unsigned long) = delete; - TAngle &operator= (int other) = delete; - TAngle &operator= (unsigned other) = delete; - TAngle &operator= (long other) = delete; - TAngle &operator= (unsigned long other) = delete; - - TAngle() = default; - - TAngle (vec_t amt) - : Degrees(amt) - { - } - - TAngle(const TAngle &other) = default; - TAngle &operator= (const TAngle &other) = default; - - TAngle &operator= (double other) - { - Degrees = (decltype(Degrees))other; - return *this; - } - - // intentionally disabled so that common math functions cannot be accidentally called with a TAngle. - //operator vec_t() const { return Degrees; } - - TAngle operator- () const - { - return TAngle(-Degrees); - } - - TAngle &operator+= (TAngle other) - { - Degrees += other.Degrees; - return *this; - } - - TAngle &operator-= (TAngle other) - { - Degrees -= other.Degrees; - return *this; - } - - TAngle &operator*= (TAngle other) - { - Degrees *= other.Degrees; - return *this; - } - - TAngle &operator/= (TAngle other) - { - Degrees /= other.Degrees; - return *this; - } - - TAngle operator+ (TAngle other) const - { - return Degrees + other.Degrees; - } - - TAngle operator- (TAngle other) const - { - return Degrees - other.Degrees; - } - - TAngle operator* (TAngle other) const - { - return Degrees * other.Degrees; - } - - TAngle operator/ (TAngle other) const - { - return Degrees / other.Degrees; - } - - TAngle &operator+= (vec_t other) - { - Degrees = Degrees + other; - return *this; - } - - TAngle &operator-= (vec_t other) - { - Degrees = Degrees - other; - return *this; - } - - TAngle &operator*= (vec_t other) - { - Degrees = Degrees * other; - return *this; - } - - TAngle &operator/= (vec_t other) - { - Degrees = Degrees / other; - return *this; - } - - TAngle operator+ (vec_t other) const - { - return Degrees + other; - } - - TAngle operator- (vec_t other) const - { - return Degrees - other; - } - - friend TAngle operator- (vec_t o1, TAngle o2) - { - return TAngle(o1 - o2.Degrees); - } - - TAngle operator* (vec_t other) const - { - return Degrees * other; - } - - TAngle operator/ (vec_t other) const - { - return Degrees / other; - } - - // Should the comparisons consider an epsilon value? - bool operator< (TAngle other) const - { - return Degrees < other.Degrees; - } - - bool operator> (TAngle other) const - { - return Degrees > other.Degrees; - } - - bool operator<= (TAngle other) const - { - return Degrees <= other.Degrees; - } - - bool operator>= (TAngle other) const - { - return Degrees >= other.Degrees; - } - - bool operator== (TAngle other) const - { - return Degrees == other.Degrees; - } - - bool operator!= (TAngle other) const - { - return Degrees != other.Degrees; - } - - bool operator< (vec_t other) const - { - return Degrees < other; - } - - bool operator> (vec_t other) const - { - return Degrees > other; - } - - bool operator<= (vec_t other) const - { - return Degrees <= other; - } - - bool operator>= (vec_t other) const - { - return Degrees >= other; - } - - bool operator== (vec_t other) const - { - return Degrees == other; - } - - bool operator!= (vec_t other) const - { - return Degrees != other; - } - - // Ensure the angle is between [0.0,360.0) degrees - TAngle Normalized360() const - { - // Normalizing the angle converts it to a BAM, which masks it, and converts it back to a float. - // Note: We MUST use xs_Float here because it is the only method that guarantees reliable wraparound. - return (vec_t)(BAM_FACTOR * BAMs()); - } - - // Ensures the angle is between (-180.0,180.0] degrees - TAngle Normalized180() const - { - return (vec_t)(BAM_FACTOR * (signed int)BAMs()); - } - - vec_t Radians() const - { - return vec_t(Degrees * (pi::pi() / 180.0)); - } - - unsigned BAMs() const - { - return xs_CRoundToInt(Degrees * (0x40000000 / 90.)); - } - - TVector2 ToVector(vec_t length = 1) const - { - return TVector2(length * Cos(), length * Sin()); - } - - vec_t Cos() const - { - return vec_t(g_cosdeg(Degrees)); - } - - vec_t Sin() const - { - return vec_t(g_sindeg(Degrees)); - } - - double Tan() const - { - return g_tan(Degrees * (pi::pi() / 180.)); - } - - // This is for calculating vertical velocity. For high pitches the tangent will become too large to be useful. - double TanClamped(double max = 5.) const - { - return clamp(Tan(), -max, max); - } - - static inline TAngle ToDegrees(double rad) - { - return TAngle(double(rad * (180.0 / pi::pi()))); - } - -}; - -// Emulates the old floatbob offset table with direct calls to trig functions. -inline double BobSin(double fb) -{ - return TAngle(double(fb * (180.0 / 32))).Sin() * 8; -} - -template -inline TAngle fabs (const TAngle °) -{ - return TAngle(fabs(deg.Degrees)); -} - -template -inline TAngle deltaangle(const TAngle &a1, const TAngle &a2) -{ - return (a2 - a1).Normalized180(); -} - -template -inline TAngle deltaangle(const TAngle &a1, double a2) -{ - return (a2 - a1).Normalized180(); -} - -template -inline TAngle deltaangle(double a1, const TAngle &a2) -{ - return (a2 - a1).Normalized180(); -} - -template -inline TAngle absangle(const TAngle &a1, const TAngle &a2) -{ - return fabs((a1 - a2).Normalized180()); -} - -template -inline TAngle absangle(const TAngle &a1, double a2) -{ - return fabs((a1 - a2).Normalized180()); -} - -inline TAngle VecToAngle(double x, double y) -{ - return g_atan2(y, x) * (180.0 / pi::pi()); -} - -template -inline TAngle VecToAngle (const TVector2 &vec) -{ - return (T)g_atan2(vec.Y, vec.X) * (180.0 / pi::pi()); -} - -template -inline TAngle VecToAngle (const TVector3 &vec) -{ - return (T)g_atan2(vec.Y, vec.X) * (180.0 / pi::pi()); -} - -template -TAngle TVector2::Angle() const -{ - return VecToAngle(X, Y); -} - -template -TAngle TVector3::Angle() const -{ - return VecToAngle(X, Y); -} - -template -TAngle TVector3::Pitch() const -{ - return -VecToAngle(TVector2(X, Y).Length(), Z); -} - -// Much of this is copied from TVector3. Is all that functionality really appropriate? -template -struct TRotator -{ - typedef TAngle Angle; - - Angle Pitch; // up/down - Angle Yaw; // left/right - Angle Roll; // rotation about the forward axis. - Angle CamRoll; // Roll specific to actor cameras. Used by quakes. - - TRotator() = default; - - TRotator (const Angle &p, const Angle &y, const Angle &r) - : Pitch(p), Yaw(y), Roll(r) - { - } - - TRotator(const TRotator &other) = default; - TRotator &operator= (const TRotator &other) = default; - - // Access angles as an array - Angle &operator[] (int index) - { - return *(&Pitch + index); - } - - const Angle &operator[] (int index) const - { - return *(&Pitch + index); - } - - // Test for equality - bool operator== (const TRotator &other) const - { - return fabs(Pitch - other.Pitch) < Angle(EQUAL_EPSILON) && fabs(Yaw - other.Yaw) < Angle(EQUAL_EPSILON) && fabs(Roll - other.Roll) < Angle(EQUAL_EPSILON); - } - - // Test for inequality - bool operator!= (const TRotator &other) const - { - return fabs(Pitch - other.Pitch) >= Angle(EQUAL_EPSILON) && fabs(Yaw - other.Yaw) >= Angle(EQUAL_EPSILON) && fabs(Roll - other.Roll) >= Angle(EQUAL_EPSILON); - } - - // Unary negation - TRotator operator- () const - { - return TRotator(-Pitch, -Yaw, -Roll); - } - - // Scalar addition - TRotator &operator+= (const Angle &scalar) - { - Pitch += scalar, Yaw += scalar, Roll += scalar; - return *this; - } - - friend TRotator operator+ (const TRotator &v, const Angle &scalar) - { - return TRotator(v.Pitch + scalar, v.Yaw + scalar, v.Roll + scalar); - } - - friend TRotator operator+ (const Angle &scalar, const TRotator &v) - { - return TRotator(v.Pitch + scalar, v.Yaw + scalar, v.Roll + scalar); - } - - // Scalar subtraction - TRotator &operator-= (const Angle &scalar) - { - Pitch -= scalar, Yaw -= scalar, Roll -= scalar; - return *this; - } - - TRotator operator- (const Angle &scalar) const - { - return TRotator(Pitch - scalar, Yaw - scalar, Roll - scalar); - } - - // Scalar multiplication - TRotator &operator*= (const Angle &scalar) - { - Pitch *= scalar, Yaw *= scalar, Roll *= scalar; - return *this; - } - - friend TRotator operator* (const TRotator &v, const Angle &scalar) - { - return TRotator(v.Pitch * scalar, v.Yaw * scalar, v.Roll * scalar); - } - - friend TRotator operator* (const Angle &scalar, const TRotator &v) - { - return TRotator(v.Pitch * scalar, v.Yaw * scalar, v.Roll * scalar); - } - - // Scalar division - TRotator &operator/= (const Angle &scalar) - { - Angle mul(1 / scalar.Degrees); - Pitch *= scalar, Yaw *= scalar, Roll *= scalar; - return *this; - } - - TRotator operator/ (const Angle &scalar) const - { - Angle mul(1 / scalar.Degrees); - return TRotator(Pitch * mul, Yaw * mul, Roll * mul); - } - - // Vector addition - TRotator &operator+= (const TRotator &other) - { - Pitch += other.Pitch, Yaw += other.Yaw, Roll += other.Roll; - return *this; - } - - TRotator operator+ (const TRotator &other) const - { - return TRotator(Pitch + other.Pitch, Yaw + other.Yaw, Roll + other.Roll); - } - - // Vector subtraction - TRotator &operator-= (const TRotator &other) - { - Pitch -= other.Pitch, Yaw -= other.Yaw, Roll -= other.Roll; - return *this; - } - - TRotator operator- (const TRotator &other) const - { - return TRotator(Pitch - other.Pitch, Yaw - other.Yaw, Roll - other.Roll); - } -}; - -// Create a forward vector from a rotation (ignoring roll) - -template -inline TVector3::TVector3 (const TRotator &rot) -{ - double pcos = rot.Pitch.Cos(); - X = pcos * rot.Yaw.Cos(); - Y = pcos * rot.Yaw.Sin(); - Z = rot.Pitch.Sin(); -} - -template -inline TMatrix3x3::TMatrix3x3(const TVector3 &axis, TAngle degrees) -{ - double c = degrees.Cos(), s = degrees.Sin(), t = 1 - c; - double sx = s*axis.X, sy = s*axis.Y, sz = s*axis.Z; - double tx, ty, txx, tyy, u, v; - - tx = t*axis.X; - Cells[0][0] = T( (txx=tx*axis.X) + c ); - Cells[0][1] = T( (u=tx*axis.Y) - sz ); - Cells[0][2] = T( (v=tx*axis.Z) + sy ); - - ty = t*axis.Y; - Cells[1][0] = T( u + sz ); - Cells[1][1] = T( (tyy=ty*axis.Y) + c ); - Cells[1][2] = T( (u=ty*axis.Z) - sx ); - - Cells[2][0] = T( v - sy ); - Cells[2][1] = T( u + sx ); - Cells[2][2] = T( (t-txx-tyy) + c ); -} - - -typedef TVector2 FVector2; -typedef TVector3 FVector3; -typedef TVector4 FVector4; -typedef TRotator FRotator; -typedef TMatrix3x3 FMatrix3x3; -typedef TAngle FAngle; - -typedef TVector2 DVector2; -typedef TVector3 DVector3; -typedef TVector4 DVector4; -typedef TRotator DRotator; -typedef TMatrix3x3 DMatrix3x3; -typedef TAngle DAngle; - - -class Plane -{ -public: - void Set(FVector3 normal, float d) - { - m_normal = normal; - m_d = d; - } - - // same for a play-vector. Note that y and z are inversed. - void Set(DVector3 normal, double d) - { - m_normal = { (float)normal.X, (float)normal.Z, (float)normal.Y }; - m_d = (float)d; - } - - float DistToPoint(float x, float y, float z) - { - FVector3 p(x, y, z); - - return (m_normal | p) + m_d; - } - - - bool PointOnSide(float x, float y, float z) - { - return DistToPoint(x, y, z) < 0.f; - } - - bool PointOnSide(FVector3 &v) { return PointOnSide(v.X, v.Y, v.Z); } - - float A() { return m_normal.X; } - float B() { return m_normal.Y; } - float C() { return m_normal.Z; } - float D() { return m_d; } - - const FVector3 &Normal() const { return m_normal; } -protected: - FVector3 m_normal; - float m_d; -}; - -#endif diff --git a/src/utility/x86.cpp b/src/utility/x86.cpp deleted file mode 100644 index c03c87efba5..00000000000 --- a/src/utility/x86.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* -** -** -**--------------------------------------------------------------------------- -** Copyright 2005-2016 Randy Heit -** Copyright 2005-2016 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "doomtype.h" -#include "doomdef.h" -#include "x86.h" - -CPUInfo CPU; - -#if !defined(__amd64__) && !defined(__i386__) && !defined(_M_IX86) && !defined(_M_X64) -void CheckCPUID(CPUInfo *cpu) -{ - memset(cpu, 0, sizeof(*cpu)); - cpu->DataL1LineSize = 32; // Assume a 32-byte cache line -} - -void DumpCPUInfo(const CPUInfo *cpu) -{ -} -#else - -#ifdef _MSC_VER -#include -#endif -#include - - -#ifdef __GNUC__ -#if defined(__i386__) && defined(__PIC__) -// %ebx may by the PIC register. */ -#define __cpuid(output, func) \ - __asm__ __volatile__("xchgl\t%%ebx, %1\n\t" \ - "cpuid\n\t" \ - "xchgl\t%%ebx, %1\n\t" \ - : "=a" ((output)[0]), "=r" ((output)[1]), "=c" ((output)[2]), "=d" ((output)[3]) \ - : "a" (func)); -#else -#define __cpuid(output, func) __asm__ __volatile__("cpuid" : "=a" ((output)[0]),\ - "=b" ((output)[1]), "=c" ((output)[2]), "=d" ((output)[3]) : "a" (func)); -#endif -#endif - -void CheckCPUID(CPUInfo *cpu) -{ - int foo[4]; - unsigned int maxext; - - memset(cpu, 0, sizeof(*cpu)); - - cpu->DataL1LineSize = 32; // Assume a 32-byte cache line - -#if !defined(_M_IX86) && !defined(__i386__) && !defined(_M_X64) && !defined(__amd64__) - return; -#else - -#if defined(_M_IX86) || defined(__i386__) - // Old 486s do not have CPUID, so we must test for its presence. - // This code is adapted from the samples in AMD's document - // entitled "AMD-K6 MMX Processor Multimedia Extensions." -#ifndef __GNUC__ - __asm - { - pushfd // save EFLAGS - pop eax // store EFLAGS in EAX - mov ecx,eax // save in ECX for later testing - xor eax,0x00200000 // toggle bit 21 - push eax // put to stack - popfd // save changed EAX to EFLAGS - pushfd // push EFLAGS to TOS - pop eax // store EFLAGS in EAX - cmp eax,ecx // see if bit 21 has changed - jne haveid // if no change, then no CPUID - } - return; -haveid: -#else - int oldfd, newfd; - - __asm__ __volatile__("\t" - "pushf\n\t" - "popl %0\n\t" - "movl %0,%1\n\t" - "xorl $0x200000,%0\n\t" - "pushl %0\n\t" - "popf\n\t" - "pushf\n\t" - "popl %0\n\t" - : "=r" (newfd), "=r" (oldfd)); - if (oldfd == newfd) - { - return; - } -#endif -#endif - - // Get vendor ID - __cpuid(foo, 0); - cpu->dwVendorID[0] = foo[1]; - cpu->dwVendorID[1] = foo[3]; - cpu->dwVendorID[2] = foo[2]; - if (foo[1] == MAKE_ID('A','u','t','h') && - foo[3] == MAKE_ID('e','n','t','i') && - foo[2] == MAKE_ID('c','A','M','D')) - { - cpu->bIsAMD = true; - } - - // Get features flags and other info - __cpuid(foo, 1); - cpu->FeatureFlags[0] = foo[1]; // Store brand index and other stuff - cpu->FeatureFlags[1] = foo[2]; // Store extended feature flags - cpu->FeatureFlags[2] = foo[3]; // Store feature flags - - cpu->HyperThreading = (foo[3] & (1 << 28)) > 0; - - // If CLFLUSH instruction is supported, get the real cache line size. - if (foo[3] & (1 << 19)) - { - cpu->DataL1LineSize = (foo[1] & 0xFF00) >> (8 - 3); - } - - cpu->Stepping = foo[0] & 0x0F; - cpu->Type = (foo[0] & 0x3000) >> 12; // valid on Intel only - cpu->Model = (foo[0] & 0xF0) >> 4; - cpu->Family = (foo[0] & 0xF00) >> 8; - - if (cpu->Family == 15) - { // Add extended family. - cpu->Family += (foo[0] >> 20) & 0xFF; - } - if (cpu->Family == 6 || cpu->Family == 15) - { // Add extended model ID. - cpu->Model |= (foo[0] >> 12) & 0xF0; - } - - // Check for extended functions. - __cpuid(foo, 0x80000000); - maxext = (unsigned int)foo[0]; - - if (maxext >= 0x80000004) - { // Get processor brand string. - __cpuid((int *)&cpu->dwCPUString[0], 0x80000002); - __cpuid((int *)&cpu->dwCPUString[4], 0x80000003); - __cpuid((int *)&cpu->dwCPUString[8], 0x80000004); - } - - if (cpu->bIsAMD) - { - if (maxext >= 0x80000005) - { // Get data L1 cache info. - __cpuid(foo, 0x80000005); - cpu->AMD_DataL1Info = foo[2]; - } - if (maxext >= 0x80000001) - { // Get AMD-specific feature flags. - __cpuid(foo, 0x80000001); - cpu->AMDStepping = foo[0] & 0x0F; - cpu->AMDModel = (foo[0] & 0xF0) >> 4; - cpu->AMDFamily = (foo[0] & 0xF00) >> 8; - - if (cpu->AMDFamily == 15) - { // Add extended model and family. - cpu->AMDFamily += (foo[0] >> 20) & 0xFF; - cpu->AMDModel |= (foo[0] >> 12) & 0xF0; - } - cpu->FeatureFlags[3] = foo[3]; // AMD feature flags - } - } -#endif -} - -void DumpCPUInfo(const CPUInfo *cpu) -{ - char cpustring[4*4*3+1]; - - // Why does Intel right-justify this string (on P4s) - // or add extra spaces (on Cores)? - const char *f = cpu->CPUString; - char *t; - - // Skip extra whitespace at the beginning. - while (*f == ' ') - { - ++f; - } - - // Copy string to temp buffer, but condense consecutive - // spaces to a single space character. - for (t = cpustring; *f != '\0'; ++f) - { - if (*f == ' ' && *(f - 1) == ' ') - { - continue; - } - *t++ = *f; - } - *t = '\0'; - - if (cpu->VendorID[0] && !batchrun) - { - Printf("CPU Vendor ID: %s\n", cpu->VendorID); - if (cpustring[0]) - { - Printf(" Name: %s\n", cpustring); - } - if (cpu->bIsAMD) - { - Printf(" Family %d (%d), Model %d, Stepping %d\n", - cpu->Family, cpu->AMDFamily, cpu->AMDModel, cpu->AMDStepping); - } - else - { - Printf(" Family %d, Model %d, Stepping %d\n", - cpu->Family, cpu->Model, cpu->Stepping); - } - Printf(" Features:"); - if (cpu->bSSE2) Printf(" SSE2"); - if (cpu->bSSE3) Printf(" SSE3"); - if (cpu->bSSSE3) Printf(" SSSE3"); - if (cpu->bSSE41) Printf(" SSE4.1"); - if (cpu->bSSE42) Printf(" SSE4.2"); - if (cpu->b3DNow) Printf(" 3DNow!"); - if (cpu->b3DNowPlus) Printf(" 3DNow!+"); - if (cpu->HyperThreading) Printf(" HyperThreading"); - Printf ("\n"); - } -} - -#endif diff --git a/src/utility/x86.h b/src/utility/x86.h deleted file mode 100644 index 13152e0d769..00000000000 --- a/src/utility/x86.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef X86_H -#define X86_H - -#include "basictypes.h" - -struct CPUInfo // 92 bytes -{ - union - { - char VendorID[16]; - uint32_t dwVendorID[4]; - }; - union - { - char CPUString[48]; - uint32_t dwCPUString[12]; - }; - - uint8_t Stepping; - uint8_t Model; - uint8_t Family; - uint8_t Type; - uint8_t HyperThreading; - - union - { - struct - { - uint8_t BrandIndex; - uint8_t CLFlush; - uint8_t CPUCount; - uint8_t APICID; - - uint32_t bSSE3:1; - uint32_t DontCare1:8; - uint32_t bSSSE3:1; - uint32_t DontCare1a:9; - uint32_t bSSE41:1; - uint32_t bSSE42:1; - uint32_t DontCare2a:11; - - uint32_t bFPU:1; - uint32_t bVME:1; - uint32_t bDE:1; - uint32_t bPSE:1; - uint32_t bRDTSC:1; - uint32_t bMSR:1; - uint32_t bPAE:1; - uint32_t bMCE:1; - uint32_t bCX8:1; - uint32_t bAPIC:1; - uint32_t bReserved1:1; - uint32_t bSEP:1; - uint32_t bMTRR:1; - uint32_t bPGE:1; - uint32_t bMCA:1; - uint32_t bCMOV:1; - uint32_t bPAT:1; - uint32_t bPSE36:1; - uint32_t bPSN:1; - uint32_t bCFLUSH:1; - uint32_t bReserved2:1; - uint32_t bDS:1; - uint32_t bACPI:1; - uint32_t bMMX:1; - uint32_t bFXSR:1; - uint32_t bSSE:1; - uint32_t bSSE2:1; - uint32_t bSS:1; - uint32_t bHTT:1; - uint32_t bTM:1; - uint32_t bReserved3:1; - uint32_t bPBE:1; - - uint32_t DontCare2:22; - uint32_t bMMXPlus:1; // AMD's MMX extensions - uint32_t bMMXAgain:1; // Just a copy of bMMX above - uint32_t DontCare3:6; - uint32_t b3DNowPlus:1; - uint32_t b3DNow:1; - }; - uint32_t FeatureFlags[4]; - }; - - uint8_t AMDStepping; - uint8_t AMDModel; - uint8_t AMDFamily; - uint8_t bIsAMD; - - union - { - struct - { - uint8_t DataL1LineSize; - uint8_t DataL1LinesPerTag; - uint8_t DataL1Associativity; - uint8_t DataL1SizeKB; - }; - uint32_t AMD_DataL1Info; - }; -}; - - -extern CPUInfo CPU; -struct PalEntry; - -void CheckCPUID (CPUInfo *cpu); -void DumpCPUInfo (const CPUInfo *cpu); - -#endif - diff --git a/src/utility/zstrformat.cpp b/src/utility/zstrformat.cpp deleted file mode 100644 index bf61ce282bf..00000000000 --- a/src/utility/zstrformat.cpp +++ /dev/null @@ -1,1061 +0,0 @@ -/* -** zstrformat.cpp -** Routines for generic printf-style formatting. -** -**--------------------------------------------------------------------------- -** Copyright 2005-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** Portions of this file relating to printing floating point numbers -** are covered by the following copyright: -** -**--------------------------------------------------------------------------- -** Copyright (c) 1990, 1993 -** The Regents of the University of California. All rights reserved. -** -** This code is derived from software contributed to Berkeley by -** Chris Torek. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. -** -**--------------------------------------------------------------------------- -** -** Even though the standard C library has a function to do printf-style -** formatting in a generic way, there is no standard interface to this -** function. So if you want to do some printf formatting that doesn't fit in -** the context of the provided functions, you need to roll your own. Why is -** that? -** -** Maybe Microsoft wants you to write a better one yourself? When used as -** part of a sprintf replacement, this function is significantly faster than -** Microsoft's offering. When used as part of a fprintf replacement, this -** function turns out to be slower, but that's probably because the CRT's -** fprintf can interact with the FILE object on a low level for better -** perfomance. If you sprintf into a buffer and then fwrite that buffer, this -** routine wins again, though the difference isn't great. -*/ - -#include -#include -#include -#include -#include - -#include "zstring.h" -#include "gdtoa.h" -#include "utf8.h" - - -/* - * MAXEXPDIG is the maximum number of decimal digits needed to store a - * floating point exponent in the largest supported format. It should - * be ceil(log10(LDBL_MAX_10_EXP)) or, if hexadecimal floating point - * conversions are supported, ceil(log10(LDBL_MAX_EXP)). But since it - * is presently never greater than 5 in practice, we fudge it. - */ -#define MAXEXPDIG 6 -#if LDBL_MAX_EXP > 999999 -#error "floating point buffers too small" -#endif - -#define DEFPREC 6 - -static const char hexits[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; -static const char HEXits[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; -static const char spaces[16] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; -static const char zeroes[17] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','.'}; - -namespace StringFormat -{ - static int writepad (OutputFunc output, void *outputData, const char *pad, int padsize, int spaceToFill); - static int printandpad (OutputFunc output, void *outputData, const char *p, const char *ep, int len, const char *with, int padsize); - static int exponent (char *p0, int exp, int fmtch); - - int Worker (OutputFunc output, void *outputData, const char *fmt, ...) - { - va_list arglist; - int len; - - va_start (arglist, fmt); - len = VWorker (output, outputData, fmt, arglist); - va_end (arglist); - return len; - } - - int VWorker (OutputFunc output, void *outputData, const char *fmt, va_list arglist) - { - const char *c; - const char *base; - int len = 0; - int width; - int precision; - int flags; - - base = c = fmt; - for (;;) - { - while (*c && *c != '%') - { - ++c; - } - if (*c == '\0') - { - return len + output (outputData, base, int(c - base)); - } - - if (c - base > 0) - { - len += output (outputData, base, int(c - base)); - } - c++; - - // Gather the flags, if any - for (flags = 0;; ++c) - { - if (*c == '-') - { - flags |= F_MINUS; // bit 0 - } - else if (*c == '+') - { - flags |= F_PLUS; // bit 1 - } - else if (*c == '0') - { - flags |= F_ZERO; // bit 2 - } - else if (*c == ' ') - { - flags |= F_BLANK; // bit 3 - } - else if (*c == '#') - { - flags |= F_HASH; // bit 4 - } - else - { - break; - } - } - - width = precision = -1; - - // Read the width, if any - if (*c == '*') - { - ++c; - width = va_arg (arglist, int); - if (width < 0) - { // Negative width means minus flag and positive width - flags |= F_MINUS; - width = -width; - } - } - else if (*c >= '0' && *c <= '9') - { - width = *c++ - '0'; - while (*c >= '0' && *c <= '9') - { - width = width * 10 + *c++ - '0'; - } - } - - // If 0 and - both appear, 0 is ignored. - // If the blank and + both appear, the blank is ignored. - flags &= ~((flags & 3) << 2); - - // Read the precision, if any - if (*c == '.') - { - precision = 0; - if (*++c == '*') - { - ++c; - precision = va_arg (arglist, int); - } - else if (*c >= '0' && *c <= '9') - { - precision = *c++ - '0'; - while (*c >= '0' && *c <= '9') - { - precision = precision * 10 + *c++ - '0'; - } - } - } - - // Read the size prefix, if any - if (*c == 'h') - { - if (*++c == 'h') - { - flags |= F_HALFHALF; - ++c; - } - else - { - flags |= F_HALF; - } - } - else if (*c == 'l') - { - if (*++c == 'l') - { - flags |= F_LONGLONG; - ++c; - } - else - { - flags |= F_LONG; - } - } - else if (*c == 'I') - { - if (*++c == '6') - { - if (*++c == '4') - { - flags |= F_LONGLONG; - ++c; - } - } - else - { - flags |= F_BIGI; - } - } - else if (*c == 't') - { - flags |= F_PTRDIFF; - ++c; - } - else if (*c == 'z') - { - flags |= F_SIZE; - ++c; - } - - base = c+1; - - // Now that that's all out of the way, we should be pointing at the type specifier - { - char prefix[3]; - int prefixlen; - char hexprefix = '\0'; - char sign = '\0'; - int postprefixzeros = 0; - int size = flags & 0xF000; - char buffer[80], *ibuff; - const char *obuff = 0; - char type = *c++; - int bufflen = 0; - int outlen = 0; - unsigned int intarg = 0; - uint64_t int64arg = 0; - const void *voidparg; - const char *charparg; - double dblarg; - const char *xits = hexits; - int inlen = len; - /* - * We can decompose the printed representation of floating - * point numbers into several parts, some of which may be empty: - * - * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ - * A B ---C--- D E F - * - * A: 'sign' holds this value if present; '\0' otherwise - * B: hexprefix holds the 'x' or 'X'; '\0' if not hexadecimal - * C: obuff points to the string MMMNNN. Leading and trailing - * zeros are not in the string and must be added. - * D: expchar holds this character; '\0' if no exponent, e.g. %f - * F: at least two digits for decimal, at least one digit for hex - */ - const char *decimal_point = ".";/* locale specific decimal point */ - int signflag; /* true if float is negative */ - int expt; /* integer value of exponent */ - char expchar = 'e'; /* exponent character: [eEpP\0] */ - char *dtoaend; /* pointer to end of converted digits */ - int expsize = 0; /* character count for expstr */ - int ndig = 0; /* actual number of digits returned by dtoa */ - char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ - char *dtoaresult = NULL; /* buffer allocated by dtoa */ - - // Using a bunch of if/else if statements is faster than a switch, because a switch generates - // a jump table. A jump table means a possible data cache miss and a hefty penalty while the - // cache line is loaded. - - if (type == 'x' || type == 'X' || - type == 'p' || - type == 'd' || type == 'u' || type == 'i' || - type == 'o' || - type == 'B') - { - if (type == 'X' || type == 'p') - { - xits = HEXits; - } - if (type == 'p') - { - type = 'X'; - voidparg = va_arg (arglist, void *); - if (sizeof(void*) == sizeof(int)) - { - intarg = (unsigned int)(size_t)voidparg; - precision = 8; - size = 0; - } - else - { - int64arg = (uint64_t)(size_t)voidparg; - precision = 16; - size = F_LONGLONG; - } - } - else - { - if (size == 0) - { - intarg = va_arg (arglist, int); - } - else if (size == F_HALFHALF) - { - intarg = va_arg (arglist, int); - intarg = (signed char)intarg; - } - else if (size == F_HALF) - { - intarg = va_arg (arglist, int); - intarg = (short)intarg; - } - else if (size == F_LONG) - { - if (sizeof(long) == sizeof(int)) intarg = va_arg (arglist, int); - else { int64arg = va_arg (arglist, int64_t); size = F_LONGLONG; } - } - else if (size == F_BIGI) - { - if (sizeof(void*) == sizeof(int)) intarg = va_arg (arglist, int); - else { int64arg = va_arg (arglist, int64_t); size = F_LONGLONG; } - } - else if (size == F_LONGLONG) - { - int64arg = va_arg (arglist, int64_t); - } - else if (size == F_PTRDIFF) - { - if (sizeof(ptrdiff_t) == sizeof(int)) intarg = va_arg (arglist, int); - else { int64arg = va_arg (arglist, int64_t); size = F_LONGLONG; } - } - else if (size == F_SIZE) - { - if (sizeof(size_t) == sizeof(int)) intarg = va_arg (arglist, int); - else { int64arg = va_arg (arglist, int64_t); size = F_LONGLONG; } - } - else - { - intarg = va_arg (arglist, int); - } - } - - if (precision < 0) precision = 1; - - ibuff = &buffer[sizeof(buffer)]; - - if (size == F_LONGLONG) - { - if (int64arg == 0) - { - flags |= F_ZEROVALUE; - } - else - { - if (type == 'o') - { // Octal: Dump digits until it fits in an unsigned int - while (int64arg > UINT_MAX) - { - *--ibuff = char(int64arg & 7) + '0'; int64arg >>= 3; - } - intarg = int(int64arg); - } - else if (type == 'x' || type == 'X') - { // Hexadecimal: Dump digits until it fits in an unsigned int - while (int64arg > UINT_MAX) - { - *--ibuff = xits[int64arg & 15]; int64arg >>= 4; - } - intarg = int(int64arg); - } - else if (type == 'B') - { // Binary: Dump digits until it fits in an unsigned int - while (int64arg > UINT_MAX) - { - *--ibuff = char(int64arg & 1) + '0'; int64arg >>= 1; - } - intarg = int(int64arg); - } - else - { - if (type != 'u') - { - // If a signed number is negative, set the negative flag and make it positive. - int64_t sint64arg = (int64_t)int64arg; - if (sint64arg < 0) - { - flags |= F_NEGATIVE; - sint64arg = -sint64arg; - int64arg = sint64arg; - } - flags |= F_SIGNED; - type = 'u'; - } - // If an unsigned int64 is too big to fit in an unsigned int, dump out - // digits until it is sufficiently small. - while (int64arg > INT_MAX) - { - *--ibuff = char(int64arg % 10) + '0'; int64arg /= 10; - } - intarg = (unsigned int)(int64arg); - } - } - } - else - { - if (intarg == 0) - { - flags |= F_ZEROVALUE; - } - else if (type == 'i' || type == 'd') - { // If a signed int is negative, set the negative flag and make it positive. - signed int sintarg = (signed int)intarg; - if (sintarg < 0) - { - flags |= F_NEGATIVE; - sintarg = -sintarg; - intarg = sintarg; - } - flags |= F_SIGNED; - type = 'u'; - } - } - if (flags & F_ZEROVALUE) - { - if (precision != 0) - { - *--ibuff = '0'; - } - } - else if (type == 'u') - { // Decimal - int i; - - // Unsigned division is typically slower than signed division. - // Do it at most once. - if (intarg > INT_MAX) - { - *--ibuff = char(intarg % 10) + '0'; intarg /= 10; - } - i = (int)intarg; - while (i != 0) - { - *--ibuff = char(i % 10) + '0'; i /= 10; - } - } - else if (type == 'o') - { // Octal - while (intarg != 0) - { - *--ibuff = char(intarg & 7) + '0'; intarg >>= 3; - } - } - else if (type == 'B') - { // Binary - while (intarg != 0) - { - *--ibuff = char(intarg & 1) + '0'; intarg >>= 1; - } - } - else - { // Hexadecimal - while (intarg != 0) - { - *--ibuff = xits[intarg & 15]; intarg >>= 4; - } - } - // Check for prefix (only for non-decimal, which are always unsigned) - if ((flags & (F_HASH|F_ZEROVALUE)) == F_HASH) - { - if (type == 'o') - { - if (bufflen >= precision) - { - sign = '0'; - } - } - else if (type == 'x' || type == 'X') - { - hexprefix = type; - } - else if (type == 'B') - { - hexprefix = '!'; - } - } - bufflen = (int)(ptrdiff_t)(&buffer[sizeof(buffer)] - ibuff); - obuff = ibuff; - if (precision >= 0) - { - postprefixzeros = precision - bufflen; - if (postprefixzeros < 0) postprefixzeros = 0; -// flags &= ~F_ZERO; - } - } - else if (type == 'c') - { - intarg = va_arg (arglist, int); - if (utf8_encode(intarg, (uint8_t*)buffer, &bufflen) != 0) - { - buffer[0] = '?'; - bufflen = 1; - } - obuff = buffer; - } - else if (type == 's') - { - charparg = va_arg (arglist, const char *); - if (charparg == NULL) - { - obuff = "(null)"; - bufflen = 6; - } - else - { - obuff = charparg; - if (precision < 0) - { - bufflen = (int)strlen (charparg); - } - else - { - for (bufflen = 0; bufflen < precision && charparg[bufflen] != '\0'; ++bufflen) - { /* empty */ } - } - } - } - else if (type == '%') - { // Just print a '%': Output it with the next stage. - base--; - continue; - } - else if (type == 'n') - { - if (size == F_HALFHALF) - { - *va_arg (arglist, char *) = (char)inlen; - } - else if (size == F_HALF) - { - *va_arg (arglist, short *) = (short)inlen; - } - else if (size == F_LONG) - { - *va_arg (arglist, long *) = inlen; - } - else if (size == F_LONGLONG) - { - *va_arg (arglist, int64_t *) = inlen; - } - else if (size == F_BIGI) - { - *va_arg (arglist, ptrdiff_t *) = inlen; - } - else - { - *va_arg (arglist, int *) = inlen; - } - } - else if (type == 'f' || type == 'F') - { - expchar = '\0'; - goto fp_begin; - } - else if (type == 'g' || type == 'G') - { - expchar = type - ('g' - 'e'); - if (precision == 0) - { - precision = 1; - } - goto fp_begin; - } - else if (type == 'H') - { // %H is an extension that behaves similarly to %g, except it automatically - // selects precision based on whatever will produce the smallest string. - expchar = 'e'; - goto fp_begin; - } -#if 0 - // The hdtoa function provided with FreeBSD uses a hexadecimal FP constant. - // Microsoft's compiler does not support these, so I would need to hack it - // together with ints instead. It's very do-able, but until I actually have - // some reason to print hex FP numbers, I won't bother. - else if (type == 'a' || type == 'A') - { - if (type == 'A') - { - xits = HEXits; - hexprefix = 'X'; - expchar = 'P'; - } - else - { - hexprefix = 'x'; - expchar = 'p'; - } - if (precision >= 0) - { - precision++; - } - dblarg = va_arg(arglist, double); - dtoaresult = obuff = hdtoa(dblarg, xits, precision, &expt, &signflag, &dtoaend); - if (precision < 0) - { - precision = (int)(dtoaend - obuff); - } - if (expt == INT_MAX) - { - hexprefix = '\0'; - } - goto fp_common; - } -#endif - else if (type == 'e' || type == 'E') - { - expchar = type; - if (precision < 0) // account for digit before decpt - { - precision = DEFPREC + 1; - } - else - { - precision++; - } -fp_begin: - if (precision < 0) - { - precision = DEFPREC; - } - dblarg = va_arg(arglist, double); - obuff = dtoaresult = dtoa(dblarg, type != 'H' ? (expchar ? 2 : 3) : 0, precision, &expt, &signflag, &dtoaend); -//fp_common: - decimal_point = localeconv()->decimal_point; - flags |= F_SIGNED; - if (signflag) - { - flags |= F_NEGATIVE; - } - if (expt == 9999) // inf or nan - { - if (*obuff == 'N') - { - obuff = (type >= 'a') ? "nan" : "NAN"; - flags &= ~F_SIGNED; - } - else - { - obuff = (type >= 'a') ? "inf" : "INF"; - } - bufflen = 3; - flags &= ~F_ZERO; - } - else - { - flags |= F_FPT; - ndig = (int)(dtoaend - obuff); - if (type == 'g' || type == 'G') - { - if (expt > -4 && expt <= precision) - { // Make %[gG] smell like %[fF]. - expchar = '\0'; - if (flags & F_HASH) - { - precision -= expt; - } - else - { - precision = ndig - expt; - } - if (precision < 0) - { - precision = 0; - } - } - else - { // Make %[gG] smell like %[eE], but trim trailing zeroes if no # flag. - if (!(flags & F_HASH)) - { - precision = ndig; - } - } - } - else if (type == 'H') - { - if (expt > -(ndig + 2) && expt <= (ndig + 4)) - { // Make %H smell like %f - expchar = '\0'; - precision = ndig - expt; - if (precision < 0) - { - precision = 0; - } - } - else - {// Make %H smell like %e - precision = ndig; - } - } - if (expchar) - { - expsize = exponent(expstr, expt - 1, expchar); - bufflen = expsize + precision; - if (precision > 1 || (flags & F_HASH)) - { - ++bufflen; - } - } - else - { // space for digits before decimal point - if (expt > 0) - { - bufflen = expt; - } - else // "0" - { - bufflen = 1; - } - // space for decimal pt and following digits - if (precision != 0 || (flags & F_HASH)) - { - bufflen += precision + 1; - } - } - } - } - - // Check for sign prefix (only for signed numbers) - if (flags & F_SIGNED) - { - if (flags & F_NEGATIVE) - { - sign = '-'; - } - else if (flags & F_PLUS) - { - sign = '+'; - } - else if (flags & F_BLANK) - { - sign = ' '; - } - } - - // Construct complete prefix from sign and hex prefix character - prefixlen = 0; - if (sign != '\0') - { - prefix[0] = sign; - prefixlen = 1; - } - if (hexprefix != '\0') - { - prefix[prefixlen] = '0'; - prefix[prefixlen + 1] = hexprefix; - prefixlen += 2; - } - - // Pad the output to the field width, if needed - int fieldlen = prefixlen + postprefixzeros + bufflen; - const char *pad = (flags & F_ZERO) ? zeroes : spaces; - - // If the output is right aligned and zero-padded, then the prefix must come before the padding. - if ((flags & (F_ZERO|F_MINUS)) == F_ZERO && prefixlen > 0) - { - outlen += output (outputData, prefix, prefixlen); - prefixlen = 0; - } - if (!(flags & F_MINUS) && fieldlen < width) - { // Field is right-justified, so padding comes first - outlen += writepad (output, outputData, pad, sizeof(spaces), width - fieldlen); - width = -1; - } - - // Output field: Prefix, post-prefix zeros, buffer text - if (prefixlen > 0) - { - outlen += output (outputData, prefix, prefixlen); - } - outlen += writepad (output, outputData, zeroes, sizeof(spaces), postprefixzeros); - if (!(flags & F_FPT)) - { - if (bufflen > 0) - { - outlen += output (outputData, obuff, bufflen); - } - } - else - { - if (expchar == '\0') // %[fF] or sufficiently short %[gG] - { - if (expt <= 0) - { - outlen += output (outputData, zeroes, 1); - if (precision != 0 || (flags & F_HASH)) - { - outlen += output (outputData, decimal_point, 1); - } - outlen += writepad (output, outputData, zeroes, sizeof(zeroes), -expt); - // already handled initial 0's - precision += expt; - } - else - { - outlen += printandpad (output, outputData, obuff, dtoaend, expt, zeroes, sizeof(zeroes)); - obuff += expt; - if (precision || (flags & F_HASH)) - { - outlen += output (outputData, decimal_point, 1); - } - } - outlen += printandpad (output, outputData, obuff, dtoaend, precision, zeroes, sizeof(zeroes)); - } - else // %[eE] or sufficiently long %[gG] - { - if (precision > 1 || (flags & F_HASH)) - { - buffer[0] = *obuff++; - buffer[1] = *decimal_point; - outlen += output (outputData, buffer, 2); - outlen += output (outputData, obuff, ndig - 1); - outlen += writepad (output, outputData, zeroes, sizeof(zeroes), precision - ndig); - } - else // XeYY - { - outlen += output (outputData, obuff, 1); - } - outlen += output (outputData, expstr, expsize); - } - } - - if ((flags & F_MINUS) && fieldlen < width) - { // Field is left-justified, so padding comes last - outlen += writepad (output, outputData, pad, sizeof(spaces), width - fieldlen); - } - len += outlen; - if (dtoaresult != NULL) - { - freedtoa(dtoaresult); - dtoaresult = NULL; - } - } - } - } - - static int writepad (OutputFunc output, void *outputData, const char *pad, int padsize, int spaceToFill) - { - int outlen = 0; - while (spaceToFill > 0) - { - int count = spaceToFill > padsize ? padsize : spaceToFill; - outlen += output (outputData, pad, count); - spaceToFill -= count; - } - return outlen; - } - - static int printandpad (OutputFunc output, void *outputData, const char *p, const char *ep, int len, const char *with, int padsize) - { - int outlen = 0; - int n2 = (int)(ep - p); - if (n2 > len) - { - n2 = len; - } - if (n2 > 0) - { - outlen = output (outputData, p, n2); - } - return outlen + writepad (output, outputData, with, padsize, len - (n2 > 0 ? n2 : 0)); - } - - static int exponent (char *p0, int exp, int fmtch) - { - char *p, *t; - char expbuf[MAXEXPDIG]; - - p = p0; - *p++ = fmtch; - if (exp < 0) - { - exp = -exp; - *p++ = '-'; - } - else - { - *p++ = '+'; - } - t = expbuf + MAXEXPDIG; - if (exp > 9) - { - do - { - *--t = '0' + (exp % 10); - } - while ((exp /= 10) > 9); - *--t = '0' + exp; - for(; t < expbuf + MAXEXPDIG; *p++ = *t++) - { } - } - else - { - // Exponents for decimal floating point conversions - // (%[eEgG]) must be at least two characters long, - // whereas exponents for hexadecimal conversions can - // be only one character long. - if (fmtch == 'e' || fmtch == 'E') - { - *p++ = '0'; - } - *p++ = '0' + exp; - } - return (int)(p - p0); - } -}; - -//========================================================================// -// snprintf / vsnprintf imitations - -#ifdef __GNUC__ -#define GCCPRINTF(stri,firstargi) __attribute__((format(printf,stri,firstargi))) -#define GCCFORMAT(stri) __attribute__((format(printf,stri,0))) -#define GCCNOWARN __attribute__((unused)) -#else -#define GCCPRINTF(a,b) -#define GCCFORMAT(a) -#define GCCNOWARN -#endif - -struct snprintf_state -{ - char *buffer; - size_t maxlen; - size_t curlen; - int ideallen; -}; - -static int myvsnprintf_helper(void *data, const char *cstr, int cstr_len) -{ - snprintf_state *state = (snprintf_state *)data; - - if (INT_MAX - cstr_len < state->ideallen) - { - state->ideallen = INT_MAX; - } - else - { - state->ideallen += cstr_len; - } - if (state->curlen + cstr_len > state->maxlen) - { - cstr_len = (int)(state->maxlen - state->curlen); - } - if (cstr_len > 0) - { - memcpy(state->buffer + state->curlen, cstr, cstr_len); - state->curlen += cstr_len; - } - return cstr_len; -} - -extern "C" -{ - -// Unlike the MS CRT function snprintf, this one always writes a terminating -// null character to the buffer. It also returns the full length of the string -// that would have been output if the buffer had been large enough. In other -// words, it follows BSD/Linux rules and not MS rules. -int myvsnprintf(char *buffer, size_t count, const char *format, va_list argptr) -{ - size_t originalcount = count; - if (count != 0) - { - count--; - } - if (count > INT_MAX) - { // This is probably an error. Output nothing. - originalcount = 0; - count = 0; - } - snprintf_state state = { buffer, count, 0, 0 }; - StringFormat::VWorker(myvsnprintf_helper, &state, format, argptr); - if (originalcount > 0) - { - buffer[state.curlen] = '\0'; - } - return state.ideallen; -} - -int mysnprintf(char *buffer, size_t count, const char *format, ...) -{ - va_list argptr; - va_start(argptr, format); - int len = myvsnprintf(buffer, count, format, argptr); - va_end(argptr); - return len; -} - -} diff --git a/src/version.h b/src/version.h index 24e0fbd96a6..21d2247e606 100644 --- a/src/version.h +++ b/src/version.h @@ -41,20 +41,20 @@ const char *GetVersionString(); /** Lots of different version numbers **/ -#define VERSIONSTR "4.4pre" +#define VERSIONSTR "4.13pre" // The version as seen in the Windows resource -#define RC_FILEVERSION 4,3,9999,0 -#define RC_PRODUCTVERSION 4,3,9999,0 +#define RC_FILEVERSION 4,12,9999,0 +#define RC_PRODUCTVERSION 4,12,9999,0 #define RC_PRODUCTVERSION2 VERSIONSTR // These are for content versioning. #define VER_MAJOR 4 -#define VER_MINOR 4 +#define VER_MINOR 13 #define VER_REVISION 0 // This should always refer to the GZDoom version a derived port is based on and not reflect the derived port's version number! #define ENG_MAJOR 4 -#define ENG_MINOR 4 +#define ENG_MINOR 13 #define ENG_REVISION 0 // Version identifier for network games. @@ -65,7 +65,7 @@ const char *GetVersionString(); // Version stored in the ini's [LastRun] section. // Bump it if you made some configuration change that you want to // be able to migrate in FGameConfigFile::DoGlobalSetup(). -#define LASTRUNVERSION "219" +#define LASTRUNVERSION "225" // Protocol version used in demos. // Bump it if you change existing DEM_ commands or add new ones. @@ -74,7 +74,7 @@ const char *GetVersionString(); // Minimum demo version we can play. // Bump it whenever you change or remove existing DEM_ commands. -#define MINDEMOVERSION 0x21F +#define MINDEMOVERSION 0x221 // SAVEVER is the version of the information stored in level snapshots. // Note that SAVEVER is not directly comparable to VERSION. @@ -88,19 +88,24 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4558 +#define SAVEVER 4560 // This is so that derivates can use the same savegame versions without worrying about engine compatibility #define GAMESIG "GZDOOM" #define BASEWAD "gzdoom.pk3" #define OPTIONALWAD "game_support.pk3" +#define GZDOOM 1 +#define VR3D_ENABLED // More stuff that needs to be different for derivatives. #define GAMENAME "GZDoom" #define WGAMENAME L"GZDoom" #define GAMENAMELOWERCASE "gzdoom" +#define QUERYIWADDEFAULT true #define FORUM_URL "http://forum.zdoom.org/" #define BUGS_FORUM_URL "http://forum.zdoom.org/viewforum.php?f=2" +// For QUERYIWADDEFAULT: Set to 'true' to always show dialog box on startup by default, 'false' to disable. +// Should set to 'false' for standalone games, and set to 'true' for regular source port forks that are meant to run any game. #if defined(__APPLE__) || defined(_WIN32) #define GAME_DIR GAMENAME @@ -108,5 +113,12 @@ const char *GetVersionString(); #define GAME_DIR ".config/" GAMENAMELOWERCASE #endif +#define DEFAULT_DISCORD_APP_ID "951303644597325885" + +const int SAVEPICWIDTH = 216; +const int SAVEPICHEIGHT = 162; +const int VID_MIN_WIDTH = 320; +const int VID_MIN_HEIGHT = 200; + #endif //__VERSION_H__ diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 4a5cf486676..dddc37c3101 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -38,7 +38,7 @@ #include "m_random.h" #include "m_swap.h" -#include "w_wad.h" +#include "filesystem.h" #include "g_level.h" #include "s_sound.h" #include "doomstat.h" @@ -54,11 +54,15 @@ #include "cmdlib.h" #include "g_levellocals.h" #include "vm.h" +#include "texturemanager.h" +#include "v_draw.h" CVAR(Bool, wi_percents, true, CVAR_ARCHIVE) CVAR(Bool, wi_showtotaltime, true, CVAR_ARCHIVE) CVAR(Bool, wi_noautostartmap, false, CVAR_USERINFO | CVAR_ARCHIVE) CVAR(Int, wi_autoadvance, 0, CVAR_SERVERINFO) +CVAR(Bool, wi_cleantextscale, false, CVAR_ARCHIVE) +EXTERN_CVAR(Bool, inter_classic_scaling) // States for the intermission enum EState @@ -88,6 +92,8 @@ static const char *WI_Cmd[] = { "Pic", "NoAutostartMap", + "Screensize", + "TileBackground", NULL }; @@ -137,7 +143,7 @@ class DInterBackground : public DObject int period; // period in tics between animations yahpt_t loc; // location of animation int data; // ALWAYS: n/a, RANDOM: period deviation (<256) - TArray frames; // actual graphics for frames of animations + TArray frames; // actual graphics for frames of animations // following must be initialized to zero before use! int nexttic; // next value of bcnt (used in conjunction with period) @@ -160,12 +166,16 @@ class DInterBackground : public DObject TArray lnodes; TArray anims; int bcnt = 0; // used for timing of background animation - TArray yah; // You Are Here graphic - FTexture* splat = nullptr; // splat - FTexture *background = nullptr; + TArray yah; // You Are Here graphic + FTextureID splat{}; // splat + FTextureID background{}; wbstartstruct_t *wbs; level_info_t *exitlevel; - + int bgwidth = -1; + int bgheight = -1; + bool tilebackground = false; + + public: DInterBackground(wbstartstruct_t *wbst); @@ -207,27 +217,27 @@ class DInterBackground : public DObject // //==================================================================== - void drawOnLnode(int n, FTexture * c[], int numc) + void drawOnLnode(int n, FTextureID c[], int numc, double backwidth, double backheight) { int i; for (i = 0; iGetDisplayWidth(); - bottom = c[i]->GetDisplayHeight(); - left = lnodes[n].x - c[i]->GetDisplayLeftOffset(); - top = lnodes[n].y - c[i]->GetDisplayTopOffset(); + double left; + double top; + double right; + double bottom; + + auto tex = TexMan.GetGameTexture(c[i]); + right = tex->GetDisplayWidth(); + bottom = tex->GetDisplayHeight(); + left = lnodes[n].x - tex->GetDisplayLeftOffset(); + top = lnodes[n].y - tex->GetDisplayTopOffset(); right += left; bottom += top; if (left >= 0 && right < 320 && top >= 0 && bottom < 200) { - screen->DrawTexture(c[i], lnodes[n].x, lnodes[n].y, DTA_320x200, true, TAG_DONE); + DrawTexture(twod, tex, lnodes[n].x, lnodes[n].y, DTA_FullscreenScale, FSMode_ScaleToFit43, DTA_VirtualWidthF, backwidth, DTA_VirtualHeightF, backheight, TAG_DONE); break; } } @@ -258,8 +268,8 @@ DEFINE_ACTION_FUNCTION(DInterBackground, Create) bool DInterBackground::LoadBackground(bool isenterpic) { - const char *lumpname = nullptr; - const char *exitpic = nullptr; + const char* lumpname = nullptr; + const char* exitpic = nullptr; char buffer[10]; in_anim_t an; lnode_t pt; @@ -268,16 +278,25 @@ bool DInterBackground::LoadBackground(bool isenterpic) bcnt = 0; + if (!isenterpic) tilebackground = false; texture.SetInvalid(); - level_info_t * li = FindLevelInfo(wbs->current); - if (li != nullptr) exitpic = li->ExitPic; + level_info_t* li = FindLevelInfo(wbs->current.GetChars()); + if (li != nullptr) + { + exitpic = li->ExitPic.GetChars(); + if (li->ExitPic.IsNotEmpty()) tilebackground = false; + } lumpname = exitpic; if (isenterpic) { - level_info_t * li = FindLevelInfo(wbs->next); - if (li != NULL) lumpname = li->EnterPic; + level_info_t* li = FindLevelInfo(wbs->next.GetChars()); + if (li != NULL) + { + lumpname = li->EnterPic.GetChars(); + if (li->EnterPic.IsNotEmpty()) tilebackground = false; + } } // Try to get a default if nothing specified @@ -290,11 +309,12 @@ bool DInterBackground::LoadBackground(bool isenterpic) case GAME_Doom: if (!(gameinfo.flags & GI_MAPxx)) { - const char *levelname = isenterpic ? wbs->next : wbs->current; + const char* levelname = isenterpic ? wbs->next.GetChars() : wbs->current.GetChars(); if (IsExMy(levelname)) { mysnprintf(buffer, countof(buffer), "$IN_EPI%c", levelname[1]); lumpname = buffer; + tilebackground = false; } } if (!lumpname) @@ -311,29 +331,32 @@ bool DInterBackground::LoadBackground(bool isenterpic) if (!(gameinfo.flags & GI_MAPxx)) { // not if the last level is not from the first 3 episodes - if (!IsExMy(wbs->current)) return false; + if (!IsExMy(wbs->current.GetChars())) return false; // not if the next level is one of the first 3 episodes - if (IsExMy(wbs->next)) return false; + if (IsExMy(wbs->next.GetChars())) return false; } } lumpname = "INTERPIC"; + tilebackground = false; } break; case GAME_Heretic: if (isenterpic) { - if (IsExMy(wbs->next)) + if (IsExMy(wbs->next.GetChars())) { mysnprintf(buffer, countof(buffer), "$IN_HTC%c", wbs->next[1]); lumpname = buffer; + tilebackground = false; } } if (!lumpname) { if (isenterpic) return false; lumpname = "FLOOR16"; + tilebackground = true; } break; @@ -346,21 +369,22 @@ bool DInterBackground::LoadBackground(bool isenterpic) default: // Strife doesn't have an intermission pic so choose something neutral. if (isenterpic) return false; - lumpname = gameinfo.BorderFlat; + lumpname = gameinfo.BorderFlat.GetChars(); + tilebackground = true; break; } } if (lumpname == NULL) { // shouldn't happen! - background = NULL; + background.SetInvalid(); return false; } lnodes.Clear(); anims.Clear(); yah.Clear(); - splat = NULL; + splat.SetInvalid(); // a name with a starting '$' indicates an intermission script if (*lumpname != '$') @@ -369,7 +393,7 @@ bool DInterBackground::LoadBackground(bool isenterpic) } else { - int lumpnum = Wads.CheckNumForFullName(lumpname + 1, true); + int lumpnum = fileSystem.CheckNumForFullName(lumpname + 1, true); if (lumpnum >= 0) { FScanner sc(lumpnum); @@ -386,13 +410,13 @@ bool DInterBackground::LoadBackground(bool isenterpic) case 1: // Splat sc.MustGetString(); - splat = TexMan.GetTextureByName(sc.String); + splat = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); break; case 2: // Pointers while (sc.GetString() && !sc.Crossed) { - yah.Push(TexMan.GetTextureByName(sc.String)); + yah.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny)); } if (sc.Crossed) sc.UnGet(); @@ -452,11 +476,23 @@ bool DInterBackground::LoadBackground(bool isenterpic) noautostartmap = true; break; + case 15: // screensize + sc.MustGetNumber(); + bgwidth = sc.Number; + sc.MustGetNumber(); + bgheight = sc.Number; + break; + + case 16: // tilebackground + tilebackground = true; + break; + readanimation: sc.MustGetString(); an.LevelName = sc.String; sc.MustGetString(); caseval = sc.MustMatchString(WI_Cmd); + [[fallthrough]]; default: switch (caseval) @@ -484,14 +520,14 @@ bool DInterBackground::LoadBackground(bool isenterpic) if (!sc.CheckString("{")) { sc.MustGetString(); - an.frames.Push(TexMan.GetTextureByName(sc.String)); + an.frames.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny)); } else { while (!sc.CheckString("}")) { sc.MustGetString(); - an.frames.Push(TexMan.GetTextureByName(sc.String)); + an.frames.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny)); } } an.ctr = -1; @@ -506,7 +542,7 @@ bool DInterBackground::LoadBackground(bool isenterpic) an.loc.y = sc.Number; sc.MustGetString(); an.frames.Reserve(1); // allocate exactly one element - an.frames[0] = TexMan.GetTextureByName(sc.String); + an.frames[0] = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); anims.Push(an); break; @@ -522,7 +558,11 @@ bool DInterBackground::LoadBackground(bool isenterpic) texture = TexMan.GetTextureID("INTERPIC", ETextureType::MiscPatch); } } - background = TexMan.GetTexture(texture); + background = texture; + auto tex = TexMan.GetGameTexture(texture); + // extremely small textures will always be tiled. + if (tex && tex->GetDisplayWidth() < 128 && tex->GetDisplayHeight() < 128) + tilebackground = true; return noautostartmap; } @@ -586,29 +626,34 @@ DEFINE_ACTION_FUNCTION(DInterBackground, updateAnimatedBack) void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointeron) { unsigned int i; - double animwidth = 320; // For a flat fill or clear background scale animations to 320x200 - double animheight = 200; + double animwidth = bgwidth; // For a flat fill or clear background scale animations to 320x200 + double animheight = bgheight; - if (background) + if (background.isValid()) { + auto bgtex = TexMan.GetGameTexture(background); // background - if (background->isMiscPatch()) + if (!tilebackground) { - // scale all animations below to fit the size of the base pic + // if no explicit size was set scale all animations below to fit the size of the base pic // The base pic is always scaled to fit the screen so this allows // placing the animations precisely where they belong on the base pic - animwidth = background->GetDisplayWidthDouble(); - animheight = background->GetDisplayHeightDouble(); - screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE); + if (bgwidth < 0 || bgheight < 0) + { + animwidth = bgtex->GetDisplayWidth(); + animheight = bgtex->GetDisplayHeight(); + if (animheight == 200) animwidth = 320; // deal with widescreen replacements that keep the original coordinates. + } + DrawTexture(twod, bgtex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); } else { - screen->FlatFill(0, 0, SCREENWIDTH, SCREENHEIGHT, background); + twod->AddFlatFill(0, 0, twod->GetWidth(), twod->GetHeight(), bgtex, (inter_classic_scaling ? -1 : 0)); } } else { - screen->Clear(0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0); + ClearRect(twod, 0, 0, twod->GetWidth(), twod->GetHeight(), 0, 0); } for (i = 0; itype & ANIM_CONDITION) { case ANIM_IFVISITED: - li = FindLevelInfo(a->LevelName); + li = FindLevelInfo(a->LevelName.GetChars()); if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; break; case ANIM_IFNOTVISITED: - li = FindLevelInfo(a->LevelName); + li = FindLevelInfo(a->LevelName.GetChars()); if (li == NULL || (li->flags & LEVEL_VISITED)) continue; break; // StatCount means 'leaving' - everything else means 'entering'! case ANIM_IFENTERING: - if (state == StatCount || strnicmp(a->LevelName, wbs->next, 8)) continue; + if (state == StatCount || a->LevelName.CompareNoCase(wbs->next, 8)) continue; break; case ANIM_IFNOTENTERING: - if (state != StatCount && !strnicmp(a->LevelName, wbs->next, 8)) continue; + if (state != StatCount && !a->LevelName.CompareNoCase(wbs->next, 8)) continue; break; case ANIM_IFLEAVING: - if (state != StatCount || strnicmp(a->LevelName, wbs->current, 8)) continue; + if (state != StatCount || a->LevelName.CompareNoCase(wbs->current, 8)) continue; break; case ANIM_IFNOTLEAVING: - if (state == StatCount && !strnicmp(a->LevelName, wbs->current, 8)) continue; + if (state == StatCount && !a->LevelName.CompareNoCase(wbs->current, 8)) continue; break; case ANIM_IFTRAVELLING: - if (strnicmp(a->LevelName2, wbs->current, 8) || strnicmp(a->LevelName, wbs->next, 8)) continue; + if (a->LevelName2.CompareNoCase(wbs->current, 8) || a->LevelName.CompareNoCase(wbs->next, 8)) continue; break; case ANIM_IFNOTTRAVELLING: - if (!strnicmp(a->LevelName2, wbs->current, 8) && !strnicmp(a->LevelName, wbs->next, 8)) continue; + if (!a->LevelName2.CompareNoCase(wbs->current, 8) && !a->LevelName.CompareNoCase(wbs->next, 8)) continue; break; } if (a->ctr >= 0) - screen->DrawTexture(a->frames[a->ctr], a->loc.x, a->loc.y, - DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); + DrawTexture(twod, a->frames[a->ctr], false, a->loc.x, a->loc.y, + DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, DTA_FullscreenScale, FSMode_ScaleToFit43, TAG_DONE); } if (drawsplat) { for (i = 0; iflags & LEVEL_VISITED) drawOnLnode(i, &splat, 1); // draw a splat on taken cities. + level_info_t * li = FindLevelInfo(lnodes[i].Level.GetChars()); + if (li && li->flags & LEVEL_VISITED) drawOnLnode(i, &splat, 1, animwidth, animheight); // draw a splat on taken cities. } } // draw flashing ptr if (snl_pointeron && yah.Size()) { - unsigned int v = MapToIndex(wbs->next); + unsigned int v = MapToIndex(wbs->next.GetChars()); // Draw only if it points to a valid level on the current screen! - if (vFillBorder(nullptr); - VMValue self = WI_Screen; - VMCall(func, &self, 1, nullptr, 0); - screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. - - // The internal handling here is somewhat poor. After being set to 'LeavingIntermission' - // the screen is needed for one more draw operation so we cannot delete it right away but only here. - if (WI_Screen->IntVar("CurState") == LeavingIntermission) - { - WI_Screen->Destroy(); - GC::DelSoftRoot(WI_Screen); - WI_Screen = nullptr; - } - } - } -} - //==================================================================== // // Setup for an intermission screen. // //==================================================================== -void WI_Start(wbstartstruct_t *wbstartstruct) +DObject* WI_Start(wbstartstruct_t *wbstartstruct) { FName screenclass = deathmatch ? gameinfo.statusscreen_dm : multiplayer ? gameinfo.statusscreen_coop : gameinfo.statusscreen_single; auto cls = PClass::FindClass(screenclass); @@ -763,14 +756,37 @@ void WI_Start(wbstartstruct_t *wbstartstruct) } } - WI_Screen = cls->CreateNew(); - ScaleOverrider s; + auto WI_Screen = cls->CreateNew(); + + + ScaleOverrider s(twod); IFVIRTUALPTRNAME(WI_Screen, "StatusScreen", Start) { VMValue val[2] = { WI_Screen, wbstartstruct }; VMCall(func, val, 2, nullptr, 0); } - GC::AddSoftRoot(WI_Screen); + + if (!wi_cleantextscale) + { + // Only modify the original single player screens. Everything else must set itself up as intended + if (cls->TypeName == NAME_DoomStatusScreen || cls->TypeName == NAME_RavenStatusScreen) + { + int w = screen->GetWidth(); + int h = screen->GetHeight(); + float ratio = ActiveRatio(w, h); + int pixw = int(320 * (ratio * 0.75)); + if (pixw > 336) pixw -= 16; // leave a bit of space at the sides. + + WI_Screen->IntVar(NAME_cwidth) = 320; + WI_Screen->IntVar(NAME_cheight) = 200; + WI_Screen->IntVar(NAME_scalemode) = FSMode_ScaleToFit43; + WI_Screen->IntVar(NAME_scalefactorx) = 1; + WI_Screen->IntVar(NAME_scalefactory) = 1; + WI_Screen->IntVar(NAME_wrapwidth) = pixw; + } + } + + return WI_Screen; } //==================================================================== @@ -787,7 +803,7 @@ DEFINE_ACTION_FUNCTION(DStatusScreen, GetPlayerWidths) if (numret > 0) ret[0].SetInt(maxnamewidth); if (numret > 1) ret[1].SetInt(maxscorewidth); if (numret > 2) ret[2].SetInt(maxiconheight); - return MIN(numret, 3); + return min(numret, 3); } //==================================================================== @@ -859,6 +875,7 @@ DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, nextauthor); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, thisauthor); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, LName0); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, LName1); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, totalkills); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxkills); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxitems); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxsecret); diff --git a/src/wi_stuff.h b/src/wi_stuff.h index d9f089c8578..869348698a8 100644 --- a/src/wi_stuff.h +++ b/src/wi_stuff.h @@ -29,7 +29,6 @@ #include "doomdef.h" -class FTexture; struct FLevelLocals; // @@ -62,6 +61,7 @@ struct wbstartstruct_t FTextureID LName0; FTextureID LName1; + int totalkills; int maxkills; int maxitems; int maxsecret; @@ -81,17 +81,7 @@ struct wbstartstruct_t }; -// Intermission stats. -// Parameters for world map / intermission. - -// Called by main loop, animate the intermission. -void WI_Ticker (); - -// Called by main loop, -// draws the intermission directly into the screen buffer. -void WI_Drawer (); - // Setup for an intermission screen. -void WI_Start (wbstartstruct_t *wbstartstruct); +DObject* WI_Start (wbstartstruct_t *wbstartstruct); #endif diff --git a/src/win32/hardware.cpp b/src/win32/hardware.cpp deleted file mode 100644 index af6ab118878..00000000000 --- a/src/win32/hardware.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* -** hardware.cpp -** Somewhat OS-independant interface to the screen, mouse, keyboard, and stick -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#define WIN32_LEAN_AND_MEAN -#include -#include - -#include "hardware.h" -#include "c_dispatch.h" -#include "v_text.h" -#include "doomstat.h" -#include "m_argv.h" -#include "version.h" -#include "win32glvideo.h" -#include "win32polyvideo.h" -#ifdef HAVE_VULKAN -#include "win32vulkanvideo.h" -#endif -#include "doomerrors.h" -#include "i_system.h" -#include "swrenderer/r_swrenderer.h" - -EXTERN_CVAR(Int, vid_preferbackend) - -extern HWND Window; - -IVideo *Video; - -// do not include GL headers here, only declare the necessary functions. -IVideo *gl_CreateVideo(); - -void I_RestartRenderer(); -int currentcanvas = -1; -int currentgpuswitch = -1; -bool changerenderer; - -// Optimus/Hybrid switcher -CUSTOM_CVAR(Int, vid_gpuswitch, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) -{ - if (self != currentgpuswitch) - { - switch (self) - { - case 0: - Printf("Selecting default GPU...\n"); - break; - case 1: - Printf("Selecting high-performance dedicated GPU...\n"); - break; - case 2: - Printf("Selecting power-saving integrated GPU...\n"); - break; - default: - Printf("Unknown option (%d) - falling back to 'default'\n", *vid_gpuswitch); - self = 0; - break; - } - Printf("You must restart " GAMENAME " for this change to take effect.\n"); - } -} - - - -void I_ShutdownGraphics () -{ - if (screen) - { - DFrameBuffer *s = screen; - screen = NULL; - delete s; - } - if (Video) - delete Video, Video = NULL; -} - -void I_InitGraphics () -{ - // todo: implement ATI version of this. this only works for nvidia notebooks, for now. - currentgpuswitch = vid_gpuswitch; - if (currentgpuswitch == 1) - putenv("SHIM_MCCOMPAT=0x800000001"); // discrete - else if (currentgpuswitch == 2) - putenv("SHIM_MCCOMPAT=0x800000000"); // integrated - - // If the focus window is destroyed, it doesn't go back to the active window. - // (e.g. because the net pane was up, and a button on it had focus) - if (GetFocus() == NULL && GetActiveWindow() == Window) - { - // Make sure it's in the foreground and focused. (It probably is - // already foregrounded but may not be focused.) - SetForegroundWindow(Window); - SetFocus(Window); - // Note that when I start a 2-player game on the same machine, the - // window for the game that isn't focused, active, or foregrounded - // still receives a WM_ACTIVATEAPP message telling it that it's the - // active window. The window that is really the active window does - // not receive a WM_ACTIVATEAPP message, so both games think they - // are the active app. Huh? - } - - if (vid_preferbackend == 2) - { - Video = new Win32PolyVideo(); - } -#ifdef HAVE_VULKAN - else if (vid_preferbackend == 1) - { - // first try Vulkan, if that fails OpenGL - try - { - Video = new Win32VulkanVideo(); - } - catch (CVulkanError &error) - { - Printf(TEXTCOLOR_RED "Initialization of Vulkan failed: %s\n", error.what()); - Video = new Win32GLVideo(); - } - } -#endif - else - { - Video = new Win32GLVideo(); - } - - if (Video == NULL) - Video = new Win32PolyVideo(); - - // we somehow STILL don't have a display!! - if (Video == NULL) - I_FatalError ("Failed to initialize display"); - -} diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp deleted file mode 100644 index 61d6c188019..00000000000 --- a/src/win32/i_input.cpp +++ /dev/null @@ -1,933 +0,0 @@ -/* -** i_input.cpp -** Handles input from keyboard, mouse, and joystick -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// DI3 only supports up to 4 mouse buttons, and I want the joystick to -// be read using DirectInput instead of winmm. - -#define WIN32_LEAN_AND_MEAN -#define __BYTEBOOL__ -#ifndef __GNUC__ -#define INITGUID -#endif -#define DIRECTINPUT_VERSION 0x800 -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning(disable:4244) -#endif - -// Compensate for w32api's lack -#ifndef WM_WTSSESSION_CHANGE -#define WM_WTSSESSION_CHANGE 0x02B1 -#define WTS_CONSOLE_CONNECT 1 -#define WTS_CONSOLE_DISCONNECT 2 -#define WTS_SESSION_LOCK 7 -#define WTS_SESSION_UNLOCK 8 -#endif -#ifndef PBT_APMSUSPEND -// w32api does not #define the PBT_ macros in winuser.h like the PSDK does -#include -#endif -#ifndef GET_RAWINPUT_CODE_WPARAM -#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff) -#endif - - -#include "c_dispatch.h" -#include "doomdef.h" -#include "doomstat.h" -#include "m_argv.h" -#include "i_input.h" -#include "v_video.h" -#include "i_sound.h" -#include "g_game.h" -#include "d_main.h" -#include "d_gui.h" -#include "c_console.h" -#include "s_sound.h" -#include "gameconfigfile.h" -#include "hardware.h" -#include "d_event.h" -#include "v_text.h" -#include "version.h" -#include "events.h" -#include "doomerrors.h" -#include "i_system.h" -#include "g_levellocals.h" - - -// Compensate for w32api's lack -#ifndef GET_XBUTTON_WPARAM -#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) -#endif - - -#ifdef _DEBUG -#define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS -#else -//#define INGAME_PRIORITY_CLASS HIGH_PRIORITY_CLASS -#define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS -#endif - -FJoystickCollection *JoyDevices[NUM_JOYDEVICES]; - - -extern HINSTANCE g_hInst; -extern DWORD SessionID; - -static HMODULE DInputDLL; - -bool GUICapture; -extern FMouse *Mouse; -extern FKeyboard *Keyboard; - -bool VidResizing; - -extern BOOL vidactive; -extern HWND Window, ConWindow; - -EXTERN_CVAR (String, language) -EXTERN_CVAR (Bool, lookstrafe) -EXTERN_CVAR (Bool, use_joystick) -EXTERN_CVAR (Bool, use_mouse) - -static int WheelDelta; -extern bool CursorState; - -extern BOOL paused; -static bool noidle = false; - -LPDIRECTINPUT8 g_pdi; -LPDIRECTINPUT g_pdi3; - - -extern bool AppActive; -int SessionState = 0; -int BlockMouseMove; - -static bool EventHandlerResultForNativeMouse; - - -CVAR (Bool, i_soundinbackground, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -extern int chatmodeon; - -static void I_CheckGUICapture () -{ - bool wantCapt; - - if (menuactive == MENU_Off) - { - wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon; - } - else - { - wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause); - } - - // [ZZ] check active event handlers that want the UI processing - if (!wantCapt && primaryLevel->localEventManager->CheckUiProcessors()) - wantCapt = true; - - if (wantCapt != GUICapture) - { - GUICapture = wantCapt; - if (wantCapt && Keyboard != NULL) - { - Keyboard->AllKeysUp(); - } - } -} - -void I_SetMouseCapture() -{ - SetCapture(Window); -} - -void I_ReleaseMouseCapture() -{ - ReleaseCapture(); -} - -bool GUIWndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) -{ - event_t ev = { EV_GUI_Event }; - - *result = 0; - - switch (message) - { - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - case WM_KEYUP: - case WM_SYSKEYUP: - if (message == WM_KEYUP || message == WM_SYSKEYUP) - { - ev.subtype = EV_GUI_KeyUp; - } - else - { - ev.subtype = (lParam & 0x40000000) ? EV_GUI_KeyRepeat : EV_GUI_KeyDown; - } - if (GetKeyState(VK_SHIFT) & 0x8000) ev.data3 |= GKM_SHIFT; - if (GetKeyState(VK_CONTROL) & 0x8000) ev.data3 |= GKM_CTRL; - if (GetKeyState(VK_MENU) & 0x8000) ev.data3 |= GKM_ALT; - if (wParam == VK_PROCESSKEY) - { // Use the scan code to determine the real virtual-key code. - // ImmGetVirtualKey() will supposedly do this, but it just returns - // VK_PROCESSKEY again. - wParam = MapVirtualKey((lParam >> 16) & 255, 1); - } - if ( (ev.data1 = MapVirtualKey(wParam, 2)) ) - { - D_PostEvent(&ev); - } - else - { - switch (wParam) - { - case VK_PRIOR: ev.data1 = GK_PGUP; break; - case VK_NEXT: ev.data1 = GK_PGDN; break; - case VK_END: ev.data1 = GK_END; break; - case VK_HOME: ev.data1 = GK_HOME; break; - case VK_LEFT: ev.data1 = GK_LEFT; break; - case VK_RIGHT: ev.data1 = GK_RIGHT; break; - case VK_UP: ev.data1 = GK_UP; break; - case VK_DOWN: ev.data1 = GK_DOWN; break; - case VK_DELETE: ev.data1 = GK_DEL; break; - case VK_ESCAPE: ev.data1 = GK_ESCAPE; break; - case VK_F1: ev.data1 = GK_F1; break; - case VK_F2: ev.data1 = GK_F2; break; - case VK_F3: ev.data1 = GK_F3; break; - case VK_F4: ev.data1 = GK_F4; break; - case VK_F5: ev.data1 = GK_F5; break; - case VK_F6: ev.data1 = GK_F6; break; - case VK_F7: ev.data1 = GK_F7; break; - case VK_F8: ev.data1 = GK_F8; break; - case VK_F9: ev.data1 = GK_F9; break; - case VK_F10: ev.data1 = GK_F10; break; - case VK_F11: ev.data1 = GK_F11; break; - case VK_F12: ev.data1 = GK_F12; break; - case VK_BROWSER_BACK: ev.data1 = GK_BACK; break; - } - if (ev.data1 != 0) - { - D_PostEvent(&ev); - } - } - // Return false for key downs so that we can handle special hotkeys - // in the main WndProc. - return ev.subtype == EV_GUI_KeyUp; - - case WM_CHAR: - case WM_SYSCHAR: - if (wParam >= ' ') // only send displayable characters - { - ev.subtype = EV_GUI_Char; - ev.data1 = wParam; - ev.data2 = (message == WM_SYSCHAR); - D_PostEvent(&ev); - return true; - } - break; - - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_XBUTTONDOWN: - case WM_XBUTTONUP: - case WM_MOUSEMOVE: - if (message >= WM_LBUTTONDOWN && message <= WM_LBUTTONDBLCLK) - { - ev.subtype = message - WM_LBUTTONDOWN + EV_GUI_LButtonDown; - } - else if (message >= WM_RBUTTONDOWN && message <= WM_RBUTTONDBLCLK) - { - ev.subtype = message - WM_RBUTTONDOWN + EV_GUI_RButtonDown; - } - else if (message >= WM_MBUTTONDOWN && message <= WM_MBUTTONDBLCLK) - { - ev.subtype = message - WM_MBUTTONDOWN + EV_GUI_MButtonDown; - } - else if (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONUP) - { - ev.subtype = message - WM_XBUTTONDOWN + EV_GUI_BackButtonDown; - if (GET_XBUTTON_WPARAM(wParam) == 2) - { - ev.subtype += EV_GUI_FwdButtonDown - EV_GUI_BackButtonDown; - } - else if (GET_XBUTTON_WPARAM(wParam) != 1) - { - break; - } - } - else if (message == WM_MOUSEMOVE) - { - ev.subtype = EV_GUI_MouseMove; - if (BlockMouseMove > 0) return true; - } - - ev.data1 = LOWORD(lParam); - ev.data2 = HIWORD(lParam); - if (screen != NULL) - { - screen->ScaleCoordsFromWindow(ev.data1, ev.data2); - } - - if (wParam & MK_SHIFT) ev.data3 |= GKM_SHIFT; - if (wParam & MK_CONTROL) ev.data3 |= GKM_CTRL; - if (GetKeyState(VK_MENU) & 0x8000) ev.data3 |= GKM_ALT; - - if (use_mouse) D_PostEvent(&ev); - return true; - - // Note: If the mouse is grabbed, it sends the mouse wheel events itself. - case WM_MOUSEWHEEL: - if (!use_mouse) return false; - if (wParam & MK_SHIFT) ev.data3 |= GKM_SHIFT; - if (wParam & MK_CONTROL) ev.data3 |= GKM_CTRL; - if (GetKeyState(VK_MENU) & 0x8000) ev.data3 |= GKM_ALT; - WheelDelta += (SHORT)HIWORD(wParam); - if (WheelDelta < 0) - { - ev.subtype = EV_GUI_WheelDown; - while (WheelDelta <= -WHEEL_DELTA) - { - D_PostEvent(&ev); - WheelDelta += WHEEL_DELTA; - } - } - else - { - ev.subtype = EV_GUI_WheelUp; - while (WheelDelta >= WHEEL_DELTA) - { - D_PostEvent(&ev); - WheelDelta -= WHEEL_DELTA; - } - } - return true; - } - return false; -} - -bool CallHook(FInputDevice *device, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) -{ - if (device == NULL) - { - return false; - } - *result = 0; - return device->WndProcHook(hWnd, message, wParam, lParam, result); -} - -LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT result; - - if (message == WM_INPUT) - { - UINT size; - - if (!GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)) && - size != 0) - { - uint8_t *buffer = (uint8_t *)alloca(size); - if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER)) == size) - { - int code = GET_RAWINPUT_CODE_WPARAM(wParam); - if (Keyboard == NULL || !Keyboard->ProcessRawInput((RAWINPUT *)buffer, code)) - { - if (Mouse == NULL || !Mouse->ProcessRawInput((RAWINPUT *)buffer, code)) - { - if (JoyDevices[INPUT_RawPS2] != NULL) - { - JoyDevices[INPUT_RawPS2]->ProcessRawInput((RAWINPUT *)buffer, code); - } - } - } - } - } - return DefWindowProc(hWnd, message, wParam, lParam); - } - - if (CallHook(Keyboard, hWnd, message, wParam, lParam, &result)) - { - return result; - } - if (CallHook(Mouse, hWnd, message, wParam, lParam, &result)) - { - return result; - } - for (int i = 0; i < NUM_JOYDEVICES; ++i) - { - if (CallHook(JoyDevices[i], hWnd, message, wParam, lParam, &result)) - { - return result; - } - } - if (GUICapture && GUIWndProcHook(hWnd, message, wParam, lParam, &result)) - { - return result; - } - - if ((gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL) && message == WM_LBUTTONDOWN) - { - if (GUIWndProcHook(hWnd, message, wParam, lParam, &result)) - { - return result; - } - } - - - switch (message) - { - case WM_DESTROY: - SetPriorityClass (GetCurrentProcess(), NORMAL_PRIORITY_CLASS); - PostQuitMessage (0); - break; - - case WM_HOTKEY: - break; - - case WM_PAINT: - return DefWindowProc (hWnd, message, wParam, lParam); - - case WM_SETTINGCHANGE: - // If regional settings were changed, reget preferred languages - if (wParam == 0 && lParam != 0 && strcmp ((const char *)lParam, "intl") == 0) - { - language.Callback (); - } - return 0; - - case WM_KILLFOCUS: - I_CheckNativeMouse (true, false); // Make sure mouse gets released right away - break; - - case WM_SETFOCUS: - I_CheckNativeMouse (false, EventHandlerResultForNativeMouse); // This cannot call the event handler. Doing it from here is unsafe. - break; - - case WM_SETCURSOR: - if (!CursorState) - { - SetCursor(NULL); // turn off window cursor - return TRUE; // Prevent Windows from setting cursor to window class cursor - } - else - { - return DefWindowProc(hWnd, message, wParam, lParam); - } - break; - - case WM_SIZE: - InvalidateRect (Window, NULL, FALSE); - break; - - case WM_KEYDOWN: - break; - - case WM_SYSKEYDOWN: - // Pressing Alt+Enter can toggle between fullscreen and windowed. - if (wParam == VK_RETURN && k_allowfullscreentoggle && !(lParam & 0x40000000)) - { - ToggleFullscreen = !ToggleFullscreen; - } - // Pressing Alt+F4 quits the program. - if (wParam == VK_F4 && !(lParam & 0x40000000)) - { - PostQuitMessage(0); - } - break; - - case WM_SYSCOMMAND: - // Prevent activation of the window menu with Alt+Space - if ((wParam & 0xFFF0) != SC_KEYMENU) - { - return DefWindowProc (hWnd, message, wParam, lParam); - } - break; - - case WM_DISPLAYCHANGE: - case WM_STYLECHANGED: - return DefWindowProc(hWnd, message, wParam, lParam); - - case WM_GETMINMAXINFO: - if (screen && !VidResizing) - { - LPMINMAXINFO mmi = (LPMINMAXINFO)lParam; - if (screen->IsFullscreen()) - { - RECT rect = { 0, 0, screen->GetWidth(), screen->GetHeight() }; - AdjustWindowRectEx(&rect, WS_VISIBLE | WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW); - mmi->ptMinTrackSize.x = rect.right - rect.left; - mmi->ptMinTrackSize.y = rect.bottom - rect.top; - } - else - { - RECT rect = { 0, 0, VID_MIN_WIDTH, VID_MIN_HEIGHT }; - AdjustWindowRectEx(&rect, GetWindowLongW(hWnd, GWL_STYLE), FALSE, GetWindowLongW(hWnd, GWL_EXSTYLE)); - mmi->ptMinTrackSize.x = rect.right - rect.left; - mmi->ptMinTrackSize.y = rect.bottom - rect.top; - } - return 0; - } - break; - - case WM_ACTIVATEAPP: - AppActive = wParam == TRUE; - if (wParam) - { - SetPriorityClass (GetCurrentProcess (), INGAME_PRIORITY_CLASS); - } - else if (!noidle && !netgame) - { - SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS); - } - S_SetSoundPaused ((!!i_soundinbackground) || wParam); - break; - - case WM_WTSSESSION_CHANGE: - case WM_POWERBROADCAST: - { - int oldstate = SessionState; - - if (message == WM_WTSSESSION_CHANGE && lParam == (LPARAM)SessionID) - { -#ifdef _DEBUG - OutputDebugStringA ("SessionID matched\n"); -#endif - // When using fast user switching, XP will lock a session before - // disconnecting it, and the session will be unlocked before reconnecting it. - // For our purposes, video output will only happen when the session is - // both unlocked and connected (that is, SessionState is 0). - switch (wParam) - { - case WTS_SESSION_LOCK: - SessionState |= 1; - break; - case WTS_SESSION_UNLOCK: - SessionState &= ~1; - break; - case WTS_CONSOLE_DISCONNECT: - SessionState |= 2; - break; - case WTS_CONSOLE_CONNECT: - SessionState &= ~2; - break; - } - } - else if (message == WM_POWERBROADCAST) - { - switch (wParam) - { - case PBT_APMSUSPEND: - SessionState |= 4; - break; - case PBT_APMRESUMESUSPEND: - SessionState &= ~4; - break; - } - } - - if (GSnd != NULL) - { -#if 0 - // Do we actually need this here? - if (!oldstate && SessionState) - { - GSnd->SuspendSound (); - } -#endif - } -#ifdef _DEBUG - char foo[256]; - mysnprintf (foo, countof(foo), "Session Change: %ld %d\n", lParam, wParam); - OutputDebugStringA (foo); -#endif - } - break; - - case WM_ERASEBKGND: - return true; - - case WM_DEVICECHANGE: - if (wParam == DBT_DEVNODES_CHANGED || - wParam == DBT_DEVICEARRIVAL || - wParam == DBT_CONFIGCHANGED) - { - event_t ev = { EV_DeviceChange }; - D_PostEvent(&ev); - } - return DefWindowProc (hWnd, message, wParam, lParam); - - default: - return DefWindowProc (hWnd, message, wParam, lParam); - } - - return 0; -} - -bool I_InitInput (void *hwnd) -{ - HRESULT hr; - - Printf ("I_InitInput\n"); - - noidle = !!Args->CheckParm ("-noidle"); - g_pdi = NULL; - g_pdi3 = NULL; - - // Try for DirectInput 8 first, then DirectInput 3 for NT 4's benefit. - DInputDLL = LoadLibraryA("dinput8.dll"); - if (DInputDLL != NULL) - { - typedef HRESULT (WINAPI *blah)(HINSTANCE, DWORD, REFIID, LPVOID *, LPUNKNOWN); - blah di8c = (blah)GetProcAddress(DInputDLL, "DirectInput8Create"); - if (di8c != NULL) - { - hr = di8c(g_hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&g_pdi, NULL); - if (FAILED(hr)) - { - Printf(TEXTCOLOR_ORANGE "DirectInput8Create failed: %08lx\n", hr); - g_pdi = NULL; // Just to be sure DirectInput8Create didn't change it - } - } - else - { - Printf(TEXTCOLOR_ORANGE "Could not find DirectInput8Create in dinput8.dll\n"); - } - } - - if (g_pdi == NULL) - { - if (DInputDLL != NULL) - { - FreeLibrary(DInputDLL); - } - DInputDLL = LoadLibraryA ("dinput.dll"); - if (DInputDLL == NULL) - { - I_FatalError ("Could not load dinput.dll: %08lx", GetLastError()); - } - - typedef HRESULT (WINAPI *blah)(HINSTANCE, DWORD, LPDIRECTINPUT*, LPUNKNOWN); -#ifdef UNICODE - blah dic = (blah)GetProcAddress (DInputDLL, "DirectInputCreateW"); -#else - blah dic = (blah)GetProcAddress(DInputDLL, "DirectInputCreateA"); -#endif - - if (dic == NULL) - { - I_FatalError ("dinput.dll is corrupt"); - } - - hr = dic (g_hInst, 0x0300, &g_pdi3, NULL); - if (FAILED(hr)) - { - I_FatalError ("DirectInputCreate failed: %08lx", hr); - } - } - - Printf ("I_StartupMouse\n"); - I_StartupMouse(); - - Printf ("I_StartupKeyboard\n"); - I_StartupKeyboard(); - - Printf ("I_StartupXInput\n"); - I_StartupXInput(); - - Printf ("I_StartupRawPS2\n"); - I_StartupRawPS2(); - - Printf ("I_StartupDirectInputJoystick\n"); - I_StartupDirectInputJoystick(); - - return TRUE; -} - - -// Free all input resources -void I_ShutdownInput () -{ - if (Keyboard != NULL) - { - delete Keyboard; - Keyboard = NULL; - } - if (Mouse != NULL) - { - delete Mouse; - Mouse = NULL; - } - for (int i = 0; i < NUM_JOYDEVICES; ++i) - { - if (JoyDevices[i] != NULL) - { - delete JoyDevices[i]; - JoyDevices[i] = NULL; - } - } - if (g_pdi) - { - g_pdi->Release (); - g_pdi = NULL; - } - if (g_pdi3) - { - g_pdi3->Release (); - g_pdi3 = NULL; - } - if (DInputDLL != NULL) - { - FreeLibrary (DInputDLL); - DInputDLL = NULL; - } -} - -void I_GetEvent () -{ - MSG mess; - - // Briefly enter an alertable state so that if a secondary thread - // crashed, we will execute the APC it sent now. - SleepEx (0, TRUE); - - while (PeekMessage (&mess, NULL, 0, 0, PM_REMOVE)) - { - if (mess.message == WM_QUIT) - throw CExitEvent(mess.wParam); - - if (GUICapture) - { - TranslateMessage (&mess); - } - DispatchMessage (&mess); - } - - if (Keyboard != NULL) - { - Keyboard->ProcessInput(); - } - if (Mouse != NULL) - { - Mouse->ProcessInput(); - } -} - -// -// I_StartTic -// -void I_StartTic () -{ - BlockMouseMove--; - ResetButtonTriggers (); - I_CheckGUICapture (); - EventHandlerResultForNativeMouse = primaryLevel->localEventManager->CheckRequireMouse(); - I_CheckNativeMouse (false, EventHandlerResultForNativeMouse); - I_GetEvent (); -} - -// -// I_StartFrame -// -void I_StartFrame () -{ - if (use_joystick) - { - for (int i = 0; i < NUM_JOYDEVICES; ++i) - { - if (JoyDevices[i] != NULL) - { - JoyDevices[i]->ProcessInput(); - } - } - } -} - -void I_GetAxes(float axes[NUM_JOYAXIS]) -{ - int i; - - for (i = 0; i < NUM_JOYAXIS; ++i) - { - axes[i] = 0; - } - if (use_joystick) - { - for (i = 0; i < NUM_JOYDEVICES; ++i) - { - if (JoyDevices[i] != NULL) - { - JoyDevices[i]->AddAxes(axes); - } - } - } -} - -void I_GetJoysticks(TArray &sticks) -{ - sticks.Clear(); - for (int i = 0; i < NUM_JOYDEVICES; ++i) - { - if (JoyDevices[i] != NULL) - { - JoyDevices[i]->GetDevices(sticks); - } - } -} - -// If a new controller was added, returns a pointer to it. -IJoystickConfig *I_UpdateDeviceList() -{ - IJoystickConfig *newone = NULL; - for (int i = 0; i < NUM_JOYDEVICES; ++i) - { - if (JoyDevices[i] != NULL) - { - IJoystickConfig *thisnewone = JoyDevices[i]->Rescan(); - if (newone == NULL) - { - newone = thisnewone; - } - } - } - return newone; -} - -void I_PutInClipboard (const char *str) -{ - if (str == NULL || !OpenClipboard (Window)) - return; - EmptyClipboard (); - - auto wstr = WideString(str); - HGLOBAL cliphandle = GlobalAlloc (GMEM_DDESHARE, wstr.length() * 2 + 2); - if (cliphandle != NULL) - { - wchar_t *ptr = (wchar_t *)GlobalLock (cliphandle); - wcscpy (ptr, wstr.c_str()); - GlobalUnlock (cliphandle); - SetClipboardData (CF_UNICODETEXT, cliphandle); - } - CloseClipboard (); -} - -FString I_GetFromClipboard (bool return_nothing) -{ - FString retstr; - HGLOBAL cliphandle; - wchar_t *clipstr; - - if (return_nothing || !IsClipboardFormatAvailable (CF_UNICODETEXT) || !OpenClipboard (Window)) - return retstr; - - cliphandle = GetClipboardData (CF_UNICODETEXT); - if (cliphandle != nullptr) - { - clipstr = (wchar_t *)GlobalLock (cliphandle); - if (clipstr != nullptr) - { - // Convert CR-LF pairs to just LF. - retstr = clipstr; - GlobalUnlock(clipstr); - retstr.Substitute("\r\n", "\n"); - } - } - - CloseClipboard (); - return retstr; -} - -//========================================================================== -// -// FInputDevice - Destructor -// -//========================================================================== - -FInputDevice::~FInputDevice() -{ -} - -//========================================================================== -// -// FInputDevice :: ProcessInput -// -// Gives subclasses an opportunity to do input handling that doesn't involve -// window messages. -// -//========================================================================== - -void FInputDevice::ProcessInput() -{ -} - -//========================================================================== -// -// FInputDevice :: ProcessRawInput -// -// Gives subclasses a chance to handle WM_INPUT messages. This is not part -// of WndProcHook so that we only need to fill the RAWINPUT buffer once -// per message and be sure it gets cleaned up properly. -// -//========================================================================== - -bool FInputDevice::ProcessRawInput(RAWINPUT *raw, int code) -{ - return false; -} - -//========================================================================== -// -// FInputDevice :: WndProcHook -// -// Gives subclasses a chance to intercept window messages. -// -//========================================================================== - -bool FInputDevice::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) -{ - return false; -} - diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp deleted file mode 100644 index 254dc1bc846..00000000000 --- a/src/win32/i_main.cpp +++ /dev/null @@ -1,1300 +0,0 @@ -/* -** i_main.cpp -** System-specific startup code. Eventually calls D_DoomMain. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning(disable:4244) -#endif - -//#include -#define NOTIFY_FOR_THIS_SESSION 0 - -#ifdef _MSC_VER -#include -#include -#include -#endif -#include "resource.h" - -#include "doomerrors.h" -#include "hardware.h" - -#include "m_argv.h" -#include "d_main.h" -#include "i_module.h" -#include "c_console.h" -#include "version.h" -#include "i_input.h" -#include "w_wad.h" -#include "cmdlib.h" -#include "g_game.h" -#include "r_utility.h" -#include "g_levellocals.h" -#include "s_sound.h" -#include "vm.h" -#include "i_system.h" -#include "gstrings.h" -#include "s_music.h" - -#include "stats.h" -#include "st_start.h" - -// MACROS ------------------------------------------------------------------ - -// The main window's title. -#ifdef _M_X64 -#define X64 " 64-bit" -#else -#define X64 "" -#endif - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); -void CreateCrashLog (const char *custominfo, DWORD customsize, HWND richedit); -void DisplayCrashLog (); -void I_FlushBufferedConsoleStuff(); -void DestroyCustomCursor(); - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern EXCEPTION_POINTERS CrashPointers; -extern UINT TimerPeriod; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// The command line arguments. -FArgs *Args; - -HINSTANCE g_hInst; -DWORD SessionID; -HANDLE MainThread; -DWORD MainThreadID; -HANDLE StdOut; -bool FancyStdOut, AttachedStdOut; -bool ConWindowHidden; - -// The main window -HWND Window; - -// The subwindows used for startup and error output -HWND ConWindow, GameTitleWindow; -HWND ErrorPane, ProgressBar, NetStartPane, StartupScreen, ErrorIcon; - -HFONT GameTitleFont; -LONG GameTitleFontHeight; -LONG DefaultGUIFontHeight; -LONG ErrorIconChar; - -FModule Kernel32Module{"Kernel32"}; -FModule Shell32Module{"Shell32"}; -FModule User32Module{"User32"}; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static const WCHAR WinClassName[] = WGAMENAME "MainWindow"; -static HMODULE hwtsapi32; // handle to wtsapi32.dll - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// UnCOM -// -// Called by atexit if CoInitialize() succeeded. -// -//========================================================================== - -static void UnCOM (void) -{ - CoUninitialize (); -} - -//========================================================================== -// -// UnWTS -// -// Called by atexit if RegisterSessionNotification() succeeded. -// -//========================================================================== - -static void UnWTS (void) -{ - if (hwtsapi32 != 0) - { - typedef BOOL (WINAPI *ursn)(HWND); - ursn unreg = (ursn)GetProcAddress (hwtsapi32, "WTSUnRegisterSessionNotification"); - if (unreg != 0) - { - unreg (Window); - } - FreeLibrary (hwtsapi32); - hwtsapi32 = 0; - } -} - -//========================================================================== -// -// LayoutErrorPane -// -// Lays out the error pane to the desired width, returning the required -// height. -// -//========================================================================== - -static int LayoutErrorPane (HWND pane, int w) -{ - HWND ctl; - RECT rectc; - - // Right-align the Quit button. - ctl = GetDlgItem (pane, IDOK); - GetClientRect (ctl, &rectc); // Find out how big it is. - MoveWindow (ctl, w - rectc.right - 1, 1, rectc.right, rectc.bottom, TRUE); - InvalidateRect (ctl, NULL, TRUE); - - // Return the needed height for this layout - return rectc.bottom + 2; -} - -//========================================================================== -// -// LayoutNetStartPane -// -// Lays out the network startup pane to the specified width, returning -// its required height. -// -//========================================================================== - -int LayoutNetStartPane (HWND pane, int w) -{ - HWND ctl; - RECT margin, rectc; - int staticheight, barheight; - - // Determine margin sizes. - SetRect (&margin, 7, 7, 0, 0); - MapDialogRect (pane, &margin); - - // Stick the message text in the upper left corner. - ctl = GetDlgItem (pane, IDC_NETSTARTMESSAGE); - GetClientRect (ctl, &rectc); - MoveWindow (ctl, margin.left, margin.top, rectc.right, rectc.bottom, TRUE); - - // Stick the count text in the upper right corner. - ctl = GetDlgItem (pane, IDC_NETSTARTCOUNT); - GetClientRect (ctl, &rectc); - MoveWindow (ctl, w - rectc.right - margin.left, margin.top, rectc.right, rectc.bottom, TRUE); - staticheight = rectc.bottom; - - // Stretch the progress bar to fill the entire width. - ctl = GetDlgItem (pane, IDC_NETSTARTPROGRESS); - barheight = GetSystemMetrics (SM_CYVSCROLL); - MoveWindow (ctl, margin.left, margin.top*2 + staticheight, w - margin.left*2, barheight, TRUE); - - // Center the abort button underneath the progress bar. - ctl = GetDlgItem (pane, IDCANCEL); - GetClientRect (ctl, &rectc); - MoveWindow (ctl, (w - rectc.right) / 2, margin.top*3 + staticheight + barheight, rectc.right, rectc.bottom, TRUE); - - return margin.top*4 + staticheight + barheight + rectc.bottom; -} - -//========================================================================== -// -// LayoutMainWindow -// -// Lays out the main window with the game title and log controls and -// possibly the error pane and progress bar. -// -//========================================================================== - -void LayoutMainWindow (HWND hWnd, HWND pane) -{ - RECT rect; - int errorpaneheight = 0; - int bannerheight = 0; - int progressheight = 0; - int netpaneheight = 0; - int leftside = 0; - int w, h; - - GetClientRect (hWnd, &rect); - w = rect.right; - h = rect.bottom; - - if (DoomStartupInfo.Name.IsNotEmpty() && GameTitleWindow != NULL) - { - bannerheight = GameTitleFontHeight + 5; - MoveWindow (GameTitleWindow, 0, 0, w, bannerheight, TRUE); - InvalidateRect (GameTitleWindow, NULL, FALSE); - } - if (ProgressBar != NULL) - { - // Base the height of the progress bar on the height of a scroll bar - // arrow, just as in the progress bar example. - progressheight = GetSystemMetrics (SM_CYVSCROLL); - MoveWindow (ProgressBar, 0, h - progressheight, w, progressheight, TRUE); - } - if (NetStartPane != NULL) - { - netpaneheight = LayoutNetStartPane (NetStartPane, w); - SetWindowPos (NetStartPane, HWND_TOP, 0, h - progressheight - netpaneheight, w, netpaneheight, SWP_SHOWWINDOW); - } - if (pane != NULL) - { - errorpaneheight = LayoutErrorPane (pane, w); - SetWindowPos (pane, HWND_TOP, 0, h - progressheight - netpaneheight - errorpaneheight, w, errorpaneheight, 0); - } - if (ErrorIcon != NULL) - { - leftside = GetSystemMetrics (SM_CXICON) + 6; - MoveWindow (ErrorIcon, 0, bannerheight, leftside, h - bannerheight - errorpaneheight - progressheight - netpaneheight, TRUE); - } - // If there is a startup screen, it covers the log window - if (StartupScreen != NULL) - { - SetWindowPos (StartupScreen, HWND_TOP, leftside, bannerheight, w - leftside, - h - bannerheight - errorpaneheight - progressheight - netpaneheight, SWP_SHOWWINDOW); - InvalidateRect (StartupScreen, NULL, FALSE); - MoveWindow (ConWindow, 0, 0, 0, 0, TRUE); - } - else - { - // The log window uses whatever space is left. - MoveWindow (ConWindow, leftside, bannerheight, w - leftside, - h - bannerheight - errorpaneheight - progressheight - netpaneheight, TRUE); - } -} - - -//========================================================================== -// -// I_SetIWADInfo -// -//========================================================================== - -void I_SetIWADInfo() -{ - // Make the startup banner show itself - LayoutMainWindow(Window, NULL); -} - -//========================================================================== -// -// LConProc -// -// The main window's WndProc during startup. During gameplay, the WndProc -// in i_input.cpp is used instead. -// -//========================================================================== - -LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HWND view; - HDC hdc; - HBRUSH hbr; - HGDIOBJ oldfont; - RECT rect; - SIZE size; - LOGFONT lf; - TEXTMETRIC tm; - HINSTANCE inst = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_HINSTANCE); - DRAWITEMSTRUCT *drawitem; - CHARFORMAT2W format; - - switch (msg) - { - case WM_CREATE: - // Create game title static control - memset (&lf, 0, sizeof(lf)); - hdc = GetDC (hWnd); - lf.lfHeight = -MulDiv(12, GetDeviceCaps(hdc, LOGPIXELSY), 72); - lf.lfCharSet = ANSI_CHARSET; - lf.lfWeight = FW_BOLD; - lf.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN; - wcscpy (lf.lfFaceName, L"Trebuchet MS"); - GameTitleFont = CreateFontIndirect (&lf); - - oldfont = SelectObject (hdc, GetStockObject (DEFAULT_GUI_FONT)); - GetTextMetrics (hdc, &tm); - DefaultGUIFontHeight = tm.tmHeight; - if (GameTitleFont == NULL) - { - GameTitleFontHeight = DefaultGUIFontHeight; - } - else - { - SelectObject (hdc, GameTitleFont); - GetTextMetrics (hdc, &tm); - GameTitleFontHeight = tm.tmHeight; - } - SelectObject (hdc, oldfont); - - // Create log read-only edit control - view = CreateWindowExW (WS_EX_NOPARENTNOTIFY, L"RichEdit20W", nullptr, - WS_CHILD | WS_VISIBLE | WS_VSCROLL | - ES_LEFT | ES_MULTILINE | WS_CLIPSIBLINGS, - 0, 0, 0, 0, - hWnd, NULL, inst, NULL); - HRESULT hr; - hr = GetLastError(); - if (view == NULL) - { - ReleaseDC (hWnd, hdc); - return -1; - } - SendMessage (view, EM_SETREADONLY, TRUE, 0); - SendMessage (view, EM_EXLIMITTEXT, 0, 0x7FFFFFFE); - SendMessage (view, EM_SETBKGNDCOLOR, 0, RGB(70,70,70)); - // Setup default font for the log. - //SendMessage (view, WM_SETFONT, (WPARAM)GetStockObject (DEFAULT_GUI_FONT), FALSE); - format.cbSize = sizeof(format); - format.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_SIZE | CFM_CHARSET; - format.dwEffects = 0; - format.yHeight = 200; - format.crTextColor = RGB(223,223,223); - format.bCharSet = ANSI_CHARSET; - format.bPitchAndFamily = FF_SWISS | VARIABLE_PITCH; - wcscpy(format.szFaceName, L"DejaVu Sans"); // At least I have it. :p - SendMessageW(view, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&format); - - ConWindow = view; - ReleaseDC (hWnd, hdc); - - view = CreateWindowExW (WS_EX_NOPARENTNOTIFY, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, hWnd, nullptr, inst, nullptr); - if (view == nullptr) - { - return -1; - } - SetWindowLong (view, GWL_ID, IDC_STATIC_TITLE); - GameTitleWindow = view; - - return 0; - - case WM_SIZE: - if (wParam != SIZE_MAXHIDE && wParam != SIZE_MAXSHOW) - { - LayoutMainWindow (hWnd, ErrorPane); - } - return 0; - - case WM_DRAWITEM: - // Draw title banner. - if (wParam == IDC_STATIC_TITLE && DoomStartupInfo.Name.IsNotEmpty()) - { - const PalEntry *c; - - // Draw the game title strip at the top of the window. - drawitem = (LPDRAWITEMSTRUCT)lParam; - - // Draw the background. - rect = drawitem->rcItem; - rect.bottom -= 1; - c = (const PalEntry *)&DoomStartupInfo.BkColor; - hbr = CreateSolidBrush (RGB(c->r,c->g,c->b)); - FillRect (drawitem->hDC, &drawitem->rcItem, hbr); - DeleteObject (hbr); - - // Calculate width of the title string. - SetTextAlign (drawitem->hDC, TA_TOP); - oldfont = SelectObject (drawitem->hDC, GameTitleFont != NULL ? GameTitleFont : (HFONT)GetStockObject (DEFAULT_GUI_FONT)); - auto widename = DoomStartupInfo.Name.WideString(); - GetTextExtentPoint32W (drawitem->hDC, widename.c_str(), (int)widename.length(), &size); - - // Draw the title. - c = (const PalEntry *)&DoomStartupInfo.FgColor; - SetTextColor (drawitem->hDC, RGB(c->r,c->g,c->b)); - SetBkMode (drawitem->hDC, TRANSPARENT); - TextOutW (drawitem->hDC, rect.left + (rect.right - rect.left - size.cx) / 2, 2, widename.c_str(), (int)widename.length()); - SelectObject (drawitem->hDC, oldfont); - return TRUE; - } - // Draw startup screen - else if (wParam == IDC_STATIC_STARTUP) - { - if (StartupScreen != NULL) - { - drawitem = (LPDRAWITEMSTRUCT)lParam; - - rect = drawitem->rcItem; - // Windows expects DIBs to be bottom-up but ours is top-down, - // so flip it vertically while drawing it. - StretchDIBits (drawitem->hDC, rect.left, rect.bottom - 1, rect.right - rect.left, rect.top - rect.bottom, - 0, 0, StartupBitmap->bmiHeader.biWidth, StartupBitmap->bmiHeader.biHeight, - ST_Util_BitsForBitmap(StartupBitmap), reinterpret_cast(StartupBitmap), DIB_RGB_COLORS, SRCCOPY); - - // If the title banner is gone, then this is an ENDOOM screen, so draw a short prompt - // where the command prompt would have been in DOS. - if (GameTitleWindow == NULL) - { - auto quitmsg = WideString(GStrings("TXT_QUITENDOOM")); - - SetTextColor (drawitem->hDC, RGB(240,240,240)); - SetBkMode (drawitem->hDC, TRANSPARENT); - oldfont = SelectObject (drawitem->hDC, (HFONT)GetStockObject (DEFAULT_GUI_FONT)); - TextOutW (drawitem->hDC, 3, drawitem->rcItem.bottom - DefaultGUIFontHeight - 3, quitmsg.c_str(), (int)quitmsg.length()); - SelectObject (drawitem->hDC, oldfont); - } - return TRUE; - } - } - // Draw stop icon. - else if (wParam == IDC_ICONPIC) - { - HICON icon; - POINTL char_pos; - drawitem = (LPDRAWITEMSTRUCT)lParam; - - // This background color should match the edit control's. - hbr = CreateSolidBrush (RGB(70,70,70)); - FillRect (drawitem->hDC, &drawitem->rcItem, hbr); - DeleteObject (hbr); - - // Draw the icon aligned with the first line of error text. - SendMessage (ConWindow, EM_POSFROMCHAR, (WPARAM)&char_pos, ErrorIconChar); - icon = (HICON)LoadImage (0, IDI_ERROR, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); - DrawIcon (drawitem->hDC, 6, char_pos.y, icon); - return TRUE; - } - return FALSE; - - case WM_COMMAND: - if (ErrorIcon != NULL && (HWND)lParam == ConWindow && HIWORD(wParam) == EN_UPDATE) - { - // Be sure to redraw the error icon if the edit control changes. - InvalidateRect (ErrorIcon, NULL, TRUE); - return 0; - } - break; - - case WM_CLOSE: - PostQuitMessage (0); - break; - - case WM_DESTROY: - if (GameTitleFont != NULL) - { - DeleteObject (GameTitleFont); - } - break; - } - return DefWindowProc (hWnd, msg, wParam, lParam); -} - -//========================================================================== -// -// ErrorPaneProc -// -// DialogProc for the error pane. -// -//========================================================================== - -INT_PTR CALLBACK ErrorPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_INITDIALOG: - // Appear in the main window. - LayoutMainWindow (GetParent (hDlg), hDlg); - return TRUE; - - case WM_COMMAND: - // There is only one button, and it's "Ok" and makes us quit. - if (HIWORD(wParam) == BN_CLICKED) - { - PostQuitMessage (0); - return TRUE; - } - break; - } - return FALSE; -} - -//========================================================================== -// -// I_SetWndProc -// -// Sets the main WndProc, hides all the child windows, and starts up -// in-game input. -// -//========================================================================== - -void I_SetWndProc() -{ - if (GetWindowLongPtr (Window, GWLP_USERDATA) == 0) - { - SetWindowLongPtr (Window, GWLP_USERDATA, 1); - SetWindowLongPtr (Window, GWLP_WNDPROC, (WLONG_PTR)WndProc); - ShowWindow (ConWindow, SW_HIDE); - ConWindowHidden = true; - ShowWindow (GameTitleWindow, SW_HIDE); - I_InitInput (Window); - } -} - -//========================================================================== -// -// RestoreConView -// -// Returns the main window to its startup state. -// -//========================================================================== - -void RestoreConView() -{ - HDC screenDC = GetDC(0); - int dpi = GetDeviceCaps(screenDC, LOGPIXELSX); - ReleaseDC(0, screenDC); - int width = (512 * dpi + 96 / 2) / 96; - int height = (384 * dpi + 96 / 2) / 96; - - // Make sure the window has a frame in case it was fullscreened. - SetWindowLongPtr (Window, GWL_STYLE, WS_VISIBLE|WS_OVERLAPPEDWINDOW); - if (GetWindowLong (Window, GWL_EXSTYLE) & WS_EX_TOPMOST) - { - SetWindowPos (Window, HWND_BOTTOM, 0, 0, width, height, - SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE); - SetWindowPos (Window, HWND_TOP, 0, 0, 0, 0, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE); - } - else - { - SetWindowPos (Window, NULL, 0, 0, width, height, - SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER); - } - - SetWindowLongPtr (Window, GWLP_WNDPROC, (WLONG_PTR)LConProc); - ShowWindow (ConWindow, SW_SHOW); - ConWindowHidden = false; - ShowWindow (GameTitleWindow, SW_SHOW); - I_ShutdownInput (); // Make sure the mouse pointer is available. - // Make sure the progress bar isn't visible. - DeleteStartupScreen(); -} - -//========================================================================== -// -// ShowErrorPane -// -// Shows an error message, preferably in the main window, but it can -// use a normal message box too. -// -//========================================================================== - -void ShowErrorPane(const char *text) -{ - auto widetext = WideString(text); - if (Window == nullptr || ConWindow == nullptr) - { - if (text != NULL) - { - MessageBoxW (Window, widetext.c_str(), - WGAMENAME " Fatal Error", MB_OK|MB_ICONSTOP|MB_TASKMODAL); - } - return; - } - - if (StartScreen != NULL) // Ensure that the network pane is hidden. - { - StartScreen->NetDone(); - } - if (text != NULL) - { - FStringf caption("Fatal Error - " GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); - auto wcaption = caption.WideString(); - SetWindowTextW (Window, wcaption.c_str()); - ErrorIcon = CreateWindowExW (WS_EX_NOPARENTNOTIFY, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, Window, NULL, g_hInst, NULL); - if (ErrorIcon != NULL) - { - SetWindowLong (ErrorIcon, GWL_ID, IDC_ICONPIC); - } - } - ErrorPane = CreateDialogParam (g_hInst, MAKEINTRESOURCE(IDD_ERRORPANE), Window, ErrorPaneProc, (LONG_PTR)NULL); - - if (text != NULL) - { - CHARRANGE end; - CHARFORMAT2 oldformat, newformat; - PARAFORMAT2 paraformat; - - // Append the error message to the log. - end.cpMax = end.cpMin = GetWindowTextLength (ConWindow); - SendMessage (ConWindow, EM_EXSETSEL, 0, (LPARAM)&end); - - // Remember current charformat. - oldformat.cbSize = sizeof(oldformat); - SendMessage (ConWindow, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&oldformat); - - // Use bigger font and standout colors. - newformat.cbSize = sizeof(newformat); - newformat.dwMask = CFM_BOLD | CFM_COLOR | CFM_SIZE; - newformat.dwEffects = CFE_BOLD; - newformat.yHeight = oldformat.yHeight * 5 / 4; - newformat.crTextColor = RGB(255,170,170); - SendMessage (ConWindow, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&newformat); - - // Indent the rest of the text to make the error message stand out a little more. - paraformat.cbSize = sizeof(paraformat); - paraformat.dwMask = PFM_STARTINDENT | PFM_OFFSETINDENT | PFM_RIGHTINDENT; - paraformat.dxStartIndent = paraformat.dxOffset = paraformat.dxRightIndent = 120; - SendMessage (ConWindow, EM_SETPARAFORMAT, 0, (LPARAM)¶format); - SendMessageW (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)L"\n"); - - // Find out where the error lines start for the error icon display control. - SendMessage (ConWindow, EM_EXGETSEL, 0, (LPARAM)&end); - ErrorIconChar = end.cpMax; - - // Now start adding the actual error message. - SendMessageW (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)L"Execution could not continue.\n\n"); - - // Restore old charformat but with light yellow text. - oldformat.crTextColor = RGB(255,255,170); - SendMessage (ConWindow, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&oldformat); - - // Add the error text. - SendMessageW (ConWindow, EM_REPLACESEL, FALSE, (LPARAM)widetext.c_str()); - - // Make sure the error text is not scrolled below the window. - SendMessage (ConWindow, EM_LINESCROLL, 0, SendMessage (ConWindow, EM_GETLINECOUNT, 0, 0)); - // The above line scrolled everything off the screen, so pretend to move the scroll - // bar thumb, which clamps to not show any extra lines if it doesn't need to. - SendMessage (ConWindow, EM_SCROLL, SB_PAGEDOWN, 0); - } - - BOOL bRet; - MSG msg; - - while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) - { - if (bRet == -1) - { - MessageBoxW (Window, widetext.c_str(), WGAMENAME " Fatal Error", MB_OK|MB_ICONSTOP|MB_TASKMODAL); - return; - } - else if (!IsDialogMessage (ErrorPane, &msg)) - { - TranslateMessage (&msg); - DispatchMessage (&msg); - } - } -} - -void PeekThreadedErrorPane() -{ - // Allow SendMessage from another thread to call its message handler so that it can display the crash dialog - MSG msg; - PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); -} - -static void UnTbp() -{ - timeEndPeriod(TimerPeriod); -} - -//========================================================================== -// -// DoMain -// -//========================================================================== - -int DoMain (HINSTANCE hInstance) -{ - LONG WinWidth, WinHeight; - int height, width, x, y; - RECT cRect; - TIMECAPS tc; - DEVMODE displaysettings; - - // Do not use the multibyte __argv here because we want UTF-8 arguments - // and those can only be done by converting the Unicode variants. - Args = new FArgs(); - auto argc = __argc; - auto wargv = __wargv; - for (int i = 0; i < argc; i++) - { - Args->AppendArg(FString(wargv[i])); - } - - // Load Win32 modules - Kernel32Module.Load({"kernel32.dll"}); - Shell32Module.Load({"shell32.dll"}); - User32Module.Load({"user32.dll"}); - - // Under XP, get our session ID so we can know when the user changes/locks sessions. - // Since we need to remain binary compatible with older versions of Windows, we - // need to extract the ProcessIdToSessionId function from kernel32.dll manually. - HMODULE kernel = GetModuleHandleA ("kernel32.dll"); - - if (Args->CheckParm("-stdout")) - { - // As a GUI application, we don't normally get a console when we start. - // If we were run from the shell and are on XP+, we can attach to its - // console. Otherwise, we can create a new one. If we already have a - // stdout handle, then we have been redirected and should just use that - // handle instead of creating a console window. - - StdOut = GetStdHandle(STD_OUTPUT_HANDLE); - if (StdOut != NULL) - { - // It seems that running from a shell always creates a std output - // for us, even if it doesn't go anywhere. (Running from Explorer - // does not.) If we can get file information for this handle, it's - // a file or pipe, so use it. Otherwise, pretend it wasn't there - // and find a console to use instead. - BY_HANDLE_FILE_INFORMATION info; - if (!GetFileInformationByHandle(StdOut, &info)) - { - StdOut = NULL; - } - } - if (StdOut == NULL) - { - if (AttachConsole(ATTACH_PARENT_PROCESS)) - { - StdOut = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD foo; WriteFile(StdOut, "\n", 1, &foo, NULL); - AttachedStdOut = true; - } - if (StdOut == NULL && AllocConsole()) - { - StdOut = GetStdHandle(STD_OUTPUT_HANDLE); - } - - // These two functions do not exist in Windows XP. - BOOL (WINAPI* p_GetCurrentConsoleFontEx)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); - BOOL (WINAPI* p_SetCurrentConsoleFontEx)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); - - p_SetCurrentConsoleFontEx = (decltype(p_SetCurrentConsoleFontEx))GetProcAddress(kernel, "SetCurrentConsoleFontEx"); - p_GetCurrentConsoleFontEx = (decltype(p_GetCurrentConsoleFontEx))GetProcAddress(kernel, "GetCurrentConsoleFontEx"); - if (p_SetCurrentConsoleFontEx && p_GetCurrentConsoleFontEx) - { - CONSOLE_FONT_INFOEX cfi; - cfi.cbSize = sizeof(cfi); - - if (p_GetCurrentConsoleFontEx(StdOut, false, &cfi)) - { - if (*cfi.FaceName == 0) // If the face name is empty, the default (useless) raster font is actoive. - { - //cfi.dwFontSize = { 8, 14 }; - wcscpy(cfi.FaceName, L"Lucida Console"); - cfi.FontFamily = FF_DONTCARE; - p_SetCurrentConsoleFontEx(StdOut, false, &cfi); - } - } - } - FancyStdOut = true; - } - } - - // Set the timer to be as accurate as possible - if (timeGetDevCaps (&tc, sizeof(tc)) != TIMERR_NOERROR) - TimerPeriod = 1; // Assume minimum resolution of 1 ms - else - TimerPeriod = tc.wPeriodMin; - - timeBeginPeriod (TimerPeriod); - atexit(UnTbp); - - // Figure out what directory the program resides in. - WCHAR progbuff[1024]; - if (GetModuleFileNameW(nullptr, progbuff, sizeof progbuff) == 0) - { - MessageBoxA(nullptr, "Fatal", "Could not determine program location.", MB_ICONEXCLAMATION|MB_OK); - exit(-1); - } - - progbuff[1023] = '\0'; - if (auto lastsep = wcsrchr(progbuff, '\\')) - { - lastsep[1] = '\0'; - } - - progdir = progbuff; - FixPathSeperator(progdir); - - HDC screenDC = GetDC(0); - int dpi = GetDeviceCaps(screenDC, LOGPIXELSX); - ReleaseDC(0, screenDC); - width = (512 * dpi + 96 / 2) / 96; - height = (384 * dpi + 96 / 2) / 96; - - // Many Windows structures that specify their size do so with the first - // element. DEVMODE is not one of those structures. - memset (&displaysettings, 0, sizeof(displaysettings)); - displaysettings.dmSize = sizeof(displaysettings); - EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings); - x = (displaysettings.dmPelsWidth - width) / 2; - y = (displaysettings.dmPelsHeight - height) / 2; - - if (Args->CheckParm ("-0")) - { - x = y = 0; - } - - WNDCLASS WndClass; - WndClass.style = 0; - WndClass.lpfnWndProc = LConProc; - WndClass.cbClsExtra = 0; - WndClass.cbWndExtra = 0; - WndClass.hInstance = hInstance; - WndClass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON1)); - WndClass.hCursor = LoadCursor (NULL, IDC_ARROW); - WndClass.hbrBackground = NULL; - WndClass.lpszMenuName = NULL; - WndClass.lpszClassName = WinClassName; - - /* register this new class with Windows */ - if (!RegisterClass((LPWNDCLASS)&WndClass)) - { - MessageBoxA(nullptr, "Could not register window class", "Fatal", MB_ICONEXCLAMATION|MB_OK); - exit(-1); - } - - /* create window */ - FStringf caption("" GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); - std::wstring wcaption = caption.WideString(); - Window = CreateWindowExW( - WS_EX_APPWINDOW, - WinClassName, - wcaption.c_str(), - WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, - x, y, width, height, - (HWND) NULL, - (HMENU) NULL, - hInstance, - NULL); - - if (!Window) - { - MessageBoxA(nullptr, "Unable to create main window", "Fatal", MB_ICONEXCLAMATION|MB_OK); - exit(-1); - } - - if (kernel != NULL) - { - typedef BOOL (WINAPI *pts)(DWORD, DWORD *); - pts pidsid = (pts)GetProcAddress (kernel, "ProcessIdToSessionId"); - if (pidsid != 0) - { - if (!pidsid (GetCurrentProcessId(), &SessionID)) - { - SessionID = 0; - } - hwtsapi32 = LoadLibraryA ("wtsapi32.dll"); - if (hwtsapi32 != 0) - { - FARPROC reg = GetProcAddress (hwtsapi32, "WTSRegisterSessionNotification"); - if (reg == 0 || !((BOOL(WINAPI *)(HWND, DWORD))reg) (Window, NOTIFY_FOR_THIS_SESSION)) - { - FreeLibrary (hwtsapi32); - hwtsapi32 = 0; - } - else - { - atexit (UnWTS); - } - } - } - } - - GetClientRect (Window, &cRect); - - WinWidth = cRect.right; - WinHeight = cRect.bottom; - - CoInitialize (NULL); - atexit (UnCOM); - - int ret = D_DoomMain (); - DestroyCustomCursor(); - if (ret == 1337) // special exit code for 'norun'. - { - if (!batchrun) - { - if (FancyStdOut && !AttachedStdOut) - { // Outputting to a new console window: Wait for a keypress before quitting. - DWORD bytes; - HANDLE stdinput = GetStdHandle(STD_INPUT_HANDLE); - - ShowWindow(Window, SW_HIDE); - WriteFile(StdOut, "Press any key to exit...", 24, &bytes, NULL); - FlushConsoleInputBuffer(stdinput); - SetConsoleMode(stdinput, 0); - ReadConsole(stdinput, &bytes, 1, &bytes, NULL); - } - else if (StdOut == NULL) - { - ShowErrorPane(NULL); - } - } - } - return ret; -} - -void I_ShowFatalError(const char *msg) -{ - I_ShutdownGraphics (); - RestoreConView (); - S_StopMusic(true); - I_FlushBufferedConsoleStuff(); - - if (CVMAbortException::stacktrace.IsNotEmpty()) - { - Printf("%s", CVMAbortException::stacktrace.GetChars()); - } - - if (!batchrun) - { - ShowErrorPane(msg); - } - else - { - Printf("%s\n", msg); - } -} - -//========================================================================== -// -// DoomSpecificInfo -// -// Called by the crash logger to get application-specific information. -// -//========================================================================== - -void DoomSpecificInfo (char *buffer, size_t bufflen) -{ - const char *arg; - char *const buffend = buffer + bufflen - 2; // -2 for CRLF at end - int i; - - buffer += mysnprintf (buffer, buffend - buffer, GAMENAME " version %s (%s)", GetVersionString(), GetGitHash()); - FString cmdline(GetCommandLineW()); - buffer += mysnprintf (buffer, buffend - buffer, "\r\nCommand line: %s\r\n", cmdline.GetChars() ); - - for (i = 0; (arg = Wads.GetWadName (i)) != NULL; ++i) - { - buffer += mysnprintf (buffer, buffend - buffer, "\r\nWad %d: %s", i, arg); - } - - if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) - { - buffer += mysnprintf (buffer, buffend - buffer, "\r\n\r\nNot in a level."); - } - else - { - buffer += mysnprintf (buffer, buffend - buffer, "\r\n\r\nCurrent map: %s", primaryLevel->MapName.GetChars()); - - if (!viewactive) - { - buffer += mysnprintf (buffer, buffend - buffer, "\r\n\r\nView not active."); - } - else - { - auto &vp = r_viewpoint; - buffer += mysnprintf (buffer, buffend - buffer, "\r\n\r\nviewx = %f", vp.Pos.X); - buffer += mysnprintf (buffer, buffend - buffer, "\r\nviewy = %f", vp.Pos.Y); - buffer += mysnprintf (buffer, buffend - buffer, "\r\nviewz = %f", vp.Pos.Z); - buffer += mysnprintf (buffer, buffend - buffer, "\r\nviewangle = %f", vp.Angles.Yaw); - } - } - *buffer++ = '\r'; - *buffer++ = '\n'; - *buffer++ = '\0'; -} - -// Here is how the error logging system works. -// -// To catch exceptions that occur in secondary threads, CatchAllExceptions is -// set as the UnhandledExceptionFilter for this process. It records the state -// of the thread at the time of the crash using CreateCrashLog and then queues -// an APC on the primary thread. When the APC executes, it raises a software -// exception that gets caught by the __try/__except block in WinMain. -// I_GetEvent calls SleepEx to put the primary thread in a waitable state -// periodically so that the APC has a chance to execute. -// -// Exceptions on the primary thread are caught by the __try/__except block in -// WinMain. Not only does it record the crash information, it also shuts -// everything down and displays a dialog with the information present. If a -// console log is being produced, the information will also be appended to it. -// -// If a debugger is running, CatchAllExceptions never executes, so secondary -// thread exceptions will always be caught by the debugger. For the primary -// thread, IsDebuggerPresent is called to determine if a debugger is present. -// Note that this function is not present on Windows 95, so we cannot -// statically link to it. -// -// To make this work with MinGW, you will need to use inline assembly -// because GCC offers no native support for Windows' SEH. - -//========================================================================== -// -// SleepForever -// -//========================================================================== - -void SleepForever () -{ - Sleep (INFINITE); -} - -//========================================================================== -// -// ExitMessedUp -// -// An exception occurred while exiting, so don't do any standard processing. -// Just die. -// -//========================================================================== - -LONG WINAPI ExitMessedUp (LPEXCEPTION_POINTERS foo) -{ - ExitProcess (1000); -} - -//========================================================================== -// -// ExitFatally -// -//========================================================================== - -void CALLBACK ExitFatally (ULONG_PTR dummy) -{ - SetUnhandledExceptionFilter (ExitMessedUp); - I_ShutdownGraphics (); - RestoreConView (); - DisplayCrashLog (); - exit(-1); -} - -//========================================================================== -// -// CatchAllExceptions -// -//========================================================================== - -namespace -{ - CONTEXT MainThreadContext; -} - -LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info) -{ -#ifdef _DEBUG - if (info->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) - { - return EXCEPTION_CONTINUE_SEARCH; - } -#endif - - static bool caughtsomething = false; - - if (caughtsomething) return EXCEPTION_EXECUTE_HANDLER; - caughtsomething = true; - - char *custominfo = (char *)HeapAlloc (GetProcessHeap(), 0, 16384); - - CrashPointers = *info; - DoomSpecificInfo (custominfo, 16384); - CreateCrashLog (custominfo, (DWORD)strlen(custominfo), ConWindow); - - // If the main thread crashed, then make it clean up after itself. - // Otherwise, put the crashing thread to sleep and signal the main thread to clean up. - if (GetCurrentThreadId() == MainThreadID) - { -#ifdef _M_X64 - *info->ContextRecord = MainThreadContext; -#else - info->ContextRecord->Eip = (DWORD_PTR)ExitFatally; -#endif // _M_X64 - } - else - { -#ifndef _M_X64 - info->ContextRecord->Eip = (DWORD_PTR)SleepForever; -#else - info->ContextRecord->Rip = (DWORD_PTR)SleepForever; -#endif - QueueUserAPC (ExitFatally, MainThread, 0); - } - return EXCEPTION_CONTINUE_EXECUTION; -} - -//========================================================================== -// -// infiniterecursion -// -// Debugging routine for testing the crash logger. -// -//========================================================================== - -#ifdef _DEBUG -static void infiniterecursion(int foo) -{ - if (foo) - { - infiniterecursion(foo); - } -} -#endif - -// Setting this to 'true' allows getting the standard notification for a crash -// which offers the very important feature to open a debugger and see the crash in context right away. -CUSTOM_CVAR(Bool, disablecrashlog, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - SetUnhandledExceptionFilter(!*self ? CatchAllExceptions : nullptr); -} - -//========================================================================== -// -// WinMain -// -//========================================================================== - -int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE nothing, LPWSTR cmdline, int nCmdShow) -{ - g_hInst = hInstance; - - InitCommonControls (); // Load some needed controls and be pretty under XP - - // We need to load riched20.dll so that we can create the control. - if (NULL == LoadLibraryA ("riched20.dll")) - { - // This should only happen on basic Windows 95 installations, but since we - // don't support Windows 95, we have no obligation to provide assistance in - // getting it installed. - MessageBoxA(NULL, "Could not load riched20.dll", GAMENAME " Error", MB_OK | MB_ICONSTOP); - return 0; - } - -#if !defined(__GNUC__) && defined(_DEBUG) - if (__argc == 2 && __wargv != nullptr && wcscmp (__wargv[1], L"TestCrash") == 0) - { - __try - { - *(int *)0 = 0; - } - __except(CrashPointers = *GetExceptionInformation(), - CreateCrashLog ("TestCrash", 9, NULL), EXCEPTION_EXECUTE_HANDLER) - { - } - DisplayCrashLog (); - return 0; - } - if (__argc == 2 && __wargv != nullptr && wcscmp (__wargv[1], L"TestStackCrash") == 0) - { - __try - { - infiniterecursion(1); - } - __except(CrashPointers = *GetExceptionInformation(), - CreateCrashLog ("TestStackCrash", 14, NULL), EXCEPTION_EXECUTE_HANDLER) - { - } - DisplayCrashLog (); - return 0; - } -#endif - - MainThread = INVALID_HANDLE_VALUE; - DuplicateHandle (GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &MainThread, - 0, FALSE, DUPLICATE_SAME_ACCESS); - MainThreadID = GetCurrentThreadId(); - -#ifndef _DEBUG - if (MainThread != INVALID_HANDLE_VALUE) - { - SetUnhandledExceptionFilter (CatchAllExceptions); - -#ifdef _M_X64 - static bool setJumpResult = false; - RtlCaptureContext(&MainThreadContext); - if (setJumpResult) - { - ExitFatally(0); - return 0; - } - setJumpResult = true; -#endif // _M_X64 - } -#endif - -#if defined(_DEBUG) && defined(_MSC_VER) - // Uncomment this line to make the Visual C++ CRT check the heap before - // every allocation and deallocation. This will be slow, but it can be a - // great help in finding problem areas. - //_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF); - - // Enable leak checking at exit. - _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); - - // Use this to break at a specific allocation number. - //_crtBreakAlloc = 227524; -#endif - - int ret = DoMain (hInstance); - - CloseHandle (MainThread); - MainThread = INVALID_HANDLE_VALUE; - return ret; -} - -// each platform has its own specific version of this function. -void I_SetWindowTitle(const char* caption) -{ - std::wstring widecaption; - if (!caption) - { - FStringf default_caption("" GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); - widecaption = default_caption.WideString(); - } - else - { - widecaption = WideString(caption); - } - SetWindowText(Window, widecaption.c_str()); -} diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp deleted file mode 100644 index 6d0ea884dcf..00000000000 --- a/src/win32/i_specialpaths.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* -** i_specialpaths.cpp -** Gets special system folders where data should be stored. (Windows version) -** -**--------------------------------------------------------------------------- -** Copyright 2013-2016 Randy Heit -** Copyright 2016 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#include - -#include "cmdlib.h" -#include "doomtype.h" -#include "m_misc.h" -#include "version.h" // for GAMENAME - -// Vanilla MinGW does not have folder ids -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -static const GUID FOLDERID_LocalAppData = { 0xf1b32785, 0x6fba, 0x4fcf, 0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91 }; -static const GUID FOLDERID_RoamingAppData = { 0x3eb685db, 0x65f9, 0x4cf6, 0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d }; -static const GUID FOLDERID_SavedGames = { 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4 }; -static const GUID FOLDERID_Documents = { 0xfdd39ad0, 0x238f, 0x46af, 0xad, 0xb4, 0x6c, 0x85, 0x48, 0x03, 0x69, 0xc7 }; -static const GUID FOLDERID_Pictures = { 0x33e28130, 0x4e1e, 0x4676, 0x83, 0x5a, 0x98, 0x39, 0x5c, 0x3b, 0xc3, 0xbb }; -#endif - -//=========================================================================== -// -// IsProgramDirectoryWritable -// -// If the program directory is writable, then dump everything in there for -// historical reasons. Otherwise, known folders get used instead. -// -//=========================================================================== - -bool UseKnownFolders() -{ - // Cache this value so the semantics don't change during a single run - // of the program. (e.g. Somebody could add write access while the - // program is running.) - static INTBOOL iswritable = -1; - HANDLE file; - - if (iswritable >= 0) - { - return !iswritable; - } - std::wstring testpath = progdir.WideString() + L"writest"; - file = CreateFile(testpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); - if (file != INVALID_HANDLE_VALUE) - { - CloseHandle(file); - if (!batchrun) Printf("Using program directory for storage\n"); - iswritable = true; - return false; - } - if (!batchrun) Printf("Using known folders for storage\n"); - iswritable = false; - return true; -} - -//=========================================================================== -// -// GetKnownFolder -// -// Returns the known_folder if SHGetKnownFolderPath is available, otherwise -// returns the shell_folder using SHGetFolderPath. -// -//=========================================================================== - -bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path) -{ - PWSTR wpath; - if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) - { - return false; - } - path = wpath; - CoTaskMemFree(wpath); - return true; -} - -//=========================================================================== -// -// M_GetAppDataPath Windows -// -// Returns the path for the AppData folder. -// -//=========================================================================== - -FString M_GetAppDataPath(bool create) -{ - FString path; - - if (!GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create, path)) - { // Failed (e.g. On Win9x): use program directory - path = progdir; - } - // Don't use GAME_DIR and such so that ZDoom and its child ports can - // share the node cache. - path += "/" GAMENAMELOWERCASE; - path.Substitute("//", "/"); // needed because progdir ends with a slash. - if (create) - { - CreatePath(path); - } - return path; -} - -//=========================================================================== -// -// M_GetCachePath Windows -// -// Returns the path for cache GL nodes. -// -//=========================================================================== - -FString M_GetCachePath(bool create) -{ - FString path; - - if (!GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create, path)) - { // Failed (e.g. On Win9x): use program directory - path = progdir; - } - // Don't use GAME_DIR and such so that ZDoom and its child ports can - // share the node cache. - path += "/zdoom/cache"; - path.Substitute("//", "/"); // needed because progdir ends with a slash. - if (create) - { - CreatePath(path); - } - return path; -} - -//=========================================================================== -// -// M_GetAutoexecPath Windows -// -// Returns the expected location of autoexec.cfg. -// -//=========================================================================== - -FString M_GetAutoexecPath() -{ - return "$PROGDIR/autoexec.cfg"; -} - -//=========================================================================== -// -// M_GetCajunPath Windows -// -// Returns the location of the Cajun Bot definitions. -// -//=========================================================================== - -FString M_GetCajunPath(const char *botfilename) -{ - FString path; - - path << progdir << "zcajun/" << botfilename; - if (!FileExists(path)) - { - path = ""; - } - return path; -} - -//=========================================================================== -// -// M_GetConfigPath Windows -// -// Returns the path to the config file. On Windows, this can vary for reading -// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try -// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. -// -//=========================================================================== - -FString M_GetConfigPath(bool for_reading) -{ - FString path; - HRESULT hr; - - path.Format("%s" GAMENAME "_portable.ini", progdir.GetChars()); - if (FileExists(path)) - { - return path; - } - path = ""; - - // Construct a user-specific config name - if (UseKnownFolders() && GetKnownFolder(CSIDL_APPDATA, FOLDERID_RoamingAppData, true, path)) - { - path += "/" GAME_DIR; - CreatePath(path); - path += "/" GAMENAMELOWERCASE ".ini"; - } - else - { // construct "$PROGDIR/zdoom-$USER.ini" - TCHAR uname[UNLEN+1]; - DWORD unamelen = countof(uname); - - path = progdir; - hr = GetUserName(uname, &unamelen); - if (SUCCEEDED(hr) && uname[0] != 0) - { - // Is it valid for a user name to have slashes? - // Check for them and substitute just in case. - auto probe = uname; - while (*probe != 0) - { - if (*probe == '\\' || *probe == '/') - *probe = '_'; - ++probe; - } - path << GAMENAMELOWERCASE "-" << FString(uname) << ".ini"; - } - else - { // Couldn't get user name, so just use zdoom.ini - path += GAMENAMELOWERCASE ".ini"; - } - } - - // If we are reading the config file, check if it exists. If not, fallback - // to $PROGDIR/zdoom.ini - if (for_reading) - { - if (!FileExists(path)) - { - path = progdir; - path << GAMENAMELOWERCASE ".ini"; - } - } - - return path; -} - -//=========================================================================== -// -// M_GetScreenshotsPath Windows -// -// Returns the path to the default screenshots directory. -// -//=========================================================================== - -// I'm not sure when FOLDERID_Screenshots was added, but it was probably -// for Windows 8, since it's not in the v7.0 Windows SDK. -static const GUID MyFOLDERID_Screenshots = { 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f }; - -FString M_GetScreenshotsPath() -{ - FString path; - - if (!UseKnownFolders()) - { - return progdir; - } - else if (GetKnownFolder(-1, MyFOLDERID_Screenshots, true, path)) - { - path << "/" GAMENAME; - } - else if (GetKnownFolder(CSIDL_MYPICTURES, FOLDERID_Pictures, true, path)) - { - path << "/Screenshots/" GAMENAME; - } - else - { - return progdir; - } - CreatePath(path); - return path; -} - -//=========================================================================== -// -// M_GetSavegamesPath Windows -// -// Returns the path to the default save games directory. -// -//=========================================================================== - -FString M_GetSavegamesPath() -{ - FString path; - - if (!UseKnownFolders()) - { - return progdir; - } - // Try standard Saved Games folder - else if (GetKnownFolder(-1, FOLDERID_SavedGames, true, path)) - { - path << "/" GAMENAME; - } - // Try defacto My Documents/My Games folder - else if (GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true, path)) - { - // I assume since this isn't a standard folder, it doesn't have - // a localized name either. - path << "/My Games/" GAMENAME; - CreatePath(path); - } - else - { - path = progdir; - } - return path; -} - -//=========================================================================== -// -// M_GetDocumentsPath Windows -// -// Returns the path to the default documents directory. -// -//=========================================================================== - -FString M_GetDocumentsPath() -{ - FString path; - - // A portable INI means that this storage location should also be portable. - path.Format("%s" GAMENAME "_portable.ini", progdir.GetChars()); - if (FileExists(path)) - { - return progdir; - } - - if (!UseKnownFolders()) - { - return progdir; - } - // Try defacto My Documents/My Games folder - else if (GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true, path)) - { - // I assume since this isn't a standard folder, it doesn't have - // a localized name either. - path << "/My Games/" GAMENAME; - CreatePath(path); - } - else - { - path = progdir; - } - return path; -} diff --git a/src/win32/i_steam.cpp b/src/win32/i_steam.cpp new file mode 100644 index 00000000000..2cc76ab663c --- /dev/null +++ b/src/win32/i_steam.cpp @@ -0,0 +1,413 @@ +/* +** i_system.cpp +** Timers, pre-console output, IWAD selection, and misc system routines. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright (C) 2007-2012 Skulltag Development Team +** Copyright (C) 2007-2016 Zandronum Development Team +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. Redistributions in any form must be accompanied by information on how to +** obtain complete source code for the software and any accompanying software +** that uses the software. The source code must either be included in the +** distribution or be available for no more than the cost of distribution plus +** a nominal fee, and must be freely redistributable under reasonable +** conditions. For an executable file, complete source code means the source +** code for all modules it contains. It does not include source code for +** modules or files that typically accompany the major components of the +** operating system on which the executable file runs. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include +#include +#include + +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include + +#include "printf.h" + +#include "engineerrors.h" +#include "version.h" +#include "i_sound.h" +#include "stats.h" +#include "v_text.h" +#include "utf8.h" + +#include "d_main.h" +#include "d_net.h" +#include "g_game.h" +#include "c_dispatch.h" + +#include "gameconfigfile.h" +#include "v_font.h" +#include "g_level.h" +#include "doomstat.h" +#include "bitmap.h" +#include "cmdlib.h" +#include "i_interface.h" + + +//TODO maybe move this code to a separate cpp file, so that there isn't code duplication between the win32 and posix backends +static void PSR_FindEndBlock(FScanner &sc) +{ + int depth = 1; + do + { + if(sc.CheckToken('}')) + --depth; + else if(sc.CheckToken('{')) + ++depth; + else + sc.MustGetAnyToken(); + } + while(depth); +} + +static TArray ParseSteamRegistry(const char* path) +{ + TArray result; + FScanner sc; + if (sc.OpenFile(path)) + { + sc.SetCMode(true); + + sc.MustGetToken(TK_StringConst); + sc.MustGetToken('{'); + // Get a list of possible install directories. + while(sc.GetToken() && sc.TokenType != '}') + { + sc.TokenMustBe(TK_StringConst); + sc.MustGetToken('{'); + + while(sc.GetToken() && sc.TokenType != '}') + { + sc.TokenMustBe(TK_StringConst); + FString key(sc.String); + if(key.CompareNoCase("path") == 0) + { + sc.MustGetToken(TK_StringConst); + result.Push(FString(sc.String) + "/steamapps/common"); + PSR_FindEndBlock(sc); + break; + } + else if(sc.CheckToken('{')) + { + PSR_FindEndBlock(sc); + } + else + { + sc.MustGetToken(TK_StringConst); + } + } + } + } + return result; +} + +//========================================================================== +// +// QueryPathKey +// +// Returns the value of a registry key into the output variable value. +// +//========================================================================== + +static bool QueryPathKey(HKEY key, const wchar_t *keypath, const wchar_t *valname, FString &value) +{ + HKEY pathkey; + DWORD pathtype; + DWORD pathlen; + LONG res; + + value = ""; + if(ERROR_SUCCESS == RegOpenKeyEx(key, keypath, 0, KEY_QUERY_VALUE, &pathkey)) + { + if (ERROR_SUCCESS == RegQueryValueEx(pathkey, valname, 0, &pathtype, NULL, &pathlen) && + pathtype == REG_SZ && pathlen != 0) + { + // Don't include terminating null in count + TArray chars(pathlen + 1, true); + res = RegQueryValueEx(pathkey, valname, 0, NULL, (LPBYTE)chars.Data(), &pathlen); + if (res == ERROR_SUCCESS) value = FString(chars.Data()); + } + RegCloseKey(pathkey); + } + return value.IsNotEmpty(); +} + +//========================================================================== +// +// I_GetGogPaths +// +// Check the registry for GOG installation paths, so we can search for IWADs +// that were bought from GOG.com. This is a bit different from the Steam +// version because each game has its own independent installation path, no +// such thing as /SteamApps/common/. +// +//========================================================================== + +TArray I_GetGogPaths() +{ + TArray result; + FString path; + std::wstring gamepath; + +#ifdef _WIN64 + std::wstring gogregistrypath = L"Software\\Wow6432Node\\GOG.com\\Games"; +#else + // If a 32-bit ZDoom runs on a 64-bit Windows, this will be transparently and + // automatically redirected to the Wow6432Node address instead, so this address + // should be safe to use in all cases. + std::wstring gogregistrypath = L"Software\\GOG.com\\Games"; +#endif + + // Look for Ultimate Doom + gamepath = gogregistrypath + L"\\1435827232"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path); // directly in install folder + } + + // Look for Doom I Enhanced + gamepath = gogregistrypath + L"\\2015545325"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path + "/DOOM_Data/StreamingAssets"); // in a subdirectory + } + + // Look for Doom II + gamepath = gogregistrypath + L"\\1435848814"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path + "/doom2"); // in a subdirectory + // If direct support for the Master Levels is ever added, they are in path + /master/wads + } + + // Look for Doom II Enhanced + gamepath = gogregistrypath + L"\\1426071866"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path + "/DOOM II_Data/StreamingAssets"); // in a subdirectory + } + + // Look for Doom + Doom II + gamepath = gogregistrypath + L"\\1413291984"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path); // directly in install folder + } + + // Look for Final Doom + gamepath = gogregistrypath + L"\\1435848742"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + // in subdirectories + result.Push(path + "/TNT"); + result.Push(path + "/Plutonia"); + } + + // Look for Doom 3: BFG Edition + gamepath = gogregistrypath + L"\\1135892318"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path + "/base/wads"); // in a subdirectory + } + + // Look for Strife: Veteran Edition + gamepath = gogregistrypath + L"\\1432899949"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path); // directly in install folder + } + + // Look for Heretic: SOTSR + gamepath = gogregistrypath + L"\\1290366318"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path); // directly in install folder + } + + // Look for Hexen: Beyond Heretic + gamepath = gogregistrypath + L"\\1247951670"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path); // directly in install folder + } + + // Look for Hexen: Death Kings + gamepath = gogregistrypath + L"\\1983497091"; + if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) + { + result.Push(path); // directly in install folder + } + + return result; +} + +//========================================================================== +// +// I_GetSteamPath +// +// Check the registry for the path to Steam, so that we can search for +// IWADs that were bought with Steam. +// +//========================================================================== + +TArray I_GetSteamPath() +{ + TArray result; + static const char *const steam_dirs[] = + { + "doom 2/base", + "final doom/base", + "heretic shadow of the serpent riders/base", + "hexen/base", + "hexen deathkings of the dark citadel/base", + "ultimate doom/base", + "ultimate doom/base/doom2", // 2024 Update + "ultimate doom/base/tnt", // 2024 Update + "ultimate doom/base/plutonia", // 2024 Update + "DOOM 3 BFG Edition/base/wads", + "Strife", + "Ultimate Doom/rerelease/DOOM_Data/StreamingAssets", // 2019 Unity port (previous-re-release branch in Doom + Doom II app) + "Ultimate Doom/rerelease", // 2024 KEX Port + "Doom 2/rerelease/DOOM II_Data/StreamingAssets", + "Doom 2/finaldoombase", + "Master Levels of Doom/doom2" + }; + + FString steamPath; + + if (!QueryPathKey(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", L"SteamPath", steamPath)) + { + if (!QueryPathKey(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", L"InstallPath", steamPath)) + return result; + } + + try + { + TArray paths = ParseSteamRegistry((steamPath + "/config/libraryfolders.vdf").GetChars()); + + for (FString& path : paths) + { + path.ReplaceChars('\\', '/'); + path += "/"; + } + + paths.Push(steamPath + "/steamapps/common/"); + + for (unsigned int i = 0; i < countof(steam_dirs); ++i) + { + for (const FString& path : paths) + { + result.Push(path + steam_dirs[i]); + } + } + } + catch (const CRecoverableError& err) + { + // don't abort on errors in here. Just return an empty path. + } + + return result; +} + +//========================================================================== +// +// I_GetBethesdaPath +// +// Check the registry for the path to the Bethesda.net Launcher, so that we +// can search for IWADs that were bought from Bethesda.net. +// +//========================================================================== + +TArray I_GetBethesdaPath() +{ + TArray result; + static const char* const bethesda_dirs[] = + { + "DOOM_Classic_2019/base", + "DOOM_Classic_2019/rerelease/DOOM_Data/StreamingAssets", + "DOOM_II_Classic_2019/base", + "DOOM_II_Classic_2019/rerelease/DOOM II_Data/StreamingAssets", + "DOOM 3 BFG Edition/base/wads", + "Heretic Shadow of the Serpent Riders/base", + "Hexen/base", + "Hexen Deathkings of the Dark Citadel/base" + + // Alternate DOS versions of Doom and Doom II (referred to as "Original" in the + // Bethesda Launcher). While the DOS versions that come with the Unity ports are + // unaltered, these use WADs from the European PSN versions. These WADs are currently + // misdetected by GZDoom: DOOM.WAD is detected as the Unity version (which it's not), + // while DOOM2.WAD is detected as the original DOS release despite having Doom 3: BFG + // Edition's censored secret level titles (albeit only in the title patches, not in + // the automap). Unfortunately, these WADs have exactly the same lump names as the WADs + // they're misdetected as, so it's not currently possible to distinguish them using + // GZDoom's current IWAD detection system. To prevent them from possibly overriding the + // real Unity DOOM.WAD and DOS DOOM2.WAD, these paths have been commented out. + //"Ultimate DOOM/base", + //"DOOM II/base", + + // Doom Eternal includes DOOM.WAD and DOOM2.WAD, but they're the same misdetected + // PSN versions used by the alternate DOS releases above. + //"Doom Eternal/base/classicwads" + }; + +#ifdef _WIN64 + const wchar_t *bethesdaregistrypath = L"Software\\Wow6432Node\\Bethesda Softworks\\Bethesda.net"; +#else + // If a 32-bit ZDoom runs on a 64-bit Windows, this will be transparently and + // automatically redirected to the Wow6432Node address instead, so this address + // should be safe to use in all cases. + const wchar_t *bethesdaregistrypath = L"Software\\Bethesda Softworks\\Bethesda.net"; +#endif + + FString path; + if (!QueryPathKey(HKEY_LOCAL_MACHINE, bethesdaregistrypath, L"installLocation", path)) + { + return result; + } + path += "/games/"; + + for (unsigned int i = 0; i < countof(bethesda_dirs); ++i) + { + result.Push(path + bethesda_dirs[i]); + } + + return result; +} diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp deleted file mode 100644 index 9361e76586e..00000000000 --- a/src/win32/i_system.cpp +++ /dev/null @@ -1,1334 +0,0 @@ -/* -** i_system.cpp -** Timers, pre-console output, IWAD selection, and misc system routines. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** Copyright (C) 2007-2012 Skulltag Development Team -** Copyright (C) 2007-2016 Zandronum Development Team -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** 4. Redistributions in any form must be accompanied by information on how to -** obtain complete source code for the software and any accompanying software -** that uses the software. The source code must either be included in the -** distribution or be available for no more than the cost of distribution plus -** a nominal fee, and must be freely redistributable under reasonable -** conditions. For an executable file, complete source code means the source -** code for all modules it contains. It does not include source code for -** modules or files that typically accompany the major components of the -** operating system on which the executable file runs. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include -#include -#include - -#include - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include - -#include "hardware.h" -#include "doomerrors.h" - -#include "version.h" -#include "m_misc.h" -#include "i_sound.h" -#include "resource.h" -#include "x86.h" -#include "stats.h" -#include "v_text.h" -#include "utf8.h" - -#include "d_main.h" -#include "d_net.h" -#include "g_game.h" -#include "i_input.h" -#include "c_dispatch.h" -#include "templates.h" -#include "gameconfigfile.h" -#include "v_font.h" -#include "g_level.h" -#include "doomstat.h" -#include "i_system.h" -#include "textures/bitmap.h" - -// MACROS ------------------------------------------------------------------ - -#ifdef _MSC_VER -// Turn off "conversion from 'LONG_PTR' to 'LONG', possible loss of data" -// generated by SetClassLongPtr(). -#pragma warning(disable:4244) -#endif - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -extern void CheckCPUID(CPUInfo *cpu); -extern void LayoutMainWindow(HWND hWnd, HWND pane); - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void DestroyCustomCursor(); - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static void CalculateCPUSpeed(); - -static HCURSOR CreateCompatibleCursor(FBitmap &cursorpic, int leftofs, int topofs); -static HCURSOR CreateAlphaCursor(FBitmap &cursorpic, int leftofs, int topofs); -static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP color_mask); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -EXTERN_CVAR (Bool, queryiwad); -// Used on welcome/IWAD screen. -EXTERN_CVAR (Bool, disableautoload) -EXTERN_CVAR (Bool, autoloadlights) -EXTERN_CVAR (Bool, autoloadbrightmaps) -EXTERN_CVAR (Int, vid_preferbackend) - -extern HWND Window, ConWindow, GameTitleWindow; -extern HANDLE StdOut; -extern bool FancyStdOut; -extern HINSTANCE g_hInst; -extern FILE *Logfile; -extern bool NativeMouse; -extern bool ConWindowHidden; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -CVAR (String, queryiwad_key, "shift", CVAR_GLOBALCONFIG|CVAR_ARCHIVE); -CVAR (Bool, con_debugoutput, false, 0); - -double PerfToSec, PerfToMillisec; - -UINT TimerPeriod; - -int sys_ostype = 0; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static ticcmd_t emptycmd; - -static WadStuff *WadList; -static int NumWads; -static int DefaultWad; - -static HCURSOR CustomCursor; - -//========================================================================== -// -// I_Tactile -// -// Doom calls it when you take damage, so presumably it could be converted -// to something compatible with force feedback. -// -//========================================================================== - -void I_Tactile(int on, int off, int total) -{ - // UNUSED. - on = off = total = 0; -} - -//========================================================================== -// -// I_BaseTiccmd -// -// Returns an empty ticcmd. I have no idea why this should be system- -// specific. -// -//========================================================================== - -ticcmd_t *I_BaseTiccmd() -{ - return &emptycmd; -} - -//========================================================================== -// -// I_DetectOS -// -// Determine which version of Windows the game is running on. -// -//========================================================================== - -void I_DetectOS(void) -{ - OSVERSIONINFOEX info; - const char *osname; - - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - if (!GetVersionEx((OSVERSIONINFO *)&info)) - { - // Retry with the older OSVERSIONINFO structure. - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx((OSVERSIONINFO *)&info); - } - - switch (info.dwPlatformId) - { - case VER_PLATFORM_WIN32_NT: - osname = "NT"; - if (info.dwMajorVersion == 6) - { - if (info.dwMinorVersion == 0) - { - osname = (info.wProductType == VER_NT_WORKSTATION) ? "Vista" : "Server 2008"; - sys_ostype = 2; // legacy OS - } - else if (info.dwMinorVersion == 1) - { - osname = (info.wProductType == VER_NT_WORKSTATION) ? "7" : "Server 2008 R2"; - sys_ostype = 2; // supported OS - } - else if (info.dwMinorVersion == 2) - { - // Starting with Windows 8.1, you need to specify in your manifest - // the highest version of Windows you support, which will also be the - // highest version of Windows this function returns. - osname = (info.wProductType == VER_NT_WORKSTATION) ? "8" : "Server 2012"; - sys_ostype = 2; // supported OS - } - else if (info.dwMinorVersion == 3) - { - osname = (info.wProductType == VER_NT_WORKSTATION) ? "8.1" : "Server 2012 R2"; - sys_ostype = 2; // supported OS - } - else if (info.dwMinorVersion == 4) - { - osname = (info.wProductType == VER_NT_WORKSTATION) ? "10 (beta)" : "Server 2016 (beta)"; - } - } - else if (info.dwMajorVersion == 10) - { - osname = (info.wProductType == VER_NT_WORKSTATION) ? "10 (or higher)" : "Server 2016 (or higher)"; - sys_ostype = 3; // modern OS - } - break; - - default: - osname = "Unknown OS"; - break; - } - - if (!batchrun) Printf ("OS: Windows %s (NT %lu.%lu) Build %lu\n %s\n", - osname, - info.dwMajorVersion, info.dwMinorVersion, - info.dwBuildNumber, info.szCSDVersion); -} - -//========================================================================== -// -// CalculateCPUSpeed -// -// Make a decent guess at how much time elapses between TSC steps. This can -// vary over runtime depending on power management settings, so should not -// be used anywhere that truely accurate timing actually matters. -// -//========================================================================== - -void CalculateCPUSpeed() -{ - LARGE_INTEGER freq; - - QueryPerformanceFrequency (&freq); - - if (freq.QuadPart != 0) - { - LARGE_INTEGER count1, count2; - cycle_t ClockCalibration; - DWORD min_diff; - - ClockCalibration.Reset(); - - // Count cycles for at least 55 milliseconds. - // The performance counter may be very low resolution compared to CPU - // speeds today, so the longer we count, the more accurate our estimate. - // On the other hand, we don't want to count too long, because we don't - // want the user to notice us spend time here, since most users will - // probably never use the performance statistics. - min_diff = freq.LowPart * 11 / 200; - - // Minimize the chance of task switching during the testing by going very - // high priority. This is another reason to avoid timing for too long. - SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - - // Make sure we start timing on a counter boundary. - QueryPerformanceCounter(&count1); - do { QueryPerformanceCounter(&count2); } while (count1.QuadPart == count2.QuadPart); - - // Do the timing loop. - ClockCalibration.Clock(); - do { QueryPerformanceCounter(&count1); } while ((count1.QuadPart - count2.QuadPart) < min_diff); - ClockCalibration.Unclock(); - - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); - - PerfToSec = double(count1.QuadPart - count2.QuadPart) / (double(ClockCalibration.GetRawCounter()) * freq.QuadPart); - PerfToMillisec = PerfToSec * 1000.0; - } - - if (!batchrun) Printf ("CPU speed: %.0f MHz\n", 0.001 / PerfToMillisec); -} - -//========================================================================== -// -// I_Init -// -//========================================================================== - -void I_Init() -{ - CheckCPUID(&CPU); - CalculateCPUSpeed(); - DumpCPUInfo(&CPU); -} - - -//========================================================================== -// -// I_PrintStr -// -// Send output to the list box shown during startup (and hidden during -// gameplay). -// -//========================================================================== - -static void DoPrintStr(const char *cpt, HWND edit, HANDLE StdOut) -{ - if (edit == nullptr && StdOut == nullptr && !con_debugoutput) - return; - - wchar_t wbuf[256]; - int bpos = 0; - CHARRANGE selection; - CHARRANGE endselection; - LONG lines_before = 0, lines_after; - CHARFORMAT format; - - if (edit != NULL) - { - // Store the current selection and set it to the end so we can append text. - SendMessage(edit, EM_EXGETSEL, 0, (LPARAM)&selection); - endselection.cpMax = endselection.cpMin = GetWindowTextLength(edit); - SendMessage(edit, EM_EXSETSEL, 0, (LPARAM)&endselection); - - // GetWindowTextLength and EM_EXSETSEL can disagree on where the end of - // the text is. Find out what EM_EXSETSEL thought it was and use that later. - SendMessage(edit, EM_EXGETSEL, 0, (LPARAM)&endselection); - - // Remember how many lines there were before we added text. - lines_before = (LONG)SendMessage(edit, EM_GETLINECOUNT, 0, 0); - } - - const uint8_t *cptr = (const uint8_t*)cpt; - - auto outputIt = [&]() - { - wbuf[bpos] = 0; - if (edit != nullptr) - { - SendMessageW(edit, EM_REPLACESEL, FALSE, (LPARAM)wbuf); - } - if (con_debugoutput) - { - OutputDebugStringW(wbuf); - } - if (StdOut != nullptr) - { - // Convert back to UTF-8. - DWORD bytes_written; - if (!FancyStdOut) - { - FString conout(wbuf); - WriteFile(StdOut, conout.GetChars(), (DWORD)conout.Len(), &bytes_written, NULL); - } - else - { - WriteConsoleW(StdOut, wbuf, bpos, &bytes_written, nullptr); - } - } - bpos = 0; - }; - - while (int chr = GetCharFromString(cptr)) - { - if ((chr == TEXTCOLOR_ESCAPE && bpos != 0) || bpos == 255) - { - outputIt(); - } - if (chr != TEXTCOLOR_ESCAPE) - { - if (chr >= 0x1D && chr <= 0x1F) - { // The bar characters, most commonly used to indicate map changes - chr = 0x2550; // Box Drawings Double Horizontal - } - wbuf[bpos++] = chr; - } - else - { - EColorRange range = V_ParseFontColor(cptr, CR_UNTRANSLATED, CR_YELLOW); - - if (range != CR_UNDEFINED) - { - // Change the color of future text added to the control. - PalEntry color = V_LogColorFromColorRange(range); - if (StdOut != NULL && FancyStdOut) - { - // Unfortunately, we are pretty limited here: There are only - // eight basic colors, and each comes in a dark and a bright - // variety. - float h, s, v, r, g, b; - int attrib = 0; - - RGBtoHSV(color.r / 255.f, color.g / 255.f, color.b / 255.f, &h, &s, &v); - if (s != 0) - { // color - HSVtoRGB(&r, &g, &b, h, 1, 1); - if (r == 1) attrib = FOREGROUND_RED; - if (g == 1) attrib |= FOREGROUND_GREEN; - if (b == 1) attrib |= FOREGROUND_BLUE; - if (v > 0.6) attrib |= FOREGROUND_INTENSITY; - } - else - { // gray - if (v < 0.33) attrib = FOREGROUND_INTENSITY; - else if (v < 0.90) attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - else attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; - } - SetConsoleTextAttribute(StdOut, (WORD)attrib); - } - if (edit != NULL) - { - // GDI uses BGR colors, but color is RGB, so swap the R and the B. - swapvalues(color.r, color.b); - // Change the color. - format.cbSize = sizeof(format); - format.dwMask = CFM_COLOR; - format.dwEffects = 0; - format.crTextColor = color; - SendMessage(edit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); - } - } - } - } - if (bpos != 0) - { - outputIt(); - } - - if (edit != NULL) - { - // If the old selection was at the end of the text, keep it at the end and - // scroll. Don't scroll if the selection is anywhere else. - if (selection.cpMin == endselection.cpMin && selection.cpMax == endselection.cpMax) - { - selection.cpMax = selection.cpMin = GetWindowTextLength (edit); - lines_after = (LONG)SendMessage(edit, EM_GETLINECOUNT, 0, 0); - if (lines_after > lines_before) - { - SendMessage(edit, EM_LINESCROLL, 0, lines_after - lines_before); - } - } - // Restore the previous selection. - SendMessage(edit, EM_EXSETSEL, 0, (LPARAM)&selection); - // Give the edit control a chance to redraw itself. - I_GetEvent(); - } - if (StdOut != NULL && FancyStdOut) - { // Set text back to gray, in case it was changed. - SetConsoleTextAttribute(StdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); - } -} - -static TArray bufferedConsoleStuff; - -void I_DebugPrint(const char *cp) -{ - if (IsDebuggerPresent()) - { - auto wstr = WideString(cp); - OutputDebugStringW(wstr.c_str()); - } -} - -void I_PrintStr(const char *cp) -{ - if (ConWindowHidden) - { - bufferedConsoleStuff.Push(cp); - DoPrintStr(cp, NULL, StdOut); - } - else - { - DoPrintStr(cp, ConWindow, StdOut); - } -} - -void I_FlushBufferedConsoleStuff() -{ - for (unsigned i = 0; i < bufferedConsoleStuff.Size(); i++) - { - DoPrintStr(bufferedConsoleStuff[i], ConWindow, NULL); - } - bufferedConsoleStuff.Clear(); -} - -//========================================================================== -// -// SetQueryIWAD -// -// The user had the "Don't ask again" box checked when they closed the -// IWAD selection dialog. -// -//========================================================================== - -static void SetQueryIWad(HWND dialog) -{ - HWND checkbox = GetDlgItem(dialog, IDC_DONTASKIWAD); - int state = (int)SendMessage(checkbox, BM_GETCHECK, 0, 0); - bool query = (state != BST_CHECKED); - - if (!query && queryiwad) - { - MessageBoxA(dialog, - "You have chosen not to show this dialog box in the future.\n" - "If you wish to see it again, hold down SHIFT while starting " GAMENAME ".", - "Don't ask me this again", - MB_OK | MB_ICONINFORMATION); - } - - queryiwad = query; -} - -//========================================================================== -// -// IWADBoxCallback -// -// Dialog proc for the IWAD selector. -// -//========================================================================== - -BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND ctrl; - int i; - - switch (message) - { - case WM_INITDIALOG: - // Add our program name to the window title - { - WCHAR label[256]; - FString newlabel; - - GetWindowTextW(hDlg, label, countof(label)); - FString alabel(label); - newlabel.Format(GAMENAME " %s: %s", GetVersionString(), alabel.GetChars()); - auto wlabel = newlabel.WideString(); - SetWindowTextW(hDlg, wlabel.c_str()); - } - - // [SP] Upstreamed from Zandronum - char szString[256]; - - // Check the current video settings. - //SendDlgItemMessage( hDlg, vid_renderer ? IDC_WELCOME_OPENGL : IDC_WELCOME_SOFTWARE, BM_SETCHECK, BST_CHECKED, 0 ); - SendDlgItemMessage( hDlg, IDC_WELCOME_FULLSCREEN, BM_SETCHECK, fullscreen ? BST_CHECKED : BST_UNCHECKED, 0 ); - switch (vid_preferbackend) - { - case 1: - SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN2, BM_SETCHECK, BST_CHECKED, 0 ); - break; - case 2: - SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN3, BM_SETCHECK, BST_CHECKED, 0 ); - break; - default: - SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN1, BM_SETCHECK, BST_CHECKED, 0 ); - break; - } - - - // [SP] This is our's - SendDlgItemMessage( hDlg, IDC_WELCOME_NOAUTOLOAD, BM_SETCHECK, disableautoload ? BST_CHECKED : BST_UNCHECKED, 0 ); - SendDlgItemMessage( hDlg, IDC_WELCOME_LIGHTS, BM_SETCHECK, autoloadlights ? BST_CHECKED : BST_UNCHECKED, 0 ); - SendDlgItemMessage( hDlg, IDC_WELCOME_BRIGHTMAPS, BM_SETCHECK, autoloadbrightmaps ? BST_CHECKED : BST_UNCHECKED, 0 ); - - // Set up our version string. - sprintf(szString, "Version %s.", GetVersionString()); - SetDlgItemTextA (hDlg, IDC_WELCOME_VERSION, szString); - - // Populate the list with all the IWADs found - ctrl = GetDlgItem(hDlg, IDC_IWADLIST); - for (i = 0; i < NumWads; i++) - { - const char *filepart = strrchr(WadList[i].Path, '/'); - if (filepart == NULL) - filepart = WadList[i].Path; - else - filepart++; - FStringf work("%s (%s)", WadList[i].Name.GetChars(), filepart); - std::wstring wide = work.WideString(); - SendMessage(ctrl, LB_ADDSTRING, 0, (LPARAM)wide.c_str()); - SendMessage(ctrl, LB_SETITEMDATA, i, (LPARAM)i); - } - SendMessage(ctrl, LB_SETCURSEL, DefaultWad, 0); - SetFocus(ctrl); - // Set the state of the "Don't ask me again" checkbox - ctrl = GetDlgItem(hDlg, IDC_DONTASKIWAD); - SendMessage(ctrl, BM_SETCHECK, queryiwad ? BST_UNCHECKED : BST_CHECKED, 0); - // Make sure the dialog is in front. If SHIFT was pressed to force it visible, - // then the other window will normally be on top. - SetForegroundWindow(hDlg); - break; - - case WM_COMMAND: - if (LOWORD(wParam) == IDCANCEL) - { - EndDialog (hDlg, -1); - } - else if (LOWORD(wParam) == IDOK || - (LOWORD(wParam) == IDC_IWADLIST && HIWORD(wParam) == LBN_DBLCLK)) - { - SetQueryIWad(hDlg); - // [SP] Upstreamed from Zandronum - fullscreen = SendDlgItemMessage( hDlg, IDC_WELCOME_FULLSCREEN, BM_GETCHECK, 0, 0 ) == BST_CHECKED; - if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN3, BM_GETCHECK, 0, 0) == BST_CHECKED) - vid_preferbackend = 2; - else if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN2, BM_GETCHECK, 0, 0) == BST_CHECKED) - vid_preferbackend = 1; - else if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN1, BM_GETCHECK, 0, 0) == BST_CHECKED) - vid_preferbackend = 0; - - // [SP] This is our's. - disableautoload = SendDlgItemMessage( hDlg, IDC_WELCOME_NOAUTOLOAD, BM_GETCHECK, 0, 0 ) == BST_CHECKED; - autoloadlights = SendDlgItemMessage( hDlg, IDC_WELCOME_LIGHTS, BM_GETCHECK, 0, 0 ) == BST_CHECKED; - autoloadbrightmaps = SendDlgItemMessage( hDlg, IDC_WELCOME_BRIGHTMAPS, BM_GETCHECK, 0, 0 ) == BST_CHECKED; - ctrl = GetDlgItem (hDlg, IDC_IWADLIST); - EndDialog(hDlg, SendMessage (ctrl, LB_GETCURSEL, 0, 0)); - } - break; - } - return FALSE; -} - -//========================================================================== -// -// I_PickIWad -// -// Open a dialog to pick the IWAD, if there is more than one found. -// -//========================================================================== - -int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad) -{ - int vkey; - - if (stricmp(queryiwad_key, "shift") == 0) - { - vkey = VK_SHIFT; - } - else if (stricmp(queryiwad_key, "control") == 0 || stricmp (queryiwad_key, "ctrl") == 0) - { - vkey = VK_CONTROL; - } - else - { - vkey = 0; - } - if (showwin || (vkey != 0 && GetAsyncKeyState(vkey))) - { - WadList = wads; - NumWads = numwads; - DefaultWad = defaultiwad; - - return (int)DialogBox(g_hInst, MAKEINTRESOURCE(IDD_IWADDIALOG), - (HWND)Window, (DLGPROC)IWADBoxCallback); - } - return defaultiwad; -} - -//========================================================================== -// -// I_SetCursor -// -// Returns true if the cursor was successfully changed. -// -//========================================================================== - -bool I_SetCursor(FTexture *cursorpic) -{ - HCURSOR cursor; - - if (cursorpic != NULL && cursorpic->isValid()) - { - auto image = cursorpic->GetBgraBitmap(nullptr); - // Must be no larger than 32x32. (is this still necessary? - if (image.GetWidth() > 32 || image.GetHeight() > 32) - { - return false; - } - // Fixme: This should get a raw image, not a texture. (Once raw images get implemented.) - int lo = cursorpic->GetDisplayLeftOffset(); - int to = cursorpic->GetDisplayTopOffset(); - - cursor = CreateAlphaCursor(image, lo, to); - if (cursor == NULL) - { - cursor = CreateCompatibleCursor(image, lo, to); - } - if (cursor == NULL) - { - return false; - } - // Replace the existing cursor with the new one. - DestroyCustomCursor(); - CustomCursor = cursor; - } - else - { - DestroyCustomCursor(); - cursor = LoadCursor(NULL, IDC_ARROW); - } - SetClassLongPtr(Window, GCLP_HCURSOR, (LONG_PTR)cursor); - if (NativeMouse) - { - POINT pt; - RECT client; - - // If the mouse pointer is within the window's client rect, set it now. - if (GetCursorPos(&pt) && GetClientRect(Window, &client) && - ClientToScreen(Window, (LPPOINT)&client.left) && - ClientToScreen(Window, (LPPOINT)&client.right)) - { - if (pt.x >= client.left && pt.x < client.right && - pt.y >= client.top && pt.y < client.bottom) - { - SetCursor(cursor); - } - } - } - return true; -} - -//========================================================================== -// -// CreateCompatibleCursor -// -// Creates a cursor with a 1-bit alpha channel. -// -//========================================================================== - -static HCURSOR CreateCompatibleCursor(FBitmap &bmp, int leftofs, int topofs) -{ - int picwidth = bmp.GetWidth(); - int picheight = bmp.GetHeight(); - - // Create bitmap masks for the cursor from the texture. - HDC dc = GetDC(NULL); - if (dc == NULL) - { - return nullptr; - } - HDC and_mask_dc = CreateCompatibleDC(dc); - HDC xor_mask_dc = CreateCompatibleDC(dc); - HBITMAP and_mask = CreateCompatibleBitmap(dc, 32, 32); - HBITMAP xor_mask = CreateCompatibleBitmap(dc, 32, 32); - ReleaseDC(NULL, dc); - - SelectObject(and_mask_dc, and_mask); - SelectObject(xor_mask_dc, xor_mask); - - // Initialize with an invisible cursor. - SelectObject(and_mask_dc, GetStockObject(WHITE_PEN)); - SelectObject(and_mask_dc, GetStockObject(WHITE_BRUSH)); - Rectangle(and_mask_dc, 0, 0, 32, 32); - SelectObject(xor_mask_dc, GetStockObject(BLACK_PEN)); - SelectObject(xor_mask_dc, GetStockObject(BLACK_BRUSH)); - Rectangle(xor_mask_dc, 0, 0, 32, 32); - - const uint8_t *pixels = bmp.GetPixels(); - - // Copy color data from the source texture to the cursor bitmaps. - for (int y = 0; y < picheight; ++y) - { - for (int x = 0; x < picwidth; ++x) - { - const uint8_t *bgra = &pixels[x*4 + y*bmp.GetPitch()]; - if (bgra[3] != 0) - { - SetPixelV(and_mask_dc, x, y, RGB(0,0,0)); - SetPixelV(xor_mask_dc, x, y, RGB(bgra[2], bgra[1], bgra[0])); - } - } - } - DeleteDC(and_mask_dc); - DeleteDC(xor_mask_dc); - - // Create the cursor from the bitmaps. - return CreateBitmapCursor(leftofs, topofs, and_mask, xor_mask); -} - -//========================================================================== -// -// CreateAlphaCursor -// -// Creates a cursor with a full alpha channel. -// -//========================================================================== - -static HCURSOR CreateAlphaCursor(FBitmap &source, int leftofs, int topofs) -{ - HDC dc; - BITMAPV5HEADER bi; - HBITMAP color, mono; - void *bits; - - // Find closest integer scale factor for the monitor DPI - HDC screenDC = GetDC(0); - int dpi = GetDeviceCaps(screenDC, LOGPIXELSX); - int scale = MAX((dpi + 96 / 2 - 1) / 96, 1); - ReleaseDC(0, screenDC); - - memset(&bi, 0, sizeof(bi)); - bi.bV5Size = sizeof(bi); - bi.bV5Width = 32 * scale; - bi.bV5Height = 32 * scale; - bi.bV5Planes = 1; - bi.bV5BitCount = 32; - bi.bV5Compression = BI_BITFIELDS; - bi.bV5RedMask = 0x00FF0000; - bi.bV5GreenMask = 0x0000FF00; - bi.bV5BlueMask = 0x000000FF; - bi.bV5AlphaMask = 0xFF000000; - - dc = GetDC(NULL); - if (dc == NULL) - { - return NULL; - } - - // Create the DIB section with an alpha channel. - color = CreateDIBSection(dc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, &bits, NULL, 0); - ReleaseDC(NULL, dc); - - if (color == NULL) - { - return NULL; - } - - // Create an empty mask bitmap, since CreateIconIndirect requires this. - mono = CreateBitmap(32 * scale, 32 * scale, 1, 1, NULL); - if (mono == NULL) - { - DeleteObject(color); - return NULL; - } - - // Copy cursor to the color bitmap. Note that GDI bitmaps are upside down compared - // to normal conventions, so we create the FBitmap pointing at the last row and use - // a negative pitch so that Blit will use GDI's orientation. - if (scale == 1) - { - FBitmap bmp((uint8_t *)bits + 31 * 32 * 4, -32 * 4, 32, 32); - bmp.Blit(0, 0, source); - } - else - { - TArray unscaled; - unscaled.Resize(32 * 32); - for (int i = 0; i < 32 * 32; i++) unscaled[i] = 0; - FBitmap bmp((uint8_t *)&unscaled[0] + 31 * 32 * 4, -32 * 4, 32, 32); - bmp.Blit(0, 0, source); - uint32_t *scaled = (uint32_t*)bits; - for (int y = 0; y < 32 * scale; y++) - { - for (int x = 0; x < 32 * scale; x++) - { - scaled[x + y * 32 * scale] = unscaled[x / scale + y / scale * 32]; - } - } - } - - return CreateBitmapCursor(leftofs * scale, topofs * scale, mono, color); -} - -//========================================================================== -// -// CreateBitmapCursor -// -// Create the cursor from the bitmaps. Deletes the bitmaps before returning. -// -//========================================================================== - -static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP color_mask) -{ - ICONINFO iconinfo = - { - FALSE, // fIcon - (DWORD)xhot, // xHotspot - (DWORD)yhot, // yHotspot - and_mask, // hbmMask - color_mask // hbmColor - }; - HCURSOR cursor = CreateIconIndirect(&iconinfo); - - // Delete the bitmaps. - DeleteObject(and_mask); - DeleteObject(color_mask); - - return cursor; -} - -//========================================================================== -// -// DestroyCustomCursor -// -//========================================================================== - -void DestroyCustomCursor() -{ - if (CustomCursor != NULL) - { - DestroyCursor(CustomCursor); - CustomCursor = NULL; - } -} - -//========================================================================== -// -// I_WriteIniFailed -// -// Display a message when the config failed to save. -// -//========================================================================== - -bool I_WriteIniFailed() -{ - char *lpMsgBuf; - FString errortext; - - FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPSTR)&lpMsgBuf, - 0, - NULL - ); - errortext.Format ("The config file %s could not be written:\n%s", GameConfig->GetPathName(), lpMsgBuf); - LocalFree (lpMsgBuf); - return MessageBoxA(Window, errortext.GetChars(), GAMENAME " configuration not saved", MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDRETRY; -} - -//========================================================================== -// -// I_FindFirst -// -// Start a pattern matching sequence. -// -//========================================================================== - - -void *I_FindFirst(const char *filespec, findstate_t *fileinfo) -{ - static_assert(sizeof(WIN32_FIND_DATAW) == sizeof(fileinfo->FindData), "Findata size mismatch"); - auto widespec = WideString(filespec); - fileinfo->UTF8Name = ""; - return FindFirstFileW(widespec.c_str(), (LPWIN32_FIND_DATAW)&fileinfo->FindData); -} - -//========================================================================== -// -// I_FindNext -// -// Return the next file in a pattern matching sequence. -// -//========================================================================== - -int I_FindNext(void *handle, findstate_t *fileinfo) -{ - fileinfo->UTF8Name = ""; - return !FindNextFileW((HANDLE)handle, (LPWIN32_FIND_DATAW)&fileinfo->FindData); -} - -//========================================================================== -// -// I_FindClose -// -// Finish a pattern matching sequence. -// -//========================================================================== - -int I_FindClose(void *handle) -{ - return FindClose((HANDLE)handle); -} - -//========================================================================== -// -// I_FindName -// -// Returns the name for an entry -// -//========================================================================== - -const char *I_FindName(findstate_t *fileinfo) -{ - if (fileinfo->UTF8Name.IsEmpty()) fileinfo->UTF8Name = fileinfo->FindData.Name; - return fileinfo->UTF8Name.GetChars(); -} - -//========================================================================== -// -// QueryPathKey -// -// Returns the value of a registry key into the output variable value. -// -//========================================================================== - -static bool QueryPathKey(HKEY key, const wchar_t *keypath, const wchar_t *valname, FString &value) -{ - HKEY pathkey; - DWORD pathtype; - DWORD pathlen; - LONG res; - - value = ""; - if(ERROR_SUCCESS == RegOpenKeyEx(key, keypath, 0, KEY_QUERY_VALUE, &pathkey)) - { - if (ERROR_SUCCESS == RegQueryValueEx(pathkey, valname, 0, &pathtype, NULL, &pathlen) && - pathtype == REG_SZ && pathlen != 0) - { - // Don't include terminating null in count - TArray chars(pathlen + 1, true); - res = RegQueryValueEx(pathkey, valname, 0, NULL, (LPBYTE)chars.Data(), &pathlen); - if (res == ERROR_SUCCESS) value = FString(chars.Data()); - } - RegCloseKey(pathkey); - } - return value.IsNotEmpty(); -} - -//========================================================================== -// -// I_GetGogPaths -// -// Check the registry for GOG installation paths, so we can search for IWADs -// that were bought from GOG.com. This is a bit different from the Steam -// version because each game has its own independent installation path, no -// such thing as /SteamApps/common/. -// -//========================================================================== - -TArray I_GetGogPaths() -{ - TArray result; - FString path; - std::wstring gamepath; - -#ifdef _WIN64 - std::wstring gogregistrypath = L"Software\\Wow6432Node\\GOG.com\\Games"; -#else - // If a 32-bit ZDoom runs on a 64-bit Windows, this will be transparently and - // automatically redirected to the Wow6432Node address instead, so this address - // should be safe to use in all cases. - std::wstring gogregistrypath = L"Software\\GOG.com\\Games"; -#endif - - // Look for Ultimate Doom - gamepath = gogregistrypath + L"\\1435827232"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) - { - result.Push(path); // directly in install folder - } - - // Look for Doom II - gamepath = gogregistrypath + L"\\1435848814"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) - { - result.Push(path + "/doom2"); // in a subdirectory - // If direct support for the Master Levels is ever added, they are in path + /master/wads - } - - // Look for Final Doom - gamepath = gogregistrypath + L"\\1435848742"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) - { - // in subdirectories - result.Push(path + "/TNT"); - result.Push(path + "/Plutonia"); - } - - // Look for Doom 3: BFG Edition - gamepath = gogregistrypath + L"\\1135892318"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) - { - result.Push(path + "/base/wads"); // in a subdirectory - } - - // Look for Strife: Veteran Edition - gamepath = gogregistrypath + L"\\1432899949"; - if (QueryPathKey(HKEY_LOCAL_MACHINE, gamepath.c_str(), L"Path", path)) - { - result.Push(path); // directly in install folder - } - - return result; -} - -//========================================================================== -// -// I_GetSteamPath -// -// Check the registry for the path to Steam, so that we can search for -// IWADs that were bought with Steam. -// -//========================================================================== - -TArray I_GetSteamPath() -{ - TArray result; - static const char *const steam_dirs[] = - { - "doom 2/base", - "final doom/base", - "heretic shadow of the serpent riders/base", - "hexen/base", - "hexen deathkings of the dark citadel/base", - "ultimate doom/base", - "DOOM 3 BFG Edition/base/wads", - "Strife" - }; - - FString path; - - if (!QueryPathKey(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", L"SteamPath", path)) - { - if (!QueryPathKey(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", L"InstallPath", path)) - return result; - } - path += "/SteamApps/common/"; - - for(unsigned int i = 0; i < countof(steam_dirs); ++i) - { - result.Push(path + steam_dirs[i]); - } - - return result; -} - -//========================================================================== -// -// I_MakeRNGSeed -// -// Returns a 32-bit random seed, preferably one with lots of entropy. -// -//========================================================================== - -unsigned int I_MakeRNGSeed() -{ - unsigned int seed; - - // If RtlGenRandom is available, use that to avoid increasing the - // working set by pulling in all of the crytographic API. - HMODULE advapi = GetModuleHandleA("advapi32.dll"); - if (advapi != NULL) - { - BOOLEAN (APIENTRY *RtlGenRandom)(void *, ULONG) = - (BOOLEAN (APIENTRY *)(void *, ULONG))GetProcAddress(advapi, "SystemFunction036"); - if (RtlGenRandom != NULL) - { - if (RtlGenRandom(&seed, sizeof(seed))) - { - return seed; - } - } - } - - // Use the full crytographic API to produce a seed. If that fails, - // time() is used as a fallback. - HCRYPTPROV prov; - - if (!CryptAcquireContext(&prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - { - return (unsigned int)time(NULL); - } - if (!CryptGenRandom(prov, sizeof(seed), (uint8_t *)&seed)) - { - seed = (unsigned int)time(NULL); - } - CryptReleaseContext(prov, 0); - return seed; -} - -//========================================================================== -// -// I_GetLongPathName -// -// Returns the long version of the path, or the original if there isn't -// anything worth changing. -// -//========================================================================== - -FString I_GetLongPathName(const FString &shortpath) -{ - std::wstring wshortpath = shortpath.WideString(); - DWORD buffsize = GetLongPathNameW(wshortpath.c_str(), nullptr, 0); - if (buffsize == 0) - { // nothing to change (it doesn't exist, maybe?) - return shortpath; - } - TArray buff(buffsize, true); - DWORD buffsize2 = GetLongPathNameW(wshortpath.c_str(), buff.Data(), buffsize); - if (buffsize2 >= buffsize) - { // Failure! Just return the short path - return shortpath; - } - FString longpath(buff.Data()); - return longpath; -} - -#ifdef _USING_V110_SDK71_ -//========================================================================== -// -// _stat64i32 -// -// Work around an issue where stat() function doesn't work -// with Windows XP compatible toolset. -// It uses GetFileInformationByHandleEx() which requires Windows Vista. -// -//========================================================================== - -int _wstat64i32(const wchar_t *path, struct _stat64i32 *buffer) -{ - WIN32_FILE_ATTRIBUTE_DATA data; - if(!GetFileAttributesExW(path, GetFileExInfoStandard, &data)) - return -1; - - buffer->st_ino = 0; - buffer->st_mode = ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG)| - ((data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE); - buffer->st_dev = buffer->st_rdev = 0; - buffer->st_nlink = 1; - buffer->st_uid = 0; - buffer->st_gid = 0; - buffer->st_size = data.nFileSizeLow; - buffer->st_atime = (*(uint64_t*)&data.ftLastAccessTime) / 10000000 - 11644473600LL; - buffer->st_mtime = (*(uint64_t*)&data.ftLastWriteTime) / 10000000 - 11644473600LL; - buffer->st_ctime = (*(uint64_t*)&data.ftCreationTime) / 10000000 - 11644473600LL; - return 0; -} -#endif - -struct NumaNode -{ - uint64_t affinityMask = 0; - int threadCount = 0; -}; -static TArray numaNodes; - -static void SetupNumaNodes() -{ - if (numaNodes.Size() == 0) - { - // Query processors in the system - DWORD_PTR processMask = 0, systemMask = 0; - BOOL result = GetProcessAffinityMask(GetCurrentProcess(), &processMask, &systemMask); - if (result) - { - // Find the numa node each processor belongs to - std::map nodes; - for (int i = 0; i < sizeof(DWORD_PTR) * 8; i++) - { - DWORD_PTR processorMask = (((DWORD_PTR)1) << i); - if (processMask & processorMask) - { - UCHAR nodeNumber = 0; - result = GetNumaProcessorNode(i, &nodeNumber); - if (nodeNumber != 0xff) - { - nodes[nodeNumber].affinityMask |= (uint64_t)processorMask; - nodes[nodeNumber].threadCount++; - } - } - } - - // Convert map to a list - for (const auto &it : nodes) - { - numaNodes.Push(it.second); - } - } - - // Fall back to a single node if something went wrong - if (numaNodes.Size() == 0) - { - NumaNode node; - node.threadCount = std::thread::hardware_concurrency(); - if (node.threadCount == 0) - node.threadCount = 1; - numaNodes.Push(node); - } - } -} - -int I_GetNumaNodeCount() -{ - SetupNumaNodes(); - return numaNodes.Size(); -} - -int I_GetNumaNodeThreadCount(int numaNode) -{ - SetupNumaNodes(); - return numaNodes[numaNode].threadCount; -} - -void I_SetThreadNumaNode(std::thread &thread, int numaNode) -{ - if (numaNodes.Size() > 1) - { - HANDLE handle = (HANDLE)thread.native_handle(); - SetThreadAffinityMask(handle, (DWORD_PTR)numaNodes[numaNode].affinityMask); - } -} diff --git a/src/win32/i_system.h b/src/win32/i_system.h deleted file mode 100644 index 4a28b7f91ac..00000000000 --- a/src/win32/i_system.h +++ /dev/null @@ -1,179 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 1993-1996 id Software -// Copyright 1999-2016 Randy Heit -// Copyright 2002-2016 Christoph Oelckers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// System specific interface stuff. -// -//----------------------------------------------------------------------------- - - -#ifndef __I_SYSTEM__ -#define __I_SYSTEM__ - -#include "doomtype.h" -#include - -struct ticcmd_t; -struct WadStuff; - -// [RH] Detects the OS the game is running under. -void I_DetectOS (void); - -// Called by DoomMain. -void I_Init (void); - -// Return a seed value for the RNG. -unsigned int I_MakeRNGSeed(); - - -// -// Called by D_DoomLoop, -// called before processing any tics in a frame -// (just after displaying a frame). -// Time consuming syncronous operations -// are performed here (joystick reading). -// Can call D_PostEvent. -// -void I_StartFrame (void); - - -// -// Called by D_DoomLoop, -// called before processing each tic in a frame. -// Quick syncronous operations are performed here. -// Can call D_PostEvent. -void I_StartTic (void); - -// Asynchronous interrupt functions should maintain private queues -// that are read by the synchronous functions -// to be converted into events. - -// Either returns a null ticcmd, -// or calls a loadable driver to build it. -// This ticcmd will then be modified by the gameloop -// for normal input. -ticcmd_t *I_BaseTiccmd (void); - - -// Called by M_Responder when quit is selected. -// Clean exit, displays sell blurb. -void I_Quit (void); - - -void I_Tactile (int on, int off, int total); - -// Set the mouse cursor. The texture must be 32x32. -class FTexture; -bool I_SetCursor(FTexture *cursor); - -// Repaint the pre-game console -void I_PaintConsole (void); - -void I_DebugPrint (const char *cp); - -// Print a console string -void I_PrintStr (const char *cp); - -// Set the title string of the startup window -void I_SetIWADInfo (); - -// Pick from multiple IWADs to use -int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad); - -// The ini could not be saved at exit -bool I_WriteIniFailed (); - -// [RH] Used by the display code to set the normal window procedure -void I_SetWndProc(); - -// [RH] Checks the registry for Steam's install path, so we can scan its -// directories for IWADs if the user purchased any through Steam. -TArray I_GetSteamPath(); - -// [GZ] Same deal for GOG paths -TArray I_GetGogPaths(); - -// Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of -// giving them proper prototypes under Win32, they are just macros for -// Get/SetWindowLong, meaning they take LONGs and not LONG_PTRs. -#ifdef _WIN64 -typedef long long WLONG_PTR; -#elif _MSC_VER -typedef _W64 long WLONG_PTR; -#else -typedef long WLONG_PTR; -#endif - -// Wrapper for GetLongPathName -FString I_GetLongPathName(const FString &shortpath); - -// Directory searching routines - -// Mirror WIN32_FIND_DATAA in -#ifndef MAX_PATH -#define MAX_PATH 260 -#endif -#ifndef PATH_MAX -#define PATH_MAX 260 -#endif - -struct findstate_t -{ -private: - struct WinData - { - uint32_t Attribs; - uint32_t Times[3 * 2]; - uint32_t Size[2]; - uint32_t Reserved[2]; - wchar_t Name[MAX_PATH]; - wchar_t AltName[14]; - }; - WinData FindData; - FString UTF8Name; - - friend void *I_FindFirst(const char *filespec, findstate_t *fileinfo); - friend int I_FindNext(void *handle, findstate_t *fileinfo); - friend const char *I_FindName(findstate_t *fileinfo); - friend int I_FindAttr(findstate_t *fileinfo); -}; - -void *I_FindFirst (const char *filespec, findstate_t *fileinfo); -int I_FindNext (void *handle, findstate_t *fileinfo); -int I_FindClose (void *handle); - -const char *I_FindName(findstate_t *fileinfo); -inline int I_FindAttr(findstate_t *fileinfo) -{ - return fileinfo->FindData.Attribs; -} - -#define FA_RDONLY 0x00000001 -#define FA_HIDDEN 0x00000002 -#define FA_SYSTEM 0x00000004 -#define FA_DIREC 0x00000010 -#define FA_ARCH 0x00000020 - -int I_GetNumaNodeCount(); -int I_GetNumaNodeThreadCount(int numaNode); -void I_SetThreadNumaNode(std::thread &thread, int numaNode); - -#endif diff --git a/src/win32/st_start.cpp b/src/win32/st_start.cpp deleted file mode 100644 index 3e9a96047a0..00000000000 --- a/src/win32/st_start.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/* -** st_start.cpp -** Handles the startup screen. -** -**--------------------------------------------------------------------------- -** Copyright 2006-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include "resource.h" - -#include "st_start.h" -#include "templates.h" -#include "i_system.h" -#include "i_input.h" -#include "hardware.h" -#include "gi.h" -#include "w_wad.h" -#include "s_sound.h" -#include "m_argv.h" -#include "d_main.h" -#include "doomerrors.h" -#include "s_music.h" - -// MACROS ------------------------------------------------------------------ - - -// How many ms elapse between blinking text flips. On a standard VGA -// adapter, the characters are on for 16 frames and then off for another 16. -// The number here therefore corresponds roughly to the blink rate on a -// 60 Hz display. -#define BLINK_PERIOD 267 -#define TEXT_FONT_NAME "vga-rom-font.16" - - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -void RestoreConView(); -void LayoutMainWindow (HWND hWnd, HWND pane); -int LayoutNetStartPane (HWND pane, int w); - -bool ST_Util_CreateStartupWindow (); -void ST_Util_SizeWindowForBitmap (int scale); -void ST_Util_InvalidateRect (HWND hwnd, BitmapInfo *bitmap_info, int left, int top, int right, int bottom); - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static INT_PTR CALLBACK NetStartPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern HINSTANCE g_hInst; -extern HWND Window, ConWindow, ProgressBar, NetStartPane, StartupScreen, GameTitleWindow; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FStartupScreen *StartScreen; - -CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (self < 0) self = 0; - else if (self > 2) self=2; -} - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// FStartupScreen :: CreateInstance -// -// Initializes the startup screen for the detected game. -// Sets the size of the progress bar and displays the startup screen. -// -//========================================================================== - -FStartupScreen *FStartupScreen::CreateInstance(int max_progress) -{ - FStartupScreen *scr = NULL; - HRESULT hr; - - if (!Args->CheckParm("-nostartup")) - { - if (DoomStartupInfo.Type == FStartupInfo::HexenStartup || - (gameinfo.gametype == GAME_Hexen && DoomStartupInfo.Type == FStartupInfo::DefaultStartup)) - { - scr = new FHexenStartupScreen(max_progress, hr); - } - else if (DoomStartupInfo.Type == FStartupInfo::HereticStartup || - (gameinfo.gametype == GAME_Heretic && DoomStartupInfo.Type == FStartupInfo::DefaultStartup)) - { - scr = new FHereticStartupScreen(max_progress, hr); - } - else if (DoomStartupInfo.Type == FStartupInfo::StrifeStartup || - (gameinfo.gametype == GAME_Strife && DoomStartupInfo.Type == FStartupInfo::DefaultStartup)) - { - scr = new FStrifeStartupScreen(max_progress, hr); - } - if (scr != NULL && FAILED(hr)) - { - delete scr; - scr = NULL; - } - } - if (scr == NULL) - { - scr = new FBasicStartupScreen(max_progress, true); - } - return scr; -} - -//========================================================================== -// -// FBasicStartupScreen Constructor -// -// Shows a progress bar at the bottom of the window. -// -//========================================================================== - -FBasicStartupScreen::FBasicStartupScreen(int max_progress, bool show_bar) -: FStartupScreen(max_progress) -{ - if (show_bar) - { - ProgressBar = CreateWindowEx(0, PROGRESS_CLASS, - NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, - 0, 0, 0, 0, - Window, 0, g_hInst, NULL); - SendMessage (ProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0,MaxPos)); - LayoutMainWindow (Window, NULL); - } - NetMaxPos = 0; - NetCurPos = 0; -} - -//========================================================================== -// -// FBasicStartupScreen Destructor -// -// Called just before entering graphics mode to deconstruct the startup -// screen. -// -//========================================================================== - -FBasicStartupScreen::~FBasicStartupScreen() -{ - if (ProgressBar != NULL) - { - DestroyWindow (ProgressBar); - ProgressBar = NULL; - LayoutMainWindow (Window, NULL); - } - KillTimer(Window, 1337); -} - -//========================================================================== -// -// FBasicStartupScreen :: Progress -// -// Bumps the progress meter one notch. -// -//========================================================================== - -void FBasicStartupScreen::Progress() -{ - if (CurPos < MaxPos) - { - CurPos++; - SendMessage (ProgressBar, PBM_SETPOS, CurPos, 0); - } -} - -//========================================================================== -// -// FBasicStartupScreen :: NetInit -// -// Shows the network startup pane if it isn't visible. Sets the message in -// the pane to the one provided. If numplayers is 0, then the progress bar -// is a scrolling marquee style. If numplayers is 1, then the progress bar -// is just a full bar. If numplayers is >= 2, then the progress bar is a -// normal one, and a progress count is also shown in the pane. -// -//========================================================================== - -void FBasicStartupScreen::NetInit(const char *message, int numplayers) -{ - NetMaxPos = numplayers; - if (NetStartPane == NULL) - { - NetStartPane = CreateDialogParam (g_hInst, MAKEINTRESOURCE(IDD_NETSTARTPANE), Window, NetStartPaneProc, 0); - // We don't need two progress bars. - if (ProgressBar != NULL) - { - DestroyWindow (ProgressBar); - ProgressBar = NULL; - } - RECT winrect; - GetWindowRect (Window, &winrect); - SetWindowPos (Window, NULL, 0, 0, - winrect.right - winrect.left, winrect.bottom - winrect.top + LayoutNetStartPane (NetStartPane, 0), - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); - LayoutMainWindow (Window, NULL); - SetFocus (NetStartPane); - } - if (NetStartPane != NULL) - { - HWND ctl; - - std::wstring wmessage = WideString(message); - SetDlgItemTextW (NetStartPane, IDC_NETSTARTMESSAGE, wmessage.c_str()); - ctl = GetDlgItem (NetStartPane, IDC_NETSTARTPROGRESS); - - if (numplayers == 0) - { - // PBM_SETMARQUEE is only available under XP and above, so this might fail. - NetMarqueeMode = SendMessage (ctl, PBM_SETMARQUEE, TRUE, 100); - if (NetMarqueeMode == FALSE) - { - SendMessage (ctl, PBM_SETRANGE, 0, MAKELPARAM(0,16)); - } - else - { - // If we don't set the PBS_MARQUEE style, then the marquee will never show up. - SetWindowLong (ctl, GWL_STYLE, GetWindowLong (ctl, GWL_STYLE) | PBS_MARQUEE); - } - SetDlgItemTextW (NetStartPane, IDC_NETSTARTCOUNT, L""); - } - else - { - NetMarqueeMode = FALSE; - SendMessage (ctl, PBM_SETMARQUEE, FALSE, 0); - // Make sure the marquee really is turned off. - SetWindowLong (ctl, GWL_STYLE, GetWindowLong (ctl, GWL_STYLE) & (~PBS_MARQUEE)); - - SendMessage (ctl, PBM_SETRANGE, 0, MAKELPARAM(0,numplayers)); - if (numplayers == 1) - { - SendMessage (ctl, PBM_SETPOS, 1, 0); - SetDlgItemTextW (NetStartPane, IDC_NETSTARTCOUNT, L""); - } - } - } - NetMaxPos = numplayers; - NetCurPos = 0; - NetProgress(1); // You always know about yourself -} - -//========================================================================== -// -// FBasicStartupScreen :: NetDone -// -// Removes the network startup pane. -// -//========================================================================== - -void FBasicStartupScreen::NetDone() -{ - if (NetStartPane != NULL) - { - DestroyWindow (NetStartPane); - NetStartPane = NULL; - LayoutMainWindow (Window, NULL); - } -} - -//========================================================================== -// -// FBasicStartupScreen :: NetMessage -// -// Call this between NetInit() and NetDone() instead of Printf() to -// display messages, in case the progress meter is mixed in the same output -// stream as normal messages. -// -//========================================================================== - -void FBasicStartupScreen::NetMessage(const char *format, ...) -{ - FString str; - va_list argptr; - - va_start (argptr, format); - str.VFormat (format, argptr); - va_end (argptr); - Printf ("%s\n", str.GetChars()); -} - -//========================================================================== -// -// FBasicStartupScreen :: NetProgress -// -// Sets the network progress meter. If count is 0, it gets bumped by 1. -// Otherwise, it is set to count. -// -//========================================================================== - -void FBasicStartupScreen :: NetProgress(int count) -{ - if (count == 0) - { - NetCurPos++; - } - else - { - NetCurPos = count; - } - if (NetStartPane == NULL) - { - return; - } - if (NetMaxPos == 0 && !NetMarqueeMode) - { - // PBM_SETMARQUEE didn't work, so just increment the progress bar endlessly. - SendDlgItemMessage (NetStartPane, IDC_NETSTARTPROGRESS, PBM_SETPOS, NetCurPos & 15, 0); - } - else if (NetMaxPos > 1) - { - char buf[16]; - - mysnprintf (buf, countof(buf), "%d/%d", NetCurPos, NetMaxPos); - SetDlgItemTextA (NetStartPane, IDC_NETSTARTCOUNT, buf); - SendDlgItemMessage (NetStartPane, IDC_NETSTARTPROGRESS, PBM_SETPOS, MIN(NetCurPos, NetMaxPos), 0); - } -} - -//========================================================================== -// -// FBasicStartupScreen :: NetLoop -// -// The timer_callback function is called at least two times per second -// and passed the userdata value. It should return true to stop the loop and -// return control to the caller or false to continue the loop. -// -// ST_NetLoop will return true if the loop was halted by the callback and -// false if the loop was halted because the user wants to abort the -// network synchronization. -// -//========================================================================== - -bool FBasicStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) -{ - BOOL bRet; - MSG msg; - - if (SetTimer (Window, 1337, 500, NULL) == 0) - { - I_FatalError ("Could not set network synchronization timer."); - } - - while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) - { - if (bRet == -1) - { - KillTimer (Window, 1337); - return false; - } - else - { - if (msg.message == WM_TIMER && msg.hwnd == Window && msg.wParam == 1337) - { - if (timer_callback (userdata)) - { - KillTimer (NetStartPane, 1); - return true; - } - } - if (!IsDialogMessage (NetStartPane, &msg)) - { - TranslateMessage (&msg); - DispatchMessage (&msg); - } - } - } - KillTimer (Window, 1337); - return false; -} - -//========================================================================== -// -// NetStartPaneProc -// -// DialogProc for the network startup pane. It just waits for somebody to -// click a button, and the only button available is the abort one. -// -//========================================================================== - -static INT_PTR CALLBACK NetStartPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL) - { - PostQuitMessage (0); - return TRUE; - } - return FALSE; -} - -//========================================================================== -// -// FGraphicalStartupScreen Constructor -// -// This doesn't really do anything. The subclass is responsible for -// creating the resources that will be freed by this class's destructor. -// -//========================================================================== - -FGraphicalStartupScreen::FGraphicalStartupScreen(int max_progress) -: FBasicStartupScreen(max_progress, false) -{ -} - -//========================================================================== -// -// FGraphicalStartupScreen Destructor -// -//========================================================================== - -FGraphicalStartupScreen::~FGraphicalStartupScreen() -{ - if (StartupScreen != NULL) - { - DestroyWindow (StartupScreen); - StartupScreen = NULL; - } - if (StartupBitmap != NULL) - { - ST_Util_FreeBitmap (StartupBitmap); - StartupBitmap = NULL; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FHexenStartupScreen::SetWindowSize() -{ - ST_Util_SizeWindowForBitmap(1); - LayoutMainWindow(Window, NULL); - InvalidateRect(StartupScreen, NULL, TRUE); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FHereticStartupScreen::SetWindowSize() -{ - ST_Util_SizeWindowForBitmap(1); - LayoutMainWindow(Window, NULL); - InvalidateRect(StartupScreen, NULL, TRUE); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FStrifeStartupScreen::SetWindowSize() -{ - ST_Util_SizeWindowForBitmap(2); - LayoutMainWindow(Window, NULL); - InvalidateRect(StartupScreen, NULL, TRUE); -} - -//========================================================================== -// -// ST_Endoom -// -// Shows an ENDOOM text screen -// -//========================================================================== - -int RunEndoom() -{ - if (showendoom == 0 || gameinfo.Endoom.Len() == 0) - { - return 0; - } - - int endoom_lump = Wads.CheckNumForFullName (gameinfo.Endoom, true); - - uint8_t endoom_screen[4000]; - uint8_t *font; - MSG mess; - BOOL bRet; - bool blinking = false, blinkstate = false; - int i; - - if (endoom_lump < 0 || Wads.LumpLength (endoom_lump) != 4000) - { - return 0; - } - - if (Wads.GetLumpFile(endoom_lump) == Wads.GetMaxIwadNum() && showendoom == 2) - { - // showendoom==2 means to show only lumps from PWADs. - return 0; - } - - font = ST_Util_LoadFont (TEXT_FONT_NAME); - if (font == NULL) - { - return 0; - } - - if (!ST_Util_CreateStartupWindow()) - { - ST_Util_FreeFont (font); - return 0; - } - - I_ShutdownGraphics (); - RestoreConView (); - S_StopMusic(true); - - Wads.ReadLump (endoom_lump, endoom_screen); - - // Draw the loading screen to a bitmap. - StartupBitmap = ST_Util_AllocTextBitmap (font); - ST_Util_DrawTextScreen (StartupBitmap, endoom_screen, font); - - // Make the title banner go away. - if (GameTitleWindow != NULL) - { - DestroyWindow (GameTitleWindow); - GameTitleWindow = NULL; - } - - ST_Util_SizeWindowForBitmap (1); - LayoutMainWindow (Window, NULL); - InvalidateRect (StartupScreen, NULL, TRUE); - - // Does this screen need blinking? - for (i = 0; i < 80*25; ++i) - { - if (endoom_screen[1+i*2] & 0x80) - { - blinking = true; - break; - } - } - if (blinking && SetTimer (Window, 0x5A15A, BLINK_PERIOD, NULL) == 0) - { - blinking = false; - } - - // Wait until any key has been pressed or a quit message has been received - for (;;) - { - bRet = GetMessage (&mess, NULL, 0, 0); - if (bRet == 0 || bRet == -1 || // bRet == 0 means we received WM_QUIT - mess.message == WM_KEYDOWN || mess.message == WM_SYSKEYDOWN || mess.message == WM_LBUTTONDOWN) - { - if (blinking) - { - KillTimer (Window, 0x5A15A); - } - ST_Util_FreeBitmap (StartupBitmap); - ST_Util_FreeFont (font); - return int(bRet == 0 ? mess.wParam : 0); - } - else if (blinking && mess.message == WM_TIMER && mess.hwnd == Window && mess.wParam == 0x5A15A) - { - ST_Util_UpdateTextBlink (StartupBitmap, endoom_screen, font, blinkstate); - blinkstate = !blinkstate; - } - TranslateMessage (&mess); - DispatchMessage (&mess); - } -} - -void ST_Endoom() -{ - int code = RunEndoom(); - throw CExitEvent(code); - -} - -//========================================================================== -// -// ST_Util_CreateStartupWindow -// -// Creates the static control that will draw the startup screen. -// -//========================================================================== - -bool ST_Util_CreateStartupWindow () -{ - StartupScreen = CreateWindowEx (WS_EX_NOPARENTNOTIFY, L"STATIC", NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, - 0, 0, 0, 0, Window, NULL, g_hInst, NULL); - if (StartupScreen == NULL) - { - return false; - } - SetWindowLong (StartupScreen, GWL_ID, IDC_STATIC_STARTUP); - return true; -} - -//========================================================================== -// -// ST_Util_SizeWindowForBitmap -// -// Resizes the main window so that the startup bitmap will be drawn -// at the desired scale. -// -//========================================================================== - -void ST_Util_SizeWindowForBitmap (int scale) -{ - DEVMODE displaysettings; - int w, h, cx, cy, x, y; - RECT rect; - - if (GameTitleWindow != NULL) - { - GetClientRect (GameTitleWindow, &rect); - } - else - { - rect.bottom = 0; - } - RECT sizerect = { 0, 0, StartupBitmap->bmiHeader.biWidth * scale, - StartupBitmap->bmiHeader.biHeight * scale + rect.bottom }; - AdjustWindowRectEx(&sizerect, WS_VISIBLE|WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW); - w = sizerect.right - sizerect.left; - h = sizerect.bottom - sizerect.top; - - // Resize the window, but keep its center point the same, unless that - // puts it partially offscreen. - memset (&displaysettings, 0, sizeof(displaysettings)); - displaysettings.dmSize = sizeof(displaysettings); - EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings); - GetWindowRect (Window, &rect); - cx = (rect.left + rect.right) / 2; - cy = (rect.top + rect.bottom) / 2; - x = cx - w / 2; - y = cy - h / 2; - if (x + w > (int)displaysettings.dmPelsWidth) - { - x = displaysettings.dmPelsWidth - w; - } - if (x < 0) - { - x = 0; - } - if (y + h > (int)displaysettings.dmPelsHeight) - { - y = displaysettings.dmPelsHeight - h; - } - if (y < 0) - { - y = 0; - } - MoveWindow (Window, x, y, w, h, TRUE); -} - -//========================================================================== -// -// ST_Util_InvalidateRect -// -// Invalidates the portion of the window that the specified rect of the -// bitmap appears in. -// -//========================================================================== - -void ST_Util_InvalidateRect (HWND hwnd, BitmapInfo *bitmap_info, int left, int top, int right, int bottom) -{ - RECT rect; - - GetClientRect (hwnd, &rect); - rect.left = left * rect.right / bitmap_info->bmiHeader.biWidth - 1; - rect.top = top * rect.bottom / bitmap_info->bmiHeader.biHeight - 1; - rect.right = right * rect.right / bitmap_info->bmiHeader.biWidth + 1; - rect.bottom = bottom * rect.bottom / bitmap_info->bmiHeader.biHeight + 1; - InvalidateRect (hwnd, &rect, FALSE); -} - -void ST_Util_InvalidateRect(BitmapInfo* bitmap_info, int left, int top, int right, int bottom) -{ - ST_Util_InvalidateRect(StartupScreen , bitmap_info, left, top, right, bottom); -} diff --git a/src/win32/st_start_util.cpp b/src/win32/st_start_util.cpp deleted file mode 100644 index 72bb3f14a46..00000000000 --- a/src/win32/st_start_util.cpp +++ /dev/null @@ -1,1185 +0,0 @@ -/* -** st_start.cpp -** Handles the startup screen. -** -**--------------------------------------------------------------------------- -** Copyright 2006-2007 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - - -#include -#include -#include "st_start.h" -#include "m_alloc.h" -#include "w_wad.h" -#include "v_palette.h" -#include "s_sound.h" -#include "s_music.h" -#include "d_main.h" - -void I_GetEvent(); // i_input.h pulls in too much garbage. - -void ST_Util_InvalidateRect(BitmapInfo* bitmap_info, int left, int top, int right, int bottom); -bool ST_Util_CreateStartupWindow(); - -static const uint16_t IBM437ToUnicode[] = { - 0x0000, //#NULL - 0x0001, //#START OF HEADING - 0x0002, //#START OF TEXT - 0x0003, //#END OF TEXT - 0x0004, //#END OF TRANSMISSION - 0x0005, //#ENQUIRY - 0x0006, //#ACKNOWLEDGE - 0x0007, //#BELL - 0x0008, //#BACKSPACE - 0x0009, //#HORIZONTAL TABULATION - 0x000a, //#LINE FEED - 0x000b, //#VERTICAL TABULATION - 0x000c, //#FORM FEED - 0x000d, //#CARRIAGE RETURN - 0x000e, //#SHIFT OUT - 0x000f, //#SHIFT IN - 0x0010, //#DATA LINK ESCAPE - 0x0011, //#DEVICE CONTROL ONE - 0x0012, //#DEVICE CONTROL TWO - 0x0013, //#DEVICE CONTROL THREE - 0x0014, //#DEVICE CONTROL FOUR - 0x0015, //#NEGATIVE ACKNOWLEDGE - 0x0016, //#SYNCHRONOUS IDLE - 0x0017, //#END OF TRANSMISSION BLOCK - 0x0018, //#CANCEL - 0x0019, //#END OF MEDIUM - 0x001a, //#SUBSTITUTE - 0x001b, //#ESCAPE - 0x001c, //#FILE SEPARATOR - 0x001d, //#GROUP SEPARATOR - 0x001e, //#RECORD SEPARATOR - 0x001f, //#UNIT SEPARATOR - 0x0020, //#SPACE - 0x0021, //#EXCLAMATION MARK - 0x0022, //#QUOTATION MARK - 0x0023, //#NUMBER SIGN - 0x0024, //#DOLLAR SIGN - 0x0025, //#PERCENT SIGN - 0x0026, //#AMPERSAND - 0x0027, //#APOSTROPHE - 0x0028, //#LEFT PARENTHESIS - 0x0029, //#RIGHT PARENTHESIS - 0x002a, //#ASTERISK - 0x002b, //#PLUS SIGN - 0x002c, //#COMMA - 0x002d, //#HYPHEN-MINUS - 0x002e, //#FULL STOP - 0x002f, //#SOLIDUS - 0x0030, //#DIGIT ZERO - 0x0031, //#DIGIT ONE - 0x0032, //#DIGIT TWO - 0x0033, //#DIGIT THREE - 0x0034, //#DIGIT FOUR - 0x0035, //#DIGIT FIVE - 0x0036, //#DIGIT SIX - 0x0037, //#DIGIT SEVEN - 0x0038, //#DIGIT EIGHT - 0x0039, //#DIGIT NINE - 0x003a, //#COLON - 0x003b, //#SEMICOLON - 0x003c, //#LESS-THAN SIGN - 0x003d, //#EQUALS SIGN - 0x003e, //#GREATER-THAN SIGN - 0x003f, //#QUESTION MARK - 0x0040, //#COMMERCIAL AT - 0x0041, //#LATIN CAPITAL LETTER A - 0x0042, //#LATIN CAPITAL LETTER B - 0x0043, //#LATIN CAPITAL LETTER C - 0x0044, //#LATIN CAPITAL LETTER D - 0x0045, //#LATIN CAPITAL LETTER E - 0x0046, //#LATIN CAPITAL LETTER F - 0x0047, //#LATIN CAPITAL LETTER G - 0x0048, //#LATIN CAPITAL LETTER H - 0x0049, //#LATIN CAPITAL LETTER I - 0x004a, //#LATIN CAPITAL LETTER J - 0x004b, //#LATIN CAPITAL LETTER K - 0x004c, //#LATIN CAPITAL LETTER L - 0x004d, //#LATIN CAPITAL LETTER M - 0x004e, //#LATIN CAPITAL LETTER N - 0x004f, //#LATIN CAPITAL LETTER O - 0x0050, //#LATIN CAPITAL LETTER P - 0x0051, //#LATIN CAPITAL LETTER Q - 0x0052, //#LATIN CAPITAL LETTER R - 0x0053, //#LATIN CAPITAL LETTER S - 0x0054, //#LATIN CAPITAL LETTER T - 0x0055, //#LATIN CAPITAL LETTER U - 0x0056, //#LATIN CAPITAL LETTER V - 0x0057, //#LATIN CAPITAL LETTER W - 0x0058, //#LATIN CAPITAL LETTER X - 0x0059, //#LATIN CAPITAL LETTER Y - 0x005a, //#LATIN CAPITAL LETTER Z - 0x005b, //#LEFT SQUARE BRACKET - 0x005c, //#REVERSE SOLIDUS - 0x005d, //#RIGHT SQUARE BRACKET - 0x005e, //#CIRCUMFLEX ACCENT - 0x005f, //#LOW LINE - 0x0060, //#GRAVE ACCENT - 0x0061, //#LATIN SMALL LETTER A - 0x0062, //#LATIN SMALL LETTER B - 0x0063, //#LATIN SMALL LETTER C - 0x0064, //#LATIN SMALL LETTER D - 0x0065, //#LATIN SMALL LETTER E - 0x0066, //#LATIN SMALL LETTER F - 0x0067, //#LATIN SMALL LETTER G - 0x0068, //#LATIN SMALL LETTER H - 0x0069, //#LATIN SMALL LETTER I - 0x006a, //#LATIN SMALL LETTER J - 0x006b, //#LATIN SMALL LETTER K - 0x006c, //#LATIN SMALL LETTER L - 0x006d, //#LATIN SMALL LETTER M - 0x006e, //#LATIN SMALL LETTER N - 0x006f, //#LATIN SMALL LETTER O - 0x0070, //#LATIN SMALL LETTER P - 0x0071, //#LATIN SMALL LETTER Q - 0x0072, //#LATIN SMALL LETTER R - 0x0073, //#LATIN SMALL LETTER S - 0x0074, //#LATIN SMALL LETTER T - 0x0075, //#LATIN SMALL LETTER U - 0x0076, //#LATIN SMALL LETTER V - 0x0077, //#LATIN SMALL LETTER W - 0x0078, //#LATIN SMALL LETTER X - 0x0079, //#LATIN SMALL LETTER Y - 0x007a, //#LATIN SMALL LETTER Z - 0x007b, //#LEFT CURLY BRACKET - 0x007c, //#VERTICAL LINE - 0x007d, //#RIGHT CURLY BRACKET - 0x007e, //#TILDE - 0x007f, //#DELETE - 0x00c7, //#LATIN CAPITAL LETTER C WITH CEDILLA - 0x00fc, //#LATIN SMALL LETTER U WITH DIAERESIS - 0x00e9, //#LATIN SMALL LETTER E WITH ACUTE - 0x00e2, //#LATIN SMALL LETTER A WITH CIRCUMFLEX - 0x00e4, //#LATIN SMALL LETTER A WITH DIAERESIS - 0x00e0, //#LATIN SMALL LETTER A WITH GRAVE - 0x00e5, //#LATIN SMALL LETTER A WITH RING ABOVE - 0x00e7, //#LATIN SMALL LETTER C WITH CEDILLA - 0x00ea, //#LATIN SMALL LETTER E WITH CIRCUMFLEX - 0x00eb, //#LATIN SMALL LETTER E WITH DIAERESIS - 0x00e8, //#LATIN SMALL LETTER E WITH GRAVE - 0x00ef, //#LATIN SMALL LETTER I WITH DIAERESIS - 0x00ee, //#LATIN SMALL LETTER I WITH CIRCUMFLEX - 0x00ec, //#LATIN SMALL LETTER I WITH GRAVE - 0x00c4, //#LATIN CAPITAL LETTER A WITH DIAERESIS - 0x00c5, //#LATIN CAPITAL LETTER A WITH RING ABOVE - 0x00c9, //#LATIN CAPITAL LETTER E WITH ACUTE - 0x00e6, //#LATIN SMALL LIGATURE AE - 0x00c6, //#LATIN CAPITAL LIGATURE AE - 0x00f4, //#LATIN SMALL LETTER O WITH CIRCUMFLEX - 0x00f6, //#LATIN SMALL LETTER O WITH DIAERESIS - 0x00f2, //#LATIN SMALL LETTER O WITH GRAVE - 0x00fb, //#LATIN SMALL LETTER U WITH CIRCUMFLEX - 0x00f9, //#LATIN SMALL LETTER U WITH GRAVE - 0x00ff, //#LATIN SMALL LETTER Y WITH DIAERESIS - 0x00d6, //#LATIN CAPITAL LETTER O WITH DIAERESIS - 0x00dc, //#LATIN CAPITAL LETTER U WITH DIAERESIS - 0x00a2, //#CENT SIGN - 0x00a3, //#POUND SIGN - 0x00a5, //#YEN SIGN - 0x20a7, //#PESETA SIGN - 0x0192, //#LATIN SMALL LETTER F WITH HOOK - 0x00e1, //#LATIN SMALL LETTER A WITH ACUTE - 0x00ed, //#LATIN SMALL LETTER I WITH ACUTE - 0x00f3, //#LATIN SMALL LETTER O WITH ACUTE - 0x00fa, //#LATIN SMALL LETTER U WITH ACUTE - 0x00f1, //#LATIN SMALL LETTER N WITH TILDE - 0x00d1, //#LATIN CAPITAL LETTER N WITH TILDE - 0x00aa, //#FEMININE ORDINAL INDICATOR - 0x00ba, //#MASCULINE ORDINAL INDICATOR - 0x00bf, //#INVERTED QUESTION MARK - 0x2310, //#REVERSED NOT SIGN - 0x00ac, //#NOT SIGN - 0x00bd, //#VULGAR FRACTION ONE HALF - 0x00bc, //#VULGAR FRACTION ONE QUARTER - 0x00a1, //#INVERTED EXCLAMATION MARK - 0x00ab, //#LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - 0x00bb, //#RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - 0x2591, //#LIGHT SHADE - 0x2592, //#MEDIUM SHADE - 0x2593, //#DARK SHADE - 0x2502, //#BOX DRAWINGS LIGHT VERTICAL - 0x2524, //#BOX DRAWINGS LIGHT VERTICAL AND LEFT - 0x2561, //#BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE - 0x2562, //#BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE - 0x2556, //#BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE - 0x2555, //#BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE - 0x2563, //#BOX DRAWINGS DOUBLE VERTICAL AND LEFT - 0x2551, //#BOX DRAWINGS DOUBLE VERTICAL - 0x2557, //#BOX DRAWINGS DOUBLE DOWN AND LEFT - 0x255d, //#BOX DRAWINGS DOUBLE UP AND LEFT - 0x255c, //#BOX DRAWINGS UP DOUBLE AND LEFT SINGLE - 0x255b, //#BOX DRAWINGS UP SINGLE AND LEFT DOUBLE - 0x2510, //#BOX DRAWINGS LIGHT DOWN AND LEFT - 0x2514, //#BOX DRAWINGS LIGHT UP AND RIGHT - 0x2534, //#BOX DRAWINGS LIGHT UP AND HORIZONTAL - 0x252c, //#BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - 0x251c, //#BOX DRAWINGS LIGHT VERTICAL AND RIGHT - 0x2500, //#BOX DRAWINGS LIGHT HORIZONTAL - 0x253c, //#BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - 0x255e, //#BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE - 0x255f, //#BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE - 0x255a, //#BOX DRAWINGS DOUBLE UP AND RIGHT - 0x2554, //#BOX DRAWINGS DOUBLE DOWN AND RIGHT - 0x2569, //#BOX DRAWINGS DOUBLE UP AND HORIZONTAL - 0x2566, //#BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL - 0x2560, //#BOX DRAWINGS DOUBLE VERTICAL AND RIGHT - 0x2550, //#BOX DRAWINGS DOUBLE HORIZONTAL - 0x256c, //#BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL - 0x2567, //#BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE - 0x2568, //#BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE - 0x2564, //#BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE - 0x2565, //#BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE - 0x2559, //#BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE - 0x2558, //#BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE - 0x2552, //#BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE - 0x2553, //#BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE - 0x256b, //#BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE - 0x256a, //#BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE - 0x2518, //#BOX DRAWINGS LIGHT UP AND LEFT - 0x250c, //#BOX DRAWINGS LIGHT DOWN AND RIGHT - 0x2588, //#FULL BLOCK - 0x2584, //#LOWER HALF BLOCK - 0x258c, //#LEFT HALF BLOCK - 0x2590, //#RIGHT HALF BLOCK - 0x2580, //#UPPER HALF BLOCK - 0x03b1, //#GREEK SMALL LETTER ALPHA - 0x00df, //#LATIN SMALL LETTER SHARP S - 0x0393, //#GREEK CAPITAL LETTER GAMMA - 0x03c0, //#GREEK SMALL LETTER PI - 0x03a3, //#GREEK CAPITAL LETTER SIGMA - 0x03c3, //#GREEK SMALL LETTER SIGMA - 0x00b5, //#MICRO SIGN - 0x03c4, //#GREEK SMALL LETTER TAU - 0x03a6, //#GREEK CAPITAL LETTER PHI - 0x0398, //#GREEK CAPITAL LETTER THETA - 0x03a9, //#GREEK CAPITAL LETTER OMEGA - 0x03b4, //#GREEK SMALL LETTER DELTA - 0x221e, //#INFINITY - 0x03c6, //#GREEK SMALL LETTER PHI - 0x03b5, //#GREEK SMALL LETTER EPSILON - 0x2229, //#INTERSECTION - 0x2261, //#IDENTICAL TO - 0x00b1, //#PLUS-MINUS SIGN - 0x2265, //#GREATER-THAN OR EQUAL TO - 0x2264, //#LESS-THAN OR EQUAL TO - 0x2320, //#TOP HALF INTEGRAL - 0x2321, //#BOTTOM HALF INTEGRAL - 0x00f7, //#DIVISION SIGN - 0x2248, //#ALMOST EQUAL TO - 0x00b0, //#DEGREE SIGN - 0x2219, //#BULLET OPERATOR - 0x00b7, //#MIDDLE DOT - 0x221a, //#SQUARE ROOT - 0x207f, //#SUPERSCRIPT LATIN SMALL LETTER N - 0x00b2, //#SUPERSCRIPT TWO - 0x25a0, //#BLACK SQUARE - 0x00a0, //#NO-BREAK SPACE -}; - -BitmapInfo* StartupBitmap; - -// Hexen startup screen -#define ST_MAX_NOTCHES 32 -#define ST_NOTCH_WIDTH 16 -#define ST_NOTCH_HEIGHT 23 -#define ST_PROGRESS_X 64 // Start of notches x screen pos. -#define ST_PROGRESS_Y 441 // Start of notches y screen pos. - -#define ST_NETPROGRESS_X 288 -#define ST_NETPROGRESS_Y 32 -#define ST_NETNOTCH_WIDTH 4 -#define ST_NETNOTCH_HEIGHT 16 -#define ST_MAX_NETNOTCHES 8 - -// Heretic startup screen -#define HERETIC_MINOR_VERSION '3' // Since we're based on Heretic 1.3 - -#define THERM_X 14 -#define THERM_Y 14 -#define THERM_LEN 51 -#define THERM_COLOR 0xAA // light green - -#define TEXT_FONT_NAME "vga-rom-font.16" - -// Strife startup screen -#define PEASANT_INDEX 0 -#define LASER_INDEX 4 -#define BOT_INDEX 6 - -#define ST_LASERSPACE_X 60 -#define ST_LASERSPACE_Y 156 -#define ST_LASERSPACE_WIDTH 200 -#define ST_LASER_WIDTH 16 -#define ST_LASER_HEIGHT 16 - -#define ST_BOT_X 14 -#define ST_BOT_Y 138 -#define ST_BOT_WIDTH 48 -#define ST_BOT_HEIGHT 48 - -#define ST_PEASANT_X 262 -#define ST_PEASANT_Y 136 -#define ST_PEASANT_WIDTH 32 -#define ST_PEASANT_HEIGHT 64 - -// Text mode color values -#define LO 85 -#define MD 170 -#define HI 255 - -static const RgbQuad TextModePalette[16] = -{ - { 0, 0, 0, 0 }, // 0 black - { MD, 0, 0, 0 }, // 1 blue - { 0, MD, 0, 0 }, // 2 green - { MD, MD, 0, 0 }, // 3 cyan - { 0, 0, MD, 0 }, // 4 red - { MD, 0, MD, 0 }, // 5 magenta - { 0, LO, MD, 0 }, // 6 brown - { MD, MD, MD, 0 }, // 7 light gray - - { LO, LO, LO, 0 }, // 8 dark gray - { HI, LO, LO, 0 }, // 9 light blue - { LO, HI, LO, 0 }, // A light green - { HI, HI, LO, 0 }, // B light cyan - { LO, LO, HI, 0 }, // C light red - { HI, LO, HI, 0 }, // D light magenta - { LO, HI, HI, 0 }, // E yellow - { HI, HI, HI, 0 }, // F white -}; - -static const char* StrifeStartupPicNames[4 + 2 + 1] = -{ - "STRTPA1", "STRTPB1", "STRTPC1", "STRTPD1", - "STRTLZ1", "STRTLZ2", - "STRTBOT" -}; -static const int StrifeStartupPicSizes[4 + 2 + 1] = -{ - 2048, 2048, 2048, 2048, - 256, 256, - 2304 -}; - - -//========================================================================== -// -// FHexenStartupScreen Constructor -// -// Shows the Hexen startup screen. If the screen doesn't appear to be -// valid, it sets hr for a failure. -// -// The startup graphic is a planar, 4-bit 640x480 graphic preceded by a -// 16 entry (48 byte) VGA palette. -// -//========================================================================== - -FHexenStartupScreen::FHexenStartupScreen(int max_progress, long& hr) - : FGraphicalStartupScreen(max_progress) -{ - int startup_lump = Wads.CheckNumForName("STARTUP"); - int netnotch_lump = Wads.CheckNumForName("NETNOTCH"); - int notch_lump = Wads.CheckNumForName("NOTCH"); - hr = -1; - - if (startup_lump < 0 || Wads.LumpLength(startup_lump) != 153648 || !ST_Util_CreateStartupWindow() || - netnotch_lump < 0 || Wads.LumpLength(netnotch_lump) != ST_NETNOTCH_WIDTH / 2 * ST_NETNOTCH_HEIGHT || - notch_lump < 0 || Wads.LumpLength(notch_lump) != ST_NOTCH_WIDTH / 2 * ST_NOTCH_HEIGHT) - { - NetNotchBits = NotchBits = NULL; - return; - } - - NetNotchBits = new uint8_t[ST_NETNOTCH_WIDTH / 2 * ST_NETNOTCH_HEIGHT]; - Wads.ReadLump(netnotch_lump, NetNotchBits); - NotchBits = new uint8_t[ST_NOTCH_WIDTH / 2 * ST_NOTCH_HEIGHT]; - Wads.ReadLump(notch_lump, NotchBits); - - uint8_t startup_screen[153648]; - union - { - RgbQuad color; - uint32_t quad; - } c; - - Wads.ReadLump(startup_lump, startup_screen); - - c.color.rgbReserved = 0; - - StartupBitmap = ST_Util_CreateBitmap(640, 480, 4); - - // Initialize the bitmap palette. - for (int i = 0; i < 16; ++i) - { - c.color.rgbRed = startup_screen[i * 3 + 0]; - c.color.rgbGreen = startup_screen[i * 3 + 1]; - c.color.rgbBlue = startup_screen[i * 3 + 2]; - // Convert from 6-bit per component to 8-bit per component. - c.quad = (c.quad << 2) | ((c.quad >> 4) & 0x03030303); - StartupBitmap->bmiColors[i] = c.color; - } - - // Fill in the bitmap data. Convert to chunky, because I can't figure out - // if Windows actually supports planar images or not, despite the presence - // of biPlanes in the BITMAPINFOHEADER. - ST_Util_PlanarToChunky4(ST_Util_BitsForBitmap(StartupBitmap), startup_screen + 48, 640, 480); - - - if (!batchrun) - { - if (DoomStartupInfo.Song.IsNotEmpty()) - { - S_ChangeMusic(DoomStartupInfo.Song.GetChars(), true, true); - } - else - { - S_ChangeMusic("orb", true, true); - } - } - SetWindowSize(); - hr = 0; -} - -//========================================================================== -// -// FHexenStartupScreen Deconstructor -// -// Frees the notch pictures. -// -//========================================================================== - -FHexenStartupScreen::~FHexenStartupScreen() -{ - if (NotchBits) - delete[] NotchBits; - if (NetNotchBits) - delete[] NetNotchBits; -} - -//========================================================================== -// -// FHexenStartupScreen :: Progress -// -// Bumps the progress meter one notch. -// -//========================================================================== - -void FHexenStartupScreen::Progress() -{ - int notch_pos, x, y; - - if (CurPos < MaxPos) - { - CurPos++; - notch_pos = (CurPos * ST_MAX_NOTCHES) / MaxPos; - if (notch_pos != NotchPos) - { // Time to draw another notch. - for (; NotchPos < notch_pos; NotchPos++) - { - x = ST_PROGRESS_X + ST_NOTCH_WIDTH * NotchPos; - y = ST_PROGRESS_Y; - ST_Util_DrawBlock(StartupBitmap, NotchBits, x, y, ST_NOTCH_WIDTH / 2, ST_NOTCH_HEIGHT); - } - S_Sound(CHAN_BODY, 0, "StartupTick", 1, ATTN_NONE); - } - } - I_GetEvent(); -} - -//========================================================================== -// -// FHexenStartupScreen :: NetProgress -// -// Draws the red net noches in addition to the normal progress bar. -// -//========================================================================== - -void FHexenStartupScreen::NetProgress(int count) -{ - int oldpos = NetCurPos; - int x, y; - - FGraphicalStartupScreen::NetProgress(count); - if (NetMaxPos != 0 && NetCurPos > oldpos) - { - for (; oldpos < NetCurPos && oldpos < ST_MAX_NETNOTCHES; ++oldpos) - { - x = ST_NETPROGRESS_X + ST_NETNOTCH_WIDTH * oldpos; - y = ST_NETPROGRESS_Y; - ST_Util_DrawBlock(StartupBitmap, NetNotchBits, x, y, ST_NETNOTCH_WIDTH / 2, ST_NETNOTCH_HEIGHT); - } - S_Sound(CHAN_BODY, 0, "misc/netnotch", 1, ATTN_NONE); - I_GetEvent(); - } -} - -//========================================================================== -// -// FHexenStartupScreen :: NetDone -// -// Aside from the standard processing, also plays a sound. -// -//========================================================================== - -void FHexenStartupScreen::NetDone() -{ - S_Sound(CHAN_BODY, 0, "PickupWeapon", 1, ATTN_NORM); - FGraphicalStartupScreen::NetDone(); -} - - -//========================================================================== -// -// FHereticStartupScreen Constructor -// -// Shows the Heretic startup screen. If the screen doesn't appear to be -// valid, it returns a failure code in hr. -// -// The loading screen is an 80x25 text screen with character data and -// attributes intermixed, which means it must be exactly 4000 bytes long. -// -//========================================================================== - -FHereticStartupScreen::FHereticStartupScreen(int max_progress, long& hr) - : FGraphicalStartupScreen(max_progress) -{ - int loading_lump = Wads.CheckNumForName("LOADING"); - uint8_t loading_screen[4000]; - uint8_t* font; - - hr = -1; - if (loading_lump < 0 || Wads.LumpLength(loading_lump) != 4000 || !ST_Util_CreateStartupWindow()) - { - return; - } - - font = ST_Util_LoadFont(TEXT_FONT_NAME); - if (font == NULL) - { - return; - } - - Wads.ReadLump(loading_lump, loading_screen); - - // Slap the Heretic minor version on the loading screen. Heretic - // did this inside the executable rather than coming with modified - // LOADING screens, so we need to do the same. - loading_screen[2 * 160 + 49 * 2] = HERETIC_MINOR_VERSION; - - // Draw the loading screen to a bitmap. - StartupBitmap = ST_Util_AllocTextBitmap(font); - ST_Util_DrawTextScreen(StartupBitmap, loading_screen, font); - - ThermX = THERM_X * 8; - ThermY = THERM_Y * font[0]; - ThermWidth = THERM_LEN * 8 - 4; - ThermHeight = font[0]; - HMsgY = 7; - SMsgX = 1; - - ST_Util_FreeFont(font); - SetWindowSize(); - hr = 0; -} - -//========================================================================== -// -// FHereticStartupScreen::Progress -// -// Bumps the progress meter one notch. -// -//========================================================================== - -void FHereticStartupScreen::Progress() -{ - int notch_pos; - - if (CurPos < MaxPos) - { - CurPos++; - notch_pos = (CurPos * ThermWidth) / MaxPos; - if (notch_pos != NotchPos && !(notch_pos & 3)) - { // Time to draw another notch. - int left = NotchPos + ThermX; - int top = ThermY; - int right = notch_pos + ThermX; - int bottom = top + ThermHeight; - ST_Util_ClearBlock(StartupBitmap, THERM_COLOR, left, top, right - left, bottom - top); - NotchPos = notch_pos; - } - } - I_GetEvent(); -} - -//========================================================================== -// -// FHereticStartupScreen :: LoadingStatus -// -// Prints text in the center box of the startup screen. -// -//========================================================================== - -void FHereticStartupScreen::LoadingStatus(const char* message, int colors) -{ - uint8_t* font = ST_Util_LoadFont(TEXT_FONT_NAME); - if (font != NULL) - { - int x; - - for (x = 0; message[x] != '\0'; ++x) - { - ST_Util_DrawChar(StartupBitmap, font, 17 + x, HMsgY, message[x], colors); - } - ST_Util_InvalidateRect(StartupBitmap, 17 * 8, HMsgY * font[0], (17 + x) * 8, HMsgY * font[0] + font[0]); - ST_Util_FreeFont(font); - HMsgY++; - I_GetEvent(); - } -} - -//========================================================================== -// -// FHereticStartupScreen :: AppendStatusLine -// -// Appends text to Heretic's status line. -// -//========================================================================== - -void FHereticStartupScreen::AppendStatusLine(const char* status) -{ - uint8_t* font = ST_Util_LoadFont(TEXT_FONT_NAME); - if (font != NULL) - { - int x; - - for (x = 0; status[x] != '\0'; ++x) - { - ST_Util_DrawChar(StartupBitmap, font, SMsgX + x, 24, status[x], 0x1f); - } - ST_Util_InvalidateRect(StartupBitmap, SMsgX * 8, 24 * font[0], (SMsgX + x) * 8, 25 * font[0]); - ST_Util_FreeFont(font); - SMsgX += x; - I_GetEvent(); - } -} - -//========================================================================== -// -// FStrifeStartupScreen Constructor -// -// Shows the Strife startup screen. If the screen doesn't appear to be -// valid, it returns a failure code in hr. -// -// The startup background is a raw 320x200 image, however Strife only -// actually uses 95 rows from it, starting at row 57. The rest of the image -// is discarded. (What a shame.) -// -// The peasants are raw 32x64 images. The laser dots are raw 16x16 images. -// The bot is a raw 48x48 image. All use the standard PLAYPAL. -// -//========================================================================== - -FStrifeStartupScreen::FStrifeStartupScreen(int max_progress, long& hr) - : FGraphicalStartupScreen(max_progress) -{ - int startup_lump = Wads.CheckNumForName("STARTUP0"); - int i; - - hr = -1; - for (i = 0; i < 4 + 2 + 1; ++i) - { - StartupPics[i] = NULL; - } - - if (startup_lump < 0 || Wads.LumpLength(startup_lump) != 64000 || !ST_Util_CreateStartupWindow()) - { - return; - } - - StartupBitmap = ST_Util_CreateBitmap(320, 200, 8); - ST_Util_BitmapColorsFromPlaypal(StartupBitmap); - - // Fill bitmap with the startup image. - memset(ST_Util_BitsForBitmap(StartupBitmap), 0xF0, 64000); - auto lumpr = Wads.OpenLumpReader(startup_lump); - lumpr.Seek(57 * 320, FileReader::SeekSet); - lumpr.Read(ST_Util_BitsForBitmap(StartupBitmap) + 41 * 320, 95 * 320); - - // Load the animated overlays. - for (i = 0; i < 4 + 2 + 1; ++i) - { - int lumpnum = Wads.CheckNumForName(StrifeStartupPicNames[i]); - int lumplen; - - if (lumpnum >= 0 && (lumplen = Wads.LumpLength(lumpnum)) == StrifeStartupPicSizes[i]) - { - auto lumpr = Wads.OpenLumpReader(lumpnum); - StartupPics[i] = new uint8_t[lumplen]; - lumpr.Read(StartupPics[i], lumplen); - } - } - - // Make the startup image appear. - DrawStuff(0, 0); - SetWindowSize(); - hr = 0; -} - -//========================================================================== -// -// FStrifeStartupScreen Destructor -// -// Frees the strife pictures. -// -//========================================================================== - -FStrifeStartupScreen::~FStrifeStartupScreen() -{ - for (int i = 0; i < 4 + 2 + 1; ++i) - { - if (StartupPics[i] != NULL) - { - delete[] StartupPics[i]; - } - StartupPics[i] = NULL; - } -} - -//========================================================================== -// -// FStrifeStartupScreen :: Progress -// -// Bumps the progress meter one notch. -// -//========================================================================== - -void FStrifeStartupScreen::Progress() -{ - int notch_pos; - - if (CurPos < MaxPos) - { - CurPos++; - notch_pos = (CurPos * (ST_LASERSPACE_WIDTH - ST_LASER_WIDTH)) / MaxPos; - if (notch_pos != NotchPos && !(notch_pos & 1)) - { // Time to update. - DrawStuff(NotchPos, notch_pos); - NotchPos = notch_pos; - } - } - I_GetEvent(); -} - -//========================================================================== -// -// FStrifeStartupScreen :: DrawStuff -// -// Draws all the moving parts of Strife's startup screen. If you're -// running off a slow drive, it can look kind of good. Otherwise, it -// borders on crazy insane fast. -// -//========================================================================== - -void FStrifeStartupScreen::DrawStuff(int old_laser, int new_laser) -{ - int y; - auto bitmap_info = StartupBitmap; - - // Clear old laser - ST_Util_ClearBlock(bitmap_info, 0xF0, ST_LASERSPACE_X + old_laser, - ST_LASERSPACE_Y, ST_LASER_WIDTH, ST_LASER_HEIGHT); - // Draw new laser - ST_Util_DrawBlock(bitmap_info, StartupPics[LASER_INDEX + (new_laser & 1)], - ST_LASERSPACE_X + new_laser, ST_LASERSPACE_Y, ST_LASER_WIDTH, ST_LASER_HEIGHT); - - // The bot jumps up and down like crazy. - y = std::max(0, (new_laser >> 1) % 5 - 2); - if (y > 0) - { - ST_Util_ClearBlock(bitmap_info, 0xF0, ST_BOT_X, ST_BOT_Y, ST_BOT_WIDTH, y); - } - ST_Util_DrawBlock(bitmap_info, StartupPics[BOT_INDEX], ST_BOT_X, ST_BOT_Y + y, ST_BOT_WIDTH, ST_BOT_HEIGHT); - if (y < (5 - 1) - 2) - { - ST_Util_ClearBlock(bitmap_info, 0xF0, ST_BOT_X, ST_BOT_Y + ST_BOT_HEIGHT + y, ST_BOT_WIDTH, 2 - y); - } - - // The peasant desperately runs in place, trying to get away from the laser. - // Yet, despite all his limb flailing, he never manages to get anywhere. - ST_Util_DrawBlock(bitmap_info, StartupPics[PEASANT_INDEX + ((new_laser >> 1) & 3)], - ST_PEASANT_X, ST_PEASANT_Y, ST_PEASANT_WIDTH, ST_PEASANT_HEIGHT); -} - - -//========================================================================== -// -// ST_Util_PlanarToChunky4 -// -// Convert a 4-bpp planar image to chunky pixels. -// -//========================================================================== - -void ST_Util_PlanarToChunky4(uint8_t* dest, const uint8_t* src, int width, int height) -{ - int y, x; - const uint8_t* src1, * src2, * src3, * src4; - size_t plane_size = width / 8 * height; - - src1 = src; - src2 = src1 + plane_size; - src3 = src2 + plane_size; - src4 = src3 + plane_size; - - for (y = height; y > 0; --y) - { - for (x = width; x > 0; x -= 8) - { - // Pixels 0 and 1 - dest[0] = (*src4 & 0x80) | ((*src3 & 0x80) >> 1) | ((*src2 & 0x80) >> 2) | ((*src1 & 0x80) >> 3) | - ((*src4 & 0x40) >> 3) | ((*src3 & 0x40) >> 4) | ((*src2 & 0x40) >> 5) | ((*src1 & 0x40) >> 6); - // Pixels 2 and 3 - dest[1] = ((*src4 & 0x20) << 2) | ((*src3 & 0x20) << 1) | ((*src2 & 0x20)) | ((*src1 & 0x20) >> 1) | - ((*src4 & 0x10) >> 1) | ((*src3 & 0x10) >> 2) | ((*src2 & 0x10) >> 3) | ((*src1 & 0x10) >> 4); - // Pixels 4 and 5 - dest[2] = ((*src4 & 0x08) << 4) | ((*src3 & 0x08) << 3) | ((*src2 & 0x08) << 2) | ((*src1 & 0x08) << 1) | - ((*src4 & 0x04) << 1) | ((*src3 & 0x04)) | ((*src2 & 0x04) >> 1) | ((*src1 & 0x04) >> 2); - // Pixels 6 and 7 - dest[3] = ((*src4 & 0x02) << 6) | ((*src3 & 0x02) << 5) | ((*src2 & 0x02) << 4) | ((*src1 & 0x02) << 3) | - ((*src4 & 0x01) << 3) | ((*src3 & 0x01) << 2) | ((*src2 & 0x01) << 1) | ((*src1 & 0x01)); - dest += 4; - src1 += 1; - src2 += 1; - src3 += 1; - src4 += 1; - } - } -} - -//========================================================================== -// -// ST_Util_DrawBlock -// -//========================================================================== - -void ST_Util_DrawBlock(BitmapInfo* bitmap_info, const uint8_t* src, int x, int y, int bytewidth, int height) -{ - if (src == NULL) - { - return; - } - - int pitchshift = int(bitmap_info->bmiHeader.biBitCount == 4); - int destpitch = bitmap_info->bmiHeader.biWidth >> pitchshift; - uint8_t* dest = ST_Util_BitsForBitmap(bitmap_info) + (x >> pitchshift) + y * destpitch; - - ST_Util_InvalidateRect(bitmap_info, x, y, x + (bytewidth << pitchshift), y + height); - - if (bytewidth == 8) - { // progress notches - for (; height > 0; --height) - { - ((uint32_t*)dest)[0] = ((const uint32_t*)src)[0]; - ((uint32_t*)dest)[1] = ((const uint32_t*)src)[1]; - dest += destpitch; - src += 8; - } - } - else if (bytewidth == 2) - { // net progress notches - for (; height > 0; --height) - { - *((uint16_t*)dest) = *((const uint16_t*)src); - dest += destpitch; - src += 2; - } - } - else - { - for (; height > 0; --height) - { - memcpy(dest, src, bytewidth); - dest += destpitch; - src += bytewidth; - } - } -} - -//========================================================================== -// -// ST_Util_ClearBlock -// -//========================================================================== - -void ST_Util_ClearBlock(BitmapInfo* bitmap_info, uint8_t fill, int x, int y, int bytewidth, int height) -{ - int pitchshift = int(bitmap_info->bmiHeader.biBitCount == 4); - int destpitch = bitmap_info->bmiHeader.biWidth >> pitchshift; - uint8_t* dest = ST_Util_BitsForBitmap(bitmap_info) + (x >> pitchshift) + y * destpitch; - - ST_Util_InvalidateRect(bitmap_info, x, y, x + (bytewidth << pitchshift), y + height); - - while (height > 0) - { - memset(dest, fill, bytewidth); - dest += destpitch; - height--; - } -} - -//========================================================================== -// -// ST_Util_CreateBitmap -// -// Creates a BitmapInfoHeader, RgbQuad, and pixel data arranged -// consecutively in memory (in other words, a normal Windows BMP file). -// The BitmapInfoHeader will be filled in, and the caller must fill -// in the color and pixel data. -// -// You must pass 4 or 8 for color_bits. -// -//========================================================================== - -BitmapInfo* ST_Util_CreateBitmap(int width, int height, int color_bits) -{ - uint32_t size_image = (width * height) >> int(color_bits == 4); - BitmapInfo* bitmap_info = (BitmapInfo*)M_Malloc(sizeof(BitmapInfoHeader) + - (sizeof(RgbQuad) << color_bits) + size_image); - - // Initialize the header. - bitmap_info->bmiHeader.biSize = sizeof(BitmapInfoHeader); - bitmap_info->bmiHeader.biWidth = width; - bitmap_info->bmiHeader.biHeight = height; - bitmap_info->bmiHeader.biPlanes = 1; - bitmap_info->bmiHeader.biBitCount = color_bits; - bitmap_info->bmiHeader.biCompression = 0; - bitmap_info->bmiHeader.biSizeImage = size_image; - bitmap_info->bmiHeader.biXPelsPerMeter = 0; - bitmap_info->bmiHeader.biYPelsPerMeter = 0; - bitmap_info->bmiHeader.biClrUsed = 1 << color_bits; - bitmap_info->bmiHeader.biClrImportant = 0; - - return bitmap_info; -} - -//========================================================================== -// -// ST_Util_BitsForBitmap -// -// Given a bitmap created by ST_Util_CreateBitmap, returns the start -// address for the pixel data for the bitmap. -// -//========================================================================== - -uint8_t* ST_Util_BitsForBitmap(BitmapInfo* bitmap_info) -{ - return (uint8_t*)bitmap_info + sizeof(BitmapInfoHeader) + (sizeof(RgbQuad) << bitmap_info->bmiHeader.biBitCount); -} - -//========================================================================== -// -// ST_Util_FreeBitmap -// -// Frees all the data for a bitmap created by ST_Util_CreateBitmap. -// -//========================================================================== - -void ST_Util_FreeBitmap(BitmapInfo* bitmap_info) -{ - M_Free(bitmap_info); -} - -//========================================================================== -// -// ST_Util_BitmapColorsFromPlaypal -// -// Fills the bitmap palette from the PLAYPAL lump. -// -//========================================================================== - -void ST_Util_BitmapColorsFromPlaypal(BitmapInfo* bitmap_info) -{ - uint8_t playpal[768]; - - ReadPalette(Wads.GetNumForName("PLAYPAL"), playpal); - for (int i = 0; i < 256; ++i) - { - bitmap_info->bmiColors[i].rgbBlue = playpal[i * 3 + 2]; - bitmap_info->bmiColors[i].rgbGreen = playpal[i * 3 + 1]; - bitmap_info->bmiColors[i].rgbRed = playpal[i * 3]; - bitmap_info->bmiColors[i].rgbReserved = 0; - } -} - -//========================================================================== -// -// ST_Util_LoadFont -// -// Loads a monochrome fixed-width font. Every character is one byte -// (eight pixels) wide, so we can deduce the height of each character -// by looking at the size of the font data. -// -//========================================================================== - -uint8_t* ST_Util_LoadFont(const char* filename) -{ - int lumpnum, lumplen, height; - uint8_t* font; - - lumpnum = Wads.CheckNumForFullName(filename); - if (lumpnum < 0) - { // font not found - return NULL; - } - lumplen = Wads.LumpLength(lumpnum); - height = lumplen / 256; - if (height * 256 != lumplen) - { // font is a bad size - return NULL; - } - if (height < 6 || height > 36) - { // let's be reasonable here - return NULL; - } - font = new uint8_t[lumplen + 1]; - font[0] = height; // Store font height in the first byte. - Wads.ReadLump(lumpnum, font + 1); - return font; -} - -void ST_Util_FreeFont(uint8_t* font) -{ - delete[] font; -} - -//========================================================================== -// -// ST_Util_AllocTextBitmap -// -// Returns a bitmap properly sized to hold an 80x25 display of characters -// using the specified font. -// -//========================================================================== - -BitmapInfo* ST_Util_AllocTextBitmap(const uint8_t* font) -{ - BitmapInfo* bitmap = ST_Util_CreateBitmap(80 * 8, 25 * font[0], 4); - memcpy(bitmap->bmiColors, TextModePalette, sizeof(TextModePalette)); - return bitmap; -} - -//========================================================================== -// -// ST_Util_DrawTextScreen -// -// Draws the text screen to the bitmap. The bitmap must be the proper size -// for the font. -// -//========================================================================== - -void ST_Util_DrawTextScreen(BitmapInfo* bitmap_info, const uint8_t* text_screen, const uint8_t* font) -{ - int x, y; - - for (y = 0; y < 25; ++y) - { - for (x = 0; x < 80; ++x) - { - ST_Util_DrawChar(bitmap_info, font, x, y, text_screen[0], text_screen[1]); - text_screen += 2; - } - } -} - -//========================================================================== -// -// ST_Util_DrawChar -// -// Draws a character on the bitmap. X and Y specify the character cell, -// and fg and bg are 4-bit colors. -// -//========================================================================== - -void ST_Util_DrawChar(BitmapInfo* screen, const uint8_t* font, int x, int y, uint8_t charnum, uint8_t attrib) -{ - const uint8_t bg_left = attrib & 0x70; - const uint8_t fg = attrib & 0x0F; - const uint8_t fg_left = fg << 4; - const uint8_t bg = bg_left >> 4; - const uint8_t color_array[4] = { (uint8_t)(bg_left | bg), (uint8_t)(attrib & 0x7F), (uint8_t)(fg_left | bg), (uint8_t)(fg_left | fg) }; - const uint8_t* src = font + 1 + charnum * font[0]; - int pitch = screen->bmiHeader.biWidth >> 1; - uint8_t* dest = ST_Util_BitsForBitmap(screen) + x * 4 + y * font[0] * pitch; - - for (y = font[0]; y > 0; --y) - { - uint8_t srcbyte = *src++; - - // Pixels 0 and 1 - dest[0] = color_array[(srcbyte >> 6) & 3]; - // Pixels 2 and 3 - dest[1] = color_array[(srcbyte >> 4) & 3]; - // Pixels 4 and 5 - dest[2] = color_array[(srcbyte >> 2) & 3]; - // Pixels 6 and 7 - dest[3] = color_array[(srcbyte) & 3]; - dest += pitch; - } -} - -//========================================================================== -// -// ST_Util_UpdateTextBlink -// -// Draws the parts of the text screen that blink to the bitmap. The bitmap -// must be the proper size for the font. -// -//========================================================================== - -void ST_Util_UpdateTextBlink(BitmapInfo* bitmap_info, const uint8_t* text_screen, const uint8_t* font, bool on) -{ - int x, y; - - for (y = 0; y < 25; ++y) - { - for (x = 0; x < 80; ++x) - { - if (text_screen[1] & 0x80) - { - ST_Util_DrawChar(bitmap_info, font, x, y, on ? text_screen[0] : ' ', text_screen[1]); - ST_Util_InvalidateRect(bitmap_info, x * 8, y * font[0], x * 8 + 8, y * font[0] + font[0]); - } - text_screen += 2; - } - } -} diff --git a/src/win32/win32polyvideo.cpp b/src/win32/win32polyvideo.cpp deleted file mode 100644 index a12ea0517fa..00000000000 --- a/src/win32/win32polyvideo.cpp +++ /dev/null @@ -1,195 +0,0 @@ - -#include -#include "hardware.h" -#include "doomerrors.h" -#include - -EXTERN_CVAR(Bool, vid_vsync) - -bool ViewportLinearScale(); - -extern HWND Window; - -#include -#pragma comment(lib, "d3d9.lib") - -#ifndef D3DPRESENT_FORCEIMMEDIATE -#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L // MinGW -#endif - -namespace -{ - int SrcWidth = 0; - int SrcHeight = 0; - int ClientWidth = 0; - int ClientHeight = 0; - bool CurrentVSync = false; - - IDirect3D9Ex *d3d9 = nullptr; - IDirect3DDevice9Ex *device = nullptr; - IDirect3DSurface9* surface = nullptr; -} - -void I_PolyPresentInit() -{ - Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9); - if (!d3d9) - { - I_FatalError("Direct3DCreate9 failed"); - } - - RECT rect = {}; - GetClientRect(Window, &rect); - - ClientWidth = rect.right; - ClientHeight = rect.bottom; - - D3DPRESENT_PARAMETERS pp = {}; - pp.Windowed = true; - pp.SwapEffect = D3DSWAPEFFECT_FLIPEX; - pp.BackBufferWidth = ClientWidth; - pp.BackBufferHeight = ClientHeight; - pp.BackBufferCount = 1; - pp.hDeviceWindow = Window; - pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; - - HRESULT result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, nullptr, &device); - if (FAILED(result)) - { - I_FatalError("IDirect3D9.CreateDevice failed"); - } -} - -uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch) -{ - HRESULT result; - - RECT rect = {}; - GetClientRect(Window, &rect); - if (rect.right != ClientWidth || rect.bottom != ClientHeight || CurrentVSync != vsync) - { - if (surface) - { - surface->Release(); - surface = nullptr; - } - - CurrentVSync = vsync; - ClientWidth = rect.right; - ClientHeight = rect.bottom; - - D3DPRESENT_PARAMETERS pp = {}; - pp.Windowed = true; - pp.SwapEffect = D3DSWAPEFFECT_FLIPEX; - pp.BackBufferWidth = ClientWidth; - pp.BackBufferHeight = ClientHeight; - pp.BackBufferCount = 1; - pp.hDeviceWindow = Window; - pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; - device->Reset(&pp); - } - - if (SrcWidth != w || SrcHeight != h || !surface) - { - if (surface) - { - surface->Release(); - surface = nullptr; - } - - SrcWidth = w; - SrcHeight = h; - result = device->CreateOffscreenPlainSurface(SrcWidth, SrcHeight, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surface, 0); - if (FAILED(result)) - { - I_FatalError("IDirect3DDevice9.CreateOffscreenPlainSurface failed"); - } - } - - D3DLOCKED_RECT lockrect = {}; - result = surface->LockRect(&lockrect, nullptr, D3DLOCK_DISCARD); - if (FAILED(result)) - { - pitch = 0; - return nullptr; - } - - pitch = lockrect.Pitch; - return (uint8_t*)lockrect.pBits; -} - -void I_PolyPresentUnlock(int x, int y, int width, int height) -{ - surface->UnlockRect(); - - IDirect3DSurface9 *backbuffer = nullptr; - HRESULT result = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); - if (FAILED(result)) - return; - - result = device->BeginScene(); - if (SUCCEEDED(result)) - { - int count = 0; - D3DRECT clearrects[4]; - if (y > 0) - { - clearrects[count].x1 = 0; - clearrects[count].y1 = 0; - clearrects[count].x2 = ClientWidth; - clearrects[count].y2 = y; - count++; - } - if (y + height < ClientHeight) - { - clearrects[count].x1 = 0; - clearrects[count].y1 = y + height; - clearrects[count].x2 = ClientWidth; - clearrects[count].y2 = ClientHeight; - count++; - } - if (x > 0) - { - clearrects[count].x1 = 0; - clearrects[count].y1 = y; - clearrects[count].x2 = x; - clearrects[count].y2 = y + height; - count++; - } - if (x + width < ClientWidth) - { - clearrects[count].x1 = x + width; - clearrects[count].y1 = y; - clearrects[count].x2 = ClientWidth; - clearrects[count].y2 = y + height; - count++; - } - if (count > 0) - device->Clear(count, clearrects, D3DCLEAR_TARGET, 0, 0.0f, 0); - - RECT srcrect = {}, dstrect = {}; - srcrect.right = SrcWidth; - srcrect.bottom = SrcHeight; - dstrect.left = x; - dstrect.top = y; - dstrect.right = x + width; - dstrect.bottom = y + height; - if (ViewportLinearScale()) - device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_LINEAR); - else - device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_POINT); - - result = device->EndScene(); - if (SUCCEEDED(result)) - device->PresentEx(nullptr, nullptr, 0, nullptr, CurrentVSync ? 0 : D3DPRESENT_FORCEIMMEDIATE); - } - - backbuffer->Release(); -} - -void I_PolyPresentDeinit() -{ - if (surface) surface->Release(); - if (device) device->Release(); - if (d3d9) d3d9->Release(); -} diff --git a/src/win32/win32polyvideo.h b/src/win32/win32polyvideo.h deleted file mode 100644 index e1ad6d503b6..00000000000 --- a/src/win32/win32polyvideo.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "win32basevideo.h" -#include "c_cvars.h" -#include "rendering/polyrenderer/backend/poly_framebuffer.h" - -EXTERN_CVAR(Bool, fullscreen) - -class Win32PolyVideo : public Win32BaseVideo -{ -public: - void Shutdown() override - { - } - - DFrameBuffer *CreateFrameBuffer() override - { - auto fb = new PolyFrameBuffer(m_hMonitor, fullscreen); - return fb; - } -}; diff --git a/src/win32/win32vulkanvideo.h b/src/win32/win32vulkanvideo.h deleted file mode 100644 index 05e5c2d550d..00000000000 --- a/src/win32/win32vulkanvideo.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "win32basevideo.h" -#include "c_cvars.h" -#include "rendering/vulkan/system/vk_framebuffer.h" - - -EXTERN_CVAR(Bool, fullscreen) - -//========================================================================== -// -// -// -//========================================================================== - -class Win32VulkanVideo : public Win32BaseVideo -{ - VulkanDevice *device = nullptr; -public: - Win32VulkanVideo() - { - device = new VulkanDevice(); - } - - ~Win32VulkanVideo() - { - delete device; - } - - void Shutdown() override - { - delete device; - device = nullptr; - } - - DFrameBuffer *CreateFrameBuffer() override - { - auto fb = new VulkanFrameBuffer(m_hMonitor, fullscreen, device); - return fb; - } - -protected: -}; diff --git a/src/win32/zdoom.natvis b/src/win32/zdoom.natvis deleted file mode 100644 index 15659432955..00000000000 --- a/src/win32/zdoom.natvis +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - Size = {Count} - - Count - Most - - Count - (value_type*)Array - - - - - - Size = {Count} - - Count - - Count - (value_type*)Array - - - - - - Size = {Count} - - Count - - Count - (value_type*)Array - - - - - - {FName::NameData.NameArray[Index].Text, s} - - - - {Chars, s} - - ((FStringData*)Chars - 1)->Len - ((FStringData*)Chars - 1)->AllocLen - ((FStringData*)Chars - 1)->RefCount - - - - - {Degrees} - - - - {TypeName} - - - - {Class->TypeName} - - - - <NULL> - {o->Class->TypeName} - - - - <None> - {TexMan.Textures[texnum].Texture->Name} - - texnum - TexMan.Textures[texnum].Texture - - - - - <No Sound Engine> - <None> - {soundEngine->S_sfx[ID].name} - - - diff --git a/src/win32/zdoom.rc b/src/win32/zdoom.rc index 6ac1a23406b..6536ee91f4c 100644 --- a/src/win32/zdoom.rc +++ b/src/win32/zdoom.rc @@ -110,9 +110,9 @@ BEGIN IDD_IWADDIALOG, DIALOG BEGIN LEFTMARGIN, 5 - RIGHTMARGIN, 222 + RIGHTMARGIN, 223 TOPMARGIN, 7 - BOTTOMMARGIN, 242 + BOTTOMMARGIN, 241 END IDD_EAXPROPERTYLIST, DIALOG @@ -202,32 +202,6 @@ END // Dialog // -IDD_IWADDIALOG DIALOGEX 0, 0, 224, 249 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_APPWINDOW -CAPTION "Welcome" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - ICON IDI_ICON1,IDC_STATIC,7,7,20,20 - LTEXT "Welcome to GZDoom!",IDC_STATIC,42,8,180,8 - LTEXT "",IDC_WELCOME_VERSION,42,18,180,8 - GROUPBOX "IWAD selection",IDC_STATIC,8,32,208,117 - LTEXT "Select which game file (IWAD) to run.",IDC_STATIC,12,44,190,8 - LISTBOX IDC_IWADLIST,12,56,200,87,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Video settings",IDC_STATIC,8,155,109,52 - CONTROL "Fullscreen",IDC_WELCOME_FULLSCREEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,65,167,48,10 - GROUPBOX "Resource settings",IDC_STATIC,123,155,95,52 - CONTROL "Disable autoload",IDC_WELCOME_NOAUTOLOAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,170,65,10 - CONTROL "Load lights",IDC_WELCOME_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,180,51,10 - CONTROL "Load brightmaps",IDC_WELCOME_BRIGHTMAPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,190,65,10 - CONTROL "Don't ask me this again",IDC_DONTASKIWAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,73,211,87,10 - DEFPUSHBUTTON "Play GZDoom",IDOK,8,228,90,14 - PUSHBUTTON "Exit",IDCANCEL,166,228,50,14 - CONTROL "OpenGL",IDC_WELCOME_VULKAN1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,167,41,10 - CONTROL "Vulkan",IDC_WELCOME_VULKAN2,"Button",BS_AUTORADIOBUTTON,13,177,37,10 - CONTROL "SoftPoly",IDC_WELCOME_VULKAN3,"Button",BS_AUTORADIOBUTTON,13,188,43,10 -END - IDD_CRASHDIALOG DIALOGEX 0, 0, 415, 308 STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU @@ -236,7 +210,7 @@ CAPTION "GZDoom Very Fatal Error" FONT 8, "MS Shell Dlg", 400, 0, 0x0 BEGIN CONTROL "",IDC_CRASHTAB,"SysTabControl32",WS_TABSTOP,4,4,404,280 - PUSHBUTTON "Save Report to Disk...",IDC_SAVEREPORT,242,289,91,14 + PUSHBUTTON "&Save Report to Disk...",IDC_SAVEREPORT,242,289,91,14 PUSHBUTTON "&Discard Report",IDNO,338,289,70,14 END @@ -270,14 +244,15 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CL EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "Quit",IDOK,133,7,50,14 + DEFPUSHBUTTON "E&xit",IDOK,133,7,50,14 + PUSHBUTTON "&Restart",IDC_BUTTON1,79,7,50,14 END IDD_NETSTARTPANE DIALOGEX 0, 0, 189, 55 STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - PUSHBUTTON "Abort Network Game",IDCANCEL,45,34,89,14 + PUSHBUTTON "&Abort Network Game",IDCANCEL,45,34,89,14 CONTROL "",IDC_NETSTARTMESSAGE,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,7,7,116,8 CONTROL "",IDC_NETSTARTCOUNT,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,153,7,29,8,WS_EX_RIGHT CONTROL "",IDC_NETSTARTPROGRESS,"msctls_progress32",WS_BORDER,7,18,175,10 @@ -313,7 +288,7 @@ END // Generated from the TEXTINCLUDE 3 resource. // #ifndef NO_MANIFEST - CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "zdoom.exe.manifest" + CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "..\\common\\platform\\win32\\manifest.xml" #endif ///////////////////////////////////////////////////////////////////////////// @@ -356,7 +331,6 @@ BEGIN VALUE "Translation", 0x409, 1200 END END - ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/src/zzautozend.cpp b/src/zzautozend.cpp deleted file mode 100644 index 18c020310c7..00000000000 --- a/src/zzautozend.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -** autozend.cpp -** This file contains the tails of lists stored in special data segments -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -** See autostart.cpp for an explanation of why I do things like this. -*/ - -#include "autosegs.h" - -#if defined(_MSC_VER) - -#pragma section(".areg$z",read) -__declspec(allocate(".areg$z")) void *const ARegTail = 0; - -#pragma section(".creg$z",read) -__declspec(allocate(".creg$z")) void *const CRegTail = 0; - -#pragma section(".freg$z",read) -__declspec(allocate(".freg$z")) void *const FRegTail = 0; - -#pragma section(".greg$z",read) -__declspec(allocate(".greg$z")) void *const GRegTail = 0; - -#pragma section(".yreg$z",read) -__declspec(allocate(".yreg$z")) void *const YRegTail = 0; - - -#elif defined(__GNUC__) - -#include "doomtype.h" - -void *const ARegTail __attribute__((section(SECTION_AREG))) = 0; -void *const CRegTail __attribute__((section(SECTION_CREG))) = 0; -void *const FRegTail __attribute__((section(SECTION_FREG))) = 0; -void *const GRegTail __attribute__((section(SECTION_GREG))) = 0; -void *const YRegTail __attribute__((section(SECTION_YREG))) = 0; - -#else - -#error Please fix autozend.cpp for your compiler - -#endif diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index b3fed70ff39..25f4d243c49 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required( VERSION 2.8.7 ) +cmake_minimum_required( VERSION 3.16 ) add_subdirectory( re2c ) add_subdirectory( lemon ) diff --git a/tools/lemon/CMakeLists.txt b/tools/lemon/CMakeLists.txt index e092cf6e92c..a4da050b3db 100644 --- a/tools/lemon/CMakeLists.txt +++ b/tools/lemon/CMakeLists.txt @@ -1,14 +1,14 @@ -cmake_minimum_required( VERSION 2.8.7 ) +cmake_minimum_required( VERSION 3.16 ) if( NOT CMAKE_CROSSCOMPILING ) set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG" ) add_executable( lemon lemon.c ) set( CROSS_EXPORTS ${CROSS_EXPORTS} lemon PARENT_SCOPE ) -endif() -# Lemon wants lempar.c in its directory -add_custom_command( TARGET lemon - POST_BUILD - COMMAND echo $ - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/lempar.c $ ) + # Lemon wants lempar.c in its directory + add_custom_command( TARGET lemon + POST_BUILD + COMMAND echo $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/lempar.c $ ) +endif() diff --git a/tools/re2c/CMakeLists.txt b/tools/re2c/CMakeLists.txt index b362a3b843b..6b888773c5d 100644 --- a/tools/re2c/CMakeLists.txt +++ b/tools/re2c/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required( VERSION 2.8.7 ) +cmake_minimum_required( VERSION 3.16 ) if( NOT CMAKE_CROSSCOMPILING ) diff --git a/tools/zipdir/CMakeLists.txt b/tools/zipdir/CMakeLists.txt index 6a36b2cb5dd..d08ca093c4b 100644 --- a/tools/zipdir/CMakeLists.txt +++ b/tools/zipdir/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required( VERSION 2.8.7 ) +cmake_minimum_required( VERSION 3.16 ) if( NOT CMAKE_CROSSCOMPILING ) - include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" ) + include_directories( SYSTEM "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" ) add_executable( zipdir zipdir.c ) - target_link_libraries( zipdir ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} lzma ) + target_link_libraries( zipdir miniz ${BZIP2_LIBRARIES} lzma ) set( CROSS_EXPORTS ${CROSS_EXPORTS} zipdir PARENT_SCOPE ) endif() diff --git a/tools/zipdir/zipdir.c b/tools/zipdir/zipdir.c index 4cb98c1389a..4ae81d8e3ea 100644 --- a/tools/zipdir/zipdir.c +++ b/tools/zipdir/zipdir.c @@ -46,7 +46,7 @@ #include #include #include -#include "zlib.h" +#include #include "bzlib.h" #include "LzmaEnc.h" #include "7zVersion.h" @@ -781,6 +781,8 @@ void write_zip(const char *zipname, dir_tree_t *trees, int update) if (central_dir == NULL) { fprintf(stderr, "Could not read central directory from %s. (Is it a zipfile?)\n", zipname); + fclose(ozip); + ozip = NULL; update = 0; } } diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 00000000000..0df558c005a --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", + "builtin-baseline": "2c401863dd54a640aeb26ed736c55489c079323b", + "features": + { + "vcpkg-libvpx": + { + "description": "Use libvpx provided by vcpkg on Windows", + "dependencies": [ + { + "name": "libvpx", + "default-features": false, + "platform": "(!windows & static) | (windows & static & staticcrt)" + } + ] + }, + "vcpkg-openal-soft": + { + "description": "Use openal-soft provided by vcpkg.", + "dependencies": [ + { + "name": "openal-soft", + "default-features": false, + "platform": "(!windows & static) | (windows & static & staticcrt)" + } + ] + } + }, + "dependencies": [ + { + "name": "bzip2", + "platform": "(!windows & static) | (windows & static & staticcrt)" + }, + { + "name": "libvpx", + "platform": "!windows & static" + }, + { + "name": "gtk3", + "platform": "!windows & !osx & static" + }, + { + "name": "glib", + "platform": "!windows & !osx & static" + } + ] +} diff --git a/wadsrc/CMakeLists.txt b/wadsrc/CMakeLists.txt index 80189a328cd..5128f20a05d 100644 --- a/wadsrc/CMakeLists.txt +++ b/wadsrc/CMakeLists.txt @@ -1,3 +1 @@ -cmake_minimum_required( VERSION 2.8.7 ) - add_pk3(gzdoom.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index aacd2b5cf10..21946aa17cc 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -24,7 +24,6 @@ A80E7EE40E0D0C76A6FBD242BE29FE27 // map15 { stairs maskedmidtex - corpsegibs vileghosts } @@ -99,12 +98,15 @@ C7A2FAFB0AFB2632C50AD625CDB50E51 // Reverie map18 1E998262EE319B7D088E01DE782E6B41 // Mayhem 2013 map05 A81E2734F735A82720D8E0F1442BA0C9 // Imp's [sic] are Ghost Gods map01 { - corpsegibs vileghosts } // invert the sorting order of overlapping sprites at the same spot 551D6B416EB3324790BC0F0F74B49600 // Strain map13 +{ + spritesort +} + 2F49C29691F8565F0B99B27FCF2627E6 // Astrostein 1 MAP01 55A741F9C2955C2B06F2387E45ED6C62 // MAP02 4E7286B735671A942C54FAC6CB52A8C3 // MAP03 @@ -133,6 +135,14 @@ AB1A6C1D3898D4259C0645306939374C // map15 CA267398C9B3A8F79349D3394F8B2106 // map20 { spritesort + nombf21 +} + +62C723647C531A15F5647BA8B4818392 // riii.wad map11 +178605D81D8E8C4B78D91BC72C8A89ED // ht.wad map31 +F1EAD555B8AF5CB97D42BA632C0FA165 // cchest2.wad map19 +{ + nombf21 } 1D9E43988940CCD3555724E15DD8B1AB // Happy Time Circus map01 has bad teleporters @@ -187,6 +197,7 @@ E0E5517B7928E88B88F6A5B77AC449DF // Darken2.wad map23 - Nodes go out of bounds/b 3DEE4EFEFAF3260C800A30734F54CE75 // Hellbound, map14 5FAA25F5A6AAB3409CAE0AF87F910341 // DOOM.wad e1m6 94893A0DC429A22ADC4B3A73DA537E16 // DOOM2.WAD map25 +9D84B423D8FD28553DDE23B55F97CF4A // PLUTONIA.WAD map25 D5F64E02679A81B82006AF34A6A8EAC3 // plutonia.wad map32 BA4860C7A2F5D705DB32A1A38DB77EC4 // pl2.wad map10 EDA5CE7C462BD171BF8110AC56B67857 // pl2.wad map11 @@ -194,6 +205,19 @@ A9A9A728E689266939C1B71655F320CA // pl2.wad map25 62CA74092FC88C1E7FE2D0B1A8034E29 // pl2.wad map29 19E1CFD717FC6BBA9371F0F529B4CDFF // ur_final.wad map27 836E09559FF22A7A37C2587F7EAFF1EE // Requiem MAP29 - Incorrect sector lighting and vanishing items +35F80C968E1D41D37E543AF74F862A31 // Memento Mori map15 +F73A74BD9346AD3B6AF8246F7B389A1E // Memento Mori map20 +9D7288F7235157D8478E409CD7AE9F68 // akeldama.wad map26 +DEABADC01FE74273B7616F744EDF66D0 // dbimpact.wad e1m3 +4FDDBEED4FC6092095955FAE82C059EE // 1024.wad map02 +984A24A876E2530AEA9FD10481C362AF // sdoom2.wad map18 +40EE423E612AAAD6921AD803F62A6FCC // sdoom2.wad map23 +DCC92553625E34F94B2ED1B2719A2CB6 // sdoom2.wad map24 +D04E38921EC29D8665EA4F019F9921E5 // njdoom1.wad e1m6 +A139B45A843E26EAAFBE88093723D795 // njdoom2.wad map13 +EB61E33DDB0BABA174DF2D4C06E5536E // njdoom1.wad e3m4 +718D80A751F33558EDB0315668FDCD7F // njdoom2.wad map23 +5366DD3789F5B6E3CA455B949455F458 // tnt2fix2.wad map01 { rebuildnodes } @@ -252,6 +276,8 @@ D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 5BDA34DA60C0530794CC1EA2DA017976 // doom2.wad map14 5B3F118B337BFBFB8D5C81E98AF7B71D // Ancient Aliens map23 7C1913DEE396BA26CFF22A0E9369B7D2 // Nuke Mine, e1m2 +BFC69170CCE3550A0A53C4A556E7FD69 // btsx_e2a.wad map06 +566E9CCD2F2F41442E57A9C76074BF1A // pc_cp2.wad MAP27 { pointonline } @@ -290,3 +316,71 @@ F50C91A05E1A1E646690517641F0D1DD // daedalus.wad map19 { scriptwait } + +41C12F740CD7635E4595D3661237992F // obtic.wad map01 (untested) +{ + shorttex +} + +65C155579BEA34642A7B83DF5481B29B // Conf256.pk3 CONF55 +{ + nomirrors +} + +F1EB6927F53047F219A54997DAD9DC81 // mm2.wad map20 +{ + rebuildnodes + trace +} + +BA2247ED1465C8107192AC4215B2A5F3 // saturnia.wad map10 +{ + fdteleport +} + +// Total Chaos Directors Cut 1.40 +1C9D1306F76EA85558C4BD3BC4C7363C // TITLEMAP - retro & full +5138C10892976F7F8D58E73DF9BD1D35 // MADNESS - retro +EA96F1D692B354B2388F34CD9F0E4CDC // MADNESS - full +F7658930D904959FF43BE0A374E1E356 // MAP01 - retro & full +7C5508701E4AC3D1A00985409EC45EFD // NG1 - retro +C4C2CBACCF08F68AFC341557AEE6A727 // NG2 - retro +37853C2D108A56241E51C785CF0857D4 // NG3 - retro +0B14A4C8223F410816292E7EC578C625 // NG4 - retro +04F3D083D787DE15ACE8661163A6CA14 // NG5 - retro +F52D8B176EEFD374F342F3D9B3DEFC61 // NG6 - retro +A4D6321677AA6E7BA5CD93B39D1D063B // NG1 - full +3B4BAD71CFD7C9C1B860FB66363AEDF2 // NG2 - full +DD660C6E6E3F6F7A615D7234B7A56F59 // NG3 - full +74C68D18E6BD94B386163C4F672D3BFD // NG4 - full +835052B4078B33206675A4BB240333C8 // NG5 - full +0D3A15105CC16BCA0D06CA864AF0B58D // NG6 - full +0E186784223C02A19420BB49081FB734 // NG7 - retro & full +B57F6841E4E5C3989AA58ADDE9812762 // NGD1 - retro +A979225DED3F99E22B50FC6D9CE0355F // NGD2 - retro +95CE0EA31B85BA4D65A189B2D86D69A3 // NGD3 - retro +C1DB8E3B014A548383FDF95D999DF948 // NGD1 - full +6DB1AF715DA54226DC8D958B07FEC7DA // NGD2 - full +E6386D98F733E8D965865859E6056AFA // NGD3 - full +62958B31FB86C109B91BF2DDB9E93D2E // REGRESS - retro +84B499C6179E845265DF4BBF0D3AD361 // RESOLVE - retro +CC4D0C838C0EC5F710E220F3D77A1509 // SURFACE - retro +9FB4164A268007D7D1A630A4460C1CBB // ARRIVAL - retro +0F6AFE40771DCF448C77B6028CB53336 // REGRESS - full +B6E841EC4E5B45D90E3D4CFF805D192E // RESOLVE - full +80098CA75B3FCDE714E10832A8A08185 // SURFACE - full +EF8AA935168FED4393D68DAE04613106 // ARRIVAL - full +60C9D10D3FFDEF25E3131839FC50E1AD // CHAOS - retro +37325C08B6466A1760CA25D0D4176A64 // CROSS - retro +4F032EA6B61A5A42B1B6A7EDC8D5667B // CHAOS - full +D08C3FED35FE0489CFFAB6088FE79B3A // CROSS - full +859662ADA3A4CF634E8B7CE32B8ACB80 // CTEST - retro & full +1A3D2981D32783FED2BE7BA1587809E5 // DECAY - retro +2903FAAB2FBCD516F0559F5799EEEF14 // DECAY - full +A7898E72ED8D2C679DF18D6BC5DCC485 // FINALE - retro +EBD9BB5E7719F6E5042F12B3AE670104 // FORGOT - retro +A318D63145AA0A454475FBE426567896 // FINALE - full +C58AA89A5ACDC7F16BDA68428E31C555 // FORGOT - full +{ + noacsargcheck +} diff --git a/wadsrc/static/decaldef.txt b/wadsrc/static/decaldef.txt index e620d7816d3..ea67cc86e26 100644 --- a/wadsrc/static/decaldef.txt +++ b/wadsrc/static/decaldef.txt @@ -206,7 +206,7 @@ decal BloodSmear1 decal BloodSmear2 { - pic BSMEAR1 + pic BSMEAR2 x-scale 0.625 y-scale 0.625 shade "BloodDefault" @@ -1091,6 +1091,8 @@ generator CrossbowFX1 CrossbowScorch generator CrossbowFX2 CrossbowScorch generator CrossbowFX3 CrossbowScorch2 generator MaceFX1 BaronScorch +generator MaceFX2 BaronScorch +generator MaceFX3 BaronScorch generator MaceFX4 BFGScorch generator Blaster RailScorchLower generator BlasterFX1 HImpScorch diff --git a/wadsrc/static/defbinds.txt b/wadsrc/static/defbinds.txt deleted file mode 100644 index 420d22432e7..00000000000 --- a/wadsrc/static/defbinds.txt +++ /dev/null @@ -1,103 +0,0 @@ -/* Default keybindings for all games */ - -` toggleconsole -1 "slot 1" -2 "slot 2" -3 "slot 3" -4 "slot 4" -5 "slot 5" -6 "slot 6" -7 "slot 7" -8 "slot 8" -9 "slot 9" -0 "slot 0" -[ invprev -] invnext -mwheelleft invprev -mwheelright invnext -enter invuse -- sizedown -= sizeup -ctrl +attack -alt +strafe -shift +speed -space +use -rightarrow +right -leftarrow +left -uparrow +forward -downarrow +back -, +moveleft -. +moveright -mouse1 +attack -mouse2 +strafe -mouse3 +forward -mouse4 +speed -capslock "toggle cl_run" -f1 menu_help -f2 menu_save -f3 menu_load -f4 menu_options -f5 menu_display -f6 quicksave -f7 menu_endgame -f8 togglemessages -f9 quickload -f11 bumpgamma -f10 menu_quit -tab togglemap -pause pause -sysrq screenshot -t messagemode -\ +showscores -f12 spynext -mwheeldown weapnext -mwheelup weapprev - -// Originally just for Heretic, Hexen, and Strife. -// I can't see why they shouldn't be for Doom or Chex either. -pgup +moveup -ins +movedown -home land -pgdn +lookup -del +lookdown -end centerview - -// Generic joystick buttons -joy1 +attack -joy2 +strafe -joy3 +speed -joy4 +use - -// Xbox 360 / PS2 controllers -pad_a +use -pad_y +jump -rtrigger +attack -ltrigger +altattack -lshoulder weapprev -rshoulder weapnext -dpadleft invprev -dpadright invnext -dpaddown invuse -dpadup togglemap -pad_start pause -pad_back menu_main -lthumb crouch - - -/* Default automap bindings */ -mapbind f am_togglefollow -mapbind g am_togglegrid -mapbind p am_toggletexture -mapbind m am_setmark -mapbind c am_clearmarks -mapbind 0 am_gobig -mapbind rightarrow +am_panright -mapbind leftarrow +am_panleft -mapbind uparrow +am_panup -mapbind downarrow +am_pandown -mapbind - +am_zoomout -mapbind = +am_zoomin -mapbind kp- +am_zoomout -mapbind kp+ +am_zoomin -mapbind mwheelup "am_zoom 1.2" -mapbind mwheeldown "am_zoom -1.2" diff --git a/wadsrc/static/dehsupp.txt b/wadsrc/static/dehsupp.txt index 9a4ba032b9b..59858975f25 100644 --- a/wadsrc/static/dehsupp.txt +++ b/wadsrc/static/dehsupp.txt @@ -536,7 +536,7 @@ SoundMap "brain/sight", "brain/pain", "brain/death", - "fatso/attack", + "fatso/raiseguns", "fatso/death", "wolfss/sight", "wolfss/death", @@ -551,6 +551,249 @@ SoundMap "dog/active", "dog/death", "dog/pain", + // Padding -- DEHEXTRA's new sound range + // starts at sound ID 500, so we need + // to insert a bunch of blanks in between. + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","","","","","", + "","","","","","", + //Crispy/Retro (DEHEXTRA) + "dehextra/sound000", + "dehextra/sound001", + "dehextra/sound002", + "dehextra/sound003", + "dehextra/sound004", + "dehextra/sound005", + "dehextra/sound006", + "dehextra/sound007", + "dehextra/sound008", + "dehextra/sound009", + "dehextra/sound010", + "dehextra/sound011", + "dehextra/sound012", + "dehextra/sound013", + "dehextra/sound014", + "dehextra/sound015", + "dehextra/sound016", + "dehextra/sound017", + "dehextra/sound018", + "dehextra/sound019", + "dehextra/sound020", + "dehextra/sound021", + "dehextra/sound022", + "dehextra/sound023", + "dehextra/sound024", + "dehextra/sound025", + "dehextra/sound026", + "dehextra/sound027", + "dehextra/sound028", + "dehextra/sound029", + "dehextra/sound030", + "dehextra/sound031", + "dehextra/sound032", + "dehextra/sound033", + "dehextra/sound034", + "dehextra/sound035", + "dehextra/sound036", + "dehextra/sound037", + "dehextra/sound038", + "dehextra/sound039", + "dehextra/sound040", + "dehextra/sound041", + "dehextra/sound042", + "dehextra/sound043", + "dehextra/sound044", + "dehextra/sound045", + "dehextra/sound046", + "dehextra/sound047", + "dehextra/sound048", + "dehextra/sound049", + "dehextra/sound050", + "dehextra/sound051", + "dehextra/sound052", + "dehextra/sound053", + "dehextra/sound054", + "dehextra/sound055", + "dehextra/sound056", + "dehextra/sound057", + "dehextra/sound058", + "dehextra/sound059", + "dehextra/sound060", + "dehextra/sound061", + "dehextra/sound062", + "dehextra/sound063", + "dehextra/sound064", + "dehextra/sound065", + "dehextra/sound066", + "dehextra/sound067", + "dehextra/sound068", + "dehextra/sound069", + "dehextra/sound070", + "dehextra/sound071", + "dehextra/sound072", + "dehextra/sound073", + "dehextra/sound074", + "dehextra/sound075", + "dehextra/sound076", + "dehextra/sound077", + "dehextra/sound078", + "dehextra/sound079", + "dehextra/sound080", + "dehextra/sound081", + "dehextra/sound082", + "dehextra/sound083", + "dehextra/sound084", + "dehextra/sound085", + "dehextra/sound086", + "dehextra/sound087", + "dehextra/sound088", + "dehextra/sound089", + "dehextra/sound090", + "dehextra/sound091", + "dehextra/sound092", + "dehextra/sound093", + "dehextra/sound094", + "dehextra/sound095", + "dehextra/sound096", + "dehextra/sound097", + "dehextra/sound098", + "dehextra/sound099", + "dehextra/sound100", + "dehextra/sound101", + "dehextra/sound102", + "dehextra/sound103", + "dehextra/sound104", + "dehextra/sound105", + "dehextra/sound106", + "dehextra/sound107", + "dehextra/sound108", + "dehextra/sound109", + "dehextra/sound110", + "dehextra/sound111", + "dehextra/sound112", + "dehextra/sound113", + "dehextra/sound114", + "dehextra/sound115", + "dehextra/sound116", + "dehextra/sound117", + "dehextra/sound118", + "dehextra/sound119", + "dehextra/sound120", + "dehextra/sound121", + "dehextra/sound122", + "dehextra/sound123", + "dehextra/sound124", + "dehextra/sound125", + "dehextra/sound126", + "dehextra/sound127", + "dehextra/sound128", + "dehextra/sound129", + "dehextra/sound130", + "dehextra/sound131", + "dehextra/sound132", + "dehextra/sound133", + "dehextra/sound134", + "dehextra/sound135", + "dehextra/sound136", + "dehextra/sound137", + "dehextra/sound138", + "dehextra/sound139", + "dehextra/sound140", + "dehextra/sound141", + "dehextra/sound142", + "dehextra/sound143", + "dehextra/sound144", + "dehextra/sound145", + "dehextra/sound146", + "dehextra/sound147", + "dehextra/sound148", + "dehextra/sound149", + "dehextra/sound150", + "dehextra/sound151", + "dehextra/sound152", + "dehextra/sound153", + "dehextra/sound154", + "dehextra/sound155", + "dehextra/sound156", + "dehextra/sound157", + "dehextra/sound158", + "dehextra/sound159", + "dehextra/sound160", + "dehextra/sound161", + "dehextra/sound162", + "dehextra/sound163", + "dehextra/sound164", + "dehextra/sound165", + "dehextra/sound166", + "dehextra/sound167", + "dehextra/sound168", + "dehextra/sound169", + "dehextra/sound170", + "dehextra/sound171", + "dehextra/sound172", + "dehextra/sound173", + "dehextra/sound174", + "dehextra/sound175", + "dehextra/sound176", + "dehextra/sound177", + "dehextra/sound178", + "dehextra/sound179", + "dehextra/sound180", + "dehextra/sound181", + "dehextra/sound182", + "dehextra/sound183", + "dehextra/sound184", + "dehextra/sound185", + "dehextra/sound186", + "dehextra/sound187", + "dehextra/sound188", + "dehextra/sound189", + "dehextra/sound190", + "dehextra/sound191", + "dehextra/sound192", + "dehextra/sound193", + "dehextra/sound194", + "dehextra/sound195", + "dehextra/sound196", + "dehextra/sound197", + "dehextra/sound198", + "dehextra/sound199", }; @@ -942,13 +1185,37 @@ WeaponNames // when parsing a DEHACKED lump. Aliases { - A_Mushroom, A_Mushroom, 5, - A_Spawn, A_SpawnItem, 5, - A_Turn, A_Turn, 1, - A_Face, A_SetAngle, 1, - A_Scratch, A_CustomMeleeAttack, 5, // 19 characters for "A_CustomMeleeAttack"! - A_PlaySound, A_PlaySound, 5, // A function name any longer and the definition - A_RandomJump, A_Jump, 3, // for CodePointerAlias would need to be updated. - A_LineEffect, A_LineEffect, 2, - A_NailBomb, A_Explode, 7, + A_Mushroom, A_Mushroom, + A_Spawn, A_SpawnItem, + A_Turn, A_Turn, + A_Face, A_SetAngle, + A_Scratch, A_CustomMeleeAttack, + A_PlaySound, A_PlaySound, + A_RandomJump, A_Jump, + A_LineEffect, A_LineEffect, + A_SpawnObject, MBF21_SpawnObject, + A_MonsterProjectile, MBF21_MonsterProjectile, + A_MonsterBulletAttack, MBF21_MonsterBulletAttack, + A_MonsterMeleeAttack, MBF21_MonsterMeleeAttack, + A_RadiusDamage, A_RadiusDamage, + A_HealChase, MBF21_HealChase, + A_SeekTracer, MBF21_SeekTracer, + A_FindTracer, A_FindTracer, + A_JumpIfHealthBelow, MBF21_JumpIfHealthBelow, + A_JumpIfTargetInSight, MBF21_JumpIfTargetInSight, + A_JumpIfTargetCloser, MBF21_JumpIfTargetCloser, + A_JumpIfTracerInSight, MBF21_JumpIfTracerInSight, + A_JumpIfTracerCloser, MBF21_JumpIfTracerCloser, + A_WeaponProjectile, MBF21_WeaponProjectile, + A_WeaponBulletAttack, MBF21_WeaponBulletAttack, + A_WeaponMeleeAttack, MBF21_WeaponMeleeAttack, + A_WeaponSound, A_PlayWeaponSound, + A_WeaponJump, MBF21_WeaponJump, + A_ConsumeAmmo, MBF21_ConsumeAmmo, + A_CheckAmmo, MBF21_CheckAmmo, + A_RefireTo, MBF21_RefireTo, + A_GunFlashTo, MBF21_GunFlashTo, + A_JumpIfFlagsSet, MBF21_JumpIfFlagsSet, + A_AddFlags, MBF21_AddFlags, + A_RemoveFlags, MBF21_RemoveFlags, }; diff --git a/wadsrc/static/engine/commonbinds.txt b/wadsrc/static/engine/commonbinds.txt new file mode 100644 index 00000000000..8493529f2d6 --- /dev/null +++ b/wadsrc/static/engine/commonbinds.txt @@ -0,0 +1,120 @@ +// These bindings are valid for all configurations + +` toggleconsole +1 "slot 1" +2 "slot 2" +3 "slot 3" +4 "slot 4" +5 "slot 5" +6 "slot 6" +7 "slot 7" +8 "slot 8" +9 "slot 9" +0 "slot 0" +[ invprev +] invnext +mwheelleft invprev +mwheelright invnext +enter invuse +- sizedown += sizeup +shift +speed +mouse1 +attack +capslock "toggle cl_run" +f1 menu_help +f2 menu_save +f3 menu_load +f4 menu_options +f5 menu_display +f6 quicksave +f7 menu_endgame +f8 togglemessages +f9 quickload +f11 bumpgamma +f10 menu_quit +tab togglemap +pause pause +sysrq screenshot +t messagemode +\ +showscores +f12 spynext +mwheeldown weapnext +mwheelup weapprev + +// Originally just for Heretic, Hexen, and Strife. +// I can't see why they shouldn't be for Doom or Chex either. +pgup +moveup +ins +movedown +home land +pgdn +lookup +del +lookdown +end centerview + +// Xbox 360 / PS2 controllers +pad_a +use +pad_y +jump +rtrigger +attack +ltrigger +altattack +lshoulder weapprev +rshoulder weapnext +dpadleft invprev +dpadright invnext +dpaddown invuse +dpadup togglemap +pad_start menu_main +pad_back pause +lthumb crouch + +// Generic gamepad bindings +joy1 +use +joy4 +jump +axis6plus +attack +axis3plus +altattack +joy5 weapprev +joy6 weapnext +pov1left invprev +pov1right invnext +pov1down invuse +pov1up togglemap +joy8 menu_main +joy7 pause +joy10 crouch + +/* Default automap bindings */ +mapbind f am_togglefollow +mapbind g am_togglegrid +mapbind p am_toggletexture +mapbind m am_setmark +mapbind c am_clearmarks +mapbind 0 am_gobig +mapbind rightarrow +am_panright +mapbind leftarrow +am_panleft +mapbind uparrow +am_panup +mapbind downarrow +am_pandown +mapbind - +am_zoomout +mapbind = +am_zoomin +mapbind kp- +am_zoomout +mapbind kp+ +am_zoomin +mapbind mwheelup "am_zoom 1.2" +mapbind mwheeldown "am_zoom -1.2" + +/* Automap bindings for controllers (bare minimum functionality) */ +mapbind pad_x am_togglefollow +mapbind pad_a am_setmark +mapbind pad_b am_clearmarks +mapbind dpadright +am_panright +mapbind dpadleft +am_panleft +mapbind dpadup +am_panup +mapbind dpaddown +am_pandown +mapbind lshoulder +am_zoomout +mapbind rshoulder +am_zoomin + +mapbind joy3 am_togglefollow +mapbind joy1 am_setmark +mapbind joy2 am_clearmarks +mapbind pov1right +am_panright +mapbind pov1left +am_panleft +mapbind pov1up +am_panup +mapbind pov1down +am_pandown +mapbind joy5 +am_zoomout +mapbind joy6 +am_zoomin diff --git a/wadsrc/static/engine/defbinds.txt b/wadsrc/static/engine/defbinds.txt new file mode 100644 index 00000000000..6e3d8cff71d --- /dev/null +++ b/wadsrc/static/engine/defbinds.txt @@ -0,0 +1,10 @@ +/* Default WASD keybindings for all games */ + +w +forward +s +back +a +moveleft +d +moveright +space +jump +x crouch +e +use +mouse2 +altattack diff --git a/wadsrc/static/engine/leftbinds.txt b/wadsrc/static/engine/leftbinds.txt new file mode 100644 index 00000000000..30604f10d43 --- /dev/null +++ b/wadsrc/static/engine/leftbinds.txt @@ -0,0 +1,18 @@ +/* Default keybindings (keypad) for all games */ + +KP8 +forward +KP5 +back +KP4 +moveleft +KP6 +moveright +KP7 +jump +KP1 crouch +KP0 +use +UpArrow +forward +DownArrow +back +LeftArrow +moveleft +RightArrow +moveright +mouse2 +altattack + + + + diff --git a/wadsrc/static/engine/origbinds.txt b/wadsrc/static/engine/origbinds.txt new file mode 100644 index 00000000000..02326c7c00d --- /dev/null +++ b/wadsrc/static/engine/origbinds.txt @@ -0,0 +1,20 @@ +/* Default classic keybindings for all games */ + +ctrl +attack +alt +strafe +rightarrow +right +leftarrow +left +uparrow +forward +downarrow +back +, +moveleft +. +moveright +space +use +mouse2 +strafe +mouse3 +forward +mouse4 +speed + +// Generic joystick buttons +joy1 +attack +joy2 +strafe +joy3 +speed +joy4 +use diff --git a/wadsrc/static/filter/doom.id.doom1/after_iwad/sndinfo.txt b/wadsrc/static/filter/doom.id.doom1/after_iwad/sndinfo.txt new file mode 100644 index 00000000000..0c30de958cd --- /dev/null +++ b/wadsrc/static/filter/doom.id.doom1/after_iwad/sndinfo.txt @@ -0,0 +1,9 @@ +$musicalias D_E4M1 D_E3M4 +$musicalias D_E4M2 D_E3M2 +$musicalias D_E4M3 D_E3M3 +$musicalias D_E4M4 D_E1M5 +$musicalias D_E4M5 D_E2M7 +$musicalias D_E4M6 D_E2M4 +$musicalias D_E4M7 D_E2M6 +$musicalias D_E4M8 D_E2M5 +$musicalias D_E4M9 D_E1M9 diff --git a/wadsrc/static/filter/game-doomchex/sndinfo.txt b/wadsrc/static/filter/game-doomchex/sndinfo.txt index c103f493ca2..ac6d399219e 100644 --- a/wadsrc/static/filter/game-doomchex/sndinfo.txt +++ b/wadsrc/static/filter/game-doomchex/sndinfo.txt @@ -321,6 +321,9 @@ spider/attack dsshotgn spider/death dsspidth spider/walk dsmetal +$limit spider/sight 4 +$limit spider/death 4 + // Arachnotron baby/sight dsbspsit @@ -341,6 +344,8 @@ cyber/pain dsdmpain cyber/death dscybdth cyber/hoof dshoof +$limit cyber/sight 4 +$limit cyber/death 4 // Pain Elemental pain/sight dspesit @@ -440,6 +445,7 @@ menu/invalid dsoof // Menu not available menu/dismiss dsswtchx // Dismiss a prompt message menu/choose dspistol // Choose a menu item menu/clear dsswtchx // Close top menu +$alias menu/advance menu/choose // Open a submenu $random menu/quit1 { player/male/death1 demon/pain grunt/pain misc/gibbed misc/teleport grunt/sight1 grunt/sight3 demon/melee } $random menu/quit2 { vile/active misc/p_pkup brain/cube misc/gibbed skeleton/swing knight/death baby/active demon/melee } diff --git a/wadsrc/static/filter/game-heretic/defbinds.txt b/wadsrc/static/filter/game-heretic/engine/defbinds.txt similarity index 100% rename from wadsrc/static/filter/game-heretic/defbinds.txt rename to wadsrc/static/filter/game-heretic/engine/defbinds.txt diff --git a/wadsrc/static/filter/game-heretic/engine/leftbinds.txt b/wadsrc/static/filter/game-heretic/engine/leftbinds.txt new file mode 100644 index 00000000000..ed820a3783d --- /dev/null +++ b/wadsrc/static/filter/game-heretic/engine/leftbinds.txt @@ -0,0 +1,3 @@ +/* Default keybindings for Heretic */ + +backspace "use ArtiTomeOfPower" \ No newline at end of file diff --git a/wadsrc/static/filter/game-heretic/engine/origbinds.txt b/wadsrc/static/filter/game-heretic/engine/origbinds.txt new file mode 100644 index 00000000000..ed820a3783d --- /dev/null +++ b/wadsrc/static/filter/game-heretic/engine/origbinds.txt @@ -0,0 +1,3 @@ +/* Default keybindings for Heretic */ + +backspace "use ArtiTomeOfPower" \ No newline at end of file diff --git a/wadsrc/static/filter/game-heretic/sndinfo.txt b/wadsrc/static/filter/game-heretic/sndinfo.txt index 53017a49a82..60a0cda6f91 100644 --- a/wadsrc/static/filter/game-heretic/sndinfo.txt +++ b/wadsrc/static/filter/game-heretic/sndinfo.txt @@ -283,6 +283,7 @@ menu/change keyup menu/invalid plroof menu/dismiss dorcls menu/clear dorcls +$alias menu/advance menu/choose misc/secret dssecret diff --git a/wadsrc/static/filter/game-hexen/engine/defbinds.txt b/wadsrc/static/filter/game-hexen/engine/defbinds.txt new file mode 100644 index 00000000000..d951bc981ff --- /dev/null +++ b/wadsrc/static/filter/game-hexen/engine/defbinds.txt @@ -0,0 +1,11 @@ +/* Default keybindings for Hexen */ + +backspace invuseall +\ "use ArtiHealth" +0 useflechette +9 "use ArtiBlastRadius" +8 "use ArtiTeleport" +7 "use ArtiTeleportOther" +6 "use ArtiPork" +5 "use ArtiInvulnerability2" +scroll +showscores \ No newline at end of file diff --git a/wadsrc/static/filter/game-hexen/engine/leftbinds.txt b/wadsrc/static/filter/game-hexen/engine/leftbinds.txt new file mode 100644 index 00000000000..d951bc981ff --- /dev/null +++ b/wadsrc/static/filter/game-hexen/engine/leftbinds.txt @@ -0,0 +1,11 @@ +/* Default keybindings for Hexen */ + +backspace invuseall +\ "use ArtiHealth" +0 useflechette +9 "use ArtiBlastRadius" +8 "use ArtiTeleport" +7 "use ArtiTeleportOther" +6 "use ArtiPork" +5 "use ArtiInvulnerability2" +scroll +showscores \ No newline at end of file diff --git a/wadsrc/static/filter/game-hexen/defbinds.txt b/wadsrc/static/filter/game-hexen/engine/origbinds.txt similarity index 100% rename from wadsrc/static/filter/game-hexen/defbinds.txt rename to wadsrc/static/filter/game-hexen/engine/origbinds.txt diff --git a/wadsrc/static/filter/game-hexen/sndinfo.txt b/wadsrc/static/filter/game-hexen/sndinfo.txt index 2e36ab321e6..06598288c12 100644 --- a/wadsrc/static/filter/game-hexen/sndinfo.txt +++ b/wadsrc/static/filter/game-hexen/sndinfo.txt @@ -165,6 +165,7 @@ $alias menu/invalid DoorCloseMetal // Hexen does not use this, but I do $alias menu/dismiss PlatformStop $alias menu/choose DoorCloseLight $alias menu/clear PlatformStop +$alias menu/advance menu/choose // Hexen does not have ripslop sound like Heretic misc/ripslop dsempty diff --git a/wadsrc/static/filter/game-strife/acs/strfhelp.o b/wadsrc/static/filter/game-strife/acs/strfhelp.o index 483056f7bf4..824d8d688ed 100644 Binary files a/wadsrc/static/filter/game-strife/acs/strfhelp.o and b/wadsrc/static/filter/game-strife/acs/strfhelp.o differ diff --git a/wadsrc/static/filter/game-strife/engine/defbinds.txt b/wadsrc/static/filter/game-strife/engine/defbinds.txt new file mode 100644 index 00000000000..e5f8d029daa --- /dev/null +++ b/wadsrc/static/filter/game-strife/engine/defbinds.txt @@ -0,0 +1,7 @@ +/* Default keybindings for Strife */ + +c "showpop 1" +backspace invdrop +z "showpop 3" +k "showpop 2" +q invquery diff --git a/wadsrc/static/filter/game-strife/engine/leftbinds.txt b/wadsrc/static/filter/game-strife/engine/leftbinds.txt new file mode 100644 index 00000000000..763ff987f5a --- /dev/null +++ b/wadsrc/static/filter/game-strife/engine/leftbinds.txt @@ -0,0 +1,7 @@ +/* Default keybindings for Strife */ + +w "showpop 1" +backspace invdrop +z "showpop 3" +s "showpop 2" +q invquery diff --git a/wadsrc/static/filter/game-strife/defbinds.txt b/wadsrc/static/filter/game-strife/engine/origbinds.txt similarity index 100% rename from wadsrc/static/filter/game-strife/defbinds.txt rename to wadsrc/static/filter/game-strife/engine/origbinds.txt diff --git a/wadsrc/static/filter/game-strife/sndinfo.txt b/wadsrc/static/filter/game-strife/sndinfo.txt index f602a969b4a..f029373ddc8 100644 --- a/wadsrc/static/filter/game-strife/sndinfo.txt +++ b/wadsrc/static/filter/game-strife/sndinfo.txt @@ -107,6 +107,7 @@ menu/invalid dsoof // Menu not available menu/dismiss dsswish // Dismiss a prompt message menu/choose dsrifl // Choose a menu item menu/clear dsmtalht // Close top menu +$alias menu/advance menu/choose misc/startupdone dspsdtha misc/teleport dstelept diff --git a/wadsrc/static/fonts/consolefont/0490.png b/wadsrc/static/fonts/consolefont/0490.png new file mode 100644 index 00000000000..e02d0d80a16 Binary files /dev/null and b/wadsrc/static/fonts/consolefont/0490.png differ diff --git a/wadsrc/static/fonts/indexfont/0030.png b/wadsrc/static/fonts/indexfont/0030.png new file mode 100644 index 00000000000..1e4547d5b98 Binary files /dev/null and b/wadsrc/static/fonts/indexfont/0030.png differ diff --git a/wadsrc/static/fonts/indexfont/font.inf b/wadsrc/static/fonts/indexfont/font.inf new file mode 100644 index 00000000000..c7afafabc56 --- /dev/null +++ b/wadsrc/static/fonts/indexfont/font.inf @@ -0,0 +1,2 @@ +CellSize 4, 6 // This implies font sheets + diff --git a/wadsrc/static/graphics/bal7scr1.png b/wadsrc/static/graphics/bal7scr1.png index c3c21519105..cc7fdf367c4 100644 Binary files a/wadsrc/static/graphics/bal7scr1.png and b/wadsrc/static/graphics/bal7scr1.png differ diff --git a/wadsrc/static/graphics/bal7scr2.png b/wadsrc/static/graphics/bal7scr2.png index 04ff042c7ec..1aac4c47c8f 100644 Binary files a/wadsrc/static/graphics/bal7scr2.png and b/wadsrc/static/graphics/bal7scr2.png differ diff --git a/wadsrc/static/in_epi1.txt b/wadsrc/static/in_epi1.txt index 3a20d009a70..627516ccaa3 100644 --- a/wadsrc/static/in_epi1.txt +++ b/wadsrc/static/in_epi1.txt @@ -1,4 +1,5 @@ Background wimap0 +Screensize 320 200 Splat wisplat Pointer wiurh0 wiurh1 diff --git a/wadsrc/static/in_epi2.txt b/wadsrc/static/in_epi2.txt index 340bb042235..c0f35568a43 100644 --- a/wadsrc/static/in_epi2.txt +++ b/wadsrc/static/in_epi2.txt @@ -1,4 +1,5 @@ Background wimap1 +Screensize 320 200 Splat wisplat Pointer wiurh0 wiurh1 diff --git a/wadsrc/static/in_epi3.txt b/wadsrc/static/in_epi3.txt index 08e6fb341df..901a7655cac 100644 --- a/wadsrc/static/in_epi3.txt +++ b/wadsrc/static/in_epi3.txt @@ -1,4 +1,5 @@ Background wimap2 +Screensize 320 200 Splat wisplat Pointer wiurh0 wiurh1 diff --git a/wadsrc/static/in_htc1.txt b/wadsrc/static/in_htc1.txt index 15c2ac60154..20902bdfd6f 100644 --- a/wadsrc/static/in_htc1.txt +++ b/wadsrc/static/in_htc1.txt @@ -1,5 +1,6 @@ NoAutostartMap Background mape1 +Screensize 320 200 Splat in_x Pointer in_yah diff --git a/wadsrc/static/in_htc2.txt b/wadsrc/static/in_htc2.txt index 9d506d777ce..e123a26e295 100644 --- a/wadsrc/static/in_htc2.txt +++ b/wadsrc/static/in_htc2.txt @@ -1,5 +1,6 @@ NoAutostartMap Background mape2 +Screensize 320 200 Splat in_x Pointer in_yah diff --git a/wadsrc/static/in_htc3.txt b/wadsrc/static/in_htc3.txt index 545c59d3e05..21dd15c99e1 100644 --- a/wadsrc/static/in_htc3.txt +++ b/wadsrc/static/in_htc3.txt @@ -1,5 +1,6 @@ NoAutostartMap Background mape3 +Screensize 320 200 Splat in_x Pointer in_yah diff --git a/wadsrc/static/indexfont b/wadsrc/static/indexfont deleted file mode 100644 index eb8188e275d..00000000000 Binary files a/wadsrc/static/indexfont and /dev/null differ diff --git a/wadsrc/static/language.0 b/wadsrc/static/language.0 new file mode 100644 index 00000000000..8dc54bbd18d --- /dev/null +++ b/wadsrc/static/language.0 @@ -0,0 +1,880 @@ +default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,da,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,ja jp,ko,nl,no nb,pl,pt,ptg,ro,ru,sr,sv,tr,uk,bg +,,Miscellaneous,,,,,,,,,,,,,,,,,,,,,,,,,,, +Press Y or N.,PRESSYN,,,,Stiskni Y nebo N.,Tryk på Y eller N.,Drücke Y oder N.,"Πάτα Y ή N +",Premu Y aŭ N.,Presiona Y o N.,,Paina Y tai N.,Appuyez sur Y ou N.,Nyomj Y-t vagy N-t.,Premi Y oppure N.,YかNで答えろ,Y키 또는 N키를 누르시오.,Druk op Y of N.,Trykk på Y eller N.,Wciśnij Y lub N.,Aperte Y ou N.,Carrega Y ou N.,Apasă Y sau N.,Нажмите Y или N.,Притисните Y или N.,Tryck på Y eller N.,Y veya N tuşuna basın.,Натисніть Y або N.,Натисни Y или N. +Yes,TXT_YES,,,,Ano,Ja,Ja,Ναι,Jes,Sí,,Kyllä,Oui,Igen,Si,はい,네,Ja,Ja,Tak,Sim,,Da,Да,Да,Ja,Evet,Так,Да +No,TXT_NO,,,,Ne,Nej,Nein,Όχι,Ne,,,Ei,Non,Nem,,いいえ,아니요,Nee,Nei,Nie,Não,,Nu,Нет,Не,Nej,Hayır,Ні,Не +"You can't save if you aren't playing! + +Press a key.",SAVEDEAD,,,,"Mimo hru nelze ukládat! + +Stiskni libovolnou klávesu.","Du kan ikke gemme, hvis du ikke spiller! + +Tryk på en tast.","Du kannst nicht speichern, wenn du nicht spielst. + +Drücke eine Taste","Δεν μπορείς να αποθηκέυσης αμα δεν παίζεις ! + +Πάτα ενα κουμπί.","Vi ne povas konservi se vi ne ludas! + +Premu klavon.","¡No puedes guardar si no estás jugando! + +Presiona una tecla.",,"Et voi tallentaa, jos et ole pelissä! + +Paina jotain näppäintä.","Vous ne pouvez pas sauvegarder si vous ne jouez pas! + +Appuyez sur une touche.","Nem tudsz menteni játékon kívül! + +Nyomj meg egy gombot.","Non puoi salvare se non stai giocando! + +Premi un tasto.","プレイ中でないとセーブできない! + +何かキーを押せ","게임을 플레이 중이지 않을 때는 게임을 저장할 수 없습니다! + +키를 누르시오.","Je kunt niet opslaan als je niet speelt! + +Druk op een toets.","Du kan ikke lagre hvis du ikke spiller! + +Trykk på en tast.","Nie możesz zapisać, jeśli nie grasz! + +Wciśnij dowolny klawisz.","Você não pode salvar se não estiver jogando! + +Aperte uma tecla.","Você não pode salvar se não estiver a jogar! + +Carrega numa tecla qualquer.","Nu poți salva jocul dacă nu joci! + +Apasă o tastă.","Невозможно сохранить игру, не начав её! + +Нажмите любую клавишу.","Не можете сачувати игру ако не играте! + +Притисните тастер.",Du kan inte spara om du inte spelar! Tryck på en tangent.,"Eğer oynamıyorsanız kaydedemezsiniz! + +Bir tuşa bas.","Ви не можете зберегти гру, не почавши її! + +Натисніть будь яку клавішу.","Не може да запазите играта, ако не играете! + +Натиснете клавиш." +Do you really want to do this?,SAFEMESSAGE,,,,Vážně to chceš udělat?,Vil du virkelig gøre dette?,Möchtest du das wirklich tun?,Θέλετε πραγματικά να το κάνετε αυτό;,Ĉu vi vere volas fari tion?,¿Realmente quieres hacer eso?,,Haluatko varmasti tehdä tämän?,Voulez-vous vraiment faire ça?,Biztos ezt akarod tenni?,Sei sicuro di volerlo fare?,本当に実行するのか?,정말로 정하시겠습니까?,Wil je dit echt doen?,Vil du virkelig gjøre dette?,Naprawdę chcesz to zrobić?,Você deseja mesmo fazer isso?,Desejas mesmo fazer isso?,Ești sigur că vrei să faci asta?,Вы уверены?,Да ли заиста желите то да урадите?,Vill du verkligen göra det här?,Bunu gerçekten yapmak istiyor musun?,Ви дійсно хочете цього?,Наистина ли искаш да направиш това? +Not set,NOTSET,,,,Není nastavené,Ikke indstillet,Nicht gesetzt,Δεν έχει οριστεί,Ne agordita,No asignado,,Ei asetettu,Pas paramétré,Nincs beállítva,Non assegnato,セットされてない,정하지 않음,Niet ingesteld,Ikke innstilt,Nie ustawiono,Não definido,,Nesetat,Не задан,Није намештено,Inte inställd,Ayarlanmamış,Не встановлено,Не е зададено +"Quicksave over your game named + +'%s'? + +Press Y or N.",QSPROMPT,,,,"Rychle uložit přes hru s názvem + +'%s'? + +Stiskni Y nebo N.","Quicksave over dit spil navngivet + +'%s'? + +Tryk på Y eller N.","Überschreibe %s mit einem Schnellspeicherspielstand? + +Drücke Y oder N.","Γρήγορη αποθήκευση πάνω από το παιχνίδι σας με το όνομα '%s'; + +Πατήστε Y ή N.","Ĉu rapidkonservi anstataŭigante vian ludadon nomitan + +'%s'? + +Premu Y aŭ N.","¿Deseas guardar sobre tu partida llamada + +'%s'? + +Presiona Y o N.",,"Haluatko tallentaa pelin %s päälle? + +Paina Y tai N.","Sauvegarde rapide sur le fichier + +'%s'? + +Appuyez sur Y ou N.","Felülírod az alábbi mentésedet: + +'%s'? + +Nyomj Y-t vagy N-t.","Sovrascrivere il salvataggio + +'%s'? + +Premi Y oppure N.","この名前で上書きするのか? + +'%s' + +Y か N で答えろ","빠른 저장을 하시겠습니까? + +'%s' + +Y키 또는 N키를 누르시오.","Snel opslaan over je spel genaamd + +'%s'? + +Druk op Y of N.","Overskrive '%s' med en hurtiglagring? + +Trykk på Y eller N.","Szybko nadpisać grę + +„%s”? + +Wciśnij Y lub N.","Salvar rapidamente sobre o jogo chamado + +'%s'? + +Aperte Y ou N.","Gravar sobre o seu jogo chamado + +'%s'? + +Carrega Y ou N.","Salvare rapidă peste salvarea + +'%s' ? + +Apasă Y sau N.","Перезаписать быстрое сохранение + +«%s»? + +Нажмите Y или N.","Желите брзо чување за игру под именом + +„%s“? + +Притисните Y или N.","Snabbspara över ditt spel som heter %s? +Tryck på Y eller N.","%s' + +adlı oyununuzun üzerine hızlı kaydetme? + +Y veya N tuşuna basın.","Перезаписати швидке збереження + +""%s""? + +Натисніть Y або N.","Презапиши върху игра с име + +'%s'? + +Натисни Y или N." +"Do you want to quickload the game named + +'%s'? + +Press Y or N.",QLPROMPT,,,,"Rychle načíst hru s názvem + +'%s'? + +Stiskni Y nebo N.","Ønsker du at quickloade spillet ved navn + +'%s'? + +Tryk på Y eller N.","Möchtest du den Spielstand %s schnellladen? + +Drücke Y oder N.","Θέλετε να κάνετε γρήγορη φόρτωση του παιχνιδιού με το όνομα '%s'; + +Πατήστε Y ή N.","Ĉu vi volas rapidŝargi la ludadon nomitan + +'%s'? + +Premu Y aŭ N.","¿Deseas cargar la partida llamada + +'%s'? + +Presiona Y o N.",,"Haluatko pikaladata pelin %s? + +Paina Y tai N.","Voulez-vous charger la sauvegarde + +'%s'? + +Appuyez sur Y ou N.","Betöltöd az alábbi mentésedet: + +'%s'? + +Nyomj Y-t vagy N-t.","Vuoi fare un quickload della partita + +'%s'? + +Premi Y oppure N.","この名前のデータをロードするのか? + +'%s' + +Y か N で答えろ","빠른 불러오기를 하시겠습니까? + +'%s' + +Y키 또는 N키를 누르시오.","Wil je het spel snel laden met de naam + +'%s'? + +Druk op Y of N.","Vil du hurtiglaste spillet med navnet '%s'? + +Trykk på Y eller N.","Czy chcesz wczytać szybki zapis + +„%s”? + +Wciśnij Y lub N.","Carregar rapidamente o jogo chamado + +'%s'? + +Aperte Y ou N.","Deseja carregar o jogo chamado + +'%s'? + +Carrega Y ou N.","Vrei să încarci rapid salvarea + +'%s' ? + +Apasă Y sau N.","Загрузить быстрое сохранение + +«%s»? + +Нажмите Y или N.","Желите брзо учитавање за игру под именом + +„%s“? + +Притисните Y или N.","Vill du snabbladda spelet som heter ""%s""? +Tryck på Y eller N.","%s' + +adlı oyunu hızlı yüklemek istiyor musunuz? + +Y veya N tuşuna basın.","Завантажити швидке збереження + +""%s""? + +Натисніть Y або N.","Искате ли да заредите бързо играта с име + +'%s'? + +Натисни Y или N." +%s cheats,TXT_X_CHEATS,This is a gender sensitive message where %s represents the player,,,%s podvádí,%s snyder,%s schummelt,@[art_gr] %s απατάει,%s trompas,%s hace trampas,%s hace trampa,%s huijaa,%s triche.,%s csal,%s imbroglia,%s はチート使用,%s 이(가) 치트를 사용 함,%s bedriegt,%s jukser,%s oszukuje,%s está trapaceando,%s está a fazer batota,%s trișează,%s использует чит-коды,%s вара,%s fuskar,%s hileleri,%s чітерить,%s измамен код +Messages: OFF,MSGOFF,,,,Oznámení ZAP.,Meddelelser: FRA,Meldungen AUS,Μηνύματα ΚΛΕΙΣΤΑ,Mesaĝoj: MALŜALTITA,Mensajes DESACTIVADOS,,Viestit POIS PÄÄLTÄ,Messages désactivés.,Üzenetek: KI,Messaggi DISATTIVATI,メッセージ: オフ,메시지 끔,Berichten UIT,Meldinger: AV,Wiadomości WYŁĄCZONE,Mensagens DESATIVADAS,,Mesaje OPRITE,Сообщения ОТКЛЮЧЕНЫ,Поруке ИСКЉУЧЕНЕ,Meddelanden: Av,Mesajlar: KAPALI,Повідомлення: ВИМКНЕНІ,Съобщения: Изкл +Messages: ON,MSGON,,,,Oznámení VYP.,Meddelelser: TIL,Meldungen AN,Μηνύματα ΑΝΟΙΧΤΑ,Mesaĝoj: ŜALTITA,Mensajes ACTIVADOS,,Viestit PÄÄLLÄ,Messages activés.,Üzenetek: BE,Messaggi ATTIVATI,メッセージ: オン,메시지 켬,Berichten AAN,Meldinger: PÅ,Wiadomości WŁĄCZONE,Mensagens ATIVADAS,,Mesaje PORNITE,Сообщения ВКЛЮЧЕНЫ,Поруке УКЉУЧЕНЕ,Meddelanden: På,Mesajlar: AÇIK,Повідомлення: УВІМКНЕНІ,Съобщения: Вкл +Say:,TXT_SAY,,,,Říct:,Sig:,Sage:,Πές:,Diri:,,,Sano:,Parler:,Üzenet:,Parla:,発言:,,Zeg:,Si:,Mów:,Dizer:,Diz:,Vorbește:,Чат:,Пиши:,Säg:,Söyle:,Чат:,Пиши: +Press any key or click anywhere in the window to quit.,TXT_QUITENDOOM,,,,"Pro ukončení stiskni libovolnou klávesu, nebo klikni kdekoliv v okně.",Tryk på en vilkårlig tast eller klik et vilkårligt sted i vinduet for at afslutte.,Drücke eine Taste oder klicke mit der Maus ins Fenster zum Beenden.,Πάτα οποιοδήποτε πλήκτρο ή πάτα οπουδήποτε για να κάνεις έξοδο,Premu ajnan klavon aŭ alklaku ie ajn en la fenestro por forlasi.,Presiona una tecla o haz clic en cualquier lugar de la ventana para salir.,,Paina mitä tahansa näppäintä tai napsauta minne tahansa ikkunaa lopettaaksesi.,Appuyez sur une touche ou cliquez pour quitter.,Nyomjon egy gombot vagy kattintson valahova a kilépéshez.,Premi un qualunque tasto o fai un click ovunque nella finestra per uscire.,何かのキーを押すか、ウィンドウのどこかをクリックすると終了する。,아무 키를 누르거나 아무 곳이나 클릭하면 종료됩니다.,Druk op een willekeurige toets of klik ergens in het venster om te stoppen.,Trykk på en hvilken som helst tast eller klikk hvor som helst i vinduet for å avslutte.,Wciśnij dowolny klawisz lub kliknij myszką by wyjść.,Aperte uma tecla ou clique em qualquer lugar na janela para sair.,Carrega numa tecla ou clique em qualquer lugar na janela para sair.,Apasă orice tastă sau apasă click oriunde în fereastră pentru a ieși.,"Нажмите любую клавишу или нажмите по окну, чтобы выйти.",Притисните било који тастер или кликните било где на екрану да одустанете.,Tryck på någon tangent eller klicka någonstans i fönstret för att avsluta.,Çıkmak için herhangi bir tuşa basın veya pencerede herhangi bir yere tıklayın.,"Натисніть будь яку клавішу чи натисніть по вікну, щоб вийти.","Натиснете който и да е клавиш или щракнете където и да е в прозореца, за да излезете." +,,Savegame,,,,,,,,,,,,,,,,,,,,,,,,,,, +,NEWSAVE,,,,,,,<Νέο παιχνίδι αποθήκευσης>,,,,,,<Új mentés>,,<新規セーブ>,<새로운 게임 저장>,,,,,,,<Новое сохранение>,<Нова сачувана игра>,,,<Нове збереження>,<Нов запис на играта> +Game saved.,GGSAVED,,,,Hra uložena.,Spillet er gemt.,Spielstand gespeichert.,Παχνίδι αποθηκέυτηκε.,Ludado konservita.,Partida guardada.,,Peli tallennettu.,Partie sauvegardée.,Játék mentve.,Partita salvata.,セーブ完了。,게임이 저장됨.,Spel opgeslagen.,Spillet er lagret.,Gra zapisana.,Jogo salvo.,Jogo gravado.,Joc salvat.,Игра сохранена.,Игра сачувана.,Spelet är sparat.,Oyun kaydedildi.,Гру збережено.,Играта е записана +Time,SAVECOMMENT_TIME,,,,Čas,Tid,Zeit,Χρόνος,Tempo,Tiempo,,Aika,Temps,Idő,Tempo,"時間 +",시간,Tijd,Tid,Czas,Tempo,,Timp,Время,Време,Tid,Zaman,Час,Време +Load Game,MNU_LOADGAME,,,,Načíst hru,Indlæs spil,Spiel laden,Φώρτωσε παιχνίδι,Ŝargi ludadon,Cargar partida,,Lataa peli,Chargement,Játék betöltése,Carica partita,ロード,게임 불러오기,Laden spel,Last inn spill,Wczytaj Grę,Carregar jogo,,Încărcare Joc,Загрузка,Учитај игру,Ladda spelet,Oyun Yükle,Завантажити,Зареди игра +Save Game,MNU_SAVEGAME,,,,Uložit hru,Gem spil,Spiel sichern,Αποθήκευσε παιχνίδι,Konservi ludadon,Guardar partida,,Tallenna peli,Sauvegarde,Játék mentése,Salva partita,セーブ,게임 저장하기,Opslaan spel,Lagre spill,Zapisz Grę,Salvar jogo,Gravar,Salvare Joc,Сохранение,Сачувај игру,Spara spelet,Oyunu Kaydet,Зберегти,Запази игра +No Picture,MNU_NOPICTURE,,,,Bez obrázku,Intet billede,Kein Bild,Καμία εικόνα,Neniu bildo,Sin imagen,,Ei kuvaa,Pas d'image,Nincs kép,Nessuna immagine,画像無し,사진 없음,Geen beeld,Ingen bilde,Brak obrazka,Sem imagem,,Lipsă Imagine,"Нет +изображения",Нема слике,Ingen bild,Resim yok,Немає зображення,Без изображение +Different Version,MNU_DIFFVERSION,,,,Jiná verze,Anderledes version,Falsche Version,Διαφορετική έκδοση,Malsama versio,Versión diferente,,Eri versio,Version Différente,Eltérő verzió,Versione differente,"別バージョンの +データ",다른 버젼,Anders Versie,Annen versjon,Inna Wersja,Versão diferente,,Versiune Diferită,Другая версия,Другачија верзија,Annan version,Farklı Versiyon,Інша версія,Различна версия +No files,MNU_NOFILES,,,,Žádné soubory,Ingen filer,Keine Dateien,Καθ΄λου αρχεία ,Neniu dosiero,Sin archivos,,Ei tiedostoja,Pas de fichiers,Nincsenek fájlok,Nessun file,ファイル無し,파일 없음,Geen bestanden,Ingen filer,Brak plików,Vazio,,Niciun fișier,Нет файлов,Нема фајлова,Inga filer,Dosya yok,Немає файлів,Няма файлове +"Do you really want to delete the savegame? +",MNU_DELETESG,,,,Opravdu smazat tuto uloženou hru?,Ønsker du virkelig at slette det gemte spil?,Willst du diesen Spielstand wirklich löschen?,Θέλεις όντος να διαγράξεις το αποθηκευμένο παιχνίδι;,Ĉu vi vere volas forigi la konservitan ludadon?,"¿Realmente deseas borrar la partida? +",,Haluatko varmasti poistaa tallennetun pelin ,"Voulez vous vraiment effacer cette sauvegarde? +",Biztosan törlöd a mentést?,Vuoi veramente cancellare il salvataggio?,本当にこのセーブを消すのか?,저장된 게임을 정말로 삭제하시겠습니까?,Wil je echt de opgeslagen spel verwijderen?,Vil du virkelig slette lagringsspillet?,Czy naprawdę chcesz usunąć zapis gry?,Deseja mesmo excluir o jogo salvo?,Deseja mesmo apagar o jogo,Vrei să ștergi salvarea?,Вы действительно хотите удалить сохранение?,Да ли стварно желите да избришете сачувану игру,Vill du verkligen radera sparfilen?,"Gerçekten kayıt oyununu silmek istiyor musunuz? +",Ви дійсно хочете видалити це збереження?,Найстина ли искаш да изтриеш запазената игра +,,General,,,,,,,,,,,,,,,,,,,,,,,,,,, +Off,OPTVAL_OFF,,,,Vyp.,Fra,Aus,ενεργοποιημένη,Malŝaltita,Desactivado,,Pois,,Ki,Disattivo,オフ,끔,Uit,Av,Wyłączone,Não,,Pornit,Откл.,Искљ.,Av,Kapalı,Вимк.,Изкл. +On,OPTVAL_ON,,,,Zap.,Til,An,άπενεργοποιημένη,Ŝaltita,Activado,,Päällä,,Be,Attivo,オン,켬,Aan,På,Włączone,Sim,,Oprit,Вкл.,Укљ.,På,Açık,Увім.,Вкл. +Auto,OPTVAL_AUTO,,,,,Automatisk,,Αυτό,Aŭtomata,Automático,,Automaattinen,,Automatikus,Automatico,自動,자동,,,Automatycznie,Automático,,,Авто,Аутоматски,Automatiskt,Otomatik,Авто,Автоматично +Options,OPTMNU_TITLE,,,,Možnosti,Indstillinger,Optionen,Ρυθμίσεις,Agordoj,Opciones,,Asetukset,,Beállítások,Opzioni,オプション,설정,Opties,Alternativer,Opcje,Opções,,Opțiuni,Настройки,Подешавања,Alternativ,Seçenekler,Налаштування,Настройки +Customize Controls,OPTMNU_CONTROLS,,,,Ovládání,Tilpas kontrolelementer,Steuerung einstellen,Προσαρμογή χειριστηρίων,Adapti regilojn,Personalizar controles,,Ohjausasetukset,Modifier les Contrôles,Irányítás testreszabása,Personalizza i controlli,キー配置変更,조작 사용자 지정,Instellen van de controle,Tilpass kontroller,Ustaw Klawisze,Personalizar comandos,Configurar Controlos,Personalizare Setări Control,Управление,Контроле,Anpassa kontrollerna,Kontrolleri Özelleştir,Керування,Управление +Mouse Options,OPTMNU_MOUSE,,,,Myš,Indstillinger for mus,Mauseinstellungen,Ρυθμίσεις ποντικίου,Muso-agordoj,Opciones de ratón,,Hiiriasetukset,Options de la Souris,Egér beállítások,Opzioni Mouse,マウス オプション,마우스 설정,Muis opties,Alternativer for mus,Opcje Myszki,Opções de mouse,Opções do rato,Setări Mouse,Мышь,Миш,Alternativ för musen,Fare Seçenekleri,Миш,Мишка +Controller Options,OPTMNU_JOYSTICK,,,,Ovladač,Indstillinger for controller,Joystickeinstellungen,Επιλογές ελεγκτή,Ludregilo-agordoj,Opciones de mando,,Peliohjainasetukset,Options de la Manette,Játékvezérlő beállítások,Opzioni Joystick,コントローラーオプション,조이스틱 설정,Controller opties,Kontrollalternativer,Opcje Kontrolera,Opções de controle,,Setări Controller,Контроллер,Контролер,Alternativ för styrenhet,Kontrolör Seçenekleri,Контролер,Контролер +Player Setup,OPTMNU_PLAYER,,,,Hráč,Spilleropsætning,Spieler einrichten,Ρυθμίσεις παίχτη,Ludanto-agordaĵo,Configuración del jugador,,Pelaaja-asetukset,Options du Joueur,Játékos testreszabása,Settaggio giocatore,プレイヤーの特徴,플레이어 설정,Speler instellen,Spilleroppsett,Ustawienia Gracza,Configurações de jogador,Configurações do Jogador,Personalizare Jucător,Игрок,Играч,Inställning av spelare,Oyuncu Kurulumu,Гравець,Играч +Gameplay Options,OPTMNU_GAMEPLAY,,,,Herní mechaniky,Indstillinger for gameplay,Spieleinstellungen,Επιλογές παιχνιδιού,Ludado-agordoj,Opciones de jugabilidad,,Pelattavuusasetukset,Options du Gameplay,Játékmenet beállítások,Opzioni Gameplay,ゲームプレイ オプション,게임 설정,Gameplay-opties,Spillalternativer,Opcje Rozgrywki,Opções de jogabilidade,,Setări pe timp de joc,Игра,Гејмплеј,Spelalternativ,Oynanış Seçenekleri,Ігрові механіки,Игра +Automap Options,OPTMNU_AUTOMAP,,,,Automapa,Automap-indstillinger,Automapeinstellungen,Επιλογές Automap,Agordoj de la aŭtomata mapo,Opciones del automapa,,Automaattikartan asetukset,Options de la Carte,Térkép beállítások,Opzioni Automappa,オートマップ オプション,오토맵 설정,Automap-opties,Automap-alternativer,Opcje Mapy,Opções de automapa,,Hartă computerizată,Автокарта,Аутомапа,Automap-alternativ,Otomatik Harita Seçenekleri,Автокарта,Автокарта +HUD Options,OPTMNU_HUD,,,,Rozhraní a HUD,HUD-indstillinger,HUD Einstellungen,Ρυθμίσεις HUD,Agordoj de HUD,Opciones del HUD,,Tilanäytön asetukset,Options de l'ATH,HUD beállítások,Opzioni HUD,HUD オプション,HUD 설정,HUD opties,HUD-alternativer,Opcje HUD,Opções de HUD,,Setări HUD,Интерфейс,,HUD-alternativ,HUD Seçenekleri,Ігровий інтерфейс,Интерфейс +Miscellaneous Options,OPTMNU_MISCELLANEOUS,,,,Ostatní,Diverse indstillinger,Verschiedene Einstellungen,Διάφορες ρυθμίσεις,Diversaĵaj agordoj,Opciones misceláneas,,Sekalaiset asetukset,Options Annexes,Egyéb beállítások,Opzioni Miste,その他のオプション,그 외 설정,Diverse opties,Diverse alternativer,Różne Opcje,Outras opções,,Setări diverse,Дополнительно,Разно,Diverse alternativ,Çeşitli Seçenekler,Інше,Други настройки +Sound Options,OPTMNU_SOUND,,,,Zvuk,Lydindstillinger,Soundeinstellungen,Ρυθμίσεις ήχου,Sono-agordoj,Opciones de sonido,,Ääniasetukset,Options du Son,Hang beállítások,Opzioni Suono,サウンド オプション,음향 설정,Geluidsopties,Lydalternativer,Opcje Dźwięku,Opções de som,,Setări sunet,Звук,Звук,Ljudalternativ,Ses Seçenekleri,Звук,Звука +Display Options,OPTMNU_DISPLAY,,,,Grafika,Visningsindstillinger,Anzeigeeinstellungen,Επιλογές οθόνης,Ekrano-agordoj,Opciones de visualización,,Näyttöasetukset,Options de l'Affichage,Megjelenítés beállítások,Opzioni Display,ディスプレイ オプション,디스플레이 설정,Weergaveopties,Visningsalternativer,Opcje Wyświetlania,Opções de vídeo,,Setări afișare,Экран,Приказ,Visningsalternativ,Görüntüleme Seçenekleri,Екран,Екрана +Set video mode,OPTMNU_VIDEO,,,,Obrazový výstup,Indstil videomodus,Videomodus,Άλλαξε λειτουργία βίντεο,Agordi videoreĝimon,Modos de vídeo,Modos de video,Aseta videotila,Choisir Mode D'Affichage,Videó beállítások,Settaggio modalità video,ビデオ 調整,화면 설정,Videomodus instellen,Angi videomodus,Ustaw tryb wideo,Definir modo de vídeo,,Setare mod video,Видеорежим,Видео мод,Ställ in videoläge,Video modunu ayarlama,Відеорежим,Видеорежим +Reset to defaults,OPTMNU_DEFAULTS,,,,Obnovit původní,Nulstil til standardindstillingerne,Auf Vorgaben zurücksetzen,Επαναφορά σε προεπιλεγμένες ρυθμίσεις,Restarigi al defaŭltoj,Valores por defecto,,Palauta oletusasetukset,Réinitialiser les paramètres,Alapértelmezett beállítások használata,Reimposta ai valori di default,初期設定に戻す,초기화,Terugzetten naar standaardinstellingen,Tilbakestill til standardinnstillinger,Resetuj do domyślnych,Redefinir para configurações padrão,,Revenire la setări implicite,Сбросить все настройки,Врати подразумевано,Återställ till standardvärden,Varsayılanlara sıfırla,Скинути налаштування,Нулирай до стандартни +Reset to last saved,OPTMNU_RESETTOSAVED,,,,Obnovit naposledy uložené,Nulstil til sidst gemte,Auf gespeicherte Werte zurücksetzen,Επαναφορά στην τελευταία αποθήκευση,Restarigi al lasta konservita,Últimos valores guardados,,Palauta viimeksi tallennettu tila,Recharger dernière config.,Legutóbbi mentett beállítások használata,Reimposta ai valori salvati l'ultima volta,最後に保存した設定に戻す,이전 설정으로 초기화,Reset naar laatste opgeslagen,Tilbakestill til sist lagret,Resetuj do ostatnio zapisanych,Redefinir para a última configuração salva,Redefinir para última configuração gravada,Revenire la ultimele setări salvate,Возврат к сохранённым настройкам,Врати задње сачувано,Återställ till senast sparade,Son kaydedilene sıfırla,Відновити останні збережені налаштування,Нулирай до последно запазената игра +Save current settings,OPTMNU_WRITEINI,,,,Uložit současná nastavení,Gem de aktuelle indstillinger,Aktuelle Einstellungen speichern,Αποθήκευσε της τορινές ρυθμίσεις,Konservi nunajn reĝimojn,Guardar los ajustes de ahora,,Tallenna nykyiset asetukset,Sauvegarde des Paramètres Actuels,Jelenlegi beállítások mentése,Salva le impostazioni correnti,現在の設定を保存,현재 설정 적용,Huidige instellingen opslaan ,Lagre gjeldende innstillinger,Zapisz aktualne opcje,Salvar configurações atuais,,Salvează setările curente,Сохранить текущие настройки,,Spara aktuella inställningar,Geçerli ayarları kaydet,Зберегти поточні налаштування,Запази сегашните настройки +Go to console,OPTMNU_CONSOLE,,,,Otevřít konzoli,Gå til konsol,Öffne Konsole,Μπές στη κονσόλα,Iri al konzolo,Ir a la consola,,Mene konsoliin,Ouvrir la console,Konzol megnyitása,Vai alla console,コンソールを開く,콘솔로 이동,Ga naar de console,Gå til konsoll,Przejdź do konsoli,Abrir console,Abrir consola,Mergi la consolă,Открыть консоль,Отвори конзолу,Gå till konsolen,Konsola git,Відкрити консоль,Отвори конзолата +Network Options,OPTMNU_NETWORK,,,,Síť,Netværksindstillinger,Netzwerkeinstellungen,Ρυθμίσεις Δικτύου,Reto-agordoj,Opciones de red,,Verkkoasetukset,Options Réseau,Hálózati beállítások,Opzioni Network,ネットワーク オプション,네트워크 설정,Netwerkopties,Nettverksalternativer,Opcje Sieciowe,Opções de rede,,Setări de Rețea,Сеть,Мрежа,Nätverksalternativ,Ağ Seçenekleri,Мережа,Мрежа +Reverb environment editor,OPTMNU_REVERB,,,,Editor zvukové ozvěny,Reverb editor,Hall-Editor,Επεξεργαστής περιβαλλόντων απόσβεσης,Redaktoro pri resonmedio,Editor de amb. de reverberación,,Kaikutilaeditori,Editeur environement de révérb.,Visszhangkörnyezet-szerkesztő,Editor ambiente reverb,リバーブ環境エディタ,울림 환경 편집기,Reverb-omgeving editor,Reverb-miljøredigering,Edytor pogłosu środowiska,Editor de ambiente de reverberação,,Setări Reverb,Редактор реверберации,Уредник одјека у околини,Redigerare för reverbmiljö,Reverb ortam düzenleyicisi,Редактор реверберації,Редактор на среда за реверберация +,,Customize controls,,,,,,,,,,,,,,,,,,,,,,,,,,, +"ENTER to change, BACKSPACE to clear",CNTRLMNU_SWITCHTEXT1,,,,"ENTER pro změnu, BACKSPACE pro smazání","ENTER for at ændre, BACKSPACE for at slette",ENTER: Editieren BACKSPACE: Löschen,"ENTER για αλλαγή, BACKSPACE για διαγραφή","ENTER por ŝanĝi, BACKSPACE por forigi","ENTER para cambiar, RETROCESO para borrar","ENTER para cambiar, BACKSPACE para borrar","Aseta ENTERILLÄ, tyhjennä ASKELPALAUTTIMELLA","ENTREE pour changer, RET. ARRIERE pour effacer.","ENTER a változtatáshoz, BACKSPACE a törléshez","INVIO per modificare, BACKSPACE per ripulire",Enter で決定、BackSpaceで無効化,"바꿀려면 ENTER키, 지울려면 BACKSPACE키를 누르시오","ENTER om te veranderen, BACKSPACE om te wissen.","ENTER for å endre, BACKSPACE for å slette","ENTER by zmienić, BACKSPACE by wyczyścić",Aperte ENTER para alterar e BACKSPACE para remover,,"ENTER pentru a schimba, BACKSPACE pentru ștergere","ENTER — изменить, BACKSPACE — очистить","ENTER за промену, BACKSPACE за чишћење","ENTER för att ändra, BACKSPACE för att radera","Değiştirmek için ENTER, silmek için BACKSPACE","ENTER — змінити, BACKSPACE — очистити","ENTER — промяна, BACKSPACE — изчистване" +"Press new key for control, ESC to cancel",CNTRLMNU_SWITCHTEXT2,,,,"Zmáčkni novou klávesu, nebo ESC pro storno","Tryk på ny tast for kontrol, ESC for at annullere",Drücke eine Taste oder ESC um abzubrechen,"Πατήστε το νέο πλήκτρο για έλεγχο, ESC για ακύρωση","Premu novan klavon por regilo, ESC por nuligi","Presiona una tecla para el control, ESC para cancelar",,"Valitse näppäin toiminnolle, ESC peruuttaa","Appuyez sur la nouvelle touche pour l'assigner, +Appuyez sur ECHAP pour annuler.","Nyomj meg egy gombot, ESC a törléshez","Premi un nuovo tasto per il controllo, ESC per cancellare","登録したいキーを押すか, Escでキャンセル","명령을 얽으려면 아무 키를, 취소는 ESC키를 누르시오","Druk op de nieuwe toets voor controle, ESC om te annuleren.","Trykk på ny tast for kontroll, ESC for å avbryte","Wciśnij nowy przycisk by zmienić klawisz, ESC by anulować",Aperte uma nova tecla para o comando e ESC para cancelar,"Carrega a nova tecla para o comando, ESC para cancelar","Apasă tasta nouă, sau ESC pentru anulare","Нажмите новую клавишу, ESC для отмены","Притисните ново тастер за одређивање контроле, ESC за отказивање","Tryck på ny tangent för kontroll, ESC för att avbryta","Kontrol için yeni tuşa, iptal etmek için ESC'ye basın","Натисніть на клавішу для її призначення, ESC для скасування","Натисни нов клавиш за управление, ESC за отмяна" +Controls,CNTRLMNU_CONTROLS,,,,Ovládání,Kontrolelementer,Steuerung,Έλεγχοι,Regiloj,Controles,,Ohjaimet,Contrôles,Irányítás,Controlli,操作系統,조작,Bedieningselementen,Kontroller,Klawisze,Comandos,Controlos,Control,Управление,Контроле,Kontroller,Kontroller,Керування,Управление +Fire,CNTRLMNU_ATTACK,,,,Střelba,Ild,Feuer,Πυροβόλα,Pafi,Fuego,,Tuli,Tirer,Tűz,Fuoco,撃つ,공격,Vuur,Brann,Strzał,Atirar,,Foc,Атака,Нападни,Eld,Yangın,Атака,Атака +Secondary Fire,CNTRLMNU_ALTATTACK,,,,Sekundární střelba,Sekundær ild,Alternativfeuer,Δευτερεύουσα Πυροβόλα,Pafi duarange,Fuego secundario,,Vaihtoehtoistuli,Tir Secondaire,Másodlagos tüzelés,Fuoco secondario,セカンダリ,보조 공격,Secundaire vuur,Sekundær ild,Strzał Alternatywny,Tiro secundário,,Foc Secundar,Дополнительная атака,Секундарни напад,Sekundär eld,İkincil Yangın,Додаткова атака,Допълнителна атака +Weapon Reload,CNTRLMNU_RELOAD,,,,Přebít zbraň,Våben Genopladning,Waffe nachladen,Επαναφόρτωση Όπλου,Reŝargi armilon,Recargar arma,,Aseen lataus,Recharger Arme,Fegyver újratöltése,Ricarica dell'arma,リロード,무기 장전,Wapenherladen,Våpen Reload,Przeładowanie Broni,Recarregar arma,,Încărcare Armă,Перезарядка,Напуни,Ladda om vapen,Silah Yeniden Doldurma,Перезарядка,Презареди +Use / Open,CNTRLMNU_USE,,,,Použít/otevřít,Brug / Åbn,Benutzen / Öffnen,Χρήση / Άνοιγμα,Uzi/Malfermi,Usar/Abrir,,Käytä / Avaa,Utiliser/Ouvrir,Akciógomb/Nyitás,Usa/Apri,開く / スイッチ等使用,사용/열기,Gebruik / Openen,Bruk / Åpne,Użyj / Otwórz,Usar / Abrir,,Folosește / Deschide,Использовать/открыть,Користи / Отвори,Användning/öppna,Kullan / Aç,Відкрити / Використати,Използвай / Отвори +Move forward,CNTRLMNU_FORWARD,,,,Vpřed,Flyt fremad,Vorwärts bewegen,Μετακίνηση προς τα εμπρός,Moviĝi anatŭen,Avanzar,,Liiku eteenpäin,Avancer,Előre mozgás,Movimento in avanti,前進,앞으로 이동,Voorwaarts bewegen,Gå fremover,Idź do przodu,Mover-se para frente,,Deplasare în față,Движение вперёд,Крећи се напред,Flytta framåt,İlerleyin,Рухатись вперед,Движение напред +Move backward,CNTRLMNU_BACK,,,,Vzad,Bevæge sig bagud,Rückwarts bewegen,Μετακίνηση προς τα πίσω,Moviĝi malantaŭen,Retroceder,,Liiku taaksepäin,Reculer,Hátra mozgás,Movimento in indietro,後退,뒤로 이동,Achteruit bewegen,Gå bakover,Idź do tyłu,Mover-se para trás,,Deplasare în spate,Движение назад,Крећи се уназад,Flytta bakåt,Geriye doğru hareket et,Рухатись назад,Движение назад +Strafe left,CNTRLMNU_MOVELEFT,,,,Úkrok vlevo,Flyt til venstre,Nach links bewegen,Μετακίνηση προς τα αριστερά,Flankmovi maldekstren,Moverse a la izquierda,,Astu sivuun vasemmalle,Aller à Gauche,Balra oldalazás,Movimento laterale a sinistra,左移動,왼쪽으로 이동,Verplaats naar links,Strafe venstre,Unik w lewo,Mover-se para a esquerda,,Deplasare diagonală stânga,Движение влево,Крећи се лево,Strafe till vänster,Strafe sola,Рухатись вліво,Движение в ляво +Strafe right,CNTRLMNU_MOVERIGHT,,,,Úkrok vpravo,Flyt til højre,Nach rechts bewegen,Μετακίνηση προς τα δεξιά,Flankmovi dekstren,Moverse a la derecha,,Astu sivuun oikealle,Aller à Droite,Jobbra oldalazás,Movimento laterale a destra,右移動,오른쪽으로 이동,Verplaats naar rechts,Strafe til høyre,Unik w prawo,Mover-se para a direita,,Deplasare diagonală dreapta,Движение вправо,Крећи се десно,Strafe till höger,Strafe sağa,Рухатись вправо,Движение в дясно +Turn left,CNTRLMNU_TURNLEFT,,,,Otočení vlevo,Drej til venstre,Nach links drehen,Γύρνα αριστερά,Turni maldekstren,Girar a la izquierda,,Käänny vasemmalle,Tourner à Gauche,Balra fordul,"Gira a sinistra +",左を向く,왼쪽으로 회전,Draai naar links,Sving til venstre,Obróć się w lewo,Girar para a esquerda,,Întoarcere stânga,Поворот налево,Окрени се лево,Sväng vänster,Sola dön,Повернутись ліворуч,Обръщане в ляво +Turn right,CNTRLMNU_TURNRIGHT,,,,Otočení vpravo,Drej til højre,Nach rechts drehen,Γύρνα δεξιά,Turni dekstren,Girar a la derecha,,Käänny oikealle,Tourner à Droite,Jobbra fordul,Gira a destra,右を向く,오른쪽으로 회전,Draai naar rechts,Sving til høyre,Obróć się w prawo,Girar para a direita,,Întoarcere dreapta,Поворот направо,Окрени се десно,Sväng höger,Sağa dön,Повернутись праворуч,Обръщане в дясно +Quick Turn,CNTRLMNU_TURN180,,,,Rychlé otočení,Hurtig drejning,Schnelle Drehung,Γρήγορη γύριση,Rapida turno,Giro rápido,,Pikakäännös,Faire un 180,Megfordulás,Rotazione rapida,背後を向く,빠른 회전,Snelle draai,Rask sving,Szybki Obrót,Giro rápido,,Întoarcere rapidă,Быстрый разворот,Брзи окрет,Snabb vändning,Hızlı Dönüş,Швидкий розворот,Бързо обръщане +Jump,CNTRLMNU_JUMP,,,,Skok,Hop,Springen,Πήδα,Salti,Saltar,,Hyppää,Sauter,Ugrás,Salto,ジャンプ,점프,Springen,Hopp,Skok,Pular,Saltar,Salt,Прыжок,Скок,Hoppa,Atlama,Стрибок,Скок +Crouch,CNTRLMNU_CROUCH,,,,Kleknutí,Kryb,Ducken,Σκύψιμο,Kaŭri,Agacharse,,Kyyristy,S'accroupir (tenir),Guggolás,Abbassarsi,屈む,숙이기,Hurken,Huk,Kucnięcie,Agachar,,Ghemuire,Присесть,Чучни,Huk,Çömelme,Присісти,Клякане +Crouch Toggle,CNTRLMNU_TOGGLECROUCH,,,,Přepnout kleknutí,Krybbe omskifter,Ducken an/aus,Εναλλαγή σκύψιμο,Kaŭrobaskuli,Alternar agachado,,Kyyristymisen vaihtokytkin,S'accroupir (alterner),Guggolási kapcsoló,Attivare/disattivare abbassamento,屈む切替,숙이기 토글,Hurken Toggle,,Przełącz kucnięcie,Agachar (alternar),,Comutator ghemuire,Присесть/встать,Чучни (без држања),Växla huk,Çömelme anahtarı,Сісти/встати,Клякане постоянно +Mouse look,CNTRLMNU_MOUSELOOK,,,,Pohled myší,Musens udseende,Maus-Blick,Κοίτα με το ποντίκι,Musrigardo,Vista con ratón,,Hiirikatselu,Vue à la souris,Egérrel való nézelődés,Modalità vista col mouse,マウス視点上下化,마우스 룩,Muis-look,Museblikk,Rozglądanie się myszką,Visão com o mouse,Vista com o rato,Privire în jur cu mouse,Обзор мышью,Гледај мишем,Musens utseende,Fare bakışı,Огляд мишкою,Поглед с мишката +Look up,CNTRLMNU_LOOKUP,Look doesn't change the aim! It only alters the view pitch,,,Pohled vzhůru,Se op,Nach oben schauen,Κοίτα απάνω,Rigardi supren,Mirar arriba,,Katso ylös,Regarder en haut,Felfele nézés,Guarda sopra,視点を上げる,위로 보기,Kijk omhoog,Se opp,Patrz w górę,Olhar para cima,,Privire în sus,Смотреть вверх,Гледај горе,Titta uppåt,Yukarı bak.,Подивитись вверх,Поглед нагоре +Look down,CNTRLMNU_LOOKDOWN,,,,Pohled dolů,Se nedad,Nach unten schauen,Κοίτα κάτω,Rigardi malsupren,Mirar abajo,,Katso alas,Regarder en bas,Lefele nézés,Guarda sotto,視点を下げる,아래로 보기,Kijk naar beneden,Se nedover,Patrz w dół,Olhar para baixo,,Privire în jos,Смотреть вниз,Гледај доле,Titta ner,Aşağı bak.,Подивитись вниз,Поглед надолу +Center view,CNTRLMNU_CENTERVIEW,,,Centre view,Vystředit pohled,Centreret visning,Ansicht zentrieren,Προβολή στο κέντρο,Centrigi vidon,Centrar vista,,Keskitä katse,Recentrer Vue,Nézet középreigazítása,Sguardo centrato,視点を戻す,중앙 시점으로 보기,Middenaanzicht,Midtstilt visning,Wyśrodkuj widok,Olhar para o centro,,Centrare privire,Отцентрировать взгляд,Централизирај поглед,Centrerad vy,Merkezden görünüm,Центрувати погляд,Центриране на погледа +Run,CNTRLMNU_RUN,,,,Běh,Kør,Rennen,Τρέχα,Kuri,Correr,,Juokse,Courir (tenir),Futás,Corri,駆け足,달리기,Rennen,Kjør,Bieg,Correr,,Fugă,Бежать,Трчи,Spring,Koşmak,Біг,Бягане +Toggle Run,CNTRLMNU_TOGGLERUN,,,,Přepnout běh,Skift Kør,Rennen an/aus,Ενεργοποίηση τρέξιμου,Baskuligi kuron,Alternar «Correr»,,Juoksun vaihtokytkin,Courir (alterner),Futás kapcsoló,Abilita/disabilita corsa,常時駆け足切替,달리기 토글,Rennen aan/uit,Veksle Kjør,Przełącz bieg,Correr (alternar),,Comutator fugă,Бежать/идти,Трчи (без држања),Växla springa,Değiştir Çalıştır,Бігти / ходити,Бягане постоянно +Strafe,CNTRLMNU_STRAFE,,,,Pohyb do stran,Strafe,Seitwärts,,Flankmovi,Desplazamiento,,Astu sivuttain,Pas de côté,Oldalazás,Spostamento laterale,横移動化,양옆으로 이동,Zijdelings bewegen,,Uniki,Deslocamento lateral,,Deplasare în diagonală,Движение боком,Кретање у страну,Strafe,,Рухатись боком,Странично движение +Show Scoreboard,CNTRLMNU_SCOREBOARD,,,,Zobrazit tabulku skóre,Vis resultattavle,Punktetafel anzeigen,Εμφάνιση πίνακα αποτελεσμάτων,Montri poentotabulon,Mostrar marcador,,Näytä pistetaulu,Afficher Scores (tenir),Eredményjelző megjelenítése,Mostra la tabella punteggio,スコアボード表示,점수창 표시,Scorebord tonen,Vis resultattavle,Pokaż tablicę wyników,Exibir placar,,Afișare tabelă de marcaj,Таблица очков,Табела,Visa resultattavlan,Skor Tablosunu Göster,Таблиця лідерів,Покажи резултати +Action,CNTRLMNU_ACTION,,,,Akce,Handling,Aktion,Δράσεις,Ago,Acción,,Toiminta,,Akció,Azione,アクション,동작,Actie,Handling,Akcja,Ação,,Acțiuni,Основное,Радња,Åtgärd,Eylem,Дії,Действие +Customize Action Controls,CNTRLMNU_ACTION_TITLE,,,,Nastavení ovládání akcí,Tilpas handlingskontroller,Aktions-Steuerung einstellen,Προσαρμογή των χειριστηρίων δράσης,Adapti agajn regilojn,Cambiar controles de acción,,Toimintaohjausasetukset,Changer Contrôles Action,Akció beállítások testreszabása,Personalizza i controlli di azione,アクション操作設定,사용자 지정 동작 컨트롤,Aanpassen van de actiecontroles,Tilpass handlingskontroller,Ustaw Klawisze Akcji,Personalizar comandos de ação,Configurar Controlos de Ação,Personalizare schemă acțiuni,Основные клавиши управления,Контроле радње,Anpassa kontrollerna för åtgärder,Eylem Kontrollerini Özelleştirme,Налаштування елементів дій,Персонализиране на контролите за действие +Chat,CNTRLMNU_CHAT,,,,,,,Μίλα,Babili,,,Keskustelu,,,,チャット,채팅,,,Czat,Bate-papo,Conversar,Conversație,Чат,Ћаскање,Chatt,Sohbet,Чат,Чат +Multiplayer,MNU_MULTIPLAYER,,,,,,Mehrspieler,,Plurludanta,Multijugador,,Moninpeli,Multijoueur,Többjátékos,Multigiocatore,マルチプレイヤー,,,Flerspiller,Tryb Wieloosobowy,Multijogador,,Joc Online,Сетевая игра,,Flera spelare,Çok Oyunculu,Гра в мережі,Онлайн игра +Say,CNTRLMNU_SAY,,,,Říct,Sig,Reden,Πές,Diri,Hablar,,Sano,Parler,Üzenet ,Parla,発言,채팅하기,Zeg,Si,Powiedz,Dizer,,Vorbește,Сообщение,Пиши,Säg,Söyle,Написати повідомлення,Съобщение +Customize Chat Controls,CNTRLMNU_CHAT_TITLE,,,,Nastavení ovládání chatu,Tilpas chat-kontrollerne,Chat-Steuerung einstellen,Προσαρμογή ελέγχου συνομιλίας,Adapti babilajn regilojn,Cambiar controles de chat,,Keskusteluohjausasetukset,Changer Contrôles Chat,Chatbeállítások testreszabása,Personalizza i controlli della chat,チャット操作設定,사용자 지정 채팅 컨트롤,Chat-controles aanpassen aan uw wensen,Tilpass chattekontroller,Ustaw Klawisze Czatu,Personalizar comandos do bate-papo,Configurar Controlos de Chat,Personalizare control scriere,Клавиши управления чатом,Контроле ћаскања,Anpassa kontrollerna för chatt,Sohbet Kontrollerini Özelleştirme,Клавіші керування чатом,Персонализиране на контролите за чата +Customize Weapon Controls,CNTRLMNU_WEAPONS_TITLE,,,,Nastavení ovládání zbraní,Tilpas våbenkontroller,Waffen-Steuerung einstellen,Προσαρμογή ελέγχου όπλων,Adapti armilojn regilojn,Cambiar controles de armas,,Aseohjausasetukset,Changer Contrôles Armes,Fegyverbeállítások testreszabása,Personalizza i controlli delle armi,武器操作設定,사용자 지정 무기 컨트롤,Wapencontroles aanpassen aan uw eigen wensen,Tilpass våpenkontroller,Ustaw Klawisze Broni,Personalizar comandos de arma,Configurar Controlos de Armas,Personalizare control arme,Клавиши управления оружием,Контроле оружја,Anpassa vapenkontroller,Silah Kontrollerini Özelleştirme,Клавіші керування зброєю,Персонализиране на контролите за оръжия +Customize Inventory Controls,CNTRLMNU_INVENTORY_TITLE,,,,Nastavení ovládání inventáře,Tilpas kontrol af inventar,Inventar-Steuerung einstellen,Προσαρμογή Ελέγχου Απογραφής,Adapti inventarajn regilojn,Cambiar controles de inventario,,Varusteohjausasetukset,Changer Contrôles Inventaires,Eszköztár beállítások testreszabása,Personalizza i controlli dell'inventario,インベントリ操作設定,사용자 지정 인벤토리 컨트롤,Inventariscontroles aanpassen aan uw wensen,Tilpass beholdningskontroller,Ustaw Klawisze Ekwipunku,Personalizar comandos do inventário,Configurar Controlos de Inventário,Personalizare control inventar,Клавиши управления инвентарём,Контроле складишта,Anpassa kontrollerna för inventarier,Envanter Kontrollerini Özelleştirme,Клавіші керування інвентарем,Персонализиране на контролите за инвентара +Customize Other Controls,CNTRLMNU_OTHER_TITLE,,,,Nastavení ostatních ovládání,Tilpas andre kontrolelementer,Sonstige Steuerung einstellen,Προσαρμογή άλλων ελέγχων,Adapti ekstrajn regilojn,Cambiar otros controles,,Muut ohjausasetukset,Changer Autres Contrôles,Egyéb irányítás testreszabása,Personalizza altri controlli,その他の操作設定,사용자 지정 그 외 컨트롤,Andere bedieningselementen aanpassen,Tilpass andre kontroller,Ustaw Inne Klawisze,Personalizar outros comandos,Configurar Outros Controlos,Personalizare scheme de control diverse,Прочие клавиши,Друге контроле,Anpassa andra kontroller,Diğer Kontrolleri Özelleştirme,Інші клавіші,Персонализиране на други контроли +Weapons,CNTRLMNU_WEAPONS,,,,Zbraně,Våben,Waffen,Όπλα,Armiloj,Armas,,Aseet,Armes,Fegyverek,Armi,武器,무기,Wapens,Våpen,Bronie,Armas,,Arme,Оружие,Оружје,Vapen,Silahlar,Зброя,Оръжия +Next weapon,CNTRLMNU_NEXTWEAPON,,,,Další zbraň,Næste våben,Nächste Waffe,Επόμενο όπλο,Sekva armilo,Arma siguiente,,Seuraava ase,Arme Suivante,Következő fegyver,Arma successiva,次の武器,다음 무기,Volgende wapen,Neste våpen,Następna broń,Arma seguinte,,Arma următoare,Следующее оружие,Следеће оружје,Nästa vapen,Sonraki silah,Наступна зброя,Следващо оръжие +Previous weapon,CNTRLMNU_PREVIOUSWEAPON,,,,Předchozí zbraň,Forrige våben,Vorherige Waffe,Προηγούμενο όπλο,Antaŭa armilo,Arma anterior,,Edellinen ase,Arme Précédente,Előző fegyver,Arma precedente,前の武器,이전 무기,Vorige wapen,Forrige våpen,Poprzednia broń,Arma anterior,,Arma anterioară,Предыдущее оружие,Претходно оружје,Föregående vapen,Önceki silah,Попередня зброя,Предишно оръжие +Weapon 1,CNTRLMNU_SLOT1,Todo - make game specific,,,Slot zbraně 1,Våben 1,Waffe 1,Όπλο 1,Armilo 1,Arma 1,,Aselokero 1,Emplacement D'Arme 1,1. fegyver,Slot arma 1,武器スロット 1,무기 슬롯 1,Wapenslot 1,Våpen 1,Broń 1,Arma 1,,Arma 1,Первое оружие,Оружје 1,Vapen 1,Silah 1,Зброя 1,Оръжие 1 +Weapon 2,CNTRLMNU_SLOT2,"only show appropriate slots per game +",,,Slot zbraně 2,Våben 2,Waffe 2,Όπλο 2,Armilo 2,Arma 2,,Aselokero 2,Emplacement D'Arme 2,2. fegyver,Slot arma 2,武器スロット 2,무기 슬롯 2,Wapenslot 2,Våpen 2,Broń 2,Arma 2,,Arma 2,Второе оружие,Оружје 2,Vapen 2,Silah 2,Зброя 2,Оръжие 2 +Weapon 3,CNTRLMNU_SLOT3,,,,Slot zbraně 3,Våben 3,Waffe 3,Όπλο 3,Armilo 3,Arma 3,,Aselokero 3,Emplacement D'Arme 3,3. fegyver,Slot arma 3,武器スロット 3,무기 슬롯 3,Wapenslot 3,Våpen 3,Broń 3,Arma 3,,Arma 3,Третье оружие,Оружје 3,Vapen 3,Silah 3,Зброя 3,Оръжие 3 +Weapon 4,CNTRLMNU_SLOT4,,,,Slot zbraně 4,Våben 4,Waffe 4,Όπλο 4,Armilo 4,Arma 4,,Aselokero 4,Emplacement D'Arme 4,4. fegyver,Slot arma 4,武器スロット 4,무기 슬롯 4,Wapenslot 4,Våpen 4,Broń 4,Arma 4,,Arma 4,Четвёртое оружие,Оружје 4,Vapen 4,Silah 4,Зброя 4,Оръжие 4 +Weapon 5,CNTRLMNU_SLOT5,,,,Slot zbraně 5,Våben 5,Waffe 5,Όπλο 5,Armilo 5,Arma 5,,Aselokero 5,Emplacement D'Arme 5,5. fegyver,Slot arma 5,武器スロット 5,무기 슬롯 5,Wapenslot 5,Våpen 5,Broń 5,Arma 5,,Arma 5,Пятое оружие,Оружје 5,Vapen 5,Silah 5,Зброя 5,Оръжие 5 +Weapon 6,CNTRLMNU_SLOT6,,,,Slot zbraně 6,Våben 6,Waffe 6,Όπλο 6,Armilo 6,Arma 6,,Aselokero 6,Emplacement D'Arme 6,6. fegyver,Slot arma 6,武器スロット 6,무기 슬롯 6,Wapenslot 6,Våpen 6,Broń 6,Arma 6,,Arma 6,Шестое оружие,Оружје 6,Vapen 6,Silah 6,Зброя 6,Оръжие 6 +Weapon 7,CNTRLMNU_SLOT7,,,,Slot zbraně 7,Våben 7,Waffe 7,Όπλο 7,Armilo 7,Arma 7,,Aselokero 7,Emplacement D'Arme 7,7. fegyver,Slot arma 7,武器スロット 7,무기 슬롯 7,Wapenslot 7,Våpen 7,Broń 7,Arma 7,,Arma 7,Седьмое оружие,Оружје 7,Vapen 7,Silah 7,Зброя 7,Оръжие 7 +Weapon 8,CNTRLMNU_SLOT8,,,,Slot zbraně 8,Våben 8,Waffe 8,Όπλο 8,Armilo 8,Arma 8,,Aselokero 8,Emplacement D'Arme 8,8. fegyver,Slot arma 8,武器スロット 8,무기 슬롯 8,Wapenslot 8,Våpen 8,Broń 8,Arma 8,,Arma 8,Восьмое оружие,Оружје 8,Vapen 8,Silah 8,Зброя 8,Оръжие 8 +Weapon 9,CNTRLMNU_SLOT9,,,,Slot zbraně 9,Våben 9,Waffe 9,Όπλο 9,Armilo 9,Arma 9,,Aselokero 9,Emplacement D'Arme 9,9. fegyver,Slot arma 9,武器スロット 9,무기 슬롯 9,Wapenslot 9,Våpen 9,Broń 9,Arma 9,,Arma 9,Девятое оружие,Оружје 9,Vapen 9,Silah 9,Зброя 9,Оръжие 9 +Weapon 10,CNTRLMNU_SLOT0,,,,Slot zbraně 10,Våben 10,Waffe 10,Όπλο 0,Armilo 10,Arma 10,,Aselokero 0,Emplacement D'Arme 0,0. fegyver,Slot arma 0,武器スロット 0,무기 슬롯 0,Wapenslot 0,Våpen 10,Broń 10,Arma 10,,Arma 0,Десятое оружие,Оружје 0,Vapen 10,Silah 10,Зброя 0,Оръжие 10 +Inventory,CNTRLMNU_INVENTORY,,,,Inventář,Inventar,Inventar,Άντικείμενα,Inventaro,Inventario,,Varusteet,Inventaire,Eszköztár beállítások testreszabása,Inventario,所持品,인벤토리,Inventaris,Inventar,Ekwipunek,Inventário,,Inventar,Инвентарь,Инвентар,Inventarium,Envanter,Інвентар,Инвентар +Activate item,CNTRLMNU_USEITEM,,,,Aktivovat předmět,Aktiver genstand,Gegenstand aktivieren,Ενεργοποίηση αντικείμενου,Aktivigi objekton,Activar objeto,,Aktivoi varuste,Activer objet,Eszköz használata,Attiva oggetto,アイテムを使用,선택한 아이템 사용,Item activeren,Aktiver gjenstand,Użyj przedmiot,Ativar item,,Activează obiectul,Использовать предмет,Активирај предмет,Aktivera föremål,Öğeyi etkinleştir,Активувати предмет,Използвай предмета +Activate all items,CNTRLMNU_USEALLITEMS,,,,Aktivovat všechny předměty,Aktivering af alle genstande,Alle Gegenstände aktivieren,Ενεργοποίησε όλα τα αντικείμενα,Aktivigi ĉiujn objektojn,Activar todos los objetos,,Aktivoi kaikki varusteet,Activer tous les objets,Minden eszköz használata,Attiva tutti gli oggetti,全てのアイテムを使用,모든 아이템 사용,Activeer alle items,Aktiver alle gjenstander,Użyj wszystkie przedmioty,Ativar todos os itens,,Activează tot inventarul,Использовать все предметы,Активирај све предмете,Aktivera alla föremål,Tüm öğeleri etkinleştirin,Активувати усі предмети,Използвай всички предмети +Next item,CNTRLMNU_NEXTITEM,,,,Další předmět,Næste genstand,Nächster Gegenstand,Επόμενο αντικείμενο,Sekva objekto,Objeto siguiente,,Seuraava varuste,Objet suivant,Következő eszköz,Oggetto successivo,次のアイテム,다음 아이템,Volgende item,Neste element,Następny przedmiot,Item seguinte,,Următorul obiect,Следующий предмет,Следећи предмет,Nästa objekt,Sonraki madde,Наступний предмет,Следващ предмет +Previous item,CNTRLMNU_PREVIOUSITEM,,,,Předchozí předmět,Forrige genstand,Vorheriger Gegenstand,Προηγούμενο αντικείμενο,Antaŭa objekto,Objeto anterior,,Edellinen varuste,Objet précédent,Előző eszköz,Oggetto precedente,前のアイテム,이전 아이템,Vorige item,Forrige element,Poprzedni przedmiot,Item anterior,,Obiect anterior,Предыдущий предмет,Претходни предмет,Föregående objekt,Önceki madde,Попередній предмет,Предишен предмет +Customize Map Controls,MAPCNTRLMNU_TITLE,most are not used yet but will be,,,Nastavení ovládání mapy,Tilpas kontrolelementer til kortet,Automapsteuerung einstellen,Προσαρμογή στοιχείων ελέγχου χάρτη,Adapti map-regilojn,Cambiar controles del mapa,,Kartanohjausasetukset,Contrôles Carte,Térkép irányításának testreszabása,Personalizza i controlli mappa,マップコントロール カスタマイズ,미니맵 단축키 설정,Kaartcontroles aanpassen,Tilpass kartkontroller,Ustaw klawisze mapy,Peronalizar comandos do mapa,,Personalizare schemă de control a hărții,Клавиши управления автокартой,Промени контроле мапе,Anpassa kartkontroller,Harita Kontrollerini Özelleştirme,Клавіші керування автомапою,Персонализиране контролите за картата +Map Controls,MAPCNTRLMNU_CONTROLS,,,,Mapa,Kontrolelementer til kort,Automapsteuerung,Έλεγχοι χάρτη,Map-regiloj,Controles del mapa,,Kartanohjaus,Contrôles de la carte,Térkép irányítása,Controlli mappa,マップコントロール,미니맵 조정,Kaartcontroles,Kartkontroller,Klawisze mapy,Comandos do mapa,,Schemă de control a hărtii,Автокарта,Контроле мапе,Kontroller för kartor,Harita Kontrolleri,Автомапа,Контроли за карта +Pan left,MAPCNTRLMNU_PANLEFT,,,,Doleva,Panorere til venstre,Nach links,Μετακίνηση προς τα αριστερά,Alturni maldekstren,Mover a la izquierda,,Panoroi vasemmalle,Aller à gauche,Balra igazítás,Sposta a sinistra,左に振る,왼쪽으로 이동,Pan links,Panorer til venstre,Przesuń w lewo,Mover para a esquerda,,Mutare spre stânga,Сдвиг влево,Лево,Panorera till vänster,Sola kaydırın,Зсув вліво,Преместване наляво +Pan right,MAPCNTRLMNU_PANRIGHT,,,,Doprava,Panorering til højre,Nach rechts,Μετακίνηση προς τα δεξιά,Alturni dekstren,Mover a la derecha,,Panoroi oikealle,Aller à droite,Jobbra igazítás,Sposta a destra,右に振る,오른쪽으로 이동,Pan rechts,Panorer til høyre,Przesuń w prawo,Mover para a direita,,Mutare spre dreapta,Сдвиг вправо,Десно,Panorera till höger,Sağa kaydırın,Зсув вправо,Преместване на дясно +Pan up,MAPCNTRLMNU_PANUP,,,,Nahoru,Panorere op,Nach oben,Μετακίνηση προς τα πάνω,Alturni supren,Mover hacia arriba,,Panoroi ylös,Aller en haut,Felfele igazítás,Sposta sopra,上に振る,위쪽으로 이동,Pan omhoog,Panorer opp,Przesuń w górę,Mover para cima,,Mutare în sus,Сдвиг вверх,Горе,Panorera uppåt,Yukarı kaydırın,Зсув вверх,Преместване на горе +Pan down,MAPCNTRLMNU_PANDOWN,,,,Dolů,Panorere ned,Nach unten,Μετακίνηση προς τα κάτω,Alturni malsupren,Mover hacia abajo,,Panoroi alas,Aller en bas,Lefele igazítás,Sposta sotto,下に振る,아래쪽으로 이동,Pan neer,Panorer ned,Przesuń w dół,Mover para baixo,,Mutare în jos,Сдвиг вниз,Доле,Panorera ner,Aşağı kaydırın,Зсув вниз,Преместване на долу +Zoom in,MAPCNTRLMNU_ZOOMIN,,,,Přiblížit,Zoom ind,Reinzoomen,Μεγέθυνση,Zomi,Acercar,,Lähennä,Zoom avant,Ráközelítés,Ingrandisci,ズームイン,줌 확대,Inzoomen,Zoom inn,Przybliż,Ampliar,,Apropriere Cameră,Приблизить,Увеличати,Zooma in,Yakınlaştır,Наблизити,Приближи +Zoom out,MAPCNTRLMNU_ZOOMOUT,,,,Oddálit,Zoom ud,Rauszoomen,Σμίκρυνση,Malzomi,Alejar,,Loitonna,Zoom arrière,Távolítás,Rimpicciolisci,ズームアウト,줌 축소,Uitzoomen,Zoom ut,Oddal,Afastar,,Depărtare Cameră,Отдалить,Одзумирати,Zooma ut,Uzaklaştır,Віддалити,Отдалечи +Toggle zoom,MAPCNTRLMNU_TOGGLEZOOM,,,,Přiblížení vyp./zap.,Skift mellem zoom,Zoom an/aus,Εναλλαγή ζουμ,Baskuligi zomon,Alternar zoom,,Zoomauksen vaihtokytkin,Zoom On/Off,Közelítés átkapcsolása,Abilita/disabilita zoom,ズーム切替,표준배율 조정,Omschakelen van de zoom,Veksle mellom zoom,Przełącz przybliżanie,Ativar/desativar zoom,,Comutator Zoom,Приближение (перекл.),Укључи зум,Växla zoom,Yakınlaştırmayı aç / kapat,Перемикач наближення,Приближи постоянно +Toggle follow,MAPCNTRLMNU_TOGGLEFOLLOW,,,,Sledování hráče vyp./zap.,Skift følge,Folgen an/aus,Εναλλαγή ακολουθίας,Baskuligi sekvon,Alternar seguimiento,,Seuraamistilan vaihtokytkin,Suivi On/Off,Követés átkapcsolása,Abilita/disabilita scorrimento mappa,追従切替,추적모드 조정,Schakelen volgen,Veksle følge,Przełącz śledzenie,Ativar/desativar seguimento,,Comutator urmărire jucător,Привязка к игроку (перекл.),Укључи праћење,Växla följning,Takip etmeyi değiştir,Слідувати за гравцем,Следвай постаянно +Toggle grid,MAPCNTRLMNU_TOGGLEGRID,,,,Mřížka vyp./zap.,Skift gitter,Gitter an/aus,Εναλλαγή πλέγματος,Baskuligi kradon,Alternar cuadrícula,,Ruudukon vaihtokytkin,Grille On/Off,Rács kapcsolása,Abilita/disabilita la griglia,グリッド切替,그리드 조정,Kiesnet,Veksle rutenett,Przełącz siatkę,Ativar/desativar grade,,Comutator grilă,Сетка (перекл.),Укључи координатну мрежу,Växla rutnät,Izgarayı değiştir,Увімкнути сітку,Включи координатна мрежа +Toggle rotate,MAPCNTRLMNU_ROTATE,,,,Otáčení vyp./zap.,Skift til rotere,Rotation an/aus,Εναλλαγή περιστροφής,Baskuligi turnadon,Alternar rotación,,Kääntämisen vaihtokytkin,Rotation On/Off,Forgás kapcsolása,Abilita/disabilita la rotazione,回転切替,,Toggle rotatie,Veksle mellom rotasjon,Przełącz obracanie,Ativar/desativar rotação,,Comutator rotire,Вращение (перекл.),Укључи ротацију,Växla rotera,Döndürmeyi değiştir,Ротація мапи,Завъртане (превключване) +Toggle texture,MAPCNTRLMNU_TOGGLETEXTURE,,,,Textury vyp./zap.,Skift tekstur,Texturen an/aus,Εναλλαγή υφής,Baskuligi teksturon,Alternar textura,,Pintakuvioinnin vaihtokytkin,Textures On/Off,Textúra kapcsolása,Abilita/disabilita le texture,テクスチャ切替,미니맵 텍스쳐 조정,Toggle textuur,Veksle tekstur,Przełącz tekstury,Ativar/desativar texturas,,Comutator mod texturat,Текстуры (перекл.),Укључи текстуру,Växla textur,Dokuyu değiştir,Увімкнути текстури, +Toggle automap,CNTRLMNU_AUTOMAP,,,,Otevřít/zavřít automapu,Skift til automap,Automap an/aus,Εναλλαγή automap,Baskuligi aŭtomatan mapon,Alternar automapa,,Kytke automaattikartta päälle/pois,Ouvrir/Fermer Carte,Térkép ki/bekapcsolása,Abilita/disabilita l'automappa,オートマップの切替,오토맵 조정,Automap aan/uit,Veksle mellom automap,Włącz mapę,Ativar/desativar automapa,,Comutator hartă computerizată,Автокарта (перекл.),Прикажи аутомапу,Växla automap,Otomatik haritayı değiştir,Відкрити автомапу, +Chasecam,CNTRLMNU_CHASECAM,,,,Kamera z třetí osoby,Chasecam,Verfolgerkamera,,Ĉaskamerao,Cámara de seguimiento,,Seurantakamera,Caméra 3ième personne,Külsőnézetű kamera,Telecamera di inseguimento,背後視点,3인칭 카메라,,,Kamera Śledzenia,Câmera em terceira pessoa,Câmera em terceira-pessoa,Cameră urmăritoare,Вид от 3-го лица,Чејс-кем,,,Вид від третьої особи, +Screenshot,CNTRLMNU_SCREENSHOT,,,,Pořídit snímek obrazovky,Skærmbillede,,Στιγμιότυπο,Ekrankopio,Captura de pantalla,,Kuvakaappaus,Capture d'écran,Képernyő lefényképezése,Cattura schermo,画面キャプチャ,스크린샷,,Skjermbilde,Zrzut ekranu,Captura de tela,,Captură ecran,Снимок экрана,Усликај,Skärmdump,Ekran görüntüsü,Скріншот, +Open console,CNTRLMNU_CONSOLE,,,,Otevřít konzoli,Åbn konsollen,Konsole öffnen,Ανοίξτε την κονσόλα,Malfermi konzolon,Abrir consola,,Avaa konsoli,Ouvrir Console,Konzol megnyitása,Apri la console,コンソールを開く,콘솔 열기,Open console,Åpne konsoll,Otwórz konsolę,Abrir console,Abrir consola,Deschide consola,Открыть консоль,Отвори консолу,Öppna konsolen,Açık konsol,Відкрити консоль, +Pause,CNTRLMNU_PAUSE,,,,Pauza,,,Πάυση,Paŭzo,Pausa,,Tauko,,Szünet,Pausa,ポーズ,일시정지,Pauze,,Pauza,Pausar,,Pauză,Пауза,Пауза,Pausa,Duraklat,Пауза, +Increase Display Size,CNTRLMNU_DISPLAY_INC,,,,Zvětšit velikost obrazovky,Forøg visningsstørrelsen,Anzeige vergrößern,Αύξηση μεγέθους οθόνης,Kreskigi ekrangrandon,Agrandar ventana,,Suurenna näytön kokoa,Agrandir l'affichage,Képméret növelése,Aumenta la dimensione del display,画面サイズを拡大,화면 크기 늘리기,Vergroot het display,Øk visningsstørrelse,Powiększ Rozmiar Wyświetlania,Aumentar tamanho da exibição,Aumentar Tamanho do Ecrã,Mărire ecran,Увеличить размер экрана,Повећајте величину екрана,Öka skärmstorleken,Ekran Boyutunu Artırın,Збільшити розмір екрану, +Decrease Display Size,CNTRLMNU_DISPLAY_DEC,,,,Zmenšit velikost obrazovky,Formindsk skærmstørrelse,Anzeige verkleinern,Μείωση μεγέθους οθόνης,Malkreskigi ekrangrandon,Reducir ventana,,Pienennä näytön kokoa,Réduire l'affichage,Képméret csökkentése,Riduci la dimensione del display,画面サイズを縮小,화면 크기 줄이기,Verlaag het display,Reduser visningsstørrelse,Pomniejsz Rozmiar Wyświetlania,Reduzir tamanho da exibição,Diminuir Tamanho do Ecrã,Micșorare ecran,Уменьшить размер экрана,Смањите величину екрана,Minska visningsstorleken,Ekran Boyutunu Azaltma,Зменшити розмір екрану, +Open Help,CNTRLMNU_OPEN_HELP,,,,Nápověda,Åbn hjælp,Hilfe öffnen,Άνοιγμα βοήθειας,Malfermi helpon,Abrir ayuda,,Avaa ohje,Ouvrir Aide,Segítség előhozása,Apri la guida,"ヘルプを開く +",도움말 열기,Open hulp,Åpne Hjelp,Otwórz Pomoc,Abrir ajuda,,Deschide Ajutor,Экран помощи,Отвори помоћ,Öppna hjälp,Açık Yardım,Відкрити екран допомоги, +Open Save Menu,CNTRLMNU_OPEN_SAVE,,,,Uložit hru,Åbn menuen Gem,Speichermenü öffnen,Άνοιγμα μενού αποθήκευσης,Malfermi konservmenuon,Menú de guardar partida,,Avaa tallennusvalikko,Ouvrir Menu Sauvegarde,Mentés menü előhozása,Apri il menu di salvataggio,セーブメニューを開く,저장 화면 열기,Menu opslaan openen,Åpne Lagre-menyen,Otwórz Menu Zapisu,Abrir menu de salvar,Abrir Menu de Gravação,Deschide meniul de salvare,Меню сохранения игры,Отвори сачуване игре,Öppna sparmenyn,Kaydet Menüsünü Aç,Меню збережень, +Open Load Menu,CNTRLMNU_OPEN_LOAD,,,,Načíst hru,Åbn indlæsningsmenuen,Lademenü öffnen,Άνοιγμα μενού φόρτωσης,Malfermi ŝargmenuon,Menú de cargar partida,,Avaa latausvalikko,Ouvrir Menu Chargement,Betöltés menü előhozása,Apri il menu di caricamento,ロードメニューを開く,불러오기 화면 열기,Menu laden openen,Åpne Last-menyen,Otwórz Menu Wczytania,Abrir menu de carregar,,Deschide meniul de încărcare,Меню загрузки игры,Отвори игре за учитати,Öppna laddningsmenyn,Yük Menüsünü Aç,Меню завантаженнь, +Open Options Menu,CNTRLMNU_OPEN_OPTIONS,,,,Nastavení,Åbn menuen Indstillinger,Optionsmenü öffnen,Άνοιγμα μενού επιλογών,Malfermi agordmenuon,Menú de opciones,,Avaa asetusvalikko,Ouvrir Menu Options,Beállítások menü előhozása,Apri il menu delle opzioni,オプションメニューを開く,설정 화면 열기,Menu Opties openen,Åpne Alternativer-menyen,Otwórz Menu Opcji,Abrir menu de opções,,Deschide setările,Главное меню настроек,Отвори мени опција,Öppna alternativmenyn,Seçenekler Menüsünü Aç,Головне меню параметрів, +Open Display Menu,CNTRLMNU_OPEN_DISPLAY,,,,Nastavení grafiky,Åbn menuen Visning,Anzeigemenü öffnen,Άνοιγμα μενού οθόνης,Malfermi ekranmenuon,Menú de opciones de visualización,,Avaa näyttövalikko,Ouvrir Menu Affichage,Megjelenítés menü előhozása,Apri il menu del display,ディスプレイメニューを開く,디스플레이 화면 열기,Displaymenu openen,Åpne visningsmeny,Otwórz Menu Wyświetlania,Abrir menu de vídeo,,Deschide setările de afișare,Меню настроек видео,Отвори мени приказа,Öppna visningsmenyn,Ekran Menüsünü Aç,Параметри відео, +Quicksave,CNTRLMNU_QUICKSAVE,,,,Rychlé uložení,Quicksave,Schnellspeichern,Γρήγορη αποθήκευση,Rapidkonservo,Guardado rápido,,Pikatallenna,Sauv. Rapide,Gyorsmentés,Salvataggio rapido,クイックセーブ,빠른 저장,Snel opslaan,Hurtiglagring,Szybki Zapis,Salvar rapidamente,Gravação rápida,Salvare rapidă,Быстрое сохранение,Брзо-сачувај,Snabbspara,Hızlı Tasarruf,Швидке збереження, +Quickload,CNTRLMNU_QUICKLOAD,,,,Rychlé načtení,Quickload,Schnellladen,Γρήγορη φόρτωση,Rapidŝargo,Cargado rápido,,Pikalataa,Charg. Rapide,Gyorstöltés,Caricamento rapido,クイックロード,빠른 불러오기,Snel laden,Hurtiglasting,Szybkie Wczytanie,Carregar rapidamente,,Încărcare rapidă,Быстрая загрузка,Брзо-учитај,Snabbladdning,Hızlı Yükleme,Швидке завантаження, +Exit to Main Menu,CNTRLMNU_EXIT_TO_MAIN,,,,Odejít do hlavního menu,Afslut til hovedmenu,Zurück zum Hauptmenü,Έξοδος στο κύριο μενού,Eliri al ĉefa menuo,Salir al menú principal,,Poistu päävalikkoon,Sortie Menu Principal,Kilépés a főmenübe,Esci dal menu principale,メインメニューに戻る,메뉴로 나오기,Afsluiten naar het hoofdmenu,Avslutt til hovedmeny,Wyjdź do Głównego Menu,Sair para o menu principal,,Revenire la meniul principal,Выход в главное меню,Изађи у главни мени,Avsluta till huvudmenyn,Ana Menüden Çıkış,Вихід в головне меню, +Toggle Messages,CNTRLMNU_TOGGLE_MESSAGES,,,,Povolit/skrýt oznámení,Skift mellem meddelelser,Nachrichten an/aus,Εναλλαγή μηνυμάτων,Baskuligi mesaĝojn,Alternar mensajes,,Kytke viestit päälle tai pois,Messages On/Off,Üzenetek kapcsolása,Toggle messaggi,メッセージ表示の切替,메시지 토글,Berichten aan/uit,Veksle meldinger,Włącz / Wyłącz Wiadomości,Ativar/desativar mensagens,,Comutator mesaje,Переключение сообщений,Таглави поруке,Växla meddelanden,Mesajları Değiştir,Увімкнути повідомлення, +Quit Game,CNTRLMNU_MENU_QUIT,,,,Ukončit hru,Afslut spil,Spiel beenden,Στάματα το παιχνίδι,Mallanĉi ludon,Salir del juego,,Lopeta peli,Quitter le Jeu,Kilépés a játékból,Esci dal gioco,ゲームを終了,게임 종료,Stop het spel,Avslutt spill,Wyjdź z Gry,Sair do jogo,,Ieși din Joc,Выход,Изађи из игре,Avsluta spelet,Oyundan Çık,Вихід, +Adjust Gamma,CNTRLMNU_ADJUST_GAMMA,,,,Nastavit gamu,Juster Gamma,Gamma-Anpassung,Ρύθμιση Γάμμα,Agordi gamaon,Ajustar gama,,Säädä gammaa,Ajuster Gamma,Gamma állítása,Aggiustamento Gamma,ガンマ値を調整,감마 조정,Gamma aanpassen,Juster gamma,Dostosuj Gammę,Ajustar gama,,Ajustare gamma,Настройка гаммы,Подесите осветљење,Justera Gamma,Gama Ayarlama,Налаштування гамми, +,,Mouse,,,,,,,,,,,,,,,,,,,,,,,,,,, +Enable mouse,MOUSEMNU_ENABLEMOUSE,,,,Povolit myš,Aktiver mus,Maus aktiv,Ενεργοποίηση ποντικιόυ,Ebligi muson,Habilitar ratón,,Ota hiiri käyttöön,Activer Souris,Egér engedélyezése,Abilita il mouse,マウスの使用,마우스 사용,Muis inschakelen,Aktiver mus,Włącz myszkę,Ativar mouse,Permitir uso do rato,Activare mouse,Использовать мышь,Укључи миш,Aktivera musen,Fareyi etkinleştir,Увімкнути миш, +Enable mouse in menus,MOUSEMNU_MOUSEINMENU,,,,Povolit myš v nabídkách,Aktiver mus i menuer,Maus aktiv in Menüs,Ενεργοποίηση ποντικιόυ στα μενού,Ebligi muson en menuoj,Usa ratón en los menús,,Ota hiiri käyttöön valikoissa,Activer Souris dans les Menus,Egér engedélyezése a menüben,Abilita il mouse nei menu,メニューでのマウスの使用,메뉴에서 마우스 사용,Muis in menu's inschakelen,Aktiver mus i menyer,Włącz myszkę w menu,Ativar mouse nos menus,Permitir rato nos menus,Activare mouse în meniuri,Использовать мышь в меню,Укључи миш у менијима,Aktivera musen i menyer,Menülerde fareyi etkinleştir,Увімкнути миш в меню, +Show back button,MOUSEMNU_SHOWBACKBUTTON,,,,Zobrazit tlačítko zpět,Vis tilbage-knappen,Zeige Zurück-Knopf,Εμφάνιση του κουμπιού επιστροφής,Montri reen-butonon,Mostrar botón de retroceso,,Näytä taaksenäppäin,Afficher le bouton retour,Vissza gomb mutatása,Mostra il bottone per tornare indietro,戻るボタンを表示,뒤로가기 버튼 보이기,Toon terug knop,Vis tilbake-knapp,Pokaż przycisk powrotu,Exibir botão de voltar,,Afișare buton de întoarcere,Расположение кнопки «назад»,Прикажи тастер за назад,Visa bakåtknappen,Geri düğmesini göster,"Кнопка ""назад""", +Cursor,MOUSEMNU_CURSOR,,,,Kurzor,Markør,,Δρομέας,Musmontrilo,,,Osoitin,Curseur,Egérmutató,Cursore,カーソル,커서,,Markør,Kursor,Cursor,,,Курсор,Курсор,Markör,İmleç,Курсор, +Horizontal sensitivity,MOUSEMNU_SENSITIVITY_X,,,,Horizontální citlivost,Vandret følsomhed,Horizontale Empfindlichkeit,Οριζόντια ευαισθησία,Horizontala sentemo,Sensibilidad horizontal,,Vaakasuuntainen herkkyys,Sensibilité horizontale,Vízszintes érzékenység,Sensibilità orizzontale,水平感度,수평 감도,Horizontale gevoeligheid,Horisontal følsomhet,Czułość pozioma,Sensibilidade horizontal,,Sensibilitate orizontală,Горизонтальная чувствительность,Хоризонтална осетљивост,Horisontell känslighet,Yatay hassasiyet,Горизонтальна чутливість, +Vertical sensitivity,MOUSEMNU_SENSITIVITY_Y,,,,Vertikální citlivost,Lodret følsomhed,Vertikale Empfindlichkeit,Κάθετη ευαισθησία,Vertikala sentemo,Sensibilidad vertical,,Pystysuuntainen herkkyys,Sensibilité verticale,Függőleges érzékenység,Sensibilità verticale,垂直感度,수직 감도,Verticale gevoeligheid,Vertikal følsomhet,Czułość pionowa,Sensibilidade vertical,,Sensibilitate verticală,Вертикальная чувствительность,Вертикална осетљивост,Vertikal känslighet,Dikey hassasiyet,Вертикальна чутливість, +Smooth mouse movement,MOUSEMNU_SMOOTHMOUSE,,,,Vyhladit pohyb myši,Jævn bevægelse af musen,Mausbewegung glätten,Ομαλή κίνηση του ποντικιού,Glata musmovo,Mov. fluido del ratón,,Sulava hiiren liike,Lissage Souris,Egérmozgás simítása,Movimento del mouse liscio,マウス操作を滑らかにする,부드러운 움직임,Vlotte muisbeweging,Jevn musebevegelse,Gładki ruch myszki,Suavizar movimento do mouse,Movimento fluído do rato,Mișcare mouse fină,Плавное перемещение,Глатки окрет,Smidig musrörelse,Pürüzsüz fare hareketi,Плавний рух миші, +Turning speed,MOUSEMNU_TURNSPEED,,,,Rychlost otáčení,Drejehastighed,Umdrehgeschwindigkeit,Ταχύτητα περιστροφής,Turnorapido,Velocidad de giro,,Kääntymisnopeus,Vitesse pour tourner,Fordulás sebessége,Velocità di rotazione,旋回速度,회전 속도,Draaisnelheid,Dreiehastighet,Szybkość obracania się,Velocidade de giro,,Viteză rotire,Скорость поворота,Брзина окрета,Vändningshastighet,Dönüş hızı,Швидкість повороту, +Mouselook speed,MOUSEMNU_MOUSELOOKSPEED,,,,Rychlost pohledu nahoru/dolů,Hastighed for mus-look,Mausblick-Geschwindigkeit,Ταχύτητα εμφάνισης ποντικιού,Musrigarda rapido,Veloc. de vista con ratón,,Katselunopeus,Vitesse Vue Souris,Egérnézés sebessége,Velocità di rotazione della vista,上下視点速度,마우스룩 속도,Mouselook snelheid,Muselook-hastighet,Szybkość rozglądania się myszką,Velocidade da visão com mouse,Velocidade de vista com rato,Viteză privire în jur cu mouse,Скорость обзора,Брзина гледања мишем,Hastighet för muspekning,Mouselook hızı,Швидкість огляду, +Forward/Backward speed,MOUSEMNU_FORWBACKSPEED,,,,Rychlost pohybu vpřed/vzad,Hastighed fremad/tilbage,Vor/Rückwärtsgeschwindigkeit,Ταχύτητα προς τα εμπρός/πίσω,Antaŭa/Malantaŭa rapido,Veloc. de avance/retroceso,,Eteen-/taaksepäin liikkeen nopeus,Vitesse Avancer/reculer,Előre/Hátra sebesség,Velocità avanti/indietro,"前進/後退速度 +",전진/후진 속도,Voorwaartse/achterwaartse snelheid,Hastighet forover/bakover,Szybkość chodzenia do przodu/do tyłu,Velocidade de deslocamento para frente/trás,,Viteză deplasare față/spate,Скорость передвижения,Брзина окрета напред/уназад,Hastighet framåt/bakåt,İleri/Geri hız,Швидкість руху вперед/назад, +Strafing speed,MOUSEMNU_STRAFESPEED,,,,Rychlost pohybu do stran,Strafing-hastighed,Seitwärtsgeschwindigkeit,Ταχύτητα καταδίωξης,Flankmova rapido,Veloc. de mov. lateral,,Sivuttaisastunnan nopeus,Vitesse Gauche/Droite,Oldalazás sebessége,Velocità movimento laterale,横移動速度,좌진/우진 속도,Zijdelings snelheid,Hastigheten for stansing,Szybkość uników,Velocidade de deslocamento lateral,,Viteză deplasare în diagonală,Скорость движения боком,Брзина стрејфа,Hastighet för strafe,Strafe hızı,Швидкість руху боком, +Always Mouselook,MOUSEMNU_ALWAYSMOUSELOOK,,,,Vždy se rozhlížet myší,Altid mus-look,Mausblick immer an,Πάντα κοίτα με το ποντίκι,Ĉiam musrigardi,Siempre mirar con ratón,,Jatkuva hiirikatselu,Toujours vue Souris,Mindig egérrel nézelődés,Vista col mouse,常に上下視点をオン,마우스룩 사용,Altijd Mouselook,Alltid muselook,Zawsze zezwalaj na rozglądanie się myszką,Visão com mouse sempre ativada,Vista com rato sempre ligada,Privire în jur cu mouse permanentă,Обзор мышью,Гледање мишем,Alltid muspekande,Her zaman Mouselook,Огляд мишкою, +Invert Mouse Y,MOUSEMNU_INVERTMOUSE,,,,Vertikálně obrátit myš,Inverter mus Y,Maus Y invertieren,Αντιστροφή ποντικιού Y,Inversi muson Y,Invertir ratón Y,,Käännä hiiri Y,Inverser Souris Y,Y tengely megfordítása,Mouse Y invertito,視点操作反転,마우스 방향 전환,Muis-Y-as omkeren,Inverter mus Y,Odwróć Myszkę - Oś Y,Inverter eixo Y do mouse,Inverter rato,Inversare axă mouse Y,Инверт. мышь по вертикали (Y),Инвертуј миш Y,Invertera mus Y,Fare Y'yi Ters Çevir,Інвертувати мишу Y, +Invert Mouse X,MOUSEMNU_INVERTMOUSEX,,,,Horizontálně obrátit myš,Inverter mus X,Maus X invertieren,Αντιστροφή ποντικιού X,Inversi muson X,Invertir ratón X,,Käännä hiiri X,Inverser Souris X,X tengely megfordítása,Mouse X invertito,視点操作反転,마우스 방향 전환,Muis-X-as omkeren,Inverter mus X,Odwróć Myszkę - Oś X,Inverter eixo X do mouse,Inverter rato X,Inversare axă mouse X,Инверт. мышь по горизонтали (X),Инвертуј миш X,Invertera mus X,Fare X'i Ters Çevir,Інвертувати мишу Х, +Upper left,OPTVAL_UPPERLEFT,,,,Vlevo nahoře,Øverste venstre,Oben links,Πάνω αριστερά,Supra maldekstre,Sup. izquierda,,Ylävasemmalla,Supérieur gauche,Bal fent,Superiore sinistro,左上,왼쪽 위,Linksboven,Øvre venstre,Lewy górny róg,Esquerda superior,,Stânga sus,Вверху слева,Горње лево,Övre vänster,Sol üst,"Кнопка ""назад"": Зверху-ліворуч", +Upper right,OPTVAL_UPPERRIGHT,,,,Vpravo nahoře,Øvre højre,Oben rechts,Πάνω δεξιά,Supra dekstre,Sup. derecha,,Yläoikealla,Supérieur droite,Jobb fent,Superiore destro,右上,오른쪽 위,Rechtsboven,Øverst til høyre,Prawy górny róg,Direita superior,,Dreapta sus,Вверху справа,Горње десно,Övre höger,Sağ üst,"Кнопка ""назад"": Зверху-праворуч", +Lower left,OPTVAL_LOWERLEFT,,,,Vlevo dole,Nederste venstre,Unten links ,Κάτω αριστερά,Suba maldekstre,Inf. izquierda,,Alavasemmalla,Inférieur gauche,Bal lent,Inferiore sinistro,左下,왼쪽 밑,Linksonder,Nedre venstre,Lewy dolny róg,Esquerda inferior,,Stânga jos,Внизу слева,Доње лево,Nedre vänster,Sol alt,"Кнопка ""назад"": Знизу-ліворуч", +Lower right,OPTVAL_LOWERRIGHT,,,,Vpravo dole,Nederste højre,Unten rechts,Κάτω δεξιά,Suba dekstre,Inf. derecha,,Alaoikealla,Inférieur droite,Jobb lent,Inferiore destro,右下,오른쪽 밑,Rechtsonder,Nedre høyre,Prawy dolny róg,Direita inferior,,Dreapta jos,Внизу справа,Доње десно,Nedre höger,Sağ alt,"Кнопка ""назад"": Знизу-праворуч", +Touchscreen-like,OPTVAL_TOUCHSCREENLIKE,,,,Jako dotyková obrazovka,Touchscreen-lignende,Wie auf einem Touchscreen,Οθόνη αφής,Tuŝekraneca,Pant. táctil,,Kosketusnäyttömäinen,Style écran tactile,Érintőképernyő-szerű,Come il Touchscreen,タッチスクリーン式,터치스크린 같게,Touchscreen-achtige,Berøringsskjerm-lignende,Jak ekrean dotykowy,Estilo touchscreen,,Precum touchscreen,Как сенсорный экран,Као додирни екран,Pekskärmsliknande,Dokunmatik ekran benzeri,Як сенсорний екран, +Simple arrow,OPTSTR_SIMPLEARROW,,,,Jednoduchý kurzor,Simpel pil,Einfacher Pfeil,Απλό βέλος,Simpla sago,Flecha simple,,Yksinkertainen nuoli,Flèche simple,Sima nyíl,Freccia semplice,シンプル,기본 커서,Eenvoudige pijl,Enkel pil,Prosta strzałka,Seta simples,Cursor simples,Săgeată simplă,Стрелка,Стрелица,Enkel pil,Basit ok,Стрілка, +System cursor,OPTSTR_SYSTEMCURSOR,,,,Systémový kurzor,Systemcursor,Systemcursor,Δείκτης συστήματος,Sistema kursoro,Cursor del sistema,,Järjestelmän osoitin,Curseur Système,Rendszer egérmutatója,Cursore di sistema,システム,시스템 커서,Systeemcursor,Systemmarkør,Kursor systemu,Cursor do sistema,,Cursor simplu,Системный курсор,Системска стрелица,Systemmarkör,Sistem imleci,Системний курсор, +Default,OPTVAL_DEFAULT,,,,Výchozí,Standard,Standard,Προεπιλογή,Defaŭlta,Por defecto,,Oletus,Défaut,Alapbeállítás,Predefinito,デフォルト,기본 설정,Standaard,Standard,Domyślne,Padrão,,Implicit,По умолчанию,Подраз.,Standard,Varsayılan,За замовчуванням, +,,Controller,,,,,,,,,,,,,,,,,,,,,,,,,,, +Configure Controller,JOYMNU_TITLE,,,,Konfigurace ovladače,Konfigurer controller,Controller konfigurieren,,Agordi ludregilon,Configurar mando,,Peliohjainasetukset,Configurer Mannette,Kontroller testreszabása,Configura il controller,コントローラー構成:,컨트롤러 구성,Controller configureren,Konfigurer kontrolleren,Konfiguruj Kontroler,Configurar controle,Configurar Comando,Configurare controller,Настроить контроллер,Конфигурација контролера,Konfigurera kontroller,Denetleyiciyi Yapılandırma,Параметри контролера, +Controller Options,JOYMNU_OPTIONS,,,,Ovladač,Indstillinger for styreenhed,Controlleroptionen,,Ludregilo-agordoj,Opciones del mando,,Peliohjainasetukset,Options Mannette,Kontroller beállítások,Opzioni del controller,コントローラー設定,컨트롤러 설정,Controller opties,Alternativer for styreenhet,Opcje Kontrolera,Opções de controle,Opções do Comando,Setări controller,Настройки контроллера,Подешавања контролера,Alternativ för kontroller,Kontrolör Seçenekleri,Налаштування контролера, +Block controller input in menu,JOYMNU_NOMENU,,,,Zakázat ovladač v nabídkách,Bloker controller input i menuen,Blockiere Controllereingabe im Menü,,Blokigi ludregilan enigon en menuo,Bloq. entrada de mando en menú,,Estä ohjainsyötteet valikoissa,Bloquer manette dans les menus,Kontroller ne működjön a menüben,Blocca l'input del controller nei menu,メニューではコントローラーを無視,메뉴에서 컨트롤러 끄기,Blokkeer de controller in het menu,Blokker kontrollerinngang i menyen,Blokuj wejście kontrolera w menu,Bloquear controle no menu,Bloquear comando no menu,Blocare comenzi controller în meniu,Отключить контроллер в меню,Блокирај улаз контролера у менију,Blockera inmatning av kontroller i menyn,Menüde kontrolör girişini engelle,Відключити контролер в меню, +Enable controller support,JOYMNU_ENABLE,,,,Povolit podporu pro ovladače,Aktivering af controllerunderstøttelse,Erlaube Controllerunterstützung,,Ŝalti ludregilan subtenon,Activar soporte de mandos,,Ota käyttöön peliohjaintuki,Activer support contrôleur,Kontroller támogatás engedélyezése,Abilita il supporto del controller,コントローラーサポート許可,컨트롤러 지원 허용,Controllerondersteuning inschakelen,Aktiver støtte for styreenhet,Włącz wsparcie kontrolera,Ativar detecção de controles,,Activare support controller,Включить поддержку контроллера,Омогући подршку за контролере,Aktivera stöd för kontroller,Denetleyici desteğini etkinleştir,Увімкнути підтримку контролера, +Enable DirectInput controllers,JOYMNU_DINPUT,,,,Povolit ovladače DirectInput,Aktivering af DirectInput-controllere,Erlaube DirectInput-Controller,,Ŝalti DirectInput ludregilojn,Usa controles DirectInput,,Ota käyttöön DirectInput-ohjaimet,Activer contrôleurs DirectInput,DirectInput kontrollerek engedélyezése,Abilita i controlli DirectInput,ダイレクトインプットコントローラー許可,다이렉트 인풋 컨트롤러 허용,DirectInput-controllers inschakelen,Aktiver DirectInput-kontrollere,Włącz kontrolery DirectInput,Ativar controles DirectInput,,Activare controlere DirectInput,Включить контроллеры через DirectInput,Омогући директинпут контролере,Aktivera DirectInput-kontroller,DirectInput denetleyicilerini etkinleştirin,Увімкнути контролери DirectInput, +Enable XInput controllers,JOYMNU_XINPUT,,,,Povolit ovladače XInput,Aktiver XInput-controllere,Erlaube XInput-Controller,,Ŝalti XInput ludregilojn,Usa controles XInput,,Ota käyttöön XInput-ohjaimet,Activer contrôleurs XInput,XInput kontrollerek engedélyezése,Abilita i controlli XInput,Xinput コントローラー許可,X인풋 컨트롤러 허용,XInput-controllers inschakelen,Aktiver XInput-kontrollere,Włącz kontrolery XInput,Ativar controles XInput,,Activare controlere XInput,Включить контроллеры через XInput,Омогући Иксинпут контролере,Aktivera XInput-kontroller,XInput denetleyicilerini etkinleştirin,Увімкнути контролери XInput, +Enable raw PlayStation 2 adapters,JOYMNU_PS2,,,,Povolit ovladače PlayStation 2,Aktiver rå PlayStation 2-adaptere,Erlaube Playstation 2-Controller,,Ŝalti krudajn adaptilojn de PlayStation 2 ,Usa adaptadores de PlayStation 2,,Ota käyttöön raa'at PlayStation 2 -adapterit,Activer adaptateurs PS2 bruts,PlayStation 2 adapterek engedélyezése,Abilita gli adattatori raw PlayStation 2,PlayStation2 アダプター許可,PS2 어뎁터 허용,Raw PlayStation 2-adapters inschakelen,Aktiver rå PlayStation 2-adaptere,Włącz adaptery PlayStation 2,Ativar adaptadores de PlayStation 2,,Activare adaptoare PS2,Использовать адаптеры PlayStation 2 напрямую,Омогући сирове Плејстејшн 2 адаптере,Aktivera råa PlayStation 2-adaptrar,Ham PlayStation 2 adaptörlerini etkinleştirin,Використовувати адаптери PlayStation 2 напряму, +No controllers detected,JOYMNU_NOCON,,,,Nenalezeny žádné ovladače.,Ingen controllere er fundet,Keine Controller gefunden,,Neniu ludregilo detektita,No hay mandos detectados,,Ei havaittuja ohjaimia,Aucun Contrôleur détecté.,Nem érzékelhető kontroller,Nessun controller trovato,コントローラーが見つかりません,인식된 컨트롤러 없음,Geen controllers gedetecteerd,Ingen kontrollere oppdaget,Nie wykryto kontrolerów,Nenhum controle detectado.,Nenhum comando foi detectado,Niciun controller detectat,Контроллеры не обнаружены,Нема детектованих контролера,Inga kontroller upptäcks,Denetleyici algılanmadı,Контролерів не виявлено, +Configure controllers:,JOYMNU_CONFIG,,,,Nastavit ovladače:,Konfigurer controllere:,Controller konfigurieren,,Agordi ludregilojn:,Configurar controles:,,Mukauta ohjaimia:,Configurer contrôleurs:,Kontrollerek konfigurációja:,Configura i controller:,コントローラー構成:,컨트롤러 설정:,Configureer controllers:,Konfigurer kontrollere:,Konfiguruj kontrolery:,Configurar controles:,Configurar comandos,Configurare controlere:,Настроить контроллер:,Подешавања контролере:,Konfigurera kontroller:,Denetleyicileri yapılandırın:,Налаштувати контролери, +Controller support must be,JOYMNU_DISABLED1,,,,Pro nalezení ovladačů musí,Der skal være støtte til controlleren,Controllerunterstütung muss aktiviert sein,,Ludregilo-subteno devas esti,El soporte de mandos debe estar,,Ohjaintuen täytyy olla otettu,Le Support de contrôleur doit être activé,A kontroller támogatásnak,Il supporto ai controller deve essere,コントローラーサポートは,감지하려면 컨트롤러 지원을,Controller ondersteuning moet ingeschakeld zijn,Støtte for kontrollere må være,Wsparcie kontrolera musi być,A detecção de controles deve,Suporte a comandos devem ser,Supportul pentru controller trebuie,Включите поддержку контроллера,Омогућите подржавање контролера,Stöd för kontroller måste vara aktiverat,Denetleyici desteği şu şekilde olmalıdır,Включіть підтримку контролерів, +enabled to detect any,JOYMNU_DISABLED2,Supposed to be empty in Russian and Serbian.,,,být zapnuta jejich podpora.,aktiveret for at registrere enhver,um welche zu finden,,ŝaltita por detekti iun ajn,activado para detectar alguno,,käyttöön ohjainten havaitsemiseksi,avant de pouvoir en détecter un.,"engedélyezve kell lenni, hogy érzékeljen bármit is.",abilitato a trovare ogni,検出しました,활성화 해야합니다.,om eventuele regelaars te detecteren.,aktivert for å oppdage en hvilken som helst,Włączony by wykryć jakikolwiek,ser ativada para exibi-los.,,activat pentru a putea fi detectate, \n, \n,för att det ska gå att upptäcka några,tespit etmek için etkinleştirildi, \n, +Invalid controller specified for menu,JOYMNU_INVALID,,,,Vybrán nesprávný ovladač pro nabídky,Ugyldig controller angivet til menuen,Ungültiger Controller für Menü ausgewählt,,Nevalida ludregilo specifigita por menuo,Mando inválido especificado para el menú,,Epäkelpo ohjain määritetty valikolle,Contrôleur invalide spécifé dans le menu.,Hibás kontroller van a menühöz osztva,Controller invalido specificato per il menu,メニューではコントローラーを使用しない,메뉴에 특정된 컨트롤러가 아닙니다.,Ongeldige regelaar gespecificeerd voor het menu,Ugyldig kontroller spesifisert for menyen,Niewłaściwy kontroler określony dla menu,Controle inválido especificado para o menu.,Comando inválido,Controller pentru meniu invalid,Недопустимый контроллер выбран для меню,Невалидан контролер специфиран за мени,Ogiltig kontroller har angetts för menyn,Menü için geçersiz denetleyici belirtildi,Для меню вибрано невідповідний контролер, +Overall sensitivity,JOYMNU_OVRSENS,,,,Celková citlivost,Samlet følsomhed,Allgemeine Empfindlichkeit,,Tuta sentemeco,Sensibilidad general,,Yleisherkkyys,Sensibilité générale,Teljes érzékenység,Sensibilità generale,全体的な感度,전체 민감도,Algemene gevoeligheid,Samlet følsomhet,Ogólna Czułość,Sensibilidade geral,,Sensibilitate în ansamblu,Общая чувствительность,Уупна сензитивност,Övergripande känslighet,Genel hassasiyet,Загальна чутливість, +Axis Configuration,JOYMNU_AXIS,,,,Nastavení os,Konfiguration af akserne,Achsenkonfiguration,,Akso-agordoj,Configuración del eje,,Akseleiden säätäminen,Configuration des axes,Tengely konfigurálása,Configurazione assi,軸構成,축 구성,Asconfiguratie,Konfigurasjon av akse,Konfiguruj Oś,Configuração de eixo,,Configurare axă,Конфигурация осей,Конфигурација осе,Konfiguration av axlar,Eksen Konfigürasyonu,Конфігурація осей, +Invert,JOYMNU_INVERT,,,,Obrátit,Invert,Invertieren,,Inversigi,Invertir,,Käännä,Inverser,Megfordítás,Inverti,反転,순서 바꿈,Omkeren,Invertering,Odwróć,Inverter,,Inversare,Инвертировать,Инвертовано,Invertera,Ters çevir,Інвертувати, +Dead zone,JOYMNU_DEADZONE,,,,Mrtvá zóna,Dødzone,Totzone,,Mortozono,Zona muerta,,Kuollut alue,Zone neutre,Holttér,Zona cieca,デッドゾーン,불감대,Dode zone,Død sone,Martwa strefa,Zona morta,,Zonă moartă,Мёртвая зона,Мртва зона,Dödzon,Ölü bölge,Мертва зона, +No configurable axes,JOYMNU_NOAXES,,,,Žádné nastavitelné osy,Ingen konfigurerbare akser,Keine konfigurierbaren Achsen,,Neniuj agordeblaj aksoj,No hay ejes configurables,,Ei säädettäviä akseleita,Aucun axe à configurer,Nincs beállítható tengely,Nessun asse configurabile,軸構成を無効,설정할 방향키가 없습니다.,Geen configureerbare assen,Ingen konfigurerbare akser,Brak osi do skonfigurowania,Nenhum eixo configurável,,Nicio axă configurabilă,Нет настраиваемых осей,Нема конфигурационих оса,Inga konfigurerbara axlar,Yapılandırılabilir eksen yok,Немає настроюваних осей, +None,OPTVAL_NONE,,,,Žádný,Ingen,Kein,,Neniu,Ninguno,,Ei mitään,Aucun,Nincs,Nessuno,無し,없음,Geen,Ingen,Żaden,Nenhum,,Niciuna,Откл.,Ништа,Ingen,Hiçbiri,Вимк., +Turning,OPTVAL_TURNING,,,,Otáčení,Drejning,Umdrehen,,Turnanta,Girar,,Kääntyminen,Tourner,Fordulás,Rotazione,旋回,회전,Draaien,Dreie,Obracanie się,Girar,,Rotire,Поворот,Скретање,Vridning,Dönüş,Поворот, +Looking Up/Down,OPTVAL_LOOKINGUPDOWN,,,,Dívání se nahoru/dolů,Kigger op/ned,Hoch/runterblicken,,Rigardanta (mal)supren,Mirar hacia arriba/abajo,,Ylös/Alas katsominen,Vue haut/bas,Fel-/lenézés,Sguardo Sopra/Sotto,視点上下,위/아래로 보기,Omhoog/omlaag zoeken,Ser opp/ned,Patrzenie w górę/w dół,Olhar para cima/baixo,,Privire Sus/Jos,Взгляд вверх/вниз,Гледање горе/доле,Titta uppåt/nedåt,Yukarı/Aşağı Bakmak,Дивитись вгору, +Moving Forward,OPTVAL_MOVINGFORWARD,,,,Pohyb vpřed,Bevæger sig fremad,Vorwärtsbewegung,,Movanta antaŭen,Avanzar,,Eteenpäin liikkuminen,Avancer,Előre mozgás,Movimento in avanti,前進,앞으로 전진,Voorwaarts bewegen,Beveger seg fremover,Poruszanie się do przodu,Mover-se para a frente,,Deplasare în Față,Движение вперёд,Кретање напред,Rör sig framåt,İleriye Doğru,Рухатись вперед, +Strafing,OPTVAL_STRAFING,,,,Pohyb do stran,Strafing,Seitwärtsbewegung,,Flankmovanta,Desplazarse,,Sivuttaisastunta,Pas de côté,Oldalazás,Movimento laterale,横移動,양옆으로 이동,Strafelen,Straffe,Uniki,Deslocamento lateral,,Deplasare în Diagonală,Движение боком,Кретање у страну,Strafing,Strafing,Рухатись боком, +Moving Up/Down,OPTVAL_MOVINGUPDOWN,,,,Pohyb nahoru/dolů,Bevægelse op/ned,Auf/abwärtsbewegung,,Movanta (mal)supren,Moverse hacia arriba/abajo,,Ylös/Alas liikkuminen,Mouvement haut/bas,Felfele/Lefele mozgás,Movimento Sopra/Sotto,前進後退,위/아래로 이동,Naar boven/beneden bewegen,Beveger seg opp/ned,Poruszanie się w górę/w dół,Mover-se para cima/baixo,,Mișcare Sus/Jos,Движение вверх/вниз,Кретање горе/доле,Rör sig uppåt/nedåt,Yukarı/Aşağı Hareket Etme,Рухатись вгору/вниз, +Inverted,OPTVAL_INVERTED,,,,Inverzní,Omvendt,Invertiert,,Inversigita,Invertido,,Käännetty,Inversé,Felcserélve,Invertito,反転する,반전,Omgekeerd,Invertert,Odwrócony,Invertido,,Inversat,Инвертировано,Обрнуто,Inverterad,Ters çevrilmiş,Інвертовано, +Not Inverted,OPTVAL_NOTINVERTED,,,,Neinverzní,Ikke omvendt,nicht invertiert,,Ne inversigita,No invertido,,Ei käännetty,Non Inversé,Nincs felcserélve,Non invertito,反転しない,반전되지 않음,Niet omgekeerd,Ikke invertert,Nieodwrócony,Não invertido,,Neinversat,Прямо,Не обрнуто,Inte inverterad,Ters Çevrilmemiş,Не інвертовано, +,,Player Menu,,,,,,,,,,,,,,,,,,,,,,,,,,, +Blue,TXT_COLOR_BLUE,,,,Modrá,Blå,Blau,Μπλέ,Blua,Azul,,Sininen,Bleu,Kék,Blu,青,청색,Blauw,Blå,Niebieski,Azul,,Albastru,Синий,Плава,Blå,Mavi,Синій, +Red,TXT_COLOR_RED,,,,Červená,Rød,Rot,Κόκκινο,Ruĝa,Rojo,,Punainen,Rouge,Vörös,Rosso,赤,적색,Rood,Rød,Czerwony,Vermelho,,Roșu,Красный,Црвена,Röd,Kırmızı,Червоний, +Green,TXT_COLOR_GREEN,,,,Zelená,Grøn,Grün,Πράσινο,Verda,Verde,,Vihreä,Vert,Zöld,Verde,緑,녹색,Groen,Grønn,Zielony,Verde,,Verde,Зелёный,Зелена,Grön,Yeşil,Зелений, +Gray,TXT_COLOR_GRAY,,,Grey,Šedá,Grå,Grau,Γκρί,Griza,Gris,,Harmaa,Gris,Szürke,Grigio,灰,회색,Grijs,Grå,Szary,Cinza,,Gri,Серый,Сива,Grå,Gri,Сірий, +Dark gray,TXT_COLOR_DARKGRAY,,,"Dark grey +",Tmavě šedá,Mørkegrå,Dunkelgrau,Σκοτεινό γρκί,Malhelgriza,Gris oscuro,,Tummanharmaa,Gris sombre,Sötétszürke,Grigio scuro,鉛,치색,Donkergrijs,Mørkegrå,Ciemnoszary,Cinza escuro,,Gri închis,Тёмно-серый,Тамно сива,Mörkgrått,Koyu gri,Темно-сірий, +Dark Green,TXT_COLOR_DARKGREEN,,,,Tmavě zelená,Mørkegrøn,Dunkelgrün,Σκοτεινό πράσινο,Malhelverda,Verde oscuro,,Tummanvihreä,Vert sombre,Sötétzöld,Verde scuro,深,흑녹색,Donkergroen,Mørkegrønn,Ciemnozielony,Verde escuro,,Verde închis,Тёмно-зелёный,Тамна зелена,Mörkgrön,Koyu Yeşil,Темно-зелений, +Brown,TXT_COLOR_BROWN,,,,Hnědá,Brun,Braun,Σκούρο,Bruna,Marrón,Marrón/Café,Ruskea,Brun,Barna,Marrone,茶,갈색,Bruin,Brun,Brązowy,Marrom,,Maro,Коричневый,Браон,Brun,Kahverengi,Коричневий, +Dark Blue,TXT_COLOR_DARKBLUE,,,,Tmavě modrá,Mørk blå,Dunkelblau,Σκοτεινό μπλέ,Malhelblua,Azul oscuro,,Tummansininen,Bleu sombre,Sötétkék,Blu scuro,紺,,Donkerblauw,Mørkeblå,Ciemnoniebieski,Azul escuro,,Albastru închis,Тёмно-синий,Тамна Плава,Mörkblå,Koyu Mavi,Темно-синій, +Light Red,TXT_COLOR_LIGHTRED,,,,Světle červená,Lysrød,Hellrot,Ανοιχτό κόκκινο,Helruĝa,Rojo claro,,Vaaleanpunainen,Rouge clair,Világospiros,Rosso chiaro,丹,옅은 적색,Licht Rood,Lys rød,Jasnoczerwony,Vermelho claro,,Roșu deschis,Светло-красный,Светло црвена,Ljusröd,Açık Kırmızı,Світло-червоний, +Yellow,TXT_COLOR_YELLOW,,,,Žlutá,Gul,Gelb,Κίτρινο,Flava,Amarillo,,Keltainen,Jaune,Sárga,Giallo,黄,노란색,Geel,Gul,Żółty,Amarelo,,Galben,Жёлтый,Жута,Gul,Sarı,Жовтий, +Purple,TXT_COLOR_PURPLE,,,,Fialová,Lilla,Violett,Μόβ,Purpura,Morado,,Purppura,Violet,Lila,Viola,紫,보라색,Paars,Lilla,Fioletowy,Roxo,,Mov,Фиолетовый,Љубичаста,Lila,Mor,Фіолетовий, +Olive,TXT_COLOR_DULLGREEN,,,,Bledě zelená,Oliven,Blassgrün,,Olivkolora,Oliva,,Haaleanvihreä,Vert pâle,Olíva,Verde pallido,苔,암녹색,Saaie groen,Oliven,Matowa Zieleń,Verde oliva,,Măsliniu,Мутно-зелёный,Тупа зелена,Oliv,Zeytin,Темний жовто-зелений, +Beige,TXT_COLOR_BEIGE,,,,Béžová,Beige,,Μπέζ,Flavgriza,Beis,Beige,Beesi,,Bézs,,淡,담갈색,Beige,Beige,Beżowy,Bege,,Bej,Бежевый,Беж,Beige,Bej,Бежевий, +Light Green,TXT_COLOR_LIGHTGREEN,,,,Světle zelená,Lysegrøn,Hellgrün,Ανοιχτό Πράσινο,Helverda,Verde claro,,Vaaleanvihreä,Vert clair,Világoszöld,Verde chiaro,葵,옅은 녹색,Licht groen,Lysegrønn,Jasonzielony,Verde claro,,Verde Deschis,Светло-зелёный,Светло зелена,Ljusgrön,Açık Yeşil,Світло-зелений, +Light Blue,TXT_COLOR_LIGHTBLUE,,,,Světle modrá,Lys blå,Hellblau,Γαλάζιο,Helblua,Azul claro,,Vaaleansininen,Bleu clair,Világoskék,Blu chiaro,空,옅은 청색,Licht blauw,Lyseblå,Jasnoniebieski,Azul claro,,Albastru Deschis,Светло-синий,Светло плава,Ljusblå,Açık Mavi,Світло-синій, +Light Gray,TXT_COLOR_LIGHTGRAY,,,Light Grey,Světle šedá,Lysegrå,Hellgrau,Ανοιχτό Γκρι,Helgriza,Gris claro,,Vaaleanharmaa,Gris clair,Világosszürke,Grigio chiaro,鉛,옅은 회색,Lichtgrijs,Lysegrå,Jasnoszary,Cinza claro,,Gri Deschis,Светло-серый,Светло сива,Ljusgrå,Açık Gri,Світло-сірий, +Light Brown,TXT_COLOR_LIGHTBROWN,,,,Světle hnědá,Lys brun,Hellbraun,Ανοιχτό Καφέ,Helbruna,Marrón claro,Marrón/Café claro,Vaaleanruskea,Brun clair,Világosbarna,Marrone chiaro,褐,옅은 고동색,Lichtbruin,Lysebrun,Jasnobrązowy,Marrom claro,,Maro Deschis,Светло-коричневый,Светло браон,Ljusbrun,Açık Kahverengi,Світло-коричневий, +Gold,TXT_COLOR_GOLD,,,,Zlatá,Guld,,Χρυσό,Orkolora,Dorado,,Kulta,Or,Arany,Oro,金,금색,Goud,Gull,Złoty,Dourado,,Auriu,Золотой,Златна,Guld,Altın,Золотий, +Bright Green,TXT_COLOR_BRIGHTGREEN,,,,Jasně zelená,Lysegrøn,Hellgrün,Φωτινό Πράσινο,Brilverda,Verde claro,,Vaaleanvihreä,Vert clair,Fényeszöld,Verde chiaro,鮮,밝은 녹색,Helder groen,Lysegrønn,Jasnozielony,Verde claro,,Verde Deschis,Ярко-зелёный,Светла зелена,Ljusgrön,Parlak Yeşil,Яскраво-зелений, +Rust,TXT_COLOR_RUST,,,,Rezavá,,Rostbraun,Σκουριά,Rustokolora,Óxido,,Ruoste,Rouille,Rozsda,Arrugginito,錆,주황 적갈색,Roest,,Rdzawy,Ferrugem,,Ruginiu,Ржавый,Рђа,Rost,Pas,Іржавий, +Name,PLYRMNU_NAME,,,,Jméno,Navn,,Όνομα,Nomo,Nombre,,Nimi,Nom,Név,Nome,名前,이름,Naam,Navn,Imię,Nome,,Nume,Имя,Надимак,Namn,İsim,Ім'я, +Team,PLYRMNU_TEAM,,,,Tým,,,Ομάδα,Teamo,Equipo,,Joukkue,Equipe,Csapat,Squadra,チーム,팀,,Lag,Drużyna,Equipe,Equipa,Echipă,Команда,Тим,Lag,Takım,Команда, +Color,PLYRMNU_PLAYERCOLOR,,,Colour,Barva,Farve,Farbe,Χρώμα,Koloro,,,Väri,Couleur,Szín,Colore,色,색상,Kleur,Farge,Kolor,Cor,,Culoare,Цвет,Боја,Färg,Renk,Колір, +Gender,PLYRMNU_PLAYERGENDER,,,,Pohlaví,Køn,Geschlecht,Φύλο,Sekso,Sexo,,Sukupuoli,Genre,Nem,Sesso,性別,성별,Geslacht,Kjønn,Płeć,Gênero,,Sex,Пол,Пол,Kön,Cinsiyet,Стать, +Male,OPTVAL_MALE,,,,Muž,Mand,Männlich,Αρσενικό,Vira,Masculino,,Miespuolinen,Masculin,Férfi,Maschio,男,남성,Man,Mannlig,Mężczyzna,Masculino,,Masculin,Мужской,Мушко,Man,Erkek,Чоловіча, +Female,OPTVAL_FEMALE,,,,Žena,Kvinde,Weiblich,Θηλυκό,Ina,Femenino,,Naispuolinen,Féminin,Nő,Femmina,女,여성,Vrouw,Kvinne,Kobieta,Feminino,,Feminin,Женский,Женско,Kvinna,Kadın,Жіноча, +Neutral,OPTVAL_NEUTRAL,,,,Neutrální,,,Ουδέτερο,Neŭtra (Ri),Neutro,,Sukupuoleton,Neutre,Semleges,Neutrale,中間,중성,Neutraal,Nøytral,Neutralne,Neutro,,Neutru,Нейтральный,Неутрално,Neutral,Nötr,Нейтральна, +Object,OPTVAL_OTHER,,,,Objekt,Objekt,Objekt,Αντικείμενο,Objekto (Ĝi),Objeto,,Olio,Objet,Tárgy,Oggetto,物体,기타,Doel,Gjenstand,Obiekt,Objeto,,Obiect,Предмет,Предмет,Objekt,Nesne,Предмет, +Gameplay Options,GMPLYMNU_TITLE,,,,Nastavení herních mechanik,Gameplay-muligheder,Gameplay-Optionen,,Ludado-agordoj,Opciones de jugabilidad,,Pelattavuusasetukset,Options Gameplay,Játékmenet beállításai,Opzioni gameplay,ゲームプレイ オプション,게임플레이 설정,Gameplay-opties,Spillalternativer,Opcje Rozgrywki,Opções de jogabilidade,,Setări de Joc,Настройки игры,Подешавања гејмплеја,Spelalternativ,Oynanış Seçenekleri,Налаштування гри, +Always,OPTVAL_ALWAYS,,,,Vždy,Altid,Immer,Πάντα,Ĉiam,Siempre,,Aina,Toujours,Mindig,Sempre,常に,언제나,Altijd,Alltid,Zawsze,Sempre,,Mereu,Всегда,Увек,Alltid,Her zaman,Завжди, +Never,OPTVAL_NEVER,,,,Nikdy,Aldrig,Nie,Ποτέ,Neniam,Nunca,,Ei koskaan,Jamais,Soha,Mai,しない,없음,Nooit,Aldri,Nigdy,Nunca,,Niciodată,Никогда,Никад,Aldrig,Asla,Ніколи, +Autoaim,PLYRMNU_AUTOAIM,,,,Automatické míření,,Automatisch zielen,,Celasisto,Autoapuntar,,Automaattitähtäys,Auto-visée,Automatikus célzás,Mira automatica,自動照準,자동 조준,,,Auto-celowanie,Mira automática,,Autoțintire,Автоприцеливание,Аутоматско циљање,automatiskt sikte,,Автонаведення, +Always Run,PLYRMNU_ALWAYSRUN,,,,Vždy běžet,Altid løbe,Immer Rennen,Πάντα τρέχα,Ĉiam kuri,Siempre correr,,Jatkuva juoksu,Toujours courir,Mindig fusson,Corri sempre,常に駆け足,달리기 토글,Altijd lopen,Kjør alltid,Zawsze Biegaj,Sempre correr,Correr Sempre,Fugă în permanență,Постоянный бег,Увек трчи,Alltid springa,Daima Koş,Постійний біг, +,,Display,,,,,,,,,,,,,,,,,,,,,,,,,,, +Screen size,DSPLYMNU_SCREENSIZE,,,,Velikost obrazovky,Skærmstørrelse,Bildschirmgröße,Μέγεθος οθόνης,Ekrangrando,Tamaño de pantalla,,Näytön koko,Taille de l'écran,Képernyő mérete,Dimensione della schermata,画面サイズ,화면 크기,Schermgrootte,Skjermstørrelse,Rozmiar Ekranu,Tamanho da tela,Tamanho do ecrã,Mărime ecran,Размер экрана,Величина екрана,Skärmstorlek,Ekran boyutu,Розмір екрану, +Vertical Sync,DSPLYMNU_VSYNC,,,,Vertikální synchronizace,Lodret synkronisering,Vertikale Synchronisation,,Vertikala-sinkronigo,Sincronización vertical,,Pystytahdistys,Synchronisation Verticale,Függőleges szinkronizálás,Sincronia verticale,垂直同期,수직 동기화,Verticale Sync,Vertikal synkronisering,Synchronizacja Pionowa,Sincronização vertical,,Sincronizare Verticală,Вертикальная синхронизация,Вертикална синхорнизација,Vertikal synkronisering,Dikey Senkronizasyon,Вертикальна синхронізація, +Models,DSPLYMNU_MODELS,,,,Modely,Modeller,Modelle,Μοντέλα,Modeloj,Modelos,,Mallit,Modèles,3D modellek,Modelli,モデル,모델,Modellen,Modeller,Modele,Modelos,,Modele,Модели,Модели,Modeller,Modeller,3D Моделі, +Scale crosshair,DSPLYMNU_CROSSHAIRSCALE,,,,Velikost zaměřovače,Skalerer trådkorset,Fadenkreuz skalieren,,Skali reteton,Escalar retícula,,Skaalaa tähtäintä,Mise à l'échelle du viseur,Célkereszt méret,Scala del mirino,照準スケール,조준점 크기,Dradenkruis schalen,Skala trådkors,Skala celownika,Escala da mira,,Scară țintă,Размер прицела,Размера нишана,Skala hårkorset,Ölçekli artı işareti,Розмір прицілу, +Brightness,DSPLYMNU_BRIGHTNESS,,,,Jas,Lysstyrke,Helligkeit,Φωτηνότητα,Brileco,Brillo,,Kirkkaus,Luminosité,Fényerő,Luminosità,明るさ,밝기,Helderheid,Lysstyrke,Jasność,Brilho,,Luminozitate,Яркость,Осветљење,Ljusstyrka,Parlaklık,Яскравість, +Gamma correction,DSPLYMNU_GAMMA,,,,Korekce gama,Gammakorrektion,Gammakorrektur,,Gamaa korektado,Corrección gamma,,Gammakorjaus,Correction Gamma,Gamma korrekció,Correzione gamma,ガンマ値,감마 조정,Gamma correctie,Gammakorreksjon,Korekta gammy,Correção de gama,,Gamma,Гамма-коррекция,Корекција светлости,Gammakorrigering,Gama düzeltme,Гамма-корекція, +Contrast,DSPLYMNU_CONTRAST,,,,Kontrast,Kontrast,Kontrast,,Kontrasto,Contraste,,Sävykkyys,Contraste,Kontraszt,Contrasto,コントラスト,대비,,Kontrast,Kontrast,Contraste,,,Контраст,Контраст,Kontrast,Kontrast,Контраст, +Saturation,DSPLYMNU_SATURATION,,,,Sytost,Mætning,Sättigung,,Satureco,Saturación,,Värikylläisyys,,Telítettség,Saturazione,サチュレーション,채도,Verzadiging,Metning,Nasycenie,Saturação,,Saturație,Насыщенность,Сатурација,Mättnad,Doygunluk,Насиченість, +Status Bar Scale,DSPLYMNU_SBSCALE,,,,Velikost stavového panelu,Skala for statuslinje,Statusleistengröße,,Skalo de stata breto,Escala de barra de estado,,Tilapalkin skaalaus,Mise à l'échelle HUD,Állapotjelző mérete,Dimensioni Status Bar,ステータススケール,,Statusbalkschaal,Statuslinjeskala,Skala paska statusu,Escala da barra de estado,,Scară bară de stare,Размер строки состояния,,Skala för statusfältet,Durum Çubuğu Ölçeği,Розмір строки стану, +Messages,DSPLYMNU_MESSAGES,,,,Oznámení,Meddelelser,Nachrichten,Μηνύματα,Mesaĝoj,Mensajes,,Viestit,,Üzenetek,Messaggi,メッセージ類,메시지,Berichten,Meldinger,Wiadomości,Mensagens,,Mesaje,Сообщения,Поруке,Meddelanden,Mesajlar,Повідомлення, +Center messages,MSGMNU_CENTERMESSAGES,,,Centre messages,Oznámení na střed,Centrerede meddelelser,Nachrichten zentrieren,,Centrigi mesaĝojn,Centrar mensajes,,Keskitä viestit,Messages centrés,Üzenetek középre helyezése,Messaggi centrati,メッセージを中央に,메시지 중간에 위치,Berichten centreren,Sentrumsmeldinger,Wyśrodkuj wiadomości,Centralizar mensagens,Centrar mensagens,Mesaje centrate,Центрирование сообщений,Централне поруке,Centrerade meddelanden,Merkez mesajları,Центрування повідомлень, +Pulsating message Display,MSGMNU_PULSEMESSAGES,,,,Pulzující oznámení,Pulserende meddelelser Visning,Pulsierende Nachrichtenanzeige,,Pulsanta mesaĝ-montrejo,Mostrar mensajes pulsantes,,Sykkivät viestit,Messages pulsés,Pulzáló üzenet,Mostra messaggi pulsanti,取得時等の文を明滅,,Pulserende berichtendisplay,Pulserende melding Display,Pulsujące wyświetlanie wiadomości,Exibir mensagem pulsante,,Afișare Mesaje Pulsante,Пульсация сообщений,,Pulserande meddelande Visning,Titreşimli mesaj Ekranı,Пульсація повідомлень, +Message Scale,MSGMNU_MESSAGESCALE,,,,Velikost oznámení,Skala for meddelelser,Nachrichtengröße,Μέγεθος μηνύματον,Skalo de mesaĝoj,Escala de mensajes,,Viestien skaalaus,Mise à l'échelle Messages,Üzenet mérete,Dimensioni Messaggi,メッセージスケール,,Berichtschaal,Meldingsskala,Skalowanie Wiadomości,Escala de mensagem,,Scară Mesaje,Размер сообщений,,Meddelandeskala,Mesaj Ölçeği,Розмір повідомлень, +,,Automap,,,,,,,,,,,,,,,,,,,,,,,,,,, +Select Color,MNU_COLORPICKER,,,Select Colour,Výběr barvy,Vælg farve,Farbe auswählen,Επιλογή Χρώματος,Elektu koloron:,Elige un color,,Valitse väri,Choisir Couleur,Szín választása,Scegli il colore,色選択,색상을 고르시오,Selecteer Kleur,Velg farge,Wybierz Kolor,Selecione uma cor,,Alege o Culoare,Выбор цвета,Изабери боју,Välj färg,Renk Seçiniz,Вибір кольору, +Rotate automap,AUTOMAPMNU_ROTATE,,,,Otáčet automapu,Rotere automap,Rotiere Automap,,Turni aŭtomatan mapon,Rotar automapa,,Kiertyvä automaattikartta,Rotation de la Carte,Térkép forgatása,Ruota l'automappa,オートマップの回転表示,오토맵 회전,Automatisch roteren,Roter automatisk kart,Obracaj mapę,Girar automapa,,Rotire hartă computerizată,Вращающаяся автокарта,Ротирај аутомапу,Rotera automap,Otomatik haritayı döndür,Обертання автокарти, +Follow player,AUTOMAPMNU_FOLLOW,,,,Následovat hráče,Følg spilleren,Folge dem Spieler,Ακουλούθα το παίχτη,Sekvi ludanton,Seguir jugador,,Seuraa pelaajaa,Suivre le joueur,Kövesse a játékost,Segui il giocatore,プレイヤー追従,플레이어 추적,Volg de speler,Følg spiller,Podążaj za graczem,Seguir jogador,,Urmărire jucător,Привязка к игроку,Прати играча,Följ spelaren,Oyuncuyu takip et,Прив'язка до гравця, +Line alpha,AUTOMAPMNU_LINEALPHA,,,,Průhlednost čar,Linje alfa,Alpha für Linien,,Travidebleca de linio,Transparencia de línea,,Viivan alpha,Translucidité des lignes,Vonal áttetszóség,Traslucenza delle linee,線の半透明度,선 반투명도,Doorschijnendheid van lijnen,Linje alfa,Przezroczystość Linii,Transparência da linha,,Transparență linii,Прозрачность линий,Транслуценција линија,Linje alfa,Çizgi alfa,Прозорість ліній, +Line thickness,AUTOMAPMNU_LINETHICKNESS,,,,Tloušťka čar,Linjetykkelse,Dicke der Linien,,Dikeca de linio,Grosor de línea,,Viivan paksuus,Épaisseur des lignes,Vonal vastagság,Spessore delle linee,線の太さ,선 두께,Dikte van lijnen,Linjetykkelse,Grubość Linii,Espessura da linha,,Grosime linii,Толщина линий,Дебљина линија,Linjens tjocklek,Çizgi kalınlığı,Товщина ліній, +Customize Map Colors,MAPCOLORMNU_TITLE,,,Customize Map Colours,Nastavení barev mapy,Tilpas kortfarver,Automapfarben einstellen,,Adapti mapkolorojn,Personalizar colores (mapa),,Värien mukautus,Couleurs Carte Personnalisées,Térkép színeinek testreszabása,Personalizza i colori della mappa,カスタム色を決める,미니맵 색상 설정,Kaartkleuren aanpassen,Tilpass kartfarger,Ustaw kolory mapy,Personalizar cores do mapa,,Personalizare culori hartă,Настройки цветов автокарты,Промени боју мапе,Anpassa kartans färger,Harita Renklerini Özelleştirin,Налаштування кольорів автокарти, +Restore default custom colors,MAPCOLORMNU_DEFAULTMAPCOLORS,,,Restore default custom colours,Obnovit původní vlastní barvy,Gendan standard brugerdefinerede farver,Standardfarben wiederherstellen,,Restaŭri defaŭltajn laŭmendajn kolorojn,Restaurar colores personalizados,,Palauta oletusvärit,Couleurs par défaut,Eredeti színek visszaállítása,Reimposta i colori personalizzati al default,カスタム色を初期化,기본 색상으로 복구,Standaard aangepaste kleuren herstellen,Gjenopprett egendefinerte standardfarger,Przywróć domyślne kolory,Restaurar cores personalizadas padrão,,Revenire la culorile implicite,Вернуть стандартные цвета,Врати уобичајене разне боје,Återställ anpassade standardfärger,Varsayılan özel renkleri geri yükleme,Повернути стандартні кольори, +,,Sound,,,,,,,,,,,,,,,,,,,,,,,,,,, +Sound enabled,SNDMNU_SNDENABLED,,,,Zvuk zapnut,Lyd aktiveret,Sound aktiv,Ήχος ενεργοποιημένος,Sono ŝaltita,Sonido activado,,Ääni päällä,Son activé,Hang engedélyezve,Abilita gli effetti sonori,サウンド有効,,Geluid actief,Lyd aktivert,Dźwięk włączony,Som ativado,,Sunet activat,Звук включён,,Ljud aktiverat,Ses etkin,Звук увімкнено, +Music enabled,SNDMNU_MUSENABLED,,,,Hudba zapnuta,Musik aktiveret,Musik aktiv,Μουσική ενεργοποιημένη,Muziko ŝaltita,Música activada,,Musiikki päällä,Musique activée,Zene engedélyezve,Abilita la musica,音楽有効,,Muziek actief ,Musikk aktivert,Muzyka włączona,Música ativada,,Muzică activată,Музыка включена,,Musik aktiverad,Müzik etkin,Музику увімкнено, +4000 Hz,OPTVAL_4000HZ,,,,,,,,,,,,,,,,,,,,,,,4000 Гц,,,,4000 Гц, +8000 Hz,OPTVAL_8000HZ,,,,,,,,,,,,,,,,,,,,,,,8000 Гц,,,,8000 Гц, +11025 Hz,OPTVAL_11025HZ,,,,,,,,,,,,,,,,,,,,,,,11025 Гц,,,,11025 Гц, +22050 Hz,OPTVAL_22050HZ,,,,,,,,,,,,,,,,,,,,,,,22050 Гц,,,,22050 Гц, +32000 Hz,OPTVAL_32000HZ,,,,,,,,,,,,,,,,,,,,,,,32000 Гц,,,,32000 Гц, +44100 Hz,OPTVAL_44100HZ,,,,,,,,,,,,,,,,,,,,,,,44100 Гц,,,,44100 Гц, +48000 Hz,OPTVAL_48000HZ,,,,,,,,,,,,,,,,,,,,,,,48000 Гц,,,,48000 Гц, +64 samples,OPTVAL_64SAMPLES,,,,64 vzorků,,,64 δείγματα,64 specimenoj,64 muestras,,64 näytettä,,,,,64 샘플,,64 samplinger,64 sample,64 amostras,,64 monstre,64 семпла,64 узорка,64 samplingar,64 örnek,64 семпла, +128 samples,OPTVAL_128SAMPLES,,,,128 vzorků,,,128 δείγματα,128 specimenoj,128 muestras,,128 näytettä,,,,,128 샘플,,128 samplinger,128 sampli,128 amostras,,128 monstre,128 семплов,128 узорка,128 samplingar,128 örnek,128 семплів, +256 samples,OPTVAL_256SAMPLES,,,,256 vzorků,,,256 δείγματα,256 specimenoj,256 muestras,,256 näytettä,,,,,256 샘플,,256 samplinger,256 sampli,256 amostras,,256 monstre,256 семплов,256 узорка,256 samplingar,256 örnek,256 семплів, +512 samples,OPTVAL_512SAMPLES,,,,512 vzorků,,,512 δείγματα,512 specimenoj,512 muestras,,512 näytettä,,,,,512 샘플,,512 samplinger,512 sampli,512 amostras,,512 monstre,512 семплов,512 узорка,512 samplingar,512 örnek,512 семплів, +1024 samples,OPTVAL_1024SAMPLES,,,,1024 vzorků,,,1024 δείγματα,1024 specimenoj,1024 muestras,,1024 näytettä,,,,,1024 샘플,,1024 samplinger,1024 sampli,1.024 amostras,,1024 monstre,1024 семпла,1024 узорка,1024 samplingar,1024 örnek,1024 семплів, +2048 samples,OPTVAL_2048SAMPLES,,,,2048 vzorků,,,2048 δείγματα,2048 specimenoj,2048 muestras,,2048 näytettä,,,,,2048 샘플,,2048 samplinger,2048 sampli,2.048 amostras,,2048 monstre,2048 семплов,2048 узорка,2048 samplingar,2048 örnek,2048 семплів, +4096 samples,OPTVAL_4096SAMPLES,,,,4096 vzorků,,,4096 δείγματα,4096 specimenoj,4096 muestras,,4096 näytettä,,,,,4096 샘플,,4096 samplinger,4096 sampli,4.096 amostras,,4096 monstre,4096 семплов,4096 узорка,4096 samplingar,4096 örnek,4096 семплів, +Auto,OPTSTR_AUTO,,,,,Automatisk,,,Aŭtomata,Automático,,Automaattinen,,Automatikus,Automatico,自動,오토,,,Automatycznie,Automático,,,Авто,Аутоматски,Automatisk,Otomatik,Авто, +Mono,OPTSTR_MONO,,,,,,,,Monofonia,,,,,Monó,,モノラル,모노,,,,,,,Моно,Монотоно,,,Моно, +Stereo,OPTSTR_STEREO,,,,,,,,Stereofonia,Estéreo,,,Stéréo,Sztereó,,ステレオ,스테레오,,,,Estéreo,,,Стерео,Стереотоно,,,Стерео, +Dolby Pro Logic Decoder,OPTSTR_PROLOGIC,,,,,Dolby Pro Logic-dekoder,,,Malkodilo de Dolby Pro Logic ,,,,,,,ドルビー プロロジック デコーダー,돌비 프로 로직 디코더,,Dolby Pro Logic Dekoder,,Decodificador Dolby Pro Logic,,Decodor Pro Logic Dolby,Декодер Dolby Pro Logic,,Dolby Pro Logic-dekoder,Dolby Pro Logic Dekoder,Декодер Dolby Pro Logic, +Quad,OPTSTR_QUAD,,,,,,,,Kvadratofonia,Cuádruple,,Dolby Pro Logic -dekooderi,,,,クァッド,쿼드,,,Cztery kanały,Quadrifônico,,,Четырёхканальный,Четвородупло,,Dörtlü,Чотирьохканальний, +5 speakers,OPTSTR_SURROUND,,,,5 reproduktorů,5 højttalere,5 Lautsprecher,,5 Laŭtparoliloj,5 altavoces,,5 kaiutinta,5 enceintes,5 hangfal,Surround,5 スピーカー,5 스피커,5 luidsprekers,5 høyttalere,Głośniki 5,5 alto-falantes,,5 boxe,5 динамиков,5 спикер,5 högtalare,5 hoparlörler,5 динаміків, +5.1 speakers,OPTSTR_5POINT1,,,,Reproduktory 5.1,5.1-højttalere,5.1 Lautsprecher,,5.1 Laŭtparoliloj,Altavoces 5.1,,5.1 kaiutinta,Enceintes 5.1,5.1 hangrendszer,Surround 5.1,5.1 スピーカー,5.1 스피커,5.1 luidsprekers,5.1 høyttalere,Głośniki 5.1,Auto-falantes 5.1,,Boxe 5.1,Динамики 5.1,5.1 спикер,5.1-högtalare,5.1 hoparlörler,Динаміки 5.1, +7.1 speakers,OPTSTR_7POINT1,,,,Reproduktory 7.1,7.1-højttalere,7.1 Lautsprecher,,7.1 Laŭtparoliloj,Altavoces 7.1,,7.1 kaiutinta,Enceintes 7.1,7.1 hangrendszer,Surround 7.1,7.1 スピーカー,7.1스피커,7.1 luidsprekers,7.1-høyttalere,Głośniki 7.1,Auto-falantes 7.1,,Boxe 7.1,Динамики 7.1,7.1 спикер,7.1-högtalare,7.1 hoparlörler,Динаміки 7.1, +Playback device,OPENALMNU_PLAYBACKDEVICE,,,,Přehravací zařízení,Afspilningsenhed,Wiedergabegerät,,Ludado-aparato,Dispositivo de reproducción,,Äänitoistolaite,Sortie sonore,Visszajátszó eszköz,Dispositivo di playback,プレイバック デバイス,재생 장치,Afspeelapparaat,Avspillingsenhet,Urządzenie odtwarzania,Dispositivo de reprodução,,Dispozitiv de redare,Устройство воспроизведения,Аудио уређај,Uppspelningsenhet,Oynatma cihazı,Пристрій відтворення, +Enable EFX,OPENALMNU_ENABLEEFX,,,,Povolit EFX,Aktiver EFX,EFX aktiv,,Ŝalti EFX,Permitir EFX,,Ota käyttöön EFX,Activer EFX,EFX engedélyezése,Abilita EFX,EFXを有効化,EFX 켬,EFX inschakelen,Aktiver EFX,Pozwól na EFX,Ativar EFX,,Activare EFX,Включить EFX,Укључи EFX,Aktivera EFX,EFX'i Etkinleştir,Увімкнути EFX, +Resampler,OPENALMNU_RESAMPLER,,,,,Resampler,,,Respecimenilo,,,Näytteenottotaajuusmuunnin,,,,リサンプラー,재배열 기기,,,,Reamostrador,,,Передискретизатор,Ресемплер,,Yeniden Örnekleyici,Ресемплер, +Sounds volume,SNDMNU_SFXVOLUME,,,,Hlasitost zvuků,Lydstyrke,Effektlautstärke,Φονή ήχων,Sona laŭteco,Volumen de sonido,,Äänitehosteiden voimakkuus,Volume des Sons,Effektek hangereje,Volume suoni,効果音音量,효과음 음량,Geluidsvolume,Lydvolum,Głośność Dźwięku,Volume de sons,,Volum efecte,Громкость звука,Јачина звука,Ljudvolym,Ses seviyesi,Гучність звуків, +Menu volume,SNDMNU_MENUVOLUME,,,,Hlasitost nabídek,Menu-volumen,Menülautstärke,Φονή μενού,Menuo-laŭteco,Volumen del menú,,Valikon äänenvoimakkuus,Volume du Menu,Menü hangereje,Volume menù,メニュー音量,메뉴 음량,Menu volume,Menyvolum,Głośność Menu,Volume do menu,,Volum meniu,Громкость меню,Јачина менија,Volym för menyer,Menü ses seviyesi,Гучність меню, +Music volume,SNDMNU_MUSICVOLUME,,,,Hlasitost hudby,Lydstyrke for musik,Musiklautstärke,Φονή μουσικής,Muzika laŭteco,Volumen de la música,,Musiikin äänenvoimakkuus,Volume Musique,Zene hangereje,Volume musica,音楽音量,배경음 음량,Muziekvolume,Musikkvolum,Głośność Muzyki,Volume da música,,Volum muzică,Громкость музыки,Јачина музике,Musikvolym,Müzik sesi,Гучність музики, +MIDI device,SNDMNU_MIDIDEVICE,,,,MIDI zařízení,MIDI-enhed,MIDI-Gerät,MIDI συσκεύη,MIDI-aparato,Dispositivo MIDI,,MIDI-laite,Sortie MIDI,MIDI eszköz,Dispositivo MIDI,MIDIデバイス,MIDI 장치,MIDI-apparaat,MIDI-enhet,Urządzenie MIDI,Dispositivo MIDI,,Dispozitiv MIDI,MIDI-проигрыватель,MIDI уређај,MIDI-enhet,MIDI cihazı,MIDI програвач, +Sound in Background,SNDMNU_BACKGROUND,,,,Zvuk na pozadí,Lyd i baggrunden,Sound im Hintergrund,Ήχος στο παρασκήνιο,Sono en fono,Sonido en segundo plano,,Ääni taustalla,Son activé en arrière plan,Háttérhangok,Suono di sottofondo,バックグラウンドでのサウンド,배경화면에서도 소리 재생,Geluid in de achtergrond,Lyd i bakgrunnen,Dźwięk w Tle,Som em segundo plano,,Sunet pe fundal,Звук в фоне,Звуци у позадини,Ljud i bakgrunden,Arka Planda Ses,Звуки на фоні, +Underwater reverb,SNDMNU_UNDERWATERREVERB,,,,Ozvěna pod vodou,Undervandsreverb,Unterwasserhall,,Subakva resono,Reverberación bajo el agua,,Vedenalaiskaiku,Reverbération sous l'eau,Vízalatti visszaverődés,Reverb sott'acqua,水中反響音,수중 울림효과,Onderwater nagalm,Undervanns romklang,Pogłos pod wodą,Reverberação debaixo d'água,Reverberação debaixo de água,Reverb subacvatic,Эффект затухания под водой,Подводни одјек,Undervattensreverb,Su altı yankısı,Підводний ефект, +Randomize pitches,SNDMNU_RANDOMIZEPITCHES,,,,Náhodné výšky tónu,Randomisere tonehøjder,Zufällige Tonhöhe,,Malcertigi son-peĉojn,Tonos aleatorios,,Satunnaista äänenkorkeuksia,Tons sonores aléatoires,Hangmagasság keverése,Rendi casuale il tono,ランダマイズ ピッチ,음높이 무작위화,Willekeurige plaatsen,Tilfeldig tonehøyde,Losuj tonacje,Tons aleatórios,Tons aleatórios,Ton sunete aleatoriu,Случайная высота,Рандомизација тонова,Slumpmässiga tonhöjder,Sahaları rastgele ayarlayın,Змінювати висоту звуків, +Sound channels,SNDMNU_CHANNELS,,,,Počet zvukových kanálů,Lydkanaler,Soundkanäle,Κανάλια ήχου,Sonokanaloj,Canales de sonido,,Äänikanavat,Canaux sonores,Hangcsatorna,Numero canali del suono,サウンド チャンネル,음향 채널,Geluidskanalen,Lydkanaler,Kanały dźwiękowe,Canais de som,,Canale de sunet,Количество каналов,Звучни канали,Ljudkanaler,Ses kanalları,Кількість каналів, +Sound backend,SNDMNU_BACKEND,,,,Zvukový systém,Lyd backend,Soundsystem,,Sonoservilo,Sistema de sonido,,Äänijärjestelmä,Traitement Son,Hang backend,Backend suono,サウンド バックエンド,음향 말미,Geluidsarme achterkant,Lyd backend,System dźwiękowy,Sistema de som,,Sistem de sunet,Звуковая подсистема,Звучни бекенд,Ljudbakgrund,Ses arka ucu,Звукова система, +OpenAL options,SNDMNU_OPENAL,,,,Nastavení OpenAL,OpenAL-muligheder,OpenAL Optionen,OpenAL ρυθμίσεις,OpenAL agordoj,Opciones de OpenAL,,OpenAL-asetukset,Options OpenAL,OpenAL beállításai,Opzioni OpenAL,OpenAL オプション,오픈에이엘 설정,OpenAL opties,OpenAL-alternativer,Opcje OpenAL,Opções de OpenAL,,Setări OpenAL,Настройки OpenAL,OpenAL подешавања,OpenAL-alternativ,OpenAL seçenekleri,Параметри OpenAL, +Restart sound,SNDMNU_RESTART,,,,Restartovat zvuk,Genstart af lyd,Sound neu starten,,Rekomenci sonon,Reiniciar sonido,,Käynnistä ääni uudelleen,Redémarrer moteur sonore,Hang újraindítása,Resetta il suono,サウンド再起動,음향 재시작,Herstart geluid,Start lyd på nytt,Zresetuj dźwięk,Reiniciar som,,Reinițializare sunet,Перезапустить звук,Поново покрени звук,Starta om ljudet,Sesi yeniden başlat,Перезавантажити звук, +Advanced options,SNDMNU_ADVANCED,,,,Pokročilá nastavení,Avancerede indstillinger,Erweiterte Optionen,Προχήρημενες ρυθμίσεις,Altnivelaj agordoj,Opciones avanzadas,,Edistyneet asetukset,Options avancées,Haladó beállítások,Opzioni avanzate,高度なオプション,고급 설정,Geavanceerde opties,Avanserte alternativer,Zaawansowane Opcje,Opções avançadas,,Setări avansate,Расширенные настройки,Напредна подешавања,Avancerade alternativ,Gelişmiş seçenekler,Розширені налаштування, +Module replayer options,SNDMNU_MODREPLAYER,,,,Nastavení přehrávače modulů,Indstillinger for modulafspiller,Modul-Spieler-Optionen,,Agordoj por modulreludilo,Opciones reproductor de módulos,,Moduulisoitinasetukset,Options lecteur de module,Modul lejátszó beállításai,Opzioni Module replayer,モジュールリプレイヤー オプション,모듈 재생 설정,Module replayer opties,Alternativer for modulavspiller,Opcje Modułu Odtwarzacza,Opções de reprodutor de módulos,,Setări de redare a modulelor,Параметры воспроизведения модулей,Подешавања модулног риплејера,Alternativ för modulåterspelare,Modül yeniden oynatıcı seçenekleri,"Параметри ""Module replayer""", +Midi player options,SNDMNU_MIDIPLAYER,,,,Nastavení MIDI přehrávače,Indstillinger for Midi-afspiller,MIDI-Spieler-Optionen,,Agordoj por MIDI-ludilo,Opciones de reproductor MIDI,,MIDI-soitinasetukset,Option lecteur MIDI,Midi lejátszó beállításai,Opzioni Midi player,Midi再生のオプション,MIDI 플레이어 설정,Midi speler opties,Alternativer for midispiller,Opcje Odtwarzacza Midi,Opções de reprodutor MIDI,,Setări player MIDI,Настройки MIDI-проигрывателя,MIDI плејер подешавања,Alternativ för Midi-spelare,Midi oynatıcı seçenekleri,Параметри MIDI-програвача, +Sound in Menus,SNDMNU_MENUSOUND,,,,Zvuk v menu,Lyd i menuer,Sound in Menüs,,Sono en menuoj,,,Ääni valikoissa,Son dans les menus,Hang a menükben,Suono nei menù,メニューでのサウンド,,Geluid in menu's,Lyd i menyer,Dźwięk w Menu,Som em menus,,Sunet in meniuri,Звук в меню,,Ljud i menyer,Menülerde Ses,Звук в меню, +Advanced Sound Options,ADVSNDMNU_TITLE,,,,Pokročilá nastavení zvuku,Avancerede lydindstillinger,Erweiterte Soundoptionen,,Altnivelaj sonaj agordoj,Opciones avanzadas de sonido,,Edistyneet ääniasetukset,Options Sonores Avancées,Haladó hangbeállítások,Opzioni avanzate dei suoni,高度なサウンドオプション,고급 음향 설정,Geavanceerde geluidsopties,Avanserte lydalternativer,Zaawansowane Opcje Dźwięku,Opções de áudio avançadas,,Setări de sunet avansate,Расширенные настройки,Напредна подешавања звука,Avancerade ljudalternativ,Gelişmiş Ses Seçenekleri,Розширені налаштування звуку, +Sample rate,ADVSNDMNU_SAMPLERATE,,,,Vzorkovací frekvence,Samplerate,Samplerate,,Specimenrapideco,Frecuencia de muestreo,,Näytteenottotaajuus,Cadence de Sampling,Mintavételezési ráta,,サンプルレート,샘플링레이트,Steekproeftarief,Samplingsfrekvens,Częstotliwość próbkowania,Taxa de amostragem,,Frecvență de eșantionare,Частота дискретизации,Фреквенција узорковања,Samplingsfrekvens,Örnek oranı,Частота дискретизації, +HRTF,ADVSNDMNU_HRTF,,,,,,,,,,,,,,,,머리전달함수,,,,,,,,,,,3D звук у навушниках (HRTF), +OPL Synthesis,ADVSNDMNU_OPLSYNTHESIS,,,,Emulace OPL,OPL-syntese,OPL Synthese,,OPL-sintezo,Síntesis OPL,,OPL-synteesi,Synthèse OPL,OPL szintézis,,OPLシンセサイズ,OPL 합성,OPL synthese,OPL-syntese,Synteza OPL,Síntese OPL,,Sinteză OPL,Синтез OPL,OPL синтеза,OPL-syntes,OPL Sentezi,Синтезатор OPL, +Number of emulated OPL chips,ADVSNDMNU_OPLNUMCHIPS,,,,Počet emulovaných OPL čipů,Antal emulerede OPL-chips,Anzahl OPL Chips,,Nombro da imititaj OPL-blatoj,Número de chips OPL emulados,,Emuloitavien OPL-piirien lukumäärä,Puces OPL émulées,Emulált OPL csipek száma,Numero di chip OPL emulati,OPLチップエミュレートの番号,에뮬레이트된 OPL 칩 수,Aantal geëmuleerde OPL chips,Antall emulerte OPL-brikker,Liczba emulowanych czipów OPL,Número de chips OPL emulados,,Număr de cipuri OPL emulate,Количество эмулируемых чипов OPL,Број емулираних OPL чипа,Antal emulerade OPL-chips,Taklit edilen OPL çiplerinin sayısı,Кількість емульованих OPL-чіпів, +Full MIDI stereo panning,ADVSNDMNU_OPLFULLPAN,,,,Plné MIDI stereo,Fuld MIDI stereo panorering,Echte MIDI-Stereoeffekte,,Tuta MIDI-sterepanoramado,Balance estéreo MIDI completo,,Täysi MIDI-stereopanorointi,Latéralisation complète MIDI,Teljes MIDI sztereó tájolás,,Full MIDIステレオパンニング,완전한 MIDI 스테레오 패닝,Volledige MIDI stereo panning,Full MIDI stereo panorering,Pełne efekty stereo dla MIDI,Lateralidade estéreo completa para MIDI,,Panoramă stereo pentru MIDI,Полная стереопанорама для MIDI,Пуно MIDI стерео каналисање,Full MIDI-stereopanorering,Tam MIDI stereo kaydırma,Повне панорамування MIDI, +OPL Emulator Core,ADVSNDMNU_OPLCORES,,,,Emulační jádro OPL,OPL-emulatorkerne,OPL Emulatorkern,,OPL-imitilkerno,Núcleo de emulador OPL,,OPL-emulaattoriydin,Cœur émulateur OPL,,,OPL エミュレート コア,OPL 에뮬레이터 코어,OPL Emulator Kern,OPL-emulatorkjerne,Rdzeń Emulatora OPL,Núcleo do emulador de OPL,,Nucleu de emulare OPL,Ядро эмуляции OPL,OPL језгро емулације,OPL-emulatorns kärna,OPL Emülatör Çekirdeği,Тип OPL, +MIDI voices,ADVSNDMNU_MIDIVOICES,,,,Počet MIDI hlasů,MIDI-stemmer,MIDI Stimmen,,MIDI-voĉoj,Voces MIDI,,MIDI-äänet,Voix MIDI,MIDI hangok,Voci MIDI,MIDI ボイス,MIDI 최대 음색 양,MIDI-stemmen,MIDI stemmer,Głosy MIDI,Vozes MIDI,,Voci MIDI,MIDI-голоса,MIDI гласови,MIDI-stämmor,MIDI sesleri,MIDI поліфонія, +FluidSynth,ADVSNDMNU_FLUIDSYNTH,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Global,ADVSNDMNU_GLOBAL,,,,Globální,,,,Malloka,,,Yleinen,,,Globale,グローバル,전반적,Globaal,,Globalne,,,,Общие,Глобално,,Küresel,Загальні, +Freeverb,ADVSNDMNU_FREEVERB,,,,,,,,,,,,,,,フリーバーブ,프리버브,,,,,,,,,,Freeverb,, +Global Freeverb,ADVSNDMNU_GLOBAL_FREEVERB,,,,Globální Freeverb,Global Freeverb,Globales Freeverb,,Malloka Freeverb,Freeverb Global,,Yleinen Freeverb,Freeverb Global,,Freeverb globale,グローバル フリーバーブ,전반적 프리버브,Globale Freeverb,,Globalny Freeverb,Freeverb global,,Freeverb Global,Глобальный Freeverb,Глобални Freeverb,,Küresel Freeverb,Глобальний Freeverb, +Patch set,ADVSNDMNU_FLUIDPATCHSET,,,,Nástrojová sada,Patch-sæt,Patch-Set,,Flikaro,Set de parche,,Patch-asetus,Banque de Sons,,,パッチ セット,패치 세트,,Patch-sett,Zestaw łatek,Banco de sons,,Set patch,Патч-набор,Печ сет,Patch-uppsättning,Yama seti,Патч-набір, +Gain,ADVSNDMNU_FLUIDGAIN,,,,Zesílení,,Relative Lautstärke,,Akiro,Ganancia,,Vahvistus,,Visszaverődés,,ゲイン,쌓기,Relatief volume,,Wzmocnienie,Ganho,,Amplificare,Усиление,Појачање,Relativ volym,Kazanç,Підсилення, +Reverb,ADVSNDMNU_REVERB,,,,Ozvěna,,Hall,,Resono,Reverberación,,Kaiku,Réverbération,Visszhang,,リバーブ,리버브,Nagalm,,Pogłos,Reverberação,,,Реверберация,Одјек,,,Реверберація, +Reverb Level,ADVSNDMNU_REVERB_LEVEL,,,,Intenzita ozvěny,,Hallintensität,,Nivelo de resono,Nivel de reverberación,,Kaiunvoimakkuus,Niveau Réverb.,Visszhang szintje,,リバーブ量,리버브 강도,Nagalm niveau,Reverb-nivå,Poziom pogłosu,Nível de reverberação,,Nivel Reverb,Уровень реверберации,Ниво одјека,Reverb-nivå,Reverb Seviyesi,Рівень реверберації, +Chorus,ADVSNDMNU_CHORUS,,,,,,,,Koruso,,,,,,,コーラス,코러스,,,,,,Cor,Хор,Корус,,Koro,Хорус, +Timidity++,ADVSNDMNU_TIMIDITY,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ADLMidi,ADVSNDMNU_ADLMIDI,,,,,,,,,,,,,,,,,,,,,,,,,,,, +OPNMidi,ADVSNDMNU_OPNMIDI,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Timidity config file,ADVSNDMNU_TIMIDITYCONFIG,,,,Konfigurační soubor Timidity,Timidity-konfigurationsfil,Timidity Konfigurationsdatei,,Agorda dosiero de Timidity,Ruta al archivo config. Timidity,,Timidity-config-tiedosto,Fichier de config. TiMidity,Timidity konfigurációs fájl,File configurazione Timidity,Timidity コンフィグファイル,Timidity 코딩 파일,Timidity++ configuratiebestand,Timidity konfigurasjonsfil,Plik konfiguracyjny Timidity,Arquivo de configuração do Timidity,,Fișier configurație Timidity,Файл конфигурации Timidity,Timidity конфигурациона датотека,Timidity-konfigurationsfil,Timidity yapılandırma dosyası,Файл конфігурації Timidity, +Relative volume,ADVSNDMNU_TIMIDITYVOLUME,,,,Relativní hlasitost,Relativ lydstyrke,Relative Lautstärke,,Relativa laŭteco,Volumen relativo,,Suhteellinen äänenvoimakkuus,Volume Relatif,Relatív hangerő,Volume relativo,相対音量,비교적인 볼륨,Relatief volume,Relativt volum,Względna głośność,Volume relativo,,Volum relativ,Относительная громкость,Релативна јачина,Relativ volym,Bağıl hacim,Відносна гучність, +WildMidi,ADVSNDMNU_WILDMIDI,,,,,,,,,,,,,,,,,,,,,,,,,,,, +WildMidi config file,ADVSNDMNU_WILDMIDICONFIG,,,,Konfigurační soubor WildMidi,WildMidi konfigurationsfil,WilfMidi Konfigurationsdatei,,Agorda dosiero de WildMidi,Archivo de config. WildMidi,,WildMidi-config-tiedosto,Fichier config. WildMidi,WildMidi konfigurációs fájl,File WildMidi config,WildMidi コンフィグファイル,WildMidi 코딩 파일,WildMidi configuratiebestand,WildMidi konfigurasjonsfil,Plik konfiguracyjny WildMidi,Arquivo de configuração do WildMidi,,Fișier configurație WildMidi,Файл конфигурации WildMidi,WildMidi конфигурациона датотека,WildMidi-konfigurationsfil,WildMidi yapılandırma dosyası,Файл конфігурації WildMidi, +Select configuration,ADVSNDMNU_SELCONFIG,,,,Vybrat konfiguraci,Vælg konfiguration,Konfiguration wählen,,Elekti agordojn,Seleccionar configuración,,Valitse kokoonpano,Sélectionner configuration,Konfiguráció kiválasztása,Seleziona la configurazione,構成選択,설정을 고르시오,Selecteer configuratie,Velg konfigurasjon,Wybierz konfigurację,Selecionar configuração,,Selectare configurație,Выбор конфигурации,Изабери конфигурацију,Välj konfiguration,Yapılandırma seçin,Вибір конфігурації, +Advanced Resampling,ADVSNDMNU_ADVRESAMPLING,,,,Pokročilé převzorkování,Avanceret resampling,Erweitertes Resampling,,Altnivela respecimenado,Resampleo avanzado,,Kehittynyt näytteenottotaajuuden muuntaminen,Resampling Avancé,Fejlett Resmapling,Resampling avanzato,高度なリサンプリング,향상된 리샘플링,Geavanceerde herbemonstering,Avansert resampling,Zaawansowane Próbkowanie,Reamostragem avançada,,Resempling avansat,Продвинутый ресэмплинг,Напредно ресампловање,Avancerad återampling,Gelişmiş Yeniden Örnekleme,Розширений ресемплінг, +OPL Bank,ADVSNDMNU_OPLBANK,,,,OPL sada,,,,Banko por OPL,Banco OPL,,OPL-pankki,Banque OPL,,,,OPL 뱅크,,,Bank OPL,Banco OPL,,Bancă OPL,Банк OPL,OPL банка,OPL-bank,,Банк OPL, +OPL Emulator Core,ADVSNDMNU_ADLOPLCORES,,,,Emulační jádro OPL,OPL-emulatorkerne,OPL Emulatorkern,,Imitilkerno por OPL,Núcleos de emulador OPL,,OPL-emulaattoriydin,Cœur Emulateur OPL,OPL emulátor mag,,OPL エミュレートコア,OPL 에뮬레이터 코어,OPL Emulator Kern,OPL-emulatorkjerne,Rdzeń Emulatora OPL,Núcleo do emulador de OPL,,Nucleu de emulare OPL,Ядро эмуляции OPL,OPL емулационо језгро,OPL-emulatorns kärna,OPL Emülatör Çekirdeği,Ядро емуляції OPL, +Run emulator at PCM rate,ADVSNDMNU_RUNPCMRATE,,,,Emulátor používá PCM vzorkovací frekvenci,Kør emulator ved PCM-hastighed,Emulator benutzt PCM Samplerate,,Ruli imitilon laŭ rapido de PCM,Ejecutar emulador a velocidad PCM,,Aja emulaattoria PCM-taajuudella,Emulateur utilise cadence PCM,Emulátor futtatása PCM rátán,Esegui l'emulatore con rate PCM,PCMレートでエミュレート実行,PCM 속도로 에뮬레이터 실행,Emulator maakt gebruik van PCM Samplerate,Kjør emulator med PCM-hastighet,Uruchom emulator w częstotliwości PCM,Rodar emulador em taxa PCM,,Utilizare cu frecvența PCM,Использовать с частотой PCM,Покрени емулацију на PCM стопи,Kör emulatorn med PCM-frekvens,Emülatörü PCM hızında çalıştırın,Використовувати з частотою PCM, +Number of emulated OPL chips,ADVSNDMNU_ADLNUMCHIPS,,,,Počet emulovaných OPL čipů,Antal emulerede OPL-chips,Anzahl OPL Chips,,Numbro da imitaj OPL-blatoj,Número de chips OPL emulados,,Emuloitavien OPL-piirien lukumäärä,Puces OPL émulées,Emulált OPL csipek száma,Numero di chip OPL emulati,OPLチップエミュレートの番号,에뮬레이트된 OPL 칩 개수,Aantal geëmuleerde OPL chips,Antall emulerte OPL-brikker,Liczba emulowanych czipów OPL,Número de chips OPL emulados,,Număr de cipuri GUS emulate,Количество эмулируемых чипов OPL,Број емулираних OPL чипова,Antal emulerade OPL-chips,Taklit edilen OPL çiplerinin sayısı,Кількість емульованих OPL-чіпів, +Volume model,ADVSNDMNU_VLMODEL,,,,Model hlasitosti,Volumenmodel,Lautstärkemodell,,Modelo de laŭteco,Modelo de volumen,,Äänenvoimakkuusmalli,Modèle de Volume,Hangmodell,Modello di volume,音量モデル,모델 볼륨,Volume model,Volummodell,Model głośności,Modelo de volume,,Model volum,Модель громкости,Волумски модел,Volymmodell,Hacim modeli,Модель гучності, +OPN2 Emulator Core,ADVSNDMNU_OPNCORES,,,,Emulační jádro OPN2,OPN2-emulatorkerne,OPN2 Emulatorkern,,OPN2 Imitilkerno,Núcleo de emulador OPN2,,OPN2-emulaattoriydin,Cœur émulateur OPN2,OPN2 Emulátor Mag,,OPN2 エミュレート コア,OPN2 에뮬레이터 코어,OPN2 Emulatorkern van de OPN2-emulator,OPN2 Emulatorkjerne,Rdzeń Emulatora OPN2,Núcleo do emulador de OPN2,,Nucleu de emulare OPN2,Ядро эмуляции OPN2,OPN2 језгро емулације,OPN2-emulatorkärna,OPN2 Emülatör Çekirdeği,Ядро емуляції OPN2, +GUS Emulation,ADVSNDMNU_GUSEMULATION,,,,Emulace GUS,GUS-emulering,GUS Emulation,,GUS Imitado,Emulación GUS,,GUS-emulaatio,Emulation GUS,GUS Emuláció,,GUS エミュレーション,GUS 에뮬레이션,GUS-emulatie,GUS-emulering,Emulacja GUS,Emulação de GUS,,Emulare GUS,Эмуляция GUS,GUS емулација,GUS-emulering,GUS Emülasyonu,Емуляція GUS, +GUS config file,ADVSNDMNU_GUSCONFIG,,,,Konfigurační soubor GUS,GUS-konfigurationsfil,GUS Konfigurationsdatei,,Agorda dosiero de GUS,Archivo de config. GUS,,GUS-config-tiedosto,Fichier Config. GUS,GUS konfigurációs fájl,File GUS config,GUS コンフィグファイル,GUS 코딩 파일,GUS-configuratiebestand,GUS konfigurasjonsfil,Plik konfiguracyjny GUS,Arquivo de configuração do GUS,,Fișier configurație GUS,Файл конфигурации для GUS,GUS конфигурациона датотека,GUS-konfigurationsfil,GUS yapılandırma dosyası,Файл конфігурації для GUS, +Read DMXGUS lumps,ADVSNDMNU_DMXGUS,,,,Načíst DMXGUS soubory,Læs DMXGUS-klumper,Lese DMXGUS,,Legi DMXGUS Masojn,Leer archivos DMXGUS,,Lue DMXGUS-tietoja,Lire fichiers DMXGUS,DMXGUS lumpok beolvasása,Leggi i lump DMXGUS,DMXGUS ランプを読む,DMXGUS 럼프 읽기,DMXGUS-klonten lezen,Les DMXGUS-filer,Czytaj pliki DMXGUS,Ler lumps DMXGUS,,Citire fișiere DMXGUS,Читать файлы DMXGUS,Читај DMXGUS фајлове,Läsa DMXGUS-filer,DMXGUS dosyalarını okuma,Читати файли DMXGUS, +GUS memory size,ADVSNDMNU_GUSMEMSIZE,,,,Velikost paměti GUS,GUS-hukommelsesstørrelse,GUS Speichergröße,,GUS Memorampleksoj,Tamaño de memoria de GUS,,GUS-muistikoko,Taille mémoire GUS,GUS memória mérete,Dimensione della memoria per GUS,GUS メモリーサイズ,GUS 메모리 크기,GUS-geheugengrootte,GUS-minne størrelse,Rozmiar pamięci GUS,Tamanho de memória do GUS,,Memorie alocată pentru GUS,Размер памяти GUS,GUS величина памћења,GUS minnesstorlek,GUS bellek boyutu,Розмір пам'яті GUS, +Number of emulated OPN chips,ADVSNDMNU_OPNNUMCHIPS,,,,Počet emulovaných OPN čipů,Antal emulerede OPN-chips,Anzahl OPN Chips,,Nombro da imititaj OPL-blatoj,Número de chip OPN emulados,,Emuloitavien OPN-piirien lukumäärä,Puces OPN émulées,Emulált OPL csipek száma,Numero di chip OPN emulati,OPNチップエミュレートの番号,에뮬레이트된 OPN 칩 개수,Aantal geëmuleerde OPL chips,Antall emulerte OPN-brikker,Liczba emulowanych czipów OPN,Número de chips OPN emulados,,Număr de cipuri OPN emulate,Количество эмулируемых чипов OPN,Број емулираних OPN чипова,Antal emulerade OPN-chips,Taklit edilen OPN çiplerinin sayısı,Кількість емульованих OPN-чіпів, +Use custom WOPL bank,ADVSNDMNU_ADLCUSTOMBANK,,,,Použít vlastní WOPL sadu,Brug af brugerdefineret WOPL-bank,Benutzerdefinierte WOPL Bank,,Uzi laŭmendan WOPL-bankon,Utilizar banco WOPL personalizado,,Käytä mukautettua WOPL-pankkia,Utiliser Banque WOPL perso,Saját WOPL bank használata,Usa WOPL bank personalizzato,カスタムWOPL bankを使用,사용자 지정 WOPL 뱅크 사용,Gebruik de aangepaste WOPL bank,Bruk egendefinert WOPL-bank,Użyj niestandardowego banku WOPL,Usar banco WOPL personalizado,,Utilizați propriul bank WOPN,Использовать собственный банк WOPL,Користи прилагођенуу WOPL банку,Använd anpassad WOPL-bank,Özel WOPL bankası kullanın,Використовувати власний банк WOPL, +WOPL Bank file,ADVSNDMNU_OPLBANKFILE,,,,Soubor WOPL sady,WOPL Bank-fil,WOPL Bank-Datei,,WOPL-Bankodosiero,Archivo de banco WOPL,,WOPL-pankkitiedosto,Banque WOPL,WOPL Bank fájl,File WOPL Bank,WOPL bankファイル,WOPL 뱅크 파일,WOPL Bank-bestand,WOPL Bank-fil,Plik banku WOPL,Banco WOPL,,Fișier WOPN bank,Файл с банком WOPL,WOPL фајл банка,WOPL Bank-fil,WOPL Bank dosyası,Файл з банком WOPL, +Use custom WOPN bank,ADVSNDMNU_OPNCUSTOMBANK,,,,Použít vlastní WOPN sadu,Brug af brugerdefineret WOPN-bank,Benutzerdefinierte WOPN Bank,,Uzi laŭmendan WOPN-bankon,Utilizar banco WOPN personalizado,,Käytä mukautettua WOPN-pankkia,Utiliser Banque WOPN perso,Saját WOPN bank használata,Usa WOPN bank personalizzato,カスタムWOPN bankを使用,사용자 지정 WOPN 뱅크 사용,Gebruik aangepaste WOPN-bank op maat,Bruk egendefinert WOPN-bank,Użyj niestandardowego banku WOPN,Usar banco WOPN personalizado,,Utilizați propriul bank WOPN,Использовать собственный банк WOPN,Користи прилагођену WOPN банку,Använd anpassad WOPN-bank,Özel WOPN bankası kullanın,Використовувати власний банк WOPN, +WOPN Bank file,ADVSNDMNU_OPNBANKFILE,,,,Soubor WOPN sady,WOPN Bank-fil,WOPN Bank-Datei,,WOPN-Bankodosiero,Archivo de banco WOPN,,WOPN-pankkitiedosto,Banque WOPN,WOPN Bank fájl,File WOPN Bank,WOPN bankファイル,WOPN 뱅크 파일,WOPN Bank-bestand,WOPN-bankfil,Plik banku WOPN,Banco WOPN,,Fișier WOPN bank,Файл с банком WOPN,WOPN фајл банка,WOPN Bank-fil,WOPN Banka dosyası,Файл з банком WOPN, +Aliasing,OPTVAL_ALIASING,,,,,,,,Krenelaro,,,,,,,エイリアシング,에일리어싱,,,,,,Dedublare,Сглаживание,Преклапање,,Takma Adlandırma,Згладжування, +Linear,OPTVAL_LINEAR_1,This setting is duplicated threefold in order to allow for different grammatical gender endings,,,Lineární,Lineær,,,Lineara,Lineal,,Lineaarinen,Linéaire,Lineáris,Lineare,リニア,선형,Lineair,Lineær,Liniowy,,,Liniar,Линейное,Линеаран,Linjär,Doğrusal,Лінійне, +Linear,OPTVAL_LINEAR_2,,,,Lineární,Lineær,,,Lineara,Lineal,,Lineaarinen,Linéaire,Lineáris,Lineare,リニア,선형,Lineair,Lineær,Liniowa,,,Liniar,Линейная,Линеаран,Linjär,Doğrusal,Лінійна, +Linear,OPTVAL_LINEAR_3,,,,Lineární,Lineær,,,Lineara,Lineal,,Lineaarinen,Linéaire,Lineáris,Lineare,リニア,선형,Lineair,Lineær Lineær,Liniowe,,,Liniar,Линейный,Линеаран,Linjär,Doğrusal,Лінійний, +Nearest,OPTVAL_NEAREST,,,,Nejbližší,Nærmeste,Nächster Nachbar,,Plej proksima,Cercano,,Lähin,Nearest,Legközelebbi,Il più vicino,最寄り,가까이,Naast,Nærmeste,Najbiższe,Mais próximo,,Cel mai apropriat,Ближайший,Најближе,Närmaste,En yakın,Найближчий, +PCF (Low),OPTVAL_PCF_LOW,,,,PCF (nízké),PCF (lav),PCF (niedrig),,PCF (Malalta),PCF (Bajo),,PCF (matala),PCF (Low),PCF (Alacsony),PCF (basso),PCF (低),PCF (하급),PCF (Laag),PCF (lav),PCF (Niski),PCF (Baixo),,PCF (Scăzut),PCF (низкий),PCF (ниско),PCF (låg),PCF (Düşük),PCF (низький), +PCF (Medium),OPTVAL_PCF_MEDIUM,,,,PCF (střední),PCF (medium),PCF (mittel),,PCF (Meza),PCF (Medio),,PCF (keskitaso),PCF (Medium),PCF (Közepes),PCF (medio),PCF (中),PCF (중급),,PCF (middels),PCF (Średni),PCF (Médio),,PCF (Mediu),PCF (средний),PCF (средње),PCF (medelhög),PCF (Orta),PCF (средній), +PCF (High),OPTVAL_PCF_HIGH,,,,PCF (vysoké),PCF (høj),PCF (hoch),,PCF (Alta),PCF (Alto),,PCF (korkea),PCF (High),PCF (Magas),PCF (alto),PCF (高),PCF (상급),PCF (Hoog),PCF (høy),PCF (Wysoki),PCF (Alto),,PCF (Ridicat),PCF (высокий),PCF (високо),PCF (hög),PCF (Yüksek),PCF (високий), +Cubic,OPTVAL_CUBIC,,,,Kubická,Kubisk,Kubisch,,Kuba,Cúbico,,Kuutio,Cubique,Négyzetes,Cubico,キュービック,큐빅,Kubieke,Kubisk,Sześcienny,Cúbico,,Cub,Кубическое,Кубан,Kubisk,Kübik,Кубічне, +Band-limited step,OPTVAL_BLEP,,,,Omezené krokování,Båndbegrænset trin,Bandbegrenzte Schritte,,Bendo-limigita paŝo,Paso limitado por banda,,Kaistarajoitettu askel,Step limité par bande,Sáv-limitált lépés,Passo limitato dalla banda,帯域制限ステップ,제한된 단계별 밴드,Bandbeperkte stap,Båndbegrenset trinn,Krok ograniczony pasmem,Passo limitado por banda,,Limitare frecvență pas-cu-pas,Ограниченный полосой пропускания шаг,Постепено ограничење фреквенције,Bandbegränsat steg,Bant sınırlı adım,Покрокове обмеження частоти, +Linear (Slower),OPTVAL_LINEARSLOW,,,,Lineární (pomalejší),Lineær (langsommere),Linear (langsamer),,Lineara (Pli malrapida),Lineal (más lento),,Lineaarinen (hitaampi),Linéaire (Lent),Lineáris (Lassabb),Lineare (più lento),リニア(遅め),선형 (느리게),Lineair (langzamer),Lineær (langsommere),Liniowy (wolniejszy),Linear (mais lento),,Liniar (Mai lent),Линейное (медленнее),Линеаран (спорије),Linjär (långsammare),Doğrusal (Daha Yavaş),Лінійне (повільніше), +Band-limited linear,OPTVAL_BLAM,,,,Omezená lineární,Båndbegrænset lineær,Bandbegrenzt linear,,Bendo-limigita lineara,Lineal limitado por banda,,Kaistarajoitettu lineaarinen,Linéaire limité par bande,Sáv-limitált lineáris,Lineare limitato dalla banda,帯域制限リニア,밴드 제한 식 선형,Band-beperkt lineair,Båndbegrenset lineær,Liniowy ograniczony pasmem,Linear limitado por banda,,Limitare frecvență liniară,Ограниченное полосой пропускания линейное,Линеарно ограничење фреквенције,Bandbegränsad linjär,Bant sınırlı doğrusal,Лінійне обмеження частоти, +Cubic (Slower),OPTVAL_CUBICSLOW,,,,Kubická (pomalejší),Kubisk (langsommere),Kubisch (langsamer),,Kuba (Pli malrapida),Cúbico (más lento),,Kuutio (hitaampi),Cubique (Lent),Négyzetes (Lassabb),Cubico (più lento),キュービック (遅め),큐빅 (느리게),Kubieke (langzamer),Kubisk (langsommere),Sześcienny (wolniejszy),Cúbico (mais lento),,Cub (Mai lent),Кубическое (медленнее),Кубан (спорије),Kubisk (långsammare),Kübik (Daha Yavaş),Кубічне (повільніше), +Sinc,OPTVAL_SINC,,,,,Sinc,,,,Seno cardinal,,,,,,シンク,싱크,,,,Seno cardinal,,Sinus cardinal,Кардинальный синус,Синк,,,Функція sinc, +Note on/off only,OPTVAL_NOTEONOFFONLY,,,,Pouze začátek/konec noty,Kun note on/off,Nur für Note an/aus ,,Nur noto ek/for,Solo notas de Activ./Desact.,,Vain nuotti päällä/pois,Note on/off seulement,Hangjegy ki/be csak,Note solamente ON/OFF,ノート オン/オフ のみ,노트를 끄거나 켰을 때,Alleen toon aan/uit,Merk kun på/av,Tylko dla włączonych/wyłączonych notatek,Somente notas ligadas/desligadas,,Numai la activarea/oprirea notelor,Только при включении/отключении нот,Само током укључења/искључења ноте,Endast anteckning på/av,Yalnızca not açma/kapama,Лише для нот, +Full ramping,OPTVAL_FULLRAMPING,,,,Plný náběh,Fuld rampe,,,Plena pligrandigado,Aumento completo,,Täysi kerrytys,Rampe complète,Teljes ramping,Ramping completo,フルランピング,최대 램핑,Volledige helling,,Pełne zwiększenie,Rampa completa,,Creștere completă,Полное наращивание,Пуно појачање,Full rampning,Tam rampa,Згладжування різких змін гучності, +Master volume,MODMNU_MASTERVOLUME,,,,Celková hlasitost,Master-volumen,Grundlautstärke,,Ĉeflaŭteco,Volumen maestro,,Yleisäänenvoimakkuus,Volume maître,Fő hangerő,Volume master,全体音量,마스터 볼륨,Hoofdvolume,Hovedvolum,Całkowita głośność,Volume geral,,Volum general,Общая громкость,Глацни звук,Huvudvolym,Ana ses seviyesi,Загальна гучність, +Quality,MODMNU_QUALITY,,,,Kvalita,Kvalitet,Qualität,,Kvaliteco,Calidad,,Laatu,Qualité,Minőség,Qualità,クオリティ,품질,Kwaliteit,Kvalitet,Jakość,Qualidade,,Calitate,Качество,Квалитет,Kvalitet,Kalite,Якість, +Volume ramping,MODMNU_VOLUMERAMPING,,,,Křivka hlasitosti,Lydstyrke-rampe,Lautstärkeverhalten,,Laŭteco-pligrandigado,Aumento gradual de Volumen,,Äänenvoimakkuuden kertyminen,Rampe du volume,,Ramping volume,音量ランピング,볼륨 램핑,Volume-aanvulling,Volumramping,Zwiększenie głośności,Rampa de volume,,Creștere volum,Наращивание громкости,Појачавање звука,Volymrampning,Hacim artırma,Нарощування гучності, +Chip-o-matic,MODMNU_CHIPOMATIC,,,,,,,,,,,,,,,チップ オー マチック,칩-오-매틱,,,,,,,,,,,, +MAME OPL2,OPTVAL_MAMEOPL2,,,,,,,,,,,,,,,,마메 OPL2,,,,,,,,,,,, +DOSBox OPL3,OPTVAL_DOSBOXOPL3,,,,,,,,,,,,,,,,도스박스 OPL3,,,,,,,,,,,, +Java OPL3,OPTVAL_JAVAOPL3,,,,,,,,,,,,,,,,자바 OPL3,,,,,,,,,,,, +Nuked OPL3,OPTVAL_NUKEDOPL3,,,,,,,,,,,,,,,,,,,,,,,,,,,, +MAME YM2612,OPTVAL_MAMEOPN2,,,,,,,,,,,,,,,,마메 YM2612,,,,,,,,,,,, +Neko Project II Kai OPNA,OPTVAL_NP2OPNA,,,,,,,,,,,,,,,,,,,,,,,,,,,, +MAME YM2608,OPTVAL_MAMEOPNA,,,,,,,,,,,,,,,,마메 YM2608,,,,,,,,,,,, +PMDWin OPNA,OPTVAL_PMDWINOPNA,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Opal OPL3,OPTVAL_OPALOPL3,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Nuked OPL3 v1.7.4,OPTVAL_NUKEDOPL3174,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Nuked OPN2,OPTVAL_NUKEDOPN2,,,,,,,,,,,,,,,,,,,,,,,,,,,, +GENS YM2612,OPTVAL_GENSOPN2,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Auto (Use setup of bank),ADLVLMODEL_AUTO,,,,Auto (použít nastavení sady),Auto (Brug opsætning af bank),Auto (Benutze Einstelliung der Bank),,Aŭtomata (Uzi bankagordaĵon),Auto (Usar config. del banco),,Automaattinen (käytä pankin asetuksia),Auto (Utiliser paramètre banque),Automatikus (Beállított bank használata),Automatico (Usa le impostazioni del bank),自動(bankのセットアップ使用),자동(뱅크 셋업 사용),Auto (gebruik instelling van de bank),Auto (Bruk oppsett av bank),Automatycznie (Użyj ustawień banku),Automático (usar definições de banco),,Auto (configurare din bancă),Авто (настройка из банка),Аутоматски (користи намештену банку),Auto (använder bankens inställning),Otomatik (Banka kurulumunu kullan),Авто (налаштування з банку), +Generic,ADLVLMODEL_GENERIC,,,,Standardní,Generisk,Allgemein,,Komuna,Genérico,,Yleinen,Générique,Általános,Generico,一般的,전형적,Algemeen,Generisk,Ogólne,Genérico,,,Общий,Генерично,Generisk,Jenerik,Загальний, +OPL Native,ADLVLMODEL_NATIVE,,,,Nativní OPL,OPL Native,OPL Nativ,,Nativa OPL,Nativo OPL,,Luontainen OPL,OPL Natif,Natív OPL,,OPLネイティブ,고유 OPL,,,Natywne OPL,Nativo OPL,,OPL propriu,Встроенная OPL,OPL домаћи,OPL inhemsk,OPL Yerli,Вбудована OPL, +"DMX (Accurate, with AM bug)",ADLVLMODEL_DMX,,,,"DMX (Přesný, s AM chybou)","DMX (nøjagtig, med AM-fejl)",,,,,,,,"DMX (Pontos, de AM buggal)",,,데이터 마이닝 확장,"DMX (accuraat, met AM bug)","DMX (Nøyaktig, med AM-feil)",,"DMX (preciso, com bug de AM)",,"DMX (Precis, cu probleme în AM)","DMX (Точная, с ошибкой АМ)",,"DMX (exakt, med AM-bugg)","DMX (Doğru, AM hatalı)","DMX (Точна, з помилкою АМ)", +"Apogee (Accurate, with AM bug)",ADLVLMODEL_APOGEE,,,,"Apogee (Přesný, s AM chybou)","Apogee (nøjagtig, med AM-fejl)",,,,,,,,"Apogee (Pontos, de AM buggal)",,,어포지,"Apogee (accuraat, met AM bug)","Apogee (Nøyaktig, med AM-feil)",,"Apogee (preciso, com bug de AM)",,"Apogee (Precis, cu probleme în AM)","Apogee (Точная, с ошибкой АМ)",,"Apogee (Exakt, med AM-bugg)","Apogee (Doğru, AM hatası ile)","Apogee (Точна, з помилкою АМ)", +Win9X-like (SB16),ADLVLMODEL_WIN9X,,,,Jako Windows 9X (SB16),Win9X-lignende (SB16),Wie Windows 9X (SB16),,Kiel Win9X (SB16),Como Win9X (SB16),,Win9x-kaltainen (SB16),,Win9X szerű (SB16),,Win9X式 (SB16),Win9X 같게 (SB16),Win9X-achtig (SB16),Win9X-lignende (SB16),Jak w Win9X (SB16),Estilo Win9X (SB16),,Similar cu Win9X (SB16),Похожая на Win9X (Вариант SB16),Као у Win9X-у (SB16),Win9X-liknande (SB16),Win9X benzeri (SB16),Схожа на Win9X (Варіант SB16), +Win9X-like (Generic FM),ADLVLMODEL_WIN9XGENERIC,,,,Jako Windows 9X (Generic FM),Win9X-lignende (generisk FM),Wie Windows 9X (Generic FM),,Kiel Win9X (Generic FM),Como Win9X (Generic FM),,Win9x-kaltainen (Generic FM),,Win9X szerű (Általános FM),,Win9X式 (Generic FM),Win9X 같게 (Generic FM),Win9X-achtig (Generic FM),Win9X-lignende (Generisk FM),Jak w Win9X (Generic FM),Estilo Win9X (FM genérico),,Similar cu Win9X (Generic FM),Похожая на Win9X (Вариант Generic FM),Као у Win9X-у (Generic FM),Win9X-liknande (generisk FM),Win9X benzeri (Jenerik FM),Схожа на Win9X (Варіант Generic FM), +DMX (Without AM voice bug),ADLVLMODEL_DMX_FIXED,,,,DMX (Bez AM hlasové chyby),DMX (uden AM-stemmefejl),DMX (Ohne AM-Stimmenfehler),,DMX (Sen cimo de AM-voĉo),DMX (Sin bug de voz AM),,DMX (ilman AM-äänivikaa),DMX (Sans bug canaux AM),DMX (AM hanghiba nélkül),,DMX(AMボイスバグ無し),,DMX (zonder AM voice bug),DMX (uten AM-stemmefeil),DMX (bez głosowego błędu AM),DMX (sem bug de voz de AM),,DMX (Fără probleme în AM),DMX (Без ошибки АМ),,DMX (utan AM-röstfel),DMX (AM ses hatası olmadan),DMX (Без помилки АМ), +Apogee (Without AM voice bug),ADLVLMODEL_APOGEE_FIXED,,,,Apogee (Bez AM hlasové chyby),Apogee (uden AM-stemmefejl),Apogee (Ohne AM-Stimmenfehler),,Apogee (Sen cimo de AM-voĉo),Apogee (Sin bug de voz AM),,Apogee (ilman AM-äänivikaa),Apogee (avec bug canaux AM),Apogee (AM hanghiba nélkül),,Apogee(AMボイスバグ無し),,Apogee (zonder AM voice bug),Apogee (uten AM-stemmefeil),Apogee (bez głosowego błędu AM),Apogee (sem bug de voz de AM),,Apogee (Fără probleme în AM),Apogee (Без ошибки АМ),,Apogee (utan AM-röstfel),Apogee (AM ses hatası olmadan),Apogee (Без помилки АМ), +IBM Audio Library Interface,ADLVLMODEL_AIL,,,,,,,,IBM Aŭdbibiloteka Interfaco,,,,,IBM Hang Könyvtár Interfész,,,,,,Interfejs Biblioteki Dźwięków IBM,Interface de Biblioteca de Áudio IBM,,Interfață de Bibliotecă IBM,IBM AIL,,IBM Audio Library Interface (gränssnitt för ljudbibliotek),IBM Ses Kitaplığı Arayüzü,, +HMI Sound Operating System,ADLVLMODEL_HMI,,,,,,,,HMI Sonoperaciumo,,,,,HMI Hang Operációs Rendszer,,,,,,System Operacyjny Dźwięków HMI,Sistema Operacional de Som HMI,,Sistem Sonor HMI,HMI SOS,,HMI-ljud Operativsystem,HMI Ses İşletim Sistemi,, +"HMI SOS (Old, with bugs)",ADLVLMODEL_HMIOLD,,,,"HMI SOS (Starý, s chybami)","HMI SOS (gammelt, med fejl)","HMI SOS (alt, mit Fehlern)",,"HMI SOS (Malnova, kun cimoj)","HMI SOS (Viejo, con bugs)",,"HMI SOS (vanha, vikainen)",HMI SOS (vieux et buggé),"HMI SOS (Régi, bugokkal)",,HMI SOS(旧式、バグ含む),,"HMI SOS (oud, met bugs)","HMI SOS (gammel, med feil)","HMI SOS (Stare, z błędami)","SOS HMI (antigo, com bugs)",,"HMI SOS (Vechi, cu probleme)",HMI SOS (Старый вариант с ошибками),,"HMI SOS (gammalt, med fel)","HMI SOS (Eski, hatalı)",HMI SOS (Старий варіант з помилками), +Unlimited,OPTVAL_UNLIMITED,,,,Neomezené,Ubegrænset,Unlimitiert,,Senlima,Ilimitado,,Rajoittamaton,Illimité,Végtelen,Illimitato,無制限,무제한,Onbeperkt,Ubegrenset,Nieskończone,Sem limites,,Nelimitat,Без ограничений,Бескрајно,Obegränsad,Sınırsız,Необмежено, +256K,OPTVAL_256K,,,,,,,,,,,,,,,,,,,,,,,,,,,, +512K,OPTVAL_512K,,,,,,,,,,,,,,,,,,,,,,,,,,,, +768K,OPTVAL_768K,,,,,,,,,,,,,,,,,,,,,,,,,,,, +1024K,OPTVAL_1024K,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,Postprocessing,,,,,,,,,,,,,,,,,,,,,,,,,,, +Uncharted 2,OPTVAL_UNCHARTED2,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Hejl Dawson,OPTVAL_HEJLDAWSON,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Reinhard,OPTVAL_REINHARD,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Palette,OPTVAL_PALETTE,,,,Paleta,Palet,,Παλέτα,Paletro,Paleta,,Paletti,,Paletta,Palette,パレット,팔레트,Palet,,Paleta,Paleta,Palete,Paletă,Палитра игры,Палет,Palett,Palet,Палітра гри, +Low,OPTVAL_LOW,,,,Nízká,Lav,Niedrig,Χαμηλό,Malalta,Bajo,,Matala,Bas,Alacsony,Basso,低,낮음,Laag,Lav,Niskie,Baixo,,Scăzut,Низкое,Ниско,Låg,Düşük,Низьке, +Medium,OPTVAL_MEDIUM,,,,Střední,,Mittel,Μεσαίο,Meza,Medio,,Keskitaso,Moyen,Közepes,Medio,中,중간,Middel,Middels,Średnie,Médio,,Mediu,Среднее,Средње,Medelstor,Orta,Середнє, +High,OPTVAL_HIGH,,,,Vysoká,Høj,Hoch,Υψηλό,Alta,Alto,,Korkea,Elevé,Magas,Alto,高,높음,Hoog,Høy,Wysokie,Alto,,Ridicat,Высокое,Високо,Hög,Yüksek,Високе, +Extreme,OPTVAL_EXTREME,,,,Extrémní,Ekstrem,Extrem,Ακράιο,Ekstrema,Extremo,,Äärimmäinen,Extrême,Extrém,Estremo,最高,매우 높음,Extreem,Ekstrem,Ekstremalne,Extremo,,Extrem,Максимальное,Екстремно,Extremt,Aşırı,Максимальне, +Obverse,OPTVAL_OBVERSEFIRST,,,,Vpřed (obvers),Forside,Obvers,Παρατήρησε,Antaŭa,Anverso,,Etupuoli,,Ellentétes,Dritto,正面,앞면,Obvers,Forside,Awers,Obverso,,Avers,Прямой,Супротно,Framsida,Ön yüz,Прямий, +Reverse,OPTVAL_REVERSEFIRST,,,,Vzad (revers),Bagside,Revers,Αντίστροφο,Inversa,Inverso,,Käänteinen,Inverse,Fordított,Contrario,反転,반전,Revers,Baksiden,Rewers,Reverso,,Invers,Обратный,Обрнуто,Baksida,Ters,Зворотний, +Postprocessing,GLMNU_POSTPROCESS,,,,,Efterbehandling,,Μετα-επεξεργασία,Postprocezado,Postprocesado,,Jälkikäsittely,,,,ポストプロセッシング,포스트프로세싱 적용,Nabewerking,Etterbehandling,Przetwarzanie końcowe,Pós-processamento,,Postprocesare,Постобработка,Пост обрада,Efterbehandling,İşlem sonrası,Постобробка, +Tonemap Mode,GLPREFMNU_TONEMAP,,,,Režim tónovací mapy,Tonemap-tilstand,Tonemap Modus,,Reĝimo de Tonmapo,Modo de mapa de tonos,,Sävykarttatila,Mode Tonemap,Színleképzés módja,Modalità Tonemap,トーンマップ モード,톤맵 모드,Tonemap modus,Tonemap-modus,Tryb Mapowania Tonów,Tipo de tonemap,,Mod Tonemap,Режим тонового отображения,Тонирано-мапни мод,Tonemap-läge,Ton Haritası Modu,Режим тонального відображення, +Lens distortion effect,GLPREFMNU_LENS,,,,Efekt distorze čočky,Objektivforvrængningseffekt,Optischer Verzerrungseffekt,,Lensdistorto-efiko,Efecto de distorsión de lente,,Linssinvääristystehoste,Effet distorsion de lentille,Lencsetorzulás effekt,Effetto distorsione della lente,レンズの歪みエフェクト,렌즈 왜곡 효과,Effect van de lensvervorming,Linseforvrengningseffekt,Efekt zniekształcenia obiektywu,Distorção de lente,Efeito de distorção da lente,Efect de distorsionare,Эффект искажения линзы,Дисторзија објектива ефект,Linsförvrängningseffekt,Lens bozulma efekti,Ефект деформації лінзи, +FXAA Quality,GLPREFMNU_FXAA,,,,Kvalita FXAA,FXAA-kvalitet,FXAA Qualität,FXAA ποίοτητα,Kvaliteco de FXAA,Calidad FXAA,,FXAA-laatu,Qualité FXAA,FXAA minősége,Qualità FXAA,FXAA品質,FXAA 품질,FXAA-kwaliteit,FXAA-kvalitet,Jakość FXAA,Qualidade de FXAA,,Calitate FXAA,Качество FXAA,FXAA квалитет,FXAA-kvalitet,FXAA Kalitesi,Якість FXAA, +Dither output,GLPREFMNU_DITHER,,,,Dithering,Dither-udgang,Dithering,,Apliki punktojn al eligo,Dither de salida,,Sekoitussävytyksen (dithering) ulostulo,Dithering,Árnyalás kimenet,Dithering,ディザー出力,떨림 효과 출력,Dither output,Dither-utgang,Dygotanie,Dithering,,Putere Dithering,Дизеринг,Учестаност трептања,Dither-utgång,Dither çıkışı,Дитеринг, +Tonemap Palette Order,GLPREFMNU_PALTONEMAPORDER,,,,Pořadí palety tónovací mapy,Tonemap-palettens rækkefølge,Palettensortierung für Tonemap,,Ordo de Kolormapo-Paletro,Orden de la paleta en mapa de tonos,,Sävykartan paletin järjestys,Ordre des palettes tonemap,Színleképzés paletta sorrend,Ordine della Palette Tonemap,トーンマップパレット順序,톤맵 팔레트 순서,Tonemap Palet Orde van het Tonemap-palet,Tonemap-palettrekkefølge,Kolejność Palet Mapowania Tonów,Ordem da paleta tonemap,,Ordine paletă Tonemap,Порядок палитры тонового отображения,Тонирано-мапни палетни ред,Tonemappalettordning,Ton Haritası Palet Sırası,Порядок палітри тонального відображення, +Tonemap Palette Exponent,GLPREFMNU_PALTONEMAPPOWER,,,,Exponent palety tónovací mapy,Tonemap-palettens eksponent,Palettenexponent für Tonemap,,Exponeto de Kolormapo-Paletro,Exponente paleta en mapa de tonos,,Sävykartan paletin eksponentti,Exponent des palettes tonemap,Tonemap Paletta Exponens,Esponente della Palette Tonemap,トーンマップパレット指数,톤맵 팔레트 지수,Tonemap Palet Exponent,Tonemap Palette Eksponent,Wykładnik Palet Mapowania Tonów,Expoente da paleta tonemap,,Exponent paletă Tonemap,Экспонента палитры тонового отображения,Тонирано-мапни палетни експонент,Exponent för tonemappalett,Ton Haritası Paleti Üsteli,Експонента палітри тонального відображення, +Multisample,GLPREFMNU_MULTISAMPLE,,,,Multisampling,,Multisampling,,Plurspecimeno,Multisampling,,Moninäytteistys,,,,マルチサンプル,멀티샘플,,,Multipróbkowanie,Multiamostragem,,Multisampling,Мультисэмплинг,Мулти-узорак,,Çoklu Örneklem,Багатовибіркове згладжування, +Bloom effect,GLPREFMNU_BLOOM,,,,Efekt bloom,Bloom-effekt,Bloom Effekt,,Lumŝmiro-efiko,Efecto Bloom,,Hehkutehoste (bloom),Effet surbrillance,Bloom effekt,Effetto Bloom,ブルーム エフェクト,블룸 효과,Bloom-effect,Bloom-effekt,Effekt Bloom,Bloom,,Efect Bloom,Свечение,Мутан вид ефект,Bloom-effekt,Çiçeklenme etkisi,Ефект сяйва (Bloom), +Ambient occlusion quality,GLPREFMNU_SSAO,,,,Kvalita ambient occlusion,Omgivende okklusionskvalitet,Ambient Occlusion Qualität,,Kvaliteco de media obstrukceco,Calidad de oclusión ambiental,,Yleisvarjostuksen (ambient occlusion) laatu,Qualité Occlusion Ambiente,Ambient occlusion minősége,Qualità occlusione ambientale,アンビエント オクルージョンの品質,주변 환경 가림 효과 품질,Kwaliteit van omgevingsverduistering,Omgivende okklusjonskvalitet,Jakość okluzji otoczenia,Qualidade de oclusão de ambiente,,Calitate ocluzie ambientală,Качество глобального затенения,Оклузија амбијента ефект,Kvalitet för omgivande ocklusion,Ortam oklüzyon kalitesi,Якість імітації тіней, +Portals with AO,GLPREFMNU_SSAO_PORTALS,,,,Portály s AO,Portaler med AO,Portale mit AO,,Portaloj kun Media obstrukceco,Portales con OA,,Yleisvarjostuksen portaalit,OA pour les portails,Portálok AO-val,Portali con l'OA,AOを伴うポータル,주변 환경 가려진 포탈,Portals met AO,Portaler med AO,Portale z okluzją otoczenia,Portais com oclusão de ambiente,,Portaluri cu ocluzie ambientală,Порталы с глобальным затенением,Портали са AO,Portaler med omgivande ocklusion,AO'lu Portallar,Портали з глобальним затіненням, +Menu Blur,GLPREFMNU_MENUBLUR,,,,Rozostření pozadí v menu,Menu sløring,Menüunschärfe,Θόλοση μενού,Malklarigo de menuo ,Difuminación de menú,,Valikon sumennus,Flou menu,Menü mosódás,Blur del menu,メニューブラー,메뉴 흐림 효과,Menu vervagen,Meny uskarphet,Rozmycie w Menu,Desfoque do menu,Desfocagem do Menu,Neclaritate Meniu,Размытие фона меню,Блур мениа,Menyns oskärpa,Menü Bulanıklığı,Розмиття фону в меню, +Environment map on mirrors,GLPREFMNU_ENVIRONMENTMAPMIRROR,,,,Mapa prostředí na zrcadlech,Miljøkort på spejle,Lichteffekt auf Spiegeln,,Medimapo sur speguloj,Mapa de entorno en espejos,,Ympäristökartta peileissä,Mappage environment sur les miroirs,Környezet tükröződés,Ambiente mappa sugli specchi,マップオンミラーの画像表示,거울 주변의지도 활성,Milieukaart op spiegels,Omgivelseskart på speil,Mapa środowiska w lustrach,Mapa de ambiente em espelhos,,Efecte suplimentare pentru oglinzi,Карта окружения на зеркалах,Околинска мапа на прозорима,Miljökarta på speglar,Aynalar üzerinde çevre haritası,Карта оточення на дзеркалах, +Rendering quality,GLPREFMNU_RENDERQUALITY,,,,Kvalita vykreslování,Renderingskvalitet,Renderqualität,,Kvalito de bildigado,Calidad de renderizado,,Hahmonnuslaatu,Qualité du rendu,Renderelés minősége,Qualità resa grafica,レンダリング品質,렌더링 품질,Het teruggeven van kwaliteit,Renderingskvalitet,Jakość Renderowania,Qualidade de renderização,,Calitate video,Качество обработки,Квалитет рендовања,Renderingskvalitet,Render kalitesi,Якість візуалізації, +Speed,OPTVAL_SPEED,,,,Rychlost,Hastighed,Geschwindigkeit,Ταχύτητα,Rapido,Velocidad,,Nopeus,Vitesse,Sebesség,Prestazioni,速度寄り,성능,Snelheid,Hastighet,Szybkość,Velocidade,,Viteză,Скорость,Брзина,Hastighet,Hız,Швидкість, +Quality,OPTVAL_QUALITY,,,,Kvalita,Kvalitet,Qualität,Ποιότητα,Kvalito,Calidad,,Laatu,Qualité,Minőség,Qualità,品質寄り,고품질,Kwaliteit,Kvalitet,Jakość,Qualidade,,Calitate,Качество,Квалитет,Kvalitet,Kalite,Якість, +Sector light mode,GLPREFMNU_SECLIGHTMODE,,,,Režim osvětlení sektorů,Sektorlystilstand,Sektorlichtmodus,,Reĝimo de sektorlumo,Modo de luz de sector,,Sektorivalojen tila,Mode de lumière Secteur,Szektor fény mód,Modalità luce di settore,セクターライトモード,섹터 조명 모드,Sector lichte wijze,Sektorlysmodus,Tryb oświetlenia sektorów,Modo de luz de setor,,Mod iluminare sectorială,Режим освещения секторов,Секторско светло мод,Sektorljusläge,Sektör ışığı modu,Режим освітлення секторів, +Fog mode,GLPREFMNU_FOGMODE,,,,Režim mlhy,Tågetilstand,Nebelmodus,Λειτουργία ομίχλης,Reĝimo de nebulo,Modo de niebla,,Sumutila,Mode du broullard,Köd mód,Effetto nebbia,フォグモード,안개 모드,Mistmodus,Tåkemodus,Tryb mgły,Modo de neblina,,Mod ceață,Режим тумана,Магла мод,Dimläge,Sis modu,Режим туману, +Radial,OPTVAL_RADIAL,,,,Radiální,Radial,,Ακτινικό,Radiusa,,,Säteittäinen,,Sugaras,Radiale,放射状,방사형,Radiaal,,Promieniowe,,,Radială,Круговой,Радијално,,Radyal,Радіальний, +Standard,OPTVAL_STANDARD,,,,Standardní,,,,Norma,Estándar,,Normaali,,Szabvány,,標準,기본,Standaard,,,Padrão,,,Стандартный,Стандардно,,Standart,Стандартний, +,,Texture options,,,,,,,,,,,,,,,,,,,,,,,,,,, +Texture Filter mode,GLTEXMNU_TEXFILTER,,,,Režim filtrování textur,Tilstand for teksturfilter,Texturfiltermodus,,Reĝimo por Teksturfiltrado,Modo de filtro de texturas,,Pintakuviointien suodatustapa,Mode de Filtrage Texture,Textúrafilter módja,Modalità filtro texture,テクスチャーフィルター モード,텍스쳐 필터 모드,Textuurfiltermodus,Teksturfilter-modus,Tryb Filtrowania Tekstur,Modo de filtro de textura,,Mod Filtrare Texturi,Фильтрация текстур,Текстурни филтер мод,Texturfilterläge,Doku Filtresi modu,Тип фільтрації текстур, +Anisotropic filter,GLTEXMNU_ANISOTROPIC,,,,Anisotropické filtrování,Anisotropisk filter,Anisotropische Filterung,,Anizotropa filtro,Filtro anisotrópico,,Anisotrooppinen suodatus,Filtre Anisotropique,Anizotropikus filter,Filtro anisotropico,異方性フィルター,이방성 필터,Anisotroopfilter,Anisotropisk filter,Filtr anizotropowy,Filtro anisotrópico,,Filtrare Anizotropică,Анизотропная фильтрация,Анизотропни фолтер,Anisotropt filter,Anizotropik filtre,Анізотропна фільтрація, +None (nearest mipmap),OPTVAL_NONENEARESTMIPMAP,,,,Žádné (mipmapa - nejbližší soused),Ingen (nærmeste mipmap),Aus (nächste Mipmap),,Nenio (plej proksima mipmapo),Ninguno (mipmap cercano),,Ei mitään (lähin mipkartta),Aucun (mipmap proche voisin),Semmilyen (közeli mipmap),Nessuno (mipmap più vicina),なし(最寄りミップマップ),없음 (밉멥에 가까움),Geen (dichtstbijzijnde mipmap),Ingen (nærmeste mipmap),Brak (najbliższa mipmapa),Nenhum (mipmap mais próximo),,Niciuna (mipmap de apropriere),Нет (ближайший MIP-уровень),Ништа (најближи мипмап),Ingen (närmaste mipmap),Yok (en yakın mipmap),Відсутня (найближчий міпмап), +None (linear mipmap),OPTVAL_NONELINEARMIPMAP,,,,Žádné (mipmapa - lineární),Ingen (lineær mipmap),Aus (lineare Mipmap),,Nenio (linia mipmapo),Ninguno (mipmap lineal),,Ei mitään (lin. mipkartta),Aucun (mipmap linéaire),Semmilyen (lineáris mipmap),Nessuno (mipmap lineare),なし(リニアミップマップ),없음 (선형 밉맵),Geen (lineaire mipmap),Ingen (lineær mipmap),Brak (liniowa mipmapa),Nenhum (mipmap linear),,Niciuna (mipmap liniar),Нет (линейный MIP-уровень),Ништа (линеаран мипмап),Ingen (linjär mipmap),Yok (doğrusal mipmap),Відсутня (лінійний міпмап), +None (trilinear),OPTVAL_NONETRILINEAR,,,,Žádné (trilineární),Ingen (trilineær),Aus (trilinear),,Nenio (trilinia),Ninguno (trilineal),,Ei mitään (trilineaarinen),Aucun (mipmap trilinéaire),Semmilyen (trilineáris),Nessuno (mipmap trilineare),なし(トライリニア),없음 (삼선형),Geen (trilineair),Ingen (trilineær),Brak (trzyliniowe),Nenhum (trilinear),,Niciuna (trilinar),Нет (трилинейная),Ништа (трилинеарно),Ingen (trilinjär),Yok (trilineer),Відсутня (трилінійна), +Bilinear,OPTVAL_BILINEAR,,,,Bilineární,Bilineær,,,Dulinia,Bilineal,,Bilineaarinen,Bilinéaire,Bilineáris,Bilineare,バイリニア,쌍선형,Bilineair,Bilineær,Dwuliniowe,,,Biliniar,Билинейная,Билинеарно,Bilinjär,Bilineer,Білінійна, +Trilinear,OPTVAL_TRILINEAR,,,,Trilineární,Trilineær,,,Trilinia,Trilineal,,Trilineaarinen,Trilinéaire,Trilineáris,Trilineare,トライリニア,삼선형,Trilineair,Trilineær,Trzyliniowe,,,Triliniar,Трилинейная,Трилинеарно,Trilinjär,Trilineer,Трилінійна, +2x,OPTVAL_2X,,,,,,,,2-oble,,,,,,,,,,,,,,,,,,,, +4x,OPTVAL_4X,,,,,,,,4-oble,,,,,,,,,,,,,,,,,,,, +8x,OPTVAL_8X,,,,,,,,8-oble,,,,,,,,,,,,,,,,,,,, +16x,OPTVAL_16X,,,,,,,,16-oble,,,,,,,,,,,,,,,,,,,, +32x,OPTVAL_32X,,,,,,,,32-oble,,,,,,,,,,,,,,,,,,,, +Texture Options,GLTEXMNU_TITLE,,,,Nastavení textur,Indstillinger for teksturer,Texturoptionen,,Agordoj de Teksturoj,Opciones de texturas,,Pintakuviointiasetukset,Options Textures,Textúra Beállítások,Opzioni Texture,テクスチャー オプション,텍스쳐 설정,Textuur Opties,Teksturalternativer,Opcje Tekstur,Opções de Textura,,Setări Texturi,Настройки текстур,Подешавања текстура,Alternativ för textur,Doku Seçenekleri,Параметри текстур, +Textures enabled,GLTEXMNU_TEXENABLED,,,,Povolit textury,Teksturer aktiveret,Texturen an,,Teksturoj ŝaltitaj,Texturas activadas,,Pintakuvioinnit otettu käyttöön,Textures activées,Textúrák bekapcsolása,Texture abilitate,テクスチャー有効,텍스쳐 사용,Texturen ingeschakeld,Teksturer aktivert,Tekstury włączone,Texturas ativadas,,Texturi Activate,Включить текстуры,Текстуре омогућене,Texturer aktiverade,Dokular etkinleştirildi,Увімкнути текстури, +Enable hires textures,GLTEXMNU_ENABLEHIRES,,,,Povolit textury ve vysokém rozlišení,Aktivere hi-res teksturer,Hochauflösende Texturen an,,Ŝalti Altdistingivajn Teksturojn,Activar texturas de alta resolución,,Salli korkean erotuskyvyn pintakuvioinnit,Activer Textures haute résolution,Magas felbontású textúrák bekapcsolása,Abilita texture alta qualità,ハイレゾ テクスチャー有効,고해상도 텍스쳐 사용,Hoge-resolutie texturen op,Aktivere høyoppløselige teksturer,Włącz tekstury wysokiej jakości,Habilitar texturas de alta resolução,,Texturi de înaltă rezoluție,Текстуры высокого разрешения,Омогући текстуре велике резолуције,Aktivera texturer med högre upplösning,Yüksek çözünürlüklü dokuları etkinleştir,Увімкнути текстури високого розширення, +High Quality Resize mode,GLTEXMNU_HQRESIZE,,,,Režim zvětšovače textur,Tilstand til ændring af størrelse i høj kvalitet,Texturskalierungsmodus,,Reĝimo de Altdistingivigo-Skalilo,Modo de ajuste de alta calidad,,Korkealaatuinen kuvakoon muutostapa,Mise à l'échelle haute résolution,Magas minőségű újraméretező mód,Modalità resize alta qualità,高品質リサイズ モード,고퀄리티 리사이즈 모드,Textuurschaalmodus,Høy kvalitet Endre størrelse-modus,Tryb Wysokiej Jakości Zmieniania Rozmiaru,Modo de Redimensionamento de Alta Qualidade,,Mod Redimensionare de Înaltă Calitate,Режим высококачественного масштабирования текстур,Промена величине високог квалитета мод,Högkvalitativt storleksanpassningsläge,Yüksek Kalite Yeniden Boyutlandırma modu,Масштабування текстур, +High Quality Resize multiplier,GLTEXMNU_HQRESIZEMULT,,,,Faktor zvětšovače textur,Multiplikator for ændring af størrelse i høj kvalitet,Texturskaluerungsfaktor,,Obligilo de Altdistingivigo-Skalilo,Multiplicador de ajuste de alta calidad,,Korkealaatuisen kuvakokomuutoksen kerroin,Multiplicateur de mise à l'échelle,Magas minőségű újraméretezés szorzó,Moltiplicatore resize alta qualità,高品質リサイズ乗数,고퀄리티 리사이징 승수,Textuurschaalfactor,Multiplikator for størrelsesendring av høy kvalitet,Mnożnik Wysokiej Jakośći Rozmiaru,Multiplicador de Redimensionamento de Alta Qualidade,,Factor de Scalare,Множитель высококачественного масштабирования,Промена величине високог квалитета мултипликатор,Multiplikator för storleksändring av hög kvalitet,Yüksek Kalite Yeniden Boyutlandırma çarpanı,Множник масштабування, +This mode requires %d times more video memory,GLTEXMNU_HQRESIZEWARN,,,,Tento režim potřebuje %dkrát více paměti,Denne tilstand kræver %d gange mere videohukommelse,Dieser Modus benötigt das %d-fache an Videospeicher,Αυτή η λειτουργία χρειάζετε %d περισσότερες φορές μνήμη βίντεο,Ĉi tiu reĝimo bezonas %d-oble pli da ekranmemoro.,Este modo requiere %d veces más memoria de vídeo,,Tämä tila vaatii %d kertaa enemmän videomuistia,Ce mode nécessite %d fois plus de mémoire vidéo,Ez a mód a jelenlegi videó memória %d-szeresét igényli,Questa modalità richiede %d volte la memoria video,このモードでは %d 倍以上のビデオメモリが必要です!,이 설정은 비디오 메모리의 %d 배가 더 필요합니다.,Deze modus vereist %d keer meer videogeheugen.,Denne modusen krever %d ganger mer videominne,Ten tryb wymaga %d razy więcej pamięci wideo,Este modo precisa de %d vezes mais memória de vídeo,,Acest mod necesită de %d mai multă memorie video,Данный режим требует в %d раз больше видеопамяти,Овај мод тражи %d пута више видео меморије,Det här läget kräver %d gånger mer videominne,Bu mod %d kat daha fazla video belleği gerektirir,Цьому типу потрібно в %d рази більше відеопам'яті, +Resize textures,GLTEXMNU_RESIZETEX,,,,Škálovat textury,Ændre størrelse på teksturer,Texturen skalieren,,Regrandigi teksturojn,Ajustar texturas,,Muuta pintakuviointien kokoa,Mise à l'échelle textures,Textúrák újraméretezése,Resize delle texture,テクスチャー類のリサイズ,텍스쳐 리사이징,Texturen schalen,Endre størrelse på teksturer,Zmień rozmiar tekstur,Redimensionar texturas,,Redimensionare texturi,Масштабирование текстур,Промена величине текстура,Ändra storlek på texturer,Dokuları yeniden boyutlandırma,Масштабувати текстури, +Resize sprites,GLTEXMNU_RESIZESPR,,,,Škálovat sprity,Ændre størrelse på sprites,Sprites skalieren,,Regrandigi mov-rastrumojn,Ajustar sprites,,Muuta spritejen kokoa,Mise à l'échelle sprites,Sprite-ok újraméretezése,Resize degli sprite,スプライト類のリサイズ,스프라이트 리사이징,Sprites schalen,Endre størrelse på sprites,Zmień rozmiar sprite'ów,Redimensionar sprites,,Redimensionare sprite-uri,Масштабирование спрайтов,Промена величине спрајтова,Ändra storlek på sprites,Sprite'ları yeniden boyutlandırma,Масштабувати спрайти, +Resize fonts,GLTEXMNU_RESIZEFNT,,,,Škálovat fonty,Ændre størrelse på skrifttyper,Zeichensätze skalieren,,Regrandigi tiparojn,Ajustar fuentes,,Muuta kirjasinten kokoa,Mise à l'échelle texte,Betűk újraméretezése,Resize dei font,フォント類のリサイズ,폰트 리사이징,Lettertypen schalen,Endre størrelse på skrifter,Zmień rozmiar czcionek,Redimensionar fontes,,Redimensionare fonturi,Масштабирование шрифтов,Промена величине фонта,Ändra storlek på teckensnitt,Yazı tiplerini yeniden boyutlandırma,Масштабувати шрифти, +Resize model skins,GLTEXMNU_RESIZESKN,,,,Škálovat skiny modelů,Ændre størrelsen på modelskins,,,Regrandigi haŭtojn de modeloj,Ajustar texturas de modelo,,Muuta ulkoasujen kokoa,Mise à l'échelle des skins des modèles 3D,Model fazon újraméretezése,Ridimensiona skin modello,モデルスキン類のリサイズ,,,Endre størrelse på modellskinn,Zmień rozmiar modelu,Redimensionar skins de modelos,,Redimensionare modele,Масштабирование обликов моделей,,Ändra storlek på modellskinn,Model kaplamalarını yeniden boyutlandırma,Масштабувати текстури моделей, +Precache GL textures,GLTEXMNU_PRECACHETEX,,,,Přednačíst GL textury do cache,Precache GL-teksturer,GL Texturen zwischenspeichern,,Antaŭkaŝmemorigi GL-teksturojn,Precaché de texturas GL,,Kirjoita GL-pintakuvioinnit välimuistiin,Mise en cache des textures,Előcachelt GL textúrák,Precache texture GL,プリキャッシュGLテクスチャー,지엘 텍스쳐 미리 캐싱함,Precache GL texturen,Precache GL-teksturer,Tekstury GL pamięci podręcznej,Precachê de texturas GL,,Preîncărcarcă texturile GL,Кэшировать GL-текстуры,Прикеширане GL текстуре,Precache GL-texturer,GL dokularını önceden önbelleğe alma,Кешувати GL-текстури, +Video Mode,VIDMNU_TITLE,,,,Režim displeje,Videotilstand,Videomodus,Λειτουργία βίντεο,Video-reĝimo,Modos de vídeo,Modos de video,Videotila,Mode Vidéo,Videó mód,Modalità video,ビデオ調整,화면 설정,Videomodus,Videomodus,Tryb Wideo,Modo de vídeo,,Mod Video,Настройки видеорежима,Видео мод,Videoläge,Video Modu,Налаштування відеорежиму, +Scaled (Nearest),OPTVAL_SCALENEAREST,,,,Škálován (nejbližší),Skaleret (Nærmeste),Skaliert (nächster Nachbar),,Skalita (Plej proksime),Escalado (Lo más cerca),,Skaalattu (läheisin),Mis à l'échelle (Proche Voisin),Átméretezett (Közeli),Scalato (più vicino),スケーリング (最寄り),확대 (가깝게),Geschaald (Dichtstbijzijnd),Skalert (nærmeste),Przeskalowany (Najbliższy),Redimensionado (mais próximo),Redimensionado (Apróximado),Redimensionat (Cel mai aproape),Масштабировать (ближайшее),Скалиран (најближи),Skalad (närmast),Ölçeklendirilmiş (En Yakın),Збільшення (ближнє), +Scaled (Linear),OPTVAL_SCALELINEAR,,,,Škálován (lineární),Skaleret (lineær),Skaliert(linear),,Skalita (Linie),Escalado (Lineal),,Skaalattu (lineaarinen),Mis à l'échelle (Linéaire),Átméretezett (Lineáris),Scalato (lineare),スケーリング (リニア),확대 (선형 식),Geschaald (Lineair),Skalert (lineær),Przeskalowany (Liniowy),Redimensionado (linear),,Redimensionat (Liniar),Масштабировать (линейное),Скалиран (линеарно),Skalad (linjär),Ölçeklendirilmiş (Doğrusal),Збільшення (лінійне), +Letterbox,OPTVAL_LETTERBOX,,,,,,,,Leterkesto,Barras negras,,Mustat reunat,,Levágott,Bande nere,レターボックス,레터박스,,,,Barras pretas,,Ecran Parțial,Экранное каше,Поштанско сандуче,Brevlåda,,Техніка каше, +Stretch,OPTVAL_STRETCH,,,,Roztažený,Stræk,Strecken,,Streĉi,Estrechado,Estrecho,Venytetty,Etirer,Nyújtott,Disteso,伸縮,늘림,Rek,Strekk,Rozciągnięty,Esticado,,Lărgire,Растянутый,Растегнуто,Sträcka,Esneme,Розтягнутий, +Render Mode,VIDMNU_RENDERMODE,,,,Režim rendereru,Rendertilstand,Rendermodus,,Bildigo-reĝimo,Modo de renderizado,,Hahmonnustila,Mode de Rendu,Render Mód,Modalità rendering,レンダラー,렌더링 설정,Rendermodus,Gjengivelsesmodus,Tryb Renderowania,Modo de renderização,,Mod Video,Режим обработки,Рендер мод,Renderläge,İşleme Modu,Режим візуалізації, +Fullscreen,VIDMNU_FULLSCREEN,,,,Přes celou obrazovku,Fuld skærm,Vollbild,Πλήρης οθόνη,Plena ekrano,Pantalla completa,,Koko näyttö,Plein écran,Teljes Képernyő,Schermata piena,全画面,전체화면,Volledig scherm,Fullskjerm,Pełen Ekran,Tela cheia,Ecrã cheio,Ecran Complet,Полный экран,Цео екран,Fullskärm,Tam Ekran,Повноекранний, +Retina/HiDPI support,VIDMNU_HIDPI,,,,Podpora Retiny/HiDPI,Retina/HiDPI-understøttelse,Retina/HDPI-Unterstützung,,Retino/HiDPI subteno,Soporte para Retina/HiDPI,,Retina/HiDPI-tuki,Support Retina/HiDPI ,Retina/HiDPI támogatás,Supporto Retina/HiDPi,Retina/HiDPI サポート,망막/하이DPI 활성화,Retina / HiDPI-ondersteuning,Retina/HiDPI-støtte,Wsparcie Retina/HiDPI,Suporte para Retina/HiDPI,,Suport Retina/HiDPI,Поддержка Retina/HiDPI,Retina/HiDPI подршка,Retina/HiDPI-stöd,Retina/HiDPI desteği,Підтримка Retina/HiDPI, +Aspect ratio,VIDMNU_ASPECTRATIO,,,,Poměr stran,Aspektforhold,Seitenverhältnis,,Ekran-proporcio,Relación de aspecto,,Kuvasuhde,Rapport D'Aspect,Képarány,Proporzioni,アスペクト比,종횡비,Beeldverhouding,Bildeforhold,Wpółczynnik proporcji,Proporção de tela,Proporção de ecrã,Aspect Imagine,Соотношение сторон,Однос гледишта,Bildförhållande,En boy oranı,Співвідношення сторін, +Force aspect ratio,VIDMNU_FORCEASPECT,,,,Vynutit poměr stran,Tvinge formatforhold,Erzwinge Seitenverhältnis,,Devigi ekran-proporcion,Forzar relación de aspecto,,Pakota kuvasuhde,Forcer Rapport,Képarány kényszerítése,Forza le proporzioni video,アスペクト比に従う,강제 종횡비,Geforceerde beeldverhouding,Tving sideforhold,Wymuś współczynnik proporcji,Forçar proporção de tela,Forçar proporcção de ecrã,Forțează aspectul imaginii,Принудительное соотношение сторон,Присили однос гледишта,Forcerat bildförhållande,Kuvvet en-boy oranı,Примусове співвідношення сторін, +Forced ratio style,VIDMNU_CROPASPECT,,,,Vynucený poměr stran,Stil med tvunget forhold,Modus für erzwungenes Seitenverhältnis,,Stilo por devigita proporcio,Relación de aspecto forzada,,Kuvasuhteen pakotustapa,Style de Ratio forcé,Kényszerített képarány stílusa,Forza lo stile delle proporzioni,比率の形式,강제 비율 스타일,Geforceerde verhoudingsstijl,Tvunget formatforhold-stil,Wymuszony styl współczynnika,Estilo de proporção forçado,,Forțează tipul proporțiilor,Тип принудительного соотношения сторон,Присиљен стил односа,Stil för tvingat förhållande,Zorlanmış oran stili,Тип примусового співвідношення сторін, +Enable 5:4 aspect ratio,VIDMNU_5X4ASPECTRATIO,,,,Povolit poměr stran 5:4,Aktiver 5:4-billedformat,Erlaube 5:4 Seitenverhältnis,,Ŝalti 5:4 ekran-proporcion,Activar relación de aspecto 5:4,,Ota käyttöön 5:4-kuvasuhde,Activer Rapport 5:4,5:4 képarány engedélyezése,Abilita le proporzioni 5:4,5:4アスペクト比を可能にする,5:4 비율 사용,Schakel 5:4 beeldverhouding in,Aktiver 5:4 sideforhold,Włącz współczynnik proporcji 5:4,Ativar proporção de tela 5:4,,Activează formatul 5:4,Включить соотношение сторон 5:4,Омогући 5:4 однос гледишта,Aktivera bildförhållandet 5:4,5:4 en boy oranını etkinleştirin,Увімкнути співвідношення сторін 5:4, +Resolution scale,VIDMNU_SCALEMODE,,,,Škálování rozlišení,Opløsningsskala,Skalierung,,Distingivo-skalo,Escala de resolución,,Resoluution skaalaus,Echelle de Résolution,Felbontás mérete,Scala di risoluzione,画面スケール,해상도 크기,Resolutieschaal,Oppløsningsskala,Skala rozdzielczości,Escala de resolução,,Scară rezoluție,Масштабирование,Резолуцијска скала,Upplösningsskala,Çözünürlük ölçeği,Масштабування, +Scale Factor,VIDMNU_SCALEFACTOR,,,,Faktor rozlišení,Skalafaktor,Skalierungsfaktor,,Skalfaktoro,Factor de escala,,Skaalauskerroin,Facteur d'échelle,Méretezési Faktor,Fattore di scala,スケール倍率,축척 펙터,Schaalfactor,Skaleringsfaktor,Współczynnik Skali,Fator de escala,,Factor Scalare,Значение масштаба,Фактор скалирања,Skalfaktor,Ölçek Faktörü,Значення масштабування, +Use Linear Scaling (Fullscreen),VIDMNU_USELINEAR,,,,Použít lineární škálování (přes celou obrazovku),Brug lineær skalering (fuld skærm),Lineare Skalierung (Vollbild),,Uzi linian skaladon (Plenekrane),Usar escalado linear (Pant. completa),,Lineaarinen skaalaus (koko näyttö),Mise à l'échelle Linéaire (Plein écran),Lineáris Méretezés Használata (Teljes képernyő),Usa lo scaling lineare (a schermo pieno),リニアスケールを使う(全画面),선형 스케일링 사용 (전체화면),Lineaire schaalverdeling gebruiken (volledig scherm),Bruk lineær skalering (fullskjerm),Użyj Liniowego Skalowania (Pełen Ekran),Usar escala linear (tela cheia),Usar escala linear (ecrã cheio),Folosește Scalarea Liniară (Ecran Complet),Линейное масштабирование (полный экран),Користи линеарно скалирање (цео екран),Använd linjär skalning (helskärm),Doğrusal Ölçeklemeyi Kullan (Tam Ekran),Лінійне масштабування (повний екран), +Custom Pixel Scaling,VIDMNU_CUSTOMRES,,,,Vlastní škálování pixelů,Brugerdefineret pixelskalering,Benutzerdefinierte Skalierung,,Adaptita rastrumero-skalo,Escalado de píxel personalizado,,Mukautettu skaalaus,Résolution Personalisée,Egyéni Pixelméretezés,Scaling dei pixel personalizzato,カスタム ピクセルスケール,사용자 지정 픽셀 크기 조정,Aangepaste pixelschaalvergroting,Egendefinert pikselskalering,Niestandardowe Skalowanie Pikseli,Escala de pixels personalizada,,Scară Pixeli Personalizată,Масштабирование пикселей,Пиксел скалирање,Anpassad pixelskalning,Özel Piksel Ölçeklendirme,Масштабування пікселів, +Custom Width,VIDMNU_CUSTOMX,,,,Vlastní šířka,Brugerdefineret bredde,Benutzerdefinierte Breite,,Adaptita larĝeco,Ancho personalizado,,Mukautettu leveys,Largeur Personalisée,Egyéni szélesség,Lunghezza,カスタム 幅,사용자 지정 너비,Aangepaste breedte,Egendefinert bredde,Niestandardowa Szerokość,Largura personalizada,,Lățime Personalizată,Длина,Ширина,Anpassad bredd,Özel Genişlik,Довжина, +Custom Height,VIDMNU_CUSTOMY,,,,Vlastní výška,Brugerdefineret højde,Benutzerdefinierte Höhe,,Adaptita alteco,Alto personalizado,,Mukautettu korkeus,Hauteur Personalisée,Egyéni magasság,Altezza,カスタム 高さ,사용자 지정 높이,Aangepaste hoogte,Egendefinert høyde,Niestandardowa Wysokość,Altura personalizada,,Înălțime Personalizată,Высота,Висина,Anpassad höjd,Özel Yükseklik,Висота, +Apply Changes (Windowed),VIDMNU_APPLYW,,,,Použít změny (v okně),Anvend ændringer (vindue),Änderungen anwenden (Fenster),,Apliki ŝanĝojn (Fenestrite),Aplicar cambios (Ventana),,Ota käyttöön muutokset (ikkuna),Appliquer Changements (Fenêtre),Változtatások Elfogadása (Ablak),Applica le modifiche (a finestra),変更を適用(ウィンドウ化),변경 적용 (윈도우),Wijzigingen toepassen (in venster),Bruk endringer (vindusbasert),Zatwierdź Zmiany (Okno),Aplicar alterações (janela),,Aplică Schimbările (Mod Fereastră),Сохранить изменения (оконный режим),Примени промене (прозор),Tillämpa ändringarna (fönsterskärm),Değişiklikleri Uygula (Pencereli),Зберегти зміни (віконний режим), +Apply Changes (Fullscreen),VIDMNU_APPLYFS,,,,Použít změny (přes celou obrazovku),Anvend ændringer (fuld skærm),Änderungen anwenden (Vollbild),,Apliki ŝanĝojn (Plenekrane),Aplicar cambios (Pant. completa),,Ota käyttöön muutokset (koko näyttö),Appliquer Changements (Plein écran),Változtatások Elfogadása (Teljes képernyő),Applica le modifiche (a schermo pieno),変更を適用(全画面化),변경 적용 (전체화면),Wijzigingen toepassen (Volledig scherm),Bruk endringer (fullskjerm),Zatwierdź Zmiany (Pełen Ekran),Aplicar alterações (tela cheia),Aplicar alterações (ecrã cheio),Aplică Schimbările (Mod Ecran Complet),Сохранить изменения (полный экран),Примени промене (цели екран),Tillämpa ändringar (helskärm),Değişiklikleri Uygula (Tam Ekran),Зберегти зміни (повноекранний режим), +Choose Resolution Preset,VIDMNU_RESPRESET,,,,Vybrat přednastavené rozlišení,Vælg forindstillet opløsning,Auflösungsvoreinstellung,,Elekti antaŭagorditan distingivon,Elegir resolución predefinida,,Valitse ennalta määritetty resoluutio,Choisir paramètre personalisé,Felbontási Sablon Kiválasztása,Scegli preset di risoluzione,解像度プリセットを選ぶ,해상도 사전 설정 선택,Kies een vooraf ingestelde resolutie,Velg forhåndsinnstilt oppløsning,Wybierz Zestaw Rozdzielczości,Escolher resolução predefinida,,Alege Rezoluția Predefinită,Выбор шаблона разрешения,Резолуцијска подешавања,Välj förinställning för upplösning,Çözünürlük Ön Ayarını Seçin,Вибір пресету роздільної здатності, +Custom Resolution Presets,VIDMNU_RESPRESETTTL,,,,Vlastní přednastavení rozlišení,Brugerdefinerede opløsningsforudindstillinger,Benutzerdefinierte Auflösungsvoreinstellungen,,Viaj antaŭagorditaj distingivoj,Resoluciones predefinidas personalizadas,,Ennalta määritetyt mukautetut resoluutiot,Résolutions Personalisée,Egyéni Felbontási Sablonok,Preset di risoluzione personalizzati,カスタム解像度プリセット,사용자 지정 해상도 미리 조정,Vooraf ingestelde aangepaste resoluties,Egendefinerte forhåndsinnstillinger for oppløsning,Niestandardowe Zestawy Rozdzielczości,Predefinições de resolução personalizadas,,Rezoluții Personalizate,Пользовательские шаблоны,Резолуцијска подешавања,Anpassade förinställningar för upplösning,Özel Çözünürlük Ön Ayarları,Користувацькі пресети, +Preset Resolution Modes,VIDMNU_RESPRESETHEAD,,,,Přednastavená rozlišení,Forindstillede opløsningsmodes,Vordefinierte Auflösungsmodi,,Reĝimoj pri antaŭagordita distingivo,Modos de resolución predefinida,,Ennalta määritetyt resoluutiotilat,Choisir mode de Résolution,Felbontási Sablon Módok,Modalità preset di risoluzione,解像度モードの調整,해상도 미리 조정 모드,Vooraf ingestelde resolutiemodi,Forhåndsinnstilte oppløsningsmoduser,Tryby Zestawów Rozdzielczości,Modos de resolução predefinidas,,Rezoluții Predefinite,Доступные разрешения,Постављени резолуцијски модови,Förinställda upplösningslägen,Önceden Ayarlanmış Çözünürlük Modları,Доступні роздільні здатності, +4:3 Aspect,VIDMNU_ASPECT43,,,,Poměr stran 4:3,4:3 Aspekt,4:3 Seitenverhältnis,,4:3 proporcio,Aspecto 4:3,,4:3-tilat,Rapport 4:3,4:3 Arány,Aspetto 4:3,アスペクト比 4:3,4:3 비율,Beeldverhouding 4:3,4:3 Aspekt,Proporcje 4:3,Proporção 4:3,,Aspect 4:3,Соотношение сторон 4:3,4:3 гледиште,4:3 aspekt,4:3 Görüntü,Співвідношення сторін 4:3, +5:4 Aspect,VIDMNU_ASPECT54,,,,Poměr stran 5:4,5:4 Aspekt,5:4 Seitenverhältnis,,5:4 proporcio,Aspecto 5:4,,5:4-tilat,Rapport 5:4,5:4 Arány,Aspetto 5:4,アスペクト比 5:4,5:4 비율,Beeldverhouding 5:4,5:4 Aspekt,Proporcje 5:4,Proporção 5:4,,Aspect 5:4,Соотношение сторон 5:4,5:4 гледиште,5:4 Aspekt,5:4 Görüntü,Співвідношення сторін 5:4, +16:9 Aspect,VIDMNU_ASPECT169,,,,Poměr stran 16:9,16:9 Aspekt,16:9 Seitenverhältnis,,16:9 proporcio,Aspecto 16:9,,16:9-tilat,Rapport 16:9,16:9 Arány,Aspetto 16:9,アスペクト比 16:9,16:9 비율,Beeldverhouding 16:9,16:9 Aspekt,Proporcje 16:9,Proporção 16:9,,Aspect 16:9,Соотношение сторон 16:9,16:9 гледиште,16:9 aspekt,16:9 Görüntü,Співвідношення сторін 16:9, +16:10 Aspect,VIDMNU_ASPECT1610,,,,Poměr stran 16:10,16:10 Aspekt,16.10 Seitenverhältnis,,16:10 proporcio,Aspecto 16:10,,16:10-tilat,Rapport 16:10,16:10 Arány,Aspetto 16:10,アスペクト比 16:10,16:10 비율,Beeldverhouding 16:10,16:10 Aspekt,Proporcje 16:10,Proporção 16:10,,Aspect 16:10,Соотношение сторон 16:10,16:10 гледиште,16:10 aspekt,16:10 Aspect,Співвідношення сторін 16:10, +21:9 Aspect,VIDMNU_ASPECT219,,,,Poměr stran 21:9,21:9 Aspekt,21.9 Seitenverhältnis,,21:9 proporcio,Aspecto 21:9,,21:9-tilat,Rapport 21:9,21:9 Arány,Aspetto 21:9,アスペクト比 21:9,21:9 비율,Beeldverhouding 21:9,21:9 Aspekt,Proporcje 21:9,Proporção 21:9,,Aspect 21:9,Соотношение сторон 21:9,21:9 гледиште,21:9 Aspekt,21:9 Görüntü,Співвідношення сторін 21:9, +Normal,OPTVAL_NORMAL,,,,Normální,,,,Normala,,,Normaali,,Normál,Normale,通常,기본형,Normaal,,Normalny,,,,Обычный,Нормално,Normal,,Нормальний, +Lowest Possible Scale,OPTVAL_LOWEST,"This describes vid_scalemode 1, which represents the lowest possible scaling to fill the allocated screen area",,,Nejmenší možná velikost,Lavest mulige skala,Kleinstmögliche Auflösung,,Plej malalta ebla skalo,Menor escala posible,,Pienin mahdollinen skaalaus,Echelle la plus faible,Lehető legkisebb méret,Scala minima,可能な限り最小,,Laagst mogelijk schaal,Lavest mulig skala,Najniższa możliwa skala,Menor escala possível,,Cea mai Mică Scară Posibilă,Наименьший возможный масштаб,,Lägsta möjliga skala,Mümkün Olan En Düşük Ölçek,Найменш можливий масштаб, +Custom,OPTVAL_CUSTOM,,,,Vlastní,Brugerdefineret,Benutzerdefiniert,,Agordita de vi,Personalizado,,Mukautettu,Modifié,Egyéni,Personalizzato,カスタム,사용자 지정,Gebruikergedefinieerd,Egendefinert,Niestandardowe,Personalizado,,Personalizat,Польз.,Прилагођ.,Anpassad,Özel,Корист., +Max FPS,VIDMNU_MAXFPS,,,,Maximální FPS,,,,Maksimumaj kadroj laŭ sekundo,Límite de FPS,,Kuvataajuuden rajoitin,,,FPS Massimi,最大FPS値,,,Maks FPS,Maksymalna ilość klatek,FPS máximo,,Cadre pe secundă,Максимальная частота кадров,,,Maksimum FPS,Макс. частота кадрів, +60 fps,OPTVAL_60FPS,,,,,,,,,,,60 kuvaa/s,,,,,,,,,60 FPS,,,60 к/с,,,,60 кадрів, +75 fps,OPTVAL_75FPS,,,,,,,,,,,75 kuvaa/s,,,,,,,,,75 FPS,,,75 к/с,,,,75 кадрів, +90 fps,OPTVAL_90FPS,,,,,,,,,,,90 kuvaa/s,,,,,,,,,90 FPS,,,90 к/с,,,,90 кадрів, +120 fps,OPTVAL_120FPS,,,,,,,,,,,120 kuvaa/s,,,,,,,,,120 FPS,,,120 к/с,,,,120 кадрів, +144 fps,OPTVAL_144FPS,,,,,,,,,,,144 kuvaa/s,,,,,,,,,144 FPS,,,144 к/с,,,,144 кадри, +200 fps,OPTVAL_200FPS,,,,,,,,,,,200 kuvaa/s,,,,,,,,,200 FPS,,,200 к/с,,,,200 кадрів, +Preferred Rendering API,VIDMNU_PREFERBACKEND,,,,Upřednostňované renderovací API,Foretrukken Rendering API,Bevorzugtes Render API,Προτιμούμενο Rendering API,Preferita bildigado de API,API de renderizado preferida,,Ensisijainen hahmonnuksen ohjelmointirajapinta,API de rendu préférée,Előnyben részesített renderelő API,API di rendering preferita,優先レンダリングAPI,기본적인 API 랜더링,Voorkeur rendering API,Foretrukket Rendering API,Preferowany interfejs API renderowania,API de renderização preferida,,API Video Preferat,Предпочтительный API обработки,Преферред АПИ приказивања,Företrädesvis API för rendering,Tercih Edilen Rendering API,Бажаний інтерфейс візуалізації, +OpenGL,OPTVAL_OPENGL,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Vulkan,OPTVAL_VULKAN,,,,,,,,,,,,,,,,,,,,,,,,,,,, +OpenGL ES,OPTVAL_OPENGLES,Rendering backend,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,Miscellaneous Options,,,,,,,,,,,,,,,,,,,,,,,,,,, +Merge left+right Alt/Ctrl/Shift,MISCMNU_MERGEKEYS,,,,Kombinovat pravý a levý Alt/Ctrl/Shift,Flette venstre+højre Alt/Ctrl/Shift,Linke und rechte Umschalt/Strg/Alt zusammenfassen,,Kunigi maldekstran kaj dekstran Alt/Ctrl/Shift,Combinar Alt/Ctrl/Mayús izq. y der.,Combinar Alt/Ctrl/Shift izq. y der.,Yhdistä vasen ja oikea Alt/Ctrl/Vaihto,Combiner Alt/Ctrl/maj gauche & droite,Bal és jobb Ctrl/Alt/Shift egyként érzékelése,Unisci sinistra+destra Alt/Control/Maiusc,左と右のALT/CTRL/SHIFTキーを統合,양쪽 ALT/CTRL/SHIFT키 합병,Samenvoegen links+rechts Alt/Ctrl/Shift,Slå sammen venstre+høyre Alt/Ctrl/Shift,Połącz przyciski lewo+prawo Alt/Ctrl/Shift,"Unir as teclas Alt, Ctrl e Shift esquerdos e direitos",Juntar Alt/Ctrl/Shift esquerdo+direito,Combină Alt/Ctrl/Shift stâng+drept,Не различать левую/правую ALT/CTRL/SHIFT,Споји лево+десно Аlt/Ctrl/Shift,Sammanfoga vänster+höger Alt/Ctrl/Shift,Sol+sağ birleştirme Alt/Ctrl/Shift,Не розділяти лівий/правий ALT/CTRL/SHIFT, +Alt-Enter toggles fullscreen,MISCMNU_WINFULLSCREENTOGGLE,,,,Alt-Enter přepíná celou obrazovku,Alt-Enter skifter til fuld skærm,Alt-Enter schaltet Vollbild an/aus,,Alt+Enter baskuligas tutekranan reĝimon,Alt+Enter alterna pantalla completa,,Alt-Enter kytkee täyden ruudun päälle/pois,Alt-Entrée alterne plein écran,Alt-Enter teljes képernyőre kapcsol,Alt-Invio attiva/disattiva lo schermo pieno,ALTとENTERで全画面に切り替え,ALT+ENTER키로 전체화면 조정,Alt-Enter schakelt het volledige scherm aan/uit,Alt-Enter veksler til fullskjerm,Alt-Enter przełącza na pełen ekran,Alt+Enter ativa tela cheia,Alt-Enter ativa ecrã cheio,Alt-Enter comută modul ecran complet,Переключение полного экрана по ALT+ENTER,Alt-Enter пребацује на цео екран,Alt-Enter växlar till fullskärm,Alt-Enter tam ekrana geçiş yapar,Перемикання повного екрану на ALT+ENTER, +Command-F toggles fullscreen,MISCMNU_MACFULLSCREENTOGGLE,,,,Command-F přepíná celou obrazovku,Command-F skifter til fuld skærm,Cmd-F schaltet Vollbild an/aus,,Komando-F baskuligas tutekranan reĝimon,Cmd-F alterna pantalla completa,,Komento-F kytkee täyden ruudun päälle/pois,Command-F alterne plein écran,Command-F teljes képernyőre kapcsol,Command-F attiva/disattiva lo schermo pieno,Ctrl + Fキーで全画面表示,COMMAND+F키로 전체화면 조정,Command-F schakelt het volledige scherm aan/uit,Kommando-F veksler til fullskjerm,Command-F przełącza pełny ekran,Command+F ativa tela cheia,Command-F ativa ecrã cheio,Command-F comută modul ecran complet,Переключение полного экрана по Cmd+F,Command-F пребацује на цео екран,Command-F växlar till fullskärm,Command-F tam ekrana geçiş yapar,Перемикання повного екрану на Command+F, +Enable autosaves,MISCMNU_ENABLEAUTOSAVES,,,,Povolit automatické ukládání,Aktiver autosaves,Automatisches Speichern,,Ŝalti aŭtomatajn konservojn de ludadoj,Activar autoguardado,,Ota käyttöön automaattiset tallennukset,Activer Sauvegardes auto,Automentések engedélyezése,Abilita i salvataggi automatici,オートセーブを有効化,빠른 저장 허용,Automatisch opslaan inschakelen,Aktiver automatisk lagring,Włącz autozapis,Ativar salvamento automático,Permitir gravação automática,Permite salvări automate,Автосохранения,Омогући аутосејвове,Aktivera autosparande,Otomatik kaydetmeyi etkinleştir,Автозбереження, +Number of autosaves,MISCMNU_AUTOSAVECOUNT,,,,Počet automaticky uložených her,Antal autosaves,Anzahl von automatischen Speicherständen,,Maksimuma kvanto da aŭtomataj konservoj,Cantidad máxima de autoguardados,,Automaattisten tallennusten lukumäärä,Total de sauvegardes auto,Automentések száma,Numero di salvataggi automatici,オートセーブの最大数,빠른 저장 수,Aantal auto-opslagen,Antall autolagringer,Liczba autozapisów,Número de salvamentos automáticos,Número de gravações automáticas,Număr salvări automate,Количество автосохранений,Број аутоматских чувања,Antal autosparande,Otomatik kaydetme sayısı,Кількість автозбрежень, +Save/Load confirmation,MISCMNU_SAVELOADCONFIRMATION,,,,Potvrzení o uložení/načtení,Bekræftelse af gem/indlæsning,Laden/Speichern bestätigen,,Konfirmo de konservo/ŝargo,Confirmación al guardar/cargar,,Tallennuksen/Latauksen vahvistus,Confirmation C/S,Mentés/betöltés megerősítése,Conferma Salvataggio/Caricamento,セーブ/ロード時に確認,스크립트로 스크린샷 생성 허용,Opslaan/Laad bevestiging,Bekreftelse for lagring/innlasting,Potwierdzenie zapisu/wczytania,Confirmação ao salvar/carregar,Confirmação ao gravar/carregar,Dialog de confirmare la Salvare/Încărcare,Подтверждение при сохранении/загрузке,Потврђивање током чувања/учитавања,Bekräftelse av sparande/laddning,Kaydet/Yükle onayı,Підтвердження при збереженні/завантаженні, +Disable keyboard cheats,MISCMNU_NOCHEATS,,,,Vypnout cheaty z klávesnice,Deaktivere snyderier med tastaturet,Tastatur-Cheats deaktivieren,,Malvalidigi klavarajn trompojn,Desactivar trucos por teclado,,Poista näppäinhuijaukset,Déasctiver les codes de triche au clavier,Billentyűs csalások letiltása,Disabilita i trucchi classici,キーボードからのチート無効,,Schakel cheats uit,Deaktiver tastaturjuks,Wyłącz Oszustwa z Klawiatury,Desativar trapaças de teclado,,Dezactivează codurile din tastatură,Отключить клавиатурные чит-коды,,Inaktivera fusk med tangentbordet,Klavye hilelerini devre dışı bırak,Вимкнути клавіатурні чіт-коди, +Quicksave rotation,MISCMNU_QUICKSAVEROTATION,,,,Rotace rychle uložených her,Quicksave-rotation,Schnellspeicherrotation,,Rotacio de rapidkonservo,Rotación al hacer un guardado rápido,,Pikatallennuskierto,Rotation Sauvegardes Rapides,Gyorsmentés forgás,Rotazione del quicksave,クイックセーブ間隔,빠른 저장 간격,Rouleer snelopslag,Hurtiglagring-rotasjon,Rotacja szybkich zapisów,Rotação de salvamentos rápidos,Rotação de gravações rápidas,Rotație salvări automate,Менять ячейки для быстрых сохранений,Окретање брзих чувања,Rotation av snabbregistrering,Hızlı kaydetme rotasyonu,Чергування слотів швидких збережень, +Number of quicksaves in rotation,MISCMNU_QUICKSAVECOUNT,,,,Počet rychle uložených her v rotaci,Antal quicksaves i rotation,Anzahl Schnellspeicherplätze,,Kvanto da rapidkonservoj en rotaciado,Cantidad de guardados rápidos en rotación,,Pikatallennusten määrä kierrossa,Nombre de sauvegardes en rotation,Gyorsmentések száma a forgásban,Numero di quicksave in rotazione,間隔クイックセーブの数,빠른 저장 간격의 수,Aantal roulerende snelopslagplekken,Antall hurtiglagringer i rotasjon,Ilość szybkich zapisów w rotacji,Número de salvamentos rápidos em rotação,Número de gravações rápidas em rotação,Număr salvări rapide în rotație,Кол-во ячеек для быстрых сохранений,Број брзих чувања у окретању,Antal quicksaves i rotation,Rotasyondaki quicksave sayısı,Кількість слотів для швидких збережень, +Disable Menu Clean Scaling,MISCMNU_CLEANMENU,,,,Zakázat čisté škálování nabídek,Deaktivere Menu Clean Scaling,Gleichmäßige Menüskalierung deaktivieren,,Malebligi puran skaladon en la ĉefmenuo,El menú principal ocupa toda la pantalla,,Poista käytöstä valikon siisti skaalautuminen,Ne pas utilisé mise à l'échelle menu propre,Menü Tisztaarányítás kikapcsolása,Disabilita il fattore di scala pulito del menu,メニュー画面を伸縮させない,,Schakel uniforme menuschaling uit,Deaktiver ren skalering av meny,Wyłącz Skalowanie Menu,Desativar escala limpa do menu,,Dezactivează Scara Nouă a Meniurilor,Отключить чистое масштабирование меню,,Inaktivera ren menyskalning,Menü Temiz Ölçeklendirmeyi Devre Dışı Bırak,Вимкнути чисте масштабування меню, +Pause game in background,MISCMNU_PAUSEINBACKGROUND,,,,Pozastavit hru na pozadí,Pause spil i baggrunden,Spiel pausieren wenn im Hintergrund,,Paŭzigi ludon fone,Pausar el juego en segundo plano,,Pysäytä peli taustalla,Mettre le jeu en pause en arrière-plan,Játék megállítása a háttérben,Pausa il gioco in background,バックグラウンド時に一時停止,백그라운드에서 게임 일시 중지,Pauzeer het spel op de achtergrond,Pauser spillet i bakgrunnen,Zapauzuj grę w tle,Pausar jogo ao minimizar,,Pauză dacă jocul este minimizat.,Пауза при сворачивании окна,Паузирајте игру у позадини,Pausa spelet i bakgrunden,Oyunu arka planda duraklat,Пауза при згортуванні вікна, +Default Crosshair,HUDMNU_CROSSHAIR,,,,Výchozí zaměřovač,Standardtrådkorset,Standard-Fadenkreuz,,Defaŭlta reteto,Retícula por defecto,,Oletustähtäin,Viseur par défaut,Alap célkereszt,Mirino di default,デフォルトの照準,기본 조준점,Standaard dradenkruis,Standard trådkors,Domyślny celownik,Mira padrão,,Țintă implicită,Прицел по умолчанию,Уобичајени нишан,Standardkorshår,Varsayılan Nişangah,Типи прицілів, +Crosshair color,HUDMNU_CROSSHAIRCOLOR,,,Crosshair colour,Barva zaměřovače,Trådkors farve,Fadenkreuzfarbe,,Retetokoloro,Color de la retícula,,Tähtäimen väri,Couleur Viseur,Célkereszt színe,Colore mirino,照準色,조준점 색깔,Dradenkruis kleur,Farge på trådkors,Kolor celownika,Cor da mira,,Culoare țintă,Цвет прицела,Боја нишана,Färg på hårkorset,Nişangah rengi,Колір прицілу, +Crosshair shows health,HUDMNU_CROSSHAIRHEALTH,,,,Zaměřovač zobrazuje zdraví,Trådkors viser helbred,Fadenkreuz zeigt Gesundheit,,Reteto montras sanon,Mostrar salud en retícula,,Tähtäin näyttää terveyden,Couleur Viseur selon santé,Életerő jelzése a célkereszten,Il mirino mostra la salute,照準のヘルス表示,조준점과 체력 연동,Dradenkruis toont gezondheid,Trådkorset viser helse,Celownik pokazuje zdrowie,Exibir saúde na mira,Mostra vida na mira,Ținta afișează starea sănătății,Прицел отображает здоровье,Нишан приказује здравље,Hårkorset visar hälsa,Artı işareti sağlığı gösterir,Колір прицілу за станом здоров'я, +Scale crosshair,HUDMNU_CROSSHAIRSCALE,,,,Velikost zaměřovače,Skalerer trådkorset,Fadenkreuz skalieren,,Skali reteton,Escalar retícula,,Skaalaa tähtäintä,Mise à l'échelle du viseur,Célkereszt mérete,Fattore di scala del mirino,照準サイズ,조준점 크기,Dradenkruis schalen,Skalere trådkors,Skala celownika,Redimensionar mira,,Dimensiune țintă,Размер прицела,Размера нишана,Skala hårkorset,Ölçekli artı işareti,Розмір прицілу, +Standard,OPTVAL_YES_STANDARD,copied from elsewhere,,,Standardní,,,Πρότυπο,Norma,Estándar,,Normaali,,Alap,,標準,기본,Standaard,,,Padrão,,,Стандартный,Стандардни,,Standart,Стандартний, +Enhanced,OPTVAL_YES_ENHANCED,,,,Vylepšené,Forbedret,Verbessert,Ενισχυομένο,Bonigita,Mejorado,,Paranneltu,Amélioré,Fejlesztett,Migliorata,強調,고급,Verbeterd,Forbedret,Ulepszone,Melhorado,,Îmbunătățită,Улучшенный,Побољшани,Förbättrad,Geliştirilmiş,Покращений, +Language,OPTMNU_LANGUAGE,,,,Jazyk,Sprog,Sprache,Γλώσσα,Lingvo,Idioma,,Kieli,Langage,Nyelv,Lingua,言語設定,언어,Taal,Språk,Język,Idioma,,Limbă,Язык,Језик,Språk,Dil,Мова, +,,Reverb editor,,,,,,,,,,,,,,,,,,,,,,,,,,, +Undo Changes,TXT_UNDOCHANGES,,,,Zrušit změny,Fortryd ændringer,Rückgängig machen,Αναίρεση Αλλαγών,Malfari ŝanĝojn,Anular cambios,,Peruuttaa muutokset,Révoquer les changements,Változtatások Visszavonása,Revocare le modifiche,変更を戻す,변경 사항 취소,Wijzigingen ongedaan maken,Angre endringer,Cofnij Zmiany,Desfazer alterações,,Anulează Modificările,Отменить изменения,Поништи промене,Ångra ändringar,Değişiklikleri Geri Al,Відмінити зміни, +Select Environment,REVMNU_SELECT,,,,Vybrat prostředí,Vælg miljø,Umgebung wählen,Επιλογή Περιβάλλοντος,Elekti medion,Seleccionar ambiente,,Valitse tila,Sélectionner un environnement,Környezet Kiválasztása,Seleziona ambiente,反響選択,환경 선택,Selecteer omgeving,Velg miljø,Wybierz Środowisko,Selecione o ambiente,,Alegere Mediu,Выбрать окружение,Изабери окружење,Välj miljö,Ortam Seçiniz,Вибрати оточення, +Test Environment,REVMNU_TEST,,,,Testovat prostředí,Test miljø,Umgebung testen,Δοκιμαστκό Περιβάλλον,Provi medion,Probar ambiente,,Testaa tilaa,Tester un environnement,Környezet Tesztelése,Testa ambiente,反響テスト,환경 테스트,Test omgeving,Test miljø,Testuj Środowisko,Testar ambiente,,Testare Mediu,Проверка окружения,Тестирај окружење,Testa miljön,Test Ortamı,Тестувати оточення, +Edit Environment,REVMNU_EDIT,,,,Upravit prostředí,Rediger miljø,Umgebung editieren,Επεξεργασία Περιβάλλοντος,Modifi medion,Editar ambiente,,Muokkaa tilaa,Modifier un environnement,Környezet Szerkesztése,Modifica ambiente,反響編集,환경 편집,Omgeving bewerken,Rediger miljø,Edytuj Środowisko,Editar ambiente,,Editare Mediu,Редактировать окружение,Уреди окружење,Redigera miljön,Ortamı Düzenle,Редагувати оточення, +New Environment,REVMNU_NEW,,,,Nové prostředí,Nyt miljø,Neue Umgebung,Νέο Περιβάλλον,Nova medio,Nuevo ambiente,,Uusi tila,Nouveau environnement,Új Környezet,Nuovo ambiente,新規反響設定,새로운 환경 생성,Nieuwe omgeving,Nytt miljø,Nowe Środowisko,Novo ambiente,,Mediu Nou,Новое окружение,Ново окружење,Ny miljö,Yeni Çevre,Нове оточення, +Revert settings,REVMNU_REVERT,,,,Obnovit nastavení,Tilbageføre indstillinger,Zurücksetzen,Επαναφορά Ρυθμίσεων,Malfari agordojn,Revertir configuración,,Palauta asetukset,Réinitialiser les paramètres,Változtatások elvetése,Ripristina le impostazioni,設定を戻す,설정 되돌리기,Instellingen terugzetten,Tilbake innstillinger,Przywróć ustawienia,Reverter configurações,,Revenire la setările precedente,Сбросить настройки,Врати подешавања,Återkalla inställningar,Ayarları geri döndür,Налаштування за замовчуванням, +Environment Size,REVMNU_ENVIRONMENT_SIZE,Please translate only if you know how to properly name this technical jargon!,,,,,,Μέγεθος Περιβάλλοντος,Mediamplekso,Tamaño de ambiente,,Tilan koko,Taille Environnement,,Dimensioni dell'ambiente,反響サイズ,공간 크기,,,Rozmiar Środowiska,Tamanho do ambiente,,,,,Miljö storlek,,, +Environment Diffusion,REVMNU_ENVIRONMENT_DIFFUSION,,,,,,,Διάχυση Περιβάλλοντος,Medidifuzo,Difusión de ambiente,,Tilan äänen hajautuminen,Diffusion Environnement,,Diffusione dell'ambiente,反響伝播,공간 잔향 확산,,,Dyfuzja Środowiska,Difusão do ambiente,,,,,Miljö spridning,,, +Room,REVMNU_ROOM,,,,,,,Δωμάτιο,Ĉambro,Sala,,Tilan keskitaajuudet,Salle,,,,룸 효과,,,Pokój,Sala,,,,,,,, +Room HF,REVMNU_ROOM_HF,,,,,,,Δωμάτιο HF,Ĉambro (AF),Sala (Frecuencia alta),,Tilan korkeat taajuudet,HF Salle,,,,룸 효과 HF,,,Pokój (wysokie częstotliwości),Sala (alta frequência),,,,,,,, +Room LF,REVMNU_ROOM_LF,,,,,,,Δωμάτιο LF,Ĉambro (MaF),Sala (Frecuencia baja),,Tilan matalat taajuudet,LF Salle,,,,룸 효과 LF,,,Pokój (niskie częstotliwości),Sala (baixa frequência),,,,,,,, +Decay Time,REVMNU_DECAY_TIME,,,,,,,,Putriĝo-tempo,Tiempo de decadencia,,Häipymäaika,Temps Decay,,,,잔향 감쇠 시간,,,Czas Rozkładu,Tempo de decaimento,,,,,,,, +Decay HF Ratio,REVMNU_DECAY_HF_RATIO,,,,,,,,Putriĝo-proporcio (AF),Ratio de decadencia (Frecuencia alta),,Korkeiden taajuuksien (HF) häipymissuhdeluku,,,,Decay HF比率,잔향 감쇠 HF 비율,,,Wskażnik Rozkładu dla wysokich częstotliwości,Taxa de decaimento (alta freq.),,,,,,,, +Decay LF Ratio,REVMNU_DECAY_LF_RATIO,,,,,,,,Putriĝo-proporcio (MaF),Ratio de decadencia (Frecuencia baja),,Matalien taajuuksien (LF) häipymissuhdeluku,,,,Decay LF比率,잔향 감쇠 LF 비율,,,Wskaźnik Rozkładu dla niskich częstotliwości,Taxa de decaimento (baixa freq.),,,,,,,, +Reflections,REVMNU_REFLECTIONS,,,,,,,Αντανακλάσεις,Reflektoj,Reflejos,,Ensiheijastukset,,,,,룸 반사,,,Obicia,Reflexos,,,,,,,, +Reflections Delay,REVMNU_REFLECTIONS_DELAY,,,,,,,Καθυστέρηση Αντανακλάσεων,Prokrasto de reflektoj,Retraso de reflejos,,Ensiheijastusten viive,Délai Reflections,,,,룸 반사 딜레이 시간,,,Opóźnienie Odbić,Atraso de reflexos,,,,,,,, +Reflections Pan X,REVMNU_REFLECTIONS_PAN_X,,,,,,,,Reflektoj alturnas tra X,Desplazamiento en X de reflejos,,Ensiheijastusten X-panorointi,Orientation Reflections X,,,Reflections X定位,X축 룸 반사,,,Odbicia Osi X,Deslocamento X de reflexos,,,,,,,, +Reflections Pan Y,REVMNU_REFLECTIONS_PAN_Y,,,,,,,,Reflektoj alturnas tra Y,Desplazamiento en Y de reflejos,,Ensiheijastusten Y-panorointi,Orientation Reflections Y,,,Reflections Y定位,Y축 룸 반사,,,Odbicia Osi Y,Deslocamento Y de reflexos,,,,,,,, +Reflections Pan Z,REVMNU_REFLECTIONS_PAN_Z,,,,,,,,Reflektoj alturnas tra Z,Desplazamiento en Z de reflejos,,Ensiheijastusten Z-panorointi,Orientation Reflections Z,,,Reflections Z定位,Z축 룸 반사,,,Odbicia Osi Z,Deslocamento Z de reflexos,,,,,,,, +Reverb,REVMNU_REVERB,,,,,,,,Resono,Reverberación,,Jälkikaiunta,,,,,리버브,,,Pogłos,Reverberação,,,,,,,, +Reverb Delay,REVMNU_REVERB_DELAY,,,,,,,,Prokrasto de resono,Retraso de reverberación,,Jälkikaiunnan viive,Délai Reverb,,,,리버브 지연,,,Opóźnienie Pogłosu,Atraso de reverberação,,,,,,,, +Reverb Pan X,REVMNU_REVERB_PAN_X,,,,,,,,Resono alturnas tra X,Desplazamiento en X de reverberación,,Jälkikaiunnan X-panorointi,Orientation Reverb X,,,Reverb X定位,X축 리버브,,,Pogłos Osi X,Deslocamento X de reverberação,,,,,,,, +Reverb Pan Y,REVMNU_REVERB_PAN_Y,,,,,,,,Resono alturnas tra Y,Desplazamiento en Y de reverberación,,Jälkikaiunnan Y-panorointi,Orientation Reverb Y,,,Reverb Y定位,Y축 리버브,,,Pogłos Osi Y,Deslocamento Y de reverberação,,,,,,,, +Reverb Pan Z,REVMNU_REVERB_PAN_Z,,,,,,,,Resono alturnas tra Z,Desplazamiento en Z de reverberación,,Jälkikaiunnan Z-panorointi,Orientation Reverb Z,,,Reverb Z定位,Z축 리버브,,,Pogłos Osi Z,Deslocamento Z de reverberação,,,,,,,, +Echo Time,REVMNU_ECHO_TIME,,,,,,,,Tempo de eĥo,Tiempo de eco,,Kaikuaika,Longueur écho,,,,에코 시간,,,Czas Echa,Tempo de eco,,,,,,,, +Echo Depth,REVMNU_ECHO_DEPTH,,,,,,,,Produndo de eĥo,Profundidad de eco,,Kaiun syvyys,Profondeur écho,,,,에코 깊이,,,Głębokość Echa,Profundidade de eco,,,,,,,, +Modulation Time,REVMNU_MODULATION_TIME,,,,,,,,Tempo de modulado,Tiempo de modulación,,Modulaatioaika,Longueur Modulation,,,,전조 시간,,,Czas Modulacji,Tempo de modulação,,,,,,,, +Modulation Depth,REVMNU_MODULATION_DEPTH,,,,,,,,Produndo de modulado,Profundidad de modulación,,Modulaation syvyys,Profondeur Modulation,,,,전조 깊이,,,Głębokość Modulacji,Profundidade de modulação,,,,,,,, +Air Absorption HF,REVMNU_AIR_ABSORPTION_HF,,,,,,,,Aer-absorbo AF,Absorción en aire de frecuencia alta,,Korkeiden taajuuksien (HF) ilma-absorptio,,,,,대기 흡수 HF,,,Absorbcja Powietrza (wysokie częstotliwości),Absorção de ar de alta freq.,,,,,,,, +HF Reference,REVMNU_HF_REFERENCE,,,,,,,,AF referenco,Referencia de frecuencia alta,,Korkeiden taajuuksien vertausarvo,,,,HF参照値,HF 참조치,,,Odniesienie wysokich częstotliwości,Referência de alta freq.,,,,,,,, +LF Reference,REVMNU_LF_REFERENCE,,,,,,,,MaF referenco,Referencia de frecuencia baja,,Matalien taajuuksien vertausarvo,,,,LF参照値,LF 참조치,,,Odniesienie niskich częstotliwości,Referência de baixa freq.,,,,,,,, +Room Rolloff Factor,REVMNU_ROOM_ROLLOFF_FACTOR,,,,,,,,Ĉambro-Rolloff-faktoro,Factor de Roll-off de sala,,Tilan vaimenemiskerroin,Facteur de rolloff Salle,,,,룸 감쇠 양,,,Czynnik Zejścia,Fator de roll-off de sala,,,,,,,, +Diffusion,REVMNU_DIFFUSION,,,,,,,,Difuzo,Difusión,,Diffuusio,,,,,잔향 확산,,,Dyfuzja,Difusão,,,,,,,, +Density,REVMNU_DENSITY,,,,,,,,Denseco,Densidad,,Tiheys,Densité,,,密度,잔향 밀도,,,Zagęszczenie,Densidade,,,,,,,, +Reflections Scale,REVMNU_Reflections_Scale,,,,,,,,Skalo de reflektoj,Escala de reflejos,,Ensiheijastusten skaala,Echelle Reflections,,,Reflections音階,룸 반사 음계,,,Rozmiar Odbić,Escala de reflexos,,,,,,,, +Reflections Delay Scale,REVMNU_Reflections_Delay_Scale,,,,,,,,Prokrastskalo de reflektoj,Escala de retraso de reflejos,,Ensiheijastusten viiveen skaala,Délai d'échelle reflections,,,Reflections Delay音階,룸 반사 딜레이 음계,,,Skala Opóźnienia Odbić,Escala de atraso de reflexos,,,,,,,, +Decay Time Scale,REVMNU_Decay_Time_Scale,,,,,,,,Tempskalo de purtiĝo,Escala de tiempo de decadencia,,Häipymäajan skaala,Echelle temporelle Decay,,,Decay Time音階,잔향 감쇠시간 음계,,,Skala Czasu Rozkładu,Escala de tempo de decaimento,,,,,,,, +Decay HF Limit,REVMNU_Decay_HF_Limit,,,,,,,,AF-Limito de purtiĝo,Limite de decadencia de alta frecuencia,,Häipymän korkeiden taajuuksien raja-arvo,Limite HF Decay,,,Decay HF限度,잔향 감쇠 HF 한도,,,Limit Rozkładu Wysokich Częstotliwości,Limite de decaimento em alta freq.,,,,,,,, +Reverb Scale,REVMNU_Reverb_Scale,,,,,,,,Skalo de resono,Escala de reverberación,,Jälkikaiunnan skaala,Echelle Reverb,,,Reverb音階,리버브 음계,,,Skala Pogłosu,Escala de reverberação,,,,,,,, +Reverb Delay Scale,REVMNU_Reverb_Delay_Scale,,,,,,,,Prokrastskalo de resono,Escala de retraso de reverberación,,Jälkikaiunnan viiveen skaala,Délai d'échelle Reverb,,,Reverb Delay音階,리버브 딜레이 음계,,,Skala Opóźnienia Pogłosu,Escala de atraso de reverberação,,,,,,,, +Echo Time Scale,REVMNU_Echo_Time_Scale,,,,,,,,Tempskalo de eĥo,Escala de tiempo de eco,,Kaikuajan skaala,Echelle temporelle Echo,,,Echo Time音階,에코 시간 음계,,,Skala Czasu Echa,Escala de tempo de eco,,,,,,,, +Modulation Time Scale,REVMNU_Modulation_Time_Scale,,,,,,,,Tempskalo de modulado,Escala de tiempo de modulación,,Modulaatioajan skaala,Echelle temporelle Modulation,,,Modulation Time音階,전조 시간 음계,,,Skala Modulacji Czasu,Escala de tempo de modulação,,,,,,,, +Based on,REVMNU_Based_on,,,,Založeno na,Baseret på,Basierend auf,Βασισμένο σε,Bazita de,Basado en,,Perustana,Basé sur,Minta,Basato su,音響の元,음향 원본,Gebaseerd op,Basert på,Bazowane na,Baseado em,,Bazat pe,Основано на,Засновано на,Baserat på,Buna göre,На основі, +Name,REVMNU_Name,,,,Název,Navn,,Όνομα,Nomo,Nombre,,Nimi,Nom,Név,Nome,名前,이름,Naam,Navn,Nazwa,Nome,,Nume,Название,Назив,Namn,İsim,Назва, +ID #1,REVMNU_ID_1,,,,,,,,Identigo #1,ID Nº1,,,,,ID N°1,,아이디 #1,,,,,,,ИД №1,,,,, +ID #2,REVMNU_ID_2,,,,,,,,Identigo #2,ID Nº2,,,,,ID N°2,,아이디 #2,,,,,,,ИД №2,,,,, +Create,REVMNU_Create,,,,Vytvořit,Opret,Erstellen,Δημιουργία,Krei,Crear,,Luo,Créer,Készítés,Creare,作成,생성,Aanmaken,Opprett,Stwórz,Criar,,Creare,Создать,Направи,Skapa,Oluştur,Створити, +Save...,REVMNU_Save,,,,Uložit...,Gem...,Speichern...,Αποθήκευση,Konservi...,Guardar...,,Tallenna...,Sauvegarder...,Mentés...,Salvare...,セーブする...,저장 하기...,Opslaan...,Lagre...,Zapisz...,Salvar...,,Salvare...,Сохранить...,Сачувај...,Spara...,Kaydet...,Зберегти..., +File name,REVMNU_File_name,,,,Název souboru,Filnavn,Dateiname,Όνομα αρχείου,Dosiernomo,Nombre de archivo,,Tiedostonimi,Nom de fichier,Fájlnév,Nome del file,ファイル名,파일 이름,Bestandsnaam,Filnavn,Nazwa pliku,Nome do arquivo,,Nume fișier,Имя файла,Назив фајла,Filnamn,Dosya adı,Назва файлу, +Environments to save,REVMNU_Environments_to_save,,,,Prostředí k uložení,"Miljøer, der skal gemmes",Zu speichernde Umgebungen,Περιβάλλοντα για αποθήκευση,Medioj por konservi,Ambientes para guardar,,Tallennettavat tilat,Environnements à sauvegarder,Mentendő Környezetek,Ambienti da salvare,音響を保存,저장할 공간,Omgevingen om op te slaan,Miljøer som skal lagres,Środowiska do zapisu,Ambientes para salvar,,Medii de salvat,Сохранить окружения...,Окружења за чување,Miljöer som ska sparas,Kurtarılacak ortamlar,Зберегти оточення..., +,,Vulkan,,,,,,,,,,,,,,,,,,,,,,,,,,, +Vulkan Options (Experimental),DSPLYMNU_VKOPT,,,,Nastavení Vulkanu (Experimentální),Vulkan-indstillinger (eksperimentelt),Vulkan Optionen (Experimentell),Vulka Ρυθμίσεις (Πειραματικές),Agordoj por Vulkan (Eksperimenta),Opciones de Vulkan (Experimental),,Vulkan-asetukset (kokeellinen),Options Vulkan (Expérimental),Vulkan Beállítások (Kísérleti),Opzioni Vulkan (Sperimentale),Vulkan機能オプション(実験的),벌칸 설정(실험적),Vulkan-opties (Experimenteel),Vulkan Alternativer (Eksperimentell),Opcje Vulkan (Eksperymentalne),Opções de Vulkan (experimental),,Setări Mod Vulkan (În curs de testare),Настройки Vulkan (экспериментальные),Vulkan подешавања (експериментална),Vulkan-alternativ (experimentellt),Vulkan Seçenekleri (Deneysel),Налаштування Vulkan (експериментальні), +Vulkan Options,VK_TITLE,,,,Nastavení Vulkanu,Vulkan-indstillinger,Vulkan Optionen,Vulkan Ρυθμίσεις,Agordoj por Vulkan,Opciones de Vulkan,,Vulkan-asetukset,Options Vulkan,Vulkan Beállítások,Opzioni Vulkan,Vulkan機能オプション,벌칸 설정,Vulkan-opties,Vulkan-alternativer,Opcje Vulkan,Opções de Vulkan,,Setări Mod Vulkan,Настройки Vulkan,Vulkan подешавања,Vulkan-alternativ,Vulkan Seçenekleri,Налаштування Vulkan, +Enable Vulkan,VKMNU_ENABLE,,,,Povolit Vulkan,Aktiver Vulkan,Aktiviere Vulkan,Ενεργοποιηση του Vulkan,Ŝalti Vulkan,Activar Vulkan,,Ota käyttöön Vulkan,Activer Vulkan,Vulkan Engedélyezése,Abilita Vulkan,Vulkanを有効化,벌칸 렌더러 사용,Vulkan inschakelen,Aktiver Vulkan,Włącz Vulkan,Ativar Vulkan,,Activează modul video Vulkan,Использовать Vulkan,Омогући Vulkan,Aktivera Vulkan,Vulkan'ı Etkinleştir,Увімкнути Vulkan, +Vulkan Device ID,VKMNU_DEVICE,,,,ID zařízení Vulkanu,Vulkan-enheds-id,Vulkan Geräte ID,Vulkan ID Συσκευής,Identigo de Vulkan-aparato,ID de dispositivo Vulkan,,Vulkan-laitetunniste,ID du périphérique Vulkan,Vulkan Eszköz ID,Dispositivo ID Vulkan,Vulkanデバイス ID,벌칸 장치 아이디,Vulkan apparaat-ID,Vulkan Enhets-ID,ID urządzenia Vulkan,ID do dispositivo Vulkan,,ID Dispozitiv Vulkan,ИД устройства Vulkan,Vulkan ID уређаја,Vulkan-enhets-ID,Vulkan Cihaz Kimliği,ID пристрою Vulkan, +High Dynamic Range,VKMNU_HDR,,,,Vysoký dynamický rozsah (HDR),Høj dynamisk rækkevidde,,Υψηλό Δυναμική Εμβέλεια,Alta dinamika intervalo,Alto rango dinámico,,Korkea dynamiikka-alue (HDR),,,,ハイダイナミックレンジ,하이 다이나믹 레인지,Hoog dynamisch bereik,Høyt dynamisk område,Obraz HDR,Alto alcance dinâmico (HDR),,HDR,Расширенный динамический диапазон (HDR),HDR,Högt dynamiskt omfång,Yüksek Dinamik Aralık,HDR, +Warning: The Vulkan renderer is highly experimental!,VK_WARNING,,,,Varování: Vulkan renderer je velmi experimentální!,Advarsel: Vulkan-rendereren er meget eksperimentel!,Achtung: Der Vulkan Renderer ist noch sehr experimentell!,Προειδοποίηση: Ο Vulkan renderer είναι υψηλά πειραματικός!,Averto: La bildigilo de Vulkan estas alte eksperimenta!,Advertencia: ¡El renderizado por Vulkan es altamente experimental!,,Varoitus: Vulkan-hahmonnin on hyvin kokeellinen!,Attention: Le moteur de rendu Vulkan est très expérimental!,Vigyázat: A Vulkan renderer még teljesen kísérleti!,Attenzione: il motore grafico Vulkan è altamente sperimentale!,警告:Vulkanレンダラーは実験段階です!,경고: 벌칸 렌더러는 매우 실험적입니다!,Waarschuwing: De Vulkan renderer is zeer experimenteel!,Advarsel: Vulkan-rendereren er svært eksperimentell!,Uwaga: Renderer Vulkan jest bardzo eksperymentalny!,Atenção: o renderizador Vulkan é altamente experimental!,,Atenție: Modul Vulkan este încă în curs de testare!,Внимание: обработчик Vulkan в стадии тестирования!,УПОЗОРЕЊЕ: Vulkan рендерер је врло експерименталан!,Varning: Vulkan-renderaren är mycket experimentell!,Uyarı: Vulkan işleyici son derece deneyseldir!,Увага: рендер Vulkan на стадії тестування!, +These options will require a restart to take effect.,VK_RESTART,,,,Tato nastavení vyžadují restart hry.,Disse indstillinger kræver en genstart for at få effekt.,Diese Option erfordert einen Neustart!,Αυτές η ρυθμίσεις θα χρειαστούνε επανεκκίνηση για να ισχύσουν,Ĉi tiuj agordoj bezonos relanĉon por efikiĝi.,Estas opciones requieren reiniciar para tener efecto.,,Nämä asetukset vaativat uudelleenkäynnistyksen astuakseen voimaan.,Ces options nécessitent un redémarrage.,Ezen beállítások életbelépéséhez újraindítás szükséges.,Queste opzioni richiedono il riavvio per avere effetto.,これらのオプションを有効にするには再起動が必要です。,이 설정을 적용하려면 게임을 재시작해야 합니다.,Deze opties vereisen een herstart om van kracht te worden.,Disse alternativene krever en omstart for å tre i kraft.,"Te opcje będą wymagały ponownego włączenia, aby miały efekt.",É necessário reiniciar para que essas configurações surtam efeito.,É necessário reiniciar para estas configurações fazerem efeito.,Aceste setări necesită o repornire pentru a putea fi aplicate,Для применения этих изменений требуется перезапуск игры.,Морате поново покренути GZDoom да би промене ступиле на снагу.,De här alternativen kräver en omstart för att få effekt.,Bu seçeneklerin etkili olması için yeniden başlatılması gerekecektir.,Для застосування змін протрібно перезапустити гру., +Select Vulkan Device,VKMNU_DEVICESELECT,This is not yet implemented - but it is planned,,,Vybrat zařízení Vulkanu,Vælg Vulkan-enhed,Vulkan Gerät auswählen,Επιλογή Vulkan Συσκευής,Elekti Vulkan-aparaton,Seleccionar dispositivo Vulkan,,Valitse Vulkan-laite,Sélectionner périphérique Vulkan,Vulkan eszköz kiválasztása,Seleziona il Dispositivo Vulkan,Vulkanデバイスの選択,벌칸 장치를 고르시오,Selecteer Vulkan Apparaat,Velg Vulkan-enhet,Wybierz Urządzenie Vulkan,Selecione o dispositivo Vulkan,,Selectare Dispozitiv Vulkan,Выбрать устройство Vulkan,Изаберите Vulkan уређај,Välj Vulkan-enhet,Vulkan Aygıtını Seçin,Виберіть пристрій Vulkan, +,,Texture scaling,,,,,,,,,,,,,,,,,,,,,,,,,,, +ScaleNx,OPTVAL_SCALENX,,,,,,,,,,,,,,,,,,,,,,,,,,,, +NormalNx,OPTVAL_NORMALNX,,,,,,,,,,,,,,,,,,,,,,,,,,,, +hqNx,OPTVAL_HQNX,,,,,,,,,,,,,,,,,,,,,,,,,,,, +hqNx MMX,OPTVAL_HQNXMMX,,,,,,,,,,,,,,,,,,,,,,,,,,,, +xBRZ,OPTVAL_NXBRZ,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Old xBRZ,OPTVAL_OLD_NXBRZ,,,,xBRZ (starší),Gamle xBRZ,xBRZ alt,Παλίο xBRZ,Malnova xBRZ,Antiguo xBRZ,,Vanha xBRZ,Ancien xBRZ,Régi xBRZ,Vecchio xBRZ,旧xBRZ,구형 xBRZ,Oud xBRZ,Gammel xBRZ,Stare xBRZ,Antigo xBRZ,,Vechiul xBRZ,Старый xBRZ,Стари xBRZ,Gamla xBRZ,Eski xBRZ,Старий xBRZ, +,,Option Search,,,,,,,,,,,,,,,,,,,,,,,,,,, +Option Search,OS_TITLE,,,,Vyhledávání možností,Mulighed Søgning,Optionssuche,Αναζήτηση Ρυθμίσεων,Serĉi agordojn,Buscar opciones,,Asetushaku,Recherche Option,Beállítások keresése,Opzioni di ricerca,オプション検索,옵션 검색,Optie zoeken,Alternativt søk,Szukanie Opcji,Buscar opção,Procurar opção,Căutare Setări,Поиск настройки,Претрага,Sökning av alternativ,Seçenek Arama,Пошук налаштування, +Search for any term,OS_ANY,,,,Hledat jakékoli klíčové slovo,Søg efter et vilkårligt begreb,Suche nach beliebigem Begriff,Αναζήτηση για όποιαδηποτε λέξη,Serĉi iun ajn terminon,Buscar cualquier término,,Etsi mitä tahansa sanaa,N'importe quel mot,Keresés bármely kifejezésre,Cerca per ciascun termine,いずれかの用語を探す,용어 검색,Zoek naar eender welke term,Søk etter en hvilken som helst term,Szukaj jakiegokolwiek wyrażenia,Buscar por qualquer termo,Procurar por um termo qualquer,Căutare după orice termen,Искать любое из слов,Тражи било који термин,Sök efter valfri term,Herhangi bir terim için arama yapın,Шукати будь яке з слів, +Search for all terms,OS_ALL,,,,Hledat všechna klíčová slova,Søg efter alle udtryk,Suche nach allen Begriffen,Αναζήτηση για όλες της λέξεις,Serĉi ĉiujn terminojn,Buscar todos los términos,,Etsi kaikki sanat,Tous les mots,Keresés minden kifejezésre,Cerca per tutti i termini,全ての用語を探す,모든 조건 검색,Zoek naar alle termen,Søk etter alle termer,Szukaj wszystkich wyrażeń,Buscar por todos os termos,Procurar por todos os termos,Căutare după toți termenii,Искать все слова,Тражи сваки термин,Sök efter alla termer,Tüm terimler için arama yapın,Шукати всі слова, +No results found.,OS_NO_RESULTS,,,,Nic nenalezeno.,Ingen resultater fundet.,Keine Resultate,Δέν βρέθηκαν αποτελέσματα,Neniu trafo.,Ningún resultado.,,Ei tuloksia.,Pas de résultat trouvé,Nincs találat,Nessun risultato trovato.,見つかりませんでした。,검색 결과 없음.,Geen resultaten gevonden.,Ingen resultater funnet.,Brak wyników,Nenhum resultado encontrado.,,Niciun rezultat găsit.,Результаты не найдены.,Нема резултата.,Inga resultat hittades.,Sonuç bulunamadı.,Нічого не знайдено., +Search:,OS_LABEL,,,,Hledat:,Søg:,Suche:,Αναζήτηση:,Serĉi:,Buscar:,,Etsi:,Recherche:,Keresés:,Trova:,検索:,검색:,Zoeken:,Søk:,Szukaj:,Busca:,Procura:,Caută:,Поиск:,Претрага:,Sök:,Ara:,Пошук:, +,,Blood Bath Announcer,,,,,,,,,,,,,,,,,,,,,,,,,,, +%k boned %o like a fish,TXT_OBITUARY1,,,,%o byl@[ao_cs] vykoštěn@[ao_cs] jako ryba hráčem %k,%k udbenede %o som en fisk,%k hat %o zerlegt wie einen Fisch,Ο/Η %k ξεκοκάλοσε @[pro2_gr] %o σα ψάρι,%k senostigis %o kiel fiŝon,%k ha deshuesado a %o como a un pescado,%k deshuesó a %o como a un pescado,%k perkasi %o paran kuin kalan,%k a désossé %o comme un poisson,%k kifilézte %o -t mint a halat,%k ha dissossato %o come un pesce,%k は %o の骨を魚のように引っこ抜いた。,%k 은(는) %o 의 뼈를 발랐다.,%k mergelde %o als een vis,%k utbeinet %o som en fisk,%k odfiletował@[ao_pl] %o jak rybę,%k desossou %o como um peixe,,%k l-a dezosat pe %o ca pe un pește,%k пересчитал косточки игрока %o,%k је очистио %o као рибу,%k benade %o som en fisk,"%o, %k tarafından balık gibi kemirildi.",%k порахува@[adj_1_ua] ребра %o, +%k castrated %o,TXT_OBITUARY2,,,,%o byl@[ao_cs] vykastrován@[ao_cs] hráčem %k,%k kastrerede %o,%k hat %o kastriert,Ο/Η %k ευνούχισε %o,%k kastris %o,%k ha castrado a %o,%k castró a %o,%k kastroi %o paran,%k a castré %o,%k kasztrálta %o -t,%k ha castrato %o,%k は %o を去勢した。,%k 은(는) %o 을(를) 거세시켰다.,%k castreerde %o,%k kastrert %o,%k wykastrował@[ao_pl] %o,%k castrou %o,,%k l-a castrat pe %o,%k кастрировал игрока %o,%k је кастрирао %o,%k kastrerade %o,"%o, %k tarafından hadım edildi.",%k каструва@[adj_1_ua] %o, +%k creamed %o,TXT_OBITUARY3,,,,%o byl@[ao_cs] rozšlehán@[ao_cs] hráčem %k,%k smurte %o,%k hat %o eingeseift,Ο/Η %k κρέμασε @[pro2_gr] %o,%k kremigis %o,%k ha cremado a %o,%k cremó a %o,%k kermasi %o paran,%k a battu %o à plate couture ,%k elkente %o -t,%k ha cremato %o,%k は %o に反吐ブチ撒けさせた。,%k 은(는) %o 을(를) 양념시켰다.,%k pureerde %o,%k fløtet %o,%k spienił@[ao_pl] %o,%k fez creme de %o,,%k l-a transformat în cremă pe %o,%k взбил игрока %o,%k је истукао %o,%k gräddade %o,,%k розпуши@[adj_1_ua] %o, +%k decimated %o,TXT_OBITUARY4,,,,%o byl@[ao_cs] zdecimován@[ao_cs] hráčem %k,%k decimerede %o,%k hat %o dezimiert,Ο/Η %k αποδεκάτισε @[pro2_gr] %o,%k detruegis %o,%k ha diezmado a %o,%k diezmó a %o,%k hävitti %o paran,%k a décimé %o,%k megtizedelte %o -t,%k ha decimato %o,%k は %o の居場所を間引いた。,%k 은(는) %o 을(를) 망가뜨렸다.,%k decimeerde %o,%k desimert %o,%k przetrzebił@[ao_pl] %o,%k decimou %o,,%k l-a decimat pe %o,%k скосил игрока %o,%k је десетковао %o,%k decimerade %o,"%o, %k tarafından yok edildi.",%k зітну@[adj_1_ua] %o, +%k destroyed %o,TXT_OBITUARY5,,,,%o byl@[ao_cs] zničen@[ao_cs] hráčem %k,%k ødelagde %o,%k hat %o zerstört,Ο/Η %k κατέστεψε @[pro2_gr] %o,%k detruis %o,%k ha destruido a %o,%k destruyó a %o,%k tuhosi %o paran,%k a détruit %o,%k elpusztította %o -t,%k ha distrutto %o,%k は %o を完全に破壊した。,%k 은(는) %o 을(를) 파괴했다.,%k vernietigde %o,%k destruert %o,%k zniszczył@[ao_pl] %o,%k destruiu %o,,%k l-a distrus pe %o,%k уничтожил игрока %o,%k је уништио %o,%k förstörde %o,,%k знищи@[adj_1_ua] %o, +%k diced %o,TXT_OBITUARY6,,,,%o byl@[ao_cs] nakrájen@[ao_cs] na kostičky hráčem %k,%k skar %o i tern,%k hat %o in Würfel zerteilt,Ο/Η %k τεμάχησε @[pro2_gr] %o,%k diskubigis %o,%k ha picado en cubitos a %o,%k picó en cubitos a %o,%k pilkkosi %o paran,%k a coupé en dés %o,%k kockára vágta %o -t,%k ha tagliato a cubetti %o,%k は %o を賽の目に切った。,%k 은(는) %o 을(를) 잘게 잘게 썰었다.,%k sneed %o in stukjes,%k skåret %o i terninger,%k pokroił@[ao_pl] w kostkę %o,%k fez picadinho de %o,%k cortou %o,%k l-a feliat pe %o,%k разрезал игрока %o,%k је исецкао %o,%k skar %o i tärningar,"%o, %k tarafından doğrandı.",%k наріза@[adj_1_ua] %o, +%k disembowled %o,TXT_OBITUARY7,,,,%o byl@[ao_cs] vykuchán@[ao_cs] hráčem %k,%k udkløvede %o,%k hat %o ausgeweidet,Ο/Η %k ισοπέδοσε @[pro2_gr] %o,%k sentripigis %o,%k ha destripado a %o,%k destripó a %o,%k suolisti %o paran,%k a étripé %o,%k kibelezte %o -t,%k ha smembrato %o,%k は %o の臓物を引きずり出した。,%k 은(는) %o 의 내장을 도려냈다.,%k ontleedde %o,%k sprettet opp %o,%k wypatroszył@[ao_pl] %o,%k estripou %o,,%k l-a eviscerat pe %o,%k выпотрошил игрока %o,%k је ампутирао %o,%k tog upp %o i bitar,,%k випотроши@[adj_1_ua] %o, +%k flattened %o,TXT_OBITUARY8,,,,%o byl@[ao_cs] zplacatěn@[ao_cs] hráčem %k,%k smadrede %o,%k hat %o dem Erdboden gleichgemacht,Ο/Η %k ησοπέδοσε @[pro2_gr] %o,%k platigis %o,%k ha aplanado a %o,%k aplanó a %o,%k lyttäsi %o paran,%k a aplati %o,%k kilapította %o -t,%k ha schiacciato %o,%k は %o をぶっ潰した。,%k 은(는) %o 의 코를 납작하게 만들었다.,%k plette %o,%k flatet ut %o,%k rozpłaszczył@[ao_pl] %o,%k achatou %o,%k espalmou %o,%k l-a făcut plat pe %o,%k сплюснул игрока %o,%k је изравнао %o,%k plattade %o,"%o, %k tarafından dümdüz edildi.",%k сплющи@[adj_1_ua] %o, +%k gave %o Anal Justice,TXT_OBITUARY9,,,,%o utržil@[ao_cs] anální spravedlnost od hráče %k,%k lemlæstede %o,%k hat %o anale Gerechtigkeit gegeben,Ο/Η %k γάμησε @[pro2_gr] %o @[pro3_gr] κόλο,%k donis pugan juston al %o,%k le ha dado justicia anal a %o,%k le dió justicia anal a %o,%k jakoi %o paralle anaalioikeutta,%k a rendu une justice anale a %o,%k Anális Igazságot adott %o -nak ,%k ha dato a %o Giustizia Anale,%k は %o のケツにぶち込んだ。,%k 은(는) %o 에게 홍콩행을 보냈다.,%k gaf %o anale rechtvaardigheid,%k ga %o anal rettferdighet,%k dał@[ao_pl] %o Analną Sprawiedliwość,%k deu Justiça Anal para %o,,%k i-a făcut jucătorului %o o Justiție Anală,%k устроил анальное правосудие игроку %o,%k је дао %o аналну правду,%k gav %o anal rättvisa,"%o, %k tarafından dümdüz edildi.",%k влаштува@[adj_1_ua] анальне правосуддя %o, +%k gave AnAl MaDnEsS to %o,TXT_OBITUARY10,,,,%o utrpěl@[ao_cs] AnÁlNí ŠíLeNsTvÍ od hráče %k,%k spildte %o,%k gab %o AnAlEn WaHnSiNn,Ο/Η %k έσκισε τον κόλο του/της] %o,%k donis pUgAn frEnEzOn al %o,%k le ha dado LoCuRa AnAl a %o,%k le dió LoCuRa AnAl a %o,%k teki %o paran AnAaLiHuLlUkSi,%k a donné la FOLIE ANALE a %o,%k SeGgBe KüLDtE %o -t,%k ha dato FoLlIa AnAle a %o,%k は %o のケツをガバガバにした。,%o 은(는) %k 의 찰진 맛을 보았다.,%k gaf aNaLe DoLhEiD aan %o,%k ga %o anal rettferdighet,%k dał@[ao_pl] %o AnAlNe SzAlEńStWo ,%k deu LoUcUrA aNaL para %o,,%k i-a dat NeBuNiE AnAlĂ jucătorului %o,%k устроил АнАЛ КаРнаВаЛ игроку %o,%k је дао АнАлНо ЛуДиЛо %o,%k gav %o anal rättvisa,"%o, %k tarafından dümdüz edildi.",%k влаштува@[adj_1_ua] АнАЛ ГуЛяНнЯ %o, +%k killed %o,TXT_OBITUARY11,,,,%o byl@[ao_cs] zabit@[ao_cs] hráčem %k,%k dræbte %o,%k hat %o getötet,Ο/Η %k σκότωσε @[pro2_gr] %o,%k mortigis %o,%k ha matado a %o,%k mató a %o,%k tappoi %o paran,%k a tué %o,%k kicsinálta %o -t,%k ha ucciso %o,%k は %o をブッ殺した。,%k 은(는) %o 을(를) 죽였다.,%k doodde %o,%k drepte %o,%k zabił@[ao_pl] %o,%k matou %o,,%k l-a omorât pe %o,%k убил игрока %o,%k је убио %o,%k dödade %o,"%o, %k tarafından öldürüldü.",%k вби@[adj_1_ua] %o, +%k made mincemeat out of %o,TXT_OBITUARY12,,,,%o byl@[ao_cs] namelen@[ao_cs] hráčem %k,%k gjorde hakket kød af %o,%k hat %o zu Hackfleisch verarbeitet,Ο/Η %k έφτιαξε κυμά με @[pro2_gr] %o,%k farigis farĉon el %o,%k ha hecho picadillo de %o,%k hizo picadillo de %o,%k teki jauhelihaa %o parasta,%k a fait de la viande hachée de %o,%k ledarálta %o -t,%k ha triturato %o,%k は %o をミンチにした。,%o 은(는) %k 에 의해 분쇄됐다.,%k maakte gehakt van %o,%k laget kjøttdeig av %o,%k zrobił@[ao_pl] mięso mielone z %o,%k fez carne moída de %o,%k fez carne picada do %o,%k a facut tocătură din %o,%k сделал отбивную из игрока %o,%k је направио млевено месо од %o,%k gjorde köttfärs av %o,"%o, %k tarafından kıyma haline getirildi.",%k зроби@[adj_1_ua] відбивну з %o, +%k massacred %o,TXT_OBITUARY13,,,,%o byl@[ao_cs] zmasakrován@[ao_cs] hráčem %k,%k massakrerede %o,%k hat %o niedergemetzelt,Ο/Η %k δολοφώνησε @[pro2_gr] %o,%k masakris %o,%k ha masacrado a %o,%k masacró a %o,%k verilöylytti %o parkaa,%k a massacré %o,%k lemészárolta %o -t,%k ha fatto di %o carne tritata,%k は %o を虐殺した。,%k 은(는) %o 을(를) 참살했다.,%k slachtte %o af,%k massakrerte %o,%k zmasakrował@[ao_pl] %o,%k massacrou %o,,%k a fost masacrat de către %o,%k устроил бойню игроку %o,%k је масакрирао %o,%k massakrerade %o,"%o, %k tarafından katledildi",%k влаштува@[adj_1_ua] для %o бійню, +%k mutilated %o,TXT_OBITUARY14,,,,%o byl@[ao_cs] zmrzačen@[ao_cs] hráčem %k,%k lemlæstede %o,%k hat %o verstümmelt,Ο/Η %k ακρωτηριάσε @[pro2_gr] %o,%k mutilis %o,%k ha mutilado a %o,%k mutiló a %o,%k silpoi %o paran,%k a mutilé %o,%k megcsonkította %o -t,%k ha massacrato %o,%k は %o をバラバラ死体にした。,%k 은(는) %o 의 팔다리를 절단했다.,%k verminkte %o,%k lemlestet %o,%k rozszarpał@[ao_pl] %o,%k mutilou %o,,%k l-a mutilat pe %o,%k изуродовал игрока %o,%k је мутилирао %o,%k lemlästade %o,"%o, %k tarafından sakat bırakıldı.",%k знівечи@[adj_1_ua] %o, +%k reamed %o,TXT_OBITUARY15,,,,%o byl@[ao_cs] proděravěn@[ao_cs] hráčem %k,%k skændede %o,%k hat %o aufgerieben,Ο/Η %k δέσμισε @[pro2_gr] %o,%k alezis %o,%k ha escariado a %o,%k escarió a %o,%k porasi %o paran,%k a découpé en fines lamelles %o,%k seggbe rakta %o -t,%k ha squartato %o,%k は %o の穴を大きく広げた。,%k 은(는) %o 을(를) 크게 혼냈다.,%k holde %o uit,%k maltraktert %o,%k rozwiercił@[ao_pl] %o,%k esquartejou %o,,%k l-a transformat într-un top de hârtie pe %o,%k рассверлил игрока %o,%k је наоружао %o,%k har gjort %o illa.,"%o, %k tarafından öldürüldü.",%k просверли@[adj_1_ua] %o, +%k ripped %o a new orifice,TXT_OBITUARY16,,,,%o má novou díru od hráče %k,%k flåede %o en ny åbning,%k hat %o eine neue Körperöffnung verpasst,Ο/Η άνοιξε μια νέα τρύπα @[pro3_gr] %o,%k ŝiris novan truon en %o,%k le ha hecho a %o un nuevo orificio,%k le hizo a %o un nuevo orificio,%k repi %o paralle uuden aukon,%k a ouvert un nouvel orifice a %o,%k új szájat csinált %o -nak,%k ha aperto a %o un altro orifizio,%k は %o を切り裂いて新しい穴を作ってあげた。,%k 은(는) %o 을(를) 죽여 뜯어서 작품을 만들었다.,%k scheurde een opening uit %o,%k revet %o en ny kroppsåpning,%k rozerwał@[ao_pl] %o nowy otwór,%k abriu um novo orifício em %o,,%k i-a făcut jucătorului %o un nou orificiu,%k проделал новое отверстие в игроке %o,%k је исцепао %o нови отвор,%k slet upp en ny öppning i %o,"%o, %k tarafından yeni bir delik açıldı.",%k зроби@[adj_1_ua] в %o нову дірку, +%k slaughtered %o,TXT_OBITUARY17,,,,%o byl@[ao_cs] zavražděn@[ao_cs] hráčem %k,%k slagtede %o,%k hat %o geschlachtet,Ο/Η %k έσφαξε @[pro2_gr] %o,%k buĉis %o,%k ha sacrificado a %o,%k sacrificó a %o,%k teurasti %o paran,%k a meurtri %o,%k lemészárolta %o -t,%k ha macellato %o,%k は %o を屠殺した。,%o 은(는) %k 에 의해 도살당했다.,%k slachtte %o,%k slaktet %o,%k zarżn@[irreg_2_pl] %o,%k abateu %o,,%k l-a măcelărit pe %o,%k устроил резню игроку %o,%k је заклао %o,%k slaktade %o,"%o, %k tarafından katledildi.",%k прові@[adj_1_ua] різню %o, +%k smashed %o,TXT_OBITUARY18,,,,%o byl@[ao_cs] zmlácen@[ao_cs] hráčem %k,%k smadrede %o,%k hat %o zerklatscht,Ο/Η %k τσάκισε @[pro2_gr] %o,%k frakasis %o,%k ha destrozado a %o,%k destrozó a %o,%k murskasi %o paran,%k a enfoncé %o,%k földbe döngölte %o -t,%k ha distrutto %o,%k は %o をぶっ飛ばした。,%k 은(는) %o 을(를) 내팽개쳤다.,%k vermorzelde %o,%k knust %o,%k stłukł@[ao_pl] %o,%k esmagou %o,,%k l-a spart pe %o,%k размазал игрока %o,%k је поломио %o,%k krossade %o,"%o, %k tarafından ezildi.",%k розмаза@[adj_1_ua] %o, +%k sodomized %o,TXT_OBITUARY19,,,,Hráč %k se dopustil sodomie na hráči %o,%k sodomiserede %o,%k hat %o sodomisiert,Ο/Η %k γάμησε @[pro2_gr] %o,%k sodomizis %o,%k ha sodomizado a %o,%k sodomizó a %o,%k anaaliraiskasi %o paran,%k y a sodomisé n %o,%k szodomizálta %o -t,%k ha sodomizzato %o,%o は %k にカマを掘られた。 ,%o 은(는) %k 을(를) 위해 등을 보였다.,%k sodomiseerde %o,%k sodomisert %o,%k spenetrował@[ao_pl] %o,%k sodomizou %o,,%k l-a sodomizat pe %o,%k содомировал игрока %o,%k је изјебао %o,%k sodomiserade %o,"%o, %k tarafından sodomize edildi.",%k зґвалтува@[adj_1_ua] %o, +%k splattered %o,TXT_OBITUARY20,,,,%o byl@[ao_cs] rozplesknut@[ao_cs] hráčem %k,%k sprøjtede %o,%k hat %o zerspritzt,Ο/Η %k έσκασε @[pro2_gr] %o,%k disĵetis %o,%k ha rociado a %o,%k roció a %o,%k roiski %o paran yltympäri,%k a explosé de %o,%k szétloccsantotta %o -t,%k ha spiaccicato %o,%k は %o にばら撒かれた。,%k 은(는) %o 을(를) 박살냈다.,%k splette %o,%k sprutet %o,%k rozbryzgał@[ao_pl] %o,%k explodiu %o,,%k l-a împrăștiat pe %o,%k разбрызгал игрока %o,%k је спљоштио %o,%k sprutade %o.,"%o, %k tarafından parçalandı.",%k розбризка@[adj_1_ua] %o, +%k squashed %o,TXT_OBITUARY21,,,,%o byl@[ao_cs] rozmáčknut@[ao_cs] hráčem %k,%k kværnede %o,%k hat %o zerquetscht,Ο/Η %k πάτησε @[pro2_gr] %o,%k premplatigis %o,%k ha aplastado a %o,%k aplastó a %o,%k litisti %o paran,%k a écrabouillé %o,%k eltaposta %o -t,%k ha schiacciato %o,%k は %o に潰された。,%k 은(는) %o 을(를) 짓이겼다.,%k plette %o,%k knust %o,%k zmiażdżył@[ao_pl] %o,%k espatifou %o,,%k l-a strivit pe %o,%k расплющил игрока %o,%k је згњечио %o,%k krossade %o,"%o, %k tarafından ezildi.",%k розчави@[adj_1_ua] %o, +%k throttled %o,TXT_OBITUARY22,,,,%o byl@[ao_cs] zaškrcen@[ao_cs] hráčem %k,%k kvæler %o,%k hat %o erdrosselt,Ο/Η %k κομμάτιασε @[pro2_gr] %o,%k strangolis %o,%k ha estrangulado a %o,%k ahorcó a %o,%k polki %o paran,%k a étouffé %o,%k megfolytotta %o -t,%k ha strozzato %o,%k は %o に絞られた。,%k 은(는) %o 을(를) 목 졸라 죽였다.,%k wurgde %o,%k kvalt %o,"%k udusił@[ao_pl] %o +",%k estrangulou %o,,%k l-a strâns de gât pe %o,%k задушил игрока %o,%k је угушио %o,%k tog strypgrepp på %o,"%o, %k tarafından boğazlandı.",%k вдуши@[adj_1_ua] %o, +%k wasted %o,TXT_OBITUARY23,,,,%o byl@[ao_cs] zničen@[ao_cs] hráčem %k,%k spildte %o,%k hat %o verbraucht,Ο/Η %k σκότωσε @[pro2_gr] %o,%k malŝparis %o,%k ha desechado a %o,%k desechó a %o,%k kulutti %o paran,%k a décharné %o,%k elpusztította %o -t,%k ha distrutto %o,%k は %o に消された。,%k 은(는) %o 을(를) 쓰레기처럼 내다 버렸다.,%k maakte %o koud,%k bortkastet %o,%k roztrwonił@[ao_pl] %o,%k detonou %o,,%k l-a risipit pe %o,%k замочил игрока %o,%k је убио %o,%k slösade bort %o,"%o, %k tarafından harcandı.",%k загна@[adj_1_ua] у могилу %o, +%k body bagged %o,TXT_OBITUARY24,,,,Hráč %k narval %o@[psn1_cs] tělo do pytle,%k tog %o i en pose med kroppen,%k hat %o eingesackt,Ο/Η %k έχωσε @[pro2_gr] %o στη κάσα του/της,%k ensakigis %o,%k ha embolsado a %o,%k embolsó a %o,%k kääri %o paran ruumispussiin,%k a placé %o dans son linceul,%k összecsomagolta %o -t,%k ha mandato %o all'obitorio,%k は %o を死体袋にした。,%k 은(는) %o 의 장례식을 치렀다.,%k stopte %o in een lijkzak,%k lagt %o i likpose,%k spakował@[ao_pl] %o do torby na zwłoki,%k mandou %o para o necrotério,,%k l-a băgat în sac pe %o,%k упаковал игрока %o в мешок для трупов,%k је умртвио %o,%k dödade %o,"%o, %k tarafından öldürüldü.",%k запакува@[adj_1_ua] %o в мішок для трупів, +%k sent %o to Hell,TXT_OBITUARY25,,,,%o byl@[ao_cs] poslán@[ao_cs] do pekla hráčem %k,%k sendte %o til helvede,%k hat %o zur Hölle fahren lassen,Ο/Η %k έστειλε @[pro2_gr] %o στο δίαολο,%k sendis %o al Infero,%k ha enviado a %o al infierno,%k mandó a %o al infierno,%k lähetti %o paran helvettiin,%k a envoyé %o en enfer,%k elküldte %o -t a Pokolba,%k ha spedito %o all'Inferno,%k は %o を地獄に送った。,%o 은(는) %k 덕에 지옥으로 돌아갔다.,%k zond %o naar de hel,%k sendt %o til helvete,%k wysłał@[ao_pl] %o do Piekła,%k mandou %o para o Inferno,,%k l-a trimis pe %o în Infern,%k отправил в ад игрока %o,%k је послао %o до Врага,%k skickade %o till helvetet,"%o, %k tarafından cehenneme gönderildi.",%k посла@[adj_1_ua] %o до дідька лисого, +%k toasted %o,TXT_OBITUARY26,,,,%o byl@[ao_cs] upečen@[ao_cs] hráčem %k,%k skålede %o,%k hat %o geröstet,Ο/Η %k έψησε @[pro2_gr] %o,%k tostis %o,%k ha tostado a %o,%k tostó a %o,%k käristi %o paran,%k a grillé %o,%k megpirította %o -t,%k ha arrostito %o,%k は %o を焼却した。,%o 은(는) %k 덕에 맛있게 구워졌다.,%k roosterde %o,%k ristet %o,%k stostował@[ao_pl] %o,%k tostou %o,,%k l-a prăjit pe %o,%k поджарил игрока %o,%k је тостирао %o,%k rostade %o,"%o, %k tarafından öldürüldü.",%k піджари@[adj_1_ua] %o, +%k snuffed %o,TXT_OBITUARY27,,,,%o byl@[ao_cs] rozsápán@[ao_cs] hráčem %k,%k snusede %o,%k hat %o vernichtet,Ο/Η %k έσβησε @[pro2_gr] %o,%k snufis %o,%k ha aspirado a %o,%k aspiró a %o,%k sammutti %o paran,%k a crevé %o,%k kinyiffantotta %o -t,%k ha spento %o,%k は %o を処刑した。,%o 은(는) %k 에 의해 짓눌려졌다.,%k legde %o om,%k snuffet %o,%k powąchał@[ao_pl] %o,%k apagou %o,,%k l-a mirosit pe %o,%k прикончил игрока %o,%k је угасио %o,%k snusade %o,"%o, %k tarafından öldürüldü.",%k загаси@[adj_1_ua] %o, +%k hosed %o,TXT_OBITUARY28,,,,%o byl@[ao_cs] odstříknut@[ao_cs] hráčem %k,%k sprøjtede %o,%k hat %o eingetütet,Ο/Η %k έονιξε @[pro2_gr] %o σε σφαίρες,%k hosis %o,%k se ha cargado a %o,%k se cargó a %o,%k pesi %o paran,%k a arrosé %o,%k felhúzta %o gatyáját,%k l'ha fatta sopra %o,%k は %o にぶっかけた。,%k 은(는) %o 을(를) 패배로 씻겼다.,%k bespoot %o,%k spylt med vann %o,%k załatwił@[ao_pl] %o,%k metralhou %o,,%k a pus furtunul pe %o,%k расстрелял игрока %o,%k је упскао %o,%k sprutade %o,"%o, %k'in hışmına uğradı.",%o перепало від %k, +%k sprayed %o,TXT_OBITUARY29,,,,%o byl@[ao_cs] postříkán@[ao_cs] hráčem %k,%k sprøjtede %o,%k hat %o pulverisiert,Ο/Η %k ψέκασε @[pro2_gr] %o,%k ŝprucigis %o,%k ha pulverizado a %o,%k pulverizó a %o,%k ruiskutti %o paran,%k a pulvérise %o,%k szétporlasztotta %o -t,%k ha vaporizzato %o,%k は %o を撒き散らした。,%o 의 피는 %k 의 물감으로 쓰였다.,%k besproeide %o,%k sprayet %o,%k rozpryskał@[ao_pl] %o,%k pulverizou %o,,%k l-a pulverizat pe %o,%k распылил игрока %o,%k је испрскао %o,%k sprayade %o,"%o, %k tarafından püskürtüldü.",%k розпили@[adj_1_ua] %o, +%k made dog meat out of %o,TXT_OBITUARY30,,,,%o byl@[ao_cs] hozen@[ao_cs] psům hráčem %k,%k lavede hundekød ud af %o,%k hat Hundefutter aus %o gemacht,Ο/Η %k γύρισε @[pro2_gr] %o σε κιμά,%k farigis hundan viandon el %o,%k ha hecho comida para perros de %o,%k hizo alimento para perros de %o,%k teki %o parasta koiranruokaa,%k a fait de la pâtée pour chien de %o,%k döghúst csinált %o -ból,%k ha fatto di %o polpette,%k は %o を犬の餌にした。,%k 은(는) %o 로 개밥을 만들었다.,%k maakte hondenvlees van %o,%k laget hundekjøtt av %o,%k zrobił@[ao_pl] mięso dla psów z %o,%k fez almôndegas de %o,,%k l-a transformat în mâncare de câini pe %o,%k скормил псам игрока %o,%k је направио псеће месо од %o,%k gjorde hundkött av %o,"%o, %k tarafından köpek etine dönüştürüldü.",%k зтовк@[adj_3_ua] %o до псєчих харчів, +%k beat %o like a cur,TXT_OBITUARY31,,,,%o byl@[ao_cs] zmlácen@[ao_cs] jako pes hráčem %k,%k bankede %o som en skiderik,%k hat %o wie einen Hund geschlagen,Ο/Η %k πλάκοσε @[pro2_gr] %o σαν κοπρίτης,%k batis %o kiel hundaĉon,%k ha pateado a %o como a un perro callejero,,%k huitoi %o parkaa kuin rakkia,%k a battu %o,%k szétverte %o -t mint egy korcsot,%k ha battuto %o come un cane,%k は %o を狂犬の様に扱った。,%o 은(는) %k 에게 똥개처럼 맞았다.,%k sloeg %o als een hond,%k slått %o som en hund,%k pobił@[ao_pl] %o jak kundla,%k espancou %o como um cachorro,%k espancou %o como um cão,%k îl bate pe %o ca pe o jigodie,%k сделал игрока %o как худую свинью,%k је превио %o ко мачку,%k rostade %o,"%o, %k tarafından dövüldü.",%k відби@[adj_1_ua] печінки %o, +%o is excrement,TXT_SELFOBIT1,,,,%o je exkrement,%o er ekskrementer,%o wurde zu Exkrement verarbeitet,@[art_gr] %o είναι κόπρανα,%o estas ekskremento,%o es excremento,,%o on ulostetta,%o est une merde,%o ürülék lett,%o è un escremento,%o はもはや排泄物のようだ。,%o 은(는) 배설물이 되었다.,%o is uitschot,%o er ekskrementer,%o został@[ao_pl] odpadkami,%o virou escremento,,%o e excrement,%o теперь экскремент,%o је сада измет,%o är avföring,%o dışkıdır,%o тепер екскремент, +%o is hamburger,TXT_SELFOBIT2,,,,%o je hamburger,%o er en hamburger,%o ist Hamburger,@[art_gr] %o είναι χάμπουργκερ,%o estas hamburgero,%o es una hamburguesa,,%o on hakkelusta,%o est un hamburger,%o hamburger lett,%o è un hamburger,%o はハンバーガーになった。,%o 은(는) 고기 반죽이 되었다.,%o is hamburger,%o er hamburger,%o został@[ao_pl] hamburgerem,%o virou hambúrguer,,%o e hamburger,%o теперь гамбургер,%o је сада пљескавица,%o är hamburgare,%o hamburgerdir,%o тепер гамбургер, +%o suffered scrotum separation,TXT_SELFOBIT3,,,,%o prodělal@[ao_cs] separaci šourku,%o fik skrotumskæring,%os Eier wurden gebraten,Οι όρχις @[pro4_gr] %o βγήκανε,%o suferis skrotan disigon,%o ha sufrido separación de escroto,%o sufrió separación de escroto,%o kärsii kivespussin erotuksesta,%o a souffert d'une séparation du scrotum,%o heréi szétváltak,%o ha subito la separazione dello scroto,%o の陰嚢は剥離していた。,%o 은(는) 고자가 되었다.,%o onderging scrotumscheiding,%o led pungseparasjon,%o doznał@[ao_pl] oddzielenia moszny,%o sofreu separação escrotal,,%o a suferit o separație de șcrot,%o страдает от потери тестикул,%o му је исечена патка,%o fick pungen separerad,%o skrotum ayrılması yaşadı,%o постражда@[adj_1_ua] від втрати мошонки, +%o volunteered for population control,TXT_SELFOBIT4,,,,%o se zúčastnil@[ao_cs] čistky obyvatelstva,%o meldte sig frivilligt til befolkningskontrol,%o hat sich freiwillig zur Bevölkerungskontrolle gemeldet,@[art_gr] %o εθελώντησε για έλεγχο του πληθυσμού,%o volontulis por loĝantara regado,%o se ha hecho voluntario para control de población,%o se hizo voluntario para control de población,%o ilmoittautui vapaaehtoiseksi väestönhallintaan,%o s'est proposé pour un contrôle de la population,%o önként jelentkezett népességszabályozásra,%o si è offerto per il controllo della popolazione,%o は人口削減政策の実験台に志願した。,%o 은(는) 자연에 의해 낙태 당했다.,%o was vrijwilliger voor bevolkingsbeperking,%o meldte seg frivillig til befolkningskontroll,%o zgłosił@[ao_pl] się na kontrolę ludności,%o se voluntariou para o controle populacional,%o se voluntariou para o controlo populacional,%o a voluntariat pentru controlul populației,%o стал добровольцем в борьбе с перенаселением,%o је волунтирао за контролу популације,%o anmälde sig frivilligt till befolkningskontroll,Nüfus kontrolü için %o gönüllü oldu,%o борется з перенаселенням, +%o has suicided,TXT_SELFOBIT5,,,,%o spáchal@[ao_cs] sebevraždu,%o har begået selvmord,%o hat Selbstmord begangen,@[art_gr] %o έχει αυτοκτονήση,%o sin mortigis,%o se ha suicidado,%o se suicidó,%o on tehnyt itsemurhan,%o s'est suicidé,%o öngyilkos lett,%o si è suicidato,%o は勝手にくたばった。,%o 은(는) 한심하게 자살했다.,%o heeft zelfmoord gepleegd,%o har begått selvmord,%o popełnił@[ao_pl] samobójstwo,%o se suicidou,%o suicidou-se,%o s-a sinucis,Игрок %o самоубился,%o је убио самог себе,%o har begått självmord,%o intihar etti,%o самовби@[adj_2_ua], +%o received the Darwin Award,TXT_SELFOBIT6,,,,%o dostal@[ao_cs] Darwinovu cenu,%o modtog Darwin-prisen,%o hat den Darwinpreis erhalten,@[art_gr] %o κέρδισε το Darwin βραβείο,%o ricevis la Darwin-premion,%o ha recibido el Premio Darwin,%o recibió el Premio Darwin,%o sai Darwin-palkinnon,%o a recu la médaille Darwin,És a Darwin-díj nyertese: %o,%o ha ricevuto il Darwin Award,%o にはダーウィン賞が授与された。,%o 은(는) 다윈상을 받을 자격이 있다.,%o ontving de Darwin Award,%o mottok Darwin-prisen,%o otrzymał@[ao_pl] Nagrodę Darwina,%o ganhou o Prêmio Darwin,,%o a primit Premiul Darwin,Игрок %o получил премию Дарвина,%o је добио Дарвиново признање,%o fick Darwinpriset,%o Darwin Ödülü'nü aldı,%o отрима@[adj_1_ua] премію Дарвіна, +,USE_GENERIC_FONT,This is not a text to be translated but an engine switch for complex languages.,,,,,,,,,,,,,,1,1,,,,,,,,,,,, +,REQUIRED_CHARACTERS,This should list all uppercase characters that are REQUIRED for proper language display. If it is acceptable that accents get omitted a character should NOT be listed here!,,,ÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ,ÅÆØÉ,ÄÖÜẞ,ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ,ĈĜĤĴŜŬ,ÁÉÍÓÚÑÜ,,ÄÖ,ÀÂÇÉÈÊËÎÏÔŒÙÛŸ,ÁÉÍÓÖÚÜŐŰ,ÀÈÉÌÒÙ,,,"ÉËÖ +",ÅÆØÉ,ĄĆĘŁŃÓŚŹŻ,ÁÉÍÓÚÀÃÕÂÊÔÇ,,ĂÎȚÂȘ,АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ,АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ,ÄÖÅÉ,ÖÜÇĞİŞ,АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ, +Full options menu,OPTMNU_FULLOPTIONS,,,,Úplná nastavení,Fuld menu med indstillinger,Alle Optionen,Πλήρες μενού ρυθμίσεον,Plena agordo-menuo,Menú de opciones completo,,Täysi asetusvalikko,Menu options complet,Teljes beállításmenü,Opzioni complete,全オプション欄,전체 옵션 메뉴,Alle opties tonen,Full alternativmeny,Pełne Menu Opcji,Menu de opções completo,,Meniu Setări Complet,Полное меню настроек,,Fullständig alternativmeny,Tam seçenekler menüsü,Повне меню налаштувань, +Simple options menu,OPTMNU_SIMPLEON,,,,Zjednodušená nastavení,Enkel menu med indstillinger,Einfaches Optionsmenü,Απλό μενού ρυθμίσεον,Simpla agordo-menuo,Menú de opciones simplificado,,Yksinkertainen asetusvalikko,Menu options simplifié,Egyszerű beállításmenü,Opzioni base,必要なオプションのみ,간단한 옵션 메뉴,Eenvoudig optiemenu,Enkel meny med alternativer,Proste Menu Opcji,Menu de opções simples,,Meniu Setări Simplificat,Упрощённое меню настроек,,Enkel alternativmeny,Basit seçenekler menüsü,Спрощене меню налаштувань, +Browse Game Config,OPTMNU_OPENCONFIG,,,,Procházet konfigurační soubory,Gennemse spilkonfiguration,Konfigurationsdatei anzeigen,,Foliumi agordojn de ludo,Abrir carpeta de configuración de juego,,Selaa pelin asetuksia,Parcourir configuration,Játék konfiguráció böngészése,Apri le Configurazioni di Gioco,ゲームコンフィグ参照,게임 환경설정 찾아보기,Door gameconfiguratie bladeren,Bla gjennom spillkonfigurasjon,Przeglądaj Ustawienia Gry,Abrir pasta de configuração de jogo,,Caută Configurația Jocului,Открыть файл настроек игры,,Bläddra i spelkonfigurationen,Oyun Yapılandırmasına Gözat,Перегляд налаштувань гри, +Browse Screenshots,OPTMNU_OPENSCREENSHOTS,,,,Procházet snímky obrazovky,Gennemse skærmbilleder,Screenshots anzeigen,,Foliumi ekrankopiojn,Abrir carpeta de capturas de pantalla,,Selaa kuvakaappauksia,Parcourir les captures d'écran,Képernyőképek böngészése,Apri gli Screenshot,クリーンショット参照,스크린샷 찾아보기,Door schermafbeeldingen bladeren,Bla gjennom skjermbilder,Przeglądaj Zrzuty Ekranu,Abrir pasta de capturas de tela,,Caută Capturi de Ecran,Просмотр снимков экрана,,Bläddra bland skärmdumpar,Ekran Görüntülerine Gözat,Перегляд скріншотів, +Browse Saved Games,OPTMNU_OPENSAVES,,,,Procházet uložené hry,Gennemse gemte spil,Spielstände anzeigen,,Foliumi konservitajn ludadojn,Abrir carpeta de partidas guardadas,,Selaa tallennettuja pelejä,Parcourir sauvegardes,Elmentett játékok böngészése,Apri i Giochi Salvati,セーブしたゲーム参照,저장된 게임 찾아보기,Door opgeslagen games bladeren,Bla gjennom lagrede spill,Przeglądaj Zapisy Gry,Abrir pasta de jogos salvos,,Caută Salvări,Просмотр сохранённых игр,,Bläddra bland sparade spel,Kaydedilen Oyunlara Gözat,Перегляд збережень ігр, +Swap mouse buttons,MOUSEMNU_SWAPBUTTONS,,,,Prohodit tlačítka myši,Udskift museknapper,Maustasten vertauschen,,Permuti musbutonojn,Alternar botones de ratón,,Vaihda hiiren painikkeita,Permuter les boutons de la souris,Egérgombok felcserélése,Inverti i comandi del mouse,マウスボタンを反転,마우스 버튼 바꾸기,Muisknoppen verwisselen,Bytt museknapper,Zamień Przyciski Myszki,Trocar botões do mouse,,Schimbă Butoanele Mouse-ului între Ele,Поменять местами кнопки мыши,Замените дугмад миша,Byta musknappar,Fare düğmelerini değiştirme,Поміняти місцями кнопки миші, +,,Additional menu texts,,,,,,,,,,,,,,,,,,,,,,,,,,, +Only modified,OPTVAL_ONLYMODIFIED,,,,Pouze upravené,Kun ændret,Nur modfizierte,,Nur modifitaj,Solo modificados,,Vain muunneltu,Modifié seulement,Csak módosított,Solo modificato,モディファイのみ,수정된 것만,Alleen gewijzigd,Bare endret,Tylko zmodyfikowane,Somente modificado,,Numai modificat,Только изменённый,Само модификовано,Endast ändrat,Yalnızca değiştirilmiş,Тільки в модифікаціях, +Unknown,TXT_UNKNOWN,,,,Neznámé,Ukendt,Unbekannt,Άχνωστο,Nekonata,Desconocido,,Tuntematon,Inconnue,Ismeretlen,Sconosciuto,不明,알 수 없음,Onbekend,Ukjent,Nieznane,Desconhecido,,Necunoscut,Неизвестно,Непознат,Okänd,Bilinmiyor,Невідомо, +HUD,OPTVAL_HUD,,,,,,,,,,,,ATH,,,,,,,,,,,Отображение информации,,,,Інтерфейс, +Automap,OPTVAL_AUTOMAP,,,,Automapa,,,,Aŭtomata mapo,Automapa,,,Carte,Auto-térkép,Automappa,オートマップ,오토맵,,,Automapa,Automapa,,Hartă Computerizată,Автокарта,Аутомап,,,Автокарта, +HUD + Automap,OPTVAL_HUDANDMAP,,,,HUD + Automapa,,,,HUD + Aŭtomata mapo,HUD + Automapa,,,ATH + Carte,HUD + Auto-térkép,HUD + Automappa,HUD+オートマップ,HUD + 오토맵,,,HUD + Automapa,HUD + Automapa,,Interfață + Hartă Computerizată,Интерфейс + автокарта,HUD + Аутомап,,,Інтерфейс + Автокарта, +This savegame needs these files,TXT_SAVEGAMENEEDS,,,,Uložená hra potřebuje tyto soubory,Dette savegame har brug for disse filer,Dieser Spielstand benötigt die folgenden Dateien,Το αρχείο αποθήκευσης χριάζετε αυτά τα αρχεία,Ĉi tiu konservita ludo bezonas ĉi tiujn dosierojn,Esta partida guardada necesita los siguientes archivos,,Tämä pelitallenne tarvitsee nämä tiedostot,Cette sauvegarde nécessite les fichiers suivants:,Ehhez a mentéshez a következő fájlok kellenek:,Questo salvataggio ha bisogno di questi file,このセーブデータには 必要なファイルがある,이 저장 된 게임은 해당 파일이 필요합니다.,Dit spel heeft de volgende bestanden nodig,Dette lagringsspillet trenger disse filene,Ten zapis gry potrzebuje tych plików,Este jogo salvo precisa destes arquivos,Este jogo guardado precisa destes arquivos,Acest joc salvat necesită următoarele fișiere,Данное сохранение требует следующие файлы,Овој сачуваној игри требају ови фајлови,Detta sparande behöver dessa filer,Bu kayıt oyunu şu dosyalara ihtiyaç duyar,Цій грі потрібні такі файли, +Multiplayer Options,OPTMNU_MULTIPLAYER,,,,Multiplayer,Multiplayer-indstillinger,Mehrspieleroptionen,,Agordoj de la plurludanta reĝimo,Opciones del multijugador,,Moninpelivaihtoehdot,Options multijoueurs,Többjátékos lehetőségek,Opzioni multigiocatore,マルチプレイ オプション,멀티플레이어 옵션,Multiplayer Opties,Alternativer for flerspiller,Opcje Trybu Wielu Graczy,Opções de multijogador,,Opțiuni multiplayer,Настройки сетевой игры,Опције за више играча,Alternativ för flera spelare,Çok Oyunculu Seçenekler,Параметри багатокористувацької гри, +Input Options,OPTMNU_INPUT,,,,Vstupní zařízení,Input-indstillinger,Eingabeoptionen,,Enig-agordoj,Opciones de entrada (input),,Syöttöasetukset,Options d'entrée,Beviteli beállítások,Opzioni di ingresso,入力オプション,입력 옵션,In1voeropties,Alternativer for inndata,Opcje Sterowania,Opções de entrada,,Opțiuni de intrare,Настройки ввода,Опције уноса,Inmatningsalternativ,Girdi Seçenekleri,Параметри введення, +System Options,OPTMNU_SYSTEM,,,,Systém,Systemindstillinger,Systemoptionen,,Agordoj de la sistemo,Opciones del sistema,,Järjestelmäasetukset,Options du système,Rendszerbeállítások,Opzioni di sistema,システムオプション,시스템 옵션,Systeem Opties,Systemalternativer,Opcje Systemowe,Opções de sistema,,Opțiuni de sistem,Настройки системы,Системске опције,Systemalternativ,Sistem Seçenekleri,Системні налаштування, +Light Options,OPTMNU_LIGHT,,,,Osvětlení,Lysindstillinger,Beleuchtungsoptionen,,Lum-agordoj,Opciones de iluminación,,Valoasetukset,Options de lumière,Fénybeállítások,Opzioni luce,光源オプション,조명 옵션,Licht Opties,Alternativer for lys,Opcje Oświetlenia,Opções de iluminação,,Opțiuni de lumină,Настройки освещения,Опције осветљења,Alternativ för ljus,Işık Seçenekleri,Параметри освітлення, +Sprite Options,OPTMNU_SPRITE,,,,Sprity,Sprite-indstillinger,Spriteoptionen,,Agordoj de la mov-rastrumoj,Opciones de los «sprites»,,Sprite-asetukset,Options des sprites,Sprite beállítások,Opzioni Sprite,スプライトオプション,스프라이트 옵션,Sprite-opties,Sprite-alternativer,Opcje Sprite'ów,Opções de sprite,,Opțiuni Sprite,Настройки спрайтов,Сприте опције,Alternativ för sprite,Sprite Seçenekleri,Параметри спрайтів, +Coronas,GLPREFMNU_CORONAS,,,,Záře,Coronas,,,Lum-ampoloj,Focos de luz,,Coronat,Corons,Coronák,Corone,光冠,코로나,Corona's,Koronaer,Korony,,,Coronas,Короны,Цоронас,Koronor,Koronalar,Корони, +Appearance,DSPLYMNU_APPEARANCE,,,,Vzhled,Udseende,Spieldarstellung,,Aspekto,Apariencia,,Ulkonäkö,Apparence,Megjelenés,Aspetto,アピアランス,외형,Uiterlijk,Utseende,Wygląd,Aparência,,Aspect,Внешность,Изглед,Utseende,Görünüş,Зовнішній вигляд, +Advanced Display Options,DSPLYMNU_ADVANCED,,,,Grafika (pokročilé),Avancerede visningsindstillinger,Erweiterte Anzeigeoptionen,,Altnivelaj ekran-agordoj,Opciones avanzadas de visualización,,Näytön lisäasetukset,Options d'affichage avancées,Speciális megjelenítési beállítások,Opzioni di visualizzazione avanzate,高度なディスプレイオプション,고급 디스플레이 옵션,Geavanceerde Weergave Opties,Avanserte visningsalternativer,Zaawansowane Opcje Wyświetlania,Opções de vídeo avançadas,,Opțiuni avansate de afișare,Расширенные настройки экрана,Напредне опције приказа,Avancerade visningsalternativ,Gelişmiş Görüntüleme Seçenekleri,Додаткові параметри відображення, +,,IWAD/Game picker,,,,,,,,,,,,,,,,,,,,,,,,,,, +Select which game file to run.,PICKER_SELECT,,,,"Vyberte, jaký herní soubor spustit.","Vælg, hvilket spil du vil spille",Bitte wähle ein Spiel aus.,,Elektu kiun ludodosieron ruli.,,,Valitse suoritettava pelitiedosto.,Sélectionner le jeu à jouer,"Válassza ki, hogy melyik játékfájlt futtassa.",Selezionare il file di gioco da eseguire.,実行するゲームファイルを選択します。,실행할 게임 파일을 선택합니다.,Selecteer welk spel je wilt spelen,Velg hvilket spill du vil spille,"Wybierz, który plik gry uruchomić.",Selecione o arquivo de jogo para rodar.,,Selectați ce fișier de joc să rulați.,Выбор файла игры для запуска.,Изаберите коју датотеку игре желите да покренете.,Välj vilket spel du vill spela,Hangi oyunu oynayacağınızı seçin,Виберіть файл гри для запуску., +Play Game,PICKER_PLAY,,,,Hrát hru,Start spil,Spielen,,Ludi Ludon,,,Pelin pelaaminen,Démarrer le jeu,Játék lejátszása,Esegui gioco,ゲームをプレイする,게임 플레이,Spel starten,Start spill,Graj,Jogar,,Joacă jocul,Играть,Играј игру,Starta spel,Oyunu Başlat,Запустити гру, +Exit,PICKER_EXIT,,,,Odejít,Afslut,Verlassen,,Eliri,,,Poistu,Quitter,Kilépés,Esci,終了,종료,Verlaten,Avslutt,Wyjdź,Sair,,Ieșire,Выход,Изађи,Avsluta,Çıkış,Вихід, +General,PICKER_GENERAL,,,,Obecné,Generelt,Allgemein,,Ĝenerala,,,Yleistä,Général,Általános,Generale,一般,일반,Algemeen,Generelt,Ogólne,Geral,,,Общее,Генерал,Allmänt,Genel,Загальні, +Extra Graphics,PICKER_EXTRA,,,,Grafické doplňky,Ekstra grafik,Extragrafiken,,Ekstra Grafiko,,,Extra Graphics,Graphiques supplémentaires,Extra grafika,Grafica extra,追加グラフィックス,추가 그래픽,Extra afbeeldingen,Ekstra grafikk,Ekstra grafiki,Gráficos extras,,Grafică suplimentară,Доп. графика,Ектра Грапхицс,Extra grafik,Ekstra Grafikler,Додаткова графіка, +Fullscreen,PICKER_FULLSCREEN,,,,Přes celou obrazovku,Fuld skærm,Vollbild,,Plena ekrano,,,Koko näyttö,Plein écran,Teljes képernyő,Schermo intero,フルスクリーン,전체 화면,Volledig scherm,Fullskjerm,Pełny ekran,Tela cheia,,Ecran complet,Полный экран,Цео екран,Fullskärm,Tam Ekran,Повноекранний режим, +Disable autoload,PICKER_NOAUTOLOAD,,,,Zakázat autoload,Deaktiver autoload,Autoload deaktivieren,,Malvalidigi aŭtomatan ŝargon,,,Poista automaattinen lataus käytöstä,Désactiver le chargement automatique,Automatikus betöltés kikapcsolása,Disabilita il caricamento automatico,オートロードを無効にする,자동 로드 비활성화,Autoload uitschakelen,Deaktiver autolading,Wyłącz auto-ładowanie,Desativar autocarregamento,,Dezactivați încărcarea automată,Отключить автозагрузку,Онемогући аутоматско учитавање,Inaktivera autoload,Otomatik yükleme yok,Вимкнути автозавантаження, +Don't ask me again,PICKER_DONTASK,,,,Již se neptat,Spørg mig ikke igen,Nicht nochmal fragen,,Ne demandu min denove,,,Älä kysy uudestaan,Ne me demandez plus rien,Ne kérdezz újra,Non chiedermelo più,二度と聞くな,다시 묻지 마세요,Vraag me niet opnieuw,Ikke spør meg igjen,Nie pytaj ponownie,Não me pergunte de novo,,Nu mă mai întrebați din nou,Не спрашивать снова,Не питај ме поново,Fråga mig inte igen,Bir daha sorma.,Не запитуйте мене більше, +Lights,PICKER_LIGHTS,,,,Světla,Lys,Lichtdefinitionen,,Lumoj,,,Valot,Lumières,Fények,Luci,ライト,조명,Verlichting,Lysdefinisjoner,Oświetlenie,Luzes,,Lumini,Освещение,Светла,Definitioner av ljus,Işık tanımları,Освітлення, +Brightmaps,PICKER_BRIGHTMAPS,,,,,,,,Helomapoj,,,Brightmaps,Cartes lumineuses,Brightmaps,Mappe luminose,ブライトマップ,브라이트맵,Heldermaps,Lyskart,Mapowanie świateł,,,,Карты освещения,Бригхтмапс,Ljuskartor,Brightmaps,Яскраві карти, +Widescreen,PICKER_WIDESCREEN,,,,,,Breitbildunterstützung,,Larĝekrana,,,Laajakuva,Écran large,Szélesképernyő,Schermo largo,ワイドスクリーン,와이드스크린,Breedbeeld,Bredskjerm,Szeroki ekran,,,,Широкий экран,Широки екран,Bredbildsskärm,Geniş Ekran,Широкоформатний, +Additional Parameters:,PICKER_ADDPARM,,,,Dodatečné parametry:,Yderligere parametre:,Zusätzliche Parameter,,Aldonaj Parametroj,,,Lisäparametrit:,Paramètres supplémentaires :,További paraméterek:,Parametri aggiuntivi:,追加パラメータ,환영합니다: %s!,Extra parameters:,Ytterligere parametere:,Dodatkowe parametry:,Parâmetros adicionais:,,Parametrii suplimentari:,Доп. параметры:,Додатни параметри:,Ytterligare parametrar:,Ek Parametreler:,Додаткові параметри:, +Welcome to %s!,PICKER_WELCOME,,,,Vítejte v enginu %s!,Velkommen til %s!,Willkommen bei %s!,,Bonvenon en %s!,,,Tervetuloa %s!,Bienvenue à %s !,Üdvözöljük a %s!,Benvenuti a %s!,ようこそ: %s!,에 오신 것을 환영합니다!,Welkom bij %s!,Velkommen til %s!,Witaj w %s!,Boas vindas ao %s!,,Bine ați venit la %s!,Добро пожаловать в %s!,Добродошли у %s!,Välkommen till %s!,S'ye hoş geldiniz!,Ласкаво просимо до %s!, +Version %s,PICKER_VERSION,,,,Verze %s,,,,Versio %s,,,Versio %s,,Verzió %s,Versione %s,バージョン %s,버전 %s,Versie %s,Versjon %s,Wersja %s,Versão %s,,Versiunea %s,Версия %s,Верзија %s,,Sürüm %s,Версія %s, +Rendering API,PICKER_PREFERBACKEND,,,,Renderovací API,,Render API,,Bildigado de API,API de renderizado,,Renderöinti API,API de rendu,Renderelő API,API di rendering,優先レンダリングAPI,기본적인 API 랜더링,,,API renderowania,API de renderização,,API Video Preferat,API для рендеринга,АПИ приказивања,API för rendering,,API для візуалізації, +Game,PICKER_TAB_PLAY,,,,Hra,Spil,Spiel,,Ludo,Juego,,Peli,Jeu,Játék,Gioco,ゲーム,게임,Spel,Spill,Gra,Jogo,,Joc,Игра,Игра,Spel,Oyun,Гра, +Enable this controller,JOYMNU_JOYENABLE,Option to enable or disable individual controllers/joysticks when configuring it in the Controller Options menu,,,Povolit tento ovladač,Aktivér denne controller,Diesen Controller aktivieren,,Ŝalti ĉi tiun ludregilon,Habilitar este controlador,,Aktivoi tämä ohjain,Activer ce contrôleur,Engedélyezze ezt a vezérlőt,Abilitare questo controllore,このコントローラーを有効にする,이 컨트롤러 활성화,Deze controller inschakelen,Aktiver denne kontrolleren,,,,Activați acest controler,Включить этот контроллер,Омогућите овај контролер,Aktivera denna styrenhet,Bu denetleyiciyi etkinleştirin,Увімкніть цей контролер, +Open Main Menu,CNTRLMNU_OPEN_MAIN,,,,Otevřít hlavní menu,Åbn hovedmenuen,Hauptmenü öffnen,,Malfermi Ĉefan Menuon,Abrir el menú principal,,Avaa päävalikko,Ouvrir le menu principal,Főmenü megnyitása,Aprire il menu principale,メインメニューを開く,메인 메뉴 열기,Hoofdmenu openen,Åpne hovedmenyen,,,,Deschideți meniul principal,Открыть главное меню,Отворите главни мени,Öppna huvudmenyn,Ana Menüyü Aç,Відкрити головне меню, \ No newline at end of file diff --git a/wadsrc/static/language.csv b/wadsrc/static/language.csv index e0b59d9a5b8..81a41967e44 100644 --- a/wadsrc/static/language.csv +++ b/wadsrc/static/language.csv @@ -1,82 +1,92 @@ -default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,pl,pt,ptg,ro,ru,sr -,,Miscellaneous,,,,,,,,,,,,,,,,,,,,, -A secret is revealed!,SECRETMESSAGE,,,,Tajemství odhaleno!,Ein Geheimnis wurde enthüllt!,Ένα μυστικό αποκαλύφθηκε!,Sekreto estas malkaŝita!,¡Se ha revelado un secreto!,,Sala löydetty!,Vous avez découvert un secret!,Egy rejtekhely feltárva!,È stato svelato un segreto! ,シークレットを解き明かした!,비밀 발견!,Een geheim is onthuld!,Znaleziono sekret!,Um segredo foi revelado!,,Ai găsit un secret!,Обнаружен тайник!,Тајна је откривена! +default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,da,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,no nb,pl,pt,ptg,ro,ru,sr,sv,tr,uk +,,Miscellaneous,,,,,,,,,,,,,,,,,,,,,,,,,, +Press a key.,PRESSKEY,,,,Stiskni klávesu.,Tryk på en tast.,Drücke eine Taste,Πάτα οποιοδήποτε πλήκτρο.,Premu klavon.,Presiona una tecla.,,Paina jotain näppäintä.,Appuyez sur une touche.,Nyomjon meg egy gombot.,Premi un tasto.,何かキーを押せ,키를 누르시오.,Druk op een toets.,Trykk på en tast.,Wciśnij dowolny klawisz.,Aperte uma tecla.,Carrega numa tecla qualquer.,Apasă o tastă.,Нажмите любую клавишу.,Притисните било који тастер.,Tryck på en tangent.,Bir tuşa bas.,Натисніть будь яку клавішу. +A secret is revealed!,SECRETMESSAGE,,,,Nalezl[@ao_cs] jsi skrýš!,En hemmelighed bliver afsløret!,Ein Geheimnis wurde enthüllt!,Ένα μυστικό αποκαλύφθηκε!,Vi trovis sekretejon!,¡Lugar secreto descubierto!,,Sala löydetty!,Vous avez découvert un secret!,Egy rejtekhely feltárva!,È stato svelato un segreto! ,シークレットを解き明かした!,비밀 발견!,Een geheim is onthuld!,En hemmelighet er avslørt!,Znaleziono sekret!,Segredo revelado!,,Ai găsit un secret!,Обнаружен тайник!,Откривена тајна!,En hemlighet avslöjas!,Bir sır açığa çıkıyor!,Знайдено схованку! "Useless mode ON. -",D_DEVSTR,,,,Zbytečný režim ZAP.,Nutzloser Modus EIN.,Άχρηστη λειτουργία είναι ΑΝΟΙΧΤΗ,Senutila reĝimo AKTIVA.,"Modo inútil ACTIVADO. +",D_DEVSTR,,,,Zbytečný režim ZAP.,Ubrugelig tilstand slået til.,Nutzloser Modus EIN.,Άχρηστη λειτουργία είναι ΑΝΟΙΧΤΗ,Senutila reĝimo ŜALTITA.,"Modo inútil ACTIVADO. ",,Hyödytön tila PÄÄLLÄ.,"Mode inutile ON. ",Haszontalan mód BE.,"Modalità inutile ATTIVATA. -",このモードは使わないでおけ,쓸모없는 모드 켬.,Nutteloze modus AAN.,Tryb bezużyteczny WŁĄCZONY.,"Modo inútil ATIVADO. -",,Modul inutil ACTIVAT.,Включён режим разработчика.,Програмерски режим УКЉУЧЕН. -Press a key.,PRESSKEY,,,,Stiskni klávesu.,Drücke eine Taste,Πάτα οποιοδήποτε πλήκτρο.,Premu klavon.,Presiona una tecla.,,Paina jotain näppäintä.,Appuyez sur une touche.,Nyomj meg egy gombot.,Premi un tasto.,何かキーを押せ,키를 누르시오.,Druk op een toets.,Wciśnij dowolny klawisz.,Aperte qualquer tecla.,Carrega numa tecla qualquer.,Apasă o tastă.,Нажмите любую клавишу.,Притисните тастер. -Press Y or N.,PRESSYN,,,,Stiskni Y nebo N.,Drücke Y oder N.,"Πάτα Y ή N -",Premu Y aŭ N.,Presiona Y ó N.,,Paina Y tai N.,Appuyez sur Y ou N.,Nyomj Y-t vagy N-t.,Premi Y oppure N.,YかNで答えろ,Y키 또는 N키를 누르시오.,Druk op Y of N.,Wciśnij Y lub N.,Aperte Y ou N.,Carrega Y ou N.,Apasă Y sau N.,Нажмите Y или N.,Притисните Y или N. +",このモードは使わないでおけ,쓸모없는 모드 켬.,Nutteloze modus AAN.,"Ubrukelig modus PÅ. +",Tryb bezużyteczny WŁĄCZONY.,"Modo inútil ATIVADO. +",,Modul inutil ACTIVAT.,Бесполезный режим ВКЛЮЧЁН.,Програмерски режим УКЉУЧЕН.,"Oanvändbart läge på. +","Yararsız mod AÇIK. +",Увімкнено режим розробника "Are you sure you want to -quit this great game?",QUITMSG,,,,"Jsi si jist@[adj_cs], že chceš opustit tuto skvělou hru?","Willst du dieses großartige Spiel -wirklich beenden?",Είσαι σίγουρος ότι θέλεις να κλείσεις αυτο το σπουδαίο παιχνίδι;,"Ĉu vi certas, ke vi volas ĉesigi -ĉi tiun bonegan ludon?",¿Estás segur@[ao_esp] que deseas salir de este gran juego?,,Haluatko varmasti lopettaa tämän mahtavan pelin?,"Voulez-vous vraiment +quit this great game?",QUITMSG,,,,"Jsi si jist@[adj_cs], že chceš opustit tuto skvělou hru?","Er du sikker på, at du vil forlade +dette fantastiske spil?","Willst du dieses großartige Spiel +wirklich beenden?",Είσαι σίγουρος ότι θέλεις να κλείσεις αυτο το σπουδαίο παιχνίδι;,"Ĉu vi certas, ke vi volas mallanĉi +ĉi tiun bonegan ludon?","¿Estás segur@[ao_esp] de que +deseas salir de este juegazo?",,Haluatko varmasti lopettaa tämän mahtavan pelin?,"Voulez-vous vraiment quitter cet excellent jeu?","Biztosan kilépnél ebből a nagyszerű játékból?","Sei sicuro di volere uscire da questo grandioso gioco?","本当にこの素晴らしい運命を 終わらせるのですね?",진짜 이 개쩌는 게임을 꺼버릴려고?,"Weet je zeker dat je wilt stoppen -met dit geweldige spel?","Czy na pewno chcesz -wyjść z tej świetnej gry?","Tem certeza que deseja sair +met dit geweldige spel?",Er du sikker på at du vil avslutte dette flotte spillet?,"Czy na pewno chcesz +wyjść z tej świetnej gry?","Deseja mesmo sair deste excelente jogo?","Tem a certeza que deseja sair deste excelente jogo?",Ești sigur că vrei să ieși din acest joc grozav?,"Ты действительно хочешь выйти -из этой замечательной игры?",Да ли заиста желиш да одустанеш од ове чудесне игре? -Yes,TXT_YES,,,,Ano,Ja,Ναι,Jes,Sí,,Kyllä,Oui,Igen,Si,はい,네,Ja,Tak,Sim,,Da,Да,Да -No,TXT_NO,,,,Ne,Nein,Όχι,Ne,No,,Ei,Non,Nem,No,いいえ,아니요,Nee,Nie,Não,,Nu,Нет,Не +из этой замечательной игры?",Желиш ли заиста да изађеш из ове чудесне игре?,Är du säker på att du vill sluta med detta fantastiska spel?,Bu harika oyunu bırakmak istediğine emin misin?,Ти дійсно хочеш вийти з цієї прекрасної гри? "You can't do load while in a net game! -Press a key.",LOADNET,"In some languages, it may make more sense to translate “Press a key” as “Press any key.”",,,"Nemůžeš načíst hru, když hraješ síťovou hru! +Press a key.",LOADNET,"In some languages, it may make more sense to translate “Press a key” as “Press any key.”",,,"Během síťové hry nelze načíst hru! -Stiskni libovolnou klávesu.","Du kannst während eines Netzwerkspiels keinen Spielstand laden. +Stiskni libovolnou klávesu.","Du kan ikke indlæse, mens du er i et netspil! + +Tryk på en tast.","Du kannst während eines Netzwerkspiels keinen Spielstand laden. Drücke eine Taste","Δέν μπορίς να φορτώσεις σε ένα δικτυακό παιχνίδι ! -Πάτα οπιοδήποτε πλήκτρο.","Oni ne povas ŝargi en ret-ludo! +Πάτα οπιοδήποτε πλήκτρο.","Vi ne povas ŝargi dum retludado! -Premu klavon.","¡No puedes cargar en una partida en línea! +Premu klavon.","¡No puedes cargar una partida mientras juegas en línea! Presiona una tecla.",,"Et voi ladata verkkopelin aikana! Paina jotain näppäintä.","Impossible de charger une partie pendant un jeu en réseau! -Appuyez sur une touche.","Nem tudsz tölteni miközben net játékban vagy! +Appuyez sur une touche.","Nem tudsz betölteni miközben net játékban vagy! -Nyomj meg egy gombot.","Non puoi caricare una partita durante un netgame! +Nyomj meg egy gombot.","Non puoi caricare una partita durante una partita in rete! Premi un tasto.","オンラインプレイでは ロードできない! 何かキーを押せ ","멀티플레이 중엔 게임을 불러올 수 없습니다! -키를 누르시오.","Je kunt niet laden tijdens een netspel! +키를 누르시오.","Je kunt niet laden tijdens een netwerkspel! + +Druk op een toets.","Du kan ikke laste mens du er i et nettspill! -Druk op een toets.","Nie możesz wczytać podczas gry sieciowej! +Trykk på en tast.","Nie możesz wczytać podczas gry sieciowej! -Wciśnij dowolny klawisz.","Não pode carregar um jogo durante um jogo em rede! +Wciśnij dowolny klawisz.","Impossível carregar um jogo durante uma partida em rede! -Aperte qualquer tecla.","Não pode carregar um jogo durante um jogo em rede! +Aperte uma tecla.","Não pode carregar um jogo durante um jogo em rede! Carrega numa tecla qualquer.","Nu poți face o încărcare în timpul unui joc în rețea! Apasă orice tastă.","Невозможно загрузить сохранение в сетевой игре! -Нажмите любую клавишу.","Не можете учитати игру током мрежне игре! +Нажмите любую клавишу.","Не можете да учитате чување током мрежне игре! -Притисните тастер." +Притисните тастер.","Du kan inte göra lastning när du är i ett nätspel! +Tryck på en tangent.",Bir ağ oyunundayken yükleme yapamazsınız! Bir tuşa basın.,"Неможливо завантажити збереження під час мережевої гри! + +Натисніть будь яку клавішу." "You can't quickload during a netgame! -Press a key.",QLOADNET,,,,"Nemůžeš rychle načíst hru, když hraješ síťovou hru! +Press a key.",QLOADNET,,,,"Během síťové hry nelze rychle načíst hru! + +Stiskni libovolnou klávesu.","Du kan ikke quickloade under et netspil! -Stiskni libovolnou klávesu.","Du kannst während eines Netzwerkspiels nicht schnellladen. +Tryk på en tast.","Du kannst während eines Netzwerkspiels nicht schnellladen. Drücke eine Taste","Δέν μπορίς να κάνεις γρήγορη φόρτωση σε ένα δικτυακό παιχνίδι ! -Πάτα οποιδήποτε πλήκτρο.","Oni ne povas rapidŝargi en ret-ludo! +Πάτα οποιδήποτε πλήκτρο.","Vi ne povas rapidŝargi dum retludado! -Premu klavon.","¡No puedes cargar una partida mientras juegues en línea! +Premu klavon.","¡No puedes cargar un guardado rápido mientras juegas en línea! Presiona una tecla.",,"Et voi pikaladata verkkopelin aikana! @@ -85,37 +95,45 @@ pendant un jeu en réseau! Appuyez sur une touche.","Nem tudsz gyorstölteni miközben net játékban vagy! -Nyomj meg egy gombot.","Non puoi fare un quickload durante un netgame! +Nyomj meg egy gombot.","Non puoi fare un quickload durante una partita in rete! Premi un tasto.","オンラインプレイでは ロードできない! 何かキーを押せ","멀티플레이 중엔 빠른 불러오기를 할 수 없습니다! -키를 누르시오.","Je kunt niet snel laden tijdens een netspel! +키를 누르시오.","Je kunt niet snelladen tijdens een netwerkspel! -Druk op een toets.","Nie możesz użyć szybkiego wczytania podczas gry sieciowej! +Druk op een toets.","Du kan ikke hurtiglaste under et nettspill! -Wciśnij dowolny klawisz.","Não pode carregar um quickload durante um jogo em rede! +Trykk på en tast.","Nie możesz użyć szybkiego wczytania podczas gry sieciowej! -Aperte qualquer tecla.","Não pode carregar um quickload durante um jogo em rede! +Wciśnij dowolny klawisz.","Impossível carregar um jogo rapidamente durante uma partida em rede! + +Aperte uma tecla.","Não pode carregar um quickload durante um jogo em rede! Carrega numa tecla qualquer.","Nu poți face o încărcare rapidă în timpul unui joc în rețea! Apasă orice tastă.","Невозможно загрузить быстрое сохранение в сетевой игре! -Нажмите любую клавишу.","Не можете брзо учитати игру током мрежне игре! +Нажмите любую клавишу.","Не можете да учитате брзо чување током мрежне игре! + +Притисните тастер.","Du kan inte snabblasta under ett nätspel! +Tryck på en tangent.","Bir ağ oyunu sırasında hızlı yükleme yapamazsınız! +Bir tuşa basın.","Неможливо завантажити швидке збереження під час мережевої гри! -Притисните тастер." +Натисніть будь яку клавішу." "You haven't picked a quicksave slot yet! -Press a key.",QSAVESPOT,,,,"Ještě jsi nevybral slot pro rychlé uložení! +Press a key.",QSAVESPOT,,,,"Ještě nebyl vybrán slot pro rychlé uložení! -Stiskni libovolnou klávesu.","Du hast noch keine Schnellspeicherposition gewählt. +Stiskni libovolnou klávesu.","Du har endnu ikke valgt en quicksave-post! + +Tryk på en tast.","Du hast noch keine Schnellspeicherposition gewählt. Drücke eine Taste","Δέν έχεις επιλέξει μια θυρίδα γρήγορης αποθήκευσεις ακόμα! -Πάτα οποιδήποτε πλήκτρο.","Vi ankoraŭ ne elektis rapidkonservingon! +Πάτα οποιδήποτε πλήκτρο.","Vi ankoraŭ ne elektis rapidkonservujon! Premu klavon.","¡No has seleccionado una ranura de guardado rápido! @@ -132,217 +150,40 @@ Premi un tasto.","オンラインプレイでは セーブできない! 何かキーを押せ","멀티플레이 중엔 빠른 저장을 할 수 없습니다! -키를 누르시오.","Je hebt nog geen snelspaarplaats gekozen! - -Druk op een toets.","Nie wybrano jeszcze miejsca do szybkiego zapisu! - -Wciśnij dowolny klawisz.","Você ainda não escolheu um slot de quicksave! - -Aperte qualquer tecla.","Você ainda não escolheu um slot de quicksave! - -Carrega numa tecla qualquer.","Nu ai ales un slot pentru incărcare rapidă încă! - -Apasă orice tastă.","У Вас не выбран слот быстрого сохранения! - -Нажмите любую клавишу.","Нисте још покупили слот за брзо чување! - -Притисните тастер." -"You can't save if you aren't playing! - -Press a key.",SAVEDEAD,,,,"Nemůžeš ukládat pokud nehraješ! - -Stiskni libovolnou klávesu.","Du kannst nicht speichern, wenn du nicht spielst. +키를 누르시오.","Je hebt nog geen sneloplagplek gekozen! -Drücke eine Taste","Δέν μπορείς να αποθηκέυσεις άμα δέν παίζεις! +Druk op een toets.","Du har ikke valgt en hurtiglagringsplass ennå! -Πάτα οποιδήποτε πλήκτρο.","Vi ne povas konservi, kiam vi ne ludas! +Trykk på en tast.","Nie wybrano jeszcze miejsca do szybkiego zapisu! -Premu klavon.","¡No puedes guardar si no estás jugando! +Wciśnij dowolny klawisz.","Você ainda não escolheu um espaço de salvamento rápido! -Presiona una tecla.",,"Et voi tallentaa, jos et ole pelissä! +Aperte uma tecla.","Você ainda não escolheu um slot de quicksave! -Paina jotain näppäintä.","Vous ne pouvez pas sauvegarder si vous ne jouez pas! - -Appuyez sur une touche.","Nem tudsz menteni ha nem is játszol! - -Nyomj meg egy gombot.","Non puoi salvare se non stai giocando! - -Premi un tasto.","プレイ中でないとセーブできない! - -何かキーを押せ","게임을 플레이 중이지 않을 때는 게임을 저장할 수 없습니다! - -키를 누르시오.","Je kunt niet opslaan als je niet speelt! - -Druk op een toets.","Nie możesz zapisać, jeśli nie grasz! - -Wciśnij dowolny klawisz.","Você não pode salvar se não estiver jogando! - -Aperte qualquer tecla.","Você não pode salvar se não estiver a jogar! - -Carrega numa tecla qualquer.","Nu poți salva jocul dacă nu joci! - -Apasă orice tastă.","Невозможно сохранить игру, не начав её! - -Нажмите любую клавишу.","Не можете сачувати игру ако не играте! - -Притисните тастер." -"Quicksave over your game named - -'%s'? - -Press Y or N.",QSPROMPT,,,,"Rychle uložit přes tvoji hru s názvem - -'%s'? +Carrega numa tecla qualquer.","Nu ai ales un slot pentru încărcare rapidă încă! -Stiskni Y nebo N.","Überschreibe %s mit einem Schnellspeicherspielstand? +Apasă orice tastă.","Не выбрана ячейка быстрого сохранения! -Drücke Y oder N.","Κάνε γρήγορυ αποθήκευση στή θυρίδα με το όνομα +Нажмите любую клавишу.","Нисте још изабрали слот за брзо чување! -'%s'? - -Πάτα Y ή N","Ĉu rapidkonservu super via ludo, ke nomita - -'%s'? - -Premu Y aŭ N.","¿Deseas guardar sobre tu partida llamada - -'%s'? - -Presiona Y ó N.",,"Haluatko tallentaa pelin %s päälle? - -Paina Y tai N.","Sauvegarde rapide sur le fichier - -'%s'? - -Appuyez sur Y ou N.","Gyorsmenteni akarsz az alábbi mentésed alatt - -'%s'? - -Nyomj Y-t vagy N-t.","Sovrascrivere il salvataggio - -'%s'? - -Premi Y oppure N.","この名前で上書きするのか? - -'%s' - -Y か N で答えろ","빠른 저장을 하시겠습니까? - -'%s' - -Y키 또는 N키를 누르시오.","Snel opslaan over je spel genaamd - -'%s'? - -Druk op Y of N.","Szybko nadpisać grę - -„%s”? - -Wciśnij Y lub N.","Salvar sobre seu jogo chamado - -'%s'? +Притисните тастер.","Du har inte valt en plats för snabbsparning ännu! +Tryck på en tangent.","Henüz bir hızlı kaydetme yuvası seçmediniz! +Bir tuşa basın.","Не вибраний слот для швидкого збереження! -Aperte Y ou N.","Gravar sobre o seu jogo chamado - -'%s'? - -Carrega Y ou N.","Salvare rapidă peste jocul numit - -'%s'? - -Apasă Y sau N.","Перезаписать быстрое сохранение - -«%s»? - -Нажмите Y или N.","Желите брзо чување за игру под именом - -„%s“? - -Притисните Y или N." -"Do you want to quickload the game named - -'%s'? - -Press Y or N.",QLPROMPT,,,,"Přeješ si rychle načíst hru s názvem - -'%s'? - -Stiskni Y nebo N.","Möchtest du den Spielstand %s schnellladen? - -Drücke Y oder N.","Θέλεις να φορτώσες το παιχνίδι με το όνομα - -'%s'? - -Πάτα Y ή N","Ĉu vi volas rapidŝargi la ludon, ke nomita - -'%s'? - -Premu Y aŭ N.","¿Quieres cargar la partida llamada - -'%s'? - -Presiona Y ó N.",,"Haluatko pikaladata pelin %s? - -Paina Y tai N.","Voulez-vous charger la sauvegarde - -'%s'? - -Appuyez sur Y ou N.","Gyorstölteni akarod ezt a mentést - -'%s'? - -Nyomj Y-t vagy N-t.","Vuoi fare un quickload della partita - -'%s'? - -Premi Y oppure N.","この名前のデータをロードするのか? - -'%s' - -Y か N で答えろ","빠른 불러오기를 하시겠습니까? - -'%s' - -Y키 또는 N키를 누르시오.","Wil je het spel snel laden met de naam - -'%s'? - -Druk op Y of N.","Czy chcesz wczytać szybki zapis - -„%s”? - -Wciśnij Y lub N.","Deseja carregar o jogo chamado - -'%s'? - -Aperte Y ou N.","Deseja carregar o jogo chamado - -'%s'? - -Carrega Y ou N.","Dorești să încarci rapid jocul numit - -'%s' - -Apasă Y sau N.","Загрузить быстрое сохранение - -«%s»? - -Нажмите Y или N.","Желите брзо учитавање за игру под именом - -„%s“? - -Притисните Y или N." +Натисніть будь яку клавішу." "You can't start a new game while in a network game. -Press a key.",NEWGAME,,,,"Nemůžeš začít novou hru dokud jsi v síťové hře. +Press a key.",NEWGAME,,,,"Během síťové hry nelze začít novou hru. -Stiskni libovolnou klávesu.",Du kannst während eines Netzwerkspiels kein neues Spiel starten.,"Δέν μπορείς να ξεκινήσεις ένα νέο παιχνίδι ενώ εισαι σε ένα δικτυακό παιχνίδι. +Stiskni libovolnou klávesu.","Du kan ikke starte et nyt spil +mens du er i et netspil. -Πάτα οποιδήποτε πλήκτρο.","Oni ne povas lanĉi novan ludon, -kiam en ret-ludo. +Tryk på en tast.",Du kannst während eines Netzwerkspiels kein neues Spiel starten.,"Δέν μπορείς να ξεκινήσεις ένα νέο παιχνίδι ενώ εισαι σε ένα δικτυακό παιχνίδι. -Premu klavon.","No puedes iniciar un nuevo juego mientras estés jugando en línea. +Πάτα οποιδήποτε πλήκτρο.","Vi ne povas lanĉi novan ludadon dum retludo. + +Premu klavon.","No puedes iniciar una nueva partida mientras estás jugando en línea. Presiona una tecla.",,"Et voi aloittaa uutta peliä verkkopelin aikana. @@ -361,13 +202,15 @@ Premi un tasto.","オンラインプレイでは勝手にニューゲームは 何かキーを押せ","멀티플레이 중엔 새로운 게임을 시작할 수 없습니다. 키를 누르시오.","Je kunt geen nieuw spel starten -terwijl je in een netwerkspel zit. +wanneer je in een netwerkspel zit. -Druk op een toets.","Nie możesz zacząć nowej gry +Druk op een toets.","Du kan ikke starte et nytt spill mens du er i et nettverksspill. + +Trykk på en tast.","Nie możesz zacząć nowej gry podczas gry sieciowej. -Wciśnij dowolny klawisz.","Você não pode iniciar um novo jogo -durante um jogo em rede. +Wciśnij dowolny klawisz.","Impossível iniciar um novo jogo +durante uma partida em rede. Aperte uma tecla.","Não podes iniciar um novo jogo durante um jogo em rede. @@ -378,32 +221,39 @@ rețea. Apasă orice tastă.","Невозможно начать новую игру при активной сетевой игре. -Нажмите любую клавишу.","Не можете започети нову игру током мрежне игре. +Нажмите любую клавишу.","Не можете да започнете +нову игру током мрежне игре. + +Притисните тастер.","Du kan inte starta ett nytt spel när du är i ett nätspel. +Tryck på en tangent.","Bir ağ oyunundayken yeni bir oyun başlatamazsınız. +Bir tuşa basın.","Ви не можете розпочати нову гру під час мережевої гри. -Притисните тастер." +Натисніть будь яку клавішу." "Are you sure? This skill level isn't even remotely fair. Press Y or N.",NIGHTMARE,,,,"Jsi si jist? Tato úroveň obtížnosti není ani trochu fér. -Stiskni Y nebo N.","Bist du sicher? Dieser Schwierigkeitsgrad ist +Stiskni Y nebo N.","Er du sikker? Dette færdighedsniveau er ikke engang tilnærmelsesvis fair. + +Tryk på Y eller N.","Bist du sicher? Dieser Schwierigkeitsgrad ist nicht einmal annähernd fair. Drücke Y oder N.","Είσαι σίγουρος ? Αυτό το επίπεδο δυσκολίας δεν είναι καθόλου δίκαιη. -Πάτα Y ή N","Ĉu vi certas? Ĉi tiu lertecnivelo +Πάτα Y ή N","Ĉu vi certas? Ĉi tiu malfacileco ne estas eĉ iomete justa. Premu Y aŭ N.","¿Estás segur@[ao_esp]? Este nivel de dificultad no es ni remotamente justo. -Presiona Y ó N.",,"Oletko varma? Tämä vaikeustaso ei ole edes vähääkään reilu. +Presiona Y o N.",,"Oletko varma? Tämä vaikeustaso ei ole edes vähääkään reilu. Paina Y tai N.","Vous êtes sur? Ce niveau de difficulté est vraiment impitoyable! Appuyez sur Y ou N.","Biztos vagy benne? Ez a nehézségi szint -egyáltalán nem fer. +távolról sem fair. Nyomj Y-t vagy N-t.","Sei sicuro? Questo livello di difficoltà è dannatamente difficile. @@ -413,10 +263,13 @@ Premi Y oppure N.","本気か? このスキルは Y か N で答えろ","진심입니까? 이 난이도는 매우 어렵습니다. -Y키 또는 N키를 누르시오.","Weet je het zeker? Dit vaardigheidsniveau -Is lang niet eerlijk. +Y키 또는 N키를 누르시오.","Weet je het zeker? Dit moeilijkheidsniveau +is niet eens eerlijk. + +Druk op Y of N.","Er du sikker? Dette ferdighetsnivået +er ikke i det hele tatt rettferdig. -Druk op Y of N.","Czy jesteś pewien? Ten poziom umiejętności +Trykk på Y eller N.","Czy jesteś pewien? Ten poziom umiejętności nie jest nawet bliski sprawiedliwego. Wciśnij Y lub N.","Tem certeza? Este nível de dificuldade @@ -429,11 +282,19 @@ Carrega Y ou N.","Ești sigur? Acest nivel de dificultate nu e nici pe departe cinstit. Apasă Y sau N.","Уверены? Этот уровень сложности -даже не близок к честному. +даже отдалённо не честен. -Нажмите Y или N.","Јесте ли сигурни? Овај ниво умећа није нимали фер. +Нажмите Y или N.","Сигурни сте? Овај ниво тежине +није нимали фер. -Притисните Y или N." +Притисните Y или N.","Är du säker? Den här färdighetsnivån +är inte ens tillnärmelsevis rättvis. +Tryck på Y eller N.","Emin misiniz? Bu beceri seviyesi +hiç adil değil. + +Y veya N'ye basın.","Впевнений? Цей рівень складності навіть близько не стоїть до чесного. + +Натисніть Y або N." "This is the shareware version of Doom. You need to order the entire trilogy. @@ -442,7 +303,11 @@ Press a key.",SWSTRING,,,,"Toto je shareware verze Dooma. Musíš si objednat celou trilogii. -Stiskni libovolnou klávesu.","Dies ist die Shareware-Version von Doom. +Stiskni libovolnou klávesu.","Dette er shareware-versionen af Doom. + +Du skal bestille hele trilogien. + +Tryk på en tast.","Dies ist die Shareware-Version von Doom. Hierfür musst du die komplette Trilogie bestellen. @@ -450,13 +315,13 @@ Drücke eine Taste","Αυτή είναι η Shareware έκδοση του Doom. Πρέπει να παραγγείλετε την ολόκληρη τριλογία. -Πάτα οποιδήποτε πλήκτρο.","Ĉi tio estas la propagaĵa versio de Doom. +Πάτα οποιδήποτε πλήκτρο.","Ĉi tiu estas la propagaĵa versio de Doom. -Vi devas aĉeti la tutan trilogion. +Vi bezonas mendi la plenan version (Ultimate). -Premu klavon.","Esta es la versión shareware de Doom. +Premu klavon.","Esta es la versión demo (shareware) de Doom. -Necesitas adquirir la trilogía completa. +Necesitas adquirir la versión completa (Ultimate). Presiona una tecla.",,"Tämä on Doomin shareware-versio. @@ -466,9 +331,9 @@ Paina jotain näppäintä.","Votre version de DOOM est une version SHAREWARE. Pensez à commander la version complète! -Appuyez sur une touche.","Ez a Shareware verziója a Doom-nak. +Appuyez sur une touche.","Ez a Doom shareware verziója. -Meg kell rendelned az egész trilógiát. +Rendeld meg az egész trilógiát! Nyomj meg egy gombot.","Questa è la versione shareware di doom. @@ -485,15 +350,19 @@ Premi un tasto.","これは体験版だ。 Je moet de hele trilogie bestellen. -Druk op een toets.","To jest wersja demonstracyjna Doom. +Druk op een toets.","Dette er shareware-versjonen av Doom. + +Du må bestille hele trilogien. + +Trykk på en tast.","To jest wersja demonstracyjna Doom. Musisz kupić całą trylogię. -Wciśnij dowolny klawisz.","Esta é a versão shareware de Doom. +Wciśnij dowolny klawisz.","Esta é a versão shareware de DOOM. Você precisa obter a trilogia completa. -Aperte qualquer tecla.","Esta é a versão shareware de Doom. +Aperte uma tecla.","Esta é a versão shareware de Doom. Precisas de obter a trilogia completa. @@ -501,28 +370,33 @@ Carrega numa tecla qualquer.","Aceasta este versiunea gratuită a jocului Doom. Trebuie să comanzi întreaga trilogie. -Apasă orice tastă.","Это демонстрационная версия Doom. +Apasă orice tastă.","Это условно-бесплатная версия Doom. Вам необходимо приобрести всю трилогию. -Нажмите любую клавишу.","Ово је шервер верзија игре Doom. +Нажмите любую клавишу.","Ово је демонстрациона верзија Doom-а. + +Потребно је да наручите целу трилогију. + +Притисните било који тастер.","Detta är sharewareversionen av Doom. Du måste beställa hela trilogin. +Tryck på en tangent.",Bu Doom'un shareware versiyonu. Tüm üçlemeyi sipariş etmeniz gerekiyor. Bir tuşa bas.,"Це демонстраційна версія Doom. -Морате наручити целу трилогију. +Вам потрібно купити повну версію. -Притисните тастер." -Messages OFF,MSGOFF,,,,Zprávy ZAP,Meldungen AUS,Μηνύματα ΚΛΕΙΣΤΑ,Mesaĝoj MALAKTIVA,Mensajes DESACTIVADOS,,Viestit POIS PÄÄLTÄ,Messages désactivés.,Üzenetek KI,Messaggi DISATTIVATI,メッセージ: オフ,메시지 끔,Berichten UIT,Wiadomości WYŁĄCZONE,Mensagens DESATIVADAS,,Mesaje DEZACTIVATE.,Сообщения ОТКЛЮЧЕНЫ,Поруке ИСКЉУЧЕНЕ -Messages ON,MSGON,,,,Zprávy VYP,Meldungen AN,Μηνύματα ΑΝΟΙΧΤΑ,Mesaĝoj AKTIVA,Mensajes ACTIVADOS,,Viestit PÄÄLLÄ,Messages activés.,Üzenetek BE,Messaggi ATTIVATI,メッセージ: オン,메시지 켬,Berichten AAN,Wiadomości WŁĄCZONE,Mensagens ATIVADAS,,Mesaje ACTIVATE.,Сообщения ВКЛЮЧЁНЫ,Поруке УКЉУЧЕНЕ +Натисніть будь яку клавішу." "You can't end a netgame! -Press a key.",NETEND,,,,"Nemůžeš ukončit síťovou hru! +Press a key.",NETEND,,,,"Síťovou hru nelze ukončit! -Stiskni libovolnou klávesu.","Du kannst ein Netzwerkspiel nicht beenden. +Stiskni libovolnou klávesu.","Du kan ikke afslutte et netspil! + +Tryk på en tast.","Du kannst ein Netzwerkspiel nicht beenden. Drücke eine Taste.","Δέν μπορείς να τελειώσεις ένα δικτυακό παιχνίδι! -Πάτα οποιδήποτε πλήκτρο.","Vi ne povas fini ret-ludon! +Πάτα οποιδήποτε πλήκτρο.","Vi ne povas fini retludadon! -Premu klavon.","¡No puedes terminar un juego en línea! +Premu klavon.","¡No puedes terminar una partida en línea! Presiona una tecla.",,"Et voi päättää verkkopeliä! @@ -530,42 +404,51 @@ Paina jotain näppäintä.","Vous ne pouvez pas mettre fin à une partie en rés Appuyez sur une touche.","Nem tudsz befejezni egy netjátékot! -Nyomj meg egy gombot.","Non puoi terminare un netgame! +Nyomj meg egy gombot.","Non puoi terminare una partita in rete! Premi un tasto.","オンラインプレイでは勝手に終了できない! 何かキーを押せ","멀티플레이를 종료할 수 없습니다! -키를 누르시오.","Je kunt een netspel niet beëindigen! +키를 누르시오.","Je kunt een netwerkspel niet beëindigen! -Druk op een toets.","Nie możesz zakończyć gry sieciowej! +Druk op een toets.","Du kan ikke avslutte et nettspill! -Wciśnij dowolny klawisz.","Você não pode terminar um jogo em rede! +Trykk på en tast.","Nie możesz zakończyć gry sieciowej! -Aperte qualquer tecla.","Não podes terminar um jogo em rede! +Wciśnij dowolny klawisz.","Impossível encerrar um jogo em rede! + +Aperte uma tecla.","Não podes terminar um jogo em rede! Carrega numa tecla qualquer.","Nu poți încheia brusc o sesiune în rețea! Apasă orice tastă.","Невозможно закончить сетевую игру! -Нажмите любую клавишу.",Не можете завршити мрежну игру! Притисните тастер. +Нажмите любую клавишу.","Не можете да завршите мрежну игру! + +Притисните било који тастер.","Du kan inte avsluta ett nätspel! +Tryck på en tangent.",Net oyununu bitiremezsin! Bir tuşa basın.,"Ви не можете завершити мережеву гру! + +Натисніть будь яку клавішу." "Are you sure you want to end the game? Press Y or N.",ENDGAME,,,,"Opravdu si přeješ ukončit hru? -Stiskni Y nebo N.","Willst du das Spiel wirklich beenden? +Stiskni Y nebo N.","Er du sikker på, at du ønsker at afslutte spillet? + +Tryk på Y eller N.","Willst du das Spiel wirklich beenden? Drücke Y oder N.","Είσαι σίγουρος ότι θέλεις να τελειώσεις το παιχνίδι? Πάτα Y ή N","Ĉu vi certas, ke vi volas fini la ludon? -Premu Y aŭ N.","¿Estás segur@[ao_esp] que deseas cerrar el juego? +Premu Y aŭ N.","¿Estás segur@[ao_esp] de que deseas cerrar el juego? Presiona Y ó N.",,"Haluatko varmasti päättää pelin? Paina Y tai N.","Voulez vous mettre fin à votre partie? -Appuyez sur Y ou N.","Biztos vagy benne hogy beakarod fejezni a játékot? +Appuyez sur Y ou N.","Biztosan abbahagyod a játékot? Nyomj Y-t vagy N-t.","Sei sicuro di voler terminare la partita? @@ -575,9 +458,11 @@ Y か N で答えろ","게임을 정말로 종료하시겠습니까? Y키 또는 N키를 누르시오.","Weet je zeker dat je het spel wilt beëindigen? -Druk op Y of N.","Czy jesteś pewien że chcesz zakończyć grę? +Druk op Y of N.","Er du sikker på at du vil avslutte spillet? -Wciśnij Y lub N","Tem certeza que deseja encerrar este jogo? +Trykk på Y eller N.","Czy jesteś pewien że chcesz zakończyć grę? + +Wciśnij Y lub N","Deseja mesmo encerrar este jogo? Aperte Y ou N.","Tem certeza que deseja fechar este jogo? @@ -585,1428 +470,1433 @@ Carrega Y ou N.","Ești sigur că dorești să închei jocul? Apasă Y sau N.","Вы действительно хотите закончить игру? -Нажмите Y или N.","Јесте ли сигурни да желите завршити игру? +Нажмите Y или N.","Желите ли сигурно да завршите игру? + +Притисните Y или N.","Är du säker på att du vill avsluta spelet? +Tryck på Y eller N.",Oyunu bitirmek istediğinizden emin misiniz? Y veya N'ye basın.,"Ви дійсно хочете завершити гру? -Притисните Y или N." -Are you sure you want to quit?,RAVENQUITMSG,,,,Přeješ si odejít?,"Bist du dir sicher, dass du gehen willst?","Είσαι σίγουρος ότι θέλεις να φύγεις? -","Ĉu vi certas, ke vi volas ĉesi?",¿Estás segur@[ao_esp] que quieres salir?,,Haluatko varmasti lopettaa?,Êtes vous sûr de vouloir quitter ?,Biztos vagy benne hogy ki akarsz lépni?,Sei sicuro di voler abbandonare?,本当に終了するのか?,정말 종료하시겠습니까?,Weet je zeker dat je wilt stoppen?,Czy jesteś pewien że chcesz wyjść?,Tem certeza que quer sair?,Tens a certeza que queres sair?,Ești sigur că vrei să ieși din joc?,Вы действительно желаете выйти?,Да ли сте сигурни да желите да одустанеш? -Only available in the registered version,SWSTRING,,heretic,,Dostupné pouze v registrované verzi,Nur in der registrierten Version verfügbar,Μόνο διαθέσιμο στήν εχγραμμένη έκδοση.,Sole havebla en la registrita versio,Sólo disponible en la versión registrada,,Käytettävissä vain rekisteröidyssä versiossa,Disponible uniquement dans la version enregistrée,Egyedül a teljes verzióban érhető el,Disponibile solamente nella versione registrata,製品版でのみ可能だ。,정품 버전에서만 가능합니다,Alleen beschikbaar in de geregistreerde versie,Dostępne tylko w zarejestrowanej wersji,Disponível somente na versão registrada,Apenas disponível na versão registrada,Disponibil doar in versiunea înregistrată.,Эпизод недоступен в демоверсии,Само могуће у регистрованој верзији -Not set,NOTSET,,,,Není nastavené,Nicht gesetzt,Δεν ρυθμίστηκε,Ne agordita,No Asignado,,Ei asetettu,Pas paramétré,Nincs beállítva,Non assegnato,セットされてない,정하지 않음,Niet ingesteld,Nie ustawiono,Não definido,,Nesetat.,Не задан,Није намештено -Do you really want to do this?,SAFEMESSAGE,,,,Vážně to chceš udělat?,Möchtest du das wirklich tun?,Θέλεις όντος να το κάνεις αυτό?,Ĉu vi vere volas fari tion?,¿Realmente quieres hacer esto?,¿Realmente quieres hacerlo?,Haluatko varmasti tehdä tämän?,Voulez-vous vraiment faire ça?,Biztos megakarod tenni?,Sei sicuro di volerlo fare?,本当に実行するのか?,정말로 정하시겠습니까?,Wil je dit echt doen?,Naprawdę chcesz to zrobić?,Você deseja mesmo fazer isso?,Desejas mesmo fazer isso?,Chiar vrei să faci asta?,Вы уверены?,Да ли заиста желите то да урадите? -(Press Y to quit),DOSY,,,,(Stiskni Y pro odchod),(Drücke Y zum Verlassen.),(Πάτα Y για να φύγεις),(Premu Y por ĉesi),(Presiona Y para salir),,(Paina Y lopettaaksesi),(Appuyez sur Y pour revenir à votre OS.),(Nyomj Y-t a kilépéshez.),(Premi Y per uscire),(Y で終了),(Y을 누르시면 종료합니다),(Druk op Y om te stoppen),"(Wciśnij Y, aby wyjść)",(Aperte Y para sair),(Carrega Y para sair),(Apasă Y pentru a ieși),"(Нажмите Y, чтобы выйти)",(Притисните Y да завршите) -,,Quit messages,,,,,,,,,,,,,,,,,,,,, +Натисніть Y або N." +Are you sure you want to quit?,RAVENQUITMSG,,,,Přeješ si odejít?,"Er du sikker på, at du vil holde op?","Bist du dir sicher, dass du gehen willst?","Είσαι σίγουρος ότι θέλεις να φύγεις? +","Ĉu vi certas, ke vi volas forlasi?",¿Estás segur@[ao_esp] de que quieres salir?,,Haluatko varmasti lopettaa?,Êtes vous sûr de vouloir quitter ?,Biztosan ki akarsz lépni?,Sei sicuro di voler abbandonare?,本当に終了するのか?,정말 종료하시겠습니까?,Weet je zeker dat je wilt stoppen?,Er du sikker på at du vil avslutte?,Czy jesteś pewien że chcesz wyjść?,Deseja mesmo sair?,Tens a certeza que queres sair?,Ești sigur că vrei să ieși din joc?,Вы действительно желаете выйти?,Желите ли сигурно да изађете?,Är du säker på att du vill avsluta?,Çıkmak istediğinizden emin misiniz?,Ви дійсно хочете вийти? +Only available in the registered version,SWSTRING,,heretic,,Dostupné pouze v registrované verzi,Kun tilgængelig i den registrerede version,Nur in der registrierten Version verfügbar,Μόνο διαθέσιμο στήν εχγραμμένη έκδοση.,Nur havebla en la komercaĵa versio,Solo disponible en la versión registrada,,Käytettävissä vain rekisteröidyssä versiossa,Disponible uniquement dans la version enregistrée,Csak a teljes verzióban érhető el,Disponibile solamente nella versione registrata,製品版でのみ可能だ。,정품 버전에서만 가능합니다,Alleen beschikbaar in de geregistreerde versie,Bare tilgjengelig i den registrerte versjonen,Dostępne tylko w zarejestrowanej wersji,Disponível somente na versão registrada,Apenas disponível na versão registrada,Disponibil doar în versiunea înregistrată.,Эпизод доступен только в полной версии,Само могуће у регистрованој верзији,Endast tillgänglig i den registrerade versionen,Sadece kayıtlı sürümde mevcuttur,Доступно только в полной версии +(Press Y to quit),DOSY,,,,(Stiskni Y pro odchod),(Tryk på Y for at afslutte),(Drücke Y zum Verlassen.),(Πάτα Y για να φύγεις),(Premu Y por forlasi),(Presiona Y para salir),,(Paina Y lopettaaksesi),(Appuyez sur Y pour revenir à votre OS.),(Nyomj Y-t a kilépéshez.),(Premi Y per uscire),(Y で終了),(Y을 누르시면 종료합니다),(Druk op Y om te stoppen),(Trykk Y for å avslutte),"(Wciśnij Y, aby wyjść)",(Aperte Y para sair),(Carrega Y para sair),(Apasă Y pentru a ieși),"(нажмите Y, чтобы выйти)",(Притисните Y да завршите),(Tryck på Y för att avsluta),(Çıkmak için Y'ye basın),(Натисніть Y для виходу) +,,Quit messages,,,,,,,,,,,,,,,,,,,,,,,,,, "Please don't leave, there's more demons to toast!",QUITMSG1,,,,"Nenechávej mě tu, je tu -víc démonů k vymletí!","Bitte gehe nicht, es gibt noch mehr -Dämonen zu erlegen.","Παρακαλώ μη φύγεις, υπάρχουνε περισσότεροi δαίμονες να ψήσεις!","Bonvolu ne foriri! Estas pliaj -demonoj por rosti!","¡Por favor no te vayas, hay más demonios para tostar!",,Älä lähde; demoneita on vielä kärvennettävänä!,"Ne partez pas, il ya encore +víc démonů k vymletí!","Du må ikke gå, der er flere +dæmoner at stege!!","Bitte gehe nicht, es gibt noch mehr +Dämonen zu erlegen.","Παρακαλώ μη φύγεις, υπάρχουνε περισσότεροi δαίμονες να ψήσεις!","Bonvolu ne foriri, estas pliaj +rostindaj demonoj!","¡No te vayas, que aún quedan +demonios para freír!",,Älä lähde; demoneita on vielä kärvennettävänä!,"Ne partez pas, il ya encore des démons a buter!","Kérlek ne lépj le, sok démon vár még arra, hogy felaprítsd!","Per favore non uscire, ci sono altri demoni da ammazzare!","離れないでくれ! -まだ獲物が残っているんだ!","부디 나가지 말아줘, 아직 죽여야 할 악마들이 남아있단 말이야!","Ga alsjeblieft niet weg, er zijn meer demonen om te toosten!","Proszę, nie odchodź, jest więcej -demonów do stostowania!","Por favor não vá embora, há mais -demônios para matar!","Por favor não te vás embora, há mais -demônios para matar!","Te rog nu ieși, mai sunt demoni care trebuie prăjiți!","Пожалуйста, не уходи! -Тут ещё много демонов!","Молим те, не одлази, -има још демона да се побије!" +まだ獲物が残っているんだ!","부디 나가지 말아줘, 아직 죽여야 할 악마들이 남아있단 말이야!","Ga alsjeblieft niet weg, er zijn meer demonen te roosteren!","Vennligst ikke gå, det er flere demoner å skåle!","Proszę, nie odchodź, jest więcej +demonów do stostowania!","Por favor, não vá embora. Tem mais +demônios para torrar!","Por favor não te vás embora, há mais +demônios para matar!","Te rog nu ieși, mai sunt demoni care trebuie prăjiți!","Пожалуйста, не уходи, +тут ещё полно демонов для поджарки!","Молим те, не одлази! +Има још демона да се побије!","Lämna inte spelet, det finns fler demoner att skåla för!","Lütfen gitmeyin, kadeh kaldıracak daha çok iblis var!","Будь ласка, не йди - тут ще купа демонів!" "Let's beat it -- this is turning -into a bloodbath!",QUITMSG2,,,,"Doraž to -- začíná -tu téct krev!",Lass es uns beenden - das wird zu einem Blutbad,Πάεμε να φύγουμε -- έχει γίνει σφαγίο εδώ!,"Ni forlasu! Ĉi tio iĝas -naĝejon de sango!","Aceptémoslo, -¡esto se está volviendo en un baño de sangre!",,Häivytään -- tämä on muuttumassa verilöylyksi!,"Fichons le camp, ça dégénère +into a bloodbath!",QUITMSG2,,,,"Utečme -- začíná +tu téct krev!","Lad os smutte - det her er +ved at blive et blodbad!",Lass es uns beenden - das wird zu einem Blutbad,Πάεμε να φύγουμε -- έχει γίνει σφαγίο εδώ!,"Ni forlasu, ĉi tio iĝas +sangoverŝado!","Aceptémoslo, ¡esto se está +convirtiendo en un baño de sangre!",,Häivytään -- tämä on muuttumassa verilöylyksi!,"Fichons le camp, ça dégénère en bain de sang!","Tűnjünk innen, ebből vérfürdő lesz!","Ammettiamolo - tutto ciò si sta trasformando in un bagno di sangue!","まだ物足りないだろう? -早く戻って皆殺しにしろ!",그냥 나가자고- 유혈사태가 곧 시작될 것 같으니!,Laten we het verslaan – Dit wordt een bloedbad!,Zmywajmy się stąd -- robi się tu rzeźnia!,"Vamos encarar -- Isso está se tornando +早く戻って皆殺しにしろ!",그냥 나가자고- 유혈사태가 곧 시작될 것 같으니!,Laten we ervoor gaan - dit wordt een bloedbad!,La oss stikke - dette er i ferd med å bli et blodbad!,Zmywajmy się stąd -- robi się tu rzeźnia!,"Vamos embora — isso tá virando um banho de sangue!","Falando a sério -- Isto está se a tornar num banho de sangue!","S-o lăsăm baltă -- situația degenerează într-o -baie de sânge!","Да, давай, убегай, если эта -кровавая баня тебе не по зубам!","Хајде да завршимо -- -ово постаје прави покољ!" +baie de sânge!","Давай покончим с этим — оно превращается +в кровавую баню!","Хајде, бриши одавде +ако ти је ово одвећ крваво!",Vi sticker - det här håller på att bli ett blodbad!,"Hadi gidelim, ortalık kan gölüne dönüyor!","Споримо, що ця кривава баня тобі не по зубах!?" "I wouldn't leave if I were you. DOS is much worse.",QUITMSG3,,,,"Být tebou, neodcházel bych. -DOS je mnohem horší.","Ich würde nicht gehen, wenn ich du wäre. +DOS je mnohem horší.","Jeg ville ikke gå, hvis jeg var dig. +DOS er meget værre.","Ich würde nicht gehen, wenn ich du wäre. DOS ist viel übler.","Δέν θα έφευγα αμμα είμουνα εσύ. -Το DOS είναι πολύ χυρότερο.","Mi ne forirus, se mi estus vi. -DOS estas multe pli malbona.","No me iría si fuera tú. -DOS es mucho peor.",,Sinuna en lähtisi. DOS on paljon pahempi.,"Je ne quitterais pas si j'étais vous. +Το DOS είναι πολύ χυρότερο.","Mi ne forirus, se mi estus vi: +MS-DOS estas multe pli malbona.","No me iría si fuera tú: +MS-DOS es mucho peor.",,Sinuna en lähtisi. DOS on paljon pahempi.,"Je ne quitterais pas si j'étais vous. Votre OS est bien pire.","A helyedben nem lépnék ki. A DOS sokkal rosszabb.","Non uscirei se fossi in te. Il DOS è molto peggio.","俺がお前だったらここは離れない。 -デスクトップなぞ最悪だ。",만약 내가 너였다면 나가지 않았을 거야. DOS는 정말 최악이거든.,Ik zou niet weggaan als ik jou was. DOS is veel erger.,"Na twoim miejscu nie odchodziłbym. +デスクトップなぞ最悪だ。",만약 내가 너였다면 나가지 않았을 거야. DOS는 정말 최악이거든.,Ik zou niet weggaan als ik jou was. DOS is veel erger.,Jeg ville ikke dratt hvis jeg var deg. DOS er mye verre.,"Na twoim miejscu nie odchodziłbym. DOS jest o wiele gorszy.","Eu não sairia se fosse você. -O sistema operacional é muito pior.","Se fosse a ti não saia daqui. -O sistema operativo é bem pior.","Eu n-aș pleca în locul tău - sistemul DOS e mult +O DOS é bem pior.","Se fosse a ti não saia daqui. +O DOS é bem pior.","Eu n-aș pleca în locul tău - sistemul DOS e mult mai rău.","На твоём месте я бы не уходил. -DOS намного скучнее.","Не би одлазио да сам -ти. DOS је много гори." +DOS намного скучнее.","Да сам на твом месту, не бих одлазио. +DOS је много досаднији.",Jag skulle inte lämna om jag var du. DOS är mycket värre.,Yerinde olsam gitmezdim. DOS çok daha kötü.,Я б не йшов на твоєму місці. DOS значно нудніший. "You're trying to say you like DOS better than me, right?",QUITMSG4,,,,"Chceš mi říct, že máš -radši DOS než mě?","Willst du sagen, dass DOS -besser ist als ich?","Προσπαθείς να πείς οτι το DOS είναι καλήτερο απο εμένα, σωστά?","Vi provas diri, ke vi ŝatas DOS-on -pli ol min, ĉu ne?","¿Estás tratando de decir que DOS es mejor que yo, cierto?",,"Yritätkö sanoa pitäväsi DOSista enemmän kuin minusta, niinkö?","Vous essayez de dire que vous aimez DOS +radši DOS než mě?","Du prøver at sige, at du bedre +kan lide DOS end mig, ikke?","Willst du sagen, dass DOS +besser ist als ich?","Προσπαθείς να πείς οτι το DOS είναι καλήτερο απο εμένα, σωστά?","Vi provas diri, ke MS-DOS +estas pli bona ol mi, ĉu?","Estás tratando de decir que el +MS-DOS es mejor que yo, ¿cierto?",,"Yritätkö sanoa pitäväsi DOSista enemmän kuin minusta, niinkö?","Vous essayez de dire que vous aimez DOS mieux que moi, pas vrai?","Azt akarod mondani, hogy a DOS jobb nálam?","Stai cercando di dire che il DOS -ti piace più di me, vero?","貴方はこちらよりもデスクトップの方が -好みらしいな?","나보다 DOS가 훨씬 좋다 이 말씀이지, 그런 거지?","Je probeert te zeggen dat je DOS beter bevalt dan ik, toch?","Próbujesz powiedzieć, że wolisz DOS -ode mnie, prawda?","Você está tentando dizer que você gosta -do sistema operacional mais do que eu, é isso?","Estás a tentar dizer que gostas mais do -do sistema operativo do que eu, é isso?","Încerci să spui că-ți place de sistemul DOS mai mult -decât de mine, așa-i?","Ты хочешь сказать, что DOS -тебе нравится больше, чем я, а?","Покушаваш да кажеш да више -волиш DOS него мене, зар не?" +ti piace più di me, vero?","貴方はこちらよりも +デスクトップの方が好みらしいな?","나보다 DOS가 훨씬 좋다 이 말씀이지, 그런 거지?",Probeer je te zeggen dat DOS jou beter bevalt dan mij?,"Du prøver å si at du liker DOS bedre enn meg, ikke sant?","Próbujesz powiedzieć, że wolisz DOS +ode mnie, prawda?","Tá querendo dizer que você gosta mais +do DOS do que eu, é isso?","Estás a tentar dizer que gostas mais do +do DOS do que eu, é isso?","Încerci să spui că-ți place de sistemul DOS mai mult +decât de mine, așa-i?","Ты хочешь сказать, что DOS тебе нравится больше, чем я, а?","Више ти допада DOS +него ја, је ли?","Du försöker säga att du gillar DOS bättre än mig, eller hur?","DOS'u benden daha çok sevdiğini söylemeye çalışıyorsun, değil mi?","Хочеш сказати, що DOS цікавіший за мене, так?" "Don't leave yet -- there's a demon around that corner!",QUITMSG5,,,,"Ještě nechoď -- tam -za rohem je démon!","Bitte gehe noch nicht - hinter -der Ecke da lauert ein Dämon.","Μη φύγεις ακόμα, είναι ένας δαίμονας πίσω απο αυτή τι γονία!","Vi ne jam foriru! Estas demono -preter tiu angulo!","No te vayas aún, -¡hay un demonio por aquella esquina!",,Älä lähde vielä -- tuon kulman takana on demoni!,"Ne partez pas encore! Il y a -un démon dans le coin!","Még ne menj -- maradt egy -démon annál a saroknál!","Non abbandonare ora - c'è un +za rohem je démon!","Du må ikke gå endnu - der er en +dæmon rundt om det hjørne!","Bitte gehe noch nicht - hinter +der Ecke da lauert ein Dämon.","Μη φύγεις ακόμα, είναι ένας δαίμονας πίσω απο αυτή τι γονία!","Ne foriru ankoraŭ, estas +demono ĉirkaŭ tiu angulo!","¡No te vayas, que aún hay +demonios en la costa!",,Älä lähde vielä -- tuon kulman takana on demoni!,"Ne partez pas encore! Il y a +un démon dans le coin!",Még ne menj -- a sarkon túl még vár rád egy démon!,"Non abbandonare ora - c'è un demone dietro l'angolo!","待ってくれ!まだあそこの角に -デーモンが残っているんだ!",나가지 마- 저 구석에 악마가 숨어있다고!,Ga nog niet weg – er is een demon om die hoek!,"Nie odchodź jeszcze -- demon czai -się w tamtym zaułku!","Não vá embora ainda -- Tem um +デーモンが残っているんだ!",나가지 마- 저 구석에 악마가 숨어있다고!,Ga nog niet weg - er is een demoon hier om de hoek!,Ikke gå ennå. Det er en demon rundt hjørnet.,"Nie odchodź jeszcze -- demon czai +się w tamtym zaułku!","Não vá embora ainda, tem um demônio naquele canto!","Não te vás embora agora -- Está um -demônio ao virar da esquina!",Nu pleca încă -- e un demon după colțul acela!,"Не уходи! За углом -притаился ещё один монстр!","Немој да одеш -- има -демон иза оног угла!" +demônio ao virar da esquina!",Nu pleca încă -- e un demon după colțul acela!,"Не уходи! За тем углом +притаился ещё один монстр!","Немој да одеш -- +иза угла има још један демон!",Gå inte än -- det finns en demon runt hörnet!,"Hemen gitme, şu köşede bir iblis var!",Зачекай! Не йди - тут за куточком сховався ще один демон! "Ya know, next time you come in here -I'm gonna toast ya.",QUITMSG6,,,,"Víš, až se vrátíš, -rozmáčknu tě.","Nur damit du es weißt, wenn du -wiederkommst, dann bist du erledigt.","Ξέρεις, την επόμενη φορά που θα έρθεις εδώ, θα σε ψήσω.","Vi sciu ĉi tion, ke kiam vi sekvafoje venos ĉi tien, +I'm gonna toast ya.",QUITMSG6,,,,"Tak hele, až se vrátíš, +dostanu tě.","Ved du hvad, næste gang du +kommer herind, vil jeg stege dig.","Nur damit du es weißt, wenn du +wiederkommst, dann bist du erledigt.","Ξέρεις, την επόμενη φορά που θα έρθεις εδώ, θα σε ψήσω.","Sciu, ke kiam vi sekvafoje venos ĉi tien, mi rostos vin.","Ya lo sabes, la próxima vez -que vengas voy a tostarte.",,"Tiiäthän, että käristän sut, kun seuraavalla kerralla tuut tänne.","Vous savez, la prochaine que revenez, +que vengas voy a freírte.",,"Tiiäthän, että käristän sut, kun seuraavalla kerralla tuut tänne.","Vous savez, la prochaine fois que vous revenez, je vous grille.","Tudod, ha legközelebb idejössz, szét foglak kenni.","Sai, la prossima volta che verrai qui ti farò a pezzi.","わかったよ。 -今度戻ってきたら一杯奢るよ。","있지, 만약 네가 다시 돌아온다면 너를 아예 구워버릴 거다.","Weet je, de volgende keer dat je hier binnenkomt, ga ik op je toosten.","Wiesz, jeżeli jescze raz tu przyjdziesz, -stostuje cię.","Quer saber? Da próxima vez que você vier -aqui vou te explodir em pedaços.","Sabes, da próxima vez que vieres para +今度戻ってきたら一杯奢るよ。","있지, 만약 네가 다시 돌아온다면 너를 아예 구워버릴 거다.","Weet je, de volgende keer dat je hier binnenkomt, ga ik je roosteren.","Neste gang du kommer hit, skal jeg skåle for deg.","Wiesz, jeżeli jescze raz tu przyjdziesz, +stostuje cię.","Na próxima vez que você vier +aqui, eu vou te detonar em pedaços.","Sabes, da próxima vez que vieres para aqui vou te fazer explodir em bocadinhos.","Să știi, data viitoare când treci pe-aici o să te prăjesc!","Знаешь, по возвращении тебя -будут ждать большие неприятности.","Знаш, следећи пут кад дођеш, -заклаћу те." -Go ahead and leave. see if I care.,QUITMSG7,,,,"Tak do toho, odejdi, -jako kdyby mě to zajímalo.","Dann geh doch! Interessiert -mich nicht.","Φύγε, δες αν νιάζομαι.",Ja foriru. Vidu ĉu mi zorgas.,"Anda, vete. A ver si me importa.",,"Ole hyvä vain ja lähde. Arvaa, välitänkö.","Allez y, partez, allez voir si j'y suis.","Menj nyugodtan, úgysem érdekel.",Continua ed esci. sai che mi frega.,置いて行っちゃうんだ。勝手にしろ。,그럼 나가버려. 난 신경 안 써.,"Ga en vertrek, kijk of het me interesseert.","No dalej, odejdź. Zobaczymy czy -mnie to obchodzi.",Vá em frente e saia. Eu não ligo.,Vai te em embora. Vê lá se eu quero saber.,"Hai, pleacă, vezi dacă-mi pasă.","Давай, уходи. Мне совершенно всё равно.","Изволи, иди. Није ме брига." +будут ждать большие неприятности.","Знаш, по повратку ће те +чекати велике невоље.",Nästa gång du kommer hit ska jag skåla för dig.,"Biliyor musun, bir dahaki sefere buraya geldiğinde seni tost yapacağım.","Шоб знав, коли повернешся - я намилю тобі шию." +Go ahead and leave. see if I care.,QUITMSG7,,,,"Jen do toho, odejdi; schválně, +jestli mi to bude jedno.",Gå bare. Se om jeg er ligeglad.,"Dann geh doch! Interessiert +mich nicht.","Φύγε, δες αν νιάζομαι.",Ja foriru. Mi fajfas pri tio.,Ya vete. A ver si me importa.,,"Ole hyvä vain ja lähde. Arvaa, välitänkö.","Allez y, partez, allez voir si j'y suis.","Menj nyugodtan, nem mintha bárkit érdekelne.","Esci pure, sai che mi frega.",置いて行っちゃうんだ。勝手にしろ。,그럼 나가버려. 난 신경 안 써.,"Ga maar, eens kijken of het me interesseert.",Bare gå. Jeg bryr meg ikke.,"No dalej, odejdź. Zobaczymy czy +mnie to obchodzi.","Vai, pode ir embora. Tô nem aí.",Vai te em embora. Vê lá se eu quero saber.,"Hai, pleacă, vezi dacă-mi pasă.","Давай, уходи. Мне совершенно всё равно.","Хајде, одлази. Уопште ме није брига.",Gå du bara och se om jag bryr mig.,Devam et ve git. Bakalım umurumda olacak mı?,"Давай, йди... ніби мені не все одно." "You want to quit? Then, thou hast lost an eighth!",QUITMSG8,More info here.,,,"Chceš odejít? -Nuže, kletba nať uvalena byla!","Du willst gehen? +Nuže, přišel jsi o přízeň boží!","Vil du gå? +Har du mistet forstanden?","Du willst gehen? Hast du den Verstand verloren?","Θέλεις να φύγεις ? -Τότε, έχασες ένα έκτο!","Vi volas ĉesigi? -Tial, tu malgaynis okonon!","¿Quieres salir? Entonces, ¡habrás perdido una octava!",,"Haluat siis lopettaa? +Τότε, έχασες ένα έκτο!","Ĉu vi volas forlasi? +Tiuokaze, vi perdos okonon!","Salir del juego: +golpe de remo.","Si intentas salir +del juego, hay tabla.","Haluat siis lopettaa? Oletko menettänyt järkesi?","Vous voulez vraiment quitter? Vous avez vraiment les fils qui se croisent!","Ki akarsz lépni? -Akkor elment az eszed!","Vuoi uscire? -Allora hai perso il senno!","終了したい?それだと、貴方の体が -8分の1を失ってしまうぞ!","나가시겠다? 그럼, 당신은 8번째 조각을 잃었다!",Wil je stoppen? Ben je gek geworden?,Chcesz odejść? Wiele stracisz!,"Você quer sair? +Akkor beszolgáltatik a Te vagyonod nyolcada!","Vuoi uscire? +Allora hai perso il senno!","終了したい?ならば、 +汝は8分の1を失うぞ!","나가시겠다? 그럼, 당신은 8번째 조각을 잃었다!",Wil je stoppen? Dan ben je wel helemaal geschift!,Vil du slutte? Da har du mistet en åttendedel!,Chcesz odejść? Wiele stracisz!,"Você quer sair? Só pode ter perdido a cabeça!","Queres sair? Só podes ter perdido a cabeça!","Vrei să ieși? Atunci, ai pierdut o virtute!","Всерьёз задумываешь выйти? -Полагаю, это не очень-то разумно!","Желиш да одустанеш? -Онда си изгуби@[ao_1_sr] осмицу!" +Тем самым ты упустил что-то важное!","Озбиљно желиш да изађеш? +Није то нимало паметно!",Vill du sluta? Då har du förlorat en åttondel!,Bırakmak mı istiyorsun? O zaman sekizde birini kaybettin!,Вийти? ВИЙТИ?! Це так не працює. "Don't go now, there's a dimensional shambler waiting -at the DOS prompt!",QUITMSG9,A “dimensional shambler” is a type of creature that appears in H.P. Lovecraft’s works.,,,"Teď neodcházej, na příkazové řádce -číhá dimenzionální Jožin!","Bitte geh noch nicht! +at the DOS prompt!",QUITMSG9,A “dimensional shambler” is a creature appearing in the works of H. P. Lovecraft.,,,"Teď neodcházej, na příkazové řádce +číhá dimenzionální Jožin!","Gå ikke nu, der er en +dimensionsødelægger der +venter på DOS-prompten!","Bitte geh noch nicht! An der Eingabeaufforderung wartet -ein Dimensionszerstörer auf dich!","Μη πας τώρα, υπάρχει ένας διαστατικός τρίκλιστης ο οπίος περιμένει στη DOS γραμμή εντολών!","Ne nun iru! Estas -dimensia marŝisto atendanta -ĉe la DOS-invito!","No te vayas, ¡hay un desorden dimensional en la consola de DOS!",,Älä mene nyt; DOS-kehotteella väijyy hirviö toisesta ulottuvuudesta!,"Ne partez pas maintenant, il y a un +ein Dimensionszerstörer auf dich!","Μη πας τώρα, υπάρχει ένας διαστατικός τρίκλιστης ο οπίος περιμένει στη DOS γραμμή εντολών!","Ne foriru, dimensia malordo +atendas ĉe la DOS-konzolo!","¡No te vayas, que hay un vagabundo +dimensional en la consola de DOS!",,Älä mene nyt; DOS-kehotteella väijyy hirviö toisesta ulottuvuudesta!,"Ne partez pas maintenant, il y a un monstre interdimensionnel qui -dans attend dans votre OS!","Ne menj most, egy dimenzió forgató +dans attend dans votre OS!","Ne menj most, egy dimenzióforgató vár a DOS parancssornál!","Non andartene adesso, c'è un portale dimensionale che ti aspetta -al prompt del DOS!","まだやめたらダメだ、あの空鬼が -デスクトップには待ち構えているんだぞ!","나가지 말아줘, 지금 차원을 넘나드는 쉠블러가 DOS 프롬프트에서 기다리고 있거든!","Ga nu niet weg, er wacht een dimensionale vernietiger op de DOS-signalering!","Nie idź jeszcze, stworzenie -z innego świata na ciebie czyha w DOSie!","Não saia agora, há um -monstro de outra dimensão esperando -por você no sistema operacional!","Não saias agora, há um +al prompt del DOS!","まだやめたらダメだ、 +あの空鬼がデスクトップには +待ち構えているんだぞ!","나가지 말아줘, 지금 차원을 넘나드는 쉠블러가 DOS 프롬프트에서 기다리고 있거든!","Ga nu niet weg, er wacht een dimensionale schuifelaar op de DOS prompt!","Ikke gå nå, det er en dimensjonal shambler som venter ved DOS-prompten!","Nie idź jeszcze, stworzenie +z innego świata na ciebie czyha w DOSie!","Não saia agora, tem um shambler +de outra dimensão esperando +no prompt do DOS!","Não saias agora, há um monstro de outra dimensão à tua -espera no sistema operativo!","Nu pleca acum, e un monstru interdimensional care -te așteaptă la promptul DOS!","Не уходи! Тут межпространственный +espera no DOS!","Nu pleca acum, e un monstru interdimensional care +te așteaptă la promptul DOS!","Не уходи сейчас, межпространственный бродяга поджидает в -командной строке!","Немој да одеш, ту је -интердимензионално чудовиште -које чека код DOS промпта!" +DOS!","Немој да одеш! +Међудимензионално чудовиште +чека код DOS промпта!","Gå inte nu, det finns en dimensionell shambler som väntar vid DOS-prompten!","Şimdi gitme, DOS komut isteminde bekleyen boyutsal bir shambler var!","Підіжди трохи, між строками DOS причаївся міжпросторовий шамблер!" "Get outta here and go back to your boring programs.",QUITMSG10,,,,"Vypadni odsud a vrať se -ke svým nudným programům.","Dann geh doch zurück -zu deinen langweiligen Programmen",Βγές απο'δω και πήγαινε πίσω στα βαρετά προγράματα σου.,"Eliru el ĉi tie kaj reiru al -viaj enuaj programoj.",Vete de aquí y vuelve a tus aburridos programas.,,Ala laputtaa takaisin tylsien ohjelmiesi pariin.,"Tirez vous de là et retournez -à vos programmes ennuyeux.","Sicc innen és menj vissza az +ke svým nudným programům.","Forsvind herfra og gå tilbage +til dine kedelige programmer.","Dann geh doch zurück +zu deinen langweiligen Programmen",Βγές απο'δω και πήγαινε πίσω στα βαρετά προγράματα σου.,"Forigu kaj reiru al viaj +enuigaj programoj.","Ya vete y vuelve a tus +programitas aburridos.",,Ala laputtaa takaisin tylsien ohjelmiesi pariin.,"Tirez vous de là et retournez +à vos programmes ennuyeux.","Húzz innen, és menj vissza az unalmas programjaidhoz.","Vai fuori di qui e torna ai tuoi noiosi programmi.","早く出ていって、いつものつまらない -プログラムに戻るんだな。",당장 나가버리고 너의 후진 프로그램들이나 만지작거리시지.,Ga hier weg en ga terug naar je saaie programma's.,"Wynoś się stąd i wracaj do -swoich nudnych programów.","Cai fora daqui, volte -para os seus programas chatos.","Desaparece daqui e volta +プログラムに戻るんだな。",당장 나가버리고 너의 후진 프로그램들이나 만지작거리시지.,Ga hier weg en terug naar je saaie programma's.,Kom deg ut herfra og gå tilbake til de kjedelige programmene dine.,"Wynoś się stąd i wracaj do +swoich nudnych programów.","Se manda daqui e volte para +os seus programas chatos.","Desaparece daqui e volta para os teus programas chatos.","Cară-te de aici și întoarce-te la programele tale plictisitoare.","Вот и убирайся отсюда к -своим скучным программам.","Губи се одавде и врати се -својим досадним програмима." +своим скучным программам.","Губи се одавде +својим досадним програмима.",Försvinn härifrån och gå tillbaka till dina tråkiga program.,Git buradan ve sıkıcı programlarına geri dön.,"Ну і котись звідсіль, до своїх марудних програм." "If I were your boss, I'd deathmatch ya in a minute!",QUITMSG11,,,,"Být tvým šéfem, v deathmatchi -bych tě zabil do minuty!","Wenn ich dein Boss wäre, würde ich -dich im Deathmatch in einer Minute schlagen.","Άμα ήμουν το αφεντικό σου, θα σε προκαλούσα σε ενα deathmatch αυτη τη στιγμή!","Se mi estus via ĉefulo, -mi ja mortmatĉus vin post minuton!","Si yo fuera tu jefe, ¡te retaría a muerte en un minuto!",,"Jos oisin pomosi, lyttäisin sut kuolonottelussa minuutissa!","Si j'étais votre patron, je vous +bych tě zabil do minuty!","Hvis jeg var din chef, ville jeg +slå dig ihjel på et minut!","Wenn ich dein Boss wäre, würde ich +dich im Deathmatch in einer Minute schlagen.","Άμα ήμουν το αφεντικό σου, θα σε προκαλούσα σε ενα deathmatch αυτη τη στιγμή!","Se mi estus via ĉefo, mi +mortomaĉus vin post minuto!","Si yo fuera tu jefe, te golpearía +a muerte dentro de un minuto.",,"Jos oisin pomosi, lyttäisin sut kuolonottelussa minuutissa!","Si j'étais votre patron, je vous collerai un Deathmatch dans la minute!","Ha én lennék a főnököd, lejátszanék egy Deathmatch-et veled perceken belül!","Se fossi il tuo capo, ti batterei -a un deathmatch in un minuto!","もし私が君の上司なら、 -今すぐにでもデスマッチで戦えたのにな!","만약 내가 너의 상사였다면, 지금 당장 데스매치를 열었을 거다!","Als ik je baas was, zou ik je in een minuut doodmaken!","Gdybym był twoim szefem, +a un deathmatch in un minuto!","もし私が君の上司なら、すぐにでも +デスマッチを始める所だぞ!","만약 내가 너의 상사였다면, 지금 당장 데스매치를 열었을 거다!","Als ik je baas was, zou ik je in een minuut doodmaken!","Hvis jeg var sjefen din, ville jeg dødsmatche deg med en gang!","Gdybym był twoim szefem, wyzwałbym cię na deathmatch!","Se eu fosse seu chefe, te chamaria -para um deathmatch agora mesmo!","Se eu fosse o teu chefe, lutava +para um mata-mata rapidinho!","Se eu fosse o teu chefe, lutava num deathmatch contigo agora mesmo!","Dacă eram șeful tău, te-aș fi luat la o rundă de deathmatch!","Будь я твоим боссом, -разобрался бы с тобой ровно за минуту!","Да сам био твој шеф, -детмеч-овао бих те за -један минут!" +я бы разобрался бы с тобой за минуту!","Да сам твој шеф, +средио бих те за један минут!",Om jag var din chef skulle jag döda dig på en minut!,"Patronun olsaydım, seni bir dakika içinde öldürürdüm!",Був би я твоїм боссом - розніс у дедматчі за хвилину! "Look, bud. you leave now and you forfeit your body count!",QUITMSG12,,,,"Hele, kámo, když teď odejdeš, -přijdeš o svoje skóre!","Also, Kumpel, wenn du jetzt abhaust, -begehst du Fahnenflucht!","Κοίτα φίλε, άμα φύγεις τώρα ματαιώσες το σκόρ σου!","Vidu, amik'. Se vi nun forirus, -vi rezignus vian mortig-nombron!","Mira, amig@[ao_esp]. ¡Te vas ahora y vas a perder tu conteo de cuerpos!",,"Kuules, kaveri: Jos menet nyt, niin siinä samassa menee myös ruumislukusi.","Regardez, l'ami. Vous partez maintenant -et vous pouvez oublier votre score!","Nézd, haver. kilépsz most -és akkor semmissé válnak a pontjaid!","Senti amico, esci adesso +přijdeš o svoje skóre!","Så, kammerat, hvis du flygter nu, +begår du desertering!","Also, Kumpel, wenn du jetzt abhaust, +begehst du Fahnenflucht!","Κοίτα φίλε, άμα φύγεις τώρα ματαιώσες το σκόρ σου!","Rigardu, ulo. Se vi nun foriros, +vi rezignos vian mortig-nombron!","A ver, amig@[ao_esp]. ¡Te vas ahora +y pierdes tu número de bajas!",,"Kuules, kaveri: Jos menet nyt, niin siinä samassa menee myös ruumislukusi.","Regardez, l'ami. Vous partez maintenant +et vous pouvez oublier votre score!","Nézd, haver. Ha most kilépsz, +feladod a pontjaidat!","Senti amico, esci adesso e perdi la tua conta delle vittime!","おいおい待てよ、今やめたら -殺したデーモンの数を数えられないぞ!","이봐, 친구. 지금 여기서 나가버리면 죽여서 얻은 점수가 다 초기화될걸?","Dus, vriend, als je nu weggaat, is het een desertie!","Popatrz, stary. Odejdziesz teraz -i stracisz swoją liczbę ofiar!","Olha, se você sair agora você perde +殺したデーモンの数を数えられないぞ!","이봐, 친구. 지금 여기서 나가버리면 죽여서 얻은 점수가 다 초기화될걸?","Luister vriend, als je nu weggaat, is je dodental verbeurd!","Hør her, kompis. Hvis du går nå, mister du dødstallet ditt!","Popatrz, stary. Odejdziesz teraz +i stracisz swoją liczbę ofiar!","Olha, se você sair agora, vai perder a sua contagem de vítimas!","Olha, se saires agora perdes a tua contagem de mortes!","Uite, amice, pleci acum și renunți la numărul de cadavre!","Послушай, дружище. Выйдешь — -и сбросишь свой счётчик убийств!","Види, друже. Ако одеш -сада, изгубићеш број убистава!" +и сбросишь свой счётчик убийств!","Чуј, ортак. Одеш ли, +изгубићеш свој број убистава!","Lyssna, kompis. Om du går nu förlorar du antalet döda!","Bak, dostum. Şimdi gidersen ceset sayını kaybedersin!",Слухай друже. Якщо підеш зараз - твій лічильник вбивств впаде до нуля! "Just leave. when you come back, I'll be waiting with a bat.",QUITMSG13,,,,"Jen odejdi. Až se vrátíš, -budu čekat s baseballkou.","Geh doch. Wenn du zurückkommst, -warte ich mit einem Schläger auf dich.","Απλός φύγε. Ο΄ταν επιστρέψεις, θα περιμένω με ένα ρόπαλο.","Ja foriru. Kiam vi revenos, -mi atendos kun batilo.","Sólo ándate. Cuando vuelvas, +budu čekat s baseballkou.","Bare gå. Når du kommer tilbage, +venter jeg med et bat.","Geh doch. Wenn du zurückkommst, +warte ich mit einem Schläger auf dich.","Απλός φύγε. Ο΄ταν επιστρέψεις, θα περιμένω με ένα ρόπαλο.","Nur foriru. Kiam vi revenos, +mi estos atendanta kun batilo.","Solo lárgate. Cuando vuelvas, te esperaré con un bate.",,Senkus menet. Odottelen paluutasi mailalla.,"Allez, partez. Quand vous reviendrez, je vous attendrai avec une batte.","Menj csak. amikor visszajössz várni foglak egy ütővel.","Esci pure. quanto tornerai -ti aspetterò con un bastone.","帰ればいいさ、君が戻ってきたときには、 -私はバットを持って待ってるから",그냥 나가봐. 돌아올 때까지 방망이를 들고 기다릴테니까.,"Ga gewoon weg. als je terugkomt, zal ik met een knuppel wachten.","Tylko odejdź. Kiedy wrócisz, będę czekał z kijem.","Vá, saia. Quando você voltar -vou te esperar com um porrete.","Vá lá, sai. Quando voltares eu +ti aspetterò con un bastone.","帰ればいいさ、 +君が戻ってきたときには、 +私はバットを持って待ってるから",그냥 나가봐. 돌아올 때까지 방망이를 들고 기다릴테니까.,"Ga gewoon weg. Als je terugkomt, wacht ik met een knuppel op je.","Bare gå. Når du kommer tilbake, venter jeg med et balltre.","Tylko odejdź. Kiedy wrócisz, będę czekał z kijem.","Sai daqui. Quando você voltar, +vou estar te esperando com um taco.","Vá lá, sai. Quando voltares eu estarei a tua espera com uma moca.","Doar pleacă. Când te intorci o să te aștept cu o bâtă.","Уходи, уходи... но когда вернёшься, -я буду ждать тебя с битой.","Само иди. Када се вратиш, -чекаћу те с палицом." +я буду ждать тебя с битой.","Иди, иди... али када се вратиш, +чекаћу те са палицом.",Gå bara. När du kommer tillbaka väntar jag med ett slagträ.,Sadece git. Geri döndüğünde bir sopayla bekliyor olacağım.,"Давай, йди. Бита почекає тебе." "You're lucky I don't smack -you for thinking about leaving.",QUITMSG14,,,,"Máš štěstí, že ti nedám pár facek, -že přemýšlíš o odchodu.","Hast du ein Glück, dass ich -dir keine reinhaue, weil du gehst.",Είσαι τυχερός που δεν σε χτυπάω που σκέφτεσε να φύγεις,"Vi bonŝancas, ke mi ne batas vin -por pripensi foriri.","Tienes suerte que no pueda darte una paliza +you for thinking about leaving.",QUITMSG14,,,,"Máš štěstí, že tě neprofackuju +za to, že přemýšlíš o odchodu.","Du er heldig, at jeg ikke slår dig, +fordi du tænker på at gå.","Hast du ein Glück, dass ich +dir keine reinhaue, weil du gehst.",Είσαι τυχερός που δεν σε χτυπάω που σκέφτεσε να φύγεις,"Vi bonŝancas, ke mi ne batas +vin pro pensado pri foriro.","Tienes suerte de que +no pueda darte una paliza por pensar en salirte.",,"Kiitä onneasi, etten läimäytä sinua siitä hyvästä, että mietit lähtemistä.","Vous êtes chanceux que je ne vous en -colle pas une parce que vous pensez partir.","Szerencsés vagy, hogy nem ütlek meg -a kilépéssel való gondolatoddal.","Sei fortunato che non ti picchi -per aver pensato di andartene.","やめる ことについて考えたのに、 -私に殴られないなんて、君はラッキーだな",나간다는 이유로 싸대기를 날리지 않는 게 다행인 줄 알아.,Je hebt geluk dat ik je niet sla omdat je er niet aan denkt om weg te gaan.,"Masz szczęście, że cię nie zdzielę +colle pas une parce que vous pensez partir.","Mákod van, hogy nem kapsz egy fülest amiért ki akartál lépni.","Sei fortunato che non ti picchi +per aver pensato di andartene.","やめることについて考えたのに、 +私に殴られないなんて、 +君はラッキーだな",나간다는 이유로 싸대기를 날리지 않는 게 다행인 줄 알아.,Je hebt geluk dat ik je niet sla alleen al omdat je eraan denkt te vertrekken.,Flaks for deg at jeg ikke slår deg for å tenke på å dra.,"Masz szczęście, że cię nie zdzielę za myśl o odejściu.","Você tem sorte por eu não te dar uma surra por pensar em sair.","Tens muita sorte em eu não te dar um excerto de porrada por teres pensado em sair.","Ai noroc că nu-ți trag una pentru că te gândești să pleci.","Тебе повезло, что я не вмажу тебе -за то, что ты выходишь.","Имаш среће што те нисам ударио -када си размишља@[ao_1_sr] о одласку." +за то, что ты выходишь.","Имаш среће што те не ошамарим +због тога што одлазиш.",Du har tur att jag inte slår dig för att du funderar på att gå.,Gitmeyi düşündüğün için seni tokatlamadığım için şanslısın.,"Тобі пощастило, що я не шибану тебе за вихід." "Where are you going?! What about the rebellion?",QUITMSG15,,,,"Kam jdeš?! -A co bude s odbojem?","Wo gehst du hin?! -Was ist mit der Rebellion?",Που πάς ? Τί θα συμβεί στην επανάσταση ?,"Kien vi iras?! -Kio pri la ribelo?",¿Adónde vas? ¿Qué hay de la rebelión?,,"Minne olet menossa?! +A co bude s odbojem?","Hvor skal du hen?! +Hvad med oprørerne?","Wo gehst du hin?! +Was ist mit der Rebellion?",Που πάς ? Τί θα συμβεί στην επανάσταση ?,"Kien vi iras!? +Kio pri la ribelo?","¿¡Adónde vas!? +¿Qué hay de la rebelión?",,"Minne olet menossa?! Entä kapina?","Où allez vous? Que va devenir la rébellion?","Hová mész?! És a forradalommal mi lesz?","Dove stai andando?! E la ribellione?","どこに行く気だ?! -反抗するつもりか?",어딜 가는 거야?! 저항군은 어쩌고?,Waar ga je heen?! Hoe zit het met de opstand?,"Gdzie idziesz?! -A co z rebelią?","Para onde está indo?! -E quanto à rebelião?","Para onde estás a ir?! +反抗するつもりか?",어딜 가는 거야?! 저항군은 어쩌고?,Waar ga je heen?! En de rebellie dan?,Hvor skal du?! Hva med opprøret?,"Gdzie idziesz?! +A co z rebelią?","Para onde você vai?! +E a rebelião?","Para onde estás a ir?! E então a rebelião?","Unde pleci?! Cu rebeliunea cum rămâne?","Куда ты собрался? -А как же восстание?!","Где си кренуо?! Шта -је било са устанком?" +А как же восстание?!","Где ћеш? +Шта ће бити са устанком?!",Vart är du på väg?! Hur blir det med upproret?,Nereye gidiyorsun?! İsyan ne olacak?,"Куди зібрався?! +А повстання?" "Carnage interruptus... What a tease!",QUITMSG16,,,,"Masakr přerušus... -Takhle mě neškádli!","Carnage interruptus... -Was für ein Witzbold!",,"Buĉado interruptus... -Kia inciteto!",Masacre interruptus... ¡Qué timo!,,"Verilöyly interruptus... +Takhle mě neškádli!","Carnage interruptus... +Sikke en drillepind!","Carnage interruptus... +Was für ein Witzbold!",,"Buĉado ""interruptus""... +Kia inciteto!","Masacre interruptus... +¡Menudo timo!","Masacre interruptus... +¡Qué estafa!","Verilöyly interruptus... Mikä kiusoitus!","Carnage interruptus... Tout un programme!","Carnage interruptus... -Mily kötekedő!","Macellus interruptus... +Micsoda fenyegetés!","Macellus interruptus... Che presa in giro!","大虐殺は寸止めされた... -何という意地悪なやつだ!",학살중절이라... 놀리는구먼!,Carnage interruptus.... Wat een plaaggeest!,"Rzeź przeszkadza... +何という意地悪なやつだ!",학살중절이라... 놀리는구먼!,De slachting geïnterrumpeerd... Wat flauw!,Carnage interruptus... For en erting!,"Rzeź przeszkadza... Co za złośliwość!","Massacre interrompido... Que provocante!",,"Carnagiu întrerupt... -Ce mai tachinare!","Резня прекращается... -На самом интересном месте!","Покољ прекинут... -Каква зафрканција!" +Ce mai tachinare!","Вот так всегда... +На самом интересном месте!","Покољ се прекида... +на најзанимљивијем месту!",Carnage interruptus... Vilket hångel!,Katliam kesintisi. Ne alay ama!,"Різанина затихає... +Бісить!" "But you're the hope -- my only chance!!",QUITMSG17,,,,"Ale ty jsi naše naděje --- moje jediná šance!",Aber du bist unsere Hoffnung!,Αλλά εσύ είσε η ελπίδα -- η μόνη μου ευκαιρία!,"Sed vi estas la espero — -Mia sola ŝanco!","Pero tú eres la esperanza... +-- moje jediná šance!","Men du er håbet + - min eneste chance!!!",Aber du bist unsere Hoffnung!,Αλλά εσύ είσε η ελπίδα -- η μόνη μου ευκαιρία!,"Sed vi estas la espero... +Mia ununura ŝanco!!","Pero tú eres la esperanza... ¡¡Mi única oportunidad!!",,"Mutta sinä olet toivo -- ainoa mahdollisuuteni!!","Mais vous êtes l'espoir, -notre unique chance!","De te vagy a remény --- az egyetlen esélyem!!","Ma tu sei la speranza --- la mia unica possibilità!!","だがお前が希望なんだ --- 唯一の可能性だ!!",하지만 넌 희망이야- 나의 유일한 기회라고!!,Maar jij bent de hoop – Mijn enige kans!!,"Ale ty jesteś nadzieją +notre unique chance!","Te vagy a remény +-- az egyetlen esélyem!","Ma tu sei la speranza +-- la mia unica possibilità!!","それでもお前を信じている +-- 唯一の希望なんだ!!",하지만 넌 희망이야- 나의 유일한 기회라고!!,Maar jij bent de hoop - Mijn enige kans!!,Men du er håpet... min eneste sjanse!!!,"Ale ty jesteś nadzieją -- moją jedyną szansą!!","Mas você é a esperança --- minha única chance!!","Mas tu és a nossa esperança +— minha única chance!","Mas tu és a nossa esperança -- a minha única chance!!","Dar tu ești speranța -- singura mea șansă!!","Но на тебя вся надежда — -ты мой единственный шанс!","Али ти си нада -- -моја једина шанса!!" -Nobody walks out on Blackbird.,QUITMSG18,,,,Nikdo se neobrací zády ke Strace.,Niemand lässt Blackbird stehen.,Κανένας δεν παρατάει τον Μπλακμπερτ.,Neniu forlasas Merlon.,Nadie abandona a BlackBird.,,Kukaan ei käännä selkäänsä Blackbirdille.,Personne n'abandonne Blackbird!,Senki nem kezdhet ki a Feketerigóval!,Nessuno gira le spalle a Blackbird.,ブラックバードに気付かれず抜け出せるのか。,그 누구도 블랙버드를 내 버릴 수 없지.,Niemand loopt weg op Blackbird.,Nikt nie opuszcza Blackbird.,Ninguém vira as costas para a Blackbird.,,Nimeni nu iese afară pe Blackbird.,Ещё никто не ушёл от Чёрного дрозда.,Нико не бежи од Црне птице. -I thought you were different...,QUITMSG19,,,,"Myslela jsem, že jsi jin@[adj_cs]...","Ich dachte, du wärst anders...",Νόμιζα οτι είσουν διαφορετικός...,Mi pensis ke vi estas malsama...,Pensé que eras diferente...,,"Luulin, että olit erilainen kuin muut...",Je vous croyais différent...,Azt hittem te más vagy...,Pensavo tu fossi diverso...,私は あなたは特別だと思っていた...,난 네가 다를 줄 알았는데...,Ik dacht dat je anders was....,"Myślałam, że jesteś inny...",Eu achei que você era diferente...,Eu achei que eras diferente...,Am crezut că tu ești diferit...,Я думала о тебе иначе...,Мислила сам да си друкчији... -Fine! just kill and run!,QUITMSG20,,,,Fajn! Jen zabij a uteč!,"Na toll! -Töten und dann wegrennen.",Καλά! Απλώς σκότοσε και φύγε!,Bone! Ja mortigu kaj kuru!,¡Bien! ¡Matas y huyes!,,Hyvä! Senkun vain tapat ja lähdet!,"C'est ça! Tuez n'importe-qui -et barrez-vous comme ça!",Oké! csak ölj és fuss!,Ma bravo! uccidi e scappi!,いいぞ! ゲリラ戦の時間だ!,그래그래 알았다! 그럼 그냥 뛰고 죽이기나 해!,"Goed, gewoon doden en rennen!",Dobra! Zabijaj i biegaj!,Ótimo! Mate e fuja!,Pronto! Mata e foge!,Fie! Doar omoară și fugi!,Отлично! Пострелял и смылся!,Добро! Само убијај и бежи! +ты мой единственный шанс!","Али на тебе је сва нада -- +ти си моја једина шанса!",Men du är hoppet - min enda chans!!,"Ama sen umudumsun, tek şansımsın!","Ти ж моя єдина надія - +мій останній шанс!" +Nobody walks out on Blackbird.,QUITMSG18,,,,Nikdo se neobrací zády ke Strace.,Ingen går ud fra Blackbird. ,Niemand lässt Blackbird stehen.,Κανένας δεν παρατάει τον Μπλακμπερτ.,Neniu forlasas Merlon.,Nadie abandona a Blackbird.,,Kukaan ei käännä selkäänsä Blackbirdille.,Personne n'abandonne Blackbird!,Senki nem kezdhet ki a Feketerigóval!,Nessuno gira le spalle a Blackbird.,ブラックバードに気付かれず抜け出せるのか。,그 누구도 블랙버드를 내 버릴 수 없지.,Niemand loopt weg van Blackbird.,Ingen forlater Blackbird.,Nikt nie opuszcza Blackbird.,Ninguém vira as costas para a Blackbird.,,Nimeni nu iese afară pe Blackbird.,Ещё никто не ушёл от «Чёрного дрозда».,Нико још није побегао од Црне птице.,Ingen lämnar Blackbird.,Kimse Karatavuk'ü bırakıp gidemez.,Ще ніхто не дав чосу від Чорного дрозда. +I thought you were different...,QUITMSG19,,,,"Myslela jsem, že jsi jin@[adj_cs]...","Jeg troede, du var anderledes...","Ich dachte, du wärst anders...",Νόμιζα οτι είσουν διαφορετικός...,"Mi pensis, ke vi estas malsama...",Pensé que eras diferente...,Creí que eras diferente...,"Luulin, että olit erilainen kuin muut...",Je vous croyais différent...,Azt hittem te más vagy...,Pensavo tu fossi diverso...,私は あなたは特別だと思っていた...,난 네가 다를 줄 알았는데...,Ik dacht dat je anders was....,Jeg trodde du var annerledes...,"Myślałam, że jesteś inny...",Eu achei que você era diferente...,Eu achei que eras diferente...,Am crezut că tu ești diferit...,Я думал о тебе иначе...,О теби сам мислила другачије...,Jag trodde att du var annorlunda...,Senin farklı olduğunu sanıyordum.,"Я думав, що ти інший..." +Fine! just kill and run!,QUITMSG20,,,,Fajn! Prostě zab a uteč!,Fint! Bare dræb og løb!,"Na toll! +Töten und dann wegrennen.",Καλά! Απλώς σκότοσε και φύγε!,Bone! Nur mortigu kaj fuĝu!,¡Bien! ¡Matas y huyes!,,Hyvä! Senkun vain tapat ja lähdet!,"C'est ça! Tuez n'importe-qui +et barrez-vous comme ça!",Oké! Csak ölj és fuss!,Ma bravo! Uccidi e scappi!,いいぞ! ゲリラ戦の時間だ!,그래그래 알았다! 그럼 그냥 뛰고 죽이기나 해!,"Goed hoor, schieten en meteen wegrennen!",Greit! Bare drep og løp!,Dobra! Zabijaj i biegaj!,Ótimo! Mate e fuja!,Pronto! Mata e foge!,Fie! Doar omoară și fugi!,Отлично! Пострелял и смылся!,Добро! Само убијај и бежи!,Okej! Döda bara och spring!,İyi! Sadece öldür ve kaç!,Прекрасно! Зробив амінь чортам і втік! "You can quit... but you can't hide...",QUITMSG21,,,,"Můžeš odejít... -ale nemůžeš se skrýt...","Du kannst gehen... +ale nemůžeš se skrýt...","Du kan stoppe... +men du kan ikke gemme dig...","Du kannst gehen... aber dich nicht verstecken...","Μπορείς να φύγεις... -αλλά δεν μπορείς να κρυφτείς...","Vi povas ĉesigi... -sed ne sinkaŝi...","Puedes salir... -Pero no puedes esconderte...",,"Voit lopettaa... +αλλά δεν μπορείς να κρυφτείς...","Vi povas foriri... +sed ne kaŝi vin...","Puedes salir... +Pero no esconderte...",,"Voit lopettaa... muttet piiloutua...","Vous pouvez partir... Mais vous ne pouvez pas vous cacher...","Kiléphetsz... de nem bújhatsz el...","Puoi uscire... ma non puoi nasconderti...","終わる事は出来る... -しかし隠れることは出来ない...",나갈 수는 있겠지만... 숨을 수는 없을 거다...,Je kunt stoppen.... Maar je kan je niet verbergen....,"Możesz wyjść... +しかし隠れることは出来ない...",나갈 수는 있겠지만... 숨을 수는 없을 거다...,Je kunt stoppen.... Maar je kan je niet verbergen....,Du kan slutte... men du kan ikke gjemme deg...,"Możesz wyjść... Ale nie możesz się ukryć...","Você pode sair... -mas você não pode se esconder...","Podes sair... +mas não pode se esconder...","Podes sair... mas não te podes esconder...","Poți să ieși... dar nu te poți ascunde...","Ты можешь уйти... -но не можешь спрятаться...","Можеш да одустанеш... -али не можеш и да се кријеш..." +но не можешь спрятаться...","Можеш да одеш... +али не можеш да се кријеш...","Du kan sluta... +men du kan inte gömma dig...",Bırakabilirsin... ama saklanamazsın...,"Ти можеш вийти... +але не сховатись..." "Whaaa, what's the matter? -Mommy says dinnertime?",QUITMSG22,,,,"Cooo, copak je? -Maminka volá na večeři?","Hey, was ist los? +Mommy says dinnertime?",QUITMSG22,,,,"Cóó, copak je? +Maminka volá na večeři?","Whaaa, hvad er der i vejen? Mor siger spisetid?","Hey, was ist los? Hat Mami zum Abendessen gerufen?","Οοοοο, τι είναι το πρόβλημα? -Η μαμμάκα λέι οτι είναι ώρα για βραδινο?","Kiooo, kio okazis? -Ĉu panjo diris, ke fojas manĝi?","Queee, ¿Cuál es el problema? -¿Mami te llama a cenar?",,"Häää, mikä vikana? +Η μαμμάκα λέι οτι είναι ώρα για βραδινο?","Kio!? Kio okazas? Ĉu panjo +diris, ke estas tempo manĝi?","¿Queeeeeé?, ¿qué sucede? +¿Mami te llama a comer?",,"Häää, mikä vikana? Äiti huutaa syömään?","Bah, il est où est le problème? -Maman a dit « à table! »?","Naaaa, mi a baj? -Anya azt mondta hogy vacsora?","Eehi, che problema c'è? +Maman a dit « à table! »?","Naaa, mi a baj? +Anyuci szólt, hogy kész a vacsora?","Eehi, che problema c'è? La mamma ha detto che è ora di cena?","はあぁ、どうしたんだい? -ママに晩飯へ呼ばれたのかよ?","헤에에, 무슨 일이야? 엄마가 저녁 먹으레?","Whaaaaa, wat is er aan de hand? Zegt mama dat het etenstijd is?","Cooo, o co chodzi? -Mama powiedziała, że czas na obiad?","Ué, qual é o problema? -A mamãe disse que é hora de jantar?","Qual é o problema? +ママに晩飯へ呼ばれたのかよ?","헤에에, 무슨 일이야? 엄마가 저녁 먹으레?","Hee, wat is er aan de hand? Zegt mama dat het etenstijd is?","Whaaa, hva er i veien? Sier mamma at det er middag?","Cooo, o co chodzi? +Mama powiedziała, że czas na obiad?","Ué, o que foi? +A mamãe disse que tá na hora da janta?","Qual é o problema? A mamã chamou para o jantar?","Ceee, ce s-a întâmplat? Mami zice că e timpul pentru cină?","Ха! В чём дело? -Мама зовёт обедать?","Штааа, шта је било? -Мама те зове на вечеру?" +Мама зовёт обедать?","Ха! Шта је било? +Мама те зове на вечеру?","Vad är det för fel? +Mamma säger att det är dags för middag?",Ne oldu? Annem yemek vakti mi dedi?,"Гааа, шо таке? +Мамуся покликала їстоньки?" "Don't quit now, there are still flemoids on the loose!",QUITMSG23,,,,"Teď neodcházej, stále tu -pobíhají slizouni!","Bitte gehe nicht, es laufen noch mehr -Flemoiden herum","Μή παραιτηθέις, υπάρχουνε ακόμα φλέμοιντς τα οπία έχουν αποδράσει!","Ne nun ĉesu, ankoraŭ -estas mukuloj vagantaj!","No te vayas ahora, -¡Aún hay flemoides sueltos!",,Älä lopeta nyt; limatuksia on vielä vapaalla!,"N'abandonnez pas maintenant... -Voulez vous toujours quitter?","Ne lépj ki, még sok flemoid maradt hátra!","Non uscire ora, ci sono ancora -flemoidi a piede libero!","まだやめないでくれ、にげだしたフレモイドたちが -のこっているんだから!","부디 종료하지 말아 주세요, 플레모이드들이 아직도 널려있단 말입니다!","Niet stoppen nu, er zijn nog steeds flemoïden op vrije voeten!","Nie wychodź teraz, są tu wciąż flemoidy na wolności!","Não desista agora! Ainda há -flemoids a solta!","Não desistas agora! Ainda há +pobíhají slizouni!","Du må ikke give op nu, der er stadig flemoider på fri fod!","Bitte gehe nicht, es laufen noch mehr +Flemoiden herum","Μή παραιτηθέις, υπάρχουνε ακόμα φλέμοιντς τα οπία έχουν αποδράσει!","Ne nun foriru, ankoraŭ +estas mukuloj amoke!","No te vayas ahora, +¡que aún hay flemoides sueltos!",,Älä lopeta nyt; limatuksia on vielä vapaalla!,"N'abandonnez pas maintenant, les flémoides sont toujours à l'assaut!","Ne lépj ki, még sok slejmoid van szabadon!","Non uscire ora, ci sono ancora +flemoidi a piede libero!","まだやめないでくれ、 +にげだしたフレモイドたちが +のこっているんだから!","부디 종료하지 말아 주세요, 플레모이드들이 아직도 널려있단 말입니다!","Niet stoppen nu, er lopen nog steeds vlezerijen op vrije voeten!","Ikke gi opp nå, det er fortsatt flemoider på frifot!","Nie wychodź teraz, są tu wciąż flemoidy na wolności!","Não saia agora! +Ainda tem flemoides à solta!","Não desistas agora! Ainda há flemoids à solta!","Nu ieși acum, încă mai sunt flemoizi liberi!","Не выходи сейчас! Здесь есть -ещё много флемоидов!","Немој сада да одустајеш, -има још слободних љигавца! " +ещё много флемоидов!","Немој сада да одустајеш! +Има још много љигавца! ","Ge inte upp nu, det finns fortfarande flemoider på fri fot!","Şimdi pes etme, hala serbest flemoidler var!","Не виходь поки, тут ще багато флемоїдів лишилось!" "Don't give up -- the flemoids will get the upper hand!",QUITMSG24,,,,"Teď to nevzdávej - slizouni -budou mít výhodu!","Gib nicht auf - die Flemoiden -gewinnen sonst.",Μή παραιτηθέις -- τα φλέμοιντς θα νικήσουνε!,"Ne rezignu! La mukuloj -atingus la avantaĝon!","No te rindas... -¡Los flemoides tendrán la ventaja!",,Älä luovuta -- limatukset pääsevät voitolle!,"Ne partez pas, ou les -Flémoïdes vont nous battre!",Ne add fel -- a flemoidok lesznek fölényben!,"Non arrenderti -- i flemoidi -ci sopraffaranno!","あきらめてはダメだ、フレモイドたちの -しょうりになってしまうぞ!",부디 포기하지 마시길- 플레모이드들이 그 순간 우세할 것입니다!,Geef niet op – de flemoïden krijgen de overhand!,Nie poddawaj się -- flemoidy będą miały przewagę!,"Não desista -- os flemóides vão -tomar conta!","Não desistas -- os flemóides +budou mít výhodu!","Du må ikke give op - Flemoiderne +er ved at få overtaget!","Gib nicht auf - die Flemoiden +gewinnen sonst.",Μή παραιτηθέις -- τα φλέμοιντς θα νικήσουνε!,"Ne rezignu. La mukuloj +atingus avantaĝon!","No te rindas... ¡o los +flemoides tendrán ventaja!","No te rindas... ¡o los +flemoides van a tener ventaja!",Älä luovuta -- limatukset pääsevät voitolle!,"Ne partez pas, ou les +Flémoïdes vont nous battre!",Ne add fel -- máskülönben slejmoidok győznek!,"Non arrenderti -- i flemoidi +ci sopraffaranno!","あきらめてはダメだ、 +フレモイドたちの しょうりに +なってしまうぞ!",부디 포기하지 마시길- 플레모이드들이 그 순간 우세할 것입니다!,Geef niet op - de vlezerijen krijgen de overhand!,Ikke gi opp - flemoidene vil få overtaket!,Nie poddawaj się -- flemoidy będą miały przewagę!,"Não desista — os flemoides +vão levar a melhor!","Não desistas -- os flemóides estão a ganhar!",Nu renunța - flemoizii vor avea avantajul!,"Не сдавайся — не то флемоиды получат преимущество!","Немој да одустајеш -- -љигавци ће добити предност!" +љигавци ће добити предност!",Ge inte upp - flemoiderna kommer att ta överhanden!,"Sakın pes etme, flemoidler üstünlüğü ele geçirecek!",Не здавайся -- а то флемоїди візьмуть верх! "Don't leave now. We need your help!",QUITMSG25,,,,"Teď neodcházej. -Potřebujeme tvoji pomoc!","Bitte geh nicht. +Potřebujeme tvoji pomoc!",Du må ikke gå nu. Vi har brug for din hjælp!,"Bitte geh nicht. Wir brauchen deine Hilfe.","Μή φύγεις τώρα. -Χρειαζόμαστε τη βοήθεια σου!","Ne nun foriru! +Χρειαζόμαστε τη βοήθεια σου!","Ne nun foriru. Ni bezonas vian helpon!","No te vayas ahora. ¡Necesitamos tu ayuda!",,"Älä lähde nyt. Tarvitsemme apuasi!","S'il vous plaît, ne quittez pas, nous -avons besoin de votre aide!","Ne menj most! +avons besoin de votre aide!","Még ne menj! Szükségünk van a segítségedre!","Non andartene ora. Ci serve il tuo aiuto!","まだかえらないでくれ。 -われわれには きみのたすけが ひつようだ!",지금 떠나지 말아 주세요. 우린 당신의 도움이 필요합니다!,Ga nu niet weg. We hebben je hulp nodig!,"Nie odchodź teraz. +われわれには きみのたすけが +ひつようだ!",지금 떠나지 말아 주세요. 우린 당신의 도움이 필요합니다!,Ga nu niet weg. We hebben je hulp nodig!,Ikke gå nå. Vi trenger din hjelp!,"Nie odchodź teraz. Potrzebujemy twojej pomocy!","Não vá embora agora. -Nós precisamos da sua ajuda!","Não te vás embora agora. +Precisamos da sua ajuda!","Não te vás embora agora. Nós precisamos da tua ajuda!","Nu pleca. Avem nevoie de ajutorul tău!","Не уходи сейчас. -Нам нужна твоя помощь!","Не крећи сад. -Треба нам твоја помоћ!" +Нам нужна твоя помощь!","Не излази сада. +Треба нам твоја помоћ!",Gå inte nu. Vi behöver din hjälp!,Şimdi gitmeyin. Yardımınıza ihtiyacımız var!,"Не залишай нас. +Нам потрібна твоя допомога!" "I hope you're just taking a break for Chex(R) party mix.",QUITMSG26,,,,"Doufám, že si jen dáváš -pauzu na Chex(R) Party Mix.","Ich hoffe mal, dass du nur eine +pauzu na Chex(R) Party Mix.","Jeg håber, at du bare holder en pause for Chex(R) party mix.","Ich hoffe mal, dass du nur eine Pause für Chex(R) Party Mix machst.",Ελπίζω οτι απλώς κάνεις ενα διάλειμμα για ένα Chex (R) μέιγμα.,"Mi esperas, ke vi nur paŭzas por manĝi Chex(R)-festmikson.","Espero que solo estés tomando un descanso -para la fiesta de mix Chex(R).",,Toivottavasti pidät taukoa vain Chex(R) Party Mixiä varten.,"J'espère que tu prends une pause +para la fiesta de mezcladitos Chex(R).",,Toivottavasti pidät taukoa vain Chex(R) Party Mixiä varten.,"J'espère que tu prends une pause pour un bol de Chex(R) Party Mix.","Remélem, hogy csak egy szünetet tartasz a Chex(R) parti mixhez.","Spero tu stia solo facendo una -pausa per prendere un Chex(R) party mix.",チェックス(R)パーティミックスをたべるためにおやすみかな?,첵스(R) 한 박스를 뜯기 위해서 잠시 중단하는 거였으면 좋겠군요.,Ik hoop dat je gewoon een pauze neemt voor Chex(R) party mix.,"Mam nadzieję, że robisz sobie przerwę na -mieszankę płatków Chex(R).","Espero que só esteja fazendo uma -pausa pra fazer um Chex(R) Party Mix.","Espero que só estejas a fazer uma -pausa pra fazer um Chex(R) Party Mix.","Sper că iei doar o pauză cu un bol de cereale +pausa per prendere un Chex(R) party mix.","チェックス(R)パーティミックスを +たべるためにおやすみかな?",첵스(R) 한 박스를 뜯기 위해서 잠시 중단하는 거였으면 좋겠군요.,Ik hoop dat je gewoon een pauze neemt voor Chex(R) party mix.,Jeg håper du bare tar en pause for Chex(R) party mix.,"Mam nadzieję, że robisz sobie przerwę na +mieszankę płatków Chex(R).","Tomara que só esteja fazendo uma +pausa pra um Chex(R) Party Mix.","Espero que só estejas a fazer uma +pausa pra um Chex(R) Party Mix.","Sper că iei doar o pauză cu un bol de cereale Chex(R).","Надеюсь, ты лишь делаешь перерыв на тарелку хлопьев Chex(R).","Надам се да само паузираш -за Chex житарице." +за Chex житарице.",Jag hoppas att du bara tar en paus för Chex(R) party mix.,Umarım Chex(R) parti karışımı için ara vermişsinizdir.,"Маю надію, що ти робиш перерву на пластівці Chex(R)." "Don't quit now! We need your help!",QUITMSG27,,,,"Teď neodcházej. -Potřebujeme tvoji pomoc!","Bitte verlasse uns nicht. +Potřebujeme tvoji pomoc!",Du må ikke give op nu! Vi har brug for din hjælp!,"Bitte verlasse uns nicht. Wir brauchen deine Hilfe.","Μή κάνεις έξοδο τώρα. -Χρειαζόμαστε τη βοήθεια σου!","Ne nun ĉesu! +Χρειαζόμαστε τη βοήθεια σου!","Ne nun forlasu! Ni bezonas vian helpon!","¡No salgas ahora! ¡Necesitamos tu ayuda!",,"Älä lopeta nyt! Tarvitsemme apuasi!","Restez avec nous! -Nous avons besoin de vous!","Ne lépj ki! +Nous avons besoin de vous!","Ne menj el most! Kell a segítséged!","Non uscire ora! Ci serve il tuo aiuto!","まだやめないでくれ! -われわれには きみのたすけが ひつようだ!",지금 그만두지 마세요! 우린 당신의 도움이 필요합니다!,Niet stoppen nu! We hebben je hulp nodig!,"Nie wychodź teraz! +われわれには きみのたすけが +ひつようだ!",지금 그만두지 마세요! 우린 당신의 도움이 필요합니다!,Niet stoppen nu! We hebben je hulp nodig!,Ikke gi opp nå! Vi trenger din hjelp!,"Nie wychodź teraz! Potrzebujemy twojej pomocy!","Não saia agora! -Nós precisamos da sua ajuda!","Não saias agora! +Precisamos da sua ajuda!","Não saias agora! Nós precisamos da tua ajuda!","Nu abandona acum! -Avem nevoie de ajutorul tău!","Не уходи сейчас! +Avem nevoie de ajutorul tău!","Не бросай всё сейчас! Нам нужна твоя помощь!","Не одустај сада! -Треба нам твоја помоћ!" +Треба нам твоја помоћ!",Sluta inte nu! Vi behöver din hjälp!,Şimdi bırakmayın! Yardımınıza ihtiyacımız var!,"Не виходь! +Нам потрібна твоя допомога!" "Don't abandon the Intergalactic Federation of Cereals!",QUITMSG28,,,,"Neopouštěj Intergalaktickou -federaci cereálií!","Bitte lasse die Intergalaktische -Föderation der Cerealien nicht im Stich!",Μήν εγκαταλήψεις την Διαγαλαξιακή Ομοσπονδία των Δημητριακών!,"Ne forlasu la -Intergalaksian Federacion de Cerealaĵoj!",¡No abandones a la federación intergaláctica de cereales!,,Älä hylkää intergalaktista muroliittoa!,"N'abandonnez pas la +federaci cereálií!",Forlad ikke den Intergalaktiske Føderation af Cerealprodukter!,"Bitte lasse die Intergalaktische +Föderation der Cerealien nicht im Stich!",Μήν εγκαταλήψεις την Διαγαλαξιακή Ομοσπονδία των Δημητριακών!,"Ne forlasu la Intergalaksian +Federacion de Cerealaĵoj!","¡No abandones a la Federación +Intergaláctica de Cereales!",,Älä hylkää intergalaktista muroliittoa!,"N'abandonnez pas la Fédération Intergalactique des Céréales!","Ne hagyd cserben az -Intergalaktikus Müzliszövetséget!","Non abbandonare la -Federazione Intergalattica dei Cereali!",ぎんがシリアルれんぽう を みすてないでくれ!,은하연합시리얼국을 위해서라도 부디 떠나지 말아 주시길 바랍니다!,Laat de Intergalactische Federatie van Granen niet in de steek!,Nie opuszczaj Międzygalaktycznej Federacji Płatków!,"Não abandone a -Federação Intergalática de Cereais!",,Nu abandona Federația Intergalactică a Cerealelor!,"Не оставляй +Intergalaktikus Müzli Szövetséget!","Non abbandonare la +Federazione Intergalattica dei Cereali!","ぎんがシリアルれんぽう を +みすてないでくれ!",은하연합시리얼국을 위해서라도 부디 떠나지 말아 주시길 바랍니다!,Laat de Intergalactische Federatie van Granen niet in de steek!,Ikke forlat Den intergalaktiske kornføderasjonen!,Nie opuszczaj Międzygalaktycznej Federacji Płatków!,"Não abandone a +Federação Intergaláctica de Cereais!",,Nu abandona Federația Intergalactică a Cerealelor!,"Не оставляй Межгалактическую Федерацию Хлопьев!","Не напуштај Интергалактичку -федерацију овсених пахуљица!" +федерацију овсених пахуљица!",Överge inte Intergalactic Federation of Cereals!,Galaksilerarası Tahıl Federasyonu'nu terk etmeyin!,Не покидай Міжгалактичну Федерацію Пластівців! "The real Chex(R) Warrior wouldn't give up so fast!",QUITMSG29,,,,"Skutečný Chex(R) bojovník -by se tak rychle nevzdal!","Der echte Chex(R) Krieger +by se tak rychle nevzdal!",Den rigtige Chex(R)-kriger ville ikke give op så hurtigt!,"Der echte Chex(R) Krieger würde nicht so schnell aufgeben.",Ο αληθινός Chex(R) Πολεμιστής δέν θα έφευγε τοσο γρήγορα!,"La vera Chex(R)-batalisto -ne rezignus tiel rapide!",¡El verdadero guerrero Chex(R) no se rendiría tan rápido!,,Todellinen Chex(R)-soturi ei luovuttaisi niin nopeasti!,"Le vrai Chex Warrior +ne rezignus tiel rapide!","¡El verdadero Chex(R) Warrior +no se rendiría tan rápido!",,Todellinen Chex(R)-soturi ei luovuttaisi niin nopeasti!,"Le vrai Chex Warrior n'abandonnerait pas de si tôt!","Az igazi Chex(R) Harcos nem adná fel ilyen gyorsan!","Il vero Guerriero Chex(R) non si arrenderebbe così in fretta!","しんのチェックス(R)せんしは -そんなにすぐあきらめはしないぞ!",진정한 첵스(R)전사는 그렇게 빨리 포기하지 않을 것입니다!,De echte Chex(R) Krijger wilde niet zo snel opgeven!,"Prawdziwy Wojownik Chex(R) -nie poddałby się tak szybko!","O verdadeiro Chex(R) Warrior +そんなにすぐあきらめはしないぞ!",진정한 첵스(R)전사는 그렇게 빨리 포기하지 않을 것입니다!,De echte Chex(R) Krijger zou niet zo snel opgeven!,Den ekte Chex(R) kriger ville ikke gitt opp så fort!,"Prawdziwy Wojownik Chex(R) +nie poddałby się tak szybko!","O verdadeiro Guerreiro Chex(R) não desistiria tão rapido!",,"Adevăratul Luptător Chex(R) nu s-ar da bătut atât -de ușor!","Настоящий Воин Chex(R) +de ușor!","Настоящий воин Chex(R) не сдастся так быстро!","Прави Чекс ратници не -би одустали тако лако!" -,,Pickups,,,,,,,,,,,,,,,,,,,,, -You got a pickup,TXT_DEFAULTPICKUPMSG,,,,Dostal@[ao_cs] jsi věc,Du hast etwas aufgesammelt,Πήρες ένα πράγμα.,Vi akiris aĵon,Obtuviste un objeto.,,Poimit jotakin,Quelque chose récupéré.,Felvettél egy tárgyat.,Hai raccolto qualcosa ,何か拾った,무언가를 집어냈다,Je hebt een pick-up...,Podniesiono przedmiot,Você pegou alguma coisa,Apanhaste um item,Ai ridicat un obiect.,Что-то получено,Покупили сте нешто -,,Locks,,,,,,,,,,,,,,,,,,,,, -Any key will open this door,PD_ANY,,,,Jakýkoliv klíč otevře tyto dveře,Jeder Schlüssel wird diese Tür öffnen,Οποιδήποτε κλειδί θα ανοίξει τη πόρτα,Iu ajn ŝlosilo povas malfermi ĉi tiun pordon,Cualquier llave puede abrir esta puerta,,Mikä tahansa avain avaa tämän oven,N'importe quelle clé peut ouvrir cette porte.,Bármilyen kulcs kinyitja ezt az ajtót.,Una chiave qualunque aprirà questa porta,いずれかのキーで開けることができる。,어느 열쇠든 이 문을 열 수 있습니다,Elke sleutel zal deze deur openen.,Dowolny klucz otworzy te drzwi,Qualquer chave abrirá essa porta,Qualquer chave pode abrir esta porta,Orice cheie va deschide ușa aceasta.,Для открытия нужен любой ключ,Било који кључ може да отвори ова врата -Any key will activate this object,PD_ANYOBJ,,,,Jakýkoliv klíč aktivuje tento objekt,Jeder Schlüssel wird dieses Objekt aktivieren,Οποιδήποτε κλειδί θα ενεργοποιήσει αυτό το αντικείμενο,Iu ajn ŝlosilo povas aktivigi ĉi tiun objekton,Cualquier llave puede activar este objeto,,Mikä tahansa avain aktivoi tämän kappaleen,N'importe quelle clé peut activer cet objet.,Bármilyen kulcs aktiválja ezt az objektumot.,Una chiave qualunque attiverà questo oggetto,いずれかのキーで起動させることができる。,어느 열쇠든 이 물체를 작동 시킬 것입니다,Elke sleutel zal dit object activeren.,Dowolny klucz aktywuje ten przedmiot,Qualquer chave ativará este objeto,Qualquer chave pode ativar este objeto,Orice cheie va activa obiectul acesta.,Для активации нужен любой ключ,Било који кључ може да активира овај предмет -You need all three keys to open this door,PD_ALL3,,,,Všechny tři klíče jsou potřeba k otevření těchto dveří,"Du brauchst alle drei Schlüssel, um diese Tür zu öffnen",Χρειάζεσαι όλα τα τρία κλειδία για να ανοίξεις αυτή τη πόρτα,Vi bezonas ĉiujn tri ŝlosilojn por malfermi ĉi tiun pordon,Necesitas las tres llaves para abrir esta puerta,,Kaikki kolme avainta tarvitaan tämän oven avaamiseksi,Il vous faut une clé de chaque couleur pour ouvrir cette porte.,"Mind a 3 kulcs szükséges, hogy kinyisd ezt az ajtót.",Ti servono tutte e tre le chiavi per aprire questa porta,3つのキー全てが無ければ開かない。,이 문을 열기 위해선 3 종류의 열쇠가 필요합니다,Je hebt alle drie de sleutels nodig om deze deur te openen.,"Potrzebujesz wszystkich trzech kluczy, aby otworzyć te drzwi",Você precisa de todas as três chaves para abrir essa porta,Precisas de todas as três chaves para abrir esta porta,"Ai nevoie de toate cele trei chei pentru a deschide -ușa aceasta.",Для открытия требуются все три ключа,Треба вам сва три кључа да би отворили ова врата -You need all three keys to activate this object,PD_ALL3O,,,,Všechny tři klíče jsou potřeba k aktivaci tohoto objektu,"Du brauchst alle drei Schlüssel, um dieses Objekt zu aktivieren",Χρειάζεσε όλα τα τρία κλειδιά για να ενεργοποιήσεις αυτό το αντικείμενο,Vi bezonas ĉiujn tri ŝlosilojn por aktivigi ĉi tiun objekton,Necesitas las tres llaves para activar este objeto,,Kaikki kolme avainta tarvitaan tämän kappaleen aktivoimiseksi,Il vous faut une clé de chaque couleur pour activer cet objet.,Mind a 3 kulcs kell hogy aktiváld ezt az objektumot.,Ti servono tutte e tre le chiavi per attivare questo oggetto ,3つのキー全てが必要だ。,이 물체를 작동시키기 위해선 3 종류의 열쇠가 필요합니다,Je hebt alle drie de sleutels nodig om dit object te activeren.,"Potrzebujesz wszystkich trzech kluczy, aby aktywować ten przedmiot",Você precisa de todas as três chaves para ativar este objeto,Precisas de todas as três chaves para ativar este objeto,"Ai nevoie de toate cele trei chei pentru a activa -acest obiect.",Для активации требуются все три ключа,Треба вам сва три кључа да би активирали овај предмет -You need all six keys to open this door,PD_ALL6,,,,Všech šest klíčů je potřeba k otevření těchto dveří,"Du brauchst alle sechs Schlüssel, um diese Tür zu öffnen",Χρειάζεσαι όλα τα έξι κλειδία για να ανοίξεις αυτή τη πόρτα,Vi bezonas ĉiujn ses ŝlosilojn por malfermi ĉi tiun pordon,Necesitas las seis llaves para abrir esta puerta,,Kaikki kuusi avainta tarvitaan tämän oven avaamiseksi,Il vous faut les six clés pour ouvrir cette porte.,Mind a 6 kulcsnak meg kell lennie az ajtó kinyitásához.,Ti servono tutte e sei le chiavi per aprire questa porta,6つ全てのキーが無ければ開かない。,이 문을 열기 위해선 6 종류의 열쇠가 필요합니다,Je hebt alle zes de sleutels nodig om deze deur te openen.,"Potrzebujesz wszystkich sześciu kluczy, aby otworzyć te drzwi",Você precisa de todas as seis chaves para abrir essa porta,Precisas de todas as seis chaves para abrir esta porta,"Ai nevoie de toate cele sase chei pentru a deschide -aceasta usa.",Для открытия требуются все шесть ключей,Треба вам свих шест кључева да би отворили ова врата -You need all six keys to activate this object,PD_ALL6O,,,,Všech šest klíčů je potřeba k aktivaci tohoto objektu,"Du brauchst alle sechs Schlüssel, um dieses Objekt zu aktivieren",Χρειάζεσε όλα τα έξι κλειδιά για να ενεργοποιήσεις αυτό το αντικείμενο,Vi bezonas ĉiujn ses ŝlosilojn por aktivigi ĉi tiun objekton,Necesitas las seis llaves para activar este objeto,,Kaikki kuusi avainta tarvitaan tämän kappaleen aktivoimiseksi,Il vous faut les six clés pour activer cet objet.,"Mind a 6 kulcs kell, hogy aktiváld ezt az objektumot.",Ti servono tutte e tre le chiavi per attivare questo oggetto ,6つ全てのキーが必要だ。,이 물체를 작동시키기 위해선 6 종류의 열쇠가 필요합니다,Je hebt alle zes de sleutels nodig om dit object te activeren.,"Potrzebujesz wszystkich sześciu kluczy, aby aktywować ten przedmiot",Você precisa de todas as seis chaves para ativar este objeto,Precisas de todas as seis chaves para ativar este objeto,"Ai nevoie de toate cele șase chei pentru a activa -acest obiect.",Для активации требуются все шесть ключей,Треба вам свих шест кључева да би активирали овај предмет -You need all the keys,PD_ALLKEYS,,,,Potřebuješ všechny klíče.,Du brauchst alle Schlüssel,Χρειάζεσαι όλα τα κλειδία,Vi bezonas ĉiom de la ŝlosiloj,Necesitas todas las llaves,,Kaikki avaimet tarvitaan,Vous avez besoin de toutes les six clés.,Az összes kulcsra szükség van.,Ti servono tutte le chiavi,全てのキーが必要だ。,모든 열쇠가 필요합니다,Je hebt alle sleutels nodig.,Potrzebujesz wszystkich kluczy,Você precisa de todas as chaves,Precisas de todas as chaves,Ai nevoie de toate cheile.,Требуются все ключи,Треба вам сви кључеви -,,Obituaries,,,,,,,,,,,,,,,,,,,,, -%o suicides.,OB_SUICIDE,,,,%o spáchal@[ao_cs] sebevraždu.,%o begeht Selbstmord.,@[art_gr] %o αυτοκτόνησε,%o sinmortigas.,%o se suicidó.,,%o teki itsemurhan.,%o se suicide.,%o öngyilkos lett.,%o si è suicidato.,%o は自殺した。,%o 은(는) 자살했다.,%o heeft zelfmoord gepleegd.,%o popełnił@[ao_pl] samobójstwo.,%o se suicidou.,,%o se sinucide.,%o покончил@[ao_rus] с собой.,%o самоубиства. -%o fell too far.,OB_FALLING,,,,%o spadl@[ao_cs] příliš daleko.,%o fiel zu tief.,@[art_gr] %o έπεσε,%o falis tro foren.,%o se cayó desde muy alto.,,%o putosi liian kaukaa.,%o est tombé@[e_fr] trop loin.,%o túl nagyot esett.,%o è caduto troppo in basso.,%o はあまりにも高い所から転落した。,%o 은(는) 높은 곳에서 떨어져 사망했다.,%o viel te ver.,%o spadł@[ao_pl] za daleko.,%o caiu de um lugar alto.,,%o a căzut prea departe.,%o упал@[ao_rus] слишком высоко.,%o је па@[ao_1_sr] до сад. -%o was squished.,OB_CRUSH,,,,%o byl@[ao_cs] rozdrcen@[ao_cs].,%o wurde zerquetscht,@[art_gr] %o συνθλίφτηκε,%o dispremiĝis.,%o fue aplastad@[ao_esp].,,%o liiskautui.,%o a été écrasé@[e_fr].,%o össze lett lapítva.,%o è stato schiacciato.,%o は潰された。,%o 은(는) 뭉게졌다.,%o werd geplet.,%o spłaszczył@[ao_pl] się.,%o foi esmagad@[ao_ptb].,,%o a fost strivit.,%o был@[ao_rus] раздавлен@[ao_rus].,%o је здробљен@[adj_1_sr]. -%o tried to leave.,OB_EXIT,,,,%o se pokusil@[ao_cs] odejít.,%o wollte gehen.,@[art_gr] %o προσπάθησε να φύγει,%o provis foriri.,%o trató de huir.,,%o yritti häipyä.,%o a tenté de partir.,%o megpróbált lelépni.,%o ha provato a uscire.,%o は逃げようとした。,%o 은(는) 나가려고 발버둥 쳤다.,%o probeerde te vertrekken.,%o spróbował@[ao_pl] odejść.,%o tentou sair.,,%o a încercat să plece.,%o попытал@[refl_rus] свалить.,%o покуша@[ao_1_sr] да оде. -%o can't swim.,OB_WATER,,,,%o neumí plavat.,%o kann nicht schwimmen.,@[art_gr] %o δέν μπορεί να κολυμπήσει,%o ne povas naĝi.,%o no sabe nadar.,,%o ei osaa uida.,%o ne sait pas nager.,%o nem tud úszni.,%o non sapeva nuotare.,%o は泳げなかった。,%o 은(는) 익사했다.,%o kan niet zwemmen.,%o nie umie pływać.,%o não sabe nadar.,,%o nu poate înota.,%o не умел@[ao_rus] плавать.,%o не може да плива. -%o mutated.,OB_SLIME,,,,%o zmutoval@[ao_cs].,%o mutierte.,@[art_gr] %o μεταλάχθηκε,%o mutaciis.,%o ha mutado.,,%o mutatoitui.,%o a muté.,%o mutánssá alakult.,%o è mutato.,%o は変異した。,%o 은(는) 돌연사를 당했다.,%o gemuteerd.,%o zmutował@[ao_pl].,%o sofreu mutação.,,%o a avut parte de o mutație.,%o мутировал@[ao_rus].,%o је мутиран@[adj_1_sr]. -%o melted.,OB_LAVA,,,,%o se rozpustil@[ao_cs].,%o schmolz.,@[art_gr] %o έλειοσε,%o fandiĝis.,%o se ha fundido.,,%o suli.,%o a fondu.,%o szétolvadt.,%o si è sciolto.,%o は溶かされた。,%o 은(는) 녹아버렸다.,%o gesmolten.,%o stopił@[ao_pl] się.,%o derreteu.,%o derreteu-se.,%o s-a topit.,%o расплавил@[refl_rus].,%o је отопљен@[adj_1_sr]. -%o went boom.,OB_BARREL,,,,%o udělal@[ao_cs] bum.,%o explodierte.,@[art_gr] %o έσκασε,%o bumis.,%o explotó en mil pedazos.,,%o poksahti.,%o s'est pété@[e_fr] la face.,%o felrobbant.,%o ha fatto bum.,%o は爆発で吹き飛ばされた。,%o 은(는) 폭사했다.,%o ging boem.,%o zrobił@[ao_pl] bum.,%o explodiu.,,%o a explodat.,%o взорвал@[refl_rus].,%o је отиш@[ao_2_sr] бум. -%o stood in the wrong spot.,OB_SPLASH,,,,%o stál@[ao_cs] na špatném místě.,%o war am falschen Ort.,@[art_gr] %o έκατσε στο λάθος σημείο,%o staris en la malĝusta loko.,%o estaba en el sitio equivocado.,,%o seisoi väärässä paikassa.,%o s'est tenu@[e_fr] au mauvais endroit.,%o rossz helyre állt.,%o si è trovato nel posto sbagliato.,%o はいけない場所に立っていた。,%o 은(는) 위험한 곳에 서 있었다.,%o stond op de verkeerde plaats.,%o stan@[irreg_2_pl] w złym miejscu.,%o ficou no lugar errado.,,%o a stat în locul nepotrivit.,%o стоял@[ao_rus] в неверной точке.,%o је стаја@[ao_1_sr] на погрешно место. -%o should have stood back.,OB_R_SPLASH,,,,%o měl@[ao_cs] stát o trochu dál.,%o hätte Abstand halten sollen.,@[art_gr] %o έπρεπε να είχε κάτσι πίσω,%o devintus forstari.,%o debió haberse apartado.,,%o oli liian likellä.,%o aurait dû garder ses distances.,%o hátrébb mehetett volna.,%o si sarebbe dovuto allontanare.,%o は後ろへ引くべきだった。,%o 은(는) 좀 더 떨어져야만 했다.,%o had afstand moeten houden.,%o nie ustąpił@[ao_pl] na bok.,%o deveria ter se afastado.,,%o ar fi trebuit să stea deoparte.,%o не отступил@[ao_rus] в сторону.,Играчу %o је требало да стоји назад. -%o should have stood back.,OB_ROCKET,,,,%o měl@[ao_cs] stát o trochu dál.,%o hätte Abstand halten sollen.,@[art_gr] %o έπρεπε να είχε κάτσι πίσω,%o devintus forstari.,%o debió haberse apartado.,,%o oli liian likellä.,%o aurait dû garder ses distances.,%o hátrébb mehetett volna.,%o si sarebbe dovuto allontanare.,%o は後ろへ引くべきだった。,%o 은(는) 더 멀리 떨어져야만 했다.,%o had afstand moeten houden.,%o nie ustąpił@[ao_pl] na bok.,%o deveria ter se afastado.,,%o ar fi trebuit să stea deoparte.,%o не отступил@[ao_rus] в сторону.,Играчу %o је требало да стоји назад. -%o killed %hself.,OB_KILLEDSELF,,,,%o se zabil@[ao_cs].,%o tötete sich selbst.,@[art_gr] %o αυτοκτόνησε,%o mortigis sin.,%o se mató a sí mism@[ao_esp].,,%o tappoi itsensä.,%o s'est tué@[e_fr].,%o megölte magát.,%o ha ucciso se stesso.,%o は自滅した。,%o 은(는) 자멸했다.,%o heeft zelfmoord gepleegd.,%o zabił@[ao_pl] się.,%o se matou.,%o matou-se,%o s-a sinucis.,%o покончил@[ao_rus] с собой.,%o је уби@[ao_1_sr] себе. -%o was killed by the power of voodoo.,OB_VOODOO,,,,%o byl@[ao_cs] zabit@[ao_cs] sílou voodoo.,%o wurde durch Voodoo getötet.,@[art_gr] %o πέθανε απο τη δύναμη του βουντου,%o estas mortiga de la potenco de voduo.,%o ha sido asesinad@[ao_esp] con el poder del vudú.,,%o kuoli voodoon voimasta.,%o a succombé au pouvoir du Vaudou.,%o meghalt a voodoo erejének köszönhetően.,%o è stato ucciso dalla potenza del voodoo.,%o はブードゥー人形で殺された。,%o 은(는) 부두 마법의 저주를 받았다.,%o werd gedood door de kracht van voodoo.,%o umarł@[ao_pl] od mocy voodoo.,%o morreu pelo poder do voodoo.,,%o a fost omorât prin puterea voodoo.,Игрока %o убила сила Вуду.,%o је убијен@[adj_1_sr] од стране моћи Voodoo-а. -%o was telefragged by %k.,OB_MPTELEFRAG,,,,%o byl@[ao_cs] telefraggnut %kem.,%o stand %k im Wege.,@[art_gr] %o κοματιάστηκε μέσω τηλεμεταφοράς απο τον/την %k,%o estas teleportĉesiga de %k.,%o ha sido telefragmentad@[ao_esp] por %k.,,%k telefräggäsi %o paran.,%o a été téléfragué@[e_fr] par %k.,%o telefrag-et kapott %k által.,%o è stato telefraggato da %k.,%o は %k にテレフラグされた。,%o 은(는) %k 에 의해 텔레프랙을 당했다.,%o werd gefragged door %k.,%o został@[ao_pl] ztelefragowan@[adj_pl] przez %k.,%o foi telefragad@[ao_ptb] por %k.,,%o a fost omorât prin teleportare de către %k.,Игрок %k телефрагнул игрока %o.,%o је телефрагован@[adj_1_sr] од стране %k. -%o was telefragged.,OB_MONTELEFRAG,,,,%o byl@[ao_cs] telefraggnut@[ao_cs].,%o stand jemandem im Wege.,@[art_gr] %o κοματιάστηκε μέσω τηλεμεταφοράς,%o estas teleportĉesiga.,%o ha sido telefragmentad@[ao_esp].,,%o telefrägättiin.,%o a été téléfragué@[e_fr].,%o telefraggelve lett.,%o si è fatto telefraggare.,%o はテレフラグされた。,%o 은(는) 텔레프랙을 당했다.,%o werd gefragged.,%o został@[ao_pl] ztelefragowan@[adj_pl].,%o foi telefragad@[ao_ptb] por um monstro.,,%o a fost omorât prin teleportare.,Игрока %o телефрагнуло.,%o је телефрагован@[adj_1_sr]. -%o died.,OB_DEFAULT,,,,"%o zemřel@[ao_cs]. -",%o ist gestorben.,@[art_gr] %o πέθανε,%o mortis.,%o ha muerto.,,%o kuoli.,%o est mort@[e_fr].,%o meghalt.,%o è morto.,%o は死亡した。,%o 은(는) 죽었다.,%o stierf.,%o umarł@[ao_pl].,%o morreu.,,%o a murit.,Игрок %o погиб.,%o је умр@[ао_1_ср]. -%o was killed by %k.,OB_MPDEFAULT,,,,%o byl@[ao_cs] zabit@[ao_cs] hráčem %k.,%o wurde von %k getötet.,@[art_gr] %o στοτώθηκε απο τον/την %k,%o estis mortigita de %k.,%o ha sido asesinad@[ao_esp] por %k.,,%k tappoi %o paran.,%o a été tué@[e_fr] par %k.,%k megölte %o-t.,%o è stato ucciso da %k,%o は %k によって殺された。,%o 은(는) %k 에 의해 죽임을 당했다.,%o werd gedood door %k.,%o został@[ao_pl] zabit@[adj_pl] przez %k.,%o foi mort@[ao_ptb] por %k.,,%o a fost omorât de către %k.,Игрок %o убит %k.,%o је убијен@[adj_1_sr] од стане %k. -%k mows down a teammate.,OB_FRIENDLY1,,,,%o rozsekal@[ao_cs] spoluhráče.,%o wurde von einem Teamkameraden niedergestreckt.,Ο/Η %k σκότωσε έναν σύμαχο,%k buĉas teamanon.,%k acribilla a un compañero.,,%k niitti joukkuetoverin.,%k élimine un de ses équipiers.,%k lekaszabolta a csapattársát.,%k falcia via un compagno.,%k は仲間を無慈悲に殺した。,%o 은(는) 자신의 팀원을 죽였다.,%k maait een teamgenoot neer.,%k kosi kompana.,%k matou um colega de equipe.,%k matou um companheiro de equipa.,%k face pulbere pe un coechipier.,Игрок %k убил союзника.,Играч %k је покосио саиграча. -%k seems to need glasses.,OB_FRIENDLY2,English was changed to remove problematic pronoun referencing the killer,,,%k potřebuje brýle.,%k sollte eine Brille benutzen.,Ο/Η %k φαίνεται να χρειάζετε γυαλία,%o ŝajnas bezoni okulvitrojn.,%k comprueba sus gafas.,,%k näyttää tarvitsevan laseja.,%k vérifie ses lunettes.,%k-nak szemüvegre van szüksége.,%k sembra che abbia bisogno di occhiali.,%k には眼鏡が必要なようだ。,%o 은(는) 자신의 안경을 확인했다.,%k lijkt een bril nodig te hebben.,%k wydaje się potrzebować okularów.,%k parece que precisa de óculos.,,%k pare să aibă nevoie de ochelari.,Игроку %k следует проверить свои очки.,Играчу %k приличиле би наочаре. -%k gets a frag for the other team.,OB_FRIENDLY3,,,,%k dostal@[ao_cs] frag pro další tým.,%k macht für das andere Team einen Punkt.,Ο/Η %k πάιρνει έναν κοματιασμό για την άλλη ομάδα.,%k gajnas ĉeson por la alia teamo.,%k marca una baja para el otro equipo.,,%k teki frägin vieraalle joukkueelle.,%k marque un point pour l'autre équipe.,%k szerez egy frag-et a másik csapatnak.,%k regala un frag all'altro team.,%k は敵チームに得点を入れた。,%o 은(는) 의도치 않게 상대방 팀을 도왔다.,%k krijgt een fragiliteit voor het andere team.,%k zdobywa fraga dla przeciwnej drużyny.,%k dá um frag para o outro time.,%k dá um frag para a outra equipa.,%k face o victimă pentru echipa adversă.,Игрок %k преподнёс другой команде фраг.,%k добија фраг за други тим. -%k loses another friend.,OB_FRIENDLY4,,,,%k ztratil@[ao_cs] dalšího přítele.,%k hat wieder einen Freund verloren.,Ο/Η %k χάνει ακόμα έναν αλλο φίλο,%k perdas pluan amikon.,%k pierde otro amigo.,,%k menetti jälleen ystävän.,%k a perdu un autre ami.,%k elveszít egy másik barátot.,%k perde un altro amico.,%k はまた友達を失った。,%o 은(는) 친구를 원치 않았다.,%k verliest nog een vriend.,%k tracil kolejnego przyjaciela.,%k perde mais um amigo.,,%k mai pierde un prieten.,Игрок %k потерял ещё одного друга.,%k изгуби још једног пријатеља. -,,Blood Bath Announcer,,,,,,,,,,,,,,,,,,,,, -%k boned %o like a fish,BBA_BONED,,,,%o byl@[ao_cs] vykoštěn@[ao_cs] jako ryba hráčem %k,%k hat %o zerlegt wie einen Fisch,Ο/Η %k ξεκοκάλοσε @[pro2_gr] %o σα ψάρι,%k senostigis %o kiel fiŝon,%k deshuesó a %o como a un pescado,,%k perkasi %o paran kuin kalan,%k désossa %o comme un poisson,%k kifilézte %o -t mint a halat,%k ha dissossato %o come un pesce,%k は %o の骨を魚のように引っこ抜いた。,%k 은(는) %o 의 뼈를 발랐다.,%k uitgebeend %o zoals een vis,%k odfiletował@[ao_pl] %o jak rybę,%k desossou %o como um peixe,,%k l-a dezosat pe %o ca pe un pește,Игрок %k пересчитал косточки игрока %o,%k је очистио %o као рибу -%k castrated %o,BBA_CASTRA,,,,%o byl@[ao_cs] vykastrován@[ao_cs] hráčem %k,%k hat %o kastriert,Ο/Η %k ευνούχισε %o,%k kastris %o,%k castró a %o,,%k kastroi %o paran,%k castra %o,%k kasztrálta %o -t,%k ha castrato %o,%k は %o を去勢した。,%k 은(는) %o 을(를) 거세시켰다.,%k gecastreerd %o,%k wykastrował@[ao_pl] %o,%k castrou %o,,%k l-a castrat pe %o,Игрок %k кастрировал игрока %o,%k је кастрирао %o -%k creamed %o,BBA_CREAMED,,,,%o byl@[ao_cs] rozšlehán@[ao_cs] hráčem %k,%k hat %o eingeseift,Ο/Η %k κρέμασε @[pro2_gr] %o,%k kremigis %o,%k cremó a %o,,%k kermasi %o paran,%k a battu %o à plate couture ,%k elkente %o -t,%k ha cremato %o,%k は %o に反吐ブチ撒けさせた。,%k 은(는) %o 을(를) 양념시켰다.,%k romed %o,%k spienił@[ao_pl] %o,%k fez creme de %o,,%k l-a transformat în cremă pe %o,Игрок %k взбил игрока %o,%k је истукао %o -%k decimated %o,BBA_DECIMAT,,,,%o byl@[ao_cs] zdecimován@[ao_cs] hráčem %k,%k hat %o dezimiert,Ο/Η %k αποδεκάτισε @[pro2_gr] %o,%k detruegis %o,%k diezmó a %o,,%k hävitti %o paran,%k a décimé %o,%k megtizedelte %o -t,%k ha decimato %o,%k は %o の居場所を間引いた。,%k 은(는) %o 을(를) 망가뜨렸다.,%k gedecimeerd %o,%k przetrzebił@[ao_pl] %o,%k decimou %o,,%k l-a decimat pe %o,Игрок %k скосил игрока %o,%k је десетковао %o -%k destroyed %o,BBA_DESTRO,,,,%o byl@[ao_cs] zničen@[ao_cs] hráčem %k,%k hat %o zerstört,Ο/Η %k κατέστεψε @[pro2_gr] %o,%k detruis %o,%k destruyó a %o,,%k tuhosi %o paran,%k a détruit %o,%k elpusztította %o -t,%k ha distrutto %o,%k は %o を完全に破壊した。,%k 은(는) %o 을(를) 파괴했다.,%k vernietigd %o,%k zniszczył@[ao_pl] %o,%k destruiu %o,,%k l-a distrus pe %o,Игрок %k уничтожил игрока %o,%k је уништио %o -%k diced %o,BBA_DICED,,,,%o byl@[ao_cs] nakrájen@[ao_cs] na kostičky hráčem %k,%k hat %o in Würfel zerteilt,Ο/Η %k τεμάχησε @[pro2_gr] %o,%k diskubigis %o,%k picó en cubitos a %o,,%k pilkkosi %o paran,%k a coupé en dés %o,%k felkockázta %o -t,%k ha tagliato a cubetti %o,%k は %o を賽の目に切った。,%k 은(는) %o 을(를) 잘게 잘게 썰었다.,%k in blokjes gesneden %o,%k pokroił@[ao_pl] w kostkę %o,%k fez picadinho de %o,%k cortou %o,%k l-a feliat pe %o,Игрок %k разрезал игрока %o,%k је исецкао %o -%k disembowled %o,BBA_DISEMBO,,,,%o byl@[ao_cs] vykuchán@[ao_cs] hráčem %k,%k hat %o ausgeweidet,Ο/Η %k ισοπέδοσε @[pro2_gr] %o,%k sentripigis %o,%k destripó a %o,,%k suolisti %o paran,%k a étripé %o,%k kibelezve,%k ha smembrato %o,%k は %o の臓物を引きずり出した。,%k 은(는) %o 의 내장을 도려냈다.,%k van de ingewanden gehaald %o,%k wypatroszył@[ao_pl] %o,%k estripou %o,,%k l-a eviscerat pe %o,Игрок %k выпотрошил игрока %o,%k је ампутирао %o -%k flattened %o,BBA_FLATTE,,,,%o byl@[ao_cs] zplacatěn@[ao_cs] hráčem %k,%k hat %o dem Erdboden gleichgemacht,Ο/Η %k ησοπέδοσε @[pro2_gr] %o,%k platigis %o,%k aplanó a %o,,%k lyttäsi %o paran,%k a aplati %o,%k kilapítva,%k ha schiacciato %o,%k は %o をぶっ潰した。,%k 은(는) %o 의 코를 납작하게 만들었다.,afgevlakt %k afgevlakt %o,%k rozpłaszczył@[ao_pl] %o,%k achatou %o,%k espalmou %o,%k l-a făcut plat pe %o,Игрок %k сплюснул игрока %o,%k је изравнао %o -%k gave %o Anal Justice,BBA_JUSTICE,,,,%o utržil@[ao_cs] anální spravedlnost od hráče %k,%k hat %o anale Gerechtigkeit gegeben,Ο/Η %k γάμησε @[pro2_gr] %o @[pro3_gr] κόλο,%k donis %o puga ĵustico,%k le dió Justicia Anal a %o,,%k jakoi %o paralle anaalioikeutta,%k a rendu une justice anale a %o,%k %o -nak Anális Igazságot adott,%k ha dato a %o Giustizia Anale,%k は %o のケツにぶち込んだ。,%k 은(는) %o 에게 홍콩행을 보냈다.,%k gaf %o Anaalrechtvaardigheid,%k dał@[ao_pl] %o Analną Sprawiedliwość,%k deu Justiça Anal para %o,,%k i-a făcut jucătorului %o o Justiție Anală,Игрок %k устроил Анальное Правосудие игроку %o,%k је дао %o аналну правду -%k gave AnAl MaDnEsS to %o,BBA_MADNESS,,,,%o utrpěl@[ao_cs] AnÁlNí ŠíLeNsTvÍ od hráče %k,%k gab %o AnAlEn WaHnSiNn,Ο/Η %k έσκισε τον κόλο του/της] %o,%k donis pUgAn frEnEzOn al %o,%k le dió LoCuRa AnAl a %o,,%k teki %o paran AnAaLiHuLlUkSi,%k a donné la FOLIE ANALE a %o,%k %o -nak Seggbe Durrantott,%k ha dato FoLlIa AnAle a %o,%k は %o のケツをガバガバにした。,%o 은(는) %k 의 찰진 맛을 보았다.,%k gaf AnAl MaDnEs aan %o,%k dał@[ao_pl] %o AnAlNe SzAlEńStWo ,%k deu LoUcUrA aNaL para %o,,%k i-a dat NeBuNiE AnAlĂ jucătorului %o,Игрок %k устроил АнАЛ КаРнаВаЛ игроку %o,%k је дао АнАлНо ЛуДиЛо %o -%k killed %o,BBA_KILLED,,,,%o byl@[ao_cs] zabit@[ao_cs] hráčem %k,%k hat %o getötet,Ο/Η %k σκότωσε @[pro2_gr] %o,%k mortigis %o,%k mató a %o,,%k tappoi %o paran,%k a tué %o,%k kicsinálta %o -t,%k ha ucciso %o,%k は %o をブッ殺した。,%k 은(는) %o 을(를) 죽였다.,%k gedood %o,%k zabił@[ao_pl] %o,%k matou %o,,%k l-a omorât pe %o,Игрок %k убил игрока %o,%k је убио %o -%k made mincemeat out of %o,BBA_MINCMEAT,,,,%o byl@[ao_cs] namelen@[ao_cs] hráčem %k,%k hat %o zu Hackfleisch verarbeitet,Ο/Η %k έφτιαξε κυμά με @[pro2_gr] %o,%k faris mincemeat el %o,%k hizo picadillo de %o,,%k teki jauhelihaa %o parasta,%k a fait de la viande hachée de %o,%k darálthúst csinált %o -ból,%k ha triturato %o,%k は %o をミンチにした。,%o 은(는) %k 에 의해 분쇄됐다.,%k gemaakt gehakt vlees van %o,%k zrobił@[ao_pl] mięso mielone z %o,%k fez carne moída de %o,%k fez carne picada do %o,%k a facut tocătură din %o,Игрок %k сделал отбивную из игрока %o,%k је направио млевено месо од %o -%k massacred %o,BBA_MASSACR,,,,%o byl@[ao_cs] zmasakrován@[ao_cs] hráčem %k,%k hat %o niedergemetzelt,Ο/Η %k δολοφώνησε @[pro2_gr] %o,%k masakris %o,%k masacró a %o,,%k verilöylytti %o parkaa,%k a massacré %o,%k lemészárolta %o -t,%k ha fatto di %o carne tritata,%k は %o を虐殺した。,%k 은(는) %o 을(를) 참살했다.,%k afgeslacht %o,%k zmasakrował@[ao_pl] %o,%k massacrou %o,,%k a fost masacrat de către %o,Игрок %k устроил бойню игроку %o,%k је масакрирао %o -%k mutilated %o,BBA_MUTILA,,,,%o byl@[ao_cs] zmrzačen@[ao_cs] hráčem %k,%k hat %o verstümmelt,Ο/Η %k ακρωτηριάσε @[pro2_gr] %o,%k mutilis %o,%k mutiló a %o,,%k silpoi %o paran,%k a mutilé %o,%k megcsonkította %o -t,%k ha massacrato %o,%k は %o をバラバラ死体にした。,%k 은(는) %o 의 팔다리를 절단했다.,%k verminkt %o,%k rozszarpał@[ao_pl] %o,%k mutilou %o,,%k l-a mutilat pe %o,Игрок %k изуродовал игрока %o,%k је мутилирао %o -%k reamed %o,BBA_REAMED,,,,%o byl@[ao_cs] proděravěn@[ao_cs] hráčem %k,%k hat %o aufgerieben,Ο/Η %k δέσμισε @[pro2_gr] %o,%k reeldonis %o,%k escarió a %o,,%k porasi %o paran,%k a découpé en fines lamelles %o,%k seggbe rakta %o -t,%k ha squartato %o,%k は %o の穴を大きく広げた。,%k 은(는) %o 을(를) 크게 혼냈다.,%k geruimd %o,%k rozwiercił@[ao_pl] %o,%k esquartejou %o,,%k l-a transformat într-un top de hârtie pe %o,Игрок %k просверлил игрока %o,%k је наоружао %o -%k ripped %o a new orifice,BBA_RIPPED,,,,%o má novou díru od hráče %k,%k hat %o eine neue Körperöffnung verpasst,Ο/Η άνοιξε μια νέα τρύπα @[pro3_gr] %o,%k ŝiris %o novan orificion,%k le hizo a %o un nuevo orificio,,%k repi %o paralle uuden aukon,%k a ouvert un nouvel orifice a %o,,%k ha aperto a %o un altro orifizio,%k は %o を切り裂いて新しい穴を作ってあげた。,%k 은(는) %o 을(를) 죽여 뜯어서 작품을 만들었다.,%k gescheurd %o een nieuwe doorlaatopening,%k rozerwał@[ao_pl] %o nowy otwór,%k abriu um novo orifício em %o,,%k i-a făcut jucătorului %o un nou orificiu,Игрок %k проделал новое отверстие в игроке %o,%k је исцепао %o нови отвор -%k slaughtered %o,BBA_SLAUGHT,,,,%o byl@[ao_cs] zavražděn@[ao_cs] hráčem %k,%k hat %o geschlachtet,Ο/Η %k έσφαξε @[pro2_gr] %o,%k buĉis %o,%k sacrificó a %o,,%k teurasti %o paran,%k a meurtri %o,%k lemészárolta %o -t,%k ha macellato %o,%k は %o を屠殺した。,%o 은(는) %k 에 의해 도살당했다.,%k geslacht %o,%k zarżn@[irreg_2_pl] %o,%k abateu %o,,%k l-a măcelărit pe %o,Игрок %k устроил резню игроку %o,%k је заклао %o -%k smashed %o,BBA_SMASHED,,,,%o byl@[ao_cs] zmlácen@[ao_cs] hráčem %k,%k hat %o zerklatscht,Ο/Η %k τσάκισε @[pro2_gr] %o,%k frakasis %o,%k destrozó a %o,,%k murskasi %o paran,%k a enfoncé %o,%k földbe döngölte %o -t,%k ha distrutto %o,%k は %o をぶっ飛ばした。,%k 은(는) %o 을(를) 내팽개쳤다.,%k gebroken %o,%k stłukł@[ao_pl] %o,%k esmagou %o,,%k l-a spart pe %o,Игрок %k размазал игрока %o,%k је поломио %o -%k sodomized %o,BBA_SODOMIZ,,,,Hráč %k se dopustil sodomie na hráči %o,%k hat %o sodomisiert,Ο/Η %k γάμησε @[pro2_gr] %o,%k sodomizata %o,%k sodomizó a %o,,%k anaaliraiskasi %o paran,%k y a sodomisé n %o,%k szodomizálta %o -t,%k ha sodomizzato %o,%o は %k にカマを掘られた。 ,%o 은(는) %k 을(를) 위해 등을 보였다.,%k gesodomiseerd %o,%k spenetrował@[ao_pl] %o,%k sodomizou %o,,%k l-a sodomizat pe %o,Игрок %k содомировал игрока %o,%k је изјебао %o -%k splattered %o,BBA_SPLATT,,,,%o byl@[ao_cs] rozplesknut@[ao_cs] hráčem %k,%k hat %o zerspritzt,Ο/Η %k έσκασε @[pro2_gr] %o,%k disĵetis %o,%k roció a %o,,%k roiski %o paran yltympäri,%k a explosé de %o,%k szétloccsantotta %o -t,%k ha spiaccicato %o,%k は %o にばら撒かれた。,%k 은(는) %o 을(를) 박살냈다.,%k gespat %k gespetterd %o,%k rozbryzgał@[ao_pl] %o,%k explodiu %o,,%k l-a împrăștiat pe %o,Игрок %k разбрызгал игрока %o,%k је спљоштио %o -%k squashed %o,BBA_SQUASH,,,,%o byl@[ao_cs] rozmáčknut@[ao_cs] hráčem %k,%k hat %o zerquetscht,Ο/Η %k πάτησε @[pro2_gr] %o,%k premplatigis %o,%k aplastó a %o,,%k litisti %o paran,%k a écrabouillé %o,%k szétnyomta %o -t mint a csótányt,%k ha schiacciato %o,%k は %o に潰された。,%k 은(는) %o 을(를) 짓이겼다.,%k geplet %k geplet %o,%k zmiażdżył@[ao_pl] %o,%k espatifou %o,,%k l-a strivit pe %o,Игрок %k расплющил игрока %o,%k је згњечио %o -%k throttled %o,BBA_THROTTL,,,,%o byl@[ao_cs] zaškrcen@[ao_cs] hráčem %k,%k hat %o erdrosselt,Ο/Η %k κομμάτιασε @[pro2_gr] %o,%k ekbruligis %o,%k aceleró a %o,,%k polki %o paran,%k a étouffé %o,,%k ha strozzato %o,%k は %o に絞られた。,%k 은(는) %o 을(를) 목 졸라 죽였다.,%k gewurgt %o,"%k udusił@[ao_pl] %o -",%k estrangulou %o,,%k l-a strâns de gât pe %o,Игрок %k задушил игрока %o,%k је угушио %o -%k wasted %o,BBA_WASTED,,,,%o byl@[ao_cs] zničen@[ao_cs] hráčem %k,%k hat %o verbraucht,Ο/Η %k σκότωσε @[pro2_gr] %o,%k malŝparis %o,%k desechó a %o,,%k kulutti %o paran,%k a décharné %o,,%k ha distrutto %o,%k は %o に消された。,%k 은(는) %o 을(를) 쓰레기처럼 내다 버렸다.,%k verspild %o,%k roztrwonił@[ao_pl] %o,%k detonou %o,,%k l-a risipit pe %o,Игрок %k замочил игрока %o,%k је убио %o -%k body bagged %o,BBA_BODYBAG,,,,Hráč %k narval %o@[psn1_cs] tělo do pytle,%k hat %o eingesackt,Ο/Η %k έχωσε @[pro2_gr] %o στη κάσα του/της,%k korpo malplenigis %o,%k embolsó a %o,,%k kääri %o paran ruumispussiin,%k a placé %o dans son linceul,,%k ha mandato %o all'obitorio,%k は %o を死体袋にした。,%k 은(는) %o 의 장례식을 치렀다.,%k lichaam met zakje %o,%k spakował@[ao_pl] %o do torby na zwłoki,%k mandou %o para o necrotério,,%k l-a băgat în sac pe %o,Игрок %k упаковал игрока %o в мешок для трупов,%k је умртвио %o -%k sent %o to Hell,BBA_HELL,,,,%o byl@[ao_cs] poslán@[ao_cs] do pekla hráčem %k,%k hat %o zur Hölle fahren lassen,Ο/Η %k έστειλε @[pro2_gr] %o στο δίαολο,%k sendis %o al Infero,%k envió a %o al infierno,,%k lähetti %o paran helvettiin,%k a envoyé %o en enfer,,%k ha spedito %o all'Inferno,%k は %o を地獄に送った。,%o 은(는) %k 덕에 지옥으로 돌아갔다.,%k verzonden %o naar de hel,%k wysłał@[ao_pl] %o do Piekła,%k mandou %o para o Inferno,,%k l-a trimis pe %o în Infern,Игрок %k отправил в Ад игрока %o,%k је послао %o до Врага -%k toasted %o,BBA_TOAST,,,,%o byl@[ao_cs] upečen@[ao_cs] hráčem %k,%k hat %o geröstet,Ο/Η %k έψησε @[pro2_gr] %o,%k tostita %o,%k tostó a %o,,%k käristi %o paran,%k a grillé %o,%k megpirította %o -t,%k ha arrostito %o,%k は %o を焼却した。,%o 은(는) %k 덕에 맛있게 구워졌다.,%k geroosterd %o,%k stostował@[ao_pl] %o,%k tostou %o,,%k l-a prăjit pe %o,Игрок %k поджарил игрока %o,%k је тостирао %o -%k snuffed %o,BBA_SNUFF,,,,%o byl@[ao_cs] rozsápán@[ao_cs] hráčem %k,%k hat %o vernichtet,Ο/Η %k έσβησε @[pro2_gr] %o,%k snufis %o,%k aspiró a %o,,%k sammutti %o paran,%k a crevé %o,,%k ha spento %o,%k は %o を処刑した。,%o 은(는) %k 에 의해 짓눌려졌다.,%k gesnuffeld %o,%k powąchał@[ao_pl] %o,%k apagou %o,,%k l-a mirosit pe %o,Игрок %k прикончил игрока %o,%k је угасио %o -%k hosed %o,BBA_HOSED,,,,%o byl@[ao_cs] odstříknut@[ao_cs] hráčem %k,%k hat %o eingetütet,Ο/Η %k έονιξε @[pro2_gr] %o σε σφαίρες,%k bagigis %o,%k se cargó a %o,,%k pesi %o paran,%k a arrosé %o,,%k l'ha fatta sopra %o,%k は %o にぶっかけた。,%k 은(는) %o 을(를) 패배로 씻겼다.,%k slang %o,%k załatwił@[ao_pl] %o,%k metralhou %o,,%k a pus furtunul pe %o,Игрок %k расстрелял игрока %o,%k је упскао %o -%k sprayed %o,BBA_SPRAYED,,,,%o byl@[ao_cs] postříkán@[ao_cs] hráčem %k,%k hat %o pulverisiert,Ο/Η %k ψέκασε @[pro2_gr] %o,%k ŝprucigis %o,%k pulverizó a %o,,%k ruiskutti %o paran,%k a pulvérise %o,,%k ha vaporizzato %o,%k は %o を撒き散らした。,%o 의 피는 %k 의 물감으로 쓰였다.,%k gespoten %o,%k rozpryskał@[ao_pl] %o,%k pulverizou %o,,%k l-a pulverizat pe %o,Игрок %k распылил игрока %o,%k је испрскао %o -%k made dog meat out of %o,BBA_DOGMEAT,,,,%o byl@[ao_cs] hozen@[ao_cs] psům hráčem %k,%k hat Hundefutter aus %o gemacht,Ο/Η %k γύρισε @[pro2_gr] %o σε κιμά,%k faris hundan viandon el %o,%k hizo comida para perro de %o,,%k teki %o parasta koiranruokaa,%k a fait de la pâtée pour chien de %o,,%k ha fatto di %o polpette,%k は %o を犬の餌にした。,%k 은(는) %o 로 개밥을 만들었다.,%k gemaakt hondenvlees van %o,%k zrobił@[ao_pl] mięso dla psów z %o,%k fez almôndegas de %o,,%k l-a transformat în mâncare de câini pe %o,Игрок %k скормил псам игрока %o,%k је направио псеће месо од %o -%k beat %o like a cur,BBA_BEATEN,,,,%o byl@[ao_cs] zmlácen@[ao_cs] jako pes hráčem %k,%k hat %o wie einen Hund geschlagen,Ο/Η %k πλάκοσε @[pro2_gr] %o σαν κοπρίτης,%k batis %o kiel kur,%k pateó a %o como a un perro callejero,,%k huitoi %o parkaa kuin rakkia,%k a battu %o,,%k ha battuto %o come un cane,%k は %o を狂犬の様に扱った。,%o 은(는) %k 에게 똥개처럼 맞았다.,%k beat %o als een hond,%k pobił@[ao_pl] %o jak kundla,%k espancou %o como um cachorro,%k espancou %o como um cão,%k îl bate pe %o ca pe o jigodie,Игрок %k сделал игрока %o как худую свинью,%k је превио %o ко мачку -%o is excrement,BBA_EXCREMENT,,,,%o je exkrement,%o wurde zu Exkrement verarbeitet,@[art_gr] %o είναι κόπρανα,%o estas ekskremento,%o es excremento,,%o on ulostetta,%o est une merde,,%o è un escremento,%o はもはや排泄物のようだ。,%o 은(는) 배설물이 되었다.,%o is uitwerpselen,%o został@[ao_pl] odpadkami,%o virou escremento,,%o e excrement,%o теперь экскремент,%o је сада измет -%o is hamburger,BBA_HAMBURGER,,,,%o je hamburger,%o ist Hamburger,@[art_gr] %o είναι χάμπουργκερ,%o estas hamburgero,%o es una hamburguesa,,%o on hakkelusta,%o est un hamburger,,%o è un hamburger,%o はハンバーガーになった。,%o 은(는) 고기 반죽이 되었다.,%o is hamburger,%o został@[ao_pl] hamburgerem,%o virou hamburguer,,%o e hamburger,%o теперь гамбургер,%o је сада пљескавица -%o suffered scrotum separation,BBA_SCROTUM,,,,%o prodělal@[ao_cs] separaci šourku,%os Eier wurden gebraten,,%o suferis skrotan disigon,%o sufrió separación de escroto,,%o kärsii kivespussin erotuksesta,%o a souffert d'une séparation du scrotum,,%o ha subito la separazione dello scroto,%o の陰嚢は剥離していた。,%o 은(는) 고자가 되었다.,%o leed aan scrotumscheiding...,%o doznał@[ao_pl] oddzielenia moszny,%o sofreu separação escrotal,,%o a suferit o separație de șcrot,%o страдает от потери тестикул,%o му је исечена патка -%o volunteered for population control,BBA_POPULATION,,,,%o se zůčastnil@[ao_cs] čistky obyvatelstva,%o hat sich freiwillig zur Bevölkerungskontrolle gemeldet,@[art_gr] %o εθελώντησε για έλεγχο του πληθυσμού,%o volontulis por loĝantarkontrolo,%o fue voluntario para control de población,,%o ilmoittautui vapaaehtoiseksi väestönhallintaan,%o s'est proposé pour un contrôle de la population,,%o si è offerto per il controllo della popolazione,%o は人口削減政策の実験台に志願した。,%o 은(는) 자연에 의해 낙태 당했다.,%o vrijwilliger voor bevolkingscontrole,%o zgłosił@[ao_pl] się na kontrolę ludności,%o se voluntariou para o controle populacional,%o se voluntariou para o controlo populacional,%o a voluntariat pentru controlul populației,%o борется с перенаселением,%o је волунтирао за контролу популације -%o has suicided,BBA_SUICIDE,,,,%o spáchal@[ao_cs] sebevraždu,%o hat Selbstmord begangen,@[art_gr] %o έχει αυτοκτονήση,%o sin mortigis,%o se ha suicidado,,%o on tehnyt itsemurhan,%o s'est suicidé,%o öngyilkos lett,%o si è suicidato,%o は勝手にくたばった。,%o 은(는) 한심하게 자살했다.,%o heeft zelfmoord gepleegd.,%o popełnił@[ao_pl] samobójstwo,%o se suicidou,%o suicidou-se,%o s-a sinucis,Игрок %o самоубился,%o је убио самог себе -%o received the Darwin Award,BBA_DARWIN,,,,%o dostal@[ao_cs] darwinovu cenu,%o hat den Darwinpreis erhalten,@[art_gr] %o κέρδισε το Darwin βραβείο,%o ricevis la Darwin-Premion,%o recibió el premio Darwin,,%o sai Darwin-palkinnon,%o a recu la médaille Darwin,És a Darwin Díj nyertese : %o,%o ha ricevuto il Darwin Award,%o にはダーウィン賞が授与された。,%o 은(는) 다윈상을 받을 자격이 있다.,%o ontving de Darwin Award....,%o otrzymał@[ao_pl] Nagrodę Darwina,%o ganhou o Prêmio Darwin,,%o a primit Premiul Darwin,Игрок %o получил премию Дарвина,%o је добио Дарвиново признање -,,Cheats,,,,,,,,,,,,,,,,,,,,, -Music Change,STSTR_MUS,,,,Změna hudby,Musikwechsel,Άλλαξε μουσική,Muzikŝanĝiĝo,Cambio de música,,Musiikin vaihtaminen,Changement de Musique,Zene Váltás,Cambio di musica,music変更,음악 전환,Muziek veranderen,Zmieniono muzykę,Trocando música...,Mudar a música,Schimbare muzică...,Смена музыки,Промена музике -Impossible Selection,STSTR_NOMUS,,,,Nemožný výběr,Falsche Auswahl,Αδήνατη επιλογή,Malebla Elekto,Selección impossible,,Valinta ei mahdollinen,Séléction Impossible!,Lehetetlen Kiválasztás,Selezione impossibile,その変更は不可能だ,불가능한 선택입니다,Onmogelijke selectie,Niemożliwy wybór,Seleção impossível,,Selectare Imposibilă,НЕКОРРЕКТНЫЙ ВЫБОР,НЕМОГУЋИ ИЗБОР -Degreelessness Mode ON,STSTR_DQDON,,,,Nesmrtelnost ZAP,Unverwundbarkeit AN,Θεική λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Nevundebla Reĝimo AKTIVA,Modo de estado sin grado ACTIVADO,,Kuolemattomuustila PÄÄLLÄ,Invulnérabilité ON ,Sérthetetlenség Mód BE,Modalità Invincibilità ATTIVATA,無敵モード: オン,무미건조한 모드 켬,Gegradeloosheid modus AAN,Niewrażliwość WŁĄCZONA,Modo invencível ATIVADO,,Modul invincibil ACTIVAT,Неуязвимость включена,Нерањивост УКЉУЧЕНА -Degreelessness Mode OFF,STSTR_DQDOFF,,,,Nesmrtelnost VYP,Unverwundbarkeit AUS,Θεική λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Nevundebla Reĝimo MALAKTIVA,Modo de estado sin grado DESACTIVADO,,Kuolemattomuustila POIS PÄÄLTÄ,Invulnérabilité OFF,Sérthetetlenség Mód KI,Modalità Invincibilità DISATTIVATA,無敵モード: オフ,무미건조한 모드 끔,Gegradeloosheid modus UIT,Niewrażliwość WYŁĄCZONA,Modo invencível DESATIVADO,,Modul Invincibil DEZACTIVAT,Неуязвимость отключена,Нерањивост ИСКЉУЧЕНА -Ultimate Degreelessness Mode ON,STSTR_DQD2ON,,,,Supernesmrtelnost ZAP,Ultimative Unverwundbarkeit AN,Απόλητη θεική λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Pintega Nevundebla Reĝimo AKTIVA,Modo de estado sin grado final ACTIVADO,,Varma kuolemattomuustila PÄÄLLÄ,Parfaite Invulnérabilité ON,Tökéletes Sérthetetlenség Mód BE,Modalità Invincibilità Ultima ATTIVATA,究極無敵モード: オン,엄청나게 무미건조한 모드 켬,Uiteindelijke Gegradeloosheid modus AAN,Maksymalna niewrażliwość WŁĄCZONA,Modo invencível supremo ATIVADO,,Modul Invincibilitate Supremă ACTIVAT,Полная неуязвимость включена,Ултимативна нерањивост УКЉУЧЕНА -Ultimate Degreelessness Mode OFF,STSTR_DQD2OFF,,,,Supernesmrtelnost VYP,Ultimative Unverwundbarkeit AUS,Απόλητη θεική λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Pintega Nevundebla Reĝimo MALAKTIVA,Modo de estado sin grado final DESACTIVADO,,Varma kuolemattomuustila POIS PÄÄLTÄ,Parfaite Invulnérabilité OFF,Tökéletes Sérthetetlenség Mód KI,Modalità Invincibilità Ultima DISATTIVATA,究極無敵モード: オフ,엄청나게 무미건조한 모드 끔,Uiteindelijke Gegradeloosheid modus UIT,Maksymalna niewrażliwość WYŁĄCZONA,Modo invencível supremo DESATIVADO,,Modul Invincibilitate Supremă DEZACTIVAT,Полная неуязвимость отключена,Ултимативна нерањивост ИСКЉУЧЕНА -Very Happy Ammo Added,STSTR_KFAADDED,,,,Velmi veselá munice přidána,Munition hinzugefügt,Πάρα Πολύ Χαρούμενα Πυρομαχηκά Προστέθηκαν,Tre Feliĉa Municio Aldonita,Munición añadida hasta el tope,,Täysaseistus,Armement Maximum!,Összes Lőszer Megadva,Equipaggiamento Completato,とても満足する武器弾薬を受け取った,아주 행복한 탄약 추가됨,Zeer gelukkige munitie toegevoegd,Bardzo szczęśliwa amunicja dodana,Equipamento completo,,Echipament complet,Боезапас пополнен,Веома Срећна Муниција Додана -Ammo (no keys) Added,STSTR_FAADDED,,,,Munice (bez klíčú) přidána,Munition (keine Schlüssel) hinzugefügt,Πυρομαχικά (Όχι κλειδία) προστέθηκαν,Municio (neniuj ŝlosiloj) Aldonita,Munición añadida (sin llaves),,Täysaseistus (ilman avaimia),Arsenal ajouté. (Pas de clés!),Lőszer (nincsenek kulcsok) Megadva,Equipaggiamento Completato (senza chiavi),武器弾薬(鍵なし)を受け取った,탄약(열쇠 없이) 추가됨,Munitie (geen sleutels) toegevoegd,Amunicja (bez kluczy) dodana,Equipamento completo (sem chaves),,Echipament complet (fără muniție),Боезапас пополнен (без ключей),Муниција (без кључева) Додана -No Clipping Mode ON,STSTR_NCON,,,,Bezkolizní režim ZAP,Nicht-Kollisionsmodus AN,Noclip λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Neniu Tondado Reĝimo AKTIVA,Modo de traspaso ACTIVADO,,Seinänläpikulkutila PÄÄLLÄ,Collisions OFF,Falonátmenés Mód BE,No Clipping ATTIVATO,壁抜けモード: オン,노 클립 모드 켬,Geen Clipping Mode ON,Tryb no-clip WŁĄCZONY,Modo sem colisão ATIVADO,,Modul fără coliziune ACTIVAT,Прохождение сквозь стены ВКЛЮЧЕНО,Пролажење кроз зидове УКЉУЧЕНО -No Clipping Mode OFF,STSTR_NCOFF,,,,Bezkolizní režim VYP,Nicht-Kollisionsmodus AUS,Noclip λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Neniu Tondado Reĝimo MALAKTIVA,Modo de traspaso DESACTIVADO,,Seinänläpikulkutila POIS PÄÄLTÄ,Collisions ON,Falonátmenés Mód KI,No Clipping DISATTIVATO,壁抜けモード: オフ,노 클립 모드 끔,Geen Clipping Mode OFF,Tryb no-clip WYŁĄCZONY,Modo sem colisão DESATIVADO,,Modul fără coliziune DEZACTIVAT,Прохождение сквозь стены ОТКЛЮЧЕНО,Пролажење кроз зидове ИСКЉУЧЕНО -No Clipping Mode 2 ON,STSTR_NC2ON,,,,Bezkolizní režim 2 ZAP,Nicht-Kollisionsmodus 2 AN,Δέυτερη noclip λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Neniu Tondado Reĝimo 2 AKTIVA,Modo de traspaso 2 ACTIVADO,,Seinänläpikulkutila 2 PÄÄLLÄ,Collisions 3D OFF,Falonátmenés 2. Mód BE,No Clipping 2 ATTIVATO,壁抜けモード2: オン,노 클립 모드 2 켬,Geen Clipping Mode 2 ON,Drugi tryb no-clip WŁĄCZONY,Modo sem colisão 2 ATIVADO,,Modul fără coliziune 2 ACTIVAT,Полёт сквозь стены ВКЛЮЧЁН,Секундарни режим пролажења кроз зидове УКЉУЧЕНО +би одустали тако лако!",Den riktiga Chex(R)-krigaren skulle inte ge upp så snabbt!,Gerçek Chex(R) Savaşçısı bu kadar çabuk pes etmez!,Справжній воїн Chex(R) не здається так швидко! +,,Pickups,,,,,,,,,,,,,,,,,,,,,,,,,, +You got a pickup,TXT_DEFAULTPICKUPMSG,,,,Dostal@[ao_cs] jsi věc,Du har samlet noget op,Du hast etwas aufgesammelt,Πήρες ένα πράγμα.,Vi trovis aĵon,Encuentras un objeto,,Sait jotakin,Quelque chose récupéré.,Felvettél egy tárgyat.,Hai raccolto qualcosa ,何か拾った,무언가를 집어냈다,Je hebt iets opgepakt...,Du har en henting,Zebrano przedmiot,Você pegou um item,Apanhaste um item,Ai ridicat un obiect.,Что-то получено,Покупили сте нешто,Du har en pickup,Bir pikabın var,Ви щось підібрали +,,Locks,,,,,,,,,,,,,,,,,,,,,,,,,, +Any key will open this door,PD_ANY,,,,Tyto dveře otevře jakýkoliv klíč,Enhver nøgle kan åbne denne dør,Jeder Schlüssel wird diese Tür öffnen,Οποιδήποτε κλειδί θα ανοίξει τη πόρτα,Iu ajn ŝlosilo povas malfermi ĉi tiun pordon,Cualquier llave puede abrir esta puerta,,Mikä tahansa avain avaa tämän oven,N'importe quelle clé peut ouvrir cette porte.,Bármilyen kulcs kinyitja ezt az ajtót.,Una chiave qualunque aprirà questa porta,いずれかのキーで開けることができる。,어느 열쇠든 이 문을 열 수 있습니다,Elke sleutel zal deze deur openen,Hvilken som helst nøkkel åpner denne døren,Dowolny klucz otworzy te drzwi,Qualquer chave abre esta porta,Qualquer chave pode abrir esta porta,Orice cheie va deschide ușa aceasta.,Для открытия нужен любой ключ,За отварање потребан је било који кључ,Vilken nyckel som helst kan öppna den här dörren.,Herhangi bir anahtar bu kapıyı açar,Будь який ключ відкриє ці двері +Any key will activate this object,PD_ANYOBJ,,,,Tento objekt aktivuje jakýkoliv klíč,Enhver nøgle vil aktivere dette objekt,Jeder Schlüssel wird dieses Objekt aktivieren,Οποιδήποτε κλειδί θα ενεργοποιήσει αυτό το αντικείμενο,Iu ajn ŝlosilo povas aktivigi ĉi tiun objekton,Cualquier llave puede activar este objeto,,Mikä tahansa avain aktivoi tämän kappaleen,N'importe quelle clé peut activer cet objet.,Bármilyen kulcs aktiválja ezt a tárgyat.,Una chiave qualunque attiverà questo oggetto,いずれかのキーで起動させることができる。,어느 열쇠든 이 물체를 작동 시킬 것입니다,Elke sleutel zal dit object activeren,Hvilken som helst nøkkel vil aktivere dette objektet,Dowolny klucz aktywuje ten przedmiot,Qualquer chave ativa este objeto,Qualquer chave pode ativar este objeto,Orice cheie va activa obiectul acesta.,Для включения нужен любой ключ,За активирање потребан је било који кључ,Alla nycklar aktiverar det här objektet,Herhangi bir tuş bu nesneyi etkinleştirir,Будь який ключ активує цей об'єкт +You need all three keys to open this door,PD_ALL3,,,,K otevření těchto dveří jsou potřeba všechny tři klíče,Du skal bruge alle tre nøgler for at åbne denne dør,"Du brauchst alle drei Schlüssel, um diese Tür zu öffnen",Χρειάζεσαι όλα τα τρία κλειδία για να ανοίξεις αυτή τη πόρτα,Vi bezonas ĉiujn tri ŝlosilojn por malfermi ĉi tiun pordon,Necesitas las tres llaves para abrir esta puerta,,Kaikki kolme avainta tarvitaan tämän oven avaamiseksi,Il vous faut une clé de chaque couleur pour ouvrir cette porte.,"Mind a 3 kulcs szükséges, hogy kinyisd ezt az ajtót.",Ti servono tutte e tre le chiavi per aprire questa porta,3つのキー全てが無ければ開かない。,이 문을 열기 위해선 3 종류의 열쇠가 필요합니다,Je hebt alle drie de sleutels nodig om deze deur te openen,Du trenger alle tre nøklene for å åpne denne døren,"Potrzebujesz wszystkich trzech kluczy, aby otworzyć te drzwi",Você precisa de todas as três chaves para abrir esta porta,Precisas de todas as três chaves para abrir esta porta,"Ai nevoie de toate cele trei chei pentru a deschide +ușa aceasta.",Для открытия требуются все три ключа,За отварање потребна су сва три кључа ,Du behöver alla tre nycklarna för att öppna den här dörren.,Bu kapıyı açmak için üç anahtara da ihtiyacınız var,"Вам потрібні всі три ключі, щоб відкрити ці двері" +You need all three keys to activate this object,PD_ALL3O,,,,K aktivaci tohoto objektu jsou potřeba všechny tři klíče,Du skal bruge alle tre nøgler for at aktivere dette objekt,"Du brauchst alle drei Schlüssel, um dieses Objekt zu aktivieren",Χρειάζεσε όλα τα τρία κλειδιά για να ενεργοποιήσεις αυτό το αντικείμενο,Vi bezonas ĉiujn tri ŝlosilojn por aktivigi ĉi tiun objekton,Necesitas las tres llaves para activar este objeto,,Kaikki kolme avainta tarvitaan tämän kappaleen aktivoimiseksi,Il vous faut une clé de chaque couleur pour activer cet objet.,Mind a 3 kulcs kell hogy aktiváld ezt a tárgyat.,Ti servono tutte e tre le chiavi per attivare questo oggetto ,3つのキー全てが必要だ。,이 물체를 작동시키기 위해선 3 종류의 열쇠가 필요합니다,Je hebt alle drie de sleutels nodig om dit object te activeren,Du trenger alle tre nøklene for å aktivere dette objektet,"Potrzebujesz wszystkich trzech kluczy, aby aktywować ten przedmiot",Você precisa de todas as três chaves para ativar este objeto,Precisas de todas as três chaves para ativar este objeto,"Ai nevoie de toate cele trei chei pentru a activa +acest obiect.",Для включения требуются все три ключа,За активирање потребна су сва три кључа,Du behöver alla tre nycklarna för att aktivera det här föremålet.,Bu nesneyi etkinleştirmek için üç tuşa da ihtiyacınız var,"Вам потрібні всі три ключі, щоб активувати цей об'єкт" +You need all six keys to open this door,PD_ALL6,,,,K otevření těchto dveří je potřeba všech šest klíčů,Du skal bruge alle seks nøgler for at åbne denne dør,"Du brauchst alle sechs Schlüssel, um diese Tür zu öffnen",Χρειάζεσαι όλα τα έξι κλειδία για να ανοίξεις αυτή τη πόρτα,Vi bezonas ĉiujn ses ŝlosilojn por malfermi ĉi tiun pordon,Necesitas las seis llaves para abrir esta puerta,,Kaikki kuusi avainta tarvitaan tämän oven avaamiseksi,Il vous faut les six clés pour ouvrir cette porte.,Mind a 6 kulcsnak meg kell lennie az ajtó kinyitásához.,Ti servono tutte e sei le chiavi per aprire questa porta,6つ全てのキーが無ければ開かない。,이 문을 열기 위해선 6 종류의 열쇠가 필요합니다,Je hebt alle zes de sleutels nodig om deze deur te openen,Du trenger alle seks nøklene for å åpne denne døren,"Potrzebujesz wszystkich sześciu kluczy, aby otworzyć te drzwi",Você precisa de todas as seis chaves para abrir esta porta,Precisas de todas as seis chaves para abrir esta porta,"Ai nevoie de toate cele sase chei pentru a deschide +aceasta usa.",Для открытия требуются все шесть ключей,За отварање потребна су свих шест кључева,Du behöver alla sex nycklar för att öppna den här dörren.,Bu kapıyı açmak için altı anahtara da ihtiyacınız var,"Вам потрібні всі шість ключів, щоб відкрити ці двері" +You need all six keys to activate this object,PD_ALL6O,,,,K aktivaci tohoto objektu je potřeba všech šest klíčů,Du skal bruge alle seks nøgler for at aktivere dette objekt,"Du brauchst alle sechs Schlüssel, um dieses Objekt zu aktivieren",Χρειάζεσε όλα τα έξι κλειδιά για να ενεργοποιήσεις αυτό το αντικείμενο,Vi bezonas ĉiujn ses ŝlosilojn por aktivigi ĉi tiun objekton,Necesitas las seis llaves para activar este objeto,,Kaikki kuusi avainta tarvitaan tämän kappaleen aktivoimiseksi,Il vous faut les six clés pour activer cet objet.,"Mind a 6 kulcs kell, hogy aktiváld ezt az objektumot.",Ti servono tutte e tre le chiavi per attivare questo oggetto ,6つ全てのキーが必要だ。,이 물체를 작동시키기 위해선 6 종류의 열쇠가 필요합니다,Je hebt alle zes de sleutels nodig om dit object te activeren,Du trenger alle seks nøklene for å aktivere dette objektet,"Potrzebujesz wszystkich sześciu kluczy, aby aktywować ten przedmiot",Você precisa de todas as seis chaves para ativar este objeto,Precisas de todas as seis chaves para ativar este objeto,"Ai nevoie de toate cele șase chei pentru a activa +acest obiect.",Для включения требуются все шесть ключей,За активирање потребна су свих шест кључева,Du behöver alla sex nycklar för att aktivera detta objekt.,Bu nesneyi etkinleştirmek için altı tuşa da ihtiyacınız var,"Вам потрібні всі шість ключів, щоб активувати цей об'єкт" +You need all the keys,PD_ALLKEYS,,,,Potřebuješ všechny klíče,Du skal bruge alle nøglerne,Du brauchst alle Schlüssel,Χρειάζεσαι όλα τα κλειδία,Vi bezonas ĉiujn ŝlosilojn,Necesitas todas las llaves,,Kaikki avaimet tarvitaan,Vous avez besoin de toutes les six clés.,Az összes kulcsra szükséged van.,Ti servono tutte le chiavi,全てのキーが必要だ。,모든 열쇠가 필요합니다,Je hebt alle sleutels nodig,Du trenger alle nøklene,Potrzebujesz wszystkich kluczy,Você precisa de todas as chaves,Precisas de todas as chaves,Ai nevoie de toate cheile.,Требуются все ключи,Потребни су сви кључеви,Du behöver alla nycklar,Tüm anahtarlara ihtiyacın var,Потрібні всі ключі +,,Chat,,,,,,,,,,,,,,,,,,,,,,,,,, +[Message unsent],HUSTR_MSGU,,,,[Zpráva neposlána],[Besked ikke sendt],[Nachricht nicht gesendet],[Δέν στάλθηκε],[Mesaĝo ne sendita],[Mensaje sin enviar],,[Viestiä ei lähetetty],[Message Non Envoyé],[Üzenet nincs elküldve],[Messaggio non inviato],[メッセージ未送信],[메시지가 전달되지 않음],[Bericht niet verzonden],[Melding ikke sendt],[Wiadomość niewysłana],[Mensagem não enviada],,[Mesaj netrimis],[Сообщение не отправлено],[Порука непослата],[Meddelande ej skickat],[Mesaj gönderilmemiş],[Повідомлення не відправлено] +You mumble to yourself,HUSTR_TALKTOSELF1,,,,Něco si zamumláš pro sebe.,Du mumler for dig selv,Du murmelst zu dir selbst,Μουρμουράς στον εαυτό σου,Vi murmuras al vi mem,Te murmuras a ti mism@[ao_esp],,Mutiset itseksesi,Vous parlez tout seul.,Magadban motyogsz,Pensi fra te e te,ネタにならない呟きだ,자기 혼자서 중얼거렸다,Je mompelt in jezelf,Du mumler for deg selv,Mamroczesz do siebie,Você resmunga para si mesm@[ao_ptb]...,Tu resmungas contigo própri@[ao_ptb]...,Bolborosești în sine,Неразборчивое бормотание,Промумљате себи,Du mumlar för dig själv,Kendi kendine mırıldanıyorsun,Ви бормочете собі під ніс +Who's there?,HUSTR_TALKTOSELF2,,,,Kdo je tam?,Hvem er der?,Wer ist da?,Πιός είναι εκεί?,Kiu estas tie?,¿Quién está ahí?,,Kuka siellä?,Qui est là?,Ki van ott?,Chi c'è lì?,誰かいるか?,거기 누구 있나?,Wie is daar?,Hvem er der?,Kto tam?,Quem está aí?,,Cine-i acolo?,Кто там?,Ко је то?,Vem är där?,Kim var orada?,Хто тут? +You scare yourself,HUSTR_TALKTOSELF3,,,,Vystrašíš se.,Du skræmmer dig selv,Du machst dir Angst,Φοβήζεις τον εαυτό σου,Vi timigas vin mem,Te asustas a ti mism@[ao_esp],,Pelotat itseäsi,Vous vous surprenez.,Megijeszted magad,Ti spaventi da solo,"怯えているな +",자기 혼자서 벌벌 떨고 있다,Je wordt bang van jezelf,Du skremmer deg selv,Przestraszyłeś się,Você se assusta,Assustas-te a ti propri@[ao_ptb],Te speri pe tine însuți,Что это было?,Плашите самог себе,Du skrämmer dig själv.,Kendini korkutuyorsun.,Ви налякали себе +You start to rave,HUSTR_TALKTOSELF4,,,,Začneš pařit.,Du begynder at rave,Du beginnst zu toben,Αρχίζεις να ουρλίαζεις,Vi komencas frenezi,Empiezas a delirar,,Alat hourailla,Vous commencez à délirer!,Reszketni kezdesz,Inizi a delirare,イカレ始めた,횡설수설하기 시작했다,Je begint te razen,Du begynner å rave,Zaczynasz wariować,Você começa a delirar,Começas a delirar,Începi să aiurezi,Вы бредите.,Брбљате,Du börjar rasa.,Çıldırmaya başlıyorsun,Ви починаєте марити +You've lost it...,HUSTR_TALKTOSELF5,,,,Kleplo ti...,Du har mistet den...,Du verlierst den Verstand...,Το έχασες,Vi freneziĝis...,Te has vuelto loc@[ao_esp]...,Te volviste loc@[ao_esp]...,Olet seonnut...,Vous avez perdu les pédales...,Eldobod az agyad...,Sei andato...,我を失った...,미치기 시작했다...,Je bent het kwijt,You've lost it...,Oszalałeś...,Você enlouqueceu...,Enlouqueceste,Ai luat-o pe ulei...,Какая досада...,Лудите...,Du har förlorat det...,Kaybettin...,Як сумно... +[Message Sent],HUSTR_MESSAGESENT,,,,[Zpráva odeslána],[besked sendt],[Nachricht gesendet],[Στάλθηκε],[Mesaĝo sendita],[Mensaje enviado],,[Viesti lähetetty],[Message Envoyé],[Üzenet elküldve],[Messaggio Inviato],[メッセージ送信],[메시지가 전달됨],[Bericht verzonden],[Melding sendt],[Wiadomość wysłana],[Mensagem enviada],,[Mesaj Trimis],[Сообщение отправлено],[Порука послата],[Meddelande skickat],[Mesaj Gönderildi],[Повідомлення відправлено] +,,Cheats,,,,,,,,,,,,,,,,,,,,,,,,,, +Music Change,STSTR_MUS,,,,Změna hudby,Musik Ændring,Musikwechsel,Άλλαξε μουσική,Muzikŝanĝo,Cambio de música,,Musiikin vaihtaminen,Changement de Musique,Zene Váltás,Cambio di musica,music変更,음악 전환,Muziek veranderen,Music Change,Zmieniono muzykę,Trocando música,Mudar a música,Schimbare muzică...,Смена музыки,Промена музике,Musikbyte,Müzik Değişimi,Зміна музики +Impossible Selection,STSTR_NOMUS,,,,Nemožný výběr,Umuligt valg,Falsche Auswahl,Αδήνατη επιλογή,Malebla Elektaĵo,Selección imposible,,Valinta ei mahdollinen,Séléction Impossible!,Lehetetlen Kiválasztás,Selezione impossibile,その変更は不可能だ,불가능한 선택입니다,Onmogelijke selectie,Umulig valg,Niemożliwy wybór,Seleção impossível,,Selectare Imposibilă,Неверный выбор,НЕМОГУЋИ ИЗБОР,Omöjligt val,İmkansız Seçim,НЕКОРЕКТНИЙ ВИБІР +Degreelessness Mode ON,STSTR_DQDON,,,,Nesmrtelnost ZAP,Gradeløs tilstand TIL,Unverwundbarkeit AN,Θεική λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Nevundebla Reĝimo ŜALTITA,Invulnerabilidad ACTIVADA,,Kuolemattomuustila PÄÄLLÄ,Invulnérabilité ON ,Sérthetetlenség Mód BE,Modalità Invincibilità ATTIVATA,無敵モード: オン,무미건조한 모드 켬,Gegradeloosheid modus AAN,Gradløshetsmodus PÅ,Niewrażliwość WŁĄCZONA,Modo invencível ATIVADO,,Modul invincibil ACTIVAT,Безграмотность ВКЛЮЧЕНА,Нерањивост УКЉУЧЕНА,Gradlöshetsläge på,Dokunulmazlık Modu AÇIK,Безсмертя ввімкнено +Degreelessness Mode OFF,STSTR_DQDOFF,,,,Nesmrtelnost VYP,Gradeløs tilstand FRA,Unverwundbarkeit AUS,Θεική λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Nevundebla Reĝimo MALŜALTITA,Invulnerabilidad DESACTIVADA,,Kuolemattomuustila POIS PÄÄLTÄ,Invulnérabilité OFF,Sérthetetlenség Mód KI,Modalità Invincibilità DISATTIVATA,無敵モード: オフ,무미건조한 모드 끔,Gegradeloosheid modus UIT,Gradløshetsmodus AV,Niewrażliwość WYŁĄCZONA,Modo invencível DESATIVADO,,Modul Invincibil DEZACTIVAT,Безграмотность ОТКЛЮЧЕНА,Нерањивост ИСКЉУЧЕНА,Gradlöshetsläge av,Dokunulmazlık Modu KAPALI,Безсмертя вимкнено +Ultimate Degreelessness Mode ON,STSTR_DQD2ON,,,,Supernesmrtelnost ZAP,Ultimativ gradløs tilstand TIL,Ultimative Unverwundbarkeit AN,Απόλητη θεική λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Pleja Nevundebla Reĝimo ŜALTITA,Invulnerabilidad absoluta ACTIVADA,,Varma kuolemattomuustila PÄÄLLÄ,Parfaite Invulnérabilité ON,Tökéletes Sérthetetlenség Mód BE,Modalità Invincibilità Ultima ATTIVATA,究極無敵モード: オン,엄청나게 무미건조한 모드 켬,Uiteindelijke Gegradeloosheid modus AAN,Ultimativ gradløshetsmodus PÅ,Maksymalna niewrażliwość WŁĄCZONA,Modo invencível supremo ATIVADO,,Modul Invincibilitate Supremă ACTIVAT,Полная безграмотность ВКЛЮЧЕНА,Ултимативна нерањивост УКЉУЧЕНА,Ultimat gradlöshetsläge på,Nihai Dokunulmazlık Modu AÇIK,Повне безсмертя ввімкнено +Ultimate Degreelessness Mode OFF,STSTR_DQD2OFF,,,,Supernesmrtelnost VYP,Ultimativ gradløs tilstand FRA,Ultimative Unverwundbarkeit AUS,Απόλητη θεική λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Pleja Nevundebla Reĝimo MALŜALTITA,Invulnerabilidad absoluta DESACTIVADA,,Varma kuolemattomuustila POIS PÄÄLTÄ,Parfaite Invulnérabilité OFF,Tökéletes Sérthetetlenség Mód KI,Modalità Invincibilità Ultima DISATTIVATA,究極無敵モード: オフ,엄청나게 무미건조한 모드 끔,Uiteindelijke Gegradeloosheid modus UIT,Ultimativ gradløshetsmodus AV,Maksymalna niewrażliwość WYŁĄCZONA,Modo invencível supremo DESATIVADO,,Modul Invincibilitate Supremă DEZACTIVAT,Полная безграмотность ОТКЛЮЧЕНА,Ултимативна нерањивост ИСКЉУЧЕНА,Ultimat gradlöshetsläge av,Nihai Dokunulmazlık Modu KAPALI,Повне безсмертя вимкнено +Very Happy Ammo Added,STSTR_KFAADDED,,,,Velmi veselá munice přidána,Meget lykkelig Ammo tilføjet,Munition hinzugefügt,Πάρα Πολύ Χαρούμενα Πυρομαχηκά Προστέθηκαν,Tre Feliĉa Municio Aldonita,Munición añadida hasta el tope,,Täysaseistus,Armement Maximum!,Összes Lőszer Megadva,Equipaggiamento Completato,とても満足する武器弾薬を受け取った,아주 행복한 탄약 추가됨,Zeer gelukkige munitie toegevoegd,Veldig glad ammunisjon lagt til,Bardzo szczęśliwa amunicja dodana,Equipamento completo,,Echipament complet,Боезапас на счастье пополнен,Веома Срећна Муниција Додана,Mycket lycklig ammunition har lagts till,Çok Mutlu Cephane Eklendi,Спорядження поповнено +Ammo (no keys) Added,STSTR_FAADDED,,,,Munice (bez klíčú) přidána,Ammo (ingen nøgler) Tilføjet,Munition (keine Schlüssel) hinzugefügt,Πυρομαχικά (Όχι κλειδία) προστέθηκαν,Municio (neniuj ŝlosiloj) Aldonita,Munición añadida (sin llaves),,Täysaseistus (ilman avaimia),Arsenal ajouté. (Pas de clés!),Lőszer (nincsenek kulcsok) Megadva,Equipaggiamento Completato (senza chiavi),武器弾薬(鍵なし)を受け取った,탄약(열쇠 없이) 추가됨,Munitie (geen sleutels) toegevoegd,Ammo (ingen nøkler) Lagt til,Amunicja (bez kluczy) dodana,Equipamento completo (sem chaves),,Echipament complet (fără muniție),Боезапас пополнен (без ключей),Муниција (без кључева) Додана,Ammo (inga nycklar) Tillagd,Cephane (anahtar yok) Eklendi,Спорядження поповнено (без ключів) +No Clipping Mode ON,STSTR_NCON,,,,Bezkolizní režim ZAP,Ikke-kollisionstilstand TIL,Nicht-Kollisionsmodus AN,Noclip λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Reĝimo de Neniu Tondado ŜALTITA,Modo de traspaso ACTIVADO,,Seinänläpikulkutila PÄÄLLÄ,Collisions OFF,Falonátmenés Mód BE,No Clipping ATTIVATO,壁抜けモード: オン,노 클립 모드 켬,Geen Clipping Modus AAN,Ingen klipping-modus PÅ,Tryb no-clip WŁĄCZONY,Modo sem colisão ATIVADO,,Modul fără coliziune ACTIVAT,Режим без столкновений ВКЛЮЧЕН,Пролажење кроз зидове УКЉУЧЕНО,Inget klippningsläge på,Klipsleme Yok Modu AÇIK,"Прохід крізь стіни +ВВІМКНЕНО" +No Clipping Mode OFF,STSTR_NCOFF,,,,Bezkolizní režim VYP,Ikke-kollisionstilstand FRA,Nicht-Kollisionsmodus AUS,Noclip λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Reĝimo de Neniu Tondado MALŜALTITA,Modo de traspaso DESACTIVADO,,Seinänläpikulkutila POIS PÄÄLTÄ,Collisions ON,Falonátmenés Mód KI,No Clipping DISATTIVATO,壁抜けモード: オフ,노 클립 모드 끔,Geen Clipping Modus OFF,Ingen klippemodus AV,Tryb no-clip WYŁĄCZONY,Modo sem colisão DESATIVADO,,Modul fără coliziune DEZACTIVAT,Режим без столкновений ОТКЛЮЧЕН,Пролажење кроз зидове ИСКЉУЧЕНО,Inget klippningsläge av,Klipsleme Yok Modu KAPALI,"Прохід крізь стіни +ВИМКНЕНО" +No Clipping Mode 2 ON,STSTR_NC2ON,,,,Bezkolizní režim 2 ZAP,Ikke-kollisionstilstand 2 TIL,Nicht-Kollisionsmodus 2 AN,Δέυτερη noclip λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Reĝimo de Neniu Tondado 2 ŜALTITA,Modo de traspaso 2 ACTIVADO,,Seinänläpikulkutila 2 PÄÄLLÄ,Collisions 3D OFF,Falonátmenés 2. Mód BE,No Clipping 2 ATTIVATO,壁抜けモード2: オン,노 클립 모드 2 켬,Geen Clipping Modus 2 AAN,No Clipping Mode 2 PÅ,Drugi tryb no-clip WŁĄCZONY,Modo sem colisão 2 ATIVADO,,Modul fără coliziune 2 ACTIVAT,Режим без столкновений 2 ВКЛЮЧЁН,Секундарни режим пролажења кроз зидове УКЉУЧЕНО,Inget klippningsläge 2 på,Klipsleme Yok Modu 2 AÇIK,"Проліт крізь стіни +ВВІМКНЕНО" +No Clipping Mode 2 OFF,STSTR_NC2OFF,,,,Bezkolizní režim 2 VYP,Ikke-kollisionstilstand 2 FRA,Nicht-Kollisionsmodus 2 AUS,Noclip λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Reĝimo de Neniu Tondado 2 MALŜALTITA,Modo de traspaso 2 DESACTIVADO,,Seinänläpikulkutila 2 POIS PÄÄLTÄ,Collisions 3D ON,Falonátmenés 2 Mód KI,No Clipping 2 DISATTIVATO,壁抜けモード2: オフ,노 클립 모드 2 끔,Geen Clipping Modus 2 OFF,Ingen klippemodus 2 AV,Drugy tryb no-clip WYŁĄCZONY,Modo sem colisão 2 DESATIVADO,,Modul fără coliziune 2 DEZACTIVAT,Режим без столкновений 2 ОТКЛЮЧЁН,Секундарни режим пролажења кроз зидове ИСКЉУЧЕНО,Inget klippningsläge 2 av,Klipsleme Yok Modu 2 KAPALI,"Проліт крізь стіни +ВИМКНЕНО" "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp",STSTR_BEHOLD,"“inVuln”: Invulnerability sphere “Str”: Berserk “Inviso”: Blur sphere “Rad”: Radiation-shielding suit “Allmap”: Computer area map -“Lite-amp”: Light-amplification visor",,,"nesmrt(V), Síla, nevId, Rad, mApa nebo světLo","inVuln, Str, Inviso, Rad, Allmap, oder Lite-amp",,"inVuln, Str, Inviso, Rad, Allmap, aŭ Lite-amp","inVuln, Str, Inviso, Rad, Allmap, o Lite-amp.",,"haavoittumattomuus (V), voima (S), näkymättömyys (I), koko kartta (A) tai valonvahvistus (L)","in V ulnérable, S urpuissance, I nvisible, p R otection, c A rte, où L umière?","Sérthet (V), Berz (S), Láthat(i), Sugár(R), Térkép(A), vagy Fény Sisak(L)","inVuln, berSerk, Invisib, tuta anti-Rad, mAppa tutta, o amplif-Luce","v,i,s,a,r,l の何れかを選べ","무적, 광전사, 투명, 보호복, 지도, 아니면 바이저","inVuln, Str, Inviso, Rad, Allmap, of Lite-amp","niezniszczalność (V), siła (S), niewidzialność (I), kombinezon (R), mapa (A) lub gogle noktowizyjne (L)","inVuln., berSerk, Invisib., anti-Rad., mApa completo ou amplificação de Luz",,"InVinc, Forță amplificată, Invizib, Hartă completă, sau -Vedere amplificată","Бессм. (V), берс. (S), нев. (I), кос. (R), крт. (A), виз (L).","нерањ., снага, невидљ., радиј., мапа или ноћ. визор" -Power-up Toggled,STSTR_BEHOLDX,,,,Power-up vybrán,Verbesserung umgeschaltet!,,Enŝalti Baskulis,Poder alternado,,Tehostin kytketty,Amélioration Activée!,Túlerő Adva,Power-up concesso/tolto,パワーアップ 適用,파워-업 전환됨,Verbetering ingeschakeld,Wzmocnienie aktywowane,Poder ATIVADO,,Putere Activată,Усиление включено,Супер моћи заглављене -... doesn't suck - GM,STSTR_CHOPPERS,"Printed when entering the idchoppers cheat, which gives the player a chainsaw",,,... není cucák - GM,... gar nicht übel - GM,... δέν είναι χάλια - GW,... ne malbona — GM,... no apesta - GM,,... ei ole syvältä - GM,... C'est pas de la merde. - GM,... nem vacak - GM,... non fa cacare - GM,...わるかぁねえぞ --gm,... 후진 건 아니지만 - GM,.... is niet slecht - GM,... nie ssie - GM,...não é nada mal - GM,,... nu e jalnic - GM,... неплохо — г.м.,... није лоша - GM -"Changing Level... -",STSTR_CLEV,,,,Měním level...,Wechsle Level...,Αλλαγή πίστας...,Ŝanĝas Nivelon...,"Cambiando de nivel... -",,Vaihdetaan tasoa...,Changement de niveau...,Pálya Váltás...,"Cambio di livello... -",場所を変更...,레벨 변경 중...,Veranderen van niveau....,Zmienianie poziomu...,"Mudando de fase... -","A mudar de nível... +“Lite-amp”: Light-amplification visor",,,"nesmrt(V), (S)íla, nev(I)d, (R)ad, m(A)pa nebo svět(L)o","inVuln, Str, Inviso, Rad, Allmap, eller Lite-amp","inVuln, Str, Inviso, Rad, Allmap, oder Lite-amp",,"inVuln, Str, Inviso, Rad, Allmap, aŭ Lite-amp","inVuln, Str, Inviso, Rad, Allmap, o Lite-amp.",,"haavoittumattomuus (V), voima (S), näkymättömyys (I), koko kartta (A) tai valonvahvistus (L)","in V ulnérable, S urpuissance, I nvisible, p R otection, c A rte, où L umière?","Sérthetetlenség (V), berzerker mód (S), láthatatlanság (i), védőRuha, térkép (A), vagy éjjelLátó sisak","inVuln, berSerk, Invisib, tuta anti-Rad, mAppa tutta, o amplif-Luce","v,i,s,a,r,l の何れかを選べ","무적, 광전사, 투명, 보호복, 지도, 아니면 바이저","onSterv, Bzk, Inviso, Rad, Allmap, of Lvizier","inVuln, Str, Inviso, Rad, Allmap eller Lite-forsterker","niezniszczalność (V), siła (S), niewidzialność (I), kombinezon (R), mapa (A) lub gogle noktowizyjne (L)","Invulnerabilidade (V), Frenesi (S), Invisibilidade (I), Antirradiação (R), Mapa Completo (A) ou Amplificação de Luz (L)",,"InVinc, Forță amplificată, Invizib, Hartă completă, sau +Vedere amplificată","Бессм. (V), сила (S), невид. (I), кост. (R), п. карта (A), ус. света (L).","нерањ., снага, невидљ., радиј., мапа или ноћ. визор","inVuln, Str, Inviso, Rad, Allmap eller Lite-amp",,"Безсм. (V), берс. (S), нев. (I), кос. (R), карта (A), ПНВ (L)." +Power-up Toggled,STSTR_BEHOLDX,,,,Power-up vybrán,Strømoptagelse Skiftet,Verbesserung umgeschaltet!,,Plifortigaĵo Baskuligita,Poder alternado,,Tehostin kytketty,Amélioration Activée!,Képesség hozzáadva,Power-up concesso/tolto,パワーアップ 適用,파워-업 전환됨,Versterking ingeschakeld,Oppstart aktivert,Wzmocnienie aktywowane,Potencializador ativado,,Putere Activată,Усиление включено,Супер моћи заглављене,Start av strömmen växlade,Güç Açma Değiştirildi,Підсилення ввімкнено +... doesn't suck - GM,STSTR_CHOPPERS,"Printed when entering the idchoppers cheat, which gives the player a chainsaw",,,... není cucák - GM,... er ikke dårlig - GM,... gar nicht übel - GM,... δέν είναι χάλια - GW,... ne aĉas - GM,... no apesta - GM,,... ei ole syvältä - GM,... C'est pas de la merde. - GM,... nem annyira gáz - GM,... non fa schifo - GM,...わるかぁねえぞ --gm,... 후진 건 아니지만 - GM,.... is niet slecht - GM,... suger ikke - GM,... nie ssie - GM,... não tá ruim — GM,,... nu e jalnic - GM,...не отстой — GM,... није лоша - GM,... suger inte - GM,... berbat değil - GM,... непогано — г.м. +Changing Level...,STSTR_CLEV,,,,Měním level...,Ændring af niveau ...,Wechsle Level...,Αλλαγή πίστας...,Ŝanĝante Nivelon...,"Cambiando de nivel... +",,Vaihdetaan tasoa...,Changement de niveau...,Pályaváltás...,"Cambio di livello... +",場所を変更...,레벨 변경 중...,Level veranderen...,Endre nivå ...,Zmienianie poziomu...,Trocando de fase...,"A mudar de nível... ",Schimbare hartă...,"Смена уровня... -",Мењам ниво... -Buddha mode ON,TXT_BUDDHAON,,,,Buddha mód ZAP,Buddhamodus AN,Λειτουργία Βουδα ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Budha reĝimo AKTIVA,Modo Buda ACTIVADO,,Buddhatila PÄÄLLÄ,Mode Bouddha ON,Buddha Mód BE,Modalità Buddha ATTIVATA,ブッダモード: オン,부처 모드 켬,Boeddha-modus AAN,Tryb Buddy WŁĄCZONY,Modo Buda ATIVADO,,Modul Buddha ACTIVAT,Вы теперь Будда.,Буда Мод УКЉУЧЕН -Buddha mode OFF,TXT_BUDDHAOFF,,,,Buddha mód VYP,Buddhamodus AUS,Λειτουργία Βουδα ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Budha reĝimo MALAKTIVA,Modo Buda DESACTIVADO,,Buddhatila POIS PÄÄLTÄ,Mode Bouddha OFF,Buddha Mód KI,Modalità Buddha DISATTIVATA,ブッダモード: オフ,부처 모드 끔,Boeddha-modus UIT,Tryb Buddy WYŁĄCZONY,Modo Buda DESATIVADO,,Modul Buddha DEZACTIVAT,Вы больше не Будда.,Буда Мод ИСКЉУЧЕН -Ultimate Buddha Mode ON,TXT_BUDDHA2ON,,,,Super Buddha mód ZAP,Ultimativer Buddhamodus AN,Λειτουργία Απόλητου Βουδα ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Finfina Budha Reĝimo AKTIVA,Modo Buda Supremo ACTIVADO,,Korkein buddhatila PÄÄLLÄ,Mode Bouddha Ultime ON,Tökéletes Buddha Mód BE,Modalità Ultimo Buddha ATTIVATA,究極ブッダモード: オン,나무 아미타불 모드 켬,Ultieme Boeddha-modus AAN,Maksymalny Tryb Buddy WŁĄCZONY,Modo Buda Supremo ATIVADO,,Modul Buddha Suprem ACTIVAT,Вы теперь абсолютный Будда.,Ултимативни Буда Мод УКЉУЧЕН -Ultimate Buddha Mode OFF,TXT_BUDDHA2OFF,,,,Super Buddha mód VYP,Ultimativer Buddhamodus AUS,Λειτουργία Απόλητου Βουδα ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Finfina Budha Reĝimo MALAKTIVA,Modo Buda Supremo DESACTIVADO,,Korkein buddhatila POIS PÄÄLTÄ,Mode Bouddha Ultime OFF,Tökéletes Buddha Mód KI,Modalità Ultimo Buddha DISATTIVATA,究極ブッダモード: オフ,나무 아미타불 모드 끔,Ultieme Boeddha-modus UIT,Maksymalny Tryb Buddy WYŁĄCZONY,Modo Buda Supremo DESATIVADO,,Modul Buddha Suprem DEZACTIVAT,Вы больше не абсолютный Будда.,Ултимативни Буда Мод ИСКЉУЧЕН -Power on,TXT_CHEATPOWERON,,,,Energie ZAP,Fähigkeit AN,Δύναμη ενεργοποιημένη,Potenco aktiva,Poder activado,,Voima päällä,Pouvoir Activée,Energia BE,Potere ATTIVATO,パワー オン,파워 켬,Macht aan,Zasilanie włączone,Poder ativado,,Putere activată,Сила активирована,Моћ УКЉУЧЕНА -Power off,TXT_CHEATPOWEROFF,,,,Energie VYP,Fähigkeit AUS,Δύναμη άπενεργοποιημένη,Potenco malaktiva,Poder desactivado,,Voima pois päältä,Pouvoir Désactivée,Energia KI,Potere DISATTIVATO,パワー オフ,파워 끔,Macht uit,Zasilanie wyłączone,Poder desativado,,Putere dezactivată,Сила деактивирована,Моћ ИСКЉУЧЕНА -Full health,TXT_CHEATHEALTH,,,,Plné zdraví,Volle Lebensenergie,Ολόκληρη υγεία,Plena sano,Salud al máximo,,Täysi terveys,Pleine Santé,Teljes élet,Piena salute,ヘルス全回復,체력 완전 회복,Volledige gezondheid,Pełne zdrowie,Saúde completa,Vida totalmente cheia,Sănătate completă,Максимальное здоровье,Здравље напуњено -All keys,TXT_CHEATKEYS,,,,Všechny klíče,Alle Schlüssel,Όλα τα κλειδία,Ĉiuj ŝlosiloj,Todas las llaves,,Kaikki avaimet,Toutes les Clés,Összes kulcs,Tutte le chiavi,キー全部,모든 열쇠,Alle sleutels,Wszystkie klucze,Todas as chaves,,Toate cheile,Все ключи,Сви кључеви -Sound debug on,TXT_CHEATSOUNDON,,,,Debug zvuku ZAP,Sound Debug AN,Debug ήχου ενεργοποιημένη,Sono sencimiga reĝimo aktiva,Depuración de sonido activada,,Äänen vianmääritystila päällä,Débogage du son activé.,Hang debug BE,Debug del suono attivato,サウンドデバッグ オン,효과음 디버그 켬,Geluid debug aan,Debugowanie dźwięku włączone,Debug de som ativado,,Debug sunet activat,Отладка звука ВКЛЮЧЕНА,Дебаговање звука УКЉУЧЕНО -Sound debug off,TXT_CHEATSOUNDOFF,,,,Debug zvuku VYP,Sound Debug AUS,Debug ήχου άπενεργοποιημένη,Sono sencimiga reĝimo malaktiva,Depuración de sonido desactivada,,Äänen vianmääritystila pois päältä,Débogage du son désactivé.,Hang debug KI,Debug del suono disattivato,サウンドデバッグ オフ,효과음 디버그 끔,Geluid debug uit,Debugowanie dźwięku wyłączone,Debug de som desativado,,Debug sunet dezactivat,Отладка звука ОТКЛЮЧЕНА,Дебаговање звука ИСКЉУЧЕНО -"Trying to cheat, eh? Now you die!",TXT_CHEATIDDQD,,,,"Pokoušíš se cheatovat, co? Teď zemřeš!","Versuchst zu betrügen, was? Nun stirbst du!","Προσπαθείς να εξαπατήσεις, ε? Τώρα πεθένεις!","Provas trompi, ĉu vi? Nun vi mortas! ","¿Tratando de hacer trampa, eh? ¡Ahora morirás!",,"Yrität huijata, vai? Nyt kuolet!","Tu essaie de tricher, hein? Maintenant tu meurs!","Próbálsz csalni, mi? Most meghalsz!","Cerchi di barare, eh? Allora muori!",その名を唱えたな? 褒美に死をやろう!,치트 쓸려고? 그럼 죽어야지!,"Proberen vals te spelen, hè? Nu ga je dood!","Próbujesz oszukiwać, co? Teraz giń!","Tentando trapacear, é? Agora você morre!","A fazer batota, é? Morre!","Încerci să trișezi, ei? Acum mori!","Жульничаешь, э? Умрёшь!","Покушаваш да вараш, ех? Сада умиреш!" -Cheater - you don't deserve weapons,TXT_CHEATIDKFA,,,,Podvodníku - nezasloužíš si zbraně,Betrüger - du verdienst keine Waffen,Απατεόνα δέν σου αξήζουν όπλα,Trompanto - vi ne meritas armilojn,Trampos@[ao_esp] - No mereces tener armas,,Huijari - et ansaitse aseita,Tricheur- Tu ne mérite pas d'armes!,Csaló - nem érdemelsz fegyvereket,Imbroglione - non meriti armi,不届き者め、貴様が偉業を成すはずがない,사기꾼놈! 너는 무기를 가질 자격이 없어!,Valsspeler - je verdient geen wapens.,Oszust - nie zasługujesz na bronie,Trapaceir@[ao_ptb] - você não merece armamento,Batoteir@[ao_ptb] - Não mereces armamento,Trișor - Nu meriți arme,Обманщик — ты не заслуживаешь оружия,Варалице - ти не заслужујеш оружје -Ticker on,TXT_CHEATTICKERON,,,,Počítadlo ZAP,Zähler AN,Χρονόμετρο ενεργοποιημένο,Nombrilo aktiva,Contador activado,,Laskuri päällä,Compteur allumé,Számláló BE,Ticker attivato,ティッカー オン,프레임 속도 표시 켬,Tik aan,Wskaźnik włączony,Ticker ativado,,Ticăitoare activată,Счётчик включён,Бројач УКЉУЧЕН -Ticker off,TXT_CHEATTICKEROFF,,,,Počítadlo VYP,Zähler AUS,Χρονόμετρο άπενεργοποιημένο,Nombrilo malaktiva,Contador desactivado,,Laskuri pois päältä,Compteur éteint,Számláló KI,Ticker disattivato,ティッカー オフ,프레임 속도 표시 끔,Tik uit,Wskaźnik wyłączony,Ticker desativado,,Ticăitoare dezactivată,Счётчик отключён,Бројач ИСКЉУЧЕН -You got it,TXT_CHEATARTIFACTS3,,,,Máš to mít,Du hast es,Το πήρες,Vi havas ĝin,Lo tienes,,Saamasi pitää,C'est à vous!,Megkaptad,Concesso,それを渡そう。,얻었다,Je hebt het.,Udało ci się,Concedido,,Ai ce-ți trebuie,Вы получили это,Уреду -"You got the Midas Touch, baby",TXT_MIDASTOUCH,,,,"Máš Midasův dotek, zlato",Dagobert Duck lässt grüßen!,"Έχεις το αγγιγμα το Μίδα, μωρό.","Vi havas la Tuŝon de Midas, kara","Tienes el toque de Midas, muchach@[ao_esp]",,"Kulta, sinulla on Midaksen kosketus",,"Varázs ujjam mindenhol elér, kivéve ott","Hai avuto il Tocco di Mida, baby",ミダス王の様だな、ベイビー,넌 미다스의 손을 얻었어 베이베!,"Je hebt de Midas Touch, schatje","Zdobył@[irreg_3_pl] dotyk Midasa, skarbie","Você tem o Toque de Midas, baby","Tens o Toque de Midas, baby","Ai Atingerea lui Midas, dragule","Ты превращаешь всё в золото, детка!","Имаш златке руке, душо" -You got the stuff!,TXT_GOTSTUFF,,,,Dostal jsi věci!,Du hast den Kram erhalten,Πήρες τηατ πράγματα !,Vi havas la mojosaĵojn!,¡Tienes el material!,¡Tienes muchas cosas!,Sait kamppeet!,Voilà ton équipement!,Megkaptad a cuccot!,Hai avuto il materiale!,スタッフを手に入れた!,무언가를 얻었다!,Je hebt het spul!,Zdobył@[irreg_3_pl] parę rzeczy!,Você ganhou muitas coisas!,ganhaste muitas coisas!,Ai tot ce-ți trebuie!,Получены предметы!,Покупили сте ствари! -Freeze mode on,TXT_FREEZEON,,,,Režim zamrznutí ZAP,Gefriermodus AN,Παγομένη λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Frostigreĝimo aktiva,Modo suspendido activado,,Jäädytystila päällä,Temps arrêté.,Fagyasztás BE,Modalità arresto del tempo attivata,フリーズモード オン,시간정지 켬,Vorstmodus aan,Tryb zamrożenia włączony,Modo congelado ativado,,Modul înghețat activat,Режим заморозки включён,Мод замрзавања УКЉУЧЕН -Freeze mode off,TXT_FREEZEOFF,,,,Režim zamrznutí VYP,Gefriermodus AUS,Παγομένη λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Frostigreĝimo malaktiva,Modo suspendido desactivado,,Jäädytystila pois päältä,Le temps reprend son cours..,Fagyasztás KI,Modalità arresto del tempo disattivata,フリーズモード オフ,시간정지 끔,Vorstmodus uit,Tryb zamrożenia wyłączony,Modo congelado desativado,,Modul înghețat dezactivat,Режим заморозки отключен,Мод замрзавања ИСКЉУЧЕН -You feel strange...,TXT_STRANGE,,,,Cítíš se divně...,Du fühlst dich merkwürdig...,Νιώθης περίεργα...,Vi sentas vin strange...,Te sientes extrañ@[ao_esp]...,,Sinulla on kummallinen olo...,Vous vous sentez mal à l'aise...,Furcsán érzed magad.,Ti senti strano...,これは奇妙な感じだな...,뭔가 이상한 기분이...,Je voelt je vreemd...,Dziwnie się czujesz...,Você se sente estranh@[ao_ptb],Tu sentes-te estranh@[ao_ptb].,Te simți ciudat...,Вы чувствуете себя странно...,Осећаш се чудно... -You feel even stranger.,TXT_STRANGER,,,,Cítíš se ještě divněji...,Du fühlst dich noch merkwürdiger,Νιώθης ακόμα πιό περίεργα...,Vi sentas vin eĉ pli strange.,Te sientes aún más extrañ@[ao_esp],,Olosi on vieläkin kummempi.,Vous vous sentez très mal à l'aise...,Ennél is furcsábban érzed magad.,Ti senti ancora più strano.,これはかなり奇妙だ。,기분이 더더욱 이상해졌다.,Je voelt je nog vreemder.,Czujesz się jeszcze dziwniej.,Você se sente mais estranh@[ao_ptb] ainda.,Tu sentes-te ainda mais estranh@[ao_ptb].,Te simți si mai ciudat.,Вы чувствуете себя очень странно.,Осећаш се још чудније. -You feel like yourself again.,TXT_NOTSTRANGE,,,,Cítíš se opět jako ty.,Du fühlst dich wieder wie du selbst,Νιώθης σάν τον εαύτο σου ξανά...,Vi denove sentas vin kiel vi mem.,Te sientes como tu mism@[ao_esp] otra vez.,,Tunnet olevasi jälleen oma itsesi.,Vous vous sentez mieux.,Úgy érzed magadnál vagy.,Ti senti di nuovo te stesso.,自分自身の様に感じている。,자기 자신처럼 생각하게 됐다.,Je voelt je weer als jezelf.,Znów czujesz się sobą.,Você se sente normal novamente.,Tu sentes-te normal novamente.,Ți-ai revenit în simțiri.,Вы снова чувствуете себя собой.,Опет се осећаш као ти. -Lead boots on,TXT_LEADBOOTSON,,,,Olověné boty ZAP,Bleistiefel AN,Μολυβδένιες μπότες ΕΝΕΡΓΟΠΟΙΗΜΈΝΕΣ,Botoj el plumbo aktiva,Botas de plomo activadas,,Lyijysaappaat päällä,Bottes en plomb ON,Ólom cípők BE,Stivali di Piombo ON,足枷 オン,납 부츠 켬,Lead laarzen aan,Ołowiane buty włączone,Botas de chumbo ativadas,,Bocanci de plumb activați,Свинцовые сапоги надеты,Оловне чизме УКЉУЧЕНЕ -Lead boots off,TXT_LEADBOOTSOFF,,,,Olověné boty VYP,Bleistiefel AUS,Μολυβδένιες μπότες ΆΠΕΝΕΡΓΟΠΟΙΗΜΕΝΕΣ,Botoj el plumbo malaktiva,Botas de plomo desactivadas,,Lyijysaappaat pois päältä,Bottes en plomb OFF,Ólom cipők KI,Stivali di Piombo OFF,足枷 オフ,납 부츠 끔,Lead laarzen uit,Ołowiane buty wyłączone,Botas de chumbo desativadas,,Bocanci de plumb dezactivați,Свинцовые сапоги сняты,Оловне чизме ИСКЉУЧЕНЕ -You feel lighter,TXT_LIGHTER,,,,Cítíš se lehčí,Du fühlst dich leichter,Νιώθης πιο ελαφρής,Vi sentas vin pli malpeze,Te sientes más liger@[ao_esp],,Tunnet olosi kevyemmäksi,Vous vous sentez très léger.,Könnyűnek érzed magad,Ti senti più leggero,体が軽くなった,가벼운 느낌이 든다,Je voelt je lichter,Czujesz się lżejsz@[adj_pl],Você se sente mais leve,Tu sentes-te mais leve,Te simți mai ușor,Вы чувствуете лёгкость.,Осећаш се лакше -Gravity weighs you down,TXT_GRAVITY,,,,Gravitace tě táhne dolů,Schwerkraft belastet dich,Η βαρύτητα σε πιάνει.,Gravito pezigas vin,La gravedad te hace descender,,Painovoima painaa sinua alas,La gravité vous ramène au sol.,A gravitáció lenyom téged,La gravità ti riporta a terra,重力に従った,중력이 당신을 붙잡았다,Zwaartekracht weegt je zwaar...,Grawitacja znów cię przyciąga,A gravidade volta a funcionar normalmente,A gravidade voltou ao normal,Gravitația te trage în jos,Гравитация тянет Вас вниз.,Гравитација вас вуче надоле -,,Savegame,,,,,,,,,,,,,,,,,,,,, -Empty slot,EMPTYSTRING,,,,Prázdný slot,nicht belegt,Κενή θυρίδα,Malplena Ingo,Ranura Vacía,,Tyhjä lokero,Emplacement Vide,Üres,Slot libero,空きスロット,빈 슬롯,Lege sleuf,Puste miejsce,Vazio,,Slot liber,Пустой слот,Празни слот -,NEWSAVE,,,,,,<Νέο παιχνίδι>,,,,,,<Új mentés>,,<新規セーブ>,<새로운 게임 저장>,,,,,,<Новое сохранение>,<Нова сачувана игра> -Game saved.,GGSAVED,,,,Hra uložena.,Spielstand gespeichert.,Aποθηκεύτικε,Ludo konservita.,Partida guardada.,,Peli tallennettu.,Partie sauvegardée.,Játék mentve.,Gioco salvato.,セーブ完了。,게임이 저장됨.,Spel opgeslagen.,Gra zapisana.,Jogo salvo.,Jogo gravado.,Joc salvat.,Игра сохранена.,Игра сачувана. -Time,SAVECOMMENT_TIME,,,,Čas,Zeit,Χρόνος,Tempo,Tiempo,,Aika,Temps,Idő,Tempo,"時間 -",시간,Tijd,Czas,Tempo,,Timpul,Время,Време -,,Chat,,,,,,,,,,,,,,,,,,,,, -[Message unsent],HUSTR_MSGU,,,,[Zpráva neposlána],[Nachricht nicht gesendet],[Δέν στάλθηκε],[Mesaĝo ne sendita],[Mensaje sin enviar],,[Viestiä ei lähetetty],[Message Non Envoyé],[Üzenet nincs elküldve],[Messaggio non inviato],[メッセージ未送信],[메시지가 전달되지 않음],[Bericht niet verzonden],[Wiadomość niewysłana],[Mensagem não enviada],,[Mesaj netrimis],[Сообщение не отправлено],[Порука непослата] -You mumble to yourself,HUSTR_TALKTOSELF1,,,,Něco si zamumláš pro sebe.,Du murmelst zu dir selbst,Μουρμουράς στον εαυτό σου,Vi murmuras al si mem,Te murmuras a ti mism@[ao_esp],,Mutiset itseksesi,Vous parlez tout seul.,Magadhoz motyogsz,Pensi fra te e te,ネタにならない呟きだ,자기 혼자서 중얼거렸다,Je mompelt voor jezelf,Mamroczesz do siebie,Você resmunga para sí mesm@[ao_ptb]...,Tu resmungas contigo própri@[ao_ptb]...,Bolborosești în sine,Неразборчивое бормотание,Промумљате себи -Who's there?,HUSTR_TALKTOSELF2,,,,Kdo je tam?,Wer ist da?,Πιός είναι εκεί?,Kiu estas tie?,¿Quién está ahí?,,Kuka siellä?,Qui est là?,Ki van ott?,Chi c'è lì?,誰かいるか?,거기 누구 있나?,Wie is daar?,Kto tam?,Quem está ai?,,Cine-i acolo?,Кто там?,Ко је то? -You scare yourself,HUSTR_TALKTOSELF3,,,,Vystrašíš se.,Du machst dir Angst,Φοβήζεις τον εαυτό σου,Vi timigas vin mem,Te asustas a ti mism@[ao_esp],,Pelotat itseäsi,Vous vous surprenez.,Megijeszted magad,Ti spaventi da solo,"怯えているな -",자기 혼자서 벌벌 떨고 있다,Je maakt jezelf bang,Przestraszyłeś się,Você assusta a sí mesm@[ao_ptb],Assustas-te a ti propri@[ao_ptb],Te speri pe tine însuți,Что это было?,Плашите самог себе -You start to rave,HUSTR_TALKTOSELF4,,,,Začneš pařit.,Du beginnst zu toben,Αρχίζεις να ουρλίαζεις,Vi komencas frenezi,Empiezas a delirar,,Alat hourailla,Vous commencez à délirer!,Reszketni kezdesz,Inizi a delirare,イカレ始めた,횡설수설하기 시작했다,Je begint te razen,Zaczynasz wariować,Você começa a delirar,Começas a delirar,Începi să aiurezi,Вы бредите.,Брбљате -You've lost it...,HUSTR_TALKTOSELF5,,,,Kleplo ti...,Du verlierst den Verstand...,Το έχασες,Vi frenezigis...,Perdiste la cabeza...,,Olet seonnut...,Vous avez perdu les pédales...,Neked annyi...,Sei andato...,我を失った...,미치기 시작했다...,Je verliest je geest,Oszalałeś...,Você enlouqueceu...,Enlouqueceste,Ai luat-o pe ulei...,Какая досада...,Лудите... -[Message Sent],HUSTR_MESSAGESENT,,,,[Zpráva odeslána],[Nachricht gesendet],[Στάλθηκε],[Mesaĝo Sendita],[Mensaje enviado],,[Viesti lähetetty],[Message Envoyé],[Üzenet elküldve],[Messaggio Inviato],[メッセージ送信],[메시지가 전달됨],[Bericht verzonden],[Wiadomość wysłana],[Mensagem enviada],,[Mesaj Trimis],[Сообщение отправлено],[Порука послата] -Say:,TXT_SAY,,,,Říct:,Sage:,Πές:,Diru:,,,Sano:,Parler:,Üzenet:,Parla:,発言:,,Zeg:,Powiedz:,Fala:,Diz:,Vorbește:,Чат:,Пиши: -,,Automap,,,,,,,,,,,,,,,,,,,,, -Follow Mode ON,AMSTR_FOLLOWON,,,,Režim sledování ZAP,Folgen-Modus AN,Ακολούθηση ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Sekvigreĝimo AKTIVA,Modo de seguimiento ACTIVADO,,Seuraamistila PÄÄLLÄ,Suivi du Joueur ON,Követés Mód BE,Mappa scorribile DISATTIVATA,追従モード: オン,추적 모드 켬,Volgmodus AAN,Tryb śledzenia WŁĄCZONY,Modo de seguimento ATIVADO,,Mod Urmărire ACTIVAT,Привязка к игроку ВКЛЮЧЕНА,Праћење УКЉУЧЕНО -Follow Mode OFF,AMSTR_FOLLOWOFF,,,,Režim sledování VYP,Folgen-Modus AUS,Ακολούθηση ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Sekvigreĝimo MALAKTIVA,Modo de seguimiento DESACTIVADO,,Seuraamistila POIS PÄÄLTÄ,Suivi du Joueur OFF,Követés Mód KI,Mappa scorribile ATTIVATA,追従モード: オフ,추적 모드 끔,Volgmodus UIT,Tryb śledzenia WYŁĄCZONY,Modo de seguimento DESATIVADO,,Mod Urmărire DEZACTIVAT,Привязка к игроку ОТКЛЮЧЕНА,Праћење ИСКЉУЧЕНО -Grid ON,AMSTR_GRIDON,,,,Mřížka ZAP,Gitter AN,Πλέχμα ΕΝΕΡΓΟΠΟΙΜΈΝΟ,Krado AKTIVA,Cuadrícula ACTIVADA,Rejilla ACTIVADA,Ruudukko PÄÄLLÄ,Quadrillage ON,Rács BE,Griglia ATTIVATA,グリッド: オン,격자 켬,Raster AAN,Siatka WŁĄCZONA,Grade ATIVADA,Grelha ATIVADA,Grilă ACTIVATĂ,Сетка ВКЛЮЧЕНА,Мрежа УКЉУЧЕНА -Grid OFF,AMSTR_GRIDOFF,,,,Mrizka VYP,Gitter AUS,Πλέχμα ΆΠΕΝΕΡΓΟΠΟΙΜΈΝΟ,Krado MALAKTIVA,Cuadrícula DESACTIVADA,Rejilla DESACTIVADA,Ruudukko POIS PÄÄLTÄ,Quadrillage OFF,Rács KI,Griglia DISATTIVATA,グリッド: オフ,격자 끔,Raster UIT,Siatka WYŁĄCZONA,Grade DESATIVADA,Grelha DESATIVADA,Grilă DEZACTIVATĂ,Сетка ОТКЛЮЧЕНА,Мрежа ИСКЉУЧЕНА -Texture Mode ON,AMSTR_TEXON,,,,Texturovaný režim ZAP,Texturmodus AN,Γραφική ύλη ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Teksturo Reĝimo AKTIVA,Modo de texturas ACTIVADO,,Pintakuviointitila PÄÄLLÄ,Mode Texturé ON,Textúra Mód BE,Modalità Texture ATTIVATA,テクスチャーモード: オン,텍스쳐 모드 켬,Textuurmodus AAN,Tekstury WŁĄCZONE,Modo Textura ATIVADO,,Mod Texturat ACTIVAT,Текстурный режим ВКЛЮЧЁН,Текстуре УКЉУЧЕНЕ -Texture Mode OFF,AMSTR_TEXOFF,,,,Texturovaný režim VYP,Texturmodus AUS,Γραφική ύλη ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Teksturo Reĝimo MALAKTIVA,Modo de texturas DESACTIVADO,,Pintakuviointitila POIS PÄÄLTÄ,Mode Texturé OFF,Textúra Mód KI,Modalità Texture DISATTIVATA,テクスチャーモード: オフ,텍스쳐 모드 끔,Textuurmodus UIT,Tekstury WYŁĄCZONE,Modo Textura DESATIVADO,,Mod Netexturat DEZACTIVAT,Текстурный режим ОТКЛЮЧЕН,Текстуре ИСКЉУЧЕНЕ -Marked Spot,AMSTR_MARKEDSPOT,,,,Značka,Punkt markiert,Μαρκαρησμένη τοποθεσεία,Markis Makulon,Punto marcado,,Merkitty paikka,Repère marqué.,Hely Megjelölve,Posizione segnata,目標をマークした,지점 추가,Markeerde de plek,Oznaczono miejsce,Posição marcada,,Loc Marcat,Отметка,Означено место -All Marks Cleared,AMSTR_MARKSCLEARED,,,,Všechny značky smazány,Alle Markierungen gelöscht,Όλες η μαρκαρησμένη τοποθεσείες είναι καθαρησμένες,Ĉiuj Markoj Viŝis,Todas las marcas eliminadas,,Kaikki merkit pyyhitty,Repères éffacés.,Az Összes Megjelölések Kitörölve,Cancellati tutti i segni,全目標を解除した,모든 지점 지워짐,Alle merken gewist,Wszystkie miejsca wyczyszczone,Marcas removidas,,Toate Marcările Șterse,Отметки очищены,Ознаке избрисане -,,Multiplayer,,,,,,,,,,,,,,,,,,,,, -Fraglimit hit.,TXT_FRAGLIMIT,,,,Fraglimit dosáhnut.,Fraglimit erreicht,Το όριο κοματιασμόν έχει φτάσει.,Ĉeso-limo trafita.,Límite de bajas alcanzado.,,Frägiraja saavutettu.,Limite de frags atteinte.,Minimum Frag elérve.,Fraglimit raggiunto.,フラグリミット!,킬제한에 도달했습니다.,Fraglimiet geraakt.,Limit fragów wyczerpany.,Limite de frags atingido.,,Limita de ucideri atinsă.,Достигнут лимит фрагов.,Фраг-лимит достигнут. -Timelimit hit.,TXT_TIMELIMIT,,,,Časový limit dosáhnut.,Zeitlimit erreicht,Το χρονικό όριο έχει φτάσει.,Tempolimo trafita.,Límite de tiempo alcanzado.,,Aikaraja saavutettu.,Limite de temps atteinte.,Minimum Idő elérve.,Timelimit raggiunto.,ゲームセット!,시간제한에 도달했습니다.,Tijdslimiet geraakt.,Limit czasowy wyczerpany.,Limite de tempo atingido.,,Limita de timp atinsă.,Достигнут лимит времени.,Временско ограничење достигнуто. -%o was looking good until %g killed %hself!,SPREEKILLSELF,,,,%o vypadal@[ao_cs] dobře dokud se @[self_cs] nezabil@[ao_cs]!,"%o sah gut aus, bis das Unglück geschah.",@[art_gr] %o πήγενε μια χαρά μέχρι που αυτοκτόνησε!,"%o estis farinta bone, ĝis %g mortigis sin!",¡%o se veía bien hasta que %g se mató a si mism@[ao_esp]!,,"%o oli liekeissä, kunnes meni tappamaan itsensä!",%o était en pleine folie meurtrière avant que %g ne se bute!,%o jól nézett ki még mielőtt megölte magát!,%o stava andando bene finchè non si è ucciso da solo!,%o は自滅するまでなかなか良かったぞ!,%o 이(가) 잘 나가려던 참에 자살했습니다!,%o zag er goed uit tot @[hij_ze_nl] zelfmoord pleegde!,%o wyglądał dobrze dopóki się nie zabił@[ao_pl],%o estava indo bem até se matar!,,%o arăta atât de bine până să se sinucidă,"%o неплохо выглядел@[ao_rus], пока не покончил@[ao_rus] с собой!",%o је изгледа@[ao_1_sr] добро док није уби@[ao_1_sr] сам@[ao_3_sr] себе! -%o's killing spree was ended by %k,SPREEOVER,,,,%o@[psn1_cs] vraždící řádění ukončil hráč %k.,%os Amoklauf wurde von %k beendet.,Ο/Η %k σταμάτησε την ανθρωποκτονία %h %o.,La mortigado de %o estis finita de %k,%k acabó con la racha de muerte de %o,,%k päätti pelaajan %o tapposarjan,La folie meurtrière de %o à été terminée par %k!,%o ámokfutása meglett %k megállította.,La sequela di frag di %o è stata terminata da %k,%k が %o の快進撃を断ち切った!,%k 이(가) %o 의 연속 킬을 처단했습니다,%o's moordpartij werd beëindigd door %k.,Seria zabójstw %o zakończona przez %k,A matança de %o foi interrompida por %k,,Pofta de ucis a lui %o a fost pusă în cui de către %k,Игрок %k прервал череду убийств игрока %o,Серијско убијање играча %o је завршио играч %k -%k is on a killing spree!,SPREE5,,,,%k začal@[ao_cs] řádit!,%k läuft Amok!,Ο/Η %k άρχισε μια ανθρωποκτονία!,%k estas sur mortigado!,¡%k está atacando de lo lindo!,,%k on sarjamurhaaja!,%k est en folie meurtrière!,%o egy Ámokfutó!,%k è preda di un momento omicida!,%k が連続キル!,%k 연속 킬!,%k is op een moordpartij!,%k popełnia serię morderstw!,%k está cometendo uma matança!,,%k are chef de ucis!,Игрок %k совершил череду убийств!,%k је серијални убица! -%k is on a rampage!,SPREE10,,,,%k zuří!,%k tobt sich aus!,Ο/Η %k είναι σε ξέσπασμα!,%k estas sur furiozado!,¡%k está en medio de una aniquilación!,,%k riehuu valtoimenaan!,%k est en plein massacre!,%o Tombol!,%k sta facendo un massacro!,%k が大暴れだ!,%k 이(가) 미쳐 날뛰고 있습니다!,%k is op een rampage!,%k jest w szale!,%k está massacrando!,,%k e înverșunat!,%k в неистовстве!,%k дивља! -%k is dominating!,SPREE15,,,,%k dominuje!,%k dominiert!,Ο/Η %k κατακτεί.,%k estas dominas!,¡%k está dominando!,,%k hallitsee suvereenisti!,%k domine!,%o Uralkodik!,%k sta dominando tutti!,%k が圧倒している!,%k 이(가) 우세하고 있습니다!,%k domineert!,%k dominuje!,%k está dominando!,,%k domină!,%k доминирует!,%k доминира! -%k is unstoppable!,SPREE20,,,,%k je nezastaviteln@[adj_cs]!,%k kann nicht gestoppt werden!,Ο/Η %k είναι ασταμάτητος/η!,%k estas nehaltigebla!,¡%k está endureciendo la competición!,,%k on pysäyttämätön!,%k est inarrétable!,%o Megállíthatatlan!,%k è inarrestabile!,%k が止まらない!,%k 을(를) 막을 수없습니다!,%k is niet te stoppen!,%k jest niepowstrzymany!,%k é implacável!,,%k e de neoprit!,Игрок %k неостановим!,Играч %k је незаустављив! -%k is Godlike!,SPREE25,,,,%k je boží!,%k ist wie Gott!,Ο/Η %k είναι σαν θεός/θεά!,%k estas Dia!,¡%k es una máquina de matar!,,%k on kuin jumala!,%k est un dieu!,%o Istenszabású!,%k è un dio!,%k が神の様だ!,%k 은(는) 신적입니다! ,%k is Goddelijk!,%k jest Bogem!,%k é um deus da matança!,,%k e precum un Zeu!,Игрок %k богоподобен!,Играч %k је божанствен! -Double kill!,MULTI2,,,,Dvoj-zabití!,Doppel-Kill!,Δυπλός Θάνατος!,Duoble mortigoj!,¡Dos menos!,,Tuplatappo!,Double meurtre!,Dupla ölés!,Doppia uccisione!,ダブルキル!,더블 킬!,Dubbele kill!,Podwójne zabójstwo!,Lá se foram dois!,,Dublă ucidere!,Двойное убийство!,Дупло убиство! -Multi kill!,MULTI3,,,,Multi-zabití!,Multi-Kill!,Πολυθάνατος!,Multaj mortigoj!,¡Multidestrucción!,,Multitappo!,Multi meurtre!,Multi ölés!,Tripla uccisione!,マルチキル!,멀티 킬!,,Multi-zabójstwo!,Lá se foram três!,,Ucidere multiplă!,Массовое убийство!,Вишеструко убиство! -Ultra kill!,MULTI4,,,,Ultra-zabití!,Ultra-Kill!,Υπερθάνατος!,Ekstrema mortigo!,¡¡HIPERDESTRUCCIÓN!!,,Ultratappo!,Ultra meurtre!,Ultra ölés!,Ultra uccisione!,ウルトラキル!,울트라 킬!,,Ultra-zabójstwo!,Ultra matança!,,Ultra ucidere!,Ультра-убийство!,Ултра убиство! -Monster kill!,MULTI5,,,,Monstr-zabití!,Monster-Kill!,Τερατόδες σκοτωμός!,Monstra mortigo!,¡¡¡S.U.P.E.R.D.E.S.T.R.U.C.C.I.Ó.N!!!,,Hirviömäinen tappo!,Monstre meurtre!,Szörnyű gyilkolás!,Uccisione Mostruosa!,モンスターキル!,몬스터 킬!,,Potworne zabójstwo!,Matança monstro!,Matança monstruosa!,Ucidere monstruoasă!,Чудовищное убийство!,Монструозно убиство! -,,Scoreboard,,,,,,,,,,,,,,,,,,,,, -Items,SCORE_ITEMS,,,,Předměty,Gegenstände,Αντεικείμενα,Aĵoj,Objetos,,Esineet,Objets,Tárgyak,Oggetti,アイテム,획득한 아이템,Objecten,Przedmioty,Itens,,Obiecte,Предметы,Предмети -Bonus,SCORE_BONUS,,,,,Bonus,Bonus,Bonuso,Bonificaciones,,Lisäedut,,Bónusz,Bonus,ボーナス,보너스,Bonus,Bonusy,Bônus,,Bonus,Бонус,Бонус -Color,SCORE_COLOR,,,Colour,Barva,Farbe,Χρώμα,Koloro,,,Väri,Couleur,Szín,Colore ,色,색상,Kleur,Kolor,Cor,,Culoare,Цвет,Боја -Secret,SCORE_SECRET,,,,Tajemství,Geheimnis,Μυστικό,Sekreta,Secreto,,Salat,,Rejtély,Segreto,シークレット,밝혀낸 비밀,Geheim,Sekret,Segredo,,Secret,Тайники,Тајна -Name,SCORE_NAME,,,,Jméno,Name,Όνομα,Nomo,Nombre,,Nimi,Nom,Név,Nome,名前,이름,Naam,Nazwa,Nome,,Nume,Имя,Име -Delay (ms),SCORE_DELAY,,,,Zpoždění (ms),Verzögerung (ms),Kαθυστέρηση (μδ),Prokrasto (ms),Retraso (ms),,Viive (ms),Délai (ms),Késleltetés (ms),Ritardo (ms) ,ping,핑 (밀리초당),Vertraging (ms),Opóźnienie (ms),Atraso (ms),,Întârziere (ms),Задержка (мс),Кашњење (мс) -Kills,SCORE_KILLS,,,,Zabití,,Σκοτομοί,Mortigoj,Asesinatos,,Tapot,Victimes,Ölések,Uccisioni,キル,킬수,Doodt,Zabójstwa,Vítimas,,Ucideri,Убийства,Убиства -Frags,SCORE_FRAGS,,,,Fragy,,Κοματιασμοί,Ĉesoj,Bajas,,Frägit,,Fragek,Frags,フラグ,플레이어 킬수,Frags,Fragi,,,Victime,Фраги,Фрагови -Deaths,SCORE_DEATHS,,,,Smrti,Tode,Θάνατοι,Mortoj,Muertes,,Kuolemat,Morts,Halálok,Morti,デス,사망한 횟수,Overlijden,Śmierci,Mortes,,Decese,Смерти,Смрти -Missed,SCORE_MISSED,,,,Minuto,Verfehlt,Ξεχάστηκαν,Mankita,Pérdidas,,Hudit,Ratés,Kihagyva,Mancati ,ミス,놓친 수,Gemist,Ominięte,Perdido,,Ratate,Пропущено,Промашаји -Total,SCORE_TOTAL,,,,Celkem,Gesamt,Συνολικό,Tuta,,,Yhteensä,Total,Összesen,Totale,合計,총점,Totaal,Totalne,Total,,Total,Всего,Укупно -Level Time,SCORE_LVLTIME,,,,Čas v levelu,Levelzeit,Χρόνος Πίστας,Nivel Daŭro,Tiempo de nivel,,Tasoaika,Temps niveau,Szint Idő,Tempo Livello ,時間,레벨 시간,Niveau Tijd,Czas,Tempo de Fase,Tempo do Nível,Timp Petrecut,Время уровня,Време нивоа -,,Level Summary,,,,,,,,,,,,,,,,,,,,, -Kills,TXT_IMKILLS,,,,Zabití,,Σκοτομοί,Mortigoj,Muertes,,Tapot,Morts,Áldozatok,Uccisioni,キル,킬수,Doodt,Zabójstwa,Vítimas,,Ucideri,Враги,Убиства -Items,TXT_IMITEMS,,,,Předměty,Gegenstände,Αντεικείμενα,Aĵoj,Objetos,,Esineet,Objets,Tárgyak,Oggetti,アイテム,획득한 아이템,Artikelen,Przedmioty,Itens,,Obiecte,Предметы,Ставке -Secrets,TXT_IMSECRETS,,,,Tajemství,Geheimnisse,Μυστικά,Sekretoj,Secretos,,Salat,,Rejtekhelyek,Segreti,シークレット,밝혀낸 비밀,Geheimen,Sekrety,Segredos,,Secrete,Тайники,Тајне -Time,TXT_IMTIME,,,,Čas,Zeit,Χρόνος,Daŭro,Tiempo,,Aika,Temps,Idő,Tempo,経過時間,소모한 시간,Tijd,Czas,Tempo,,Timp,Время,Време -Par,TXT_IMPAR,,,,,,Μέσος Όρος,Alparo,,,,,Átlag,Media,最速時間,기준 시간,,Par,Média,,Record,Рекорд,Рекорд -Finished,WI_FINISHED,,,,Dokončen,Abgeschlossen,Ολοκληρώθηκε,Finita,Completado,,Suoritettu,terminé,Teljesítve,Finito,攻略,완료,Klaar,Ukończono,Finalizado,,Terminat,Уровень завершён,Ниво завршен -Entering,WI_ENTERING,,,,Vstupujete do,Betrete,Είσοδος,Enirante,Entrando a:,,Seuraava kohde,Niveau Suivant,Következik,Prossimo livello,突入開始,입장,Binnenkomen,Wchodzisz,Próxima fase,Próximo nível,Începe,Следующий уровень,Следећи ниво -Now entering:,WI_ENTERING,,heretic hexen,,Nyní vstupujete do:,Betrete:,Τώρα εισέρχεσε στο:,Nun enirante:,Ahora entrando a:,,Seuraava kohde:,Vous entrez:,Következik,Entrando adesso in:,突入中:,입장합니다:,Nu binnenkomen:,Teraz wchodzisz do:,Entrando em:,A entrar em:,Acum începe:,Следующий уровень:,Следећи ниво: -,,HUD,,,,,,,,,,,,,,,,,,,,, -Monsters:,AM_MONSTERS,,,,Příšery:,Monster:,Τέρατα,Monstroj:,Monstruos:,,Hirviöt:,Monstres:,Szörnyek,Mostri,奴等:,죽인 적들:,Monsters:,Potwory:,Monstros:,,Monștri:,Монстры:,Чудовишта: -Secrets:,AM_SECRETS,,,,Tajemství:,Geheimnisse:,Μυστικά,Sekretoj:,Secretos:,,Salat:,,Titkok,Segreti,隠場:,찾은 비밀:,Geheimen:,Sekrety:,Segredos:,,Secrete:,Тайники:,Тајне: -Items:,AM_ITEMS,,,,Věci:,Gegenstände:,Αντεικείμενα,Aĵoj:,Objetos:,,Esineet:,Objets:,Tárgyak,Oggetti,物資:,얻은 아이템:,Objecten:,Przedmioty:,Itens:,,Obiecte:,Предметы:,Предмети: -,,Doom,,,,,,,,,,,,,,,,,,,,, -,,Pickup,,,,,,,,,,,,,,,,,,,,, -Picked up the armor.,GOTARMOR,,,Picked up the armour.,Sebráno brnění.,Panzer genommen.,Πήρες την πανοπλία.,Prenis la kirason.,Recogiste la armadura.,,Poimit panssarin.,Armure récupérée.,Felvettél egy páncélt.,Raccolto un'armatura.,アーマーを身に着けた。,방호구를 얻었다.,Je hebt de harnas opgehaald.,Podniesiono zbroję.,Pegou uma armadura.,Apanhaste uma armadura.,Ai ridicat o armură.,Получена броня.,Покупили сте панцир. -Picked up the MegaArmor!,GOTMEGA,,,Picked up the MegaArmour!,Sebráno Megabrnění.,MegaPanzer genommen!,Πήρες την μέγα πανοπλία!,Prenis la Mega-Kirason!,¡Recogiste la Mega-Armadura!,,Poimit megapanssarin!,Méga-Armure récupérée!,Felvettél egy MegaPáncélt!,Raccolto una MegaArmatura!,メガアーマーを身に着けた!,메가아머를 얻었다!,Je hebt de MegaHarnas opgehaald!,Podniesiono megazbroję!,Pegou uma MegaArmadura!,Apanhaste uma MegaArmadura.,Ai ridicat o MegaArmură!,Получена мегаброня!,Покупили сте мегапанцир! -Picked up a health bonus.,GOTHTHBONUS,,,,Sebráno bonusové zdraví.,Gesundheitsbonus genommen.,Πήρες ένα bonus υγείας.,Prenis sanon bonuson.,Recogiste salud extra.,,Poimit terveyslisän.,Bonus de Santé récupéré.,Felvettél egy élet bónuszt.,Raccolto un bonus di salute.,ヘルスボーナスを拾った。,체력 보너스를 얻었다.,Je hebt een gezondheidsbonus opgehaald.,Podniesiono bonus do zdrowia.,Pegou um bônus de vida.,Apanhaste um bônus de vida.,Ai ridicat un bonus de sănătate.,Получен бонус к здоровью.,Покупили сте бонус здравља. -Picked up an armor bonus.,GOTARMBONUS,,,Picked up an armour bonus.,Sebráno bonusové brnění.,Panzerbonus genommen.,Πήρες ένα bonus πανο.πλίας.,Prenis kirasan bonuson.,Recogiste blindaje extra.,,Poimit panssarilisän.,Bonus d'Armure récupéré.,Felvettél egy páncél bónuszt.,Raccolto un bonus d'armatura.,アーマーボーナスを拾った。,보호 보너스를 얻었다.,Je hebt een harnasbonus opgehaald.,Podniesiono bonus do zbroi.,Pegou um bônus de armadura.,Apanhaste um bônus de armadura.,Ai ridicat un bonus de armură.,Получен бонус к броне.,Покупили сте бонус панцира. -Picked up a stimpack.,GOTSTIM,,,,Sebrán stimulant.,Stimpack genommen.,Πήρες ένα μικρό πακέτο υγείας.,Prenis stimulilon-pakon.,Recogiste un estimulante.,,Poimit piristeruiskeen.,Stimpack récupéré.,Felvettél egy stimpacket.,Raccolto uno stimpack.,スティムパックを拾った。,스팀팩을 사용했다.,Je hebt een stimuleringspakket opgehaald.,Podniesiono stimpacka.,Pegou um stimpack.,Apanhaste um kit de primeiros socorros.,Ai ridicat un kit de prim-ajutor mic.,Получен стимулятор.,Покупили сте стимпак. -Picked up a medikit that you REALLY need!,GOTMEDINEED,,,,"Sebrána lékárnička, kterou jsi FAKT potřeboval.","Medikit genommen, das du WIRKLICH brauchst!",Πήρες πρώτες βοήθειες που χρειαζόσουνα ΠΆΡΑ ΠΟΛΥ!,Prenis sukurkeston kiun vi VERE bezonas!,¡Recogiste un botiquín que REALMENTE necesitabas!,,"Poimit lääkintälaukun, jota TODELLA tarvitsit!","Médikit récupéré, et vous en aviez vraiment besoin!",Felvettél egy életcsomagot amire NAGYON szükséged volt!,Hai raccolto un kit medico di cui avevi PROPRIO bisogno!,本当に必要なメディキットを手に入れた!,메디킷을 필요한 순간에 사용했다!,Je hebt een medikit opgehaald die je ECHT nodig hebt!,Podniesiono apteczkę której NAPRAWDĘ potrzebujesz!,"Pegou um kit médico -que você REALMENTE precisa!","Apanhaste um kit médico +",Мењам ниво...,Ändrad nivå ...,Seviye Değiştirme...,Зміна рівня... +Buddha mode ON,TXT_BUDDHAON,,,,Buddha mód ZAP,Buddha-tilstand TIL,Buddhamodus AN,Λειτουργία Βουδα ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Budha reĝimo ŜALTITA,Modo Buda ACTIVADO,,Buddhatila PÄÄLLÄ,Mode Bouddha ON,Buddha Mód BE,Modalità Buddha ATTIVATA,ブッダモード: オン,부처 모드 켬,Boeddha-modus AAN,Buddha-modus PÅ,Tryb Buddy WŁĄCZONY,Modo Buda ATIVADO,,Modul Buddha ACTIVAT,Режим Будды ВКЛЮЧЁН,Буда Мод УКЉУЧЕН,Buddha-läge på,Buda modu AÇIK,Будда-мод ВВІМК. +Buddha mode OFF,TXT_BUDDHAOFF,,,,Buddha mód VYP,Buddha-tilstand FRA,Buddhamodus AUS,Λειτουργία Βουδα ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Budha reĝimo MALŜALTITA,Modo Buda DESACTIVADO,,Buddhatila POIS PÄÄLTÄ,Mode Bouddha OFF,Buddha Mód KI,Modalità Buddha DISATTIVATA,ブッダモード: オフ,부처 모드 끔,Boeddha-modus UIT,Buddha-modus AV,Tryb Buddy WYŁĄCZONY,Modo Buda DESATIVADO,,Modul Buddha DEZACTIVAT,Режим Будды ОТКЛЮЧЁН,Буда Мод ИСКЉУЧЕН,Buddha-läge avstängt,Buda modu KAPALI,Будда-мод ВИМК. +Ultimate Buddha Mode ON,TXT_BUDDHA2ON,,,,Super Buddha mód ZAP,Ultimate Buddha-tilstand TIL,Ultimativer Buddhamodus AN,Λειτουργία Απόλητου Βουδα ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Pleja Budha Reĝimo ŜALTITA,Modo Buda Supremo ACTIVADO,,Korkein buddhatila PÄÄLLÄ,Mode Bouddha Ultime ON,Tökéletes Buddha Mód BE,Modalità Ultimo Buddha ATTIVATA,究極ブッダモード: オン,나무 아미타불 모드 켬,Ultieme Boeddha-modus AAN,Ultimativ Buddha-modus PÅ,Maksymalny Tryb Buddy WŁĄCZONY,Modo Buda supremo ATIVADO,,Modul Buddha Suprem ACTIVAT,Окончательный режим Будды ВКЛЮЧЁН,Ултимативни Буда Мод УКЉУЧЕН,Ultimat Buddha-läge på,Nihai Buda Modu AÇIK,Ультимативний Будда-мод ВВІМК. +Ultimate Buddha Mode OFF,TXT_BUDDHA2OFF,,,,Super Buddha mód VYP,Ultimate Buddha-tilstand FRA,Ultimativer Buddhamodus AUS,Λειτουργία Απόλητου Βουδα ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Pleja Budha Reĝimo MALŜALTITA,Modo Buda Supremo DESACTIVADO,,Korkein buddhatila POIS PÄÄLTÄ,Mode Bouddha Ultime OFF,Tökéletes Buddha Mód KI,Modalità Ultimo Buddha DISATTIVATA,究極ブッダモード: オフ,나무 아미타불 모드 끔,Ultieme Boeddha-modus UIT,Ultimativ Buddha-modus AV,Maksymalny Tryb Buddy WYŁĄCZONY,Modo Buda supremo DESATIVADO,,Modul Buddha Suprem DEZACTIVAT,Окончательный режим Будды ОТКЛЮЧЁН,Ултимативни Буда Мод ИСКЉУЧЕН,Ultimat Buddha-läge av,Nihai Buda Modu KAPALI,Ультимативний Будда-мод ВИМК. +Power on,TXT_CHEATPOWERON,,,,Energie ZAP,Evne TIL,Fähigkeit AN,Δύναμη ενεργοποιημένη,Povo ŝaltita,Poder activado,,Voima päällä,Pouvoir Activée,Energia BE,Potere ATTIVATO,パワー オン,파워 켬,Vermogen aan,Strøm PÅ,Zasilanie włączone,Poder ativado,,Putere activată,Сила активирована,Моћ УКЉУЧЕНА,Makt på,Güç açık,Сила активована +Power off,TXT_CHEATPOWEROFF,,,,Energie VYP,Evne FRA,Fähigkeit AUS,Δύναμη άπενεργοποιημένη,Povo malŝaltita,Poder desactivado,,Voima pois päältä,Pouvoir Désactivée,Energia KI,Potere DISATTIVATO,パワー オフ,파워 끔,Vermogen uit,Slå AV,Zasilanie wyłączone,Poder desativado,,Putere dezactivată,Сила деактивирована,Моћ ИСКЉУЧЕНА,Makt av,Güç kapalı,Сила деактивована +Full health,TXT_CHEATHEALTH,,,,Plné zdraví,Fuldt helbred,Volle Lebensenergie,Ολόκληρη υγεία,Plena sano,Salud al máximo,,Täysi terveys,Pleine Santé,Teljes életerő,Piena salute,ヘルス全回復,체력 완전 회복,Volledige gezondheid,Full helse,Pełne zdrowie,Saúde completa,Vida totalmente cheia,Sănătate completă,Полное здоровье,Здравље напуњено,Full hälsa,Tam sağlık,Повне здоров'я +All keys,TXT_CHEATKEYS,,,,Všechny klíče,Alle taster,Alle Schlüssel,Όλα τα κλειδία,Ĉiuj ŝlosiloj,Todas las llaves,,Kaikki avaimet,Toutes les Clés,Összes kulcs,Tutte le chiavi,キー全部,모든 열쇠,Alle sleutels,Alle taster,Wszystkie klucze,Todas as chaves,,Toate cheile,Все ключи,Сви кључеви,Alla tangenter,Tüm anahtarlar,Усі ключі +Sound debug on,TXT_CHEATSOUNDON,,,,Debug zvuku ZAP,Sound debug TIL,Sound Debug AN,Debug ήχου ενεργοποιημένη,Sono-sencimiga reĝimo ŝaltita,Depuración de sonido activada,,Äänen vianmääritystila päällä,Débogage du son activé.,Hang debug BE,Debug del suono attivato,サウンドデバッグ オン,효과음 디버그 켬,Geluid debug aan,Lyd feilsøking PÅ,Debugowanie dźwięku włączone,Depuração de som ativada,,Debug sunet activat,Отладка звука включена,Дебаговање звука УКЉУЧЕНО,Ljud felsökning på,Ses hata ayıklama açık,Налагодження звуку УВІМКНЕНО +Sound debug off,TXT_CHEATSOUNDOFF,,,,Debug zvuku VYP,Sound debug FRA,Sound Debug AUS,Debug ήχου άπενεργοποιημένη,Sono-sencimiga reĝimo malŝaltita,Depuración de sonido desactivada,,Äänen vianmääritystila pois päältä,Débogage du son désactivé.,Hang debug KI,Debug del suono disattivato,サウンドデバッグ オフ,효과음 디버그 끔,Geluid debug uit,Lyd feilsøking AV,Debugowanie dźwięku wyłączone,Depuração de som desativada,,Debug sunet dezactivat,Отладка звука отключена,Дебаговање звука ИСКЉУЧЕНО,Ljud felsökning av,Ses hata ayıklama kapalı,Налагодження звуку ВИМКНЕНО +"Trying to cheat, eh? Now you die!",TXT_CHEATIDDQD,,,,"Pokoušíš se cheatovat, co? Teď zemřeš!","Prøver du at snyde, hva'? Nu dør du!","Versuchst zu betrügen, was? Nun stirbst du!","Προσπαθείς να εξαπατήσεις, ε? Τώρα πεθένεις!","Provas trompi, ĉu vi? Nun vi mortas! ","¿Tratando de hacer trampas, eh? ¡Muere!",,"Yrität huijata, vai? Nyt kuolet!","Tu essaie de tricher, hein? Maintenant tu meurs!","Csalni akarsz, mi? Most meghalsz!","Cerchi di barare, eh? Allora muori!",その名を唱えたな? 褒美に死をやろう!,치트 쓸려고? 그럼 죽어야지!,"Je wou valsspelen, hè? Nu ga je dood!",Prøver du å jukse? Nå dør du!,"Próbujesz oszukiwać, co? Teraz giń!","Tentando trapacear, né? Morra!","A fazer batota, é? Morre!","Încerci să trișezi, ei? Acum mori!","Жульничаешь, э? Так умри!","Покушаваш да вараш, ех? Сада умиреш!",Försöker du fuska? Nu dör du!,"Hile yapmaya çalışıyorsun, ha? Şimdi öleceksin!","Хех, чітериш? Тепер помри!" +Cheater - you don't deserve weapons,TXT_CHEATIDKFA,,,,Podvodníku - nezasloužíš si zbraně,Snyder - du fortjener ikke våben,Betrüger - du verdienst keine Waffen,Απατεόνα δέν σου αξήζουν όπλα,Trompanto - vi ne meritas armilojn,¡Trampos@[ao_esp]! No mereces tener armas,,Huijari - et ansaitse aseita,Tricheur- Tu ne mérite pas d'armes!,Csaló - nem érdemelsz fegyvert!,Imbroglione - non meriti armi,不届き者め、貴様が偉業を成すはずがない,사기꾼놈! 너는 무기를 가질 자격이 없어!,Valsspeler - je verdient geen wapens.,Juksemaker - du fortjener ikke våpen,Oszust - nie zasługujesz na bronie,Trapaceiros não merecem armas,Batoteir@[ao_ptb] - Não mereces armamento,Trișor - Nu meriți arme,Жулик — ты не заслуживаешь оружия,Варалице - ти не заслужујеш оружје,Fuskare - du förtjänar inte vapen.,"Hileci, silahları hak etmiyorsun.",Пройдисвіт - ти не заслужив зброї +Ticker on,TXT_CHEATTICKERON,,,,Počítadlo ZAP,Ticker TIL,Zähler AN,Χρονόμετρο ενεργοποιημένο,Nombrilo ŝaltita,Contador activado,,Laskuri päällä,Compteur allumé,Számláló BE,Ticker attivato,ティッカー オン,프레임 속도 표시 켬,Ticker aan,Ticker PÅ,Wskaźnik włączony,Contador ativado,,Ticăitoare activată,Счётчик включён,Бројач укључен,Ticker på,Ticker açık,Лічильник Ввімк. +Ticker off,TXT_CHEATTICKEROFF,,,,Počítadlo VYP,Ticker FRA,Zähler AUS,Χρονόμετρο άπενεργοποιημένο,Nombrilo malŝaltita,Contador desactivado,,Laskuri pois päältä,Compteur éteint,Számláló KI,Ticker disattivato,ティッカー オフ,프레임 속도 표시 끔,Ticker uit,Ticker AV,Wskaźnik wyłączony,Contador desativado,,Ticăitoare dezactivată,Счётчик отключён,Бројач искључен,Ticker av,Ticker kapalı,Лічильник Вимк. +You got it,TXT_CHEATARTIFACTS3,,,,Máš to mít,Du fik det,Du hast es,Το πήρες,Vi akiris ĝin,Lo tienes,,Saamasi pitää,C'est à vous!,Megkaptad,Concesso,それを渡そう。,얻었다,Je hebt het,Du har det,Udało ci się,Concedido,,Ai ce-ți trebuie,Вы получили это,Уреду,Du fick det,Tamamdır.,Ви отримали це +"You got the Midas Touch, baby",TXT_MIDASTOUCH,,,,"Máš Midasův dotek, zlato","Du har Midas Touch, baby",Dagobert Duck lässt grüßen!,"Έχεις το αγγιγμα το Μίδα, μωρό.","Vi akiris la Tuŝon de Midas, kara","Tienes el toque de Midas, muchach@[ao_esp]",,"Kulta, sinulla on Midaksen kosketus",,"Minden arannyá válik amit megérintesz, öreg","Hai avuto il Tocco di Mida, baby",ミダス王の様だな、ベイビー,넌 미다스의 손을 얻었어 베이베!,"Je hebt de Midas Touch, schatje","Du har Midas Touch, baby","Zdobył@[irreg_3_pl] dotyk Midasa, skarbie","Você tem o Toque de Midas, baby","Tens o Toque de Midas, baby","Ai Atingerea lui Midas, dragule","Ты превращаешь всё в золото, детка!","Имаш златке руке, душо","Du har Midas Touch, baby","Sende Midas Dokunuşu var, bebeğim","Дар Мідаса у твоїх руках, золотце" +You got the stuff!,TXT_GOTSTUFF,,,,Dostal jsi věci!,Du har det hele!,Du hast den Kram erhalten,Πήρες τηατ πράγματα !,Vi akiris la aĵojn!,¡Tienes un montón de cosas!,,Sait kamppeet!,Voilà ton équipement!,Megkaptad a cuccot!,Hai avuto il materiale!,スタッフを手に入れた!,무언가를 얻었다!,Je hebt het spul!,Du har greiene!,Zdobył@[irreg_3_pl] parę rzeczy!,Você ganhou muitas coisas!,ganhaste muitas coisas!,Ai tot ce-ți trebuie!,Получены предметы!,Покупили сте ствари!,Du har grejerna!,Mal sende!,Отримано предмети! +Freeze mode on,TXT_FREEZEON,,,,Režim zamrznutí ZAP,Frysetilstand TIL,Gefriermodus AN,Παγομένη λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Movhalta reĝimo ŝaltita,Modo suspendido activado,,Jäädytystila päällä,Temps arrêté.,Fagyasztás BE,Modalità arresto del tempo attivata,フリーズモード オン,시간정지 켬,Bevriesmodus aan,Frysemodus PÅ,Tryb zamrożenia włączony,Modo congelado ativado,,Modul înghețat activat,Режим заморозки включён,Мод замрзавања УКЉУЧЕН,Frysningsläge på,Dondurma modu açık,Режим заморозки ВВІМКНЕНО +Freeze mode off,TXT_FREEZEOFF,,,,Režim zamrznutí VYP,Frysetilstand FRA,Gefriermodus AUS,Παγομένη λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Movhalta reĝimo malŝaltita,Modo suspendido desactivado,,Jäädytystila pois päältä,Le temps reprend son cours..,Fagyasztás KI,Modalità arresto del tempo disattivata,フリーズモード オフ,시간정지 끔,Bevriesmodus uit,Frysemodus AV,Tryb zamrożenia wyłączony,Modo congelado desativado,,Modul înghețat dezactivat,Режим заморозки отключён,Мод замрзавања ИСКЉУЧЕН,Frysningsläge av,Dondurma modu kapalı,Режим заморозки ВИМКНЕНО +You feel strange...,TXT_STRANGE,,,,Cítíš se divně...,Du føler dig mærkelig...,Du fühlst dich merkwürdig...,Νιώθης περίεργα...,Vi sentas vin strange...,Te sientes extrañ@[ao_esp]...,,Sinulla on kummallinen olo...,Vous vous sentez mal à l'aise...,Furán érzed magad...,Ti senti strano...,これは奇妙な感じだな...,뭔가 이상한 기분이...,Je voelt je vreemd...,Du føler deg rar...,Dziwnie się czujesz...,Você está com uma sensação estranha...,Tu sentes-te estranh@[ao_ptb].,Te simți ciudat...,Вы чувствуете себя странно...,Осећате се чудно...,Du känner dig konstig...,Garip hissediyorsun.,Ви почуваєте себе дивно... +You feel even stranger.,TXT_STRANGER,,,,Cítíš se ještě divněji...,Du føler dig endnu mere mærkelig.,Du fühlst dich noch merkwürdiger,Νιώθης ακόμα πιό περίεργα...,Vi sentas vin eĉ pli strange.,Te sientes aún más extrañ@[ao_esp],,Olosi on vieläkin kummempi.,Vous vous sentez très mal à l'aise...,Még furábban érzed magad.,Ti senti ancora più strano.,これはかなり奇妙だ。,기분이 더더욱 이상해졌다.,Je voelt je nog vreemder.,Du føler deg enda merkeligere.,Czujesz się jeszcze dziwniej.,Você está com uma sensação mais estranha ainda.,Tu sentes-te ainda mais estranh@[ao_ptb].,Te simți și mai ciudat.,Вы чувствуете себя очень странно.,Осећате се врло чудно.,Du känner dig ännu konstigare.,Daha da garip hissediyorsun.,Ви почуваєте себе ще дивніше. +You feel like yourself again.,TXT_NOTSTRANGE,,,,Cítíš se opět jako ty.,Du føler dig som dig selv igen.,Du fühlst dich wieder wie du selbst,Νιώθης σάν τον εαύτο σου ξανά...,Vi denove sentas vin kiel vi mem.,Te sientes como tú mism@[ao_esp] otra vez.,,Tunnet olevasi jälleen oma itsesi.,Vous vous sentez mieux.,Magadhoz tértél.,Ti senti di nuovo te stesso.,自分自身の様に感じている。,자기 자신처럼 생각하게 됐다.,Je voelt je weer als jezelf.,Du føler deg som deg selv igjen.,Znów czujesz się sobą.,Você se sente normal novamente.,Tu sentes-te normal novamente.,Ți-ai revenit în simțiri.,Вы снова чувствуете себя собой.,Поново се осећате као ви.,Du känner dig som dig själv igen.,Tekrar kendin gibi hissediyorsun.,Ви почуваєтесь собою. +Lead boots on,TXT_LEADBOOTSON,,,,Olověné boty ZAP,Blystøvler TIL,Bleistiefel AN,Μολυβδένιες μπότες ΕΝΕΡΓΟΠΟΙΗΜΈΝΕΣ,Botoj el plumbo ŝaltita,Botas de plomo activadas,,Lyijysaappaat päällä,Bottes en plomb ON,Ólomcsizma BE,Stivali di Piombo ON,足枷 オン,납 부츠 켬,Loden laarzen aan,Blystøvler PÅ,Ołowiane buty włączone,Botas de chumbo ativadas,,Bocanci de plumb activați,Свинцовые сапоги надеты,Оловне чизме УКЉУЧЕНЕ,Blystövlar på,Kurşun çizmeler,Одягнено свинцеві чоботи +Lead boots off,TXT_LEADBOOTSOFF,,,,Olověné boty VYP,Blystøvler FRA,Bleistiefel AUS,Μολυβδένιες μπότες ΆΠΕΝΕΡΓΟΠΟΙΗΜΕΝΕΣ,Botoj el plumbo malŝaltita,Botas de plomo desactivadas,,Lyijysaappaat pois päältä,Bottes en plomb OFF,Ólomcsizma KI,Stivali di Piombo OFF,足枷 オフ,납 부츠 끔,Loden laarzen uit,Blystøvler AV,Ołowiane buty wyłączone,Botas de chumbo desativadas,,Bocanci de plumb dezactivați,Свинцовые сапоги сняты,Оловне чизме ИСКЉУЧЕНЕ,Blykängor av,Kurşun çizmeler kapalı,Знято свинцеві чоботи +You feel lighter,TXT_LIGHTER,,,,Cítíš se lehčí,Du føler dig lettere,Du fühlst dich leichter,Νιώθης πιο ελαφρής,Vi sentas vin pli malpeza,Te sientes más liger@[ao_esp],,Tunnet olosi kevyemmäksi,Vous vous sentez très léger.,Könnyűnek érzed magad,Ti senti più leggero,体が軽くなった,가벼운 느낌이 든다,Je voelt je lichter,Du føler deg lettere,Czujesz się lżejsz@[adj_pl],Você se sente mais leve,Tu sentes-te mais leve,Te simți mai ușor,Вы чувствуете лёгкость.,Осећате лакоћу.,Du känner dig lättare.,Daha hafif hissediyorsun,Ви побороли гравітацію +Gravity weighs you down,TXT_GRAVITY,,,,Gravitace tě táhne dolů,Tyngdekraften tynger dig ned,Schwerkraft belastet dich,Η βαρύτητα σε πιάνει.,Gravito pezigas vin,La gravedad te hace descender,,Painovoima painaa sinua alas,La gravité vous ramène au sol.,A gravitáció lehúz téged,La gravità ti riporta a terra,重力に従った,중력이 당신을 붙잡았다,Zwaartekracht werkt op je...,Tyngdekraften tynger deg ned,Grawitacja znów cię przyciąga,A gravidade volta a funcionar normalmente,A gravidade voltou ao normal,Gravitația te trage în jos,Гравитация тянет вас вниз.,Гравитација Вас вуче надоле.,Tyngdkraften tynger ner dig,Yerçekimi seni ağırlaştırır,Гравітація знову притискає вас до землі +No Target ON,TXT_NOTARGET_ON,,,,Neútočící příšery ZAP,Ingen mål TIL,notarget AN,Αστόχευτη λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Neniu Celo ŜALTITA,No Objetivo ACTIVADO,,Hyökkäämättömyystila PÄÄLLÄ,Monstres aveugles et sourds ON,Nem támadnak a szörnyek BE,Modalità Mostri ciechi e sordi ATTIVATA,ノーターゲット オン,적 표적 감지 켬,Geen doelwit AAN,No Target PÅ,Głuche i Ślepe Potwory WŁĄCZONE,Sem alvos ATIVADO,,Modul Inamici fără Țintă ACTIVAT,Незаметность ВКЛЮЧЕНА,Нема мете УКЉУЧЕНО,Inget mål på,Hedef Yok AÇIK,Невідчутність ввімкнено +No Target OFF,TXT_NOTARGET_OFF,,,,Neútočící příšery VYP,Ingen mål FRA,notarget AUS,Αστόχευτη λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Neniu Celo MALŜALTITA,No Objetivo DESACTIVADO,,Hyökkäämättömyystila POIS PÄÄLTÄ,Monstres aveugles et sourds OFF,Nem támadnak a szörnyek KI,Modalità Mostri ciechi e sordi DISATTIVATA,ノーターゲット オフ,적 표적 감지 끔,Geen doelwit UIT,No Target AV,Głuche i Ślepe Potwory WYŁĄCZONE,Sem alvos DESATIVADO,,Modul Inamici fără Țintă DEZACTIVAT,Незаметность ОТКЛЮЧЕНА,Нема мете ИСКЉУЧЕНО,Inget mål av,Hedef Yok KAPALI,Невідчутність вимкнено +"""Quake with fear!""",TXT_ANUBIS_ON,,,,„Třeste se strachy!“,"""Skælv af frygt!""",„Zittere vor Angst!“,"""Τρέμε με φόβο!""","""Tremu pro timo!""","""¡Temblad de miedo!""","""¡Tiemblen de miedo!""","""Vapise pelosta!""",« Tremblez de terreur! »,"""Reszkess, halandó!""","""Trema con terrore!""",恐れおののけ!,공포에 떨어라!,„Beving van angst!“,"""Skjelv av frykt!""","""Trzęś się ze strachu""","""Trema de medo!""","""Trema com medo!""","""Tremură de Frică!""",«Дрожите от страха!»,„Дрхтите у страху!“,"""Skräck skakar av rädsla!""","""Korkudan titre!""","""Трясись зі страху!""" +No more Ogre Armor,TXT_ANUBIS_OFF,,,,Už žádné zlobří brnění,Ikke mere troldepanser,Keine Ogerrüstung mehr,Καθόλου δρακοντική πανοπλία πια,Ne plu Ogrokiraso,No más armadura de Ogro,,Ei enää örkkipanssaria,Plus d'armure d'ogre,Ogre pajzs lejárt,Niente più armatura Ogre,オーガアーマーはもう嫌,오거 갑옷은 이제 없다.,Geen Ogre Pantser meer,Ikke mer Ogre Armor,Nigdy więcej Pancerza Ogrów,Chega de Armadura de Ogro,Chega de Armadura de Ogre,Gata cu Armura de Căpcăun,Броня огра снята,Нема више бауков оклоп,Inget mer träsktorns rustning,Artık Ogre Zırhı yok,Броню огра знято +chasecam ON,TXT_CHASECAM_ON,,,,Pohled z třetí osoby ZAP,chasecam TIL,chasecam AN,Κάμερα τρίτου πρωσώπου ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Ĉaskamerao ŜALTITA,Cámara de seguimiento ACTIVADA,,Seurantakamera PÄÄLLÄ,,követő kamera BE,Modalità camera da inseguimento ATTIVATA,チェイスカメラ オン,3인칭 카메라 켬,Chasecam AAN,chasecam PÅ,kamera śledzenia WŁĄCZONA,Câmera em terceira pessoa ATIVADA,Câmara em Terceira Pessoa ATIVADA,Perspectivă la Persoana a 3-a ACTIVATĂ,Вид от третьего лица ВКЛЮЧЁН,Чејс-кам УКЉУЧЕН,chasecam på,Chasecam AÇIK,Камера від 3-го лиця активована +chasecam OFF,TXT_CHASECAM_OFF,,,,Pohled z třetí osoby VYP,chasecam FRA,chasecam AUS,Κάμερα τρίτου πρωσώπου ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Ĉaskamerao MALŜALTITA,Cámara de seguimiento DESACTIVADA,,Seurantakamera POIS PÄÄLTÄ,,követő kamera KI,Modalità camera da inseguimento DISATTIVATA,チェイスカメラ オフ,3인칭 카메라 끔,Chasecam UIT,chasecam AV,kamera śledzenia WYŁĄCZONA,Câmera em terceira pessoa DESATIVADA,Câmara em Terceira Pessoa DESATIVADA,Perspectivă la Persoana a 3-a DEZACTIVATĂ,Вид от третьего лица ОТКЛЮЧЁН,Чејс-кам ИСКЉУЧЕН,chasecam av,Chasecam KAPALI,Камера від 3-го лиця деактивована +1 baddie killed,TXT_BADDIE_KILLED,,,,1 zloun zabit,1 baddie dræbt,1 Bösewicht getötet,Ενας κακός πέθανε,1 malbonulo mortigita,Un malote aniquilado,,1 pahis tapettu,1 enemi tué,1 rosszfiú kinyírva,Ucciso 1 maligno,1 体 殺した,1 명의 나쁜놈이 사살됨.,1 slechterik gedood,1 skurk drept,1 zabity przeciwnik,1 inimigo morto,,1 slab ucis,1 плохиш убит,Један зликовац убијен,1 skurk dödad,1 kötü öldürüldü,1 поганець вмер +%d baddies killed,TXT_BADDIES_KILLED,,,,%d zlounů zabito,%d baddies dræbt,%d Bösewichte getötet,%d τον κακόν πέθαναν,%d malbonuloj mortigitaj,%d malotes aniquilados,,%d pahista tapettu,%d enemis tués,%d rosszfiú kinyírva,Uccisi %d maligni,%d 体 殺した,%d 명의 나쁜놈들이 사살됨.,%d slechteriken gedood,%d skurker drept,%d zabitych przeciwników,%d inimigos mortos,,%d slabi uciși,Плохишей убито: %d,%d зликовца убијено,%d skurkar dödade,%d kötüler öldürüldü,Поганців вмерло: %d +1 monster killed,TXT_MONSTER_KILLED,,,,1 příšera zabita,1 monster dræbt,1 Monster getötet,Ένα τέρας πέθανε,1 monstro mortigita,Un monstruo aniquilado,,1 hirviö tapettu,1 monstre tué,1 szörny kinyírva,Ucciso 1 mostro,1 匹 殺した,1 마리의 몬스터가 사살됨.,1 monster gedood,1 monster drept,1 zabity potwór,1 monstro morto,,1 monstru ucis,1 монстр убит,Једно чудовиште убијено,1 monster dödat,1 canavar öldürüldü,1 монстра убито +%d monsters killed,TXT_MONSTERS_KILLED,,,,%d příšer zabito,%d monster dræbt,%d Monster getötet,%d τον τεράτων πέθαναν,%d monstroj mortigitaj,%d monstruos aniquilados,,%d hirviötä tapettu,%d monstres tués,%d szörny kinyírva,Uccisi %d mostri,%d 匹 殺した,%d 마리의 몬스터들이 사살됨.,%d monsters gedood,%d monstre drept,%d zabitych potworów,%d monstros mortos,,%d monștri uciși,Убито монстров: %d,%d чудовишта убијено,%d monster dödade,öldürülen %d canavar,Монстрів вбито: %d +Unable to resurrect. Player is no longer connected to its body.,TXT_NO_RESURRECT,,,,"Oživení není možno, hráč už není spojen se svým tělem.",Kan ikke genoplive. Spilleren er ikke længere forbundet med sin krop.,Kann nicht wiederbeleben. Der Spieler ist nicht mehr mit seinem Körper verbunden.,"Ανάσταση αδύνατη, ο παίχτης δεν είναι πια στο σώμα @[pro4_gr]","Nerevivigebla. La ludanto ne plu +estas konektita al sia korpo.",Imposible de resucitar. El jugador ya no está conectado a su cuerpo.,,Ei mahdollista herätä henkiin. Pelaaja ei ole enää yhteydessä ruumiiseensa.,Impossible de ressuciter. Le joueur n'est plus connecté à son corps.,Nem sikerült a felélesztés. A játékos nincs összekötve a testtel.,Impossibile resuscitarsi. Il giocatore non è più connesso al suo corpo.,復活できない。プレイヤーはこの体に宿っていない。,부활할 수 없습니다. 플레이어는 더 이상 육체와 연결돼있지 않습니다.,Kan niet reanimeren. De speler is niet langer verbonden met zijn lichaam.,Kan ikke gjenoppstå. Spilleren er ikke lenger koblet til kroppen sin.,Nie można wskrzesić. Gracz nie jest już połączony z resztą swojego ciała.,"Impossível ressuscitar. O jogador não +está mais ligado ao próprio corpo.",,Imposibil de înviat. Jucătorul nu mai e conectat la cadavru.,Воскрешение невозможно. Игрок больше не соединён с трупом.,Немогуће оживети. Играч није више повезан са својим телом.,Det går inte att återuppliva. Spelaren är inte längre ansluten till sin kropp.,Diriltilemiyor. Oyuncu artık bedenine bağlı değil.,Воскресіння неможливе. Гравець більше не з'єднаний з тілом. +All Artifacts!,TXT_ALL_ARTIFACTS,,,All Artefacts!,Všechny artefakty!,Alle artefakter!,Alle Artefakte!,Όλα τα τεχνουργίματα!,Ĉiuj Artefaktoj!,¡Todos los artefactos!,,Kaikki artefaktit!,Tous les artéfacts!,Összes értéktárgy!,Tutti gli Artefatti!,全アーティファクト!,모든 유물들!,Alle artefacten!,Alle artefakter!,Wszystkie Artefakty!,Todos os artefatos!,,Toate Artefactele!,Все артефакты!,Сви артифакти!,Alla artefakter!,Tüm eserler!,Усі артефакти! +What do you want to kill outside of a game?,TXT_WHAT_KILL,,,,"Co chceš zabít, když nejsi ve hře?",Hvad vil du dræbe uden for et spil?,Was willst du eigentlich außerhalb eines Spiels töten?,Τί θέλεις να σκοτώσεις έξω απο ένα παιχνίδι ?,Kion vi volas mortigi ekster ludo?,¿Qué intentas matar fuera de una partida?,,Mitä haluat tappaa pelin ulkopuolella?,Que voulez-vous tuer en dehors d'une partie?,Mit tudnál megölni játékon kívül?,Cosa vorresti uccidere fuori dal gioco?,ゲーム外で何を殺す気だ?,게임 밖에서 무엇을 죽이고 싶습니까?,Wat wil je buiten een spel om doden?,Hva vil du drepe utenfor et spill?,Co ty chcesz zabić poza grą?,O que você gostaria de matar fora de um jogo?,,Ce vrei să ucizi în afara unui joc?,Что вы хотите убить вне игры?,Шта желите да убијете ван игре?,Vad vill du döda utanför ett spel?,Oyun dışında ne öldürmek istiyorsun?,"Що, хочеш вбивати в реальності?" +Frozen player properties turned off,TXT_NOT_FROZEN,,,,Vlastnosti držící hráče na místě vypnuty,Frysningstilstand er slået fra.,Gefrier-Modus abgeschaltet.,Η ιδιότητες ενος παγομένου παίχτη απενεργοποίθηκαν,Atributoj de movhaltitaj ludantoj malŝaltitaj,Propiedades de jugador congelado desactivadas,,Jäätyneen pelaajan ominaisuudet kytketty pois päältä,Propriété gelée du joueur annulée.,Fagyasztott játékos tulajdonságai kikapcsolva,Proprietà del giocatore ghiacciato disattivate,凍ったプレイヤーのプロパティを無効化,플레이어 정지 속성이 꺼졌습니다.,Eigenschappen van de bevroren speler uitgeschakeld,Frosne spilleregenskaper slått av,Właściwości zamrożonego gracza wyłączone,Propriedades de jogador congelado desativadas,,Proprietăți jucători înghețați DEZACTIVATE,Свойства замороженного игрока отключены,Смрзнути играчи искључени,Frysta spelaregenskaper avstängda,Dondurulmuş oyuncu özellikleri kapatıldı,Властивості замороженого гравця вимкнено +,,Automap,,,,,,,,,,,,,,,,,,,,,,,,,, +Follow Mode OFF,AMSTR_FOLLOWOFF,,,,Režim sledování VYP,Følg-tilstand TIL,Folgen-Modus AUS,Ακολούθηση ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Sekvigreĝimo MALŜALTITA,Modo de seguimiento DESACTIVADO,,Seuraamistila POIS PÄÄLTÄ,Suivi du Joueur OFF,Követés mód KI,Mappa scorribile ATTIVATA,追従モード: オフ,추적 모드 끔,Volgmodus UIT,Følgemodus AV,Tryb śledzenia WYŁĄCZONY,Modo de seguimento DESATIVADO,,Mod Urmărire DEZACTIVAT,Привязка к игроку ОТКЛЮЧЕНА,Праћење ИСКЉУЧЕНО,Följningsläget av,Takip Modu KAPALI,Прив'язка до гравца ВВІМК. +Follow Mode ON,AMSTR_FOLLOWON,,,,Režim sledování ZAP,Følg-tilstand FRA,Folgen-Modus AN,Ακολούθηση ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Sekvigreĝimo ŜALTITA,Modo de seguimiento ACTIVADO,,Seuraamistila PÄÄLLÄ,Suivi du Joueur ON,Követés mód BE,Mappa scorribile DISATTIVATA,追従モード: オン,추적 모드 켬,Volgmodus AAN,Følgemodus PÅ,Tryb śledzenia WŁĄCZONY,Modo de seguimento ATIVADO,,Mod Urmărire ACTIVAT,Привязка к игроку ВКЛЮЧЕНА,Праћење УКЉУЧЕНО,Följningsläget på,Takip Modu AÇIK,Прив'язка до гравца ВИМК. +Grid ON,AMSTR_GRIDON,,,,Mřížka ZAP,Raster TIL,Gitter AN,Πλέχμα ΕΝΕΡΓΟΠΟΙΜΈΝΟ,Krado ŜALTITA,Cuadrícula ACTIVADA,,Ruudukko PÄÄLLÄ,Quadrillage ON,Rács BE,Griglia ATTIVATA,グリッド: オン,격자 켬,Raster AAN,Rutenett PÅ,Siatka WŁĄCZONA,Grade ATIVADA,Grelha ATIVADA,Grilă ACTIVATĂ,Сетка ВКЛЮЧЕНА,Мрежа УКЉУЧЕНА,Rutnät på,Izgara AÇIK,Сітка ВВІМК. +Grid OFF,AMSTR_GRIDOFF,,,,Mrizka VYP,Raster FRA,Gitter AUS,Πλέχμα ΆΠΕΝΕΡΓΟΠΟΙΜΈΝΟ,Krado MALŜALTITA,Cuadrícula DESACTIVADA,,Ruudukko POIS PÄÄLTÄ,Quadrillage OFF,Rács KI,Griglia DISATTIVATA,グリッド: オフ,격자 끔,Raster UIT,Rutenett AV,Siatka WYŁĄCZONA,Grade DESATIVADA,Grelha DESATIVADA,Grilă DEZACTIVATĂ,Сетка ОТКЛЮЧЕНА,Мрежа ИСКЉУЧЕНА,Rutnät av,Izgara KAPALI,Сітка ВИМК. +Texture Mode ON,AMSTR_TEXON,,,,Texturovaný režim ZAP,Teksturtilstand TIL,Texturmodus AN,Γραφικός χάρτης ΕΝΕΡΓΟΠΟΙΜΈΝΟΣ,Tekstura Reĝimo ŜALTITA,Modo de texturas ACTIVADO,,Pintakuviointitila PÄÄLLÄ,Mode Texturé ON,Textúrák mód BE,Modalità Texture ATTIVATA,テクスチャーモード: オン,텍스쳐 모드 켬,Textuurmodus AAN,Teksturmodus PÅ,Tekstury WŁĄCZONE,Modo de textura ATIVADO,,Mod Texturat ACTIVAT,Текстурный режим ВКЛЮЧЁН,Текстуре УКЉУЧЕНЕ,Texturläge på,Doku Modu AÇIK,Текстурний режим ВВІМК. +Texture Mode OFF,AMSTR_TEXOFF,,,,Texturovaný režim VYP,Teksturtilstand FRA,Texturmodus AUS,Γραφικός χάρτης ΑΠΕΝΕΡΓΟΠΟΙΜΈΝΟΣ,Tekstura Reĝimo MALŜALTITA,Modo de texturas DESACTIVADO,,Pintakuviointitila POIS PÄÄLTÄ,Mode Texturé OFF,Textúrák mód KI,Modalità Texture DISATTIVATA,テクスチャーモード: オフ,텍스쳐 모드 끔,Textuurmodus UIT,Teksturmodus AV,Tekstury WYŁĄCZONE,Modo de textura DESATIVADO,,Mod Netexturat DEZACTIVAT,Текстурный режим ОТКЛЮЧЁН,Текстуре ИСКЉУЧЕНЕ,Texturläge av,Doku Modu KAPALI,Текстурний режим ВИМК. +Marked Spot,AMSTR_MARKEDSPOT,,,,Značka,Markeret placering,Punkt markiert,Μαρκαρησμένη τοποθεσεία,Loko Markita,Punto marcado,,Merkitty paikka,Repère marqué.,Megjelölt hely,Posizione segnata,目標をマークした,지점 추가,Gemarkeerde plek,Markert punkt,Oznaczono miejsce,Posição marcada,,Loc Marcat,Отметка,Означено место,Markerad punkt,İşaretli Nokta,Позначка +All Marks Cleared,AMSTR_MARKSCLEARED,,,,Všechny značky smazány,Alle markeringer slettes,Alle Markierungen gelöscht,Όλες η μαρκαρησμένη τοποθεσείες είναι καθαρησμένες,Ĉiuj Markoj Forigitaj,Todas las marcas eliminadas,,Kaikki merkit pyyhitty,Repères éffacés.,Összes jelölés törölve,Cancellati tutti i segni,全目標を解除した,모든 지점 지워짐,Alle markingen gewist,Alle merker fjernet,Wszystkie miejsca wyczyszczone,Todas as marcas removidas,,Toate Marcările Șterse,Отметки очищены,Ознаке избрисане,Alla markeringar raderas,Tüm İşaretler Temizlendi,Усі позначки стерто +,,Multiplayer,,,,,,,,,,,,,,,,,,,,,,,,,, +Fraglimit hit.,TXT_FRAGLIMIT,,,,Fraglimit dosáhnut.,Fraggrænse nået,Fraglimit erreicht,Το όριο κοματιασμόν έχει φτάσει.,Ludmurdo-limo trafita.,Límite de bajas alcanzado.,,Frägiraja saavutettu.,Limite de frags atteinte.,Fraghatár elérve.,Fraglimit raggiunto.,フラグリミット!,킬제한에 도달했습니다.,Fraglimiet bereikt.,Fraglimit treff.,Limit fragów wyczerpany.,Limite de frags atingido.,,Limita de ucideri atinsă.,Достигнут лимит фрагов.,Фраг-лимит достигнут.,Fragbegränsning träffad.,Frag limiti vuruldu.,Досягнуто ліміт фрагів. +Timelimit hit.,TXT_TIMELIMIT,,,,Časový limit dosáhnut.,Tidsgrænse nået,Zeitlimit erreicht,Το χρονικό όριο έχει φτάσει.,Tempolimo trafita.,Límite de tiempo alcanzado.,,Aikaraja saavutettu.,Limite de temps atteinte.,Időhatár elérve.,Timelimit raggiunto.,ゲームセット!,시간제한에 도달했습니다.,Tijdslimiet bereikt.,Tidsbegrensningen er nådd.,Limit czasowy wyczerpany.,Limite de tempo atingido.,,Limita de timp atinsă.,Достигнут лимит времени.,Временско ограничење достигнуто.,Tidsbegränsning träffad.,Zaman limiti vuruldu.,Досягнуто ліміт часу. +%o was looking good until %g killed %hself!,SPREEKILLSELF,,,,%o vypadal@[ao_cs] dobře dokud se @[self_cs] nezabil@[ao_cs]!,"%o så godt ud, indtil @[pro_dk] dræbte sig selv!","%o sah gut aus, bis das Unglück geschah.",@[art_gr] %o πήγενε μια χαρά μέχρι που αυτοκτόνησε!,"%o estis faranta bone, ĝis @[pro_eo] mortigis sin!",¡%o se veía bien hasta que %g se mató a si mism@[ao_esp]!,,"%o oli liekeissä, kunnes meni tappamaan itsensä!",%o était en pleine folie meurtrière avant qu' %g ne se bute!,%o jól nézett ki még mielőtt megölte magát!,%o stava andando bene finchè non si è ucciso da solo!,%o は自滅するまでなかなか良かったぞ!,%o 이(가) 잘 나가려던 참에 자살했습니다!,%o zag er goed uit tot %g zelfmoord pleegde!,%o så bra ut helt til %g tok livet av seg!,%o wyglądał dobrze dopóki się nie zabił@[ao_pl],%o estava indo bem até se matar!,,%o arăta atât de bine până să se sinucidă,"%o неплохо выглядел@[ao_rus], пока не покончил@[ao_rus] с собой!",%o је изгледа@[ao_1_sr] добро док није уби@[ao_1_sr] сам@[ao_3_sr] себе!,%o såg bra ut tills han tog livet av sig!,%o kendini öldürene kadar iyi görünüyordu!,"%o вигляда@[adj_1_ua] добре, поки не вби@[adj_1_ua] себе!" +%o's killing spree was ended by %k,SPREEOVER,,,,%o@[psn1_cs] vraždící řádění ukončil hráč %k.,%os drabstog blev afsluttet af %k,%os Amoklauf wurde von %k beendet.,Ο/Η %k σταμάτησε την ανθρωποκτονία %h %o.,La mortigado de %o estis finita de %k,%k acabó con la racha de muerte de %o,,%k päätti pelaajan %o tapposarjan,La folie meurtrière de %o à été terminée par %k!,%o ámokfutását %k megállította.,La sequela di frag di %o è stata terminata da %k,%k が %o の快進撃を断ち切った!,%k 이(가) %o 의 연속 킬을 처단했습니다,%o's moordpartij werd beëindigd door %k.,%o's drapsturné ble avsluttet av %k.,Seria zabójstw %o zakończona przez %k,A matança de %o foi interrompida por %k,,Pofta de ucis a lui %o a fost pusă în cui de către %k,Игрок %k прервал череду убийств игрока %o,Серијско убијање играча %o је завршио играч %k,%os dödskampanj avslutades av %k.,%o onu öldürene kadar %k iyi görünüyordu.,%k закінчи@[adj_1_ua] бійню %o +%k is on a killing spree!,SPREE5,,,,%k začal@[ao_cs] řádit!,%k er i gang med en mordserie!,%k läuft Amok!,Ο/Η %k άρχισε μια ανθρωποκτονία!,%k estas sur mortigado!,¡%k está atacando de lo lindo!,,%k on sarjamurhaaja!,%k est en folie meurtrière!,%o egy Ámokfutó!,%k è preda di un momento omicida!,%k が連続キル!,%k 연속 킬!,%k is op een moordpartij!,%k er på drapsturné!,%k popełnia serię morderstw!,%k está cometendo uma matança!,,%k are chef de ucis!,Игрок %k совершил череду убийств!,%k је серијални убица!,%k är på en mordresa!,%k bir ölüm çılgınlığında!,%k смакує різанину! +%k is on a rampage!,SPREE10,,,,%k zuří!,%k er på et amokløb!,%k tobt sich aus!,Ο/Η %k είναι σε ξέσπασμα!,%k estas sur furiozado!,¡%k está en medio de una aniquilación!,,%k riehuu valtoimenaan!,%k est en plein massacre!,%o Tombol!,%k sta facendo un massacro!,%k が大暴れだ!,%k 이(가) 미쳐 날뛰고 있습니다!,%k heeft razernij!,%k går amok!,%k doznaje szału!,%k está massacrando!,,%k e înverșunat!,Игрок %k в неистовстве!,%k дивља!,%k är på en våldsam resa!,%k kudurmuş durumda!,%k лютує! +%k is dominating!,SPREE15,,,,%k dominuje!,%k er dominerende!,%k dominiert!,Ο/Η %k κατακτεί.,%k estas dominanta!,¡%k está dominando!,,%k hallitsee suvereenisti!,%k domine!,%o Uralkodik!,%k sta dominando tutti!,%k が圧倒している!,%k 이(가) 우세하고 있습니다!,%k domineert!,%k dominerer!,%k dominuje!,%k está dominando!,,%k domină!,Игрок %k господствует!,%k доминира!,%k dominerar!,%k hükmediyor!,%k домінує! +%k is unstoppable!,SPREE20,,,,%k je nezastaviteln@[adj_cs]!,%k er ustoppelig!,%k kann nicht gestoppt werden!,Ο/Η %k είναι ασταμάτητος/η!,%k estas nehaltigebla!,¡%k es imparable!,,%k on pysäyttämätön!,%k est inarrétable!,%o Megállíthatatlan!,%k è inarrestabile!,%k が止まらない!,%k 을(를) 막을 수없습니다!,%k is niet te stoppen!,%k er ustoppelig!,%k jest niepowstrzymany!,%k é implacável!,,%k e de neoprit!,Игрок %k неостановим!,Играч %k је незаустављив!,%k är ostoppbar!,%k durdurulamaz!,%k неспинний! +%k is Godlike!,SPREE25,,,,%k je boží!,%k er som en gud!,%k ist wie Gott!,Ο/Η %k είναι σαν θεός/θεά!,%k estas Dia!,¡%k es una máquina de matar!,,%k on kuin jumala!,%k est un dieu!,%o Istencsászár!,%k è un dio!,%k が神の様だ!,%k 은(는) 신적입니다! ,%k is Goddelijk!,%k er guddommelig!,%k jest Bogem!,%k é um deus da matança!,,%k e precum un Zeu!,Игрок %k богоподобен!,Играч %k је божанствен!,%k är som en gud!,%k tanrı gibi!,%k божественний! +Double kill!,MULTI2,,,,Dvoj-zabití!,Dobbelt drab!,Doppel-Kill!,Δυπλός Θάνατος!,Duobla mortigo!,¡Dos menos!,,Tuplatappo!,,Dupla gyilok!,Doppia uccisione!,ダブルキル!,더블 킬!,Dubbele kill!,Dobbeltdrap!,Podwójne zabójstwo!,Morte dupla!,,Dublă ucidere!,Двойное убийство!,Дупло убиство!,Dubbeldödning!,Çifte öldürme!,Подвійне вбивство! +Multi kill!,MULTI3,,,,Multi-zabití!,Multi-drab!,Multi-Kill!,Πολυθάνατος!,Pluraj mortigoj!,¡Multidestrucción!,,Multitappo!,,Multi gyilok!,Tripla uccisione!,マルチキル!,멀티 킬!,,Multidrap!,Multi-zabójstwo!,Morte tripla!,,Ucidere multiplă!,Массовое убийство!,Вишеструко убиство!,Flera dödar!,Çoklu öldürme!,Массове вбивство! +Ultra kill!,MULTI4,,,,Ultra-zabití!,Ultra-drab!,Ultra-Kill!,Υπερθάνατος!,Ekstremaj mortigoj!,¡¡HIPERDESTRUCCIÓN!!,,Ultratappo!,,Ultra gyilok!,Ultra uccisione!,ウルトラキル!,울트라 킬!,,Ultra drep!,Ultra-zabójstwo!,Ultra matança!,,Ultra ucidere!,Ультра-убийство!,Ултра убиство!,Ultra-död!,Ultra öldürme!,Безмежне вбивство! +Monster kill!,MULTI5,,,,Monstr-zabití!,Monster-drab!,Monster-Kill!,Τερατόδες σκοτωμός!,Monstraj mortigoj!,¡¡¡S.U.P.E.R.D.E.S.T.R.U.C.C.I.Ó.N!!!,,Hirviömäinen tappo!,,Szörnyű gyilkolás!,Uccisione Mostruosa!,モンスターキル!,몬스터 킬!,,Monster drep!,Potworne zabójstwo!,Matança monstro!,Matança monstruosa!,Ucidere monstruoasă!,Чудовищное убийство!,Монструозно убиство!,Monsterdöd!,Canavar öldürme!,Монструозне вбивство! +,,Scoreboard,,,,,,,,,,,,,,,,,,,,,,,,,, +Bonus,SCORE_BONUS,,,,,,,,Bonuso,Bonificaciones,,Lisäedut,,Bónusz,,ボーナス,보너스,Bonus,,Bonusy,Bônus,,,Бонус,Бонус,,,Бонус +Color,SCORE_COLOR,,,Colour,Barva,Farve,Farbe,Χρώμα,Koloro,,,Väri,Couleur,Szín,Colore ,色,색상,Kleur,Farge,Kolor,Cor,,Culoare,Цвет,Боја,Färg,Renk,Колір +Secret,SCORE_SECRET,,,,Skrýše,Hemmeligt,Geheimnis,Μυστικό,Sekreto,Secreto,,Salat,,Titok,Segreto,シークレット,밝혀낸 비밀,Geheim,Hemmelig,Sekret,Segredo,,,Тайники,Тајна,Hemlig,Sır,Схованки +Name,SCORE_NAME,,,,Jméno,Navn,Name,Όνομα,Nomo,Nombre,,Nimi,Nom,Név,Nome,名前,이름,Naam,Navn,Nazwa,Nome,,Nume,Игрок,Име,Namn,İsim,Гравець +Delay (ms),SCORE_DELAY,,,,Zpoždění (ms),Forsinkelse (ms),Verzögerung (ms),Kαθυστέρηση (μδ),Prokrasto (ms),Retraso (ms),,Viive (ms),Délai (ms),Késleltetés (ms),Ritardo (ms) ,ping,핑 (밀리초당),Vertraging (ms),Forsinkelse (ms),Opóźnienie (ms),Atraso (ms),,Întârziere (ms),Задержка (мс),Кашњење (мс),Fördröjning (ms),Gecikme (ms),Затримка (мс) +Frags,SCORE_FRAGS,,,,Fragy,,,Κοματιασμοί,Ludmurdoj,Bajas,,Frägit,,Frag-ek,,フラグ,플레이어 킬수,,,Fragi,,,Victime,Фраги,Фрагови,,,Фраги +Deaths,SCORE_DEATHS,,,,Smrti,Dødsfald,Tode,Θάνατοι,Mortoj,Muertes,,Kuolemat,Morts,Halálok,Morti,デス,사망한 횟수,Sterfgevallen,Dødsfall,Śmierci,Mortes,,Decese,Смерти,Смрти,Dödsfall,Ölümler,Смерті +Other,SCORE_OTHER,,,,Ostatní,Andre,Andere,,Alia,Demás,,Muu,Autre,Egyéb,Altro,その他,,Anders,Andre,Inne,Outro,,Altele,Прочее,,Andra,Diğer,Інше +Missed,SCORE_MISSED,,,,Minuto,Forpasset,Verfehlt,Ξεχάστηκαν,Mankita,Pérdidas,,Hudit,Ratés,Kihagyva,Mancati ,ミス,놓친 수,Gemist,Ubesvarte,Ominięte,Perdido,,Ratate,Пропущено,Пропуштено,Missade,Cevapsız,Пропущено +Total,SCORE_TOTAL,,,,Celkem,,Gesamt,Συνολικό,Tuto,,,Yhteensä,,Összesen,Totale,合計,총점,Totaal,Totalt,Totalne,,,,Всего,Укупно,Totalt,Toplam,Разом +Level Time,SCORE_LVLTIME,,,,Čas v levelu,Niveau Tid,Levelzeit,Χρόνος Πίστας,Daŭro de Nivelo,Tiempo de nivel,,Tasoaika,Temps niveau,Pályaidő,Tempo Livello ,時間,레벨 시간,Leveltijd,Nivå Tid,Czas,Tempo de fase,Tempo do Nível,Timp Petrecut,Время уровня,Време нивоа,Nivå Tid,Seviye Zaman,Час рівня +,,Level Summary,,,,,,,,,,,,,,,,,,,,,,,,,, +Kills,TXT_IMKILLS,,,,Zabití,Dræber,,Σκοτομοί,Mortigoj,Muertes,,Tapot,Morts,Áldozatok,Uccisioni,キル,킬수,Dood,Drepte,Zabici,Vítimas,,Ucideri,Убийств,Непријатељи,Dödade,Öldürür,Вороги +Items,TXT_IMITEMS,,,,Předměty,Genstande,Gegenstände,Αντεικείμενα,Objektoj,Objetos,,Esineet,Objets,Tárgyak,Oggetti,アイテム,획득한 아이템,,Gjenstander,Przedmioty,Itens,,Obiecte,Предметов,Ставке,Föremål,Eşyalar,Предмети +Secrets,TXT_IMSECRETS,,,,Skrýše,Hemmeligheder,Geheimnisse,Μυστικά,Sekretoj,Secretos,,Salat,,Titkok,Segreti,シークレット,밝혀낸 비밀,Geheimen,Hemmeligheter,Sekrety,Segredos,,Secrete,Тайников,Тајне,Hemligheter,Sırlar,Схованки +Time,TXT_IMTIME,,,,Čas,Tid,Zeit,Χρόνος,Daŭro,Tiempo,,Aika,Temps,Idő,Tempo,経過時間,소모한 시간,Tijd,Tid,Czas,Tempo,,Timp,Время,Време,Tid,Zaman,Час +Par,TXT_IMPAR,,,,,,,Μέσος Όρος,Alparo,,,,,Átlag,Media,最速時間,기준 시간,,,,Média,,Record,Рекорд,Рекорд,,,Рекорд +Finished,WI_FINISHED,,,,Dokončeno,Færdig,Abgeschlossen,Ολοκληρώθηκε,Finita,Completado,,Suoritettu,Terminé,Teljesítve,Finito,攻略,완료,Klaar,Ferdig,Ukończono,Finalizado,,Terminat,Уровень завершён,Ниво завршен,Avslutad,Bitti,Завершено +Entering,WI_ENTERING,,,,Vstupuješ do,Indtastning af,Betrete,Είσοδος,Enirante,Entrando a:,,Seuraava kohde,Niveau Suivant,Következik,Prossimo livello,突入開始,입장,Volgende,Går inn,Wchodzisz do:,Próxima fase,Próximo nível,Începe,Переход,Следећи ниво,Ingång till,Giriş,Заходимо +Now entering:,WI_ENTERING,,heretic hexen,,Nyní vstupuješ do:,Indtastning af:,Betrete:,Τώρα εισέρχεσε στο:,Nun enirante:,Ahora entrando a:,,Seuraava kohde:,Vous entrez dans:,Következik:,Entrando adesso in:,突入中:,입장합니다:,Volgende:,Går nå inn:,Teraz wchodzisz do:,Entrando em:,A entrar em:,Acum începe:,Переход на:,Следећи ниво:,Ingång till,Şimdi giriyoruz:,Просуваємось до: +,,HUD,,,,,,,,,,,,,,,,,,,,,,,,,, +Monsters:,AM_MONSTERS,,,,Příšery:,Monstre:,Monster:,Τέρατα,Monstroj:,Monstruos:,,Hirviöt:,Monstres:,Szörnyek:,Mostri,奴等:,죽인 적들:,,Monstre:,Potwory:,Monstros:,,Monștri:,Монстры:,Чудовишта:,Monster:,Canavarlar:,Монстри +Secrets:,AM_SECRETS,,,,Skrýše:,Hemmeligheder:,Geheimnisse:,Μυστικά,Sekretoj:,Secretos:,,Salat:,,Titkos helyek:,Segreti,隠場:,찾은 비밀:,Geheimen:,Hemmeligheter:,Sekrety:,Segredos:,,Secrete:,Тайники:,Тајне:,Hemligheter:,Sırlar:,Схованки: +Items:,AM_ITEMS,,,,Věci:,Genstande:,Gegenstände:,Αντεικείμενα,Objektoj:,Objetos:,,Esineet:,Objets:,Tárgyak:,Oggetti,物資:,얻은 아이템:,,Gjenstander:,Przedmioty:,Itens:,,Obiecte:,Предметы:,Предмети:,Föremål:,Eşyalar:,Предмети: +,,Obituaries,,,,,,,,,,,,,,,,,,,,,,,,,, +%o suicides.,OB_SUICIDE,,,,%o spáchal@[ao_cs] sebevraždu.,%o begår selvmord.,%o begeht Selbstmord.,@[art_gr] %o αυτοκτόνησε,%o sinmortigis.,%o se ha suicidado.,%o se suicidó.,%o teki itsemurhan.,%o se suicide.,%o öngyilkos lett.,%o si è suicidato.,%o は自殺した。,%o 은(는) 자살했다.,%o pleegt zelfmoord.,%o begår selvmord.,%o popełnił@[ao_pl] samobójstwo.,%o se suicidou.,,%o se sinucide.,Игрок %o покончил с собой.,%o самоубиства.,%o tar självmord.,%o intihar eder.,%o самовби@[adj_2_ua]. +%o fell too far.,OB_FALLING,,,,%o spadl@[ao_cs] příliš daleko.,%o faldt for langt ned.,%o fiel zu tief.,@[art_gr] %o έπεσε,%o falis tro fore.,%o se ha caído desde muy alto.,%o se cayó desde muy alto.,%o putosi liian kaukaa.,%o est tombé@[e_fr] trop loin.,%o túl messze esett.,%o è caduto troppo in basso.,%o はあまりにも高い所から転落した。,%o 은(는) 높은 곳에서 떨어져 사망했다.,%o viel te ver.,%o falt for langt.,%o spadł@[ao_pl] za daleko.,%o caiu de um lugar alto.,,%o a căzut prea departe.,Игрок %o упал слишком далеко.,%o је па@[ao_1_sr] до сад.,%o föll för långt.,%o çok uzağa düştü.,%o впа@[adj_1_ua] надто глибоко. +%o was squished.,OB_CRUSH,,,,%o byl@[ao_cs] rozdrcen@[ao_cs].,%o blev mast.,%o wurde zerquetscht,@[art_gr] %o συνθλίφτηκε,%o estis dispremita.,%o ha quedado aplastad@[ao_esp].,%o quedó aplastad@[ao_esp].,%o liiskautui.,%o a été écrasé@[e_fr].,%o össze lett lapítva.,%o è stato schiacciato.,%o は潰された。,%o 은(는) 뭉게졌다.,%o werd geplet.,%o ble knust.,%o spłaszczył@[ao_pl] się.,%o foi esmagad@[ao_ptb].,,%o a fost strivit.,Игрок %o был раздавлен.,%o је здробљен@[adj_1_sr].,%o blev mosad.,%o ezildi.,%o розчавило. +%o tried to leave.,OB_EXIT,,,,%o se pokusil@[ao_cs] odejít.,%o forsøgte at gå.,%o wollte gehen.,@[art_gr] %o προσπάθησε να φύγει,%o provis foriri.,%o ha tratado de huir.,%o trató de huir.,%o yritti häipyä.,%o a tenté de partir.,%o megpróbált lelépni.,%o ha provato a uscire.,%o は逃げようとした。,%o 은(는) 나가려고 발버둥 쳤다.,%o probeerde te vertrekken.,%o prøvde å dra.,%o spróbował@[ao_pl] odejść.,%o tentou sair.,,%o a încercat să plece.,Игрок %o попытался уйти.,%o покуша@[ao_1_sr] да оде.,%o försökte lämna.,%o gitmeye çalıştı.,%o намага@[adj_2_ua] втекти. +%o can't swim.,OB_WATER,,,,%o neumí plavat.,%o kan ikke svømme.,%o kann nicht schwimmen.,@[art_gr] %o δέν μπορεί να κολυμπήσει,%o ne scipovas naĝi.,%o no sabe nadar.,,%o ei osaa uida.,%o ne sait pas nager.,%o nem tud úszni.,%o non sapeva nuotare.,%o は泳げなかった。,%o 은(는) 익사했다.,%o kan niet zwemmen.,%o kan ikke svømme.,%o nie umie pływać.,%o não sabe nadar.,,%o nu poate înota.,Игрок %o не умел плавать.,%o не може да плива.,%o kan inte simma.,%o yüzme bilmiyor.,%o не вміє плавати. +%o mutated.,OB_SLIME,,,,%o zmutoval@[ao_cs].,%o muterede.,%o mutierte.,@[art_gr] %o μεταλάχθηκε,%o mutaciis.,%o ha mutado.,%o mutó.,%o mutatoitui.,%o a muté.,%o mutánssá alakult.,%o è mutato.,%o は変異した。,%o 은(는) 돌연사를 당했다.,%o muteerde.,%o muterte.,%o zmutował@[ao_pl].,%o sofreu mutação.,,%o a avut parte de o mutație.,Игрок %o мутировал.,%o је мутиран@[adj_1_sr].,%o muterade.,%o mutasyona uğradı.,%o мутува@[adj_1_ua]. +%o melted.,OB_LAVA,,,,%o se rozpustil@[ao_cs].,%o smeltede.,%o schmolz.,@[art_gr] %o έλειοσε,%o fandiĝis.,%o se ha fundido.,%o se fundió.,%o suli.,%o a fondu.,%o megolvadt.,%o si è sciolto.,%o は溶かされた。,%o 은(는) 녹아버렸다.,%o smolt.,%o smeltet.,%o stopił@[ao_pl] się.,%o derreteu.,%o derreteu-se.,%o s-a topit.,Игрок %o расплавился.,%o је отопљен@[adj_1_sr].,%o smälte.,%o eridi.,%o розплави@[adj_2_ua]. +%o went boom.,OB_BARREL,,,,%o udělal@[ao_cs] bum.,%o gik bum.,%o explodierte.,@[art_gr] %o έσκασε,%o eksplodis.,%o ha explotado en mil pedazos.,%o explotó en mil pedazos.,%o poksahti.,%o s'est pété@[e_fr] la face.,%o felrobbant.,%o ha fatto bum.,%o は爆発で吹き飛ばされた。,%o 은(는) 폭사했다.,%o ging boem.,%o gikk i lufta.,%o zrobił@[ao_pl] bum.,%o explodiu.,,%o a explodat.,Игрок %o взорвался.,%o је отиш@[ao_2_sr] бум.,%o blev boom.,%o patladı.,%o вибухну@[adj_1_ua]. +%o stood in the wrong spot.,OB_SPLASH,,,,%o stál@[ao_cs] na špatném místě.,%o stod på det forkerte sted.,%o war am falschen Ort.,@[art_gr] %o έκατσε στο λάθος σημείο,%o staris en la malĝusta loko.,%o estaba en el sitio equivocado.,,%o seisoi väärässä paikassa.,%o s'est tenu@[e_fr] au mauvais endroit.,%o rossz helyre állt.,%o si è trovato nel posto sbagliato.,%o はいけない場所に立っていた。,%o 은(는) 위험한 곳에 서 있었다.,%o stond op de verkeerde plek.,%o sto på feil sted.,%o stan@[irreg_2_pl] w złym miejscu.,%o ficou no lugar errado.,,%o a stat în locul nepotrivit.,Игрок %o стоял в неверной точке.,%o је стаја@[ao_1_sr] на погрешно место.,%o stod på fel plats.,%o yanlış yerde durdu.,%o бу@[adj_1_ua] не в тому місці. +%o should have stood back.,OB_R_SPLASH,,,,%o měl@[ao_cs] stát o trochu dál.,%o skulle have stået tilbage.,%o hätte Abstand halten sollen.,@[art_gr] %o έπρεπε να είχε κάτσι πίσω,%o devintus forstarinta.,%o debería haberse apartado.,,%o oli liian likellä.,%o aurait dû garder ses distances.,%o túl közel állt.,%o si sarebbe dovuto allontanare.,%o は後ろへ引くべきだった。,%o 은(는) 좀 더 떨어져야만 했다.,%o had afstand moeten houden.,%o burde ha stått tilbake.,%o nie ustąpił@[ao_pl] na bok.,%o deveria ter se afastado.,,%o ar fi trebuit să stea deoparte.,Игрок %o не отступил в сторону.,Играчу %o је требало да стоји назад.,%o borde ha stått tillbaka.,%o geri çekilmeliydi.,%o треба було відійти подалі. +%o should have stood back.,OB_ROCKET,,,,%o měl@[ao_cs] stát o trochu dál.,%o skulle have stået tilbage.,%o hätte Abstand halten sollen.,@[art_gr] %o έπρεπε να είχε κάτσι πίσω,%o devintus forstarinta.,%o debería haberse apartado.,,%o oli liian likellä.,%o aurait dû garder ses distances.,%o túl közel állt.,%o si sarebbe dovuto allontanare.,%o は後ろへ引くべきだった。,%o 은(는) 더 멀리 떨어져야만 했다.,%o had afstand moeten houden.,%o burde ha stått tilbake.,%o nie ustąpił@[ao_pl] na bok.,%o deveria ter se afastado.,,%o ar fi trebuit să stea deoparte.,Игрок %o не отступил в сторону.,Играчу %o је требало да стоји назад.,%o borde ha stått tillbaka.,%o geri çekilmeliydi.,%o треба було відійти подалі. +%o killed %hself.,OB_KILLEDSELF,,,,%o se zabil@[ao_cs].,%o begik selvmord.,%o tötete sich selbst.,@[art_gr] %o αυτοκτόνησε,%o mortigis sin.,%o se ha matado a sí mism@[ao_esp].,%o se mató a sí mism@[ao_esp].,%o tappoi itsensä.,%o s'est tué@[e_fr].,%o megölte magát.,%o ha ucciso se stesso.,%o は自滅した。,%o 은(는) 자멸했다.,%o bracht zichzelf om.,%o begår selvmord.,%o zabił@[ao_pl] się.,%o se matou.,%o matou-se,%o s-a sinucis.,Игрок %o убил себя.,%o је уби@[ao_1_sr] себе.,%o tog livet av sig.,%o kendini öldürdü.,%o вби@[adj_1_ua] себе. +%o was killed by the power of voodoo.,OB_VOODOO,,,,%o byl@[ao_cs] zabit@[ao_cs] sílou voodoo.,%o blev dræbt af voodooens magt.,%o wurde durch Voodoo getötet.,@[art_gr] %o πέθανε απο τη δύναμη του βουντου,%o estis mortigita de la povo de voduo.,A %o l@[ao_esp] ha matado el poder del vudú.,A %o l@[ao_esp] mató el poder del vudú.,%o kuoli voodoon voimasta.,%o a succombé au pouvoir du Vaudou.,%o meghalt a voodoo erejének köszönhetően.,%o è stato ucciso dalla potenza del voodoo.,%o はブードゥー人形で殺された。,%o 은(는) 부두 마법의 저주를 받았다.,%o werd gedood door de kracht van voodoo.,%o ble drept av voodooens kraft.,%o umarł@[ao_pl] od mocy voodoo.,%o morreu pelo poder do voodoo.,,%o a fost omorât prin puterea voodoo.,Игрок %o убит силой Вуду.,%o је убијен@[adj_1_sr] од стране моћи Voodoo-а.,%o dödades av voodoo-kraften.,%o voodoo'nun gücü tarafından öldürüldü.,%o вбито силою вуду. +%o was telefragged by %k.,OB_MPTELEFRAG,,,,%o byl@[ao_cs] telefraggnut %kem.,%o blev telefragged af %k.,%o stand %k im Wege.,@[art_gr] %o κοματιάστηκε μέσω τηλεμεταφοράς απο τον/την %k,%o estis teleportumita de %k.,A %o l@[ao_esp] ha telefragmentado %k.,A %o l@[ao_esp] telefragmentó %k.,%k telefräggäsi %o paran.,%o a été téléfragué@[e_fr] par %k.,%o telefrag-et kapott %k által.,%o è stato telefraggato da %k.,%o は %k にテレフラグされた。,%o 은(는) %k 에 의해 텔레프랙을 당했다.,%o werd getelefragged door %k.,%o ble telefragget av %k.,%o został@[ao_pl] ztelefragowan@[adj_pl] przez %k.,%o foi telefragad@[ao_ptb] por %k.,,%o a fost omorât prin teleportare de către %k.,Игрок %o стал жертвой телепортации игрока %k.,%o је телефрагован@[adj_1_sr] од стране %k.,%o blev telefragged av %k.,"%o, %k tarafından telefrag edildi.",%o телефрагнуто %k. +%o was telefragged.,OB_MONTELEFRAG,,,,%o byl@[ao_cs] telefraggnut@[ao_cs].,%o blev telefragged.,%o stand jemandem im Wege.,@[art_gr] %o κοματιάστηκε μέσω τηλεμεταφοράς,%o estis teleportumita.,A %o l@[ao_esp] han telefragmentado.,A %o l@[ao_esp] telefragmentaron.,%o telefrägättiin.,%o a été téléfragué@[e_fr].,%o telefraggelve lett.,%o si è fatto telefraggare.,%o はテレフラグされた。,%o 은(는) 텔레프랙을 당했다.,%o werd getelefragged.,%o ble telefragget.,%o został@[ao_pl] ztelefragowan@[adj_pl].,%o foi telefragad@[ao_ptb] por um monstro.,,%o a fost omorât prin teleportare.,Игрок %o стал жертвой телепортации.,%o је телефрагован@[adj_1_sr].,%o blev telefragged.,%o telefragged edildi.,%o вбито телепортом. +%o died.,OB_DEFAULT,,,,"%o zemřel@[ao_cs]. +",%o døde.,%o ist gestorben.,@[art_gr] %o πέθανε,%o mortis.,%o ha muerto.,%o murió.,%o kuoli.,%o est mort@[e_fr].,%o meghalt.,%o è morto.,%o は死亡した。,%o 은(는) 죽었다.,%o ging dood.,%o døde.,%o umarł@[ao_pl].,%o morreu.,,%o a murit.,Игрок %o погиб.,%o је умр@[ao_1_sr].,%o dog.,%o öldü.,%o помер@[adj_3_ua]. +%o was killed by %k.,OB_MPDEFAULT,,,,%o byl@[ao_cs] zabit@[ao_cs] hráčem %k.,%o blev dræbt af %k.,%o wurde von %k getötet.,@[art_gr] %o στοτώθηκε απο τον/την %k,%o estis mortigita de %k.,A %o l@[ao_esp] ha matado %k.,A %o l@[ao_esp] mató %k.,%k tappoi %o paran.,%o a été tué@[e_fr] par %k.,%k megölte %o-t.,%o è stato ucciso da %k,%o は %k によって殺された。,%o 은(는) %k 에 의해 죽임을 당했다.,%o werd gedood door %k.,%o ble drept av %k.,%o został@[ao_pl] zabit@[adj_pl] przez %k.,%o foi mort@[ao_ptb] por %k.,,%o a fost omorât de către %k.,Игрока %o убил игрок %k.,Играча %o је уби@[ao_1_sr] %k.,%o dödades av %k.,"%o, %k tarafından öldürüldü.",%o вбито гравцем %k. +%k mows down a teammate.,OB_FRIENDLY1,,,,%o rozsekal@[ao_cs] spoluhráče.,%k mejer en holdkammerat ned.,%o wurde von einem Teamkameraden niedergestreckt.,Ο/Η %k σκότωσε έναν σύμαχο,%k buĉas teamanon.,%k ha acribillado a un compañero.,%k acribilló a un compañero.,%k niitti joukkuetoverin.,%k élimine un de ses équipiers.,%k lekaszabolta a csapattársát.,%k falcia via un compagno.,%k は仲間を無慈悲に殺した。,%o 은(는) 자신의 팀원을 죽였다.,%k maait een teamgenoot neer.,%k meier ned en lagkamerat.,%k kosi kompana.,%k matou um colega de equipe.,%k matou um companheiro de equipa.,%k face pulbere pe un coechipier.,Игрок %k сбивает союзника.,%k је обори@[ao_1_sr] саиграча.,%k mejar ner en lagkamrat.,%k bir takım arkadaşını biçti.,%k скоси@[adj_1_ua] соратника. +%k seems to need glasses.,OB_FRIENDLY2,English was changed to remove problematic pronoun referencing the killer,,,%k nejspíš potřebuje brýle.,%k har tilsyneladende brug for briller.,%k sollte eine Brille benutzen.,Ο/Η %k φαίνεται να χρειάζετε γυαλία,%o ŝajnas bezoni okulvitrojn.,%k parece necesitar gafas.,%k parece necesitar lentes.,%k näyttää tarvitsevan laseja.,%k vérifie ses lunettes.,%k-nak szemüvegre van szüksége.,%k sembra che abbia bisogno di occhiali.,%k には眼鏡が必要なようだ。,%o 은(는) 자신의 안경을 확인했다.,%k lijkt een bril nodig te hebben.,%k ser ut til å trenge briller.,%k wydaje się potrzebować okularów.,%k parece que precisa de óculos.,,%k pare să aibă nevoie de ochelari.,Игроку %k следует носить свои очки.,Играчу %k би приличиле наочаре.,%k verkar behöva glasögon.,%k net göremiyor,"Схоже, що %k потрібні окуляри." +%k gets a frag for the other team.,OB_FRIENDLY3,,,,%k dostal@[ao_cs] frag pro další tým.,%k får en fragment til det andet hold.,%k macht für das andere Team einen Punkt.,Ο/Η %k πάιρνει έναν κοματιασμό για την άλλη ομάδα.,%k gajnas ludmurdon por la alia teamo.,%k ha marcado una baja para el otro equipo.,%k marcó una baja para el otro equipo.,%k teki frägin vieraalle joukkueelle.,%k marque un point pour l'autre équipe.,%k szerez egy frag-et a másik csapatnak.,%k regala un frag all'altro team.,%k は敵チームに得点を入れた。,%o 은(는) 의도치 않게 상대방 팀을 도왔다.,%k doet een frag voor het andere team.,%k får en frag for det andre laget.,%k zdobywa fraga dla przeciwnej drużyny.,%k dá um frag para o outro time.,%k dá um frag para a outra equipa.,%k face o victimă pentru echipa adversă.,Игрок %k преподнёс другой команде фраг.,%k осваја фраг за други тим.,%k får ett frag till det andra laget.,%k diğer takım için bir parça aldı.,%k відда@[adj_1_ua] фраг іншій команді. +%k loses another friend.,OB_FRIENDLY4,,,,%k ztratil@[ao_cs] dalšího přítele.,%k mister endnu en ven.,%k hat wieder einen Freund verloren.,Ο/Η %k χάνει ακόμα έναν αλλο φίλο,%k perdis alian amikon.,%k ha perdido a otro amigo.,%k perdió a otro amigo.,%k menetti jälleen ystävän.,%k a perdu un autre ami.,%k elveszít egy másik barátot.,%k perde un altro amico.,%k はまた友達を失った。,%o 은(는) 친구를 원치 않았다.,%k verliest nog een vriend.,%k mister enda en venn.,%k tracil kolejnego przyjaciela.,%k perde mais um amigo.,,%k mai pierde un prieten.,Игрок %k потерял ещё одного друга.,%k је изгуби@[ao_1_sr] још једног пријатеља.,%k förlorar ännu en vän.,%k başka bir arkadaşını kaybetti.,%k втрати@[adj_1_ua] ще одного друга. +,,Pickup,,,,,,,,,,,,,,,,,,,,,,,,,, +Picked up the armor.,GOTARMOR,,,Picked up the armour.,Sebráno brnění.,Hentede rustningen.,Panzer genommen.,Πήρες την πανοπλία.,Vi trovis armaĵon.,Encuentras una armadura.,,Poimit panssarin.,Armure récupérée.,Felvettél egy páncélt.,Raccolto un'armatura.,アーマーを身に着けた。,방호구를 얻었다.,Je hebt het harnas opgepakt.,Plukket opp rustningen.,Zebrano zbroję.,Pegou uma armadura.,Apanhaste uma armadura.,Ai ridicat o armură.,Получена броня.,Покупили сте панцир.,Plockade upp rustningen.,Zırhı aldım.,Взято броню. +Picked up the MegaArmor!,GOTMEGA,,,Picked up the MegaArmour!,Sebráno MegaBrnění!,Hentede Mega-rustningen!,MegaPanzer genommen!,Πήρες την μέγα πανοπλία!,Vi trovis plejan armaĵon!,¡Encuentras una Megaarmadura!,,Poimit megapanssarin!,Méga-Armure récupérée!,Felvettél egy MegaPáncélt!,Raccolto una MegaArmatura!,メガアーマーを身に着けた!,메가아머를 얻었다!,Je hebt het megaharnas opgepakt!,Plukket opp mega rustningen!,Zebrano megazbroję!,Pegou uma Mega-armadura!,Apanhaste uma MegaArmadura.,Ai ridicat o MegaArmură!,Получена мегаброня!,Покупили сте мегапанцир!,Plockade upp mega rustningen!,MegaZırhı aldı!,Взято мегаброню! +Picked up a health bonus.,GOTHTHBONUS,,,,Sebráno bonusové zdraví.,Hentede en sundhedsbonus.,Gesundheitsbonus genommen.,Πήρες ένα bonus υγείας.,Vi trovis aldonan sanon.,Encuentras salud extra.,,Poimit terveyslisän.,Bonus de Santé récupéré.,Felvettél egy életbónuszt.,Raccolto un bonus di salute.,ヘルスボーナスを拾った。,체력 보너스를 얻었다.,Je hebt een gezondheidsbonus opgepakt.,Plukket opp en helsebonus.,Zebrano bonus do zdrowia.,Pegou um bônus de saúde.,Apanhaste um bônus de vida.,Ai ridicat un bonus de sănătate.,Получен бонус к здоровью.,Покупили сте бонус здравља.,Plockade upp en hälsobonus.,Bir sağlık bonusu aldı.,Взято бонус здоров'я. +Picked up an armor bonus.,GOTARMBONUS,,,Picked up an armour bonus.,Sebráno bonusové brnění.,Hentede en rustningsbonus.,Panzerbonus genommen.,Πήρες ένα bonus πανο.πλίας.,Vi trovis aldonan kirason.,Encuentras blindaje extra.,,Poimit panssarilisän.,Bonus d'Armure récupéré.,Felvettél egy páncélbónuszt.,Raccolto un bonus d'armatura.,アーマーボーナスを拾った。,보호 보너스를 얻었다.,Je hebt een harnasbonus opgepakt.,Plukket opp en rustningsbonus.,Zebrano bonus do zbroi.,Pegou um bônus de armadura.,Apanhaste um bônus de armadura.,Ai ridicat un bonus de armură.,Получен бонус к броне.,Покупили сте бонус панцира.,Plockade upp en rustningsbonus.,Bir zırh bonusu aldı.,Взято бонус броні. +Picked up a stimpack.,GOTSTIM,,,,Sebrán stimulant.,Hentede en stimpack.,Stimpack genommen.,Πήρες ένα μικρό πακέτο υγείας.,Vi trovis stimulilo-pakon.,Encuentras un estimulante.,,Poimit piristeruiskeen.,Stimpack récupéré.,Felvettél egy szurit.,Raccolto uno stimpack.,スティムパックを拾った。,스팀팩을 사용했다.,Je hebt een opwekpakket opgepakt.,Plukket opp en stimpack.,Zebrano małą apteczkę.,Pegou um estimulante.,Apanhaste um kit de primeiros socorros.,Ai ridicat un kit de prim-ajutor mic.,Получен стимулятор.,Покупили сте стимпак.,Plockade upp en stimpack.,Bir uyarıcı aldı.,Взято стимулятор. +Picked up a medikit that you REALLY need!,GOTMEDINEED,,,,"Sebrána lékárnička, kterou jsi FAKT potřeboval@[ao_cs].","Hentede en medikit, som du VIRKELIG har brug for!","Medikit genommen, das du WIRKLICH brauchst!",Πήρες πρώτες βοήθειες που χρειαζόσουνα ΠΆΡΑ ΠΟΛΥ!,"Vi trovis sukurkeston, kiun vi VERE bezonas!",¡Encuentras un botiquín que REALMENTE necesitabas!,,"Poimit lääkintälaukun, jota TODELLA tarvitsit!","Médikit récupéré, et vous en aviez vraiment besoin!",Felvettél egy életcsomagot amire NAGYON szükséged volt már!,Hai raccolto un kit medico di cui avevi PROPRIO bisogno!,本当に必要なメディキットを手に入れた!,메디킷을 필요한 순간에 사용했다!,"Je hebt een verbandsdoos, die je ECHT nodig had, opgepakt!",Plukket opp en medikit som du virkelig trenger!,"Zebrano apteczkę, w OSTATNIEJ chwili!","Pegou um kit médico +que você REALMENTE precisava!","Apanhaste um kit médico que estavas MESMO a precisar!","Ai ridicat un kit de prim-ajutor de care CHIAR aveai -nevoie!",Получена крайне необходимая аптечка!,Покупили сте медикит који вам је СТВАРНО потребан! -Picked up a medikit.,GOTMEDIKIT,,,,Sebrána lékárnička.,Medikit genommen.,Πήρες πρώτες βοήθειες.,Prenis sukurkeston.,Recogiste un botiquín.,,Poimit lääkintälaukun.,Médikit récupéré.,Felvettél egy életcsomagot.,Raccolto un kit medico.,メディキットを拾った。,메디킷을 사용했다.,Je hebt en medikit opgehaald.,Podniesiono apteczkę.,Pegou um kit médico.,Apanhaste um kit médico.,Ai ridicat un kit de prim-ajutor.,Получена аптечка.,Покупили сте медикит. -Supercharge!,GOTSUPER,,,,Superzdraví!,Super-Ladung!,Υπερφόρτοση!,Superŝarĝo!,¡Supercarga!,,Supervaraus!,,Szupertöltés!,Sfera dell'Anima!,スーパーチャージ!,슈퍼차지!,,Supernaładowanie!,Supercarga!,,Superîncărcătură!,Сверхзаряд!,Супернабој! -Picked up a blue keycard.,GOTBLUECARD,,,,Sebrána modrá karta.,Blaue Schlüsselkarte genommen.,Πήρες ένα μπλε κλειδί.,Prenis bluan ŝlosilkarton.,Recogiste una tarjeta de acceso azul.,,Poimit sinisen avainkortin.,Carte d'accès BLEUE récupérée.,Felvettél egy kék kulcskártyát.,Raccolta una card d'accesso blu.,ブルー キーカードを手に入れた。,청색 키카드를 얻었다.,Je hebt een blauwe sleutelkaart opgehaald.,Podniesiono niebieską kartę klucz.,Pegou um cartão de acesso azul.,Apanhaste um cartão de acesso azul.,Ai ridicat un card cheie albastru.,Получена синяя ключ-карта.,Покупили сте плаву кључну карту. -Picked up a yellow keycard.,GOTYELWCARD,,,,Sebrána žlutá karta.,Gelbe Schlüsselkarte genommen.,Πήρες ένα κύτρινο κλειδί.,Prenis flavan ŝlosilkarton.,Recogiste una tarjeta de acceso amarilla.,,Poimit keltaisen avainkortin.,Carte d'accès JAUNE récupérée.,Felvettél egy sárga kulcskártyát.,Raccolta una card d'accesso gialla.,イエローキーカードを手に入れた。,황색 키카드를 얻었다.,Je hebt een gele sleutelkaart opgehaald.,Podniesiono żółtą kartę klucz.,Pegou um cartão de acesso amarelo.,Apanhaste um cartão de acesso amarelo.,Ai ridicat un card cheie galben.,Получена жёлтая ключ-карта,Покупили сте жуту кључну карту. -Picked up a red keycard.,GOTREDCARD,,,,Sebrána červená karta.,Rote Schlüsselkarte genommen.,Πήρες ένα κόκινο κλειδί.,Prenis ruĝan ŝlosilkarton.,Recogiste una tarjeta de acceso roja.,,Poimit punaisen avainkortin.,Carte d'accès ROUGE récupérée.,Felvettél egy piros kulcskártyát.,Raccolta una card d'accesso rossa.,レッド キーカードを手に入れた。,적색 키카드를 얻었다.,Je hebt een rode sleutelkaart opgehaald.,Podniesiono czerwoną kartę klucz.,Pegou um cartão de acesso vermelho.,Apanhaste um cartão de acesso vermelho.,Ai ridicat un card cheie roșu.,Получена красная ключ-карта.,Покупили сте црвену кључну карту. -Picked up a blue skull key.,GOTBLUESKUL,,,,Sebrána modrá lebka.,Blauen Schädel-Schlüssel genommen.,Πήρες ένα μπλε κρανίο.,Prenis bluan kranian ŝlosilon.,Recogiste una llave de calavera azul.,Recogiste una llave de cráneo azul.,Poimit sinisen kalloavaimen.,Clef Crâne BLEUE récupérée.,Felvettél egy kék koponya kulcsot.,Raccolta una chiave-teschio blu.,ブルー スカルキーを手に入れた。,청색 해골열쇠를 얻었다.,Je hebt een blauwe schedelsleutel opgehaald.,Podniesiono niebieską czaszkę.,Pegou uma chave-crânio azul.,Apanhaste uma chave crânio azul.,Ai ridicat o cheie craniu albastră.,Получен синий ключ-череп.,Покупили сте плави кључ лобање. -Picked up a yellow skull key.,GOTYELWSKUL,,,,Sebrána žlutá lebka.,Geben Schädel-Schlüssel genommen.,Πήρες ένα κύτρινο κρανίο.,Prenis flavan kranian ŝlosilon.,Recogiste una llave de calavera amarilla,Recogiste una llave de cráneo amarilla,Poimit keltaisen kalloavaimen.,Clef Crâne JAUNE récupérée.,Felvettél egy sárga koponya kulcsot.,Raccolta una chiave-teschio gialla.,イエロースカルキーを手に入れた。,황색 해골열쇠를 얻었다.,Je hebt een gele schedelsleutel opgehaald.,Podniesiono żółtą czaszkę.,Pegou uma chave-crânio amarela.,Apanhaste uma chave crânio amarela.,Ai ridicat o cheie craniu galbenă.,Получен жёлтый ключ-череп.,Покупили сте жути кључ лобање. -Picked up a red skull key.,GOTREDSKUL,,,,Sebrána červená lebka.,Roten Schädel-Schlüssel genommen.,Πήρες ένα κοκινο κρανίο.,Prenis ruĝan kranian ŝlosilon.,Recogiste una llave de calavera roja.,Recogiste una llave de cráneo roja.,Poimit punaisen kalloavaimen.,Clef Crâne ROUGE récupérée.,Felvettél egy piros koponya kulcsot.,Raccolta una chiave-teschio rossa.,レッド スカルキーを手に入れた。,적색 해골열쇠를 얻었다.,Je hebt een rode schedelsleutel opgehaald.,Podniesiono czerwoną czaszkę.,Pegou uma chave-crânio vermelha.,Apanhaste uma chave crânio vermelha.,Ai ridicat o cheie craniu roșie.,Получен красный ключ-череп.,Покупили сте црвени кључ лобање. -Invulnerability!,GOTINVUL,,,,Nezranitelnost!,Unverwundbarkeit!,Αθανασία!,Nevundebleco!,¡Invulnerabilidad!,,Haavoittumattomuus!,Invulnérabilité!,Sérthetetlenség!,Invulnerabilità!,不死身だ!,무적!,Onkwetsbaarheid!,Niezniszczalność!,Invulnerabilidade!,,Invincibilitate!,Неуязвимость!,Нерањивост! -Berserk!,GOTBERSERK,,,,,,Μανία!,Furiozilo!,¡Berserker!,,Raivo!,,Dühös mód!,,バーサーク!,광전사!,,Szał!,,,Forță amplificată!,Берсерк!,Берсерк! -Partial Invisibility,GOTINVIS,,,,Částečná neviditelnost,Teilweise Unsichtbarkeit,Ημη-αoρατότητα,Parta Nevidebleco,Invisibilidad parcial,,Osittainen näkymättömyys,Invisibilité Partielle,Részleges Láthatatlanság,Invisibilità parziale,半透明化スフィア,일시적 투명 효과!,Gedeeltelijke Onzichtbaarheid,Częściowa niewidzialność,Invisibilidade parcial,,Invizibilitate parțială,Частичная невидимость.,Делимична невидљивост -Radiation Shielding Suit,GOTSUIT,,,,Ochranný oblek proti radioaktivitě,Strahlenschutzanzug.,Προστατευτηκή Στολή,Radiado Ŝildo-Kostumo,Traje anti-radiación,,Säteilysuojapuku,Combinaison Hazmat,Sugárzás Elleni Öltöny,Tuta anti-radiazioni,放射線防護服 ,방사능 보호복,Stralingsafschermingspak,Kombinezon przeciwradiacyjny,Traje anti-radiação,Fato anti-radiação,Costum de protecție împotriva radiaților,Костюм радиационной защиты.,Одело против радијације -Computer Area Map,GOTMAP,,,,Počítačová mapa,Computerkarte.,Τοπικός Χάρτης,Komputila Area Mapo,Mapa computarizado de área,,Alueen tietokonekartta,Carte Informatique,Térkép,Mappa Completata,コンピューターエリアマップ,구역 지도 컴퓨터,Computer kaart.,Komputerowa mapa obszaru,Mapa completo,,Hartă completă,Компьютерная карта уровня.,Компјутерска мапа нивоа -Light Amplification Visor,GOTVISOR,,,,Noktovizor,Lichtverstärkungsgerät,Νυχτερινή Όραση,Vizilo de Luma Amplifikado,Visor de amplificación de luz,,Valonvahvistusvisiiri,Lunettes de Vision Nocturne,Fény Felerősítő Sisak,Amplificatore di luce,"暗視バイザー -",야간투시 바이저,Lichtversterkingsvizier,Gogle noktowizyjne,Visor de amplificação de luz,Visor de amplificação luminosa,Vedere amplificată,Очки ночного видения.,Ноћни визир -MegaSphere!,GOTMSPHERE,,,,MegaSféra!,MegaSphäre!,Μεγασφαίρα!,MegaSfero!,¡Megaesfera!,,Megakuula!,Mégasphère!,MegaGömb!,MegaSfera!,メガスフィアー!,메가스피어!,,Megasfera!,MegaEsfera!,,Megasferă!,Мегасфера!,Мегасфера! -Picked up a clip.,GOTCLIP,,,,Sebrán zásobník.,Magazin genommen.,Πήρες ένα κουτάκι σφαιρών.,Prenis municion klipon.,Recogiste un cargador.,,Poimit lippaan.,Chargeur récupéré.,Felvettél egy töltényt.,Raccolto un caricatore.,弾倉を拾った。,탄창을 얻었다.,Je hebt een clip opgehaald.,Podniesiono magazynek.,Pegou um carregador.,Apanhaste um carregador,Ai ridicat un cartuș.,Получен магазин.,Покупили сте оквир. -Picked up a box of bullets.,GOTCLIPBOX,,,,Sebrána krabice s kulkami.,Kiste mit Pistolenkugeln genommen.,Πήρες ένα κουτί με σφαίρες.,Prenis skatolon da kugloj.,Recogiste una caja de balas.,,Poimit laatikollisen luoteja.,Boîte de balles récupérée.,Felvettél egy doboznyi töltényt.,Raccolta una scatola di proiettili.,弾薬箱を拾った。,실탄 탄통을 얻었다.,Je hebt een doos kogels opgehaald.,Podniesiono pudełko z nabojami.,Pegou uma caixa de balas.,Apanhaste uma caixa de balas,Ai ridicat o cutie cu gloanțe.,Получена коробка патронов.,Покупили сте кутију метака. -Picked up a rocket.,GOTROCKET,,,,Sebrána raketa.,Rakete genommen,Πήρες ένα πύραυλο.,Prenis raketon.,Recogiste un cohete.,,Poimit raketin.,Roquette récupérée.,Felvettél egy rakétát.,Raccolto un razzo.,ロケットを拾った。,로켓을 얻었다.,Je hebt een raket opgepikt.,Podniesiono rakietę.,Pegou um foguete.,Apanhaste um míssil,Ai ridicat o rachetă.,Получена ракета.,Покупили сте ракету. -Picked up a box of rockets.,GOTROCKBOX,,,,Sebrána krabice s raketami.,Kiste mit Raketen genommen.,Πήρες ένα κουτί με πυράυλους.,Prenis skatolon da raketoj.,Recogiste una caja de cohetes.,,Poimit laatikollisen raketteja.,Caisse de roquettes récupérée.,Felvettél egy doboznyi rakétát.,Raccolta una cassa di razzi.,ロケット箱を拾った。,로켓 상자를 얻었다.,Je hebt een doos raketten opgehaald.,Podniesiono pudełko z rakietami.,Pegou uma caixa de foguetes.,Apanhaste uma caixa de mísseis,Ai ridicat o cutie cu rachete.,Получен ящик ракет.,Покупили сте кутију ракета. -Picked up an energy cell.,GOTCELL,,,,Sebrán energetický článek.,Energiezelle genommen.,Πήρες ένα κύτταρο ενέργιας.,Prenis energiĉelon.,Recogiste una célula de energía.,,Poimit energia-akun.,Cellule énergétique récupérée.,Felvettél egy energia cellát.,Raccolta una batteria.,エネルギーセルを拾った。,에너지 셀을 얻었다.,Je hebt een energiecel opgepikt.,Podniesiono ogniwo energetyczne.,Pegou uma célula de energia.,Apanhaste uma célula de energia,Ai ridicat o celulă cu energie.,Получена энергобатарея.,Покупили сте енергетску ћелију. -Picked up an energy cell pack.,GOTCELLBOX,,,,Sebrán svazek energetických článků.,Energiezellenpackung genommen.,Πήρες ένα πακέτο κύτταρων ενέργιας.,Prenis energiĉelon pakon.,Recogiste un pack de células de energía.,,Poimit energia-akkupaketin.,Pack de cellules énergétiques récupéré.,Felvettél egy doboznyi energia cellát.,Raccolta una confezione di batterie.,エネルギーセルパックを拾った。,대용량 에너지 셀을 얻었다.,Je hebt een energiecelpakket opgehaald.,Podniesiono paczkę ogniw energetycznych.,Pegou um pacote de células de energia.,Apanhaste um pacote de células de energia.,Ai ridicat un pachet de celule cu energie.,Получен энергоаккумулятор.,Покупили сте паковање енергетских ћелија. -Picked up 4 shotgun shells.,GOTSHELLS,,,,Sebrány 4 broky.,4 Schrotflintenpatronen genommen,Πήρες τέσσερεις σφάιρες ντουγεκιόυ.,Prenis 4 kartoĉojn.,Recogiste 4 cartuchos de escopeta.,,Poimit 4 haulikon patruunaa.,4 cartouches récupérées.,Felvettél 4 sörétes töltényt.,Raccolte 4 cartucce per fucile.,4発の散弾を拾った。,샷건 쉘 4개를 얻었다.,Je hebt 4 jachtgeweer schelpen opgehaald.,Podniesiono 4 loftki do strzelby.,Pegou 4 cartuchos de espingarda.,Apanhaste 4 cartuchos de espingarda.,Ai ridicat 4 proiectile pentru pușcă.,Получено 4 патрона для дробовика.,Покупили сте 4 патроне од пумпарице. -Picked up a box of shotgun shells.,GOTSHELLBOX,,,,Sebrána krabice s broky.,Kiste mit Schrotflintenpatronen genommen.,Πήρες ένα κουτί με σφάιρες ντουγεκιόυ.,Prenis skatolon da kartoĉoj.,Recogiste una caja de cartuchos de escopeta.,,Poimit laatikollisen haulikon patruunoita.,Boîte de cartouches récupérée.,Felvettél egy doboznyi sörétes töltényt.,Raccolta una scatola di cartucce per fucile.,散弾箱を拾った。,샷건 쉘 보관함을 얻었다.,Je hebt een doos jachtgeweer schelpen opgehaald.,Podniesiono pudełko loftek do strzelby.,Pegou uma caixa de cartuchos de espingarda.,Apanhaste uma caixa de cartuchos de espingarda,Ai ridicat o cutie cu proiectile pentru pușcă.,Получена коробка патронов для дробовика.,Покупили сте кутију патрона од пумпарице. -Picked up a backpack full of ammo!,GOTBACKPACK,,,,Sebrán batoh s haldou munice!,Rucksack mit Munition genommen.,Πήρες μια τσάντα γεμάτη με πυρομαχικά!,Prenis tornistron plenan da municioj!,¡Recogiste una mochila llena de munición!,,Poimit repun täynnä ammuksia!,Sac à dos plein de munitions récupéré!,Felvettél egy hátizsákot tele tölténnyel!,Raccolto uno zaino zeppo di munizioni!,弾薬の入ったバックパックを手に入れた!,탄약이 들어있는 배낭을 얻었다!,Je hebt een rugzak vol munitie opgehaald!,Podniesiono plecak pełen amunicji!,Pegou uma mochila cheia de munição!,Apanhaste uma mochila cheia de munição,Ai ridicat o raniță plină cu muniție!,"Получен рюкзак, полный патронов!",Покупили сте ранац с патронама! -"You got the BFG9000! Oh, yes.",GOTBFG9000,,,,"Sebráno BFG9000! Ó, ano!","Das BFG9000! Oh, ja!","Πήρες το BFG9000! ο, ΝΑΊ.","Vi ricevis la BFG9000! Ho, jes.","¡Obtuviste la BFG9000! Oh, sí.",,Sait BFG9000:n! Voi kyllä.,"UN BFG9000! OH, OUI!",Felvetted a BFG9000-et! Ezaz!,"Hai trovato il BFG9000! Eh, sì!",BFG9000を手に入れた!やったぜ。,당신은 BFG9000을 습득했다! 오우 예.,"Je hebt de BFG9000! Oh, ja.","Podniesiono BFG9000! O, tak.","Você pegou a BFG! Ah, que delícia!","Apanhaste a BFG9000! Oh, SIM!","Ai pus mâna pe BFG9000! Oh, da.",Получено BFG9000! О да!,"Покупили сте ВЈП9000! О, да." -You got the chaingun!,GOTCHAINGUN,,,,Sebrán kulomet.,Maschinengewehr genommen.,Πήρες το πολυβόλο.,Vi ricevis la maŝinpafilon!,¡Obtuviste la ametralladora!,,Sait Gatling-konekiväärin!,Une MITRAILLEUSE!,Felvetted a golyószórót!,Hai trovato un mitragliatore!,チェーンガンを手に入れた!,당신은 체인건을 습득했다!,Je hebt de machinegeweer!,Podniesiono karabin maszynowy!,Você pegou a metralhadora!,Apanhaste a metrelhadora!,Ai pus mâna pe mitraliera rotativă!,Получен пулемёт!,Покупили сте митраљез! -A chainsaw! Find some meat!,GOTCHAINSAW,,,,Motorová pila! Najdi maso!,Eine Kettensäge. Such mir etwas Fleisch!,Ένα αλυσοπρίονο! Βρες κρέας!,Ĉensegilo! Trovu iom da viando!,¡Una motosierra! ¡Encuentra algo de carne!,,Moottorisaha! Mene etsimään lihaa!,Une TRONCONNEUSE! Viande frâiche!,Egy láncfűrész! Keress néhány húst!,Una motosega! Trova un pò di carne!,チェーンソウだ!肉を寄越せ!,당신은 전기톱을 습득했다! 도륙할 시간!,Een kettingzaag! Vind wat vlees!,Piła łańcuchowa! Znajdź trochę mięsa!,Uma motoserra! Encontre alguma carne!,Uma motoserra! Bora encontrar alguma carne!,O drujbă! Găsește niște carne!,Бензопила! Найди немного мяса!,Тестера! Нађи месо! -You got the rocket launcher!,GOTLAUNCHER,,,,Sebrán raketomet.,Raketenwerfer genommen.,Πήρες το πυραβλοβόλο.,Vi ricevis la raketlanĉilon!,¡Obtuviste el lanzacohetes!,,Sait singon!,Un LANCE-ROQUETTES!,Felvetted a rakétavetőt!,Hai trovato un lanciarazzi!,ロケットランチャーを手に入れた!,당신은 로켓 런쳐를 습득했다!,Je hebt de raketwerper!,Podniesiono wyrzutnię rakiet!,Você pegou um lança-foguetes.,Apanhaste um lança-mísseis!,Ai pus mâna pe lansatorul de rachete!,Получена ракетница!,Покупили сте ракетни бацач! -You got the plasma gun!,GOTPLASMA,,,,Sebrána plazmová puška.,Plasma-Gewehr genommen.,Πήρες το όπλο πλάσματος!,Vi ricevis la plasmo-pafilon!,¡Obtuviste el fusil de plasma!,,Sait plasmapyssyn!,Un FUSIL A PLASMA!,Felvetted a plazma fegyvert!,Hai trovato un fucile al plasma!,プラズマライフルを手に入れた!,당신은 플라즈마 건을 습득했다!,Je hebt het plasmageweer!,Podniesiono karabin plazmowy!,Você pegou o fuzil de plasma!,Apanhaste uma pistola de plasma!,Ai pus mâna pe arma cu plasmă!,Получен плазмомет!,Покупили сте плазма оружје! -You got the shotgun!,GOTSHOTGUN,,,,Sebrána brokovnice.,Schrotflinte genommen.,Πήρες το ντουφέκι!,Vi ricevis la ĉaspafilon!,¡Obtuviste la escopeta!,,Sait haulikon!,Un FUSIL A POMPE!,Felvetted a sörétes puskát!,Hai trovato un fucile!,ショットガンを手に入れた!,당신은 샷건을 습득했다!,Je hebt het jachtgeweer!,Podniesiono strzelbę!,Você pegou a espingarda!,Apanhaste uma espingarda.,Ai pus mâna pe pușcă!,Получен дробовик!,Покупили сте пумпарицу! -You got the super shotgun!,GOTSHOTGUN2,,,,Sebrána superbrokovnice.,Super-Schrotflinte genommen.,Πήρες το διπλό ντουφέκι!,Vi ricevis la superan ĉaspafilon!,¡Obtuviste la súper escopeta!,,Sait superhaulikon!,Un SUPER FUSIL DE CHASSE!,Felvetted a Szuper sörétes puskát!,Hai trovato una doppietta!,スーパーショットガンを手に入れた!,당신은 슈퍼 샷건을 습득했다!,Je hebt de super jachtgeweer!,Podniesiono super strzelbę!,Você pegou uma espingarda de cano duplo!,Apanhaste uma espingarda de cano duplo!,Ai pus mâna pe super pușcă!,Получен супер-дробовик!,Покупили сте двоцевку! -Picked up a pistol.,PICKUP_PISTOL_DROPPED,,,,Sebrána pistole.,Pistole genommen.,Πήρες ενα πιστόλι.,Prenis pistolon.,Recogiste una pistola.,,Poimit pistoolin.,Un PISTOLET.,Felvettél egy pisztolyt.,Raccolta una pistola.,ピストルを拾った。,권총을 주웠다.,Je hebt de pistool.,Podniesiono pistolet.,Pegou uma pistola.,Apanhaste uma pistola.,Ai ridicat un pistol.,Получен пистолет.,Покупили сте пиштољ. -You pick up a demonic dagger.,BETA_BONUS1,,,,Sebrána démonická dýka.,Dämonischen Dolch genommen.,Πήρες ένα δαιμονικό μαχαίρι.,Vi reprenas demonan ponardon.,Recogiste una daga demoníaca.,,Poimit demonisen tikarin.,Dague diabolique récupérée.,Felvettél egy démoni tőrt.,Hai raccolto un pugnale demoniaco.,デモニックダガーを拾った。,당신은 마귀내린 단검을 얻었다.,Je hebt een demonische dolk opgehaald.,Podniesiono demoniczny sztylet.,Você pegou uma adaga demoníaca.,Apanhaste uma navalha demoníaca.,Ai ridicat un pumnal demonic.,Вы подобрали демонический кинжал.,Купите демонски бодеж. -You pick up a skullchest.,BETA_BONUS2,,,,Sebrána lebkotruhla.,Schädelkiste genommen.,Πήρες ένα κρανομπαούλο.,Vi reprenas kranian keston.,Recogiste un cofre de calaveras.,Recogiste un cofre de cráneos.,Poimit kalloarkun.,Coffre-crâne récupéré.,Felvettél egy skullchest-et.,Hai raccolto un cofanetto del teschio.,スカルチェストを拾った。,당신은 해골상자를 얻었다.,Je hebt een schedelborst opgehaald.,Podniesiono skrzynię czaszki.,Você pegou um cofre-caveira.,Apanhaste um cofre caveira.,Ai ridicat o cutie cu craniu.,Вы подобрали сундук с черепом.,Купите ковчег с лобањом. -You pick up an evil sceptre.,BETA_BONUS3,,,,Sebráno zlé žezlo.,Teuflisches Zepter genommen.,Πήρες το μοχθηρό σκήπτρο.,Vi reprenas malbonan sceptron.,Recogiste un cetro del mal.,,Poimit pahan valtikan.,Sceptre maléfique récupéré.,Felvettél egy gonosz jogart.,Hai raccolto uno scettro del male.,エビルセプターを拾った。,당신은 사악한 홀을 얻었다.,Je hebt een kwade scepter opgehaald.,Podniesiono złe berło.,Você pegou um cetro maligno.,Apanhaste um cetro maligno,Ai ridicat un sceptru malefic.,Вы подобрали скипетр зла.,Купите зли скиптар. -You pick up an unholy bible.,BETA_BONUS4,,,,Sebrána bezbožná bible.,Unheilige Bibel genommen,Πήρες τήν ανίερη βίβλο.,Vi reprenas malsanktan biblion.,Recogiste una biblia profana.,,Poimit epäpyhän raamatun.,Bible profane récupérée.,Felvettél egy istentelen bibliát.,Hai raccolto una bibbia profana.,アンホーリーバイブルを拾った。,당신은 불경스러운 성서를 얻었다.,Je hebt een onheilige bijbel opgehaald.,Podniesiono nieświętą biblię.,Você pegou uma bíblia profana.,Apanhaste uma bíblia profana.,Ai ridicat o biblie nesfântă.,Вы подобрали порочную Библию.,Купите несвету библију. -,,Locks,,,,,,,,,,,,,,,,,,,,, -You need a blue key to activate this object,PD_BLUEO,,,,Pro aktivaci tohoto objektu potřebuješ modrý klíč.,"Du brauchst einen blauen Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα μπλέ κλειδί για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas bluan ŝlosilon por aktivigi ĉi tiun objekton,Necesitas una llave azul para activar este objeto,,Tarvitset sinisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé bleue pour activer cet objet.,Egy kék kulcs szükséges az objektum aktiválásához.,Ti serve una chiave blu per attivare questo oggetto,この装置には ブルーキーが必要だ。,이 물체를 작동시키기 위해선 청색 열쇠가 필요합니다,Je hebt een blauwe sleutel nodig om dit object te activeren.,"Potrzebujesz niebieskiego klucza, aby aktywować ten przedmiot",Você precisa de uma chave azul para ativar este objeto,Precisas de uma chave azul para ativar este objeto,"Ai nevoie de o cheie albastră pentru a activa acest -obiect",Для активации нужен синий ключ,Треба вам плави кључ да би активирали овај предмет -You need a red key to activate this object,PD_REDO,,,,Pro aktivaci tohoto objektu potřebuješ červený klíč.,"Du brauchst einen roten Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα κόκινο κλειδί για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas ruĝan ŝlosilon por aktivigi ĉi tiun objekton,Necesitas una llave roja para activar este objeto,,Tarvitset punaisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé rouge pour activer cet objet.,"Piros kulcs kell, hogy aktiválhasd ezt az objektumot.",Ti serve una chiave rossa per attivare questo oggetto,この装置には レッドキーが必要だ。,이 물체를 작동시키기 위해선 적색 열쇠가 필요합니다,Je hebt een rode sleutel nodig om dit object te activeren.,"Potrzebujesz czerwonego klucza, aby aktywować ten przedmiot",Você precisa de uma chave vermelha para ativar este objeto,Precisas de uma chave vermelha para ativar este objeto,"Ai nevoie de o cheie roșie pentru a activa acest -obiect",Для активации нужен красный ключ,Треба вам црвени кључ да би активирали овај предмет -You need a yellow key to activate this object,PD_YELLOWO,,,,Pro aktivaci tohoto objektu potřebuješ žlutý klíč.,"Du brauchst einen gelben Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα κύτρινο κλειδί για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas flavan ŝlosilon por aktivigi ĉi tiun objekton,Necesitas una llave amarilla para activar este objeto,,Tarvitset keltaisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé jaune pour activer cet objet.,Egy sárga kulccsal aktiválható ez az objektum,Ti serve una chiave gialla per attivare questo oggetto,この装置にはイエローキーが必要だ。,이 물체를 작동시키기 위해선 황색 열쇠가 필요합니다,Je hebt een gele sleutel nodig om dit object te activeren.,"Potrzebujesz żółtego klucza, aby aktywować ten przedmiot",Você precisa de uma chave amarela para ativar este objeto,Precisas de uma chave amarela para ativar este objeto,"Ai nevoie de o cheie galbenă pentru a activa acest -obiect",Для активации нужен жёлтый ключ,Треба вам жути кључ да би активирали овај предмет -You need a blue key to open this door,PD_BLUEK,,,,Pro otevření těchto dveří potřebuješ modrý klíč.,"Du brauchst einen blauen Schlüssel, um diese Tür zu öffnen.",Χρειάζεσε ένα μπλέ κλειδί για να ανοίξεις αυτή τη πόρτα,Vi bezonas bluan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave azul para abrir esta puerta,,Tarvitset sinisen avaimen avataksesi tämän oven,Il vous faut une clé bleue pour ouvrir cette porte.,Az ajtót a kék kulcs nyitja.,Ti serve una chiave blu per aprire questa porta,このドアには ブルーキーが必要だ。,이 문을 열기 위해선 청색 열쇠가 필요합니다,Je hebt een blauwe sleutel nodig om deze deur te openen.,"Potrzebujesz niebieskiego klucza, aby otworzyć te drzwi",Você precisa de uma chave azul para abrir essa porta,Precisas de uma chave azul para abrir esta porta,"Ai nevoie de o cheie albastră pentru a deschide -ușa aceasta",Для открытия нужен синий ключ,Треба вам плави кључ да би отворили ова врата -You need a red key to open this door,PD_REDK,,,,Pro otevření těchto dveří potřebuješ červený klíč.,"Du brauchst einen roten Schlüssel, um diese Tür zu öffnen.",Χρειάζεσε ένα κόκινο κλειδί για να ανοίξεις αυτή τη πόρτα,Vi bezonas ruĝan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave roja para abrir esta puerta,,Tarvitset punaisen avaimen avataksesi tämän oven,Il vous faut une clé rouge pour ouvrir cette porte.,"Piros kulcs szükséges, hogy az ajtót kinyithasd.",Ti serve una chiave rossa per aprire questa porta,このドアには レッドキーが必要だ。,이 문을 열기 위해선 적색 열쇠가 필요합니다,Je hebt een rode sleutel nodig om deze deur te openen.,"Potrzebujesz czerwonego klucza, aby otworzyć te drzwi",Você precisa de uma chave vermelha para abrir essa porta,Precisas de uma chave vermelha para abrir esta porta,"Ai nevoie de o cheie roșie pentru a deschide ușa -aceasta",Для открытия нужен красный ключ,Треба вам црвени кључ да би отворили ова врата -You need a yellow key to open this door,PD_YELLOWK,,,,Pro otevření těchto dveří potřebuješ žlutý klíč.,"Du brauchst einen gelben Schlüssel, um diese Tür zu öffnen.",Χρειάζεσε ένα κύτρινο κλειδί για να ανοίξεις αυτή τη πόρτα,Vi bezonas flavan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave amarilla para abrir esta puerta,,Tarvitset keltaisen avaimen avataksesi tämän oven,Il vous faut une clé jaune pour ouvrir cette porte.,Kell egy sárga kulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave gialla per aprire questa porta,このドアには イエローキー が必要だ。,이 문을 열기 위해선 황색 열쇠가 필요합니다,Je hebt een gele sleutel nodig om deze deur te openen.,"Potrzebujesz żółtego klucza, aby otworzyć te drzwi",Você precisa de uma chave amarela para abrir essa porta,Precisas de uma chave amarela para abrir esta porta,"Ai nevoie de o cheie galbena pentru a deschide ușa -aceasta",Для открытия нужен жёлтый ключ,Треба вам жути кључ да би отворили ова врата -You need a blue card to activate this object,PD_BLUECO,,,,Pro aktivaci tohoto objektu potřebuješ modrou kartu.,"Du brauchst eine blaue Schlüsselkarte, um dieses Objekt zu aktivieren.",Χρειάζεσε μια μπλέ κάρτα για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas bluan karton por aktivigi ĉi tiun objekton,Necesitas una tarjeta azul para activar este objeto,,Tarvitset sinisen avainkortin aktivoidaksesi tämän kappaleen,Il vous faut une carte bleue pour activer cet objet.,"Egy kék kártya kell, hogy ezt az objektumot aktiválhasd",Ti serve una card d'accesso blu per attivare questo oggetto ,この装置には ブルーカード が必要だ。,이 물체를 작동시키기 위해선 청색 키카드가 필요합니다,Je hebt een blauwe sleutelkaart nodig om dit object te activeren.,"Potrzebujesz niebieskiej karty, aby aktywować ten obiekt",Você precisa de um cartão de acesso azul para ativar este objeto,Precisas de um cartão de acesso azul para ativar este objeto,"Ai nevoie de un card albastru pentru a activa -acest obiect",Для активации нужен синий ключ,Треба вам плава карта да би активирали овај предмет -You need a red card to activate this object,PD_REDCO,,,,Pro aktivaci tohoto objektu potřebuješ červenou kartu.,"Du brauchst eine rote Schlüsselkarte, um dieses Objekt zu aktivieren.",Χρειάζεσε μια κόκινη κάρτα για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas ruĝan karton por aktivigi ĉi tiun objekton,Necesitas una tarjeta roja para activar este objeto,,Tarvitset punaisen avainkortin aktivoidaksesi tämän kappaleen,Il vous faut une carte rouge pour activer cet objet.,Piros kártyával aktiválható ez az objektum,Ti serve una card d'accesso rossa per attivare questo oggetto ,この装置には レッドカード が必要だ。,이 물체를 작동시키기 위해선 적색 키카드가 필요합니다,Je hebt een rode sleutelkaart nodig om dit object te activeren.,"Potrzebujesz czerwonej karty, aby aktywować ten obiekt",Você precisa de um cartão de acesso vermelho para ativar este objeto,Precisas de um cartão de acesso vermelho para ativar este objeto,"Ai nevoie de un card roșu pentru a activa -acest obiect",Для активации нужен красный ключ,Треба вам црвена карта да би активирали овај предмет -You need a yellow card to activate this object,PD_YELLOWCO,,,,Pro aktivaci tohoto objektu potřebuješ žlutou kartu.,"Du brauchst eine gelbe Schlüsselkarte, um dieses Objekt zu aktivieren.",Χρειάζεσε μια κύτρινη κάρτα για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas flavan karton por aktivigi ĉi tiun objekton,Necesitas una tarjeta amarilla para activar este objeto,,Tarvitset keltaisen avainkortin aktivoidaksesi tämän kappaleen,Il vous faut une carte jaune pour activer cet objet.,Kell egy sárga kártya hogy aktiváld ezt az objektumot.,ti serve una card d'accesso gialla per attivare questo oggetto ,この装置には イエローカード が必要だ。,이 물체를 작동시키기 위해선 황색 키카드가 필요합니다,Je hebt een gele sleutelkaart nodig om dit object te activeren.,"Potrzebujesz żółtej karty, aby aktywować ten obiekt",Você precisa de um cartão de acesso amarelo para ativar este objeto,Precisas de um cartão de acesso amarelo para ativar este objeto,"Ai nevoie de un card galben pentru a activa -acest obiect",Для активации нужен жёлтый ключ,Треба вам жута карта да би активирали овај предмет -You need a blue skull to activate this object,PD_BLUESO,,,,Pro aktivaci tohoto objektu potřebuješ modrou lebku.,"Du brauchst einen blauen Schädel-Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα μπλέ κρανιο για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas bluan kranion por aktivigi ĉi tiun objekton,Necesitas una calavera azul para activar este objeto,Necesitas un cráneo azul para activar este objeto,Tarvitset sinisen kalloavaimen aktivoidaksesi tämän kappaleen,Il vous faut un crâne bleu pour activer cet objet.,Kell egy kék koponya hogy aktiváld ezt az objektumot.,ti serve una chiave-teschio blu per attivare questo oggetto ,この装置には ブルースカル が必要だ。,이 물체를 작동시키기 위해선 청색 해골이 필요합니다,Je hebt een blauwe schedel nodig om dit object te activeren.,"Potrzebujesz niebieskiej czaszki, aby aktywować ten obiekt",Você precisa de uma chave-crânio azul para ativar este objeto,Precisas de uma chave crânio azul para ativar este objeto,"Ai nevoie de un craniu albastru pentru a activa -acest obiect",Для активации нужен синий череп,Треба вам плава лобања да би активирали овај предмет -You need a red skull to activate this object,PD_REDSO,,,,Pro aktivaci tohoto objektu potřebuješ červenou lebku.,"Du brauchst einen roten Schädel-Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα κόκινο κρανιο για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas ruĝan kranion por aktivigi ĉi tiun objekton,Necesitas una calavera roja para activar este objeto,Necesitas un cráneo rojo para activar este objeto,Tarvitset punaisen kalloavaimen aktivoidaksesi tämän kappaleen,Il vous faut un crâne rouge pour activer cet objet.,Kell egy piros koponya hogy aktiváld ezt az objektumot.,ti serve una chiave-teschio rossa per attivare questo oggetto ,この装置には レッドスカル が必要だ。,이 물체를 작동시키기 위해선 적색 해골이 필요합니다,Je hebt een rode schedel nodig om dit object te activeren.,"Potrzebujesz czerwonej czaszki, aby aktywować ten obiekt",Você precisa de uma chave-crânio vermelha para ativar este objeto,Precisas de uma chave crânio vermelha para ativar este objeto,"Ai nevoie de un craniu roșu pentru a activa -acest obiect",Для активации нужен красный череп,Треба вам црвена лобања да би активирали овај предмет -You need a yellow skull to activate this object,PD_YELLOWSO,,,,Pro aktivaci tohoto objektu potřebuješ žlutou lebku.,"Du brauchst einen gelben Schädel-Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα κύτρινο κρανιο για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas flavan kranion por aktivigi ĉi tiun objekton,Necesitas una calavera amarilla para activar este objeto,Necesitas un cráneo amarillo para activar este objeto,Tarvitset keltaisen kalloavaimen aktivoidaksesi tämän kappaleen,Il vous faut un crâne jaune pour activer cet objet.,Kell egy sárga koponya hogy aktiváld ezt az objektumot.,ti serve una chiave-teschio gialla per attivare questo oggetto ,この装置には イエロースカル が必要だ。,이 물체를 작동시키기 위해선 황색 해골이 필요합니다,Je hebt een gele schedel nodig om dit object te activeren.,"Potrzebujesz żółtej czaszki, aby aktywować ten obiekt",Você precisa de uma chave-crânio amarela para ativar este objeto,Precisas de uma chave crânio amarela para ativar este objeto,"Ai nevoie de un craniu galben pentru a activa -acest obiect",Для активации нужен жёлтый череп,Треба вам жута лобања да би активирали овај предмет -You need a blue card to open this door,PD_BLUEC,,,,Pro otevření těchto dveří potřebuješ modrou kartu.,"Du brauchst eine blaue Schlüsselkarte, um diese Tür zu öffnen",Χρειάζεσε μια μπλέ κάρτα για να ανοίξεις αυτή τη πόρτα,Vi bezonas bluan karton por malfermi ĉi tiun pordon,Necesitas una tarjeta azul para abrir esta puerta,,Tarvitset sinisen avainkortin avataksesi tämän oven,Il vous faut une carte bleue pour ouvrir cette porte.,"Egy kék kártya kell, hogy kinyisd ezt az ajtót.",Ti serve una card d'accesso blu per aprire questa porta,このドアには ブルーカード が必要だ。,이 문을 열기 위해선 청색 키카드가 필요합니다,Je hebt een blauwe sleutelkaart nodig om deze deur te openen.,"Potrzebujesz niebieskiej karty, aby otworzyć te drzwi",Você precisa de um cartão de acesso azul para abrir essa porta,Precisas de um cartão de acesso azul para abrir esta porta,"Ai nevoie de un card albastru pentru a activa -această usă",Для активации нужна синяя карта,Треба вам плава карта да би отворили ова врата -You need a red card to open this door,PD_REDC,,,,Pro otevření těchto dveří potřebuješ červenou kartu.,"Du brauchst eine rote Schlüsselkarte, um diese Tür zu öffnen",Χρειάζεσε μια κόκινη κάρτα για να ανοίξεις αυτή τη πόρτα,Vi bezonas ruĝan karton por malfermi ĉi tiun pordon,Necesitas una tarjeta roja para abrir esta puerta,,Tarvitset punaisen avainkortin avataksesi tämän oven,Il vous faut une carte rouge pour ouvrir cette porte.,Piros kártya nyitja ezt az ajtót.,Ti serve una card d'accesso rossa per aprire questa porta,このドアには レッドカード が必要だ。,이 문을 열기 위해선 적색 키카드가 필요합니다,Je hebt een rode sleutelkaart nodig om deze deur te openen.,"Potrzebujesz czerwonej karty, aby otworzyć te drzwi",Você precisa de um cartão de acesso vermelho para abrir essa porta,Precisas de um cartão de acesso vermelho para abrir esta porta,"Ai nevoie de un card galben pentru a activa -această ușă",Для активации нужна красная карта,Треба вам црвена карта да би отворили ова врата -You need a yellow card to open this door,PD_YELLOWC,,,,Pro otevření těchto dveří potřebuješ žlutou kartu.,"Du brauchst eine gelbe Schlüsselkarte, um diese Tür zu öffnen",Χρειάζεσε μια κύτρινη κάρτα για να ανοίξεις αυτή τη πόρτα,Vi bezonas flavan karton por malfermi ĉi tiun pordon,Necesitas una tarjeta amarilla para abrir esta puerta,,Tarvitset keltaisen avainkortin avataksesi tämän oven,Il vous faut une carte jaune pour ouvrir cette porte.,Ez az ajtó a sárga kártyával nyílik.,Ti serve una card d'accesso gialla per aprire questa porta,このドアには イエローカード が必要だ。,이 문을 열기 위해선 황색 키카드가 필요합니다,Je hebt een gele sleutelkaart nodig om deze deur te openen.,"Potrzebujesz żółtej karty, aby otworzyć te drzwi",Você precisa de um cartão de acesso amarelo para abrir essa porta,Precisas de um cartão de acesso amarelo para abrir esta porta,"Ai nevoie de un card galben pentru a activa -această ușă",Для активации нужна желтая карта,Треба вам жута карта да би отворили ова врата -You need a blue skull to open this door,PD_BLUES,,,,Pro otevření těchto dveří potřebuješ modrou lebku.,"Du brauchst einen blauen Schädel-Schlüssel, um diese Tür zu öffnen",Χρειάζεσε ένα μπλέ κρανίο για να ανοίξεις αυτή τη πόρτα,Vi bezonas bluan kranion por malfermi ĉi tiun pordon,Necesitas una calavera azul para abrir esta puerta,Necesitas un cráneo azul para abrir esta puerta,Tarvitset sinisen kalloavaimen avataksesi tämän oven,Il vous faut un crâne bleu pour ouvrir cette porte.,Kék koponya nyitja ezt az ajtót.,Ti serve una chiave-teschio blu per aprire questa porta,このドアには ブルースカル が必要だ。,이 문을 열기 위해선 청색 해골이 필요합니다,Je hebt een blauwe schedel nodig om deze deur te openen.,"Potrzebujesz niebieskiej czaszki, aby otworzyć te drzwi",Você precisa de uma chave-crânio azul para abrir essa porta,Precisas de uma chave crânio azul para abrir esta porta,"Ai nevoie de un craniu albastru pentru a activa -această ușă",Для активации нужен синий череп,Треба вам плава лобања да би отворили ова врата -You need a red skull to open this door,PD_REDS,,,,Pro otevření těchto dveří potřebuješ červenou lebku.,"Du brauchst einen roten Schädel-Schlüssel, um diese Tür zu öffnen",Χρειάζεσε ένα κόκινο κρανίο για να ανοίξεις αυτή τη πόρτα,Vi bezonas ruĝan kranion por malfermi ĉi tiun pordon,Necesitas una calavera roja para abrir esta puerta,Necesitas un cráneo rojo para abrir esta puerta,Tarvitset punaisen kalloavaimen avataksesi tämän oven,Il vous faut un crâne rouge pour ouvrir cette porte.,"Egy piros koponya szükséges, hogy kinyisd ezt az ajtót.",Ti serve una chiave-teschio rossa per aprire questa porta,このドアには レッドスカル が必要だ。,이 문을 열기 위해선 적색 해골이 필요합니다,Je hebt een rode schedel nodig om deze deur te openen.,"Potrzebujesz czerwonej czaszki, aby otworzyć te drzwi",Você precisa de uma chave-crânio vermelha para abrir essa porta,Precsias de uma chave crânio vermelha para abrir esta porta,"Ai nevoie de un craniu roșu pentru a activa -această ușă",Для активации нужен красный череп,Треба вам црвена лобања да би отворили ова врата -You need a yellow skull to open this door,PD_YELLOWS,,,,Pro otevření těchto dveří potřebuješ žlutou lebku.,"Du brauchst einen gelben Schädel-Schlüssel, um diese Tür zu öffnen",Χρειάζεσε ένα κύτρινο κρανίο για να ανοίξεις αυτή τη πόρτα,Vi bezonas flavan kranion por malfermi ĉi tiun pordon,Necesitas una calavera amarillo para abrir esta puerta,Necesitas un cráneo amarillo para abrir esta puerta,Tarvitset keltaisen kalloavaimen avataksesi tämän oven,Il vous faut un crâne jaune pour ouvrir cette porte.,Ezt az ajtót egy sárga koponya nyitja.,Ti serve una chiave-teschio gialla per aprire questa porta,このドアには イエロースカル が必要だ。,이 문을 열기 위해선 황색 해골이 필요합니다,Je hebt een gele schedel nodig om deze deur te openen.,"Potrzebujesz żółtej czaszki, aby otworzyć te drzwi",Você precisa de uma chave-crânio amarela para abrir essa porta,Precisas de uma chave crânio amarela para abrir esta porta,"Ai nevoie de un craniu galben pentru a activa -această ușă",Для активации нужен жёлтый череп,Треба вам жута лобања да би отворили ова врата -,,Cast call names,,,,,,,,,,,,,,,,,,,,, -Zombieman,CC_ZOMBIE,,,,Zombík,Zombie,Ζόμπι,Zombiviro,Zombi,,Zombimies,Zombie,Zombi,Zombie Marine,ゾンビ兵,좀비맨,Zombie,Zombie,Fuzileiro Possuído,Homem Zombie,Zombi,Зомби,Зомби -Shotgun Guy,CC_SHOTGUN,,,,Seržant,Schütze,Τύπος με ντουφέκι,Ĉaspafilisto,Tipo de Escopeta,Tipo de la escopeta,Haulikkohemmo,Type au Fusil,Őrmester,Zombie Sergente,ショットガンゾンビ,샷건 가이,Jachtgeweer kerel,Zombie-sierżant,Sargento Possuído,Tipo de Espingarda,Pușcaș,Зомби-сержант,Пумпераш -Heavy Weapon Dude,CC_HEAVY,,,,Kulometčík,MG-Schütze,Τύπος με βαρί όπλο,Maŝinpafilisto,Tipo de Armas Pesadas,Ametrallador,Raskasaseäijä,Type au Gros Flingue,Gépágyús pasas,Zombie Commando,ヘビーウェポンゾンビ,헤비 웨폰 듀드,Zware wapens kerel,Ciężkozbrojny Zombie,Comando Possuído,Gajo das Armas Pesadas,Tip cu Armă Grea,Пулемётчик,Митраљезац -Imp,CC_IMP,,,,Čertík,Kobold,Διάβολος,Diableto,,,Piru,Diablotin,Kobold,Imp,インプ,임프,,Chochlik,Diabrete,,Drac,Имп,Враг -Demon,CC_DEMON,,,,Démon,Dämon,Δαίμονας,Demono,Demonio,,Demoni,Démon,Démon,Demone,デーモン,데몬,,Demon,Demônio,,Demon,Демон,Демон -Lost Soul,CC_LOST,,,,Ztracená duše,Verlorene Seele,Χαμένη Ξυχή,Perdita Animo,Alma perdida,,Kadonnut sielu,Ame Perdue,Elveszett lélek,Anima Errante,ロストソウル,로스트 소울,Verloren ziel,Zagubiona Dusza,Alma Perdida,Alma Penada,Suflet Pierdut,Потерянная душа,Изгубљена душа -Cacodemon,CC_CACO,,,,Kakodémon,Cacodämon,Κακοδαίμονας,Kakodemono,Cacodemonio,,Kakodemoni,Cacodémon,Kakodémon,Cacodemone,カコデーモン,카코데몬,,Kakodemon,Cacodemônio,,Cacodemon,Какодемон,Какодемон -Hell Knight,CC_HELL,,,,Pekelný rytíř,Höllenritter,Ιππότης της Κόλασης,Inferkavaliro,Caballero del Infierno,,Hornanritari,Chevalier Infernal,Pokollovag,Cavaliere Infernale,ヘルナイト,헬 나이트,Hel Ridder,Rycerz Piekła,Guarda Infernal,Cavaleiro Infernal,Cavaler al Infernului,Рыцарь Ада,Витез пакла -Baron of Hell,CC_BARON,,,,Baron pekel,Höllenbaron,Βαρώνος της Κολασης,Barono de Infero,Barón del Infierno,,Hornanparoni,Baron des Enfers,Pokolbáró,Barone Infernale,バロンオブヘル,바론 오브 헬,Baron van de Hel,Baron Piekła,Barão do Inferno,,Baron al Infernului,Барон Ада,Барон пакла -Arachnotron,CC_ARACH,,,,,,Αράχνοτρον,Elektronaraneo,Aracnotrón,,Araknotroni,Arachnotron,,Arachnotron,アラクノトロン,아라크노트론,,Arachnotron,,,Aracnotron,Арахнотрон,Паукотрон -Pain Elemental,CC_PAIN,,,,Elementál bolesti,Elementarschmerz,Στοιχείομα του Πόνου,Doloro-Elementulo,Elementar del dolor,,Kivun henki,Elémentaire de Douleur,Elemi Kín,Elementale del Dolore,ペインエレメンタル,페인 엘리멘탈,Pijn Elementair,Elemental Bólu,Elemental da Dor,,Elemental al Durerii,Элементаль боли,Елементал патње -Revenant,CC_REVEN,,,,Umrlec,Wiederauferstandener,Εκδικητής,Renaskitulo,Renacido,,Henkiinpalannut,Revenant,Kísértet,Revenant,レバナント,레버넌트,Wraakzuchtiger,Zjawa,Insepulto,Renascido,Nemort,Ревенант,Повратник -Mancubus,CC_MANCU,,,,Mankubus,,Χοντρός,Mankubo,,,Mankubus,Mancube,,Mancubus,マンキュバス,맨큐버스,,Mankubus,,,Mancubus,Манкубус,Манкубус -Arch-Vile,CC_ARCH,,,,Veleběs,Scheusal,Νεκρομάντις,Ĉefaĉbesto,Arch-Vile,,Arkkihirvitys,Arche-vile,Ősálnok,Arch-vile,アーチバイル,아크-바일,,Arcy-Bestia,,,Cel Abject,Арчвайл,Арчвајл -The Spider Mastermind,CC_SPIDER,,,,Pavoučí vojevůdce,Der Spinnenmeister,Το Αραχνό Ιθύνων Νους,Elektronaraneo-Mastro,Mente-Maestra Arácnida,,Hämähäkkiaivot,L'Araignée Commandante,A Pókvezér,L'Aracnomente Suprema,スパイダーマスターマインド,스파이더 마스터마인드,Het Spin Meesterbrein,Pajęczy Mistrz,A Aranha-Mestra,,Păianjen Maestru,Паук-предводитель,Паук-руководилац -The Cyberdemon,CC_CYBER,,,,Kyberdémon,Der Cyberdämon,Ο Cyber-δαίμονας,Ciborgdemono,El Ciberdemonio,,Kyberdemoni,Le Cyberdémon,A Kiberdémon,Il Cyberdemonio,サイバーデーモン,사이버데몬,De Cyberdemon,Cyberdemon,O Ciberdemônio,,Ciberdemon,Кибердемон,Сајбердемон -Our Hero,CC_HERO,,,,Náš hrdina,Unser Held,Ο ήρωας μας,Nia Heroo,Nuestro héroe,,Sankarimme,Notre Héros,Hősünk,Il Nostro eroe,我らのヒーロー,우리들의 영웅,Onze held,Nasz bohater,Nosso Herói,O Nosso Herói,Eroul Nostru,Наш герой,Наш херој -,,Actor tag names,,,,,,,,,,,,,,,,,,,,, -Zombieman,FN_ZOMBIE,,,,Zombík,Zombie,Ζόμπι,Zombiviro,Zombi,,Zombi,Zombie,zombi,Zombie Marine,ゾンビ兵,좀비맨,Zombie,Zombie,Fuzileiro Possuído,Homem Zombie,Zombi,Зомби,Зомби -Sergeant,FN_SHOTGUN,,,,Seržant,Schütze,Λοχίας,Serĝento,Sargento,,Kersantti,Type au Fusil,őrmester,Zombie Sergente,ゾンビ軍曹,샷건 가이,Jachtgeweer kerel,Zombie-sierżant,Sargento Possuído,Sargento,Sergent,Сержант,Водник -Chaingunner,FN_HEAVY,,,,Kulometčík,MG-Schütze,Πολυβόλο Ζόμπι,Maŝinpafilisto,Ametrallador,,Konekiväärimies,Type au Gros Flingue,gépágyús,Zombie Commando,チェーンガンゾンビ,체인거너,Zware wapens kerel,Ciężkozbrojny Zombie,Comando Possuído,Metrelhador,Mitralior,Пулемётчик,Митраљезац -Imp,FN_IMP,,,,Čertík,Kobold,Διάβολος,Diableto,,,Piru,Diablotin,kobold,Imp,インプ,임프,,Chochlik,Diabrete,,Drac,Имп,Враг -Demon,FN_DEMON,,,,Démon,Dämon,Δαίμονας,Demono,Demonio,,Demoni,Démon,démon,Demone,デーモン,데몬,,Demon,Demônio,,Demon,Демон,Демон -Spectre,FN_SPECTRE,,,,Přízrak,Schemen,Φάντασμα,Fantomo,Espectro,,Haamu,,fantom,Spettro,スペクトル,스펙터,Spook,Widmo,Espectro,,Spectru,Спектр,Авет -Lost Soul,FN_LOST,,,,Ztracená duše,Verlorene Seele,Χαμένη Ξυχή,Perdita Animo,Alma perdida,,Kadonnut sielu,Ame Perdue,Elveszett lélek,Anima Errante,ロストソウル,로스트 소울,Verloren ziel,Zagubiona Dusza,Alma Perdida,Alma Penada,Suflet Pierdut,Потерянная душа,Изгубљена душа -Cacodemon,FN_CACO,,,,Kakodémon,Cacodämon,Κακοδαίμονας,Kakodemono,Cacodemonio,,Kakodemoni,Cacodémon,kakodémon,Cacodemone,カコデーモン,카코 데몬,,Kakodemon,Cacodemônio,,Cacodemon,Какодемон,Какодемон -Hell Knight,FN_HELL,,,,Pekelný rytíř,Höllenritter,Ιππότης της Κόλασης,Inferkavaliro,Caballero infernal,,Hornanritari,Chevalier Infernal,pokollovag,Cavaliere Infernale,ヘルナイト,헬 나이트,Hel Ridder,Rycerz Piekła,Guarda Infernal,Cavaleiro Infernal,Cavaler al Infernului,Рыцарь Ада,Витез пакла -Baron of Hell,FN_BARON,,,,Baron pekel,Höllenbaron,Βαρώνος της Κολασης,Barono de Infero,Barón del infierno,,Hornanparoni,Baron des Enfers,pokolbáró,Barone Infernale,バロンオブヘル,바론 오브 헬,Baron van de Hel,Baron Piekła,Barão do Inferno,,Baron al Infernului,Барон Ада,Барон пакла -Arachnotron,FN_ARACH,,,,,,Αράχνοτρον,Elektronaraneo,Aracnotrón,,Araknotroni,,,Arachnotron,アラクノトロン,아라크노트론,,,,,Aracnotron,Арахнотрон,Паукотрон -Pain Elemental,FN_PAIN,,,,Elementál bolesti,Elementarschmerz,Στοιχείομα του Πόνου,Doloro-Elementulo,Elementar del dolor,,Kivun henki,Elémentaire de Douleur,Elemi Kín,Elementale del Dolore,ペインエレメンタル,페인 엘리멘탈,Pijn Elementair,Elemental Bólu,Elemental da Dor,,Elemental al Durerii,Элементаль боли,Елементал патње -Revenant,FN_REVEN,,,,Umrlec,Wiederauferstandener,Εκδικητής,Renaskitulo,Renacido,,Henkiinpalannut,,kísértet,Revenant,レバナント,레버넌트,Wraakzuchtiger,Zjawa,Insepulto,Renascido,Nemort,Ревенант,Повратник -Mancubus,FN_MANCU,,,,Mankubus,,Χοντρός,Mankubo,,,Mankubus,Mancube,,Mancubus,マンキュバス,맨큐버스,,Mankubus,,,Mancubus,Манкубус,Манкубус -Arch-vile,FN_ARCH,,,,Veleběs,Scheusal,Νεκρομάντις,Ĉefaĉbesto,Arch-Vile,,Arkkihirvitys,Arche-vile,Ősálnok,Arch-vile,アーチバイル,아크-바일,Aartsvijand,Arcy-bestia,,,Cel Abject,Арчвайл,Арчвајл -Spider Mastermind,FN_SPIDER,,,,Pavoučí vojevůdce,Spinnenmeister,Αραχνό Ιθύνων Νους,Elektronaraneo-Mastro,Mente-Maestra Arácnida,,Hämähäkkiaivot,L'Araignée Commandante,Pókvezér,L'Aracnomente Suprema,スパイダーマスターマインド,스파이더 마스터마인드,Spin Meesterbrein,Pajęczy Mistrz,A Aranha-Mestra,,Păianjen Maestru,Паук-предводитель,Паук-руководилац -Cyberdemon,FN_CYBER,,,,Kyberdémon,Cyberdämon,Cyber-δαίμονας,Ciborgdemono,Ciberdemonio,,Kyberdemoni,Le Cyberdémon,Kiberdémon,Il Cyberdemonio,サイバーデーモン,사이버데몬,De Cyberdemon,Cyberdemon,O Ciberdemônio,,Ciberdemon,Кибердемон,Сајбердемон -Nazi,FN_WOLFSS,,,,Nácek,,Ναζιστής,Nazio,,,Natsi,,náci,Nazista,ナチ兵,나치,,Nazista,Nazista,Nazi,Nazist,Нацист,Нациста -Dog,FN_DOG,,,,Pes,Hund,Σκύλος,Hundo,Perro,,Koira,Chien,kutya,Cane,犬,개,Hond,Pies,Cão,,Câine,Собака,Пас -Brass Knuckles,TAG_FIST,,,,Boxer,Schlagringe,Γροθιά,Latuna Fingrartikoj,Nudillos de bronce,,Nyrkkirauta,Poing Américain,Ököl,Tirapugni ,ナックルダスター,너클,Boksbeugels,Kastety,Soco Inglês,Soqueira,Rozetă,Кулаки,Боксер -Chainsaw,TAG_CHAINSAW,,,,Motorová pila,Kettensäge,Αλλησοπρίονο,Ĉensegilo,Motosierra,,Moottorisaha,Tronçonneuse,Láncfűrész,Motosega,チェーンソウ,전기톱,Kettingzaag,Piła łańcuchowa,Motoserra,,Drujbă,Бензопила,Моторна тестера -Pistol,TAG_PISTOL,,,,Pistole,Pistole,Πιστόλι,Pafileto,Pistola,,Pistooli,Pistolet,Pisztoly,Pistola,ピストル,권총,Pistool,Pistolet,Pistola,,Pistol,Пистолет,Пиштољ -Shotgun,TAG_SHOTGUN,,,,Brokovnice,Schrotflinte,Ντουφέκι,Ĉaspafilo,Escopeta,,Haulikko,Fusil à pompe,Sörétes puska,Fucile,ショットガン,샷건,Jachtgeweer,Strzelba,Espingarda,,Pușcă,Дробовик,Пумпарица -Super Shotgun,TAG_SUPERSHOTGUN,,,,Superbrokovnice,Super-Schrotflinte,Διπλό Ντουφέκι,Supera Ĉaspafilo,Súper Escopeta,,Superhaulikko,Super Fusil de chasse,Szuper sörétes puska,Fucile a doppia canna ,スーパーショットガン,슈퍼 샷건,Super Jachtgeweer,Super strzelba,Espingarda de cano duplo,,Super Pușcă,Супер-дробовик,Двоцевка -Chaingun,TAG_CHAINGUN,,,,Kulomet,Maschinengewehr,Πολυβόλο,Maŝinpafilo,Ametralladora,,Gatling-kk,Mitrailleuse,Golyószóró,Mitragliatore a canne rotanti ,チェーンガン,체인건,Machinegeweer,Karabin maszynowy,Metralhadora,,Mitralieră rotativă,Пулемёт,Митраљез -Rocket Launcher,TAG_ROCKETLAUNCHER,,,,Raketomet,Raketenwerfer,Πυραυλοβόλο,Raketlanĉilo,Lanzacohetes,,Sinko,Lance-Roquettes,Rakétavető,Lanciamissili,ロケットランチャー,로켓 런쳐,Raketwerper,Wyrzutnia rakiet,Lança-foguetes,Lança-Mísseis,Lansator de Rachete,Ракетница,Бацач ракета -Plasma Rifle,TAG_PLASMARIFLE,,,,Plazmová puška,Plasmagewehr,Πλάσμα Όπλο,Plasmo-pafilo,Rifle de Plasma,,Plasmapyssy,Fusil à Plasma,Plazmafegyver,Fucile al Plasma ,プラズマライフル,플라즈마 라이플,Plasmageweer,Karabin plazmowy,Fuzil de Plasma,Pistola de Plasma,Pușcă cu Plasmă,Плазменная пушка,Плазма оружје -BFG 9000,TAG_BFG9000,,,,,,,,,,,,,,,,,,,,,,ВЈП 9000 -Bullets,AMMO_CLIP,,,,Kulky,Patronen,Σφαίρες,Kugloj,Balas,,Luodit,Balles,Töltények,Proiettili,銃弾,권총 탄약,Kogels,Naboje,Balas,,Gloanțe,Пули,Меци -Shotgun Shells,AMMO_SHELLS,,,,Broky,Schrotpatronen,Σφαίρες Ντουφεκιού,Kartoĉoj,Cartuchos de escopeta,,Haulikon patruunat,Cartouches,Sörétek,Cartucce per fucile,散弾シェル,샷건 탄약,Jachtgeweer schelpen,Loftki,Cartuchos de Espingarda,,Proiectile pentru Pușcă,Патроны для дробовика,Патроне за пумпарицу -Rockets,AMMO_ROCKETS,,,,Rakety,Raketen,Πύραυλοι,Raketoj,Cohetes,,Raketit,Roquettes,Rakéták,Razzi,ロケット弾,로켓,Raketten,Rakiety,Foguetes,Mísseis,Rachete,Ракеты,Ракете -Energy Cells,AMMO_CELLS,,,,Energetické články,Energiezellen,Κύτταρα Ενέργιας,Energiĉeloj,Célula de energía,,Energia-akut,Cellules,Energiacellák,Batterie,エネルギーセル,에너지 셀,Energiecel,Ogniwa energetyczne,Células de Energia,,Celule cu Energie,Энергетические ячейки,Енергетске ћелије -,,Obituaries,,,,,,,,,,,,,,,,,,,,, -%o thought %g saw an arachnotron.,OB_STEALTHBABY,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] arachnotrona.","%o dachte, ein Arachnotron zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Αραχνοτρόν.,"%o pensis, ke @[pro_eo] vidis elektronaraneon.",%o creyó haber visto un aracnotrón.,,%o luuli nähneensä araknotronin.,%o a cru voir un Arachnotron.,"%o azt hitte, hogy látott egy Arachnotron-t.",a %o sembrava di aver visto un arachnotron.,%o がアラクノトロンを見た気がした。,%o 은(는) 아라크노트론을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een arachnotron zag.,%o kątem oka zauważył@[ao_pl] arachnotrona.,%o achou que viu uma arachnotron.,,%o a crezut că %g a văzut un aracnotron.,%o краем глаза заметил@[ao_rus] арахнотрона.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] паукотрона. -%o thought %g saw an archvile.,OB_STEALTHVILE,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] velezrůdu.","%o dachte, ein Scheusal zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Νεκρομάντη,"%o pensis, ke @[pro_eo] vidis ĉefaĉbeston.",%o creyó haber visto un arch-vile.,,%o luuli nähneensä arkkihirvityksen,%o a cru voir un Arche-Vile.,"%o azt hitte, hogy látott egy ősálnokot.",a %o sembrava di aver visto un Arch-Vile.,%o がアーチバイルを見た気がした。,%o 은(는) 아크-바일을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een aartsvijand zag.,%o kątem oka zauważył@[ao_pl] arcy-bestię.,%o achou que viu um archvile.,,%o a crezut că %g l-a văzut pe cel abject.,%o краем глаза заметил@[ao_rus] арчвайла.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] једног арчвајла. -%o thought %g saw a Baron of Hell.,OB_STEALTHBARON,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] barona pekel.","%o dachte, einen Höllenbaron zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Βαρώνο της Κόλασης.,"%o pensis, ke @[pro_eo] vidis Baronon de Infero.",%o creyó haber visto un Barón del Infierno.,,%o luuli nähneensä hornanparonin.,%o a cru voir un Baron des enfers.,"%o azt hitte, hogy látott egy pokolbárót.",a %o sembrava di aver visto un Barone Infernale.,%o がバロンを見た気がした。,%o 은(는) 바론 오브 헬을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een baron van de Hel zag.,%o kątem oka zauważył@[ao_pl] Barona Piekła.,%o achou que viu um barão do inferno.,,%o a crezut că %g a văzut un Baron al Infernului.,%o краем глаза заметил@[ao_rus] барона Ада.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] барона пакла. -%o thought %g saw a cacodemon.,OB_STEALTHCACO,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] kakodémona.","%o dachte, einen Cacodämonen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Κακοδαίμονα.,"%o pensis, ke @[pro_eo] vidis kakodemonon.",%o creyó haber visto un cacodemonio.,,%o luuli nähneensä kakodemonin.,%o a cru voir un Cacodémon.,"%o azt hitte, hogy látott egy kakodémont.",a %o sembrava di aver visto un cacodemone.,%o がカコデーモンを見た気がした。,%o 은(는) 카코데몬을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een cacodemon zag.,%o kątem oka zauważył@[ao_pl] kakodemona.,%o achou que viu um cacodemônio.,,%o a crezut că %g a văzut un cacodemon.,%o краем глаза заметил@[ao_rus] какодемона.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] какодемона. -%o thought %g saw a chaingunner.,OB_STEALTHCHAINGUY,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] kulometčíka.","%o dachte, einen MG-Schützen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Ζόμπι με ένα πολυβόλο.,"%o pensis, ke @[pro_eo] vidis maŝinpafiliston.",%o creyó haber visto un ametrallador.,,%o luuli nähneensä konekiväärimiehen.,%o a cru voir un mitrailleur.,"%o azt hitte, hogy látott egy Golyószóróst.",a %o sembrava di aver visto uno zombie commando.,%o がチェインガンナーを見た気がした。,%o 은(는) 체인거너를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een zware wapens kerel zag.,%o kątem oka zauważył@[ao_pl] ciężkozbrojnego zombie.,%o achou que viu um comando possuído.,%o achou que viu um metrelhador.,%o a crezut că %g a văzut un mitralior.,%o краем глаза заметил@[ao_rus] пулемётчика.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] митраљезца. -%o thought %g saw a demon.,OB_STEALTHDEMON,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] démona.","%o dachte, einen Dämonen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα δαίμονα.,"%o pensis, ke @[pro_eo] vidis demonon.",%o creyó haber visto un demonio.,,%o luuli nähneensä demonin.,%o a cru voir un démon.,"%o azt hitte, hogy látott egy Démont.",a %o sembrava di aver visto un demone.,%o がデーモンを見た気がした。,%o 은(는) 데몬을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een demon zag.,%o kątem oka zauważył@[ao_pl] demona.,%o achou que viu um demônio.,,%o a crezut că %g a văzut un demon.,%o краем глаза заметил@[ao_rus] демона.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] демона. -%o thought %g saw a Hell Knight.,OB_STEALTHKNIGHT,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] rytíře pekel.","%o dachte, einen Höllenritter zu sehen.",@[art_gr] %o νόμιζε οτι είδε έναν Ιππότη της Κόλασης.,"%o pensis, ke @[pro_eo] vidis inferkavaliron.",%o creyó haber visto un Caballero Infernal.,,%o luuli nähneensä hornanritarin.,%o a cru voir un chevalier infernal.,"%o azt hitte, hogy látott egy Pokol Lovagot.",a %o sembrava di aver visto un Cavaliere Infernale.,%o がヘルナイトを見た気がした。,%o 은(는) 헬 나이트를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een hel ridder zag.,%o kątem oka zauważył@[ao_pl] Rycerza Piekła.,%o achou que viu um guarda infernal.,%o achou que viu um cavaleiro infernal.,%o a crezut că %g a văzut un Cavaler al Infernului.,%o краем глаза заметил@[ao_rus] рыцаря Ада.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] витеза пакла. -%o thought %g saw an imp.,OB_STEALTHIMP,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] čertíka.","%o dachte, einen Kobold zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Διάβολο.,"%o pensis, ke @[pro_eo] vidis diableton.",%o creyó haber visto un diablillo.,,%o luuli nähneensä pirun.,%o a cru voir un diablotin.,"%o azt hitte, hogy látott egy Imp-et.",a %o sembrava di aver visto un imp.,%o がインプを見た気がした。,%o 은(는) 임프를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een imp zag.,%o kątem oka zauważył@[ao_pl] chochlika.,%o achou que viu um diabrete.,,%o a crezut că %g a văzut un drac.,%o краем глаза заметил@[ao_rus] импа.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] врага. -%o thought %g saw a mancubus.,OB_STEALTHFATSO,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] menkuba.","%o dachte, einen Mancubus zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Χοντρό.,"%o pensis, ke @[pro_eo] vidis mankubon.",%o creyó haber visto un mancubus.,,%o luuli nähneensä mankubuksen.,%o a cru voir un mancube.,"%o azt hitte, hogy látott egy Mancubus-t.",a %o sembrava di aver visto un mancubus.,%o がマンキュバスを見た気がした。,%o 은(는) 맨큐버스를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een mancubus zag.,%o kątem oka zauważył@[ao_pl] mankubusa.,%o achou que viu um mancubus.,,%o a crezut că %g a văzut un mancubus.,%o краем глаза заметил@[ao_rus] манкубуса.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] манкубуса. -%o thought %g saw a revenant.,OB_STEALTHUNDEAD,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] umrlce.","%o dachte, einen Wiederauferstandenen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Εκδικητή.,"%o pensis, ke @[pro_eo] vidis renaskitulon.",%o creyó haber visto un renacido.,,%o luuli nähneensä henkiinpalanneen.,%o a cru voir un revenant.,"%o azt hitte, hogy látott egy Revenant.",a %o sembrava di aver visto un revenant.,%o がレバナントを見た気がした。,%o 은(는) 레버넌트를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een wraakzuchtige zag.,%o kątem oka zauważył@[ao_pl] zjawę.,%o achou que viu um insepulto.,%o achou que viu um renascido.,%o a crezut că %g a văzut un nemort.,%o краем глаза заметил@[ao_rus] ревенанта.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] повратника. -%o thought %g saw a sergeant.,OB_STEALTHSHOTGUNGUY,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] seržanta.","%o dachte, einen Schützen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Λοχία.,"%o pensis, ke @[pro_eo] vidis serĝenton.",%o creyó haber visto un sargento.,,%o luuli nähneensä kersantin.,%o a cru voir un type au fusil.,"%o azt hitte, hogy látott egy Sörétesalakot.",a %o sembrava di aver visto un zombie sergente.,%o が軍曹を見た気がした。,%o 은(는) 샷건 가이를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een jachtgeweer kerel zag.,%o kątem oka zauważył@[ao_pl] zombie-sierżanta.,%o achou que viu um sargento possuído.,%o achou que viu um sargento.,%o a crezut că %g a văzut un sergent.,%o краем глаза заметил@[ao_rus] сержанта.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] водника. -%o thought %g saw a zombieman.,OB_STEALTHZOMBIE,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] zombíka.","%o dachte, einen Zombie zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Ζόμπι.,"%o pensis, ke @[pro_eo] vidis zombiviron.",%o creyó haber visto un zombi.,,%o luuli nähneensä zombin.,%o a cru voir un zombie.,"%o azt hitte, hogy látott egy Zombifickót.",a %o sembrava di aver visto uno zombie marine.,%o がゾンビ兵を見た気がした。,%o 은(는) 좀비맨을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een zombie zag.,%o kątem oka zauważył@[ao_pl] zombie.,%o achou que viu um fuzileiro possuído.,%o achou que viu um zombie.,%o a crezut că %g a văzut un zombi.,%o краем глаза заметил@[ao_rus] зомби.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] зомбија. -%o was punched by a revenant.,OB_UNDEADHIT,,,,%o byl@[ao_cs] udeřen@[ao_cs] umrlcem.,%o wurde von einem Wiederauferstandenen K.O geschlagen.,@[art_gr] %o έφαγε μια μπουνία απο έναν Εκδικητή.,%o estis batita per renaskitulo.,%o fue golpead@[ao_esp] por un renacido.,,%o joutui henkiinpalanneen lyömäksi.,%o s'est pris@[e_fr] une raclée de la part d'un revenant.,%o egy Revenanttal próbált bunyózni.,%o è stato colpito dal pugno di un revenant.,%o はレバナントに殴られた。,%o 은(는) 레버넌트에게 맞아 죽었다.,%o werd geslagen door een wraakzuchtige.,%o został@[ao_pl] uderzon@[adj_pl] przez zjawę.,%o foi socad@[ao_ptb] por um insepulto.,%o foi socad@[ao_ptb] por um renascido.,%o a primit un pumn de la un nemort.,Игрока %o ударил ревенант.,%o је ударен@[adj_1_sr] од стане повратника. -%o was slashed by an imp.,OB_IMPHIT,,,,%o byl@[ao_cs] rozsápán@[ao_cs] čertíkem.,%o wurde von einem Kobold gekratzt.,@[art_gr] %o κόπηκε απο ενα Διάβολο.,%o estis tranĉita per diableto.,%o fue desgarrad@[ao_esp] por un Imp.,,%o joutui pirun sivaltamaksi.,%o a été lacéré@[e_fr] par un diablotin.,%o egy Imp által szét lett hasítva.,%o è stato squarciato da un imp.,%o はインプに切り裂かれた。,%o 은(는) 임프에게 찢겨 죽었다.,%o werd gesneden door een imp.,%o został@[ao_pl] rozcięt@[adj_pl] przez chochlika.,%o foi dilacerad@[ao_ptb] por um diabrete.,,%o a fost zgâriat de un drac.,Игрока %o расцарапал имп.,Играча %o је пресеко враг. -%o got too close to a cacodemon.,OB_CACOHIT,,,,%o se dostal@[ao_cs] moc blízko ke kakodémonovi.,%o kam dem Cacodämonen zu nahe.,@[art_gr] %o ήτανε πολυ κοντά σε ένα Κακοδαίμονα.,%o venis tro proksime al kakodemonon.,%o se acercó demasiado a un cacodemonio.,,%o meni liian lähelle kakodemonia.,%o s'est approché@[e_fr] trop près d'un Cacodémon.,%o túl közel került egy Cacodémonhoz.,%o si è avvicinato troppo a un cacodemone.,%o はカコデーモンに近づきすぎた。,%o 은(는) 카코데몬과 가까웠다.,%o kwam te dicht bij een cacodemon.,%o pod@[irreg_1_pl] zbyt blisko do kakodemona.,%o chegou muito perto de um cacodemônio.,,%o s-a apropiat prea mult de un cacodemon.,%o слишком сблизил@[refl_rus] с какодемоном.,%o се превише приближи@[ao_1_sr] какодемону. -%o was bit by a demon.,OB_DEMONHIT,,,,%o byl@[ao_cs] rozkousán@[ao_cs] démonem.,%o wurde von einem Dämonen gebissen.,@[art_gr] %o δαγκόθηκε απο ένα Δαίμονα.,%o estis mordita per demono.,%o fue mordid@[ao_esp] por un demonio.,,%o joutui demonin puremaksi.,%o a été mordu@[e_fr] par un démon.,%o meg lett harapva egy Démon által.,%o è stato sbranato da un demone.,%o はデーモンに噛まれた。,%o 은(는) 데몬에게 물렸다.,%o werd gebeten door een demon.,%o wpada w szczęki demona.,%o foi mordid@[ao_ptb] por um demônio.,,%o a fost mușcat de un demon.,Игрока %o укусил демон.,Играча %o је ујео демон. -%o was eaten by a spectre.,OB_SPECTREHIT,,,,%o byl@[ao_cs] sežrán@[ao_cs] přízrakem.,%o wurde von dem Schemen gefressen.,Ένα φάντασμα έφαγε @[pro_gr] %o.,%o estis manĝita per fantomo.,%o fue devorad@[ao_esp] por un espectro.,,%o joutui haamun syömäksi.,%o a été dévoré@[e_fr] par un spectre.,%o fel lett falva egy Kísértet jóvoltábol.,%o è stato divorato da uno spettro.,%o はスペクトルに喰われた。,%o 은(는) 스펙터에게 잡아먹혔다.,%o werd opgegeten door een spook.,%o został@[ao_pl] zjedzon@[adj_pl] przez widmo.,%o foi devorad@[ao_ptb] por um espectro.,,%o a fost mâncat de un spectru.,Игрока %o сожрал спектр.,Играча %o је појео авет. -%o was ripped open by a Baron of Hell.,OB_BARONHIT,,,,%o byl@[ao_cs] rozčtvrcen@[ao_cs] baronem pekel.,%o wurde von dem Höllenbaron aufgerissen.,@[art_gr] %o σχίστηκε απο εναν Βαρώνο της Κόλασης.,%o estis disŝirita per Barono de Infero.,%o quedó hech@[ao_esp] trizas por un Barón del Infierno.,,%o joutui hornanparonin auki repimäksi.,%o a été déchiré@[e_fr] par un Baron des Enfers.,%o szét lett nyitva egy Pokol Báró által.,%o è stato scoperchiato da un Barone dell'Inferno.,%o はバロンオブヘルに体を抉じ開けられた。,%o 은(는) 바론 오브 헬에게 뜯겨 죽었다.,%o werd opengereten door een Baron van de hel.,%o został@[ao_pl] rozerwan@[adj_pl] przez Barona Piekła.,%o foi rasgad@[ao_ptb] por um Barão do Inferno.,%o foi desventrad@[ao_ptb] por um Barão do Inferno.,%o a fost deschis pe viu de un Baron al Infernului.,Игрока %o разорвал барон Ада.,%o је поцеп@[adj_2_sr] од стране барон пакла. -%o was gutted by a Hell Knight.,OB_KNIGHTHIT,,,,%o byl@[ao_cs] vykuchán@[ao_cs] rytířem pekel.,%o wurde von dem Höllenritter ausgenommen.,@[art_gr] %o ξεκοιλιάστηκε απο έναν Ιππότη της Κόλασης.,%o estis tranĉintestigita per inferkavaliro.,%o fue destripad@[ao_esp] por un Caballero Infernal.,,%o joutui hornanritarin perkaamaksi.,%o a été étripé@[e_fr] par un un chevalier infernal.,%ot kibelezte egy pokollovag.,%o è stato sbudellato da un Cavaliere dell'Inferno.,%o はヘルナイトに内臓を抉られた。,%o 은(는) 헬 나이트에게 도륙당했다.,%o werd gestript door een hel ridder.,%o został@[ao_pl] wypatroszon@[adj_pl] przez Rycerza Piekła.,%o foi estripad@[ao_ptb] por um Guarda Infernal.,%o foi estripad@[ao_ptb] por um Cavaleiro Infernal.,%o a fost măcelărit de un Cavaler al Infernului.,Игрока %o распотрошил рыцарь Ада.,Играча %o је унаказио витез пакла. -%o was killed by a zombieman.,OB_ZOMBIE,,,,%o byl@[ao_cs] zabit@[ao_cs] zombíkem.,%o wurde von einem Zombie getötet.,@[art_gr] %o σκοτώθηκε απο ένα Ζόμπι.,%o estis mortigita per zombiviro.,%o fue asesinad@[ao_esp] por un zombi.,,%o joutui zombin tappamaksi.,%o a été tué@[e_fr] par un zombie.,%o meghalt egy Zombifickó által.,%o è stato ucciso da uno zombie marine.,%o はゾンビ兵に殺された。,%o 은(는) 좀비맨에게 죽었다.,%o werd gedood door een zombie.,%o został@[ao_pl] zabit@[adj_pl] przez zombie.,%o foi mort@[ao_ptb] por um possuído.,%o foi mort@[ao_ptb] por um zombie.,%o a fost omorât de un zombi.,Игрока %o убил зомби.,%o је убијен@[adj_1_sr] од стране зомбија. -%o was shot by a sergeant.,OB_SHOTGUY,,,,%o byl@[ao_cs] zastřelen@[ao_cs] seržantem.,%o wurde von einem Schützen erschossen.,Ένας Λοχίας πυροβόλησε @[pro_gr] %o.,%o estis pafita per serĝento.,%o fue fusilad@[ao_esp] por un sargento.,,%o joutui kersantin ampumaksi.,%o s'est fait flinguer par un type au fusil.,%o meg lett lőve egy Söréteses alak által.,%o è sato impallinato da uno zombie sergente.,%o はゾンビ軍曹に撃たれた。,%o 은(는) 서전트에게 총을 맞았다.,%o werd neergeschoten door een sergeant.,%o został@[ao_pl] zastrzelon@[adj_pl] przez zombie-sierżanta.,%o levou um tiro de um sargento possuído.,,%o a fost împușcat de un sergent.,Игрока %o застрелил сержант.,Играча %o је погодио водник. -%o was incinerated by an archvile.,OB_VILE,,,,%o byl@[ao_cs] zpopelněn@[ao_cs] velezrůdou.,%o wurde von einem Scheusal verbrannt.,@[art_gr] %o αποτεφρώθηκε απο ένα Νεκρομάντη.,%o estis cindrigita per ĉefaĉbesto.,%o fue calcinad@[ao_esp] por un arch-vile.,,%o joutui arkkihirvityksen kärventämäksi.,%o a été incinéré@[e_fr] par un Arche-Vile.,%o meg lett pörkölve egy Archördög által.,%o è stato incenerito da un arch-vile.,%o はアーチバイルに焼き尽くされた。,%o 은(는) 아크-바일에 의해 소각되었다.,%o werd verbrand door een aartsvijand.,%o został@[ao_pl] spalon@[adj_pl] przez arcy-bestię.,%o foi incinerad@[ao_ptb] pelo archvile.,,%o a fost incinerat de cel abject.,Игрока %o кремировал арчвайл.,Играча %o је запалио арчвајл. -%o couldn't evade a revenant's fireball.,OB_UNDEAD,,,,%o se nevyhnul@[ao_cs] umrlčí ohnivé kouli.,%o konnte dem Feuerball des Wiederauferstandenen nicht ausweichen.,@[art_gr] %o δέν μπορούσε να αποφείγει τον πύραυλο ενός Εκδικητή.,%o ne povis eviti fajrpilkon de renaskitulo.,%o no pudo esquivar la bola de fuego de un renacido.,,%o ei kyennyt väistämään henkiinpalanneen tulipalloa.,%o n'a pas réussi à esquiver un missile de revenant.,%o nem tudta kivédeni a Revenant tűzgolyóját.,%o non ha potuto evitare il missile di un revenant.,%o はレバナントのファイアボールを回避できなかった。,%o 은(는) 레버넌트의 화염구를 피하지 못했다.,%o kon de vuurbal van een wraakzuchtige niet ontwijken.,%o nie udaje się uniknąć pocisku od zjawy.,%o não conseguiu desviar do míssil do insepulto.,%o não conseguiu desviar do míssil do renascido.,%o n-a putut scăpa de mingea de foc a nemortului.,%o не успел@[ao_rus] увернуться от снаряда ревенанта.,%o није мог@[ao_2_sr] да избегне повратникову пламену куглу. -%o was squashed by a mancubus.,OB_FATSO,,,,%o byl@[ao_cs] rozmačkán@[ao_cs] mankubusem.,%o wurde von einem Mancubus plattgemacht.,@[art_gr] %o λιόθηκε απο έναν Χοντρό.,%o estis premita per mankubo.,%o fue pulverizad@[ao_esp] por un mancubus.,,%o joutui mankubuksen liiskaamaksi.,%o s'est fait@[e_fr] aplatir par un Mancube.,%o agyon lett lapítva egy Mancubus által.,%o è stato disintegrato da un mancubus.,%o はマンキュバスに潰された。,%o 은(는) 맨큐버스에게 짓이겨졌다.,%o werd verpletterd door een mancubus.,%o został@[ao_pl] zmiażdżon@[adj_pl] przez mankubusa.,%o foi esmagad@[ao_ptb] por um mancubus.,,%o a fost strivit de un mancubus.,Игрока %o раздавил манкубус.,Играча %o је изгњечио манкубус. -%o was perforated by a chaingunner.,OB_CHAINGUY,,,,%o byl@[ao_cs] prostřelen@[ao_cs] kulometčikém.,%o wurde von einem MG-Schützen perforiert.,@[art_gr] %o εκτελέστικε απο ένα Ζόμπι με ένα πολυβόλο.,%o estis truhaviĝita per maŝonpafilisto.,%o fue perforad@[ao_esp] por un ametrallador.,,%o joutui konekiväärimiehen rei'ittämäksi.,%o a été perforé@[e_fr] par un mitrailleur.,%o szítává lett lőve egy Golyószórós által.,%o è stato perforato da uno zombie commando.,%o はチェインガンナーに蜂の巣にされた。,%o 은(는) 체인거너에 의해 벌집이 됐다.,%o werd geperforeerd door een zware wapens kerel.,%o został@[ao_pl] przedziurawion@[adj_pl] przez ciężkozbrojnego zombie.,%o foi perfurad@[ao_ptb] por um comando possuído.,%o foi perfurad@[ao_ptb] por um metrelhador.,%o a fost perforat de un mitralior.,Игрока %o продырявил пулемётчик.,Играча %o је изрешетао митраљезац. -%o was spooked by a lost soul.,OB_SKULL,,,,%o se lekl@[ao_cs] ztracené duše.,%o wurde von einer Verlorenen Seele heimgesucht.,Μια Χαμένη Ξυχή φόβησε @[pro_gr] %o.,%o estis timigita per perdita animo.,%o se murió de miedo ante un alma perdida.,,%o joutui kadonneen sielun säikäyttämäksi.,%o s'est fait@[e_fr] surprendre par une âme perdue.,%o Halálra ijedt egy Elveszett Léleknek köszönhetően,%o è stato spaventato a morte da un'Anima Errante.,%o はロストソウルにビビらされた。,%o 은(는) 로스트 소울을 보고 깜짝 놀랐다.,%o werd bang gemaakt door een verloren ziel.,%o został@[ao_pl] przestraszon@[adj_pl] przez zagubioną duszę.,%o se assustou com uma alma perdida.,%o se assustou com uma alma penada.,%o a fost speriat de un suflet pierdut.,%o испугал@[refl_rus] потерянной души.,%o је уплашен@[adj_1_sr] од изгубљене душе. -%o was burned by an imp.,OB_IMP,,,,%o byl@[ao_cs] spálen@[ao_cs] čertem.,%o wurde von einem Kobold verbrannt.,@[art_gr] %o κάικε απο έναν Διάβολο.,%o estis bruligita per diableto.,%o fue incendiad@[ao_esp] por un Imp.,,%o joutui pirun polttamaksi.,%o brûlé@[e_fr] par un diablotin.,%o megégett egy Imp által.,%o è stato bruciato da un imp.,%o はインプに焼かれた。,%o 은(는) 임프에게 불태워졌다.,%o werd verbrand door een imp.,%o został@[ao_pl] spalon@[adj_pl] przez chochlika.,%o foi queimad@[ao_ptb] por um diabrete.,,%o a fost ars de un demon.,Игрока %o сжёг имп.,%o је изгорен@[adj_1_sr] од стране врага. -%o was smitten by a cacodemon.,OB_CACO,,,,%o byl@[ao_cs] udeřen@[ao_cs] kakodémonem.,%o wurde von einem Cacodämonen gequält.,@[art_gr] %o καίκε απο έναν Κακοδαίμονα.,%o estis venkobatita per kakodemono.,%o fue aniquilad@[ao_esp] por un cacodemonio.,,%o joutui kakodemonin iskemäksi.,%o a été terrassé@[e_fr] par un Cacodémon.,%o beégett egy Cacodémon által.,%o è stato abbattuto da un cacodemone.,%o はカコデーモンに裁きを受けた。,%o 은(는) 카코데몬에게 엄습 당했다.,%o werd geslagen door een cacodemon.,%o został@[ao_pl] porażon@[adj_pl] przez kakodemona.,%o foi golpead@[ao_ptb] por um cacodemônio.,,%o a fost lovit de un cacodemon.,Игрока %o поразил какодемон.,Играча %o је ударио какодемон. -%o was bruised by a Baron of Hell.,OB_BARON,,,,%o byl@[ao_cs] pomačkán@[ao_cs] baronem pekel.,%o wurde von einem Höllenbaron geröstet.,@[art_gr] %o γρατζουνήθηκε απο ένα Βαρώνο της Κόλασης.,%o estis kontuzita per Barono de Infero.,%o fue vapulead@[ao_esp] por un Barón del Infierno.,,%o joutui hornanparonin ruhjomaksi.,%o a été démoli@[e_fr] par un Baron des Enfers.,%o szétlett zúzva egy Pokol Báró által.,%o è stato scorticato da un Barone Infernale.,%o はバロンオブヘルに痛めつけられた。,%o 은(는) 바론 오브 헬에게 상처받았다.,%o werd gekneusd door een baron van de hel.,%o został@[ao_pl] stłuczon@[adj_pl] Barona Piekła.,%o foi ferid@[ao_ptb] por um Barão do Inferno.,,%o a fost contuzionat de un Baron al Infernului.,%o получил@[ao_rus] синяк от барона Ада.,%o је мод@[adj_3_sr] због барона пакла. -%o was splayed by a Hell Knight.,OB_KNIGHT,,,,%o byl@[ao_cs] rozpůlen@[ao_cs] rytířem pekel.,%o wurde von einem Höllenritter gebraten.,@[art_gr] %o απλώθηκε απο έναν Ιππότη της Κόλασης,%o estis disstreĉita per infermkavaliro.,%o fue partid@[ao_esp] en dos por un Caballero Infernal.,,%o joutui hornanritarin repimäksi.,%o a été éclaté@[e_fr] par un chevalier infernal.,%o szétfolyt egy Pokol Lovag által.,%o è stato squartato da un Cavaliere Infernale.,%o はヘルナイトにバラ撒かれた。,%o 은(는) 헬 나이트에게 갈라졌다.,%o werd gespierd door een hel ridder.,%o został@[ao_pl] rozcapierzon@[adj_pl] przez Rycerza Piekła.,%o foi espalmad@[ao_ptb] por um Guarda Infernal.,%o foi espalmad@[ao_ptb] por um Cavaleiro Infernal.,%o a fost scrântit de un Cavaler al Infernului.,Игрока %o распластал рыцарь Ада.,%o је раширен@[adj_1_sr] због витеза пакла. -%o stood in awe of the spider demon.,OB_SPIDER,,,,%o zůstal@[ao_cs] stát v úžasu před pavoučím démonem.,%o stand in Ehrfurcht vor dem Spinnendämon.,@[art_gr] %o στάθηκε με δέος μπροστά στόν αραχνοδαίμονα.,%o staris mirigita pro la aranedemonon.,%o no tuvo oportunidad contra la mente-maestra arácnida.,,%o kunnioitti syvästi hämähäkkidemonia,%o est resté pris@[e_fr] d'admiration devant le Démon Arachnéen.,%o csak egyhelyben állt megrémülve a Pók Agytröszt miatt.,%o è stato soggiogato dal Ragno demoniaco.,%o はスパイダーデーモンに恐れをなした。,%o 은(는) 거미악마의 무자비함을 느꼈다.,%o stond in ontzag voor de spindemon.,%o podziwiał@[ao_pl] pajęczego mistrza.,%o ajoelhou-se em frente da Aranha-Mestra.,,%o a stat înfricoșat în fața păianjenului maestru.,%o стоял@[ao_rus] в восторге перед пауком-предводителем.,%o се смрзну@[ao_1_sr] у очарању паук-руководилаца. -%o let an arachnotron get %h.,OB_BABY,,,,%o se nechal@[ao_cs] dostat arachnotronem.,%o ließ sich von einem Arachnotron erledigen.,@[art_gr] %o άφησε ένα Αράχνοτρον να @[pro_gr] σκοτώσει.,%o lasis elektronaraneon venki @[pro_eo]n.,%o fue alcanzad@[ao_esp] por un aracnotrón.,,%o antoi anaktrotronin saada hänet.,%o a laissé un arachnotron l'avoir.,%o hagyta hogy elkapja egy Arachnotron.,%o ha permesso che un arachnotron l'uccidesse.,%o が アラクノトロンに討ち取られた。,%o 은(는) 아라크노트론이 %o를(을) 죽이도록 놔두었다.,%o werd gedood door een arachnotron,%o pozwolił@[ao_pl] arachnotronowi się do siebie dobrać.,%o foi peg@[ao_ptb] por uma arachnotron.,%o foi apanhad@[ao_ptb] por uma arachnotron.,%o s-a lăsat prins de un aracnotron.,%o дал@[ao_rus] арахнотрону себя убить.,%o је допусти@[ao_1_sr] да паукотрон дође до %h. -%o was splattered by a cyberdemon.,OB_CYBORG,,,,%o byl@[ao_cs] rozplesknut@[ao_cs] na kaši kyberdémonem.,%o wurde von einem Cyberdämon zerfetzt.,@[art_gr] %o έσκασε απο ένα Cyber-δαίμονα.,%o estis ŝprucigita per ciborgdemono.,%o fue hech@[ao_esp] pedazos por un ciberdemonio.,,%o joutui kyberdemonin yltympäri roiskimaksi.,%o a été pulvérisé@[e_fr] par un Cyberdémon.,%o szétloccsant egy Kiborgdémon által.,%o è stato spiaccicato da un Cyberdemone.,%o はサイバーデーモンにバラバラにされた。,%o 은(는) 사이버데몬에 의해 산산조각이 났다.,%o werd gespetterd door een cyberdemon.,%o został@[ao_pl] rozbryzgan@[adj_pl] przez cyberdemona.,%o foi arrebentad@[ao_ptb] pelo Ciberdemônio.,,%o a fost împroșcat de ciberdemon.,Игрока %o размазал кибердемон.,%o је спљоштен@[adj_1_sr] од стране сајбердемона -%o met a Nazi.,OB_WOLFSS,,,,%o potkal@[ao_cs] nácka.,%o traf einen Nazi.,@[art_gr] %o χνώρισε ένα Ναζιστή.,%o renkontis Nazion.,%o se encontró a un Nazi.,,%o tapasi natsin.,%o a rencontré un Nazi.,%o találkozott egy nácival.,%o ha incontrato un Nazista.,%o はナチ兵と遭遇した。,%o 은(는) 나치를 만났다.,%o ontmoette een nazi.,%o spotkał@[ao_pl] nazistę.,%o encontrou um Nazista.,%o encontrou um Nazi.,%o a întâlnit un Nazist.,%o встретил@[ao_rus] нациста.,%o је упозна@[ao_1_sr] нацисту. -%o was mauled by a dog.,OB_DOG,,,,%o byl@[ao_cs] roztrhán@[ao_cs] psem.,%o wurde von einem Hund zerrissen.,@[art_gr] %o φαγόθικε απο ένα σκύλο.,%o estis disŝirita per hundaĉo.,%o fue magullad@[ao_esp] por un perro.,,%o joutui koiran raatelemaksi.,%o s'est fait mordre par un chien.,%o nem kapott tetanuszt miután a kutya megharapta,%o è stato sbranato da un cane.,%o は犬に引き裂かれた。,%o 은(는) 개한테 으스러졌다.,%o werd verminkt door een hond.,%o został@[ao_pl] poturbowan@[adj_pl] przez psa.,%o foi mutilad@[ao_ptb] por um cachorro.,%o foi mutilad@[ao_ptb] por um cão.,%o a fost sfâșiat de un câine.,Игрока %o разорвала собака.,Играча %o је удавио пас. -%o chewed on %k's fist.,OB_MPFIST,,,,%o ochutnal@[ao_cs] pěst hráče %k.,%o kaute auf %ks Faust herum.,@[art_gr] %o μάσησε τη γροθία του/της %k.,%o maĉis la pugnon de %k.,%o masticó el puño de %k.,,%k rusikoi %o paran.,%o a bouffé le poing de %k.,%o megrágta %k ökleit.,%o si è schiantato contro il pugno di %k.,%o は %k の拳を顔面に受けた。,%o 은(는) %k 의 주먹을 물었다.,%o gekauwd op %k's vuist.,%o przygryza pięść %k.,%o foi espancad@[ao_ptb] até a morte por %k,,%o a mestecat pumnul lui %k.,Игрок %o отведал кулака игрока %k.,Играча %o је сажвакао песницу играча %k. -%o was mowed over by %k's chainsaw.,OB_MPCHAINSAW,,,,%o byl@[ao_cs] zkácen@[ao_cs] motorovkou hráče %k.,%o wurde von %ks Kettensäge zerteilt.,@[art_gr] %o κόπηκε απο το αλλησοπρίονο του/της %k.,%o estis buĉita per la ĉensagilo de %k.,%o fue masacrad@[ao_esp] por la motosierra de %k.,,%k katkoi %o paran.,%o a été tondu@[e_fr] par la tronconneuse de %k.,%o lelett nyírva %k Láncfűrészének által.,%o è stato falciato dalla motosega di %k.,%o は %k のチェーンソーで刈り取られた。,%o 은(는) %k 의 전기톱에 갈렸다.,%o werd gemaaid met %k's kettingzaag.,%o został@[ao_pl] skoszon@[adj_pl] przez piłę łańcuchową %k.,%o foi picad@[ao_ptb] pela motoserra de %k,,%o a fost tăiat de drujba lui %k.,Игрока %o разрезал бензопилой игрок %k.,%o је исечен@[adj_1_sr] моторном тестером играча %k. -%o was tickled by %k's pea shooter.,OB_MPPISTOL,,,,%o byl@[ao_cs] polechtán@[ao_cs] pistolkou hráče %k.,%o wurde von %ks Erbsenpistole gekitzelt.,@[art_gr] %o γαργαλίθηκε απο το οπλάκι του/της %k.,%o estis ticklita per la eta pafilo de %k.,%o fue cosquillead@[ao_esp] por el tirachinas de %k.,%o ha sido asesinad@[ao_esp] por la pipa de %k.,%o kutitti %o parkaa hernepyssyllään.,%o a été châtouillé@[e_fr] par le pistolet de %k.,%o halálra lett csiklandozva %k Pisztolya által.,%o è stato sforacchiato dalla pistola di %k'.,%o は %k の豆鉄砲でくすぐられた。,%o 은(는) %k 의 권총에 간지럼을 탔다.,%o werd gekieteld door %k's erwtenschutter.,%o został@[ao_pl] połaskotan@[adj_pl] przez spluwę %k.,%o levou cócegas da pistolinha de %k.,,%o a fost gâdilat de pistolașul lui %k.,Игрока %o застрелил из пистолета игрок %k.,%o је заголицан@[adj_1_sr] пиштољем играча %k. -%o chewed on %k's boomstick.,OB_MPSHOTGUN,,,,%o si pochutnal@[ao_cs] na brokádě hráče %k.,%o wurde Opfer von %ks Schrotflinte.,@[art_gr] %o έφαγε το ντουφέκι του/της %k.,%o maĉis la ĉaspafilon de %k.,%o mordió@[ao_esp] el trabuco de %k.,%o ha sido agujeread@[ao_esp] por el trabuco de %k.,%k jauhoi %o paran tussarillaan.,%o a s'est mangé@[e_fr] de la chevrotine de la part de %k.,%o megrágta %k BUMMbotját.,%o si è trovato davanti il fucile di %k.,%o は %k のブームスティックを顔面に受けた。,%o 은(는) %k 의 붐스틱에 꽂혔다.,%o gekauwd op %k's boomstick.,%o przygryza pukawkę %k.,%o foi mort@[ao_ptb] pela espingarda de %k.,,%o a mestecat pușca lui %k.,Игрока %o накормил дробью игрок %k.,%o је сажвака@[ao_1_sr] на пумпарицу играча %k. -%o was splattered by %k's super shotgun.,OB_MPSSHOTGUN,,,,%o byl@[ao_cs] rozplesknut@[ao_cs] na kaši superbrokovnicí hráče %k.,%o wurde von %ks Super-Schrotflinte zerfetzt.,@[art_gr] %o διαλύθηκε απο το διπλό ντουφέκι του/της %k,%o estis ŝprucigita per la supera ĉaspafilo de %k.,%o fue reventad@[ao_esp] por la súper escopeta de %k.,,%k roiski %o paran yltympäriinsä superhaulikollaan.,%o s'est fait@[e_fr] gicler par le fusil de chasse de %k.,%o szétloccsant %k szuper sörétespuskája által.,%o è stato smembrato dalla doppietta di %k.,%o は %k のスーパーショットガンでバラバラにされた。,%o 은(는) %k 의 슈퍼 샷건에 의해 터졌다.,%o werd gespat door %k's super jachtgeweer.,%o został@[ao_pl] rozpryskan@[adj_pl] przez super strzelbę %k.,%o foi estraçalhad@[ao_ptb] pela espingarda de cano duplo de %k.,,%o a fost împroșcat de super pușca lui %k.,Игрока %o размазал из обреза игрок %k.,Играча %o је спљоштила двоцевка играча %k. -%o was mowed down by %k's chaingun.,OB_MPCHAINGUN,,,,%o byl@[ao_cs] prostřílen@[ao_cs] kulometem hráče %k.,%o wurde von %ks Maschinengewehr niedergemäht.,@[art_gr] %o κοματίαστηκε απο το πολυβόλο του/της %k.,%o estis kuglo-pleniĝita per la maŝinpafilo de %k.,%o fue masacrado por la ametralladora de %k.,,%k niitti %o paran konekiväärillään.,%o a été ventilé@[e_fr] par la mitrailleuse de %k.,%o szítává lett lőve %k golyószórójának által.,%o è stato falciato dal mitragliatore di %k.,%o は %k のチェーンガンで蜂の巣にされた。,%o 은(는) %k 의 체인건에 의해 으깨졌다.,%o werd gemaaid met %k's machinegeweer.,%o został@[ao_pl] skoszon@[adj_pl] przez karabin maszynowy %k.,%o foi massacrad@[ao_ptb] pela metralhadora de %k.,,%o a fost secerat de mitraliera rotativă a lui %k.,Игрока %o скосил из пулемёта игрок %k.,%o је покоси@[ao_1_sr] митраљез играча %k. -%o rode %k's rocket.,OB_MPROCKET,,,,%o se projel@[ao_cs] na raketě hráče %k.,%o ritt auf %ks Rakete.,@[art_gr] %o καβάλησε τον πύραυλο του/της %k.,%o rajdis la raketon de %k.,%o se montó en el cohete de %k.,%o quería montarse en el cohete de %k.,%o ratsasti pelaajan %k raketilla.,%o a chevauché la roquette de %k.,%o meglovagolta %k rakétáját.,%o ha cavalcato il razzo di %k.,%o は %k のロケットに乗ってしまった。,%o 은(는) %k 의 로켓을 탔다.,%o reed op %k's raket.,%o ujeżdżał@[ao_pl] rakietę %k.,%o não viu o foguete de %k.,%o não viu o míssil de %k.,%o a călărit racheta lui %k.,Игрок %o прокатился на ракете игрока %k.,%o је ујаха@[ao_1_sr] ракету играча %k. -%o almost dodged %k's rocket.,OB_MPR_SPLASH,,,,%o se skoro vyhnul@[ao_cs] raketě hráče %k.,"%o schaffte es fast, %ks Rakete auszuweichen.",@[art_gr] %o σχεδόν απόφηγε τον πύραυλο του/της %k.,%o preskaŭ evitis la raketon de %k.,%o casi esquivó el cohete de %k.,%o casi esquiva el cohete de %k.,%o melkein väisti pelaajan %k raketin.,%o a presque esquivé la roquette de %k.,%o majdnem kikerülte %k rakétáját.,%o aveva quasi schivato il razzo di %k.,%o は %k のロケットをあと少しで避けられそうだった。,%o 은(는) %k 의 로켓 폭발을 거의 피했다.,%o ontweek bijna %k's raket.,%o prawie unika rakiety %k.,%o quase escapou do foguete de %k.,%o quase escapou do míssil de %k.,%o aproape a evitat racheta lui %k.,Игрок %o почти увернулся от ракеты %k.,%o је за длаку избега@[ao_1_sr] ракету играча %k. -%o was melted by %k's plasma gun.,OB_MPPLASMARIFLE,,,,%o se roztekl@[ao_cs] plazmapuškou hráče %k.,%o wurde von %ks Plasmagewehr geschmolzen.,@[art_gr] %o λίοθηκε απο το πλάσμα όπλο του/της %k.,%o estis fandita per la plasmo-pafilo de %k.,%o fue derretid@[ao_esp] por el rifle de plasma de %k.,,%k sulatti %o paran plasmapyssyllään.,%o a été réduit@[e_fr] en bouillie par le fusil a plasma de %k.,%o megolvadt %k Plazma fegyverének által.,%o è stato fuso dal fucile al plasma di %k.,%o は %k のプラズマガンに溶かされた。,%o 은(는) %k 의 플라즈마 건에 의해 융해되었다.,%o was gesmolten door %k's plasmageweer.,%o został@[ao_pl] stopion@[adj_pl] przez pistolet plasmowy %k.,%o foi torrad@[ao_ptb] pelo fuzil de plasma de %k.,%o foi torrad@[ao_ptb] pela pistola de plasma de %k.,%o a fost topit de pușca cu plasmă a lui %k.,Игрока %o расплавил из плазмомёта игрок %k.,%o је отопљен@[adj_1_sr] плазма оружјем играча %k. -%o was splintered by %k's BFG.,OB_MPBFG_BOOM,,,,%o byl@[ao_cs] rozštěpen@[ao_cs] BFGčkem hráče %k.,%o wurde von %ks BFG in Stücke gerissen.,@[art_gr] %o κοματιάστηκε απο το BFG του/της %k.,%o estis disrompita per la BFG de %k.,%o fue aniquilado por la BFG de %k.,,%k pirstoi %o paran BFG:llään.,%o a été oblitéré@[e_fr] par le BFG de %k.,%o szilánkká alakult %k BFG fegyverének által.,%o è stato sminuzzato dal BFG di %k.,%o は %k のBFGで木っ端微塵にされた。,%o 은(는) %k 의 BFG덕에 산산조각 났다.,%o was versplinterd door %k's BFG.,%o został@[ao_pl] rozpryskan@[adj_pl] przez BFG %k.,%o foi vaporizad@[ao_ptb] pela BFG de %k.,,%o a fost despicat de către BFG-ul lui %k.,Игрока %o разорвал выстрел из BFG игрока %k.,%o је расцепан@[adj_1_sr] ВЈП играча %k. -%o couldn't hide from %k's BFG.,OB_MPBFG_SPLASH,,,,%o se nemohl@[ao_cs] ukrýt před BFGčkem hráče %k.,%o konnte sich nicht vor %ks BFG verstecken.,@[art_gr] %o δέν μπόρεσε να κρυφτέι απο το BFG του/της %k.,%o ne povis kaŝi de la BFG-on de %k.,%o no pudo esconderse de la BFG de %k.,,%o ei kyennyt piiloutumaan pelaajan %k BFG:ltä.,%o n a pas pu se couvrir du BFG de %k.,%o nem tudott elmenekülni %k BFG-je elől.,%o non poteva nascondersi dal BFG di %k.,%o は %k のBFGから隠れることはできなかった。,%o 은(는) %k 의 BFG의 일격으로부터 피할 수 없었다.,%o kon zich niet verbergen voor %k's BFG.,%o nie może się schować przed BFG %k.,%o não conseguiu se esconder da BFG de %k,,%o nu s-a putut ascunde de BFG-ul lui %k.,Игрок %o не успел спрятаться от BFG игрока %k.,%o се није мог@[ao_2_sr] сакрити од ВЈП играча %k. -%o was railed by %k.,OB_RAILGUN,,,,%o byl@[ao_cs] napíchnut@[ao_cs] hráčem %k.,%o stand in %ks Schusslinie.,@[art_gr] %o καρφόθηκε απο τον/την %k.,%o estis relita per %k.,%o fue rielad@[ao_esp] por %k.,,%o lävisti %o paran.,%o a été aligné@[e_fr] par %k.,%o nem tudott elmenekülni %k railgun-ja elől.,%o è stato bucherellato dal railgun di %k.,%o は %k のレールガンで死亡した。,%o 은(는) %k 의 레일건에 관통당했다.,%o was met een reling van %k.,%o stał@[ao_pl] na linii ognia %k.,%o estava na mira do canhão elétrico de %k.,,%o a fost ocărit de %k.,Игрока %o пробил насквозь игрок %k.,%o је убијен@[adj_1_sr] од играча %k. -%o was burned by %k's BFG.,OB_MPBFG_MBF,,,,%o shořel@[ao_cs] BFGčkem hráče %k.,%o wurde von %ks BFG verbrannt.,@[art_gr] %o κάικε απο το BFG του/της %k.,%o estis bruligita per la BFG de %k.,%o fue vaporizad@[ao_esp] por la BFG de %k.,,%k korvensi %o paran BFG:llään.,%o a été irradié@[e_fr] par le BFG de %k.,%o meglett égetve %k BFG-je által.,%o è stato bruciato dal BFG di %k.,%o は %k のBFGで焼き殺された。,%o 은(는) %k 의 BFG에 의해 타올랐다.,%o was verbrand door %k's BFG.,%o został@[ao_pl] spalon@[adj_pl] przez BFG %k.,%o foi cozid@[ao_ptb] pela BFG de %k.,,%o a fost ars de BFG-ul lui %k.,Игрока %o сжёг из BFG игрок %k.,%o је изгоре@[ao_1_sr] од ВЈП играча %k. -,,Heretic,,,,,,,,,,,,,,,,,,,,, -,,Pickup ,,,,,,,,,,,,,,,,,,,,, -Blue Key,TXT_GOTBLUEKEY,,,,Modrý klíč,Blauer Schlüssel,Μπλέ Κλειδί,Blua Ŝlosilo,Llave Azul,,Sininen avain,Clé Bleue,Kék Kulcs,Chiave blu,青の鍵,청색 열쇠,Blauwe sleutel,Niebieski klucz,Chave Azul,,Cheie Albastră,Синий ключ,Плави кључ -Yellow Key,TXT_GOTYELLOWKEY,,,,Žlutý klíč,Gelber Schlüssel,Κύτρινο Κλειδί,Flava Ŝlosilo,Llave Amarilla,,Keltainen avain,Clé Jaune,Sárga Kulcs,Chiave gialla,黄の鍵,황색 열쇠,Gele sleutel,Żółty klucz,Chave Amarela,,Cheie Galbenă,Жёлтый ключ,Жути кључ -Green Key,TXT_GOTGREENKEY,,,,Zelený klíč,Grüner Schlüssel,Πράσινο Κλειδί,Verda Ŝlosilo,Llave Verde,,Vihreä avain,Clé Verte,Zöld Kulcs,Chiave verde,緑の鍵,녹색 열쇠,Groene sleutel,Zielony klucz,Chave Verde,,Cheie Verde,Зелёный ключ,Зелени кључ -Quartz Flask,TXT_ARTIHEALTH,,,,Blyštivá baňka,Quarzflasche,Φλάσκα Χαλαζίας,Kvarca Flakono,Frasco de Cuarzo,,Kvartsipullo,Flasque en Quartz,Kvarc Flaska,Ampolla di quarzo,石英フラスコ,석영 플라스크,Kwartskolf,Kwarcowa Butelka,Frasco de Quartzo,,Flacon de Quartz,Кварцевый флакон,Кварцна боца -Wings of Wrath,TXT_ARTIFLY,,,,Křídla hněvu,Flügel des Zorns,Φτερά της Οργής,Flugiloj de Kolero,Alas de Ira,,Kiihtymyksen siivet,Ailes du Courroux,Haragnak Szárnyai,Ali iraconde,レイスの翼,분노의 날개,Vleugels van toorn,Skrzydła Gniewu,Asas da Ira,,Aripile Furiei,Крылья гнева,Крила гнева -Ring of Invincibility,TXT_ARTIINVULNERABILITY,,,,Prsten nesmrtelnosti,Ring der Unverwundbarkeit,Δαχτυλίδι της Αθανασίας,Ringo de Nevenkebleco,Anillo de Invencibilidad,,Näkymättömyyden sormus,Anneau d'Invincibilité,Sérthetetlenség Gyűrűje,Anello dell'invincibilità,不死の指輪,불멸의 반지,Ring van onoverwinnelijkheid,Pierścień Niewrażliwości,Anel da Invencibilidade,,Inelul Invincibilității,Кольцо неуязвимости,Прстен непобедивости -Tome of Power,TXT_ARTITOMEOFPOWER,,,,Kniha moci,Buch der Macht,Τομός της Δύναμης,Librego de Forto,Tomo de Poder,,Väkevyyden kirja,Livre du Pouvoir,Erőnek Kódexe,Tomo del potere,力の術書,힘의 서,Boek van de macht,Tom Mocy,Tomo do Poder,Livro do Poder,Cartea Puterii,Том могущества,Том моћи -Shadowsphere,TXT_ARTIINVISIBILITY,,,,Šerosféra,Schattensphäre,Σκιόσφαιρα,Ombrosfero,Esfera de Sombra,,Varjokehrä,Sphère des Ombres,Sötétgömb,Sfera dell'ombra,闇の球体,그림자 구체,Schaduwrijke plek,Sfera Cieni,Esfera das Sombras,,Sfera Umbrei,Теневая сфера,Сфера сенки -Morph Ovum,TXT_ARTIEGG,,,,Měnivejce,Transformations-Ei,Μετασχηματίζοντικο Ωάριο,Ovo de Transformado,Huevo de Transformación,,Muodonmuutoksen muna,Ovule de Métamorphose,Alakváltó Tojás,Uovo della metamorfosi,変貌の卵子,변신 알,Transformaties-Ei,Jajko Morfujące,Ovo da Metamorfose,,Oul Metamorfozei,Яйцо превращения,Преображавајуће јајашце -Mystic Urn,TXT_ARTISUPERHEALTH,,,,Tajemná urna,Mystische Urne,Μυστικό Δοχείο,Mistika Urno,Urna Mística,,Mystinen uurna,Urne Mystique,Misztikus Urna,Urna mistica,神秘の骨壷,신비한 항아리,Mystieke urn,Mistyczna Urna,Urna Mística,,Urnă Mistică,Мистическая урна,Мистериозна урна -Torch,TXT_ARTITORCH,,,,Pochodeň,Fackel,Πυρσός,Torĉo,Antorcha,,Soihtu,Torche,Fáklya,Torcia,松明,횃불,Fakkel,Pochodnia,Tocha,,Torță,Факел,Бакља -Time Bomb of the Ancients,TXT_ARTIFIREBOMB,,,,Časovaná bomba starověku,Zeitbombe der Alten,Χρονοβόμβα τον Αρχαίων,Tempobombo de la Antikvuloj,Bomba de tiempo de los Ancestros,,Vanhain aikapommi,Bombe a Retardement des Anciens,Ősöknek Időzített Bombája,Bomba a tempo degli antichi,古代の時限爆薬,고대의 시한폭탄,Tijdbom van de Ouderen,Starożytna Bomba Czasu,Bomba-Relógio dos Antigos,,Bomba cu Ceas a Anticilor,Часовая бомба древних,Временска бомба древних -Chaos Device,TXT_ARTITELEPORT,,,,Zmatkostroj,Chaosgerät,Συσκευή του Χάος,Ĥaos-Aparato,Dispositivo del Caos,,Kaaoskoje,Outil du Chaos,Káosz Szerkezet,"Dispositivo del Caos -",カオスデバイス,혼돈의 장치,Chaos apparaat,Urządzenie Chaosu,Dispositivo do Caos,,Dispozitiv al Haosolui,Эмблема Хаоса,Уређај хаоса -Crystal Vial,TXT_ITEMHEALTH,,,,Křišťálový flakón,Kristallfläschchen,Κρυσταλλικό Φιάλιδο,Fiolo de Kristalo,Tubo de Cristal,,Kristallipullo,Fiole de Cristal,Kristály Ampulla,Fiala di cristallo,水晶瓶,수정 약병,Kristallen flesje,Kryształowa Fiolka,Ampola de Cristal,,Fiolă de Cristal,Кристальный флакон,Кристална бочица -Bag of Holding,TXT_ITEMBAGOFHOLDING,,,,Tlumok,Rucksack,Τσάντα Κρατησης,Taŝo de Tenado,Bolso sin Fondo,,Säilön laukku,Sac sans Fond,A Birtoklás Batyuja,Borsa Portaoggetti,持ち物袋,보관용 가방,Zak met holding,Plecak,Bolsa de Utensílios,,Poșetă,Носильный кошель,Торба носивости -Silver Shield,TXT_ITEMSHIELD1,,,,Stříbrný štít,Silberner Schild,Ασημένια Ασπίδα,Arĝenta Ŝildo,Escudo Plateado,,Hopeakilpi,Bouclier d'Argent,Ezüst Pajzs,Scudo d'argento,銀の盾,은 방패,Zilveren Schild,Srebrna Tarcza,Escudo de Prata,,Scut de Argint,Серебряный щит,Сребрни штит -Enchanted Shield,TXT_ITEMSHIELD2,,,,Kouzelný štít,Verzauberter Schild,,Sorĉita Ŝildo,Escudo Encantado,,Lumottu kilpi,Bouclier Enchanté,Bűvös Pajzs,Scudo incantato,魔法の盾,마력 강화 방패,Betoverd schild,Zaklęta Tarcza,Escudo Encantado,,Scut Mistificat,Зачарованный щит,Зачарани штит -Map Scroll,TXT_ITEMSUPERMAP,,,,Mapa,Kartenrolle,,Map-volvolibro,Mapa en Pergamino,,Karttakäärö,Rouleau du Cartographe,Térkép Tekercs,Pergamena della Mappa,地図の巻物,두루마리 지도,Kaartrol,Zwój Mapy,Pergaminho do Mapa,,Hartă Pergament,Свиток карты,Мапа -Wand Crystal,TXT_AMMOGOLDWAND1,,,,Zlaté krystaly,Zauberstabkristall,,Kristalo de Sorĉbastono,Cristal para Vara,,Sauvakristalli,Cristal Elfique,Kristálypor,Bacchetta di cristallo,ワンドクリスタル,지팡이 결정,Toverstokje Kristal,Kryształ do Różdżki,Cristal para o Cetro,,Cristal pentru Toiag,Кристалл для эльфийского жезла,Кристали за штап -Crystal Geode,TXT_AMMOGOLDWAND2,,,,Shluk krystalů,Kristallklumpen,,Kristalgeodo,Geoda de Cristal,,Kristalligeoidi,Géode de Cristal,,Geode di cristallo,晶洞石,결정 원석,Kristal Geode,Kryształowa Geoda,Geodo de Cristal,,Geodă de Cristal,Жеода кристалла,Кристални камен -Mace Spheres,TXT_AMMOMACE1,,,,Žezlometné koule,Keulenkugeln,,Klabsferoj,Esferas de Maza,,Nuijakuulia,Sphère de Masse,Buzogány Gömbök,Sfere per la mazza,メイス球弾,철퇴 포탄,Mace Sferen,Kule do Buzdyganu,Esferas para Clava,,Sfere pentru Buzdugan,Сферы для булавы,Сфере за буздован -Pile of Mace Spheres,TXT_AMMOMACE2,,,,Hromada žezlometných koulí,Haufen von Keulenkugeln,,Stako de Klabsferoj,Pila de Esferas de Maza,,Nuijakuulakasa,Pile de Sphères de Masse,,Pila di sfere per la mazza,メイス球弾の固まり,철퇴 포탄 무더기,Stapel van Mace Sferen,Sterta Kul do Buzdyganu,Pilha de Esferas para Clava,,Grămadă de Sfere pentru Buzdugan,Груда сфер для булавы,Гомила сфера за буздован -Ethereal Arrows,TXT_AMMOCROSSBOW1,,,,Éterické šípy,Ätherische Pfeile,,Eteraj Sagoj,Flechas Etéreas,,Eetterinuolia,Carreaux Ethériques,,Frecce eteree,イセリアルの矢,유체 화살,Etherische Pijlen,Eteryczne Strzały,Flechas Etéreas,,Săgeți Celeste,Эфирные стрелы,Етеричне стреле -Quiver of Ethereal Arrows,TXT_AMMOCROSSBOW2,,,,Toulec éterických šípů,Köcher mit ätherischen Pfeilen,,Sagujo da Eteraj Sagoj,Carcaj de Flechas Etéreas,Carcaza de Flechas Etéreas,Eetterinuoliviini,Carquois de Carreaux Ethériques,,Faretra di frecce eteree,イセリアルの矢筒,유체 화살집,Koker van Etherische Pijlen,Kołczan Eterycznych Strzał,Aljava de Flechas Etéreas,,Tolbă de Săgeți Celeste,Колчан эфирных стрел,Тоболац етеричних стрела -Claw Orb,TXT_AMMOBLASTER1,,,,Pazouří střela,Klauenball,,Kriforbo,Orbe de Garra,,Kynsikehrä,Orbe de Griffe,,Sfera d'artiglio,クローオーブ,발톱 보주,Klauw Bol,Kula do Pazura,Orbe para Garra,Esfera para Garra,Glob pentru Gheară,Когтевой шар,Канџаста сфера -Energy Orb,TXT_AMMOBLASTER2,,,,Silová střela,Energieball,,Energiorbo,Orbe de Energía,,Energiakehrä,Orbe Draconique,,Sfera di energia,エネルギーオーブ,기력의 보주,Energie Bol,Kula Energii,Orbe de Energia,Esfera de Energia,Glob de Energie,Энергетический шар,Енергетска сфера -Lesser Runes,TXT_AMMOSKULLROD1,,,,Menší runy,Kleine Runen,,Runetoj,Runas Menores,,Vähäriimut,Runes Mineurs,,Rune inferiori,レッサールーン,룬 조각,Minder Runen,Gorsze Runy,Runas Inferiores,,Rune Mici,Младшие руны,Нижа руна -Greater Runes,TXT_AMMOSKULLROD2,,,,Větší runy,Große Runen,,Runegoj,Runas Mayores,,Isoriimut,Runes Supérieures,,Rune superiori,グレータールーン,최상급 룬,Grotere Runen,Lepsze Runy,Runas Superiores,,Rune Mari,Старшие руны,Већа руна -Flame Orb,TXT_AMMOPHOENIXROD1,,,,Plamenný náboj,Flammenkugel,,Flamorbo,Orbe de Flama,,Liekkikehrä,Orbe de Flammes,Tűzgömb,Sfera di fuoco,フレイムオーブ,화염 구슬,Vlam Bol,Kula Ognia,Orbe de Chamas,Esfera de Chamas,Glob de Foc,Пламенный шар,Ватрена сфера -Inferno Orb,TXT_AMMOPHOENIXROD2,,,,Pekelný náboj,Infernokugel,,Brulorbo,Orbe de Averno,,Infernokehrä,Orbe Infernal,Pokolgömb,Sfera infernale,インフェルノオーブ,지옥불 구슬,Inferno Bol,Kula Piekielna,Orbe Infernal,Esfera Infernal,Glob Infernal,Инфернальный шар,Пламена сфера -Gold Wand,TXT_WPNGOLDWAND,,,,Zlatá hůl,Goldener Zauberstab,,Ora Sorĉbastono,Vara Dorada,,Kultasauva,Baguette Elfique,Aranypálca,Bacchetta d'oro,ゴールドワンド,황금 지팡이,Gouden Toverstok,Złota Różdżka,Bastão de Ouro,,Toiag cu Aur,Эльфийский жезл,Златни магични штап -Firemace,TXT_WPNMACE,,,,Žezlomet,Feuerkeule,,Fajrklabo,Maza de Fuego,,Tulinuija,Masse de Feu,Tűzbuzogány,"Mazza di fuoco -",ファイアメイス,투사철퇴,Vuurmace,Buzdygan Ognia,Clava de Fogo,,Buzdugan de Foc,Огненная булава,Ватрени буздован -Ethereal Crossbow,TXT_WPNCROSSBOW,,,,Éterická kuše,Ätherische Armbrust,,Etera Arbalesto,Ballesta Etérea,,Eetterivarsijousi,Arbalète Ethérique,Éteri Számszeríj,Balestra eterea,イセリアルクロスボウ,유체 쇠뇌,Etherische kruisboog,Eteryczna Kusza,Besta Etérea,,Arbaletă Celestă,Эфирный арбалет,Етерични самострел -Dragon Claw,TXT_WPNBLASTER,,,,Drakospár,Drachenklaue,,Drakokrifo,Garra de Dragón,,Lohikäärmeenkynsi,Griffe Draconique,Sárkány Karom,Artiglio del drago,ドラゴンクロー,용발톱,Drakenklauw,Smoczy Pazur,Garras do Dragão,,Gheara Dragonului,Коготь дракона,Змајева канџа -Hellstaff,TXT_WPNSKULLROD,,,,Peklopal,Höllenrute,,Inferbastono,Bastón Infernal,,Hornansauva,Bâton Infernal,Pokolpálca,Staffa infernale,ヘルスタッフ,지옥지팡이,Hellestok,Piekielny Kostur,Cajado Infernal,,Baston Infernal,Посох ада,Паклени штап -Phoenix Rod,TXT_WPNPHOENIXROD,,,,Fénixova hůl,Phönixstab,,Feniksvergo,Báculo del Fénix,,Feenikssauva,Bâton du Phénix,Főnix Rúd,Asta della fenice,フェニックスロッド,불사조 지팡이,Feniksstang,Różdżka Feniksa,Bastão da Fenix,,Joarda Phoenix,Жезл феникса,Шипка феникса -Gauntlets of the Necromancer,TXT_WPNGAUNTLETS,,,,Nekromancerovy rukavice,Handschuhe des Zauberers,,Fergantoj de la Nekromancisto,Guanteletes del Nigromante,,Manaajan rautakintaat,Gantelets du Nécromancien,Halottidéző Páncélkesztyűi,Guanti del Negromante,ネクロマンサーの篭手,강령술사의 건틀릿,Handschoenen van de Tovenaar,Rękawice Nekromanty,Manoplas do Necromante,,Mănușile Necromantului,Перчатки некроманта,Рукавице призивача духова -,,Locks,,,,,,,,,,,,,,,,,,,,, -You need a blue key to open this door,TXT_NEEDBLUEKEY,,,,Potřebuješ modrý klíč pro otevření těchto dveří,Du brauchst einen blauen Schlüssel um diese Tür zu öffnen,Χρειάζεσε ένα μπλέ κλειδί για να ενεργοποίησεις αυτη τη πόρτα,Vi bezonas bluan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave azul para abrir esta puerta,,Tarvitset sinisen avaimen avataksesi tämän oven,Cette porte nécessite une clé bleue pour s'ouvrir.,Az ajtó nyitásához szükséged van a kék kulcsra,"Ti serve una chiave blu per aprire questa porta -",開くには 青の鍵が必要だ,이 문을 열기 위해선 청색 열쇠가 필요하다,Je hebt een blauwe sleutel nodig om deze deur te openen.,"Potrzebujesz niebieskiego klucza, by otworzyć te drzwi.",Você precisa da chave azul para abrir essa porta,Precisas da chave azul para abrir esta porta,"Ai nevoie de o cheie albastră pentru a deschide -această ușă",Для открытия нужен синий ключ,Треба вам плави кључ да би отворили ова врата -You need a green key to open this door,TXT_NEEDGREENKEY,,,,Potřebuješ červený klíč pro otevření těchto dveří,Du brauchst einen grünen Schlüssel um diese Tür zu öffnen,Χρειάζεσε ένα πράσινο κλειδί για να ενεργοποίησεις αυτη τη πόρτα,Vi bezonas verdan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave verde para abrir esta puerta,,Tarvitset vihreän avaimen avataksesi tämän oven,Cette porte nécessite une clé verte pour s'ouvrir.,Az ajtó nyitásához szükséged van a zöld kulcsra,"Ti serve una chiave verde per aprire questa porta -",開くには 緑の鍵が必要だ,이 문을 열기 위해선 녹색 열쇠가 필요하다,Je hebt een groene sleutel nodig om deze deur te openen.,"Potrzebujesz zielonego klucza, by otworzyć te drzwi.",Você precisa da chave verde para abrir essa porta,Precisas da chave verde para abrir esta porta,"Ai nevoie de o cheie verde pentru a deschide -această ușă",Для открытия нужен зелёный ключ,Треба вам зелени кључ да би отворили ова врата -You need a yellow key to open this door,TXT_NEEDYELLOWKEY,,,,Potřebuješ žlutý klíč pro otevření těchto dveří,Du brauchst einen gleben Schlüssel um diese Tür zu öffnen,Χρειάζεσε ένα κύτρινο κλειδί για να ενεργοποίησεις αυτη τη πόρτα,Vi bezonas flavan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave amarilla para abrir esta puerta,,Tarvitset keltaisen avaimen avataksesi tämän oven,Cette porte nécessite une clé jaune pour s'ouvrir.,Az ajtó nyitásához szükséged van a sárga kulcsra,Ti serve una chiave gialla per aprire questa porta,開くには 黄の鍵が必要だ,이 문을 열기 위해선 황색 열쇠가 필요하다,Je hebt een gele sleutel nodig om deze deur te openen.,"Potrzebujesz żółtego klucza, by otworzyć te drzwi.",Você precisa da chave amarela para abrir essa porta,Precisas da chave amarela para abrir esta porta,"Ai nevoie de o cheie galbenă pentru a deschide -această ușă",Для открытия нужен жёлтый ключ,Треба вам жути кључ да би отворили ова врата -,,Actor tag names,,,,,,,,,,,,,,,,,,,,, -Chicken,FN_CHICKEN,,,,Slepice,Huhn,Κότα,Koko,Pollo,,Kana,Poulet,Csirke,Pollo,鶏,닭,Kip,Kurczak,Galinha,,Găină,Цыплёнок,Кокошка -Weredragon,FN_BEAST,,,,Vlkodrak,Werdrache,Θηρίο,Lupdrako,Bestia dragón,,Ihmislohikäärme,Dragon-garou,Vérsárkány,Drago Mannaro,ウェア ドラゴン,웨어드래곤,Weerdraak,Smokołak,Homem-dragão,,Vârcodragon,Дракон-оборотень,Змајодлак -Sabreclaw,FN_CLINK,,,,Šavlozub,Säbelklaue,,Sabrokrifo,Garra de sable,,Sapelikynsi,Sabregriffe,Szablyakarom,Lamartiglio,サーベルクロー,세이버클로,Sabelklauw,Szabloszpon,Unhas-de-Sabre,,Gheară de Sabie,Саблекоготь,Тигар -D'Sparil,FN_DSPARIL,,,,D'Sparil,,,,,,,D'Sparil,,D'Sparil,デ'スパリル,드'스파릴,D'Sparil,D'Sparil,,,D'Sparil,Д'Спарил,Д'Спарил -Gargoyle,FN_HERETICIMP,,,,Chrlič,,,Gargojlo,Gárgola,,Gargoili,Gargouille,Vízköpő,Gargoyle,ガーゴイル,가고일,,Gargulec,Gárgula,,Garguie,Горгулья,Камена утвара -Ironlich,FN_IRONLICH,,,,Železný kostěj,Eiserne Leiche,,Ferliĉo,Liche de hierro,,Rautakalmo,Liche de Fer,Ezüst Lich,Lich di Ferro,アイアンリッチ,아이언 리치,IJzeren lijk,Żelazny Lisz,Lich de Ferro,,Cadavru de Fier,Железный лич,Челични лич -Undead Warrior,FN_BONEKNIGHT,,,,Nemrtvý válečník,Untoter Krieger,Αθάνατος Πολεμιστής,Malviva Batalisto,Guerrero no-muerto,,Epäkuollut soturi,Guerrier Mort-Vivant,Élőhalott Harcos,Guerriero Non Morto,アンデット兵,언데드 전사,Ondoden Krijger,Nieumarły wojownik,Guerreiro Morto-vivo,,Războinic Nemort,Воин-нежить,Немртви ратник -Maulotaur,FN_MINOTAUR,,,,Mínotaurus,Minotaurus,Μινόταυρος,Bategtaŭro,Maulotauro,,Maulotauri,Massetaure,,Maulotauro,マウロタウロス,몰로타우어,Maulotaurus,Młototaur,Marretauro,,Maulotaur,Молотавр,Минотаур -Golem,FN_MUMMY,,,,Golém,,,Golemo,,,,Golem,Gólem,Golem,ゴーレム,골렘,,Golem,,,Golem,Голем,Голем -Nitrogolem,FN_MUMMYLEADER,,,,Střelgolém,,,Azotgolemo,,,,Nitrogolem,Nitrógólem,Nitrogolem,ニトロゴーレム,니트로 골렘,,Nitrogolem,,,Nitrogolem,Нитроголем,Нитро голем -Ophidian,FN_SNAKE,,,,Šupinatec,,,Ofidio,Ofidio,,Käärmeolio,Ophidien,Ofidián,Ophidian,オフィディアン,오피디안,Ophidiaan,Wężowaty,Ofídio,,Ofidian,Офидиан,Змија -Wizard,FN_WIZARD,,,,Čaroděj,Zauberer,Μάγος,Sorĉisto,Mago,,Velho,Magicien,Mágus,Mago,ウィザード,마법사,Tovenaar,Czarownik,Mago,,Vrăjitor,Колдун,Чаробњак -Wand Crystals,AMMO_GOLDWAND,,,,Zlaté krystaly,Elfenstabkristalle,,Sorĉbastono-kristalo,Cristales para vara,,Sauvakristalleja,Cristaux,Pálca Kristályok,Cristalli per la bacchetta,ワンド クリスタル,지팡이 결정,Toverstaf kristallen,Kryształy do Różdżki,Cristais para o Cetro,,Cristale pentru Toiag,Кристалл для эльфийского жезла,Кристали за штап -Ethereal Arrows,AMMO_CROSSBOW,,,,Éterické šípy,Ätherische Pfeile,,Eteraj Sagoj,Flechas etéreas,,Eetterinuolia,Carreaux,Éteri Nyilak,Frecce eteree,イセリアルの矢,유체 화살,Etherische Pijlen,Eteryczne Strzały,Flechas Etéreas,,Săgeți Celeste,Эфирные стрелы,Етеричне стреле -Claw Orbs,AMMO_BLASTER,,,,Pazouří střely,Klauenbälle,,Kriforboj,Orbes de garra,,Kynsikehriä,Orbes,Karom Golyók,Sfere di artigli,クロー オーブ,발톱 보주,Klauw Bollen,Kule do Pazura,Orbes para Garra,,Globuri pentru Gheară,Когтевой шар,Канџаста сфера -Mace Spheres,AMMO_MACE,,,,Žezlometné koule,Energiebälle,,Klabsferoj,Esferas de maza,,Nuijakuulia,Sphères,Buzogány Gömbök,Sfere per la mazza,メイス スフィア,철퇴 포탄,Mace Sferen,Kule do Buzdyganu,Esferas para Clava,,Sfere pentru Buzdugan,Сферы для булавы,Сфере за буздован -Hellstaff Runes,AMMO_SKULLROD,,,,Peklopalné runy,Höllenrutenrunen,,Inferbastono-runoj,Runas de Vara Infernal,,Hornansauvan riimuja,Runes,Pokolbot Rúnák,Rune infernali,ヘルスタッフ ルーン,룬 조각,Hellestok Runen,Runy do Piekielnego Kostura,Runas Infernais,,Rune pentru Bastonul Infernal,Руны посоха ада,Пуне за паклени штап -Flame Orbs,AMMO_PHOENIXROD,,,,Plamenné náboje,Flammenkugeln,,Fajrorboj,Orbes de llama,Orbes de flama,Liekkikehriä,Orbes de Feu,Tűzgolyók,Sfere di fuoco,フレイム オーブ,화염 구슬,Vlam Bollen,Kule Ognia,Orbes de Chamas,,Globuri de Foc,Пламенный шар,Ватрена сфера -Staff,TAG_STAFF,,,,Hole,Stab,Ράβδος,Bastono,Bastón,,Sauva,Bâton,Bot,Staffa,杖,지팡이,Staf,Kostur,Bastão,,Baston,Посох,Штап -Gauntlets of the Necromancer,TAG_GAUNTLETS,,,,Nekromancerovy rukavice,Handschuhe des Zauberers,,Fergantoj de la Nekromancisto,Guanteletes del Nigromante,,Manaajan rautakintaat,Gantelets du Nécromancien,Halottidéző Páncélkesztyűi,Guanti del Negromante,ネクロマンサーの篭手,강령술사의 건틀릿,Handschoenen van de Tovenaar,Rękawice Nekromanty,Manoplas do Necromante,,Mănușile Necromantului,Перчатки некроманта,Рукавице призивача духова -Elven Wand,TAG_GOLDWAND,,,,Elfská hůl,Elfenstab,,Elfa Sorĉbastono,Vara de Elfo,,Haltiasauva,Baguette Elfique,Elf Pálca,Scettro Elfico,エルフのワンド,엘프 지팡이,Elven Toverstaf,Elfia Różdżka,Cetro Élfico,,Toiagul Elfilor,Эльфийский жезл,Вилењачки штапић -Ethereal Crossbow,TAG_CROSSBOW,,,,Éterická kuše,Ätherische Armbrust,,Etera Arbalesto,Ballesta Etérea,,Eetterivarsijousi,Arbalète Etherique,Éteri Nyílpuska,Balestra Eterea ,イセリアルクロスボウ,유체 쇠뇌,Etherische kruisboog,Eteryczna Kusza,Besta Etérea,,Arbaletă Celestă,Эфирный арбалет,Етерични самострел -Dragon Claw,TAG_BLASTER,,,,Drakospár,Drachenklaue,,Drakokrifo,Garra de Dragón,,Lohikäärmeenkynsi,Griffe Draconique,Sárkány Karom,Artiglio del Drago ,ドラゴンの鉤爪,용발톱,Drakenklauw,Smoczy Pazur,Garra de Dragão,,Gheara Dragonului,Драконий коготь,Змајева канџа -Hellstaff,TAG_SKULLROD,,,,Peklopal,Höllenrute,,Inferbastono,Bastón infernal,,Hornansauva,Bâton Infernal,Pokolbot,Staffa Infernale ,ヘルスタッフ,지옥지팡이,Hellestok,Piekielny Kostur,Cajado Infernal,,Baston Infernal,Посох ада,Паклени штап -Phoenix Rod,TAG_PHOENIXROD,,,,Fénixova hůl,Phönixstab,,Feniksvergo,Báculo del Fénix,,Feenikssauva,Bâton du Phénix,Főnix Rúd,Bastone della Fenice,フェニックスロッド,불사조 지팡이,Phoenixstang,Różdżka Feniksa,Bastão da Fênix,,Joarda Phoenix,Жезл феникса,Шипка феникса -Firemace,TAG_MACE,,,,Žezlomet,Feuerkeule,,Fajrklabo,Maza de Fuego,,Tulinuija,Masse de Feu,Tűzbuzogány,Mazza del Fuoco ,ファイアメイス,투사철퇴,Vuurmace,Buzdygan Ognia,Clava de Fogo,,Buzdugan de Foc,Огненная булава,Ватрени буздован -Staff,TAG_STAFFP,,,,Hůl,Stab,Ράβδος,Bastono,Bastón,,Sauva,Bâton,Bot,Staffa ,杖,마법부가 지팡이,Staf,Kostur,Bastão,,Baston,Посох,Штап -Gauntlets of the Necromancer,TAG_GAUNTLETSP,,,,Nekromancerovy rukavice,Handschuhe des Zauberers,,Fergantoj de la Nekromancisto,Guanteletes del Nigromante,,Manaajan rautakintaat,Gantelets du Nécromancien,Halottidéző Páncélkesztyűi,Guanti del Negromante,ネクロマンサーの篭手,마법부가 강령술사 건틀릿,Handschoenen van de Tovenaar,Rękawice Nekromanty,Manoplas do Necromante,,Mănușile Necromantului,Перчатки некроманта,Рукавице некроманцера -Elven Wand,TAG_GOLDWANDP,,,,Elfská hůlka,Elfenstab,,Elfa Sorĉbastono,Vara de Elfo,,Haltiasauva,Baguette Elfique,Elf Pálca,Scettro Elfico,エルフのワンド,마법부가 엘프 지팡이,Elven Toverstaf,Elfia Różdżka,Cetro Élfico,,Toiagul Elfilor,Эльфийский жезл,Вилењачки штапић -Ethereal Crossbow,TAG_CROSSBOWP,,,,Éterická kuše,Ätherische Armbust,,Etera Arbalesto,Ballesta Etérea,,Eetterivarsijousi,Arbalète Etherique,Éteri Nyílpuska,Balestra Eterea ,イセリアルクロスボウ,마법부가 유체 쇠뇌,Etherische kruisboog,Eteryczna Kusza,Besta Etérea,,Arbaletă Celestă,Эфирный арбалет,Етерични самострел -Dragon Claw,TAG_BLASTERP,,,,Drakospár,Drachenklaue,,Drakokrifo,Garra de Dragón,,Lohikäärmeenkynsi,Griffe Draconique,Sárkány Karom,Artiglio del Drago ,ドラゴンの鉤爪,마법부가 용발톱,Drakenklauw,Smoczy Pazur,Garra de Dragão,,Gheara Dragonului,Коготь дракона,Змајева канџа -Hellstaff,TAG_SKULLRODP,,,,Peklopal,Höllenrute,,Inferbastono,Bastón infernal,,Hornansauva,Bâton Infernal,Pokolbot,Staffa Infernale ,ヘルスタッフ,마법부가 지옥지팡이,Hellestok,Piekielny Kostur,Cajado Infernal,,Baston Infernal,Посох ада,Мотка пакла -Phoenix Rod,TAG_PHOENIXRODP,,,,Fénixova hůl,Phönixstab,,Feniksvergo,Báculo del Fénix,,Feenikssauva,Bâton du Phénix,Főnix Rúd,Bastone della Fenice,フェニックスロッド,마법부가 불사조 지팡이,Feniksstang,Różdżka Feniksa,Bastão da Fênix,,Joarda Phoenix,Жезл феникса,Фениксов прут -Firemace,TAG_MACEP,,,,Žezlomet,Feuerkeule,,Fajrklabo,Maza de Fuego,,Tulinuija,Masse de Feu,Tűzbuzogány,Mazza del Fuoco ,ファイアメイス,마법부가 투사철퇴,Vuurmace,Buzdygan Ognia,Clava de Fogo,,Buzdugan de Foc,Огненная булава,Ватрени буздован -Morph Ovum,TAG_ARTIEGG,,,,Měnivejce,Transformations-Ei,,Ovo de Transformado,Huevo de Transformación,,Muodonmuutoksen muna,Ovule de Métamorphose,Átváltoztató Gömb,Morph Ovum,変貌の卵子,변신 알,Transformaties-Ei,Jajko Morfujące,Ovo da Metamorfose,,Oul Metamorfozei,Яйцо превращения,Преображајyће јајашце -Time Bomb of the Ancients,TAG_ARTIFIREBOMB,,,,Časovaná bomba starověku,Zeitbombe der Alten,,Tempobombo de la Antikvuloj,Bomba de tiempo de los Ancestros,,Vanhain aikapommi,Bombe a retardement des Anciens,Ősiek Időbombája,Bomba a Tempo degli Antichi,古代の時限爆薬,고대의 시한폭탄,Tijdbom van de Ouderen,Starożytna Bomba Czasu,Bomba-relógio dos Antigos,,Bomba cu Ceas a Anticilor,Часовая бомба древних,Временска бомба древних -Wings of Wrath,TAG_ARTIFLY,,,,Křídla hněvu,Flügel des Zorns,,Flugiloj de Kolero,Alas de Ira,,Kiihtymyksen siivet,Ailes du Courroux,Harag Szárnyai,Ali Iraconde,レイスの翼,분노의 날개,Vleugels van toorn,Skrzydła Gniewu,Asas da Ira,,Aripile Furiei,Крылья гнева,Крила гнева -Quartz Flask,TAG_ARTIHEALTH,,,,Blyštivá baňka,Quarzflasche,,Kvarca Flakono,Frasco de Cuarzo,,Kvartsipullo,Flasque en Quartz,Kvarc Flaska,Fiaschetta al Quarzo,石英フラスコ,석영 플라스크,Kwartskolf,Kwarcowa Butelka,Frasco de Quartzo,,Flacon de Quartz,Кварцевый флакон,Кварцна боца -Shadowsphere,TAG_ARTIINVISIBILITY,,,,Šerosféra,Schattensphäre,Σκιόσφαιρα,Ombrosfero,Esfera de Sombra,,Varjokehrä,Orbe des Ombres,Sötétgömb,Ombrosfera,闇の球体,그림자 구체,Schaduwrijke plek,Sfera Cieni,Esfera das Sombras,,Sfera Umbrei,Теневая сфера,Сфера сенки -Ring of Invincibility,TAG_ARTIINVULNERABILITY,,,,Prsten nesmrtelnosti,Ring der Unverwundbarkeit,,Ringo de Nevenkebleco,Anillo de Invencibilidad,,Näkymättömyyden sormus,Anneau d'Invincibilité,Sérthetetlenség Gyűrűje,Anello dell'invincibilità,不死の指輪,불멸의 반지,Ring van onoverwinnelijkheid,Pierścień Niewrażliwości,Anel da Invencibilidade,,Inelul Invincibilității,Кольцо неуязвимости,Прстен непобедивости -Mystic Urn,TAG_ARTISUPERHEALTH,,,,Tajemná urna,Mystische Urne,,Mistika Urno,Urna Mística,,Mystinen uurna,Urne Mystique,Misztikus Urna,Urna Mistica,神秘の骨壷,신비한 항아리,Mystieke urn,Mistyczna Urna,Urna Mística,,Urnă Mistică,Мистическая урна,Мистериозна урна -Chaos Device,TAG_ARTITELEPORT,,,,Zmatkostroj,Chaosgerät,Συσκευή του Χάος,Ĥaos-aparato,Dispositivo del Caos,,Kaaoskoje,Outil du Chaos,Káosz Eszköz,Strumento del Caos,カオスデバイス,혼돈의 장치,Chaos apparaat,Urządzenie Chaosu,Dispositivo do Caos,,Dispozitiv al Haosului,Механизм хаоса,Уређај хаоса -Tome of Power,TAG_ARTITOMEOFPOWER,,,,Kniha moci,Buch der Macht,Τόμος της Δύναμης,Librego de Potenco,Tomo de Poder,,Väkevyyden kirja,Livre du Pouvoir,Erő Kódexe,Tomo del Potere,力の術書,힘의 서,Boek van de macht,Tom Mocy,Tomo do Poder,,Cartea Puterii,Том могущества,Табла моћи -Torch,TAG_ARTITORCH,,,,Pochodeň,Fackel,Πύρσος,Torĉo,Antorcha,,Soihtu,Torche,Fáklya,Torcia ,松明,횃불,Fakkel,Pochodnia,Tocha,Torcha,Torță,Факел,Бакља -,,Obituaries,,,,,,,,,,,,,,,,,,,,, -%o was pecked to death.,OB_CHICKEN,,,,%o byl@[ao_cs] uklován@[ao_cs] k smrti.,%o wurde zu Tode gepickt.,,%o estis bekita ĝis morto.,%o fue picotead@[ao_esp] hasta la muerte.,,%o nokittiin kuoliaaksi.,%o a été picoré@[e_fr] a mort.,%o halálra lett csípve.,%o è stato beccato a morte.,%o はくちばしで突かれ死んだ。,%o 은(는) 쪽팔리게 쪼여 죽었다.,%o werd doodgepikt.,%o został@[ao_pl] zadzioban@[adj_pl] na śmierć.,%o foi bicad@[ao_ptb] até a morte.,%o foi picad@[ao_ptb] até a morte.,%o a fost ciocănit până la moarte.,Игрока %o заклевал до смерти цыплёнок.,%o је искљуцан@[adj_1_sr] до смрти. -%o was charred by a weredragon.,OB_BEAST,,,,%o byl@[ao_cs] spálen@[ao_cs] vlkodrakem.,%o wurde von dem Werdrachen verschmort.,,%o brulegiĝis per lupdrako.,%o fue carbonizad@[ao_esp] por una bestia dragón.,,%o joutui ihmislohikäärmeen kärventämäksi.,%o a été carbonisé@[e_fr] par un dragon-garou.,%o szénné égett egy Vérsárkány által.,%o è stato carbonizzato da una bestia.,%o はウェアドラゴンに黒焦げにされた。,%o 은(는) 웨어드래곤에 의해 검게 탔다.,%o werd verbrand door een weerdraak.,%o został@[ao_pl] zwęglon@[adj_pl] przez smokołaka.,%o foi carbonizad@[ao_ptb] por um homem-dragão.,,%o a fost ceruit de un vârcodragon.,Игрока %o обуглил дракон-оборотень.,%o је реш печен@[adj_1_sr] од стране замјодлака. -%o was slashed by a sabreclaw.,OB_CLINK,,,,%o byl@[ao_cs] rozsápán@[ao_cs] šavlozubem.,%o wurde von der Säbelklaue zerschlitzt.,,%o tranĉegiĝis per sabrokrifo.,%o fue acuchillad@[ao_esp] por un garra de sable.,,%o joutui sapelikynnen sivaltamaksi.,%o s'est fait découper par un sabregriffe.,%o meglett vágva egy Szablyakarom által.,%o è stato squarciato da un lapillo.,%o はサーベルクローに切り裂かれた。,%o 은(는) 세이버클로에게 잘렸다.,%o werd door een sabelklauw gesneden.,%o został@[ao_pl] posiekan@[adj_pl] przez szabloszpona.,%o foi cortad@[ao_ptb] por um unhas-de-sabre.,,%o a fost tăiat de o gheară de sabie.,Игрока %o нарезал саблекоготь.,Играча %o је исекао тигар. -%o was scalded by D'Sparil's serpent.,OB_DSPARIL1,,,,%o byl@[ao_cs] zpopelněn@[ao_cs] ořem D'Sparila.,%o wurde von D'Sparils Schlange verbrüht.,,%o varmegiĝis per la serpento de D'Sparil.,%o fue abrasad@[ao_esp] por la serpiente de D'Sparil.,,%o joutui D'Sparilin käärmeen kalttaamaksi.,%o a été ébouillanté@[e_fr] par un serpent de D'Sparil.,%o le lett forrázva D'Sparil Kígyója által.,%o è stato bruciato dal serpente di D'Sparil.,%o はデ'スパリルのサーペントに火傷を負わされた。,%o 은(는) 드'스파릴의 서펜트에 데였다.,%o werd gebroeid door de slang van D'Sparil.,%o został@[ao_pl] poparzon@[adj_pl] przez węża D'Sparila.,%o foi escaldad@[ao_ptb] pela serpente de D'Sparil.,,%o a fost opărit de șarpele lui D'Sparil.,Игрока %o обжёг серпент Д'Спарила.,Играча %o је опекао Д'Спарилова змија. -%o was chewed up by D'Sparil's serpent.,OB_DSPARIL1HIT,,,,%o byl@[ao_cs] rozkousán@[ao_cs] ořem D'Sparila.,%o wurde von D'Sparils Schlange verspeist.,,%o maĉegiĝis per la serpento de D'Sparil.,%o fue engullid@[ao_esp] por la serpiente de D'Sparil.,,%o joutui D'Sparilin käärmeen pureksimaksi.,%o a été dévoré@[e_fr] par un serpent de D'Sparil.,%o meglett rágva D'Sparil Kigyója által.,%o è stato masticato dal serpente di D'Sparil.,%o はデ'スパリルのサーペントに噛み砕かれた。,%o 은(는) 드'스파릴의 서펜트에게 씹혔다.,%o werd door de slang van D'Sparil opgekauwd.,%o został@[ao_pl] przeżut@[adj_pl] przez węża D'Sparila.,%o foi mastigad@[ao_ptb] pela serpente de D'Sparil.,,%o a fost mestecat de șarpele lui D'Sparil.,Игрока %o пожрал серпент Д'Спарила.,%o је сажвакан@[adj_1_sr] од стране Д'Спарилове змије. -%o was no match for D'Sparil.,OB_DSPARIL2,,,,%o nebyl@[ao_cs] pro D'Sparila žádná výzva.,%o war kein Gegner für D'Sparil.,,%o ne estis rivalo por D'Sparil. ,%o no fue rival para D'Sparil.,,%o ei mahtanut mitään D'Sparilille.,%o n'a pas pu égaler D'Sparil.,%o nem volt mértó ellenfél D'Sparil számára.,%o non era all'altezza di D'Sparil.,%o はデ'スパリルには全く歯が立たなかった。,%o 은(는) 드'스파릴에겐 상대가 되지 못했다.,%o was geen partij voor D'Sparil.,%o nie miał@[ao_pl] szans z D'Sparilem.,%o não foi páreo para D'Sparil.,%o não foi desafio para D'Sparil.,%o n-a fost nici pe departe pe măsura lui D'Sparil.,%o был@[ao_rus] не ровня Д'Спарилу.,%o није ни до колена Д'Спарилу. -%o was smacked down by D'Sparil.,OB_DSPARIL2HIT,,,,%o byl@[ao_cs] sražen@[ao_cs] D'Sparilem.,%o wurde von D'Sparil zerklatscht.,,%o frapiĝis per D'Sparil.,%o fue vapulead@[ao_esp] por D'Sparil.,%o ha sido golpead@[ao_esp] por D'Sparil.,%o joutui D'Sparilin löylyttämäksi.,%o a été battu@[e_fr] a plate couture par D'Sparil.,%o a földre lett csapva D'Sparil által.,%o è stato abbattuto da D'Sparil.,%o はデ'スパリルに打ち負かされた。,%o 은(는) 드'스파릴의 맹격에 쓰러졌다.,%o werd neergeslagen door D'Sparil.,%o został@[ao_pl] roztrzaskan@[adj_pl] przez D'Sparila,%o foi mort@[ao_ptb] por D'Sparil.,,%o a fost pus la pământ de D'Sparil.,Игрока %o сбил Д'Спарил.,%o је претучен@[adj_1_sr] од стране Д'Спарила. -%o was scarred by a gargoyle.,OB_HERETICIMP,,,,%o byl@[ao_cs] upálen@[ao_cs] chrličem.,%o wurde von einem Gargoyle zerkratzt.,,%o ĉikartiĝis per gargojlo.,%o fue cicatrizad@[ao_esp] por una gárgola.,,%o joutui gargoilin arpeuttamaksi.,%o a été effrayé@[e_fr] par une gargouille.,%o meglett sebesítve egy Vízköpő által.,%o è stato terrorizzato da un imp.,%o はガーゴイルに傷を負わされた。,%o 은(는) 가고일에 의해 다쳤다.,%o was getekend door een gargoyle.,%o został@[ao_pl] zadrapan@[adj_pl] przez gargulca,%o foi cicatrizad@[ao_ptb] por uma gárgula.,,%o a fost cicatrizat de o garguie.,Игрока %o изуродовала горгулья.,%o је ожиљкан@[adj_1_sr] од стране камене утваре. -%o was hacked by a gargoyle.,OB_HERETICIMPHIT,,,,%o byl@[ao_cs] rozsekán@[ao_cs] chrličem.,%o wurde von einem Gargoyle zerhackt.,,%o hakiĝis per gargojlo.,%o fue arañad@[ao_esp] por una gárgola.,,%o joutui gargoilin pilkkomaksi.,%o a été mis@[e_fr] en pièces par une gargouille.,%o fel lett vágva egy Vízköpő által.,%o è stato eliminato da un imp.,%o はガーゴイルに切り刻まれた。,%o 은(는) 가고일에 의해 베였다.,%o werd gehackt door een gargoyle.,%o został@[ao_pl] pocięt@[adj_pl] przez gargulca,%o foi mutilad@[ao_ptb] por uma gárgula.,,%o a fost tăiat de o garguie.,Игрока %o покалечила горгулья.,Играча %o је исекла камена утвара. -%o was devastated by an ironlich.,OB_IRONLICH,,,,%o byl@[ao_cs] zničen@[ao_cs] železným kostějem.,%o wurde von der Eisernen Leiche zerstört.,,%o ruiniĝis per ferliĉo.,%o fue devastad@[ao_esp] por un liche de hierro.,,%o joutui rautakalmon hävittämäksi.,%o a été dévasté@[e_fr] par une Liche de Fer.,%o elpusztult egy Vastetem által.,%o è stato devastato da un ironlich.,%o はアイアンリッチに吹き飛ばされた。,%o 은(는) 아이언 리치에게 붕괴 당했다.,%o werd verwoest door een irjzeren lijk.,%o został@[ao_pl] zdewastowan@[adj_pl] przez żelaznego lisza,%o foi devastad@[ao_ptb] por um lich de ferro.,,%o a fost devastat de un cadavru de fier.,Игрока %o растоптал железный лич.,%o је уништен@[adj_1_sr] од стране челичног лича. -%o got up-close and personal with an ironlich.,OB_IRONLICHHIT,,,,%o se dostal@[ao_cs] moc blízko k železnému kostěji.,%o kam der Eisernen Leiche zu nahe.,,%o havis proksiman kaj personan rekonton kun ferliĉo.,%o tuvo un encuentro cercano y personal con un liche de hierro.,,%o meni lähelle rautakalmoa.,%o a fait ami@[e_fr]-ami@[e_fr] avec une Liche de Fer.,%o közel került és személyes volt egy Vastetemmel szemben.,%o è andato troppo vicino a un ironlich.,%o はアイアンリッチと密接に関わった。,%o 은(는) 사적인 이유로 아이언 리치에게 다가왔다.,%o kwam dicht en persoonlijk met een irjzeren lijk op de proppen.,%o był@[ao_pl] blisko i na osobności z żelaznym liszem,%o chegou muito perto de um lich de ferro.,,"%o s-a apropiat prea mult si prea personal de un -cadavru de fier.",%o сближал@[refl_rus] с железным личем.,%o се лично приближи@[ao_1_sr] челичном личу. -%o was axed by an undead warrior.,OB_BONEKNIGHT,,,,%o dostal@[ao_cs] sekyrou od nemrtvého válečníka.,%o wurde von dem Untoten Krieger mit der Axt bearbeitet.,,%o hakiliĝis per malviva batalisto.,%o recibió un hachazo de un guerrero no-muerto.,,%o joutui epäkuolleen soturin kirvestämäksi.,%o s'est pris@[e_fr] la hâche d'un guerrier mort-vivant.,%o baltát kapott egy Élőhalott Harcostól.,%o è stato accettato da un guerriero non morto .,%o はアンデッド兵の斧でやられた。,%o 은(는) 언데드 전사에게 도끼질 당했다.,%o werd bijgezet door een ondode krijger.,%o został@[ao_pl] rozłupany siekierą przez nieumarłego wojownika,%o foi decepad@[ao_ptb] por um guerreiro morto-vivo.,%o foi decapitad@[ao_ptb] por um guerreiro morto-vivo.,%o a primit un topor de la un războinic nemort.,Игрока %o зарубил воин-нежить.,%o је исечен@[adj_1_sr] од стане немртвог ратника. -%o was slain by an undead warrior.,OB_BONEKNIGHTHIT,,,,%o byl@[ao_cs] zabit@[ao_cs] nemrtvým válečníkem.,%o wurde von dem Untoten Krieger hingemetzelt.,,%o estis mortigita per malviva batalisto.,%o fue descuartizad@[ao_esp] por un guerrero no-muerto.,,%o joutui epäkuolleen soturin tappamaksi.,%o s'est fait pourfendre par un guerrier mort-vivant.,%o meghalt egy Élőhalott Harcos által.,%o è stato ucciso da un guerriero non morto. ,%o はアンデッド兵の手で葬られた。,%o 은(는) 언데드 전사에게 처단당했다.,%o werd gedood door een ondode krijger.,%o został@[ao_pl] zgładzon@[adj_pl] przez nieumarłego wojownika,%o foi picotad@[ao_ptb] por um guerreiro morto-vivo.,,%o a fost omorât de un războinic nemort.,Игрока %o сразил воин-нежить.,Играча %o је убио немртви ратник. -%o was blasted into cinders by a Maulotaur.,OB_MINOTAUR,,,,%o byl@[ao_cs] rozmetán@[ao_cs] na popel Mínotaurem.,%o wurde von dem Minotaurus in Asche verwandelt.,,%o eksplodiĝis en cindrojn per Bategtaŭro.,%o fue volad@[ao_esp] en cenizas por un Maulotauro.,,%o tuhottiin tuusan nuuskaksi maulotaurin toimesta.,%o s'est fait@[e_fr] incinérer par un Massetaure.,%o darabokra robbant egy Maulotaurusz által.,%o è stato incenerito da un Maulotaur. ,%o はマウロタウロスに燃やされ炭化した。,%o 은(는) 몰로타우어에게 잿더미가 되도록 파괴당했다.,%o werd door een Maulotaurus in sintels geblazen.,%o został@[ao_pl] obrócon@[adj_pl] w popiół przez Młototaura,%o foi incinerad@[ao_ptb] por um Marretauro,,%o a fost făcut cenușă de un Maulotaur.,Игрока %o разнёс на сгоревшие части Молотавр.,%o је испуцан@[adj_1_sr] у пепео од стране минотаура. -%o was pulped by a Maulotaur.,OB_MINOTAURHIT,,,,%o byl@[ao_cs] rozmáčknut@[ao_cs] Mínotaurem.,%o wurde von dem Minotaurus zu Brei verarbeitet.,,%o pulpiĝis per Bategtaŭro.,%o fue pulpad@[ao_esp] por un Maulotauro.,,%o joutui maulotaurin möyhentämäksi.,%o s'est fait@[e_fr] éclater par un Massetaure.,%o péppé lett zúzva egy Maulotaurusz által.,%o è stato ridotto in poltiglia da un Maulotaur. ,%o はマウロタウロスにグシャグシャにされた。,%o 은(는) 몰로타우어에 의해 내동댕이쳐졌다.,%o werd verpulverd door een Maulotaurus.,%o został@[ao_pl] roztart@[adj_pl] na miazgę przez Młototaura,%o foi esmagad@[ao_ptb] por um Marretauro,,%o a fost descojit de un Maulotaur.,Игрока %o превратил в кровавое месиво Молотавр.,Играча %o је претукао минотаур. -%o was smashed by a golem.,OB_MUMMY,,,,%o byl@[ao_cs] umlácen@[ao_cs] golémem.,%o wurde von einem Golem erschlagen.,,%o frakasiĝis per golemo.,%o fue aplastad@[ao_esp] por un golem.,,%o joutui golemin murskaamaksi.,%o a été défoncé@[e_fr] par un golem.,%o összelett törve egy Gólem által.,%o è stato schiacciato da una mummia.,%o はゴーレムに叩きのめされた。,%o 은(는) 골렘에게 두들겨 맞았다.,%o werd verbrijzeld door een golem.,%o został@[ao_pl] stłuczon@[adj_pl] przez golema,%o foi esmagad@[ao_ptb] por um golem.,,%o a fost lovit de un golem.,Игрока %o разбил голем.,Играча %o је смрвио голем. -%o was shrieked to death by a nitrogolem.,OB_MUMMYLEADER,,,,%o byl@[ao_cs] ukřičen@[ao_cs] k smrti střelgolémem.,%o wurde von einem Nitrogolem zu Tode gekreischt.,,%o estis kriegita ĝis morto per azotgolemo.,%o fue chillad@[ao_esp] hasta la muerte por un nitrogolem.,%o ha sido aplanad@[ao_esp] hasta la muerte por un nitrogolem.,%o kirkaistiin kuoliaaksi nitrogolemin toimesta.,%o s'est fait@[e_fr] percer les tympans par un nitrogolem.,%o halálra lett ijesztve egy Nitrógólem által.,%o è stato stroncato da una mummia.,%o はニトロゴーレムに脅かされた。,%o 은(는) 니트로 골렘에 의해 비명횡사 당했다.,%o werd doodgeschreeuwd door een nitrogolem.,%o został@[ao_pl] zakrzyczan@[adj_pl] na śmierć przez nitrogolema,%o agonizou na frente de um nitrogolem.,,%o a fost chiuit până la moarte de un nitrogolem.,Игрока %o убил криком нитроголем.,Играча %o је извриштао до смрти нитроголем. -%o was rattled by an ophidian.,OB_SNAKE,,,,%o byl@[ao_cs] zachřestěn@[ao_cs] šupinatcem.,%o hörte das Klappern des Ophidian.,,%o klakiĝis per ofidio.,%o fue agitad@[ao_esp] por un ofidio.,,%o joutui käärmeolion kalkattamaksi.,%o s'est fait@[e_fr] secouer par un ophidien.,%o halálra lett csörgetve egy Kígyószerű által.,%o è stato stritolato da un serpente.,%o はオフィディアンに動揺した。,%o 은(는) 오피디안에게 흔들렸다.,%o werd gerammeld door een ophidiaan,%o został@[ao_pl] rozgrzechotan@[adj_pl] przez wężowatego,%o foi sacudid@[ao_ptb] por um ofídio.,,%o a fost bătut până la moarte de un ofidian.,Игрока %o потряс офидиан.,Играча %o је угризла змија. -%o was cursed by a wizard.,OB_WIZARD,,,,%o byl@[ao_cs] zaklet@[ao_cs] čarodějem.,%o wurde von dem Magier verflucht.,,%o malbeniĝis per sorĉisto.,%o fue maldecid@[ao_esp] por un mago.,%o ha sido hechizad@[ao_esp] por un mago.,%o joutui velhon kiroamaksi.,%o a été maudit@[e_fr] par un sorcier.,%o meglett átkozva egy Varázsló által.,%o è stato maledetto da un mago.,%o はウィザードに呪われた。,%o 은(는) 드'스파릴의 제자에 의해 저주받았다.,%o werd vervloekt door een tovenaar.,%o został@[ao_pl] przeklęt@[adj_pl] przez czarownika,%o foi amaldiçoad@[ao_ptb] por um mago.,,%o a fost blestemat de un vrăjitor.,Игрока %o проклял колдун.,%o је проклет@[adj_1_sr] од стране чаробњака. -%o was palpated by a wizard.,OB_WIZARDHIT,,,,%o byl@[ao_cs] prozkoumán@[ao_cs] čarodějem.,%o spürte den Hauch des Magiers.,,%o palpatiĝis per sorĉisto.,%o fue palpad@[ao_esp] por un mago.,,%o joutui velhon tunnustelemaksi.,%o a été palpé@[e_fr] par un sorcier.,%o meglett tapogatva egy Varázsló által.,%o è stato toccato da un mago.,%o はウィザードに触診されてしまった。,%o 은(는) 드'스파릴의 제자에게 촉진당했다.,%o werd gepikeerd door een tovenaar.,%o został@[ao_pl] przebadan@[adj_pl] przez czarownika,%o foi apalpad@[ao_ptb] por um mago.,,%o a fost palpat de un vrăjitor.,Игрока %o нащупал колдун.,Играча %o је палпатирао чаробњак. -%o got staffed by %k.,OB_MPSTAFF,,,,%o dostal@[ao_cs] holí od hráče %k.,%o wurde von %k verprügelt.,,%o bategiĝis per %k.,%o fue apalead@[ao_esp] por %k.,,%k sauvoi %k paran.,%o s'est fait@[e_fr] matraquer par %k.,%o meglett botozva %k által.,%o è stato preso a colpi di staffa da %k.,%o は %k の棒でぶん殴られた。,%o 은(는) %k 의 지팡이에 제압당했다.,%o werd bemand door %k.,%o został@[ao_pl] walnięt@[adj_pl] laską przez %k,%o levou uma sova do bastão de %k.,,%o a fost bastonat de %k.,Игрок %o сел на посох игрока %k.,%o је претуцан@[adj_1_sr] штапом од стране %k. -%o got a shock from %k's gauntlets.,OB_MPGAUNTLETS,,,,%o byl@[ao_cs] prošokován@[ao_cs] rukavicemi hráče %k.,%o bekam einen Schock von %ks Handschuhen.,,%o recivis ŝokon de la fergantoj de %k.,%o recibió un choque de los guanteletes de %k.,,%o sai sähköiskun pelaajan %k kintaista.,%o s'est pris@[e_fr] un coup de jus par les gantelets de %k.,%o kapott egy sokkot %k által.,%o è stato folgorato dai guanti di %k.,%o は %k の篭手からショックを受けた。,%o 은(는) %k 가 쓰고 있는 건틀릿의 전격을 느꼈다.,%o kreeg een schok van %k's handschoenen.,%o został@[ao_pl] wstrząśnięt@[adj_pl] rękawicami %k,%o tomou um choque das manoplas de %k.,,%o a primit un șoc de la mănușile lui %k.,Игрок %o шокирован перчатками %k.,%o је доби@[ao_1_sr] шок од %k штапа. -%o waved goodbye to %k's elven wand.,OB_MPGOLDWAND,,,,%o zamával@[ao_cs] elfské hůlce hráče %k.,%o sagte „Tschüß“ zu %ks Elfenstab.,,%o ĝisis al la elfa sorĉbastono de %k.,%o le dijo adiós a la vara de elfo de %k.,,%o heilutti hyvästit pelaajan %k haltiasauvalle.,%o à fait coucou à la baguette magique de %k.,%o integetett egy viszlátot %k Elf Pálcájának.,%o ha fatto ciao ciao allo scettro elfico di %k.,%o は %k のエルフのワンドに別れの挨拶をした。,%o 은(는) %k 의 엘프 지팡이를 보고 작별인사를 했다.,%o zwaaide afscheid van %k's elfenstaf.,%o pomachał@[ao_pl] na do widzenia elfiej różdżce %k,%o deu tchauzinho para o cetro élfico de %k.,%o disse adeuzinho para o cetro élfico de %k.,%o a facut cu mână toiagului elfilor al lui %k.,Игрок %o узрел прощальный взмах эльфийского жезла %k.,%o је рек@[ao_2_sr] збогом %k вилењачком штапићу. -%o was pegged by %k's ethereal crossbow.,OB_MPCROSSBOW,,,,%o byl@[ao_cs] prostřelen@[ao_cs] éterickou kuší hráče %k.,%o von %ks Armbrustbolzen aufgespießt.,,%o kejlis per la etera arbalesto de %k.,%o fue flechad@[ao_esp] por la ballesta etérea de %k.,,%k ripusti %o paran eteerivarsijousellaan.,%o s'est fait@[e_fr] clouer par l'arbalète étherique de %k.,%o fel lett rögzítve %k Éteri Nyílpuskájának által.,%o è stato inchiodato dalla balestra eterea di %k.,%o は %k のイセリアルクロスボウで釘付けにされた。,%o 은(는) %k 의 유체 쇠뇌에 의해 처박혔다.,%o was vastgepind door %k's etherische kruisboog.,%o został@[ao_pl] przebit@[adj_pl] przez eteryczną kuszę %k,%o foi esmigalhad@[ao_ptb] pela besta etérea de %k.,,%o a fost prins de arbaleta celestă a lui %k.,Игрок %o изранен болтами эфирного арбалета %k.,%o је упуц@[adj_2_sr] од стране %k етералног самострела. -%o was blasted a new one by %k's dragon claw.,OB_MPBLASTER,,,,%o poznal@[ao_cs] středověk drakospárem hráče %k.,%o bekam %ks Drachenklaue zu spüren.,,%o estis diseksplodita per la drakokrifo de %k.,%o quedó bien jodid@[ao_esp] por la garra de dragón de %k.,,%k puhkoi %o parkaan uuden aukon lohikäärmeenkynnellään.,%o s'est fait flinguer par la griffe draconique de %k.,%o újszerűnek látszik %k Sárkány Karomjának köszönhetően.,A %o èstato aperto un buco nuovo dall'Artiglio di Drago di %k.,%o は %k のドラゴンクローで発破体験した。,%o 은(는) %k 의 용발톱에 의해 형태를 잃었다.,%o werd met een nieuwe drakenklauw gestraald door %k's drakenklauw.,%o został wysadzony nowy otwór przez %k,%o sentiu o poder da garra de dragão de %k.,,%o a fost aruncat în aer de gheara dragonului a lui %k.,Игрок %o взорван драконьим когтем %k.,Играчу %o је отворена нова рупа змајевском канџом играча %k. -%o got sent down under by %k's hellstaff.,OB_MPSKULLROD,,,,Pod hráčem %o se propadla zem peklopalem hráče %k.,%o brach unter %ks Höllenrute zusammen.,,%o forsendiĝis sub per la inferbastono de %k.,%o se inclinó ante el bastón infernal de %k.,,%k lähetti %o paran maan syövereihin hornansauvallaan.,%o repose six pieds sous terre grâce au Bâton infernal de %k.,%o lelett küldve %k Pokolbotjának köszönhetően.,%o è stato mandato sottoterra dalla Staffa Infernale di %k.,%o は %k のヘルスタッフで冥界に送られた。,%o 은(는) %k 의 지옥지팡이에 의해 저승으로 날아갔다.,%o werd door %k's hellestok ondersteboven gestuurd.,%o został@[ao_pl] zesłan@[adj_pl] pod piekielny kostur %k,%o foi mandad@[ao_ptb] pra baixo do solo pelo cajado infernal de %k.,,%o a fost trimis sub bastonul infernal al lui %k.,Игрок %o сослан в самый низ посохом ада %k.,%o је укопан@[adj_1_sr] од стране пакленог штапа играча %k. -%o was scorched to cinders by %k's phoenix rod.,OB_MPPHOENIXROD,,,,%o byl@[ao_cs] spálen@[ao_cs] na prach fénixovou holí hráče %k.,%o wurde voin %ks Phönixstab verschmort.,,%o brulegiĝis en cindrojn per la feniksvergo de %k.,%o fue reducid@[ao_esp] a cenizas por el báculo del Fénix de %k.,,%k kärvensi %o paran tuhannen päreiksi feenikssauvallaan.,%o s'est fait@[e_fr] réduire en cendres par le Bâton du Phénix de %k.,%o halomra lett égve %k Főnix Rúdjának által.,%o è stato ridotto in cenere dal Bastone della Fenice di %k.,%o は %k のフェニックスロッドで焼かれた。,%o 은(는) %k 의 불사조 지팡이 덕에 검게 익었다.,%o werd door %k's feniksstang tot sintels verschroeid.,%o został@[ao_pl] spalon@[adj_pl] na popiół przez różdżkę feniksa %k,%o virou cinzas com o bastão da fênix de %k.,,%o a fost făcut cenușă de joarda phoenix a lui %k.,Игрок %o сожжён в пепел жезлом феникса %k.,%o запаљен@[adj_1_sr] у пепео од стране шипке феникса играча %k. -%o was bounced by %k's firemace.,OB_MPMACE,,,,%o byl@[ao_cs] odpálen@[ao_cs] žezlometem hráče %k.,%o prallte an %ks Feuerkeule ab.,,%o estis resaltita per la fajrklabo de %k.,%o recibió los rebotes de la maza de fuego de %k.,,%k pomputti %o parkaa tulinuijallaan.,%o a rebondi@[e_fr] sur les balles de la Masse de Feu à %k.,%o pattant egy nagyot %k Tűzbuzogányának köszönhetően.,%o è stato spazzato via dalla Mazza del Fuoco di %k.,%o は %k のファイアメイスで飛ばされた。,%o 은(는) %k 의 투사철퇴의 포탄을 맞고 튕겨져 날아갔다.,%o werd door %k's vuurmace gestuiterd.,%o został@[ao_pl] wybit@[adj_pl] przez buzdygan ognia %k,%o saiu pulando após ver a clava de fogo de %k.,,"%o a fost aruncat de colo colo de buzduganul de -foc al lui %k.",Игрок %o отбит огненной булавой %k.,%o је ударен@[adj_1_sr] са ватреним буздованом играча %k. -%o got clapped by %k's charged staff.,OB_MPPSTAFF,,,,%o byl@[ao_cs] profackován@[ao_cs] nabitou holí hráče %k.,%o bekam eine Klatsche durch %ks geladenen Stab.,,%o estis aplaŭdita per la ŝargita bastono de %k.,%o recibió los palos del bastón cargado de %k .,,%k jyrisytti %o parkaa varatulla sauvallaan.,%o à été foudroyé@[e_fr] par le bâton chargé de %k.,%o csattant egy nagyot %k Feltöltött Botjának által.,%o è scoppiato a causa della staffa incantata di %k.,%o は %k の魔力を帯びた棒で暖かく迎えられた。,%o 은(는) %k 의 마법부가 지팡이를 얻어맞았다.,%o werd geklapt door %k's opgeladen staf.,%o został@[ao_pl] trzepnięt@[adj_pl] naładowaną laską %k,%o tomou uma pancada do bastão carregado de %k.,,%o a fost tăiat de bastonul încărcat al lui %k.,Игрок %o отведал заряженного посоха %k.,%o је потапшан@[adj_1_sr] напуњеним штапом играча %k. -%o was bled dry by %k's gauntlets.,OB_MPPGAUNTLETS,,,,Rukavicemi hráče %k nezůstala v těle hráče %o ani kapka krve.,%o wurde von %ks Handschuhen ausgeblutet.,,%o sensangiĝis per la fergantoj de %k.,%o fue desangrad@[ao_esp] por los guanteletes de %k.,,%k vuodatti %o paran kuiviin kintaillaan.,%o s'est fait@[e_fr] saigner à blanc par les gantelets de %k.,%o elvérzett %k Páncélöklei által.,Il sangue di %o è stato prosciugato dai guanti di %k.,%o は %k の篭手で血を絞り取られた。,%o 은(는) %k 의 마법부가 건틀릿에 의해 바싹 말랐다.,%o werd drooggebloed door %k's handschoentjes.,%o wykrwawił@[ao_pl] się przez rękawice %k,%o sangrou nas manoplas de %k.,,"%o a fost stors până la ultima picătură de sânge -de mănușile lui %k.",Игрок %o опустошён перчатками %k.,%o је путпуно искрвари@[ao_1_sr] од рукавица играча %k. -%o was assaulted by %k's elven wand.,OB_MPPGOLDWAND,,,,%o byl@[ao_cs] napaden@[ao_cs] elfskou hůlkou hráče %k.,%o wurde von %ks Elfenstab überwältigt.,,%o atakiĝis per la elfa sorĉbastono de %k.,%o fue asaltad@[ao_esp] por la vara de elfo de %k.,,%o joutui pelaajan %k haltiasauvan pahoinpitelemäksi.,%o à été assailli@[e_fr] par la baguette elfique de %k.,%o meglett bántva %k Elf Botjának köszönhetően.,%o è stato assalito dallo Scettro Elfico di %k.,%o は %k のエルフのワンドで襲われた。,%o 은(는) %k 의 마법부가 엘프 지팡이에 의해 사냥당했다.,%o werd aangevallen door %k's elvenstaf.,%o został@[ao_pl] zaatakowan@[adj_pl] przez elfią różdżkę %k,%o foi atacad@[ao_ptb] pelo cetro élfico de %k.,,%o a fost luat cu asalt de togaiul elfilor al lui %k.,Игрок %o атакован %k с эльфийским жезлом.,%o је нападнут@[adj_1_sr] вилењачким штапом играча %k. -%o was shafted by %k's ethereal crossbow.,OB_MPPCROSSBOW,,,,%o byl@[ao_cs] proděravěn@[ao_cs] éterickou kuší hráče %k.,%o wurde von %ks Armbrustbolzen durchbohrt.,,%o akiris novan truon per etera arbalesto de %k.,%o fue encañonad@[ao_esp] por la ballesta etérea de %k.,,%k joutui pelaajan %k eteerivarsijousen kepittämäksi.,%o s'est fait@[e_fr] transpercer par l'arbalète éthérique de %k.,%o megkóstolta %k Éteri Nyílpuskáját.,%o è stato impalato dalla balestra eterea di %k.,%o は %k のイセリアルクロスボウで押された。,%o 은(는) %k 의 마법부가 유체 쇠뇌에 의해 무뎌졌다.,%o werd door %k's etherische kruisboog geschaafd.,%o został@[ao_pl] wykiwan@[adj_pl] przez eteryczną kuszę %k,%o foi flechad@[ao_ptb] pela besta etérea de %k.,,"%o a fost pus la proțap de arbaleta celestă a lui -%k.",Игрок %o пробит эфирным арбалетом %k.,%o је упуцан@[adj_1_sr] етеричним самострелом играча %k. -%o was ripped apart by %k's dragon claw.,OB_MPPBLASTER,,,,%o byl@[ao_cs] roztrhnut@[ao_cs] naskrz drakospárem hráče %k.,%o wurde von der Drachenklaue zerrissen.,,%o disrompiĝis per la drakokrifo de %k.,%o fue desgarrad@[ao_esp] por la garra de dragón de %k.,,%k repi %o paran kappaleiksi lohikäärmeenkynnellään.,%o à été mis@[e_fr] en pièces par la griffe draconique de %k.,%o szét lett tépve %k Sárkány Karomja által.,%è stato fatto a brandelli dall'Artiglio di Drago di %k.,%o は %k のドラゴンの鉤爪でバラバラに引き裂かれた。,%o 은(는) %k 의 마법부가 용발톱에 갈기갈기 찢겨졌다.,%o werd uit elkaar gescheurd door %k's drakenklauw.,%o został@[ao_pl] rozerwan@[adj_pl] przez smoczy pazur %k,%o foi cortad@[ao_ptb] pela garra de dragão de %k.,,%k a fost făcut bucăți de gheara dragonului a lui %k.,Игрок %o разорван драконьим когтем %k.,%o је поцепан@[adj_1_sr] змајевим канџама играча %k. -%k poured the hellstaff on %o.,OB_MPPSKULLROD,,,,Hráč %k vylil svůj peklopal na hráče %o.,%k ließ den Höllenregen auf %o los.,,%k ŝutas la inferbastonon sur %o.,%k virtió su bastón infernal en %o.,,%k vuodatti hornansauvansa %o parkaan.,%k à versé toute la rage des enfers sur %o.,%k ráfröcsögte a Pokolbotját %o felé.,%k ha fatto sgorgare la sua Staffa Infernale su %o.,%o は %k にヘルスタッフを %p 注ぎ込まれた。,%k의 마법부가 지옥지팡이가 쏟아붓는 비를 %o 이(가) 맞았다.,%k liet de helregen vrij op %o.,%k polał@[ao_pl] swoim piekielnym kosturem %o,%k usou seu cajado infernal no %o.,,%k a vărsat bastonul infernal pe %o.,"Игрок %k залил игрока %o горячим дождём, использовав посох ада.",%k је просипа@[ao_1_sr] пламени штап на %o. -%o was burned down by %k's phoenix staff.,OB_MPPPHOENIXROD,,,,%o byl@[ao_cs] vyhořen@[ao_cs] fénixovou holí hráče %k.,%o wurde von %ks Phönixstab verbrannt.,,%o torĉiĝis per la feniksvergo de %k.,%o fue rostizad@[ao_esp] por el báculo del Fénix de %k.,,%k poltti %o paran feenikssauvallaan.,%o à été incinéré@[e_fr] par le Bâton du Phénix de %k.,%o elégett %k Főnix Botjának által.,%o è stato incendiato dal Bastone della Fenice di %k.,%o は %k のフェニックスロッドで焼き滅ぼされた。,%o 은(는) %k 의 마법부가 불사조 지팡이에 의해 화장당했다.,%o werd afgebrand door %k's feniksstang.,%o został@[ao_pl] spalon@[adj_pl] przez różdżkę feniksa %k,%o foi queimad@[ao_ptb] pelo bastão da fênix de %k.,,%o a fost ars complet de joarda phoenix a lui %k.,Игрок %o сожжён жезлом феникса %k.,%o је изгоре@[ao_1_sr] шипком феникса играча %k. -%o was squished by %k's giant mace sphere.,OB_MPPMACE,,,,%o byl@[ao_cs] rozmačkán@[ao_cs] obrovskou žezlometnou koulí hráče %k.,%o wurde von %ks Feuerkeule zerquetscht.,,%o premiĝis per la grandega klubsfero de %k.,%o fue aplastad@[ao_esp] por una esfera gigante de la maza de %k.,,%k liiskasi %o paran jättiläisnuijapallollaan.,%o s'est fait@[e_fr] écraser par la balle de Masse géante de %k.,%o össze lett nyomva %k hatalmas buzogány gömbje által.,%o è stato spiaccicato da una sfera gigante della Mazza del Fuoco di %k.,%o は %k の巨大なメイススフィアで潰された。,%o 은(는) %k 의 마법부가 투사철퇴가 뿜은 거대포탄에 의해 납작해졌다.,%o werd verpletterd door %k's reusachtige mace sfeer.,%o został@[ao_pl] zmiażdżon@[adj_pl] przez ogromną kulę z buzdygana %k,%o foi esmagad@[ao_ptb] pela esfera de clava gigante de %k.,,"%o a fost strivit de globul gigantic al buzduganului -lui %k.",Игрок %o раздавлен огромной сферой из огненной булавы %k.,%o је смрвљен@[adj_1_sr] од стане огромном сферско буздована играча %k. -,,Hexen,,,,,,,,,,,,,,,,,,,,, -,,Pickup,,,,,,,,,,,,,,,,,,,,, -Blue Mana,TXT_MANA_1,,,,Modrá mana,Blaues Mana,,Blua Manao,Maná Azul,Mana Azul,Sininen mana,Mana Bleu,,Mana blu,青マナ,청색 마나,Blauwe Mana,Niebieska Mana,Mana Azul,,Mană Albastră,Синяя мана,Плава мана -Green Mana,TXT_MANA_2,,,,Zelená mana,Grünes Mana,,Verda Manao,Maná Verde,Mana Verde,Vihreä mana,Mana Vert,,Mana verde,緑マナ,녹색 마나,Groene Mana,Zielona Mana,Mana Verde,,Mană Verde,Зеленая мана,Зелена мана -Combined Mana,TXT_MANA_BOTH,,,,Smíšená mana,Kombiniertes Mana,,Kuna Manao,Maná Combinado,Mana Combinado,Yhdistetty mana,Mana Combiné,,Mana misto,複合マナ,윰합된 마나,Gecombineerde Mana,Połączona Mana,Mana Combinada,,Mană Mixtă,Комбинированная мана,Мешана мана -Steel Key,TXT_KEY_STEEL,,,,Ocelový klíč,Stahlschlüssel,Ατσάλινο Κλειδί,Ŝtala Ŝlosilo,Llave de Acero,,Teräsavain,Clé d'Acier,,Chiave d'acciaio,鋼の鍵,강철 열쇠,Stalen sleutel,Stalowy Klucz,Chave de Aço,,Cheia din Oțel,Стальной ключ,Челични кључ -Cave Key,TXT_KEY_CAVE,,,,Klíč od jeskyně,Höhlenschlüssel,,Kavern-Ŝlosilo,Llave de la Caverna,,Luola-avain,Clé de la Cave,,Chiave della caverna,洞窟の鍵,동굴 열쇠,Grotensleutel,Klucz do Jaskini,Chave da Caverna,,Cheia Peșterii,Пещерный ключ,Пећински кључ -Axe Key,TXT_KEY_AXE,,,,Sekyrový klíč,Axtschlüssel,,Hakil-Ŝlosilo,Llave de Hacha,,Kirvesavain,Clé de la Hache,,Chiave dell'ascia,斧の鍵,도끼 열쇠,Bijlsleutel,Klucz-topór,Chave do Machado,,Cheia Topor,Ключ-топор,Кључ секире -Fire Key,TXT_KEY_FIRE,,,,Ohnivý klíč,Feuerschlüssel,,Fajro-Ŝlosilo,Llave de Fuego,,Tuliavain,Clé du Feu,,Chiave del fuoco,炎の鍵,불 열쇠,Vuursleutel,Ognisty Klucz,Chave do Fogo,,Cheia de Foc,Огненный ключ,Ватрени кључ -Emerald Key,TXT_KEY_EMERALD,,,,Smaragdový klíč,Smaragdschlüssel,,Smerelda Ŝlosilo,Llave Esmeralda,,Smaragdiavain,Clé d'Emeraude,,Chiave di smeraldo,翠玉の鍵,에메랄드 열쇠,Smaragdensleutel,Szmaragdowy Klucz,Chave de Esmeralda,,Cheia din Smarald,Изумрудный ключ,Смарагдни кључ -Dungeon Key,TXT_KEY_DUNGEON,,,,Klíč od žaláře,Kerkerschlüssel,,Karcer-Ŝlosilo,Llave del Calabozo,,Tyrmän avain,Clé du Donjon,,Chiave del sotterraneo,迷宮の鍵,지하감옥 열쇠,Kerkersleutel,Klucz do Lochu,Chave da Masmorra,,Cheia Temniței,Ключ от подземелья,Кључ од тамнице -Silver Key,TXT_KEY_SILVER,,,,Stříbrný klíč,Silberschlüssel,Ασυμένιο Κλειδί,Arĝenta Ŝlosilo,Llave de Plata,,Hopea-avain,Clé d'Argent,,Chiave d'argento,銀の鍵,은 열쇠,Zilveren sleutel,Srebrny Klucz,Chave de Prata,,Cheia din Argint,Серебряный ключ,Сребрни кључ -Rusted Key,TXT_KEY_RUSTED,,,,Zrezivělý klíč,Rostiger Schlüssel,Σκουριασμένο Κλειδί,Rusta Ŝlosilo,Llave Oxidada,,Ruosteinen avain,Clé Rouillée,,Chiave arrugginita,錆びた鍵,녹슨 열쇠,Geroeste sleutel,Zardzewiały Klucz,Chave Enferrujada,,Cheia Ruginită,Ржавый ключ,Зарђао кључ -Horn Key,TXT_KEY_HORN,,,,Parožní klíč,Hornschlüssel,,Hup-Ŝlosilo,Llave de Cuerno,,Sarviavain,Clé Corne,,Chiave del corno,角の鍵,뿔 열쇠,Hoornsleutel,Rogowy Klucz,Chave do Chifre,,Cheia Corn,Роговой ключ,Рогати кључ -Swamp Key,TXT_KEY_SWAMP,,,,Klíč od bažiny,Sumpfschlüssel,,Marĉ-Ŝlosilo,Llave del Pantano,,Suoavain,Clé des Marécages,,Chiave della palude,沼の鍵,늪지대 열쇠,Moerassleutel,Bagienny Klucz,Chave do Pântano,,Cheia Mlaștinii,Болотный ключ,Мочварни кључ -Castle Key,TXT_KEY_CASTLE,,,,Klíč od hradu,Burgschlüssel,,Kastel-Ŝlosilo,Llave del Castillo,,Linnan avain,Clé du Château,,Chiave del castello,城の鍵,성 열쇠,Kasteelsleutel,Klucz do Zamku,Chave do Castelo,,Cheia Castelului,Ключ от замка,Кључ од замка -Icon of the Defender,TXT_ARTIINVULNERABILITY2,,,,Obráncova ikona,Ikone des Verteidigers,,Ikono de la Defendanto,Ícono del Defensor,Ícono del Defensor,Puolustajan ikoni,Icône du Défenseur,,Icona del difensore,守護者の像,수호의 성상,Symbool van de verdediger,Ikona Obrońcy,Ícone do Defensor,,Imaginea Apărătorului,Символ защитника,Икона браниоца -Dark Servant,TXT_ARTISUMMON,,,,Temný služebník,Dunkler Diener,,Malluma Servanto,Sirviente Oscuro,,Pimeä palvelija,Serviteur Noir,,Servitore oscuro,闇の従者,어둠의 하인,Donkere dienaar,Mroczny Sługa,Servo Negro,,Servitor Întunecat,Тёмный слуга,Мрачни слуга -Porkalator,TXT_ARTIEGG2,,,,Vepřovitel,,,Porkigilo,Porcinador,,Sikaannuttaja,Porcificateur,,Porchificatore,ポークレイター,돈육기,,Schabowator,Porquificador,,Porcolator,Свиноморфер,Поркалатор -Flechette,TXT_ARTIPOISONBAG,,,,Střelka,,,Flakono,Flechette,,,Fléchette,,Fiaschetta,フレチェット,플레셰트,,Flaszka,,,Flacon,Зелье,Флечет -Banishment Device,TXT_ARTITELEPORTOTHER,,,,Vyhošťovač,Verbannungsgerät,,Forpelilo,Dispositivo de Desvanecimiento,,Häivytyskoje,Outil de Banissement,,Artifatto dell'esilio,追放のデバイス,소멸 장치,Verbanningsapparaat,Urządzenie Wygnania ,Dispositivo do Banimento,,Dispozitiv al Alungării,Эмблема изгнания,Уређај протеривања -Boots of Speed,TXT_ARTISPEED,,,,Běhuté boty,Turbo-Stiefel,,Botoj de Rapideco,Botas de Velocidad,,Ripeyssaappaat,Bottes de Célérité,,Stivali della velocità,素早さの靴,속도의 신발,Snelheidslaarzen,Buty Szybkości,Botas da Velocidade,,Bocancii Vitezei,Сапоги-скороходы,Чизме брзине -Krater of Might,TXT_ARTIBOOSTMANA,,,,Kalich síly,Kelch der Macht,,Kratero de Potenco,Vasija de Fuerza,,Mahtikrateeri,Cratère de Pouvoir,,Calice della forza,魔力の盃,힘의 향로,Beker van Macht,Czara mocy,Cálice do Poder,,Pocal al Puterii,Чаша могущества,Кратер силе -Dragonskin Bracers,TXT_ARTIBOOSTARMOR,,,,Náramky dračích šupin,Drachenhaut-Armschutz,,Brakbendo el Drakhaŭto,Brazaletes de piel de Dragón,,Lohikäärmeennahkarannesuojat,Bracelets en Peau de Dragon,,Bracciali in pelle di drago,竜皮の小手,용가죽 팔찌,Draakenhuid bescherming,Karwasze ze Smoczej Skóry,Braçadeiras de Pele de Dragão,,Brățări din Piele de Dragon,Наручи из драконьей кожи,Наруквице од змајеве коже -Disc of Repulsion,TXT_ARTIBLASTRADIUS,,,,Kotouč odpuzení,Rückstoßscheibe,,Disko de Repelado,Disco de Repulsión,,Karkotuskiekko,Disque de Répulsion,,Disco della repulsione,反発の円盤,방탄의 원반,Schijf van afstoting,Dysk Odpychania,Disco da Repulsão,,Disc al Repulsiei,Диск отторжения,Диск одвратности -Mystic Ambit Incant,TXT_ARTIHEALINGRADIUS,,,,Tajemný svitek okolí,Verbannungsgerät,,Sorĉo de Mistika Sfero,Encanto de Ámbito Místico,,Mystisen piirin loitsu,Incantation Mystique,,Confine mistico,魅知国の秘法,신비 영역의 주문,,Inkantancja Mistycznego Kręgu,Encanto Místico,,Pergament Mistic,Чары магического единства,Мистични очарани свитак -Yorick's Skull,TXT_ARTIPUZZSKULL,,,,Jorikova lebka,Yoricks Schädel,,Kranio de Yorick,Calavera de Yorick,,Yorickin kallo,Crâne de Yorick,,Teschio di Yorick,ヨリックの髑髏,요릭의 두개골,Yorick's schedel,Czaszka Yoricka,Caveira de Yorick,,Craniul lui Yorick,Череп Йорика,Јорикова лобања -Heart of D'sparil,TXT_ARTIPUZZGEMBIG,,,,Srdce D'Sparila,D'Sparils Herz,,Koro de D'sparil,Corazón de D'Sparil,,D'Sparilin sydän,Cœur de D'Sparil,,Cuore di d'sparil,デ'スパリルの心,드'스파릴의 심장,Hart van D'sparil,Serce D'Sparila,Coração de D'Sparil,,Inima lui D'Sparil,Сердце Д'Спарила,Срце Д'Спарила -Ruby Planet,TXT_ARTIPUZZGEMRED,,,,Rubínová planeta,Rubinplanet,,Rubena Planedo,Planeta Rubí,,Rubiiniplaneetta,Planète de Rubis,,Pianeta di rubino,ルビーの宝石,루비 행성석,Robijnrode planeet,Rubinowa Planeta,Planeta Rubi,,Planetă din Rubin,Рубиновая планета,Планета рубина -Emerald Planet,TXT_ARTIPUZZGEMGREEN1,,,,Smaragdová planeta,Smaragdplanet,,Smeralda Planedo,Planeta Esmeralda,,Smaragdiplaneetta,Planète d'Emeraude,,Pianeta di smeraldo,エメラルドの宝石,에메랄드 행성석 (1),Smaragdgroene planeet,Szmaragdowa Planeta,Planeta Esmeralda,,Planetă din Smarald,Изумрудная планета,Планета смарагда -Emerald Planet,TXT_ARTIPUZZGEMGREEN2,,,,Smaragdová planeta,Smaragdplanet,,Smeralda Planedo,Planeta Esmeralda,,Smaragdiplaneetta,Planète de Saphir,,Pianeta di smeraldo,エメラルドの宝石,에메랄드 행성석 (2),Smaragdgroene planeet,Szmaragdowa Planeta,Planeta Esmeralda,,Planetă din Smarald,Изумрудная планета,Планета смарагда -Sapphire Planet,TXT_ARTIPUZZGEMBLUE1,,,,Safírová planeta,Saphirplanet,,Safira Planedo,Planeta Zafiro,,Safiiriplaneetta,Planète de Saphir,,Pianeta di zaffiro,サファイアの宝石,사파이어 행성석 (1),Saffier Planeet,Szafirowa Planeta,Planeta Safira,,Planetă din Safir,Сапфировая планета,Планета сафира -Sapphire Planet,TXT_ARTIPUZZGEMBLUE2,,,,Safírová planeta,Saphirplanet,,Safira Planedo,Planeta Zafiro,,Safiiriplaneetta,Planète de Saphir,,Pianeta di zaffiro,サファイアの宝石,사파이어 행성석 (2),Saffier Planeet,Szafirowa Planeta,Planeta Safira,,Planetă din Safir,Сапфировая планета,Планета сафира -Daemon Codex,TXT_ARTIPUZZBOOK1,,,,,,,Kodekso de Demono,Códice del Demonio,,,Codex Démoniaque,,Codice Demoniaco ,デーモンの写本,악마의 고문서,,Demoniczny Kodeks,Códice Demoníaco,,Codexul Demonilor,Демонический кодекс,Демонски кодекс -Liber Oscura,TXT_ARTIPUZZBOOK2,,,,,,,Liber Oscura,Liber Oscura,,,Liber Oscura,,,オスキュラ公文書,어둠의 자유서,,Liber Oscura,,,,Либер Оскура,Либер Оскура -Flame Mask,TXT_ARTIPUZZSKULL2,,,,Plamenná maska,Flammenmaske,,Fajrmasko,Mascara de Llamas,Mascara de Flamas,Liekkinaamio,Masque de Flammes,,Maschera delle fiamme,炎の仮面,화염의 가면,Vlammasker,Maska Płomieni,Máscara das Chamas,,Mască de Foc,Маска пламени,Маска пламена -Glaive Seal,TXT_ARTIPUZZFWEAPON,,,,Glévská pečeť,Schwetsiegel,,Sigelo de Glavo,Sello de Espada,,Miekkasinetti,Sceau du Glaive,,Sigillo della brando,グレイブシール,밀폐된 칼날,Zwaardzegel,Pieczęć Glewii,Selo do Gládio,,Sigiliu Spadă,Печать воителя,Запечаћен глејв -Holy Relic,TXT_ARTIPUZZCWEAPON,,,,Svatá relikvie,Heiliges Relikt,,Sankta Relikvo,Santa Reliquia,,Pyhä reliikki,Relique Sacrée,,Reliquia sacra,聖遺物,신성한 유물,Heilige Relikwie,Święta Relikwia,Relíquia Sagrada,,Relicvă Sfântă,Святая реликвия,Света реликвија -Sigil of the Magus,TXT_ARTIPUZZMWEAPON,,,,Mágovo sigilium,Symbol des Magiers,,Sigelo de la Mago,Emblema del Mago,,Taikurin sinetti,Sceau du Mage,,Suggello del magus,メイガスの印章,마거스의 인장,Sigaar van de Magus,Emblemat Maga,Sigilo do Mago,,Sigiliul Magului,Символ мага,Магнусов сигил -Clock Gear,TXT_ARTIPUZZGEAR,,,,Ozubené kolečko,Zahnrad,,Dentrado de Horloĝo,Engranaje de reloj,,Kellonratas,Rouage d'Horloge,,Ingranaggio d'orologio,時計の歯車,시계 톱니바퀴,Versnelling,Mechanizm Zegara,Engrenagem de Relógio,,Mecanism Ceas,Часовая шестерня,Сатни зупчаник -You Cannot Use This Here,TXT_USEPUZZLEFAILED,,,,Zde se tento předmět použít nedá,Das kannst du hier nicht benutzen,,Vi ne eblas uzi tion ĉi tie.,No puedes usar esto aquí,,Et voi käyttää tätä tässä,Vous ne pouvez pas utiliser cela ici.,,Non puoi usare questo oggetto qui,ここでは使用できない,이것은 여기에 사용할 수 없다,Dat kun je hier niet gebruiken.,Nie możesz użyć tego tutaj,Você não pode usar isso aqui,Não podes usar isto aqui,Nu Poți Folosi Asta Aici,Здесь это невозможно использовать,Не можете ово да користите овде -Mesh Armor,TXT_ARMOR1,,,Mesh Armour,Kroužkové brnění,Kettenrüstung,,Marŝkiraso,Armadura de Malla,,Rengashaarniska,Armure de Mailles,,Maglia metallica,鎖帷子,사슬 갑옷,Netwerk Pantser,Kolczuga,Armadura de Malha,,Armură din Zale,Кольчуга,Верижњача -Falcon Shield,TXT_ARMOR2,,,,Sokolí štít,Falkenschild,,Falko-Ŝildo,Escudo de Halcón,,Haukkakilpi,Bouclier du Faucon,,Scudo del falco,鷹の盾,팔콘 방패,Valkenschild,Sokola Tarcza,Escudo do Falcão,,Scut Șoim,Соколиный щит,Соколов штит -Platinum Helmet,TXT_ARMOR3,,,,Platinová helma,Platinhelm,,Platena Kasko,Casco de Platino,,Platinakypärä,Casque de Platine,,Elmo di platino,白金の兜,백금 투구,Platina-helm,Platynowy Hełm,Capacete de Platina,,Coif de Platină,Платиновый шлем,Кацига од платине -Amulet of Warding,TXT_ARMOR4,,,,Amulet uhýbání,Wachamulett,,Amuleto de Gardado,Amuleto de Guarda,,Suojelusamuletti,Amulette de Protection,,Amuleto di protezione,回避の護符,수호의 부적,Amulet van bescherming,Amulet Ochrony,Amuleto da Proteção,,Amuleta Protecției,Амулет стража,Амулет одлагања -Timon's Axe,TXT_WEAPON_F2,,,,Timonova sekera,Timons Axt,,Hakilo de Timon,Hacha de Timón,,Timonin kirves,Hache de Timon,,Ascia di timon,タイモンの斧,티몬의 도끼,Timon's bijl,Topór Timona,Machado de Timon,,Toporul lui Timon,Топор Тимона,Тимонова секира -Hammer of Retribution,TXT_WEAPON_F3,,,,Kladivo odplaty,Hammer der Rache,,Martelo de Repago,Martillo de Retribución,,Koston vasara,Marteau de la Rétribution,,Martello del castigo,報復の金槌,징벌의 망치,Hamer van vergelding,Młot Odkupienia,Martelo da Retribuição,,Ciocanul Salvării,Молот возмездия,Чекић одмазде -Quietus Assembled,TXT_WEAPON_F4,,,,Složený Tišitel,Erlöser komplettiert,,Kvietus' Muntita,Quietus Ensamblado,,Quietus koottuna,Quietus Assemblée,,Quietus assemblato,組み立てた 死滅の剣,완성된 종언의 검,Quietus gemonteerd,Złożony Uciszacz,Quietus Montada,,Argument Final Asamblat,Последний довод собран воедино,Састављен је Куиетус -Serpent Staff,TXT_WEAPON_C2,,,,Hadí hůl,Schlangenstab,,Serpentbastono,Vara de Serpiente,,Käärmesauva,Sceptre du Serpent,,Bastone del serpente,蛇の杖,뱀 지팡이,Slangenstaf,Laska Węży,Cetro da Serpente,,Bastonul Șarpelui,Змеиный посох,Змијски штап -Firestorm,TXT_WEAPON_C3,,,,Ohnivá bouře,Feuersturm,,Fajrŝtormo,Tormenta de Fuego,,Tulimyrsky,Tempête de Feu,,Tempesta di fuoco,ファイアストーム,화염폭풍,Vuurstorm,Burza Ognia,Tempestade-de-Fogo,,Furtună de Foc,Огненный шторм,Ватрена олуја -Wraithverge Assembled,TXT_WEAPON_C4,,,,Složený Zjevitel,Geisterbringer komplettiert,,Fantomkruc' Muntita,Vara Fantasmal Ensamblada,Vara Fantasmal Ensamblada,Haamusauva koottuna,Verge Phantasmale Assemblée,,Verga Sconfinaspettri assemblata,組み立てた レイスバージ,완성된 사령의 십자가,Spookbrenger gemonteerd,Złożony Widmoskraj,Cajado Fantasma Montado,,Toiag Stafie Asamblat,Жезл духов собран воедино,Састављен је Штап утвара -Frost Shards,TXT_WEAPON_M2,,,,Ledové střepy,Frostsplitter,,Frostfragmentoj,Fragmentos de Escarcha,,Pakkassirpaleet,Eclats de Givre,,Frantumi gelati,フロスト シャード,얼음 파편,Vorst Scherven,Lodowe Odłamki,Fragmentos de Geada,,Cioburi de Gheață,Ледяные осколки,Ледене крхотине -Arc of Death,TXT_WEAPON_M3,,,,Jiskry smrti,Todesblitz,,Arkoj de Morto,Arcos de la Muerte,,Kuolonkaari,Foudre Mortelle,,Arco della morte,死の円弧,죽음의 번갯불,Boog van de Dood,Łuk Śmierci,Arcos da Morte,,Izvorul Morții,Дуга смерти,Лукови смрти -Bloodscourge Assembled,TXT_WEAPON_M4,,,,Složený Krvehrom,Blutgeißel komplettiert,,Sangskurĝ' Muntita,Plaga Sangrienta ensamblada,,Veripiiska koottuna,Fléau Sanglant Assemblé,,Flagello di Sangue assemblato,組み立てた 天罰,완성된 피의 재앙,Bloedplaag gemonteerd,Złożona Krwioplaga,Flagelo de Sangue Montado,,Flagel Sângeros Asamblat,Кровавый бич собран воедино,Састављено је Крваво зло -A weapon piece! This is your lucky day!,TXT_WEAPONPIECE,,,,Část zbraně! Dnes je tvůj šťastný den!,Ein Waffensegment. Das ist dein Glückstag!,,Peco de armilo! Estas via bonŝanca tago!,¡Una pieza de un arma! ¡Es tu día de suerte!,,Aseen osa! Tämä on onnenpäiväsi!,Une pièce d'arme! C'est votre jour de chance!,,Il frammento di un'arma! È il tuo giorno fortunato! ,武器の一片! 今日は吉日だ!,무기의 한 조각이다! 운수 좋은 날인 것 같다!,Een wapenstuk! Dit is je geluksdag!,Część broni! To twój szczęśliwy dzień!,Um fragmento de arma! Esse é o seu dia de sorte!,Um fragmento de arma! Este é o teu dia de sorte!,O piesă de armă! E ziua ta norocoasă!,Часть оружия! Сегодня Ваш счастливый день!,Део оружја! Ово је твој срећан дан! -Segment of Quietus,TXT_QUIETUS_PIECE,,,,Část Tišitele,Segment des Erlösers,,Segmento de Kvietus',Segmento de Quietus,,Quietuksen osa,Segment de Quietus,,Parte del Quietus,死滅の剣の切片,종언의 검 조각,Segment van Quietus,Fragment Uciszacza,Segmento de Quietus,,Fragment din Argumentul Final,Часть последнего довода,Део Куиетуса -Segment of Wraithverge,TXT_WRAITHVERGE_PIECE,,,,Část Zjevitele,Segment des Geisterbringers,,Segmento de Fantomkruc',Segmento del Báculo Fantasmal,,Haamusauvan osa,Segment de la Verge Phantasmale,,Parte della Verga Sconfinaspettri,レイスバージの切片,사령의 십자가 조각,Segment van Spookbrenger,Fragment Widmoskraju,Segmento do Cajado Fantasma,,Fragment din Toiagul Stafie,Часть жезла духов,Део штапа утвара -Segment of Bloodscourge,TXT_BLOODSCOURGE_PIECE,,,,Část Krvehromu,Segment der Blutgeißel,,Segmento de Sangskurĝ',Segmento de la Plaga Sangrienta,,Veripiiskan osa,Segment du Fléau Sanglant,,Parte del Flagello di Sangue,天罰の切片,피의 재앙 조각,Segment van Bloedplaag,Fragment Krwioplagi,Segmento do Flagelo de Sangue,,Fragment din Flagelul Sângeros,Часть кровавого бича,Део крвавог зла -,,Locks,,,,,,,,,,,,,,,,,,,,, -You need the Steel Key,TXT_NEED_KEY_STEEL,,,,Potřebuješ ocelový klíč,Du brauchst den Stahlschlüssel,Χρειάζεσε το Ατσάλινο κλειδί.,Vi bezonas la Ŝtalan Ŝlosilon,Necesitas la Llave de Acero,,Tarvitset teräsavaimen,Vous avez besoin de la Clé d'Acier,,Ti serve la Chiave d'Acciaio,鋼の鍵が必要だ,강철 열쇠가 필요하다,Je hebt de stalen sleutel nodig.,Potrzebujesz Stalowego Klucza,Você precisa da Chave de Aço,Precisas da Chave de Aço,Ai nevoie de Cheia din Oțel,Для открытия нужен стальной ключ,Треба вам челични кључ -You need the Cave Key,TXT_NEED_KEY_CAVE,,,,Potřebuješ klíč od jeskyně,Du brauchst den Höhlenschlüssel,,Vi bezonas la Kavern-Ŝlosilon,Necesitas la Llave de la Caverna,,Tarvitset luola-avaimen,Vous avez besoin de la Clé de la Cave,,Ti serve la Chiave della Caverna ,洞窟の鍵が必要だ,동굴 열쇠가 필요하다,Je hebt de grotsleutel nodig.,Potrzebujesz Klucza do Jaskini,Você precisa da Chave da Caverna,Precisas da Chave da Caverna,Ai nevoie de Cheia Peșterii,Для открытия нужен пещерный ключ,Треба вам пећински кључ -You need the Axe Key,TXT_NEED_KEY_AXE,,,,Potřebuješ sekyrový klíč,Du brauchst den Axtschlüssel,,Vi bezonas la Hakil-Ŝlosilon,Necesitas la Llave de Hacha,,Tarvitset kirvesavaimen,Vous avez besoin de la Clé de la Hache,,Ti serve la Chiave dell'Ascia,斧の鍵が必要だ,도끼 열쇠가 필요하다,Je hebt de bijlsleutel nodig.,Potrzebujesz Klucza-Topora,Você precisa da Chave do Machado,Precisas da Chave do Machado,Ai nevoie de Cheia Topor,Для открытия нужен ключ-топор,Треба вам кључ секире -You need the Fire Key,TXT_NEED_KEY_FIRE,,,,Potřebuješ ohnivý klíč,Du brauchst den Feuerschlüssel,,Vi bezonas la Fajro-Ŝlosilon,Necesitas la Llave de Fuego,,Tarvitset tuliavaimen,Vous avez besoin de la Clé du Feu,,Ti serve la Chiave del Fuoco ,炎の鍵が必要だ,불 열쇠가 필요하다,Je hebt de vuursleutel nodig.,Potrzebujesz Ognistego Klucza,Você precisa da Chave do Fogo,Precisas da Chave do Fogo,Ai nevoie de Cheia de Foc,Для открытия нужен огненный ключ,Треба вам ватрени кључ -You need the Emerald Key,TXT_NEED_KEY_EMERALD,,,,Potřebuješ smaragdový klíč,Du brauchst den Smaragdschlüssel,,Vi bezonas la Smeraldan Ŝlosilon,Necesitas la Llave Esmeralda,,Tarvitset smaragdiavaimen,Vous avez besoin de la Clé d'Emeraude,,Ti serve la Chiave di Smeraldo ,翠玉の鍵が必要だ,에메랄드 열쇠가 필요하다,Je hebt de smaragdensleutel nodig.,Potrzebujesz Szmaragdowego Klucza,Você precisa da Chave Esmeralda,Precisas da Chave Esmeralda,Ai nevoie de Cheia din Smarald,Для открытия нужен изумрудный ключ,Треба вам смарагдни кључ -You need the Dungeon Key,TXT_NEED_KEY_DUNGEON,,,,Potřebuješ klíč od žaláře,Du brauchst den Kerkerschlüssel,,Vi bezonas la Karcer-Ŝlosilon,Necesitas la Llave del Calabozo,,Tarvitset tyrmän avaimen,Vous avez besoin de la Clé du Donjon,,Ti serve la Chiave del Sotterraneo ,迷宮の鍵が必要だ,지하감옥 열쇠가 필요하다,Je hebt de kerkersleutel nodig.,Potrzebujesz Klucza do Lochu,Você precisa da Chave das Masmorras,Precisas da Chave das Masmorras,Ai nevoie de Cheia Temniței,Для открытия нужен ключ от подземелья,Треба вам кључ од тамнице -You need the Silver Key,TXT_NEED_KEY_SILVER,,,,Potřebuješ stříbrný klíč,Du brauchst den Silberschlüssel,Χρειάζεσε το Ασυμένιο κλειδί.,Vi bezonas la Arĝentan Ŝlosilon,Necesitas la Llave de Plata,,Tarvitset hopea-avaimen,Vous avez besoin de la Clé d'Argent,,Ti serve la Chiave d'Argento ,銀の鍵が必要だ,은 열쇠가 필요하다,Je hebt de silveren Sleutel nodig.,Potrzebujesz Srebrnego Klucza,Você precisa da Chave Prata,Precisas da Chave Prata,Ai nevoie de Cheia din Argint,Для открытия нужен серебряный ключ,Треба вам сребрни кључ -You need the Rusted Key,TXT_NEED_KEY_RUSTED,,,,Potřebuješ zrezivělý klíč,Du brauchst den rostigen Schlüssel,Χρειάζεσε το Σκουριασμένο κλειδί.,Vi bezonas la Rustan Ŝlosilon,Necesitas la Llave Oxidada,,Tarvitset ruosteisen avaimen,Vous avez besoin de la Clé Rouillée,,Ti serve la Chiave Arrugginita ,錆びた鍵が必要だ,녹슨 열쇠가 필요하다,Je hebt de geroeste sleutel nodig.,Potrzebujesz Zardzewiałego Klucza,Você precisa da Chave Enferrujada,Precisas da Chave Enferrujada,Ai nevoie de Cheia Ruginită,Для открытия нужен ржавый ключ,Треба вам зарђао кључ -You need the Horn Key,TXT_NEED_KEY_HORN,,,,Potřebuješ parožní klíč,Du brauchst den Hornschlüssel,,Vi bezonas la Hup-Ŝlosilon,Necesitas la Llave de Cuerno,,Tarvitset sarviavaimen,Vous avez besoin de la Clé Corne,,Ti serve la Chiave del Corno ,角の鍵が必要だ,뿔 열쇠가 필요하다,Je hebt de hoornsleutel nodig.,Potrzebujesz Rogowego Klucza,Você precisa da Chave do Chifre,Precisas da Chave do Chifre,Ai nevoie de Cheia Corn,Для открытия нужен роговой ключ,Треба вам рогати кључ -You need the Swamp Key,TXT_NEED_KEY_SWAMP,,,,Potřebuješ klíč od bažiny,Du brauchst den Sumpfschlüssel,,Vi bezonas la Marĉ-Ŝlosilon,Necesitas la Llave del Pantano,,Tarvitset suoavaimen,Vous avez besoin de la Clé des Marécages,,Ti serve la Chiave della Palude ,沼の鍵が必要だ,늪지대 열쇠가 필요하다,Je hebt de moerassleutel nodig.,Potrzebujesz Bagiennego Klucza,Você precisa da Chave do Pântano,Precisas da Chave do Pântano,Ai nevoie de Cheia Mlaștinii,Для открытия нужен болотный ключ,Треба вам мочварни кључ -You need the Castle Key,TXT_NEED_KEY_CASTLE,,,,Potřebuješ klíč od hradu,Du brauchst den Burgschlüssel,,Vi bezonas la Kastel-Ŝlosilon,Necesitas la Llave del Castillo,,Tarvitset linnan avaimen,Vous avez besoin de la Clé du Château,,Ti serve la Chiave del Castello ,城の鍵が必要だ,성 열쇠가 필요하다,Je hebt de kasteelsleutel nodig.,Potrzebujesz Klucza do Zamku,Você precisa da Chave do Castelo,Precisas da Chave do Castelo,Ai nevoie de Cheia Castelului,Для открытия нужен ключ от замка,Треба вам кључ од замка -,,Actor tag names,,,,,,,,,,,,,,,,,,,,, -Afrit,FN_FIREDEMON,,,,,,,Afrito,,,,,,Afrit,アフリート,아프리트,,Afrit,,,Demon de Foc,Африт,Африт -Serpent,FN_DEMON1,,,,Zlohad,Chaos-Schlange,,Serpento,Serpiente,,Käärme,,Kígyó,Serpente del Caos,サーペント,서펜트,Slang,Wąż,Serpente,,Șarpe,Серпент,Серпент -Ettin,FN_ETTIN,,,,,,,Aĉgiganto,,,,,,Ettin,エティン,에틴,,Ettin,,,Etin,Эттин,Етин -Centaur,FN_CENTAUR,,,,Kentaur,Zentaur,,Centaŭro,Centauro,,Kentauri,Centaure,Kentaúr,Centauro,ケンタウロス,켄타우로스,,Centaur,Centauro,,Centaur,Кентавр,Кентаур -Slaughtaur,FN_SLAUGHTAUR,,,,Ničitaur,Schlachtaur,,Buĉataŭro,Massacauro,,Teurastauri,Sangtaure,Slaughtaúr,Sventrauro,スロアタウル,슬로터로스,Slachttaur,Rzeziotaur,Chacinotauro,,Centaur Violent,Старший кентавр,Старији кентаур -Bishop,FN_BISHOP,,,,Biskup,Bischof,,Episkopo,Obispo,,Piispa,Evèque,Érsek,Vescovo,ビショップ,비숍,Bisschop,Biskup,Bispo,,Episcop,Епископ,Епископ -Wendigo,FN_ICEGUY,,,,,,,Vendiko,,,,,,Wendigo,ウェンディゴ,윈디고,,Wendigo,,,Vendigo,Вендиго,Вендиго -Stalker,FN_SERPENT,,,,Slídil,Wasserjäger,,Gvatanto,Acechador,,Vaanija,Chasseur,Cserkész,Cacciatore,ストーカー,스토커,Waterjager,Prześladowca,Caçador,,Vânător,Сталкер,Уходитељ -Reiver,FN_WRAITH,,,,Přízrak,Phantom,,Fantomo,Saqueador,,Ryöväri,,,Incursore,レイバー,리버,,Rozbójnik,Fantasma,,Pungaș,Грабитель,Грабљивац -Death Wyvern,FN_DRAGON,,,,Smrtidrak,Todesdrache,,Mortviverno,Wyvern de la muerte,Guiverno de la muerte,Kuolontraakki,Vouivre de la Mort,,Viverna Mortale,デス ワイバーン,데스 와이번,Doodsdraak,Wiwerna Śmierci,Serpe da Morte,,Balaur al Morții,Виверна смерти,Змај -Korax,FN_KORAX,,,,,,,Korax,,,Kooraks,,,Korax,唯一神コラックス,코락스,,Korax,,,Korax,Коракс,Коракс -Zedek,FN_FBOSS,,,,,,,Zedeko,,,Sedek,,,Zedek,ゼデク,제닥,,Zedek,,,Zedek,Зедек,Зедек -Menelkir,FN_MBOSS,,,,,,,Menelkiro,,,Menelkir,,,Menelkir,メネルキル,메넬키어,,Menelkir,,,Menelkir,Менелкир,Менелкир -Traductus,FN_CBOSS,,,,Traduktus,,,Traduktuso,,,Traduktus,,,Traductus,トラダクタス,트라닥투스,,Traductus,,,Traductus,Традуктус,Традуктус -Heresiarch,FN_HERESIARCH,,,,Arcikacíř,Erzketzer,,Ĉefherezulo,Heresiarca,,Kerettiarkki,L'Hérésiarche,,Eresiarca,ヘレシアーク,헤러시아크,,Herezjarcha,Heresiarca,,Ereziarh,Ересиарх,Јересијарх -Blue Mana,AMMO_MANA1,,,,Modrá mana,Blaues Mana,,Blua Manao,Maná azul,Mana azul,Sininen mana,Mana Bleu,,Mana blu,ブルーマナ,청색 마나,Blauwe Mana,Niebieska Mana,Mana Azul,,Mană Albastră,Синяя мана,Плава мана -Green Mana,AMMO_MANA2,,,,Zelená mana,Grünes Mana,,Verda Manao,Maná verde,Mana verde,Vihreä mana,Mana Vert,,Mana verde,グリーンマナ,녹색 마나,Groene Mana,Zielona Mana,Mana Verde,,Mană Verde,Зелёная мана,Зелена мана -Mace of Contrition,TAG_CWEAPMACE,,,,Palcát kajícnosti,Streitkolben,,Klabo de Penteco,Maza de Contrición,,Katumuksen nuija,Masse de Pénitence,Bűnbánat Buzogánya,Mazza del Pentimento,懺悔のメイス,참회의 철퇴,Foelie van strijdigheid,Buzdygan Skruchy,Maça da Contrição,,Buzduganul Remușcării,Булава раскаяния,Буздован кајања -Serpent Staff,TAG_CWEAPSTAFF,,,,Hadí hůl,Schlangenstab,,Serpentbastono,Bastón de Serpiente,,Käärmesauva,Sceptre du Serpent,Kígyó Bot,Staffa del Serpente ,蛇の杖,뱀 지팡이,Slangenstaf,Laska Węży,Cetro da Serpente,,Bastonul Șarpelui,Змеиный посох,Змијски штап -Firestorm,TAG_CWEAPFLAME,,,,Ohnivá bouře,Feuersturm,,Fajrŝtormo,Tormenta de Fuego,,Tulimyrsky,Tempête de Feu,Tűzvihar,Tempesta di Fuoco ,ファイアストーム,화염폭풍,Vuurstorm,Burza Ognia,Tempestade-de-fogo,,Furtună de Foc,Огненный шторм,Ватрена олуја -Wraithverge,TAG_CWEAPWRAITHVERGE,,,,Zjevitel,Geisterbringer,,Fantomkruc',Báculo Fantasmal,,Haamusauva,Verge Phantasmale,Lélekvég,Verga SconfinaSpettri,レイスバージ,사령의 십자가,Spookbrenger,Widmoskraj,Cajado Fantasma,,Toiag Stafie,Жезл духов,Штап утвара -Spiked Gauntlets,TAG_FWEAPFIST,,,,Ohrocené rukavice,Stachelhandschuhe,,Pintaj Fergantoj,Guanteletes Puntiagudos,,Piikkirautakintaat,Gantelets à Pointes,Tűskés Páncélkesztyűk,Guantoni Spinati,スパイク ガントレット,가시 장갑,Spijkerhandschoenen,Kolczaste Rękawice,Manoplas Espinhadas,,Mănuși cu Țepi,Шипастые перчатки,Бодљикаве рукавице -Timon's Axe,TAG_FWEAPAXE,,,,Timonova sekera,Timons Axt,,Hakilo de Timon,Hacha de Timón,,Timonin kirves,Hache de Timon,Timon Baltája,Ascia di Timon,タイモンの斧,티몬의 도끼,Timon's bijl,Topór Timona,Machado de Timon,,Toporul lui Timon,Топор тимона,Тимонова секира -Hammer of Retribution,TAG_FWEAPHAMMER,,,,Kladivo odplaty,Hammer der Rache,,Martelo de Repago,Martillo de Retribución,,Koston vasara,Marteau de la Rétribution,Büntetés Kalapácsa,Martello del Castigo,報復の金槌,징벌의 망치,Hamer van vergelding,Młot Odkupienia,Martelo da Retribuição,,Ciocanul Salvării,Молот возмездия,Чекић одмазде -Quietus,TAG_FWEAPQUIETUS,,,,Tišitel,Erlöser,,Kvietus',,,,Quietus,Némusz,Quietus,死滅の剣,종언의 검,,Uciszacz,,,Argument Final,Последний довод,Куиетус -Sapphire Wand,TAG_MWEAPWAND,,,,Safírová hůl,Saphirstab,,Safirsorĉbastono,Varita de Zafiro,,Safiirisauva,Baguette de Saphir,Zafír Pálca,Scettro di Zaffiro ,サファイア ワンド,사파이어 지팡이,Saffier Toverstokje,Szafirowa Różdżka,Cetro de Safira,,Toiag cu Safir,Сапфировая волшебная палочка,Сафиров штап -Frost Shards,TAG_MWEAPFROST,,,,Ledové střepy,Frostsplitter,,Frostfragmentoj,Fragmentos de Escarcha,,Pakkassirpaleet,Eclats de Givre,Fagy Szilánkok,Schegge di Ghiaccio ,フロスト シャード,얼음 파편,Vorst Scherven,Lodowe Odłamki,Fragmentos de Geada,,Cioburi de Gheață,Замораживающие осколки,Ледене крхотине -Arcs of Death,TAG_MWEAPLIGHTNING,,,,Jiskry smrti,Todesblitz,,Arkoj de Morto,Arcos de la Muerte,,Kuolonkaaret,Foudre Mortelle,Halál Körívei,Archi della Morte ,死の円弧,죽음의 번갯불,Boog van de Dood,Łuki Śmierci,Arcos da Morte,,Izvoarele Morții,Дуга смерти,Лукови смрти -Bloodscourge,TAG_MWEAPBLOODSCOURGE,,,,Krvehrom,Blutgeißel,,Sangskurĝ',Plaga Sangrienta,,Veripiiska,Fléau Sanglant,Vérkorbács,Flagello di Sangue,天罰,피의 재앙,Bloedplaag,Krwioplaga,Flagelo de Sangue,,Flagel Sângeros,Кровавый бич,Крваво зло -Disc of Repulsion,TAG_ARTIBLASTRADIUS,,,,Kotouč odpuzení,Rückstoßscheibe,,Disko de Repelado,Disco de Repulsión,,Karkotuskiekko,Disque de Répulsion,Visszaszorítás Lemeze,Disco della Repulsione ,反発の円盤,방탄의 원반,Schijf van afstoting,Dysk Odpychania,Disco da Repulsão,,Disc al Repulsiei,Отражающий диск,Диск одвратности -Dragonskin Bracers,TAG_ARTIBOOSTARMOR,,,,Náramky dračích šupin,Drachenhaut-Armschutz,,Brakbendo el Drakhaŭto,Brazaletes de piel de Dragón,,Lohikäärmeennahkarannesuojat,Brassards en peau de Dragon,Sárkánybőr Hevederek,Bracciali in Pelle di Drago ,竜皮の小手,용가죽 팔찌,Draakenhuid bescherming,Karwasze ze Smoczej Skóry,Braçadeiras de Pele de Dragão,,Brățări din Piele de Dragon,Наручи драконьей кожи,Наруквице од змајеве коже -Krater of Might,TAG_ARTIBOOSTMANA,,,,Kalich síly,Kelch der Macht,,Kratero de Potenco,Crátera de Poder,,Mahtikrateeri,Cratère de Pouvoir,Hatalom Kráterje,Calice della Forza,魔力の盃,힘의 향로,Beker van Macht,Czara mocy,Cálice do Poder,,Pocal al Puterii,Кубок могущества,Кратер силе -Flechette,TAG_ARTIPOISONBAG,,,,Střelka,,,Flakono,,,,Fléchette,Nyíl,Fiaschetta ,フレシェット,플레셰트,,Flaszka,,,Flacon,Флешетта,Флечет -Poison Cloud Flechette,TAG_ARTIPOISONBAG1,,,,Otrávená střelka,Flechette (Giftwolke),,Venennub-Flakono,Flechette de Nube Venenosa,,Myrkkypilviflechette,Fléchette - Nuage Toxique,Mérgező Felhő Nyíl,Fiaschetta Velenosa,毒ガス フレシェット,독구름 플레셰트,Flechette (giftige wolk),Flaszka Trującej Chmury,Flechette de Nuvem Venenosa,,Flacon cu Otravă,Флешетта ядовитого облака,Флечет отровног облака -Timebomb Flechette,TAG_ARTIPOISONBAG2,,,,Časovaná střelka,Flechette (Zeitbombe),,Horloĝbomb-Flakono ,Bomba de Tiempo Flechette,,Aikapommiflechette,Fléchette - Bombe a Retardement,Időbomba Nyíl,Fiaschetta a Tempo ,時限爆弾フレシェット,시한폭탄 플레셰트,Flechette (tijdbom),Flaszka-Bomba Zegarowa,Flechette Bomba-Relógio,,Bombă cu Ceas,Флешетта часовой бомбы,Флечет временске бомбе -Grenade Flechette,TAG_ARTIPOISONBAG3,,,,Granátová střelka,Flechettre (Granate),,Grenad-Flakono,Granada Flechette,,Kranaattiflechette,Fléchette - Grenade,Gránát Nyíl,Fiaschetta da Lancio,グレネードフレシェット,폭발성 플레셰트,Flechette (granaat),Flaszka-Granat,Flechette Granada,,Flacon-Grenadă,Флешетта граната,Флечет граната -Mystic Ambit Incant,TAG_ARTIHEALINGRADIUS,,,,Tajemný svitek okolí,,,Sorĉo de Mistika Sfero,Encantamiento de Ámbito Místico,,Mystisen piirin loitsu,Incantation Mystique,Misztikus Mágialista,Incantamento Mistico ,魅知国の秘法,신비 영역의 주문,,Inkantancja Mistycznego Kręgu,Encantamento Místico,,Pergament Mistic,Мистический зачарованный свиток,Мистични очарани свитак -Icon of the Defender,TAG_ARTIDEFENDER,,,,Obráncova ikona,Ikone des Verteidigers,,Ikono de la Defendanto,Icono del Defensor,Ícono del Defensor,Puolustajan ikoni,Icône du Défenseur,Védelmező Ikonja,Emblema del Difensore ,守護者の像,수호의 성상,,Ikona Obrońcy,Ícone do Defensor,,Imaginea Apărătotului,Икона защитника,Икона браниоца -Porkalator,TAG_ARTIPORK,,,,Vepřovitel,Porkalator,,Porkigilo,Porcinador,,Sikaannuttaja,Porcificateur,Malacátor,Porchificatore,ポークレイター,돈육기,,Schabowator,Porquificador,,Porcolator,Хрякинатор,Поркалатор -Boots of Speed,TAG_ARTISPEED,,,,Běhuté boty,Turbo-Stiefel,,Botoj de Rapideco,Botas de Velocidad,,Ripeyssaappaat,Bottes de Célérité,Sebesség Cipői,Stivali della Fretta,素早さの靴,속도의 부츠,Snelheidslaarzen,Buty Szybkości,Botas da Rapidez,,Bocancii Vitezei,Сапоги-скороходы,Чизме брзине -Dark Servant,TAG_ARTISUMMON,,,,Temný služebník,Dunkler Diener,,Malluma Servanto,Servidor Oscuro,,Pimeä palvelija,Serviteur Noir,Sötét Szolga,Servo Oscuro,闇の従者,어둠의 하인,Donkere dienaar,Mroczny Sługa,Servo Negro,,Servitor Întunecat,Тёмный слуга,Мрачни слуга -Banishment Device,TAG_ARTITELEPORTOTHER,,,,Vyhošťovač,Verbannungsgerät,,Forpelilo,Dispositivo de Destierro,,Häivytyskoje,Outil de Banissement,Számüzető Készülék,Congegno dell'Esilio,追放のデバイス,소멸 장치,Verbanningsapparaat,Urządzenie Wygnania ,Dispositivo do Banimento,,Dispozitiv al Alungării,Механизм изгнания,Уређај протеривања -Yorick's Skull,TAG_ARTIPUZZSKULL,,,,Jorikova lebka,Yoricks Schädel,,Kranio de Yorick,Calavera de Yorick,Cráneo de Yorick,Yorickin kallo,Crâne de Yorick,Yorick Koponyája,Teschio di Yorick,ヨリックの髑髏,요릭의 두개골,Yorick's schedel,Czaszka Yoricka,Crânio de Yorick,,Craniul lui Yorick,Череп Йорика,Јорикова лобања -Heart of D'Sparil,TAG_ARTIPUZZGEMBIG,,,,Srdce D'Sparila,D'Sparils Herz,,Koro de D'sparil,Corazón de D'Sparil,,D'Sparilin sydän,Cœur de D'Sparil,D'Sparil Szíve,Cuore di D'Sparil,デ'スパリルの心,드'스파릴의 심장,Hart van D'sparil,Serce D'Sparila,Coração de D'Sparil,,Inima lui D'Sparil,Сердце Д'Спарила,Срце Д'Спарила -Ruby Planet,TAG_ARTIPUZZGEMRED,,,,Rubínová planeta,Rubinplanet,,Rubena Planedo,Planeta Rubí,,Rubiiniplaneetta,Planète en rubis,Rubin Bolygó,Pianeta di Rubino,ルビーの宝石,루비 행성석,Robijnrode planeet,Rubinowa Planeta,Planeta Rubi,,Planetă din Rubin,Рубиновая планета,Планета рубина -Emerald Planet (1),TAG_ARTIPUZZGEMGREEN1,,,,Smaragdová planeta (1),Smaragdplanet (1),,Smeralda Planedo (1),Planeta Esmeralda (1),,Smaragdiplaneetta (1),Planète en émeraude (1),Smaragd Bolygó (1),Pianeta di Smeraldo (1),エメラルドの宝石1,에메랄드 행성석 (1),Smaragdgroene planeet (1),Szmaragdowa Planeta (1),Planeta Esmeralda (1),,Planetă din Smarald (1),Изумрудная планета (1),Планета смарагда (1) -Emerald Planet (2),TAG_ARTIPUZZGEMGREEN2,,,,Smaragdová planeta (2),Smaragdplanet (2),,Smeralda Planedo (2),Planeta Esmeralda (2),,Smaragdiplaneetta (2),Planète en émeraude (2),Smaragd Bolygó (2),Pianeta di Smeraldo (2),エメラルドの宝石2,에메랄드 행성석 (2),Smaragdgroene planeet (2),Szmaragdowa Planeta (2),Planeta Esmeralda (2),,Planetă din Smarald (2),Изумрудная планета (2),Планета смарагда (2) -Sapphire Planet (1),TAG_ARTIPUZZGEMBLUE1,,,,Safírová planeta (1),Saphirplanet (1),,Safira Planedo (1),Planeta Zafiro (1),,Safiiriplaneetta (1),Planète en saphir (1),Zafír Bolygó (1),Pianeta di Zaffiro (1),サファイアの宝石1,사파이어 행성석 (1),Saffier Planeet (1),Szafirowa Planeta (1),Planeta Safira (1),,Planetă din Safir (1),Сапфировая планета (1),Планета сафира (1) -Sapphire Planet (2),TAG_ARTIPUZZGEMBLUE2,,,,Safírová planeta (2),Saphirplanet (2),,Safira Planedo (2),Planeta Zafiro (2),,Safiiriplaneetta (2),Planète en saphir (2),Zafír Bolygó (2),Pianeta di Zaffiro (2),サファイアの宝石2,사파이어 행성석 (2),Saffier Planeet (2),Szafirowa Planeta (2),Planeta Safira (2),,Planetă din Safir (2),Сапфировая планета (2),Планета сафира (2) -Daemon Codex,TAG_ARTIPUZZBOOK1,,,,,,,Kodekso de Demono,Códice del Demonio,,,Codex Démoniaque,Démon Kódex,Codice Demoniaco ,デーモンの写本,악마의 고문서,,Demoniczny Kodeks,Códice Demoníaco,,Codexul Demonilor,Демонический кодекс,Демонски кодекс -Liber Oscura,TAG_ARTIPUZZBOOK2,,,,,,,Liber Oscura,Liber Oscura,,,,,,オスキュラ公文書,어둠의 자유서,,Liber Oscura,,,Liber Obscura,Либер Оскура,Либер Оскура -Flame Mask,TAG_ARTIPUZZSKULL2,,,,Plamenná maska,Flammenmaske,,Fajrmasko,Mascara de Llamas,Mascara de Flamas,Liekkinaamio,Masque de Flammes,Láng Maszk,Maschera delle Fiamme ,炎の仮面,화염의 가면,Vlammasker,Maska Płomieni,Máscara das Chamas,,Mască de Foc,Маска пламени,Маска пламена -Glaive Seal,TAG_ARTIPUZZFWEAPON,,,,Glévská pečeť,Schwertsiegel,,Sigelo de Glavo,Sello de Espada,,Miekkasinetti,Sceau du Glaive,Glaive Pecsét,Sigillo del Brando,グレイブシール,밀폐된 칼날,Zwaardzegel,Pieczęć Glewii,Selo do Gládio,,Sigiliu Spadă,Печать воителя,Запечаћено сечиво -Holy Relic,TAG_ARTIPUZZCWEAPON,,,,Svatá relikvie,Heiliges Relikt,,Sankta Relikvo,Santa Reliquia,,Pyhä reliikki,Relique Sacrée,Szent Ereklye,Reliquia Sacra,聖遺物,신성한 유물,Heilige Relikwie,Święta Relikwia,Relíquia Sagrada,,Relicvă Sfântă,Святая реликвия,Света реликвија -Sigil of the Magus,TAG_ARTIPUZZMWEAPON,,,,Mágovo sigilium,Symbol des Magiers,,Sigelo de la Mago,Emblema del Mago,,Taikurin sinetti,Sceau du Mage,Mágus Pecsétje,Suggello del Magus,メイガスの印章,마거스의 인장,Sigaar van de Magus,Emblemat Maga,Sígilo do Mago,,Sigiliul Magului,Символ мага,Симбол Магуса -Iron gear,TAG_ARTIPUZZGEAR1,,,,Železné kolečko,Eisenzahnrad,,Fera Dentrado,Engranaje de Hierro,,Rautaratas,Engrenage en Fer,Vas Felszerelés,Ingranaggio di Ferro,鉄の歯車,양철 톱니바퀴,IJzeren versnelling,Żelazna Zębatka,Engrenagem de ferro,,Mecanism din fier,Железная шестерня,Сатни зупчаник -Brass gear,TAG_ARTIPUZZGEAR2,,,,Mosazné kolečko,Messingzahnrad,,Latuna Dentrado,Engranaje de Bronce,,Messinkiratas,Engrenage en Bronze,Sárgaréz Felszerelés,Ingranaggio di Ottone ,真鍮のギア,황동 톱니바퀴,Messing versnelling,Mosiężna Zębatka,Engrenagem de latão,,Mecanism din alamă,Латунная шестерня,Месингани зупчаник -Brass and iron gear,TAG_ARTIPUZZGEAR3,,,,Mosazo-železné kolečko,Messing-und-Eisen-Zahnrad,,Latuna Fera Dentrado,Engranaje de Bronce y Hierro,,Messinki- ja rautaratas,Engrenage en Fer et Bronze,Vas és Sárgaréz Felszerelés,Ingranaggio di Ferro e Ottone ,鉄と真鍮のギア,황동과 양철 톱니바퀴,Messing en ijzeren versnelling,Zębatka z mosiądzu i żelaza,Engrenagem de ferro e latão,,Mecanism din alamă și fier,Латунно-железная шестерня,Месингани и сатни зупчаник -Silver and brass gear,TAG_ARTIPUZZGEAR4,,,,Střibro-mosazné kolečko,Silber-und-Messing-Zahnrad,,Arĝenta Latuna Dentrado,Engranaje de Plata y Bronce,,Hopea- ja messinkiratas,Engrenage en Argent et Bronze,Ezüst és Sárgaréz Felszerelés,Ingranaggio di Ottone e Argento ,銀と真鍮のギア,은과 황동 톱니바퀴,Zilver en messing versnelling,Zębatka ze srebra i mosiądzu,Engrenagem de prata e latão,,Mecanism din argint și alamă,Серебряно-латунная шестерня,Сребрни и месингани зупчаник -,,Obituaries,,,,,,,,,,,,,,,,,,,,, -%o tasted an Afrit's fire.,OB_FIREDEMON,,,,%o ochutnal@[ao_cs] Afritův oheň.,%o spürte das Feuer des Afrits.,,%o gustis la fajron de Afrito.,%o probó el fuego de un Afrit.,,%o maistoi afritin tulta.,%o a goûté au feu d'un Afrit.,%o megkóstolta a Tűz Szellem varázsát.,%o ha assaggiato il fuoco di un Afrit. ,%o はアフリートの炎を味わった。,%o 은(는) 아프리트의 화염을 맛봤다.,%o proefde het vuur van een draak.,%o spróbował@[ao_pl] ognia Afrita.,%o provou o fogo de um Afrit.,,%o a gustat flacăra Demonului de Foc.,%o отведал@[ao_rus] огня Африта.,%o је окушен@[adj_1_sr] Афритовом ватром. -%o was scalded by a Serpent.,OB_DEMON1,,,,%o byl@[ao_cs] spálen@[ao_cs] Zlohadem.,%o wurde von der Chaos-Schlange gebissen.,,%o burlegiĝis per Serpento.,%o fue escaldad@[ao_esp] por una Serpiente.,,%o joutui käärmeen kalttaamaksi.,%o a été brûlé@[e_fr] par un Serpent.,%o meglett forrázva egy Kígyó által.,%o è stato sciolto da un Serpente del Caos,%o はサーペントに火傷を負わされた。,%o 은(는) 서펜트에 데였다.,%o werd gebroeid door een slang.,%o został@[ao_pl] poparzon@[adj_pl] przez Węża.,%o foi escaldad@[ao_ptb] por uma Serpente.,,%o a fost opărit de un Șarpe.,Игрока %o спалил Серпент.,%o је ошурен@[adj_1_sr] од Серпента. -%o was poisoned by a Serpent.,OB_DEMON2,,,,%o byl@[ao_cs] otráven@[ao_cs] Zlohadem.,%o wurde von der Chaos-Schlange verbrannt.,,%o veneniĝis per Serpento.,%o fue envenenad@[ao_esp] por una Serpiente.,,%o joutui käärmeen myrkyttämäksi.,%o a été empoisonné@[e_fr] par un Serpent.,%o meglett mérgezve egy Kígyó által.,%o è stato avvelenato da un Serpente del Caos. ,%o はサーペントの毒にやられた。,%o 은(는) 독 서펜트에게 중독 당했다.,%o werd vergiftigd door een slang.,%o został@[ao_pl] zatrut@[adj_pl] przez Węża.,%o foi envenenad@[ao_ptb] por uma Serpente.,,%o a fost otrăvit de un Șarpe.,Игрока %o отравил Серпент.,%o је отров@[adj_2_sr] од Серпента. -%o was mashed by an Ettin.,OB_ETTIN,,,,%o byl@[ao_cs] umlácen@[ao_cs] Ettinem.,%o wurde von dem Ettin zermatscht.,,%o frakasiĝis per Aĉgiganto.,%o fue hech@[ao_esp] puré por un Ettin.,%o quedó hech@[ao_esp] puré por un Ettin.,%o joutui ettinin muhentamaksi.,%o a été réduit@[e_fr] en purée par un Ettin.,%o péppé lett ütve egy Kétfejű által.,%o è stato schiacciato da un Ettin. ,%o はエティンに潰された。,%o 은(는) 에틴에게 철퇴를 맞았다.,%o werd gepureerd door een Ettin.,%o został@[ao_pl] stłuczon@[adj_pl] przez Ettina.,%o foi feito purê por um Ettin.,,%o a fost făcut piure de un Etin.,Игрока %o раздробил Эттин.,%o је згњечен@[adj_1_sr] од Еттина. -%o was cut up by a Centaur.,OB_CENTAUR,,,,%o byl@[ao_cs] rozsekán@[ao_cs] Kentaurem.,%o wurde von dem Zentaur aufgeschlitzt.,,%o distranĉiĝis per Centaŭro.,%o fue partid@[ao_esp] por un Centauro.,,%o joutui kentaurin pilkkomaksi.,%o a été tranché@[e_fr] par un Centaure.,%o szétlett vágva egy Kentaur által.,%o è stato affettato da un Centauro. ,%o はケンタウロスに切り刻まれた。,%o 은(는) 켄타우로스에 의해 절단됐다.,%o werd versneden door een Centaur.,%o został@[ao_pl] pocięt@[adj_pl] przez Centaura.,%o foi fatiad@[ao_ptb] por um Centauro.,,%o a fost tăiat deschis de un Centaur.,Игрока %o разрезал Кентавр.,%o је заклан@[adj_1_sr] од Кентаура. -%o was cut up by a Slaughtaur.,OB_SLAUGHTAURHIT,,,,%o byl@[ao_cs] rozsekán@[ao_cs] Ničitaurem.,%o wurde von dem Schlachtaur aufgeschlitzt.,,%o distranĉiĝis per Buĉataŭro.,%o fue partid@[ao_esp] por un Masacrauro.,,%o joutui teurastaurin pilkkomaksi.,%o a été tranché@[e_fr] par un Sangtaure.,%o szétlett vágva egy Vágtaur által.,%o è stato affettato da uno Sventrauro. ,%o はスロアタウルに切り刻まれた。,%o 은(는) 슬로터로스에 의해 심하게 절단됐다.,%o werd versneden door een Slachtaur.,%o został@[ao_pl] pocięt@[adj_pl] Rzeziotaura.,%o foi fatiad@[ao_ptb] por um Chacinotauro.,,%o a fost tăiat deschis de un Centaur Violent.,Игрока %o разрезал Старший кентавр.,%o је заклан@[adj_1_sr] од Старијег кентаура. -%o was struck down by a Slaughtaur's fireball.,OB_SLAUGHTAUR,,,,%o byl@[ao_cs] zabit@[ao_cs] Ničitaurovou ohnivou koulí.,%o wurde von dem Feuerball des Schlachtaurs niedergestreckt.,,%o subite mortiĝis per fajropilko de Buĉataŭro.,%o fue abatid@[ao_esp] por la bola de fuego de un Masacrauro.,,%o joutui teurastaurin tulipallon kaatamaksi.,%o a été touché@[e_fr] par une boule de feu de Sangtaure.,%o szétesett egy Vágtaur tűzgolyója által.,%o è stato abbattuto dalla palla di fuoco di uno Sventrauro. ,%o はスロアタウルの火玉に倒された。,%o 은(는) 슬로터로스의 마법구에 의해 피격당했다.,%o werd neergeslagen door een Slachtaur's vuurbal.,%o został@[ao_pl] trafion@[adj_pl] przez kulę ognia Rzeziotaura.,%o foi abatid@[ao_ptb] pela bola de fogo de um Chacinotauro.,,"%o a fost răpus de mingea de foc a unui Centaur -Violent.",Игрока %o сбил огненным шаром Старший кентавр.,%o је оборен@[adj_1_sr] Кентауровом ватреном лоптом. -%o succumbed to a Bishop's dark power.,OB_BISHOP,,,,%o podlehl@[ao_cs] Biskupově temné moci.,%o fiel der dunklen Macht des Bischofs zum Opfer.,,%o subfaliĝis per malluma potenco de Episkopo.,%o fue sucumbid@[ao_esp] al poder oscuro de un Obispo.,,%o lankesi piispan pimeään voimaan.,%o a succombé au pouvoir obscur d'un évèque.,%o megadta magát a Püspök fekete erejének.,%o è stato sottomesso dalla magia oscura di un Vescovo. ,%o はビショップの闇の力に屈した。,%o 은(는) 비숍의 힘에 무릎을 꿇었다.,%o bezweek aan de donkere kracht van een bisschop.,%o uległ@[ao_pl] mrocznej mocy Biskupa.,%o sucumbiu ao poder negro de um Bispo.,,%o a cedat puterii întunecate a Episcopului.,%o поддал@[refl_rus] чёрным силам Епископа.,%o је покорен@[adj_1_sr] Епископовој мрачној сили. -%o was frozen solid by a Wendigo.,OB_ICEGUY,,,,%o byl@[ao_cs] zamrznut@[ao_cs] Wendigem.,%o wurde von dem Wendigo tiefgefroren.,,%o tute frostiĝis per Vendiko.,%o quedó congelad@[ao_esp] por un Wendigo.,,%o joutui wendigon läpikotaisin jäädyttämäksi.,%o a été gelé@[e_fr] par un Wendigo.,%o befagyott egy Wendigo által.,%o è stato congelato da un Wendigo. ,%o はウェンディゴによって固められた。,%o 은(는) 윈디고에 의해 단단하게 얼려졌다.,%o was bevroren door een Wendigo.,%o został@[ao_pl] zamrożon@[adj_pl] przez Wendigo.,%o foi congelad@[ao_ptb] por um Wendigo.,,%o a fost făcut statuie de un Vendigo.,Игрока %o полностью заморозил Вендиго.,%o је чврсто замрзнут@[adj_1_sr] од Вендига. -%o was mauled by a Stalker.,OB_SERPENTHIT,,,,%o byl@[ao_cs] umlácen@[ao_cs] Slídilem.,%o wurde von dem Wasserjäger zerfleischt.,,%o vundegiĝis per Gvatanto.,%o fue triturad@[ao_esp] por un Acechador.,,%o joutui vaanijan raatelemaksi.,%o a été mutilé@[e_fr] par un Chasseur.,%o szétlett marcangolva egy Orvvadász által.,%o è stato malmenato da un Cacciatore. ,%o はストーカーに引っ掻かれた。,%o 은(는) 스토커에게 발렸다.,%o werd verminkt door een Waterjager.,%o został@[ao_pl] poturbowan@[adj_pl] przez Prześladowcę.,%o foi mutilad@[ao_ptb] por um Caçador.,,%o a fost sfâșiat de un Vânător.,Игрока %o сломал Сталкер.,%o је растрган@[adj_1_sr] од Сталкера. -%o was melted by a Stalker.,OB_SERPENT,,,,%o byl@[ao_cs] rozpuštěn@[ao_cs] Slídilem.,%o wurde von dem Wasserjäger geschmolzen.,,%o fandiĝis per Gvatanto.,%o fue derretid@[ao_esp] por un Acechador.,,%o joutui vaanijan sulattamaksi.,%o a été fondu@[e_fr] par un Chasseur.,%o szétfolyt egy Orvvadász által.,%o è stato squagliato da un Cacciatore. ,%o はストーカーに溶かされた。,%o 은(는) 스토커에 의해 녹았다.,%o werd gesmolten door een Waterjager.,%o został@[ao_pl] stopion@[adj_pl] przez Prześladowcę.,%o foi derretid@[ao_ptb] por um Caçador.,,%o a fost topit de un Vânător.,Игрока %o расплавил Сталкер.,%o је растопљен@[adj_1_sr] од Сталкера. -%o was charred by a Reiver.,OB_WRAITH,,,,%o byl@[ao_cs] zpopelněn@[ao_cs] Přízrakem.,%o wurde von dem Phantom verkohlt.,,%o brulegiĝis per Fantomo.,%o fue carbonizad@[ao_esp] por un Saqueador.,,%o joutui ryövärin hiiltämäksi.,%o a été carbonisé@[e_fr] par un Reiver.,%o elszenesedett egy Fosztogató által.,%o è stato carbonizzato da un Incursore. ,%o はレイバーに黒焦げにされた。,%o 은(는) 리버에 의해 그슬렸다.,%o werd verbrand door een Reiver.,%o został@[ao_pl] zwęglon@[adj_pl] przez Rozbójnika.,%o foi carbonizad@[ao_ptb] por um Fantasma.,,%o a fost ceruit de un Pungaș.,Игрока %o обуглил Грабитель.,%o је спаљен@[adj_1_sr] од Грабљивца. -%o had %p life stolen by a Reiver.,OB_WRAITHHIT,,,,%o si nechal@[ao_cs] ukradnout život Přízrakem.,%o wurde das Leben von dem Phantom gestohlen.,,%o havis sian vivon ŝtelita per Fantomo.,%o fue robad@[ao_esp] de su vida por un Saqueador.,,Ryöväri riisti pelaajan %o hengen.,%o a perdu la vie face à un Reiver.,%o élete el lett lopva egy Fosztogató által.,%o ha permesso che un Incursore prosciugasse la sua vita ,%o はレイバーに命を %p盗まれた。,%o 은(는) 리버에게 영혼을 도둑맞았다.,%o had @[zijn_haar_nl] leven gestolen door een Reiver.,"Życie %o zostało skradzione przez Rozbójnika. -",%o teve sua vida roubada por um Fantasma.,,Viața lui %o a fost furată de un Pungaș.,Жизнь игрока %o украл Грабитель.,Живот играча %o је украо Грабљивац. -%o was incinerated by the Death Wyvern.,OB_DRAGON,,,,%o byl@[ao_cs] upálen@[ao_cs] Smrtidrakem.,%o wurde von dem Todesdrachen verbrannt.,,%o cindriĝis per Mortviverno.,%o fue calcinad@[ao_esp] por el Guiverno de la Muerte.,,%o joutui kuolontraakin polttamaksi.,%o a été incinéré@[e_fr] par une vouivre de la mort.,%o el lett égetve egy Halál Sárkány által.,%o è stato incenerito da una Viverna Mortale. ,%o はダークワイバーンに焼却された。,%o 은(는) 데스 와이번에 의해 분신 당했다.,%o werd verbrand door de Doodsdraak.,%o został@[ao_pl] spalon@[adj_pl] przez Wiwernę Śmierci.,%o foi incinerad@[ao_ptb] por uma Serpe da Morte,,%o a fost incinerat de Balaurul Morții.,Игрока %o кремировала Виверна Смерти.,%o је претворен@[adj_1_sr] у пепео од Змаја. -%o was swept from the board by Korax.,OB_KORAX,,,,%o byl@[ao_cs] odebrán@[ao_cs] ze šachovnice Koraxem.,%o wurde von Korax vom Feld gefegt.,,%o estis prenita el la tabulo per Korax.,%o fue barrid@[ao_esp] del tablero por Korax.,,%o pyyhkäistiin laudalta Kooraksen voimasta.,%o a été balayé@[e_fr] de l'échiquier par Korax.,%o el lett söpörve a tábláról Korax által.,%o è stato eliminato dalla scacchiera da Korax. ,%o は唯一神の怒りに触れた。,%o 은(는) 코락스의 체스판에서 사라졌다.,%o werd door Korax van het bord geveegd.,%o został@[ao_pl] zmiecion@[adj_pl] z pokładu przez Koraxa.,%o foi eliminad@[ao_ptb] do tabuleiro por Korax.,,%o a fost măturat de pe drum de Korax.,Игрока %o скинул с доски Коракс.,%o је збрисан@[adj_1_sr] са табле од Коракса. -%o was slain by Zedek.,OB_FBOSS,,,,%o byl@[ao_cs] zabit@[ao_cs] Zedekem.,%o wurde von Zedek hingemetzelt.,,%o mortigis per Zedeko.,%o recibió una puñalada de Zedek.,,%o joutui Sedekin tappamaksi.,%o a été pourfendu@[e_fr] par Zedek.,%o meghalt Zedek által.,%o è stato ammazzato da Zedek. ,%o はゼデクに討ち取られた。,%o 은(는) 제닥의 이름으로 쓰러졌다.,%o werd gedood door Zedek.,%o został@[ao_pl] zgładzon@[adj_pl] przez Zedeka.,%o foi mort@[ao_ptb] por Zedek.,,%o a fost omorât de Zedek.,Игрока %o сразил Зедек.,%o је убијен@[adj_1_sr] од Зедека. -%o couldn't absorb Menelkir's Mana.,OB_MBOSS,,,,%o nemohl@[ao_cs] pojmout Menelkirovu manu.,%o konnte Menelkirs Mana nicht verkraften.,,%o ne povis absorbi la Manaon de Menelkiro.,%o no pudo absorber el maná de Menelkir.,%o No pudo absorber el mana de Menelkir.,%o ei kyennyt ottamaan vastaan Menelkirin manaa.,%o n'aurait pu absorber le mana de Menelkir.,%o nem tudta elnyelni Menelkir manáját.,%o non è riuscito ad assorbire il mana di Menelkir. ,%o はメネルキルのマナを吸収できなかった。,%o 은(는) 메넬키어의 마나를 흡수하지 못했다.,%o kon Menelkir's Mana niet absorberen.,%o nie m@[irreg_4_pl] wchłonąć Many Menelkira.,%o não conseguiu absorver a Mana de Menelkir.,,%o nu a reușit să absoarbă mana lui Menelkir.,%o не смог@[irreg_2_rus] бороться с маной Менелкира.,%o није мог@[ao_2_sr] упити Менелкирову ману. -%o was baptized by Traductus.,OB_CBOSS,,,,%o byl@[ao_cs] posvěcen@[ao_cs] Traduktem.,%o wurde von Traductus getauft.,,%o baptiĝis per Traduktuso.,%o fue bautizad@[ao_esp] por Traductus.,,%o joutui Traduktuksen kastamaksi.,%o a été baptisé@[e_fr] par Traductus.,%o meglett keresztelve Traductus által.,%o è stato battezzato da Traductus. ,%o はトラダクタスの洗礼を受けた。,%o 은(는) 트라닥투스에게 침례를 당했다.,%o werd gedoopt door Traductus.,%o został@[ao_pl] ochrzczon@[adj_pl] przez Traductusa.,%o foi batizad@[ao_ptb] por Traductus.,,%o a fost botezat de Traductus.,Игрока %o крестил Традуктус.,%o је крштен@[adj_1_sr] од Традуктуса. -%o had %p bones rolled by the Heresiarch.,OB_HERESIARCH,,,,%o si nechal@[ao_cs] rozmetat kosti Arcikacířem.,%os Knochen wurden vom Erzketzer gerollt.,,%o havis siajn ostojn rulis per la Ĉefherezulo.,%o tuvo sus huesos arrollados por el Heresiarca.,,Kerettiarkki jyräsi pelaajan %o luut.,%o s'est fait@[e_fr] rouler les os par l'Hérésiarche.,%o csontváza kilett forgatva az Eretnek Vezér által.,Le ossa di %o sono state accartocciate dall'Eresiarca. ,%o はヘレシアークに骨を %p本 撒き散らされた。,%o 은(는) 헤러시아크에 의해 뼈와 살이 분리되었다.,%o had @[zijn_haar_nl] botten gerold door de Heresiarch.,Kości %o zostały porozrzucane przez Herezjarchę.,%o teve seus ossos moídos pelo Heresiarca.,,Oasele lui %o au fost făcute praf de către Ereziarh.,Ересиарх сыграл в кости игрока %o.,Јересијарх је бацио кости играча %o. -%o was beaten to a pulp by %k's bare fists.,OB_MPFWEAPFIST,,,,%o byl@[ao_cs] umlácen@[ao_cs] k smrti holými pěstmi hráče %k.,%o wurde von %ks nackten Fäusten zu Hackfleisch verarbeitet.,,%o kaĉe draŝiĝis per la nudaj pugnoj de %k.,%o quedó molid@[ao_esp] a golpes por los puños limpios de %k.,,%k hakkasi %o paran muusiksi paljailla nyrkeillään.,%o à été tabassé@[e_fr] à mort par les poings de %k.,%o péppé lett verve %k ökleivel.,%k ha ridotto %o in poltiglia a mani nude.,%o は %k に素手でボコボコにされた。,%o 은(는) %k 의 맨손 타격으로 묵사발이 되었다.,%o werd tot pulp geslagen door %k's blote vuisten.,%o został@[ao_pl] zbit@[adj_pl] na miazgę przez gołe pięści %k.,%o foi espancad@[ao_ptb] até a morte pelos punhos nus de %k.,,%k l-a omorât în bătaie pe %o cu mâinile goale.,Игрок %o избит в мясо голыми руками %k.,%o је пребијен@[adj_1_sr] на смрт голим рукама играч %k. -%o got the axe from %k.,OB_MPFWEAPAXE,,,,%o dostal@[ao_cs] sekerou od hráče %k.,%o sah %ks Axt.,,%o akiris hakilon el %k.,%o recibió el hachazo de %k.,,%o sai pelaajan %k kirveestä.,%o s'est fait@[e_fr] hacher menu par %k.,%o megkapta %k baltáját.,%o ha preso un colpo d'ascia da %k.,%o は %k から斧を受けた。,%o 은(는) %k 의 티몬의 도끼를 어설프게 받아쳤다.,%o kreeg de bijl van %k.,%o dostał@[ao_pl] z topora %k.,%o recebeu o machado de %k.,,%o a primit un topor de la %k.,Игрок %o словил топорик %k.,%o је добио секиру од %k. -%o had %p head caved in by %k's hammer.,OB_MPFWEAPHAMMERM,,,,%o ztratil@[ao_cs] hlavu kladivem hráče %k.,%o wurde der Kopf von %ks Hammer eingeschlagen.,,%p havis sian kapon enfalis per la martelo de %k.,%o tuvo su cabeza hundida por el martillo de %k.,,%k painoi vasarallaan %o paran pään kasaan.,%o s'est fait@[e_fr] éclater le crâne par le marteau de %k.,%o kapott egy üreges fejet %k Kalapácsa által.,La testa di %o è stata aperta in due dal martello di %k.,%o は %k のハンマーで頭に空洞を開けられた。,%k 은(는) 징벌의 망치로 %o 의 머리 위에 우물을 만들었다.,%o had @[zijn_haar_nl] kop ingestort met %k's hamer.,Głowa %o została zmiażdżona przez młot %k.,%o teve seu crânio afundado pelo martelo de %k.,%o teve seu crânio amolgado pelo martelo de %k.,%k i-a băgat capul lui %o în interior cu ciocanul.,Голова игрока %o была вдолблена в тело молотом %k.,Играч %k је расцепао играчу %o главу. -%o's soul was forged anew by %k's hammer.,OB_MPFWEAPHAMMERR,,,,%o@[psf1_cs] duše byla obrozena kladivem hráče %k.,%os Seele wurde durch %ks Hammer erneuert.,,La animo de %o nove forĝiĝis per la martelo de %k.,El alma de %o fue forjada de nuevo por el martillo de %k.,,%k uudelleentakoi %o paran sielun vasarallaan.,%o a eu son âme reforgée par le marteau de %k.,%o lelke újra lett kovácsolva %k Kalapácsa által.,L'anima di %o è stata riforgiata dal martello di %k.,%o の魂は %k のハンマーで一から鍛え直された。,%o 의 영혼은 %k 의 징벌의 망치에 의해 철거되었다.,De ziel van %o was opnieuw gesmeed van %k's hamer.,Dusza %o została wykuta na nowo przez młot %k.,%o teve sua alma reforjada pelo martelo de %k.,,%k i-a făcut sufletul lui %o ca nou cu ciocanul.,Душа игрока %o была перекована молотом %k.,Играч %k је прековао душу играча %o чекићем. -%o was silenced by %k's mighty Quietus.,OB_MPFWEAPQUIETUS,,,,%o byl@[ao_cs] umlčen@[ao_cs] mocným Tišitelem hráče %k.,%o wurde durck %ks Erlöser befreit.,,%o slientiĝis per La Pova Kvietus' de %k.,%o fue silenciad@[ao_esp] por el poderoso Quietus de %k.,,%k vaiensi %o paran mahtavalla Quietuksellaan.,%o à été réduit@[e_fr] au silence par le pouvoir de %k et Quietus.,%o el lett némítva %k hatalmas Némusza által.,%o è stato zittito dal potente Quietus di %k.,%o は %k の強靭なクワイエタスで静かにされた。,%o 은(는) %k 의 종언의 검 덕에 침묵을 지킬 수 있었다.,%o werd tot zwijgen gebracht door %k's machtige Quietus.,%o został@[ao_pl] uciszon@[adj_pl] przez %k.,%o foi silenciad@[ao_ptb] pelo poderoso Quietus de %k.,,"%o a fost redus la tăcere de argumentul final al -lui %k.",Игрок %o утихомирен легендарным Последним доводом %k.,%o је утишан@[adj_1_sr] од моћи Куиетуса играч %k. -%o got a mace to the face from %k.,OB_MPCWEAPMACE,,,,%o dostal@[ao_cs] palcátem po hlavě od hráče %k.,%o bekam %ks Streitkolben ins Gesicht.,,%o prenis klabon al la vizaĝon el %k.,%o consiguió un mazazo a la cara de parte de %k.,,%o sai pelaajan %k nuijasta naamaansa.,%o s'est fait@[e_fr] casser la figure par la masse de %k.,%o kapott egy buzogányt a fejébe %k által.,%o si è preso una mazzata in faccia da %k.,%o は自らの顔に %k のメイスを受けた。,%o 은(는) %k 의 철퇴를 맞은 뒤에야 철이 들었다.,%o kreeg een foelie in het gezicht van %k.,%o dostał@[ao_pl] buzdyganem %k w twarz.,%o levou com a maça de %k na cara.,,%o a primit un buzdugan în față de la %k.,Игрок %o получил по морде булавой %k.,%o је доби@[ao_1_sr] буздован у фацу играч %k. -%o was bitten by %k's serpent staff.,OB_MPCWEAPSTAFFM,,,,%o byl@[ao_cs] kousnut@[ao_cs] hadí holí hráče %k.,%o wurde von %ks Schlangenstab gebissen.,,%o mordiĝis per la serpentbastono de %k.,%o fue mordid@[ao_esp] por el bastón de la serpiente de %k.,,%k puri %o parkaa käärmesauvallaan.,%o s'est fait@[e_fr] mordre par le Bâton du Serpent %k.,%o meglett harapva %k Kígyó Botja által.,%o è stato morso dalla Staffa del Serpente di %k.,%o は %k の蛇の杖に噛まれた。,%o 은(는) %k 의 뱀 지팡이에 의해 독살당했다.,%o werd gebeten door %k's slangenstaf.,%o został@[ao_pl] ugryzion@[adj_pl] laską węży %k.,%o foi mordid@[ao_ptb] pelo Cetro da Serpente de %k.,,%o a fost mușcat de bastonul șarpe al lui %k.,Игрок %o искусан змеиным посохом %k.,%o је угрижен@[adj_1_sr] змијским штапом играч %k. -%o choked on %k's serpent staff.,OB_MPCWEAPSTAFFR,,,,%o se zadusil@[ao_cs] hadí holí hráče %k.,%o verschluckte sich an %ks Schlangenstab.,,%o sufokis la serpentbastonon de %k.,%o se ahogó con el bastón de la serpiente de %k.,,%o tukehtui pelaajan %k käärmesauvaan.,%o s'est étranglé@[e_fr] sur le Bâton du Serpent de %k,%o megfulladt %k Kígyó Botja által.,%o è soffocato a causa della Staffa del Serpente di %k.,%o は %k の蛇の杖に息の根を止められた。,%o 은(는) %k 의 뱀 지팡이 때문에 숨을 쉬지 못했다.,%o stikte in %k's slangenstaf.,%o zakrztusił@[ao_pl] się laską węży %k.,%o se engasgou com o Cetro da Serpente de %k,,%o s-a sufocat pe bastonul șarpe al lui %k.,Игрок %o задушен змеиным посохом %k.,%o је задављен@[adj_1_sr] змијским штапом играч %k. -%o was lit up by %k's flames.,OB_MPCWEAPFLAME,,,,%o vzplanul@[ao_cs] plameny hráče %k.,%o wurde von %ks Flammen erleuchtet.,,%o ekbruliĝis per la fajroj de %k.,%o fue encendid@[ao_esp] por las llamas de %k.,,%o syttyi pelaajan %k liekeistä.,%o s'est fait@[e_fr] allumer par %k.,%o fel lett gyújtva %k tűze által.,%o è stato illuminato dalle fiamme di %k.,%o は %k によって炎を灯された。,%o 은(는) %k 의 화염폭풍에 휩쓸렸다.,%o werd verlicht door %k's vlammen.,%o został@[ao_pl] oświetlon@[adj_pl] płomieniami %k.,%o foi incendiad@[ao_ptb] pelas chamas de %k.,,%o s-a aprins de la flăcările lui %k.,Игрок %o сгорел в огне %k.,%o је осветљен@[adj_1_sr] пламеном играч %k. -%o was cleansed by %k's Wraithverge.,OB_MPCWEAPWRAITHVERGE,,,,%o byl@[ao_cs] očištěn@[ao_cs] Zjevitelem hráče %k.,%o wurde durch %ks Geisterbringer geläutert.,,%o puriĝis per la Fantomkruc' de %k.,%o fue limpiad@[ao_esp] por la vara fantasmal de %k.,,%k puhdisti pelaajan %o Haamusauvallaan.,%o a été purifié@[e_fr] par la Verge Phantasmale de %k.,%o meglett tisztítva %k Lélekvégje által.,%o è stato purificato dalla Verga SconfinaSpettri di %k.,%o は %k のレイスバージによって浄化された。,%o 은(는) %k 의 사령의 지팡이에 의해 정화되었다.,%o werd gereinigd door %k's Spookbrenger.,%o został@[ao_pl] oczyszczon@[adj_pl] przez Widmoskraj %k.,%o foi purificad@[ao_ptb] pelo Cajado Fantasma de %k.,,%o a fost purificat de Toiagul Stafie al lui %k.,Игрок %o очищен Жезлом Духов %k.,%o je прочишћен@[adj_1_sr] штапом утваре играч %k. -%o took one too many sapphire beams from %k.,OB_MPMWEAPWAND,,,,%o koupil@[ao_cs] moc safírových ran od hráče %k.,%o bekam zu viele Saphierstrahlen von %k ab.,,%o recivis unu tro da safira radio per %k.,%o recibió demasiados rayos de zafiro de %k.,,%o otti vastaan yhden liikaa pelaajan %k safiirisäteistä.,%o s'est pris@[e_fr] un rayon saphirique en trop de la part de %k.,%o túl sok zafír sugarat kapott %k-tól/től.,%o si è buscato un raggio di zaffiro di troppo da %k.,%o は %k から多量のサファイアビームを受け取った。,%o 은(는) %k 의 사파이어 빛을 너무 많이 째려봤다.,%o nam één te veel saffierbalken van %k.,%o wzi@[irreg_2_pl] o jeden szafirowy promień od %k za dużo.,%o levou muitos raios de safira de %k.,,%o a primit o rază în plus de la safirul lui %k.,Игрок %o схватил слишком много сапфировых зарядов от %k.,%o је узе@[ao_1_sr] превише сафирских зракова играч %k. -%o was turned into a frosty fellow by %k.,OB_MPMWEAPFROST,,,,%o byl@[ao_cs] zchlazen@[ao_cs] hráčem %k.,%o wurde von %k schockgefrostet.,,%o farigiĝis frostulon per %k.,%o fue convertid@[ao_esp] en un helado por %k.,%o fue convertid@[ao_esp] en una persona helada por %k.,%k muutti %o paran pakkasveikoksi.,%o s'est fait@[e_fr] transformer en glaçon par %k.,%o jégbaráttá alakult %k által.,%o è stato trasformato in un simpatico pupazzo di neve da %k.,%o は %k によって冷ややかな輩になった。,%o 은(는) %k 의 얼음 파편에 의해 눈사람이 되었다.,%o werd veranderd in een ijskoude kerel door %k.,%o został@[ao_pl] zmienion@[adj_pl] w mroźnego koleżkę przez %k.,%o foi transformad@[ao_ptb] em picolé por %k.,,%o a fost transformat într-un amic de gheață de %k.,Игрок %o обращается в ледяную скульптуру благодаря %k.,%o је претворен@[adj_1_sr] у лед играч %k. -%o received a shocking revelation from %k.,OB_MPMWEAPLIGHTNING,,,,%o zjistil@[ao_cs] šokující odhalení hráče %k.,%o musste eine schockierende Enthüllung von %k verkraften.,,%o recivis teruran revelacion per %k.,%o recibió una revelación impactante de %k.,,%o sai sähköistävän ilmestyksen pelaajalta %k.,%o a reçu un sacré coup de jus de la part de %k.,%o kapott egy sokkoló relevációt %k-tól/től,"%o ha ricevuto una notizia ""elettrizzante"" da %k.",%o は %k から衝撃的な啓示を受けた。,%o 은(는) %k 의 번갯불 덕에 충격적인 계시를 받았다.,%o kreeg een schokkende openbaring van %k.,%o otrzymał@[ao_pl] szokujące objawienie od %k.,%o recebeu uma revelação chocante de %k.,,%o a primit o revelație șocantă de la %k.,Игрок %o откровенно шокирован %k.,%o је прими@[ao_1_sr] шокантно откриће играч %k. -%o was wiped off the face of the universe by %k's Bloodscourge.,OB_MPMWEAPBLOODSCOURGE,,,,%o byl@[ao_cs] smazán@[ao_cs] z tváře vesmíru Krvehromem hráče %k.,%o wurde von %ks Blutgeißel aus dem Universum verbannt.,,%o disdetruiĝis el la universo per la Sangskurĝ' de %k.,%o fue borrad@[ao_esp] de la faz del universo por la plaga sangrienta de %k.,,%k pyyhki %o paran maailmankaikkeudesta.,%o s'est fait@[e_fr] effacer de l'univers par le Fléau Sanglant de %k.,%o kilett törölve az univerzumból %k Vérkorbácsának köszönhetően.,%o è stato cancellato dalla faccia dell'universo dal Flagello di Sangue di %k.,%o は %k の天罰によりこの世から一掃された。,%o 은(는) %k 이(가) 피의 재앙을 씀으로써 전혀 존재하지 않는 존재가 되어버렸다.,%o werd van het gezicht van het universum geveegd door %k's Bloedplaag.,Twarz %o została zmieciona z wszechświata przez Krwioplagę %k.,%o foi varrid@[ao_ptb] da face do universo pelo Flagelo de Sangue de %k.,,"%o a fost ras de pe fața universului de -Flagelul Sângeros al lui %k.",Игрок %o стёрт с лица вселенной Кровавым бичем %k.,%o је обрисан@[adj_1_sr] са лица свемира од Крвавог зла играч %k. -,,Strife,,,,,,,,,,,,,,,,,,,,, -,,Pickups,,,,,,,,,,,,,,,,,,,,, -You picked up the Metal Armor.,TXT_METALARMOR,,,You picked up the Metal Armour.,Sebral@[ao_cs] jsi kovové brnění.,Du hast die Metallrüstung genommen.,Πήρες τη Μεταληκή Πανοπλία.,Vi prenis la Metalan Kirason.,Recogiste la Armadura de Metal.,,Poimit metallipanssarin.,Vous avez pris l'armure de métal.,Felvetted a Fémpáncélt.,Hai raccolto l'Armatura di Metallo.,メタルアーマー 入手。,강철 갑옷을 획득했다.,Je hebt het metalen harnas opgehaald.,Podniosł@[irreg_3_pl] Metalowy Pancerz.,Você pegou a Armadura de Metal.,Apanhaste a Armadura de Metal.,Ai ridicat Armura din Metal.,Получена металлическая броня.,Покупио си метални оклоп. -You picked up the Leather Armor.,TXT_LEATHERARMOR,,,You picked up the Leather Armour.,Sebral@[ao_cs] jsi kožené brnění.,Du hast die Lederrüstung genommen.,Πήρες τη Δερμάτινη Πανοπλία.,Vi prenis la Ledan Kirason.,Recogiste la Armadura de Cuero.,,Poimit nahka-asun.,Vous avez pris l'armure de cuir.,Felvetted a Bőrpáncélt.,Hai raccolto l'Armatura di Cuoio.,レザーアーマー 入手。,가죽 갑옷을 획득했다.,Je hebt het lederen harnas opgehaald.,Podniosł@[irreg_3_pl] Skórzany Pancerz.,Você pegou a Armadura de Couro.,Apanhaste a Armadura de Couro.,Ai ridicat Armura din Piele.,Получена кожаная броня.,Покупио си кожни оклоп. -You picked up the Med patch.,TXT_MEDPATCH,,,,Sebral@[ao_cs] jsi obvaz.,Du hast den Verband genommen.,,Vi prenis la Medicinan Flikaĵon.,Recogiste un Parche Médico.,,Poimit sidekääreen.,Vous avez pris le pansement.,Felvetted a Raktapaszt.,Hai raccolto le Bende.,医薬パッチ 入手。,의료 붕대를 획득했다.,Je hebt de Med-patch opgehaald.,Podniosł@[irreg_3_pl] Bandaż.,Você pegou a compressa médica.,Apanhaste a compressa médica.,Ai ridicat Trusa de Prim-Ajutor.,Получен медицинский бинт.,Покупио си прву помоћ. -You picked up the Medical kit.,TXT_MEDICALKIT,,,,Sebral@[ao_cs] jsi lékárničku.,Du hast den Verbandskasten genommen.,,Vi prenis la Medicinilaron.,Recogiste un Kit Médico.,,Poimit lääkintälaukun.,Vous avez pris le kit médical.,Felvetted az Elsősegélycsomagot.,Hai raccolto il Kit di Pronto Soccorso.,医療用キット 入手。,구급 키트를 획득했다.,Je hebt de Medische kit opgehaald.,Podniosł@[irreg_3_pl] Apteczkę.,Você pegou o Kit Médico.,Apanhaste o Kit Médico.,Ai ridicat Kitul de Prim-Ajutor.,Получена аптечка.,Покупио си медицински комплет -You picked up the Surgery Kit.,TXT_SURGERYKIT,,,,Sebral@[ao_cs] jsi chirurgickou soupravu.,Du hast den Erste-Hilfe-Kasten genommen.,,Vi prenis la Kirurgirilaron.,Recogiste un Kit Quirúrgico.,,Poimit kirurgilaukun.,Vous avez pris le kit de chirurgie.,Felvetted az Orvosi Műtőfelszerelést.,Hai raccolto il Kit Chirurgico.,手術キット 入手。,수술 키트를 획득했다.,Je hebt de chirurgische kit opgehaald.,Podniosł@[irreg_3_pl] Zestaw Chirurga.,Você pegou o Kit de Cirurgia.,Apanhaste o Kit de Cirugia.,Ai ridicat Kitul pentru Operații.,Получен медкомплект.,Покупио си хируршки комплет -You picked up the map.,TXT_STRIFEMAP,,,,Sebral@[ao_cs] jsi mapu.,Du hast die Karte genommen.,Πήρες το χάρτη.,Vi prenis la mapon.,Recogiste el mapa.,,Poimit kartan.,Vous avez pris la carte,Felvetted a térképet.,Hai raccolto la Mappa.,マップ 取得。,지도를 획득했다.,Je hebt de kaart opgehaald.,Podniosł@[irreg_3_pl] mapę.,Você pegou o mapa.,Apanhaste o mapa.,Ai ridicat harta.,Получена карта.,Покупио си мапу. -You picked up the ring.,TXT_BELDINSRING,,,,Sebral@[ao_cs] jsi prsten.,Du hast den Ring genommen.,Πήρες το Δακτύλιο.,Vi prenis la ringon.,Recogiste un anillo.,,Poimit sormuksen.,Vous avez pris l'anneau.,Felvetted a gyűrűt.,Hai raccolto l'Anello.,指輪 取得。,반지를 획득했다.,Je hebt de ring opgehaald.,Podniosł@[irreg_3_pl] pierścień.,Você pegou o anel.,Apanhaste o anel.,Ai ridicat inelul.,Получено кольцо.,Покупио си прстен. -You picked up the Offering Chalice.,TXT_OFFERINGCHALICE,,,,Sebral@[ao_cs] jsi obětní kalich.,Du hast den Opferkelch genommen.,,Vi prenis la Ofertkilkon.,Recogiste el Cáliz de Ofrenda.,,Poimit uhrimaljan.,Vous avez pris le Calice d'obole.,Felvetted az Áldozati Kelyhet.,Hai raccolto il Calice delle Offerte.,寄贈された聖杯 取得。,번제 성배를 훔쳤다.,Je hebt de offerbeker opgehaald.,Podniosł@[irreg_3_pl] Kielich Ofiarny.,Você pegou o Cálice de Oferenda.,Apanhaste o Cálice de Oferenda.,Ai ridicat Potirul pentru Ofrande.,Получена чаша для подношений.,Покупио си Жртвени пехар. -You picked up the ear.,TXT_EAR,,,,Sebral@[ao_cs] jsi ucho.,Du hast das Ohr gernommen.,Πήρες το αυτί.,Vi prenis la orelon.,Recogiste la oreja.,,Poimit korvan.,Vous avez pris l'oreille.,Felvetted a fület.,Hai raccolto l'Orecchio.,耳 取得。,잘린 귀를 주웠다.,Je hebt het oor opgehaald.,Podniosł@[irreg_3_pl] ucho.,Você pegou a orelha.,Apanhaste a orelha.,Ai ridicat urechea.,Получено ухо.,Покупио си уво. -You picked up the broken power coupling.,TXT_BROKENCOUPLING,,,,Sebral@[ao_cs] jsi rozbitou spojku.,Du hast den defekten Stromabnehmer genommen.,,Vi prenis la rompan povkuplilon.,Recogiste el acoplador de energía roto.,,Poimit rikkinäisen virtaliittimen.,Vous avez pris le coupleur énergétique cassé.,Felvetted a hibás tápcsatlakozót.,Hai raccolto la Coppia Energetica Rotta.,壊れたパワーカップリング 取得。,망가진 동력선 장치를 획득했다.,Je hebt de kapotte stroomkoppeling opgehaald.,Podniosł@[irreg_3_pl] zepsute obwody zasilające.,Você pegou o acoplador de energia quebrado.,Apanhaste o acoplador de energia partido.,Ai ridicat cuplajul defect de curent.,Получена повреждённая муфта.,Покупио си неисправну спојницу напајања. -You picked up the Shadow armor.,TXT_SHADOWARMOR,,,You picked up the Shadow armour.,Sebral@[ao_cs] jsi krycí brnění.,Du hast die Schattenrüstung genommen.,,Vi prenis la Ombrokirason.,Recogiste una armadura de Sombra.,,Poimit varjopanssarin.,Vous avez pris l'armure de l'ombre.,Felvetted az Árnyékpáncélt.,Hai raccolto l'Armatura Ombra.,シャドウアーマー 入手。,그림자 갑옷을 획득했다.,Je hebt het Schaduw harnas opgehaald.,Podniosł@[irreg_3_pl] Cienisty Pancerz.,Você pegou a armadura das sombras.,Apanhaste a armadura das sombras.,Ai ridicat Armura Umbrei.,Получена теневая броня.,Покупио си оклоп сенки. -You picked up the Environmental Suit.,TXT_ENVSUIT,,,,Sebral@[ao_cs] jsi ochranný oděv,Du hast den Schutzanzug genommen.,,Vi prenis la Mediveston,Recogiste un Traje Ambiental.,,Poimit ympäristösuojapuvun.,Vous avez pris la combinaison hazmat.,Felvetted a Védőruhát.,Hai raccolto la Tuta Ambientale.,耐環境スーツ 入手。,환경 방호복을 획득했다.,Je hebt het beschermend pak opgehaald.,Podniosł@[irreg_3_pl] Skafander Ochronny.,Você pegou o Traje de Proteção.,Apanhaste o Fato Protetor.,Ai ridicat Costumul de Protecție.,Получен защитный костюм.,Покупио си заштитно одело. -You picked up the Guard Uniform.,TXT_GUARDUNIFORM,,,,Sebral@[ao_cs] jsi hlídačovu uniformu.,Du hast die Wächteruniform genommen.,,Vi prenis la Gardistan Uniformon.,Recogiste el Uniforme de un Guardia.,,Poimit vartijan univormun.,Vous avez pris l'Uniforme du garde.,Felvetted az Őr Egyenruhát.,Hai raccolto l'Uniforme da Guardia.,守衛の制服 入手。,경비 전투복을 획득했다.,Je hebt het Wachtuniform opgehaald.,Podniosł@[irreg_3_pl] Mundur Strażnika.,Você pegou o Uniforme de Guarda.,Apanhaste o Uniforme de Guarda.,Ai ridicat Uniforma de Paznic.,Получена униформа стражника.,Покупио си стражарску униформу -You picked up the Officer's Uniform.,TXT_OFFICERSUNIFORM,,,,Sebral@[ao_cs] jsi důstojníkovu uniformu.,Du hast die Offiziersuniform genommen.,,Vi prenis la Oficiran Uniformon.,Recogiste el Uniforme de un Oficial.,,Poimit upseerin univormun.,Vous avez pris l'Uniforme de l'officier.,Felvetted a Tiszti Egyenruhát.,Hai raccolto l'Uniforme da Ufficiale.,士官の制服 入手。,장교 전투복을 획득했다.,Je hebt het uniform van de officier opgehaald.,Podniosł@[irreg_3_pl] Mundur Oficera.,Você pegou o Uniforme de Oficial.,Apanhaste o Uniforme de Oficial.,Ai ridicat Uniforma Ofițerului.,Получена униформа офицера.,Покупио си официрску униформу -You picked up the flame thrower parts.,TXT_FTHROWERPARTS,,,,Sebral@[ao_cs] jsi součástky plamenometu.,Du hast die Flammenwerferteile genommen.,,Vi prenis la partojn de la flamĵetilo.,Recogiste las partes del lanzallamas.,,Poimit liekinheittimen osat.,Vous avez pris les pièces du lance-flames.,Felvetted a lángszóró részeit.,Hai raccolto delle parti di Lanciafiamme.,火炎放射器の部品 入手。,화염방사기 부품을 획득했다.,Je hebt de onderdelen van de vlammenwerper opgehaald.,Podniosł@[irreg_3_pl] części miotacza ognia.,Você pegou as partes do lança-chamas.,Apanhaste as peças do lança-chamas.,Ai ridicat bucățile aruncătorului de flăcări.,Получены детали для огнемёта.,Покупио си делове за бацач пламена. -You picked up the report.,TXT_REPORT,,,,Sebral@[ao_cs] jsi hlášení.,Du hast den Report genommen.,,Vi prenis la raporton.,Recogiste el reporte.,,Poimit raportin.,Vous avez pris le compte-rendu.,Felvetted a jelentést.,Hai raccolto il rapporto.,報告書 取得。,보고서를 획득했다.,Je hebt het rapport opgepakt,Podniosł@[irreg_3_pl] raport.,Você pegou o relatório.,Apanhaste o relatório.,Ai ridicat raportul.,Получен отчёт.,Покупио си извештај. -You picked up the info.,TXT_INFO,,,,Sebral@[ao_cs] jsi informace.,Du hast die Info genommen.,Πήρες της πληροφορίες,Vi prenis la informon.,Recogiste la información.,,Poimit tiedot.,Vous avez pris l'info.,Felvetted az információt.,Hai raccolto delle Informazioni.,情報 取得。,정보를 획득했다.,Je hebt de informatie opgehaald.,Podniosł@[irreg_3_pl] informacje.,Você pegou a informação.,Apanhaste a informação.,Ai recepționat informația.,Получена сводка.,Покупио си инфо. -You picked up the Targeter.,TXT_TARGETER,,,,Sebral@[ao_cs] jsi zaměřovač.,Du hast die Zielhilfe genommen.,Πήρες τον Στοχευτή.,Vi prenis la Celilon.,Recogiste el apuntador.,,Poimit tähtäinlaitteen.,Vous avez pris le cibleur.,Felvetted a Célzóberendezést.,Hai raccolto il Puntatore.,照準器 入手。,조준기를 획득했다.,Je hebt de doelwit opgehaald.,Podniosł@[irreg_3_pl] Namierzacz.,Você pegou a Mira.,Apanhaste a Mira.,Ai ridicat Țintitorul.,Получен целеуказатель.,Покупио си нишанитеља. -You picked up the Communicator.,TXT_COMMUNICATOR,,,,Sebral@[ao_cs] jsi komunikátor.,Du hast den Kommunikator genommen.,,Vi prenis la Komunikilon.,Recogiste el comunicador.,,Poimit viestintälaitteen.,Vous avez pris le Communicateur,Felvetted a Kommunikátort,Hai raccolto il Comunicatore.,コミュニケーター 取得。,연락장치를 획득했다.,Je hebt de Communicator opgehaald.,Podniosł@[irreg_3_pl] Komunikator.,Você pegou o Comunicador.,Apanhaste o Comunicador.,Ai ridicat Comunicatorul.,Получен передатчик.,Покупио си комуникатор. -You picked up the coin.,TXT_COIN,,,,Sebral@[ao_cs] jsi minci.,Du hast die Münze genommen.,Πήρες το κέρμα.,Vi prenis la moneron.,Recogiste una moneda.,,Poimit kolikon.,Vous avez pris la pièce.,Felvetted az érmét.,Hai raccolto la Moneta.,コイン 入手。,동전을 주웠다.,Je hebt de munt opgehaald.,Podniosł@[irreg_3_pl] monetę.,Você pegou a moeda.,Apanhaste a moeda.,Ai ridicat moneda.,Получена монета.,Покупио си новчић. -You picked up %d gold.,TXT_XGOLD,,,,Sebral@[ao_cs] jsi %d zlatých.,Du hast %d Gold genommen.,,Vi prenis %d da oro.,Recogiste %d monedas de oro.,,Poimit kultaa %d arvosta.,Vous avez pris %d pièces.,Felvettél %d aranyat.,Hai raccolto %d pezzi d'oro.,%d ゴールド 入手。,골드 %d 개를 획득했다.,Je hebt %d goud opgehaald.,Podniosł@[irreg_3_pl] %d monet.,Você pegou %d moedas de ouro.,Apanhaste %d moedas de ouro.,Ai ridicat %g bucăți de aur.,Получено %d золотых.,Покупио си %d златника. -You picked up the Teleporter Beacon.,TXT_BEACON,,,,Sebral@[ao_cs] jsi teleportační maják.,Du hast das Teleportersignal genommen.,,Vi prenis la Formovilan Signalilon.,Recogiste un faro de teletransportación.,,Poimit kaukosiirrinmajakan.,Vous avez pris la balise de téléporteur.,Felvetted a Teleport jelzőt.,Hai raccolto il Radiofaro per Teletrasporto.,テレポータービーコン 取得。,텔레포터 비콘을 획득했다.,Je hebt de Teleporter Baken opgehaald.,Podniosł@[irreg_3_pl] Nadajnik Teleportera.,Você pegou o Sinalizador de Teletransporte.,Apanhaste o Sinalizador de Teletransporte.,Ai ridicat Luminatorul pentru Teleportor.,Получен телепортационный маяк.,Покупио си одашиљач за телепортовање. -You picked up the Degnin Ore.,TXT_DEGNINORE,,,,Sebral@[ao_cs] jsi degninskou rudu.,Du hast das Degnin-Erz genommen.,,Vi prenis la Degninan Ercon.,Recogiste el Mineral Degnin.,,Poimit Degnin-malmia.,Vous avez pris le minerai de Degnin.,Felvetted a Degnin Ércet.,Hai raccolto il Minerale Degnin.,デグニン鉱石 取得。,데그닌 광석을 획득했다.,Je hebt de Degnin Erts opgehaald.,Podniosł@[irreg_3_pl] Rudę Degninu.,Você pegou o Minério Degnin.,Apanhaste o Minério Degnin.,Ai ridicat minereul de Degnin.,Получена дегнинская руда.,Покупио си Дегнинску руду. -You picked up the scanner.,TXT_SCANNER,,,,Sebral@[ao_cs] jsi skener.,Du hast den Scanner genommen.,Πήρες το σαρωτή.,Vi prenis la skanilon.,Recogiste el escáner.,,Poimit skannerin.,Vous avez pris l'analyseur.,Felvetted a szkennert.,Hai raccolto lo Scanner.,スキャナー 入手。,탐지기를 획득했다.,Je hebt de scanner opgehaald.,Podniosł@[irreg_3_pl] skaner.,Você pegou o scanner.,Apanhaste o scanner.,Ai ridicat scannerul.,Получен сканер.,Покупио си скенер. +nevoie!",Получена КРАЙНЕ необходимая аптечка!,Покупили сте медикит који вам је СТВАРНО потребан!,Plockade upp en medikit som du VÄLDIGT behöver!,GERÇEKTEN ihtiyacın olan bir medikit aldı!,Взято КРАЙНЄ необхідну аптечку! +Picked up a medikit.,GOTMEDIKIT,,,,Sebrána lékárnička.,Samlede en medikit op.,Medikit genommen.,Πήρες πρώτες βοήθειες.,Vi trovis sukurkeston.,Encuentras un botiquín.,,Poimit lääkintälaukun.,Médikit récupéré.,Felvettél egy életcsomagot.,Raccolto un kit medico.,メディキットを拾った。,메디킷을 사용했다.,Je hebt een verbandsdoos opgepakt.,Plukket opp en medikit.,Zebrano apteczkę.,Pegou um kit médico.,Apanhaste um kit médico.,Ai ridicat un kit de prim-ajutor.,Получена аптечка.,Покупили сте медикит.,Plockade upp en medikit.,Bir medikit aldı.,Взято аптечку. +Supercharge!,GOTSUPER,,,,Superzdraví!,,Super-Ladung!,Υπερφόρτοση!,Superŝargo!,¡Supercarga!,,Supervaraus!,,Szupertöltés!,Sfera dell'Anima!,スーパーチャージ!,슈퍼차지!,,,Supernaładowanie!,Supercarga!,,Superîncărcătură!,Сверхзаряд!,Супернабој!,Superladdning!,Süper şarj!,Суперзаряд! +Picked up a blue keycard.,GOTBLUECARD,,,,Sebrána modrá karta.,Samlede et blåt nøglekort op.,Blaue Schlüsselkarte genommen.,Πήρες ένα μπλε κλειδί.,Vi trovis bluan ŝlosilkarton.,Encuentras una tarjeta de acceso azul.,,Poimit sinisen avainkortin.,Carte d'accès BLEUE récupérée.,Felvettél egy kék kulcskártyát.,Raccolta una card d'accesso blu.,ブルー キーカードを手に入れた。,청색 키카드를 얻었다.,Je hebt een blauwe sleutelkaart opgepakt.,Plukket opp et blått nøkkelkort.,Zebrano niebieską kartę klucz.,Pegou um cartão de acesso azul.,Apanhaste um cartão de acesso azul.,Ai ridicat un card cheie albastru.,Получена синяя ключ-карта.,Покупили сте плаву кључну карту.,Plockade upp ett blått nyckelkort.,Mavi bir anahtar kartı aldı.,Взято синю ключ-карту. +Picked up a yellow keycard.,GOTYELWCARD,,,,Sebrána žlutá karta.,Samlede et gult nøglekort op.,Gelbe Schlüsselkarte genommen.,Πήρες ένα κύτρινο κλειδί.,Vi trovis flavan ŝlosilkarton.,Encuentras una tarjeta de acceso amarilla.,,Poimit keltaisen avainkortin.,Carte d'accès JAUNE récupérée.,Felvettél egy sárga kulcskártyát.,Raccolta una card d'accesso gialla.,イエローキーカードを手に入れた。,황색 키카드를 얻었다.,Je hebt een gele sleutelkaart opgepakt.,Plukket opp et gult nøkkelkort.,Zebrano żółtą kartę klucz.,Pegou um cartão de acesso amarelo.,Apanhaste um cartão de acesso amarelo.,Ai ridicat un card cheie galben.,Получена жёлтая ключ-карта.,Покупили сте жуту кључну карту.,Plockade upp ett gult nyckelkort.,Sarı bir anahtar kartı aldı.,Взято жовту ключ-карту. +Picked up a red keycard.,GOTREDCARD,,,,Sebrána červená karta.,Samlede et rødt nøglekort op.,Rote Schlüsselkarte genommen.,Πήρες ένα κόκινο κλειδί.,Vi trovis ruĝan ŝlosilkarton.,Encuentras una tarjeta de acceso roja.,,Poimit punaisen avainkortin.,Carte d'accès ROUGE récupérée.,Felvettél egy piros kulcskártyát.,Raccolta una card d'accesso rossa.,レッド キーカードを手に入れた。,적색 키카드를 얻었다.,Je hebt een rode sleutelkaart opgepakt.,Plukket opp et rødt nøkkelkort.,Zebrano czerwoną kartę klucz.,Pegou um cartão de acesso vermelho.,Apanhaste um cartão de acesso vermelho.,Ai ridicat un card cheie roșu.,Получена красная ключ-карта.,Покупили сте црвену кључну карту.,Plockade upp ett rött nyckelkort.,Kırmızı bir anahtar kartı aldı.,Взято червону ключ-карту. +Picked up a blue skull key.,GOTBLUESKUL,,,,Sebrána modrá lebka.,Samlede en blå kranie-nøgle op.,Blauen Schädel-Schlüssel genommen.,Πήρες ένα μπλε κρανίο.,Vi trovis bluan kraniŝlosilon.,Encuentras una llave de calavera azul.,,Poimit sinisen kalloavaimen.,Clef Crâne BLEUE récupérée.,Felvettél egy kék koponyakulcsot.,Raccolta una chiave-teschio blu.,ブルー スカルキーを手に入れた。,청색 해골열쇠를 얻었다.,Je hebt een blauwe schedelsleutel opgepakt.,Plukket opp en blå hodeskallenøkkel.,Zebrano niebieską czaszkę.,Pegou uma chave-crânio azul.,Apanhaste uma chave crânio azul.,Ai ridicat o cheie craniu albastră.,Получен синий череп-ключ.,Покупили сте плави кључ лобање.,Plockade upp en blå dödskalle-nyckel.,Mavi bir kafatası anahtarı aldı.,Взято синій ключ-череп. +Picked up a yellow skull key.,GOTYELWSKUL,,,,Sebrána žlutá lebka.,Samlede en gul kranie-nøgle op.,Geben Schädel-Schlüssel genommen.,Πήρες ένα κύτρινο κρανίο.,Vi trovis flavan kraniŝlosilon.,Encuentras una llave de calavera amarilla,,Poimit keltaisen kalloavaimen.,Clef Crâne JAUNE récupérée.,Felvettél egy sárga koponyakulcsot.,Raccolta una chiave-teschio gialla.,イエロースカルキーを手に入れた。,황색 해골열쇠를 얻었다.,Je hebt een gele schedelsleutel opgepakt.,Plukket opp en gul hodeskallenøkkel.,Zebrano żółtą czaszkę.,Pegou uma chave-crânio amarela.,Apanhaste uma chave crânio amarela.,Ai ridicat o cheie craniu galbenă.,Получен жёлтый череп-ключ.,Покупили сте жути кључ лобање.,Plockade upp en gul dödskalle-nyckel.,Sarı bir kafatası anahtarı aldı.,Взято жовтий ключ-череп. +Picked up a red skull key.,GOTREDSKUL,,,,Sebrána červená lebka.,Samlede en rød kranie-nøgle op.,Roten Schädel-Schlüssel genommen.,Πήρες ένα κοκινο κρανίο.,Vi trovis ruĝan kraniŝlosilon.,Encuentras una llave de calavera roja.,,Poimit punaisen kalloavaimen.,Clef Crâne ROUGE récupérée.,Felvettél egy piros koponyakulcsot.,Raccolta una chiave-teschio rossa.,レッド スカルキーを手に入れた。,적색 해골열쇠를 얻었다.,Je hebt een rode schedelsleutel opgepakt.,Plukket opp en rød hodeskallenøkkel.,Zebrano czerwoną czaszkę.,Pegou uma chave-crânio vermelha.,Apanhaste uma chave crânio vermelha.,Ai ridicat o cheie craniu roșie.,Получен красный череп-ключ.,Покупили сте црвени кључ лобање.,Plockade upp en röd dödskalle-nyckel.,Kırmızı kafatası anahtarı aldı.,Взято червоний ключ-череп. +Invulnerability!,GOTINVUL,,,,Nezranitelnost!,Udsårbarhed!,Unverwundbarkeit!,Αθανασία!,Nevundebleco!,¡Invulnerabilidad!,,Haavoittumattomuus!,Invulnérabilité!,Sérthetetlenség!,Invulnerabilità!,不死身だ!,무적!,Onkwetsbaarheid!,Usårbarhet!,Niezniszczalność!,Invulnerabilidade!,,Invincibilitate!,Неуязвимость!,Нерањивост!,Osårbarhet!,Dokunulmazlık!,Невразливість! +Berserk!,GOTBERSERK,,,,,,,Μανία!,Furiozigaĵo!,¡Berserker!,,Raivo!,,Dühödt mód!,,バーサーク!,광전사!,,,Szał!,Frenesi!,,Forță amplificată!,Берсерк!,Берсерк!,,,Берсерк! +Partial Invisibility,GOTINVIS,,,,Částečná neviditelnost,Delvis usynlighed,Teilweise Unsichtbarkeit,Ημη-αoρατότητα,Parta nevidebleco,Invisibilidad parcial,,Osittainen näkymättömyys,Invisibilité Partielle,Részleges láthatatlanság,Invisibilità parziale,半透明化スフィア,일시적 투명 효과!,Gedeeltelijke onzichtbaarheid,Delvis usynlighet,Częściowa niewidzialność,Invisibilidade parcial,,Invizibilitate parțială,Частичная невидимость.,Делимична невидљивост,Partiell osynlighet,Kısmi Görünmezlik,Часткова невидимість +Radiation Shielding Suit,GOTSUIT,,,,Ochranný oblek proti radioaktivitě,Stråleafskærmningsdragt,Strahlenschutzanzug.,Προστατευτηκή Στολή,Radiado-ŝirma vesto,Traje antiradiación,,Säteilysuojapuku,Combinaison Hazmat,Védőruha,Tuta anti-radiazioni,放射線防護服 ,방사능 보호복,Stralingsbeschermingspak,Strålingsskjermingsdrakt,Kombinezon przeciwradiacyjny,Traje antirradiação,Fato anti-radiação,Costum de protecție împotriva radiaților,Костюм радиационной защиты.,Одело против радијације,Strålningsskyddande dräkt,Radyasyon Koruyucu Giysi,Антирадіаційний костюм +Computer Area Map,GOTMAP,,,,Počítačová mapa,Computerkort.,Computerkarte.,Τοπικός Χάρτης,Plena mapo,Mapa completo,,Alueen tietokonekartta,Carte Informatique,Térkép,Mappa Completata,コンピューターエリアマップ,구역 지도 컴퓨터,Computerkaart,Datakart,Mapa obszaru,Mapa completo,,Hartă completă,Компьютерная карта уровня.,Компјутерска мапа нивоа,Karta över datorområdet,Bilgisayar Alanı Haritası,Комп'ютерна карта району +Light Amplification Visor,GOTVISOR,,,,Noktovizor,Lysforstærkningsvisir,Lichtverstärkungsgerät,Νυχτερινή Όραση,Vizilo de luma amplifikado,Visor de amplificación de luz,,Valonvahvistusvisiiri,Lunettes de Vision Nocturne,Éjjellátó sisak,Amplificatore di luce,"暗視バイザー +",야간투시 바이저,Lichtversterkingsvizier,Lysforsterkende visir,Gogle noktowizyjne,Visor de amplificação de luz,Visor de amplificação luminosa,Vedere amplificată,Очки ночного видения.,Ноћни визир,Ljusförstärkande visir,Işık Amplifikasyon Vizörü,Окуляри нічного бачення +MegaSphere!,GOTMSPHERE,,,,MegaSféra!,,MegaSphäre!,Μεγασφαίρα!,Pleja sfero!,¡MegaEsfera!,,Megakuula!,Mégasphère!,MegaGömb!,MegaSfera!,メガスフィアー!,메가스피어!,,,Megasfera!,Megaesfera!,,Megasferă!,Мегасфера!,Мегасфера!,,MegaSfer!,Мегасфера! +Picked up a clip.,GOTCLIP,,,,Sebrán zásobník.,Hentede et magasin med kugler.,Magazin genommen.,Πήρες ένα κουτάκι σφαιρών.,Vi trovis magazenon.,Encuentras un cargador.,,Poimit lippaan.,Chargeur récupéré.,Felvettél egy töltényt.,Raccolto un caricatore.,弾倉を拾った。,탄창을 얻었다.,Je hebt een patroon opgepakt.,Plukket opp et magasin.,Zebrano magazynek.,Pegou um carregador.,Apanhaste um carregador,Ai ridicat un cartuș.,Получен магазин.,Покупили сте оквир.,Plockade upp ett klipp.,Bir şarjör aldım.,Взято набійницю. +Picked up a box of bullets.,GOTCLIPBOX,,,,Sebrána krabice s kulkami.,Hentede en kasse med kugler.,Kiste mit Pistolenkugeln genommen.,Πήρες ένα κουτί με σφαίρες.,Vi trovis skatolon da kugloj.,Encuentras una caja de balas.,,Poimit laatikollisen luoteja.,Boîte de balles récupérée.,Felvettél egy doboz töltényt.,Raccolta una scatola di proiettili.,弾薬箱を拾った。,실탄 탄통을 얻었다.,Je hebt een doos kogels opgepakt.,Plukket opp en eske med kuler.,Zebrano pudełko z nabojami.,Pegou uma caixa de balas.,Apanhaste uma caixa de balas,Ai ridicat o cutie cu gloanțe.,Получена коробка пуль.,Покупили сте кутију метака.,Plockade upp en låda med kulor.,Bir kutu mermi aldı.,Взято коробку набоїв. +Picked up a rocket.,GOTROCKET,,,,Sebrána raketa.,Hentede en raket.,Rakete genommen,Πήρες ένα πύραυλο.,Vi trovis misilon.,Encuentras un misil.,,Poimit raketin.,Roquette récupérée.,Felvettél egy rakétát.,Raccolto un razzo.,ロケットを拾った。,로켓을 얻었다.,Je hebt een raket opgepakt.,Plukket opp en rakett.,Zebrano rakietę.,Pegou um foguete.,Apanhaste um míssil,Ai ridicat o rachetă.,Получена ракета.,Покупили сте ракету.,Plockade upp en raket.,Bir roket aldı.,Взято ракету. +Picked up a box of rockets.,GOTROCKBOX,,,,Sebrána krabice s raketami.,Hentede en kasse med raketter.,Kiste mit Raketen genommen.,Πήρες ένα κουτί με πυράυλους.,Vi trovis keston da misiloj.,Encuentras una caja de misiles.,,Poimit laatikollisen raketteja.,Caisse de roquettes récupérée.,Felvettél egy doboz rakétát.,Raccolta una cassa di razzi.,ロケット箱を拾った。,로켓 상자를 얻었다.,Je hebt een doos raketten opgepakt.,Plukket opp en eske med raketter.,Zebrano pudełko z rakietami.,Pegou uma caixa de foguetes.,Apanhaste uma caixa de mísseis,Ai ridicat o cutie cu rachete.,Получен ящик ракет.,Покупили сте кутију ракета.,Plockade upp en låda med raketer.,Bir kutu roket aldı.,Взято коробку з ракетами. +Picked up an energy cell.,GOTCELL,,,,Sebrán energetický článek.,Hentede en energicelle.,Energiezelle genommen.,Πήρες ένα κύτταρο ενέργιας.,Vi trovis energiĉelon.,Encuentras una célula de energía.,,Poimit energia-akun.,Cellule énergétique récupérée.,Felvettél egy energia cellát.,Raccolta una batteria.,エネルギーセルを拾った。,에너지 셀을 얻었다.,Je hebt een energiecel opgepakt.,Plukket opp en energicelle.,Zebrano ogniwo energetyczne.,Pegou uma célula de energia.,Apanhaste uma célula de energia,Ai ridicat o celulă cu energie.,Получена энергобатарея.,Покупили сте енергетску ћелију.,Plockade upp en energicell.,Bir enerji hücresi aldı.,Взято енергетичну батарею. +Picked up an energy cell pack.,GOTCELLBOX,,,,Sebrán svazek energetických článků.,Hentede en energicellepakke.,Energiezellenpackung genommen.,Πήρες ένα πακέτο κύτταρων ενέργιας.,Vi trovis energiĉelo-pakon.,Encuentras un paquete de células de energía.,,Poimit energia-akkupaketin.,Pack de cellules énergétiques récupéré.,Felvettél egy doboznyi energia cellát.,Raccolta una confezione di batterie.,エネルギーセルパックを拾った。,대용량 에너지 셀을 얻었다.,Je hebt een energiecelpakket opgepakt.,Plukket opp en energipakke.,Zebrano paczkę ogniw energetycznych.,Pegou um pacote de células de energia.,Apanhaste um pacote de células de energia.,Ai ridicat un pachet de celule cu energie.,Получен комплект энергобатарей.,Покупили сте паковање енергетских ћелија.,Plockade upp ett energicellpaket.,Bir enerji hücresi paketi aldı.,Взято велику енергетичну батарею. +Picked up 4 shotgun shells.,GOTSHELLS,,,,Sebrány 4 broky.,Hentede 4 haglpatroner.,4 Schrotflintenpatronen genommen,Πήρες τέσσερεις σφάιρες ντουγεκιόυ.,Vi trovis 4 kartoĉojn.,Encuentras 4 cartuchos de escopeta.,,Poimit 4 haulikon patruunaa.,4 cartouches récupérées.,Felvettél 4 sörétes töltényt.,Raccolte 4 cartucce per fucile.,4発の散弾を拾った。,샷건 쉘 4개를 얻었다.,Je hebt 4 jachtgeweerkogels opgepakt.,Plukket opp 4 haglpatroner.,Zebrano 4 loftki do strzelby.,Pegou 4 cartuchos de espingarda.,Apanhaste 4 cartuchos de espingarda.,Ai ridicat 4 proiectile pentru pușcă.,Получено 4 патрона дробовика.,Покупили сте 4 патроне од пумпарице.,Plockade upp 4 hagelpatroner.,4 av tüfeği mermisi aldı.,Взято 4 рушничні набої. +Picked up a box of shotgun shells.,GOTSHELLBOX,,,,Sebrána krabice s broky.,Hentede en kasse med haglpatroner.,Kiste mit Schrotflintenpatronen genommen.,Πήρες ένα κουτί με σφάιρες ντουγεκιόυ.,Vi trovis skatolon da kartoĉoj.,Encuentras una caja de cartuchos de escopeta.,,Poimit laatikollisen haulikon patruunoita.,Boîte de cartouches récupérée.,Felvettél egy doboz sörétes töltényt.,Raccolta una scatola di cartucce per fucile.,散弾箱を拾った。,샷건 쉘 보관함을 얻었다.,Je hebt een doos jachtgeweerkogels opgepakt.,Plukket opp en eske med haglepatroner.,Zebrano pudełko loftek do strzelby.,Pegou uma caixa de cartuchos de espingarda.,Apanhaste uma caixa de cartuchos de espingarda,Ai ridicat o cutie cu proiectile pentru pușcă.,Получена коробка патронов дробовика.,Покупили сте кутију патрона од пумпарице.,Plockade upp en låda med hagelpatroner.,Bir kutu av tüfeği mermisi aldı.,Взято коробку рушничних набоїв. +Picked up a backpack full of ammo!,GOTBACKPACK,,,,Sebrán batoh s haldou munice!,Hentede en rygsæk fuld af ammunition!,Rucksack mit Munition genommen.,Πήρες μια τσάντα γεμάτη με πυρομαχικά!,Vi trovis tornistron plena de municioj!,¡Encuentras una mochila llena de munición!,,Poimit repun täynnä ammuksia!,Sac à dos plein de munitions récupéré!,Felvettél egy tölténnyel teli hátizsákot!,Raccolto uno zaino zeppo di munizioni!,弾薬の入ったバックパックを手に入れた!,탄약이 들어있는 배낭을 얻었다!,Je hebt een rugzak vol munitie opgepakt!,Plukket opp en ryggsekk full av ammunisjon!,Zebrano plecak pełen amunicji!,Pegou uma mochila cheia de munição!,Apanhaste uma mochila cheia de munição,Ai ridicat o raniță plină cu muniție!,"Получен рюкзак, полный патронов!",Покупили сте ранац с патронама!,Plockade upp en ryggsäck full av ammunition!,Cephane dolu bir sırt çantası aldı!,Взято рюкзак повний набоїв! +"You got the BFG9000! Oh, yes.",GOTBFG9000,,,,"Sebráno BFG9000! Ó, ano!","Du fik BFG9000! Åh, ja.","Das BFG9000! Oh, ja!","Πήρες το BFG9000! ο, ΝΑΊ.",Vi trovis BFG9000! Bonege.,¡Encuentras una BFG9000! Qué guay.,¡Encuentras una BFG9000! Genial.,Sait BFG9000:n! Voi kyllä.,"UN BFG9000! OH, OUI!",Felvetted a BFG9000-et! Ezaz.,"Hai trovato il BFG9000! Eh, sì!",BFG9000を手に入れた!やったぜ。,당신은 BFG9000을 습득했다! 오우 예.,Je hebt de BFG9000! Jawel.,"Du har BFG9000! Å, ja.","Zebrano BFG9000! O, tak.","Você pegou a BFG! Ah, que delícia!","Apanhaste a BFG9000! Oh, SIM!","Ai pus mâna pe BFG9000! Oh, da.","У вас BFG9000! О, да!","Покупили сте ВЈП9000! О, да.","Du fick fått BFG9000! Ja, ja.","BFG9000'i aldın! Oh, evet.",Взято БФГ9000! О так. +You got the chaingun!,GOTCHAINGUN,,,,Sebrán kulomet.,Du har et maskingevær!,Maschinengewehr genommen.,Πήρες το πολυβόλο.,Vi trovis maŝinpafilon!,¡Encuentras una ametralladora!,,Sait Gatling-konekiväärin!,Une MITRAILLEUSE!,Felvetted a golyószórót!,Hai trovato un mitragliatore!,チェーンガンを手に入れた!,당신은 체인건을 습득했다!,Je hebt het machinegeweer!,Du har en maskinpistol!,Zebrano karabin maszynowy!,Você pegou a metralhadora!,Apanhaste a metrelhadora!,Ai pus mâna pe mitraliera rotativă!,Получен пулемёт!,Покупили сте митраљез!,Du fick kedjepistolen!,Silahı aldın!,Взято кулемета. +A chainsaw! Find some meat!,GOTCHAINSAW,,,,Motorová pila! Najdi maso!,En motorsav! Find noget kød!,Eine Kettensäge. Such mir etwas Fleisch!,Ένα αλυσοπρίονο! Βρες κρέας!,Ĉensegilo! Trovu ian karnon!,¡Una motosierra! ¡Busca algo de carne!,,Moottorisaha! Mene etsimään lihaa!,Une TRONCONNEUSE! Viande frâiche!,Egy láncfűrész! Keress valami aprítanivalót!,Una motosega! Trova un po' di carne!,チェーンソウだ!肉を寄越せ!,당신은 전기톱을 습득했다! 도륙할 시간!,Een kettingzaag! Vind vlees!,En motorsag! Finn litt kjøtt!,Piła łańcuchowa! Znajdź trochę mięsa!,Uma motoserra! Encontre alguma carne!,Uma motoserra! Bora encontrar alguma carne!,O drujbă! Găsește niște carne!,Бензопила! Найди немного мяса!,Тестера! Нађи месо!,En motorsåg! Hitta lite kött!,Elektrikli testere! Biraz et bul!,Бензопила! Знайди трохи м'яса! +You got the rocket launcher!,GOTLAUNCHER,,,,Sebrán raketomet.,Du har en raketkaster!,Raketenwerfer genommen.,Πήρες το πυραβλοβόλο.,Vi trovis misilpafilon!,¡Encuentras un lanzamisiles!,,Sait singon!,Un LANCE-ROQUETTES!,Felvetted a rakétavetőt!,Hai trovato un lanciarazzi!,ロケットランチャーを手に入れた!,당신은 로켓 런쳐를 습득했다!,Je hebt de raketwerper!,Du har rakettkasteren!,Zebrano wyrzutnię rakiet!,Você pegou um lança-foguetes!,Apanhaste um lança-mísseis!,Ai pus mâna pe lansatorul de rachete!,Получен ракетомёт!,Покупили сте ракетни бацач!,Du fick raketkastaren!,Roketatarı aldın!,Взято ракетомет! +You got the plasma gun!,GOTPLASMA,,,,Sebrána plazmová puška.,Du har plasmapistolen!,Plasma-Gewehr genommen.,Πήρες το όπλο πλάσματος!,Vi trovis plasmo-pafilon!,¡Encuentras un fusil de plasma!,,Sait plasmapyssyn!,Un FUSIL A PLASMA!,Felvetted a plazmafegyvert!,Hai trovato un fucile al plasma!,プラズマライフルを手に入れた!,당신은 플라즈마 건을 습득했다!,Je hebt het plasmageweer!,Du har plasmapistolen!,Zebrano karabin plazmowy!,Você pegou o fuzil de plasma!,Apanhaste uma pistola de plasma!,Ai pus mâna pe arma cu plasmă!,Получен плазмомёт!,Покупили сте плазма оружје!,Du fick plasmapistolen!,Plazma silahın var!,Взято плазмаган! +You got the shotgun!,GOTSHOTGUN,,,,Sebrána brokovnice.,Du har et haglgevær!,Schrotflinte genommen.,Πήρες το ντουφέκι!,Vi trovis kartoĉan fusilon!,¡Encuentras una escopeta!,,Sait haulikon!,Un FUSIL A POMPE!,Felvetted a puskát!,Hai trovato un fucile!,ショットガンを手に入れた!,당신은 샷건을 습득했다!,Je hebt het jachtgeweer!,Du har haglen!,Zebrano strzelbę!,Você pegou a espingarda!,Apanhaste uma espingarda.,Ai pus mâna pe pușcă!,Получен дробовик!,Покупили сте пумпарицу!,Du fick hagelgeväret!,Pompalı tüfeğin var!,Взято дробовик! +You got the super shotgun!,GOTSHOTGUN2,,,,Sebrána superbrokovnice.,Du har et super-haglgevær!,Super-Schrotflinte genommen.,Πήρες το διπλό ντουφέκι!,Vi trovis dutuban fusilon!,¡Encuentras una superescopeta!,,Sait superhaulikon!,Un SUPER FUSIL DE CHASSE!,Felvetted a Szuper puskát!,Hai trovato una doppietta!,スーパーショットガンを手に入れた!,당신은 슈퍼 샷건을 습득했다!,Je hebt het superjachtgeweer!,Du har supergeværet!,Zebrano super strzelbę!,Você pegou uma espingarda de cano duplo!,Apanhaste uma espingarda de cano duplo!,Ai pus mâna pe super pușcă!,Получен супердробовик!,Покупили сте двоцевку!,Du fick super-hagelgeväret!,Süper av tüfeğini aldın!,Взято двостволку! +Picked up a pistol.,PICKUP_PISTOL_DROPPED,,,,Sebrána pistole.,Du har fået en pistol.,Pistole genommen.,Πήρες ενα πιστόλι.,Prenis pistolon.,Una pistola.,,Poimit pistoolin.,Un PISTOLET.,Felvettél egy pisztolyt.,Raccolta una pistola.,ピストルを拾った。,권총을 주웠다.,Je hebt het pistool opgepakt.,Plukket opp en pistol.,Zebrano pistolet.,Pegou uma pistola.,Apanhaste uma pistola.,Ai ridicat un pistol.,Получен пистолет.,Покупили сте пиштољ.,Jag plockade upp en pistol.,Bir tabanca aldın.,Взято пістолет. +You pick up a demonic dagger.,BETA_BONUS1,,,,Sebrána démonická dýka.,Du har samlet en dæmonisk dolk op.,Dämonischen Dolch genommen.,Πήρες ένα δαιμονικό μαχαίρι.,Vi trovis demonan ponardon.,Encuentras una daga demoníaca.,,Poimit demonisen tikarin.,Dague diabolique récupérée.,Felvettél egy démoni tőrt.,Hai raccolto un pugnale demoniaco.,デモニックダガーを拾った。,당신은 마귀내린 단검을 얻었다.,Je hebt een demonische dolk opgepakt.,Du plukket opp en demonisk dolk.,Zebrano demoniczny sztylet.,Você pegou uma adaga demoníaca.,Apanhaste uma navalha demoníaca.,Ai ridicat un pumnal demonic.,Вы подобрали демонический кинжал.,Купите демонски бодеж.,Plockade upp en demonisk dolk.,Şeytani bir hançer aldın.,Взято демонічний кинжал. +You pick up a skullchest.,BETA_BONUS2,,,,Sebrána lebkotruhla.,Du samler en kraniekasse op.,Schädelkiste genommen.,Πήρες ένα κρανομπαούλο.,Vi trovis kraniokeston.,Encuentras un cofre de calaveras.,,Poimit kalloarkun.,Coffre-crâne récupéré.,Felvettél egy skullchest-et.,Hai raccolto un cofanetto del teschio.,スカルチェストを拾った。,당신은 해골상자를 얻었다.,Je hebt een schedelborst opgepakt.,Du plukker opp en hodeskalle.,Zebrano skrzynię czaszki.,Você pegou um cofre-caveira.,Apanhaste um cofre caveira.,Ai ridicat o cutie cu craniu.,Вы подобрали сундук с черепом.,Купите ковчег с лобањом.,Plockade upp en skalle.,Bir kafatası sandığı aldın.,Взято скриню з черепом. +You pick up an evil sceptre.,BETA_BONUS3,,,,Sebráno zlé žezlo.,Du samler et ondt scepter op.,Teuflisches Zepter genommen.,Πήρες το μοχθηρό σκήπτρο.,Vi trovis malbonan sceptron.,Encuentras un cetro del mal.,,Poimit pahan valtikan.,Sceptre maléfique récupéré.,Felvettél egy gonosz jogart.,Hai raccolto uno scettro del male.,エビルセプターを拾った。,당신은 사악한 홀을 얻었다.,Je hebt een kwaadaardige scepter opgepakt.,Du plukker opp et ondt septer.,Zebrano złe berło.,Você pegou um cetro maligno.,Apanhaste um cetro maligno,Ai ridicat un sceptru malefic.,Вы подобрали скипетр зла.,Купите зли скиптар.,Plockade upp en ond scepter.,Şeytani bir asa alıyorsun.,Взято скіпетр зла. +You pick up an unholy bible.,BETA_BONUS4,,,,Sebrána bezbožná bible.,Du samler en uhellig bibel op.,Unheilige Bibel genommen,Πήρες τήν ανίερη βίβλο.,Vi trovis malsanktan biblion.,Encuentras una biblia profana.,,Poimit epäpyhän raamatun.,Bible profane récupérée.,Felvettél egy istentelen bibliát.,Hai raccolto una bibbia profana.,アンホーリーバイブルを拾った。,당신은 불경스러운 성서를 얻었다.,Je hebt een onheilige bijbel opgepakt.,Du plukker opp en uhellig bibel.,Zebrano nieświętą biblię.,Você pegou uma bíblia profana.,Apanhaste uma bíblia profana.,Ai ridicat o biblie nesfântă.,Вы подобрали порочную библию.,Купите несвету библију.,Plockade upp en ohelig bibel.,Kutsal olmayan bir İncil aldın.,Взято нечестиву біблію. +,,Locks,,,,,,,,,,,,,,,,,,,,,,,,,, +You need a blue key to activate this object,PD_BLUEO,,,,K aktivaci tohoto objektu potřebuješ modrý klíč.,Du skal bruge en blå nøgle for at aktivere dette objekt,"Du brauchst einen blauen Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα μπλέ κλειδί για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas bluan ŝlosilon por aktivigi ĉi tiun objekton,Necesitas una llave azul para activar este objeto,,Tarvitset sinisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé bleue pour activer cet objet.,Egy kék kulcs szükséges az tárgy aktiválásához.,Ti serve una chiave blu per attivare questo oggetto,この装置には ブルーキーが必要だ。,이 물체를 작동시키기 위해선 청색 열쇠가 필요합니다,Je hebt een blauwe sleutel nodig om dit object te activeren.,Du trenger en blå nøkkel for å aktivere denne gjenstanden,"Potrzebujesz niebieskiego klucza, aby aktywować ten przedmiot",Você precisa de uma chave azul para ativar este objeto,Precisas de uma chave azul para ativar este objeto,"Ai nevoie de o cheie albastră pentru a activa acest +obiect",Для применения нужен синий ключ,Треба вам плави кључ да би активирали овај предмет,Du behöver en blå nyckel för att aktivera det här föremålet.,Bu nesneyi etkinleştirmek için mavi bir anahtara ihtiyacınız var,"Вам потрібна синя ключ-карта, щоб активувати цей об'єкт" +You need a red key to activate this object,PD_REDO,,,,K aktivaci tohoto objektu potřebuješ červený klíč.,Du skal bruge en rød nøgle for at aktivere dette objekt,"Du brauchst einen roten Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα κόκινο κλειδί για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas ruĝan ŝlosilon por aktivigi ĉi tiun objekton,Necesitas una llave roja para activar este objeto,,Tarvitset punaisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé rouge pour activer cet objet.,"Piros kulcs kell, hogy aktiválhasd ezt a tárgyat.",Ti serve una chiave rossa per attivare questo oggetto,この装置には レッドキーが必要だ。,이 물체를 작동시키기 위해선 적색 열쇠가 필요합니다,Je hebt een rode sleutel nodig om dit object te activeren.,Du trenger en rød nøkkel for å aktivere dette objektet,"Potrzebujesz czerwonego klucza, aby aktywować ten przedmiot",Você precisa de uma chave vermelha para ativar este objeto,Precisas de uma chave vermelha para ativar este objeto,"Ai nevoie de o cheie roșie pentru a activa acest +obiect",Для применения нужен красный ключ,Треба вам црвени кључ да би активирали овај предмет,Du behöver en röd nyckel för att aktivera det här föremålet.,Bu nesneyi etkinleştirmek için kırmızı bir anahtara ihtiyacınız var,"Вам потрібна червона ключ-карта, щоб активувати цей об'єкт" +You need a yellow key to activate this object,PD_YELLOWO,,,,K aktivaci tohoto objektu potřebuješ žlutý klíč.,Du skal bruge en gul nøgle for at aktivere dette objekt,"Du brauchst einen gelben Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα κύτρινο κλειδί για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas flavan ŝlosilon por aktivigi ĉi tiun objekton,Necesitas una llave amarilla para activar este objeto,,Tarvitset keltaisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé jaune pour activer cet objet.,Egy sárga kulccsal aktiválható ez a tárgy,Ti serve una chiave gialla per attivare questo oggetto,この装置にはイエローキーが必要だ。,이 물체를 작동시키기 위해선 황색 열쇠가 필요합니다,Je hebt een gele sleutel nodig om dit object te activeren.,Du trenger en gul nøkkel for å aktivere dette objektet,"Potrzebujesz żółtego klucza, aby aktywować ten przedmiot",Você precisa de uma chave amarela para ativar este objeto,Precisas de uma chave amarela para ativar este objeto,"Ai nevoie de o cheie galbenă pentru a activa acest +obiect",Для применения нужен жёлтый ключ,Треба вам жути кључ да би активирали овај предмет,Du behöver en gul nyckel för att aktivera det här föremålet.,Bu nesneyi etkinleştirmek için sarı bir anahtara ihtiyacınız var,"Вам потрібна жовта ключ-карта, щоб активувати цей об'єкт" +You need a blue key to open this door,PD_BLUEK,,,,K otevření těchto dveří potřebuješ modrý klíč.,Du skal bruge en blå nøgle for at åbne denne dør,"Du brauchst einen blauen Schlüssel, um diese Tür zu öffnen.",Χρειάζεσε ένα μπλέ κλειδί για να ανοίξεις αυτή τη πόρτα,Vi bezonas bluan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave azul para abrir esta puerta,,Tarvitset sinisen avaimen avataksesi tämän oven,Il vous faut une clé bleue pour ouvrir cette porte.,Az ajtót egy kék kulcs nyitja.,Ti serve una chiave blu per aprire questa porta,このドアには ブルーキーが必要だ。,이 문을 열기 위해선 청색 열쇠가 필요합니다,Je hebt een blauwe sleutel nodig om deze deur te openen.,Du trenger en blå nøkkel for å åpne denne døren,"Potrzebujesz niebieskiego klucza, aby otworzyć te drzwi",Você precisa de uma chave azul para abrir esta porta,Precisas de uma chave azul para abrir esta porta,"Ai nevoie de o cheie albastră pentru a deschide +ușa aceasta",Для открытия нужен синий ключ,Треба вам плави кључ да би отворили ова врата,Du behöver en blå nyckel för att öppna den här dörren,Bu kapıyı açmak için mavi bir anahtara ihtiyacın var.,"Вам потрібна синя ключ-карта, щоб відкрити ці двері" +You need a red key to open this door,PD_REDK,,,,K otevření těchto dveří potřebuješ červený klíč.,Du skal bruge en rød nøgle for at åbne denne dør,"Du brauchst einen roten Schlüssel, um diese Tür zu öffnen.",Χρειάζεσε ένα κόκινο κλειδί για να ανοίξεις αυτή τη πόρτα,Vi bezonas ruĝan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave roja para abrir esta puerta,,Tarvitset punaisen avaimen avataksesi tämän oven,Il vous faut une clé rouge pour ouvrir cette porte.,"Piros kulcs szükséges, hogy az ajtót kinyithasd.",Ti serve una chiave rossa per aprire questa porta,このドアには レッドキーが必要だ。,이 문을 열기 위해선 적색 열쇠가 필요합니다,Je hebt een rode sleutel nodig om deze deur te openen.,Du trenger en rød nøkkel for å åpne denne døren,"Potrzebujesz czerwonego klucza, aby otworzyć te drzwi",Você precisa de uma chave vermelha para abrir esta porta,Precisas de uma chave vermelha para abrir esta porta,"Ai nevoie de o cheie roșie pentru a deschide ușa +aceasta",Для открытия нужен красный ключ,Треба вам црвени кључ да би отворили ова врата,Du behöver en röd nyckel för att öppna den här dörren,Bu kapıyı açmak için kırmızı bir anahtara ihtiyacın var.,"Вам потрібна червона ключ-карта, щоб відкрити ці двері" +You need a yellow key to open this door,PD_YELLOWK,,,,K otevření těchto dveří potřebuješ žlutý klíč.,Du skal bruge en gul nøgle for at åbne denne dør,"Du brauchst einen gelben Schlüssel, um diese Tür zu öffnen.",Χρειάζεσε ένα κύτρινο κλειδί για να ανοίξεις αυτή τη πόρτα,Vi bezonas flavan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave amarilla para abrir esta puerta,,Tarvitset keltaisen avaimen avataksesi tämän oven,Il vous faut une clé jaune pour ouvrir cette porte.,Kell egy sárga kulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave gialla per aprire questa porta,このドアには イエローキー が必要だ。,이 문을 열기 위해선 황색 열쇠가 필요합니다,Je hebt een gele sleutel nodig om deze deur te openen.,Du trenger en gul nøkkel for å åpne denne døren,"Potrzebujesz żółtego klucza, aby otworzyć te drzwi",Você precisa de uma chave amarela para abrir esta porta,Precisas de uma chave amarela para abrir esta porta,"Ai nevoie de o cheie galbena pentru a deschide ușa +aceasta",Для открытия нужен жёлтый ключ,Треба вам жути кључ да би отворили ова врата,Du behöver en gul nyckel för att öppna den här dörren.,Bu kapıyı açmak için sarı bir anahtara ihtiyacınız var,"Вам потрібна жовта ключ-карта, щоб відкрити ці двері" +You need a blue card to activate this object,PD_BLUECO,,,,K aktivaci tohoto objektu potřebuješ modrou kartu.,Du skal bruge et blåt kort for at aktivere denne objekt,"Du brauchst eine blaue Schlüsselkarte, um dieses Objekt zu aktivieren.",Χρειάζεσε μια μπλέ κάρτα για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas bluan karton por aktivigi ĉi tiun objekton,Necesitas una tarjeta azul para activar este objeto,,Tarvitset sinisen avainkortin aktivoidaksesi tämän kappaleen,Il vous faut une carte bleue pour activer cet objet.,"Egy kék kártya kell, hogy ezt a tárgyat aktiválhasd",Ti serve una card d'accesso blu per attivare questo oggetto ,この装置には ブルーカード が必要だ。,이 물체를 작동시키기 위해선 청색 키카드가 필요합니다,Je hebt een blauwe sleutelkaart nodig om dit voorwerp te activeren.,Du trenger et blått kort for å aktivere dette objektet,"Potrzebujesz niebieskiej karty, aby aktywować ten obiekt",Você precisa de um cartão de acesso azul para ativar este objeto,Precisas de um cartão de acesso azul para ativar este objeto,"Ai nevoie de un card albastru pentru a activa +acest obiect",Для применения нужна синяя карта,Треба вам плава карта да би активирали овај предмет,Du behöver ett blått kort för att aktivera det här objektet.,Bu nesneyi etkinleştirmek için mavi bir karta ihtiyacınız var,"Вам потрібна синя ключ-карта, щоб активувати цей об'єкт" +You need a red card to activate this object,PD_REDCO,,,,K aktivaci tohoto objektu potřebuješ červenou kartu.,Du skal bruge et rødt kort for at aktivere denne objekt,"Du brauchst eine rote Schlüsselkarte, um dieses Objekt zu aktivieren.",Χρειάζεσε μια κόκινη κάρτα για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas ruĝan karton por aktivigi ĉi tiun objekton,Necesitas una tarjeta roja para activar este objeto,,Tarvitset punaisen avainkortin aktivoidaksesi tämän kappaleen,Il vous faut une carte rouge pour activer cet objet.,Piros kártyával aktiválható ez a tárgy,Ti serve una card d'accesso rossa per attivare questo oggetto ,この装置には レッドカード が必要だ。,이 물체를 작동시키기 위해선 적색 키카드가 필요합니다,Je hebt een rode sleutelkaart nodig om dit voorwerp te activeren.,Du trenger et rødt kort for å aktivere dette objektet,"Potrzebujesz czerwonej karty, aby aktywować ten obiekt",Você precisa de um cartão de acesso vermelho para ativar este objeto,Precisas de um cartão de acesso vermelho para ativar este objeto,"Ai nevoie de un card roșu pentru a activa +acest obiect",Для применения нужна красная карта,Треба вам црвена карта да би активирали овај предмет,Du behöver ett rött kort för att aktivera det här föremålet.,Bu nesneyi etkinleştirmek için kırmızı bir karta ihtiyacınız var,"Вам потрібна червона ключ-карта, щоб активувати цей об'єкт" +You need a yellow card to activate this object,PD_YELLOWCO,,,,K aktivaci tohoto objektu potřebuješ žlutou kartu.,Du skal bruge et gult kort for at aktivere denne objekt,"Du brauchst eine gelbe Schlüsselkarte, um dieses Objekt zu aktivieren.",Χρειάζεσε μια κύτρινη κάρτα για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas flavan karton por aktivigi ĉi tiun objekton,Necesitas una tarjeta amarilla para activar este objeto,,Tarvitset keltaisen avainkortin aktivoidaksesi tämän kappaleen,Il vous faut une carte jaune pour activer cet objet.,Kell egy sárga kártya hogy aktiváld ezt a tárgyat,ti serve una card d'accesso gialla per attivare questo oggetto ,この装置には イエローカード が必要だ。,이 물체를 작동시키기 위해선 황색 키카드가 필요합니다,Je hebt een gele sleutelkaart nodig om dit voorwerp te activeren.,Du trenger et gult kort for å aktivere dette objektet,"Potrzebujesz żółtej karty, aby aktywować ten obiekt",Você precisa de um cartão de acesso amarelo para ativar este objeto,Precisas de um cartão de acesso amarelo para ativar este objeto,"Ai nevoie de un card galben pentru a activa +acest obiect",Для применения нужна жёлтая карта,Треба вам жута карта да би активирали овај предмет,Du behöver ett gult kort för att aktivera det här föremålet.,Bu nesneyi etkinleştirmek için sarı bir karta ihtiyacınız var,"Вам потрібна жовта ключ-карта, щоб активувати цей об'єкт" +You need a blue skull to activate this object,PD_BLUESO,,,,K aktivaci tohoto objektu potřebuješ modrou lebku.,Du skal bruge et blåt kranium for at aktivere denne objekt,"Du brauchst einen blauen Schädel-Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα μπλέ κρανιο για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas bluan kranion por aktivigi ĉi tiun objekton,Necesitas una calavera azul para activar este objeto,Necesitas un cráneo azul para activar este objeto,Tarvitset sinisen kalloavaimen aktivoidaksesi tämän kappaleen,Il vous faut un crâne bleu pour activer cet objet.,Kell egy kék koponya hogy aktiváld ezt a tárgyat.,ti serve una chiave-teschio blu per attivare questo oggetto ,この装置には ブルースカル が必要だ。,이 물체를 작동시키기 위해선 청색 해골이 필요합니다,Je hebt een blauwe schedel nodig om dit voorwerp te activeren.,Du trenger en blå hodeskalle for å aktivere dette objektet,"Potrzebujesz niebieskiej czaszki, aby aktywować ten obiekt",Você precisa de uma chave-crânio azul para ativar este objeto,Precisas de uma chave crânio azul para ativar este objeto,"Ai nevoie de un craniu albastru pentru a activa +acest obiect",Для применения нужен синий череп,Треба вам плава лобања да би активирали овај предмет,Du behöver en blå skalle för att aktivera det här objektet.,Bu nesneyi etkinleştirmek için mavi bir kafatasına ihtiyacınız var,"Вам потрібен синій ключ-череп, щоб активувати цей об'єкт" +You need a red skull to activate this object,PD_REDSO,,,,K aktivaci tohoto objektu potřebuješ červenou lebku.,Du skal bruge et rødt kranium for at aktivere denne objekt,"Du brauchst einen roten Schädel-Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα κόκινο κρανιο για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas ruĝan kranion por aktivigi ĉi tiun objekton,Necesitas una calavera roja para activar este objeto,Necesitas un cráneo rojo para activar este objeto,Tarvitset punaisen kalloavaimen aktivoidaksesi tämän kappaleen,Il vous faut un crâne rouge pour activer cet objet.,Kell egy piros koponya hogy aktiváld ezt a tárgyat.,ti serve una chiave-teschio rossa per attivare questo oggetto ,この装置には レッドスカル が必要だ。,이 물체를 작동시키기 위해선 적색 해골이 필요합니다,Je hebt een rode schedel nodig om dit voorwerp te activeren.,Du trenger en rød hodeskalle for å aktivere dette objektet,"Potrzebujesz czerwonej czaszki, aby aktywować ten obiekt",Você precisa de uma chave-crânio vermelha para ativar este objeto,Precisas de uma chave crânio vermelha para ativar este objeto,"Ai nevoie de un craniu roșu pentru a activa +acest obiect",Для применения нужен красный череп,Треба вам црвена лобања да би активирали овај предмет,Du behöver en röd skalle för att aktivera det här föremålet.,Bu nesneyi etkinleştirmek için kırmızı bir kafatasına ihtiyacınız var,"Вам потрібен червоний ключ-череп, щоб активувати цей об'єкт" +You need a yellow skull to activate this object,PD_YELLOWSO,,,,K aktivaci tohoto objektu potřebuješ žlutou lebku.,Du skal bruge et gult kranium for at aktivere denne objekt,"Du brauchst einen gelben Schädel-Schlüssel, um dieses Objekt zu aktivieren.",Χρειάζεσε ένα κύτρινο κρανιο για να ενεργοποίησεις αυτο το αντικείμενο,Vi bezonas flavan kranion por aktivigi ĉi tiun objekton,Necesitas una calavera amarilla para activar este objeto,Necesitas un cráneo amarillo para activar este objeto,Tarvitset keltaisen kalloavaimen aktivoidaksesi tämän kappaleen,Il vous faut un crâne jaune pour activer cet objet.,Kell egy sárga koponya hogy aktiváld ezt a tárgyat.,ti serve una chiave-teschio gialla per attivare questo oggetto ,この装置には イエロースカル が必要だ。,이 물체를 작동시키기 위해선 황색 해골이 필요합니다,Je hebt een gele schedel nodig om dit voorwerp te activeren.,Du trenger en gul hodeskalle for å aktivere dette objektet,"Potrzebujesz żółtej czaszki, aby aktywować ten obiekt",Você precisa de uma chave-crânio amarela para ativar este objeto,Precisas de uma chave crânio amarela para ativar este objeto,"Ai nevoie de un craniu galben pentru a activa +acest obiect",Для применения нужен жёлтый череп,Треба вам жута лобања да би активирали овај предмет,Du behöver en gul skalle för att aktivera detta föremål.,Bu nesneyi etkinleştirmek için sarı bir kafatasına ihtiyacınız var,"Вам потрібен жовтий ключ-череп, щоб активувати цей об'єкт" +You need a blue card to open this door,PD_BLUEC,,,,K otevření těchto dveří potřebuješ modrou kartu.,Du skal bruge et blåt kort for at åbne denne dør,"Du brauchst eine blaue Schlüsselkarte, um diese Tür zu öffnen",Χρειάζεσε μια μπλέ κάρτα για να ανοίξεις αυτή τη πόρτα,Vi bezonas bluan karton por malfermi ĉi tiun pordon,Necesitas una tarjeta azul para abrir esta puerta,,Tarvitset sinisen avainkortin avataksesi tämän oven,Il vous faut une carte bleue pour ouvrir cette porte.,Ez az ajtó egy kék kártyával nyílik.,Ti serve una card d'accesso blu per aprire questa porta,このドアには ブルーカード が必要だ。,이 문을 열기 위해선 청색 키카드가 필요합니다,Je hebt een blauwe sleutelkaart nodig om deze deur te openen.,Du trenger et blått kort for å åpne denne døren,"Potrzebujesz niebieskiej karty, aby otworzyć te drzwi",Você precisa de um cartão de acesso azul para abrir esta porta,Precisas de um cartão de acesso azul para abrir esta porta,"Ai nevoie de un card albastru pentru a activa +această usă",Для открытия нужна синяя карта,Треба вам плава карта да би отворили ова врата,Du behöver ett blått kort för att öppna den här dörren.,Bu kapıyı açmak için mavi bir karta ihtiyacınız var,"Вам потрібна синя карта, щоб активувати цей об'єкт" +You need a red card to open this door,PD_REDC,,,,K otevření těchto dveří potřebuješ červenou kartu.,Du skal bruge et rødt kort for at åbne denne dør,"Du brauchst eine rote Schlüsselkarte, um diese Tür zu öffnen",Χρειάζεσε μια κόκινη κάρτα για να ανοίξεις αυτή τη πόρτα,Vi bezonas ruĝan karton por malfermi ĉi tiun pordon,Necesitas una tarjeta roja para abrir esta puerta,,Tarvitset punaisen avainkortin avataksesi tämän oven,Il vous faut une carte rouge pour ouvrir cette porte.,Ez az ajtó egy piros kártyával nyílik.,Ti serve una card d'accesso rossa per aprire questa porta,このドアには レッドカード が必要だ。,이 문을 열기 위해선 적색 키카드가 필요합니다,Je hebt een rode sleutelkaart nodig om deze deur te openen.,Du trenger et rødt kort for å åpne denne døren,"Potrzebujesz czerwonej karty, aby otworzyć te drzwi",Você precisa de um cartão de acesso vermelho para abrir esta porta,Precisas de um cartão de acesso vermelho para abrir esta porta,"Ai nevoie de un card galben pentru a activa +această ușă",Для открытия нужна красная карта,Треба вам црвена карта да би отворили ова врата,Du behöver ett rött kort för att öppna den här dörren.,Bu kapıyı açmak için kırmızı bir karta ihtiyacınız var.,"Вам потрібна червона карта, щоб активувати цей об'єкт" +You need a yellow card to open this door,PD_YELLOWC,,,,K otevření těchto dveří potřebuješ žlutou kartu.,Du skal bruge et gult kort for at åbne denne dør,"Du brauchst eine gelbe Schlüsselkarte, um diese Tür zu öffnen",Χρειάζεσε μια κύτρινη κάρτα για να ανοίξεις αυτή τη πόρτα,Vi bezonas flavan karton por malfermi ĉi tiun pordon,Necesitas una tarjeta amarilla para abrir esta puerta,,Tarvitset keltaisen avainkortin avataksesi tämän oven,Il vous faut une carte jaune pour ouvrir cette porte.,Ez az ajtó egy sárga kártyával nyílik.,Ti serve una card d'accesso gialla per aprire questa porta,このドアには イエローカード が必要だ。,이 문을 열기 위해선 황색 키카드가 필요합니다,Je hebt een gele sleutelkaart nodig om deze deur te openen.,Du trenger et gult kort for å åpne denne døren,"Potrzebujesz żółtej karty, aby otworzyć te drzwi",Você precisa de um cartão de acesso amarelo para abrir esta porta,Precisas de um cartão de acesso amarelo para abrir esta porta,"Ai nevoie de un card galben pentru a activa +această ușă",Для открытия нужна жёлтая карта,Треба вам жута карта да би отворили ова врата,Du behöver ett gult kort för att öppna den här dörren.,Bu kapıyı açmak için sarı bir karta ihtiyacınız var,"Вам потрібна жовта карта, щоб активувати цей об'єкт" +You need a blue skull to open this door,PD_BLUES,,,,K otevření těchto dveří potřebuješ modrou lebku.,Du skal bruge et blåt kranium for at åbne denne dør,"Du brauchst einen blauen Schädel-Schlüssel, um diese Tür zu öffnen",Χρειάζεσε ένα μπλέ κρανίο για να ανοίξεις αυτή τη πόρτα,Vi bezonas bluan kranion por malfermi ĉi tiun pordon,Necesitas una calavera azul para abrir esta puerta,Necesitas un cráneo azul para abrir esta puerta,Tarvitset sinisen kalloavaimen avataksesi tämän oven,Il vous faut un crâne bleu pour ouvrir cette porte.,Ez az ajtó egy kék koponyával nyílik.,Ti serve una chiave-teschio blu per aprire questa porta,このドアには ブルースカル が必要だ。,이 문을 열기 위해선 청색 해골이 필요합니다,Je hebt een blauwe schedel nodig om deze deur te openen.,Du trenger en blå hodeskalle for å åpne denne døren,"Potrzebujesz niebieskiej czaszki, aby otworzyć te drzwi",Você precisa de uma chave-crânio azul para abrir esta porta,Precisas de uma chave crânio azul para abrir esta porta,"Ai nevoie de un craniu albastru pentru a activa +această ușă",Для открытия нужен синий череп,Треба вам плава лобања да би отворили ова врата,Du behöver en blå skalle för att öppna den här dörren.,Bu kapıyı açmak için mavi bir kafatasına ihtiyacın var.,"Вам потрібен синій череп, щоб активувати цей об'єкт" +You need a red skull to open this door,PD_REDS,,,,K otevření těchto dveří potřebuješ červenou lebku.,Du skal bruge et rødt kranium for at åbne denne dør,"Du brauchst einen roten Schädel-Schlüssel, um diese Tür zu öffnen",Χρειάζεσε ένα κόκινο κρανίο για να ανοίξεις αυτή τη πόρτα,Vi bezonas ruĝan kranion por malfermi ĉi tiun pordon,Necesitas una calavera roja para abrir esta puerta,Necesitas un cráneo rojo para abrir esta puerta,Tarvitset punaisen kalloavaimen avataksesi tämän oven,Il vous faut un crâne rouge pour ouvrir cette porte.,Ez az ajtó egy piros koponyával nyílik.,Ti serve una chiave-teschio rossa per aprire questa porta,このドアには レッドスカル が必要だ。,이 문을 열기 위해선 적색 해골이 필요합니다,Je hebt een rode schedel nodig om deze deur te openen.,Du trenger en rød hodeskalle for å åpne denne døren,"Potrzebujesz czerwonej czaszki, aby otworzyć te drzwi",Você precisa de uma chave-crânio vermelha para abrir esta porta,Precsias de uma chave crânio vermelha para abrir esta porta,"Ai nevoie de un craniu roșu pentru a activa +această ușă",Для открытия нужен красный череп,Треба вам црвена лобања да би отворили ова врата,Du behöver en röd skalle för att öppna den här dörren.,Bu kapıyı açmak için kırmızı bir kafatasına ihtiyacın var.,"Вам потрібен червоний череп, щоб активувати цей об'єкт" +You need a yellow skull to open this door,PD_YELLOWS,,,,K otevření těchto dveří potřebuješ žlutou lebku.,Du skal bruge et gult kranium for at åbne denne dør,"Du brauchst einen gelben Schädel-Schlüssel, um diese Tür zu öffnen",Χρειάζεσε ένα κύτρινο κρανίο για να ανοίξεις αυτή τη πόρτα,Vi bezonas flavan kranion por malfermi ĉi tiun pordon,Necesitas una calavera amarilla para abrir esta puerta,Necesitas un cráneo amarillo para abrir esta puerta,Tarvitset keltaisen kalloavaimen avataksesi tämän oven,Il vous faut un crâne jaune pour ouvrir cette porte.,Ez az ajtó egy sárga koponyával nyílik.,Ti serve una chiave-teschio gialla per aprire questa porta,このドアには イエロースカル が必要だ。,이 문을 열기 위해선 황색 해골이 필요합니다,Je hebt een gele schedel nodig om deze deur te openen.,Du trenger en gul hodeskalle for å åpne denne døren,"Potrzebujesz żółtej czaszki, aby otworzyć te drzwi",Você precisa de uma chave-crânio amarela para abrir esta porta,Precisas de uma chave crânio amarela para abrir esta porta,"Ai nevoie de un craniu galben pentru a activa +această ușă",Для открытия нужен жёлтый череп,Треба вам жута лобања да би отворили ова врата,Du behöver en gul skalle för att öppna den här dörren.,Bu kapıyı açmak için sarı bir kafatasına ihtiyacın var.,"Вам потрібен жовтий череп, щоб активувати цей об'єкт" +,,Cast call names,,,,,,,,,,,,,,,,,,,,,,,,,, +Zombieman,CC_ZOMBIE,,,,Zombie,Zombie,Zombie,Ζόμπι,Zombio,Zombi,,Zombimies,Zombie,Zombi,Zombie Marine,ゾンビ兵,좀비맨,Zombie,Zombiemann,Zombie,Zumbi,Homem Zombie,Zombi,Зомби,Зомби,Zombie,Zombi,Зомбі +Shotgun Guy,CC_SHOTGUN,a.k.a. (former human) sergeant,,,Seržant,Sergent,Schütze,Τύπος με ντουφέκι,Ĉaspafilulo,Sargento,,Haulikkohemmo,Type au Fusil,Őrmester,Zombie Sergente,ショットガンゾンビ,샷건 가이,Jachtgeweerkerel,Sersjant,Zombie-sierżant,Sargento Possuído,Tipo de Espingarda,Pușcaș,Зомби-сержант,Пумпераш,Hagelgevärskille,Çavuş,Зомбі-сержант +Heavy Weapon Dude,CC_HEAVY,a.k.a. former commando,,,Kulometčík,,MG-Schütze,Τύπος με βαρί όπλο,Pezarmilulo,Ametrallador,,Raskasaseäijä,Type au Gros Flingue,Kommandós,Zombie Commando,ヘビーウェポンゾンビ,헤비 웨폰 듀드,Zwarewapenskerel,Maskingeværskyt,Ciężkozbrojny Zombie,Comando Possuído,Gajo das Armas Pesadas,Mitralior,Зомби-пулемётчик,Митраљезац,Tunga vapen kille,Ağır Silah Dostum,Кулеметник +Imp,CC_IMP,,,,Čert,,Kobold,Διάβολος,Diableto,,,Piru,Diablotin,Tűzkobold,,インプ,임프,,,Diablik,Diabrete,,Drac,Имп,Враг,,İmp,Імп +Demon,CC_DEMON,,,,Démon,Dæmon,Dämon,Δαίμονας,Demono,Demonio,,Demoni,Démon,Démon,Pinky,デーモン,데몬,Demoon,,,Demônio,,,Демон,Демон,,İblis,Демон +Lost Soul,CC_LOST,,,,Ztracená duše,Fortabt sjæl,Verlorene Seele,Χαμένη Ξυχή,Perdita Animo,Alma Errante,,Kadonnut sielu,Ame Perdue,Kóbor lélek,Anima Errante,ロストソウル,로스트 소울,Verloren ziel,Fortapt sjel,Zaginiona Dusza,Alma Perdida,Alma Penada,Suflet Pierdut,Потерянная душа,Изгубљена душа,Förlorad själ,Kayıp Ruh,Пропаща душа +Cacodemon,CC_CACO,,,,Kakodémon,Cacodæmon,Cacodämon,Κακοδαίμονας,Kakodemono,Cacodemonio,,Kakodemoni,Cacodémon,Kakodémon,Cacodemone,カコデーモン,카코데몬,Cacodemoon,Kacodemon,Kakodemon,Cacodemônio,,Cacodemon,Какодемон,Какодемон,Cacodemon,Cacodemon,Какодемон +Hell Knight,CC_HELL,,,,Pekelný rytíř,Helvedesridder,Höllenritter,Ιππότης της Κόλασης,Inferkavaliro,Caballero del Infierno,,Hornanritari,Chevalier Infernal,Pokollovag,Cavaliere Infernale,ヘルナイト,헬 나이트,Helleridder,Helvetesridder,Rycerz Piekła,Cavaleiro Infernal,Cavaleiro Infernal,Cavaler al Infernului,Рыцарь ада,Витез пакла,Helvete riddare,Cehennem Şövalyesi,Лицар Пекла +Baron of Hell,CC_BARON,,,,Baron pekel,Helvedesbaron,Höllenbaron,Βαρώνος της Κολασης,Barono de Infero,Barón del Infierno,,Hornanparoni,Baron des Enfers,Pokolbáró,Barone Infernale,バロンオブヘル,바론 오브 헬,Baron des Hels,Helvetesbaron,Baron Piekła,Barão do Inferno,,Baron al Infernului,Барон ада,Барон пакла,Helvetets baron,Cehennem Baronu,Барон Пекла +Arachnotron,CC_ARACH,,,,,,,Αράχνοτρον,Elektraraneo,Aracnotrón,,Araknotroni,,Póktron,,アラクノトロン,아라크노트론,,,,Aracnotron,,Aracnotron,Арахнотрон,Паукотрон,,Araknotron,Арахнотрон +Pain Elemental,CC_PAIN,,,,Živel trýzně,Smerteelementar,Elementarschmerz,Στοιχείομα του Πόνου,Doloro-Elementulo,Elemental del Dolor,,Kivun henki,Elémentaire de Douleur,Elemi Kín,Elementale del Dolore,ペインエレメンタル,페인 엘리멘탈,Smartelementaal,Smerte Elemental,Żywiołak Bólu,Elemental da Dor,,Elemental al Durerii,Элементаль боли,Елементал патње,Smärta elementär,Acı Elementi,Елементаль болю +Revenant,CC_REVEN,,,,Umrlec,Hævnen,Wiederauferstandener,Εκδικητής,Renaskitulo,,,Henkiinpalannut,,Kísértet,,レバナント,레버넌트,Wreker,Gjenganger,Zjawa,Insepulto,Renascido,Nemort,Ревенант,Повратник,Återfödare,,Ревевант +Mancubus,CC_MANCU,,,,Mankubus,,,Χοντρός,Mankubo,,,Mankubus,Mancube,Mankubusz,,マンキュバス,맨큐버스,,,Antropokub,,,,Манкубус,Манкубус,,,Манкубус +Arch-Vile,CC_ARCH,,,,Veleběs,Ærkevile,Scheusal,Νεκρομάντις,Ĉef-Fiulo,,,Arkkihirvitys,Arche-vile,Ősármány,Arch-vile,アーチバイル,아크-바일,Aartsgedrocht,Erkefiende,Arcy-Podlec,Arquivil,,Abject,Архвиль,Арчвајл,Ärkevild,Baş Aşağılık,Арчвайл +The Spider Mastermind,CC_SPIDER,,,,Pavoučí velevůdce,Edderkoppen Mastermind,Der Spinnenmeister,Το Αραχνό Ιθύνων Νους,La Elektraraneo-Mastro,La Mente-Maestra Arácnida,,Hämähäkkiaivot,L'Araignée Commandante,Pókelme,L'Aracnomente Suprema,スパイダーマスターマインド,스파이더 마스터마인드,Het Spinnenmeesterbrein,Edderkopphjernen,Pajęczy Mistrz,A Aranha-Mestra,,Păianjen Maestru,Паук-предводитель,Паук-руководилац,Spindelns hjärna,Örümcek Beyni,Павук-полководець +The Cyberdemon,CC_CYBER,,,,Kyberdémon,Cyberdæmonen,Der Cyberdämon,Ο Cyber-δαίμονας,La Ciberdemono,El Ciberdemonio,,Kyberdemoni,Le Cyberdémon,A Kiberdémon,Il Cyberdemonio,サイバーデーモン,사이버데몬,Het Cyberdemoon,Kyberdemonen,Cyberdemon,O Ciberdemônio,,Ciberdemon,Кибердемон,Сајбердемон,Cyberdemon,Siber Şeytan,Кібердемон +Our Hero,CC_HERO,,,,Náš hrdina,Vores helt,Unser Held,Ο ήρωας μας,Nia heroo,Nuestro héroe,,Sankarimme,Notre Héros,Hősünk,Il Nostro eroe,我らのヒーロー,우리들의 영웅,Onze held,Vår helt,Nasz bohater,Nosso herói,O Nosso Herói,Eroul Nostru,Наш герой,Наш херој,Vår hjälte,Bizim Kahramanımız,Наш герой +,,Actor tag names,,,,,,,,,,,,,,,,,,,,,,,,,, +Sergeant,FN_SHOTGUN,,,,Seržant,Sergent,Schütze,Λοχίας,Serĝento,Sargento,,Kersantti,Type au Fusil,Őrmester,Zombie Sergente,ゾンビ軍曹,샷건 가이,,Sersjant,Zombie-sierżant,Sargento,Sargento,Sergent,Зомби-сержант,Водник,Hagelgevärskille,Çavuş,Зомбі-сержант +Chaingunner,FN_HEAVY,,,,Kulometčík,,MG-Schütze,Πολυβόλο Ζόμπι,Maŝinpafilisto,Ametrallador,,Konekiväärimies,Type au Gros Flingue,Kommandós,Zombie Commando,チェーンガンゾンビ,체인거너,Machinegeweerman,Maskingeværskyt,Ciężkozbrojny Zombie,Comando,Metrelhador,Mitralior,Зомби-пулемётчик,Митраљезац,Tunga vapen kille,Ağır Silah Dostum,Кулеметник +Spectre,FN_SPECTRE,,,,Přízrak,Spøgelse,Schemen,Φάντασμα,Fantomo,Espectro,,Haamu,,Lidérc,Spettro,スペクトル,스펙터,Spook,Spøkelse,Widmo,Espectro,,Spectru,Фантом,Авет,,Hayalet,Примара +Spider Mastermind,FN_SPIDER,,,,Pavoučí velevůdce,Edderkoppen Mastermind,Spinnenmeister,Αραχνό Ιθύνων Νους,Elektraraneo-Mastro,Mente-Maestra Arácnida,,Hämähäkkiaivot,L'Araignée Commandante,Pókelme,L'Aracnomente Suprema,スパイダーマスターマインド,스파이더 마스터마인드,Spinnenmeesterbrein,Edderkopphjerne,Pajęczy Mistrz,Aranha-Mestra,,Păianjen Maestru,Паук-предводитель,Паук-руководилац,Spindelns hjärna,Örümcek Beyni,Павук-полководець +Cyberdemon,FN_CYBER,,,,Kyberdémon,Cyberdæmon,Cyberdämon,Cyber-δαίμονας,Ciberdemono,Ciberdemonio,,Kyberdemoni,Le Cyberdémon,Kiberdémon,Il Cyberdemonio,サイバーデーモン,사이버데몬,Cyberdemoon,Kyberdemon,Cyberdemon,Ciberdemônio,,Ciberdemon,Кибердемон,Сајбердемон,Cyberdemon,Siber İblis,Кібердемон +Nazi,FN_WOLFSS,,,,Nácek,,,Ναζιστής,Nazio,,,Natsi,,Náci,Nazista,ナチ兵,나치,,Nazist,Nazista,Nazista,,Nazist,Нацист,Нациста,Nazist,,Нацист +Dog,FN_DOG,,,,Pes,Hund,Hund,Σκύλος,Hundo,Perro,,Koira,Chien,Kutya,Cane,犬,개,Hond,Hund,Pies,Cão,,Câine,Собака,Пас,Hund,Köpek,Пес +Brass Knuckles,TAG_FIST,,,,Boxer,Messing knoer,Schlagringe,Γροθιά,Pugningo,Puño americano,Manopla (puño de acero),Nyrkkirauta,Poing Américain,Bokszer,Tirapugni ,ナックルダスター,너클,Boksbeugels,Knokejern,Kastety,Soco Inglês,Soqueira,Rozetă,Латунный кастет,Боксер,Mässingsknoglar,Pirinç Muşta,Кулаки +Chainsaw,TAG_CHAINSAW,,,,Motorová pila,Kædesav,Kettensäge,Αλλησοπρίονο,Ĉensegilo,Motosierra,,Moottorisaha,Tronçonneuse,Láncfűrész,Motosega,チェーンソウ,전기톱,Kettingzaag,Motorsag,Piła łańcuchowa,Motosserra,,Drujbă,Бензопила,Моторна тестера,Motorsåg,Testere,Бензопила +Pistol,TAG_PISTOL,,,,Pistole,,Pistole,Πιστόλι,Pafileto,Pistola,,Pistooli,Pistolet,Pisztoly,Pistola,ピストル,권총,Pistool,,Pistolet,Pistola,,,Пистолет,Пиштољ,,Tabanca,Пістолет +Shotgun,TAG_SHOTGUN,,,,Brokovnice,Haglgevær,Schrotflinte,Ντουφέκι,Kartoĉa fusilo,Escopeta,,Haulikko,Fusil à pompe,Sörétes Puska,Fucile,ショットガン,샷건,Jachtgeweer,Haglgevær,Strzelba,Espingarda,,Pușcă,Дробовик,Пумпарица,Hagelgevär,Av Tüfeği,Дробовик +Super Shotgun,TAG_SUPERSHOTGUN,,,,Superbrokovnice,Super-Haglgevær,Super-Schrotflinte,Διπλό Ντουφέκι,Dutuba fusilo,Superescopeta,,Superhaulikko,Super Fusil de chasse,Szuper Sörétes,Fucile a doppia canna ,スーパーショットガン,슈퍼 샷건,Superjachtgeweer,Super-Haglgevær,Super strzelba,Espingarda de cano duplo,,Super Pușcă,Супердробовик,Двоцевка,Super hagelgevär,Süper Av Tüfeği,Двостволка +Chaingun,TAG_CHAINGUN,,,,Kulomet,Maskingevær,Maschinengewehr,Πολυβόλο,Maŝinpafilo,Ametralladora,,Gatling-kk,Mitrailleuse,Golyószóró,Mitragliatore a canne rotanti ,チェーンガン,체인건,Machinegeweer,Maskinpistol,Karabin maszynowy,Metralhadora,,Mitralieră rotativă,Пулемёт,Митраљез,Kedjepistol,,Кулемет +Rocket Launcher,TAG_ROCKETLAUNCHER,,,,Raketomet,Raketkaster,Raketenwerfer,Πυραυλοβόλο,Misilpafilo,Lanzamisiles,,Sinko,Lance-Roquettes,Rakétavető,Lanciamissili,ロケットランチャー,로켓 런쳐,Raketwerper,Rakettkaster,Wyrzutnia rakiet,Lança-foguetes,Lança-Mísseis,Lansator de Rachete,Ракетомёт,Бацач ракета,Raketkastare,Roket Fırlatıcı,Ракетомет +Plasma Rifle,TAG_PLASMARIFLE,,,,Plazmová puška,Plasma riffel,Plasmagewehr,Πλάσμα Όπλο,Plasmo-pafilo,Fusil de plasma,,Plasmapyssy,Fusil à Plasma,Plazmafegyver,Fucile al Plasma ,プラズマライフル,플라즈마 라이플,Plasmageweer,Plasmagevær,Karabin plazmowy,Fuzil de Plasma,Pistola de Plasma,Pușcă cu Plasmă,Плазменная пушка,Плазма оружје,Plasmagevär,Plazma Tüfeği,Плазмаган +BFG 9000,TAG_BFG9000,,,,,,,,,,,,,,,,,,,,,,,,ВЈП 9000,,,БФГ 9000 +Bullets,AMMO_CLIP,,,,Kulky,Kugler,Patronen,Σφαίρες,Kugloj,Balas,,Luodit,Balles,Töltények,Proiettili,銃弾,권총 탄약,Kogels,Kuler,Naboje,Balas,,Gloanțe,Пули,Меци,Kulor,Kurşunlar,Кулі +Shotgun Shells,AMMO_SHELLS,,,,Broky,Haglgeværpatroner,Schrotpatronen,Σφαίρες Ντουφεκιού,Kartoĉoj,Cartuchos de escopeta,,Haulikon patruunat,Cartouches,Sörétek,Cartucce per fucile,散弾シェル,샷건 탄약,Jachtgeweerkogels,Haglepatroner,Loftki,Cartuchos de Espingarda,,Proiectile pentru Pușcă,Патроны дробовика,Патроне за пумпарицу,Skottgubbar,Av Tüfeği Fişekleri,Рушничні набої +Rockets,AMMO_ROCKETS,,,,Rakety,Raketter,Raketen,Πύραυλοι,Raketoj,Cohetes,,Raketit,Roquettes,Rakéták,Razzi,ロケット弾,로켓,Raketten,Raketter,Rakiety,Foguetes,Mísseis,Rachete,Ракеты,Ракете,Raketer,Roketler,Ракети +Energy Cells,AMMO_CELLS,,,,Energetické články,Energiceller,Energiezellen,Κύτταρα Ενέργιας,Energiĉeloj,Célula de energía,,Energia-akut,Cellules,Energiacellák,Batterie,エネルギーセル,에너지 셀,Energiecellen,Energiceller,Ogniwa energetyczne,Células de Energia,,Celule cu Energie,Энергобатареи,Енергетске ћелије,Energiceller,Enerji Hücreleri,Енергетичні батареї +,,Obituaries,,,,,,,,,,,,,,,,,,,,,,,,,, +%o thought %g saw an arachnotron.,OB_STEALTHBABY,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] arachnotrona.","%o troede, @[pro_dk] så en arachnotron.","%o dachte, ein Arachnotron zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Αραχνοτρόν.,"%o pensis, ke @[pro_eo] vidis elektraraneon.",%o ha creído ver un Aracnotrón.,%o creyó haber visto un Aracnotrón.,%o luuli nähneensä araknotronin.,%o a cru voir un Arachnotron.,"%o azt hitte, hogy látott egy póktront.",a %o sembrava di aver visto un arachnotron.,%o がアラクノトロンを見た気がした。,%o 은(는) 아라크노트론을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een arachnotron zag.,%o trodde @[pro_dk] så et arachnotron.,%o kątem oka zauważył@[ao_pl] arachnotrona.,%o achou que viu uma arachnotron.,,%o a crezut că %g a văzut un aracnotron.,Игрок %o краем глаза заметил арахнотрона.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] паукотрона.,%o trodde att @[pro_sv] såg en arachnotron.,%o bir araknotron gördüğünü sandı.,Арахнотрон мелькнув перед очима %o. +%o thought %g saw an archvile.,OB_STEALTHVILE,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] veleběsa.","%o troede, @[pro_dk] så en ærkevile.","%o dachte, ein Scheusal zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Νεκρομάντη,"%o pensis, ke @[pro_eo] vidis ĉef-fiulon.",%o ha creído ver un Arch-Vile.,%o creyó haber visto un Arch-Vile.,%o luuli nähneensä arkkihirvityksen,%o a cru voir un Arche-Vile.,"%o azt hitte, hogy látott egy ősármányt.",a %o sembrava di aver visto un Arch-Vile.,%o がアーチバイルを見た気がした。,%o 은(는) 아크-바일을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een aartsvijand zag.,%o trodde @[pro_dk] så en erkefiende.,%o kątem oka zauważył@[ao_pl] arcypodleca.,%o achou que viu um arquivil.,,%o a crezut că %g a văzut un abject.,Игрок %o краем глаза заметил архвиля.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] једног арчвајла.,%o trodde att @[pro_sv] såg en ärkevild.,%o bir iğrençlik gördüğünü sandı.,Арчвайл мелькнув перед очима %o. +%o thought %g saw a Baron of Hell.,OB_STEALTHBARON,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] barona pekel.","%o troede, @[pro_dk] så en helvedesbaron.","%o dachte, einen Höllenbaron zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Βαρώνο της Κόλασης.,"%o pensis, ke @[pro_eo] vidis Baronon de Infero.",%o ha creído ver un Barón del Infierno.,%o creyó haber visto un Barón del Infierno.,%o luuli nähneensä hornanparonin.,%o a cru voir un Baron des enfers.,"%o azt hitte, hogy látott egy pokolbárót.",a %o sembrava di aver visto un Barone Infernale.,%o がバロンを見た気がした。,%o 은(는) 바론 오브 헬을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een baron van de Hel zag.,%o trodde @[pro_dk] så en helvetesbaron,%o kątem oka zauważył@[ao_pl] Barona Piekła.,%o achou que viu um barão do inferno.,,%o a crezut că %g a văzut un Baron al Infernului.,Игрок %o краем глаза заметил барона ада.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] барона пакла.,%o trodde att @[pro_sv] såg en helvetets baron.,%o bir Cehennem Baronu gördüğünü sandı.,Барон Пекла мелькнув перед очима %o. +%o thought %g saw a cacodemon.,OB_STEALTHCACO,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] kakodémona.","%o troede, @[pro_dk] så en cacodemon.","%o dachte, einen Cacodämonen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Κακοδαίμονα.,"%o pensis, ke @[pro_eo] vidis kakodemonon.",%o ha creído ver un Cacodemonio.,%o creyó haber visto un Cacodemonio.,%o luuli nähneensä kakodemonin.,%o a cru voir un Cacodémon.,"%o azt hitte, hogy látott egy kakodémont.",a %o sembrava di aver visto un cacodemone.,%o がカコデーモンを見た気がした。,%o 은(는) 카코데몬을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een cacodemon zag.,%o trodde @[pro_dk] så en kakodemon.,%o kątem oka zauważył@[ao_pl] kakodemona.,%o achou que viu um cacodemônio.,,%o a crezut că %g a văzut un cacodemon.,Игрок %o краем глаза заметил какодемона.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] какодемона.,%o trodde att @[pro_sv] såg en cacodemon.,%o bir caco iblisi gördüğünü sandı.,Какодемон мелькнув перед очима %o. +%o thought %g saw a chaingunner.,OB_STEALTHCHAINGUY,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] kulometčíka.","%o troede, @[pro_dk] så en chaingunner.","%o dachte, einen MG-Schützen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Ζόμπι με ένα πολυβόλο.,"%o pensis, ke @[pro_eo] vidis maŝinpafiliston.",%o ha creído ver un Ametrallador.,%o creyó haber visto un Ametrallador.,%o luuli nähneensä konekiväärimiehen.,%o a cru voir un mitrailleur.,"%o azt hitte, hogy látott egy kommandóst.",a %o sembrava di aver visto uno zombie commando.,%o がチェインガンナーを見た気がした。,%o 은(는) 체인거너를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een zware wapens kerel zag.,%o trodde @[pro_dk] så en maskingeværskyt.,%o kątem oka zauważył@[ao_pl] ciężkozbrojnego zombie.,%o achou que viu um comando possuído.,%o achou que viu um metrelhador.,%o a crezut că %g a văzut un mitralior.,Игрок %o краем глаза заметил пулемётчика.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] митраљезца.,%o trodde att @[pro_sv] såg en tunga vapen kille.,%o bir ağır silah dostu gördüğünü sandı.,Кулеметник мелькнув перед очима %o. +%o thought %g saw a demon.,OB_STEALTHDEMON,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] démona.","%o troede, @[pro_dk] så en dæmon.","%o dachte, einen Dämonen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα δαίμονα.,"%o pensis, ke @[pro_eo] vidis demonon.",%o ha creído ver un Demonio.,%o creyó haber visto un Demonio.,%o luuli nähneensä demonin.,%o a cru voir un démon.,"%o azt hitte, hogy látott egy démont.",a %o sembrava di aver visto un demone.,%o がデーモンを見た気がした。,%o 은(는) 데몬을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een demon zag.,%o trodde @[pro_dk] så en demon.,%o kątem oka zauważył@[ao_pl] demona.,%o achou que viu um demônio.,,%o a crezut că %g a văzut un demon.,Игрок %o краем глаза заметил демона.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] демона.,%o trodde att @[pro_sv] såg en demon.,%o bir iblis gördüğünü sandı.,Демон мелькнув перед очима %o. +%o thought %g saw a Hell Knight.,OB_STEALTHKNIGHT,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] rytíře pekel.","%o troede, @[pro_dk] så en helvedesridder.","%o dachte, einen Höllenritter zu sehen.",@[art_gr] %o νόμιζε οτι είδε έναν Ιππότη της Κόλασης.,"%o pensis, ke @[pro_eo] vidis Inferkavaliron.",%o ha creído ver un Caballero del Infierno.,%o creyó haber visto un Caballero del Infierno.,%o luuli nähneensä hornanritarin.,%o a cru voir un chevalier infernal.,"%o azt hitte, hogy látott egy pokollovagot.",a %o sembrava di aver visto un Cavaliere Infernale.,%o がヘルナイトを見た気がした。,%o 은(는) 헬 나이트를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een hel ridder zag.,%o trodde @[pro_dk] så en helvetesridder.,%o kątem oka zauważył@[ao_pl] Rycerza Piekła.,%o achou que viu um cavaleiro infernal.,%o achou que viu um cavaleiro infernal.,%o a crezut că %g a văzut un Cavaler al Infernului.,Игрок %o краем глаза заметил рыцаря ада.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] витеза пакла.,%o trodde att @[pro_sv] såg en helvetesriddare.,%o bir Cehennem Şövalyesi gördüğünü sandı.,Лицар Пекла мелькнув перед очима %o. +%o thought %g saw an imp.,OB_STEALTHIMP,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] čerta.","%o troede, @[pro_dk] så en imp.","%o dachte, einen Kobold zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Διάβολο.,"%o pensis, ke @[pro_eo] vidis diableton.",%o ha creído ver un Imp.,%o creyó haber visto un Imp.,%o luuli nähneensä pirun.,%o a cru voir un diablotin.,"%o azt hitte, hogy látott egy tűzkoboldot.",a %o sembrava di aver visto un imp.,%o がインプを見た気がした。,%o 은(는) 임프를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een imp zag.,%o trodde @[pro_dk] så en imp.,%o kątem oka zauważył@[ao_pl] diablika.,%o achou que viu um diabrete.,,%o a crezut că %g a văzut un drac.,Игрок %o краем глаза заметил импа.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] врага.,%o trodde att @[pro_sv] såg en imp.,%o bir impus gördüğünü sandı.,Імп мелькнув перед очима %o. +%o thought %g saw a mancubus.,OB_STEALTHFATSO,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] mankuba.","%o troede, @[pro_dk] så en mankubus.","%o dachte, einen Mancubus zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Χοντρό.,"%o pensis, ke @[pro_eo] vidis mankubon.",%o ha creído ver un Mancubus.,%o creyó haber visto un Mancubus.,%o luuli nähneensä mankubuksen.,%o a cru voir un mancube.,"%o azt hitte, hogy látott egy mankubuszt.",a %o sembrava di aver visto un mancubus.,%o がマンキュバスを見た気がした。,%o 은(는) 맨큐버스를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een mancubus zag.,%o trodde @[pro_dk] så en mancubus.,%o kątem oka zauważył@[ao_pl] antropokuba.,%o achou que viu um mancubus.,,%o a crezut că %g a văzut un mancubus.,Игрок %o краем глаза заметил манкубуса.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] манкубуса.,%o trodde att @[pro_sv] såg en mancubus.,%o bir mancubus gördüğünü sandı.,Манкубус мелькнув перед очима %o. +%o thought %g saw a revenant.,OB_STEALTHUNDEAD,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] umrlce.","%o troede, @[pro_dk] så en hævnen.","%o dachte, einen Wiederauferstandenen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Εκδικητή.,"%o pensis, ke @[pro_eo] vidis renaskitulon.",%o ha creído ver un Revenant.,%o creyó haber visto un Revenant.,%o luuli nähneensä henkiinpalanneen.,%o a cru voir un revenant.,"%o azt hitte, hogy látott egy kísértetet.",a %o sembrava di aver visto un revenant.,%o がレバナントを見た気がした。,%o 은(는) 레버넌트를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een wraakzuchtige zag.,%o trodde @[pro_dk] så en gjenganger.,%o kątem oka zauważył@[ao_pl] zjawę.,%o achou que viu um insepulto.,%o achou que viu um renascido.,%o a crezut că %g a văzut un nemort.,Игрок %o краем глаза заметил ревенанта.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] повратника.,%o trodde att @[pro_sv] såg en återfödare.,%o bir iskelet gördüğünü sandı.,Ревенант мелькнув перед очима %o. +%o thought %g saw a sergeant.,OB_STEALTHSHOTGUNGUY,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] seržanta.","%o troede, @[pro_dk] så en sergent.","%o dachte, einen Schützen zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Λοχία.,"%o pensis, ke @[pro_eo] vidis serĝenton.",%o ha creído ver un Sargento.,%o creyó haber visto un Sargento.,%o luuli nähneensä kersantin.,%o a cru voir un type au fusil.,"%o azt hitte, hogy látott egy őrmestert.",a %o sembrava di aver visto un zombie sergente.,%o が軍曹を見た気がした。,%o 은(는) 샷건 가이를 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een jachtgeweer kerel zag.,%o trodde @[pro_dk] så en sersjant.,%o kątem oka zauważył@[ao_pl] zombie-sierżanta.,%o achou que viu um sargento possuído.,%o achou que viu um sargento.,%o a crezut că %g a văzut un sergent.,Игрок %o краем глаза заметил сержанта.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] водника.,%o trodde att @[pro_sv] såg en hagelgevärskille.,%o bir çavuş gördüğünü sandı.,Сержант мелькнув перед очима %o. +%o thought %g saw a zombieman.,OB_STEALTHZOMBIE,,,,"%o si myslel@[ao_cs], že viděl@[ao_cs] zombíka.","%o troede, @[pro_dk] så en zombie.","%o dachte, einen Zombie zu sehen.",@[art_gr] %o νόμιζε οτι είδε ένα Ζόμπι.,"%o pensis, ke @[pro_eo] vidis zombion.",%o ha creído ver un Zombi.,%o creyó haber visto un Zombi.,%o luuli nähneensä zombin.,%o a cru voir un zombie.,"%o azt hitte, hogy látott egy zombit.",a %o sembrava di aver visto uno zombie marine.,%o がゾンビ兵を見た気がした。,%o 은(는) 좀비맨을 봤다고 생각했다.,%o dacht dat @[hij_ze_nl] een zombie zag.,%o trodde @[pro_dk] så en zombiemann.,%o kątem oka zauważył@[ao_pl] zombie.,%o achou que viu um zumbi.,%o achou que viu um zombie.,%o a crezut că %g a văzut un zombi.,Игрок %o краем глаза заметил зомби.,%o мисли@[ao_1_sr] да је виде@[ao_1_sr] зомбија.,%o trodde att @[pro_sv] såg en zombie.,%o bir zombi gördüğünü sandı.,Зомбі мелькнув перед очима %o. +%o was punched by a revenant.,OB_UNDEADHIT,,,,%o byl@[ao_cs] udeřen@[ao_cs] umrlcem.,%o blev slået af en genfødt.,%o wurde von einem Wiederauferstandenen K.O geschlagen.,@[art_gr] %o έφαγε μια μπουνία απο έναν Εκδικητή.,%o estis pugnita de renaskitulo.,A %o l@[ao_esp] ha golpeado un Revenant.,A %o l@[ao_esp] golpeó un Revenant.,%o joutui henkiinpalanneen lyömäksi.,%o s'est pris@[e_fr] une raclée de la part d'un revenant.,%o-t kiütötte egy kísértet.,%o è stato colpito dal pugno di un revenant.,%o はレバナントに殴られた。,%o 은(는) 레버넌트에게 맞아 죽었다.,%o werd geslagen door een wraakzuchtige.,%o ble slått av en gjenganger.,%o został@[ao_pl] uderzon@[adj_pl] przez zjawę.,Um insepulto socou %o.,%o foi socad@[ao_ptb] por um renascido.,%o a primit un pumn de la un nemort.,Игрока %o ударил ревенант.,%o је ударен@[adj_1_sr] од стане повратника.,%o blev slagen av en återfödare.,%o bir iskelet tarafından yumruklandı.,%o бу@[adj_1_ua] забит@[adj_4_ua] ревевантом. +%o was slashed by an imp.,OB_IMPHIT,,,,%o byl@[ao_cs] rozsápán@[ao_cs] čertem.,%o blev skåret ned af en spøgelse.,%o wurde von einem Kobold gekratzt.,@[art_gr] %o κόπηκε απο ενα Διάβολο.,%o estis tranĉvundita de diableto.,A %o l@[ao_esp] ha desgarrado un Imp.,A %o l@[ao_esp] desgarró un Imp.,%o joutui pirun sivaltamaksi.,%o a été lacéré@[e_fr] par un diablotin.,%o-t széttépte egy tűzkobold.,%o è stato squarciato da un imp.,%o はインプに切り裂かれた。,%o 은(는) 임프에게 찢겨 죽었다.,%o werd gesneden door een imp.,%o ble kuttet av en imp.,%o został@[ao_pl] rozcięt@[adj_pl] przez diablika.,Um diabrete dilacerou %o.,,%o a fost zgâriat de un drac.,Игрока %o расцарапал имп.,Играча %o је пресеко враг.,%o blev knivhuggen av en imp.,%o bir imp tarafından kesildi.,%o роздер імп. +%o got too close to a cacodemon.,OB_CACOHIT,,,,%o se dostal@[ao_cs] moc blízko ke kakodémonovi.,%o kom for tæt på en cacodæmon.,%o kam dem Cacodämonen zu nahe.,@[art_gr] %o ήτανε πολυ κοντά σε ένα Κακοδαίμονα.,%o tro proksimiĝis al kakodemono.,%o se ha acercado demasiado a un Cacodemonio.,%o se acercó demasiado a un Cacodemonio.,%o meni liian lähelle kakodemonia.,%o s'est approché@[e_fr] trop près d'un Cacodémon.,%o túl közel ment egy kakodémonhoz.,%o si è avvicinato troppo a un cacodemone.,%o はカコデーモンに近づきすぎた。,%o 은(는) 카코데몬과 가까웠다.,%o kwam te dicht bij een cacodemon.,%o kom for nær en kakodemon.,%o pod@[irreg_1_pl] zbyt blisko do kakodemona.,%o chegou muito perto de um cacodemônio.,,%o s-a apropiat prea mult de un cacodemon.,Игрок %o слишком сблизился с какодемоном.,%o се превише приближи@[ao_1_sr] какодемону.,%o kom för nära en cacodemon.,%o bir caco iblisiyle çok yakınlaştı.,%o опини@[adj_2_ua] надто близько до какодемона. +%o was bit by a demon.,OB_DEMONHIT,,,,%o byl@[ao_cs] rozkousán@[ao_cs] démonem.,%o blev bidt af en dæmon.,%o wurde von einem Dämonen gebissen.,@[art_gr] %o δαγκόθηκε απο ένα Δαίμονα.,%o estis mordita de demono.,A %o l@[ao_esp] ha mordido un Demonio.,A %o l@[ao_esp] mordió un Demonio.,%o joutui demonin puremaksi.,%o a été mordu@[e_fr] par un démon.,%o-t megharapta egy démon.,%o è stato sbranato da un demone.,%o はデーモンに噛まれた。,%o 은(는) 데몬에게 물렸다.,%o werd gebeten door een demon.,%o ble bitt av en demon.,%o wpada w szczęki demona.,Um demônio mordeu %o.,,%o a fost mușcat de un demon.,Игрока %o укусил демон.,Играча %o је ујео демон.,%o blev biten av en demon.,%o bir iblis tarafından ısırıldı.,%o покусав демон. +%o was eaten by a spectre.,OB_SPECTREHIT,,,,%o byl@[ao_cs] sežrán@[ao_cs] přízrakem.,%o blev spist af et imp.,%o wurde von dem Schemen gefressen.,Ένα φάντασμα έφαγε @[pro_gr] %o.,%o estis manĝita de fantomo.,A %o l@[ao_esp] ha devorado un Espectro.,A %o l@[ao_esp] devoró un Espectro.,%o joutui haamun syömäksi.,%o a été dévoré@[e_fr] par un spectre.,%o-t felfalta egy lidérc.,%o è stato divorato da uno spettro.,%o はスペクトルに喰われた。,%o 은(는) 스펙터에게 잡아먹혔다.,%o werd opgegeten door een spook.,%o ble spist av et spøkelse.,%o został@[ao_pl] zjedzon@[adj_pl] przez widmo.,Um espectro devorou %o.,,%o a fost mâncat de un spectru.,Игрока %o сожрал фантом.,Играча %o је појео авет.,%o blev uppäten av ett spöke.,%o bir hayalet tarafından yenildi.,%o зжерла примара. +%o was ripped open by a Baron of Hell.,OB_BARONHIT,,,,%o byl@[ao_cs] rozčtvrcen@[ao_cs] baronem pekel.,%o blev flået op af en helvedesbaron.,%o wurde von dem Höllenbaron aufgerissen.,@[art_gr] %o σχίστηκε απο εναν Βαρώνο της Κόλασης.,%o estis disŝirigita de Barono de Infero.,A %o l@[ao_esp] ha hecho trizas un Barón del Infierno.,A %o l@[ao_esp] hizo trizas un Barón del Infierno.,%o joutui hornanparonin auki repimäksi.,%o a été déchiré@[e_fr] par un Baron des Enfers.,%o-t széttépte egy pokolbáró.,%o è stato scoperchiato da un Barone dell'Inferno.,%o はバロンオブヘルに体を抉じ開けられた。,%o 은(는) 바론 오브 헬에게 뜯겨 죽었다.,%o werd opengereten door een Baron van de hel.,%o ble revet opp av en helvetesbaron.,%o został@[ao_pl] rozerwan@[adj_pl] przez Barona Piekła.,Um Barão do Inferno rasgou %o.,%o foi desventrad@[ao_ptb] por um Barão do Inferno.,%o a fost deschis pe viu de un Baron al Infernului.,Игрока %o разорвал барон ада.,%o је поцеп@[adj_2_sr] од стране барон пакла.,%o slets upp av en helvetesbaron.,%o bir Cehennem Baronu tarafından parçalandı.,Барон Пекла роздер %o. +%o was gutted by a Hell Knight.,OB_KNIGHTHIT,,,,%o byl@[ao_cs] vykuchán@[ao_cs] rytířem pekel.,%o blev udtaget af en helvedesridder.,%o wurde von dem Höllenritter ausgenommen.,@[art_gr] %o ξεκοιλιάστηκε απο έναν Ιππότη της Κόλασης.,%o estis senintestigita de Inferkavaliro.,A %o l@[ao_esp] ha destripado un Caballero del Infierno.,A %o l@[ao_esp] destripó un Caballero del Infierno.,%o joutui hornanritarin perkaamaksi.,%o a été étripé@[e_fr] par un un chevalier infernal.,%o-t kibelezte egy pokollovag.,%o è stato sbudellato da un Cavaliere dell'Inferno.,%o はヘルナイトに内臓を抉られた。,%o 은(는) 헬 나이트에게 도륙당했다.,%o werd gestript door een hel ridder.,%o ble sløyet av en helvetesridder.,%o został@[ao_pl] wypatroszon@[adj_pl] przez Rycerza Piekła.,Um Cavaleiro Infernal estripou %o.,%o foi estripad@[ao_ptb] por um Cavaleiro Infernal.,%o a fost măcelărit de un Cavaler al Infernului.,Игрока %o распотрошил рыцарь ада.,Играча %o је унаказио витез пакла.,%o blev uppsliten av en helvetesriddare.,%o bir Cehennem Şövalyesi tarafından parçalandı.,Лицар Пекла розпотрошив %o. +%o was killed by a zombieman.,OB_ZOMBIE,,,,%o byl@[ao_cs] zabit@[ao_cs] zombíkem.,%o blev dræbt af en zombie.,%o wurde von einem Zombie getötet.,@[art_gr] %o σκοτώθηκε απο ένα Ζόμπι.,%o estis mortigita de zombio.,A %o se l@[ao_esp] ha cargado un Zombi.,A %o l@[ao_esp] mató un Zombi.,%o joutui zombin tappamaksi.,%o a été tué@[e_fr] par un zombie.,%o-t megölte egy zombi.,%o è stato ucciso da uno zombie marine.,%o はゾンビ兵に殺された。,%o 은(는) 좀비맨에게 죽었다.,%o werd gedood door een zombie.,%o ble drept av en zombiemann.,%o został@[ao_pl] zabit@[adj_pl] przez zombie.,Um zumbi matou %o.,%o foi mort@[ao_ptb] por um zombie.,%o a fost omorât de un zombi.,Игрока %o убил зомби.,%o је убијен@[adj_1_sr] од стране зомбија.,%o blev dödad av en zombie.,%o bir zombi tarafından öldürüldü.,%o вбив зомбі. +%o was shot by a sergeant.,OB_SHOTGUY,,,,%o byl@[ao_cs] zastřelen@[ao_cs] seržantem.,%o blev skudt af en sergent.,%o wurde von einem Schützen erschossen.,Ένας Λοχίας πυροβόλησε @[pro_gr] %o.,%o estis pafita de serĝento.,A %o l@[ao_esp] ha fusilado un Sargento.,A %o l@[ao_esp] fusiló un Sargento.,%o joutui kersantin ampumaksi.,%o s'est fait@[e_fr] flinguer par un type au fusil.,%o-t lelőtte egy őrmester.,%o è sato impallinato da uno zombie sergente.,%o はゾンビ軍曹に撃たれた。,%o 은(는) 서전트에게 총을 맞았다.,%o werd neergeschoten door een sergeant.,%o ble skutt av en sersjant.,%o został@[ao_pl] zastrzelon@[adj_pl] przez zombie-sierżanta.,Um sargento possuído atirou em %o.,,%o a fost împușcat de un sergent.,Игрока %o застрелил сержант.,Играча %o је погодио водник.,%o blev skjuten av en hagelgevärskille.,%o bir çavuş tarafından vuruldu.,Сержант застрелив %o. +%o was incinerated by an archvile.,OB_VILE,,,,%o byl@[ao_cs] zpopelněn@[ao_cs] veleběsem.,%o blev brændt af en ærkevile.,%o wurde von einem Scheusal verbrannt.,@[art_gr] %o αποτεφρώθηκε απο ένα Νεκρομάντη.,%o estis cindrigita de ĉef-fiulo.,A %o l@[ao_esp] ha incinerado un Arch-Vile.,A %o l@[ao_esp] incineró un Arch-Vile.,%o joutui arkkihirvityksen kärventämäksi.,%o a été incinéré@[e_fr] par un Arche-Vile.,%o-t megpörkölte egy ősármány.,%o è stato incenerito da un arch-vile.,%o はアーチバイルに焼き尽くされた。,%o 은(는) 아크-바일에 의해 소각되었다.,%o werd verbrand door een aartsvijand.,%o ble brent av en erkefiende.,%o został@[ao_pl] spalon@[adj_pl] przez arcypodleca.,Um arquivil incinerou %o.,,%o a fost incinerat de un abject.,Игрока %o заживо сжёг архвиль.,Играча %o је запалио арчвајл.,%o blev förbränd av en ärkevilde,%o bir iğrençlik tarafından yakıldı.,Арчвайл спалив вщент %o. +%o couldn't evade a revenant's fireball.,OB_UNDEAD,,,,%o se nevyhnul@[ao_cs] umrlčí ohnivé kouli.,%o kunne ikke undvige en ildkugle fra en hævnen.,%o konnte dem Feuerball des Wiederauferstandenen nicht ausweichen.,@[art_gr] %o δέν μπορούσε να αποφείγει τον πύραυλο ενός Εκδικητή.,%o ne povis eviti fajrobulon de renaskitulo.,A %o l@[ao_esp] ha hecho reventar un Revenant.,A %o l@[ao_esp] hizo reventar un Revenant.,%o ei kyennyt väistämään henkiinpalanneen tulipalloa.,%o n'a pas réussi à esquiver un missile de revenant.,%o nem tudta kivédeni egy kísértet tűzgolyóját.,%o non ha potuto evitare il missile di un revenant.,%o はレバナントのファイアボールを回避できなかった。,%o 은(는) 레버넌트의 화염구를 피하지 못했다.,%o kon de vuurbal van een wraakzuchtige niet ontwijken.,%o klarte ikke å unngå en gjengangers ildkule.,%o nie udaje się uniknąć pocisku od zjawy.,%o não conseguiu desviar do míssil do insepulto.,%o não conseguiu desviar do míssil do renascido.,%o n-a putut scăpa de mingea de foc a nemortului.,Игрок %o не успел увернуться от снаряда ревенанта.,%o није мог@[ao_2_sr] да избегне повратникову пламену куглу.,%o kunde inte undvika en återfödds eldklot.,%o bir iskeletin ateş topundan kaçamadı.,Снаряд ревенанта дістав %o. +%o was squashed by a mancubus.,OB_FATSO,,,,%o byl@[ao_cs] rozmačkán@[ao_cs] mankubem.,%o blev knust af en mankubus.,%o wurde von einem Mancubus plattgemacht.,@[art_gr] %o λιόθηκε απο έναν Χοντρό.,%o estis dispremita de mankubo.,A %o l@[ao_esp] ha pulverizado un Mancubus.,A %o l@[ao_esp] pulverizó un Mancubus.,%o joutui mankubuksen liiskaamaksi.,%o s'est fait@[e_fr] aplatir par un Mancube.,%o-t szétlapította egy mankubusz.,%o è stato disintegrato da un mancubus.,%o はマンキュバスに潰された。,%o 은(는) 맨큐버스에게 짓이겨졌다.,%o werd verpletterd door een mancubus.,%o ble knust av en mancubus.,%o został@[ao_pl] zmiażdżon@[adj_pl] przez antropokuba.,Um mancubus esmagou %o.,,%o a fost strivit de un mancubus.,Игрока %o раздавил манкубус.,Играча %o је изгњечио манкубус.,%o blev krossad av en mancubus.,%o bir mancubus tarafından ezildi.,%o розчавлено манкубусом. +%o was perforated by a chaingunner.,OB_CHAINGUY,,,,%o byl@[ao_cs] prostřelen@[ao_cs] kulometčíkem.,%o blev perforeret af en chaingunner.,%o wurde von einem MG-Schützen perforiert.,@[art_gr] %o εκτελέστικε απο ένα Ζόμπι με ένα πολυβόλο.,%o estis truigadita de maŝinpafilisto.,A %o l@[ao_esp] ha perforado un Ametrallador.,A %o l@[ao_esp] perforó un Ametrallador.,%o joutui konekiväärimiehen rei'ittämäksi.,%o a été perforé@[e_fr] par un mitrailleur.,%o-t szitává lőtte egy kommandós.,%o è stato perforato da uno zombie commando.,%o はチェインガンナーに蜂の巣にされた。,%o 은(는) 체인거너에 의해 벌집이 됐다.,%o werd geperforeerd door een zware wapens kerel.,%o ble perforert av en chaingunner.,%o został@[ao_pl] przedziurawion@[adj_pl] przez ciężkozbrojnego zombie.,Um comando possuído perfurou %o.,%o foi perfurad@[ao_ptb] por um metrelhador.,%o a fost perforat de un mitralior.,Игрока %o продырявил пулемётчик.,Играча %o је изрешетао митраљезац.,%o blev perforerad av en tunga vapen kille.,%o bir ağır silah tarafından delindi.,%o отрима@[adj_1_ua] численні отвори від куль кулеметника. +%o was spooked by a lost soul.,OB_SKULL,,,,%o se lekl@[ao_cs] ztracené duše.,%o blev skræmt af en fortabt sjæl.,%o wurde von einer Verlorenen Seele heimgesucht.,Μια Χαμένη Ξυχή φόβησε @[pro_gr] %o.,%o estis timigita de perdita animo.,%o se ha muerto de miedo con un Alma Errante.,%o se murió de miedo con un Alma Errante.,%o joutui kadonneen sielun säikäyttämäksi.,%o s'est fait@[e_fr] surprendre par une âme perdue.,%o-t halálra ijesztette egy kóbor lélek.,%o è stato spaventato a morte da un'Anima Errante.,%o はロストソウルにビビらされた。,%o 은(는) 로스트 소울을 보고 깜짝 놀랐다.,%o werd bang gemaakt door een verloren ziel.,%o ble skremt av en fortapt sjel.,%o został@[ao_pl] przestraszon@[adj_pl] przez zaginioną duszę.,Uma alma penada assustou %o.,%o se assustou com uma alma penada.,%o a fost speriat de un suflet pierdut.,Игрок %o запуган до смерти потерянной душой.,%o је уплашен@[adj_1_sr] од изгубљене душе.,%o blev skrämd av en förlorad själ.,%o kayıp bir ruh tarafından korkutuldu.,Заблудла душа перестрашила %o. +%o was burned by an imp.,OB_IMP,,,,%o byl@[ao_cs] spálen@[ao_cs] čertem.,%o blev brændt af en spøgelse.,%o wurde von einem Kobold verbrannt.,@[art_gr] %o κάικε απο έναν Διάβολο.,%o estis bruligita de diableto.,A %o l@[ao_esp] ha calcinado un Imp.,A %o l@[ao_esp] calcinó un Imp.,%o joutui pirun polttamaksi.,%o brûlé@[e_fr] par un diablotin.,%o-t szénné égette egy tűzkobold.,%o è stato bruciato da un imp.,%o はインプに焼かれた。,%o 은(는) 임프에게 불태워졌다.,%o werd verbrand door een imp.,%o ble brent av en imp.,%o został@[ao_pl] spalon@[adj_pl] przez diablika.,Um diabrete queimou %o.,,%o a fost ars de un demon.,Игрока %o сжёг имп.,%o је изгорен@[adj_1_sr] од стране врага.,%o blev bränd av en imp.,%o bir imp tarafından yakıldı.,%o спалено імпом. +%o was smitten by a cacodemon.,OB_CACO,,,,%o byl@[ao_cs] udeřen@[ao_cs] kakodémonem.,%o blev ramt af en cacodæmon.,%o wurde von einem Cacodämonen gequält.,@[art_gr] %o καίκε απο έναν Κακοδαίμονα.,%o estis venkobatita de kakodemono.,A %o l@[ao_esp] ha cascado un Cacodemonio.,A %o l@[ao_esp] cascó un Cacodemonio.,%o joutui kakodemonin iskemäksi.,%o a été terrassé@[e_fr] par un Cacodémon.,%o-ra lesújtott egy kakodémon.,%o è stato abbattuto da un cacodemone.,%o はカコデーモンに裁きを受けた。,%o 은(는) 카코데몬에게 엄습 당했다.,%o werd geslagen door een cacodemon.,%o ble slått av en kakodemon.,%o został@[ao_pl] porażon@[adj_pl] przez kakodemona.,Um cacodemônio golpeou %o.,,%o a fost lovit de un cacodemon.,Игрока %o поразил какодемон.,Играча %o је ударио какодемон.,%o blev förkrossad av en cacodemon.,%o bir caco iblisi tarafından vuruldu.,%o уражено какодемоном. +%o was bruised by a Baron of Hell.,OB_BARON,,,,%o byl@[ao_cs] pomačkán@[ao_cs] baronem pekel.,%o blev såret af en helvedesbaron.,%o wurde von einem Höllenbaron geröstet.,@[art_gr] %o γρατζουνήθηκε απο ένα Βαρώνο της Κόλασης.,%o estis kontuzita de Barono de Infero.,A %o l@[ao_esp] ha magullado un Barón del Infierno.,A %o l@[ao_esp] magulló un Barón del Infierno.,%o joutui hornanparonin ruhjomaksi.,%o a été démoli@[e_fr] par un Baron des Enfers.,%o-t összezúzta egy pokolbáró.,%o è stato scorticato da un Barone Infernale.,%o はバロンオブヘルに痛めつけられた。,%o 은(는) 바론 오브 헬에게 상처받았다.,%o werd gekneusd door een baron van de hel.,%o ble forslått av en helvetesbaron.,%o został@[ao_pl] stłuczon@[adj_pl] Barona Piekła.,Um Barão do Inferno feriu %o.,,%o a fost contuzionat de un Baron al Infernului.,Игрок %o зашиблен бароном ада.,%o је мод@[adj_3_sr] због барона пакла.,%o blev skadad av en helvetesbaron.,%o bir Cehennem Baronu tarafından yaralandı.,%o потовчено бароном Пекла. +%o was splayed by a Hell Knight.,OB_KNIGHT,,,,%o byl@[ao_cs] rozpůlen@[ao_cs] rytířem pekel.,%o blev splejset af en helvedesridder.,%o wurde von einem Höllenritter gebraten.,@[art_gr] %o απλώθηκε απο έναν Ιππότη της Κόλασης,%o estis bisekcita de Inferkavaliro.,A %o l@[ao_esp] ha partido en dos un Caballero del Infierno.,A %o l@[ao_esp] partió en dos un Caballero del Infierno.,%o joutui hornanritarin repimäksi.,%o a été éclaté@[e_fr] par un chevalier infernal.,%o-t kilapította egy pokollovag.,%o è stato squartato da un Cavaliere Infernale.,%o はヘルナイトにバラ撒かれた。,%o 은(는) 헬 나이트에게 갈라졌다.,%o werd gespierd door een hel ridder.,Jeg ble sprettet opp av en helvetesridder.,%o został@[ao_pl] rozcapierzon@[adj_pl] przez Rycerza Piekła.,Um Cavaleiro Infernal espalmou %o.,%o foi espalmad@[ao_ptb] por um Cavaleiro Infernal.,%o a fost scrântit de un Cavaler al Infernului.,Игрока %o распластал рыцарь ада.,%o је раширен@[adj_1_sr] због витеза пакла.,%o blev spretad av en helvetesriddare.,%o bir Cehennem Şövalyesi tarafından yere serildi.,Лицар Пекла розкатав %o. +%o stood in awe of the spider demon.,OB_SPIDER,,,,%o zůstal@[ao_cs] stát v úžasu před pavoučím démonem.,%o stod i ærefrygt for edderkoppedæmonen.,%o stand in Ehrfurcht vor dem Spinnendämon.,@[art_gr] %o στάθηκε με δέος μπροστά στόν αραχνοδαίμονα.,%o staris mirigita antaŭ la aranedemono.,%o se ha arrodillado ante la Mente-Maestra Arácnida.,%o se arrodilló ante la Mente-Maestra Arácnida.,%o kunnioitti syvästi hämähäkkidemonia,%o est resté pris@[e_fr] d'admiration devant le Démon Arachnéen.,%o halálra ijedt a Pókelme.,%o è stato soggiogato dal Ragno demoniaco.,%o はスパイダーデーモンに恐れをなした。,%o 은(는) 거미악마의 무자비함을 느꼈다.,%o stond in ontzag voor de spindemon.,%o sto i ærefrykt for edderkoppdemonen.,%o podziwiał@[ao_pl] pajęczego mistrza.,%o ajoelhou-se em frente à Aranha-Mestra.,,%o a stat înfricoșat în fața păianjenului maestru.,Игрок %o стоял в восторге перед пауком-предводителем.,%o се смрзну@[ao_1_sr] у очарању паук-руководилаца.,%o stod i vördnad inför spindeldemonen.,%o örümcek iblisin karşısında huşu içinde durdu.,%o бу@[adj_1_ua] захоплен@[ao_ua] могутністю павука-воєводи. +%o let an arachnotron get %h.,OB_BABY,,,,%o se nechal@[ao_cs] dostat arachnotronem.,%o blev sprængt af en arachnotron.,%o ließ sich von einem Arachnotron erledigen.,@[art_gr] %o άφησε ένα Αράχνοτρον να @[pro_gr] σκοτώσει.,%o lasis elektraraneon venki @[pro_eo]n.,A %o l@[ao_esp] ha alcanzado un Aracnotrón.,A %o l@[ao_esp] alcanzó un Aracnotrón.,%o antoi anaktrotronin saada hänet.,%o a laissé un arachnotron l'avoir@[e_fr].,"%o hagyta, hogy elkapja egy póktron.",%o ha permesso che un arachnotron l'uccidesse.,%o が アラクノトロンに討ち取られた。,%o 은(는) 아라크노트론이 %o를(을) 죽이도록 놔두었다.,%o werd gedood door een arachnotron,%o ble sprengt av et arachnotron.,%o pozwolił@[ao_pl] arachnotronowi się do siebie dobrać.,Uma arachnotron pegou %o.,%o foi apanhad@[ao_ptb] por uma arachnotron.,%o s-a lăsat prins de un aracnotron.,Игрок %o дал себя на откуп арахнотрону.,%o је допусти@[ao_1_sr] да паукотрон дође до %h.,%o lät en arachnotron ta @[ref_sv].,%o bir araknotronun onu yakalamasına izin verdi.,%o да@[adj_1_ua] арахнотрону себе вбити. +%o was splattered by a cyberdemon.,OB_CYBORG,,,,%o byl@[ao_cs] rozplesknut@[ao_cs] na kaši kyberdémonem.,%o blev splattet af en cyberdæmon.,%o wurde von einem Cyberdämon zerfetzt.,@[art_gr] %o έσκασε απο ένα Cyber-δαίμονα.,%o estis disŝprucigita de ciberdemono.,A %o l@[ao_esp] ha hecho pedazos un Ciberdemonio.,A %o l@[ao_esp] hizo pedazos un Ciberdemonio.,%o joutui kyberdemonin yltympäri roiskimaksi.,%o a été pulvérisé@[e_fr] par un Cyberdémon.,%o-t cafatokra tépték a kiberdémon rakétái.,%o è stato spiaccicato da un Cyberdemone.,%o はサイバーデーモンにバラバラにされた。,%o 은(는) 사이버데몬에 의해 산산조각이 났다.,%o werd gespetterd door een cyberdemon.,%o ble sprutet av en kyberdemon.,%o został@[ao_pl] rozbryzgan@[adj_pl] przez cyberdemona.,Um Ciberdemônio arrebentou %o.,,%o a fost împroșcat de ciberdemon.,Игрока %o размазал кибердемон.,%o је спљоштен@[adj_1_sr] од стране сајбердемона,%o blev sönderslagen av en cyberdemon.,%o bir siber iblis tarafından parçalandı.,Кібердемон перетворив %o в хмарину крові. +%o met a Nazi.,OB_WOLFSS,,,,%o potkal@[ao_cs] nácka.,%o mødte en nazist.,%o traf einen Nazi.,@[art_gr] %o χνώρισε ένα Ναζιστή.,%o renkontis Nazion.,%o se ha topado con un Nazi.,%o se topó con un Nazi.,%o tapasi natsin.,%o a rencontré un Nazi.,%o találkozott egy nácival.,%o ha incontrato un Nazista.,%o はナチ兵と遭遇した。,%o 은(는) 나치를 만났다.,%o ontmoette een nazi.,Jeg møtte en nazist.,%o spotkał@[ao_pl] nazistę.,%o encontrou um Nazista.,%o encontrou um Nazi.,%o a întâlnit un Nazist.,Игрок %o встретил нациста.,%o је упозна@[ao_1_sr] нацисту.,%o mötte en nazist.,%o bir Nazi ile karşılaştı.,%o зустрі@[adj_1_ua] нациста. +%o was mauled by a dog.,OB_DOG,,,,%o byl@[ao_cs] roztrhán@[ao_cs] psem.,%o blev mast af en hund.,%o wurde von einem Hund zerrissen.,@[art_gr] %o φαγόθικε απο ένα σκύλο.,%o estis atakita de hundo.,A %o l@[ao_esp] ha despedazado un Perro.,A %o l@[ao_esp] despedazó un Perro.,%o joutui koiran raatelemaksi.,%o s'est fait mordre par un chien.,%o-t szétmarcangolta egy kutya.,%o è stato sbranato da un cane.,%o は犬に引き裂かれた。,%o 은(는) 개한테 으스러졌다.,%o werd verminkt door een hond.,%o ble maltraktert av en hund.,%o został@[ao_pl] poturbowan@[adj_pl] przez psa.,Um cachorro mutilou %o.,%o foi mutilad@[ao_ptb] por um cão.,%o a fost sfâșiat de un câine.,Игрока %o разорвала собака.,Играча %o је удавио пас.,%o blev misshandlad av en hund.,%o bir köpek tarafından parçalandı.,%o загризла собака. +%o chewed on %k's fist.,OB_MPFIST,,,,%o si pochutnal@[ao_cs] na pěsti hráče %k.,%o tyggede på %ks knytnæve.,%o kaute auf %ks Faust herum.,@[art_gr] %o μάσησε τη γροθία του/της %k.,%o maĉis la pugnon de %k.,%o se ha comido el puño de %k.,%o se comió el puño de %k.,%k rusikoi %o paran.,%o a bouffé le poing de %k.,%o megkóstolta %k ökleit.,%o si è schiantato contro il pugno di %k.,%o は %k の拳を顔面に受けた。,%o 은(는) %k 의 주먹을 물었다.,%o gekauwd op %k's vuist.,%o tygget på %ks knyttneve.,%o przygryza pięść %k.,%k espancou %o até a morte.,,%o a mestecat pumnul lui %k.,Игрок %o отведал кулака игрока %k.,Играча %o је сажвакао песницу играча %k.,%o tuggade på %ks knytnäve.,"%o, %k tarafından öldürüldü.",%o відчу@[adj_1_ua] кулак %k. +%o was mowed over by %k's chainsaw.,OB_MPCHAINSAW,,,,%o byl@[ao_cs] zkácen@[ao_cs] motorovkou hráče %k.,%o blev slået ned af %ks motorsav.,%o wurde von %ks Kettensäge zerteilt.,@[art_gr] %o κόπηκε απο το αλλησοπρίονο του/της %k.,%o estis buĉita de la ĉensegilo de %k.,Ha habido matanza de %o con la motosierra de %k.,Hubo mascare de %o con la motosierra de %k.,%k katkoi %o paran.,%o a été tondu@[e_fr] par la tronconneuse de %k.,%o-t kettészelte %k láncfűrésze.,%o è stato falciato dalla motosega di %k.,%o は %k のチェーンソーで刈り取られた。,%o 은(는) %k 의 전기톱에 갈렸다.,%o werd gemaaid met %k's kettingzaag.,%o ble klippet over av %ks motorsag.,%o został@[ao_pl] skoszon@[adj_pl] przez piłę łańcuchową %k.,%k fez picadinho de %o com sua motoserra.,,%o a fost tăiat de drujba lui %k.,Игрока %o разрезал бензопилой игрок %k.,%o је исечен@[adj_1_sr] моторном тестером играча %k.,%o blev överkörd av %ks motorsåg.,"%o, %k tarafından biçildi",%k розпили@[adj_1_ua] %o бензопилою. +%o was tickled by %k's pea shooter.,OB_MPPISTOL,,,,%o byl@[ao_cs] polechtán@[ao_cs] pistolkou hráče %k.,%o blev kildet af %ks ærteskytte.,%o wurde von %ks Erbsenpistole gekitzelt.,@[art_gr] %o γαργαλίθηκε απο το οπλάκι του/της %k.,%o estis tiklita de la pistolo de %k.,A %o le ha hecho cosquillas la pistola de %k.,A %o le hizo cosquillas la pistola de %k.,%o kutitti %o parkaa hernepyssyllään.,%o a été châtouillé@[e_fr] par le pistolet de %k.,%o meg lett csiklandozva %k játékpisztolyával.,%o è stato sforacchiato dalla pistola di %k'.,%o は %k の豆鉄砲でくすぐられた。,%o 은(는) %k 의 권총에 간지럼을 탔다.,%o werd gekieteld door %k's erwtenschutter.,%o ble kilt av %ks ertebøsse.,%o został@[ao_pl] połaskotan@[adj_pl] przez spluwę %k.,%k fez cócegas em %o com sua pistolinha.,,%o a fost gâdilat de pistolașul lui %k.,Игрока %o защекочен вусмерть из горохострела игрока %k.,%o је заголицан@[adj_1_sr] пиштољем играча %k.,%o blev kittlad av %ks ärtskytt.,"%o, %k tarafından gıdıklandı",%o бу@[adj_1_ua] заколупан@[ao_ua] пістолетом %k. +%o chewed on %k's boomstick.,OB_MPSHOTGUN,,,,%o si pochutnal@[ao_cs] na brokádě hráče %k.,%o tyggede på %ks bommestok.,%o wurde Opfer von %ks Schrotflinte.,@[art_gr] %o έφαγε το ντουφέκι του/της %k.,%o maĉis la kartoĉan fusilon de %k.,A %o l@[ao_esp] ha agujereado la escopeta de %k.,A %o l@[ao_esp] agujereó la escopeta de %k.,%k jauhoi %o paran tussarillaan.,%o a s'est mangé@[e_fr] de la chevrotine de la part de %k.,%o megízlelte %k villámbotját.,%o si è trovato davanti il fucile di %k.,%o は %k のブームスティックを顔面に受けた。,%o 은(는) %k 의 붐스틱에 꽂혔다.,%o gekauwd op %k's boomstick.,%o tygget på %ks boomstick.,%o przygryza pukawkę %k.,%k meteu chumbo em %o com sua espingarda.,,%o a mestecat pușca lui %k.,Игрока %o накормил дробью игрок %k.,%o је сажвака@[ao_1_sr] на пумпарицу играча %k.,%o tuggade på %ks bomstock.,"%o, %k tarafından patlatıldı",%k насипа@[adj_1_ua] свинцевого гороху %o. +%o was splattered by %k's super shotgun.,OB_MPSSHOTGUN,,,,%o byl@[ao_cs] rozplesknut@[ao_cs] na kaši superbrokovnicí hráče %k.,%o blev sprøjtet af %ks super haglgevær.,%o wurde von %ks Super-Schrotflinte zerfetzt.,@[art_gr] %o διαλύθηκε απο το διπλό ντουφέκι του/της %k,%o estis disŝprucigita de la dutuba fusilo de %k.,A %o l@[ao_esp] reventado la superescopeta de %k.,A %o l@[ao_esp] reventó la superescopeta de %k.,%k roiski %o paran yltympäriinsä superhaulikollaan.,%o s'est fait@[e_fr] gicler par le fusil de chasse de %k.,%o-t cafatokra tépte %k szupersörétese.,%o è stato smembrato dalla doppietta di %k.,%o は %k のスーパーショットガンでバラバラにされた。,%o 은(는) %k 의 슈퍼 샷건에 의해 터졌다.,%o werd gespat door %k's super jachtgeweer.,%o ble skutt med %ks super-haglgevær.,%o został@[ao_pl] rozpryskan@[adj_pl] przez super strzelbę %k.,%k estraçalhou %o com sua espingarda de cano duplo.,,%o a fost împroșcat de super pușca lui %k.,Игрока %o размазал из супердробовика игрок %k.,Играча %o је спљоштила двоцевка играча %k.,%o blev besprutat av %ks super-hagelgevär.,"%o, %k tarafından sıçratıldı",%k розмаза@[adj_1_ua] з двустволки %o. +%o was mowed down by %k's chaingun.,OB_MPCHAINGUN,,,,%o byl@[ao_cs] prostřílen@[ao_cs] kulometem hráče %k.,%o blev mejet ned af %ks maskingevær.,%o wurde von %ks Maschinengewehr niedergemäht.,@[art_gr] %o κοματίαστηκε απο το πολυβόλο του/της %k.,%o estis kuglo-plenigita de la maŝinpafilo de %k.,A %o l@[ao_esp] ha dejado hecho colador la ametralladora de %k.,A %o l@[ao_esp] dejó hecho colador la ametralladora de %k.,%k niitti %o paran konekiväärillään.,%o a été ventilé@[e_fr] par la mitrailleuse de %k.,%k gépágyúval szétszaggatta %o testét.,%o è stato falciato dal mitragliatore di %k.,%o は %k のチェーンガンで蜂の巣にされた。,%o 은(는) %k 의 체인건에 의해 으깨졌다.,%o werd gemaaid met %k's machinegeweer.,%o ble meiet ned av %ks maskinpistol.,%o został@[ao_pl] skoszon@[adj_pl] przez karabin maszynowy %k.,%k massacrou %o com sua metralhadora.,,%o a fost secerat de mitraliera rotativă a lui %k.,Игрок %o скошен из пулемёта игрока %k.,%o је покоси@[ao_1_sr] митраљез играча %k.,%o blev nedklippt av %ks kedjepistol.,"%o, %k tarafından biçildi",%k скоси@[adj_1_ua] кулеметом %o. +%o rode %k's rocket.,OB_MPROCKET,,,,%o se projel@[ao_cs] na raketě hráče %k.,%o red på %ks raket.,%o ritt auf %ks Rakete.,@[art_gr] %o καβάλησε τον πύραυλο του/της %k.,%o rajdis la raketon de %k.,%o ha montado el misil de %k.,%o montó el misil de %k.,%o ratsasti pelaajan %k raketilla.,%o a chevauché la roquette de %k.,%o meglovagolta %k rakétáját.,%o ha cavalcato il razzo di %k.,%o は %k のロケットに乗ってしまった。,%o 은(는) %k 의 로켓을 탔다.,%o reed op %k's raket.,%o red på %ks rakett.,%o ujeżdżał@[ao_pl] rakietę %k.,%o não viu o foguete de %k.,%o não viu o míssil de %k.,%o a călărit racheta lui %k.,Игрок %o прокатился на ракете игрока %k.,%o је ујаха@[ao_1_sr] ракету играча %k.,%o åkte på %ks raket.,"%o, %k tarafından sıçratıldı",%o проїха@[adj_2_ua] на ракеті %k. +%o almost dodged %k's rocket.,OB_MPR_SPLASH,,,,%o se skoro vyhnul@[ao_cs] raketě hráče %k.,%o undgik næsten %ks raket.,"%o schaffte es fast, %ks Rakete auszuweichen.",@[art_gr] %o σχεδόν απόφηγε τον πύραυλο του/της %k.,%o preskaŭ evitis la raketon de %k.,%o casi esquiva el misil de %k.,,%o melkein väisti pelaajan %k raketin.,%o a presque esquivé la roquette de %k.,%o majdnem kitért %k rakétája elől.,%o aveva quasi schivato il razzo di %k.,%o は %k のロケットをあと少しで避けられそうだった。,%o 은(는) %k 의 로켓 폭발을 거의 피했다.,%o ontweek bijna %k's raket.,%o unngikk nesten %ks rakett.,%o prawie unika rakiety %k.,%o quase escapou do foguete de %k.,%o quase escapou do míssil de %k.,%o aproape a evitat racheta lui %k.,Игрок %o почти увернулся от ракеты %k.,%o је за длаку избега@[ao_1_sr] ракету играча %k.,%o undvek nästan %ks raket.,"%o, %k tarafından sıçratıldı",%o майже укникну@[adj_1_ua] ракети %k. +%o was melted by %k's plasma gun.,OB_MPPLASMARIFLE,,,,%o se roztekl@[ao_cs] plazmapuškou hráče %k.,%o blev smeltet af %ks plasma riffel.,%o wurde von %ks Plasmagewehr geschmolzen.,@[art_gr] %o λίοθηκε απο το πλάσμα όπλο του/της %k.,%o estis fandigita de la plasmo-pafilo de %k.,A %o l@[ao_esp] ha derretido el fusil de plasma de %k.,A %o l@[ao_esp] derritió el fusil de plasma de %k.,%k sulatti %o paran plasmapyssyllään.,%o a été réduit@[e_fr] en bouillie par le fusil a plasma de %k.,%k plazmafegyverével megolvaszotta %o testét.,%o è stato fuso dal fucile al plasma di %k.,%o は %k のプラズマガンに溶かされた。,%o 은(는) %k 의 플라즈마 건에 의해 융해되었다.,%o was gesmolten door %k's plasmageweer.,%o ble smeltet av %ks plasmakanon.,%o został@[ao_pl] stopion@[adj_pl] przez pistolet plasmowy %k.,%k torrou %o com seu fuzil de plasma.,%o foi torrad@[ao_ptb] pela pistola de plasma de %k.,%o a fost topit de pușca cu plasmă a lui %k.,Игрока %o расплавил из плазмомёта игрок %k.,%o је отопљен@[adj_1_sr] плазма оружјем играча %k.,%o smältes av %ks plasmagevär.,"%o, %k tarafından eritildi",%k розплавив з плазмагана %o. +%o was splintered by %k's BFG.,OB_MPBFG_BOOM,,,,%o byl@[ao_cs] rozštěpen@[ao_cs] BFGčkem hráče %k.,%o blev splintret af %ks BFG.,%o wurde von %ks BFG in Stücke gerissen.,@[art_gr] %o κοματιάστηκε απο το BFG του/της %k.,%o estis splitigita de la BFG de %k.,A %o l@[ao_esp] ha astillado la BFG de %k.,A %o l@[ao_esp] astilló la BFG de %k.,%k pirstoi %o paran BFG:llään.,%o a été oblitéré@[e_fr] par le BFG de %k.,%o teste atomjaira szakadt %k BFG-jétől.,%o è stato sminuzzato dal BFG di %k.,%o は %k のBFGで木っ端微塵にされた。,%o 은(는) %k 의 BFG덕에 산산조각 났다.,%o was versplinterd door %k's BFG.,%o ble splintret av %ks BFG.,%o został@[ao_pl] rozpryskan@[adj_pl] przez BFG %k.,%k vaporizou %o com sua BFG.,,%o a fost despicat de către BFG-ul lui %k.,Игрока %o порвал на осколки выстрел из BFG игрока %k.,%o је расцепан@[adj_1_sr] ВЈП играча %k.,%o splittrades av %ks BFG.,"%o, %k tarafından parçalandı",%o розірвало снарядом БФГ %k. +%o couldn't hide from %k's BFG.,OB_MPBFG_SPLASH,,,,%o se nemohl@[ao_cs] ukrýt před BFGčkem hráče %k.,%o kunne ikke gemme sig for %ks BFG.,%o konnte sich nicht vor %ks BFG verstecken.,@[art_gr] %o δέν μπόρεσε να κρυφτέι απο το BFG του/της %k.,%o ne povis kaŝi sin de la BFG de %k.,%o no ha conseguido esconderse de la BFG de %k.,%o no logró esconderse de la BFG de %k.,%o ei kyennyt piiloutumaan pelaajan %k BFG:ltä.,%o n a pas pu se couvrir du BFG de %k.,%o nem tudott elmenekülni %k BFG-je elől.,%o non poteva nascondersi dal BFG di %k.,%o は %k のBFGから隠れることはできなかった。,%o 은(는) %k 의 BFG의 일격으로부터 피할 수 없었다.,%o kon zich niet verbergen voor %k's BFG.,%o kunne ikke gjemme seg for %ks BFG.,%o nie może się schować przed BFG %k.,%o não conseguiu se esconder da BFG de %k,,%o nu s-a putut ascunde de BFG-ul lui %k.,Игрок %o не успел спрятаться от BFG игрока %k.,%o се није мог@[ao_2_sr] сакрити од ВЈП играча %k.,%o kunde inte gömma sig för %ks BFG.,"%o, %k tarafından parçalandı",%o не встиг@[adj_3_ua] сховатись від БФГ %k. +%o was railed by %k.,OB_RAILGUN,,,,%o byl@[ao_cs] napíchnut@[ao_cs] hráčem %k.,%o blev skudt af %k.,%o stand in %ks Schusslinie.,@[art_gr] %o καρφόθηκε απο τον/την %k.,%o estis traborita de la elektropafilo de %k.,A %o l@[ao_esp] ha agujereado el cañón de riel de %k.,A %o l@[ao_esp] agujereó el cañón de riel de %k.,%o lävisti %o paran.,%o a été aligné@[e_fr] par %k.,%o beleállt %k lézerébe.,%o è stato bucherellato dal railgun di %k.,%o は %k のレールガンで死亡した。,%o 은(는) %k 의 레일건에 관통당했다.,%o werd gespaakt door %k.,%o ble skutt av %k.,%o stał@[ao_pl] na linii ognia %k.,%k acertou %o com seu canhão elétrico.,,%o a fost ocărit de %k.,Игрока %o пробил насквозь игрок %k.,%o је убијен@[adj_1_sr] од играча %k.,%o blev fördärvad av %k.,%o %k tarafından kovuldu.,%k прониза@[adj_1_ua] %o наскрізь. +%o was burned by %k's BFG.,OB_MPBFG_MBF,,,,%o shořel@[ao_cs] BFGčkem hráče %k.,%o blev brændt af %ks BFG.,%o wurde von %ks BFG verbrannt.,@[art_gr] %o κάικε απο το BFG του/της %k.,%o estis bruligita de la BFG de %k.,A %o l@[ao_esp] ha calcinado la BFG de %k.,A %o l@[ao_esp] calcinó la BFG de %k.,%k korvensi %o paran BFG:llään.,%o a été irradié@[e_fr] par le BFG de %k.,%k hamuvá égette %o testét BFG-vel.,%o è stato bruciato dal BFG di %k.,%o は %k のBFGで焼き殺された。,%o 은(는) %k 의 BFG에 의해 타올랐다.,%o werd verbrand door %k's BFG.,%o ble brent av %ks BFG.,%o został@[ao_pl] spalon@[adj_pl] przez BFG %k.,%k cozinhou %o com sua BFG.,,%o a fost ars de BFG-ul lui %k.,Игрока %o сжёг из BFG игрок %k.,%o је изгоре@[ao_1_sr] од ВЈП играча %k.,%o blev bränd av %ks BFG.,%o %k tarafından yakıldı,%o спалило БФГ %k. +,,Heretic,,,,,,,,,,,,,,,,,,,,,,,,,, +,,Pickup ,,,,,,,,,,,,,,,,,,,,,,,,,, +Blue Key,TXT_GOTBLUEKEY,,,,Modrý klíč,Blå nøgle,Blauer Schlüssel,Μπλέ Κλειδί,Blua Ŝlosilo,Llave Azul,,Sininen avain,Clé Bleue,Kék kulcs,Chiave blu,青の鍵,청색 열쇠,Blauwe sleutel,Blå nøkkel,Niebieski klucz,Chave Azul,,Cheie Albastră,Синий ключ,Плави кључ,Blå nyckel,Mavi Anahtar,Синій ключ +Yellow Key,TXT_GOTYELLOWKEY,,,,Žlutý klíč,Gul nøgle,Gelber Schlüssel,Κύτρινο Κλειδί,Flava Ŝlosilo,Llave Amarilla,,Keltainen avain,Clé Jaune,Sárga kulcs,Chiave gialla,黄の鍵,황색 열쇠,Gele sleutel,Gul nøkkel,Żółty klucz,Chave Amarela,,Cheie Galbenă,Жёлтый ключ,Жути кључ,Gul nyckel,Sarı Anahtar,Жовтий ключ +Green Key,TXT_GOTGREENKEY,,,,Zelený klíč,Grøn nøgle,Grüner Schlüssel,Πράσινο Κλειδί,Verda Ŝlosilo,Llave Verde,,Vihreä avain,Clé Verte,Zöld kulcs,Chiave verde,緑の鍵,녹색 열쇠,Groene sleutel,Grønn nøkkel,Zielony klucz,Chave Verde,,Cheie Verde,Зелёный ключ,Зелени кључ,Grön nyckel,Yeşil Anahtar,Зелений ключ +Quartz Flask,TXT_ARTIHEALTH,,,,Blyštivá baňka,Kvartsflaske,Quarzflasche,Φλάσκα Χαλαζίας,Kvarca Flakono,Frasco de Cuarzo,,Kvartsipullo,Flasque en Quartz,Kvarc flaska,Ampolla di quarzo,石英フラスコ,석영 플라스크,Kwartskolf,Kvartskolbe,Kwarcowa Butelka,Frasco de Quartzo,,Flacon de Quartz,Кварцевый флакон,Кварцна боца,Kvartsflaska,Kuvars Şişesi,Кварцова пляшечка +Wings of Wrath,TXT_ARTIFLY,,,,Křídla hněvu,Vredens vinger,Flügel des Zorns,Φτερά της Οργής,Flugiloj de Kolero,Alas de Ira,,Kiihtymyksen siivet,Ailes du Courroux,A Harag Szárnyai,Ali iraconde,レイスの翼,분노의 날개,Vleugels der Toorn,Vredens vinger,Skrzydła Gniewu,Asas da Ira,,Aripile Furiei,Крылья гнева,Крила гнева,Vridsvingar,Gazap Kanatları,Крила гніву +Ring of Invincibility,TXT_ARTIINVULNERABILITY,,,,Prsten nesmrtelnosti,Ring af uovervindelighed,Ring der Unverwundbarkeit,Δαχτυλίδι της Αθανασίας,Ringo de Nevenkebleco,Anillo de Invencibilidad,,Näkymättömyyden sormus,Anneau d'Invincibilité,A Sérthetetlenség Gyűrűje,Anello dell'invincibilità,不死の指輪,불멸의 반지,Ring van Onoverwinnelijkheid,Uovervinnelighetens ring,Pierścień Niewrażliwości,Anel da Invencibilidade,,Inelul Invincibilității,Кольцо неуязвимости,Прстен непобедивости,Ring av oövervinnlighet,Yenilmezlik Yüzüğü,Кільце Непереможності +Tome of Power,TXT_ARTITOMEOFPOWER,,,,Kniha moci,Bog om magt,Buch der Macht,Τομός της Δύναμης,Librego de Forto,Tomo de Poder,,Väkevyyden kirja,Livre du Pouvoir,Az Erő Kódexe,Tomo del potere,力の術書,힘의 서,Boek van de Macht,Maktens bok,Tom Mocy,Livro do Poder,Livro do Poder,Cartea Puterii,Том могущества,Том моћи,Maktens tome,Güç Kitabı,Том сили +Shadowsphere,TXT_ARTIINVISIBILITY,,,,Šerosféra,Skyggesfære,Schattensphäre,Σκιόσφαιρα,Ombrosfero,Esfera de Sombra,,Varjokehrä,Sphère des Ombres,Árnygömb,Sfera dell'ombra,闇の球体,그림자 구체,Schaduwbol,Skyggesfære,Sfera Cieni,Esfera das Sombras,,Sfera Umbrei,Теневая сфера,Сфера сенки,Skuggsfär,Gölge Küre,Сфера тіні +Morph Ovum,TXT_ARTIEGG,,,,Měnivejce,,Transformations-Ei,Μετασχηματίζοντικο Ωάριο,Ovo de Transformado,Huevo de Transformación,,Muodonmuutoksen muna,Ovule de Métamorphose,Alakváltó tojás,Uovo della metamorfosi,変貌の卵子,변신 알,Morfose-Ei,,Jajko Morfujące,Ovo da Metamorfose,,Oul Metamorfozei,Яйцо превращения,Преображавајуће јајашце,,Dönüşümlü Yumurta,Яйце трансформації +Mystic Urn,TXT_ARTISUPERHEALTH,,,,Tajemná urna,Mystisk urne,Mystische Urne,Μυστικό Δοχείο,Mistika Urno,Urna Mística,,Mystinen uurna,Urne Mystique,Misztikus urna,Urna mistica,神秘の骨壷,신비한 항아리,Mystieke Urn,Mystisk urne,Mistyczna Urna,Urna Mística,,Urnă Mistică,Мистическая урна,Мистериозна урна,Mystisk urna,Mistik Urn,Містична урна +Torch,TXT_ARTITORCH,,,,Pochodeň,Fakkel,Fackel,Πυρσός,Torĉo,Antorcha,,Soihtu,Torche,Fáklya,Torcia,松明,횃불,Fakkel,Fakkel,Pochodnia,Tocha,,Torță,Факел,Бакља,Fackel,Meşale,Смолоскип +Time Bomb of the Ancients,TXT_ARTIFIREBOMB,,,,Časovaná bomba starověku,De ældres tidsbombe,Zeitbombe der Alten,Χρονοβόμβα τον Αρχαίων,Tempobombo de la Antikvuloj,Bomba de tiempo de los Ancestros,,Vanhain aikapommi,Bombe a Retardement des Anciens,Az Ősök Időbombája,Bomba a tempo degli antichi,古代の時限爆薬,고대의 시한폭탄,Tijdbom der Tijden,De eldgamles tidsinnstilte bombe,Starożytna Bomba Czasu,Bomba-relógio dos Anciãos,,Bomba cu Ceas a Anticilor,Часовая бомба древних,Временска бомба древних,De gamlas tidsbomb,Kadimlerin Saatli Bombası,Часова бомба древніх +Chaos Device,TXT_ARTITELEPORT,,,,Zmatkostroj,Chaos-enhed,Chaosgerät,Συσκευή του Χάος,Ĥaos-Aparato,Dispositivo del Caos,,Kaaoskoje,Outil du Chaos,Káoszszerkezet,"Dispositivo del Caos +",カオスデバイス,혼돈의 장치,Chaosapparaat,Kaosinnretning,Urządzenie Chaosu,Dispositivo do Caos,,Dispozitiv al Haosolui,Механизм хаоса,Уређај хаоса,Chaos-enhet,Kaos Cihazı,Пристрій Хаосу +Crystal Vial,TXT_ITEMHEALTH,,,,Křišťálový flakón,Krystalflaske,Kristallfläschchen,Κρυσταλλικό Φιάλιδο,Fiolo de Kristalo,Tubo de Cristal,,Kristallipullo,Fiole de Cristal,Kristályampulla,Fiala di cristallo,水晶瓶,수정 약병,Kristallen Flesje,Krystallflaske,Kryształowa Fiolka,Ampola de Cristal,,Fiolă de Cristal,Кристальный флакон,Кристална бочица,Kristallflaska,Kristal Şişe,Кришталевий флакон +Bag of Holding,TXT_ITEMBAGOFHOLDING,,,,Tlumok,Pose med opbevaringspose,Rucksack,Τσάντα Κρατησης,Taŝo de Tenado,Bolso sin Fondo,,Säilön laukku,Sac sans Fond,A Birtoklás Batyuja,Borsa Portaoggetti,持ち物袋,보관용 가방,Rugzak,Posen som holder,Plecak,Bolsa de Utensílios,,Poșetă,Носильный кошель,Торба носивости,Väska med behållare,Holding Çantası,Запасний підсумок +Silver Shield,TXT_ITEMSHIELD1,,,,Stříbrný štít,Sølvskjold,Silberner Schild,Ασημένια Ασπίδα,Arĝenta Ŝildo,Escudo Plateado,,Hopeakilpi,Bouclier d'Argent,Ezüst Pajzs,Scudo d'argento,銀の盾,은 방패,Zilveren Schild,Sølvskjold,Srebrna Tarcza,Escudo de Prata,,Scut de Argint,Серебряный щит,Сребрни штит,Silversköld,Gümüş Kalkan,Срібний щит +Enchanted Shield,TXT_ITEMSHIELD2,,,,Kouzelný štít,Fortryllet skjold,Verzauberter Schild,,Sorĉita Ŝildo,Escudo Encantado,,Lumottu kilpi,Bouclier Enchanté,Bűvös Pajzs,Scudo incantato,魔法の盾,마력 강화 방패,Betoverd schild,Fortryllet skjold,Zaklęta Tarcza,Escudo Encantado,,Scut Mistificat,Зачарованный щит,Зачарани штит,Förtrollad sköld,Büyülü Kalkan,Зачарований щит +Map Scroll,TXT_ITEMSUPERMAP,,,,Mapa,Kortrulle,Kartenrolle,,Map-volvolibro,Mapa en Pergamino,,Karttakäärö,Rouleau du Cartographe,Térkép Tekercs,Pergamena della Mappa,地図の巻物,두루마리 지도,Kaartrol,Kartrulle,Zwój Mapy,Pergaminho do Mapa,,Hartă Pergament,Свиток карты,Мапа,Kartrulle,Harita Kaydırma,Сувій-карта +Wand Crystal,TXT_AMMOGOLDWAND1,,,,Zlaté krystaly,Stav krystal,Zauberstabkristall,,Kristalo de Sorĉbastono,Cristal para Vara,,Sauvakristalli,Cristal Elfique,Kristálypor,Bacchetta di cristallo,ワンドクリスタル,지팡이 결정,Toverstok van Kristal,Tryllestav-krystall,Kryształ do Różdżki,Cristal para o Cetro,,Cristal pentru Toiag,Кристалл эльфийского жезла,Кристали за штап,Stavkristall,Değnek Kristali,Кристал для жезлу +Crystal Geode,TXT_AMMOGOLDWAND2,,,,Shluk krystalů,Krystal-geode,Kristallklumpen,,Kristalgeodo,Geoda de Cristal,,Kristalligeoidi,Géode de Cristal,Kristály Geoda,Geode di cristallo,晶洞石,결정 원석,Kristal Geode,Krystallgeode,Kryształowa Geoda,Geodo de Cristal,,Geodă de Cristal,Жеода кристалла,Кристални камен,Kristallgeod,Kristal Jeot,Кристалічна жеода +Mace Spheres,TXT_AMMOMACE1,,,,Žezlometné koule,Kølle kugler,Keulenkugeln,,Klabsferoj,Esferas de Maza,,Nuijakuulia,Sphère de Masse,Jogargömbök,Sfere per la mazza,メイス球弾,철퇴 포탄,Strijdknotsen,Mace-kuler,Kule do Buzdyganu,Esferas para Clava,,Sfere pentru Buzdugan,Сферы булавы,Сфере за буздован,Eldstötsfärer,Ateş Küreleri,Сфери для булави +Pile of Mace Spheres,TXT_AMMOMACE2,,,,Hromada žezlometných koulí,Bunke af kølle kugler,Haufen von Keulenkugeln,,Stako de Klabsferoj,Pila de Esferas de Maza,,Nuijakuulakasa,Pile de Sphères de Masse,Egy rakás jogargömb,Pila di sfere per la mazza,メイス球弾の固まり,철퇴 포탄 무더기,Stapel Strijdknotsen,Haug med muskettkuler,Sterta Kul do Buzdyganu,Pilha de Esferas para Clava,,Grămadă de Sfere pentru Buzdugan,Груда сфер булавы,Гомила сфера за буздован,Hög med Eldstötsfärer,Ateş Küreleri Yığını,Купа булавних сфер +Ethereal Arrows,TXT_AMMOCROSSBOW1,,,,Éterické šípy,Æteriske pile,Ätherische Pfeile,,Eteraj Sagoj,Flechas Etéreas,,Eetterinuolia,Carreaux Ethériques,Éteri nyílvesszők,Frecce eteree,イセリアルの矢,유체 화살,Etherische Pijlen,Eteriske piler,Eteryczne Strzały,Flechas Etéreas,,Săgeți Celeste,Эфирные стрелы,Етеричне стреле,Eteriska pilar,Eterik Oklar,Ефірні стріли +Quiver of Ethereal Arrows,TXT_AMMOCROSSBOW2,,,,Toulec éterických šípů,Kogger af æteriske pile,Köcher mit ätherischen Pfeilen,,Sagujo da Eteraj Sagoj,Carcaj de Flechas Etéreas,Carcaza de Flechas Etéreas,Eetterinuoliviini,Carquois de Carreaux Ethériques,Éteri nyíltok,Faretra di frecce eteree,イセリアルの矢筒,유체 화살집,Koker van Etherische Pijlen,Kogger av eteriske piler,Kołczan Eterycznych Strzał,Aljava de Flechas Etéreas,,Tolbă de Săgeți Celeste,Колчан эфирных стрел,Тоболац етеричних стрела,Kvant av eteriska pilar,Eterik Okların Sadağı,Сагайдак ефірних стріл +Claw Orb,TXT_AMMOBLASTER1,,,,Pazouří střela,Klovkugle,Klauenball,,Kriforbo,Orbe de Garra,,Kynsikehrä,Orbe de Griffe,Karomgömb,Sfera d'artiglio,クローオーブ,발톱 보주,Klauwbal,Klo-kule,Kula do Pazura,Orbe para Garra,Esfera para Garra,Glob pentru Gheară,Когтевой шар,Канџаста сфера,Klorör klot,Pençe Küresi,Кігтьова сфера +Energy Orb,TXT_AMMOBLASTER2,,,,Silová střela,Energikugle,Energieball,,Energiorbo,Orbe de Energía,,Energiakehrä,Orbe Draconique,Energiagömb,Sfera di energia,エネルギーオーブ,기력의 보주,Energiebal,Energikule,Kula Energii,Orbe de Energia,Esfera de Energia,Glob de Energie,Энергетический шар,Енергетска сфера,Energikulor,Enerji Küresi,Енергетична сфера +Lesser Runes,TXT_AMMOSKULLROD1,,,,Menší runy,Mindre runer,Kleine Runen,,Runetoj,Runas Menores,,Vähäriimut,Runes Mineurs,Gyenge rúnák,Rune inferiori,レッサールーン,룬 조각,Lichte Runen,Mindre runer,Gorsze Runy,Runas Inferiores,,Rune Mici,Младшие руны,Нижа руна,Mindre runor,Küçük Rünler,Молодші руни +Greater Runes,TXT_AMMOSKULLROD2,,,,Větší runy,Større runer,Große Runen,,Runegoj,Runas Mayores,,Isoriimut,Runes Supérieures,Erős rúnák,Rune superiori,グレータールーン,최상급 룬,Zware Runen,Store runer,Lepsze Runy,Runas Superiores,,Rune Mari,Старшие руны,Већа руна,Större runor,Büyük Rünler,Старші руни +Flame Orb,TXT_AMMOPHOENIXROD1,,,,Plamenný náboj,Flamme kugle,Flammenkugel,,Flamorbo,Orbe de Flama,,Liekkikehrä,Orbe de Flammes,Tűzgömb,Sfera di fuoco,フレイムオーブ,화염 구슬,Vuurbal,Flammekule,Kula Ognia,Orbe de Chamas,Esfera de Chamas,Glob de Foc,Пламенный шар,Ватрена сфера,Flamkula,Alev Küresi,Вогняна сфера +Inferno Orb,TXT_AMMOPHOENIXROD2,,,,Pekelný náboj,Inferno-kugle,Infernokugel,,Brulorbo,Orbe de Averno,,Infernokehrä,Orbe Infernal,Pokolgömb,Sfera infernale,インフェルノオーブ,지옥불 구슬,Infernobal,Inferno-kule,Kula Piekielna,Orbe Infernal,Esfera Infernal,Glob Infernal,Инфернальный шар,Пламена сфера,Infernokula,Cehennem Küresi,Пекельна сфера +Gold Wand,TXT_WPNGOLDWAND,,,,Zlatá hůl,Guldstav,Goldener Zauberstab,,Ora Sorĉbastono,Vara Dorada,,Kultasauva,Baguette Elfique,Aranypálca,Bacchetta d'oro,ゴールドワンド,황금 지팡이,Gouden Toverstok,Gullstav,Złota Różdżka,Varinha de Ouro,,Toiag cu Aur,Эльфийский жезл,Златни магични штап,Guldstav,Altın Değnek,Посох Ельфів +Firemace,TXT_WPNMACE,,,,Žezlomet,Ildspyd,Feuerkeule,,Fajroklabo,Maza de Fuego,,Tulinuija,Masse de Feu,Tűzbuzogány,"Mazza di fuoco +",ファイアメイス,투사철퇴,Vuurfoelie,Ildsted,Buzdygan Ognia,Clava de Fogo,,Buzdugan de Foc,Огненная булава,Ватрени буздован,Eldstöt,Ateş Çubuğu,Вогняна булава +Ethereal Crossbow,TXT_WPNCROSSBOW,,,,Éterická kuše,Æterisk armbrøst,Ätherische Armbrust,,Etera Arbalesto,Ballesta Etérea,,Eetterivarsijousi,Arbalète Ethérique,Éteri számszeríj,Balestra eterea,イセリアルクロスボウ,유체 쇠뇌,Etherische kruisboog,Eterisk armbrøst,Eteryczna Kusza,Besta Etérea,,Arbaletă Celestă,Эфирный арбалет,Етерични самострел,Eteriskt armborst,Eterik Arbalet,Ефірний арбалет +Dragon Claw,TXT_WPNBLASTER,,,,Drakospár,Drageklo,Drachenklaue,,Drakokrifo,Garra de Dragón,,Lohikäärmeenkynsi,Griffe Draconique,Sárkány karom,Artiglio del drago,ドラゴンクロー,용발톱,Drakenklauw,Drageklo,Smoczy Pazur,Garra de Dragão,,Gheara Dragonului,Коготь дракона,Змајева канџа,Drakklocka,Ejder Pençesi,Кіготь Дракона +Hellstaff,TXT_WPNSKULLROD,,,,Peklopal,Helvedestav,Höllenrute,,Inferbastono,Bastón Infernal,,Hornansauva,Bâton Infernal,Pokolpálca,Staffa infernale,ヘルスタッフ,지옥지팡이,Hellestaf,Helvetesstav,Piekielny Kostur,Cajado Infernal,,Baston Infernal,Посох Ада,Паклени штап,Helvetesstång,Cehennem Çubuğu,Пекельний посох +Phoenix Rod,TXT_WPNPHOENIXROD,,,,Fénixova hůl,Phønix-stang,Phönixstab,,Feniksvergo,Báculo del Fénix,,Feenikssauva,Bâton du Phénix,Főnix Rúd,Asta della fenice,フェニックスロッド,불사조 지팡이,Feniksstaf,Føniksstaven,Różdżka Feniksa,Bastão da Fênix,,Joarda Phoenix,Жезл феникса,Шипка феникса,Fenixstång,Anka Kuşu Çubuğu,Жезл Фенікса +Gauntlets of the Necromancer,TXT_WPNGAUNTLETS,,,,Nekromancerovy rukavice,Nekromantikernes handsker,Handschuhe des Zauberers,,Fergantoj de la Nekromancisto,Guanteletes del Nigromante,,Manaajan rautakintaat,Gantelets du Nécromancien,Halottidéző Páncélkesztyűi,Guanti del Negromante,ネクロマンサーの篭手,강령술사의 건틀릿,Handschoenen van de Geestenbezweerder,Nekromantens hansker,Rękawice Nekromanty,Manoplas do Necromante,,Mănușile Necromantului,Перчатки некроманта,Рукавице призивача духова,Nekromantikerns handskar,Ölü Çağıranın Eldivenleri,Рукавиці Некроманта +,,Locks,,,,,,,,,,,,,,,,,,,,,,,,,, +You need a blue key to open this door,TXT_NEEDBLUEKEY,,,,K otevření těchto dveří potřebuješ modrý klíč,Du skal bruge en blå nøgle for at åbne denne dør,Du brauchst einen blauen Schlüssel um diese Tür zu öffnen,Χρειάζεσε ένα μπλέ κλειδί για να ενεργοποίησεις αυτη τη πόρτα,Vi bezonas bluan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave azul para abrir esta puerta,,Tarvitset sinisen avaimen avataksesi tämän oven,Cette porte nécessite une clé bleue pour s'ouvrir.,Az ajtó nyitásához szükséged van egy kék kulcsra,"Ti serve una chiave blu per aprire questa porta +",開くには 青の鍵が必要だ,이 문을 열기 위해선 청색 열쇠가 필요하다,Je hebt een blauwe sleutel nodig om deze deur te openen,Du trenger en blå nøkkel for å åpne denne døren,"Potrzebujesz niebieskiego klucza, by otworzyć te drzwi.",Você precisa da chave azul para abrir esta porta,Precisas da chave azul para abrir esta porta,"Ai nevoie de o cheie albastră pentru a deschide +această ușă",Для открытия нужен синий ключ,Треба вам плави кључ да би отворили ова врата,Du behöver en blå nyckel för att öppna den här dörren.,Bu kapıyı açmak için mavi bir anahtara ihtiyacın var.,"Вам потрібен синій ключ, щоб відкрити ці двері" +You need a green key to open this door,TXT_NEEDGREENKEY,,,,K otevření těchto dveří potřebuješ červený klíč,Du skal bruge en grøn nøgle for at åbne denne dør,Du brauchst einen grünen Schlüssel um diese Tür zu öffnen,Χρειάζεσε ένα πράσινο κλειδί για να ενεργοποίησεις αυτη τη πόρτα,Vi bezonas verdan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave verde para abrir esta puerta,,Tarvitset vihreän avaimen avataksesi tämän oven,Cette porte nécessite une clé verte pour s'ouvrir.,Az ajtó nyitásához szükséged van egy zöld kulcsra,"Ti serve una chiave verde per aprire questa porta +",開くには 緑の鍵が必要だ,이 문을 열기 위해선 녹색 열쇠가 필요하다,Je hebt een groene sleutel nodig om deze deur te openen,Du trenger en grønn nøkkel for å åpne denne døren,"Potrzebujesz zielonego klucza, by otworzyć te drzwi.",Você precisa da chave verde para abrir esta porta,Precisas da chave verde para abrir esta porta,"Ai nevoie de o cheie verde pentru a deschide +această ușă",Для открытия нужен зелёный ключ,Треба вам зелени кључ да би отворили ова врата,Du behöver en grön nyckel för att öppna den här dörren,Bu kapıyı açmak için yeşil bir anahtara ihtiyacın var.,"Вам потрібен зелений ключ, щоб відкрити ці двері" +You need a yellow key to open this door,TXT_NEEDYELLOWKEY,,,,K otevření těchto dveří potřebuješ žlutý klíč.,Du skal bruge en gul nøgle for at åbne denne dør,Du brauchst einen gleben Schlüssel um diese Tür zu öffnen,Χρειάζεσε ένα κύτρινο κλειδί για να ενεργοποίησεις αυτη τη πόρτα,Vi bezonas flavan ŝlosilon por malfermi ĉi tiun pordon,Necesitas una llave amarilla para abrir esta puerta,,Tarvitset keltaisen avaimen avataksesi tämän oven,Cette porte nécessite une clé jaune pour s'ouvrir.,Az ajtó nyitásához szükséged van egy sárga kulcsra,Ti serve una chiave gialla per aprire questa porta,開くには 黄の鍵が必要だ,이 문을 열기 위해선 황색 열쇠가 필요하다,Je hebt een gele sleutel nodig om deze deur te openen,Du trenger en gul nøkkel for å åpne denne døren,"Potrzebujesz żółtego klucza, by otworzyć te drzwi.",Você precisa da chave amarela para abrir esta porta,Precisas da chave amarela para abrir esta porta,"Ai nevoie de o cheie galbenă pentru a deschide +această ușă",Для открытия нужен жёлтый ключ,Треба вам жути кључ да би отворили ова врата,Du behöver en gul nyckel för att öppna den här dörren,Bu kapıyı açmak için sarı bir anahtara ihtiyacınız var,"Вам потрібен жовтий ключ, щоб відкрити ці двері" +,,Actor tag names,,,,,,,,,,,,,,,,,,,,,,,,,, +Chicken,FN_CHICKEN,,,,Slepice,Kylling,Huhn,Κότα,Koko,Pollo,,Kana,Poulet,Csirke,Pollo,鶏,닭,Kip,Kylling,Kurczak,Galinha,,Găină,Цыплёнок,Кокошка,Kyckling,Tavuk,Курка +Weredragon,FN_BEAST,Wordplay: werewolf,,,Vlkodrak,Varedrage,Werdrache,Θηρίο,Drakfantomo,Hombre dragón,,Ihmislohikäärme,Dragon-garou,Vérsárkány,Drago Mannaro,ウェア ドラゴン,웨어드래곤,Weerdraak,Vardrage,Smokołak,Homem-dragão,,Vârcodragon,Дракон-оборотень,Змајодлак,Vardrake,Kurt ejderha,Дракон-перевертень +Sabreclaw,FN_CLINK,Wordplay: sabre-tooth,,,Šavlozub,Sabelklo,Säbelklaue,,Sabrokrifo,Garras de sable,,Sapelikynsi,Sabregriffe,Szablyakarom,Lamartiglio,サーベルクロー,세이버클로,Sabelklauw,Sabreklo,Szabloszpon,Unhas-de-sabre,,Gheară de Sabie,Саблекоготь,Тигар,Sabelklo,Kılıçpençe,Шаблекіготь +D'Sparil,FN_DSPARIL,,,,,,,,,,,,,,,デ'スパリル,드'스파릴,,,,,,,Д'Спарил,Д'Спарил,,,Д'Спаріл +Gargoyle,FN_HERETICIMP,,,,Chrlič,,,,Gargojlo,Gárgola,,Gargoili,Gargouille,Vízköpő,,ガーゴイル,가고일,,,Gargulec,Gárgula,,Garguie,Горгулья,Камена утвара,,,Ґарґуйль. +Ironlich,FN_IRONLICH,,,,Železný kostěj,Jern lig,Eiserne Leiche,,Ferliĉo,Liche de hierro,,Rautakalmo,Liche de Fer,Ezüst lich,Lich di Ferro,アイアンリッチ,아이언 리치,IJzeren Lijk,Jernlich,Żelazny Lisz,Lich de Ferro,,Cadavru de Fier,Железный лич,Челични лич,Järnlich,Demir Ceset,Залізний Ліч +Undead Warrior,FN_BONEKNIGHT,,,,Nemrtvý válečník,Udøde Kriger,Untoter Krieger,Αθάνατος Πολεμιστής,Malmortinta Batalisto,Guerrero no muerto,,Epäkuollut soturi,Guerrier Mort-Vivant,Élőhalott harcos,Guerriero Non Morto,アンデット兵,언데드 전사,Ondode Krijger,Udød kriger,Nieumarły wojownik,Guerreiro Morto-vivo,,Războinic Nemort,Воин-нежить,Немртви ратник,Odöd krigare,Ölümsüz Savaşçı,Воїн-нежить +Maulotaur,FN_MINOTAUR,,,,Minotaurus,Maulotaurus,Minotaurus,Μινόταυρος,Bategtaŭro,Mazotauro,,Maulotauri,Massetaure,,Maulotauro,マウロタウロス,몰로타우어,Maulotaurus,Maulotaur,Młototaur,Marretauro,,,Избитавр,Минотаур,Maulotaurus,Maulotor,Молотаур +Golem,FN_MUMMY,,,,Golém,,,,Golemo,Gólem,,,,Gólem,,ゴーレム,골렘,,,,,,,Голем,Голем,,,Голем +Nitrogolem,FN_MUMMYLEADER,,,,Střelgolém,,,,Azotgolemo,Gólem de ázoe,,,,Nitrógólem,,ニトロゴーレム,니트로 골렘,,,,,,,Нитроголем,Нитро голем,,,Нітроголем +Ophidian,FN_SNAKE,,,,Šupinatec,,,,Ofidio,Ofidio,,Käärmeolio,Ophidien,Ofidián,,オフィディアン,오피디안,Ophidiaan,,Wężowaty,Ofídio,,Ofidian,Офидиан,Змија,,,Офідіан +Wizard,FN_WIZARD,,,,Čaroděj,Troldmand,Zauberer,Μάγος,Sorĉisto,Mago,Hechicero,Velho,Magicien,Mágus,Mago,ウィザード,마법사,Tovenaar,Trollmann,Czarownik,Mago,,Vrăjitor,Колдун,Чаробњак,Trollkarl,Sihirbaz,Чаклун +Wand Crystals,AMMO_GOLDWAND,,,,Zlaté krystaly,Stav krystaller,Elfenstabkristalle,,Sorĉbastono-Kristaloj,Cristales para vara,,Sauvakristalleja,Cristaux,Pálca kristályok,Cristalli per la bacchetta,ワンド クリスタル,지팡이 결정,Toverstafkristallen,Tryllestavkrystaller,Kryształy do Różdżki,Cristais para o Cetro,,Cristale pentru Toiag,Кристалл эльфийского жезла,Кристали за штап,Stavkristaller,Değnek Kristalleri,Кристал для жезлу +Ethereal Arrows,AMMO_CROSSBOW,,,,Éterické šípy,Æteriske pile,Ätherische Pfeile,,Eteraj Sagoj,Flechas etéreas,,Eetterinuolia,Carreaux,Éteri nyilak,Frecce eteree,イセリアルの矢,유체 화살,Etherische Pijlen,Eteriske piler,Eteryczne Strzały,Flechas Etéreas,,Săgeți Celeste,Эфирные стрелы,Етеричне стреле,Eteriska pilar,Eterik Oklar,Ефірні стріли +Claw Orbs,AMMO_BLASTER,,,,Pazouří střely,Kugler med kløer,Klauenbälle,,Kriforboj,Orbes de garra,,Kynsikehriä,Orbes,Karom golyók,Sfere di artigli,クロー オーブ,발톱 보주,Klauwbollen,Klo-kuler,Kule do Pazura,Orbes para Garra,,Globuri pentru Gheară,Когтевые шары,Канџаста сфера,Klor bollar,Pençe Küreleri,Кігтьова сфера +Mace Spheres,AMMO_MACE,,,,Žezlometné koule,Kugler til stridskølle,Energiebälle,,Klabsferoj,Esferas de maza,,Nuijakuulia,Sphères,Buzogány gömbök,Sfere per la mazza,メイス スフィア,철퇴 포탄,Strijdknotsen,Ildsted-kuler,Kule do Buzdyganu,Esferas para Clava,,Sfere pentru Buzdugan,Сферы булавы,Сфере за буздован,Eldstötsfärer,Ateş Küreleri,Сфери для булави +Hellstaff Runes,AMMO_SKULLROD,,,,Peklopalné runy,Helvedestav-runer,Höllenrutenrunen,,Inferbastono-Runoj,Runas de Vara Infernal,,Hornansauvan riimuja,Runes,Pokolbot rúnák,Rune infernali,ヘルスタッフ ルーン,룬 조각,Hellestafrunen,Helvetesstav-runer,Runy do Piekielnego Kostura,Runas Infernais,,Rune pentru Bastonul Infernal,Руны посоха ада,Пуне за паклени штап,Runor för helvetesstång,Cehennem Asası Rünleri,Руни пекельного посоху +Flame Orbs,AMMO_PHOENIXROD,,,,Plamenné náboje,Flammekugler,Flammenkugeln,,Flamorboj,Orbes de llama,,Liekkikehriä,Orbes de Feu,Tűzgolyók,Sfere di fuoco,フレイム オーブ,화염 구슬,Vuurballen,Flammekuler,Kule Ognia,Orbes de Chamas,,Globuri de Foc,Пламенные шары,Ватрена сфера,Flamkärnor,Alev Küreleri,Вогняна сфера +Staff,TAG_STAFF,,,,Hole,Stav,Stab,Ράβδος,Bastono,Bastón,,Sauva,Bâton,Bot,Staffa,杖,지팡이,Staf,Stav,Kostur,Bastão,,Baston,Посох,Штап,Stav,Çubuk,Палиця +Elven Wand,TAG_GOLDWAND,,,,Elfí hůlka,Elverstav,Elfenstab,,Elfa Sorĉbastono,Vara de Elfo,,Haltiasauva,Baguette Elfique,Elf pálca,Scettro Elfico,エルフのワンド,엘프 지팡이,Elvenstokje,Alvestav,Elfia Różdżka,Cetro Élfico,,Toiag,Эльфийский жезл,Вилењачки штапић,Elfenstav,Elf Asası,Посох Ельфів +,,Obituaries,,,,,,,,,,,,,,,,,,,,,,,,,, +%o was pecked to death.,OB_CHICKEN,,,,%o byl@[ao_cs] uklován@[ao_cs] k smrti.,%o blev hakket ihjel.,%o wurde zu Tode gepickt.,,%o estis bekita ĝis morto.,A %o l@[ao_esp] han picoteado a muerte.,A %o l@[ao_esp] picotearon a muerte.,%o nokittiin kuoliaaksi.,%o a été picoré@[e_fr] a mort.,%o halálra lett csípve.,%o è stato beccato a morte.,%o はくちばしで突かれ死んだ。,%o 은(는) 쪽팔리게 쪼여 죽었다.,%o werd doodgepikt.,%o ble hakket i hjel.,%o został@[ao_pl] zadzioban@[adj_pl] na śmierć.,%o foi bicad@[ao_ptb] até a morte.,%o foi picad@[ao_ptb] até a morte.,%o a fost ciocănit până la moarte.,Игрок %o заклёван до смерти.,%o је искљуцан@[adj_1_sr] до смрти.,%o blev hackad till döds.,%o gagalanarak öldürüldü.,%o задзьобано до смерті. +%o was charred by a weredragon.,OB_BEAST,,,,%o byl@[ao_cs] spálen@[ao_cs] vlkodrakem.,%o blev forkullet af en varedrage.,%o wurde von dem Werdrachen verschmort.,,%o brulegiĝis de drakfantomo.,A %o l@[ao_esp] ha carbonizado un hombre dragón.,A %o l@[ao_esp] carbonizó un hombre dragón.,%o joutui ihmislohikäärmeen kärventämäksi.,%o a été carbonisé@[e_fr] par un dragon-garou.,%o szénné égett egy Vérsárkány által.,%o è stato carbonizzato da una bestia.,%o はウェアドラゴンに黒焦げにされた。,%o 은(는) 웨어드래곤에 의해 검게 탔다.,%o werd verbrand door een weerdraak.,%o ble forkullet av en vardrage.,%o został@[ao_pl] zwęglon@[adj_pl] przez smokołaka.,%o foi carbonizad@[ao_ptb] por um homem-dragão.,,%o a fost ceruit de un vârcodragon.,Игрок %o обуглен драконом-оборотнем.,%o је реш печен@[adj_1_sr] од стране замјодлака.,%o blev förkolnad av en vardrake.,%o bir kurt ejderha tarafından yakıldı.,%o було спалено драконом-перевертнем. +%o was slashed by a sabreclaw.,OB_CLINK,,,,%o byl@[ao_cs] rozsápán@[ao_cs] šavlozubem.,%o blev skåret op af en sabreklo.,%o wurde von der Säbelklaue zerschlitzt.,,%o tranĉegiĝis de sabrokrifo.,A %o l@[ao_esp] ha cortado un garras de sable.,A %o l@[ao_esp] cortó un garras de sable.,%o joutui sapelikynnen sivaltamaksi.,%o s'est fait découper par un sabregriffe.,%o meg lett vágva egy Szablyakarom által.,%o è stato squarciato da un lapillo.,%o はサーベルクローに切り裂かれた。,%o 은(는) 세이버클로에게 잘렸다.,%o werd door een sabelklauw gesneden.,%o ble kuttet av en sabelklo.,%o został@[ao_pl] posiekan@[adj_pl] przez szabloszpona.,Um Unhas-de-sabre cortou %o.,,%o a fost tăiat de o gheară de sabie.,Игрока %o нарезал саблекоготь.,Играча %o је исекао тигар.,%o blev huggen av en sabelklo.,%o bir kılıç pençe tarafından kesildi.,%o було розсічено шаблекігтем. +%o was scalded by D'Sparil's serpent.,OB_DSPARIL1,,,,%o byl@[ao_cs] zpopelněn@[ao_cs] ořem D'Sparila.,%o blev skoldet af D'Sparils slange.,%o wurde von D'Sparils Schlange verbrüht.,,%o varmegiĝis de la serpento de D'Sparil.,A %o l@[ao_esp] ha carbonizado la serpiente de D'Sparil.,A %o l@[ao_esp] carbonizó la serpiente de D'Sparil.,%o joutui D'Sparilin käärmeen kalttaamaksi.,%o a été ébouillanté@[e_fr] par un serpent de D'Sparil.,%o le lett forrázva D'Sparil Kígyója által.,%o è stato bruciato dal serpente di D'Sparil.,%o はデ'スパリルのサーペントに火傷を負わされた。,%o 은(는) 드'스파릴의 서펜트에 데였다.,%o werd gebroeid door de slang van D'Sparil.,%o ble skåldet av D'Sparils slange.,%o został@[ao_pl] poparzon@[adj_pl] przez węża D'Sparila.,%o foi escaldad@[ao_ptb] pela serpente de D'Sparil.,,%o a fost opărit de șarpele lui D'Sparil.,Игрока %o обжёг змей Д'Спарила.,Играча %o је опекао Д'Спарилова змија.,%o blev skållad av D'Sparils orm.,"%o, D'Sparil'in yılanı tarafından haşlandı.",%o було спалено змієм Д'Спаріла. +%o was chewed up by D'Sparil's serpent.,OB_DSPARIL1HIT,,,,%o byl@[ao_cs] rozkousán@[ao_cs] ořem D'Sparila.,%o blev tygget op af D'Sparils slange.,%o wurde von D'Sparils Schlange verspeist.,,%o maĉegiĝis de la serpento de D'Sparil.,A %o l@[ao_esp] ha engullido la serpiente de D'Sparil.,A %o l@[ao_esp] tragó la serpiente de D'Sparil.,%o joutui D'Sparilin käärmeen pureksimaksi.,%o a été dévoré@[e_fr] par un serpent de D'Sparil.,%o meg lett rágva D'Sparil Kigyója által.,%o è stato masticato dal serpente di D'Sparil.,%o はデ'スパリルのサーペントに噛み砕かれた。,%o 은(는) 드'스파릴의 서펜트에게 씹혔다.,%o werd door de slang van D'Sparil opgekauwd.,%o ble tygd opp av D'Sparils slange.,%o został@[ao_pl] przeżut@[adj_pl] przez węża D'Sparila.,%o foi mastigad@[ao_ptb] pela serpente de D'Sparil.,,%o a fost mestecat de șarpele lui D'Sparil.,Игрока %o пожрал змей Д'Спарила.,%o је сажвакан@[adj_1_sr] од стране Д'Спарилове змије.,%o blev tuggad av D'Sparils orm.,"%o, D'Sparil'in yılanı tarafından çiğnendi.",Змій Д'Спаріла зжер %o . +%o was no match for D'Sparil.,OB_DSPARIL2,,,,%o nebyl@[ao_cs] pro D'Sparila žádná výzva.,%o kunne ikke klare D'Sparil.,%o war kein Gegner für D'Sparil.,,%o ne estis rivalo por D'Sparil. ,%o no era rival para D'Sparil.,,%o ei mahtanut mitään D'Sparilille.,%o n'a pas pu égaler D'Sparil.,%o nem volt méltó ellenfél D'Sparil számára.,%o non era all'altezza di D'Sparil.,%o はデ'スパリルには全く歯が立たなかった。,%o 은(는) 드'스파릴에겐 상대가 되지 못했다.,%o was geen partij voor D'Sparil.,%o var ingen match for D'Sparil.,%o nie miał@[ao_pl] szans z D'Sparilem.,%o não foi páreo para D'Sparil.,%o não foi desafio para D'Sparil.,%o n-a fost nici pe departe pe măsura lui D'Sparil.,Игрок %o был не ровня Д'Спарилу.,%o није ни до колена Д'Спарилу.,%o var ingen match för D'Sparil.,"%o, D'Sparil'in dengi değildi.",%o ніщо проти Д'Спаріла. +%o was smacked down by D'Sparil.,OB_DSPARIL2HIT,,,,%o byl@[ao_cs] sražen@[ao_cs] D'Sparilem.,%o blev slået ned af D'Sparil.,%o wurde von D'Sparil zerklatscht.,,%o frapiĝis de D'Sparil.,A %o l@[ao_esp] ha humillado D'Sparil.,A %o l@[ao_esp] humilló D'Sparil.,%o joutui D'Sparilin löylyttämäksi.,%o a été battu@[e_fr] a plate couture par D'Sparil.,%o a földre lett csapva D'Sparil által.,%o è stato abbattuto da D'Sparil.,%o はデ'スパリルに打ち負かされた。,%o 은(는) 드'스파릴의 맹격에 쓰러졌다.,%o werd neergeslagen door D'Sparil.,%o ble slått ned av D'Sparil.,%o został@[ao_pl] roztrzaskan@[adj_pl] przez D'Sparila,%o foi mort@[ao_ptb] por D'Sparil.,,%o a fost pus la pământ de D'Sparil.,Игрок %o сбит с ног Д'Спарилом.,%o је претучен@[adj_1_sr] од стране Д'Спарила.,%o blev nedslagen av D'Sparil.,"%o, D'Sparil tarafından yere serildi.",Д'Спаріл збив %o. +%o was scarred by a gargoyle.,OB_HERETICIMP,,,,%o byl@[ao_cs] upálen@[ao_cs] chrličem.,%o blev mærket af en gargoyle.,%o wurde von einem Gargoyle zerkratzt.,,%o ĉikartiĝis de gargojlo.,"A %o l@[ao_esp] ha marcado, y no de cicatrices, una gárgola.","A %o l@[ao_esp] marcó, y no de cicatrices, una gárgola.",%o joutui gargoilin arpeuttamaksi.,%o a été effrayé@[e_fr] par une gargouille.,%o meg lett sebesítve egy vízköpő által.,%o è stato terrorizzato da un imp.,%o はガーゴイルに傷を負わされた。,%o 은(는) 가고일에 의해 다쳤다.,%o was getekend door een gargoyle.,%o ble arret av en gargoyle.,%o został@[ao_pl] zadrapan@[adj_pl] przez gargulca,%o foi cicatrizad@[ao_ptb] por uma gárgula.,,%o a fost cicatrizat de o garguie.,Игрока %o изуродовала горгулья.,%o је ожиљкан@[adj_1_sr] од стране камене утваре.,%o blev ärrad av en gargoyle.,%o bir gargoyle tarafından yaralandı.,%o понівечено ґарґуйлем. +%o was hacked by a gargoyle.,OB_HERETICIMPHIT,,,,%o byl@[ao_cs] rozsekán@[ao_cs] chrličem.,%o blev hakket af en gargoyle.,%o wurde von einem Gargoyle zerhackt.,,%o hakiĝis de gargojlo.,A %o l@[ao_esp] ha arañado una gárgola.,A %o l@[ao_esp] arañó una gárgola.,%o joutui gargoilin pilkkomaksi.,%o a été mis@[e_fr] en pièces par une gargouille.,%o fel lett vágva egy vízköpő által.,%o è stato eliminato da un imp.,%o はガーゴイルに切り刻まれた。,%o 은(는) 가고일에 의해 베였다.,%o werd gehackt door een gargoyle.,%o ble hakket av en gargoyle.,%o został@[ao_pl] pocięt@[adj_pl] przez gargulca,%o foi mutilad@[ao_ptb] por uma gárgula.,,%o a fost tăiat de o garguie.,Игрока %o покалечила горгулья.,Играча %o је исекла камена утвара.,%o blev hackad av en gargoyle.,%o bir gargoyle tarafından kesildi.,%o скалічено ґарґуйлем. +%o was devastated by an ironlich.,OB_IRONLICH,,,,%o byl@[ao_cs] zničen@[ao_cs] železným kostějem.,%o blev ødelagt af en jern lig.,%o wurde von der Eisernen Leiche zerstört.,,%o ruiniĝis de ferliĉo.,A %o l@[ao_esp] ha devastado un liche de hierro.,A %o l@[ao_esp] devastó un liche de hierro.,%o joutui rautakalmon hävittämäksi.,%o a été dévasté@[e_fr] par une Liche de Fer.,%o elpusztult egy ezüst lich miatt.,%o è stato devastato da un ironlich.,%o はアイアンリッチに吹き飛ばされた。,%o 은(는) 아이언 리치에게 붕괴 당했다.,%o werd verwoest door een ijzeren lijk.,%o ble knust av en jernlich.,%o został@[ao_pl] zdewastowan@[adj_pl] przez żelaznego lisza,%o foi devastad@[ao_ptb] por um lich de ferro.,,%o a fost devastat de un cadavru de fier.,Игрока %o растоптал железный лич.,%o је уништен@[adj_1_sr] од стране челичног лича.,%o blev förödd av en järnlich,%o demir bir ceset tarafından harap edildi.,%o знищено залізним лічем. +%o got up-close and personal with an ironlich.,OB_IRONLICHHIT,,,,%o se dostal@[ao_cs] moc blízko k železnému kostěji.,%o kom helt tæt på en jern lig.,%o kam der Eisernen Leiche zu nahe.,,%o havis proksiman kaj desonan rekonton kun ferliĉo.,%o ha tenido un encuentro cercano y personal con un liche de hierro.,%o tuvo un encuentro cercano y personal con un liche de hierro.,%o meni lähelle rautakalmoa.,%o a fait ami@[e_fr]-ami@[e_fr] avec une Liche de Fer.,%o közel került és személyes volt egy ezüst lichhel szemben.,%o è andato troppo vicino a un ironlich.,%o はアイアンリッチと密接に関わった。,%o 은(는) 사적인 이유로 아이언 리치에게 다가왔다.,%o werd door een ijzeren lijk onheus bejegend.,%o fikk nærkontakt med en jernlich.,%o był@[ao_pl] blisko i na osobności z żelaznym liszem,%o chegou muito perto de um lich de ferro.,,"%o s-a apropiat prea mult de un +cadavru de fier.",Игрок %o близко и лимно узнал железного лича.,%o се лично приближи@[ao_1_sr] челичном личу.,%o kom nära och personligt med en järnlich.,%o demir bir cesede çok yaklaştı.,%o надто зблизи@[adj_2_ua] з залізним лічем. +%o was axed by an undead warrior.,OB_BONEKNIGHT,,,,%o dostal@[ao_cs] sekyrou od nemrtvého válečníka.,%o blev øksehugget af en udød kriger.,%o wurde von dem Untoten Krieger mit der Axt bearbeitet.,,%o hakiliĝis de malmortinta batalisto.,%o ha recibido un hachazo de un guerrero no muerto.,%o recibió un hachazo de un guerrero no muerto.,%o joutui epäkuolleen soturin kirvestämäksi.,%o s'est pris@[e_fr] la hâche d'un guerrier mort-vivant.,%o baltát kapott egy Élőhalott Harcostól.,%o è stato accettato da un guerriero non morto .,%o はアンデッド兵の斧でやられた。,%o 은(는) 언데드 전사에게 도끼질 당했다.,%o werd doorkliefd door een ondode krijger.,%o ble hugget av en udød kriger.,%o został@[ao_pl] rozłupany siekierą przez nieumarłego wojownika,%o foi decepad@[ao_ptb] por um guerreiro morto-vivo.,%o foi decapitad@[ao_ptb] por um guerreiro morto-vivo.,%o a primit un topor de la un războinic nemort.,Игрока %o зарубил воин-нежить.,%o је исечен@[adj_1_sr] од стане немртвог ратника.,%o blev yxad av en odöd krigare.,%o bir ölümsüz savaşçı tarafından baltalandı.,Воїн-нежить зарубав %o. +%o was slain by an undead warrior.,OB_BONEKNIGHTHIT,,,,%o byl@[ao_cs] zabit@[ao_cs] nemrtvým válečníkem.,%o blev dræbt af en udød kriger.,%o wurde von dem Untoten Krieger hingemetzelt.,,%o estis mortigita de malmortinta batalisto.,A %o l@[ao_esp] ha descuartizado un guerrero no muerto.,A %o l@[ao_esp] descuartizó un guerrero no muerto.,%o joutui epäkuolleen soturin tappamaksi.,%o s'est fait pourfendre par un guerrier mort-vivant.,%o meghalt egy Élőhalott Harcos által.,%o è stato ucciso da un guerriero non morto. ,%o はアンデッド兵の手で葬られた。,%o 은(는) 언데드 전사에게 처단당했다.,%o werd gedood door een ondode krijger.,%o ble drept av en levende død kriger.,%o został@[ao_pl] zgładzon@[adj_pl] przez nieumarłego wojownika,%o foi picotad@[ao_ptb] por um guerreiro morto-vivo.,,%o a fost omorât de un războinic nemort.,Игрока %o сразил воин-нежить.,Играча %o је убио немртви ратник.,%o blev dödad av en odödlig krigare.,%o bir ölümsüz savaşçı tarafından katledildi.,%o бу@[adj_1_ua] повален@[ao_ua] воїном-нежитю. +%o was blasted into cinders by a Maulotaur.,OB_MINOTAUR,,,,%o byl@[ao_cs] rozmetán@[ao_cs] na popel Minotaurem.,%o blev sprængt i aske af en Maulotaurus.,%o wurde von dem Minotaurus in Asche verwandelt.,,%o eksplodiĝis en cindrojn de Bategtaŭro.,A %o l@[ao_esp] ha volado en cenizas un Mazotauro.,A %o l@[ao_esp] voló en cenizas un Mazotauro.,%o tuhottiin tuusan nuuskaksi maulotaurin toimesta.,%o s'est fait@[e_fr] incinérer par un Massetaure.,%o darabokra robbant egy Maulotaurusz által.,%o è stato incenerito da un Maulotauro. ,%o はマウロタウロスに燃やされ炭化した。,%o 은(는) 몰로타우어에게 잿더미가 되도록 파괴당했다.,%o werd door een Maulotaurus tot sintels geblazen.,%o ble sprengt til aske av en Maulotaur.,%o został@[ao_pl] obrócon@[adj_pl] w popiół przez Młototaura,%o foi incinerad@[ao_ptb] por um Marretauro,,%o a fost făcut cenușă de un Maulotaur.,Игрока %o разнёс на угольки Избитавр.,%o је испуцан@[adj_1_sr] у пепео од стране минотаура.,%o blev sprängd till aska av en maulotaurus.,%o bir Maulotor tarafından kül haline getirildi.,%o бу@[adj_1_ua] стерт@[ao_ua] в пил Молотауром. +%o was pulped by a Maulotaur.,OB_MINOTAURHIT,,,,%o byl@[ao_cs] rozmáčknut@[ao_cs] Minotaurem.,%o blev knust af en Maulotaurus.,%o wurde von dem Minotaurus zu Brei verarbeitet.,,%o pulpiĝis de Bategtaŭro.,A %o l@[ao_esp] ha hecho puré un Mazotauro.,A %o l@[ao_esp] hizo puré un Mazotauro.,%o joutui maulotaurin möyhentämäksi.,%o s'est fait@[e_fr] éclater par un Massetaure.,%o péppé lett zúzva egy Maulotaurusz által.,%o è stato ridotto in poltiglia da un Maulotauro. ,%o はマウロタウロスにグシャグシャにされた。,%o 은(는) 몰로타우어에 의해 내동댕이쳐졌다.,%o werd verpulverd door een Maulotaurus.,%o ble knust av en maulotaur.,%o został@[ao_pl] roztart@[adj_pl] na miazgę przez Młototaura,%o foi esmagad@[ao_ptb] por um Marretauro,,%o a fost descojit de un Maulotaur.,Игрока %o превратил в кровавое месиво Избитавр.,Играча %o је претукао минотаур.,%o blev krossad av en maulotaurus.,%o bir Maulotor tarafından ezildi.,Молотаур перетворив %o в криваве місиво. +%o was smashed by a golem.,OB_MUMMY,,,,%o byl@[ao_cs] umlácen@[ao_cs] golémem.,%o blev smadret af en golem.,%o wurde von einem Golem erschlagen.,,%o frakasiĝis de golemo.,A %o l@[ao_esp] ha aplastado un gólem.,A %o l@[ao_esp] aplastó un gólem.,%o joutui golemin murskaamaksi.,%o a été défoncé@[e_fr] par un golem.,%o össze lett törve egy Gólem által.,%o è stato schiacciato da un golem.,%o はゴーレムに叩きのめされた。,%o 은(는) 골렘에게 두들겨 맞았다.,%o werd verbrijzeld door een golem.,%o ble knust av en golem.,%o został@[ao_pl] stłuczon@[adj_pl] przez golema,%o foi esmagad@[ao_ptb] por um golem.,,%o a fost lovit de un golem.,Игрока %o разбил голем.,Играча %o је смрвио голем.,%o blev krossad av en golem.,%o bir golem tarafından parçalandı.,%o потовк голем. +%o was shrieked to death by a nitrogolem.,OB_MUMMYLEADER,,,,%o byl@[ao_cs] ukřičen@[ao_cs] k smrti střelgolémem.,%o blev skriget til døde af en nitrogolem.,%o wurde von einem Nitrogolem zu Tode gekreischt.,,%o estis kriegita ĝis morto de azotgolemo.,A %o le ha chillado a muerte un gólem de ázoe.,A %o le gritó a muerte un gólem de ázoe.,%o kirkaistiin kuoliaaksi nitrogolemin toimesta.,%o s'est fait@[e_fr] percer les tympans par un nitrogolem.,%o halálra lett ijesztve egy Nitrógólem által.,%o è stato stroncato da un golem.,%o はニトロゴーレムに脅かされた。,%o 은(는) 니트로 골렘에 의해 비명횡사 당했다.,%o werd doodgekrijst door een nitrogolem.,%o ble skreket i hjel av en nitrogolem.,%o został@[ao_pl] zakrzyczan@[adj_pl] na śmierć przez nitrogolema,%o agonizou na frente de um nitrogolem.,,%o a fost chiuit până la moarte de un nitrogolem.,Игрока %o убил криком нитроголем.,Играча %o је извриштао до смрти нитроголем.,%o skrek ihjäl av en nitrogolem.,%o bir nitrogolem tarafından çığlık çığlığa öldürüldü.,%o почу@[adj_1_ua] смертельний крик нітроголема. +%o was rattled by an ophidian.,OB_SNAKE,,,,%o byl@[ao_cs] zachřestěn@[ao_cs] šupinatcem.,%o blev rystet af en ophidian.,%o hörte das Klappern des Ophidian.,,%o klakiĝis de ofidio.,A %o l@[ao_esp] ha agitado un ofidio.,A %o l@[ao_esp] sacudió un ofidio.,%o joutui käärmeolion kalkattamaksi.,%o s'est fait@[e_fr] sonner par un ophidien.,%o halálra lett csörgetve egy Ofidián által.,%o è stato stritolato da un serpente.,%o はオフィディアンに動揺した。,%o 은(는) 오피디안에게 흔들렸다.,%o werd gerammeld door een ophidiaan.,%o ble rystet av en ophidian.,%o został@[ao_pl] rozgrzechotan@[adj_pl] przez wężowatego,%o foi sacudid@[ao_ptb] por um ofídio.,,%o a fost bătut până la moarte de un ofidian.,Игрока %o потряс офидиан.,Играча %o је угризла змија.,%o blev skrämd av en ophidian.,%o bir ophidian tarafından sarsıldı.,Офідіан загриз совість %o. +%o was cursed by a wizard.,OB_WIZARD,,,,%o byl@[ao_cs] zaklet@[ao_cs] čarodějem.,%o blev forbandet af en troldmand.,%o wurde von dem Magier verflucht.,,%o malbeniĝis de sorĉisto.,A %o l@[ao_esp] ha maldecido un mago.,A %o l@[ao_esp] maldijo un hechicero.,%o joutui velhon kiroamaksi.,%o a été maudit@[e_fr] par un sorcier.,%o meg lett átkozva egy Varázsló által.,%o è stato maledetto da un mago.,%o はウィザードに呪われた。,%o 은(는) 드'스파릴의 제자에 의해 저주받았다.,%o werd vervloekt door een tovenaar.,%o ble forbannet av en trollmann.,%o został@[ao_pl] przeklęt@[adj_pl] przez czarownika,%o foi amaldiçoad@[ao_ptb] por um mago.,,%o a fost blestemat de un vrăjitor.,Игрока %o проклял колдун.,%o је проклет@[adj_1_sr] од стране чаробњака.,%o blev förbannad av en trollkarl.,%o bir büyücü tarafından lanetlendi.,%o бу@[adj_1_ua] проклят@[ao_ua] чаклуном. +%o was palpated by a wizard.,OB_WIZARDHIT,,,,%o byl@[ao_cs] prozkoumán@[ao_cs] čarodějem.,%o blev palperet af en troldmand.,%o spürte den Hauch des Magiers.,,%o palpatiĝis de sorĉisto.,A %o l@[ao_esp] ha tocado un mago.,A %o l@[ao_esp] tocó un hechicero.,%o joutui velhon tunnustelemaksi.,%o a été palpé@[e_fr] par un sorcier.,%o meg lett tapogatva egy Varázsló által.,%o è stato toccato da un mago.,%o はウィザードに触診されてしまった。,%o 은(는) 드'스파릴의 제자에게 촉진당했다.,%o werd betast door een tovenaar.,%o ble palpert av en trollmann.,%o został@[ao_pl] przebadan@[adj_pl] przez czarownika,%o foi apalpad@[ao_ptb] por um mago.,,%o a fost palpat de un vrăjitor.,Игрока %o пощупал колдун.,Играча %o је палпатирао чаробњак.,%o blev palperad av en trollkarl.,%o bir büyücü tarafından palpe edildi.,Чаклун дослідив внутрішній світ %o. +%o got staffed by %k.,OB_MPSTAFF,,,,%o dostal@[ao_cs] holí od hráče %k.,%o blev stafferet af %k.,%o wurde von %k verprügelt.,,%o bategiĝis de %k.,A %o l@[ao_esp] ha apaleado %k.,A %o l@[ao_esp] apaleó %k.,%k sauvoi %k paran.,%o s'est fait@[e_fr] matraquer par %k.,%o meg lett botozva %k által.,%o è stato preso a colpi di staffa da %k.,%o は %k の棒でぶん殴られた。,%o 은(는) %k 의 지팡이에 제압당했다.,%o kreeg een tik van %k's staf.,%o ble staffet av %k.,%o został@[ao_pl] walnięt@[adj_pl] laską przez %k,%o levou uma sova do bastão de %k.,,%o a fost bastonat de %k.,Игрок %o дополнил посох игрока %k.,%o је претуцан@[adj_1_sr] штапом од стране %k.,%o blev bemannad av %k.,"%o, %k tarafından öldüresiye dövüldü.",%o скуштува@[adj_1_ua] палицю %k. +%o got a shock from %k's gauntlets.,OB_MPGAUNTLETS,,,,%o byl@[ao_cs] prošokován@[ao_cs] rukavicemi hráče %k.,%o fik et chok af %ks handsker.,%o bekam einen Schock von %ks Handschuhen.,,%o recivis ŝokon de la fergantoj de %k.,%o ha recibido un choque de los guanteletes de %k.,%o recibió un choque de los guanteletes de %k.,%o sai sähköiskun pelaajan %k kintaista.,%o s'est pris@[e_fr] un coup de jus des gantelets de %k.,%o kapott egy sokkot %k által.,%o è stato folgorato dai guanti di %k.,%o は %k の篭手からショックを受けた。,%o 은(는) %k 가 쓰고 있는 건틀릿의 전격을 느꼈다.,%o kreeg een schok van %k's handschoenen.,%o fikk støt av %ks hansker.,%o został@[ao_pl] wstrząśnięt@[adj_pl] rękawicami %k,%o tomou um choque das manoplas de %k.,,%o a primit un șoc de la mănușile lui %k.,Игрок %o шокирован перчатками игрока %k.,%o је доби@[ao_1_sr] шок од %k штапа.,%o blev chockad av %ks handskar.,"%o, %k tarafından şoklandı.",%k використа@[adj_1_ua] зворотню дефібриляцію на %o. +%o waved goodbye to %k's elven wand.,OB_MPGOLDWAND,,,,%o zamával@[ao_cs] elfské hůlce hráče %k.,%o vinkede farvel til %ks elverstav.,%o sagte „Tschüß“ zu %ks Elfenstab.,,%o ĝisis al la elfa sorĉbastono de %k.,%o se ha despedido de la vara de elfo de %k.,%o se despidió de la vara de elfo de %k.,%o heilutti hyvästit pelaajan %k haltiasauvalle.,%o à fait coucou à la baguette magique de %k.,%o integetett egy viszlátot %k Elf Pálcájának.,%o ha fatto ciao ciao allo scettro elfico di %k.,%o は %k のエルフのワンドに別れの挨拶をした。,%o 은(는) %k 의 엘프 지팡이를 보고 작별인사를 했다.,%o zwaaide afscheid van %k's elvenstaf.,%o vinket farvel til %ks alvestav.,%o pomachał@[ao_pl] na do widzenia elfiej różdżce %k,%o deu tchauzinho para o cetro élfico de %k.,%o disse adeuzinho para o cetro élfico de %k.,%o a facut cu mână toiagului lui %k.,Игрок %o узрел прощальный взмах эльфийского жезла игрока %k.,%o је рек@[ao_2_sr] збогом %k вилењачком штапићу.,%o vinkade farväl till %ks elviga stav.,"%o, %k tarafından delik deşik edildi.",%k помаха@[adj_1_ua] ельфійським посохом на прощання %o. +%o was pegged by %k's ethereal crossbow.,OB_MPCROSSBOW,,,,%o byl@[ao_cs] prostřelen@[ao_cs] éterickou kuší hráče %k.,%o blev stukket af %ks æteriske armbrøst.,%o von %ks Armbrustbolzen aufgespießt.,,%o kejlis de la etera arbalesto de %k.,A %o l@[ao_esp] ha flechado la ballesta etérea de %k.,A %o l@[ao_esp] flechó la ballesta etérea de %k.,%k ripusti %o paran eteerivarsijousellaan.,%o s'est fait@[e_fr] clouer par l'arbalète étherique de %k.,%o fel lett rögzítve %k Éteri Nyílpuskájának által.,%o è stato inchiodato dalla balestra eterea di %k.,%o は %k のイセリアルクロスボウで釘付けにされた。,%o 은(는) %k 의 유체 쇠뇌에 의해 처박혔다.,%o was vastgepind door %k's etherische kruisboog.,%o ble truffet av %ks eteriske armbrøst.,%o został@[ao_pl] przebit@[adj_pl] przez eteryczną kuszę %k,%o foi esmigalhad@[ao_ptb] pela besta etérea de %k.,,%o a fost prins de arbaleta celestă a lui %k.,Игрок %o изранен болтами эфирного арбалета игрока %k.,%o је упуц@[adj_2_sr] од стране %k етералног самострела.,%o blev fast av %ks eteriska armborst.,"%o, %k tarafından çivilendi.",%k насипа@[adj_1_ua] %o трохи магічних болтів. +%o was blasted a new one by %k's dragon claw.,OB_MPBLASTER,,,,%o poznal@[ao_cs] středověk drakospárem hráče %k.,%o blev sprængt en ny af %ks drageklo.,%o bekam %ks Drachenklaue zu spüren.,,%o estis diseksplodita de la drakokrifo de %k.,%o ha quedado bien jodid@[ao_esp] por la garra de dragón de %k.,%o quedó irreconocible por la garra de dragón de %k.,%k puhkoi %o parkaan uuden aukon lohikäärmeenkynnellään.,%o s'est fait flinguer par la griffe draconique de %k.,%o újszerűnek látszik %k Sárkány Karomjának köszönhetően.,A %o èstato aperto un buco nuovo dall'Artiglio di Drago di %k.,%o は %k のドラゴンクローで発破体験した。,%o 은(는) %k 의 용발톱에 의해 형태를 잃었다.,%o werd opengescheurd door %k's drakenklauw.,%o fikk en ny en av %ks drageklo.,%o został wysadzony nowy otwór przez %k,%o sentiu o poder da garra de dragão de %k.,,%o a fost aruncat în aer de gheara dragonului a lui %k.,Игрок %o получил новую форму драконьим когтем игрока %k.,Играчу %o је отворена нова рупа змајевском канџом играча %k.,%o blev skjuten på nytt av %ks drakklo.,"%o, %k tarafından patlatıldı.",%o отрима@[adj_1_ua] кігтедраконових вибухів від %k. +%o got sent down under by %k's hellstaff.,OB_MPSKULLROD,,,,Pod hráčem %o se propadla zem peklopalem hráče %k.,%o blev sendt ned under jorden af %ks helvedestav.,%o brach unter %ks Höllenrute zusammen.,,%o forsendiĝis sub de la inferbastono de %k.,%o se ha inclinado ante el bastón infernal de %k.,%o se inclinó ante el bastón infernal de %k.,%k lähetti %o paran maan syövereihin hornansauvallaan.,%o repose six pieds sous terre grâce au Bâton infernal de %k.,%o le lett küldve %k Pokolbotjának köszönhetően.,%o è stato mandato sottoterra dalla Staffa Infernale di %k.,%o は %k のヘルスタッフで冥界に送られた。,%o 은(는) %k 의 지옥지팡이에 의해 저승으로 날아갔다.,%o werd door %k's hellestaf naar beneden gestuurd.,%o ble sendt til helvete av %ks helvetesstav.,%o został@[ao_pl] zesłan@[adj_pl] pod piekielny kostur %k,%o foi mandad@[ao_ptb] pra baixo do solo pelo cajado infernal de %k.,,%o a fost trimis sub bastonul infernal al lui %k.,Игрок %o сослан в самый низ посохом ада игрока %k.,%o је укопан@[adj_1_sr] од стране пакленог штапа играча %k.,%o blev nedskjuten av %ks helvetesstång.,"%o, %k tarafından biçildi.",%o па@[adj_1_ua] в самі глибини від пекельного посоху %k. +%o was scorched to cinders by %k's phoenix rod.,OB_MPPHOENIXROD,,,,%o byl@[ao_cs] spálen@[ao_cs] na prach fénixovou holí hráče %k.,%o blev brændt til aske af %ks føniksstav.,%o wurde voin %ks Phönixstab verschmort.,,%o brulegiĝis en cindrojn de la feniksvergo de %k.,A %o l@[ao_esp] ha pulverizado el báculo del Fénix de %k.,A %o l@[ao_esp] pulverizó el báculo del Fénix de %k.,%k kärvensi %o paran tuhannen päreiksi feenikssauvallaan.,%o s'est fait@[e_fr] réduire en cendres par le Bâton du Phénix de %k.,%o halomra lett égve %k Főnix Rúdjának által.,%o è stato ridotto in cenere dal Bastone della Fenice di %k.,%o は %k のフェニックスロッドで焼かれた。,%o 은(는) %k 의 불사조 지팡이 덕에 검게 익었다.,%o werd door %k's feniksstaf tot sintels verschroeid.,%o ble svidd til aske av %ks føniksstav.,%o został@[ao_pl] spalon@[adj_pl] na popiół przez różdżkę feniksa %k,%o virou cinzas com o bastão da fênix de %k.,,%o a fost făcut cenușă de joarda phoenix a lui %k.,Игрок %o сожжён до пепла жезлом феникса игрока %k.,%o запаљен@[adj_1_sr] у пепео од стране шипке феникса играча %k.,%o blev bränd till aska av %ks fenixstav.,"%o, %k tarafından cayır cayır yakıldı.",Від %o залишився тільки попіл через жезл фенікса %k. +%o was bounced by %k's firemace.,OB_MPMACE,,,,%o byl@[ao_cs] odpálen@[ao_cs] žezlometem hráče %k.,%o blev kastet afsted af %ks ildspyd.,%o prallte an %ks Feuerkeule ab.,,%o estis resaltita de la fajroklabo de %k.,%o ha rebotado en la maza de fuego de %k.,%o rebotó en la maza de fuego de %k.,%k pomputti %o parkaa tulinuijallaan.,%o a rebondi@[e_fr] sur les balles de la Masse de Feu à %k.,%o pattant egy nagyot %k Tűzbuzogányának köszönhetően.,%o è stato spazzato via dalla Mazza del Fuoco di %k.,%o は %k のファイアメイスで飛ばされた。,%o 은(는) %k 의 투사철퇴의 포탄을 맞고 튕겨져 날아갔다.,%o werd door %k's vuurknots geraakt.,%o ble kastet av %ks ildkule.,%o został@[ao_pl] wybit@[adj_pl] przez buzdygan ognia %k,%o saiu pulando após ver a clava de fogo de %k.,,%o a fost aruncat de colo colo de buzduganul de foc al lui %k.,Игрок %o отбит огненной булавой игрока %k.,%o је ударен@[adj_1_sr] са ватреним буздованом играча %k.,%o blev utvisad av %ks eldstöt,"%o, %k tarafından ezildi.",%o вбили в землю вогняною булавою %k. +%o got clapped by %k's charged staff.,OB_MPPSTAFF,,,,%o byl@[ao_cs] profackován@[ao_cs] nabitou holí hráče %k.,%o blev klappet af %ks ladede stav.,%o bekam eine Klatsche durch %ks geladenen Stab.,,%o estis aplaŭdita de la ŝargita bastono de %k.,A %o l@[ao_esp] ha apaleado el bastón cargado de %k .,A %o l@[ao_esp] apaleó el bastón cargado de %k .,%k jyrisytti %o parkaa varatulla sauvallaan.,%o à été foudroyé@[e_fr] par le bâton chargé de %k.,%o csattant egy nagyot %k Feltöltött Botjának által.,%o è scoppiato a causa della staffa incantata di %k.,%o は %k の魔力を帯びた棒で暖かく迎えられた。,%o 은(는) %k 의 마법부가 지팡이를 얻어맞았다.,%o kreeg een klap van %k's opgeladen staf.,%o ble klappet av %ks ladede stav.,%o został@[ao_pl] trzepnięt@[adj_pl] naładowaną laską %k,%o tomou uma pancada do bastão carregado de %k.,,%o a fost tăiat de bastonul încărcat al lui %k.,Игрок %o отведал заряженного посоха игрока %k.,%o је потапшан@[adj_1_sr] напуњеним штапом играча %k.,%o fick en klapp av %ks laddade stav.,"%o, %k tarafından yakıldı.",%o перечепи@[adj_2_ua] через заряджену палицю %k. +%o was bled dry by %k's gauntlets.,OB_MPPGAUNTLETS,,,,Rukavicemi hráče %k nezůstala v těle hráče %o ani kapka krve.,%o blev udblødt af %ks handsker.,%o wurde von %ks Handschuhen ausgeblutet.,,%o sensangiĝis de la fergantoj de %k.,A %o l@[ao_esp] han dejado exangüe los guanteletes de %k.,A %o l@[ao_esp] dejaron exangüe los guanteletes de %k.,%k vuodatti %o paran kuiviin kintaillaan.,%o s'est fait@[e_fr] saigner à blanc par les gantelets de %k.,%k megtanította %o-t Páncélkesztyűbe dudálni.,Il sangue di %o è stato prosciugato dai guanti di %k.,%o は %k の篭手で血を絞り取られた。,%o 은(는) %k 의 마법부가 건틀릿에 의해 바싹 말랐다.,%o werd leeggebloed door %k's handschoenen.,%o ble tappet for blod av %ks hansker.,%o wykrwawił@[ao_pl] się przez rękawice %k,%o sangrou nas manoplas de %k.,,"%o a fost stors până la ultima picătură de sânge +de mănușile lui %k.",Игрок %o был обескровлен перчатками игрока %k.,%o је путпуно искрвари@[ao_1_sr] од рукавица играча %k.,%o blev blödd av %ks handskar.,"%o, %k tarafından kan kaybından kurutuldu.",%k висмокта@[adj_1_ua] дух %o через рукавиці. +%o was assaulted by %k's elven wand.,OB_MPPGOLDWAND,,,,%o byl@[ao_cs] napaden@[ao_cs] elfskou hůlkou hráče %k.,%o blev overfaldet af %ks elverstav.,%o wurde von %ks Elfenstab überwältigt.,,%o atakiĝis de la elfa sorĉbastono de %k.,%o ha sido asaltad@[ao_esp] por la vara de elfo de %k.,%o fue asaltad@[ao_esp] por la vara de elfo de %k.,%o joutui pelaajan %k haltiasauvan pahoinpitelemäksi.,%o à été assailli@[e_fr] par la baguette elfique de %k.,%k megbotozta %o az Elf Botjával.,%o è stato assalito dallo Scettro Elfico di %k.,%o は %k のエルフのワンドで襲われた。,%o 은(는) %k 의 마법부가 엘프 지팡이에 의해 사냥당했다.,%o werd aangevallen door %k's elvenstaf.,%o ble angrepet av %ks alvestav.,%o został@[ao_pl] zaatakowan@[adj_pl] przez elfią różdżkę %k,%o foi atacad@[ao_ptb] pelo cetro élfico de %k.,,%o a fost luat cu asalt de togaiul lui %k.,Игрок %o атакован эльфийским жезлом игрока %k.,%o је нападнут@[adj_1_sr] вилењачким штапом играча %k.,%o blev attackerad av %ks älvstav.,"%o, %k tarafından saldırıya uğradı.",%o бу@[adj_1_ua] атакований ельфійським посохом %k. +%o was shafted by %k's ethereal crossbow.,OB_MPPCROSSBOW,,,,%o byl@[ao_cs] proděravěn@[ao_cs] éterickou kuší hráče %k.,%o blev ramt af %ks æteriske armbrøst.,%o wurde von %ks Armbrustbolzen durchbohrt.,,%o akiris novan truon de etera arbalesto de %k.,%o ha sido encañonad@[ao_esp] por la ballesta etérea de %k.,%o fue encañonad@[ao_esp] por la ballesta etérea de %k.,%k joutui pelaajan %k eteerivarsijousen kepittämäksi.,%o s'est fait@[e_fr] transpercer par l'arbalète éthérique de %k.,%o megkóstolta %k Éteri Nyílpuskáját.,%o è stato impalato dalla balestra eterea di %k.,%o は %k のイセリアルクロスボウで押された。,%o 은(는) %k 의 마법부가 유체 쇠뇌에 의해 무뎌졌다.,%o werd door %k's etherische kruisboog geschaafd.,%o ble truffet av %ks eteriske armbrøst.,%o został@[ao_pl] wykiwan@[adj_pl] przez eteryczną kuszę %k,%o foi flechad@[ao_ptb] pela besta etérea de %k.,,"%o a fost pus la proțap de arbaleta celestă a lui +%k.",Игрок %o пробит эфирным арбалетом игрока %k.,%o је упуцан@[adj_1_sr] етеричним самострелом играча %k.,%o blev skjuten av %ks eteriska armborst.,"%o, %k tarafından şaftlandı.",%k проби@[adj_1_ua] %o магічним болтом. +%o was ripped apart by %k's dragon claw.,OB_MPPBLASTER,,,,%o byl@[ao_cs] roztrhnut@[ao_cs] naskrz drakospárem hráče %k.,%o blev flået i stykker af %ks drageklo.,%o wurde von der Drachenklaue zerrissen.,,%o disrompiĝis de la drakokrifo de %k.,A %o l@[ao_esp] ha desgarrado la garra de dragón de %k.,A %o l@[ao_esp] desgarró la garra de dragón de %k.,%k repi %o paran kappaleiksi lohikäärmeenkynnellään.,%o à été mis@[e_fr] en pièces par la griffe draconique de %k.,%o szét lett tépve %k Sárkány Karomja által.,%è stato fatto a brandelli dall'Artiglio di Drago di %k.,%o は %k のドラゴンの鉤爪でバラバラに引き裂かれた。,%o 은(는) %k 의 마법부가 용발톱에 갈기갈기 찢겨졌다.,%o werd uit elkaar gescheurd door %k's drakenklauw.,%o ble revet i filler av %ks drageklo.,%o został@[ao_pl] rozerwan@[adj_pl] przez smoczy pazur %k,%o foi cortad@[ao_ptb] pela garra de dragão de %k.,,%k a fost făcut bucăți de gheara lui %k.,Игрок %o разорван драконьим когтём игрока %k.,%o је поцепан@[adj_1_sr] змајевим канџама играча %k.,%o blev sliten i bitar av %ks drakklo.,"%o, %k tarafından parçalara ayrıldı.",%o розірвало кігтем дракона %k. +%k poured the hellstaff on %o.,OB_MPPSKULLROD,,,,Hráč %k vylil svůj peklopal na hráče %o.,%k hældte helvedesstaven ud over %o.,%k ließ den Höllenregen auf %o los.,,%k ŝutas la inferbastonon sur %o.,%k ha vertido su bastón infernal en %o.,%k vertió su bastón infernal en %o.,%k vuodatti hornansauvansa %o parkaan.,%k à versé toute la rage des enfers sur %o.,%o nem hozott esernyőt %o Pokolbot zápora ellen.,%k ha fatto sgorgare la sua Staffa Infernale su %o.,%o は %k にヘルスタッフを %p 注ぎ込まれた。,%k의 마법부가 지옥지팡이가 쏟아붓는 비를 %o 이(가) 맞았다.,%k liet de helregen los op %o.,%k helte helvetesstaven over %o.,%k polał@[ao_pl] swoim piekielnym kosturem %o,%k usou seu cajado infernal no %o.,,%k a vărsat bastonul infernal pe %o.,Игрок %k залил игрока %o горячим дождём при помощи посоха ада.,%k је просипа@[ao_1_sr] пламени штап на %o.,%k hällde helvetesstången på %o.,"%o, %k tarafından yakıldı.",%k залив %o пекельним дощем. +%o was burned down by %k's phoenix staff.,OB_MPPPHOENIXROD,,,,%o byl@[ao_cs] vyhořen@[ao_cs] fénixovou holí hráče %k.,%o blev brændt ned af %ks Føniks stav.,%o wurde von %ks Phönixstab verbrannt.,,%o torĉiĝis de la feniksvergo de %k.,A %o l@[ao_esp] ha calcinado el báculo del Fénix de %k.,A %o l@[ao_esp] calcinó el báculo del Fénix de %k.,%k poltti %o paran feenikssauvallaan.,%o à été incinéré@[e_fr] par le Bâton du Phénix de %k.,%o elégett %k Főnix Botjának által.,%o è stato incendiato dal Bastone della Fenice di %k.,%o は %k のフェニックスロッドで焼き滅ぼされた。,%o 은(는) %k 의 마법부가 불사조 지팡이에 의해 화장당했다.,%o werd afgebrand door %k's feniksstaf.,%o ble brent ned av %ks føniksstav.,%o został@[ao_pl] spalon@[adj_pl] przez różdżkę feniksa %k,%o foi queimad@[ao_ptb] pelo bastão da fênix de %k.,,%o a fost ars complet de joarda lui %k.,Игрок %o сожжён жезлом феникса игрока %k.,%o је изгоре@[ao_1_sr] шипком феникса играча %k.,%o brändes ner av %ks Fenix-stav.,"%o, %k tarafından yakıldı.",%o згорі@[adj_1_ua] через жезл фенікса %k. +%o was squished by %k's giant mace sphere.,OB_MPPMACE,,,,%o byl@[ao_cs] rozmačkán@[ao_cs] obrovskou žezlometnou koulí hráče %k.,%o blev mast af %ks ildspyd kugle.,%o wurde von %ks Feuerkeule zerquetscht.,,%o premiĝis de la grandega klubsfero de %k.,A %o l@[ao_esp] ha aplastado una esfera gigante de la maza de %k.,A %o l@[ao_esp] aplastó una esfera gigante de la maza de %k.,%k liiskasi %o paran jättiläisnuijapallollaan.,%o s'est fait@[e_fr] écraser par la balle de Masse géante de %k.,%o össze lett nyomva %k hatalmas buzogány gömbje által.,%o è stato spiaccicato da una sfera gigante della Mazza del Fuoco di %k.,%o は %k の巨大なメイススフィアで潰された。,%o 은(는) %k 의 마법부가 투사철퇴가 뿜은 거대포탄에 의해 납작해졌다.,%o werd verpletterd door %k's reusachtige strijdknots.,%o ble knust av %ks gigantiske muskatblomstkule.,%o został@[ao_pl] zmiażdżon@[adj_pl] przez ogromną kulę z buzdygana %k,%o foi esmagad@[ao_ptb] pela esfera de clava gigante de %k.,,"%o a fost strivit de globul buzduganului +lui %k.",Игрок %o раздавлен огромной сферой из огненной булавы %k.,%o је смрвљен@[adj_1_sr] од стане огромном сферско буздована играча %k.,%o blev mosad av %ks gigantiska eldstötsfär.,"%o, %k tarafından ezildi.",%k розчави@[adj_1_ua] %o велитенською вогняною сферою. +,,Hexen,,,,,,,,,,,,,,,,,,,,,,,,,, +,,Pickup,,,,,,,,,,,,,,,,,,,,,,,,,, +Blue Mana,TXT_MANA_1,,,,Modrá mana,Blå Mana,Blaues Mana,,Blua Manao,Maná Azul,,Sininen mana,Mana Bleu,Kék Mana,Mana blu,青マナ,청색 마나,Blauwe Mana,Blå Mana,Niebieska Mana,Mana Azul,,Mană Albastră,Синяя мана,Плава мана,Blå Mana,Mavi Mana,Синя мана +Green Mana,TXT_MANA_2,,,,Zelená mana,Grøn Mana,Grünes Mana,,Verda Manao,Maná Verde,,Vihreä mana,Mana Vert,Zöld Mana,Mana verde,緑マナ,녹색 마나,Groene Mana,Grønn Mana,Zielona Mana,Mana Verde,,Mană Verde,Зелёная мана,Зелена мана,Grön Mana,Yeşil Mana,Зелена мана +Combined Mana,TXT_MANA_BOTH,,,,Smíšená mana,Kombineret Mana,Kombiniertes Mana,,Kuna Manao,Maná Combinado,,Yhdistetty mana,Mana Combiné,Kombinált Mana,Mana misto,複合マナ,윰합된 마나,Gecombineerde Mana,Kombinert mana,Połączona Mana,Mana Combinado,,Mană Mixtă,Общая мана,Комбинована мана,Kombinerad Mana,Kombine Mana,Комбінована мана +Steel Key,TXT_KEY_STEEL,,,,Ocelový klíč,Stålnøgle,Stahlschlüssel,Ατσάλινο Κλειδί,Ŝtala Ŝlosilo,Llave de Acero,,Teräsavain,Clé d'Acier,Acél Kulcs,Chiave d'acciaio,鋼の鍵,강철 열쇠,Stalen Sleutel,Stålnøkkel,Stalowy Klucz,Chave de Aço,,Cheia din Oțel,Стальной ключ,Челични кључ,Stålnyckel,Çelik Anahtar,Сталевий ключ +Cave Key,TXT_KEY_CAVE,,,,Klíč od jeskyně,Hule-nøgle,Höhlenschlüssel,,Kavern-Ŝlosilo,Llave de la Caverna,,Luola-avain,Clé de la Cave,Barlang Kulcs,Chiave della caverna,洞窟の鍵,동굴 열쇠,Grotsleutel,Hulenøkkel,Klucz do Jaskini,Chave da Caverna,,Cheia Peșterii,Пещерный ключ,Пећински кључ,Grottnyckel,Mağara Anahtarı,Печерний ключ +Axe Key,TXT_KEY_AXE,,,,Sekyrový klíč,Økse-nøgle,Axtschlüssel,,Hakil-Ŝlosilo,Llave de Hacha,,Kirvesavain,Clé de la Hache,Fejsze Kulcs,Chiave dell'ascia,斧の鍵,도끼 열쇠,Bijlsleutel,Økse-nøkkel,Klucz-topór,Chave do Machado,,Cheia Topor,Топор-ключ,Кључ секира,Yxnyckel,Balta Anahtarı,Сокирний ключ +Fire Key,TXT_KEY_FIRE,,,,Ohnivý klíč,Ild-nøgle,Feuerschlüssel,,Fajro-Ŝlosilo,Llave de Fuego,,Tuliavain,Clé du Feu,Tűz Kulcs,Chiave del fuoco,炎の鍵,불 열쇠,Vuursleutel,Ildnøkkel,Ognisty Klucz,Chave do Fogo,,Cheia de Foc,Огненный ключ,Огњени кључ,Eldnyckel,Yangın Anahtarı,Вогняний ключ +Emerald Key,TXT_KEY_EMERALD,,,,Smaragdový klíč,Smaragdnøgle,Smaragdschlüssel,,Smerelda Ŝlosilo,Llave Esmeralda,,Smaragdiavain,Clé d'Emeraude,Smaragd Kulcs,Chiave di smeraldo,翠玉の鍵,에메랄드 열쇠,Smaragden Sleutel,Smaragdnøkkel,Szmaragdowy Klucz,Chave de Esmeralda,,Cheia din Smarald,Изумрудный ключ,Смарагдни кључ,Smaragdnyckel,Zümrüt Anahtar,Смарагдовий ключ +Dungeon Key,TXT_KEY_DUNGEON,,,,Klíč od žaláře,Dungeon-nøgle,Kerkerschlüssel,,Karcer-Ŝlosilo,Llave del Calabozo,,Tyrmän avain,Clé du Donjon,Várbörtön Kulcs,Chiave del sotterraneo,迷宮の鍵,지하감옥 열쇠,Kerkersleutel,Dungeon-nøkkel,Klucz do Lochu,Chave da Masmorra,,Cheia Temniței,Ключ от подземелья,Кључ од лагума,Kerker-nyckel,Zindan Anahtarı,Ключ від підземелля +Silver Key,TXT_KEY_SILVER,,,,Stříbrný klíč,Sølvnøgle,Silberschlüssel,Ασυμένιο Κλειδί,Arĝenta Ŝlosilo,Llave de Plata,,Hopea-avain,Clé d'Argent,Ezüst Kulcs,Chiave d'argento,銀の鍵,은 열쇠,Zilveren Sleutel,Sølvnøkkel,Srebrny Klucz,Chave de Prata,,Cheia din Argint,Серебряный ключ,Сребрни кључ,Silvernyckel,Gümüş Anahtar,Срібний ключ +Rusted Key,TXT_KEY_RUSTED,,,,Zrezivělý klíč,Rustet nøgle,Rostiger Schlüssel,Σκουριασμένο Κλειδί,Rusta Ŝlosilo,Llave Oxidada,,Ruosteinen avain,Clé Rouillée,Rozsdás Kulcs,Chiave arrugginita,錆びた鍵,녹슨 열쇠,Geroeste Sleutel,Rustet nøkkel,Zardzewiały Klucz,Chave Enferrujada,,Cheia Ruginită,Ржавый ключ,Зарђали кључ,Rostad nyckel,Paslı Anahtar,Іржавий ключ +Horn Key,TXT_KEY_HORN,,,,Parožní klíč,Hornnøgle,Hornschlüssel,,Hup-Ŝlosilo,Llave de Cuerno,,Sarviavain,Clé Corne,Szarv Kulcs,Chiave del corno,角の鍵,뿔 열쇠,Hoornsleutel,Horn-nøkkel,Rogowy Klucz,Chave do Chifre,,Cheia Corn,Роговой ключ,Рогати кључ,Horn-nyckel,Korna Anahtarı,Ріговий ключ +Swamp Key,TXT_KEY_SWAMP,,,,Klíč od bažiny,Sumpnøgle,Sumpfschlüssel,,Marĉo-Ŝlosilo,Llave del Pantano,,Suoavain,Clé des Marécages,Mocsár Kulcs,Chiave della palude,沼の鍵,늪지대 열쇠,Moerassleutel,Sumpnøkkel,Bagienny Klucz,Chave do Pântano,,Cheia Mlaștinii,Болотный ключ,Мочварни кључ,Träsknyckel,Bataklık Anahtarı,Болотний ключ +Castle Key,TXT_KEY_CASTLE,,,,Klíč od hradu,Slotsnøgle,Burgschlüssel,,Kastel-Ŝlosilo,Llave del Castillo,,Linnan avain,Clé du Château,Kastély Kulcs,Chiave del castello,城の鍵,성 열쇠,Kasteelsleutel,Slottsnøkkel,Klucz do Zamku,Chave do Castelo,,Cheia Castelului,Ключ от замка,Кључ од замка,Slottsnyckel,Kale Anahtarı,Ключ від фортеці +Icon of the Defender,TXT_ARTIINVULNERABILITY2,,,,Obráncova ikona,Ikon af forsvareren,Ikone des Verteidigers,,Ikono de la Defendanto,Icono del Defensor,Ícono del Defensor,Puolustajan ikoni,Icône du Défenseur,Védelmező Ikonja,Icona del difensore,守護者の像,수호의 성상,Symbool van de Verdediger,Forsvarerens ikon,Ikona Obrońcy,Ícone do Defensor,,Imaginea Apărătorului,Символ защитника,Симбол браниоца,Försvararens ikon,Savunucunun Simgesi,Символ захисника +Dark Servant,TXT_ARTISUMMON,,,,Temný služebník,Mørk tjener,Dunkler Diener,,Malluma Servanto,Sirviente Oscuro,,Pimeä palvelija,Serviteur Noir,Árny Szolga,Servitore oscuro,闇の従者,어둠의 하인,Donkere Dienaar,Mørk tjener,Mroczny Sługa,Servo Negro,,Servitor Întunecat,Тёмный слуга,Мрачни слуга,Mörk tjänare,Karanlık Hizmetkar,Темний слуга +Porkalator,TXT_ARTIEGG2,,,,Vepřovitel,,,,Porkigilo,Porcinador,,Sikaannuttaja,Porcificateur,Ártányátok,Porchificatore,ポークレイター,돈육기,,,Schabowator,Porquificador,,Porcolator,Свиновизатор,Свињатор,,,Захрюкувач +Flechette,TXT_ARTIPOISONBAG,,,,Střelka,,,,Flakono,,,,Fléchette,Flakon,Fiaschetta,フレチェット,플레셰트,,,Flaszka,,,Flacon,Флешетта,Бочица,,,Флешета +Banishment Device,TXT_ARTITELEPORTOTHER,,,,Vyhošťovač,Forvisningsanordning,Verbannungsgerät,,Forpelilo,Dispositivo de Desvanecimiento,,Häivytyskoje,Outil de Banissement,Száműző,Artifatto dell'esilio,追放のデバイス,소멸 장치,Verbanningsapparaat,Forvisningsanordning,Urządzenie Wygnania ,Dispositivo do Banimento,,Dispozitiv al Alungării,Устройство изгнания,Амблем прогањања,Förvisningsenhet,Sürgün Cihazı,Пристрій заслання +Boots of Speed,TXT_ARTISPEED,,,,Běhuté boty,Støvler af hastighed,Turbo-Stiefel,,Botoj de Rapideco,Botas de Velocidad,,Ripeyssaappaat,Bottes de Célérité,Sebesség Cipője,Stivali della velocità,素早さの靴,속도의 신발,Snelheidslaarzen,Støvler av fart,Buty Szybkości,Botas da Velocidade,,Bocancii Vitezei,Сапоги-скороходы,Брзинске чизме,Snabbhetens stövlar,Hız Çizmeleri,Семимильні чоботи +Krater of Might,TXT_ARTIBOOSTMANA,,,,Kalich síly,Krater of Might,Kelch der Macht,,Kratero de Potenco,Vasija de Fuerza,,Mahtikrateeri,Cratère de Pouvoir,Hatalom Krátere,Calice della forza,魔力の盃,힘의 향로,Beker van Macht,Krater av makt,Czara mocy,Cálice do Poder,,Pocal al Puterii,Чаша могущества,Чаша силе,Mäktighetens krater,Kudret Krateri,Чаша міці +Dragonskin Bracers,TXT_ARTIBOOSTARMOR,,,,Dračí nátepníky,Drageskindsarmbøjler,Drachenhaut-Armschutz,,Brakbendo el Drakhaŭto,Brazaletes de piel de Dragón,,Lohikäärmeennahkarannesuojat,Bracelets en Peau de Dragon,Sárkánybőr Karkötők,Bracciali in pelle di drago,竜皮の小手,용가죽 팔찌,Drakenhuidbescherming,Dragehud-bindinger,Karwasze ze Smoczej Skóry,Braçadeiras de Pele de Dragão,,Brățări din Piele de Dragon,Наручи из драконьей кожи,Наруквице од змајеве коже,Drakskinnsarmbågar,Ejderha Derisi Bilezikler,Наручі зі шкіри дракона +Disc of Repulsion,TXT_ARTIBLASTRADIUS,,,,Kotouč odpuzení,Skive af frastødning,Rückstoßscheibe,,Disko de Repelado,Disco de Repulsión,,Karkotuskiekko,Disque de Répulsion,Visszaverés Lemeze,Disco della repulsione,反発の円盤,방탄의 원반,Schijf van Afstoting,Frastøtelsesskive,Dysk Odpychania,Disco da Repulsão,,Disc al Repulsiei,Диск отторжения,Диск одбијања,Skiva av avstötning,İtme Diski,Диск відштовхування +Mystic Ambit Incant,TXT_ARTIHEALINGRADIUS,,,,Tajemný čár koljdoucí,Mystic Ambit Incant,Verbannungsgerät,,Sorĉo de Mistika Sfero,Encanto de Ámbito Místico,,Mystisen piirin loitsu,Incantation Mystique,Misztikus Mágialista,Confine mistico,魅知国の秘法,신비 영역의 주문,,Mystic Ambit-besvergelse,Inkantancja Mistycznego Kręgu,Encanto Místico,,Pergament Mistic,Чары магического единства,Чаролија магичног јединства,,Mistik Ambit Büyüsü,Закляття містичної області +Yorick's Skull,TXT_ARTIPUZZSKULL,,,,Jorikova lebka,Yoricks kranium,Yoricks Schädel,,Kranio de Yorick,Calavera de Yorick,,Yorickin kallo,Crâne de Yorick,Yorick Koponyája,Teschio di Yorick,ヨリックの髑髏,요릭의 두개골,Yorick's Schedel,Yoricks hodeskalle,Czaszka Yoricka,Caveira de Yorick,,Craniul lui Yorick,Череп Йорика,Јорикова лобања,Yoricks skalle,Yorick'in Kafatası,Череп Йоріка +Heart of D'sparil,TXT_ARTIPUZZGEMBIG,,,,Srdce D'Sparila,D'sparils hjerte,D'Sparils Herz,,Koro de D'sparil,Corazón de D'Sparil,,D'Sparilin sydän,Cœur de D'Sparil,D'Sparil szíve,Cuore di d'sparil,デ'スパリルの心,드'스파릴의 심장,Hart van D'sparil,D'Sparils hjerte,Serce D'Sparila,Coração de D'Sparil,,Inima lui D'Sparil,Сердце Д'Спарила,Д'Спарилино срце,D'sparils hjärta,D'sparil'in Kalbi,Серце Д'Спаріла +Ruby Planet,TXT_ARTIPUZZGEMRED,,,,Rubínová planeta,Rubinplanet,Rubinplanet,,Rubena Planedo,Planeta Rubí,,Rubiiniplaneetta,Planète de Rubis,Rubin Bolygó,Pianeta di rubino,ルビーの宝石,루비 행성석,Robijnrode Planeet,Rubinplaneten,Rubinowa Planeta,Planeta Rubi,,Planetă din Rubin,Рубиновая планета,Планета рубина,Rubinplanet,Yakut Gezegeni,Рубінова планета +Emerald Planet,TXT_ARTIPUZZGEMGREEN1,,,,Smaragdová planeta,Smaragdplanet,Smaragdplanet,,Smeralda Planedo,Planeta Esmeralda,,Smaragdiplaneetta,Planète d'Emeraude,Smaragd Bolygó,Pianeta di smeraldo,エメラルドの宝石,에메랄드 행성석 (1),Smaragdgroene Planeet,Smaragdplaneten,Szmaragdowa Planeta,Planeta Esmeralda,,Planetă din Smarald,Изумрудная планета,Смарагдна планета,Smaragdplanet,Zümrüt Gezegen,Смарагдова планета +Emerald Planet,TXT_ARTIPUZZGEMGREEN2,,,,Smaragdová planeta,Smaragdplanet,Smaragdplanet,,Smeralda Planedo,Planeta Esmeralda,,Smaragdiplaneetta,Planète de Saphir,Smaragd Bolygó,Pianeta di smeraldo,エメラルドの宝石,에메랄드 행성석 (2),Smaragdgroene Planeet,Smaragdplaneten,Szmaragdowa Planeta,Planeta Esmeralda,,Planetă din Smarald,Изумрудная планета,Смарагдна планета,Smaragdplanet,Zümrüt Gezegen,Смарагдова планета +Sapphire Planet,TXT_ARTIPUZZGEMBLUE1,,,,Safírová planeta,Safirplanet,Saphirplanet,,Safira Planedo,Planeta Zafiro,,Safiiriplaneetta,Planète de Saphir,Zafír Bolygó,Pianeta di zaffiro,サファイアの宝石,사파이어 행성석 (1),Saffierblauwe Planeet,Safirplaneten,Szafirowa Planeta,Planeta Safira,,Planetă din Safir,Сапфировая планета,Сафирна планета,Safirplanet,Safir Gezegen,Сапфірова планета +Sapphire Planet,TXT_ARTIPUZZGEMBLUE2,,,,Safírová planeta,Safirplanet,Saphirplanet,,Safira Planedo,Planeta Zafiro,,Safiiriplaneetta,Planète de Saphir,Zafír Bolygó,Pianeta di zaffiro,サファイアの宝石,사파이어 행성석 (2),Saffierblauwe Planeet,Safirplaneten,Szafirowa Planeta,Planeta Safira,,Planetă din Safir,Сапфировая планета,Сафирна планета,Safirplanet,Safir Gezegen,Сапфірова планета +Daemon Codex,TXT_ARTIPUZZBOOK1,,,,,,,,Kodekso de Demono,Códice del Demonio,,Daemon-koodeksi,Codex Démoniaque,Démon Kódex,Codice Demoniaco ,デーモンの写本,악마의 고문서,,,Demoniczny Kodeks,Códice Demoníaco,,Codexul Demonilor,Демонический кодекс,Демонски кодекс,,,Демонічний кодекс +Liber Oscura,TXT_ARTIPUZZBOOK2,,,,,,,,,,,,,,,オスキュラ公文書,어둠의 자유서,,,Liber Oscura,,,,Либер Оскура,Либер Оскура,,,Лібер Оскура +Flame Mask,TXT_ARTIPUZZSKULL2,,,,Plamenná maska,Flammemaske,Flammenmaske,,Flamomasko,Máscara de llamas,,Liekkinaamio,Masque de Flammes,Láng Maszk,Maschera delle fiamme,炎の仮面,화염의 가면,Vuurmasker,Flammemaske,Maska Płomieni,Máscara das Chamas,,Mască de Foc,Маска пламени,Маска пламена,Flam-mask,Alev Maskesi,Полум'яна маска +Glaive Seal,TXT_ARTIPUZZFWEAPON,,,,Glévská pečeť,Glasur-segl,Schwetsiegel,,Sigelo de Glavo,Sello de Espada,,Miekkasinetti,Sceau du Glaive,Pallos Pecsét,Sigillo della brando,グレイブシール,밀폐된 칼날,Lanszegel,Glaive segl,Pieczęć Glewii,Selo do Gládio,,Sigiliu Spadă,Печать воителя,Војников печат,Glasögonsegel,Glaive Mühür,Воїнська печатка +Holy Relic,TXT_ARTIPUZZCWEAPON,,,,Svatá relikvie,Hellig relikvie,Heiliges Relikt,,Sankta Relikvo,Santa Reliquia,,Pyhä reliikki,Relique Sacrée,Szent Ereklye,Reliquia sacra,聖遺物,신성한 유물,Heilige Relikwie,Hellig relikvie,Święta Relikwia,Relíquia Sagrada,,Relicvă Sfântă,Святая реликвия,Света реликвија,Heliga reliker,Kutsal Emanet,Свята реліквія +Sigil of the Magus,TXT_ARTIPUZZMWEAPON,,,,Mágovo sigilium,Magus' segl,Symbol des Magiers,,Sigelo de la Mago,Emblema del Mago,,Taikurin sinetti,Sceau du Mage,Mágus Pecsétje,Suggello del magus,メイガスの印章,마거스의 인장,Sigaar van de Magus,Magusens segl,Emblemat Maga,Sigilo do Mago,,Sigiliul Magului,Печать Мага,Чаробњаков симбол,Magikerns sigill,Büyücünün Sigil'i,Знак магів +Clock Gear,TXT_ARTIPUZZGEAR,,,,Ozubené kolečko,Urværk,Zahnrad,,Dentrado de Horloĝo,Engranaje de reloj,,Kellonratas,Rouage d'Horloge,Óra Szerkezet,Ingranaggio d'orologio,時計の歯車,시계 톱니바퀴,Kloktandwiel,Klokkeutstyr,Mechanizm Zegara,Engrenagem de Relógio,,Mecanism Ceas,Часовая шестерня,Сатни зупчаник,Klockan växel,Saat Dişlisi,Механічна шестерня +You Cannot Use This Here,TXT_USEPUZZLEFAILED,,,,Zde se tento předmět použít nedá,Du kan ikke bruge dette her,Das kannst du hier nicht benutzen,,Vi ne povas uzi ĉi tion ĉi tie.,No puedes usar esto aquí,,Et voi käyttää tätä tässä,Vous ne pouvez pas utiliser cela ici.,Ezt Itt Nem Használhatod,Non puoi usare questo oggetto qui,ここでは使用できない,이것은 여기에 사용할 수 없다,Dat kan je hier niet gebruiken,Du kan ikke bruke dette her,Nie możesz użyć tego tutaj,Você não pode usar isso aqui,Não podes usar isto aqui,Nu Poți Folosi Asta Aici,Здесь это невозможно использовать,Ово се не може користити овде,Du kan inte använda detta här,Bunu Burada Kullanamazsınız,Ви не можете використати тут це +Mesh Armor,TXT_ARMOR1,,,Mesh Armour,Kroužkové brnění,,Kettenrüstung,,Marŝkiraso,Armadura de Malla,,Rengashaarniska,Armure de Mailles,Háló Páncél,Maglia metallica,鎖帷子,사슬 갑옷,Maliënkolder,Nettrustning,Kolczuga,Armadura de Malha,,Armură din Zale,Кольчуга,Верижњача,Nätrustning,Örgü Zırh,Кольчуга +Falcon Shield,TXT_ARMOR2,,,,Sokolí štít,Falke-skjold,Falkenschild,,Falko-Ŝildo,Escudo de Halcón,,Haukkakilpi,Bouclier du Faucon,Sólyom Pajzs,Scudo del falco,鷹の盾,팔콘 방패,Valkenschild,Falkeskjold,Sokola Tarcza,Escudo do Falcão,,Scut Șoim,Соколиный щит,Соколов штит,Falken-sköld,Falcon Kalkanı,Соколиний щит +Platinum Helmet,TXT_ARMOR3,,,,Platinová helma,Platin-hjelm,Platinhelm,,Platena Kasko,Casco de Platino,,Platinakypärä,Casque de Platine,Platina Sisak,Elmo di platino,白金の兜,백금 투구,Platina Helm,Platinahjelm,Platynowy Hełm,Capacete de Platina,,Coif de Platină,Платиновый шлем,Шлем од платине,Platinahjälm,Platin Kask,Платиновий шолом +Amulet of Warding,TXT_ARMOR4,,,,Amulet uhýbání,Amulet af afværge,Wachamulett,,Amuleto de Gardado,Amuleto de Guarda,,Suojelusamuletti,Amulette de Protection,Oltalom Amulettje,Amuleto di protezione,回避の護符,수호의 부적,Amulet van Bescherming,Amulett av beskyttelse,Amulet Ochrony,Amuleto da Proteção,,Amuleta Protecției,Амулет стража,Амулет страже,Amulett för skydd,Korunma Tılsımı,Амулет вартового +Timon's Axe,TXT_WEAPON_F2,,,,Timonova sekera,Timons økse,Timons Axt,,Hakilo de Timon,Hacha de Timón,,Timonin kirves,Hache de Timon,Timon Baltája,Ascia di timon,タイモンの斧,티몬의 도끼,Timon's Bijl,Timons øks,Topór Timona,Machado de Timon,,Toporul lui Timon,Топор Тимона,Тимонова секира,Timons yxa,Timon'un Baltası,Тімонова сокира +Hammer of Retribution,TXT_WEAPON_F3,,,,Kladivo odplaty,Gengældelsens hammer,Hammer der Rache,,Martelo de Repago,Martillo de Retribución,,Koston vasara,Marteau de la Rétribution,Kárhozat Kalapácsa,Martello del castigo,報復の金槌,징벌의 망치,Hamer der Vergelding,Gjengjeldelsens hammer,Młot Odkupienia,Martelo da Retribuição,,Ciocanul Salvării,Молот возмездия,Чекић одмазде,Hämndhammaren,İntikam Çekici,Молот відплати +Quietus Assembled,TXT_WEAPON_F4,,,,Složený Tišitel,Forløser samlet,Erlöser komplettiert,,Kvietus' Muntita,Quietus Ensamblado,,Quietus koottuna,Quietus Assemblée,Némusz Összerakva,Quietus assemblato,組み立てた 死滅の剣,완성된 종언의 검,Quietus in elkaar gezet,Quietus samlet,Złożony Uciszacz,Quietus Montada,,Argument Final Asamblat,Последний довод собран воедино,Самрт је сабрана,Quietus monterad,Quietus Birleştirildi,Упокій зібрано воєдино +Serpent Staff,TXT_WEAPON_C2,,,,Hadí hůl,Slange-stav,Schlangenstab,,Serpentbastono,Vara de Serpiente,,Käärmesauva,Sceptre du Serpent,Kígyó Bot,Bastone del serpente,蛇の杖,뱀 지팡이,Slangenstaf,Slangestav,Laska Węży,Cetro da Serpente,,Bastonul Șarpelui,Змеиный посох,Змијски штап,Ormens stav,Yılan Asa,Посох змія +Firestorm,TXT_WEAPON_C3,,,,Ohnivá bouře,Ildstorm,Feuersturm,,Fajroŝtormo,Tormenta de Fuego,,Tulimyrsky,Tempête de Feu,Tűzvihar,Tempesta di fuoco,ファイアストーム,화염폭풍,Vuurstorm,Ildstorm,Burza Ognia,Tempestade-de-Fogo,,Furtună de Foc,Огненный шторм,Огњена олуја,Eldstorm,Ateş Fırtınası,Вогняний шторм +Wraithverge Assembled,TXT_WEAPON_C4,,,,Složený Zjevitel,Spirit Bringer samlet,Geisterbringer komplettiert,,Fantomkruc' Muntita,Báculo Fantasmal Ensamblado,Vara Fantasmal Ensamblada,Haamusauva koottuna,Verge Phantasmale Assemblée,Bosszúbot Összerakva,Verga Sconfinaspettri assemblata,組み立てた レイスバージ,완성된 사령의 십자가,Schimroede in elkaar gezet,Wraithverge samlet,Złożony Widmoskraj,Cajado Fantasma Montado,,Toiag Stafie Asamblat,Жезл духов собран воедино,Жезло утвара је сабрано,Wraithverge monterad,Wraithverge Birleştirildi,Символ Мари зібрано воєдино +Frost Shards,TXT_WEAPON_M2,,,,Ledové střepy,Frostskår,Frostsplitter,,Frostfragmentoj,Fragmentos de Escarcha,,Pakkassirpaleet,Eclats de Givre,Fagyos Szilánkok,Frantumi gelati,フロスト シャード,얼음 파편,Vorstscherven,Frostskår,Lodowe Odłamki,Fragmentos de Geada,,Cioburi de Gheață,Ледяные осколки,Ледене крхотине,Frostskärvor,Buz Kırıkları,Льодяні уламки +Arc of Death,TXT_WEAPON_M3,,,,Jiskry smrti,Dødens bue,Todesblitz,,Arko de Morto,Arcos de la Muerte,,Kuolonkaari,Foudre Mortelle,Halál Boltíve,Arco della morte,死の円弧,죽음의 번갯불,Doodsboog,Dødens bue,Łuk Śmierci,Arcos da Morte,,Izvorul Morții,Дуга смерти,Лук смрти,Dödsbåge,Ölüm Arkı,Арка смерті +Bloodscourge Assembled,TXT_WEAPON_M4,,,,Složený Krvehrom,Blodgisel samlet,Blutgeißel komplettiert,,Sangskurĝ' Muntita,Plaga Sangrienta ensamblada,,Veripiiska koottuna,Fléau Sanglant Assemblé,Vérkorbács Összerakva,Flagello di Sangue assemblato,組み立てた 天罰,완성된 피의 재앙,Bloedgesel in elkaar gezet,Bloodscourge samlet,Złożona Krwioplaga,Flagelo de Sangue Montado,,Flagel Sângeros Asamblat,Кровавый бич собран воедино,Крвави бич је сабран,Bloodscourge monterad,Bloodscourge Birleştirildi,Кривава Кара зібрана воєдино +A weapon piece! This is your lucky day!,TXT_WEAPONPIECE,,,,Část zbraně! Dnes je tvůj šťastný den!,Et våbenstykke! Dette er din heldige dag!,Ein Waffensegment. Das ist dein Glückstag!,,Peco de armilo! Estas via bonŝanca tago!,¡Una pieza de un arma! ¡Es tu día de suerte!,,Aseen osa! Tämä on onnenpäiväsi!,Une pièce d'arme! C'est votre jour de chance!,Egy fegyver darab! Szerencés napod van!,Il frammento di un'arma! È il tuo giorno fortunato! ,武器の一片! 今日は吉日だ!,무기의 한 조각이다! 운수 좋은 날인 것 같다!,Een wapenstuk! Dit is je geluksdag!,En våpendel! Dette er lykkedagen din!,Część broni! To twój szczęśliwy dzień!,Um fragmento de arma! Esse é o seu dia de sorte!,Um fragmento de arma! Este é o teu dia de sorte!,O piesă din super armă! E ziua ta norocoasă!,Часть оружия! Сегодня ваш счастливый день!,Део оружја! Данас Вам је срећан дан!,En vapendel! Detta är din lyckodag!,Bir silah parçası! Bugün şanslı gününüz!,Частина зброї! Та ви щасливчик! +Segment of Quietus,TXT_QUIETUS_PIECE,,,,Část Tišitele,Segment af Forløseren,Segment des Erlösers,,Segmento de Kvietus',Segmento de Quietus,,Quietuksen osa,Segment de Quietus,Darab a Némuszból,Parte del Quietus,死滅の剣の切片,종언의 검 조각,Segment van Quietus,Segment av Quietus,Fragment Uciszacza,Segmento de Quietus,,Fragment din Argumentul Final,Часть последнего довода,Део Самрти,Segment av Quietus,Quietus'un bir bölümü,Частина Упокою +Segment of Wraithverge,TXT_WRAITHVERGE_PIECE,,,,Část Zjevitele,Segment af Spirit Bringer,Segment des Geisterbringers,,Segmento de Fantomkruc',Segmento del Báculo Fantasmal,,Haamusauvan osa,Segment de la Verge Phantasmale,Darab a Bosszúbotból,Parte della Verga Sconfinaspettri,レイスバージの切片,사령의 십자가 조각,Segment van Schimroede,Segment av Wraithverge,Fragment Widmoskraju,Segmento do Cajado Fantasma,,Fragment din Toiagul Stafie,Часть жезла духов,Део Жезла утвара,Segment av Wraithverge,Wraithverge'in Segmenti,Частина Символу Мари +Segment of Bloodscourge,TXT_BLOODSCOURGE_PIECE,,,,Část Krvehromu,Segment af Blodgiselen,Segment der Blutgeißel,,Segmento de Sangskurĝ',Segmento de la Plaga Sangrienta,,Veripiiskan osa,Segment du Fléau Sanglant,Darab a Vérkorbácsból,Parte del Flagello di Sangue,天罰の切片,피의 재앙 조각,Segment van Bloedgesel,Segment av Bloodscourge,Fragment Krwioplagi,Segmento do Flagelo de Sangue,,Fragment din Flagelul Sângeros,Часть кровавого бича,Део Крвавог бича,Segment av Bloodscourge,Bloodscourge'un Segmenti,Частина Кривавої Кари +,,Locks,,,,,,,,,,,,,,,,,,,,,,,,,, +You need the Steel Key,TXT_NEED_KEY_STEEL,,,,Potřebuješ ocelový klíč,Du skal bruge stålnøglen,Du brauchst den Stahlschlüssel,Χρειάζεσε το Ατσάλινο κλειδί.,Vi bezonas la Ŝtalan Ŝlosilon,Necesitas la Llave de Acero,,Tarvitset teräsavaimen,Vous avez besoin de la Clé d'Acier,Az Acél Kulcsra van szükséged,Ti serve la Chiave d'Acciaio,鋼の鍵が必要だ,강철 열쇠가 필요하다,Je hebt de Stalen Sleutel nodig.,Du trenger stålnøkkelen,Potrzebujesz Stalowego Klucza,Você precisa da Chave de Aço,Precisas da Chave de Aço,Ai nevoie de Cheia din Oțel,Нужен стальной ключ,За отварање је потребан челични кључ,Du behöver stålnyckeln.,Çelik Anahtara ihtiyacın var,Вам потрібен сталевий ключ +You need the Cave Key,TXT_NEED_KEY_CAVE,,,,Potřebuješ klíč od jeskyně,Du skal bruge hulenøglen,Du brauchst den Höhlenschlüssel,,Vi bezonas la Kavern-Ŝlosilon,Necesitas la Llave de la Caverna,,Tarvitset luola-avaimen,Vous avez besoin de la Clé de la Cave,A Barlang Kulcsra van szükséged,Ti serve la Chiave della Caverna ,洞窟の鍵が必要だ,동굴 열쇠가 필요하다,Je hebt de Grotsleutel nodig.,Du trenger hulenøkkelen,Potrzebujesz Klucza do Jaskini,Você precisa da Chave da Caverna,Precisas da Chave da Caverna,Ai nevoie de Cheia Peșterii,Нужен пещерный ключ,За отварање је потребан пећински кључ,Du behöver grottnyckeln,Mağara Anahtarına ihtiyacın var,Вам потрібен печерний ключ +You need the Axe Key,TXT_NEED_KEY_AXE,,,,Potřebuješ sekyrový klíč,Du skal bruge øksenøglen,Du brauchst den Axtschlüssel,,Vi bezonas la Hakil-Ŝlosilon,Necesitas la Llave de Hacha,,Tarvitset kirvesavaimen,Vous avez besoin de la Clé de la Hache,A Fejsze Kulcsra van szükséged,Ti serve la Chiave dell'Ascia,斧の鍵が必要だ,도끼 열쇠가 필요하다,Je hebt de Bijlsleutel nodig.,Du trenger øksenøkkelen,Potrzebujesz Klucza-Topora,Você precisa da Chave do Machado,Precisas da Chave do Machado,Ai nevoie de Cheia Topor,Нужен ключ-топор,За отварање је потребан кључ секира,Du behöver yxnyckeln,Balta Anahtarına ihtiyacın var,Вам потрібен сокирний ключ +You need the Fire Key,TXT_NEED_KEY_FIRE,,,,Potřebuješ ohnivý klíč,Du skal bruge brandnøglen,Du brauchst den Feuerschlüssel,,Vi bezonas la Fajro-Ŝlosilon,Necesitas la Llave de Fuego,,Tarvitset tuliavaimen,Vous avez besoin de la Clé du Feu,A Tűz Kulcsra van szükséged,Ti serve la Chiave del Fuoco ,炎の鍵が必要だ,불 열쇠가 필요하다,Je hebt de Vuursleutel nodig.,Du trenger Ildnøkkelen,Potrzebujesz Ognistego Klucza,Você precisa da Chave do Fogo,Precisas da Chave do Fogo,Ai nevoie de Cheia de Foc,Нужен огненный ключ,За отварање је потребан огњени кључ,Du behöver eldnyckeln,Ateş Anahtarına ihtiyacın var,Вам потрібен вогняний ключ +You need the Emerald Key,TXT_NEED_KEY_EMERALD,,,,Potřebuješ smaragdový klíč,Du skal bruge smaragdnøglen,Du brauchst den Smaragdschlüssel,,Vi bezonas la Smeraldan Ŝlosilon,Necesitas la Llave Esmeralda,,Tarvitset smaragdiavaimen,Vous avez besoin de la Clé d'Emeraude,A Smaragd Kulcsra van szükséged,Ti serve la Chiave di Smeraldo ,翠玉の鍵が必要だ,에메랄드 열쇠가 필요하다,Je hebt de Smaragden Sleutel nodig.,Du trenger smaragdnøkkelen,Potrzebujesz Szmaragdowego Klucza,Você precisa da Chave Esmeralda,Precisas da Chave Esmeralda,Ai nevoie de Cheia din Smarald,Нужен изумрудный ключ,За отварање је потребан смарагдни кључ,Du behöver smaragdnyckeln,Zümrüt Anahtarı'na ihtiyacın var.,Вам потрібен смарагдовий ключ +You need the Dungeon Key,TXT_NEED_KEY_DUNGEON,,,,Potřebuješ klíč od žaláře,Du skal bruge fangehulsnøglen,Du brauchst den Kerkerschlüssel,,Vi bezonas la Karcer-Ŝlosilon,Necesitas la Llave del Calabozo,,Tarvitset tyrmän avaimen,Vous avez besoin de la Clé du Donjon,A Várbörtön Kulcsra van szükséged,Ti serve la Chiave del Sotterraneo ,迷宮の鍵が必要だ,지하감옥 열쇠가 필요하다,Je hebt de Kerkersleutel nodig.,Du trenger fangehullsnøkkelen,Potrzebujesz Klucza do Lochu,Você precisa da Chave da Masmorra,Precisas da Chave das Masmorras,Ai nevoie de Cheia Temniței,Нужен ключ от подземелья,За отварање је потребан кључ од лагума,Du behöver Kerker-nyckeln,Zindan Anahtarına ihtiyacın var,Вам потрібен ключ від підземелля +You need the Silver Key,TXT_NEED_KEY_SILVER,,,,Potřebuješ stříbrný klíč,Du skal bruge sølvnøglen,Du brauchst den Silberschlüssel,Χρειάζεσε το Ασυμένιο κλειδί.,Vi bezonas la Arĝentan Ŝlosilon,Necesitas la Llave de Plata,,Tarvitset hopea-avaimen,Vous avez besoin de la Clé d'Argent,Az Ezüst Kulcsra van szükséged,Ti serve la Chiave d'Argento ,銀の鍵が必要だ,은 열쇠가 필요하다,Je hebt de Zilveren Sleutel nodig.,Du trenger sølvnøkkelen,Potrzebujesz Srebrnego Klucza,Você precisa da Chave de Prata,Precisas da Chave Prata,Ai nevoie de Cheia din Argint,Нужен серебряный ключ,За отварање је потребан сребрни кључ,Du behöver silvernyckeln,Gümüş Anahtara ihtiyacın var,Вам потрібен срібний ключ +You need the Rusted Key,TXT_NEED_KEY_RUSTED,,,,Potřebuješ zrezivělý klíč,Du skal bruge den rustne nøgle,Du brauchst den rostigen Schlüssel,Χρειάζεσε το Σκουριασμένο κλειδί.,Vi bezonas la Rustan Ŝlosilon,Necesitas la Llave Oxidada,,Tarvitset ruosteisen avaimen,Vous avez besoin de la Clé Rouillée,A Rozsdás Kulcsra van szükséged,Ti serve la Chiave Arrugginita ,錆びた鍵が必要だ,녹슨 열쇠가 필요하다,Je hebt de Geroeste Sleutel nodig.,Du trenger den rustne nøkkelen,Potrzebujesz Zardzewiałego Klucza,Você precisa da Chave Enferrujada,Precisas da Chave Enferrujada,Ai nevoie de Cheia Ruginită,Нужен ржавый ключ,За отварање је потребан зарђали кључ,Du behöver den rostade nyckeln,Paslı Anahtar'a ihtiyacın var.,Вам потрібен іржавий ключ +You need the Horn Key,TXT_NEED_KEY_HORN,,,,Potřebuješ parožní klíč,Du skal bruge hornnøglen,Du brauchst den Hornschlüssel,,Vi bezonas la Hup-Ŝlosilon,Necesitas la Llave de Cuerno,,Tarvitset sarviavaimen,Vous avez besoin de la Clé Corne,A Szarv Kulcsra van szükséged,Ti serve la Chiave del Corno ,角の鍵が必要だ,뿔 열쇠가 필요하다,Je hebt de Hoornsleutel nodig.,Du trenger Horn-nøkkelen,Potrzebujesz Rogowego Klucza,Você precisa da Chave do Chifre,Precisas da Chave do Chifre,Ai nevoie de Cheia Corn,Нужен роговой ключ,За отварање је потребан рогати кључ,Du behöver hornnyckeln,Korna Anahtarına ihtiyacınız var,Вам потрібен ріговий ключ +You need the Swamp Key,TXT_NEED_KEY_SWAMP,,,,Potřebuješ klíč od bažiny,Du skal bruge sumpnøglen,Du brauchst den Sumpfschlüssel,,Vi bezonas la Marĉ-Ŝlosilon,Necesitas la Llave del Pantano,,Tarvitset suoavaimen,Vous avez besoin de la Clé des Marécages,A Mocsár Kulcsra van szükséged,Ti serve la Chiave della Palude ,沼の鍵が必要だ,늪지대 열쇠가 필요하다,Je hebt de Moerassleutel nodig.,Du trenger Sump-nøkkelen,Potrzebujesz Bagiennego Klucza,Você precisa da Chave do Pântano,Precisas da Chave do Pântano,Ai nevoie de Cheia Mlaștinii,Нужен болотный ключ,За отварање је потребан мочварни кључ,Du behöver träsknyckeln,Bataklık Anahtarına ihtiyacın var.,Вам потрібен болотний ключ +You need the Castle Key,TXT_NEED_KEY_CASTLE,,,,Potřebuješ klíč od hradu,Du skal bruge slotsnøglen,Du brauchst den Burgschlüssel,,Vi bezonas la Kastel-Ŝlosilon,Necesitas la Llave del Castillo,,Tarvitset linnan avaimen,Vous avez besoin de la Clé du Château,A Kastély Kulcsra van szükséged,Ti serve la Chiave del Castello ,城の鍵が必要だ,성 열쇠가 필요하다,Je hebt de Kasteelsleutel nodig.,Du trenger slottsnøkkelen,Potrzebujesz Klucza do Zamku,Você precisa da Chave do Castelo,Precisas da Chave do Castelo,Ai nevoie de Cheia Castelului,Нужен ключ от замка,За отварање је потребан кључ од замка,Du behöver slottsnyckeln,Kale Anahtarına ihtiyacın var,Вам потрібен ключ від фортеці +,,Actor tag names,,,,,,,,,,,,,,,,,,,,,,,,,, +Afrit,FN_FIREDEMON,,,,,,,,Afrito,,,,,,,アフリート,아프리트,Afriet,,,,,Demon de Foc,Африт,Африт,,,Африт +Serpent,FN_DEMON1,,,,Zlohad,Slange,Chaos-Schlange,,Serpento,Serpiente,,Käärme,,Kígyó,Serpente del Caos,サーペント,서펜트,Slang,Slangen,Wąż,Serpente,,Șarpe,Змей,Серпент,Ormen,Yılan,Змій +Ettin,FN_ETTIN,,,,Skřet,,,,Gigantaĉo,,,,,,,エティン,에틴,,,,,,Etin,Эттин,Етин,Ettin,,Еттін +Centaur,FN_CENTAUR,,,,Kentaur,Kentaur,Zentaur,,Centaŭro,Centauro,,Kentauri,Centaure,Kentaur,Centauro,ケンタウロス,켄타우로스,Centaurus,Kentaur,,Centauro,,,Кентавр,Кентаур,Kentaur,Kentaur,Кентавр +Slaughtaur,FN_SLAUGHTAUR,,,,Ničitaur,Slagtaur,Schlachtaur,,Buĉataŭro,Masacratauro,,Teurastauri,Sangtaure,Vágtaur,Sventrauro,スロアタウル,슬로터로스,Slachttaurus,Slakttaur,Rzeziotaur,Chacinotauro,,Centaur Violent,Убитавр,Кентаур старешина,Slaktaur,Katlaur,Кентавр хорунжий +Bishop,FN_BISHOP,,,,Biskup,Biskop,Bischof,,Episkopo,Obispo,,Piispa,Evèque,Érsek,Vescovo,ビショップ,비숍,Bisschop,Biskop,Biskup,Bispo,,Episcop,Епископ,Епископ,Biskop,Piskopos,Єпископ +Wendigo,FN_ICEGUY,,,,,,,,Vendiko,,,,,,,ウェンディゴ,윈디고,,,,,,Vendigo,Вендиго,Вендиго,,,Віндіго +Stalker,FN_SERPENT,,,,Slídil,,Wasserjäger,,Gvatanto,Acechador,,Vaanija,Chasseur,Orvhalász,Cacciatore,ストーカー,스토커,,,Prześladowca,Caçador,,Vânător,Преследователь,Вребач,,,Сталкер +Reiver,FN_WRAITH,,,,Přízrak,,Phantom,,Fantomo,Saqueador,,Ryöväri,,Martalóc,Incursore,レイバー,리버,Rover,,Rozbójnik,Fantasma,,Pungaș,Грабитель,Грабљивац,Reiver,Hayalet,Розбійник +Death Wyvern,FN_DRAGON,,,,Smrtidrak,Døden Wyvern,Todesdrache,,Morta viverno,Guiverno de la muerte,,Kuolontraakki,Vouivre de la Mort,A Halál Sárkánya,Viverna Mortale,デス ワイバーン,데스 와이번,Doodsdraak,Døden Wyvern,Wiwerna Śmierci,Serpe da Morte,,Balaur al Morții,Виверна смерти,Змајак смрти,Döds Wyvern,Ölüm Wyvern,Віверна Смерті +Korax,FN_KORAX,,,,,,,,,,,Kooraks,,,,唯一神コラックス,코락스,,,,,,,Коракс,Коракс,,,Коракс +Zedek,FN_FBOSS,,,,,,,,Zedeko,,,Sedek,,,,ゼデク,제닥,,,,,,,Зедек,Зедек,,,Зедек +Menelkir,FN_MBOSS,,,,,,,,Menelkiro,,,Menelkir,,,,メネルキル,메넬키어,,,,,,,Менелкир,Менелкир,,,Менелкір +Traductus,FN_CBOSS,,,,Traduktus,,,,Traduktuso,,,Traduktus,,Traduktusz,,トラダクタス,트라닥투스,,,,,,,Традуктус,Традуктус,,,Традуктус +Heresiarch,FN_HERESIARCH,,,,Arcikacíř,Heresiark,Erzketzer,,Ĉefherezulo,Heresiarca,,Kerettiarkki,L'Hérésiarche,Főeretnek,Eresiarca,ヘレシアーク,헤러시아크,,Heresiark,Herezjarcha,Heresiarca,,Ereziarh,Ересиарх,Јересијарх,Heresiark,Heresiark,Єресіарх +Blue Mana,AMMO_MANA1,,,,Modrá mana,Blå Mana,Blaues Mana,,Blua Manao,Maná azul,,Sininen mana,Mana Bleu,Kék Mana,Mana blu,ブルーマナ,청색 마나,Blauwe Mana,Blå Mana,Niebieska Mana,Mana Azul,,Mană Albastră,Синяя мана,Плава мана,Blå Mana,Mavi Mana,Синя мана +Green Mana,AMMO_MANA2,,,,Zelená mana,Grøn Mana,Grünes Mana,,Verda Manao,Maná verde,,Vihreä mana,Mana Vert,Zöld Mana,Mana verde,グリーンマナ,녹색 마나,Groene Mana,Grønn Mana,Zielona Mana,Mana Verde,,Mană Verde,Зелёная мана,Зелена мана,Grön Mana,Yeşil Mana,Зелена мана +Mace of Contrition,TAG_CWEAPMACE,,,,Palcát kajícnosti,Stridskølle af anger,Streitkolben,,Klabo de Penteco,Maza de Contrición,,Katumuksen nuija,Masse de Pénitence,Bűnbánat Buzogánya,Mazza del Pentimento,懺悔のメイス,참회의 철퇴,Knots van Wroeging,Mace of Contrition,Buzdygan Skruchy,Maça da Contrição,,Buzduganul Remușcării,Булава раскаяния,Буздован покајања,Tystnadens stridsspira,Pişmanlık Topuzu,Булава покаяння +Serpent Staff,TAG_CWEAPSTAFF,,,,Hadí hůl,Slange-stav,Schlangenstab,,Serpentbastono,Bastón de Serpiente,,Käärmesauva,Sceptre du Serpent,Kígyó Bot,Staffa del Serpente ,蛇の杖,뱀 지팡이,Slangenstaf,Slangestav,Laska Węży,Cetro da Serpente,,Bastonul Șarpelui,Змеиный посох,Змијски штап,Ormens stav,Yılan Asa,Посох змія +Firestorm,TAG_CWEAPFLAME,,,,Ohnivá bouře,Ildstorm,Feuersturm,,Fajrŝtormo,Tormenta de Fuego,,Tulimyrsky,Tempête de Feu,Tűzvihar,Tempesta di Fuoco ,ファイアストーム,화염폭풍,Vuurstorm,Ildstorm,Burza Ognia,Tempestade-de-fogo,,Furtună de Foc,Огненный шторм,Огњена олуја,Eldstorm,Ateş Fırtınası,Вогняний шторм +Wraithverge,TAG_CWEAPWRAITHVERGE,,,,Zjevitel,Spirit Bringer,Geisterbringer,,Fantomkruc',Báculo Fantasmal,,Haamusauva,Verge Phantasmale,Lidércvég,Verga SconfinaSpettri,レイスバージ,사령의 십자가,Schimroede,Wraithverge,Widmoskraj,Cajado Fantasma,,Toiag Stafie,Жезл духов,Жезло утвара,,Wraithverge,Символ Мари +Spiked Gauntlets,TAG_FWEAPFIST,,,,Ohrocené rukavice,Spidse handsker,Stachelhandschuhe,,Pintaj Fergantoj,Guanteletes Puntiagudos,,Piikkirautakintaat,Gantelets à Pointes,Tűskés Páncélkesztyűk,Guantoni Spinati,スパイク ガントレット,가시 장갑,Spijkerhandschoenen,Pigghansker,Kolczaste Rękawice,Manoplas Espinhadas,,Mănuși cu Țepi,Шипастые перчатки,Бодљикаве рукавице,Spikade handskar,Çivili Eldivenler,Шипасті рукавиці +Timon's Axe,TAG_FWEAPAXE,,,,Timonova sekera,Timons økse,Timons Axt,,Hakilo de Timon,Hacha de Timón,,Timonin kirves,Hache de Timon,Timon Baltája,Ascia di Timon,タイモンの斧,티몬의 도끼,Timon's Bijl,Timons øks,Topór Timona,Machado de Timon,,Toporul lui Timon,Топор Тимона,Тимонова секира,Timons yxa,Timon'un Baltası,Тімонова сокира +Hammer of Retribution,TAG_FWEAPHAMMER,,,,Kladivo odplaty,Hævnens hammer,Hammer der Rache,,Martelo de Repago,Martillo de Retribución,,Koston vasara,Marteau de la Rétribution,Kárhozat Kalapácsa,Martello del Castigo,報復の金槌,징벌의 망치,Hamer van Vergelding,Gjengjeldelsens hammer,Młot Odkupienia,Martelo da Retribuição,,Ciocanul Salvării,Молот возмездия,Чекић одмазде,Hämndhammaren,İntikam Çekici,Молот відплати +Quietus,TAG_FWEAPQUIETUS,,,,Tišitel,Forløser,Erlöser,,Kvietus',,,,Quietus,Némusz,,死滅の剣,종언의 검,,,Uciszacz,,,Argument Final,Последний довод,Самрт,,,Упокій +Sapphire Wand,TAG_MWEAPWAND,,,,Safírová hůl,Safir-stav,Saphirstab,,Safirsorĉbastono,Varita de Zafiro,,Safiirisauva,Baguette de Saphir,Zafír Pálca,Scettro di Zaffiro ,サファイア ワンド,사파이어 지팡이,Saffieren Toverstok,Safirstaven,Szafirowa Różdżka,Cetro de Safira,,Toiag cu Safir,Сапфировая волшебная палочка,Сафирни штап,Safirstav,Safir Değnek,Сапфіровий жезл +Frost Shards,TAG_MWEAPFROST,,,,Ledové střepy,Frostskår,Frostsplitter,,Frostfragmentoj,Fragmentos de Escarcha,,Pakkassirpaleet,Eclats de Givre,Fagyos Szilánkok,Schegge di Ghiaccio ,フロスト シャード,얼음 파편,Vorstscherven,Frostskår,Lodowe Odłamki,Fragmentos de Geada,,Cioburi de Gheață,Замораживающие осколки,Ледене крхотине,Frostskärvor,Buz Kırıkları,Льодяні уламки +Arcs of Death,TAG_MWEAPLIGHTNING,,,,Jiskry smrti,Dødens buer,Todesblitz,,Arkoj de Morto,Arcos de la Muerte,,Kuolonkaaret,Foudre Mortelle,Halál Boltíve,Archi della Morte ,死の円弧,죽음의 번갯불,Doodsboog,Dødens buer,Łuki Śmierci,Arcos da Morte,,Izvoarele Morții,Дуга смерти,Лук смрти,Dödsbågar,Ölüm Yayları,Арка смерті +Bloodscourge,TAG_MWEAPBLOODSCOURGE,,,,Krvehrom,Blodgisel,Blutgeißel,,Sangskurĝ',Plaga Sangrienta,,Veripiiska,Fléau Sanglant,Vérkorbács,Flagello di Sangue,天罰,피의 재앙,Bloedgesel,,Krwioplaga,Flagelo de Sangue,,Flagel Sângeros,Кровавый бич,Крвави бич,,,Кривава Кара +Disc of Repulsion,TAG_ARTIBLASTRADIUS,,,,Kotouč odpuzení,Afstødningsskive,Rückstoßscheibe,,Disko de Repelado,Disco de Repulsión,,Karkotuskiekko,Disque de Répulsion,Visszaverő Pajzs,Disco della Repulsione ,反発の円盤,방탄의 원반,Schijf van Afstoting,Frastøtelsens skive,Dysk Odpychania,Disco da Repulsão,,Disc al Repulsiei,Диск отторжения,Диск одбијања,Skiva av avstötning,İtme Diski,Диск відштовхування +Dragonskin Bracers,TAG_ARTIBOOSTARMOR,,,,Dračí nátepníky,Drageskindsarmbøjler,Drachenhaut-Armschutz,,Brakbendo el Drakhaŭto,Brazaletes de piel de Dragón,,Lohikäärmeennahkarannesuojat,Brassards en peau de Dragon,Sárkánybőr Karkötők,Bracciali in Pelle di Drago ,竜皮の小手,용가죽 팔찌,Drakenhuidbescherming,Dragehud-bindinger,Karwasze ze Smoczej Skóry,Braçadeiras de Pele de Dragão,,Brățări din Piele de Dragon,Наручи драконьей кожи,Наруквице од змајеве коже,Drakskinnsarmband,Ejderha Derisi Bilezikler,Наручі зі шкіри дракона +Krater of Might,TAG_ARTIBOOSTMANA,,,,Kalich síly,Kraftens bæger,Kelch der Macht,,Kratero de Potenco,Crátera de Poder,,Mahtikrateeri,Cratère de Pouvoir,Hatalom Kráterje,Calice della Forza,魔力の盃,힘의 향로,Beker van Macht,Krater av makt,Czara mocy,Cálice do Poder,,Pocal al Puterii,Кубок могущества,Чаша силе,Mäktighetens krater,Kudret Krateri,Чаша міці +Flechette,TAG_ARTIPOISONBAG,,,,Střelka,,,,Flakono,,,,Fléchette,Nyílhegy,Fiaschetta ,フレシェット,플레셰트,,,Flaszka,,,Flacon,Флешетта,Бочица,,,Флешета +Poison Cloud Flechette,TAG_ARTIPOISONBAG1,,,,Otrávená střelka,Flechette (giftig sky),Flechette (Giftwolke),,Venennub-Flakono,Flechette de Nube Venenosa,,Myrkkypilviflechette,Fléchette - Nuage Toxique,Méregfelhő hegy,Fiaschetta Velenosa,毒ガス フレシェット,독구름 플레셰트,Flechette (giftige wolk),Giftsky-flechette,Flaszka Trującej Chmury,Flechette de Nuvem Venenosa,,Flacon cu Otravă,Флешетта ядовитого облака,Бочица отровног облака,Flechette med giftmoln,Zehirli Bulut Flechette,Флешета отруйної хмари +Timebomb Flechette,TAG_ARTIPOISONBAG2,,,,Časovaná střelka,Flechette (tidsbombe),Flechette (Zeitbombe),,Horloĝbomb-Flakono ,Bomba de Tiempo Flechette,,Aikapommiflechette,Fléchette - Bombe a Retardement,Időbomba hegy,Fiaschetta a Tempo ,時限爆弾フレシェット,시한폭탄 플레셰트,Flechette (tijdbom),Tidsbombe Flechette,Flaszka-Bomba Zegarowa,Flechette Bomba-Relógio,,Bombă cu Ceas,Флешетта часовой бомбы,Бочица временске бомбе,Tidsbomb Flechette,Saatli bomba Flechette,Флешета часової бомби +Grenade Flechette,TAG_ARTIPOISONBAG3,,,,Granátová střelka,Flechette (granat),Flechettre (Granate),,Grenad-Flakono,Granada Flechette,,Kranaattiflechette,Fléchette - Grenade,Robbanó hegy,Fiaschetta da Lancio,グレネードフレシェット,폭발성 플레셰트,Flechette (granaat),Granat Flechette,Flaszka-Granat,Flechette Granada,,Flacon-Grenadă,Гранатная флешетта ,Бочица граната,Granat Flechette,El Bombası Flechette,Гранатна флешета +Mystic Ambit Incant,TAG_ARTIHEALINGRADIUS,,,,Tajemný čár koljdoucí,,,,Sorĉo de Mistika Sfero,Encantamiento de Ámbito Místico,,Mystisen piirin loitsu,Incantation Mystique,Misztikus Mágialista,Incantamento Mistico ,魅知国の秘法,신비 영역의 주문,,,Inkantancja Mistycznego Kręgu,Encantamento Místico,,Pergament Mistic,Мистический зачарованный свиток,Чаролија магичног јединства,,Mistik Ambit Büyüsü,Закляття містичної області +Icon of the Defender,TAG_ARTIDEFENDER,,,,Obráncova ikona,Ikon af forsvareren,Ikone des Verteidigers,,Ikono de la Defendanto,Icono del Defensor,Ícono del Defensor,Puolustajan ikoni,Icône du Défenseur,Védelmező Ikonja,Emblema del Difensore ,守護者の像,수호의 성상,,Forsvarerens ikon,Ikona Obrońcy,Ícone do Defensor,,Imaginea Apărătorului,Символ защитника,Симбол браниоца,Försvararens ikon,Savunucunun Simgesi,Символ захисника +Porkalator,TAG_ARTIPORK,,,,Vepřovitel,,,,Porkigilo,Porcinador,,Sikaannuttaja,Porcificateur,Ártányátok,Porchificatore,ポークレイター,돈육기,,,Schabowator,Porquificador,,Porcolator,Свиновизатор,Свињатор,,,Захрюкувач +Boots of Speed,TAG_ARTISPEED,,,,Běhuté boty,Støvler af hastighed,Turbo-Stiefel,,Botoj de Rapideco,Botas de Velocidad,,Ripeyssaappaat,Bottes de Célérité,Sebesség Cipői,Stivali della Fretta,素早さの靴,속도의 부츠,Snelheidslaarzen,Støvler av fart,Buty Szybkości,Botas da Rapidez,,Bocancii Vitezei,Сапоги-скороходы,Брзинске чизме,Stövlar av snabbhet,Hız Çizmeleri,Семимильні чоботи +Dark Servant,TAG_ARTISUMMON,,,,Temný služebník,Mørk tjener,Dunkler Diener,,Malluma Servanto,Servidor Oscuro,,Pimeä palvelija,Serviteur Noir,Árny Szolga,Servo Oscuro,闇の従者,어둠의 하인,Donkere Dienaar,Mørk tjener,Mroczny Sługa,Servo Negro,,Servitor Întunecat,Тёмный слуга,Мрачни слуга,Mörk tjänare,Karanlık Hizmetkar,Темний слуга +Banishment Device,TAG_ARTITELEPORTOTHER,,,,Vyhošťovač,Forvisningsanordning,Verbannungsgerät,,Forpelilo,Dispositivo de Destierro,,Häivytyskoje,Outil de Banissement,Számüzető Szerkentyű,Congegno dell'Esilio,追放のデバイス,소멸 장치,Verbanningsapparaat,Forvisningsinnretning,Urządzenie Wygnania ,Dispositivo do Banimento,,Dispozitiv al Alungării,Механизм изгнания,Амблем прогањања,Förvisningsenhet,Sürgün Cihazı,Пристрій заслання +Yorick's Skull,TAG_ARTIPUZZSKULL,,,,Jorikova lebka,Yoricks kranium,Yoricks Schädel,,Kranio de Yorick,Calavera de Yorick,Cráneo de Yorick,Yorickin kallo,Crâne de Yorick,Yorick Koponyája,Teschio di Yorick,ヨリックの髑髏,요릭의 두개골,Yorick's Schedel,Yoricks hodeskalle,Czaszka Yoricka,Crânio de Yorick,,Craniul lui Yorick,Череп Йорика,Јорикова лобања,Yoricks skalle,Yorick'in Kafatası,Череп Йоріка +Heart of D'Sparil,TAG_ARTIPUZZGEMBIG,,,,Srdce D'Sparila,D'Sparils hjerte,D'Sparils Herz,,Koro de D'Sparil,Corazón de D'Sparil,,D'Sparilin sydän,Cœur de D'Sparil,D'Sparil Szíve,Cuore di D'Sparil,デ'スパリルの心,드'스파릴의 심장,Hart van D'Sparil,D'Sparils hjerte,Serce D'Sparila,Coração de D'Sparil,,Inima lui D'Sparil,Сердце Д'Спарила,Д'Спарилово срце,D'Sparils hjärta,D'Sparil'in Kalbi,Серце Д'Спаріла +Ruby Planet,TAG_ARTIPUZZGEMRED,,,,Rubínová planeta,Rubinplanet,Rubinplanet,,Rubena Planedo,Planeta Rubí,,Rubiiniplaneetta,Planète en rubis,Rubin Bolygó,Pianeta di Rubino,ルビーの宝石,루비 행성석,Robijnrode Planeet,Rubinplaneten,Rubinowa Planeta,Planeta Rubi,,Planetă din Rubin,Рубиновая планета,Планета рубина,Rubinplanet,Yakut Gezegeni,Рубінова планета +Emerald Planet (1),TAG_ARTIPUZZGEMGREEN1,,,,Smaragdová planeta (1),Smaragdplanet (1),Smaragdplanet (1),,Smeralda Planedo (1),Planeta Esmeralda (1),,Smaragdiplaneetta (1),Planète en émeraude (1),Smaragd Bolygó (1),Pianeta di Smeraldo (1),エメラルドの宝石1,에메랄드 행성석 (1),Smaragdgroene Planeet (1),Smaragdplaneten (1),Szmaragdowa Planeta (1),Planeta Esmeralda (1),,Planetă din Smarald (1),Изумрудная планета (1),Смарагдна планета (1),Smaragdplanet (1),Zümrüt Gezegen (1),Смарагдова планета (1) +Emerald Planet (2),TAG_ARTIPUZZGEMGREEN2,,,,Smaragdová planeta (2),Smaragdplanet (2),Smaragdplanet (2),,Smeralda Planedo (2),Planeta Esmeralda (2),,Smaragdiplaneetta (2),Planète en émeraude (2),Smaragd Bolygó (2),Pianeta di Smeraldo (2),エメラルドの宝石2,에메랄드 행성석 (2),Smaragdgroene Planeet (2),Smaragdplaneten (2),Szmaragdowa Planeta (2),Planeta Esmeralda (2),,Planetă din Smarald (2),Изумрудная планета (2),Смарагдна планета (2),Smaragdplanet (2),Zümrüt Gezegen (2),Смарагдова планета (2) +Sapphire Planet (1),TAG_ARTIPUZZGEMBLUE1,,,,Safírová planeta (1),Safirplanet (1),Saphirplanet (1),,Safira Planedo (1),Planeta Zafiro (1),,Safiiriplaneetta (1),Planète en saphir (1),Zafír Bolygó (1),Pianeta di Zaffiro (1),サファイアの宝石1,사파이어 행성석 (1),Saffierblauwe Planeet (1),Safirplaneten (1),Szafirowa Planeta (1),Planeta Safira (1),,Planetă din Safir (1),Сапфировая планета (1),Сафирна планета (1),Safirplanet (1),Safir Gezegen (1),Сапфірова планета (1) +Sapphire Planet (2),TAG_ARTIPUZZGEMBLUE2,,,,Safírová planeta (2),Safirplanet (2),Saphirplanet (2),,Safira Planedo (2),Planeta Zafiro (2),,Safiiriplaneetta (2),Planète en saphir (2),Zafír Bolygó (2),Pianeta di Zaffiro (2),サファイアの宝石2,사파이어 행성석 (2),Saffierblauwe Planeet (2),Safirplaneten (2),Szafirowa Planeta (2),Planeta Safira (2),,Planetă din Safir (2),Сапфировая планета (2),Сафирна планета (2),Safirplanet (2),Safir Gezegen (2),Сапфірова планета (2) +Daemon Codex,TAG_ARTIPUZZBOOK1,,,,,,,,Kodekso de Demono,Códice del Demonio,,Daemon-koodeksi,Codex Démoniaque,Démon Kódex,Codice Demoniaco ,デーモンの写本,악마의 고문서,,,Demoniczny Kodeks,Códice Demoníaco,,Codexul Demonilor,Демонический кодекс,Демонски кодекс,,,Демонічний кодекс +Liber Oscura,TAG_ARTIPUZZBOOK2,,,,,,,,Liber Oscura,Liber Oscura,,,,,,オスキュラ公文書,어둠의 자유서,,,Liber Oscura,,,Liber Obscura,Либер Оскура,Либер Оскура,,,Лібер Оскура +Flame Mask,TAG_ARTIPUZZSKULL2,,,,Plamenná maska,Flamme-maske,Flammenmaske,,Fajrmasko,Mascara de Llamas,Mascara de Flamas,Liekkinaamio,Masque de Flammes,Láng Maszk,Maschera delle Fiamme ,炎の仮面,화염의 가면,Vuurmasker,Flammemaske,Maska Płomieni,Máscara das Chamas,,Mască de Foc,Маска пламени,Маска пламена,Flam-Mask,Alev Maskesi,Полум'яна маска +Glaive Seal,TAG_ARTIPUZZFWEAPON,,,,Glévská pečeť,Sværdsegl,Schwertsiegel,,Sigelo de Glavo,Sello de Espada,,Miekkasinetti,Sceau du Glaive,Pallos Pecsét,Sigillo del Brando,グレイブシール,밀폐된 칼날,Lanszegel,Glaive segl,Pieczęć Glewii,Selo do Gládio,,Sigiliu Spadă,Печать воителя,Војников печат,Glasögonsegel,Glaive Mühür,Воїнська печатка +Holy Relic,TAG_ARTIPUZZCWEAPON,,,,Svatá relikvie,Hellig relikvie,Heiliges Relikt,,Sankta Relikvo,Santa Reliquia,,Pyhä reliikki,Relique Sacrée,Szent Ereklye,Reliquia Sacra,聖遺物,신성한 유물,Heilige Relikwie,Hellig relikvie,Święta Relikwia,Relíquia Sagrada,,Relicvă Sfântă,Святая реликвия,Света реликвија,Heliga reliker,Kutsal Emanet,Свята реліквія +Sigil of the Magus,TAG_ARTIPUZZMWEAPON,,,,Mágovo sigilium,Magus' segl,Symbol des Magiers,,Sigelo de la Mago,Emblema del Mago,,Taikurin sinetti,Sceau du Mage,Mágus Pecsétje,Suggello del Magus,メイガスの印章,마거스의 인장,Sigaar van de Magus,Magusens segl,Emblemat Maga,Sígilo do Mago,,Sigiliul Magului,Печать Мага,Чаробњаков симбол,Magikerns sigill,Büyücünün Sigil'i,Знак магів +Iron gear,TAG_ARTIPUZZGEAR1,,,,Železné kolečko,Tandhjul af jern,Eisenzahnrad,,Fera Dentrado,Engranaje de Hierro,,Rautaratas,Engrenage en Fer,Vas Felszerelés,Ingranaggio di Ferro,鉄の歯車,양철 톱니바퀴,IJzeren uitrusting,Jernutstyr,Żelazna Zębatka,Engrenagem de ferro,,Mecanism din fier,Железная шестерня,Гвожђени зупчаник,Kugghjul av järn,Demir dişli,Залізна шестерня +Brass gear,TAG_ARTIPUZZGEAR2,,,,Mosazné kolečko,Tandhjul i messing,Messingzahnrad,,Latuna Dentrado,Engranaje de Bronce,,Messinkiratas,Engrenage en Bronze,Réz Felszerelés,Ingranaggio di Ottone ,真鍮のギア,황동 톱니바퀴,Messing uitrusting,Utstyr av messing,Mosiężna Zębatka,Engrenagem de latão,,Mecanism din alamă,Латунная шестерня,Месингани зупчаник,Kugghjul av mässing,Pirinç dişli,Латунна шестерня +Brass and iron gear,TAG_ARTIPUZZGEAR3,,,,Mosazno-železné kolečko,Tandhjul af messing og jern,Messing-und-Eisen-Zahnrad,,Latuna Fera Dentrado,Engranaje de Bronce y Hierro,,Messinki- ja rautaratas,Engrenage en Fer et Bronze,Vas és Réz Felszerelés,Ingranaggio di Ferro e Ottone ,鉄と真鍮のギア,황동과 양철 톱니바퀴,Messing en ijzeren uitrusting,Utstyr av messing og jern,Zębatka z mosiądzu i żelaza,Engrenagem de ferro e latão,,Mecanism din alamă și fier,Латунно-железная шестерня,Месинганoгвожђени зупчаник,Kugghjul av mässing och järn,Pirinç ve demir dişli,Латунно-залізна шестерня +Silver and brass gear,TAG_ARTIPUZZGEAR4,,,,Stříbro-mosazné kolečko,Tandhjul af sølv og messing,Silber-und-Messing-Zahnrad,,Arĝenta Latuna Dentrado,Engranaje de Plata y Bronce,,Hopea- ja messinkiratas,Engrenage en Argent et Bronze,Ezüst és Réz Felszerelés,Ingranaggio di Ottone e Argento ,銀と真鍮のギア,은과 황동 톱니바퀴,Zilveren en messing uitrusting,Utstyr av sølv og messing,Zębatka ze srebra i mosiądzu,Engrenagem de prata e latão,,Mecanism din argint și alamă,Серебряно-латунная шестерня,Сребрномесигани зупчаник,Kugghjul av silver och mässing,Gümüş ve pirinç dişli,Срібно-латунна шестерня +,,Obituaries,,,,,,,,,,,,,,,,,,,,,,,,,, +%o tasted an Afrit's fire.,OB_FIREDEMON,,,,%o okusil@[ao_cs] afritův oheň.,%o smagte en afrits ild.,%o spürte das Feuer des Afrits.,,%o gustis la fajron de Afrito.,%o ha probado el fuego de un Afrit.,%o probó el fuego de un Afrit.,%o maistoi afritin tulta.,%o a goûté au feu d'un Afrit.,%o megkóstolta a Tűz Szellem parazsát.,%o ha assaggiato il fuoco di un Afrit. ,%o はアフリートの炎を味わった。,%o 은(는) 아프리트의 화염을 맛봤다.,%o proefde het vuur van een Afriet.,%o smakte en Afrits ild.,%o spróbował@[ao_pl] ognia Afrita.,%o provou o fogo de um Afrit.,,%o a gustat flacăra Demonului de Foc.,Игрок %o отведал огня африта.,%o је окуси@[ao_1_sr] Афритов огањ.,%o smakade en Afrits eld.,%o bir Afrit'in ateşini tattı.,%o скуштува@[adj_1_ua] вогню Африта. +%o was scalded by a Serpent.,OB_DEMON1,,,,%o byl@[ao_cs] upálen@[ao_cs] zlohadem.,%o blev skoldet af en slange.,%o wurde von der Chaos-Schlange gebissen.,,%o brogiĝis de Serpento.,A %o l@[ao_esp] ha carbonizado una Serpiente.,A %o l@[ao_esp] carbonizó una Serpiente.,%o joutui käärmeen kalttaamaksi.,%o a été brûlé@[e_fr] par un Serpent.,%o testét leforrázta egy Kígyó,%o è stato sciolto da un Serpente del Caos,%o はサーペントに火傷を負わされた。,%o 은(는) 서펜트에 데였다.,%o werd gebroeid door een Slang.,%o ble skåldet av en slange.,%o został@[ao_pl] poparzon@[adj_pl] przez Węża.,Uma Serpente escaldou %o.,,%o a fost opărit de un Șarpe.,Игрок %o спалён змеем.,Играча %o је спалио Серпент.,%o blev skållad av en orm.,%o bir yılan tarafından haşlandı.,%o було спалено змієм. +%o was poisoned by a Serpent.,OB_DEMON2,,,,%o byl@[ao_cs] otráven@[ao_cs] zlohadem.,%o blev forgiftet af en slange.,%o wurde von der Chaos-Schlange verbrannt.,,%o veneniĝis de Serpento.,A %o l@[ao_esp] ha envenenado una Serpiente.,A %o l@[ao_esp] envenenó una Serpiente.,%o joutui käärmeen myrkyttämäksi.,%o a été empoisonné@[e_fr] par un Serpent.,%o vérébe mérget juttatott egy Kígyó,%o è stato avvelenato da un Serpente del Caos. ,%o はサーペントの毒にやられた。,%o 은(는) 독 서펜트에게 중독 당했다.,%o werd vergiftigd door een Slang.,%o ble forgiftet av en slange.,%o został@[ao_pl] zatrut@[adj_pl] przez Węża.,%o foi envenenad@[ao_ptb] por uma Serpente.,,%o a fost otrăvit de un Șarpe.,Игрок %o отравлен змеем.,Играча %o је отровао Серпент.,%o blev förgiftad av en orm.,%o bir yılan tarafından zehirlendi.,%o було отруєно змієм. +%o was mashed by an Ettin.,OB_ETTIN,,,,%o byl@[ao_cs] umlácen@[ao_cs] skřetem.,%o blev moset af en Ettin.,%o wurde von dem Ettin zermatscht.,,%o frakasiĝis de Gigantaĉo.,%o ha quedado hech@[ao_esp] puré por un Ettin.,%o quedó hech@[ao_esp] puré por un Ettin.,%o joutui ettinin muhentamaksi.,%o a été réduit@[e_fr] en purée par un Ettin.,%o csillagokat lát az Ettin miatt.,%o è stato schiacciato da un Ettin. ,%o はエティンに潰された。,%o 은(는) 에틴에게 철퇴를 맞았다.,%o werd gepureerd door een Ettin.,%o ble knust av en Ettin.,%o został@[ao_pl] stłuczon@[adj_pl] przez Ettina.,%o foi feito purê por um Ettin.,,%o a fost făcut piure de un Etin.,Игрока %o раздробил эттин.,Играча %o је смрскао Еттин.,%o blev mosad av en Ettin.,%o bir Ettin tarafından ezildi.,%o затовк еттін. +%o was cut up by a Centaur.,OB_CENTAUR,,,,%o byl@[ao_cs] rozsekán@[ao_cs] kentaurem.,%o blev skåret op af en kentaur.,%o wurde von dem Zentaur aufgeschlitzt.,,%o distranĉiĝis de Centaŭro.,A %o l@[ao_esp] ha partido un Centauro.,A %o l@[ao_esp] partió un Centauro.,%o joutui kentaurin pilkkomaksi.,%o a été tranché@[e_fr] par un Centaure.,%o fel lett vágva a Kentaur jóvoltából.,%o è stato affettato da un Centauro. ,%o はケンタウロスに切り刻まれた。,%o 은(는) 켄타우로스에 의해 절단됐다.,%o werd versneden door een Centaurus.,%o ble kuttet opp av en Kentaur.,%o został@[ao_pl] pocięt@[adj_pl] przez Centaura.,%o foi fatiad@[ao_ptb] por um Centauro.,,%o a fost tăiat deschis de un Centaur.,Игрока %o разрезал кентавр.,Играча %o је расекао Кентаур.,%o blev styckad av en Kentaur.,%o bir Kentaur tarafından kesildi.,%o зарізав кентавр. +%o was cut up by a Slaughtaur.,OB_SLAUGHTAURHIT,,,,%o byl@[ao_cs] rozsekán@[ao_cs] ničitaurem.,%o blev skåret op af en slagtaur.,%o wurde von dem Schlachtaur aufgeschlitzt.,,%o distranĉiĝis de Buĉataŭro.,A %o l@[ao_esp] ha partido un Masacratauro.,A %o l@[ao_esp] partió un Masacratauro.,%o joutui teurastaurin pilkkomaksi.,%o a été tranché@[e_fr] par un Sangtaure.,%o nagyon felvágott és a Vágtaur is a játékost,%o è stato affettato da uno Sventrauro. ,%o はスロアタウルに切り刻まれた。,%o 은(는) 슬로터로스에 의해 심하게 절단됐다.,%o werd versneden door een Slachtaurus.,%o ble kuttet opp av en Slakttaur.,%o został@[ao_pl] pocięt@[adj_pl] Rzeziotaura.,%o foi fatiad@[ao_ptb] por um Chacinotauro.,,%o a fost tăiat deschis de un Centaur Violent.,Игрока %o разрезал убитавр.,Играча %o је расекао Кентаур старешина.,%o blev styckad av en Slaktaur.,%o bir Katlaur tarafından kesildi.,%o зарізав кентавр хорунжий. +%o was struck down by a Slaughtaur's fireball.,OB_SLAUGHTAUR,,,,%o byl@[ao_cs] zabit@[ao_cs] ničitaurovou ohnivou koulí.,%o blev slået ned af en slagtauras ildkugle.,%o wurde von dem Feuerball des Schlachtaurs niedergestreckt.,,%o subite mortiĝis de fajropilko de Buĉataŭro.,A %o l@[ao_esp] ha abatido la bola de fuego de un Masacratauro.,A %o l@[ao_esp] derribó la bola de fuego de un Masacratauro.,%o joutui teurastaurin tulipallon kaatamaksi.,%o a été touché@[e_fr] par une boule de feu de Sangtaure.,%o másodfokú égési sérüléseket szenvedett el a Vágtaur tűzgolyójától.,%o è stato abbattuto dalla palla di fuoco di uno Sventrauro. ,%o はスロアタウルの火玉に倒された。,%o 은(는) 슬로터로스의 마법구에 의해 피격당했다.,%o werd neergeslagen door een Slachtaurus' vuurbal.,%o ble truffet av en Slakttaurs ildkule.,%o został@[ao_pl] trafion@[adj_pl] przez kulę ognia Rzeziotaura.,%o foi abatid@[ao_ptb] pela bola de fogo de um Chacinotauro.,,"%o a fost răpus de mingea de foc a unui Centaur +Violent.",Игрока %o сбил огненным шаром убитавр.,Играча %o је огњеном куглом оборио Кентаур старешина.,%o blev nedslagen av en Slauktaurs eldklot.,%o bir Katlaur'un ateş topuyla vuruldu.,Кентавр хорунжий знищив %o фаєрболом. +%o succumbed to a Bishop's dark power.,OB_BISHOP,,,,%o podlehl@[ao_cs] biskupově temné moci.,%o bukkede under for en biskops mørke kraft.,%o fiel der dunklen Macht des Bischofs zum Opfer.,,%o subfaliĝis de malluma potenco de Episkopo.,%o ha sucumbido ante el poder oscuro de un Obispo.,%o sucumbió ante el poder oscuro de un Obispo.,%o lankesi piispan pimeään voimaan.,%o a succombé au pouvoir obscur d'un évèque.,%o megadta magát a Püspök sötét erejének,%o è stato sottomesso dalla magia oscura di un Vescovo. ,%o はビショップの闇の力に屈した。,%o 은(는) 비숍의 힘에 무릎을 꿇었다.,%o bezweek aan de donkere kracht van een Bisschop.,%o bukket under for en Biskops mørke kraft.,%o uległ@[ao_pl] mrocznej mocy Biskupa.,%o sucumbiu ao poder negro de um Bispo.,,%o a cedat puterii întunecate a Episcopului.,Игрок %o поддался чёрным силам Епископа.,%o је подлег@[ao_2_sr] Епископовим црним силама.,%o gav efter för en biskops mörka kraft.,%o bir Piskopos'un karanlık gücüne yenik düştü.,%o підкори@[adj_2_ua] темній магії епископа. +%o was frozen solid by a Wendigo.,OB_ICEGUY,,,,%o byl@[ao_cs] zamrznut@[ao_cs] wendigem.,%o blev frosset fast af en wendigo.,%o wurde von dem Wendigo tiefgefroren.,,%o tute frostiĝis de Vendiko.,A %o l@[ao_esp] ha congelado un Wendigo.,A %o l@[ao_esp] congeló un Wendigo.,%o joutui wendigon läpikotaisin jäädyttämäksi.,%o a été gelé@[e_fr] par un Wendigo.,%o testét keményre fagyasztotta egy Wendigo,%o è stato congelato da un Wendigo. ,%o はウェンディゴによって固められた。,%o 은(는) 윈디고에 의해 단단하게 얼려졌다.,%o werd bevroren door een Wendigo.,%o ble frosset fast av en Wendigo.,%o został@[ao_pl] zamrożon@[adj_pl] przez Wendigo.,%o foi congelad@[ao_ptb] por um Wendigo.,,%o a fost făcut statuie de un Vendigo.,Игрока %o полностью заморозил вендиго.,Играча %o је потпуно замрзнуо Вендиго.,%o blev frusen av en Wendigo.,%o bir Wendigo tarafından kaskatı donduruldu.,Вендіго повністю заморозив %o. +%o was mauled by a Stalker.,OB_SERPENTHIT,,,,%o byl@[ao_cs] umlácen@[ao_cs] slídilem.,%o blev mast af en stalker.,%o wurde von dem Wasserjäger zerfleischt.,,%o vundegiĝis de Gvatanto.,A %o l@[ao_esp] ha triturado un Acechador.,A %o l@[ao_esp] trituró un Acechador.,%o joutui vaanijan raatelemaksi.,%o a été mutilé@[e_fr] par un Chasseur.,%o szét lett marcangolva egy Orhalász által.,%o è stato malmenato da un Cacciatore. ,%o はストーカーに引っ掻かれた。,%o 은(는) 스토커에게 발렸다.,%o werd verminkt door een Stalker.,%o ble maltraktert av en Stalker.,%o został@[ao_pl] poturbowan@[adj_pl] przez Prześladowcę.,%o foi mutilad@[ao_ptb] por um Caçador.,,%o a fost sfâșiat de un Vânător.,Игрок %o покусан преследователем.,Играча %o је растргао Вребач.,%o blev söndersliten av en Stalker.,%o bir Stalker tarafından parçalandı.,%o роздер сталкер. +%o was melted by a Stalker.,OB_SERPENT,,,,%o byl@[ao_cs] rozpuštěn@[ao_cs] slídilem.,%o blev smeltet af en stalker.,%o wurde von dem Wasserjäger geschmolzen.,,%o fandiĝis de Gvatanto.,A %o l@[ao_esp] ha derretido un Acechador.,A %o l@[ao_esp] derritió un Acechador.,%o joutui vaanijan sulattamaksi.,%o a été fondu@[e_fr] par un Chasseur.,%o csontjairól a húst leolvasztotta egy Orvhalász,%o è stato squagliato da un Cacciatore. ,%o はストーカーに溶かされた。,%o 은(는) 스토커에 의해 녹았다.,%o werd gesmolten door een Stalker.,%o ble smeltet av en Stalker.,%o został@[ao_pl] stopion@[adj_pl] przez Prześladowcę.,%o foi derretid@[ao_ptb] por um Caçador.,,%o a fost topit de un Vânător.,Игрока %o расплавил преследователь.,Играча %o је растопио Вребач.,%o blev smält av en Stalker.,%o bir Takipçi tarafından eritildi.,%o розплавив сталкер. +%o was charred by a Reiver.,OB_WRAITH,,,,%o byl@[ao_cs] zpopelněn@[ao_cs] přízrakem.,%o blev forkullet af en reiver.,%o wurde von dem Phantom verkohlt.,,%o brulegiĝis de Fantomo.,A %o l@[ao_esp] ha carbonizado un Saqueador.,A %o l@[ao_esp] carbonizó un Saqueador.,%o joutui ryövärin hiiltämäksi.,%o a été carbonisé@[e_fr] par un Reiver.,%o testét egy Martalóc elszenesítette.,%o è stato carbonizzato da un Incursore. ,%o はレイバーに黒焦げにされた。,%o 은(는) 리버에 의해 그슬렸다.,%o werd verbrand door een Rover.,%o ble forkullet av en Reiver.,%o został@[ao_pl] zwęglon@[adj_pl] przez Rozbójnika.,%o foi carbonizad@[ao_ptb] por um Fantasma.,,%o a fost ceruit de un Pungaș.,Игрока %o обуглил грабитель.,Играча %o је угљенисао Вребач.,%o blev förkolnad av en Reiver.,%o bir Hayalet tarafından yakıldı.,%o було спалено розбійником. +%o had %p life stolen by a Reiver.,OB_WRAITHHIT,,,,%o si nechal@[ao_cs] ukradnout život přízrakem.,%o fik sit liv stjålet af en reiver.,%o wurde das Leben von dem Phantom gestohlen.,,%o havis sian vivon ŝtelita de Fantomo.,A %o le ha robado la vida un Saqueador.,A %o le robó la vida un Saqueador.,Ryöväri riisti pelaajan %o hengen.,%o a perdu la vie face à un Reiver.,%o %p életét ellopta egy Martalóc,%o ha permesso che un Incursore prosciugasse la sua vita ,%o はレイバーに命を %p盗まれた。,%o 은(는) 리버에게 영혼을 도둑맞았다.,%o had @[zijn_haar_nl] leven gestolen door een Rover.,%o fikk %p liv stjålet av en Reiver.,"Życie %o zostało skradzione przez Rozbójnika. +",%o teve sua vida roubada por um Fantasma.,,Viața lui %o a fost furată de un Pungaș.,Жизнь игрока %o украл грабитель.,Играчу %o је живот украо Вребач.,%o fick sitt liv stulet av en Reiver.,%o bir Hayalet tarafından kurutuldu.,Життя %o було вкрадено розбійником. +%o was incinerated by the Death Wyvern.,OB_DRAGON,,,,%o byl@[ao_cs] upálen@[ao_cs] smrtidrakem.,%o blev forbrændt af wyvern.,%o wurde von dem Todesdrachen verbrannt.,,%o cindriĝis de Mortviverno.,A %o l@[ao_esp] ha incinerado el Guiverno de la Muerte.,A %o l@[ao_esp] incineró el Guiverno de la Muerte.,%o joutui kuolontraakin polttamaksi.,%o a été incinéré@[e_fr] par une vouivre de la mort.,%o testét porig égette egy Halálsárkány,%o è stato incenerito da una Viverna Mortale. ,%o はダークワイバーンに焼却された。,%o 은(는) 데스 와이번에 의해 분신 당했다.,%o werd verbrand door de Doodsdraak.,%o ble brent opp av en Døden Wyvern.,%o został@[ao_pl] spalon@[adj_pl] przez Wiwernę Śmierci.,%o foi incinerad@[ao_ptb] por uma Serpe da Morte,,%o a fost incinerat de Balaurul Morții.,Игрока %o кремировала виверна Смерти.,Играча %o је кремировао Змајак смрти.,%o blev bränd av Döds Wyvern.,"%o, Ölüm Wyvern tarafından yakıldı.",Віверна Смерті спалила %o вщент. +%o was swept from the board by Korax.,OB_KORAX,,,,%o byl@[ao_cs] odhozen@[ao_cs] ze šachovnice Koraxem.,%o blev fejet væk fra brættet af Korax.,%o wurde von Korax vom Feld gefegt.,,%o estis prenita el la tabulo de Korax.,%o ha sido barrid@[ao_esp] del tablero por Korax.,%o fue barrid@[ao_esp] del tablero por Korax.,%o pyyhkäistiin laudalta Kooraksen voimasta.,%o a été balayé@[e_fr] de l'échiquier par Korax.,%o el lett söpörve a tábláról Korax által.,%o è stato eliminato dalla scacchiera da Korax. ,%o は唯一神の怒りに触れた。,%o 은(는) 코락스의 체스판에서 사라졌다.,%o werd door Korax van het bord geveegd.,%o ble feid fra brettet av Korax.,%o został@[ao_pl] zmiecion@[adj_pl] z pokładu przez Koraxa.,%o foi eliminad@[ao_ptb] do tabuleiro por Korax.,,%o a fost măturat de pe drum de Korax.,Игрока %o скинул с доски Коракс.,Играча %o је с табле уклонио Коракс.,%o blev avförd från spelplanen av Korax.,"%o, Korax tarafından tahtadan süpürüldü.",Коракс скинув з ігрової дошки %o. +%o was slain by Zedek.,OB_FBOSS,,,,%o byl@[ao_cs] zabit@[ao_cs] Zedekem.,%o blev dræbt af Zedek.,%o wurde von Zedek hingemetzelt.,,%o mortigis de Zedeko.,A %o l@[ao_esp] ha asesinado Zedek.,A %o l@[ao_esp] asesinó Zedek.,%o joutui Sedekin tappamaksi.,%o a été pourfendu@[e_fr] par Zedek.,%o meghalt Zedek által.,%o è stato ammazzato da Zedek. ,%o はゼデクに討ち取られた。,%o 은(는) 제닥의 이름으로 쓰러졌다.,%o werd gedood door Zedek.,%o ble drept av Zedek.,%o został@[ao_pl] zgładzon@[adj_pl] przez Zedeka.,%o foi mort@[ao_ptb] por Zedek.,,%o a fost omorât de Zedek.,Игрока %o сразил Зедек.,Играча %o је оборио Коракс.,%o blev dödad av Zedek.,"%o, Zedek tarafından öldürüldü.",%o зустрі@[adj_1_ua] смерть від Зедека. +%o couldn't absorb Menelkir's Mana.,OB_MBOSS,,,,%o nemohl@[ao_cs] pojmout Menelkirovu manu.,%o kunne ikke absorbere Menelkirs Mana.,%o konnte Menelkirs Mana nicht verkraften.,,%o ne povis absorbi la Manaon de Menelkiro.,%o intenta absorber el maná de Menelkir y sale mal.,,%o ei kyennyt ottamaan vastaan Menelkirin manaa.,%o n'aurait pu absorber le mana de Menelkir.,%o nem tudta elnyelni Menelkir manáját.,%o non è riuscito ad assorbire il mana di Menelkir. ,%o はメネルキルのマナを吸収できなかった。,%o 은(는) 메넬키어의 마나를 흡수하지 못했다.,%o kon Menelkir's mana niet absorberen.,%o kunne ikke absorbere Menelkirs Mana.,%o nie m@[irreg_4_pl] wchłonąć Many Menelkira.,%o não conseguiu absorver o Mana de Menelkir.,,%o nu a reușit să absoarbă mana lui Menelkir.,Игрок %o не смог поглотить ману Менелкира.,%o се није узмог@[ao_2_sr] носити с Менелкировом маном.,%o kunde inte absorbera Menelkirs Mana.,"%o, Menelkir'in Mana'sını ememedi.",У %o не вийшло побороти ману Менелкіра. +%o was baptized by Traductus.,OB_CBOSS,,,,%o byl@[ao_cs] posvěcen@[ao_cs] Traduktem.,%o blev døbt af Traductus.,%o wurde von Traductus getauft.,,%o baptiĝis de Traduktuso.,A %o l@[ao_esp] ha bautizado Traductus.,A %o l@[ao_esp] bautizó Traductus.,%o joutui Traduktuksen kastamaksi.,%o a été baptisé@[e_fr] par Traductus.,%o meg lett keresztelve Traductus által.,%o è stato battezzato da Traductus. ,%o はトラダクタスの洗礼を受けた。,%o 은(는) 트라닥투스에게 침례를 당했다.,%o werd gedoopt door Traductus.,%o ble døpt av Traductus.,%o został@[ao_pl] ochrzczon@[adj_pl] przez Traductusa.,%o foi batizad@[ao_ptb] por Traductus.,,%o a fost botezat de Traductus.,Игрока %o крестил Традуктус.,Играча %o је крстио Традуктус.,%o blev döpt av Traductus.,"%o, Traductus tarafından vaftiz edildi.",Традуктус похрестив %o. +%o had %p bones rolled by the Heresiarch.,OB_HERESIARCH,,,,%o si nechal@[ao_cs] rozmetat kosti Arcikacířem.,%o fik sine knogler rullet af Heresiark.,%os Knochen wurden vom Erzketzer gerollt.,,%o havis siajn ostojn rulis de la Ĉefherezulo.,A %o le ha arrollado los huesos el Heresiarca.,A %o le arrolló los huesos el Heresiarca.,Kerettiarkki jyräsi pelaajan %o luut.,%o s'est fait@[e_fr] rouler les os par l'Hérésiarche.,%o csontváza ki lett forgatva az Eretnek Vezér által.,Le ossa di %o sono state accartocciate dall'Eresiarca. ,%o はヘレシアークに骨を %p本 撒き散らされた。,%o 은(는) 헤러시아크에 의해 뼈와 살이 분리되었다.,%o @[zijn_haar_nl] botten werden opgerold door de Heresiarch.,%o fikk %p bein rullet av Heresiark.,Kości %o zostały porozrzucane przez Herezjarchę.,%o teve seus ossos moídos pelo Heresiarca.,,Oasele lui %o au fost făcute praf de către Ereziarh.,Ересиарх сыграл в кости игрока %o.,На играча %o су пале Јересијархове коцке.,%o fick sina ben rullade av Heresiark.,"%o, Heresiark tarafından kutsandı.",Єресіарх зіграв партію кістками %o. +%o was beaten to a pulp by %k's bare fists.,OB_MPFWEAPFIST,,,,%o byl@[ao_cs] umlácen@[ao_cs] k smrti holými pěstmi hráče %k.,%o blev slået til plukfisk af %ks bare næver.,%o wurde von %ks nackten Fäusten zu Hackfleisch verarbeitet.,,%o kaĉe draŝiĝis de la nudaj pugnoj de %k.,%o ha quedado molid@[ao_esp] por los puños limpios de %k.,%o quedó molid@[ao_esp] por los puños limpios de %k.,%k hakkasi %o paran muusiksi paljailla nyrkeillään.,%o à été tabassé@[e_fr] à mort par les poings de %k.,%o péppé lett verve %k ökleivel.,%k ha ridotto %o in poltiglia a mani nude.,%o は %k に素手でボコボコにされた。,%o 은(는) %k 의 맨손 타격으로 묵사발이 되었다.,%o werd tot pulp geslagen door %k's blote vuisten.,%o ble slått til mos av %ks bare never.,%o został@[ao_pl] zbit@[adj_pl] na miazgę przez gołe pięści %k.,%o foi espancad@[ao_ptb] até a morte pelos punhos nus de %k.,,%k l-a omorât în bătaie pe %o cu mâinile goale.,Игрок %o избит в мясо голыми руками игрока %k.,%o је пребијен@[adj_1_sr] на смрт голим рукама играч %k.,%o blev slagen till mos av %ks nakna knytnävar.,"%o, %k tarafından eşek sudan gelinceye kadar dövüldü.",%k заби@[adj_1_ua] %o голими руками. +%o got the axe from %k.,OB_MPFWEAPAXE,,,,%o dostal@[ao_cs] sekerou od hráče %k.,%o fik øksen af %k.,%o sah %ks Axt.,,%o ricevis la hakilon el %k.,%o ha recibido el hachazo de %k.,%o recibió el hachazo de %k.,%o sai pelaajan %k kirveestä.,%o s'est fait@[e_fr] hacher menu par %k.,%o megkapta %k baltáját.,%o ha preso un colpo d'ascia da %k.,%o は %k から斧を受けた。,%o 은(는) %k 의 티몬의 도끼를 어설프게 받아쳤다.,%o kreeg de bijl van %k.,%o fikk øksa av %k.,%o dostał@[ao_pl] z topora %k.,%o recebeu o machado de %k.,,%o a primit un topor de la %k.,Игрок %o словил топорик игрока %k.,%o је добио секиру од %k.,%o fick yxan av %k.,"%o, %k tarafından baltayla dövüldü.",%o отрима@[adj_1_ua] сокирою від %k. +%o had %p head caved in by %k's hammer.,OB_MPFWEAPHAMMERM,,,,%o dostal@[ao_cs] po hlavě kladivem hráče %k.,%o fik sit hoved udhulet af %ks hammer.,%o wurde der Kopf von %ks Hammer eingeschlagen.,,%p havis sian kapon enfalis de la martelo de %k.,A %o le ha abollado la cabeza el martillo de %k.,A %o le abolló la cabeza el martillo de %k.,%k painoi vasarallaan %o paran pään kasaan.,%o s'est fait@[e_fr] éclater le crâne par le marteau de %k.,%o kapott egy üreges fejet %k Kalapácsa által.,La testa di %o è stata aperta in due dal martello di %k.,%o は %k のハンマーで頭に空洞を開けられた。,%k 은(는) 징벌의 망치로 %o 의 머리 위에 우물을 만들었다.,%o had @[zijn_haar_nl] kop ingestort met %k's hamer.,%o fikk %p hode knust av %ks hammer.,Głowa %o została zmiażdżona przez młot %k.,%o teve seu crânio afundado pelo martelo de %k.,%o teve seu crânio amolgado pelo martelo de %k.,%k i-a băgat capul lui %o în interior cu ciocanul.,Голова игрока %o была вдолблена в тело молотом игрока %k.,Играч %k је расцепао играчу %o главу.,%o fick huvudet krossat av %ks hammare.,"%o, %k tarafından dövüldü.",Голова %o опинилась всередині тіла через молот %k. +%o's soul was forged anew by %k's hammer.,OB_MPFWEAPHAMMERR,,,,%o@[psf1_cs] duše byla obrozena kladivem hráče %k.,%os sjæl blev smedet på ny af %ks hammer.,%os Seele wurde durch %ks Hammer erneuert.,,La animo de %o nove forĝiĝis de la martelo de %k.,El alma de %o ha sido forjada de nuevo por el martillo de %k.,El alma de %o fue forjada de nuevo por el martillo de %k.,%k uudelleentakoi %o paran sielun vasarallaan.,%o a eu son âme reforgée par le marteau de %k.,%o lelke újra lett kovácsolva %k Kalapácsa által.,L'anima di %o è stata riforgiata dal martello di %k.,%o の魂は %k のハンマーで一から鍛え直された。,%o 의 영혼은 %k 의 징벌의 망치에 의해 철거되었다.,%o's ziel werd omgesmeed door %k's hamer.,%o's sjel ble smidd på nytt av %ks hammer.,Dusza %o została wykuta na nowo przez młot %k.,%o teve sua alma reforjada pelo martelo de %k.,,%k i-a făcut sufletul lui %o ca nou cu ciocanul.,Душа игрока %o была перекована молотом игрока %k.,Играч %k је прековао душу играча %o чекићем.,%os själ smiddes på nytt av %ks hammare.,"%o, %k tarafından dövüldü.",Душа %o була наново перекована молотом %k. +%o was silenced by %k's mighty Quietus.,OB_MPFWEAPQUIETUS,,,,%o byl@[ao_cs] umlčen@[ao_cs] mocným Tišitelem hráče %k.,%o blev bragt til tavshed af %ks mægtige Forløser.,%o wurde durch %ks Erlöser befreit.,,%o slientiĝis de La Pova Kvietus' de %k.,A %o l@[ao_esp] ha silenciado el poderoso Quietus de %k.,A %o l@[ao_esp] silenció el poderoso Quietus de %k.,%k vaiensi %o paran mahtavalla Quietuksellaan.,%o à été réduit@[e_fr] au silence par le pouvoir de %k et Quietus.,%o el lett némítva %k hatalmas Némusza által.,%o è stato zittito dal potente Quietus di %k.,%o は %k の強靭なクワイエタスで静かにされた。,%o 은(는) %k 의 종언의 검 덕에 침묵을 지킬 수 있었다.,%o werd tot zwijgen gebracht door %k's machtige Quietus.,%o ble brakt til taushet av %ks mektige Quietus.,%o został@[ao_pl] uciszon@[adj_pl] przez %k.,%o foi silenciad@[ao_ptb] pelo poderoso Quietus de %k.,,"%o a fost redus la tăcere de argumentul final al +lui %k.",Игрок %o утихомирен легендарным Последним доводом игрока %k.,%o је утишан@[adj_1_sr] од моћи Куиетуса играч %k.,%o tystades av %ks mäktiga Quietus.,"%o, %k tarafından susturuldu.",%k упокої@[adj_1_ua] %o. З миром? +%o got a mace to the face from %k.,OB_MPCWEAPMACE,,,,%o dostal@[ao_cs] palcátem po hlavě od hráče %k.,%o fik en stridskølle i ansigtet af %k.,%o bekam %ks Streitkolben ins Gesicht.,,%o prenis klabon al la vizaĝon el %k.,%o ha recibido un mazazo en la cara por %k.,%o recibió un mazazo en la cara por %k.,%o sai pelaajan %k nuijasta naamaansa.,%o s'est fait@[e_fr] casser la figure par la masse de %k.,%o kapott egy buzogányt a fejébe %k által.,%o si è preso una mazzata in faccia da %k.,%o は自らの顔に %k のメイスを受けた。,%o 은(는) %k 의 철퇴를 맞은 뒤에야 철이 들었다.,%o kreeg een %k's gesel in @[zijn_haar_nl] gezicht.,%o ble slått i ansiktet av %k.,%o dostał@[ao_pl] buzdyganem %k w twarz.,%o levou com a maça de %k na cara.,,%o a primit un buzdugan în față de la %k.,Игрок %o получил по морде булавой игрока %k.,%o је доби@[ao_1_sr] буздован у фацу играч %k.,%o fick en stridsklubba i ansiktet av %k.,"%o, %k tarafından eşek sudan gelinceye kadar dövüldü.",%o отрима@[adj_1_ua] по пиці булавою %k. +%o was bitten by %k's serpent staff.,OB_MPCWEAPSTAFFM,,,,%o byl@[ao_cs] kousnut@[ao_cs] hadí holí hráče %k.,%o blev bidt af %ks slange-stav.,%o wurde von %ks Schlangenstab gebissen.,,%o mordiĝis de la serpentbastono de %k.,A %o l@[ao_esp] ha mordido el bastón de la serpiente de %k.,A %o l@[ao_esp] mordió el bastón de la serpiente de %k.,%k puri %o parkaa käärmesauvallaan.,%o s'est fait@[e_fr] mordre par le Bâton du Serpent %k.,%o meg lett harapva %k Kígyó Botja által.,%o è stato morso dalla Staffa del Serpente di %k.,%o は %k の蛇の杖に噛まれた。,%o 은(는) %k 의 뱀 지팡이에 의해 독살당했다.,%o werd gebeten door %k's slangenstaf.,%o ble bitt av %ks slangestav.,%o został@[ao_pl] ugryzion@[adj_pl] laską węży %k.,%o foi mordid@[ao_ptb] pelo Cetro da Serpente de %k.,,%o a fost mușcat de bastonul șarpe al lui %k.,Игрок %o искусан змеиным посохом игрока %k.,%o је угрижен@[adj_1_sr] змијским штапом играч %k.,%o blev biten av %ks ormstab.,"%o, %k tarafından zehirlendi.",Посох змія %k покусав %o. +%o choked on %k's serpent staff.,OB_MPCWEAPSTAFFR,,,,%o se zadusil@[ao_cs] hadí holí hráče %k.,%o blev kvalt af %ks slange stav.,%o verschluckte sich an %ks Schlangenstab.,,%o sufokis la serpentbastonon de %k.,%o se ha ahogado con el bastón de la serpiente de %k.,%o se ahogó con el bastón de la serpiente de %k.,%o tukehtui pelaajan %k käärmesauvaan.,%o s'est étranglé@[e_fr] sur le Bâton du Serpent de %k,%o megfulladt %k Kígyó Botja által.,%o è soffocato a causa della Staffa del Serpente di %k.,%o は %k の蛇の杖に息の根を止められた。,%o 은(는) %k 의 뱀 지팡이 때문에 숨을 쉬지 못했다.,%o stikte in %k's slangenstaf.,%o ble kvalt av %ks slangestav.,%o zakrztusił@[ao_pl] się laską węży %k.,%o se engasgou com o Cetro da Serpente de %k,,%o s-a sufocat pe bastonul șarpe al lui %k.,Игрок %o задушен змеиным посохом игрока %k.,%o је задављен@[adj_1_sr] змијским штапом играч %k.,%o kvävdes av %ks ormstab.,"%o, %k tarafından kurutuldu.",Посох змія %k задушив %o. +%o was lit up by %k's flames.,OB_MPCWEAPFLAME,,,,%o vzplanul@[ao_cs] plameny hráče %k.,%o blev tændt af %ks flammer.,%o wurde von %ks Flammen erleuchtet.,,%o ekbruliĝis de la fajroj de %k.,A %o l@[ao_esp] han calcinado las llamas de %k.,A %o l@[ao_esp] calcinaron las llamas de %k.,%o syttyi pelaajan %k liekeistä.,%o s'est fait@[e_fr] allumer par %k.,%o fel lett gyújtva %k tűze által.,%o è stato illuminato dalle fiamme di %k.,%o は %k によって炎を灯された。,%o 은(는) %k 의 화염폭풍에 휩쓸렸다.,%o werd opgelicht door %k's vlammen.,%o ble opplyst av %ks flammer.,%o został@[ao_pl] oświetlon@[adj_pl] płomieniami %k.,%o foi incendiad@[ao_ptb] pelas chamas de %k.,,%o s-a aprins de la flăcările lui %k.,Игрок %o сгорел в огне игрока %k.,%o је осветљен@[adj_1_sr] пламеном играч %k.,%o blev upplyst av %ks lågor.,"%o, %k tarafından aydınlatıldı.",%o було спалено в полум'ї %k. +%o was cleansed by %k's Wraithverge.,OB_MPCWEAPWRAITHVERGE,,,,%o byl@[ao_cs] očištěn@[ao_cs] Zjevitelem hráče %k.,%o blev renset af %ks Spirit Bringer.,%o wurde durch %ks Geisterbringer geläutert.,,%o puriĝis de la Fantomkruc' de %k.,A %o l@[ao_esp] ha limpiado la vara fantasmal de %k.,A %o l@[ao_esp] limpió la vara fantasmal de %k.,%k puhdisti pelaajan %o Haamusauvallaan.,%o a été purifié@[e_fr] par la Verge Phantasmale de %k.,%o meg lett tisztítva %k Bosszúbot által.,%o è stato purificato dalla Verga SconfinaSpettri di %k.,%o は %k のレイスバージによって浄化された。,%o 은(는) %k 의 사령의 지팡이에 의해 정화되었다.,%o werd gereinigd door %k's Schimroede.,%o ble renset av %ks Wraithverge.,%o został@[ao_pl] oczyszczon@[adj_pl] przez Widmoskraj %k.,%o foi purificad@[ao_ptb] pelo Cajado Fantasma de %k.,,%o a fost purificat de Toiagul Stafie al lui %k.,Игрок %o очищен жезлом духов игрока %k.,%o je прочишћен@[adj_1_sr] штапом утваре играч %k.,%o blev renad av %ks Wraithverge.,"%o, %k tarafından temizlendi.",%k очисти@[adj_1_ua] %o Символом Мари. +%o took one too many sapphire beams from %k.,OB_MPMWEAPWAND,,,,%o koupil@[ao_cs] přespříliš safírových střel od hráče %k.,%o tog en safirstråle for meget fra %k.,%o bekam zu viele Saphierstrahlen von %k ab.,,%o recivis unu tro da safira radio de %k.,%o ha recibido demasiados rayos de zafiro de %k.,%o recibió demasiados rayos de zafiro de %k.,%o otti vastaan yhden liikaa pelaajan %k safiirisäteistä.,%o s'est pris@[e_fr] un rayon saphirique en trop de la part de %k.,%o túl sok zafír sugarat kapott %k-tól/től.,%o si è buscato un raggio di zaffiro di troppo da %k.,%o は %k から多量のサファイアビームを受け取った。,%o 은(는) %k 의 사파이어 빛을 너무 많이 째려봤다.,%o kreeg een saffierstraal teveel van %k.,%o fikk en safirstråle for mye fra %k.,%o wzi@[irreg_2_pl] o jeden szafirowy promień od %k za dużo.,%o levou muitos raios de safira de %k.,,%o a primit o rază în plus de la safirul lui %k.,Игрок %o схватил слишком много сапфировых зарядов от игрока %k.,%o је узе@[ao_1_sr] превише сафирских зракова играч %k.,%o tog emot en för många safirstrålar från %k.,"%o, %k tarafından dönüştürüldü.",%o хапану@[adj_1_ua] надто багато сапфірових снарядів від %k. +%o was turned into a frosty fellow by %k.,OB_MPMWEAPFROST,,,,%o byl@[ao_cs] zchlazen@[ao_cs] hráčem %k.,%o blev forvandlet til en frostklar fyr af %k.,%o wurde von %k schockgefrostet.,,%o farigiĝis frostulon de %k.,%o ha sido convertid@[ao_esp] en un helado por %k.,%o fue convertid@[ao_esp] en un helado por %k.,%k muutti %o paran pakkasveikoksi.,%o s'est fait@[e_fr] transformer en glaçon par %k.,%o jégbaráttá alakult %k által.,%o è stato trasformato in un simpatico pupazzo di neve da %k.,%o は %k によって冷ややかな輩になった。,%o 은(는) %k 의 얼음 파편에 의해 눈사람이 되었다.,%o werd ijskoud veranderd door %k.,%o ble forvandlet til en iskald fyr av %k.,%o został@[ao_pl] zmienion@[adj_pl] w mroźnego koleżkę przez %k.,%o foi transformad@[ao_ptb] em picolé por %k.,,%o a fost transformat într-un amic de gheață de %k.,Игрок %o обращается в ледяную скульптуру игроком %k.,%o је претворен@[adj_1_sr] у лед играч %k.,%o förvandlades till en frostig kille av %k.,"%o, %k tarafından soğuk bir adama dönüştürüldü.",%o перетвори@[adj_2_ua] в лід завдяки %k. +%o received a shocking revelation from %k.,OB_MPMWEAPLIGHTNING,,,,%o zjistil@[ao_cs] šokující odhalení hráče %k.,%o fik en chokerende åbenbaring af %k.,%o musste eine schockierende Enthüllung von %k verkraften.,,%o recivis teruran revelacion de %k.,%o ha recibido una revelación impactante de %k.,%o recibió una revelación impactante de %k.,%o sai sähköistävän ilmestyksen pelaajalta %k.,%o a reçu un sacré coup de jus de la part de %k.,%o kapott egy sokkoló relevációt %k-tól/től,"%o ha ricevuto una notizia ""elettrizzante"" da %k.",%o は %k から衝撃的な啓示を受けた。,%o 은(는) %k 의 번갯불 덕에 충격적인 계시를 받았다.,%o kreeg een schokkende openbaring van %k.,%o fikk en sjokkerende åpenbaring fra %k.,%o otrzymał@[ao_pl] szokujące objawienie od %k.,%o recebeu uma revelação chocante de %k.,,%o a avut parte de o revelație șocantă de la %k.,Игрок %o откровенно шокирован игроком %k.,%o је прими@[ao_1_sr] шокантно откриће играч %k.,%o fick ett chockerande avslöjande av %k.,"%o, %k tarafından şoka uğratıldı.",%k розкри@[adj_1_ua] для %o шокуючу істину. +%o was wiped off the face of the universe by %k's Bloodscourge.,OB_MPMWEAPBLOODSCOURGE,,,,%o byl@[ao_cs] vymýcen@[ao_cs] ze jsoucna vesmíru Krvehromem hráče %k.,%o blev udslettet af universets overflade af %ks Blodgisel.,%o wurde von %ks Blutgeißel aus dem Universum verbannt.,,%o disdetruiĝis el la universo de la Sangskurĝ' de %k.,%o ha sido borrad@[ao_esp] de la faz del universo por la plaga sangrienta de %k.,%o fue borrad@[ao_esp] de la faz del universo por la plaga sangrienta de %k.,%k pyyhki %o paran maailmankaikkeudesta.,%o s'est fait@[e_fr] effacer de l'univers par le Fléau Sanglant de %k.,%o ki lett törölve az univerzumból %k Vérkorbácsának köszönhetően.,%o è stato cancellato dalla faccia dell'universo dal Flagello di Sangue di %k.,%o は %k の天罰によりこの世から一掃された。,%o 은(는) %k 이(가) 피의 재앙을 씀으로써 전혀 존재하지 않는 존재가 되어버렸다.,%o werd van het gezicht van het universum geveegd door %k's Bloedgesel.,%o ble utslettet fra universets overflate av %ks Bloodscourge.,Twarz %o została zmieciona z wszechświata przez Krwioplagę %k.,%o foi varrid@[ao_ptb] da face do universo pelo Flagelo de Sangue de %k.,,"%o a fost ras de pe fața universului de +Flagelul Sângeros al lui %k.",Игрок %o стёрт с лица вселенной Кровавым бичом игрока %k.,%o је обрисан@[adj_1_sr] са лица свемира од Крвавог зла играч %k.,%o blev utplånad från universums yta av %ks Bloodscourge.,"%o, %k tarafından evrenden silindi.",%o було стерто з лиця всесвіту за допомогою Кривавої Кари %k. +,,Strife,,,,,,,,,,,,,,,,,,,,,,,,,, +,,Pickups,,,,,,,,,,,,,,,,,,,,,,,,,, +You picked up the Metal Armor.,TXT_METALARMOR,,,You picked up the Metal Armour.,Sebral@[ao_cs] jsi kovové brnění.,Du samlede metalrustningen op.,Du hast die Metallrüstung genommen.,Πήρες τη Μεταληκή Πανοπλία.,Vi trovis metalan armaĵon.,Encuentras una armadura de metal.,,Poimit metallihaarniskan.,Vous avez pris l'armure de métal.,Felvetted a Fémpáncélt.,Hai raccolto l'Armatura di Metallo.,メタルアーマー 入手。,강철 갑옷을 획득했다.,Je hebt het metalen harnas opgepakt.,Du plukket opp metallrustningen.,Podniosł@[irreg_3_pl] Metalowy Pancerz.,Você pegou a Armadura de Metal.,Apanhaste a Armadura de Metal.,Ai ridicat Armura din Metal.,Получена металлическая броня.,Покупио си метални оклоп.,Du plockade upp metallrustningen.,Metal Zırhı aldın.,Взято Металічну броню. +You picked up the Leather Armor.,TXT_LEATHERARMOR,,,You picked up the Leather Armour.,Sebral@[ao_cs] jsi kožené brnění.,Du samlede læderrustningen op.,Du hast die Lederrüstung genommen.,Πήρες τη Δερμάτινη Πανοπλία.,Vi trovis ledan armaĵon.,Encuentras una armadura de cuero.,,Poimit nahkasuojuksen.,Vous avez pris l'armure de cuir.,Felvetted a Bőrpáncélt.,Hai raccolto l'Armatura di Cuoio.,レザーアーマー 入手。,가죽 갑옷을 획득했다.,Je hebt het leren harnas opgepakt.,Du plukket opp lærrustningen.,Podniosł@[irreg_3_pl] Skórzany Pancerz.,Você pegou a Armadura de Couro.,Apanhaste a Armadura de Couro.,Ai ridicat Armura din Piele.,Получена кожаная броня.,Покупио си кожни оклоп.,Du plockade upp läderrustningen.,Deri Zırhı aldın.,Взято Шкіряну броню. +You picked up the Med patch.,TXT_MEDPATCH,,,,Sebral@[ao_cs] jsi obvaz.,Du samlede Med patch op.,Du hast den Verband genommen.,,Vi trovis kuracbendojn.,Encuentras unas tiritas.,Encuentras unas curitas.,Poimit sidekääreen.,Vous avez pris le pansement.,Felvetted a Ragtapaszt.,Hai raccolto le Bende.,医薬パッチ 入手。,의료 붕대를 획득했다.,Je hebt de med-patch opgepakt.,Du plukket opp en Med-patch.,Podniosł@[irreg_3_pl] Bandaż.,Você pegou a compressa médica.,Apanhaste a compressa médica.,Ai ridicat Trusa de Prim-Ajutor.,Получен медицинский бинт.,Покупио си прву помоћ.,Du plockade upp den medicinska plåstret.,Sağlık bandını aldın.,Взято оклюзійну пов'язку. +You picked up the Medical kit.,TXT_MEDICALKIT,,,,Sebral@[ao_cs] jsi lékárničku.,Du samlede Medicinsk kit op.,Du hast den Verbandskasten genommen.,,Vi trovis sukurkeston.,Encuentras un botiquín.,,Poimit lääkintälaukun.,Vous avez pris le kit médical.,Felvetted az Elsősegélycsomagot.,Hai raccolto il Kit di Pronto Soccorso.,医療用キット 入手。,구급 키트를 획득했다.,Je hebt de medicijndoos opgepakt.,Du plukket opp det medisinske settet.,Podniosł@[irreg_3_pl] Apteczkę.,Você pegou o Kit Médico.,Apanhaste o Kit Médico.,Ai ridicat Kitul de Prim-Ajutor.,Получена аптечка.,Покупио си медицински комплет,Du plockade upp den medicinska utrustningen.,Tıbbi kiti aldın.,Взято індивідуальну аптечку. +You picked up the Surgery Kit.,TXT_SURGERYKIT,,,,Sebral@[ao_cs] jsi chirurgickou soupravu.,Du samlede kirurgisættet op.,Du hast den Erste-Hilfe-Kasten genommen.,,Vi trovis kirurgian keston.,Encuentras un kit quirúrgico.,,Poimit kirurgilaukun.,Vous avez pris le kit de chirurgie.,Felvetted az Orvosi Műtőfelszerelést.,Hai raccolto il Kit Chirurgico.,手術キット 入手。,수술 키트를 획득했다.,Je hebt het chirurgenpakket opgepakt.,Du plukket opp Kirurgi-settet.,Podniosł@[irreg_3_pl] Zestaw Chirurga.,Você pegou o Kit de Cirurgia.,Apanhaste o Kit de Cirugia.,Ai ridicat Kitul pentru Operații.,Получен медкомплект.,Покупио си хируршки комплет,Du plockade upp operationssatsen.,Ameliyat setini aldın.,Взято медичний кейс. +You picked up the map.,TXT_STRIFEMAP,,,,Sebral@[ao_cs] jsi mapu.,Du samlede kortet op.,Du hast die Karte genommen.,Πήρες το χάρτη.,Vi trovis la mapon.,Encuentras el mapa.,,Poimit kartan.,Vous avez pris la carte,Felvetted a térképet.,Hai raccolto la Mappa.,マップ 取得。,지도를 획득했다.,Je hebt de kaart opgepakt.,Du plukket opp kartet.,Podniosł@[irreg_3_pl] mapę.,Você pegou o mapa.,Apanhaste o mapa.,Ai ridicat harta.,Получена карта.,Покупио си мапу.,Du plockade upp kartan.,Haritayı aldın.,Взято карту. +You picked up the ring.,TXT_BELDINSRING,,,,Sebral@[ao_cs] jsi prsten.,Du samlede ringen op.,Du hast den Ring genommen.,Πήρες το Δακτύλιο.,Vi havas la ringon.,Tienes el anillo.,,Poimit sormuksen.,Vous avez pris l'anneau.,Felvetted a Gyűrűt.,Hai raccolto l'Anello.,指輪 取得。,반지를 획득했다.,Je hebt de ring opgepakt.,Du plukket opp ringen.,Podniosł@[irreg_3_pl] pierścień.,Você pegou o anel.,Apanhaste o anel.,Ai ridicat inelul.,Получено кольцо.,Покупио си прстен.,Du plockade upp ringen.,Yüzüğü aldın.,Взято каблучку. +You picked up the Offering Chalice.,TXT_OFFERINGCHALICE,,,,Sebral@[ao_cs] jsi obětní kalich.,Du samlede offerkalken op.,Du hast den Opferkelch genommen.,,Vi trovis oferdonan kalikon.,Encuentras un cáliz de ofrenda.,,Poimit uhrimaljan.,Vous avez pris le Calice d'obole.,Felvetted az Áldozati Kelyhet.,Hai raccolto il Calice delle Offerte.,寄贈された聖杯 取得。,번제 성배를 훔쳤다.,Je hebt de Offerbeker opgepakt.,Du plukket opp offerbegeret.,Podniosł@[irreg_3_pl] Kielich Ofiarny.,Você pegou o Cálice de Oferenda.,Apanhaste o Cálice de Oferenda.,Ai ridicat Potirul pentru Ofrande.,Получена чаша для подношений.,Покупио си Жртвени пехар.,Du plockade upp offerkalken.,Adak Kadehini aldın.,Взято чашу для жертвоприношення. +You picked up the ear.,TXT_EAR,,,,Sebral@[ao_cs] jsi ucho.,Du samlede øret op.,Du hast das Ohr gernommen.,Πήρες το αυτί.,Vi havas la orelon.,Tienes la oreja.,,Poimit korvan.,Vous avez pris l'oreille.,Felvetted a Fület.,Hai raccolto l'Orecchio.,耳 取得。,잘린 귀를 주웠다.,Je hebt het oor opgepakt.,Du plukket opp øret.,Podniosł@[irreg_3_pl] ucho.,Você pegou a orelha.,Apanhaste a orelha.,Ai ridicat urechea.,Получено ухо.,Покупио си уво.,Du plockade upp örat.,Kulağı aldın.,Взято вухо. +You picked up the broken power coupling.,TXT_BROKENCOUPLING,,,,Sebral@[ao_cs] jsi rozbitou spojku.,Du samlede den ødelagte strømkobling op.,Du hast den defekten Stromabnehmer genommen.,,Vi havas la rompitan energian kuplilon.,Tienes el acoplador de energía roto.,,Poimit rikkinäisen virtaliittimen.,Vous avez pris le coupleur énergétique cassé.,Felvetted a hibás tápcsatlakozót.,Hai raccolto la Coppia Energetica Rotta.,壊れたパワーカップリング 取得。,망가진 동력선 장치를 획득했다.,Je hebt de kapotte stroomkoppeling opgepakt.,Du plukket opp den ødelagte kraftkoblingen.,Podniosł@[irreg_3_pl] zepsute obwody zasilające.,Você pegou o acoplador de energia quebrado.,Apanhaste o acoplador de energia partido.,Ai ridicat cuplajul defect de curent.,Получена повреждённая муфта.,Покупио си неисправну спојницу напајања.,Du plockade upp den trasiga kraftkopplingen.,Kırık güç bağlantısını aldın.,Взято зламану силову муфту. +You picked up the Shadow armor.,TXT_SHADOWARMOR,,,You picked up the Shadow armour.,Sebral@[ao_cs] jsi krycí brnění.,Du samlede skyggerustningen op.,Du hast die Schattenrüstung genommen.,,Vi trovis ombran armaĵon.,Encuentras una armadura de sombra.,,Poimit varjohaarniskan.,Vous avez pris l'armure de l'ombre.,Felvetted az Árnyékpáncélt.,Hai raccolto l'Armatura Ombra.,シャドウアーマー 入手。,그림자 갑옷을 획득했다.,Je hebt het schaduwharnas opgepakt.,Du plukket opp Skygge-rustningen.,Podniosł@[irreg_3_pl] Cienisty Pancerz.,Você pegou a armadura das sombras.,Apanhaste a armadura das sombras.,Ai ridicat Armura Umbrei.,Получена теневая броня.,Покупио си оклоп сенки.,Du plockade upp skuggrustningen.,Gölge zırhını aldın.,Взято Тіньову броню. +You picked up the Environmental Suit.,TXT_ENVSUIT,,,,Sebral@[ao_cs] jsi ochranný oděv,Du samlede miljødragten op.,Du hast den Schutzanzug genommen.,,Vi trovis medi-ŝirman veston,Encuentras un traje NBQ.,,Poimit ympäristösuojapuvun.,Vous avez pris la combinaison hazmat.,Felvetted a Védőruhát.,Hai raccolto la Tuta Ambientale.,耐環境スーツ 入手。,환경 방호복을 획득했다.,Je hebt het beschermende pak opgepakt.,Du plukket opp miljødrakten.,Podniosł@[irreg_3_pl] Skafander Ochronny.,Você pegou o Traje de Proteção.,Apanhaste o Fato Protetor.,Ai ridicat Costumul de Protecție.,Получен защитный костюм.,Покупио си заштитно одело.,Du plockade upp miljödräkten.,Çevresel Kıyafeti aldın.,Взято захисний костюм. +You picked up the Guard Uniform.,TXT_GUARDUNIFORM,,,,Sebral@[ao_cs] jsi hlídačovu uniformu.,Du samlede vagtuniformen op.,Du hast die Wächteruniform genommen.,,Vi havas la uniformon de gardisto.,Tienes el uniforme de un guardia.,,Poimit vartijan univormun.,Vous avez pris l'Uniforme du garde.,Felvetted az Őr Egyenruhát.,Hai raccolto l'Uniforme da Guardia.,守衛の制服 入手。,경비 전투복을 획득했다.,Je hebt het wachtersuniform opgepakt.,Du plukket opp vaktuniformen.,Podniosł@[irreg_3_pl] Mundur Strażnika.,Você pegou o Uniforme de Guarda.,Apanhaste o Uniforme de Guarda.,Ai ridicat Uniforma de Paznic.,Получена униформа стражника.,Покупио си стражарску униформу,Du plockade upp vaktuniformen.,Muhafız Üniformasını aldın.,Взято уніформу охоронця. +You picked up the Officer's Uniform.,TXT_OFFICERSUNIFORM,,,,Sebral@[ao_cs] jsi důstojníkovu uniformu.,Du samlede officersuniformen op.,Du hast die Offiziersuniform genommen.,,Vi trovis oficiran uniformon.,Encuentras un uniforme de oficial.,,Poimit upseerin univormun.,Vous avez pris l'Uniforme de l'officier.,Felvetted a Tiszti Egyenruhát.,Hai raccolto l'Uniforme da Ufficiale.,士官の制服 入手。,장교 전투복을 획득했다.,Je hebt het officiersuniform opgepakt.,Du plukket opp offisersuniformen.,Podniosł@[irreg_3_pl] Mundur Oficera.,Você pegou o Uniforme de Oficial.,Apanhaste o Uniforme de Oficial.,Ai ridicat Uniforma Ofițerului.,Получена униформа офицера.,Покупио си официрску униформу,Du plockade upp officersuniformen.,Subay üniformasını aldın.,Взято офіцерську уніформу. +You picked up the flame thrower parts.,TXT_FTHROWERPARTS,,,,Sebral@[ao_cs] jsi součásti plamenometu.,Du samlede flammekasterdele op.,Du hast die Flammenwerferteile genommen.,,Vi havas la partojn de flamĵetilo.,Tienes las partes de un lanzallamas.,,Poimit liekinheittimen osat.,Vous avez pris les pièces du lance-flames.,Felvetted a lángszóró részeit.,Hai raccolto delle parti di Lanciafiamme.,火炎放射器の部品 入手。,화염방사기 부품을 획득했다.,Je hebt de vlammenwerperonderdelen opgepakt.,Du plukket opp delene til flammekasteren.,Podniosł@[irreg_3_pl] części miotacza ognia.,Você pegou as partes do lança-chamas.,Apanhaste as peças do lança-chamas.,Ai ridicat bucățile aruncătorului de flăcări.,Получены детали для огнемёта.,Покупио си делове за бацач пламена.,Du plockade upp delarna till flamkastaren.,Alev silahının parçalarını aldın.,Взято деталі для вогнемету. +You picked up the report.,TXT_REPORT,,,,Sebral@[ao_cs] jsi hlášení.,Du samlede rapporten op.,Du hast den Report genommen.,,Vi havas la raporton.,Tienes el reporte.,,Poimit raportin.,Vous avez pris le compte-rendu.,Felvetted a jelentést.,Hai raccolto il rapporto.,報告書 取得。,보고서를 획득했다.,Je hebt het rapport opgepakt.,Du plukket opp rapporten.,Podniosł@[irreg_3_pl] raport.,Você pegou o relatório.,Apanhaste o relatório.,Ai ridicat raportul.,Получен отчёт.,Покупио си извештај.,Du plockade upp rapporten.,Raporu aldın.,Взято звіт. +You picked up the info.,TXT_INFO,,,,Sebral@[ao_cs] jsi informace.,Du samlede oplysningerne op.,Du hast die Info genommen.,Πήρες της πληροφορίες,Vi havas la informojn.,Tienes la información.,,Poimit tiedot.,Vous avez pris l'info.,Felvetted az információt.,Hai raccolto delle Informazioni.,情報 取得。,정보를 획득했다.,Je hebt de informatie opgepakt.,Du plukket opp informasjonen.,Podniosł@[irreg_3_pl] informacje.,Você pegou a informação.,Apanhaste a informação.,Ai recepționat informația.,Получена сводка.,Покупио си инфо.,Du plockade upp informationen.,Bilgiyi aldın.,Отримано данні. +You picked up the Targeter.,TXT_TARGETER,,,,Sebral@[ao_cs] jsi zaměřovač.,Du samlede targeter op.,Du hast die Zielhilfe genommen.,Πήρες τον Στοχευτή.,Vi trovis celilon.,Encuentras una mira de arma.,,Poimit tähtäinlaitteen.,Vous avez pris le cibleur.,Felvetted a Célzóberendezést.,Hai raccolto il Puntatore.,照準器 入手。,조준기를 획득했다.,Je hebt het Richter opgepakt.,Du plukket opp Targeteren.,Podniosł@[irreg_3_pl] Namierzacz.,Você pegou a Mira.,Apanhaste a Mira.,Ai ridicat Țintitorul.,Получен целеуказатель.,Покупио си нишанитеља.,Du plockade upp targeter.,Hedefleyiciyi aldın.,Взято цілевказівник. +You picked up the Communicator.,TXT_COMMUNICATOR,,,,Sebral@[ao_cs] jsi komunikátor.,Du samlede kommunikatoren op.,Du hast den Kommunikator genommen.,,Vi trovis interfonon.,Encuentras un intercomunicador.,,Poimit viestintälaitteen.,Vous avez pris le Communicateur,Felvetted a Kommunikátort,Hai raccolto il Comunicatore.,コミュニケーター 取得。,연락장치를 획득했다.,Je hebt de Communicator opgepakt.,Du plukket opp kommunikatoren.,Podniosł@[irreg_3_pl] Komunikator.,Você pegou o Comunicador.,Apanhaste o Comunicador.,Ai ridicat Comunicatorul.,Получен передатчик.,Покупио си комуникатор.,Du plockade upp kommunikatorn.,İletişim cihazını aldın.,Взято комунікатор. +You picked up the coin.,TXT_COIN,,,,Sebral@[ao_cs] jsi minci.,Du samlede mønten op.,Du hast die Münze genommen.,Πήρες το κέρμα.,Vi trovis moneron.,Encuentras una moneda.,,Poimit kolikon.,Vous avez pris la pièce.,Felvetted az érmét.,Hai raccolto la Moneta.,コイン 入手。,동전을 주웠다.,Je hebt de munt opgepakt.,Du plukket opp mynten.,Podniosł@[irreg_3_pl] monetę.,Você pegou a moeda.,Apanhaste a moeda.,Ai ridicat moneda.,Получена монета.,Покупио си новчић.,Du plockade upp myntet.,Parayı aldın.,Взято монету. +You picked up %d gold.,TXT_XGOLD,,,,Sebral@[ao_cs] jsi %d zlatých.,Du samlede %d guld op.,Du hast %d Gold genommen.,,Vi trovis %d da oro.,Encuentras %d monedas de oro.,,Poimit kultaa %d arvosta.,Vous avez pris %d pièces.,Felvettél %d aranyat.,Hai raccolto %d pezzi d'oro.,%d ゴールド 入手。,골드 %d 개를 획득했다.,Je hebt %d goud opgepakt.,Du plukket opp %d gull.,Podniosł@[irreg_3_pl] %d monet.,Você pegou %d moedas de ouro.,Apanhaste %d moedas de ouro.,Ai ridicat %g bucăți de aur.,Получено %d золотых.,Покупио си %d златника.,Du plockade upp %d guld.,%d altın aldın.,Взято %d золотих. +You picked up the Teleporter Beacon.,TXT_BEACON,,,,Sebral@[ao_cs] jsi teleportační maják.,Du samlede Teleporter Beacon op.,Du hast das Teleportersignal genommen.,,Vi trovis teleportil-signalilon.,Encuentras una baliza de teletransporte.,,Poimit kaukosiirrinmajakan.,Vous avez pris la balise de téléporteur.,Felvetted a Teleport jelzőt.,Hai raccolto il Radiofaro per Teletrasporto.,テレポータービーコン 取得。,텔레포터 비콘을 획득했다.,Je hebt de teleporterbaken opgepakt.,Du plukket opp Teleporter-signalet.,Podniosł@[irreg_3_pl] Nadajnik Teleportera.,Você pegou o Sinalizador de Teletransporte.,Apanhaste o Sinalizador de Teletransporte.,Ai ridicat Luminatorul pentru Teleportor.,Получен телепортационный маяк.,Покупио си одашиљач за телепортовање.,Du plockade upp teleporterfyren.,Işınlayıcı İşaretini aldın.,Взято пристрій телепортації. +You picked up the Degnin Ore.,TXT_DEGNINORE,,,,Sebral@[ao_cs] jsi degninskou rudu.,Du samlede Degnin Ore op.,Du hast das Degnin-Erz genommen.,,Vi trovis degninan minaĵon.,Encuentras mineral de Degnin.,,Poimit Degnin-malmia.,Vous avez pris le minerai de Degnin.,Felvetted a Degnin Ércet.,Hai raccolto il Minerale Degnin.,デグニン鉱石 取得。,데그닌 광석을 획득했다.,Je hebt het Degnin-erts opgepakt.,Du plukket opp Degnin-malmen.,Podniosł@[irreg_3_pl] Rudę Degninu.,Você pegou o Minério Degnin.,Apanhaste o Minério Degnin.,Ai ridicat minereul de Degnin.,Получена дегнинская руда.,Покупио си Дегнинску руду.,Du plockade upp Degnin Malm.,Degnin Cevherini aldın.,Взято Дегінську руду. +You picked up the scanner.,TXT_SCANNER,,,,Sebral@[ao_cs] jsi skener.,Du samlede scanneren op.,Du hast den Scanner genommen.,Πήρες το σαρωτή.,Vi trovis skanilon.,Encuentras un escáner.,,Poimit skannerin.,Vous avez pris l'analyseur.,Felvetted a szkennert.,Hai raccolto lo Scanner.,スキャナー 入手。,탐지기를 획득했다.,Je hebt de scanner opgepakt.,Du plukket opp skanneren.,Podniosł@[irreg_3_pl] skaner.,Você pegou o scanner.,Apanhaste o scanner.,Ai ridicat scannerul.,Получен сканер.,Покупио си скенер.,Du plockade upp skannern.,Tarayıcıyı aldın.,Отримано сканер. "The scanner won't work without a map! -",TXT_NEEDMAP,,,,Skener bez mapy fungovat nebude!,Der Scanner kann ohne Karte nicht funktionieren.,Ο σαρωτής δέν θα δουλέψει χωρίς ένα χάρτη!,La skanilo ne funkcios sen mapo!,¡El escáner no funcionará sin un mapa!,,Skanneri ei toimi ilman karttaa!,"L'analyseur ne marchera pas sans une carte! -",Térkép nélkül nem fog működni a szkenner!,Lo scanner non può funzionare senza una mappa!,マップが無ければ スキャナーは機能しない!,지도 없이는 탐지기를 사용할 수 없다!,De scanner werkt niet zonder een kaart!,Skaner nie zadziała bez mapy!,"O scanner não funciona sem um mapa! +",TXT_NEEDMAP,,,,Skener bez mapy fungovat nebude!,"Scanneren virker ikke uden et kort! +",Der Scanner kann ohne Karte nicht funktionieren.,Ο σαρωτής δέν θα δουλέψει χωρίς ένα χάρτη!,La skanilo ne funkcias sen mapo!,¡El escáner no funciona sin un mapa!,,Skanneri ei toimi ilman karttaa!,"L'analyseur ne marchera pas sans une carte! +",Térkép nélkül nem fog működni a szkenner!,Lo scanner non può funzionare senza una mappa!,マップが無ければ スキャナーは機能しない!,지도 없이는 탐지기를 사용할 수 없다!,De scanner werkt niet zonder een kaart!,"Skanneren virker ikke uten et kart! +",Skaner nie zadziała bez mapy!,"O scanner não funciona sem um mapa! ",,Scannerul nu poate funcționa fără o hartă!,"Сканер не будет работать без карты! -",Скенер неће радити без мапе! -You picked up the Prison pass.,TXT_PRISONPASS,,,,Sebral@[ao_cs] jsi vězeňskou propustku.,Du hast den Gefängnispass genommen.,,Vi prenis la Malliberejan pasaĵon.,Recogiste el pase de la Prisión.,,Poimit vankilan pääsyluvan.,Vous avez pris le passe de la prison.,Felvetted a Börtön belépőkártyát.,Hai raccolto il lasciapassare per la Prigione.,刑務所の許可証 取得。,감옥 통행증을 획득했다.,Je hebt de Gevangenispas opgehaald.,Podniosł@[irreg_3_pl] przepustkę do Więzienia.,Você pegou o passe da Prisão.,Apanhaste o passe da Prisão.,Ai ridicat Legitimația pentru Închisoare.,Получен пропуск в тюрьму.,Покупио си затворску пропусницу. -You picked up the crossbow.,TXT_STRIFECROSSBOW,,,,Sebral@[ao_cs] jsi kuši.,Du hast die Armbrust genommen.,Πήρες το τόξο,Vi prenis la arbaleston.,Recogiste la ballesta.,,Poimit jousipyssyn.,Vous avez pris l'arbalète.,Felvetted a számszeríjat.,Hai raccolto la Balestra.,クロスボウ 入手。,석궁을 획득했다.,Je hebt de kruisboog opgehaald.,Podniosł@[irreg_3_pl] kuszę.,Você pegou a besta.,Apanhaste uma besta.,Ai ridicat arbaleta.,Получен арбалет.,Покупио си самострел. -You picked up the assault gun.,TXT_ASSAULTGUN,,,,Sebral@[ao_cs] jsi pušku.,Du hast das Sturmgewehr genommen.,Πήρες το πολυβόλο.,Vi prenis la atakan pafilon.,Recogiste el fusil de asalto.,,Poimit rynnäkkökiväärin.,Vous avez pris le fusil d'assaut.,Felvetted a gépfegyvert.,Hai raccolto il fucile d'assalto.,アサルトガン 入手。,돌격소총을 획득했다.,Je hebt het aanvalswapen opgehaald.,Podniosł@[irreg_3_pl] karabin szturmowy.,Você pegou o fuzil de assalto.,Apanhaste a arma de assalto.,Ai ridicat pușca de asalt.,Получена штурмовая винтовка.,Покупио си аутоматску пушку. -You picked up the mini missile launcher.,TXT_MMLAUNCHER,,,,Sebral@[ao_cs] jsi miniraketomet.,Du hast den Miniraketenwerfer genommen.,Πήρες το μίνι πυραυλοβόλο.,Vi prenis la misilĵetetilon.,Recogiste el mini lanzacohetes.,,Poimit miniohjuslaukaisimen.,Vous avez pris le lance mini-missile.,Felvetted a minirakétavetőt.,Hai raccolto il Mini-Lanciamissili.,ミニミサイル ランチャー入手。,미니 미사일 런쳐를 획득했다.,Je hebt de mini-raketwerper opgehaald.,Podniosł@[irreg_3_pl] wyrzutnię minipocisków.,Você pegou o mini lança-mísseis.,Apanhaste o mini lança-mísseis,Ai ridicat mini lansatorul de rachete.,Получена мини-ракетница.,Покупио си мини ручни бацач. -You picked up the flame thrower.,TXT_FLAMER,,,,Sebral@[ao_cs] jsi plamenomet.,Du hast den Flammenwerfer genommen.,Πήρες το φλογοβόλο.,Vi prenis la flamĵetilon.,Recogiste el lanzallamas.,,Poimit liekinheittimen.,Vous avez pris le lance-flames.,Felvetted a lángszórót.,Hai raccolto il Lanciafiamme.,火炎放射器 入手。,완성된 화염방사기를 얻었다.,Je hebt de vlammenwerper opgehaald.,Podniosł@[irreg_3_pl] miotacz ognia.,Você pegou o lança-chamas.,Apanhaste o lança-chamas.,Ai ridicat aruncătorul de flăcări.,Получен огнемёт.,Покупио си бацач пламена. -You picked up the mauler.,TXT_MAULER,,,,Sebral@[ao_cs] jsi trhač.,Du hast den Vernichter genommen.,,Vi prenis la vundegilon.,Recogiste el triturador.,,Poimit moukarin.,Vous avez pris le Broyeur.,Felvetted a sorvasztót.,Hai raccolto il Pestatore.,マウラー 入手。,마울러를 획득했다.,Je hebt de mauler opgehaald.,Podniosł@[irreg_3_pl] miażdżyciel.,Você pegou o desintegrador.,Apanhaste o desintegrador.,Ai ridicat sfâșietorul.,Получен истязатель.,Покупио си маулер. -You picked up the Grenade launcher.,TXT_GLAUNCHER,,,,Sebral@[ao_cs] jsi granátomet.,Du hast den Granatwerfer genommen.,Πήρες το εκτοξευτη χειροβομβίδων.,Vi prenis la Gernadĵetilon.,Recogiste el lanzagranadas.,,Poimit kranaatinheittimen.,Vous avez pris le lance-grenades,Felvetted a gránátvetőt.,Hai raccolto il Lanciagranate.,グレネードランチャー 入手。,유탄발사기를 획득했다.,Je hebt de granaatwerper opgehaald.,Podniosł@[irreg_3_pl] wyrzutnię granatów.,Você pegou o lança-granadas.,Apanhaste o lança-granadas.,Ai ridicat Lansatorul de rachete.,Получен гранатомёт.,Покупио си бацач граната. -You picked up the SIGIL.,TXT_SIGIL,,,,Sebral@[ao_cs] jsi Pečeť.,Du hast das SIGIL genommen.,,Vi prenis la SIGELON.,Recogiste el EMBLEMA.,,Poimit SINETIN.,Vous avez pris le SIGIL.,Felvetted a Pecsétet.,Hai raccolto il SIGILLO.,シジル 取得。,시질은 이제 당신의 것이다.,Je hebt de SIGIL opgehaald.,Podniosł@[irreg_3_pl] SYMBOL.,Você pegou o SIGILO.,Apanhaste o SIGILO,Ai ridicat SIGILIUL.,Получен СИГИЛ.,Покупио си СИГИЛ. -You picked up the Base Key.,TXT_BASEKEY,,,,Sebral@[ao_cs] jsi klíč od základny.,Du hast den Basisschlüssel genommen.,,Vi prenis la Ŝliosilon de la Bazejo.,Recogiste la Llave de la Base.,,Poimit tukikohdan avaimen.,Vous avez pris la clé de la Base.,Felvetted a Bázis kulcsát.,Hai raccolto la chiave della Base.,基地のキー 取得。,기지 키를 획득했다.,Je hebt de Basissleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Bazy.,Você pegou a Chave da Base.,Apanhaste a Chave da Base.,Ai ridicat Cheia Bazei.,Получен ключ от базы.,Покупио си кључ базе. -You picked up the Govs Key.,TXT_GOVSKEY,,,,Sebral@[ao_cs] jsi klíč ke guvernérovi.,Du hast den Gouverneursschlüssel genommen.,,Vi prenis la Ŝliosilon de la Registaro.,Recogiste la Llave del Gobernador.,,Poimit kuvernöörin avaimen.,Vous avez pris la clé du Gouverneur.,Felvetted a Kormányzó parcellájának kulcsát.,Hai raccolto la chiave del Governatore.,政府のキー 取得。,총독의 키를 획득했다.,Je hebt de Gouverneursleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz Gubernatora.,Você pegou a Chave do Governador.,Apanhaste a Chave do Governador.,Ai ridicat Cheia Guvernatorului.,Получен ключ губернатора.,Покупио си клуч гувернанте. -You picked up the Passcard.,TXT_PASSCARD,,,,Sebral@[ao_cs] jsi průkaz.,Du hast die Zugangskarte genommen.,,Vi prenis la Paskarton.,Recogiste el Pase de Acceso.,,Poimit avainkortin.,Vous avez pris le passe.,Felvetted a Belépőkártyát.,Hai raccolto la Tessera Lasciapassare.,パスカード 取得。,통행 카드를 획득했다.,Je hebt de paspoortkaart opgehaald.,Podniosł@[irreg_3_pl] Kartę Dostępu.,Você pegou o Cartão de Acesso.,Apanhaste o Cartão de Acesso.,Ai ridicat Legitimația.,Получен пропуск.,Покупио си пасош. -You picked up the ID Badge.,TXT_IDBADGE,,,,Sebral@[ao_cs] jsi identifikační odznak.,Du hast die Identitätskarte genommen.,,Vi prenis la Identigo-insignon.,Recogiste la insignia de Identificación.,,Poimit henkilötunnisteen.,Vous avez pris le Badge d'identification.,Felvetted az Azonosítójelvényt.,Hai raccolto il Distintivo.,IDバッジ 取得。,신분 휘장을 획득했다.,Je hebt de ID Badge opgehaald.,Podniosł@[irreg_3_pl] Odznakę Identyfikacyjną.,Você pegou o Crachá de Identificação.,Apanhaste o Crachá de Identificação,Ai ridicat Ecusonul de Identificare.,Получена личная карта.,Покупио си личну карту. -You picked up the Prison Key.,TXT_PRISONKEY,,,,Sebral@[ao_cs] jsi klič k vězení.,Du hast den Gefängnisschlüssel genommen.,,Vi prenis la Ŝlosilon de la Malliberejo.,Recogiste la Llave de la Prisión.,,Poimit vankilan avaimen.,Vous avez pris la clé de la Prison.,Felvetted a Börtönkulcsot.,Hai raccolto la chiave della Prigione.,刑務所のキー 取得。,감옥 키를 획득했다.,Je hebt de Gevangenissleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Więzienia.,Você pegou a Chave da Prisão.,Apanhaste a Chave da Prisão.,Ai ridicat Cheia Închisorii.,Получен ключ от тюрьмы.,Покупио си затворски кључ -You picked up the Severed Hand.,TXT_SEVEREDHAND,,,,Sebral@[ao_cs] jsi useknutou ruku.,Du hast die abgetrennte Hand genommen.,,Vi prenis la Apartan Manon.,Recogiste la Mano Cercenada.,,Poimit katkenneen käden.,Vous avez pris la main coupée.,Felvetted a Levágott kezet.,Hai raccolto la Mano Mozzata.,切り取った手 取得。,잘린 손목을 주웠다.,Je hebt de Gescheurde Hand opgehaald.,Podniosł@[irreg_3_pl] Odciętą Rękę.,Você pegou a Mão Decepada.,Apanhaste a Mão Desmenbrada.,Ai ridicat Mâna Retezată.,Получена отрезанная рука.,Покупио си шаку -You picked up the Power1 Key.,TXT_POWER1KEY,,,,Sebral@[ao_cs] jsi klíč k elektrárně 1.,Du hast den Kraftwerksschlüssel 1 genommen,,Vi prenis Povŝlosilon1.,Recogiste la Llave de Energía 1.,,Poimit Power1-avaimen.,Vous avez pris la clé Power1.,Felvetted az Áram1 kulcsot.,Hai raccolto la chiave della Centrale n.1,パワー1キー 取得。,발전소 1호 키를 획득했다.,Je hebt de Centrale Sleutel 1 opgehaald.,Podniosł@[irreg_3_pl] Klucz do Elektrowni 1.,Você pegou a Chave da Usina 1.,Apanhaste a Chave Energética 1,Ai ridicat Cheia Putere1.,Получен ключ электростанции 1.,Покупио си први кључ од електране. -You picked up the Power2 Key.,TXT_POWER2KEY,,,,Sebral@[ao_cs] jsi klíč k elektrárně 2.,Du hast den Kraftwerksschlüssel 2 genommen,,Vi prenis Povŝlosilon2.,Recogiste la Llave de Energía 2.,,Poimit Power2-avaimen.,Vous avez pris la clé Power2.,Felvetted az Áram2 kulcsot.,Hai raccolto la chiave della Centrale n.2,パワー2キー 取得。,발전소 2호 키를 획득했다.,Je hebt de Centrale Sleutel 2 opgehaald.,Podniosł@[irreg_3_pl] Klucz do Elektrowni 2.,Você pegou a Chave da Usina 2.,Apanhaste a Chave Energética 2,Ai ridicat Cheia Putere2.,Получен ключ электростанции 2.,Покупио си други кључ од електране. -You picked up the Power3 Key.,TXT_POWER3KEY,,,,Sebral@[ao_cs] jsi klíč k elektrárně 3.,Du hast den Kraftwerksschlüssel 3 genommen,,Vi prenis Povŝlosilon3.,Recogiste la Llave de Energía 3.,,Poimit Power3-avaimen.,Vous avez pris la clé Power3.,Felvetted az Áram3 kulcsot.,Hai raccolto la chiave della Centrale n.3,パワー3キー 取得。,발전소 3호 키를 획득했다.,Je hebt de Centrale Sleutel 3 opgehaald.,Podniosł@[irreg_3_pl] Klucz do Elektrowni 3.,Você pegou a Chave da Usina 3.,Apanhaste a Chave Energética 3,Ai ridicat Cheia Putere3.,Получен ключ электростанции 3.,Покупио си трећи кључ од електране. -You picked up the Gold Key.,TXT_GOLDKEY,,,,Sebral@[ao_cs] jsi zlatý klíč.,Du hast den Goldschlüssel genommen.,,Vi prenis la Orkoloran Ŝlosilon.,Recogiste la Llave de Oro.,,Poimit kulta-avaimen.,Vous avez pris la clé d'or.,Felvetted az Aranykulcsot.,Hai raccolto la chiave dorata,ゴールドキー 取得。,황금 키를 획득했다.,Je hebt de gouden sleutel opgehaald.,Podniosł@[irreg_3_pl] Złoty Klucz.,Você pegou a Chave de Ouro.,Apanhaste a Chave de Ouro,Ai ridicat Cheia de Aur.,Получен золотой ключ.,Покупио си златни кључ. -You picked up the ID Card.,TXT_IDCARD,,,,Sebral@[ao_cs] jsi ID kartu.,Du hast den Ausweis genommen.,,Vi prenis la Identigo-karton.,Recogiste la Tarjeta de Identificación.,,Poimit henkilökortin.,Vous avez pris la Carte d'identité.,Felvetted az Igazolványt.,Hai raccolto la Tessera di Identificazione.,IDカード 取得。,신분증을 획득했다.,Je hebt de ID-kaart opgehaald.,Podniosł@[irreg_3_pl] Kartę Identyfikacyjną.,Você pegou o Cartão de Identifiçacão.,Apanhaste o Cartão de Identificação,Ai ridicat Cardul de Identitate.,Получено удостоверение.,Покупио си идентификациону картицу. -You picked up the Silver Key.,TXT_SILVERKEY,,,,Sebral@[ao_cs] jsi stříbrný klíč.,Du hast den Silberschlüssel genommen.,,Vi prenis la Arĝentkoloran Ŝlosilon.,Recogiste la Llave Plateada.,,Poimit hopea-avaimen.,Vous avez pris la clé d'argent.,Felvetted az ezüstkulcsot.,Hai raccolto la chiave argentata,シルバーキー 取得。,은 키를 획득했다.,Je hebt de zilveren sleutel opgehaald.,Podniosł@[irreg_3_pl] Srebrny Klucz.,Você pegou a Chave de Prata.,Apanhaste a Chave de Prata,Ai ridicat Cheia de Argint.,Получен серебряный ключ.,Покупио си сребрни кључ. -You picked up the Oracle Key.,TXT_ORACLEKEY,,,,Sebral@[ao_cs] jsi věštcův klíč.,Du hast den Orakelschlüssel genommen.,,Vi prenis la Ŝlosilo de la Oraklo,Recogiste la Llave del Oráculo.,,Poimit Oraakkelin avaimen.,Vous avez pris la clé Oraclé.,Felvetted az Orákulum kulcsát.,Hai raccolto la chiave dell'Oracolo.,オラクルキー 取得。,오라클 키를 획득했다.,Je hebt de Orakelsleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Wyroczni.,Você pegou a Chave do Oráculo.,Apanhaste a Chave do Oráculo.,Ai ridicat Cheia Oracol.,Получен ключ Оракула.,Покупио си кључ пророка -You picked up the Military ID.,TXT_MILITARYID,,,,Sebral@[ao_cs] jsi vojenské ID.,Du hast den Militärausweis genommen.,,Vi prenis la Militan Identigon.,Recogiste la Identificación Militar.,,Poimit sotilastunnuksen.,Vous avez pris l'ID Militaire.,Felvetted a Katonai igazolványt.,Hai raccolto l'Identificativo Militare.,ミリタリーID 取得。,군용 아이디를 획득했다.,Je hebt de militaire ID opgehaald.,Podniosł@[irreg_3_pl] Wojskowy Identyfikator.,Você pegou a Identificação Militar.,Apanhaste a Identificação Militar.,Ai ridicat Legitimația Militară.,Получено военное удостоверение.,Покупио си војну идентификацију -You picked up the Order Key.,TXT_ORDERKEY,,,,Sebral@[ao_cs] jsi klíč Řádu.,Du hast den Ordensschlüssel genommen.,,Vi prenis la Ŝlosilon de la Ordeno.,Recogiste la Llave de la Orden.,,Poimit Veljeskunnan avaimen.,Vous avez pris la clé de l'Ordre.,Felvetted a Rend kulcsát.,Hai raccolto la chiave dell'Ordine.,オーダーキー 取得。,오더의 키를 획득했다.,Je hebt de Ordersleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz Zakonu.,Você pegou a Chave da Ordem.,Apanhaste a Chave da Ordem.,Ai ridicat Cheia Ordinului.,Получен ключ Ордена.,Покупио си кључ одреда -You picked up the Warehouse Key.,TXT_WAREHOUSEKEY,,,,Sebral@[ao_cs] jsi klíč ke skladu.,Du hast den Lagerhausschlüssel genommen,,Vi prenis la Ŝlosilon de la Magazeno.,Recogiste la Llave del Almacén.,,Poimit varaston avaimen.,Vous avez pris la clé de l'entrepôt.,Felvetted a Raktár kulcsát.,Hai raccolto la chiave del Magazzino.,倉庫のキー 取得。,창고 키를 획득했다.,Je hebt de Magazijnsleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Magazynu.,Você pegou a Chave do Armazém.,Apanhaste a Chave do Armazém,Ai ridicat Cheia Depozitului.,Получен ключ от склада.,Покупио си кључ складишта -You picked up the Brass Key.,TXT_BRASSKEY,,,,Sebral@[ao_cs] jsi mosazný klíč.,Du hast den Messingschlüssel genommen.,,Vi prenis la Latunan Ŝlosilon.,Recogiste la Llave de Latón.,,Poimit messinkiavaimen.,Vous avez pris la clé de bronze.,Felvetted a Rézkulcsot.,Hai raccolto la chiave d'Ottone.,ブラスキー 取得。,황동 키를 획득했다.,Je hebt de messing sleutel opgehaald.,Podniosł@[irreg_3_pl] Mosiężny Klucz.,Você pegou a Chave de Latão.,Apanhaste a Chave de Latão,Ai ridicat Cheia din Alamă.,Получен латунный ключ.,Покупио си кључ месинга -You picked up the Red Crystal Key.,TXT_REDCRYSTAL,,,,Sebral@[ao_cs] jsi červený krystalový klíč.,Du hast den roten Kristallschlüssel genommen.,,Vi prenis la Ruĝan Kristalan Ŝlosilon.,Recogiste la Llave de Cristal Rojo.,,Poimit punaisen kristalliavaimen.,Vous avez pris la clé cristal rouge.,Felvetted a Vörös Kristály Kulcsot.,Hai raccolto la chiave del Cristallo Rosso.,赤水晶のキー 取得。,적색 크리스탈 키를 획득했다.,Je hebt de Rode Kristallen Sleutel opgehaald.,Podniosł@[irreg_3_pl] Czerwony Kryształowy Klucz.,Você pegou a Chave de Cristal Vermelho.,Apanhaste a Chave de Cristal Vermelho.,Ai ridicat Cheia din Cristal Roșu.,Получен красный ключ-кристалл.,Покупио си кључ од црвеног кристала -You picked up the Blue Crystal Key.,TXT_BLUECRYSTAL,,,,Sebral@[ao_cs] jsi modrý krystalový klíč.,Du hast den blauen Kristallschlüssel genommen.,,Vi prenis la Bluan Kristalan Ŝlosilon,Recogiste la Llave de Cristal Azul.,,Poimit sinisen kristalliavaimen.,Vous avez pris la clé cristal bleu.,Felvetted a Kék Kristály Kulcsot.,Hai raccolto la chiave del Cristallo Blu.,青水晶のキー 取得。,청색 크리스탈 키를 획득했다.,Je hebt de Blauwe Kristallen Sleutel opgehaald.,Podniosł@[irreg_3_pl] Niebieski Kryształowy Klucz.,Você pegou a Chave de Cristal Azul.,Apanhaste a Chave de Cristal Azul.,Ai ridicat Cheia din Cristal Albastru.,Получен синий ключ-кристалл.,Покупио си кључ од плавог кристала -You picked up the Chapel Key.,TXT_CHAPELKEY,,,,Sebral@[ao_cs] jsi klíč ke kapli.,Du hast den Kapellenschlüssel genommen.,,Vi prenis la Ŝlosilon de la Preĝejeto.,Recogiste la Llave de la Capilla.,,Poimit kappelin avaimen.,Vous avez pris la clé de la chapel.,Felvetted a Kápolna Kulcsát.,Hai raccolto la chiave della Cappella,チャペルキー 取得。,예배당 키를 획득했다.,Je hebt de Kapelsleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Kaplicy.,Você pegou a Chave da Capela.,Apanhaste a Chave da Capela.,Ai ridicat Cheia Capelei.,Получен ключ от часовни.,Покупио си кључ капеле -You picked up the Catacomb Key.,TXT_CATACOMBKEY,,,,Sebral@[ao_cs] jsi klíč do katakomb.,Du hast den Katakombenschlüssel genommen.,,Vi prenis la Ŝlosilon de la Katakombo.,Recogiste la Llave de la Catacumba.,,Poimit katakombin avaimen.,Vous avez pris la clé des Catacombes.,Felvetted a Katakombák kulcsát.,Hai raccolto la chiave delle Catacombe.,カタコンベキー 取得。,고대 묘지 키를 획득했다.,Je hebt de Catacombesleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Katakumb.,Você pegou a Chave da Catacumba.,Apanhaste a Chave da Catacumba.,Ai ridicat Cheia Catacombei.,Получен ключ от катакомб.,Покупио си кључ катакомбе -You picked up the Security Key.,TXT_SECURITYKEY,,,,Sebral@[ao_cs] jsi klíč ochranky.,Du hast den Sicherheitsschlüssel genommen.,,Vi prenis la Sekurecŝlosilon.,Recogiste la Llave de Seguridad.,,Poimit turvamiesavaimen.,Vous avez pris la clé de la Sécurité.,Felvetted a Biztonsági Kulcsot.,Hai raccolto la chiave della Sicurezza.,警備のキー 取得。,보안 키를 획득했다.,Je hebt de Beveiligingssleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz Ochrony.,Você pegou a Chave de Seguranca.,Apanhaste a Chave de Segurança,Ai ridicat Cheia Securității.,Получен ключ охраны.,Покупио си кључ обезбеђења -You picked up the Core Key.,TXT_COREKEY,,,,Sebral@[ao_cs] jsi klíč k jádru.,Du hast den Reaktorschlüssel genommen.,,Vi prenis la Ŝlosilon de la Kernejo.,Recogiste la Llave del Núcleo.,,Poimit ytimen avaimen.,Vous avez pris la clé du réacteur.,Felvetted a Mag kulcsát.,Hai raccolto la chiave del Nucleo.,コアキー 取得。,중심부 키를 획득했다.,Je hebt de Reactorsleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Rdzenia.,Você pegou a Chave do Núcleo.,Apanhaste a Chave do Núcleo.,Ai ridicat Cheia Nucleului.,Получен ключ от реактора.,Покупио си кључ језгра -You picked up the Mauler Key.,TXT_MAULERKEY,,,,Sebral@[ao_cs] jsi klíč k trhačům.,Du hast den Vernichterschlüssel genommen.,,Vi prenis la Ŝlosilon de la Vundegilo.,Recogiste la Llave del Triturador.,,Poimit moukarin avaimen.,Vous avez pris la clé du Broyeur.,Felvetted a sorvasztó kulcsát -- vagy mi ez is majd megnézem,Hai raccolto la chiave del Pestatore.,マウラーキー 取得。,마울러 키를 획득했다.,Je hebt de Maulersleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Magazynu Miażdżycieli.,Você pegou a Chave do Mauler.,Apanhaste a Chave do Mauler.,Ai ridicat Cheia Sfâșietorului.,Получен ключ истязателя.,Покупио си кључ Маулера. -You picked up the Factory Key.,TXT_FACTORYKEY,,,,Sebral@[ao_cs] jsi klíč do továrny.,Du hast den Fabrikschlüssel genommen.,,Vi prenis la Ŝlosilon de la Fabriko.,Recogiste la Llave de la Fábrica.,,Poimit tehtaan avaimen.,Vous avez pris la clé de l'usine.,Felvetted a Gyár kulcsát.,Hai raccolto la chiave della Fabbrica.,工場のキー 取得。,공장 키를 획득했다.,Je hebt de Fabriekssleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Fabryki.,Você pegou a Chave da Fábrica.,Apanhaste a Chave da Fábrica.,Ai ridicat Cheia Fabricii.,Получен ключ от фабрики.,Покупио си кључ фабрике -You picked up the Mine Key.,TXT_MINEKEY,,,,Sebral@[ao_cs] jsi klíč do dolů.,Du hast den Minenschlüssel genommen.,,Vi prenis la Ŝlosilon de la Minejo.,Recogiste la Llave de la Mina.,,Poimit kaivoksen avaimen.,Vous avez pris la clé de la mine.,Felvetted a Bánya kulcsát.,Hai raccolto la chiave della Miniera.,鉱山のキー 取得。,탄광 키를 획득했다.,Je hebt de Mijnsleutel opgehaald.,Podniosł@[irreg_3_pl] Klucz do Kopalni.,Você pegou a Chave da Mina.,Apanhaste a Chave da Mina.,Ai ridicat Cheia Minei.,Получен ключ от шахт.,Покупио си кључ рудника -You picked up the New Key5.,TXT_NEWKEY5,,,,Sebral@[ao_cs] jsi nový klíč 5,Du hast den neuen Schlüssel 5 genommen.,,Vi prenis la Novan Ŝlosilon5.,Recogiste la Llave Nueva5.,,Poimit uuden 5-avaimen.,Vous avez pris la nouvelle clé 5.,Felvetted az Új kulcs5-öt.,Hai raccolto la Nuova Chiave n.5,ニューキー5 取得。,새로운 키5를 획득했다.,Je hebt de nieuwe sleutel 5 opgehaald.,Podniosł@[irreg_3_pl] Nowy Klucz5,Você pegou a Chave Nova 5.,Apanhaste a Chave Nova 5.,Ai ridicat Cheia Nouă5.,Получен Новый Ключ5.,Покупио си нови кључ5 -You picked up the Oracle Pass.,TXT_ORACLEPASS,,,,Sebral@[ao_cs] jsi věštcovu propustku.,Du hast den Orakelpass genommen.,,Vi prenis la Pasaĵo de la Okralo.,Recogiste el Pase del Oráculo.,,Poimit Oraakkelin passin.,Vous avez pris le passe de l'Oracle.,Felvetted az Orákulum Belépőkártyáját.,Hai raccolto il Lasciapassare dell'Oracolo.,オラクルパス 取得。,오라클의 통행증을 획득했다.,Je hebt de Orakelkaart opgehaald.,Podniosł@[irreg_3_pl] Przepustkę Wyroczni.,Você pegou o Passe do Oráculo.,Apanhaste o Passe do Oráculo.,Ai ridicat Legitimația Oracol.,Получен пропуск Оракула.,Покупио си пророкову пропусницу -You picked up the HE-Grenade Rounds.,TXT_HEGRENADES,,,,Sebral@[ao_cs] jsi výbušné granáty.,Du hast die HE-Granaten genommen.,,Vi prenis la PE-Gernadmuniciojn.,Recogiste las Granadas HE.,,Poimit räjähdekranaattiammuksia.,Vous avez pris les Grenades Explosives.,Felvetted a HE-Gránátokat.,Hai raccolto delle granate ad Alto Potenziale,HEグレネード弾 入手。,고폭 유탄을 획득했다.,Je hebt de HE-granaten opgehaald.,Podniosł@[irreg_3_pl] Wiązkę Granatów.,Você pegou as Granadas Explosivas.,Apanhaste as Granadas Explosivas.,Ai ridicat Grenadele Explozive.,Получена связка гранат.,Покупио си ХЕ-Граната чауре -You picked up the Phosphorus-Grenade Rounds.,TXT_PHGRENADES,,,,Sebral@[ao_cs] jsi fosforečné granáty.,Du hasr die Phosphorgranaten genommen.,,Vi prenis la Fosforajn Gernadmuniciojn.,Recogiste las Granadas de Fósforo.,,Poimit fosforikranaattiammuksia.,Vous avez pris les Grenades Phosphoriques.,Felvetted a Foszfor-gránátokat.,Hai raccolto delle Granate al Fosforo.,白リングレネード弾 入手。,소이 유탄을 획득했다.,Je hebt de Fosforgranaten opgehaald.,Podniosł@[irreg_3_pl] Wiązkę Fosforowych Granatów.,Você pegou as Granadas de Fósforo.,Apanhaste as Granadas de Fósforo.,Ai ridicat Grenadele cu Fosfor.,Получена связка фосфорных гранат.,Покупио си шаржер фосфорних граната. -You picked up the clip of bullets.,TXT_CLIPOFBULLETS,,,,Sebral@[ao_cs] jsi zásobník.,Du hast die Gewehrmunition genommen.,Πήρες το κουτάκι με σφαίρες.,Vi prenis la kuglujon.,Recogiste un cargador con balas.,,Poimit luotilippaan.,Vous avez pris le Chargeur.,Felvettél egy tár lőszert.,Hai raccolto un caricatore di proiettili.,銃弾倉 入手。,돌격소총 탄창을 획득했다.,Je hebt de clip van de kogels opgehaald.,Podniosł@[irreg_3_pl] magazynek.,Você pegou o carregador.,Apanhaste o carregador.,Ai ridicat cartușul cu gloanțe.,Получена обойма., -You picked up the box of bullets.,TXT_BOXOFBULLETS,,,,Sebral@[ao_cs] jsi krabici kulek.,Du hast die Munitionskiste genommen.,Πήρες το κουτί με σφαίρες.,Vi prenis la kuglarujon.,Recogiste una caja de balas.,,Poimit luotilaatikon.,Vous avez pris la boîte de balles.,Felvettél egy doboz lőszert.,Hai raccolto una scatola di proiettili.,弾薬箱 入手。,돌격소총 탄약 박스를 획득했다.,Je hebt de doos met kogels opgehaald.,Podniosł@[irreg_3_pl] pudło z amunicją.,Você pegou a caixa de balas.,Apanhaste a caixa de balas.,Ai ridicat cutia cu gloanțe.,Получена коробка патронов.,Покупио си кутију меткова -You picked up the mini missiles.,TXT_MINIMISSILES,,,,Sebral@[ao_cs] jsi minirakety.,Du hast die Miniraketen genommen.,Πήρες τους μινι-πυράυλους.,Vi prenis la misiletojn.,Recogiste mini misiles.,,Poimit miniohjuksia.,Vous avez pris les mini-missiles.,Felvetted a minirakétákat.,Hai raccolto dei mini-missili.,ミニミサイル 入手。,미니 미사일 꾸러미를 획득했다.,Je hebt de mini-raketten opgehaald.,Podniosł@[irreg_3_pl] mini pociski.,Você pegou os mini-mísseis.,Apanhaste os mini-mísseis.,Ai ridicat mini proiectilele.,Получены мини-ракеты.,Покупио си мини ракете -You picked up the crate of missiles.,TXT_CRATEOFMISSILES,,,,Sebral@[ao_cs] jsi krabici miniraket.,Du hast die Miniraketenkiste genommen.,Πήρες το κιβώτιο με πυράυλους.,Vi prenis la misilarujon.,Recogiste una caja de misiles.,,Poimit ohjuslaatikon.,Vous avez pris la caisse de missiles.,Felvettél egy ládányi minirakétát.,Hai raccolto una cassa di missili.,ミサイルの箱 入手。,미니 미사일 박스를 획득했다.,Je hebt de kist met raketten opgehaald.,Podniosł@[irreg_3_pl] skrzynię z pociskami.,Você pegou a caixa de mísseis.,Apanhaste a caixa de mísseis.,Ai ridicat lada cu proiectile.,Получен ящик мини-ракет.,Покупио си кутију ракета -You picked up the energy pod.,TXT_ENERGYPOD,,,,Sebral@[ao_cs] jsi energetický kokón.,Du hast die Energiezelle genommen.,,Vi prenis la umon de energio.,Recogiste una vaina de energía.,,Poimit energia-akun.,Vous avez pris la cellule d'énergie.,Felvettél egy energiahüvelyt.,Hai raccolto un nucleo energetico.,エネルギーポット 入手。,에너지 포드를 획득했다.,Je hebt de energiecel opgehaald.,Podniosł@[irreg_3_pl] kapsułę energii.,Você pegou a célula de energia (pequeno).,Apanhaste a célula de energia (pequeno).,Ai ridicat capsula cu energie.,Получена энергоячейка.,Покупио си енергетско постоље. -You picked up the energy pack.,TXT_ENERGYPACK,,,,Sebral@[ao_cs] jsi energetický svazek.,Du hast das Energiepack genommen.,,Vi prenis la pako de energio.,Recogiste un pack de energía.,,Poimit energiapaketin.,Vous avez pris le pack energétique.,Felvetted az energiacsomagot.,Hai raccolto una carica energetica grande.,エネルギーパック 入手。,에너지 팩을 획득했다.,Je hebt de energiecapsule opgehaald.,Podniosł@[irreg_3_pl] zasobnik energii.,Você pegou a célula de energia (grande).,Apanhaste a célula de energia (grande).,Ai ridicat pachetul cu energie.,Получена энергобатарея.,Покупио си пакет енергије -You picked up the poison bolts.,TXT_POISONBOLTS,,,,Sebral@[ao_cs] jsi jedovaté šípy.,Du hase die Giftbolzen genommen.,,Vi prenis la venenajn sagetojn.,Recogiste las saetas venenosas.,,Poimit myrkkynuolia.,Vous avez pris les carreaux empoisonnés.,Felvetted a mérgezett nyilakat.,Hai raccolto dei dardi velenosi.,ポイズンボルト 入手。,맹독 볼트를 획득했다.,Je hebt de gifbouten opgehaald.,Podniosł@[irreg_3_pl] zatrute bełty.,Você pegou as setas envenenadas.,Apanhaste as setas envenedadas.,Ai ridicat bolțurile cu otravă.,Получены отравленные болты.,Покупио си отровне стреле -You picked up the electric bolts.,TXT_ELECTRICBOLTS,,,,Sebral@[ao_cs] jsi elektrické šípy.,Du hast die elektrischen Bolzen genommen.,,Vi prenis la elektrajn sagetojn.,Recogiste las saetas eléctricas.,,Poimit sähkönuolia.,Vous avez pris les carreaux électriques.,Felvetted az elektromos nyilakat.,Hai raccolto dei dardi elettrici.,エレクトリックボルト 入手。,전격 볼트를 획득했다.,Je hebt de elektrische bouten opgehaald.,Podniosł@[irreg_3_pl] elektryczne bełty.,Você pegou as setas eletricas.,Apanhaste as setas electricas.,Ai ridicat bolțurile cu electricitate.,Получены электрические болты.,Покупио си електричне стреле -You picked up the ammo satchel.,TXT_AMMOSATCHEL,,,,Sebral@[ao_cs] jsi brašnu na munici.,Du hast die Munitionstasche genommen.,,Vi prenis la municiingo.,Recogiste un estuche de munición.,,Poimit ammuslaukun.,Vous avez pris la sacoche de munitions,Felvetted a lőszeres táskát.,Hai raccolto una Borsa delle Munizioni.,弾薬鞄 入手。,탄약 배낭을 획득했다.,Je hebt de munitie tas opgepakt,Podniosł@[irreg_3_pl] torbę z amunicją.,Você pegou a mochila de munição.,Apanhaste a mochila de munição.,Ai ridicat sacoșa cu muniție.,Получен ранец для боеприпасов.,Покупио си торбицу муниције -You have a feeling that it wasn't to be touched...,MSG_TALISMANRED,,,,"Máš pocit, že jsi na to sahat neměl@[ao_cs]...","Du hast das Gefühl, dass man es nicht anfassen sollte...",,"Vi sentas, ke ĝi ne devas tuŝiĝi...",Tienes la sensación de que no debía ser tocado...,,"Sinusta tuntuu, ettei siihen olisi pitänyt koskea.",Vous avez un pressentiment qu'il ne fallait pas y toucher.....,Úgy érzed azt nem kéne megérinteni...,Hai la sensazione che non doveva essere toccato...,己の勘が 触れてはならない物だと訴えている...,"결코, 만지면 안 된다는 생각이 든다...",Je hebt het gevoel dat het niet aangeraakt moest worden....,"Czujesz, że trzeba było tego nie dotykać...",Você tem um pressentimento de que isso não devia ser tocado...,Tens um pressentimento que não devias ter mexido nisso.,Ai sentimentul că nu trebuia atinsă...,"Кажется, этой вещи ещё никто не касался...",Имаш осећај да није требало бити дирано... -"Whatever it is, it doesn't belong in this world...",MSG_TALISMANGREEN,,,,"Je jedno, co to je, do tohoto světa to nepatří...","Was auch immer es ist, es gehört nicht in diese Welt...","Οτιδήποτε είναι, δέν είναι απο αυτό τον κόσμο...","Kio ajn ĝi estas, ĝi ne apartenas al ĉi tiu mundo...","Sea lo que sea, no pertenece a este mundo...",,"Mikä ikinä se onkaan, se ei kuulu tähän maailmaan...","Quel que soit cette chose, elle ne devrait pas être ici...","Bármi legyen ez, nem ebben a világban van a helye...","Qualunque cosa sia, non appartiene a questo mondo...",何であろうと、この世には属さない物だ...,뭔지는 몰라도 이 세상에 속한 것이 아닌 것 같다...,"Wat het ook is, het hoort niet thuis in deze wereld....","Cokolwiek to jest, nie należy to do tego świata...","Seja o que for, isso não pertence a este mundo...","O que quer que isso seja, não pertence a este mundo...","Orice ar fi, nu are ce căuta în lumea asta...","Что бы это ни было, оно не из этого мира...","Шта год да је, не припада овом свету..." -It must do something...,MSG_TALISMANBLUE,,,,Něco to dělat musí...,Es muss etwas tun...,Πρέπει να κάνι κάτι...,Ĝi devas fari ion...,Debe hacer algo...,,Sen on pakko tehdä jotakin...,Ca doit servir a quelque chose...,,Deve fare qualcosa...,何かを成し遂げなければならない...,분명히 뭔가를 할 것이다...,Het moet iets doen....,To musi coś robić...,Deveria fazer alguma coisa...,Devia fazer alguma coisa.,Trebuie să facă ceva...,Оно ведь зачем-то нужно?..,Мора урадити нешто... -You have super strength!,MSG_TALISMANPOWER,,,,Dostal@[ao_cs] jsi super sílu!,Du hast Superkräfte,,Vi havas superan forton!,¡Tienes súper fuerza!,,Sinulla on supervoimat!,Vous avez une puissance inégalée!,,Hai la super forza!,豪剛なる力を得た!,엄청난 힘이 솟는다!,Je hebt superkracht!,Masz super siłę!,Você tem a super força!,Tu tens super força!,Ai super forță!,Вы получили сверхсилу!,Имаш супер снагу! -,,Locks,,,,,,,,,,,,,,,,,,,,, -You don't have the key,TXT_NEEDKEY,,,,Nemáš klíč.,Du hast den Schlüssel nicht,Δέν έχεις το κλειδί,Vi ne havas la ŝlosilon.,No tienes la llave,,Sinulla ei ole avainta,Vous n'avez pas la clé.,Ehhez nincs kulcsod.,Non hai la chiave necessaria,キーを持っていない,필요한 열쇠가 없다,Je hebt de sleutel niet.,Nie masz klucza,Você não possui a chave,Tu não tens a chave,Nu ai cheia,Нужен ключ,Немаш кључ -You need a passcard,TXT_NEED_PASSCARD,,,,Potřebuješ průkaz.,Du brauchst eine Zugangskarte.,,Vi bezonas paskarton.,Necesitas el pase de acceso,,Tarvitset avainkortin,Vous avez besoin du passe.,Belépőkártyára lesz szükséged.,Ti serve un lasciapassare,パスカード が必要だ,통행 카드가 필요하다,Je hebt een paspoortkaart nodig.,Potrzebujesz karty dostępu,Você precisa de um cartão de acesso,Precisas de um cartão de acesso,Ai nevoie de un card de acces,Нужен пропуск,Треба ти пропусница -You need a pass card key to open this door,TXT_NEED_PASSCARD_DOOR,,,,Pro otevření dveří potřebuješ průkaz.,"Du brauchst eine Zugangskarte, um diese Tür zu öffnen.",,Vi bezonas paskarton por malfermi tiun pordon.,Necesitas un pase de acceso para abrir esta puerta,,Tarvitset avainkortin tämän oven avaamiseksi,Vous avez besoin du passe ouvrir cette porte.,Belépőkártya nélkül nem nyílik ez az ajtó.,Ti serve una tessera lasciapassare per aprire questa porta.,このドアには パスカード が必要だ,이 문을 열기 위해서는 통행 카드가 필요하다,Je hebt een sleutel nodig om deze deur te openen....,Potrzebujesz karty dostępu aby otworzyć te drzwi,Você precisa de um cartão de acesso para abrir essa porta,Precisas de um cartão de acesso para abrir esta porta,"Ai nevoie de un card de acces ca să deschizi ușa -asta",Для открытия нужен пропуск,Треба ти пасош да отвориш ова врата -You need an ID card,TXT_NEED_IDCARD,,,,Potřebuješ identifikační kartu.,Du brauchst einen Ausweis.,,Vi ne bezonas identigo-karton.,Necesitas una tarjeta de Identificación,,Tarvitset henkilökortin,Vous avez besoin d'une carte d'identité.,Igazolvány szükséges,Ti serve una tessera identificativa.,IDカード が必要だ,신분증이 필요하다,Je hebt een ID-kaart nodig,Potrzebujesz karty identyfikacyjną,Você precisa do cartão de identificação,Precisas do cartão de identificação,Ai nevoie de un card de identitate,Нужна личная карта,Треба ти идентификациона картица -You don't have the key to the prison,TXT_NEED_PRISONKEY,,,,Nemáš klíč do vězení.,Du brauchst den Schlüssel zum Gefängnis,,Vi ne havas la ŝlosilon de la malliberejo.,No tienes la llave a la prisión,,Sinulla ei ole vankilan avainta,Vous n'avez pas la clé de la prison.,Nincs kulcsod a börtönhöz.,Ti manca la chiave per la prigione,刑務所のキーを持っていない,감옥에 입장하기 위한 열쇠가 없다,Je hebt de sleutel van de gevangenis niet in handen.,Nie masz klucza do więzienia,Você não tem a chave da prisão,Não tens a chave da prisão,Nu ai cheia închisorii,Нужен ключ от тюрьмы,Треба ти кључ затвора -Hand print not on file,TXT_NEED_HANDPRINT,,,,Otisk ruky není v databázi.,Handabdruck nicht gespeichert!,,Manspuro ne sur dosiero,La huella digital no esta en el archivo,,Kädenjälki puuttuu tiedostosta,Votre main n'est pas reconnue par le scanner.,Azonosítatlan kézlenyomat.,Impronta digitale non in archivio,手形認証が一致しません,알 수 없는 지문입니다,Handafdruk niet op bestand,Brak odcisku dłoni w bazie danych,Biometria não autorizada,Impressão digital não autorizada,Amprenta mâinii nerecunoscută,Отпечаток руки не распознан,Отисак длана није у записнику -You need the Gold Key,TXT_NEED_GOLDKEY,,,,Potřebuješ zlatý klíč.,Du brauchst den goldenen Schlüssel,,Vi bezonas la Ora Ŝlosilon.,Necesitas la Llave Dorada,,Tarvitset kulta-avaimen,Vous avez besoin d'une clé d'or.,Aranykulcs szükséges.,Ti serve la chiave dorata,ゴールドキーが必要だ,황금 키가 필요하다,Je hebt de gouden sleutel nodig,Potrzebujesz Złotego Klucza,Você precisa da Chave de Ouro,Precisas da Chave de Ouro,Ai nevoie de cheia din Aur,Нужен золотой ключ,Треба ти златни кључ -You need an ID Badge,TXT_NEED_IDBADGE,,,,Potřebuješ identifikační odznak.,Du brauchst eine Identitätskarte.,,Vi bezonas identig-insignon.,Necesitas una Insignia de Identificación,,Tarvitset henkilötunnisteen,Vous avez besoin d'un badge d'identification.,Azonosító jelvény szükséges.,Ti serve un distintivo di identificazione,IDバッジが必要だ,신분 휘장이 필요하다,Je hebt een ID badge nodig.,Potrzebujesz Odznaki Identyfikacyjnej,Você precisa do Crachá de Identificação,Precisas do Crachá de Identificação,Ai nevoie de un ecuson de identificare,Нужна личная карта,Треба ти лична карта -You need an ID Badge to open this door,TXT_NEED_IDBADGE_DOOR,,,,Potřebuješ identifikační odznak pro otevření dveří.,"Du brauchst eine Identitätskarte, um diese Tür zu öffnen.",,Vi bezonas identig-insignon por malfermi tion pordon.,Necesitas una Insignia de Identificación para abrir esta puerta,,Tarvitset henkilötunnisteen tämän oven avaamiseksi,Vous avez besoin d'un badge d'identification pour ouvrir cette porte.,Azonosító jelvény szükséges az ajtó kinyitásához.,Ti serve un distintivo di identificazione per superare questa porta,このドアには IDバッジ が必要だ,이 문을 열기 위해서는 신분 휘장이 필요하다,Je hebt een ID badge nodig om deze deur te openen.,Potrzebujesz Odznaki Identyfikacyjnej aby otworzyć te drzwi,Você precisa do Crachá de Identificação para abrir a porta,Precisas do Crachá de Identificação para abrir a porta,"Ai nevoie de un ecuson de identificare ca să -deschizi ușa",Для открытия нужна личная карта,Треба ти лична карта да отвориш ова врата -You need the Silver Key,TXT_NEED_SILVERKEY,,,,Potřebuješ stříbrný klíč.,Du brauchst den Silberschlüssel,,Vi bezonas la Arĝentan Ŝlosilon. ,Necesitas la Llave Plateada,,Tarvitset hopea-avaimen,Vous avez besoin de la clé en argent.,Az ezüskulccsal szükséges.,Ti serve la chiave argentata,シルバーキーが必要だ,은 키가 필요하다,Je hebt de Zilveren Sleutel nodig.,Potrzebujesz Srebrnego Klucza,Você precisa da Chave de Prata,Precisas da Chavede Prata,Ai nevoie de cheia din Argint,Нужен серебряный ключ,Треба ти сребрни кључ -You need the Brass Key,TXT_NEED_BRASSKEY,,,,Potřebuješ mosazný klíč.,Du brauchst den Messingschlüssel,,Vi bezonas la Latunan Ŝlosilon.,Necesitas la Llave de Bronce,,Tarvitset messinkiavaimen,Vous avez besoin de la clé en bronze.,A rézkulcs szükséges.,Ti serve la chiave d'ottone,ブラスキーが必要だ,황동 키가 필요하다,Je hebt de messing sleutel nodig.,Potrzebujesz Mosiężnego Klucza,Você precisa da Chave de Latão,Precisas da Chave de Latão,Ai nevoie de cheia din Alamă,Нужен латунный ключ,Треба ти кључ од месинга -You need the Red Crystal,TXT_NEED_REDCRYSTAL,,,,Potřebuješ červený krystal.,Du brauchst den roten Kristall,,Vi bezonas la Ruĝan Kristalon.,Necesitas el Cristal Rojo,,Tarvitset punaisen kristallin,Vous avez besoin du cristal rouge.,A vörös kristályra lesz szükség itt.,Ti serve il Cristallo Rosso,赤水晶のキーが必要だ,적색 크리스탈이 필요하다,Je hebt de rode kristallen sleutel nodig.,Potrzebujesz Czerwonego Kryształu,Você precisa do Cristal Vermelho,Precisas do Cristal Vermelho,Ai nevoie de Cristalul Roșu,Нужен красный кристалл,Треба ти црвени кристал -You need the Blue Crystal,TXT_NEED_BLUECRYSTAL,,,,Potřebuješ modrý krystal.,Du brauchst den blauen Kristall,,Vi bezonas la Bluan Kristalon.,Necesitas el Cristal Azul,,Tarvitset sinisen kristallin,Vous avez besoin du cristal bleu.,A kék kristályra lesz szükség itt.,Ti serve il Cristallo Blu,青水晶のキーが必要だ,청색 크리스탈이 필요하다,Je hebt de blauwe kristallen sleutel nodig.,Potrzebujesz Niebieskiego Kryształu,Você precisa do Cristal Azul,Precisas do Cristal Azul,Ai nevoie de Cristalul Albastru,Нужен синий кристалл,Треба ти плави кристал -This area is only available in the retail version of Strife,TXT_RETAIL_ONLY,,,,Tato oblast je dostupná pouze v registrované verzi.,Dieser Bereich ist nur in der kompletten Version von Strife erreichbar.,Αυτή η περιοχή είναι μονο διαθέσημη στήν εγραμμένη έκδοση του Strife,Tio regiono estas enirebla en nur la vendata versio de Strife.,Esta área solo está disponible en la versión retail de Strife.,,Tämä alue on saatavilla ainoastaan Strifen kokoversiossa,Cette zone n'est accessible que dans la version complète de Strife.,Ez a terület kizárólag a Strife teljes verziójában érhető el,Quest'area è disponibile solo nella versione completa di Strife.,このエリアは Strifeの製品版でのみ利用可能です,이 구역은 정품 버전에서만 입장이 가능합니다,Deze ruimte is alleen beschikbaar in de verkoopversie van Strife.,Ten obszar jest dostępny tylko w pełnej wersji Strife,Essa área está disponível apenas na versão registrada de Strife,,"Această zonă e disponibilă doar în versiunea -cumpărată a jocului Strife",Эта локация доступна только в полной версии Strife,Ова област је само доступна у пуној верзији Strife-а -That doesn't seem to work,TXT_DOES_NOT_WORK,,,,Takhle to nepůjde.,Das scheint nicht zu funktionieren,,Tio ŝajne ne funkcias.,Parece que eso no funciona,,Se ei näytä toimivan,Cela ne semble pas fonctionner.,Ez így nem megy.,Non sembra funzionare,それは作動していない,작동이 안 되는 것 같다,Dat lijkt niet te werken.,To zdaje się nie działać,Parece que isso não funciona,,Nu pare să funcționeze,"Похоже, это не работает",То изгледа да не ради -You need the chalice!,TXT_NEED_CHALICE,,,,Potřebuješ kalich!,Du brauchst den Kelch!,,Vi bezonas la kalikon!,¡Necesitas el Cáliz!,,Tarvitset maljan!,Vous avez besoin du calice!,,Hai bisogno del calice.,聖杯が必要だ!,성배가 필요하다!,Je hebt de beker nodig!,Potrzebujesz kielicha!,Você precisa do cálice!,Precisas do cálice!,Ai nevoie de potir!,Нужна чаша!,Треба ти пехар! -You need the Oracle Pass!,TXT_NEED_OPASS,,,,Potřebuješ propustku od věštce!,Du brauchst den Orakelpass!,,Vi bezonas la Pason de Oraklo!,¡Necesitas el Pase del Oráculo!,,Tarvitset Oraakkelin passin,Vous avez besoin du passe Oracle!,,Hai bisogno del pass dell'Oracolo.,オラクルパスが必要だ!,오라클 통행증이 필요하다!,Je hebt de Orakelkaart nodig!,Potrzebujesz Przepustki Wyroczni!,Você precisa do Passe do Oráculo!,Precisas do Passe do Oráculo!,Ai nevoie de legitimația Oracol!,Нужен пропуск Оракула!,Треба ти Пророкова пропусница! -,,Actor tags,,,,,,,,,,,,,,,,,,,,, -Dagger,TAG_PUNCHDAGGER,,,,Dýka,Dolch,Μαχάιρι,Ponardo,Daga,,Tikari,Dague de Poing,Tör,Pugnale,ダガー,단검,Dolk,Sztylet,Punhal,,Pumnal,Кинжал,Бодеж -Crossbow,TAG_STRIFECROSSBOW1,Crossbow with electric bolts,,,Kuše,Armbrust,Τόξο (Δηλητήριο),Arbalesto (Elektraj segetoj),Ballesta,,Jousipyssy,Arbalète Electrique,Nyílpuska,Balestra ,クロスボウ,석궁 (전격),Kruisboog,Kusza,Besta,,Arbaletă,Арбалет,Самострел -Crossbow,TAG_STRIFECROSSBOW2,Crossbow with poison bolts,,,Kuše,Armbrust,Τόξο (Ηλεκτρικό),Arbalesto (Venemaj segetoj),Ballesta,,Jousipyssy,Arbalète Empoisonée,Nyílpuska,Balestra ,クロスボウ,석궁 (맹독),Kruisboog,Kusza,Besta,,Arbaletă,Арбалет,Самострел -Assault Gun,TAG_ASSAULTGUN,,,,Útočná puška,Sturmgewehr,,Ataka Pafilo,Fusil de Asalto,,Rynnäkkökivääri,Fusil d'Assaut,Gépfegyver,Fucile d'Assalto ,アサルトガン,돌격소총,Aanvalswapen,Karabin Szturmowy,Fuzil de Assalto,Arma de Assalto,Pușcă de Asalt,Винтовка,Аутоматска пушка -Mini Missile Launcher,TAG_MMLAUNCHER,,,,Miniraketomet,Miniraketenwerfer,Μίνι-Πυραυλοβόλο,Misiletĵteilo,Mini Lanzamisiles,,Miniohjuslaukaisin,Lanceur de Mini-Missiles,Mini Rakétavető,Mini-Lanciamissili,ミニミサイルランチャー,미니 미사일 런쳐,Mini Raketwerper,Wyrzutnia Minipocisków,Mini Lança-mísseis,,Mini Lansator de Proiectile,Мини-ракетница,Мини ракетни бацач -Flame Thrower,TAG_FLAMER,,,,Plamenomet,Flammenwerfer,,Flamĵetilo,Lanzallamas,,Liekinheitin,Lance-Flammes,Lángszóró,Lanciafiamme ,火炎放射器,화염방사기,Vlammenwerper,Miotacz Ognia,Lança-chamas,,Aruncător de Flăcări,Огнемёт,Бацеч пламена -Mauler,TAG_MAULER1,,,,Trhač,Vernichter,,Vundegilo,Triturador,,Moukari,Broyeur,Szétbomló,Pestatore ,マウラー,마울러 (저출력),Mauler,Miażdżyciel,Desintegrador,,Sfâșietor,Истязатель,Маулер -Mauler,TAG_MAULER2,,,,Trhač,Vernichter,,Vundegilo,Triturador,,Moukari,Broyeur,Szétbomló,Pestatore,マウラー,마울러 (고출력),Mauler,Miażdżyciel,Desintegrador,,Sfâșietor,Мучитель,Маулер -Grenade Launcher,TAG_GLAUNCHER1,High-explosive grenade launcher,,,Granátomet,Granatwerfer,,Granadĵetilo (PE),Lanzagranadas,,Kranaatinheitin,Lance-Grenades Explosif,Gránátvető,Lanciagranate,グレネードランチャー,유탄발사기 (고폭탄),Granaatwerper,Wyrzutnia Granatów,Lança-granadas,,Lansator de Grenade,Гранатомёт,Бацач граната -Grenade Launcher,TAG_GLAUNCHER2,White phosphorous grenade launcher ,,,Granátomet,Granatwerfer,,Granadĵetilo (Fosfora),Lanzagranadas,,Kranaatinheitin,Lance-Grenades Incendiaire,Gránátvető,Lanciagranate,グレネードランチャー,유탄발사기 (소이탄),Granaatwerper,Wyrzutnia Granatów,Lança-granadas,,Lansator de Grenade,Гранатомёт,Бацач граната -Sigil,TAG_SIGIL,,,,Pečeť,,,Sigelo,Emblema,,Sinetti,,Pecsét,Sigillo,シジル,시질,Sigil,Symbol,Sigilo,,Sigiliu,Сигил,Сигил -Coin,TAG_COIN,,,,Mince,Münze,,Monero,Moneda,,Kolikko,Pièce,Érme,Moneta,コイン,동전,Munt,Moneta,Moeda(s),,Monedă,Монета,Новчић -Med patch,TAG_MEDPATCH,,,,Obvaz,Medizinische Bandage,,Medicina Flikaĵo,Parche Médico,,Sidekääre,Pansement,Ragtapasz,Bende,医薬パッチ,의료 붕대,Med-patch,Bandaż,Compressa médica,,Trusă de Prim-Ajutor,Бинт,Прва помоћ -Medical kit,TAG_MEDICALKIT,,,,Lékárnička,Verbandskasten,,Medicinilaro,Kit Médico,,Lääkintälaukku,Kit Médical,Orvosi Készlet,Kit di Pronto Soccorso ,医療キット,구급 키트,Medische kit,Apteczka,Kit médico,,Kit de Prim-Ajutor,Аптечка,Медицински прибор -Surgery Kit,TAG_SURGERYKIT,,,,Chirurgická souprava,Erste-Hilfe-Kasten,,Kirurgirilaro,Kit Quirúrgico,,Kirurgilaukku,Kit de Chirurgie,Sebészeti Készlet,Kit Chirurgico ,手術キット,수술 키트,Chirurgiekit,Zestaw Chirurga,Kit de Cirurgia,,Kit pentru Operații,Медкомплект,Хируршки прибор -Ring,TAG_BELDINSRING,,,,Prsten,,,Ringo,Anillo,,Sormus,Anneau,Gyűrű,Anello ,指輪,반지,Ring,Pierścień,Anel,,Inel,Кольцо,Прстен -Offering Chalice,TAG_OFFERINGCHALICE,,,,Obětní kalich,Opferkelch,,Ofertkilko,Cáliz de Ofrenda,,Uhrimalja,Calice d'Obole,Áldozati kehely,Calice delle Offerte,寄贈された聖杯,번제 성배,Offerbeker,Kielich Ofiarny,Calice de Oferenda,,Potir pentru Ofrande,Чаша для подношений,Жртвени пехар -Ear,TAG_EAR,,,,Ucho,Ohr,,Orelo,Oreja,,Korva,Oreille,Fül,Orecchio,耳,귀,Oor,Ucho,Orelha,,Ureche,Ухо,Уво -Broken Power Coupling,TAG_BROKENCOUPLING,,,,Rozbitá spojka,Defekter Stromabnehmer,,Rompa Povkuplilo,Acoplador de Energía Roto,,Rikkinäinen virtaliitin,Coupleur Energétique cassé,Elromlott Tápcsatlakozó,Coppia Energetica Rotta ,壊れたパワーカップリング,망가진 동력선,Gebroken stroomkoppeling,Zepsute Obwody Zasilające,Acoplador de Energia Quebrado,Acoplador de Energia Partido,Cuplaj de Putere Defect,Повреждённая муфта,Неисправна спојница напајања -Shadow Armor,TAG_SHADOWARMOR,,,Shadow Armour,Krycí brnění,Schattenrüstung,,Ombrokiraso,Armadura de Sombra,,Varjopanssari,Armure de l'Ombre,Sötét Páncél,Armatura Ombra ,シャドウアーマー,그림자 갑옷,Schaduw harnas,Cienisty Pancerz,Armadura das Sombras,,Armura Umbrei,Теневая броня,Оклоп сенки -Environmental Suit,TAG_ENVSUIT,,,,Ochranný oblek,Schutzanzug,,Medivesto,Traje Ambiental,,Ympäristösuojapuku,Combinaison Hazmat,Védőöltözet,Tuta Ambientale ,耐環境スーツ,환경 방호복,Beschermend pak,Skafander Ochronny,Traje de Proteção,Fato Protetor,Costum de Protecție,Защитный костюм,Заштитно одело -Guard Uniform,TAG_GUARDUNIFORM,,,,Hlídačova uniforma,Wächteruniform,,Gardista Uniformo,Uniforme de Guardia,,Vartijan univormu,Uniforme de Garde,Őr Egyenruha,Uniforme da Guardia,ガードの制服,경비 전투복,Wachtuniform,Mundur Strażnika,Uniforme de Guarda,,Uniformă de Paznic,Униформа стражника,Стражарска униформа -Officer's Uniform,TAG_OFFICERSUNIFORM,,,,Důstojníkova uniforma,Offiziersuniform,,Oficira Uniformo,Uniforme de Oficial,,Upseerin univormu,Uniforme d'Officier,Tiszti Egyenruha,Uniforme da Ufficiale ,士官の制服,장교 전투복,Uniform van de officier,Mundur Oficera,Uniforme de Oficial,,Uniformă de Ofițer,Офицерская униформа,Официрска униформа -Flame Thrower Parts,TAG_FTHROWERPARTS,,,,Součásti plamenometu,Flammenwerferteile,,Partoj de Flamjetilo,Partes de Lanzallamas,,Liekinheittimen osat,Pièces de Lance-Flamme,Lángszóró Alkatrészek,Parti di Lanciafiamme ,火炎放射器の部品,화염방사기 부품,Vlammenwerper onderdelen,Części Miotacza Ognia,Partes do lança-chamas,,Bucăți de Aruncător de Flăcări,Детали огнемёта,Делови бацача пламена -Report,TAG_REPORT,,,,Hlášení,,,Raporto,Reporte,,Raportti,Compte-rendu,Jelentés,Rapporto ,報告書,보고서,Verslag,Raport,Relatório,,Raport,Отчёт,Извештај -Info,TAG_INFO,,,,Informace,,,Informo,Información,,Tiedot,,Információ,Informazioni ,情報,정보,Info,Informacje,Informação,,Informație,Сводка,Инфо -Targeter,TAG_TARGETER,,,,Zaměřovač,Zielhilfe,,Celilo,Apuntador,,Tähtäinlaite,Cibleur,Célzó eszköz,Puntatore,照準器,조준기,Doelwit,Namierzacz,Mira,,Țintitor,Целеуказатель,Нишанџија -Communicator,TAG_COMMUNICATOR,,,,Komunikátor,Kommunikator,,Komunikilo,Comunicador,,Viestintälaite,Communicateur,Kommunikátor,Comunicatore ,コミュニケーター,연락장치,Communicator,Komunikator,Comunicador,,Comunicator,Передатчик,Комуникатор -Degnin Ore,TAG_DEGNINORE,,,,Degninská ruda,Degnin-Erz,,Degnina Erco,Mineral Degnin,,Degnin-malmi,Minerai de Degnin,Degnin Érc,Minerale Degnin,デグニン鉱石,데그닌 광석,Degnin Erts,Ruda Degninu,Minério Degnin,,Minereu de Degnir,Денгинская руда,Дегнинска руда -Accuracy,TAG_GUNTRAINING,,,,Přesnost,Präzision,,Akurateco,Precisión,,Tarkkuus,Précision,Pontosság,Precisione,精度,정확도,Nauwkeurigheid,Precyzja,Precisão,,Acuratețe,Меткость,Прецизност -Toughness,TAG_HEALTHTRAINING,,,,Tvrdost,Ausdauer,,Forteco,Dureza,,Sitkeys,Endurance,Kitartás,Robustezza ,タフネス,힘,Hardheid,Wytrzymałość,Força,,Rezistență,Живучесть,Издржљивост -Scanner,TAG_SCANNER,,,,Skener,,,Saknilo,Escáner,,Skanneri,Analyseur,Szkenner,Scanner,スキャナー,탐지기,Scanner,Skaner,Scanner,,Scanner,Сканер,Скенер -Prison Pass,TAG_PRISONPASS,,,,Propustka do vězení,Gefängnispass,,Mallibereja pasilo,Pase de Prisión,,Vankilan pääsylupa,Passe de la Prison,Börtön Engedély,Lasciapassare Prigione ,刑務所の許可証,감옥 통행증,Gevangenispas,Przepustka do Więzienia,Passe da Prisão,,Legitimația pentru Închisoare,Пропуск в тюрьму,Затворска пропусница -Alarm,TAG_ALARM,,,,,,,Alarmilo,Alarma,,Hälytys,Alarme,Riasztó,Allarme ,警報,알람,Alarm,Alarm,Alarme,,Alarmă,Тревога,Аларм -Ammo,TAG_AMMOFILLUP,,,,Munice,Munition,,Municio,Munición,,Ammukset,Munitions,Lőszer,Munizioni ,弾薬,탄약,Munitie,Amunicja,Munição,,Muniție,Боеприпасы,Муниција -Health,TAG_HEALTHFILLUP,,,,Zdraví,Gesundheit,,Sano,Salud,,Terveys,Santé,Életerő,Salute ,体力,체력,Gezondheid,Zdrowie,Saúde,,Sănătate,Здоровье,Живот -Teleporter Beacon,TAG_TELEPORTERBEACON,,,,Teleportační maják,Teleportersignal,,Formovila Signalilo,Faro de Teletransportación,,Kaukosiirrinmajakka,Balise de téléportation,Teleport Sugárzó,Radiofaro per Teletrasporto ,テレポータービーコン,텔레포터 비콘,Teleporter Baken,Nadajnik Teleportera,Sinalizador para Teletransporte,,Lumină pentru Teleportor,Телепортационный маяк,Одашиљач за телепортовање -Metal Armor,TAG_METALARMOR,,,Metal Armour,Kovové brnění,Metallrüstung,,Metala Kiraso,Armadura de Metal,,Metallipanssari,Armure en Métal,Fém Páncél,Armatura di Metallo ,メタルアーマー,강철 갑옷,Metalen pantser,Metalowy Pancerz,Armadura de Metal,,Armură din Metal,Металлическая броня,Метални оклоп -Leather Armor,TAG_LEATHER,,,Leather Armour,Kožené brnění,Lederrüstung,,Leda Kiraso,Armadura de Cuero,,Nahka-asu,Armure en Cuir,Bőr Páncél,Armatura di Cuoio,レザーアーマー,가죽 갑옷,Leren pantser,Skórzany Pancerz,Armadura de Couro,,Armură din Piele,Кожаная броня,Кожни оклоп -HE-Grenade Rounds,TAG_HEGRENADES,,,,Výbušné granáty,HE-Granaten,,PV-Gernadmunicioj,Granadas HE,,Räjähdekranaatit,Grenades Explosives,Gránát Lőszer,Granata HE,HEグレネード弾,고폭 유탄,HE-granaten,Wiązka Granatów,Munição - Granadas Explosivas,,Grenade Explozive,Осколочные гранаты,Хе-Граната чауре -Phosphorus-Grenade Rounds,TAG_PHGRENADES,,,,Fosforečné granáty,Phosphorgranaten,,Fosforaj Gernadmunicioj,Granadas de Fósforo,,Fosforikranaatit,Grenades Incendiaires,Foszfor-Gránát Lőszer,Granata al Fosforo ,白リングレネード弾,소이 유탄,Fosforgranaten,Wiązka Fosforowych Granatów,Municão - Granadas de Fósforo,,Grenade cu Fosfor,Фосфорные гранаты,Фосфорне гранате -Clip of Bullets,TAG_CLIPOFBULLETS,,,,Zásobník,Gewehrmunition,,Kuglujo,Cargador de Balas,,Luotilipas,Chargeur d'Assaut,Golyó töltények,Caricatore di Proiettili ,弾丸のクリップ,소총 탄창,Clip van kogels,Magazynek,Carregador de Balas,,Cartuș cu Gloanțe,Обойма,Клип метака -Ammo,TAG_BOXOFBULLETS,,,,Bedna munice,Munitionskiste,,Municio,Caja de Municiones,,Luotilaatikko,Bôite de Munitions,Lőszer,Munizioni ,弾薬箱,탄약,Munitie,Amunicja,Caixa de Balas,,Muniție,Боеприпасы,Муниција -Mini Missiles,TAG_MINIMISSILES,,,,Minirakety,Miniraketen,,Misileto,Mini Misiles,,Miniohjukset,Mini-Missiles,Mini Rakéták,Mini-Missili,ミニミサイル,미니 미사일,Mini-raketten,Mini Pociski,Mísseis,,Mini Proiectile,Мини-ракеты,Мини Ракете -Crate of Missiles,TAG_CRATEOFMISSILES,,,,Bedna raket,Raketenkiste,,Misilarujo,Caja de Cohetes,,Ohjuslaatikko,Caisse de Mini-Missiles,Ládányi Rakéta,Cassa di Missili,ミサイルの箱,미사일 박스,Krat van raketten,Skrzynia z Pociskami,Caixa de Mísseis,,Ladă cu Proiectile,Коробка ракет,Кутија ракета -Energy Pod,TAG_ENERGYPOD,,,,Energetický kokón,Energiezelle,,Umon de Energio,Vaina de Energía,,Energia-akku,Cellule Energétique,Energia Lőszer,Nucleo Enegetico ,エネルギーポット,에너지 포드,Energiecel,Kapsuła Energii,Energia (pequeno),,Capsulă cu Energie,Энергоячейка,Енергетска шипка -Energy Pack,TAG_ENERGYPACK,,,,Energetický svazek,Energiekiste,,Pako de Energio,Pack de Energía,,Energiapaketti,Pack Energétique,Energia Csomag,Carica Energetica ,エネルギーパック,에너지 팩,Energiecapsule,Zasobnik Energii,Energia (grande),,Pachet cu Energie,Энергобатарея,Паковање енергије -Poison Bolts,TAG_POISONBOLTS,,,,Otrávené šípy,Giftbolzen,,Venenaj Sagetoj,Saetas Venenosas,,Myrkkynuolet,Carreaux Empoisonnés,Mérgező Nyílak,Dardi Velenosi ,ポイズンボルト,맹독 볼트,Giftige bouten,Zatrute Bełty,Setas Envenenadas,,Bolțuri cu Otravă,Отравленные болты,Отровне стреле -Electric Bolts,TAG_ELECTRICBOLTS,,,,Elektrické šípy,Elektrische Bolzen,,Elektraj Sagetoj,Saetas Eléctricas,,Sähkönuolet,Carreaux Electriques,Elektromos Nyílak,Dardi Elettrici ,エレクトリックボルト,전격 볼트,Elektrische bouten,Elektryczne Bełty,Setas Elétricas,,Bolțuri cu Electricitate,Электрические болты,Електричне стреле -Ammo Satchel,TAG_AMMOSATCHEL,,,,Brašna na munici,Munitionstasche,,Municiingo,Bolsa de Municiones,,Ammuslaukku,Sacoche à munitions,Lőszeres táska,Borsa di Munizioni ,弾薬鞄,탄약 배낭,Munitie Tassen,Torba z Amunicją,Bolsa de Munição,,Sacoșă cu Muniție,Ранец для боеприпасов,Торбица муниције -Base Key,TAG_BASEKEY,,,,Klíč od základny,Basisschlüssel,,Bazŝlosilo,Llave de la Base,,Tukikohdan avain,Clé de la base,Bázis Kulcs,Chiave della Base,,기지 키,Basissleutel,Klucz do Bazy,Chave da Base,,Cheia Bazei,Ключ от базы,Кључ базе -Govs Key,TAG_GOVSKEY,,,,Klíč ke guvernérovi,Gouverneursschlüssel,,Ŝlosilo de Reganto,Llave del Gobernador,,Kuvernöörin avain,Clé du Gouverneur,Kormányzó Kulcs,Chiave del Governatore ,,총독의 키,Gouverneursleutel,Klucz Gubernatora,Chave do Governador,,Cheia Guvernatorului,Ключ губернатора,Гувернеров кључ -Passcard,TAG_PASSCARD,,,,Vstupní karta,Zugangskarte,,Paskarto,Pase de Acceso,,Avainkortti,Passe,Belépőkártya,Tessera Lasciapassare ,,통행 카드,Paspoortkaart,Karta Dostępu,Cartão de Acesso,,Legitimație,Пропуск,Пропусница -ID Badge,TAG_IDBADGE,,,,Identifikační odznak,Identitätskarte,,Identigo-insigno,Insignia de identificación,,Henkilötunniste,Badge d'Identification,Azonosító Jelvény,Distintivo ,,신분 휘장,ID-badge,Odznaka Identyfikacyjna,Crachá de Identificação,,Ecuson de Identificare,Личная карта,Идентификациона значка -Prison Key,TAG_PRISONKEY,,,,Klíč od věznice,Gefängnisschlüssel,,Malliberejo-ŝlosilo,Llave de Prisión,,Vankilan avain,Clé de la Prison,Börtön Kulcs,Chiave della Prigione ,,감옥 키,Gevangenissleutel,Klucz do Więzienia,Chave da Prisão,,Cheia Închisorii,Ключ от тюрьмы,Кључ од 3атвора -Severed Hand,TAG_SEVEREDHAND,,,,Useknutá ruka,Abgetrennte Hand,,Disiga Mano,Mano Cercenada,,Katkennut käsi,Main coupée,Levágott Kéz,Mano Mozzata,,잘린 손목,Gescheurde hand,Odcięta Ręka,Mão Decepada,Mão Desmenbrada,Mână Retezată,Отрезанная рука,Одвојена шака -Power1 Key,TAG_POWER1KEY,,,,Klíč od elektrárny 1,Kraftwerksschlüssel 1,,Povo 1 Klavo,Llave de Poder 1,,Power1-avain,Clé Power1,Áram1 Kulcs,Chiave della Centrale 1,,발전소 1호 키,Centrale Sleutel 1,Klucz do Elektrowni 1,Chave da Usina 1,Chave Energética 1,Cheia Putere1,Ключ ЭС 1,Кључ од ел. 1 -Power2 Key,TAG_POWER2KEY,,,,Klíč od elektrárny 2,Kraftwerksschlüssel 2,,Povo 2 Klavo,Llave de Poder 2,,Power2-avain,Clé Power2,Áram2 Kulcs,Chiave della Centrale 2,,발전소 2호 키,Centrale Sleutel 2,Klucz do Elektrowni 2,Chave da Usina 2,Chave Energética 2,Cheia Putere2,Ключ ЭС 2,Кључ од ел. 2 -Power3 Key,TAG_POWER3KEY,,,,Klíč od elektrárny 3,Kraftwerksschlüssel 3,,Povo 3 Klavo,Llave de Poder 3,,Power3-avain,Clé Power3,Áram3 Kulcs,Chiave della Centrale 3,,발전소 3호 키,Centrale Sleutel 3,Klucz do Elektrowni 3,Chave da Usina 3,Chave Energética 3,Cheia Putere3,Ключ ЭС 3,Кључ од ел. 3 -Gold Key,TAG_GOLDKEY,,,,Zlatý klíč,Goldschlüssel,,Ora Klavo,Llave Dorada,,Kulta-avain,Clé en Or,Aranykulcs,Chiave Dorata,,황금 키,Gouden sleutel,Złoty Klucz,Chave de Ouro,,Cheia din Aur,Золотой ключ,Златни кључ -ID Card,TAG_IDCARD,,,,Identifikační karta,Ausweis,,Identigo-karto,Tarjeta de Identificación,,Henkilökortti,Carte d'Identité,Azonosító Kártya,Tessera Identificativa,,신분증,ID-kaart,Karta Identyfikacyjna,Cartão de Identificação,,Card de Identitate,Удостоверение,Лична карта -Silver Key,TAG_SILVERKEY,,,,Stříbrný klíč,Silberschlüssel,,Arĝenta Ŝlosilo,Llave Plateada,,Hopea-avain,Clé en Argent,Ezüst Kulcs,Chiave Argentata,,은 키,Zilveren sleutel,Srebrny Klucz,Chave de Prata,,Cheia din Argint,Серебряный ключ,Сребрни кључ -Oracle Key,TAG_ORACLEKEY,,,,Věštcův klíč,Orakelschlüssel,,Orakolo-ŝlosilo,Llave del Oráculo,,Oraakkelin avain,Clé de l'Oracle,Orákulum kulcs,Chiave dell'Oracolo ,,오라클 키,Orakelsleutel,Klucz do Wyroczni,Chave do Oráculo,,Cheia Oracol,Ключ Оракула,Пророков кључ -Military ID,TAG_MILITARYID,,,,Vojenské ID,Militärausweis,,Militidentigilo,Identificación Militar,,Sotilastunnus,Identification Militaire,Katonai Azonosító Kártya,Identificativo Militare,,군용 아이디,Militaire ID,Wojskowy Identyfikator,ID Militar,,Legitimație Militară,Военный ID,Војна идентификација -Order Key,TAG_ORDERKEY,,,,Klíč Řádu,Ordensschlüssel,,Ordeno-ŝlosilo,Llave de la Orden,,Veljeskunnan avain,Clé de l'Ordre,Rend Kulcs,Chiave dell'Ordine,,오더의 키,Ordersleutel,Klucz Zakonu,Chave da Ordem,,Cheia Ordinului,Ключ Ордена,Кључ одреда -Warehouse Key,TAG_WAREHOUSEKEY,,,,Klíč ke skladu,Lagerhausschlüssel,,Stokejŝlosilo,Llave del Almacén,,Varaston avain,Clé de l'Entrepôt,Raktár Kulcs,Chiave del Magazzino ,,창고 키,Magazijnsleutel,Klucz do Magazynu,Chave do Armazém,,Cheia Depozitului,Ключ от склада,Кључ складишта -Brass Key,TAG_BRASSKEY,,,,Mosazný klíč,Messingschlüssel,,Latuna Ŝlosilo,Llave de Latón,,Messinkiavain,Clé en Bronze,Sárgaréz Kulcs,Chiave d'Ottone ,,황동 키,Messing sleutel,Mosiężny Klucz,Chave de Latão,,Cheia din Alamă,Латунный ключ,Кључ од месинга -Red Crystal Key,TAG_REDCRYSTALKEY,,,,Červený krystalový klíč,Roter Kristallschlüssel,,Ruĝa Kristala Ŝlosilo,Llave de Cristal Rojo,,Punainen kristalliavain,Clé de Cristal Rouge,Piros Kristály Kulcs,Chiave di Cristallo Rosso ,,적색 크리스탈 키,Rode Kristallen Sleutel,Czerwony Kryształowy Klucz,Chave de Cristal Vermelho,,Cheia din Cristal Roșu,Крас. ключ-кристалл,Кључ од црвеног кристала -Blue Crystal Key,TAG_BLUECRYSTALKEY,,,,Modrý krystalový klíč,Blauer Kristallschlüssel,,Blua Kristala Ŝlosilo,Llave de Cristal Azul,,Sininen kristalliavain,Clé de Crisal Bleu,Kék Kristály Kulcs,Chiave di Cristallo Blu,,청색 크리스탈 키,Blauwe Kristallen Sleutel,Niebieski Kryształowy Klucz,Chave de Cristal Azul,,Cheia din Cristal Albastru,Син. ключ-кристалл,Кључ од плавог кристала -Chapel Key,TAG_CHAPELKEY,,,,Klíč od kaple,Kapellenschlüssel,,Kapelŝlosilo,Llave de la Capilla,,Kappelin avain,Clé de la Chapelle,Kápolna Kulcs,Chiave della Cappella ,,예배당 키,Kappelsleutel,Klucz do Kaplicy,Chave da Capela,,Cheia Capelei,Ключ от часовни,Кључ капеле -Catacomb Key,TAG_CATACOMBKEY,,,,Klíč do katakomb,Katakombenschlüssel,,Katakombŝlosilo,Llave de la Catacumba,,Katakombin avain,Clé des Catacombes,Katakomb Kulcs,Chiave delle Catacombe ,,고대 묘지 키,Catacombe sleutel,Klucz do Katakumb,Chave da Catacumba,,Cheia Catacombei,Ключ от катакомб,Кључ од катакомби -Security Key,TAG_SECURITYKEY,,,,Klíč ochranky,Sicherheitsschlüssel,,Gardŝlosilo,Llave de Seguridad,,Turvamiesavain,Clé de la Sécurité,Biztonsági Kulcs,Chiave della Sicurezza ,,보안 키,Beveiligingssleutel,Klucz Ochrony,Chave de Segurança,,Cheia Securității,Ключ охраны,Сигурносни кључ -Core Key,TAG_COREKEY,,,,Klíč k jádru,Reaktorschlüssel,,Kernŝlosilo,Llave del Núcleo,,Ytimen avain,Clé du Réacteur,Mag Kulcs,Chiave del Nucleo,,중심부 키,Reactorsleutel,Klucz do Rdzenia,Chave do Núcleo,,Cheia Nucleului,Ключ от реактора,Кључ језгра -Mauler Key,TAG_MAULERKEY,,,,Klíč k trhačům,Vernichterschlüssel,,Vundegilo-ŝlosilo,Llave del Triturador,,Moukarin avain,Clé du Broyeur,Szétbomló Kulcs,Chiave del Pestatore ,,마울러 키,Maulersleutel,Klucz do Magazynu Miażdżycieli,Chave - Mauler,,Cheia Sfâșietorului,Ключ истязателя,Маулер кључ -Factory Key,TAG_FACTORYKEY,,,,Klíč do továrny,Fabrikschlüssel,,Fabrikejo-ŝlosilo,Llave de la Fábrica,,Tehtaan avain,Clé de l'Usine,Gyár Kulcs,Chiave della Fabbrica ,,공장 키,Fabriekssleutel,Klucz do Fabryki,Chave da Fábrica,,Cheia Fabricii,Ключ от фабрики,Кључ фабрике -Mine Key,TAG_MINEKEY,,,,Klíč od dolů,Minenschlüssel,,Minejŝlosilo,Llave de la Mina,,Kaivoksen avain,Clé de la Mine,Bánya Kulcs,Chiave della Miniera ,,탄광 키,Mijnsleutel,Klucz do Kopalni,Chave da Mina,,Cheia Minei,Ключ от шахт,Кључ рудника -New Key5,TAG_NEWKEY5,,,,Nový klíč 5,Neuer Schlüssel 5,,Nova Ŝlosilo5,Llave Nueva5,,Uusi 5-avain,Clé nouveau 5,Új Kulcs5,Nuova Chiave 5,,새로운 키5,Nieuwe sleutel 5,Nowy Klucz5,Chave Nova 5,,Noua Cheie5,Новый ключ5,Нови кључ5 -Oracle Pass,TAG_ORACLEPASS,,,,Věštcova propustka,Orakelpass,,Oraklo-pasilo,Pase del Oráculo,,Oraakkelin kulkulupa,Passe de l'Oracle,Orákulum engedély,Lasciapassare dell'Oracolo ,,오라클의 통행증,Orakelkaart,Przepustka Wyroczni,Passe do Oráculo,,Legitimația Oracol,Пропуск Оракула,Пророкова пропусница -10 gold,TAG_10GOLD,,,,10 zlatých,10 Gold,,10 da oro,10 de Oro,,10 kolikkoa,10 Pièces,10 arany,10 pezzi d'oro ,10ゴールド,10 골드,10 goud,10 monet,10 moedas,10 moedas de ouro,10 monezi de aur,10 золотых,10 златника -25 gold,TAG_25GOLD,,,,25 zlatých,25 Gold,,25 da oro,25 de Oro,,25 kolikkoa,25 Pièces,25 arany,25 pezzi d'oro ,25ゴールド,25 골드,25 goud,25 monet,25 moedas,25 moedas de ouro,25 de monezi de aur,25 золотых,25 златника -50 gold,TAG_50GOLD,,,,50 zlatých,50 Gold,,50 da oro,50 de Oro,,50 kolikkoa,50 Pièces,50 arany,50 pezzi d'oro ,50ゴールド,50 골드,50 goud,50 monet,50 moedas,50 moedas de ouro,50 de monezi de aur,50 золотых,50 златника -300 gold,TAG_300GOLD,,,,300 zlatých,400 Gold,,300 da oro,300 de Oro,,300 kolikkoa,300 Pièces,300 arany,300 pezzi d'oro ,300ゴールド,300 골드,300 goud,300 monet,300 moedas,300 moedas de ouro,300 de monezi de aur,300 золотых,300 златника -Person,TXT_PERSON,,,,Osoba,,,Persono,Persona,,Henkilö,Personne,Személy,Persona,一員,민간인,Persoon,Osoba,Pessoa,,Persoană,Горожанин,Особа -Acolyte,TAG_ACOLYTE,,,,Akolyta,Ministrant,,Akolito,Acólito,,Alttaripalvelija,Acolyte,Ministráns,Accolito ,アコライト,아콜라이트,Acoliet,Akolita,Acólito,,Acolit,Служитель,Следбеник -Armorer,TAG_ARMORER,,,Armourer,Kovář,Rüster,,Armilisto,Armero,,Asemestari,Armurier,Páncél Kovács,Armaiolo ,装甲,병기공,Armorer,Płatnerz,Armeiro,,Armurier,Бронник,Ковач -Bar Keep,TAG_BARKEEP,,,,Barman,Wirt,,Trinkejisto,Cantinero,,Baarimikko,Barman,Csapos,Barista,酒屋,바텐더,,Barman,Dono do Bar,,Barman,Хозяин таверны,Конобар -Beggar,TAG_BEGGAR,,,,Žebrák,Bettler,,Almozulo,Mendigo,,Kerjäläinen,Mendiant,Koldus,Mendicante ,乞食,거지,Bedelaar,Żebrak,Mendigo,,Sărman,Нищий,Просјак -Macil,TAG_MACIL1,,,,Macil,,,,Macil,,,Macil,Macil,Macil,マシル,마실,Macil,Macil,Macil,,Macil,Мэйсил,Мејсил -Macil,TAG_MACIL2,,,,Macil,,,,Macil,,,Macil,Macil,Macil ,マシル,마실,Macil,Macil,Macil,,Macil,Мэйсил,Мејсил -Medic,TAG_MEDIC,,,,Medik,Sanitäter,,Kuracisto,Médico,,Lääkintämies,Médecin,Szanitéc,Medico,メディック,의무관,Paramedicus,Medyk,Médico,,Medic,Врач,Болничар -Oracle,TAG_ORACLE,,,,Věštec,Orakel,,Orakolo,Oráculo,,Oraakkeli,,Orákulum,Oracolo,オラクル,오라클,Orakel,Wyrocznia,Oráculo,,Oracol,Оракул,Пророк -Priest,TAG_PRIEST,,,,Kněz,Priester,,Pastro,Sacerdote,,Pappi,Prêtre,Pap,Sacerdote ,プリースト,성직자,Priester,Kapłan,Sacerdote,,Preot,Жрец,Свештеник -Rat Buddy,TAG_RATBUDDY,,,,Krysí kamarád,Ratte,,Ratkamarado,Ratero,,Rottakamu,Copain Rat,Patkány Cimbora,Amico dei Ratti ,ラット バディ,생쥐 친구,Rattenvriendje,Koleżka Szczurów,Rato,,Amicul Șobolanilor,Крыса,Друг пацов -Rebel,TAG_REBEL,,,,,Rebell,,Ribelulo,Rebelde,,Kapinallinen,Rebelle,Lázadó,Ribelle ,反乱軍,저항군,Rebel,Rebeliant,Rebelde,,Rebel,Повстанец,Побуњеник -Templar,TAG_TEMPLAR,,,,Templář,Templer,,Templano,Templario,,Temppeliherra,Templier,Templomos,Templare ,騎士団員,템플러,Tempelier,Templariusz,Templário,,Templier,Храмовник,Темплар -Weapon Smith,TAG_WEAPONSMITH,,,,Zbraňmistr,Waffenschmied,,Armilforĝisto,Forjador de Armas,,Aseseppä,Forgeron,Fegyver Kovács,Fabbro ,武器工,무기 제조상,Wapensmid,Wytwórca Broni,Ferreiro,,Făurar,Оружейник,Ковач оружја -Red Talisman,TAG_TALISMANRED,,,,Červený talisman,Roter Talisman,,Ruĝa Talismano,Talismán rojo,,Punainen talismaani,Talisman Rouge,Vörös Talízmán,Talismano rosso,赤の魔除け,붉은 부적,Rode Talisman,Czerwony Talizman,Talismã Vermelho,,Talisman Roșu,Красный талисман,Црвени талисман -Green Talisman,TAG_TALISMANGREEN,,,,Zelený talisman,Grüner Talisman,,Verda Talismano,Talismán verde,,Vihreä talismaani,Talisman Vert,,Talismano verde,緑の魔除け,녹색 부적,Groene Talisman,Zielony Talizman,Talismã Verde,,Talisman Verde,Зелёный талисман,Зелени талисман -Blue Talisman,TAG_TALISMANBLUE,,,,Modrý talisman,Blauer Talisman,,Blua Talismano,Talismán azul,,Sininen talismaani,Talisman Bleu,,Talismano blu,青の魔除け,푸른 부적,Blauwe Talisman,Niebieski Talizman,Talismã Azul,,Talisman Albastru,Синий талисман,Плави талисман -,,Obituaries,,,,,,,,,,,,,,,,,,,,, -%o was zealously shot down by an Acolyte.,OB_ACOLYTE,,,,%o byl@[ao_cs] horlivě zastřelen@[ao_cs] akolytou.,%o wurde eifrig von dem Ministranten erschossen.,,%o fervore pafiĝis per Akolito.,%o fue celosamente derribad@[ao_esp] por un Acólito.,,%o joutui kiivailevan alttaripalvelijan ampumaksi.,%o a souffert d'une bavure policière.,%o buzgóan lelett lőve egy Oltárszolga által.,%o è stato zelantemente abbattuto da un accolito. ,%o は熱心なアコライトに堕とされた。,%o 은(는) 아콜라이트에게 맹신적으로 사격 당했다.,%o werd gretig neergeschoten door een Acoliet.,%o został@[ao_pl] żarliwie zastrzelon@[adj_pl] przez Akolitę.,%o foi zelosamente abatid@[ao_ptb] por um Acólito.,,%o a fost împușcat zelos de un Acolit.,%o фанатично убит@[ao_rus] служителем.,%o је ревносно упуцан@[adj_1_sr] од стране секташа. -%o should have never rebelled against Macil.,OB_MACIL,,,,%o se nikdy neměl@[ao_cs] vzbouřit vůči Macilovi.,%o hätte nicht gegen Macil rebellieren sollen.,,%o neniam ribelu knotraŭ Macilo.,%o no debió haberse rebelado contra Macil.,,%o paran ei olisi ikinä pitänyt kapinoida Macilia vastaan.,%o n'aurait jamais du se rebeller contre Macil.,%o Macil ellen próbált fellázadni.,%o non avrebbe mai dovuto opporsi a Macil. ,%o はマシルに歯向かうべきではなかった。,%o 은(는) 마실의 적이 되지 말았어야 했다.,%o had nooit in opstand mogen komen tegen Macil.,%o nie powin@[irreg_5_pl] buntować się przeciwko Macilowi.,%o nunca deveria ter se rebelado contra Macil.,%o nunca deveria ter se rebeliado contra Macil.,"%o nu ar fi trebuit să se răscoale împotriva lui -Macil.",Игроку %o не следовало восставать против Мэйсила.,%o никад није треба@[ao_1_sr] да се супротстави Мејсилу. -%o was gunned down by a Rebel.,OB_REBEL,,,,%o byl@[ao_cs] odstřelen@[ao_cs] rebelem.,%o wurde von einem Rebellen erschossen.,,%o pafegiĝis per ribelanto.,%o fue fusilad@[ao_esp] por un Rebelde.,,%o joutui kapinallisen alas ampumaksi.,%o a été abattu@[e_fr] par un rebelle.,%o lelett lőve egy Lázadó által.,%o è stato colpito a morte da un Ribelle. ,%o は反乱軍に撃ち殺された。,%o 은(는) 저항군에 의해 제압당했다.,%o werd neergeschoten door een Rebel.,%o został@[ao_pl] rozstrzelan@[adj_pl] przez Rebelianta.,%o foi abatid@[ao_ptb] por um Rebelde.,,%o a fost pus la pământ de un Rebel.,Игрока %o расстрелял повстанец.,%o је упуцан@[adj_1_sr] од стране побуњеника. -%o was beaten to death by the poor.,OB_BEGGAR,,,,%o byl@[ao_cs] umlácen@[ao_cs] chudými.,%o fiel der Armut zum Opfer.,,%o morte bategiĝis per la malriĉuloj.,%o fue abatid@[ao_esp] hasta la muerte por los pobres.,,%o joutui köyhälistön kuoliaaksi hakkaamaksi.,%o a été battu@[e_fr] a mort par un pauvre.,%o halálra lett verve a szegénység által.,%o è stato calpestato dalla povertà. ,%o は貧民に殴り殺された。,%o 은(는) 자업자득으로 거지에게 맞아 죽었다.,%o werd door de armen doodgeslagen.,%o został@[ao_pl] zatłuczon@[adj_pl] na śmierć przez żebraka.,%o foi espancad@[ao_ptb] até a morte pelos pobres.,,%o a fost omorât în bătaie de sărmani.,Игрока %o забили до смерти нищие.,%o је претучен@[adj_1_sr] од стране просјака. -%o should have never picked a fight with a civilian.,OB_PEASANT,,,,%o si neměl@[ao_cs] začínat s civilistou.,%o hätte sich nicht mit einem Zivilisten anlegen sollen.,,%o neniam komencu batalon al civilulo.,%o nunca debió haberse metido en una pelea con un civil.,,%o hölmön ei olisi ikinä pitänyt haastaa riitaa siviilin kanssa.,%o n'aurait jamais du chercher des noises a un civil.,%o megpróbált Civillel szemben harcolni.,%o non avrebbe mai dovuto prendersela con un civile. ,%o は庶民に戦いを挑むべきではなかった。,%o 은(는) 민간인과 싸울 힘도 전혀 없었다.,%o had nooit een gevecht met een burger moeten aangaan.,%o nigdy nie powin@[irreg_5_pl] wdawać się w bójkę z cywilem.,%o nunca deveria ter arrumado briga com um civil.,%o nunca deveria ter pegado à briga com um civil.,%o n-ar fi trebuit să se încaiere cu un civil.,Игроку %o не следовало начинать драку с горожанином.,%o никад није треба@[ao_1_sr] да се потуче са цивилом. -%o was struck down by the Spectre.,OB_ALIENSPECTRE,,,,%o byl@[ao_cs] zničen@[ao_cs] přízrakem.,%o wurde von dem Schemen niedergestreckt.,,%o subite mortiĝis per la Fantomo.,%o fue abatid@[ao_esp] por el Espectro.,,%o joutui aaveen kaatamaksi.,%o a été terrassé@[e_fr] par le Spectre.,%o ki lett ütve a Kísértet által.,%o è stato abbattuto dallo Spettro. ,%o はスペクトルに討ち滅ぼされた。,%o 은(는) 스펙터에 의해 무너져 내렸다.,%o werd door de Specter neergeslagen.,%o został@[ao_pl] powalon@[adj_pl] przez Widmo.,%o foi abatid@[ao_ptb] por um Espectro.,,%o a fost răpus de Spectru.,Игрока %o уничтожил спектр.,%o је обори@[ao_1_sr] са ногу утвара. -%o felt the wrath of The One God.,OB_ENTITY,,,,%o pocítil@[ao_cs] vztek Jediného Boha,%o spürte den Zorn des Einen Gottes.,,%o sentis la koleregon de La Unu Dio.,%o sintió la ira del Dios Único.,,%o sai tuta Yhden Jumalan vihan.,%o a senti le courroux du Seul Dieu.,%o megérezte az Egyetlen Isten haragját.,%o ha assistito all'ira dell'Unico Dio. ,%o は唯一神の怒りに触れた。,%o 은(는) 유일신의 이름으로 천벌을 받았다.,%o voelde de toorn van de Ene God.,%o poczuł@[ao_pl] gniew Jedynego Boga.,,,%o a simțit furia Zeului.,%o столкнул@[refl_rus] с гневом Единого Бога.,Играча %o је осетио бес Јединог бога. -%o couldn't escape from the Lore Master's grasp.,OB_LOREMASTER,,,,%o nemohl@[ao_cs] utéct Dějepiscově sevření.,%o konnte dem Griff des Wissensmeisters nicht entkommen.,,%o ne povis eskapi el la kapto de le Ĉeffoklorulo.,%o no pudo escapar del agarre del Maestro del Conocimiento.,,%o ei kyennyt pakenemaan Oppi-Isän otteesta.,%o n'a pu échapper a l'emprise du Maître des Traditions.,%o nem tudott elmenekülni a Tan Mester elől.,%o non è riuscito a sfuggire alla stretta del Maestro del Sapere. ,%o はロアマスターの手から逃れられなかった。,%o 은(는) 로어마스터의 촉수를 벗어나지 못했다.,%o kon niet ontsnappen aan de greep van de kennismeester.,%o nie m@[irreg_4_pl] uniknąć chwytu Mędrca.,%o não conseguiu escapar do alcance do Mestre do Conhecimento.,,"%o n-a putut scăpa din mâinile Maestrului -Cunoștințelor.",%o не смог@[irreg_2_rus] избежать длани Хранителя мудрости.,%o није успе@[ao_1_sr] побећи из Чувареве мудрости домашаја. -%o was deleted by the Programmer.,OB_PROGRAMMER,,,,%o byl@[ao_cs] vymazán@[ao_cs] Programátorem.,%o wurde vom Programmierer gelöscht.,,%o eksiĝis per la Programisto.,%o fue suprimid@[ao_esp] por el Programador.,,%o joutui Ohjelmoijan poistamaksi.,%o a été effacé@[e_fr] par le Programmeur.,%o kilett törölve a Programozó által.,%o è stato cancellato dal Programmatore. ,%o はプログラマーに消去された。,%o 은(는) 프로그래머에 의해 삭제됐다.,%o werd door de programmeur verwijderd.,"%o został@[ao_pl] usunięt@[adj_pl] przez Programistę. -",%o foi deletad@[ao_ptb] pelo Programador.,%o foi apagad@[ao_ptb] pelo Programador.,%o a fost șters de Programator.,Игрока %o удалил Программист.,Играча %о је обрисао Програмер. -%o was blown away by the Bishop.,OB_STFBISHOP,,,,%o byl@[ao_cs] odpálen@[ao_cs] Biskupem.,%o wurde vom Bischof weggeblasen.,,%o forbloviĝis per la Episkopo.,%o fue volad@[ao_esp] en pedazos por el Obispo.,,%o joutui Piispan tyrmäämäksi.,%o a été pulvérisé@[e_fr] par l'Evèque.,%o el lett fújva a Püspök által.,%o è stato spazzato via dal Vescovo. ,%o はビショップに吹き飛ばされた。,%o 은(는) 비숍에 의해 초토화되었다.,%o werd door de bisschop weggeblazen.,%o został@[ao_pl] wysadzon@[adj_pl] przez Biskupa.,%o foi detonad@[ao_ptb] pelo Bispo.,,%o a fost aruncat cât colo de Episcop.,Игрока %o поразил Епископ.,Играча %o је екслопдирао Епископ. -%o was shot down by a Sentinel.,OB_SENTINEL,,,,%o byl@[ao_cs] odstřelen@[ao_cs] strážným robotem.,%o wurde von dem Wächter niedergeschossen.,,%o pafegiĝis per Gardspektisto.,%o fue derribado por un Centinela.,,%o joutui vartijan ampumaksi.,%o a été abattu@[e_fr] par une Sentinelle.,%o meglett lőve egy Őrszem által.,%o è stato impallinato dalla Sentinella. ,%o はセンティネルに堕とされた。,%o 은(는) 센티넬의 레이져를 맞았다.,%o werd neergeschoten door een Sentinel.,%o został@[ao_pl] zastrzelon@[adj_pl] przez Wartownika.,%o foi abatid@[ao_ptb] por uma Sentinela.,,%o a fost pus la pământ de o Santinelă.,Игрока %o застрелил страж.,Играча %o је упуцао стражар. -%o was swept away by a Crusader.,OB_CRUSADER,,,,%o byl@[ao_cs] odhozen@[ao_cs] křižákem.,%o wurde vom Ordensritter weggeblasen.,,%o rapide svingiĝis per Krucmilitisto.,%o fue barrid@[ao_esp] por un Cruzado.,,%o joutui ristiretkeläisen pois pyyhkäisemäksi.,%o a été balayé@[e_fr] par un croisé.,%o el lett söpörve egy Keresztes Lovag által.,%o è stato tolto di mezzo da un Crociato. ,"%o はクルセーダーに一掃された。 -",%o 은(는) 크루세이더의 공격에 날라갔다.,%o werd weggevaagd door een kruisvaarder.,%o został@[ao_pl] zmiecion@[adj_pl] przez Krzyżowca.,%o foi varrid@[ao_ptb] por um Cruzado.,,%o a fost măturat de un Cruciat.,Игрока %o смёл крестоносец.,%o је обори@[ao_1_sr] с ногу крсташ. -%o was sentenced by an Inquisitor.,OB_INQUISITOR,,,,%o byl@[ao_cs] odsouzen@[ao_cs] inkvizitorem.,%o wurde vom Inquisitor verurteilt.,,%o kondamniĝis per Inkvizitoro.,%o fue sentenciad@[ao_esp] por un Inquisidor.,,%o joutui inkvisiittorin tuomitsemaksi.,%o a été condamné@[e_fr] par un Inquisiteur.,%o el lett ítélve egy Vizsgálóbíró által.,%o è stato condannato da un Inquisitore. ,"%o は審問官によって宣告された。 -",%o 은(는) 인퀴지터에 의해 처벌받았다.,%o werd veroordeeld door een inquisiteur.,%o został@[ao_pl] skazan@[adj_pl] przez Inkwizytora.,%o foi condenad@[ao_ptb] por um Inquisidor.,,%o a fost condamnat de un Inchizitor.,Игрока %o приговорил инквизитор.,Играчу %o је пресудио инквизитор. -%o was bugged by a Stalker.,OB_STALKER,,,,%o se nechal@[ao_cs] otravovat slídilem.,%o wurde von dem Jäger genervt.,,%o ĝeniĝis per Gvantanto.,%o fue fastidiad@[ao_esp] por un Acechador.,,%o joutui vaanijan häiritsemäksi.,%o a été asticoté@[e_fr] par un chasseur.,%o bogaras lett egy Settenkedő által.,%o è stato violentato da un Cacciatore. ,"%o はストーカーに精神を蝕まれた。 -",%o 은(는) 스토커에게 벌레 물림을 당했다.,%o werd afgeluisterd door een Stalker.,%o został@[ao_pl] zaczepion@[adj_pl] przez Prześladowcę.,%o foi atacad@[ao_ptb] por um Caçador.,,%o a fost cicălit de un Hărțuitor.,Игрока %o ужалил сталкер.,Играча %o је убио прогонитељ. -%o triggered the automatic defenses.,OB_TURRET,,,%o triggered the automatic defences.,%o spustil@[ao_cs] automatickou obranu.,%o hat die automatische Verteidigung ausgelöst.,,%o aktivigis la aŭtomatajn defendojn.,%o activó las defensas automáticas.,,%o laukaisi automaattipuolustukset.,%o a déclenché les défenses automatiques.,%o bekapcsolta az automata védelmi rendszert.,%o ha attivato le difese automatiche. ,%o は警備システムを起動してしまった。,%o 은(는) 경비 시스템에 발각되었다.,%o activeerde de automatische verdediging.,%o aktywował@[ao_pl] automatyczne zabezpieczenia.,%o ativou as defesas automáticas.,,%o a alertat sistemul de protecție automat.,%o включил@[ao_rus] автоматическую защиту.,%o је активира@[ao_1_sr] дефанзивне системе. -%o was clawed by a Templar.,OB_TEMPLARHIT,,,,%o byl@[ao_cs] rozsápán@[ao_cs] templářem.,%o wurde von dem Templer aufgeschlitzt.,,%o ungegiĝis per Templano.,%o fue desgarrad@[ao_esp] por un Templario.,,%o joutui temppeliherran raatelemaksi.,%o a été griffé@[e_fr] par un Templier.,%o meglett karmolva egy Templomos által.,%o è stato artigliato da un Templare. ,%o は騎士団員に連行された。,%o 은(는) 템플러에게 할큄을 당했다.,%o werd geklauwd door een Tempelier.,%o został@[ao_pl] rozszarpan@[adj_pl] przez Templariusza.,%o foi rasgad@[ao_ptb] por um Templário.,,%o a fost zgâriat de un Templier.,Игрока %o разорвал храмовник.,%o је пресечен@[adj_1_sr] од стране темплара. -%o was vaporized by a Templar.,OB_TEMPLAR,,,,%o byl@[ao_cs] rozpuštěn@[ao_cs] templářem.,%o wurde von dem Templer vaporisiert.,,%o vaporiĝis per Templano.,%o fue vaporizad@[ao_esp] por un Templario.,,%o joutui temppeliherran höyryttämäksi.,%o a été vaporisé@[e_fr] par un Templier.,%o elpárolgott egy Templomos által.,%o è stato vaporizzato da un Templare. ,%o は騎士団員に浄化された。,%o 은(는) 템플러에 의해 존재가 소멸됐다.,%o werd verdampt door een Tempelier.,%o rozpłyn@[irreg_2_pl] się przez Templariusza.,%o foi vaporizad@[ao_ptb] por um Templário.,,%o a fost vaporizat de un Templier.,Игрока %o испепелил храмовник.,Играча %o је испарио темплар. -%o was sliced open by a Reaver.,OB_REAVERHIT,,,,%o byl@[ao_cs] rozřezán@[ao_cs] pleničem.,%o wude von dem Plünderer aufgeschlitzt.,,%o distranĉiĝis per Misilroboto.,%o fue rebanad@[ao_esp] por un Saqueador.,,%o joutui raastajan auki viiltämäksi.,%o a été fendu@[e_fr] par un Reaver.,%o szétlett vágva egy Fosztogató által.,%o è stato aperto a metà da un Saccheggiatore. ,%o はリーバーに切り裂かれた。,%o 은(는) 리버에게 해부되었다.,%o werd opengesneden door een Reaver.,%o został@[ao_pl] rozcięt@[adj_pl] przez Rozbójnika.,%o foi fatiad@[ao_ptb] por um Saqueador.,,%o a fost feliat de un Pungaș.,Игрока %o разрезал на куски похититель.,%o је исечен@[adj_1_sr] на отворено од стране сакупљача. -%o was shot down by a Reaver.,OB_REAVER,,,,%o byl@[ao_cs] zastřelen@[ao_cs] pleničem.,%o wurde von dem Plünderer niedergeschossen.,,%o pafegiĝis per Misilroboto.,%o fue derribad@[ao_esp] por un Saqueador.,,%o joutui raastajan alas ampumaksi.,%o a été descendu@[e_fr] par un Reaver.,%o le lett lőve egy Fosztogató által.,%o è stato colpito da un Saccheggiatore. ,%o はリーバーに撃ち殺された。,%o 은(는) 리버에게 격파되었다.,%o werd neergeschoten door een Reaver.,%o został@[ao_pl] zastrzelon@[adj_pl] przez Rozbójnika.,%o foi abatid@[ao_ptb] por um Saqueador.,,%o a fost împușcat de un Pungaș.,Игрока %o застрелил похититель.,Играча %o је упуцао сакупљач. -%o was unwittingly backstabbed by %k.,OB_MPPUNCHDAGGER,,,,%o dostal@[ao_cs] kudlou do zad od hráče %k.,%o wurde von %k hinterrücks erdolcht.,,%o akcidente dorspikiĝis per %k.,%o fue apuñalad@[ao_esp] sin darse cuenta por %k.,,%o joutui tahattomasti pelaajan %k selkäänpuukottamaksi.,%o s'est fait@[e_fr] planter un lame dans le dos de la part de %k.,%o véletlenül hátbalett szúrva %k által.,%o è stato colto alle spalle da %k senza che se ne accorgesse.,%o は電気ショックを %k からもらった。,%o 은(는) 모르는 사이에 %k 에 의해 비수를 찔렸다.,%o werd achtergestoken door %k.,%o został@[ao_pl] bezwiednie dźgnięt@[adj_pl] przez %k.,%o foi apunhalad@[ao_ptb] de surpresa por %k.,,%o a fost înjunghiat pe la spate de %k.,Игрок %o был непреднамеренно заколот кинжалом %k.,%o је убоден@[adj_1_sr] у леђа од стране играча %k. -%o got bolted to the wall by %k.,OB_MPELECTRICBOLT,,,,%o byl@[ao_cs] přišpendlen@[ao_cs] ke zdi hráčem %k.,%o wurde von %k an die Wand genagelt.,,%o pafiĝis per sageto sur la muro per %k.,%o quedó atornillad@[ao_esp] a la pared por %k.,,%o naulitsi %o paran seinään.,%o s'est fait@[e_fr] clouer au mur par %k.,%o falra lett szegezve %k által.,%o è stato inchiodato al muro da %k.,%o は %k に壁へ打ち付けられた。,%o 은(는) %k 의 전류가 흐르는 볼트촉을 만졌다.,%o werd door %k aan de muur geschroefd.,%o został@[ao_pl] przybit@[adj_pl] do ściany przez %k.,%o foi pregad@[ao_ptb] na parede por %k.,,%o a fost pus pe zid de %k.,Игрок %o был прибит к стене %k.,%o је причвршћен@[adj_1_sr] за зид од стране играча %k. -%o received a lethal dose of %k's wrath.,OB_MPPOISONBOLT,,,,%o přijal@[ao_cs] smrtelnou dávku hněvu hráče %k.,%o erhielt eine tödliche Dosis von %ks Zorn.,,%o recivis mortigan dozon per la kolerego de %k.,%o recibió una dosis letal de la ira de %k.,,%o sai tappavan annoksen pelaajan %k vihaa.,%o a recu une dose létale de la colère de %k.,%o kapott egy haragnyi adalékot %k-tól/től.,%o ha ricevuto una dose letale dell'ira di %k.,%o は 致死量の %k の怒りを盛られた。,%o 은(는) %k 로부터 암살 같지 않은 암살을 당했다.,%o kreeg een dodelijke dosis van %k's toorn.,%o dostał@[ao_pl] śmiertelną dawkę gniewu %k.,%o recebeu uma dose letal da ira de %k.,,%o a primit o doză letală din furia lui %k.,Игрок %o получил смертельную дозу гнева %k.,%o је доби@[ao_1_sr] смртну дозу гнева играча %k. -%o was drilled full of holes by %k's assault gun.,OB_MPASSAULTGUN,,,,%o byl@[ao_cs] proděravěn@[ao_cs] skrz na skrz puškou hráče %k.,%o wurde von %ks Sturmgewehr perforiert.,,%o boriĝis kun multaj truoj per la ataka pafilo de %k.,%o fue taladrad@[ao_esp] por el fusil de asalto de %k.,,%k porasi %o paran täyteen reikiä rynnäkkökiväärillään.,%o s'est fait@[e_fr] couvrir de trous par le fusil d'assaut de %k.,%o kilett lyukazva %k Gépfegyvere által.,%o è stato crivellato dall'arma d'assalto di %k.,%o は %k のアサルトガンで穴だらけにされた。,%o 은(는) %k 의 돌격소총 덕분에 멋진 구멍을 선물 받았다.,%o werd geperforeerd door %k.,%o został@[ao_pl] przedziurkowan@[adj_pl] przez karabin szturmowy %k.,%o foi perfurad@[ao_ptb] pelo fuzil de assalto de %k.,,"%o a fost umplut de găuri de pușca de asalt a lui -%k.",Игрок %o изрешечён штурмовой винтовкой %k.,%o је изрешетан@[adj_1_sr] од стране јуришне пушке играча %k. -%o gulped down %k's missile.,OB_MPMINIMISSILELAUNCHER,,,,%o spolknul@[ao_cs] raketu hráče %k.,%o schluckte %ks Rakete herunter.,,%o glutis la misilon de %k.,%o se tragó el misil de %k.,,%o nieli alas pelaajan %k ohjuksen.,%o a avalé le missile de %k.,%o lenyelte %k rakétáját.,%o ha inghiottito il missile di %k.,%o は %k のミサイルを味わった。,%o 은(는) %k 의 미니 미사일을 고맙게 삼켰다.,%o heeft %k's raket naar beneden geslingerd.,%o połkn@[irreg_2_pl] rakietę %k.,%o engoliu o míssil de %k.,,%o a înghițit proiectilul lui %k.,Игрок %o проглотил ракету %k.,%o је прогута@[ao_1_sr] ракету играча %k. -%o was inverted by %k's H-E grenade.,OB_MPSTRIFEGRENADE,,,,%o byl@[ao_cs] otočen@[ao_cs] naruby výbušným granátem hráče %k.,%o wurde von %ks HE-Granate invertiert.,,%o estis inversigita per la P-E granato de %k.,%o fue invertid@[ao_esp] por la granada HE de %k.,,%k käänsi %o paran nurinpäin räjähdekranaatillaan.,%o a été mis@[e_fr] sens dessus dessous par la grenade explosive de %k.,%o kilett fordítva %k gránátája által.,%o è stato invertito dalla granata H-E di %k.,%o は %k のHE手榴弾によって反逆された。,%o 은(는) %k 의 고폭탄에 의해 역전당했다.,%o werd omgekeerd door %k's HE-granaat.,%o został@[ao_pl] wywrócon@[adj_pl] przez granat %k.,%o foi peg@[ao_ptb] pelas granadas de %k.,,%o a fost întors pe dos de grenada lui %k.,Игрок %o инвертировался H-E гранатой %k.,%o се преокрену@[ao_1_sr] од стране Х-Е гранате играча %k. -%o took a flame bath in %k's phosphorous pyre.,OB_MPPHOSPHOROUSGRENADE,,,,%o si dal@[ao_cs] ohnivou koupel ve fosforovém požáru hráče %k.,%o nahm ein Flammenbad in %ks Scheiterhaufen.,,%o prenis flaman banon en la fosfora ŝtiparo de %k.,%o tomó un baño de llamas en la hoguera de fósforo de %k.,,%o otti liekkikylvyn pelaajan %k fosforiroviolla.,%o s'est permis@[e_fr] une pyroclave dans les flammes phosphoriques de %k.,%o kapott egy tűzfürdőt %k máglyájától.,%o ha fatto un bagno nelle fiamme nella pira di fosforo di %k.,%o は %k の白リン弾で炎に包まれた。,%o 은(는) %k 의 소이탄이 뿜는 화염에 몸을 담갔다.,%o nam een vlammenbad in %k's fosforbrandstapel.,%o wzi@[irreg_2_pl] ognistą kąpiel w fosforowym stosie %k.,%o se banhou nas chamas de fósforo de %k.,,%o a făcut o baie fierbinte in fosforul lui %k.,Игрок %o принял горячую ванну из чистого фосфора %k.,%o се окупа@[ao_1_sr] у пламену од стране фосфорне гранате играча %k. -%o was barbecued by %k.,OB_MPFLAMETHROWER,,,,%o byl@[ao_cs] osmažen@[ao_cs] hráčem %k.,%o wurde von %k gegrillt,,%o kradrostiĝis de %k.,%o fue asad@[ao_esp] por %k.,,%k grillasi %o paran.,%o est passé@[e_fr] au barbecue de %k.,%o meglett sütve %k által.,%o è stato fatto alla griglia da %k.,%o は %k に丸焼きにされてしまった。,%o 은(는) %k 의 바비큐 파티에 참여했다. 혼자서.,%o werd gebarbecued door %k.,%o został@[ao_pl] ugrillowan@[adj_pl] przez %k.,%o virou churrasco por causa de %k.,,%o a fost făcut grătar de %k.,Игрок %k поджарил игрока %o.,%o је реш печен@[adj_1_sr] од стране играча %k. -%o was zapped by %k.,OB_MPMAULER1,,,,%o byl@[ao_cs] zničen@[ao_cs] hráčem %k.,%o wurde von %k geschockt.,,%o elektrokutiĝis de %k.,%o fue electrocutad@[ao_esp] por %k.,,%o joutui pelaajan %k sähköistämäksi.,%o s'est fait@[e_fr] électrocuter par %k.,%o kapott egy áramot %k által.,%o è stato fulminato da %k.,%o は %k から電気ショックを浴びた。,%o 은(는) %k 이(가) 가한 전기 충격을 당했다.,%o werd door %k gezapt.,%o został@[ao_pl] porażon@[adj_pl] przez %k.,%o foi eletrocutad@[ao_ptb] por %k.,,%o a fost electrocutat de %k.,Игрок %k ударил током игрока %o.,%o је елетрошокиран@[adj_1_sr] од стране играча %k. -%o was viciously vaporized by %k.,OB_MPMAULER,,,,%o byl@[ao_cs] rozpuštěn@[ao_cs] hráčem %k.,%o wurde von %k vaporisiert.,,%o estis brutale vaporigita de %k.,%o fue viciosamente vaporizad@[ao_esp] por %k.,,%o joutui pelaajan %k höyrystämäksi.,%o à été vicieusement vaporisé@[e_fr] par %k.,%o elpárolgott %k által.,%o è stato crudelmente vaporizzato da %k.,%o は %k の悪辣さにより気化した。,%o 은(는) %k 에 의해 소극적으로 소멸되었다.,%o was door %k verdampt.,%o rozpłyn@[irreg_2_pl] się przez %k.,%o foi vaporizado por %k.,,%o a fost evaporat în mod vicios de %k.,Игрок %k безжалостно распылил игрока %o.,%o је брутално испари@[ao_1_sr] од стране играча %k. -%o bowed down to the sheer power of %k's Sigil.,OB_MPSIGIL,,,,%o poklekl@[ao_cs] před čirou sílou Pečeti hráče %k.,%o kapitulierte vor der Macht von %ks Sigil.,,%o kliniĝis antaŭ la plena potenco de la Sigelo de %k.,%o se inclinó ante el poder puro del emblema de %k.,,%o kumartui pelaajan %k Sinetin silkasta voimasta.,%o s'est prosterné@[e_fr] face à la toute puissance du Sigil de %k.,%o fejet hajtott %k Pecsétje ereje előtt.,%o si è prostrato davanti alla pura potenza del Sigillo di %k.,%o は %k のシジルによる威圧に屈した。,%o 은(는) %k 를 죽이기 전에 시질의 이름으로 절을 해야만 했다.,%o boog voor de kracht van %k's Sigil.,%o pokłonił@[ao_pl] się czystej mocy Symbolu %k.,%o sentiu o poder do Sigilo de %k.,,"%o s-a plecat în fața puterii imense a Sigiliului -lui %k.",Игрок %o склонился перед силой Сигила игрока %k.,%o је одклекну@[ao_1_sr] сировој моћи %k Сигила. -,,Miscellaneous,,,,,,,,,,,,,,,,,,,,, -Quest for the Sigil,TXT_STRIFE_EPI,,,,Pátrání za Pečetí,Suche nach dem Sigil,,Serĉado por la Sigelo,La búsqueda del Emblema,,Päämääränä Sinetti,La Quête du Sigil,,Alla ricerca del Sigillo,シジルの探求,시질을 위한 임무,Zoektocht naar de Sigil,Wyprawa po Symbol,Em Busca do Sigilo,Demanda pelo Sigilo,În căutarea Sigiliului,В поисках Сигила,Потрага за Сигил -You've freed the prisoners!,TXT_FREED_PRISONERS,,,,Vysvobodil@[ao_cs] jsi vězně!,Du hast die Gefangenen befreit!,,Vi liberigis la kaptitojn!,¡Has liberado a los prisioneros!,,Olet vapauttanut vangit!,Vous avez libéré les prisonniers!,,"Hai liberato i prigionieri! -",囚人を解放した!,죄수들을 탈옥시켰다!,Je hebt de gevangenen bevrijd!,Uwolnił@[irreg_3_pl] więźniów,Você liberou os prisioneiros!,Libertaste os prisioneiros!,Ai eliberat prizonierii!,Пленники освобождены!,Затвореници су ослобођени! -You've destroyed the Converter!,TXT_DESTROYED_CONVERTER,,,,Zničil@[ao_cs] jsi konvertér!,Du hast den Konverter zerstört!,,Vi detruis la Konvertilon!,¡Has destruido el Convertidor!,,Olet tuhonnut muuntajan!,Vous avez détruit le convertisseur!,,Hai distrutto i Convertitori!,コンバーターを破壊した!,개조 장치를 파괴했다!,Je hebt de Converter vernietigd!,Zniszczył@[irreg_3_pl] Transformator!,Você destruiu o Conversor!,Destruiste o Transformador!,Ai distrus Convertorul!,Конвертер уничтожен!,Претварач је уништен! -Congratulations! You have completed the training area,TXT_COMPLETED_TRAINING,,,,Gratulujeme! Dokončil@[ao_cs] jsi tréninkový areál,Gratuliere! Du hast das Trainingsprogramm bestanden.,,Gratulon! Vi kompletigis la trejnan areon,¡Felicidades! Has completado el área de entrenamiento,,Onnittelut! Olet suorittanut koulutusalueen,Félicitations! Vous êtes arrivé à la fin de l'entraînement.,Gratulálok. Elvégezted a gyakorló területet.,Congratulazioni! Hai completato l'area di addestramento,おめでとう!トレーニングエリアを完了した,훈련 코스를 마쳤다. 능력치 업!,Gefeliciteerd! Je hebt de training voltooid.,Gratulacje! Ukończył@[irreg_3_pl] trening,Parabéns! Você completou a área de treinamento,Parabéns! Completaste a área de treino,Felicitări! Ai încheiat cu zona de antrenament,Браво! Ты прошёл тренировку,Честитке! Завршио си тренинг подручје -You've blown up the Crystal,TXT_QUEST_14,,,,Odpálil@[ao_cs] jsi krystal,Du hast den Kristall zerstört.,,Vi eksplodigis la Kristalon,Has volado el Cristal,,Olet räjäyttänyt kristallin,Vous avez explosé le cristal!,Szétrobbantottad a kristályt,Hai fatto esplodere il Cristallo,クリスタルを爆破した,수정체를 파괴했다,Je hebt de Crystal opgeblazen.,Wysadził@[irreg_3_pl] Kryształ,Você explodiu o cristal,Explodiste o cristal,Ai aruncat în aer Cristalul,Кристалл взорван,Дигао си у ваздух кристал -You've blown up the Gates,TXT_QUEST_16,,,,Odpálil@[ao_cs] jsi brány,Du hast die Tore geöffnet.,,Vi eksplodigis la Pordegojn,Has volado las Puertas,,Olet räjäyttänyt portit,Vous avez explosé les portes!,A levegőbe repítetted a kapukat,Hai fatto esplodere i Cancelli,ゲートを爆破した,성문을 파괴해서 열었다,Je hebt de Gates opgeblazen.,Wysadził@[irreg_3_pl] Bramy,Você explodiu as portões,Explodiste os portões,Ai aruncat în aer Porțile,Ворота взорваны,Дигао си у ваздух капију -You've blown up the Computer,TXT_QUEST_27,,,,Odpálil@[ao_cs] jsi počítač,Du hast den Computer zerstört.,,Vi eksplodigis la Komputilon,Has volado la Computadora,,Olet räjäyttänyt tietokoneen,Vous avez explosé l'ordinateur!,Felrobbantottad a számítógépet,Hai fatto esplodere il Computer,コンピューターを爆破した,컴퓨터를 파괴했다,Je hebt de computer opgeblazen.,Wysadził@[irreg_3_pl] Komputer,Você explodiu o computador,Explodiste o computador,Ai aruncat în aer Calculatorul,Компьютер взорван,Дигао си у ваздух компјутер -You killed the Bishop!,TXT_KILLED_BISHOP,,,,Zabil@[ao_cs] jsi Biskupa!,Du hast den Bischof getötet.,,Vi mortigis la Episkopon!,¡Mataste al Arzobispo!,,Olet tappanut Piispan!,Vous avez tué l'évèque!,Megölted a Püspököt!,Hai ucciso il Vescovo!,ビショップを殺した!,비숍을 사살했다!,Je hebt de bisschop vermoord!,Zabił@[irreg_3_pl] Biskupa!,Você matou o Bispo!,Mataste o Bispo!,Ai omorât Episcopul!,Епископ убит!,Епископ је мртав! -You've killed the Oracle!,TXT_KILLED_ORACLE,,,,Zabil@[ao_cs] jsi Věštce!,Du hast das Orakel getötet,,Vi mortigis la Orakolon!,¡Has matado al Oráculo!,,Olet tappanut Oraakkelin!,Vous avez tué l'oracle!,Megölted az Orákulumot!,Hai ucciso l'Oracolo!,オラクルの予言を覆した!,오라클의 음모를 막았다!,Je hebt het Orakel vermoord!,Zabił@[irreg_3_pl] Wyrocznię!,Você matou o Oráculo!,Mataste o Oráculo,Ai omorât Oracolul!,Оракул убит!,Пророк је мртав! -You killed Macil!,TXT_KILLED_MACIL,,,,Zabil@[ao_cs] jsi Macila!,Du hast Macil getötet.,,Vi mortigis Macil!,¡Mataste a Macil!,¡Has matado a Macil!,Tapoit Macilin!,Vous avez tué Macil!,Megölted Macilt!,Hai ucciso Macil!,マシルを討ち取った!,마실을 처단했다!,Je hebt Macil vermoord!,Zabił@[irreg_3_pl] Macila!,Você matou o Macil!,Mataste Macil!,L-ai omorât pe Macil!,Мэйсил убит!,Мејсил је мртав! -You've killed the Loremaster!,TXT_KILLED_LOREMASTER,,,,Zabil@[ao_cs] jsi Dějepisce!,Du hast den Wissensmeister getötet!,,Vi mortigis la Scimajstro!,¡Has matado al Maestro del Conocimiento!,,Olet tappanut Oppi-Isän!,Vous avez tué le Maitre des traditions!,Megölted a Tudóst!,Hai ucciso il Maestro del Sapere!,ロアマスターを吊り上げた!,로어마스터의 목숨에 종지부를 찍었다!,Je hebt de Kennismeester vermoord!,Zabił@[irreg_3_pl] Mędrca!,Você matou o Mestre do Conhecimento!,Mataste o Mestre do Conhecimento!,L-ai omorât pe Maestrul Cunoștințelor!,Хранитель мудрости убит!,Чувара мудрости је мртав! -You fool! You've set off the alarm.,TXT_YOUFOOL,,,,Blázne! Spustil@[ao_cs] jsi alarm!,Du Trottel! Du hast den Alarm ausgelöst.,,Vi stultulo! Vi ekigis la alarmon.,¡Insensat@[ao_esp]! Has activado la alarma.,¡Tont@[ao_esp]! Has activado la alarma.,Sinä mieletön! Olet laukaissut hälytyksen.,Vous êtes fou! Vous avez activé l'alarme!,Te barom! Beindítottad a riasztót.,Stolto! Hai fatto scattare l'allarme.,バカな真似を! 警報を鳴らしてしまった。,어리석은 것! 알람이 작동되었다고!,Jij dwaas! Je hebt het alarm laten afgaan.,Głupcze! Włączył@[irreg_3_pl] alarm!,Seu idiota! Você ativou o alarme.,Idiota! Ativaste o alarme.,Nesăbuitule! Ai declanșat alarma!,Глупец. Ты включил сигнализацию!,Будало! Активирао си аларм. -You're dead! You set off the alarm.,TXT_YOUREDEAD,,,,Jsi mrtv@[adj_cs]! Spustil@[ao_cs] jsi alarm!,Du bist tot. Du hast den Alarm ausgelöst.,,Vi estas morta! Vi ekigis la alarmon.,¡Estás muert@[ao_esp]! Activaste la alarma.,,Sinä kuolet! Laukaisit hälytyksen.,Vous êtes mort! Vous avez activé l'alarme!,Beindult a riasztó. Halott vagy!,Sei morto! L'allarme è scattato.,絶望的だ! 警報を鳴らしてしまった。,알람이 작동되었다. 넌 죽었어!,Je bent dood! Je hebt het alarm laten afgaan.,Już nie żyjesz! Włączył@[irreg_3_pl] alarm!,Você está mort@[ao_ptb]! Você ativou o alarme.,Estás mort@[ao_ptb]! Ativaste o alarme.,Ești mort! AI declanșat alarma!,Ты поднял тревогу! Готовься к смерти!,Активирао си аларм. Спреми се да умреш! -You seem to have enough!,TXT_HAVEENOUGH,,,,Ty už toho máš dostatek!,Du scheinst genug zu haben.,,Vi ŝajnas havi sufiĉe!,¡Se ve que tienes suficiente!,,Sinulla näyttää olevan tarpeeksi!,Vous avez l'air d'en avoir assez!,Úgy néz ki eleged van már!,Sembra ne hai avuto abbastanza!,十分に持ち合わせている!,충분히 가진 것 같은데?,Je lijkt genoeg te hebben!,"Wydaje się, że już ci wystarczy!",Você parece ter o suficiente!,Pareces ter o suficiente!,Pare că ai destule!,"Кажется, тебе хватит!",Изгледа да ти је доста! -Go away!,TXT_GOAWAY,,,,Jdi pryč!,Verschwinde!,,Foriru!,¡Lárgate!,,Häivy!,Allez-vous en!,Takarodj!,Vattene via!,逃げ出せ!,저리 가!,Ga weg!,Idź stąd!,Vá embora!,Vai-te embora!,Pleacă!,Уходи!,Одлази! -Incoming Message...,TXT_COMM0,,,,Příchozí zpráva...,Nachricht erhalten...,,Alvenanta Mesaĝo...,Mensaje entrante...,,Vastaantuleva viesti...,Message reçu.,Bejövő Üzenet,Messaggio in arrivo...,メッセージが届いた...,메시지가 옴...,Inkomend bericht....,Nadchodzi wiadomość...,Recebendo Mensagem...,A Receber Mensagem...,Mesaj în intrare...,Входящее сообщение...,Наилази порука... -Incoming Message from BlackBird...,TXT_COMM1,,,,Příchozí zpráva od Straky...,Nachricht von Blackbird erhalten...,,Alvenanta Mesaĝo de BlackBird...,Mensaje entrante de BlackBird...,,Vastaantuleva viesti Blackbirdiltä...,Message reçu de BlackBird,Bejövő Üzenet Feketerigótól.,Messaggio in arrivo da Blackbird...,ブラックバードからのメッセージが届いた...,블랙버드로부터 메시지가 옴...,Inkomend bericht van BlackBird....,Nadchodzi wiadomość od BlackBird...,Recebendo Mensagem de BlackBird...,A Receber Mensagem de BlackBird...,Mesaj în intrare de la BlackBird...,Входящее сообщение от Чёрного дрозда...,Наилази порука од Црне птице.... -Find help,TXT_FINDHELP,,,,Najdi pomoc.,Finde Hilfe,,Trovu helpon,Busca ayuda,,Etsi apua,Trouvez de L'aide,Keress segítséget,Trova aiuto,助けを探せ,도움말,Zoek hulp,Znajdź pomoc,Procure ajuda,Procura ajuda,Găsește ajutor,Найди помощь,Нађи помоћ -for %u,TXT_TRADE,As in “for %u amount of money.”,,,za %u zlatých.,für %u,,por %u,por %u,,hintaan %u,pour %u,csak neked %u,per %u,%u ゴールド,(가격: %u),voor %u,za %u,por %u,,pentru %u,за %u,за %u -,,Chex Quest,,,,,,,,,,,,,,,,,,,,, -,,Pickups,,,,,,,,,,,,,,,,,,,,, -Picked up the Chex(R) Armor.,GOTCHEXARMOR,,,Picked up the Chex(R) Armour.,Sebráno Chex(R) brnění.,Du hast die Chex(R) Rüstung genommen,,Prenis la Chex(R)-kirason.,Recogiste la armadura Chex(R).,,Poimit Chex(R)-panssarin.,Vous avez pris l'armure Chex(R).,,Raccolta un'Armatura Chex(R).,チェックス(R)アーマー をてにいれた。,첵스(R) 갑옷 획득.,Je hebt het Chex(R) harnas opgehaald.,Podniesiono Pancerz Chex(R).,Pegou uma Armadura Chex(R).,Apanhaste uma Armadura Chex(R).,Ai ridicat Armura Chex(R).,Получена Chex(R)-броня.,Покупио си Чех оклоп. -Picked up the Super Chex(R) Armor!,GOTSUPERCHEXARMOR,,,Picked up the Super Chex(R) Armour!,Sebráno Super Chex(R) brnění!,Du hast die Superchex(R)Rüstung genommen!,,Prenis la superan Chex(R)-kirason!,¡Recogiste la armadura Súper Chex(R)!,,Poimit Super-Chex(R)-panssarin!,Vous avez pris la super armure Chex(R)!,,Raccolta la Super Armatura Chex(R)!,スーパーチェックス(R)アーマー をてにいれた。,슈퍼 첵스(R) 갑옷 획득!,Je hebt het Super-Chex(R) harnas opgehaald!,Podniesiono Super Pancerz Chex(R)!,Pegou uma Super Armadura Chex(R)!,Apanhaste uma Super Armadura Chex(R)!,Ai ridicat Super Armura Chex(R)!,Получена Chex(R)-сверхброня!,Покупио си Супер Чех оклоп. -Picked up a glass of water.,GOTWATER,,,,Sebrána sklenice vody.,Du hast ein Glas Wasser genommen.,,Prenis glason de akvo.,Recogiste un vaso de agua.,,Poimit vesilasin.,Vous avez pris un verre d'eau.,,Raccolto un bicchiere d'acqua.,コップいっぱいの みずをひろった。,물 한 컵 섭취.,Je hebt een glas water opgehaald.,Podniesiono szklankę wody.,Pegou um copo d'água.,Apanhaste um copo de água.,Ai ridicat un pahar cu apă.,Получен стакан воды.,Покупио си чашу воде -Picked up slime repellent.,GOTREPELLENT,,,,Sebrán repelent proti slizu.,Du hast das Schleimabwehrmittel genommen.,,Prenis mukforigilon.,Recogiste un repelente de baba.,,Poimit limakarkotteen.,Vous avez pris de la chaux répulsive.,,Raccolto del repellente allo slime.,スライム はんぱつざい をひろった。,오물 방수제 획득.,Je hebt de slijmafstotende stof opgehaald.,Podniesiono odstraszacz szlamu.,Pegou repelente de gosma.,Apanhaste repelente de gosma.,Ai ridicat respingătorul de mâzga.,Получен репеллент против слизи.,Покупио си одбијаш љигавца. -Supercharge Breakfast!,GOTBREAKFAST,,,,Supervýživná snídaně!,Überladenes Frühstück!,,Ŝargega Matenmanĝon!,¡Desayuno supercargado!,,Superaamiaislatinki!,Petit-déjeuner superchargé!,,Colazione da supercarica!,ちょうしょく スーパーチャージ!,힘찬 아침식사 섭취!,Overbelast ontbijt!,Supernaładowane Śniadanie!,Super Café da Manhã!,Super Pequeno-Almoço!,Superîncărcătură Mic Dejun!,Супер-завтрак!,Супер-напуњен доручак. -Picked up a blue key.,GOTCBLUEKEY,,,,Sebrán modrý klíč.,Du hast einen blauen Schlüssel genommen.,,Prenis bluan ŝlosilon.,Recogiste una llave azul.,,Poimit sinisen avaimen.,Vous avez pris une clé bleue.,,Raccolta una chiave blu.,あお のかぎ をひろった。,파란색 열쇠 획득.,Je hebt een blauwe sleutel opgehaald.,Podniesiono niebieski klucz.,Pegou a chave azul.,Apanhaste a chave azul.,Ai ridicat o cheie albastră.,Получен синий ключ.,Покупио си плави кључ. -Picked up a yellow key.,GOTCYELLOWKEY,,,,Sebrán žlutý klíč.,Du hast einen gelben Schlüssel genommen.,,Prenis ruĝan ŝlosilon.,Recogiste una llave amarilla.,,Poimit keltaisen avaimen.,Vous avez pris une clé jaune.,,Raccolta una chiave gialla.,きいろ のかぎ をひろった。,노란색 열쇠 획득.,Je hebt een gele sleutel opgehaald.,Podniesiono żółty klucz.,Pegou a chave amarela.,Apanhaste a chave amarela.,Ai ridicat o cheie galbenă.,Получен жёлтый ключ.,Покупио си жути кључ. -Picked up a red key.,GOTCREDKEY,,,,Sebrán červený klíč.,Du hast einen roten Schlüssel genommen.,,Prenis flavan ŝlosilon.,Recogiste una llave roja.,,Poimit punaisen avaimen.,Vous avez pris une clé rouge.,,Raccolta una chiave rossa.,あか のかぎ をひろった。,빨간색 열쇠 획득.,Je hebt een rode sleutel opgehaald.,Podniesiono czerwony klucz.,Pegou a chave vermelha.,Apanhaste a chave vermelha.,Ai ridicat o cheie roșie.,Получен красный ключ.,Покупио си црвени кључ. -Picked up a bowl of fruit.,GOTFRUIT,,,,Sebrána mísa s ovocem.,Du hast eine Obstschale genommen.,,Prenis bovlon de fruktoj.,Recogiste un tazón de fruta.,,Poimit hedelmäkulhon.,Vous avez pris un bol de fruits.,,Raccolto un vassoio di frutta.,フルーツのボウル をひろった。,과일 한 그릇 섭취.,Je hebt een fruitschaal opgehaald.,Podniesiono miskę owoców.,Pegou uma tigela de frutas.,Apanhaste uma taça com fruta.,Ai ridicat un bol de fructe.,Полуена тарелка с фруктами.,Покупио си чинију воћа. -Vegetables are REALLY good for you!,GOTVEGETABLESNEED,,,,Zelenina je VELMI zdravá!,Gemüse ist RICHTIG gut für dich!,,Legomoj estas TRE bonaj por vi!,¡Los vegetales son REALMENTE buenos para ti!,,Vihannekset ovat TOSI terveellisiä!,Les légumes sont VRAIMENT bons pour vous!,,La verdura ti fa DAVVERO bene!,いま とってもひつような やさいのボウルだ!,채소의 건강한 영양분이 독 기운을 없앴습니다!,Groenten zijn echt goed voor je!,Warzywa są BARDZO dobre dla ciebie!,Vegetais fazem MUITO bem para você!,Os Vegetais são MUITO bons para ti!,Legumele sunt FOARTE bune pentru tine!,Овощи ОЧЕНЬ полезны для здоровья!,Поврће је ЈАКО добро за тебе! -Picked up a bowl of vegetables.,GOTVEGETABLES,,,,Sebrána mísa se zeleninou.,Du hast eine Gemüseschale genommen.,,Prenis bovlon de legomoj.,Recogiste un tazón de vegetales.,,Poimit vihannesvadin.,Vous avez pris un bol de légumes.,,Raccolto un vassoio di verdura.,やさいのボウル をひろった。,채소 한 그릇 섭취.,Je hebt een kom groenten opgehaald.,Podniesiono miskę warzyw.,Pegou uma tigela de vegetais.,Apanhaste uma tigela com vegetais.,Ai ridicat un bol de legume.,Получена тарелка с овощами.,Покупио си чинију поврћа. -Found a Slime-Proof Suit,GOTSLIMESUIT,,,,Nalezen slizu odolný oblek.,Du hast einen Schleimbeständigen Anzug gefunden,,Trovis mukimunan kompleton.,Encontraste un traje a prueba de baba.,,Löysit limaapitävän puvun,Combinaison pare-gelée,,Raccolto un vestito a prova di slime,たい スライム スーツ をてにいれた。,오물 보호복 사용.,Je hebt een slijtvast pak opgehaald.,Znaleziono Szlamoodporny Kombinezon,Achou um Traje Anti-Gosma,Apanhaste um Fato Anti-Gosma.,Ai ridicat un Costum Rezistent la Mâzgă,Получен противослизневый костюм,Нашо си љигаво-отпорано одело. -Found a Computer Area Map,GOTCHEXMAP,,,,Nalezena počítačová mapa oblasti.,Du hast eine Computerkarte gefunden,,Trovis komputilan regionmapon.,Encontraste un mapa computarizado del área.,,Löysit alueen tietokonekartan,Vous avez trouve une carte informatique de la zone.,,Trovata una mappa computerizzata,コンピューターエリアマップ をてにいれた。,컴퓨터 지도 사용.,Je hebt een computerkaart opgehaald.,Znaleziono Komputerową Mapę Obszaru,Achou um Mapa Computadorizado,Apanhaste um Mapa Digital.,Ai ridicat o Hartă Generată pe Calculator a Zonei.,Получена компьютерная карта местности,Нашао компјутерку мапу окружења -Picked up a mini zorch recharge.,GOTZORCHRECHARGE,,,,Sebrán minibzukový náboj.,Du hast eine Minizorcher-Ladung genommen.,,Prenis zorĉreŝargeton.,Recogiste una recarga de mini zorch.,,Poimit minizorchlatauksen.,Vous avez pris une mini recharge zorch.,,Raccolta una ricarica di mini zorch.,ミニゾーチ リチャージ をひろった。,소형 저치 전지 획득.,Je hebt een minizorcherlading opgehaald.,Podniesiono mini ładunek zorch.,Pegou recarga para mini zorch.,Apanhaste uma recarga para o mini zorch.,Ai ridicat o mini încărcătură pentru zorch.,Получена зарядка для Мини-Зорчера.,Покупио си мини зорч пуњач. -Picked up a mini zorch pack.,GOTMINIZORCHPACK,,,,Sebrán minibzukový balík.,Du hast ein Minizorcher-Ladepaket genommen.,,Prenis zorĉpaketon,Recogiste un paquete de mini zorch.,,Poimit minizorchpaketin.,Vous avez pris un pack de mini recharges zorch.,,Raccolta una scatola di mini zorch.,ミニゾーチ パック をひろった。,저치 전지 박스 획득.,Je hebt een pakket met minizorcherladingen opgehaald.,Podniesiono mini paczkę zorch.,Pegou um pacote de recargas de mini zorch.,Apanhaste um pagcote de recargas para o mini zorch.,Ai ridicat un mini patchet de încărcătură pentru zorch.,Получена батарея для Мини-Зорчера.,Покупио си мини зорч пакет. -Picked up a zorch propulsor recharge.,GOTPROPULSORRECHARGE,,,,Sebrán náboj pro bzukový propulzor.,Du hast eine Propeller-Ladung genommen.,,Prenis zorĉpropulsilo-reŝargon.,Recogiste una recarga de propulsor de zorch.,,Poimit zorchtyöntimen latauksen.,Vous avez pris une recharge propulseur zorch.,,Raccolta una ricarica di zorch a propulsione.,ゾーチプロパルサーリチャージ をひろった。,저치 추진료 획득.,Je hebt een propulsorlading opgehaald.,Podniesiono ładunek do pędnika zorch.,Pegou recarga para propulsor de zorch.,Apanhaste recarga para o propulsor de zorch.,Ai ridicat o încărcătură pentru acceleratorul zorch.,Получена зарядка для Ускорителя Зорча.,Покупио си зорч погонски пуњач. -Picked up a zorch propulsor pack.,GOTPROPULSORPACK,,,,Sebrán balík pro bzukový propulzor.,Du hast ein Propeller-Ladepaket genommen.,,Prenis zorĉpropulsilo-pakon.,Recogiste un paquete de propulsor de zorch.,,Poimit zorchtyöntimen paketin.,Vous avez pris un paquet propulseur zorch.,,Raccolta una scatola di zorch a propulsione.,ゾーチプロパルサーパック をひろった。,저치 추진 팩 획득.,Je hebt een pakket met propulsorladingen opgehaald.,Podniesiono paczkę pędnika zorch.,Pegou um pacote de recargas para propulsor de zorch.,Apanhaste um pacote de recargas para o propulsor de zorch,Ai ridicat un pachet de baterii pentru acceleratorul zorch.,Получена батарея для Ускорителя Зорча.,Покупио си зорч погонски пакет. -Picked up a phasing zorcher recharge,GOTPHASINGZORCHERRECHARGE,,,,Sebrán náboj pro fázovací bzukr.,Du hast eine Phasenzorcher-Ladung genommen.,,Prenis fluktuantzorĉilo-reŝargon.,Recogiste una recarga de zorch de fase.,,Poimit vaiheiszorcherin latauksen.,Vous avez pris une recharge zorch phasée.,,Raccolta una ricarica per zorcher a phasing,フェイシング ゾーチャーリチャージ をひろった。,저치 전자 충전기 획득.,Je hebt een phasenzorcherlading opgehaald.,Podniesiono ładunek do fazowego zorchera.,Pegou recarga para zorcher fásico.,Apanhaste recarga para o zorcher fásico,Ai ridicat o încărcătură fazată pentru zorcher,Получена зарядка для Фазерного Зорчера.,Покупио си фазни зорчер пуњач. -Picked up a phasing zorcher pack.,GOTPHASINGZORCHERPACK,,,,Sebrán balík pro fázovací bzukr.,Du hast ein Phasenzorcher-Ladepaket genommen.,,Prenis fluktuantzorĉilo-pakon.,Recogiste un paquete de zorch de fase.,,Poimit vaiheiszorcherin paketin.,Vous avez pris un pack de recharges zorch phasée.,,Raccolta una scatola per zorcher a phasing.,フェイシング ゾーチャーパック をひろった。,특대 저치 충전기 획득.,Je hebt een pakket met phasenzorcherladingen opgehaald.,Podniesiono paczkę fazowego zorchera.,Pegou um pacote de recargas para zorcher fásico.,Apanhaste um pacote de recargas para o zorcher fásico,"Ai ridicat un pachet de încărcături fazate pentru -zorcher.",Получена батарея для Фазерного Зорчера.,Покупио си фазни зорчер пакет. -Picked up a large zorcher recharge.,GOTLARGEZORCHERRECHARGE,,,,Sebrán náboj pro velký bzukr.,Du hast eine Zorcher-Ladung genommen.,,Prenis grandzorĉilo-reŝargon.,Recogiste una gran recarga de zorch.,,Poimit ison zorcherin latauksen,Vous avez pris une recharge pour zorcheur large.,,Raccolta una ricarica per zorcher grande.,ラージ ゾーチャーリチャージ をひろった。,대형 저치 카트리지 획득.,Je hebt een zorcherlading opgehaald.,Podniesiono ładunek do dużego zorchera.,Pegou recarga para zorcher grande.,Apanhaste recarga para o zorcher grande.,Ai ridicat o încărcătură mare pentru zorcher.,Получена зарядка для Большого Зорчера.,Покупио си велики зорчер пуњач. -Picked up a large zorcher pack.,GOTLARGEZORCHERPACK,,,,Sebrán balík pro velký bzukr.,Du hast ein Zorcher-Ladepaket genommen.,,Prenis grandegzorĉilo-reŝargon.,Recogiste un gran paquete de zorch.,,Poimit ison zorcherin paketin.,Vous avez pris un pack de recharges pour zorcheur large.,,Raccolta una scatola per zorcher grande.,ラージ ゾーチャーパック をひろった。,저치 카트리지 묶음 획득.,Je hebt een pakket met zorcherladingen opgehaald.,Podniesiono paczkę dużego zorchera.,Pegou um pacote de recargas para zorcher grande.,Apanhaste um pacote de recargas para o zocher grande.,Ai ridicat un pachet mare de încărcături pentru zorcher.,Получена батарея для Большого Зорчера.,Покупио си велики зорчер пакет. -Picked up a Zorchpak!,GOTZORCHPACK,,,,Sebrán Bzukrbatoh!,Du hast ein Zorchpaket genommen.,,Prenis Zorĉpakon!,¡Recogiste un Zorchpak!,,Poimit zorchpakin!,Vous avez pris un zorchpak!,,Raccolto uno ZorchZaino!,ゾーチパックをてにいれた!,저치 팩 획득!,Je hebt en zorchpak opgehaald.,Podniesiono Paczkę Zorch.,Pegou um Zorchpak!,Apanhaste um Zorchpak!,Ai ridicat un Ghiozdan Zorch!,Получен Зорч-рюкзак!,Покупио си зорчпак. -You got the LAZ Device! Woot!,GOTLAZDEVICE,,,,Získal@[ao_cs] jsi velkodosahový bzukr! Cooo?,Du hast den Flächenzorcher!,,Vi prenis la LAZ-aparaton! Hura!,¡Tienes el dispositivo LAZ! ¡Yuju!,,Sait SAZ-laitteen! Juhuu!,Vous avez pris l'Outil ZZL! Wahou!,,Hai trovato il dispositivo LAZ! Cavolo!,LAZ デバイスをてにいれた! ワァオ!,LAZ 장치 습득! 완전 짱인걸!,Je hebt het LAZ-apparaat! Woot!,Zdobył@[irreg_3_pl] urządzenie LAZ! Juhu!,Você achou o Dispositivo LAZ! Oba!,Apanhaste um Dispositivo LAZ! Fixe!,Ai ridicat un Dispozitiv LAZ! Uraa!,Получено Устройство Зорчирования Большого Радиуса! Ура!,Добио си ЛАЗ уређај. ВУТ! -You got the Rapid Zorcher!,GOTRAPIDZORCHER,,,,Získal@[ao_cs] jsi rychlobzukr!,Du hast den schnellen Zorcher genommen!,,Vi prenis la Rapidzorĉilon!,¡Tienes el Zorcher rápido!,,Sait pikazorcherin!,Vous avez pris le Zorcheur Rapide!,,Hai trovato il zorcher rapido!,ラピッドゾーチャー をてにいれた!,속사 자쳐 습득!,Je hebt de snelle Zorcher!,Zdobył@[irreg_3_pl] Szybkostrzelny Zorcher!,Você pegou o Zorcher Automático!,Apanhaste o Zorcher Automático!,Ai ridicat un Zorcher cu Foc Rapid!,Получен Скорострельный Зорчер!,Добио си рапидан зорчер! -You got the Super Bootspork!,GOTSUPERBOOTSPORK,,,,Získal@[ao_cs] jsi super botovidličku!,Du hast den Super-Gabelquirl genommen!,,Vi prenis la Superan Ŝargmanĝilaron!,¡Tienes el Súper cubierto!,,Sait superluhan!,Vous avez pris la Super Fourchette!,,Hai trovato il super bootspork!,スーパーさきわれスプーン をてにいれた!,부트스포크 습득!,Je hebt de Super Bootspork!,Zdobył@[irreg_3_pl] Super Łyżkowidelec!,Você pegou o Super Garfo!,Apanhaste o Super Garfo-Colher!,Ai ridicat o Super Lingură!,Получена Супер Ложковилка!,Добио си супер чизмо-порк! -You got the Zorch Propulsor!,GOTZORCHPROPULSOR,,,,Získal@[ao_cs] jsi bzukový propulsor!,Du hast den Propellerzorcher genommen!,,Vi prenis la Zorĉpropulsilon!,¡Tienes el Propulsor de zorch!,,Sait zorchtyöntimen!,Vous avez pris le Propulseur Zorch!,,Hai trovato il propulsore zorch!,ロケット ゾーチャー をてにいれた!,저치 추진기 습득!,Je hebt de Zorch Propulsor!,Zdobył@[irreg_3_pl] Pędnik Zorch!,Você pegou o Propulsor de Zorch!,Apanhaste o Propulsor de Zorch!,Ai ridicat un Accelerator Zorch!,Получен Ускоритель Зорча!,Добио си зорч погон! -You got the Phasing Zorcher!,GOTPHASINGZORCHER,,,,Získal@[ao_cs] jsi fázovací bzukr!,Du hast den Phasenzorcher genommen!,,Vi prenis la Fluktuantzorĉilon!,¡Tienes el Zorcher de fase!,,Sait vaiheiszorcherin!,Vous avez pris le Zorcheur phasé!,,Hai trovato il zorcher a phasing!,フェイシング ゾーチャー をてにいれた!,전자 자쳐 습득!,Je hebt de Fasezorcher!,Zdobył@[irreg_3_pl] Fazowy Zorcher!,Você pegou o Zorcher Fásico!,Apanhaste o Zorcher Fásico!,Ai ridicat un Zorcher Fazat!,Получен Фазерный Зорчер!,Добио си фазни зорчер! -You got the Large Zorcher!,GOTLARGEZORCHER,,,,Získal@[ao_cs] jsi velký bzukr!,Du hast den großen Zorcher genommen!,,Vi prenis la Grandzorĉilon,¡Tienes el Zorcher largo!,,Sait ison zorcherin!,Vous avez pris le Zorcheur Large!,,Hai trovato il zorcher grande!,おおがたゾーチャー をてにいれた!,대형 자쳐 습득!,Je hebt de grote Zorcher!,Zdobył@[irreg_3_pl] Duży Zorcher!,Você pegou o Zorcher Grande!,Apanhaste o Zorcher Grande!,Ai ridicat un Zorcher Mare!,Получен Большой Зорчер!,Добио си велики зорчер! -You got the Mega Zorcher!,GOTSUPERLARGEZORCHER,,,,Získal@[ao_cs] jsi megabzukr!,Du hast den Megazorcher genommen!,,Vi prenis la Grandegzorĉilon!,¡Tienes el Mega Zorcher!,,Sait megazorcherin!,Vous avez pris le méga Zorcheur!,,Hai trovato il mega zorcher!,ちょうおおがたゾーチャー をてにいれた!,초대형 자쳐 습득!,Je hebt de Megazorcher!,Zdobył@[irreg_3_pl] Mega Zorcher!,Você pegou o Mega Zorcher!,Apanhaste o Mega Zorcher!,Ai ridicat un Mega Zorcher!,Получен Мега-Зорчер!,Добио си мега зорчер! -Picked up a Mini Zorcher.,GOTMINIZORCHER,,,,Sebrán minibzukr.,Du hast einen Minizorcher genommen.,,Prenis Zorĉileton.,Recogiste un Mini Zorcher,,Poimit minizorcherin.,Vous avez pris le Mini Zorcheur.,,Raccolto un mini zorcher.,こがたゾーチャー をてにいれた。,소형 자쳐 습득.,Je hebt een minizorcher opgehaald.,Podniesiono Mini Zorcher.,Você pegou um Mini Zorcher.,Apanhaste um Mini Zorcher.,Ai ridicat un Mini Zorcher.,Получен Мини-Зорчер.,Покупио си мини зорчер! -,,Actor tags,,,,,,,,,,,,,,,,,,,,, -Spoon,TAG_SPOON,,,,Lžíce,Löffel,,Kulero,Cuchara,,Lusikka,Cuillère à Botte,Kanál,Cucchiaio ,スプーン,숟가락,Lepel,Łyżka,Colher,,Lingură,Ложка,Кашика -Super Bootspork,TAG_SPORK,,,,Super botodlička,Supergabel,,Ega Ŝargmanĝilaro,Súper Cubierto,,Superluha,Super Fourchette,Szuper Rotációs Villa,Super Forcucchiaio,スーパーさきわれスプーン,부트스포크,,Super Łyżkowidelec,Super Garfo,Super Garfo-Colher,Super Lingură,Супер Ложковилка,Супер виљушка -Mini Zorcher,TAG_MINIZORCHER,,,,Minibzukr,Minizorcher,,Zorĉileto,Mini Zorcher,,Minizorcheri,Mini Zorcheur,Mini Zorker,Mini Zorcher,こがたゾーチャー,소형 자쳐,Minizorcher,Mini Zorcher,Mini Zorcher,,Mini Zorcher,Мини-Зорчер,Мини зорчер -Large Zorcher,TAG_LARGEZORCHER,,,,Velký bzukr,Großer Zorcher,,Granda Zorĉilo,Zorcher largo,,Iso zorcheri,Zorcheur Large,Nagy Zorker,Grosso Zorcher ,おおがたゾーチャー,대형 자쳐,Grote Zorcher,Duży Zorcher,Zorcher Grande,,Zorcher Mare,Большой Зорчер,Велики зорчер -Super-Large Zorcher,TAG_SUPERLARGEZORCHER,,,,Supervelký bzukr,Riesenzorcher,,Grandega Zorĉilo,Zorcher Súper Largo,,Superiso zorcheri,Zorcheur Extra-large,Hatalmas Zorker,Zorcher Enorme ,ちょうおおがたゾーチャー,초대형 자쳐,Super grote Zorcher,Większy Zorcher,Super Zorcher Grande,,Zorcher Super-Mare,Мега-Зорчер,Супер-велики зорчер -Rapid Zorcher,TAG_RAPIDZORCHER,,,,Rychlobzukr,Schnellzorcher,,Rapida Zorĉilo,Zorcher Rápido,,Pikazorcheri,Zorcheur Rapide,Gyors Zorker,Zorcher Rapido,れんしゃ ゾーチャー,속사 자쳐,Snelle Zorcher,Szybkostrzelny Zorcher,Zorcher Automático,,Zorcher cu Foc Rapid,Быстрый Зорчер,Рапидни зорчер -Zorch Propulsor,TAG_ZORCHPROPULSOR,,,,Bzukový propulzor,Zorch-Propeller,,Zorĉpropulsilo,Propulsor de Zorch,,Zorchtyönnin,Propulseur de Zorch,Zork Elhárító,Propulsore Zorch,ロケット ゾーチ,저치 추진기,,Pędnik Zorch,Propulsor de Zorch,,Accelerator Zorch,Ускоритель Зорча,Погонски зорчер -Phasing Zorcher,TAG_PHASINGZORCHER,,,,Fázovací bzukr,Phasenzorcher,,Fluktuantzorĉilo,Zorcher de Fase,,Vaiheiszorcheri,Zorcheur à Phase,Fokozatos Zorker,Zorcher di Fase,フェイシング ゾーチャー,전자 자쳐,Fasezorcher,Fazowy Zorcher,Zorcher Fásico,,Zorcher Fazat,Фазерный Зорчер,Фазни зорчер -LAZ Device,TAG_LAZDEVICE,,,,Velkodosahový bzukr,Flächenzorcher,,LAZ-Aparato,Dispositivo LAZ,,SAZ-laite,Zorcheur Zone Large,LAZ Szerkezet,Dispositivo LAZ,ラージエリアゾーキング デバイス,LAZ 장치,LAZ-aparaat,Urządzenie LAZ,Dispositivo LAZ,,Dispozitiv LAZ,Устройство «ЗБР»,ЛАЗ уређај -%o was slimed by a flemoid.,OB_COMMONUS,,,,%o byl@[ao_cs] osliznut@[ao_cs] slizounem.,%o wurde von einem Flemoiden vollgeschleimt.,,%o estas ŝlimiga de mukulo.,%o fue pegotead@[ao_esp] por un flemoide.,,%o joutui limatuksen limaamaksi.,%o à été gélifié par un flemoid.,%o egy flemoid eltrutyizott,%o è stato coperto di slime da un flemoid.,%o はフレモイドにベトベトにされた。,%o 은(는) 플레모이드에 의해 더러워졌습니다.,%o werd afgeslankt door een flemoid.,"%o został@[ao_pl] oszlamion@[adj_pl] przez flemoida. -",%o foi melecad@[ao_ptb] por um flemóide.,%o foi suj@[ao_ptb] por um flemóide.,%o a fost transformat în mâzgă de un flemoid.,Игрока %o обслюнявил флемоид.,%o је унаказио љигавац. -%o was slimed by a bipedicus.,OB_BIPEDICUS,,,,%o byl@[ao_cs] osliznut@[ao_cs] dvojnožkem.,%o wurde von einem Bipedicus vollgeschleimt.,,%o estas ŝlimiga de dupiedmukulo.,%o fue pegotead@[ao_esp] por un bipedicus.,,%o joutui bipedicuksen limaamaksi.,%o à été gélifié par un bipedicus.,,%o è stato coperto di slime da un bipedicus.,%o はバイペディクスにベトベトにされた。,%o 은(는) 바이피디쿠스의 끈쩍한 시야에 걸렸습니다.,%o werd afgeslankt door een bipedicus.,%o został@[ao_pl] oszlamion@[adj_pl] przez bipedicusa.,%o foi melecad@[ao_ptb] por um bipedicus.,%o foi suj@[ao_ptb] por um bipedicus.,% a fost transformat în mâzgă de un biped.,Игрока %o обслюнявила двуножка.,%o је унаказио двоножни-љигавац. -%o was slimed by an armored bipedicus.,OB_BIPEDICUS2,,,%o was slimed by an armoured bipedicus.,%o byl@[ao_cs] osliznut@[ao_cs] obrněným dvojnožkem.,%o wurde von einem gepanzerten Bipedicus vollgeschleimt.,,%o estas ŝlimiga de kirasa dupiedmukulo.,%o fue pegotead@[ao_esp] por un bipedicus blindado.,,%o joutui panssaroidun bipedicuksen limaamaksi.,%o à été gélifié par un bipedicus en armure.,,%o è stato coperto di slime da un bipedicus corazzato.,%o はアーマードペディクスにベトベトにされた。,%o 은(는) 정예 바이피디쿠스의 찐득한 공격을 받았습니다.,%o werd afgeslankt door een gepantserde bipedicus.,%o został@[ao_pl] oszlamion@[adj_pl] przez opancerzonego bipedicusa.,%o foi melecad@[ao_ptb] por um bipedicus de armadura.,%o foi suj@[ao_ptb] por um bipedicus de armadura.,"%o a fost transformat în mâzgă de un biped cu -armură.",Игрока %o обслюнявила бронированная двуножка.,%o је унаказио оклопни-љигавац. -%o was slimed by a cycloptis.,OB_CYCLOPTIS,,,,%o byl@[ao_cs] osliznut@[ao_cs] jednoočkem.,%o wurde von einem Cycloptis vollgeschleimt.,,%o estas ŝlimiga de ciklopmukulo,%o fue pegotead@[ao_esp] por un cicloptis.,,%o joutui cycloptiksen limaamaksi.,%o à été gélifié par un cycloptis.,,%o è stato coperto di slime da un cycloptis.,%o はサイクロプティスにベトベトにされた。,%o 은(는) 사이클롭티스 곁에 미끄러졌습니다.,%o werd afgeslankt door een cycloptis.,%o został@[ao_pl] oszlamion@[adj_pl] przez cykloptisa.,%o foi melecad@[ao_ptb] por um cycloptis.,%o foi suj@[ao_ptb] por um cycloptis.,%o a fost transformat în mâzgă de un ciclioptic.,Игрока %o обслюнявил циклоптис.,%o је унаказио циклогавац. -%o was defeated by the Flembrane.,OB_FLEMBRANE,,,,%o byl@[ao_cs] poražen@[ao_cs] Slizobránou.,%o wurde von der Flembrane geschlagen,,%o estas venkita de La Mukmembrano.,%o fue vencid@[ao_esp] por la Flembrana.,,%o joutui Limakalvon päihittämäksi.,%o à été battu par la Flembrane.,,%o è stato sconfitto dalla Flembrana.,%o はフレムブランにはいぼくした。,%o 은(는) 역겨운 플렘브레인을 돌파하지 못했습니다.,%o werd verslagen door de Flembrane.,%o został@[ao_pl] pokonan@[adj_pl] przez Flembranę.,%o foi derrotad@[ao_ptb] pela Flembrane.,,%o a fost învins de Flembrană.,Игрока %o победила Флембрана.,%o је поразио љигомозак. -%o was spoon fed by %k.,OB_MPSPOON,,,,%o byl@[ao_cs] nakrmen@[ao_cs] lžičkou hráče %k.,%o wurde von %k mit dem Löffel gefüttert.,,%o estas kulernutrita de %k.,%o fue cucharead@[ao_esp] por %k.,,%k syötti pelaajaa %o lusikalla.,%o à été nourri a la petite cuillière par %k.,,%o è stato imboccato da %k.,%o は %k にスプーンでたべさせられた。,%k 이(가) %o 을(를) 숟가락으로 맛있게 먹였습니다.,%o werd met een lepel gevoed door %k.,%o został@[ao_pl] nakarmion@[adj_pl] łyżką przez %k.,%o foi comid@[ao_ptb] de colher por %k.,,%o a fost hrănit cu lingura de %k.,Игрок %o поел с ложечки у игрока %k.,%o је накашикан од %k -%o was thoroughly mixed with %k's bootspork.,OB_MPBOOTSPORK,,,,%o byl@[ao_cs] pořádně namíchán@[ao_cs] botovidličkou hráče %k.,%o wurde von %k gründlich durchgerührt.,,%o estas plene miksita de la ŝargmanĝilaro de %k.,%o fue profundamente revuelt@[ao_esp] por el cubierto de %k.,,%k läpikotaisin sekoitti %o paran luhallaan.,%o à été mélange minutieusement par la Super Fourchette de %k.,,%o è stato mischiato ben bene dal bootspork di %k.,%o は %k にスーパーさきわれスプーンでかきまぜられた。,%k 이(가) %o 을(를) 부트스포크로 빙빙 돌렸습니다.,%o werd grondig gemengd met %k's bootspork.,%o został@[ao_pl] dokładnie wymieszan@[adj_pl] łyżkowidelcem %k.,%o foi mexid@[ao_ptb] pelo garfo de %k.,%o foi mexid@[ao_ptb] pelo garfo-colher de %k.,%o a fost amestecat bine de lingura lui %k.,Игрок %o тщательно перемешан ложковилкой игрока %k.,%o је темељно измешан од стране %k супер виљушке. -%o was zorched by %k.,OB_MPZORCH,,,,%o byl@[ao_cs] bzukrnut@[ao_cs] hráčem %k.,%o wurde von %k gezorcht,,%o estas zorĉita de %k.,%o fue electrizad@[ao_esp] por %k.,,%k zorchasi %o paran.,%o à été zorché par %k.,,%o è stato zorchato da %k.,%o は %k にビリビリさせられた。,%o 은(는) %k 의 소형 자쳐 광선에 맞았습니다.,%o werd gezorched door %k.,%o został@[ao_pl] został zazorchowan@[adj_pl] przez %k.,%o foi zorchead@[ao_ptb] por %k.,,%o a fost înlăturat de zorcherul lui %k.,Игрок %o получил заряд из Зорчера %k.,%o је зорчован %k. -%o was hit by %k's mega-zorcher.,OB_MPMEGAZORCH,,,,%o byl@[ao_cs] trefen@[ao_cs] megabzukrem hráče %k.,%o wurde von%ks Mega-Zorcher getroffen,,%o estas trafita de la zorĉilego de %k.,%o fue impactad@[ao_esp] por el mega-zorcher de %k.,,%k osui %o parkaan megazorcherillaan.,%o à été frappé par le mega zorcheur de %k.,,%o è stato colpito dal mega-zorcher di %k.,%o に %k のメガゾーチャーがヒットした。,%o 은(는) %k 의 초대형 자쳐 광선에 날라갔습니다.,%o werd geraakt door %k's megazorcher.,%o został@[ao_pl] trafion@[adj_pl] mega-zorcherem %k.,%o foi atingid@[ao_ptb] pelo mega-zorcher de %k.,,%o a fost lovit de mega-zorcherul lui %k.,Игрок %o подстрелен из Мега-Зорчера %k.,%o је ударен од стране %k мега-зорчера. -%o was rapid zorched by %k.,OB_MPRAPIDZORCH,,,,%o dostal@[ao_cs] rychlobzukrem hráče %k.,%o wurde von %k schnellgezorcht.,,%o estas rapidzorĉita de %k.,%o fue electrizad@[ao_esp] rápidamente por %k.,,%k pikazorchasi %o paran.,%o à été zorché rapidement par %k.,,%o è stato rapid-zorchato da %k.,%o は %k に めをまわされた。,%o 은(는) %k 의 속사 자쳐 때문에 춤을 췄습니다.,%o werd snel zorched door %k.,%o został@[ao_pl] szybko zazorchowan@[adj_pl] przez %k.,%o foi zorchead@[ao_ptb] automaticamente por %k.,,%o a fost învins de zorcherul rapid al lui %k.,Игрок %o получил заряд из Быстрого Зорчера %k.,%o је рапидно зорчован %k -%o was zorched by %k's propulsor.,OB_MPPROPULSOR,,,,%o byl@[ao_cs] bzukrnut@[ao_cs] propulzorem hráče %k.,%o wurde von %ks Propeller gezorcht,,%o estas zorĉita de la propulsilo de %k.,%o fue electrizad@[ao_esp] por el propulsor de %k.,,%k zorchasi %o paran työntimellään.,%o à été zorché par le propulseur de %k.,,%o è stato zorchato dal propulsore di %k.,%o は %k のロケットゾーチャーにあたった。,%o 은(는) %k 의 저치 추진기 쓴 맛을 봤습니다.,%o werd zorched door %k's propulsor.,%o został@[ao_pl] zazorchowan@[adj_pl] przez pędnik %k.,%o foi zorchead@[ao_ptb] pelo propulsor de %k.,,%o a fost învins de acceleratorul zorch al lui %k.,Игрок %o получил заряд из Ускорителя Зорча %k.,%o је зорчован %k погоном. -%o was hit by %k's propulsor.,OB_MPP_SPLASH,,,,%o byl@[ao_cs] zasažen@[ao_cs] propulzorem hráčem %k.,%o wurde von %ks Propeller getroffen,,%o estas trafita de la propulsilo de %k.,%o fue impactad@[ao_esp] por el propulsor de %k.,,%k osui %o parkaan työntimellään.,%o à été frappé par le propulseur de %k.,,%o è stato colpito dal propulsore di %k.,%o に %k のロケットゾーチャーがとどいた。,%o 은(는) %k 의 저치 추진기의 방사 능력을 우습게 봤습니다.,%o werd geraakt door %k's propulsor.,%o został@[ao_pl] trafion@[adj_pl] pędnikiem %k.,%o foi atingid@[ao_ptb] pelo propulsor de %k.,,%o a fost învins de acceleratorul lui %k.,Игрок %o подстрелен из Ускорителя Зорча %k.,%o је ударен %k погоном. -%o was phase zorched by %k.,OB_MPPHASEZORCH,,,,%o byl@[ao_cs] bzukr-vyfázován@[ao_cs] hráčem %k.,%o wurde von %k wegsynchronisiert,,%o estas fluktuantzorĉita de %k.,%o fue electrizad@[ao_esp] en fase por %k.,,%k vaiheiszorchasi %o paran.,%o à été phasé par %k.,,%o è stato phase-zorchato da %k.,%o は %k によってスベスベにされた。,%o 은(는) %k 의 전자 자쳐에 의해 쓰러졌습니다.,%o was fase zorched door %k.,%o został@[ao_pl] został sfazowan@[adj_pl] przez %k.,%o foi atingid@[ao_ptb] pelo zorcher fásico por %k.,,%o a fost înfrânt de zorcherul fazat al lui %k.,Игрок %o получил заряд из Фазерного Зорчера %k.,%o је фазно торчован %k. -%o fell prey to %k's LAZ device.,OB_MPLAZ_BOOM,,,,%o padl@[ao_cs] velkodosahovému bzukru hráče %k.,%o fiel %ks Flächenzorcher zum Opfer,,%o iĝis predo de la LAZ-aparato de %k.,%o cayó pres@[ao_esp] ante el dispositivo LAZ de %k.,,%o lankesi pelaajan %k SAZ-laitteen uhriksi.,%o est devenu la proie du ZZL de %k.,,%o è stato preda del dispositivo LAZ di %k.,%o は %k のLAZデバイスのえじきになった。,%k 이(가) LAZ 장치를 들기 전에 %o 은(는) 도망쳐야 했습니다.,%o viel ten prooi aan %k's LAZ apparaat.,%o stał@[ao_pl] się ofiarą urządzenia LAZ %k.,%o foi vítima do dispositivo LAZ de %k.,,%o a căzut pradă dispozitivului LAZ al lui %k.,Игрок %o склонился перед «ЗБР» игрока %k.,%o је постао жртва %k ЛАЗ уређаја. -%o was lazzed by %k.,OB_MPLAZ_SPLASH,,,,%o byl@[ao_cs] odbzukrován hráčem %k.,%o wurde von %k weggebeamt.,,%o estas LAZ-ita de %k.,%o fue LAZeado por %k.,,%k sazzasi pelaajaan %o.,%o à été pris par le ZZL de %k.,,%o è stato lazzato da %k.,%o は %k にとかされた。,%o 은(는) %k 의 LAZ 장치 범위를 벗어날 수 없었습니다.,%o werd gelazed door %k.,%o został@[ao_pl] zLAZowan@[adj_pl] przez %k.,%o foi LAZead@[ao_ptb] por %k.,,%o a fost stropit de dispozitivul LAZ al lui %k.,Игрок %o получил заряд из «ЗБР» игрока %k.,%o је ЛАЗ-овао %k. -,,Miscellaneous,,,,,,,,,,,,,,,,,,,,, -E1M1: Landing Zone,CHUSTR_E1M1,,,,E1M1: Přistávací zóna,E1M1: Landezone,,E1M1: Surterejo,E1M1: Zona de Aterrizaje,,E1M1: Laskeutumisalue,E1M1: La piste d'atterissage,E1M1: Landoló Zóna,E1M1: Zona di Atterraggio,E1M1: ちゃくりく ちてん,E1M1: 착륙 지점,E1M1: Landingszone,E1M1: Strefa Lądowania,E1M1: Zona de Pouso,E1M1: Zona de Aterragem,E1M1: Pista de Aterizare,E1M1: Зона приземления,Е1М1: Зона слетања -E1M2: Storage Facility,CHUSTR_E1M2,,,,E1M2: Skladiště,E1M2: Lagerhalle,,E1M2: Stokejo,E1M2: Instalación de Almacenamiento,,E1M2: Varastolaitos,E1M2: Le centre de stockage,,E1M2: Struttura di Immagazzinamento,E1M2: ほかん しせつ,E1M2: 저장 시설,E1M2: Opslagfaciliteit,E1M2: Magazyn,E1M2: Depósito,E1M2: Armazém,E1M2: Depozitul,E1M2: Хранилище,Е1М2: Складиште -E1M3: Experimental Lab,CHUSTR_E1M3,,,,E1M3: Testovací laboratoř,E1M3: Experimentelles Labor,,E1M3: Eksperimenta Laboratorio,E1M3: Laboratorio Experimental,,E1M3: Koelaboratorio,E1M3: Les labos expérimentaux,,E1M3: Laboratorio Sperimentale,E1M3: じっけんしつ,E1M3: 연구소,E1M3: Experimenteel laboratorium,E1M3: Laboratorium Eksperymentalne,E1M3: Laboratório de Experimentos,E1M3: Laboratório Experimental,E1M2: Laboratorul,E1M3: Лаборатория,Е1М3: Експериментална лабораторија -E1M4: Arboretum,CHUSTR_E1M4,,,,,,,E1M4: Arbejo,E1M4: Arboreto,,,E1M4: L'Arboretum,,E1M4: Arboreto,E1M4: じゅもくえん,E1M4: 수목원,E1M4: Arboretum,E1M4: Arboretum,E1M4: Arvoredo,,E1M4: Arboretum,E1M4: Дендрарий,Е1М4: Ботаничка башта -E1M5: Caverns of Bazoik,CHUSTR_E1M5,,,,E1M5: Bazoikské jeskyně,E1M5: Die Höhlen von Bazoik,,E1M5: Kavernoj de Bazojk,E1M5: Cavernas de Bazoik,,E1M5: Bazoikin luolastot,E1M5: Les cavernes de Bazoik,,E1M5: Caverne di Bazoik,E1M5: バゾイクの どうくつ,E1M5: 바조이크의 대동굴,E1M5: Grotten van Bazoik,E1M5: Jaskinie Bazoik,E1M5: Cavernas de Bazoik,,E1M5: Cavernele lui Bazoik,E1M5: Каверны Базоика,Е1М5: Пећине Базоика +",Скенер неће радити без мапе!,"Skannern fungerar inte utan en karta! +","Tarayıcı harita olmadan çalışmaz! +",Сканер не буде працювати без карти! +You picked up the Prison pass.,TXT_PRISONPASS,,,,Sebral@[ao_cs] jsi propustku do vězení.,Du samlede fængselspasset op.,Du hast den Gefängnispass genommen.,,Vi havas la malliberejan paspermeson.,Tienes el pase a la prisión.,,Poimit vankilan pääsyluvan.,Vous avez pris le passe de la prison.,Felvetted a Börtön belépőkártyát.,Hai raccolto il lasciapassare per la Prigione.,刑務所の許可証 取得。,감옥 통행증을 획득했다.,Je hebt de gevangenispas opgepakt.,Du plukket opp fengselspasset.,Podniosł@[irreg_3_pl] przepustkę do Więzienia.,Você pegou o passe da Prisão.,Apanhaste o passe da Prisão.,Ai ridicat Legitimația pentru Închisoare.,Получен пропуск в тюрьму.,Покупио си затворску пропусницу.,Du plockade upp fängelsepasset.,Hapishane kartını aldın.,Взято пропуск до тюрми. +You picked up the crossbow.,TXT_STRIFECROSSBOW,,,,Sebral@[ao_cs] jsi kuši.,Du samlede armbrøst op.,Du hast die Armbrust genommen.,Πήρες το τόξο,Vi trovis arbaleston.,Encuentras una ballesta.,,Poimit jousipyssyn.,Vous avez pris l'arbalète.,Felvetted a számszeríjat.,Hai raccolto la Balestra.,クロスボウ 入手。,석궁을 획득했다.,Je hebt de kruisboog opgepakt.,Du plukket opp armbrøsten.,Podniosł@[irreg_3_pl] kuszę.,Você pegou a besta.,Apanhaste uma besta.,Ai ridicat arbaleta.,Получен арбалет.,Покупио си самострел.,Du plockade upp armborstet.,Tatar yayını aldın.,Взято арбалет. +You picked up the assault gun.,TXT_ASSAULTGUN,,,,Sebral@[ao_cs] jsi pušku.,Du samlede pistolen op.,Du hast das Sturmgewehr genommen.,Πήρες το πολυβόλο.,Vi trovis sturmofusilon.,Encuentras un fusil de asalto.,,Poimit rynnäkkökiväärin.,Vous avez pris le fusil d'assaut.,Felvetted a gépfegyvert.,Hai raccolto il fucile d'assalto.,アサルトガン 入手。,돌격소총을 획득했다.,Je hebt het aanvalswapen opgepakt.,Du plukket opp stormgeværet.,Podniosł@[irreg_3_pl] karabin szturmowy.,Você pegou o fuzil de assalto.,Apanhaste a arma de assalto.,Ai ridicat pușca de asalt.,Получена штурмовая винтовка.,Покупио си аутоматску пушку.,Du plockade upp pistolen.,Saldırı silahını aldın.,Взято штурмову гвинтівку. +You picked up the mini missile launcher.,TXT_MMLAUNCHER,,,,Sebral@[ao_cs] jsi miniraketomet.,Du samlede mini-missilkasteren op.,Du hast den Miniraketenwerfer genommen.,Πήρες το μίνι πυραυλοβόλο.,Vi trovis misilet-pafilon.,Encuentras un minilanzamisiles.,,Poimit miniohjuslaukaisimen.,Vous avez pris le lance mini-missile.,Felvetted a minirakétavetőt.,Hai raccolto il Mini-Lanciamissili.,ミニミサイル ランチャー入手。,미니 미사일 런쳐를 획득했다.,Je hebt de mini-raketwerper opgepakt.,Du plukket opp mini-missilkasteren.,Podniosł@[irreg_3_pl] wyrzutnię minipocisków.,Você pegou o mini lança-mísseis.,Apanhaste o mini lança-mísseis,Ai ridicat mini lansatorul de rachete.,Получена мини-ракетница.,Покупио си мини ручни бацач.,Du plockade upp mini-missilkastaren.,Mini füze fırlatıcısını aldın.,Взято міні-ракетомет. +You picked up the flame thrower.,TXT_FLAMER,,,,Sebral@[ao_cs] jsi plamenomet.,Du samlede flammekasteren op.,Du hast den Flammenwerfer genommen.,Πήρες το φλογοβόλο.,Vi trovis flamĵetilon.,Encuentras un lanzallamas.,,Poimit liekinheittimen.,Vous avez pris le lance-flames.,Felvetted a lángszórót.,Hai raccolto il Lanciafiamme.,火炎放射器 入手。,완성된 화염방사기를 얻었다.,Je hebt de vlammenwerper opgepakt.,Du plukket opp flammekasteren.,Podniosł@[irreg_3_pl] miotacz ognia.,Você pegou o lança-chamas.,Apanhaste o lança-chamas.,Ai ridicat aruncătorul de flăcări.,Получен огнемёт.,Покупио си бацач пламена.,Du plockade upp flamkastaren.,Alev silahını aldın.,Взято вогнемет. +You picked up the mauler.,TXT_MAULER,,,,Sebral@[ao_cs] jsi trhač.,Du tog mauleren op.,Du hast den Vernichter genommen.,,Vi trovis polvigilon.,Encuentras un triturador.,,Poimit moukarin.,Vous avez pris le Broyeur.,Felvetted a marcangolót.,Hai raccolto il Pestatore.,マウラー 入手。,마울러를 획득했다.,Je hebt de toetakelaar opgepakt.,Du plukket opp mauleren.,Podniosł@[irreg_3_pl] miażdżyciel.,Você pegou o desintegrador.,Apanhaste o desintegrador.,Ai ridicat sfâșietorul.,Получен истязатель.,Покупио си маулер.,Du plockade upp mauler.,Parçalayıcıyı aldın.,Взято розсіювач. +You picked up the Grenade launcher.,TXT_GLAUNCHER,,,,Sebral@[ao_cs] jsi granátomet.,Du samlede granatkasteren op.,Du hast den Granatwerfer genommen.,Πήρες το εκτοξευτη χειροβομβίδων.,Vi trovis grenadĵetilon.,Encuentras un lanzagranadas.,,Poimit kranaatinheittimen.,Vous avez pris le lance-grenades,Felvetted a gránátvetőt.,Hai raccolto il Lanciagranate.,グレネードランチャー 入手。,유탄발사기를 획득했다.,Je hebt de granaatwerper opgepakt.,Du plukket opp granatkasteren.,Podniosł@[irreg_3_pl] wyrzutnię granatów.,Você pegou o lança-granadas.,Apanhaste o lança-granadas.,Ai ridicat Lansatorul de rachete.,Получен гранатомёт.,Покупио си бацач граната.,Du plockade upp granatkastaren.,El bombası fırlatıcısını aldın.,Взято гранатомет. +You picked up the SIGIL.,TXT_SIGIL,,,,Sebral@[ao_cs] jsi Pečeť.,Du samlede SIGIL op.,Du hast das SIGIL genommen.,,Vi trovis la SIGELON.,Encuentras el EMBLEMA.,,Poimit SINETIN.,Vous avez pris le SIGIL.,Felvetted a Pecsétet.,Hai raccolto il SIGILLO.,シジル 取得。,시질은 이제 당신의 것이다.,Je hebt de SIGIL opgepakt.,Du plukket opp SIGIL.,Podniosł@[irreg_3_pl] PIECZĘĆ.,Você pegou o SIGILO.,Apanhaste o SIGILO,Ai ridicat SIGILIUL.,Получена ПЕЧАТЬ.,Покупио си СИГИЛ.,Du plockade upp Sigillet.,SİGİL'i aldın.,Отримано СІГІЛ. +You picked up the Base Key.,TXT_BASEKEY,,,,Sebral@[ao_cs] jsi klíč od základny.,Du samlede Base nøglen op.,Du hast den Basisschlüssel genommen.,,Vi havas la ŝlosilon de la bazo.,Tienes la llave de la base.,,Poimit tukikohdan avaimen.,Vous avez pris la clé de la Base.,Felvetted a Bázis kulcsát.,Hai raccolto la chiave della Base.,基地のキー 取得。,기지 키를 획득했다.,Je hebt de basissleutel opgepakt.,Du plukket opp basenøkkelen.,Podniosł@[irreg_3_pl] Klucz do Bazy.,Você pegou a Chave da Base.,Apanhaste a Chave da Base.,Ai ridicat Cheia Bazei.,Получен ключ от базы.,Покупио си кључ базе.,Du plockade upp basnyckeln.,Üs Anahtarını aldın.,Взято ключ від бази. +You picked up the Govs Key.,TXT_GOVSKEY,,,,Sebral@[ao_cs] jsi klíč ke guvernérovi.,Du samlede guvernørens nøglen op.,Du hast den Gouverneursschlüssel genommen.,,Vi havas la ŝlosilon de la registo.,Tienes la llave del Gobernador.,,Poimit kuvernöörin avaimen.,Vous avez pris la clé du Gouverneur.,Felvetted a Kormányzó parcellájának kulcsát.,Hai raccolto la chiave del Governatore.,政府のキー 取得。,총독의 키를 획득했다.,Je hebt de gouverneursleutel opgepakt.,Du plukket opp regjeringsnøkkelen.,Podniosł@[irreg_3_pl] Klucz Gubernatora.,Você pegou a Chave do Governador.,Apanhaste a Chave do Governador.,Ai ridicat Cheia Guvernatorului.,Получен ключ губернатора.,Покупио си клуч гувернанте.,Du plockade upp Govs nyckeln.,Hükümet Anahtarını aldın.,Взято ключ губернатора. +You picked up the Passcard.,TXT_PASSCARD,,,,Sebral@[ao_cs] jsi průkazku.,Du samlede Adgangskort op.,Du hast die Zugangskarte genommen.,,Vi havas la ŝlosilon de la elektra centralo.,Tienes la llave de la central eléctrica.,,Poimit avainkortin.,Vous avez pris le passe.,Felvetted a Belépőkártyát.,Hai raccolto la Tessera Lasciapassare.,パスカード 取得。,통행 카드를 획득했다.,Je hebt de doorgangskaart opgepakt.,Du plukket opp adgangskortet.,Podniosł@[irreg_3_pl] Kartę Dostępu.,Você pegou o Cartão de Acesso.,Apanhaste o Cartão de Acesso.,Ai ridicat Legitimația.,Получен пропуск.,Покупио си пасош.,Du plockade upp passerkortet.,Erişim kartıni aldın.,Взято карту доступу. +You picked up the ID Badge.,TXT_IDBADGE,,,,Sebral@[ao_cs] jsi identifikační odznak.,Du samlede ID Badge op.,Du hast die Identitätskarte genommen.,,Vi havas la insignon de la malliberejo.,Tienes la insignia de la prisión.,,Poimit henkilötunnisteen.,Vous avez pris le Badge d'identification.,Felvetted az Azonosítójelvényt.,Hai raccolto il Distintivo.,IDバッジ 取得。,신분 휘장을 획득했다.,Je hebt de ID-badge opgepakt.,Du plukket opp ID-skiltet.,Podniosł@[irreg_3_pl] Odznakę Identyfikacyjną.,Você pegou o Crachá de Identificação.,Apanhaste o Crachá de Identificação,Ai ridicat Ecusonul de Identificare.,Получена личная карта.,Покупио си личну карту.,Du plockade upp ID-brickan.,Kimlik Rozetini aldın.,Взято бейджик. +You picked up the Prison Key.,TXT_PRISONKEY,,,,Sebral@[ao_cs] jsi klič k vězení.,Du samlede nøglen til fængslet op.,Du hast den Gefängnisschlüssel genommen.,,Vi havas la ŝlosilon de la malliberejo.,Tienes la llave de la prisión.,,Poimit vankilan avaimen.,Vous avez pris la clé de la Prison.,Felvetted a Börtönkulcsot.,Hai raccolto la chiave della Prigione.,刑務所のキー 取得。,감옥 키를 획득했다.,Je hebt de gevangenissleutel opgepakt.,Du plukket opp Fengselsnøkkelen.,Podniosł@[irreg_3_pl] Klucz do Więzienia.,Você pegou a Chave da Prisão.,Apanhaste a Chave da Prisão.,Ai ridicat Cheia Închisorii.,Получен ключ от тюрьмы.,Покупио си затворски кључ,Du tog upp fängelsenyckeln.,Hapishane Anahtarını aldın.,Взято ключ від тюрми. +You picked up the Severed Hand.,TXT_SEVEREDHAND,,,,Sebral@[ao_cs] jsi useknutou ruku.,Du samlede den afhuggede hånd op.,Du hast die abgetrennte Hand genommen.,,Vi havas amputitan manon.,Tienes una mano amputada.,,Poimit katkenneen käden.,Vous avez pris la main coupée.,Felvetted a Levágott kezet.,Hai raccolto la Mano Mozzata.,切り取った手 取得。,잘린 손목을 주웠다.,Je hebt de Gescheurde Hand opgepakt.,Du plukket opp den avkuttede hånden.,Podniosł@[irreg_3_pl] Odciętą Rękę.,Você pegou a Mão Decepada.,Apanhaste a Mão Desmenbrada.,Ai ridicat Mâna Retezată.,Получена отрезанная рука.,Покупио си шаку,Du plockade upp den avhuggna handen.,Kesik El'i aldın.,Взято відрізану руку. +You picked up the Power1 Key.,TXT_POWER1KEY,,,,Sebral@[ao_cs] jsi klíč k elektrárně 1.,Du samlede Power1-nøglen op.,Du hast den Kraftwerksschlüssel 1 genommen,,Vi havas la unuan centralan identigilon.,Tienes una identificación nivel uno de la central.,,Poimit voimalan 1-avaimen.,Vous avez pris la clé Power1.,Felvetted az 1-es Áram kulcsot.,Hai raccolto la chiave della Centrale n.1,パワー1キー 取得。,발전소 1호 키를 획득했다.,Je hebt de 1e Machtsleutel opgepakt.,Du plukket opp Power1-nøkkelen.,Podniosł@[irreg_3_pl] Klucz do Elektrowni 1.,Você pegou a Chave da Usina 1.,Apanhaste a Chave Energética 1,Ai ridicat Cheia Putere1.,Получен ключ электростанции №1.,Покупио си први кључ од електране.,Du plockade upp kraftnyckeln 1.,Güç1 Anahtarını aldın.,Взято ключ від електростанції 1. +You picked up the Power2 Key.,TXT_POWER2KEY,,,,Sebral@[ao_cs] jsi klíč k elektrárně 2.,Du samlede Power2-nøglen op.,Du hast den Kraftwerksschlüssel 2 genommen,,Vi havas la duan centralan identigilon.,Tienes una identificación nivel dos de la central.,,Poimit voimalan 2-avaimen.,Vous avez pris la clé Power2.,Felvetted az 2-es Áram kulcsot.,Hai raccolto la chiave della Centrale n.2,パワー2キー 取得。,발전소 2호 키를 획득했다.,Je hebt de 2e Machtsleutel opgepakt.,Du plukket opp Power2-nøkkelen.,Podniosł@[irreg_3_pl] Klucz do Elektrowni 2.,Você pegou a Chave da Usina 2.,Apanhaste a Chave Energética 2,Ai ridicat Cheia Putere2.,Получен ключ электростанции №2.,Покупио си други кључ од електране.,Du plockade upp kraftnyckeln 2.,Güç2 Anahtarını aldın.,Взято ключ від електростанції 2. +You picked up the Power3 Key.,TXT_POWER3KEY,,,,Sebral@[ao_cs] jsi klíč k elektrárně 3.,Du samlede Power3-nøglen op.,Du hast den Kraftwerksschlüssel 3 genommen,,Vi havas la trian centralan identigilon.,Tienes una identificación nivel tres de la central.,,Poimit voimalan 3-avaimen.,Vous avez pris la clé Power3.,Felvetted az 3-as Áram kulcsot.,Hai raccolto la chiave della Centrale n.3,パワー3キー 取得。,발전소 3호 키를 획득했다.,Je hebt de 3e Machtsleutel opgepakt.,Du plukket opp Power3-nøkkelen.,Podniosł@[irreg_3_pl] Klucz do Elektrowni 3.,Você pegou a Chave da Usina 3.,Apanhaste a Chave Energética 3,Ai ridicat Cheia Putere3.,Получен ключ электростанции №3.,Покупио си трећи кључ од електране.,Du plockade upp kraftnyckeln 3.,Güç3 Anahtarını aldın.,Взято ключ від електростанції 3. +You picked up the Gold Key.,TXT_GOLDKEY,,,,Sebral@[ao_cs] jsi zlatý klíč.,Du samlede den guldnøglen op.,Du hast den Goldschlüssel genommen.,,Vi havas oran ŝlosilon.,Tienes una llave dorada.,,Poimit kulta-avaimen.,Vous avez pris la clé d'or.,Felvetted az Aranykulcsot.,Hai raccolto la chiave dorata,ゴールドキー 取得。,황금 키를 획득했다.,Je hebt de gouden sleutel opgepakt.,Du plukket opp Gullnøkkelen.,Podniosł@[irreg_3_pl] Złoty Klucz.,Você pegou a Chave de Ouro.,Apanhaste a Chave de Ouro,Ai ridicat Cheia de Aur.,Получен золотой ключ.,Покупио си златни кључ.,Du plockade upp guldnyckeln.,Altın Anahtarı aldın.,Взято золотий ключ. +You picked up the ID Card.,TXT_IDCARD,,,,Sebral@[ao_cs] jsi ID kartu.,Du samlede ID-kortet op.,Du hast den Ausweis genommen.,,Vi havas identigilon de la kloakoj.,Tienes una identificación de las clocacas.,,Poimit henkilökortin.,Vous avez pris la Carte d'identité.,Felvetted az Igazolványt.,Hai raccolto la Tessera di Identificazione.,IDカード 取得。,신분증을 획득했다.,Je hebt de ID-kaart opgepakt.,Du plukket opp ID-kortet.,Podniosł@[irreg_3_pl] Kartę Identyfikacyjną.,Você pegou o Cartão de Identifiçacão.,Apanhaste o Cartão de Identificação,Ai ridicat Cardul de Identitate.,Получено удостоверение.,Покупио си идентификациону картицу.,Du plockade upp ID-kortet.,Kimlik Kartını aldın.,Взято ідентифікаційну карту. +You picked up the Silver Key.,TXT_SILVERKEY,,,,Sebral@[ao_cs] jsi stříbrný klíč.,Du tog sølvnøglen op.,Du hast den Silberschlüssel genommen.,,Vi havas arĝentan ŝlosilon.,Tienes una llave plateada.,,Poimit hopea-avaimen.,Vous avez pris la clé d'argent.,Felvetted az Ezüstkulcsot.,Hai raccolto la chiave argentata,シルバーキー 取得。,은 키를 획득했다.,Je hebt de zilveren sleutel opgepakt.,Du plukket opp sølvnøkkelen.,Podniosł@[irreg_3_pl] Srebrny Klucz.,Você pegou a Chave de Prata.,Apanhaste a Chave de Prata,Ai ridicat Cheia de Argint.,Получен серебряный ключ.,Покупио си сребрни кључ.,Du plockade upp silvernyckeln.,Gümüş Anahtarı aldınız.,Взято срібний ключ +You picked up the Oracle Key.,TXT_ORACLEKEY,,,,Sebral@[ao_cs] jsi věštcův klíč.,Du tog Oracle-nøglen op.,Du hast den Orakelschlüssel genommen.,,Vi havas ŝlosilon de la Orakolo,Tienes una llave del Oráculo.,,Poimit Oraakkelin avaimen.,Vous avez pris la clé Oraclé.,Felvetted az Orákulum kulcsát.,Hai raccolto la chiave dell'Oracolo.,オラクルキー 取得。,오라클 키를 획득했다.,Je hebt de Orakelsleutel opgepakt.,Du plukket opp Oracle-nøkkelen.,Podniosł@[irreg_3_pl] Klucz do Wyroczni.,Você pegou a Chave do Oráculo.,Apanhaste a Chave do Oráculo.,Ai ridicat Cheia Oracol.,Получен ключ Оракула.,Покупио си кључ пророка,Du plockade upp Orakel-nyckeln.,Kahin Anahtarını aldın.,Взято ключ Оракула. +You picked up the Military ID.,TXT_MILITARYID,,,,Sebral@[ao_cs] jsi vojenské ID.,Du samlede militær-ID op.,Du hast den Militärausweis genommen.,,Vi havas militan identigilon.,Tienes una identificación militar.,,Poimit sotilastunnuksen.,Vous avez pris l'ID Militaire.,Felvetted a Katonai igazolványt.,Hai raccolto l'Identificativo Militare.,ミリタリーID 取得。,군용 아이디를 획득했다.,Je hebt de militaire ID opgepakt.,Du plukket opp den militære ID-en.,Podniosł@[irreg_3_pl] Wojskowy Identyfikator.,Você pegou a Identificação Militar.,Apanhaste a Identificação Militar.,Ai ridicat Legitimația Militară.,Получено военное удостоверение.,Покупио си војну идентификацију,Du plockade upp det militära ID-kortet.,Askeri Kimliği aldın.,Взято військову ID карту. +You picked up the Order Key.,TXT_ORDERKEY,,,,Sebral@[ao_cs] jsi klíč Řádu.,Du samlede Ordensnøglen op.,Du hast den Ordensschlüssel genommen.,,Vi havas la ŝlosilon de La Ordeno.,Tienes la llave de La Orden.,,Poimit Veljeskunnan avaimen.,Vous avez pris la clé de l'Ordre.,Felvetted a Rend kulcsát.,Hai raccolto la chiave dell'Ordine.,オーダーキー 取得。,오더의 키를 획득했다.,Je hebt de Ordesleutel opgepakt.,Du plukket opp Bestillingsnøkkelen.,Podniosł@[irreg_3_pl] Klucz Zakonu.,Você pegou a Chave da Ordem.,Apanhaste a Chave da Ordem.,Ai ridicat Cheia Ordinului.,Получен ключ Ордена.,Покупио си кључ одреда,Du plockade ordernyckeln.,Emir Anahtarını aldın.,Взято ключ Ордену. +You picked up the Warehouse Key.,TXT_WAREHOUSEKEY,,,,Sebral@[ao_cs] jsi klíč ke skladu.,Du samlede lagernøglen op.,Du hast den Lagerhausschlüssel genommen,,Vi havas la ŝlosilon de la magazeno.,Tienes la llave del almacén.,,Poimit varaston avaimen.,Vous avez pris la clé de l'entrepôt.,Felvetted a Raktár kulcsát.,Hai raccolto la chiave del Magazzino.,倉庫のキー 取得。,창고 키를 획득했다.,Je hebt de pakhuissleutel opgepakt.,Du plukket opp Lagernøkkelen.,Podniosł@[irreg_3_pl] Klucz do Magazynu.,Você pegou a Chave do Armazém.,Apanhaste a Chave do Armazém,Ai ridicat Cheia Depozitului.,Получен ключ от склада.,Покупио си кључ складишта,Du plockade lagernyckeln.,Depo Anahtarını aldın.,Взято ключ від складу. +You picked up the Brass Key.,TXT_BRASSKEY,,,,Sebral@[ao_cs] jsi mosazný klíč.,Du samlede messingnøglen op.,Du hast den Messingschlüssel genommen.,,Vi havas la latunan ŝlosilon.,Tienes la llave de latón.,,Poimit messinkiavaimen.,Vous avez pris la clé de bronze.,Felvetted a Rézkulcsot.,Hai raccolto la chiave d'Ottone.,ブラスキー 取得。,황동 키를 획득했다.,Je hebt de messing sleutel opgepakt.,Du plukket opp messingnøkkelen.,Podniosł@[irreg_3_pl] Mosiężny Klucz.,Você pegou a Chave de Latão.,Apanhaste a Chave de Latão,Ai ridicat Cheia din Alamă.,Получен латунный ключ.,Покупио си кључ месинга,Du plockade mässingsnyckeln.,Pirinç Anahtarı aldın.,Взято латунний ключ. +You picked up the Red Crystal Key.,TXT_REDCRYSTAL,,,,Sebral@[ao_cs] jsi červený krystalový klíč.,Du samlede den røde krystalnøgle op.,Du hast den roten Kristallschlüssel genommen.,,Vi trovis la ruĝkristalan ŝlosilon.,Encuentras la llave de cristal rojo.,,Poimit punaisen kristalliavaimen.,Vous avez pris la clé cristal rouge.,Felvetted a Vörös Kristály Kulcsot.,Hai raccolto la chiave del Cristallo Rosso.,赤水晶のキー 取得。,적색 크리스탈 키를 획득했다.,Je hebt de rode kristallen sleutel opgepakt.,Du plukket opp den røde krystallnøkkelen.,Podniosł@[irreg_3_pl] Czerwony Kryształowy Klucz.,Você pegou a Chave de Cristal Vermelho.,Apanhaste a Chave de Cristal Vermelho.,Ai ridicat Cheia din Cristal Roșu.,Получен красный ключ-кристалл.,Покупио си кључ од црвеног кристала,Du plockade upp den röda kristallnyckeln.,Kırmızı Kristal Anahtarı aldın.,Взято червоний кристальний ключ. +You picked up the Blue Crystal Key.,TXT_BLUECRYSTAL,,,,Sebral@[ao_cs] jsi modrý krystalový klíč.,Du samlede den blå krystalnøgle op.,Du hast den blauen Kristallschlüssel genommen.,,Vi trovis la blukristalan ŝlosilon,Encuentras la llave de cristal azul.,,Poimit sinisen kristalliavaimen.,Vous avez pris la clé cristal bleu.,Felvetted a Kék Kristály Kulcsot.,Hai raccolto la chiave del Cristallo Blu.,青水晶のキー 取得。,청색 크리스탈 키를 획득했다.,Je hebt de blauwe kristallen sleutel opgepakt.,Du plukket opp den blå krystallnøkkelen.,Podniosł@[irreg_3_pl] Niebieski Kryształowy Klucz.,Você pegou a Chave de Cristal Azul.,Apanhaste a Chave de Cristal Azul.,Ai ridicat Cheia din Cristal Albastru.,Получен синий ключ-кристалл.,Покупио си кључ од плавог кристала,Du plockade upp den blå kristallnyckeln.,Mavi Kristal Anahtarı aldın.,Взято синій кристальний ключ. +You picked up the Chapel Key.,TXT_CHAPELKEY,,,,Sebral@[ao_cs] jsi klíč ke kapli.,Du samlede Kapel-nøglen op.,Du hast den Kapellenschlüssel genommen.,,Vi trovis la ŝlosilon de la kapelo.,Encuentras la llave de la capilla.,,Poimit kappelin avaimen.,Vous avez pris la clé de la chapelle.,Felvetted a Kápolna Kulcsát.,Hai raccolto la chiave della Cappella,チャペルキー 取得。,예배당 키를 획득했다.,Je hebt de kapelsleutel opgepakt.,Du plukket opp kapellnøkkelen.,Podniosł@[irreg_3_pl] Klucz do Kaplicy.,Você pegou a Chave da Capela.,Apanhaste a Chave da Capela.,Ai ridicat Cheia Capelei.,Получен ключ от часовни.,Покупио си кључ капеле,Du plockade upp kapellnyckeln.,Şapel Anahtarını aldın.,Взято ключ від каплиці. +You picked up the Catacomb Key.,TXT_CATACOMBKEY,,,,Sebral@[ao_cs] jsi klíč do katakomb.,Du samlede Katakombe-nøglen op.,Du hast den Katakombenschlüssel genommen.,,Vi havas la ŝlosilon de la katakombo.,Tienes la llave de las catacumbas.,,Poimit katakombin avaimen.,Vous avez pris la clé des catacombes.,Felvetted a Katakombák kulcsát.,Hai raccolto la chiave delle Catacombe.,カタコンベキー 取得。,고대 묘지 키를 획득했다.,Je hebt de catacombesleutel opgepakt.,Du plukket opp Katakomb-nøkkelen.,Podniosł@[irreg_3_pl] Klucz do Katakumb.,Você pegou a Chave da Catacumba.,Apanhaste a Chave da Catacumba.,Ai ridicat Cheia Catacombei.,Получен ключ от катакомб.,Покупио си кључ катакомбе,Du plockade upp katakomberna nyckeln.,Yeraltı Mezarı Anahtarını aldın.,Взято ключ від катакомб. +You picked up the Security Key.,TXT_SECURITYKEY,,,,Sebral@[ao_cs] jsi klíč ochranky.,Du samlede sikkerhedsnøglen op.,Du hast den Sicherheitsschlüssel genommen.,,Vi havas la sekureco-ŝlosilon.,Tienes la llave de seguridad.,,Poimit turvamiesavaimen.,Vous avez pris la clé de la sécurité.,Felvetted a Biztonsági Kulcsot.,Hai raccolto la chiave della Sicurezza.,警備のキー 取得。,보안 키를 획득했다.,Je hebt de beveiligingssleutel opgepakt.,Du plukket opp Sikkerhetsnøkkelen.,Podniosł@[irreg_3_pl] Klucz Ochrony.,Você pegou a Chave de Seguranca.,Apanhaste a Chave de Segurança,Ai ridicat Cheia Securității.,Получен ключ охраны.,Покупио си кључ обезбеђења,Du plockade upp säkerhetsnyckeln.,Güvenlik Anahtarını aldın.,Взято ключ охорони. +You picked up the Core Key.,TXT_COREKEY,,,,Sebral@[ao_cs] jsi klíč k jádru.,Du samlede reaktornøglen op.,Du hast den Reaktorschlüssel genommen.,,Vi trovis la ŝlosilon de la kernejo.,Encuentras la llave del núcleo.,,Poimit ytimen avaimen.,Vous avez pris la clé du réacteur.,Felvetted a Mag kulcsát.,Hai raccolto la chiave del Nucleo.,コアキー 取得。,중심부 키를 획득했다.,Je hebt de kernsleutel opgepakt.,Du plukket opp Kjernenøkkelen.,Podniosł@[irreg_3_pl] Klucz do Rdzenia.,Você pegou a Chave do Núcleo.,Apanhaste a Chave do Núcleo.,Ai ridicat Cheia Nucleului.,Получен ключ от реактора.,Покупио си кључ језгра,Du plockade upp kärnnyckeln.,Çekirdek Anahtarını aldın.,Взято ключ від реактора. +You picked up the Mauler Key.,TXT_MAULERKEY,,,,Sebral@[ao_cs] jsi klíč k trhačům.,Du samlede Mauler-nøglen op.,Du hast den Vernichterschlüssel genommen.,,Vi havas la ŝlosilon de la polvigiloj.,Tienes la llave de los trituradores.,,Poimit moukarin avaimen.,Vous avez pris la clé du Broyeur.,Felvetted a Marcangoló kulcsot.,Hai raccolto la chiave del Pestatore.,マウラーキー 取得。,마울러 키를 획득했다.,Je hebt de toetakelaarssleutel opgepakt.,Du plukket opp Mauler-nøkkelen.,Podniosł@[irreg_3_pl] Klucz do Magazynu Miażdżycieli.,Você pegou a Chave do Mauler.,Apanhaste a Chave do Mauler.,Ai ridicat Cheia Sfâșietorului.,Получен ключ истязателя.,Покупио си кључ Маулера.,Du plockade upp Mauler-nyckeln.,Mauler Anahtarını aldın.,Взято ключ розсіювача. +You picked up the Factory Key.,TXT_FACTORYKEY,,,,Sebral@[ao_cs] jsi klíč do továrny.,Du samlede fabriksnøglen op.,Du hast den Fabrikschlüssel genommen.,,Vi trovis la ŝlosilon de la fabriko.,Encuentras la llave de la fábrica.,,Poimit tehtaan avaimen.,Vous avez pris la clé de l'usine.,Felvetted a Gyár kulcsát.,Hai raccolto la chiave della Fabbrica.,工場のキー 取得。,공장 키를 획득했다.,Je hebt de fabriekssleutel opgepakt.,Du plukket opp fabrikknøkkelen.,Podniosł@[irreg_3_pl] Klucz do Fabryki.,Você pegou a Chave da Fábrica.,Apanhaste a Chave da Fábrica.,Ai ridicat Cheia Fabricii.,Получен ключ от фабрики.,Покупио си кључ фабрике,Du plockade upp fabriksnyckeln.,Fabrika Anahtarını aldın.,Взято ключ від фабрики. +You picked up the Mine Key.,TXT_MINEKEY,,,,Sebral@[ao_cs] jsi klíč do dolů.,Du samlede minenøglen op.,Du hast den Minenschlüssel genommen.,,Vi trovis la ŝlosilon de la minejo.,Encuentras la llave de la mina.,,Poimit kaivoksen avaimen.,Vous avez pris la clé de la mine.,Felvetted a Bánya kulcsát.,Hai raccolto la chiave della Miniera.,鉱山のキー 取得。,탄광 키를 획득했다.,Je hebt de mijnsleutel opgepakt.,Du plukket opp Gruvenøkkelen.,Podniosł@[irreg_3_pl] Klucz do Kopalni.,Você pegou a Chave da Mina.,Apanhaste a Chave da Mina.,Ai ridicat Cheia Minei.,Получен ключ от шахт.,Покупио си кључ рудника,Du plockade upp gruvnyckeln.,Maden Anahtarını aldın.,Взято ключ від шахт. +You picked up the New Key5.,TXT_NEWKEY5,,,,Sebral@[ao_cs] jsi nový klíč 5.,Du samlede den nye nøgle5 op.,Du hast den neuen Schlüssel 5 genommen.,,Vi havas la novan ŝlosilon kvin.,Tienes la llave nueva cinco.,,Poimit uuden 5-avaimen.,Vous avez pris la nouvelle clé 5.,Felvetted az 5. kulcsot.,Hai raccolto la Nuova Chiave n.5,ニューキー5 取得。,새로운 키5를 획득했다.,Je hebt de nieuwe sleutel 5 opgepakt.,Du plukket opp den nye nøkkelen5.,Podniosł@[irreg_3_pl] Nowy Klucz5,Você pegou a Chave Nova 5.,Apanhaste a Chave Nova 5.,Ai ridicat Cheia Nouă5.,Получен новый ключ №5.,Покупио си нови кључ5,Du hämtade den nya nyckeln5.,Yeni Anahtar5'i aldın.,Взято новий ключ 5. +You picked up the Oracle Pass.,TXT_ORACLEPASS,,,,Sebral@[ao_cs] jsi věštcovu propustku.,Du samlede orakelpas op.,Du hast den Orakelpass genommen.,,Vi havas la paspermeson de la Orakolo.,Tienes el pase del Oráculo.,,Poimit Oraakkelin passin.,Vous avez pris le passe de l'Oracle.,Felvetted az Orákulum Belépőkártyáját.,Hai raccolto il Lasciapassare dell'Oracolo.,オラクルパス 取得。,오라클의 통행증을 획득했다.,Je hebt de Orakelkaart opgepakt.,Du plukket opp Orakelpasset.,Podniosł@[irreg_3_pl] Przepustkę Wyroczni.,Você pegou o Passe do Oráculo.,Apanhaste o Passe do Oráculo.,Ai ridicat Legitimația Oracol.,Получен пропуск Оракула.,Покупио си пророкову пропусницу,Du plockade upp orakelpasset.,Kahin Geçiş Kartını aldın.,Взято пропуск Оракула. +You picked up the HE-Grenade Rounds.,TXT_HEGRENADES,,,,Sebral@[ao_cs] jsi výbušné granáty.,Du samlede HE-granaterne op.,Du hast die HE-Granaten genommen.,,Vi trovis eksplodeg-povajn grenadojn.,Encuentras granadas de conmoción.,,Poimit räjähdekranaattiammuksia.,Vous avez pris les Grenades Explosives.,Felvetted a robbanó gránátot.,Hai raccolto delle granate ad Alto Potenziale,HEグレネード弾 入手。,고폭 유탄을 획득했다.,Je hebt de HE-granaten opgepakt.,Du plukket opp HE-granaten.,Podniosł@[irreg_3_pl] Wiązkę Granatów.,Você pegou as Granadas Explosivas.,Apanhaste as Granadas Explosivas.,Ai ridicat Grenadele Explozive.,Получена связка гранат.,Покупио си ХЕ-Граната чауре,Du plockade upp HE-granaterna.,HE-Bombası Mermilerini aldın.,Взято в'язку гранат. +You picked up the Phosphorus-Grenade Rounds.,TXT_PHGRENADES,,,,Sebral@[ao_cs] jsi fosforové granáty.,Du samlede fosforgranaterne op.,Du hasr die Phosphorgranaten genommen.,,Vi trovis fosforajn grenadojn.,Encuentras granadas de fósforo.,,Poimit fosforikranaattiammuksia.,Vous avez pris les Grenades Phosphoriques.,Felvetted a foszfor-gránátokat.,Hai raccolto delle Granate al Fosforo.,白リングレネード弾 入手。,소이 유탄을 획득했다.,Je hebt de fosforgranaten opgepakt.,Du plukket opp fosforgranaten.,Podniosł@[irreg_3_pl] Wiązkę Fosforowych Granatów.,Você pegou as Granadas de Fósforo.,Apanhaste as Granadas de Fósforo.,Ai ridicat Grenadele cu Fosfor.,Получена связка фосфорных гранат.,Покупио си шаржер фосфорних граната.,Du plockade upp fosforgranater.,Fosforlu El Bombası Mermilerini aldın.,Взято в'язку фосфорних гранат. +You picked up the clip of bullets.,TXT_CLIPOFBULLETS,,,,Sebral@[ao_cs] jsi zásobník s náboji.,Du samlede patroner op.,Du hast die Gewehrmunition genommen.,Πήρες το κουτάκι με σφαίρες.,Vi trovis magazenon.,Encuentras un cargador.,,Poimit luotilippaan.,Vous avez pris le Chargeur.,Felvettél egy tár lőszert.,Hai raccolto un caricatore di proiettili.,銃弾倉 入手。,돌격소총 탄창을 획득했다.,Je hebt de patroon met kogels opgepakt.,Du plukket opp magasinet med kuler.,Podniosł@[irreg_3_pl] magazynek.,Você pegou o carregador.,Apanhaste o carregador.,Ai ridicat cartușul cu gloanțe.,Получена обойма.,,Du plockade upp ett magasin med kulor.,Mermi şarjörünü aldın.,Взято набійницю. +You picked up the box of bullets.,TXT_BOXOFBULLETS,,,,Sebral@[ao_cs] jsi krabici nábojů.,Du samlede kassen med kugler op.,Du hast die Munitionskiste genommen.,Πήρες το κουτί με σφαίρες.,Vi trovis munici-keston.,Encuentras una caja de municiones.,,Poimit luotilaatikon.,Vous avez pris la boîte de balles.,Felvettél egy doboz lőszert.,Hai raccolto una scatola di proiettili.,弾薬箱 入手。,돌격소총 탄약 박스를 획득했다.,Je hebt de doos met kogels opgepakt.,Du plukket opp esken med kuler.,Podniosł@[irreg_3_pl] pudło z amunicją.,Você pegou a caixa de balas.,Apanhaste a caixa de balas.,Ai ridicat cutia cu gloanțe.,Получена коробка пуль.,Покупио си кутију меткова,Du plockade upp lådan med kulor.,Mermi kutusunu aldın.,Взято коробку куль. +You picked up the mini missiles.,TXT_MINIMISSILES,,,,Sebral@[ao_cs] jsi minirakety.,Du samlede mini-missiler op.,Du hast die Miniraketen genommen.,Πήρες τους μινι-πυράυλους.,Vi trovis misiletojn.,Encuentras minimisiles.,,Poimit miniohjuksia.,Vous avez pris les mini-missiles.,Felvetted a minirakétákat.,Hai raccolto dei mini-missili.,ミニミサイル 入手。,미니 미사일 꾸러미를 획득했다.,Je hebt de mini-raketten opgepakt.,Du plukket opp minirakettene.,Podniosł@[irreg_3_pl] mini pociski.,Você pegou os mini-mísseis.,Apanhaste os mini-mísseis.,Ai ridicat mini proiectilele.,Получены мини-ракеты.,Покупио си мини ракете,Du plockade upp miniraketerna.,Mini füzeleri aldın.,Взято міні-ракети. +You picked up the crate of missiles.,TXT_CRATEOFMISSILES,,,,Sebral@[ao_cs] jsi bednu miniraket.,Du samlede kassen med missiler op.,Du hast die Miniraketenkiste genommen.,Πήρες το κιβώτιο με πυράυλους.,Vi trovis misilet-keston.,Encuentras una caja de minimisiles.,,Poimit ohjuslaatikon.,Vous avez pris la caisse de missiles.,Felvettél egy ládányi minirakétát.,Hai raccolto una cassa di missili.,ミサイルの箱 入手。,미니 미사일 박스를 획득했다.,Je hebt de kist met raketten opgepakt.,Du plukket opp kassen med missiler.,Podniosł@[irreg_3_pl] skrzynię z pociskami.,Você pegou a caixa de mísseis.,Apanhaste a caixa de mísseis.,Ai ridicat lada cu proiectile.,Получен ящик мини-ракет.,Покупио си кутију ракета,Du plockade upp lådan med missiler.,Füze sandığını aldın.,Взято ящик міні-ракети. +You picked up the energy pod.,TXT_ENERGYPOD,,,,Sebral@[ao_cs] jsi energetický kokón.,Du samlede energipoden op.,Du hast die Energiezelle genommen.,,Vi trovis energi-kapsulon.,Encuentras una cápsula de energía.,,Poimit energia-akun.,Vous avez pris la cellule d'énergie.,Felvettél egy energiahüvelyt.,Hai raccolto un nucleo energetico.,エネルギーポット 入手。,에너지 포드를 획득했다.,Je hebt de energiecel opgepakt.,Du plukket opp energikapselen.,Podniosł@[irreg_3_pl] kapsułę energii.,Você pegou a célula de energia (pequeno).,Apanhaste a célula de energia (pequeno).,Ai ridicat capsula cu energie.,Получена энергокапсула.,Покупио си енергетско постоље.,Du plockade upp energipodden.,Enerji kapsülünü aldın.,Взято енерго-капсулу. +You picked up the energy pack.,TXT_ENERGYPACK,,,,Sebral@[ao_cs] jsi energetický svazek.,Du samlede energipakken op.,Du hast das Energiepack genommen.,,Vi trovis pakon de energio.,Encuentras un paquete de energía.,,Poimit energiapaketin.,Vous avez pris le pack énergétique.,Felvetted az energiacsomagot.,Hai raccolto una carica energetica grande.,エネルギーパック 入手。,에너지 팩을 획득했다.,Je hebt het energiepak opgepakt.,Du plukket opp energipakken.,Podniosł@[irreg_3_pl] zasobnik energii.,Você pegou a célula de energia (grande).,Apanhaste a célula de energia (grande).,Ai ridicat pachetul cu energie.,Получен энергокомплект.,Покупио си пакет енергије,Du plockade upp energipaketet.,Enerji paketini aldın.,Взято енерго-батарею. +You picked up the poison bolts.,TXT_POISONBOLTS,,,,Sebral@[ao_cs] jsi otrávené šípy.,Du samlede giftboltene op.,Du hase die Giftbolzen genommen.,,Vi trovis venenajn sagojn.,Encuentras flechas envenenadas.,,Poimit myrkkynuolia.,Vous avez pris les carreaux empoisonnés.,Felvetted a mérgezett nyilakat.,Hai raccolto dei dardi velenosi.,ポイズンボルト 入手。,맹독 볼트를 획득했다.,Je hebt de gifbouten opgepakt.,Du plukket opp giftboltene.,Podniosł@[irreg_3_pl] zatrute bełty.,Você pegou as setas envenenadas.,Apanhaste as setas envenedadas.,Ai ridicat bolțurile cu otravă.,Получены отравленные болты.,Покупио си отровне стреле,Du plockade upp giftbultarna.,Zehirli cıvataları aldın.,Взято отруйні болти. +You picked up the electric bolts.,TXT_ELECTRICBOLTS,,,,Sebral@[ao_cs] jsi elektrické šípy.,Du samlede de elektriske bolte op.,Du hast die elektrischen Bolzen genommen.,,Vi trovis elektrajn sagojn.,Encuentras flechas eléctricas.,,Poimit sähkönuolia.,Vous avez pris les carreaux électriques.,Felvetted az elektromos nyilakat.,Hai raccolto dei dardi elettrici.,エレクトリックボルト 入手。,전격 볼트를 획득했다.,Je hebt de elektrische bouten opgepakt.,Du plukket opp de elektriske boltene.,Podniosł@[irreg_3_pl] elektryczne bełty.,Você pegou as setas eletricas.,Apanhaste as setas electricas.,Ai ridicat bolțurile cu electricitate.,Получены электрические болты.,Покупио си електричне стреле,Du plockade upp de elektriska bultarna.,Elektrikli cıvataları aldın.,Взято електричні болти. +You picked up the ammo satchel.,TXT_AMMOSATCHEL,,,,Sebral@[ao_cs] jsi brašnu na munici.,Du samlede ammunitionstasken op.,Du hast die Munitionstasche genommen.,,Vi trovis munici-sakon.,Encuentras un bolso de munición.,,Poimit ammuslaukun.,Vous avez pris la sacoche de munitions,Felvetted a lőszeres táskát.,Hai raccolto una Borsa delle Munizioni.,弾薬鞄 入手。,탄약 배낭을 획득했다.,Je hebt de munitietas opgepakt.,Du plukket opp ammunisjonsvesken.,Podniosł@[irreg_3_pl] torbę z amunicją.,Você pegou a mochila de munição.,Apanhaste a mochila de munição.,Ai ridicat sacoșa cu muniție.,Получен ранец боеприпасов.,Покупио си торбицу муниције,Du plockade upp ammunitionsväskan.,Cephane çantasını aldın.,Взято сумку для набоїв. +You have a feeling that it wasn't to be touched...,MSG_TALISMANRED,,,,"Máš pocit, že jsi na to sahat neměl@[ao_cs]...","Du har en fornemmelse af, at den ikke måtte røres...","Du hast das Gefühl, dass man es nicht anfassen sollte...",,"Vi sentas, ke vi ne devis tuŝi ĝin...",Tienes la sensación de que no debía ser tocado...,,"Sinusta tuntuu, ettei siihen olisi pitänyt koskea.",Vous avez un pressentiment qu'il ne fallait pas y toucher.....,Úgy érzed azt nem kéne megérinteni...,Hai la sensazione che non doveva essere toccato...,己の勘が 触れてはならない物だと訴えている...,"결코, 만지면 안 된다는 생각이 든다...",Je hebt het gevoel dat het niet aangeraakt dient te worden...,Du har en følelse av at den ikke skulle røres...,"Czujesz, że trzeba było tego nie dotykać...",Você tem um pressentimento de que isso não devia ser tocado...,Tens um pressentimento que não devias ter mexido nisso.,Ai sentimentul că nu trebuia atinsă...,"Кажется, эту вещь лучше не трогать...",Имаш осећај да није требало бити дирано...,Du har en känsla av att den inte fick röras...,İçinizde dokunulmaması gerektiğine dair bir his var.,"Ви відчуваєте, що не слід це чіпати..." +"Whatever it is, it doesn't belong in this world...",MSG_TALISMANGREEN,,,,"Je jedno, co to je, do tohoto světa to nepatří...","Uanset hvad det er, hører det ikke hjemme i denne verden...","Was auch immer es ist, es gehört nicht in diese Welt...","Οτιδήποτε είναι, δέν είναι απο αυτό τον κόσμο...","Tio ajn, kio ĝi estas, ĝi ne apartenas al ĉi tiu mondo...","Sea lo que sea, no pertenece a este mundo...",,"Mikä ikinä se onkaan, se ei kuulu tähän maailmaan...","Quel que soit cette chose, elle ne devrait pas être ici...","Bármi legyen ez, nem ebben a világban van a helye...","Qualunque cosa sia, non appartiene a questo mondo...",何であろうと、この世には属さない物だ...,뭔지는 몰라도 이 세상에 속한 것이 아닌 것 같다...,"Wat het ook is, het hoort niet thuis in deze wereld...","Uansett hva det er, hører det ikke hjemme i denne verden...","Cokolwiek to jest, nie należy to do tego świata...","Seja o que for, isso não pertence a este mundo...","O que quer que isso seja, não pertence a este mundo...","Orice ar fi, nu are ce căuta în lumea asta...","Что бы это ни было, оно не из этого мира...","Шта год да је, не припада овом свету...",Vad det än är så hör det inte hemma i den här världen...,"O her neyse, bu dünyaya ait değil.","Що б це не було, воно не належить цьому світу..." +It must do something...,MSG_TALISMANBLUE,,,,Něco to dělat musí...,Det må gøre noget...,Es muss etwas tun...,Πρέπει να κάνι κάτι...,Ĝi devas fari ion...,Debe hacer algo...,,Sen on pakko tehdä jotakin...,Ca doit servir a quelque chose...,Valamit kell hogy csináljon...,Deve fare qualcosa...,何かを成し遂げなければならない...,분명히 뭔가를 할 것이다...,Het moet iets doen....,Det må gjøre noe...,To musi coś robić...,Deveria fazer alguma coisa...,Devia fazer alguma coisa.,Trebuie să facă ceva...,Оно ведь зачем-то нужно?..,Мора урадити нешто...,Det måste göra något...,Bir şey yapmalı.,Воно повинно мати якесь призначення... +You have super strength!,MSG_TALISMANPOWER,,,,Získal@[ao_cs] jsi super sílu!,Du har superstyrke!,Du hast Superkräfte,,Vi havas superan forton!,¡Tienes superfuerza!,,Sinulla on supervoimat!,Vous avez une puissance inégalée!,Tied a Szuper Erő!,Hai la super forza!,豪剛なる力を得た!,엄청난 힘이 솟는다!,Je hebt superkracht!,Du har superkrefter!,Masz super siłę!,Você tem a super força!,Tu tens super força!,Ai super forță!,Вы получили сверхсилу!,Имаш супер снагу!,Du har superstyrka!,Süper gücün var!,Ви отримали суперсилу! +,,Locks,,,,,,,,,,,,,,,,,,,,,,,,,, +You don't have the key,TXT_NEEDKEY,,,,Nemáš klíč.,Du har ikke nøglen,Du hast den Schlüssel nicht,Δέν έχεις το κλειδί,Vi ne havas la ŝlosilon,No tienes la llave,,Sinulla ei ole avainta,Vous n'avez pas la clé.,Ehhez nincs kulcsod.,Non hai la chiave necessaria,キーを持っていない,필요한 열쇠가 없다,Je hebt de sleutel niet.,Du har ikke nøkkelen,Nie masz klucza,Você não tem a chave,Tu não tens a chave,Nu ai cheia,Нужен ключ,Немаш кључ,Du har inte nyckeln.,Anahtar sende değil.,У вас немає ключа +You need a passcard,TXT_NEED_PASSCARD,,,,Potřebuješ průkaz.,Du har brug for et adgangskort,Du brauchst eine Zugangskarte.,,Vi bezonas central-ŝlosilon,Necesitas la llave de la central,,Tarvitset avainkortin,Vous avez besoin du passe.,Belépőkártyára lesz szükséged.,Ti serve un lasciapassare,パスカード が必要だ,통행 카드가 필요하다,Je hebt een doorgangskaart nodig.,Du trenger et passerkort,Potrzebujesz karty dostępu,Você precisa de um cartão de acesso,Precisas de um cartão de acesso,Ai nevoie de un card de acces,Нужен пропуск,Треба ти пропусница,Du behöver ett passerkort.,Bir erişim kartına ihtiyacınız var,Потрібна карта доступу +You need a pass card key to open this door,TXT_NEED_PASSCARD_DOOR,,,,Pro otevření dveří potřebuješ průkaz.,Du skal bruge en adgangskort for at åbne denne dør,"Du brauchst eine Zugangskarte, um diese Tür zu öffnen.",,"Vi bezonas central-ŝlosilon +por malfermi tiun pordon","Necesitas una llave de la +central para abrir esta puerta",,Tarvitset avainkortin tämän oven avaamiseksi,Vous avez besoin du passe ouvrir cette porte.,Belépőkártya nélkül nem nyílik ez az ajtó.,Ti serve una tessera lasciapassare per aprire questa porta.,このドアには パスカード が必要だ,이 문을 열기 위해서는 통행 카드가 필요하다,Je hebt een doorgangskaart nodig om deze deur te openen.,Du trenger en passerkortnøkkel for å åpne denne døren.,Potrzebujesz karty dostępu aby otworzyć te drzwi,Você precisa de um cartão de acesso para abrir esta porta,Precisas de um cartão de acesso para abrir esta porta,"Ai nevoie de un card de acces ca să deschizi ușa +asta",Для открытия нужен пропуск,Треба ти пасош да отвориш ова врата,Du behöver ett passerkort för att öppna den här dörren.,Bu kapıyı açmak için bir erişim kartı anahtarına ihtiyacınız var,"Вам потрібна карта доступу, щоб відкрити ці двері" +You need an ID card,TXT_NEED_IDCARD,,,,Potřebuješ identifikační kartu.,Du skal bruge et ID-kort,Du brauchst einen Ausweis.,,Vi bezonas identigil-karton,"Necesitas una tarjeta +de identificación",,Tarvitset henkilökortin,Vous avez besoin d'une carte d'identité.,Igazolvány szükséges,Ti serve una tessera identificativa.,IDカード が必要だ,신분증이 필요하다,Je hebt een ID-kaart nodig.,Du trenger et ID-kort,Potrzebujesz karty identyfikacyjną,Você precisa do cartão de identificação,Precisas do cartão de identificação,Ai nevoie de un card de identitate,Нужна личная карта,Треба ти идентификациона картица,Du behöver ett ID-kort,Bir kimlik kartına ihtiyacınız var,Вам потрібна ідентифікаційна карта. +You don't have the key to the prison,TXT_NEED_PRISONKEY,,,,Nemáš klíč do vězení.,Du har ikke nøglen til fængslet,Du brauchst den Schlüssel zum Gefängnis,,"Vi ne havas la ŝlosilon +de la malliberejo",No tienes la llave a la prisión,,Sinulla ei ole vankilan avainta,Vous n'avez pas la clé de la prison.,Nincs kulcsod a börtönhöz.,Ti manca la chiave per la prigione,刑務所のキーを持っていない,감옥에 입장하기 위한 열쇠가 없다,Je hebt de sleutel van de gevangenis niet.,Du har ikke nøkkelen til fengselet.,Nie masz klucza do więzienia,Você não tem a chave da prisão,Não tens a chave da prisão,Nu ai cheia închisorii,Нужен ключ от тюрьмы,Треба ти кључ затвора,Du har inte nyckeln till fängelset.,Hapishanenin anahtarı sende değil.,У вас немає ключа від в'язниці. +Hand print not on file,TXT_NEED_HANDPRINT,,,,Otisk ruky není v databázi.,Håndaftryk er ikke registreret,Handabdruck nicht gespeichert!,,Neregistrita manspuro,Huella de la mano no registrada,,Kädenjälki puuttuu tiedostosta,Votre main n'est pas reconnue par le scanner.,Azonosítatlan kézlenyomat.,Impronta digitale non in archivio,手形認証が一致しません,알 수 없는 지문입니다,Handafdruk niet in het bestand.,Håndavtrykk finnes ikke i filen,Brak odcisku dłoni w bazie danych,Biometria não autorizada,Impressão digital não autorizada,Amprenta mâinii nerecunoscută,Отпечаток руки не распознан,Отисак длана није у записнику,Handavtryck finns inte i registret,El izi dosyada yok,Відбиток руки не упізнано +You need the Gold Key,TXT_NEED_GOLDKEY,,,,Potřebuješ zlatý klíč.,Du har brug for guldnøglen,Du brauchst den goldenen Schlüssel,,Vi bezonas la oran ŝlosilon,Necesitas la llave dorada,,Tarvitset kulta-avaimen,Vous avez besoin d'une clé d'or.,Aranykulcs szükséges.,Ti serve la chiave dorata,ゴールドキーが必要だ,황금 키가 필요하다,Je hebt de gouden sleutel nodig.,Du trenger gullnøkkelen,Potrzebujesz Złotego Klucza,Você precisa da Chave de Ouro,Precisas da Chave de Ouro,Ai nevoie de cheia din Aur,Нужен золотой ключ,Треба ти златни кључ,Du behöver guldnyckeln,Altın Anahtara ihtiyacınız var,Вам потрібен золотий ключ +You need an ID Badge,TXT_NEED_IDBADGE,,,,Potřebuješ identifikační odznak.,Du har brug for et ID-badge,Du brauchst eine Identitätskarte.,,Vi bezonas malliberejan insignon,"Necesitas una insignia +de la prisión",,Tarvitset henkilötunnisteen,Vous avez besoin d'un badge d'identification.,Azonosító jelvény szükséges.,Ti serve un distintivo di identificazione,IDバッジが必要だ,신분 휘장이 필요하다,Je hebt een ID-badge nodig.,Du trenger en ID-badge,Potrzebujesz Odznaki Identyfikacyjnej,Você precisa do Crachá de Identificação,Precisas do Crachá de Identificação,Ai nevoie de un ecuson de identificare,Нужна личная карта,Треба ти лична карта,Du behöver ett ID-bricka,Bir Kimlik Rozetine ihtiyacınız var,Вам потрібен бейджик +You need an ID Badge to open this door,TXT_NEED_IDBADGE_DOOR,,,,Pro otevření dveří potřebuješ identifikační odznak.,Du har brug for et ID Badge for at åbne denne dør,"Du brauchst eine Identitätskarte, um diese Tür zu öffnen.",,"Vi bezonas malliberejan insignon +por malfermi ĉi tiun pordon","Necesitas una insignia de la +prisión para abrir esta puerta",,Tarvitset henkilötunnisteen tämän oven avaamiseksi,Vous avez besoin d'un badge d'identification pour ouvrir cette porte.,Azonosító jelvény szükséges az ajtó kinyitásához.,Ti serve un distintivo di identificazione per superare questa porta,このドアには IDバッジ が必要だ,이 문을 열기 위해서는 신분 휘장이 필요하다,Je hebt een ID-badge nodig om deze deur te openen.,Du trenger en ID-badge for å åpne denne døren,Potrzebujesz Odznaki Identyfikacyjnej aby otworzyć te drzwi,Você precisa do Crachá de Identificação para abrir a porta,Precisas do Crachá de Identificação para abrir a porta,"Ai nevoie de un ecuson de identificare ca să +deschizi ușa",Для открытия нужна личная карта,Треба ти лична карта да отвориш ова врата,Du behöver en ID-bricka för att öppna den här dörren.,Bu kapıyı açmak için kimlik kartına ihtiyacınız var,"Вам потрібен бейджик, щоб відкрити ці двері" +You need the Silver Key,TXT_NEED_SILVERKEY,,,,Potřebuješ stříbrný klíč.,Du skal bruge sølvnøglen,Du brauchst den Silberschlüssel,,Vi bezonas la arĝentan ŝlosilon,Necesitas la llave plateada,,Tarvitset hopea-avaimen,Vous avez besoin de la clé en argent.,Az ezüstkulcs szükséges.,Ti serve la chiave argentata,シルバーキーが必要だ,은 키가 필요하다,Je hebt de zilveren sleutel nodig.,Du trenger sølvnøkkelen,Potrzebujesz Srebrnego Klucza,Você precisa da Chave de Prata,Precisas da Chavede Prata,Ai nevoie de cheia din Argint,Нужен серебряный ключ,Треба ти сребрни кључ,Du behöver silvernyckeln,Gümüş Anahtara ihtiyacın var,Вам потрібен срібний ключ +You need the Brass Key,TXT_NEED_BRASSKEY,,,,Potřebuješ mosazný klíč.,Du skal bruge messingnøglen,Du brauchst den Messingschlüssel,,Vi bezonas la latunan ŝlosilon,Necesitas la llave de latón,,Tarvitset messinkiavaimen,Vous avez besoin de la clé en bronze.,A rézkulcs szükséges.,Ti serve la chiave d'ottone,ブラスキーが必要だ,황동 키가 필요하다,Je hebt de messing sleutel nodig.,Du trenger messingnøkkelen,Potrzebujesz Mosiężnego Klucza,Você precisa da Chave de Latão,Precisas da Chave de Latão,Ai nevoie de cheia din Alamă,Нужен латунный ключ,Треба ти кључ од месинга,Du behöver mässingsnyckeln,Pirinç Anahtara ihtiyacın var,Вам потрібен латунний ключ +You need the Red Crystal,TXT_NEED_REDCRYSTAL,,,,Potřebuješ červený krystal.,Du skal bruge den røde krystal,Du brauchst den roten Kristall,,Vi bezonas la ruĝan kristalon,Necesitas el cristal rojo,,Tarvitset punaisen kristallin,Vous avez besoin du cristal rouge.,A vörös kristályra lesz szükség itt.,Ti serve il Cristallo Rosso,赤水晶のキーが必要だ,적색 크리스탈이 필요하다,Je hebt de rode kristallen sleutel nodig.,Du trenger den røde krystallen,Potrzebujesz Czerwonego Kryształu,Você precisa do Cristal Vermelho,Precisas do Cristal Vermelho,Ai nevoie de Cristalul Roșu,Нужен красный кристалл,Треба ти црвени кристал,Du behöver den röda kristallen,Kırmızı Kristal'e ihtiyacın var.,Вам потрібен червоний кристальний ключ +You need the Blue Crystal,TXT_NEED_BLUECRYSTAL,,,,Potřebuješ modrý krystal.,Du skal bruge den blå krystal,Du brauchst den blauen Kristall,,Vi bezonas la bluan kristalon,Necesitas el cristal azul,,Tarvitset sinisen kristallin,Vous avez besoin du cristal bleu.,A kék kristályra lesz szükség itt.,Ti serve il Cristallo Blu,青水晶のキーが必要だ,청색 크리스탈이 필요하다,Je hebt de blauwe kristallen sleutel nodig.,Du trenger den blå krystallen,Potrzebujesz Niebieskiego Kryształu,Você precisa do Cristal Azul,Precisas do Cristal Azul,Ai nevoie de Cristalul Albastru,Нужен синий кристалл,Треба ти плави кристал,Du behöver den blå kristallen,Mavi Kristal'e ihtiyacın var.,Вам потрібен синій кристальний ключ +This area is only available in the retail version of Strife,TXT_RETAIL_ONLY,,,,Tato oblast je dostupná pouze v registrované verzi.,Dette område er kun tilgængeligt i detailudgaven af Strife,Dieser Bereich ist nur in der kompletten Version von Strife erreichbar.,Αυτή η περιοχή είναι μονο διαθέσημη στήν εγραμμένη έκδοση του Strife,"Ĉi tiu loko estas enirebla nur +en la komercaĵa versio de Strife","Esta área solo está disponible +en la versión completa de Strife",,Tämä alue on saatavilla ainoastaan Strifen kokoversiossa,Cette zone n'est accessible que dans la version complète de Strife.,Ez a terület kizárólag a Strife teljes verziójában érhető el,Quest'area è disponibile solo nella versione completa di Strife.,このエリアは Strifeの製品版でのみ利用可能です,이 구역은 정품 버전에서만 입장이 가능합니다,Deze ruimte is alleen beschikbaar in de verkoopversie van Strife.,Dette området er bare tilgjengelig i salgsversjonen av Strife.,Ten obszar jest dostępny tylko w pełnej wersji Strife,Essa área está disponível apenas na versão registrada de Strife,,"Această zonă e disponibilă doar în versiunea +cumpărată a jocului Strife",Эта локация доступна только в полной версии Strife,Ова област је само доступна у пуној верзији Strife-а,Det här området finns bara i detaljhandelsversionen av Strife.,Bu alan yalnızca Strife'ın perakende sürümünde mevcuttur,Ця локація доступна тільки у повній версії Strife +That doesn't seem to work,TXT_DOES_NOT_WORK,,,,Takhle to nepůjde.,Det ser ikke ud til at virke,Das scheint nicht zu funktionieren,,Tio ŝajne ne funkcias,Parece que eso no funciona,,Se ei näytä toimivan,Cela ne semble pas fonctionner.,Ez nem akar működni.,Non sembra funzionare,それは作動していない,작동이 안 되는 것 같다,Dat lijkt niet te werken.,Det ser ikke ut til å virke,To zdaje się nie działać,Parece que isso não funciona,,Nu pare să funcționeze,"Похоже, что не работает",То изгледа да не ради,Det verkar inte fungera.,Bu işe yaramıyor gibi görünüyor.,"Здається, воно не працює" +You need the chalice!,TXT_NEED_CHALICE,,,,Potřebuješ kalich!,Du skal bruge bægeret!,Du brauchst den Kelch!,,Vi bezonas la kalikon!,¡Necesitas el Cáliz!,,Tarvitset maljan!,Vous avez besoin du calice!,A Kupára van szükséged!,Hai bisogno del calice.,聖杯が必要だ!,성배가 필요하다!,Je hebt de beker nodig!,Du trenger begeret!,Potrzebujesz kielicha!,Você precisa do cálice!,Precisas do cálice!,Ai nevoie de potir!,Нужна чаша!,Треба ти пехар!,Du behöver kalken!,Kadehe ihtiyacın var!,Вам потрібна чаша! +You need the Oracle Pass!,TXT_NEED_OPASS,,,,Potřebuješ propustku od věštce!,Du har brug for orakelpas!,Du brauchst den Orakelpass!,,"Vi bezonas la paspermeson +de la Orakolo!",¡Necesitas el pase del Oráculo!,,Tarvitset Oraakkelin passin,Vous avez besoin du passe Oracle!,Az Orákulum Engedélyére van szükséged!,Hai bisogno del pass dell'Oracolo.,オラクルパスが必要だ!,오라클 통행증이 필요하다!,Je hebt de Orakelpas nodig!,Du trenger Orakelpasset!,Potrzebujesz Przepustki Wyroczni!,Você precisa do Passe do Oráculo!,Precisas do Passe do Oráculo!,Ai nevoie de legitimația Oracol!,Нужен пропуск Оракула!,Треба ти Пророкова пропусница!,Du behöver Orakelpasset!,Kahin Kartı'na ihtiyacın var!,Вам потрібен пропуск Оракула! +,,Actor tags,,,,,,,,,,,,,,,,,,,,,,,,,, +Dagger,TAG_PUNCHDAGGER,,,,Dýka,Dolk,Dolch,Μαχάιρι,Ponardo,Daga,,Tikari,Dague de Poing,Tőr,Pugnale,ダガー,단검,Dolk,Dolk,Sztylet,Punhal,,Pumnal,Кинжал,Бодеж,Dolk,Hançer,Кинжал +Crossbow,TAG_STRIFECROSSBOW1,Crossbow with electric bolts,,,Kuše,Armbrøst,Armbrust,Τόξο (Δηλητήριο),Arbalesto (elektraj sagoj),Ballesta (eléctrica),,Jousipyssy,Arbalète Electrique,Nyílpuska,Balestra ,クロスボウ,석궁 (전격),Kruisboog,Armbrøst,Kusza,Besta,,Arbaletă,Арбалет,Самострел,Armborst,Arbalet,Арбалет +Crossbow,TAG_STRIFECROSSBOW2,Crossbow with poison bolts,,,Kuše,Armbrøst,Armbrust,Τόξο (Ηλεκτρικό),Arbalesto (venenaj sagoj),Ballesta (veneno),,Jousipyssy,Arbalète Empoisonée,Nyílpuska,Balestra ,クロスボウ,석궁 (맹독),Kruisboog,Armbrøst,Kusza,Besta,,Arbaletă,Арбалет,Самострел,Armborst,Arbalet,Арбалет +Assault Gun,TAG_ASSAULTGUN,,,,Útočná puška,Angrebsvåben,Sturmgewehr,,Sturmofusilo,Fusil de asalto,,Rynnäkkökivääri,Fusil d'Assaut,Gépfegyver,Fucile d'Assalto ,アサルトガン,돌격소총,Aanvalswapen,Stormgevær,Karabin Szturmowy,Fuzil de Assalto,Arma de Assalto,Pușcă de Asalt,Штурмовая винтовка,Аутоматска пушка,Anfallspistol,Saldırı Silahı,Штурмова гвинтівка +Mini Missile Launcher,TAG_MMLAUNCHER,,,,Miniraketomet,Mini-missilkaster,Miniraketenwerfer,Μίνι-Πυραυλοβόλο,Misilet-pafilo,Minilanzamisiles,,Miniohjuslaukaisin,Lanceur de Mini-Missiles,Mini Rakétavető,Mini-Lanciamissili,ミニミサイルランチャー,미니 미사일 런쳐,Miniraketwerper,Mini rakettkaster,Wyrzutnia Minipocisków,Mini Lança-mísseis,,Mini Lansator de Proiectile,Мини-гранатомёт,Мини ракетни бацач,Mini missilkastare,Mini Füze Fırlatıcı,Міні-ракетниця +Flame Thrower,TAG_FLAMER,,,,Plamenomet,Flammekaster,Flammenwerfer,,Flamĵetilo,Lanzallamas,,Liekinheitin,Lance-Flammes,Lángszóró,Lanciafiamme ,火炎放射器,화염방사기,Vlammenwerper,Flammekaster,Miotacz Ognia,Lança-chamas,,Aruncător de Flăcări,Огнемёт,Бацеч пламена,Flamkastare,Alev Fırlatıcı,Вогнемет +Mauler,TAG_MAULER1,,,,Trhač,,Vernichter,,Polvigilo (normala),Triturador (dispersión),,Moukari,Broyeur,Marcangoló,Pestatore ,マウラー,마울러 (저출력),Toetakelaar,,Miażdżyciel,Desintegrador,,Sfâșietor,Истязатель,Маулер,,Parçalayıcı,Розсіювач +Mauler,TAG_MAULER2,,,,Trhač,,Vernichter,,Polvigilo (fortega),Triturador (torpedo),,Moukari,Broyeur,Marcangoló,Pestatore,マウラー,마울러 (고출력),Toetakelaar,,Miażdżyciel,Desintegrador,,Sfâșietor,Истязатель,Маулер,,Parçalayıcı,Розсіювач +Grenade Launcher,TAG_GLAUNCHER1,High-explosive grenade launcher,,,Granátomet,Granatkaster,Granatwerfer,,Grenadĵetilo (eksplodeg-pova),Lanzagranadas (conmoción),,Kranaatinheitin,Lance-Grenades Explosif,Gránátvető,Lanciagranate,グレネードランチャー,유탄발사기 (고폭탄),Granaatwerper,Granatkaster,Wyrzutnia Granatów,Lança-granadas,,Lansator de Grenade,Гранатомёт,Бацач граната,Granatkastare,El Bombası Fırlatıcı,Гранатомет +Grenade Launcher,TAG_GLAUNCHER2,White phosphorous grenade launcher ,,,Granátomet,Granatkaster,Granatwerfer,,Grenadĵetilo (fosfora),Lanzagranadas (fósforo),,Kranaatinheitin,Lance-Grenades Incendiaire,Gránátvető,Lanciagranate,グレネードランチャー,유탄발사기 (소이탄),Granaatwerper,Granatkaster,Wyrzutnia Granatów,Lança-granadas,,Lansator de Grenade,Гранатомёт,Бацач граната,Granatkastare,El Bombası Fırlatıcı,Гранатомет +Sigil,TAG_SIGIL,,,,Pečeť,,,,Sigelo,Emblema,,Sinetti,,Pecsét,Sigillo,シジル,시질,,,Pieczęć,Sigilo,,Sigiliu,Печать,Сигил,,,Сигіл +Coin,TAG_COIN,,,,Mince,Mønt,Münze,,Monero,Moneda,,Kolikko,Pièce,Érme,Moneta,コイン,동전,Munt,Mynt,Moneta,Moeda(s),,Monedă,Монета,Новчић,Mynt,Madeni Para,Монета +Med patch,TAG_MEDPATCH,,,,Obvazy,Medicinsk bandage,Medizinische Bandage,,Kuracbendoj,Tiritas,Curitas,Sidekääre,Pansement,Ragtapasz,Bende,医薬パッチ,의료 붕대,Med-patch,Medisinsk lapp,Bandaż,Compressa médica,,Trusă de Prim-Ajutor,Бинт,Прва помоћ,Medicinska plåster,Med yama,Оклюзійна пов'язка +Medical kit,TAG_MEDICALKIT,,,,Lékárnička,Medicinsk kit,Verbandskasten,,Sukurkesto,Botiquín,,Lääkintälaukku,Kit Médical,Orvosi Készlet,Kit di Pronto Soccorso ,医療キット,구급 키트,Medicijndoos,Medisinsk sett,Apteczka,Kit médico,,Kit de Prim-Ajutor,Аптечка,Медицински прибор,Medicinsk utrustning,Tıbbi kit,Індивідуальна аптечка +Surgery Kit,TAG_SURGERYKIT,,,,Chirurgická souprava,Kirurgisæt,Erste-Hilfe-Kasten,,Kirurgia kesto,Kit quirúrgico,,Kirurgilaukku,Kit de Chirurgie,Sebészeti Készlet,Kit Chirurgico ,手術キット,수술 키트,Chirurgiepakket,Kirurgisk sett,Zestaw Chirurga,Kit de Cirurgia,,Kit pentru Operații,Медкомплект,Хируршки прибор,Kirurgiskt kit,Ameliyat Kiti,Медичний кейс +Ring,TAG_BELDINSRING,,,,Prsten,,,,Ringo,Anillo,,Sormus,Anneau,Gyűrű,Anello ,指輪,반지,,,Pierścień,Anel,,Inel,Кольцо,Прстен,,Yüzük,Каблучка +Offering Chalice,TAG_OFFERINGCHALICE,,,,Obětní kalich,Offerkalk,Opferkelch,,Oferdona kaliko,Cáliz de ofrenda,,Uhrimalja,Calice d'Obole,Áldozati kehely,Calice delle Offerte,寄贈された聖杯,번제 성배,Offerbeker,Offerbeger,Kielich Ofiarny,Calice de Oferenda,,Potir pentru Ofrande,Чаша для подношений,Жртвени пехар,Offertkalke,Adak Kadehi,Чаша для жертвоприношення +Ear,TAG_EAR,,,,Ucho,Øre,Ohr,,Orelo,Oreja,,Korva,Oreille,Fül,Orecchio,耳,귀,Oor,Øre,Ucho,Orelha,,Ureche,Ухо,Уво,Öra,Kulak,Вухо +Broken Power Coupling,TAG_BROKENCOUPLING,,,,Rozbitá spojka,Brækket strømkobling,Defekter Stromabnehmer,,Rompita energia kuplilo,Acoplador de energía roto,,Rikkinäinen virtaliitin,Coupleur Energétique cassé,Elromlott Tápcsatlakozó,Coppia Energetica Rotta ,壊れたパワーカップリング,망가진 동력선,Gebroken stroomkoppeling,Ødelagt kraftkobling,Zepsute Obwody Zasilające,Acoplador de Energia Quebrado,Acoplador de Energia Partido,Cuplaj de Putere Defect,Повреждённая муфта,Неисправна спојница напајања,Trasig kraftkoppling,Kırık Güç Kaplini,Зламана силова муфта +Shadow Armor,TAG_SHADOWARMOR,,,Shadow Armour,Stínové brnění,Skygge rustning,Schattenrüstung,,Ombra armaĵo,Armadura de sombra,,Varjohaarniska,Armure de l'Ombre,Sötét Páncél,Armatura Ombra ,シャドウアーマー,그림자 갑옷,Schaduwharnas,Skygge rustning,Cienisty Pancerz,Armadura das Sombras,,Armura Umbrei,Теневая броня,Оклоп сенки,Skuggarmering,Gölge Zırhı,Тіньова броня +Environmental Suit,TAG_ENVSUIT,,,,Ochranný oblek,Miljømæssig dragt,Schutzanzug,,Medi-ŝirma vesto,Traje NBQ,,Ympäristösuojapuku,Combinaison Hazmat,Védőöltözet,Tuta Ambientale ,耐環境スーツ,환경 방호복,Beschermend pak,Miljødrakt,Skafander Ochronny,Traje de Proteção,Fato Protetor,Costum de Protecție,Защитный костюм,Заштитно одело,Miljödräkt,Çevresel Takım,Захисний костюм +Guard Uniform,TAG_GUARDUNIFORM,,,,Hlídačova uniforma,Gardeuniform,Wächteruniform,,Gardista uniformo,Uniforme de guardia,,Vartijan univormu,Uniforme de Garde,Őr Egyenruha,Uniforme da Guardia,ガードの制服,경비 전투복,Wachtersuniform,Vaktuniform,Mundur Strażnika,Uniforme de Guarda,,Uniformă de Paznic,Униформа стражника,Стражарска униформа,Skyddsuniform,Bekçi Üniforması,Уніформа охоронця +Officer's Uniform,TAG_OFFICERSUNIFORM,,,,Důstojníkova uniforma,Officersuniform,Offiziersuniform,,Oficira uniformo,Uniforme de oficial,,Upseerin univormu,Uniforme d'Officier,Tiszti Egyenruha,Uniforme da Ufficiale ,士官の制服,장교 전투복,Officiersuniform,Offisersuniform,Mundur Oficera,Uniforme de Oficial,,Uniformă de Ofițer,Офицерская униформа,Официрска униформа,Officersuniform,Memur Üniforması,Уніформа офіцера +Flame Thrower Parts,TAG_FTHROWERPARTS,,,,Díly plamenometu,Dele til flammekasteren,Flammenwerferteile,,Partoj de flamjetilo,Partes de lanzallamas,,Liekinheittimen osat,Pièces de Lance-Flamme,Lángszóró Alkatrészek,Parti di Lanciafiamme ,火炎放射器の部品,화염방사기 부품,Vlammenwerperonderdelen,Deler til flammekaster,Części Miotacza Ognia,Partes do lança-chamas,,Bucăți de Aruncător de Flăcări,Детали огнемёта,Делови бацача пламена,Delar till flamkastaren,Alev Püskürtücü Parçaları,Деталі для вогнемету +Report,TAG_REPORT,,,,Hlášení,Rapport,,,Raporto,Reporte,,Raportti,Compte-rendu,Jelentés,Rapporto ,報告書,보고서,Verslag,Rapport,Raport,Relatório,,Raport,Отчёт,Извештај,Rapportera,Rapor,Звіт +Info,TAG_INFO,,,,Informace,,,,Informoj,Información,,Tiedot,,Információ,Informazioni ,情報,정보,,Informasjon,Informacje,Informação,,Informație,Сводка,Инфо,,Bilgi,Дані +Targeter,TAG_TARGETER,,,,Zaměřovač,,Zielhilfe,,Celilo,Mira de arma,,Tähtäinlaite,Cibleur,Célzó eszköz,Puntatore,照準器,조준기,Richter,,Namierzacz,Mira,,Țintitor,Целеуказатель,Нишанџија,,Hedefleme cihazı,Цілевказівник +Communicator,TAG_COMMUNICATOR,,,,Komunikátor,Kommunikator,Kommunikator,,Interfono,Intercomunicador,,Viestintälaite,Communicateur,Kommunikátor,Comunicatore ,コミュニケーター,연락장치,,Kommunikator,Komunikator,Comunicador,,Comunicator,Передатчик,Комуникатор,Kommunikator,İletişimci,Комунікатор +Degnin Ore,TAG_DEGNINORE,,,,Degninská ruda,Degnin malm,Degnin-Erz,,Degnina minaĵo,Mineral de Degnin,,Degnin-malmi,Minerai de Degnin,Degnin Érc,Minerale Degnin,デグニン鉱石,데그닌 광석,Degnin-erts,Degnin malm,Ruda Degninu,Minério Degnin,,Minereu de Degnir,Денгинская руда,Дегнинска руда,Degnin Malm,Degnin Cevheri,Дегінська руда +Accuracy,TAG_GUNTRAINING,,,,Přesnost,Nøjagtighed,Präzision,,Akurateco,Precisión,,Tarkkuus,Précision,Pontosság,Precisione,精度,정확도,Nauwkeurigheid,Nøyaktighet,Precyzja,Precisão,,Acuratețe,Меткость,Прецизност,Noggrannhet,Doğruluk,Точність +Toughness,TAG_HEALTHTRAINING,,,,Tvrdost,Robusthed,Ausdauer,,Forteco,Dureza,,Sitkeys,Endurance,Kitartás,Robustezza ,タフネス,힘,Stevigheid,Seighet,Wytrzymałość,Força,,Rezistență,Живучесть,Издржљивост,Seghet,Sertlik,Стійкість +Scanner,TAG_SCANNER,,,,Skener,,,,Skanilo,Escáner,,Skanneri,Analyseur,Szkenner,Scanner,スキャナー,탐지기,Scanner,Skanner,Skaner,Scanner,,Scanner,Сканер,Скенер,Scanner,Tarayıcı,Сканер +Prison Pass,TAG_PRISONPASS,,,,Propustka do vězení,Fængselspas,Gefängnispass,,Mallibereja pasilo,Pase a la prisión,,Vankilan pääsylupa,Passe de la Prison,Börtön Engedély,Lasciapassare Prigione ,刑務所の許可証,감옥 통행증,Gevangenispas,Fengselspass,Przepustka do Więzienia,Passe da Prisão,,Legitimația pentru Închisoare,Пропуск в тюрьму,Затворска пропусница,Fängelsepass,Hapishane Kartı,Тюремний пропуск +Alarm,TAG_ALARM,,,,,,,,Alarmo,Alarma,,Hälytys,Alarme,Riasztó,Allarme ,警報,알람,,,,Alarme,,Alarmă,Тревога,Аларм,Larm,,Тривога +Ammo,TAG_AMMOFILLUP,,,,Munice,Munition,Munition,,Municio,Munición,,Ammukset,Munitions,Lőszer,Munizioni ,弾薬,탄약,Munitie,Ammunisjon,Amunicja,Munição,,Muniție,Боеприпасы,Муниција,Ammunition,Cephane,Набої +Health,TAG_HEALTHFILLUP,,,,Zdraví,Sundhed,Gesundheit,,Sano,Salud,,Terveys,Santé,Életerő,Salute ,体力,체력,Gezondheid,Helse,Zdrowie,Saúde,,Sănătate,Здоровье,Живот,Hälsa,Sağlık,Здоров'я +Teleporter Beacon,TAG_TELEPORTERBEACON,,,,Teleportační maják,Teleportør-bakke,Teleportersignal,,Teleportil-signalilo,Baliza de teletransporte,,Kaukosiirrinmajakka,Balise de téléportation,Teleport Vészfény,Radiofaro per Teletrasporto ,テレポータービーコン,텔레포터 비콘,Teleporterbaken,Teleporter Beacon,Nadajnik Teleportera,Sinalizador para Teletransporte,,Lumină pentru Teleportor,Телепортационный маяк,Одашиљач за телепортовање,Teleporterfyr,Işınlayıcı İşaretçisi,Пристрій телепортації +Metal Armor,TAG_METALARMOR,,,Metal Armour,Kovové brnění,Metal rustning,Metallrüstung,,Metala armaĵo,Armadura de metal,,Metallihaarniska,Armure en Métal,Fém Páncél,Armatura di Metallo ,メタルアーマー,강철 갑옷,Metalen harnas,Metall rustning,Metalowy Pancerz,Armadura de Metal,,Armură din Metal,Металлическая броня,Метални оклоп,Metall rustning,Metal Zırh,Металічна броня +Leather Armor,TAG_LEATHER,,,Leather Armour,Kožené brnění,Læderpanser,Lederrüstung,,Leda armaĵo,Armadura de cuero,,Nahkasuojus,Armure en Cuir,Bőr Páncél,Armatura di Cuoio,レザーアーマー,가죽 갑옷,Leren harnas,Lær rustning,Skórzany Pancerz,Armadura de Couro,,Armură din Piele,Кожаная броня,Кожни оклоп,Läderrustning,Deri Zırh,Шкіряна броня +HE-Grenade Rounds,TAG_HEGRENADES,,,,Výbušné granáty,HE-granater,HE-Granaten,,Eksplodeg-povaj grenadoj,Granadas de conmoción,,Räjähdekranaatit,Grenades Explosives,Gránát Lőszer,Granata HE,HEグレネード弾,고폭 유탄,HE-granaten,HE-Granater,Wiązka Granatów,Munição - Granadas Explosivas,,Grenade Explozive,Осколочные гранаты,Хе-Граната чауре,HE-granater,HE-Bomba Mermileri,В'язка гранат +Phosphorus-Grenade Rounds,TAG_PHGRENADES,,,,Fosforové granáty,Fosforgranater,Phosphorgranaten,,Fosforaj grenadoj,Granadas de fósforo,,Fosforikranaatit,Grenades Incendiaires,Foszfor-Gránát Lőszer,Granata al Fosforo ,白リングレネード弾,소이 유탄,Fosforgranaten,Fosforgranater,Wiązka Fosforowych Granatów,Municão - Granadas de Fósforo,,Grenade cu Fosfor,Фосфорные гранаты,Фосфорне гранате,Fosforgranater,Fosforlu El Bombası Mermileri,В'язка фосфорних гранат. +Clip of Bullets,TAG_CLIPOFBULLETS,,,,Zásobník s náboji,Kugleklip,Gewehrmunition,,Magazeno,Cargador de balas,,Luotilipas,Chargeur d'Assaut,Golyó töltények,Caricatore di Proiettili ,弾丸のクリップ,소총 탄창,Patroon kogels,Klipp av kuler,Magazynek,Carregador de Balas,,Cartuș cu Gloanțe,Обойма,Клип метака,Kulor i klipp,Kurşun Klipsi,Набійниця +Ammo,TAG_BOXOFBULLETS,,,,Krabice nábojů,Munition,Munitionskiste,,Munici-kesto,Caja de municiones,,Luotilaatikko,Bôite de Munitions,Lőszer,Munizioni ,弾薬箱,탄약,Munitie,Ammunisjon,Amunicja,Caixa de Balas,,Muniție,Боеприпасы,Муниција,Ammunition,Cephane,Набої +Mini Missiles,TAG_MINIMISSILES,,,,Minirakety,Mini missiler,Miniraketen,,Misiletoj,Minimisiles,,Miniohjukset,Mini-Missiles,Mini Rakéták,Mini-Missili,ミニミサイル,미니 미사일,Mini-raketten,Mini missiler,Mini Pociski,Mísseis,,Mini Proiectile,Мини-ракеты,Мини Ракете,Miniraketer,Mini Füzeler,Міні-ракети +Crate of Missiles,TAG_CRATEOFMISSILES,,,,Bedna raket,kasse med missiler,Raketenkiste,,Misilet-kesto,Caja de minimisiles,,Ohjuslaatikko,Caisse de Mini-Missiles,Ládányi Rakéta,Cassa di Missili,ミサイルの箱,미사일 박스,Krat raketten,Kasse med missiler,Skrzynia z Pociskami,Caixa de Mísseis,,Ladă cu Proiectile,Коробка ракет,Кутија ракета,Låda med missiler,Füze Sandığı,Ящик мініракет +Energy Pod,TAG_ENERGYPOD,,,,Energetický kokón,Energipod,Energiezelle,,Energi-kapsulo,Cápsula de energía,,Energia-akku,Cellule Energétique,Energia Lőszer,Nucleo Enegetico ,エネルギーポット,에너지 포드,Energiecel,Energikapsel,Kapsuła Energii,Energia (pequeno),,Capsulă cu Energie,Энергоячейка,Енергетска шипка,Energipod,Enerji Bölmesi,Енерго-капсула +Energy Pack,TAG_ENERGYPACK,,,,Energetický svazek,Energipakke,Energiepack,,Pako de energio,Paquete de energía,,Energiapaketti,Pack Energétique,Energia Csomag,Carica Energetica ,エネルギーパック,에너지 팩,Energiepak,Energipakke,Zasobnik Energii,Energia (grande),,Pachet cu Energie,Энергобатарея,Паковање енергије,Energipaket,Enerji Paketi,Енерго-батарея +Poison Bolts,TAG_POISONBOLTS,,,,Otrávené šípy,Giftige bolte,Giftbolzen,,Venenaj sagoj,Flechas venenosas,,Myrkkynuolet,Carreaux Empoisonnés,Mérgező hegyek,Dardi Velenosi ,ポイズンボルト,맹독 볼트,Giftige bouten,Giftbolter,Zatrute Bełty,Setas Envenenadas,,Bolțuri cu Otravă,Отравленные болты,Отровне стреле,Giftiga bultar,Zehirli Cıvatalar,Отруйні болти +Electric Bolts,TAG_ELECTRICBOLTS,,,,Elektrické šípy,Elektriske bolte,Elektrische Bolzen,,Elektraj sagoj,Flechas eléctricas,,Sähkönuolet,Carreaux Electriques,Elektromos hegyek,Dardi Elettrici ,エレクトリックボルト,전격 볼트,Elektrische bouten,Elektriske bolter,Elektryczne Bełty,Setas Elétricas,,Bolțuri cu Electricitate,Электрические болты,Електричне стреле,Elektriska bultar,Elektrikli Cıvatalar,Електричні болти +Ammo Satchel,TAG_AMMOSATCHEL,,,,Brašna na munici,Ammo Satchel,Munitionstasche,,Sako da municioj,Bolso de municiones,,Ammuslaukku,Sacoche à munitions,Lőszeres táska,Borsa di Munizioni ,弾薬鞄,탄약 배낭,Munitietassen,Ammunisjonsveske,Torba z Amunicją,Bolsa de Munição,,Sacoșă cu Muniție,Ранец боеприпасов,Торбица муниције,Ammo Satchel,Cephane Çantası,Сумка для набоїв +Base Key,TAG_BASEKEY,,,,Klíč od základny,Basisnøgle,Basisschlüssel,,Bazoŝlosilo,Llave de la base,,Tukikohdan avain,Clé de la base,Bázis Kulcs,Chiave della Base,,기지 키,Basissleutel,Basenøkkel,Klucz do Bazy,Chave da Base,,Cheia Bazei,Ключ от базы,Кључ базе,Basnyckel,Temel Anahtar,Ключ від бази +Govs Key,TAG_GOVSKEY,,,,Klíč ke guvernérovi,Govs nøgle,Gouverneursschlüssel,,Ŝlosilo de registo,Llave Gobernador,,Kuvernöörin avain,Clé du Gouverneur,Kormányzó Kulcs,Chiave del Governatore ,,총독의 키,Gouverneursleutel,Regjeringsnøkkel,Klucz Gubernatora,Chave do Governador,,Cheia Guvernatorului,Ключ губернатора,Гувернеров кључ,Govs-nyckel,Govs Anahtar,Ключ губернатора +Passcard,TAG_PASSCARD,,,,Vstupní karta,Adgangskort,Zugangskarte,,Central-ŝlosilo,Llave de la central,,Avainkortti,Passe,Belépőkártya,Tessera Lasciapassare ,,통행 카드,Paspoortkaart,Adgangskort,Karta Dostępu,Cartão de Acesso,,Legitimație,Пропуск,Пропусница,Passerkort,Geçiş kartı,Карта доступу +ID Badge,TAG_IDBADGE,,,,Identifikační odznak,ID-badge,Identitätskarte,,Mallibereja insigno,Insignia de prisión,,Henkilötunniste,Badge d'Identification,Azonosító Jelvény,Distintivo ,,신분 휘장,ID-Badge,ID-badge,Odznaka Identyfikacyjna,Crachá de Identificação,,Ecuson de Identificare,Личная карта,Идентификациона значка,ID-bricka,Kimlik Rozeti,Бейджик +Prison Key,TAG_PRISONKEY,,,,Klíč od věznice,Fængselsnøgle,Gefängnisschlüssel,,Mallibereja ŝlosilo,Llave de la prisión,,Vankilan avain,Clé de la Prison,Börtön Kulcs,Chiave della Prigione ,,감옥 키,Gevangenissleutel,Fengselsnøkkel,Klucz do Więzienia,Chave da Prisão,,Cheia Închisorii,Ключ от тюрьмы,Кључ од 3атвора,Fängelsenyckel,Hapishane Anahtarı,Ключ від тюрми +Severed Hand,TAG_SEVEREDHAND,,,,Useknutá ruka,Afskåret hånd,Abgetrennte Hand,,Amputita mano,Mano amputada,,Katkennut käsi,Main coupée,Levágott Kéz,Mano Mozzata,,잘린 손목,Gescheurde Hand,Avkuttet hånd,Odcięta Ręka,Mão Decepada,Mão Desmenbrada,Mână Retezată,Отрезанная рука,Одвојена шака,Avskuren hand,Kesik El,Відрізана рука +Power1 Key,TAG_POWER1KEY,,,,Klíč od elektrárny 1,Power1 nøgle,Kraftwerksschlüssel 1,,Central-identigo 1,Ident. central nv. 1,,Voimalan 1-avain,Clé Power1,1. erő kulcs,Chiave della Centrale 1,,발전소 1호 키,1e Machtsleutel,Power1-nøkkel,Klucz do Elektrowni 1,Chave da Usina 1,Chave Energética 1,Cheia Putere1,Ключ ЭС №1,Кључ од ел. 1,Kraftnyckel 1,Güç1 Anahtarı,Ключ від електростанції 1 +Power2 Key,TAG_POWER2KEY,,,,Klíč od elektrárny 2,Power2-nøgle,Kraftwerksschlüssel 2,,Central-identigo 2,Ident. central nv. 2,,Voimalan 2-avain,Clé Power2,2. erő kulcs,Chiave della Centrale 2,,발전소 2호 키,2e Machtsleutel,Power2-nøkkel,Klucz do Elektrowni 2,Chave da Usina 2,Chave Energética 2,Cheia Putere2,Ключ ЭС №2,Кључ од ел. 2,Kraftnyckel 2,Güç2 Anahtarı,Ключ від електростанції 2 +Power3 Key,TAG_POWER3KEY,,,,Klíč od elektrárny 3,Power3-nøgle,Kraftwerksschlüssel 3,,Central-identigo 3,Ident. central nv. 3,,Voimalan 3-avain,Clé Power3,3. erő kulcs,Chiave della Centrale 3,,발전소 3호 키,3e Machtsleutel,Power3-nøkkel,Klucz do Elektrowni 3,Chave da Usina 3,Chave Energética 3,Cheia Putere3,Ключ ЭС №3,Кључ од ел. 3,Kraftnyckel 3,Güç3 Anahtarı,Ключ від електростанції 3 +Gold Key,TAG_GOLDKEY,,,,Zlatý klíč,Guldnøgle,Goldschlüssel,,Ora ŝlosilo,Llave dorada,,Kulta-avain,Clé en Or,Aranykulcs,Chiave Dorata,,황금 키,Gouden sleutel,Gullnøkkel,Złoty Klucz,Chave de Ouro,,Cheia din Aur,Золотой ключ,Златни кључ,Guldnyckel,Altın Anahtar,Золотий ключ +ID Card,TAG_IDCARD,,,,Identifikační karta,ID-kort,Ausweis,,Kloaka identigilo,Identif. cloacas,,Henkilökortti,Carte d'Identité,Azonosító Kártya,Tessera Identificativa,,신분증,ID-Kaart,ID-kort,Karta Identyfikacyjna,Cartão de Identificação,,Card de Identitate,Удостоверение,Лична карта,ID-kort,Kimlik Kartı,Ідентифікаційна карта +Silver Key,TAG_SILVERKEY,,,,Stříbrný klíč,Sølvnøgle,Silberschlüssel,,Arĝenta ŝlosilo,Llave plateada,,Hopea-avain,Clé en Argent,Ezüst Kulcs,Chiave Argentata,,은 키,Zilveren sleutel,Sølv-nøkkel,Srebrny Klucz,Chave de Prata,,Cheia din Argint,Серебряный ключ,Сребрни кључ,Silvernyckel,Gümüş Anahtar,Срібний ключ +Oracle Key,TAG_ORACLEKEY,,,,Věštcův klíč,Orakel-nøgle,Orakelschlüssel,,Orakolo-ŝlosilo,Llave del Oráculo,,Oraakkelin avain,Clé de l'Oracle,Orákulum kulcs,Chiave dell'Oracolo ,,오라클 키,Orakelsleutel,Oracle-nøkkel,Klucz do Wyroczni,Chave do Oráculo,,Cheia Oracol,Ключ Оракула,Пророков кључ,Oracle-nyckel,Kahin Anahtarı,Ключ Оракула +Military ID,TAG_MILITARYID,,,,Vojenské ID,Militær ID,Militärausweis,,Milita identigilo,Identif. militar,,Sotilastunnus,Identification Militaire,Katonai Azonosító Kártya,Identificativo Militare,,군용 아이디,Militaire ID,Militær ID,Wojskowy Identyfikator,ID Militar,,Legitimație Militară,Удостовер. военного,Војна идентификација,Militärt ID,Askeri Kimlik,Військова ID карта +Order Key,TAG_ORDERKEY,,,,Klíč Řádu,Bestillingsnøgle,Ordensschlüssel,,Ordena ŝlosilo,Llave de La Orden,,Veljeskunnan avain,Clé de l'Ordre,Rend Kulcs,Chiave dell'Ordine,,오더의 키,Ordesleutel,Bestillingsnøkkel,Klucz Zakonu,Chave da Ordem,,Cheia Ordinului,Ключ Ордена,Кључ одреда,Beställningsnyckel,Sipariş Anahtarı,Ключ Ордену +Warehouse Key,TAG_WAREHOUSEKEY,,,,Klíč ke skladu,Lagernøgle,Lagerhausschlüssel,,Magazena ŝlosilo,Llave del almacén,,Varaston avain,Clé de l'Entrepôt,Raktár Kulcs,Chiave del Magazzino ,,창고 키,Magazijnsleutel,Lagernøkkel,Klucz do Magazynu,Chave do Armazém,,Cheia Depozitului,Ключ от склада,Кључ складишта,Lagernyckel,Depo Anahtarı,Ключ від складу +Brass Key,TAG_BRASSKEY,,,,Mosazný klíč,Messingnøgle,Messingschlüssel,,Latuna ŝlosilo,Llave de latón,,Messinkiavain,Clé en Bronze,Réz Kulcs,Chiave d'Ottone ,,황동 키,Messing sleutel,Messingnøkkel,Mosiężny Klucz,Chave de Latão,,Cheia din Alamă,Латунный ключ,Кључ од месинга,Mässingsnyckel,Pirinç Anahtar,Латунний ключ +Red Crystal Key,TAG_REDCRYSTALKEY,,,,Červený krystalový klíč,Rød krystalnøgle,Roter Kristallschlüssel,,Ruĝkristala ŝlosilo,Llave cristal rojo,,Punainen kristalliavain,Clé de Cristal Rouge,Piros Kristály Kulcs,Chiave di Cristallo Rosso ,,적색 크리스탈 키,Rode kristallen sleutel,Rød krystallnøkkel,Czerwony Kryształowy Klucz,Chave de Cristal Vermelho,,Cheia din Cristal Roșu,Крас. ключ-кристалл,Кључ од црвеног кристала,Nyckel i röd kristall,Kırmızı Kristal Anahtar,Червоний кристальний ключ +Blue Crystal Key,TAG_BLUECRYSTALKEY,,,,Modrý krystalový klíč,Blå krystalnøgle,Blauer Kristallschlüssel,,Blukristala ŝlosilo,Llave cristal azul,,Sininen kristalliavain,Clé de Crisal Bleu,Kék Kristály Kulcs,Chiave di Cristallo Blu,,청색 크리스탈 키,Blauwe kristallen sleutel,Blå krystallnøkkel,Niebieski Kryształowy Klucz,Chave de Cristal Azul,,Cheia din Cristal Albastru,Син. ключ-кристалл,Кључ од плавог кристала,Blå kristallnyckel,Mavi Kristal Anahtar,Синій кристальний ключ +Chapel Key,TAG_CHAPELKEY,,,,Klíč od kaple,Kapel nøgle,Kapellenschlüssel,,Kapelo-ŝlosilo,Llave de la Capilla,,Kappelin avain,Clé de la Chapelle,Kápolna Kulcs,Chiave della Cappella ,,예배당 키,Kappelsleutel,Kapell-nøkkel,Klucz do Kaplicy,Chave da Capela,,Cheia Capelei,Ключ от часовни,Кључ капеле,Kapellnyckel,Şapel Anahtarı,Ключ від каплиці +Catacomb Key,TAG_CATACOMBKEY,,,,Klíč do katakomb,Katakomb Nøgle,Katakombenschlüssel,,Katakomb-ŝlosilo,Llave Catacumbas,,Katakombin avain,Clé des Catacombes,Katakomba Kulcs,Chiave delle Catacombe ,,고대 묘지 키,Catacombesleutel,Katakomb-nøkkel,Klucz do Katakumb,Chave da Catacumba,,Cheia Catacombei,Ключ от катакомб,Кључ од катакомби,Katakomb-nyckel,Katakomb Anahtarı,Ключ від катакомб +Security Key,TAG_SECURITYKEY,,,,Klíč ochranky,Sikkerhedsnøgle,Sicherheitsschlüssel,,Sekureco-ŝlosilo,Llave de Seguridad,,Turvamiesavain,Clé de la Sécurité,Biztonsági Kulcs,Chiave della Sicurezza ,,보안 키,Beveiligingssleutel,Sikkerhetsnøkkel,Klucz Ochrony,Chave de Segurança,,Cheia Securității,Ключ охраны,Сигурносни кључ,Säkerhetsnyckel,Güvenlik Anahtarı,Ключ охорони +Core Key,TAG_COREKEY,,,,Klíč k jádru,Reaktor Nøgle,Reaktorschlüssel,,Kernoŝlosilo,Llave del Núcleo,,Ytimen avain,Clé du Réacteur,Mag Kulcs,Chiave del Nucleo,,중심부 키,Kernsleutel,Kjernenøkkel,Klucz do Rdzenia,Chave do Núcleo,,Cheia Nucleului,Ключ от реактора,Кључ језгра,Kärnnyckel,Çekirdek Anahtar,Ключ від реактора +Mauler Key,TAG_MAULERKEY,,,,Klíč k trhačům,Mauler-nøgle,Vernichterschlüssel,,Polvigilo-ŝlosilo,Llave Triturador,,Moukarin avain,Clé du Broyeur,Marcangoló Kulcs,Chiave del Pestatore ,,마울러 키,Toetakelaarssleutel,Mauler-nøkkel,Klucz do Magazynu Miażdżycieli,Chave - Mauler,,Cheia Sfâșietorului,Ключ истязателя,Маулер кључ,Mauler-nyckel,Mauler Anahtar,Ключ розсіювача +Factory Key,TAG_FACTORYKEY,,,,Klíč do továrny,Fabriksnøgle,Fabrikschlüssel,,Fabriko-ŝlosilo,Llave de la Fábrica,,Tehtaan avain,Clé de l'Usine,Gyár Kulcs,Chiave della Fabbrica ,,공장 키,Fabriekssleutel,Fabrikknøkkel,Klucz do Fabryki,Chave da Fábrica,,Cheia Fabricii,Ключ от фабрики,Кључ фабрике,Fabriksnyckel,Fabrika Anahtarı,Ключ від фабрики +Mine Key,TAG_MINEKEY,,,,Klíč od dolů,Mine-nøgle,Minenschlüssel,,Minejo-ŝlosilo,Llave de la Mina,,Kaivoksen avain,Clé de la Mine,Bánya Kulcs,Chiave della Miniera ,,탄광 키,Mijnsleutel,Gruve-nøkkel,Klucz do Kopalni,Chave da Mina,,Cheia Minei,Ключ от шахт,Кључ рудника,Gruvnyckel,Maden Anahtarı,Ключ від шахт +New Key5,TAG_NEWKEY5,,,,Nový klíč 5,Ny nøgle5,Neuer Schlüssel 5,,Nova ŝlosilo kvin,Llave nueva cinco,,Uusi 5-avain,Clé nouveau 5,5. kulcs,Nuova Chiave 5,,새로운 키5,Nieuwe sleutel 5,Ny nøkkel5,Nowy Klucz5,Chave Nova 5,,Noua Cheie5,Новый ключ №5,Нови кључ5,Ny nyckel5,Yeni Anahtar5,Новий ключ 5 +Oracle Pass,TAG_ORACLEPASS,,,,Věštcova propustka,Orakelpas,Orakelpass,,Orakolo-pasilo,Pase del Oráculo,,Oraakkelin kulkulupa,Passe de l'Oracle,Orákulum útlevél,Lasciapassare dell'Oracolo ,,오라클의 통행증,Orakelpas,Oracle Pass,Przepustka Wyroczni,Passe do Oráculo,,Legitimația Oracol,Пропуск Оракула,Пророкова пропусница,Orakelpass,Kahin Kartı,Пропуск Оракула +10 gold,TAG_10GOLD,,,,10 zlatých,10 guld,,,10 da oro,10 de oro,,10 kolikkoa,10 Pièces,10 arany,10 pezzi d'oro ,10ゴールド,10 골드,10 goud,10 gull,10 monet,10 moedas,10 moedas de ouro,10 monezi de aur,10 золотых,10 златника,10 guld,10 altın,10 золотих +25 gold,TAG_25GOLD,,,,25 zlatých,25 guld,,,25 da oro,25 de oro,,25 kolikkoa,25 Pièces,25 arany,25 pezzi d'oro ,25ゴールド,25 골드,25 goud,25 gull,25 monet,25 moedas,25 moedas de ouro,25 de monezi de aur,25 золотых,25 златника,25 guld,25 altın,25 золотих +50 gold,TAG_50GOLD,,,,50 zlatých,50 guld,,,50 da oro,50 de oro,,50 kolikkoa,50 Pièces,50 arany,50 pezzi d'oro ,50ゴールド,50 골드,50 goud,50 gull,50 monet,50 moedas,50 moedas de ouro,50 de monezi de aur,50 золотых,50 златника,50 guld,50 altın,50 золотих +300 gold,TAG_300GOLD,,,,300 zlatých,300 guld,,,300 da oro,300 de oro,,300 kolikkoa,300 Pièces,300 arany,300 pezzi d'oro ,300ゴールド,300 골드,300 goud,300 gull,300 monet,300 moedas,300 moedas de ouro,300 de monezi de aur,300 золотых,300 златника,300 guld,300 altın,300 золотих +Person,TXT_PERSON,,,,Osoba,,,,Persono,Persona,,Henkilö,Personne,Személy,Persona,一員,민간인,Persoon,,Osoba,Pessoa,,Persoană,Горожанин,Особа,Person,Kişi,Цивільний +Acolyte,TAG_ACOLYTE,,,,Akolyta,Akolyt,Ministrant,,Akolito,Acólito,,Akoluutti,,Ministráns,Accolito ,アコライト,아콜라이트,Acoliet,Akolytt,Akolita,Acólito,,Acolit,Служитель,Следбеник,Akolyt,Yardımcı,Адепт +Armorer,TAG_ARMORER,,,Armourer,Kovář,Våbendør,Rüster,,Armilisto,Armero,,Asemestari,Armurier,Páncélkovács,Armaiolo ,装甲,병기공,Harnassmid,Våpensmed,Płatnerz,Armeiro,,Armurier,Продавец брони,Ковач,Rusthållare,Zırhçı,Коваль +Bar Keep,TAG_BARKEEP,,,,Výčepní,Bar-værn,Wirt,,Drinkejestro,Cantinero,,Baarimikko,Barman,Csapos,Barista,酒屋,바텐더,Barman,Bartender,Barman,Dono do Bar,,Barman,Хозяин таверны,Конобар,Bartender,Barmen,Бармен +Beggar,TAG_BEGGAR,,,,Žebrák,Tigger,Bettler,,Almozulo,Mendigo,,Kerjäläinen,Mendiant,Koldus,Mendicante ,乞食,거지,Bedelaar,Tigger,Żebrak,Mendigo,,Sărman,Нищий,Просјак,Tiggare,Dilenci,Жебрак +Macil,TAG_MACIL1,,,,,,,,,,,,,,,マシル,마실,,,,,,,Мэйсил,Мејсил,,Macil,Масіл +Macil,TAG_MACIL2,,,,,,,,,,,,,,,マシル,마실,,,,,,,Мэйсил,Мејсил,,Macil,Масіл +Medic,TAG_MEDIC,,,,Medik,Læge,Sanitäter,,Kuracisto,Médico,,Lääkintämies,Médecin,Szanitéc,Medico,メディック,의무관,Paramedicus,,Medyk,Médico,,,Врач,Болничар,Sjukvårdare,,Лікар +Oracle,TAG_ORACLE,,,,Věštec,Orakel,Orakel,,Orakolo,Oráculo,,Oraakkeli,,Orákulum,Oracolo,オラクル,오라클,Orakel,Orakel,Wyrocznia,Oráculo,,Oracol,Оракул,Пророк,Orakel,Kahin,Оракул +Priest,TAG_PRIEST,,,,Kněz,Præst,Priester,,Pastro,Sacerdote,,Pappi,Prêtre,Pap,Sacerdote,プリースト,성직자,Priester,Prest,Kapłan,Sacerdote,,Preot,Жрец,Свештеник,Präst,Rahip,Священник +Rat Buddy,TAG_RATBUDDY,,,,Krysík,Rottekammerat,Ratte,,Rato,Rata,,Rottakamu,Copain Rat,Patkánypajtás,Ratto,ラット バディ,생쥐 친구,Rattenvriendje,Rottekompis,Koleżka Szczurów,Rato,,Amicul Șobolanilor,Крыса-друг,Друг пацов,Råttkompis,Sıçan Dostu,Друзяка щур +Rebel,TAG_REBEL,,,,,,Rebell,,Ribelanto,Rebelde,,Kapinallinen,Rebelle,Lázadó,Ribelle ,反乱軍,저항군,,Rebell,Rebeliant,Rebelde,,,Повстанец,Побуњеник,Rebell,Asi,Повстанець +Templar,TAG_TEMPLAR,,,,Templář,Tempelridder,Templer,,Templano,Templario,,Temppeliherra,Templier,Templomos,Templare ,騎士団員,템플러,Tempelier,Tempelridder,Templariusz,Templário,,Templier,Храмовник,Темплар,Tempelriddare,Tapınakçı,Тамплієр +Weapon Smith,TAG_WEAPONSMITH,,,,Zbraňmistr,Våbensmed,Waffenschmied,,Armilforĝisto,Forjador de armas,,Aseseppä,Forgeron,Fegyverkovács,Fabbro ,武器工,무기 제조상,Wapensmid,Våpensmed,Wytwórca Broni,Ferreiro,,Făurar,Оружейник,Ковач оружја,Vapensmed,Silah Ustası,Зброяр +Red Talisman,TAG_TALISMANRED,,,,Červený talisman,Rød Talisman,Roter Talisman,,Ruĝa Talismano,Talismán rojo,,Punainen talismaani,Talisman Rouge,Vörös Talizmán,Talismano rosso,赤の魔除け,붉은 부적,Rode Talisman,Rød talisman,Czerwony Talizman,Talismã Vermelho,,Talisman Roșu,Красный талисман,Црвени талисман,Röd talisman,Kızıl Tılsım,Червоний талісман +Green Talisman,TAG_TALISMANGREEN,,,,Zelený talisman,Grøn Talisman,Grüner Talisman,,Verda Talismano,Talismán verde,,Vihreä talismaani,Talisman Vert,Zöld Talizmán,Talismano verde,緑の魔除け,녹색 부적,Groene Talisman,Grønn talisman,Zielony Talizman,Talismã Verde,,Talisman Verde,Зелёный талисман,Зелени талисман,Grön Talisman,Yeşil Tılsım,Зелений талісман +Blue Talisman,TAG_TALISMANBLUE,,,,Modrý talisman,Blå Talisman,Blauer Talisman,,Blua Talismano,Talismán azul,,Sininen talismaani,Talisman Bleu,Kék Talizmán,Talismano blu,青の魔除け,푸른 부적,Blauwe Talisman,Blå talisman,Niebieski Talizman,Talismã Azul,,Talisman Albastru,Синий талисман,Плави талисман,Blå Talisman,Mavi Tılsım,Синій талісман +,,Obituaries,,,,,,,,,,,,,,,,,,,,,,,,,, +%o was zealously shot down by an Acolyte.,OB_ACOLYTE,,,,%o byl@[ao_cs] horlivě zastřelen@[ao_cs] akolytou.,%o blev skudt ned af en akolyt.,%o wurde eifrig von dem Ministranten erschossen.,,%o fervore pafiĝis de Akolito.,A %o l@[ao_esp] ha derribado con fervor un Acólito.,A %o l@[ao_esp] derribó con entusiasmo un Acólito.,%o joutui kiivailevan akoluutin ampumaksi.,%o a souffert d'une bavure policière.,%o-t buzgó módon le lett lőve egy Oltárszolga által.,%o è stato zelantemente abbattuto da un accolito. ,%o は熱心なアコライトに堕とされた。,%o 은(는) 아콜라이트에게 맹신적으로 사격 당했다.,%o werd gretig neergeschoten door een Acoliet.,%o ble nidkjært skutt ned av en akolytt.,%o został@[ao_pl] żarliwie zastrzelon@[adj_pl] przez Akolitę.,%o foi zelosamente abatid@[ao_ptb] por um Acólito.,,%o a fost împușcat zelos de un Acolit.,Игрок %o фанатично убит служителем.,%o је ревносно упуцан@[adj_1_sr] од стране секташа.,%o blev nitiskt nedskjuten av en akolyt.,"%o, bir yardımcısı tarafından gayretle vuruldu.",Адепт пристрелив %o. +%o should have never rebelled against Macil.,OB_MACIL,,,,%o se nikdy neměl@[ao_cs] vzbouřit vůči Macilovi.,%o skulle aldrig have gjort oprør mod Macil.,%o hätte nicht gegen Macil rebellieren sollen.,,%o ne estus devinta ribeli kontraŭ Macil.,%o no debería haberse rebelado contra Macil.,%o hizo mal en rebelarse contra Macil.,%o paran ei olisi ikinä pitänyt kapinoida Macilia vastaan.,%o n'aurait jamais du se rebeller contre Macil.,%o Macil ellen próbált fellázadni.,%o non avrebbe mai dovuto opporsi a Macil. ,%o はマシルに歯向かうべきではなかった。,%o 은(는) 마실의 적이 되지 말았어야 했다.,%o had nooit in opstand mogen komen tegen Macil.,%o skulle aldri ha gjort opprør mot Macil.,%o nie powin@[irreg_5_pl] buntować się przeciwko Macilowi.,%o nunca deveria ter se rebelado contra Macil.,%o nunca deveria ter se rebeliado contra Macil.,"%o nu ar fi trebuit să se răscoale împotriva lui +Macil.",Игроку %o не следовало восставать против Мэйсила.,%o никад није треба@[ao_1_sr] да се супротстави Мејсилу.,%o borde aldrig ha gjort uppror mot Macil.,"%o, Macil'e karşı asla isyan etmemeliydi.",%o ніколи не ма@[adj_1_ua] бунтувати проти Масіла. +%o was gunned down by a Rebel.,OB_REBEL,,,,%o byl@[ao_cs] odstřelen@[ao_cs] rebelem.,%o blev skudt ned af en oprører.,%o wurde von einem Rebellen erschossen.,,%o pafegiĝis de ribelanto.,A %o l@[ao_esp] ha fusilado un Rebelde.,A %o l@[ao_esp] fusiló un Rebelde.,%o joutui kapinallisen alas ampumaksi.,%o a été abattu@[e_fr] par un rebelle.,%o le lett lőve egy Lázadó által.,%o è stato colpito a morte da un Ribelle. ,%o は反乱軍に撃ち殺された。,%o 은(는) 저항군에 의해 제압당했다.,%o werd neergeschoten door een Rebel.,%o ble skutt ned av en opprører.,%o został@[ao_pl] rozstrzelan@[adj_pl] przez Rebelianta.,%o foi abatid@[ao_ptb] por um Rebelde.,,%o a fost pus la pământ de un Rebel.,Игрока %o расстрелял повстанец.,%o је упуцан@[adj_1_sr] од стране побуњеника.,%o blev skjuten av en rebell.,%o bir asi tarafından vuruldu.,%o було розстріляно повстанцем. +%o was beaten to death by the poor.,OB_BEGGAR,,,,%o byl@[ao_cs] umlácen@[ao_cs] chudinou.,%o blev slået ihjel af de fattige.,%o fiel der Armut zum Opfer.,,%o morte bategiĝis de la malriĉuloj.,%o ha sido abatid@[ao_esp] a muerte por los pobres.,%o recibió una paliza letal de los pobres.,%o joutui köyhälistön kuoliaaksi hakkaamaksi.,%o a été battu@[e_fr] a mort par un pauvre.,%o halálra lett verve a szegénység által.,%o è stato calpestato dalla povertà. ,%o は貧民に殴り殺された。,%o 은(는) 자업자득으로 거지에게 맞아 죽었다.,%o werd door de armen doodgeslagen.,%o ble slått i hjel av de fattige.,%o został@[ao_pl] zatłuczon@[adj_pl] na śmierć przez żebraka.,%o foi espancad@[ao_ptb] até a morte pelos pobres.,,%o a fost omorât în bătaie de sărmani.,Игрока %o забили до смерти нищие.,%o је претучен@[adj_1_sr] од стране просјака.,%o blev ihjälslagen av de fattiga.,%o fakirler tarafından ölene kadar dövüldü.,%o забив до смерті жебрак. +%o should have never picked a fight with a civilian.,OB_PEASANT,,,,%o si neměl@[ao_cs] začínat s civilistou.,%o skulle aldrig have taget et slagsmål med en civilist.,%o hätte sich nicht mit einem Zivilisten anlegen sollen.,,%o ne estus devinta komenci batalon al civilulo.,%o no debería haber empezado una pelea con un civil.,%o hizo mal en iniciar una pelea con un civil.,%o hölmön ei olisi ikinä pitänyt haastaa riitaa siviilin kanssa.,%o n'aurait jamais du chercher des noises a un civil.,%o ujjat húzott egy civillel.,%o non avrebbe mai dovuto prendersela con un civile. ,%o は庶民に戦いを挑むべきではなかった。,%o 은(는) 민간인과 싸울 힘도 전혀 없었다.,%o had nooit een gevecht met een burger moeten aangaan.,%o skulle aldri ha kranglet med en sivilist.,%o nigdy nie powin@[irreg_5_pl] wdawać się w bójkę z cywilem.,%o nunca deveria ter arrumado briga com um civil.,%o nunca deveria ter pegado à briga com um civil.,%o n-ar fi trebuit să se încaiere cu un civil.,Игроку %o не следовало начинать драку с горожанином.,%o никад није треба@[ao_1_sr] да се потуче са цивилом.,%o skulle aldrig ha börjat slåss med en civilperson.,%o asla bir sivil ile kavga etmemeliydi.,%o не варто було починати бійку з цивільним. +%o was struck down by the Spectre.,OB_ALIENSPECTRE,,,,%o byl@[ao_cs] zničen@[ao_cs] přízrakem.,%o blev slået ned af spøgelset.,%o wurde von dem Schemen niedergestreckt.,,%o subite mortiĝis de la Fantomo.,A %o l@[ao_esp] ha fulminado el Espectro.,A %o l@[ao_esp] fulminó el Espectro.,%o joutui haamun kaatamaksi.,%o a été terrassé@[e_fr] par le Spectre.,%o ki lett ütve a lidérc által.,%o è stato abbattuto dallo Spettro. ,%o はスペクトルに討ち滅ぼされた。,%o 은(는) 스펙터에 의해 무너져 내렸다.,%o werd door de Specter neergeslagen.,%o ble slått ned av Spekter.,%o został@[ao_pl] powalon@[adj_pl] przez Widmo.,%o foi abatid@[ao_ptb] por um Espectro.,,%o a fost răpus de Spectru.,Игрока %o уничтожил фантом.,%o је обори@[ao_1_sr] са ногу утвара.,%o blev nedsliten av spektret.,%o Hortlak tarafından vuruldu.,Спектр вразив %o. +%o felt the wrath of The One God.,OB_ENTITY,,,,%o pocítil@[ao_cs] vztek Jediného Boha,%o følte den ene Guds vrede.,%o spürte den Zorn des Einen Gottes.,,%o sentis la koleregon de la Vera Dio.,%o ha sentido la ira del Dios Único.,%o sintió la ira del Dios Único.,%o sai tuta Yhden Ainoan Jumalan vihan.,%o a senti le courroux du Seul Dieu.,%o megérezte az Egyetlen Isten haragját.,%o ha assistito all'ira dell'Unico Dio. ,%o は唯一神の怒りに触れた。,%o 은(는) 유일신의 이름으로 천벌을 받았다.,%o voelde de toorn van de Ene God.,%o følte vreden til Den ene Gud.,%o poczuł@[ao_pl] gniew Jedynego Boga.,%o sentiu a ira do Deus Único.,,%o a simțit furia Zeului.,Игрок %o столкнулся с гневом Единого Бога.,Играча %o је осетио бес Јединог бога.,%o fick känna på den ende gudens vrede.,%o Tek Tanrı'nın gazabını hissetti.,%o відчу@[adj_1_ua] гнів Єдиного Бога. +%o couldn't escape from the Lore Master's grasp.,OB_LOREMASTER,,,,%o nemohl@[ao_cs] utéct Dějepiscově sevření.,%o kunne ikke undslippe Loremesterens greb.,%o konnte dem Griff des Wissensmeisters nicht entkommen.,,%o ne povis eskapi el la kapto de la Folkloristo.,%o no ha conseguido huir de las garras del Maestro del Conocimiento.,%o no logró huir de las garras del Maestro del Conocimiento.,%o ei kyennyt pakenemaan Oppi-Isän otteesta.,%o n'a pu échapper a l'emprise du Maître des Traditions.,%o nem tudott elmenekülni a Tan Mester elől.,%o non è riuscito a sfuggire alla stretta del Sapiente.,%o はロアマスターの手から逃れられなかった。,%o 은(는) 로어마스터의 촉수를 벗어나지 못했다.,%o kon niet ontsnappen aan de greep van de kennismeester.,%o kunne ikke unnslippe Loremesterens grep.,%o nie m@[irreg_4_pl] uniknąć chwytu Mędrca.,%o não conseguiu escapar do alcance do Mestre do Conhecimento.,,"%o n-a putut scăpa din mâinile Maestrului +Cunoștințelor.",Игрок %o не смог избежать длани Хранителя мудрости.,%o није успе@[ao_1_sr] побећи из Чувареве мудрости домашаја.,%o kunde inte fly från läromästarens grepp.,"%o, İrfan Ustası'nın elinden kaçamadı.",%o не здужа@[adj_1_ua] хват Хранителя мудрості. +%o was deleted by the Programmer.,OB_PROGRAMMER,,,,%o byl@[ao_cs] vymazán@[ao_cs] Programátorem.,%o blev slettet af Programmøren.,%o wurde vom Programmierer gelöscht.,,%o eksiĝis de La Programisto.,%o ha sido suprimid@[ao_esp] por El Programador.,%o fue suprimid@[ao_esp] por El Programador.,%o joutui Ohjelmoijan poistamaksi.,%o a été effacé@[e_fr] par le Programmeur.,%o ki lett törölve a Programozó által.,%o è stato cancellato dal Programmatore. ,%o はプログラマーに消去された。,%o 은(는) 프로그래머에 의해 삭제됐다.,%o werd door de programmeur verwijderd.,%o ble slettet av Programmereren.,"%o został@[ao_pl] usunięt@[adj_pl] przez Programistę. +",%o foi deletad@[ao_ptb] pelo Programador.,%o foi apagad@[ao_ptb] pelo Programador.,%o a fost șters de Programator.,Игрока %o удалил Программист.,Играча %о је обрисао Програмер.,%o blev raderad av programmeraren.,%o Programcı tarafından silindi.,Програміст стер %o. +%o was blown away by the Bishop.,OB_STFBISHOP,,,,%o byl@[ao_cs] odpálen@[ao_cs] Biskupem.,%o blev sprængt væk af Biskoppen.,%o wurde vom Bischof weggeblasen.,,%o forbloviĝis de la Episkopo.,%o ha sido volad@[ao_esp] en pedazos por el Obispo.,%o fue volad@[ao_esp] en pedazos por el Obispo.,%o joutui Piispan tyrmäämäksi.,%o a été pulvérisé@[e_fr] par l'Evèque.,%o el lett fújva a Püspök által.,%o è stato spazzato via dal Vescovo. ,%o はビショップに吹き飛ばされた。,%o 은(는) 비숍에 의해 초토화되었다.,%o werd door de bisschop weggeblazen.,%o ble blåst bort av biskopen.,%o został@[ao_pl] wysadzon@[adj_pl] przez Biskupa.,%o foi detonad@[ao_ptb] pelo Bispo.,,%o a fost aruncat cât colo de Episcop.,Игрока %o поразил Епископ.,Играча %o је екслопдирао Епископ.,%o blev bortblåst av biskopen.,"%o, Piskopos tarafından havaya uçuruldu.",%o підірвано Єпископом. +%o was shot down by a Sentinel.,OB_SENTINEL,,,,%o byl@[ao_cs] odstřelen@[ao_cs] strážným robotem.,%o blev skudt ned af en Sentinel.,%o wurde von dem Wächter niedergeschossen.,,%o pafegiĝis de Sentinelo.,A %o l@[ao_esp] ha derribado un Centinela.,A %o l@[ao_esp] derribó un Centinela.,%o joutui vartijan ampumaksi.,%o a été abattu@[e_fr] par une Sentinelle.,%o meg lett lőve egy Őrszem által.,%o è stato impallinato dalla Sentinella. ,%o はセンティネルに堕とされた。,%o 은(는) 센티넬의 레이져를 맞았다.,%o werd neergeschoten door een Sentinel.,%o ble skutt ned av en Sentinel.,%o został@[ao_pl] zastrzelon@[adj_pl] przez Wartownika.,%o foi abatid@[ao_ptb] por uma Sentinela.,,%o a fost pus la pământ de o Santinelă.,Игрока %o застрелил страж.,Играча %o је упуцао стражар.,%o blev nedskjuten av en Sentinel.,%o bir Nöbetçi tarafından vuruldu.,Вартовий пристрелив %o. +%o was swept away by a Crusader.,OB_CRUSADER,,,,%o byl@[ao_cs] odhozen@[ao_cs] křižákem.,%o blev fejet væk af en korsfarer.,%o wurde vom Ordensritter weggeblasen.,,%o tute detruiĝis de Krucisto.,A %o l@[ao_esp] ha aniquilado un Cruzado.,A %o l@[ao_esp] aniquiló un Cruzado.,%o joutui ristiretkeläisen pois pyyhkäisemäksi.,%o a été balayé@[e_fr] par un Croisé.,%o el lett söpörve egy Keresztes Lovag által.,%o è stato tolto di mezzo da un Crociato. ,"%o はクルセーダーに一掃された。 +",%o 은(는) 크루세이더의 공격에 날라갔다.,%o werd weggevaagd door een kruisvaarder.,%o ble feid bort av en korsfarer.,%o został@[ao_pl] zmiecion@[adj_pl] przez Krzyżowca.,%o foi varrid@[ao_ptb] por um Cruzado.,,%o a fost măturat de un Cruciat.,Игрока %o смёл крестоносец.,%o је обори@[ao_1_sr] с ногу крсташ.,%o sveptes bort av en korsriddare.,%o bir Haçlı tarafından süpürüldü.,%o змів хрестоносець. +%o was sentenced by an Inquisitor.,OB_INQUISITOR,,,,%o byl@[ao_cs] odsouzen@[ao_cs] inkvizitorem.,%o blev dømt af en inkvisitor.,%o wurde vom Inquisitor verurteilt.,,%o kondamniĝis de Inkvizitoro.,A %o l@[ao_esp] ha sentenciado un Inquisidor.,A %o l@[ao_esp] sentenció un Inquisidor.,%o joutui inkvisiittorin tuomitsemaksi.,%o a été condamné@[e_fr] par un Inquisiteur.,%o el lett ítélve egy Vizsgálóbíró által.,%o è stato condannato da un Inquisitore. ,"%o は審問官によって宣告された。 +",%o 은(는) 인퀴지터에 의해 처벌받았다.,%o werd veroordeeld door een inquisiteur.,%o ble dømt av en inkvisitor.,%o został@[ao_pl] skazan@[adj_pl] przez Inkwizytora.,%o foi condenad@[ao_ptb] por um Inquisidor.,,%o a fost condamnat de un Inchizitor.,Игрока %o приговорил инквизитор.,Играчу %o је пресудио инквизитор.,%o blev dömd av en inkvisitor.,%o bir Engizisyoncu tarafından mahkum edildi.,Інквізитор здійснив суд над %o. +%o was bugged by a Stalker.,OB_STALKER,,,,%o se nechal@[ao_cs] otravovat slídilem.,%o blev aflyttet af en Stalker.,%o wurde von dem Jäger genervt.,,%o ĝeniĝis de Gvatanto.,A %o l@[ao_esp] ha fastidiado un Acechador.,A %o l@[ao_esp] fastidió un Acechador.,%o joutui vaanijan häiritsemäksi.,%o a été asticoté@[e_fr] par un chasseur.,%o bogaras lett egy Settenkedő által.,%o è stato violentato da un Cacciatore. ,"%o はストーカーに精神を蝕まれた。 +",%o 은(는) 스토커에게 벌레 물림을 당했다.,%o werd afgeluisterd door een Stalker.,%o ble avlyttet av en Stalker.,%o został@[ao_pl] zaczepion@[adj_pl] przez Prześladowcę.,%o foi atacad@[ao_ptb] por um Caçador.,,%o a fost cicălit de un Hărțuitor.,Игрока %o ужалил преследователь.,Играча %o је убио прогонитељ.,%o blev avlyssnad av en Stalker.,%o bir Takipçi tarafından dinlendi.,%o загриз сталкер. +%o triggered the automatic defenses.,OB_TURRET,,,%o triggered the automatic defences.,%o spustil@[ao_cs] automatickou obranu.,%o udløste det automatiske forsvar.,%o hat die automatische Verteidigung ausgelöst.,,%o ekagigis la aŭtomatajn defendojn.,%o ha activado las defensas automáticas.,%o activó las defensas automáticas.,%o laukaisi automaattipuolustukset.,%o a déclenché les défenses automatiques.,%o bekapcsolta az automata védelmi rendszert.,%o ha attivato le difese automatiche. ,%o は警備システムを起動してしまった。,%o 은(는) 경비 시스템에 발각되었다.,%o activeerde de automatische verdediging.,%o utløste det automatiske forsvaret.,%o aktywował@[ao_pl] automatyczne zabezpieczenia.,%o ativou as defesas automáticas.,,%o a alertat sistemul de protecție automat.,Из-за игрока %o активировалась автоматическая защита.,%o је активира@[ao_1_sr] дефанзивне системе.,%o utlöste det automatiska försvaret.,%o otomatik savunmayı tetikledi.,%o активува@[adj_1_ua] автоматичний захист. +%o was clawed by a Templar.,OB_TEMPLARHIT,,,,%o byl@[ao_cs] rozsápán@[ao_cs] templářem.,%o blev kløet af en Tempelridder.,%o wurde von dem Templer aufgeschlitzt.,,%o ungegiĝis de Templano.,A %o l@[ao_esp] ha desgarrado un Templario.,A %o l@[ao_esp] desgarró un Templario.,%o joutui temppeliherran raatelemaksi.,%o a été griffé@[e_fr] par un Templier.,%o meg lett karmolva egy Templomos által.,%o è stato artigliato da un Templare. ,%o は騎士団員に連行された。,%o 은(는) 템플러에게 할큄을 당했다.,%o werd geklauwd door een Tempelier.,%o ble klort av en tempelridder.,%o został@[ao_pl] rozszarpan@[adj_pl] przez Templariusza.,%o foi rasgad@[ao_ptb] por um Templário.,,%o a fost zgâriat de un Templier.,Игрока %o разорвал храмовник.,%o је пресечен@[adj_1_sr] од стране темплара.,%o blev klömsugen av en tempelriddare.,%o bir Tapınakçı tarafından pençelendi.,%o розірвав тамплієр. +%o was vaporized by a Templar.,OB_TEMPLAR,,,,%o byl@[ao_cs] rozpuštěn@[ao_cs] templářem.,%o blev fordampet af en Tempelridder.,%o wurde von dem Templer vaporisiert.,,%o vaporiĝis de Templano.,A %o l@[ao_esp] ha vaporizado un Templario.,A %o l@[ao_esp] vaporizó un Templario.,%o joutui temppeliherran höyryttämäksi.,%o a été vaporisé@[e_fr] par un Templier.,%o elpárolgott egy Templomos által.,%o è stato vaporizzato da un Templare. ,%o は騎士団員に浄化された。,%o 은(는) 템플러에 의해 존재가 소멸됐다.,%o werd verdampt door een Tempelier.,%o ble fordampet av en tempelridder.,%o rozpłyn@[irreg_2_pl] się przez Templariusza.,%o foi vaporizad@[ao_ptb] por um Templário.,,%o a fost vaporizat de un Templier.,Игрока %o испепелил храмовник.,Играча %o је испарио темплар.,%o blev förångad av en tempelriddare.,%o bir Tapınakçı tarafından buharlaştırıldı.,Тамплієр розсіяв %o. +%o was sliced open by a Reaver.,OB_REAVERHIT,,,,%o byl@[ao_cs] rozřezán@[ao_cs] pleničem.,%o blev skåret op af en Reaver.,%o wude von dem Plünderer aufgeschlitzt.,,%o distranĉiĝis de Lertulo.,A %o l@[ao_esp] ha rebanado un Saqueador.,A %o l@[ao_esp] rebanó un Saqueador.,%o joutui raastajan auki viiltämäksi.,%o a été fendu@[e_fr] par un Reaver.,%o szét lett vágva egy Fosztogató által.,%o è stato aperto a metà da un Saccheggiatore. ,%o はリーバーに切り裂かれた。,%o 은(는) 리버에게 해부되었다.,%o werd opengesneden door een Reaver.,%o ble skåret opp av en Reaver.,%o został@[ao_pl] rozcięt@[adj_pl] przez Rozbójnika.,%o foi fatiad@[ao_ptb] por um Saqueador.,,%o a fost feliat de un Pungaș.,Игрока %o разрезал на куски похититель.,%o је исечен@[adj_1_sr] на отворено од стране сакупљача.,%o blev uppskuren av en Reaver.,%o bir Yağmacı tarafından kesildi.,Рейдер нарізав на куски %o. +%o was shot down by a Reaver.,OB_REAVER,,,,%o byl@[ao_cs] zastřelen@[ao_cs] pleničem.,%o blev skudt ned af en Reaver.,%o wurde von dem Plünderer niedergeschossen.,,%o pafegiĝis de Lertulo.,A %o l@[ao_esp] ha derribado un Saqueador.,A %o l@[ao_esp] derribó un Saqueador.,%o joutui raastajan alas ampumaksi.,%o a été descendu@[e_fr] par un Reaver.,%o le lett lőve egy Fosztogató által.,%o è stato colpito da un Saccheggiatore. ,%o はリーバーに撃ち殺された。,%o 은(는) 리버에게 격파되었다.,%o werd neergeschoten door een Reaver.,%o ble skutt ned av en Reaver.,%o został@[ao_pl] zastrzelon@[adj_pl] przez Rozbójnika.,%o foi abatid@[ao_ptb] por um Saqueador.,,%o a fost împușcat de un Pungaș.,Игрока %o застрелил похититель.,Играча %o је упуцао сакупљач.,%o blev nedskjuten av en Reaver.,%o bir Yağmacı tarafından vuruldu.,Рейдер пристрелив %o. +%o was unwittingly backstabbed by %k.,OB_MPPUNCHDAGGER,,,,%o dostal@[ao_cs] kudlou do zad od hráče %k.,%o blev ufrivilligt stukket i ryggen af %k.,%o wurde von %k hinterrücks erdolcht.,,%o akcidente dorspikiĝis de %k.,%o ha sido apuñalad@[ao_esp] sin querer por %k.,%o fue apuñalad@[ao_esp] sin querer por %k.,%o joutui tahattomasti pelaajan %k selkäänpuukottamaksi.,%o s'est fait@[e_fr] planter un lame dans le dos de la part de %k.,%o véletlenül hátbalett szúrva %k által.,%o è stato colto alle spalle da %k senza che se ne accorgesse.,%o は電気ショックを %k からもらった。,%o 은(는) 모르는 사이에 %k 에 의해 비수를 찔렸다.,%o werd achtergestoken door %k.,%o ble uforvarende dolket i ryggen av %k.,%o został@[ao_pl] bezwiednie dźgnięt@[adj_pl] przez %k.,%o foi apunhalad@[ao_ptb] de surpresa por %k.,,%o a fost înjunghiat pe la spate de %k.,Игрок %o был непреднамеренно заколот кинжалом игрока %k.,%o је убоден@[adj_1_sr] у леђа од стране играча %k.,%o blev omedvetet knivhuggen i ryggen av %k.,"%o, %k tarafından farkında olmadan arkadan bıçaklandı.",%k випадково заріза@[adj_1_ua] %o. +%o got bolted to the wall by %k.,OB_MPELECTRICBOLT,,,,%o byl@[ao_cs] přišpendlen@[ao_cs] ke zdi hráčem %k.,%o blev boltet fast til væggen af %k.,%o wurde von %k an die Wand genagelt.,,%o pafiĝis de sageto sur la muro de %k.,%o ha quedado atornillad@[ao_esp] a la pared por %k.,%o quedó atornillad@[ao_esp] a la pared por %k.,%o naulitsi %o paran seinään.,%o s'est fait@[e_fr] clouer au mur par %k.,%o falra lett szegezve %k által.,%o è stato inchiodato al muro da %k.,%o は %k に壁へ打ち付けられた。,%o 은(는) %k 의 전류가 흐르는 볼트촉을 만졌다.,%o werd door %k aan de muur geschroefd.,%o ble boltet fast til veggen av %k.,%o został@[ao_pl] przybit@[adj_pl] do ściany przez %k.,%o foi pregad@[ao_ptb] na parede por %k.,,%o a fost agățat de perete de %k.,Игрок %o был прибит к стене игроком %k.,%o је причвршћен@[adj_1_sr] за зид од стране играча %k.,%o blev bultad mot väggen av %k.,"%o, %k tarafından duvara yapıştırıldı.",%k приби@[adj_1_ua] до стіни %o. +%o received a lethal dose of %k's wrath.,OB_MPPOISONBOLT,,,,%o přijal@[ao_cs] smrtelnou dávku hněvu hráče %k.,%o fik en dødelig dosis af %ks vrede.,%o erhielt eine tödliche Dosis von %ks Zorn.,,%o recivis mortigan dozon de la kolerego de %k.,%o ha recibido una dosis letal de la ira de %k.,%o recibió una dosis letal de la ira de %k.,%o sai tappavan annoksen pelaajan %k vihaa.,%o a recu une dose létale de la colère de %k.,%o kapott egy halálos adagot %k-tól/től.,%o ha ricevuto una dose letale dell'ira di %k.,%o は 致死量の %k の怒りを盛られた。,%o 은(는) %k 로부터 암살 같지 않은 암살을 당했다.,%o kreeg een dodelijke dosis van %k's toorn.,%o fikk en dødelig dose av %ks vrede.,%o dostał@[ao_pl] śmiertelną dawkę gniewu %k.,%o recebeu uma dose letal da ira de %k.,,%o a primit o doză letală din furia lui %k.,Игрок %o получил смертельную дозу гнева игрока %k.,%o је доби@[ao_1_sr] смртну дозу гнева играча %k.,%o fick en dödlig dos av %ks vrede.,"%o, %k tarafından zehirlendi.",%o відчу@[adj_1_ua] смертельну дозу гніву %k. +%o was drilled full of holes by %k's assault gun.,OB_MPASSAULTGUN,,,,%o byl@[ao_cs] proděravěn@[ao_cs] skrz na skrz puškou hráče %k.,%o blev boret fuld af huller af %ks angrebspistol.,%o wurde von %ks Sturmgewehr perforiert.,,%o boriĝis kun multaj truoj de la sturmofusilo de %k.,%o ha sido taladrad@[ao_esp] por el fusil de asalto de %k.,%o fue taladrad@[ao_esp] por el fusil de asalto de %k.,%k porasi %o paran täyteen reikiä rynnäkkökiväärillään.,%o s'est fait@[e_fr] couvrir de trous par le fusil d'assaut de %k.,%o ki lett lyukasztva %k Gépfegyvere által.,%o è stato crivellato dall'arma d'assalto di %k.,%o は %k のアサルトガンで穴だらけにされた。,%o 은(는) %k 의 돌격소총 덕분에 멋진 구멍을 선물 받았다.,%o werd geperforeerd door %k.,%o ble boret full av hull av %ks stormgevær.,%o został@[ao_pl] przedziurkowan@[adj_pl] przez karabin szturmowy %k.,%o foi perfurad@[ao_ptb] pelo fuzil de assalto de %k.,,"%o a fost umplut de găuri de pușca lui +%k.",Игрок %o изрешечён штурмовой винтовкой игрока %k.,%o је изрешетан@[adj_1_sr] од стране јуришне пушке играча %k.,%o blev fullborrad med hål av %ks attackpistol.,"%o, %k tarafından delik deşik edildi.",%k нароби@[adj_1_ua] дірок в %o штурмовою гвинтівкою. +%o gulped down %k's missile.,OB_MPMINIMISSILELAUNCHER,,,,%o spolknul@[ao_cs] raketu hráče %k.,%o slugte %ks missil.,%o schluckte %ks Rakete herunter.,,%o glutis la misilon de %k.,%o se ha tragado el misil de %k.,%o se tragó el misil de %k.,%o nieli alas pelaajan %k ohjuksen.,%o a avalé le missile de %k.,%o lenyelte %k rakétáját.,%o ha inghiottito il missile di %k.,%o は %k のミサイルを味わった。,%o 은(는) %k 의 미니 미사일을 고맙게 삼켰다.,%o heeft %k's raket naar beneden geslingerd.,%o slukte %k's missil.,%o połkn@[irreg_2_pl] rakietę %k.,%o engoliu o míssil de %k.,,%o a înghițit proiectilul lui %k.,Игрок %o проглотил ракету игрока %k.,%o је прогута@[ao_1_sr] ракету играча %k.,%o slukade %ks missil.,"%o, %k tarafından patlatıldı.",%o ковтну@[adj_1_ua] ракети %k. +%o was inverted by %k's H-E grenade.,OB_MPSTRIFEGRENADE,,,,%o byl@[ao_cs] otočen@[ao_cs] naruby výbušným granátem hráče %k.,%o blev omvendt af %ks H-E granat.,%o wurde von %ks HE-Granate invertiert.,,%o estis inversigita de la HE-grenado de %k.,%o ha sido invertid@[ao_esp] por la granada HE de %k.,%o fue invertid@[ao_esp] por la granada HE de %k.,%k käänsi %o paran nurinpäin räjähdekranaatillaan.,%o a été mis@[e_fr] sens dessus dessous par la grenade explosive de %k.,%o ki lett fordítva %k gránátája által.,%o è stato invertito dalla granata H-E di %k.,%o は %k のHE手榴弾によって反逆された。,%o 은(는) %k 의 고폭탄에 의해 역전당했다.,%o werd omgekeerd door %k's HE-granaat.,%o ble invertert av %ks H-E-granat.,%o został@[ao_pl] wywrócon@[adj_pl] przez granat %k.,%o foi peg@[ao_ptb] pelas granadas de %k.,,%o a fost întors pe dos de grenada lui %k.,Игрок %o вывернут наизнанку разрывной гранатой игрока %k.,%o се преокрену@[ao_1_sr] од стране Х-Е гранате играча %k.,%o blev omvänd av %ks H-E-granat.,"%o, %k tarafından ters çevrildi.",%o інвертува@[adj_2_ua] гранатою %k. +%o took a flame bath in %k's phosphorous pyre.,OB_MPPHOSPHOROUSGRENADE,,,,%o si dal@[ao_cs] ohnivou koupel ve fosforovém žáru hráče %k.,%o tog et flambad i %ks fosforbål.,%o nahm ein Flammenbad in %ks Scheiterhaufen.,,%o prenis flaman banon en la fosfora ŝtiparo de %k.,%o se ha bañado en las llamas de fósforo de %k.,%o se bañó en las llamas de fósforo de %k.,%o otti liekkikylvyn pelaajan %k fosforiroviolla.,%o s'est permis@[e_fr] une pyroclave dans les flammes phosphoriques de %k.,%o kapott egy tűzfürdőt %k máglyájától.,%o ha fatto un bagno nelle fiamme nella pira di fosforo di %k.,%o は %k の白リン弾で炎に包まれた。,%o 은(는) %k 의 소이탄이 뿜는 화염에 몸을 담갔다.,%o nam een vlammenbad in %k's fosforbrandstapel.,%o tok et flammebad i %ks fosforbål.,%o wzi@[irreg_2_pl] ognistą kąpiel w fosforowym stosie %k.,%o se banhou nas chamas de fósforo de %k.,,%o a făcut o baie fierbinte in fosforul lui %k.,Игрок %o принял горячую ванну из чистого фосфора игрока %k.,%o се окупа@[ao_1_sr] у пламену од стране фосфорне гранате играча %k.,%o tog ett flambad i %ks fosforbål.,"%o, %k tarafından fosforlu ateşte alev banyosu yaptırıldı.",%k приготува@[adj_1_ua] ванну з чистого фосфору для %o. +%o was barbecued by %k.,OB_MPFLAMETHROWER,,,,%o byl@[ao_cs] usmažen@[ao_cs] hráčem %k.,%o blev grillet af %k.,%o wurde von %k gegrillt,,%o kradrostiĝis de %k.,%o ha sido asad@[ao_esp] por %k.,%o fue asad@[ao_esp] por %k.,%k grillasi %o paran.,%o est passé@[e_fr] au barbecue de %k.,%o meg lett sütve %k által.,%o è stato fatto alla griglia da %k.,%o は %k に丸焼きにされてしまった。,%o 은(는) %k 의 바비큐 파티에 참여했다. 혼자서.,%o werd gebarbecued door %k.,%o ble grillet av %k.,%o został@[ao_pl] ugrillowan@[adj_pl] przez %k.,%o virou churrasco por causa de %k.,,%o a fost făcut grătar de %k.,Игрок %k поджарил игрока %o.,%o је реш печен@[adj_1_sr] од стране играча %k.,%o blev grillad av %k.,"%o, %k tarafından mangalda pişirildi.",%k зажари@[adj_1_ua] %o. +%o was zapped by %k.,OB_MPMAULER1,,,,%o byl@[ao_cs] zničen@[ao_cs] hráčem %k.,%o blev zappet af %k.,%o wurde von %k geschockt.,,%o elektrokutiĝis de %k.,A %o l@[ao_esp] ha electrocutado %k.,A %o l@[ao_esp] electrocutó %k.,%o joutui pelaajan %k sähköistämäksi.,%o s'est fait@[e_fr] électrocuter par %k.,%o kapott egy áramot %k által.,%o è stato fulminato da %k.,%o は %k から電気ショックを浴びた。,%o 은(는) %k 이(가) 가한 전기 충격을 당했다.,%o werd door %k gezapt.,%o fikk støt av %k.,%o został@[ao_pl] porażon@[adj_pl] przez %k.,%o foi eletrocutad@[ao_ptb] por %k.,,%o a fost electrocutat de %k.,Игрок %k ударил током игрока %o.,%o је елетрошокиран@[adj_1_sr] од стране играча %k.,%o blev zappad av %k.,"%o, %k tarafından zaplandı.",%o отрима@[adj_1_ua] дозу струму від %k. +%o was viciously vaporized by %k.,OB_MPMAULER,,,,%o byl@[ao_cs] rozpuštěn@[ao_cs] hráčem %k.,%o blev brutalt fordampet af %k.,%o wurde von %k vaporisiert.,,%o estis brutale vaporigita de %k.,%o ha sido ferozmente vaporizad@[ao_esp] por %k.,%o fue ferozmente vaporizad@[ao_esp] por %k.,%o joutui pelaajan %k höyrystämäksi.,%o à été vicieusement vaporisé@[e_fr] par %k.,%o elpárolgott %k által.,%o è stato crudelmente vaporizzato da %k.,%o は %k の悪辣さにより気化した。,%o 은(는) %k 에 의해 소극적으로 소멸되었다.,%o was door %k verdampt.,%o ble ondskapsfullt fordampet av %k.,%o rozpłyn@[irreg_2_pl] się przez %k.,%o foi vaporizad@[ao_ptb] por %k.,,%o a fost evaporat în mod violent de %k.,Игрок %k безжалостно распылил игрока %o.,%o је брутално испари@[ao_1_sr] од стране играча %k.,%o blev brutalt förångad av %k.,"%o, %k tarafından acımasızca buharlaştırıldı.",%k безжалісно розсія@[adj_1_ua] %o. +%o bowed down to the sheer power of %k's Sigil.,OB_MPSIGIL,,,,%o poklekl@[ao_cs] před čirou sílou Pečeti hráče %k.,%o bøjede sig for %ks sigil.,%o kapitulierte vor der Macht von %ks Sigil.,,%o kliniĝis antaŭ la plena potenco de la Sigelo de %k.,%o se ha inclinado ante el poder puro del emblema de %k.,%o se inclinó ante el poder puro del emblema de %k.,%o kumartui pelaajan %k Sinetin silkasta voimasta.,%o s'est prosterné@[e_fr] face à la toute puissance du Sigil de %k.,%o fejet hajtott %k Pecsétje ereje előtt.,%o si è prostrato davanti alla pura potenza del Sigillo di %k.,%o は %k のシジルによる威圧に屈した。,%o 은(는) %k 를 죽이기 전에 시질의 이름으로 절을 해야만 했다.,%o boog voor de kracht van %k's Sigil.,%o bøyde seg for kraften til %ks Sigil.,%o pokłonił@[ao_pl] się czystej mocy Pieczęci %k.,%o sentiu o poder do Sigilo de %k.,,"%o s-a plecat în fața puterii imense a Sigiliului +lui %k.",Игрок %o склонился перед силой Печати игрока %k.,%o је одклекну@[ao_1_sr] сировој моћи %k Сигила.,%o böjde sig för den rena kraften i %ks Sigill.,"%o, %k'in Sigil'inin katıksız gücüne boyun eğdi.",%o покори@[adj_2_ua] Сігілу %k. +,,Miscellaneous,,,,,,,,,,,,,,,,,,,,,,,,,, +Quest for the Sigil,TXT_STRIFE_EPI,,,,Pátrání za Pečetí,Jagten på Sigilet,Suche nach dem Sigil,,Serĉado por la Sigelo,La búsqueda del Emblema,,Päämääränä Sinetti,La Quête du Sigil,A Pecsét felkutatása,Alla ricerca del Sigillo,シジルの探求,시질을 위한 임무,Zoektocht naar de Sigil,Jakten på sigilet,Poszukiwanie Pieczęci,Em Busca do Sigilo,Demanda pelo Sigilo,În căutarea Sigiliului,В поисках Печати,Потрага за Сигил,Jakten på Sigillet,Sigilin Peşinde, +You've freed the prisoners!,TXT_FREED_PRISONERS,,,,Vysvobodil@[ao_cs] jsi vězně!,Du har befriet fangerne!,Du hast die Gefangenen befreit!,,Vi liberigis la kaptitojn!,¡Has liberado a los prisioneros!,¡Liberaste a los prisioneros!,Olet vapauttanut vangit!,Vous avez libéré les prisonniers!,Kiszabadítottad a foglyokat!,"Hai liberato i prigionieri! +",囚人を解放した!,죄수들을 탈옥시켰다!,Je hebt de gevangenen bevrijd!,Du har befridd fangene!,Uwolnił@[irreg_3_pl] więźniów,Você liberou os prisioneiros!,Libertaste os prisioneiros!,Ai eliberat prizonierii!,Пленники освобождены!,Затвореници су ослобођени!,Du har befriat fångarna!,Mahkumları serbest bıraktınız!,Ви звільнили в'язнів! +You've destroyed the Converter!,TXT_DESTROYED_CONVERTER,,,,Zničil@[ao_cs] jsi konvertér!,Du har ødelagt konverteren!,Du hast den Konverter zerstört!,,Vi detruis la konvertilon!,¡Has destruido el convertidor!,¡Destruiste el convertidor!,Olet tuhonnut muuntajan!,Vous avez détruit le convertisseur!,Elpusztítottad a konvertálót!,Hai distrutto i Convertitori!,コンバーターを破壊した!,개조 장치를 파괴했다!,Je hebt de Converter vernietigd!,Du har tilintetgjort Omformeren!,Zniszczył@[irreg_3_pl] Transformator!,Você destruiu o Conversor!,Destruiste o Transformador!,Ai distrus Convertorul!,Преобразователь уничтожен!,Претварач је уништен!,Du har förstört omvandlaren!,Dönüştürücüyü yok ettiniz!,Ви знищили конвертер! +Congratulations! You have completed the training area,TXT_COMPLETED_TRAINING,,,,Gratulujeme! Dokončil@[ao_cs] jsi tréninkový areál,Tillykke med det! Du har gennemført træningsområdet,Gratuliere! Du hast das Trainingsprogramm bestanden.,,Gratulon! Vi kompletigis la trejnejon,"¡Enhorabuena! Has completado +la zona de entrenamiento","¡Muy bien! Completaste +la zona de entrenamiento",Onnittelut! Olet suorittanut koulutusalueen,Félicitations! Vous êtes arrivé à la fin de l'entraînement.,Gratulálok! Elvégezted a gyakorló területet.,Congratulazioni! Hai completato l'area di addestramento,おめでとう!トレーニングエリアを完了した,훈련 코스를 마쳤다. 능력치 업!,Gefeliciteerd! Je hebt de training voltooid.,Gratulerer! Du har fullført treningsområdet,Gratulacje! Ukończył@[irreg_3_pl] trening,Parabéns! Você completou a área de treinamento,Parabéns! Completaste a área de treino,Felicitări! Ai încheiat cu zona de antrenament,Браво! Ты прошёл тренировку,Честитке! Завршио си тренинг подручје,Grattis! Du har avslutat träningsområdet,Tebrikler! Eğitim alanını tamamladınız,Вітаю! Ви пройшли курс тренувань +You've blown up the Crystal,TXT_QUEST_14,,,,Odpálil@[ao_cs] jsi krystal,Du ødelagde krystallen.,Du hast den Kristall zerstört.,,Vi eksplodigis la kristalon,Has volado el cristal,Volaste el cristal,Olet räjäyttänyt kristallin,Vous avez explosé le cristal!,Szétrobbantottad a kristályt,Hai fatto esplodere il Cristallo,クリスタルを爆破した,수정체를 파괴했다,Je hebt de Crystal opgeblazen.,Du har sprengt krystallen,Wysadził@[irreg_3_pl] Kryształ,Você explodiu o cristal,Explodiste o cristal,Ai aruncat în aer Cristalul,Кристалл взорван,Дигао си у ваздух кристал,Du har sprängt kristallen.,Kristali havaya uçurdun.,Ви підірвали кристал +You've blown up the Gates,TXT_QUEST_16,,,,Odpálil@[ao_cs] jsi brány,Du åbnede portene.,Du hast die Tore geöffnet.,,Vi detruis la pordegojn,Has destruido las puertas,Destruiste las puertas,Olet räjäyttänyt portit,Vous avez explosé les portes!,A levegőbe repítetted a kapukat,Hai fatto esplodere i Cancelli,ゲートを爆破した,성문을 파괴해서 열었다,Je hebt de Gates opgeblazen.,Du har sprengt portene,Wysadził@[irreg_3_pl] Bramy,Você explodiu as portões,Explodiste os portões,Ai aruncat în aer Porțile,Ворота взорваны,Дигао си у ваздух капију,Du har sprängt portarna.,Kapıları havaya uçurdun.,Ви підірвали ворота +You've blown up the Computer,TXT_QUEST_27,,,,Odpálil@[ao_cs] jsi počítač,Du har ødelagt computeren.,Du hast den Computer zerstört.,,Vi detruis la komputilon,Has destruido el ordenador,Destruiste la computadora,Olet räjäyttänyt tietokoneen,Vous avez explosé l'ordinateur!,Felrobbantottad a számítógépet,Hai fatto esplodere il Computer,コンピューターを爆破した,컴퓨터를 파괴했다,Je hebt de computer opgeblazen.,Du har sprengt Datamaskinen,Wysadził@[irreg_3_pl] Komputer,Você explodiu o computador,Explodiste o computador,Ai aruncat în aer Calculatorul,Компьютер взорван,Дигао си у ваздух компјутер,Du har sprängt datorn.,Bilgisayarı havaya uçurdun.,Ви підірвали комп'ютер +You killed the Bishop!,TXT_KILLED_BISHOP,,,,Zabil@[ao_cs] jsi Biskupa!,Du har dræbt biskoppen!,Du hast den Bischof getötet.,,Vi mortigis la Episkopon!,¡Has matado al Obispo!,¡Mataste al Obispo!,Olet tappanut Piispan!,Vous avez tué l'évèque!,Megölted a Püspököt!,Hai ucciso il Vescovo!,ビショップを殺した!,비숍을 사살했다!,Je hebt de bisschop vermoord!,Du har drept Biskopen!,Zabił@[irreg_3_pl] Biskupa!,Você matou o Bispo!,Mataste o Bispo!,Ai omorât Episcopul!,Епископ убит!,Епископ је мртав!,Du har dödat biskopen!,Piskoposu öldürdün!,Єпископа вбито! +You've killed the Oracle!,TXT_KILLED_ORACLE,,,,Zabil@[ao_cs] jsi Věštce!,Du har dræbt Oraklet!,Du hast das Orakel getötet,,Vi mortigis la Orakolon!,¡Has matado al Oráculo!,¡Mataste al Oráculo!,Olet tappanut Oraakkelin!,Vous avez tué l'oracle!,Megölted az Orákulumot!,Hai ucciso l'Oracolo!,オラクルの予言を覆した!,오라클의 음모를 막았다!,Je hebt het Orakel vermoord!,Du har drept Oraklet!,Zabił@[irreg_3_pl] Wyrocznię!,Você matou o Oráculo!,Mataste o Oráculo,Ai omorât Oracolul!,Оракул убит!,Пророк је мртав!,Du har dödat oraklet!,Kahini öldürdün!,Оракула вбито! +You killed Macil!,TXT_KILLED_MACIL,,,,Zabil@[ao_cs] jsi Macila!,Du har dræbt Macil!,Du hast Macil getötet.,,Vi mortigis Macil-on!,¡Has matado a Macil!,¡Mataste a Macil!,Tapoit Macilin!,Vous avez tué Macil!,Megölted Macilt!,Hai ucciso Macil!,マシルを討ち取った!,마실을 처단했다!,Je hebt Macil vermoord!,Du har drept Macil!,Zabił@[irreg_3_pl] Macila!,Você matou o Macil!,Mataste Macil!,L-ai omorât pe Macil!,Мэйсил убит!,Мејсил је мртав!,Du har dödat Macil!,Macil'i öldürdün!,Масіла вбито! +You've killed the Loremaster!,TXT_KILLED_LOREMASTER,,,,Zabil@[ao_cs] jsi Dějepisce!,Du har dræbt Loremesteren!,Du hast den Wissensmeister getötet!,,Vi mortigis la Folkloriston!,"¡Has matado al +Maestro del Conocimiento!","¡Mataste al +Maestro del Conocimiento!",Olet tappanut Oppi-Isän!,Vous avez tué le Maitre des traditions!,Megölted a Tudóst!,Hai ucciso il Sapiente!,ロアマスターを吊り上げた!,로어마스터의 목숨에 종지부를 찍었다!,Je hebt de Kennismeester vermoord!,Du har drept Loremaster!,Zabił@[irreg_3_pl] Mędrca!,Você matou o Mestre do Conhecimento!,Mataste o Mestre do Conhecimento!,L-ai omorât pe Maestrul Cunoștințelor!,Хранитель мудрости убит!,Чувара мудрости је мртав!,Du har dödat Läromästaren!,Loremaster'ı öldürdün!,Хранителя мудрості вбито! +You fool! You've set off the alarm.,TXT_YOUFOOL,,,,Blázne! Spustil@[ao_cs] jsi alarm!,Dit fjols! Du har udløst alarmen.,Du Trottel! Du hast den Alarm ausgelöst.,,"Stultulo! +Vi ekigis la alarmon.","¡Insensat@[ao_esp]! +Has activado la alarma.","¡Tont@[ao_esp]! +Activaste la alarma.",Sinä mieletön! Olet laukaissut hälytyksen.,Vous êtes fou! Vous avez activé l'alarme!,Te barom! Beindítottad a riasztót.,Stolto! Hai fatto scattare l'allarme.,バカな真似を! 警報を鳴らしてしまった。,어리석은 것! 알람이 작동되었다고!,Jij dwaas! Je hebt het alarm laten afgaan.,Din idiot! Du har utløst alarmen.,Głupcze! Włączył@[irreg_3_pl] alarm!,Seu idiota! Você ativou o alarme.,Idiota! Ativaste o alarme.,Nesăbuitule! Ai declanșat alarma!,Глупец. Ты привёл в действие сигнализацию!,Будало! Активирао си аларм.,Din idiot! Du har utlöst larmet.,Seni aptal! Alarmı çalıştırdın.,Дурень! Ти активував тривогу. +You're dead! You set off the alarm.,TXT_YOUREDEAD,,,,Jsi mrtv@[adj_cs]! Spustil@[ao_cs] jsi alarm!,Du er død! Du udløste alarmen.,Du bist tot. Du hast den Alarm ausgelöst.,,"Vi estas mortinta! +Vi ekigis la alarmon.","¡Estás muert@[ao_esp]! +Has activado la alarma.","¡Estás muert@[ao_esp]! +Activaste la alarma.",Sinä kuolet! Laukaisit hälytyksen.,Vous êtes mort! Vous avez activé l'alarme!,Beindult a riasztó. Halott vagy!,Sei morto! L'allarme è scattato.,絶望的だ! 警報を鳴らしてしまった。,알람이 작동되었다. 넌 죽었어!,Je bent dood! Je hebt het alarm laten afgaan.,Du er død! Du utløste alarmen.,Już nie żyjesz! Włączył@[irreg_3_pl] alarm!,Você está mort@[ao_ptb]! Você ativou o alarme.,Estás mort@[ao_ptb]! Ativaste o alarme.,Ești mort! AI declanșat alarma!,Ты поднял тревогу! Готовься к смерти!,Активирао си аларм. Спреми се да умреш!,Du är död! Du utlöste larmet.,Sen öldün! Alarmı çalıştırdın.,Ти труп! Тривогу активовано. +You seem to have enough!,TXT_HAVEENOUGH,,,,Ty už máš přece dost!,Du ser ud til at have nok!,Du scheinst genug zu haben.,,Vi ŝajnas havi sufiĉe!,¡Se ve que tienes suficiente!,,Sinulla näyttää olevan tarpeeksi!,Vous avez l'air d'en avoir assez!,Úgy néz ki eleged van már!,Sembri averne abbastanza!,十分に持ち合わせている!,충분히 가진 것 같은데?,Je lijkt genoeg te hebben!,Du har visst fått nok!,"Wydaje się, że już ci wystarczy!",Você parece ter o suficiente!,Pareces ter o suficiente!,Pare că ai destule!,"Кажется, тебе хватит!",Изгледа да ти је доста!,Du verkar ha fått nog!,Yeterince var gibi görünüyor!,"Здається, тобі досить!" +Go away!,TXT_GOAWAY,,,,Jdi pryč!,Gå væk!,Verschwinde!,,Foriru!,¡Lárgate!,,Häivy!,Allez-vous en!,Takarodj!,Vattene via!,逃げ出せ!,저리 가!,Ga weg!,Forsvinn!,Idź stąd!,Vá embora!,Vai-te embora!,Pleacă!,Уходи!,Одлази!,Gå härifrån!,Git başımdan!,Йди геть! +Incoming Message...,TXT_COMM0,,,,Příchozí zpráva...,Indkommende besked...,Nachricht erhalten...,,Alvenas mesaĝo...,Mensaje entrante...,,Vastaantuleva viesti...,Message reçu.,Bejövő Üzenet...,Messaggio in arrivo...,メッセージが届いた...,메시지가 옴...,Inkomend bericht....,Innkommende melding...,Nadchodzi wiadomość...,Recebendo Mensagem...,A Receber Mensagem...,Mesaj în intrare...,Входящее сообщение...,Наилази порука...,Inkommande meddelande...,Gelen Mesaj...,Вхідне повідомлення... +Incoming Message from BlackBird...,TXT_COMM1,,,,Příchozí zpráva od Straky...,Indkommende besked fra BlackBird...,Nachricht von Blackbird erhalten...,,Alvenas mesaĝo de Merlo...,Mensaje entrante de Blackbird...,,Vastaantuleva viesti Blackbirdiltä...,Message reçu de BlackBird,Bejövő Üzenet Feketerigótól...,Messaggio in arrivo da Blackbird...,ブラックバードからのメッセージが届いた...,블랙버드로부터 메시지가 옴...,Inkomend bericht van BlackBird....,Innkommende melding fra BlackBird...,Nadchodzi wiadomość od BlackBird...,Recebendo Mensagem de BlackBird...,A Receber Mensagem de BlackBird...,Mesaj în intrare de la BlackBird...,Входящее сообщение от «Чёрного дрозда»...,Наилази порука од Црне птице....,Inkommande meddelande från BlackBird...,Gelen Mesaj...,Вхідне повідомлення від Чорного Дрозда... +Find help,TXT_FINDHELP,,,,Najdi pomoc.,Find hjælp,Finde Hilfe,,Trovu helpon.,Busca ayuda.,,Etsi apua,Trouvez de L'aide,Keress segítséget,Trova aiuto,助けを探せ,도움말,Zoek hulp,Finn hjelp,Znajdź pomoc,Procure ajuda,Procura ajuda,Găsește ajutor,Найди помощь,Нађи помоћ,Hitta hjälp,Yardım bul,Знайди допомогу +for %u,TXT_TRADE,As in for %u amount of money.,,,za %u zlatých,til %u,für %u,,kontraŭ %u da oro.,por %u de oro.,,hintaan %u,pour %u,%u számára,per %u,%u ゴールド,(가격: %u),voor %u,til %u,za %u,por %u,,pentru %u,за %u,за %u,för %u,için %u,за %u +,,Chex Quest,,,,,,,,,,,,,,,,,,,,,,,,,, +,,Pickups,,,,,,,,,,,,,,,,,,,,,,,,,, +Picked up the Chex(R) Armor.,GOTCHEXARMOR,,,Picked up the Chex(R) Armour.,Sebráno Chex(R) brnění.,Hentede Chex(R) Rustning.,Du hast die Chex(R) Rüstung genommen,,Prenis la Chex(R)-kirason.,Recogiste la Armadura Chex(R).,,Poimit Chex(R)-panssarin.,Vous avez pris l'armure Chex(R).,Felvettél egy Chex(R) páncélt.,Raccolta un'Armatura Chex(R).,チェックス(R)アーマー をてにいれた。,첵스(R) 갑옷 획득.,Je hebt het Chex(R) harnas opgepakt.,Plukket opp Chex(R) Armor.,Zebrano Pancerz Chex(R).,Pegou uma Armadura Chex(R).,Apanhaste uma Armadura Chex(R).,Ai ridicat Armura Chex(R).,Получена Chex(R)-броня.,Покупио си Чех оклоп.,Plockade upp Chex(R) rustningen.,Chex(R) Zırhı'nı aldım.,Взято Chex(R) броню. +Picked up the Super Chex(R) Armor!,GOTSUPERCHEXARMOR,,,Picked up the Super Chex(R) Armour!,Sebráno Super Chex(R) brnění!,Hentede Super Chex(R) Rustning!,Du hast die Superchex(R)Rüstung genommen!,,Prenis la superan Chex(R)-kirason!,¡Recogiste la Súper-Armadura Chex(R)!,,Poimit Super-Chex(R)-panssarin!,Vous avez pris la super armure Chex(R)!,Felvettél egy szuper Chex(R) páncélt!,Raccolta la Super Armatura Chex(R)!,スーパーチェックス(R)アーマー をてにいれた。,슈퍼 첵스(R) 갑옷 획득!,Je hebt het Super-Chex(R) harnas opgehaald!,Plukket opp Super Chex(R) Armor!,Zebrano Super Pancerz Chex(R)!,Pegou uma Super Armadura Chex(R)!,Apanhaste uma Super Armadura Chex(R)!,Ai ridicat Super Armura Chex(R)!,Получена Chex(R)-сверхброня!,Покупио си Супер Чех оклоп.,Plockade upp Super Chex(R) rustningen!,Süper Chex(R) Zırhı'nı aldı!,Взято Chex(R) супер броню! +Picked up a glass of water.,GOTWATER,,,,Sebrána sklenice vody.,Samlede et glas vand op.,Du hast ein Glas Wasser genommen.,,Prenis glason de akvo.,Recogiste un vaso de agua.,,Poimit vesilasin.,Vous avez pris un verre d'eau.,Felvettél egy pohár vizet.,Raccolto un bicchiere d'acqua.,コップいっぱいの みずをひろった。,물 한 컵 섭취.,Je hebt een glas water opgepakt.,Hentet et glass vann.,Zebrano szklankę wody.,Pegou um copo d'água.,Apanhaste um copo de água.,Ai ridicat un pahar cu apă.,Получен стакан воды.,Покупио си чашу воде,Plockade upp ett glas vatten.,Bir bardak su aldım.,Взято стакан води. +Picked up slime repellent.,GOTREPELLENT,,,,Sebrán repelent proti slizu.,Hentede slimafvisende middel.,Du hast das Schleimabwehrmittel genommen.,,Prenis mukforigilon.,Recogiste un repelente de baba.,,Poimit limakarkotteen.,Vous avez pris de la chaux répulsive.,Felvettél egy nyálkataszítót.,Raccolto del repellente allo slime.,スライム はんぱつざい をひろった。,오물 방수제 획득.,Je hebt de slijmafstotende stof opgepakt.,Plukket opp slime repellent.,Zebrano odstraszacz szlamu.,Pegou repelente de gosma.,Apanhaste repelente de gosma.,Ai ridicat respingătorul de mâzga.,Получен репеллент от слизи.,Покупио си одбијаш љигавца.,Plockade upp ett slemavvisande medel.,Balçık kovucu aldım.,Взято репелент проти слизняків. +Supercharge Breakfast!,GOTBREAKFAST,,,,Supervýživná snídaně!,Supercharge Morgenmad!,Überladenes Frühstück!,,Ŝargega Matenmanĝon!,¡Desayuno supercargado!,,Superaamiaislatinki!,Petit-déjeuner superchargé!,Szupertöltött Reggeli!,Colazione da supercarica!,ちょうしょく スーパーチャージ!,힘찬 아침식사 섭취!,Overbelast ontbijt!,Superladet frokost!,Supernaładowane Śniadanie!,Super Café da Manhã!,Super Pequeno-Almoço!,Superîncărcătură Mic Dejun!,Завтрак из сверхзаряда!,Супер-напуњен доручак.,Supercharge frukost!,Süper Şarjlı Kahvaltı!,Суперзаряджений сніданок! +Picked up a blue key.,GOTCBLUEKEY,,,,Sebrán modrý klíč.,Samlede en blå nøgle op.,Du hast einen blauen Schlüssel genommen.,,Prenis bluan ŝlosilon.,Recogiste una llave azul.,,Poimit sinisen avaimen.,Vous avez pris une clé bleue.,Felvettél egy kék kulcsot.,Raccolta una chiave blu.,あお のかぎ をひろった。,파란색 열쇠 획득.,Je hebt een blauwe sleutel opgepakt.,Plukket opp en blå nøkkel.,Zebrano niebieski klucz.,Pegou a chave azul.,Apanhaste a chave azul.,Ai ridicat o cheie albastră.,Получен синий ключ.,Покупио си плави кључ.,Plockade upp en blå nyckel.,Mavi bir anahtar aldı.,Взято синій ключ. +Picked up a yellow key.,GOTCYELLOWKEY,,,,Sebrán žlutý klíč.,Samlede en gul nøgle op.,Du hast einen gelben Schlüssel genommen.,,Prenis ruĝan ŝlosilon.,Recogiste una llave amarilla.,,Poimit keltaisen avaimen.,Vous avez pris une clé jaune.,Felvettél egy sárga kulcsot.,Raccolta una chiave gialla.,きいろ のかぎ をひろった。,노란색 열쇠 획득.,Je hebt een gele sleutel opgepakt.,Plukket opp en gul nøkkel.,Zebrano żółty klucz.,Pegou a chave amarela.,Apanhaste a chave amarela.,Ai ridicat o cheie galbenă.,Получен жёлтый ключ.,Покупио си жути кључ.,Plockade upp en gul nyckel.,Sarı bir anahtar aldı.,Взято жовтий ключ. +Picked up a red key.,GOTCREDKEY,,,,Sebrán červený klíč.,Samlede en rød nøgle op.,Du hast einen roten Schlüssel genommen.,,Prenis flavan ŝlosilon.,Recogiste una llave roja.,,Poimit punaisen avaimen.,Vous avez pris une clé rouge.,Felvettél egy piros kulcsot.,Raccolta una chiave rossa.,あか のかぎ をひろった。,빨간색 열쇠 획득.,Je hebt een rode sleutel opgepakt.,Plukket opp en rød nøkkel.,Zebrano czerwony klucz.,Pegou a chave vermelha.,Apanhaste a chave vermelha.,Ai ridicat o cheie roșie.,Получен красный ключ.,Покупио си црвени кључ.,Plockade upp en röd nyckel.,Kırmızı bir anahtar aldı.,Взято червоний ключ. +Picked up a bowl of fruit.,GOTFRUIT,,,,Sebrána mísa s ovocem.,Samlede en skål med frugt op.,Du hast eine Obstschale genommen.,,Prenis bovlon de fruktoj.,Recogiste un tazón de fruta.,,Poimit hedelmäkulhon.,Vous avez pris un bol de fruits.,Felvettél egy tál gyümölcsöt.,Raccolto un vassoio di frutta.,フルーツのボウル をひろった。,과일 한 그릇 섭취.,Je hebt een fruitschaal opgepakt.,Plukket opp en bolle med frukt.,Zebrano miskę owoców.,Pegou uma tigela de frutas.,Apanhaste uma taça com fruta.,Ai ridicat un bol de fructe.,Получена тарелка с фруктами.,Покупио си чинију воћа.,Plockade upp en skål med frukt.,Bir kase meyve al.,Взято тарілку фруктів. +Vegetables are REALLY good for you!,GOTVEGETABLESNEED,,,,Zelenina je VELMI zdravá!,Grøntsager er VIRKELIG gode for dig!,Gemüse ist RICHTIG gut für dich!,,Legomoj estas TRE bonaj por vi!,¡Las verduras son REALMENTE buenas para ti!,,Vihannekset ovat TOSI terveellisiä!,Les légumes sont VRAIMENT bons pour vous!,A zöldségek NAGYON jót tesznek neked!,La verdura ti fa DAVVERO bene!,いま とってもひつような やさいのボウルだ!,채소의 건강한 영양분이 독 기운을 없앴습니다!,Groenten zijn echt goed voor je!,Grønnsaker er VIRKELIG bra for deg!,Warzywa są BARDZO dobre dla ciebie!,Vegetais fazem MUITO bem para você!,Os Vegetais são MUITO bons para ti!,Legumele sunt FOARTE bune pentru tine!,Овощи ОЧЕНЬ полезны для здоровья!,Поврће је ЈАКО добро за тебе!,Grönsaker är VÄLDIGT bra för dig!,Sebzeler sizin için GERÇEKTEN iyidir!,Овочі ДУЖЕ корисні для тебе! +Picked up a bowl of vegetables.,GOTVEGETABLES,,,,Sebrána mísa se zeleninou.,Samlede en skål med grøntsager op.,Du hast eine Gemüseschale genommen.,,Prenis bovlon de legomoj.,Recogiste un tazón de verduras.,,Poimit vihannesvadin.,Vous avez pris un bol de légumes.,Felvettél egy tál zöldséget.,Raccolto un vassoio di verdura.,やさいのボウル をひろった。,채소 한 그릇 섭취.,Je hebt een kom groenten opgepakt.,Plukket opp en bolle med grønnsaker.,Zebrano miskę warzyw.,Pegou uma tigela de vegetais.,Apanhaste uma tigela com vegetais.,Ai ridicat un bol de legume.,Получена тарелка с овощами.,Покупио си чинију поврћа.,Plockade upp en skål med grönsaker.,Bir kase sebze aldı.,Взято тарілку овочів. +Found a Slime-Proof Suit,GOTSLIMESUIT,,,,Nalezen slizu odolný oblek.,Fandt et slim-sikret jakkesæt,Du hast einen Schleimbeständigen Anzug gefunden,,Trovis mukimunan kompleton.,Encontraste un traje a prueba de baba.,,Löysit limaapitävän puvun,Combinaison pare-gelée,Felvettél egy nyálkaálló védőruhát,Raccolto un vestito a prova di slime,たい スライム スーツ をてにいれた。,오물 보호복 사용.,Je hebt een slijtvast pak opgepakt.,Fant en slimsikker drakt,Znaleziono Szlamoodporny Kombinezon,Achou um Traje Anti-Gosma,Apanhaste um Fato Anti-Gosma.,Ai ridicat un Costum Rezistent la Mâzgă,Получен противослизневый костюм,Нашо си љигаво-отпорано одело.,Hittade en slimsäker kostym,Balçık Geçirmez Takım Elbise Buldum,Взято протислизнячий костюм +Found a Computer Area Map,GOTCHEXMAP,,,,Nalezena počítačová mapa oblasti.,Fandt et kort over et computerområde,Du hast eine Computerkarte gefunden,,Trovis komputilan regionmapon.,Encontraste un mapa computarizado del área.,,Löysit alueen tietokonekartan,Vous avez trouve une carte informatique de la zone.,Felvettél egy Számítógépes Térképet,Trovata una mappa computerizzata,コンピューターエリアマップ をてにいれた。,컴퓨터 지도 사용.,Je hebt een computerkaart opgepakt.,Fant et datamaskinkart,Znaleziono Komputerową Mapę Obszaru,Achou um Mapa Computadorizado,Apanhaste um Mapa Digital.,Ai ridicat o Hartă Generată pe Calculator a Zonei.,Получена компьютерная карта местности,Нашао компјутерку мапу окружења,Hittade en karta över datorområdet,Bilgisayar Alanı Haritası Bulundu,Знайдено комп'ютерну карту району +Picked up a mini zorch recharge.,GOTZORCHRECHARGE,,,,Sebrán minibzukový náboj.,Samlede en mini zorch-opladning op.,Du hast eine Minizorcher-Ladung genommen.,,Prenis zorĉreŝargeton.,Recogiste una recarga de mini zorch.,,Poimit minizorchlatauksen.,Vous avez pris une mini recharge zorch.,Felvettél egy Mini Zorker Újratöltőt,Raccolta una ricarica di mini zorch.,ミニゾーチ リチャージ をひろった。,소형 저치 전지 획득.,Je hebt een minizorcherlading opgepakt.,Plukket opp en mini zorch-opplading.,Zebrano mini ładunek zorch.,Pegou recarga para mini zorch.,Apanhaste uma recarga para o mini zorch.,Ai ridicat o mini încărcătură pentru zorch.,Получена зарядка мини-зорчера.,Покупио си мини зорч пуњач.,Plockade upp en mini zorch-uppladdning.,Mini bir Zorch şarjı aldım.,Взято заряд міні-Зорчера. +Picked up a mini zorch pack.,GOTMINIZORCHPACK,,,,Sebrán minibzukový balík.,Afhentede en mini zorch-pakke.,Du hast ein Minizorcher-Ladepaket genommen.,,Prenis zorĉpaketon,Recogiste un paquete de mini zorch.,,Poimit minizorchpaketin.,Vous avez pris un pack de mini recharges zorch.,Felvettél egy Mini Zorker Csomagot,Raccolta una scatola di mini zorch.,ミニゾーチ パック をひろった。,저치 전지 박스 획득.,Je hebt een pakket met minizorcherladingen opgepakt.,Plukket opp en mini zorch-pakke.,Zebrano mini paczkę zorch.,Pegou um pacote de recargas de mini zorch.,Apanhaste um pagcote de recargas para o mini zorch.,Ai ridicat un mini patchet de încărcătură pentru zorch.,Получена батарея мини-зорчера.,Покупио си мини зорч пакет.,Plockade upp en mini zorch pack.,Mini bir Zorch paketi aldım.,Взято батарею для міні-Зорчера. +Picked up a zorch propulsor recharge.,GOTPROPULSORRECHARGE,,,,Sebrán náboj pro bzukový propulzor.,Afhentede en zorch propulsor opladning.,Du hast eine Propeller-Ladung genommen.,,Prenis zorĉpropulsilo-reŝargon.,Recogiste una recarga de propulsor de zorch.,,Poimit zorchtyöntimen latauksen.,Vous avez pris une recharge propulseur zorch.,Felvettél egy Zork Elhárító Újratöltőt,Raccolta una ricarica di zorch a propulsione.,ゾーチプロパルサーリチャージ をひろった。,저치 추진료 획득.,Je hebt een propulsorlading opgepakt.,Plukket opp en zorch propulsor-opplading.,Zebrano ładunek do pędnika zorch.,Pegou recarga para propulsor de zorch.,Apanhaste recarga para o propulsor de zorch.,Ai ridicat o încărcătură pentru acceleratorul zorch.,Получена зарядка ускорителя зорча.,Покупио си зорч погонски пуњач.,Plockade upp en zorch propulsoruppladdning.,Bir Zorch itici şarjı aldı.,Взято заряд Зорч-прискорювача. +Picked up a zorch propulsor pack.,GOTPROPULSORPACK,,,,Sebrán balík pro bzukový propulzor.,Afhentede en zorch propulsorpakke.,Du hast ein Propeller-Ladepaket genommen.,,Prenis zorĉpropulsilo-pakon.,Recogiste un paquete de propulsor de zorch.,,Poimit zorchtyöntimen paketin.,Vous avez pris un paquet propulseur zorch.,Felvettél egy Zork Elhárító Csomagot,Raccolta una scatola di zorch a propulsione.,ゾーチプロパルサーパック をひろった。,저치 추진 팩 획득.,Je hebt een pakket met propulsorladingen opgepakt.,Plukket opp en zorch fremdriftspakke.,Zebrano paczkę pędnika zorch.,Pegou um pacote de recargas para propulsor de zorch.,Apanhaste um pacote de recargas para o propulsor de zorch,Ai ridicat un pachet de baterii pentru acceleratorul zorch.,Получена батарея ускорителя зорча.,Покупио си зорч погонски пакет.,Plockade upp en zorch propulsor pack.,Bir Zorch itici paketi aldı.,Взято батарею Зорч-прискорювача. +Picked up a phasing zorcher recharge,GOTPHASINGZORCHERRECHARGE,,,,Sebrán náboj pro fázovací bzukr.,Afhentede en zorcher-opladning til faseopladning.,Du hast eine Phasenzorcher-Ladung genommen.,,Prenis fluktuantzorĉilo-reŝargon.,Recogiste una recarga de zorch de fase.,,Poimit vaiheiszorcherin latauksen.,Vous avez pris une recharge zorch phasée.,Felvettél egy Fázis Zorker Újratöltőt,Raccolta una ricarica per zorcher a phasing,フェイシング ゾーチャーリチャージ をひろった。,저치 전자 충전기 획득.,Je hebt een phasenzorcherlading opgepakt.,Plukket opp en fasing zorcher oppladning.,Zebrano ładunek do fazowego zorchera.,Pegou recarga para zorcher fásico.,Apanhaste recarga para o zorcher fásico,Ai ridicat o încărcătură fazată pentru zorcher,Получена зарядка фазерного зорчера.,Покупио си фазни зорчер пуњач.,Plockade upp en phasing zorcher-uppladdning.,Bir faz zorcher şarjı aldı,Взято заряд фазового Зорчера. +Picked up a phasing zorcher pack.,GOTPHASINGZORCHERPACK,,,,Sebrán balík pro fázovací bzukr.,Afhentede en phasing zorcher-pakke.,Du hast ein Phasenzorcher-Ladepaket genommen.,,Prenis fluktuantzorĉilo-pakon.,Recogiste un paquete de zorch de fase.,,Poimit vaiheiszorcherin paketin.,Vous avez pris un pack de recharges zorch phasée.,Felvettél egy Fázis Zorker Csomagot,Raccolta una scatola per zorcher a phasing.,フェイシング ゾーチャーパック をひろった。,특대 저치 충전기 획득.,Je hebt een pakket met phasenzorcherladingen opgepakt.,Plukket opp en fasing zorcher-pakke.,Zebrano paczkę fazowego zorchera.,Pegou um pacote de recargas para zorcher fásico.,Apanhaste um pacote de recargas para o zorcher fásico,"Ai ridicat un pachet de încărcături fazate pentru +zorcher.",Получена батарея фазерного зорчера.,Покупио си фазни зорчер пакет.,Plockade upp en phasing zorcher pack.,Bir faz zorcher paketi aldım.,Взято батарею фазового Зорчера. +Picked up a large zorcher recharge.,GOTLARGEZORCHERRECHARGE,,,,Sebrán náboj pro velký bzukr.,Afhentede en stor zorcher-opladning.,Du hast eine Zorcher-Ladung genommen.,,Prenis grandzorĉilo-reŝargon.,Recogiste una gran recarga de zorch.,,Poimit ison zorcherin latauksen,Vous avez pris une recharge pour zorcheur large.,Felvettél egy Nagy Zorker Újratöltőt,Raccolta una ricarica per zorcher grande.,ラージ ゾーチャーリチャージ をひろった。,대형 저치 카트리지 획득.,Je hebt een zorcherlading opgepakt.,Plukket opp en stor zorcher-opplading.,Zebrano ładunek do dużego zorchera.,Pegou recarga para zorcher grande.,Apanhaste recarga para o zorcher grande.,Ai ridicat o încărcătură mare pentru zorcher.,Получена зарядка большого зорчера.,Покупио си велики зорчер пуњач.,Plockade upp en stor zorcher-uppladdning.,Büyük bir zorcher şarjı aldım.,Взято заряд великого Зорчера. +Picked up a large zorcher pack.,GOTLARGEZORCHERPACK,,,,Sebrán balík pro velký bzukr.,Afhentede en stor zorcher-pakke.,Du hast ein Zorcher-Ladepaket genommen.,,Prenis grandegzorĉilo-reŝargon.,Recogiste un gran paquete de zorch.,,Poimit ison zorcherin paketin.,Vous avez pris un pack de recharges pour zorcheur large.,Felvettél egy Nagy Zorker Csomagot,Raccolta una scatola per zorcher grande.,ラージ ゾーチャーパック をひろった。,저치 카트리지 묶음 획득.,Je hebt een pakket met zorcherladingen opgepakt.,Plukket opp en stor zorcherpakke.,Zebrano paczkę dużego zorchera.,Pegou um pacote de recargas para zorcher grande.,Apanhaste um pacote de recargas para o zocher grande.,Ai ridicat un pachet mare de încărcături pentru zorcher.,Получена батарея большого зорчера.,Покупио си велики зорчер пакет.,Plockade upp ett stort zorcherpaket.,Büyük bir zorcher paketi aldı.,Взято батарею великого Зорчера. +Picked up a Zorchpak!,GOTZORCHPACK,,,,Sebrán Bzukrbatoh!,Afhentede en Zorchpak!,Du hast ein Zorchpaket genommen.,,Prenis Zorĉpakon!,¡Recogiste un Zorchpak!,,Poimit zorchpakin!,Vous avez pris un zorchpak!,Felvettél egy Zorkpakkot!,Raccolto uno ZorchZaino!,ゾーチパックをてにいれた!,저치 팩 획득!,Je hebt en zorchpak opgepakt.,Plukket opp en Zorchpak!,Zebrano Paczkę Zorch.,Pegou um Zorchpak!,Apanhaste um Zorchpak!,Ai ridicat un Ghiozdan Zorch!,Получен зорч-рюкзак!,Покупио си зорчпак.,Jag hämtade en Zorchpak!,Bir Zorchpak aldım!,Взято Зорч-сумку! +You got the LAZ Device! Woot!,GOTLAZDEVICE,,,,Získal@[ao_cs] jsi velkodosahový bzukr! Cooo?,Du fik LAZ-enheden! Woot!,Du hast den Flächenzorcher!,,Vi prenis la LAZ-aparaton! Hura!,¡Tienes el dispositivo LAZ! ¡Yuju!,,Sait SAZ-laitteen! Juhuu!,Vous avez pris l'Outil ZZL! Wahou!,Felvetted a LAZ Készüléket! Wáó!,Hai trovato il dispositivo LAZ! Cavolo!,LAZ デバイスをてにいれた! ワァオ!,LAZ 장치 습득! 완전 짱인걸!,Je hebt het LAZ-apparaat! Woot!,Du har LAZ-enheten! Woot!,Zdobył@[irreg_3_pl] urządzenie LAZ! Juhu!,Você achou o Dispositivo LAZ! Oba!,Apanhaste um Dispositivo LAZ! Fixe!,Ai ridicat un Dispozitiv LAZ! Uraa!,Получено устройство зорчирования большого радиуса! Ура!,Добио си ЛАЗ уређај. ВУТ!,Du fick LAZ-enheten! Woot!,LAZ cihazını aldın! Woot!,Ти отримав пристрій LAZ! Супер! +You got the Rapid Zorcher!,GOTRAPIDZORCHER,,,,Získal@[ao_cs] jsi rychlobzukr!,Du fik en Rapid Zorcher!,Du hast den schnellen Zorcher genommen!,,Vi prenis la Rapidzorĉilon!,¡Tienes el Zorcher Rápido!,,Sait pikazorcherin!,Vous avez pris le Zorcheur Rapide!,Felvetted a Gyors Zorkert!,Hai trovato il zorcher rapido!,ラピッドゾーチャー をてにいれた!,속사 자쳐 습득!,Je hebt de snelle Zorcher!,Du har Rapid Zorcher!,Zdobył@[irreg_3_pl] Szybkostrzelny Zorcher!,Você pegou o Zorcher Automático!,Apanhaste o Zorcher Automático!,Ai ridicat un Zorcher cu Foc Rapid!,Получен скорострельный зорчер!,Добио си рапидан зорчер!,Du fick den snabba Zorcher!,Hızlı Zorcher'ı aldın!,Ти отримав Авто Зорчер! +You got the Super Bootspork!,GOTSUPERBOOTSPORK,,,,Získal@[ao_cs] jsi super botovidličku!,Du fik Super Bootspork!,Du hast den Super-Gabelquirl genommen!,,Vi prenis la Superan Ŝargmanĝilaron!,¡Tienes el Súper Cuchador!,,Sait superluhan!,Vous avez pris la Super Fourchette!,Felvetted a Szuper Rotációs Villát!,Hai trovato il super bootspork!,スーパーさきわれスプーン をてにいれた!,부트스포크 습득!,Je hebt de Super Bootspork!,Du har Super Bootspork!,Zdobył@[irreg_3_pl] Super Łyżkowidelec!,Você pegou o Super Garfo!,Apanhaste o Super Garfo-Colher!,Ai ridicat o Super Lingură!,Получена суперложковилка!,Добио си супер чизмо-порк!,Du fick Super Bootspork!,Süper Bootspork'u aldın!,Ти отримав Супер Вилколожку! +You got the Zorch Propulsor!,GOTZORCHPROPULSOR,,,,Získal@[ao_cs] jsi bzukový propulsor!,Du fik Zorch-propulsoren!,Du hast den Propellerzorcher genommen!,,Vi prenis la Zorĉpropulsilon!,¡Tienes el Propulsor de Zorch!,,Sait zorchtyöntimen!,Vous avez pris le Propulseur Zorch!,Felvetted a Zork Elhárítót!,Hai trovato il propulsore zorch!,ロケット ゾーチャー をてにいれた!,저치 추진기 습득!,Je hebt de Zorch Propulsor!,Du fikk Zorch Propulsor!,Zdobył@[irreg_3_pl] Pędnik Zorch!,Você pegou o Propulsor de Zorch!,Apanhaste o Propulsor de Zorch!,Ai ridicat un Accelerator Zorch!,Получен ускоритель хорча!,Добио си зорч погон!,Du fick Zorch Propulsor!,Zorch Propulsor'u aldın!,Ти отримав Зорч-Двигун! +You got the Phasing Zorcher!,GOTPHASINGZORCHER,,,,Získal@[ao_cs] jsi fázovací bzukr!,Du fik Phasing Zorcher!,Du hast den Phasenzorcher genommen!,,Vi prenis la Fluktuantzorĉilon!,¡Tienes el Zorcher de Fase!,,Sait vaiheiszorcherin!,Vous avez pris le Zorcheur phasé!,Felvetted a Fázis Zorkert!,Hai trovato il zorcher a phasing!,フェイシング ゾーチャー をてにいれた!,전자 자쳐 습득!,Je hebt de Fasezorcher!,Du har Phasing Zorcher!,Zdobył@[irreg_3_pl] Fazowy Zorcher!,Você pegou o Zorcher Fásico!,Apanhaste o Zorcher Fásico!,Ai ridicat un Zorcher Fazat!,Получен фазерный зорчер!,Добио си фазни зорчер!,Du fick Fasande Zorcher!,Fazlama Zorcher'ı aldın!,Ти отримав Прискорений Зорчер! +You got the Large Zorcher!,GOTLARGEZORCHER,,,,Získal@[ao_cs] jsi velký bzukr!,Du fik den store Zorcher!,Du hast den großen Zorcher genommen!,,Vi prenis la Grandzorĉilon,¡Tienes el Zorcher Grande!,,Sait ison zorcherin!,Vous avez pris le Zorcheur Large!,Felvetted a Nagy Zorkert!,Hai trovato il zorcher grande!,おおがたゾーチャー をてにいれた!,대형 자쳐 습득!,Je hebt de grote Zorcher!,Du har den store Zorcher!,Zdobył@[irreg_3_pl] Duży Zorcher!,Você pegou o Zorcher Grande!,Apanhaste o Zorcher Grande!,Ai ridicat un Zorcher Mare!,Получен большой зорчер!,Добио си велики зорчер!,Du har den stora Zorcher!,Büyük Zorcher'ı aldınız!,Ти отримав Великий Зорчер! +You got the Mega Zorcher!,GOTSUPERLARGEZORCHER,,,,Získal@[ao_cs] jsi megabzukr!,Du fik Mega Zorcher!,Du hast den Megazorcher genommen!,,Vi prenis la Grandegzorĉilon!,¡Tienes el Mega Zorcher!,,Sait megazorcherin!,Vous avez pris le méga Zorcheur!,Felvetted a Mega Zorkert!,Hai trovato il mega zorcher!,ちょうおおがたゾーチャー をてにいれた!,초대형 자쳐 습득!,Je hebt de Megazorcher!,Du har Mega Zorcher!,Zdobył@[irreg_3_pl] Mega Zorcher!,Você pegou o Mega Zorcher!,Apanhaste o Mega Zorcher!,Ai ridicat un Mega Zorcher!,Получен мегазорчер!,Добио си мега зорчер!,Du har Mega Zorcher!,Mega Zorcher'ı aldın!,Ти отримав Мега Зорчер! +Picked up a Mini Zorcher.,GOTMINIZORCHER,,,,Sebrán minibzukr.,Du har fået en Mini Zorcher.,Du hast einen Minizorcher genommen.,,Prenis Zorĉileton.,Recogiste un Mini Zorcher,,Poimit minizorcherin.,Vous avez pris le Mini Zorcheur.,Felvettél egy Mini Zorkert.,Raccolto un mini zorcher.,こがたゾーチャー をてにいれた。,소형 자쳐 습득.,Je hebt een minizorcher opgepakt.,Plukket opp en Mini Zorcher.,Zebrano Mini Zorcher.,Você pegou um Mini Zorcher.,Apanhaste um Mini Zorcher.,Ai ridicat un Mini Zorcher.,Получен мини-зорчер.,Покупио си мини зорчер!,Du fick en Mini Zorcher.,Bir Mini Zorcher aldın.,Ти отримав Міні Зорчер. +,,Actor tags,,,,,,,,,,,,,,,,,,,,,,,,,, +Spoon,TAG_SPOON,,,,Lžíce,Ske,Löffel,,Kulero,Cuchara,,Lusikka,Cuillère à Botte,Kanál,Cucchiaio ,スプーン,숟가락,Lepel,Skje,Łyżka,Colher,,Lingură,Ложка,Кашика,Sked,Kaşık,Ложка +Super Bootspork,TAG_SPORK,,,,Super botodlička,,Supergabel,,Ega Ŝargmanĝilaro,Súper Cuchador,,Superluha,Super Fourchette,Szuper Rotációs Villa,Super Forcucchiaio,スーパーさきわれスプーン,부트스포크,,,Super Łyżkowidelec,Super Garfo,Super Garfo-Colher,Super Lingură,Суперложковилка,Супер виљушка,Super Bootspork,Süper Bootspork,Супер Вилколожка +Mini Zorcher,TAG_MINIZORCHER,,,,Minibzukr,,Minizorcher,,Zorĉileto,,,Minizorcheri,Mini Zorcheur,Mini Zorker,,こがたゾーチャー,소형 자쳐,Minizorcher,,,Mini Zorcher,,,Мини-зорчер,Мини зорчер,,,Міні Зорчер +Large Zorcher,TAG_LARGEZORCHER,,,,Velký bzukr,Stor Zorcher,Großer Zorcher,,Granda Zorĉilo,Zorcher Grande,,Iso zorcheri,Zorcheur Large,Nagy Zorker,Grosso Zorcher ,おおがたゾーチャー,대형 자쳐,Grote Zorcher,Stor Zorcher,Duży Zorcher,Zorcher Grande,,Zorcher Mare,Большой зорчер,Велики зорчер,Stor Zorcher,Büyük Zorcher,Великий Зорчер +Super-Large Zorcher,TAG_SUPERLARGEZORCHER,,,,Supervelký bzukr,Super-stor Zorcher,Riesenzorcher,,Grandega Zorĉilo,Zorcher Súper Grande,,Superiso zorcheri,Zorcheur Extra-large,Hatalmas Zorker,Zorcher Enorme ,ちょうおおがたゾーチャー,초대형 자쳐,Super grote Zorcher,Super-stor Zorcher,Większy Zorcher,Super Zorcher Grande,,Zorcher Super-Mare,Мегазорчер,Супер-велики зорчер,Superstor Zorcher,Süper Büyük Zorcher,Мега Зорчер +Rapid Zorcher,TAG_RAPIDZORCHER,,,,Rychlobzukr,,Schnellzorcher,,Rapida Zorĉilo,Zorcher Rápido,,Pikazorcheri,Zorcheur Rapide,Gyors Zorker,Zorcher Rapido,れんしゃ ゾーチャー,속사 자쳐,Snelle Zorcher,,Szybkostrzelny Zorcher,Zorcher Automático,,Zorcher cu Foc Rapid,Быстрый зорчер,Рапидни зорчер,Snabbt Zorcher,Hızlı Zorcher,Авто Зорчер +Zorch Propulsor,TAG_ZORCHPROPULSOR,,,,Bzukový propulzor,,Zorch-Propeller,,Zorĉpropulsilo,Propulsor de Zorch,,Zorchtyönnin,Propulseur de Zorch,Zork Elhárító,Propulsore Zorch,ロケット ゾーチ,저치 추진기,,,Pędnik Zorch,Propulsor de Zorch,,Accelerator Zorch,Ускоритель зорча,Погонски зорчер,,,Прискорений Зорчер +Phasing Zorcher,TAG_PHASINGZORCHER,,,,Fázovací bzukr,,Phasenzorcher,,Fluktuantzorĉilo,Zorcher de Fase,,Vaiheiszorcheri,Zorcheur à Phase,Fokozatos Zorker,Zorcher di Fase,フェイシング ゾーチャー,전자 자쳐,Fasezorcher,,Fazowy Zorcher,Zorcher Fásico,,Zorcher Fazat,Фазерный зорчер,Фазни зорчер,Fasande Zorcher,Fazlama Zorcher,Фазовий Зорчер +LAZ Device,TAG_LAZDEVICE,,,,Velkodosahový bzukr,LAZ-enhed,Flächenzorcher,,LAZ-Aparato,Dispositivo LAZ,,SAZ-laite,Zorcheur Zone Large,LAZ Készülék,Dispositivo LAZ,ラージエリアゾーキング デバイス,LAZ 장치,LAZ-aparaat,LAZ-enhet,Urządzenie LAZ,Dispositivo LAZ,,Dispozitiv LAZ,Устройство «ЗБР»,ЛАЗ уређај,LAZ-enhet,LAZ Cihazı,Пристрій LAZ +%o was slimed by a flemoid.,OB_COMMONUS,,,,%o byl@[ao_cs] osliznut@[ao_cs] slizounem.,%o blev slimet af en flemoid.,%o wurde von einem Flemoiden vollgeschleimt.,,%o estas ŝlimiga de mukulo.,%o fue pegotead@[ao_esp] por un flemoide.,,%o joutui limatuksen limaamaksi.,%o à été gélifié par un flemoid.,%o el lett trutyizva egy Flemoid által.,%o è stato coperto di slime da un flemoid.,%o はフレモイドにベトベトにされた。,%o 은(는) 플레모이드에 의해 더러워졌습니다.,%o werd afgeslankt door een flemoid.,%o ble slimet av en flemoid.,"%o został@[ao_pl] oszlamion@[adj_pl] przez flemoida. +",%o foi melecad@[ao_ptb] por um flemóide.,%o foi suj@[ao_ptb] por um flemóide.,%o a fost transformat în mâzgă de un flemoid.,Игрока %o обслюнявил флемоид.,%o је унаказио љигавац.,%o blev slemmad av en flemoid.,%o bir flemoid tarafından sümüklendi.,Виберіть рівень важкості: +%o was slimed by a bipedicus.,OB_BIPEDICUS,,,,%o byl@[ao_cs] osliznut@[ao_cs] dvojnožkem.,%o blev slimet af en bipedicus.,%o wurde von einem Bipedicus vollgeschleimt.,,%o estas ŝlimiga de dupiedmukulo.,%o fue pegotead@[ao_esp] por un bipedicus.,,%o joutui bipedicuksen limaamaksi.,%o à été gélifié@[e_fr] par un bipedicus.,%o el lett trutyizva egy kétlábusz által.,%o è stato coperto di slime da un bipedicus.,%o はバイペディクスにベトベトにされた。,%o 은(는) 바이피디쿠스의 끈쩍한 시야에 걸렸습니다.,%o werd afgeslankt door een bipedicus.,%o ble slimet av en bipedicus.,%o został@[ao_pl] oszlamion@[adj_pl] przez bipedicusa.,%o foi melecad@[ao_ptb] por um bipedicus.,%o foi suj@[ao_ptb] por um bipedicus.,% a fost transformat în mâzgă de un biped.,Игрока %o обслюнявила двуножка.,%o је унаказио двоножни-љигавац.,%o blev slemmad av en bipedicus.,%o bir bipedicus tarafından sümüklendi., +%o was slimed by an armored bipedicus.,OB_BIPEDICUS2,,,%o was slimed by an armoured bipedicus.,%o byl@[ao_cs] osliznut@[ao_cs] obrněným dvojnožkem.,%o blev slimet af en pansret bipedicus.,%o wurde von einem gepanzerten Bipedicus vollgeschleimt.,,%o estas ŝlimiga de kirasa dupiedmukulo.,%o fue pegotead@[ao_esp] por un bipedicus blindado.,,%o joutui panssaroidun bipedicuksen limaamaksi.,%o à été gélifié@[e_fr] par un bipedicus en armure.,%o el lett trutyizva egy páncélozott kétlábusz által.,%o è stato coperto di slime da un bipedicus corazzato.,%o はアーマードペディクスにベトベトにされた。,%o 은(는) 정예 바이피디쿠스의 찐득한 공격을 받았습니다.,%o werd afgeslankt door een gepantserde bipedicus.,%o ble slimet av en pansret bipedicus.,%o został@[ao_pl] oszlamion@[adj_pl] przez opancerzonego bipedicusa.,%o foi melecad@[ao_ptb] por um bipedicus de armadura.,%o foi suj@[ao_ptb] por um bipedicus de armadura.,"%o a fost transformat în mâzgă de un biped cu +armură.",Игрока %o обслюнявила бронированная двуножка.,%o је унаказио оклопни-љигавац.,%o blev slemmad av en bepansrad bipedicus.,%o zırhlı bir bipedicus tarafından sümüklendi., +%o was slimed by a cycloptis.,OB_CYCLOPTIS,,,,%o byl@[ao_cs] osliznut@[ao_cs] jednoočkem.,%o blev slimet af en cycloptis.,%o wurde von einem Cycloptis vollgeschleimt.,,%o estas ŝlimiga de ciklopmukulo,%o fue pegotead@[ao_esp] por un cicloptis.,,%o joutui cycloptiksen limaamaksi.,%o à été gélifié@[e_fr] par un cycloptis.,%o el lett trutyizva egy kükloptisz által.,%o è stato coperto di slime da un cycloptis.,%o はサイクロプティスにベトベトにされた。,%o 은(는) 사이클롭티스 곁에 미끄러졌습니다.,%o werd afgeslankt door een cycloptis.,%o ble slimet av en cycloptis.,%o został@[ao_pl] oszlamion@[adj_pl] przez cykloptisa.,%o foi melecad@[ao_ptb] por um cycloptis.,%o foi suj@[ao_ptb] por um cycloptis.,%o a fost transformat în mâzgă de un ciclioptic.,Игрока %o обслюнявил циклоптис.,%o је унаказио циклогавац.,%o blev slemmad av en cycloptis.,%o bir cycloptis tarafından sümüklendi., +%o was defeated by the Flembrane.,OB_FLEMBRANE,,,,%o byl@[ao_cs] poražen@[ao_cs] Slizobránou.,%o blev besejret af Flembrane.,%o wurde von der Flembrane geschlagen,,%o estas venkita de La Mukmembrano.,%o fue vencid@[ao_esp] por la Flembrana.,,%o joutui Limakalvon päihittämäksi.,%o à été battu@[e_fr] par la Flembrane.,%o vereséget szenvedett a Slejmbrántól.,%o è stato sconfitto dalla Flembrana.,%o はフレムブランにはいぼくした。,%o 은(는) 역겨운 플렘브레인을 돌파하지 못했습니다.,%o werd verslagen door de Flembrane.,%o ble beseiret av Flembrane.,%o został@[ao_pl] pokonan@[adj_pl] przez Flembranę.,%o foi derrotad@[ao_ptb] pela Flembrane.,,%o a fost învins de Flembrană.,Игрока %o победила Флембрана.,%o је поразио љигомозак.,%o blev besegrad av Flembrane.,"%o, Flembrane tarafından yenildi.", +%o was spoon fed by %k.,OB_MPSPOON,,,,%o byl@[ao_cs] nakrmen@[ao_cs] lžičkou hráče %k.,%o blev spoon-fodret af %k.,%o wurde von %k mit dem Löffel gefüttert.,,%o estas kulernutrita de %k.,%o fue cucharead@[ao_esp] por %k.,,%k syötti pelaajaa %o lusikalla.,%o à été nourri@[e_fr] a la petite cuillière par %k.,%o kanállal lett etetve %k által.,%o è stato imboccato da %k.,%o は %k にスプーンでたべさせられた。,%k 이(가) %o 을(를) 숟가락으로 맛있게 먹였습니다.,%o werd met een lepel gevoed door %k.,%o ble matet med skje av %k.,%o został@[ao_pl] nakarmion@[adj_pl] łyżką przez %k.,%o foi comid@[ao_ptb] de colher por %k.,,%o a fost hrănit cu lingura de %k.,Игрок %o поел с ложечки у игрока %k.,%o је накашикан од %k,%o blev matad med sked av %k.,"%o, %k tarafından kaşıkla beslendi.", +%o was thoroughly mixed with %k's bootspork.,OB_MPBOOTSPORK,,,,%o byl@[ao_cs] pořádně namíchán@[ao_cs] botovidličkou hráče %k.,%o blev grundigt blandet med %ks støvlespork.,%o wurde von %k gründlich durchgerührt.,,%o estas plene miksita de la ŝargmanĝilaro de %k.,%o fue profundamente revuelt@[ao_esp] por el cubierto de %k.,,%k läpikotaisin sekoitti %o paran luhallaan.,%o à été mélangé@[e_fr] minutieusement par la Super Fourchette de %k.,%o össze lett keverve %k Rotációsvillája által.,%o è stato mischiato ben bene dal bootspork di %k.,%o は %k にスーパーさきわれスプーンでかきまぜられた。,%k 이(가) %o 을(를) 부트스포크로 빙빙 돌렸습니다.,%o werd grondig gemengd met %k's bootspork.,%o ble grundig blandet med %k's bootspork.,%o został@[ao_pl] dokładnie wymieszan@[adj_pl] łyżkowidelcem %k.,%o foi mexid@[ao_ptb] pelo garfo de %k.,%o foi mexid@[ao_ptb] pelo garfo-colher de %k.,%o a fost amestecat bine de lingura lui %k.,Игрок %o тщательно перемешан ложковилкой игрока %k.,%o је темељно измешан од стране %k супер виљушке.,%o blev ordentligt uppblandad med %ks bootspork.,%o iyice karıştırıldı., +%o was zorched by %k.,OB_MPZORCH,,,,%o byl@[ao_cs] bzukrnut@[ao_cs] hráčem %k.,%o blev zorched af %k.,%o wurde von %k gezorcht,,%o estas zorĉita de %k.,%o fue electrizad@[ao_esp] por %k.,,%k zorchasi %o paran.,%o à été zorché@[e_fr] par %k.,%o zorkolva lett %k által.,%o è stato zorchato da %k.,%o は %k にビリビリさせられた。,%o 은(는) %k 의 소형 자쳐 광선에 맞았습니다.,%o werd gezorched door %k.,%o ble svidd av %k.,%o został@[ao_pl] został zazorchowan@[adj_pl] przez %k.,%o foi zorchead@[ao_ptb] por %k.,,%o a fost înlăturat de zorcherul lui %k.,Игрок %o получил заряд из зорчера %k.,%o је зорчован %k.,%o blev zorchad av %k.,"%o, %k tarafından yenildi.", +%o was hit by %k's mega-zorcher.,OB_MPMEGAZORCH,,,,%o byl@[ao_cs] trefen@[ao_cs] megabzukrem hráče %k.,%o blev ramt af %k's mega-zorcher.,%o wurde von%ks Mega-Zorcher getroffen,,%o estas trafita de la zorĉilego de %k.,%o fue impactad@[ao_esp] por el mega-zorcher de %k.,,%k osui %o parkaan megazorcherillaan.,%o à été frappé@[e_fr] par le méga zorcheur de %k.,%o elérte %k mega zorkerét.,%o è stato colpito dal mega-zorcher di %k.,%o に %k のメガゾーチャーがヒットした。,%o 은(는) %k 의 초대형 자쳐 광선에 날라갔습니다.,%o werd geraakt door %k's megazorcher.,%o ble truffet av %k's mega-zorcher.,%o został@[ao_pl] trafion@[adj_pl] mega-zorcherem %k.,%o foi atingid@[ao_ptb] pelo mega-zorcher de %k.,,%o a fost lovit de mega-zorcherul lui %k.,Игрок %o подстрелен из мегазорчера %k.,%o је ударен од стране %k мега-зорчера.,%o blev träffad av %ks mega-zorcher.,"%o, %k tarafından yenildi.", +%o was rapid zorched by %k.,OB_MPRAPIDZORCH,,,,%o dostal@[ao_cs] rychlobzukrem hráče %k.,%o blev hurtigt zorched af %k.,%o wurde von %k schnellgezorcht.,,%o estas rapidzorĉita de %k.,%o fue electrizad@[ao_esp] rápidamente por %k.,,%k pikazorchasi %o paran.,%o à été zorché@[e_fr] rapidement par %k.,%o gyors zorkolva lett %k által.,%o è stato rapid-zorchato da %k.,%o は %k に めをまわされた。,%o 은(는) %k 의 속사 자쳐 때문에 춤을 췄습니다.,%o werd snel zorched door %k.,%o ble raskt svidd av %k.,%o został@[ao_pl] szybko zazorchowan@[adj_pl] przez %k.,%o foi zorchead@[ao_ptb] automaticamente por %k.,,%o a fost învins de zorcherul rapid al lui %k.,Игрок %o получил заряд из быстрого зорчера %k.,%o је рапидно зорчован %k,%o blev snabbt zorchad av %k.,"%o, %k tarafından yenildi.", +%o was zorched by %k's propulsor.,OB_MPPROPULSOR,,,,%o byl@[ao_cs] bzukrnut@[ao_cs] propulzorem hráče %k.,%o blev zorched af %ks propulsor.,%o wurde von %ks Propeller gezorcht,,%o estas zorĉita de la propulsilo de %k.,%o fue electrizad@[ao_esp] por el propulsor de %k.,,%k zorchasi %o paran työntimellään.,%o à été zorché@[e_fr] par le propulseur de %k.,%o zorkolva lett %k elhárítója által.,%o è stato zorchato dal propulsore di %k.,%o は %k のロケットゾーチャーにあたった。,%o 은(는) %k 의 저치 추진기 쓴 맛을 봤습니다.,%o werd zorched door %k's propulsor.,%o ble zorched av %k's propulsor.,%o został@[ao_pl] zazorchowan@[adj_pl] przez pędnik %k.,%o foi zorchead@[ao_ptb] pelo propulsor de %k.,,%o a fost învins de acceleratorul zorch al lui %k.,Игрок %o получил заряд из ускорителя зорча %k.,%o је зорчован %k погоном.,%o blev zorchad av %ks propulsor.,"%o, %k tarafından yenildi.", +%o was hit by %k's propulsor.,OB_MPP_SPLASH,,,,%o byl@[ao_cs] zasažen@[ao_cs] propulzorem hráčem %k.,%o blev ramt af %k's propulsor.,%o wurde von %ks Propeller getroffen,,%o estas trafita de la propulsilo de %k.,%o fue impactad@[ao_esp] por el propulsor de %k.,,%k osui %o parkaan työntimellään.,%o à été frappé@[e_fr] par le propulseur de %k.,%o elérte %k elhárítóját.,%o è stato colpito dal propulsore di %k.,%o に %k のロケットゾーチャーがとどいた。,%o 은(는) %k 의 저치 추진기의 방사 능력을 우습게 봤습니다.,%o werd geraakt door %k's propulsor.,%o ble truffet av %k's propulsor.,%o został@[ao_pl] trafion@[adj_pl] pędnikiem %k.,%o foi atingid@[ao_ptb] pelo propulsor de %k.,,%o a fost învins de acceleratorul lui %k.,Игрок %o подстрелен из ускорителя зорча %k.,%o је ударен %k погоном.,%o blev träffad av %ks propulsor.,"%o, %k tarafından yenildi.", +%o was phase zorched by %k.,OB_MPPHASEZORCH,,,,%o byl@[ao_cs] bzukr-vyfázován@[ao_cs] hráčem %k.,%o blev fasezorched af %k.,%o wurde von %k wegsynchronisiert,,%o estas fluktuantzorĉita de %k.,%o fue electrizad@[ao_esp] en fase por %k.,,%k vaiheiszorchasi %o paran.,%o à été phasé@[e_fr] par %k.,%o fázis zorker áldozata lett %k által.,%o è stato phase-zorchato da %k.,%o は %k によってスベスベにされた。,%o 은(는) %k 의 전자 자쳐에 의해 쓰러졌습니다.,%o was fase zorched door %k.,%o ble fasebrent av %k.,%o został@[ao_pl] został sfazowan@[adj_pl] przez %k.,%o foi atingid@[ao_ptb] pelo zorcher fásico por %k.,,%o a fost înfrânt de zorcherul fazat al lui %k.,Игрок %o получил заряд из фазерного зорчера %k.,%o је фазно торчован %k.,%o blev faszorchad av %k.,"%o, %k tarafından yenildi.", +%o fell prey to %k's LAZ device.,OB_MPLAZ_BOOM,,,,%o padl@[ao_cs] velkodosahovému bzukru hráče %k.,%o blev offer for %k's LAZ-enhed.,%o fiel %ks Flächenzorcher zum Opfer,,%o iĝis predo de la LAZ-aparato de %k.,%o cayó pres@[ao_esp] ante el dispositivo LAZ de %k.,,%o lankesi pelaajan %k SAZ-laitteen uhriksi.,%o est devenu@[e_fr] la proie du ZZL de %k.,%o prédául lett ejtve %k LAZ készülékével.,%o è stato preda del dispositivo LAZ di %k.,%o は %k のLAZデバイスのえじきになった。,%k 이(가) LAZ 장치를 들기 전에 %o 은(는) 도망쳐야 했습니다.,%o viel ten prooi aan %k's LAZ apparaat.,%o ble offer for %k's LAZ-enhet.,%o stał@[ao_pl] się ofiarą urządzenia LAZ %k.,%o foi vítima do dispositivo LAZ de %k.,,%o a căzut pradă dispozitivului LAZ al lui %k.,Игрок %o склонился перед «ЗБР» игрока %k.,%o је постао жртва %k ЛАЗ уређаја.,%o föll offer för %ks LAZ-enhet.,"%o, %k tarafından lazzlandı.", +%o was lazzed by %k.,OB_MPLAZ_SPLASH,,,,%o byl@[ao_cs] odbzukrován hráčem %k.,%o blev lazzed af %k.,%o wurde von %k weggebeamt.,,%o estas LAZ-ita de %k.,%o fue LAZeado por %k.,,%k sazzasi pelaajaan %o.,%o à été pris@[e_fr] par le ZZL de %k.,%o el lett lazzázva %k által.,%o è stato lazzato da %k.,%o は %k にとかされた。,%o 은(는) %k 의 LAZ 장치 범위를 벗어날 수 없었습니다.,%o werd gelazed door %k.,%o ble lazzed av %k.,%o został@[ao_pl] zLAZowan@[adj_pl] przez %k.,%o foi LAZead@[ao_ptb] por %k.,,%o a fost stropit de dispozitivul LAZ al lui %k.,Игрок %o получил заряд из «ЗБР» игрока %k.,%o је ЛАЗ-овао %k.,%o blev lazzad av %k.,"%o, %k tarafından lazzlandı.", +,,Miscellaneous,,,,,,,,,,,,,,,,,,,,,,,,,, +E1M1: Landing Zone,CHUSTR_E1M1,,,,E1M1: Přistávací zóna,E1M1: Landingszone,E1M1: Landezone,,E1M1: Surterejo,E1M1: Zona de Aterrizaje,,E1M1: Laskeutumisalue,E1M1: La piste d'atterissage,E1M1: Leszállópálya,E1M1: Zona di Atterraggio,E1M1: ちゃくりく ちてん,E1M1: 착륙 지점,E1M1: Landingszone,E1M1: Landingssone,E1M1: Strefa Lądowania,E1M1: Zona de Pouso,E1M1: Zona de Aterragem,E1M1: Pista de Aterizare,E1M1: Зона приземления,Е1М1: Зона слетања,E1M1: Landningszon,E1M1: İniş Bölgesi,E1M1: Зона висадки +E1M2: Storage Facility,CHUSTR_E1M2,,,,E1M2: Skladiště,E1M2: Opbevaringsanlæg,E1M2: Lagerhalle,,E1M2: Stokejo,E1M2: Instalación de Almacenamiento,,E1M2: Varastolaitos,E1M2: Le centre de stockage,E1M2: Raktárépület,E1M2: Struttura di Immagazzinamento,E1M2: ほかん しせつ,E1M2: 저장 시설,E1M2: Opslagfaciliteit,E1M2: Lagringsanlegg,E1M2: Magazyn,E1M2: Depósito,E1M2: Armazém,E1M2: Depozitul,E1M2: Хранилище,Е1М2: Складиште,E1M2: Förvaringsanläggning,E1M2: Depolama Tesisi,E1M2: Сховище +E1M3: Experimental Lab,CHUSTR_E1M3,,,,E1M3: Testovací laboratoř,E1M3: Forsøgslaboratorium,E1M3: Experimentelles Labor,,E1M3: Eksperimenta Laboratorio,E1M3: Laboratorio Experimental,,E1M3: Koelaboratorio,E1M3: Les labos expérimentaux,E1M3: Laboratórium,E1M3: Laboratorio Sperimentale,E1M3: じっけんしつ,E1M3: 연구소,E1M3: Experimenteel laboratorium,E1M3: Eksperimentelt laboratorium,E1M3: Laboratorium Eksperymentalne,E1M3: Laboratório de Experimentos,E1M3: Laboratório Experimental,E1M2: Laboratorul,E1M3: Лаборатория,Е1М3: Експериментална лабораторија,E1M3: Experimentellt labb,E1M3: Deneysel Laboratuvar,E1M3: Експериментальна лабораторія +E1M4: Arboretum,CHUSTR_E1M4,,,,,,,,E1M4: Arbejo,E1M4: Arboreto,,,E1M4: L'Arboretum,E1M4: Arborétum,E1M4: Arboreto,E1M4: じゅもくえん,E1M4: 수목원,,E1M4: Arboretet,,E1M4: Arvoredo,,,E1M4: Дендрарий,Е1М4: Ботаничка башта,,,E1M4: Дендропарк +E1M5: Caverns of Bazoik,CHUSTR_E1M5,,,,E1M5: Bazoikské jeskyně,E1M5: Bazoiks grotter,E1M5: Die Höhlen von Bazoik,,E1M5: Kavernoj de Bazojko,E1M5: Cavernas de Bazoik,,E1M5: Bazoikin luolastot,E1M5: Les cavernes de Bazoik,E1M5: Bazoik barlangjai,E1M5: Caverne di Bazoik,E1M5: バゾイクの どうくつ,E1M5: 바조이크의 대동굴,E1M5: Grotten van Bazoik,E1M5: Grottene til Bazoik,E1M5: Jaskinie Bazoik,E1M5: Cavernas de Bazoik,,E1M5: Cavernele lui Bazoik,E1M5: Пещеры Базоика,Е1М5: Пећине Базоика,E1M5: Bazoiks grottor,E1M5: Bazoik Mağaraları,E1M5: Печери Базойка "Mission accomplished. Are you prepared for the next mission? @@ -2024,7 +1914,16 @@ Jsi připraven@[ao_cs] na další misi? -Pokračuj stisknutím klávesy ESC...","Mission erfüllt. +Pokračuj stisknutím klávesy ESC...","Missionen er fuldført. + +Er du klar til den næste mission? + + + + + + +Tryk på ESC-tasten for at fortsætte...","Mission erfüllt. Bist du für die nächste Mission bereit? @@ -2068,7 +1967,16 @@ Etes vous prêt pour la prochaine mission? -Appuyez sur échap pour continuer...",,"Missione compiuta. +Appuyez sur échap pour continuer...","Küldetés teljesítve. + +Készen állsz a következő küldetésre? + + + + + + +Nyomd meg az ESC gombot a folytatáshoz...","Missione compiuta. Sei pronto per la prossima missione? @@ -2100,7 +2008,16 @@ Bent u voorbereid op de volgende missie? -Druk op de Escape-toets om verder te gaan....","Misja zakończona. +Druk op de Escape-toets om verder te gaan....","Oppdrag utført. + +Er du klar for neste oppdrag? + + + + + + +Trykk på escape-tasten for å fortsette...","Misja zakończona. Jesteś gotowy na kolejną misję? @@ -2144,35 +2061,66 @@ Apasă tasta Esc pentru a continua...","Миссия выполнена. -Нажмите ESC для продолжения...","Мисија успешна. +Нажмите ESC для продолжения...","Мисија је извршена. + +Јесте ли спремни за следећу мисију? + + + + + -Да ли си спреман за следећу мисију? +Притисни ESC да наставиш...","Uppdraget slutfört. +Är du redo för nästa uppdrag? -Притисни ESC да наставиш..." -You've done it!,CE2TEXT,,,,Dokázal@[ao_cs] jsi to!,Du hast es geschafft!,,Vi sukcesis!,¡Lo hiciste!,,Teit sen!,Vous l'avez fait!,,Ce l'hai fatta!,よくやった!,해내셨습니다!,Het is je gelukt!,Udało ci się!,Você conseguiu!,Conseguiste!,Ai reușit!,Вы справились!,Урадио си то! -Wonderful Job!,CE3TEXT,,,,Skvělá práce!,Großartige Arbeit!,,Mirindan Laboron!,¡Maravilloso!,,Hienoa työtä!,Merveilleux travail!,,Meraviglioso!,ワンダフル!,멋지게 잘하셨습니다!,Geweldig werk!,Dobra Robota!,Ótimo trabalho!,,O treabă minunată!,Превосходная работа!,Изванредан посао! -Fantastic,CE4TEXT,,,,Fantastické,Fantastisch,,Mirinda,¡Fantástico!,,Fantastista,Fantastique!,,Fantastico,すばらしい!,환상적,Fantastisch,Fantastycznie,Fantástico,,Fantastic,Великолепно.,Фантастично + +Tryck på escape-tangenten för att fortsätta...","Görev tamamlandı. + +Bir sonraki görev için hazır mısınız? + + + + + + +Devam etmek için kaçış tuşuna basın...","Місія виконана. + +Ти готов@[ao_ua] до наступної місії? + + + + + + +Натисни клавішу escape, щоб продовжити..." +You've done it!,CE2TEXT,,,,Dokázal@[ao_cs] jsi to!,Du har gjort det!,Du hast es geschafft!,,Vi sukcesis!,¡Lo hiciste!,,Teit sen!,Vous l'avez fait!,Megcsináltad!,Ce l'hai fatta!,よくやった!,해내셨습니다!,Het is je gelukt!,Du klarte det!,Udało ci się!,Você conseguiu!,Conseguiste!,Ai reușit!,Вы справились!,Урадио си то!,Du har gjort det!,Başardınız!,У тебе вийшло! +Wonderful Job!,CE3TEXT,,,,Skvělá práce!,Vidunderligt arbejde!,Großartige Arbeit!,,Mirindan Laboron!,¡Maravilloso!,,Hienoa työtä!,Merveilleux travail!,Tökéletes munka!,Meraviglioso!,ワンダフル!,멋지게 잘하셨습니다!,Geweldig werk!,Fantastisk jobb!,Dobra Robota!,Ótimo trabalho!,,O treabă minunată!,Превосходная работа!,Изванредан посао!,Underbart jobb!,Harika bir iş!,Чудова робота! +Fantastic,CE4TEXT,,,,Fantastické,Fantastisk,Fantastisch,,Mirinda,¡Fantástico!,,Fantastista,Fantastique!,Fantasztikus!,Fantastico,すばらしい!,환상적,Fantastisch,Fantastisk!,Fantastycznie,Fantástico,,,Великолепно.,Фантастично,Fantastiskt,Fantastik,Фантастика "You can't do load while in a net quest! Press a key.",CLOADNET,,,,"Nemůžeš použít načtení, když hraješ síťové pátrání! -Stiskni libovolnou klávesu.","Du kannst während eines Netzwerkspiels keinen Spielstand laden. +Stiskni libovolnou klávesu.","Du kan ikke quickloade under et netspil! + +Tryk på en tast.","Du kannst während eines Netzwerkspiels keinen Spielstand laden. -Drücke eine Taste",,"Vi ne povas ŝargi kiam en ret-serĉo! +Drücke eine Taste",,"Vi ne povas ŝargi dum ret-serĉo! -Premu klavon.","¡No puedes cargar mientras estés en una aventura en línea! +Premu klavon.","¡No puedes cargar mientras estés en una aventura online! Presiona una tecla.",,"Et voi ladata verkkopelin aikana! Paina jotain näppäintä.","Vous ne pouvez pas charger quand vous êtes en ligne! -Appuyez sur une touche.",,"Non puoi caricare una partita durante una net quest! +Appuyez sur une touche.","Nem tudsz mentést betölteni netes küldetés közben! + +Nyomj meg egy gombot.","Non puoi caricare una partita durante una netquest! Premi un tasto.","オンラインモードでは セーブデータをロードできません @@ -2181,7 +2129,9 @@ Premi un tasto.","オンラインモードでは セーブデータをロード 키를 누르시오.","Je kunt niet laden tijdens een netspel! -Druk op een toets.","Nie możesz wczytać podczas sieciowej misji! +Druk op een toets.","Du kan ikke gjøre last mens du er i et nettoppdrag! + +Trykk på en tast.","Nie możesz wczytać podczas sieciowej misji! Wciśnij dowolny klawisz.","Não é possível carregar durante uma aventura em rede! @@ -2190,11 +2140,16 @@ Aperte alguma tecla.","Não é possível carregar durante uma aventura em rede! Carrega numa tecla qualquer.","Nu poți face o încărcare în timpul unei căutări online! -Apasă orice tastă.","Невозможно загрузить сохранение в сетевом квесте! +Apasă orice tastă.","Невозможно загрузить сохранение в сетевом задании! Нажмите любую клавишу.","Не можете учитати док сте у мрежној потрази! -Притисните тастер." +Притисните тастер.","Du kan inte göra lastning när du är i ett nätspel! +Tryck på en tangent.","Bir ağ görevindeyken yükleme yapamazsınız! + +Bir tuşa basın.","Ти не можеш завантажитись під час мережевого квесту! + +Натисни будь яку клавішу." "Quicksave over your quest named '%s'? @@ -2203,9 +2158,13 @@ Press Y or N.",QSPROMPT,,chex,,"Rychle uložit přes tvé pátrání s názvem '%s'? -Stiskni Y nebo N.","Überschreibe %s mit einem Schnellspeicherspielstand? +Stiskni Y nebo N.","Quicksave over dit spil navngivet -Drücke Y oder N.",,"Rapidkonservu super via serĉo nomita +'%s'? + +Tryk på Y eller N.","Überschreibe %s mit einem Schnellspeicherspielstand? + +Drücke Y oder N.",,"Ĉu rapidkonservi anstataŭigante vian serĉon nomitan '%s'? @@ -2217,7 +2176,11 @@ Paina Y tai N.","Sauvegarde rapide sur le fichier '%s'? -Appuyez sur Y ou N.",,"Sovrascrivere il salvataggio +Appuyez sur Y ou N.","Gyorsmenteni akarod az alábbi küldetést: + +'%s'? + +Nyomj Y vagy N-t.","Sovrascrivere il salvataggio '%s'? @@ -2233,7 +2196,9 @@ Y키 나 N키를 누르시오.","Snel opslaan over je spel genaamd '%s'? -Druk op Y of N.","Czy szybko nadpisać twoją misję +Druk op Y of N.","Overskrive '%s' med en hurtiglagring? + +Trykk på Y eller N.","Czy szybko nadpisać twoją misję „%s”? @@ -2249,27 +2214,40 @@ Carrega Y ou N.","Salvare rapidă peste căutarea numită '%s'? -Apasă Y sau N.","Выполнить быстрое сохранение квеста +Apasă Y sau N.","Выполнить быстрое сохранение задания «%s»? -Нажмите Y или N.",Брзо-сачувајте преко ваше потраге назване '%s'? Притисните Y или N. +Нажмите Y или N.",Брзо-сачувајте преко ваше потраге назване '%s'? Притисните Y или N.,"Snabbt spara över ditt spel som heter %s? +Tryck på Y eller N.","%s' + +adlı oyununuzun üzerine hızlı kaydetme? + +Y veya N tuşuna basın.","Швидко перезаписати твій квест під назвою + +'%s'? + +Натисни Y або N." "You can't quickload during a netquest! Press a key.",QLOADNET,,chex,,"Nemůžeš použít rychlé načtení , když hraješ síťové pátrání! -Stiskni libovolnou klávesu.","Du kannst während eines Netzwerkspiels nicht schnellladen. +Stiskni libovolnou klávesu.","Du kan ikke quickloade under et netspil! + +Tryk på en tast.","Du kannst während eines Netzwerkspiels nicht schnellladen. -Drücke eine Taste",,"Vi ne povas rapidŝargi kiam ret-serĉo! +Drücke eine Taste",,"Vi ne povas rapidŝargi dum ret-serĉo! -Premu klavon.","¡No puedes cargar una partida guardada durante una aventura en línea! +Premu klavon.","¡No puedes cargar una partida guardada durante una aventura online! Presiona una tecla.",,"Et voi pikaladata verkkopelin aikana! Paina jotain näppäintä.","Vous ne pouvez pas charger quand vous êtes en ligne! -Appuyez sur une touche.",,"Non puoi fare un quickload durante una netquest! +Appuyez sur une touche.","Nem tudsz gyorstölteni netes küldetés közben! + +Nyomj meg egy gombot.","Non puoi fare un quickload durante una netquest! Premi un tasto.","オンラインモードでは セーブデータをロードできません @@ -2280,7 +2258,9 @@ Premi un tasto.","オンラインモードでは セーブデータをロード '%s'? -Druk op Y of N.","Nie możesz użyć szybkiego wczytania podczas sieciowej misji! +Druk op Y of N.","Du kan ikke hurtiglaste under et nettoppdrag! + +Trykk på en tast.","Nie możesz użyć szybkiego wczytania podczas sieciowej misji! Wciśnij dowolny klawisz.","Não é possível carregar durante uma aventura em rede! @@ -2289,11 +2269,16 @@ Aperte alguma tecla.","Não é possível carregar durante uma aventura em rede! Carrega numa tecla qualquer.","Nu poți faci o încărcare rapidă în timpul unei căutări online! -Apasă orice tastă.","Невозможно загрузить быстрое сохранение в сетевом квесте! +Apasă orice tastă.","Невозможно загрузить быстрое сохранение в сетевом задании! Нажмите любую клавишу.","Не можете брзо-учитати док сте у мрежној потрази! -Притисните тастер." +Притисните тастер.","Du kan inte snabbladda under ett nätspel! + +Tryck på en tangent.","Bir ağ oyunu sırasında hızlı yükleme yapamazsınız! +Bir tuşa basın.","Ти не можеш швидко завантажитись під час мережевого квесту! + +Натисни будь яку клавішу." "Do you want to quickload the quest named '%s'? @@ -2302,7 +2287,11 @@ Press Y or N.",QLPROMPT,,chex,,"Přeješ si rychle načíst pátrání s názvem '%s'? -Stiskni Y nebo N.","Möchtest du den Spielstand %s schnellladen? +Stiskni Y nebo N.","Ønsker du at quickloade spillet ved navn + +'%s'? + +Tryk på Y eller N.","Möchtest du den Spielstand %s schnellladen? Drücke Y oder N.",,"Ĉu vi volas rapidŝargi la serĉon nomitan @@ -2316,7 +2305,11 @@ Paina Y tai N.","Chargement rapide sur le fichier '%s'? -Appuyez sur Y ou N.",,"Vuoi fare un quickload della quest +Appuyez sur Y ou N.","Be akarod tölteni a következő küldetést + +'%s'? + +Nyomj Y-t vagy N-t.","Vuoi fare un quickload della quest '%s'? @@ -2332,7 +2325,11 @@ Y키 나 N키를 누르시오.","Wil je het spel snel laden met de naam '%s'? -Druk op Y of N.","Czy chcesz wczytać szybki zapis misji +Druk op Y of N.","Ønsker du å hurtiglaste oppdraget med navnet + +'%s'? + +Trykk Y eller N.","Czy chcesz wczytać szybki zapis misji „%s”? @@ -2348,30 +2345,44 @@ Carrega Y ou N.","Vrei să faci o încărcare rapidă a misiunii '%s'? -Apasă Y sau N.","Загрузить быстрое сохранение квеста +Apasă Y sau N.","Загрузить быстрое сохранение задания «%s»? Нажмите Y или N.","Да ли желиш да брзо-учиташ потрагу названу '%s'? -Притисните Y или N." +Притисните Y или N.","Vill du snabbladda spelet som heter ""%s""? +Tryck på Y eller N.","%s' + +adlı oyunu hızlı yüklemek istiyor musunuz? + +Y veya N tuşuna basın.","Швидко завантажити твій квест під назвою + +'%s'? + +Натисни Y або N." "You can't start a new quest while in a network quest. Press a key.",CNEWGAME,,,,"Nemůžeš začít nové pátrání dokud jsi v síťové hře. -Stiskni libovolnou klávesu.","Du kannst während eines Netzwerkspiels kein neues Spiel starten. +Stiskni libovolnou klávesu.","Du kan ikke starte et nyt spil +mens du er i et netspil. + +Tryk på en tast.","Du kannst während eines Netzwerkspiels kein neues Spiel starten. -Drücke eine Taste",,"Vi ne povas komencigi novan serĉon kiam en ret-serĉon. +Drücke eine Taste",,"Vi ne povas komencigi novan serĉon dum ret-serĉon. -Premu klavon.","No puedes iniciar una nueva aventura mientras estés en una aventura en línea. +Premu klavon.","No puedes iniciar una nueva aventura mientras estés en una aventura online. Presiona una tecla.",,"Et voi aloittaa uutta peliä verkkopelin aikana. Paina jotain näppäintä.","Vous ne pouvez pas lancer une partie quand vous êtes en ligne! -appuyez sur une touche.",,"Non puoi iniziare una nuova quest +appuyez sur une touche.","Nem tudsz új játékot indítani netes küldetés közben! + +Nyomj meg egy gombot.","Non puoi iniziare una nuova quest durante una network quest. Premi un tasto.","オンラインモードでは セーブデータをロードできません @@ -2382,7 +2393,10 @@ Premi un tasto.","オンラインモードでは セーブデータをロード 키를 누르시오.","Je kunt geen nieuw spel starten terwijl je in een netwerkspel zit. -Druk op een toets.","Nie możesz zacząć nowej misji +Druk op een toets.","Du kan ikke starte et nytt oppdrag +mens du er i et nettverksoppdrag. + +Trykk på en tast.","Nie możesz zacząć nowej misji podczas misji sieciowej. Wciśnij dowolny klawisz.","Não é possível iniciar uma nova aventura durante uma aventura em rede. @@ -2392,19 +2406,28 @@ Aperte alguma tecla.","Não é possível iniciar uma nova aventura durante uma a Carrega numa tecla qualquer.","Nu poți începe o căutare nouă în timpul unei căutări în rețea! -Apasă orice tastă.","Невозможно начать новый квест -при сетевом квесте! +Apasă orice tastă.","Невозможно начать новое задание при сетевом задании! Нажмите любую клавишу.","Не можете почети нову потрагу док сте у мрежној потрази. -Притисните тастер." +Притисните тастер.","Du kan inte starta ett nytt spel när du är i ett nätspel. + +Tryck på en tangent.","Yeni bir görev başlatamazsınız +bir ağ görevindeyken. + +Bir tuşa basın.","Ти не можеш почати новий квест під час мережевого квесту! + +Натисни будь яку клавішу." "Careful, this will be tough. Do you wish to continue? Press Y or N.",CNIGHTMARE,,,,"Opatrně, tohle bude těžké. Chceš pokračovat? -Stiskni Y nebo N.","Achtung, das ist schwer! +Stiskni Y nebo N.","Pas på, det bliver svært. +Ønsker du at fortsætte? + +Tryk på Y eller N.","Achtung, das ist schwer! Willst du das wirklich machen. Drücker Y oder N.",,"Singardu, ĉi tio malfacilos. @@ -2419,7 +2442,10 @@ Haluatko jatkaa? Paina Y tai N.","Attention, ce mode n'y va pas avec tact... Voulez-vous continuer? -Appuyez sur Y ou N.",,"Attento, sarà dura. +Appuyez sur Y ou N.","Vigyázz, ez nehéz lesz. +Biztosan folytatni akarod? + +Nyomj Y-t vagy N-t.","Attento, sarà dura. Vuoi continuare? Premi Y oppure N.","きをつけて、これはすごく てごわい。 @@ -2431,7 +2457,10 @@ Y か N をおしてください。 Y키 나 N키를 누르시오.","Voorzichtig, dit wordt moeilijk. Wil je doorgaan? -Druk op Y of N.","Uważaj, to będzie trudne. +Druk op Y of N.","Forsiktig, dette blir vanskelig. +Ønsker du å fortsette? + +Trykk Y eller N.","Uważaj, to będzie trudne. Czy chcesz kontynuować? Wciśnij Y lub N.","Cuidado, isto vai ser difícil. @@ -2448,7 +2477,16 @@ Apasă Y sau N.","Осторожно — будет сложно. Нажмите Y или N.","Пажљиво, ово је ће бити тешко. Да ли желиш да наставиш? -Притисните Y или N." +Притисните Y или N.","Försiktigt, det här kommer att bli svårt. +Vill du fortsätta? + +Tryck på Y eller N.","Dikkatli ol, bu zor olacak. +Devam etmek istiyor musunuz? + +Y veya N tuşuna basın.","Бережись, тут буде скрутно. +Хочеш продовжити? + +Натисни Y або N." "This is Chex(R) Quest. look for future levels at www.chexquest.com. @@ -2457,7 +2495,11 @@ Press a key.",CSWSTRING,,,,"Toto je Chex(R) Quest. Najdi další levely na www.chexquest.com. -Stiskni libovolnou klávesu.","Dies ist Chex Quest(R). Finde +Stiskni libovolnou klávesu.","Dette er Chex(R) Quest. + +fremtidige kort på www.chexquest.com. + +Tryk på en tast.","Dies ist Chex Quest(R). Finde weitere Level auf www.chexquest.com @@ -2475,7 +2517,11 @@ Paina jotain näppäintä.","Ceci est Chex(R) Quest. Attendez-vous à de futur niveaux sur www.chexquest.com. -Appuyez sur une touche.",,"Questo è Chex(R) Quest. cerca +Appuyez sur une touche.","Ez a Chex(R) Quest. Keresd + +az új pályákat a www.chexquest.com-on. + +Nyomj egy gombot.","Questo è Chex(R) Quest. cerca i futuri livelli su www.chexquest.com @@ -2491,7 +2537,11 @@ Premi un tasto.","これは チェックス(R)クエスト。 toekomstige niveaus op www.chexquest.com -Druk op een toets.","To jest Chex(R) Quest. Szukaj +Druk op een toets.","Dette er Chex(R) Quest. se etter fremtidige nivåer på + +fremtidige nivåer på www.chexquest.com. + +Trykk på en tast.","To jest Chex(R) Quest. Szukaj kolejnych poziomów na www.chexquest.com. @@ -2507,31 +2557,45 @@ Carrega numa tecla qualquer.","Acesta este Chex(R) Quest, pentru mai multe niveluri vizitează www.chexquest.com. -Apasă orice tastă.","Вы играете в Chex(R) Quest. Остальные уровни +Apasă orice tastă.","Вы играете в Chex(R) Quest. Остальные -на www.chexquest.com. +уровни на www.chexquest.com. Нажмите любую клавишу.","Ово је Chex Quest. Тражите нове нивое на www.chexquest.com. -Притисните Y или N." +Притисните Y или N.","Det här är Chex(R) Quest. + +framtida nivåer på www.chexquest.com. + +Tryck på en tangent.","Bu Chex(R) Görevi. + +www.chexquest.com adresinde gelecekteki seviyeler. + +Bir tuşa basın.","Ти граєш в Chex(R) Quest. Інші рівні тут - www.chexquest.com. + +Натисни Y або N." "You can't end a netquest! Press a key.",NETEND,,chex,,"Nemůžeš ukončit síťové pátrání! -Stiskni libovolnou klávesu","Du kannst ein Netzwerkspiel nicht beenden. +Stiskni libovolnou klávesu","Du kan ikke afslutte en netspil! + +Tryk på en tast.","Du kannst ein Netzwerkspiel nicht beenden. Drücke eine Taste.",,"Vi ne povas fini ret-serĉon! -Premu klavon.","¡No puedes terminar una aventura en línea! +Premu klavon.","¡No puedes terminar una aventura online! Presiona una tecla.",,"Et voi päättää verkkopeliä! Paina jotain näppäintä.","Vous ne pouvez pas arrêter la partie quand vous êtes en ligne! -Appuyez sur une touche.",,"Non puoi terminare una netquest! +Appuyez sur une touche.","Nem tudsz kilépni a netes küldetésből! + +Nyomj egy gombot.","Non puoi terminare una netquest! Premi un tasto.","オンラインモードでは タイトルがめんにはもどれません @@ -2540,7 +2604,9 @@ Premi un tasto.","オンラインモードでは タイトルがめんにはも 키를 누르시오.","Je kunt een netspel niet beëindigen! -Druk op een toets.","Nie możesz zakończyć misji sieciowej! +Druk op een toets.","Du kan ikke avslutte en netquest! + +Trykk på en tast.","Nie możesz zakończyć misji sieciowej! Wciśnij dowolny klaiwsz.","Você não pode terminar uma aventura em rede! @@ -2548,16 +2614,23 @@ Aperte alguma tecla.","Não podes terminar uma aventura em rede! Carrega numa tecla qualquer.","Nu poți încheia brusc o căutare în rețea! -Apasă orice tastă.","Невозможно прервать сетевой квест! +Apasă orice tastă.","Невозможно прервать сетевое задание! Нажмите любую клавишу.","Не можете завршити мрежну потрагу! -Притисните тастер." +Притисните тастер.","Du kan inte avsluta ett nätspel! +Tryck på en tangent.","Bir netquest'i sonlandıramazsınız! + +Bir tuşa basın.","Ти не можеш завершити мережевий квест! + +Натисни будь яку клавішу." "Are you sure you want to end the quest? Press Y or N.",ENDGAME,,chex,,"Opravdu si přeješ ukončit pátrání? -Stiskni Y nebo N.","Willst du das Spiel wirklich beenden? +Stiskni Y nebo N.","Er du sikker på, at du ønsker at afslutte spillet? + +Tryk på Y eller N.","Willst du das Spiel wirklich beenden? Drücke Y oder N.",,"Ĉu vi certas ke vi volas fini la serĉon? @@ -2567,7 +2640,9 @@ Presiona Y ó N.",,"Haluatko varmasti päättää pelin? Paina Y tai N.","Finir la partie? -Appuyez sur Y ou N.",,"Sei sicuro di voler terminare la quest? +Appuyez sur Y ou N.","Biztosan be akarod fejezni a küldetést? + +Nyomj Y-t vagy N-t.","Sei sicuro di voler terminare la quest? Premi Y oppure N.","ほんとうに いまのぼうけんを おわらせますか? @@ -2576,7 +2651,9 @@ Y か N をおしてください。 Y키 나 N키를 누르시오.","Weet je zeker dat je het spel wilt beëindigen? -Druk op Y of N.","Czy na pewno chcesz zakończyć misję? +Druk op Y of N.","Er du sikker på at du vil avslutte oppdraget? + +Trykk Y eller N.","Czy na pewno chcesz zakończyć misję? Wciśnij Y lub N.","Tem certeza que quer terminar esta aventura? @@ -2584,1206 +2661,736 @@ Aperte Y ou N.","Tens a certeza que queres terminar esta aventura? Carrega Y ou N.","Ești sigur că vrei să încetezi căutarea? -Apasă Y sau N.","Вы точно хотите завершить квест? +Apasă Y sau N.","Вы точно хотите завершить задание? Нажмите Y или N.","Да ли си сигуран да желиш да завршиш трагање? -Притисни Y или N." -Invincible Mode ON,STSTR_DQDON,,chex,,Režim nezranitelnosti ZAP,Unbesiegbarer Modus EIN,,Nevenkebla-reĝimo AKTIVA,Modo invencible ACTIVADO,,Kuolemattomuustila PÄÄLLÄ,Mode invincible ON,,Modalità invincibile attivata,むてきモード オン,무적 모드 켬,Onoverwinnelijke modus AAN,Tryb Niewrażliwości WŁĄCZONY,Modo invencível ATIVADO,,Modul Invincibil ACTIVAT,Режим неуязвимости включён,Неуништив УКЉУЧЕН -Invincible Mode OFF,STSTR_DQDOFF,,chex,,Režim nezranitelnosti VYP,Unbesiegbarer Modus AUS,,Nevenkebla-reĝimo MALAKTIVA,Modo invencible DESACTIVADO,,Kuolemattomuustila POIS PÄÄLLÄ,Mode invincible OFF,,Modalità invincibile disattivata,むてきモード オフ,무적 모드 끔,Onoverwinnelijke modus UIT,Tryb Niewrażliwości WYŁĄCZONY,Modo invencível DESATIVADO,,Modul Invincibil DEZACTIVAT,Режим неуязвимости выключен,Неуништив ИСКЉУЧЕН -Zorch Added,STSTR_FAADDED,,chex,,Bzukry přidány,Zorch hinzugefügt,,Zorĉo Aldonita,Zorch añadido,,Zorch lisätty,Zorch Ajouté,,Zorch aggiunto,ゾーチ ついか,모든 저치 에너지 추가,Zorch toegevoegd,Zorch dodany,Zorch adicionado,,Zorcher Adăugat,Добавлен Зорч,Зорч додат -Super Zorch Added,STSTR_KFAADDED,,chex,,Superbzukry přidány,Super Zorch hinzugefügt,,Supera Zorĉo Aldonita,Súper Zorch añadido,,Superzorch lisätty,Super Zorch Ajouté,,Super Zorch aggiunto,スーパーゾーチ ついか,모든 아이템 습득!,Super Zorch toegevoegd,Super Zorch dodany,Super Zorch adicionado,,Super Lingură Adăugată,Добавлен Супер Зорч,Супер зорч додат -... Eat Chex(R)!,STSTR_CHOPPERS,,chex,,... Jez Chex(R)!,...Iss Chex(R)!,,... Manĝu Chex(R)-on!,... Come Chex(R),,... Syö Chex(R):ä!,... Mangez du Chex(R)!,,... Mangia I Chex(R)!,... Chex(R)をたべよう!,... 첵스(R) 를 많이 먹자!,... Eet Chex(R)!,... jedz płatki Chex(R)!,... coma Chex(R)!,,... Mănâncă Chex(R)!,... Ешь Chex(R)!,... Једи Chex(R)! -Mini Zorch Charge,AMMO_CLIP,,chex,,Minibzukrové náboje,Minizorcher-Ladung,,Zorĉileto-Ŝarĝo,Carga de Mini Zorch,,Minizorchvaraus,Charge Zorch,,Ricarica Mini Zorch,ミニゾーチ ほきゅう,소형 저치 전지,Mini Zorchlading,Mini Ładunek Zorch,Recarga de Mini Zorch,,Mini Încărcătură pentru Zorcher,Заряд Мини-Зорчера,Мини зорч пуњач -Large Zorcher Charge,AMMO_SHELLS,,chex,,Velkobzukrové náboje,Zorcher-Ladung,,Ŝarĝo por Granda Zorĉilo,Carga de Zorcher Largo,,Ison zorcherin varaus,Charge de Zorcheur Large,,Ricarica Grande Zorch,ラージゾーチャー ほきゅう,대형 저치 카트리지,Grote Zorchlading,Ładunek do Dużego Zorchera,Recarga de Zorch Grande,,Încărcătură Mare pentru Zorcher,Заряд Большого Зорчера,Велики зорч пуњач -Propulsor Charge,AMMO_ROCKETS,,chex,,Propulzorové náboje,Propeller-Ladung,,Zorĉpropulsilo-ŝarĝo,Carga de Propulsor de Zorcher,,Työntimen varaus,Charge de Propulseur,,Ricarica Propulsore,プロパルサー ほきゅう,저치 추진료,Propulsorlading,Ładunek do Pędnika,Recarga de Propulsor de Zorch,,Încărcătură pentru Accelerator,Заряд Ускорителя,Погонски зорч пуњач -Phasing Zorcher Charge,AMMO_CELLS,,chex,,Fázovací náboje,Phasenzorcher-Ladung,,Fluktuantzorĉilo-ŝarĝo,Carga de Zorcher de Fase,,Vaiheiszorcherin varaus,Charge de Phaseur,,Ricarica Zorcher di Fase,フェイシング ゾーチャー ほきゅう,저치 전자 충전기,Fasezorcherlading,Ładunek do Fazowego Zorchera,Recarga de Zorcher Fásico,,Încărcătură pentru Zorcherul Fazat,Заряд Фазового Зорчера,Фазни зорч пуњач -,,Menus,,,,,,,,,,,,,,,,,,,,, -,,Main Menus,,,,,,,,,,,,,,,,,,,,, -New Game,MNU_NEWGAME,,,,Nová hra,Neues Spiel,Νέο Παιχνίδι,Nova Ludo,Nueva Partida,,Uusi peli,Nouvelle Partie,,Nuovo gioco,新規ゲーム,새로운 게임,Nieuw spel,Nowa Gra,Novo Jogo,,Joc Nou,Новая игра,Нова игра -Options,MNU_OPTIONS,,,,Možnosti,Optionen,Ρυθμίσεις,Agordoj,Opciones,,Asetukset,Options,,Opzioni,オプション,설정,Opties,Opcje,Opções,,Opțiuni,Настройки,Подешавања -Game Files,MNU_GAMEFILES,,,,Uložené hry,Spieldateien,Αρχεία Παιχνιδιού,Ludo-Dosieroj,Archivos del Juego,,Pelitiedostot,Fichiers de jeu,,File di gioco,ゲームファイル,게임 파일,Spelbestanden,Pliki Gry,Jogos Salvos,Jogos Gravados,Fișiere Joc,Файлы игры,Фајлови игре -Info,MNU_INFO,,,,Informace,Informationen,Πληροφορίες,Informo,Información,,Tiedot,Info,,Informazioni,情報,정보,Info,Info,Informações,,Info,Информация,Подаци -Quit Game,MNU_QUITGAME,,,,Ukončit hru,Spiel verlassen,Έξοδος,Ĉesigi Ludon,Salir del juego,,Lopeta peli,Quitter le jeu,,Esci dal gioco,終了,게임 종료,Verlaat spel,Wyjdź z Gry,Sair,,Ieșire din Joc,Выход,Заврши игру -Choose Skill Level:,MNU_CHOOSESKILL,This text is extremely space limited!,,,Vyber obtížnost:,Schwierigkeitsgrad:,Επίλεξε ΔυσκολΊα:,Elektu Malfacileco:,Elige nivel de dificultad:,,Valitse vaikeustaso:,Difficulté:,,Livello di difficoltà:,実力を選べ:,난이도를 고르시오:,Vaardigheidsniveau:,Wybierz Poziom Trudności:,Escolha o Nível de Dificuldade:,,Alege Dificultatea:,Уровень сложности:,Ниво тежине: -I'm too young to die.,SKILL_BABY,,,,Ještě nechci umřít.,Ich bin zu jung zum Sterben.,Είμαι πολύ νεαρός για να πεθάνω!,Mi estas tro juna por morti.,Soy muy joven para morir.,,Olen liian nuori kuolemaan.,Trop jeune pour mourir!,,Troppo giovane per morire.,死ぬには若すぎる,난 죽기엔 너무 젊어.,Ik ben te jong om te sterven.,Jestem za młody by umierać.,Sou jovem demais para morrer.,Demasiado novo para morrer.,Sunt prea tânăr ca să mor.,Мне рано умирать.,Премлад сам да умрем. -"Hey, not too rough.",SKILL_EASY,,,,"Hej, ne tak tvrdě.","He, nicht so ruppig.",Όχι πολύ δύσκολο,"He, ne tro malafabla.","Oye, no tan rudo.",,"Hei, ei liian kovaa.","Hé, pas trop fort!",,"Ehi, non troppo duro!",あまり激しくするな,너무 세게 하지는 마.,"Hé, niet te ruw.","Hej, nie tak mocno.","Opa, pega leve aí.","Ei, mais devagar.","Hei, nu foarte dur.","Эй, не так грубо.","Хеј, не претерано грубо." -Hurt me plenty.,SKILL_NORMAL,,,,Pojď do mě.,Tu mir weh.,Πόνεσε με,Vundu min multe.,Lastímame suficiente.,,Satuta minua kunnolla.,Fais-moi mal!,,Fammi molto male.,存分にやってくれ,마음껏 때려봐.,Doe me veel pijn.,Dowal mi.,Pode vir quente.,Dá-me com força.,Rănește-mă din plin.,Сделай мне больно.,Повреди ме кол'ко можеш. -Ultra-Violence.,SKILL_HARD,,,,Ultrařežba.,Volle Gewalt.,Ύπερ-Βία,Ekstrema Perforto.,Ultra-Violencia.,,Ultraväkivalta.,Ultra-Violence!,,Ultra-violenza.,ウルトラ バイオレンス,극단적인-폭력.,Ultra Geweld.,Ultra-Przemoc.,Ultra-Violência,,Ultra-Violență.,Ультранасилие.,Ултра-насилно. -Nightmare!,SKILL_NIGHTMARE,,,,Noční můra!,Alptraum!,Εφιάλτης!,Inkubo!,¡Pesadilla!,,Painajainen!,Cauchemar!,,Incubo!,悪夢だ!,악몽!,Nachtmerrie!,Koszmar!,Pesadelo!,,Coșmar!,Кошмар!,Ноћна мора! -Easy does it,CSKILL_BABY,,,,Hezky zlehka,Immer sachte,,Kvietiĝu,Así de fácil,,Hiljaa hyvä tulee,On y va Doucement,,Facile no?,やさしくして,살살 하면 좋겠네,Gemakkelijk doet het,Łatwizna,Vamos com calma,,Merge ușor,Потихоньку-полегоньку,Лагано сад -Not so sticky,CSKILL_EASY,,,,Ne tak ulepeně,Nicht so schmierig,,Ne tiel glueca,No tan pegajoso,,Ei niin tahmaista,Pas trop Collant,,"Non così appiccicoso -",ダラダラしない,질척하진 않게,Niet zo plakkerig.,Nie tak lepko,Não tão gosmento,,Nu așa de lipicios,Не особо липко,Не тако лепљиво -Gobs of goo,CSKILL_NORMAL,,,,Hafo hlenu,Schleimklumpen,,Buloj de muko,Montón de mugre,,Limaklönttejä,Des Tonnes de Gelée,,Sputi di sostanza,"カッチカチスライム -",적지 않은 질퍽함,brokken slijm,Maziste Gęby,Um montão de meleca,Um montão de ranho,Multă mâzgă,Масса слизи,Лопте љиге -Extreme Ooze,CSKILL_HARD,,,,Extra bláto,Extrem glitschig,,Ega Pusado,Goteo en extremo,,Äärimmäisen mönjäistä,Extrêmement Gluant,,Melma estrema,"かげきなウーズ -",엄청난 끈끈함,Uiterst glibberig,Ekstremalny Muł,Gosma ao extremo,,Noroi Extrem,Экстремальная грязь,Екстремно љигаво -Super Slimey!,CSKILL_NIGHTMARE,,,,Superslizké!,Super schleimig!,,Tre Ŝlima!,¡Súper baboso!,,Superlimaista!,Carrément Crade!,,Super Viscido!,ちょうベトベト!,끈쩍함 천지!,Super slijmerig!,Super Oślizgły!,Super Gosmento!,,Super Mâzgos!,Сверхсклизский!,СУПЕР ЉИГАВО -Training,SSKILL_BABY,,,,Trénink,,Eκπαίδευση,Trejnado,Práctica,,Koulutus,Entrâinement,,Allenamento,トレーニング,훈련병,Opleiding,Trening,Treinamento,Treino,În Pregătiri,Разминка,Тренинг -Rookie,SSKILL_EASY,,,,Zelenáč,Anfänger,Αρχάριος,Komencanto,Novato,,Aloittelija,Recrue,,Matricola,ルーキー,신병,,Rekrut,Novato,,Începător,Новичок,Новајлија -Veteran,SSKILL_NORMAL,,,,Veterán,,,Veterano,Veterano,,Veteraani,Véteran,,Veterano,ベテラン,고참병,Veteraan,Weteran,Veterano,,Veteran,Ветеран,Ветеран -Elite,SSKILL_HARD,,,,Elita,,,Elito,Elite,,Eliitti,,,Elite,エリート,정예병,,Elita,Elite,,Elită,Элита,Елитни -Bloodbath,SSKILL_NIGHTMARE,,,,Krveřežba,Blutbad,,Sangoverŝado,Baño de sangre,,Verilöyly,Massacre!,,Bagno di sangue,ブラッドバス,피의 목욕,Bloedbad,Rozlew krwi,Banho de sangue,,Baie de sânge,Кровавая бойня,Купка крви -Thou needeth a Wet-Nurse,MNU_WETNURSE,,,,Potřěbuješ krmlici,Wo ist die Krankenschwester?,,Ci sian panjon devu necesigi,Necesitareis una nodriza,,Tarvitseos imettäjää,Une Nourrice Vous Voulez,,Necessiti di un'infermiera per neonati,汝は乳母を欲する,그대에게는 유모가 필요하다,Waar is de verpleegster?,Chyba potrzebujesz Mamki,Tu necessitas de uma Ama-de-Leite,Tu precisas de uma Ama-Seca,Doica are Nevoie de Mine,Нянечка надобна мне,Треба ти бабица -Yellowbellies-R-Us,MNU_YELLOWBELLIES,,,,Nemehla tož jsme my,Vereinigte Waschlappen,,Flavaventroj-Es-Ni,Somos pusilánimes,,Mameronapero,Un Trouillard-Tu-Est,,Codardo-tu-sei,我等こそが臆病者,장난감을 가지고 노는가,Verenigd washandje,Tchórze To My,Tu és um Amarelão,Tu és um Cobardolas,Nu Sunt Așa de Curajos,Не столь мужественен я,Ми-смо-жутица -Bringest Them Oneth,MNU_BRINGEST,,,,Chtějúci se práti?,Her damit,,Vi al ili unaĵon kunvenigu,Traédnoslos,,Antaos tullaos,Amenez les moi!,,Portali a me,招かれし者共,혈투를 벌일 준비하라,Geef me dat.,Dawaj Ich,Podeis Virdes,Podeis Virdes,Aduceți-mi,Подайте мне их,Донеси изабраног -Thou art a Smite-Meister,MNU_SMITE,,,,Ktož jsú boží bojovníci,Du bist der Meistertöter,,Vi ĉefmortiganto estas iĝanta,Sois un regicida,,Olet lyömäherra,Tu est Maître-Meurtrier,,Sei un maestro assassino,汝 芸術的殺戮を,그대야말로 타격의 대가,Jij bent de meestermoordenaar.,Jesteś Mistrzem Walki,Tu és Mestre-de-Massacres,,Lupta mă Ispitește,Искушён я сражениями,Ти си обузети-мајстор -Black Plague Possesses Thee,MNU_BLACKPLAGUE,,,,Jsúci Smrtonošem morovým!,Von der Pest besessen,,Nigra Pesto vin infestas,La peste negra os posee,,Musta surma on saanut sun,La Peste Noire me Possède!,,La peste nera ti possiede,汝に憑した黒死病,흑사병이 그대를 저주 내리리,Geobsedeerd door de pest,Czarna Plaga Cię Opętuje,A Peste Negra te Possui,A Peste Negra Possui-te,Ciuma Neagră mă Posedă,Чума овладела мной,Имаш црну кугу -Squire,MNU_SQUIRE,,,,Panoš,Gutsherr,,Servanto,Escudero,,Aseenkantaja,Ecuyer,,Scudiero,見習い騎士,향사,Squire,Giermek,Escudeiro,,Scutier,Оруженосец,Штитоноша -Knight,MNU_KNIGHT,,,,Rytíř,Ritter,Ιππότης,Kavaliro,Caballero,,Ritari,Chevalier,,Cavaliere,騎士,기사,Ridder,Rycerz,Cavaleiro,,Cavaler,Рыцарь,Витез -Warrior,MNU_WARRIOR,,,,Válečník,Krieger,Πολεμιστής,Militisto,Guerrero,,Soturi,Guerrier,,Guerriero,戦士,전사,Krijger,Wojownik,Guerreiro,,Războinic,Воитель,Борац -Berserker,MNU_BERSERKER,,,,Berserkr,Berserker,,Frenezisto,Berserker,,Berserkkeri,,,Berserker,狂戦士,광전사,Berserker,Szaleniec,,,Turbat,Берсерк,Делија -Titan,MNU_TITAN,,,,Titán,Titan,Τιτάνας,Titano,Titán,,Titaani,,,Titano,タイタン,철인,Titan,Tytan,Titã,,Titan,Титан,Титан -Altar Boy,MNU_ALTARBOY,,,,Ministrant,Novize,,Altaranto,Monaguillo,,Pyhäkköpoika,Enfant de Chœur,,Chirichetto,堂役,복사,Altaarjongen,Ministrant,Menino de coral,Menino do coro,Paracliser,Алтарник,Министрант -Acolyte,MNU_ACOLYTE,,,,Akolyta,Missionar,,Pursuvanto,Acólito,,Alttaripalvelija,,,Accolito,侍祭,시종,Acoliet,Akolita,Coroinha,Acólito,Acolit,Служитель,Помоћник -Priest,MNU_PRIEST,,,,Kněz,Altardiener,,Pastro,Sacerdote,,Pappi,Prêtre,,Prete,司祭,사제,Priester,Kapłan,Padre,,Preot,Священник,Свештеник -Cardinal,MNU_CARDINAL,,,,Kardinál,Eingeweihter,,Preĝejestro,Cardenal,,Kardinaali,,,Cardinale,枢機卿,추기경,Kardinaal,Kardynał,Cardeal,,Cardinal,Кардинал,Кардинал -Pope,MNU_POPE,,,,Papež,Mystiker,Πάπας,Papo,Papa,,Paavi,Pape,,Papa,教皇,교황,Paus,Papież,Papa,,Papă,Епископ,Папа -Apprentice,MNU_APPRENTICE,,,,Učeň,Lehrling,,Lernanto,Aprendiz,,Kisälli,Apprenti,,Apprendista,入門者,조수,Leerling,Uczeń,Aprendiz,,Ucenic,Ученик,Шегрт -Enchanter,MNU_ENCHANTER,,,,Kouzelník,Zauberer,,Ravisto,Encantador,,Lumooja,Enchanteur,,Incantatore,妖術士,주술사,Betoveraar,Zaklinacz,Encantador,,Fermecător,Чародей,Чаробњак -Sorcerer,MNU_SORCERER,,,,Čaroděj,Hexer,,Sorĉisto,Hechicero,,Taikuri,Sorcier,,Mago,魔術士,마법사,Tovenaar,Mag,Feiticeiro,,Mag,Колдун,Врачар -Warlock,MNU_WARLOCK,,,,Zaklínač,Hexenmeister,,Magiisto,Brujo,,Noita,Mage de Guerre,,Stregone,黒魔術士,전투술사,Tovenaar,Wiedźmak,Mago,,Vrăjitor,Чернокнижник,Вештац -Archmage,MNU_ARCHMAGE,,,,Arcimág,Erzmagier,,Magiestranto,Archimago,,Arkkivelho,Archimage,,Arcimago,大魔導師,대마법사,Aartsbisschop,Arcymag,Arquimago,,Prim-Vrăjitor,Архимаг,Врховни вештац -Choose Class:,MNU_CHOOSECLASS,,,,Vyber třídu:,Figurengruppe wählen:,,Elektu Profesion:,Elige tú clase:,,Valitse luokka:,Choissisez une Classe:,,Scegli la classe:,クラス選抜:,영웅 선택:,Kies klasse:,Wybierz klasę:,Escolha a classe:,,Alege Clasa:,Класс:,Класа: -Fighter,MNU_FIGHTER,,,,Bojovník,Krieger,,Batalanto,Luchador,,Taistelija,Guerrier,,Combattente,戦士,전사,Vechter,Wojownik,Lutador,,Luptător,Воин,Борац -Cleric,MNU_CLERIC,,,,Klerik,Geistlicher,,Kleriko,Clérigo,,Pappi,Moine,,Chierico,僧侶,성직자,Geestelijk,Kleryk,Clérigo,,Cleric,Клерик,Свештеник -Mage,MNU_MAGE,,,,Mág,Magier,,Magianto,Mago,,Velho,,,Mago,魔導士,마법사,Tovenaar,Mag,Mago,,Magician,Маг,Чаробњак -Random,MNU_RANDOM,,,,Náhodný,Zufällig,,Loteca,Al Azar,,Satunnainen,Au Hasard,,Casuale,ランダム,랜덤,Willekeurig,Losowa,Aleatório,,Aleatoriu,Наугад,Насумично -Load Game,MNU_LOADGAME,,,,Načíst hru,Spiel laden,,Ŝarĝi Ludon,Cargar Partida,,Lataa peli,Chargement,,Carica gioco,ロード,게임 불러오기,Laden spel,Wczytaj Grę,Carregar,,Încărcare Joc,Загрузка,Учитај игру -Save Game,MNU_SAVEGAME,,,,Uložit hru,Spiel sichern,,Konservi Ludon,Guardar Partida,,Tallenna peli,Sauvegarde,,Salva gioco,セーブ,게임 저장하기,Opslaan spel,Zapisz Grę,Salvar,Gravar,Salvare Joc,Сохранение,Сачувај игру -No Picture,MNU_NOPICTURE,,,,Bez obrázku,Kein Bild,,Neniu Bildo,Sin Imagen,,Ei kuvaa,Pas d'image,,Nessuna immagine,画像無し,사진 없음,Geen beeld,Brak obrazka,Sem imagem,,Nicio Imagine,"Нет -изображения",Нема слике -"Different -Version",MNU_DIFFVERSION,,,,Jiná verze,Falsche Version,,Malsama Versio,Versión Diferente,,Eri versio,"Version -Différente",,Versione differente,"別バージョンの -データ",다른 버젼,Anders Versie,"Inna -Wersja","Versão -Diferente",,"Versiune -Diferită","Другая -версия",Другачија верзија -No files,MNU_NOFILES,,,,Žádné soubory,Keine Dateien,,Neniuj dosieroj,Sin archivos,,Ei tiedostoja,Pas de fichiers,,Nessun file,ファイル無し,파일 없음,Geen bestanden,Brak plików,Vazio,,Niciun Fișier,Нет файлов,Нема фајлова -"Do you really want to delete the savegame -",MNU_DELETESG,,,,Opravdu chceš smazat tuto uloženou hru?,Willst du diesen Spielstand wirklich löschen?,,Ĉu vi vere volas forviŝi la konservan ludon?,"¿Realmente deseas eliminar la partida? -",,Haluatko varmasti poistaa tallennetun pelin ,"Voulez vous vraiment effacer cette sauvegarde? -",Biztos ki akarod törölni a mentést?,Vuoi veramente rimuovere il salvataggio,本当にこのセーブを消すのか?,저장된 게임을 정말로 삭제하시겠습니까?,Wil je echt de opgeslagen spel verwijderen?,Czy naprawdę chcesz usunąć zapis gry,"Deseja mesmo deletar o jogo salvo -",Deseja mesmo apagar o jogo,Ești sigur că vrei să ștergi salvarea?,"Вы действительно хотите удалить сохранение -",Да ли стварно желите да избришете сачувану игру -Which Episode?,MNU_EPISODE,,,,Jakou epizodu?,Welche Episode?,,Kiun Epizodon?,¿Qué Episodio?,,Mikä episodi?,Quel épisode?,Melyik epizód?,Quale episodio?,どのエピソードだ?,에피소드 선택:,Welke aflevering?,Który Epizod?,Qual Episódio?,,Care Episod?,Какой эпизод?,Која епизода? -Choose Campaign,MNU_EPISODE,,strife,,Vyber kampaň,Mission auswählen,,Elektu Kampanjon,Selecciona una campaña,,Valitse kampanja,Choisissez la Campagne,Válassz hadjáratot.,Scegli la campagna,キャンペーンを選べ,캠페인을 고르시오:,Kies campagne,Wybierz kampanię,Escolha a Campanha,,Alege Campania,Выбор кампании,Изабери кампању -City of the Damned,MNU_COTD,,,,Město zatracených,Stadt der Verdammten,,Urbo de la Damnitaj,Ciudad de los Condenados,,Kirottuin kaupunki,La Cité des Damnés,A Nyomorultak Városa.,Città del dannato,呪われた都,멸망한 도시,Stad van de verdoemden,Miasto Przeklętych,Cidade dos Condenados,,Orașul Blestemaților,Город проклятых,Град проклетих -Hell's Maw,MNU_HELLSMAW,,,,Chřtán pekel,Der Schlund zur Hölle,,Faŭko de Infero,Fauces del infierno,,Hornankita,La Geule des Enfers,A Pokol Szája,Lo Stomaco dell'Inferno,地獄の肚,지옥의 목구멍,De slokdarm naar de hel,Paszcza Piekieł,A Boca do Inferno,,Străfundurile Infernului,Адская утроба,Чељусти пакла -The Dome of D'Sparil,MNU_DOME,,,,Báň D'Sparilova,D'Sparils Dom,,La Kupolo de D'Sparil,La Cúpula de D'Sparil,El Domo de D'Sparil,D'Sparilin kupoli,Le Dôme de D'Sparil,D'Sparil Dómja,La Casa del D'Sparil,デ'スパリルの穹窿,드'스파릴의 돔,D'Sparils Kathedraal,Gmach D'Sparila,A Cúpula de D'Sparil,,Domul lui D'Sparil,Купол Д'Спарила,Купола Д'Спарила -The Ossuary,MNU_OSSUARY,,,,Kostnice,Das Beinhaus,,La Ostejo,El Osario,,Luuhuone,L'Ossuaire,,L'Ossario,納骨堂,납골당,Het Ossuarium,Kostnica,O Ossuário,O Ossário,Osuarul,Склеп,Костурница -The Stagnant Demesne,MNU_DEMESNE,,,,Zatuchlé panství,Das stagnierende Reich,,La Senmova Posedaĵo,La Heredad Estancada,,Seisahtunut maa,Le domaine Stagnant,,La Proprietà terriera Stagnante,澱んだ荘園,침체된 영지,Het stagnerende rijk,Zapuszczona Posiadłość,O Reino Estagnado,,Tărâmul Stagnării,Застойные владения,Стагнирајући домени -,,Option Menus,,,,,,,,,,,,,,,,,,,,, -Select Color,MNU_COLORPICKER,,,Select Colour,Vyber barvu,Farbe auswählen,Επιλογή Χρώματος,Elektu Koloron:,Elige un color,,Valitse väri,Choisir Couleur,Szín Választás,Scegli il colore,色選択,색상을 고르시오,Selecteer Kleur,Wybierz Kolor,Selecione a Cor,,Alege o Culoare,Выбор цвета,Изабери боју -Options,OPTMNU_TITLE,,,,Možnosti,Optionen,Ρυθμίσεις,Agordoj,Opciones,,Asetukset,Options,Beállítások,Opzioni,オプション,설정,Opties,Opcje,Opções,,Opțiuni,Настройки,Подешавања -Customize Controls,OPTMNU_CONTROLS,,,,Nastavení ovládání,Steuerung einstellen,Αλλαγή Χειριστήριον,Agordi Regilojn,Personalizar Controles,,Ohjausasetukset,Modifier les Contrôles,Irányítás testreszabása,Personalizza i controlli,キー配置変更,조작 사용자 지정,Instellen van de controle,Ustaw Klawisze,Configurar Controles,Configurar Controlos,Personalizare Schemă de Control,Управление,Контроле -Mouse Options,OPTMNU_MOUSE,,,,Nastavení myši,Mauseinstellungen,Ρυθμίσεις Ποντικιού,Musagordoj,Opciones de Ratón,,Hiiriasetukset,Options de la Souris,Egér beállítások,Opzioni Mouse,マウス オプション,마우스 설정,Muis opties,Opcje Myszki,Opções de mouse,Opções do rato,Setări Mouse,Мышь,Миш -Controller Options,OPTMNU_JOYSTICK,,,,Nastavení ovladače,Joystickeinstellungen,Ρυθμίσεις Χειριστήριον,Ludregilagordoj,Opciones de Mando,,Peliohjainasetukset,Options de la Manette,Játékvezérlő beállítások,Opzioni Joystick,コントローラーオプション,조이스틱 설정,Controller opties,Opcje Kontrolera,Opções de joystick,,Setări Controller,Контроллер,Контролер -Player Setup,OPTMNU_PLAYER,,,,Nastavení hráče,Spieler einrichten,Ρυθμίσεις Πάιχτη,Ludanta Agordaĵo,Config. del Jugador,,Pelaaja-asetukset,Options du Joueur,Játékos testreszabása,Settaggio giocatore,プレイヤーの特徴,플레이어 설정,Speler instellen,Ustawienia Gracza,Configurações de Jogador,Configurações do Jogador,Setări Jucător,Игрок,Играч -Gameplay Options,OPTMNU_GAMEPLAY,,,,Nastavení herních mechanik,Spieleinstellungen,Ρυθμίσεις Παιχνιδιού,Ludadagordoj,Opciones de Jugabilidad,,Pelattavuusasetukset,Options du Gameplay,Játék mechanika,Opzioni Gameplay,ゲームプレイ オプション,게임 설정,Gameplay-opties,Opcje Rozgrywki,Opções de jogabilidade,,Setări de Joc,Геймплей,Гејмплеј -Compatibility Options,OPTMNU_COMPATIBILITY,,,,Nastavení kompatibility,Kompatibilitätseinstellungen,Ρυθμίσεις Συμβατότητας,Kongruagordoj,Opciones de Compatibilidad,,Yhteensopivuusasetukset,Options de Compatibilité,Kompatibilitási beállítások,Opzioni Compatibilità,互換性 オプション,호환 설정,Compatibiliteitsopties,Opcje Zgodności,Opções de compatibilidade,,Setări de Compatibilitate,Совместимость,Компатибилност -Automap Options,OPTMNU_AUTOMAP,,,,Nastavení automapy,Automapeinstellungen,Ρυθμίσεις Χάρτη,Aŭtomapagordoj,Opciones del Automapa,,Automaattikartan asetukset,Options de la Carte,Térkép beállítások,Opzioni Automappa,オートマップ オプション,오토맵 설정,Automap-opties,Opcje Mapy,Opções de automapa,,Setări Hartă Computerizată,Автокарта,Аутомапа -HUD Options,OPTMNU_HUD,,,,Nastavení HUD,HUD Einstellungen,Ρυθμίσεις Προβολής Επικεφαλής,Agordoj de HUD,Opciones del HUD,,Tilanäytön asetukset,Options de l'ATH,HUD beállítások,Opzioni HUD,HUD オプション,HUD 설정,HUD opties,Opcje Paska HUD,Opções de HUD,,Setări Interfață în Timpul Jocului,HUD,HUD -Miscellaneous Options,OPTMNU_MISCELLANEOUS,,,,Ostatní nastavení,Verschiedene Einstellungen,Διάφορες Ρυθμίσεις ,Ekstraĵagordoj,Opciones Misceláneas,,Sekalaiset asetukset,Options Annexes,Általános beállítások,Opzioni miste,その他のオプション,그 외 설정,Diverse opties,Różne Opcje,Outras opções,,Setări Suplimentare,Дополнительно,Разно -Network Options,OPTMNU_NETWORK,,,,Nastavení sítě,Netzwerkeinstellungen,Ρυθμίσεις Δικτύου,Retagordoj,Opciones de Red,,Verkkoasetukset,Options Réseau,Hálózati beállítások,Opzioni Network,ネットワーク オプション,네트워크 설정,Netwerkopties,Opcje Sieciowe,Opções de rede,,Setări de Rețea,Сеть,Мрежа -Sound Options,OPTMNU_SOUND,,,,Nastavení zvuku,Soundeinstellungen,Ρυθμίσεις Ήχου,Sonagordoj,Opciones de Sonido,,Ääniasetukset,Options du Son,Hang beállítások,Opzioni Suono,サウンド オプション,음향 설정,Geluidsopties,Opcje Dźwięku,Opções de som,,Setări Sunet,Звук,Звук -Display Options,OPTMNU_DISPLAY,,,,Nastavení grafiky,Anzeigeeinstellungen,Ρυθμίσεις Προβολής,Ekranagordoj,Opciones de Visualización,,Näyttöasetukset,Options de l'Affichage,Megjelenítés beállítások,Opzioni Display,ディスプレイ オプション,디스플레이 설정,Weergaveopties,Opcje Wyświetlania,Opções de vídeo,,Setări Afișare,Экран,Приказ -Set video mode,OPTMNU_VIDEO,,,,Nastavit režim displeje,Videomodus,Άλλαγη λειτουργίας βίντεο,Agordi videoreĝimon,Modos de Vídeo,,Aseta videotila,Choisir Mode D'Affichage,Felbontás,Settaggio modalità video,ビデオ 調整,화면 설정,Videomodus instellen,Ustaw tryb wideo,Definir modo de vídeo,,Setare Mod Video,Видеорежим,Видео мод -Change Rendering Output,OPTMNU_CHANGERENDER,,,,Změnit výstup vykreslování,Render-Modus,Άλλαγη παραγωγής βίντεο,Ŝanĝi Bildigon Eligon,Cambiar Tipo de Renderizado,,Vaihda hahmonnustilaa,Changer de Moteur de Rendu,Renderelés beállítása,Cambia l'output del motore grafico,レンダー出力設定,렌더링 출력 전환,Renderingmodus,Zmień Wyjście Renderowania,Alterar tipo de renderizador,,Schimbare Mod Redare Video,Режим рендеринга,Промени рендеринг излаз -Reset to defaults,OPTMNU_DEFAULTS,,,,Obnovit původní,Auf Vorgaben zurücksetzen,Επαναφορά στής προεπιλογές,Reŝanĝi al defaŭltoj,Valores por Defecto,,Palauta oletusasetukset,Réinitialiser les paramètres,Alapértelmezett beállítások használata,Reimposta ai valori di default,初期設定に戻す,초기화,Terugzetten naar standaardinstellingen,Resetuj do domyślnych,Redefinir para configurações padrão,,Revenire la Setările Implicite,Сбросить все настройки,Врати подразумевано -Reset to last saved,OPTMNU_RESETTOSAVED,,,,Obnovit naposledy uložené,Auf gespeicherte Werte zurücksetzen,Επαναφορά στο τελευτάια αποθηκευμένο,Reŝanĝi al lasta konservo,Últimos Valores Guardados,,Palauta viimeksi tallennettu tila,Recharger dernière config.,Legutóbbi mentett beállítások használata,Reimposta ai valori salvati l'ultima volta,最後に保存した設定に戻す,이전 설정으로 초기화,Reset naar laatste opgeslagen,Resetuj do ostatnio zapisanych,Redefinir para última configuração salva,Redefinir para última configuração gravada,Revenire la Setările Anterioare,Вернуть предыдущие настройки,Врати задње сачувано -Go to console,OPTMNU_CONSOLE,,,,Jít do konzole,Öffne Konsole,Εισαγογή στη κονσόλα,Iri al konzolo,Ir a la consola,,Mene konsoliin,Ouvrir la console,Konzol megnyitása,Vai alla console,コンソールを開く,콘솔로 이동,Ga naar de console,Przejdź do konsoli,Abrir console,Abrir consola,Mergi la consolă,Открыть консоль,Отвори конзолу -Reverb environment editor,OPTMNU_REVERB,,,,Editor zvukové ozvěny,Hall-Editor,Επεξεργαστής περιβαλλόντων απόσβεσης,Redaktoro pri resonmedio,Editor de Amb. de Reverb.,,Kaikutilaeditori,Editeur environement de révérb.,Visszhang-környezet szerkesztő,Editor ambiente reverb,リバーブ環境エディタ,울림 환경 편집기,Reverb-omgeving editor,Edytor pogłosu środowiska,Editor de ambiente de reverberação,,Setări Reverb,Редактор реверберации,Уредник одјека у околини -Language,OPTMNU_LANGUAGE,,,,Jazyk,Sprache,Γλώσσα,Lingvo,Idioma,,Kieli,Langage,Nyelv,Lingua,言語設定,언어,Taal,Język,Idioma,,Limbă,Язык,Језик -Customize Controls,CNTRLMNU_TITLE,,,,Nastavení ovládání,Steuerung einstellen,Αλλαγή Χειριστήριον,Agordi Regilojn,Personalizar Controles ,,Ohjausasetukset,Modifier contrôles,Irányítás testreszabása,Personalizza i controlli,キー配置変更,조작 사용자 지정,Instellen van de controle,Ustaw Klawisze,Configurar Controles,Configurar Controlos,Personalizare Schemă de Control,Настройки управления,Подешавања контрола -"ENTER to change, BACKSPACE to clear",CNTRLMNU_SWITCHTEXT1,,,,"ENTER pro změnu, BACKSPACE pro smazání",ENTER: Editieren BACKSPACE: Löschen,"ENTER για αλλαγή, BACKSPACE για καθαρισμό","ENTER klavo por ŝanĝi, BACKSPACE klavo por viŝi","ENTER para cambiar, BACKSPACE para limpiar",,"Aseta ENTERILLÄ, tyhjennä ASKELPALAUTTIMELLA","ENTREE pour changer, RET. ARRIERE pour effacer.","ENTER a változtatáshoz, BACKSPACE a törléshez","INVIO per modificare, BACKSPACE per ripulire",Enter で決定、BackSpaceで無効化,"바꿀려면 ENTER키, 지울려면 BACKSPACE키를 누르시오","ENTER om te veranderen, BACKSPACE om te wissen.","ENTER by zmienić, BACKSPACE by wyczyścić","ENTER para alterar, BACKSPACE para limpar",,"Apasă ENTER pentru schimbare, BACKSPACE pentru ștergere","ENTER — изменить, BACKSPACE — очистить","ENTER за промену, BACKSPACE за чишћење" -"Press new key for control, ESC to cancel",CNTRLMNU_SWITCHTEXT2,,,,"Zmáčkni novou klávesu pro nastavení, ESC pro storno",Drücke eine Taste oder ESC um abzubrechen,"Πάτα το κουμπί που θέλεις για αθτο το χειριστήριο, ESC για ακύρωση","Premi novan klavon por reakiri regilon, ESC por nuligi","Presiona una tecla para el control, ESC para cancelar",,"Valitse näppäin toiminnolle, ESC peruuttaa","Appuyez sur la nouvelle touche pour l'assigner, -Appuyez sur ECHAP pour annuler.","Nyomj meg egy gombot, ESC a törléshez","Premi un nuovo tasto per il controllo, ESC per cancellare","登録したいキーを押すか, Escでキャンセル","명령을 얽으려면 아무 키를, 취소는 ESC키를 누르시오","Druk op de nieuwe toets voor controle, ESC om te annuleren.","Wciśnij nowy przycisk by zmienić klawisz, ESC by anulować","Aperte a nova tecla para o comando, ESC para cancelar","Carrega a nova tecla para o comando, ESC para cancelar","Apasă o tastă nouă, sau ESC pentru anulare","Нажмите клавишу управления, ESC для отмены","Притисните ново тастер за одређивање контроле, ESC за отказивање" -Controls,CNTRLMNU_CONTROLS,,,,Ovládání,Steuerung,Χειριστήρια,Regiloj,Controles,,Ohjaimet,Contrôles,Irányítás,Controlli,操作系統,조작,Bedieningselementen,Klawisze,Comandos,Controlos,Control,Управление,Контроле -Fire,CNTRLMNU_ATTACK,,,,Střelba,Feuer,Πυροβόλα,Pafi,Fuego,,Tuli,Tirer,Tűz,Fuoco,撃つ,공격,Vuur,Strzał,Atirar,,Foc,Атака,Нападни -Secondary Fire,CNTRLMNU_ALTATTACK,,,,Sekundární střelba,Alternativfeuer,Πυροβόλα (Δέυτερο),Duaranga Pafi,Fuego secundario,,Vaihtoehtoistuli,Tir Secondaire,Másodlagos tüzelés,Fuoco secondario,セカンダリ,보조 공격,Secundaire vuur,Strzał Alternatywny,Tiro Secundário,,Mod de Foc Alternativ,Вторичная атака,Секундарни напад -Weapon Reload,CNTRLMNU_RELOAD,,,,Přebít zbraň,Waffe nachladen,Επαναφόρτωση Όπλου,Armilreŝarĝo,Recargar,,Aseen lataus,Recharger Arme,Fegyver újratöltése,Ricarica dell'arma,リロード,무기 장전,Wapenherlading,Przeładowanie Broni,Recarregar Arma,,Încărcare Armă,Перезарядка,Напуни -Weapon Zoom,CNTRLMNU_ZOOM,,,,Přiblížení zbraně,Waffenzoom,Ζοομ,Armilzumo,Zoom del arma,,Aseen kiikaritähtäys,Zoom avec Arme,Közelítés fegyverrel,Zoom dell'arma,ズーム,무기 조준,Wapen Zoom,Przybliżenie Broni,Zoom da Arma,,Zoom Armă,Приближение,Зум -Weapon State 1,CNTRLMNU_USER1,,,,Akce zbraně 1,Waffen-Aktion 1,Κατάσταση Όπλου 1,Armilstato 1,Estado del arma 1,,Aseen tila 1,Etat d'Arme 1,Fegyver 1. állapot,Stato dell'arma 1,武器特殊動作 1,무기 상태 1,Wapen staat 1,Stan Broni 1,Estado da Arma 1,,Poziție Armă 1,Положение оружия (1),Стање оружја (1) -Weapon State 2,CNTRLMNU_USER2,,,,Akce zbraně 2,Waffen-Aktion 2,Κατάσταση Όπλου 2,Armilstato 2,Estado del arma 2,,Aseen tila 2,Etat d'Arme 2,Fegyver 2. állapot,Stato dell'arma 2,武器特殊動作 2,무기 상태 2,Wapen staat 2,Stan Broni 2,Estado da Arma 2,,Poziție Armă 2,Положение оружия (2),Стање оружја (2) -Weapon State 3,CNTRLMNU_USER3,,,,Akce zbraně 3,Waffen-Aktion 3,Κατάσταση Όπλου 3,Armilstato 3,Estado del arma 3,,Aseen tila 3,Etat d'Arme 3,Fegyver 3. állapot,Stato dell'arma 3,武器特殊動作 3,무기 상태 3,Wapen staat 3,Stan Broni 3,Estado da Arma 3,,Poziție Armă 3,Положение оружия (3),Стање оружја (3) -Weapon State 4,CNTRLMNU_USER4,,,,Akce zbraně 4,Waffen-Aktion 4,Κατάσταση Όπλου 4,Armilstato 4,Estado del arma 4,,Aseen tila 4,Etat d'Arme 4,Fegyver 4. állapot,Stato dell'arma 4,武器特殊動作 4,무기 상태 4,Wapen staat 4,Stan Broni 4,Estado da Arma 4,,Poziție Armă 4,Положение оружия (4),Стање оружја (4) -Use / Open,CNTRLMNU_USE,,,,Použít / otevřít,Benutzen / Öffnen,Χρήση/Άνοιγμα,Uzi / Malfermi,Usar / Abrir,,Käytä / Avaa,Utiliser/Ouvrir,Használ / Ajtónyitás,Usa / Apri,開く / スイッチ等使用,사용/열기,Gebruik / Openen,Użyj / Otwórz,Usar / Abrir,,Activare / Deschidere,Использовать/открыть,Користи / Отвори -Move forward,CNTRLMNU_FORWARD,,,,Pohyb vpřed,Vorwärts bewegen,Κίνηση Μπροστά,Movi anatŭe,Avanzar,,Liiku eteenpäin,Avancer,Előre mozgás,Movimento in Avanti,前進,앞으로 이동,Voorwaarts bewegen,Idź do przodu,Mover para frente,,Deplasare în Față,Движение вперёд,Крећи се напред -Move backward,CNTRLMNU_BACK,,,,Pohyb vzad,Rückwarts bewegen,Κίνηση Πίσω,Movi malantaŭe,Retroceder,,Liiku taaksepäin,Reculer,Hátra mozgás,Movimento in Indietro,後退,뒤로 이동,Achteruit bewegen,Idź do tyłu,Mover para trás,,Deplasare în Spate,Движение назад,Крећи се уназад -Strafe left,CNTRLMNU_MOVELEFT,,,,Pohyb doleva,Nach links bewegen,Κίνηση Αριστερά,Flankmovi maldekstre,Moverse a la izquierda,,Astu sivuun vasemmalle,Aller à Gauche,Balra oldalazás,Movimento laterale a sinistra,左移動,왼쪽으로 이동,Verplaats naar links,Unik w lewo,Mover para a esquerda,,Deplasare în diagonală spre Stânga,Движение влево,Крећи се лево -Strafe right,CNTRLMNU_MOVERIGHT,,,,Pohyb doprava,Nach rechts bewegen,Κίνηση Δεξιά,Flankmovi dekstre,Moverse a la derecha,,Astu sivuun oikealle,Aller à Droite,Jobbra oldalazás,Movimento laterale a destra,右移動,오른쪽으로 이동,Verplaats naar rechts,Unik w prawo,Mover para a direita,,Deplasare în diagonală spre Dreapta,Движение вправо,Крећи се десно -Turn left,CNTRLMNU_TURNLEFT,,,,Otočení vlevo,Nach links drehen,Γύρνα Αριστερά,Turni maldekstre,Girar a la izquierda,,Käänny vasemmalle,Tourner à Gauche,Balra fordul,"Gira a sinistra -",左を向く,왼쪽으로 회전,Draai naar links,Obróć się w lewo,Girar para a esquerda,,Rotire spre Stânga,Поворот налево,Окрени се лево -Turn right,CNTRLMNU_TURNRIGHT,,,,Otočení vpravo,Nach rechts drehen,Γύρνα Δεξιά,Turni dekstre,Girar a la derecha,,Käänny oikealle,Tourner à Droite,Jobbra fordul,Gira a destra,右を向く,오른쪽으로 회전,Draai naar rechts,Obróć się w prawo,Girar para a direita,,Rotire spre Dreapta,Поворот направо,Окрени се десно -Quick Turn,CNTRLMNU_TURN180,,,,Rychlé otočení,Schnelle Drehung,Γρήγορη Στροφή,Rapida turno,Giro rápido,,Pikakäännös,Faire un 180,Megfordulás,Rotazione rapida,背後を向く,빠른 회전,Snelle draai,Nagły Obrót,Giro rápido,,Rotire Rapidă,Быстрый разворот,Брзи окрет -Jump,CNTRLMNU_JUMP,,,,Skok,Springen,Πήδημα,Salti,Saltar,,Hyppää,Sauter,Ugrás,Salta,ジャンプ,점프,Springen,Skok,Pular,Saltar,Săritură,Прыжок,Скок -Crouch,CNTRLMNU_CROUCH,,,,Kleknutí,Ducken,Σκύψιμο,Kaŭri,Agacharse,,Kyyristy,S'accroupir (tenir),Guggolás,Abbassati,屈む,숙이기,Hurken,Kucnięcie,Agachar,,Ghemuire,Приседание,Чучни -Crouch Toggle,CNTRLMNU_TOGGLECROUCH,,,,Zap. / Vyp. kleknutí,Ducken an/aus,Ενεργοποίηση σκύψιμου,Kaŭrbaskulo,Alternar agachado,,Kyyristymisen vaihtokytkin,S'accroupir (alterner),Guggolási kapcsoló,Toggle abbassamento,屈む切替,숙이기 토글,Hurken Toggle,Włącz / Wyłącz kucnięcie,Agachar (Liga/Desliga),,Comutator pentru Ghemuire,Сесть/встать,Чучни (без држања) -Fly / Swim up,CNTRLMNU_MOVEUP,,,,Letět / plavat vzhůru,Fliegen / Hochschwimmen,Πέτα/Κολύμπα πάνω,Flugi/Naĝi supre,Volar / Nadar arriba,,Lennä / Ui ylös,Voler/Nager en haut,Repülés / Felfele úszás,Vola / Nuota in alto,飛行/水泳時 上昇,위로 날기 / 해엄치기,Vliegen/zwemmen omhoog,Lot / Pływanie w górę,Voar / Nadar para cima,,Zbor / Înot în Sus,Лететь/плыть вверх,Лети/пливај нагоре -Fly / Swim down,CNTRLMNU_MOVEDOWN,,,,Letět / plavat dolů,Fliegen / Runterschwimmen,Πέτα/Κολύμπα κάτω,Flugi/Naĝi malsupre,Volar / Nadar abajo,,Lennä / Ui alas,Voler/Nager en bas,Repülés / Lefele úszás,Vola / Nuota in basso,飛行/水泳時 下降,아래로 날기 / 해엄치기,Vliegen/zwemmen naar beneden,Lot / Pływanie w dół,Voar / Nadar para baixo,,Zbor / Înot în Jos,Лететь/плыть вниз,Лети/пливај надоле -Stop flying,CNTRLMNU_LAND,,,,Přestat létat,Landen,Σταμάτα πέταμα,Ĉesi flugi,Dejar de volar,,Lopeta lentäminen,Arrêter de voler,Repülés abbahagyása,Stop al volo,飛行停止,비행 정지,Stop met vliegen,Przestań latać,Parar de voar,,Încetare Zbor,Приземлиться,Престани летети -Mouse look,CNTRLMNU_MOUSELOOK,,,,Pohled myší,Maus-Blick,Κατακόρυφο κοίταχμα (Ποντίκι),Musilregardo,Vista con ratón,,Hiirikatselu,Vue à la souris,Egérrel való nézelődés,Modalità vista col mouse,マウス視点上下化,마우스 룩,Muis-look,Rozglądanie się myszką,Vista com o mouse,Vista com o rato,Utilizare Mouse pentru a Privi în Jur,Обзор мышью,Гледај мишем -Keyboard look,CNTRLMNU_KEYBOARDLOOK,,,,Pohled klávesnicí,Tastatur-Blick,Κατακόρυφο κοίταχμα (Πλητρoλόγιο),Klavarregardo,Vista con teclado,,Näppäinkatselu,Vue au clavier,Billentyűzettel való nézelődés,Modalità vista con la tastiera,キー視点上下化,키보드 룩,Toetsenbord look,Rozglądanie się klawiaturą,Vista com o teclado,,Utilizare Tastatură pentru a Privi în Jur,Обзор клавиатурой,Гледај тастатуром -Look up,CNTRLMNU_LOOKUP,,,,Pohled vzhůru,Nach oben schauen,Κοίτα πάνω,Rigardi supre,Mirar arriba,,Katso ylös,Regarder en haut,Felfele nézés,Guarda sopra,視点を上げる,위로 보기,Kijk omhoog,Patrz w górę,Olhar para cima,,Privește în Sus,Смотреть вверх,Гледај горе -Look down,CNTRLMNU_LOOKDOWN,,,,Pohled dolů,Nach unten schauen,Κοίτα κάτω,Rigardi malsupre,Mirar abajo,,Katso alas,Regarder en bas,Lefele nézés,Guarda sotto,視点を下げる,아래로 보기,Kijk naar beneden,Patrz w dół,Olhar para baixo,,Privește în Jos,Смотреть вниз,Гледај доле -Center view,CNTRLMNU_CENTERVIEW,,,Centre view,Vystředit pohled,Ansicht zentrieren,Κεντράρισμα όρασης,Centra vidon,Centrar vista,,Keskitä katse,Recentrer Vue,Nézet középreigazítása,Sguardo centrato,視点を戻す,중앙 시점으로 보기,Middenaanzicht,Wyśrodkuj widok,Olhar para o centro,,Privește Înainte,Отцентрировать взгляд,Централизирај поглед -Run,CNTRLMNU_RUN,,,,Běh,Rennen,Τρέχα,Kuri,Correr,,Juokse,Courir (tenir),Futás,Corri,駆け足,달리기,Rennen,Bieg,Correr,,Fugă,Бег,Трчи -Toggle Run,CNTRLMNU_TOGGLERUN,,,,Zap. / Vyp. běh,Rennen an/aus,Ενεργοποίηση τρέξιμου,Baskulkuri,Alternar Correr,,Juoksun vaihtokytkin,Courir (alterner),Futás kapcsoló,Toggle corsa,常時駆け足切替,달리기 토글,Rennen aan/uit,Włącz / Wyłącz bieg,Correr (Liga/Desliga),,Comutator pentru Fugă,Бежать/идти,Трчи (без држања) -Strafe,CNTRLMNU_STRAFE,,,,Pohyb vlevo/vpravo,Seitwärts,Σφυροκόπιμα,Flankmovi,Desplazamiento,,Astu sivuttain,Pas de côté,,Spostamento laterale,横移動化,양옆으로 이동,Zijdelings bewegen,Uniki,Deslocamento lateral,,Deplasare în diagonală,Движение боком,Кретање у страну -Show Scoreboard,CNTRLMNU_SCOREBOARD,,,,Zobrazit tabulku skóre,Punktetafel anzeigen,Προβολή Πίνακα Σκόρ,Montri poentartabulon,Mostrar Marcador,,Näytä pistetaulu,Afficher Scores (tenir),Eredményjelző megjelenítése,Mostra la tabella punteggio,スコアボード表示,점수창 표시,Scorebord tonen,Pokaż tablicę wyników,Mostrar pontuação,,Afișare Tabelă de Marcaj,Таблица очков,Табела -Toggle Scoreboard,CNTRLMNU_TOGGLESCOREBOARD,,,,Zap. / Vyp. tabulku skóre,Punktetafel an/aus,Ενεργοποίηση Πίνακα Σκόρ,Baskuligi poentartabulon,Alternar Marcador,,Pistetaulun vaihtokytkin,Afficher Scores (alterner),Eredményjelző kapcsoló,Abilita/disabilita tabella punteggio,スコアボード切替,점수창 토글,Scorebord aan/uit,Włącz / Wyłącz tablicę wyników,Manter pontuação na tela,Manter Pontuação no Ecrã,Comutator pentru Tabela de Marcaj,Таблица очков (перекл.),Табела (без држања) -Action,CNTRLMNU_ACTION,,,,Akce,Aktion,Ενέργειες,Ago,Acción,,Toiminta,,Akció,Azione,アクション,동작,Actie,Akcja,Ação,,Acțiune,Основное,Радња -Customize Action Controls,CNTRLMNU_ACTION_TITLE,,,,Nastavit ovládání akcí,Aktions-Steuerung einstellen,Προσαρμογή Χειριστήριων Ενεργιών,Agordi Agajn Regilojn,Controles de Acción,,Toimintaohjausasetukset,Changer Contrôles Action,Akció beállítások testreszabása,Personalizza i controlli di azione,アクション操作設定,사용자 지정 동작 컨트롤,Aanpassen van de actiecontroles,Ustaw Klawisze Akcji,Configurar Comandos de Ação,Configurar Controlos de Ação,Personalizare Comenzi pentru Control,Основные клавиши управления,Контроле радње -Customize Chat Controls,CNTRLMNU_CHAT_TITLE,,,,Nastavit ovládání chatu,Chat-Steuerung einstellen,Προσαρμογή Χειριστήριων Ομιλίας,Agordi Babiladajn Regilojn,Controles de Chat,,Keskusteluohjausasetukset,Changer Contrôles Chat,Chat beállítások testreszabása,Personalizza i controlli della chat,チャット操作設定,사용자 지정 채팅 컨트롤,Chat-controles aanpassen aan uw wensen,Ustaw Klawisze Czatu,Configurar Comandos de Chat,Configurar Controlos de Chat,Personalizare Comenzi pentru Chat,Клавиши управления чатом,Контроле ћаскања -Customize Weapon Controls,CNTRLMNU_WEAPONS_TITLE,,,,Nastavit ovládání zbraní,Waffen-Steuerung einstellen,Προσαρμογή Χειριστήριων Όπλων,Agordi Armilojn Regilojn,Controles de Armas,,Aseohjausasetukset,Changer Contrôles Armes,Fegyver beállítások testreszabása,Personalizza i controlli delle armi,武器操作設定,사용자 지정 무기 컨트롤,Wapencontroles aanpassen aan uw eigen wensen,Ustaw Klawisze Broni,Configurar Comandos de Arma,Configurar Controlos de Armas,Personalizare Schemă de Control Arme,Клавиши управления оружием,Контроле оружја -Customize Inventory Controls,CNTRLMNU_INVENTORY_TITLE,,,,Nastavit ovládání inventáře,Inventar-Steuerung einstellen,Προσαρμογή Χειριστήριων Εμπορευμάτων,Agordi Inventarajn Regilojn,Controles de Inventario,,Varusteohjausasetukset,Changer Contrôles Inventaires,Eszköztár beállítások testreszabása,Personalizza i controlli dell'inventario,インベントリ操作設定,사용자 지정 인벤토리 컨트롤,Inventariscontroles aanpassen aan uw wensen,Ustaw Klawisze Ekwipunku,Configurar Comandos de Inventário,Configurar Controlos de Inventário,Personalizare Schemă de Control Inventar,Клавиши управления инвентарём,Контроле складишта -Customize Other Controls,CNTRLMNU_OTHER_TITLE,,,,Nastavit ostatní ovládání,Sonstige Steuerung einstellen,Προσαρμογή Διάφωρων Χειριστήριων,Agordi Ekstrajn Regilojn,Otros Controles,,Muut ohjausasetukset,Changer Autres Contrôles,Egyéb irányítás testreszabása,Personalizza altri controlli,その他の操作設定,사용자 지정 그 외 컨트롤,Andere bedieningselementen aanpassen,Ustaw Inne Klawisze,Configurar Outros Comandos,Configurar Outros Controlos,Personalizare Scheme Suplimentare,Прочие клавиши,Друге контроле -Strife Popup Screens Controls,CNTRLMNU_POPUPS_TITLE,,,,Ovládání vyskakovacích oken ve Strife,Strife Popup Steuerung einstellen,,Strife Ŝprucfenestra Regilojn,Popups de Strife,,Strifen ponnahdusruutujen ohjausasetukset,Contrôles Popups Strife,Strife Felugró Ablakok Irányítása,Controlli Schermate popup di Strife,Strifeポップアップ表示設定,스트라이프 팝업 화면 조작,Strife Popup Schermen Bedieningselementen voor Popup-schermen,Ustaw Klawisze Okienek Strife'a,Comandos de Popups do Strife,Controlos de Popups do Strife,Control pentru Mesaje Strife,Всплывающие окна Strife,Искакајући прикази контроле у Strife-у -Pause,CNTRLMNU_PAUSE,,,,Pauza,,Πάυση,Paŭzo,Pausa,,Tauko,,Szünet,Pausa,ポーズ,일시정지,Pauze,Pauza,Pausa,,Pauză,Пауза,Пауза -Increase Display Size,CNTRLMNU_DISPLAY_INC,,,,Zvětšit velikost displeje,Anzeige vergrößern,Άυξηση Μεγέθους Οθόνης,Pligrandigi Ekranamplekson,Agrandar Ventana,,Suurenna näytön kokoa,Agrandir l'affichage,Képméret növelése,Incrementa la dimensione del display,画面サイズを拡大,화면 크기 늘리기,Vergroot het display,Powiększ Rozmiar Wyświetlania,Aumentar Tamanho de Tela,Aumentar Tamanho do Ecrã,Mărire Dimensiune Afișaj,Увеличить размер экрана,Повећајте величину екрана -Decrease Display Size,CNTRLMNU_DISPLAY_DEC,,,,Zmenšit velikost displeje,Anzeige verkleinern,Μείωση Μεγέθους Οθόνης,Plimalgrandigi Ekranamplekson,Reducir Ventana,,Pienennä näytön kokoa,Réduire l'affichage,Képméret csökkentése,Decrementa la dimensione del display,画面サイズを縮小,화면 크기 줄이기,Verlaag het display,Pomniejsz Rozmiar Wyświetlania,Diminuir Tamanho de Tela,Diminuir Tamanho do Ecrã,Micșorare Dimensiune Afișaj,Уменьшить размер экрана,Смањите величину екрана -Open Help,CNTRLMNU_OPEN_HELP,,,,Otevřít nápovědu,Hilfe öffnen,Άνοιγμα Βοήθειας,Malfermi Helpon,Abrir Ayuda,,Avaa ohje,Ouvrir Aide,Segítség előhozása,Apri l'aiuto,"ヘルプを開く -",도움말 열기,Open hulp,Otwórz Pomoc,Abrir Ajuda,,Deschidere Meniu pentru Ajutor,Экран помощи,Отвори помоћ -Open Save Menu,CNTRLMNU_OPEN_SAVE,,,,Otevřít menu pro uložení,Speichermenü öffnen,,Malfermi Konservmenuon,Menú de Guardar Partida,,Avaa tallennusvalikko,Ouvrir Menu Sauvegarde,Mentés menü előhozása,Apri il menu di salvataggio,セーブメニューを開く,저장 화면 열기,Menu opslaan openen,Otwórz Menu Zapisu,Abrir Menu de Salvar,Abrir Menu de Gravação,Deschidere Meniu Salvări,Сохранение игры,Отвори сачуване игре -Open Load Menu,CNTRLMNU_OPEN_LOAD,,,,Otevřít menu pro načtení,Lademenü öffnen,,Malfermi Ŝarĝmenuon,Menú de Cargar Partida,,Avaa latausvalikko,Ouvrir Menu Chargement,Betöltés menü előhozása,Apri il menu di caricamento,ロードメニューを開く,불러오기 화면 열기,Menu laden openen,Otwórz Menu Wczytania,Abrir Menu de Carregar,,Deschidere Meniu Încărcări,Загрузка игры,Отвори игре за учитати -Open Options Menu,CNTRLMNU_OPEN_OPTIONS,,,,Otevřít nastavení,Optionsmenü öffnen,Άνοιγμα Μενού Ρυθμίσεων,Malfermi Agordmenuon,Menú de Opciones,,Avaa asetusvalikko,Ouvrir Menu Options,Beállítások menü előhozása,Apri il menu delle opzioni,オプションメニューを開く,설정 화면 열기,Menu Opties openen,Otwórz Menu Opcji,Abrir Menu de Opções,,Deschidere Meniu Opțiuni,Главное меню настроек,Отвори мени опција -Open Display Menu,CNTRLMNU_OPEN_DISPLAY,,,,Otevřít nastavení grafiky,Anzeigemenü öffnen,Άνοιγμα Μενού Οθόνης,Malfermi Ekranmenuon,Menú de Opciones de Visualización,,Avaa näyttövalikko,Ouvrir Menu Affichage,Megjelenítés menü előhozása,Apri il menu del display,ディスプレイメニューを開く,디스플레이 화면 열기,Displaymenu openen,Otwórz Menu Wyświetlania,Abrir Menu de Vídeo,,Deschidere Meniu Afișaj,Меню настроек видео,Отвори мени приказа -Quicksave,CNTRLMNU_QUICKSAVE,,,,Rychlé uložení,Schnellspeichern,Γρήγορη Αποθήκευση,Rapidkonservo,Guardado Rápido,,Pikatallenna,Sauv. Rapide,Gyorsmentés,Salvataggio rapido,クイックセーブ,빠른 저장,Snel opslaan,Szybki Zapis,Quicksave,Gravação rápida,Salvare Rapidă,Быстрое сохранение,Брзо-сачувај -Quickload,CNTRLMNU_QUICKLOAD,,,,Rychlé načtení,Schnellladen,Γρήγορη Φόρτωση,Rapidŝarĝo,Cargado Rápido,,Pikalataa,Charg. Rapide,Gyors betöltés,Caricamento rapido,クイックロード,빠른 불러오기,Snel laden,Szybkie Wczytanie,Quickload,,Încărcare Rapidă,Быстрая загрузка,Брзо-учитај -Exit to Main Menu,CNTRLMNU_EXIT_TO_MAIN,,,,Odejít do hlavního menu,Zurück zum Hauptmenü,Έξοδος στο Κύριο Μενού,Eliri al Ĉefa Menuo,Salir al Menú Principal,,Poistu päävalikkoon,Sortie Menu Principal,Kilépés a főmenübe,Esci dal menu principale,メインメニューに戻る,메뉴로 나오기,Afsluiten naar het hoofdmenu,Wyjdź do Głównego Menu,Sair para o Menu Principal,,Revenire la Meniul Principal,Выход в главное меню,Изађи у главни мени -Toggle Messages,CNTRLMNU_TOGGLE_MESSAGES,,,,Zap. / Vyp. zprávy,Nachrichten an/aus,Ενεργοποίηση Μήνυματων,Baskuligi Mensaĝojn,Alternar Mensajes,,Kytke viestit päälle tai pois,Act./Déasct. Messages,Üzenetek kapcsololása,Toggle messaggi,メッセージ表示の切替,메시지 토글,Berichten aan/uit,Włącz / Wyłącz Wiadomości,Ativar Mensagens,,Comutator pentru Mesaje,Переключение сообщений,Таглави поруке -Quit Game,CNTRLMNU_MENU_QUIT,,,,Odejít ze hry,Spiel beenden,Έξοδος Παιγνιδιού,Ĉesigi Ludon,Salir del Juego,,Lopeta peli,Quitter le Jeu,Kilépés a játékból.,Esci dal gioco,ゲームを終了,게임 종료,Stop het spel,Wyjdź z Gry,Sair do Jogo,,Ieșire din Joc,Выход,Изађи из игре -Adjust Gamma,CNTRLMNU_ADJUST_GAMMA,,,,Nastavit gamu,Gamma-Anpassung,Προσαρμογή Γάμματος,Agordi Gamaon,Ajustar Gamma,,Säädä gammaa,Ajuster Gamma,Gamma állítása,Aggiustamento Gamma,ガンマ値を調整,감마 조정,Gamma aanpassen,Dostosuj Gammę,Ajustar Gama,,Ajustare Gamma,Настройка гаммы,Подесите осветљење -Chat,CNTRLMNU_CHAT,,,,Chat,Chat,Ομιλία,Babilo,Chat,,Keskustelu,Chat,Chat,Chat,チャット,채팅,Chat,Czat,Chat,Conversar,Conversație,Чат,Ћаскање -Say,CNTRLMNU_SAY,,,,Říct,Reden,Πές,Diro,Hablar,,Sano,Parler,Üzenet ,Parla,発言,채팅하기,Zeg,Powiedz,Fala,Falar,Vorbește,Сообщение,Пиши -Team say,CNTRLMNU_TEAMSAY,,,,Říct týmu,Readen im Team,Πές στην ομάδα,Teama diro,Hablar al equipo,,Sano omille,Parler (équipe),Üzenet csapattársaknak,Parla nella squadra,チーム内発言,팀 채팅하기,Zeggen in team,Powiedz do Drużyny,Fala (equipe),Falar à equipa,Vorbește cu Echipa Proprie,Сообщение команде,Пиши тиму -Weapons,CNTRLMNU_WEAPONS,,,,Zbraně,Waffen,Όπλα,Armiloj,Armas,,Aseet,Armes,Fegyverek,Armi,武器,무기,Wapens,Bronie,Armas,,Arme,Оружие,Оружје -Next weapon,CNTRLMNU_NEXTWEAPON,,,,Další zbraň,Nächste Waffe,Επόμενο Όπλο,Proksima armilo,Arma siguiente,,Seuraava ase,Arme Suivante,Következő fegyver,Arma successiva,次の武器,다음 무기,Volgende wapen,Następna broń,Próxima arma,,Arma Următoare,Следующее оружие,Следеће оружје -Previous weapon,CNTRLMNU_PREVIOUSWEAPON,,,,Předchozí zbraň,Vorherige Waffe,Προηγούμενο Όπλο,Antaŭa armilo,Arma anterior,,Edellinen ase,Arme Précédente,Előző fegyver,Arma precedente,前の武器,이전 무기,Vorige wapen,Poprzednia broń,Arma anterior,,Arma Anterioară,Предыдущее оружие,Претходно оружје -Weapon Slot 1,CNTRLMNU_SLOT1,,,,Slot zbraně 1,Waffen-Slot 1,Θυρίδα Όπλου 1,Armingo 1,Ranura de Arma 1,,Aselokero 1,Emplacement D'Arme 1,1. Fegyver,Slot arma 1,武器スロット 1,무기 슬롯 1,Wapenslot 1,Broń 1,Arma 1,,Slot Arma 1,Оружие 1,Оружје 1 -Weapon Slot 2,CNTRLMNU_SLOT2,,,,Slot zbraně 2,Waffen-Slot 2,Θυρίδα Όπλου 2,Armingo 2,Ranura de Arma 2,,Aselokero 2,Emplacement D'Arme 2,2. Fegyver,Slot arma 2,武器スロット 2,무기 슬롯 2,Wapenslot 2,Broń 2,Arma 2,,Slot Arma 2,Оружие 2,Оружје 2 -Weapon Slot 3,CNTRLMNU_SLOT3,,,,Slot zbraně 3,Waffen-Slot 3,Θυρίδα Όπλου 3,Armingo 3,Ranura de Arma 3,,Aselokero 3,Emplacement D'Arme 3,3. Fegyver,Slot arma 3,武器スロット 3,무기 슬롯 3,Wapenslot 3,Broń 3,Arma 3,,Slot Arma 3,Оружие 3,Оружје 3 -Weapon Slot 4,CNTRLMNU_SLOT4,,,,Slot zbraně 4,Waffen-Slot 4,Θυρίδα Όπλου 4,Armingo 4,Ranura de Arma 4,,Aselokero 4,Emplacement D'Arme 4,4. Fegyver,Slot arma 4,武器スロット 4,무기 슬롯 4,Wapenslot 4,Broń 4,Arma 4,,Slot Arma 4,Оружие 4,Оружје 4 -Weapon Slot 5,CNTRLMNU_SLOT5,,,,Slot zbraně 5,Waffen-Slot 5,Θυρίδα Όπλου 5,Armingo 5,Ranura de Arma 5,,Aselokero 5,Emplacement D'Arme 5,5. Fegyver,Slot arma 5,武器スロット 5,무기 슬롯 5,Wapenslot 5,Broń 5,Arma 5,,Slot Arma 5,Оружие 5,Оружје 5 -Weapon Slot 6,CNTRLMNU_SLOT6,,,,Slot zbraně 6,Waffen-Slot 6,Θυρίδα Όπλου 6,Armingo 6,Ranura de Arma 6,,Aselokero 6,Emplacement D'Arme 6,6. Fegyver,Slot arma 6,武器スロット 6,무기 슬롯 6,Wapenslot 6,Broń 6,Arma 6,,Slot Arma 6,Оружие 6,Оружје 6 -Weapon Slot 7,CNTRLMNU_SLOT7,,,,Slot zbraně 7,Waffen-Slot 7,Θυρίδα Όπλου 7,Armingo 7,Ranura de Arma 7,,Aselokero 7,Emplacement D'Arme 7,7. Fegyver,Slot arma 7,武器スロット 7,무기 슬롯 7,Wapenslot 7,Broń 7,Arma 7,,Slot Arma 7,Оружие 7,Оружје 7 -Weapon Slot 8,CNTRLMNU_SLOT8,,,,Slot zbraně 8,Waffen-Slot 8,Θυρίδα Όπλου 8,Armingo 8,Ranura de Arma 8,,Aselokero 8,Emplacement D'Arme 8,8. Fegyver,Slot arma 8,武器スロット 8,무기 슬롯 8,Wapenslot 8,Broń 8,Arma 8,,Slot Arma 8,Оружие 8,Оружје 8 -Weapon Slot 9,CNTRLMNU_SLOT9,,,,Slot zbraně 9,Waffen-Slot 9,Θυρίδα Όπλου 9,Armingo 9,Ranura de Arma 9,,Aselokero 9,Emplacement D'Arme 9,9. Fegyver,Slot arma 9,武器スロット 9,무기 슬롯 9,Wapenslot 9,Broń 9,Arma 9,,Slot Arma 9,Оружие 9,Оружје 9 -Weapon Slot 0,CNTRLMNU_SLOT0,,,,Slot zbraně 0,Waffen-Slot 10,Θυρίδα Όπλου 0,Armingo 0,Ranura de Arma 0,,Aselokero 0,Emplacement D'Arme 0,0. Fegyver,Slot arma 0,武器スロット 0,무기 슬롯 0,Wapenslot 0,Broń 10,Arma 0,,Slot Arma 0,Оружие 0,Оружје 0 -Inventory,CNTRLMNU_INVENTORY,,,,Inventář,Inventar,Εμπόριο,Inventaro,Inventario,,Varusteet,Inventaire,Eszköztár beállítások testreszabása,Inventario,所持品,인벤토리,Inventaris,Ekwipunek,Inventário,,Inventar,Инвентарь,Инвентар -Activate item,CNTRLMNU_USEITEM,,,,Aktivovat předmět,Gegenstand aktivieren,Ενεργοποίηση Aντικείμενου,Aktivigi aĵon,Activar objeto,,Aktivoi varuste,Activer objet,Eszköz használata,Attiva oggetto,アイテムを使用,선택한 아이템 사용,Item activeren,Użyj przedmiot,Ativar item,,Activare Obiect,Использовать предмет,Активирај предмет -Activate all items,CNTRLMNU_USEALLITEMS,,,,Aktivovat všechny předměty,Alle Gegenstände aktivieren,Ενεργοποίηση όλων Aντικείμενων,Aktivigi ĉiuj aĵojn,Activar todos los objetos,,Aktivoi kaikki varusteet,Activer tous les objets,Minden eszköz használata,Attiva tutti gli oggetti,全てのアイテムを使用,모든 아이템 사용,Activeer alle items,Użyj wszystkie przedmioty,Ativar todos os itens,,Activarea Tuturor Obiectelor,Использовать все предметы,Активирај све предмете -Next item,CNTRLMNU_NEXTITEM,,,,Další předmět,Nächster Gegenstand,Επόμενο Aντικείμενο,Proksima aĵo,Objeto siguiente,,Seuraava varuste,Objet suivant,Következő eszköz,Oggetto successivo,次のアイテム,다음 아이템,Volgende item,Następny przedmiot,Próximo item,,Obiectul Următor,Следующий предмет,Следећи предмет -Previous item,CNTRLMNU_PREVIOUSITEM,,,,Předchozí předmět,Vorheriger Gegenstand,Προηγούμενο Aντικείμενο,Antaŭa aĵo,Objeto anterior,,Edellinen varuste,Objet précédent,Előző eszköz,Oggetto precedente,前のアイテム,이전 아이템,Vorige item,Poprzedni przedmiot,Item anterior,,Obiectul Anterior,Предыдущий предмет,Претходни предмет -Drop item,CNTRLMNU_DROPITEM,,,,Odhodit předmět,Gegenstand fallen lassen,Πέτα Aντικείμενο,Faligi aĵon,Arrojar objeto,,Pudota varuste,Lâcher objet,Eszköz eldobása,Fai cadere l'oggetto,"アイテムを捨てる -",아이템 버리기,Laat vallen,Upuść przedmiot,Largar item,,Aruncare Obiect,Выбросить предмет,Баци предмет -Query item,CNTRLMNU_QUERYITEM,,,,Informace o předmětu,Informationen über Gegenstand,,Demandi pri aĵo,Consultar objeto,,Hae varustetta,Vérifier objet,,Indaga sull'oggetto,アイテム名を表示,아이템 정보 표시,Vraag item,Zapytaj o przedmiot,Consultar item,,Cercetare Obiect,Показать предмет,Прикажи предмет -Drop weapon,CNTRLMNU_DROPWEAPON,,,,Odhodit zbraň,Waffe fallen lassen,Πέτα Όπλο,Faligi armilon,Arrojar arma,,Pudota ase,Lâcher arme,Fegyver eldobása,Fai cadere l'arma,武器を捨てる,무기 버리기,Laat het wapen vallen,Upuść broń,Largar arma,,Aruncare Armă,Выбросить оружие,Баци оружје -Other,CNTRLMNU_OTHER,,,,Ostatní,Andere,Άλλα,Alia,Otros,,Muu,Autres,Más,Altro,その他,그 외 조작,Andere,Inne,Outro,,Altele,Прочее,Остало -Toggle automap,CNTRLMNU_AUTOMAP,,,,Zap. / Vyp. automapu,Automap an/aus,Ενεργοποίηση χάρτη,Baskuligi aŭtomapo,Alternar automapa,,Kytke automaattikartta päälle/pois,Activer Carte,Térkép ki- bekapcsolása,Toggle automappa,オートマップの切替,오토맵 조정,Automap aan/uit,Włącz mapę,Ativar automapa,,Comutator Hartă Computerizată,Открыть автокарту,Прикажи аутомапу -Chasecam,CNTRLMNU_CHASECAM,,,,Kamera z třetí osoby,Verfolgerkamera,Κάμερα τρίτου προσώπου,Ĉaskamerao,Cámara de Seguimiento,,Seurantakamera,Caméra 3ième personne,Külsőnézetű kamera,Telecamera di inseguimento,背後視点,3인칭 카메라,,Kamera Śledzenia,Câmera de terceira-pessoa,Câmera em terceira-pessoa,Vedere la Persoana a 3-a (Chasecam),Вид от 3-го лица (Chasecam),Чејс-кем -Coop spy,CNTRLMNU_COOPSPY,,,,Co-op špión,Coop Spion,,KoopSpiono,Espía cooperativo,,Vakoile joukkuetovereita,Espionner Coéquiper,Coop leskelődés,Spia cooperativa,他者視点,멀티플레이 카메라,Coop spion,Śledź (kooperacja),Visualização coop,,Vedere prin Ochii Altui Jucător,Вид от другого игрока,Поглед од другог играча -Screenshot,CNTRLMNU_SCREENSHOT,,,,Pořídit snímek obrazovky,,,Ekranfoto,Captura de pantalla,,Kuvakaappaus,Capture d'écran,Képernyő lefényképezése,Cattura schermo,画面キャプチャ,스크린샷,,Zrzut ekranu,Captura de tela,,Poză Ecran,Скриншот,Усликај -Open console,CNTRLMNU_CONSOLE,,,,Otevřít konzoli,Konsole öffnen,Άνοιγμα κονσόλας,Malfermi konzolon,Abrir consola,,Avaa konsoli,Ouvrir Console,Konzol előhozása,Apri la console,コンソールを開く,콘솔 열기,Open console,Otwórz konsolę,Abrir console,Abrir consola,Deschidere Consolă,Открыть консоль,Отвори консолу -Strife Popup Screens,CNTRLMNU_POPUPS,,,,Vyskakovací okna Strife,Strife Popups,,Malpacaj Ekmontraĵaj Ekranoj,Pop-ups de Strife,,Strifen ponnahdusruudut,Popups de Strife,Strife Felugró Ablakok,Schermate popup di Strife,Strife ポップアップスクリーン,스트라이프 팝업 화면,Strife Popup Schermen,Okienka Strife'a,Popup do Strife,,Mesaje Strife,Strife,Информација у Strife-у -Mission objectives,CNTRLMNU_MISSION,,,,Úkoly mise,Missionsziele,Στόχοι Αποστολής,Misiobjektivoj,Objetivos de misión,,Tehtävätavoitteet,Objectifs de Mission,Küldetés feladata,Obiettivi della missione,ミッションオブジェクト,임무 목록,Missie doelstellingen,Cele misji,Objetivos da missão,,Obiectivele Misiunii,Текущее задание,Циљ мисије -Keys list,CNTRLMNU_KEYS,,,,Seznam klíčů,Schlüsselliste,Λίστα Κλειδιών,Ŝlosillisto,Lista de llaves,,Avainlista,Liste des Clés,Kulcslista,Lista delle chiavi,キー類リスト,열쇠 목록,Toetsenlijst,Lista kluczy,Lista de chaves,,Listă Chei,Список ключей,Списка кључева -Weapons/ammo/stats,CNTRLMNU_STATS,,,,Zbraně/munice/staty,Waffen/Munition/Statistik,Οπλα/Πυρομαχικά/Στατιστικές,Armiloj/municio/stataĵoj,Armas/Munición/Estadísticas,,Aseet/ammukset/tila,"Statistiques, armes et munitions",Fegyver/lőszer/statisztika,Armi/ammunizioni/statistiche,武器 / 弾薬 / 状態,무기/탄약/통계 목록,Wapens/ammo/statica,Bronie/amunicja/statystyki,Armas/munição/estatísticas,,Arme/muniție/statistici,"Оружие, патроны и показатели",Оружје/муниција/статистика -Mouse Options,MOUSEMNU_TITLE,,,,Nastavení myši,Mausoptionen,Ρυθμίσεις Ποντικιού,Musilagordoj,Opciones del Ratón,,Hiiriasetukset,Options Souris,Egér beállítások,Opzioni Mouse,マウス オプション,마우스 설정,Muis opties,Opcje Myszki,Opções de mouse,Opções do rato,Opțiuni mouse,Настройки мыши,Миш -Enable mouse,MOUSEMNU_ENABLEMOUSE,,,,Povolit myš,Maus aktiv,Ενεργοποίηση Ποντικιού,Aktivigi muson,Habilitar ratón,,Ota hiiri käyttöön,Activer Souris,Egér engedélyezése,Abilita il mouse,マウスの使用,마우스 사용,Muis inschakelen,Włącz myszkę,Habilitar mouse,Permitir uso do rato,Activare mouse,Использовать мышь,Укључи миш -Enable mouse in menus,MOUSEMNU_MOUSEINMENU,,,,Povolit myš v nabídkách,Maus aktiv in Menüs,Ενεργοποίηση Ποντικιού στα Μενού ,Aktivigi muson en menuoj,Usa ratón en los menús,,Ota hiiri käyttöön valikoissa,Activer Souris dans les Menus,Egér engedélyezése a menüben.,Abilita il mouse nei menu,メニューでのマウスの使用,메뉴에서 마우스 사용,Muis in menu's inschakelen,Włącz myszkę w menu,Habilitar mouse nos menus,Permitir rato nos menus,Permite navigarea cu mouse în meniuri,Использовать мышь в меню,Укључи миш у менијима -Show back button,MOUSEMNU_SHOWBACKBUTTON,,,,Zobrazit tlačítko zpět,Zeige Zurück-Knopf,,Montri antaŭklavon,Botón de retroceso,,Näytä taaksenäppäin,Afficher le bouton retour,Vissza gomb mutatása,Mostra il bottone per tornare indietro,戻るボタンを表示,뒤로가기 버튼 보이기,Toon terug knop,Pokaż przycisk powrotu,Mostrar botão de voltar,,"Afișează butonul ""Înapoi""",Расположение кнопки «назад»,Прикажи тастер за назад -Cursor,MOUSEMNU_CURSOR,,,,Kurzor,,,Musmontrilo,,,Osoitin,Curseur,Egérmutató,Cursore,カーソル,커서,,Kursor,,,Cursor,Курсор,Курсор -Overall sensitivity,MOUSEMNU_SENSITIVITY,,,,Celková citlivost,Allgemeine Empfindlichkeit,,Tutsentemo,Sensibilidad promedio,,Yleinen herkkyys,Sensibilité générale,Teljes érzékenység,Sensibilità complessiva,全体的な感度,전체 민감도,Algemene gevoeligheid,Ogólna wrażliwość,Sensibilidade geral,,Sensibilitate mouse per ansamblu,Общая чувствительность,Осетљивост -Prescale mouse movement,MOUSEMNU_NOPRESCALE,,,,Akcelerace myši,Mausbewegung skalieren,,Antaŭpesilo musmovo,Pre-escalar movimiento,,Esiskaalaa hiiren liike,Prescaling mouvement souris,,Prescala il movimento del mouse,マウス操作の精密化,속도 높인 움직임,Muisbewegingen vooraf inschalen,Przeskaluj ruch myszki,Movimento pré-escalar do mouse,Movimento pré-escalar do rato,Sensibilitate mărită,Увеличенная чувствительность,Убрзање миша -Smooth mouse movement,MOUSEMNU_SMOOTHMOUSE,,,,Vyhladit pohyb myši,Mausbewegung glätten,,Glata musmovo,Mov. fluido del ratón,,Sulava hiiren liike,Lissage Souris,Egyenletes egérmozdulatok,Movimento del mouse liscio,マウス操作を滑らかにする,부드러운 움직임,Vlotte muisbeweging,Gładki ruch myszki,Movimento fluído do mouse,Movimento fluído do rato,Mișcare fină mouse,Плавное перемещение,Глатки окрет -Turning speed,MOUSEMNU_TURNSPEED,,,,Rychlost otáčení,Umdrehgeschwindigkeit,,Turnorapido,Velocidad de giro,,Kääntymisnopeus,Vitesse pour tourner,Fordulási sebesség,Velocità di rotazione,旋回速度,회전 속도,Draaisnelheid,Szybkość obracania się,Velocidade de giro,,Viteză rotire,Скорость поворота,Брзина окрета -Mouselook speed,MOUSEMNU_MOUSELOOKSPEED,,,,Rychlost pohledu nahoru/dolů,Mausblick-Geschwindigkeit,,Musrigarda rapido.,Veloc. de vista con ratón,,Katselunopeus,Vitesse Vue Souris,Egérrel való nézés sebessége,Velocità di rotazione della vista,上下視点速度,마우스룩 속도,Mouselook snelheid,Szybkość rozglądania się myszką,Velocidade de vista com mouse,Velocidade de vista com rato,Viteză Privire în Jur cu mouse,Скорость обзора,Брзина гледања мишем -Forward/Backward speed,MOUSEMNU_FORWBACKSPEED,,,,Rychlost pohybu vpřed/vzad,Vor/Rückwärtsgeschwindigkeit,,Antaŭa/Malantaŭa rapido,Veloc. de avance/retroceso,,Eteen-/taaksepäin liikkeen nopeus,Vitesse Avancer/reculer,Előre/Hátra sebesség,Velocità avanti/indietro,"前進/後退速度 -",전진/후진 속도,Voorwaartse/achterwaartse snelheid,Szybkość chodzenia do przodu/do tyłu,Velocidade de deslocamento para frente/trás,,Viteză deplasare înainte/înapoi,Скорость передвижения,Брзина окрета напред/уназад -Strafing speed,MOUSEMNU_STRAFESPEED,,,,Rychlost pohybu do stran,Seitwärtsgeschwindigkeit,,Flankmova rapido,Veloc. de mov. lateral,,Sivuttaisastunnan nopeus,Vitesse Gauche/Droite,,Velocità movimento laterale,横移動速度,좌진/우진 속도,Zijdelings snelheid,Szybkość uników,Velocidade de deslocamento lateral,,Viteză deplasare în diagonală,Скорость движения боком,Брзина стрејфа -Always Mouselook,MOUSEMNU_ALWAYSMOUSELOOK,,,,Vždy se rozhlížet myší,Mausblick immer an,,Ĉiam Musrigardo,Siempre mirar con ratón,,Jatkuva hiirikatselu,Toujours vue Souris,Mindig nézelődés az egérrel,Vista col mouse,常に上下視点をオン,마우스룩 사용,Altijd Mouselook,Zawsze zezwalaj na rozglądanie się myszką,Vista com mouse sempre ligado,Vista com rato sempre ligada,Privire în Jur cu Mouse Permanentă,Обзор мышью,Гледање мишем -Invert Mouse,MOUSEMNU_INVERTMOUSE,,,,Inverzní myš,Maus invertieren,,Inversa Muso,Invertir ratón,,Käännä hiiri,Inverser Souris,Egérirányok megfordítása,Mouse invertito,視点操作反転,마우스 방향 전환,Muis omkeren,Odwróć Myszkę,Inverter mouse,Inverter rato,Inversare axe mouse,Инвертирование мыши,Инвертуј миш -Lookspring,MOUSEMNU_LOOKSPRING,,,,Automatické vystředění pohledu,Automatisch zentrieren,,Rigardsalto,Mirar con ratón,,Katseenpalautin,Recentrer après Vue Souris,,,視点水平化,마우스룩 시점 초기화,Lente,Automatyczne Wyśrodkowanie,Centralizar automáticamente,Centrar automáticamente,Mișcare a jucătorului prin mouse,Передвижение мышью,Покрет мишем -Lookstrafe,MOUSEMNU_LOOKSTRAFE,,,,Použít myš k pohybu do stran,Seitwärts bewegen mit der Maus,,Rigardturnmovo,Mirar con movimiento,,Sivuttaisastuntapalautin,Mouvement Latéral par Souris,,,視点横移動化,마우스룩 좌우 이동,Lookstrafe,Unikanie przy użyciu myszki,Deslocamento lateral com o mouse,Deslocamento lateral com o rato,Mișcare în diagonală cu mouse,Движение боком мышью,Стрејф мишем -Configure Controller,JOYMNU_TITLE,,,,Konfigurovat ovladač,Controller konfigurieren,,Agordi Ludregilon,Configurar Mando,,Peliohjainasetukset,Configurer Mannette,Kontroller testreszabása,Configura il controller,コントローラー構成:,컨트롤러 구성,Controller configureren,Konfiguruj Kontroler,Configurar Controle,Configurar Comando,Configurare Controller,Настроить контроллер,Конфигурација контролера -Controller Options,JOYMNU_OPTIONS,,,,Nastavení ovladače,Controlleroptionen,,Ludregilagordoj,Opciones del mando,,Peliohjainasetukset,Options Mannette,Kontroller beállításai,Opzioni del controller,コントローラー設定,컨트롤러 설정,Controller opties,Opcje Kontrolera,Opções de Controle,Opções do Comando,Setări Controller,Настройки контроллера,Подешавања контролера -Block controller input in menu,JOYMNU_NOMENU,,,,Zakázat ovladač v nabídkách,Blockiere Controllereingabe im Menü,,Blokigi ludregilon enigon en menuo,Bloq. entrada de mando en menú,,Estä ohjainsyötteet valikoissa,Bloquer manette dans les menus,Kontroller ne működjön a menüben,Blocca l'input del controller nei menu,メニューではコントローラーを無視,메뉴에서 컨트롤러 끄기,Blokkeer de controller in het menu,Blokuj wejście kontrolera w menu,Bloquear controle no menu,Bloquear comando no menu,Blocare comenzi controller în meniu,Отключить контроллер в меню,Блокирај улаз контролера у менију -Player Setup,MNU_PLAYERSETUP,,,,Nastavení hráče,Spielereinstellungen,,Ludanto Agordaĵo,Config. del jugador,,Pelaaja-asetukset,Options Joueur,Játékos testreszabása,Settaggio giocatore,プレイヤーの特徴,플레이어 설정,Speler instellen,Ustawienia Gracza,Definições de Jogador,,Configurare Jucător,Настройки игрока,Подешавања играча -Name,PLYRMNU_NAME,,,,Jméno,,,Nomo,Nombre,,Nimi,Nom,Név,Nome,名前,이름,Naam,Imię,Nome,,Nume,Имя,Надимак -Team,PLYRMNU_TEAM,,,,Tým,,,Teamo,Equipo,,Joukkue,Equipe,Csapat,Squadra,チーム,팀,Team,Drużyna,Equipe,Equipa,Echipă,Команда,Тим -Color,PLYRMNU_PLAYERCOLOR,,,Colour,Barva,Farbe,,Koloro,,,Väri,Couleur,Szín,Colore,色,색상,Kleur,Kolor,Cor,,Culoare,Цвет,Боја -Red,PLYRMNU_RED,,,,Červená,Rot,,Ruĝo,Rojo,,Punainen,Rouge,Piros,Rosso,赤の量,빨강,Rood,Czerwony,Vermelho,,Roșu,Красный,Црвева -Green,PLYRMNU_GREEN,,,,Zelená,Grün,,Verdo,Verde,,Vihreä,Vert,Zöld,Verde,緑の量,초록,Groen,Zielony,Verde,,Verde,Зелёный,Зелена -Blue,PLYRMNU_BLUE,,,,Modrá,Blau,,Bluo,Azul,,Sininen,Bleu,Kék,Blu,青の量,파랑,Blauw,Niebieski,Azul,,Albastru,Синий,Плава -Class,PLYRMNU_PLAYERCLASS,,,,Třída,Klasse,,Klaso,Clase,,Luokka,Classe,Osztály,Classe,役職,클래스,Klasse,Klasa,Classe,,Clasă,Класс,Класа -Skin,PLYRMNU_PLAYERSKIN,,,,Skin,Skin,,Haŭto,Piel,,Ulkonäkö,,Kinézet,Skin,外装,스킨,Skin,Wygląd,Skin,,Textură,Скин,Скин -Gender,PLYRMNU_PLAYERGENDER,,,,Pohlaví,Geschlecht,,Genro,Género,,Sukupuoli,Genre,Nem,Sesso,性別,성별,Geslacht,Płeć,Gênero,,Sex,Пол,Пол -Autoaim,PLYRMNU_AUTOAIM,,,,Automatické míření,Automatisch zielen,,Aŭtomate-celi,Autoapuntar,,Automaattitähtäys,Auto-visée,Auto célzás,Mira automatica,自動照準,자동 조준,Autoaim,Automatyczne Celowanie,Mira Automática,,Asistență țintire,Автоприцеливание,Аутоматско циљање -Switch on pickup,PLYRMNU_SWITCHONPICKUP,,,,Přepnout zbraň při sebrání,Waffenwechsel bei Aufnahme,,Ŝanĝi kiam peni,Cambiar arma al recoger,,Vaihda uuteen aseeseen,Dernière arme,Felvételkor váltás,Cambio d'arma quando si riceve,武器取得時に持ち替え,무기 획득 시 바꿈,Ophaling inschakelen,Przełącz po podniesieniu,Mudar de arma ao pegar,,Schimbare armă la ridicare,Смена оружия при подборе,Пребаци на покупљено оружје -Always Run,PLYRMNU_ALWAYSRUN,,,,Vždy běžet,Immer Rennen,,Ĉiam Kuri,Siempre correr,,Jatkuva juoksu,Toujours courir,Mindig fusson,Corri sempre,常に駆け足,달리기 토글,Altijd lopen,Zawsze Biegaj,Sempre Correr,Correr Sempre,Fugă Permanentă,Постоянный бег,Увек трчи -Press \cjSPACE,PLYRMNU_PRESSSPACE,,,,Zmáčkni \cjMEZERNÍK,\cjLeertaste,,Premu \cjSPACETON,Presiona \cjEspacio,,Paina \cjVÄLI \cfnähdäk-,\cjEspace,,Premi \cjSPAZIO,\cjスペースキー,회전: \cjSPACE바,Druk op \cjSPACE,\cjSPACJA,Aperte \cjESPAÇO,,Apasă \cjSPACE,Нажмите \cjПРОБЕЛ,Притисните \cjSPACE -to see front,PLYRMNU_SEEFRONT,,,,pro pohled zepředu,für Frontansicht,,por vidi fronton,Para ver de Frente,,sesi etupuolen,Pour L'Avant,Előre nézni,per vedere avanti,で前面を表示,캐릭터 앞모습,om de voorkant te zien,by widzieć przód,para ver pela frente,,pentru a vedea fața,Посмотреть спереди,да видите спреда -to see back,PLYRMNU_SEEBACK,,,,pro pohled zezadu,für Rückansicht,,por vidi dorson,Para ver por Detrás,,sesi takapuolen,Pour l'Arrière,Hátra Nézni,per vedere dietro,で背面を表示,캐릭터 뒷모습,om terug te kijken,by widzieć tył,para ver por trás,,pentru a vedea spatele,Посмотреть сзади,да видите позади -Display Options,DSPLYMNU_TITLE,,,,Nastavení grafiky,Anzeigeoptionen,,Ekranagordoj,Opciones de visualización,,Näyttöasetukset,Options Affichage,Megjelenítés beállítások,Opzioni display,ディスプレイ オプション,디스플레이 설정,Weergaveopties,Opcje Wyświetlania,Opções de Vídeo,,Setări de Afișare,Настройки экрана,Подешавања приказа -Scoreboard Options,DSPLYMNU_SCOREBOARD,,,,Nastavení tabulky skóre,Punktetafeloptionen,,Poentotabulo-agordoj,Opciones de marcador,,Pistetauluasetukset,Options Tableau des Scores,Eredményjelző beállítások,Opzioni tabella punteggio,スコアボード オプション,점수창 설정,Scorebord opties,Opcje Tablicy Wyników,Opções de Tela de Pontuação,,Opțiuni Tabelă de Marcaj,Таблица очков,Табеларне подешавања -Screen size,DSPLYMNU_SCREENSIZE,,,,Velikost obrazovky,Bildschirmgröße,,Ekrano-grandeco,Tamaño de pantalla,,Näytön koko,Taille de l'écran,Képernyő mérete,Dimensione della schermata,画面サイズ,화면 크기,Schermgrootte,Rozmiar Ekranu,Tamanho de tela,Tamanho do ecrã,Dimensiune Afișaj,Размер экрана,Величина екрана -Brightness,DSPLYMNU_BRIGHTNESS,,,,Jas,Helligkeit,,Brileco,Brillo,,Kirkkaus,Luminosité,Fényerő,Luminosità,明るさ,밝기,Helderheid,Jasność,Brilho,,Luminozitate,Яркость,Осветљење -Vertical Sync,DSPLYMNU_VSYNC,,,,Vertikální synchronizace,Vertikale Synchronisation,,Vertikala-sinkronigo,Sincr. vertical,,Pystytahdistys,Synchronisation Verticale,Függőleges szinkronizálás,Sync verticale,垂直同期,수직 동기화,Verticale Sync,Synchronizacja Pionowa,Sincronização Vertical,,Sincronizare Verticală,Вертикальная синхронизация,Вертикална синхорнизација -Rendering Interpolation,DSPLYMNU_CAPFPS,,,,Interpolace renderingu,Renderinterpolation,,Bildigo-interpolado,Interpolación de rend.,,Hahmonnuksen interpolointi,Interpolation du rendu,,Interpolazione grafica,レンダリング補間,프레임 제한,Het teruggeven van Interpolatie,Interpolacja Renderowania,Interpolação de renderização,,Interpolare Imagine,Сглаживание рендеринга,Интерполација рендеринга -Transparency render mode,DSPLYMNU_BLENDMETHOD,,,,Režim vykreslování průhlednosti,Transparenzmodus,,Diafaneco-bildigo reĝimo,Modo rend. transparencia,,Läpinäkyvyyden hahmonnustila,Mode de Rendu transparence,Átlászóság render mód,Modalità della resa grafica della trasparenza,レンダリング透過モード,투명도 표시 모드,Transparantie render mode,Tryb renderowania przezroczystości,Modo de renderiz. de transparência,,Mod Transparență,Режим рендеринга прозрачности,Режим рендеринга транспарентности -Screen wipe style,DSPLYMNU_WIPETYPE,,,,Styl přechodů,Bildschirmwechseleffekt,,Ekrano-viŝo-maniero,Transición de pantalla,,Ruudun pyyhkiytymistyyli,Style de Fondu d'écran,Képernyőtörlődés Stílus,Stile della pulizia dello schermo,スクリーンワイプモード,화면 전환 방식,Scherm veeg stijl,Styl przejścia ekranu,Tipo de transição de tela,Tipo de transição de ecrã,Stil ștergere imagine,Эффект плавной смены экранов,Ефект брисања екрана -Show ENDOOM screen,DSPLYMNU_SHOWENDOOM,,,,Zobrazit ENDOOM obrazovku,Zeige ENDOOM,,Montri ENDOOM-ekrano,Mostrar pantalla ENDOOM,,Näytä ENDOOM-ruutu,Montrer la fenêtre ENDOOM,Mutasd az ENDOOM ablakot,Mostra lo screen ENDOOM,ENDOOM画面を表示,종료화면 표시,Toon ENDOOM scherm,Pokaż ekran ENDOOM,Mostrar tela ENDOOM,,Afișare fereastră ENDOOM,Показать экран ENDOOM,Прикажи ENDOOM екран -Blood Flash Intensity,DSPLYMNU_BLOODFADE,,,,Intenzita bliknutí při zranění,Intensität für Bluteffekt,,Sango-ekbrilo-egeco,Intensidad Destello de Sangre,,Verivälähdyksen voimakkuus,Intensité du flash dommages,Vér Villódzásának Mértéke,Intensità Bagliore Sangue,血粉の濃度,피격 표시 강도,De Intensiteit van de bloedflitser,Intensywność Efektów Krwi,Intensidade de Flash de Sangue,,Intensitate strălucire sânge,Интенсивность вспышки при ранении,Интензивност треперења током повређивања -Pickup Flash Intensity,DSPLYMNU_PICKUPFADE,,,,Intenzita bliknutí při sebrání předmětu,Intensität für Aufnehmen-Effekt,,Preni-ekbrilo-egeco,Intensidad Destello de Recogida,,Poimintavälähdyksen voimakkuus,Intensité du flash objets,,Intensità Bagliore Raccolta,取得の視界色濃度,습득 표시 강도,De Intensiteit van de afhaalflitser,Intesnywność Efektów Podnoszenia Przedmiotów,Intensidade de Flash ao Pegar Itens,,Intensitate strălucire la ridicarea obiectelor,Интенсивность вспышки при подборе,Интензивност треперења током купљења -Underwater Blend Intensity,DSPLYMNU_WATERFADE,,,,Intenzita podvodního obarvení,Intensität für Unterwasser-Effekt,,Subakva miksi-egeco,Intensidad Color Sumergido,Intensidad Color Submarino,Vedenalaissumennuksen voimakkuus,Intensité du fondu sous l'eau,,Intensità Blend sott'acqua,水中反響音の濃度,수중 효과 강도,Mengsel Intensiteit onder water,Intensywność Efektów Pod Wodą,Intensidade de Efeito Debaixo d'Água,Intensidade de Efeito Debaixo de Água,Intensitate amestec culori subacvatice,Интенсивность эффекта под водой,Интензивност подводног треперења -Sky render mode,DSPLYMNU_SKYMODE,,,,Režim vykreslování oblohy,Rendermodus für Himmel,,Ĉielo-bildigo-reĝimo,Modo de Rend. de Cielo,,Taivaan hahmonnustila,Mode du rendu du Ciel,,Modalità resa grafica del cielo,空の表示方法,하늘 표시 모드,Render mode voor de hemel,Tryb renderowania nieba,Modo de renderização de céu,,Mod de vizualizare al cerului,Режим отрисовки неба,Режим рендеринга неба -Linear skies,DSPLYMNU_LINEARSKY,,,,Lineární obloha,Lineare Himmel,,Liniaj ĉieloj,Cielo lineal,,Lineaariset taivaat,Ciel linéaire,,Cieli lineari,空の歪み,선형 하늘,Lineaire hemelen,Liniowe niebo,Céus lineares,,Cer rectiliniu,Линейное небо,Линеарна неба -Fullbright overrides sector color,DSPLYMNU_GZDFULLBRIGHT,,,,Plný jas ignoruje barvu sektoru,Ignoriere Sektorfarbe bei voller Helligkeit,,Plenbrileco tranpasas sektorkoloron,Brillo máximo anula color del sector,,Täyskirkkaat ohittavat sektorin värin,Fullbright ignore couleur secteur,Telljes fényerő felülírja a szektor szinét,Luce piena sovrappone il colore del settore,明るさ最大時にsector color塗り替え,섹터 색상 최대밝기 우선화,De volledig heldere overschrijft de sectorkleur,Ignoruj kolor sektora przy pełnej jasności,Brilho máximo anula cor de setor,,Luminozitatea maximă suprascrie culoarea sectorului,Полная яркость замещает цвет сектора,Пуно осветљење премошћује боју сектора -Models,DSPLYMNU_MODELS,,,,Modely,Modelle,,Modeloj,Modelos,,Mallit,Modèles,3D modellek,Modelli,モデル,모델,Modellen,Modele,Modelos,,Modele,Модели,Модели -Scale fuzz effect,DSPLYMNU_SCALEFUZZ,,,,Škálovat velikost fuzz efektu,Skaliere Fuzz-Effekt,,Skali barblano-efekton,Escala de efecto fuzz,,Skaalaa sumennustehostetta,Scaling de l'effet de bruit,Fuzz efekt átméretezése,Scala l'effetto di fuzz,ファズエフェクトサイズ,반투명 효과 조정,Schaal fuzz effect,Skalowanie efektu szumu,Escala de efeito difuso,,Putere efect de strălucire,Масштабировать эффект шума,Повечавај шумни ефект -Use fuzz effect,DSPLYMNU_DRAWFUZZ,,,,Použít fuzz efekt,Benutze Fuzz-Effekt,,Uzi barblano-efekton,Usar efecto fuzz,,Käytä sumennustehostetta,Effet de bruit,Fuzz efekt használata,Usa l'effetto di fuzz,ファズエフェクトを使用,반투명 효과 사용,Gebruik fuzz effect,Użyj efektu szumu,Usar efeito difuso,,Mod efect de strălucire,Использовать эффект шума,Користи шумни ефект -Classic Transparency,DSPLYMNU_OLDTRANS,,,,Klasická průhlednost,Klasssische Transparenz,,Klasildiafenco,Transp. Clásicas,,Perinteinen läpinäkyvyys,Transparence classique,Klasszikus átlátszóság,Trasparenza classica,旧式の透明度,구형 투명도,Klassieke transparantie,Klasyczna Przezroczystość,Transparência Clássica,,Transparență Clasică,Классическая прозрачность,Класична транспарентност -Lost Soul translucency,DSPLYMNU_TRANSSOUL,,,,Průhlednost ztracených duší,Transparenz für Verlorene Seelen,,Perdita Animo diafana,Transp. del alma perdida,,Kadonneiden sielujen läpikuultavuus,Transparence des âmes perdues,Lost soul átlátszóság,Trasparenza anima errante,ロストソウルの透明度,로스트 소울 반투명도,Verloren Ziel doorschijnendheid,Przezroczystość Zagubionych Dusz,Translucência da Alma Perdida,Translucidez da Alma Penada,Transparență Suflete Pierdute,Прозрачность потерянных душ,Транспарентност изгубљених душа -Use fake contrast,DSPLYMNU_FAKECONTRAST,,,,Použít falešný kontrast,Benutze falschen Kontrast,,Uzi malvera kontrasto,Usar falso contraste,,Käytä tekosävykkyyttä,Faux Contraste,Hamis kontraszt használata,Usa il falso contrasto,フェイクコントラストを使用,가명암 효과 사용,Gebruik vals contrast,Użyj sztuczny kontrast,Usar contraste falso,,Utilizare contrast fals,Имитация контрастного освещения стен,Користи фејк-контраст -Rocket Trails,DSPLYMNU_ROCKETTRAILS,,,,Kouř raket,Raketenschweife,,Raketspuro,Rastro de cohetes,,Rakettivanat,Trainées des Roquettes,Rakéta füstcsíkok,Scia del razzo,ロケットの軌跡,로켓 추진 효과,Raketsporen,Wiązki Rakiet,Rastro de Foguete,Rasto dos Mísseis,Dâră Rachete,Дымовой след у ракет,Траг дима код ракета -Blood Type,DSPLYMNU_BLOODTYPE,,,,Druh krve,Blut-Typ,,Sango-tipo,Tipo de sangre,,Verityyli,Type de particules Sang,Vér fajtája,Tipo di sangue,血の種類,혈흔 효과,Bloedgroep,Typ Krwi,Tipo de Sangue,,Tip efecte sângeroase,Тип крови,Тип крви -Bullet Puff Type,DSPLYMNU_PUFFTYPE,,,,Druh kouře nábojů,Pistolenrauch-Typ,,Kuglo-pufo-tipo,Tipo de agujero de bala,,Luotien pöllähdystyyli,Type de particules Balles,Lövedék becsapódás fajtája,Tipo di sbuffo del proiettile,弾煙の種類,탄알 피격 효과,Het Type van kogelwolver,Typ Dymu,Tipo de Ricochete de Bala,,Tip efecte pentru gloanțe,Тип рикошетов,Тип рикошета -Number of particles,DSPLYMNU_MAXPARTICLES,,,,Množství částic,Anzahl Partikel,,Nombro da partikloj,Número de partículas,,Hiukkasten lukumäärä,Nombre de particules,Részecskék száma,Numero di particelle,パーティクルの最大数,최대 입자 수,Aantal deeltjes,Liczba cząsteczek,Número de partículas,,Număr particule,Количество частиц,Број честица -Number of decals,DSPLYMNU_MAXDECALS,,,,Množství decalů,Anzahl Trefferspuren,,Nombro da dekaloj,Número de calcomanías,,Siirtokuvien lukumäärä,Number de décalques,Matricák száma,Numero di decal,デカールの最大数,최대 데칼 수,Aantal stickers,Liczba kalk,Número de decalques,,Număr autocolante,Количество декалей,Број декала -Show player sprites,DSPLYMNU_PLAYERSPRITES,,,,Zobrazit hráčovy sprity,Zeige Spieler-Sprites,,Montri ludantspritojn,Mostrar sprites del jugador,,Näytä pelaajaspritet,Montrer les sprites joueur,Játékos sprite-ok mutatása,Mostra gli sprite del giocatore,プレイヤーの武器の表示,1인칭 무기 표시,Toon speler sprites,Pokaż sprite'y gracza,Mostrar sprites do jogador,,Afișare arme,Показывать спрайты игрока,Прикажи спрајтове играча -Death camera,DSPLYMNU_DEATHCAM,,,,Posmrtná kamera,Todeskamera,,Mortkamerao,Cámara de muerte,,Kuolonkamera,Caméra 3ème pers à la mort,Halál kamera,Telecamera all'atto della morte,死亡時の三人称視点,사망 화면 표시,Doodscamera,Kamera śmierci,Câmera de morte,Câmara da morte,Cameră de Deces,Вид от 3-го лица при смерти,Смртна камера -Teleporter zoom,DSPLYMNU_TELEZOOM,,,,Zoom při teleportaci,Teleporter Zoom,,Formovilzumo,Zoom en teletransp.,,Kaukosiirrynnän kameran zoomaus ,Zoom sur téléportation,Teleporter közelítés,Zoom telecamera,テレポーター使用時のズーム,순간이동 효과,Teleporter zoom,Przybliżenie teleportowania,Zoom de teletransporte,,Apropriere Cameră la Teleportare,Зум при телепортации,Зум током телепортације -Earthquake shake intensity,DSPLYMNU_QUAKEINTENSITY,,,,Síla třesu při zemětřesení,Erdbeben Intensität,,Tertremo-egeco,Intensidad del terremoto,,Maanjäristystehosteen voimakkuus,Intensité des séismes,Földrengés erőssége,Intensità vibrazione terremoto,地震エフェクトの激しさ,지진 효과 강도,Intensiteit van de aardbevingsschok,Siła trzęsienia ziemi,Intensidade do tremor de terremoto,,Intensitate zguduire la cutremur,Интенсивность землетрясений,Интенсивност земљотреса -Interpolate monster movement,DSPLYMNU_NOMONSTERINTERPOLATION,,,,Interpolovat pohyb příšer,Interpoliere Monsterbewegung,,Intermeti monstro-movo,Interpolar mov. de los monstruos,,Interpoloi hirviöiden liike,Interpolation des monstres,,Interpola il movimento dei mostri,モンスターの移動補間,개체 이동 보정,Interpoleer de monsterbeweging,Interpolacja ruchu potworów,Interpolar movimento de monstros,,Interpolare mișcare monștri (efect vizual),Сглаживание движения монстров,Интерполирај кретање чудовишта -Menu dim,DSPLYMNU_MENUDIM,,,,Síla barvy pozadí v menu,Menüabdunklung,,Malheligi menuon,Atenuación del menú,,Valikon himmennys,Assombrissement menu,,Offuscamento menu,メニュー背景,메뉴 배경색 강도,Donkere menuachtergrond,Mgła w menu,Atenuação do menu,,Întunecare meniu,Затемнение фона меню,Пригушивање менија -Dim color,DSPLYMNU_DIMCOLOR,,,Dim colour,Barva pozadí v menu,Abdunklungsfarbe,,Malhela koloro,Color de la atenuación,,Himmennysväri,Couleur de l'assombrissement,,Colore offuscamento,背景色,배경색 설정,Donkere kleur,Kolor mgły,Cor da atenuação,,Culoare întunecare,Цвет затемнения,Боја пригушивања -View bob amount while moving,DSPLYMNU_MOVEBOB,,,,Intenzita pohupování v pohybu,Waffenpendeln beim Bewegen,,Vidi kapo-ekmova kvanto dum movas,Cantidad de balanceo al moverse,,Aseen heilumisvoimakkuus liikkeessä,Chaloupage arme en movement,,Ammontare di bob di movimento,視点揺れする移動値,이동 시 화면 흔들림 강도,,Dygaj kiedy się ruszasz,Quantidade de balanço durante movimento,,Mișcare cameră în timpul deplasării,Покачивание камеры при движении,Тресење камере током кретања -View bob amount while not moving,DSPLYMNU_STILLBOB,,,,Intenzita pohupování v klidu,Waffenpendeln bei Nichtbewegen,,Vidi kapo-ekmova kvanto dum ne movas,Cantidad de balanceo al no moverse,,Aseen heilumisvoimakkuus levossa,Chaloupage arme statique,,Ammontare di bob di movimento da fermo,視点揺れしない移動値,정지 시 화면 움직임 강도,,Dygaj kiedy się nie ruszasz,Quantidade de balanço parado,,Mișcare cameră în timpul staționării,Покачивание камеры при бездействии,Тресење камере током неактивности -Weapon bob speed,DSPLYMNU_BOBSPEED,,,,Rychlost pohupování zbraně,Waffenpendelgeschwindigkeit,,Armilo-ekmova rapido,Velocidad de balanceo de Arma,,Aseen heilumisnopeus,Vitesse du chaloupage,,Velocità di bob dell'arma,武器揺れ速度,무기 흔들림 속도,Wapens zwaaien snelheid,Szybkość ruchu broni,Velocidade de balanço de arma,,Viteză mișcare arme,Скорость покачивания оружия,Брзина трсења оружја -Notebook Switchable GPU,DSPLYMNU_GPUSWITCH,,,,Přepínatelné GPU pro notebooky,GPU Umschaltung für Notebooks,,Kajero Ŝanĝa GPU,GPU Altern. de Portátil,,Kannettavan kytkettävä grafiikkapiiri,GPU alternatif sur PC Portable,Váltható GPU laptopon,Scheda GPU Switchable per notebook,ノートブックGPU切替,노트북 성능 조정,Notitieboekje schakelbare GPU,Zmiana GPU Notebooka,Placa de vídeo alternativa de notebook,,Schimbare GPU Notebook,Использование GPU ноутбука,Користи GPU ноутбук -HUD Options,HUDMNU_TITLE,,,,Nastavení HUD,HUD Optionen,,HUD Agordoj,Opciones del HUD,,Tilanäytön asetukset,Options ATH,HUD beállításai,Opzioni HUD,HUD オプション,HUD 설정,HUD opties,Opcje HUD,Opções de HUD,,Setări Interfață pe Timp de Joc,Настройки HUD,HUD подешавања -Alternative HUD,HUDMNU_ALTHUD,,,,Alternativní HUD,Alternatives HUD,,Alternativa HUD,HUD alternativo,,Vaihtoehtoinen tilanäyttö,ATH Alternatif,Alternatív HUD,HUD alternativo,オルタナティブHUD,대체 HUD,Alternatieve HUD,Alternatywny HUD,HUD Alternativo,,Interfață pe Timp de Joc Alternativă,Альтернативный HUD,Алтернативни HUD -Message Options,HUDMNU_MESSAGE,,,,Nastavení zpráv,Nachrichtenoptionen,,Mesaĝagordoj,Opciones de mensajes,,Viestiasetukset,Options des Messages,Üzenet beállítások,Opzioni messaggi,メッセージの設定,메시지 설정,Berichtopties,Opcje wiadomości,Opções de Mensagem,,Setări Mesaje,Настройки сообщений,Подешавања порука -User interface scale,HUDMNU_UISCALE,,,,Velikost rozhraní,Benutzerinterfaceskalierung,,Uzanto-interfacskalo,Escala de la interfaz de usuario,,Käyttöliittymän skaalaus,Echelle de l'interface,Felhasználó Panel mérete,Scala l'interfaccia utente,インターフェースの大きさ,인터페이스 크기 조정,Gebruikersinterface schaal,Skala interfejsu,Escala de interface de usuário,Escala de interface do utilizador,Dimensiune Interfață Utilizator,Масштабирование интерфейса,Размера интерфејса -Default Crosshair,HUDMNU_CROSSHAIR,,,,Výchozí zaměřovač,Standard-Fadenkreuz,,Defaŭlta Translinio,Retícula por defecto,,Oletustähtäin,Viseur par défaut,Alapcélkereszt,Mirino di default,デフォルトの照準,기본 조준점,Standaard dradenkruis,Domyślny celownik,Mira padrão,,Țintă implicită,Тип прицела,Уобичајени нишан -Force default crosshair,HUDMNU_FORCECROSSHAIR,,,,Vynutit výchozí zaměřovač,Erzwinge Standard-Fadenkreuz,,Devigi defaŭltan translinion,Forzar retícula por defecto,,Pakota oletustähtäin,Forcer Viseur par défaut,Alapcélkereszt erőltetése,Forza il mirino di default,デフォルトの照準を使う,기본 조준점 강제 설정,Forceer standaard dradenkruis,Wymuś domyślny celownik,Forçar mira padrão,,Forțare țintă implicită,Всегда стандартный прицел,Форсирај уобичајени нишан -Grow crosshair when picking up items,HUDMNU_GROWCROSSHAIR,,,,Zvětšit zaměřovač při sebrání předmětu,Größeres Fadenkreuz bei Gegenstandsaufnahme,,Grandigi translinion kiam prenas aĵojn,Aumentar retícula al obtener obj.,Crecer retícula al obtener obj.,Suurenna tähtäintä esineitä poimiessa,Agrandir viseur en prenant un objet,A célkereszt nőjön tárgyfelvételkor,Accresci il mirino quando si raccolgono oggetti,アイテム取得時に照準を大きくする,아이템 획득 시 조준점 키우기 ,Kweek het dradenkruis bij het oppakken van items,"Powiększ celownik, gdy podnosisz przedmioty",Aumentar mira ao pegar itens,Aumentar mira ao apanhar itens,Mărește ținta la ridicarea obiectelor,Увеличение прицела при подборе,Побољшај нишан током купљења предмета -Crosshair color,HUDMNU_CROSSHAIRCOLOR,,,Crosshair colour,Barva zaměřovače,Fadenkreuzfarbe,,Translinikoloro,Color de la retícula,,Tähtäimen väri,Couleur Viseur,Célkereszt színe,Colore mirino,照準色,조준점 색깔,Dradenkruis kleur,Kolor celownika,Cor da mira,,Culoare țintă,Цвет прицела,Боја нишана -Crosshair shows health,HUDMNU_CROSSHAIRHEALTH,,,,Zaměřovač zobrazuje zdraví,Fadenkreuz zeigt Gesundheit,,Translinio montri sanon,Mostrar salud en retícula,,Tähtäin näyttää terveyden,Couleur Viseur selon santé,Életerő jelzése a célkereszten,Il mirino mostra la salute,照準のヘルス表示,조준점과 체력 연동,Draadenkruis toont gezondheid,Celownik pokazuje zdrowie,Mostrar saúde na mira,Mostra vida na mira,Ținta afișează starea sănătății,Цвет прицела по состоянию здоровья,Нишан приказује здравље -Scale crosshair,HUDMNU_CROSSHAIRSCALE,,,,Velikost zaměřovače,Fadenkreuz skalieren,,Skali translinion,Escalar retícula,,Skaalaa tähtäintä,Mise à l'échelle du viseur,,Scala del mirino,照準サイズ,조준점 크기,Dradenkruis schalen,Skala celownika,Escala da mira,,Dimensiune țintă,Масштабирование прицела,Размера нишана -Display nametags,HUDMNU_NAMETAGS,,,,Zobrazovat jmenovky,Zeige Gegenstandsnamen,,Montri nometikedojn,Mostrar etiquetas,,Näytä nimitunnisteet,Afficher noms des objets,,Mostra le targhette identificative,ディスプレイネームタグ,이름표 표시,Naamplaatjes weergeven,Pokazuj nazwy przedmiotów,Mostrar nomes,,Indicare nume obiecte,Указание названия предметов,Прикажи имена предмета -Nametag color,HUDMNU_NAMETAGCOLOR,,,Nametag colour,Barva jmenovek,Farbe für Gegenstandsnamen,,Nometikeda koloro,Color de las etiquetas,,Nimitunnisteen väri,Couleur des noms d'objet,,Colore targhetta identificativa,ネームタグ色,이름표 색깔,Naamplaatje kleur,Kolor nazw przedmiotów,Cor dos nomes,,Culoare nume obiecte,Цвет названия предметов,Боја имена предмета -Use old ouch mug shot formula,HUDMNU_OLDOUCH,,,,Použít starý vzorec pro 'ouch' portrét,Alte Formel für „Autsch“-Gesicht,,Uzi maljuno-aj malliberejo-foto-forumlo,Usar formula antigua de foto de daño,,Käytä vanhaa auts-naamakuvan kaavaa,Ancien code pour l' « ouch face »,,Mostra la formula originale del viso 'ouch',旧式ouch mug shotを使用,구형 피격 표정 스프라이트 방식 사용,"Oude formule voor ""Ouch""-gezicht",Używaj starej formuły twarzy przy dostaniu obrażeń,Usar fórmula original do rosto de dor,,Utilizare mod portret vechi,Старая формула для портрета,Стара формула за приказ лика -Hexen weapon flashes,HUDMNU_HEXENFLASHES,,,,Druh bliknutí zbraní v Hexenu,Hexen-Waffenblitze,,Heksenaj armoj ekbrili,Destello armas Hexen,,Hexenin asevälähdykset,Flash d'arme dans Hexen,,Bagliori armi Hexen,Hexen 武器の視界色,헥센 무기 반짝임,Hexen-wapen flitsen,Błysk przy podnoszeniu broni z Hexena,Flash de arma do Hexen,,Tip strălucire arme Hexen,Тип вспышки оружия в Hexen,Треперење оружја у Hexen-у -Poison damage flashes,HUDMNU_POISONFLASHES,,,,Druh bliknutí při otrávení,Gift-Effekt,,Venonaj aromj ekbrili,Destello daño por veneno,,Myrkkyvahinkovälähdykset,Flash de poison dans Hexen,,Bagliori danno da veleno,毒ダメージの視界色,독데미지 반짝임,Vergiftigingsschade knippert,Efekt obrażeń przy zatruciu,Flash de dano por veneno,,Tip strălucire efect de otrăvire,Тип вспышки яда,Треперење током тровања -Ice death flashes,HUDMNU_ICEFLASHES,,,,Druh bliknutí při smrti umrznutím,Eis-Tod-Effekt,,Glacimorto ekbrili,Destello muerte por hielo,,Jääkuolemavälähdykset,Flash de morts par glace,,Bagliori morte da ghiaccio,氷結死の視界色,동사시 반짝임,Ijsdood knippert,Błysk przy śmierci poprzez zamrożenie,Flash de morte por congelamento,,Tip strălucire deces prin înghețare,Тип вспышки при смерти от льда,Треперење током смрти од леда -Poison Buildup flashes,HUDMNU_HAZARDFLASHES,,,,Druh blikání při kumulaci jedu,Kumulativer Gift-Effekt,,Venonamasigo ekbrili,Destello acumulación de veneno,,Myrkyn kertymisvälähdykset,Flash d'accumulation de poison,,Bagliori danno accumulato da veleno,蓄積毒の視界色,독데미지 반짝임 증강,Vergiftiging Opbouw knippert,Miganie przy nasilaniu się trucizny,Flash por acúmulo de dano por veneno,,Tip strălucire acumulare de otravă,Тип вспышки при скоплении яда,Треперење током гомилања отрова -Scaling Options,HUDMNU_SCALEOPT,,,,Nastavení velikosti,Skalierungsoptionen,,Skalagordoj,Opciones de escalado,,Skaalausasetukset,Option de mise à l'échelle,,Opzioni di scala,スケーリング オプション,배율 설정,Schaalopties,Opcje skalowania,Opções de Escala,,Setări Dimensiuni,Настройки масштабирования,Подешавања размере -Scaling Options,SCALEMNU_TITLE,,,,Nastavení velikosti,Skalierungsoptionen,,Skalagordoj,Opciones de escalado,,Skaalausasetukset,Option de mise à l'échelle,,Opzioni di scala,スケーリング オプション,배율 설정,Schaalopties,Opcje skalowania,Opções de Escala,,Setări Dimensiuni,Настройки масштабирования,Подешавања размере -Overrides for above setting,SCALEMNU_OVERRIDE,,,,Potlačení nastavení výše,Spezialisierungen,,Transpasi agordojn ke estas supre,Anular ajuste anterior,,Ohittaa asetuksen ylhäällä,Annule les paramètres au dessus,,Sovrascritture per i settaggi sopra,設定の上書き,위 설정을 위해 무시,Overschrijdingen voor bovenstaande instelling,Nadpisuje dla powyższego ustawienia,Anular configurações acima,,Suprascriere pentru setările de mai sus,Задать специальные настройки,Специјална подешавања -Messages,SCALEMNU_MESSAGES,,,,Zprávy,Nachrichten,,Mesaĝoj,Mensajes,,Viestit,Messages,,Messaggi,メッセージ類,메시지,Berichten,Wiadomości,Mensagens,,Mesaje,Сообщения,Поруке -Console,SCALEMNU_CONSOLE,,,,Konzole,Konsole,,Konzolo,Consola,,Konsoli,Console,,Console,コンソール,콘솔,Console,Konsola,Console,Consola,Consolă,Консоль,Конзола -Status bar,SCALEMNU_STATBAR,,,,Stavový panel,Statusleiste,,Stata baro,Barra de estado,,Tilapalkki,Barre d'état,,Barra di stato,ステータスバー,상태 바,Statusbalk,Pasek statusu,Barra de status,Barra de estado,Bară de Stare,Строка состояния,Статусна трака -Fullscreen HUD,SCALEMNU_HUD,,,,HUD přes celou obrazovku,Vollbild-HUD,,Tutekrana HUD,HUD de pantalla completa,,Täyden ruudun tilanäyttö,ATH plein écran,,HUD a pieno schermo,全画面HUD,전체화면 HUD,Volle scherm HUD,HUD pełnoekranowy,HUD de tela cheia,HUD de ecrã cheio,Interfață pe Timp de Joc tip Fullscreen,Полноэкранный HUD,HUD преко целог екрана -Alternative HUD,SCALEMNU_ALTHUD,,,,Alternativní HUD,Alternatives HUD,,Alternativa HUD,HUD alternativo,,Vaihtoehtoinen tilanäyttö,ATH alternatif,,HUD alternativo,オルタナティブHUD,대체 HUD,Alternatieve HUD,Alternatywny HUD,HUD alternativo,,Interfață pe Timp de Joc Alternativă,Альтернативный HUD,Алтернативни HUD -HUD preserves aspect ratio,SCALEMNU_HUDASPECT,,,,HUD uchovává poměr stran,HUD bewahrt Seitenverhältnisse,,HUD Konservas aspekto-proporcion,HUD conserva la rel. de aspecto,,Tilanäyttö säilyttää kuvasuhteen,ATH préserve le rapport d'aspect,,HUD preserva le proporzioni,HUDのアスペクト比維持,HUD 화면 비율 보존,HUD behoudt de beeldverhouding,HUD zachowuje współczynnik proporcji,HUD deve preservar proporções,,Interfața pe Timp de Joc își Păstrează Aspectul,Сохранение соотношения сторон HUD,Сачувај пропорције HUD-а -Use default scale,SCALEMNU_USEUI,,,,Použít výchozí velikost,Benutze Standardskalierung,,Uzi defaŭltskalo,Usar escalado por defecto,,Käytä oletusmittakaavaa,Défaut,,Usa la scala di default,通常サイズを使う,기본 배율 사용,Gebruik standaardweegschaal,Użyj domyślnej skali,Usar escala padrão,,Folosește dimensiunea implicită,Размер по умолчанию,Уобичајена размера -Scale to fullscreen,SCALEMNU_USEFS,,,,Škalovat přes celou obrazovku,Skaliere auf Vollbild,,Skali al tutekrano,Escalar a pant. completa,,Skaalaa täyteen ruutuun,Plein écran,,Scala a pieno schermo,全画面に拡大,전체화면에 맞게 축척,Schaalbaar tot volledig scherm,Przeskaluj do pełnego ekranu,Escala de tela cheia,Escalar para ecrã cheio,Dimensionare la modul Fullscreen,Масштабировать со всем экраном,Проширење преко целог екрана -Adapt to screen size,SCALEMNU_ADAPT,,,,Přizpůsobit velikosti obrazovky,Passe an Bildschirmgröße an,,Adapti al ekranamplekso,Adaptar al tamaño de pantalla,,Sovita näytön kokoon,Ecran,,Adatta alla dimensione della schermata,スクリーン サイズに合わせる,화면 사이즈에 맞게 축척,Aanpassen aan de grootte van het scherm,Dostosuj do pełnego ekranu,Adaptar ao tamanho de tela,,Adaptează la dimensiunea ecranului,Адаптироваться к размеру экрана,Прилагоди размери екрана -Alternative HUD,ALTHUDMNU_TITLE,,,,Alternativní HUD,Alternatives HUD,,Alternativa HUD,HUD Alternativo,,Vaihtoehtoinen tilanäyttö,ATH Alternatif,,HUD alternativo,オルタナティブHUD,대체 HUD,Alternatieve HUD,Alternatywny HUD,HUD alternativo,,Interfață pe Timp de Joc Alternativă,Альтернативный HUD,Алтернативни HUD -Enable alternative HUD,ALTHUDMNU_ENABLE,,,,Povolit alternativní HUD,Alternatives HUD eingeschaltet,,Aktivigi alternativan HUD,Activar HUD Alternativo,,Ota käyttöön vaihtoehtoinen tilanäyttö,Activer l'ATH Alternatif,,Abilita HUD alternativo,オルタナティブHUD有効,대체 HUD 사용,Alternatieve HUD inschakelen,Włącz alternatywny HUD,Habilitar HUD alternativo,,Activează Interfața pe Timp de Joc Alternativă,Альтернативный HUD,Укључи алтернативни HUD -Show secret count,ALTHUDMNU_SHOWSECRETS,,,,Zobrazit počet skrýší,Zeige Geheimniszähler,,Montri skretkvanton,Mostrar cont. de secretos,,Näytä salojen lukumäärä,Afficher compteur de secrets,,Mostra il conteggio dei segreti,シークレット数 表示,비밀 수 표시,Toon geheime telling,Pokaż liczbę sekretów,Mostrar contagem de segredos,,Afișează numărul secretelor,Отображение обнаруженных тайников,Прикажи количину тајна -Show monster count,ALTHUDMNU_SHOWMONSTERS,,,,Zobrazit počet příšer,Zeige Monsterzähler,,Montri monstro-kvanton,Mostrar cont. de monstruos,,Näytä hirviöiden lukumäärä,Afficher compteur de monstres,,Mostra il conteggio dei mostri,モンスター数 表示,적 개체 수 표시,Toon het aantal monsters,Pokaż liczbę zabójstw,Mostrar contagem de monstros,,Afișează numărul de monștri,Отображение количества монстров,Прикажи количину чудовишта -Show item count,ALTHUDMNU_SHOWITEMS,,,,Zobrazit počet předmětů,Zeige Gegenstandszähler,,Montri aĵkvanton,Mostrar cont. de objetos,,Näytä esineiden lukumäärä,Afficher compteur d'objets,,Mostra il conteggio degli oggetti,アイテム数の表示,아이템 수 표시,Toon aantal items,Pokaż liczbę przedmiotów,Mostrar contagem de itens,,Afișează numărul de obiecte,Отображение количества предметов,Прикажи количину предмета -Show stamina and accuracy,ALTHUDMNU_SHOWSTATS,,,,Zobrazit výdrž a přesnost,Zeige Kondition und Genauigkeit,,Montri viglecon kaj akuratecon,Mostrar resistencia/precisión,,Näytä puhti ja tarkkuus,Afficher Endurance et Précision,,Mostra stamina e accuratezza,スタミナと精度の表示,스테미나와 정확도를 표시,Toon uithoudingsvermogen en nauwkeurigheid,Pokaż wytrzymałość i precyzję,Mostrar resistência e precisão,,Afișează rezistența fizică si acuratețea,Отображение стойкости и точности,Прикажи издржљивост и прецизност -Show berserk,ALTHUDMNU_SHOWBERSERK,,,,Zobrazit berserk,Zeige Berserk,,Montri frenezecon,Mostrar berserker,,Näytä raivo,Afficher Berserk,,Mostra il berserk,バーサーク表示,버서크 아이템을 표시,Toon berserk,Pokaż szał,Mostrar berserk,,Afișează pachetul de forță mărită,Отображение берсерка,Прикажи берсерк -Show weapons,ALTHUDMNU_SHOWWEAPONS,,,,Zobrazit zbraně,Zeige Waffen,,Montri aromojn,Mostrar armas,,Näytä aseet,Afficher Armes,,Mostra le armi,武器表示,무기들을 표시,Toon wapens,Pokaż bronie,Mostrar armas,,Afișează armele,Отображение оружия,Прикажи оружја -Show ammo for,ALTHUDMNU_SHOWAMMO,,,,Zobrazit munici pro,Zeige Munition,,Montri municion por,Mostrar munición para,,Näytä ammukset aseelle,Afficher Munitions pour,,Mostra le munizioni per,弾薬とか 表示,탄약을 표시,Toon munitie voor,Pokaż amunicję dla,Mostrar munição para,,Afișează muniția pentru,Показывать патроны для,Прикажи муниције за -Show time,ALTHUDMNU_SHOWTIME,,,,Zobrazit čas,Zeige Zeit,,Montri tempon,Mostrar tiempo,,Näytä aika,Afficher temps niveau,,Mostra il tempo,時間の表示,시간 표시,Toon tijd,Pokaż czas,Mostrar tempo,,Afișează timpul,Отображение времени,Прикажи време -Time color,ALTHUDMNU_TIMECOLOR,,,Time colour,Barva času,Zeiot-Farbe,,Tempkoloro,Color del tiempo,,Ajan väri,Couleur du timer,,Colore del tempo,時間の字色,시간 색상,Tijd kleur,Kolor czasu,Cor do tempo,,Culoare timp,Цвет времени,Боја времена -Show network latency,ALTHUDMNU_SHOWLAG,,,,Zobrazit latenci sitě,Zeige Netzwerk-Latenz,,Montri reto-respondotempo,Mostrar latencia de red,,Näytä verkon viive,Afficher latence réseau,,Mostra la latenza del network,ネットのラグ表示,내트워크 트래픽 표시,Toon netwerklatentie,Pokaż czas oczekiwania sieci,Mostrar latência de rede,,Afișează perioada de întârziere a conexiunii,Отображение задержки сети,Прикажи кашњење мреже -Ammo display order,ALTHUDMNU_AMMOORDER,,,,Pořadí zobrazení munice,Munitionsreihenfolge,,Municividiga aranĝo,Orden vista de munición,,Ammusten esitysjärjestys,Ordre d'affichage des munitions,,Ordine mostra delle munizioni,弾薬表示順,탄약 표시 순서,Volgorde van de munitieweergave,Kolejność pokazywania amunicji,Ordem de exibição de munição,,Ordine afișare muniție,Порядок отображения боеприпасов,Редослед муниција -Red ammo display below %,ALTHUDMNU_AMMORED,,,,Červený indikátor munice pod %,Rot für Munition unter %,,Ruĝa municividigo sub %,Porcent. de munición en rojo,,Punaiset ammukset ammusten alittaessa %,Compteur de munitions rouge sous,,Contatore delle munizioni di colore rosso sotto,弾薬の赤色表示%,적색 남은 탄약 밑에 표시,Rood munitieweergave onder %,Wyświetl czerwoną amunicję pod ,Porcentagem de munição em vermelho até,Percentagem de munição em vermelho até,Muniția schimbă culoarea în roșu sub %,"Отображение боеприпасов красным ниже, %",Прикажи муниције црвеном испод % -Yellow ammo display below %,ALTHUDMNU_AMMOYELLOW,,,,Žlutý indikátor munice pod %,Gelb für Munition unter %,,Flava municividigo sub %,Porcent. de munición en amarillo,,Keltaiset ammukset ammusten alittaessa %,Compteur de munitions jaune sous,,Contatore delle munizioni di colore giallo sotto,弾薬の黄色表示%,황색 남은 탄약 밑에 표시,Gele munitieweergave onder %.,Wyświetl żółtą amunicję pod ,Porcentagem de munição em amarelo até,Percentagem de munição em amarelo até,Muniția schimbă culoarea în galben sub %,"Отображение боеприпасов жёлтым ниже, %",Прикажи муниције жутом испод % -Red health display below,ALTHUDMNU_HEALTHRED,,,,Červený indikátor zdraví pod,Rot für Gesundheit unter %,,Ruĝa sanvidigo sube,Porcent. de salud en rojo,,Punainen terveys terveyden alittaessa,Compteur de santé rouge sous,,Contatore della salute di colore rosso sotto,体力の赤色表示%,적색 체력 밑에 표시,Rood gezondheidsweergave beneden,Wyświetl czerwone zdrowie pod ,Porcentagem de saúde em vermelho até,Percentagem de saúde em vermelho até,Sănătatea schimbă culoarea în roșu sub %,"Отображение здоровья красным ниже, %",Прикажи здравље црвеном испод -Yellow health display below,ALTHUDMNU_HEALTHYELLOW,,,,Žlutý indikátor zdraví pod,Gelb für Gesundheit unter %,,Flava sanvidigo sube,Porcent. de salud en amarillo,,Keltainen terveys terveyden alittaessa,Compteur de santé jaune sous,,Contatore della salute di colore giallo sotto,体力の黄色表示%,황색 체력 밑에 표시,Geel gezondheidsweergave beneden,Wyświetl żółte zdrowie pod ,Porcentagem de saúde em amarelo até,Percentagem de saúde em amarelo até,Sănătatea schimbă culoarea în galben sub %,"Отображение здоровья жёлтым ниже, %",Прикажи здравље жутом испод -Green health display below,ALTHUDMNU_HEALTHGREEN,,,,Zelený indikátor zdraví pod,Grün für Gesundheit unter %,,Verda sanvidigo sube,Porcent. de salud en verde,,Vihreä terveys terveyden alittaessa,Compteur de santé vert sous,,Contatore della salute di colore verde sotto,体力の緑色表示%,녹색 체력 밑에 표시,Groen gezondheidsweergave beneden,Wyświetl zielone zdrowie pod ,Porcentagem de saúde em verde até,Percentagem de saúde em verde até,Sănătatea schimbă culoarea în verde sub %,"Отображение здоровья зелёным ниже, %",Прикажи здравље зеленом испод -Red armor display below,ALTHUDMNU_ARMORRED,,,Red armour display below,Červený indikátor brnění pod,Rot für Panzerung unter %,,Ruĝa kirasvidigo sube,Porcent. de blindaje en rojo,,Punainen panssari panssarin alittaessa,Compteur d' armure rouge sous,,Contatore dell'armatura di colore rosso sotto,防具の赤色表示%,적색 아머 밑에 표시,Rood pantserweergave beneden,Wyświetl czerwony pancerz pod ,Porcentagem de armadura em vermelho até,Percentagem de armadura em vermelho até,Armura schimbă culoarea în galben sub %,"Отображение брони красным ниже, %",Прикажи оклоп црвеном испод -Yellow armor display below,ALTHUDMNU_ARMORYELLOW,,,Yellow armour display below,Žlutý indikátor brnění pod,Gelb für Panzerung unter %,,Flava kirasvidigo sube,Porcent. de blindaje en amarillo,,Keltainen panssari panssarin alittaessa,Compteur d' armure jaune sous,,Contatore dell'armatura di colore giallo sotto,防具の黄色表示%,황색 아머 밑에 표시,Geel pantserweergave beneden,Wyświetl żółty pancerz pod ,Porcentagem de armadura em amarelo até,Percentagem de armadura em amarelo até,Armura schimbă culoarea în galben sub %,"Отображение брони жёлтым ниже, %",Прикажи оклоп жутом испод -Green armor display below,ALTHUDMNU_ARMORGREEN,,,Green armour display below,Zelený indikátor brnění pod,Grün für Panzerung unter %,,Verda kirasvidigo sube,Porcent. de blindaje en verde,,Vihreä panssari panssarin alittaessa,Compteur d' armure bleu sous,,Contatore dell'armatura di colore verde sotto,防具の緑色表示%,녹색 아머 밑에 표시,Groen pantserweergave beneden,Wyświetl zielony pancerz pod ,Porcentagem de armadura em verde até,Percentagem de armadura em verde até,Armura schimbă culoarea în verde sub %,"Отображение брони зелёным ниже, %",Прикажи оклоп зеленом испод -Alternative Automap HUD,ALTHUDMNU_AUTOMAPHUD,,,,Alternativní HUD automapy,Alternatives Automap HUD,,Elekteca Aŭtomapa HUD,HUD alternativo del automapa,,Vaihtoehtoinen automaattikartan tilanäyttö,ATH Alternatif pour carte,,HUD automappa alternativo,オルタナティブ オートマップHUD,대체 오토맵 HUD,Alternatieve Automap HUD,Alternatywny HUD mapy,HUD alternativo de automapa,,Hartă Computerizată Alternativă,Альтернативный HUD на автокарте,Алтернативни HUD за аутомапу -Map title color,ALTHUDMNU_TITLECOLOR,,,Map title colour,Barva názvu levelu,Farbe für Levelnamen,,Maptitolo-Koloro,Color del título del mapa,,Tason nimen väri,Couleur titre du niveau,,Colore titolo mappa,マップ名の色,맵 제목 색깔,Kaarttitel kleur,Kolor nazwy mapy,Cor do título do fase,Cor do título do nível,Culoare titlu hartă,Цвет названия уровня,Боја назива нивоа -Map time color,ALTHUDMNU_MAPTIMECOLOR,,,Map time colour,Barva času levelu,Farbe für Level-Zeit,,Maptempo-Koloro,Color del tiempo del mapa,,Tason ajan väri,Couleur temps du niveau,,Colore tempo mappa,経過時間の色,맵 시간 색깔,Kaarttijd kleur,Kolor czasu na mapie,Cor do tempo da fase,Cor do tempo do nível,Culoare timp petrecut pe hartă,Цвет времени для уровней,Боја времена на нивоу -Hub time color,ALTHUDMNU_HUBTIMECOLOR,,,Hub time colour,Barva času hubu,Farbe für Hub-Zeit,,Nabtempo-Koloro,Color del tiempo del nodo,,Tasokokoelman ajan väri,Couleur temps du hub,,Colore tempo hub di mappe,区間経過時間の色,허브 시간 색깔,Kleur naaftijd,Kolor czasu w hubie,Cor do tempo no HUD,,Culoare timp petrecut în hub,Цвет времени для хабов,Боја времена на хабу -Total time color,ALTHUDMNU_TOTALTIMECOLOR,,,Total time colour,Barva celkového času,Farbe für Gesamtzeit,,Tuttempo-Koloro,Color del tiempo total,,Kokonaisajan väri,Couleur temps total,,Colore tempo totale,合計経過時間の色,누적 경과한 시간 색깔,Totale tijd kleur,Kolor całkowitego czasu,Cor do tempo total,,Culoare timp total,Цвет общего времени,Боја укупног времена -Coordinate color,ALTHUDMNU_COORDINATECOLOR,,,Coordinate colour,Barva souřadnic,Farbe für Koordinaten,,Kunordigi koloron,Color de Coordenadas,,Koordinaattien väri,Couleur coordonnées,,Colore coordinate,座標色,좌표 색깔,Coördinaat kleur,Skoordynuj kolor,Cor das coordenadas,,Culoare coordonate,Цвет координат,Боја координата -Coordinate mode,ALTHUDMNU_COORDINATEMODE,,,,Režim souřadnic,Koordinatenmodus,,Kunordigi modon,Modo de Coordenadas,,Koordinaattitila,Mode coordonnées,,Modalità coordinate,座標モード,좌표 모드,Coördinatiemodus,Skoordynuj tryb,Modo de coordenada,,Mod coordonate,Координаты игрока,Мод координата -Statistics name color,ALTHUDMNU_STATSNAMECOLOR,,,Statistics name colour,Barva názvu statistik,Farbe für Statistik-Namen,,Statistiknomo-koloro,Color del nombre de estadísticas,,Tilastotiedon nimen väri,Couleur nom des statistiques,,Colore nome statistica,統計名の色,통계표 이름 색상,Statistieken naam kleur,Kolor nazw statystyk,Cor do nome das estatísticas,,Culoare nume statistici,Цвет имён в статистике,Боја назива статистика -Statistics color,ALTHUDMNU_STATSCOLOR,,,Statistics colour,Barva statistik,Farbe für Statistik-Nummern,,Statistiko-koloro,Color de las estadísticas,,Tilastotiedon väri,Couleur statistiques,,Colore contatore statistica,統計の色,통계표 색상,Statistische kleur,Kolor statystyk,Cor das estatísticas,,Culoare statistici,Цвет статистики,Боја статистика -Miscellaneous Options,MISCMNU_TITLE,,,,Ostatní nastavení,Verschiedene Optionen,,Ekstraĵa agordoj,Opciones Misceláneas,,Sekalaiset asetukset,Options Annexes,,Opzioni miste,その他のオプション,그 외 설정,Diverse opties,Różne Opcje,Outras Opções,,Setări suplimentare,Дополнительные настройки,Разна подешавања -Merge left+right Alt/Ctrl/Shift,MISCMNU_MERGEKEYS,,,,Zkombinovat pravý a levý Alt/Ctrl/Shift,Linke und rechte Umschalt/Strg/Alt zusammenfassen,,Kunigi maldekstro+dekstro Alt/Ctrl/Shift,Combinar izq.+der. Alt/Ctrl/Mayús,,Yhdistä vasen ja oikea Alt/Ctrl/Vaihto,Combiner Alt/Ctrl/maj gauche & droite,,Unisci sinistra+destra Alt/Control/Maiusc,左と右のALT/CTRL/SHIFTキーを統合,양쪽 ALT/CTRL/SHIFT키 합병,Samenvoegen links+rechts Alt/Ctrl/Shift,Połącz przyciski lewo+prawo Alt/Ctrl/Shift,Unir teclas Alt/Ctrl/Shift esquerdas e direitas,Juntar Alt/Ctrl/Shift esquerdo+direito,Combină tastele Alt/Ctrl/Shift drepte + stângi,Не разделять левый/правый ALT/CTRL/SHIFT,Споји лево+десно Аlt/Ctrl/Shift -Alt-Enter toggles fullscreen,MISCMNU_WINFULLSCREENTOGGLE,,,,Alt-Enter přepíná celou obrazovku,Alt-Enter schaltet Vollbild an/aus,,Alt klavo-Enter klavo baskuligi tutekranon,Alt+Enter alterna pantalla completa,,Alt-Enter kytkee täyden ruudun päälle/pois,Alt-Entrée alterne plein écran,,Alt-Invio attiva/disattiva lo schermo pieno,ALTとENTERで全画面に切り替え,ALT+ENTER키로 전체화면 조정,Alt-Enter schakelt het volledige scherm aan/uit,Alt-Enter przełącza na pełen ekran,Alt-Enter ativa tela cheia,Alt-Enter ativa ecrã cheio,Alt-Enter comută modul fullscreen,Переключение полного экрана по ALT+ENTER,Alt-Enter пребацује на цео екран -Command-F toggles fullscreen,MISCMNU_MACFULLSCREENTOGGLE,,,,Command-F přepíná celou obrazovku,Cmd-F schaltet Vollbild an/aus,,Komando-F baskuligi tutekranon,Cmd-F alterna pantalla completa,,Komento-F kytkee täyden ruudun päälle/pois,Command-F alterne plein écran,,Command-F attiva/disattiva lo schermo pieno,Ctrl + Fキーで全画面表示,COMMAND+F키로 전체화면 조정,Command-F schakelt het volledige scherm aan/uit,Command-F przełącza pełny ekran,Command-F ativa tela cheia,Command-F ativa ecrã cheio,Comanda-F comută modul fullscreen,Переключение полного экрана по Command+F,Command-F пребацује на цео екран -Show IWAD selection dialog,MISCMNU_QUERYIWAD,,,,Zobrazit dialog pro výběr IWADu,Zeige IWAD-Auswahl,,Montri IWAD elekta dialogo,Mostrar diálogo de selección de IWAD,,Näytä IWAD-valintaikkuna,Afficher la séléction d'IWAD,,Mostra la schermata della selezione IWAD,IWADの選択画面を表示,IWAD 게임 선택창 표시,IWAD-selectiedialoogvenster weergeven,Pokaż ekran wyboru gry (IWAD),Mostrar janela de seleção de IWAD,,Afișează fereastra de selectare a jocurilor,Выбор IWAD-файла при запуске,Покажи IWAD дијалог за избор -Enable cheats from all games,MISCMNU_ALLCHEATS,,,,Povolit cheaty ze všech her,Ermögliche Cheats aus allen Spielen,,Aktivigi trompojn el tutaj ludoj,Activar trucos de todos los juegos,,Ota käyttöön huijauskoodit kaikista peleistä,Activer cheats de tous les jeux,,Abilita tutti i cheat da tutti i giochi,全ゲームでチート使用可にする,모든 게임에 치트 허용,Laat bedriegers van alle spellen toe,Włącz oszustwa ze wszystkich gier,Habilitar trapaças de todos os jogos,Permitir batotas de todos os jogos,Activează codurile din toate jocurile,Читы из всех игр,Омогући читове од свих игара -Enable autosaves,MISCMNU_ENABLEAUTOSAVES,,,,Povolit automatické ukládání,Automatisches Speichern,,Aktivigi aŭtokonservojn,Activar autoguardado,,Ota käyttöön automaattiset tallennukset,Activer Sauvegardes auto,,Abilita i salvataggi automatici,オートセーブを有効化,빠른 저장 허용,Automatisch opslaan inschakelen,Włącz autozapis,Habilitar salvamento automático,Permitir gravação automática,Activează salvări automate,Автосохранения,Омогући аутосејвове -Number of autosaves,MISCMNU_AUTOSAVECOUNT,,,,Počet automatických uložených her,Anzahl von automatischen Speicherständen,,Kvanto da aŭtokonservojn,Número de autoguardados,,Automaattisten tallennusten lukumäärä,Total de sauvegardes auto,,Numero di salvataggi automatici,オートセーブの最大数,빠른 저장 수,Aantal autosafes,Liczba autozapisów,Número de salvamentos automáticos,Número de gravações automáticos,Număr salvări automate,Количество автосохранений,Број аутоматских чувања -Save/Load confirmation,MISCMNU_SAVELOADCONFIRMATION,,,,Potvrzení o uložení/načtení,Laden/Speichern bestätigen,,Konservi/Ŝarĝi jesigo,Confirmación al guardar/cargar,,Tallennuksen/Latauksen vahvistus,Confirmation C/S,,Conferma Salvataggio/Caricamento,セーブ/ロード時に確認,스크립트로 스크린샷 생성 허용,Opslaan/Laad bevestiging,Potwierdzenie zapisu/wczytania,Confirmação ao salvar/carregar,Confirmação ao gravar/carregar,Confirmare pentru salvare/încărcare,Подтверждение при сохранении/загрузке,Потврђивање током чувања/учитавања -Enable making screenshots by scripts,MISCMNU_ENABLESCRIPTSCREENSHOTS,,,,Povolit skriptům pořizovat snímky obrazovky,"Erlaube Skripts, Screenshots zu machen",,Aktivigi faranto ekrankopiojn per skriptoj,Habilitar captura de pantalla por scripts,,Salli komentosarjoin otetut kuvakaappaukset,Autoriser les Scripts à prendre des captures,,Abilita la cattura dello schermo tramite scripts,スクリプトからのスクショ作成を有効化,저장/불러오기 확인,Screenshots maken met behulp van scripts,Pozwól na robienie zrzutów ekranu przez skrypty,Habilitar capturas de tela por scripts,Permitir capturas de ecrã por scripts,Posibilitate de a face poze prin scripturi,Возможность делать скриншоты через скрипты,Омогући прављење скриншотова по скрипти -Load *.deh/*.bex lumps,MISCMNU_DEHLOAD,,,,Načítat *.deh/*.bex soubory,Lade *.deh/*.bex Daten,,Ŝarĝi *.deh/*.bex lumpoj,Cargar archivos *.deh/*.bex,,Lataa *.deh/*.bex-lump-tiedostot,Charger fichiers *.deh/*.bex,,Carica i lump *.deh/*.bex,.deh/.bexファイルを読み込む,*.deh/*.bex 럼프 파일 불러오기,*.deh/*.bex laden,Załaduj dane *.deh/*.bex,Carregar lumps *.deh/*.bex,,Încarcă nodurile *.deh/*.bex,Загружать файлы *.deh/*.bex,Учитај *.deh/*.bex фајлове -Cache nodes,MISCMNU_CACHENODES,,,,Cachovat nodes,Nodes zwischenspeichern,,Kaŝmemoraj nodoj,Caché de nodos,,Tallenna solmut välimuistiin,Mise en cache des nodes,,Cache dei nodi,ノードキャッシュ,캐시 노드,Cache nodes,Węzły pamięci podręcznej,Cachê de nodes,Cache de nodes,Depozitare noduri cache,Кэширование нодов,Кеширани чворови -Time threshold for node caching,MISCMNU_CACHETIME,,,,Časový práh pro cachování nodes,Zeitschwelle für das Zwischenspeichern von Nodes,,Templimo pro kaŝmemornodi,Umbral de tiempo para caché de nodos,,Kynnysaika solmujen välimuistitallennukseen,Limite cache des nodes,,Soglia di tempo per il caching dei nodi,ノードキャッシュ時間の閾値,노드 캐싱을 위한 시간 임계값 계산,Tijdsdrempel voor het cachen van nodes,Próg czasowy buforowania węzłów,Limite de tempo para cachê de nodes,Limite de tempo para cache de nodes,Limită de timp pentru depozitare cache,Временной порог для кэширования нодов,Временски праг за кеширање чвора -Clear node cache,MISCMNU_CLEARNODECACHE,,,,Vyčistit node cache,Nodespeicher löschen,,Viŝi kaŝmemorajn nodojn,Limpiar Caché de nodos,,Tyhjennä solmuvälimuisti,Vider le cache des nodes,,Pulisci la cache dei nodi,ノードのキャッシュをクリア,노드 캐시를 삭제,Duidelijke node cache,Wyczyść pamięć podręczną,Limpar cachê de nodes,Limpar cache de nodes,Ștergere noduri cache,Очистить кэш нодов,"Избриши кеширане чворове -" -Allow skipping of intermission scrollers,MISCMNU_INTERSCROLL,,,,Povolit přeskakování intermission posuvníků,Erlaube Überspringen von Intermission-Scrollern,,Permesi transsalti interaktajn rulumojn,Permitir omisión de intermedios,,Salli tarinaruutujen vierityksen ohittaminen,Sauter compteurs d'intermission,,Consenti di saltare gli scorrimenti delle intermissioni,クリア結果集計のスキップを許可,인터미션 스크롤러 생략 허용,,Pozwól na pominięcie wstawek,Pular telas de intervalo entre fases,Saltar ecrãs de intervalo entre níveis,Permite saltul peste inserările de text,Разрешение пропуска текстовых вставок,Дозволи прескакање прелаза са текстовима -Automap Options,AUTOMAPMNU_TITLE,,,,Nastavení automapy,Automapoptionen,,Aŭtomapagordoj,Opciones del Automapa,,Automaattikartan asetukset,Options Carte,,Opzioni automappa,オートマップ オプション,오토맵 설정,Automap-opties,Opcje Mapy,Opções de Automapa,,Setări Hartă Computerizată,Настройки автокарты,Подешавања аутомапе -Map color set,AUTOMAPMNU_COLORSET,,,Map colour set,Nastavit barvy mapy,Farbset,,Mapkoloragordaĵo,Definir colores,,Kartan värikokoelma,Set de couleurs de la carte,,Colori della mappa,地図色セット,맵 색상 설정,Kaartkleurenset,Zestaw kolorów mapy,Definir cores de mapa,,Set culori hartă,Цвета автокарты,Боје за мапу -Allow map defined colors,AUTOMAPMNU_CUSTOMCOLORS,,,Allow map defined colours,Povolit barvy nastavené v modech,Erlaube levelspezifische Farben,,Permesi mapdefinito-koloron,Permitir colores definidos,,Salli tason määrittelemät värit,Couleurs définies par carte,,Consenti i colori definiti dalla mappa,定義したマップ色の許可,맵 정의 색상 허용,Niveau-specifieke kleuren toestaan,Pozwól na kolory zdefiniowne przez mapę,Permitir cores definidas por mapa,,Permite culorilor să fie definite de hartă,Настроить цвета автокарты,Дозволи дефинисане боје за мапу -Set custom colors,AUTOMAPMNU_SETCUSTOMCOLORS,,,Set custom colours,Nastavit vlastní barvy,Benutzerdefinierte Farben,,Agordi laŭmendajn kolorojn,Fijar colores personalizados,,Mukauta värejä,Choisir couleurs personnalisées,,Modifica i colori personalizzati,カスタム色を決める,사용자 지정 색상 설정,Aangepaste kleuren instellen,Spersonalizuj kolory,Definir cores personalizadas,,Setare culori personalizate,Выбор цветов,Промени боје -Customize map controls,AUTOMAPMNU_CONTROLS,,,,Nastavit ovládání mapy,Automapsteuerung einstellen,,Agordi mapregilojn,Personalizar Controles del mapa,,Kartanohjausasetukset,Choisir contrôles de la carte,,Personalizza i controlli mappa,マップコントロール カスタマイズ,맵 조작 설정,Kaartcontroles aanpassen,Ustaw klawisze mapy,Configurar comandos de mapa,,Personalizare schemă de control a hărții,Управление,Промени контроле мапе -Rotate automap,AUTOMAPMNU_ROTATE,,,,Otáčet automapu,Rotiere Automap,,Rotacii aŭtomapon,Rotar automapa,,Kiertyvä automaattikartta,Rotation de la Carte,,Ruota l'automappa,オートマップの回転表示,오토맵 회전,Automatisch roteren,Obracaj mapę,Girar automapa,,Rotire hartă computerizată,Вращающаяся автокарта,Ротирај аутомапу -Overlay automap,AUTOMAPMNU_OVERLAY,,,,Použít překryvnou mapu,Überlagere Automap,,Surmeti aŭtomapon,Superponer automapa,,Projisoi automaattikartta,Carte en Surimpression,,Copri l'automappa,オートマップを重ねる,오토맵을 오버레이,Overlay automap,Nałożenie mapy,Sobreposição de automapa,,Acoperire hartă computerizată,Прозрачная автокарта,Провидна аутомапа -Enable textured display,AUTOMAPMNU_TEXTURED,,,,Povolit textury,Texturanzeige,,Aktivigi teksaĵekrano,Mostrar automapa texturizado,,Ota käyttöön pintakuvioinnit,Activer affichage texturé,,Abilita la mostra texture,床テクスチャ表示を許可,텍스쳐 디스플레이 허용,Structuurweergave inschakelen,Włącz oteksturowanie mapy,Habilitar automapa texturizado,Permitir automapa texturizado,Activare mod texturat,Текстуры на автокарте,Омогући приказ текстура -Follow player,AUTOMAPMNU_FOLLOW,,,,Následovat hráče,Folge dem Spieler,,Sekvi ludanton,Seguir jugador,,Seuraa pelaajaa,Suivre le joueur,,Segui il giocatore,プレイヤー追従,플레이어 추적,Volg de speler,Podążaj za graczem,Seguir jogador,,Urmărire jucător,Привязка к игроку,Прати играча -Show item counts,AUTOMAPMNU_SHOWITEMS,,,,Zobrazit počet předmětů,Zeige Gegenstandsanzahl,,Montri aĵkvantojn,Mostrar conteo de objetos,,Näytä esineiden lukumäärä,Afficher compte d'objets,,Mostra il conteggio degli oggetti,アイテム数 表示,주운 아이템의 갯수를 표시,Toon artikeltellingen,Pokaż liczbę przedmiotów,Mostrar contagem de itens,,Afișare numărătoare obiecte,Количество предметов,Прикажи бројач за предмете -Show monster counts,AUTOMAPMNU_SHOWMONSTERS,,,,Zobrazit počet příšer,Zeige Monsteranzahl,,Montri monstro,Mostrar conteo de monstruos,,Näytä hirviöiden lukumäärä,Afficher compte de monstres,,Mostra il conteggio dei mostri,モンスター数 表示,죽인 적의 횟수 표시,Toon monstertellingen,Pokaż liczbę potworów,Mostrar contagem de monstros,,Afișare numărătoare monștri,Количество монстов,Прикажи бројач за чудовишта -Show secret counts,AUTOMAPMNU_SHOWSECRETS,,,,Zobrazit počet tajemství,Zeige Geheimnisanzahl,,Montri monstro-kvantojn,Mostrar conteo de secretos,,Näytä salojen lukumäärä,Afficher compte de secrets,,Mostra il conteggio dei segreti,シークレット数 表示,밝힌 비밀의 수 표시,Toon geheime tellingen,Pokaż liczbę sekretów,Mostrar contagem de segredos,,Afișare numărătoare secrete,Количество тайников,Прикажи бројач за тајне -Show time elapsed,AUTOMAPMNU_SHOWTIME,,,,Zobrazit uplynulý čas,Zeige vergangene Zeit,,Montri pastempon,Mostrar tiempo transcurrido,,Näytä kulunut aika,Afficher temps passé,,Mostra il tempo trascorso,経過時間 表示,경과한 시간 표시,Verstreken tijd tonen,Pokaż ile czasu upłynęło,Mostrar tempo decorrido,,Afișare timp petrecut pe hartă,Прошедшее время,Прикажи протекло време -Show total time elapsed,AUTOMAPMNU_SHOWTOTALTIME,,,,Zobrazit celkový uplynulý čas,Zeige Gesamtzeit,,Montri tutan pastempon,Mostrar tiempo total transc.,,Näytä yhteensä kulunut aika,Afficher total de temps passé,,Mostra il tempo totale trascorso,統計時間 表示,누적 경과한 시간 표시,Toon de totale verstreken tijd,"Pokaż całkowity czas, który upłynął",Mostrar tempo total decorrido,,Afișare timp total petrecut în joc,Общее время,Прикажи укупно протекло време -Show secrets on map,AUTOMAPMNU_MAPSECRETS,,,,Zobrazit tajemství na mapě,Zeige Geheimnisse auf der Karte,,Montri sekretojn mape,Mostrar secretos en el mapa,,Näytä salat kartalla,Afficher secrets sur carte,,Mostra i segreti nella mappa,シークレットを地図に表示,맵의 비밀을 표시,Toon geheimen op de kaart,Pokaż sekrety na mapie,Mostrar segredos no mapa,,Afișare secrete,Тайники на карте,Прикажи тајне на аутомапи -Show map label,AUTOMAPMNU_SHOWMAPLABEL,,,,Zobrazit kód mapy,Zeige Levelnamen,,Montri mapetikedon,Mostrar etiqueta del mapa,,Näytä tason tunniste,Afficher label de carte,,Mostra le etichette della mappa,マップ名 表示,맵의 이름 표시,Toon kaartlabel,Pokaż etykietę mapy,Mostrar etiqueta do mapa,,Afișare etichetă hartă,Название карты,Прикажи ознаку мапе -Draw map background,AUTOMAPMNU_DRAWMAPBACK,,,,Vykreslovat pozadí mapy,Zeige Kartenhintergrund,,Desegni mapfondon,Dibujar fondo de mapa,,Piirrä tason tausta,Afficher fond d'écran carte,,Mostra lo sfondo della mappa,マップの背景 描写,맵의 배경 출력,Teken de achtergrond van de kaart,Rysuj tło mapy,Desenhar fundo do mapa,,Afișare fundal hartă,Отображать фон автокарты,Нацртај позадину мапе -Show keys (cheat),AUTOMAPMNU_SHOWKEYS,,,,Zobrazovat klíče (cheat),Zeige Schlüssel (Cheat),,Montri klavojn (trompo),Mostrar llaves (truco),,Näytä avaimet (huijauskeino),Afficher les clés (cheat),,Mostra le chiavi (cheat),鍵 表示(チート時),키를 표시 (치트),Toon sleutels (valsspeler),Pokaż klucze (oszustwo),Mostrar chaves (trapaça),,Afișare chei (trișare),Отображать ключи (только чит),Прикажи кључеве (чит) -Show trigger lines,AUTOMAPMNU_SHOWTRIGGERLINES,,,,Zobrazovat aktivující čáry,Zeige Auslöserlinien,,Montri baskulliniojn,Mostrar líneas de activación,,Näytä laukaisinviivat,Afficher lignes d'action,,Mostra le linee d'attivazione,トリガーライン 表示,트리거 선을 표시,Triggerlijnen tonen,Pokaż linie przełączników,Mostrar linhas de ativação,,Afișare linii declanșatoare,Отображать триггеры,Прикажи триггер линије -Show things as sprites,AUTOMAPMNU_SHOWTHINGSPRITES,,,,Zobrazit objekty jako sprity,Zeige Dinge als Sprites,,Montri aĵojn kiel spritoj,Mostrar cosas como sprites,,Näytä oliot spriteinä,Afficher objets comme sprites,,Mostra gli oggetti come sprite,thingsのスプライト表示,물체를 스프라이트로 표시,Toon dingen als sprites,Pokaż rzeczy jako sprite'y,Mostrar objetos como sprites,,Afișare obiecte drept sprite,Отображать спрайты предметов,Прикажи ствари као спрајтове -Overlay portals,AUTOMAPMNU_PTOVERLAY,,,,Překrývat portály,Überlagere Portale,,Surmeti portalojn,Sobreponer portales,,Projisoi portaalit,Superposer les portails,,Sovrapponi i portali,オーバーレイ ポータルズ,포탈을 오버레이,Overlappende portalen,Nałóż portale,Sobreposição de portais,,Acoperire portaluri,Порталы в прозрачном режиме,Провидни портали -Empty space margin,AUTOMAPMNU_EMPTYSPACEMARGIN,,,,Práh prázdného prostoru,Breite des Randes,,Malplene spacia marĝeno,Margen de Espacio Vacío,,Tyhjän reunan leveys,Marge d'espace vide,,Margine dello spazio vuoto,空間の余白,빈공간 여백,Breedte van de rand,Opróżnij margines przestrzeni,Margem de espaço vazio,,Margine spațiu gol,Край автокарты,Празна маргина -Mark font,AUTOMAPMNU_MARKFONT,,,,Font značek,Zeichensatz für Markierungen,,Marki tiparon,Fuente para Marcas,,Karttamerkkien fontti,Police Marqueur,,Font del segnaposto,マークフォント,미니맵 마킹 폰트,Font voor markers,Czcionka oznaczeń,Fonte das marcações,,Font marcaj,Шрифт отметок,Фонт ознака -Mark color,AUTOMAPMNU_MARKCOLOR,,,,Barva značek,Farbe für Markierungen,,Marki koloron,Color de las Marcas,,Karttamerkkien väri,Couleur Marqueur,,Colore del segnaposto,マーク色,미니맵 마킹 색상,Markeer kleur,Kolor oznaczeń,Cor das marcações,,Culoare marcaj,Цвет отметок,Боја ознака -Customize Map Controls,MAPCNTRLMNU_TITLE,,,,Nastavení ovládání mapy,Automapsteuerung einstellen,,Agordi mapregilojn,Controles del mapa,,Kartanohjausasetukset,Contrôles Carte,,Personalizza i controlli mappa,マップコントロール カスタマイズ,미니맵 단축키 설정,Kaartcontroles aanpassen,Ustaw klawisze mapy,Configurar comandos de mapa,,Personalizare schemă de control a hărții,Клавиши управления автокартой,Промени контроле мапе -Map Controls,MAPCNTRLMNU_CONTROLS,,,,Ovládání mapy,Automapsteuerung,,Mapregilojn,Controles del mapa,,Kartanohjaus,Contrôles de la carte,,Controlli mappa,マップコントロール,미니맵 조정,Kaartcontroles,Klawisze mapy,Comandos de mapa,,Schemă de control a hărtii,Автокарта,Контроле мапе -Pan left,MAPCNTRLMNU_PANLEFT,,,,Posun vlevo,Nach links,,Alturni maldekstren,Mover a la izquierda,,Panoroi vasemmalle,Aller à gauche,,Sposta a sinistra,左に振る,왼쪽으로 이동,Pan links,Przesuń w lewo,Mover para a esquerda,,Mutare spre stânga,Сдвиг влево,Лево -Pan right,MAPCNTRLMNU_PANRIGHT,,,,Posun vpravo,Nach rechts,,Alturni dekstren,Mover a la derecha,,Panoroi oikealle,Aller à droite,,Sposta a destra,右に振る,오른쪽으로 이동,Pan rechts,Przesuń w prawo,Mover para a direita,,Mutare spre dreapta,Сдвиг вправо,Десно -Pan up,MAPCNTRLMNU_PANUP,,,,Posun nahoru,Nach oben,,Alturni supren,Mover hacia arriba,,Panoroi ylös,Aller en haut,,Sposta sopra,上に振る,위쪽으로 이동,Pan omhoog,Przesuń w górę,Mover para cima,,Mutare în sus,Сдвиг вверх,Горе -Pan down,MAPCNTRLMNU_PANDOWN,,,,Posun dolů,Nach unten,,Alturni malsupren,Mover hacia abajo,,Panoroi alas,Aller en bas,,Sposta sotto,下に振る,아래쪽으로 이동,Pan neer,Przesuń w dół,Mover para baixo,,Mutare în jos,Сдвиг вниз,Доле -Zoom in,MAPCNTRLMNU_ZOOMIN,,,,Přiblížit,Reinzoomen,,Zomi,Acercar,,Lähennä,Zoom avant,,Ingrandisci,ズームイン,줌 확대,Inzoomen,Przybliż,Ampliar,,Apropriere Cameră,Увеличить масштаб,Увеличати -Zoom out,MAPCNTRLMNU_ZOOMOUT,,,,Oddálit,Rauszoomen,,Malzomi,Alejar,,Loitonna,Zoom arrière,,Rimpicciolisci,ズームアウト,줌 축소,Uitzoomen,Oddal,Diminuir,,Depărtare Cameră,Уменьшить масштаб,Одзумирати -Toggle zoom,MAPCNTRLMNU_TOGGLEZOOM,,,,Zoom vyp./zap.,Zoom an/aus,,Inversigi zomon,Alternar zoom,,Zoomauksen vaihtokytkin,Alterner zoom,,Abilita/disabilita zoom,ズーム切替,표준배율 조정,Omschakelen van de zoom,Przełącz przybliżanie,Ativar zoom,,Comutator Zoom,Переключить зум,Укључи зум -Toggle follow,MAPCNTRLMNU_TOGGLEFOLLOW,,,,Následování hráče vyp./zap.,Folgen an/aus,,Aktivigi sekvon,Alternar seguimiento,,Seuraamistilan vaihtokytkin,Alterner suivi,,Abilita/disabilita scorrimento mappa,追従切替,추적모드 조정,Schakelen volgen,Przełącz śledzenie,Ativar seguimento,,Comutator urmărire jucător,Переключить привязку к игроку,Укључи праћење -Toggle grid,MAPCNTRLMNU_TOGGLEGRID,,,,Mřížka vyp./zap.,Gitter an/aus,,Aktivigi kradon,Alternar cuadrícula,Alternar rejilla,Ruudukon vaihtokytkin,Alterner grille,,Abilita/disabilita la griglia,グリッド切替,그리드 조정,Kiesnet,Przełącz siatkę,Ativar grade,,Comutator grilă,Переключить сетку,Укључи координатну мрежу -Toggle texture,MAPCNTRLMNU_TOGGLETEXTURE,,,,Textury vyp./zap.,Texturen an/aus,,Akitvigi teksturon,Alternar textura,,Pintakuvioinnin vaihtokytkin,Alterner texture,,Abilita/disabilita le texture,テクスチャ切替,미니맵 텍스쳐 조정,Toggle textuur,Przełącz tekstury,Ativar texturas,,Comutator mod texturat,Переключить текстуры,Укључи текстуру -Set mark,MAPCNTRLMNU_SETMARK,,,,Umístit značku,Setze Markierung,,Meti markon,Fijar marca,,Aseta merkki,Placer repère,,Aggiungi segnaposto,マークを置く,마크 추가,Markering instellen,Ustaw znacznik,Posicionar marcação,,Marcare,Поставить отметку,Постави ознаку -Clear mark,MAPCNTRLMNU_CLEARMARK,,,,Vyčistit značky,Lösche Markierung,,Forviŝi markon,Limpiar marca,,Pyyhi merkit,Enlever repères,,Pulisci il segnaposto,マーククリア,마크 삭제,Duidelijke markering,Usuń znacznik,Limpar marcação,,Ștergere marcaj,Убрать отметку,Уклони ознаку -Customize Map Colors,MAPCOLORMNU_TITLE,,,Customize Map Colours,Nastavení barev mapy,Automapfarben einstellen,,Agordi mapkolorojn,Personalizar colores (mapa),,Värien mukautus,Couleurs Carte Personnalisées,,Personalizza i colori della mappa,カスタム色を決める,미니맵 색상 설정,Kaartkleuren aanpassen,Ustaw kolory mapy,Configurar cores de mapa,,Personalizare culori hartă,Настройки цветов автокарты,Промени боју мапе -Restore default custom colors,MAPCOLORMNU_DEFAULTMAPCOLORS,,,Restore default custom colours,Obnovit původní vlastní barvy,Standardfarben wiederherstellen,,"Restaŭri defaŭltajn, laŭmendajn kolorojn",Restaurar colores personalizados,,Palauta oletusvärit,Couleurs par défaut,,Reimposta i colori personalizzati al default,カスタム色を初期化,기본 색상으로 복구,Standaard aangepaste kleuren herstellen,Przywróć domyślne kolory,Restaurar cores padrão,,Revenire la culorile implicite,Вернуть стандартные цвета,Врати уобичајене разне боје -Background,MAPCOLORMNU_BACKCOLOR,,,,Pozadí,Hintergrund,,Fono,Fondo,,Tausta,Fond,,Sfondo,背景,배경,Achtergrond,Tło,Fundo,,Fundal,Фон,Позадина -You,MAPCOLORMNU_YOURCOLOR,,,,Ty,Du,,Vi,Tú,,Sinä,Votre couleur,,Tu,自分,당신,,Ty,Você,Tu,Tu,Игрок,Ти -1-sided walls,MAPCOLORMNU_WALLCOLOR,,,,Jednostranné zdi,Einseitige Wände,,1-lateraj muroj,Paredes de 1 lado,,Yksipuoliset seinät,Murs à 1 côté,,Muri unilaterali,壁,단면 벽들,1-zijdige wanden,Jednostronne ściany,Paredes de 1 lado,,Pereți cu o singură față,Односторонние стены,Једнострани зид -2-sided walls with different floors,MAPCOLORMNU_FDWALLCOLOR,,,,Oboustranné zdi s různými podlahami,Zweiseitige Wände mit unterschiedlicher Bodenhöhe,,2-lateraj muroj kun malsamaj plankoj,Paredes de 2 lados con pisos distintos,,Kaksipuoliset seinät eroavilla lattiakorkeuksilla,Murs à 2 côtés avec différents sols,,Muri bilaterali con pavimenti diversi,高低差のある床,다른 층 추가된 양면 벽들,2-zijdige wanden met verschillende vloeren,Dwustronne ściany z innymi piętrami,Paredes de 2 lados com pisos diferentes,,Pereți cu două fețe si podele diferite,Двусторонние стены,Двострани зид са различитим нивоима -2-sided walls with different ceilings,MAPCOLORMNU_CDWALLCOLOR,,,,Oboustranné zdi s různými stropy,Zweiseitige Wände mit unterschiedlicher Deckenhöhe,,2-lateraj muroj kun malasamaj plafonoj,Paredes de 2 lados con techos distintos,,Kaksipuoliset seinät eroavilla kattokorkeuksilla,Murs à 2 côtés avec différents plafonds,,Muri bilaterali con soffitti diversi,高低差のある天井,다른 천장 추가된 양면 벽들,2-zijdige wanden met verschillende plafonds,Dwustronne ściany z innymi sufitami,Paredes de 2 lados com tetos diferentes,,Pereți cu două fețe si tavane diferite,Двусторонние стены с разными потолками,Двострани зид са различитим плафонима -2-sided walls with 3D floors,MAPCOLORMNU_EFWALLCOLOR,,,,Oboustranné zdi s 3D podlahami,Zweiseitige Wände mit 3D-Ebenen,,2-lateraj muroj kun 3D-plankoj,Paredes de 2 lados con suelos 3D,,Kaksipuoliset seinät kolmiulotteisilla lattioilla,Murs à 2 côtés avec sols 3d,,Muri bilaterali con 3D floor,多重床,3D 층 추가된 양면 벽들,2-zijdige wanden met 3D-vloeren,Dwustronne ściany z piętrami 3D,Paredes de 2 lados com pisos 3D,,Pereți cu două fețe si podele 3D,Двусторонние стены с разными полами,Двострани зид са 3D нивоима -Map grid,MAPCOLORMNU_GRIDCOLOR,,,,Mřížka,Kartengitter,,Mapkrado,Cuadrícula del mapa,Rejilla del mapa,Kartan ruudukko,Quadrillage,,Griglia mappa,マップグリッド,맵 격자,Kaart raster,Siatka mapy,Grade do mapa,Grelha do mapa,Grilă hartă,Цвет сетки,Мапа координатне мреже -Center point,MAPCOLORMNU_XHAIRCOLOR,,,Centre point,Středobod,Mittelpunkt,,Centra punkto,Punto central,,Keskipiste,Point Central,,Punto centrale,中心点,중간 지점,Middenpunt,Środek,Ponto central,,Punct în centru,Курсор,Централна тачка -Not-yet-seen walls,MAPCOLORMNU_NOTSEENCOLOR,,,,Neobjevené zdi,Ungesehene Wände,,Nevidintaj-muroj,Paredes sin ver,,Tutkimattomat seinät,Murs non découvers,,Muri ancora da scoprire,未見の壁,안 본 벽들,Nog niet zichtbare wanden,Jeszcze niewidziane ściany,Paredes não vistas até o momento,,Ziduri încă neobservate,Необнаруженные стены,Неоткривени зидови -Locked doors,MAPCOLORMNU_LOCKEDCOLOR,,,,Zamčené dveře,Verschlossene Türen,,Ŝlositaj muroj,Puertas bloqueadas,,Lukitut ovet,Portes verouillées,,Porte bloccate,鍵の掛かったドア,잠긴 문들,Gesloten deuren,Zablokowane drzwi,Portas trancadas,,Uși închise,Запертые двери,Закључана врата -Teleporter to the same map,MAPCOLORMNU_INTRALEVELCOLOR,,,,Teleportér,Teleporter,,Teleportilo al la sama mapo,Telepuerto al mismo mapa,,Kaukosiirrin samaan tasoon,Téléporteurs (même niveau),,Teletrasporto nella stessa mappa,テレポーター,같은 맵에 텔레포터 추가,Teleporter naar dezelfde niveau,Teleporter do tej samej mapy,Teletransportador para o mesmo mapa,,Teleportor către aceeași hartă,Телепорт в пределах уровня,Телепортер до истог нивоа -Teleporter to a different map,MAPCOLORMNU_INTERLEVELCOLOR,,,,Teleportér do jiného levelu,Teleporter in ein anderes Level,,Teleportilo al alia mapo,Telepuerto a un mapa diferente,,Kaukosiirrin eri tasoon,Téléporteurs (autre niveau),,Teletrasporto in una mappa diversa,別マップへのテレポーター,다른 맵에 텔레포터 추가,Teleporter naar een andere niveau,Teleporter do innej mapy,Teletransportador para outro mapa,,Teleportor către altă hartă,Телепорт на другой уровень,Телепортер до различитог нивоа -Secret sector,MAPCOLORMNU_SECRETSECTORCOLOR,,,,Tajný sektor,Geheimer Sektor,,Sekreta sektoro,Sector secreto,,Salasektori,Secteur Secret,,Settore segreto,シークレット,비밀 섹터,Geheime sector,Sekretny sektor,Setor secreto,,Sector secret,Тайный сектор,Тајни сектор -Unexplored secret,MAPCOLORMNU_UNEXPLOREDSECRETCOLOR,,,,Neobjevená tajemství,nicht gefundener geheimer Sektor,,Neesplorita sekreto,Sector secreto inexplorado,,Tutkimaton sala,Secret non révélé,,Segreto non esplorato,未知のシークレット,발견하지 않은 비밀,Onontgonnen geheim,Niezbadany sekret,Segredo não-explorado,,Secret neexplorat,Необнаруженный тайник,Ноткривена тајна -Special trigger lines,MAPCOLORMNU_SPECIALWALLCOLOR,,,,Akční čáry,Spezielle Linien,,Specialaj aktivigo-linioj,Líneas especiales de activación,,Erikoislaukaisinviivat,Lignes d'actions spéciales,,Linee di attivazione speciali,特殊トリガー,특수 트리거 선,Speciale trekkerlijnen,Specjalne linie przełączników,Linhas de ativação especiais,,Linii declașatoare speciale,Специальные триггер-линии,Специјалне линије окидача -Cheat Mode,MAPCOLORMNU_CHEATMODE,,,,Cheatovací režim,Cheat-Modus,,Tromp-reĝimo,Modo de truco,,Huijaustila,Mode Cheat,,Modalità cheat,チートモード時,치트 모드,Bedriegingsmodus,Tryb oszustwa,Modo Trapaça,Modo de Batota,Modul Trișor,Чит-режим,Чит мод -Invisible 2-sided walls,MAPCOLORMNU_TSWALLCOLOR,,,,Neviditelné oboustranné zdi,Unsichtbare zweiseitige Wände,,Nevideblaj 2-lateraj muroj,Paredes de 2 lados Invisibles,,Näkymättömät kaksipuoliset seinät,Murs à 2 côtés invisibles,,Muri invisibili bilaterali,表示されないline,투명한 양면 벽,Onzichtbare 2-zijdige wanden,Niewidzialne dwustronne ściany,Paredes invisíveis de 2 lados,,Pereți cu două fețe invizibili,Невидимые двусторонние стены,Невидљиви двострани зидови -Secret walls,MAPCOLORMNU_SECRETWALLCOLOR,,,,Tajné zdi,Geheime Wände,,Sekretaj muroj,Paredes secretas,,Salaiset seinät,Murs Secrets,,Muri segreti,シークレットの壁,비밀 벽,Geheime muren,Sekretne ściany,Paredes secretas,,Pereți ascunși,Тайные стены,Тајни зидови -Actors,MAPCOLORMNU_THINGCOLOR,,,,Objekty,Akteure,,Aktoroj,Actores,,Oliot,Acteurs,,Attori,アクター,개체,Acteurs,Aktorzy,Atores,,Actori,Акторы,Актори -Monsters,MAPCOLORMNU_MONSTERCOLOR,,,,Příšery,Monster,,Monstroj,Monstruos,,Hirviöt,Monstres,,Mostri,モンスター,적들,Monsters,Potwory,Monstros,,Monștri,Монстры,Чудовишта -Non-counting Monsters,MAPCOLORMNU_NONCOUNTINGMONSTERCOLOR,,,,Nepočítané příšery,nicht gezählte Monster,,Nenombrotaj Monstroj,Monstruos no contados,Monstruos sin contar,Ei-laskettavat hirviöt,Monstres non comptés,,Mostri non contati,非カウントモンスター,킬수에 포함 되지 않는 적들,Niet-tellende Monsters,Niezliczane Potwory,Monstros Não Contados,,Monștri neacoperiți de numărătoare,Неучитываемые монстры,Не рачунајући чудовишта -Friends,MAPCOLORMNU_FRIENDCOLOR,,,,Přátelé,Freunde,,Amikoj,Amigos,,Omat,Amis,,Amici,仲間,친구들,Vrienden,Przyjaciele,Amigos,,Prieteni,Дружественные,Пријатељи -Items,MAPCOLORMNU_ITEMCOLOR,,,,Předměty,Gegenstände,,Aĵoj,Objetos,,Esineet,Objets,,Oggetti,アイテム,아이템들,Artikelen,Przedmioty,Itens,,Obiecte,Предметы,Предмети -Count Items,MAPCOLORMNU_COUNTITEMCOLOR,,,,Počítané předměty,gezählte Gegenstände,,Nombri aĵojn,Objetos contados,Conteo de objetos,Laske esineet,Objets comptés,,Oggetti contati,カウント対象アイテム,아이템 계산,Tellen,Zlicz przedmioty,Itens Contados,,Numără obiectele,Учитываемые предметы,Рачунајући предмети -Overlay Mode,MAPCOLORMNU_OVERLAY,,,,Překryvný režim,Überlagerungsmodus,,Surmeto-reĝimo,Modo sobrepuesto,,Projisointitila,Mode surimpression,,Modalità sovrapposizione,オーバーレイモード,오버레이 모드,Overlaadmodus,Tryb Nakładki,Modo de Sobreposição,,Mod acoperit,Прозрачный режим,Провидна аутомапа -Overlay Cheat Mode,MAPCOLORMNU_OVCHEATMODE,,,,Překryvný cheatovací režim,Überlagerungsmodus Cheats,,Surmeto-tromp-reĝimo,Sobreposición modo de truco,,Projisointihuijaustila,Mode Cheat Surimpression,,Modalità cheat sovrapposizione,オーバーレイ チートモード,치트 모드 오버레이,Overlaadmodus Cheats,Tryb Nakładki Oszustwa,Modo Trapaça de Sobreposição,Modo Batota de Sobreposição,Mod acoperit trișor,Прозрачный чит-режим,Провидни читови -Portal Overlays,MAPCOLORMNU_PORTAL,,,,Portálové překryvy,Portalüberlagerung,,Portalo-surmetoj,Sobreposición de portal,,Portaaliprojisoinnit,Portails superposés,,Sovrapposizioni del portale,ポータル オーバーレイ,포탈 오버레이,Portaaloverlays,Nakładanie się Portali,Sobreposição de portais,,Acoperiri portaluri,Порталы в прозрачном режиме,Провидни портали -Messages,MSGMNU_TITLE,,,,Zprávy,Nachrichten,,Mesaĝoj,Mensajes,,Viestit,,,Messaggi,メッセージ類,메시지들,Berichten,Wiadomości,Mensagens,,Mesaje,Сообщения,Поруке -Show messages,MSGMNU_SHOWMESSAGES,,,,Zobrazit zprávy,Zeige Nachrichten,,Montri mesaĝojn,Mostrar Mensajes,,Näytä viestit,Afficher messages,,Mostra messaggi,メッセージ表示,메시지 표시,Berichten tonen,Pokaż wiadomości,Mostrar mensagens,,Afișare mesaje,Отображение сообщений,Прикажи поруке -Show obituaries,MSGMNU_SHOWOBITUARIES,,,,Zobrazit zprávy o smrtích,Zeige Todesanzeigen,,Montri nekrologojn,Mostrar obituarios,,Näytä kuolinviestit,Afficher avis de décès,,Mostra i necrologi,訃報表示,사망 메시지 표시,Doodsbrieven tonen,Pokaż nekrologi,Mostrar obituários,,Afișare necrologuri,Отображение некрологов,Прикажи читуље -Show secret notifications,MSGMNU_SHOWSECRETS,,,,Zobrazit upozornění na tajemství,Zeige Geheimnismeldung,,Montri sekretajn sciigojn,Mostrar notificación de secretos,,Ilmoita salojen löytymisestä,Afficher secrets,,Mostra le notifiche dei segreti,シークレット発見表示,비밀 알림 표시,Geheime meldingen tonen,Pokaż wiadomości znalezienia sekretu,Mostrar notificação de segredos,,Afișare notificări pentru secrete,Отображение сообщений о тайниках,Прикажи тајне нотификације -Minimum message level,MSGMNU_MESSAGELEVEL,,,,Minimální úroveň zpráv,Min. Nachrichtenanzeigestufe,,Minimuma nivelo de mesaĝoj,Nivel mínimo de mensaje,,Pienin viestintätaso,Niveau de message minimum,,Numero di messaggi minimo,最小メッセージレベル,메시지 축소량,Minimaal berichtenniveau,Poziom minimalnych wiadomości,Nível mínimo de mensagem,,Nivel minim de afișare mesaje,Минимальный уровень сообщений,Минимум левел порука -Center messages,MSGMNU_CENTERMESSAGES,,,Centre messages,Vycentrovat zprávy,Nachrichten zentrieren,,Centrigi mesaĝoj,Centrar mensajes,,Keskitä viestit,Messages centrés,,Messaggi centrati,メッセージを中央に,메시지 중간에 위치,Berichten centreren,Wyśrodkuj wiadomości,Centralizar mensagens,Centrar mensagens,Mesaje centrate,Центрирование сообщений,Централне поруке -Message Colors,MSGMNU_MESSAGECOLORS,,,Message Colours,Barva zpráv,Nachrichtenfarben,,Mesaĝkoloroj,Colores de los Mensajes,,Viestien värit,Couleur des messages,,Colore dei messaggi,メッセージ色,메시지 색상,Bericht Kleuren,Kolory Wiadomości,Cores de Mensagem,,Culori Mesaje,Цвета сообщений,Боје порука -Item Pickup,MSGMNU_ITEMPICKUP,,,,Sebrání předmětu,Genommene Gegenstände,,Aĵprenado,Toma de objetos,,Esineen poimiminen,Objets ramassés,,Raccolta oggetti,アイテム取得,아이템 획득,Puntafhaling,Podniesienie Przedmiotu,Coleta de Item,Aquisição de Itens,Ridicare obiecte,Подбор предмета,Покупити предмет -Obituaries,MSGMNU_OBITUARIES,,,,Zprávy o úmrtí,Todesanzeigen,,Nekrologoj,Obituarios,,Kuolinviestit,Avis de décès,,Necrologi,死亡時メッセージ,사망 메시지,Doodsbrieven,Nekrologi,Obituários,,Necrologuri,Некрологи,Читуље -Critical Messages,MSGMNU_CRITICALMESSAGES,,,,Kritické zprávy,Kritische Nachrichten,,Gravegaj Mesaĝoj,Mensajes críticos,,Tärkeät viestit,Messages d'erreur,,Messaggi critici,致命的なメッセージ,중요한 메시지,Kritische berichten,Wiadomości krytyczne,Mensagens Críticas,,Mesaje Critice,Важные сообщения,Критичне поруке -Chat Messages,MSGMNU_CHATMESSAGES,,,,Chatové zprávy,Chatnachrichten,,Babilmesaĝoj,Mensajes de chat,,Keskusteluviestit,Message de Chat,,Messaggi chat,チャットメッセージ,채팅 메시지,Chatberichten,Wiadomości czatu,Mensagens de Chat,,Mesaje Conversație,Сообщения в чате,Ћаскања -Team Messages,MSGMNU_TEAMMESSAGES,,,,Týmové zprávy,Teamnachrichten,,Teammesaĝoj,Mensajes de equipo,,Joukkueen viestit,Messages d'équipe,,Messaggi chat di squadra,チームメッセージ,팀 채팅 메시지,Team Berichten,Wiadomości czatu drużynowego,Mensagens de Equipe,Mensagens de Equipa,Mesajele Echipei Proprii,Командные сообщения в чате,Тимске поруке -Centered Messages,MSGMNU_CENTEREDMESSAGES,,,Centred Messages,Vycentrované zprávy,Zentrierte Nachrichten,,Centra Mesaĝoj,Mensajes centrados,,Keskitetyt viestit,Messages centrés,,Messaggi centrati,スクリプトメッセージ,중간에 위치한 메시지,Gecentreerde berichten,Wyśrodkowane wiadomości,Mensagens Centralizadas,Mensagens Centradas,Mesaje Centrate,Центрированные сообщения,Централне поруке -Screenshot messages,MSGMNU_SCREENSHOTMESSAGES,,,,Zprávy o snímcích obrazovky,Screnshot-Meldungen,,Mesaĝojn de ekrankopiado,Mensajes de captura de pantalla,,Kuvakaappausviestit,Messages de capture d'écran,,Messaggi di cattura schermo,スクショメッセージ,스크린샷 메시지,Screenshot berichten,Wiadomości o zrobieniu zrzutu ekranu,Mensagens de captura de tela,Mensagen de captura de ecrã,Mesaje Capturi Ecran,Сообщения о скриншотах,Скриншот поруке -Detailed save messages,MSGMNU_LONGSAVEMESSAGES,,,,Detailní zprávy o uložené hře,Detaillierte Speicher-Meldungen,,Detalaj konservmesaĝoj,Mensajes detallados de guardado,,Yksityiskohtaiset tallennusviestit,Messages de sauvegarde détailés,,Messaggi sui dettagli di salvataggio,詳細なセーブメッセージ,자세한 저장 메시지,Gedetailleerde berichten voor op te slaan,Szczegółowe wiadomości o zapisie,Mensagens detalhadas de salvamento,Mensagens detalhadas de gravação,Mesaje detaliate pentru salvări,Подробные сообщения о сохранениях,Детаљно сачуване поруке -Developer message mode,MSGMNU_DEVELOPER,,,,Vývojářský režim zpráv,Entwickler-Modus,,Reĝimo de mesaĝoj por programistoj,Modo de mensajes de desarrollador,,Pelinkehittäjäviestitila,Mode de Développement,,Modalità messaggi per sviluppatore,開発者用モード,개발자 메시지 모드,Berichtenmodus voor ontwikkelaars,Tryb wiadomości deweloperskich,Modo de mensagens de desenvolvedor,,Mod mesaje pentru dezvoltator,Режим сообщений для разработчиков,Поруке девелопера -Scoreboard Options,SCRBRDMNU_TITLE,,,,Nastavení tabulky skóre,Punktetabellenoptionen,,Poenttabulo-agordoj,Opciones de marcador,,Pistetauluasetukset,Tableau des Scores,,Opzioni per la tabella punteggio,スコアボード オプション,점수판 설정,Scorebord opties,Opcje Tablicy Wyników,Opções de Tela de Pontuação,Opções do Ecrã de Pontuação,Setări Tabelă de Marcaj,Настройки таблицы очков,Подешавања бодовања -Cooperative Options,SCRBRDMNU_COOPERATIVE,,,,Nastavení co-op módu,Kooperativ-Optionen,,Kooperativagrodoj,Opciones de cooperativo,,Yhteispeliasetukset,Options Mode Coop,,Opzioni per il gioco cooperativo,協力モード オプション,코옵 설정,Coöperatieve Opties,Opcje Kooperacji,Opções de Jogo Cooperativo,,Setări Mod Cooperativ,Настройки для команд,Подешавања сарадње -Enable Scoreboard,SCRBRDMNU_ENABLE,,,,Povolit tabulku skóre,Punktetabelle aktiv,,Aktivigi poenttabulon,Activar marcador,,Ota käyttöön pistetaulu,Activer Tableau des Scores,,Abilita la tabella punteggio,スコアボード表示,점수판 허용,Scorebord inschakelen,Zezwól na Tablicę Wyników,Habilitar Tela de Pontuação,Permitir Ecrã de Pontuação,Activare Tabelă de Marcaj,Включить таблицу очков,Омогући бодовање -Header Color,SCRBRDMNU_HEADERCOLOR,,,Header Colour,Barva hlavičky,Kopfzeilenfarbe,,Tutilkoloro,Color de cabecera,,Otsikon väri,Couleur du Titre,,Colore della testata,ヘッダー色,헤더의 색깔,Kleur koptekst,Kolor Nagłówka,Cor de Cabeçalho,,Culoare Antet,Цвет заголовка,Боја заглавља -Your Player Color,SCRBRDMNU_YOURCOLOR,,,Your Player Colour,Barva tvého hráče,Deine Spielerfarbe,,Via ludantkoloro,Color de tu jugador,,Pelaajasi väri,Votre couleur,,Colore del giocatore 'Tu',自分の色,플레이어의 색깔,Uw Spelerskleur,Twoje Kolory,Cor do Seu Jogador,Cor do teu Jogador,Culoarea Jucătorului Tău,Ваш цвет,Боја твога играча -Other Players' Color,SCRBRDMNU_OTHERPLAYERCOLOR,,,Other Players' Colour,Barva ostatních hráčů,Andere Spielerfarbe,,Koloro de aliaj ludantoj,Color de otros jugadores,,Muiden pelaajien väri,Couleur des autres joueurs,,Colore degli altri giocatori,他者の色,다른 플레이어들의 색깔,Andere spelerskleur,Kolory Innych Graczy,Cor de Outros Jogadores,Cor dos Outros Jogadores,Culorile Celorlalți Jucători,Цвет других игроков,Боја другог играча -Deathmatch Options,SCRBRDMNU_DEATHMATCH,,,,Nastavení deathmatche,Deathmatch-Optionen,,Mortmatĉagordoj,Opciones modo a muerte,,Kuolonotteluasetukset,Options Deathmatch,,Opzioni deathmatch,デスマッチの設定,데스매치 설정,Deathmatch opties,Opcje Deathmatchu,Opções de Deathmatch,,Setări Deathmatch,Настройки Deathmatch,Детмеч подешавања -Team Deathmatch Options,SCRBRDMNU_TEAMDEATHMATCH,,,,Nastavení týmového deathmatche,Team-Deathmatch-Optionen,,Teammortmatĉagordoj,Opciones modo a muerte por equipos,,Joukkuekuolonotteluasetukset,Options Deathmatch en équipe,,Opzioni deathmatch a squadra,チームデスマッチの設定,팀 데스매치 설정,Team Deathmatch Opties,Opcje Drużynowego Deathmatchu,Opções de Deathmatch de Equipe,Opções de Deathmatch de Equipa,Setări Deathmatch în Echipă,Настройки командного Deathmatch,Тимски детмеч подешавања -Gameplay Options,GMPLYMNU_TITLE,,,,Nastavení herních mechanik,Gameplay-Optionen,,Ludadagordoj,Opciones de jugabilidad,,Pelattavuusasetukset,Options Gameplay,,Opzioni gameplay,ゲームプレイ オプション,게임플레이 설정,Gameplay-opties,Opcje Rozgrywki,Opções de Jogabilidade,,Setări de Joc,Настройки геймплея,Подешавања гејмплеја -Teamplay,GMPLYMNU_TEAMPLAY,,,,Týmová hra,Teamspiel,,Teamludado,Juego por equipos,,Joukkuepeli,Jeu en équipe,,Gioco di squadra,チーム制,팀플레이,Teamplay,Gra Drużynowa,Jogo em Equipe,Jogo em Equipa,Joc în Echipă,Командный режим,Тимска игра -Team damage scalar,GMPLYMNU_TEAMDAMAGE,,,,Faktor týmového poškození,Team-Schadenfaktor,,Teamdamaĝo-skalio,Escalar de daño del equipo,,Omien tulen vahinkokerroin,Facteur de Tir Fratricide,,Fattore danno da fuoco amico,チームメンバーへのダメージ倍率,팀 데미지 배율,Teamschade scalair,Skalar Obrażeń Drużyny,Escala de fogo amigo,,Multiplicator daune,Множитель урона по своим,Мултипликатор пријатељске ватре -Smart Autoaim,GMPLYMNU_SMARTAUTOAIM,,,,Chytré automatické zaměřování,Intelligene Zielautomatik,,Lerta Aŭtomate-celi,Autoapuntado inteligente,,Älykäs automaattitähtäys,Autovisée intelligente,,Mira automatica intelligente,スマートオートエイム,정확한 자동 조준,Slimme Autoaim,Mądre Autocelowanie,Mira Automática Inteligente,,Asistare inteligentă la țintire,Умное автоприцеливание,Паметни нишан -Falling damage,GMPLYMNU_FALLINGDAMAGE,,,,Zranění pádem,Fallschaden,,Faldamaĝo,Daño por caída,,Putoamisvahinko,Dommages de chute,,Danno da caduta,落下ダメージ,낙하 데미지,Vallende schade,Obrażenia przy upadku,Dano de queda,,Daune la căderi libere,Урон от падения,Штета од пада -Drop weapon,GMPLYMNU_DROPWEAPON,,,,Odhazování zbraní,Waffen fallen lassen,,Faligi armilon,Arrojar arma,,Aseen pudottaminen,Arme lâchée à la mort,,"Arma lasciata cadere -",死亡時に武器を落とす,무기 버리기,Laat het wapen vallen,Wyrzuć broń,Largar arma,,Aruncare armă,Сохранять оружие после смерти,Баци оружје -Double ammo,GMPLYMNU_DOUBLEAMMO,,,,Dvojnásobná munice,Doppelte Munition,,Duomumicio,Doble munición,,Tupla-ammukset,Double munitions,,Doppie munizioni,弾2倍,두 배의 탄약,Dubbele munitie,Podwojona amunicja,Munição em dobro,,Muniție dublă,Удвоенные патроны,Дупла муниција -Infinite ammo,GMPLYMNU_INFINITEAMMO,,,,Nekonečná munice,Unendlich Munition,,Infinitmunivio,Munición infinita,,Loppumattomat ammukset,Munitions infinies,,Infinite munizioni,弾無限,무한 탄약,Oneindige munitie,Nieskończona amunicja,Munição infinita,,Muniție infinită,Бесконечные патроны,Бесконачна муниција -Infinite inventory,GMPLYMNU_INFINITEINVENTORY,,,,Nekonečný inventář,Unendliche Gegenstände,,Infinitinventorio,Inventario infinito,,Loppumattomat varusteet,Objets infinis,,Infinito inventario,所持品無限,무한 인벤토리,Oneindige voorraad,Nieskończony ekwipunek,Inventário infinito,,Inventar infinit,Бесконечный инвентарь,Бесконачно складиштење -No monsters,GMPLYMNU_NOMONSTERS,,,,Bez příšer,Keine Monster,,Neniu monstroj,Sin monstruos,,Ei hirviöitä,Pas de monstres,,Nessun mostro,モンスターを出現させない,적 제거,Geen monsters,Brak potworów,Sem monstros,,Fără monștri,Без монстров,Без чудовишта -No monsters to exit,GMPLYMNU_NOMONSTERSTOEXIT,,,,Ukončení levelu pouze bez příšer,Keine Monster um Level zu beenden,,Neniu monstroj por eliri,Sin monstruos para salir,,Ei hirviöitä tason lopettamiseksi,Rien à tuer pour sortir,,Nessun mostro da uccidere per uscire,モンスター全滅までMAPから脱出不可,탈출을 위한 적 제거,Geen monsters om af te sluiten,Brak potworów do wyjścia,Sem monstros para sair da fase,Sem monstros para sair do nível,Fără monștri pentru a putea ieși,Убить всех монстров для выхода,Без чудовишта до излаза -Monsters respawn,GMPLYMNU_MONSTERSRESPAWN,,,,Příšery se respawnují,Monster kehren zurück,,Monstrojn reaperiĝi,Reaparecer enemigos,,Hirviöt heräävät henkiin,Monstres réapparaissent,,Respawn mostri,モンスターの自力復活,적 부활,Monsters respawn,Ponowne pojawianie się potworów,Monstros reaparecem,,Monștrii reapar,Монстры воскрешаются,Чудовишта се оживљавају -No respawn,GMPLYMNU_NORESPAWN,,,,Příšery se nerespawnují,Kein Zurückkehren,,Neniu reaperiĝo,Sin reaparición,,Ei henkiinheräämistä,Pas de réapparition,,Nessun respawn,プレイヤーの復活禁止,부활 없음,Geen respawn,Brak ponownego pojawienia się,Sem reaparecimentos,,Fără reapariții,Отключить воскрешение,Без оживљавања -Items respawn,GMPLYMNU_ITEMSRESPAWN,,,,Předměty se respawnují,Gegenstände erscheinen wieder,,Aĵojn reaperiĝi,Reaparecer objetos,,Esineet syntyvät takaisin,Objets réapparaissent,,Respawn oggetti,アイテムを復活,아이템 재생성,Items respawn,Ponowne pojawianie się przedmiotów,Itens reaparecem,,Obiectele reapar,Восстановление предметов,Предмети се ресетују -Big powerups respawn,GMPLYMNU_SUPERRESPAWN,,,,Bonusy se respawnují,Große Boni erscheinen wieder,,Grandaj fortegaĵoj reaperiĝi,Reaparecer poderes grandes,,Isot tehostimet syntyvät takaisin,Powerups réapparaissent,,Respawn grandi potenziamenti,強力なパワーアップアイテムを復活,파워업 재생성,Grote power-ups respawn,Ponowne pojawianie się dużych wzmocnień,Powerups reaparecem,,Super bonusurile reapar,Восстановление супер-бонусов,Велики предмети се ресетују -Fast monsters,GMPLYMNU_FASTMONSTERS,,,,Rychlé příšery,Schnelle Monster,,Rapidaj monstroj,Monstruos rápidos,,Nopeat hirviöt,Monstres Rapides,,Mostri veloci,モンスター高速化,빠른 적 개체 움직임,Snelle monsters,Szybkie potwory,Monstros rápidos,,Monștri rapizi,Ускоренные монстры,Брза чудовишта -Degeneration,GMPLYMNU_DEGENERATION,,,,Degenerace,,,Malregeneri,Degeneración,,Rappeutuva terveys,Dégéneration,,Degrado della salute,プレイヤーの自動体力減少,약화,Degeneratie,Degeneracja,Degeneração,,Degenerare,Уменьшать дополнительное здоровье,Смањење додатног здравља -Allow Autoaim,GMPLYMNU_NOAUTOAIM,,,,Povolit automatické míření,Zielautomatik zulassen,,Permesi Aŭtomate-celon,Permitir Autoapuntar,,Salli automaattitähtäys,Autoriser Auto-visée,,Mira automatica consentita,オートエイム有効化,자동 조준 허용,Autoaim toestaan,Pozwól na Autocelowanie,Permitir Mira Automática,,Permite asistența pentru țintire,Разрешить автоприцеливание,Дозволи аутоматско циљање -Allow Suicide,GMPLYMNU_ALLOWSUICIDE,,,,Povolit sebevraždu,Selbstmord zulassen,,Permesi Memmorti,Permitir Suicidio,,Salli itsemurha,Autoriser Suicide,,Suicidio consentito,自殺コマンド有効化,자살 허용,Zelfmoord toestaan,Pozwól na Samobójstwo,Permitir suicídio,,Permite sinuciderile,Разрешить суицид,Дозволи самоубиство -Allow jump,GMPLYMNU_ALLOWJUMP,,,,Povolit skákání,Springen zulassen,,Permesi salti,Permitir salto,,Salli hyppiminen,Autoriser Sauts,,Salto consentito,ジャンプ有効化,점프 허용,Springen toestaan,Pozwól na skakanie,Permitir pulo,Permitir salto,Permite săriturile,Прыжки,Дозволи скок -Allow crouch,GMPLYMNU_ALLOWCROUCH,,,,Povolit klečení,Ducken zulassen,,Permesi kaŭri,Permitir agacharse,,Salli kyyristyminen,Autoriser Acroupissement,,Abbassamento consentito,しゃがみ有効化,앉기 허용,Hurken toestaan,Pozwól na kucanie,Permitir agachamento,,Permite ghemuirile,Приседание,Дозволи чучање -Allow freelook,GMPLYMNU_ALLOWFREELOOK,,,,Povolit koukání nahoru/dolů,Freien Blick zulassen,,Permesi liberregardon,Permitir visión libre,,Salli vapaa katselu,Autoriser Vue Libre,,Sguardo libero consentito,フリールック有効化,프리룩 허용,Freelook toestaan,Pozwól na swobodne rozglądanie się,Permitir vista livre,,Permite privirea în jur cu mouse-ul,Обзор мышью,Дозволи слободан поглед -Allow FOV,GMPLYMNU_ALLOWFOV,,,,Povolit změnu FOV,Blickwinkeländerung zulassen,,Permesi FOV-on,Permitir FOV,,Salli näkökentän muokkaaminen,Autoriser Angles de vue,,Campo visivo consentito,FOVの調整を有効化,FOV 허용,Laat FOV,Pozwól na Pole Widzenia,Permitir ângulo de visão,,Permite ajustarea câmpului vizual,Разрешить изменение FOV,Дозволи FOV -Allow BFG aiming,GMPLYMNU_BFGFREEAIM,,,,Povolit míření s BFG,Zielen mit BFG zulassen,,Permesi ekceladon de BFG,Permitir apuntado de BFG,,Salli BFG-tähtäys,Autoriser Visée au BFG,,Mira BFG consentita,BFG使用時のフリールックを有効化,BFG 조준 허용,Laat BFG toe om te streven naar,Pozwól na celowanie BFG,Permitir mira de BFG,,Permite țintirea cu BFG,Разрешить прицеливание с BFG,Дозволи BFG нишање -Allow automap,GMPLYMNU_ALLOWAUTOMAP,,,,Povolit automapu,Automap zulassen,,Permesi aŭtomapon,Permitir automapa,,Salli automaattikartta,Autoriser Carte,,Automap consentito,オートマップ有効化,오토맵 허용,Automap toestaan,Pozwól na mapę,Permitir automapa,,Permite utilizarea hărții computerizate,Разрешить использование автокарты,Дозволи мапу -Automap allies,GMPLYMNU_AUTOMAPALLIES,,,,Zobrazit na automapě spojence,Verbündete zulassen,,Permesi aliancanojn,Aliados en el automapa,,Omat automaattikartalla,Alliés sur la carte,,Alleati nell'automap,オートマップに味方を表示,오토맵에 아군 표시,Automap bondgenoten,Sojusznicy na mapie,Permitir aliados no automapa,,Aliați pe harta computerizată,Показывать союзников на автокарте,Савезници на аутомапи -Allow spying,GMPLYMNU_ALLOWSPYING,,,,Povolit špehování,Spionieren zulassen,,Permesi spionadon,Permitir espiar,,Salli vakoileminen,Autoriser espionnage,,Spionaggio consentita,死亡時の他プレイヤー観戦を許可,관전 허용,Laat spionage toe,Pozwól na śledzenie,Permitir visualização de outros jogadores,,Permite vederea prin ochii altor jucători,Разрешить вид от других игроков,Дозволи поглед од другог играча -Chasecam cheat,GMPLYMNU_CHASECAM,,,,Povolit kameru z třetí osoby (cheat),Verfolgerkamera Cheat,,Ĉaskameratrumpo,Truco de vista 3era persona,,Seurantakamerahuijaus,Cheat caméra 3ième personne,,Cheat camera di inseguimento,チェイスカメラチート有効化,3인칭 카메라 치트,Chasecam cheat,Oszustwo kamrey śledzenia,Trapaça de câmera em terceira pessoa,Batota de câmera em terceira pessoa,Trișare pentru vedere la persoana a 3-a,Разрешить вид от 3-го лица,Дозволи чејс-кем -Check ammo for weapon switch,GMPLYMNU_DONTCHECKAMMO,,,,Přepnout na zbraň pouze s municí,Munition beim Waffenwechsel prüfen,,Kontroli municion por armŝanĝi,Revisar munición para cambiar armas,,Tarkista ammustilanne aseenvaihdon yhteydessä,Vérifier muni. pour changer arme,,Controlla le munizioni per il cambio arma,武器切替時に弾の有無を確認,탄약 소진 시 무기 변경,Controleer munitie op wapenschakelaars.,Sprawdź amunicję przy sprawdzaniu broni,Conferir munição para troca de arma,,Verifică muniția armei pentru schimbare,Проверять патроны при переключении оружия,Проверити муницију за прекидач за оружје -Icon's death kills its spawns,GMPLYMNU_KILLBOSSSPAWNS,,,,Smrt Ikony zabije i její potomky,,,La morto de Icon motrigas siajn idojn,La muerte del icono destruye sus lacayos,La muerte del ícono destruye sus lacayos,Ikonin kuolema tappaa myös siitä siinneet hirviöt,Tuer L'Icône tue ses monstres,,La morte dell'Icona uccide tutti i suoi figli,最終ボスを殺した際に召喚モンスターも殺す,보스 사망시 소환된 적들도 사망,Icon's dood doodt zijn spawns,Śmierć Ikony zabija stworzone przez nią potwory,Morte do Ícone mata as suas crias,Morte do Ícone mata os seus demónios,Decesul Idolului anihilează propriile creații,Убить порождения Иконы при её смерти,Смрт Икона греха убија његова потомства -End sector counts for kill %,GMPLYMNU_NOCOUNTENDMONSTER,,,,Započítávat monstra v ukončujících sektorech,Monster in Level-Beenden-Sektor zählen,,Finsektoro estas la samo kiel morto %,Sector de salida cuenta para % de muertes,,Loppusektori lasketaan mukaan tappoprosenttiin,Ennemis du secteur sortie comptés,,Conteggio dei nemici da uccidere nel settore in %,最終セクターの敵もキルに含む,레벨종료 섹터의 적들도 킬 수에 포함,Eindsector telt voor kill %,"Zliczanie potworów w sektorze kończącym poziom -",Setor de saída conta para porcentagem de mortes,Setor de saída conta para percentagem de mortes,Numărare decese monștri în sectoare finale,Засчитывать убийства монстров в конечных секторах,Урачунај убиство чудовишта у коначним секторима -Deathmatch Settings,GMPLYMNU_DEATHMATCH,,,,Nastavení deathmatche,Deathmatcheinstellungen,,Mortmatĉagordoj,Configuración modo a muerte,,Kuolonotteluasetukset,Options Deathmatch,,Impostazioni deathmatch,デスマッチの設定,데스매치 설정,Deathmatch instellingen,Ustawienia Deathmatchu,Configurações de Deathmatch,,Setări Deathmatch,Настройки deathmatch,Детмеч подешавања -Weapons stay,GMPLYMNU_WEAPONSSTAY,,,,Zbraně zůstávají,Waffen bleiben,,Armilojn restiĝi,Las armas se quedan,,Aseet pysyvät,Armes restent au sol quand prises,,Le armi rimangono in posizione,武器を取得時も残す,습득 후 무기가 남아있기,Wapenverblijven,Bronie zostają,Armas permanecem,,Părăsire arme după selectare,Оставлять оружие после подбора,Оружје се остаје након купљења -Allow powerups,GMPLYMNU_ALLOWPOWERUPS,,,,Povolit bonusy,Boni erlauben,,Permesi fortegecojn,Permitir poderes,,Salli tehostimet,Autoriser powerups,,Potenziamenti consentiti,パワーアップアイテムを出現させる,파워 업 허용,Power-ups toestaan,Pozwól na wzmocnienia,Permitir powerups,,Permite bonusuri,Разрешить бонусы,Дозволи бонусе -Allow health,GMPLYMNU_ALLOWHEALTH,,,,Povolit zdraví,Gesundheit erlauben,,Permesi sanon,Permitir salud,,Salli terveysesineet,Autoriser objets santé,,Oggetti per la salute consentiti,回復アイテムを出現させる,체력 회복 아이템 허용,Gezondheid toestaan,Pozwól na przedmioty zdrowotne,Permitir itens de saúde,,Permite prim-ajutor,Разрешить бонусы к здоровью,Дозволи бонусе за здравље -Allow armor,GMPLYMNU_ALLOWARMOR,,,Allow armour,Povolit brnění,Panzer erlauben,,Permesi kirason,Permitir armadura,,Salli panssariesineet,Autoriser objets armure,,Armature consentite,アーマーを出現させる,아머 허용,Pantsertoeslag toestaan,Pozwól na pancerz,Permitir itens de armadura,,Permite bonusuri de armură,Разрешить броню,Дозволи оклоп -Spawn farthest,GMPLYMNU_SPAWNFARTHEST,,,,Hráčí se spawnují co nejdále od sebe,Am weitesten entfernten Punkt erscheinen,,Reaperi pli fora,Aparecer más lejos,,Herää henkiin kauimpaa,Apparaître au plus loin,,Spawn il più lontano possibile,他のプレイヤーから最遠の場所に復活,먼 곳에서 소환,Kuitschieten het verst verwijderd,Pojaw się jak najdalej,Aparecer mais longe,,Apariție cât mai departată de ceilalți,Воскрешение подальше от остальных,Оживљавање даље од других -Same map,GMPLYMNU_SAMEMAP,,,,Stejná mapa,Gleiches Level,,Sama mapo,Mismo mapa,,Sama taso,Même Carte,,Stessa mappa,同じMAPを繰り返す,같은 맵 플레이,Dezelfde kaart,Ta sama mapa,Mesmo mapa,,Reluare nivel,Зациклить уровень,Понављање нивоа -Force respawn,GMPLYMNU_FORCERESPAWN,,,,Vynutit respawn,Zurückkehren erzwingen,,Devigi reaperon,Forzar reaparición,,Pakota henkiinherääminen,Forcer Réapparition,,Forza il respawn,死亡後に強制復活,강제 부활,Respawn is gedwongen,Wymuś ponowne pojawienie się,Forçar reaparecimento,,Reapariție instantă,Моментальное воскрешение,Форсирано оживљавање -Allow exit,GMPLYMNU_ALLOWEXIT,,,,Povolit ukončení levelu,Verlassen erlauben,,Permesi eliri,Permitir salir,,Salli tasosta poistuminen,Autoriser Sortie,,Uscita consentita,出口の使用を許可,탈출 허용,Uitgang toestaan,Pozwól na wyjście,Permitir saída,,Permite ieșirea,Разрешить выход,Дозволи излазак из нивоа -Barrels respawn,GMPLYMNU_BARRELSRESPAWN,,,,Barely se respawnují,Fässer kehren zurück,,Bareloj reaperi,Reaparecer Barriles,,Tynnyrit syntyvät takaisin,Réapparition des Tonneaux,,Respawn barili esplosivi,爆発バレルを復活させる,폭발통 재생성,Vaten respawn,Beczki pojawiają się ponownie,Barrís reaparecem,,Butoaiele reapar,Восстановление бочек,Бурад се ресетују -Respawn protection,GMPLYMNU_RESPAWNPROTECTION,,,,Ochrana po respawnu,Schutzboni kehen zurück,,Reaperprotekto,Reaparecer protección,,Henkiinheräämissuoja,Protection à la réapparition,,Protezione al respawn,復活したばかりのプレイヤーを保護,부활시 무적,Respawn bescherming,Ochrona przy ponownym pojawieniu się,Proteção de reaparecimento,,Protecție la apariția pe hartă,Кратковременная защита после воскрешения,Ресетује се заштита -Lose frag if fragged,GMPLYMNU_LOSEFRAG,,,,Ztratit frag pokud zabit,Fragabzug bei Tod,,Perdi fragmentigon se fragmentiga,Perder baja al morir,,"Frägin menettäminen, jos joutuu frägätyksi",Perdre 1 frag quand tué,,Perdere i frag se fraggato,キルされた場合は得点を失う,적에게 사망시 점수를 잃음,Verlies frag bij dood,Strać fraga jeśli jesteś sfragowany,Perder frag ao ser fragado,,Pierdere din victime la deces,Терять фраг при смерти,Изгубити гранату ако опаљена -Keep frags gained,GMPLYMNU_KEEPFRAGS,,,,Ponechávání fragů mezi levely,Frags zwischen Leveln behalten,,Teni gajnitajn fragmentigojn,Mantener bajas ganadas,,Pidä ansaitut frägit,Garder les frags gagnés,,Mantenere i frag vinti,MAP変更後も得点を保持する,맵 변경 시 점수 유지,Houd frags opgedaan,Zachowaj zdobyte fragi,Manter frags ganhos,,Păstrare număr victime,Сохранять фраги между уровнями,Задржати стечене гранате -No team switching,GMPLYMNU_NOTEAMSWITCH,,,,Uzamknout týmy,Kein Teamwechsel,,Neniu teamŝanĝado,No cambiar equipos,,Ei joukkueenvaihtoa,Pas de changement d'équipe,,Nessun cambio di squadra,チーム変更を禁止,팀 변경 없음,Geen teamwisseling,Zakaz zmieniania drużyn,Desativar troca de time,Desativar troca de equipa,Nu permite schimbarea echipelor,Запретить переход между командами,Нема мешања тимова -Cooperative Settings,GMPLYMNU_COOPERATIVE,,,,Nastavení co-op módu,Kooperativ-Einstellungen,,Agordoj de Koopera Reĝimo,Configuración de cooperativo,,Yhteispeliasetukset,Options Coopératives,,Impostazioni cooperativa,協力プレイの設定,협동 플레이 설정,Coöperatieve instellingen,Ustawienia Kooperacji,Configurações de Jogo Cooperativo,,Setări cooperative,Настройки совместного режима,Кооперативне поставке -Spawn multi. weapons,GMPLYMNU_MULTIPLAYERWEAPONS,,,,Spawnovat multiplayerově zbraně,Deathmartch Waffen sind verfügbar,,Aperigi armilojn por plurdanta reĝimo,Aparecer armas multi.,,Kuolonotteluaseet saatavilla,Spawns d'armes deathmatch,,Spawn armi multiplayer,マルチプレイ用の武器を出現させる,멀티플레이어 무기 소환,Spawn multi. wapens,Zezwól na bronie trybu dla wielu graczy,Aparecimento de armas multiplayer,,Permite apariția armelor din modul online,Появление оружия из мультиплеера,Створити мулти оружја -Lose entire inventory,GMPLYMNU_LOSEINVENTORY,,,,Ztrácet celý inventář,Verliere ganzes Inventar,,Perdi tutan inventorion,Perder todo el inventario,,Menetä kaikki varusteet,Perdre l'inventaire,,Perdere l'inventario,死亡時に全ての所持品を失う,인벤토리 비우기,Verlies van de volledige inventaris,Utrać cały ekwipunek,Perder todo o inventário,,Pierdere inventar,Терять весь инвентарь при смерти,Изгубити цело складиште -Keep keys,GMPLYMNU_KEEPKEYS,,,,Ponechat klíče,Schlüssel behalten,,Teni ŝlosiojn,Mantener llaves,,Pidä avaimet,Garder clés,,Mantenere le chiavi,死亡後もキーを保持する,열쇠들을 소지하고 시작,Sleutels bewaren,Zachowaj klucze,Manter chaves,,Păstrare chei,Сохранять ключи,Задржати кључеве -Keep weapons,GMPLYMNU_KEEPWEAPONS,,,,Ponechat zbraně,Waffen behalten,,Teni armilojn,Mantener armas,,Pidä aseet,Garder armes,,Mantenere le armi,死亡後も武器を保持する,무기들을 소지하고 시작,Wapens bewaren,Zachowaj bronie,Manter armas,,Păstrare arme,Сохранять оружие,Задржати оружје -Keep armor,GMPLYMNU_KEEPARMOR,,,Keep armour,Ponechat brnění,Rüstung behalten,,Teni kirason,Mantener armadura,,Pidä panssari,Garder armure,,Mantenere l'armatura,死亡後もアーマーを保持する,아머를 소지하고 시작,Pantser bewaren,Zachowaj pancerz,Manter armadura,,Păstrare armură,Сохранять броню,Задржати панцир -Keep powerups,GMPLYMNU_KEEPPOWERUPS,,,,Ponechat bonusy,Behalte Boni,,Teni fortegecojn,Mantener poderes,,Pidä tehostimet,Garder powerups,,Mantenere i potenziamenti,死亡後もパワーアップを保持する,파워업을 소지하고 시작,Power-ups bewaren,Zachowaj wzmocnienia,Manter powerups,,Păstrare bonusuri,Сохранять супер-бонусы,Задржати повећану моћ -Keep ammo,GMPLYMNU_KEEPAMMO,,,,Ponechat munici,Munition behalten,,Teni municion,Mantener munición,,Pidä ammukset,Garder munitions,,Mantenere le ammunizioni,死亡後も弾薬を保持する,탄약을 소지하고 시작,Munitie bewaren,Zachowaj amunicję,Manter munição,,Păstrare armură,Сохранять патроны,Задржати муницију -Lose half ammo,GMPLYMNU_LOSEHALFAMMO,,,,Ztratit polovinu munice,Halbe Munition verlieren,,Perdi duonon da viaj municioj,Perder la mitad de la munición,,Menetä puolet ammuksista,Perdre la moité des munitions,,Perdere metà ammunizioni,死亡時に弾を半分失う,탄약의 반을 잃음,Verlies halve munitie,Utrać pół amunicji,Perder metade da munição,,Pierdere jumătate din armură,Терять половину патронов,Изгубити пола муниције -Spawn where died,GMPLYMNU_SPAWNWHEREDIED,,,,Respawn na místě smrti,Neuerscheinen wo gestorben,,Reaperi kie mortigis,Aparecer donde moriste,,Herää henkiin kuolinpaikalla,Réapparaitre sur lieu de mort,,Respawn nel luogo di morte,死亡したその場で復活,죽은 곳에서 소환,Kuit waar gestorven is,Pojaw się znów tam gdzie zginąłeś,Aparecer no local de morte,Reaparecer onde morreu,Apariție la locul decesului,Воскрешение на месте смерти,Оживљавање на месту смрти -Compatibility Options,CMPTMNU_TITLE,,,,Nastavení kompatibility,Kompatibilitätsoptionen,,Kongru-agrodoj,Opciones de compatibilidad,,Yhteensopivuusasetukset,Options Compatibilité,,Opzioni compatibilità,互換性 オプション,호환성 설정,Compatibiliteitsopties,Opcje Zgodności,Opções de Compatibilidade,,Setări de Compatibilitate,Настройки совместимости,Компатибилна подешавања -Compatibility mode,CMPTMNU_MODE,,,,Režim kompatibility,Kompatibilitätsmodus,,Kongru-reĝimo,Modo de Compatibilidad,,Yhteensopivuustila,Mode de compatibilité,,Modalità compatibilità,互換性モード,호환 모드,Compatibiliteitsmodus,Tryb Zgodności,Modo de compatibilidade,,Mod Compatibilitate,Режим совместимости,Компатибилни мод -Actor Behavior,CMPTMNU_ACTORBEHAVIOR,,,Actor Behaviour,Chování objektů,Verhalten der Akteure,,Aktorkonduto,Comportamiento del actor,,Olioiden käyttäytyminen,Comportement des Acteurs,,Comportamento degli attori,アクターの挙動,개체 관련 설정,Gedrag van de acteur,Zachowanie Aktorów,Comportamento de Atores,,Comportament actori,Поведение акторов,Понашање актора -Crushed monsters can be resurrected,CMPTMNU_CORPSEGIBS,,,,Rozmáčklé příšery mohou být oživeny,Zermalmte Monster können wiederbelebt werden,,Pistitaj monstroj povas reviviĝi,Los monstruos aplastados pueden resucitar,,Murskatut hirviöt voidaan herättää henkiin,Monstres écrasés résucitables,,I mostri schiacciati possono essere resuscitati,潰れた敵が復活可能,으깨진 개체는 부활 불가,Verpletterde monsters kunnen herrezen worden,Zmiażdżone potwory mogą być wskrzeszone,Monstros esmagados podem ser ressucitados,,Monștrii striviți pot fi înviați,Раздавленные монстры могут быть воскрешены,Згњечена чудовишта могу ускрснути -Friendly monsters aren't blocked,CMPTMNU_NOBLOCKFRIENDS,,,,Spojenecké příšery nejsou blokovány,Freundliche Monster werden nicht geblockt,,Amikaj monstroj ne estas baritaj,Monstruos amistosos no son bloqueados,,Myötämielisten hirviöiden esteetön liikkuminen,Monstres amicaux non bloqués,,I mostri amichevoli non sono bloccati,フレンドリーキャラはモンスターブロックラインの影響を受けない,아군 개체는 BLOCK 선분 무시,Vriendelijke monsters worden niet geblokkeerd.,Przyjazne potwory nie mogą być blokowane,Monstros aliados não são bloqueados,,Monștrii aliați nu pot fi blocați,Не блокировать дружественных монстров,Пријатељска чудовишта се не блокирају -Limit Pain Elementals' Lost Souls,CMPTMNU_LIMITPAIN,,,,Omezit počet Elementálových Ztracených duší,Limit für Verlorene Seelen,,Limigi Perditanimojn de Dolorelementoj,Limitar almas perdidas de los elementales del dolor,,Rajoita kivun henkien kadonneitten sielujen määrää,Limiter âmes des élémentaires,,Limita le Anime Erranti degli Elementali del dolore,ペインエレメンタルのロストソウル制限,로스트 소울 소환 21개로 제한,Beperk de Verloren Zielen van Pijn Elementairs,Ogranicz Zagubione Dusze Elementala Bólu,Limitar Almas Penadas de Elementais da Dor,,Limitează numărul Sufletelor Pierdute create de Elementalii Durerii,Ограничить число потерянных душ из элементалей боли,Ограничи изгубљене душе од елементала патње -Monster movement is affected by effects,CMPTMNU_MBFMONSTERMOVE,,,,Pohyb příšer je ovlivněn efekty,Monsterbewegung wird von Effekten beeinflusst,,Monstrmovoj estas afektita per efektoj,Los efectos afectan al movimiento de los monstruos,,Tehosteet vaikuttavat hirviöiden liikkumiseen,Mouvement monstre affecté par effets,,Il movimento dei mostri è affetto dagli effetti,敵の移動が床の影響を受ける,구역의 이동 효과가 개체들에 영향,Monsterbeweging wordt beïnvloed door effecten,Efekty wpływają na ruch potworów,Movimento dos monstros é afetado por efeitos,,Efectele afectează deplasarea monștrilor,Эффекты влияют на движение монстров,Ефекти утицају на покретљивост чудовишта -Monsters cannot cross dropoffs,CMPTMNU_CROSSDROPOFF,,,,Příšery nemohou překročit výšiny,Monster können Abbruchkanten nicht überqueren,,Monstroj ne povas movi trans krutejojn,Los monstruos no pueden cruzar declives,,Hirviöt eivät voi ylittää pudotuksia,Monstres ne passent pas les corniches,,I mostri non posso attraversare gli spigoli,敵はdropoffを横切れない,개체들이 난간에서 추락 불가,Monsters kunnen geen dropoffs kruisen,Potwory nie mogą przekraczać spadków,Monstros não podem atravessar penhascos,,Monștrii nu pot trece peste prăpăstii,Монстрам нельзя пересекать уступы,Чудовишта не могу прећи падове -Monsters get stuck over dropoffs,CMPTMNU_DROPOFF,,,,Příšery se zasekávají na výšinách,Monster bleiben auf Abbruchkanten hängen,,Monstroj ĉesiĝi super kretejoj,Los monstruos se atrapan sobre declives,Los monstruos se atoran sobre declives,Hirviöt joutuvat jumiin pudotusten ylle,Monstres bloqués par les corniches,,I mostri rimangono bloccati sugli spigoli,敵がdropoffにスタックする,개체들이 난간에 끼일 수 있음,Monsters komen vast te zitten boven dropoffs,Potwory mogą utknąć nad spadkami,Monstros ficam presos em penhascos,,Monștrii înțepenesc peste prăpăstii,Монстры застревают на уступах,Чудовишта се заглављују на падовима -Monsters see invisible players,CMPTMNU_INVISIBILITY,,,,Příšery vidí neviditelné hráče,Monster können unsichtbare Spieler sehen,,Monstroj povas vidi invisiblajn ludantojn,Los monstruos ven jugadores invisibles,,Hirviöt näkevät näkymättömät pelaajat,Monstres voient joueurs invisibles,,I mostri vedono i giocatori invisibili,敵が透明を見破る,개체들이 투명 플레이어 감지 가능,Monsters zien onzichtbare spelers,Potwory widzą niewidzialnych graczy,Monstros enxergam jogadores invisíveis,,Monștrii pot vedea jucătorii invizibili,Монстры видят невидимых игроков,Чудовишта могу да виде невидљиве играче -No Minotaur floor flames in water,CMPTMNU_MINOTAUR,,,,Mínotauři nemohou tvořit plameny ve vodě,Keine Minotaurus-Flammen im Wasser,,Neniuj plankfajroj de Mintaŭroj en akvo,Sin llamas de minotauro en el agua,,Ei minotaurien lattialiekkejä vedessä,Pas de feu de Massetaur sur l'eau,,Niente fiamme da terra del Minotauro sull'acqua,ミノタウロスの攻撃が水を通過しない,수면에서는 몰로타우어 지면화염 차단,Geen Minotaurus vloer vlammen in water,Brak płomieni Minotaura w wodzie,Desativar fogo do Minotauro na água,,Minotaurii nu pot folosi atacul de foc pe apă,Минотавры не создают огонь в воде,Минотаури не пале ватру у води -Spawn item drops on the floor,CMPTMNU_NOTOSSDROPS,,,,Spadlé předměty se objeví na zemi,Gegenstände erscheinen auf dem Fußboden,,Aperigi malprenitajn aĵojn sur la plankon,Aparecer objetos dejados en el suelo,,Synnytä esinepudotukset lattialle,Objets lâchés direct au sol,,Gli oggetti allo spawn cadono a terra,アイテムドロップが床に出る,아이템이 떨어질때 지면에 즉시 착지,Paaipunt druppels op de vloer,Obiekty pojawiają się na podłodze,Itens aparecidos caem direto no chão,,Obiectele scăpate vor apărea la nivelul podelei,Выброшенные предметы создаются на земле,Одбачени предмети се појављују на поду -DehackEd Behavior,CMPTMNU_DEHACKEDBEHAVIOR,,,DehackEd Behaviour,Chování DeHackEd,DehackEd Verhalten,,DehackEd Konduto,Comportamiento de DehackEd,,DehackEd-käyttäytyminen,Comportement DeHackEd,,Comportamento DehackEd,Dehackedの挙動,DehackEd 관련 설정,DehackEd Gedrag,Zachowanie DehackEd,Comportamento DehackEd,,Comportament DehackEd,Поведение DeHackEd,DehackEd понашање -DEH health settings like Doom2.exe,CMPTMNU_DEHHEALTH,,,,Nastavení DEH jako v Doom2.exe,DEH Gesundheitseinstellungen wie in Doom2.exe,,DEH sanagordoj kiel Doom2.exe,Configuración de salud DEH como en Doom2.exe,,DEH-terveysasetukset kuin Doom2.exessä,Para. santé DEH comme Doom2.EXE,,Impostazioni di salute DEH come in Doom2.exe,Doom2.exe式の Dehヘルス設定,DEH 자체의 체력 최댓값 사용,DEH-gezondheidsinstellingen zoals Doom2.exe,Ustawienia zrowia DEH jak w Doom2.exe,Configurações de saúde DEH como em Doom2.exe,,Setări sănătate în DEH precum în Doom2.exe,Настройки здоровья DEH как в Doom2.exe,DEH подешавања здравља као у Doom2.exe -Original A_Mushroom speed in DEH mods,CMPTMNU_MUSHROOM,,,,Původní rychlost pro A_Mushroom,Originale Berechnung für A_Mushroom,,Originala A_Mushroom rapideco en DEH-modifaĵoj,Velocidad original de A_Mushroom en mods con DEH,,Alkuperäinen A_Mushroom-nopeus DEH-modeissa,Vitesse A_Mushroom originale pour DEH,,Velocità originale di A_Mushroom nei mod DEH,Deh Modでの元の A_Mushroom速度,A_Mushroom효과가 MBF 원본의 속력 사용,Originele A_Mushroom in DEH-modellen,Oryginalna prędkość A_Mushroom w modach DEH,Velocidade original do A_Mushroom em mods DEH,,Folosește viteza originală pentru A_Mushroom în DEH în moduri,Оригинальная скорость A_Mushroom в модах DEH,Оригинална брзина A_Mushroom в DEH модовима -Map/Action Behavior,CMPTMNU_MAPACTIONBEHAVIOR,,,Map/Action Behaviour,Chování levelů a aktivací,Level/Aktionsverhalten,,Map/Ago-Konduto,Comportamiento Mapa/Acción,,Tason/Toimintojen käyttäytyminen,Comportement Niveau/Actions,,Comportamento Mappa/Azioni,マップ/アクション の挙動,맵/동작 관련 설정,Kaart/Actiegedrag,Zachowanie Mapy/Akcji,Comportamento Mapa/Ação,,Comportament hartă/actori,Поведение уровней/действий,Понашање нивоа/догађаја -All special lines can block ,CMPTMNU_USEBLOCKING,,,,Veškeré akční čáry blokují použití hráčem,Alle Speziallinien blockieren Benutzung,,Ĉiuj el specialaj linioj povas bari -on,Todas las líneas especiales pueden bloquear ,,Kaikki erikoisviivat voivat tukkia -toiminnon,Toute ligne d'action bloque ,,Tutte le linee speciali possono bloccare il comando ,全てのSpecial Linesがをブロック,특정 선상에 겹쳐있을 시 <사용> 무력화,Alle speciale lijnen kunnen blokkeren.,Wszystkie specjalne linie mogą blokować ,Todas as linhas especiais podem bloquear o comando ,,Toate liniile speciale pot bloca ,Все специальные линии могут блокировать ,Све специјалне линије могу да блокирају -Allow any bossdeath for level special,CMPTMNU_ANYBOSSDEATH,,,,Smrt jakéhokoli bosse může aktivovat speciální akci levelu,Jeder Boss-Tod zählt für Spezialaktionen,,Permesi iun ajn estro-morton por nivelspecialo,Permitir cualquier muerte de jefe por especial de nivel,,Mikä tahansa pomokuolema lasketaan tason erikoistoiminnossa,N'importe quel boss active actions boss,,"Qualunque morte del boss per le azioni speciali consentita -",いずれのBossdeathでも level specialを許可,어느 레벨에서든 BOSSDEATH 이벤트 허용,Laat een eventuele bossdood voor een speciaal niveau toe....,Każda śmierć bossa liczy się jako akcja specjalna,Permitir qualquer morte de chefão para ação especial,Permitir qualquer morte de chefe para ação especial,Orice utilizare de A_BossDeath activează evenimente speciale în nivel,Любой случай A_BossDeath активирует special на уровне,Било који случај A_BossDeath активира special на нивоу -Disable BOOM door light effect,CMPTMNU_NODOORLIGHT,,,,Zakázat světelný efekt dveří z BOOMu,Boom-Türlichteffekt deaktiviert.,,Malaktivigi pordlumo-efekto de BOOM,Desactivar efecto de luz de puerta de BOOM,,BOOM-ovivalotehoste pois käytöstä,Pas d'effet de lumière BOOM sur portes,,Disabilitato l'effetto BOOM della luce della porta,BOOMドアライト エフェクトを無効化,붐 문간 조명보정 효과 끄기,BOOM-deurlichteffect uitschakelen,Wyłącz efekt oświetlenia drzwi BOOM,Desabilitar efeito de luz de porta do BOOM,,Dezactivează efectele de lumină BOOM pentru uși,Отключить световой эффект на дверях из BOOM,Онемогући светлосни ефекат из BOOM-а на вратима -Find neighboring light like Doom,CMPTMNU_LIGHT,,,Find neighbouring light like Doom,Nacházet nejbližší světlo jako Doom,Finde benachbartes Licht wie in Doom,,Trovi najbaran lumon kiel Doom,Encontrar luces vecinas como en Doom,,Etsi vierustava valo niin kuin Doom,Trouver prochaine texture comme DOOM,,Trova le luci vicine come in Doom,DOOM式の最寄りライト検知,고전적인 조명추적 사용,Vind naburig licht zoals Doom,Znajdź sąsiadujące światło jak w Doomie,Encontrar luz vizinha como em Doom,,Caută o sursă de lumină apropriată ca în Doom,Искать соседний источник света как в Doom,Нађи суседно светло као у Doom-у -Find shortest textures like Doom,CMPTMNU_SHORTTEX,,,,Nacházet nejkratší textury jako Doom,Finde kurze Texturen wie in Doom,,Trovi la plej mallongajn tekstaĵojn kiel Doom,Encontrar texturas más cortas como en Doom,,Etsi lyhyimmät pintakuvioinnit niin kuin Doom,Trouver plus petite texture comme Doom,,Trova le texture più piccole come in Doom,DOOM式の最短テクスチャー検知,고전적인 텍스처분류 사용,Vind de kortste texturen zoals Doom,Znajdź najkrótsze tekstury jak w Doomie,Encontrar menores texturas como em Doom,,Caută cele mai scurte texturi ca în Doom,Искать кратчайшие текстуры как в Doom,Нађи најкраће текстуре као у Doom-у -Use buggier stair building,CMPTMNU_STAIRS,,,,Použít méně stabilní stavění schodů,Benutze fehlerhafte Treppenbaufunktion,,Uzi pli ciman ŝtupo-konstruadon,Usar construcción defectuosa de escaleras,,Käytä viallisempaa portaanrakennusfunktiota,Construction d'escalier plus buggée,,Usa la struttura a scalinate più buggata,バグった階段生成を使用,구형 계단상승 효과 사용,Gebruik buggier trapgebouw,Użyj wadliwej funkcji budowania schodów,Usar construção defeituosa de escadas,,Utilizare mod de ridicare al scărilor incorect,Использовать неисправленное построение лестниц,Користи непоправљено грађење степеница -Use Doom's floor motion behavior,CMPTMNU_FLOORMOVE,,,Use Doom's floor motion behaviour,Použít původní chování Doomu pro pohyb podlah,Benutze Dooms Verhalten für bewegende Böden,,Uzi konduton de Doom por plankmovo-konduto,Usar comportamiento de mov. del suelo de Doom,,Lattialiike käyttäytyy kuin Doomissa,Mouvement des sols à la DOOM,,Adotta il comportamento di Doom per il movimento sul pavimento,DOOMでの床の動作挙動を使用,표면이나 천장이 서로 통과가 가능함,Gebruik Doom's vloer beweging vloer,Użyj zachowanie ruchu podłogi Dooma,Usar comportamento de mov. do chão de Doom,,Utilizare comportament de mișcare al podelelor din Doom,Поведение движения по полу из Doom,Користи Doom-ово подно моционо понашање -Use Doom's point-on-line algorithm,CMPTMNU_POINTONLINE,,,,Použít původní algoritmus bod-na-čáře z Doomu,Benutze Dooms Punkt-auf-Linie Algorithmus,,Uzi algoritmon de Doom por trovi punkton sur linio,Usar algoritmo de punto en línea de Doom,,Käytä Doomin piste viivalla -algoritmia,Algorithme point-sur-ligne de DOOM,,Usa l'algoritmo del 'punto giacente sulla linea' di Doom,DOOMでのポイントライン アルゴリズム を使用,구형 선상 지점 정의법 사용,Gebruik Doom's point-on-line-algoritme,Użyj algorytmu punktu na linii z Dooma,Usar algorítmo de ponto-em-linha de Doom,,Utilizare algoritm point-on-line din Doom,Использовать алгоритм point-on-line из Doom,Користи Doom-ов point-on-line алгоритам -Level exit can be triggered more than once,CMPTMNU_MULTIEXIT,,,,Odchod z levelu může být spuštěn vícekrát,Ausgang kann mehr als einmal aktiviert werden,,Nivelelirejo povas esti aktiviga pli ol unufoje,La salida de nivel puede ser activada más de una vez,,Tasosta poistumisen voi laukaista useammin kuin kerran,Sortie niveau utilisable plusieures fois,,L'uscita del livello può attivarsi più di una volta,Exitを複数回起動出来る,레벨 출구 트리거 한 번 이상 작동,Niveau-uitgang kan meer dan eens worden geactiveerd,Wyjście z poziomu może być uruchomione więcej niż raz,Saída de fase pode ser ativada mais de uma vez,Saída de nível pode ser ativada mais de uma vez,Ieșirea nivelului poate fi activată de mai multe ori,Выходы могут быть активированы более одного раза,Излаз нивоа може бити активиран више пута -Physics Behavior,CMPTMNU_PHYSICSBEHAVIOR,,,Physics Behaviour,Chováni fyziky,Physik-Verhalten,,Fizikkonduto,Comportamiento de la física,,Fysiikan käyttäytyminen,Comportement Physique,,Comportamento della fisica,物理の挙動,물리 관련 설정,Fysica gedrag,Zachowanie Fizyki,Comportamento de Física,Comportamento das Físicas,Comportament fizică,Поведение физики,Физичко понашање -Actors are infinitely tall,CMPTMNU_NOPASSOVER,,,,Objekty jsou nekonečně vysoké,Akteure sind unendlich hoch,,Aktoroj estas senfine alta,Los actores son infinitamente altos,,Oliot ovat äärettömän korkeita,Hauteur des acteurs infinie,,Gli attori sono infinitamente alti,アクターの縦軸には入れない,무한으로 키가 큰 개체,Acteurs zijn oneindig lang,Aktorzy są nieskończenie wysocy,Atores são infinitamente altos,,Actorii au înălțime infinită,Акторы бесконечно высокие,Глумци су бесконачно велики -Boom scrollers are additive,CMPTMNU_BOOMSCROLL,,,,Boom posuvníky jsou aditivní,Boom-Scroller sind additiv,,Skrolantaj Teksturaj de Boom estas adicia,Scrollers de Boom son aditivos,,Boom-vierittimet ovat additiivisia,Glisseurs BOOM additifs,,Le barre di scorrimento Boom sono additivi,BOOM型 壁スクロールを適用,붐 스크롤러 누적법 사용,Boom scrollers zijn additief,Przewijane tekstury Boom są addytywne,Scrollers de Boom são aditivos,,Elementele derulante BOOM sunt aditive,Скроллеры из BOOM являются аддитивными,Boom скролери су додаци -Cannot travel straight NSEW,CMPTMNU_BADANGLES,,,,Nelze se pohybovat přímo na SJVZ,Bewegungsrichtungen direkt NSOW nicht möglich,,Ne eblas veturi rekte NSEW,Emular error de mal ángulo,,Liikkuminen puhtaasti pääilmansuuntiin mahdotonta,Direction pure NSEO impossible,,Non si può viaggiare esattamente nelle direzioni cardinali,テレポート時 東西南北に真っ直ぐ直進出来ない,전방위 방향으로 이동 불가,Kan niet rechtdoor reizen NZOW,Pozwól na błąd złego kąta,Impossível se deslocar reto em direções cardeais,Impossível se deslocar em frente em direções cardeais,Interzice deplasarea liniară NSEW,"Запрещено двигаться прямо на С, Ю, З, В",Немогуће путовати право на NSEW -Enable wall running,CMPTMNU_WALLRUN,,,,Povolit wall running (běhaní pomocí zdi),Ermögliche Wandrennen,,Aktivigi kuradon sur muroj,Activar correr por muros,,Salli seinäjuoksu,Activer Wallrunning,,Wall running abilitata,壁伝い走行を許可,벽면가속이동 허용,Wandloop mogelijk maken,Włącz szybkie bieganie wzdłuż ścian,Habilitar corrida por paredes,Permitir corrida pelas paredes,Permite fuga cu ajutorul pereților (Wallrun),Включить быстрый бег вдоль стен (Wallrun),Омогући пролажење кроз зида -Raven scrollers use original speed,CMPTMNU_RAVENSCROLL,,,,Raven posuvníky používají původní rychlost,Raven-Scroller benutzen originale Geschwindigkeit,,Skrolantaj teksturoj de Raven uzas originala rapidecon,Los scrollers de Raven usan la velocidad original,,Ravenin vierittimet liikkuvat alkuperäisnopeudella,Glisseurs Raven à leur vitesse originale,,Le barre di scorrimento Raven usano la velocità originale,Raven型 壁スクロールは元の速度を使用,구형 헤러틱/헥센 스크롤러 사용,Raven scrollers gebruiken originele snelheid,Przwijane tekstury podłogi Raven używają oryginalną prędkość,Scrollers da Raven usam velocidade original,,Elementele derulante Raven folosesc viteza originală,Raven-скроллеры используют оригинальную скорость,Raven скролери користе оригиналну брзину -Self ref. sectors don't block shots,CMPTMNU_TRACE,,,,Sebe-odkazující sektory neblokují střely,Selbstreferenzierende Sektoren blockieren keine Schüsse,,Sinreferencantaj sektoroj ne baras pafojn,Sectores autoreferidos no bloquean los disparos,,Itseensä viittaavat sektorit eivät estä laukauksia,Secteur autoréférencé ne bloque pas les tirs,,Settori autoreferenziati non bloccano i colpi,Self ref.セクターは射撃を阻害しない,자기 참조 섹터가 총탄을 막지 않음,Zelfreferentie sectoren blokkeren geen schoten,Sektory odnoszoce się do siebie nie blokują strzałów,Setores autorreferidos não bloqueiam tiros,,Sectoarele cu referință proprie blochează focurile,Самоссылающиеся секторы не блокируют выстрелы,Самореф. сектори не блокирају пуцњеве -Use Doom code for hitscan checks,CMPTMNU_HITSCAN,,,,Použít původní Doom kód pro kontrolu hitscanů,Benutze Original-Doom-Code für Hitscan-Checks,,Uzi kodon de Doom por batskanoj-kontrolado,Usar código de Doom para revisión de hitscan,,Käytä Doomin osumislaskentakoodia,Vérification Hitscan à la DOOM,,Usa il codice Doom per il controllo sugli hitscan,DOOM型 ヒットスキャンチェックを使用,구형 총탄 판정법 사용,Gebruik Doom-code voor hitscancontroles,Użyj kod Dooma dla hitscanu,Usam código de Doom para verificação de hitscan,Usar código de Doom para verificação de hitscan,Utilizează cod din Doom pentru a verifica coliziunea focurilor,Использовать код из Doom для проверок хит-сканов,Користи Doom код за хитскен проверу -Use Doom heights for missile clipping,CMPTMNU_MISSILECLIP,,,,Použít původní výšky z Doomu pro kolizi raket,Benutze Doom-Größen für Kollisionen mit Projektilen,,Uzi Doomaltoj por misiltonadoj,Usar altura de Doom para desplazamiento de misiles,,Käytä Doomin korkeuksia lentokappaleiden törmäyksissä,Clipping des missiles à la DOOM,,Usa le altezze di Doom per il clipping del razzo,DOOM型 ミサイルクリッピングの高さを使用,구형 발사체 판정법 사용,Gebruik Doom hoogtes voor het knippen van raketten,Użyj wysokości Dooma dla przenikania pocisków,Usar alturas de Doom para colisão de projéteis,,Utilizează metoda de verificare a înălțimilor din Doom,Использовать высоты из Doom для столкновения ракет,Користи Doom висине за клиповање ракета -Rendering Behavior,CMPTMNU_RENDERINGBEHAVIOR,,,Rendering Behaviour,Chování renderingu,Renderverhalten,,Bildigado-konduto,Comportamiento de renderizado,,Hahmonnuksen käyttäytyminen,Comportement d'affichage,,Comportamento della grafica,レンダリングの挙動,렌더링 관련 설정,Rendering gedrag,Zachowanie Renderowania,Comportamento de Renderização,,Comportament Video,Поведение рендеринга,Понашање рендовања -Draw polyobjects like Hexen,CMPTMNU_POLYOBJ,,,,Vykreslovat polyobjekty jako Hexen,Zeichne Polyobjekte wie in Hexen,,Desegni plurangulo-objektojn kiel Hexen,Dibujar poliobjetos como en Hexen,,Piirrä polyobjektit niin kuin Hexen,Dessiner les Polyobjets comme Hexen,,Polioggetti disegnati come Hexen,Hexen式のポリオブジェクト描画,구형 폴리오브젝트 시스템 사용,Teken polyobjecten zoals Hexen,Rysuj poliobiekty jak w Hexenie,Desenhar poliobjetos como em Hexen,,Afișează poliobiectele precum în Hexen,Рисовать полиобъекты как в Hexen,Цртај поли-објекте као Hexen -Ignore Y offsets on masked midtextures,CMPTMNU_MASKEDMIDTEX,,,,Ignorovat Y posuny na průhledných mid-texturách,Ignoriere Y-Offsets bei transparenten Mitteltexturen,,Malatenti Yn deŝovaĵojn sur maskito-midtekstaĵoj,Ignorar offsets de eje Y en texturas medias enmascaradas,,Älä huomioi Y-siirroksia peitetyissä keskipintakuvioinneissa,Offsets Y ignorés sur les textures centrales,,Ignora gli offset Y sulle midtexture mascherate,中間テクスチャーのマスクされたYオフセットを無効,이면선분의 중앙 텍스쳐의 Y축값 무시,Negeer Y compensaties op gemaskerde middentexturen,Ignoruj przesunięcia osi Y na zamaskowanych teksturach po środku,Ignorar offsets de Y em texturas centrais,,Ignoră ofsetul Y de pe texturile 3D mascate,Игнорировать смещение Y на скрытых мид-текстурах,Игнориши Y нагиб на маскиране средње текстуре -Invert sprite sorting,CMPTMNU_SPRITESORT,,,,Obrátit řazení spritů,Umgekehrte Spritesortierung,,Inversigi spritordigadon,Invertir ordenado de sprites,,Käännä spritelajittelu,Ordres des sprites inversé,,Ordinamento sprite invertito,反転スプライトの並び替え,구형 스프라이트 겹침 판정 사용,Sprite sorteren omkeren,Odwróć sortowanie sprite'ów,Inverter ordem de sprites,,Inversare sortare sprite-uri,Инвертировать сортировку спрайтов,Обрнуто сортирање спрајтова -Sound Behavior,CMPTMNU_SOUNDBEHAVIOR,,,Sound Behaviour,Chování zvuku,Sound-Verhalten,,Sonkonduto,Comportamiento de sonido,,Äänen käyttäytyminen,Comportement Sonore,,Comportamento suono,音の挙動,효과음 관련 설정,Geluidsgedrag,Zachowanie dźwięku,Comportamento de Áudio,,Comportament Sunet,Поведение звуков,Понашање звука -Cripple sound for silent BFG trick,CMPTMNU_SOUNDSLOTS,,,,Zmrzačit zvukový systém pro trik tichého BFG,Amputiere Soundsystem für geräuschloses BFG,,Kripligi sonon por lertaĵo de silenta BFG,Estropear sonido para truco de BFG silencioso,,Rampauta äänijärjestelmä hiljaista BFG-temppua varten,Massacrer le son pour BFG silencieux,,Blocca il suono per il trucco del BFG silenzioso,消音BFGトリックの為にサウンドを重複させない,소음 BFG 효과 허용,Kreupel geluid voor een stille BFG-truc,Obetnij dźwięk dla triku cichego BFG,Bloquear som para o truque da BFG silenciosa,,Taie sunetul pentru trucul BFG silențios,Исказить звуки для трюка бесшумной BFG,Онемогући звук за тихи ВЈП трик -Don't let others hear your pickups,CMPTMNU_SILENTPICKUP,,,,Ostatní tě neslyší sbírat předměty,Andere können deine Gegenstandsaufnahmen nicht hören,,Ne lasu aliajn aŭdi via prenadoj,No dejar a otros oír tus recogidas,,"Älä anna muiden kuulla, kun poimit esineitä",Autres joueurs n'entendent pas les ramassages,,Non consentire agli altri giocatori di sentire le tue raccolte,他人にピックアップ音を聞かせない,상대방의 습득 효과음 청음 불가,Laat anderen uw pick-ups niet horen,"Nie pozwalaj by inni słyszeli, że podnosisz przedmioty",Não permitir que outros ouçam sua coleta de itens,Não permitir que outros ouçam sua aquisição de itens,Nu permite celorlalți să audă sunetul ridicării obiectelor,Запрещать другим слышать Ваш подбор предметов,Не допусти да други чују ваше скупљање -Inst. moving floors are not silent,CMPTMNU_SILENTINSTANTFLOORS,,,,Okamžitě pohybující se podlahy nejsou tiché,Böden mit sofortiger Bewegung machen Geräusche,,Tujaj movantaj plankoj ne estas silentaj,Suelos inst. movibles no son silenciosos,,Silmänräpäyksellisesti liikkuvat lattiat eivät ole hiljaisia,Sols à movement instanté font du bruit,,I pavimenti istantanei in movimento non sono silenziosi,即時稼働する床の音を鳴らさない,즉발식 이동표면 소음효과 제거,Direct bewegende vloeren zijn niet geruisloos,Nagle przesuwające się podłogi nie są ciche,Pisos que se deslocam instantâneamente emitem som,,Podelele care se mișcă instant nu sunt silențioase,Мгновенно двигающиеся полы не беззвучны,Инстантно покрећући нивои нису тихи -Sector sounds use center as source,CMPTMNU_SECTORSOUNDS,,,Sector sounds use centre as source,Sektorové zvuky používají jeho střed jako zdroj,Sektor-Sounds benutzen den Mittelpunkt des Sektors,,Sektorsonoj fontas de centro,Sonidos de sector usan el centro como fuente,,Sektoriäänet käyttävät keskipistettä lähteenä,Sons secteur utilisent le centre comme origine,,I suoni usano il centro dei settori come punto di sorgente,セクターサウンドをフロア中央で鳴らす,섹터 중심부를 효과음의 원천으로 판정,Sectorgeluiden gebruiken centrum als bron,Dźwięki sektorów używają środka jako źródła,Sons de setor são emitidos a partir do centro,,Sunetele sectoarelor au ca sursă centrul,Звуки секторов используют центр как источник,Секторски звукови су центрисани -Sounds stop when actor vanishes,CMPTMNU_SOUNDCUTOFF,,,,"Utnout zvuky, když jejich objekt zmizí","Sounds werden beendet, wenn der Akteur verschwindet",,"Sonoj ĉesas, kiam aktoro malaperas",El sonido se detiene cuando el actor desaparece,,"Äänet lakkaavat, kun olio katoaa",Sons s'arrêtent quand acteur disparait,,I suoni si fermano quando gli attori svaniscono,アクター消滅で音を止める,효과음 원천 소멸 시 효과음도 중단,Geluiden stoppen wanneer de acteur verdwijnt,Dźwięki zatrzymują się kiedy aktor znika,Som para quando o ator desaparece,,Sunetele se opresc când actorul sursă dispare,Останавливать звуки при исчезновении актора,Звукови престају кад глумац нестане -Use original sound target handling,CMPTMNU_SOUNDTARGET,,,,Použít původní chování pro uchování zvukového cíle,Benutze originale Behandlung für das Sound-Ziel,,Uzi originalan manipuladon por soncelo,Usar manejo de destino de sonido original,,Käytä alkuperäistä äänen kohteen käsittelyä,Ciblage des sons selon algorithme original,,Targeting dei suoni in base all'algoritmo originale,元のサウンドターゲット処理を使用,구형 섹터 경고음 보존법 사용,Gebruik originele geluidsdoelwitverwerking,Użyj oryginalną obsługę celu dźwięku,Usar método original de destino de som,,Procesare originală pentru sursele de sunet,Оригинальная обработка источников звука,Користи оригинални звук руковања метом -Scripted teleports don't trigger sector actions,CMPTMNU_TELEPORT,,,,Skriptované teleportace neaktivují sektorové akce,Teleports in Skripten lösen keine Sektoraktionen aus,,Skriptataj teleportoj ne aktivigas sektor-agojn,Telepuertos por script no activan acciones del sector,,Käsikirjoitetut kaukosiirtimet eivät laukaise sektoritoimintoja,Téléports par scripts n'activent pas le secteur,,I teletrasporti scriptati non attivano le azioni del settore,スクリプトテレポートではセクターアクションを起こさない,순간이동 스크립트는 섹터 이벤트 발동 불가능,De gescripte teleports leiden niet tot acties in de sector.,Oskryptowane teleporty nie włączają akcji sektora,Teletransportes scriptados não ativam ações de setor,,Teleporturile scriptate nu declanșează acțiuni în sectoare,Скриптовые телепорты не инициируют действия секторов,Скриптовани телепортери не активирају секторске радње -Non-blocking lines can be pushed,CMPTMNU_PUSHWINDOW,,,,Neblokující čáry mohou být zmáčknuty,Nicht-blockende Linien können angestoßen werden,,Nehaltantaj linioj povas esti premitaj,Líneas sin bloquear pueden ser presionadas,,Ei-tukkivia viivoja voi työntää,Lignes non-bloquantes sont non-poussables,,Le linee non bloccanti possono essere spinti,Non-bloking linesを押せる,비차단 선분 밀어내기 가능,Niet-blokkerende lijnen kunnen worden geduwd,Nieblokujące ściany mogą być pchnięte,Linhas não-bloqueadoras podem ser pressionadas,,Liniile care nu blochează pot fi împinse înapoi,Неблокирующие линии могут быть отодвинуты,Неблокирабе линје могу бити гурнуте -Enable buggy CheckSwitchRange behavior,CMPTMNU_CHECKSWITCHRANGE,,,,Povolit nestabilní chování pro CheckSwitchRange,Erlaube fehlerhaftes CheckSwitchRange Verhalten,,Aktivigi cimajn kondutojn por CheckSwitchRange,Permitir comportamiento viejo de CheckSwitchRange,,Ota käyttöön viallinen CheckSwitchRange-käyttäytyminen,Fonction CheckSwitchRange buggée,,Abilita il comportamento buggato del CheckSwitchRange,バグのある CheckSwitchRange を許可,구형 CheckSwitchRange 판정법 사용,Buggy CheckSwitchSwitchRange gedrag inschakelen,Zezwól na zepsute zachowanie CheckSwitchRange,Habilitar comportamento CheckSwitchRange defeituoso,,Comportament incorect pentru CheckSwitchRange,Включить багнутое поведение CheckSwitchRange,Омогући баговано CheckSwitchRange понашање -Sound Options,SNDMNU_TITLE,,,,Nastavení zvuku,Soundeinstellungen,,Son-agordoj,Opciones de sonido,,Ääniasetukset,Options Sonores,Hangbeállítások,Opzioni del suono,サウンド オプション,음향 설정,Geluidsopties,Opcje Dźwięku,Opções de Áudio,,Setări Sunet,Настройки звука,Звучна подешавања -Sounds volume,SNDMNU_SFXVOLUME,,,,Hlasitost zvuků,Effektlautstärke,,Son-laŭteco,Volumen de sonido,,Äänitehosteiden voimakkuus,Volume des Sons,Effektek hangereje,Volume suoni,効果音音量,효과음 음량,Geluidsvolume,Głośność Dźwięku,Volume de sons,,Volum efecte,Громкость звука,Јачина звука -Menu volume,SNDMNU_MENUVOLUME,,,,Hlasitost nabídek,Menülautstärke,,Menu-laŭteco,Volumen del menú,,Valikon äänenvoimakkuus,Volume du Menu,Menü hangereje,Volume menu,メニュー音量,메뉴 음량,Menu volume,Głośność Menu,Volume do menu,,Volum meniu,Громкость меню,Јачина менија -Music volume,SNDMNU_MUSICVOLUME,,,,Hlasitost hudby,Musiklautstärke,,Muzik-laŭteco,Volumen de la Música,,Musiikin äänenvoimakkuus,Volume Musique,Zene hangereje,Volume musica,音楽音量,배경음 음량,Muziekvolume,Głośność Muzyki,Volume da música,,Volum muzică,Громкость музыки,Јачина музике -MIDI device,SNDMNU_MIDIDEVICE,,,,MIDI zařízení,MIDI-Gerät,,MIDI-aparato,Dispositivo MIDI,,MIDI-laite,Sortie MIDI,MIDI eszköz,Dispositivo MIDI,MIDIデバイス,MIDI 장치,MIDI-apparaat,Urządzenie MIDI,Dispositivo MIDI,,Dispozitiv MIDI,MIDI проигрыватель,MIDI уређај -Sound in Background,SNDMNU_BACKGROUND,,,,Zvuk na pozadí,Sound im Hintergrund,,Sono en Fono,Sonido en segundo plano,,Ääni taustalla,Son activé en arrière plan,Háttérhangok,Suono di sottofondo,バックグラウンドでのサウンド,배경화면에서도 소리 재생,Geluid in de achtergrond,Dźwięk w Tle,Som de Fundo,,Sunet pe fundal,Звуки в фоне,Звуци у позадини -Underwater reverb,SNDMNU_UNDERWATERREVERB,,,,Ozvěna pod vodou,Unterwasserhall,,Subakva resono,Reverb. bajo el agua,,Vedenalaiskaiku,Reverbération sous l'eau,Vízalatti viszhang,Reverb sott'acqua,水中反響音,수중 울림효과,Onderwater nagalm,Pogłos pod wodą,Reverberação debaixo d'água,Reverberação debaixo de água,Reverb subacvatic,Эффект под водой,Подводни одјек -Randomize pitches,SNDMNU_RANDOMIZEPITCHES,,,,Náhodné výšky tónu,Zufällige Tonhöhe,,Malcertigi son-peĉojn,Tonos aleatorios,,Satunnaista äänenkorkeuksia,Tons sonores aléatoires,Hangmagasság véletlenszerű,Rendi casuale il tono,ランダマイズ ピッチ,음높이 무작위화,Willekeurige plaatsen,Losuj tonacje,Aleatorizar tons,Tons aleatórios,Ton sunete aleatoriu,Изменять высоту,Рандомизација тонова -Sound channels,SNDMNU_CHANNELS,,,,Počet zvukových kanálů,Soundkanäle,,Son-kanaloj,Canales de sonido,,Äänikanavat,Canaux sonores,Hangcsatorna,Numero canali del suono,サウンド チャンネル,음향 채널,Geluidskanalen,Kanały dźwiękowe,Canais de som,,Canale de sunet,Количество каналов,Звучни канали -Sound backend,SNDMNU_BACKEND,,,,Zvukový systém,Soundsystem,,Son-servilo,Sistema de sonido,,Äänijärjestelmä,Traitement Son,,Backend suono,サウンド バックエンド,음향 말미,Geluidsarme achterkant,System dźwiękowy,Sistema de som,,Sistem de sunet,Звуковая система,Звучни бекенд -OpenAL options,SNDMNU_OPENAL,,,,Nastavení OpenAL,OpenAL Optionen,,OpenAL-agordoj,Opciones de OpenAL,,OpenAL-asetukset,Options OpenAL,OpenAL beállításai,Opzioni OpenAL,OpenAL オプション,오픈에이엘 설정,OpenAL opties,Opcje OpenAL,Opções de OpenAL,,Setări OpenAL,Настройки OpenAL,OpenAL подешавања -Restart sound,SNDMNU_RESTART,,,,Restartovat zvuk,Sound neu starten,,Rekomenci sonon,Reiniciar sonido,,Käynnistä ääni uudelleen,Redémarrer moteur sonore,Hang újraindítása,Resetta il suono,サウンド再起動,음향 재시작,Herstart geluid,Zresetuj dźwięk,Reiniciar som,,Reinițializare sunet,Перезапустить звук,Поново покрени звук -Advanced options,SNDMNU_ADVANCED,,,,Pokročilá nastavení,Erweiterte Optionen,,Altnivelaj agordoj,Opciones avanzadas,,Edistyneet asetukset,Options avancées,Haladó beállítások,Opzioni avanzate,高度なオプション,고급 설정,Geavanceerde opties,Zaawansowane Opcje,Opções avançadas,,Setări avansate,Расширенные настройки,Напредна подешавања -Module replayer options,SNDMNU_MODREPLAYER,,,,Nastavení přehrávače modulů,Modul-Spieler-Optionen,,Agordoj por modulreludilo,Opciones reproductor de módulos,,Moduulisoitinasetukset,Options lecteur de module,,Opzioni Module replayer,モジュールリプレイヤー オプション,모듈 재생 설정,Module replayer opties,Opcje Modułu Odtwarzacza,Opções de reprodutor de módulos,,Setări de redare a modulelor,Параметры воспроизведения модулей,Подешавања модулног риплејера -Midi player options,SNDMNU_MIDIPLAYER,,,,Nastavení MIDI přehrávače,MIDI-Spieler-Optionen,,Agordoj por MIDI-ludilo,Opciones de reproductor MIDI,,MIDI-soitinasetukset,Option lecteur MIDI,,Opzioni Midi player,Midi再生のオプション,MIDI 플레이어 설정,Midi speler opties,Opcje Odtwarzacza Midi,Opções de reprodutor MIDI,,Setări player MIDI,Настройки MIDI-проигрывателя,MIDI плејер подешавања -OpenAL Options,OPENALMNU_TITLE,,,,Nastavení OpenAL,OpenAL Optionen,,OpenAL-agordoj,Opciones de OpenAL,,OpenAL-asetukset,Options OpenAL,,Opzioni OpenAL,OpenAL オプション,오픈에이엘 설정,OpenAL opties,Opcje OpenAL,Opções de OpenAL,,Setări OpenAL,Настройки OpenAL,OpenAL подешавања -Playback device,OPENALMNU_PLAYBACKDEVICE,,,,Přehrávací zařízení,Wiedergabegerät,,Ludado-aparato,Dispositivo de reproducción,,Äänitoistolaite,Sortie sonore,,Dispositivo di playback,プレイバック デバイス,재생 장치,Afspeelapparaat,Urządzenie odtwarzania,Dispositivo de reprodução,,Dispozitiv de redare,Устройство воспроизведения,Аудио уређај -Enable EFX,OPENALMNU_ENABLEEFX,,,,Povolit EFX,EFX aktiv,,Aktivigi EFX,Permitir EFX,,Ota käyttöön EFX,Activer EFX,,Abilita EFX,EFXを有効化,EFX 켬,EFX inschakelen,Pozwól na EFX,Habilitar EFX,,Activare EFX,Включить EFX,Укључи EFX -Resampler,OPENALMNU_RESAMPLER,,,,,,,Respecimenilo,,,Näytteenottotaajuusmuunnin,,,,リサンプラー,재배열 기기,,Resampler,,,Resempler,Ресэмплер,Ресемплер -Advanced Sound Options,ADVSNDMNU_TITLE,,,,Pokročilá nastavení zvuku,Erweiterte Soundoptionen,,Altnivelaj Son-agordoj,Opciones avanzadas de sonido,,Edistyneet ääniasetukset,Options Sonores Avancées,,Opzioni avanzate dei suoni,高度なサウンドオプション,고급 음향 설정,Geavanceerde geluidsopties,Zaawansowane Opcje Dźwięku,Opções de Áudio Avançadas,,Setări de sunet avansate,Расширенные настройки,Напредна подешавања звука -Sample rate,ADVSNDMNU_SAMPLERATE,,,,Vzorkovací frekvence,Samplerate,,Specimenrapideco,Frecuencia de muestreo,,Näytteenottotaajuus,Cadence de Sampling,,,サンプルレート,샘플링레이트,Steekproeftarief,Częstotliwość próbkowania,Taxa de amostragem,,Frecvență de eșantionare,Частота дискретизации,Фреквенција узорковања -HRTF,ADVSNDMNU_HRTF,,,,,,,,,,,,,,,머리전달함수,,HRTF,,,HRTF,, -OPL Synthesis,ADVSNDMNU_OPLSYNTHESIS,,,,Emulace OPL,OPL Synthese,,OPL-Sintezo,Síntesis OPL,,OPL-synteesi,Synthèse OPL,,,OPLシンセサイズ,OPL 합성,OPL synthese,Synteza OPL,Síntese OPL,,Sinteză OPL,Синтез OPL,OPL синтеза -Number of emulated OPL chips,ADVSNDMNU_OPLNUMCHIPS,,,,Počet emulovaných OPL čipů,Anzahl OPL Chips,,Nombro da imititaj OPL-blatoj,Número de chips OPL emulados,,Emuloitavien OPL-piirien lukumäärä,Puces OPL émulées,,Numero di chip OPL emulati,OPLチップエミュレートの番号,에뮬레이트된 OPL 칩 수,Aantal geëmuleerde OPL chips,Liczba emulowanych czipów OPL,Número de chips OPL emulados,,Număr de cipuri OPL emulate,Количество эмулируемых OPL чипов,Број емулираних OPL чипа -Full MIDI stereo panning,ADVSNDMNU_OPLFULLPAN,,,,Plné MIDI stereo,Echte MIDI-Stereoeffekte,,Tuta MIDI-sterepanoramado,Balance estéreo MIDI completo,,Täysi MIDI-stereopanorointi,Latéralisation complète MIDI,,,Full MIDIステレオパンニング,완전한 MIDI 스테레오 패닝,Volledige MIDI stereo panning,Pełne efekty stereo dla MIDI,Lateralidade estéreo completa para MIDI,,Panoramă stereo pentru MIDI,Полная стереопанорама для MIDI,Пуно MIDI стерео каналисање -OPL Emulator Core,ADVSNDMNU_OPLCORES,,,,Emulační jádro OPL,OPL Emulatorkern,,OPL Imitilkerno,Núcleo de emulador OPL,,OPL-emulaattoriydin,Cœur émulateur OPL,,,OPL エミュレート コア,OPL 에뮬레이터 코어,OPL Emulator Kern,Rdzeń Emulatora OPL,Núcleo do emulador de OPL,,Nucleu de emulare OPL,Ядро эмуляции OPL,OPL језгро емулације -OPN2 Emulator Core,ADVSNDMNU_OPNCORES,,,,Emulační jádro OPN2,OPN2 Emulatorkern,,OPN2 Imitilkerno,Núcleo de emulador OPN2,,OPN2-emulaattoriydin,Cœur émulateur OPN2,,,OPN2 エミュレート コア,OPN2 에뮬레이터 코어,OPN2 Emulatorkern van de OPN2-emulator,Rdzeń Emulatora OPN2,Núcleo do emulador de OPN2,,Nucleu de emulare OPN2,Ядро эмуляции OPN2,OPN2 језгро емулације -GUS Emulation,ADVSNDMNU_GUSEMULATION,,,,Emulace GUS,GUS Emulation,,GUS Imitado,Emulación GUS,,GUS-emulaatio,Emulation GUS,,,GUS エミュレーション,GUS 에뮬레이션,GUS-emulatie,Emulacja GUS,Emulação de GUS,,Emulare GUS,Эмуляция GUS,GUS емулација -GUS config file,ADVSNDMNU_GUSCONFIG,,,,Konfigurační soubor GUS,GUS Konfigurationsdatei,,GUS Agordarkivo,Archivo de config. GUS,,GUS-config-tiedosto,Fichier Config. GUS,,File GUS config,GUS コンフィグファイル,GUS 코딩 파일,GUS-configuratiebestand,Plik konfiguracyjny GUS,Arquivo de configuração do GUS,,Fișier configurație GUS,Файл конфигурации для GUS,GUS конфигурациона датотека -MIDI voices,ADVSNDMNU_MIDIVOICES,,,,Počet MIDI hlasů,MIDI Stimmen,,MIDI Voĉoj,Voces MIDI,,MIDI-äänet,Voix MIDI,,Voci MIDI,MIDI ボイス,MIDI 최대 음색 양,MIDI-stemmen,Głosy MIDI,Vozes MIDI,,Voci MIDI,MIDI-голоса,MIDI гласови -Read DMXGUS lumps,ADVSNDMNU_DMXGUS,,,,Načíst DMXGUS soubory,Lese DMXGUS,,Legi DMXGUS Masojn,Leer archivos DMXGUS,,Lue DMXGUS-tietoja,Lire fichiers DMXGUS,,Leggi i lump DMXGUS,DMXGUS ランプを読む,DMXGUS 럼프 읽기,DMXGUS-klonten lezen,Czytaj pliki DMXGUS,Ler lumps DMXGUS,,Citire fișiere DMXGUS,Читать файлы DMXGUS,Читај DMXGUS фајлове -GUS memory size,ADVSNDMNU_GUSMEMSIZE,,,,Velikost paměti GUS,GUS Speichergröße,,GUS Memorampleksoj,Tamaño de memoria de GUS,,GUS-muistikoko,Taille mémoire GUS,,Dimensione della memoria per GUS,GUS メモリーサイズ,GUS 메모리 크기,GUS-geheugengrootte,Rozmiar pamięci GUS,Tamanho de memória do GUS,,Memorie alocată pentru GUS,Размер памяти GUS,GUS величина памћења -FluidSynth,ADVSNDMNU_FLUIDSYNTH,,,,,,,,,,,,,,,,,,,,,, -Patch set,ADVSNDMNU_FLUIDPATCHSET,,,,Nástrojová sada,Patch-Set,,Flikaro,Set de parche,,Patch-asetus,Banque de Sons,,,パッチ セット,패치 세트,,Zestaw patchów,Banco de sons,,Set patch,Патч-набор,Печ сет -Gain,ADVSNDMNU_FLUIDGAIN,,,,Zesílení,Relative Lautstärke,,Akiro,Ganancia,,Vahvistus,,,,ゲイン,쌓기,Relatief volume,Wzmocnienie,Ganho,,Amplificare,Усиление,Појачање -Reverb,ADVSNDMNU_REVERB,,,,Ozvěna,Hall,,Resono,Reverberación,,Kaiku,Réverbération,,,リバーブ,리버브,Nagalm,Pogłos,Reverberação,,,Реверберация,Одјек -Reverb Level,ADVSNDMNU_REVERB_LEVEL,,,,Intenzita ozvěny,Hallintensität,,Resono-nivelo,Nivel de Reverberación,,Kaiunvoimakkuus,Niveau Réverb.,,,リバーブ量,리버브 강도,Nagalm niveau,Poziom pogłosu,Nível de reverberação,,Nivel Reverb,Уровень реверберации,Ниво одјека -Chorus,ADVSNDMNU_CHORUS,,,,,,,Koruso,,,,,,,コーラス,코러스,,,,,Cor,Хорус,Корус -Timidity++,ADVSNDMNU_TIMIDITY,,,,,,,,,,,,,,,,,,,,,, -ADLMidi,ADVSNDMNU_ADLMIDI,,,,,,,,,,,,,,,,,,,,,, -OPNMidi,ADVSNDMNU_OPNMIDI,,,,,,,,,,,,,,,,,,,,,, -Timidity config file,ADVSNDMNU_TIMIDITYCONFIG,,,,Konfigurační soubor Timidity,Timidity Konfigurationsdatei,,Agordo-arkivo por Timidity,Ruta al archivo config. Timidity,,Timidity-config-tiedosto,Fichier de config. TiMidity,,File Timidity config,Timidity コンフィグファイル,Timidity 코딩 파일,Timidity++ configuratiebestand,Plik konfiguracyjny Timidity,Arquivo de configuração do Timidity,,Fișier configurație Timidity,Файл конфигурации Timidity,Timidity конфигурациона датотека -Relative volume,ADVSNDMNU_TIMIDITYVOLUME,,,,Relativní hlasitost,Relative Lautstärke,,Relativa volumeno,Volumen relativo,,Suhteellinen äänenvoimakkuus,Volume Relatif,,Volume relativo,相対音量,비교적인 볼륨,Relatief volume,Względna głośność,Volume relativo,,Volum relativ,Относительная громкость,Релативна јачина -WildMidi,ADVSNDMNU_WILDMIDI,,,,,,,,,,,,,,,,,,,,,, -WildMidi config file,ADVSNDMNU_WILDMIDICONFIG,,,,Konfigurační soubor WildMidi,WilfMidi Konfigurationsdatei,,WildMidi agordarkivo,Archivo de config. WildMidi,,WildMidi-config-tiedosto,Fichier config. WildMidi,,File WildMidi config,WildMidi コンフィグファイル,WildMidi 코딩 파일,WildMidi configuratiebestand,Plik konfiguracyjny WildMidi,Arquivo de configuração do WildMidi,,Fișier configurație WildMidi,Файл конфигурации WildMidi,WildMidi конфигурациона датотека -Select configuration,ADVSNDMNU_SELCONFIG,,,,Vybrat konfiguraci,Konfiguration wählen,,Elekti agordojn,Seleccionar configuración,,Valitse kokoonpano,Sélectionner configuration,,Seleziona la configurazione,構成選択,설정을 고르시오,Selecteer configuratie,Wybierz konfigurację,Selecionar configuração,,Selectare configurație,Выбор конфигурации,Изабери конфигурацију -Global,ADVSNDMNU_GLOBAL,,,,Globální,,,Malloka,Global,,Yleinen,,,Globale,グローバル,전반적,Globaal,Globalne,,,,Общие,Глобално -Freeverb,ADVSNDMNU_FREEVERB,,,,,,,,,,,,,,フリーバーブ,프리버브,,,,,,, -Global Freeverb,ADVSNDMNU_GLOBAL_FREEVERB,,,,Globální Freeverb,Globales Freeverb,,Malloka Freeverb,Freeverb Global,,Yleinen Freeverb,Freeverb Global,,Freeverb globale,グローバル フリーバーブ,전반적 프리버브,Globale Freeverb,Globalny Freeverb,Freeverb Global,,Freeverb Global,Глобальный Freeverb,Глобални Freeverb -Advanced Resampling,ADVSNDMNU_ADVRESAMPLING,,,,Pokročilé převzorkování,Erweitertes Resampling,,Altnivela respecimenado,Resampleo Avanzado,,Kehittynyt näytteenottotaajuuden muuntaminen,Resampling Avancé,,Resampling avanzato,高度なリサンプリング,향상된 리샘플링,Geavanceerde herbemonstering,Zaawansowane Próbkowanie,Reamostragem Avançada,,Resempling avansat,Продвинутый ресэмплинг,Напредно ресампловање -OPL Bank,ADVSNDMNU_OPLBANK,,,,OPL sada,,,Banko por OPL,Banco OPL,,OPL-pankki,Banque OPL,,,,OPL 뱅크,,Bank OPL,Banco OPL,,,Банк OPL,OPL банка -OPL Emulator Core,ADVSNDMNU_ADLOPLCORES,,,,Emulační jádro OPL,OPL Emulatorkern,,Imitilkerno por OPL,Núcleos de Emulador OPL,,OPL-emulaattoriydin,Cœur Emulateur OPL,,,OPL エミュレートコア,OPL 에뮬레이터 코어,OPL Emulator Kern,Rdzeń Emulatora OPL,Núcleo do Emulador de OPL,,Nucleu de emulare GUS,Ядро эмуляции OPL,OPL емулационо језгро -Run emulator at PCM rate,ADVSNDMNU_RUNPCMRATE,,,,Emulátor používá PCM vzorkovací frekvenci,Emulator benutzt PCM Samplerate,,Kurigi imitilon laŭ rapido de PCM,Ejecutar emulador a velocidad PCM,,Aja emulaattoria PCM-taajuudella,Emulateur utilise cadence PCM,,Esegui l'emulatore con rate PCM,PCMレートでエミュレート実行,PCM 속도로 에뮬레이터 실행,Emulator maakt gebruik van PCM Samplerate,Uruchom emulator w częstotliwości PCM,Rodar emulador em taxa PCM,,Utilizare cu frecvența PCM,Использовать с частотой PCM,Покрени емулацију на PCM стопи -Number of emulated OPL chips,ADVSNDMNU_ADLNUMCHIPS,,,,Počet emulovaných OPL čipů,Anzahl OPL Chips,,Numbro da imitaj OPL-blatoj,Número de chips OPL emulados,,Emuloitavien OPL-piirien lukumäärä,Puces OPL émulées,,Numero di chip OPL emulati,OPLチップエミュレートの番号,에뮬레이트된 OPL 칩 개수,Aantal geëmuleerde OPL chips,Liczba emulowanych czipów OPL,Número de chips OPL emulados,,Număr de cipuri GUS emulate,Количество эмулируемых чипов OPL,Број емулираних OPL чипова -Volume model,ADVSNDMNU_VLMODEL,,,,Model hlasitosti,Lautstärkemodell,,Volumen-modelo,Modelo de Volumen,,Äänenvoimakkuusmalli,Modèle de Volume,,Modello di volume,音量モデル,모델 볼륨,Volume model,Model głośności,Modelo de volume,,Model volum,Модель громкости,Волумски модел -Number of emulated OPN chips,ADVSNDMNU_OPNNUMCHIPS,,,,Počet emulovaných OPN čipů,Anzahl OPN Chips,,Nombro da imititaj OPL-blatoj,Número de chip OPN emulados,,Emuloitavien OPN-piirien lukumäärä,Puces OPN émulées,,Numero di chip OPN emulati,OPNチップエミュレートの番号,에뮬레이트된 OPN 칩 개수,Aantal geëmuleerde OPL chips,Liczba emulowanych czipów OPN,Número de chips OPN emulados,,Număr de cipuri OPN emulate,Количество эмулируемых чипов OPN,Број емулираних OPN чипова -Use custom WOPL bank,ADVSNDMNU_ADLCUSTOMBANK,,,,Použít vlastní WOPL sadu,Benutzerdefinierte WOPL Bank,,Uzi laŭmendan WOPL-bankon,Utilizar banco WOPL personalizado,,Käytä mukautettua WOPL-pankkia,Utiliser Banque WOPL perso,,Usa WOPL bank personalizzato,カスタム WOPL bankを使用,사용자 지정 WOPL 뱅크 사용,Gebruik de aangepaste WOPL bank,Użyj niestandardowego banku WOPL,Usar banco WOPL personalizado,,Utilizați propriul bank WOPN,Использовать собственный банк WOPL,Користи прилагођенуу WOPL банку -WOPL Bank file,ADVSNDMNU_OPLBANKFILE,,,,Soubor WOPL sady,WOPL Bank-Datei,,WOPL-Banko-arkivo,Archivo de banco WOPL,,WOPL-pankkitiedosto,Banque WOPL,,File WOPL Bank,WOPL bank ファイル,WOPL 뱅크 파일,WOPL Bank-bestand,Plik banku WOPL,Banco WOPL,,Fișier WOPN bank,Файл с банком WOPL,WOPL фајл банка -Use custom WOPN bank,ADVSNDMNU_OPNCUSTOMBANK,,,,Použít vlastní WOPN sadu,Benutzerdefinierte WOPN Bank,,Uzi laŭmendan WOPN bankon,Utilizar banco WOPN personalizado,,Käytä mukautettua WOPN-pankkia,Utiliser Banque WOPL perso,,Usa WOPN bank personalizzato,カスタム WOPN bankを使用,사용자 지정 WOPN 뱅크 사용,Gebruik aangepaste WOPN-bank op maat,Użyj niestandardowego banku WOPN,Usar banco WOPN personalizado,,Utilizați propriul bank WOPN,Использовать собственный банк WOPN,Користи прилагођену WOPN банку -WOPN Bank file,ADVSNDMNU_OPNBANKFILE,,,,Soubor WOPN sady,WOPN Bank-Datei,,WOPN Bankarkivo,Archivo de banco WOPN,,WOPN-pankkitiedosto,Banque WOPL,,File WOPN Bank,WOPN bank ファイル,WOPN 뱅크 파일,WOPN Bank-bestand,Plik banku WOPN,Banco WOPN,,Fișier WOPN bank,Файл с банком WOPN,WOPN фајл банка -Auto (Use setup of bank),ADLVLMODEL_AUTO,,,,Auto (použít nastavení sady),Auto (Benutze Einstelliung der Bank),,Aŭto (Uzi bankagordaĵon),Auto (Usar config. del banco),,Automaattinen (käytä pankin asetuksia),Auto (Utiliser paramètre banque),,Automatico (Usa le impostazioni del bank),自動 (bankのセットアップ使用),자동(뱅크 셋업 사용),Auto (gebruik instelling van de bank),Automatycznie (Użyj ustawień banku),Automático (Usar definições do banco),,Auto (configurare din bank),Авто (настройка из банка),Аутоматски (користи намештену банку) -Generic,ADLVLMODEL_GENERIC,,,,Standardní,Allgemein,,Komuna,Genérico,,Yleinen,Générique,,Generico,一般的,전형적,Algemeen,Ogólne,Genérico,,,Общий,Генерично -OPL Native,ADLVLMODEL_NATIVE,,,,Nativní OPL,OPL Nativ,,Nativa OPL,Nativo OPL,,Luontainen OPL,OPL Natif,,,OPL ネイティブ,고유 OPL,OPL Inheems,Natywne OPL,Nativo OPL,,OPL propriu,Собственный OPL,OPL домаћи -DMX,ADLVLMODEL_DMX,,,,,,,,,,,,,,,데이터 마이닝 확장,,,,,,, -Apogee,ADLVLMODEL_APOGEE,,,,,,,,,,,,,,,어포지,,,,,,, -Win9X-like,ADLVLMODEL_WIN9X,,,,Jako Windows 9X,Wie Windows 9X,,Kiel Win9X,Como Win9X,,Win9x-kaltainen,Comme Win9x,,,Win9X式,Win9X 같게,Win9X-achtige,Jak w Win9X,Estilo Win9X,,Similar cu Win9X,Похожая на Win9X,Као у Win9X-у -Module Replayer Options,MODMNU_TITLE,,,,Nastavení přehrávače modulů,Modul-Spieler-Optionen,,Agordoj por Modulo-reludilo,Opciones de reproductor de módulos,,Moduulisoitinasetukset,Options Lecteur de Module,,Opzioni Module replayer,モジュールリプレイヤー オプション,모듈 재생 설정,Module Speler Opties,Opcje Odtwarzacza Modułów,Opções de Reprodutor de Módulos,,Setări de redare module,Параметры воспроизведения модулей,Подешавања модуларног реплејера -Master volume,MODMNU_MASTERVOLUME,,,,Celková hlasitost,Grundlautstärke,,Ĉefvolumeno,Volumen maestro,,Yleisäänenvoimakkuus,Volume maître,,Volume master,全体音量,마스터 볼륨,Hoofdvolume,Całkowita głośność,Volume master,,Volum general,Общая громкость,Глацни звук -Quality,MODMNU_QUALITY,,,,Kvalita,Qualität,,Kvaliteco,Calidad,,Laatu,Qualité,,Qualità,クオリティ,품질,Kwaliteit,Jakość,Qualidade,,Calitate,Качество,Квалитет -Volume ramping,MODMNU_VOLUMERAMPING,,,,Křivka hlasitosti,Lautstärkeverhalten,,Volumeno-pligrandigado,Aumento gradual de Volumen,,Äänenvoimakkuuden kertyminen,Rampe du volume,,Ramping volume,音量ランピング,볼륨 램핑,Volume-aanvulling,Zwiększenie głośności,Rampa de volume,,Creștere volum,Наращивание громкости,Појачавање звука -Chip-o-matic,MODMNU_CHIPOMATIC,,,,,,,,,,,,,,チップ オー マチック,칩-오-매틱,,,,,,, -Video Mode,VIDMNU_TITLE,,,,Režim displeje,Videomodus,,Video-reĝimo,Modos de video,,Videotila,Mode Vidéo,,Modalità video,ビデオ 調整,화면 설정,Videomodus,Tryb Wideo,Modo de Vídeo,,Mod Video,Настройки видеорежима,Видео мод -Render Mode,VIDMNU_RENDERMODE,,,,Režim renderování,Rendermodus,,Bildigo-reĝimo,Modo de Renderizado,,Hahmonnustila,Mode de Rendu,,Modalità motore grafico,レンダラー,렌더링 설정,Render Mode,Tryb Renderowania,Modo de Renderização,,Mod Redare,Режим рендеринга,Рендер мод -Fullscreen,VIDMNU_FULLSCREEN,,,,Přes celou obrazovku,Vollbild,,Plena ekrano,Pantalla completa,,Koko näyttö,Plein écran,,Schermata piena,全画面,전체화면,Volledig scherm,Pełen Ekran,Tela cheia,Ecrã cheio,,Полный экран,Цео екран -Retina/HiDPI support,VIDMNU_HIDPI,,,,Podpora Retiny/HiDPI,Retina/HDPI-Unterstützung,,Retino/HiDPI subteno,Soporte para Retina/HiDPI,,Retina/HiDPI-tuki,Support Retina/HiDPI ,Retina/HiDPI támogatás,Supporto Retina/HiDPi,Retina/HiDPI サポート,망막/하이DPI 활성화,Retina / HiDPI-ondersteuning,Wsparcie Retina/HiDPI,Suporte para Retina/HiDPI,,Suport retină/HiDPI,Поддержка Retina/HiDPI,Retina/HiDPI подршка -Aspect ratio,VIDMNU_ASPECTRATIO,,,,Poměr stran,Seitenverhältnis,,Ekran-proporcio,Relación de aspecto,,Kuvasuhde,Rapport D'Aspect,Képarány,Proporzioni,アスペクト比,종횡비,Beeldverhouding,Wpółczynnik proporcji,Proporção de tela,Proporção de ecrã,Aspect imagine,Соотношение сторон,Однос гледишта -Force aspect ratio,VIDMNU_FORCEASPECT,,,,Vynutit poměr stran,Erzwinge Seitenverhältnis,,Devigi ekran-proporcion,Forzar relación de aspecto,,Pakota kuvasuhde,Forcer Rapport,,Forza le proporzioni,アスペクト比に従う,강제 종횡비,Geforceerde beeldverhouding,Wymuś współczynnik proporcji,Forçar proporção de tela,Forçar proporcção de ecrã,Forțează aspectul imaginii,Принудительное соотношение сторон,Присили однос гледишта -Forced ratio style,VIDMNU_CROPASPECT,,,,Vynucený poměr stran,Modus für erzwungenes Seitenverhältnis,,Maniero por devigi proporcion,Relación de aspecto forzada,,Kuvasuhteen pakotustapa,Style de Ratio forcé,,Forza lo stile delle proporzioni,比率の形式,강제 비율 스타일,Gedwongen verhouding stijl,Wymuszony styl współczynnika,Forçar tipo de proporção,,Tipul raportului de aspect forțat,Тип принудительного соотношения сторон,Присиљен стил односа -Enable 5:4 aspect ratio,VIDMNU_5X4ASPECTRATIO,,,,Povolit poměr stran 5:4,Erlaube 5:4 Seitenverhältnis,,Aktivigi 5:4 ekran-proporcion,Activar relación de aspecto 5:4,,Ota käyttöön 5:4-kuvasuhde,Activer Rapport 5:4,5:4 képarány engedélyezése,Abilita le proporzioni 5:4,5:4アスペクト比を可能にする,5:4 비율 사용,Inschakelen 5:4 beeldverhouding,Włącz współczynnik proporcji 5:4,Habilitar proporção 5:4,,Activează aspectul de imagine 5:4,Включить соотношение сторон 5:4,Омогући 5:4 однос гледишта -Resolution scale,VIDMNU_SCALEMODE,,,,Škálování rozlišení,Skalierung,,Distingivo-skalo,Escala de Resolución,,Resoluution skaalaus,Echelle de Résolution,,Scala di risoluzione,画面スケール,해상도 크기,Resolutie schaal,Skala rozdzielczości,Escala de resolução,,Scalare rezoluție,Масштабирование,Резолуцијска скала -Scale Factor,VIDMNU_SCALEFACTOR,,,,Faktor rozlišení,Skalierungsfaktor,,Skalfaktoro,Factor de Escala,,Skaalauskerroin,Facteur d'échelle,,Fattore di scala,スケール倍率,축척 펙터,Schaalfactor,Współczynnik Skali,Fator de escala,,Valoare scalare,Значение масштаба,Фактор скалирања -Use Linear Scaling (Fullscreen),VIDMNU_USELINEAR,,,,Použít lineární škálování (přes celou obrazovku),Lineare Skalierung (Vollbild),,Uzi Linian Skaladon (Plena ekrano),Usar Escalado Linear (Pant. Completa),,Lineaarinen skaalaus (koko näyttö),Mise à l'échelle Linéaire (Plein écran),,Usa lo scaling lineare (a schermo pieno),リニアスケールを使う(全画面),선형 스케일링 사용 (전체화면),Lineaire schaalverdeling gebruiken (volledig scherm),Użyj Liniowego Skalowania (Pełen Ekran),Usar escala linear (tela cheia),Usar escala linear (ecrã cheio),Scalare liniară (doar în Fullscreen),Линейное масштабирование (полный экран),Користи линеарно скалирање (цео екран) -Custom Pixel Scaling,VIDMNU_CUSTOMRES,,,,Vlastní škálování pixelů,Benutzerdefinierte Skalierung,,Agorda bildero-skalo,Escalado de Pixel Personalizado,,Mukautettu skaalaus,Résolution Personalisée,,Scaling dei pixel personalizzato,カスタム ピクセルスケール,사용자 지정 픽셀 크기 조정,Aangepaste Pixel Schaalvergroting,Niestandardowe Skalowanie Pikseli,Escala de Pixel Personalizada,,Scalare pixeli personalizată,Масштабирование пикселов,Пиксел скалирање -Custom Width,VIDMNU_CUSTOMX,,,,Vlastní šířka,Benutzerdefinierte Breite,,Agorda larĝo,Ancho Personalizado,,Mukautettu leveys,Largeur Personalisée,Egyéni szélesség,Lunghezza,カスタム 幅,사용자 지정 너비,Aangepaste breedte,Niestandardowa Szerokość,Largura Personalizada,,Lungime,Длина,Ширина -Custom Height,VIDMNU_CUSTOMY,,,,Vlastní výška,Benutzerdefinierte Höhe,,Agorda alto,Alto Personalizado,,Mukautettu korkeus,Hauteur Personalisée,Egyéni magasság,Altezza,カスタム 高さ,사용자 지정 높이,Aangepaste hoogte,Niestandardowa Wysokość,Altura Personalizada,,Înălțime,Высота,Висина -Apply Changes (Windowed),VIDMNU_APPLYW,,,,Použít změny (v okně),Änderungen anwenden (Fenster),,Apliki ŝanĝojn (Fenestrito),Aplicar Cambios (ventana),,Ota käyttöön muutokset (ikkuna),Appliquer Changements (Fenêtre),,Applica le modifiche (a finestra),変更を適用(ウィンドウ化),변경 적용 (윈도우),Wijzigingen toepassen (opgewonden),Zatwierdź Zmiany (Okno),Aplicar alterações (janela),,Aplică setările (mod Fereastră),Сохранить изменения (оконный режим),Примени промене (прозор) -Apply Changes (Fullscreen),VIDMNU_APPLYFS,,,,Použít změny (přes celou obrazovku),Änderungen anwenden (Vollbild),,Apliki ŝanĝojn (Plena ekrano),Aplicar Cambios (Pant. Completa),,Ota käyttöön muutokset (koko näyttö),Appliquer Changements (Plein écran),,Applica le modifiche (a schermo pieno),変更を適用(全画面化),변경 적용 (전체화면),Wijzigingen toepassen (Volledig scherm),Zatwierdź Zmiany (Pełen Ekran),Aplicar alterações (tela cheia),Aplicar alterações (ecrã cheio),Aplică setările (mod Fullscreen),Сохранить изменения (полный экран),Примени промене (цели екран) -Choose Resolution Preset,VIDMNU_RESPRESET,,,,Vybrat přednastavené rozlišení,Auflösungsvoreinstellung,,Elekti Agordaĵon por Distingivo,Seleccionar Preset de Resolución,,Valitse ennalta määritetty resoluutio,Choisir paramètre personalisé,,Scegli preset di risoluzione,解像度プリセットを選ぶ,해상도 사전 설정 선택,Kies een vooraf ingestelde resolutie,Wybierz Zestaw Rozdzielczości,Escolher Resolução Predefinida,,Alege o Rezoluție Presetată,Выбор пресета разрешения,Резолуцијска подешавања -Custom Resolution Presets,VIDMNU_RESPRESETTTL,,,,Vlastní přednastavení rozlišení,Benutzerdefinierte Auflösungsvoreinstellungen,,Laŭmendaj agordaĵoj por Distingivo,Seleccionar Preset de Resoluciones,,Ennalta määritetyt mukautetut resoluutiot,Résolutions Personalisée,,Preset di risoluzione personalizzati,カスタム解像度プリセット,사용자 지정 해상도 미리 조정,Vooraf ingestelde aangepaste resolutie,Niestandardowe Zestawy Rozdzielczości,Predefinições Personalizadas,,Rezoluție Presetată Personalizată,Пользовательские пресеты,Резолуцијска подешавања -Preset Resolution Modes,VIDMNU_RESPRESETHEAD,,,,Přednastavená rozlišení,Vordefinierte Auflösungsmodi,,Agordaĵaj Distingivreĝimoj,Modos de Preset de Resolución,,Ennalta määritetyt resoluutiotilat,Choisir mode de Résolution,,Modalità preset di risoluzione,解像度モードの調整,해상도 미리 조정 모드,Vooraf ingestelde resolutie modi,Tryby Zestawów Rozdzielczości,Modos de Resolução Predefinidas,,Moduri Rezoluții Presetate,Доступные разрешения,Постављени резолуцијски модови -4:3 Aspect,VIDMNU_ASPECT43,,,,Poměr stran 4:3,4:3 Seitenverhältnis,,4:3 Proporcio,Aspecto 4:3,,4:3-tilat,Rapport 4:3,,Aspetto 4:3,4:3アスペクト比,4:3 비율,,Proporcje 4:3,Proporção 4:3,,Aspect 4:3,Соотношение сторон 4:3,4:3 гледиште -5:4 Aspect,VIDMNU_ASPECT54,,,,Poměr stran 5:4,5:4 Seitenverhältnis,,5:4 Proporcio,Aspecto 5:4,,5:4-tilat,Rapport 5:4,,Aspetto 5:4,5:4アスペクト比,5:4 비율,,Proporcje 5:4,Proporção 5:4,,Aspect 5:4,Соотношение сторон 5:4,5:4 гледиште -16:9 Aspect,VIDMNU_ASPECT169,,,,Poměr stran 16:9,16:9 Seitenverhältnis,,16:9 Proporcio,Aspecto 16:9,,16:9-tilat,Rapport 16:9,,Aspetto 16:9,16:9アスペクト比,16:9 비율,,Proporcje 16:9,Proporção 16:9,,Aspect 16:9,Соотношение сторон 16:9,16:9 гледиште -16:10 Aspect,VIDMNU_ASPECT1610,,,,Poměr stran 16:10,16.10 Seitenverhältnis,,16:10 Proporcio,Aspecto 16:10,,16:10-tilat,Rapport 16:10,,Aspetto 16:10,16:10アスペクト比,16:10 비율,,Proporcje 16:10,Proporção 16:10,,Aspect 16:10,Соотношение сторон 16:10,16:10 гледиште -Network Options,NETMNU_TITLE,,,,Nastavení sítě,Netzwerkeinstellungen,,Retagordoj,Opciones de Red,,Verkkoasetukset,Options Réseau,,Opzioni network,ネットワーク オプション,네트워크 설정,Netwerkopties,Opcje Sieci,Opções de Rede,,Setări de Rețea,Настройки сети,Мрежна подешавања -Local options,NETMNU_LOCALOPTIONS,,,,Lokální nastavení,Lokale Einstellungen,,Lokaj agordoj,Opciones locales,,Paikallisasetukset,Options Locales,,Opzioni locali,ローカル オプション,로컬 설정,Lokale opties,Opcje Lokalne,Opções locais,,Setări Locale,Локальные настройки,Локална подешавања -Movement prediction,NETMNU_MOVEPREDICTION,,,,Predikce pohybu,Bewegungsvorausberechnung,,Movprognozado,Predicción de Movimiento,,Liikkeen ennakoiminen,Prédiction de Mouvement,,Predizione movimenti,移動予測,움직임 예측도,Voorspelling van bewegingen,Przewidywanie Ruchu,Previsão de movimento,,Anticipare mișcare,Предсказание движения,Предвиђање покрета -Predict line actions,NETMNU_LINESPECIALPREDICTION,,,,Predikce čárových akcí,Berechne Linienaktionen voraus,,Prognozi lini-agojn,Predecir acciones de línea,,Ennakoi viivasuorat toiminnat,Prédiction des actions de ligne,,Predizione azioni di linea,line actionsを予測する,라인 움직임 감지,Voorspel lijnacties,Przewidź akcje linii,Prever ações de linha,,Anticipează acționarea liniilor,Предсказание действий на уровне,Предвиђање линијске радње -Prediction Lerp Scale,NETMNU_PREDICTIONLERPSCALE,,,,Velikost interpolace predikce,Vorberechnungs Lerp-Skalierung,,Skalo de linia interpolado,Escala de interp. lineal de predicción,,Lineaarisen interpolaatioennakoinnin skaalaus,Prédiction d'échelle LERP,,Scala Lerp predizione,リープスケール予測,러프 예측 강도,Voorspelling Lerp Scale,Przewidywanie Skali Lerp,Escala de previsão de LERP,,Anticipare scară lerp,Предсказание масштаба лэрпа,Предвиђање лерп скале -Lerp Threshold,NETMNU_LERPTHRESHOLD,,,,Práh interpolace,Lerp-Schwellwert,,Limito de linia interpolado,Umbral de interp. lineal,,Interpolaatiokynnys,Limite LERP,,Soglia Lerp,リープ敷居置,러프 계산,Lerp Threshold,Próg Lerp,Limite de LERP,,Prag Lerp,Порог лэрпа,Лерп праг -Host options,NETMNU_HOSTOPTIONS,,,,Nastavení hostitele,Gastoptionen,,Agordoj de Gastiganto,Opciones de Host,,Isäntäasetukset,Options Hôte,,Opzioni ospitante,ホスト オプション,호스트 설정,Verhuurders opties,Opcje hosta,Opções de host,,Setări gazdă,Настройки хоста,Подешавања домаћина -Extra Tics,NETMNU_EXTRATICS,,,,Extra tiky,,,Ekstraj Tikoj,Tics Extra,,Lisäticit,Tics supplémentaires,,Tics extra,予備秒数,추가 틱,,Dodatkowe tiki,Tics extras,,Ticuri suplimentare,Дополнительные тики,Додатни тикови -Latency balancing,NETMNU_TICBALANCE,,,,Vyrovnání latence,Latenzbalance,,Respondotempo-balancado,Balanceo de latencia,,Viiveen tasapainoitus,Equilibrage de latence,,Bilanciamento latenza,レイテンシーバランス,지연 시간 조정,Latency balans,Balans czasu oczekiwania,Equilíbrio de latência,,Întârzierea echilibrării,Балансировка задержки,Балансирање кашњења -Enable controller support,JOYMNU_ENABLE,,,,Povolit podporu pro ovladače,Erlaube Controllerunterstützung,,Aktivigi ludregilsubtenon,Activar soporte de mandos,,Ota käyttöön peliohjaintuki,Activer support contrôleur,,Abilita il supporto del controller,コントローラーサポート許可,컨트롤러 지원 허용,Controllerondersteuning inschakelen,Włącz wsparcie kontrolera,Habilitar suporte de controles,,Activare suport controller,Включить поддержку контроллера,Омогући подршку за контролере -Enable DirectInput controllers,JOYMNU_DINPUT,,,,Povolit ovladače DirectInput,Erlaube DirectInput-Controller,,Aktivigi DirectInput ludregilojn,Usa controles DirectInput,,Ota käyttöön DirectInput-ohjaimet,Activer contrôleurs DirectInput,,Abilita i controlli DirectInput,ダイレクトインプットコントローラー許可,다이렉트 인풋 컨트롤러 허용,DirectInput-controllers inschakelen,Włącz kontrolery DirectInput,Habilitar controles DirectInput,,Activare controllere de tip DirectInput,Включить контроллеры DirectInput,Омогући директинпут контролере -Enable XInput controllers,JOYMNU_XINPUT,,,,Povolit ovladače XInput,Erlaube XInput-Controller,,Aktivigi XInput ludregilojn,Usa controles XInput,,Ota käyttöön XInput-ohjaimet,Activer contrôleurs XInput,,Abilita i controlli XInput,Xinput コントローラー許可,X인풋 컨트롤러 허용,XInput-controllers inschakelen,Włącz kontrolery XInput,Habilitar controles XInput,,Activare controllere de tip XInput,Включить контроллеры XInput,Омогући Иксинпут контролере -Enable raw PlayStation 2 adapters,JOYMNU_PS2,,,,Povolit ovladače PlayStation 2,Erlaube Playstation 2-Controller,,Aktivigi krudajn PlayStation 2 adaptilojn,Usa adaptadores de PlayStation 2,,Ota käyttöön raa'at PlayStation 2 -adapterit,Activer adaptateurs PS2 bruts,,Abilita gli adattatori raw PlayStation 2,PlayStation2 アダプター許可,PS2 어뎁터 허용,Raw PlayStation 2-adapters inschakelen,Włącz adaptery PlayStation 2,Habilitar adaptadores de PlayStation 2,,Utilizează direct adaptoarele PlayStation 2,Использовать адаптеры PlayStation 2 напрямую,Омогући сирове Плејстејшн 2 адаптере -No controllers detected,JOYMNU_NOCON,,,,Nenalezeny žádné ovladače.,Keine Controller gefunden,,Neniu ludregilojn detektas,No hay mandos detectados,,Ei havaittuja ohjaimia,Aucun Contrôleur détecté.,,Nessun controller trovato,コントローラーが見つかりません,인식된 컨트롤러 없음,Geen controllers gedetecteerd,Nie wykryto kontrolerów,Nenhum controle detectado,Nenhum comando foi detectado,Niciun controller detectat,Контроллеры не обнаружены,Нема детектованих контролера -Configure controllers:,JOYMNU_CONFIG,,,,Nastavit ovladače:,Controller konfigurieren,,Agordi ludregilojn:,Configurar controles:,,Mukauta ohjaimia:,Configurer contrôleurs:,,Configura i controller:,コントローラー構成:,컨트롤러 설정:,Configureer controllers:,Konfiguruj kontrolery:,Configurar controles:,Configurar comandos,Configurare controllere:,Настроить контроллер:,Подешавања контролере: -Controller support must be,JOYMNU_DISABLED1,,,,Podpora ovladačů musí být,Controllerunterstütung muss aktiviert sein,,Ludregilsubteno devas esti,El soporte de mandos debe estar,,Ohjaintuen täytyy olla otettu,Le Support de contrôleur doit être activé,,Il supporto ai controller deve essere,検出するにはコントローラーサポートを,감지하려면 컨트롤러 지원을,Controller ondersteuning moet ingeschakeld zijn,Wsparcie kontrolera musi być,Suporte à controles deve ser,Suporte a comandos devem ser,Suportul pentru controllere trebuie să,Включите поддержку контроллера,Омогућите подржавање контролера -enabled to detect any,JOYMNU_DISABLED2,Supposed to be empty in Russian and Serbian.,,,zapnuta pro jejich detekování.,um welche zu finden,,ŝaltita detekti ajn,activado para detectar alguno,,käyttöön ohjainten havaitsemiseksi,avant de pouvoir en détecter un.,,abilitato a trovare ogni,許可する必要があります,활성화 해야합니다.,om eventuele regelaars te detecteren.,Włączony by wykryć jakikolwiek,habilitado para poder detectar algum,,fie activat pentru a le putea detecta, \n, \n -Invalid controller specified for menu,JOYMNU_INVALID,,,,Vybrán nesprávný ovladač pro nabídky,Ungültiger Controller für Menü ausgewählt,,Malprava ludregilo specifigis por menuo,Mando inválido especificado para el menú,,Epäkelpo ohjain määritetty valikolle,Contrôleur invalide spécifé dans le menu.,,Controller invalido specificato per il menu,メニューではコントローラーを使用しない,메뉴에 특정된 컨트롤러가 아닙니다.,Ongeldige regelaar gespecificeerd voor het menu,Niewłaściwy kontroler określony dla menu,Controle inválido especificado para o menu,Comando inválido,Controller ales pentru meniu invalid,Недопустимый контроллер выбран для меню,Невалидан контролер специфиран за мени -Overall sensitivity,JOYMNU_OVRSENS,,,,Celková citlivost,Allgemeine Empfindlichkeit,,Tutsentemeco,Sensibilidad general,,Yleisherkkyys,Sensibilité générale,,Sensibilità generale,全体的な感度,전체 민감도,Algemene gevoeligheid,Ogólna Czułość,Sensibilidade geral,,Sensibilitate per ansamblu,Общая чувствительность,Уупна сензитивност -Axis Configuration,JOYMNU_AXIS,,,,Nastavení os,Achsenkonfiguration,,Akso-agordoj,Configuración del eje,,Akseleiden säätäminen,Configuration des axes,,Configurazione assi,軸構成,축 구성,Asconfiguratie,Konfiguruj Oś,Configuração de Eixo,,Configurația axei,Конфигурация осей,Конфигурација осе -Invert,JOYMNU_INVERT,,,,Obrátit,Invertieren,,Inversigi,Invertir,,Käännä,Inverser,,Inverti,反転,순서 바꿈,Omkeren,Odwróć,Inverter,,Inversare,Инвертировать,Инвертовано -Dead zone,JOYMNU_DEADZONE,,,,Mrtvá zóna,Totzone,,Mortzono,Zona muerta,,Kuollut alue,Zone neutre,,Zona cieca,デッドゾーン,불감대,Dode zone,Martwa strefa,Zona morta,,Zonă moartă,Мёртвая зона,Мртва зона -No configurable axes,JOYMNU_NOAXES,,,,Žádné nastavitelné osy,Keine konfigurierbaren Achsen,,Neniu agordeblaj aksoj,No hay ejes configurables,,Ei säädettäviä akseleita,Aucun axe à configurer,,Nessun asse configurabile,軸構成を無効,설정할 방향키가 없습니다.,Geen configureerbare assen,Brak osi do skonfigurowania,Sem eixos configuráveis,,Nicio axă nu este configurabilă,Нет настраиваемых осей,Нема конфигурационих оса -Off,OPTVAL_OFF,,,,Vyp.,Aus,,Malaktiva,Desactivado,,Pois,,,Disattivo,オフ,끔,Uit,Wyłączone,Desligado,,Pornit,Откл.,Искљ. -On,OPTVAL_ON,,,,Zap.,An,,Aktiva,Activado,,Päällä,,,Attivo,オン,켬,Aan,Włączone,Ligado,,Oprit,Вкл.,Укљ. -Auto,OPTVAL_AUTO,,,,,,,Aŭtomata,Automático,,Automaattinen,,,Automatico,自動,자동,,Automatycznie,Automático,,,Авто,Аутоматски -Male,OPTVAL_MALE,,,,Muž,Männlich,,Vira (Li),Masculino,,Miespuolinen,Masculin,,Maschio,男,남성,Man,Mężczyzna,Masculino,,Masculin,Мужской,Мушко -Female,OPTVAL_FEMALE,,,,Žena,Weiblich,,Ina (Ŝi),Femenino,,Naispuolinen,Féminin,,Femmina,女,여성,Vrouw,Kobieta,Feminino,,Feminin,Женский,Женско -Neutral,OPTVAL_NEUTRAL,,,,Neutrální,Neutral,,Neŭtrala (Ri),Neutro,,Sukupuoleton,Neutre,,Neutrale,中間,중성,Neutraal,Neutralne,Neutro,,Neutru,Нейтральный,Неутрално -Object,OPTVAL_OTHER,,,,Objekt,Objekt,,Objekto (Ĝi),Objeto,,Olio,Objet,,Oggetto,物体,기타,Doel,Obiekt,Objeto,,Obiect,Предмет,Предмет -Upper left,OPTVAL_UPPERLEFT,,,,Vlevo nahoře,Oben links,,Supra maldekstre,Sup. izquierda,,Ylävasemmalla,Supérieur gauche,,Superiore sinistro,左上,왼쪽 위,Linksboven,Lewy górny róg,Esquerda superior,,Stânga sus,Вверху слева,Горње лево -Upper right,OPTVAL_UPPERRIGHT,,,,Vpravo nahoře,Oben rechts,,Supra dekstre,Sup. derecha,,Yläoikealla,Supérieur droite,,Superiore destro,右上,오른쪽 위,Rechtsboven,Prawy górny róg,Direita superior,,Dreapta sus,Вверху справа,Горње десно -Lower left,OPTVAL_LOWERLEFT,,,,Vlevo dole,Unten links ,,Suba maldekstre,Inf. izquierda,,Alavasemmalla,Inférieur gauche,,Inferiore sinistro,左下,왼쪽 밑,Linksonder,Lewy dolny róg,Esquerda inferior,,Stânga jos,Внизу слева,Доње лево -Lower right,OPTVAL_LOWERRIGHT,,,,Vpravo dole,Unten rechts,,Suba dekstre,Inf. derecha,,Alaoikealla,Inférieur droite,,Inferiore destro,右下,오른쪽 밑,Rechtsonder,Prawy dolny róg,Direita inferior,,Dreapta jos,Внизу справа,Доње десно -Touchscreen-like,OPTVAL_TOUCHSCREENLIKE,,,,Jako dotyková obrazovka,Wie auf einem Touchscreen,,Tuŝekrana,Pant. táctil,,Kosketusnäyttömäinen,Style écran tactile,,Come il Touchscreen,タッチスクリーン式,터치스크린 같게,Touchscreen-achtige,Jak ekrean dotykowy,Estilo touchscreen,,Precum ecranul tactil,Как сенсорный экран,Као додирни екран -None,OPTVAL_NONE,,,,Žádný,Kein,,Neniu,Ninguno,,Ei mitään,Aucun,,Nessuno,無し,없음,Geen,Żaden,Nenhum,,Nimic,Откл.,Ништа -Turning,OPTVAL_TURNING,,,,Otáčení,Umdrehen,,Turnanta,Girar,,Kääntyminen,Tourner,,Rotazione,旋回,회전,Draaien,Obracanie się,Girar,,Rotire,Поворот,Скретање -Looking Up/Down,OPTVAL_LOOKINGUPDOWN,,,,Dívání se nahoru/dolů,Hoch/runterblicken,,Rigardanta Supre/Malsupre,Mirar hacia Arriba/Abajo,,Ylös/Alas katsominen,Vue haut/bas,,Sguardo Sopra/Sotto,視点上下,위/아래로 보기,Omhoog/omlaag zoeken,Patrzenie w górę/w dół,Olhar para cima/baixo,,Privire în sus/jos,Взгляд вверх/вниз,Гледање горе/доле -Moving Forward,OPTVAL_MOVINGFORWARD,,,,Pohyb vpřed,Vorwärtsbewegung,,Movanta Rekte,Avanzar,,Eteenpäin liikkuminen,Avancer,,Movimento in avanti,前進,앞으로 전진,Voorwaarts bewegen,Poruszanie się do przodu,Mover para a frente,,Deplasare în față,Движение вперёд,Кретање напред -Strafing,OPTVAL_STRAFING,,,,Pohyb do stran,Seitwärtsbewegung,,Flankmovanta,Desplazarse,,Sivuttaisastunta,Pas de côté,,Movimento laterale,横移動,양옆으로 이동,Strafelen,Uniki,Deslocamento lateral,,Deplasare în diagonală,Движение боком,Кретање у страну -Moving Up/Down,OPTVAL_MOVINGUPDOWN,,,,Pohyb nahoru/dolů,Auf/abwärtsbewegung,,Movanta Supre/Malsupre,Moverse hacia Arriba/Abajo,,Ylös/Alas liikkuminen,Mouvement haut/bas,,Movimento Sopra/Sotto,前進後退,위/아래로 이동,Naar boven/beneden bewegen,Poruszanie się w górę/w dół,Deslocar para cima/baixo,,Deplasare în sus/jos,Движение вверх/вниз,Кретање горе/доле -Inverted,OPTVAL_INVERTED,,,,Inverzní,Invertiert,,Inversigita,Invertido,,Käännetty,Inversé,,Invertito,反転する,반전,Omgekeerd,Odwrócony,Invertido,,Inversat,Инвертировано,Обрнуто -Not Inverted,OPTVAL_NOTINVERTED,,,,Nikoliv inverzní,nicht invertiert,,Ne Inversigita,No invertido,,Ei käännetty,Non Inversé,,Non invertito,反転しない,반전되지 않음,Niet omgekeerd,Nieodwrócony,Não Invertido,,Neinversat,Прямо,Не обрнуто -Original,OPTVAL_ORIGINAL,,,,Původní,,,Originala,,,Alkuperäinen,Original,,Originale,オリジナル,원형,Origineel,Oryginalny,Original,,,Оригинальный,Оригинално -Optimized,OPTVAL_OPTIMIZED,,,,Optimalizovaný,Optimiert,,Optimumigita,Optimizado,,Optimoitu,Optimisé,,Ottimizzato,最適化,최적화 형,Geoptimaliseerd,Zoptymalizowany,Otimizado,,Optimizat,Оптимизированный,Оптимизовано -Classic (Faster),OPTVAL_CLASSIC,,,,Klasický (rychlejší),Klassisch (schneller),,Klasika (Pli rapide),Clásico (Más rápido),,Perinteinen (nopeampi),Classique (+ Rapide),,Classico (più veloce),旧式(速度重視),구형 (빠르게),Klassiek (sneller),Klasyczny (szybszy),Clássico (Mais rápido),,Clasic (Mai rapid),Классический (быстрее),Класични (бржи) -Precise,OPTVAL_PRECISE,,,,Přesný,Genau,,Preciza,Preciso,,Tarkka,Précis,,Preciso,精密,정확하게,Nauwkeurig,Dokładny,Preciso,,Precis,Точный,Прецизно -Normal,OPTVAL_NORMAL,,,,Normální,,,Normala,,,Normaali,,,Normale,通常,기본형,Normaal,Normalny,Normal,,,Обычный,Нормално -Stretch,OPTVAL_STRETCH,,,,Roztažený,Strecken,,Streĉi,Estrechado,Estrecho,Venytetty,Etirer,,Disteso,伸縮,늘림,Rek,Rozciągnięty,Esticado,,Lărgește,Растянутый,Растегнуто -Capped,OPTVAL_CAPPED,,,,Uzavřený,Limitiert,,Limitigita,Limitado,,Rajoitettu,Limité,,Limitato,上限,색상에 맞게,Afgeschermd,Ograniczony,Limitado,,Limitat,Ограниченный,Ограничено -Particles,OPTVAL_PARTICLES,,,,Částice,Partikel,,Partikloj,Partículas,,Hiukkasina,Particules,,Particelle,パーティクル,입자만,Deeltjes,Cząstki,Partículas,,Particule,Частицы,Честице -Sprites,OPTVAL_SPRITES,,,,Sprity,Sprites,,Spritoj,,,Spriteinä,,,Sprite,スプライト,스프라이트만,Sprites,Sprite'y,Sprites,,,Спрайты,Спрајтови -Sprites & Particles,OPTVAL_SPRITESPARTICLES,,,,Sprity a částice,Sprites und Partikel,,Spritoj kaj Partikloj,Sprites y partículas,,Spriteinä ja hiukkasina,Sprites & Particules,,Sprite e particelle,スプライト & パーティクル,스프라이트+입자,Sprites & Deeltjes,Sprite'y i cząstki,Sprites & Partículas,Sprites e Partículas,Sprite-uri & Particule,Спрайты и частицы,Спрајтови и честице -Melt,OPTVAL_MELT,,,,Rozpuštění,Verlauf,,Fandi,Derretir,,Sulaminen,Fondu,,Scioglimento,メルト,녹는 효과,Smelten,Stopienie,Derreter,,Topire,Таяние,Топљење -Burn,OPTVAL_BURN,,,,Oheň,Einbrennen,,Bruli,Quemar,,Palaminen,Brûlure,,Bruciamento,バーン,타는 효과,Verbranden,Wypalenie,Queimar,,Ardere,Жжение,Спаљивање -Crossfade,OPTVAL_CROSSFADE,,,,Prolínačka,Überblenden,,Transvelki,Entrelazar,,Ristihäivytys,Fondu en croix,,Dissolvenza a croce,クロスフェード,화면 교차,Crossfade,Przenikanie,Dissolver,,Ofilire,Увядание,Вењење -Only modified,OPTVAL_ONLYMODIFIED,,,,Pouze upravené,Nur modfizierte,,Sole modifita,Solo modificados,,Vain muunneltu,Modifié seulement,,Solo modificato,モディファイのみ,수정된 것만,Alleen gewijzigd,Tylko zmodyfikowane,Somente modificado,,Numai în modificări,Только в модификациях,Само модификовано -Smooth,OPTVAL_SMOOTH_1,"This setting is duplicated in order to allow for different grammatical gender endings in the Russian language (and any other language that depends on a grammatical gender system). In English, due to the lack of a grammatical gender system, both option values are the same.",,,Vyhlazený,Glatt,,Glata,Fluido,,Pehmeä,Lisse,,Liscio,スムーズ,부드럽게,Glad,Gładki,Suavizado,,Fin,Плавная,Глатко -Smooth,OPTVAL_SMOOTH_2,,,,Vyhlazené,Glatt,,Glata,Fluido,,Pehmeä,Lisse,,Liscio,スムーズ,부드럽게,Glad,Gładka,Suavizado,,Fin,Плавные,Глатко -Translucent,OPTVAL_TRANSLUCENT,,,,Průhledný,Transparent,,Diafana,Translúcido,,Läpikuultava,Transparent,,Traslucido,半透明,투명하게,Doorschijnend,Przeświecający,Translúcido,,Transparent,Полупрозрачный,Прозрачно -Fuzz,OPTVAL_FUZZ,,,,Šum,Fuzz,,Lanugo,Borroso,,Sumeus,Bruit Blanc,,,ファズ,퍼즈 효과,Fuzz,Szum,Difuso,,Sclipitor,Шумовой,Фаз -Shadow,OPTVAL_SHADOW,,,,Stín,Schatten,,Ombro,Sombra,,Varjo,Ombre,,Ombra,シャドウ,그림자 효과,Schaduw,Cień,Sombra,,Umbră,Теневой,Сенка -Items,OPTVAL_ITEMS,,,,Předměty,Gegenstände,,Aĵoj,Objetos,,Esineet,Objets,,Oggetti,アイテム,아이템들,Artikelen,Przedmioty,Itens,,Obiecte,Предметы,Предмет -Weapons,OPTVAL_WEAPONS,,,,Zbraně,Waffen,,Armiloj,Armas,,Aseet,Armes,,Armi,武器,무기들,Wapens,Bronie,Armas,,Arme,Оружие,Оружја -Both,OPTVAL_BOTH,,,,Obojí,Beide,,Ambaŭ,Ambos,,Molemmat,Les Deux,,Entrambi,両方,둘 다,Beide,Oba,Ambos,,Ambele,Оба,Оба -ZDoom,OPTVAL_ZDOOM,,,,,,,,,,,,,,,Z둠,,,,,,, -Strife,OPTVAL_STRIFE,,,,,,,,,,,,,,,스트라이프,,,,,,, -Player,OPTVAL_PLAYER,,,,Hráč,Spieler,,Ludanto,Jugador,,Pelaaja,Joueur,,Giocatore,プレイヤー,플레이어,Speler,Gracz,Jogador,,Jucător,Игрок,Играч -Map,OPTVAL_MAP,,,,Level,Level,,Mapo,Mapa,,Kartta,Niveau,,Mappa,マップ,맵,Kaart,Mapa,Mapa,,Hartă,Карта,Мапа -Scale to 640x400,OPTVAL_SCALETO640X400,,,,Zvětšit na 640x400,Skaliere auf 640x400,,Skali al 640x400,Escalar a 640x400,,Skaalaa resoluutioon 640x400,Echelle 640x400,,Scala a 640x400,640x400スケール,640x400까지 확대,Schaal tot 640x400,Skaluj do 640x400,Escalar para 640x400,,Dimensionare la 640x480,Масштабировать до 640x400,Скалирај на 640x400 -Pixel double,OPTVAL_PIXELDOUBLE,,,,Zdvojení pixelů,Pixelverdopplung,,Bilderon duobligi,Pixel doble,,Kuvapistekaksinkertaistus,,,Pixel doppi,ピクセル2倍,2배 픽셀,Pixel dubbel,Dwukrotnie więcej pikseli,Pixel duplo,,Dublare pixeli,Двойные пиксели,Дупли пиксел -Pixel quadruple,OPTVAL_PIXELQUADRUPLE,,,,Zčtyřnásobení pixelů,Pixelvervierfachung,,Bilderon kavarobligi,Pixel cuádruple,,Kuvapistenelinkertaistus,,,Pixel quadrupli,ピクセル4倍,4배 픽셀,Pixel viervoudig,Czterokrotnie więcej pikseli,Pixel quádruplo,,Împătrire pixeli,Четверные пиксели,Четвороструки пиксел -Current weapon,OPTVAL_CURRENTWEAPON,,,,Současná zbraň,Aktuelle Waffe,,Nuntempa armilo,Arma actual,,Nykyinen ase,Arme actuelle,,Arma corrente,使用中の武器,현 무기,Huidig wapen,Aktualna broń,Arma atual,,Arma curentă,текущего оружия,Тренутно оружје -Available weapons,OPTVAL_AVAILABLEWEAPONS,,,,Dostupně zbraně,Verfügbare Waffen,,Haveblaj armiloj,Armas disponibles,,Käytettävissä olevat aseet,Armes Disponibles,,Armi disponibili,所持してる武器,사용 가능한 무기들,Beschikbare wapens,Dostępne bronie,Armas disponíveis,,Arme disponibile,доступного оружия,Доступно оружје -All weapons,OPTVAL_ALLWEAPONS,,,,Všechny zbraně,Alle Waffen,,Ĉiuj armiloj,Todas las armas,,Kaikki aseet,Toutes les armes,,Tutte le armi,全ての武器,모든 무기들,Alle wapens,Wszystkie bronie,Todas as armas,,Toate armele,всех видов оружия,Сва оружја -"Level, milliseconds",OPTVAL_LEVELMILLISECONDS,,,,"Level, milivteřiny","Level, Millisekunden",,"Nivelo, milisekundoj","Nivel, milisegundos",,"Taso, millisekunnit","Niveau, milisecondes",,"Livello, millisecondi","現場, ミリ秒","레벨, 밀리초당","Niveau, milliseconden","Poziom, milisekundy","Fase, milisegundos","Nível, milisegundos","Nivel, milisecunde","Уровень, миллисекунды","Ниво, милисекунде" -"Level, seconds",OPTVAL_LEVELSECONDS,,,,"Level, vteřiny","Level, Sekunden",,"Nivelo, sekundoj","Nivel, segundos",,"Taso, sekunnit","Niveau, secondes",,"Livello, secondi","現場, 秒","레벨, 초당","Niveau, seconden","Poziom, sekundy","Fase, segundos","Nível, segundos","Nivel, secunde","Уровень, секунды","Ниво, секунде" -Level,OPTVAL_LEVEL,,,,Level,Level,,Nivelo,Nivel,,Taso,Niveau,,Livello,現場,레벨,Niveau,Poziom,Fase,Nível,Nivel,Уровень,Ниво -"Hub, seconds",OPTVAL_HUBSECONDS,,,,"Hub, vteřiny","Hub, Sekunden",,"Rekontejo, sekundoj","Hub, segundos",,"Tasokokoelma, sekunnit","Hub, secondes",,"Hub, secondi","区間, 秒","허브, 초당","Naaf, seconden","Hub, sekundy","Hub, segundos",,"Hub, secunde",Хаб (секунды),"Хуб, секунде" -Hub,OPTVAL_HUB,,,,Hub,Hub,,Rekontejo,Hub,,Tasokokoelma,Hub,,Hub,区間,허브,Naaf,,,,,Хаб,Хуб -"Total, seconds",OPTVAL_TOTALSECONDS,,,,"Celkem, vteřiny","Gesamt, Sekunden",,"Tuto, sekundoj","Total, segundos",,"Yhteensä, sekunnit","Total, secondes",,"Totale, secondi","合計, 秒","누적 경과, 초당","Totaal, seconden","Totalne, sekundy","Total, segundos",,"Total, secunde",Общее (секунды),"Тотал, секунде" -Total,OPTVAL_TOTAL,,,,Celkem,Gesamt,,Tuto,,,Yhteensä,Total,,Totale,合計,누적 경과,Totaal,Totalne,,,Total,Общее,Тотал -"System, seconds",OPTVAL_SYSTEMSECONDS,,,,"Systém, vteřiny","System, Sekunden",,"Sistemo, sekundoj","Sistema, segundos",,"Järjestelmä, sekunnit","Système, secondes",,"Sistema, secondi","PC時刻, 秒","시스템, 초당","Systeem, seconden","System, sekundy","Sistema, segundos",,"Sistem, secunde",Система (секунды),"Систем, секунде" -System,OPTVAL_SYSTEM,,,,Systém,System,,Sistemo,Sistema,,Järjestelmä,Système,,Sistema,PC時刻,시스템,Systeem,System,Sistema,,Sistem,Система,Систем -Netgames only,OPTVAL_NETGAMESONLY,,,,Pouze v síťové hře,Nur Netzwerkspiele,,Retludoj sole,Sólo para juegos en red,,Vain verkkopelit,Parties en Ligne seulement,,Solo giochi net,オンラインのみ,멀티플레이에만,Alleen Netspellen,Tylko gry sieciowe,Jogos em rede apenas,,Doar în rețea,Только сетевые игры,Мрежне игре само -Always,OPTVAL_ALWAYS,,,,Vždy,Immer,,Ĉiam,Siempre,,Aina,Toujours,,Sempre,常に,언제나,Altijd,Zawsze,Sempre,,Mereu,Всегда,Увек -Image and Text,OPTVAL_AMMOIMAGETEXT,,,,Obrázek a text,Bild und Text,,Bildo kaj Teksto,Imagen y texto,,Kuva ja teksti,Image et Texte,,Immagini e testo,画像と字,이미지와 텍스트,Beeld en tekst,Obraz i Tekst,Imagem e texto,,Imagine si Text,Изображение и текст,Слика и текст -Text and Image,OPTVAL_AMMOTEXTIMAGE,,,,Text a obrázek,Text und Bild,,Teksto kaj Bildo,Texto e imagen,,Teksti ja kuva,Texte et Image,,Testo e immagini,字と画像,텍스트와 이미지,Tekst en beeld,Tekst i Obraz,Texto e imagem,,Text si Imagine,Текст и изобр.,Текст и слика -Scripts Only,OPTVAL_SCRIPTSONLY,,,,Pouze skripty,Nur Skripte,,Skriptoj Sole,Sólo scripts,,Vain komentosarjat,Scripts seulement,,Solo script,スクリプトのみ,스크립트에만,Alleen scripts,Tylko skrypty,Scripts apenas,,Numai scripturi,Только скрипты,Само скрипте -Never,OPTVAL_NEVER,,,,Nikdy,Nie,,Neniam,Nunca,,Ei koskaan,Jamais,,Mai,しない,없음,Nooit,Nigdy,Nunca,,Niciodată,Никогда,Никад -All,OPTVAL_ALL,,,,Všechny,Alle,,Ĉiuj,Todos,,Kaikki,Tout,,Tutti,全て,모두 작동,Alle,Wszystko,Todos,,Tot,Все,Све -Only last one,OPTVAL_ONLYLASTONE,,,,Pouze poslední,Nur das letzte,,Nur fino,Sólo el ultimo,,Vain viimeinen,Dernier seulement,,Solo l'ultimo,最後のみ,오직 마지막 것만,Alleen de laatste,Tylko ostatni,Somente o último,Apenas o último,Doar ultimul,Только последнее,Само последњи -Custom,OPTVAL_CUSTOM,,,,Vlastní,Benutzerdefiniert,,Laŭmenda,Personalizado,,Mukautettu,Modifié,,Personalizzato,カスタム,사용자 지정,Gebruiker gedefinieerd,Niestandardowe,Personalizado,,Personalizat,Польз.,Прилагођ. -Traditional Doom,OPTVAL_TRADITIONALDOOM,,,,Tradiční Doom,Doom traditionell,,Tradicia Doom,Doom tradicional,,Perinteinen Doom,Doom Traditionnel,,Doom tradizionale,正式DOOM,전형적인 둠 스타일,Traditioneel Doom,Tradycyjny Doom,Doom Tradicional,,Tradițional Doom,Цвета из Doom,Традиционални Doom -Traditional Strife,OPTVAL_TRADITIONALSTRIFE,,,,Tradiční Strife,Strife traditionell,,Tradicia Strife,Strife tradicional,,Perinteinen Strife,Strife Traditionnel,,Strife tradizionale,正式Strife,전형적인 스트라이프 스타일,Traditionele Strife,Tradycyjny Strife,Strife Tradicional,,Tradițional Strife,Цвета из Strife,Традиционални Strife -Traditional Raven,OPTVAL_TRADITIONALRAVEN,,,,Tradiční Raven,Raven traditionell,,Tradicia Raven,Raven tradicional,,Perinteinen Raven,Raven Traditionnel,,Raven tradizionale,正式Raven,전형적인 레이븐 스타일,Traditionele Raven,Tradycyjny Raven,Raven Tradicional,,Tradițional Raven,Цвета из Raven,Традиционални Raven -Only when found,OPTVAL_ONLYWHENFOUND,,,,Pouze po nalezení,Nur wenn gefunden,,Nur kiam trovita,Una vez encontrados,,"Vain, kun löydetty",Seulement découverts,,Solo quando trovato,発見時のみ,획득했을 때만,Alleen wanneer gevonden,Tylko gdy znaleziono,Somente quando encontrado,Apenas quando encontrado,Doar la descoperire,После обнаружения,Само кад је пронађен -On for overlay only,OPTVAL_ONFOROVERLAYONLY,,,,Pouze v překryvném režimu,Nur auf Overlay,,Sur por nur surmeto,Sólo para superpuesto,,Päällä vain karttaprojisoinnin kanssa,On pour Surimpression,,Solo attivo per la sovrapposizione,オーバーレイ専用,오버레이에만 작동,Alleen op voor overlay alleen voor overlay,Włączony tylko dla nakładek,Ativado somente para sobreposição,Apenas ativado para sobreposição,Doar pentru transparent,Только прозрачный,Укључен само за навлаку -Overlay+Normal,OPTVAL_OVERLAYNORMAL,,,,Překryv + normální,Overlay+Normal,,Surmento+Normale,Superpuesto+Normal,,Projisointi+tavallinen,Surimpression+Normal,,Sovrapposizione+Normale,オーバーレイ+通常,오버레이+기본,Overlay+Normaal,Nakładka+Normalnie,Sobreposição+Normal,,Transparent + Normal,Прозрачный + обычный,Навлака + нормално -Overlay Only,OPTVAL_OVERLAYONLY,,,,Pouze překryv,Nur Overlay,,Nur Surmento,Sólo superpuesto,,Vain projisointi,Surimpression seulement,,Solo Sovrapposizione,オーバーレイのみ,오버레이만,Alleen Overlay,Tylko Nakładka,Sobreposição apenas,,Doar transparent,Только прозрачный,Навлак само -Not for hubs,OPTVAL_NOTFORHUBS,,,,Ne pro huby,Nicht für Hubs,,Ne por huboj,No para hubs,,Ei tasokokoelmille,Pas pour les hubs,,Non per gli hub,区間では出さない,허브는 제외,Niet voor hubs,Nie dla hubów,Exceto hubs,,Nu pentru hub-uri,Кроме хабов,Није за хубове -Front,OPTVAL_FRONT,,,,Zepředu,Frontalansicht,,Antaŭo,Frontal,,Etu,Devant,,Fronte,画像,정면,Voorkant,Przód,Frente,,Înainte,Перед,Испред -Animated,OPTVAL_ANIMATED,,,,Animované,Animiert,,Animita,Animado,,Animoitu,Animés,,Animato,動作,움직임,Geanimeerd,Animowany,Animado,,Animat,Анимированные,Анимирано -Rotated,OPTVAL_ROTATED,,,,Otáčivé,Rotiert,,Turnita,Rotado,,Kääntyvä,Tournés,,Ruotato,回転,회전함,Geroteerd,Obrócony,Rotacionado,Rodado,Rotit,Повёрнутые,Ротирано -Map defined colors only,OPTVAL_MAPDEFINEDCOLORSONLY,,,Map defined colours only,Pouze barvy definované mapou,Nur Leveldefinierte Farben,,Nur mapaj difinitaj koloroj,Colores definidos por el usuario,,Vain kartan määrittämät värit,Couleurs définies carte seul.,,Solo i colori definiti dalla mappa,指定した色のみ,자체 미니맵 색상 사용,Alleen gedefinieerde kleuren op de kaart,Tylko kolory zdefiniowane przez mapę,Cores definidas por mapa apenas,,Doar culori specifice hărții,Только определённые картой цвета,Само дефинисане мапом боје -All except doors,OPTVAL_NODOORS,,,,Všechny krom dveří,Alle außer Türen,,Ĉiom krom prodoj,Todo excepto puertas,,Kaikki paitsi ovet,Tout sauf portes,,Tutti eccetto le porte,ドア以外全て,문을 제외한 모두,Allemaal behalve deuren,Wszystko oprócz drzwi,Tudo exceto portas,,Cu excepția ușilor,Кроме дверей,Све осим врата -Double,OPTVAL_DOUBLE,,,,Dvojitý,Doppel,,Duobligi,Doble,,Kaksinkertainen,,,Doppio,ダブル,2배,Dubbele,Podwójny,Dobro,,Dublu,Двойной,Дупло -Triple,OPTVAL_TRIPLE,,,,Trojitý,Dreifach,,Triobligi,,,Kolminkertainen,,,Triplo,トリプル,3배,Drievoudig,Potrójny,Triplo,,Triplu,Тройной,Тродупло -Quadruple,OPTVAL_QUADRUPLE,,,,Čtveritý,Vierfach,,Kvarobligi,Cuádruple,,Nelinkertainen,,,Quadruplo,クァッド,4배,Viervoudig,Poczwórny,Quádruplo,,Cvadruplu,Четверной,Четвороструко -Item Pickup,OPTVAL_ITEMPICKUP,,,,Sebrání předmětu,Gegenstand genommen,,Aĵpreni,Recogida de objetos,,Esineen poiminta,Objets Ramassés,,Raccolta oggetto,アイテム取得,아이템 획득시,Puntafhaling,Podniesienie Przedmiotu,Coleta de Item,Aquisição de Itens,Obiect Ridicat,Подбор,Подигнут предмет -Obituaries,OPTVAL_OBITUARIES,,,,Zprávy o smrti,Todesanzeige,,Nekrologo,Obituarios,,Kuolinviestit,Avis de décès,,Necrologio,死亡時,사망 메시지,Doodsbrieven,Nekrologi,Obituários,,Necrologuri,Некрологи,Читуље -Critical Messages,OPTVAL_CRITICALMESSAGES,,,,Kritické zprávy,Kritische Meldungen,,Gravegaj Mesagoj,Mensajes críticos,,Tärkeät viestit,Messages Critiques,,Messaggi critici,重要メッセージ,중요한 메시지,Kritische berichten,Wiadomości krytyczne,Mensagens Críticas,,Mesaje Critice,Важные сообщения,Критичне поруке -Never friends,OPTVAL_NEVERFRIENDS,,,,Nikdy spojence,Keine Freunde,,Neniam amikoj,Nunca amigos,,Ei koskaan ystäviä,Jamais les Amis,,Mai amici,フレンド以外,아군 무시,Nooit vrienden,Żadnych przyjaciół,Nunca amigos,,Nu aliați,Не по союзникам,Никад за пријатеље -Only monsters,OPTVAL_ONLYMONSTERS,,,,Pouze příšery,Nur Monster,,Nur monstroj,Solo monstruos,,Vain hirviöt,Monstres Seulement,,Solo i mostri,モンスターのみ,적에게만,Alleen monsters,Tylko potwory,Somente monstros,Monstros apenas,Doar monștri,Для монстров,Само чудовишста -Hexen,OPTVAL_HEXEN,,,,,,,,,,,Hexen,,,,헥센,,,,,,, -Old,OPTVAL_OLD,,,,Starý,Alt,,Maljuna,Viejo,,Vanha,Ancien,,Vecchio,旧式,구형,Oud,Stare,Antigo,,Vechi,Старый,Стар -Default,OPTVAL_DEFAULT,,,,Výchozí,Standard,,Defaŭlte,Por defecto,,Oletus,Défaut,,,デフォルト,기본 설정,Standaard,Domyślne,Padrão,,Implicit,По умолчанию,Подраз. -Doom,OPTVAL_DOOM,,,,,,,,,,,,,,,둠,,,,,,, -Doom (strict),OPTVAL_DOOMSTRICT,,,,Doom (striktní),Doom (strikt),,Doom (severa),Doom (estricto),,Doom (tiukka),,,Doom (rigoroso),Doom(厳密),둠 (엄격하게),Doom (streng),Doom (ścisły),Doom (estritamente),Doom (estrito),,Doom (строгий),Doom (строг) -Boom,OPTVAL_BOOM,,,,,,,,,,,,,,,붐,,,,,,, -Boom (strict),OPTVAL_BOOMSTRICT,,,,Boom (striktní),Boom (strikt),,Boom (severa),Boom (estricto),,Boom (tiukka),,,Boom (rigoroso),Boom(厳密),붐 (엄격하게),Boom (streng),Boom (ścisły),Boom (estritamente),Boom (estrito),,Boom (строгий),Boom (строг) -MBF,OPTVAL_MBF,,,,,,,,,,,,,,,마린의 절친한 친구,,,,,,, -ZDoom 2.0.63,OPTVAL_ZDOOM2063,,,,,,,,,,,,,,,Z둠 2.0.63,,,,,,, -4000 Hz,OPTVAL_4000HZ,,,,,,,,,,,,,,,,,,,,,4000 Гц, -8000 Hz,OPTVAL_8000HZ,,,,,,,,,,,,,,,,,,,,,8000 Гц, -11025 Hz,OPTVAL_11025HZ,,,,,,,,,,,,,,,,,,,,,11025 Гц, -22050 Hz,OPTVAL_22050HZ,,,,,,,,,,,,,,,,,,,,,22050 Гц, -32000 Hz,OPTVAL_32000HZ,,,,,,,,,,,,,,,,,,,,,32000 Гц, -44100 Hz,OPTVAL_44100HZ,,,,,,,,,,,,,,,,,,,,,44100 Гц, -48000 Hz,OPTVAL_48000HZ,,,,,,,,,,,,,,,,,,,,,48000 Гц, -64 samples,OPTVAL_64SAMPLES,,,,64 vzorků,64 Samples,,64 specimenoj,64 Muestras,,64 näytettä,,,,,64 샘플,,64 sample,64 amostras,,,64 семпла,64 узорка -128 samples,OPTVAL_128SAMPLES,,,,128 vzorků,128 Samples,,128 specimenoj,128 Muestras,,128 näytettä,,,,,128 샘플,,128 sampli,128 amostras,,,128 семплов,128 узорка -256 samples,OPTVAL_256SAMPLES,,,,256 vzorků,256 Samples,,256 specimenoj,256 Muestras,,256 näytettä,,,,,256 샘플,,256 sampli,256 amostras,,,256 семплов,256 узорка -512 samples,OPTVAL_512SAMPLES,,,,512 vzorků,512 Samples,,512 specimenoj,512 Muestras,,512 näytettä,,,,,512 샘플,,512 sampli,512 amostras,,,512 семплов,512 узорка -1024 samples,OPTVAL_1024SAMPLES,,,,1024 vzorků,1024 Samples,,1024 specimenoj,1024 Muestras,,1024 näytettä,,,,,1024 샘플,,1024 sampli,1024 amostras,,,1024 семпла,1024 узорка -2048 samples,OPTVAL_2048SAMPLES,,,,2048 vzorků,2048 Samples,,2048 specimenoj,2048 Muestras,,2048 näytettä,,,,,2048 샘플,,2048 sampli,2048 amostras,,,2048 семплов,2048 узорка -4096 samples,OPTVAL_4096SAMPLES,,,,4096 vzorků,4096 Samples,,4096 specimenoj,4096 Muestras,,4096 näytettä,,,,,4096 샘플,,4096 sampli,4096 amostras,,,4096 семплов,4096 узорка -Unlimited,OPTVAL_UNLIMITED,,,,Neomezený,Unlimitiert,,Senlima,Ilimitado,,Rajoittamaton,Illimité,,Illimitato,無制限,무제한,Onbeperkt,Nieskończone,Sem limite,,Nelimitat,Без ограничений,Бескрајно -256K,OPTVAL_256K,,,,,,,,,,,,,,,,,,,,,256К, -512K,OPTVAL_512K,,,,,,,,,,,,,,,,,,,,,512К, -768K,OPTVAL_768K,,,,,,,,,,,,,,,,,,,,,768К, -1024K,OPTVAL_1024K,,,,,,,,,,,,,,,,,,,,,1024К, -MAME OPL2,OPTVAL_MAMEOPL2,,,,,,,,,,,,,,,마메 OPL2,,,,,,, -MAME YM2612,OPTVAL_MAMEOPN2,,,,,,,,,,,,,,,마메 YM2612,,,,,,, -DOSBox OPL3,OPTVAL_DOSBOXOPL3,,,,,,,,,,,,,,,도스박스 OPL3,,,,,,, -Java OPL3,OPTVAL_JAVAOPL3,,,,,,,,,,,,,,,자바 OPL3,,,,,,, -Nuked OPL3,OPTVAL_NUKEDOPL3,,,,,,,,,,,,,,,,,,,,,, -Nuked OPL3 v1.7.4,OPTVAL_NUKEDOPL3174,,,,,,,,,,,,,,,,,,,,,, -Nuked OPN2,OPTVAL_NUKEDOPN2,,,,,,,,,,,,,,,,,,,,,, -GENS YM2612,OPTVAL_GENSOPN2,,,,,,,,,,,,,,,,,,,,,, -Sound System,OPTVAL_SOUNDSYSTEM,,,,Zvukový systém,,,Sonsistemo,Sistema de sonido,,Äänijärjestelmä,Système Sonore,,Sistema dei suoni,サウンドシステム,음향 시스템,Geluidssysteem,System dźwięku,Sistema de som,,Sistem Sunet,Аудиосистема,Систем звукова -foo_dumb,OPTVAL_FOO_DUMB,,,,,,,,,,,,,,,,,,,,,, -Aliasing,OPTVAL_ALIASING,,,,,,,Kromnomado,,,,,,,エイリアシング,에일리어싱,,,,,,Алиасинг,Преклапање -Linear,OPTVAL_LINEAR_1,"This setting is duplicated threefold in order to allow for different grammatical gender endings in the Russian language (and any other language that depends on a grammatical gender system). In English, due to the lack of a grammatical gender system, all three option values are the same. - -— Undead",,,Lineární,,,Lineara,Lineal,,Lineaarinen,Linéaire,,Lineare,リニア,선형,Lineair,Liniowy,,,Liniar,Линейное,Линеаран -Linear,OPTVAL_LINEAR_2,,,,Lineární,,,Lineara,Lineal,,Lineaarinen,Linéaire,,Lineare,リニア,선형,Lineair,Liniowa,,,Liniar,Линейная,Линеаран -Linear,OPTVAL_LINEAR_3,,,,Lineární,,,Lineara,Lineal,,Lineaarinen,Linéaire,,Lineare,リニア,선형,Lineair,Liniowe,,,Liniar,Линейный,Линеаран -Nearest,OPTVAL_NEAREST,,,,Nejbližší,Nächster Nachbar,,Plej proksima,Cercano,,Lähin,Nearest,,Il più vicino,最寄り,가까이,Naast,Najbiższe,Vizinho mais próximo,,Cel mai apropriat,Ближайший,Најближе -PCF (Low),OPTVAL_PCF_LOW,,,,PCF (nízké),PCF (niedrig),,PCF (Malata),PCF (Bajo),,PCF (matala),PCF (Low),,PCF (basso),PCF (低),PCF (하급),PCF (Laag),PCF (Niski),PCF (Baixo),,PCF (Scăzut),PCF (низкий),PCF (ниско) -PCF (Medium),OPTVAL_PCF_MEDIUM,,,,PCF (střední),PCF (mittel),,PCF (Meza),PCF (Medio),,PCF (keskitaso),PCF (Medium),,PCF (medio),PCF (中),PCF (중급),PCF (Medium),PCF (Średni),PCF (Médio),,PCF (Mediu),PCF (средний),PCF (средње) -PCF (High),OPTVAL_PCF_HIGH,,,,PCF (vysoké),PCF (hoch),,PCF (Alta),PCF (Alto),,PCF (korkea),PCF (High),,PCF (alto),PCF (高),PCF (상급),PCF (Hoog),PCF (Wysoki),PCF (Alto),,PCF (Ridicat),PCF (высокий),PCF (високо) -Cubic,OPTVAL_CUBIC,,,,Kubická,Kubisch,,Kuba,Cúbico,,Kuutio,Cubique,,Cubico,キュービック,큐빅,Kubieke,Sześcienny,Cúbico,,Cub,Кубическое,Кубан -Band-limited step,OPTVAL_BLEP,,,,Omezené krokování,Bandbegrenzte Schritte,,Bendo-limigita paŝo,Paso limitado por banda,,Kaistarajoitettu askel,Step limité par bande,,Passo limitato dalla banda,帯域制限ステップ,제한된 단계별 밴드,Bandbeperkte stap,Krok ograniczony pasmem,Passo limitado por banda,,Limitare frecvență pas-cu-pas,Пошаговое ограничение частоты,Постепено ограничење фреквенције -Linear (Slower),OPTVAL_LINEARSLOW,,,,Lineární (pomalejší),Linear (langsamer),,Lineara (Pli malrapida),Lineal (más lento),,Lineaarinen (hitaampi),Linéaire (Lent),,Lineare (più lento),リニア(遅め),선형 (느리게),Lineair (langzamer),Liniowy (wolniejszy),Linear (Mais lento),,Liniar (Mai lent),Линейное (медленнее),Линеаран (спорије) -Band-limited linear,OPTVAL_BLAM,,,,Omezená lineární,Bandbegrenzt linear,,Bendo-limigita lineara,Lineal limitado por banda,,Kaistarajoitettu lineaarinen,Linéaire limité par bande,,Lineare limitato dalla banda,帯域制限リニア,밴드 제한 식 선형,Band-beperkt lineair,Liniowy ograniczony pasmem,Linear limitado por banda,,Limitare frecvență liniară,Линейное ограничение частоты,Линеарно ограничење фреквенције -Cubic (Slower),OPTVAL_CUBICSLOW,,,,Kubická (pomalejší),Kubisch (langsamer),,Kuba (Pli malrapida),Cúbico (más lento),,Kuutio (hitaampi),Cubique (Lent),,Cubico (più lento),キュービック (遅め),큐빅 (느리게),Kubieke (langzamer),Sześcienny (wolniejszy),Cúbico (Mais lento),,Cub (Mai lent),Кубическое (медленнее),Кубан (спорије) -Sinc,OPTVAL_SINC,,,,,,,,Seno cardinal,,,,,,シンク,싱크,,,,,Sinus cardinal,Кардинальный синус,Синк -Note on/off only,OPTVAL_NOTEONOFFONLY,,,,Pouze začátek/konec noty,Nur für Note an/aus ,,Nur noton aktivigi/malatkivigi,Sólo notas de Activ./Desact.,,Vain nuotti päällä/pois,Note on/off seulement,,Note solamente ON/OFF,ノート オン/オフ のみ,노트를 끄거나 켰을 때,Alleen toon aan/uit,Tylko dla włączonych/wyłączonych notatek,Somente notas lig./deslig.,,Numai la activarea/oprirea notelor,Только при включении/отключении нот,Само током укључења/искључења ноте -Full ramping,OPTVAL_FULLRAMPING,,,,Plný náběh,,,Plena rampante,Aumento completo,,Täysi kerrytys,Rampe complète,,Ramping completo,フルランピング,최대 램핑,Volledige helling,Pełne zwiększenie,Rampa completa,,Creștere completă,Полное наращивание,Пуно појачање -All unacknowledged,OPTVAL_ALLUNACKNOWLEDGED,,,,Všechny nepotrvzené,Alle unbestätigten,,Tuton neatendis,Todos no reconocidos,,Kaikki kuittaamattomat,Tout non-acknowledged,,Tutti non riconosciuti,未確認全て,모두 미확인함,Allemaal onbekend,Wszystkie niepotwierdzone,Todos não-reconhecidos,,Toate necunoscute,Всё неизвестное,Све неусвојено -Errors,OPTVAL_ERRORS,,,,Chyby,Fehler,,Eraroj,Errores,,Virheet,Erreurs,,Errori,エラー,에러,Fouten,Błędy,Erros,,Erori,Ошибки,Грешка -Warnings,OPTVAL_WARNINGS,,,,Varování,Warnungen,,Avertoj,Advertencias,,Varoitukset,Avertissements,,Avvisi,警告,경고,Waarschuwingen,Ostrzeżenia,Avisos,,Atenționări,Предупреждения,Упозорење -Notifications,OPTVAL_NOTIFICATIONS,,,,Zprávy,Benachrichtigungen,,Notifoj,Notificaciones,,Ilmoitukset,,,Notifiche,通知,알림,Kennisgevingen,Powiadomienia,Notificações,,Notificări,Уведомления,Обавештење -Everything,OPTVAL_EVERYTHING,,,,Všechno,Alles,,Ĉiom,Todo,,Kaikki,Tout,,Tutti,全て,전체,Alles,Wszystko,Tudo,,Tot,Всё,Све -Hardware accelerated,OPTVAL_HWPOLY,,,,Hardwarová akcelerace,Hardwarebeschleunigt,,Aparatara Plirapidigo,Acelerado por Hardware,,Laitteistokiihdytetty,Accéléré par Hardware,,Accelerazione Hardware,OpenGL-アクセラレーション,오픈지엘 가속,Hardware versneld,Napędzane sprzętowo,Acelerado por hardware,,Accelerat Hardware,Аппаратный,Харвер убрзан -Doom Software Renderer,OPTVAL_SWDOOM,,,,Doom softwarový renderer,,,Program-bildigilo de Doom,Renderizado por Software de Doom,,Doomin ohjelmistohahmonnin,Rendu Software Doom,,Motore grafico Doom software,Doom ソフトウェアレンダー,둠 소프트웨어 렌더러,,Renderer Oprogramowania Dooma,Renderizador Software do Doom,,Software,Программный,Doom софтверски рендерер -True Color SW Renderer,OPTVAL_SWDOOMTC,,,,True color softwarový renderer,,,Program-bildigilo kun Verkoloro,Renderizado SW Color Verdadero,Renderizado SW True Color,True Color -ohjelmistohahmonnin,Rendu Software Couleurs Réeles,,Motore grafico software a pieni colori,トゥルーカラー SWレンダー,트루 컬러 소프트웨어 렌더러,,Renderer True Color,Renderizador Software True Color,,Software Color Complet,Полноцветный програмный,SW рендерер праве боје -Softpoly Renderer,OPTVAL_SWPOLY,,,,Softpoly renderer,,,Plurlatera Program-bildigilo,Renderizado Softpoly,,Softpoly-hahmonnin,Rendu Softpoly,,Motore grafico Softpoly,ソフトポリ レンダー,소프트폴리 렌더러,,Renderer Softpoly,Renderizador Softpoly,,Softpoly,Полирендер,Softpoly рендерер -True Color Softpoly,OPTVAL_SWPOLYTC,,,,,,,Plurlatera Program-bildigilo kun Verkoloro,Softpoly Color Verdadero,Softpoly True Color,True Color -Softpoly,Softpoly Couleurs Réeles,,Softpoly a pieni colori,トゥルーカラー ソフトポリ,트루 컬러 소프트폴리,,,Softpoly True Color,,Softpoly Color Complet,Полноцветный полирендер,Softpoly праве боје -High-Performance,OPTVAL_DEDICATED,,,,Vysoký výkon,Volle Leistung,,Alta Rendimento,Alto rendimiento,,Korkea suorituskyky,Hautes Performances,,Performance elevate,ハイパフォーマンス,고 성능,Hoogwaardige prestaties,Wysoka Wydajność,Alta-Performance,,De înaltă performanță,Высокая производительность,Високо-перформанси -Power-Saving,OPTVAL_INTEGRATED,,,,Nízká spotřeba,energiesparend,,Energikonservo,Ahorro de energía,,Virransäästö,Economie d'Energie,,Risparmio energetico,パワーセービング,저전력,Energiebesparing,Oszczędzanie Energii,Economia de Energia,,Economie de energie,Энергосбережение,Енергетско-штедљиви -Vanilla,OPTVAL_VANILLA,,,,Původní,,,Originala,,,Alkuperäinen,,,Vanilla,バニラ,바닐라,,Czysty,,,Original,Ванильный,Ванила -ZDoom (Forced),OPTVAL_VTFZDOOM,,,,ZDoom (vynucený),ZDoom (erzwungen),,ZDoom (Devigita),ZDoom (forzado),,ZDoom (pakotettu),ZDoom (Forcé),,ZDoom (forzato),ZDoom (強制),ZDoom (강제 설정),ZDoom (Gedwongen),ZDoom (Wymuszony),ZDoom (Forçar),,ZDoom (Forțat),ZDoom (принудительно),ZDoom (присиљен) -Vanilla (Forced),OPTVAL_VTFVANILLA,,,,Původní (vynucený),Vanilla (erzwungen),,Originala (Devigita),Vanilla (Forzado),,Alkuperäinen (pakotettu),Vanilla (Forcé),,Vanilla (forzato),バニラ (強制),바닐라 (강제 설정),Vanilla (Gedwongen),Czysty (Wymuszony),Vanilla (Forçar),DOS Original (Forçar),Original (Forțat),Vanilla (принудительно),Ванила (присиљен) -Auto (ZDoom Preferred),OPTVAL_VTAZDOOM,,,,Auto (preferován ZDoom),Auto (ZDoom bevorzugt),,Aŭtomata (ZDoom Preferita),Auto (ZDoom preferido),,Automaattinen (ZDoomia suosiva),Auto (ZDoom Préféré),,Automatico (ZDoom preferito),自動 (ZDoom優先),자동 (ZDoom 기본 설정),Auto (bij voorkeur ZDoom),Automatyczny (Preferowany ZDoom),Automático (De preferência ZDoom),,Auto (ZDoom preferat),Автоматически (предпочитать ZDoom),Аутоматски (ZDoom преферијални) -Auto (Vanilla Preferred),OPTVAL_VTAVANILLA,,,,Auto (preferován původní),Auto (Vanilla bevorzugt),,Aŭtomata (Originala Preferita),Auto (Vanilla preferido),,Automaattinen (alkuperäistä suosiva),Auto (Vanilla Préféré),,Automatico (Vanilla preferito),自動 (バニラ優先),자동 (바닐라 기본 설정),Auto (bij voorkeur Vanilla),Automatyczny (Preferowany czysty),Automático (De preferência Vanilla),Automático (De preferência DOS Original),Auto (Original preferat),Автоматически (предпочитать оригинал),Аутоматски (ванила преферијални) -Scaled (Nearest),OPTVAL_SCALENEAREST,,,,Škálován (nejbližší),Skaliert (nächster Nachbar),,Skalita (Plej proksime),Escalado (Cercano),,Skaalattu (läheisin),Mis à l'échelle (Proche Voisin),,Scalato (più vicino),スケーリング (最寄り),확대 (가깝게),Geschaald (Dichtstbijzijnde),Przeskalowany (Najbliższy),Redimensionado (Vizinho mais próximo),Redimensionado (Apróximado),La scară (Cel mai apropriat),Масштабировать (ближайшее),Скалиран (најближи) -Scaled (Linear),OPTVAL_SCALELINEAR,,,,Škálován (lineární),Skaliert(linear),,Skalita (Linia),Escalado (Lineal),,Skaalattu (lineaarinen),Mis à l'échelle (Linéaire),,Scalato (lineare),スケーリング (リニア),확대 (선형 식),Geschaald (Lineair),Przeskalowany (Liniowy),Redimensionado (Linear),,La scară (Liniar),Масштабировать (линейное),Скалиран (линеарно) -Letterbox,OPTVAL_LETTERBOX,,,,,,,Leterkesto,,,,,,Bande nere,レターボックス,레터박스,Brievenbus,,,,Bări verticale,Экранное каше,Поштанско сандуче -Small,OPTVAL_SMALL,,,,Malé,Klein,,Malgranda,Pequeño,,Pieni,Petit,,Piccolo,小,작게,Klein,Mały,Pequeno,,Mic,Мелкий,Мало -Large,OPTVAL_LARGE,,,,Velké,Groß,,Granda,Grande,,Suuri,Grand,,Grande,大,크게,Groot,Duży,Grande,,Mare,Крупный,Велико -Console,OPTVAL_CONSOLE,,,,Konzole,Konsole,,Konzolo,Consola,,Konsoli,Console,,,コンソール,콘솔,Console,Konsola,Console,Consola,Consolă,Консольный,Конзола -\caBrick,C_BRICK,,,,\cacihla,\caziegelrot,,\caBrikkolora,\caladrillo,,\catiili,\cabrique,\catéglavörös,\camattone,\ca丹,\ca주홍색,\casteenrood,\cacegła,\catijolo,,\caCărămiziu,\caКирпичный,\caБоја цигле -\cbTan,C_TAN,,,,\cbsvětle hnědá,\cbhellbraun,,\cbTana,\cbbeis,\cbtostado,\cbkeltaruskea,\cbbeige,\cbbézs,\cbabbronzatura,\cb香,\cb상아색,\cblichtbruin,\cbjasnobrązowy,\cbbege,,\caBronz,\cbБежевый,\cbБеж -\ccGray,C_GRAY,,,\ccgrey,\ccšedá,\ccgrau,,\ccGriza,\ccgris,,\ccharmaa,\ccgris,\ccszürke,\ccgrigio,\cc灰,\cc회색,\ccgrijs,\ccszary,\cccinza,,\ccGri,\ccСерый,\ccСива -\cdGreen,C_GREEN,,,,\cdzelená,\cdgrün,,\cdVerda,\cdverde,,\cdvihreä,\cdvert,\cdzöld,\cdverde,\cd緑,\cd녹색,\cdgroen,\cdzielony,\cdverde,,\cdVerde,\cdЗелёный,\cdЗелена -\ceBrown,C_BROWN,,,,\cehnědá,\cebraun,,\ceBruna,\cemarrón,\cecafé,\ceruskea,\cebrun,\cebarna,\cemarrone,\ce茶,\ce갈색,\cebruin,\cebrązowy,\cemarrom,,\ceMaro,\ceКоричневый,\ceСмеђа -\cfGold,C_GOLD,,,,\cfzlatá,,,\cfOrkolora,\cfdorado,,\cfkulta,\cfor,\cfarany,\cforo,\cf金,\cf금색,\cfgoud,\cfzłoty,\cfdourado,,\cfAuriu,\cfЗолотой,\cfЗлатна -\cgRed,C_RED,,,,\cgčervená,\cgrot,,\cfRuĝa,\cgrojo,,\cgpunainen,\cgrouge,\cgvörös,\cgrosso,\cg赤,\cg적색,\cgrood,\cgczerwony,\cgvermelho,,\gRoșu,\cgКрасный,\cgЦрвена -\chBlue,C_BLUE,,,,\chmodrá,\chblau,,\chBlua,\chazul,,\chsininen,\chbleu,\chkék,\chblu,\ch青,\ch청색,\chblauw,\chniebieski,\chazul,,\chAlbastru,\chСиний,\chПлава -\ciOrange,C_ORANGE,,,,\cioranžová,,,\ciOranĝkolora,\cinaranja,,\cioranssi,,\cinarancs,\ciarancione,\ci橙,\ci주황색,\cioranje,\cipomarańczowy,\cilaranja,,\ciPortocaliu,\ciОранжевый,\ciНаранџаста -\cjWhite,C_WHITE,,,,\cjbílá,\cjweiß,,\cjBlanca,\cjblanco,,\cjvalkoinen,\cjblanc,\cjfehér,\cjbianco,\cj白,\cj흰색,\cjwit,\cjbiały,\cjbranco,,\cjAlb,\cjБелый,\cjБела -\ckYellow,C_YELLOW,,,,\ckžlutá,\ckgelb,,\ckFluva,\ckamarillo,,\ckkeltainen,\ckjaune,\cksárga,\ckgiallo,\ck黄,\ck노란색,\ckgeel,\ckżółty,\ckamarelo,,\ckGalben,\ckЖёлтый,\ckЖута -\clDefault,C_DEFAULT,,,,\clvýchozí,\clstandard,,\clDefaŭlta,\clpor defecto,,\cloletus,\cldéfaut,\clalap,,\cl初期,\cl기본 색,\clstandaard,\cldomyślny,\clpadrão,,\clImplicită,\clПо умолчанию,\clУобичајена -\cmBlack,C_BLACK,,,,\cmčerná,\cmschwarz,,\cmNigra,\cmnegro,,\cmmusta,\cmnoir,\cmfekete,\cmnero,\cm黒,\cm검은색,\cmzwart,\cmczarny,\cmpreto,,\cmNegru,\cmЧёрный,\cmЦрна -\cnLight blue,C_LIGHTBLUE,,,,\cnsvětle modrá,\cnhellblau,,\cnBlueta,\cnazul claro,,\cnvaaleansininen,\cnbleu clair,\cnvilágoskék,\cnblu chiaro,\cn空,\cn하늘색,\cnlicht blauw,\cnjasnoniebieski,\cnazul claro,,\cnAlbastru deschis,\cnГолубой,\cnСветло плава -\coCream,C_CREAM,,,,\cokrémová,\cocremefarben,,\coKremkolora,\cocrema,,\cokerma,\cocrème,\cokrémszínű,\cocrema,\co肉,\co살구색,\cocrème,\cokremowy,\cocreme,,\coCrem,\coКремовый,\coКрем -\cpOlive,C_OLIVE,,,,\cpolivová,\cpoliv,,\cpOlivkolora,\cpoliva,,\cpoliivi,\cpolive,\cpolíva,\cpoliva,\cp泥,\cp녹갈색,\cpolijf,\cpoliwkowy,\cpoliva,,\cpMăsliniu,\cpОливковый,\cpМаслинаста -\cqDark green,C_DARKGREEN,,,,\cqtmavě zelená,\cqdunkelgrün,,\cqVerdeta,\cqverde oscuro,,\cqtummanvihreä,\cqvert sombre,\cqsötétzöld,\cqverde scuro,\cq深,\cq암녹색,\cqdonkergroen,\cqciemnozielony,\cqverde escuro,,\cqVerde închis,\cqТёмно-зелёный,\cqТамно зелена -\crDark red,C_DARKRED,,,,\crtmavě červená,\crdunkelrot,,\crRuĝeta,\crrojo oscuro,,\crtummanpunainen,\crrouge sombre,\crsötétvörös,\crrosso scuro,\cr朱,\cr암적색,\crdonkerrood,\crciemnoczerwony,\crvermelho escuro,,\crRoșu închis,\crТёмно-красный,\crБордо -\csDark brown,C_DARKBROWN,,,,\cstmavě hnědá,\csdunkelbraun,,\csBruneta,\csmarrón oscuro,\cscafé oscuro,\cstummanruskea,\csbrun sombre,\cssötétbarna,\csmarrone scuro,\cs焦,\cs암갈색,\csdonkerbruin,\csciemnobrązowy,\csmarrom escuro,,\csMaro închis,\csТёмно-коричневый,\csБраон -\ctPurple,C_PURPLE,,,,\ctfialová,\ctlila,,\ctPurpura,\ctmorado,,\ctpurppura,\ctviolet,\ctlila,\ctviola,\ct紫,\ct보라색,\ctpaars,\ctfioletowy,\ctroxo,,\ctMov,\ctФиолетовый,\ctЉубичаста -\cuDark gray,C_DARKGRAY,,,\cudark grey,\cutmavě šedá,\cudunkelgrau,,\cuGrizeta,\cugris oscuro,,\cutummanharmaa,\cugris sombre,\cusötétszürke,\cugrigio scuro,\cu鉛,\cu치색,\cudonkergrijs,\cuciemnoszary,\cucinza escuro,,\cuGri închis,\cuТёмно-серый,\cuТамно сива -\cvCyan,C_CYAN,,,,\cvazurová,\cvtürkis,,\cvCejana,\cvcián,,\cvsinivihreä,\cvcyan,\cvcián,\cvciano,\cv天,\cv청록색,\cvcyan,\cvbłękitny,\cvciano,,\cvTurcoaz,\cvСине-зелёный,\cvЦијан -\cwIce,C_ICE,,,,\cwled,\cweis,,\cwGlacikolora,\cwhielo,,\cwjää,\cwglace,\cwjég,\cwghiaccio,\cw氷,\cw구색,\cwice,\cwlód,\cwgelo,,\cwGheață,\cwЛедяной,\cwЛед -\cxFire,C_FIRE,,,,\cxoheň,\cxfeuer,,\cxFajrkolora,\cxfuego,,\cxtuli,\cxfeu,\cxtűz,\cxfuoco,\cx炎,\cx자황색,\cxvuur,\cxogień,\cxfogo,,\cxFoc,\cxОгненный,\cxВатрена -\cySapphire,C_SAPPHIRE,,,,\cysafírová,\cysaphirblau,,\cySafirkolora,\cyzafiro,,\cysafiiri,\cysaphir,\cyzafír,\cyzaffiro,\cy蒼,\cy벽청색,\cysaffier,\cyszafirowy,\cysafira,,\cySafir,\cyСапфировый,\cyТамно плава -\czTeal,C_TEAL,,,,\czmodrozelená,\czblaugrün,,\czTurkisa,\czturquesa,,\cztummansinivihreä,\czturquoise,\cztürkiz,\czverde acqua,\cz碧,\cz암청록색,\czteal,\czmorski,\czturquesa,,\czMare,\czМорской,\czТиркизна -Simple arrow,OPTSTR_SIMPLEARROW,,,,Jednoduchý kurzor,Einfacher Pfeil,,Simpla sago,Flecha simple,,Yksinkertainen nuoli,Flèche simple,,Freccia semplice,シンプル,기본 커서,Eenvoudige pijl,Prosta strzałka,Flecha simples,Cursor simples,Săgeată,Стрелка,Стрелица -Heretic,OPTSTR_HERETIC,,,,,,,,,,,,,,,헤러틱 커서,,,,,,, -Chex,OPTSTR_CHEX,,,,,,,,,,,,,,,첵스 커서,,,,,,, -System cursor,OPTSTR_SYSTEMCURSOR,,,,Systémový kurzor,Systemcursor,,Sistema kursoro,Cursor del sistema,,Järjestelmän osoitin,Curseur Système,,Cursore di sistema,システム,시스템 커서,Systeemcursor,Kursor systemu,Cursor do sistema,,Cursor sistem,Системный курсор,Системска стрелица -No Sound,OPTSTR_NOSOUND,,,,Žádný zvuk,Kein Sound,,Neniu Sono,Sin sonido,,Ei ääntä,Pas de son,,Nessun suono,サウンドなし,음향 없음,Geen geluid,Brak dźwięku,Sem som,,Fără Sunet,Без звука,Без-звучни -Auto,OPTSTR_AUTO,,,,,,,Aŭtomata,Automático,,Automaattinen,,,Automatico,自動,오토,,Automatycznie,Automático,,,Авто,Аутоматски -Mono,OPTSTR_MONO,,,,,,,1 Laŭtparolilo,,,,,,,モノラル,모노,,,,,,Моно,Монотоно -Stereo,OPTSTR_STEREO,,,,,,,2 Laŭtparoliloj,Estereo,,,Stéréo,,,ステレオ,스테레오,,,Estéreo,,,Стерео,Стереотоно -Dolby Pro Logic Decoder,OPTSTR_PROLOGIC,,,,,,,Malkodilo de Dolby Pro Logic ,,,,,,,ドルビー プロロジック デコーダー,돌비 프로 로직 디코더,,,,,Decodor Pro Logic Dolby,Декодер Dolby Pro Logic, -Quad,OPTSTR_QUAD,,,,,,,4 Laŭtparolilol,Cuádruple,,Dolby Pro Logic -dekooderi,,,,クァッド,쿼드,,Cztery kanały,,,,Четырёхканальный,Четвородупло -5 speakers,OPTSTR_SURROUND,,,,5 reproduktorů,5 Lautsprecher,,5 Laŭtparoliloj,5 altavoces,5 Bocinas,5 kaiutinta,5 enceintes,,,5 スピーカー,5 스피커,5 luidsprekers,Głośniki 5,5 alto falantes,,5 boxe,5 динамиков,5 спикер -5.1 speakers,OPTSTR_5POINT1,,,,Reproduktory 5.1,5.1 Lautsprecher,,5.1 Laŭtparoliloj,Altavoces 5.1,Bocinas 5.1,5.1 kaiutinta,Enceintes 5.1,,,5.1 スピーカー,5.1 스피커,5.1 luidsprekers,Głośniki 5.1,Auto falantes 5.1,,Boxe 5.1,Динамики 5.1,5.1 спикер -7.1 speakers,OPTSTR_7POINT1,,,,Reproduktory 7.1,7.1 Lautsprecher,,7.1 Laůtparoliloj,Altavoces 7.1,Bocinas 7.1,7.1 kaiutinta,Enceintes 7.1,,,7.1 スピーカー,7.1스피커,7.1 luidsprekers,Głośniki 7.1,Auto falantes 7.1,,Boxe 7.1,Динамики 7.1,7.1 спикер -No interpolation,OPTSTR_NOINTERPOLATION,,,,Bez interpolace,Keine Interpolation,,Neniu interpolado,Sin interpolación,,Ei interpolaatiota,Pas d'interpolation,,No interpolazione,補間無し,보간 없음,Geen interpolatie,Brak interpolacji,Sem interpolação,,Fără interpolare,Без интерполяции,Нема уметања -Spline,OPTSTR_SPLINE,,,,Křivka,,,Splajno,,,Splini,,,,スプライン,스플라인,,,,,,Сплайн,Сплајн -OpenAL,OPTSTR_OPENAL,,,,,,,,,,,,,,,오픈에이엘,,,,,,, -Hardware Renderer,DSPLYMNU_GLOPT,,,,Hardwarový renderer,,,Aparatara Bildigilo,Renderizado por Hardware,,Laitteistohahmonnin,Moteur de Rendu Hardware,,Motore grafico Hardware,OpenGL レンダー,오픈지엘 렌더러,,Renderer Sprzętowy,Renderizador Hardware,,Setări Mod OpenGL,Рендерер OpenGL,Хардвер рендерер -Software Renderer,DSPLYMNU_SWOPT,,,,Softwarový renderer,,,Programa Bildigilo,Renderizado por Software,,Ohjelmistohahmonnin,Moteur de Rendu Software,,Motore grafico Software,ソフトウェア レンダー,소프트웨어 렌더러,,Renderer Oprogramowania,Renderizador Software,,Setări Mod Software,Программный рендерер,Софтвер рендерер -Gamma correction,DSPLYMNU_GAMMA,,,,Korekce gama,Gammakorrektur,,Gamaa korektado,Corrección gamma,,Gammakorjaus,Correction Gamma,,Correzione gamma,ガンマ値,감마 조정,Gamma correctie,Korekta gammy,Correção gama,,Corecție gamma,Гамма-коррекция,Корекција светлости -Contrast,DSPLYMNU_CONTRAST,,,,Kontrast,Kontrast,,Kontrasto,Contraste,,Sävykkyys,Contraste,,Contrasto,コントラスト,대비,,Kontrast,Contraste,,,Контраст,Контраст -Saturation,DSPLYMNU_SATURATION,,,,Sytost,Sättigung,,Satureco,Saturación,,Värikylläisyys,,,Saturazione,サチュレーション,채도,Verzadiging,Nasycenie,Saturação,,Saturație,Насыщенность,Сатурација -Hardware Rendering Options,GLMNU_TITLE,,,,Nastavení hardwarového rendereru,Hardware-Renderer Optionen,,Agordoj de La Aparatara Bildigilo,Opciones de OpenGL,,Laitteistohahmonnusasetukset,Options OpenGL,,Opzioni OpenGL,ハードウェアレンダリング オプション,오픈지엘 설정,Hardware Rendering Opties,Opcje Renderowania Sprzętowego,Opções de Renderização por Hardware,,Setări Redare OpenGL,Настройки OpenGL,Опција хардвер рендера -Dynamic Light Options,GLMNU_DYNLIGHT,,,,Nastavení dynamických světel,Dynamisches-Licht-Optionen,,Agordoj de Dinamikaj Lumoj,Opciones de luz dinámica,,Dynaamisen valon asetukset,Options Lumières Dynamiques,,Opzioni Luci Dinamiche,ダイナミックライト オプション,광원 설정,Dynamische Licht Opties,Opcje Dynamicznego Oświetlenia,Opções de Luz Dinâmica,,Setări Lumini Dinamice,Динамическое освещение,Подешавања динамичког осветљења -Texture Options,GLMNU_TEXOPT,,,,Nastavení textur,Texturoptionen,,Agordoj de Teksturoj,Opciones de texturas,,Pintakuviointiasetukset,Options Textures,,Opzioni Texture,テクスチャー オプション,텍스쳐 설정,Textuur Opties,Opcje Tekstur,Opções de Textura,,Setări de Textură,Настройки текстур,Подешавања текстура -Preferences,GLMNU_PREFS,,,,Možnosti,Einstellungen,,Preferoj,Preferencias,,Asetukset,Préférences,,Preferenze,環境設定,성능,Voorkeuren,Preferencje,Preferências,,Preferințe,Настройки,Преференција -Texture Options,GLTEXMNU_TITLE,,,,Nastavení textur,Texturoptionen,,Agordoj de Teksturoj,Opciones de texturas,,Pintakuviointiasetukset,Options Textures,,Opzioni Texture,テクスチャー オプション,텍스쳐 설정,Textuur Opties,Opcje Tekstur,Opções de Textura,,Setări Textură,Настройки текстур,Подешавања текстура -Textures enabled,GLTEXMNU_TEXENABLED,,,,Povolit textury,Texturen an,,Teksturoj Aktivigaj,Texturas activadas,,Pintakuvioinnit otettu käyttöön,Textures activées,,Texture abilitate,テクスチャー有効,텍스쳐 사용,Texturen ingeschakeld,Tekstury włączone,Texturas ativadas,,Texturi Activate,Включить текстуры,Текстуре омогућене -Texture Filter mode,GLTEXMNU_TEXFILTER,,,,Režim filtrování textur,Texturfiltermodus,,Reĝimo por Teksturfiltrado,Modo de filtro de texturas,,Pintakuviointien suodatustapa,Mode de Filtrage Texture,,Modalità filtro texture,テクスチャーフィルター モード,텍스쳐 필터 모드,Textuur Filter mode,Tryb Filtrowania Tekstur,Modo de filtragem de textura,,Mod filtrare texturi,Фильтрация текстур,Текстурни филтер мод -Anisotropic filter,GLTEXMNU_ANISOTROPIC,,,,Anisotropické filtrování,Anisotropische Filterung,,Anizotropa Filtro,Filtro anisotrópico,,Anisotrooppinen suodatus,Filtre Anisotropique,,Filtro anisotropico,異方性フィルター,이방성 필터,Anisotroop filter,Filtr anizotropowy,Filtragem anisotrópica,,Filtrare anizotropă,Анизотропная фильтрация,Анизотропни фолтер -Texture Format,GLTEXMNU_TEXFORMAT,,,,Formát textur,Texturformat,,Aranĝo de Teksturoj,Formato de textura,,Pintakuvioinnin tiedostomuoto,Format Texture,,Formato texture,テクスチャー フォーマット,텍스쳐 포맷,Textuur Formaat,Format Tekstur,Formato de Textura,,Format Texturi,Формат текстур,Формат текстура -Enable hires textures,GLTEXMNU_ENABLEHIRES,,,,Povolit textury ve vysokém rozlišení,Hochauflösende Texturen an,,Aktivigi Altdistingivajn Teksturojn,Activar texturas de alta resolución,,Salli korkean erotuskyvyn pintakuvioinnit,Activer Textures haute résolution,,Abilita texture alta qualità,ハイレゾ テクスチャー有効,고해상도 텍스쳐 사용,Hoge-resolutie texturen op,Włącz tekstury wysokiej jakości,Habilitar texturas de alta resolução,,Texturi de înaltă rezoluție,Текстуры с высоким разрешением,Омогући текстуре велике резолуције -High Quality Resize mode,GLTEXMNU_HQRESIZE,,,,Režim zvětšovače textur,Texturskalierungsmodus,,Altdistingivigo-Skalilo,Modo de ajuste de alta calidad,,Korkealaatuinen kuvakoon muutostapa,Mise à l'échelle haute résolution,,Modalità resize alta qualità,高品質リサイズ モード,고퀄리티 리사이즈 모드,Textuurschaalmodus,Tryb Wysokiej Jakości Zmieniania Rozmiaru,Modo de Redimensionamento de Alta Qualidade,,Mod Redimensionare de Înaltă Calitate,Масштабирование текстур,Промена величине високог квалитета мод -High Quality Resize multiplier,GLTEXMNU_HQRESIZEMULT,,,,Faktor zvětšovače textur,Texturskaluerungsfaktor,,Skalilo Obligilo,Multiplicador de ajuste de alta calidad,,Korkealaatuisen kuvakokomuutoksen kerroin,Multiplicateur de mise à l'échelle,,Moltiplicatore resize alta qualità,高品質リサイズ乗数,고퀄리티 리사이징 승수,Textuurschaalfactor,Mnożnik Wysokiej Jakośći Rozmiaru,Multiplicador de Redimensionamento de Alta Qualidade,,Factor de Scalare,Множитель масштабирования,Промена величине високог квалитета мултипликатор -This mode requires %d times more video memory,GLTEXMNU_HQRESIZEWARN,,,,Tento režim potřebuje %dkrát více paměti,Dieser Modus benötigt das %d-fache an Videospeicher,,Tio reĝimo bezonas %d-oble pli ekranmemoron.,Este modo requiere %d veces más memoria de vídeo,,Tämä tila vaatii %d kertaa enemmän videomuistia,Ce mode nécessite %d fois plus de mémoire vidéo,,Questa modalità richiede %d volte la memoria video,このモードでは %d 倍以上のビデオメモリが必要です!,이 설정은 비디오 메모리의 %d 배가 더 필요합니다.,Deze modus vereist %d keer meer videogeheugen.,Ten tryb wymaga %d razy więcej pamięci wideo,Este modo precisa de %d vezes mais memória de vídeo,,Acest mod necesită de %d mai multă memorie video,Потребует в %d раз больше видеопамяти,Овај мод тражи %d пута више видео меморије -Resize textures,GLTEXMNU_RESIZETEX,,,,Škálovat textury,Texturen skalieren,,Regrandigi Teksturojn,Ajustar texturas,,Muuta pintakuviointien kokoa,Mise à l'échelle textures,,Resize delle texture,リサイズ テクスチャー,텍스쳐 리사이징,Texturen schalen,Zmień rozmiar tekstur,Redimensionar texturas,,Redimensionare texturi,Масштабирование текстур,Промена величине текстура -Resize sprites,GLTEXMNU_RESIZESPR,,,,Škálovat sprity,Sprites skalieren,,Regrandigi Spritojn,Ajustar sprites,,Muuta spritejen kokoa,Mise à l'échelle sprites,,Resize degli sprite,リサイズ スプライト,스프라이트 리사이징,Sprites schalen,Zmień rozmiar sprite'ów,Redimensionar sprites,,Redimensionare sprite-uri,Масштабирование спрайтов,Промена величине спрајтова -Resize fonts,GLTEXMNU_RESIZEFNT,,,,Škálovat fonty,Zeichensätze skalieren,,Regrandigi Tiparojn,Ajustar fuentes,,Muuta kirjasinten kokoa,Mise à l'échelle texte,,Resize dei font,リサイズ フォント,폰트 리사이징,Lettertypen schalen,Zmień rozmiar czcionek,Redimensionar fontes,,Redimensionare fonturi,Масштабирование шрифтов,Промена величине фонта -Precache GL textures,GLTEXMNU_PRECACHETEX,,,,Přednačíst GL textury do cache,GL Texturen zwischenspeichern,,Antaŭkaŝmemorigi GL-teksturojn,Precaché de texturas GL,,Kirjoita GL-pintakuvioinnit välimuistiin,Mise en cache des textures,,Precache texture GL,プリキャッシュ GLテクスチャー,지엘 텍스쳐 미리 캐싱함,Precache GL texturen,Tekstury GL pamięci podręcznej,Precachê de texturas GL,,Preîncărcarcă texturile GL,Кэшировать GL-текстуры,Прикеширане GL текстуре -Trim sprite edges,GLTEXMNU_TRIMSPREDGE,,,,Oříznout okraje spritů,Leerraum in Sprites wegschneiden,,Ĉirkaŭtranĉi Randojn de Spritoj,Recortar líneas de sprite,,Siisti spritejen reunat,Nettoyer le bord des sprites,,Taglia gli spigoli agli sprite,スプライトの角を取る,스프라이트 모서리 다듬기,,Przycinanie krawędzi sprite'ów,Cortar bordas de sprites,,Tundere margini sprite-uri,Обрезание краёв спрайтов,Подсећи ивице спрајтова -Sort draw lists by texture,GLTEXMNU_SORTDRAWLIST,,,,Seřadit vykreslování podle textury,Renderlisten nach Textur sortieren,,Ordigi desegnado-listojn laŭ Teksturo,Ordenar tablas por textura,,Lajittele piirtotaulut pintakuvioinneittain,Ordonner liste de rendu par texture,,Ordina la lista draw per texture,テクスチャーから描画リストを分類,텍스처별로 생성 목록 정렬,Tekeninglijsten sorteren op textuur,Sortowanie list renderowania wdług tekstur,Organizar listas de renderização por textura,,Sortează listele de texturi,Сортировать списки текстур,Сортирано цртај листе од текстуре -Dynamic Lights,GLLIGHTMNU_TITLE,,,,Dynamická světla,Dynamische Lichter,,Dinamikaj Lumoj,Luces dinámicas,,Dynaamiset valot,Lumières Dynamiques,,Luci Dinamiche,ダイナミックライト,다이나믹 라이트,Dynamische verlichting,Dynamiczne Oświetlenie,Luzes Dinâmicas,,Lumini Dinamice,Динамическое освещение,Динамичко осветљење -Dynamic Lights (Hardware),GLLIGHTMNU_LIGHTSENABLED,,,,Dynamická světla (hardware),Dynamische Lichter (Hardware),,Dinamikaj Lumoj (Aparataro),Luces dinámicas (Hardware),,Dynaamiset valot (laitteistokiihdytys),Lumières Dynamiques (Hardware),,Luci Dinamiche (Hardware),ダイナミックライト(OpenGL),다이나믹 라이트(오픈지엘),Dynamische verlichting (hardware),Dynamiczne Oświetlenie (Sprzętowe),Luzes Dinâmicas (Hardware),,Lumini Dinamice (OpenGL),Динамическое освещение (OpenGL),Динамичко осветљење (хардвер) -Enable light definitions,GLLIGHTMNU_LIGHTDEFS,,,Activer les définitions GLDEFS,Povolit definice světel,Lichtdefinitionen an,,Aktivigi lumdifinojn,Activar definiciones de luz,,Ota käyttöön valomääritykset,Activer les définitions de lumière,,Abilita le definizioni GLDEFS,ライト定義 許可,조명 선명도 사용,Lichtdefinities mogelijk maken,Włącz definicje światła,Habilitar definições de luz,Permitir definições de luz,Activare definiții lumini,Включить определения света,Омогући светлосне дефиниције -Lights affect sprites,GLLIGHTMNU_LIGHTSPRITES,,,,Světla ovlivňují sprity,Sprites werden beleuchtet,,Lumoj efiki spritojn,Las luces afectan a los sprites,,Valot vaikuttavat spriteihin,Lumières affectent les sprites,,Le luci influiscono sugli sprite,ライトがスプライトに影響,조명에 영향받는 스프라이트,Lichten beïnvloeden sprites,Światło ma wpływ na sprite'y,Luzes afetam sprites,,Luminile afectează sprite-urile,Освещение спрайтов,Светло утиче на спрајтове -Lights affect particles,GLLIGHTMNU_LIGHTPARTICLES,,,,Světla ovlivňují částice,Partikel werden beleuchtet,,Spritoj efiki partiklojn,Las luces afectan a las partículas,,Valot vaikuttavat hiukkasiin,Lumières affectent les particules,,Le luci influiscono sulle particelle,ライトがパーティクルに影響,조명에 영향받는 입자들,Lichten beïnvloeden deeltjes,Światło ma wpływ na cząsteczki,Luzes afetam partículas,,Luminile afectează particulele,Освещение частиц,Светло утиче на честице -Light shadowmaps,GLLIGHTMNU_LIGHTSHADOWMAP,,,,Mapy stínů,Shadowmaps für Lichter,,Lum-ombro-mapojn,Mapeo de sombra de Luz,,Valojen varjokartat,Shadowmaps,,Mappe shadow,ライトのシャドウマッピング,조명에 영향받는 섀도우맵,Lichte schaduwkaarten,Oświetlenie map cieni,Shadowmaps,,Umbre lumini,Свет на теневых картах,Светло мапе сенки -Shadowmap quality,GLLIGHTMNU_LIGHTSHADOWMAPQUALITY,,,,Kvalita map stínů,Shadowmap Qualität,,Kvalito de ombro-mapo,Calidad de Mapeo de Sombras,,Varjokarttojen laatu,Qualité Shadowmap,,Qualità mappe shadow,シャドウマップ 品質,섀도우맵 퀄리티,Schaduwkaart kwaliteit,Jakość map cieni,Qualidade de shadowmap,,Calitate umbre,Качество теневых карт,Мапа сенки квалитет -Shadowmap filter,GLLIGHTMNU_LIGHTSHADOWMAPFILTER,,,,Filtrování map stínů,Shadowmap Filter,,Filtro de ombro-mapo,Filtro de Mapeo de Sombras,,Varjokarttojen suodatus,Filtre de Shadowmaps,,Filtro mappe shadow,シャドウマップ フィルター,섀도우맵 필터,Schaduwkaart filter,Filtr map cieni,Filtro de shadowmap,,Filtru umbre,Фильтр теневых карт,Мапа сенки филтер -Sector light mode,GLPREFMNU_SECLIGHTMODE,,,,Režim osvětlení sektorů,Sektorlichtmodus,,Reĝimo de sektorlumo,Modo de luz de sector,,Sektorivalojen tila,Mode de lumière Secteur,,Modalità luce di settore,セクターライトモード,섹터 조명 모드,Sector lichte wijze,Tryb oświetlenia sektorów,Modo de luz de setor,,Mod iluminare sectorială,Режим освещения секторов,Секторско светло мод -Fog mode,GLPREFMNU_FOGMODE,,,,Režim mlhy,Nebelmodus,,Reĝimo de nebulo,Modo de niebla,,Sumutila,Mode du broullard,,Modalità nebbia,フォグモード,안개 모드,Mistmodus,Tryb mgły,Modo de neblina,,Mod ceață,Режим тумана,Магла мод -Fog forces fullbright,GLPREFMNU_FOGFORCEFULLBRIGHT,,,,Mlha vynucuje plný jas,Nebel erzwingt volle Helligkeit,,Nebulo devigas plenbrilon,Forzar brillo completo en niebla,,Sumu pakottaa täyskirkkauden,Brouillard force fullbright,,La nebbia forza piena luce,濃霧は明るさ最大,안개를 최대한 강제로 밝힘,Mistkrachten volle lichtsterkte,Mgła wymusza pełną jasność,Neblina força brilho máximo,,Ceața forțează luminozitate maximă,Туман включает режим максимальной яркости,Магла присиљава пуну светлост -Weapon light strength,GLPREFMNU_WPNLIGHTSTR,,,,Intenzita světel zbraní,Waffenlichtstärke,,Lumforteco de armilo,Intensidad de luz de las armas,,Aseiden valovoima,Intensité lumineuse des armes,,Intensità luminosa dell'arma,武器ライトの強さ,무기 빛 강도,Sterkte van het wapenlicht,Natężenie światła broni,Intensidade de luz da arma,,Intensitate lumină armă,Интенсивность вспышек оружия,Блага снага оружја -Environment map on mirrors,GLPREFMNU_ENVIRONMENTMAPMIRROR,,,,Mapa prostředí na zrcadlech,Lichteffekt auf Spiegeln,,Medimapo sur speguloj,Mapa de entorno en espejos,,Ympäristökartta peileissä,Mappage environment sur les miroirs,,Ambiente mappa sugli specchi,マップオンミラーの画像表示,거울 주변의지도 활성,Milieukaart op spiegels,Mapa środowiska w lustrach,Mapa de ambiente em espelhos,,Reflecții pe oglinzi,Карта окружения на зеркалах,Околинска мапа на прозорима -Enhanced night vision mode,GLPREFMNU_ENV,,,,Vylepšený režim nočního vidění,Verbesserter Nachtsichtmodus,,Plibonigita reĝimo de noktvido,Modo de visión nocturna mejorado,,Paranneltu pimeänäkötila,Mode de vision nocture amélioré,,Modalità visione notturna migliorata,バイザーを暗視装置調にする,야시경 효과 향상,Verbeterde nachtzicht modus,Ulepszony tryb widzenia w ciemności,Modo de visão noturna avançada,,Vedere infraroșie avansată,Расширенный режим ночного видения,Побољшана ноћна визија мод -ENV shows stealth monsters,GLPREFMNU_ENVSTEALTH,,,,Noční vidění ukazuje skryté příšery,Nachtsichtmodus zeigt Stealth-Monster,,ENV montras kaŝiĝitajn monstrojn,ENV muestra enemigos sigilosos,,PPN näyttää näkymättömät hirviöt,VNA affiche monstres invisibles,,La VNM mostra i mostri stealth ,暗視バイザーが透明を見破る,스텔스 적 개체를 감지하는 ENV,ENV toont stealth monsters,UTWC pokazuje ukrywających się przeciwników,Visão noturna mostra monstros invisíveis,,PNV afișează monștri ascunși,ПНВ показывает скрытых монстров,ПНВ показује скривена чудовишта -Adjust sprite clipping,GLPREFMNU_SPRCLIP,,,,Vyladění clippingu spritů,Sprite Clipping,,Agordi trairadon de spritoj,Ajustar recortado de sprites,,Spritejen asettelu,Adjusted le clipping des sprites,,Aggiusta il clipping degli sprite,スプライトのずらし を調整する,스프라이트 클리핑 조정,Sprite clipping,Ustaw wcięcie sprite'ów,Ajustar clipping de sprite,,Ajustare poziții sprite-uri,Режим обрезки спрайтов,Подеси спрајт клипинг -Smooth sprite edges,GLPREFMNU_SPRBLEND,,,,Vyhladit okraje spritů,Glätte Spritekanten,,Glatigi randojn de spritoj,Suavizar bordes de sprites,,Pehmeät spritejen reunat,Adoucir bords des sprites,,Smussa gli angoli degli sprite,スプライトの角を丸める,부드러운 스프라이트 모서리,Gladde sprite randen,Gładkie krawędzie sprite'ów,Suavizar bordas de sprites,,Netezire margini sprite-uri,Размытие краёв спрайтов,Углачати ивице спрајта -Fuzz Style,GLPREFMNU_FUZZSTYLE,,,,Styl šumu,Fuzz Stil,,Stilo de lenugo,Estilo de difuminación,,Sumennustyyli,Style de bruit blanc,,Stile fuzz,ファズスタイル,퍼즈 스타일,Fuzz stijl,Styl Szumu,Estilo de difusão,,Stil sclipire,Тип шума,Фаз стајл -Sprite billboard,GLPREFMNU_SPRBILLBOARD,,,,Orientace spritů,,,Liniigi Spritojn,Alineado de sprites,,Spritetaulu,Etalage des sprites,,,スプライト ビルボード,스프라이트 샘플링,Sprite billboard,Wyrównanie Sprite'ów,Alinhamento de sprite,,Rotire sprite-uri,Поворот спрайтов,Спрајт билборд -Sprites face camera,GLPREFMNU_SPRBILLFACECAMERA,,,,Sprity čelí kameře,Sprites zur Kamera ausrichten,,Spritoj turnas al kamareon,Los sprites miran a la cámara,,Spritet suuntaavat kameraan,Sprites font face à la caméra,,Gli sprite sono rivolti alla telecamera.,スプライトのフェイスカメラ,카메라를 향한 스프라이트,Sprites gezicht camera,Sprite'y skierowane w kamerę,Sprites de frente pra câmera,,Sprite-urile privesc înspre cameră,Спрайты направлены к камере,Спрајт камера фаце -Particle style,GLPREFMNU_PARTICLESTYLE,,,,Styl částic,Partikelstil,,Partiklstilo,Estilo de partículas,,Hiukkastyyli,Style de particules,,Stile particelle,パーティクル スタイル,입자 스타일,Deeltjes stijl,Styl Cząsteczek,Tipo de partícula,,Stil particule,Тип частиц,Честице стајл -Rendering quality,GLPREFMNU_RENDERQUALITY,,,,Kvalita vykreslování,Renderqualität,,Kvalito de bildigado,Calidad de Renderizado,,Hahmonnuslaatu,Qualité du rendu,,Qualità resa grafica,レンダリング品質,렌더링 품질,Het teruggeven van kwaliteit,Jakość Renderowania,Qualidade de renderização,,Calitate video,Качество рендеринга,Квалитет рендовања -Menu Blur,GLPREFMNU_MENUBLUR,,,,Rozostření pozadí v menu,Menüunschärfe,,Menumalpurigo,Difuminación de Menú,,Valikon sumennus,Flou menu,,Blur del menu,メニューブラー,메뉴 흐림 효과,Menu vervagen,Rozmycie w Menu,Desfoque do Menu,Desfocagem do Menu,Neclaritate Meniu,Размытие фона меню,Блур мениа -Stereo 3D VR,GLPREFMNU_VRMODE,,,,,,,Duvida 3D VR,Modo Stereo 3D VR,,,3D VR Stéréo,,,ステレオ3DのVR,VR 입체 스테레오 사용,,,3D Estéreo (VR),,Mod VR,VR-режим,Стереотоно 3D VR -Enable Quad Stereo,GLPREFMNU_VRQUADSTEREO,,,,Povolit Quad Stereo,Quad Stereo aktivieren,,Aktivigi Kvaroblo-stereon,Activar Quad Stereo,,Ota käyttöön Quad Stereo,Activer Quad Stereo,,Abilita il Quad Stereo,クァッドステレオを有効,쿼드 스테레오 사용,Quad Stereo inschakelen,Włącz Poczwórne Stereo,Habilitar Quad Stereo,Permitir Quad Stereo,Activare Quad Stereo,Четырёхкратный стереорежим,Омогући четвороструки стерео -Multisample,GLPREFMNU_MULTISAMPLE,,,,Multisampling,,,Plurspecimeno,Multisampling,,Moninäytteistys,,,,マルチサンプル,멀티샘플,,Multipróbkowanie,Multiamostragem,,Multisampling,Мультисэмплинг,Мулти-узорак -Tonemap Mode,GLPREFMNU_TONEMAP,,,,Režim tónovací mapy,Tonemap Modus,,Reĝimo de tonmapo,Modo de mapa de tonos,,Sävykarttatila,Mode Tonemap,,Modalità Tonemap,トーンマップ モード,톤맵 모드,Tonemap modus,Tryb Mapowania Tonów,Tipo de tonemap,,Mod Tonemap,Режим тоун-мэппинга,Тонирано-мапни мод -Bloom effect,GLPREFMNU_BLOOM,,,,Efekt bloom,Bloom Effekt,,Lumŝmir-efiko,Efecto Bloom,,Hehkutehoste (bloom),Effet surbrillance,,Effetto Bloom,ブルーム エフェクト,블룸 효과,Bloei effect,Effekt Bloom,Efeito Bloom,,Efect Bloom,Режим блум,Мутан вид ефект -Lens distortion effect,GLPREFMNU_LENS,,,,Efekt distorze čočky,Optischer Verzerrungseffekt,,Lensdistorto-efiko,Efecto de distorsión de lente,,Linssinvääristystehoste,Effet distorsion de lentille,,Effetto distorsione della lente,レンズの歪みエフェクト,렌즈 왜곡 효과,Effect van de lensvervorming,Efekt zniekształcenia obiektywu,Efeito de distorção de lente,Efeito de distorção da lente,Efect de distorsionare,Искажение линзы,Дисторзија објектива ефект -Ambient occlusion quality,GLPREFMNU_SSAO,,,,Kvalita ambient occlusion,Ambient Occlusion Qualität,,Kvaliteco de media okluso,Calidad de oclusión ambiental,,Yleisvarjostuksen (ambient occlusion) laatu,Qualité Occlusion Ambiente,,Qualità occlusione ambientale,アンビエント オクルージョンの品質,주변 환경 가림 효과 품질,Ambient occlusion kwaliteit,Jakość okluzji otoczenia,Qualidade de oclusão de ambiente,,Calitate ocluzie ambientală,Качество ambient occlusion,Оклузија амбијента ефект -Portals with AO,GLPREFMNU_SSAO_PORTALS,,,,Portály s AO,Portale mit AO,,Portaloj kun media okluso,Portales con OA,,Yleisvarjostuksen portaalit,OA pour les portails,,Portali con l'OA,AOを伴うポータル,주변 환경 가려진 포탈,Portalen met AO,Portale z okluzją otoczenia,Portais com oclusão de ambiente,,Portaluri cu ocluzie ambientală,"Порталы с ambient occlusion -",Портали са AO -FXAA Quality,GLPREFMNU_FXAA,,,,Kvalita FXAA,FXAA Qualität,,Kvaliteco de FXAA,Calidad FXAA,,FXAA-laatu,Qualité FXAA,,Qualità FXAA,FXAA品質,FXAA 품질,FXAA-kwaliteit,Jakość FXAA,Qualidade de FXAA,,Calitate FXAA,Качество FXAA,FXAA квалитет -Dither output,GLPREFMNU_DITHER,,,,Dithering,Dithering,,Diteri eligon,Dither de salida,,Sekoitussävytyksen (dithering) ulostulo,Dithering,,Dithering,ディザー出力,떨림 효과 출력,Dither output,Dygotanie,Dithering,,Putere Dithering,Дизеринг,Учестаност трептања -Tonemap Palette Order,GLPREFMNU_PALTONEMAPORDER,,,,Pořadí palety tónovací mapy,Palettensortierung für Tonemap,,Ordo de kolormapo-paletro,Orden de la paleta en mapa de tonos,,Sävykartan paletin järjestys,Ordre des palettes tonemap,,Ordine della Palette Tonemap,トーンマップパレット順序,톤맵 팔레트 순서,Tonemap Palet Orde van het Tonemap-palet,Kolejność Palet Mapowania Tonów,Ordem da paleta do tonemap,,Ordine paletă Tonemap,Порядок палитры тоун-мэпа,Тонирано-мапни палетни ред -Tonemap Palette Exponent,GLPREFMNU_PALTONEMAPPOWER,,,,Exponent palety tónovací mapy,Palettenexponent für Tonemap,,Exponeto de kolormapo-paletro,Exponente paleta en mapa de tonos,,Sävykartan paletin eksponentti,Exponent des palettes tonemap,,Esponente della Palette Tonemap,トーンマップパレット指数,톤맵 팔레트 지수,Tonemap Palet Exponent,Wykładnik Palet Mapowania Tonów,Expoente da paleta do tonemap,,Exponent paletă Tonemap,Экспонента палитры тоун-мэпа,Тонирано-мапни палетни експонент -Banded SW Lightmode,GLPREFMNU_SWLMBANDED,,,,Režim pruhovaného SW osvětlení,Gebänderter SW-Lichtmodus,,Reĝimo de Bendiga Lumo de Programbildigo,Modo de luz por bandas de SW,,Kaistoitettu ohjelmistoväritila,Lumière bandées en Software,,Softare Lightmode bandata,バンデドSWライトモード,단결된 SW 라이트 모드,SW-lichtmodus met banden,Naznaczony Tryb Oświetlenia Oprogramowania,Modo de luz por bandas em software,,Mod limitat de iluminare Software,Ограниченный программный режим освещения,Повезани SW режим осветљења -Distance Between Your Eyes,GLPREFMNU_VRIPD,,,,Vzdálenost mezi očima,Abstand zwischen den Augen,,Distanco inter Viaj Okuloj,Distancia entre tus ojos,,Silmiesi etäisyys toisistaan,Distance entre vos yeux,,Distranza tra i tuoi occhi,自分の目との距離,시야 간의 거리,Afstand tussen uw ogen,Odległość Pomiędzy Twoimi Oczami,Distância entre os olhos,,Distanța dintre ochi,Расстояние между глазами,Даљина између твојих очију -Distance From Your Screen,GLPREFMNU_VRSCREENDIST,,,,Vzdálenost od obrazovky,Abstand vom Bildschirm,,Distanco inter Via Ekrano,Distancia desde tu pantalla,,Etäisyys ruudullesi,Distance entre vous et l'écran,,Distanza dal tuo schermo,画面からの距離,화면과의 거리,Afstand van uw scherm,Odległość Od Twojego Ekranu4,Distância a partir da tela,,Distanța față de ecranul tău,Расстояние от экрана,Даљина од окрена -Smart,OPTVAL_SMART,,,,Chytré,,,Inteligenta,Inteligente,,Älykäs,Intelligent,,Intelligente,スマート,자동 조정,Slim,Mądry,Inteligente,,Inteligent,Умный,Паметно -Smarter,OPTVAL_SMARTER,,,,Chytřejší,,,Pli inteligenta,Más inteligente,,Älykkäämpi,+ Intelligent,,Ancora più intelligente,よりスマート,고급 자동 조정,Slimmer,Mądrzejszy,Mais inteligente,,Mai inteligent,Умнее,Паметније -Infrared only,OPTVAL_INFRAREDONLY,,,,Pouze infračervené,Nur Infrarot,,Nur transruĝo,Solo infrarrojo,,Vain infrapuna,Vis. Noct. Seulement,,Solo infrarossi,赤外線のみ,야시경만,Alleen infrarood,Tylko Podczerwień,Somente infravermelho,,Doar în infraroșu,Только инфракрасный,Само инфрацрвена -Infrared and torch,OPTVAL_INFRAREDANDTORCH,,,,Infračervené a pochodeň,Infrarot und Fackel,,Transruĝo kaj torĉo,Infrarrojo y antorcha,,Vain infrapuna ja soihtu,Iis Noct. & Torche,,Infrarossi e torcia,赤外線と松明,야시경과 횃불만,Infrarood en fakkels,Tylko Podczerwień i Pochodnie,Infravermelho e tocha,,Infraroșu si torță,Инфракрасный и факел,Инфрацрвена/бакља -Any fixed colormap,OPTVAL_ANYFIXEDCOLORMAP,,,Any fixed colourmap,Jakákoli fixní mapa barev,Alle Lichteffekte,,Iu ajn fiksa kolormapo,Cualquier mapa de color fijo,,Mikä tahansa kiinteä värikartta,N'importe quelle colormap,,Ogni colormap fissata,任意の固定カラーマップ,고정된 컬러맵만,Elke vaste colormap,Którekolwiek naprawione mapy kolorów,Qualquer colormap fixo,,Orice colormap,Любая исправленная цветовая карта,Било која поправљена табела боја -None (nearest mipmap),OPTVAL_NONENEARESTMIPMAP,,,,Žádné (nejbližší mipmapa),Aus (nächste Mipmap),,Nenio (plej proksima mipmapo),Ninguno (mipmap cercano),,Ei mitään (lähin mipkartta),Aucun (mipmap proche voisin),,Nessuno (mipmap più vicina),なし(最寄りミップマップ),없음 (밉멥에 가까움),Geen (dichtstbijzijnde mipmap),Brak (najbliższa mipmapa),Nenhum (mipmap vizinho mais próximo),,Niciunul (cel mai apropriat mipmap),Нет (ближайший мипмап),Ништа (најближи мипмап) -None (linear mipmap),OPTVAL_NONELINEARMIPMAP,,,,Žádné (lineární mipmapa),Aus (lineare Mipmap),,Nenio (linia mipmapo),Ninguno (mipmap lineal),,Ei mitään (lin. mipkartta),Aucun (mipmap linéaire),,Nessuno (mipmap lineare),なし(リニアミップマップ),없음 (선형 밉맵),Geen (lineaire mipmap),Brak (liniowa mipmapa),Nenhum (mipmap linear),,Niciunul (mipmap triliniar),Нет (линейный мипмап),Ништа (линеаран мипмап) -None (trilinear),OPTVAL_NONETRILINEAR,,,,Žádné (trilineární),Aus (trilinear),,Nenio (trilinia),Ninguno (trilineal),,Ei mitään (trilineaarinen),Aucun (mipmap trilinéaire),,Nessuno (mipmap trilineare),なし(トライリニア),없음 (삼선형),Geen (trilineair),Brak (trzyliniowe),Nenhum (trilinear),,Niciunul (triliniar),Нет (трилинейная),Ништа (трилинеарно) -Bilinear,OPTVAL_BILINEAR,,,,Bilineární,,,Dulinia,Bilineal,,Bilineaarinen,Bilinéaire,,Bilineare,バイリニア,쌍선형,Bilineair,Dwuliniowe,,,Biliniar,Билинейная,Билинеарно -Trilinear,OPTVAL_TRILINEAR,,,,Trilineární,,,Trilinia,Trilineal,,Trilineaarinen,Trilinéaire,,Trilineare,トライリニア,삼선형,Trilineair,Trzyliniowe,,,Triliniar,Трилинейная,Трилинеарно -RGBA8,OPTVAL_RGBA8,,,,,,,,,,,,,,,,,,,,,, -RGB5_A1,OPTVAL_RGB5A1,,,,,,,,,,,,,,,,,,,,,, -RGBA4,OPTVAL_RGBA4,,,,,,,,,,,,,,,,,,,,,, -RGBA2,OPTVAL_RGBA2,,,,,,,,,,,,,,,,,,,,,, -COMPR_RGBA,OPTVAL_COMPRRGBA,,,,,,,,,,,,,,,,,,,,,, -S3TC_DXT1,OPTVAL_S3TCDXT1,,,,,,,,,,,,,,,,,,,,,, -S3TC_DXT3,OPTVAL_S3TCDXT3,,,,,,,,,,,,,,,,,,,,,, -S3TC_DXT5,OPTVAL_S3TCDXT5,,,,,,,,,,,,,,,,,,,,,, -2x,OPTVAL_2X,,,,,,,2-oble,,,,,,,,,,,,,,, -4x,OPTVAL_4X,,,,,,,4-oble,,,,,,,,,,,,,,, -8x,OPTVAL_8X,,,,,,,8-oble,,,,,,,,,,,,,,, -16x,OPTVAL_16X,,,,,,,16-oble,,,,,,,,,,,,,,, -32x,OPTVAL_32X,,,,,,,32-oble,,,,,,,,,,,,,,, -Use as palette,OPTVAL_USEASPALETTE,,,,Použít jako paletu,Benutze als Palette,,Uzi kiel paletro,Usar como paleta,,Käytä palettina,Utiliser comme pallette,,Utilizza come palette,パレットとして使用,팔레트로 적용,Gebruik als palet,"Użyj jako palety -",Usar como paleta,Usar como palete,Folosire drept paletă,Использовать как палитру,Користи као палету -Blend,OPTVAL_BLEND,,,,Míchat,Überblenden,,Miksi,Mezclar,,Sekoitus,Mélanger,,Miscela,混合,혼합,Mengen,Połącz,Mesclar,Misturar,Amestec,Смешать,Бленд -Standard,OPTVAL_STANDARD,,,,Standardní,,,Norma,Estándar,,Normaali,,,Standard,標準,기본,Standaard,Standard,Padrão,,,Стандартный,Стандардно -Bright,OPTVAL_BRIGHT,,,,Světlý,Hell,,Brila,Brillante,,Kirkas,Clair,,Chiara,明るい,밝은,Helder,Jasne,Claro,,Luminos,Яркий,Свијетло -Dark,OPTVAL_DARK,,,,Tmavý,Dunkel,,Malbrila,Oscuro,,Tumma,Sombre,,Scura,暗い,어두운,Donker,Ciemne,Escuro,,Întunecat,Тёмный,Тамно -Doom Legacy,OPTVAL_LEGACY,,,,,Doom Legacy,,,,,Perinteinen Doom,,,,DOOM調,둠 레거시,,,,,,, -Software,OPTVAL_SOFTWARE,,,,,,,Programbildigilo,,,Ohjelmisto,,,,ソフトウェア,소프트웨어,,Oprogramowanie,,,,Программный,Софтвер -Speed,OPTVAL_SPEED,,,,Rychlost,Geschwindigkeit,,Rapido,Velocidad,,Nopeus,Vitesse,,Velocità,速度寄り,성능,Snelheid,Szybkość,Velocidade,,Viteză,Скорость,Брзина -Quality,OPTVAL_QUALITY,,,,Kvalita,Qualität,,Kvalito,Calidad,,Laatu,Qualité,,Qualità,品質寄り,고품질,Kwaliteit,Jakość,Qualidade,,Calitate,Качество,Квалитет -Optimal,OPTVAL_OPTIMAL,,,,Optimální,,,Optima,Óptimo,,Tasapainoinen,Optimiser,,Ottimale,最適,최적함,Optimaal,Optymalne,Otimizado,,Optim,Оптимальный,Оптимал -60,OPTVAL_60,,,,,,,,,,,,,,,,,,,,,, -70,OPTVAL_70,,,,,,,,,,,,,,,,,,,,,, -72,OPTVAL_72,,,,,,,,,,,,,,,,,,,,,, -75,OPTVAL_75,,,,,,,,,,,,,,,,,,,,,, -85,OPTVAL_85,,,,,,,,,,,,,,,,,,,,,, -100,OPTVAL_100,,,,,,,,,,,,,,,,,,,,,, -Y Axis,OPTVAL_YAXIS,,,,Po ose Y,Y-Achse,,Y-Akso,Eje Y,,Y-akseli,Axe Y,,Asse Y,縦軸,Y 축,Y-as,Oś Y,Eixo Y,,Axa Y,По горизонтали,Y оса -X/Y Axis,OPTVAL_XYAXIS,,,,Po osách X/Y,X/Y-Achse,,X/Y-Akso,Ejes X/Y,,X- ja Y-akselit,Axes X/Y,,Asse X/Y,横縦軸,X/Y 축,X/Y As,Oś X/Y,Eixo X/Y,,Axa Y/Z,По обеим осям,X/Y оса -Square,OPTVAL_SQUARE,,,,Čtvercové,Quadratisch,,Kvadrata,Cuadrado,,Kulmikas,Carrées,,Quadrato,平方,정사각형,Vierkant,Kwadrat,Quadrado,,Pătrat,Квадратные,Квадрат -Round,OPTVAL_ROUND,,,,Kulaté,Rund,,Ronda,Redondo,,Pyöreä,Rondes,,Arrotondato,円形,원형,Rond,Okrągłe,Redondo,,Rotund,Круглые,Круг -ScaleNx,OPTVAL_SCALENX,,,,,,,,,,,,,,,,,,,,,, -NormalNx,OPTVAL_NORMALNX,,,,,,,,,,,,,,,,,,,,,, -hqNx,OPTVAL_HQNX,,,,,,,,,,,,,,,,,,,,,, -hqNx MMX,OPTVAL_HQNXMMX,,,,,,,,,,,,,,,,,,,,,, -xBRZ,OPTVAL_NXBRZ,,,,,,,,,,,,,,,,,,,,,, -Old xBRZ,OPTVAL_OLD_NXBRZ,,,,xBRZ (starší),xBRZ alt,Παλίο xBRZ,Malnova xBRZ,Antíguo xBRZ,,Vanha xBRZ,Ancien xBRZ,,Vecchio xBRZ,旧xBRZ,구형 xBRZ,Oud xBRZ,Stare xBRZ,Antigo xBRZ,,Vechiul xBRZ,Старый xBRZ,Стари xBRZ -Radial,OPTVAL_RADIAL,,,,Radiální,,Ακτινικό,Radiusa,,,Säteittäinen,,,Radiale,放射状,방사형,Radiaal,Promieniowe,,,,Радиальный,Радијално -Pixel fuzz,OPTVAL_PIXELFUZZ,,,,Pixelový fuzz,Pixel,Pixel θολούρα,Bildera lanugo,Difuminado pixelado,,Kuvapistesumennus,Bruit Pixélisé,,Fuzz pixelato,ピクセル ファズ,픽셀 퍼즈,Pixel fuzz,Szum pikseli,Difuso pixelado,,Puf,Пиксельный шум,Пикселизовани фаз -Smooth fuzz,OPTVAL_SMOOTHFUZZ,,,,Hladký fuzz,Glatt,Ομαλή θολούρα,Glata lanugo,Difuminado borroso,,Pehmeä sumennus,Bruit doux,,Fuzz liscio,滑らかなファズ,부드러운 퍼즈,Gladde fuzz,Wygładzony szum,Difuso suavizado,,Lin,Гладкий шум,Глатки фаз -Swirly fuzz,OPTVAL_SWIRLYFUZZ,,,,Míchající fuzz,Gewirbelt,Περιστροφηκή θολούρα,Kirla lanugo,Difuminado en remolino, ,Pyörteinen sumennus,Bruit marbré,,Fuzz vorticoso,渦状ファズ,소용돌이 퍼즈,Zwerpend fuzz,Wirujący szum,Difuso encaracolado,,Vârtej,Кружащийся шум,Увртен фаз -Translucent fuzz,OPTVAL_TRANSLUCENTFUZZ,,,,Průhledný fuzz,Transparent,Ημιδιαφανής θολούρα,Diafana lanugo,Difuminado Translúcido,,Läpikuultava sumennus,Bruit transparent,,Fuzz traslucido,半透明ファズ,반투명 퍼즈,Doorschijnende fuzz,Przezroczysty szum,Difuso translúcido,,Transparent,Прозрачный шум,Прозрачан фаз -Noise,OPTVAL_NOISE,,,,Šum,Rauschen,Ήχος,Bruo,Ruido,,Kohina,Neige,,Rumore,ノイズ,노이즈,Lawaaierige fuzz,Huk,Ruído,,Zgomot,Шум,Звук -Smooth Noise,OPTVAL_SMOOTHNOISE,,,,Hladký šum,Geglättetes Rauschen,Ομαλός ήχος,Glata Bruo,Ruido borroso,,Pehmeä kohina,Neige adoucie,,Rumore liscio,滑らかなノイズ,부드러운 노이즈,Gladde lawaaierige fuzz,Wugładzony huk,Ruído suavizado,,Zgomot lin,Мягкий шум,Милозвучан звук -Jagged fuzz,OPTVAL_JAGGEDFUZZ,,,,Zubatý šum,Gezackt,Ζαρομένη θολούρα,Malglateca lanugo,Difuminado dentado,,Sahalaitainen sumennus,Neige rugeuse,,Fuzz frastagliato,ギザギザ,들쭉날쭉한 퍼즈,Gekartelde fuzz,Poszarpany szum,Difuso serrilhado,,Zimțat,Зазубренный шум,Назубљен фаз -Green/Magenta,OPTVAL_GREENMAGENTA,,,,Zelená/purpurová,Grün/Magenta,Πράσινο/Magenta,Verda/Magenta,Verde/Magenta,,Vihreä/Magenta,Vert/Magenta,,Verde/Magenta,緑/紫,초록/심홍색,Groen/Magenta,Zielony/Magenta,Verde/Magenta,,Verde/Purpuriu,Зелёный/Маджента,Зелен/Магента -Red/Cyan,OPTVAL_REDCYAN,,,,Červená/tyrkysová,Rot/Cyan,Κόκινο/Κυανό,Ruĝa/Cejana,Rojo/Cian,,Punainen/Sinivihreä,Rouge/Bleu,,Rosso/Ciano,赤/空,빨강/하늘색,Rood/Cyaan,Czerwony/Błękitny,Vermelho/Ciano,,Roșu/Turcoaz,Красный/Голубой,Црвен/Цијан -Amber/Blue,OPTVAL_AMBERBLUE,,,,Oranžová/modrá,Orange/Blau,Amber/Μπλέ,Sukcenokolora/Blua,Ámbar/Azul,,Ruskeankeltainen/Sininen,Ambre/Bleu,,Ambra/Blu,黄/青,황토/파랑색,Amber/Blauw,Bursztynowy/Niebieski,Âmbar/Azul,,Chihlimbar/Albastru,Янтарный/Синий,Ћилибарски/Плаво -Left Eye,OPTVAL_LEFTEYE,,,,Levé oko,Linkes Auge,Αριστερό μάτι,Maldekstra Okulo,Ojo izquierdo,,Vasen silmä,Oeil Gauche,,Occhio sinistro,左目,왼쪽 눈,Linkeroog,Lewe Oko,Olho Esquerdo,,Ochi Stâng,Левый глаз,Лево око -Right Eye,OPTVAL_RIGHTEYE,,,,Pravé oko,Rechtes Auge,Δεξί μάτι,Dekstra Okulo,Ojo derecho,,Oikea silmä,Oeil Droit,,Occhio destro,右目,오른쪽 눈,Rechteroog,Prawe Oko,Olho Direito,,Ochi drept,Правый глаз,Десно око -Side-by-side Full,OPTVAL_SBSFULL,,,,"Vedle sebe, plné",Nebeneinander volle Breite,,Flank-ĉe-flanka Tuta,Lado a lado completo,,Täysi rinnakkaisasettelu,Côte-â-côte Complet,,Fianco a fianco completo,両サイド フル,크게 좌우배치,Zij-aan-zij Volledig,Pełne Obok Siebie,Lado a lado completo,,Una lângă alta Pline,"Бок о бок, полно",Раме уз раме цело -Side-by-side Narrow,OPTVAL_SBSNARROW,,,,"Vedle sebe, úzké",Nebeneinander halbe Breite,,Flank-ĉe-flanka Mallarĝa,Lado a lado estrecho,,Kapea rinnakkaisasettelu,Côte-â-côte étroit,,Fianco a fianco stretto,両サイド ナロー,좁게 좌우배치,Zij-aan-zij smal,Wąskie Obok Siebie,Lado a lado estreito,,Una lângă alta Înguste,"Бок о бок, узко",Раме уз раме уско -Top/Bottom,OPTVAL_TOPBOTTOM,,,,Nad sebou,Übereinander,Πάνω/Κάτω,Supero/Subo,Superior/Inferior,,Ylä-/Alaosa,Dessus/Dessous,,Sopra/Sotto,天/底,위/아래,Boven/onderkant,Góra/Dół,Superior/Inferior,,Sus/Jos,Сверху/снизу,Врх/Дно -Row Interleaved,OPTVAL_ROWINTERLEAVED,,,,Po řádcích,Zeilenversetzt,,Vicoj interteksitaj,Fila intercalada,,Vaakalomitus,Entrelacement rangée,,Riga interfogliata,行インターリーブ,열 교차 배치,Rij interleaved,Przepleciony Szereg,Linha Intercalada,,Rând intercalat,Чередование строк,Редно прошарано -Column Interleaved,OPTVAL_COLUMNINTERLEAVED,,,,Po sloupcích,Spaltenversetzt,,Kolonoj interteksitaj,Columna intercalada,,Pystylomitus,Entralcement colonne,,Colonna interfogliata,列インターリーブ,세로줄 교차 배치,Kolom Interleaved,Przepleciona Kolumna,Coluna Intercalada,,Coloană intercalată,Чередование столбцов,Колонско прошарано -Checkerboard,OPTVAL_CHECKERBOARD,,,,Šachovnice,Schachbrettmuster,,Ŝaktablo,Tablero de damas,,Shakkilautakuvio,Damier,,Scacchiere,市松模様,체크무늬,Dambord,Szachownica,Xadrez,,Tablă de Șah,Шахматная доска,Шаховска табла -Quad-buffered,OPTVAL_QUADBUFFERED,,,,Quad buffer,Vierfachgepuffert,,Kvarobla bufro,Cuádruple búfer,,Neloispuskurointi,Quadruple-tampon,,Quad buffer,クワッドバッファー,쿼드 버퍼,Viervoudig gebufferd,Poczwórnie zbuforowane,Buffer quádruplo,,Împătrit,Четырёхкратный,Квад-унапређено -Uncharted 2,OPTVAL_UNCHARTED2,,,,,,,,,,,,,,,,,,,,,, -Hejl Dawson,OPTVAL_HEJLDAWSON,,,,,,,,,,,,,,,,,,,,,, -Reinhard,OPTVAL_REINHARD,,,,,,,,,,,,,,,,,,,,,, -Palette,OPTVAL_PALETTE,,,,Paleta,,,Paletro,Paleta,,Paletti,,,Palette,パレット,팔레트,Palet,Paleta,Paleta,Palete,Paletă,Палитра игры,Палет -Low,OPTVAL_LOW,,,,Nízká,Niedrig,Χαμηλό,Malalta,Bajo,,Matala,Bas,,Basso,低,낮음,Laag,Niskie,Baixo,,Scăzut,Низкое,Ниско -Medium,OPTVAL_MEDIUM,,,,Střední,Mittel,Μεσαίο,Meza,Medio,,Keskitaso,Moyen,,Medio,中,중간,Middel,Średnie,Médio,,Mediu,Среднее,Средње -High,OPTVAL_HIGH,,,,Vysoká,Hoch,Υψηλό,Alta,Alto,,Korkea,Haut,,Alto,高,높음,Hoog,Wysokie,Alto,,Ridicat,Высокое,Високо -Extreme,OPTVAL_EXTREME,,,,Extrémní,Extrem,Ακράιο,Ekstrema,Extremo,,Äärimmäinen,Extrême,,Estremo,最高,매우 높음,Extreem,Ekstremalne,Extremo,,Extrem,Максимальное,Екстремно -Obverse,OPTVAL_OBVERSEFIRST,,,,Vpřed (obvers),Obvers,Παρατήρησε,Aversa,Anverso,,Etupuoli,,,Dritto,正面,앞면,Gezicht,Awers,Obverso,,Avers,Прямой,Супротно -Reverse,OPTVAL_REVERSEFIRST,,,,Vzad (revers),Revers,Αντίστροφο,Inversa,Inverso,,Käänteinen,Inverse,,Contrario,反転,반전,Omgekeerd,Rewers,Reverso,,Invers,Обратный,Обрнуто -TrueColor Options,DSPLYMNU_TCOPT,,,,Nastavení True color,TrueColor Optionen,TrueColor Ρυθμίσεις,Verkoloro-agordoj,Opciones TrueColor,,TrueColor-asetukset,Options TrueColor,,Opzioni TrueColor,トゥルーカラー オプション,트루 컬러 설정,TrueColor Opties,Opcje TrueColor,Opções de TrueColor,,Setări Mod Culori Complete,Полноцветный режим,Подешавања правих боја -TrueColor Options,TCMNU_TITLE,,,,Nastavení True color,TrueColor Optionen,TrueColor Ρυθμίσεις,Verkoloro-agordoj,Opciones TrueColor,,TrueColor-asetukset,Options TrueColor,,Opzioni TrueColor,トゥルーカラー オプション,트루 컬러 설정,TrueColor Opties,Opcje TrueColor,Opções de TrueColor,,Setări Mod Culori Complete,Настройки полноцветности,Подешавања правих боја -True color output,TCMNU_TRUECOLOR,,,,Výstup True color,TrueColor Ausgabe,TrueColor παραγωγή,Verkoloro-eligo,Salida de True color,,True color -ulostulo,Sortie Truecolor,,Output true color,トゥルーカラー出力,트루 컬러 출력,Ware kleurenoutput,Wyjście TrueColor,Saída de true color,,Putere Mod Culori Complete,Полноцветный вывод,Излаз правих боја -Linear filter when downscaling,TCMNU_MINFILTER,,,,Lineární filtrování při zmenšení,Linearer Filter beim Herunterskalieren,Γραμμικό φίλτρο για σμίκρυνση,Linia filtro kiam subskali,Filtro lineal por reducción,,Lineaarinen suodatin alas skaalatessa,Filtrage linéaire en réduction,,Filtro lineare per la riduzione,縮小時のリニアフィルター,축소시 선형 필터링함,Lineair filter voor downscaling,Liniowy filtr podczas zmniejszania rozmiaru,Filtro linear ao reduzir,,Filtru liniar la micșorare,Линейная фильтрация при уменьшении,Линеарни филтер током смањења -Linear filter when upscaling,TCMNU_MAGFILTER,,,,Lineární filtrování při zvětšení,Linearer Filter beim Hochskalieren,Γραμμικό φίλτρο για πολυτέληση,Linia filtro kima superskali,Filtro lineal por escalado,,Lineaarinen suodatin ylös skaalatessa,Filtrage linéaire en agrandissement,,Filtro lineare per l'aumento,拡大時のリニアフィルター,확대시 선형 필터링함,Lineair filter voor upscaling,Liniowy filtr podczas zwiększania rozmiaru,Filtro linear ao aumentar,,Filtru liniar la mărire,Линейная фильтрация при увеличении,Линеарни филтер током повећања -Use mipmapped textures,TCMNU_MIPMAP,,,,Použít mipmapy,Benutze Textur-Mipmaps,Χρήση mipmapped υφών,Uzi mipmapajn teksturojn,Usar texturas con mipmap,,Käytä mipkartallisia pintakuviointeja,Utiliser textures mipmappées,,Usa le texture mipmapped,ミップマップテクスチャを使用,밉맵 텍스쳐 사용,Gebruik mipmapped texturen,Użyj mipmapowane tekstury,Usar texturas com mipmapping,,Mip mapping pentru texturi,Мип-маппинг для текстур,Користи мипмаповане текстуре -Dynamic lights (Software),TCMNU_DYNLIGHTS,,,,Dynamická světla (Software),Dynamisches Licht (Software),Δυναμικά φώτα (Λογισμικό),Dinamikaj lumoj (Programbildigilo),Luces dinámicas (Software),,Dynaamiset valot (ohjelmisto),Lumières Dynamiques (Software),,Luci Dinamiche (Software),ダイナミックライト (ソフトウェア),다이나믹 라이트 (소프트웨어 버전),Dynamische verlichting (software),Dynamiczne Światło (Oprogramowanie),Luzes Dinâmicas (Software),,Lumini Dinamice (Mod Software),Динамическое освещение (программное),Динамичко осветљење (софтвер) -Option Search,OS_TITLE,,,,Vyhledávání možností,Optionssuche,Αναζήτηση Ρυθμίσεων,Serĉi Agordojn,Buscar Opciones,,Asetushaku,Recherche Option,,Opzioni di ricerca,オプション検索,옵션 검색,Optie zoeken,Szukanie Opcji,Buscar opção,Procurar opção,Căutare Setări,Поиск настройки,Претрага -Search for any term,OS_ANY,,,,Hledat jakékoli klíčové slovo,Suche nach beliebigem Begriff,Αναζήτηση για όποιαδηποτε λέξη,Serĉi por termino,Buscar cualquier término,,Etsi mitä tahansa sanaa,N'importe quel mot,,Cerca per ciascun termine,いずれかの用語を探す,용어 검색,Zoek naar eender welke term,Szukaj jakiegokolwiek wyrażenia,Buscar por qualquer termo,Procurar por um termo qualquer,Căutare după orice termen,Искать любое из слов,Тражи било који термин -Search for all terms,OS_ALL,,,,Hledat všechna klíčová slova,Suche nach allen Begriffen,Αναζήτηση για όλες της λέξεις,Serĉi por ĉiuj terminoj,Buscar todos los términos,,Etsi kaikki sanat,Tous les mots,,Cerca per tutti i termini,全ての用語を探す,모든 조건 검색,Zoek naar alle termen,Szukaj wszystkich wyrażeń,Buscar por todos os termos,Procurar por todos os termos,Căutare după toți termenii,Искать все слова,Тражи сваки термин -No results found.,OS_NO_RESULTS,,,,Nic nenalezeno.,Keine Resultate,Δέν βρέθηκαν αποτελέσματα,Neniuj rezultoj trovitaj.,Ningun resultado.,,Ei tuloksia.,Pas de résultat trouvé,,Nessun risultato trovato.,見つかりませんでした。,검색 결과 없음.,Geen resultaten gevonden.,Brak wyników,Nenhum resultado encontrado.,,Niciun rezultat găsit.,Результатов не найдено.,Нема резултата. -Search:,OS_LABEL,,,,Hledat:,Suche:,Αναζήτηση:,Serĉi:,Buscar:,,Etsi:,Recherche:,,Trova:,検索:,검색:,Zoeken:,Szukaj:,Busca:,Procura:,Căutare:,Поиск:,Претрага: -Always show keys,AUTOMAPMNU_SHOWKEYS_ALWAYS,,,,Vždy zobrazit klíče,Zeige immer alle Schlüssel,Εμφάνιση πλήκτρων πάντα,Ĉiam montri ŝlosilojn,Mostrar llaves siempre,,Aina näytä avaimet,Toujour afficher clés,,Mostra sempre le chiavi,常にキーを表示,항상 키들을 표시,Toon altijd de toetsen,Zawsze pokazuj klucze,Sempre mostrar chaves,Mostrar chaves sempre,Afișează cheile în permanență,Всегда отображать ключи,Увек прикажи тастере -,,Newly added content,,,,,,,,,,,,,,,,,,,,, -No Target ON,TXT_NOTARGET_ON,,,,Neútočící příšery ZAP,notarget AN,Αστόχευτη λειτουργία ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Neniu Celo AKTIVA,No Objetivo ACTIVADO,,Hyökkäämättömyystila PÄÄLLÄ,Monstres aveugles et sourds ON,,Modalità Mostri ciechi e sordi ATTIVATA,ノーターゲット オン,적 표적 감지 켬,Geen doelwit AAN,Głuche i Ślepe Potwory WŁĄCZONE,Inimigos cegos e surdos ATIVADO,,Modul Inamici fără Țintă ACTIVAT,Незаметность включена,Нема мете УКЉУЧЕНО -No Target OFF,TXT_NOTARGET_OFF,,,,Neútočící příšery VYP,notarget AUS,Αστόχευτη λειτουργία ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Neniu Celo MALAKTIVA,No Objetivo DESACTIVADO,,Hyökkäämättömyystila POIS PÄÄLTÄ,Monstres aveugles et sourds OFF,,Modalità Mostri ciechi e sordi DISATTIVATA,ノーターゲット オフ,적 표적 감지 끔,Geen doelwit UIT,Głuche i Ślepe Potwory WYŁĄCZONE,Inimigos cegos e surdos DESATIVADO,,Modul Inamici fără Țintă DEZACTIVAT,Незаметность отключена,Нема мете ИСКЉУЧЕНО -"""Quake with fear!""",TXT_ANUBIS_ON,,,,„Třeste se strachy!“,"""Bebe vor Angst!""","""Τρέμε με φόβο!""","""Tremu pro timo!""","""¡Estremeceos de miedo!""","""Estremecete de Miedo!""","""Vapise pelosta!""",« Tremblez de terreur! »,,"""Trema con terrore!""",恐れおののけ!,공포에 떨어라!,„Beving van angst!“,"""Trzęś się ze strachu""","""Trema de medo!""","""Trema com medo!""","""Tremură de Frică!""",«Дрожите от страха!»,„Дрхтите у страху!“ -No more Ogre Armor,TXT_ANUBIS_OFF,,,,Už žádné zlobří brnění,Keine Ogerrüstung mehr,Καθόλου δρακοντική πανοπλία πια,Ne Ogrokiraso plu,No más armadura de Ogro,,Ei enää örkkipanssaria,Plus d'armure d'ogre,,Niente più armatura Ogre,オーガアーマーはもう嫌,오거 갑옷은 이제 없다.,Geen Ogre Pantser meer,Nigdy więcej Pancerza Ogrów,Chega de Armadura de Ogro,Chega de Armadura de Ogre,Gata cu Armura de Căpcăun,Броня Огра снята,Нема више бауков оклоп -chasecam ON,TXT_CHASECAM_ON,,,,Pohled z třetí osoby ZAP,chasecam AN,Κάμερα τρίτου πρωσώπου ΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Ĉaskamerao AKTIVA,Cámara de seguimiento ACTIVADA,,Seurantakamera PÄÄLLÄ,,,Modalità camera da inseguimento ATTIVATA,チェイスカメラ オン,3인칭 카메라 켬,Chasecam AAN,kamera śledzenia WŁĄCZONA,Câmera em Terceira Pessoa ATIVADA,Câmara em Terceira Pessoa ATIVADA,Perspectivă la Persoana a 3-a ACTIVATĂ,Вид от третьего лица активирован,Чејс-кам УКЉУЧЕН -chasecam OFF,TXT_CHASECAM_OFF,,,,Pohled z třetí osoby VYP,chasecam AUS,Κάμερα τρίτου πρωσώπου ΆΠΕΝΕΡΓΟΠΟΙΗΜΈΝΗ,Ĉaskamerao MALAKTIVA,Cámara de seguimiento DESACTIVADA,,Seurantakamera POIS PÄÄLTÄ,,,Modalità camera da inseguimento DISATTIVATA,チェイスカメラ オフ,3인칭 카메라 끔,Chasecam UIT,kamera śledzenia WYŁĄCZONA,Câmera em Terceira Pessoa DESATIVADA,Câmara em Terceira Pessoa DESATIVADA,Perspectivă la Persoana a 3-a DEZACTIVATĂ,Вид от третьего лица деактивирован,Чејс-кам ИСКЉУЧЕН -1 baddie killed,TXT_BADDIE_KILLED,,,,1 zloun zabit,1 Bösewicht getötet,Ενας κακός πέθανε,1 malbonulo mortiga,1 malo matado,,1 pahis tapettu,1 enemi tué,,Ucciso 1 maligno,1 体 殺した,1 명의 나쁜놈이 사살됨.,1 slechterik gedood,1 zabity przeciwnik,1 inimigo morto,,1 slab ucis,1 плохиш убит,Један зликовац убијен -%d baddies killed,TXT_BADDIES_KILLED,,,,%d zlounů zabito,%d Bösewichte getötet,%d τον κακόν πέθαναν,%d malbonuloj mortigaj,%d malos matados,,%d pahista tapettu,%d enemis tués,,Uccisi %d maligni,%d 体 殺した,%d 명의 나쁜놈들이 사살됨.,%d slechteriken gedood,%d zabitych przeciwników,%d inimigos mortos,,%d slabi uciși,Плохишей убито: %d,%d зликовца убијено -1 monster killed,TXT_MONSTER_KILLED,,,,1 příšera zabita,1 Monster getötet,Ένα τέρας πέθανε,1 monstro mortiga,1 monstruo matado,,1 hirviö tapettu,1 monstre tué,,Ucciso 1 mostro,1 匹 殺した,1 마리의 몬스터가 사살됨.,1 monster gedood,1 zabity potwór,1 monstro morto,,1 monstru ucis,1 монстр убит,Једно чудовиште убијено -%d monsters killed,TXT_MONSTERS_KILLED,,,,%d příšer zabito,%d Monster getötet,%d τον τεράτων πέθαναν,%d monstroj mortigaj,%d monstruos matados,,%d hirviötä tapettu,%d monstres tués,,Uccisi %d mostri,%d 匹 殺した,%d 마리의 몬스터들이 사살됨.,%d monsters gedood,%d zabitych potworów,%d monstros mortos,,%d monștri uciși,Убито монстров: %d,%d чудовишта убијено -Unable to resurrect. Player is no longer connected to its body.,TXT_NO_RESURRECT,,,,"Oživení není možno, hráč už není spojen se svým tělem.",Kann nicht wiederbeleben. Der Spieler ist nicht mehr mit seinem Körper verbunden.,"Ανάσταση αδύνατη, ο παίχτης δεν είναι πια στο σώμα @[pro4_gr]","Ne kapablas revivi. Ludanto ne estas -konektita al si korpo plu.",Imposible resucitar. Jugador ya no conectado a su cuerpo.,,Ei mahdollista herätä henkiin. Pelaaja ei ole enää yhteydessä ruumiiseensa.,Impossible de ressuciter. Le joueur n'est plus connecté à son corps.,,Impossibile resuscitarsi. Il giocatore non è più connesso al suo corpo.,復活できない。プレイヤーはこの体に宿っていない。,부활할 수 없습니다. 플레이어는 더 이상 육체와 연결돼있지 않습니다.,Kan niet reanimeren. De speler is niet langer verbonden met zijn lichaam.,Nie można wskrzesić. Gracz nie jest już połączony z resztą swojego ciała.,"Impossível ressuscitar. Jogador não -está mais ligado ao seu corpo.",,Imposibil de înviat. Jucătorul nu mai e conectat la cadavru.,Воскрешение невозможно. Игрок больше не соединён с трупом.,Немогуће оживети. Играч није више повезан са својим телом. -All Artifacts!,TXT_ALL_ARTIFACTS,,,All Artefacts!,Všechny artefakty!,Alle Artefakte!,Όλα τα τεχνουργίματα!,Ĉiuj Artefaktoj!,¡Todos los Artefactos!,,Kaikki artefaktit!,Tous les artéfacts!,,Tutti gli Artefatti!,全アーティファクト!,모든 유물들!,Alle artefacten!,Wszystkie Artefakty!,Todos os Artefatos!,,Toate Artefactele!,Все артефакты!,Сви артифакти! -What do you want to kill outside of a game?,TXT_WHAT_KILL,,,,"Co chceš zabít, když nejsi ve hře?",Was willst du eigentlich außerhalb eines Spiels töten?,Τί θέλεις να σκοτώσεις έξω απο ένα παιχνίδι ?,Kion vi volas mortigi ekster el ludo?,¿Qué intentas matar fuera de una partida?,,Mitä haluat tappaa pelin ulkopuolella?,Que voulez-vous tuer en dehors d'une partie?,,Cosa vorresti uccidere fuori dal gioco?,ゲーム外で何を殺す気だ?,게임 밖에서 무엇을 죽이고 싶습니까?,Wat wil je buiten een spel om doden?,Co ty chcesz zabić poza grą?,O que você gostaria de matar fora de um jogo?,,Ce vrei să ucizi în afara unui joc?,Что вы хотите убить вне игры?,Шта желите да убијете ван игре? -Frozen player properties turned off,TXT_NOT_FROZEN,,,,Vlastnosti držící hráče na místě vypnuty,Gefrier-Modus abgeschaltet.,Η ιδιότητες ενος παγομένου παίχτη απενεργοποίθηκαν,Atributoj de frostitaj ludantaj malaktivaj,Propiedades de jugador congelado desactivadas,,Jäätyneen pelaajan ominaisuudet kytketty pois päältä,Propriété gelée du joueur annulée.,,Proprietà del giocatore ghiacciato disattivate,凍ったプレイヤーのプロパティを無効化,플레이어 정지 속성이 꺼졌습니다.,Eigenschappen van de bevroren speler uitgeschakeld,Właściwości zamrożonego gracza wyłączone,Jogador congelado desativado,,Proprietăți de înghețare DEZACTIVATE,Свойства замороженного игрока отключены,Смрзнути играчи искључени -%s cheats,TXT_X_CHEATS,This is a gender sensitive message where %s represents the player,,,%s cheatuje,%s schummelt,@[art_gr] %s απατάει,%s trompas,%s hace trampa,,%s huijaa,%s triche.,,%s imbroglia,%s はチート使用,%s 이(가) 치트를 사용 함,%s bedriegt,%s oszukuje,%s está trapaceando,%s está a fazer batota,%s trișează,%s использует чит-коды,%s вара -Team changing has been disabled!,TXT_NO_TEAM_CHANGE,,,,Změna týmu je vypnuta!,Teamwechsel ist deaktiviert!,Η αλαγγή ομάδον απαγορεύεται!,Ŝanĝi teamojn estas malaktivigita!,¡El cambio de equipo ha sido desactivado!,,Joukkueen vaihtaminen on kytketty pois päältä!,Les changements d'équipe sont désactivés!,,È stato disabilitato il cambio di squadra!,チームの変更は受け付けない!,팀 변경이 불가능해짐!,Teamwisseling is uitgeschakeld!,Zmiana drużyn została wyłączona!,Troca de equipe foi desativada!,Troca de equipa foi desativada!,Schimbarea echipelor a fost dezactivată!,Смена команды была отключена!,Мењање тима искључено! -%s joined the %t team,TXT_JOINED_TEAM,%s is the player and gender sensitive,,,%s se připojil@[ao_cs] k týmu %t.,%s is dem %t Team beigetreten.,@[art_gr] %s έγινε μέλος τής %t ομάδας,%s kuniĝis kun la %tn teamon,%s se unió al equipo %t,,%s liittyi joukkueeseen %t,%s a rejoint l'équipe %t.,,%s entra nel team %t,%s は %t のチームに入隊した,%s 이(가) %s 팀에 합류함,%s zijn bij het %t team gekomen.,%s dołącza do drużyny %t,%s entrou na equipe %t,,%s s-a alăturat echipei %t,Игрок %s присоединился к команде %t,%s је уш@[ao_2_sr] у %t тим -%s is now a loner.,TXT_LONER,,,,%s je teď @[self_cs].,%s ist jetzt ein@[e_de] Einzelgänger@[in_de].,@[art_gr] %s είναι τώρα μόνο/ς/η @[pro4_gr],%s nun estas solemulo.,%s es ahora solitari@[ao_esp].,,%s on nyt yksikseen.,%s joue maintenant tout seul.,,%s è da solo,%s は今 一匹狼だ。,%s 은(는) 혼자 남음.,%s is nu een eenling.,%s jest teraz sam@[ao_pl],%s está sozinh@[ao_ptb] agora.,,%s este singur acum,Игрок %s теперь одиночка.,%s је сада самотњак. -%s left the game with %d frags,TXT_LEFTWITHFRAGS,,,,%s opustil@[ao_cs] hru s %d fragy,%s hat das Spiel mit %d Frags verlassen.,@[art_gr] %s έφυγε με %d κοματιασμόυς,%s eliris el la ludon kun %d ĉesoj,%s salió de la partida con %d bajas,,%s poistui pelistä frägimäärällä %d,%s a quitté le jeu avec %d frags.,,%s ha lasciato il gioco con %d frag,"%s が逃げ出したので %d に点が入った -",%s 이(가) 게임에서 %d 의 점수를 기록하고 퇴장 함.,%s verliet het spel met %d frags,%s opuścił@[ao_pl] grę z %d fragami,%s saiu do jogo com %d frags,,%s a părăsit jocul cu %d victime,Игрок %s покинул игру с количеством фрагов: %d,%s је изаш@[ao_2_sr] из игре са %d фраговима. -%s left the game,TXT_LEFTTHEGAME,,,,%s opustil@[ao_cs] hru,%s hat das Spiel verlassen.,@[art_gr] %s έφυγε,%s eliris el la ludon,%s salió de la partida,,%s poistui pelistä,%s a quitté le jeu.,,%s ha lasciato il gioco,%s は退出した,%s 이(가) 게임을 떠남.,%s verliet het spel,%s opuścił@[ao_pl] grę,%s saiu do jogo,,%s a părăsit jocul,Игрок %s покинул игру,%s је изаш@[ao_2_sr] из игре -This savegame needs these files,TXT_SAVEGAMENEEDS,,,,Uložená hra potřebuje tyto soubory,Dieser Spielstand benötigt die folgenden Dateien,Το αρχείο αποθήκευσης χριάζετε αυτά τα αρχεία,Ĉi tiu konservita ludo bezonas ĉi tiujn dosierojn,Esta partida guardada necesita los siguientes archivos,,Tämä pelitallenne tarvitsee nämä tiedostot,Cette sauvegarde nécessite les fichiers suivants:,,Questo salvataggio ha bisogno di questi file,このセーブデータには 必要なファイルがある,이 저장 된 게임은 해당 파일이 필요합니다.,Dit spel heeft de volgende bestanden nodig,Ten zapis gry potrzebuje tych plików,Este jogo salvo precisa destes arquivos,Este jogo guardado precisa destes arquivos,Acest joc salvat necesită următoarele fișiere,Данное сохранение требует следующие файлы,Овој сачуваној игри требају ови фајлови -Could not read savegame '%s'.,TXT_COULDNOTREAD,,,,Nepodařilo se načíst uloženou hru '%s'.,Konnte Spielstand '%s' nicht lesen.,Το αρχείο αποθήκευσης %s δέν μπόρε να φορτωθεί,Ne povis legi la konservitan ludon '%s'.,No se pudo leer la partida guardada '%s'.,,Pelitallennetta '%s' ei voitu lukea.,Impossible de lire la sauvegarde '%s'.,,Non si è potuto leggere il salvataggio '%s'.,%s' のセーブデータを読み込めなかった。,저장된 게임을 불러올 수 없습니다.'%s',Kon het savegame '%s' niet lezen.,Nie można odczytać zapisu „%s”.,"Não foi possível ler o jogo salvo ""%s"".","Não foi possível ler o jogo guardado ""%s"".",Salvarea '%s' nu a putut fi citită.,Невозможно прочитать сохранение: «%s».,Није могуће прочитати сачувану игру %s. -%s' is not a valid savegame: Missing 'info.json'.,TXT_NOINFOJSON,,,,%s' není funkční uloženou hrou: Chybí 'info.json'.,%s' ist kein gültiger Spielstand. 'info.json' fehlt.,Το %s δεν είναι ένα έγκυρο αρχείο αποθήκευσης: Το info.json λείπει,%s' ne estas valida konservita ludo: Mankante 'info.json'.,%s' no es una partida guardada válida: Falta 'info.json'.,,%s' ei ole kelvollinen pelitallenne. Puuttuva 'info.json'.,%s n'est pas une sauvegarde valide. Fichier 'info.json' manquant.,,%s' non è un salvataggio valido: 'info.json' mancante.,%s' は有効なセーブデータ ではない: 'info.json'が不明。,%s' 는 유효하지 않습니다: 파일이 없습니다.'info.json',"%s"" is geen geldig savegame: Ontbreekt 'info.json'.","„%s” nie jest prawidłowym zapisem gry: Brak „info.json” +Притисни Y или N.","Är du säker på att du vill avsluta spelet? +Tryck på Y eller N.","Görevi sonlandırmak istediğinizden emin misiniz? + +Y veya N tuşuna basın.","Ти дійсно хочеш завершити квест? + +Натисни Y або N." +Invincible Mode ON,STSTR_DQDON,,chex,,Režim nezranitelnosti ZAP,Uovervindelig tilstand TIL,Unbesiegbarer Modus EIN,,Nevenkebla-reĝimo ŜALTITA,Modo invencible ACTIVADO,,Kuolemattomuustila PÄÄLLÄ,Mode invincible ON,Sérthetetlen mód BE,Modalità invincibile attivata,むてきモード オン,무적 모드 켬,Onoverwinnelijke modus AAN,Uovervinnelig modus PÅ,Tryb Niewrażliwości WŁĄCZONY,Modo invencível ATIVADO,,Modul Invincibil ACTIVAT,Режим неуязвимости ВКЛЮЧЁН,Неуништив УКЉУЧЕН,Oövervinnerligt läge på,Yenilmez Mod AÇIK,Невразливість увімкнено +Invincible Mode OFF,STSTR_DQDOFF,,chex,,Režim nezranitelnosti VYP,Uovervindelig tilstand FRA,Unbesiegbarer Modus AUS,,Nevenkebla-reĝimo MALŜALTITA,Modo invencible DESACTIVADO,,Kuolemattomuustila POIS PÄÄLLÄ,Mode invincible OFF,Sérthetetlen mód KI,Modalità invincibile disattivata,むてきモード オフ,무적 모드 끔,Onoverwinnelijke modus UIT,Uovervinnelig modus AV,Tryb Niewrażliwości WYŁĄCZONY,Modo invencível DESATIVADO,,Modul Invincibil DEZACTIVAT,Режим неуязвимости ОТКЛЮЧЁН,Неуништив ИСКЉУЧЕН,Oövervinnerligt läge av,Yenilmez Modu KAPALI,Невразливість вимкнено +Zorch Added,STSTR_FAADDED,,chex,,Bzukry přidány,Zorch tilføjet,Zorch hinzugefügt,,Zorĉo Aldonita,Zorch añadido,,Zorch lisätty,Zorch Ajouté,Szörcs felvéve,Zorch aggiunto,ゾーチ ついか,모든 저치 에너지 추가,Zorch toegevoegd,Zorch lagt til,Zorch dodany,Zorch adicionado,,Zorcher Adăugat,Получен зорч,Зорч додат,Zorch har lagts till,Zorch Eklendi,Додано Зорч +Super Zorch Added,STSTR_KFAADDED,,chex,,Superbzukry přidány,Super Zorch Tilføjet,Super Zorch hinzugefügt,,Supera Zorĉo Aldonita,Súper Zorch añadido,,Superzorch lisätty,Super Zorch Ajouté,Szuper Szörcs feléve,Super Zorch aggiunto,スーパーゾーチ ついか,모든 아이템 습득!,Super Zorch toegevoegd,Super Zorch lagt til,Super Zorch dodany,Super Zorch adicionado,,Super Lingură Adăugată,Получен суперзорч,Супер зорч додат,Super Zorch läggs till,Süper Zorch Eklendi,Додано Супер Зорч +... Eat Chex(R)!,STSTR_CHOPPERS,,chex,,... Jez Chex(R)!,... Spis Chex(R)!,...Iss Chex(R)!,,... Manĝu Chex(R)-on!,... Come Chex(R),,... Syö Chex(R):ä!,... Mangez du Chex(R)!,...egyél Chex(R)-et!,... Mangia I Chex(R)!,...Chex(R)をたべよう!,... 첵스(R) 를 많이 먹자!,... Eet Chex(R)!,... Spis Chex(R)!,... jedz płatki Chex(R)!,... coma Chex(R)!,,... Mănâncă Chex(R)!,...ешь Chex(R)!,... Једи Chex(R)!,... Ät Chex(R)!,... Chex(R) yiyin!,... Їж Chex(R)! +Mini Zorch Charge,AMMO_CLIP,,chex,,Minibzukrové náboje,Mini Zorch ladning,Minizorcher-Ladung,,Zorĉileto-Ŝarĝo,Carga de Mini Zorch,,Minizorchvaraus,Charge Zorch,Mini szörcs töltet,Ricarica Mini Zorch,ミニゾーチ ほきゅう,소형 저치 전지,Mini Zorchlading,Mini Zorch ladning,Mini Ładunek Zorch,Recarga de Mini Zorch,,Mini Încărcătură pentru Zorcher,Заряд мини-зорчера,Мини зорч пуњач,,Mini Zorch Şarjı,Заряд міні-Зорчера +Large Zorcher Charge,AMMO_SHELLS,,chex,,Velkobzukrové náboje,Stor Zorch ladning,Zorcher-Ladung,,Ŝarĝo por Granda Zorĉilo,Carga de Zorcher Grande,,Ison zorcherin varaus,Charge de Zorcheur Large,Nagy szörcs töltet,Ricarica Grande Zorch,ラージゾーチャー ほきゅう,대형 저치 카트리지,Grote Zorchlading,Stor Zorch ladning,Ładunek do Dużego Zorchera,Recarga de Zorch Grande,,Încărcătură Mare pentru Zorcher,Заряд большого зорчера,Велики зорч пуњач,Stor Zorch-laddning,Büyük Zorcher Şarjı,Заряд Великого Зорчера +Propulsor Charge,AMMO_ROCKETS,,chex,,Propulzorové náboje,Propulsor ladning,Propeller-Ladung,,Zorĉpropulsilo-ŝarĝo,Carga de Propulsor de Zorch ,,Työntimen varaus,Charge de Propulseur,Hajtómű töltet,Ricarica Propulsore,プロパルサー ほきゅう,저치 추진료,Propulsorlading,Propulsor ladning,Ładunek do Pędnika,Recarga de Propulsor de Zorch,,Încărcătură pentru Accelerator,Заряд ускорителя,Погонски зорч пуњач,Propulsor-laddning,İtici Şarjı,Заряд Прискорювача +Phasing Zorcher Charge,AMMO_CELLS,,chex,,Fázovací náboje,Phasing-Zorcher ladning,Phasenzorcher-Ladung,,Fluktuantzorĉilo-ŝarĝo,Carga de Zorcher de Fase,,Vaiheiszorcherin varaus,Charge de Phaseur,Fázisszörcsölő töltet,Ricarica Zorcher di Fase,フェイシング ゾーチャー ほきゅう,저치 전자 충전기,Fasezorcherlading,Phasing-Zorcher ladning,Ładunek do Fazowego Zorchera,Recarga de Zorcher Fásico,,Încărcătură pentru Zorcherul Fazat,Заряд фазерного зорчера,Фазни зорч пуњач,Zorcher-laddning för fasning,Zorcher Yükünün Aşamalandırılması,Заряд фазового Зорчера +,,Menus,,,,,,,,,,,,,,,,,,,,,,,,,, +,,Main Menus,,,,,,,,,,,,,,,,,,,,,,,,,, +New Game,MNU_NEWGAME,,,,Nová hra,Nyt spil,Neues Spiel,Νέο Παιχνίδι,Nova ludado,Nueva partida,,Uusi peli,Nouvelle Partie,Új játék,Nuova partita,新規ゲーム,새로운 게임,Nieuw spel,Nytt spill,Nowa Gra,Novo jogo,,Joc Nou,Новая игра,Нова игра,Nytt spel,Yeni Oyun,Нова гра +Options,MNU_OPTIONS,,,,Možnosti,Indstillinger,Optionen,Ρυθμίσεις,Agordoj,Opciones,,Asetukset,Options,Beállítások,Opzioni,オプション,설정,Opties,Alternativer,Opcje,Opções,,Opțiuni,Настройки,Подешавања,Alternativ,Seçenekler,Налаштування +Game Files,MNU_GAMEFILES,,,,Uložené hry,Spilfiler,Spieldateien,Αρχεία Παιχνιδιού,Ludo-dosieroj,Archivos del juego,,Pelitiedostot,Fichiers de jeu,Játékfájlok,File di gioco,ゲームファイル,게임 파일,Spelbestanden,Spillfiler,Pliki Gry,Jogos salvos,Jogos Gravados,Fișiere Joc,Файлы игры,Фајлови игре,Spelfiler,Oyun Dosyaları,Ігрові файли +Info,MNU_INFO,,,,Informace,,Informationen,Πληροφορίες,Informoj,Información,,Tiedot,,Információ,Informazioni,情報,정보,,,,Informações,,,Информация,Подаци,,Bilgi,Інформація +Quit Game,MNU_QUITGAME,,,,Ukončit hru,Afslut spil,Spiel verlassen,Έξοδος,Forlasi ludon,Salir del juego,,Lopeta peli,Quitter le jeu,Kilépés,Esci dal gioco,終了,게임 종료,Verlaat spel,Avslutt spill,Wyjdź z Gry,Sair,,Ieșire din Joc,Выход из игры,Заврши игру,Avsluta spelet,Oyundan Çık,Вихід +Choose Skill Level:,MNU_CHOOSESKILL,This text is extremely space limited!,,,Vyber obtížnost:,Vælg færdighedsniveau:,Schwierigkeitsgrad:,Επίλεξε ΔυσκολΊα:,Elektu malfacilecon:,Elige nivel de dificultad:,,Valitse vaikeustaso:,Difficulté:,Nehézségi szint:,Livello di difficoltà:,実力を選べ:,난이도를 고르시오:,Vaardigheidsniveau:,Velg ferdighetsnivå:,Poziom Trudności:,Escolha o nível de dificuldade:,,Alege Dificultatea:,Уровень сложности:,Ниво тежине:,Välj färdighetsnivå:,Beceri Seviyesini Seçin:, +I'm too young to die.,SKILL_BABY,,,,Ještě nechci umřít.,Jeg er for ung til at dø.,Ich bin zu jung zum Sterben.,Είμαι πολύ νεαρός για να πεθάνω!,Mi tro junas por morti.,Soy muy joven para morir.,,Olen liian nuori kuolemaan.,Trop jeune pour mourir!,Kicsi vagyok még a halálhoz.,Troppo giovane per morire.,死ぬには若すぎる,난 죽기엔 너무 젊어.,Ik ben te jong om te sterven.,Jeg er for ung til å dø.,Jestem za młody by umierać.,Sou jovem demais para morrer.,Demasiado novo para morrer.,Sunt prea tânăr ca să mor.,Мне рано умирать.,Премлад сам да умрем.,Jag är för ung för att dö.,Ölmek için çok gencim., +"Hey, not too rough.",SKILL_EASY,,,,"Hej, ne tak tvrdě.","Hey, ikke for hårdt.","He, nicht so ruppig.",Όχι πολύ δύσκολο,"He, ne tro malafable.","Oye, no seas tan duro.",,"Hei, ei liian kovaa.","Hé, pas trop fort!","Hé, ne túl erősen!","Ehi, non troppo duro!",あまり激しくするな,너무 세게 하지는 마.,"Hé, niet te ruw.","Hei, ikke for hardhendt.","Hej, nie tak mocno.","Opa, pega leve aí.","Ei, mais devagar.","Hei, nu foarte dur.","Эй, не слишком грубо.","Хеј, не претерано грубо.",Inte alltför grovt.,Çok sert değil., +Hurt me plenty.,SKILL_NORMAL,,,,Pojď do mě.,Gør mig rigeligt ondt.,Tu mir weh.,Πόνεσε με,Vundu min multe.,Dame con todo.,,Satuta minua kunnolla.,Fais-moi mal!,Adjál bőven!,Fammi molto male.,手加減無用,마음껏 때려봐.,Doe me veel pijn.,Skader meg mye.,Dowal mi.,Vem com tudo.,Dá-me com força.,Rănește-mă din plin.,Сделай мне больно.,Повреди ме кол'ко можеш.,Gör mig mycket illa.,Beni çok incittin., +Ultra-Violence.,SKILL_HARD,,,,Ultrařežba.,Ultra-vold.,Volle Gewalt.,Ύπερ-Βία,Ekstrema perforto.,Ultraviolencia.,,Ultraväkivalta.,Ultra-Violence!,Ultraerőszak!,Ultra-violenza.,ウルトラ バイオレンス,극단적인-폭력.,Ultra Geweld.,Ultra-vold.,Ultra-Przemoc.,Ultraviolência.,,Ultra-Violență.,Ультранасилие.,Ултра-насилно.,Ultra-våld.,Ultra Şiddet., +Nightmare!,SKILL_NIGHTMARE,,,,Noční můra!,Mareridt!,Alptraum!,Εφιάλτης!,Inkubo!,¡Pesadilla!,,Painajainen!,Cauchemar!,Rémálom!,Incubo!,悪夢だ!,악몽!,Nachtmerrie!,Mareritt!,Koszmar!,Pesadelo!,,Coșmar!,Кошмар!,Ноћна мора!,Mardröm!,Kabus!,Кошмар! +Easy does it,CSKILL_BABY,,,,Hezky zlehka,Let gør det,Immer sachte,,Kvietiĝu,Así de fácil,,Hiljaa hyvä tulee,On y va Doucement,Csak gyengéden.,Facile no?,やさしくして,살살 하면 좋겠네,Gemakkelijk doet het,Rolig nå,Łatwizna,Vamos com calma,,Merge ușor,Потихоньку-полегоньку,Лагано сад,Det är lätt att göra det.,Sakin ol., +Not so sticky,CSKILL_EASY,,,,Ne tak ulepeně,Ikke så klistret,Nicht so schmierig,,Ne tiel glueca,No tan pegajoso,,Ei niin tahmaista,Pas trop Collant,Ne túl ragadósan!,"Non così appiccicoso +",ダラダラしない,질척하진 않게,Niet zo plakkerig.,Ikke så klissete,Nie tak lepko,Não tão gosmento,,Nu așa de lipicios,Не особо липко,Не тако лепљиво,Inte så klibbigt,Çok yapışkan değil, +Gobs of goo,CSKILL_NORMAL,,,,Hafo hlenu,Masser af klister,Schleimklumpen,,Buloj de muko,Montón de moco,,Limaklönttejä,Des Tonnes de Gelée,Egy csomó trutymó,Sputi di sostanza,"カッチカチスライム +",적지 않은 질퍽함,brokken slijm,Klumper av klister,Maziste Gęby,Um montão de meleca,Um montão de ranho,Multă mâzgă,Масса слизи,Лопте љиге,Massor av kladd,Çok fazla çamur, +Extreme Ooze,CSKILL_HARD,,,,Extra bláto,Ekstrem slim,Extrem glitschig,,Ekstrema pusado,Goteo extremo,,Äärimmäisen mönjäistä,Extrêmement Gluant,Extrém nyúlós,Melma estrema,"かげきなウーズ +",엄청난 끈끈함,Uiterst glibberig,Ekstrem slim,Ekstremalny Muł,Gosma ao extremo,,Noroi Extrem,Экстремальная грязь,Екстремно љигаво,Extremt slemmigt,Aşırı Sızıntı, +Super Slimey!,CSKILL_NIGHTMARE,,,,Superslizké!,Super slimet!,Super schleimig!,,Tre ŝlima!,¡Súper viscoso!,,Superlimaista!,Carrément Crade!,Szupernyálkás!,Super Viscido!,ちょうベトベト!,끈쩍함 천지!,Super slijmerig!,Super slimete!,Super Oślizgły!,Super Gosmento!,,Super Mâzgos!,Сверхсклизский!,СУПЕР ЉИГАВО,Super slemmig!,Süper yapışkan!, +Training,SSKILL_BABY,,,,Trénink,Træning,,Eκπαίδευση,Trejnado,Práctica,,Koulutus,Entrâinement,Kiképzés,Allenamento,トレーニング,훈련병,Opleiding,Trening,Trening,Treinamento,Treino,În Pregătiri,Разминка,Тренинг,Träning,Eğitim, +Rookie,SSKILL_EASY,,,,Zelenáč,Nybegynder,Anfänger,Αρχάριος,Komencanto,Novato,,Aloittelija,Recrue,Újonc,Matricola,ルーキー,신병,,Nybegynner,Rekrut,Novato,,Începător,Новичок,Новајлија,Nybörjare,Çaylak, +Veteran,SSKILL_NORMAL,,,,Veterán,,,,Veterano,Veterano,,Veteraani,Véteran,Veterán,Veterano,ベテラン,고참병,Veteraan,,Weteran,Veterano,,,Ветеран,Ветеран,,Gazi, +Elite,SSKILL_HARD,,,,Elita,,,,Elito,Élite,,Eliitti,,Elit,,エリート,정예병,,,Elita,,,Elită,Элита,Елитни,,Elit, +Bloodbath,SSKILL_NIGHTMARE,,,,Krveřežba,Blodbad,Blutbad,,Sangoverŝado,Baño de sangre,,Verilöyly,Massacre!,Vérfürdő,Bagno di sangue,ブラッドバス,피의 목욕,Bloedbad,Blodbad,Rozlew krwi,Banho de sangue,,Baie de sânge,Кровавая бойня,Купка крви,Blodbad,Kan banyosu, +Thou needeth a Wet-Nurse,MNU_WETNURSE,,,,Potřěbuješ krmlici?,Du har brug for en våd sygeplejerske,Wo ist die Krankenschwester?,,Vi nutristinon bezonas,Necesitaréis una nodriza,,Tarvitseos imettäjää,Une Nourrice Vous Voulez,Süldőgyermek,Necessiti di un'infermiera per neonati,汝は乳母を欲する,그대에게는 유모가 필요하다,Waar is de verpleegster?,Du trenger en amme,Wciąż w pieluszkach,Tu precisas de uma Ama-de-Leite,Tu precisas de uma Ama-Seca,Doica are Nevoie de Mine,Нянечка надобна мне,Треба ти бабица,Du behöver en våtsjuksköterska,Islak bir hemşireye ihtiyacın var., +Yellowbellies-R-Us,MNU_YELLOWBELLIES,,,,"Nemehla, tož jsme my",,Vereinigte Waschlappen,,Malkuraĝuloj-as-ni,Somos pusilánimes,,Mameronapero,Un Trouillard-Tu-Est,Ne bántsék kend!,Codardo-tu-sei,我等こそが臆病者,장난감을 가지고 노는가,Verenigd washandje,Yellowbellies-R-Us,"Nie książę, lecz tchórz",Tu és um Amarelão,Tu és um Cobardolas,Nu Sunt Așa de Curajos,Не столь мужественен я,Ми-смо-жутица,Förenade ynkryggar,Birleşik Korkak Kediler, +Bringest Them Oneth,MNU_BRINGEST,,,,Chtějúci se práti?,Kom med dem,Her damit,,Al mi ilin kunvenigu,Traédnoslos,,Antaos tullaos,Amenez les moi!,Ide velük hinnye,Portali a me,招かれし者共,혈투를 벌일 준비하라,Geef me dat.,Kom med dem,Dawajże Ich,Podeis Virdes,Podeis Virdes,Aduceți-mi,Подайте мне их,Донеси изабраног,Ta med dem in,Onları Getir, +Thou art a Smite-Meister,MNU_SMITE,,,,Ktož jsú boží bojovníci,Du er mesterdræberen,Du bist der Meistertöter,,Vi Venkobatanto estas,Sois un regicida,,Olet lyömäherra,Tu est Maître-Meurtrier,Csapjunk bele kend!,Sei un maestro assassino,汝は芸術的殺戮者,그대야말로 타격의 대가,Jij bent de meestermoordenaar.,Du er mesterdraperen,Mistrz w swoim fachu,Tu és Mestre-de-Massacres,,Lupta mă Ispitește,Искушён я сражениями,Ти си обузети-мајстор,Du är en Mästerdödare,Sen baş sihirbazsın, +Black Plague Possesses Thee,MNU_BLACKPLAGUE,,,,Jsúci Smrtonošem morovým!,Den sorte pest besætter dig,Von der Pest besessen,,Nigra morto vin posedas,La peste negra os posee,,Musta surma on saanut sun,La Peste Noire me Possède!,Ehun gyün a pestis,La peste nera ti possiede,汝に憑した黒死病,흑사병이 그대를 저주 내리리,Geobsedeerd door de pest,Den svarte pesten besetter deg,Sługa Czarnej Plagi,A Peste Negra te Possui,A Peste Negra Possui-te,Ciuma Neagră mă Posedă,Чума овладела мной,Имаш црну кугу,Svarta pesten besitter dig,Kara Veba Seni Ele Geçirdi, +Squire,MNU_SQUIRE,,,,Panoš,Laird,Gutsherr,,Varleto,Escudero,,Aseenkantaja,Ecuyer,Apród,Scudiero,見習い騎士,향사,,Væpner,Giermek,Escudeiro,,Scutier,Оруженосец,Штитоноша,,Beyefendi, +Knight,MNU_KNIGHT,,,,Rytíř,Ridder,Ritter,Ιππότης,Kavaliro,Caballero,,Ritari,Chevalier,Lovag,Cavaliere,騎士,기사,Ridder,Ridder,Rycerz,Cavaleiro,,Cavaler,Рыцарь,Витез,Riddaren,Şövalye, +Warrior,MNU_WARRIOR,,,,Válečník,Kriger,Krieger,Πολεμιστής,Militisto,Guerrero,,Soturi,Guerrier,Katona,Guerriero,戦士,전사,Krijger,Kriger,Wojownik,Guerreiro,,Războinic,Воитель,Борац,Krigare,Savaşçı, +Berserker,MNU_BERSERKER,,,,Berserkr,,,,Frenezisto,,,Berserkkeri,,Harcos,,狂戦士,광전사,,,Szaleniec,,,Turbat,Берсерк,Делија,,, +Titan,MNU_TITAN,,,,Titán,,,Τιτάνας,Titano,Titán,,Titaani,,Titán,Titano,タイタン,철인,,,Tytan,Titã,,,Титан,Титан,,, +Altar Boy,MNU_ALTARBOY,,,,Ministrant,Alterdreng,Novize,,Messervanto,Monaguillo,,Pyhäkköpoika,Enfant de Chœur,Ministráns,Chirichetto,堂役,복사,Altaarjongen,Altergutt,Ministrant,Menino de coral,Menino do coro,Paracliser,Алтарник,Министрант,Altarpojke,Sunak Çocuğu, +Acolyte,MNU_ACOLYTE,,,,Akolyta,Akolyt,Missionar,,Akolito,Acólito,,Akoluutti,,Oltárszolga,Accolito,侍祭,시종,Acoliet,Akolytt,Akolita,Coroinha,Acólito,Acolit,Служитель,Помоћник,Akolyt,Yardımcı, +Priest,MNU_PRIEST,,,,Kněz,Præst,Priester,,Pastro,Sacerdote,,Pappi,Prêtre,Pap,Prete,司祭,사제,Priester,Prest,Kapłan,Padre,,Preot,Священник,Свештеник,Präst,Rahip, +Cardinal,MNU_CARDINAL,,,,Kardinál,Kardinal,Kardinal,,Kardinalo,Cardenal,,Kardinaali,,Bíboros,Cardinale,枢機卿,추기경,Kardinaal,Kardinal,Kardynał,Cardeal,,Cardinal,Кардинал,Кардинал,Kardinal,Kardinal, +Pope,MNU_POPE,,,,Papež,Pave,Papst,Πάπας,Papo,Papa,,Paavi,Pape,Pápa,Papa,教皇,교황,Paus,Pave,Papież,Papa,,Papă,Епископ,Папа,Påve,Papa, +Apprentice,MNU_APPRENTICE,,,,Učeň,Lærling,Lehrling,,Lernanto,Aprendiz,,Kisälli,Apprenti,Tanonc,Apprendista,入門者,조수,Leerling,Lærling,Uczeń,Aprendiz,,Ucenic,Ученик,Шегрт,Lärling,Çırak, +Enchanter,MNU_ENCHANTER,,,,Kouzelník,Fortryller,Zauberer,,Ravisto,Encantador,,Lumooja,Enchanteur,Bűvölő,Incantatore,妖術士,주술사,Betoveraar,Trollmann,Zaklinacz,Encantador,,Fermecător,Чародей,Чаробњак,Magiker,Sihirbaz, +Sorcerer,MNU_SORCERER,,,,Čaroděj,Troldmand,Hexer,,Sorĉisto,Hechicero,,Taikuri,Sorcier,Varázsló,Mago,魔術士,마법사,Tovenaar,Magiker,Mag,Feiticeiro,,Mag,Колдун,Врачар,Trollkarl,Büyücü, +Warlock,MNU_WARLOCK,,,,Zaklínač,,Hexenmeister,,Magiisto,Brujo,,Noita,Mage de Guerre,Boszorkánymester,Stregone,黒魔術士,전투술사,Tovenaar,Veiviser,Wiedźmak,Mago,,Vrăjitor,Чернокнижник,Вештац,Häxkarl,Efsuncu, +Archmage,MNU_ARCHMAGE,,,,Arcimág,Ærkemagiker,Erzmagier,,Magiantestro,Archimago,,Arkkivelho,Archimage,Főmágus,Arcimago,大魔導師,대마법사,Aartsbisschop,Erkemagiker,Arcymag,Arquimago,,Prim-Vrăjitor,Архимаг,Врховни вештац,Ärkemagiker,Başbüyücü, +Choose Class:,MNU_CHOOSECLASS,,,,Vyber třídu:,Vælg klasse:,Figurengruppe wählen:,,Elektu klason:,Elige tu clase:,,Valitse luokka:,Choissisez une Classe:,Válassz kasztot:,Scegli la classe:,クラス選抜:,영웅 선택:,Kies klasse:,Velg klasse:,Wybierz klasę:,Escolha a classe:,,Alege Clasa:,Класс:,Класа:,Välj klass:,Sınıf seç:, +Fighter,MNU_FIGHTER,,,,Bojovník,Kriger,Krieger,,Batalanto,Luchador,,Taistelija,Guerrier,Harcos,Combattente,戦士,전사,Vechter,Kriger,Wojownik,Lutador,,Luptător,Воин,Борац,Kämpe,Dövüşçü, +Cleric,MNU_CLERIC,,,,Klerik,Kleriker,Geistlicher,,Kleriko,Clérigo,,Pappi,Moine,Lelkész,Chierico,僧侶,성직자,Geestelijk,Kleriker,Kleryk,Clérigo,,,Клерик,Свештеник,Kleriker,Ruhban, +Mage,MNU_MAGE,,,,Mág,,Magier,,Magianto,Mago,,Velho,,Mágus,Mago,魔導士,마법사,Tovenaar,Magiker,Mag,Mago,,Magician,Маг,Чаробњак,Magiker,Sihirbaz, +Random,MNU_RANDOM,,,,Náhodný,Tilfældig,Zufällig,,Hazarda,Al azar,,Satunnainen,Au Hasard,Véletlenszerű,Casuale,ランダム,랜덤,Willekeurig,Tilfeldig,Losowa,Aleatório,,Aleatoriu,Наугад,Насумично,Slumpmässig,Rastgele, +Which Episode?,MNU_EPISODE,,,,Jakou epizodu?,Hvilken episode?,Welche Episode?,,Kiu epizodo?,¿Qué episodio?,,Mikä episodi?,Quel épisode?,Melyik epizód?,Quale episodio?,どのエピソードだ?,에피소드 선택:,Welke aflevering?,Hvilken episode?,Który Epizod?,Qual episódio?,,Care Episod?,Какой эпизод?,Која епизода?,Vilken episod?,Hangi Bölüm?, +Choose Campaign,MNU_EPISODE,,strife,,Vyber kampaň,Vælg kampagne,Mission auswählen,,Elektu kampanjon,Selecciona una campaña,,Valitse kampanja,Choisissez la Campagne,Válassz hadjáratot,Scegli la campagna,キャンペーンを選べ,캠페인을 고르시오:,Kies campagne,Velg kampanje,Wybierz kampanię,Escolha a campanha,,Alege Campania,Выбор кампании,Изабери кампању,Välj kampanj,Kampanyayı Seçin, +City of the Damned,MNU_COTD,,,,Město zatracených,Byen af de forbandede,Stadt der Verdammten,,Urbo de la damnitaj,Ciudad de los condenados,,Kirottuin kaupunki,La Cité des Damnés,Az átkozottak városa,Città del dannato,呪われた都,멸망한 도시,Stad van de verdoemden,De fordømtes by,Miasto Przeklętych,Cidade dos Condenados,,Orașul Blestemaților,Город проклятых,Град проклетих,De fördömdas stad,Lanetliler Şehri, +Hell's Maw,MNU_HELLSMAW,,,,Chřtán pekel,Helvedes gab,Der Schlund zur Hölle,,Faŭko de Infero,Fauces del infierno,,Hornankita,La Geule des Enfers,A Pokol bugyrai,Lo Stomaco dell'Inferno,地獄の肚,지옥의 목구멍,De slokdarm naar de hel,Helvetes gap,Paszcza Piekieł,A Boca do Inferno,,Străfundurile Infernului,Адское жерло,Чељусти пакла,Helvetets gap,Cehennem Ağzı, +The Dome of D'Sparil,MNU_DOME,,,,Báň D'Sparilova,D'Sparils kuppel,D'Sparils Dom,,La Kupolo de D'Sparil,La Cúpula de D'Sparil,El Domo de D'Sparil,D'Sparilin kupoli,Le Dôme de D'Sparil,D'Sparil kupolája,La Casa del D'Sparil,デ'スパリルの穹窿,드'스파릴의 돔,D'Sparils Kathedraal,D'Sparils kuppel,Gmach D'Sparila,A Cúpula de D'Sparil,,Domul lui D'Sparil,Купол Д'Спарила,Купола Д'Спарила,D'Sparils kupol,D'Sparil'in Kubbesi, +The Ossuary,MNU_OSSUARY,,,,Kostnice,Benhuset,Das Beinhaus,,La Ostejo,El Osario,,Luuhuone,L'Ossuaire,Csontkamra,L'Ossario,納骨堂,납골당,Het Ossuarium,Beinhuset,Kostnica,O Ossuário,O Ossário,Osuarul,Склеп,Костурница,Benhuset,Mezar Odası, +The Stagnant Demesne,MNU_DEMESNE,,,,Zatuchlé panství,Den stagnerede demesne,Das stagnierende Reich,,La Senmova Posedaĵo,La Heredad Estancada,,Seisahtunut maa,Le domaine Stagnant,A pangó birtok,La Proprietà terriera Stagnante,澱んだ荘園,침체된 영지,Het stagnerende rijk,Den stillestående herregården,Opuszczone Włości,O Reino Estagnado,,Tărâmul Stagnării,Застойная Демесна,Стагнирајући домени,Den stillastående demesnen,Durgun Diyar, +,,Gameplay menus,,,,,,,,,,,,,,,,,,,,,,,,,, +Teamplay,GMPLYMNU_TEAMPLAY,,,,Týmová hra,,Teamspiel,,Teamludado,Juego por equipos,,Joukkuepeli,Jeu en équipe,Csapatjáték,Gioco di squadra,チーム制,팀플레이,,Lagspill,Gra Drużynowa,Jogo em equipe,Jogo em Equipa,Joc în Echipă,Командная игра,Тимска игра,,Takım Oyunu, +Team damage scalar,GMPLYMNU_TEAMDAMAGE,,,,Faktor týmového poškození,Skala for holdskader,Team-Schadenfaktor,,Teamdamaĝo-skalio,Escalar de daño del equipo,,Omien tulen vahinkokerroin,Facteur de Tir Fratricide,Csapatsebzés mértéke,Fattore danno da fuoco amico,チームメンバーへのダメージ倍率,팀 데미지 배율,Teamschade scalair,Skalar for lagskade,Skalar Obrażeń Drużyny,Escala de fogo amigo,,Multiplicator daune,Множитель урона по своим,Мултипликатор пријатељске ватре,Skador i laget skalar,Takım hasar skalası, +Smart Autoaim,GMPLYMNU_SMARTAUTOAIM,,,,Chytré automatické zaměřování,Intelligent Autoaim,Intelligente Zielautomatik,,Inteligenta Celasisto,Autoapuntado inteligente,,Älykäs automaattitähtäys,Autovisée intelligente,Okos automata célzás,Mira automatica intelligente,スマートオートエイム,정확한 자동 조준,Slimme Autoaim,Smart Autoaim,Mądre Autocelowanie,Mira automática inteligente,,Asistare inteligentă la țintire,Умное автоприцеливание,Паметни нишан,Smart Autoaim,Akıllı Autoaim, +Falling damage,GMPLYMNU_FALLINGDAMAGE,,,,Zranění pádem,Faldskader,Fallschaden,,Faldamaĝo,Daño por caída,,Putoamisvahinko,Dommages de chute,Eséskor sebzés,Danno da caduta,落下ダメージ,낙하 데미지,Vallende schade,Fallende skade,Obrażenia przy upadku,Dano de queda,,Daune la căderi libere,Урон от падения,Штета од пада,Fallande skador,Düşme hasarı, +Drop weapon,GMPLYMNU_DROPWEAPON,,,,Odhazování zbraní,Taber våben,Waffen fallen lassen,,Faligi armilon,Arrojar arma,,Aseen pudottaminen,Arme lâchée à la mort,Fegyver eldobása,"Arma lasciata cadere +",死亡時に武器を落とす,무기 버리기,Laat het wapen vallen,Slipp våpen,Wyrzuć broń,Largar arma,,Aruncare armă,Терять оружие,Баци оружје,Släpp vapen,Silahı bırak, +Double ammo,GMPLYMNU_DOUBLEAMMO,,,,Dvojnásobná munice,Dobbelt ammunition,Doppelte Munition,,Duobla municio,Doble munición,,Tupla-ammukset,Double munitions,Dupla muníció,Doppie munizioni,弾2倍,두 배의 탄약,Dubbele munitie,Dobbel ammunisjon,Podwojona amunicja,Munição em dobro,,Muniție dublă,Удвоенные патроны,Дупла муниција,Dubbel ammunition,Çift cephane, +Infinite ammo,GMPLYMNU_INFINITEAMMO,,,,Nekonečná munice,Uendelig ammunition,Unendlich Munition,,Senlima municio,Munición infinita,,Loppumattomat ammukset,Munitions infinies,Végtelen muníció,Infinite munizioni,弾無限,무한 탄약,Oneindige munitie,Uendelig ammunisjon,Nieskończona amunicja,Munição infinita,,Muniție infinită,Бесконечные патроны,Бесконачна муниција,Oändlig ammunition,Sonsuz cephane, +Infinite inventory,GMPLYMNU_INFINITEINVENTORY,,,,Nekonečný inventář,Uendelig lagerbeholdning,Unendliche Gegenstände,,Senlima inventaro,Inventario infinito,,Loppumattomat varusteet,Objets infinis,Végtelen felszerelés,Infinito inventario,所持品無限,무한 인벤토리,Oneindige voorraad,Uendelig lagerbeholdning,Nieskończony ekwipunek,Inventário infinito,,Inventar infinit,Бесконечный инвентарь,Бесконачно складиштење,Oändligt inventarium,Sonsuz envanter, +No monsters,GMPLYMNU_NOMONSTERS,,,,Bez příšer,Ingen monstre,Keine Monster,,Neniu monstro,Sin monstruos,,Ei hirviöitä,Pas de monstres,Szörnyek nélkül,Nessun mostro,モンスターを出現させない,적 제거,Geen monsters,Ingen monstre,Brak potworów,Sem monstros,,Fără monștri,Без монстров,Без чудовишта,Inga monster,Canavar yok, +No monsters to exit,GMPLYMNU_NOMONSTERSTOEXIT,,,,Ukončení levelu pouze bez příšer,Ingen monstre for at komme ud,Keine Monster um Level zu beenden,,Neniu monstro por eliri,Sin monstruos para salir,,Ei hirviöitä tason lopettamiseksi,Rien à tuer pour sortir,Megölendő szörnyek nélkül,Nessun mostro da uccidere per uscire,モンスター全滅までMAPから脱出不可,탈출을 위한 적 제거,Geen monsters om af te sluiten,Ingen monstre å avslutte,Brak potworów do wyjścia,Sem monstros para sair da fase,Sem monstros para sair do nível,Fără monștri pentru a ieși,Убить всех монстров для выхода,Без чудовишта до излаза,Inga monster för att ta sig ut,Çıkacak canavar yok, +Monsters respawn,GMPLYMNU_MONSTERSRESPAWN,,,,Příšery se respawnují,Monstre genopstår igen,Monster kehren zurück,,Monstroj reekaperas,Reaparecer enemigos,,Hirviöt heräävät henkiin,Monstres réapparaissent,Szörnyek újraszületnek,Respawn mostri,モンスターの自力復活,적 부활,Monsters respawn,Monstre respawn,Ponowne pojawianie się potworów,Ressurgimento de monstros,,Monștrii reapar,Монстры воскрешаются,Чудовишта се оживљавају,Monster återuppstår,Canavarlar yeniden doğar, +Monsters do not respawn,GMPLYMNU_NORESPAWN,,,,Příšery se nerespawnují,Monstre respawner ikke igen,Kein Zurückkehren,,Monstroj ne reekaperas,Sin reaparición,,Ei henkiinheräämistä,Pas de réapparition,Szörnyek nem születnek újra,Nessun respawn,プレイヤーの復活禁止,부활 없음,Geen respawn,Monstre respawn ikke,Brak ponownego pojawienia się,Sem ressurgimento de monstros,,Monștrii nu reapar,Монстры не воскрешаются,Без оживљавања,Monstren återuppstår inte,Canavarlar yeniden doğmaz, +Items respawn,GMPLYMNU_ITEMSRESPAWN,,,,Předměty se respawnují,Genstande respawnes,Gegenstände erscheinen wieder,,Objektoj reekaperas,Reaparecer objetos,,Esineet syntyvät takaisin,Objets réapparaissent,tárgyak újrateremnek,Respawn oggetti,アイテムを復活,아이템 재생성,Items respawn,Gjenstander respawn,Ponowne pojawianie się przedmiotów,Ressurgimento de itens,,Obiectele reapar,Восстановление предметов,Предмети се ресетују,Föremål återuppstår.,Eşyalar yeniden doğar, +Big powerups respawn,GMPLYMNU_SUPERRESPAWN,,,,Bonusy se respawnují,Store powerups respawnes,Große Boni erscheinen wieder,,Grandaj plifortigaĵoj reekaperas,Reaparecer poderes grandes,,Isot tehostimet syntyvät takaisin,Powerups réapparaissent,Nagy képességek újraszületnek,Respawn grandi potenziamenti,強力なパワーアップアイテムを復活,파워업 재생성,Grote power-ups respawn,Store powerups respawn,Ponowne pojawianie się dużych wzmocnień,Ressurgimento de potencializadores,,Super bonusurile reapar,Восстановление больших усилений,Велики предмети се ресетују,Stora powerups återuppstår.,Büyük güçlendiriciler yeniden doğar, +Fast monsters,GMPLYMNU_FASTMONSTERS,,,,Rychlé příšery,Hurtige monstre,Schnelle Monster,,Rapidaj monstroj,Monstruos rápidos,,Nopeat hirviöt,Monstres Rapides,Gyors szörnyek,Mostri veloci,モンスター高速化,빠른 적 개체 움직임,Snelle monsters,Raske monstre,Szybkie potwory,Monstros rápidos,,Monștri rapizi,Ускоренные монстры,Брза чудовишта,Snabba monster,Hızlı canavarlar, +Monsters Nightmare Reflexes,GMPLYMNU_INSTANTREACTION,,,,Okamžité reakce příšer (obtížnost Noční můra!),Monsterrefleksioner i 'Mareridt',Monsterreflexe in 'Alptraum!'.,,Refleksoj de monstroj en Inkubo-modo,Reflejos de los monsturos en Pesadilla,,Painajaisvaikeustason hirviöiden reaktioajat,,Rémálom szintű szörny reakciók,,敵が悪夢と同じ機敏さ,,,Monstre mareritt reflekser,Refleks Potworów z Trybu Koszmar,Reflexos dos Monstros em Pesadelo,,Monștri cu Reflexe de Coșmar,Кошмарные рефлексы монстров,,Monster mardrömsreflexer,Canavarlar Kabus Refleksleri, +Degeneration,GMPLYMNU_DEGENERATION,,,,Degenerace,,,,Degenero,Degeneración,,Rappeutuva terveys,Dégéneration,Degeneráció,Degrado della salute,プレイヤーの自動体力減少,약화,Degeneratie,Degenerasjon,Degeneracja,Degeneração,,Degenerare,Уменьшать дополнительное здоровье,Смањење додатног здравља,,Dejenerasyon, +Allow Autoaim,GMPLYMNU_NOAUTOAIM,,,,Povolit automatické míření,Tillad autoaim,Zielautomatik zulassen,,Permesi cel-asiston,Permitir autoapuntar,,Salli automaattitähtäys,Autoriser Auto-visée,Autocélzás engedélyezése,Mira automatica consentita,オートエイム有効化,자동 조준 허용,Autoaim toestaan,Tillat Autoaim,Pozwól na Autocelowanie,Permitir mira automática,,Permite asistența pentru țintire,Разрешить автоприцеливание,Дозволи аутоматско циљање,Tillåt autoaim,Autoaim'e İzin Ver, +Allow Suicide,GMPLYMNU_ALLOWSUICIDE,,,,Povolit sebevraždu,Tillad selvmord,Selbstmord zulassen,,Permesi memmortigon,Permitir suicidio,,Salli itsemurha,Autoriser Suicide,Öngyilkosság engedélyezése,Suicidio consentito,自殺コマンド有効化,자살 허용,Zelfmoord toestaan,Tillat selvmord,Pozwól na Samobójstwo,Permitir suicídio,,Permite sinuciderile,Разрешить самоубийство,Дозволи самоубиство,Tillåt självmord,İntihara İzin Ver, +Allow jump,GMPLYMNU_ALLOWJUMP,,,,Povolit skákání,Tillader spring,Springen zulassen,,Permesi salton,Permitir salto,,Salli hyppiminen,Autoriser Sauts,Ugrás engedélyezése,Salto consentito,ジャンプ有効化,점프 허용,Springen toestaan,Tillat hopp,Pozwól na skakanie,Permitir pulo,Permitir salto,Permite săriturile,Разрешить прыжки,Дозволи скок,Tillåt hopp,Atlamaya izin ver, +Allow crouch,GMPLYMNU_ALLOWCROUCH,,,,Povolit klečení,Tillader krybeøvelser,Ducken zulassen,,Permesi kaŭron,Permitir agacharse,,Salli kyyristyminen,Autoriser Acroupissement,Guggolás engedélyezése,Abbassamento consentito,しゃがみ有効化,앉기 허용,Hurken toestaan,Tillat huk,Pozwól na kucanie,Permitir agachamento,,Permite ghemuirile,Разрешить приседание,Дозволи чучање,Tillåt huk,Çömelmeye izin ver, +Allow freelook,GMPLYMNU_ALLOWFREELOOK,,,,Povolit koukání nahoru/dolů,Tillader freelook,Freien Blick zulassen,,Permesi liberrigardon,Permitir visión libre,,Salli vapaa katselu,Autoriser Vue Libre,Szabad egérmozgás engedélyezése,Sguardo libero consentito,フリールック有効化,프리룩 허용,Freelook toestaan,Tillat freelook,Pozwól na swobodne rozglądanie się,Permitir visão livre,,Permite privirea în jur cu mouse-ul,Обзор мышью,Дозволи слободан поглед,Tillåt freelook,Freelook'a izin ver, +Allow FOV,GMPLYMNU_ALLOWFOV,,,,Povolit změnu FOV,Tillad FOV,Blickwinkeländerung zulassen,,Permesi vidkampon,Permitir FOV,,Salli näkökentän muokkaaminen,Autoriser Angles de vue,Látószög állítás engedélyezése,Campo visivo consentito,FOVの調整を有効化,FOV 허용,Laat FOV,Tillat FOV,Pozwól na Pole Widzenia,Permitir campo de visão,,Permite ajustarea câmpului vizual,Разрешить изменение поля зрения,Дозволи FOV,Tillåt FOV,FOV'a İzin Ver, +Allow BFG aiming,GMPLYMNU_BFGFREEAIM,,,,Povolit míření s BFG,Tillad BFG-målsætning,Zielen mit BFG zulassen,,Permesi ekceladon de BFG,Permitir apuntado de BFG,,Salli BFG-tähtäys,Autoriser Visée au BFG,BFG célzás engedélyezése,Mira BFG consentita,BFG使用時のフリールックを有効化,BFG 조준 허용,Laat BFG toe om te streven naar,Tillat BFG-sikting,Pozwól na celowanie BFG,Permitir mira de BFG,,Permite țintirea cu BFG,Разрешить прицеливание с BFG,Дозволи BFG нишање,Tillåt BFG-målning,BFG hedeflemesine izin ver, +Allow automap,GMPLYMNU_ALLOWAUTOMAP,,,,Povolit automapu,Tillader automap,Automap zulassen,,Permesi aŭtomatan mapon,Permitir automapa,,Salli automaattikartta,Autoriser Carte,Autotérkép engedélyezése,Automap consentito,オートマップ有効化,오토맵 허용,Automap toestaan,Tillat automap,Pozwól na mapę,Permitir automapa,,Permite utilizarea hărții computerizate,Разрешить использование автокарты,Дозволи мапу,Tillåt automap,Otomatik eşlemeye izin ver, +Automap allies,GMPLYMNU_AUTOMAPALLIES,,,,Zobrazit na automapě spojence,Automatisk indtegning af allierede,Verbündete zulassen,,Aliancanoj en aŭtomata mapo,Aliados en el automapa,,Omat automaattikartalla,Alliés sur la carte,Társak mutatása a térképen,Alleati nell'automap,オートマップに味方を表示,오토맵에 아군 표시,Automap bondgenoten,Automatisk kartlegging av allierte,Sojusznicy na mapie,Permitir aliados no automapa,,Aliați pe harta computerizată,Отображение союзников на автокарте,Савезници на аутомапи,Automatiska allierade,Automap müttefikleri, +Allow spying,GMPLYMNU_ALLOWSPYING,,,,Povolit špehování,Tillader spionage,Spionieren zulassen,,Permesi spionadon,Permitir espiar,,Salli vakoileminen,Autoriser espionnage,Kémkedés engedélyezése,Spionaggio consentita,死亡時の他プレイヤー観戦を許可,관전 허용,Laat spionage toe,Tillat spionering,Pozwól na śledzenie,Permitir visualização de outros jogadores,,Permite vederea prin ochii altor jucători,Разрешить вид от других игроков,Дозволи поглед од другог играча,Tillåter spionage,Casusluğa izin ver, +Chasecam cheat,GMPLYMNU_CHASECAM,,,,Povolit kameru z třetí osoby (cheat),Chasecam snyder,Verfolgerkamera Cheat,,Trompo por ĉaskamerao,Truco de vista 3era persona,,Seurantakamerahuijaus,Cheat caméra 3ième personne,Követésőkamera csalás,Cheat camera di inseguimento,チェイスカメラチート有効化,3인칭 카메라 치트,Chasecam cheat,Chasecam juks,Oszustwo kamery śledzenia,Trapaça de câmera em terceira pessoa,Batota de câmera em terceira pessoa,Trișare pentru vedere la persoana a 3-a,Разрешить вид от 3-го лица,Дозволи чејс-кем,Fusk med Chasecam,Chasecam hilesi, +Check ammo for weapon switch,GMPLYMNU_DONTCHECKAMMO,,,,Přepnout na zbraň pouze s municí,Kontroller ammunition for våbenskift,Munition beim Waffenwechsel prüfen,,Kontroli municion por armŝanĝi,Revisar munición para cambiar armas,,Tarkista ammustilanne aseenvaihdon yhteydessä,Vérifier muni. pour changer arme,Váltáskor üres fegyver átugrása,Controlla le munizioni per il cambio arma,武器切替時に弾の有無を確認,탄약 소진 시 무기 변경,Controleer munitie op wapenschakelaars.,Sjekk ammunisjon for våpenbryter,Sprawdź amunicję przy sprawdzaniu broni,Conferir munição para troca de arma,,Verifică muniția armei pentru schimbare,Проверять патроны при переключении оружия,Проверити муницију за прекидач за оружје,Kontrollera ammunition för vapenbyte,Silah anahtarı için cephaneyi kontrol edin, +Icon's death kills its spawns,GMPLYMNU_KILLBOSSSPAWNS,,,,Smrt Ikony zabije i její potomky,Ikonets død dræber dets spawns,,,La morto de la piktogramo mortigas siajn idojn,La muerte del icono destruye sus lacayos,La muerte del ícono destruye sus lacayos,Ikonin kuolema tappaa myös siitä siinneet hirviöt,Tuer L'Icône tue ses monstres,Az ikon halála esetén a teremtményei is meghalnak,La morte dell'Icona uccide tutti i suoi figli,最終ボスを殺した際に召喚モンスターも殺す,보스 사망시 소환된 적들도 사망,Icon's dood doodt zijn spawns,Ikonets død dreper dets gyter,Śmierć Ikony zabija stworzone przez nią potwory,Morte do Ícone mata os seus monstros,Morte do Ícone mata os seus demónios,Decesul Idolului anihilează propriile creații,Убить порождения Иконы при её смерти,Смрт Икона греха убија његова потомства,Ikonens död dödar dess spawns,İkon'un ölümü yumurtalarını öldürür, +End sector counts for kill %,GMPLYMNU_NOCOUNTENDMONSTER,,,,Započítávat monstra v ukončujících sektorech,Slut sektor tæller for dræber %,Monster in Level-Beenden-Sektor zählen,,Finsektoro kalkulas al nombro da mortigoj,Sector de salida cuenta para % de muertes,,Loppusektori lasketaan mukaan tappoprosenttiin,Ennemis du secteur sortie comptés,Utolsó szektornál számít az ölés %,Conteggio dei nemici da uccidere nel settore in %,最終セクターの敵もキルに含む,레벨종료 섹터의 적들도 킬 수에 포함,Eindsector telt voor kill %,Slutt sektor teller for drap i prosent,"Zliczanie potworów w sektorze kończącym poziom +",Setor de saída conta para porcentagem de mortes,Setor de saída conta para percentagem de mortes,Numărare decese monștri în sectoare finale,Засчитывать убийства монстров в секторах конца игры,Урачунај убиство чудовишта у коначним секторима,Slutsektorn räknas för dödande %,Öldürme %'si için son sektör sayıları, +Deathmatch Settings,GMPLYMNU_DEATHMATCH,,,,Nastavení deathmatche,Indstillinger for Deathmatch,Deathmatcheinstellungen,,Mortmatĉo-agordoj,Configuración modo a muerte,,Kuolonotteluasetukset,Options Deathmatch,Deathmatch beállítások,Impostazioni deathmatch,デスマッチの設定,데스매치 설정,Deathmatch instellingen,Deathmatch-innstillinger,Ustawienia Deathmatchu,Configurações de Deathmatch,,Setări Deathmatch,Настройки боя насмерть,Детмеч подешавања,Inställningar för Deathmatch,Ölüm Maçı Ayarları, +Weapons stay,GMPLYMNU_WEAPONSSTAY,,,,Zbraně zůstávají,Våben forbliver,Waffen bleiben,,Armiloj restiĝas,Las armas se quedan,,Aseet pysyvät,Armes restent au sol quand prises,Fegyverek mindig felvehetőek,Le armi rimangono in posizione,武器を取得時も残す,습득 후 무기가 남아있기,Wapenverblijven,Våpen forblir,Bronie zostają,Armas permanecem,,Părăsire arme după selectare,Оставлять оружие после подбора,Оружје се остаје након купљења,Vapen stannar kvar,Silahlar kalıyor, +Allow powerups,GMPLYMNU_ALLOWPOWERUPS,,,,Povolit bonusy,Tillad powerups,Boni erlauben,,Permesi plifortigaĵojn,Permitir poderes,,Salli tehostimet,Autoriser powerups,Powerupok engedélyezése,Potenziamenti consentiti,パワーアップアイテムを出現させる,파워 업 허용,Power-ups toestaan,Tillat powerups,Pozwól na wzmocnienia,Permitir powerups,,Permite bonusuri,Разрешить бонусы,Дозволи бонусе,Tillåter powerups,Güçlendirmelere izin ver, +Allow health,GMPLYMNU_ALLOWHEALTH,,,,Povolit zdraví,Tillad sundhed,Gesundheit erlauben,,Permesi sanon,Permitir salud,,Salli terveysesineet,Autoriser objets santé,Életerő engedélyezése,Oggetti per la salute consentiti,回復アイテムを出現させる,체력 회복 아이템 허용,Gezondheid toestaan,Tillat helse,Pozwól na przedmioty zdrowotne,Permitir itens de saúde,,Permite prim-ajutor,Разрешить здоровье,Дозволи бонусе за здравље,Tillåter hälsa,Sağlığa izin ver, +Allow armor,GMPLYMNU_ALLOWARMOR,,,Allow armour,Povolit brnění,Tillad rustning,Panzer erlauben,,Permesi kirason,Permitir armadura,,Salli panssariesineet,Autoriser objets armure,Páncél engedélyezése,Armature consentite,アーマーを出現させる,아머 허용,Pantsertoeslag toestaan,Tillat rustning,Pozwól na pancerz,Permitir itens de armadura,,Permite bonusuri de armură,Разрешить броню,Дозволи оклоп,Tillåt rustning,Zırha izin ver, +Spawn farthest,GMPLYMNU_SPAWNFARTHEST,,,,Spawnovat hráče co nejdále od sebe,Spawn længst væk,Am weitesten entfernten Punkt erscheinen,,Ekaperi plej fore,Aparecer más lejos,,Herää henkiin kauimpaa,Apparaître au plus loin,Legmesszebb születés,Spawn il più lontano possibile,他のプレイヤーから最遠の場所に復活,먼 곳에서 소환,Kuitschieten het verst verwijderd,Spawn lengst,Pojaw się jak najdalej,Surgimento mais longe,,Apariție cât mai departată de ceilalți,Воскрешение подальше от остальных,Оживљавање даље од других,Spawna längst bort,En uzakta yumurtla, +Same map,GMPLYMNU_SAMEMAP,,,,Stejná mapa,Samme kort,Gleiches Level,,Sama mapo,Mismo mapa,,Sama taso,Même Carte,Ugyanazon pálya,Stessa mappa,同じMAPを繰り返す,같은 맵 플레이,Dezelfde kaart,Samme kart,Ta sama mapa,Mesmo mapa,,Reluare nivel,Зациклить уровень,Понављање нивоа,Samma karta,Aynı harita, +Force respawn,GMPLYMNU_FORCERESPAWN,,,,Vynutit respawn,Tvinge respawn,Zurückkehren erzwingen,,Devigi reekaperon,Forzar reaparición,,Pakota henkiinherääminen,Forcer Réapparition,Újraszületés kényszerítése,Forza il respawn,死亡後に強制復活,강제 부활,Respawn is gedwongen,Force respawn,Wymuś ponowne pojawienie się,Forçar reaparecimento,,Reapariție instantă,Моментальное воскрешение,Форсирано оживљавање,Tvinga till återkomst,Yeniden doğmaya zorla, +Allow exit,GMPLYMNU_ALLOWEXIT,,,,Povolit ukončení levelu,Tillad at forlade,Verlassen erlauben,,Permesi eliron,Permitir salir,,Salli tasosta poistuminen,Autoriser Sortie,Kijárat engedélyezése,Uscita consentita,出口の使用を許可,탈출 허용,Uitgang toestaan,Tillat utgang,Pozwól na wyjście,Permitir saída,,Permite ieșirea,Разрешить выход,Дозволи излазак из нивоа,Tillåter utgång,Çıkışa izin ver, +Barrels respawn,GMPLYMNU_BARRELSRESPAWN,,,,Barely se respawnují,Tønder respawner,Fässer kehren zurück,,Bareloj reekaperas,Reaparecer barriles,,Tynnyrit syntyvät takaisin,Réapparition des Tonneaux,Hordók újraszületése,Respawn barili esplosivi,爆発バレルを復活させる,폭발통 재생성,Vaten respawn,Tønner respawn,Beczki pojawiają się ponownie,Barrís reaparecem,,Butoaiele reapar,Восстановление бочек,Бурад се ресетују,Tunnor återkommer,Variller yeniden doğar, +Respawn protection,GMPLYMNU_RESPAWNPROTECTION,,,,Ochrana po respawnu,Respawn-beskyttelse,Schutz beim Zurückkehren,,Protekto de reekapero,Reaparecer protección,,Henkiinheräämissuoja,Protection à la réapparition,Újraszületési védelem,Protezione al respawn,復活したばかりのプレイヤーを保護,부활시 무적,Respawn bescherming,Respawn-beskyttelse,Ochrona przy ponownym pojawieniu się,Proteção de reaparecimento,,Protecție la apariția pe hartă,Кратковременная защита после воскрешения,Ресетује се заштита,Skydd för återstart,Yeniden doğma koruması, +Lose frag if fragged,GMPLYMNU_LOSEFRAG,,,,"Hráč ztratí frag, pokud je zabit",Mister frag hvis der er en fragged,Fragabzug bei Tod,,Perdi ludmurdon se ludmurdita,Perder baja al morir,,"Frägin menettäminen, jos joutuu frägätyksi",Perdre 1 frag quand tué,Halál esetén pont veszítése,Perdere i frag se fraggato,キルされた場合は得点を失う,적에게 사망시 점수를 잃음,Verlies frag bij dood,Miste frag hvis fragged,Strać fraga jeśli jesteś sfragowany,Perder frag ao ser fragado,,Pierdere din victime la deces,Терять фраг при смерти,Изгубити гранату ако опаљена,Förlorar frag om du blir träffad,Parçalanırsa parça kaybeder, +Keep frags gained,GMPLYMNU_KEEPFRAGS,,,,Ponechávat fragy mezi levely,Beholde vundne frags,Frags zwischen Leveln behalten,,Teni ludmurdojn gajnitajn,Mantener bajas ganadas,,Pidä ansaitut frägit,Garder les frags gagnés,Megszerzett pontok megmaradnak,Mantenere i frag vinti,MAP変更後も得点を保持する,맵 변경 시 점수 유지,Houd frags opgedaan,Behold frags vunnet,Zachowaj zdobyte fragi,Manter frags ganhos,,Păstrare număr victime,Сохранять фраги между уровнями,Задржати стечене гранате,Behåll de frags som vunnits,Kırıntıları kazanmaya devam edin, +No team switching,GMPLYMNU_NOTEAMSWITCH,,,,Uzamknout týmy,Ingen holdskifte,Kein Teamwechsel,,Neniu teamŝanĝado,No cambiar equipos,,Ei joukkueenvaihtoa,Pas de changement d'équipe,Nincs csapatváltás,Nessun cambio di squadra,チーム変更を禁止,팀 변경 없음,Geen teamwisseling,Ingen lagbytte,Zakaz zmieniania drużyn,Desativar troca de time,Desativar troca de equipa,Nu permite schimbarea echipelor,Запретить переход между командами,Нема мешања тимова,Inget byte av lag,Takım değiştirme yok, +Cooperative Settings,GMPLYMNU_COOPERATIVE,,,,Nastavení co-op módu,Kooperativ indstillinger,Kooperativ-Einstellungen,,Agordoj de koopera reĝimo,Configuración de cooperativo,,Yhteispeliasetukset,Options Coopératives,Együttműködő beállítások,Impostazioni cooperativa,協力モードの設定,협동 플레이 설정,Coöperatieve instellingen,Samarbeidsinnstillinger,Ustawienia Kooperacji,Configurações de jogo cooperativo,,Setări cooperative,Настройки совместной игры,Кооперативне поставке,Inställningar för samarbete,Kooperatif Ayarları, +Spawn multiplayer weapons,GMPLYMNU_MULTIPLAYERWEAPONS,,,,Spawnovat multiplayerově zbraně,Spawn multiplayer-våben,Deathmartch Waffen sind verfügbar,,Ekaperigi armilojn por plurludanta reĝimo,Aparecer armas multi.,,Kuolonotteluaseet saatavilla,Spawns d'armes deathmatch,Többjátékos fegyverek engedélyezése,Fai apparire le armi di multigiocatore,マルチプレイ用の武器を出現させる,멀티플레이어 무기 소환,Spawn multi. wapens,Spawn flerspillervåpen,Zezwól na bronie trybu dla wielu graczy,Surgimento de armas em multijogador,,Permite apariția armelor din modul online,Появление оружия из сетевой игры,Створити мулти оружја,Spawna flerspelarvapen,Çok oyunculu silahları ortaya çıkarma, +Lose entire inventory,GMPLYMNU_LOSEINVENTORY,,,,Ztrácet celý inventář,Mister hele inventaret,Verliere ganzes Inventar,,Perdi tutan inventorion,Perder todo el inventario,,Menetä kaikki varusteet,Perdre l'inventaire,Teljes készlet elvesztése,Perdere l'inventario,死亡時に全ての所持品を失う,인벤토리 비우기,Verlies van de volledige inventaris,Miste hele beholdningen,Utrać cały ekwipunek,Perder todo o inventário,,Pierdere inventar,Терять весь инвентарь при смерти,Изгубити цело складиште,Förlorar hela inventariet,Tüm envanteri kaybetmek, +Keep keys,GMPLYMNU_KEEPKEYS,,,,Ponechat klíče,Beholde nøgler,Schlüssel behalten,,Teni ŝlosiojn,Mantener llaves,,Pidä avaimet,Garder clés,Kulcsok megtartása,Mantenere le chiavi,死亡後もキーを保持する,열쇠들을 소지하고 시작,Sleutels bewaren,Behold nøkler,Zachowaj klucze,Manter chaves,,Păstrare chei,Сохранять ключи,Задржати кључеве,Behåll nycklar,Anahtarları sakla, +Keep weapons,GMPLYMNU_KEEPWEAPONS,,,,Ponechat zbraně,Behold våben,Waffen behalten,,Teni armilojn,Mantener armas,,Pidä aseet,Garder armes,Fegyverek megtartása,Mantenere le armi,死亡後も武器を保持する,무기들을 소지하고 시작,Wapens bewaren,Behold våpen,Zachowaj bronie,Manter armas,,Păstrare arme,Сохранять оружие,Задржати оружје,Behåll vapen,Silahları saklayın, +Keep armor,GMPLYMNU_KEEPARMOR,,,Keep armour,Ponechat brnění,Behold rustning,Rüstung behalten,,Teni kirason,Mantener armadura,,Pidä panssari,Garder armure,Páncél megtartása,Mantenere l'armatura,死亡後もアーマーを保持する,아머를 소지하고 시작,Pantser bewaren,Behold rustning,Zachowaj pancerz,Manter armadura,,Păstrare armură,Сохранять броню,Задржати панцир,Behåll rustning,Zırhı sakla, +Keep powerups,GMPLYMNU_KEEPPOWERUPS,,,,Ponechat bonusy,Beholde powerups,Behalte Boni,,Teni plifortigaĵojn,Mantener poderes,,Pidä tehostimet,Garder powerups,Powerupok megtartása,Mantenere i potenziamenti,死亡後もパワーアップを保持する,파워업을 소지하고 시작,Power-ups bewaren,Behold powerups,Zachowaj wzmocnienia,Manter powerups,,Păstrare bonusuri,Сохранять супербонусы,Задржати повећану моћ,Behåll powerups,Güçlendirmeleri sakla, +Keep ammo,GMPLYMNU_KEEPAMMO,,,,Ponechat munici,Beholde ammunition,Munition behalten,,Teni municion,Mantener munición,,Pidä ammukset,Garder munitions,Muníció megtartása,Mantenere le ammunizioni,死亡後も弾薬を保持する,탄약을 소지하고 시작,Munitie bewaren,Behold ammunisjon,Zachowaj amunicję,Manter munição,,Păstrare armură,Сохранять патроны,Задржати муницију,Behålla ammunition,Cephaneyi sakla, +Lose half ammo,GMPLYMNU_LOSEHALFAMMO,,,,Ztratit polovinu munice,Mister halvdelen af ammunitionen,Halbe Munition verlieren,,Perdi duonon de onia municio,Perder la mitad de la munición,,Menetä puolet ammuksista,Perdre la moité des munitions,Fele muníció elvesztése,Perdere metà ammunizioni,死亡時に弾を半分失う,탄약의 반을 잃음,Verlies halve munitie,Miste halv ammunisjon,Utrać pół amunicji,Perder metade da munição,,Pierdere jumătate din armură,Терять половину патронов,Изгубити пола муниције,Förlorar halva ammunitionen,Cephanenin yarısını kaybet, +Spawn where died,GMPLYMNU_SPAWNWHEREDIED,,,,Respawn na místě smrti,Spawn hvor du døde,Neuerscheinen wo gestorben,,Ekaperigi kie oni mortigis,Aparecer donde moriste,,Herää henkiin kuolinpaikalla,Réapparaitre sur lieu de mort,Halál helyén újraszületés,Respawn nel luogo di morte,死亡したその場で復活,죽은 곳에서 소환,Kuit waar gestorven is,Gyte der du døde,Pojaw się znów tam gdzie zginąłeś,Surgir no local da morte,Reaparecer onde morreu,Apariție la locul decesului,Воскрешение на месте смерти,Оживљавање на месту смрти,Spawna där du dog,Öldüğü yerde yumurtlama, +Always spawn multiplayer objects,GMPLYMNU_ALWAYSSPAWNMULTI,,,,Vždy spawnovat multiplayerové objekty,Spawn altid multiplayer-objekter,Mehrspielerobjekte immer erzeugen,,Ĉiam ekaperi plurludantajn objektojn,Siempre hacer aparecer objetos en el modo multijugador,,Aina luo moninpelioliot,Toujours créer des objets multi-joueurs,Mindig megjelennek a többjátékos tárgyak,Fai sempre apparire gli oggetti di multigiocatore,常にマルチプレイ用の物を出現,,Altijd multiplayer objecten spawnen,Alltid gyte flerspillerobjekter,Pozwól na przedmioty dla trybu wielu graczy,Permitir surgimento de objetos multijogador,,Permite apariția obiectelor din multiplayer,Появление объектов из сетевой игры,Увек стварајте објекте за више играча,Alltid spawna flerspelarobjekt,Her zaman çok oyunculu nesneler oluşturun, +Allow Vertical Bullet Spread,GMPLYMNU_NOVERTSPREAD,,,,Povolit svislý rozptyl střelby,Tillad lodret kuglespredning,Vertikale Streuung erlauben,,Permesi vertikalan kuglan disvastiĝon,Desparramar balas de todas las armas en vertical,,Permesu Vertikalan Kuglon Disvastiĝon ,Permettre la propagation verticale des balles,Vertikális fegyverszórás engedélyezve,Permetti la diffusione dei proiettili in verticale,垂直方向への散弾を許可,,Verticale kogelspreiding toestaan,Tillat vertikal kulespredning,Pozwól na pionowy rozrzut pocisków,Permitir dispersão vertical das balas,,Permiteți răspândirea verticală a gloanțelor,Разрешить вертикальный разброс пуль,Дозволи вертикално ширење метака,Tillåt vertikal kulspridning,Dikey Mermi Yayılımına İzin Ver, +Weapons give extra ammo (DM),GMPLYMNU_NOEXTRAAMMO,,,,Zbraně dávají munici navíc (DM),Våben giver ekstra munition (DM),Waffen geben Extramunition,,Armiloj donas ekstran municion (DM),Las armas dan munición extra (DM),,Armiloj donas ekstran municion (DM),Les armes donnent des munitions supplémentaires (DM),A fegyverek extra lőszert adnak (DM),Le armi danno munizioni extra (DM),武器に追加弾薬を付与 (DMのみ),,Wapens geven extra munitie (DM),Våpen gir ekstra ammunisjon (DM),Broń daje dodatkową amunicję (DM),Armas dão munição extra (DM),,Armele oferă muniție suplimentară (DM),Оружие даёт дополнительные патроны (бой насмерть),Оружје даје додатну муницију (ДМ),Vapen ger extra ammunition (DM),Silahlar ekstra cephane verir (DM), +Compatibility Options,OPTMNU_COMPATIBILITY,,,,Kompatibilita,Kompatibilitetsindstillinger,Kompatibilitätsoptionen,Ρυθμίσεις Συμβατότητας,Kongruo-agordoj,Opciones de compatibilidad,,Yhteensopivuusasetukset,Options de Compatibilité,Kompatibilitási beállítások,Opzioni Compatibilità,互換性 オプション,호환 설정,Compatibiliteitsopties,Kompatibilitetsalternativer,Opcje Zgodności,Opções de compatibilidade,,Setări de Compatibilitate,Настройки совместимости,Компатибилност,Kompatibilitetsalternativ,Uyumluluk Seçenekleri, +Compatibility Options,CMPTMNU_TITLE,,,,Nastavení kompatibility,Kompatibilitetsindstillinger,Kompatibilitätsoptionen,Ρυθμίσεις Συμβατότητας,Kongruo-agordoj,Opciones de compatibilidad,,Yhteensopivuusasetukset,Options Compatibilité,Kompatibilitási beállítások,Opzioni compatibilità,互換性 オプション,호환성 설정,Compatibiliteitsopties,Kompatibilitetsalternativer,Opcje Zgodności,Opções de compatibilidade,,Setări de Compatibilitate,Настройки совместимости,Компатибилна подешавања,Kompatibilitetsalternativ,Uyumluluk Seçenekleri, +Compatibility mode,CMPTMNU_MODE,,,,Režim kompatibility,Kompatibilitetstilstand,Kompatibilitätsmodus,,Kongruo-reĝimo,Modo de compatibilidad,,Yhteensopivuustila,Mode de compatibilité,Kompatibilitási mód,Modalità compatibilità,互換性モード,호환 모드,Compatibiliteitsmodus,Kompatibilitetsmodus,Tryb Zgodności,Modo de compatibilidade,,Mod Compatibilitate,Режим совместимости,Компатибилни мод,Kompatibilitetsläge,Uyumluluk modu, +Actor Behavior,CMPTMNU_ACTORBEHAVIOR,,,Actor Behaviour,Objekty,Skuespilleradfærd,Verhalten der Akteure,,Aktorkonduto,Comportamiento del actor,,Olioiden käyttäytyminen,Comportement des Acteurs,Actor viselkedés,Comportamento degli attori,アクターの挙動,개체 관련 설정,Gedrag van de acteur,Skuespilleroppførsel,Zachowanie Aktorów,Comportamento de atores,,Comportament actori,Поведение объектов (акторов),Понашање актора,Beteende hos skådespelare,Aktör Davranışı, +Friendly monsters aren't blocked,CMPTMNU_NOBLOCKFRIENDS,,,,Spojenecké příšery nejsou blokovány,Venlige monstre er ikke blokeret,Freundliche Monster werden nicht geblockt,,Amikaj monstroj ne estas baritaj,Monstruos amistosos no son bloqueados,,Myötämielisten hirviöiden esteetön liikkuminen,Monstres amicaux non bloqués,Barátságos szörnyek nem blokkolódnak,I mostri amichevoli non sono bloccati,仲間キャラは敵通行不可ラインの影響を受けない,아군 개체는 BLOCK 선분 무시,Vriendelijke monsters worden niet geblokkeerd.,Vennlige monstre er ikke blokkert,Przyjazne potwory nie mogą być blokowane,Monstros aliados não são bloqueados,,Monștrii aliați nu pot fi blocați,Не блокировать дружественных монстров,Пријатељска чудовишта се не блокирају,Vänliga monster blockeras inte,Dost canavarlar engellenmez, +Limit Pain Elementals' Lost Souls,CMPTMNU_LIMITPAIN,,,,Omezit počet Ztrac. duší (Lost Souls) od Živlů (Pain Elementals),Grænse for tabte sjæle,Limit für Verlorene Seelen,,Limigi Perditajn Animojn de Doloro-Elementuloj,Limitar Almas Errantes de los Elementales del Dolor,,Rajoita kivun henkien kadonneitten sielujen määrää,Limiter âmes des élémentaires,Kiköpött Elveszett Lelkek limitálása,Limita le Anime Erranti degli Elementali del dolore,ペインエレメンタルのロストソウル制限,로스트 소울 소환 21개로 제한,Beperk de Verloren Zielen van Pijn Elementairs,Begrens smertelementalers tapte sjeler,Ogranicz Zagubione Dusze Elementala Bólu,Limitar Almas Perdidas criadas por Elementais da Dor,,Limitează numărul Sufletelor Pierdute create de Elementalii Durerii,Ограничить число потерянных душ от элементалей боли,Ограничи изгубљене душе од елементала патње,Begränsa Pain Elementals förlorade själar,Acı Elementallerinin Kayıp Ruhlarını Sınırla, +Monster movement is affected by effects,CMPTMNU_MBFMONSTERMOVE,,,,Pohyb příšer je ovlivněn efekty,Monsterbevægelse er påvirket af effekter,Monsterbewegung wird von Effekten beeinflusst,,Monstromovado estas afektita per efektoj,Los efectos afectan al movimiento de los monstruos,,Tehosteet vaikuttavat hirviöiden liikkumiseen,Mouvement monstre affecté par effets,Szörny sebesség függ az effektektől,Il movimento dei mostri è affetto dagli effetti,敵の移動が床の影響を受ける,구역의 이동 효과가 개체들에 영향,Monsterbeweging wordt beïnvloed door effecten,Monsterbevegelse påvirkes av effekter,Efekty wpływają na ruch potworów,Movimento dos monstros é afetado por efeitos,,Efectele afectează deplasarea monștrilor,Эффекты влияют на движение монстров,Ефекти утицају на покретљивост чудовишта,Monsterrörelse påverkas av effekter,Canavar hareketi etkilerden etkilenir, +Monsters cannot cross dropoffs,CMPTMNU_CROSSDROPOFF,,,,Příšery nemohou překročit výšiny,Monstre kan ikke krydse faldgruber,Monster können Abbruchkanten nicht überqueren,,Monstroj ne povas movi trans krutaĵojn,Los monstruos no pueden cruzar declives,,Hirviöt eivät voi ylittää pudotuksia,Monstres ne passent pas les corniches,Szörnyek le tudnak esni a lejtőről,I mostri non posso attraversare gli spigoli,敵はdropoffを横切れない,개체들이 난간에서 추락 불가,Monsters kunnen geen dropoffs kruisen,Monstre kan ikke krysse dropoffs,Potwory nie mogą przekraczać spadków,Monstros não podem atravessar penhascos,,Monștrii nu pot trece peste prăpăstii,Монстрам нельзя пересекать уступы,Чудовишта не могу прећи падове,Monster kan inte korsa stupstockar,Canavarlar inişleri geçemez, +Monsters get stuck over dropoffs,CMPTMNU_DROPOFF,,,,Příšery se zasekávají na výšinách,Monstre bliver hængende over faldgruber,Monster bleiben auf Abbruchkanten hängen,,Monstroj ĉesiĝi super krutaĵoj,Los monstruos se atascan sobre declives,Los monstruos se atoran sobre declives,Hirviöt joutuvat jumiin pudotusten ylle,Monstres bloqués par les corniches,Szörnyek nem mennek tovább a lejtőnél,I mostri rimangono bloccati sugli spigoli,敵がdropoffにスタックする,개체들이 난간에 끼일 수 있음,Monsters komen vast te zitten boven dropoffs,Monstre blir sittende fast over dropoffs,Potwory mogą utknąć nad spadkami,Monstros ficam presos em penhascos,,Monștrii înțepenesc peste prăpăstii,Монстры застревают на уступах,Чудовишта се заглављују на падовима,Monster fastnar över stupstockar,Canavarlar inişlerde sıkışıp kalıyor, +Monsters see invisible players,CMPTMNU_INVISIBILITY,,,,Příšery vidí neviditelné hráče,Monstre kan se usynlige spillere,Monster können unsichtbare Spieler sehen,,Monstroj povas vidi nevideblajn ludantojn,Los monstruos ven jugadores invisibles,,Hirviöt näkevät näkymättömät pelaajat,Monstres voient joueurs invisibles,Láthatatlanság alatt is látható a játékos,I mostri vedono i giocatori invisibili,敵が透明を見破る,개체들이 투명 플레이어 감지 가능,Monsters zien onzichtbare spelers,Monstre ser usynlige spillere,Potwory widzą niewidzialnych graczy,Monstros enxergam jogadores invisíveis,,Monștrii pot vedea jucătorii invizibili,Монстры видят невидимых игроков,Чудовишта могу да виде невидљиве играче,Monster ser osynliga spelare,Canavarlar görünmez oyuncuları görür, +No Minotaur floor flames in water,CMPTMNU_MINOTAUR,,,,Minotauři nemohou tvořit plameny ve vodě,Ingen Minotaur gulvflammer i vand,Keine Minotaurus-Flammen im Wasser,,Neniuj plankfajroj de Mintaŭroj en akvo,Sin llamas de minotauro en el agua,,Ei minotaurien lattialiekkejä vedessä,Pas de feu de Massetaur sur l'eau,Minotaurusz égő nyom nincs a vízben,Niente fiamme da terra del Minotauro sull'acqua,ミノタウロスの攻撃が水を通過しない,수면에서는 몰로타우어 지면화염 차단,Geen Minotaurus vloer vlammen in water,Ingen Minotaur-gulvflammer i vann,Brak płomieni Minotaura w wodzie,Desativar fogo do Marretauro na água,,Minotaurii nu pot folosi atacul de foc pe apă,Минотавры не создают огонь в воде,Минотаури не пале ватру у води,Ingen Minotaur golvlåga flammar i vatten,Suda Minotor zemin alevleri yok, +Spawn item drops on the floor,CMPTMNU_NOTOSSDROPS,,,,Spadlé předměty se objeví na zemi,Spawn-genstande falder på gulvet,Gegenstände erscheinen auf dem Fußboden,,Ekaperigi faligitajn objektojn sur la plankon,Aparecer objetos dejados en el suelo,,Synnytä esinepudotukset lattialle,Objets lâchés direct au sol,Spawnolt tárgy a földön jelenik meg,Gli oggetti allo spawn cadono a terra,アイテムドロップが床に出る,아이템이 떨어질때 지면에 즉시 착지,Paaipunt druppels op de vloer,Spawn-element faller på gulvet,Obiekty pojawiają się na podłodze,Itens surgidos caem direto no chão,,Obiectele scăpate vor apărea la nivelul podelei,Выброшенные предметы создаются на земле,Одбачени предмети се појављују на поду,Spawner föremål faller på golvet.,Eşya yere düşer, +DehackEd Behavior,CMPTMNU_DEHACKEDBEHAVIOR,,,DehackEd Behaviour,DeHackEd,DehackEd Adfærd,DehackEd Verhalten,,Konduto de DehackEd,Comportamiento de DehackEd,,DehackEd-käyttäytyminen,Comportement DeHackEd,DeHackEd viselkedés,Comportamento DehackEd,DehackEdの挙動,DehackEd 관련 설정,DehackEd Gedrag,DehackEd oppførsel,Zachowanie DehackEd,Comportamento DehackEd,,Comportament DehackEd,Поведение DeHackEd,DehackEd понашање,DehackEd-beteende,DehackEd Davranışı, +DEH health settings like Doom2.exe,CMPTMNU_DEHHEALTH,,,,Nastavení DEH jako v Doom2.exe,DEH sundhedsindstillinger som Doom2.exe,DEH Gesundheitseinstellungen wie in Doom2.exe,,DEH sanagordoj kiel Doom2.exe,Configuración de salud DEH como en Doom2.exe,,DEH-terveysasetukset kuin Doom2.exessä,Para. santé DEH comme Doom2.EXE,DEH életerő beállítások mint a Doom2.exe esetében,Impostazioni di salute DEH come in Doom2.exe,Doom2.exe式のDEHヘルス設定,DEH 자체의 체력 최댓값 사용,DEH-gezondheidsinstellingen zoals Doom2.exe,DEH helseinnstillinger som Doom2.exe,Ustawienia zrowia DEH jak w Doom2.exe,Configurações de saúde de DEH como em Doom2.exe,,Setări sănătate în DEH precum în Doom2.exe,Настройки здоровья DEH как в Doom2.exe,DEH подешавања здравља као у Doom2.exe,DEH-hälsoinställningar som Doom2.exe,Doom2.exe gibi DEH sağlık ayarları, +Original A_Mushroom speed in DEH mods,CMPTMNU_MUSHROOM,,,,Původní rychlost pro A_Mushroom,Original A_Mushroom hastighed i DEH mods,Originale Berechnung für A_Mushroom,,Originala A_Mushroom rapideco en DEH-modifaĵoj,Velocidad original de A_Mushroom en mods con DEH,,Alkuperäinen A_Mushroom-nopeus DEH-modeissa,Vitesse A_Mushroom originale pour DEH,Eredeti A_Mushroom sebesség a DEH modoknál,Velocità originale di A_Mushroom nei mod DEH,DEH Modでの元のA_Mushroom速度,A_Mushroom효과가 MBF 원본의 속력 사용,Originele A_Mushroom in DEH-modellen,Original A_Mushroom hastighet i DEH mods,Oryginalna prędkość A_Mushroom w modach DEH,Velocidade original do A_Mushroom em mods DEH,,Folosește viteza originală pentru A_Mushroom în DEH în moduri,Изначальная скорость A_Mushroom в мод. DEH,Оригинална брзина A_Mushroom в DEH модовима,Ursprunglig A_Mushroom-hastighet i DEH-modifieringar,DEH modlarında orijinal A_Mushroom hızı, +Map/Action Behavior,CMPTMNU_MAPACTIONBEHAVIOR,,,Map/Action Behaviour,Levely a akce,Map/Action Adfærd,Level/Aktionsverhalten,,Mapo/Ago-Konduto,Comportamiento Mapa/Acción,,Tason/Toimintojen käyttäytyminen,Comportement Niveau/Actions,Pálya/Akció viselkedés,Comportamento Mappa/Azioni,マップ/アクションの挙動,맵/동작 관련 설정,Kaart/Actiegedrag,Kart / handling oppførsel,Zachowanie Mapy/Akcji,Comportamento de Mapa/Ação,,Comportament hartă/actori,Поведение уровней/действий,Понашање нивоа/догађаја,Beteende för kartor/handlingar,Harita/Eylem Davranışı, +All special lines can block ,CMPTMNU_USEBLOCKING,,,,Veškeré akční čáry blokují použití hráčem,Alle specielle linjer kan blokere ,Alle Speziallinien blockieren Benutzung,,Ĉiuj el specialaj linioj povas bari je ,Todas las líneas especiales pueden bloquear ,,Kaikki erikoisviivat voivat tukkia -toiminnon,Toute ligne d'action bloque ,Minden speciális sor blokkolhatja a parancsot,Tutte le linee speciali possono bloccare il comando ,全てのSpecial Linesがをブロック,특정 선상에 겹쳐있을 시 <사용> 무력화,Alle speciale lijnen kunnen blokkeren.,Alle spesielle linjer kan blokkere ,Wszystkie specjalne linie mogą blokować ,Todas as linhas especiais podem bloquear o comando ,,Toate liniile speciale pot bloca ,Все специальные линии могут блокировать использование,Све специјалне линије могу да блокирају ,Alla speciella linjer kan blockera ,Tüm özel hatlar engelleyebilir, +Allow any bossdeath for level special,CMPTMNU_ANYBOSSDEATH,,,,Smrt jakéhokoli bosse může aktivovat speciální akci levelu,Tillad enhver bossdeath for level special,Jeder Boss-Tod zählt für Spezialaktionen,,Permesi iun ajn estro-morton por nivelspecialo,Permitir cualquier muerte de jefe por especial de nivel,,Mikä tahansa pomokuolema lasketaan tason erikoistoiminnossa,N'importe quel boss active actions boss,Főgonosz halála megengedett a speciális pályákon,"Qualunque morte del boss per le azioni speciali consentita +",いずれのBossdeathでもlevel specialを許可,어느 레벨에서든 BOSSDEATH 이벤트 허용,Laat een eventuele bossdood voor een speciaal niveau toe....,Tillat enhver bossdeath for nivå spesiell,Każda śmierć bossa liczy się jako akcja specjalna,Permitir qualquer morte de chefão para ação especial,Permitir qualquer morte de chefe para ação especial,Orice utilizare de A_BossDeath activează evenimente speciale în nivel,Любой вызов A_BossDeath активирует special уровня,Било који случај A_BossDeath активира special на нивоу,Tillåt alla bossdödsfall för specialnivå,Özel seviye için herhangi bir boss ölümüne izin ver, +Disable BOOM door light effect,CMPTMNU_NODOORLIGHT,,,,Zakázat světelný efekt dveří z BOOMu,Deaktivere BOOM dør lys effekt,Boom-Türlichteffekt deaktiviert.,,Malvalidigi pordlumo-efekton de BOOM,Desactivar efecto de luz de puerta de BOOM,,BOOM-ovivalotehoste pois käytöstä,Pas d'effet de lumière BOOM sur portes,A BOOM ajtó fény effekt kikapcsolása ,Disabilitato l'effetto Boom della luce della porta,BOOMドアライト エフェクトを無効化,붐 문간 조명보정 효과 끄기,BOOM-deurlichteffect uitschakelen,Deaktiver BOOM dør lyseffekt,Wyłącz efekt oświetlenia drzwi BOOM,Desabilitar efeito de luz de porta do BOOM,,Dezactivează efectele de lumină BOOM pentru uși,Отключить световой эффект из BOOM на дверях,Онемогући светлосни ефекат из BOOM-а на вратима,Inaktivera BOOM-dörrljuseffekten,BOOM kapı ışığı efektini devre dışı bırak, +Find neighboring light like Doom,CMPTMNU_LIGHT,,,Find neighbouring light like Doom,Nacházet nejbližší světlo jako Doom,Find nabo lys som Doom,Finde benachbartes Licht wie in Doom,,Trovi najbaran lumon kiel Doom,Encontrar luces vecinas como en Doom,,Etsi vierustava valo niin kuin Doom,Trouver prochaine texture comme DOOM,Szomszédos fényforrás keresése mint Doom-ban,Trova le luci vicine come in DOOM,DOOM式の最寄りライト検知,고전적인 조명추적 사용,Vind naburig licht zoals Doom,Finn nærliggende lys som Doom,Znajdź sąsiadujące światło jak w Doomie,Encontrar luz vizinha como em Doom,,Caută o sursă de lumină apropriată ca în Doom,Искать соседний источник света как в Doom,Нађи суседно светло као у Doom-у,Hitta närliggande ljus som Doom,Doom gibi komşu ışık bulun, +Find shortest textures like Doom,CMPTMNU_SHORTTEX,,,,Nacházet nejkratší textury jako Doom,Find korteste teksturer som Doom,Finde kurze Texturen wie in Doom,,Trovi la plej mallongajn tekstaĵojn kiel Doom,Encontrar texturas más cortas como en Doom,,Etsi lyhyimmät pintakuvioinnit niin kuin Doom,Trouver plus petite texture comme Doom,Legkisebb textúrák keresése mint Doom-ban,Trova le texture più piccole come in DOOM,DOOM式の最短テクスチャー検知,고전적인 텍스처분류 사용,Vind de kortste texturen zoals Doom,Finn korteste teksturer som Doom,Znajdź najkrótsze tekstury jak w Doomie,Encontrar menores texturas como em Doom,,Caută cele mai scurte texturi ca în Doom,Искать кратчайшие текстуры как в Doom,Нађи најкраће текстуре као у Doom-у,Hitta kortaste texturer som Doom,Doom gibi en kısa dokuları bulun, +Use buggier stair building,CMPTMNU_STAIRS,,,,Použít méně stabilní stavění schodů,Brug buggier trappe bygning,Benutze fehlerhafte Treppenbaufunktion,,Uzi pli ciman ŝtupo-konstruadon,Usar construcción defectuosa de escaleras,,Käytä viallisempaa portaanrakennusfunktiota,Construction d'escalier plus buggée,Bugosabb lépcsőépítés használata,Usa la struttura a scalinate più buggata,バグだらけの階段生成を使用,구형 계단상승 효과 사용,Gebruik buggier trapgebouw,Bruk buggier trappebygging,Użyj wadliwej funkcji budowania schodów,Usar construção defeituosa de escadas,,Utilizare mod de ridicare al scărilor incorect,Использовать неисправленное построение лестниц,Користи непоправљено грађење степеница,Använda en mer buggig trappbyggnad,Daha az doğru merdiven binası kullanın, +Use Doom's floor motion behavior,CMPTMNU_FLOORMOVE,,,Use Doom's floor motion behaviour,Použít původní chování Doomu pro pohyb podlah,Brug Dooms gulv bevægelsesadfærd,Benutze Dooms Verhalten für bewegende Böden,,Uzi konduton de Doom por plankmovo-konduto,Usar comportamiento de mov. del suelo de Doom,,Lattialiike käyttäytyy kuin Doomissa,Mouvement des sols à la DOOM,Doom jellegű padló mozgás,Adotta il comportamento di DOOM per il movimento sul pavimento,DOOMでの床の動作挙動を使用,표면이나 천장이 서로 통과가 가능함,Gebruik Doom's vloer beweging vloer,Bruk Dooms gulvbevegelsesatferd,Użyj zachowanie ruchu podłogi Dooma,Usar comportamento de mov. do chão de Doom,,Utilizare comportament de mișcare al podelelor din Doom,Поведение движения по полу из Doom,Користи Doom-ово подно моционо понашање,Använd Dooms golvrörelsebeteende,Doom'un zemin hareketi davranışını kullanın, +Use Doom's point-on-line algorithm,CMPTMNU_POINTONLINE,,,,Použít původní algoritmus bod-na-čáře z Doomu,Brug Dooms point-on-line algoritme,Benutze Dooms Punkt-auf-Linie Algorithmus,,Uzi algoritmon de Doom por trovi punkton sur linio,Usar algoritmo de punto en línea de Doom,,Käytä Doomin piste viivalla -algoritmia,Algorithme point-sur-ligne de DOOM,Doom jellegű point-on-line algoritmus,Usa l'algoritmo del 'punto giacente sulla linea' di DOOM,DOOMでのポイントライン アルゴリズム を使用,구형 선상 지점 정의법 사용,Gebruik Doom's point-on-line-algoritme,Bruk Dooms punkt-på-nett-algoritme,Użyj algorytmu punktu na linii z Dooma,Usar algorítmo de ponto-em-linha de Doom,,Utilizare algoritm point-on-line din Doom,Использовать алгоритм «точка на линии» из Doom,Користи Doom-ов point-on-line алгоритам,Använda Dooms algoritm för punkt-till-linje-arbete,Doom'un point-on-line algoritmasını kullanın, +Level exit can be triggered more than once,CMPTMNU_MULTIEXIT,,,,Odchod z levelu může být spuštěn vícekrát,Level exit kan udløses mere end én gang,Ausgang kann mehr als einmal aktiviert werden,,Nivelelirejo povas esti ekagigita pli ol unufoje,La salida de nivel puede ser activada más de una vez,,Tasosta poistumisen voi laukaista useammin kuin kerran,Sortie niveau utilisable plusieures fois,Pálya kijárat többször is triggerelhető,L'uscita del livello può attivarsi più di una volta,Exitを複数回起動出来る,레벨 출구 트리거 한 번 이상 작동,Niveau-uitgang kan meer dan eens worden geactiveerd,Nivåutgang kan utløses mer enn én gang,Wyjście z poziomu może być uruchomione więcej niż raz,Saída de fase pode ser ativada mais de uma vez,Saída de nível pode ser ativada mais de uma vez,Ieșirea nivelului poate fi activată de mai multe ori,Выходы могут быть активированы более одного раза,Излаз нивоа може бити активиран више пута,Nivåutgång kan utlösas mer än en gång,Seviye çıkışı birden fazla kez tetiklenebilir, +Physics Behavior,CMPTMNU_PHYSICSBEHAVIOR,,,Physics Behaviour,Fyzika,Fysik-adfærd,Physik-Verhalten,,Fizikokonduto,Comportamiento de la física,,Fysiikan käyttäytyminen,Comportement Physique,Fizika viselkedés,Comportamento della fisica,物理の挙動,물리 관련 설정,Fysica gedrag,Fysikkoppførsel,Zachowanie Fizyki,Comportamento de Física,Comportamento das Físicas,Comportament fizică,Поведение физики,Физичко понашање,Fysikbeteende,Fiziksel Davranış, +Actors are infinitely tall,CMPTMNU_NOPASSOVER,,,,Objekty jsou nekonečně vysoké,Aktører er uendeligt høje,Akteure sind unendlich hoch,,Aktoroj estas senfine altaj,Los actores son infinitamente altos,,Oliot ovat äärettömän korkeita,Hauteur des acteurs infinie,Személyek végtelen magasak,Gli attori sono infinitamente alti,アクターの上下には入れない,무한으로 키가 큰 개체,Acteurs zijn oneindig lang,Skuespillere er uendelig høye,Aktorzy są nieskończenie wysocy,Atores são infinitamente altos,,Actorii au înălțime infinită,Объекты бесконечно высокие,Глумци су бесконачно велики,Aktörerna är oändligt höga.,Aktörler sonsuz uzunlukta, +Boom scrollers are additive,CMPTMNU_BOOMSCROLL,,,,Boom posuvníky jsou aditivní,Boom scrollers er additive,Boom-Scroller sind additiv,,Skrolantaj Teksturaj de Boom estas adicia,Los scrollers de Boom son aditivos,,Boom-vierittimet ovat additiivisia,Glisseurs BOOM additifs,Boom scroller-ek összeadódnak,Le barre di scorrimento BOOM sono additivi,BOOM型スクロール床を適用,붐 스크롤러 누적법 사용,Boom scrollers zijn additief,Boom scrollere er additive,Przewijane tekstury Boom są addytywne,Scrollers de Boom são aditivos,,Elementele derulante BOOM sunt aditive,Конвейеры из BOOM складываются с собой,Boom скролери су додаци,Boom scrollers är additiva,Bom kaydırıcıları katkı maddelidir, +Cannot travel straight NSEW,CMPTMNU_BADANGLES,,,,Nelze se pohybovat přímo na SJVZ,Kan ikke rejse lige NSØV,Bewegungsrichtungen direkt NSOW nicht möglich,,Ne eblas veturi rekte NSEW,Emular error de mal ángulo,,Liikkuminen puhtaasti pääilmansuuntiin mahdotonta,Direction pure NSEO impossible,Nem haladhat egyenes vonalban NSEW,Non si può viaggiare esattamente nelle direzioni cardinali,NSEW直進走法の不許可,전방위 방향으로 이동 불가,Kan niet rechtdoor reizen NZOW,Kan ikke reise rett NSØV,Pozwól na błąd złego kąta,Impossível se deslocar reto em direções cardeais,Impossível se deslocar em frente em direções cardeais,Interzice deplasarea liniară NSEW,Запрещено двигаться прямо на С/Ю/З/В,Немогуће путовати право на NSEW,Kan inte resa rakt NSÖV,Düz seyahat edemez KGDB, +Enable wall running,CMPTMNU_WALLRUN,,,,Povolit wall running (běhaní pomocí zdi),Aktiver vægløb,Ermögliche Wandrennen,,Ebligi kuradon sur muroj,Activar correr por muros,,Salli seinäjuoksu,Activer Wallrunning,Falon futás engedélyezése,Wall running abilitata,壁伝い走行を許可,벽면가속이동 허용,Wandloop mogelijk maken,Aktiver veggkjøring,Włącz szybkie bieganie wzdłuż ścian,Habilitar corrida por paredes,Permitir corrida pelas paredes,Permite fuga cu ajutorul pereților (Wallrun),Включить быстрый бег вдоль стен (wallrunning),Омогући пролажење кроз зида,Aktiverar väggkörning,Duvar çalışmasını etkinleştirin, +Raven scrollers use original speed,CMPTMNU_RAVENSCROLL,,,,Raven posuvníky používají původní rychlost,Raven scrollers bruger original hastighed,Raven-Scroller benutzen originale Geschwindigkeit,,Skrolantaj teksturoj de Raven uzas originalan rapidecon,Los scrollers de Raven usan la velocidad original,,Ravenin vierittimet liikkuvat alkuperäisnopeudella,Glisseurs Raven à leur vitesse originale,Raven scroller-ek eredeti sebességűek,Le barre di scorrimento Raven usano la velocità originale,Raven式スクロール床を原作準拠にする,구형 헤러틱/헥센 스크롤러 사용,Raven scrollers gebruiken originele snelheid,Raven scrollers bruker original hastighet,Przwijane tekstury podłogi Raven używają oryginalną prędkość,Scrollers da Raven usam velocidade original,,Elementele derulante Raven folosesc viteza originală,Конвейеры из Raven используют неизменённую скорость,Raven скролери користе оригиналну брзину,Raven-skrollers använder ursprunglig hastighet,Kuzgun kaydırıcılar orijinal hızı kullanır, +Self ref. sectors don't block shots,CMPTMNU_TRACE,,,,Sebe-odkazující sektory neblokují střely,Selvreflekterende sektorer blokerer ikke for skud,Selbstreferenzierende Sektoren blockieren keine Schüsse,,Sinreferencantaj sektoroj ne baras pafojn,Sectores autoreferidos no bloquean los disparos,,Itseensä viittaavat sektorit eivät estä laukauksia,Secteur autoréférencé ne bloque pas les tirs,Saját ref.sektorok nem blokkkolják a lövéseket,Settori autoreferenziati non bloccano i colpi,Self ref.Sectorsは射撃を阻害しない,자기 참조 섹터가 총탄을 막지 않음,Zelfreferentie sectoren blokkeren geen schoten,Selvrefererende sektorer blokkerer ikke skudd.,Sektory odnoszoce się do siebie nie blokują strzałów,Setores autorreferidos não bloqueiam tiros,,Sectoarele cu referință proprie blochează focurile,Самоссылающиеся секторы не блокируют выстрелы,Самореф. сектори не блокирају пуцњеве,Självbetjäningssektorer blockerar inte skott.,Kendi kendine hakemlik yapan sektörler atışları engellemez., +Use Doom code for hitscan checks,CMPTMNU_HITSCAN,,,,Použít původní Doom kód pro kontrolu hitscanů,Brug Doom-code til hitscan-kontrol,Benutze Original-Doom-Code für Hitscan-Checks,,Uzi kodon de Doom por batskanoj-kontrolado,Usar código de Doom para revisión de hitscan,,Käytä Doomin osumislaskentakoodia,Vérification Hitscan à la DOOM,Doom kód használata a hitscan ellenőrzéshez,Usa il codice DOOM per il controllo sugli hitscan,DOOM式の即着弾判定を使用,구형 총탄 판정법 사용,Gebruik Doom-code voor hitscancontroles,Bruk Doom-kode for treffkontroll,Użyj kod Dooma dla hitscanu,Usam código de Doom para verificação de hitscan,Usar código de Doom para verificação de hitscan,Utilizează cod din Doom pentru a verifica coliziunea focurilor,Использовать код из Doom для проверок зон мгновенного попадания (hitscan),Користи Doom код за хитскен проверу,Använd Doom-kod för hitscan-kontroller,Hitscan kontrolleri için Doom kodunu kullanın, +Use Doom heights for missile clipping,CMPTMNU_MISSILECLIP,,,,Použít původní výšky z Doomu pro kolizi raket,Brug Doom-højder til missilklipper,Benutze Doom-Größen für Kollisionen mit Projektilen,,Uzi altojn de Doom por misilo-tonadoj,Usar altura de Doom para desplazamiento de misiles,,Käytä Doomin korkeuksia lentokappaleiden törmäyksissä,Clipping des missiles à la DOOM,Doom féle magasság használata a rakáta találathoz,Usa le altezze di DOOM per il clipping del razzo,ミサイル通過にDOOM heightsを使用,구형 발사체 판정법 사용,Gebruik Doom hoogtes voor het knippen van raketten,Bruk Doom-høyder for missilklipping,Użyj wysokości Dooma dla przenikania pocisków,Usar alturas de Doom para colisão de projéteis,,Utilizează metoda de verificare a înălțimilor din Doom,Использовать высоту из Doom для столкновения ракет,Користи Doom висине за клиповање ракета,Använd Doom-höjder för missilklippning.,Füze kırpma için Doom yüksekliklerini kullanın, +Rendering Behavior,CMPTMNU_RENDERINGBEHAVIOR,,,Rendering Behaviour,Vykreslování,Rendering Adfærd,Renderverhalten,,Bildigado-Konduto,Comportamiento de renderizado,,Hahmonnuksen käyttäytyminen,Comportement d'affichage,Renderelés viselkedése,Comportamento della grafica,レンダリングの挙動,렌더링 관련 설정,Rendering gedrag,Gjengivelse av oppførsel,Zachowanie Renderowania,Comportamento de Renderização,,Comportament Video,Поведение обработки,Понашање рендовања,Beteende vid rendering,Rendering Davranışı, +Draw polyobjects like Hexen,CMPTMNU_POLYOBJ,,,,Vykreslovat polyobjekty jako Hexen,Tegn polyobjekter som Hexen,Zeichne Polyobjekte wie in Hexen,,Desegni plurangulo-objektojn kiel Hexen,Dibujar poliobjetos como en Hexen,,Piirrä polyobjektit niin kuin Hexen,Dessiner les Polyobjets comme Hexen,Hexen féle tárgy kirajzolás,Polioggetti disegnati come Hexen,Hexen式のPolyObjects描画,구형 폴리오브젝트 시스템 사용,Teken polyobjecten zoals Hexen,Tegn polyobjekter som Hexen,Rysuj poliobiekty jak w Hexenie,Desenhar poliobjetos como em Hexen,,Afișează poliobiectele precum în Hexen,Отрисовка полиобъектов как в Hexen,Цртај поли-објекте као Hexen,Rita polyobjekt som Hexen,Hexen gibi çoklu nesneler çizin, +Ignore Y offsets on masked midtextures,CMPTMNU_MASKEDMIDTEX,,,,Ignorovat Y posuny na průhledných mid-texturách,Ignorer Y offsets på maskerede midtextures,Ignoriere Y-Offsets bei transparenten Mitteltexturen,,Malatenti Y-deŝovaĵojn sur maskitaj midtekstaĵoj,Ignorar offsets de eje Y en texturas medias enmascaradas,,Älä huomioi Y-siirroksia peitetyissä keskipintakuvioinneissa,Offsets Y ignorés sur les textures centrales,Függőleges mozgatás ignorálása a maszkolt midtextúráknál,Ignora gli offset Y sulle midtexture mascherate,マスクされた中間テクスチャーのY軸ずれを無効,이면선분의 중앙 텍스쳐의 Y축값 무시,Negeer Y compensaties op gemaskerde middentexturen,Ignorer Y-forskyvninger på maskerte mellomteksturer,Ignoruj przesunięcia osi Y na zamaskowanych teksturach po środku,Ignorar offsets de Y em texturas centrais,,Ignoră offsetul Y de pe texturile 3D mascate,Игнорировать смещение по вертикали на средних текстурах с маской,Игнориши Y нагиб на маскиране средње текстуре,Ignorera Y-förskjutningar på maskerade midtexturer.,Maskelenmiş orta dokularda Y ofsetlerini yoksay, +Invert sprite sorting,CMPTMNU_SPRITESORT,,,,Obrátit řazení spritů,Inverter sprite-sortering,Umgekehrte Spritesortierung,,Inversigi ordigadon de mov-rastrumoj,Invertir ordenado de sprites,,Käännä spritelajittelu,Ordres des sprites inversé,Sprite rendzés megfordítása,Ordinamento sprite invertito,反転スプライトの並び替え,구형 스프라이트 겹침 판정 사용,Sprite sorteren omkeren,Inverter sprite-sortering,Odwróć sortowanie sprite'ów,Inverter ordem de sprites,,Inversare sortare sprite-uri,Обратить порядок сортировки спрайтов,Обрнуто сортирање спрајтова,Invertera sprite-sortering,Sprite sıralamasını ters çevir, +Sound Behavior,CMPTMNU_SOUNDBEHAVIOR,,,Sound Behaviour,Zvuk,Adfærd med lyd,Sound-Verhalten,,Sonkonduto,Comportamiento de sonido,,Äänen käyttäytyminen,Comportement Sonore,Hang viselkedés,Comportamento suono,音の挙動,효과음 관련 설정,Geluidsgedrag,Lydoppførsel,Zachowanie dźwięku,Comportamento de Áudio,,Comportament Sunet,Поведение звуков,Понашање звука,Ljudbeteende,Ses Davranışı, +Cripple sound for silent BFG trick,CMPTMNU_SOUNDSLOTS,,,,Zmrzačit zvukový systém pro trik tichého BFG,Lyd forkrøblet ved lydløst BFG-trick,Amputiere Soundsystem für geräuschloses BFG,,Kripligi sonon por lertaĵo de silenta BFG,Estropear sonido para truco de BFG silencioso,,Rampauta äänijärjestelmä hiljaista BFG-temppua varten,Massacrer le son pour BFG silencieux,Bénító hang a halk BFG trükknél,Blocca il suono per il trucco del BFG silenzioso,消音BFG技の為にサウンドを重複させない,소음 BFG 효과 허용,Kreupel geluid voor een stille BFG-truc,Krymp lyd for stille BFG-triks,Obetnij dźwięk dla triku cichego BFG,Bloquear som para o truque da BFG silenciosa,,Taie sunetul pentru trucul BFG silențios,Ограничить звуки ради трюка бесшумной BFG,Онемогући звук за тихи ВЈП трик,Förlamning av ljudet vid tyst BFG-trick,Sessiz BFG numarası için sesi kısın, +Don't let others hear your pickups,CMPTMNU_SILENTPICKUP,,,,Ostatní tě neslyší sbírat předměty,Lad ikke andre høre dine pickupper,Andere können deine Gegenstandsaufnahmen nicht hören,,Ne lasi aliulojn aŭdas viajn prenadojn,No dejar a otros oír tus recogidas,,"Älä anna muiden kuulla, kun poimit esineitä",Autres joueurs n'entendent pas les ramassages,Mások ne hallhassák a tárgy felvételeidet,Non consentire agli altri giocatori di sentire le tue raccolte,他人にピックアップ音を聞かせない,상대방의 습득 효과음 청음 불가,Laat anderen uw pick-ups niet horen,Ikke la andre høre pickupene dine,"Nie pozwalaj by inni słyszeli, że podnosisz przedmioty",Não permitir que outros ouçam sua coleta de itens,Não permitir que outros ouçam sua aquisição de itens,Nu permite celorlalți să audă sunetul ridicării obiectelor,Запрещать другим слышать звук подбора предметов,Не допусти да други чују ваше скупљање,Låt inte andra höra dina pickuper,Başkalarının manyetiklerinizi duymasına izin vermeyin, +Inst. moving floors are not silent,CMPTMNU_SILENTINSTANTFLOORS,,,,Okamžitě pohybující se podlahy nejsou tiché,Inst. bevægelige gulve er ikke lydløse,Böden mit sofortiger Bewegung machen Geräusche,,Tujaj movantaj plankoj ne estas silentaj,Suelos inst. movibles no son silenciosos,,Silmänräpäyksellisesti liikkuvat lattiat eivät ole hiljaisia,Sols à movement instanté font du bruit,Halk isntant mozgó padló,I pavimenti istantanei in movimento non sono silenziosi,即時稼働するFloorsの音を鳴らさない,즉발식 이동표면 소음효과 제거,Direct bewegende vloeren zijn niet geruisloos,Øyeblikkelig bevegelige gulv er ikke stille,Nagle przesuwające się podłogi nie są ciche,Pisos que se deslocam instantâneamente emitem som,,Podelele care se mișcă instant nu sunt silențioase,Мгновенно двигающиеся полы не беззвучны,Инстантно покрећући нивои нису тихи,Inst. rörliga golv är inte tysta,Inst. hareketli zeminler sessiz değildir, +Sector sounds use center as source,CMPTMNU_SECTORSOUNDS,,,Sector sounds use centre as source,Sektorové zvuky používají jeho střed jako zdroj,Sektorlyde bruger centrum som kilde,Sektor-Sounds benutzen den Mittelpunkt des Sektors,,Sektorsonoj uzas centron kiel fonto,Sonidos de sector usan el centro como fuente,,Sektoriäänet käyttävät keskipistettä lähteenä,Sons secteur utilisent centre comme origine,Center forrás használata a szektor hangoknál,I suoni usano il centro dei settori come punto di sorgente,Sectorサウンドをフロア中央で鳴らす,섹터 중심부를 효과음의 원천으로 판정,Sectorgeluiden gebruiken centrum als bron,Sektorlyder bruker senter som kilde,Dźwięki sektorów używają środka jako źródła,Sons de setor são emitidos a partir do centro,,Sunetele sectoarelor au ca sursă centrul,Звуки секторов используют центр как источник,Секторски звукови су центрисани,Sektorljud använder centrum som källa,Sektör sesleri kaynak olarak merkezi kullanır, +Sounds stop when actor vanishes,CMPTMNU_SOUNDCUTOFF,,,,"Utnout zvuky, když jejich objekt zmizí","Lydene stopper, når aktøren forsvinder","Sounds werden beendet, wenn der Akteur verschwindet",,"Sonoj ĉesas, kiam aktoro malaperas",El sonido se detiene cuando el actor desaparece,,"Äänet lakkaavat, kun olio katoaa",Sons s'arrêtent quand acteur disparait,Hangok megszűnnek az eltűnéskor,I suoni si fermano quando gli attori svaniscono,アクター消滅で音を止める,효과음 원천 소멸 시 효과음도 중단,Geluiden stoppen wanneer de acteur verdwijnt,Lyder stopper når skuespilleren forsvinner,Dźwięki zatrzymują się kiedy aktor znika,Som para quando o ator desaparece,,Sunetele se opresc când actorul sursă dispare,Останавливать звуки при исчезновении объекта,Звукови престају кад глумац нестане,Ljudet upphör när aktören försvinner,Aktör ortadan kaybolduğunda sesler kesilir, +Use original sound target handling,CMPTMNU_SOUNDTARGET,,,,Použít původní chování pro uchování zvukového cíle,Brug original lydmålhåndtering,Benutze originale Behandlung für das Sound-Ziel,,Uzi originalan manipuladon por soncelo,Usar manejo de destino de sonido original,,Käytä alkuperäistä äänen kohteen käsittelyä,Ciblage des sons selon algorithme original,Eredeti hang célpont kezelés,Targeting dei suoni in base all'algoritmo originale,元のサウンドターゲット処理を使用,구형 섹터 경고음 보존법 사용,Gebruik originele geluidsdoelwitverwerking,Bruk original lydmålhåndtering,Użyj oryginalną obsługę celu dźwięku,Usar método original de destino de som,,Procesare originală pentru sursele de sunet,Неизменённая обработка источников звука,Користи оригинални звук руковања метом,Använd original ljudmålshantering,Orijinal ses hedefi kullanımını kullanın, +Scripted teleports don't trigger sector actions,CMPTMNU_TELEPORT,,,,Skriptované teleportace neaktivují sektorové akce,Scriptede teleporteringer udløser ikke sektorhandlinger,Teleports in Skripten lösen keine Sektoraktionen aus,,Skriptitaj teleportoj ne ekagigas sektor-agojn,Telepuertos por script no activan acciones del sector,,Käsikirjoitetut kaukosiirtimet eivät laukaise sektoritoimintoja,Téléports par scripts n'activent pas le secteur,Szkriptelt teleportok nem triggerelnek szektor műveletet,I teletrasporti scriptati non attivano le azioni del settore,スクリプトテレポートではSector actionsを起こさない,순간이동 스크립트는 섹터 이벤트 발동 불가능,De gescripte teleports leiden niet tot acties in de sector.,Skriptede teleporter utløser ikke sektorhandlinger,Oskryptowane teleporty nie włączają akcji sektora,Teletransportes scriptados não ativam ações de setor,,Teleportările scriptate nu declanșează acțiuni în sectoare,Скриптовые телепорты не запускают действия секторов,Скриптовани телепортери не активирају секторске радње,Skriptbaserade teleporter utlöser inte sektoråtgärder.,Komut dosyası ışınlanmaları sektör eylemlerini tetiklemiyor, +Non-blocking lines can be pushed,CMPTMNU_PUSHWINDOW,,,,Neblokující čáry mohou být zmáčknuty,Ikke-blokerende linjer kan skubbes,Nicht-blockende Linien können angestoßen werden,,Nehaltantaj linioj povas esti premitaj,Líneas sin bloquear pueden ser presionadas,,Ei-tukkivia viivoja voi työntää,Lignes non-bloquantes sont non-poussables,Nem blokkoló vonalak megnyomhatóak,Le linee non bloccanti possono essere spinti,Non-bloking linesを押せる,비차단 선분 밀어내기 가능,Niet-blokkerende lijnen kunnen worden geduwd,Ikke-blokkerende linjer kan skyves,Nieblokujące ściany mogą być pchnięte,Linhas não-bloqueadoras podem ser pressionadas,,Liniile care nu blochează pot fi împinse înapoi,Неблокирующие линии можно задействовать перемещением сквозь,Неблокирабе линје могу бити гурнуте,Linjer som inte blockerar kan skjutas,Engelleyici olmayan hatlar itilebilir, +Enable buggy CheckSwitchRange behavior,CMPTMNU_CHECKSWITCHRANGE,,,,Povolit nestabilní chování pro CheckSwitchRange,Aktiver den fejlbehæftede CheckSwitchRange-adfærd,Erlaube fehlerhaftes CheckSwitchRange Verhalten,,Ebligi cimajn kondutojn por CheckSwitchRange,Permitir comportamiento viejo de CheckSwitchRange,,Ota käyttöön viallinen CheckSwitchRange-käyttäytyminen,Fonction CheckSwitchRange buggée,Bugos CheckSwitchRange mechanika bekapcsolás,Abilita il comportamento buggato del CheckSwitchRange,バグのあるCheckSwitchRangeを許可,구형 CheckSwitchRange 판정법 사용,Buggy CheckSwitchSwitchRange gedrag inschakelen,Aktiver fejlbehæftet CheckSwitchRange-adfærd,Zezwól na zepsute zachowanie CheckSwitchRange,Permitir comportamento CheckSwitchRange defeituoso,,Comportament incorect pentru CheckSwitchRange,Включить ошибочное поведение CheckSwitchRange,Омогући баговано CheckSwitchRange понашање,Aktivera det felsägande CheckSwitchRange-beteendet,Hatalı CheckSwitchRange davranışını etkinleştirin, +Enable buggy Strife railing,CMPTMNU_RAILINGHACK,,,,Povolit nestabilní zábradlí ze Strifu,Aktiver buggy Strife railing,Fehlerhafte Strife-Geländer,Ενεργοποιηση σπασμένης συμπεριφοράς καγκέλον για το Strife,Ebligi ciman reladon de Strife,Activar barandillas bugueadas de Strife,,Ota käyttöön Strifen vialliset kaiteet,Barrières buggées pour Strife,Bugos Strife korlát bekapcsolása,Abilita il railing buggato di Strife,バグのあるStrife railingを許可,고전 스트라이프 철책 적용,Buggy mogelijk maken Strijk-reling,Aktiver fejlbehæftet Strife rekkverk,Włącz wadliwe bariery Strife'a,Permitir railing defeituoso do Strife,Permitir railing defeituoso do Strife,Utilizare comportament grilaj Strife incorect,Вернуть ошибочные перила в Strife,Омогући непоправљену ограду у Strife-у,Aktivera felande Strife-Räcken,Yanlış Strife korkuluğunu etkinleştirin, +No vertical thrust from explosions,CMPTMNU_EXPLODE1,,,,Exploze neodhazují do výšky,Ingen vertikal fremdrift fra eksplosioner,Keine vertikale Bewegung durch Explosionen,Καθόλου κατακόρυφη ώθηση απο εκρήξεις,Neniuj vertikalaj puŝoj de eksplodoj,No causar empuje vertical en explosiones,,Ei pystysuuntaista työntövoimaa räjähdyksistä,Explosions sans propulsion verticale,A robbanásnak nincs függőleges lökése,Nessuna spinta verticale dalle esplosioni,爆風は垂直方向全域に影響しない,폭발시 수직방향 반동 억제,Geen verticale stuwkracht van explosies,Ingen vertikal skyvekraft fra eksplosjoner,Brak pionowego nacisku od eksplozji,Desativar propulsão vertical das explosões,,Fără împingere verticală de la explozii,Взрывы не отбрасывают вверх/вниз,Нема вертикалног гурања од експлозија,Ingen vertikal dragkraft från explosioner,Patlamalardan kaynaklanan dikey itme yok, +Use original Doom explosion behavior,CMPTMNU_EXPLODE2,,,Use original Doom explosion behaviour,Používat původní chování explozí Doomu,Brug original Doom eksplosionsadfærd,Benutze Original Doom Explosionsverhalten,Συμπεριφορά εκρήξεων απο το πρωτότυπο Doom,Uzi originalan konduton de Doom por eksplodoj ,Usar comportamiento de explosiones del DOOM original,,Käytä Doomin alkuperäisiä räjähdysten käyttäytymissääntöjä,Utiliser comportement Doom original,Eredeti Doom robbanás mechanika használata,Usa l'originale comportamento dell'esplosione di DOOM,Doom本来の爆発動作を使用する,고전 둠의 폭발 반발력 적용,Gebruik het originele Doom explosiegedrag,Bruk original Doom-eksplosjonsatferd,Użyj oryginalnego zachowania eksplozji z Dooma,Usar comportamento original de explosões do Doom,,Utilizare comportament original pentru explozii,Использовать модель взрывов из Doom,Користи оригнално Doom понашање за експлозије,Använd det ursprungliga Doom-explosionsbeteendet,Orijinal Doom patlama davranışını kullanın, +,,player,,,,,,,,,,,,,,,,,,,,,,,,,, +Red,PLYRMNU_RED,,,,Červená,Rød,Rot,,Ruĝo,Rojo,,Punainen,Rouge,Piros,Rosso,赤の量,빨강,Rood,Rød,Czerwony,Vermelho,,Roșu,Красный,Црвева,Röd,Kırmızı, +Green,PLYRMNU_GREEN,,,,Zelená,Grøn,Grün,,Verdo,Verde,,Vihreä,Vert,Zöld,Verde,緑の量,초록,Groen,Grønn,Zielony,Verde,,Verde,Зелёный,Зелена,Grön,Yeşil, +Blue,PLYRMNU_BLUE,,,,Modrá,Blå,Blau,,Bluo,Azul,,Sininen,Bleu,Kék,Blu,青の量,파랑,Blauw,Blå,Niebieski,Azul,,Albastru,Синий,Плава,Blå,Mavi, +Class,PLYRMNU_PLAYERCLASS,,,,Třída,Klasse,Klasse,,Klaso,Clase,,Luokka,Classe,Kaszt,Classe,役職,클래스,Klasse,Klasse,Klasa,Classe,,Clasă,Класс,Класа,Klass,Sınıf, +Skin,PLYRMNU_PLAYERSKIN,,,,,,,,Aspekto,Aspecto,,Ulkoasu,,Kinézet,,外装,스킨,Uiterlijk,Hud,Wygląd,Aparência,,Textură,Облик,Скин,Hud,Cilt, +Switch on pickup,PLYRMNU_SWITCHONPICKUP,,,,Přepnout zbraň při sebrání,Tænd for pickup,Waffenwechsel bei Aufnahme,,Ŝanĝi armon ĉe preno,Elegir arma al coger una,Elegir arma al agarrar una,Vaihda uuteen aseeseen,Dernière arme,Felvételkor váltás,Cambio d'arma quando si riceve,武器取得時に持ち替え,무기 획득 시 바꿈,Gebruik wapen meteen na oppakken,Slå på pickup,Przełącz po podniesieniu,Mudar de arma ao pegar,,Schimbare armă la ridicare,Смена оружия при подборе,Пребаци на покупљено оружје,Slå på pickupen,Elinize aldığınızda silahı değiştirin, +Press \cjSPACE,PLYRMNU_PRESSSPACE,,,,Zmáčkni \cjMEZERNÍK,Tryk på \cjSPACE,\cjLeertaste,,Premu \cjSPACON,Presiona \cjEspacio,,Paina \cjVÄLI \cfnähdäk-,\cjEspace,Nyomj \cjSPACE -t,Premi \cjSPAZIO,\cjスペースキー,회전: \cjSPACE바,Druk op \cjSPACE,Trykk \cjSPACE,\cjSPACJA,Aperte \cjESPAÇO,,Apasă \cjSPACE,Нажмите \cjПРОБЕЛ,Притисните \cjSPACE,Tryck på \cjSPACE,\cjSPACE tuşuna basın, +to see front,PLYRMNU_SEEFRONT,,,,pro pohled zepředu,for at se forsiden,für Frontansicht,,por vidi vian antaŭon,para verte de frente,,sesi etupuolen,Pour L'Avant,Előre nézni,per vedere avanti,で前面を表示,캐릭터 앞모습,om de voorkant te zien,for å se forsiden,by widzieć przód,para ver a frente,,pentru a vedea fața,для просмотра спереди,да видите спреда,för att se framsidan,ön tarafı görmek için, +to see back,PLYRMNU_SEEBACK,,,,pro pohled zezadu,for at se bagsiden,für Rückansicht,,por vidi vian malantaŭon,para verte por detrás,,sesi takapuolen,Pour l'Arrière,Hátra Nézni,per vedere dietro,で背面を表示,캐릭터 뒷모습,om terug te kijken,for å se baksiden,by widzieć tył,para ver atrás,,pentru a vedea spatele,для просмотра сзади,да видите позади,för att se baksidan,geri görmek için, +Vertical Bullet Spread,PLYRMNU_VERTSPREAD,,,,Svislý rozptyl střelby,Lodret kuglespredning,Vertikale Streuung,,Vertikala Kugla Disvastiĝo,Dispersión vertical de la bala,,Pystysuora luodin leviäminen,Écartement vertical des balles,Vertikális fegyver szórás,Diffusione dei proiettili in verticale,垂直方向の散弾,,Verticale kogelspreiding,Vertikal kulespredning,Pionowy rozrzut pocisków,Dispersão vertical das balas,,Recul Vertical Gloanțe,Вертикальный разброс пуль,,Vertikal kulspridning,Dikey Mermi Yayılımı, +,,controls,,,,,,,,,,,,,,,,,,,,,,,,,, +Weapon Zoom,CNTRLMNU_ZOOM,,,,Přiblížení zbraně,Våbenzoom,Waffenzoom,Ζοομ,Armilzumo,Zoom del arma,,Aseen kiikaritähtäys,Zoom avec Arme,Ráközelítés fegyverrel,Zoom dell'arma,ズーム,무기 조준,Wapen Zoom,Våpen Zoom,Przybliżenie Broni,Zoom da Arma,,Zoom Armă,Приближение,Зум,Vapenzoom,Silah Yakınlaştırma, +Weapon State 1,CNTRLMNU_USER1,,,,Akce zbraně 1,Våbenstatus 1,Waffen-Aktion 1,Κατάσταση Όπλου 1,Armilstato 1,Estado del arma 1,,Aseen tila 1,Etat d'Arme 1,Fegyver 1. állapot,Stato dell'arma 1,武器特殊動作 1,무기 상태 1,Wapenstaat 1,Våpenstat 1,Stan Broni 1,Estado da Arma 1,,Poziție Armă 1,Функция первого оружия,Стање оружја (1),Vapen Åtgärd 1,Silah Durumu 1, +Weapon State 2,CNTRLMNU_USER2,,,,Akce zbraně 2,Våbenstatus 2,Waffen-Aktion 2,Κατάσταση Όπλου 2,Armilstato 2,Estado del arma 2,,Aseen tila 2,Etat d'Arme 2,Fegyver 2. állapot,Stato dell'arma 2,武器特殊動作 2,무기 상태 2,Wapenstaat 2,Våpenstat 2,Stan Broni 2,Estado da Arma 2,,Poziție Armă 2,Функция второго оружия,Стање оружја (2),Vapen Åtgärd 2,Silah Durumu 2, +Weapon State 3,CNTRLMNU_USER3,,,,Akce zbraně 3,Våbenstatus 3,Waffen-Aktion 3,Κατάσταση Όπλου 3,Armilstato 3,Estado del arma 3,,Aseen tila 3,Etat d'Arme 3,Fegyver 3. állapot,Stato dell'arma 3,武器特殊動作 3,무기 상태 3,Wapenstaat 3,Våpenstat 3,Stan Broni 3,Estado da Arma 3,,Poziție Armă 3,Функция третьего оружия,Стање оружја (3),Vapen Åtgärd 3,Silah Durumu 3, +Weapon State 4,CNTRLMNU_USER4,,,,Akce zbraně 4,Våbenstatus 4,Waffen-Aktion 4,Κατάσταση Όπλου 4,Armilstato 4,Estado del arma 4,,Aseen tila 4,Etat d'Arme 4,Fegyver 4. állapot,Stato dell'arma 4,武器特殊動作 4,무기 상태 4,Wapenstaat 4,Våpentilstand 4,Stan Broni 4,Estado da Arma 4,,Poziție Armă 4,Функция четвёртого оружия,Стање оружја (4),Vapen Åtgärd 4,Silah Durumu 4, +Fly / Swim up,CNTRLMNU_MOVEUP,,,,Letět / plavat vzhůru,Flyv / svøm op,Fliegen / Hochschwimmen,Πέτα/Κολύμπα πάνω,Flugi/Naĝi supren,Volar/Nadar arriba,,Lennä / Ui ylös,Voler/Nager en haut,Repülés / Felfele úszás,Vola / Nuota in alto,飛行/水泳時 上昇,위로 날기 / 해엄치기,Omhoog vliegen/zwemmen omhoog,Fly / Svøm opp,Lot / Pływanie w górę,Voar / Nadar para cima,,Zbor / Înot în Sus,Лететь/плыть вверх,Лети/пливај нагоре,Flyga/simma upp,Uç / Yüz yukarı, +Fly / Swim down,CNTRLMNU_MOVEDOWN,,,,Letět / plavat dolů,Flyv / svøm ned,Fliegen / Runterschwimmen,Πέτα/Κολύμπα κάτω,Flugi/Naĝi malsupren,Volar/Nadar abajo,,Lennä / Ui alas,Voler/Nager en bas,Repülés / Lefele úszás,Vola / Nuota in basso,飛行/水泳時 下降,아래로 날기 / 해엄치기,Naar beneden vliegen/zwemmen,Fly / Svøm ned,Lot / Pływanie w dół,Voar / Nadar para baixo,,Zbor / Înot în Jos,Лететь/плыть вниз,Лети/пливај надоле,Flyga/simma ner,Uç / Yüz aşağı, +Stop flying,CNTRLMNU_LAND,,,,Přestat létat,Stop flyvning,Landen,Σταμάτα πέταμα,Ĉesi flugadon,Dejar de volar,,Lopeta lentäminen,Arrêter de voler,Repülés abbahagyása,Stop al volo,飛行停止,비행 정지,Stoppen met vliegen,Slutt å fly,Przestań latać,Parar de voar,,Încetare Zbor,Приземлиться,Престани летети,Sluta flyga,Uçmayı bırak, +Keyboard look,CNTRLMNU_KEYBOARDLOOK,,,,Pohled klávesnicí,Tastatur-look,Tastatur-Blick,Κατακόρυφο κοίταχμα (Πλητρoλόγιο),Klavar-rigardo,Vista con teclado,,Näppäinkatselu,Vue au clavier,Billentyűzettel való nézelődés,Modalità vista con la tastiera,キー視点上下化,키보드 룩,Toetsenbordaanzicht,Tastatur utseende,Rozglądanie się klawiaturą,Vista com o teclado,,Utilizare Tastatură pentru a Privi în Jur,Обзор клавиатурой,Гледај тастатуром,Tangentbordsutseende,Klavye görünümü, +Strife Popup Screens Controls,CNTRLMNU_POPUPS_TITLE,,,,Ovládání vyskakovacích oken ve Strife,Strife Popup-skærme Kontrolelementer,Strife Popup Steuerung einstellen,,Ŝprucfenestraĵoj de Strife,Ventanas emergentes de Strife,,Strifen ponnahdusruutujen ohjausasetukset,Contrôles Popups Strife,Strife Felugró Ablak Irányítás,Controlli Schermate popup di Strife,Strifeポップアップ表示設定,스트라이프 팝업 화면 조작,Strife Popup Schermen Bediening,Strife Popup-skjermer Kontroller,Ustaw Klawisze Okienek Strife'a,Comandos de Popups do Strife,Controlos de Popups do Strife,Control pentru Mesaje Strife,Управление всплывающими окнами Strife,Искакајући прикази контроле у Strife-у,Strife Popup-skärmar Kontroller,Strife Açılır Ekran Kontrolleri, +Team say,CNTRLMNU_TEAMSAY,,,,Říct týmu,Team sige,Teamkommunikation,Πές στην ομάδα,Teama diro,Hablar al equipo,,Sano omille,Parler (équipe),Üzenet csapattársaknak,Parla nella squadra,チーム内発言,팀 채팅하기,Zeggen in team,Lag si,Powiedz do Drużyny,Fala (equipe),Falar à equipa,Vorbește cu Echipa Proprie,Сообщение команде,Пиши тиму,Laget säger,Ekip diyor ki, +Drop item,CNTRLMNU_DROPITEM,,,,Odhodit předmět,Smid genstand,Gegenstand fallen lassen,Πέτα Aντικείμενο,Faligi objekton,Soltar objeto,,Pudota varuste,Lâcher objet,Tárgy eldobása,Fai cadere l'oggetto,"アイテムを捨てる +",아이템 버리기,Item laten vallen,Slipp element,Upuść przedmiot,Largar item,,Aruncare Obiect,Бросить предмет,Баци предмет,Släpp föremål,Eşyayı bırak, +Query item,CNTRLMNU_QUERYITEM,,,,Informace o předmětu,Forespørgsel element,Informationen über Gegenstand,,Informpeti objekton,Consultar objeto,,Hae varustetta,Vérifier objet,Rákérdez a tárgy eldobásnál,Indaga sull'oggetto,アイテム名を表示,아이템 정보 표시,Vraag item op,Spør om element,Zapytaj o przedmiot,Consultar item,,Cercetare Obiect,Проверить предмет,Прикажи предмет,Fråga efter objekt,Sorgu öğesi, +Drop weapon,CNTRLMNU_DROPWEAPON,,,,Odhodit zbraň,Smid våben,Waffe fallen lassen,Πέτα Όπλο,Faligi armilon,Soltar arma,,Pudota ase,Lâcher arme,Fegyver eldobása,Butta l'arma,武器を捨てる,무기 버리기,Wapen laten vallen,Slipp våpen,Upuść broń,Largar arma,,Aruncare Armă,Выбросить оружие,Баци оружје,Släpp vapen,Silahı bırak, +Other,CNTRLMNU_OTHER,,,,Ostatní,Andre,Andere,Άλλα,Alia,Otros,,Muu,Autres,Más,Altro,その他,그 외 조작,Andere,Annet,Inne,Outro,,Altele,Прочее,Остало,Annat,Diğer, +Coop spy,CNTRLMNU_COOPSPY,,,,Co-op špehování,Coop-spion,Coop Spion,,Kunlabora spiono,Espía cooperativo,,Vakoile joukkuetovereita,Espionner Coéquiper,Coop leskelődés,Spia cooperativa,他者視点,멀티플레이 카메라,Coöpspion,Coop-spion,Śledź (kooperacja),Visualização coop,,Vedere prin Ochii Altui Jucător,Вид от другого игрока,Поглед од другог играча,Spion för samarbete,Coop casusu, +Strife Popup Screens,CNTRLMNU_POPUPS,,,,Vyskakovací okna Strife,Strife popup-skærme,Strife Popups,,Ŝprucfenestraĵoj de Strife,Ventanas emergentes de Strife,,Strifen ponnahdusruudut,Popups de Strife,Strife Felugró Ablakok,Schermate popup di Strife,Strife ポップアップ画面,스트라이프 팝업 화면,Strife Popup Schermen,Strife Popup-skjermer,Okienka Strife'a,Popup do Strife,,Mesaje Strife,Всплывающие окна Strife,Информација у Strife-у,Strife Popup-skärmar,Strife Açılır Ekranları, +Mission objectives,CNTRLMNU_MISSION,,,,Úkoly mise,Mål for en mission,Missionsziele,Στόχοι Αποστολής,Taskoceloj,Objetivos de misión,,Tehtävätavoitteet,Objectifs de Mission,Küldetési célok,Obiettivi della missione,ミッションオブジェクト,임무 목록,Missiedoelen,Oppdragets mål,Cele misji,Objetivos da missão,,Obiectivele Misiunii,Текущее задание,Циљ мисије,Mål för uppdraget,Görev hedefleri, +Keys list,CNTRLMNU_KEYS,,,,Seznam klíčů,Liste over nøgler,Schlüsselliste,Λίστα Κλειδιών,Ŝlosilolisto,Lista de llaves,,Avainlista,Liste des Clés,Kulcslista,Lista delle chiavi,キー類リスト,열쇠 목록,Lijst van toetsen,Liste over nøkler,Lista kluczy,Lista de teclas,,Listă Chei,Список ключей,Списка кључева,Lista över nycklar,Anahtar listesi, +Weapons/ammo/stats,CNTRLMNU_STATS,,,,Zbraně/munice/staty,Våben/ammo/stats,Waffen/Munition/Statistik,Οπλα/Πυρομαχικά/Στατιστικές,Armiloj/municio/stataĵoj,Armas/Munición/Estadísticas,,Aseet/ammukset/tila,"Statistiques, armes et munitions",Fegyver/lőszer/statisztika,Armi/ammunizioni/statistiche,武器 / 弾薬 / 状態,무기/탄약/통계 목록,Wapens/ammo/statistieken,Våpen/ammunisjon/statistikk,Bronie/amunicja/statystyki,Armas/munição/estatísticas,,Arme/muniție/statistici,"Оружие, патроны и показатели",Оружје/муниција/статистика,Vapen/ammo/statistik,Silahlar/mühimmat/istatistikler, +Toggle Scoreboard,CNTRLMNU_TOGGLESCOREBOARD,,,,Přepnout tabulku skóre,Skift Scoreboard,Punktetafel an/aus,Ενεργοποίηση Πίνακα Σκόρ,Baskuligi poentotabulon,Alternar Marcador,,Pistetaulun vaihtokytkin,Afficher Scores (alterner),Eredményjelző kapcsoló,Abilita/disabilita tabella punteggio,スコアボード切替,점수창 토글,Scorebord aan/uit,Veksle resultattavle,Włącz / Wyłącz tablicę wyników,Ativar/desativar placar,Ligar/desligar Pontuação no Ecrã,Comutator pentru Tabela de Marcaj,Таблица очков (перекл.),Табела (без држања),Växla resultattavla,Skor Tablosunu Değiştir, +Lookspring,MOUSEMNU_LOOKSPRING,,,,Automatické vystředění pohledu,Centret automatisk,Automatisch zentrieren,,Rigardsalto,Mirar con ratón,,Katseenpalautin,Recentrer après Vue Souris,,,視点水平化,마우스룩 시점 초기화,Automatisch centraliseren,Sentrer automatisk,Automatyczne Wyśrodkowanie,Centralizar automaticamente,Centrar automáticamente,Mișcare a jucătorului prin mouse,Передвижение мышью,Покрет мишем,Centrum automatiskt,Merkez otomatik olarak, +Lookstrafe,MOUSEMNU_LOOKSTRAFE,,,,Použít myš k pohybu do stran,Flyt sidelæns med musen,Seitwärts bewegen mit der Maus,,Rigardturnmovo,Mirar con movimiento,,Sivuttaisastuntapalautin,Mouvement Latéral par Souris,,,視点横移動化,마우스룩 좌우 이동,Zijwaartse muisbeweging,Flytt sidelengs med musen,Unikanie przy użyciu myszki,Deslocamento lateral com o mouse,Deslocamento lateral com o rato,Mișcare în diagonală cu mouse,Движение боком мышью,Стрејф мишем,Flytta i sidled med musen,Fare ile yana doğru hareket ettirin, +,,Map colors,,,,,,,,,,,,,,,,,,,,,,,,,, +Background,MAPCOLORMNU_BACKCOLOR,,,,Pozadí,Baggrund,Hintergrund,,Fono,Fondo,,Tausta,Fond,Háttér,Sfondo,背景,배경,Achtergrond,Bakgrunn,Tło,Fundo,,Fundal,Фон,Позадина,Bakgrund,Arka plan, +You,MAPCOLORMNU_YOURCOLOR,,,,Ty,Du,Du,,Vi,Tú,,Sinä,Votre couleur,Te,Tu,自分,당신,,Du,Ty,Você,Tu,Tu,Вы,Ти,Du,Sen, +1-sided walls,MAPCOLORMNU_WALLCOLOR,,,,Jednostranné zdi,1-sidede vægge,Einseitige Wände,,1-flankaj muroj,Paredes de 1 lado,,Yksipuoliset seinät,Murs à 1 côté,1 oldalú falak,Muri unilaterali,壁,단면 벽들,1-zijdige wanden,1-sidige vegger,Jednostronne ściany,Paredes de 1 lado,,Pereți cu o singură față,Односторонние стены,Једнострани зид,1-sidiga väggar,1 taraflı duvarlar, +2-sided walls with different floors,MAPCOLORMNU_FDWALLCOLOR,,,,Oboustranné zdi s různými podlahami,2-sidede vægge med forskellige gulve,Zweiseitige Wände mit unterschiedlicher Bodenhöhe,,2-flankaj muroj kun malsamaj plankoj,Paredes de 2 lados con pisos distintos,,Kaksipuoliset seinät eroavilla lattiakorkeuksilla,Murs à 2 côtés avec différents sols,2 oldalú falak különböző padlókkal,Muri bilaterali con pavimenti diversi,高低差のある床,다른 층 추가된 양면 벽들,2-zijdige wanden met verschillende vloeren,2-sidige vegger med forskjellige gulv,Dwustronne ściany z innymi piętrami,Paredes de 2 lados com pisos diferentes,,Pereți cu două fețe si podele diferite,Двусторонние стены,Двострани зид са различитим нивоима,2-sidiga väggar med olika golv,Farklı zeminlere sahip 2 taraflı duvarlar, +2-sided walls with different ceilings,MAPCOLORMNU_CDWALLCOLOR,,,,Oboustranné zdi s různými stropy,2-sidede vægge med forskellige lofter,Zweiseitige Wände mit unterschiedlicher Deckenhöhe,,2-flankaj muroj kun malsamaj plafonoj,Paredes de 2 lados con techos distintos,,Kaksipuoliset seinät eroavilla kattokorkeuksilla,Murs à 2 côtés avec différents plafonds,2 oldalú falak különböző plafonnal,Muri bilaterali con soffitti diversi,高低差のある天井,다른 천장 추가된 양면 벽들,2-zijdige wanden met verschillende plafonds,2-sidige vegger med forskjellige tak,Dwustronne ściany z innymi sufitami,Paredes de 2 lados com tetos diferentes,,Pereți cu două fețe si tavane diferite,Двусторонние стены с разными потолками,Двострани зид са различитим плафонима,2-sidiga väggar med olika tak,Farklı tavanlara sahip 2 taraflı duvarlar, +2-sided walls with 3D floors,MAPCOLORMNU_EFWALLCOLOR,,,,Oboustranné zdi s 3D podlahami,2-sidede vægge med 3D-gulve,Zweiseitige Wände mit 3D-Ebenen,,2-flankaj muroj kun 3D-plankoj,Paredes de 2 lados con suelos 3D,,Kaksipuoliset seinät kolmiulotteisilla lattioilla,Murs à 2 côtés avec sols 3d,2 oldalú falak 3D-s padlókkal,Muri bilaterali con 3D floor,多重床,3D 층 추가된 양면 벽들,2-zijdige wanden met 3D-vloeren,2-sidige vegger med 3D-gulv,Dwustronne ściany z piętrami 3D,Paredes de 2 lados com pisos 3D,,Pereți cu două fețe si podele 3D,Двусторонние стены с разными полами,Двострани зид са 3D нивоима,2-sidiga väggar med 3D-golv,3D zeminli 2 taraflı duvarlar, +Map grid,MAPCOLORMNU_GRIDCOLOR,,,,Mřížka,Kortgitter,Kartengitter,,Mapkrado,Cuadrícula del mapa,,Kartan ruudukko,Quadrillage,Pálya szél,Griglia mappa,マップグリッド,맵 격자,Kaart raster,Kartrutenett,Siatka mapy,Grade do mapa,Grelha do mapa,Grilă hartă,Цвет сетки,Мапа координатне мреже,Kartnät,Harita ızgarası, +Center point,MAPCOLORMNU_XHAIRCOLOR,,,Centre point,Středobod,Midterpunkt,Mittelpunkt,,Centra punkto,Punto central,,Keskipiste,Point Central,Pálya közepe,Punto centrale,中心点,중간 지점,Middenpunt,Midtpunkt,Środek,Ponto central,,Punct în centru,Курсор,Централна тачка,Centrumpunkt,Merkez noktası, +Not-yet-seen walls,MAPCOLORMNU_NOTSEENCOLOR,,,,Neobjevené zdi,"Vægge, der endnu ikke er synlige",Ungesehene Wände,,Vidotaj muroj,Paredes sin ver,,Tutkimattomat seinät,Murs non découvers,Még nem látott falak,Muri ancora da scoprire,未見の壁,안 본 벽들,Nog niet zichtbare wanden,Vegger som ennå ikke er sett,Jeszcze niewidziane ściany,Paredes não vistas até o momento,,Ziduri încă neobservate,Необнаруженные стены,Неоткривени зидови,Väggar som ännu inte har setts,Henüz görülmemiş duvarlar, +Locked doors,MAPCOLORMNU_LOCKEDCOLOR,,,,Zamčené dveře,Låste døre,Verschlossene Türen,,Ŝlositaj pordoj,Puertas bloqueadas,,Lukitut ovet,Portes verouillées,Zárt ajtók,Porte bloccate,鍵の掛かったドア,잠긴 문들,Gesloten deuren,Låste dører,Zablokowane drzwi,Portas trancadas,,Uși închise,Запертые двери,Закључана врата,Låsta dörrar,Kilitli kapılar, +Teleporter to the same map,MAPCOLORMNU_INTRALEVELCOLOR,,,,Teleportér,Teleporter til samme kort,Teleporter,,Teleportilo al la sama mapo,Teletransporte al mismo mapa,,Kaukosiirrin samaan tasoon,Téléporteurs (même niveau),Ugyanarra a pályára teleportálás,Teletrasporto nella stessa mappa,テレポーター,같은 맵에 텔레포터 추가,Teleporter naar dezelfde niveau,Teleporter til samme kart,Teleporter do tej samej mapy,Teletransportador para o mesmo mapa,,Teleportor către aceeași hartă,Телепорт в пределах уровня,Телепортер до истог нивоа,Teleporter till samma karta,Aynı haritaya ışınlayıcı, +Teleporter to a different map,MAPCOLORMNU_INTERLEVELCOLOR,,,,Teleportér do jiného levelu,Teleporter til et andet kort,Teleporter in ein anderes Level,,Teleportilo al alia mapo,Teletransporte a un mapa diferente,,Kaukosiirrin eri tasoon,Téléporteurs (autre niveau),Másik pályára teleportálás,Teletrasporto in una mappa diversa,別マップへのテレポーター,다른 맵에 텔레포터 추가,Teleporter naar een andere niveau,Teleporter til et annet kart,Teleporter do innej mapy,Teletransportador para outro mapa,,Teleportor către altă hartă,Телепорт на другой уровень,Телепортер до различитог нивоа,Teleporter till en annan karta,Farklı bir haritaya ışınlayıcı, +Secret sector,MAPCOLORMNU_SECRETSECTORCOLOR,,,,Skrýš,Hemmelig sektor,Geheimer Sektor,,Sekreta sektoro,Sector secreto,,Salasektori,Secteur Secret,Rejtekhely szektora,Settore segreto,シークレット,비밀 섹터,Geheime sector,Hemmelig sektor,Sekretny sektor,Setor secreto,,Sector secret,Тайный сектор,Тајни сектор,Hemlig sektor,Gizli sektör, +Unexplored secret,MAPCOLORMNU_UNEXPLOREDSECRETCOLOR,,,,Neobjevená skrýš,Uudforsket hemmelighed,nicht gefundener geheimer Sektor,,Neesplorita sekreto,Secreto sin explorar,,Tutkimaton sala,Secret non révélé,Még fel nem fedezett rejtekhely,Segreto non esplorato,未知のシークレット,발견하지 않은 비밀,Onontgonnen geheim,Uutforsket hemmelighet,Niezbadany sekret,Segredo não-explorado,,Secret neexplorat,Необнаруженный тайник,Ноткривена тајна,Oexploaterad hemlighet,Keşfedilmemiş sır, +Special trigger lines,MAPCOLORMNU_SPECIALWALLCOLOR,,,,Akční čáry,Særlige udløserlinjer,Spezielle Linien,,Specialaj ekagilo-linioj,Líneas especiales de activación,,Erikoislaukaisinviivat,Lignes d'actions spéciales,Speciális trigger vonalak,Linee di attivazione speciali,特殊トリガー,특수 트리거 선,Speciale trekkerlijnen,Spesielle utløserlinjer,Specjalne linie przełączników,Linhas de ativação especiais,,Linii declașatoare speciale,Специальные спусковые линии,Специјалне линије окидача,Särskilda utlösningslinjer,Özel tetik hatları, +Cheat Mode,MAPCOLORMNU_CHEATMODE,,,,Cheatovací režim,Snyd-tilstand,Cheat-Modus,,Tromp-Reĝimo,Modo de truco,,Huijaustila,Mode Cheat,Csalás mód,Modalità cheat,チートモード時,치트 모드,Bedriegingsmodus,Juksemodus,Tryb oszustwa,Modo trapaça,Modo de Batota,Modul Trișor,Чит-режим,Чит мод,Fuskläge,Hile Modu, +Invisible 2-sided walls,MAPCOLORMNU_TSWALLCOLOR,,,,Neviditelné oboustranné zdi,Usynlige 2-sidede vægge,Unsichtbare zweiseitige Wände,,Nevideblaj 2-flankaj muroj,Paredes de 2 lados Invisibles,,Näkymättömät kaksipuoliset seinät,Murs à 2 côtés invisibles,Láthatatlan 2 oldalú falak,Muri invisibili bilaterali,表示されないline,투명한 양면 벽,Onzichtbare 2-zijdige wanden,Usynlige 2-sidige vegger,Niewidzialne dwustronne ściany,Paredes invisíveis de 2 lados,,Pereți cu două fețe invizibili,Невидимые двусторонние стены,Невидљиви двострани зидови,Osynliga 2-sidiga väggar,Görünmez 2 taraflı duvarlar, +Secret walls,MAPCOLORMNU_SECRETWALLCOLOR,,,,Tajné zdi,Hemmelige vægge,Geheime Wände,,Sekretaj muroj,Paredes secretas,,Salaiset seinät,Murs Secrets,Titkos falak,Muri segreti,シークレットの壁,비밀 벽,Geheime muren,Hemmelige vegger,Sekretne ściany,Paredes secretas,,Pereți ascunși,Тайные стены,Тајни зидови,Hemliga väggar,Gizli duvarlar, +Actors,MAPCOLORMNU_THINGCOLOR,,,,Objekty,Skuespillere,Akteure,,Aktoroj,Actores,,Oliot,Acteurs,Játékos,Attori,アクター,개체,Acteurs,Skuespillere,Aktorzy,Atores,,Actori,Объекты,Актори,Skådespelare,Aktörler, +Monsters,MAPCOLORMNU_MONSTERCOLOR,,,,Příšery,Monstre,Monster,,Monstroj,Monstruos,,Hirviöt,Monstres,Szörnyek,Mostri,モンスター,적들,,Monstre,Potwory,Monstros,,Monștri,Монстры,Чудовишта,Monster,Canavarlar, +Non-counting Monsters,MAPCOLORMNU_NONCOUNTINGMONSTERCOLOR,,,,Nepočítané příšery,Ikke-tællende monstre,nicht gezählte Monster,,Nenombradaj Monstroj,Monstruos no contados,Monstruos sin contar,Ei-laskettavat hirviöt,Monstres non comptés,Nem számolt szörnyek,Mostri non contati,非カウントモンスター,킬수에 포함 되지 않는 적들,Niet-tellende Monsters,Ikke-tellende monstre,Niezliczane Potwory,Monstros não contados,,Monștri neacoperiți de numărătoare,Неучитываемые монстры,Не рачунајући чудовишта,Icke-räknande monster,Sayılamayan Canavarlar, +Friends,MAPCOLORMNU_FRIENDCOLOR,,,,Přátelé,Venner,Freunde,,Amikoj,Amigos,,Omat,Amis,Barátok,Amici,仲間,친구들,Vrienden,Venner,Przyjaciele,Amigos,,Prieteni,Дружественные,Пријатељи,Vänner,Arkadaşlar, +Items,MAPCOLORMNU_ITEMCOLOR,,,,Předměty,Genstande,Gegenstände,,Objektoj,Objetos,,Esineet,Objets,Tárgyak,Oggetti,アイテム,아이템들,Artikelen,Gjenstander,Przedmioty,Itens,,Obiecte,Предметы,Предмети,Föremål,Eşyalar, +Count Items,MAPCOLORMNU_COUNTITEMCOLOR,,,,Počítané předměty,Tælle genstande,gezählte Gegenstände,,Nombri Objektojn,Objetos contados,Conteo de objetos,Laske esineet,Objets comptés,Tárgyak számolása,Oggetti contati,カウント対象アイテム,아이템 계산,Tellen,Telle elementer,Zlicz przedmioty,Itens contados,,Numără obiectele,Учитываемые предметы,Рачунајући предмети,Räkna objekt,Sayım Öğeleri, +Overlay Mode,MAPCOLORMNU_OVERLAY,,,,Překryvný režim,Overlay-tilstand,Überlagerungsmodus,,Surmeto-Reĝimo,Modo sobrepuesto,,Projisointitila,Mode surimpression,Overlay mód,Modalità sovrapposizione,オーバーレイモード,오버레이 모드,Overlaadmodus,Overleggsmodus,Tryb Nakładki,Modo de sobreposição,,Mod acoperit,Прозрачный режим,Провидна аутомапа,Överlagringsläge,Kaplama Modu, +Overlay Cheat Mode,MAPCOLORMNU_OVCHEATMODE,,,,Překryvný cheatovací režim,Overlay snydetilstand,Überlagerungsmodus Cheats,,Surmeto-Tromp-Reĝimo,Sobreposición modo de truco,,Projisointihuijaustila,Mode Cheat Surimpression,overlay csaló mód,Modalità cheat sovrapposizione,オーバーレイ チートモード,치트 모드 오버레이,Overlaadmodus Cheats,Overlegg-juksemodus,Tryb Nakładki Oszustwa,Modo trapaça de sobreposição,Modo Batota de Sobreposição,Mod acoperit trișor,Прозрачный чит-режим,Провидни читови,Överlagrat fuskläge,Kaplama Hile Modu, +Portal Overlays,MAPCOLORMNU_PORTAL,,,,Portálové překryvy,Portal-overlejringer,Portalüberlagerung,,Portalo-Surmetoj,Sobreposición de portal,,Portaaliprojisoinnit,Portails superposés,Portál overlay-ek,Sovrapposizioni del portale,ポータル オーバーレイ,포탈 오버레이,Portaaloverlays,Portal-overlegg,Nakładanie się Portali,Sobreposição de portais,,Acoperiri portaluri,Порталы в прозрачном режиме,Провидни портали,Överlagringar i portalen,Portal Kaplamaları, +,,Messages,,,,,,,,,,,,,,,,,,,,,,,,,, +Messages,MSGMNU_TITLE,,,,Nastavení oznámení,Meddelelser,Nachrichten,,Mesaĝoj,Mensajes,,Viestit,,Üzenetek,Messaggi,メッセージ類,메시지들,Berichten,Meldinger,Wiadomości,Mensagens,,Mesaje,Сообщения,Поруке,Meddelanden,Mesajlar, +Show messages,MSGMNU_SHOWMESSAGES,,,,Zobrazit oznámení,Vis meddelelser,Zeige Nachrichten,,Montri mesaĝojn,Mostrar mensajes,,Näytä viestit,Afficher messages,Üzenetek mutatása,Mostra messaggi,メッセージ表示,메시지 표시,Berichten tonen,Vis meldinger,Pokaż wiadomości,Exibir mensagens,,Afișare mesaje,Отображение сообщений,Прикажи поруке,Visa meddelanden,Mesajları göster, +Show obituaries,MSGMNU_SHOWOBITUARIES,,,,Zobrazit oznámení o smrtích,Vis dødsannoncer,Zeige Todesanzeigen,,Montri nekrologojn,Mostrar obituarios,,Näytä kuolinviestit,Afficher avis de décès,Halálok mutatása,Mostra i necrologi,訃報表示,사망 메시지 표시,Doodsbrieven tonen,Vis dødsannonser,Pokaż nekrologi,Exibir obituários,,Afișare necrologuri,Отображение некрологов,Прикажи читуље,Visa dödsannonser,Ölüm ilanlarını göster, +Show secret notifications,MSGMNU_SHOWSECRETS,,,,Zobrazit zprávy o skrýších,Vis hemmelige meddelelser,Zeige Geheimnismeldung,,Montri sciigojn de sekretoj,Mostrar notificación de secretos,,Ilmoita salojen löytymisestä,Afficher secrets,Titkos üzenetek mutatása,Mostra le notifiche dei segreti,シークレット発見表示,비밀 알림 표시,Geheime meldingen tonen,Vis hemmelige meldinger,Pokaż wiadomości znalezienia sekretu,Exibir notificação de segredos,,Afișare notificări pentru secrete,Отображение сообщений о тайниках,Прикажи тајне нотификације,Visa hemliga meddelanden,Gizli bildirimleri göster, +Minimum message level,MSGMNU_MESSAGELEVEL,,,,Minimální úroveň oznámení,Mindste beskedniveau,Min. Nachrichtenanzeigestufe,,Minimuma nivelo de mesaĝoj,Nivel mínimo de mensaje,,Pienin viestintätaso,Niveau de message minimum,Milyen üzenet jelenjen meg,Numero di messaggi minimo,最小メッセージレベル,메시지 축소량,Minimaal berichtenniveau,Minste meldingsnivå,Poziom minimalnych wiadomości,Nível mínimo de mensagem,,Nivel minim de afișare mesaje,Минимальный уровень сообщений,Минимум левел порука,Minsta nivå för meddelanden,Minimum mesaj seviyesi, +Message Colors,MSGMNU_MESSAGECOLORS,,,Message Colours,Barva oznámení,Farver på meddelelser,Nachrichtenfarben,,Mesaĝkoloroj,Colores de los mensajes,,Viestien värit,Couleur des messages,Üzenet színek,Colore dei messaggi,メッセージ色,메시지 색상,Bericht Kleuren,Meldingsfarger,Kolory Wiadomości,Cores de mensagem,,Culori Mesaje,Цвета сообщений,Боје порука,Färger för meddelanden,Mesaj Renkleri, +Item Pickup,MSGMNU_ITEMPICKUP,,,,Sebrání předmětu,Afhentning af varer,Genommene Gegenstände,,Objektoprenado,Coger objetos,Agarrar objetos,Esineen poimiminen,Objets ramassés,Tárgy felvétele,Raccolta oggetti,アイテム取得,아이템 획득,Puntafhaling,Henting av element,Podniesienie Przedmiotu,Coleta de item,Aquisição de Itens,Ridicare obiecte,Подбор предмета,Покупити предмет,Upphämtning av objekt,Bir eşyayı almak, +Obituaries,MSGMNU_OBITUARIES,,,,Oznámení o úmrtí,Dødsannoncer,Todesanzeigen,,Nekrologoj,Obituarios,,Kuolinviestit,Avis de décès,Halálok,Necrologi,死亡時メッセージ,사망 메시지,Doodsbrieven,Nekrologer,Nekrologi,Obituários,,Necrologuri,Некрологи,Читуље,Dödsannonser,Ölüm İlanları, +Critical Messages,MSGMNU_CRITICALMESSAGES,,,,Kritická oznámení,Kritiske meddelelser,Kritische Nachrichten,,Gravaj Mesaĝoj,Mensajes críticos,,Tärkeät viestit,Messages d'erreur,Fontos üzenetek,Messaggi critici,致命的なメッセージ,중요한 메시지,Kritische berichten,Kritiske meldinger,Wiadomości krytyczne,Mensagens críticas,,Mesaje Critice,Важные сообщения,Критичне поруке,Kritiska meddelanden,Kritik Mesajlar, +Chat Messages,MSGMNU_CHATMESSAGES,,,,Chatová oznámení,Chat-meddelelser,Chatnachrichten,,Babilmesaĝoj,Mensajes del chat,,Keskusteluviestit,Message de Chat,Chat üzenetek,Messaggi chat,チャットメッセージ,채팅 메시지,Chatberichten,Chat-meldinger,Wiadomości czatu,Mensagens de chat,,Mesaje Conversație,Сообщения в чате,Ћаскања,Chatt-meddelanden,Sohbet Mesajları, +Team Messages,MSGMNU_TEAMMESSAGES,,,,Týmová oznámení,Hold-meddelelser,Teamnachrichten,,Teammesaĝoj,Mensajes del equipo,,Joukkueen viestit,Messages d'équipe,Csapat chat üzenetek,Messaggi chat di squadra,チームメッセージ,팀 채팅 메시지,Team Berichten,Team-meldinger,Wiadomości czatu drużynowego,Mensagens de equipe,Mensagens de Equipa,Mesajele Echipei Proprii,Командные сообщения в чате,Тимске поруке,Meddelanden till laget,Ekip Mesajları, +Centered Messages,MSGMNU_CENTEREDMESSAGES,,,Centred Messages,Oznámení na střed,Centrerede meddelelser,Zentrierte Nachrichten,,Centritaj Mesaĝoj,Mensajes centrados,,Keskitetyt viestit,Messages centrés,Üzenet középre igazítása,Messaggi centrati,スクリプトメッセージ,중간에 위치한 메시지,Gecentreerde berichten,Sentrerte meldinger,Wyśrodkowane wiadomości,Mensagens centralizadas,Mensagens Centradas,Mesaje Centrate,Центрированные сообщения,Централне поруке,Centrerade meddelanden,Merkezli Mesajlar, +Screenshot messages,MSGMNU_SCREENSHOTMESSAGES,,,,Oznámení o snímcích obrazovky,Beskeder med skærmbilleder,Screnshot-Meldungen,,Mesaĝoj de ekrankopio,Mensajes de captura de pantalla,,Kuvakaappausviestit,Messages de capture d'écran,Képernyőkép készítés visszajelzés,Messaggi di cattura schermo,スクショメッセージ,스크린샷 메시지,Screenshot berichten,Skjermbilde-meldinger,Wiadomości o zrobieniu zrzutu ekranu,Mensagens de captura de tela,Mensagen de captura de ecrã,Mesaje Capturi Ecran,Сообщения о снимках экрана,Скриншот поруке,Meddelanden med skärmdump,Ekran görüntüsü mesajları, +Detailed save messages,MSGMNU_LONGSAVEMESSAGES,,,,Detailní oznámení o uložené hře,Detaljerede beskeder om lagring,Detaillierte Speicher-Meldungen,,Detalaj konservmesaĝoj,Mensajes detallados de guardado,,Yksityiskohtaiset tallennusviestit,Messages de sauvegarde détailés,Részletes mentési információ,Messaggi sui dettagli di salvataggio,詳細なセーブメッセージ,자세한 저장 메시지,Gedetailleerde berichten voor op te slaan,Detaljerte lagringsmeldinger,Szczegółowe wiadomości o zapisie,Mensagens detalhadas de salvamento,Mensagens detalhadas de gravação,Mesaje detaliate pentru salvări,Подробные сообщения о сохранениях,Детаљно сачуване поруке,Detaljerade meddelanden om sparande,Ayrıntılı kaydetme mesajları, +Developer message mode,MSGMNU_DEVELOPER,,,,Vývojářská oznámení,Meddelelsestilstand for udviklere,Entwickler-Modus,,Reĝimo de mesaĝoj por programistoj,Modo de mensajes de desarrollador,,Pelinkehittäjäviestitila,Mode de Développement,Fejlesztői üzenetek,Modalità messaggi per sviluppatore,開発者用モード,개발자 메시지 모드,Berichtenmodus voor ontwikkelaars,Meldingsmodus for utviklere,Tryb wiadomości deweloperskich,Modo de mensagens de desenvolvedor,,Mod mesaje pentru dezvoltator,Режим сообщений для разработчиков,Поруке девелопера,Meddelandeläge för utvecklare,Geliştirici mesaj modu, +,,Automap,,,,,,,,,,,,,,,,,,,,,,,,,, +Map color set,AUTOMAPMNU_COLORSET,,,Map colour set,Barevné schéma,Farvesæt til kort,Farbset,,Mapkoloro-agordaĵo,Definir colores,,Kartan värikokoelma,Set de couleurs de la carte,Pálya térkép szín séma,Colori della mappa,地図色セット,맵 색상 설정,Kaartkleurenset,Kartfargesett,Zestaw kolorów mapy,Definir cores de mapa,,Set culori hartă,Цвета автокарты,Боје за мапу,Färgsättning av kartan,Harita renk seti, +Allow map defined colors,AUTOMAPMNU_CUSTOMCOLORS,,,Allow map defined colours,Povolit barvy dle modů,Tillad kortdefinerede farver,Erlaube levelspezifische Farben,,Permesi mapdefinitajn kolorojn,Permitir colores definidos,,Salli tason määrittelemät värit,Couleurs définies par carte,Pálya orientált színséma használata,Consenti i colori definiti dalla mappa,定義したマップ色の許可,맵 정의 색상 허용,Niveau-specifieke kleuren toestaan,Tillat kartdefinerte farger,Pozwól na kolory zdefiniowne przez mapę,Permitir cores definidas por mapa,,Permite culorilor să fie definite de hartă,Разрешить определённые уровнем цвета автокарты,Дозволи дефинисане боје за мапу,Tillåter kartdefinierade färger,Harita tanımlı renklere izin ver, +Set custom colors,AUTOMAPMNU_SETCUSTOMCOLORS,,,Set custom colours,Vlastní barvy,Indstil brugerdefinerede farver,Benutzerdefinierte Farben,,Agordi laŭmendajn kolorojn,Fijar colores personalizados,,Mukauta värejä,Choisir couleurs personnalisées,Egyéni színek beállítása,Modifica i colori personalizzati,カスタム色を決める,사용자 지정 색상 설정,Aangepaste kleuren instellen,Angi egendefinerte farger,Spersonalizuj kolory,Definir cores personalizadas,,Setare culori personalizate,Задать свои цвета,Промени боје,Ställ in egna färger,Özel renkleri ayarlama, +Customize map controls,AUTOMAPMNU_CONTROLS,,,,Ovládání mapy,Tilpas kontrolelementer til kortet,Automapsteuerung einstellen,,Adapti mapregilojn,Personalizar controles del mapa,,Kartanohjausasetukset,Choisir contrôles de la carte,Térkép irányítás testreszabása,Personalizza i controlli mappa,マップコントロール カスタマイズ,맵 조작 설정,Kaartcontroles aanpassen,Tilpass kartkontroller,Ustaw klawisze mapy,Configurar comandos de mapa,,Personalizare schemă de control a hărții,Управление автокартой,Промени контроле мапе,Anpassa kartkontroller,Harita kontrollerini özelleştirme, +Overlay automap,AUTOMAPMNU_OVERLAY,,,,Překryvná mapa,Overlay automap,Überlagere Automap,,Surmeti aŭtomatan mapon,Superponer automapa,,Projisoi automaattikartta,Carte en Surimpression,Képen felüli térkép,Copri l'automappa,オートマップを重ねる,오토맵을 오버레이,Overlay automap,Overlegg automatisk kart,Nałożenie mapy,Sobreposição de automapa,,Acoperire hartă computerizată,Прозрачная автокарта,Провидна аутомапа,Överlagring av automap,Yerleşim otomatik haritası, +Enable textured display,AUTOMAPMNU_TEXTURED,,,,Textury,Aktiver tekstureret visning,Texturanzeige,,Ŝalti teksturitan ekranon,Mostrar automapa texturizado,,Ota käyttöön pintakuvioinnit,Activer affichage texturé,Textúrázott térkép,Abilita la mostra texture,床テクスチャ表示を許可,텍스쳐 디스플레이 허용,Structuurweergave inschakelen,Aktiver teksturert visning,Włącz oteksturowanie mapy,Habilitar automapa texturizado,Permitir automapa texturizado,Activare mod texturat,Текстуры на автокарте,Омогући приказ текстура,Aktivera texturerad visning,Dokulu ekranı etkinleştir, +Show item counts,AUTOMAPMNU_SHOWITEMS,,,,Počet předmětů,Vis tællinger af emner,Zeige Gegenstandsanzahl,,Montri nombron de objektoj,Mostrar conteo de objetos,,Näytä esineiden lukumäärä,Afficher compte d'objets,Tárgy számláló mutatása,Mostra il conteggio degli oggetti,アイテム数 表示,주운 아이템의 갯수를 표시,Toon artikeltellingen,Vis antall elementer,Pokaż liczbę przedmiotów,Exibir contagem de itens,,Afișare numărătoare obiecte,Количество предметов,Прикажи бројач за предмете,Visa antal objekt,Öğe sayılarını göster, +Show monster counts,AUTOMAPMNU_SHOWMONSTERS,,,,Počet příšer,Vis monstertællinger,Zeige Monsteranzahl,,Montri nombron de monstroj,Mostrar conteo de monstruos,,Näytä hirviöiden lukumäärä,Afficher compte de monstres,Szörny számláló mutatása,Mostra il conteggio dei mostri,モンスター数 表示,죽인 적의 횟수 표시,Toon monstertellingen,Vis antall monster,Pokaż liczbę potworów,Exibir contagem de monstros,,Afișare numărătoare monștri,Количество монстов,Прикажи бројач за чудовишта,Visa antal monster,Canavar sayılarını göster, +Show secret counts,AUTOMAPMNU_SHOWSECRETS,,,,Počet skrýší,Vis hemmelige tællinger,Zeige Geheimnisanzahl,,Montri nombron de sekretoj,Mostrar conteo de secretos,,Näytä salojen lukumäärä,Afficher compte de secrets,Rejtekhely számláló mutatása,Mostra il conteggio dei segreti,シークレット数 表示,밝힌 비밀의 수 표시,Toon geheime tellingen,Vis hemmelige tellinger,Pokaż liczbę sekretów,Exibir contagem de segredos,,Afișare numărătoare secrete,Количество тайников,Прикажи бројач за тајне,Visa antalet hemligheter,Gizli sayıları göster, +Show time elapsed,AUTOMAPMNU_SHOWTIME,,,,Uplynulý čas na mapě,Vis den forgangne tid,Zeige vergangene Zeit,,Montri pasintan tempon,Mostrar tiempo transcurrido,,Näytä kulunut aika,Afficher temps passé,Eltöltött idő mutatása,Mostra il tempo trascorso,経過時間 表示,경과한 시간 표시,Verstreken tijd tonen,Vis medgått tid,Pokaż ile czasu upłynęło,Exibir tempo decorrido,,Afișare timp petrecut pe hartă,Прошедшее время,Прикажи протекло време,Visa förfluten tid,Geçen süreyi göster, +Show total time elapsed,AUTOMAPMNU_SHOWTOTALTIME,,,,Celkový uplynulý čas,"Vis den samlede tid, der er gået",Zeige Gesamtzeit,,Montri tutan pasintan tempon,Mostrar tiempo total transc.,,Näytä yhteensä kulunut aika,Afficher total de temps passé,Teljes eltelt idő mutatása,Mostra il tempo totale trascorso,統計時間 表示,누적 경과한 시간 표시,Toon de totale verstreken tijd,Vis total tid som har gått,"Pokaż całkowity czas, który upłynął",Exibir tempo total decorrido,,Afișare timp total petrecut în joc,Общее время,Прикажи укупно протекло време,Visa total tid som förflutit,Geçen toplam süreyi göster, +Show secrets on map,AUTOMAPMNU_MAPSECRETS,,,,Zobrazit skrýše,Vis hemmeligheder på kortet,Zeige Geheimnisse auf der Karte,,Montri sekretojn sur mapo,Mostrar secretos en el mapa,,Näytä salat kartalla,Afficher secrets sur carte,Rejtekhelyek mutatása a pályán,Mostra i segreti nella mappa,シークレットを地図に表示,맵의 비밀을 표시,Toon geheimen op de kaart,Vis hemmeligheter på kartet,Pokaż sekrety na mapie,Exibir segredos no mapa,,Afișare secrete,Тайники на карте,Прикажи тајне на аутомапи,Visa hemligheter på kartan,Haritada sırları göster, +Show map label,AUTOMAPMNU_SHOWMAPLABEL,,,,Zobrazit název mapy,Vis kortmærke,Zeige Levelnamen,,Montri mapetikedon,Mostrar etiqueta del mapa,,Näytä tason tunniste,Afficher label de carte,Pályacím mutatása,Mostra le etichette della mappa,マップ名 表示,맵의 이름 표시,Toon kaartlabel,Vis kartetikett,Pokaż etykietę mapy,Exibir etiqueta do mapa,,Afișare etichetă hartă,Название карты,Прикажи ознаку мапе,Visa kartans etikett,Harita etiketini göster, +Draw map background,AUTOMAPMNU_DRAWMAPBACK,,,,Pozadí mapy,Tegne kortbaggrund,Zeige Kartenhintergrund,,Desegni mapfondon,Dibujar fondo de mapa,,Piirrä tason tausta,Afficher fond d'écran carte,Térkép háttér kirajzolása,Mostra lo sfondo della mappa,マップの背景 描写,맵의 배경 출력,Teken de achtergrond van de kaart,Tegn kartbakgrunn,Rysuj tło mapy,Desenhar fundo do mapa,,Afișare fundal hartă,Отображение фона автокарты,Нацртај позадину мапе,Rita kartans bakgrund,Harita arka planı çizme, +Show keys (cheat),AUTOMAPMNU_SHOWKEYS,,,,Zobrazení klíčů (podvod),Vis nøgler (snyd),Zeige Schlüssel (Cheat),,Montri klavojn (trompo),Mostrar llaves (truco),,Näytä avaimet (huijauskeino),Afficher les clés (cheat),Kulcsok mutatása,Mostra le chiavi (cheat),鍵 表示(チート時),키를 표시 (치트),Toon sleutels (valsspeler),Vis nøkler (juks),Pokaż klucze (oszustwo),Exibir chaves (trapaça),,Afișare chei (trișare),Отображение ключей (чит-коды),Прикажи кључеве (чит),Visa nycklar (fusk),Tuşları göster (hile), +Show trigger lines,AUTOMAPMNU_SHOWTRIGGERLINES,,,,Zobrazení aktivujících čar,Vis trigger-linjer,Zeige Auslöserlinien,,Montri baskulliniojn,Mostrar líneas de activación,,Näytä laukaisinviivat,Afficher lignes d'action,Trigger vonalak mutatása,Mostra le linee d'attivazione,トリガーライン 表示,트리거 선을 표시,Triggerlijnen tonen,Vis utløserlinjer,Pokaż linie przełączników,Exibir linhas de ativação,,Afișare linii declanșatoare,Отображение спусковых линий,Прикажи триггер линије,Visa utlösningslinjer,Tetik çizgilerini göster, +Show things as sprites,AUTOMAPMNU_SHOWTHINGSPRITES,,,,Zobrazení objektů jako spritů,Vis ting som sprites,Zeige Dinge als Sprites,,Montri aĵojn kiel mov-rastrumojn,Mostrar cosas como sprites,,Näytä oliot spriteinä,Afficher objets comme sprites,Tárgyak sprite-ként megjelenítése,Mostra gli oggetti come sprite,thingsのスプライト表示,물체를 스프라이트로 표시,Toon dingen als sprites,Vis ting som sprites,Pokaż rzeczy jako sprite'y,Exibir objetos como sprites,,Afișare obiecte drept sprite,Отображение спрайтов объектов,Прикажи ствари као спрајтове,Visa saker som sprites,Nesneleri sprite olarak gösterme, +Overlay portals,AUTOMAPMNU_PTOVERLAY,,,,Překrývat portály,Overlay portaler,Überlagere Portale,,Surmeti portalojn,Sobreponer portales,,Projisoi portaalit,Superposer les portails,Overlay portálok,Sovrapponi i portali,オーバーレイ ポータルズ,포탈을 오버레이,Overlappende portalen,Overlegg portaler,Nałóż portale,Sobreposição de portais,,Acoperire portaluri,Порталы в прозрачном режиме,Провидни портали,Överlagra portaler,Yerleşim portalları, +Empty space margin,AUTOMAPMNU_EMPTYSPACEMARGIN,,,,Práh prázdného prostoru,Tomrumsmargin,Breite des Randes,,Malplena spacia marĝeno,Margen de espacio vacío,,Tyhjän reunan leveys,Marge d'espace vide,Üres hely szegély,Margine dello spazio vuoto,空間の余白,빈공간 여백,Breedte van de rand,Tøm mellomromsmargen,Opróżnij margines przestrzeni,Margem de espaço vazio,,Margine spațiu gol,Край автокарты,Празна маргина,Marginal för tomt utrymme,Boş alan marjı, +Mark font,AUTOMAPMNU_MARKFONT,,,,Písmo značek,Marker skrifttype,Zeichensatz für Markierungen,,Marki tiparon,Fuente para marcas,,Karttamerkkien fontti,Police Marqueur,Jelzés betűtípus,Font del segnaposto,マークフォント,미니맵 마킹 폰트,Font voor markers,Merk skrifttype,Czcionka oznaczeń,Fonte das marcações,,Font marcaj,Шрифт отметок,Фонт ознака,Markera typsnitt,Mark yazı tipi, +Mark color,AUTOMAPMNU_MARKCOLOR,,,,Barva značek,Markere farve,Farbe für Markierungen,,Marki koloron,Color de las marcas,,Karttamerkkien väri,Couleur Marqueur,Jelzés szín,Colore del segnaposto,マーク色,미니맵 마킹 색상,Markeer kleur,Merk farge,Kolor oznaczeń,Cor das marcações,,Culoare marcaj,Цвет отметок,Боја ознака,Markera färg,Renk işaretle, +Set mark,MAPCNTRLMNU_SETMARK,,,,Umístit značku,Indstille mærke,Setze Markierung,,Meti markon,Fijar marca,,Aseta merkki,Placer repère,Jelzés beállítása,Aggiungi segnaposto,マークを置く,마크 추가,Markering instellen,Sett merke,Ustaw znacznik,Posicionar marcação,,Marcare,Поставить отметку,Постави ознаку,Ställ in märket,İşareti ayarla, +Clear mark,MAPCNTRLMNU_CLEARMARK,,,,Smazat značky,Slet markering,Lösche Markierung,,Forigi markon,Limpiar marca,,Pyyhi merkit,Enlever repères,Jelzések törlése,Pulisci il segnaposto,マーククリア,마크 삭제,Duidelijke markering,Fjern merke,Usuń znacznik,Limpar marcação,,Ștergere marcaj,Убрать отметку,Уклони ознаку,Rensa markeringen,Açık işaret, +,,Scoreboard,,,,,,,,,,,,,,,,,,,,,,,,,, +Scoreboard Options,DSPLYMNU_SCOREBOARD,,,,Tabulka skóre,Indstillinger for resultattavlen,Punktetabellenoptionen,,Poentotabulo-Agordoj,Opciones de marcador,,Pistetauluasetukset,Options Tableau des Scores,Eredményjelző beállítások,Opzioni tabella punteggio,スコアボード オプション,점수창 설정,Scorebord opties,Alternativer for resultattavlen,Opcje Tablicy Wyników,Opções de Tela de Pontuação,,Opțiuni Tabelă de Marcaj,Таблица очков,Табеларне подешавања,Alternativ för resultattavlan,Skorbord Seçenekleri, +Scoreboard Options,SCRBRDMNU_TITLE,,,,Nastavení tabulky skóre,Indstillinger for resultattavlen,Punktetabellenoptionen,,Poentotabulo-Agordoj,Opciones de marcador,,Pistetauluasetukset,Tableau des Scores,Eredményjelző beállítások,Opzioni per la tabella punteggio,スコアボード オプション,점수판 설정,Scorebord opties,Alternativer for resultattavlen,Opcje Tablicy Wyników,Opções de Tela de Pontuação,Opções do Ecrã de Pontuação,Setări Tabelă de Marcaj,Настройки таблицы очков,Подешавања бодовања,Alternativ för resultattavlan,Skorbord Seçenekleri, +Cooperative Options,SCRBRDMNU_COOPERATIVE,,,,Kooperativní mód,Samarbejdsmuligheder,Kooperativ-Optionen,,Kooperativo-Agordoj,Opciones de cooperativo,,Yhteispeliasetukset,Options Mode Coop,Együttműködő beállítása,Opzioni per il gioco cooperativo,協力モードの設定,코옵 설정,Coöperatieve Opties,Samarbeidsalternativer,Opcje Kooperacji,Opções de Jogo Cooperativo,,Setări Mod Cooperativ,Настройки для команд,Подешавања сарадње,Alternativ för samarbete,Kooperatif Seçenekleri, +Enable Scoreboard,SCRBRDMNU_ENABLE,,,,Povolit tabulku skóre,Aktiver resultattavle,Punktetabelle aktiv,,Ŝalti Poentotabulon,Activar marcador,,Ota käyttöön pistetaulu,Activer Tableau des Scores,Eredményjelző bekapcsolása,Abilita la tabella punteggio,スコアボード表示,점수판 허용,Scorebord inschakelen,Aktiver resultattavle,Zezwól na Tablicę Wyników,Habilitar Tela de Pontuação,Permitir Ecrã de Pontuação,Activare Tabelă de Marcaj,Включить таблицу очков,Омогући бодовање,Aktivera resultattavlan,Skor Tablosunu Etkinleştir, +Header Color,SCRBRDMNU_HEADERCOLOR,,,Header Colour,Barva hlavičky,Overskriftsfarve,Kopfzeilenfarbe,,Kapokoloro,Color de cabecera,,Otsikon väri,Couleur du Titre,Fejléc szín,Colore della testata,ヘッダー色,헤더의 색깔,Kleur koptekst,Farge på topptekst,Kolor Nagłówka,Cor de Cabeçalho,,Culoare Antet,Цвет заголовка,Боја заглавља,Färg på rubriken,Başlık Rengi, +Your Player Color,SCRBRDMNU_YOURCOLOR,,,Your Player Colour,Barva tvého hráče,Din spillerfarve,Deine Spielerfarbe,,Via ludantkoloro,Color de tu jugador,,Pelaajasi väri,Votre couleur,Játékos színe,Colore del giocatore 'Tu',自分の色,플레이어의 색깔,Uw Spelerskleur,Din spillerfarge,Twoje Kolory,Cor do Seu Jogador,Cor do teu Jogador,Culoarea Jucătorului Tău,Ваш цвет,Боја твога играча,Din spelares färg,Oyuncu Renginiz, +Other Players' Color,SCRBRDMNU_OTHERPLAYERCOLOR,,,Other Players' Colour,Barva ostatních hráčů,Andre spilleres farve,Andere Spielerfarbe,,Koloro de aliaj ludantoj,Color de otros jugadores,,Muiden pelaajien väri,Couleur des autres joueurs,Más játékosok színe,Colore degli altri giocatori,他者の色,다른 플레이어들의 색깔,Andere spelerskleur,Andre spilleres farge,Kolory Innych Graczy,Cor de Outros Jogadores,Cor dos Outros Jogadores,Culorile Celorlalți Jucători,Цвет других игроков,Боја другог играча,Andra spelares färg,Diğer Oyuncuların Rengi, +Deathmatch Options,SCRBRDMNU_DEATHMATCH,,,,Deathmatch,Indstillinger for Deathmatch,Deathmatch-Optionen,,Mortmaĉo-Agordoj,Opciones modo a muerte,,Kuolonotteluasetukset,Options Deathmatch,Deathmatch Beállítások,Opzioni deathmatch,デスマッチの設定,데스매치 설정,Deathmatch opties,Deathmatch-alternativer,Opcje Deathmatchu,Opções de Deathmatch,,Setări Deathmatch,Настройки боя насмерть,Детмеч подешавања,Alternativ för Deathmatch,Ölüm Maçı Seçenekleri, +Team Deathmatch Options,SCRBRDMNU_TEAMDEATHMATCH,,,,Týmový deathmatch,Indstillinger for Team Deathmatch,Team-Deathmatch-Optionen,,Teamo-Mortmaĉo-Agordoj,Opciones modo a muerte por equipos,,Joukkuekuolonotteluasetukset,Options Deathmatch en équipe,Team Deathmatch Beállítások,Opzioni deathmatch a squadra,チームデスマッチの設定,팀 데스매치 설정,Team Deathmatch Opties,Lag Deathmatch-alternativer,Opcje Drużynowego Deathmatchu,Opções de Deathmatch de Equipe,Opções de Deathmatch de Equipa,Setări Deathmatch în Echipă,Настройки командного боя насмерть,Тимски детмеч подешавања,Alternativ för Team Deathmatch,Takım Ölüm Maçı Seçenekleri, +,,Alt HUD,,,,,,,,,,,,,,,,,,,,,,,,,, +Alternative HUD,ALTHUDMNU_TITLE,,,,Alternativní HUD,Alternativ HUD,Alternatives HUD,,Alternativa HUD,HUD alternativo,,Vaihtoehtoinen tilanäyttö,ATH Alternatif,Alternatív HUD,HUD alternativo,オルタナティブHUD,대체 HUD,Alternatieve HUD,Alternativ HUD,Alternatywny HUD,HUD alternativo,,Interfață pe Timp de Joc Alternativă,Альтернативное отображение информации,Алтернативни HUD,Alternativ HUD,Alternatif HUD, +Enable alternative HUD,ALTHUDMNU_ENABLE,,,,Povolit alternativní HUD,Aktiver alternativt HUD,Alternatives HUD eingeschaltet,,Ŝalti alternativan HUD,Activar HUD alternativo,,Ota käyttöön vaihtoehtoinen tilanäyttö,Activer l'ATH Alternatif,Alternatív HUD bekapcsolása,Abilita HUD alternativo,オルタナティブHUD有効,대체 HUD 사용,Alternatieve HUD inschakelen,Aktiver alternativ HUD,Włącz alternatywny HUD,Habilitar HUD alternativo,,Activează Interfața pe Timp de Joc Alternativă,Включить альтернативное отображение,Укључи алтернативни HUD,Aktivera alternativ HUD,Alternatif HUD'yi etkinleştirin, +Show secret count,ALTHUDMNU_SHOWSECRETS,,,,Zobrazit počet skrýší,Vis hemmelig optælling,Zeige Geheimniszähler,,Montri sekretonombron,Mostrar cont. de secretos,,Näytä salojen lukumäärä,Afficher compteur de secrets,Rejtekhely számláló mutatása,Mostra il conteggio dei segreti,シークレット数 表示,비밀 수 표시,Toon het aantal geheimen,Vis hemmelig antall,Pokaż liczbę sekretów,Exibir contagem de segredos,,Afișează numărul secretelor,Отображение обнаруженных тайников,Прикажи количину тајна,Visa hemligt antal,Gizli sayımı göster, +Show monster count,ALTHUDMNU_SHOWMONSTERS,,,,Zobrazit počet příšer,Vis monstertælling,Zeige Monsterzähler,,Montri monstronombron,Mostrar cont. de monstruos,,Näytä hirviöiden lukumäärä,Afficher compteur de monstres,Szörny számláló mutatása,Mostra il conteggio dei mostri,モンスター数 表示,적 개체 수 표시,Toon het aantal monsters,Vis antall monstre,Pokaż liczbę zabójstw,Exibir contagem de monstros,,Afișează numărul de monștri,Отображение количества монстров,Прикажи количину чудовишта,Visa antalet monster,Canavar sayısını göster, +Show item count,ALTHUDMNU_SHOWITEMS,,,,Zobrazit počet předmětů,Vis optælling af genstande,Zeige Gegenstandszähler,,Montri objektonombron,Mostrar cont. de objetos,,Näytä esineiden lukumäärä,Afficher compteur d'objets,Tárgy számláló mutatása,Mostra il conteggio degli oggetti,アイテム数の表示,아이템 수 표시,Toon het aantal items,Vis antall gjenstander,Pokaż liczbę przedmiotów,Exibir contagem de itens,,Afișează numărul de obiecte,Отображение количества предметов,Прикажи количину предмета,Visa antalet föremål,Öğe sayısını göster, +Show stamina and accuracy,ALTHUDMNU_SHOWSTATS,,,,Zobrazit výdrž a přesnost,Vis udholdenhed og nøjagtighed,Zeige Kondition und Genauigkeit,,Montri viglecon kaj akuratecon,Mostrar resistencia/precisión,,Näytä puhti ja tarkkuus,Afficher Endurance et Précision,Állóképesség és pontosság mutatása,Mostra stamina e accuratezza,スタミナと精度の表示,스테미나와 정확도를 표시,Toon uithoudingsvermogen en nauwkeurigheid,Vis utholdenhet og nøyaktighet,Pokaż wytrzymałość i precyzję,Exibir resistência e precisão,,Afișează rezistența fizică si acuratețea,Отображение выносливости и точности,Прикажи издржљивост и прецизност,Visa uthållighet och noggrannhet,Dayanıklılık ve doğruluk gösterin, +Show berserk,ALTHUDMNU_SHOWBERSERK,,,,Zobrazit berserk,Vis berserk,Zeige Berserk,,Montri frenezecon,Mostrar berserker,,Näytä raivo,Afficher Berserk,Berserk mutatása,Mostra il berserk,バーサーク表示,버서크 아이템을 표시,Toon berserk,Vis berserk,Pokaż szał,Exibir berserk,,Afișează pachetul de forță mărită,Отображение берсерка,Прикажи берсерк,Visa berserk,Berserk'i göster, +Show weapons,ALTHUDMNU_SHOWWEAPONS,,,,Zobrazit zbraně,Vis våben,Zeige Waffen,,Montri armojn,Mostrar armas,,Näytä aseet,Afficher Armes,Fegyverek mutatása,Mostra le armi,武器表示,무기들을 표시,Toon wapens,Vis våpen,Pokaż bronie,Exibir armas,,Afișează armele,Отображение оружия,Прикажи оружја,Visa vapen,Silahları göster, +Show ammo for,ALTHUDMNU_SHOWAMMO,,,,Zobrazit munici pro,Vis ammunition for,Zeige Munition,,Montri municion por,Mostrar munición para,,Näytä ammukset aseelle,Afficher Munitions pour,Ammo mutatása a,Mostra le munizioni per,弾薬等の表示,탄약을 표시,Toon munitie voor,Vis ammunisjon for,Pokaż amunicję dla,Exibir munição para,,Afișează muniția pentru,Отображение патронов для,Прикажи муниције за,Visa ammunition för,Cephane göster, +Show time,ALTHUDMNU_SHOWTIME,,,,Zobrazit čas,Vis tid,Zeige Zeit,,Montri tempon,Mostrar tiempo,,Näytä aika,Afficher temps niveau,Idő mutatása,Mostra il tempo,時間の表示,시간 표시,Toon tijd,Vis tid,Pokaż czas,Exibir tempo,,Afișează timpul,Отображение времени,Прикажи време,Visa tid,Gösteri zamanı, +Time color,ALTHUDMNU_TIMECOLOR,,,Time colour,Barva času,Tidens farve,Zeit-Farbe,,Tempkoloro,Color del tiempo,,Ajan väri,Couleur du timer,Idő színe,Colore del tempo,時間の字色,시간 색상,Tijdskleur,Tid farge,Kolor czasu,Cor do tempo,,Culoare timp,Цвет времени,Боја времена,Tidens färg,Zaman rengi, +Show network latency,ALTHUDMNU_SHOWLAG,,,,Zobrazit latenci sitě,Vis netværksforsinkelse,Zeige Netzwerk-Latenz,,Montri reto-respondotempon,Mostrar latencia de red,,Näytä verkon viive,Afficher latence réseau,Válaszidő mutatása,Mostra la latenza del network,ネットのラグ表示,내트워크 트래픽 표시,Toon netwerklatentie,Vis nettverksforsinkelse,Pokaż czas oczekiwania sieci,Exibir latência de rede,,Afișează perioada de întârziere a conexiunii,Отображение задержки сети,Прикажи кашњење мреже,Visa nätverksfördröjning,Ağ gecikmesini göster, +Ammo display order,ALTHUDMNU_AMMOORDER,,,,Pořadí zobrazení munice,Visningsrækkefølge for ammunition,Munitionsreihenfolge,,Vidiga aranĝo de municio,Orden vista de munición,,Ammusten esitysjärjestys,Ordre d'affichage des munitions,Muníció típus rendezése,Ordine mostra delle munizioni,弾薬表示順,탄약 표시 순서,Volgorde van de munitieweergave,Rekkefølge for ammunisjonsvisning,Kolejność pokazywania amunicji,Ordem de exibição de munição,,Ordine afișare muniție,Порядок отображения боеприпасов,Редослед муниција,Ordning för visning av ammunition,Cephane teşhir düzeni, +Red ammo display below %,ALTHUDMNU_AMMORED,,,,Červený indikátor munice pod %,Rød ammunitionsvisning under %,Rot für Munition unter %,,Ruĝa municividigo sub %,Porcent. de munición en rojo,,Punaiset ammukset ammusten alittaessa %,Compteur de munitions rouge sous,Piros muníció szín % alatt,Contatore delle munizioni di colore rosso sotto,弾薬の赤色表示%,적색 남은 탄약 밑에 표시,Rood munitieweergave onder %,Rød visning av ammunisjonsnivå under %,Wyświetl czerwoną amunicję pod ,Porcentagem de munição em vermelho até,Percentagem de munição em vermelho até,Muniția schimbă culoarea în roșu sub %,"Отображение боеприпасов красным ниже, %",Прикажи муниције црвеном испод %,Röd ammunition visas under %,Aşağıda kırmızı cephane göstergesi %, +Yellow ammo display below %,ALTHUDMNU_AMMOYELLOW,,,,Žlutý indikátor munice pod %,Gul ammunitionsvisning under %,Gelb für Munition unter %,,Flava municividigo sub %,Porcent. de munición en amarillo,,Keltaiset ammukset ammusten alittaessa %,Compteur de munitions jaune sous,Sárga muníció szín % alatt,Contatore delle munizioni di colore giallo sotto,弾薬の黄色表示%,황색 남은 탄약 밑에 표시,Gele munitieweergave onder %,Gult ammunisjonsdisplay under %.,Wyświetl żółtą amunicję pod ,Porcentagem de munição em amarelo até,Percentagem de munição em amarelo até,Muniția schimbă culoarea în galben sub %,"Отображение боеприпасов жёлтым ниже, %",Прикажи муниције жутом испод %,Gul ammunition visas under %,Aşağıda sarı cephane göstergesi %, +Red health display below,ALTHUDMNU_HEALTHRED,,,,Červený indikátor zdraví pod,Rødt sundhedsindikator under %,Rot für Gesundheit unter %,,Ruĝa sanvidigo sube,Porcent. de salud en rojo,,Punainen terveys terveyden alittaessa,Compteur de santé rouge sous,Piros életerő szín ezen szám alatt,Contatore della salute di colore rosso sotto,体力の赤色表示%,적색 체력 밑에 표시,Rood gezondheidsweergave beneden,Rød helsevisning under,Wyświetl czerwone zdrowie pod ,Porcentagem de saúde em vermelho até,Percentagem de saúde em vermelho até,Sănătatea schimbă culoarea în roșu sub %,"Отображение здоровья красным ниже, %",Прикажи здравље црвеном испод,Röd hälsoindikator nedanför,Aşağıdaki kırmızı sağlık göstergesi, +Yellow health display below,ALTHUDMNU_HEALTHYELLOW,,,,Žlutý indikátor zdraví pod,Gul sundhedsindikator under %,Gelb für Gesundheit unter %,,Flava sanvidigo sube,Porcent. de salud en amarillo,,Keltainen terveys terveyden alittaessa,Compteur de santé jaune sous,Sárga életerő szín ezen szám alatt,Contatore della salute di colore giallo sotto,体力の黄色表示%,황색 체력 밑에 표시,Geel gezondheidsweergave beneden,Gul helsevisning nedenfor,Wyświetl żółte zdrowie pod ,Porcentagem de saúde em amarelo até,Percentagem de saúde em amarelo até,Sănătatea schimbă culoarea în galben sub %,"Отображение здоровья жёлтым ниже, %",Прикажи здравље жутом испод,Gul hälsoindikator nedanför,Aşağıdaki sarı sağlık göstergesi, +Green health display below,ALTHUDMNU_HEALTHGREEN,,,,Zelený indikátor zdraví pod,Grønt sundhedsindikator under %,Grün für Gesundheit unter %,,Verda sanvidigo sube,Porcent. de salud en verde,,Vihreä terveys terveyden alittaessa,Compteur de santé vert sous,Zöld életerő szín ezen szám alatt,Contatore della salute di colore verde sotto,体力の緑色表示%,녹색 체력 밑에 표시,Groen gezondheidsweergave beneden,Grønn helsevisning under,Wyświetl zielone zdrowie pod ,Porcentagem de saúde em verde até,Percentagem de saúde em verde até,Sănătatea schimbă culoarea în verde sub %,"Отображение здоровья зелёным ниже, %",Прикажи здравље зеленом испод,Grön hälsoindikator nedan,Aşağıdaki yeşil sağlık göstergesi, +Red armor display below,ALTHUDMNU_ARMORRED,,,Red armour display below,Červený indikátor brnění pod,Rødt panser display under %,Rot für Panzerung unter %,,Ruĝa kirasvidigo sube,Porcent. de blindaje en rojo,,Punainen panssari panssarin alittaessa,Compteur d' armure rouge sous,Piros páncél szín ezen szám alatt,Contatore dell'armatura di colore rosso sotto,防具の赤色表示%,적색 아머 밑에 표시,Rood pantserweergave beneden,Visning av rød rustning under,Wyświetl czerwony pancerz pod ,Porcentagem de armadura em vermelho até,Percentagem de armadura em vermelho até,Armura schimbă culoarea în galben sub %,"Отображение брони красным ниже, %",Прикажи оклоп црвеном испод,Röd rustning visas nedan,Kırmızı zırh ekranı aşağıda, +Yellow armor display below,ALTHUDMNU_ARMORYELLOW,,,Yellow armour display below,Žlutý indikátor brnění pod,gul panser under displayet under %,Gelb für Panzerung unter %,,Flava kirasvidigo sube,Porcent. de blindaje en amarillo,,Keltainen panssari panssarin alittaessa,Compteur d' armure jaune sous,Sárga páncél szín ezen szám alatt,Contatore dell'armatura di colore giallo sotto,防具の黄色表示%,황색 아머 밑에 표시,Geel pantserweergave beneden,Visning av gul rustning under,Wyświetl żółty pancerz pod ,Porcentagem de armadura em amarelo até,Percentagem de armadura em amarelo até,Armura schimbă culoarea în galben sub %,"Отображение брони жёлтым ниже, %",Прикажи оклоп жутом испод,Gul rustning visas nedan,Aşağıdaki sarı zırh ekranı, +Green armor display below,ALTHUDMNU_ARMORGREEN,,,Green armour display below,Zelený indikátor brnění pod,grønt panser display under %,Grün für Panzerung unter %,,Verda kirasvidigo sube,Porcent. de blindaje en verde,,Vihreä panssari panssarin alittaessa,Compteur d' armure bleu sous,Zöld páncél szín ezen szám alatt,Contatore dell'armatura di colore verde sotto,防具の緑色表示%,녹색 아머 밑에 표시,Groen pantserweergave beneden,Visning av grønn rustning under,Wyświetl zielony pancerz pod ,Porcentagem de armadura em verde até,Percentagem de armadura em verde até,Armura schimbă culoarea în verde sub %,"Отображение брони зелёным ниже, %",Прикажи оклоп зеленом испод,Grön rustning visas nedan,Aşağıdaki yeşil zırh ekranı, +Alternative Automap HUD,ALTHUDMNU_AUTOMAPHUD,,,,Alternativní HUD automapy,Alternativ Automap HUD,Alternatives Automap HUD,,Alternativa HUD de aŭtomata mapo,HUD alternativo del automapa,,Vaihtoehtoinen automaattikartan tilanäyttö,ATH Alternatif pour carte,Alternatív Automap HUD,HUD automappa alternativo,オルタナティブ オートマップHUD,대체 오토맵 HUD,Alternatieve Automap HUD,Alternativ Automap HUD,Alternatywny HUD mapy,HUD alternativo de automapa,,Hartă Computerizată Alternativă,Альтернативный интерфейс на автокарте,Алтернативни HUD за аутомапу,Alternativ automap HUD,Alternatif Automap HUD, +Map title color,ALTHUDMNU_TITLECOLOR,,,Map title colour,Barva názvu levelu,Farve på korttitel,Farbe für Levelnamen,,Maptitolo-koloro,Color del título del mapa,,Tason nimen väri,Couleur titre du niveau,Pálya cím szín,Colore titolo mappa,マップ名の色,맵 제목 색깔,Kleur kaarttitel,Farge på karttittel,Kolor nazwy mapy,Cor do título do fase,Cor do título do nível,Culoare titlu hartă,Цвет названия уровня,Боја назива нивоа,Färg på kartans titel,Harita başlık rengi, +Map time color,ALTHUDMNU_MAPTIMECOLOR,,,Map time colour,Barva času levelu,Farve på kortets tid,Farbe für Level-Zeit,,Maptempo-koloro,Color del tiempo del mapa,,Tason ajan väri,Couleur temps du niveau,Pálya idő szín,Colore tempo mappa,経過時間の色,맵 시간 색깔,Kleur kaarttijd,Kartets tidsfarge,Kolor czasu na mapie,Cor do tempo da fase,Cor do tempo do nível,Culoare timp petrecut pe hartă,Цвет времени для уровней,Боја времена на нивоу,Färg för kartans tid,Harita zaman rengi, +Hub time color,ALTHUDMNU_HUBTIMECOLOR,,,Hub time colour,Barva času hubu,Farve på hub-tid,Farbe für Hub-Zeit,,Nabtempo-koloro,Color del tiempo del nodo,,Tasokokoelman ajan väri,Couleur temps du hub,Csomópont idő szín,Colore tempo hub di mappe,区間経過時間の色,허브 시간 색깔,Kleur hubtijd,Farge for knutepunkttid,Kolor czasu w hubie,Cor do tempo no HUD,,Culoare timp petrecut în hub,Цвет времени для хабов,Боја времена на хабу,Färg för navets tid,Hub zaman rengi, +Total time color,ALTHUDMNU_TOTALTIMECOLOR,,,Total time colour,Barva celkového času,Farve for samlet tid,Farbe für Gesamtzeit,,Tuttempo-koloro,Color del tiempo total,,Kokonaisajan väri,Couleur temps total,Teljes idő szín,Colore tempo totale,合計経過時間の色,누적 경과한 시간 색깔,Kleur totale tijd,Farge for total tid,Kolor całkowitego czasu,Cor do tempo total,,Culoare timp total,Цвет общего времени,Боја укупног времена,Färg för total tid,Toplam zaman rengi, +Coordinate color,ALTHUDMNU_COORDINATECOLOR,,,Coordinate colour,Barva souřadnic,Koordinat farve,Farbe für Koordinaten,,Kunordigi koloron,Color de coordenadas,,Koordinaattien väri,Couleur coordonnées,Koordináló szín,Colore coordinate,座標色,좌표 색깔,Kleur coördinaten,Koordinatfarge,Skoordynuj kolor,Cor das coordenadas,,Culoare coordonate,Цвет координат,Боја координата,Färg för koordinater,Koordinat rengi, +Coordinate mode,ALTHUDMNU_COORDINATEMODE,,,,Režim souřadnic,Koordinattilstand,Koordinatenmodus,,Kunordigi modon,Modo de coordenadas,,Koordinaattitila,Mode coordonnées,Koordináló mód,Modalità coordinate,座標モード,좌표 모드,Coördinatiemodus,Koordinat-modus,Skoordynuj tryb,Modo de coordenada,,Mod coordonate,Координаты игрока,Мод координата,Koordinatläge,Koordinat modu, +Statistics name color,ALTHUDMNU_STATSNAMECOLOR,,,Statistics name colour,Barva názvu statistik,Farve på statistiknavn,Farbe für Statistik-Namen,,Statistiknomo-koloro,Color del nombre de estadísticas,,Tilastotiedon nimen väri,Couleur nom des statistiques,Statisztika név szín,Colore nome statistica,統計名の色,통계표 이름 색상,Kleur statistiekennaam,Farge på statistikknavn,Kolor nazw statystyk,Cor do nome das estatísticas,,Culoare nume statistici,Цвет имён в статистике,Боја назива статистика,Färg för statistiknamn,İstatistik adı renk, +Statistics color,ALTHUDMNU_STATSCOLOR,,,Statistics colour,Barva statistik,Statistik farve,Farbe für Statistik-Nummern,,Statistiko-koloro,Color de las estadísticas,,Tilastotiedon väri,Couleur statistiques,Statisztika szín,Colore contatore statistica,統計の色,통계표 색상,Kleur statistieken,Statistikk farge,Kolor statystyk,Cor das estatísticas,,Culoare statistici,Цвет статистики,Боја статистика,Färg för statistik,İstatistik renk, +,,Display (game related),,,,,,,,,,,,,,,,,,,,,,,,,, +Rendering Interpolation,DSPLYMNU_CAPFPS,,,,Interpolace vykreslování,Interpolering af rendering,Renderinterpolation,,Bildigo-Interpolado,Interpolación de renderizado,,Hahmonnuksen interpolointi,Interpolation du rendu,Render animáció simítás,Interpolazione grafica,レンダリング補間,프레임 제한,Interpolatie renderen,Gjengivelse av interpolasjon,Interpolacja Renderowania,Interpolação de renderização,,Interpolare Imagine,Сглаживание обработки,Интерполација рендеринга,Rendering Interpolering,Rendering Enterpolasyonu, +Transparency render mode,DSPLYMNU_BLENDMETHOD,,,,Režim vykreslování průhlednosti,Gennemsigtighedstilstand,Transparenzmodus,,Travidebleco-bildigo-reĝimo,Modo de renderizado de transparencia,,Läpinäkyvyyden hahmonnustila,Mode de Rendu transparence,Átlászóság render mód,Modalità della resa grafica della trasparenza,レンダリング透過モード,투명도 표시 모드,Transparantie render modus,Gjengivelsesmodus for gjennomsiktighet,Tryb renderowania przezroczystości,Modo de renderiz. de transparência,,Mod Transparență,Режим обработки прозрачности,Режим рендеринга транспарентности,Återgivning med transparens,Şeffaflık render modu, +Screen wipe style,DSPLYMNU_WIPETYPE,,,,Styl přechodů,Skærmens aftørringsstil,Bildschirmwechseleffekt,,Stilo de ekranviŝo,Transición de pantalla,,Ruudun pyyhkiytymistyyli,Style de Fondu d'écran,Képernyőtörlődés módja,Stile della pulizia dello schermo,スクリーンワイプモード,화면 전환 방식,Schermveegstijl,Stil for skjermtørking,Styl przejścia ekranu,Tipo de transição de tela,Tipo de transição de ecrã,Stil ștergere imagine,Эффект плавной смены экранов,Ефект брисања екрана,Stil för skärmtorkning,Ekran silme stili, +Show ENDOOM screen,DSPLYMNU_SHOWENDOOM,,,,Zobrazit ENDOOM obrazovku,Vis ENDOOM-skærm,Zeige ENDOOM,,Montri ENDOOM-ekranon,Mostrar pantalla ENDOOM,,Näytä ENDOOM-ruutu,Montrer la fenêtre ENDOOM,ENDOOM képernyő mutatása,Mostra la schermata ENDOOM,ENDOOM画面を表示,종료화면 표시,Toon ENDOOM scherm,Vis ENDOOM-skjerm,Pokaż ekran ENDOOM,Exibir tela ENDOOM,,Afișare fereastră ENDOOM,Показать экран ENDOOM,Прикажи ENDOOM екран,Visa ENDOOM-skärm,ENDOOM ekranını göster, +Blood Flash Intensity,DSPLYMNU_BLOODFADE,,,,Intenzita bliknutí při zranění,Blodblinkintensitet,Intensität für Bluteffekt,,Egeco de sango-ekbrilo,Intensidad del destello al ser atacado,,Verivälähdyksen voimakkuus,Intensité du flash dommages,Sebzéskor villanás mértéke,Intensità Bagliore Sangue,血粉の濃度,피격 표시 강도,Intensiteit van de bloedflitser,Intensitet for blodblits,Intensywność Efektów Krwi,Intensidade de Flash de Sangue,,Intensitate strălucire sânge,Интенсивность вспышки при ранении,Интензивност треперења током повређивања,Intensitet av blodblixt,Kan Flaş Yoğunluğu, +Pickup Flash Intensity,DSPLYMNU_PICKUPFADE,,,,Intenzita bliknutí při sebrání předmětu,Intensitet for optageeffekt,Intensität für Aufnehmen-Effekt,,Egeco de prenado-ekbrilo,Intensidad del destello al coger algo,Intensidad del destello al agarrar algo,Poimintavälähdyksen voimakkuus,Intensité du flash objets,Fegyver felvételekor villanás mértéke,Intensità Bagliore Raccolta,取得の視界色濃度,습득 표시 강도,Intensiteit van de oppakflitser,Intensitet av opptaksblits,Intesnywność Efektów Podnoszenia Przedmiotów,Intensidade de Flash ao Pegar Itens,,Intensitate strălucire la ridicarea obiectelor,Интенсивность вспышки при подборе,Интензивност треперења током купљења,Intensitet av pickupblink,Pikap Flaş Yoğunluğu, +Underwater Blend Intensity,DSPLYMNU_WATERFADE,,,,Intenzita zbarvení pod vodou,Undervandsblinkintensitet,Intensität für Unterwasser-Effekt,,Egeco de Subakva Mikso,Intensidad Color Sumergido,Intensidad Color Submarino,Vedenalaissumennuksen voimakkuus,Intensité du fondu sous l'eau,Vízalatti keverődés mértéke,Intensità Blend sott'acqua,水中反響音の濃度,수중 효과 강도,Intensiteit kleurvermenging onder water,Intensitet for undervannsblanding,Intensywność Efektów Pod Wodą,Intensidade de Efeito Debaixo d'Água,Intensidade de Efeito Debaixo de Água,Intensitate amestec culori subacvatice,Интенсивность эффекта под водой,Интензивност подводног треперења,Undervattensbländning Intensitet,Sualtı Karışım Yoğunluğu, +Sky render mode,DSPLYMNU_SKYMODE,,,,Režim vykreslování oblohy,Himmel-renderingstilstand,Rendermodus für Himmel,,Ĉielo-bildigo-reĝimo,Modo de renderizado del cielo,,Taivaan hahmonnustila,Mode du rendu du Ciel,Égbolt render mód,Modalità resa grafica del cielo,空の表示方法,하늘 표시 모드,Luchtrendermodus,Modus for gjengivelse av himmel,Tryb renderowania nieba,Modo de renderização de céu,,Mod de vizualizare al cerului,Режим обработки неба,Режим рендеринга неба,Läge för rendering av himmel,Gökyüzü oluşturma modu, +Linear skies,DSPLYMNU_LINEARSKY,,,,Lineární obloha,Lineære himmelstrøg,Lineare Himmel,,Linearaj ĉieloj,Cielo lineal,,Lineaariset taivaat,Ciel linéaire,Lineáris égboltok,Cieli lineari,空の歪み,선형 하늘,Lineaire lucht,Lineær himmel,Liniowe niebo,Céus lineares,,Cer rectiliniu,Линейное небо,Линеарна неба,Linjär himmel,Doğrusal gökyüzü, +Fullbright overrides sector color,DSPLYMNU_GZDFULLBRIGHT,,,,Při plném jasu ignorovat barvu sektoru,Ignorer sektorfarve ved fuld lysstyrke,Ignoriere Sektorfarbe bei voller Helligkeit,,Plenbrileco tranpasas sektorkoloron,Brillo máximo anula color del sector,,Täyskirkkaat ohittavat sektorin värin,Fullbright ignore couleur secteur,Fullbright felülírja a szektor szinét,Luce piena sovrappone il colore del settore,明るさ最大時にsector color塗り替え,섹터 색상 최대밝기 우선화,Volledig helderheid overschrijft de sectorkleur,Fullbright overstyrer sektorfarge,Ignoruj kolor sektora przy pełnej jasności,Brilho máximo anula cor de setor,,Luminozitatea maximă suprascrie culoarea sectorului,Полная яркость замещает цвет сектора,Пуно осветљење премошћује боју сектора,Fullbright åsidosätter sektorfärg,Fullbright sektör rengini geçersiz kılar, +Scale fuzz effect,DSPLYMNU_SCALEFUZZ,,,,Škálovat velikost fuzz efektu,Skala fuzz-effekt,Skaliere Fuzz-Effekt,,Skali barblano-efekton,Escala de efecto fuzz,,Skaalaa sumennustehostetta,Scaling de l'effet de bruit,Homályosodás effekt átméretezése,Scala l'effetto di fuzz,ファズエフェクトサイズ,반투명 효과 조정,Schaal fuzz effect,Skala fuzz-effekt,Skalowanie efektu szumu,Escala de efeito difuso,,Putere efect de strălucire,Масштабировать эффект шума,Повечавај шумни ефект,Skala fuzz-effekt,Ölçekli fuzz efekti, +Use fuzz effect,DSPLYMNU_DRAWFUZZ,,,,Typ fuzz efektu,Brug fuzz-effekt,Benutze Fuzz-Effekt,,Uzi barblano-efekton,Usar efecto fuzz,,Käytä sumennustehostetta,Effet de bruit,Homályosodás effekt használata,Usa l'effetto di fuzz,ファズエフェクトを使用,반투명 효과 사용,Gebruik fuzz effect,Bruk fuzz-effekt,Użyj efektu szumu,Usar efeito difuso,,Mod efect de strălucire,Использовать эффект шума,Користи шумни ефект,Använd fuzz-effekt,Fuzz efekti kullanın, +Classic Transparency,DSPLYMNU_OLDTRANS,,,,Klasická průhlednost,Klassisk gennemsigtighed,Klasssische Transparenz,,Klasika Travidebleco,Transparencia clásica,,Perinteinen läpinäkyvyys,Transparence classique,Klasszikus átlátszóság,Trasparenza classica,旧式の透明度,구형 투명도,Klassieke transparantie,Klassisk gjennomsiktighet,Klasyczna Przezroczystość,Transparência Clássica,,Transparență Clasică,Классическая прозрачность,Класична транспарентност,Klassisk genomskinlighet,Klasik Şeffaflık, +Lost Soul translucency,DSPLYMNU_TRANSSOUL,,,,Průhlednost Ztracených duší,Fortabt sjæl-translucens,Transparenz für Verlorene Seelen,,Diafaneco de Perdita Animo,Traslucidez del Alma Errante,,Kadonneiden sielujen läpikuultavuus,Transparence des âmes perdues,Lost soul átlátszóság,Trasparenza anima errante,ロストソウルの透明度,로스트 소울 반투명도,Verloren Ziel doorschijnendheid,Lost Soul gjennomskinnelighet,Przezroczystość Zagubionych Dusz,Translucência da Alma Perdida,Translucidez da Alma Penada,Transparență Suflete Pierdute,Прозрачность потерянных душ,Транспарентност изгубљених душа,Lost Soul-translucens,Kayıp Ruh yarı saydamlığı, +Use fake contrast,DSPLYMNU_FAKECONTRAST,,,,Použít falešný kontrast,Brug falsk kontrast,Benutze falschen Kontrast,,Uzi malveran kontraston,Usar falso contraste,,Käytä tekosävykkyyttä,Faux Contraste,Hamis kontraszt használata,Usa il falso contrasto,フェイクコントラストを使用,가명암 효과 사용,Gebruik vals contrast,Bruk falsk kontrast,Użyj sztuczny kontrast,Usar contraste falso,,Utilizare contrast fals,Имитация контрастного освещения стен,Користи фејк-контраст,Använd falsk kontrast,Sahte kontrast kullanın, +Rocket Trails,DSPLYMNU_ROCKETTRAILS,,,,Kouř raket,Raketspor,Raketenschweife,,Raketospuroj,Rastro de cohetes,,Rakettivanat,Trainées des Roquettes,Rakéta füstnyomok,Scia del razzo,ロケットの軌跡,로켓 추진 효과,Raketsporen,Rakettspor,Wiązki Rakiet,Rastro de foguete,Rasto dos Mísseis,Dâră Rachete,Дымовой след у ракет,Траг дима код ракета,Raketspår,Roket Parkurları, +Blood Type,DSPLYMNU_BLOODTYPE,,,,Druh krve,Blodtype,Blut-Typ,,Sangad-efekto,Sangre chorreando,,Verityyli,Type de particules Sang,Vér fajta,Tipo di sangue,血の種類,혈흔 효과,Bloedtype,Blodtype,Typ Krwi,Tipo de sangue,,Tip efecte sângeroase,Тип крови,Тип крви,Blodtyp,Kan Grubu, +Bullet Puff Type,DSPLYMNU_PUFFTYPE,,,,Druh kouře nábojů,Kuglestød type,Pistolenrauch-Typ,,Pulvo pro kolizio de kuglo,Polvo por impacto de bala,,Luotien pöllähdystyyli,Type de particules Balles,Lövedék becsapódás fajtája,Tipo di sbuffo del proiettile,弾煙の種類,탄알 피격 효과,Kogelwolvertype,Bullet Puff Type,Typ Dymu,Tipo de ricochete de bala,,Tip efecte pentru gloanțe,Тип дыма от пуль,Тип рикошета,Kulavfallstyp,Mermi Puf Tipi, +Number of particles,DSPLYMNU_MAXPARTICLES,,,,Množství částic,Antal partikler,Anzahl Partikel,,Nombro da partikloj,Número de partículas,,Hiukkasten lukumäärä,Nombre de particules,Részecskék száma,Numero di particelle,パーティクルの最大数,최대 입자 수,Aantal deeltjes,Antall partikler,Liczba cząsteczek,Número de partículas,,Număr particule,Количество частиц,Број честица,Antal partiklar,Parçacık sayısı, +Number of decals,DSPLYMNU_MAXDECALS,,,,Množství decalů,Antal decals,Anzahl Trefferspuren,,Nombro da dekaloj,Número de calcomanías,,Siirtokuvien lukumäärä,Number de décalques,Lövésnyomok száma,Numero di decal,デカールの最大数,최대 데칼 수,Aantal stickers,Antall dekaler,Liczba kalk,Número de decalques,,Număr autocolante,Количество декалей,Број декала,Antal dekaler,Çıkartma sayısı, +Show player sprites,DSPLYMNU_PLAYERSPRITES,,,,Zobrazit hráčovy sprity,Vis spiller sprites,Zeige Spieler-Sprites,,Montri ludanto-rastrumojn,Mostrar «sprites» del jugador,,Näytä pelaajaspritet,Montrer les sprites joueur,Játékos sprite-ok mutatása,Mostra gli sprite del giocatore,プレイヤーの武器の表示,1인칭 무기 표시,Toon speler sprites,Vis spillerens sprites,Pokaż sprite'y gracza,Exibir sprites do jogador,,Afișare arme,Отображение спрайтов игрока,Прикажи спрајтове играча,Visa spelarens sprites,Oyuncu sprite'larını göster, +Death camera,DSPLYMNU_DEATHCAM,,,,Posmrtná kamera,Dødskamera,Todeskamera,,Dummorta tripersona kamerao,Muerte del jugador en tercera persona,,Kuolonkamera,Caméra 3ème pers à la mort,Halál kamera,Telecamera all'atto della morte,死亡時の三人称視点,사망 화면 표시,Doodscamera,Dødskamera,Kamera śmierci,Câmera de morte,Câmara da morte,Cameră de Deces,Вид от 3-го лица при смерти,Смртна камера,Dödskamera,Ölüm kamerası, +Teleporter zoom,DSPLYMNU_TELEZOOM,,,,Zoom při teleportaci,Teleporter zoom,Teleporter Zoom,,Teleportila zomo,Zoom en teletransporte,,Kaukosiirrynnän kameran zoomaus ,Zoom sur téléportation,Teleporter ráközelítés,Zoom telecamera,テレポーター使用時のズーム,순간이동 효과,Teleporter zoom,Teleporter zoom,Przybliżenie teleportowania,Zoom de teletransporte,,Apropriere Cameră la Teleportare,Увеличение при телепортации,Зум током телепортације,Teleportörens zoom,Işınlayıcı yakınlaştırma, +Earthquake shake intensity,DSPLYMNU_QUAKEINTENSITY,,,,Intenzita zemětřesení,Intensitet af jordskælv,Erdbeben Intensität,,Egeco de tertremo,Intensidad del terremoto,,Maanjäristystehosteen voimakkuus,Intensité des séismes,Földrengés erőssége,Intensità vibrazione terremoto,地震エフェクトの激しさ,지진 효과 강도,Aardbevingsschoksintensiteit,Intensitet av jordskjelvrystelser,Siła trzęsienia ziemi,Intensidade do tremor de terremoto,,Intensitate zguduire la cutremur,Интенсивность тряски землетрясений,Интенсивност земљотреса,Intensitet av jordbävningar,Deprem sarsıntı şiddeti, +Interpolate monster movement,DSPLYMNU_NOMONSTERINTERPOLATION,,,,Interpolovat pohyb příšer,Interpolere monsterbevægelse,Interpoliere Monsterbewegung,,Interpoli monstro-movadon,Interpolar movimiento de los monstruos,,Interpoloi hirviöiden liike,Interpolation des monstres,Szörny mozgás simítása,Interpola il movimento dei mostri,モンスターの移動補間,개체 이동 보정,Interpoleer monsterbewegingen,Interpolere monsterbevegelse,Interpolacja ruchu potworów,Interpolar movimento de monstros,,Interpolare mișcare monștri (efect vizual),Сглаживание движения монстров,Интерполирај кретање чудовишта,Interpolera monsterrörelse,Canavar hareketini enterpole et, +Menu dim,DSPLYMNU_MENUDIM,,,,Síla barvy pozadí v menu,Menu dæmpes,Menüabdunklung,,Menuo-malheleco,Atenuación del menú,,Valikon himmennys,Assombrissement menu,Menü homályosítása,Offuscamento menu,メニュー背景,메뉴 배경색 강도,Donkere menuachtergrond,Demp meny,Mgła w menu,Atenuação do menu,,Întunecare meniu,Затемнение фона меню,Пригушивање менија,Dimma menyn,Menü loş, +Dim color,DSPLYMNU_DIMCOLOR,,,Dim colour,Barva pozadí v menu,Dim farve,Abdunklungsfarbe,,Malheleca koloro,Color de la atenuación,,Himmennysväri,Couleur de l'assombrissement,Homályosítás színe,Colore offuscamento,背景色,배경색 설정,Donkere kleur,Demp farge,Kolor mgły,Cor da atenuação,,Culoare întunecare,Цвет затемнения,Боја пригушивања,Dimma färgen,Loş renk, +View bob amount while moving,DSPLYMNU_MOVEBOB,,,,Pohupování pohledu při pohybu,Vis bob-beløb under bevægelse,Waffenpendeln beim Bewegen,,Vidi kvanton de kapo-balanciĝo dum movado,Cantidad de balanceo al moverse,,Aseen heilumisvoimakkuus liikkeessä,Chaloupage arme en movement,Fegyver mozgása lépés közben,Ammontare di bob di movimento,視点揺れする移動値,이동 시 화면 흔들림 강도,Bekijk bob bedrag terwijl je beweegt,Vis bob-beløp mens du beveger deg,Dygaj kiedy się ruszasz,Quantidade de balanço durante movimento,,Mișcare cameră în timpul deplasării,Покачивание камеры при движении,Тресење камере током кретања,Visa bob-mängden under förflyttning,Hareket halindeyken bob miktarını görüntüleme, +View bob amount while not moving,DSPLYMNU_STILLBOB,,,,Pohupování pohledu v klidu,"Vis bob-beløbet, mens du ikke bevæger dig",Waffenpendeln bei Nichtbewegen,,Vidi kvanton de kapo-balanciĝo dum ne movado,Cantidad de balanceo al no moverse,,Aseen heilumisvoimakkuus levossa,Chaloupage arme statique,Fegyver mozgása egy helyben,Ammontare di bob di movimento da fermo,視点揺れしない移動値,정지 시 화면 움직임 강도,Bekijk bob bedrag terwijl je niet beweegt,Vis bobmengde mens du ikke beveger deg,Dygaj kiedy się nie ruszasz,Quantidade de balanço parado,,Mișcare cameră în timpul staționării,Покачивание камеры при бездействии,Тресење камере током неактивности,Visa bob-mängden när den inte rör sig,Hareket etmiyorken bob miktarını görüntüleme, +Weapon bob speed,DSPLYMNU_BOBSPEED,,,,Rychlost pohupování zbraně,Våben bob hastighed,Waffenpendelgeschwindigkeit,,Rapido de armilo-balanciĝo,Velocidad de balanceo de Arma,,Aseen heilumisnopeus,Vitesse du chaloupage,Fegyver mozgás sebesség,Velocità di bob dell'arma,武器揺れ速度,무기 흔들림 속도,Snelheid wapenzwaaieffect,Våpen bob hastighet,Szybkość ruchu broni,Velocidade de balanço de arma,,Viteză mișcare arme,Скорость покачивания оружия,Брзина трсења оружја,Vapens hastighet,Silah bob hızı, +,,Scaling,,,,,,,,,,,,,,,,,,,,,,,,,, +Scaling Options,SCALEMNU_TITLE,,,,Nastavení škálování rozhraní,Indstillinger for skalering,Skalierungsoptionen,,Skalo-Agordoj,Opciones de escalado,,Skaalausasetukset,Option de mise à l'échelle,Méretezési Beállítások,Opzioni di scala,スケーリング オプション,배율 설정,Schaalopties,Alternativer for skalering,Opcje skalowania,Opções de escala,,Setări Dimensiuni,Настройки масштабирования,Подешавања размере,Skalningsalternativ,Ölçeklendirme Seçenekleri, +Overrides for above setting,SCALEMNU_OVERRIDE,,,,Potlačení nastavení výše,Overrides for ovenstående indstilling,Spezialisierungen,,Transpasoj por ĉi-supre agordo,Anular ajuste anterior,,Ohittaa asetuksen ylhäällä,Annule les paramètres au dessus,Beállítások felülírása,Sovrascritture per i settaggi sopra,設定の上書き,위 설정을 위해 무시,Overschrijdingen voor bovenstaande instelling,Overstyrer for innstillingen ovenfor,Nadpisuje dla powyższego ustawienia,Anular configurações acima,,Suprascriere pentru setările de mai sus,Задать специальные настройки,Специјална подешавања,Överordnar ovanstående inställningar,Yukarıdaki ayar için geçersiz kılmalar, +Messages,SCALEMNU_MESSAGES,,,,Oznámení,Meddelelser,Nachrichten,,Mesaĝoj,Mensajes,,Viestit,,Üzenetek,Messaggi,メッセージ類,메시지,Berichten,Meldinger,Wiadomości,Mensagens,,Mesaje,Сообщения,Поруке,Meddelanden,Mesajlar, +Console,SCALEMNU_CONSOLE,,,,Konzole,Konsol,Konsole,,Konzolo,Consola,,Konsoli,,Konzol,,コンソール,콘솔,,Konsoll,Konsola,,Consola,Consolă,Консоль,Конзола,Konsol,Konsol, +Status bar,SCALEMNU_STATBAR,,,,Stavový panel,Statuslinje,Statusleiste,,Stata baro,Barra de estado,,Tilapalkki,Barre d'état,Státusz sáv,Barra di stato,ステータスバー,상태 바,Statusbalk,Statuslinje,Pasek statusu,Barra de status,Barra de estado,Bară de Stare,Строка состояния,Статусна трака,Statusfältet,Durum çubuğu, +Fullscreen HUD,SCALEMNU_HUD,,,,HUD přes celou obrazovku,HUD i fuld skærm,Vollbild-HUD,,Tutekrana HUD,HUD de pantalla completa,,Täyden ruudun tilanäyttö,ATH plein écran,Teljes képernyős HUD,HUD a pieno schermo,全画面HUD,전체화면 HUD,Volle scherm HUD,HUD i fullskjerm,HUD pełnoekranowy,HUD de tela cheia,HUD de ecrã cheio,Interfață pe Timp de Joc tip Fullscreen,Полноэкранный интерфейс,HUD преко целог екрана,HUD i fullskärm,Tam Ekran HUD, +Alternative HUD,SCALEMNU_ALTHUD,,,,Alternativní HUD,Alternativ HUD,Alternatives HUD,,Alternativa HUD,HUD alternativo,,Vaihtoehtoinen tilanäyttö,ATH alternatif,Alternatív HUD,HUD alternativo,オルタナティブHUD,대체 HUD,Alternatieve HUD,Alternativ HUD,Alternatywny HUD,HUD alternativo,,Interfață pe Timp de Joc Alternativă,Альтернативный интерфейс,Алтернативни HUD,Alternativ HUD,Alternatif HUD, +HUD preserves aspect ratio,SCALEMNU_HUDASPECT,,,,HUD zachovává poměr stran,HUD bevarer formatforholdet,HUD bewahrt Seitenverhältnisse,,HUD konservas aspekto-proporcion,HUD conserva la rel. de aspecto,,Tilanäyttö säilyttää kuvasuhteen,ATH préserve le rapport d'aspect,A HUD képarány visszaállítása,HUD preserva le proporzioni,HUDのアスペクト比維持,HUD 화면 비율 보존,HUD behoudt de beeldverhouding,HUD bevarer størrelsesforholdet,HUD zachowuje współczynnik proporcji,HUD deve preservar proporção da tela,,Interfața pe Timp de Joc își Păstrează Aspectul,Сохранение соотношения сторон интерфейса,Сачувај пропорције HUD-а,HUD behåller bildförhållandet,HUD en boy oranını korur, +Use default scale,SCALEMNU_USEUI,,,,Použít výchozí velikost,Brug standardskala,Benutze Standardskalierung,,Uzi defaŭltskalon,Usar escalado por defecto,,Käytä oletusmittakaavaa,Défaut,Alap arányok használata,Usa la scala di default,通常サイズを使う,기본 배율 사용,Gebruik standaardweegschaal,Bruk standard skala,Użyj domyślnej skali,Usar escala padrão,,Folosește dimensiunea implicită,Размер по умолчанию,Уобичајена размера,Använder standardskalan,Varsayılan ölçeği kullan, +Scale to fullscreen,SCALEMNU_USEFS,,,,Škalovat přes celou obrazovku,Skaleres til fuld skærm,Skaliere auf Vollbild,,Skali al tutekrano,Escalar a pant. completa,,Skaalaa täyteen ruutuun,Plein écran,Teljes képernyőre arányítás,Scala a pieno schermo,全画面に拡大,전체화면에 맞게 축척,Schaalbaar tot volledig scherm,Skaler til fullskjerm,Przeskaluj do pełnego ekranu,Escala de tela cheia,Escalar para ecrã cheio,Dimensionare la modul Fullscreen,Масштабировать со всем экраном,Проширење преко целог екрана,Skala till fullskärm,Tam ekrana ölçeklendir, +Adapt to screen size,SCALEMNU_ADAPT,,,,Přizpůsobit velikosti obrazovky,Tilpasning til skærmstørrelse,Passe an Bildschirmgröße an,,Adapti al ekranamplekso,Adaptar al tamaño de pantalla,,Sovita näytön kokoon,Ecran,Képernyő mérethez alkalmazkodik,Adatta alla dimensione della schermata,画面サイズに合わせる,화면 사이즈에 맞게 축척,Aanpassen aan de grootte van het scherm,Tilpass til skjermstørrelse,Dostosuj do pełnego ekranu,Adaptar ao tamanho de tela,,Adaptează la dimensiunea ecranului,Адаптироваться к размеру экрана,Прилагоди размери екрана,Anpassas till skärmstorlek,Ekran boyutuna uyum sağlayın, +,,HUD,,,,,,,,,,,,,,,,,,,,,,,,,, +HUD Options,HUDMNU_TITLE,,,,Nastavení rozhraní a HUD,HUD-indstillinger,HUD Optionen,,HUD Agordoj,Opciones del HUD,,Tilanäytön asetukset,Options ATH,HUD beállításai,Opzioni HUD,HUDオプション,HUD 설정,HUD-opties,HUD-alternativer,Opcje HUD,Opções de HUD,,Setări Interfață pe Timp de Joc,Настройки отображения информации,HUD подешавања,Alternativ för HUD,HUD Seçenekleri, +Alternative HUD,HUDMNU_ALTHUD,,,,Alternativní HUD,Alternativ HUD,Alternatives HUD,,Alternativa HUD,HUD alternativo,,Vaihtoehtoinen tilanäyttö,ATH Alternatif,Alternatív HUD,HUD alternativo,オルタナティブHUD,대체 HUD,Alternatieve HUD,Alternativ HUD,Alternatywny HUD,HUD alternativo,,Interfață pe Timp de Joc Alternativă,Альтернативное отображение информации,Алтернативни HUD,Alternativ HUD,Alternatif HUD, +Message Options,HUDMNU_MESSAGE,,,,Oznámení,Indstillinger for meddelelser,Nachrichtenoptionen,,Mesaĝo-Agordoj,Opciones de mensajes,,Viestiasetukset,Options des Messages,Üzenet beállítások,Opzioni messaggi,メッセージの設定,메시지 설정,Berichtopties,Meldingsalternativer,Opcje wiadomości,Opções de mensagem,,Setări Mesaje,Настройки сообщений,Подешавања порука,Alternativ för meddelanden,Mesaj Seçenekleri, +User interface scale,HUDMNU_UISCALE,,,,Velikost rozhraní,Skala for brugergrænseflade,Benutzerinterfaceskalierung,,Interfaco-skalo de uzanto,Escala de la interfaz de usuario,,Käyttöliittymän skaalaus,Echelle de l'interface,Felhasználó Panel mérete,Scala l'interfaccia utente,インターフェースの大きさ,인터페이스 크기 조정,Schaal gebruikersinterface,Skalering av brukergrensesnitt,Skala interfejsu,Escala de interface de usuário,Escala de interface do utilizador,Dimensiune Interfață Utilizator,Размер интерфейса,Размера интерфејса,Skala för användargränssnittet,Kullanıcı arayüzü ölçeği, +Force default crosshair,HUDMNU_FORCECROSSHAIR,,,,Vynutit výchozí zaměřovač,Tvinge standard-trådkorset,Erzwinge Standard-Fadenkreuz,,Devigi defaŭltan reteton,Forzar retícula por defecto,,Pakota oletustähtäin,Forcer Viseur par défaut,Alapcélkereszt erőltetése,Forza il mirino di default,デフォルトの照準を使う,기본 조준점 강제 설정,Forceer standaard dradenkruis,Tving frem standard trådkors,Wymuś domyślny celownik,Forçar mira padrão,,Forțare țintă implicită,Всегда стандартный прицел,Форсирај уобичајени нишан,Forcera standardkorset,Varsayılan artı işaretini zorla, +Grow crosshair when picking up items,HUDMNU_GROWCROSSHAIR,,,,Zvětšit zaměřovač při sebrání předmětu,"Vokse trådkorset, når du samler genstande op",Größeres Fadenkreuz bei Gegenstandsaufnahme,,Grandigi reteton kiam oni prenas objektojn,Aumentar retícula al obtener obj.,Crecer retícula al obtener obj.,Suurenna tähtäintä esineitä poimiessa,Agrandir viseur en prenant un objet,A célkereszt nőjön tárgyfelvételkor,Accresci il mirino quando si raccolgono oggetti,アイテム取得時に照準を大きくする,아이템 획득 시 조준점 키우기 ,Vergroot het dradenkruis bij het oppakken van items,Utvid trådkorset når du plukker opp elementer,"Powiększ celownik, gdy podnosisz przedmioty",Aumentar mira ao pegar itens,Aumentar mira ao apanhar itens,Mărește ținta la ridicarea obiectelor,Увеличение прицела при подборе,Побољшај нишан током купљења предмета,Växer hårkorset när du plockar upp föremål,Eşyaları alırken artı işaretini büyütün, +Display nametags,HUDMNU_NAMETAGS,,,,Zobrazovat jmenovky,Viser navneskilte,Zeige Gegenstandsnamen,,Montri nometikedojn,Mostrar etiquetas,,Näytä nimitunnisteet,Afficher noms des objets,Névtábla mutatása,Mostra le targhette identificative,ディスプレイネームタグ,이름표 표시,Naamlabels weergeven,Vis navnelapper,Pokazuj nazwy przedmiotów,Exibir nomes,,Indică numele obiectelor,Указание названия предметов,Прикажи имена предмета,Visa namnbrickor,İsim etiketlerini gösterin, +Nametag color,HUDMNU_NAMETAGCOLOR,,,Nametag colour,Barva jmenovek,Farve på navneskilte,Farbe für Gegenstandsnamen,,Nometikeda koloro,Color de las etiquetas,,Nimitunnisteen väri,Couleur des noms d'objet,Névtábla szín,Colore targhetta identificativa,ネームタグ色,이름표 색깔,Kleur naamlabel,Farge på navneskilt,Kolor nazw przedmiotów,Cor dos nomes,,Culoare nume obiecte,Цвет названия предметов,Боја имена предмета,Färg på namnbrickor,İsim etiketi rengi, +Use old ouch mug shot formula,HUDMNU_OLDOUCH,,,,Použít starý vzorec pro 'ouch' portrét,"Gammel formel for ""av"" ansigt",Alte Formel für „Autsch“-Gesicht,,Uzi maljunan formulon de aj-vizaĝo-foto,Usar formula antigua de foto de daño,,Käytä vanhaa auts-naamakuvan kaavaa,Ancien code pour l' « ouch face »,Régi sebződő fej formula használata,Mostra la formula originale del viso 'ouch',旧式ouch mug shotを使用,구형 피격 표정 스프라이트 방식 사용,"Oude formule voor ""Ouch""-gezicht",Bruk formelen for gamle forbryterbilder,Używaj starej formuły twarzy przy dostaniu obrażeń,Usar fórmula original do rosto de dor,,Utilizează modul portret vechi,Старая формула для портрета,Стара формула за приказ лика,"Använd den gamla formeln med ""ouch"" foton",Eski ouch oyuncu yüzü formülünü kullanın, +Hexen weapon flashes,HUDMNU_HEXENFLASHES,,,,Druh bliknutí zbraní v Hexenu,Hexen-våben blinker,Hexen-Waffenblitze,,Ekbriloj de Hexen-armo,Destello armas Hexen,,Hexenin asevälähdykset,Flash d'arme dans Hexen,Hexen fegyver villanások,Bagliori armi Hexen,Hexen武器の視界色,헥센 무기 반짝임,Hexen-wapen flitsen,Hexen våpen blinker,Błysk przy podnoszeniu broni z Hexena,Flash de arma do Hexen,,Tip strălucire arme Hexen,Тип вспышки оружия в Hexen,Треперење оружја у Hexen-у,Hexen-vapen blinkar,Hexen silah flaşları, +Poison damage flashes,HUDMNU_POISONFLASHES,,,,Druh bliknutí při otrávení,Giftskabte skader blinker,Gift-Effekt,,Ekbriloj de venondamaĝo,Destello daño por veneno,,Myrkkyvahinkovälähdykset,Flash de poison dans Hexen,Méreg sebzés villanások,Bagliori danno da veleno,毒ダメージの視界色,독데미지 반짝임,Vergiftigingsschade knippert,Giftskade blinker,Efekt obrażeń przy zatruciu,Flash de dano por veneno,,Tip strălucire efect de otrăvire,Тип вспышки яда,Треперење током тровања,Blinkar för giftskador,Zehir hasarı flaşları, +Ice death flashes,HUDMNU_ICEFLASHES,,,,Druh bliknutí při smrti umrznutím,Isdødsblink,Eis-Tod-Effekt,,Ekbriloj de glacimorto,Destello muerte por hielo,,Jääkuolemavälähdykset,Flash de morts par glace,Jéghalál villanások,Bagliori morte da ghiaccio,氷結死の視界色,동사시 반짝임,IJsdood knippert,Isdød blinker,Błysk przy śmierci poprzez zamrożenie,Flash de morte por congelamento,,Tip strălucire deces prin înghețare,Тип вспышки при смерти от льда,Треперење током смрти од леда,Blinkar för isdöd,Buz ölüm flaşları, +Poison Buildup flashes,HUDMNU_HAZARDFLASHES,,,,Druh blikání při kumulaci jedu,Gift Buildup blinker,Kumulativer Gift-Effekt,,Ekbriloj de venonamasigo,Destello acumulación de veneno,,Myrkyn kertymisvälähdykset,Flash d'accumulation de poison,Fokozatos méreg sebzés villanások,Bagliori danno accumulato da veleno,蓄積毒の視界色,독데미지 반짝임 증강,Vergiftiging Opbouw knippert,Giftoppbygging blinker,Miganie przy nasilaniu się trucizny,Flash por acúmulo de dano por veneno,,Tip strălucire acumulare de otravă,Тип вспышки при скоплении яда,Треперење током гомилања отрова,Blinkningar för giftuppbyggnad,Zehir Birikimi yanıp söner, +Scaling Options,HUDMNU_SCALEOPT,,,,Škálování velikosti rozhraní,Skaleringsmuligheder,Skalierungsoptionen,,Skalo-Agordoj,Opciones de escalado,,Skaalausasetukset,Option de mise à l'échelle,Méretezés Beállítások,Opzioni di scala,スケーリング オプション,배율 설정,Schaalopties,Alternativer for skalering,Opcje skalowania,Opções de escala,,Setări Dimensiuni,Настройки масштабирования,Подешавања размере,Alternativ för skalning,Ölçeklendirme Seçenekleri, +Show IWAD selection dialog,MISCMNU_QUERYIWAD,,,,Zobrazit dialog pro výběr IWADu,Vis IWAD-valgdialogboks,Zeige IWAD-Auswahl,,Montri elektodialogon de IWAD,Mostrar diálogo de selección de IWAD,,Näytä IWAD-valintaikkuna,Afficher la séléction d'IWAD,IWAD kiválasztó ablak mutatása,Mostra la schermata della selezione IWAD,IWADの選択画面を表示,IWAD 게임 선택창 표시,IWAD-selectiedialoogvenster weergeven,Vis IWAD-valgdialogboks,Pokaż ekran wyboru gry (IWAD),Exibir janela de seleção de IWAD,,Afișează fereastra de selectare a jocurilor,Выбор IWAD-файла при запуске,Покажи IWAD дијалог за избор,Visa dialogrutan för val av IWAD,IWAD seçim iletişim kutusunu göster, +Enable cheats from all games,MISCMNU_ALLCHEATS,,,,Povolit cheaty ze všech her,Aktiver snyderier fra alle spil,Ermögliche Cheats aus allen Spielen,,Ebligi trompojn el tutaj ludoj,Activar trucos de todos los juegos,,Ota käyttöön huijauskoodit kaikista peleistä,Activer cheats de tous les jeux,Minden játék csaláskódja érvényes,Abilita tutti i cheat da tutti i giochi,全ゲームでチート使用可にする,모든 게임에 치트 허용,Laat bedriegers van alle spellen toe,Aktiver juks fra alle spill,Włącz oszustwa ze wszystkich gier,Habilitar trapaças de todos os jogos,Permitir batotas de todos os jogos,Permite codurile din toate jocurile,Читы из всех игр,Омогући читове од свих игара,Aktivera fusk från alla spel,Tüm oyunlardan hileleri etkinleştirin, +,,Option Menus,,,,,,,,,,,,,,,,,,,,,,,,,, +Enable making screenshots by scripts,MISCMNU_ENABLESCRIPTSCREENSHOTS,,,,Povolit skriptům pořizovat snímky obrazovky,Aktivering af skærmbilleder ved hjælp af scripts,"Erlaube Skripts, Screenshots zu machen",,Ebligi faradon de ekrankopioj per skriptoj,Habilitar captura de pantalla por scripts,,Salli komentosarjoin otetut kuvakaappaukset,Autoriser les Scripts à prendre des captures,Szkriptek is készíthetnek képernyőképet,Abilita la cattura dello schermo tramite scripts,スクリプトからのスクショ作成を有効化,저장/불러오기 확인,Screenshots maken met behulp van scripts,Gjør det mulig å lage skjermbilder av skript,Pozwól na robienie zrzutów ekranu przez skrypty,Habilitar capturas de tela por scripts,Permitir capturas de ecrã por scripts,Posibilitate de a face poze prin scripturi,Возможность делать снимки экрана через скрипты,Омогући прављење скриншотова по скрипти,Aktivera att göra skärmdumpar med hjälp av skript,Komut dosyalarıyla ekran görüntüsü almayı etkinleştirme, +Load *.deh/*.bex lumps,MISCMNU_DEHLOAD,,,,Načítat *.deh/*.bex soubory,Indlæsning af *.deh/*.bex-filer,Lade *.deh/*.bex Daten,,Ŝargi je *.deh/*.bex lumpoj,Cargar archivos *.deh/*.bex,,Lataa *.deh/*.bex-lump-tiedostot,Charger fichiers *.deh/*.bex,*.deh/*.bex lump-ok betöltése,Carica i lump *.deh/*.bex,.deh/.bexファイルを読み込む,*.deh/*.bex 럼프 파일 불러오기,*.deh/*.bex laden,Last inn *.deh/*.bex-arkiver,Załaduj dane *.deh/*.bex,Carregar lumps *.deh/*.bex,,Încarcă nodurile *.deh/*.bex,Загружать файлы *.deh/*.bex,Учитај *.deh/*.bex фајлове,Ladda *.deh/*.bex-filer,.deh/*.bex topaklarını yükle, +Cache nodes,MISCMNU_CACHENODES,,,,Cachovat nodes,,Nodes zwischenspeichern,,Kaŝmemoraj nodoj,Caché de nodos,,Tallenna solmut välimuistiin,Mise en cache des nodes,Node-ok cache-lése,Cache dei nodi,ノードキャッシュ,캐시 노드,Cache nodes,Bufre noder,Węzły pamięci podręcznej,Cachê de nodes,Cache de nodes,Depozitare noduri cache,Кэширование узлов,Кеширани чворови,Cache-noder,Önbellek düğümleri, +Time threshold for node caching,MISCMNU_CACHETIME,,,,Časový práh pro cachování nodes,Tidsgrænse for node-cache,Zeitschwelle für das Zwischenspeichern von Nodes,,Templimo pro kaŝmemornodi,Umbral de tiempo para caché de nodos,,Kynnysaika solmujen välimuistitallennukseen,Limite cache des nodes,Időhatár node cache-hez,Soglia di tempo per il caching dei nodi,ノードキャッシュ時間の閾値,노드 캐싱을 위한 시간 임계값 계산,Tijdsdrempel voor het cachen van nodes,Tidsterskel for nodebufring,Próg czasowy buforowania węzłów,Limite de tempo para cachê de nodes,Limite de tempo para cache de nodes,Limită de timp pentru depozitare cache,Временной порог для кэширования узлов,Временски праг за кеширање чвора,Tidströskel för cachelagring av noder,Düğüm önbelleğe alma için zaman eşiği, +Clear node cache,MISCMNU_CLEARNODECACHE,,,,Vyčistit node cache,Ryd node-cache,Nodespeicher löschen,,Forigi kaŝmemorajn nodojn,Limpiar Caché de nodos,,Tyhjennä solmuvälimuisti,Vider le cache des nodes,Cache node ürítése,Pulisci la cache dei nodi,ノードのキャッシュをクリア,노드 캐시를 삭제,Node cache legen,Tøm nodebuffer,Wyczyść pamięć podręczną,Limpar cachê de nodes,Limpar cache de nodes,Ștergere noduri cache,Очистить кэш узлов,"Избриши кеширане чворове +",Rensa nodcache,Düğüm önbelleğini temizle, +Allow skipping of intermission scrollers,MISCMNU_INTERSCROLL,,,,Povolit přeskakování skrolujících obrázků,Tillad at springe over pausescrollere,Erlaube Überspringen von Intermission-Scrollern,,Permesi preterpason de intermitaj rulumoj,Permitir omisión de intermedios,,Salli vierivien väliruutujen ohittaminen,Sauter compteurs d'intermission,Pályaközi szünetek átugorhatóak,Consenti di saltare gli scorrimenti delle intermissioni,クリア結果集計のスキップを許可,인터미션 스크롤러 생략 허용,Overslaan van intermissiescrollers toestaan,Tillat å hoppe over pauserullere,Pozwól na pominięcie wstawek,Pular telas de intervalo entre fases,Saltar ecrãs de intervalo entre níveis,Permite saltul peste inserările de text,Разрешение пропуска текстовых вставок,Дозволи прескакање прелаза са текстовима,Tillåt att hoppa över rullgardiner för pauslägen.,Ara kaydırıcıların atlanmasına izin ver, +Network Options,NETMNU_TITLE,,,,Nastavení sítě,Netværksindstillinger,Netzwerkeinstellungen,,Reta Agordoj,Opciones de Red,,Verkkoasetukset,Options Réseau,Hálózati Beállítások,Opzioni network,ネットワーク オプション,네트워크 설정,Netwerkopties,Nettverksalternativer,Opcje Sieci,Opções de Rede,,Setări de Rețea,Настройки сети,Мрежна подешавања,Nätverksalternativ,Ağ Seçenekleri, +Local options,NETMNU_LOCALOPTIONS,,,,Lokální nastavení,Lokale indstillinger,Lokale Einstellungen,,Lokaj agordoj,Opciones locales,,Paikallisasetukset,Options Locales,Helyi beállítások,Opzioni locali,ローカル オプション,로컬 설정,Lokale opties,Lokale alternativer,Opcje Lokalne,Opções locais,,Setări Locale,Локальные настройки,Локална подешавања,Lokala alternativ,Yerel seçenekler, +Movement prediction,NETMNU_MOVEPREDICTION,,,,Predikce pohybu,Forudsigelse af bevægelser,Bewegungsvorausberechnung,,Movprognozado,Predicción de Movimiento,,Liikkeen ennakoiminen,Prédiction de Mouvement,Mozgás előrejelzés,Predizione movimenti,移動予測,움직임 예측도,Voorspelling van bewegingen,Forutsigelse av bevegelse,Przewidywanie Ruchu,Previsão de movimento,,Anticipare mișcare,Предсказание движения,Предвиђање покрета,Förutsägelse av rörelser,Hareket tahmini, +Predict line actions,NETMNU_LINESPECIALPREDICTION,,,,Predikce čárových akcí,Forudsige linjehandlinger,Berechne Linienaktionen voraus,,Prognozi linio-agojn,Predecir acciones de línea,,Ennakoi viivasuorat toiminnat,Prédiction des actions de ligne,Előrejelzés vonal művelet,Predizione azioni di linea,line actionsを予測する,라인 움직임 감지,Voorspel lijnacties,Forutsi linjehandlinger,Przewidź akcje linii,Prever ações de linha,,Anticipează acționarea liniilor,Предсказание действий на уровне,Предвиђање линијске радње,Förutsägelse av linjeåtgärder,Hat eylemlerini tahmin edin, +Prediction Lerp Scale,NETMNU_PREDICTIONLERPSCALE,,,,Velikost interpolace predikce,Forudsigelse Lerp-skala,Vorberechnungs Lerp-Skalierung,,Skalo de Linia Lnterpolado,Escala de interp. lineal de predicción,,Lineaarisen interpolaatioennakoinnin skaalaus,Prédiction d'échelle LERP,Előrejelzés LERP Arány,Scala Lerp predizione,リープスケール予測,러프 예측 강도,Voorspelling Lerp Scale,Prediksjon Lerp-skala,Przewidywanie Skali Lerp,Escala de previsão de LERP,,Anticipare scară lerp,Предсказание увеличения доп. задержки,Предвиђање лерп скале,Förutsägelse Lerp Scale,Tahmin Lerp Ölçeği, +Lerp Threshold,NETMNU_LERPTHRESHOLD,,,,Práh interpolace,Lerp-tærskel,Lerp-Schwellwert,,Limito de Linia Interpolado,Umbral de interp. lineal,,Interpolaatiokynnys,Limite LERP,LERP küszöbérték,Soglia Lerp,リープしきい値,러프 계산,Lerp Threshold,Lerp-terskel,Próg Lerp,Limite de LERP,,Prag Lerp,Порог доп. задержки,Лерп праг,Lerp Tröskelvärde,Lerp Eşiği, +Host options,NETMNU_HOSTOPTIONS,,,,Nastavení hostitele,Værtsindstillinger,Gastoptionen,,Agordoj de Gastiganto,Opciones de Host,,Isäntäasetukset,Options Hôte,Host beállítások,Opzioni ospitante,ホスト オプション,호스트 설정,Verhuurders opties,Vertsalternativer,Opcje hosta,Opções de host,,Setări gazdă,Настройки сервера,Подешавања домаћина,Alternativ för värdar,Ev sahibi seçenekleri, +Extra Tics,NETMNU_EXTRATICS,,,,Extra tiky,Ekstra tics,,,Ekstraj Tikoj,Tics Extra,,Lisäticit,Tics supplémentaires,Extra Tic-ek,Tics extra,予備秒数,추가 틱,,Ekstra tics,Dodatkowe tiki,Tics extras,,Ticăituri suplimentare,Дополнительные секунды,Додатни тикови,Extra tics,Ekstra Tikler, +Latency balancing,NETMNU_TICBALANCE,,,,Vyrovnání latence,Balancering af latenstid,Latenzbalance,,Respondotempo-balancado,Balanceo de latencia,,Viiveen tasapainoitus,Equilibrage de latence,Válaszidő balanszolás,Bilanciamento latenza,レイテンシーバランス,지연 시간 조정,Latency balans,Balansering av ventetid,Balans czasu oczekiwania,Equilíbrio de latência,,Întârzierea echilibrării,Балансировка задержки,Балансирање кашњења,Balansering av latenstid,Gecikme dengeleme, +Original,OPTVAL_ORIGINAL,,,,Původní,,,,Originala,,,Alkuperäinen,,Eredeti,Originale,オリジナル,원형,Origineel,,Oryginalny,,,,Изначальный,Оригинално,Ursprunglig,Orijinal, +Optimized,OPTVAL_OPTIMIZED,,,,Optimalizovaný,Optimeret,Optimiert,,Optimumigita,Optimizado,,Optimoitu,Optimisé,Optimalizált,Ottimizzato,最適化,최적화 형,Geoptimaliseerd,Optimalisert,Zoptymalizowany,Otimizado,,Optimizat,Оптимизированный,Оптимизовано,Optimerad,Optimize Edilmiş, +Classic (Faster),OPTVAL_CLASSIC,,,,Klasický (rychlejší),Classic (hurtigere),Klassisch (schneller),,Klasika (Pli rapide),Clásico (Más rápido),,Perinteinen (nopeampi),Classique (+ Rapide),Klasszikus (gyorsabb),Classico (più veloce),旧式(速度重視),구형 (빠르게),Klassiek (sneller),Klassisk (raskere),Klasyczny (szybszy),Clássico (Mais rápido),,Clasic (Mai rapid),Классический (быстрее),Класични (бржи),Classic (snabbare),Klasik (Daha Hızlı), +Precise,OPTVAL_PRECISE,,,,Přesný,Præcist,Genau,,Preciza,Preciso,,Tarkka,Précis,Pontos,Preciso,精密,정확하게,Nauwkeurig,Presis,Dokładny,Preciso,,Precis,Точный,Прецизно,Exakt,Kesin, +Capped,OPTVAL_CAPPED,,,,Uzavřený,Begrænset,Limitiert,,Limitigita,Limitado,,Rajoitettu,Limité,Lekorlátozva,Limitato,上限,색상에 맞게,Afgeschermd,Begrenset,Ograniczony,Limitado,,Limitat,Ограниченный,Ограничено,Begränsad,Sınırlı, +Particles,OPTVAL_PARTICLES,,,,Částice,Partikler,Partikel,,Partikloj,Partículas,,Hiukkasina,Particules,Részecskék,Particelle,パーティクル,입자만,Deeltjes,Partikler,Cząstki,Partículas,,Particule,Частицы,Честице,Partiklar,Parçacıklar, +Sprites,OPTVAL_SPRITES,,,,Sprity,,,,Mov-rastrumoj,,,Spriteinä,,Sprite-ok,Sprite,スプライト,스프라이트만,,,Sprite'y,,,Sprite-uri,Спрайты,Спрајтови,,Sprite'lar, +Sprites & Particles,OPTVAL_SPRITESPARTICLES,,,,Sprity a částice,Sprites og partikler,Sprites und Partikel,,Mov-rastrumoj kaj partikloj,Sprites y partículas,,Spriteinä ja hiukkasina,Sprites & Particules,Sprite-ok és részecskék,Sprite e particelle,スプライト & パーティクル,스프라이트+입자,Sprites & Deeltjes,Sprites og partikler,Sprite'y i cząstki,Sprites & Partículas,Sprites e Partículas,Sprite-uri & Particule,Спрайты и частицы,Спрајтови и честице,Sprites och partiklar,Sprite'lar ve Parçacıklar, +Melt,OPTVAL_MELT,,,,Rozpuštění,Smelt,Verlauf,,Fandi,Derretir,,Sulaminen,Fondu,Olvadás,Scioglimento,メルト,녹는 효과,Smelten,Smelte,Stopienie,Derreter,,Topire,Таяние,Топљење,Smält,Eriyik, +Burn,OPTVAL_BURN,,,,Oheň,Brænde,Einbrennen,,Bruli,Quemar,,Palaminen,Brûlure,Égés,Bruciamento,バーン,타는 효과,Verbranden,Brenne,Wypalenie,Queimar,,Ardere,Жжение,Спаљивање,Bränn,Yanmak, +Crossfade,OPTVAL_CROSSFADE,,,,Prolínačka,Crossfade,Überblenden,,Transvelki,Entrelazar,,Ristihäivytys,Fondu en croix,Átvezetés,Dissolvenza a croce,クロスフェード,화면 교차,Crossfade,Overblending,Przenikanie,Dissolver,,Ofilire,Увядание,Вењење,Crossfade,Crossfade, +Smooth,OPTVAL_SMOOTH_1,"This setting is duplicated in order to allow for different grammatical gender endings in the Russian language (and any other language that depends on a grammatical gender system). In English, due to the lack of a grammatical gender system, both option values are the same.",,,Vyhlazený,Glat,Glatt,,Glata,Fluido,,Pehmeä,Lisse,Simítás,Liscio,スムーズ,부드럽게,Glad,Glatt,Gładki,Suavizado,,Fin,Плавная,Глатко,Smidig,Pürüzsüz, +Smooth,OPTVAL_SMOOTH_2,,,,Vyhlazené,Glat,Glatt,,Glata,Fluido,,Pehmeä,Lisse,Simítás,Liscio,スムーズ,부드럽게,Glad,Glatt,Gładka,Suavizado,,Fin,Плавные,Глатко,Smidig,Pürüzsüz, +Translucent,OPTVAL_TRANSLUCENT,,,,Průhledný,Gennemskinnelig,Transparent,,Diafana,Translúcido,,Läpikuultava,Transparent,Áttetsző,Traslucido,半透明,투명하게,Doorschijnend,Gjennomskinnelig,Przeświecający,Translúcido,,Transparent,Полупрозрачный,Прозрачно,Genomskinlig,Yarı Saydam, +Fuzz,OPTVAL_FUZZ,,,,Šum,,Fuzz,,Lanugo,Borroso,,Sumeus,Bruit Blanc,Homályosítás,Annebbiato,ファズ,퍼즈 효과,Fuzz,,Szum,Difuso,,Sclipitor,Шумовой,Фаз,Fuzz,Fuzz, +Shadow,OPTVAL_SHADOW,,,,Stín,Skygge,Schatten,,Ombro,Sombra,,Varjo,Ombre,Árnyék,Ombra,シャドウ,그림자 효과,Schaduw,Skygge,Cień,Sombra,,Umbră,Теневой,Сенка,Skugga,Gölge, +Items,OPTVAL_ITEMS,,,,Předměty,Varer,Gegenstände,,Objektoj,Objetos,,Esineet,Objets,Tárgyak,Oggetti,アイテム,아이템들,Artikelen,Gjenstander,Przedmioty,Itens,,Obiecte,Предметы,Предмет,Artiklar,Eşyalar, +Weapons,OPTVAL_WEAPONS,,,,Zbraně,Våben,Waffen,,Armiloj,Armas,,Aseet,Armes,Fegyverek,Armi,武器,무기들,Wapens,Våpen,Bronie,Armas,,Arme,Оружие,Оружја,Vapen,Silahlar, +Both,OPTVAL_BOTH,,,,Obojí,Begge,Beide,,Ambaŭ,Ambos,,Molemmat,Les Deux,Mindkettő,Entrambi,両方,둘 다,Beide,Begge,Oba,Ambos,,Ambele,Оба,Оба,Båda,Her ikisi de, +ZDoom,OPTVAL_ZDOOM,,,,,,,,,,,,,,,,Z둠,,,,,,,,,,, +Strife,OPTVAL_STRIFE,,,,,,,,,,,,,,,,스트라이프,,,,,,,,,,, +Player,OPTVAL_PLAYER,,,,Hráč,Spiller,Spieler,,Ludanto,Jugador,,Pelaaja,Joueur,Játékos,Giocatore,プレイヤー,플레이어,Speler,Spiller,Gracz,Jogador,,Jucător,Игрок,Играч,Spelare,Oyuncu, +Map,OPTVAL_MAP,,,,Level,Kort,Level,,Mapo,Mapa,,Kartta,Niveau,Pálya,Mappa,マップ,맵,Kaart,Kart,Mapa,Mapa,,Hartă,Карта,Мапа,Karta,Harita, +Scale to 640x400,OPTVAL_SCALETO640X400,,,,Zvětšit na 640x400,Skaleres til 640x400,Skaliere auf 640x400,,Skali al 640x400,Escalar a 640x400,,Skaalaa resoluutioon 640x400,Echelle 640x400,640x480-hoz arányít,Scala a 640x400,640x400スケール,640x400까지 확대,Schaal tot 640x400,Skala til 640x400,Skaluj do 640x400,Escalar para 640x400,,Dimensionare la 640x480,Масштабировать до 640x400,Скалирај на 640x400,Skala till 640x400,640x400'e ölçeklendirin, +Pixel double,OPTVAL_PIXELDOUBLE,,,,Zdvojení pixelů,Pixel dobbelt,Pixelverdopplung,,Bilderon duobligi,Pixel doble,,Kuvapistekaksinkertaistus,,Pixel duplázás,Pixel doppi,ピクセル2倍,2배 픽셀,Pixel dubbel,Dobbel piksel,Dwukrotnie więcej pikseli,Pixel duplo,,Dublare pixeli,Двойные пиксели,Дупли пиксел,Pixel dubbelt så mycket,Piksel çift, +Pixel quadruple,OPTVAL_PIXELQUADRUPLE,,,,Zčtyřnásobení pixelů,Pixel firedobbelt,Pixelvervierfachung,,Bilderon kvarobligi,Pixel cuádruple,,Kuvapistenelinkertaistus,,Pixel négyszerezés,Pixel quadrupli,ピクセル4倍,4배 픽셀,Pixel viervoudig,Piksel firedoblet,Czterokrotnie więcej pikseli,Pixel quádruplo,,Împătrire pixeli,Учетверённые пиксели,Четвороструки пиксел,Pixel fyrdubbel,Piksel dörtlü, +Current weapon,OPTVAL_CURRENTWEAPON,,,,Současná zbraň,Nuværende våben,Aktuelle Waffe,,Nuntempa armilo,Arma actual,,Nykyinen ase,Arme actuelle,Jelenlegi fegyver,Arma corrente,使用中の武器,현 무기,Huidig wapen,Nåværende våpen,Aktualna broń,Arma atual,,Arma curentă,текущего оружия,Тренутно оружје,Aktuellt vapen,Mevcut silah, +Available weapons,OPTVAL_AVAILABLEWEAPONS,,,,Dostupně zbraně,Tilgængelige våben,Verfügbare Waffen,,Haveblaj armiloj,Armas disponibles,,Käytettävissä olevat aseet,Armes Disponibles,Elérhető fegyverek,Armi disponibili,所持してる武器,사용 가능한 무기들,Beschikbare wapens,Tilgjengelige våpen,Dostępne bronie,Armas disponíveis,,Arme disponibile,доступного оружия,Доступно оружје,Tillgängliga vapen,Mevcut silahlar, +All weapons,OPTVAL_ALLWEAPONS,,,,Všechny zbraně,Alle våben,Alle Waffen,,Ĉiuj armiloj,Todas las armas,,Kaikki aseet,Toutes les armes,Minden fegyver,Tutte le armi,全ての武器,모든 무기들,Alle wapens,Alle våpen,Wszystkie bronie,Todas as armas,,Toate armele,всех видов оружия,Сва оружја,Alla vapen,Tüm silahlar, +"Level, milliseconds",OPTVAL_LEVELMILLISECONDS,,,,"Level, milisekundy","Level, millisekunder","Level, Millisekunden",,"Nivelo, milisekundoj","Nivel, milisegundos",,"Taso, millisekunnit","Niveau, milisecondes","Pálya, milliszekundum","Livello, millisecondi","現場, ミリ秒","레벨, 밀리초당","Niveau, milliseconden","Nivå, millisekunder","Poziom, milisekundy","Fase, milisegundos","Nível, milisegundos","Nivel, milisecunde","Уровень, миллисекунды","Ниво, милисекунде","Nivå, millisekunder","Seviye, milisaniye", +"Level, seconds",OPTVAL_LEVELSECONDS,,,,"Level, vteřiny","Level, sekunder","Level, Sekunden",,"Nivelo, sekundoj","Nivel, segundos",,"Taso, sekunnit","Niveau, secondes","Pálya, másodpercek","Livello, secondi","現場, 秒","레벨, 초당","Niveau, seconden","Nivå, sekunder","Poziom, sekundy","Fase, segundos","Nível, segundos","Nivel, secunde","Уровень, секунды","Ниво, секунде","Nivå, sekunder","Seviye, saniye", +Level,OPTVAL_LEVEL,,,,,,,,Nivelo,Nivel,,Taso,Niveau,Pálya,Livello,現場,레벨,Niveau,Nivå,Poziom,Fase,Nível,Nivel,Уровень,Ниво,Nivå,Seviye, +"Hub, seconds",OPTVAL_HUBSECONDS,,,,"Hub, vteřiny","Hub, sekunder","Hub, Sekunden",,"Rekontejo, sekundoj","Hub, segundos",,"Tasokokoelma, sekunnit","Hub, secondes","Csomópont, másodpercek","Hub, secondi","区間, 秒","허브, 초당","Naaf, seconden","Hub, sekunder","Hub, sekundy","Hub, segundos",,"Hub, secunde",Хаб (секунды),"Хуб, секунде","Hub, sekunder","Hub, saniye", +Hub,OPTVAL_HUB,,,,,,,,Rekontejo,,,Tasokokoelma,,Csomópont,,区間,허브,Naaf,,,,,,Хаб,Хуб,Nav,, +"Total, seconds",OPTVAL_TOTALSECONDS,,,,"Celkový, vteřiny","I alt, sekunder","Gesamt, Sekunden",,"Tuto, sekundoj","Total, segundos",,"Yhteensä, sekunnit","Total, secondes","Teljes, másodpercek","Totale, secondi","合計, 秒","누적 경과, 초당","Totaal, seconden","Totalt, sekunder","Razem, sekundy","Total, segundos",,"Total, secunde",Общее (секунды),"Тотал, секунде","Totalt, sekunder","Toplam, saniye", +Total,OPTVAL_TOTAL,,,,Celkový,I alt,Gesamt,,Tuto,,,Yhteensä,,Teljes,Totale,合計,누적 경과,Totaal,Totalt,Razem,,,,Общее,Тотал,Totalt,Toplam, +"System, seconds",OPTVAL_SYSTEMSECONDS,,,,"Systémový, vteřiny","System, sekunder","System, Sekunden",,"Sistemo, sekundoj","Sistema, segundos",,"Järjestelmä, sekunnit","Système, secondes","Rendszer, másodpercek","Sistema, secondi","PC時刻, 秒","시스템, 초당","Systeem, seconden","System, sekunder","System, sekundy","Sistema, segundos",,"Sistem, secunde",Система (секунды),"Систем, секунде","System, sekunder","Sistem, saniye", +System,OPTVAL_SYSTEM,,,,Systémový,,,,Sistemo,Sistema,,Järjestelmä,Système,Rendszer,Sistema,PC時刻,시스템,Systeem,,,Sistema,,Sistem,Система,Систем,,Sistem, +Netgames only,OPTVAL_NETGAMESONLY,,,,Pouze v síťové hře,Kun netspil,Nur Netzwerkspiele,,Retludoj sole,Solo para juegos en red,,Vain verkkopelit,Parties en Ligne seulement,Csak Netgames,Solo giochi net,オンラインのみ,멀티플레이에만,Alleen Netspellen,Kun nettspill,Tylko gry sieciowe,Jogos em rede apenas,,Doar în rețea,Только сетевые игры,Мрежне игре само,Endast nätspel,Sadece net oyunlar, +Image and Text,OPTVAL_AMMOIMAGETEXT,,,,Obrázek a text,Billede og tekst,Bild und Text,,Bildo kaj Teksto,Imagen y texto,,Kuva ja teksti,Image et Texte,Kép és szöveg,Immagini e testo,画像と字,이미지와 텍스트,Beeld en tekst,Bilde og tekst,Obraz i Tekst,Imagem e texto,,Imagine și Text,Изображение и текст,Слика и текст,Bild och text,Resim ve Metin, +Text and Image,OPTVAL_AMMOTEXTIMAGE,,,,Text a obrázek,Tekst og billede,Text und Bild,,Teksto kaj Bildo,Texto e imagen,,Teksti ja kuva,Texte et Image,Szöveg és kép,Testo e immagini,字と画像,텍스트와 이미지,Tekst en beeld,Tekst og bilde,Tekst i Obraz,Texto e imagem,,Text și Imagine,Текст и изобр.,Текст и слика,Text och bild,Metin ve Görüntü, +Scripts Only,OPTVAL_SCRIPTSONLY,,,,Pouze skripty,Kun scripts,Nur Skripte,,Skriptoj Sole,Solo scripts,,Vain komentosarjat,Scripts seulement,Csak szkript,Solo script,スクリプトのみ,스크립트에만,Alleen scripts,Bare skript,Tylko skrypty,Scripts apenas,,Numai scripturi,Только скрипты,Само скрипте,Endast skript,Sadece Senaryolar, +All,OPTVAL_ALL,,,,Všechny,Alle,Alle,,Ĉiuj,Todos,,Kaikki,Tout,Mind,Tutti,全て,모두 작동,Alle,Alle,Wszystko,Todos,,Tot,Все,Све,Alla,Tümü, +Only last one,OPTVAL_ONLYLASTONE,,,,Pouze poslední,Kun den sidste,Nur das letzte,,Nur fina unu,Solo el último,,Vain viimeinen,Dernier seulement,Csak a legutolsó,Solo l'ultimo,最後のみ,오직 마지막 것만,Alleen de laatste,Bare den siste,Tylko ostatni,Somente o último,Apenas o último,Doar ultimul,Только последнее,Само последњи,Endast den sista,Sadece sonuncusu, +Traditional Doom,OPTVAL_TRADITIONALDOOM,,,,Tradiční Doom,Traditionel Doom,Doom traditionell,,Tradicia Doom,Doom tradicional,,Perinteinen Doom,Doom Traditionnel,Tradícionális Doom,DOOM tradizionale,正式DOOM,전형적인 둠 스타일,Traditioneel Doom,Tradisjonell undergang,Tradycyjny Doom,Doom Tradicional,,Tradițional Doom,Цвета из Doom,Традиционални Doom,Traditionell Doom,Geleneksel Doom, +Traditional Strife,OPTVAL_TRADITIONALSTRIFE,,,,Tradiční Strife,Traditionel Strife,Strife traditionell,,Tradicia Strife,Strife tradicional,,Perinteinen Strife,Strife Traditionnel,Tradícionális Strife,Strife tradizionale,正式Strife,전형적인 스트라이프 스타일,Traditionele Strife,Tradisjonell strid,Tradycyjny Strife,Strife Tradicional,,Tradițional Strife,Цвета из Strife,Традиционални Strife,Traditionell Strife,Geleneksel Strife, +Traditional Raven,OPTVAL_TRADITIONALRAVEN,,,,Tradiční Raven,Traditionel Raven,Raven traditionell,,Tradicia Raven,Raven tradicional,,Perinteinen Raven,Raven Traditionnel,Tradícionális Raven,Raven tradizionale,正式Raven,전형적인 레이븐 스타일,Traditionele Raven,Tradisjonell ravn,Tradycyjny Raven,Raven Tradicional,,Tradițional Raven,Цвета из Raven,Традиционални Raven,Traditionell Raven,Geleneksel Raven, +Only when found,OPTVAL_ONLYWHENFOUND,,,,Pouze po nalezení,Kun når de findes,Nur wenn gefunden,,Nur kiam trovita,Una vez encontrados,,"Vain, kun löydetty",Seulement découverts,Csak ha megleled,Solo quando trovato,発見時のみ,획득했을 때만,Alleen wanneer gevonden,Bare når funnet,Tylko gdy znaleziono,Somente quando encontrado,Apenas quando encontrado,Doar la descoperire,После обнаружения,Само кад је пронађен,Endast när den hittas,Sadece bulunduğunda, +On for overlay only,OPTVAL_ONFOROVERLAYONLY,,,,Pouze v překryvném režimu,Kun til overlay,Nur auf Overlay,,Ŝaltita nur por surmeto,Solo para superpuesto,,Päällä vain karttaprojisoinnin kanssa,On pour Surimpression,Csak az overlayen,Solo attivo per la sovrapposizione,オーバーレイ専用,오버레이에만 작동,Alleen op voor overlay alleen voor overlay,På kun for overlegg,Włączony tylko dla nakładek,Ativado somente para sobreposição,Apenas ativado para sobreposição,Doar pentru modul transparent,Только наложенная,Укључен само за навлаку,Endast på för överlagring,Yalnızca kaplama için etkin, +Overlay+Normal,OPTVAL_OVERLAYNORMAL,,,,Překryv + normální,Overlay+Normal,Overlay+Normal,,Surmeto+Normala,Superpuesto+Normal,,Projisointi+tavallinen,Surimpression+Normal,Overlay+Normál,Sovrapposizione+Normale,オーバーレイ+通常,오버레이+기본,Overlay+Normaal,,Nakładka+Normalnie,Sobreposição+Normal,,Transparent + Normal,Наложенная + обычная,Навлака + нормално,Överlagring+Normal,Yer Kaplama+Normal, +Overlay Only,OPTVAL_OVERLAYONLY,,,,Pouze překryv,Kun overlay,Nur Overlay,,Nur Surmeto,Solo superpuesto,,Vain projisointi,Surimpression seulement,Csak Overlay-nél,Solo Sovrapposizione,オーバーレイのみ,오버레이만,Alleen Overlay,Kun overlegg,Tylko Nakładka,Sobreposição apenas,,Doar modul transparent,Только прозрачный,Навлак само,Endast överlagring,Yalnızca Kaplama, +Not for hubs,OPTVAL_NOTFORHUBS,,,,Ne pro huby,Ikke for knudepunkter,Nicht für Hubs,,Ne por naboj,No para hubs,,Ei tasokokoelmille,Pas pour les hubs,Csomópontokhoz nem,Non per gli hub,区間では出さない,허브는 제외,Niet voor hubs,Ikke for nav,Nie dla hubów,Exceto hubs,,Nu pentru hub-uri,Кроме групп,Није за хубове,Inte för nav,Hub'lar için değil, +Front,OPTVAL_FRONT,,,,Zepředu,Forside,Frontalansicht,,Fronto,Frontal,,Etu,Devant,Előnézet,Fronte,画像,정면,Voorkant,Forside,Przód,Frente,,Înainte,Перед,Испред,Framsida,Ön, +Animated,OPTVAL_ANIMATED,,,,Animované,Animeret,Animiert,,Animita,Animado,,Animoitu,Animés,Animált,Animato,動作,움직임,Geanimeerd,Animert,Animowany,Animado,,Animat,Анимированные,Анимирано,Animerad,Animasyonlu, +Rotated,OPTVAL_ROTATED,,,,Otáčivé,Drejet,Rotiert,,Turnita,Rotado,,Kääntyvä,Tournés,Elforgatott,Ruotato,回転,회전함,Geroteerd,Rotert,Obrócony,Rotacionado,Rodado,Rotit,Повёрнутые,Ротирано,Roterad,Döndürülmüş, +Map defined colors only,OPTVAL_MAPDEFINEDCOLORSONLY,,,Map defined colours only,Pouze barvy definované mapou,Kun kortdefinerede farver,Nur Leveldefinierte Farben,,Nur mapaj difinitaj koloroj,Colores definidos por el usuario,,Vain kartan määrittämät värit,Couleurs définies carte seul.,Csak map orientált színek,Solo i colori definiti dalla mappa,指定した色のみ,자체 미니맵 색상 사용,Alleen gedefinieerde kleuren op de kaart,Kun kartdefinerte farger,Tylko kolory zdefiniowane przez mapę,Cores definidas por mapa apenas,,Doar culori specifice hărții,Только определённые картой цвета,Само дефинисане мапом боје,Endast kartdefinierade färger,Yalnızca harita tanımlı renkler, +All except doors,OPTVAL_NODOORS,,,,Všechny krom dveří,Alle undtagen døre,Alle außer Türen,,Ĉiom krom pordoj,Todo excepto puertas,,Kaikki paitsi ovet,Tout sauf portes,"Minden, kivétel az ajtók",Tutti eccetto le porte,ドア以外全て,문을 제외한 모두,Allemaal behalve deuren,Alle unntatt dører,Wszystko oprócz drzwi,Tudo exceto portas,,Cu excepția ușilor,Кроме дверей,Све осим врата,Alla utom dörrar,Kapılar hariç hepsi, +Double,OPTVAL_DOUBLE,,,,Dvojitý,Dobbelt,Doppel,,Duobligi,Doble,,Kaksinkertainen,,Dupla,Doppio,ダブル,2배,Dubbele,Dobbel,Podwójny,Dobro,,Dublu,Двойной,Дупло,Dubbel,Çift, +Triple,OPTVAL_TRIPLE,,,,Trojitý,Tredobbelt,Dreifach,,Triobligi,,,Kolminkertainen,,Tripla,Triplo,トリプル,3배,Drievoudig,Trippel,Potrójny,Triplo,,Triplu,Тройной,Тродупло,Tredubbel,Üçlü, +Quadruple,OPTVAL_QUADRUPLE,,,,Čtveritý,Firedobbelt,Vierfach,,Kvarobligi,Cuádruple,,Nelinkertainen,,Négyszeres,Quadruplo,クァッド,4배,Viervoudig,Firedoblet,Poczwórny,Quádruplo,,Cvadruplu,Четырёхкратный ,Четвороструко,Fyrdubbel,Dörtlü, +Item Pickup,OPTVAL_ITEMPICKUP,,,,Sebrání předmětu,Afhentning af varer,Gegenstand genommen,,Objektoprenado,Coger objetos,Agarrar objetos,Esineen poiminta,Objets Ramassés,Tárgy felvétele,Raccolta oggetto,アイテム取得,아이템 획득시,Puntafhaling,Varehenting,Podniesienie Przedmiotu,Coleta de Item,Aquisição de Itens,Obiect Ridicat,Подбор предметов,Подигнут предмет,Hämtning av föremål,Bir eşyayı almak, +Obituaries,OPTVAL_OBITUARIES,,,,Oznámení o smrti,Dødsannoncer,Todesanzeige,,Nekrologoj,Obituarios,,Kuolinviestit,Avis de décès,Halálok,Necrologio,死亡時,사망 메시지,Doodsbrieven,Dødsannonser,Nekrologi,Obituários,,Necrologuri,Некрологи,Читуље,Dödsannonser,Ölüm İlanları, +Critical Messages,OPTVAL_CRITICALMESSAGES,,,,Kritická oznámení,Kritiske meddelelser,Kritische Meldungen,,Gravaj mesaĝoj,Mensajes críticos,,Tärkeät viestit,Messages Critiques,Fontos üzenetek,Messaggi critici,重要メッセージ,중요한 메시지,Kritische berichten,Kritiske meldinger,Wiadomości krytyczne,Mensagens Críticas,,Mesaje Critice,Важные сообщения,Критичне поруке,Kritiska meddelanden,Kritik Mesajlar, +Never friends,OPTVAL_NEVERFRIENDS,,,,Nikdy spojence,Aldrig venner,Keine Freunde,,Neniam amikoj,Nunca amigos,,Ei koskaan ystäviä,Jamais les Amis,Barátokat sose,Mai amici,フレンド以外,아군 무시,Nooit vrienden,Aldri venner,Żadnych przyjaciół,Nunca amigos,,Nu aliați,Не по союзникам,Никад за пријатеље,Aldrig vänner,Asla arkadaş değil, +Only monsters,OPTVAL_ONLYMONSTERS,,,,Pouze příšery,Kun monstre,Nur Monster,,Nur monstroj,Solo monstruos,,Vain hirviöt,Monstres Seulement,Csak szörnyeket,Solo i mostri,モンスターのみ,적에게만,Alleen monsters,Bare monstre,Tylko potwory,Somente monstros,Monstros apenas,Doar monștri,Для монстров,Само чудовишста,Endast monster,Sadece canavarlar, +Hexen,OPTVAL_HEXEN,,,,,,,,,,,,Hexen,,,,헥센,,,,,,,,,,, +Old,OPTVAL_OLD,,,,Starý,Gamle,Alt,,Maljuna,Viejo,,Vanha,Ancien,Régi,Vecchio,旧式,구형,Oud,Gamle,Stare,Antigo,,Vechi,Старый,Стар,Gamla,Eski, +Doom,OPTVAL_DOOM,,,,,,,,,,,,,,,,둠,,,,,,,,,,, +Doom (strict),OPTVAL_DOOMSTRICT,,,,Doom (striktní),Doom (streng),Doom (strikt),,Doom (severa),Doom (estricto),,Doom (tiukka),,Doom (szigorú),Doom (rigoroso),Doom(厳密),둠 (엄격하게),Doom (streng),Doom (streng),Doom (ścisły),Doom (estritamente),Doom (estrito),,Doom (строгий),Doom (строг),Doom (strikt),Doom (katı), +Boom,OPTVAL_BOOM,,,,,,,,,,,,,,,,붐,,,,,,,,,,, +Boom (strict),OPTVAL_BOOMSTRICT,,,,Boom (striktní),Boom (streng),Boom (strikt),,Boom (severa),Boom (estricto),,Boom (tiukka),,Boom (szigorú),Boom (rigoroso),Boom(厳密),붐 (엄격하게),Boom (streng),Boom (streng),Boom (ścisły),Boom (estritamente),Boom (estrito),,Boom (строгий),Boom (строг),Boom (strikt),Boom (katı), +MBF,OPTVAL_MBF,,,,,,,,,,,,,,,,마린의 절친한 친구,,,,,,,,,,, +MBF (strict),OPTVAL_MBFSTRICT,,,,MBF (striktní),MBF (streng),MBF (strikt),,MBF (severa),MBF (estricto),,MBF (tiukka),,MBF (szigorú),MBF (rigoroso),MBF(厳密),마린의 절친한 친구 (엄격하게),MBF (streng),MBF (streng),MBF (ścisły),MBF (estritamente),MBF (estrito),,MBF (строгий),MBF (строг),MBF (strikt),MBF (katı), +MBF21,OPTVAL_MBF21,,,,,,,,,,,,,,,,,,,,,,,,,,, +MBF21 (strict),OPTVAL_MBF21STRICT,,,,MBF21 (striktní),MBF21 (streng),MBF21 (strikt),,MBF21 (severa),MBF21 (estricto),,MBF21 (tiukka),,MBF21 (szigorú),MBF21 (rigoroso),MBF21(厳密),MBF21 (엄격하게),MBF21 (streng),MBF21 (streng),MBF21 (ścisły),MBF21 (estritamente),MBF21 (estrito),,MBF21 (строгий),MBF21 (строг),MBF21 (strikt),MBF21 (katı), +ZDoom 2.0.63,OPTVAL_ZDOOM2063,,,,,,,,,,,,,,,,Z둠 2.0.63,,,,,,,,,,, +All unacknowledged,OPTVAL_ALLUNACKNOWLEDGED,,,,Všechny nepotrvzené,Alle ubekræftede,Alle unbestätigten,,Ĉiuj neagnoskitaj,Todos no reconocidos,,Kaikki kuittaamattomat,Tout non-acknowledged,Minden visszaigazolatlan,Tutti non riconosciuti,未確認全て,모두 미확인함,Allemaal onbekend,Alle ubekreftet,Wszystkie niepotwierdzone,Todos não-reconhecidos,,Toate necunoscute,Всё неопознанное,Све неусвојено,Alla obeaktade,Tüm onaylanmamış, +Errors,OPTVAL_ERRORS,,,,Chyby,Fejl,Fehler,,Eraroj,Errores,,Virheet,Erreurs,Hibák,Errori,エラー,에러,Fouten,Feil,Błędy,Erros,,Erori,Ошибки,Грешка,Fel,Hatalar, +Warnings,OPTVAL_WARNINGS,,,,Varování,Advarsler,Warnungen,,Avertoj,Advertencias,,Varoitukset,Avertissements,Figyelmeztetések,Avvisi,警告,경고,Waarschuwingen,Advarsler,Ostrzeżenia,Avisos,,Atenționări,Предупреждения,Упозорење,Varningar,Uyarılar, +Notifications,OPTVAL_NOTIFICATIONS,,,,Oznámení,Meddelelser,Benachrichtigungen,,Sciigoj,Notificaciones,,Ilmoitukset,,Üzenetek,Notifiche,通知,알림,Kennisgevingen,Varsler,Powiadomienia,Notificações,,Notificări,Уведомления,Обавештење,Meddelanden,Bildirimler, +Everything,OPTVAL_EVERYTHING,,,,Všechno,Alt,Alles,,Ĉio,Todo,,Kaikki,Tout,Minden,Tutti,全て,전체,Alles,Alt,Wszystko,Tudo,,Tot,Всё,Све,Allt,Her şey, +Hardware accelerated,OPTVAL_HWPOLY,,,,Hardwarová akcelerace,Hardware accelereret,Hardwarebeschleunigt,,Aparatara plirapidigo,Acelerado por «hardware»,,Laitteistokiihdytetty,Accéléré par Hardware,Hardveres gyorsítás,Accelerazione Hardware,ハードウェア アクセラレート,오픈지엘 가속,Hardware versneld,Maskinvareakselerert,Napędzane sprzętowo,Acelerado por hardware,,Accelerat Hardware,Аппаратный,Харвер убрзан,Hårdvara påskyndad,Hızlandırılmış donanım, +Doom Software Renderer,OPTVAL_SWDOOM,,,,Doom softwarový renderer,,,,Programar-bildigilo de Doom,Renderizado por «software» de Doom,,Doomin ohjelmistohahmonnin,Rendu Software Doom,Doom szoftveres renderer,Rendering DOOM software,Doom ソフトウェアレンダー,둠 소프트웨어 렌더러,,,Renderer Oprogramowania Dooma,Renderizador Software do Doom,,Software,Doom-программный,Doom софтверски рендерер,Doom Mjukvarurenderare,Doom Yazılım Oluşturucu, +True Color SW Renderer,OPTVAL_SWDOOMTC,,,,True color softwarový renderer,,,,Programar-bildigilo kun plenkoloro,Renderizado Truecolor (color verdadero) del «software»,,True Color -ohjelmistohahmonnin,Rendu Software Couleurs Réeles,,Rendering software a pieni colori,トゥルーカラー SWレンダー,트루 컬러 소프트웨어 렌더러,,,Renderer True Color,Renderizador Software True Color,,Software Color Complet,Полноцветный програмный,SW рендерер праве боје,True Color Mjukvarurenderare,Gerçek Renk SW Oluşturucu, +High-Performance,OPTVAL_DEDICATED,,,,Vysoký výkon,Højtydende,Volle Leistung,,Alta rendimento,Alto rendimiento,,Korkea suorituskyky,Hautes Performances,Nagy teljesítmény,Prestazioni massime,ハイパフォーマンス,고 성능,Hoogwaardige prestaties,Høy ytelse,Wysoka Wydajność,Alta-Performance,,De înaltă performanță,Высокая производительность,Високо-перформанси,Högpresterande,Yüksek Performans, +Power-Saving,OPTVAL_INTEGRATED,,,,Nízká spotřeba,Strømbesparende,energiesparend,,Energikonservo,Ahorro de energía,,Virransäästö,Economie d'Energie,Energia takarékos,Risparmio energetico,パワーセービング,저전력,Energiebesparing,Strømsparende,Oszczędzanie Energii,Economia de Energia,,Economie de energie,Энергосбережение,Енергетско-штедљиви,Energibesparande,Güç Tasarrufu, +Vanilla,OPTVAL_VANILLA,,,,Původní,,,,Originala ludversio,,,Alkuperäinen,,Hagyományos,,バニラ,바닐라,,,Czysty,,,Original,Изначальный,Ванила,,Vanilya, +ZDoom (Forced),OPTVAL_VTFZDOOM,,,,ZDoom (vynucený),ZDoom (tvunget),ZDoom (erzwungen),,ZDoom (devigita),ZDoom (forzado),,ZDoom (pakotettu),ZDoom (Forcé),ZDoom (erőltetett),ZDoom (forzato),ZDoom(強制),ZDoom (강제 설정),ZDoom (Gedwongen),ZDoom (Tvunget),ZDoom (Wymuszony),ZDoom (Forçar),,ZDoom (Forțat),ZDoom (принудительно),ZDoom (присиљен),ZDoom (tvingad),ZDoom (Zorla), +Vanilla (Forced),OPTVAL_VTFVANILLA,,,,Původní (vynucený),Vanilla (tvungen),Vanilla (erzwungen),,Originala ludversio (devigita),Vanilla (forzado),,Perus (pakotettu),Vanilla (Forcé),Hagyományos (erőltettt),Vanilla (forzato),バニラ(強制),바닐라 (강제 설정),Vanilla (Gedwongen),Vanilla (Tvunget),Czysty (Wymuszony),Vanilla (Forçar),DOS Original (Forçar),Original (Forțat),Изначальный (принудительно),Ванила (присиљен),Vanilla (tvingad),Vanilya (Zorlanmış), +Auto (ZDoom Preferred),OPTVAL_VTAZDOOM,,,,Auto (preferován ZDoom),Auto (ZDoom foretrukket),Auto (ZDoom bevorzugt),,Aŭtomata (preferata de ZDoom),Automático (preferido por ZDoom),,Automaattinen (ZDoomia suosiva),Auto (ZDoom Préféré),Automata (ZDoom preferált),Automatico (ZDoom preferito),自動(ZDoom優先),자동 (ZDoom 기본 설정),Auto (bij voorkeur ZDoom),Auto (ZDoom foretrukket),Automatyczny (Preferowany ZDoom),Automático (De preferência ZDoom),,Auto (ZDoom preferat),Автоматически (предпочитать ZDoom),Аутоматски (ZDoom преферијални),Auto (ZDoom föredraget),Otomatik (ZDoom Tercih Edilir), +Auto (Vanilla Preferred),OPTVAL_VTAVANILLA,,,,Auto (preferován původní),Auto (Vanilla foretrukket),Auto (Vanilla bevorzugt),,Aŭtomata (preferata de la originala),Automático (preferido por Vanilla),,Automaattinen (alkuperäistä suosiva),Auto (Vanilla Préféré),Automata (Hagyományos preferált),Automatico (Vanilla preferito),自動(バニラ優先),자동 (바닐라 기본 설정),Auto (bij voorkeur Vanilla),Auto (Vanilla foretrukket),Automatyczny (Preferowany czysty),Automático (De preferência Vanilla),Automático (De preferência DOS Original),Auto (Original preferat),Автоматически (предпочитать изначальный),Аутоматски (ванила преферијални),Auto (Vanilla föredraget),Otomatik (Vanilya Tercihli), +Small,OPTVAL_SMALL,,,,Malé,Lille,Klein,,Malgranda,Pequeño,,Pieni,Petit,Kicsi,Piccolo,小,작게,Klein,Liten,Mały,Pequeno,,Mic,Мелкий,Мало,Liten,Küçük, +Large,OPTVAL_LARGE,,,,Velké,Stor,Groß,,Granda,Grande,,Suuri,Grand,Nagy,Grande,大,크게,Groot,Stor,Duży,Grande,,Mare,Крупный,Велико,Stor,Büyük, +Console,OPTVAL_CONSOLE,,,,Konzole,Konsol,Konsole,,Konzolo,Consola,,Konsoli,,Konzol,,コンソール,콘솔,,Konsoll,Konsola,,Consola,Consolă,Консольный,Конзола,Konsol,Konsol, +\caBrick,C_BRICK,,,,\caCihlová,\caMursten,\caZiegelrot,,\caBrikkolora,\caLadrillo,,\catiili,\cabrique,\catéglavörös,\camattone,\ca丹,\ca주홍색,\casteenrood,\caMurstein,\cacegła,\catijolo,,\caCărămiziu,\caКирпичный,\caБоја цигле,\caTegelsten,\caTuğla, +\cbTan,C_TAN,,,,\cbSvětle hnědá,,\cbHellbraun,,\cbTankolora,\cbBeis,\cbBeige,\cbkeltaruskea,\cbbeige,\cbbézs,\cbabbronzatura,\cb香,\cb상아색,\cblichtbruin,\cbBrun,\cbjasnobrązowy,\cbbege,,\caBronz,\cbБежевый,\cbБеж,,, +\ccGray,C_GRAY,,,\ccgrey,\ccŠedá,\ccGrå,\ccGrau,,\ccGriza,\ccGris,,\ccharmaa,\ccgris,\ccszürke,\ccgrigio,\cc灰,\cc회색,\ccgrijs,\ccGrå,\ccszary,\cccinza,,\ccGri,\ccСерый,\ccСива,\ccGrå,\ccGri, +\cdGreen,C_GREEN,,,,\cdZelená,\cdGrøn,\cdGrün,,\cdVerda,\cdVerde,,\cdvihreä,\cdvert,\cdzöld,\cdverde,\cd緑,\cd녹색,\cdgroen,\cdGrønn,\cdzielony,\cdverde,,\cdVerde,\cdЗелёный,\cdЗелена,\cdGrön,\cdYeşil, +\ceBrown,C_BROWN,,,,\ceHnědá,\ceBrun,\ceBraun,,\ceBruna,\ceMarrón,\ceMarrón/Café,\ceruskea,\cebrun,\cebarna,\cemarrone,\ce茶,\ce갈색,\cebruin,\ceBrun,\cebrązowy,\cemarrom,,\ceMaro,\ceКоричневый,\ceСмеђа,\ceBrun,\ceKahverengi, +\cfGold,C_GOLD,,,,\cfZlatá,\cfGuld,,,\cfOrkolora,\cfDorado,,\cfkulta,\cfor,\cfarany,\cforo,\cf金,\cf금색,\cfgoud,\cfGull,\cfzłoty,\cfdourado,,\cfAuriu,\cfЗолотой,\cfЗлатна,\cfGuld,\cfAltın, +\cgRed,C_RED,,,,\cgČervená,\cgRød,\cGrot,,\cfRuĝa,\cgRojo,,\cgpunainen,\cgrouge,\cgvörös,\cgrosso,\cg赤,\cg적색,\cgrood,\cgRød,\cgczerwony,\cgvermelho,,\gRoșu,\cgКрасный,\cgЦрвена,\cgRöd,\cgKırmızı, +\chBlue,C_BLUE,,,,\chModrá,\chBlå,\chBlau,,\chBlua,\chAzul,,\chsininen,\chbleu,\chkék,\chblu,\ch青,\ch청색,\chblauw,\chBlå,\chniebieski,\chazul,,\chAlbastru,\chСиний,\chПлава,\chBlå,\chMavi, +\ciOrange,C_ORANGE,,,,\ciOranžová,,,,\ciOranĝkolora,\ciNaranja,,\cioranssi,\ciorange,\cinarancs,\ciarancione,\ci橙,\ci주황색,\cioranje,\ciOransje,\cipomarańczowy,\cilaranja,,\ciPortocaliu,\ciОранжевый,\ciНаранџаста,,\ciTuruncu, +\cjWhite,C_WHITE,,,,\cjBílá,\cjHvid,\cjWeiß,,\cjBlanka,\cjBlanco,,\cjvalkoinen,\cjblanc,\cjfehér,\cjbianco,\cj白,\cj흰색,\cjwit,\cjHvit,\cjbiały,\cjbranco,,\cjAlb,\cjБелый,\cjБела,\cjVit,\cjBeyaz, +\ckYellow,C_YELLOW,,,,\ckŽlutá,\ckGul,\ckGelb,,\ckFlava,\ckAmarillo,,\ckkeltainen,\ckjaune,\cksárga,\ckgiallo,\ck黄,\ck노란색,\ckgeel,\ckGul,\ckżółty,\ckamarelo,,\ckGalben,\ckЖёлтый,\ckЖута,\ckGul,\ckSarı, +\clDefault,C_DEFAULT,,,,\clVýchozí,\clStandard,\clStandard,,\clDefaŭlta,\clPor defecto,,\cloletus,\cldéfaut,\clalap,\cldefault,\cl初期,\cl기본 색,\clstandaard,\clStandard,\cldomyślny,\clpadrão,,\clImplicită,\clПо умолчанию,\clУобичајена,\clStandard,\clVarsayılan, +\cmBlack,C_BLACK,,,,\cmČerná,\cmSort,\cmSchwarz,,\cmNigra,\cmNegro,,\cmmusta,\cmnoir,\cmfekete,\cmnero,\cm黒,\cm검은색,\cmzwart,\cmSvart,\cmczarny,\cmpreto,,\cmNegru,\cmЧёрный,\cmЦрна,\cmSvart,\cmSiyah, +\cnLight blue,C_LIGHTBLUE,,,,\cnSvětle modrá,\cnLyseblå,\cnHellblau,,\cnHelblua,\cnAzul claro,,\cnvaaleansininen,\cnbleu clair,\cnvilágoskék,\cnblu chiaro,\cn空,\cn하늘색,\cnlicht blauw,\cnLyseblå,\cnjasnoniebieski,\cnazul claro,,\cnAlbastru deschis,\cnГолубой,\cnСветло плава,\cnLjusblått,\cnAçık mavi, +\coCream,C_CREAM,,,,\coKrémová,\coCreme,\coCremefarben,,\coKremkolora,\coCrema,,\cokerma,\cocrème,\cokrémszínű,\cocrema,\co肉,\co살구색,\cocrème,\coKremfarget,\cokremowy,\cocreme,,\coCrem,\coКремовый,\coКрем,\coGrädde,\coKrem, +\cpOlive,C_OLIVE,,,,\cpOlivová,\cpOliven,\cpOliv,,\cpOlivkolora,\cpOliva,,\cpoliivi,\cpolive,\cpolíva,\cpoliva,\cp泥,\cp녹갈색,\cpolijf,\cpOliven,\cpoliwkowy,\cpoliva,,\cpMăsliniu,\cpОливковый,\cpМаслинаста,\cpOliv,\cpZeytin, +\cqDark green,C_DARKGREEN,,,,\cqTmavě zelená,\cqMørkegrøn,\cqDunkelgrün,,\cqMalhelverda,\cqVerde oscuro,,\cqtummanvihreä,\cqvert sombre,\cqsötétzöld,\cqverde scuro,\cq深,\cq암녹색,\cqdonkergroen,\cqMørkegrøn,\cqciemnozielony,\cqverde escuro,,\cqVerde închis,\cqТёмно-зелёный,\cqТамно зелена,\cqMörkgrön,\cqKoyu yeşil, +\crDark red,C_DARKRED,,,,\crTmavě červená,\crMørkerød,\crDunkelrot,,\crMalhelruĝa,\crRojo oscuro,,\crtummanpunainen,\crrouge sombre,\crsötétvörös,\crrosso scuro,\cr朱,\cr암적색,\crdonkerrood,\crMørkerød,\crciemnoczerwony,\crvermelho escuro,,\crRoșu închis,\crТёмно-красный,\crБордо,\crMörkröd,\crKoyu kırmızı, +\csDark brown,C_DARKBROWN,,,,\csTmavě hnědá,\csMørkebrun,\csDunkelbraun,,\csMalhelbruna,\csMarrón oscuro,\csMarrón/Café oscuro,\cstummanruskea,\csbrun sombre,\cssötétbarna,\csmarrone scuro,\cs焦,\cs암갈색,\csdonkerbruin,\csMørkebrun,\csciemnobrązowy,\csmarrom escuro,,\csMaro închis,\csТёмно-коричневый,\csБраон,\csMörkbrun,\csKoyu kahverengi, +\ctPurple,C_PURPLE,,,,\ctFialová,\ctLilla,\ctLila,,\ctPurpura,\ctMorado,,\ctpurppura,\ctviolet,\ctlila,\ctviola,\ct紫,\ct보라색,\ctpaars,\ctLilla,\ctfioletowy,\ctroxo,,\ctMov,\ctФиолетовый,\ctЉубичаста,\ctLila,\ctMor, +\cuDark gray,C_DARKGRAY,,,\cudark grey,\cuTmavě šedá,\cuMørkegrå,\cuDunkelgrau,,\cuMalhelgriza,\cuGris oscuro,,\cutummanharmaa,\cugris sombre,\cusötétszürke,\cugrigio scuro,\cu鉛,\cu치색,\cudonkergrijs,\cuMørkegrå,\cuciemnoszary,\cucinza escuro,,\cuGri închis,\cuТёмно-серый,\cuТамно сива,\cuMörkgrå,\cuKoyu gri, +\cvCyan,C_CYAN,,,,\cvAzurová,,\cvTürkis,,\cvCejana,\cvCian,,\cvsinivihreä,\cvcyan,\cvcián,\cvciano,\cv天,\cv청록색,\cvcyan,,\cvbłękitny,\cvciano,,\cvTurcoaz,\cvСине-зелёный,\cvЦијан,,, +\cwIce,C_ICE,,,,\cwLed,\cwIs,\cwEis,,\cwGlacikolora,\cwHielo,,\cwjää,\cwglace,\cwjég,\cwghiaccio,\cw氷,\cw구색,\cwice,\cwIs,\cwlód,\cwgelo,,\cwGheață,\cwЛедяной,\cwЛед,\cwIs,\cwBuz, +\cxFire,C_FIRE,,,,\cxOheň,\cxIld,\cxFeuer,,\cxFajrkolora,\cxFuego,,\cxtuli,\cxfeu,\cxtűz,\cxfuoco,\cx炎,\cx자황색,\cxvuur,\cxIld,\cxogień,\cxfogo,,\cxFoc,\cxОгненный,\cxВатрена,\cxEld,\cxYangın, +\cySapphire,C_SAPPHIRE,,,,\cySafírová,\cySafir,\cySaphirblau,,\cySafirkolora,\cyZafiro,,\cysafiiri,\cysaphir,\cyzafír,\cyzaffiro,\cy藍,\cy벽청색,\cysaffier,\cySafir,\cyszafirowy,\cysafira,,\cySafir,\cyСапфировый,\cyТамно плава,\cySafir,\cySafir, +\czTeal,C_TEAL,,,,\czModrozelená,\czKrikand,\czBlaugrün,,\czBluverda,\czTurquesa,,\cztummansinivihreä,\czturquoise,\cztürkiz,\czverde acqua,\cz碧,\cz암청록색,\czteal,\czBlågrønn,\czmorski,\czturquesa,,\czMare,\czМорской,\czТиркизна,,\czDeniz mavisi, +Heretic,OPTSTR_HERETIC,,,,,,,,,,,,,,,,헤러틱 커서,,,,,,,,,,, +Chex,OPTSTR_CHEX,,,,,,,,,,,,,,,,첵스 커서,,,,,,,,,,, +No Sound,OPTSTR_NOSOUND,,,,Bez zvuku,Ingen lyd,Kein Sound,,Neniu sono,Sin sonido,,Ei ääntä,Pas de son,Hang nélkül,Nessun suono,サウンドなし,음향 없음,Geen geluid,Ingen lyd,Brak dźwięku,Sem som,,Fără Sunet,Без звука,Без-звучни,Inget ljud,Ses Yok, +No interpolation,OPTSTR_NOINTERPOLATION,,,,Bez interpolace,Ingen interpolation,Keine Interpolation,,Neniu interpolado,Sin interpolación,,Ei interpolaatiota,Pas d'interpolation,Nincs interoláció,No interpolazione,補間無し,보간 없음,Geen interpolatie,Ingen interpolasjon,Brak interpolacji,Sem interpolação,,Fără interpolare,Без сглаживания,Нема уметања,Ingen interpolering,Enterpolasyon yok, +Spline,OPTSTR_SPLINE,,,,Křivka,,,,Splajno,,,Splini,,,,スプライン,스플라인,,,,,,,Сплайн,Сплајн,,, +OpenAL,OPTSTR_OPENAL,,,,,,,,,,,,,,,,오픈에이엘,,,,,,,,,,, +Hardware Renderer,DSPLYMNU_GLOPT,,,,Hardwarový renderer,,,,Aparatara bildigilo,Renderizado por «hardware»,,Laitteistohahmonnin,Moteur de Rendu Hardware,Hardver Render,Rendering Hardware,ハードウェア レンダラー,오픈지엘 렌더러,,,Renderer Sprzętowy,Renderizador Hardware,,Setări Mod OpenGL,Обработка с OpenGL,Хардвер рендерер,Hårdvaru-renderare,Donanım Oluşturucu, +Software Renderer,DSPLYMNU_SWOPT,,,,Softwarový renderer,,,,Programara bildigilo,Renderizado por «software»,,Ohjelmistohahmonnin,Moteur de Rendu Software,Szoftver Render,Rendering Software,ソフトウェア レンダラー,소프트웨어 렌더러,,,Renderer Oprogramowania,Renderizador Software,,Setări Mod Software,Программная обработка,Софтвер рендерер,Mjukvarurenderare,Yazılım Oluşturucu, +Hardware Rendering Options,GLMNU_TITLE,,,,Nastavení hardwarového rendereru,Indstillinger for hardware-rendering,Hardware-Renderer Optionen,,Agordoj de OpenGL (aparatara bildigilo),Opciones de OpenGL,,Laitteistohahmonnusasetukset,Options OpenGL,Hardver Renderelő Beállítások,Opzioni OpenGL,ハードウェアレンダリング オプション,오픈지엘 설정,Hardware Rendering Opties,Alternativer for maskinvaregjengivelse,Opcje Renderowania Sprzętowego,Opções de Renderização por Hardware,,Setări Redare OpenGL,Настройки OpenGL,Опција хардвер рендера,Alternativ för maskinvarurendering,Donanım Oluşturma Seçenekleri, +Dynamic Light Options,GLMNU_DYNLIGHT,,,,Nastavení dynamických světel,Indstillinger for dynamisk lys,Dynamisches-Licht-Optionen,,Agordoj de dinamikaj lumoj,Opciones de luz dinámica,,Dynaamisen valon asetukset,Options Lumières Dynamiques,Dinamikus Fény Beállítások,Opzioni Luci Dinamiche,ダイナミックライト オプション,광원 설정,Dynamische Licht Opties,Alternativer for dynamisk lys,Opcje Dynamicznego Oświetlenia,Opções de Luz Dinâmica,,Setări Lumini Dinamice,Динамическое освещение,Подешавања динамичког осветљења,Alternativ för dynamiskt ljus,Dinamik Işık Seçenekleri, +Preferences,GLMNU_PREFS,,,,Možnosti,Præferencer,Einstellungen,,Preferoj,Preferencias,,Asetukset,Préférences,Preferenciák,Preferenze,環境設定,성능,Voorkeuren,Innstillinger,Preferencje,Preferências,,Preferințe,Настройки,Преференција,Inställningar,Tercihler, +Trim sprite edges,GLTEXMNU_TRIMSPREDGE,,,,Oříznout okraje spritů,Trimme sprite-kanter,Leerraum in Sprites wegschneiden,,Ĉirkaŭtranĉi randojn de mov-rastrumoj,Recortar líneas de «sprite»,,Siisti spritejen reunat,Nettoyer le bord des sprites,Sprite szél igazítása,Taglia gli spigoli agli sprite,スプライトの角を取る,스프라이트 모서리 다듬기,,Trim sprite kanter,Przycinanie krawędzi sprite'ów,Cortar bordas de sprites,,Tundere margini sprite-uri,Обрезание краёв спрайтов,Подсећи ивице спрајтова,Trimma sprite-kanter,Sprite kenarlarını kırpma, +Sort draw lists by texture,GLTEXMNU_SORTDRAWLIST,,,,Seřadit vykreslování podle textury,Sortere tegningslister efter tekstur,Renderlisten nach Textur sortieren,,Ordigi desegnado-listojn laŭ teksturo,Ordenar tablas por textura,,Lajittele piirtotaulut pintakuvioinneittain,Ordonner liste de rendu par texture,Textúra szerinti kirajzolási lista,Ordina la lista draw per texture,テクスチャーから描画リストを分類,텍스처별로 생성 목록 정렬,Tekeninglijsten sorteren op textuur,Sorter tegningslister etter tekstur,Sortowanie list renderowania wdług tekstur,Organizar listas de renderização por textura,,Sortează listele de texturi,Сортировать списки текстур,Сортирано цртај листе од текстуре,Sortera ritningslistor efter textur,Çizim listelerini dokuya göre sıralama, +Dynamic Lights,GLLIGHTMNU_TITLE,,,,Dynamická světla,Dynamisk lys,Dynamische Lichter,,Dinamikaj lumoj,Luces dinámicas,,Dynaamiset valot,Lumières Dynamiques,Dinamikus Fények,Luci Dinamiche,ダイナミックライト,다이나믹 라이트,Dynamische verlichting,Dynamiske lys,Dynamiczne Oświetlenie,Luzes Dinâmicas,,Lumini Dinamice,Динамическое освещение,Динамичко осветљење,Dynamiska lampor,Dinamik Işıklar, +Dynamic Lights (Hardware),GLLIGHTMNU_LIGHTSENABLED,,,,Dynamická světla (hardware),Dynamisk lys (hardware),Dynamische Lichter (Hardware),,Dinamikaj lumoj (Aparataro),Luces dinámicas (Hardware),,Dynaamiset valot (laitteistokiihdytys),Lumières Dynamiques (Hardware),Dinamikus Fények (hardveres),Luci Dinamiche (Hardware),ダイナミックライト(OpenGL),다이나믹 라이트(오픈지엘),Dynamische verlichting (hardware),Dynamiske lys (maskinvare),Dynamiczne Oświetlenie (Sprzętowe),Luzes Dinâmicas (Hardware),,Lumini Dinamice (OpenGL),Динамическое освещение (аппаратное),Динамичко осветљење (хардвер),Dynamiska lampor (maskinvara),Dinamik Işıklar (Donanım), +Enable light definitions,GLLIGHTMNU_LIGHTDEFS,,,,Povolit definice světel,Aktiver lysdefinitioner,Lichtdefinitionen an,,Ŝalti lumdifinojn,Activar definiciones de luz,,Ota käyttöön valomääritykset,Activer les définitions de lumière,Fény részletesség,Abilita le definizioni GLDEFS,ライト定義 許可,조명 선명도 사용,Lichtdefinities mogelijk maken,Aktiver lysdefinisjoner,Włącz definicje światła,Habilitar definições de luz,Permitir definições de luz,Activează definiții lumini,Включить определения света,Омогући светлосне дефиниције,Aktivera ljusdefinitioner,Işık tanımlarını etkinleştirin, +Lights affect sprites,GLLIGHTMNU_LIGHTSPRITES,,,,Světla ovlivňují sprity,Lys påvirker sprites,Sprites werden beleuchtet,,Lumoj efikas mov-rastrumojn,Las luces afectan a los «sprites»,,Valot vaikuttavat spriteihin,Lumières affectent les sprites,A fény hatással van a sprite-okra,Le luci influiscono sugli sprite,ライトがスプライトに影響,조명에 영향받는 스프라이트,Lichten beïnvloeden sprites,Lys påvirker sprites,Światło ma wpływ na sprite'y,Luzes afetam sprites,,Luminile afectează sprite-urile,Освещать спрайты,Светло утиче на спрајтове,Ljus påverkar sprites,Işıklar sprite'ları etkiler, +Lights affect particles,GLLIGHTMNU_LIGHTPARTICLES,,,,Světla ovlivňují částice,Lys påvirker partikler,Partikel werden beleuchtet,,Lumoj efikas partiklojn,Las luces afectan a las partículas,,Valot vaikuttavat hiukkasiin,Lumières affectent les particules,A fény hatással van a részecskékre,Le luci influiscono sulle particelle,ライトがパーティクルに影響,조명에 영향받는 입자들,Lichten beïnvloeden deeltjes,Lys påvirker partikler,Światło ma wpływ na cząsteczki,Luzes afetam partículas,,Luminile afectează particulele,Освещать частицы,Светло утиче на честице,Ljus påverkar partiklar,Işıklar parçacıkları etkiler, +Light shadowmaps,GLLIGHTMNU_LIGHTSHADOWMAP,,,,Mapy stínů,Lys skyggemapper,Shadowmaps für Lichter,,Lum-ombro-mapoj,Mapeo de sombra de luz,,Valojen varjokartat,Shadowmaps,,Ombre proiettate,ライトのシャドウマッピング,조명에 영향받는 섀도우맵,Lichte schaduwkaarten,Lys skyggekart,Oświetlenie map cieni,Shadowmaps,,Umbre lumini,Карты светотеней,Светло мапе сенки,Ljusskuggor,Işık gölge haritaları, +Shadowmap quality,GLLIGHTMNU_LIGHTSHADOWMAPQUALITY,,,,Kvalita map stínů,Shadowmap-kvalitet,Shadowmap Qualität,,Kvalito de ombro-mapo,Calidad de mapeo de sombras,,Varjokarttojen laatu,Qualité Shadowmap,Shadowmap minőség,Qualità ombre proiettate,シャドウマップ 品質,섀도우맵 퀄리티,Schaduwkaart kwaliteit,Shadowmap-kvalitet,Jakość map cieni,Qualidade de shadowmap,,Calitate umbre,Качество карт светотеней,Мапа сенки квалитет,Skuggmappens kvalitet,Gölge haritası kalitesi, +Shadowmap filter,GLLIGHTMNU_LIGHTSHADOWMAPFILTER,,,,Filtrování map stínů,Skyggemap-filter,Shadowmap Filter,,Filtro de ombro-mapo,Filtro de mapeo de sombras,,Varjokarttojen suodatus,Filtre de Shadowmaps,,Filtro ombre proiettate,シャドウマップ フィルター,섀도우맵 필터,Schaduwkaart filter,Shadowmap-filter,Filtr map cieni,Filtro de shadowmap,,Filtru umbre,Фильтр карт светотеней,Мапа сенки филтер,Filter för skuggmappor,Gölge haritası filtresi, +Fog mode,GLPREFMNU_FOGMODE,,,,Režim mlhy,Tågetilstand,Nebelmodus,,Reĝimo de nebulo,Modo de niebla,,Sumutila,Mode du broullard,Köd mód,Modalità nebbia,フォグモード,안개 모드,Mistmodus,Tåke-modus,Tryb mgły,Modo de neblina,,Mod ceață,Режим тумана,Магла мод,Dimläget,Sis modu, +Fog forces fullbright,GLPREFMNU_FOGFORCEFULLBRIGHT,,,,Mlha vynucuje plný jas,Tåge tvinger fullbright,Nebel erzwingt volle Helligkeit,,Nebulo devigas plenbrilon,Forzar brillo completo en niebla,,Sumu pakottaa täyskirkkauden,Brouillard force fullbright,Köd Fullbright-ot erőltet ki,La nebbia forza piena luce,濃霧は明るさ最大,안개를 최대한 강제로 밝힘,Mistkrachten volle lichtsterkte,Tåke styrker fullbright,Mgła wymusza pełną jasność,Neblina força brilho máximo,,Ceața forțează luminozitate maximă,Туман включает режим максимальной яркости,Магла присиљава пуну светлост,Dimma tvingar fram full ljusstyrka,Sis fullbright'ı zorlar, +Weapon light strength,GLPREFMNU_WPNLIGHTSTR,,,,Intenzita světel zbraní,Våbenlysstyrke,Waffenlichtstärke,,Lumforteco de armilo,Intensidad de luz de las armas,,Aseiden valovoima,Intensité lumineuse des armes,Fegyver lövés fényerősség,Intensità luminosa dell'arma,武器ライトの強さ,무기 빛 강도,Sterkte van het wapenlicht,Våpen lysstyrke,Natężenie światła broni,Intensidade de luz da arma,,Intensitate lumină armă,Интенсивность вспышек оружия,Блага снага оружја,Vapenljusets styrka,Silah ışık gücü, +Environment map on mirrors,GLPREFMNU_ENVIRONMENTMAPMIRROR,,,,Mapa prostředí na zrcadlech,Miljøkort på spejle,Lichteffekt auf Spiegeln,,Medimapo sur speguloj,Mapa de entorno en espejos,,Ympäristökartta peileissä,Mappage environment sur les miroirs,Környezeti mappolás a tükrökön,Ambiente mappa sui riflessi,マップオンミラーの画像表示,거울 주변의지도 활성,Milieukaart op spiegels,Omgivelseskart på speil,Mapa środowiska w lustrach,Mapa de ambiente em espelhos,,Reflecții pe oglinzi,Карта окружения на зеркалах,Околинска мапа на прозорима,Miljökarta på speglar,Aynalar üzerinde çevre haritası, +Enhanced night vision mode,GLPREFMNU_ENV,,,,Vylepšený režim nočního vidění,Forbedret nattesynstilstand,Verbesserter Nachtsichtmodus,,Plibonigita reĝimo de noktvido,Modo de visión nocturna mejorado,,Paranneltu pimeänäkötila,Mode de vision nocture amélioré,Felerősített éjjellátó mód,Modalità visione notturna migliorata,バイザーを暗視装置調にする,야시경 효과 향상,Verbeterde nachtzicht modus,Forbedret nattsynsmodus,Ulepszony tryb widzenia w ciemności,Modo de visão noturna avançada,,Vedere infraroșie avansată,Улучшенный режим ночного видения,Побољшана ноћна визија мод,Förbättrat läge för mörkerseende,Geliştirilmiş gece görüş modu, +ENV shows stealth monsters,GLPREFMNU_ENVSTEALTH,,,,Vylepšené noční vidění ukazuje skryté příšery,ENV viser stealth-monstre,Nachtsichtmodus zeigt Stealth-Monster,,ENV montras kaŝiĝitajn monstrojn,ENV muestra enemigos sigilosos,,PPN näyttää näkymättömät hirviöt,VNA affiche monstres invisibles,ENV felfedi a lopakodó szörnyeket,La VNM mostra i mostri stealth ,暗視バイザーが透明を見破る,스텔스 적 개체를 감지하는 ENV,ENV toont stealth monsters,ENV viser stealth monstre,Ulepszony noktowizor pokazuje ukrywających się przeciwników,Visão noturna mostra monstros invisíveis,,PNV afișează monștri ascunși,ПНВ показывает скрытых монстров,ПНВ показује скривена чудовишта,ENV visar smygande monster,ENV gizli canavarları gösteriyor, +Adjust sprite clipping,GLPREFMNU_SPRCLIP,,,,Vyladění clippingu spritů,Juster sprite clipping,Sprite Clipping,,Agordi trairadon de mov-rastrumoj,Ajustar recortado de sprites,,Spritejen asettelu,Adjusted le clipping des sprites,Sprite átlógás igazítása,Aggiusta il clipping degli sprite,スプライトのずらしを調整する,스프라이트 클리핑 조정,Sprite clipping,Juster sprite klipping,Ustaw wcięcie sprite'ów,Ajustar clipping de sprite,,Ajustare poziții sprite-uri,Режим обрезки спрайтов,Подеси спрајт клипинг,Justera sprite clipping,Sprite kırpmayı ayarlama, +Smooth sprite edges,GLPREFMNU_SPRBLEND,,,,Vyhladit okraje spritů,Udglatte sprite-kanter,Glätte Spritekanten,,Glatigi randojn de mov-rastrumoj,Suavizar bordes de sprites,,Pehmeät spritejen reunat,Adoucir bords des sprites,Sprite szélek simítása,Smussa gli angoli degli sprite,スプライトの角を丸める,부드러운 스프라이트 모서리,Gladde sprite randen,Glatte sprite kanter,Gładkie krawędzie sprite'ów,Suavizar bordas de sprites,,Netezire margini sprite-uri,Размытие краёв спрайтов,Углачати ивице спрајта,Slätar ut sprite-kanter,Düzgün sprite kenarları, +Fuzz Style,GLPREFMNU_FUZZSTYLE,,,,Styl šumu,Fuzz-stil,Fuzz Stil,,Stilo de Lenugo,Estilo de difuminación,,Sumennustyyli,Style de bruit blanc,Homályosítás stílusa,Stile fuzz,ファズスタイル,퍼즈 스타일,Fuzz stijl,Fuzz-stil,Styl Szumu,Estilo de difusão,,Stil sclipire,Тип шума,Фаз стајл,Fuzz stil,Fuzz Tarzı, +Sprite billboard,GLPREFMNU_SPRBILLBOARD,,,,Orientace spritů,,Spriteausrichtung,,Liniigi mov-rastrumojn,Alineado de sprites,,Spritetaulu,Etalage des sprites,Sprite alapú reklámtábla,,スプライト ビルボード,스프라이트 샘플링,,,Wyrównanie Sprite'ów,Alinhamento de sprite,,Rotire sprite-uri,Привязка по осям спрайтов,Спрајт билборд,,Sprite reklam panosu, +Sprites face camera,GLPREFMNU_SPRBILLFACECAMERA,,,,Sprity čelí kameře,Sprites vender mod kameraet,Sprites zur Kamera ausrichten,,Mov-rastrumoj ĉiam rigardas vian kameraon,Los sprites miran a la cámara,,Spritet suuntaavat kameraan,Sprites font face à la caméra,Sprite alapú kamera,Gli sprite sono rivolti alla telecamera.,スプライトのフェイスカメラ,카메라를 향한 스프라이트,Sprites gezicht camera,Sprites vender mot kameraet,Sprite'y skierowane w kamerę,Sprites de frente para a câmera,,Sprite-urile privesc înspre cameră,Спрайты направлены к камере,Спрајт камера фаце,Sprites vänder sig mot kameran,Sprite'lar kamerayla yüzleşir, +Particle style,GLPREFMNU_PARTICLESTYLE,,,,Styl částic,Partikelstil,Partikelstil,,Partikla stilo,Estilo de partículas,,Hiukkastyyli,Style de particules,Részecske stílusa,Stile particelle,パーティクル スタイル,입자 스타일,Deeltjes stijl,Partikkel-stil,Styl Cząsteczek,Tipo de partícula,,Stil particule,Тип частиц,Честице стајл,Partikelstil,Parçacık stili, +Rendering quality,GLPREFMNU_RENDERQUALITY,,,,Kvalita vykreslování,Renderingskvalitet,Renderqualität,,Kvalito de bildigado,Calidad de Renderizado,,Hahmonnuslaatu,Qualité du rendu,Renderelés minősége,Qualità resa grafica,レンダリング品質,렌더링 품질,Het teruggeven van kwaliteit,Renderingskvalitet,Jakość Renderowania,Qualidade de renderização,,Calitate video,Качество обработки,Квалитет рендовања,Renderingskvalitet,Render kalitesi, +Stereo 3D VR,GLPREFMNU_VRMODE,,,,,,,,Duvida 3D VR,Modo Stereo 3D VR,,,3D VR Stéréo,,,ステレオ3DのVR,VR 입체 스테레오 사용,,,,3D Estéreo (VR),,Mod VR,Стерео 3D VR-режим,Стереотоно 3D VR,,, +Enable Quad Stereo,GLPREFMNU_VRQUADSTEREO,,,,Povolit Quad Stereo,Aktiver Quad Stereo,Quad Stereo aktivieren,,Ŝalti Kvaroblo-Stereon,Activar Quad Stereo,,Ota käyttöön Quad Stereo,Activer Quad Stereo,Quad Sztereó bekapcsolása,Abilita il Quad Stereo,クァッドステレオを有効,쿼드 스테레오 사용,Quad Stereo inschakelen,Aktiver Quad Stereo,Włącz Poczwórne Stereo,Habilitar Quad Stereo,Permitir Quad Stereo,Activare Quad Stereo,Четырёхкратный стереорежим,Омогући четвороструки стерео,Aktivera Quad Stereo,Dörtlü Stereoyu Etkinleştir, +Banded SW Lightmode,GLPREFMNU_SWLMBANDED,,,,Režim pruhovaného SW osvětlení,Båndede SW-lystilstand,Gebänderter SW-Lichtmodus,,Reĝimo de Bendiga Lumo de Programbildigo,Modo de luz por bandas de SW,,Kaistoitettu ohjelmistoväritila,Lumière bandées en Software,,Lightmode software bandata,バンデドSWライトモード,단결된 SW 라이트 모드,SW-lichtmodus met banden,Båndet SW-lysmodus,Naznaczony Tryb Oświetlenia Oprogramowania,Modo de luz por bandas em software,,Mod limitat de iluminare Software,Программный режим освещения полосами,Повезани SW режим осветљења,SW Ljusläge i bandform,Bantlı SW Işık Modu, +Distance Between Your Eyes,GLPREFMNU_VRIPD,,,,Vzdálenost mezi očima,Afstand mellem øjnene,Abstand zwischen den Augen,,Distanco Inter Viaj Okuloj,Distancia entre tus ojos,,Silmiesi etäisyys toisistaan,Distance entre vos yeux,Szemek közötti távolság,Distranza tra i tuoi occhi,自分の目との距離,시야 간의 거리,Afstand tussen uw ogen,Avstand mellom øynene dine,Odległość Pomiędzy Twoimi Oczami,Distância entre os olhos,,Distanța dintre ochi,Расстояние между глазами,Даљина између твојих очију,Avstånd mellan ögonen,Gözleriniz Arasındaki Mesafe, +Distance From Your Screen,GLPREFMNU_VRSCREENDIST,,,,Vzdálenost od obrazovky,Afstand fra din skærm,Abstand vom Bildschirm,,Distanco De Via Ekrano,Distancia desde tu pantalla,,Etäisyys ruudullesi,Distance entre vous et l'écran,Képernyőtől mért távolság,Distanza dal tuo schermo,画面からの距離,화면과의 거리,Afstand van uw scherm,Avstand fra skjermen,Odległość Od Twojego Ekranu4,Distância a partir da tela,,Distanța față de ecranul tău,Расстояние от экрана,Даљина од окрена,Avstånd från skärmen,Ekranınızdan Uzaklık, +Smart,OPTVAL_SMART,,,,Chytré,,,,Inteligenta,Inteligente,,Älykäs,Intelligent,Okos,Intelligente,スマート,자동 조정,Slim,,Mądry,Inteligente,,Inteligent,Умный,Паметно,,Akıllı, +Smarter,OPTVAL_SMARTER,,,,Chytřejší,Smartere,,,Pli inteligenta,Más inteligente,,Älykkäämpi,+ Intelligent,Okosabb,Ancora più intelligente,よりスマート,고급 자동 조정,Slimmer,Smartere,Mądrzejszy,Mais inteligente,,Mai inteligent,Умнее,Паметније,Smartare,Daha Akıllı, +Infrared only,OPTVAL_INFRAREDONLY,,,,Pouze infračervené,Kun infrarødt,Nur Infrarot,,Nur transruĝa,Solo infrarrojo,,Vain infrapuna,Vis. Noct. Seulement,Csak az infravörösnél,Solo infrarossi,赤外線のみ,야시경만,Alleen infrarood,Kun infrarød,Tylko Podczerwień,Somente infravermelho,,Doar în infraroșu,Только инфракрасный,Само инфрацрвена,Endast infrarött ljus,Sadece kızılötesi, +Infrared and torch,OPTVAL_INFRAREDANDTORCH,,,,Infračervené a pochodeň,Infrarød og lommelygte,Infrarot und Fackel,,Transruĝa kaj torĉo,Infrarrojo y antorcha,,Vain infrapuna ja soihtu,Iis Noct. & Torche,Infravörös és fáklya,Infrarossi e torcia,赤外線と松明,야시경과 횃불만,Infrarood en fakkels,Infrarød og lommelykt,Tylko Podczerwień i Pochodnie,Infravermelho e tocha,,Infraroșu si torță,Инфракрасный и факел,Инфрацрвена/бакља,Infraröd och ficklampa,Kızılötesi ve fener, +Any fixed colormap,OPTVAL_ANYFIXEDCOLORMAP,,,Any fixed colourmap,Jakákoli fixní mapa barev,Alle lyseffekter,Alle Lichteffekte,,Iu ajn fiksita kolormapo,Cualquier mapa de color fijo,,Mikä tahansa kiinteä värikartta,N'importe quelle colormap,Bármely fixált colormap,Ogni colormap fissata,任意の固定カラーマップ,고정된 컬러맵만,Elke vaste colormap,Alle faste fargekart,Którekolwiek naprawione mapy kolorów,Qualquer colormap fixo,,Orice colormap,Любая заданная цветовая карта,Било која поправљена табела боја,Alla fasta färgkartor,Herhangi bir sabit renk haritası, +Use as palette,OPTVAL_USEASPALETTE,,,,Použít jako paletu,Brug som palet,Benutze als Palette,,Uzi kiel paletro,Usar como paleta,,Käytä palettina,Utiliser comme pallette,Palettaként használat,Utilizza come palette,パレットとして使用,팔레트로 적용,Gebruik als palet,Bruk som palett,"Użyj jako palety +",Usar como paleta,Usar como palete,Utilizare drept paletă,Использовать как палитру,Користи као палету,Används som palett,Palet olarak kullanın, +Blend,OPTVAL_BLEND,,,,Míchat,,Überblenden,,Miksi,Mezclar,,Sekoitus,Mélanger,Kever,Miscela,混合,혼합,Mengen,Blanding,Połącz,Mesclar,Misturar,Amestec,Смешать,Бленд,Blanda,Karışım, +Bright,OPTVAL_BRIGHT,,,,Světlý,Lys,Hell,,Hela,Brillante,,Kirkas,Clair,Világos,Chiara,明るい,밝은,Helder,Lys,Jasne,Claro,,Luminos,Яркий,Свијетло,Ljusa,Parlak, +Dark,OPTVAL_DARK,,,,Tmavý,Mørk,Dunkel,,Malhela,Oscuro,,Tumma,Sombre,Sötét,Scura,暗い,어두운,Donker,Mørk,Ciemne,Escuro,,Întunecat,Тёмный,Тамно,Mörk,Karanlık, +Doom Legacy,OPTVAL_LEGACY,"This refers to the Doom Legacy port, not a legacy lighting style!",,,,,,,,,,,,,,,,,,,,,,,,,, +Software,OPTVAL_SOFTWARE,,,,,,,,Programa bildigilo,,,Ohjelmisto,,Szoftver,,ソフトウェア,소프트웨어,,,Oprogramowanie,,,,Программный,Софтвер,Programvara,Yazılım, +Optimal,OPTVAL_OPTIMAL,,,,Optimální,,,,Optima,Óptimo,,Optimaalinen,Optimiser,Optimális,Ottimale,最適,최적함,Optimaal,,Optymalne,Otimizado,,Optim,Оптимальный,Оптимал,Optimal,Optimal, +Y Axis,OPTVAL_YAXIS,,,,Po ose Y,Y-akse,Y-Achse,,Y-Akso,Eje Y,,Y-akseli,Axe Y,Y tengely,Asse Y,縦軸,Y 축,Y-as,Y-akse,Oś Y,Eixo Y,,Axa Y,По горизонтали,Y оса,Y-axeln,Y Ekseni, +X/Y Axis,OPTVAL_XYAXIS,,,,Po osách X/Y,X/Y-akse,X/Y-Achse,,X/Y-Akso,Ejes X/Y,,X- ja Y-akselit,Axes X/Y,X/Y tengely,Asse X/Y,縦/横軸,X/Y 축,X/Y As,X/Y-akse,Oś X/Y,Eixo X/Y,,Axa Y/Z,По обеим осям,X/Y оса,X/Y-axel,X/Y Ekseni, +Square,OPTVAL_SQUARE,,,,Čtvercové,Firkantet,Quadratisch,,Kvadrata,Cuadrado,,Kulmikas,Carrées,Négyzet,Quadrato,平方,정사각형,Vierkant,Firkantet,Kwadrat,Quadrado,,Pătrat,Квадратные,Квадрат,Kvadratisk,Kare, +Round,OPTVAL_ROUND,,,,Kulaté,Rund,Rund,,Ronda,Redondo,,Pyöreä,Rondes,Kör,Arrotondato,円形,원형,Rond,Rund,Okrągłe,Redondo,,Rotund,Круглые,Круг,Rund,Yuvarlak, +Radial,OPTVAL_RADIAL,,,,Radiální,,,Ακτινικό,Radiusa,,,Säteittäinen,,Sugaras,Radiale,放射状,방사형,Radiaal,,Promieniowe,,,Radială,Радиальный,Радијално,Radial,Radyal, +Pixel fuzz,OPTVAL_PIXELFUZZ,,,,Pixelový fuzz,,Pixel,Pixel θολούρα,Bildera lanugo,Difuminado pixelado,,Kuvapistesumennus,Bruit Pixélisé,Pixeles homály,Fuzz pixelato,ピクセル ファズ,픽셀 퍼즈,Pixel fuzz,,Szum pikseli,Difuso pixelado,,Puf,Пиксельный шум,Пикселизовани фаз,,Piksel fuzz, +Smooth fuzz,OPTVAL_SMOOTHFUZZ,,,,Hladký fuzz,Glat fuzz,Glatt,Ομαλή θολούρα,Glata lanugo,Difuminado borroso,,Pehmeä sumennus,Bruit doux,Simított homály,Fuzz liscio,滑らかなファズ,부드러운 퍼즈,Gladde fuzz,Glatt fuzz,Wygładzony szum,Difuso suavizado,,Lin,Гладкий шум,Глатки фаз,Slät fuzz,Pürüzsüz fuzz, +Swirly fuzz,OPTVAL_SWIRLYFUZZ,,,,Míchající fuzz,Svirklende fuzz,Gewirbelt,Περιστροφηκή θολούρα,Kirla lanugo,Difuminado en remolino, ,Pyörteinen sumennus,Bruit marbré,Örvénylő homály,Fuzz vorticoso,渦状ファズ,소용돌이 퍼즈,Zwerpend fuzz,Virvlende fuzz,Wirujący szum,Difuso encaracolado,,Vârtej,Кружащийся шум,Увртен фаз,Virvlande fuzz,Girdaplı fuzz, +Translucent fuzz,OPTVAL_TRANSLUCENTFUZZ,,,,Průhledný fuzz,Gennemskinnelig fuzz,Transparent,Ημιδιαφανής θολούρα,Diafana lanugo,Difuminado Translúcido,,Läpikuultava sumennus,Bruit transparent,Áttetsző homály,Fuzz traslucido,半透明ファズ,반투명 퍼즈,Doorschijnende fuzz,Gjennomsiktig fuzz,Przezroczysty szum,Difuso translúcido,,Transparent,Прозрачный шум,Прозрачан фаз,Genomskinlig fuzz,Yarı saydam fuzz, +Noise,OPTVAL_NOISE,,,,Šum,Støj,Rauschen,Ήχος,Bruo,Ruido,,Kohina,Neige,Zaj,Rumore,ノイズ,노이즈,Lawaaierige fuzz,Støy,Huk,Ruído,,Zgomot,Шум,Звук,Buller,Gürültü, +Smooth Noise,OPTVAL_SMOOTHNOISE,,,,Hladký šum,Glat støj,Geglättetes Rauschen,Ομαλός ήχος,Glata Bruo,Ruido borroso,,Pehmeä kohina,Neige adoucie,Simított zaj,Rumore liscio,滑らかなノイズ,부드러운 노이즈,Gladde lawaaierige fuzz,Glatt støy,Wugładzony huk,Ruído suavizado,,Zgomot lin,Мягкий шум,Милозвучан звук,Slätt brus,Yumuşak Gürültü, +Jagged fuzz,OPTVAL_JAGGEDFUZZ,,,,Zubatý šum,Skarpt fuzz,Gezackt,Ζαρομένη θολούρα,Malglateca lanugo,Difuminado dentado,,Sahalaitainen sumennus,Neige rugeuse,Recés homály,Fuzz frastagliato,ギザギザ,들쭉날쭉한 퍼즈,Gekartelde fuzz,Takkete fuzz,Poszarpany szum,Difuso serrilhado,,Zimțat,Зазубренный шум,Назубљен фаз,Skarvig fuzz,Pürüzlü fuzz, +Green/Magenta,OPTVAL_GREENMAGENTA,,,,Zelená/purpurová,Grøn/Magenta,Grün/Magenta,Πράσινο/Magenta,Verda/Magenta,Verde/Magenta,,Vihreä/Magenta,Vert/Magenta,Zöld/Magenta,Verde/Magenta,緑/紫,초록/심홍색,Groen/Magenta,Grønn/magenta,Zielony/Magenta,Verde/Magenta,,Verde/Purpuriu,Зелёный/пурпурный,Зелен/Магента,Grön/Magenta,Yeşil/Macenta, +Red/Cyan,OPTVAL_REDCYAN,,,,Červená/tyrkysová,Rød/Cyan,Rot/Cyan,Κόκινο/Κυανό,Ruĝa/Cejana,Rojo/Cian,,Punainen/Sinivihreä,Rouge/Bleu,Piros/Türkiz,Rosso/Ciano,赤/空,빨강/하늘색,Rood/Cyaan,Rød/cyan,Czerwony/Błękitny,Vermelho/Ciano,,Roșu/Turcoaz,Красный/голубой,Црвен/Цијан,Röd/Cyan,Kırmızı/Mavi, +Amber/Blue,OPTVAL_AMBERBLUE,,,,Oranžová/modrá,Rav/blå,Orange/Blau,Amber/Μπλέ,Sukcenokolora/Blua,Ámbar/Azul,,Ruskeankeltainen/Sininen,Ambre/Bleu,Sárga/Kék,Ambra/Blu,黄/青,황토/파랑색,Amber/Blauw,Rav/blå,Bursztynowy/Niebieski,Âmbar/Azul,,Chihlimbar/Albastru,Янтарный/синий,Ћилибарски/Плаво,Bärnsten/blått,Kehribar/Mavi, +Left Eye,OPTVAL_LEFTEYE,,,,Levé oko,Venstre øje,Linkes Auge,Αριστερό μάτι,Maldekstra Okulo,Ojo izquierdo,,Vasen silmä,Oeil Gauche,Bal szem,Occhio sinistro,左目,왼쪽 눈,Linkeroog,Venstre øye,Lewe Oko,Olho Esquerdo,,Ochi Stâng,Левый глаз,Лево око,Vänster öga,Sol Göz, +Right Eye,OPTVAL_RIGHTEYE,,,,Pravé oko,Højre øje,Rechtes Auge,Δεξί μάτι,Dekstra Okulo,Ojo derecho,,Oikea silmä,Oeil Droit,Jobb szem,Occhio destro,右目,오른쪽 눈,Rechteroog,Høyre øye,Prawe Oko,Olho Direito,,Ochi drept,Правый глаз,Десно око,Höger öga,Sağ Göz, +Side-by-side Full,OPTVAL_SBSFULL,,,,"Vedle sebe, plné",Side ved side i fuld bredde,Nebeneinander volle Breite,,Flank-ĉe-flanka Tuta,Lado a lado completo,,Täysi rinnakkaisasettelu,Côte-â-côte Complet,Egymás melletti Teljes,Fianco a fianco completo,両サイド フル,크게 좌우배치,Zij-aan-zij Volledig,Side-ved-side Full,Pełne Obok Siebie,Lado a lado completo,,Una lângă alta Pline,"Бок о бок, полно",Раме уз раме цело,Sidoordnat fullt ut,Yan yana Tam, +Side-by-side Narrow,OPTVAL_SBSNARROW,,,,"Vedle sebe, úzké",Side ved side i halv bredde,Nebeneinander halbe Breite,,Flank-ĉe-flanka Mallarĝa,Lado a lado estrecho,,Kapea rinnakkaisasettelu,Côte-â-côte étroit,Egymás melletti Szűk,Fianco a fianco stretto,両サイド ナロー,좁게 좌우배치,Zij-aan-zij smal,Side ved side Smal,Wąskie Obok Siebie,Lado a lado estreito,,Una lângă alta Înguste,"Бок о бок, узко",Раме уз раме уско,Sidoväggar smal,Yan yana Dar, +Top/Bottom,OPTVAL_TOPBOTTOM,,,,Nad sebou,Øverst/underst,Übereinander,Πάνω/Κάτω,Supero/Subo,Superior/Inferior,,Ylä-/Alaosa,Dessus/Dessous,Fent/Lent,Sopra/Sotto,天/底,위/아래,Boven/onderkant,Topp/Bunn,Góra/Dół,Superior/Inferior,,Sus/Jos,Сверху/снизу,Врх/Дно,Överst/underst,Üst/Alt, +Row Interleaved,OPTVAL_ROWINTERLEAVED,,,,Po řádcích,Forskydning af rækker,Zeilenversetzt,,Vicoj interteksitaj,Fila intercalada,,Vaakalomitus,Entrelacement rangée,Sor beillesztés,Riga interfogliata,行インターリーブ,열 교차 배치,Rij interleaved,Rad sammenflettet,Przepleciony Szereg,Linha Intercalada,,Rând intercalat,Чередование строк,Редно прошарано,Rad med interfolierad rad,Satır Aralıklı, +Column Interleaved,OPTVAL_COLUMNINTERLEAVED,,,,Po sloupcích,Forskydning af kolonner,Spaltenversetzt,,Kolonoj interteksitaj,Columna intercalada,,Pystylomitus,Entralcement colonne,Oszlop beillesztés,Colonna interfogliata,列インターリーブ,세로줄 교차 배치,Kolom Interleaved,Kolonne sammenflettet,Przepleciona Kolumna,Coluna Intercalada,,Coloană intercalată,Чередование столбцов,Колонско прошарано,Kolumn interfolierad,Sütun Aralıklı, +Checkerboard,OPTVAL_CHECKERBOARD,,,,Šachovnice,Ternet,Schachbrettmuster,,Ŝaktablo,Tablero de damas,,Shakkilautakuvio,Damier,Tábla,Scacchiere,市松模様,체크무늬,Dambord,Sjakkbrett,Szachownica,Xadrez,,Tablă de Șah,Шахматная доска,Шаховска табла,Tärningsbräda,Dama Tahtası, +Quad-buffered,OPTVAL_QUADBUFFERED,,,,Quad buffer,Quad-buffered,Vierfachgepuffert,,Kvarobla bufro,Cuádruple búfer,,Neloispuskurointi,Quadruple-tampon,Négyszeresen bufferelt,Quad buffer,クワッドバッファー,쿼드 버퍼,Viervoudig gebufferd,Firebufret,Poczwórnie zbuforowane,Buffer quádruplo,,Împătrit,Четырёхкратный,Квад-унапређено,Kvadratbuffrad,Dört tamponlu, +TrueColor Options,DSPLYMNU_TCOPT,,,,Nastavení True color,TrueColor-indstillinger,TrueColor Optionen,TrueColor Ρυθμίσεις,Plenkolora Agordoj,Opciones TrueColor,,TrueColor-asetukset,Options TrueColor,TrueColor Beállítások,Opzioni TrueColor,トゥルーカラー オプション,트루 컬러 설정,TrueColor Opties,TrueColor-alternativer,Opcje TrueColor,Opções de TrueColor,,Setări Mod Culori Complete,Полноцветный режим,Подешавања правих боја,TrueColor-alternativ,TrueColor Seçenekleri, +TrueColor Options,TCMNU_TITLE,,,,Nastavení True color,TrueColor-indstillinger,TrueColor Optionen,TrueColor Ρυθμίσεις,Plenkolora Agordoj,Opciones TrueColor,,TrueColor-asetukset,Options TrueColor,TrueColor Beállítások,Opzioni TrueColor,トゥルーカラー オプション,트루 컬러 설정,TrueColor Opties,TrueColor-alternativer,Opcje TrueColor,Opções de TrueColor,,Setări Mod Culori Complete,Настройки полноцветности,Подешавања правих боја,TrueColor-alternativ,TrueColor Seçenekleri, +True color output,TCMNU_TRUECOLOR,,,,Výstup True color,TrueColor-udgang,TrueColor Ausgabe,TrueColor παραγωγή,Plenkolora eligo,Salida de True color,,True color -ulostulo,Sortie Truecolor,Truecolor Kimenet,Output true color,トゥルーカラー出力,트루 컬러 출력,Ware kleurenoutput,Ekte fargeutgang,Wyjście TrueColor,Saída de true color,,Putere Mod Culori Complete,Полноцветный вывод,Излаз правих боја,Utmatning i äkta färg,Gerçek renk çıkışı, +Linear filter when downscaling,TCMNU_MINFILTER,,,,Lineární filtrování při zmenšení,Lineært filter ved nedskalering,Linearer Filter beim Herunterskalieren,Γραμμικό φίλτρο για σμίκρυνση,Linia filtro kiam subskali,Filtro lineal por reducción,,Lineaarinen suodatin alas skaalatessa,Filtrage linéaire en réduction,Lineáris filterezés leméretezésnél,Filtro lineare per la riduzione,縮小時のリニアフィルター,축소시 선형 필터링함,Lineair filter voor downscaling,Lineært filter ved nedskalering,Liniowy filtr podczas zmniejszania rozmiaru,Filtro linear ao reduzir,,Filtru liniar la micșorare,Линейная фильтрация при уменьшении,Линеарни филтер током смањења,Linjärt filter vid nedskalning,Küçültme sırasında doğrusal filtre, +Linear filter when upscaling,TCMNU_MAGFILTER,,,,Lineární filtrování při zvětšení,Lineært filter ved opskalering,Linearer Filter beim Hochskalieren,Γραμμικό φίλτρο για πολυτέληση,Linia filtro kima superskali,Filtro lineal por escalado,,Lineaarinen suodatin ylös skaalatessa,Filtrage linéaire en agrandissement,Lineáris filterezés felméretezésnél,Filtro lineare per l'aumento,拡大時のリニアフィルター,확대시 선형 필터링함,Lineair filter voor upscaling,Lineært filter ved oppskalering,Liniowy filtr podczas zwiększania rozmiaru,Filtro linear ao aumentar,,Filtru liniar la mărire,Линейная фильтрация при увеличении,Линеарни филтер током повећања,Linjärt filter vid uppskalning,Yükseltme sırasında doğrusal filtre, +Use mipmapped textures,TCMNU_MIPMAP,,,,Použít mipmapy,Brug mipmapped teksturer,Benutze Textur-Mipmaps,Χρήση mipmapped υφών,Uzi mipmapajn teksturojn,Usar texturas con mipmap,,Käytä mipkartallisia pintakuviointeja,Utiliser textures mipmappées,Mipmap textúrák,Usa le texture mipmapped,ミップマップテクスチャを使用,밉맵 텍스쳐 사용,Gebruik mipmapped texturen,Bruk mipmapped teksturer,Użyj mipmapowane tekstury,Usar texturas com mipmapping,,Mip mapping pentru texturi,Применять MIP-текстурирование,Користи мипмаповане текстуре,Använd mipmappade texturer,Eşlenmiş dokular kullanın, +Dynamic lights (Software),TCMNU_DYNLIGHTS,,,,Dynamická světla (software),Dynamisk lys (software),Dynamisches Licht (Software),Δυναμικά φώτα (Λογισμικό),Dinamikaj lumoj (Programbildigilo),Luces dinámicas (Software),,Dynaamiset valot (ohjelmisto),Lumières Dynamiques (Software),Dinamikus fények (szoftveres),Luci Dinamiche (Software),ダイナミックライト (ソフトウェア),다이나믹 라이트 (소프트웨어 버전),Dynamische verlichting (software),Dynamiske lys (programvare),Dynamiczne Światło (Oprogramowanie),Luzes Dinâmicas (Software),,Lumini Dinamice (Mod Software),Динамическое освещение (программное),Динамичко осветљење (софтвер),Dynamiskt ljus (programvara),Dinamik ışıklar (Yazılım), +Option Search,OS_TITLE,,,,Vyhledávání možností,Mulighed Søg,Optionssuche,Αναζήτηση Ρυθμίσεων,Agorda Serĉo,Buscar Opciones,,Asetushaku,Recherche Option,Beállítás Keresés,Opzioni di ricerca,オプション検索,옵션 검색,Optie zoeken,Alternativt søk,Szukanie Opcji,Buscar opção,Procurar opção,Căutare Setări,Поиск настройки,Претрага,Alternativ Sök,Seçenek Arama, +Search for any term,OS_ANY,,,,Hledat jakékoli klíčové slovo,Søg efter et vilkårligt begreb,Suche nach beliebigem Begriff,Αναζήτηση για όποιαδηποτε λέξη,Serĉi por iu ajn termino,Buscar cualquier término,,Etsi mitä tahansa sanaa,N'importe quel mot,Bármilyen szótagra keresés,Cerca per ciascun termine,いずれかの用語を探す,용어 검색,Zoek naar eender welke term,Søk etter et vilkårlig begrep,Szukaj jakiegokolwiek wyrażenia,Buscar por qualquer termo,Procurar por um termo qualquer,Căutare după orice termen,Искать любое из слов,Тражи било коју од речи,Sök efter valfri term,Herhangi bir terim için arama yapın, +Search for all terms,OS_ALL,,,,Hledat všechna klíčová slova,Søg efter alle udtryk,Suche nach allen Begriffen,Αναζήτηση για όλες της λέξεις,Serĉi por ĉiuj terminoj,Buscar todos los términos,,Etsi kaikki sanat,Tous les mots,Összes szótagra keresés,Cerca per tutti i termini,全ての用語を探す,모든 조건 검색,Zoek naar alle termen,Søk etter alle termer,Szukaj wszystkich wyrażeń,Buscar por todos os termos,Procurar por todos os termos,Căutare după toți termenii,Искать все слова,Тражи све речи,Sök efter alla termer,Tüm terimler için arama yapın, +No results found.,OS_NO_RESULTS,,,,Nic nenalezeno.,Ingen resultater fundet.,Keine Resultate,Δέν βρέθηκαν αποτελέσματα,Neniuj rezultoj trovitaj.,Ningun resultado.,,Ei tuloksia.,Pas de résultat trouvé,Nincs keresési találat,Nessun risultato trovato.,見つかりませんでした。,검색 결과 없음.,Geen resultaten gevonden.,Ingen resultater funnet.,Brak wyników,Nenhum resultado encontrado.,,Niciun rezultat găsit.,Результаты не найдены.,Нема резултата.,Inga resultat hittades.,Sonuç bulunamadı., +Search:,OS_LABEL,,,,Hledat:,Søg:,Suche:,Αναζήτηση:,Serĉi:,Buscar:,,Etsi:,Recherche:,Keresés:,Trova:,検索:,검색:,Zoeken:,Søk:,Szukaj:,Busca:,Procura:,Căutare:,Поиск:,Претрага:,Sök:,Arama yapın:, +Always show keys,AUTOMAPMNU_SHOWKEYS_ALWAYS,,,,Vždy zobrazit klíče,Vis altid nøgler,Zeige immer alle Schlüssel,Εμφάνιση πλήκτρων πάντα,Ĉiam montri ŝlosilojn,Mostrar llaves siempre,,Aina näytä avaimet,Toujour afficher clés,Kulcsokat mindig mutat,Mostra sempre le chiavi,常にキーを表示,항상 키들을 표시,Toon altijd de toetsen,Vis alltid nøkler,Zawsze pokazuj klucze,Sempre mostrar chaves,Exibir chaves sempre,Afișează cheile în permanență,Всегда отображать ключи,Увек приказуј кључеве,Visa alltid nycklar,Her zaman anahtarları göster, +,,Newly added content,,,,,,,,,,,,,,,,,,,,,,,,,, +Team changing has been disabled!,TXT_NO_TEAM_CHANGE,,,,Změna týmu je vypnuta!,Holdskift er blevet deaktiveret!,Teamwechsel ist deaktiviert!,Η αλαγγή ομάδον απαγορεύεται!,Teamŝanĝiĝo estas malvalidigita!,¡El cambio de equipo ha sido desactivado!,,Joukkueen vaihtaminen on kytketty pois päältä!,Les changements d'équipe sont désactivés!,Csapatváltás letiltva,È stato disabilitato il cambio di squadra!,チームの変更は受け付けない!,팀 변경이 불가능해짐!,Teamwisseling is uitgeschakeld!,Lagbytte har blitt deaktivert!,Zmiana drużyn została wyłączona!,Troca de equipe foi desativada!,Troca de equipa foi desativada!,Schimbarea echipelor a fost dezactivată!,Смена команды была отключена!,Мењање тима је искључено!,Lagbyte har inaktiverats!,Takım değiştirme devre dışı bırakıldı!, +%s joined the %t team,TXT_JOINED_TEAM,%s is the player and gender sensitive,,,%s se připojil@[ao_cs] k týmu %t.,%s er blevet medlem af %t-team,%s is dem %t Team beigetreten.,@[art_gr] %s έγινε μέλος τής %t ομάδας,%s aliĝis al la %t teamo,%s se unió al equipo %t,,%s liittyi joukkueeseen %t,%s a rejoint l'équipe %t.,%s belépett a %t csapatba,%s entra nel team %t,%s は %t のチームに入隊した,%s 이(가) %s 팀에 합류함,%s zijn bij het %t team gekomen.,%s ble med i %t-teamet,%s dołącza do drużyny %t,%s entrou na equipe %t,,%s s-a alăturat echipei %t,Игрок %s присоединяется к команде %t,%s је уш@[ao_2_sr] у %t тим,%s anslöt sig till %t teamet.,%s %t takımına katıldı, +%s is now a loner.,TXT_LONER,,,,%s je teď @[self_cs].,%s er nu en enspænder.,%s ist jetzt ein@[e_de] Einzelgänger@[in_de].,@[art_gr] %s είναι τώρα μόνο/ς/η @[pro4_gr],%s nun estas solemulo.,%s es ahora solitari@[ao_esp].,,%s on nyt yksikseen.,%s joue maintenant tout seul.,%s immáron magányos útralépett,%s è da solo,%s は今 一匹狼だ。,%s 은(는) 혼자 남음.,%s is nu een eenling.,%s er nå en einstøing.,%s jest teraz sam@[ao_pl],%s está sozinh@[ao_ptb] agora.,,%s este singur acum,Игрок %s теперь одиночка.,%s је сада самотњак.,%s är nu en ensamvarg.,%s artık yalnız., +%s left the game with %d frags,TXT_LEFTWITHFRAGS,,,,%s opustil@[ao_cs] hru s %d fragy,%s forlod spillet med %d frags,%s hat das Spiel mit %d Frags verlassen.,@[art_gr] %s έφυγε με %d κοματιασμόυς,%s eliris el la ludo kun %d ludmurdoj,%s salió de la partida con %d bajas,,%s poistui pelistä frägimäärällä %d,%s a quitté le jeu avec %d frags.,%s kilépett %d fraggel,%s ha lasciato il gioco con %d frag,"%s が逃げ出したので %d に点が入った +",%s 이(가) 게임에서 %d 의 점수를 기록하고 퇴장 함.,%s verliet het spel met %d frags,%s forlot spillet med %d frags,%s opuścił@[ao_pl] grę z %d fragami,%s saiu do jogo com %d frags,,%s a părăsit jocul cu %d victime,Игрок %s покидает игру с количеством фрагов: %d,%s је изаш@[ao_2_sr] из игре са %d фраговима.,%s lämnade spelet med %d frags,%s oyunu %d frag ile terk etti, +%s left the game,TXT_LEFTTHEGAME,,,,%s opustil@[ao_cs] hru,%s forlod spillet,%s hat das Spiel verlassen.,@[art_gr] %s έφυγε,%s eliris el la ludo,%s salió de la partida,,%s poistui pelistä,%s a quitté le jeu.,%s kilépett,%s ha lasciato il gioco,%s は退出した,%s 이(가) 게임을 떠남.,%s verliet het spel,%s forlot spillet,%s opuścił@[ao_pl] grę,%s saiu do jogo,,%s a părăsit jocul,Игрок %s покидает игру,%s је изаш@[ao_2_sr] из игре,%s har lämnat spelet.,%s oyundan ayrıldı, +Could not read savegame '%s'.,TXT_COULDNOTREAD,,,,Nepodařilo se načíst uloženou hru '%s'.,Kunne ikke læse savegame '%s'.,Konnte Spielstand '%s' nicht lesen.,Το αρχείο αποθήκευσης %s δέν μπόρε να φορτωθεί,Ne povis legi la konservitan ludon '%s'.,No se pudo leer la partida guardada '%s'.,,Pelitallennetta '%s' ei voitu lukea.,Impossible de lire la sauvegarde '%s'.,A '%s' nem tölthető be.,Non si è potuto leggere il salvataggio '%s'.,%s' のセーブデータを読み込めなかった。,저장된 게임을 불러올 수 없습니다.'%s',Kon het savegame '%s' niet lezen.,Kunne ikke lese savegame '%s'.,Nie można odczytać zapisu „%s”.,"Não foi possível ler o jogo salvo ""%s"".","Não foi possível ler o jogo guardado ""%s"".",Salvarea '%s' nu a putut fi citită.,Невозможно прочитать сохранение: «%s».,Није могуће прочитати сачувану игру %s.,"Kunde inte läsa sparspelet ""%s"".",%s' kayıt oyunu okunamadı., +%s' is not a valid savegame: Missing 'info.json'.,TXT_NOINFOJSON,,,,%s' není funkční uloženou hrou: Chybí 'info.json'.,%s' er ikke et gyldigt savegame: Mangler 'info.json'.,%s' ist kein gültiger Spielstand. 'info.json' fehlt.,Το %s δεν είναι ένα έγκυρο αρχείο αποθήκευσης: Το info.json λείπει,%s' ne estas valida konservita ludo: Mankante 'info.json'.,%s' no es una partida guardada válida: Falta 'info.json'.,,%s' ei ole kelvollinen pelitallenne. Puuttuva 'info.json'.,%s n'est pas une sauvegarde valide. Fichier 'info.json' manquant.,%s' nem egy valós mentés: Hiányzó 'info.json'.,%s' non è un salvataggio valido: 'info.json' mancante.,%s' は有効なセーブデータ ではない: 'info.json'が不明。,%s' 는 유효하지 않습니다: 파일이 없습니다.'info.json',"%s"" is geen geldig savegame: Ontbreekt 'info.json'.",%s' er ikke et gyldig savegame: Mangler 'info.json'.,"„%s” nie jest prawidłowym zapisem gry: Brak „info.json” ","""%s"" não é um jogo salvo válido: Está faltando ""info.json"".","""%s"" não é um jogo gravado válido: Está faltando -""info.json"".",%s' nu este o salvare validă. Lipsește 'info.json',Сохранение «%s» некорректно: отсутствует «info.json».,%s није валидно сачувана игра: Недостаје „info.json“. -Failed to access savegame info in '%s'.,TXT_FAILEDTOREADSG,,,,Nepodařily se načíst informace v uložené hře '%s'.,Konnte Spielstandinfo in '%s' nicht lesen.,Η πρόσβαση πληροφοριών του αρχείου αποθήκευσης %s δέν ήταν επιτυχής,Malsukcesis aliri informon de la konservludo en '%s'.,Fallo al acceder a información de partida guardada en '%s'.,,Tiedoston '%s' pelitallennetietoihin ei päästy käsiksi.,Impossible d'accéder aux infos de sauvegarde dans le fichier '%s'.,,Accesso alle informazioni sul salvataggio in '%s' fallito.,%s' のセーブデータにアクセス出来なかった。,%s'의 저장된 게임 정보에 액세스 할 수 없습니다.,Geen toegang tot de opgeslagen informatie in '%s'.,Nie udało się dostać informacji zapisu „%s”.,"Não foi possível acessar a informação do jogo salvo em ""%s"".","Não foi possível acessar a informação do jogo gravado em ""%s"".",Nu s-au putut accesa informațiile din salvarea '%s'.,Невозможно получить информацию из сохранения «%s».,Не успешно пристопљено инфу сачуване игре %s. -Savegame '%s' is from an incompatible version.,TXT_INCOMPATIBLESG,,,,Uložená hra '%s' je z nekompatibilní verze.,Spielstand '%s' ist von einer inkompatiblen Version.,Το αρχείο αποθήκευσης %s είναι απο μια ασύμβατη έκδοση,Konservita ludo '%s' estas el nekongrua versio.,La partida guardada '%s' es de una versión no compatible.,,Pelitallenne '%s' on yhteensopimattomasta versiosta.,La sauvegarde '%s' vient d'une version incompatible.,,Il salvataggio '%s' proviene da una versione incompatibile.,%s' は互換性の無いバージョンのセーブデータだ。,저장된 게임'%s'은(는) 호환되지 않는 버전입니다.,Savegame '%s' komt uit een incompatibele versie.,Zapis gry „%s” jest z niekompatybilnej wersji.,"O jogo salvo ""%s"" é de uma versão incompatível.","O jogo gravado ""%s"" é de uma versão incompatível.",Salvarea '%s' este dintr-o versiune incompatibilă.,Сохранение «%s» из несовместимой версии порта.,Сачувана игра %s је из инкомпетабилне верзије. -Savegame '%s' is from another ZDoom-based engine:,TXT_OTHERENGINESG,,,,Uložená hra '%s' je z jiného enginu založeného na ZDoomu:,Spielstand '%s' ist von einer anderen ZDoom-basierten Engine:,Το αρχείο αποθήκευσης %s είναι απο μια άλλη ZDoom βασισμένη μηχανή,Konservita ludo '%s' estas el alia ZDoom-bazita modulo:,La partida guardada '%s' es de otro motor basado en ZDoom:,,Pelitallenne '%s' on toisesta ZDoom-pohjaisesta moottorista.,La sauvegarde '%s' vient d'un autre moteur basé sur ZDoom:,,Il salvataggio '%s' proviene da un altro motore basato su ZDoom:,%s' は別のZDoom型のセーブデータだ。,저장된 게임 '%s'은(는) 다른 Z둠 기반 엔진입니다:,Savegame '%s' is van een andere ZDoom-gebaseerde engine:,Zapis gry „%s” jest z innego silnika bazowanego na ZDoomie:,"O jogo salvo ""%s"" é de outra engine baseada em ZDoom:","O jogo gravado ""%s"" é de outro motor baseado em ZDoom:",Salvarea '%s' este dintr-un alt motor care are ca bază ZDoom:,"Сохранение «%s» из другого, основанного на ZDoom, движка:",Сачувана игра %s је из други ZDoom-базиран енџин: -Savegame '%s' is from an older version: %d (%e is the oldest supported),TXT_TOOOLDSG,,,,Uložená hra '%s' je ze starší verze: %d (%e je nejstarší podporovaná verze),Spielstand '%s' ist von einer älteren Version: %s (%e ist die älteste noch unterstützte Version,Το αρχείο αποθήκευσης %s είναι απο την %d έκδοση (H %e είναι η παλιότερη υποστηριζώμενη),Konservita ludo '%s' estas el pli malnova versio: %d(%e estas la plej mallnova ke estas subtenita),La partida guardada '%s' es de una versión anterior: %d (%e es la más anterior soportada),,Pelitallenne '%s' on vanhemmasta versiosta: %d (%e on vanhin tuettu versio),La sauvegarde '%s' vient d'une version obsolète: %d (%e est la plus ancienne supportée.),,Il salvataggio '%s' proviene da una versione precedente: %d (%e è la più vecchia supportata),%s' はバージョンが合わないセーブデータだ: %d(%e は旧式版の物),저장된 게임'%s'은(는) 구 버전입니다: %d (%e 이 지원되는 버전 중 가장 오래된 버전),Savegame '%s' is van een oudere versie: %d (%e is de oudste ondersteunde versie).,Zapis gry „%s” jest ze starszej wersji: %d (%e jest najstarszą wspieraną),"O jogo salvo ""%s"" é de uma versão mais antiga: %d (%e sendo a mais antiga suportada)","O jogo gravado ""%s"" é de uma versão mais antiga: %d (%e sendo a mais antiga suportada)",Salvarea '%s' este dintr-o versiune mai veche: %d (%e e cea mai veche suportată),Сохранение «%s» из старой версии: %d (%e — последняя совместимая).,Сачувана игра „%s“ је из старије верзије: %d (%e је најстарија подржана) -Savegame '%s' is from an newer version: %d (%e is the highest supported),TXT_TOONEWSG,"Shouldn’t this say “%e is the newest supported”? +""info.json"".",%s' nu este o salvare validă. Lipsește 'info.json',Сохранение «%s» некорректно: отсутствует «info.json».,%s није валидно сачувана игра: Недостаје „info.json“.,"%s' är inte ett giltigt sparspel: Saknar ""info.json"".",%s' geçerli bir kayıt oyunu değil: Eksik 'info.json'., +Failed to access savegame info in '%s'.,TXT_FAILEDTOREADSG,,,,Nepodařilo se načíst informace v uložené hře '%s'.,Det lykkedes ikke at få adgang til savegame info i '%s'.,Konnte Spielstandinfo in '%s' nicht lesen.,Η πρόσβαση πληροφοριών του αρχείου αποθήκευσης %s δέν ήταν επιτυχής,Malsukcesis aliri informon de la konservita ludo en '%s'.,Fallo al acceder a información de partida guardada en '%s'.,,Tiedoston '%s' pelitallennetietoihin ei päästy käsiksi.,Impossible d'accéder aux infos de sauvegarde dans le fichier '%s'.,A '%s' mentésben nem sikerült fellelni a mentésinfókat.,Accesso alle informazioni sul salvataggio in '%s' fallito.,%s' のセーブデータにアクセス出来なかった。,%s'의 저장된 게임 정보에 액세스 할 수 없습니다.,Geen toegang tot de opgeslagen informatie in '%s'.,Kunne ikke få tilgang til savegame-info i '%s'.,Nie udało się dostać informacji zapisu „%s”.,"Não foi possível acessar a informação do jogo salvo em ""%s"".","Não foi possível acessar a informação do jogo gravado em ""%s"".",Nu s-au putut accesa informațiile din salvarea '%s'.,Невозможно получить информацию из сохранения «%s».,Не успешно пристопљено инфу сачуване игре %s.,"Misslyckades med att få tillgång till information om sparspelet i ""%s"".",%s' içindeki kayıt oyunu bilgilerine erişilemedi., +Savegame '%s' is from an incompatible version.,TXT_INCOMPATIBLESG,,,,Uložená hra '%s' je z nekompatibilní verze.,Savegame '%s' er fra en inkompatibel version.,Spielstand '%s' ist von einer inkompatiblen Version.,Το αρχείο αποθήκευσης %s είναι απο μια ασύμβατη έκδοση,Konservita ludo '%s' estas el nekongrua versio.,La partida guardada '%s' es de una versión no compatible.,,Pelitallenne '%s' on yhteensopimattomasta versiosta.,La sauvegarde '%s' vient d'une version incompatible.,A '%s' mentés egy nem kompatibilis verzió mentése.,Il salvataggio '%s' proviene da una versione incompatibile.,%s' は互換性の無いバージョンのセーブデータだ。,저장된 게임'%s'은(는) 호환되지 않는 버전입니다.,Savegame '%s' komt uit een incompatibele versie.,Savegame '%s' er fra en inkompatibel versjon.,Zapis gry „%s” jest z niekompatybilnej wersji.,"O jogo salvo ""%s"" é de uma versão incompatível.","O jogo gravado ""%s"" é de uma versão incompatível.",Salvarea '%s' este dintr-o versiune incompatibilă.,Сохранение «%s» из несовместимой версии порта.,Сачувана игра %s је из инкомпетабилне верзије.,"Sparfil ""%s"" är från en inkompatibel version.",%s' kayıt oyunu uyumsuz bir sürüme ait., +Savegame '%s' is from another ZDoom-based engine:,TXT_OTHERENGINESG,,,,Uložená hra '%s' je z jiného enginu založeného na ZDoomu:,Savegame '%s' er fra en anden ZDoom-baseret engine:,Spielstand '%s' ist von einer anderen ZDoom-basierten Engine:,Το αρχείο αποθήκευσης %s είναι απο μια άλλη ZDoom βασισμένη μηχανή,Konservita ludo '%s' estas el alia ZDoom-bazita modulo:,La partida guardada '%s' es de otro motor basado en ZDoom:,,Pelitallenne '%s' on toisesta ZDoom-pohjaisesta moottorista.,La sauvegarde '%s' vient d'un autre moteur basé sur ZDoom:,A '%s' mentés egy másik ZDoom motorhoz való:,Il salvataggio '%s' proviene da un altro motore basato su ZDoom:,%s' は別のZDoom型のセーブデータだ。,저장된 게임 '%s'은(는) 다른 Z둠 기반 엔진입니다:,Savegame '%s' is van een andere ZDoom-gebaseerde engine:,Savegame '%s' er fra en annen ZDoom-basert engine:,Zapis gry „%s” jest z innego silnika bazowanego na ZDoomie:,"O jogo salvo ""%s"" é de outra engine baseada em ZDoom:","O jogo gravado ""%s"" é de outro motor baseado em ZDoom:",Salvarea '%s' este dintr-un alt motor care are ca bază ZDoom:,"Сохранение «%s» из другого, основанного на ZDoom, движка:",Сачувана игра %s је из други ZDoom-базиран енџин:,"Sparfil ""%s"" är från en annan ZDoom-baserad motor:",%s' kayıt oyunu başka bir ZDoom tabanlı motordan:, +Savegame '%s' is from an older version: %d (%e is the oldest supported),TXT_TOOOLDSG,,,,Uložená hra '%s' je ze starší verze: %d (%e je nejstarší podporovaná verze),Savegame '%s' er fra en ældre version: %d (%e er den ældste understøttede version),Spielstand '%s' ist von einer älteren Version: %s (%e ist die älteste noch unterstützte Version,Το αρχείο αποθήκευσης %s είναι απο την %d έκδοση (H %e είναι η παλιότερη υποστηριζώμενη),Konservita ludo '%s' estas el pli malnova versio: %d (%e estas la plej malnova subtenata),La partida guardada '%s' es de una versión anterior: %d (%e es la más anterior soportada),,Pelitallenne '%s' on vanhemmasta versiosta: %d (%e on vanhin tuettu versio),La sauvegarde '%s' vient d'une version obsolète: %d (%e est la plus ancienne supportée.),A '%s' mentés egy túl régi verzióhoz való: %d (%e a legfrissebb támogatott verzió),Il salvataggio '%s' proviene da una versione precedente: %d (%e è la più vecchia supportata),%s' はバージョンが合わないセーブデータだ: %d(%e は旧式版の物),저장된 게임'%s'은(는) 구 버전입니다: %d (%e 이 지원되는 버전 중 가장 오래된 버전),Savegame '%s' is van een oudere versie: %d (%e is de oudste ondersteunde versie).,Savegame '%s' er fra en eldre versjon: %d (%e er den eldste som støttes).,Zapis gry „%s” jest ze starszej wersji: %d (%e jest najstarszą wspieraną),"O jogo salvo ""%s"" é de uma versão mais antiga: %d (%e sendo a mais antiga suportada)","O jogo gravado ""%s"" é de uma versão mais antiga: %d (%e sendo a mais antiga suportada)",Salvarea '%s' este dintr-o versiune mai veche: %d (%e e cea mai veche suportată),Сохранение «%s» из старой версии: %d (%e — последняя совместимая).,Сачувана игра „%s“ је из старије верзије: %d (%e је најстарија подржана),"Sparfil ""%s"" är från en äldre version: %d (%e är den äldsta versionen som stöds).",%s' kayıt oyunu daha eski bir sürümden: %d (%e desteklenen en eski sürümdür), +Savegame '%s' is from a newer version: %d (%e is the highest supported),TXT_TOONEWSG,"Shouldn’t this say “%e is the newest supported”? — Undead -Ask Randi: The text is old. I won't change it.",,,Uložená hra '%s' je z novější verze: %d (%e je nejnovější podporovaná verze),Spielstand '%s' ist von einer neueren Version: %s (%e ist die neueste noch unterstützte Version,Το αρχείο αποθήκευσης %s είναι απο μια πιο καινούρια έκδοση: %d (Η %e είναι η πιο καινούρια που υποστηρίζεται),"Konservita ludo '%s' estas el pli nova versio: %d -(%e estas la plej nova, kiu estas subtenita)",La partida guardada '%s' es de una versión posterior: %d (%e es la más alta soportada),,Pelitallenne '%s' on uudemmasta versiosta: %d (%e on korkein tuettu versio),La sauvegarde '%s' vient d'une version plus récente: %d (%e est la plus récente supportée.),,Il salvataggio '%s' proviene da una versione recente: %d (%e è la più recente supportata),%s' はバージョンが合わないセーブデータだ: %d(%e は最新版の物),저장된 게임'%s'은(는) 새 버전입니다: %d (%e 이 지원되는 버전 중 가장 최근 버전),Savegame '%s' is van een nieuwere versie: %d (%e is de hoogst ondersteunde versie).,Zapis gry „%s” jest z nowszej wersji: %d (%e jest najwyższą wspieraną),"O jogo salvo ""%s"" é de uma versão mais nova: %d (%e sendo a mais recente suportada)","O jogo gravado ""%s"" é de uma versão mais nova: %d (%e sendo a mais recente suportada)",Salvarea '%s' e dintr-o versiune mai nouă: %d (%e este cea mai nouă suportată),Сохранение «%s» из новой версии: %d (%e — последняя совместимая).,Сачувана игра „%s“ је из новије верзије: %d (%e је најновија подржана) -Savegame '%s' is missing the current map.,TXT_NOMAPSG,,,,Uložená hra '%s' neobsahuje současný level.,Spielstand '%s' hat keine Information über den alktuellen Level.,Το αρχείο αποθήκευσης %s δέν έχει την τωρινή πίστα,Konservita ludo '%s' mankas la nunan mapon.,La partida guardada '%s' carece del mapa actual.,,Pelitallenteesta '%s' puuttuu nykyinen taso.,La sauvegarde '%s' ne contient pas la carte actuelle.,,Il salvataggio '%s' non contiene la mappa corrente.,セーブデータ '%s'に現在のマップはない。,저장된 게임 '%s'에 현재 맵이 없습니다.,Savegame '%s' mist de huidige kaart.,W zapisie gry „%s” brakuje obecnej mapy.,"O jogo salvo ""%s"" não possui o mapa atual.","O jogo gravado ""%s"" não possui o mapa atual.",Salvării '%s' îi lipsește harta actuală.,В сохранении «%s» отсутствует текущая карта.,Сачувана игри „%s“ недостаје тренутна мапа. -%s' is not a valid savegame: Missing 'globals.json'.,TXT_NOGLOBALSJSON,,,,%s' není funkční uloženou hrou: Chybí 'globals.json'.,%s' ist kein gültiger Spielstand. 'globals.json' fehlt.,Το %s δεν είναι ένα έγκυρο αρχείο αποθήκευσης: Το globals.json λείπει,"%s' ne estas valida konservita ludo: -Mankas 'globals.json'.",%s' no es una partida guardada válida: Falta 'globals.json'.,,%s' ei ole kelvollinen pelitallenne. Puuttuva 'globals.json'.,%s n'est pas une sauvegarde valide. Fichier 'global.json' manquant.,,%s' non è un salvataggio valido: 'globals.json' mancante.,%s' は有効なセーブデータではない: 'globals.json'が不明。,%s' 는 유효하지 않습니다: 파일이 없습니다.'globals.json',%s' is geen geldig savegame: Ontbrekende 'globals.json'.,„%s” nie jest prawidłowym zapisem gry: Brak „globals.json”,"""%s"" não é um jogo salvo válido: Está faltando +Ask Randi: The text is old. I won't change it.",,,Uložená hra '%s' je z novější verze: %d (%e je nejvyšší podporovaná verze),Savegame '%s' er fra en nyere version: %d (%e er den højest understøttede),Spielstand '%s' ist von einer neueren Version: %s (%e ist die neueste noch unterstützte Version,Το αρχείο αποθήκευσης %s είναι απο μια πιο καινούρια έκδοση: %d (Η %e είναι η πιο καινούρια που υποστηρίζεται),Konservita ludo '%s' estas el pli nova versio: %d (%e estas la plej nova subtenata),La partida guardada '%s' es de una versión posterior: %d (%e es la más alta soportada),,Pelitallenne '%s' on uudemmasta versiosta: %d (%e on korkein tuettu versio),La sauvegarde '%s' vient d'une version plus récente: %d (%e est la plus récente supportée.),A '%s' mentés egy túl új verzióhoz való: %d (%e a legkorábbi támogatott verzió),Il salvataggio '%s' proviene da una versione recente: %d (%e è la più recente supportata),%s' はバージョンが合わないセーブデータだ: %d(%e は最新版の物),저장된 게임'%s'은(는) 새 버전입니다: %d (%e 이 지원되는 버전 중 가장 최근 버전),Savegame '%s' is van een nieuwere versie: %d (%e is de hoogst ondersteunde versie).,Savegame '%s' er fra en nyere versjon: %d (%e er den høyeste versjonen som støttes).,Zapis gry „%s” jest z nowszej wersji: %d (%e jest najwyższą wspieraną),"O jogo salvo ""%s"" é de uma versão mais nova: %d (%e sendo a mais recente suportada)","O jogo gravado ""%s"" é de uma versão mais nova: %d (%e sendo a mais recente suportada)",Salvarea '%s' e dintr-o versiune mai nouă: %d (%e este cea mai nouă suportată),Сохранение «%s» из новой версии: %d (%e — последняя совместимая).,Сачувана игра „%s“ је из новије верзије: %d (%e је најновија подржана),"Sparfil ""%s"" är från en nyare version: %d (%e är den högsta versionen som stöds).",%s' kayıt oyunu daha yeni bir sürümden: %d (%e desteklenen en yüksek sürümdür), +Savegame '%s' is missing the current map.,TXT_NOMAPSG,,,,Uložená hra '%s' neobsahuje současný level.,Savegame '%s' mangler det aktuelle kort.,Spielstand '%s' hat keine Information über den alktuellen Level.,Το αρχείο αποθήκευσης %s δέν έχει την τωρινή πίστα,Al la konservita ludo '%s' mankas la nuna mapo.,La partida guardada '%s' carece del mapa actual.,,Pelitallenteesta '%s' puuttuu nykyinen taso.,La sauvegarde '%s' ne contient pas la carte actuelle.,A '%s' mentés hiányolja a jelenlegi pályát.,Il salvataggio '%s' non contiene la mappa corrente.,セーブデータ '%s'に現在のマップはない。,저장된 게임 '%s'에 현재 맵이 없습니다.,Savegame '%s' mist de huidige kaart.,Savegame '%s' mangler det gjeldende kartet.,W zapisie gry „%s” brakuje obecnej mapy.,"O jogo salvo ""%s"" não possui o mapa atual.","O jogo gravado ""%s"" não possui o mapa atual.",Salvării '%s' îi lipsește harta actuală.,В сохранении «%s» отсутствует текущая карта.,Сачувана игри „%s“ недостаје тренутна мапа.,"Sparfil ""%s"" saknar den aktuella kartan.",%s' kayıt oyununda geçerli harita eksik., +%s' is not a valid savegame: Missing 'globals.json'.,TXT_NOGLOBALSJSON,,,,%s' není funkční uloženou hrou: Chybí 'globals.json'.,%s' er ikke et gyldigt savegame: Mangler 'globals.json'.,%s' ist kein gültiger Spielstand. 'globals.json' fehlt.,Το %s δεν είναι ένα έγκυρο αρχείο αποθήκευσης: Το globals.json λείπει,%s' ne estas valida konservita ludo: Mankante 'globals.json'.,%s' no es una partida guardada válida: Falta 'globals.json'.,,%s' ei ole kelvollinen pelitallenne. Puuttuva 'globals.json'.,%s n'est pas une sauvegarde valide. Fichier 'global.json' manquant.,A '%s' nem valós mentés: Hiányzó 'globals.json'.,%s' non è un salvataggio valido: 'globals.json' mancante.,%s' は有効なセーブデータではない: 'globals.json'が不明。,%s' 는 유효하지 않습니다: 파일이 없습니다.'globals.json',%s' is geen geldig savegame: Ontbrekende 'globals.json'.,%s' er ikke et gyldig lagringsspill: Mangler 'globals.json'.,„%s” nie jest prawidłowym zapisem gry: Brak „globals.json”,"""%s"" não é um jogo salvo válido: Está faltando ""globals.json"".","""%s"" não é um jogo gravado válido: Está faltando -""globals.json"".",%s nu este o salvare validă. Lipsește 'globals.json'.,Сохранение «%s» некорректно: отсутствует «globals.json».,%s није валидно сачувана игра: Недостаје „globals.json“. -Failed to access savegame info in '%s',TXT_SGINFOERR,,,,Nepodařilo se načíst informace v uložené hře '%s'.,Konnte Spielstandinformationen von '%s' nicht lesen.,Η πρόσβαση πληροφοριών του αρχείου αποθήκευσης %s δέν ήταν επιτυχής,Malsukcesis aliri informo de la konservita ludo en '%s',Fallo al acceder a información de partida guardada en '%s'.,,Tiedoston '%s' pelitallennetietoihin ei päästy käsiksi.,Impossible d'accéder aux infos de sauvegarde dans le fichier '%s'.,,Accesso alle informazioni sul salvataggio in '%s' fallito,%s' のセーブデータにアクセス出来なかった,%s'의 저장된 게임 정보에 액세스 할 수 없습니다.,Geen toegang tot savegame info in '%s'.,Nie udało się dostać informacji zapisu „%s”.,"Não foi possível acessar a informação do jogo salvo em ""%s"".","Não foi possível acessar a informação do jogo gravado em ""%s"".",Informațiile salvării '%s' nu au putut fi accesate,Невозможно получить информацию из сохранения «%s».,Не успешно приступљено саучуваној игри у %s -A game save is still pending.,TXT_SAVEPENDING,,,,Stále se čeká na uložení hry.,Das Speichern eines Spielstandes steht noch aus.,Μια αποθήκευση παιχνιδίου είναι ακόμα σε αναμονή,Konservita ludo ankoraŭ estas pritaktoti.,Un guardado de partida aún está pendiente.,,Pelin tallennus on vielä kesken.,Une sauvegarde est déjà en cours.,,Un salvataggio di gioco è ancora in corso.,セーブ中だ,게임 저장이 아직 보류 중입니다.,Een spel opslaan is nog steeds in behandeling.,Zapis gry jest wciąż w toku.,Jogo salvo ainda pendente.,Jogo gravado ainda pendente.,O salvare este încă în așteptare.,Сохранение в очереди.,Сачувана игра идаље чека -Not in a saveable game.,TXT_NOTSAVEABLE,,,,Nejsi v uložitelné hře.,Kein speicherbares Spiel aktiv.,Δέν είσαι σε ένα παιχνίδει που μπορεί να αποθηκευτεί,Ne esti en konservebla ludo.,No en una partida guardable.,,Ei tallennettavassa pelissä.,Vous n'êtes pas dans une partie sauvegardable.,,Non è in un gioco salvabile.,セーブ可能なゲームではない,저장 가능한 게임에선 불가능 합니다.,Geen opslagbaar spel actief.,Nie w grze do zapisywania.,Não está em uma partida salvável.,Não estás numa partida que possa ser gravada.,Nu ești într-un joc în care poți salva.,Не в сохраняемой игре.,Није у сачувајућој игри -Not in a level,TXT_NOTINLEVEL,,,,Nejsi v levelu.,Nicht in einem Level.,Δέν ε'ισαι σε μια πίστα,Ne esti en nivelo,No en un nivel,,Ei tasossa,Vous n'êtes pas dans un niveau.,,Non è in un livello,レベル内ではない,레벨 안에선 불가능 합니다.,Niet in een level,Nie w poziomie.,Não está em uma fase.,Não estás em nenhum nível.,Nu ești în niciun nivel,Не на уровне,Није у нивоу -Player is dead in a single-player game,TXT_SPPLAYERDEAD,,,,Hráč je mrtvý v singleplayer hře.,Spieler ist tot in einem Einzelspieler-Spiel.,Ο παίχτης έιναι νεκρός σε ένα singleplayer παιχνίδι,Ludanto estas mortinta en sol-ludanta ludo,Jugador muerto en partida de un solo jugador,,Pelaaja on kuollut yksinpelissä,Le joueur est mort en mode solo.,,Il giocatore è morto in un gioco single player,シングルプレイヤーゲームでプレイヤーが死んだ,플레이어가 싱글 플레이 게임에서 죽었습니다.,Speler is dood in een een-speler spel,Gracz jest martwy w grze dla jednego gracza,Jogador está morto em partida single player.,Jogador está morto numa partida single player.,Jucătorul este mort într-un joc single-player,Игрок мёртв в одиночной игре,Играч је мртав у сингл-плејер игри -Save failed,TXT_SAVEFAILED,,,,Uložení se nezdařilo.,Speichern fehlgeschlagen.,Η αποθήκευση απέτυχε,Konservado malsukcesis,Guardado fallido,,Tallennus epäonnistui,La sauvegarde à échoué.,,Salvataggio fallito,セーブに失敗した。,저장 실패,Opslaan mislukt,Nie udało się zapisać,Falha ao salvar,Falha ao gravar,Salvare eșuată,Ошибка сохранения игры,Сачување није успело -Could not create screenshot.,TXT_SCREENSHOTERR,,,,Nepodařilo se pořídit snímek obrazovky.,Konnte Screenshot nicht erzeugen.,Ένα screenshot δέν μπόρεσε να τραβυχτεί,Ne povis krei ekrankopion.,No se pudo crear captura de pantalla.,,Ei voitu ottaa kuvakaappausta.,La capture d'écran à échoué.,,Non è stato possibile effettuare la cattura dello schermo.,スクリーンショットを作成できなかった。,스크린샷을 만들 수 없음.,Kon geen screenshot maken.,Nie można zrobić zrzutu ekranu.,Não foi possível capturar a tela.,Não foi possível capturar ecrã,Captura de ecran nu a putut fi creată.,Ошибка создания скриншота,Није успело направити снимак екрана. -By %s,TXT_BY,"As in ""paused by player""",,,hráčem %s,Von %s,Απο @[pro_gr} %s,De %s,Por %s,,Pelaajan %s toimesta,Par %s,,Da %s,"%s より -",%s 에 의해,Met %s,Przez %s,Por %s,,De către %s,игроком %s,играчем %s -Vulkan Options (Experimental),DSPLYMNU_VKOPT,,,,Nastavení Vulkanu (Experimentální),Vulkan Optionen (Experimentell),Vulka Ρυθμίσεις (Πειραματικές),Vulkan Agordoj (Eksperimenta),Opciones de Vulkan (Experimental),,Vulkan-asetukset (kokeellinen),Options Vulkan (Expérimental),,Opzioni Vulkan (Sperimentale),Vulkan機能オプション(実験的),벌칸 설정(실험적),Vulkan Opties (Experimenteel),Opcje Vulkan (Eksperymentalne),Opções de Vulkan (Experimental),,Setări Mod Vulkan (În curs de testare),Настройки Vulkan (экспериментальные),Vulkan подешавања (експериментална) -Vulkan Options,VK_TITLE,,,,Nastavení Vulkanu,Vulkan Optionen,Vulkan Ρυθμίσεις,Vulkan Agordoj,Opciones de Vulkan,,Vulkan-asetukset,Options Vulkan (Expérimental),,Opzioni Vulkan,Vulkan機能オプション,벌칸 설정,Vulkan Opties,Opcje Vulkan,Opções de Vulkan,,Setări Mod Vulkan,Настройки Vulkan,Vulkan подешавања -Enable Vulkan,VKMNU_ENABLE,,,,Povolit Vulkan,Aktiviere Vulkan,Ενεργοποιηση του Vulkan,Aktivigi Vulkan,Activar Vulkan,,Ota käyttöön Vulkan,Activer Vulkan,,Abilita Vulkan,Vulkanを有効化,벌칸 렌더러 사용,Vulkan inschakelen,Włącz Vulkan,Habilitar Vulkan,,Activează modul video Vulkan,Включить Vulkan,Омогући Vulkan -Vulkan Device ID,VKMNU_DEVICE,,,,ID zařízení Vulkanu,Vulkan Geräte ID,Vulkan ID Συσκευής,Vulkan Aparato ID,ID de Dispositivo Vulkan,,Vulkan-laitetunniste,ID du périphérique Vulkan,,Dispositivo ID Vulkan,Vulkanデバイス ID,벌칸 장치 아이디,Vulkan apparaat-ID,ID urządzenia Vulkan,ID do dispositivo Vulkan,,ID Dispozitiv Vulkan,ID устройства Vulkan,Vulkan ID уређаја -High Dynamic Range,VKMNU_HDR,,,,Vysoký dynamický rozsah (HDR),,Υψηλό Δυναμική Εμβέλεια,Alta Dinamika Amplekso,Alto Rango Dinámico,,Korkea dynamiikka-alue (HDR),,,,ハイダイナミックレンジ,하이 다이나믹 레인지,Hoog dynamisch bereik,Obraz HDR,Alto Alcance Dinâmico (HDR),,HDR,HDR,HDR -Warning: The Vulkan renderer is highly experimental!,VK_WARNING,,,,Varování: Vulkan renderer je silně experimentální!,Achtung: Der Vulkan Renderer ist noch sehr experimentell!,Προειδοποίηση: Ο Vulkan renderer είναι υψηλά πειραματικός!,Averto: La Vulkan bildigilo estas alte eksperimenta!,Advertencia: ¡El renderizado por Vulkan es altamente experimental!,,Varoitus: Vulkan-hahmonnin on hyvin kokeellinen!,Attention: Le moteur de rendu Vulkan est très expérimental!,,Attenzione: il motore grafico Vulkan è altamente sperimentale!,警告:Vulkanレンダラーは実験段階です!,경고: 벌칸 렌더러는 매우 실험적입니다!,Waarschuwing: De Vulkan renderer is zeer experimenteel!,Uwaga: Renderer Vulkan jest bardzo eksperymentalny!,Atenção: O renderizador Vulkan é altamente experimental!,,Atenție: Modul Vulkan este încă în curs de testare!,Внимание: рендерер Vulkan в стадии тестирования!,УПОЗОРЕЊЕ: Vulkan рендерер је врло експерименталан! -These options will require a restart to take effect.,VK_RESTART,,,,Tato nastavení vyžadují restart hry.,Diese Option erfordert einen Neustart!,Αυτές η ρυθμίσεις θα χρειαστούνε επανεκκίνηση για να ισχύσουν,Ĉi tiuj agordoj bezonos rekomencon por efikiĝi.,Estas opciones requieren reiniciar para tener efecto.,,Nämä asetukset vaativat uudelleenkäynnistyksen astuakseen voimaan.,Ces options nécessitent un redémarrage.,,Queste opzioni richiedono il riavvio per avere effetto.,これらのオプションを有効にするには再起動が必要です。,이 설정을 적용하려면 게임을 재시작해야 합니다.,Deze opties vereisen een herstart om van kracht te worden.,"Te opcje będą wymagały ponownego włączenia, aby miały efekt.",É necessário reiniciar para essas configurações fazerem efeito.,É necessário reiniciar para estas configurações fazerem efeito.,Aceste setări necesită o repornire pentru a putea fi aplicate,Для применения изменений требуется рестарт.,Морате поново покренути GZDoom да би промене ступиле на снагу. -Select Vulkan Device,VKMNU_DEVICESELECT,This is not yet implemented - but it is planned,,,Vyber zařízení Vulkanu,Vulkan Gerät auswählen,Επιλογή Vulkan Συσκευής,Elekti Vulkan Aparaton,Seleccionar Dispositivo Vulkan,,Valitse Vulkan-laite,Sélectionner périphérique Vulkan,,Seleziona il Dispositivo Vulkan,Vulkanデバイスの選択,벌칸 장치를 고르시오,Selecteer Vulkan Apparaat,Wybierz Urządzenie Vulkan,Selecione o dispositivo Vulkan,,Selectare Dispozitiv Vulkan,Выберите устройство Vulkan,Изаберите Vulkan уређај -Press any key or click anywhere in the window to quit.,TXT_QUITENDOOM,,,,"Stiskni libovolnou klávesu, nebo kdekoliv v okně klikni pro ukončení",Drücke eine Taste oder klicke mit der Maus ins Fenster zum Beenden.,Πάτα οποιοδήποτε πλήκτρο ή πάτα οπουδήποτε για να κάνεις έξοδο,Premu klavon aŭ alklaki kie ajn en la fenestro por ĉesigi.,Presiona una tecla o haz click en cualquier lugar de la ventana para salir.,Presiona una tecla o da click en cualquier lugar de la ventana para salir.,Paina mitä tahansa näppäintä tai napsauta minne tahansa ikkunaa lopettaaksesi.,Appuyez sur une touche ou cliquez pour quitter.,,Premi un qualunque tasto o fai un click ovunque nella finestra per uscire.,何かのキーを押すか、ウィンドウのどこかをクリックすると終了する。,아무 키를 누르거나 아무 곳이나 클릭하면 종료됩니다.,Druk op een willekeurige toets of klik ergens in het venster om te stoppen.,Wciśnij dowolny klawisz lub gdziekolwiek kliknij myszką aby wyjść.,Aperte qualquer tecla ou clique em qualquer lugar na janela para sair.,Carrega numa tecla ou clique em qualquer lugar na janela para sair.,Apasă orice tastă sau fă click oriunde în fereastră pentru a ieși.,"Нажмите любую клавишу или кликните по окну, чтобы выйти.",Притисните било који тастер или кликните било где на екрану да одустанете. -No vertical thrust from explosions,CMPTMNU_EXPLODE1,,,,Exploze neodhazují do výšky,Keine vertikale Bewegung durch Explosionen,Καθόλου κατακόρυφη ώθηση απο εκρήξεις,Neniu vertikalaj puŝoj el eksplodoj,No causar empuje vertical en explosiones,,Ei pystysuuntaista työntövoimaa räjähdyksistä,Explosions sans propulsion verticale,,Nessuna spinta verticale dalle esplosioni,爆風は縦軸全域に影響しない,폭발시 수직방향 반동 억제,Geen verticale stuwkracht van explosies,Brak pionowego nacisku od eksplozji,Desativar propulsão vertical das explosões,,Fără împingere verticală de la explozii,Взрывы не отбрасывают вверх/вниз,Нема вертикалног гурања од експлозија -Use original Doom explosion behavior,CMPTMNU_EXPLODE2,,,Use original Doom explosion behaviour,Používat původní chování explozí Doomu,Benutze Original Doom Explosionsverhalten,Συμπεριφορά εκρήξεων απο το πρωτότυπο Doom,Uzi originalan konduton de Doom por eksplodoj ,Usar comportamiento de explosiones del DOOM original,,Käytä Doomin alkuperäisiä räjähdysten käyttäytymissääntöjä,Utiliser comportement Doom original,,Usa l'originale comportamento dell'esplosione di Doom,Doom本来の爆発動作を使用する,고전 둠의 폭발 반발력 적용,Gebruik het originele Doom explosiegedrag,Użyj oryginalnego zachowania eksplozji z Dooma,Usar comportamento original de explosões do Doom,,Utilizare comportament original pentru explozii,Использовать модель взрывов из оригинального Doom,Користи оригнално Doom понашање за експлозије -Screen Blend Options,HUDMNU_FLASH,,,,Nastavení míchání obrazovky,Überblendoptionen,Ρυθμίσεις Ανάμειξης Οθόνης,Ekranmisko-agordoj,Opciones de tintado de pantalla,,Näytön sekoitusasetukset,Options de blending écran,,Opzioni Blending dello Schermo,スクリーンブレンド オプション,화면 조합 설정,Opties voor schermmengsel,Opcje scalania ekranu,Opções de mescla de tela,Opções de mistura de ecrã,Setări Amestec Imagine,Настройки смешивания экрана,Подешавања блед екрана -Postprocessing,GLMNU_POSTPROCESS,,,,,,Μετα-επεξεργασία,Postprocezado,Postprocesado,,Jälkikäsittely,,,,ポストプロセッシング,포스트프로세싱 적용,Nabewerking,Przetwarzanie końcowe,Pós processamento,,Postprocesare,Постобработка,Пост обрада -3D mode,GLMNU_3DMODE,,,,3D režim,3D Modus,3D λειτουργία,3D-reĝimo,Modo 3D,,3D-tila,Mode 3D,3D mód,Modalità 3D,3Dモード,3D 모드 적용,3D-modus,Tryb 3D,Modo 3D,,Mod 3D,Режим 3D,3D режим -Enable buggy Strife railing,CMPTMNU_RAILINGHACK,,,,Povolit nestabilní zábradlí ze Strifu,Fehlerhafte Strife-Geländer,Ενεργοποιηση σπασμένης συμπεριφοράς καγκέλον για το Strife,Aktivigi ciman reladon de Strife,Activar barandillas bugueadas de Strife,,Ota käyttöön Strifen vialliset kaiteet,Barrières buggées pour Strife,,Abilita il railing buggato di Strife,バグのあるStrife railingを許可,고전 스트라이프 철책 적용,Buggy mogelijk maken Strijk-reling,Włącz wadliwe bariery Strife'a,Habilitar railing defeituoso do Strife,Permitir railing defeituoso do Strife,Utilizare comportament grilaj Strife incorect,Вернуть багнутые перила в Strife,Омогући непоправљену ограду у Strife-у -Crosshair,HUDMNU_CROSSHAIRON,,,,Křížek,Fadenkreuz,Crosshair,Reteto,Retícula,,Tähtäin,Viseur,,Mirino,クロスヘア,조준점,Draadkruis,Celownik,Mira,,Țintă,Прицел,Нишан -Subtitles,MSGMNU_SUBTITLES,,,,Titulky,Untertitel,Υπότιτλοι,Subtekstoj,Subtitulos,,Tekstitys,Sous-titres,,Sottotitoli,サブタイトル,자막,Ondertitels,Napisy,Legendas,,Subtitrări,Субтитры,Титлови -Undo Changes,TXT_UNDOCHANGES,,,,Zrušit změny,Rückgängig machen,Αναίρεση Αλλαγών,Malfari Ŝanĝojn,Anular cambios,,Peruuttaa muutokset,Révoquer les changements,,Revocare le modifiche,変更を戻す,변경 사항 취소,Wijzigingen ongedaan maken,Cofnij Zmiany,Desfazer alterações,,Anulează Modificările,Отменить изменения,Поништи промене -Red,TXT_COLOR_RED,,,,Červená,Rot,Κόκινο,Ruĝa,Rojo,,Punainen,Rouge,Vörös,Rosso,赤,적색,Rood,Czerwony,Vermelho,,Roșu,Красный,Црвена -Green,TXT_COLOR_GREEN,,,,Zelená,Grün,Πράσινο,Verda,Verde,,Vihreä,Vert,Zöld,Verde,緑,녹색,Groen,Zielony,Verde,,Verde,Зелёный,Зелена -Blue,TXT_COLOR_BLUE,,,,Modrá,Blau,Μπλέ,Blua,Azul,,Sininen,Bleu,Kék,Blu,青,청색,Blauw,Niebieski,Azul,,Albastru,Синий,Плава -Gray,TXT_COLOR_GRAY,,,Grey,Šedá,Grau,Γκρί,Griza,Gris,,Harmaa,Gris,Szürke,Grigio,灰,회색,Grijs,Szary,Cinza,,Gri,Серый,Сива -Brown,TXT_COLOR_BROWN,,,,Hnědá,Braun,Καφέ,Bruna,Marrón,,Ruskea,Brun,Barna,Marrone,茶,갈색,Bruin,Brązowy,Marrom,,Maro,Коричневый,Браон -Yellow,TXT_COLOR_YELLOW,,,,Žlutá,Gelb,Κίτρινο,Flava,Amarillo,,Keltainen,Jaune,Sárga,Giallo,黄,노란색,Geel,Żółty,Amarelo,,Galben,Жёлтый,Жута -Beige,TXT_COLOR_BEIGE,,,,Béžová,,Μπέζ,Flavgriza,Beis,,Beesi,,,,淡,담갈색,Beige,Beżowy,Bege,,Bej,Бежевый,Беж -Light Red,TXT_COLOR_LIGHTRED,,,,Světle červená,Hellrot,Ανοιχτό Κόκκινο,Ruĝeta,Rojo claro,,Vaaleanpunainen,Rouge clair,,Rosso chiaro,丹,옅은 적색,Licht Rood,Jasnoczerwony,Vermelho claro,,Roșu Deschis,Светло-красный,Светло црвена -Light Green,TXT_COLOR_LIGHTGREEN,,,,Světle zelená,Hellgrün,Ανοιχτό Πράσινο,Verdeta,Verde claro,,Vaaleanvihreä,Vert clair,,Verde chiaro,葵,옅은 녹색,Licht groen,Jasonzielony,Verde claro,,Verde Deschis,Светло-зелёный,Светло зелена -Light Blue,TXT_COLOR_LIGHTBLUE,,,,Světle modrá,Hellblau,Γαλάζιο,Blueta,Azul claro,,Vaaleansininen,Bleu clair,Világoskék,Blu chiaro,空,옅은 청색,Licht blauw,Jasnoniebieski,Azul claro,,Albastru Deschis,Светло-синий,Светло плава -Light Gray,TXT_COLOR_LIGHTGRAY,,,Light Grey,Světle šedá,Hellgrau,Ανοιχτό Γκρι,Grizeta,Gris claro,,Vaaleanharmaa,Gris clair,,Grigio chiaro,鉛,옅은 회색,Lichtgrijs,Jasnoszary,Cinza claro,,Gri Deschis,Светло-серый,Светло сива -Light Brown,TXT_COLOR_LIGHTBROWN,,,,Světle hnědá,Hellbraun,Ανοιχτό Καφέ,Bruneta,Marrón claro,,Vaaleanruskea,Brun clair,,Marrone chiaro,褐,옅은 고동색,Lichtbruin,Jasnobrązowy,Marrom claro,,Maro Deschis,Светло-коричневый,Светло браон -Gold,TXT_COLOR_GOLD,,,,Zlatá,,Χρυσό,Orkolora,Dorado,,Kulta,Or,Farany,Oro,金,금색,Goud,Złoty,Dourado,,Auriu,Золотой,Златна -Purple,TXT_COLOR_PURPLE,,,,Fialová,Violett,Μώβ,Purpura,Morado,,Purppura,Violet,Lila,Viola,紫,보라색,Paars,Fioletowy,Roxo,,Mov,Фиолетовый,Љубичаста -Dull Green,TXT_COLOR_DULLGREEN,,,,Bledě zelená,Blassgrün,Αμβλύς Πράσινο,Gris-Verda,Verde pálido,,Haaleanvihreä,Vert pâle,,Verde pallido,苔,암녹색,Saaie groen,Matowa Zieleń,Verde pálido,,Verde Pastel,Мутно-зелёный,Тупа зелена -Bright Green,TXT_COLOR_BRIGHTGREEN,,,,Jasně zelená,Hellgrün,Φωτινό Πράσινο,Verdega,Verde claro,,Vaaleanvihreä,Vert clair,,Verde chiaro,鮮,밝은 녹색,Helder groen,Jasnozielony,Verde claro,,Verde Deschis,Ярко-зелёный,Светла зелена -Dark Green,TXT_COLOR_DARKGREEN,,,,Tmavě zelená,Dunkelgrün,Σκοτεινό Πράσινο,Malhelverda,Verde oscuro,,Tummanvihreä,Vert sombre,Sötétzöld,Verde scuro,深,흑녹색,Donkergroen,Ciemnozielony,Verde escuro,,Verde Închis,Тёмно-зелёный,Тамна зелена -Rust,TXT_COLOR_RUST,,,,Rez,Rostbraun,Σκουριά,Rustokolora,Óxido,,Ruoste,Rouille,,Arrugginito,錆,주황 적갈색,Roest,Rdzawy,Ferrugem,,Ruginiu,Ржавый,Рђа -Quicksave rotation,MISCMNU_QUICKSAVEROTATION,,,,Rotace rychle uložených her,Schnellspeicherrotation,Περιστροφή γρήγορων αποθηκέυσεων ,Rapidkonservado-rotacio,Rotación de Salvado Rápido,,Pikatallennuskierto,Rotation Sauvegardes Rapides,,Rotazione rapide della quicksave,クイックセーブ間隔,빠른 저장 간격,Roteer quicksaves,Rotacja szybkich zapisów,Rotação de quicksave,,Rotație salvări rapide,Чередовать слоты для быстрых сохранений,Окретање брзих чувања -Number of quicksaves in rotation,MISCMNU_QUICKSAVECOUNT,,,,Počet rychle uložených her v rotaci,Anzahl Schnellspeicherplätze,Αριθμός γρήγορων αποθηκέυσεων σε περιστροφή,Nombro da rapidkonservitaj ludoj en rotaciado,Número de Salvados Rápidos en Rotación,,Pikatallennusten määrä kierrossa,Nombre de sauvegardes en rotation,,Numero di quicksaves in rotazione,間隔クイックセーブの数,빠른 저장 간격의 수,Aantal roterende quicksaves,Ilość szybkich zapisów w rotacji,Número de quicksaves em rotação,,Număr salvări în rotație,Кол-во слотов для быстрых сохранений,Број брзих чувања у окретању -Select Environment,REVMNU_SELECT,,,,Vybrat prostředí,Umgebung wählen,Επιλογή Περιβάλλοντος,Elekti Medion,Seleccionar Ambiente,,Valitse tila,Sélectionner un environnement,,Seleziona ambiente,反響選択,환경 선택,Selecteer omgeving,Wybierz Środowisko,Selecione o Ambiente,,Alegere Mediu,Выбрать окружение,Изабери окружење -Test Environment,REVMNU_TEST,,,,Testovat prostředí,Umgebung testen,Δοκιμαστκό Περιβάλλον,Provi Medion,Probar Ambiente,,Testaa tilaa,Tester un environnement,,Testare ambiente,反響テスト,환경 테스트,Test omgeving,Testuj Środowisko,Testar Ambiente,,Testare Mediu,Тестировать окружение,Тестирај окружење -Edit Environment,REVMNU_EDIT,,,,Upravit prostředí,Umgebung editieren,Επεξεργασία Περιβάλλοντος,Modifi Medion,Editar Ambiente,,Muokkaa tilaa,Modifier un environnement,,Modifica ambiente,反響編集,환경 편집,Omgeving bewerken,Edytuj Środowisko,Editar Ambiente,,Editare Mediu,Редактировать окружение,Уреди окружење -New Environment,REVMNU_NEW,,,,Nové prostředí,Neue Umgebung,Νέο Περιβάλλον,Nova Medion,Nuevo Ambiente,,Uusi tila,Nouveau environnement,,Nuovo ambiente,新規反響設定,새로운 환경 생성,Nieuwe omgeving,Nowe Środowisko,Novo Ambiente,,Mediu Nou,Новое окружение,Ново окружење -Revert settings,REVMNU_REVERT,,,,Obnovit nastavení,Zurücksetzen,Επαναφορά Ρυθμίσεων,Defaŭltigi agordojn,Revertir Configuración,,Palauta asetukset,Réinitialiser les paramètres,,Ripristina impostazioni,設定を戻す,설정 되돌리기,Instellingen terugzetten,Przywróć ustawienia,Reverter definições,,Revenire la setările precedente,Настройки по умолчанию,Врати подешавања -Environment Size,REVMNU_ENVIRONMENT_SIZE,Please translate only if you know how to properly name this technical jargon!,,,,,Μέγεθος Περιβάλλοντος,Mediamplekso,Tamaño de Ambiente,,Tilan koko,Taille Environnement,,,反響サイズ,공간 크기,,,Tamanho do Ambiente,,,, -Environment Diffusion,REVMNU_ENVIRONMENT_DIFFUSION,,,,,,Διάχυση Περιβάλλοντος,Medidifuzo,Difusión de Ambiente,,Tilan äänen hajautuminen,Diffusion Environnement,,,反響伝播,공간 잔향 확산,,,Difusão do Ambiente,,,, -Room,REVMNU_ROOM,,,,,,Δωμάτιο,Ĉambro,Sala,,Tilan keskitaajuudet,Salle,,,,룸 효과,,,Sala,,,, -Room HF,REVMNU_ROOM_HF,,,,,,Δωμάτιο HF,Ĉambro (AF),Sala (Frecuencia Alta),,Tilan korkeat taajuudet,HF Salle,,,,룸 효과 HF,,,Sala (Alta Frequência),,,, -Room LF,REVMNU_ROOM_LF,,,,,,Δωμάτιο LF,Ĉambro (MaF),Sala (Frecuencia Baja),,Tilan matalat taajuudet,LF Salle,,,,룸 효과 LF,,,Sala (Baixa Frequência),,,, -Decay Time,REVMNU_DECAY_TIME,,,,,,,Putriĝo-tempo,Tiempo de Decadencia,,Häipymäaika,Temps Decay,,,,잔향 감쇠 시간,,,Tempo de Decaimento,,,, -Decay HF Ratio,REVMNU_DECAY_HF_RATIO,,,,,,,Putriĝo-proporcio (AF),Ratio de Decadencia (Frecuencia Alta),,Korkeiden taajuuksien (HF) häipymissuhdeluku,,,,Decay HF比率,잔향 감쇠 HF 비율,,,Taxa de Decaimento (Alta Freq.),,,, -Decay LF Ratio,REVMNU_DECAY_LF_RATIO,,,,,,,Putriĝo-proporcio (MaF),Ratio de Decadencia (Frecuencia Baja),,Matalien taajuuksien (LF) häipymissuhdeluku,,,,Decay LF比率,잔향 감쇠 LF 비율,,,Taxa de Decaimento (Baixa Freq.),,,, -Reflections,REVMNU_REFLECTIONS,,,,,,Αντανακλάσεις,Reflektoj,Reflejos,,Ensiheijastukset,,,,,룸 반사,,,Reflexos,,,, -Reflections Delay,REVMNU_REFLECTIONS_DELAY,,,,,,Καθυστέρηση Αντανακλάσεων,Prokrasto de Reflektoj,Retraso de Reflejos,,Ensiheijastusten viive,Délai Reflections,,,,룸 반사 딜레이 시간,,,Atraso de Reflexos,,,, -Reflections Pan X,REVMNU_REFLECTIONS_PAN_X,,,,,,,Reflektoj Alturnas tra X,Desplazamiento en X de Reflejos,,Ensiheijastusten X-panorointi,Orientation Reflections X,,,Reflections X定位,X축 룸 반사,,,Deslocamento X de Reflexos,,,, -Reflections Pan Y,REVMNU_REFLECTIONS_PAN_Y,,,,,,,Reflektoj Alturnas tra Y,Desplazamiento en Y de Reflejos,,Ensiheijastusten Y-panorointi,Orientation Reflections Y,,,Reflections Y定位,Y축 룸 반사,,,Deslocamento Y de Reflexos,,,, -Reflections Pan Z,REVMNU_REFLECTIONS_PAN_Z,,,,,,,Reflektoj Alturnas tra Z,Desplazamiento en Z de Reflejos,,Ensiheijastusten Z-panorointi,Orientation Reflections Z,,,Reflections Z定位,Z축 룸 반사,,,Deslocamento Z de Reflexos,,,, -Reverb,REVMNU_REVERB,,,,,,,Resono,Reverberación,,Jälkikaiunta,,,,,리버브,,,Reverberação,,,, -Reverb Delay,REVMNU_REVERB_DELAY,,,,,,,Prokrasto de Resono,Retraso de Reverberación,,Jälkikaiunnan viive,Délai Reverb,,,,리버브 지연,,,Atraso de Reverberação,,,, -Reverb Pan X,REVMNU_REVERB_PAN_X,,,,,,,Resono Alturnas tra X,Desplazamiento en X de Reverberación,,Jälkikaiunnan X-panorointi,Orientation Reverb X,,,Reverb X定位,X축 리버브,,,Deslocamento X de Reverberação,,,, -Reverb Pan Y,REVMNU_REVERB_PAN_Y,,,,,,,Resono Alturnas tra Y,Desplazamiento en Y de Reverberación,,Jälkikaiunnan Y-panorointi,Orientation Reverb Y,,,Reverb Y定位,Y축 리버브,,,Deslocamento Y de Reverberação,,,, -Reverb Pan Z,REVMNU_REVERB_PAN_Z,,,,,,,Resono Alturnas tra Z,Desplazamiento en Z de Reverberación,,Jälkikaiunnan Z-panorointi,Orientation Reverb Z,,,Reverb Z定位,Z축 리버브,,,Deslocamento Z de Reverberação,,,, -Echo Time,REVMNU_ECHO_TIME,,,,,,,Tempo de Eko,Tiempo de Eco,,Kaikuaika,Longueur écho,,,,에코 시간,,,Tempo de Eco,,,, -Echo Depth,REVMNU_ECHO_DEPTH,,,,,,,Produndo de Eko,Profundidad de Eco,,Kaiun syvyys,Profondeur écho,,,,에코 깊이,,,Profundidade de Eco,,,, -Modulation Time,REVMNU_MODULATION_TIME,,,,,,,Tempo de Modulado,Tiempo de Modulación,,Modulaatioaika,Longueur Modulation,,,,전조 시간,,,Tempo de Modulação,,,, -Modulation Depth,REVMNU_MODULATION_DEPTH,,,,,,,Produndo de Modulado,Profundidad de Modulación,,Modulaation syvyys,Profondeur Modulation,,,,전조 깊이,,,Profundidade de Modulação,,,, -Air Absorption HF,REVMNU_AIR_ABSORPTION_HF,,,,,,,Aerabsorbo AF,Absorción en Aire de Frecuencia Alta,,Korkeiden taajuuksien (HF) ilma-absorptio,,,,,대기 흡수 HF,,,Absorção de Ar de Alta Freq.,,,, -HF Reference,REVMNU_HF_REFERENCE,,,,,,,AF Refrenco,Referencia de Frecuencia Alta,,Korkeiden taajuuksien vertausarvo,,,,HF参照値,HF 참조치,,,Referência de Alta Freq.,,,, -LF Reference,REVMNU_LF_REFERENCE,,,,,,,MaF Refrenco,Referencia de Frecuencia Baja,,Matalien taajuuksien vertausarvo,,,,LF参照値,LF 참조치,,,Referência de Baixa Freq.,,,, -Room Rolloff Factor,REVMNU_ROOM_ROLLOFF_FACTOR,,,,,,,Ĉambro-Rolloff-Faktoro,Factor de Roll-off de Sala,,Tilan vaimenemiskerroin,Facteur de rolloff Salle,,,,룸 감쇠 양,,,Fator de Roll-off da Sala,,,, -Diffusion,REVMNU_DIFFUSION,,,,,,,Difuzo,Difusión,,Diffuusio,,,,,잔향 확산,,,Difusão,,,, -Density,REVMNU_DENSITY,,,,,,,Denseco,Densidad,,Tiheys,Densité,,,密度,잔향 밀도,,,Densidade,,,, -Reflections Scale,REVMNU_Reflections_Scale,,,,,,,Skalo de Reflektoj,Escala de Reflejos,,Ensiheijastusten skaala,Echelle Reflections,,,Reflections音階,룸 반사 음계,,,Escala de Reflexos,,,, -Reflections Delay Scale,REVMNU_Reflections_Delay_Scale,,,,,,,Prokrastskalo de Reflektoj,Escala de Retraso de Reflejos,,Ensiheijastusten viiveen skaala,Délai d'échelle reflections,,,Reflections Delay音階,룸 반사 딜레이 음계,,,Escala de Atraso de Reflexos,,,, -Decay Time Scale,REVMNU_Decay_Time_Scale,,,,,,,Tempskalo de Purtiĝo,Escala de Tiempo de Decadencia,,Häipymäajan skaala,Echelle temporelle Decay,,,Decay Time音階,잔향 감쇠시간 음계,,,Escala de Tempo de Decaimento,,,, -Decay HF Limit,REVMNU_Decay_HF_Limit,,,,,,,AF-Limito de Purtiĝo,Limite de Decadencia de Alta Frecuencia,,Häipymän korkeiden taajuuksien raja-arvo,,,,Decay HF限度,잔향 감쇠 HF 한도,,,Limite de Decaimento em Alta Freq.,,,, -Reverb Scale,REVMNU_Reverb_Scale,,,,,,,Skalo de Resono,Escala de Reverberación,,Jälkikaiunnan skaala,Echelle Reverb,,,Reverb音階,리버브 음계,,,Escala de Reverberação,,,, -Reverb Delay Scale,REVMNU_Reverb_Delay_Scale,,,,,,,Prokrastskalo de Resono,Escala de Retraso de Reverberación,,Jälkikaiunnan viiveen skaala,Délai d'échelle Reverb,,,Reverb Delay音階,리버브 딜레이 음계,,,Escala de Atraso de Reverberação,,,, -Echo Time Scale,REVMNU_Echo_Time_Scale,,,,,,,Tempskalo de Eko,Escala de Tiempo de Eco,,Kaikuajan skaala,Echelle temporelle Echo,,,Echo Time音階,에코 시간 음계,,,Escala de Tempo de Eco,,,, -Modulation Time Scale,REVMNU_Modulation_Time_Scale,,,,,,,Tempskalo de Modulado,Escala de Tiempo de Modulación,,Modulaatioajan skaala,Echelle temporelle Modulation,,,Modulation Time音階,전조 시간 음계,,,Escala de Tempo de Modulação,,,, -Based on,REVMNU_Based_on,,,,Založeno na,Basierend auf,Βασισμένο σε,Bazita de,Basado En,,Perustana,Basé sur,,Basato su,音響の元,음향 원본,Gebaseerd op,Bazowane na,Baseado em,,Bazat pe,Основано на,Засновано на -Name,REVMNU_Name,,,,Název,,Όνομα,Nomo,Nombre,,Nimi,Nom,,Name,名前,이름,Naam,Nazwa,Nome,,Nume,Название,Назив -ID #1,REVMNU_ID_1,,,,,,ID #1,ID #1,ID Nº1,,,,,,,아이디 #1,,ID #1,,,,, -ID #2,REVMNU_ID_2,,,,,,ID #2,ID #2,ID Nº2,,,,,,,아이디 #2,,ID #2,,,,, -Create,REVMNU_Create,,,,Vytvořit,Erstellen,Δημιουργία,Krei,Crear,,Luo,Créer,,Creare,作成,생성,Creëren,Stwórz,Criar,,Creare,Создать,Направи -Save...,REVMNU_Save,,,,Uložit...,Speichern...,Αποθήκευση,Konservi...,Guardar...,,Tallenna...,Sauvegarder...,,Salvare...,セーブする...,저장 하기...,Opslaan ...,Zapisz...,Salvar...,,Salvare...,Сохранить...,Сачувај... -File name,REVMNU_File_name,,,,Název souboru,Dateiname,Όνομα αρχείου,Dosiernomo,Nombre de Archivo,,Tiedostonimi,Nom de fichier,,Nome del file,ファイル名,파일 이름,Bestandsnaam,Nazwa pliku,Nome do arquivo,,Nume fișier,Название файла,Назив фајла -Environments to save,REVMNU_Environments_to_save,,,,Prostředí k uložení,Zu speichernde Umgebungen,Περιβάλλοντα για αποθήκευση,Medioj konserviĝendaj,Ambientes para Guardar,,Tallennettavat tilat,Environnements à sauvegarder,,Ambienti da salvare,音響を保存,저장할 공간,Omgevingen om op te slaan,Środowiska do zapisu,Ambientes para salvar,,Medii de salvat,Сохранить окружения…,Окружења за чување -Tonemap Palette Colormap,GLPREFMNU_PALTONECMAP,This line of text is under review,,,,,,Tonmapo Paletro Kolormapo,Colormap para Mapa de Tonos,,Sävykartan paletin värikartta,Tonemap type colormap palette,,,トーンマップ パレット カラーマップ,톤맵 팔레트 컬러맵 설정,,,Colormap da Paleta de Tonemap,,,, -Prevent gray shadows,GLPREFMNU_PALTONENOGREY,,,Prevent grey shadows,Předejít šedým stínům,Vermeide graue Schatten,Απότρεξη γρί σκιών,Preventi grisajn ombrojn,Prevenir sombras grises,,Estä harmaat varjot,Eviter les ombres grises,,Prevenire le ombre grigie,グレイシャドウを防ぐ,회색 그림자 없에기,Voorkom grijze schaduwen,Zapobiegaj szarym cieniom,Prevenir sombras cinzentas,,Prevenire umbre gri,Убрать серые тени,Онемогући сиве сенке -Font Options,HUDMNU_FONTOPTIONS,,,,Nastavení písem,Zeichensatzoptionen,Ρυθμίσεις Γραμματοσειρών,Tiparagordoj,Opciones de fuentes,,Fonttiasetukset,Options de police,,Opzioni di font,フォント オプション,폰트 설정,Lettertype opties,Opcje czcionek,Opções de Fonte,,Setări Font,Настройки шрифта,Подешавања фонта -Use standard font for log display,FONTMNU_LOG,,,,Použít standardní písmo pro záznamy,Benutze Standardzeichensatz für das Log,Χρησιμοποίηση πρότυπης γραμματοσειράς για προβολή ημερολόγιου,Uzi norman tiparon por protokolekrano,Usar la fuente estándar para logs,,Käytä oletusfonttia lokinäytölle,Police standard pour affichage du log,,Usa font standard per la visualizzazione dei messaggi di log,ログ表示に標準フォントを使用,로그 표시에서 기본 폰트 사용,Gebruik het standaardlettertype voor de weergave van logboekberichten,Użyj standardowej czcionki do wyświetlania dziennika,Usar fonte padrão para exibição de log,,Utilizează fontul standard pentru mesajele de tip log,Использовать стандартный шрифт для панели задач,Користи стандардни фонт за приказ лога -Use standard font for dialogues,FONTMNU_DLG,,,,Použít standardní písmo pro dialogy,Benutze Standardzeichensatz für Dialoge,Χρησιμοποίηση πρότυπης γραμματοσειράς,Uzi norman tiparon por dialogoj,Usar la fuente estándar para diálogos,,Käytä oletusfonttia keskustelulle,Police standard pour dialogues,,Usa font standard per la visualizzazione dei dialoghi,ダイアログに標準フォントを使用,대화에서 기본 폰트 사용,Gebruik het standaardlettertype voor dialoogweergave,Użyj standardowej czcionki do dialogów,Usar fonte padrão para diálogos,,Utiliează fontul standard pentru căsuțele de dialog,Использовать стандартный шрифт для диалогов,Користи стандардни фонт за дијалоге -Standard,OPTVAL_YES_STANDARD,copied from elsewhere,,,Standardní,,Πρότυπο,Norma,Estándar,,Normaali,,,,標準,기본,Standaard,Standard,Padrão,,,Стандартный,Стандардни -Enhanced,OPTVAL_YES_ENHANCED,,,,Vylepšené,Verbessert,Ενισχυομένο,Bonigita,Mejorado,,Paranneltu,Amélioré,,Migliorata,強調,고급,Verbeterd,Ulepszone,Melhorado,,Îmbunătățit(ă),Улучшенный,Побољшани -Quick Exit,MISCMNU_QUICKEXIT,,,,Rychlé ukončení,"Schnelles Beenden -",Γρήγορη Έξοδος,Rapide Eliri,Salida Rápida,,Pikapoistuminen,Sortie rapide,,Uscita rapida,終了メッセージ無し,빠른 종료,Snel eindigen,Szybkie wyjście,Saída Rápida,,Ieșire Rapidă,Быстрый выход,Брзи излаз -Disable keyboard cheats,MISCMNU_NOCHEATS,,,,Zakázat cheaty z klávesnice,Tastatur-Cheats deaktivieren,Απενεργοποίηση απάτεον πληκτρολογίου,Malaktivigi klavaran trumpon,Desactivar trucos por teclado,,Poista käytöstä näppäinhuijaukset,Désactiver les tricheurs au clavier,,Disabilita i trucchi della tastiera,キーボードからのチート無効,키보드 전용 치트 해제,Schakel cheats uit,Wyłącz kody na klawiaturze,Desabilitar trapaças de teclado,,Dezactivare coduri,Отключить читы клавиатуры,Онемогући варање тастатуре -Custom Inverse Map,DSPLYMNU_CUSTOMINVERTMAP,,,,Vlastní inverzní mapa,Benutzerdefinierte invertierte Farben,Προσαρμοσμένος Ανάποδος Χάρτης,Agorda Mala Mapo,Personalizar Filtro Invertido,,Mukautettu käänteinen kartta,Couleurs inverses personnalisées,,Mappa inversa personalizzata,カスタム反転マップ,사용자 지정 반전 맵,Aangepaste omgekeerde kleuren,Niestandardowe odwrócone kolory,Personalizar Cores Invertidas,,Personalizare Inverse Map,Настраиваемая обратная карта,Прилагођена обрнута мапа +""globals.json"".",%s nu este o salvare validă. Lipsește 'globals.json'.,Сохранение «%s» некорректно: отсутствует «globals.json».,%s није валидно сачувана игра: Недостаје „globals.json“.,"%s"" är inte ett giltigt sparfil: Saknar ""globals.json"".",%s' geçerli bir kayıt oyunu değil: Eksik 'globals.json'., +Failed to access savegame info in '%s',TXT_SGINFOERR,,,,Nepodařilo se načíst informace v uložené hře '%s'.,Fejlslagen adgang til savegame info i '%s',Konnte Spielstandinformationen von '%s' nicht lesen.,Η πρόσβαση πληροφοριών του αρχείου αποθήκευσης %s δέν ήταν επιτυχής,Malsukcesis aliri informon de la konservita ludo en '%s',Fallo al acceder a información de partida guardada en '%s'.,,Tiedoston '%s' pelitallennetietoihin ei päästy käsiksi.,Impossible d'accéder aux infos de sauvegarde dans le fichier '%s'.,A '%s' -ban nem található mentési információ.,Accesso alle informazioni sul salvataggio in '%s' fallito,%s' のセーブデータにアクセス出来なかった,%s'의 저장된 게임 정보에 액세스 할 수 없습니다.,Geen toegang tot savegame info in '%s'.,Kunne ikke få tilgang til lagringsinformasjon i '%s'.,Nie udało się dostać informacji zapisu „%s”.,"Não foi possível acessar a informação do jogo salvo em ""%s"".","Não foi possível acessar a informação do jogo gravado em ""%s"".",Informațiile salvării '%s' nu au putut fi accesate,Невозможно получить информацию из сохранения «%s».,Не успешно приступљено саучуваној игри у %s,"Misslyckades med att få tillgång till information om sparfilet i ""%s"".",%s' içindeki savegame bilgisine erişilemedi, +A game save is still pending.,TXT_SAVEPENDING,,,,Stále se čeká na uložení hry.,Et spilopbevaringsspil venter stadig på at blive gemt.,Das Speichern eines Spielstandes steht noch aus.,Μια αποθήκευση παιχνιδίου είναι ακόμα σε αναμονή,Konservita ludo ankoraŭ estas pritraktata.,Un guardado de partida aún está pendiente.,,Pelin tallennus on vielä kesken.,Une sauvegarde est déjà en cours.,A mentés folyamatban.,Un salvataggio di gioco è ancora in corso.,セーブ中だ,게임 저장이 아직 보류 중입니다.,Een spel opslaan is nog steeds in behandeling.,En spilloppdatering venter fortsatt.,Zapis gry jest wciąż w toku.,Jogo salvo ainda pendente.,Jogo gravado ainda pendente.,O salvare este încă în așteptare.,Сохранение в очереди.,Сачувана игра идаље чека,Ett sparande av spelet väntar fortfarande.,Bir oyun kaydı hala beklemede., +Not in a saveable game.,TXT_NOTSAVEABLE,,,,Nejsi v uložitelné hře.,"Ikke i et spil, der kan gemmes.",Kein speicherbares Spiel aktiv.,Δέν είσαι σε ένα παιχνίδει που μπορεί να αποθηκευτεί,Ne estas en konservebla ludo.,No en una partida guardable.,,Ei tallennettavassa pelissä.,Vous n'êtes pas dans une partie sauvegardable.,Nem menthető játék.,Non è in un gioco salvabile.,セーブ可能なゲームではない,저장 가능한 게임에선 불가능 합니다.,Geen opslagbaar spel actief.,Ikke i et spill som kan lagres.,Nie w grze do zapisywania.,Não está em uma partida salvável.,Não estás numa partida que possa ser gravada.,Nu ești într-un joc în care poți salva.,Не в сохранимой игре.,Није у сачувајућој игри,Inte i ett spel som kan sparas.,Kaydedilebilir bir oyunda değil., +Not in a level,TXT_NOTINLEVEL,,,,Nejsi v levelu.,Ikke i en kort,Nicht in einem Level.,Δέν ε'ισαι σε μια πίστα,Ne estas en nivelo,No en un nivel,,Ei tasossa,Vous n'êtes pas dans un niveau.,Nem menthető pályán van.,Non è in un livello,レベル内ではない,레벨 안에선 불가능 합니다.,Niet in een level,Ikke i et nivå,Nie w poziomie.,Não está em uma fase.,Não estás em nenhum nível.,Nu ești în niciun nivel,Не на уровне,Није у нивоу,Inte i en nivå.,Bir seviyede değil, +Player is dead in a single-player game,TXT_SPPLAYERDEAD,,,,Hráč je mrtvý v singleplayer hře.,Spilleren er død i et single-player spil,Spieler ist tot in einem Einzelspieler-Spiel.,Ο παίχτης έιναι νεκρός σε ένα singleplayer παιχνίδι,Ludanto estas mortinta en sol-ludanta ludado,Jugador muerto en partida de un solo jugador,,Pelaaja on kuollut yksinpelissä,Le joueur est mort en mode solo.,Játékos meghalt egy egyjátékos módban.,Il giocatore è morto in un gioco single player,シングルプレイでプレイヤーが死んだ,플레이어가 싱글 플레이 게임에서 죽었습니다.,Speler is dood in een een-speler spel,Spilleren er død i et enspiller-spill,Gracz jest martwy w grze dla jednego gracza,Jogador está morto em partida single player.,Jogador está morto numa partida single player.,Jucătorul este mort într-un joc single-player,Игрок мёртв в одиночной игре,Играч је мртав у сингл-плејер игри,Spelaren är död i ett enspelarspel.,Oyuncu tek oyunculu bir oyunda öldü, +Save failed,TXT_SAVEFAILED,,,,Uložení se nezdařilo.,Save mislykkedes,Speichern fehlgeschlagen.,Η αποθήκευση απέτυχε,Konservo malsukcesis,Guardado fallido,,Tallennus epäonnistui,La sauvegarde à échoué.,Mentés meghiusult,Salvataggio fallito,セーブに失敗した。,저장 실패,Opslaan mislukt,Lagring mislyktes,Nie udało się zapisać,Falha ao salvar,Falha ao gravar,Salvare eșuată,Ошибка сохранения игры,Сачување није успело,Spara misslyckades.,Kaydetme başarısız, +Could not create screenshot.,TXT_SCREENSHOTERR,,,,Nepodařilo se pořídit snímek obrazovky.,Kunne ikke oprette et skærmbillede.,Konnte Screenshot nicht erzeugen.,Ένα screenshot δέν μπόρεσε να τραβυχτεί,Ne povis krei ekrankopion.,No se pudo crear captura de pantalla.,,Ei voitu ottaa kuvakaappausta.,La capture d'écran à échoué.,Képernyőmentés meghiusult,Non è stato possibile effettuare la cattura dello schermo.,スクリーンショットを作成できなかった。,스크린샷을 만들 수 없음.,Kon geen screenshot maken.,Kunne ikke opprette skjermbilde.,Nie można zrobić zrzutu ekranu.,Não foi possível capturar a tela.,Não foi possível capturar ecrã,Captura de ecran nu a putut fi creată.,Ошибка создания снимка экрана.,Није успело направити снимак екрана.,Kunde inte skapa en skärmdump.,Ekran görüntüsü oluşturulamadı., +By %s,TXT_BY,As in paused by player %s.,,,hráčem %s,Af %s,Von %s,Απο @[pro_gr] %s,De %s,Por %s,,Pelaajan %s toimesta,Par %s,%s által,Da %s,"%s より +",%s 에 의해,Met %s,Etter %s,Przez %s,Por %s,,De către %s,игроком %s,играчем %s,Av %s,Tarafından %s, +Press any key or click anywhere in the window to quit.,TXT_QUITENDOOM,,,,"Pro ukončení stiskni libovolnou klávesu, nebo klikni kdekoliv v okně.",Tryk på en vilkårlig tast eller klik et vilkårligt sted i vinduet for at afslutte.,Drücke eine Taste oder klicke mit der Maus ins Fenster zum Beenden.,Πάτα οποιοδήποτε πλήκτρο ή πάτα οπουδήποτε για να κάνεις έξοδο,Premu ajnan klavon aŭ alklaku ie ajn en la fenestro por forlasi.,Presiona una tecla o haz click en cualquier lugar de la ventana para salir.,,Paina mitä tahansa näppäintä tai napsauta minne tahansa ikkunaa lopettaaksesi.,Appuyez sur une touche ou cliquez pour quitter.,Nyomjon egy billentyűt vagy kattintson bárhova a kilépéshez.,Premi un qualunque tasto o fai un click ovunque nella finestra per uscire.,何かのキーを押すか、ウィンドウのどこかをクリックすると終了する。,아무 키를 누르거나 아무 곳이나 클릭하면 종료됩니다.,Druk op een willekeurige toets of klik ergens in het venster om te stoppen.,Trykk på en hvilken som helst tast eller klikk hvor som helst i vinduet for å avslutte.,Wciśnij dowolny klawisz lub gdziekolwiek kliknij myszką aby wyjść.,Aperte qualquer tecla ou clique em qualquer lugar na janela para sair.,Carrega numa tecla ou clique em qualquer lugar na janela para sair.,Apasă orice tastă sau dă click oriunde în fereastră pentru a ieși.,"Нажмите любую клавишу или нажмите по окну, чтобы выйти.",Притисните било који тастер или кликните било где на екрану да одустанете.,Tryck på någon tangent eller klicka någonstans i fönstret för att avsluta.,Çıkmak için herhangi bir tuşa basın veya pencerede herhangi bir yere tıklayın., +Screen Blend Options,HUDMNU_FLASH,,,,Barvení obrazovky,Indstillinger for skærmblanding,Überblendoptionen,Ρυθμίσεις Ανάμειξης Οθόνης,Ekranmisko-Agordoj,Opciones de tintado de pantalla,,Näytön sekoitusasetukset,Options de blending écran,Képernyő Keverés Beállítások,Opzioni Blending dello Schermo,スクリーンブレンド オプション,화면 조합 설정,Opties voor schermmengsel,Alternativer for skjermblanding,Opcje scalania ekranu,Opções de mescla de tela,Opções de mistura de ecrã,Setări Amestec Imagine,Настройки смешивания экрана,Подешавања блед екрана,Alternativ för skärmblandning,Ekran Karışım Seçenekleri, +3D mode,GLMNU_3DMODE,,,,3D režim,3D-tilstand,3D Modus,3D λειτουργία,3D-reĝimo,Modo 3D,,3D-tila,Mode 3D,3D mód,Modalità 3D,3Dモード,3D 모드 적용,3D-modus,3D-modus,Tryb 3D,Modo 3D,,Mod 3D,Режим 3D,3D режим,3D-läge,3D modu, +Crosshair,HUDMNU_CROSSHAIRON,,,,Zaměřovač,Trådkors,Fadenkreuz,,Reteto,Retícula,,Tähtäin,Viseur,Célkereszt,Mirino,クロスヘア,조준점,Draadkruis,Trådkors,Celownik,Mira,,Țintă,Прицел,Нишан,Hårkors,, +Subtitles,MSGMNU_SUBTITLES,,,,Titulky,Undertekster,Untertitel,Υπότιτλοι,Subtekstoj,Subtítulos,,Tekstitys,Sous-titres,Feliratok,Sottotitoli,サブタイトル,자막,Ondertitels,Undertekster,Napisy,Legendas,,Subtitrări,Субтитры,Титлови,Undertexter,Altyazılar, +Prevent gray shadows,GLPREFMNU_PALTONENOGREY,,,Prevent grey shadows,Předejít šedým stínům,Forebyg grå skygger,Vermeide graue Schatten,Απότρεξη γρί σκιών,Preventi grizajn ombrojn,Prevenir sombras grises,,Estä harmaat varjot,Eviter les ombres grises,Szürke árnyákok megakadályozása,Prevenire le ombre grigie,グレイシャドウを防ぐ,회색 그림자 없에기,Voorkom grijze schaduwen,Forhindre grå skygger,Zapobiegaj szarym cieniom,Prevenir sombras cinzentas,,Prevenire umbre gri,Убрать серые тени,Онемогући сиве сенке,Förhindra gråa skuggor,Gri gölgeleri önleyin, +Font Options,HUDMNU_FONTOPTIONS,,,,Písma,Indstillinger for skrifttyper,Zeichensatzoptionen,Ρυθμίσεις Γραμματοσειρών,Tiparo-Agordoj,Opciones de fuentes,,Fonttiasetukset,Options de police,Betű Beállítások,Opzioni per il tipo di carattere,フォント オプション,폰트 설정,Lettertype opties,Alternativer for skrifttype,Opcje czcionek,Opções de Fonte,,Setări Font,Настройки шрифта,Подешавања фонта,Typsnittsalternativ,Yazı Tipi Seçenekleri, +Use standard font for log display,FONTMNU_LOG,,,,Použít standardní font pro záznamy,Brug standardskrifttype til visning af logfiler,Benutze Standardzeichensatz für das Log,Χρησιμοποίηση πρότυπης γραμματοσειράς για προβολή ημερολόγιου,Uzi norman tiparon por protokola ekrano,Usar la fuente estándar para logs,,Käytä oletusfonttia lokinäytölle,Police standard pour affichage du log,Szabvány betűstílus használata a logokhoz,Usa il tipo di carattere di default per la visualizzazione dei messaggi di log,ログ表示に標準フォントを使用,로그 표시에서 기본 폰트 사용,Gebruik het standaardlettertype voor de weergave van logboekberichten,Bruk standard skrifttype for loggvisning,Użyj standardowej czcionki do wyświetlania dziennika,Usar fonte padrão para exibição de log,,Utilizează fontul standard pentru mesajele de tip log,Использовать стандартный шрифт для журнала,Користи стандардни фонт за приказ лога,Använd standardtypsnitt för loggvisningen,Günlük ekranı için standart yazı tipi kullanın, +Use standard font for dialogues,FONTMNU_DLG,,,,Použít standardní font pro dialogy,Brug standardskrifttype til dialoger,Benutze Standardzeichensatz für Dialoge,Χρησιμοποίηση πρότυπης γραμματοσειράς,Uzi norman tiparon por dialogoj,Usar la fuente estándar para diálogos,,Käytä oletusfonttia keskustelulle,Police standard pour dialogues,Szabvány betűstílus használata a dialógusokhoz,Usa il tipo di carattere di default per la visualizzazione dei dialoghi,ダイアログに標準フォントを使用,대화에서 기본 폰트 사용,Gebruik het standaardlettertype voor dialoogweergave,Bruk standard skrifttype for dialoger,Użyj standardowej czcionki do dialogów,Usar fonte padrão para diálogos,,Utiliează fontul standard pentru căsuțele de dialog,Использовать стандартный шрифт для диалогов,Користи стандардни фонт за дијалоге,Använd standardtypsnitt för dialoger,Diyaloglar için standart yazı tipi kullanın, +Quick Exit,MISCMNU_QUICKEXIT,,,,Rychlé ukončení,Hurtig afslutning,"Schnelles Beenden +",Γρήγορη Έξοδος,Rapida Eliro,Salida Rápida,,Pikapoistuminen,Sortie rapide,Gyors kilépés,Uscita rapida,終了メッセージ無し,빠른 종료,Snel eindigen,Hurtigavslutning,Szybkie wyjście,Saída Rápida,,Ieșire Rapidă,Быстрый выход,Брзи излаз,Snabbavslutning,Hızlı Çıkış, +Custom Inverse Map,DSPLYMNU_CUSTOMINVERTMAP,,,,Vlastní inverzní barvení,Brugerdefinerede omvendte farver,Benutzerdefinierte invertierte Farben,Προσαρμοσμένος Ανάποδος Χάρτης,Propra Inversa Mapo,Personalizar Filtro Invertido,,Mukautettu käänteinen kartta,Couleurs inverses personnalisées,Egyéni inverz pálya,Mappa inversa personalizzata,マップ反転色カスタム,사용자 지정 반전 맵,Aangepaste inversiekleuren,Egendefinert omvendt kart,Niestandardowe odwrócone kolory,Personalizar Cores Invertidas,,Personalizare Inverse Map,Настроить цвета при неуязвимости,Прилагођена обрнута мапа,Anpassad omvänd karta,Özel Ters Harita, "Custom Inverse Color Dark -",DSPLYMNU_CUSTOMINVERTC1,,,Custom Inverse Colour Dark,Vlastní inverzní tmavá barva,Dunkle Farbe für Invertierung,Προσαρμοσμένος Ανάποδο Χρώμα Σκοτεινό,Agorda Mala Kolormelhelo,"Color Oscuro de Filtro Invertido -",,Mukautettu käänteinen tumma väri,Couleur foncée pour l'inversion,,Colore inverso personalizzato scuro,カスタム反転色 暗め,사용자 지정 어두운 반전 색상,Donkere kleur voor inversie,Ciemny kolor do inwersji,Personalizar Cores Invertidas - Cor escura,,Personalizare Culoare Inverse Map Întunecată,Пользовательский обратный цвет темный,Прилагођена инверзна боја тамна -Custom Inverse Color Light,DSPLYMNU_CUSTOMINVERTC2,,,Custom Inverse Colour Light,Vlastní inverzní světlá barva,Helle Farbe für Invertierung,Προσαρμοσμένος Ανάποδο Χρώμα Φωτεινό,Agorda Mala Kolorhelo,Color Claro de Filtro Invertido,,"Mukautettu käänteinen vaalea väri -",Couleur claire pour l'inversion,,Luce inversa di colore personalizzata,カスタム反転色 明るめ,사용자 지정 밝은 반전 색상,Lichte kleur voor inversie,Jasny kolor do inwersji,Personalizar Cores Invertidas - Cor clara,,Personalizare Culoare Inverse Map Deschisă,Пользовательский обратный цвет света,Прилагођено инверзно светло у боји -Preferred Rendering API,VIDMNU_PREFERBACKEND,,,,Upřednostňované renderovací API,Bevorzugtes Render API,Προτιμούμενο Rendering API,Preferita Bildigado de API,API de Renderizado Preferida,,Ensisijainen hahmonnuksen ohjelmointirajapinta,API de rendu préférée,,API di rendering preferita,優先レンダリングAPI,기본적인 API 랜더링,Voorkeur render-API,Preferowany interfejs API renderowania,API de Renderização Preferida,,API Video Preferat,Предпочтительный интерфейс рендеринга,Преферред АПИ приказивања -OpenGL,OPTVAL_OPENGL,,,,,,,,,,,,,,,,,,,,,, -Vulkan,OPTVAL_VULKAN,,,,,,,,,,,,,,,,,,,,,, -SoftPoly,OPTVAL_SOFTPOLY,,,,,,,,,,,,,,,,,,,,,, -Lowest Possible Scale,OPTVAL_LOWEST,"This describes vid_scalemode 6, which represents the lowest possible scaling to fill the allocated screen area",,,Nejmenší možná velikost,Kleinstmögliche Auflösung,Μικρότερο Δυνατόν Μέγεθος,Plej Malpli Ebla Skalo,Menor Escala Posible,,Pienin mahdollinen asteikko,Echelle la plus faible,,Scala più bassa possibile,可能な限り最小,최소 낮은 척도,Laagst mogelijke schaal,Najniższa możliwa skala,Menor Escala Possível,,Cea mai mică scară posibilă,Минимально возможный масштаб,Најнижа могућа скала -,USE_GENERIC_FONT,This is not a text to be translated but an engine switch for complex languages.,,,,,,,,,,,,,1,1,,,,,,, -,REQUIRED_CHARACTERS,This should list all uppercase characters that are REQUIRED for proper language display. If it is acceptable that accents get omitted a character should NOT be listed here!,,,ÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ,ÄÖÜẞ,ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩς,ĈĜĤĴŜŬ,ÁÉÍÓÚÑÜ,,ÄÖ,ÀÂÇÉÈÊËÎÏÔŒÙÛŸ,ÁÉÍÓÖÚÜŐŰ,ÀÈÉÌÒÙ,,,"ÉËÖ -",ĄĆĘŁŃÓŚŹŻ,ÁÉÍÓÚÀÃÕÂÊÔÇ,,ĂÎȚÂȘ,АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ,АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ \ No newline at end of file +",DSPLYMNU_CUSTOMINVERTC1,,,Custom Inverse Colour Dark,Vlastní inverzní tmavá barva,Brugerdefineret omvendt farve mørk,Dunkle Farbe für Invertierung,Προσαρμοσμένος Ανάποδο Χρώμα Σκοτεινό,Propra Inversa Koloro Malhela,"Color Oscuro de Filtro Invertido +",,Mukautettu käänteinen tumma väri,Couleur foncée pour l'inversion,Egyéni inverz sötét szín,Colore inverso personalizzato scuro,反転色カスタム 暗,사용자 지정 어두운 반전 색상,Aangepaste donkere inversiekleur,"Egendefinert invers farge mørk +",Ciemny kolor do inwersji,Personalizar Cores Invertidas - Cor escura,,Personalizare Culoare Inverse Map Închisă,Тёмный цвет,Прилагођена инверзна боја тамна,"Anpassad omvänd färg Mörk +","Özel Ters Renk Koyu +", +Custom Inverse Color Light,DSPLYMNU_CUSTOMINVERTC2,,,Custom Inverse Colour Light,Vlastní inverzní světlá barva,Brugerdefineret omvendt farve lys,Helle Farbe für Invertierung,Προσαρμοσμένος Ανάποδο Χρώμα Φωτεινό,Propra Inversa Koloro Hela,Color Claro de Filtro Invertido,,"Mukautettu käänteinen vaalea väri +",Couleur claire pour l'inversion,Egyéni inverz világos szín,Colore inverso personalizzato chiaro,反転色カスタム 明,사용자 지정 밝은 반전 색상,Aangepaste lichte inversiekleur,Egendefinert invers farge lys,Jasny kolor do inwersji,Personalizar Cores Invertidas - Cor clara,,Personalizare Culoare Inverse Map Deschisă,Светлый цвет,Прилагођено инверзно светло у боји,Anpassad omvänd färg ljus,Özel Ters Renkli Işık, +Weapon bob amount when firing,DSPLYMNU_BOBFIRE,,,,Pohupování zbraně při střelbě,Våben bob-beløb ved affyring,Waffenpendeln beim Schießen,,Vidi kvanton de kapo-balanciĝo dum pafado,Balanceo de pantalla al disparar,,Aseen heilumisvoimakkuus ammuttaessa,Intensité du chaloupage lors des tirs,Fegyvermozgás lövésnél,Movimento dell'arma quando si spara,射撃時の武器スイング,사격 시 무기 스윙,Wapenzwaai bij schieten,Våben bob-beløp ved avfyring,Częstotliwość bujania się broni przy strzelaniu,Quantidade de balanço ao atirar,,Intensitate mișcare arme în timpul deplasării,Кол-во тряски экрана при стрельбе,,Vapen bob-värde vid skottlossning,Ateşleme sırasında bob miktarını görüntüleme, +Intermission and Screen Border Classic Scaling,SCALEMNU_SCALECLASSIC,HUD->Scaling Options,,,Klasické škálování text. obrazovek a okrajů obrazovky,Pause og skærmkant Klassisk skalering,Klassische Skalierung von Texthintergrund und Rahmen,,Klasika Skalado de Intermito kaj Ekranbordero,Escalado Clásico de Intermisión y Bordes de Pantalla,,Perinteinen väliruutujen ja ruudunreunusten skaalaus,Mise à l'échelle classique pour bordure écran et intermission,Megszakító és Képszél klasszikus arányosítása,Ridimensionamento classico dell'intermissione e del bordo dello schermo,旧式スケールのクリア結果と画面ボーダー,인터미션 및 화면 테두리 클래식 스케일링,Intermissie en schermrand schalen,Klassisk skalering av pause og skjermkant,Klasyczne skalowanie wstawek i ramek,Escala clássica para tela de intervalo e borda de tela,,Scară bordură antract și ecran,Классические размеры экрана между миссиями и границ экрана,Класично скалирање паузе и ивице екрана,Klassisk skalning för paus och skärmkant,Ara ve Ekran Kenarlığı Klasik Ölçeklendirme, +Intermission background,SCALEMNU_INTER,,,,Pozadí textových obrazovek,Intermission baggrund,Texthintergrund,,Fono de intermito,Fondo de intermisión,,Väliruutujen tausta,Fond d'écran intermission,Megszakító háttér,Sottofondi delle intermissioni,クリア結果の背景,인터미션 배경,Intermissieachtergrond,Pause bakgrunn,Tło wstawek,Fundo da tela de intervalo,,Fundal antract,Фон экрана между миссиями,Интермиссион бацкгроунд,Bakgrund för mellanslag,Devre arası arka planı, +Screen border,SCALEMNU_BORDER,,,,Okraje obrazovky,Skærmbord,Rahmen,,Ekranbordero,Bordes de pantalla,,Ruudunreunus,Bordure d'écran,Kép széle,Bordo dello schermo,画面ボーダー,화면 테두리,Schermrand,Skjermkant,Ramka,Borda de tela,,Bordură ecran,Границы экрана,Граница екрана,Skärmgräns,Ekran kenarlığı, +Scaling factor,SCALEMNU_FACTOR,,,,Měřítko,Skaleringsfaktor,Skalierungsfaktor,,Skalfaktoro,Factor de escalado,,Skaalauskerroin,Facteur de mise à l'échelle,Arányosító faktor,Fattore di scala,スケーリング倍率,스케일링 계수,Schaalfactor,Skaleringsfaktor,Współczynnik skalowania,Fator de escala,,Factor de scalare,Значение масштабирования,Фактор за скалирање,Skalningsfaktor,Ölçekleme faktörü, +Aspect ratio,SCALEMNU_RATIO,,,,Poměr stran,Aspektforhold,Seitenverhältnis,,Proporcio,Ratio de aspecto,,Kuvasuhde,,Képarány,Proporzioni,アスペクト比,화면 비율,Beeldverhouding,Bildeforhold,Rozdzielczość,Proporção de tela,,Aspect imagine,Соотношение сторон,Однос ширине и висине,Bildförhållande,En boy oranı, +Build,OPTVAL_BUILD,"as in ""Build engine"". This should not be translated unless there is a translated name for the engine",,,,,,,,,,,,,,,,,,,,,,,,,, +Show Tally Screen On Level Exit,MISCMNU_ALWAYSTALLY,sv_alwaystally,,,Zobrazit výsledky na konci mapy,"Vis resultater, når du forlader kortet",Zeige Ergebnisse beim Verlassen des Levels,,Montri Kalkulekranon Sur Niveleliro,Mostrar pantalla de conteo al salir de nivel,,Näytä pisteruutu tasosta poistuttaessa,Montrer les scores en fin de niveau,Elért pontok mutatása a megszakító képen,Mostra i punteggi alla fine del livello,Exit時にタリー画面を表示,레벨 종료 시 집계 화면 표시,Toon tellingen na eind van het level,Vis Tally-skjerm på nivåutgang,Pokazuj wyniki pod koniec poziomu,Exibir tela de pontuação no fim da fase,,Afișează Totalul la Ieșirea din Nivel,Отображение экрана статистики при выходе с уровня,Прикажи екран за израчунавање на излазу из нивоа,Visa Tally-skärmen på nivå Avsluta,Seviye Çıkışında Çetele Ekranını Göster, +Mod Defined,OPTVAL_MODDEFINED,this is '==0',,,Určeno mody,Mod Defineret,Mod-definiert,,Difinita per modifaĵo,Definido por mod,,Modin määrittämä,Défini par Mod,Beállított Mod,Definito dalla mod,Mod定義,모드 정의,Volgens de mod,Mod Definert,Zdefiniowane przez modyfikację,Definir por mod,,Definit de către moduri,Определено модификацией,Мод Дефинед,Mod definierad,Mod Tanımlı, +"Always, except within hubs",OPTVAL_NOTHUBS,,,,Vždy kromě hubů,"Altid, undtagen i hubs","Immer, außer in Hubs",,"Ĉiam, krom en naboj","Siempre, excepto en hubs",,"Aina, keskustasoja lukuun ottamatta","Toujours, sauf dans les hubs","Mindig, kivétel a csomópontoknál","Sempre, tranne gli hub",区間を除き、常に,"항상, 허브 내 제외","Altijd, behalve binnen hubs","Alltid, unntatt innenfor knutepunkter","Zawsze, oprócz hubów","Sempre, exceto em hubs",,"Mereu, mai puțin în hub-uri",Всегда (кроме групп уровней),"Увек, осим унутар чворишта","Alltid, utom i nav","Her zaman, hub'lar hariç", +"Always, even within hubs",OPTVAL_WITHHUBS,,,,Vždy včetně hubů,"Altid, også inden for hubs","Immer, auch in Hubs",,"Ĉiam, eĉ en naboj","Siempre, incluso en hubs",,"Aina, keskustasot mukaan lukien","Toujours, même dans les hubs","Mindig, még a csomópontoknál is","Sempre, inclusi gli hub",区間内でも、常に,"항상, 허브 내에서도","Altijd, zelfs binnen hubs","Alltid, også innenfor knutepunkter","Zawsze, nawet w hubach","Sempre, inclusive em hubs",,"Mereu, inclusiv în hub-uri",Всегда (включая группы уровни),"Увек, чак и унутар чворишта","Alltid, även inom nav","Her zaman, merkezler içinde bile", +Preferred keyboard layout,CNTRLMNU_LAYOUT,,,,Preferované rozložení klávesnice,Foretrukket tastaturlayout,Bevorzugte Tastaturbelegung,,Preferita klavararanĝo,Disposición de teclado preferida,,Lempinäppäinasettelu,Organisation préférée du clavier,Preferált billentyűkiosztás,Layout della tastiera preferito,優先するキー配列,기본 키보드 레이아웃,Voorkeur toetsenbordindeling,Foretrukket tastaturoppsett,Preferowany układ klawiatury,Layout de teclado preferido,,Schemă de control preferată,Раскладка клавиатуры,Жељени распоред тастатуре,Föredragen tangentbordslayout,Tercih edilen klavye düzeni, +Classic ZDoom,OPTVAL_CLASSICZ,,,,Klasický ZDoom,Klassisk ZDoom,ZDoom klassisch,,Klasika ZDoom,ZDoom clásico,,Perinteinen ZDoom,Zdoom Classique,Klasszikus ZDoom,ZDoom Classico,従来のZDOOM,클래식 ZDoom,Klassiek ZDoom,Klassisk ZDoom,Klasyczny ZDoom,ZDoom Clássico,,ZDoom Clasic,Классическая ZDoom,Цлассиц ЗДоом,Klassiskt ZDoom,Klasik ZDoom, +Modern (WASD),OPTVAL_MODERN,,,,Moderní (WASD),Moderne (WASD),,,Moderna (WASD),Moderno (WASD),,Nykyaikainen (WASD),Moderne (ZQSD),,Moderno (WASD),現代的(WASD),모던(WASD),,Moderne (WASD),Współczesny (WSAD),Moderno (WASD),,Modernă (WASD),Современная (ЦФЫВ),модерно,Modernt (WASD),, +Modern (Keypad),OPTVAL_MODERNLEFT,,,,Moderní (číselník),Moderne (Keypad),,,Moderna (Cifera klavaro),Moderno (Teclado Numérico),,Nykyaikainen (numeronäppäimistö),Moderne (Pavé numérique),Modern (numpad),Moderno (tastierino numerico),現代的(Keypad),모던(키패드),Modern (nummeriek toetsenbord),Moderne (Keypad),Współczesny (klawiatura numeryczna),Moderno (Teclado numérico),,Modernă (Tastatură),Современная (цифр. клавиатура),Модерна (тастатура),Modernt (tangentbord),Modern (Tuş Takımı), +Strict KEYCONF Weapons/Players,MISCMNU_SETSLOTSTRICT,,,,Striktně zbraně/hráči z KEYCONF,Strenge KEYCONF Våben/spillere,Strikte KEYKONF Behandlung für Waffen und Spieler,,Strikta KEYCONF Armiloj/Ludantoj,KEYCONF de Armas/Jugadores estricto,,Pelaajien/Aseiden tiukka KEYCONF,Armes/Joueurs strictement selon KEYCONF,Szigorú KEYCONF a Fegyverek/Játékosok esetében,KEYCONF rigoroso per armi/giocatori,厳密なKEYCONFの武器/プレイヤー,엄격한 키콘프 무기/플레이어,Strikte KEYCONF Wapens/Spelers,Strenge KEYCONF-våpen/spillere,Surowe opcje KEYCONF dla broni/graczy,Armas/Jogadores estritamente de acordo com KEYCONF,,KEYCONF Strictă pentru Arme/Jucători,Строгий KEYCONF для оружия/игроков,Строго KEYKONF оружје/играчи,Strikt KEYCONF Vapen/spelare,Sıkı KEYCONF Silahlar/Oyuncular, +Classic ZDoom menu scaling,"MISCMNU_CLEANMENU +",,,,Škálování menu dle starého ZDoomu,Klassisk ZDoom-menu skalering,Alte ZDoom-Skalierung im Menü,,Klasika skalado de ZDoom-menuo,Escalado clásico de ZDoom en menús,,Perinteinen ZDoomin skaalaus valikossa,Mise à l'échelle du menu ZDoom Classique,Klasszikus ZDoom menü arányok,Fattore di scala ZDoom classico per i menu,従来のZDメニュースケール,클래식 ZDoom 메뉴 크기 조정,Klassieke ZDoom-menuschaal,Klassisk ZDoom-menyskalering,Klasyczne skalowanie menu z ZDooma,Escala clássica para menu do ZDoom,,Scară meniuri ZDoom clasică,Классический размер меню ZDoom,Класично скалирање ZDoom менија,Skalning av Classic ZDoom-menyn,Klasik ZDoom menü ölçeklendirme, +Use percents on summary screen,MISCMNU_WIPERCENT,,,,Použít procenta ve výsledcích mapy,Brug procenter på oversigtsskærmen,Zeige Prozente auf Statistikseite,,Uzi procentojn sur resumekrano,Usar porcentajes en pantalla de sumario,,Käytä prosentteja pisteruuduilla,Utiliser pourcentages sur l'écran de fin de niveau,Százalékok használata az összefoglaló oldalon,Usa percentuali per le schermate di riepilogo,集計画面でパーセント表示,요약 화면에서 퍼센트 사용,Gebruik procenten op het overzichtsscherm,Bruk prosenter på sammendragsskjermen,Używaj procentów w ekranie wyników pod koniec poziomu,Usar porcentagem na tela de resumo,,Folosește procentaje la totaluri,Использовать проценты на экране итогов уровня,Користите проценте на екрану резимеа,Använd procentsatser på sammanfattningsskärmen,Özet ekranında yüzdeleri kullanma, +Classic ZDoom scaling on summary screen,MISCMNU_CLEANSTAT,,,,Škálovat obrazovky se shrnutím dle starého ZDoomu,Klassisk ZDoom-skala på oversigtsskærmen,Alte ZDoom-Skalierung auf Statistikseite,,Klasika ZDoom-skalado sur resumekrano,Escalado clásico de ZDoom en pantalla de sumario,,Perinteinen ZDoomin skaalaus pisteruudulla,Mise à l'échelle écran de fin de niveau ZDoom Classique,Klasszikus ZDoom arányok az összefoglaló oldalon,Fattore di scala ZDoom classico per le schermate di riepilogo,集計画面で従来のZDスケール,요약 화면에서 클래식 ZDoom 스케일링,Klassieke ZDoom-schaalverdeling op overzichtsscherm,Klassisk ZDoom-skalering på oppsummeringsskjermen,Klasyczne skalowanie ekranu z wynikami poziomu,Escala clássica do ZDoom na tela de resumo,,Scară ZDoom clasică a tabelei de marcaj,Классический размер ZDoom экрана итогов уровня,Класично ZDoom скалирање на екрану сажетка,Klassisk ZDoom-skalering på sammanfattningsskärmen,Özet ekranında klasik ZDoom ölçeklendirme, +Citizen,TAG_STRIFEZOMBIE,"Called ""citizens"" according to Doomwiki",,,Občan,Borger,Bürger,Πολίτης,Civilulo,Ciudadano,,Kansalainen,Citoyen,Polgár,Cittadino,住民,시민,Burger,Innbygger,Mieszkańcy,Cidadão,,Cetățean,Горожанин,грађанин,Medborgare,Vatandaş, +Ceiling Turret,TAG_CEILINGTURRET,,,,Střílna,Tårn til loftet,Deckengeschütz,,Plafona tureto,Torreta de techo,,Kattotykkitorni,Tourelle de plafond,Plafon lövésztorony,Torretta da soffitto,警備システム,천장 터렛,Plafond torentje,Tak-tårn,Wieżyczka,Defesa Automática,,Turetă de Tavan,Потолочная турель,Цеилинг Туррет,Tak turret,Tavan Tareti, +Crusader,TAG_CRUSADER,Names need to match the obituaries!,,,Křižák,Korsfarer,Ordensritter,,Krucisto,Cruzado,,Ristiretkeläinen,Croisé,Keresztes,Crociato,クルセーダー,성전사,Kruisvaarder,Korsfarer,Krzyżowiec,Cruzado,,Cruciat,Крестоносец,Црусадер,Korsriddar,Haçlı, +Inquisitor,TAG_INQUISITOR,,,,Inkvizitor,Inkvisitor,,,Inkvizitoro,Inquisidor,,Inkvisiittori,Inquisiteur,Inkvizítor,Inquisitore,審問官,인퀴지터,Inquisiteur,Inkvisitor,Inkwizytor,Inquisidor,,Inchizitor,Инквизитор,Инквизитор,Inkvisitor,Engizisyoncu, +Peasant,TAG_PEASANT,,,,Rolník,Bonde,Bauer,Χωρικός,Kamparano,Campesino,,Maallikko,Paysan,Jobbágy,Civile,庶民,농민,Onderdaan,Bonde,Mieszczuch,Camponês,,Sărman,Рабочий,Сељак,Bonde,Köylü, +Reaver,TAG_REAVER,,,,Plenitel,,Plünderer,,Lertulo,Saqueador,,Raastaja,,Fosztogató,Saccheggiatore,リーバー,사수,,,Rozbójnik,Saqueador,,Hoț,Похититель,Реавер,,Yağmacı, +Sentinel,TAG_SENTINEL,,,,Strážbot,,Wächter,,Sentinelo,Centinela,,Vartija,Sentinelle,Őrszem,Sentinella,センティネル,센티넬,,Vaktpost,Strażnik,Sentinela,,Santinelă,Страж,Сентинел,,Nöbetçi, +Stalker,TAG_STALKER,,,,Slídil,,Jäger,,Gvatanto,Acechador,,Vaanija,Chasseur,Lesipuskás,Cacciatore,ストーカー,스토커,,Forfølgeren,Prześladowca,Caçador,,Hărțuitor,Преследователь,Сталкер,,Takipçi, +The Bishop,TAG_BISHOP,,,,Biskup,Biskoppen,Bischof,,La Episkopo,El Obispo,,Piispa,Evèque,A Püspök,Vescovo,ビショップ,비숍,De Bisschop,Biskopen,Biskup,O Bispo,,Episcopul,Епископ,Бискуп,Biskopen,Piskopos, +The One God,TAG_ENTITY,,,,Jeden Bůh,Den ene gud,Der Eine Gott,Ο ένας Θεός,La Vera Dio,El Dios Único,,Yksi Ainoa Jumala,Le Seul Dieu,Az Egy Isten,Unico Dio,唯一神,유일신,De ene god,Den ene Gud,Jedyny Bóg,O Deus Único,,Adevăratul Zeu,Единый Бог,Једини Бог,Den ende guden,Tek Tanrı, +The Programmer,TAG_PROGRAMMER,,,,Programátor,Programmøren,Programmierer,,La Programisto,El Programador,,Ohjelmoija,Programmeur,A Programozó,Programmatore,プログラマー,프로그래머,Programmeur,Programmereren,Programista,O Programador,,Programatorul,Программист,Програмер,Programmeraren,Programcı, +The Spectre,TAG_ALIENSPECTRE,,,,Přízrak,Spøgelset,Schemen,,La Fantomo,El Espectro,,Haamu,Le spectre,A Lidérc,Spettro,スペクトル,스펙터,Het spook,Spøkelset,Widmo,O Espectro,,Spectrul,Фантом,Тхе Спецтре,Spektret,Hortlak, +Kneeling Guy,TAG_KNEELINGGUY,,,,Ctitel,Den knælende fyr,Kniender Typ,,Genuantulo,Tipo arrodillado,,Polvistunut mies,Homme agenouillé,Térdelő,Uomo inchinato,礼拝者,무릎 꿇은 남자,Knielende man,Den knelende fyren,Oddający pokłon,Crente,,Tip Îngenunchiat,Парень на коленях,Човек који клечи,Den knäböjande killen,Diz Çökmüş Adam, +Spawn multiplayer things in coop,GMPLYMNU_MULTIPLAYERTHINGS,,,,Spawnovat multiplayerové předměty v co-opu,Spawn multiplayer-ting i coop,Multispielergegenstände in Coop,,Ekaperigi plurludantajn aĵojn en koopera reĝimo,Hacer aparecer cosas del multijugador en cooperativo,,Luo moninpelioliot yhteispelissä,Objets multijoueurs en co-op,Multiplayer tárgyak létrehozása Együttműködő módban,Fai apparire gli oggetti di multigiocatore in cooperativa,協力モードでマルチ用thingsを出す,협동 플레이에서 멀티플레이어 사물 생성,Spawnen van multiplayer dingen in coop,Spawn multiplayer ting i coop,Daj przedmioty trybu wieloosobowego w trybie kooperacji,Surgir objetos de multijogador no modo coperativo,,Afișează obiectele marcate pentru modul online,Появление вещей из сетевой игры в совместной игре,Поставите ствари за више играча у кооперацији,Spawna multiplayer saker i coop,Coop'ta çok oyunculu şeyler ortaya çıkarma, +Sprite shadows,DSPLYMNU_SPRITESHADOW,,,,Stíny spritů,Sprite skygger,Spriteschatten,,Ombroj de mov-rastrumoj,Sombras de «sprites»,,Spritevarjot,Ombres de sprites,Sprite árnyékok,Ombre per sprite,スプライト シャドウ,스프라이트 그림자,Sprite schaduwen,Sprite skygger,Cienie sprite'ów,Sombras de sprites,,Umbre pentru sprite-uri,Тени спрайтов,Сприте схадовс,Sprite-skuggor,Sprite gölgeleri, +Monsters and players,OPTVAL_SPRSHADALWAYS,Will enable sprite shadows for monster and player sprites,,,Monstra a hráči,Monstre og spillere,Monster und Spieler,Τέρατα και παίχτες,Monstroj kaj ludantoj,Monstruos y jugadores,,Hirviöt ja pelaajat,Monstres et joueurs,Szörnyek és játékosok,Mostri e giocatori,敵とプレイヤー,몬스터와 플레이어,Monsters en spelers,Monstre og spillere,Potwory i Gracze,Monstros e jogadores,,Monștrii și jucători,Монстров и игроков,Чудовишта и играчи,Monster och spelare,Canavarlar ve oyuncular, +FOV,DSPLYMNU_FOV,the FOV slider,,,Zorné pole (FOV),,,,Vidkampo,Campo de visión,,Näkökenttä,Champ de vision,Látószög,Campo visivo,,,,,Pole Widzenia,Campo de visão,,Câmp vizual,Поле зрения,,,, +Disable MBF21 features,CMPTMNU_NOMBF21,,,,Zakázat funkce MBF21,Deaktivere MBF21-funktioner,MBF21 Features deaktivieren,Απενεργοποίηση MBF21 λειτουργιών,Malvalidigi funkciojn de MBF21,Deshabilitar las funciones de MBF21,,Poista MBF21-ominaisuudet käytöstä,Désactiver les fonctionnalités MBF21,MBF21 vonások kikapcsolása,Disabilita le funzioni MBF21,MBF21機能を無効,MBF21 기능 비활성화,MBF21-functies uitschakelen,Deaktiver MBF21-funksjoner,Wyłącz funkcje MBF21,Desativar recursos do MBF21,,Dezactivare caracteristici MBF21,Отключить функции MBF21,Онемогућите функције MBF21,Inaktivera MBF21-funktioner,MBF21 özelliklerini devre dışı bırakma, +Show time widget,ALTHUDMNU_SHOWTIMESTAT,,,,Zobrazit widget s časem,Vis tid widget,Zeige Zeit-Widget,,Montri tempo-fenestraĵon,Mostrar widget de tiempo,,Näytä aikatyökalu,Afficher le widget horloge,Óra mutatása,Mostra orario,ウィジットタイマーの表示,시간 표시 위젯,Tijdwidget tonen,Vis tid widget,Pokaż widżet czasu,Mostrar widget de tempo,,Afișare dispozitiv pt. timp,Показать виджет времени,Прикажи виџет времена,Visa tidswidget,Zaman widget'ını göster, +MBF21,OPTVAL_MBF21,,,,,,,,,,,,,,,,,,,,,,,,,,, +Crushed monsters get resurrected as ghosts,CMPTMNU_VILEGHOSTS,,,,Oživovat rozdrcené příšery jako duchy,Knuste monstre genopstår som spøgelser,Zermalmte Monster werden als Geister wiedererweckt,Συνθλιμένα τέρατα αναστήνοντε ως φαντάσματα,Dispremitaj monstroj reviviĝas kiel fantomojn,Los monstruos aplastados son resucitados como fantasmas,,Murskatut hirviöt heräävät henkiin aaveina...,Les monstres écrasés ressuscitent en fantômes,Összenyomott szörnyek szellemként születnek újra,Mostri schiacciati vengono resuscitati come fantasmi,圧死した敵が蘇生でゴースト化,분쇄된 몬스터는 유령으로 부활합니다.,Verpletterde monsters worden herrezen als geesten,Knuste monstre gjenoppstår som spøkelser,Zmiażdżone potwory wskrzeszone jako duchy,Monstros esmagados ressucitam como fantasmas,,Monștrii striviți sunt readuși la viață ca fantome.,Раздавленные монстры воскресают в виде призраков,Сломљена чудовишта васкрсавају као духови,Krossade monster återuppstår som spöken.,Ezilmiş canavarlar hayalet olarak dirilir, +View bobbing while flying,MISCMNU_FVIEWBOB,,,,Pohupování pohledu při létání,Vis bobbing mens du flyver,Waffenpendeln beim Fliegen,,Vidi kapo-balanciĝon dum flugado,La vista tambalea al volar,,,Chaloupage en vol,Nézet repüléskori billegése,,飛行中の視点揺れ,비행 중 흔들림 보기,Bekijk bob bedrag terwijl je vliegt,Se bobbing mens du flyr,Pokaż bujanie podczas lotu,Balanço na visão durante voo,,Mișcare cameră în timpul zborului,Покачивание камеры при полёте,Погледајте скакање током лета,Visa att det guppar när du flyger,Uçarken sallanmayı görüntüle, +%o was maimed by a Serpent.,OB_DEMON1HIT,,,,%o byl@[ao_cs] zmrzačen@[ao_cs] zlohadem.,%o blev lemlæstet af en slange.,%o wurde von einer Schlange zerfleischt.,,%o vundegiĝis de Serpento.,,,,%o a été mutilé@[e_fr] par un Serpent.,,%o è stato mutilato da un serpente.,%o はサーペントに斬り捨てられた。,,%o werd verminkt door een slang.,%o ble lemlestet av en slange.,Wąż skaleczył gracza %o,%o foi mutilad@[ao_ptb] por uma Serpente.,,,Игрок %o искалечен змеем.,,%o blev lemlästad av en orm.,"%o, bir yılan tarafından sakat bırakıldı.", +Antialias Lines,AUTOMAPMNU_LINEANTIALIASING,,,,Vyhlazovat čáry,Antialias-linjer,Linien glätten,,Glatigaj Linioj,,,,Lignes Antialias,,,Linesのアンチエイリアス,,Antialijnen,Antialias-linjer,Linie Antyaliasowe,Linhas com antiserrilhamento,,,Линии сглаживания,,Antialias Linjer,Antialias Hatları, +Move and shoot through other players,GMPLYMNU_NOPLAYERCLIP ,,,,Procházet a střílet skrz ostatní hráče,Bevæg dig og skyd gennem andre spillere,Keine Kollisionen mit anderen Spielern,,Movi kaj pafi tra aliajn ludantojn,,,,Déplacez-vous et tirez à travers les autres joueurs,,Muoversi e sparare attraverso gli altri giocatori,移動と攻撃が他プレイヤーを通過,,Beweeg en schiet door andere spelers,Beveg deg og skyt gjennom andre spillere,Brak kolizji z innymi graczami,Mover e atirar através de outros jogadores,,,Перемещение и стрельба через игроков,,Förflytta dig och skjut genom andra spelare,Diğer oyuncuların arasından geçin ve ateş edin, +Share keys with all players,GMPLYMNU_SHAREKEYS,,,,Sdílet klíče se všemi hráči,Del nøgler med alle spillere,Schlüssel mit allen Spielern teilen,,Kunhavigi ŝlosilojn kun ĉiuj ludantoj,,,,Partager les clés avec tous les joueurs,,Condividere i tasti con tutti i giocatori,全プレイヤーにキーを共有,,Deel toetsen met alle spelers,Del nøkler med alle spillere,Współdziel klucze z innymi graczami,Compartilhar chaves com todos os jogadores,,,Общие ключи игроков,,Dela nycklar med alla spelare,Anahtarları tüm oyuncularla paylaşın, +Disallow override of camera facing mode,GLPREFMNU_SPRBILLFACECAMERAFORCE,,,,,Tillad ikke tilsidesættelse af kameravendt tilstand,Änderung des Kameramodus nicht erlauben,,Malebligi transpason de kamerao-rigardado-reĝimo,,,,Interdiction de modifier le mode d'orientation de la caméra,,Disconoscimento della modalità telecamera,Facing modeのカメラをオーバーライドしない,,Overschrijven van camerastand verbieden,Tillat ikke overstyring av kameramodus,Zabroń nadpisywania trybu widoku,Forçar modo de alinhamento do sprite à câmera,,,Запретить переопределение режима поворота камеры,,Tillåt inte åsidosättande av kamerans vändläge,Kameraya bakma modunun geçersiz kılınmasına izin verme, +Swap health and armor,ALTHUDMNU_SWAPHEALTHARMOR,,,,Prohodit zdraví a brnění,Byt om på helbred og rustning,Anzeige für Gesundheit und Panzerung tauschen,,Permuti sanon kaj kirason,,,,Échanger la santé et l'armure,,Scambio di salute e armatura,体力とアーマーをスワップ,,Verwissel gezondheid en pantser,Bytt helse og rustning,Zamień zdrowie i pancerz,Trocar saúde e armadura,,,Поменять отображение здоровья и брони местами,,Byt hälsa och rustning,Sağlık ve zırhı değiştir, +Use classic HUD scaling,SCALEMNU_HUD_OLDSCALE,hud_oldscale,,,Pro HUD použít klasické škálování,Brug klassisk HUD-skalering,Klassische HUD-Skalierung,,Uzi klasikan skaladon de HUD,,,,Utiliser l'échelle classique du HUD,,Utilizzare la scalatura classica dell'HUD,旧式HUDスケーリングを使う,,Gebruik klassieke HUD-schaling,Bruk klassisk HUD-skalering,,Usar escala clássica do HUD,,,Классическое масштабирование интерфейса,,Använd klassisk HUD-skalning,Klasik HUD ölçeklendirmesini kullanın, +HUD scale factor,SCALEMNU_HUD_SCALEFACTOR,hud_scalefactor,,,Faktor HUD škálování,HUD-skaleringsfaktor,HUD-Skalierungsfaktor,,Skalfaktoro de HUD,,,,Facteur d'échelle du HUD,,Fattore di scala dell'HUD,HUDスケール倍率,,HUD-schaalfactor,HUD-skaleringsfaktor,,Fator de escala do HUD,,,Значение масштабирования интерфейса,,Skalningsfaktor för HUD,HUD ölçek faktörü, +Spawn co-op only things in multiplayer,GMPLYMNU_COOPTHINGS,Any Actor that only appears in co-op is disabled,,,Co-op věci pouze v multiplayeru,Skab kun co-op-objekter i multiplayer,Erzeuge Nur-Co-op Dinge in Multiplayer,,Ekaperigi nurajn kooperajn aĵojn en plurludanta reĝimo,,,,Faire apparaitre les acteurs Co-Op Seulement en Multijoueur,,Creare oggetti solo per la cooperativa in multigiocatore,マルチで協力モード限定thingsを出す,,Alleen co-op-voorwerpen maken in multiplayer,Opprett co-op-objekter i flerspillermodus,,,,,Появление вещей из совместной игры в сетевой игре,,Skapa co-op-objekt i flerspelarläget,Çok oyunculu modda ortak nesneler oluşturun, +Spawn co-op only pickup items in multiplayer,GMPLYMNU_COOPITEMS,Items that only appear in co-op are disabled,,,Co-op předměty pouze v multiplayeru,Skab kun co-op-genstande i multiplayer,Erzeuge Nur-Co-op Gegenstände in Multiplayer,,Ekaperigi nurajn kooperajn objektojn en plurludanta reĝimo,,,,Faire apparaitre les objets Co-Op Seulement en Multijoueur,,Creare pickup solo per la cooperativa in multigiocatore,マルチで協力モード限定アイテムを出す,,Alleen co-op pickups maken in multiplayer,Opprett co-op-pickuper i flerspillermodus,,,,,Появление предметов из совместной игры в сетевой игре,,Skapa co-op pickups i flerspelarläget,Çok oyunculu modda ortak pikaplar oluşturun, +Players pick up their own copy of items in multiplayer,GMPLYMNU_LOCALITEMS,Items are picked up client-side rather than fully taken by the client who picked it up,,,V multiplayeru hráči sbírají své vlastní kopie předmětů,Spillere samler deres egen kopi af genstande op i multiplayer,Spieler nehmen ihre eigene Kopie von Gegenständen im Mehrspielermodus auf,,Ludantoj prenas sian propran kopion de objektoj en plurludanta reĝimo,,,,Chaque joueur obtient sa copie de chaque objet en Multijoueur,,I giocatori raccolgono la propria copia di oggetti in multigiocatore,マルチでプレイヤー達は複製アイテムを拾う,,Spelers pikken hun eigen exemplaar van voorwerpen op in multiplayer,Spillere plukker opp sin egen kopi av gjenstander i flerspiller,,,,,Игроки подбирают собственные копии предметов в сетевой игре,,Spelare plockar upp sin egen kopia av föremål i flerspelarläget,Oyuncular çok oyunculu modda eşyaların kendi kopyalarını alırlar, +Disable client-side pick ups on dropped items,GMPLYMNU_NOLOCALDROP,Drops from Actors aren't picked up locally,,,Zakázat sbírání odhozených předmětů na straně klientů,Deaktiver opsamling på klientsiden af tabte genstande,Client-seitiges Aufnehmen von fallengelassenen Gegenständen deaktivieren,,Malvalidigi klientflankajn prenadojn de faligitaj objektoj,,,,Désactiver le ramassage des objets lâchés en clientside,,Disabilita il ritiro degli oggetti caduti dal lato client,クライアント側で落としたアイテムを拾わせない,,Client-side pick ups van gedropte items uitschakelen,Deaktiver opphenting på klientsiden av gjenstander som droppes,,,,,Отключить подбирание выпавших предметов на стороне клиента,,Inaktivera upphämtning av tappade föremål på klientsidan,Düşen öğeleri istemci tarafında almayı devre dışı bırakma, +Restart level on Death,MISCMNU_RESTARTONDEATH,Disables autoloading save on death,,,Restart po umření,Genstart niveau ved død,Level bei Tod neu starten,,,,,,Recharger après mort,,Riavvio del livello in caso di morte,,,Level herstarten bij dood,Start nivået på nytt ved død,,,,,Перезапуск уровня после смерти,,Starta om nivån vid död,Ölüm halinde seviyeyi yeniden başlat, +Pistol Start,GMPLYMNU_PISTOLSTART,Resets inventory on every map,,,Začít jen s pistolí,Start med pistol,Pistolenstart,,,,,,Démarrage du pistolet,,Avvio pistola,,,Start met pistool,Start med pistol,,,,,Пистолет в начале,,Starta med pistol,Tabanca ile başlayın, +Allow creation of zombie players,CMPTMNU_VOODOOZOMBIES,,,,,,Erlaube Zombieplayer,,,,,,,,,,,,,,,,,,,,, +ignore floor z when teleporting,CMPTMNU_FDTELEPORT,,,,,,Ignoriere Fußbodenhöhe bem Teleportieren,,,,,,,,,,,,,,,,,,,,, \ No newline at end of file diff --git a/wadsrc/static/language.def b/wadsrc/static/language.def index d9367eb0884..103d4d3a94d 100644 --- a/wadsrc/static/language.def +++ b/wadsrc/static/language.def @@ -34,6 +34,15 @@ MUSIC_E3M6 = "e3m6"; MUSIC_E3M7 = "e3m7"; MUSIC_E3M8 = "e3m8"; MUSIC_E3M9 = "e3m9"; +MUSIC_E4M1 = "e4m1"; +MUSIC_E4M2 = "e4m2"; +MUSIC_E4M3 = "e4m3"; +MUSIC_E4M4 = "e4m4"; +MUSIC_E4M5 = "e4m5"; +MUSIC_E4M6 = "e4m6"; +MUSIC_E4M7 = "e4m7"; +MUSIC_E4M8 = "e4m8"; +MUSIC_E4M9 = "e4m9"; MUSIC_INTER = "inter"; MUSIC_INTRO = "intro"; MUSIC_BUNNY = "bunny"; @@ -325,3 +334,62 @@ HE2TEXT = ""; HE3TEXT = ""; HE4TEXT = ""; HE5TEXT = ""; + +// +// mappings for duplicate texts +// + +CNTRLMNU_TITLE = "$$OPTMNU_CONTROLS"; +MOUSEMNU_TITLE = "$$OPTMNU_MOUSE"; +MNU_PLAYERSETUP = "$$OPTMNU_PLAYER"; +DSPLYMNU_TITLE = "$$OPTMNU_DISPLAY"; +AUTOMAPMNU_TITLE = "$$OPTMNU_AUTOMAP"; +OPENALMNU_TITLE = "$$SNDMNU_OPENAL"; +SNDMNU_TITLE = "$$OPTMNU_SOUND"; +MODMNU_TITLE = "$$SNDMNU_MODREPLAYER"; +MISCMNU_TITLE = "$$OPTMNU_MISCELLANEOUS"; +GLMNU_TEXOPT = "$$GLTEXMNU_TITLE"; + +SCORE_ITEMS = "$$TXT_IMITEMS"; +SCORE_KILLS = "$$TXT_IMKILLS"; + +FN_ZOMBIE = "$$CC_ZOMBIE"; +FN_IMP = "$$CC_IMP"; +FN_DEMON = "$$CC_DEMON"; +FN_LOST = "$$CC_LOST"; +FN_CACO = "$$CC_CACO"; +FN_HELL = "$$CC_HELL"; +FN_BARON = "$$CC_BARON"; +FN_ARACH = "$$CC_ARACH"; +FN_PAIN = "$$CC_PAIN"; +FN_REVEN = "$$CC_REVEN"; +FN_MANCU = "$$CC_MANCU"; +FN_ARCH = "$$CC_ARCH"; + +TAG_GAUNTLETS = "$$TXT_WPNGAUNTLETS"; +TAG_GAUNTLETSP = "$$TXT_WPNGAUNTLETS"; +TAG_CROSSBOW = "$$TXT_WPNCROSSBOW"; +TAG_CROSSBOWP = "$$TXT_WPNCROSSBOW"; +TAG_STAFFP = "$$TAG_STAFF"; +TAG_GOLDWANDP = "$$TAG_GOLDWAND"; +TAG_BLASTER = "$$TXT_WPNBLASTER"; +TAG_BLASTERP = "$$TXT_WPNBLASTER"; +TAG_SKULLROD = "$$TXT_WPNSKULLROD"; +TAG_SKULLRODP = "$$TXT_WPNSKULLROD"; +TAG_PHOENIXROD = "$$TXT_WPNPHOENIXROD"; +TAG_PHOENIXRODP = "$$TXT_WPNPHOENIXROD"; +TAG_MACE = "$$TXT_WPNMACE"; +TAG_MACEP = "$$TXT_WPNMACE"; + +TAG_ARTIEGG = "$$TXT_ARTIEGG"; +TAG_ARTIFIREBOMB = "$$TXT_ARTIFIREBOMB"; +TAG_ARTIFLY = "$$TXT_ARTIFLY"; +TAG_ARTIHEALTH = "$$TXT_ARTIHEALTH"; +TAG_ARTISUPERHEALTH = "$$TXT_ARTISUPERHEALTH"; +TAG_ARTIINVISIBILITY = "$$TXT_ARTIINVISIBILITY"; +TAG_ARTIINVULNERABILITY = "$$TXT_ARTIINVULNERABILITY"; +TAG_ARTITELEPORT = "$$TXT_ARTITELEPORT"; +TAG_ARTITOMEOFPOWER = "$$TXT_ARTITOMEOFPOWER"; +TAG_ARTITORCH = "$$TXT_ARTITORCH"; + +OPTMNU_SWRENDERER = "$$DSPLYMNU_SWOPT"; diff --git a/wadsrc/static/lmacros.csv b/wadsrc/static/lmacros.csv index 44573ded858..89ce640ce1a 100644 --- a/wadsrc/static/lmacros.csv +++ b/wadsrc/static/lmacros.csv @@ -11,12 +11,14 @@ in_de,de,,in,, pp_de,de,seine,ihre,seine,seine pro_eo,eo,li,ŝi,ri,ĝi ao_esp,es,o,a,o,o +a_esp,es,,a,, +ae_esp,es,e,a,e,e e_fr,fr,,e,, hij_ze_nl,nl,hij,ze,hij,hij zijn_haar_nl,nl,zijn,haar,zijn,zijn ao_pl,pl,,a,o,o adj_pl,pl,y,a,e,e -irreg_1_pl,pl,szedł ,eszła,eszło,eszło +irreg_1_pl,pl,szedł ,eszła,eszło,eszło irreg_2_pl,pl,ął,ęła,ęło,ęło irreg_3_pl,pl,eś,aś,eś,eś irreg_4_pl,pl,ógł,ogła,ogło,ogło @@ -30,10 +32,25 @@ adj_3_rus,ru,ён,на,но,но irreg_1_rus,ru,ёл,ла,ло,ло irreg_2_rus,ru,,ла,ло,ло irreg_3_rus,ru,ёг,егла,егло,егло -pron_rus,ru,него,неё,него,него +irreg_4_rus,ru,ёк,екла,екло,екло +pron_rus,ru,него,неё,, +cheatpron_rus,ru,щик,щица,, ao_1_sr,sr,о,ла,ло,ло ao_2_sr,sr,ао,ла,ло,ло ao_3_sr,sr,ог,у,ог,ог adj_1_sr,sr,,а,о,о adj_2_sr,sr,ан,на,но,но -adj_3_sr,sr,ар,ра,ро,ро \ No newline at end of file +adj_3_sr,sr,ар,ра,ро,ро +pro_gr,el,τον,την,τον,το +pro2_gr,el,Τον,Την,Τον,Το +pro3_gr,el,στον,στην,στο,στο +art_gr,el,Ο,Η,Το,Το +pro4_gr,el,του,της,του,του +pro_dk,"da, no",han,hun,han,det +pro_sv,sv,han,hon,han,den +ref_sv,sv,honom,henne,honom,den +ao_ua,ua,ий,а,о,о +adj_1_ua,ua,в,ла,ло,ло +adj_2_ua,ua,вся,лась,лось,лось +adj_3_ua,ua,,ла,ло,ло +adj_4_ua,ua,ий,та,то,то \ No newline at end of file diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index 42760eaab92..14f6a78b035 100644 --- a/wadsrc/static/mapinfo/chex.txt +++ b/wadsrc/static/mapinfo/chex.txt @@ -16,7 +16,7 @@ gameinfo finalepage = "CREDIT", "VICTORY2", "ENDPIC" infopage = "HELP1", "CREDIT" quitsound = "menu/quit1" - borderflat = "FLOOR7_2" + borderflat = "CEIL5_1" border = DoomBorder telefogheight = 0 defkickback = 100 @@ -40,6 +40,7 @@ gameinfo dimamount = 0.5 bluramount = 0.0 menuslidercolor = "Orange" + menusliderbackcolor = "White" definventorymaxamount = 25 defaultrespawntime = 12 defaultdropstyle = 1 @@ -73,10 +74,17 @@ gameinfo statscreen_dm = "DeathmatchStatusScreen" statscreen_single = "DoomStatusScreen" messageboxclass = "MessageBoxMenu" + helpmenuclass = "ReadThisMenu" + menudelegateclass = "DoomMenuDelegate" normforwardmove = 0x19, 0x32 normsidemove = 0x18, 0x28 } +gamedefaults +{ + enableskyboxao +} + DoomEdNums { 5 = ChexBlueCard @@ -177,6 +185,7 @@ skill nightmare { AmmoFactor = 2 FastMonsters + InstantReaction DisableCheats RespawnTime = 12 SpawnFilter = Nightmare diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt index 642eaeac809..f079ee6e6e3 100644 --- a/wadsrc/static/mapinfo/common.txt +++ b/wadsrc/static/mapinfo/common.txt @@ -136,6 +136,9 @@ DoomEdNums 9872 = SpotLightFlickerAttenuated 9873 = SectorSpotLightAttenuated 9874 = SpotLightFlickerRandomAttenuated + 9876 = None // ZDRay static point light + 9881 = None // ZDRay static spotlight + 9890 = None // ZDRayInfo 9982 = SecActEyesAboveC 9983 = SecActEyesBelowC 9988 = CustomSprite @@ -359,7 +362,6 @@ Intermission Inter_Bunny Intermission TheEnd { - // no backgrounds are set here so this will reuse the previous one. Image { Draw = "END0", 108, 68 @@ -409,9 +411,6 @@ Intermission Inter_Underwater { Background = "E2END", 0 } - GotoTitle - { - } } Intermission Inter_Demonscroll diff --git a/wadsrc/static/mapinfo/doom1.txt b/wadsrc/static/mapinfo/doom1.txt index c28186c55a0..851171530f5 100644 --- a/wadsrc/static/mapinfo/doom1.txt +++ b/wadsrc/static/mapinfo/doom1.txt @@ -149,7 +149,7 @@ map E1M8 lookup "HUSTR_E1M8" par = 30 nointermission nosoundclipping - baronspecial + e1m8special specialaction_lowerfloor music = "$MUSIC_E1M8" needclustertext @@ -264,7 +264,7 @@ map E2M8 lookup "HUSTR_E2M8" par = 30 nointermission nosoundclipping - cyberdemonspecial + e2m8special specialaction_exitlevel music = "$MUSIC_E2M8" needclustertext @@ -379,7 +379,7 @@ map E3M8 lookup "HUSTR_E3M8" par = 30 nointermission nosoundclipping - spidermastermindspecial + e3m8special specialaction_exitlevel music = "$MUSIC_E3M8" needclustertext @@ -408,7 +408,7 @@ map E4M1 lookup "HUSTR_E4M1" sky1 = "SKY4" cluster = 4 par = 165 - music = "$MUSIC_E3M4" + music = "$MUSIC_E4M1" } map E4M2 lookup "HUSTR_E4M2" @@ -420,7 +420,7 @@ map E4M2 lookup "HUSTR_E4M2" sky1 = "SKY4" cluster = 4 par = 255 - music = "$MUSIC_E3M2" + music = "$MUSIC_E4M2" } map E4M3 lookup "HUSTR_E4M3" @@ -432,7 +432,7 @@ map E4M3 lookup "HUSTR_E4M3" sky1 = "SKY4" cluster = 4 par = 135 - music = "$MUSIC_E3M3" + music = "$MUSIC_E4M3" } map E4M4 lookup "HUSTR_E4M4" @@ -444,7 +444,7 @@ map E4M4 lookup "HUSTR_E4M4" sky1 = "SKY4" cluster = 4 par = 150 - music = "$MUSIC_E1M5" + music = "$MUSIC_E4M4" } map E4M5 lookup "HUSTR_E4M5" @@ -456,7 +456,7 @@ map E4M5 lookup "HUSTR_E4M5" sky1 = "SKY4" cluster = 4 par = 180 - music = "$MUSIC_E2M7" + music = "$MUSIC_E4M5" } map E4M6 lookup "HUSTR_E4M6" @@ -468,9 +468,9 @@ map E4M6 lookup "HUSTR_E4M6" sky1 = "SKY4" cluster = 4 par = 390 - cyberdemonspecial + e4m6special specialaction_opendoor - music = "$MUSIC_E2M4" + music = "$MUSIC_E4M6" } map E4M7 lookup "HUSTR_E4M7" @@ -482,7 +482,7 @@ map E4M7 lookup "HUSTR_E4M7" sky1 = "SKY4" cluster = 4 par = 135 - music = "$MUSIC_E2M6" + music = "$MUSIC_E4M7" } map E4M8 lookup "HUSTR_E4M8" @@ -496,9 +496,9 @@ map E4M8 lookup "HUSTR_E4M8" par = 360 nointermission nosoundclipping - spidermastermindspecial + e4m8special specialaction_lowerfloor - music = "$MUSIC_E2M5" + music = "$MUSIC_E4M8" needclustertext } @@ -511,7 +511,7 @@ map E4M9 lookup "HUSTR_E4M9" sky1 = "SKY4" cluster = 4 par = 180 - music = "$MUSIC_E1M9" + music = "$MUSIC_E4M9" } // Clusters (correspond with same-numbered episode) diff --git a/wadsrc/static/mapinfo/doom2bfg.txt b/wadsrc/static/mapinfo/doom2bfg.txt index b53d7944fb9..4c15bf6bf11 100644 --- a/wadsrc/static/mapinfo/doom2bfg.txt +++ b/wadsrc/static/mapinfo/doom2bfg.txt @@ -9,15 +9,13 @@ gameinfo clearepisodes episode map01 { - name = "Hell On Earth" - picname = "M_EPI1" + name = "$TXT_D2E1" key = "h" } episode level01 { - name = "No Rest for the Living" - picname = "M_EPI2" + name = "$TXT_D2E2" key = "n" optional } diff --git a/wadsrc/static/mapinfo/doom2unity.txt b/wadsrc/static/mapinfo/doom2unity.txt index f4c468821fa..e23b8651ca3 100644 --- a/wadsrc/static/mapinfo/doom2unity.txt +++ b/wadsrc/static/mapinfo/doom2unity.txt @@ -3,14 +3,13 @@ include "mapinfo/doom2.txt" gameinfo { - titlepage = "DMENUPIC" + } clearepisodes episode map01 { - name = "Hell On Earth" - picname = "M_EPI1" + name = "$TXT_D2E1" key = "h" } @@ -20,27 +19,3 @@ episode level01 key = "n" optional } - -// Wolfenstein 3D censorship -map MAP31 lookup "HUSTR_31B" -{ - titlepatch = "CWILV30" - next = "MAP16" - secretnext = "MAP32" - sky1 = "SKY3" - cluster = 9 - par = 120 - music = "$MUSIC_EVIL" - needclustertext -} - -map MAP32 lookup "HUSTR_32B" -{ - titlepatch = "CWILV31" - next = "MAP16" - secretnext = "MAP16" - sky1 = "SKY3" - cluster = 10 - par = 30 - music = "$MUSIC_ULTIMA" -} diff --git a/wadsrc/static/mapinfo/doom2xbox.txt b/wadsrc/static/mapinfo/doom2xbox.txt index 50321440dbb..fd98f64f45e 100644 --- a/wadsrc/static/mapinfo/doom2xbox.txt +++ b/wadsrc/static/mapinfo/doom2xbox.txt @@ -4,15 +4,13 @@ include "mapinfo/doom2.txt" clearepisodes episode map01 { - name = "Hell On Earth" - picname = "M_EPI1" + name = "$TXT_D2E1" key = "h" } episode level01 { - name = "No Rest for the Living" - picname = "M_EPI2" + name = "$TXT_D2E2" key = "n" optional } diff --git a/wadsrc/static/mapinfo/doomcommon.txt b/wadsrc/static/mapinfo/doomcommon.txt index ca9722b569a..89d4c44a8a1 100644 --- a/wadsrc/static/mapinfo/doomcommon.txt +++ b/wadsrc/static/mapinfo/doomcommon.txt @@ -40,6 +40,7 @@ gameinfo dimamount = 0.5 bluramount = 0.0 menuslidercolor = "Orange" + menusliderbackcolor = "White" definventorymaxamount = 25 defaultrespawntime = 12 defaultdropstyle = 1 @@ -74,10 +75,17 @@ gameinfo statscreen_dm = "DeathmatchStatusScreen" statscreen_single = "DoomStatusScreen" messageboxclass = "MessageBoxMenu" + helpmenuclass = "ReadThisMenu" + menudelegateclass = "DoomMenuDelegate" normforwardmove = 0x19, 0x32 normsidemove = 0x18, 0x28 } +gamedefaults +{ + enableskyboxao +} + spawnnums { 1 = ShotgunGuy @@ -211,6 +219,7 @@ skill nightmare { AmmoFactor = 2 FastMonsters + InstantReaction DisableCheats RespawnTime = 12 SpawnFilter = Nightmare diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index 41c378ee1bb..8e8594345ee 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -1,4 +1,4 @@ -// MAPINFO for Heretic (Shareware and Retail) +// MAPINFO for Heretic (Retail) include "mapinfo/common.txt" gameinfo @@ -40,6 +40,7 @@ gameinfo dimamount = 0.5 bluramount = 0 menuslidercolor = "Orange" + menusliderbackcolor = "White" definventorymaxamount = 16 defaultrespawntime = 12 defaultdropstyle = 1 @@ -72,10 +73,17 @@ gameinfo statscreen_dm = "DeathmatchStatusScreen" statscreen_single = "RavenStatusScreen" messageboxclass = "MessageBoxMenu" + helpmenuclass = "ReadThisMenu" + menudelegateclass = "DoomMenuDelegate" normforwardmove = 0x19, 0x32 normsidemove = 0x18, 0x28 } +gamedefaults +{ + enableskyboxao +} + DoomEdNums { 5 = HereticImpLeader @@ -309,6 +317,7 @@ skill nightmare AmmoFactor = 1.5 DoubleAmmoFactor = 1.5 FastMonsters + InstantReaction DisableCheats SpawnFilter = Nightmare Name = "$MNU_BLACKPLAGUE" diff --git a/wadsrc/static/mapinfo/hereticshareware.txt b/wadsrc/static/mapinfo/hereticshareware.txt new file mode 100644 index 00000000000..fe369f36ff7 --- /dev/null +++ b/wadsrc/static/mapinfo/hereticshareware.txt @@ -0,0 +1,7 @@ +// MAPINFO for Heretic (Shareware) +include "mapinfo/heretic.txt" + +gameinfo +{ + borderflat = "FLOOR04" +} \ No newline at end of file diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt index 2e9196075d5..adb52f13565 100644 --- a/wadsrc/static/mapinfo/hexen.txt +++ b/wadsrc/static/mapinfo/hexen.txt @@ -39,6 +39,7 @@ gameinfo dimamount = 0.5 bluramount = 0.0 menuslidercolor = "Orange" + menusliderbackcolor = "White" definventorymaxamount = 25 defaultrespawntime = 12 defaultdropstyle = 1 @@ -70,6 +71,8 @@ gameinfo statscreen_dm = "DeathmatchStatusScreen" statscreen_single = "RavenStatusScreen" messageboxclass = "MessageBoxMenu" + helpmenuclass = "ReadThisMenu" + menudelegateclass = "DoomMenuDelegate" normforwardmove = 0x19, 0x32 normsidemove = 0x18, 0x28 } @@ -455,6 +458,7 @@ skill nightmare AmmoFactor = 1.5 DoubleAmmoFactor = 1.5 FastMonsters + InstantReaction DisableCheats SpawnFilter = Nightmare Name = "$MNU_BLACKPLAGUE" @@ -511,6 +515,7 @@ gamedefaults noautosequences missilesactivateimpactlines monsterfallingdamage + enableskyboxao } // There is also support for showing a clus5msg after cluster 5, but diff --git a/wadsrc/static/mapinfo/mindefaults.txt b/wadsrc/static/mapinfo/mindefaults.txt index bfe37054073..9f266881061 100644 --- a/wadsrc/static/mapinfo/mindefaults.txt +++ b/wadsrc/static/mapinfo/mindefaults.txt @@ -29,6 +29,7 @@ gameinfo dimamount = 0.8 bluramount = 0.0 menuslidercolor = "Orange" + menusliderbackcolor = "White" definventorymaxamount = 25 defaultrespawntime = 12 defaultdropstyle = 1 @@ -60,6 +61,13 @@ gameinfo statscreen_contentfont = "*BigFont" statscreen_authorFont = "*SmallFont" messageboxclass = "MessageBoxMenu" + helpmenuclass = "ReadThisMenu" + menudelegateclass = "DoomMenuDelegate" +} + +gamedefaults +{ + enableskyboxao } DoomEdNums diff --git a/wadsrc/static/mapinfo/strife.txt b/wadsrc/static/mapinfo/strife.txt index 75b7120fdab..b39e950cdc2 100644 --- a/wadsrc/static/mapinfo/strife.txt +++ b/wadsrc/static/mapinfo/strife.txt @@ -40,6 +40,7 @@ gameinfo dimamount = 0.5 bluramount = 0 menuslidercolor = "Orange" + menusliderbackcolor = "White" definventorymaxamount = 25 defaultrespawntime = 16 defaultdropstyle = 2 @@ -72,6 +73,8 @@ gameinfo statscreen_single = "RavenStatusScreen" statusbarclass = "StrifeStatusBar" messageboxclass = "MessageBoxMenu" + helpmenuclass = "ReadThisMenu" + menudelegateclass = "DoomMenuDelegate" normforwardmove = 0x19, 0x32 normsidemove = 0x18, 0x28 } @@ -611,6 +614,7 @@ gamedefaults nointermission clipmidtextures noinfighting + enableskyboxao } map MAP01 LOOKUP "TXT_STRIFE_MAP01" diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index b59af595f4f..0d099afb67b 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -209,6 +209,7 @@ ListMenu "EpisodeMenu" { Position 48, 63 StaticPatch 54, 38, "M_EPISOD", 0 , "$MNU_EPISODE" + linespacing 16 } IfGame(Strife) { @@ -231,10 +232,10 @@ ListMenu "EpisodeMenu" ListMenu "SkillMenu" { - IfGame(Doom, Chex) { StaticPatch 96, 14, "M_NEWG", 0, "$MNU_NEWGAME" + linespacing 16 } IfGame(Strife) { @@ -286,9 +287,10 @@ ListMenu "LoadGameMenu" { NetgameMessage "$CLOADNET" } - StaticTextCentered 160, -10, "$MNU_LOADGAME" - Position 80,54 + CaptionItem "$MNU_LOADGAME" + Position 80,40 Class "LoadMenu" // uses its own implementation + Size Clean } //------------------------------------------------------------------------------------------- @@ -299,9 +301,10 @@ ListMenu "LoadGameMenu" ListMenu "SaveGameMenu" { - StaticTextCentered 160, -10, "$MNU_SAVEGAME" - Position 80,54 + CaptionItem "$MNU_SAVEGAME" + Position 80,40 Class "SaveMenu" // uses its own implementation + Size Clean } //------------------------------------------------------------------------------------------- @@ -341,18 +344,6 @@ OptionValue AutoOffOn 1, "$OPTVAL_ON" } -OptionMenuSettings -{ - // These can be overridden if a different menu fonts requires it. - Linespacing 17 - /* - IfGame(Heretic, Hexen) - { - Linespacing 9 - } - */ -} - DefaultOptionMenu { Position -15 @@ -381,10 +372,17 @@ OptionMenu "OptionsMenu" protected Submenu "$OPTMNU_VIDEO", "VideoModeMenu" StaticText " " Submenu "$OS_TITLE", "os_Menu" + Option "$OPTMNU_SIMPLEON", "m_simpleoptions", "OnOff" + StaticText " " - SafeCommand "$OPTMNU_DEFAULTS", "reset2defaults" + SafeCommand "$OPTMNU_DEFAULTS", "reset2defaults" SafeCommand "$OPTMNU_RESETTOSAVED", "reset2saved" + SafeCommand "$OPTMNU_WRITEINI", "writeini" + Command "$OPTMNU_CONSOLE", "menuconsole" + Command "$OPTMNU_OPENCONFIG", "openconfig" + Command "$OPTMNU_OPENSCREENSHOTS", "openscreenshots" + Command "$OPTMNU_OPENSAVES", "opensaves" StaticText " " } @@ -448,6 +446,7 @@ OptionMenu "NewPlayerMenu" protected PlayerSkinItem "$PLYRMNU_PLAYERSKIN", "PlayerSkin" PlayerGenderItem "$PLYRMNU_PLAYERGENDER", "Gender" AutoaimSlider "$PLYRMNU_AUTOAIM" + Option "$PLYRMNU_VERTSPREAD", vertspread, "OnOff" PlayerSwitchOnPickupItem "$PLYRMNU_SWITCHONPICKUP", "OffOn" Option "$PLYRMNU_ALWAYSRUN", cl_run, "OnOff" Class "NewPlayerMenu" @@ -493,6 +492,7 @@ ListMenu "PlayerMenu" ValueText "$PLYRMNU_PLAYERSKIN", "Skin" ValueText "$PLYRMNU_PLAYERGENDER", "Gender", "Gender" Slider "$PLYRMNU_AUTOAIM", "Autoaim", 0, 35, 1 + ValueText "$PLYRMNU_VERTSPREAD", vertspread, "OnOff" ValueText "$PLYRMNU_SWITCHONPICKUP", "Switch", "OffOn" ValueText "$PLYRMNU_ALWAYSRUN", "AlwaysRun", "OnOff" Class "PlayerMenu" @@ -504,17 +504,27 @@ ListMenu "PlayerMenu" // //------------------------------------------------------------------------------------------- +OptionValue "Layouts" +{ + 0, "$OPTVAL_MODERN" + 1, "$OPTVAL_CLASSICZ" + 2, "$OPTVAL_MODERNLEFT" +} + OptionMenu "CustomizeControls" protected { Title "$CNTRLMNU_TITLE" Submenu "$CNTRLMNU_ACTION" , "ActionControlsMenu" - Submenu "$CNTRLMNU_CHAT" , "ChatControlsMenu" Submenu "$CNTRLMNU_WEAPONS" , "WeaponsControlMenu" Submenu "$CNTRLMNU_INVENTORY" , "InventoryControlsMenu" + Submenu "$MAPCNTRLMNU_CONTROLS" , "MapControlsMenu" Submenu "$CNTRLMNU_OTHER" , "OtherControlsMenu" Submenu "$CNTRLMNU_POPUPS" , "StrifeControlsMenu" - Submenu "$MAPCNTRLMNU_CONTROLS" , "MapControlsMenu" + Submenu "$MNU_MULTIPLAYER" , "ChatControlsMenu" + StaticText "" + Option "$CNTRLMNU_LAYOUT", "cl_defaultconfiguration", "Layouts" + SafeCommand "$OPTMNU_DEFAULTS", "resetb2defaults" } OptionMenu "ActionControlsMenu" protected @@ -564,24 +574,18 @@ OptionMenu "ActionControlsMenu" protected Control "$CNTRLMNU_RUN" , "+speed" Control "$CNTRLMNU_TOGGLERUN" , "toggle cl_run" Control "$CNTRLMNU_STRAFE" , "+strafe" - - StaticText "" - Control "$CNTRLMNU_SCOREBOARD" , "+showscores" - Control "$CNTRLMNU_TOGGLESCOREBOARD" , "togglescoreboard" - - StaticText "" - Control "$CNTRLMNU_USER1" , "+user1" - Control "$CNTRLMNU_USER2" , "+user2" - Control "$CNTRLMNU_USER3" , "+user3" - Control "$CNTRLMNU_USER4" , "+user4" } OptionMenu "ChatControlsMenu" protected { - Title "$CNTRLMNU_CHAT_TITLE" + Title "$MNU_MULTIPLAYER" ScrollTop 2 StaticTextSwitchable "$CNTRLMNU_SWITCHTEXT1", "$CNTRLMNU_SWITCHTEXT2", "ControlMessage" + StaticText "" + Control "$CNTRLMNU_SCOREBOARD" , "+showscores" + Control "$CNTRLMNU_TOGGLESCOREBOARD" , "togglescoreboard" + StaticText "" Control "$CNTRLMNU_SAY" , "messagemode" Control "$CNTRLMNU_TEAMSAY" , "messagemode2" @@ -608,6 +612,12 @@ OptionMenu "WeaponsControlMenu" protected Control "$CNTRLMNU_SLOT8" , "slot 8" Control "$CNTRLMNU_SLOT9" , "slot 9" Control "$CNTRLMNU_SLOT0" , "slot 0" + + StaticText "" + Control "$CNTRLMNU_USER1" , "+user1" + Control "$CNTRLMNU_USER2" , "+user2" + Control "$CNTRLMNU_USER3" , "+user3" + Control "$CNTRLMNU_USER4" , "+user4" } OptionMenu "InventoryControlsMenu" protected @@ -657,6 +667,7 @@ OptionMenu "OtherControlsMenu" protected Control "$CNTRLMNU_ADJUST_GAMMA" , "bumpgamma" StaticText "" + Control "$CNTRLMNU_OPEN_MAIN" , "menu_main" Control "$CNTRLMNU_OPEN_HELP" , "menu_help" Control "$CNTRLMNU_OPEN_SAVE" , "menu_save" Control "$CNTRLMNU_OPEN_LOAD" , "menu_load" @@ -722,11 +733,14 @@ OptionMenu "MouseOptions" protected Option "$MOUSEMNU_ENABLEMOUSE", "use_mouse", "YesNo" Option "$MOUSEMNU_MOUSEINMENU", "m_use_mouse", "MenuMouse", "use_mouse" Option "$MOUSEMNU_SHOWBACKBUTTON", "m_show_backbutton", "Corners", "use_mouse" + IfOption(Windows) + { + Option "$MOUSEMNU_SWAPBUTTONS", "m_swapbuttons", "YesNo" + } Option "$MOUSEMNU_CURSOR", "vid_cursor", "Cursors" StaticText "" - Slider "$MOUSEMNU_SENSITIVITY", "mouse_sensitivity", 0.5, 2.5, 0.1 - Option "$MOUSEMNU_NOPRESCALE", "m_noprescale", "NoYes" - Option "$MOUSEMNU_SMOOTHMOUSE", "smooth_mouse", "YesNo" + Slider "$MOUSEMNU_SENSITIVITY_X", "m_sensitivity_x", 0.1, 8, 0.05 + Slider "$MOUSEMNU_SENSITIVITY_Y", "m_sensitivity_y", 0.1, 8, 0.05 StaticText "" Slider "$MOUSEMNU_TURNSPEED", "m_yaw", 0, 2.5, 0.1 Slider "$MOUSEMNU_MOUSELOOKSPEED", "m_pitch", 0, 2.5, 0.1 @@ -734,6 +748,7 @@ OptionMenu "MouseOptions" protected Slider "$MOUSEMNU_STRAFESPEED", "m_side", 0, 2.5, 0.1 StaticText "" Option "$MOUSEMNU_ALWAYSMOUSELOOK", "freelook", "OnOff" + Option "$MOUSEMNU_INVERTMOUSEX", "invertmousex", "OnOff" Option "$MOUSEMNU_INVERTMOUSE", "invertmouse", "OnOff" Option "$MOUSEMNU_LOOKSPRING", "lookspring", "OnOff" Option "$MOUSEMNU_LOOKSTRAFE", "lookstrafe", "OnOff" @@ -800,12 +815,6 @@ OptionMenu "JoystickConfigMenu" protected // //------------------------------------------------------------------------------------------- -OptionValue ColumnMethods -{ - 0.0, "$OPTVAL_ORIGINAL" - 1.0, "$OPTVAL_OPTIMIZED" -} - OptionValue BlendMethods { 0.0, "$OPTVAL_CLASSIC" @@ -878,18 +887,11 @@ OptionValue VanillaTrans 3.0, "$OPTVAL_VTAVANILLA" } -OptionValue GPUSwitch -{ - 0.0, "$OPTVAL_DEFAULT" - 1.0, "$OPTVAL_DEDICATED" - 2.0, "$OPTVAL_INTEGRATED" -} - OptionValue PreferBackend { 0, "$OPTVAL_OPENGL" 1, "$OPTVAL_VULKAN" - 2, "$OPTVAL_SOFTPOLY" + 2, "$OPTVAL_OPENGLES" } OptionMenu "TrueColorOptions" protected @@ -926,18 +928,20 @@ OptionMenu "VideoOptions" protected StaticText " " Slider "$DSPLYMNU_SCREENSIZE", "screenblocks", 3.0, 12.0, 1.0, 0 - Slider "$DSPLYMNU_GAMMA", "Gamma", 0.75, 3.0, 0.05, 2 + Slider "$DSPLYMNU_GAMMA", "vid_gamma", 0.75, 3.0, 0.05, 2 Slider "$DSPLYMNU_BRIGHTNESS", "vid_brightness", -0.8,0.8, 0.05,2 Slider "$DSPLYMNU_CONTRAST", "vid_contrast", 0.1, 3.0, 0.1 Slider "$DSPLYMNU_SATURATION", "vid_saturation", -3.0, 3.0, 0.25, 2 StaticText " " + Slider "$DSPLYMNU_FOV", "fov", 75.0, 120.0, 0.1, 1 + StaticText " " + Option "$DSPLYMNU_SPRITESHADOW", "r_actorspriteshadow", "SpriteShadowModes" Option "$DSPLYMNU_CUSTOMINVERTMAP", "cl_customizeinvulmap", "OnOff" ColorPicker "$DSPLYMNU_CUSTOMINVERTC1", "cl_custominvulmapcolor1" ColorPicker "$DSPLYMNU_CUSTOMINVERTC2", "cl_custominvulmapcolor2" Option "$DSPLYMNU_WIPETYPE", "wipetype", "Wipes" Option "$DSPLYMNU_DRAWFUZZ", "r_drawfuzz", "Fuzziness" Option "$DSPLYMNU_OLDTRANS", "r_vanillatrans", "VanillaTrans" - Slider "$DSPLYMNU_TRANSSOUL", "transsouls", 0.25, 1.0, 0.05, 2 Option "$DSPLYMNU_FAKECONTRAST", "r_fakecontrast", "Contrast" Option "$DSPLYMNU_ROCKETTRAILS", "cl_rockettrails", "RocketTrailTypes" Option "$DSPLYMNU_BLOODTYPE", "cl_bloodtype", "BloodTypes" @@ -1045,6 +1049,7 @@ OptionMenu "HUDOptions" protected Slider "$DSPLYMNU_MOVEBOB", "movebob", 0, 1.0, 0.05, 2 Slider "$DSPLYMNU_STILLBOB", "stillbob", 0, 1.0, 0.05, 2 Slider "$DSPLYMNU_BOBSPEED", "wbobspeed", 0, 2.0, 0.1 + Slider "$DSPLYMNU_BOBFIRE", "wbobfire", 0, 1.0, 0.1 StaticText " " Slider "$DSPLYMNU_MENUDIM", "dimamount", 0, 1.0, 0.05, 2 ColorPicker "$DSPLYMNU_DIMCOLOR", "dimcolor" @@ -1073,11 +1078,19 @@ OptionMenu "ScalingOptions" protected StaticText "$SCALEMNU_OVERRIDE", 1 ScaleSlider "$SCALEMNU_MESSAGES", "con_scaletext", 0.0, 8.0, 1.0, "$SCALEMNU_USEUI" ScaleSlider "$SCALEMNU_CONSOLE", "con_scale", 0.0, 8.0, 1.0, "$SCALEMNU_USEUI" - ScaleSlider "$SCALEMNU_STATBAR", "st_scale", -1.0, 8.0, 1.0, "$SCALEMNU_USEUI", "$SCALEMNU_USEFS" - ScaleSlider "$SCALEMNU_HUD", "hud_scale", -1.0, 8.0, 1.0, "$SCALEMNU_USEUI", "$SCALEMNU_USEFS" - ScaleSlider "$SCALEMNU_ALTHUD", "hud_althudscale", 0.0, 8.0, 1.0, "$SCALEMNU_USEUI" + Option "$SCALEMNU_HUD_OLDSCALE", "hud_oldscale", "OnOff" + Slider "$SCALEMNU_HUD_SCALEFACTOR", "hud_scalefactor", 0.0, 1.0, 0.025, 3, "hud_oldscale", 1 + ScaleSlider "$SCALEMNU_STATBAR", "st_scale", -1.0, 8.0, 1.0, "$SCALEMNU_USEUI", "$SCALEMNU_USEFS", "hud_oldscale" + ScaleSlider "$SCALEMNU_HUD", "hud_scale", -1.0, 8.0, 1.0, "$SCALEMNU_USEUI", "$SCALEMNU_USEFS", "hud_oldscale" + ScaleSlider "$SCALEMNU_ALTHUD", "hud_althudscale", 0.0, 8.0, 1.0, "$SCALEMNU_USEUI", "", "hud_oldscale" StaticText " " Option "$SCALEMNU_HUDASPECT", "hud_aspectscale", "OnOff" + StaticText " " + StaticText "$SCALEMNU_SCALECLASSIC", 1 + Option "$SCALEMNU_INTER", "inter_classic_scaling", "OnOff" + Option "$SCALEMNU_BORDER", "ui_screenborder_classic_scaling", "OnOff" + Slider "$SCALEMNU_FACTOR", "classic_scaling_factor", 1.0, 3.0, 0.2, 1 + Slider "$SCALEMNU_RATIO", "classic_scaling_pixelaspect", 1.0, 1.2, 0.2, 1 } //------------------------------------------------------------------------------------------- // @@ -1136,6 +1149,7 @@ OptionMenu "AltHUDOptions" protected Option "$ALTHUDMNU_SHOWSTATS", "hud_showstats", "OnOff" Option "$ALTHUDMNU_SHOWBERSERK", "hud_berserk_health", "OnOff" Option "$ALTHUDMNU_SHOWWEAPONS", "hud_showweapons", "OnOff" + Option "$ALTHUDMNU_SHOWTIMESTAT", "hud_showtimestat", "OnOff" Option "$ALTHUDMNU_SHOWAMMO", "hud_showammo", "AltHUDAmmo" Option "$ALTHUDMNU_SHOWTIME", "hud_showtime", "AltHUDTime" Option "$ALTHUDMNU_TIMECOLOR", "hud_timecolor", "TextColors" @@ -1143,6 +1157,7 @@ OptionMenu "AltHUDOptions" protected Option "$ALTHUDMNU_AMMOORDER", "hud_ammo_order", "AltHUDAmmoOrder" Slider "$ALTHUDMNU_AMMORED", "hud_ammo_red", 0, 100, 1, 0 Slider "$ALTHUDMNU_AMMOYELLOW", "hud_ammo_yellow", 0, 100, 1, 0 + Option "$ALTHUDMNU_SWAPHEALTHARMOR", "hud_swaphealtharmor", "OnOff" Slider "$ALTHUDMNU_HEALTHRED", "hud_health_red", 0, 100, 1, 0 Slider "$ALTHUDMNU_HEALTHYELLOW", "hud_health_yellow", 0, 100, 1, 0 Slider "$ALTHUDMNU_HEALTHGREEN", "hud_health_green", 0, 100, 1, 0 @@ -1181,6 +1196,13 @@ OptionValue dehopt 2, "$OPTVAL_ONLYLASTONE" } +OptionValue AlwaysTally +{ + 0, "$OPTVAL_MODDEFINED" + 1, "$OPTVAL_NOTHUBS" + 2, "$OPTVAL_WITHHUBS" +} + OptionMenu "MiscOptions" protected { Title "$MISCMNU_TITLE" @@ -1196,32 +1218,40 @@ OptionMenu "MiscOptions" protected } Option "$MISCMNU_QUERYIWAD", "queryiwad", "OnOff" StaticText " " - Option "$MISCMNU_NOCHEATS", "nocheats", "OnOff" + Option "$MISCMNU_FVIEWBOB", "fviewbob", "OnOff" + Option "$MISCMNU_NOCHEATS", "nocheats", "OnOff" Option "$MISCMNU_ALLCHEATS", "allcheats", "OnOff" Option "$MISCMNU_ENABLEAUTOSAVES", "disableautosave", "Autosave" - Option "$MISCMNU_SAVELOADCONFIRMATION", "saveloadconfirmation", "OnOff" + Option "$MISCMNU_RESTARTONDEATH", "cl_restartondeath", "OnOff" + Option "$MISCMNU_SAVELOADCONFIRMATION", "saveloadconfirmation", "OnOff" Slider "$MISCMNU_AUTOSAVECOUNT", "autosavecount", 1, 20, 1, 0 - Option "$MISCMNU_QUICKSAVEROTATION", "quicksaverotation", "OnOff" + Option "$MISCMNU_QUICKSAVEROTATION", "quicksaverotation", "OnOff" Slider "$MISCMNU_QUICKSAVECOUNT", "quicksaverotationcount", 1, 20, 1, 0 Option "$MISCMNU_DEHLOAD", "dehload", "dehopt" - Option "$MISCMNU_ENABLESCRIPTSCREENSHOTS", "enablescriptscreenshot", "OnOff" + Option "$MISCMNU_ENABLESCRIPTSCREENSHOTS", "enablescriptscreenshot", "OnOff" + Option "$MISCMNU_SETSLOTSTRICT", "setslotstrict", "YesNo" Option "$MISCMNU_INTERSCROLL", "nointerscrollabort", "OffOn" + Option "$MISCMNU_PAUSEINBACKGROUND", "i_pauseinbackground", "OnOff" StaticText " " Option "$MISCMNU_CACHENODES", "gl_cachenodes", "OnOff" Slider "$MISCMNU_CACHETIME", "gl_cachetime", 0.0, 2.0, 0.1 SafeCommand "$MISCMNU_CLEARNODECACHE", "clearnodecache" StaticText " " - Option "$OPTMNU_LANGUAGE", "language", "LanguageOptions" + Option "$OPTMNU_LANGUAGE", "language", "LanguageOptions" StaticText " " Option "$MISCMNU_QUICKEXIT", "m_quickexit", "OnOff" - IfOption(Windows) - { - StaticText " " - Option "$DSPLYMNU_SHOWENDOOM", "showendoom", "Endoom" - } + StaticText " " + Option "$DSPLYMNU_SHOWENDOOM", "showendoom", "Endoom" + + StaticText " " + Option "$MISCMNU_CLEANMENU", "m_cleanscale", "OffOn" + Option "$MISCMNU_CLEANSTAT", "wi_cleantextscale", "OnOff" + Option "$MISCMNU_WIPERCENT", "wi_percents", "OnOff" + StaticText " " + Option "$MISCMNU_ALWAYSTALLY", "sv_alwaystally", "AlwaysTally" } @@ -1310,9 +1340,12 @@ OptionMenu AutomapOptions protected StaticText "" Option "$AUTOMAPMNU_ROTATE", "am_rotate", "RotateTypes" + Option "$AUTOMAPMNU_FOLLOW", "am_followplayer", "OnOff" Option "$AUTOMAPMNU_OVERLAY", "am_overlay", "OverlayTypes" Option "$AUTOMAPMNU_TEXTURED", "am_textured", "OnOff" - Option "$AUTOMAPMNU_FOLLOW", "am_followplayer", "OnOff" + Slider "$AUTOMAPMNU_LINEALPHA", "am_linealpha", 0.1, 1.0, 0.1, 1 + Slider "$AUTOMAPMNU_LINETHICKNESS", "am_linethickness", 1, 8, 1, 0 + Option "$AUTOMAPMNU_LINEANTIALIASING", "am_lineantialiasing", "OnOff" StaticText "" Option "$AUTOMAPMNU_SHOWITEMS", "am_showitems", "OnOff" @@ -1366,6 +1399,7 @@ OptionMenu MapControlsMenu protected StaticText "" MapControl "$MAPCNTRLMNU_TOGGLEZOOM", "am_gobig" MapControl "$MAPCNTRLMNU_TOGGLEFOLLOW", "am_togglefollow" + MapControl "$MAPCNTRLMNU_ROTATE", "toggle am_rotate" MapControl "$MAPCNTRLMNU_TOGGLEGRID", "am_togglegrid" MapControl "$MAPCNTRLMNU_TOGGLETEXTURE", "am_toggletexture" @@ -1433,6 +1467,7 @@ OptionMenu MapColorMenuOverlay protected ColorPicker "$MAPCOLORMNU_INTRALEVELCOLOR", "am_ovtelecolor" ColorPicker "$MAPCOLORMNU_INTERLEVELCOLOR", "am_ovinterlevelcolor" ColorPicker "$MAPCOLORMNU_SECRETSECTORCOLOR", "am_ovsecretsectorcolor" + ColorPicker "$MAPCOLORMNU_UNEXPLOREDSECRETCOLOR", "am_ovunexploredsecretcolor" ColorPicker "$MAPCOLORMNU_SPECIALWALLCOLOR", "am_ovspecialwallcolor" ColorPicker "$MAPCOLORMNU_PORTAL", "am_ovportalcolor" } @@ -1494,6 +1529,7 @@ OptionMenu MessageOptions protected Option "$MSGMNU_MESSAGELEVEL", "msg", "MessageLevels" Option "$MSGMNU_DEVELOPER", "developer", "DevMessageLevels" Option "$MSGMNU_CENTERMESSAGES", "con_centernotify", "OnOff" + Option "$MSGMNU_PULSEMESSAGES", "con_pulsetext", "OnOff" Option "$MSGMNU_SUBTITLES", "inter_subtitles", "OnOff" StaticText " " StaticText "$MSGMNU_MESSAGECOLORS", 1 @@ -1592,10 +1628,11 @@ OptionMenu GameplayOptions protected Submenu "$GMPLYMNU_COOPERATIVE", "CoopOptions" StaticText " " Option "$GMPLYMNU_TEAMPLAY", "teamplay", "OnOff" - Slider "$GMPLYMNU_TEAMDAMAGE", "teamdamage", 0, 1, 0.05,2 + Slider "$GMPLYMNU_TEAMDAMAGE", "teamdamage", 0, 1, 0.05,2 StaticText " " Option "$GMPLYMNU_SMARTAUTOAIM", "sv_smartaim", "SmartAim" StaticText " " + Option "$GMPLYMNU_PISTOLSTART", "sv_pistolstart", "YesNo" Option "$GMPLYMNU_FALLINGDAMAGE", "sv_fallingdamage", "FallingDM" Option "$GMPLYMNU_DROPWEAPON", "sv_weapondrop", "YesNo" Option "$GMPLYMNU_DOUBLEAMMO", "sv_doubleammo", "YesNo" @@ -1608,8 +1645,10 @@ OptionMenu GameplayOptions protected Option "$GMPLYMNU_ITEMSRESPAWN", "sv_itemrespawn", "YesNo" Option "$GMPLYMNU_SUPERRESPAWN", "sv_respawnsuper", "YesNo" Option "$GMPLYMNU_FASTMONSTERS", "sv_fastmonsters", "YesNo" + Option "$GMPLYMNU_INSTANTREACTION", "sv_instantreaction", "YesNo" Option "$GMPLYMNU_DEGENERATION", "sv_degeneration", "YesNo" Option "$GMPLYMNU_NOAUTOAIM", "sv_noautoaim", "NoYes" + Option "$GMPLYMNU_NOVERTSPREAD", "sv_novertspread", "NoYes" Option "$GMPLYMNU_ALLOWSUICIDE", "sv_disallowsuicide", "NoYes" Option "$GMPLYMNU_ALLOWJUMP", "sv_jump", "JumpCrouchFreeLook" Option "$GMPLYMNU_ALLOWCROUCH", "sv_crouch", "JumpCrouchFreeLook" @@ -1623,6 +1662,7 @@ OptionMenu GameplayOptions protected Option "$GMPLYMNU_DONTCHECKAMMO", "sv_dontcheckammo", "NoYes" Option "$GMPLYMNU_KILLBOSSSPAWNS", "sv_killbossmonst", "YesNo" Option "$GMPLYMNU_NOCOUNTENDMONSTER", "sv_nocountendmonst", "NoYes" + Option "$GMPLYMNU_ALWAYSSPAWNMULTI", "sv_alwaysspawnmulti", "YesNo" Class "GameplayMenu" } @@ -1644,6 +1684,7 @@ OptionMenu DeathmatchOptions protected Option "$GMPLYMNU_LOSEFRAG", "sv_losefrag", "YesNo" Option "$GMPLYMNU_KEEPFRAGS", "sv_keepfrags", "YesNo" Option "$GMPLYMNU_NOTEAMSWITCH", "sv_noteamswitch", "YesNo" + Option "$GMPLYMNU_NOEXTRAAMMO", "sv_noextraammo", "NoYes" Class "GameplayMenu" } @@ -1652,6 +1693,9 @@ OptionMenu CoopOptions protected Position -35 Title "$GMPLYMNU_COOPERATIVE" + Option "$GMPLYMNU_MULTIPLAYERTHINGS", "sv_nothingspawn", "NoYes" + Option "$GMPLYMNU_COOPTHINGS", "sv_nocoopthings", "NoYes" + Option "$GMPLYMNU_COOPITEMS", "sv_nocoopitems", "NoYes" Option "$GMPLYMNU_MULTIPLAYERWEAPONS", "sv_noweaponspawn", "NoYes" Option "$GMPLYMNU_LOSEINVENTORY", "sv_cooploseinventory", "YesNo" Option "$GMPLYMNU_KEEPKEYS", "sv_cooplosekeys", "NoYes" @@ -1661,6 +1705,11 @@ OptionMenu CoopOptions protected Option "$GMPLYMNU_KEEPAMMO", "sv_cooploseammo", "NoYes" Option "$GMPLYMNU_LOSEHALFAMMO", "sv_coophalveammo", "YesNo" Option "$GMPLYMNU_SPAWNWHEREDIED", "sv_samespawnspot", "YesNo" + Option "$GMPLYMNU_NOPLAYERCLIP", "sv_noplayerclip", "YesNo" + Option "$GMPLYMNU_SHAREKEYS", "sv_coopsharekeys", "YesNo" + Option "$GMPLYMNU_LOCALITEMS", "sv_localitems", "YesNo" + Option "$GMPLYMNU_NOLOCALDROP", "sv_nolocaldrops", "YesNo" + Option "$GMPLYMNU_REMEMBERWEAP", "sv_rememberlastweapon", "YesNo" Class "GameplayMenu" } @@ -1680,6 +1729,8 @@ OptionValue CompatModes 6, "$OPTVAL_BOOMSTRICT" 5, "$OPTVAL_MBF" 7, "$OPTVAL_MBFSTRICT" + 8, "$OPTVAL_MBF21" + 9, "$OPTVAL_MBF21STRICT" 4, "$OPTVAL_ZDOOM2063" } @@ -1702,7 +1753,7 @@ OptionMenu "CompatActorMenu" protected { Position -35 Title "$CMPTMNU_ACTORBEHAVIOR" - Option "$CMPTMNU_CORPSEGIBS", "compat_CORPSEGIBS", "YesNo" + Option "$CMPTMNU_VILEGHOSTS", "compat_VILEGHOSTS", "YesNo" Option "$CMPTMNU_NOBLOCKFRIENDS", "compat_NOBLOCKFRIENDS", "YesNo" Option "$CMPTMNU_LIMITPAIN", "compat_LIMITPAIN", "YesNo" Option "$CMPTMNU_MBFMONSTERMOVE", "compat_MBFMONSTERMOVE", "YesNo" @@ -1711,6 +1762,7 @@ OptionMenu "CompatActorMenu" protected Option "$CMPTMNU_INVISIBILITY", "compat_INVISIBILITY", "YesNo" Option "$CMPTMNU_MINOTAUR", "compat_MINOTAUR", "YesNo" Option "$CMPTMNU_NOTOSSDROPS", "compat_NOTOSSDROPS", "YesNo" + Option "$CMPTMNU_VOODOOZOMBIES", "compat_voodoozombies", "YesNo" Class "CompatibilityMenu" } @@ -1737,9 +1789,11 @@ OptionMenu "CompatMapMenu" protected Option "$CMPTMNU_POINTONLINE", "compat_pointonline", "YesNo" Option "$CMPTMNU_MULTIEXIT", "compat_multiexit", "YesNo" Option "$CMPTMNU_TELEPORT", "compat_teleport", "YesNo" + Option "$CMPTMNU_FDTELEPORT", "compat_fdteleport", "YesNo" Option "$CMPTMNU_PUSHWINDOW", "compat_pushwindow", "YesNo" Option "$CMPTMNU_CHECKSWITCHRANGE", "compat_checkswitchrange", "YesNo" Option "$CMPTMNU_RAILINGHACK", "compat_railing", "YesNo" + Option "$CMPTMNU_NOMBF21", "compat_nombf21", "YesNo" Class "CompatibilityMenu" } @@ -1779,7 +1833,6 @@ OptionMenu "CompatSoundMenu" protected Option "$CMPTMNU_SILENTPICKUP", "compat_SILENTPICKUP", "YesNo" Option "$CMPTMNU_SILENTINSTANTFLOORS", "compat_silentinstantfloors", "YesNo" Option "$CMPTMNU_SECTORSOUNDS", "compat_SECTORSOUNDS", "YesNo" - Option "$CMPTMNU_SOUNDCUTOFF", "compat_soundcutoff", "YesNo" Option "$CMPTMNU_SOUNDTARGET", "compat_SOUNDTARGET", "YesNo" Class "CompatibilityMenu" } @@ -1793,7 +1846,6 @@ OptionMenu "CompatSoundMenu" protected OptionValue SampleRates { 0, "$OPTVAL_DEFAULT" - 4000, "$OPTVAL_4000HZ" 8000, "$OPTVAL_8000HZ" 11025, "$OPTVAL_11025HZ" 22050, "$OPTVAL_22050HZ" @@ -1987,12 +2039,6 @@ OptionMenu OPNMIDICustomBanksMenu protected * *=======================================*/ -OptionValue ModReplayers -{ - 0.0, "$OPTVAL_SOUNDSYSTEM" - 1.0, "$OPTVAL_FOO_DUMB" -} - OptionValue ModQuality { @@ -2019,7 +2065,7 @@ OptionValue ModVolumeRamps OptionMenu ModReplayerOptions protected { Title "$MODMNU_TITLE" - Slider "$MODMNU_MASTERVOLUME", "mod_dumb_mastervolume", 1, 16, 0.5, 1 + Slider "$MODMNU_MASTERVOLUME", "mod_dumb_mastervolume", 0.25, 4, 0.1, 1 Option "$ADVSNDMNU_SAMPLERATE", "mod_samplerate", "SampleRates" Option "$MODMNU_QUALITY", "mod_interp", "ModQuality" Option "$MODMNU_VOLUMERAMPING", "mod_volramp", "ModVolumeRamps" @@ -2073,7 +2119,7 @@ OptionMenu ModReplayerOptions protected Title "$ADVSNDMNU_TIMIDITY" LabeledSubMenu "$ADVSNDMNU_SELCONFIG", "timidity_config", "TimidityConfigMenu" Option "$ADVSNDMNU_REVERB", "timidity_reverb", "TimidityReverb" - Slider "$ADVSNDMNU_REVERB_LEVEL", "timidity_reverb_level", 9, 127, 1, 0 + Slider "$ADVSNDMNU_REVERB_LEVEL", "timidity_reverb_level", 0, 127, 1, 0 Option "$ADVSNDMNU_CHORUS", "timidity_chorus", "OnOff" // other CVARs need to be revieved for usefulness } @@ -2111,6 +2157,12 @@ OptionMenu ModReplayerOptions protected 3, "$ADLVLMODEL_DMX" 4, "$ADLVLMODEL_APOGEE" 5, "$ADLVLMODEL_WIN9X" + 6, "$ADLVLMODEL_DMX_FIXED" + 7, "$ADLVLMODEL_APOGEE_FIXED" + 8, "$ADLVLMODEL_AIL" + 9, "$ADLVLMODEL_WIN9XGENERIC" + 10, "$ADLVLMODEL_HMI" + 11, "$ADLVLMODEL_HMIOLD" } OptionValue ADLOplCores @@ -2118,6 +2170,8 @@ OptionMenu ModReplayerOptions protected 0, "$OPTVAL_NUKEDOPL3" 1, "$OPTVAL_NUKEDOPL3174" 2, "$OPTVAL_DOSBOXOPL3" + 3, "$OPTVAL_OPALOPL3" + 4, "$OPTVAL_JAVAOPL3" } OptionValue OpnCores @@ -2125,6 +2179,9 @@ OptionMenu ModReplayerOptions protected 0, "$OPTVAL_MAMEOPN2" 1, "$OPTVAL_NUKEDOPN2" 2, "$OPTVAL_GENSOPN2" + 4, "$OPTVAL_NP2OPNA" + 5, "$OPTVAL_MAMEOPNA" + 6, "$OPTVAL_PMDWINOPNA" } OptionMenu ADLOptions protected @@ -2209,23 +2266,34 @@ OptionValue CropAspect 1, "$OPTVAL_LETTERBOX" } +OptionValue MaxFps +{ + 0, "$OPTVAL_UNLIMITED" + 60, "$OPTVAL_60FPS" + 75, "$OPTVAL_75FPS" + 90, "$OPTVAL_90FPS" + 120, "$OPTVAL_120FPS" + 144, "$OPTVAL_144FPS" + 200, "$OPTVAL_200FPS" +} + + OptionMenu VideoModeMenu protected { Title "$VIDMNU_TITLE" Option "$VIDMNU_PREFERBACKEND", "vid_preferbackend", "PreferBackend" StaticText " " - Option "$VIDMNU_RENDERMODE", "vid_rendermode", "RenderMode" - Option "$VIDMNU_FULLSCREEN", "fullscreen", "YesNo" + IfOption(SWRender) + { + Option "$VIDMNU_RENDERMODE", "vid_rendermode", "RenderMode" + } + Option "$VIDMNU_FULLSCREEN", "vid_fullscreen", "YesNo" IfOption(Mac) { Option "$VIDMNU_HIDPI", "vid_hidpi", "YesNo" } - IfOption(Windows) - { - Option "$DSPLYMNU_GPUSWITCH", vid_gpuswitch, "GPUSwitch" - } Option "$VIDMNU_FORCEASPECT", "vid_aspect", "ForceRatios" Option "$VIDMNU_CROPASPECT", "vid_cropaspect", "CropAspect" @@ -2234,6 +2302,7 @@ OptionMenu VideoModeMenu protected StaticText " " Option "$DSPLYMNU_VSYNC", "vid_vsync", "OnOff" + Slider "$VIDMNU_MAXFPS", "vid_maxfps", 35, 500, 1 Option "$DSPLYMNU_CAPFPS", "cl_capfps", "OffOn" StaticText "" @@ -2278,6 +2347,10 @@ OptionMenu CustomResolutionMenu protected Command "1440x900", "menu_resolution_set_custom 1440 900" Command "1680x1050", "menu_resolution_set_custom 1680 1050" Command "1920x1200", "menu_resolution_set_custom 1920 1200" + StaticText "" + StaticText "$VIDMNU_ASPECT219" + Command "1920x810", "menu_resolution_set_custom 1920 810" + Command "2560x1080", "menu_resolution_set_custom 2560 1080" } /*======================================= @@ -2290,10 +2363,9 @@ OptionMenu NetworkOptions protected { Title "$NETMNU_TITLE" StaticText "$NETMNU_LOCALOPTIONS", 1 - Option "$NETMNU_MOVEPREDICTION", "cl_noprediction", "OffOn" Option "$NETMNU_LINESPECIALPREDICTION", "cl_predict_specials", "OnOff" - Slider "$NETMNU_PREDICTIONLERPSCALE", "cl_predict_lerpscale", 0.0, 0.5, 0.05, 2 - Slider "$NETMNU_LERPTHRESHOLD", "cl_predict_lerpthreshold", 0.1, 16.0, 0.1 + Slider "$NETMNU_PREDICTIONLERPSCALE", "cl_rubberband_scale", 0.0, 1.0, 0.05, 2 + Slider "$NETMNU_LERPTHRESHOLD", "cl_rubberband_threshold", 0.0, 256.0, 8.0 StaticText " " StaticText "$NETMNU_HOSTOPTIONS", 1 Option "$NETMNU_EXTRATICS", "net_extratic", "ExtraTicMode" @@ -2347,7 +2419,6 @@ OptionValue "TonemapModes" 1, "$OPTVAL_UNCHARTED2" 2, "$OPTVAL_HEJLDAWSON" 3, "$OPTVAL_REINHARD" - 4, "$OPTVAL_LINEAR_3" 5, "$OPTVAL_PALETTE" } @@ -2395,13 +2466,9 @@ OptionValue "Colormaps" OptionValue "LightingModes" { - 0, "$OPTVAL_STANDARD" - 1, "$OPTVAL_BRIGHT" - 2, "$OPTVAL_DOOM" - 3, "$OPTVAL_DARK" - 4, "$OPTVAL_LEGACY" - 8, "$OPTVAL_SOFTWARE" - 16, "$OPTVAL_VANILLA" + 0, "$OPTVAL_CLASSIC" + 1, "$OPTVAL_SOFTWARE" + 2, "$OPTVAL_VANILLA" } OptionValue "Precision" @@ -2420,17 +2487,6 @@ OptionValue "DitherModes" 12, "12 BPC" } -OptionValue "Hz" -{ - 0, "$OPTVAL_OPTIMAL" - 60, "$OPTVAL_60" - 70, "$OPTVAL_70" - 72, "$OPTVAL_72" - 75, "$OPTVAL_75" - 85, "$OPTVAL_85" - 100, "$OPTVAL_100" -} - OptionValue "BillboardModes" { 0, "$OPTVAL_YAXIS" @@ -2504,6 +2560,7 @@ OptionValue VRMode 9, "$OPTVAL_AMBERBLUE" 3, "$OPTVAL_SBSFULL" 4, "$OPTVAL_SBSNARROW" + 8, "$OPTVAL_SBSLETTERBOX" 11, "$OPTVAL_TOPBOTTOM" 12, "$OPTVAL_ROWINTERLEAVED" 13, "$OPTVAL_COLUMNINTERLEAVED" @@ -2550,6 +2607,7 @@ OptionMenu "GLTextureGLOptions" protected Option "$GLTEXMNU_RESIZETEX", gl_texture_hqresize_textures, "OnOff" Option "$GLTEXMNU_RESIZESPR", gl_texture_hqresize_sprites, "OnOff" Option "$GLTEXMNU_RESIZEFNT", gl_texture_hqresize_fonts, "OnOff" + Option "$GLTEXMNU_RESIZESKN", gl_texture_hqresize_skins, "OnOff" Option "$GLTEXMNU_PRECACHETEX", gl_precache, "YesNo" Option "$GLTEXMNU_SORTDRAWLIST", gl_sort_textures, "YesNo" Class "GLTextureGLOptions" @@ -2586,8 +2644,10 @@ OptionMenu "OpenGLOptions" protected Option "$GLPREFMNU_FUZZSTYLE", gl_fuzztype, "FuzzStyle" Option "$GLPREFMNU_SPRBILLBOARD", gl_billboard_mode, "BillboardModes" Option "$GLPREFMNU_SPRBILLFACECAMERA", gl_billboard_faces_camera, "OnOff" + Option "$GLPREFMNU_SPRBILLFACECAMERAFORCE", hw_force_cambbpref, "OnOff" Option "$GLPREFMNU_PARTICLESTYLE", gl_particles_style, "Particles" - Option "$GLPREFMNU_RENDERQUALITY", gl_render_precise, "Precision" + Option "$GLPREFMNU_RENDERQUALITY", gl_seamless, "Precision" + //Option "$GLPREFMNU_CORONAS", gl_coronas, "OnOff" StaticText " " Slider "$GLPREFMNU_MENUBLUR", gl_menu_blur, 0, 5.0, 0.5, 2 StaticText " " @@ -2720,22 +2780,26 @@ OptionString "LanguageOptions" "default", "English (US)" "eng", "English (UK)" "cs", "Česky (Czech)" + "da", "Dansk (Danish)" "de", "Deutsch (German)" "es", "Español (España) (Castilian Spanish)" "esm", "Español (Latino) (Latin American Spanish)" "eo", "Esperanto" "fi", "Suomi (Finnish)" "fr", "Français (French)" + "hu", "Magyar (Hungarian)" "it", "Italiano (Italian)" "jp", "日本語 (Japanese)" "ko", "한국어 (Korean)" "nl", "Nederlands (Dutch)" + "no", "Norsk Bokmål (Norwegian)" "pl", "Polski (Polish)" "ptg", "Português (European Portuguese)" "pt", "Português do Brasil (Brazilian Portuguese)" "ro", "Română (Romanian)" "ru", "Русский (Russian)" "sr", "Српски (Serbian)" + "tr", "Türkçe (Turkish)" } /*======================================= @@ -2765,9 +2829,16 @@ OptionValue "os_isanyof_values" OptionMenu "vkoptions" { Title "$VK_TITLE" - StaticText "$VK_WARNING" + //StaticText "$VK_WARNING" StaticText "$VK_RESTART" StaticText "" TextField "$VKMNU_DEVICE", vk_device Option "$VKMNU_HDR", "vk_hdr", "OnOff" } + +OptionValue "SpriteShadowModes" +{ + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_DEFAULT" + 2, "$OPTVAL_SPRSHADALWAYS" +} diff --git a/wadsrc/static/menudef.zsimple b/wadsrc/static/menudef.zsimple new file mode 100644 index 00000000000..512dc3a0bf6 --- /dev/null +++ b/wadsrc/static/menudef.zsimple @@ -0,0 +1,124 @@ +// this file has the simplified menu here. +// this file is *only* for options that are relevant to a novice user of GZDoom +// this file needs to be regularly pruned, with options coalesced as much as possible. any and all verbosity should go to the "full" menus. + +OptionMenu "OptionsMenuSimple" protected +{ + Title "$OPTMNU_TITLE" + Submenu "$OPTMNU_CONTROLS", "CustomizeControls" + Submenu "$OPTMNU_MOUSE", "MouseOptionsSimple" + Submenu "$OPTMNU_JOYSTICK", "JoystickOptions" + StaticText " " + Submenu "$OPTMNU_PLAYER", "NewPlayerMenu" + StaticText " " + Submenu "$OPTMNU_SOUND", "SoundOptionsSimple" + Submenu "$OPTMNU_DISPLAY", "VideoOptionsSimple" + Submenu "$HUDMNU_SCALEOPT", "ScalingOptionsSimple" + StaticText " " + Submenu "$OPTMNU_MISCELLANEOUS", "MiscOptionsSimple" + StaticText " " + Submenu "$OS_TITLE", "os_Menu" + StaticText " " + Submenu "$OPTMNU_FULLOPTIONS", "OptionsMenuFull" + StaticText " " + SafeCommand "$OPTMNU_DEFAULTS", "reset2defaults" + SafeCommand "$OPTMNU_RESETTOSAVED", "reset2saved" + SafeCommand "$OPTMNU_WRITEINI", "writeini" + Command "$OPTMNU_CONSOLE", "menuconsole" + StaticText " " +} + +OptionMenu SoundOptionsSimple protected +{ + Title "$SNDMNU_TITLE" + Slider "$MODMNU_MASTERVOLUME", "snd_mastervolume", 0, 1, 0.05, 2 + StaticText " " + Slider "$SNDMNU_SFXVOLUME", "snd_sfxvolume", 0, 1, 0.05, 2 + Slider "$SNDMNU_MUSICVOLUME", "snd_musicvolume", 0, 1, 0.05, 2 + StaticText " " + Slider "$SNDMNU_MENUVOLUME", "snd_menuvolume", 0, 1, 0.05, 2 + StaticText " " + Option "$SNDMNU_MIDIDEVICE", "snd_mididevice", "MidiDevices" + Command "$SNDMNU_RESTART", "snd_reset" +} + +OptionMenu VideoOptionsSimple protected +{ + Title "$DSPLYMNU_TITLE" + + Option "$VIDMNU_PREFERBACKEND", "vid_preferbackend", "PreferBackend" + IfOption(SWRender) + { + Option "$VIDMNU_RENDERMODE", "vid_rendermode", "RenderMode" + } + Option "$VIDMNU_FULLSCREEN", "vid_fullscreen", "YesNo" + IfOption(Mac) + { + Option "$VIDMNU_HIDPI", "vid_hidpi", "YesNo" + } + + StaticText " " + Option "$DSPLYMNU_DRAWFUZZ", "r_drawfuzz", "Fuzziness" + Option "$DSPLYMNU_WIPETYPE", "wipetype", "Wipes" + StaticText " " + Option "$GLTEXMNU_TEXFILTER", gl_texture_filter, "FilterModes" + Option "$GLTEXMNU_ANISOTROPIC", gl_texture_filter_anisotropic, "Anisotropy" + Option "$GLPREFMNU_SECLIGHTMODE", gl_lightmode, "LightingModes" + StaticText " " + Option "$DSPLYMNU_VSYNC", "vid_vsync", "OnOff" + Slider "$VIDMNU_MAXFPS", "vid_maxfps", 35, 500, 1 + StaticText " " + Slider "$DSPLYMNU_GAMMA", "vid_gamma", 0.75, 3.0, 0.05, 2 + Slider "$DSPLYMNU_BRIGHTNESS", "vid_brightness", -0.8,0.8, 0.05,2 + Slider "$DSPLYMNU_CONTRAST", "vid_contrast", 0.1, 3.0, 0.1 + Slider "$DSPLYMNU_SATURATION", "vid_saturation", -3.0, 3.0, 0.25, 2 + StaticText " " + Slider "$DSPLYMNU_FOV", "fov", 75.0, 120.0, 0.1, 1 + // commenting this out for now, this menu is so general purpose I am not sure it makes sense, but I'm leaving it here just in case + // the "full" menu doesn't have some of the options that are in this one. + //StaticText " " + //Submenu "$OPTMNU_FULLOPTIONS", "VideoModeMenu" +} + +OptionMenu ScalingOptionsSimple protected +{ + Title "$SCALEMNU_TITLE" + StaticText "$OPTMNU_HUD" + ScaleSlider "$HUDMNU_UISCALE", "uiscale", 0.0, 8.0, 1.0, "$SCALEMNU_ADAPT" + Option "$SCALEMNU_HUDASPECT", "hud_aspectscale", "OnOff" + Slider "$DSPLYMNU_SCREENSIZE", "screenblocks", 3.0, 12.0, 1.0, 0 + StaticText " " + StaticText "$VIDMNU_TITLE" + Option "$VIDMNU_SCALEMODE", "vid_scalemode", "ScaleModes" + Slider "$VIDMNU_SCALEFACTOR", "vid_scalefactor", 0.25, 2.0, 0.25, 2 +} + +OptionMenu MiscOptionsSimple protected +{ + Title "$MISCMNU_TITLE" + Option "$MISCMNU_QUERYIWAD", "queryiwad", "OnOff" + Option "$MISCMNU_NOCHEATS", "nocheats", "OnOff" + Option "$MISCMNU_ALLCHEATS", "allcheats", "OnOff" + Option "$MISCMNU_ENABLEAUTOSAVES", "disableautosave", "Autosave" + Option "$MISCMNU_DEHLOAD", "dehload", "dehopt" + Option "$MISCMNU_ENABLESCRIPTSCREENSHOTS", "enablescriptscreenshot", "OnOff" + Option "$OPTMNU_LANGUAGE", "language", "LanguageOptions" + Option "$MSGMNU_LONGSAVEMESSAGES", "longsavemessages", "OnOff" +} + +OptionMenu "MouseOptionsSimple" protected +{ + Title "$MOUSEMNU_TITLE" + Option "$MOUSEMNU_ENABLEMOUSE", "use_mouse", "YesNo" + Option "$MOUSEMNU_MOUSEINMENU", "m_use_mouse", "MenuMouse", "use_mouse" + IfOption(Windows) + { + Option "$MOUSEMNU_SWAPBUTTONS", "m_swapbuttons", "YesNo" + } + Option "$MOUSEMNU_CURSOR", "vid_cursor", "Cursors" + StaticText "" + Slider "$MOUSEMNU_SENSITIVITY_X", "m_sensitivity_x", 0.1, 8, 0.05 + Slider "$MOUSEMNU_SENSITIVITY_Y", "m_sensitivity_y", 0.1, 8, 0.05 + StaticText "" + Option "$MOUSEMNU_INVERTMOUSE", "invertmouse", "OnOff" +} diff --git a/wadsrc/static/shaders/glsl/burn.fp b/wadsrc/static/shaders/glsl/burn.fp index 486789f54c1..ff9c1d699d6 100644 --- a/wadsrc/static/shaders/glsl/burn.fp +++ b/wadsrc/static/shaders/glsl/burn.fp @@ -9,6 +9,6 @@ void main() vec4 t1 = texture(tex, vTexCoord.xy); vec4 t2 = texture(texture2, vec2(vTexCoord.x, 1.0-vTexCoord.y)); - + FragColor = frag * vec4(t1.r, t1.g, t1.b, t2.a); } diff --git a/wadsrc/static/shaders/glsl/colormap.fp b/wadsrc/static/shaders/glsl/colormap.fp deleted file mode 100644 index 43cc28b25c4..00000000000 --- a/wadsrc/static/shaders/glsl/colormap.fp +++ /dev/null @@ -1,13 +0,0 @@ - -layout(location=0) in vec2 TexCoord; -layout(location=0) out vec4 FragColor; -layout(binding=0) uniform sampler2D SceneTexture; - -void main() -{ - vec4 frag = texture(SceneTexture, TexCoord); - float gray = (frag.r * 0.3 + frag.g * 0.56 + frag.b * 0.14); - vec4 cm = uFixedColormapStart + gray * uFixedColormapRange; - FragColor = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a); -} - diff --git a/wadsrc/static/shaders/glsl/fogboundary.fp b/wadsrc/static/shaders/glsl/fogboundary.fp index 9494a9ca9fe..3bfa059c08b 100644 --- a/wadsrc/static/shaders/glsl/fogboundary.fp +++ b/wadsrc/static/shaders/glsl/fogboundary.fp @@ -15,7 +15,7 @@ void main() { float fogdist; float fogfactor; - + // // calculate fog factor // diff --git a/wadsrc/static/shaders/glsl/func_brightmap.fp b/wadsrc/static/shaders/glsl/func_brightmap.fp deleted file mode 100644 index 30c2a737b8e..00000000000 --- a/wadsrc/static/shaders/glsl/func_brightmap.fp +++ /dev/null @@ -1,9 +0,0 @@ - -Material ProcessMaterial() -{ - Material material; - material.Base = getTexel(vTexCoord.st); - material.Normal = ApplyNormalMap(vTexCoord.st); - material.Bright = texture(brighttexture, vTexCoord.st); - return material; -} diff --git a/wadsrc/static/shaders/glsl/func_defaultlight.fp b/wadsrc/static/shaders/glsl/func_defaultlight.fp index 7463528fd27..6738af8f5f7 100644 --- a/wadsrc/static/shaders/glsl/func_defaultlight.fp +++ b/wadsrc/static/shaders/glsl/func_defaultlight.fp @@ -1,17 +1,5 @@ -#if defined(BRIGHTMAP) - -vec4 ProcessLight(Material material, vec4 color) -{ - vec4 brightpix = desaturate(material.Bright); - return vec4(min(color.rgb + brightpix.rgb, 1.0), color.a); -} - -#else - vec4 ProcessLight(Material material, vec4 color) { return color; } - -#endif diff --git a/wadsrc/static/shaders/glsl/func_defaultmat.fp b/wadsrc/static/shaders/glsl/func_defaultmat.fp index 0535b8750a8..d4c3c99f783 100644 --- a/wadsrc/static/shaders/glsl/func_defaultmat.fp +++ b/wadsrc/static/shaders/glsl/func_defaultmat.fp @@ -1,11 +1,7 @@ -Material ProcessMaterial() +void SetupMaterial(inout Material material) { - Material material; material.Base = ProcessTexel(); material.Normal = ApplyNormalMap(vTexCoord.st); -#if defined(BRIGHTMAP) material.Bright = texture(brighttexture, vTexCoord.st); -#endif - return material; } diff --git a/wadsrc/static/shaders/glsl/func_defaultmat2.fp b/wadsrc/static/shaders/glsl/func_defaultmat2.fp new file mode 100644 index 00000000000..b2beb254e6d --- /dev/null +++ b/wadsrc/static/shaders/glsl/func_defaultmat2.fp @@ -0,0 +1,6 @@ + +void SetupMaterial(inout Material material) +{ + vec2 texCoord = GetTexCoord(); + SetMaterialProps(material, texCoord); +} diff --git a/wadsrc/static/shaders/glsl/func_normal.fp b/wadsrc/static/shaders/glsl/func_normal.fp index fbf40113f94..49dfadd9aa0 100644 --- a/wadsrc/static/shaders/glsl/func_normal.fp +++ b/wadsrc/static/shaders/glsl/func_normal.fp @@ -1,8 +1,5 @@ -Material ProcessMaterial() +void SetupMaterial(inout Material material) { - Material material; - material.Base = getTexel(vTexCoord.st); - material.Normal = ApplyNormalMap(vTexCoord.st); - return material; + SetMaterialProps(material, vTexCoord.st); } diff --git a/wadsrc/static/shaders/glsl/func_pbr.fp b/wadsrc/static/shaders/glsl/func_pbr.fp index b0e61d10147..79de3bb8577 100644 --- a/wadsrc/static/shaders/glsl/func_pbr.fp +++ b/wadsrc/static/shaders/glsl/func_pbr.fp @@ -1,14 +1,8 @@ -Material ProcessMaterial() +void SetupMaterial(inout Material material) { - Material material; - material.Base = getTexel(vTexCoord.st); - material.Normal = ApplyNormalMap(vTexCoord.st); + SetMaterialProps(material, vTexCoord.st); material.Metallic = texture(metallictexture, vTexCoord.st).r; material.Roughness = texture(roughnesstexture, vTexCoord.st).r; material.AO = texture(aotexture, vTexCoord.st).r; -#if defined(BRIGHTMAP) - material.Bright = texture(brighttexture, vTexCoord.st); -#endif - return material; } diff --git a/wadsrc/static/shaders/glsl/func_spec.fp b/wadsrc/static/shaders/glsl/func_spec.fp index afa1af84355..7de5b1d4ea2 100644 --- a/wadsrc/static/shaders/glsl/func_spec.fp +++ b/wadsrc/static/shaders/glsl/func_spec.fp @@ -1,14 +1,8 @@ -Material ProcessMaterial() +void SetupMaterial(inout Material material) { - Material material; - material.Base = getTexel(vTexCoord.st); - material.Normal = ApplyNormalMap(vTexCoord.st); + SetMaterialProps(material, vTexCoord.st); material.Specular = texture(speculartexture, vTexCoord.st).rgb; material.Glossiness = uSpecularMaterial.x; material.SpecularLevel = uSpecularMaterial.y; -#if defined(BRIGHTMAP) - material.Bright = texture(brighttexture, vTexCoord.st); -#endif - return material; } diff --git a/wadsrc/static/shaders/glsl/func_warp1.fp b/wadsrc/static/shaders/glsl/func_warp1.fp index 4214f771f2b..dfadf8ada88 100644 --- a/wadsrc/static/shaders/glsl/func_warp1.fp +++ b/wadsrc/static/shaders/glsl/func_warp1.fp @@ -1,5 +1,5 @@ -vec4 ProcessTexel() +vec2 GetTexCoord() { vec2 texCoord = vTexCoord.st; @@ -9,8 +9,11 @@ vec4 ProcessTexel() offset.y = sin(pi * 2.0 * (texCoord.x + timer * 0.125)) * 0.1; offset.x = sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1; - texCoord += offset; + return texCoord + offset; +} - return getTexel(texCoord); +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); } diff --git a/wadsrc/static/shaders/glsl/func_warp2.fp b/wadsrc/static/shaders/glsl/func_warp2.fp index 389fad9df74..1ee0f7fd02e 100644 --- a/wadsrc/static/shaders/glsl/func_warp2.fp +++ b/wadsrc/static/shaders/glsl/func_warp2.fp @@ -1,5 +1,6 @@ -vec4 ProcessTexel() + +vec2 GetTexCoord() { vec2 texCoord = vTexCoord.st; @@ -9,8 +10,11 @@ vec4 ProcessTexel() offset.y = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.61 + 900.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.36 + 300.0/8192.0)); offset.x = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.49 + 700.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.49 + 1200.0/8192.0)); - texCoord += offset * 0.025; + return texCoord + offset * 0.025; +} - return getTexel(texCoord); +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); } diff --git a/wadsrc/static/shaders/glsl/func_warp3.fp b/wadsrc/static/shaders/glsl/func_warp3.fp index dceca24773f..9edea0004e7 100644 --- a/wadsrc/static/shaders/glsl/func_warp3.fp +++ b/wadsrc/static/shaders/glsl/func_warp3.fp @@ -1,5 +1,6 @@ -vec4 ProcessTexel() + +vec2 GetTexCoord() { vec2 texCoord = vTexCoord.st; @@ -10,8 +11,11 @@ vec4 ProcessTexel() offset.y = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.75)) * 0.03; offset.x = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.45)) * 0.02; - texCoord += offset; + return texCoord + offset; +} - return getTexel(texCoord); +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); } diff --git a/wadsrc/static/shaders/glsl/func_wavex.fp b/wadsrc/static/shaders/glsl/func_wavex.fp index 05ab5302847..3b892da9d7f 100644 --- a/wadsrc/static/shaders/glsl/func_wavex.fp +++ b/wadsrc/static/shaders/glsl/func_wavex.fp @@ -1,5 +1,5 @@ -vec4 ProcessTexel() +vec2 GetTexCoord() { vec2 texCoord = vTexCoord.st; @@ -7,6 +7,11 @@ vec4 ProcessTexel() texCoord.x += sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1; - return getTexel(texCoord); + return texCoord; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); } diff --git a/wadsrc/static/shaders/glsl/fuzz_smooth.fp b/wadsrc/static/shaders/glsl/fuzz_smooth.fp index 3c642c399a7..b2af9a2e5bc 100644 --- a/wadsrc/static/shaders/glsl/fuzz_smooth.fp +++ b/wadsrc/static/shaders/glsl/fuzz_smooth.fp @@ -13,6 +13,6 @@ vec4 ProcessTexel() basicColor.a = basicColor.a * test; basicColor.r = basicColor.g = basicColor.b = 0.0; - + return basicColor; } diff --git a/wadsrc/static/shaders/glsl/fuzz_standard.fp b/wadsrc/static/shaders/glsl/fuzz_standard.fp index 3eb3b67e6b4..fd166760a2c 100644 --- a/wadsrc/static/shaders/glsl/fuzz_standard.fp +++ b/wadsrc/static/shaders/glsl/fuzz_standard.fp @@ -17,6 +17,6 @@ vec4 ProcessTexel() basicColor.a = basicColor.a * test; basicColor.r = basicColor.g = basicColor.b = 0.0; - + return basicColor; } diff --git a/wadsrc/static/shaders/glsl/fuzz_swirly.fp b/wadsrc/static/shaders/glsl/fuzz_swirly.fp index 266858999e7..0bb584cd581 100644 --- a/wadsrc/static/shaders/glsl/fuzz_swirly.fp +++ b/wadsrc/static/shaders/glsl/fuzz_swirly.fp @@ -13,6 +13,6 @@ vec4 ProcessTexel() basicColor.a = basicColor.a * test; basicColor.r = basicColor.g = basicColor.b = 0.0; - + return basicColor; } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 095c16a35f0..95f248d69ab 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -1,4 +1,5 @@ + layout(location = 0) in vec4 vTexCoord; layout(location = 1) in vec4 vColor; layout(location = 2) in vec4 pixelpos; @@ -6,6 +7,7 @@ layout(location = 3) in vec3 glowdist; layout(location = 4) in vec3 gradientdist; layout(location = 5) in vec4 vWorldNormal; layout(location = 6) in vec4 vEyeNormal; +layout(location = 9) in vec3 vLightmap; #ifdef NO_CLIPDISTANCE_SUPPORT layout(location = 7) in vec4 ClipDistanceA; @@ -22,6 +24,7 @@ struct Material { vec4 Base; vec4 Bright; + vec4 Glow; vec3 Normal; vec3 Specular; float Glossiness; @@ -33,9 +36,34 @@ struct Material vec4 Process(vec4 color); vec4 ProcessTexel(); -Material ProcessMaterial(); +Material ProcessMaterial(); // note that this is deprecated. Use SetupMaterial! +void SetupMaterial(inout Material mat); vec4 ProcessLight(Material mat, vec4 color); vec3 ProcessMaterialLight(Material material, vec3 color); +vec2 GetTexCoord(); + +// These get Or'ed into uTextureMode because it only uses its 3 lowermost bits. +const int TEXF_Brightmap = 0x10000; +const int TEXF_Detailmap = 0x20000; +const int TEXF_Glowmap = 0x40000; +const int TEXF_ClampY = 0x80000; + +//=========================================================================== +// +// RGB to HSV +// +//=========================================================================== + +vec3 rgb2hsv(vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} //=========================================================================== // @@ -88,27 +116,27 @@ const int Tex_Blend_Alpha = 1; const int Tex_Blend_Screen = 2; const int Tex_Blend_Overlay = 3; const int Tex_Blend_Hardlight = 4; - + vec4 ApplyTextureManipulation(vec4 texel, int blendflags) { // Step 1: desaturate according to the material's desaturation factor. texel = dodesaturate(texel, uTextureModulateColor.a); - + // Step 2: Invert if requested if ((blendflags & 8) != 0) { texel.rgb = vec3(1.0 - texel.r, 1.0 - texel.g, 1.0 - texel.b); } - + // Step 3: Apply additive color texel.rgb += uTextureAddColor.rgb; - + // Step 4: Colorization, including gradient if set. texel.rgb *= uTextureModulateColor.rgb; - + // Before applying the blend the value needs to be clamped to [0..1] range. texel.rgb = clamp(texel.rgb, 0.0, 1.0); - + // Step 5: Apply a blend. This may just be a translucent overlay or one of the blend modes present in current Build engines. if ((blendflags & 7) != 0) { @@ -153,47 +181,55 @@ const int Tex_Blend_Hardlight = 4; vec4 getTexel(vec2 st) { vec4 texel = texture(tex, st); - + // // Apply texture modes // - switch (uTextureMode) + switch (uTextureMode & 0xffff) { case 1: // TM_STENCIL texel.rgb = vec3(1.0,1.0,1.0); break; - + case 2: // TM_OPAQUE texel.a = 1.0; break; - + case 3: // TM_INVERSE texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, texel.a); break; - + case 4: // TM_ALPHATEXTURE { float gray = grayscale(texel); texel = vec4(1.0, 1.0, 1.0, gray*texel.a); break; } - + case 5: // TM_CLAMPY if (st.t < 0.0 || st.t > 1.0) { texel.a = 0.0; } break; - + case 6: // TM_OPAQUEINVERSE texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, 1.0); break; - + case 7: //TM_FOGLAYER return texel; } - + + if ((uTextureMode & TEXF_ClampY) != 0) + { + if (st.t < 0.0 || st.t > 1.0) + { + texel.a = 0.0; + } + } + // Apply the texture modification colors. int blendflags = int(uTextureAddColor.a); // this alpha is unused otherwise if (blendflags != 0) @@ -301,6 +337,16 @@ float R_DoomLightingEquation(float light) z = pixelpos.w; } + if ((uPalLightLevels >> 16) == 5) // gl_lightmode 5: Build software lighting emulation. + { + // This is a lot more primitive than Doom's lighting... + float numShades = float(uPalLightLevels & 255); + float curshade = (1.0 - light) * (numShades - 1.0); + float visibility = max(uGlobVis * uLightFactor * z, 0.0); + float shade = clamp((curshade + visibility), 0.0, numShades - 1.0); + return clamp(shade * uLightDist, 0.0, 1.0); + } + float colormap = R_DoomColormap(light, z); if ((uPalLightLevels & 0xff) != 0) @@ -312,10 +358,86 @@ float R_DoomLightingEquation(float light) //=========================================================================== // -// Check if light is in shadow according to its 1D shadow map +// Check if light is in shadow // //=========================================================================== +#ifdef SUPPORTS_RAYTRACING + +bool traceHit(vec3 origin, vec3 direction, float dist) +{ + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, TopLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, 0.01f, direction, dist); + while(rayQueryProceedEXT(rayQuery)) { } + return rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT; +} + +vec2 softshadow[9 * 3] = vec2[]( + vec2( 0.0, 0.0), + vec2(-2.0,-2.0), + vec2( 2.0, 2.0), + vec2( 2.0,-2.0), + vec2(-2.0, 2.0), + vec2(-1.0,-1.0), + vec2( 1.0, 1.0), + vec2( 1.0,-1.0), + vec2(-1.0, 1.0), + + vec2( 0.0, 0.0), + vec2(-1.5,-1.5), + vec2( 1.5, 1.5), + vec2( 1.5,-1.5), + vec2(-1.5, 1.5), + vec2(-0.5,-0.5), + vec2( 0.5, 0.5), + vec2( 0.5,-0.5), + vec2(-0.5, 0.5), + + vec2( 0.0, 0.0), + vec2(-1.25,-1.75), + vec2( 1.75, 1.25), + vec2( 1.25,-1.75), + vec2(-1.75, 1.75), + vec2(-0.75,-0.25), + vec2( 0.25, 0.75), + vec2( 0.75,-0.25), + vec2(-0.25, 0.75) +); + +float shadowAttenuation(vec4 lightpos, float lightcolorA) +{ + float shadowIndex = abs(lightcolorA) - 1.0; + if (shadowIndex >= 1024.0) + return 1.0; // Don't cast rays for this light + + vec3 origin = pixelpos.xzy; + vec3 target = lightpos.xzy + 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes + + vec3 direction = normalize(target - origin); + float dist = distance(origin, target); + + if (uShadowmapFilter <= 0) + { + return traceHit(origin, direction, dist) ? 0.0 : 1.0; + } + else + { + vec3 v = (abs(direction.x) > abs(direction.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); + vec3 xdir = normalize(cross(direction, v)); + vec3 ydir = cross(direction, xdir); + + float sum = 0.0; + int step_count = uShadowmapFilter * 9; + for (int i = 0; i <= step_count; i++) + { + vec3 pos = target + xdir * softshadow[i].x + ydir * softshadow[i].y; + sum += traceHit(origin, normalize(pos - origin), dist) ? 0.0 : 1.0; + } + return sum / step_count; + } +} + +#else #ifdef SUPPORTS_SHADOWMAPS float shadowDirToU(vec2 dir) @@ -404,7 +526,7 @@ float sampleShadowmapPCF(vec3 planePoint, float v) float sum = 0.0; float step_count = uShadowmapFilter; - + texelPos -= step_count + 0.5; for (float x = -step_count; x <= step_count; x++) { @@ -459,6 +581,7 @@ float shadowAttenuation(vec4 lightpos, float lightcolorA) return 1.0; } +#endif #endif float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle) @@ -524,6 +647,41 @@ vec3 ApplyNormalMap(vec2 texcoord) } #endif +//=========================================================================== +// +// Sets the common material properties. +// +//=========================================================================== + +void SetMaterialProps(inout Material material, vec2 texCoord) +{ +#ifdef NPOT_EMULATION + if (uNpotEmulation.y != 0.0) + { + float period = floor(texCoord.t / uNpotEmulation.y); + texCoord.s += uNpotEmulation.x * floor(mod(texCoord.t, uNpotEmulation.y)); + texCoord.t = period + mod(texCoord.t, uNpotEmulation.y); + } +#endif + material.Base = getTexel(texCoord.st); + material.Normal = ApplyNormalMap(texCoord.st); + +// OpenGL doesn't care, but Vulkan pukes all over the place if these texture samplings are included in no-texture shaders, even though never called. +#ifndef NO_LAYERS + if ((uTextureMode & TEXF_Brightmap) != 0) + material.Bright = desaturate(texture(brighttexture, texCoord.st)); + + if ((uTextureMode & TEXF_Detailmap) != 0) + { + vec4 Detail = texture(detailtexture, texCoord.st * uDetailParms.xy) * uDetailParms.z; + material.Base.rgb *= Detail.rgb; + } + + if ((uTextureMode & TEXF_Glowmap) != 0) + material.Glow = desaturate(texture(glowtexture, texCoord.st)); +#endif +} + //=========================================================================== // // Calculate light @@ -541,7 +699,7 @@ vec3 ApplyNormalMap(vec2 texcoord) vec4 getLightColor(Material material, float fogdist, float fogfactor) { vec4 color = vColor; - + if (uLightLevel >= 0.0) { float newlightlevel = 1.0 - R_DoomLightingEquation(uLightLevel); @@ -554,13 +712,13 @@ vec4 getLightColor(Material material, float fogdist, float fogfactor) { color.rgb *= uLightFactor - (fogdist / uLightDist) * (uLightFactor - 1.0); } - + // // apply light diminishing through fog equation // color.rgb = mix(vec3(0.0, 0.0, 0.0), color.rgb, fogfactor); } - + // // handle glowing walls // @@ -574,11 +732,32 @@ vec4 getLightColor(Material material, float fogdist, float fogfactor) } color = min(color, 1.0); + // these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set. +#if !defined LEGACY_USER_SHADER && !defined NO_LAYERS + // + // apply glow + // + color.rgb = mix(color.rgb, material.Glow.rgb, material.Glow.a); + // - // apply brightmaps (or other light manipulation by custom shaders. + // apply brightmaps + // + color.rgb = min(color.rgb + material.Bright.rgb, 1.0); +#endif + + // + // apply other light manipulation by custom shaders, default is a NOP. // color = ProcessLight(material, color); + // + // apply lightmaps + // + if (vLightmap.z >= 0.0) + { + color.rgb += texture(LightMap, vLightmap).rgb; + } + // // apply dynamic lights // @@ -606,7 +785,7 @@ vec3 AmbientOcclusionColor() { float fogdist; float fogfactor; - + // // calculate fog factor // @@ -619,7 +798,7 @@ vec3 AmbientOcclusionColor() fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); } fogfactor = exp2 (uFogDensity * fogdist); - + return mix(uFogColor.rgb, vec3(0.0), fogfactor); } @@ -635,9 +814,25 @@ void main() if (ClipDistanceA.x < 0 || ClipDistanceA.y < 0 || ClipDistanceA.z < 0 || ClipDistanceA.w < 0 || ClipDistanceB.x < 0) discard; #endif +#ifndef LEGACY_USER_SHADER + Material material; + + material.Base = vec4(0.0); + material.Bright = vec4(0.0); + material.Glow = vec4(0.0); + material.Normal = vec3(0.0); + material.Specular = vec3(0.0); + material.Glossiness = 0.0; + material.SpecularLevel = 0.0; + material.Metallic = 0.0; + material.Roughness = 0.0; + material.AO = 0.0; + SetupMaterial(material); +#else Material material = ProcessMaterial(); +#endif vec4 frag = material.Base; - + #ifndef NO_ALPHATEST if (frag.a <= uAlphaThreshold) discard; #endif @@ -646,7 +841,7 @@ void main() { float fogdist = 0.0; float fogfactor = 0.0; - + // // calculate fog factor // @@ -662,10 +857,11 @@ void main() } fogfactor = exp2 (uFogDensity * fogdist); } - - if (uTextureMode != 7) + + if ((uTextureMode & 0xffff) != 7) { frag = getLightColor(material, fogdist, fogfactor); + // // colored fog // @@ -681,7 +877,7 @@ void main() } else // simple 2D (uses the fog color to add a color overlay) { - if (uTextureMode == 7) + if ((uTextureMode & 0xffff) == 7) { float gray = grayscale(frag); vec4 cm = (uObjectColor + gray * (uAddColor - uObjectColor)) * 2; @@ -691,6 +887,27 @@ void main() frag.rgb = frag.rgb + uFogColor.rgb; } FragColor = frag; + +#ifdef DITHERTRANS + int index = (int(pixelpos.x) % 8) * 8 + int(pixelpos.y) % 8; + const float DITHER_THRESHOLDS[64] = + { + 1.0 / 65.0, 33.0 / 65.0, 9.0 / 65.0, 41.0 / 65.0, 3.0 / 65.0, 35.0 / 65.0, 11.0 / 65.0, 43.0 / 65.0, + 49.0 / 65.0, 17.0 / 65.0, 57.0 / 65.0, 25.0 / 65.0, 51.0 / 65.0, 19.0 / 65.0, 59.0 / 65.0, 27.0 / 65.0, + 13.0 / 65.0, 45.0 / 65.0, 5.0 / 65.0, 37.0 / 65.0, 15.0 / 65.0, 47.0 / 65.0, 7.0 / 65.0, 39.0 / 65.0, + 61.0 / 65.0, 29.0 / 65.0, 53.0 / 65.0, 21.0 / 65.0, 63.0 / 65.0, 31.0 / 65.0, 55.0 / 65.0, 23.0 / 65.0, + 4.0 / 65.0, 36.0 / 65.0, 12.0 / 65.0, 44.0 / 65.0, 2.0 / 65.0, 34.0 / 65.0, 10.0 / 65.0, 42.0 / 65.0, + 52.0 / 65.0, 20.0 / 65.0, 60.0 / 65.0, 28.0 / 65.0, 50.0 / 65.0, 18.0 / 65.0, 58.0 / 65.0, 26.0 / 65.0, + 16.0 / 65.0, 48.0 / 65.0, 8.0 / 65.0, 40.0 / 65.0, 14.0 / 65.0, 46.0 / 65.0, 6.0 / 65.0, 38.0 / 65.0, + 64.0 / 65.0, 32.0 / 65.0, 56.0 / 65.0, 24.0 / 65.0, 62.0 / 65.0, 30.0 / 65.0, 54.0 / 65.0, 22.0 /65.0 + }; + + vec3 fragHSV = rgb2hsv(FragColor.rgb); + float brightness = clamp(1.5*fragHSV.z, 0.1, 1.0); + if (DITHER_THRESHOLDS[index] < brightness) discard; + else FragColor *= 0.5; +#endif + #ifdef GBUFFER_PASS FragFog = vec4(AmbientOcclusionColor(), 1.0); FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0); diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index 86da9868a9b..f718d73bc8f 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -5,11 +5,15 @@ layout(location = 2) in vec4 aColor; layout(location = 0) out vec4 vTexCoord; layout(location = 1) out vec4 vColor; +layout(location = 9) out vec3 vLightmap; #ifndef SIMPLE // we do not need these for simple shaders layout(location = 3) in vec4 aVertex2; layout(location = 4) in vec4 aNormal; layout(location = 5) in vec4 aNormal2; +layout(location = 6) in vec3 aLightmap; +layout(location = 7) in vec4 aBoneWeight; +layout(location = 8) in uvec4 aBoneSelector; layout(location = 2) out vec4 pixelpos; layout(location = 3) out vec3 glowdist; @@ -23,15 +27,25 @@ layout(location = 7) out vec4 ClipDistanceA; layout(location = 8) out vec4 ClipDistanceB; #endif +struct BonesResult +{ + vec3 Normal; + vec4 Position; +}; + +BonesResult ApplyBones(); + void main() { float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4; vec2 parmTexCoord; vec4 parmPosition; - + + BonesResult bones = ApplyBones(); + parmTexCoord = aTexCoord; - parmPosition = aPosition; + parmPosition = bones.Position; #ifndef SIMPLE vec4 worldcoord = ModelMatrix * mix(parmPosition, aVertex2, uInterpolationFactor); @@ -51,6 +65,8 @@ void main() #endif #ifndef SIMPLE + vLightmap = aLightmap; + pixelpos.xyz = worldcoord.xyz; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; @@ -62,7 +78,7 @@ void main() glowdist.y = worldcoord.y - bottomatpoint; glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); } - + if (uObjectColor2.a != 0) { float topatpoint = (uGradientTopPlane.w + uGradientTopPlane.x * worldcoord.x + uGradientTopPlane.y * worldcoord.z) * uGradientTopPlane.z; @@ -71,24 +87,17 @@ void main() gradientdist.y = worldcoord.y - bottomatpoint; gradientdist.z = clamp(gradientdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); } - + if (uSplitBottomPlane.z != 0.0) { ClipDistance3 = ((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y; ClipDistance4 = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); } - #ifdef HAS_UNIFORM_VERTEX_DATA - if ((useVertexData & 2) == 0) - vWorldNormal = NormalModelMatrix * vec4(uVertexNormal.xyz, 1.0); - else - vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0); - #else - vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0); - #endif - vEyeNormal = NormalViewMatrix * vWorldNormal; + vWorldNormal = NormalModelMatrix * vec4(normalize(bones.Normal), 1.0); + vEyeNormal = NormalViewMatrix * vec4(normalize(vWorldNormal.xyz), 1.0); #endif - + #ifdef SPHEREMAP vec3 u = normalize(eyeCoordPos.xyz); vec4 n = normalize(NormalViewMatrix * vec4(parmTexCoord.x, 0.0, parmTexCoord.y, 0.0)); @@ -99,7 +108,7 @@ void main() #else vTexCoord = TextureMatrix * vec4(parmTexCoord, 0.0, 1.0); #endif - + gl_Position = ProjectionMatrix * eyeCoordPos; #ifdef VULKAN_COORDINATE_SYSTEM @@ -142,3 +151,66 @@ void main() gl_PointSize = 1.0; } + +#if !defined(SIMPLE) +vec3 GetAttrNormal() +{ + #ifdef HAS_UNIFORM_VERTEX_DATA + if ((useVertexData & 2) == 0) + return uVertexNormal.xyz; + else + return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor); + #else + return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor); + #endif +} + +void AddWeightedBone(uint boneIndex, float weight, inout vec4 position, inout vec3 normal) +{ + if (weight != 0.0) + { + mat4 transform = bones[uBoneIndexBase + int(boneIndex)]; + mat3 rotation = mat3(transform); + position += (transform * aPosition) * weight; + normal += (rotation * aNormal.xyz) * weight; + } +} + +BonesResult ApplyBones() +{ + BonesResult result; + if (uBoneIndexBase >= 0 && aBoneWeight != vec4(0.0)) + { + result.Position = vec4(0.0); + result.Normal = vec3(0.0); + + // We use low precision input for our bone weights. Rescale so the sum still is 1.0 + float totalWeight = aBoneWeight.x + aBoneWeight.y + aBoneWeight.z + aBoneWeight.w; + float weightMultiplier = 1.0 / totalWeight; + vec4 boneWeight = aBoneWeight * weightMultiplier; + + AddWeightedBone(aBoneSelector.x, boneWeight.x, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.y, boneWeight.y, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.z, boneWeight.z, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.w, boneWeight.w, result.Position, result.Normal); + + result.Position.w = 1.0; // For numerical stability + } + else + { + result.Position = aPosition; + result.Normal = GetAttrNormal(); + } + return result; +} + +#else + +BonesResult ApplyBones() +{ + BonesResult result; + result.Position = aPosition; + return result; +} + +#endif diff --git a/wadsrc/static/shaders/glsl/material_normal.fp b/wadsrc/static/shaders/glsl/material_normal.fp index add12881295..b9d25852c04 100644 --- a/wadsrc/static/shaders/glsl/material_normal.fp +++ b/wadsrc/static/shaders/glsl/material_normal.fp @@ -13,7 +13,7 @@ vec3 lightContribution(int i, vec3 normal) vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); float dotprod = dot(normal, lightdir); if (dotprod < -0.0001) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. Note that this can cause precision issues. - + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); if (lightspot1.w == 1.0) @@ -59,7 +59,21 @@ vec3 ProcessMaterialLight(Material material, vec3 color) } } - vec3 frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4); + vec3 frag; + + if ( uLightBlendMode == 1 ) + { // COLOR_CORRECT_CLAMPING + vec3 lightcolor = color + desaturate(dynlight).rgb; + frag = material.Base.rgb * ((lightcolor / max(max(max(lightcolor.r, lightcolor.g), lightcolor.b), 1.4) * 1.4)); + } + else if ( uLightBlendMode == 2 ) + { // UNCLAMPED + frag = material.Base.rgb * (color + desaturate(dynlight).rgb); + } + else + { + frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4); + } if (uLightIndex >= 0) { @@ -67,7 +81,7 @@ vec3 ProcessMaterialLight(Material material, vec3 color) if (lightRange.w > lightRange.z) { vec4 addlight = vec4(0.0,0.0,0.0,0.0); - + // additive lights for(int i=lightRange.z; i= 0.0 && t <= 1.0)? a:0) + TM_INVERTOPAQUE, // (1-r, 1-g, 1-b, 1) + TM_FOGLAYER, // (renders a fog layer in the shape of the active texture) + TM_FIXEDCOLORMAP = TM_FOGLAYER, + +0xF0000 = +(USES all) + TEXF_Brightmap = 0x10000, + TEXF_Detailmap = 0x20000, + TEXF_Glowmap = 0x40000, + + + + + + +uPalLightLevels + +0xFF = + 32 0r 0 or 1 + +0xFF00 = +gl_fogmode : +(USES 2) + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_STANDARD" + 2, "$OPTVAL_RADIAL" + +0xFF0000 +gl_lightmode: +(USES 16, 5) + 0, "$OPTVAL_STANDARD" + 1, "$OPTVAL_BRIGHT" + 2, "$OPTVAL_DOOM" + 3, "$OPTVAL_DARK" + 4, "$OPTVAL_LEGACY" + 5, "$OPTVAL_BUILD" + 8, "$OPTVAL_SOFTWARE" + 16, "$OPTVAL_VANILLA" + + + + + +uTextureAddColor.a -> blendflags +0x7 = +(USES all) +const int Tex_Blend_Alpha = 1; +const int Tex_Blend_Screen = 2; +const int Tex_Blend_Overlay = 3; +const int Tex_Blend_Hardlight = 4; + + +0x8 = +Invert blend bit + + + + +uDesaturationFactor +> 0 diff --git a/wadsrc/static/shaders_gles/glsl/burn.fp b/wadsrc/static/shaders_gles/glsl/burn.fp new file mode 100644 index 00000000000..040311711d4 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/burn.fp @@ -0,0 +1,13 @@ + +varying vec4 vTexCoord; +varying vec4 vColor; + +void main() +{ + vec4 frag = vColor; + + vec4 t1 = texture2D(tex, vTexCoord.xy); + vec4 t2 = texture2D(texture2, vec2(vTexCoord.x, 1.0-vTexCoord.y)); + + gl_FragColor = frag * vec4(t1.r, t1.g, t1.b, t2.a); +} diff --git a/wadsrc/static/shaders_gles/glsl/fogboundary.fp b/wadsrc/static/shaders_gles/glsl/fogboundary.fp new file mode 100644 index 00000000000..9a6448bee34 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fogboundary.fp @@ -0,0 +1,30 @@ +varying vec4 pixelpos; + +//=========================================================================== +// +// Main shader routine +// +//=========================================================================== + +void main() +{ + float fogdist; + float fogfactor; + + // + // calculate fog factor + // +#if (DEF_FOG_ENABLED == 1) && (DEF_FOG_RADIAL == 0) && (DEF_FOG_COLOURED == 1) // This was uFogEnabled = -1,, TODO check this + { + fogdist = pixelpos.w; + } +#else + { + fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + } +#endif + fogfactor = exp2 (uFogDensity * fogdist); + + gl_FragColor = vec4(uFogColor.rgb, 1.0 - fogfactor); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_defaultlight.fp b/wadsrc/static/shaders_gles/glsl/func_defaultlight.fp new file mode 100644 index 00000000000..6738af8f5f7 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_defaultlight.fp @@ -0,0 +1,5 @@ + +vec4 ProcessLight(Material material, vec4 color) +{ + return color; +} diff --git a/wadsrc/static/shaders_gles/glsl/func_defaultmat.fp b/wadsrc/static/shaders_gles/glsl/func_defaultmat.fp new file mode 100644 index 00000000000..35006820c85 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_defaultmat.fp @@ -0,0 +1,7 @@ + +void SetupMaterial(inout Material material) +{ + material.Base = ProcessTexel(); + material.Normal = ApplyNormalMap(vTexCoord.st); + material.Bright = texture2D(brighttexture, vTexCoord.st); +} diff --git a/wadsrc/static/shaders_gles/glsl/func_defaultmat2.fp b/wadsrc/static/shaders_gles/glsl/func_defaultmat2.fp new file mode 100644 index 00000000000..b2beb254e6d --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_defaultmat2.fp @@ -0,0 +1,6 @@ + +void SetupMaterial(inout Material material) +{ + vec2 texCoord = GetTexCoord(); + SetMaterialProps(material, texCoord); +} diff --git a/wadsrc/static/shaders_gles/glsl/func_normal.fp b/wadsrc/static/shaders_gles/glsl/func_normal.fp new file mode 100644 index 00000000000..49dfadd9aa0 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_normal.fp @@ -0,0 +1,5 @@ + +void SetupMaterial(inout Material material) +{ + SetMaterialProps(material, vTexCoord.st); +} diff --git a/wadsrc/static/shaders_gles/glsl/func_notexture.fp b/wadsrc/static/shaders_gles/glsl/func_notexture.fp new file mode 100644 index 00000000000..9337ad6b138 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_notexture.fp @@ -0,0 +1,6 @@ + +vec4 ProcessTexel() +{ + return desaturate(uObjectColor); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_paletted.fp b/wadsrc/static/shaders_gles/glsl/func_paletted.fp new file mode 100644 index 00000000000..3b223d2f8a8 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_paletted.fp @@ -0,0 +1,10 @@ + +vec4 ProcessTexel() +{ + float index = getTexel(vTexCoord.st).a; + index = ((index * 255.0) + 0.5) / 256.0; + vec4 tex = texture2D(texture2, vec2(index, 0.5)); + tex.a = 1.0; + return tex; +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_pbr.fp b/wadsrc/static/shaders_gles/glsl/func_pbr.fp new file mode 100644 index 00000000000..49dfadd9aa0 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_pbr.fp @@ -0,0 +1,5 @@ + +void SetupMaterial(inout Material material) +{ + SetMaterialProps(material, vTexCoord.st); +} diff --git a/wadsrc/static/shaders_gles/glsl/func_spec.fp b/wadsrc/static/shaders_gles/glsl/func_spec.fp new file mode 100644 index 00000000000..f2574a521c3 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_spec.fp @@ -0,0 +1,8 @@ + +void SetupMaterial(inout Material material) +{ + SetMaterialProps(material, vTexCoord.st); + material.Specular = texture2D(speculartexture, vTexCoord.st).rgb; + material.Glossiness = uSpecularMaterial.x; + material.SpecularLevel = uSpecularMaterial.y; +} diff --git a/wadsrc/static/shaders_gles/glsl/func_warp1.fp b/wadsrc/static/shaders_gles/glsl/func_warp1.fp new file mode 100644 index 00000000000..dfadf8ada88 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_warp1.fp @@ -0,0 +1,19 @@ + +vec2 GetTexCoord() +{ + vec2 texCoord = vTexCoord.st; + + const float pi = 3.14159265358979323846; + vec2 offset = vec2(0,0); + + offset.y = sin(pi * 2.0 * (texCoord.x + timer * 0.125)) * 0.1; + offset.x = sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1; + + return texCoord + offset; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_warp2.fp b/wadsrc/static/shaders_gles/glsl/func_warp2.fp new file mode 100644 index 00000000000..1ee0f7fd02e --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_warp2.fp @@ -0,0 +1,20 @@ + + +vec2 GetTexCoord() +{ + vec2 texCoord = vTexCoord.st; + + const float pi = 3.14159265358979323846; + vec2 offset = vec2(0.0,0.0); + + offset.y = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.61 + 900.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.36 + 300.0/8192.0)); + offset.x = 0.5 + sin(pi * 2.0 * (texCoord.y + timer * 0.49 + 700.0/8192.0)) + sin(pi * 2.0 * (texCoord.x * 2.0 + timer * 0.49 + 1200.0/8192.0)); + + return texCoord + offset * 0.025; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_warp3.fp b/wadsrc/static/shaders_gles/glsl/func_warp3.fp new file mode 100644 index 00000000000..9edea0004e7 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_warp3.fp @@ -0,0 +1,21 @@ + + +vec2 GetTexCoord() +{ + vec2 texCoord = vTexCoord.st; + + const float pi = 3.14159265358979323846; + vec2 offset = vec2(0.0,0.0); + + float siny = sin(pi * 2.0 * (texCoord.y * 2.0 + timer * 0.75)) * 0.03; + offset.y = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.75)) * 0.03; + offset.x = siny + sin(pi * 2.0 * (texCoord.x + timer * 0.45)) * 0.02; + + return texCoord + offset; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); +} + diff --git a/wadsrc/static/shaders_gles/glsl/func_wavex.fp b/wadsrc/static/shaders_gles/glsl/func_wavex.fp new file mode 100644 index 00000000000..3b892da9d7f --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/func_wavex.fp @@ -0,0 +1,17 @@ + +vec2 GetTexCoord() +{ + vec2 texCoord = vTexCoord.st; + + const float pi = 3.14159265358979323846; + + texCoord.x += sin(pi * 2.0 * (texCoord.y + timer * 0.125)) * 0.1; + + return texCoord; +} + +vec4 ProcessTexel() +{ + return getTexel(GetTexCoord()); +} + diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_jagged.fp b/wadsrc/static/shaders_gles/glsl/fuzz_jagged.fp new file mode 100644 index 00000000000..083c2206895 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_jagged.fp @@ -0,0 +1,24 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + + vec2 texSplat; + const float pi = 3.14159265358979323846; + texSplat.x = texCoord.x + mod(sin(pi * 2.0 * (texCoord.y + timer * 2.0)),0.1) * 0.1; + texSplat.y = texCoord.y + mod(cos(pi * 2.0 * (texCoord.x + timer * 2.0)),0.1) * 0.1; + + vec4 basicColor = getTexel(texSplat); + + float texX = sin(texCoord.x * 100.0 + timer*5.0); + float texY = cos(texCoord.x * 100.0 + timer*5.0); + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_noise.fp b/wadsrc/static/shaders_gles/glsl/fuzz_noise.fp new file mode 100644 index 00000000000..0107ebbd2fc --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_noise.fp @@ -0,0 +1,20 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + texCoord.x = float( int(texCoord.x * 128.0) ) / 128.0; + texCoord.y = float( int(texCoord.y * 128.0) ) / 128.0; + + float texX = sin(mod(texCoord.x * 100.0 + timer*5.0, 3.489)) + texCoord.x / 4.0; + float texY = cos(mod(texCoord.y * 100.0 + timer*5.0, 3.489)) + texCoord.y / 4.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + + float test = mod(timer*2.0+(vX + vY), 0.5); + basicColor.a = basicColor.a * test; + basicColor.rgb = vec3(0.0,0.0,0.0); + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_smooth.fp b/wadsrc/static/shaders_gles/glsl/fuzz_smooth.fp new file mode 100644 index 00000000000..3c642c399a7 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_smooth.fp @@ -0,0 +1,18 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + float texX = texCoord.x / 3.0 + 0.66; + float texY = 0.34 - texCoord.y / 3.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + basicColor.r = basicColor.g = basicColor.b = 0.0; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_smoothnoise.fp b/wadsrc/static/shaders_gles/glsl/fuzz_smoothnoise.fp new file mode 100644 index 00000000000..d446a3d0a93 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_smoothnoise.fp @@ -0,0 +1,19 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + float texX = sin(mod(texCoord.x * 100.0 + timer*5.0, 3.489)) + texCoord.x / 4.0; + float texY = cos(mod(texCoord.y * 100.0 + timer*5.0, 3.489)) + texCoord.y / 4.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + + + float test = mod(timer*2.0+(vX + vY), 0.5); + basicColor.a = basicColor.a * test; + + basicColor.rgb = vec3(0.0,0.0,0.0); + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_smoothtranslucent.fp b/wadsrc/static/shaders_gles/glsl/fuzz_smoothtranslucent.fp new file mode 100644 index 00000000000..1b727a1bc6b --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_smoothtranslucent.fp @@ -0,0 +1,18 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + float texX = sin(texCoord.x * 100.0 + timer*5.0); + float texY = cos(texCoord.x * 100.0 + timer*5.0); + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_software.fp b/wadsrc/static/shaders_gles/glsl/fuzz_software.fp new file mode 100644 index 00000000000..1edcb0099e6 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_software.fp @@ -0,0 +1,21 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + texCoord.x = float( int(texCoord.x * 128.0) ) / 128.0; + texCoord.y = float( int(texCoord.y * 128.0) ) / 128.0; + + float texX = texCoord.x / 3.0 + 0.66; + float texY = 0.34 - texCoord.y / 3.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + basicColor.r = basicColor.g = basicColor.b = 0.0; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_standard.fp b/wadsrc/static/shaders_gles/glsl/fuzz_standard.fp new file mode 100644 index 00000000000..1edcb0099e6 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_standard.fp @@ -0,0 +1,21 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + texCoord.x = float( int(texCoord.x * 128.0) ) / 128.0; + texCoord.y = float( int(texCoord.y * 128.0) ) / 128.0; + + float texX = texCoord.x / 3.0 + 0.66; + float texY = 0.34 - texCoord.y / 3.0; + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + basicColor.r = basicColor.g = basicColor.b = 0.0; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/fuzz_swirly.fp b/wadsrc/static/shaders_gles/glsl/fuzz_swirly.fp new file mode 100644 index 00000000000..266858999e7 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/fuzz_swirly.fp @@ -0,0 +1,18 @@ +//created by Evil Space Tomato + +vec4 ProcessTexel() +{ + vec2 texCoord = vTexCoord.st; + vec4 basicColor = getTexel(texCoord); + + float texX = sin(texCoord.x * 100.0 + timer*5.0); + float texY = cos(texCoord.x * 100.0 + timer*5.0); + float vX = (texX/texY)*21.0; + float vY = (texY/texX)*13.0; + float test = mod(timer*2.0+(vX + vY), 0.5); + + basicColor.a = basicColor.a * test; + basicColor.r = basicColor.g = basicColor.b = 0.0; + + return basicColor; +} diff --git a/wadsrc/static/shaders_gles/glsl/main.fp b/wadsrc/static/shaders_gles/glsl/main.fp new file mode 100644 index 00000000000..90429f8e061 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/main.fp @@ -0,0 +1,571 @@ + +varying vec4 vTexCoord; +varying vec4 vColor; +varying vec4 pixelpos; +varying vec3 glowdist; +varying vec3 gradientdist; +varying vec4 vWorldNormal; +varying vec4 vEyeNormal; + +#ifdef NO_CLIPDISTANCE_SUPPORT +varying vec4 ClipDistanceA; +varying vec4 ClipDistanceB; +#endif + + +struct Material +{ + vec4 Base; + vec4 Bright; + vec4 Glow; + vec3 Normal; + vec3 Specular; + float Glossiness; + float SpecularLevel; +}; + +vec4 Process(vec4 color); +vec4 ProcessTexel(); +Material ProcessMaterial(); // note that this is deprecated. Use SetupMaterial! +void SetupMaterial(inout Material mat); +vec4 ProcessLight(Material mat, vec4 color); +vec3 ProcessMaterialLight(Material material, vec3 color); +vec2 GetTexCoord(); + +// These get Or'ed into uTextureMode because it only uses its 3 lowermost bits. +//const int TEXF_Brightmap = 0x10000; +//const int TEXF_Detailmap = 0x20000; +//const int TEXF_Glowmap = 0x40000; + + +//=========================================================================== +// +// Color to grayscale +// +//=========================================================================== + +float grayscale(vec4 color) +{ + return dot(color.rgb, vec3(0.3, 0.56, 0.14)); +} + +//=========================================================================== +// +// Desaturate a color +// +//=========================================================================== + +vec4 dodesaturate(vec4 texel, float factor) +{ + if (factor != 0.0) + { + float gray = grayscale(texel); + return mix (texel, vec4(gray,gray,gray,texel.a), factor); + } + else + { + return texel; + } +} + +//=========================================================================== +// +// Desaturate a color +// +//=========================================================================== + +vec4 desaturate(vec4 texel) +{ +#if (DEF_DO_DESATURATE == 1) + return dodesaturate(texel, uDesaturationFactor); +#else + return texel; +#endif +} + +//=========================================================================== +// +// Texture tinting code originally from JFDuke but with a few more options +// +//=========================================================================== + +const int Tex_Blend_Alpha = 1; +const int Tex_Blend_Screen = 2; +const int Tex_Blend_Overlay = 3; +const int Tex_Blend_Hardlight = 4; + + vec4 ApplyTextureManipulation(vec4 texel) + { + // Step 1: desaturate according to the material's desaturation factor. + texel = dodesaturate(texel, uTextureModulateColor.a); + + // Step 2: Invert if requested // TODO FIX + //if ((blendflags & 8) != 0) + //{ + // texel.rgb = vec3(1.0 - texel.r, 1.0 - texel.g, 1.0 - texel.b); + //} + + // Step 3: Apply additive color + texel.rgb += uTextureAddColor.rgb; + + // Step 4: Colorization, including gradient if set. + texel.rgb *= uTextureModulateColor.rgb; + + // Before applying the blend the value needs to be clamped to [0..1] range. + texel.rgb = clamp(texel.rgb, 0.0, 1.0); + + // Step 5: Apply a blend. This may just be a translucent overlay or one of the blend modes present in current Build engines. +#if (DEF_BLEND_FLAGS != 0) + + vec3 tcol = texel.rgb * 255.0; // * 255.0 to make it easier to reuse the integer math. + vec4 tint = uTextureBlendColor * 255.0; + +#if (DEF_BLEND_FLAGS == 1) + + tcol.b = tcol.b * (1.0 - uTextureBlendColor.a) + tint.b * uTextureBlendColor.a; + tcol.g = tcol.g * (1.0 - uTextureBlendColor.a) + tint.g * uTextureBlendColor.a; + tcol.r = tcol.r * (1.0 - uTextureBlendColor.a) + tint.r * uTextureBlendColor.a; + +#elif (DEF_BLEND_FLAGS == 2) // Tex_Blend_Screen: + tcol.b = 255.0 - (((255.0 - tcol.b) * (255.0 - tint.r)) / 256.0); + tcol.g = 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 256.0); + tcol.r = 255.0 - (((255.0 - tcol.r) * (255.0 - tint.b)) / 256.0); + +#elif (DEF_BLEND_FLAGS == 3) // Tex_Blend_Overlay: + + tcol.b = tcol.b < 128.0? (tcol.b * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.b)) / 128.0); + tcol.g = tcol.g < 128.0? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0); + tcol.r = tcol.r < 128.0? (tcol.r * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.r)) / 128.0); + +#elif (DEF_BLEND_FLAGS == 4) // Tex_Blend_Hardlight: + + tcol.b = tint.b < 128.0 ? (tcol.b * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.b)) / 128.0); + tcol.g = tint.g < 128.0 ? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0); + tcol.r = tint.r < 128.0 ? (tcol.r * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.r)) / 128.0); + +#endif + + texel.rgb = tcol / 255.0; + +#endif + + return texel; +} + +//=========================================================================== +// +// This function is common for all (non-special-effect) fragment shaders +// +//=========================================================================== + +vec4 getTexel(vec2 st) +{ + vec4 texel = texture2D(tex, st); + +#if (DEF_TEXTURE_MODE == 1) + + texel.rgb = vec3(1.0,1.0,1.0); + +#elif (DEF_TEXTURE_MODE == 2)// TM_OPAQUE + + texel.a = 1.0; + +#elif (DEF_TEXTURE_MODE == 3)// TM_INVERSE + + texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, texel.a); + +#elif (DEF_TEXTURE_MODE == 4)// TM_ALPHATEXTURE + + float gray = grayscale(texel); + texel = vec4(1.0, 1.0, 1.0, gray*texel.a); + +#elif (DEF_TEXTURE_MODE == 5)// TM_CLAMPY + + if (st.t < 0.0 || st.t > 1.0) + { + texel.a = 0.0; + } + +#elif (DEF_TEXTURE_MODE == 6)// TM_OPAQUEINVERSE + + texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, 1.0); + + +#elif (DEF_TEXTURE_MODE == 7)//TM_FOGLAYER + + return texel; + +#endif + + // Apply the texture modification colors. +#if (DEF_BLEND_FLAGS != 0) + + // only apply the texture manipulation if it contains something. + texel = ApplyTextureManipulation(texel); + +#endif + + // Apply the Doom64 style material colors on top of everything from the texture modification settings. + // This may be a bit redundant in terms of features but the data comes from different sources so this is unavoidable. + + texel.rgb += uAddColor.rgb; + +#if (DEF_USE_OBJECT_COLOR_2 == 1) + texel *= mix(uObjectColor, uObjectColor2, gradientdist.z); +#else + texel *= uObjectColor; +#endif + + // Last but not least apply the desaturation from the sector's light. + return desaturate(texel); +} + + + + +//=========================================================================== +// +// Doom software lighting equation +// +//=========================================================================== + +#define DOOMLIGHTFACTOR 232.0 + +float R_DoomLightingEquation_OLD(float light) +{ + // z is the depth in view space, positive going into the screen + float z = pixelpos.w; + + + /* L in the range 0 to 63 */ + float L = light * 63.0/31.0; + + float min_L = clamp(36.0/31.0 - L, 0.0, 1.0); + + // Fix objects getting totally black when close. + if (z < 0.0001) + z = 0.0001; + + float scale = 1.0 / z; + float index = (59.0/31.0 - L) - (scale * DOOMLIGHTFACTOR/31.0 - DOOMLIGHTFACTOR/31.0); + + // Result is the normalized colormap index (0 bright .. 1 dark) + return clamp(index, min_L, 1.0) / 32.0; +} + + +//=========================================================================== +// +// zdoom colormap equation +// +//=========================================================================== +float R_ZDoomColormap(float light, float z) +{ + float L = light * 255.0; + float vis = min(uGlobVis / z, 24.0 / 32.0); + float shade = 2.0 - (L + 12.0) / 128.0; + float lightscale = shade - vis; + return lightscale * 31.0; +} + +//=========================================================================== +// +// Doom software lighting equation +// +//=========================================================================== +float R_DoomLightingEquation(float light) +{ + // z is the depth in view space, positive going into the screen + float z; + +#if (DEF_FOG_RADIAL == 1) + z = distance(pixelpos.xyz, uCameraPos.xyz); +#else + z = pixelpos.w; +#endif + +#if (DEF_BUILD_LIGHTING == 1) // gl_lightmode 5: Build software lighting emulation. + // This is a lot more primitive than Doom's lighting... + float numShades = float(uPalLightLevels); + float curshade = (1.0 - light) * (numShades - 1.0); + float visibility = max(uGlobVis * uLightFactor * abs(z), 0.0); + float shade = clamp((curshade + visibility), 0.0, numShades - 1.0); + return clamp(shade * uLightDist, 0.0, 1.0); +#endif + + float colormap = R_ZDoomColormap(light, z); // ONLY Software mode, vanilla not yet working + +#if (DEF_BANDED_SW_LIGHTING == 1) + colormap = floor(colormap) + 0.5; +#endif + + // Result is the normalized colormap index (0 bright .. 1 dark) + return clamp(colormap, 0.0, 31.0) / 32.0; +} + + +float shadowAttenuation(vec4 lightpos, float lightcolorA) +{ + return 1.0; +} + + +float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle) +{ + vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); + float cosDir = dot(lightDirection, spotdir); + return smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir); +} + +vec3 ApplyNormalMap(vec2 texcoord) +{ + return normalize(vWorldNormal.xyz); +} + +//=========================================================================== +// +// Sets the common material properties. +// +//=========================================================================== + +void SetMaterialProps(inout Material material, vec2 texCoord) +{ + +#ifdef NPOT_EMULATION + +#if (DEF_NPOT_EMULATION == 1) + float period = floor(texCoord.t / uNpotEmulation.y); + texCoord.s += uNpotEmulation.x * floor(mod(texCoord.t, uNpotEmulation.y)); + texCoord.t = period + mod(texCoord.t, uNpotEmulation.y); +#endif + +#endif + + material.Base = getTexel(texCoord.st); + material.Normal = ApplyNormalMap(texCoord.st); + + #if (DEF_TEXTURE_FLAGS & 0x1) + material.Bright = texture2D(brighttexture, texCoord.st); + #endif + + #if (DEF_TEXTURE_FLAGS & 0x2) + { + vec4 Detail = texture2D(detailtexture, texCoord.st * uDetailParms.xy) * uDetailParms.z; + material.Base *= Detail; + } + #endif + + #if (DEF_TEXTURE_FLAGS & 0x4) + { + material.Glow = texture2D(glowtexture, texCoord.st); + } + #endif + +} + +//=========================================================================== +// +// Calculate light +// +// It is important to note that the light color is not desaturated +// due to ZDoom's implementation weirdness. Everything that's added +// on top of it, e.g. dynamic lights and glows are, though, because +// the objects emitting these lights are also. +// +// This is making this a bit more complicated than it needs to +// because we can't just desaturate the final fragment color. +// +//=========================================================================== + +vec4 getLightColor(Material material, float fogdist, float fogfactor) +{ + vec4 color = vColor; + +#if (DEF_USE_U_LIGHT_LEVEL == 1) + { + float newlightlevel = 1.0 - R_DoomLightingEquation(uLightLevel); + color.rgb *= newlightlevel; + } +#else + { + + #if (DEF_FOG_ENABLED == 1) && (DEF_FOG_COLOURED == 0) + { + // brightening around the player for light mode 2 + if (fogdist < uLightDist) + { + color.rgb *= uLightFactor - (fogdist / uLightDist) * (uLightFactor - 1.0); + } + + // + // apply light diminishing through fog equation + // + color.rgb = mix(vec3(0.0, 0.0, 0.0), color.rgb, fogfactor); + } + #endif + } +#endif + + + // + // handle glowing walls + // +#if (DEF_USE_GLOW_TOP_COLOR) + if (glowdist.x < uGlowTopColor.a) + { + color.rgb += desaturate(uGlowTopColor * (1.0 - glowdist.x / uGlowTopColor.a)).rgb; + } +#endif + + +#if (DEF_USE_GLOW_BOTTOM_COLOR) + if (glowdist.y < uGlowBottomColor.a) + { + color.rgb += desaturate(uGlowBottomColor * (1.0 - glowdist.y / uGlowBottomColor.a)).rgb; + } +#endif + + color = min(color, 1.0); + + // these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set. +#ifndef LEGACY_USER_SHADER + // + // apply glow + // + color.rgb = mix(color.rgb, material.Glow.rgb, material.Glow.a); + + // + // apply brightmaps + // + color.rgb = min(color.rgb + material.Bright.rgb, 1.0); +#endif + + // + // apply other light manipulation by custom shaders, default is a NOP. + // + color = ProcessLight(material, color); + + // + // apply dynamic lights + // + return vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a); +} + +//=========================================================================== +// +// Applies colored fog +// +//=========================================================================== + +vec4 applyFog(vec4 frag, float fogfactor) +{ + return vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a); +} + +//=========================================================================== +// +// Main shader routine +// +//=========================================================================== + +void main() +{ + + //if (ClipDistanceA.x < 0.0 || ClipDistanceA.y < 0.0 || ClipDistanceA.z < 0.0 || ClipDistanceA.w < 0.0 || ClipDistanceB.x < 0.0) discard; + +#ifndef LEGACY_USER_SHADER + Material material; + + material.Base = vec4(0.0); + material.Bright = vec4(0.0); + material.Glow = vec4(0.0); + material.Normal = vec3(0.0); + material.Specular = vec3(0.0); + material.Glossiness = 0.0; + material.SpecularLevel = 0.0; + SetupMaterial(material); +#else + Material material = ProcessMaterial(); +#endif + vec4 frag = material.Base; + +#ifndef NO_ALPHATEST + if (frag.a <= uAlphaThreshold) discard; +#endif + +#ifdef DITHERTRANS + int index = (int(pixelpos.x) % 2) * 2 + int(pixelpos.y) % 2; + if (index != 2) discard; +#endif + + #if (DEF_FOG_2D == 0) // check for special 2D 'fog' mode. + { + float fogdist = 0.0; + float fogfactor = 0.0; + + // + // calculate fog factor + // + #if (DEF_FOG_ENABLED == 1) + { + #if (DEF_FOG_RADIAL == 0) + fogdist = max(16.0, pixelpos.w); + #else + fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + #endif + + fogfactor = exp2 (uFogDensity * fogdist); + } + #endif + + #if (DEF_TEXTURE_MODE != 7) + { + frag = getLightColor(material, fogdist, fogfactor); + + // + // colored fog + // + #if (DEF_FOG_ENABLED == 1) && (DEF_FOG_COLOURED == 1) + { + frag = applyFog(frag, fogfactor); + } + #endif + } + #else + { + frag = vec4(uFogColor.rgb, (1.0 - fogfactor) * frag.a * 0.75 * vColor.a); + } + #endif + } + #else + { + #if (DEF_TEXTURE_MODE == 7) + { + float gray = grayscale(frag); + vec4 cm = (uObjectColor + gray * (uAddColor - uObjectColor)) * 2.0; + frag = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a); + } + #endif + + frag = frag * ProcessLight(material, vColor); + frag.rgb = frag.rgb + uFogColor.rgb; + } + #endif // (DEF_2D_FOG == 0) + +#if (DEF_USE_COLOR_MAP == 1) // This mostly works but doesn't look great because of the blending. + { + frag.rgb = clamp(pow(frag.rgb, vec3(uFixedColormapStart.a)), 0.0, 1.0); + if (uFixedColormapRange.a == 0.0) + { + float gray = (frag.r * 0.3 + frag.g * 0.56 + frag.b * 0.14); + vec4 cm = uFixedColormapStart + gray * uFixedColormapRange; + frag.rgb = clamp(cm.rgb, 0.0, 1.0); + } + } +#endif + + gl_FragColor = frag; + + //gl_FragColor = vec4(0.8, 0.2, 0.5, 1); + +} diff --git a/wadsrc/static/shaders_gles/glsl/main.vp b/wadsrc/static/shaders_gles/glsl/main.vp new file mode 100644 index 00000000000..efa1ff00871 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/main.vp @@ -0,0 +1,219 @@ + +attribute vec4 aPosition; +attribute vec2 aTexCoord; +attribute vec4 aColor; + +varying vec4 vTexCoord; +varying vec4 vColor; + +#ifndef SIMPLE // we do not need these for simple shaders +attribute vec4 aVertex2; +attribute vec4 aNormal; +attribute vec4 aNormal2; +#if __VERSION__ >= 300 +attribute vec4 aBoneWeight; +attribute uvec4 aBoneSelector; +#endif + +varying vec4 pixelpos; +varying vec3 glowdist; +varying vec3 gradientdist; +varying vec4 vWorldNormal; +varying vec4 vEyeNormal; +#endif + +#ifdef NO_CLIPDISTANCE_SUPPORT +varying vec4 ClipDistanceA; +varying vec4 ClipDistanceB; +#endif + +struct BonesResult +{ + vec3 Normal; + vec4 Position; +}; + +BonesResult ApplyBones(); + + +void main() +{ + float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4; + + vec2 parmTexCoord; + vec4 parmPosition; + + BonesResult bones = ApplyBones(); + + parmTexCoord = aTexCoord; + parmPosition = bones.Position; + + #ifndef SIMPLE + vec4 worldcoord = ModelMatrix * mix(parmPosition, aVertex2, uInterpolationFactor); + #else + vec4 worldcoord = ModelMatrix * parmPosition; + #endif + + vec4 eyeCoordPos = ViewMatrix * worldcoord; + + #ifdef HAS_UNIFORM_VERTEX_DATA + if ((useVertexData & 1) == 0) + vColor = uVertexColor; + else + vColor = aColor; + #else + vColor = aColor; + #endif + + #ifndef SIMPLE + pixelpos.xyz = worldcoord.xyz; + pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; + + if (uGlowTopColor.a > 0.0 || uGlowBottomColor.a > 0.0) + { + float topatpoint = (uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z; + float bottomatpoint = (uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z; + glowdist.x = topatpoint - worldcoord.y; + glowdist.y = worldcoord.y - bottomatpoint; + glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + } + + if (uObjectColor2.a != 0.0) + { + float topatpoint = (uGradientTopPlane.w + uGradientTopPlane.x * worldcoord.x + uGradientTopPlane.y * worldcoord.z) * uGradientTopPlane.z; + float bottomatpoint = (uGradientBottomPlane.w + uGradientBottomPlane.x * worldcoord.x + uGradientBottomPlane.y * worldcoord.z) * uGradientBottomPlane.z; + gradientdist.x = topatpoint - worldcoord.y; + gradientdist.y = worldcoord.y - bottomatpoint; + gradientdist.z = clamp(gradientdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + } + + if (uSplitBottomPlane.z != 0.0) + { + ClipDistance3 = ((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y; + ClipDistance4 = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); + } + + vWorldNormal = NormalModelMatrix * vec4(normalize(bones.Normal), 1.0); + + vEyeNormal = NormalViewMatrix * vWorldNormal; + #endif + + #ifdef SPHEREMAP + vec3 u = normalize(eyeCoordPos.xyz); + vec4 n = normalize(NormalViewMatrix * vec4(parmTexCoord.x, 0.0, parmTexCoord.y, 0.0)); + vec3 r = reflect(u, n.xyz); + float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); + vec2 sst = vec2(r.x/m + 0.5, r.y/m + 0.5); + vTexCoord.xy = sst; + #else + vTexCoord = TextureMatrix * vec4(parmTexCoord, 0.0, 1.0); + #endif + + + if (uClipHeightDirection != 0.0) // clip planes used for reflective flats + { + ClipDistance0 = (worldcoord.y - uClipHeight) * uClipHeightDirection; + } + else if (uClipLine.x > -1000000.0) // and for line portals - this will never be active at the same time as the reflective planes clipping so it can use the same hardware clip plane. + { + ClipDistance0 = -( (worldcoord.z - uClipLine.y) * uClipLine.z + (uClipLine.x - worldcoord.x) * uClipLine.w ) + 1.0/32768.0; // allow a tiny bit of imprecisions for colinear linedefs. + } + else + { + ClipDistance0 = 1.0; + } + + // clip planes used for translucency splitting + ClipDistance1 = worldcoord.y - uClipSplit.x; + ClipDistance2 = uClipSplit.y - worldcoord.y; + + if (uSplitTopPlane == vec4(0.0)) + { + ClipDistance3 = 1.0; + ClipDistance4 = 1.0; + } + + ClipDistanceA = vec4(ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3); + ClipDistanceB = vec4(ClipDistance4, 0.0, 0.0, 0.0); + + gl_Position = ProjectionMatrix * eyeCoordPos; +} + +#if !defined(SIMPLE) + +vec3 GetAttrNormal() +{ + #ifdef HAS_UNIFORM_VERTEX_DATA + if ((useVertexData & 2) == 0) + return uVertexNormal.xyz; + else + return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor); + #else + return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor); + #endif +} + +#if __VERSION__ >= 300 + +void AddWeightedBone(uint boneIndex, float weight, inout vec4 position, inout vec3 normal) +{ + if (weight != 0.0) + { + mat4 transform = bones[uBoneIndexBase + int(boneIndex)]; + mat3 rotation = mat3(transform); + position += (transform * aPosition) * weight; + normal += (rotation * aNormal.xyz) * weight; + } +} + +BonesResult ApplyBones() +{ + BonesResult result; + if (uBoneIndexBase >= 0 && aBoneWeight != vec4(0.0)) + { + result.Position = vec4(0.0); + result.Normal = vec3(0.0); + + // We use low precision input for our bone weights. Rescale so the sum still is 1.0 + float totalWeight = aBoneWeight.x + aBoneWeight.y + aBoneWeight.z + aBoneWeight.w; + float weightMultiplier = 1.0 / totalWeight; + vec4 boneWeight = aBoneWeight * weightMultiplier; + + AddWeightedBone(aBoneSelector.x, boneWeight.x, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.y, boneWeight.y, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.z, boneWeight.z, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.w, boneWeight.w, result.Position, result.Normal); + + result.Position.w = 1.0; // For numerical stability + } + else + { + result.Position = aPosition; + result.Normal = GetAttrNormal(); + } + return result; +} + +#else + +BonesResult ApplyBones() +{ + BonesResult result; + + result.Position = aPosition; + result.Normal = GetAttrNormal(); + + return result; +} +#endif + +#else // SIMPLE + +BonesResult ApplyBones() +{ + BonesResult result; + result.Position = aPosition; + return result; +} + +#endif diff --git a/wadsrc/static/shaders_gles/glsl/material_nolight.fp b/wadsrc/static/shaders_gles/glsl/material_nolight.fp new file mode 100644 index 00000000000..b714044232f --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/material_nolight.fp @@ -0,0 +1,5 @@ + +vec3 ProcessMaterialLight(Material material, vec3 color) +{ + return material.Base.rgb * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4); +} diff --git a/wadsrc/static/shaders_gles/glsl/material_normal.fp b/wadsrc/static/shaders_gles/glsl/material_normal.fp new file mode 100644 index 00000000000..0fceef675a5 --- /dev/null +++ b/wadsrc/static/shaders_gles/glsl/material_normal.fp @@ -0,0 +1,118 @@ + +vec3 lightContribution(int i, vec3 normal) +{ + vec4 lightpos = lights[i]; + vec4 lightcolor = lights[i+1]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + + //if (lightpos.w < lightdistance) + // return vec3(0.0); // Early out lights touching surface but not this fragment + + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + float dotprod = dot(normal, lightdir); + + if (dotprod < -0.0001) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. Note that this can cause precision issues. + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + +#if (DEF_HAS_SPOTLIGHT == 1) // Only perform test below if there are ANY spot lights on this surface. + + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + +#endif + + if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag + { + attenuation *= clamp(dotprod, 0.0, 1.0); + } + return lightcolor.rgb * attenuation; +} + + +vec3 ProcessMaterialLight(Material material, vec3 color) +{ + vec4 dynlight = uDynLightColor; + vec3 normal = material.Normal; + +#if (DEF_DYNAMIC_LIGHTS_MOD == 1) + // modulated lights + + // Some very old GLES2 hardware does not allow non-constants in a for-loop expression because it can not unroll it. + // However they do allow 'break', so use stupid hack + #if (USE_GLSL_V100 == 1) + + for(int i = 0; i < 8; i++) // Max 8 lights + { + if(i == ((uLightRange.y - uLightRange.x) / 4)) + break; + + dynlight.rgb += lightContribution(i * 4, normal); + } + + #else + + for(int i=uLightRange.x; i> (int type, int tag) case 228: if (CheckInventory ("QuestItem24")) { + int logNum = 128; if (CheckInventory ("QuestItem28")) { - LocalAmbientSound ("svox/voc130", 127); - } - else - { - LocalAmbientSound ("svox/voc128", 127); + logNum = 130; } + str soundToPlay = StrParam(s: "svox/voc", d: logNum); + LocalAmbientSound(soundToPlay, 127); + SetSubtitleNumber(logNum, soundToPlay); clearlinespecial (); } break; diff --git a/wadsrc/static/textcolors.txt b/wadsrc/static/textcolors.txt index d8e40182e37..a03281b96b6 100644 --- a/wadsrc/static/textcolors.txt +++ b/wadsrc/static/textcolors.txt @@ -140,8 +140,8 @@ Flat: Cream { - #6B4727 #BF7B4B 0 94 - #BF7B4B #FFBF9B 95 256 + #18120a #BF7B4B 0 128 + #BF7B4B #FFBF9B 129 256 Console: #2B230F #BF7B4B 0 127 #FFB383 #FFFFFF 128 256 diff --git a/wadsrc/static/vga-rom-font.16 b/wadsrc/static/vga-rom-font.16 deleted file mode 100644 index 672d0e1a999..00000000000 Binary files a/wadsrc/static/vga-rom-font.16 and /dev/null differ diff --git a/wadsrc/static/widgets/banner.png b/wadsrc/static/widgets/banner.png new file mode 100644 index 00000000000..96ac9a0931e Binary files /dev/null and b/wadsrc/static/widgets/banner.png differ diff --git a/wadsrc/static/widgets/noto/NotoSans-Regular.ttf b/wadsrc/static/widgets/noto/NotoSans-Regular.ttf new file mode 100644 index 00000000000..fa4cff505eb Binary files /dev/null and b/wadsrc/static/widgets/noto/NotoSans-Regular.ttf differ diff --git a/wadsrc/static/widgets/noto/NotoSansArmenian-Regular.ttf b/wadsrc/static/widgets/noto/NotoSansArmenian-Regular.ttf new file mode 100644 index 00000000000..097432059b4 Binary files /dev/null and b/wadsrc/static/widgets/noto/NotoSansArmenian-Regular.ttf differ diff --git a/wadsrc/static/widgets/noto/NotoSansGeorgian-Regular.ttf b/wadsrc/static/widgets/noto/NotoSansGeorgian-Regular.ttf new file mode 100644 index 00000000000..49163cc37e2 Binary files /dev/null and b/wadsrc/static/widgets/noto/NotoSansGeorgian-Regular.ttf differ diff --git a/wadsrc/static/widgets/noto/OFL.txt b/wadsrc/static/widgets/noto/OFL.txt new file mode 100644 index 00000000000..76df3b56567 --- /dev/null +++ b/wadsrc/static/widgets/noto/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/wadsrc/static/xg.wopn b/wadsrc/static/xg.wopn index c5d63367ef4..b5290c54250 100644 Binary files a/wadsrc/static/xg.wopn and b/wadsrc/static/xg.wopn differ diff --git a/wadsrc/static/xlat/base.txt b/wadsrc/static/xlat/base.txt index 0fc02739efb..a53119b9ea8 100644 --- a/wadsrc/static/xlat/base.txt +++ b/wadsrc/static/xlat/base.txt @@ -375,6 +375,11 @@ include "xlat/defines.i" 438 = SHOOT, Floor_RaiseByValue (tag, F_SLOW, 2) 439 = SHOOT|REP, Floor_RaiseByValue (tag, F_SLOW, 2) +// MBF21 extensions +1024 = 0, Scroll_Texture_Offsets(0, tag, 0, 8) +1025 = 0, Scroll_Texture_Offsets(0, tag, 1, 8) +1026 = 0, Scroll_Texture_Offsets(0, tag, 2, 8) + /****** BOOM generalized linetypes ****** * * The general structure for a BOOM generalized translator is @@ -416,7 +421,7 @@ include "xlat/defines.i" // Generalized crusher (tag, dnspeed, upspeed, silent, damage) -[Generic_Crusher] (0x2f80, 0x2fff) +[Generic_CrusherDist] (0x2f80, 0x2fff) { flags |= 0x0020 [0x0020 : MONST] arg2 = 0x0018 [0x0000 : C_SLOW, diff --git a/wadsrc/static/xlat/defines.i b/wadsrc/static/xlat/defines.i index 0b0999478f7..0259803823a 100644 --- a/wadsrc/static/xlat/defines.i +++ b/wadsrc/static/xlat/defines.i @@ -236,6 +236,7 @@ enum ML_FIRSTSIDEONLY = 0x00800000, ML_BLOCKPROJECTILE = 0x01000000, ML_BLOCKUSE = 0x02000000, + ML_BLOCKLANDMONSTERS = 0x80000001, // goes into the second flag word. // ML_PASSTHROUGH = -1, diff --git a/wadsrc/static/xlat/doom.txt b/wadsrc/static/xlat/doom.txt index 14ecdd7d0d5..7915f08332b 100644 --- a/wadsrc/static/xlat/doom.txt +++ b/wadsrc/static/xlat/doom.txt @@ -1,8 +1,8 @@ include "xlat/base.txt" -sector bitmask 0xf000 clear; -sector bitmask 0xfe0 <<= 3; +sector bitmask 0xc000 clear; +sector bitmask 0x3fe0 <<= 3; sector 1 = dLight_Flicker; sector 2 = dLight_StrobeFast; @@ -40,3 +40,5 @@ lineflag 8 = ML_MAPPED; lineflag 9 = ML_PASSTHROUGH; lineflag 10 = ML_3DMIDTEX; lineflag 11 & (ML_BLOCKING|ML_BLOCKMONSTERS|ML_TWOSIDED|ML_DONTPEGTOP|ML_DONTPEGBOTTOM|ML_SECRET|ML_SOUNDBLOCK|ML_DONTDRAW|ML_MAPPED); +lineflag 12 = ML_BLOCKLANDMONSTERS; +lineflag 13 = ML_BLOCK_PLAYERS; diff --git a/wadsrc/static/xlat/strife.txt b/wadsrc/static/xlat/strife.txt index e4ae8244f10..8b1e2506673 100644 --- a/wadsrc/static/xlat/strife.txt +++ b/wadsrc/static/xlat/strife.txt @@ -321,7 +321,7 @@ RetailOnly = 121 207 = USE|REP, Door_Animated (tag, 4, 3*35) 214 = USE|REP, Plat_DownWaitUpStayLip (tag, 8, 1050, 0, 1) 229 = USE|REP, ACS_ExecuteWithResult (0, 229, tag) -233 = USE|REP, ACS_ExecuteWithResult (0, 233, tag) +233 = USE, ACS_ExecuteWithResult (0, 233, tag) 234 = USE|REP, ACS_ExecuteWithResult (0, 234, tag) sector bitmask 0xf000 clear; diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index cfd2ff16667..e671b4480ad 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -1,14 +1,48 @@ -version "4.3" -#include "zscript/base.zs" +version "4.12" + +// Generic engine code +#include "zscript/engine/base.zs" +#include "zscript/engine/dynarrays.zs" +#include "zscript/engine/maps.zs" +#include "zscript/engine/dictionary.zs" +#include "zscript/engine/inputevents.zs" +#include "zscript/engine/service.zs" +#include "zscript/engine/ppshader.zs" +#include "zscript/engine/screenjob.zs" + +#include "zscript/engine/ui/menu/colorpickermenu.zs" +#include "zscript/engine/ui/menu/joystickmenu.zs" +#include "zscript/engine/ui/menu/listmenu.zs" +#include "zscript/engine/ui/menu/listmenuitems.zs" +#include "zscript/engine/ui/menu/loadsavemenu.zs" +#include "zscript/engine/ui/menu/menu.zs" +#include "zscript/engine/ui/menu/menucustomize.zs" +#include "zscript/engine/ui/menu/menuitembase.zs" +#include "zscript/engine/ui/menu/messagebox.zs" +#include "zscript/engine/ui/menu/custommessagebox.zs" +#include "zscript/engine/ui/menu/optionmenu.zs" +#include "zscript/engine/ui/menu/optionmenuitems.zs" +#include "zscript/engine/ui/menu/reverbedit.zs" +#include "zscript/engine/ui/menu/textentermenu.zs" +#include "zscript/engine/ui/menu/imagescroller.zs" + +#include "zscript/engine/ui/menu/search/menu.zs" +#include "zscript/engine/ui/menu/search/searchfield.zs" +#include "zscript/engine/ui/menu/search/query.zs" +#include "zscript/engine/ui/menu/search/anyoralloption.zs" + +#include "zscript/engine/ui/statusbar/statusbarcore.zs" + +// GZDoom exclusive. +#include "zscript/doombase.zs" #include "zscript/sounddata.zs" #include "zscript/mapdata.zs" -#include "zscript/dynarrays.zs" #include "zscript/constants.zs" #include "zscript/events.zs" #include "zscript/destructible.zs" #include "zscript/level_postprocessor.zs" #include "zscript/level_compatibility.zs" -#include "zscript/dictionary.zs" +#include "zscript/visualthinker.zs" #include "zscript/actors/actor.zs" #include "zscript/actors/checks.zs" @@ -61,6 +95,7 @@ version "4.3" #include "zscript/actors/shared/fastprojectile.zs" #include "zscript/actors/shared/randomspawner.zs" #include "zscript/actors/shared/dynlights.zs" +#include "zscript/actors/shared/corona.zs" #include "zscript/actors/doom/doomplayer.zs" #include "zscript/actors/doom/possessed.zs" @@ -238,29 +273,13 @@ version "4.3" #include "zscript/actors/chex/chexdecorations.zs" #include "zscript/actors/chex/chexplayer.zs" -#include "zscript/ui/menu/colorpickermenu.zs" #include "zscript/ui/menu/conversationmenu.zs" -#include "zscript/ui/menu/joystickmenu.zs" -#include "zscript/ui/menu/listmenu.zs" -#include "zscript/ui/menu/listmenuitems.zs" -#include "zscript/ui/menu/loadsavemenu.zs" -#include "zscript/ui/menu/menu.zs" -#include "zscript/ui/menu/menuitembase.zs" -#include "zscript/ui/menu/messagebox.zs" -#include "zscript/ui/menu/optionmenu.zs" -#include "zscript/ui/menu/optionmenuitems.zs" +#include "zscript/ui/menu/doommenus.zs" #include "zscript/ui/menu/newplayermenu.zs" #include "zscript/ui/menu/playercontrols.zs" #include "zscript/ui/menu/playerdisplay.zs" #include "zscript/ui/menu/playermenu.zs" #include "zscript/ui/menu/readthis.zs" -#include "zscript/ui/menu/reverbedit.zs" -#include "zscript/ui/menu/textentermenu.zs" - -#include "zscript/ui/menu/search/menu.zs" -#include "zscript/ui/menu/search/searchfield.zs" -#include "zscript/ui/menu/search/query.zs" -#include "zscript/ui/menu/search/anyoralloption.zs" #include "zscript/ui/statscreen/statscreen.zs" #include "zscript/ui/statscreen/statscreen_coop.zs" @@ -276,5 +295,8 @@ version "4.3" #include "zscript/ui/statusbar/statusbar.zs" #include "zscript/ui/statusbar/strife_sbar.zs" +#include "zscript/ui/intermission.zs" + #include "zscript/compatibility.zs" #include "zscript/scriptutil/scriptutil.zs" +#include "zscript/actors/mbf21.zs" diff --git a/wadsrc/static/zscript/actors/actions.zs b/wadsrc/static/zscript/actors/actions.zs index 8e27a46d20b..69a6542ebe1 100644 --- a/wadsrc/static/zscript/actors/actions.zs +++ b/wadsrc/static/zscript/actors/actions.zs @@ -95,4 +95,9 @@ extend class Actor } } + void A_SpriteOffset(double ox = 0.0, double oy = 0.0) + { + SpriteOffset.X = ox; + SpriteOffset.Y = oy; + } } diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index a0f5a9ca358..584b466aff0 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -67,12 +67,19 @@ struct LinkContext voidptr render_list; } +class ViewPosition native +{ + native readonly Vector3 Offset; + native readonly int Flags; +} + class Actor : Thinker native { const DEFAULT_HEALTH = 1000; const ONFLOORZ = -2147483648.0; const ONCEILINGZ = 2147483647.0; + const STEEPSLOPE = (46342./65536.); // [RH] Minimum floorplane.c value for walking const FLOATRANDZ = ONCEILINGZ-1; const TELEFRAG_DAMAGE = 1000000; const MinVel = 1./65536; @@ -80,21 +87,25 @@ class Actor : Thinker native const ORIG_FRICTION = (0xE800/65536.); // original value const ORIG_FRICTION_FACTOR = (2048/65536.); // original value const DEFMORPHTICS = 40 * TICRATE; - + const MELEEDELTA = 20; // flags are not defined here, the native fields for those get synthesized from the internal tables. // for some comments on these fields, see their native representations in actor.h. native readonly Actor snext; // next in sector list. native PlayerInfo Player; + native readonly ViewPosition ViewPos; // Will be null until A_SetViewPos() is called for the first time. native readonly vector3 Pos; native vector3 Prev; + native uint ThruBits; + native vector2 SpriteOffset; + native vector3 WorldOffset; native double spriteAngle; native double spriteRotation; - native double VisibleStartAngle; - native double VisibleStartPitch; - native double VisibleEndAngle; - native double VisibleEndPitch; + native float VisibleStartAngle; + native float VisibleStartPitch; + native float VisibleEndAngle; + native float VisibleEndPitch; native double Angle; native double Pitch; native double Roll; @@ -148,13 +159,14 @@ class Actor : Thinker native native int StartHealth; native uint8 WeaveIndexXY; native uint8 WeaveIndexZ; - native int skillrespawncount; + native uint16 skillrespawncount; native int Args[5]; native int Mass; native int Special; native readonly int TID; native readonly int TIDtoHate; native readonly int WaterLevel; + native readonly double WaterDepth; native int Score; native int Accuracy; native int Stamina; @@ -189,6 +201,7 @@ class Actor : Thinker native native int DesignatedTeam; native Actor BlockingMobj; native Line BlockingLine; + native Line MovementBlockingLine; native Sector Blocking3DFloor; native Sector BlockingCeiling; native Sector BlockingFloor; @@ -204,7 +217,7 @@ class Actor : Thinker native native Inventory Inv; native uint8 smokecounter; native uint8 FriendPlayer; - native uint Translation; + native TranslationID Translation; native sound AttackSound; native sound DeathSound; native sound SeeSound; @@ -216,6 +229,7 @@ class Actor : Thinker native native sound CrushPainSound; native double MaxDropoffHeight; native double MaxStepHeight; + native double MaxSlopeSteepness; native int16 PainChance; native name PainType; native name DeathType; @@ -231,17 +245,23 @@ class Actor : Thinker native native uint8 fountaincolor; native double CameraHeight; // Height of camera when used as such native double CameraFOV; + native double ViewAngle, ViewPitch, ViewRoll; native double RadiusDamageFactor; // Radius damage factor native double SelfDamageFactor; + native double ShadowAimFactor, ShadowPenaltyFactor; native double StealthAlpha; native int WoundHealth; // Health needed to enter wound state native readonly color BloodColor; - native readonly int BloodTranslation; + native readonly TranslationID BloodTranslation; native int RenderHidden; native int RenderRequired; - native readonly int FriendlySeeBlocks; + native int FriendlySeeBlocks; + native int16 lightlevel; native readonly int SpawnTime; private native int InventoryID; // internal counter. + native uint freezetics; + native Vector2 AutomapOffsets; + native double LandingSpeed; meta String Obituary; // Player was killed by this actor meta String HitObituary; // Player was killed by this actor in melee @@ -253,13 +273,20 @@ class Actor : Thinker native meta Name BloodType2; // Bloopsplatter replacement type meta Name BloodType3; // AxeBlood replacement type meta bool DontHurtShooter; - meta int ExplosionRadius; + meta double ExplosionRadius; meta int ExplosionDamage; meta int MeleeDamage; meta Sound MeleeSound; + meta Sound RipSound; meta double MissileHeight; meta Name MissileName; meta double FastSpeed; // speed in fast mode + meta Sound PushSound; // Sound being played when pushed by something + + // todo: implement access to native meta properties. + // native meta int infighting_group; + // native meta int projectile_group; + // native meta int splash_group; Property prefix: none; Property Obituary: Obituary; @@ -300,6 +327,7 @@ class Actor : Thinker native property DeathSound: DeathSound; property ActiveSound: ActiveSound; property CrushPainSound: CrushPainSound; + property PushSound: PushSound; property Alpha: Alpha; property MaxTargetRange: MaxTargetRange; property MeleeThreshold: MeleeThreshold; @@ -311,6 +339,7 @@ class Actor : Thinker native property MinMissileChance: MinMissileChance; property MaxStepHeight: MaxStepHeight; property MaxDropoffHeight: MaxDropoffHeight; + property MaxSlopeSteepness: MaxSlopeSteepness; property PoisonDamageType: PoisonDamageType; property RadiusDamageFactor: RadiusDamageFactor; property SelfDamageFactor: SelfDamageFactor; @@ -329,9 +358,16 @@ class Actor : Thinker native property Ripperlevel: RipperLevel; property RipLevelMin: RipLevelMin; property RipLevelMax: RipLevelMax; + property RipSound: RipSound; property RenderHidden: RenderHidden; property RenderRequired: RenderRequired; property FriendlySeeBlocks: FriendlySeeBlocks; + property ThruBits: ThruBits; + property LightLevel: LightLevel; + property ShadowAimFactor: ShadowAimFactor; + property ShadowPenaltyFactor: ShadowPenaltyFactor; + property AutomapOffsets : AutomapOffsets; + property LandingSpeed: LandingSpeed; // need some definition work first //FRenderStyle RenderStyle; @@ -356,6 +392,7 @@ class Actor : Thinker native Default { + LightLevel -1; Scale 1; Health DEFAULT_HEALTH; Reactiontime 8; @@ -366,9 +403,10 @@ class Actor : Thinker native RenderStyle 'Normal'; Alpha 1; MinMissileChance 200; - MeleeRange 64 - 20; + MeleeRange 64 - MELEEDELTA; MaxDropoffHeight 24; MaxStepHeight 24; + MaxSlopeSteepness STEEPSLOPE; BounceFactor 0.7; WallBounceFactor 0.75; BounceCount -1; @@ -390,10 +428,11 @@ class Actor : Thinker native RipperLevel 0; RipLevelMin 0; RipLevelMax 0; + RipSound "misc/ripslop"; DefThreshold 100; BloodType "Blood", "BloodSplatter", "AxeBlood"; ExplosionDamage 128; - ExplosionRadius -1; // i.e. use ExplosionDamage value + ExplosionRadius -1.0; // i.e. use ExplosionDamage value MissileHeight 32; SpriteAngle 0; SpriteRotation 0; @@ -406,6 +445,9 @@ class Actor : Thinker native FastSpeed -1; RadiusDamageFactor 1; SelfDamageFactor 1; + ShadowAimFactor 1; + ShadowPenaltyFactor 1; + AutomapOffsets (0,0); StealthAlpha 0; WoundHealth 6; GibHealth int.min; @@ -414,6 +456,7 @@ class Actor : Thinker native RenderHidden 0; RenderRequired 0; FriendlySeeBlocks 10; // 10 (blocks) * 128 (one map unit block) + LandingSpeed -8; // landing speed from a jump with normal gravity (squats the player's view) } // Functions @@ -438,6 +481,7 @@ class Actor : Thinker native MarkSound(CrushPainSound); MarkSound(HowlSound); MarkSound(MeleeSound); + MarkSound(PushSound); } bool IsPointerEqual(int ptr_select1, int ptr_select2) @@ -450,7 +494,7 @@ class Actor : Thinker native return sin(fb * (180./32)) * 8; } - native bool isFrozen(); + native clearscope bool isFrozen() const; virtual native void BeginPlay(); virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); @@ -458,9 +502,17 @@ class Actor : Thinker native virtual native int TakeSpecialDamage (Actor inflictor, Actor source, int damage, Name damagetype); virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0, Name MeansOfDeath = 'none'); virtual native bool Slam(Actor victim); - virtual native void Touch(Actor toucher); - native void Substitute(Actor replacement); + virtual void Touch(Actor toucher) {} + virtual native void FallAndSink(double grav, double oldfloorz); + native bool MorphInto(Actor morph); native ui void DisplayNameTag(); + native clearscope void DisableLocalRendering(uint playerNum, bool disable); + native ui bool ShouldRenderLocally(); // Only clients get to check this, never the playsim. + + // Called when the Actor is being used within a PSprite. This happens before potentially changing PSprite + // state so that any custom actions based on things like player input can be done before moving to the next + // state of something like a weapon. + virtual void PSpriteTick(PSprite psp) {} // Called by inventory items to see if this actor is capable of touching them. // If true, the item will attempt to be picked up. Useful for things like @@ -471,12 +523,37 @@ class Actor : Thinker native return true; } + // [AA] Called by inventory items in CallTryPickup to see if this actor needs + // to process them in some way before they're received. Gets called before + // the item's TryPickup, allowing fully customized handling of all items. + virtual bool CanReceive(Inventory item) + { + return true; + } + + // [AA] Called by inventory items at the end of CallTryPickup to let actors + // do something with the items they've received. 'Item' might be null for + // items that disappear on pickup. + // 'itemcls' is passed unconditionally, so it can still be read even if + // 'item' is null due to being destroyed with GoAwayAndDie() on pickup. + virtual void HasReceived(Inventory item, class itemcls = null) {} + + // Called in TryMove if the mover ran into another Actor. This isn't called on players + // if they're currently predicting. Guarantees collisions unlike CanCollideWith. + virtual void CollidedWith(Actor other, bool passive) {} + // Called by PIT_CheckThing to check if two actors actually can collide. virtual bool CanCollideWith(Actor other, bool passive) { return true; } + // Called by PIT_CheckLine to check if an actor can cross a line. + virtual bool CanCrossLine(Line crossing, Vector3 next) + { + return true; + } + // Called by revival/resurrection to check if one can resurrect the other. // "other" can be null when not passive. virtual bool CanResurrect(Actor other, bool passive) @@ -494,7 +571,13 @@ class Actor : Thinker native // This is called before a missile gets exploded. virtual int SpecialMissileHit (Actor victim) { - return -1; + return MHIT_DEFAULT; + } + + // This is called when a missile bounces off something. + virtual int SpecialBounceHit(Actor bounceMobj, Line bounceLine, readonly bouncePlane) + { + return MHIT_DEFAULT; } // Called when the player presses 'use' and an actor is found, except if the @@ -586,14 +669,19 @@ class Actor : Thinker native // called on getting a secret, return false to disable default "secret found" message/sound virtual bool OnGiveSecret(bool printmsg, bool playsound) { return true; } + + // called before and after triggering a teleporter + // return false in PreTeleport() to cancel the action early + virtual bool PreTeleport( Vector3 destpos, double destangle, int flags ) { return true; } + virtual void PostTeleport( Vector3 destpos, double destangle, int flags ) {} native virtual bool OkayToSwitchTarget(Actor other); - native static class GetReplacement(class cls); - native static class GetReplacee(class cls); + native clearscope static class GetReplacement(class cls); + native clearscope static class GetReplacee(class cls); native static int GetSpriteIndex(name sprt); native clearscope static double GetDefaultSpeed(class type); native static class GetSpawnableType(int spawnnum); - native static int ApplyDamageFactors(class itemcls, Name damagetype, int damage, int defdamage); + native clearscope static int ApplyDamageFactors(class itemcls, Name damagetype, int damage, int defdamage); native void RemoveFromHash(); native void ChangeTid(int newtid); deprecated("3.8", "Use Level.FindUniqueTid() instead") static int FindUniqueTid(int start = 0, int limit = 0) @@ -606,8 +694,9 @@ class Actor : Thinker native protected native void CheckPortalTransition(bool linked = true); native clearscope string GetTag(string defstr = "") const; + native clearscope string GetCharacterName() const; native void SetTag(string defstr = ""); - native double GetBobOffset(double frac = 0); + native clearscope double GetBobOffset(double frac = 0) const; native void ClearCounters(); native bool GiveBody (int num, int max=0); native bool HitFloor(); @@ -618,11 +707,12 @@ class Actor : Thinker native native void SoundAlert(Actor target, bool splash = false, double maxdist = 0); native void ClearBounce(); native TerrainDef GetFloorTerrain(); - native bool CheckLocalView(int consoleplayer = -1 /* parameter is not used anymore but needed for backward compatibilityö. */); + native bool CheckLocalView(int consoleplayer = -1 /* parameter is not used anymore but needed for backward compatibility. */); native bool CheckNoDelay(); native bool UpdateWaterLevel (bool splash = true); native bool IsZeroDamage(); native void ClearInterpolation(); + native void ClearFOVInterpolation(); native clearscope Vector3 PosRelative(sector sec) const; native void RailAttack(FRailParams p); @@ -646,7 +736,7 @@ class Actor : Thinker native native void CheckFakeFloorTriggers (double oldz, bool oldz_has_viewheight = false); native bool CheckFor3DFloorHit(double z, bool trigger); native bool CheckFor3DCeilingHit(double z, bool trigger); - native int CheckMonsterUseSpecials(); + native int CheckMonsterUseSpecials(Line blocking = null); native bool CheckMissileSpawn(double maxdist); native bool CheckPosition(Vector2 pos, bool actorsonly = false, FCheckPosition tm = null); @@ -660,10 +750,11 @@ class Actor : Thinker native native Actor SpawnSubMissile(Class type, Actor target); native Actor, Actor SpawnPlayerMissile(class type, double angle = 1e37, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); - native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false); - native int ApplyDamageFactor(Name damagetype, int damage); + native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false, double fov = 0); + native clearscope int ApplyDamageFactor(Name damagetype, int damage); native int GetModifiedDamage(Name damagetype, int damage, bool passive, Actor inflictor = null, Actor source = null, int flags = 0); native bool CheckBossDeath(); + native bool CheckFov(Actor target, double fov); void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); } void A_Light0() { if (player) player.extralight = 0; } @@ -684,7 +775,7 @@ class Actor : Thinker native native void TraceBleedAngle(int damage, double angle, double pitch); native void SetIdle(bool nofunction = false); - native bool CheckMeleeRange(); + native bool CheckMeleeRange(double range = -1); native bool TriggerPainChance(Name mod, bool forcedPain = false); native virtual int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0); native void PoisonMobj (Actor inflictor, Actor source, int damage, int duration, int period, Name type); @@ -693,6 +784,7 @@ class Actor : Thinker native native bool LineTrace(double angle, double distance, double pitch, int flags = 0, double offsetz = 0., double offsetforward = 0., double offsetside = 0., out FLineTraceData data = null); native bool CheckSight(Actor target, int flags = 0); native bool IsVisible(Actor other, bool allaround, LookExParams params = null); + native bool, Actor, double PerformShadowChecks (Actor other, Vector3 pos); native bool HitFriend(); native bool MonsterMove(); @@ -703,7 +795,7 @@ class Actor : Thinker native native void FindFloorCeiling(int flags = 0); native double, double GetFriction(); native bool, Actor TestMobjZ(bool quick = false); - native static bool InStateSequence(State newstate, State basestate); + native clearscope static bool InStateSequence(State newstate, State basestate); bool TryWalk () { @@ -722,6 +814,7 @@ class Actor : Thinker native native bool CheckMissileRange(); native bool SetState(state st, bool nofunction = false); clearscope native state FindState(statelabel st, bool exact = false) const; + clearscope native state FindStateByString(string st, bool exact = false) const; bool SetStateLabel(statelabel st, bool nofunction = false) { return SetState(FindState(st), nofunction); } native action state ResolveState(statelabel st); // this one, unlike FindState, is context aware. native void LinkToWorld(LinkContext ctx = null); @@ -737,7 +830,8 @@ class Actor : Thinker native native clearscope vector2 Vec2Angle(double length, double angle, bool absolute = false) const; native clearscope vector2 Vec2Offset(double x, double y, bool absolute = false) const; native clearscope vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false) const; - native void VelIntercept(Actor targ, double speed = -1, bool aimpitch = true, bool oldvel = false); + native double PitchFromVel(); + native void VelIntercept(Actor targ, double speed = -1, bool aimpitch = true, bool oldvel = false, bool resetvel = false); native void VelFromAngle(double speed = 1e37, double angle = 1e37); native void Vel3DFromAngle(double speed, double angle, double pitch); native void Thrust(double speed = 1e37, double angle = 1e37); @@ -751,7 +845,7 @@ class Actor : Thinker native native bool LookForEnemies(bool allaround, LookExParams params = null); native bool LookForPlayers(bool allaround, LookExParams params = null); native bool TeleportMove(Vector3 pos, bool telefrag, bool modifyactor = true); - native double DistanceBySpeed(Actor other, double speed); + native clearscope double DistanceBySpeed(Actor other, double speed) const; native name GetSpecies(); native void PlayActiveSound(); native void Howl(); @@ -759,6 +853,27 @@ class Actor : Thinker native native void GiveSecret(bool printmsg = true, bool playsound = true); native clearscope double GetCameraHeight() const; native clearscope double GetGravity() const; + native void DoMissileDamage(Actor target); + native void PlayPushSound(); + native bool BounceActor(Actor blocking, bool onTop); + native bool BounceWall(Line l = null); + native bool BouncePlane(readonly plane); + native void PlayBounceSound(bool onFloor); + native bool ReflectOffActor(Actor blocking); + + clearscope double PitchTo(Actor target, double zOfs = 0, double targZOfs = 0, bool absolute = false) const + { + Vector3 origin = (pos.xy, pos.z - floorClip + zOfs); + Vector3 dest = (target.pos.xy, target.pos.z - target.floorClip + targZOfs); + + Vector3 diff; + if (!absolute) + diff = level.Vec3Diff(origin, dest); + else + diff = dest - origin; + + return -atan2(diff.z, diff.xy.Length()); + } //========================================================================== // @@ -786,7 +901,7 @@ class Actor : Thinker native return level.totaltime - SpawnTime; } - double AccuracyFactor() + clearscope double AccuracyFactor() const { return 1. / (1 << (accuracy * 5 / 100)); } @@ -806,7 +921,7 @@ class Actor : Thinker native native clearscope int GetSpawnHealth() const; native double GetCrouchFactor(int ptr = AAPTR_PLAYER1); native double GetCVar(string cvar); - native double GetCVarString(string cvar); + native string GetCVarString(string cvar); native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); native int CountProximity(class classname, double distance, int flags = 0, int ptr = AAPTR_DEFAULT); native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT); @@ -861,9 +976,9 @@ class Actor : Thinker native return SpawnMissileAngleZSpeed (pos.z + 32 + GetBobOffset(), type, angle, vz, GetDefaultSpeed (type)); } - Actor SpawnMissileAngleZ (double z, class type, double angle, double vz) + Actor SpawnMissileAngleZ (double z, class type, double angle, double vz, Actor owner = null) { - return SpawnMissileAngleZSpeed (z, type, angle, vz, GetDefaultSpeed (type)); + return SpawnMissileAngleZSpeed (z, type, angle, vz, GetDefaultSpeed (type), owner); } @@ -1037,8 +1152,9 @@ class Actor : Thinker native void A_Fall() { A_NoBlocking(); } native void A_Look(); native void A_Chase(statelabel melee = '_a_chase_default', statelabel missile = '_a_chase_default', int flags = 0); + native void A_DoChase(State melee, State missile, int flags = 0); native void A_VileChase(); - native bool A_CheckForResurrection(); + native bool A_CheckForResurrection(State state = null, Sound snd = 0); native void A_BossDeath(); bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0) { @@ -1056,15 +1172,16 @@ class Actor : Thinker native native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class pufftype = "BulletPuff"); deprecated("4.3", "Use A_StartSound() instead") native clearscope void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false, double pitch = 0.0); native clearscope void A_StartSound(sound whattoplay, int slot = CHAN_BODY, int flags = 0, double volume = 1.0, double attenuation = ATTN_NORM, double pitch = 0.0, double startTime = 0.0); + native clearscope void A_StartSoundIfNotSame(sound whattoplay, sound checkagainst, int slot = CHAN_BODY, int flags = 0, double volume = 1.0, double attenuation = ATTN_NORM, double pitch = 0.0, double startTime = 0.0); native void A_SoundVolume(int slot, double volume); native void A_SoundPitch(int slot, double pitch); - deprecated("2.3", "Use A_StartSound(, CHAN_WEAPON) instead") void A_PlayWeaponSound(sound whattoplay) { A_StartSound(whattoplay, CHAN_WEAPON); } + deprecated("2.3", "Use A_StartSound(, CHAN_WEAPON) instead") void A_PlayWeaponSound(sound whattoplay, bool fullvol = false) { A_StartSound(whattoplay, CHAN_WEAPON, 0, 1, fullvol? ATTN_NONE : ATTN_NORM); } native void A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was... void A_StopAllSounds() { A_StopSounds(0,0); } native void A_StopSounds(int chanmin, int chanmax); deprecated("2.3", "Use A_StartSound() instead") native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0); deprecated("2.3", "Use A_StopSound() instead") native void A_StopSoundEx(name slot); - native clearscope bool IsActorPlayingSound(int channel, Sound snd = 0); + native clearscope bool IsActorPlayingSound(int channel, Sound snd = -1); native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); native action state A_Jump(int chance, statelabel label, ...); native Actor A_SpawnProjectile(class missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET); @@ -1080,12 +1197,22 @@ class Actor : Thinker native native void A_FadeOut(double reduce = 0.1, int flags = 1); //bool remove == true native void A_FadeTo(double target, double amount = 0.1, int flags = 0); native void A_SpawnDebris(class spawntype, bool transfer_translation = false, double mult_h = 1, double mult_v = 1); - native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0); + native void A_SpawnParticle(color color1, int flags = 0, int lifetime = TICRATE, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0); + native void A_SpawnParticleEx(color color1, TextureID texture, int style = STYLE_None, int flags = 0, int lifetime = TICRATE, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0, double startroll = 0, double rollvel = 0, double rollacc = 0); native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); native void A_DropInventory(class itemtype, int amount = -1); native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0, double alpha2 = 0.); deprecated("2.3", "Use 'b = [true/false]' instead") native void A_ChangeFlag(string flagname, bool value); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); + action native void A_ChangeModel(name modeldef, int modelindex = 0, string modelpath = "", name model = "", int skinindex = 0, string skinpath = "", name skin = "", int flags = 0, int generatorindex = -1, int animationindex = 0, string animationpath = "", name animation = ""); + + void A_SetFriendly (bool set) + { + if (CountsAsKill() && health > 0) level.total_monsters--; + bFriendly = set; + if (CountsAsKill() && health > 0) level.total_monsters++; + } + native void A_RaiseMaster(int flags = 0); native void A_RaiseChildren(int flags = 0); native void A_RaiseSiblings(int flags = 0); @@ -1106,9 +1233,9 @@ class Actor : Thinker native native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); native void A_CustomComboAttack(class missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); native void A_Burst(class chunktype); - native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class flashtype = null); - native int GetRadiusDamage(Actor thing, int damage, int distance, int fulldmgdistance = 0, bool oldradiusdmg = false); - native int RadiusAttack(Actor bombsource, int bombdamage, int bombdistance, Name bombmod = 'none', int flags = RADF_HURTSOURCE, int fulldamagedistance = 0); + native void A_RadiusDamageSelf(int damage = 128, double distance = 128.0, int flags = 0, class flashtype = null); + native int GetRadiusDamage(Actor thing, int damage, double distance, double fulldmgdistance = 0.0, bool oldradiusdmg = false, bool circular = false); + native int RadiusAttack(Actor bombsource, int bombdamage, double bombdistance, Name bombmod = 'none', int flags = RADF_HURTSOURCE, double fulldamagedistance = 0.0, name species = "None"); native void A_Respawn(int flags = 1); native void A_RestoreSpecialPosition(); @@ -1120,12 +1247,16 @@ class Actor : Thinker native native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetViewAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetViewPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetViewRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); + native void SetViewPos(Vector3 offset, int flags = -1); deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserVar(name varname, int value); deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserArray(name varname, int index, int value); deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserVarFloat(name varname, double value); deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserArrayFloat(name varname, int index, double value); - native void A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); - native void A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, int falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0); + native void A_Quake(double intensity, int duration, double damrad, double tremrad, sound sfx = "world/quake"); + native void A_QuakeEx(double intensityX, double intensityY, double intensityZ, int duration, double damrad, double tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, double falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0, double damageMultiplier = 1, double thrustMultiplier = 0.5, int damage = 0); action native void A_SetTics(int tics); native void A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); native void A_DamageTarget(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); @@ -1156,7 +1287,7 @@ class Actor : Thinker native native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetTranslation(name transname); native bool A_SetSize(double newradius = -1, double newheight = -1, bool testpos = false); - native void A_SprayDecal(String name, double dist = 172); + native void A_SprayDecal(String name, double dist = 172, vector3 offset = (0, 0, 0), vector3 direction = (0, 0, 0), bool useBloodColor = false, color decalColor = 0); native void A_SetMugshotState(String name); native void CopyBloodColor(Actor other); @@ -1166,15 +1297,61 @@ class Actor : Thinker native action native bool A_Overlay(int layer, statelabel start = null, bool nooverride = false); native void A_WeaponOffset(double wx = 0, double wy = 32, int flags = 0); + action native void A_OverlayScale(int layer, double wx = 1, double wy = 0, int flags = 0); + action native void A_OverlayRotate(int layer, double degrees = 0, int flags = 0); + action native void A_OverlayPivot(int layer, double wx = 0.5, double wy = 0.5, int flags = 0); + action native void A_OverlayPivotAlign(int layer, int halign, int valign); + action native void A_OverlayVertexOffset(int layer, int index, double x, double y, int flags = 0); action native void A_OverlayOffset(int layer = PSP_WEAPON, double wx = 0, double wy = 32, int flags = 0); action native void A_OverlayFlags(int layer, int flags, bool set); action native void A_OverlayAlpha(int layer, double alph); action native void A_OverlayRenderStyle(int layer, int style); + action native void A_OverlayTranslation(int layer, name trname); native bool A_AttachLightDef(Name lightid, Name lightdef); native bool A_AttachLight(Name lightid, int type, Color lightcolor, int radius1, int radius2, int flags = 0, Vector3 ofs = (0,0,0), double param = 0, double spoti = 10, double spoto = 25, double spotp = 0); native bool A_RemoveLight(Name lightid); + native version("4.12") void SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int endFrame = -1, int interpolateTics = -1, int flags = 0); + native version("4.12") ui void SetAnimationUI(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int endFrame = -1, int interpolateTics = -1, int flags = 0); + + native version("4.12") void SetAnimationFrameRate(double framerate); + native version("4.12") ui void SetAnimationFrameRateUI(double framerate); + + native version("4.12") void SetModelFlag(int flag); + native version("4.12") void ClearModelFlag(int flag); + native version("4.12") void ResetModelFlags(); + + + action version("4.12") void A_SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int endFrame = -1, int interpolateTics = -1, int flags = 0) + { + invoker.SetAnimation(animName, framerate, startFrame, loopFrame, endFrame, interpolateTics, flags); + } + + action version("4.12") void A_SetAnimationFrameRate(double framerate) + { + invoker.SetAnimationFrameRate(framerate); + } + + action version("4.12") void A_SetModelFlag(int flag) + { + invoker.SetModelFlag(flag); + } + + action version("4.12") void A_ClearModelFlag(int flag) + { + invoker.ClearModelFlag(flag); + } + + action version("4.12") void A_ResetModelFlags() + { + invoker.ResetModelFlags(); + } + + + + + int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0) { return ACS_Execute(-int(script), mapnum, arg1, arg2, arg3); @@ -1218,7 +1395,7 @@ class Actor : Thinker native { if (DeathSound) { - A_StartSound(DeathSound, CHAN_VOICE, CHANF_DEFAULT, 1, bBoss? ATTN_NONE : ATTN_NORM); + A_StartSound(DeathSound, CHAN_VOICE, CHANF_DEFAULT, 1, bBoss || bFullvolDeath? ATTN_NONE : ATTN_NORM); } } @@ -1235,6 +1412,65 @@ class Actor : Thinker native } } + virtual void PlayerLandedMakeGruntSound(actor onmobj) + { + bool grunted; + + // [RH] only make noise if alive + if (self.health > 0 && !Alternative) + { + grunted = false; + // Why should this number vary by gravity? + if (self.Vel.Z < -self.player.mo.GruntSpeed) + { + A_StartSound("*grunt", CHAN_VOICE); + grunted = true; + } + bool isliquid = (pos.Z <= floorz) && HitFloor (); + if (onmobj != NULL || !isliquid) + { + if (!grunted) + { + A_StartSound("*land", CHAN_AUTO); + } + else + { + A_StartSoundIfNotSame("*land", "*grunt", CHAN_AUTO); + } + } + } + } + + virtual void PlayerSquatView(Actor onmobj) + { + if (!self.player) + return; + + if (self.player.mo == self) + { + self.player.deltaviewheight = self.Vel.Z / 8.; + } + } + + virtual void PlayDiveOrSurfaceSounds(int oldlevel) + { + if (oldlevel < 3 && WaterLevel == 3) + { + // Our head just went under. + A_StartSound("*dive", CHAN_VOICE, attenuation: ATTN_NORM); + } + else if (oldlevel == 3 && WaterLevel < 3) + { + // Our head just came up. + if (player.air_finished > Level.maptime) + { + // We hadn't run out of air yet. + A_StartSound("*surface", CHAN_VOICE, attenuation: ATTN_NORM); + } + // If we were running out of air, then ResetAirSupply() will play *gasp. + } + } + //---------------------------------------------------------------------------- // // PROC A_CheckSkullDone @@ -1264,6 +1500,9 @@ class Actor : Thinker native GenericCrush: POL5 A -1; Stop; + DieFromSpawn: + TNT1 A 1; + TNT1 A 1 { self.Die(null, null); } } // Internal functions diff --git a/wadsrc/static/zscript/actors/attacks.zs b/wadsrc/static/zscript/actors/attacks.zs index bb2cdeec449..db9da6f35bd 100644 --- a/wadsrc/static/zscript/actors/attacks.zs +++ b/wadsrc/static/zscript/actors/attacks.zs @@ -55,6 +55,7 @@ extend class Actor double bangle; double bslope = 0.; int laflags = (flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; + FTranslatedLineTarget t; if (ref != NULL || (flags & CBAF_AIMFACING)) { @@ -89,7 +90,7 @@ extend class Actor if (!(flags & CBAF_NORANDOM)) damage *= random[cwbullet](1, 3); - let puff = LineAttack(pangle, range, slope, damage, 'Hitscan', pufftype, laflags); + let puff = LineAttack(pangle, range, slope, damage, 'Hitscan', pufftype, laflags, t); if (missile != null && pufftype != null) { double ang = pangle - 90; @@ -104,11 +105,19 @@ extend class Actor bool temp = (puff == null); if (!puff) { - puff = LineAttack(pangle, range, slope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT); + puff = LineAttack(pangle, range, slope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT, t); } if (puff) { AimBulletMissile(proj, puff, flags, temp, true); + if (t.unlinked) + { + // Arbitary portals will make angle and pitch calculations unreliable. + // So use the angle and pitch we passed instead. + proj.Angle = pangle; + proj.Pitch = bslope; + proj.Vel3DFromAngle(proj.Speed, proj.Angle, proj.Pitch); + } } } } @@ -137,7 +146,7 @@ extend class Actor bInCombat = true; self.target = target; - let painstate = FindState('Pain', 'Dagger'); + let painstate = FindState('Pain.Dagger'); if (painstate != NULL) { SetState(painstate); @@ -560,7 +569,7 @@ extend class Actor // //========================================================================== - int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none") + int A_Explode(int damage = -1, double distance = -1.0, int flags = XF_HURTSOURCE, bool alert = false, double fulldamagedistance = 0.0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none") { if (damage < 0) // get parameters from metadata @@ -597,6 +606,9 @@ extend class Actor if (flags & XF_HURTSOURCE) pflags |= RADF_HURTSOURCE; if (flags & XF_NOTMISSILE) pflags |= RADF_SOURCEISSPOT; if (flags & XF_THRUSTZ) pflags |= RADF_THRUSTZ; + if (flags & XF_THRUSTLESS) pflags |= RADF_THRUSTLESS; + if (flags & XF_NOALLIES) pflags |= RADF_NOALLIES; + if (flags & XF_CIRCULAR) pflags |= RADF_CIRCULAR; int count = RadiusAttack (target, damage, distance, damagetype, pflags, fulldamagedistance); if (!(flags & XF_NOSPLASH)) CheckSplash(distance); @@ -607,16 +619,28 @@ extend class Actor return count; } + deprecated("2.3", "For Dehacked use only") + void A_NailBomb() + { + A_Explode(nails:30); + } + + deprecated("2.3", "For Dehacked use only") + void A_RadiusDamage(int dam, int dist) + { + A_Explode(dam, dist); + } + //========================================================================== // // A_RadiusThrust // //========================================================================== - void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0) + void A_RadiusThrust(int force = 128, double distance = -1.0, int flags = RTF_AFFECTSOURCE, double fullthrustdistance = 0.0, name species = "None") { if (force == 0) force = 128; - if (distance <= 0) distance = abs(force); + if (distance <= 0.0) distance = abs(force); bool nothrust = false; if (target) @@ -628,7 +652,7 @@ extend class Actor target.bNoDamageThrust = false; } } - RadiusAttack (target, force, distance, DamageType, flags | RADF_NODAMAGE, fullthrustdistance); + RadiusAttack (target, force, distance, DamageType, flags | RADF_NODAMAGE, fullthrustdistance, species); CheckSplash(distance); if (target) target.bNoDamageThrust = nothrust; } diff --git a/wadsrc/static/zscript/actors/checks.zs b/wadsrc/static/zscript/actors/checks.zs index 280abf4fe2c..018f2b55295 100644 --- a/wadsrc/static/zscript/actors/checks.zs +++ b/wadsrc/static/zscript/actors/checks.zs @@ -110,7 +110,7 @@ extend class Actor bool CheckArmorType(name Type, int amount = 1) { - let myarmor = BasicArmor(FindInventory("BasicArmor")); + let myarmor = BasicArmor(FindInventory("BasicArmor", true)); return myarmor != null && myarmor.ArmorType == type && myarmor.Amount >= amount; } diff --git a/wadsrc/static/zscript/actors/chex/chexweapons.zs b/wadsrc/static/zscript/actors/chex/chexweapons.zs index 5bf6fe75754..e135683a04c 100644 --- a/wadsrc/static/zscript/actors/chex/chexweapons.zs +++ b/wadsrc/static/zscript/actors/chex/chexweapons.zs @@ -106,7 +106,7 @@ class PhasingZorcher : PlasmaRifle States { Fire: - PLSG A 0 A_GunFlash; + PLSG A 0 A_GunFlash('Flash', GFF_NOEXTCHANGE); PLSG A 3 A_FireProjectile("PhaseZorchMissile"); PLSG B 20 A_ReFire; Goto Ready; diff --git a/wadsrc/static/zscript/actors/doom/arachnotron.zs b/wadsrc/static/zscript/actors/doom/arachnotron.zs index 56ba94831d8..862f2bc6004 100644 --- a/wadsrc/static/zscript/actors/doom/arachnotron.zs +++ b/wadsrc/static/zscript/actors/doom/arachnotron.zs @@ -16,6 +16,7 @@ class Arachnotron : Actor Monster; +FLOORCLIP +BOSSDEATH + +MAP07BOSS2 SeeSound "baby/sight"; PainSound "baby/pain"; DeathSound "baby/death"; diff --git a/wadsrc/static/zscript/actors/doom/bossbrain.zs b/wadsrc/static/zscript/actors/doom/bossbrain.zs index a2fb6f26769..b0033cb2b0d 100644 --- a/wadsrc/static/zscript/actors/doom/bossbrain.zs +++ b/wadsrc/static/zscript/actors/doom/bossbrain.zs @@ -12,6 +12,7 @@ class BossBrain : Actor Health 250; Mass 10000000; PainChance 255; + Radius 16; +SOLID +SHOOTABLE +NOICEDEATH +OLDRADIUSDMG diff --git a/wadsrc/static/zscript/actors/doom/bruiser.zs b/wadsrc/static/zscript/actors/doom/bruiser.zs index a34c91160a7..1bc1a20edd5 100644 --- a/wadsrc/static/zscript/actors/doom/bruiser.zs +++ b/wadsrc/static/zscript/actors/doom/bruiser.zs @@ -16,6 +16,7 @@ class BaronOfHell : Actor Monster; +FLOORCLIP +BOSSDEATH + +E1M8BOSS SeeSound "baron/sight"; PainSound "baron/pain"; DeathSound "baron/death"; diff --git a/wadsrc/static/zscript/actors/doom/cyberdemon.zs b/wadsrc/static/zscript/actors/doom/cyberdemon.zs index 4817207fc8d..d795fc31aaf 100644 --- a/wadsrc/static/zscript/actors/doom/cyberdemon.zs +++ b/wadsrc/static/zscript/actors/doom/cyberdemon.zs @@ -22,6 +22,8 @@ class Cyberdemon : Actor +NORADIUSDMG +DONTMORPH +BOSSDEATH + +E2M8BOSS + +E4M6BOSS SeeSound "cyber/sight"; PainSound "cyber/pain"; DeathSound "cyber/death"; diff --git a/wadsrc/static/zscript/actors/doom/dehacked.zs b/wadsrc/static/zscript/actors/doom/dehacked.zs index 470fcb92232..9e513ff1adc 100644 --- a/wadsrc/static/zscript/actors/doom/dehacked.zs +++ b/wadsrc/static/zscript/actors/doom/dehacked.zs @@ -115,129 +115,240 @@ class Deh_Actor_250 : Actor PLAY Q 5 A_Fall; PLAY RSTUV 5; PLAY W -1; // 1084 - BLD2 AAAAAAAAAAAAAAAA 0; // 1100 - SP00 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP01 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP02 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP03 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP04 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP05 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP06 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP07 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP08 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP09 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP10 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP11 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP12 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP13 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP14 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP15 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP16 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP17 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP18 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP19 AAAAAAAAAAAAAAAAAAAAAAAAA 0; // 1600 - - SP20 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP21 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP22 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP23 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP24 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP25 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP26 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP27 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP28 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP29 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP30 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP31 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP32 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP33 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP34 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP35 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP36 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP37 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP38 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP39 AAAAAAAAAAAAAAAAAAAAAAAAA 0; // 2100 - - SP40 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP41 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP42 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP43 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP44 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP45 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP46 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP47 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP48 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP49 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP50 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP51 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP52 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP53 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP54 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP55 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP56 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP57 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP58 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP59 AAAAAAAAAAAAAAAAAAAAAAAAA 0; // 2600 - - SP60 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP61 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP62 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP63 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP64 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP65 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP66 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP67 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP68 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP69 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP70 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP71 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP72 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP73 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP74 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP75 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP76 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP77 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP78 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP79 AAAAAAAAAAAAAAAAAAAAAAAAA 0; // 3100 - - SP80 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP81 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP82 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP83 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP84 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP85 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP86 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP87 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP88 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP89 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP90 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP91 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP92 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP93 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP94 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP95 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP96 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP97 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP98 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP99 AAAAAAAAAAAAAAAAAAAAAAAAA 0; // 3600 - SP80 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP81 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP82 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP83 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP84 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP85 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP86 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP87 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP88 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP89 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP90 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP91 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP92 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP93 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP94 AAAAAAAAAAAAAAAAAAAAAAAAA 0; - SP95 AAAAAAAAAAAAAAAAAAAAAAAAA 0; // 4000 + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + // 1600 + + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + // 2100 + + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + // 2600 + + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + // 3100 + + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + // 3600 + + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; TNT1 A -1; Wait; + // 4000 + + DeclareSprites: + SP00 A 0; + SP01 A 0; + SP02 A 0; + SP03 A 0; + SP04 A 0; + SP05 A 0; + SP06 A 0; + SP07 A 0; + SP08 A 0; + SP09 A 0; + SP10 A 0; + SP11 A 0; + SP12 A 0; + SP13 A 0; + SP14 A 0; + SP15 A 0; + SP16 A 0; + SP17 A 0; + SP18 A 0; + SP19 A 0; + SP20 A 0; + SP21 A 0; + SP22 A 0; + SP23 A 0; + SP24 A 0; + SP25 A 0; + SP26 A 0; + SP27 A 0; + SP28 A 0; + SP29 A 0; + SP30 A 0; + SP31 A 0; + SP32 A 0; + SP33 A 0; + SP34 A 0; + SP35 A 0; + SP36 A 0; + SP37 A 0; + SP38 A 0; + SP39 A 0; + SP40 A 0; + SP41 A 0; + SP42 A 0; + SP43 A 0; + SP44 A 0; + SP45 A 0; + SP46 A 0; + SP47 A 0; + SP48 A 0; + SP49 A 0; + SP50 A 0; + SP51 A 0; + SP52 A 0; + SP53 A 0; + SP54 A 0; + SP55 A 0; + SP56 A 0; + SP57 A 0; + SP58 A 0; + SP59 A 0; + SP60 A 0; + SP61 A 0; + SP62 A 0; + SP63 A 0; + SP64 A 0; + SP65 A 0; + SP66 A 0; + SP67 A 0; + SP68 A 0; + SP69 A 0; + SP70 A 0; + SP71 A 0; + SP72 A 0; + SP73 A 0; + SP74 A 0; + SP75 A 0; + SP76 A 0; + SP77 A 0; + SP78 A 0; + SP79 A 0; + SP80 A 0; + SP81 A 0; + SP82 A 0; + SP83 A 0; + SP84 A 0; + SP85 A 0; + SP86 A 0; + SP87 A 0; + SP88 A 0; + SP89 A 0; + SP90 A 0; + SP91 A 0; + SP92 A 0; + SP93 A 0; + SP94 A 0; + SP95 A 0; + SP96 A 0; + SP97 A 0; + SP98 A 0; + SP99 A 0; + Stop; } } \ No newline at end of file diff --git a/wadsrc/static/zscript/actors/doom/doomdecorations.zs b/wadsrc/static/zscript/actors/doom/doomdecorations.zs index 8eec812f6b0..ab5bd5b4f59 100644 --- a/wadsrc/static/zscript/actors/doom/doomdecorations.zs +++ b/wadsrc/static/zscript/actors/doom/doomdecorations.zs @@ -82,7 +82,7 @@ class ShortGreenColumn : Actor Default { Radius 16; - Height 40;; + Height 40; ProjectilePassHeight -16; +SOLID } @@ -234,7 +234,7 @@ class BlueTorch : Actor Default { Radius 16; - Height 68;; + Height 68; ProjectilePassHeight -16; +SOLID } @@ -594,7 +594,7 @@ class HeadsOnAStick : Actor Default { Radius 16; - Height 64;; + Height 64; ProjectilePassHeight -16; +SOLID } diff --git a/wadsrc/static/zscript/actors/doom/doomhealth.zs b/wadsrc/static/zscript/actors/doom/doomhealth.zs index c0ecf2dc01c..04909b248b7 100644 --- a/wadsrc/static/zscript/actors/doom/doomhealth.zs +++ b/wadsrc/static/zscript/actors/doom/doomhealth.zs @@ -16,6 +16,33 @@ class HealthBonus : Health BON1 ABCDCB 6; Loop; } + + //=========================================================================== + // + // TryPickup + // + //=========================================================================== + + override bool TryPickup (in out Actor other) + { + PrevHealth = other.player != NULL ? other.player.health : other.health; + + // Dehacked max health is compatibility dependent because Boom interpreted this value wrong. + let maxamt = MaxAmount; + if (maxamt < 0) + { + maxamt = deh.MaxHealth; + if (!(Level.compatflags & COMPATF_DEHHEALTH)) maxamt *= 2; + } + + if (other.GiveBody(Amount, maxamt)) + { + GoAwayAndDie(); + return true; + } + return false; + } + } // Stimpack ----------------------------------------------------------------- diff --git a/wadsrc/static/zscript/actors/doom/doommisc.zs b/wadsrc/static/zscript/actors/doom/doommisc.zs index c6d8af7179e..a761f94e07e 100644 --- a/wadsrc/static/zscript/actors/doom/doommisc.zs +++ b/wadsrc/static/zscript/actors/doom/doommisc.zs @@ -26,7 +26,7 @@ class ExplosiveBarrel : Actor BEXP A 5 BRIGHT; BEXP B 5 BRIGHT A_Scream; BEXP C 5 BRIGHT; - BEXP D 5 BRIGHT A_Explode; + BEXP D 10 BRIGHT A_Explode; BEXP E 10 BRIGHT; TNT1 A 1050 BRIGHT A_BarrelDestroy; TNT1 A 5 A_Respawn; diff --git a/wadsrc/static/zscript/actors/doom/doomweapons.zs b/wadsrc/static/zscript/actors/doom/doomweapons.zs index 4d3586e0540..e28cf8bf3d2 100644 --- a/wadsrc/static/zscript/actors/doom/doomweapons.zs +++ b/wadsrc/static/zscript/actors/doom/doomweapons.zs @@ -31,7 +31,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; State flash = weap.FindState('Flash'); diff --git a/wadsrc/static/zscript/actors/doom/fatso.zs b/wadsrc/static/zscript/actors/doom/fatso.zs index 82ec4623b58..493456dd8f9 100644 --- a/wadsrc/static/zscript/actors/doom/fatso.zs +++ b/wadsrc/static/zscript/actors/doom/fatso.zs @@ -16,6 +16,7 @@ class Fatso : Actor Monster; +FLOORCLIP +BOSSDEATH + +MAP07BOSS1 SeeSound "fatso/sight"; PainSound "fatso/pain"; DeathSound "fatso/death"; diff --git a/wadsrc/static/zscript/actors/doom/lostsoul.zs b/wadsrc/static/zscript/actors/doom/lostsoul.zs index f44a24754ba..7feb8553b0f 100644 --- a/wadsrc/static/zscript/actors/doom/lostsoul.zs +++ b/wadsrc/static/zscript/actors/doom/lostsoul.zs @@ -20,7 +20,6 @@ class LostSoul : Actor PainSound "skull/pain"; DeathSound "skull/death"; ActiveSound "skull/active"; - RenderStyle "SoulTrans"; Obituary "$OB_SKULL"; Tag "$FN_LOST"; } diff --git a/wadsrc/static/zscript/actors/doom/possessed.zs b/wadsrc/static/zscript/actors/doom/possessed.zs index eef344ab8e3..4fa9e0f7ec7 100644 --- a/wadsrc/static/zscript/actors/doom/possessed.zs +++ b/wadsrc/static/zscript/actors/doom/possessed.zs @@ -315,12 +315,12 @@ extend class Actor } } - void A_CPosAttack() + private void A_CPosAttackInternal(Sound snd) { if (target) { if (bStealth) visdir = 1; - A_StartSound(AttackSound, CHAN_WEAPON); + A_StartSound(snd, CHAN_WEAPON); A_FaceTarget(); double slope = AimLineAttack(angle, MISSILERANGE); double ang = angle + Random2[CPosAttack]() * (22.5/256); @@ -328,6 +328,17 @@ extend class Actor LineAttack(ang, MISSILERANGE, slope, damage, "Hitscan", "Bulletpuff"); } } + + void A_CPosAttack() + { + A_CPosAttackInternal(AttackSound); + } + + void A_CPosAttackDehacked() + { + A_CPosAttackInternal("chainguy/attack"); + } + void A_CPosRefire() { diff --git a/wadsrc/static/zscript/actors/doom/spidermaster.zs b/wadsrc/static/zscript/actors/doom/spidermaster.zs index c8b6eb091b4..3ad0b8846f6 100644 --- a/wadsrc/static/zscript/actors/doom/spidermaster.zs +++ b/wadsrc/static/zscript/actors/doom/spidermaster.zs @@ -20,6 +20,8 @@ class SpiderMastermind : Actor +NORADIUSDMG +DONTMORPH +BOSSDEATH + +E3M8BOSS + +E4M8BOSS SeeSound "spider/sight"; AttackSound "spider/attack"; PainSound "spider/pain"; diff --git a/wadsrc/static/zscript/actors/doom/weaponbfg.zs b/wadsrc/static/zscript/actors/doom/weaponbfg.zs index 583688f8dc3..cb9e0ae7d38 100644 --- a/wadsrc/static/zscript/actors/doom/weaponbfg.zs +++ b/wadsrc/static/zscript/actors/doom/weaponbfg.zs @@ -107,7 +107,7 @@ extend class StateProvider if (invoker != weap || stateinfo == null || stateinfo.mStateType != STATE_Psprite) weap = null; if (weap != null) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; doesautoaim = weap.bNoAutoaim; diff --git a/wadsrc/static/zscript/actors/doom/weaponchaingun.zs b/wadsrc/static/zscript/actors/doom/weaponchaingun.zs index 58a4506881e..50fc5eea652 100644 --- a/wadsrc/static/zscript/actors/doom/weaponchaingun.zs +++ b/wadsrc/static/zscript/actors/doom/weaponchaingun.zs @@ -60,7 +60,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; A_StartSound ("weapons/chngun", CHAN_WEAPON); diff --git a/wadsrc/static/zscript/actors/doom/weaponchainsaw.zs b/wadsrc/static/zscript/actors/doom/weaponchainsaw.zs index 7ba89635546..ac05b182819 100644 --- a/wadsrc/static/zscript/actors/doom/weaponchainsaw.zs +++ b/wadsrc/static/zscript/actors/doom/weaponchainsaw.zs @@ -16,6 +16,7 @@ class Chainsaw : Weapon Obituary "$OB_MPCHAINSAW"; Tag "$TAG_CHAINSAW"; +WEAPON.MELEEWEAPON + +WEAPON.NOAUTOSWITCHTO } States { @@ -64,7 +65,7 @@ extend class StateProvider } if (range == 0) { - range = SAWRANGE; + range = MeleeRange + MELEEDELTA + (1. / 65536.); // MBF21 SAWRANGE; } double ang = angle + spread_xy * (Random2[Saw]() / 255.); @@ -78,9 +79,11 @@ extend class StateProvider return; } + int puffFlags = (flags & SF_NORANDOMPUFFZ) ? LAF_NORANDOMPUFFZ : 0; + Actor puff; int actualdamage; - [puff, actualdamage] = LineAttack (ang, range, slope, damage, 'Melee', pufftype, false, t); + [puff, actualdamage] = LineAttack (ang, range, slope, damage, 'Melee', pufftype, puffFlags, t); if (!t.linetarget) { diff --git a/wadsrc/static/zscript/actors/doom/weaponfist.zs b/wadsrc/static/zscript/actors/doom/weaponfist.zs index 6d857f7a282..711ca97d93d 100644 --- a/wadsrc/static/zscript/actors/doom/weaponfist.zs +++ b/wadsrc/static/zscript/actors/doom/weaponfist.zs @@ -14,6 +14,7 @@ class Fist : Weapon Tag "$TAG_FIST"; +WEAPON.WIMPY_WEAPON +WEAPON.MELEEWEAPON + +WEAPON.NOAUTOSWITCHTO } States { @@ -65,9 +66,10 @@ extend class Actor damage *= 10; double ang = angle + Random2[Punch]() * (5.625 / 256); - double pitch = AimLineAttack (ang, DEFMELEERANGE, null, 0., ALF_CHECK3D); + double range = MeleeRange + MELEEDELTA; + double pitch = AimLineAttack (ang, range, null, 0., ALF_CHECK3D); - LineAttack (ang, DEFMELEERANGE, pitch, damage, 'Melee', "BulletPuff", LAF_ISMELEEATTACK, t); + LineAttack (ang, range, pitch, damage, 'Melee', "BulletPuff", LAF_ISMELEEATTACK, t); // turn to face target if (t.linetarget) diff --git a/wadsrc/static/zscript/actors/doom/weaponpistol.zs b/wadsrc/static/zscript/actors/doom/weaponpistol.zs index cddd8647aba..b44760e7db0 100644 --- a/wadsrc/static/zscript/actors/doom/weaponpistol.zs +++ b/wadsrc/static/zscript/actors/doom/weaponpistol.zs @@ -65,6 +65,11 @@ extend class StateProvider if (!accurate) { ang += Random2[GunShot]() * (5.625 / 256); + + if (GetCVar ("vertspread") && !sv_novertspread) + { + pitch += Random2[GunShot]() * (3.549 / 256); + } } LineAttack(ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', pufftype); @@ -80,7 +85,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); diff --git a/wadsrc/static/zscript/actors/doom/weaponplasma.zs b/wadsrc/static/zscript/actors/doom/weaponplasma.zs index dd711484cad..d1a474e53e4 100644 --- a/wadsrc/static/zscript/actors/doom/weaponplasma.zs +++ b/wadsrc/static/zscript/actors/doom/weaponplasma.zs @@ -133,7 +133,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; State flash = weap.FindState('Flash'); diff --git a/wadsrc/static/zscript/actors/doom/weaponrlaunch.zs b/wadsrc/static/zscript/actors/doom/weaponrlaunch.zs index 042b96823ae..dc7cd0ff24d 100644 --- a/wadsrc/static/zscript/actors/doom/weaponrlaunch.zs +++ b/wadsrc/static/zscript/actors/doom/weaponrlaunch.zs @@ -152,7 +152,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; } @@ -177,7 +177,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; } diff --git a/wadsrc/static/zscript/actors/doom/weaponshotgun.zs b/wadsrc/static/zscript/actors/doom/weaponshotgun.zs index 3b39f1d3e4a..01ca8fbc1cd 100644 --- a/wadsrc/static/zscript/actors/doom/weaponshotgun.zs +++ b/wadsrc/static/zscript/actors/doom/weaponshotgun.zs @@ -66,7 +66,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); diff --git a/wadsrc/static/zscript/actors/doom/weaponssg.zs b/wadsrc/static/zscript/actors/doom/weaponssg.zs index cf775bde00d..1312d3c9fa6 100644 --- a/wadsrc/static/zscript/actors/doom/weaponssg.zs +++ b/wadsrc/static/zscript/actors/doom/weaponssg.zs @@ -74,7 +74,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 2)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); diff --git a/wadsrc/static/zscript/actors/heretic/chicken.zs b/wadsrc/static/zscript/actors/heretic/chicken.zs index 6e535462347..a49418ca39e 100644 --- a/wadsrc/static/zscript/actors/heretic/chicken.zs +++ b/wadsrc/static/zscript/actors/heretic/chicken.zs @@ -60,6 +60,7 @@ class Beak : Weapon if (psp) { psp.y = WEAPONTOP; + ResetPSprite(psp); } player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); } @@ -220,7 +221,7 @@ class ChickenPlayer : PlayerPawn pspr.y = WEAPONTOP + player.chickenPeck / 2; } } - if (player.morphTics & 15) + if ((player.MorphTics ? player.MorphTics : Random[ChickenPlayerThink]()) & 15) { return; } diff --git a/wadsrc/static/zscript/actors/heretic/hereticammo.zs b/wadsrc/static/zscript/actors/heretic/hereticammo.zs index c5ea831aaff..6464cf9dcaf 100644 --- a/wadsrc/static/zscript/actors/heretic/hereticammo.zs +++ b/wadsrc/static/zscript/actors/heretic/hereticammo.zs @@ -84,7 +84,7 @@ Class MaceAmmo : Ammo Inventory.PickupMessage "$TXT_AMMOMACE1"; Inventory.Amount 20; Inventory.MaxAmount 150; - Ammo.BackpackAmount 20; + Ammo.BackpackAmount 0; Ammo.BackpackMaxAmount 300; Inventory.Icon "INAMLOB"; Tag "$AMMO_MACE"; diff --git a/wadsrc/static/zscript/actors/heretic/hereticartifacts.zs b/wadsrc/static/zscript/actors/heretic/hereticartifacts.zs index d12bf2b1980..b620b04b4fc 100644 --- a/wadsrc/static/zscript/actors/heretic/hereticartifacts.zs +++ b/wadsrc/static/zscript/actors/heretic/hereticartifacts.zs @@ -66,28 +66,26 @@ Class ArtiTomeOfPower : PowerupGiver Loop; } - override bool Use (bool pickup) + override bool Use(bool pickup) { - Playerinfo p = Owner.player; - if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYTOMEOFPOWER)) - { // Attempt to undo chicken - if (!p.mo.UndoPlayerMorph (p, MRF_UNDOBYTOMEOFPOWER)) - { // Failed - if (!(p.MorphStyle & MRF_FAILNOTELEFRAG)) - { - Owner.DamageMobj (null, null, TELEFRAG_DAMAGE, 'Telefrag'); - } + EMorphFlags mStyle = Owner.GetMorphStyle(); + if (Owner.Alternative && (mStyle & MRF_UNDOBYTOMEOFPOWER)) + { + // Attempt to undo chicken. + if (!Owner.Unmorph(Owner, MRF_UNDOBYTOMEOFPOWER)) + { + if (!(mStyle & MRF_FAILNOTELEFRAG)) + Owner.DamageMobj(null, null, TELEFRAG_DAMAGE, 'Telefrag'); } - else - { // Succeeded - Owner.A_StartSound ("*evillaugh", CHAN_VOICE); + else if (Owner.player) + { + Owner.A_StartSound("*evillaugh", CHAN_VOICE); } + return true; } - else - { - return Super.Use (pickup); - } + + return Super.Use(pickup); } } diff --git a/wadsrc/static/zscript/actors/heretic/weaponblaster.zs b/wadsrc/static/zscript/actors/heretic/weaponblaster.zs index 23830eb086b..d2048e594cc 100644 --- a/wadsrc/static/zscript/actors/heretic/weaponblaster.zs +++ b/wadsrc/static/zscript/actors/heretic/weaponblaster.zs @@ -65,6 +65,11 @@ class Blaster : HereticWeapon if (player.refire) { ang += Random2[FireBlaster]() * (5.625 / 256); + + if (GetCVar ("vertspread") && !sv_novertspread) + { + pitch += Random2[FireBlaster]() * (3.549 / 256); + } } LineAttack (ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', "BlasterPuff"); A_StartSound ("weapons/blastershoot", CHAN_WEAPON); diff --git a/wadsrc/static/zscript/actors/heretic/weaponphoenix.zs b/wadsrc/static/zscript/actors/heretic/weaponphoenix.zs index 3300c43d359..884db86f82a 100644 --- a/wadsrc/static/zscript/actors/heretic/weaponphoenix.zs +++ b/wadsrc/static/zscript/actors/heretic/weaponphoenix.zs @@ -93,7 +93,7 @@ class PhoenixRodPowered : PhoenixRod override void EndPowerup () { - DepleteAmmo (bAltFire); + if (FlameCount > 0) DepleteAmmo (bAltFire); Owner.player.refire = 0; Owner.A_StopSound (CHAN_WEAPON); Owner.player.ReadyWeapon = SisterWeapon; @@ -178,9 +178,10 @@ class PhoenixRodPowered : PhoenixRod return; } A_StopSound (CHAN_WEAPON); - Weapon weapon = player.ReadyWeapon; + PhoenixRodPowered weapon = PhoenixRodPowered(player.ReadyWeapon); if (weapon != null) { + weapon.FlameCount = 0; weapon.DepleteAmmo (weapon.bAltFire); } } diff --git a/wadsrc/static/zscript/actors/heretic/weaponwand.zs b/wadsrc/static/zscript/actors/heretic/weaponwand.zs index 52d5136e2bd..65829a8d455 100644 --- a/wadsrc/static/zscript/actors/heretic/weaponwand.zs +++ b/wadsrc/static/zscript/actors/heretic/weaponwand.zs @@ -64,6 +64,11 @@ class GoldWand : HereticWeapon if (player.refire) { ang += Random2[FireGoldWand]() * (5.625 / 256); + + if (GetCVar ("vertspread") && !sv_novertspread) + { + pitch += Random2[FireGoldWand]() * (3.549 / 256); + } } LineAttack(ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', "GoldWandPuff1"); A_StartSound("weapons/wandhit", CHAN_WEAPON); diff --git a/wadsrc/static/zscript/actors/hexen/bishop.zs b/wadsrc/static/zscript/actors/hexen/bishop.zs index 4ebd519f50c..1b65f3edb3a 100644 --- a/wadsrc/static/zscript/actors/hexen/bishop.zs +++ b/wadsrc/static/zscript/actors/hexen/bishop.zs @@ -63,7 +63,7 @@ class Bishop : Actor BISH J 5 BRIGHT A_Explode(random[BishopBoom](25,40)); BISH K 5 Bright; BISH LM 4 Bright; - BISH N 4 A_SpawnItemEx("BishopPuff", 0,0,40, 0,0,-0.5); + BISH N 4 A_SpawnItemEx("BishopPuff", 0,0,40, 0,0,0.5); BISH O 4 A_QueueCorpse; BISH P -1; Stop; diff --git a/wadsrc/static/zscript/actors/hexen/blastradius.zs b/wadsrc/static/zscript/actors/hexen/blastradius.zs index 9dacb58a481..271f2bcfc6d 100644 --- a/wadsrc/static/zscript/actors/hexen/blastradius.zs +++ b/wadsrc/static/zscript/actors/hexen/blastradius.zs @@ -60,7 +60,7 @@ extend class Actor (victim.radius + 1) * cos(ang), (victim.radius + 1) * sin(ang), (victim.Height / 2) - victim.Floorclip); - Actor mo = Spawn (blasteffect, spawnpos, ALLOW_REPLACE); + Actor mo = blasteffect? Spawn (blasteffect, spawnpos, ALLOW_REPLACE) : null; if (mo) { mo.Vel.XY = victim.Vel.XY; @@ -148,6 +148,11 @@ extend class Actor // in another region and cannot be seen. continue; } + if ((blastflags & BF_ONLYVISIBLETHINGS) && !isVisible(mo, true)) + { + //only blast if target can bee seen by calling actor + continue; + } BlastActor (mo, strength, speed, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE)); } } diff --git a/wadsrc/static/zscript/actors/hexen/boostarmor.zs b/wadsrc/static/zscript/actors/hexen/boostarmor.zs index 4ed7c7f8088..0592a4e2d8c 100644 --- a/wadsrc/static/zscript/actors/hexen/boostarmor.zs +++ b/wadsrc/static/zscript/actors/hexen/boostarmor.zs @@ -32,7 +32,7 @@ class ArtiBoostArmor : Inventory for (int i = 0; i < 4; ++i) { - armor = HexenArmor(Spawn("HexenArmor")); + armor = HexenArmor(Spawn(GetHexenArmorClass())); armor.bDropped = true; armor.health = i; armor.Amount = 1; diff --git a/wadsrc/static/zscript/actors/hexen/clericflame.zs b/wadsrc/static/zscript/actors/hexen/clericflame.zs index 9672d55ee09..6630713b9af 100644 --- a/wadsrc/static/zscript/actors/hexen/clericflame.zs +++ b/wadsrc/static/zscript/actors/hexen/clericflame.zs @@ -185,7 +185,7 @@ class CircleFlame : Actor Stop; Death: CFCF QR 3 Bright; - CFCF S 3 Bright A_Explode(20, 20, 0); + CFCF S 3 Bright A_Explode(20, 128, 0); CFCF TUVWXYZ 3 Bright; Stop; } diff --git a/wadsrc/static/zscript/actors/hexen/clericholy.zs b/wadsrc/static/zscript/actors/hexen/clericholy.zs index 8f2af52a4df..e3aee9bace5 100644 --- a/wadsrc/static/zscript/actors/hexen/clericholy.zs +++ b/wadsrc/static/zscript/actors/hexen/clericholy.zs @@ -346,7 +346,7 @@ class HolySpirit : Actor { if (thing.bShootable && thing != target) { - if (multiplayer && !deathmatch && thing.player && target.player) + if (multiplayer && !deathmatch && thing.player && target && target.player) { // don't attack other co-op players return true; } diff --git a/wadsrc/static/zscript/actors/hexen/demons.zs b/wadsrc/static/zscript/actors/hexen/demons.zs index 08f81b2a816..41fdf8873ee 100644 --- a/wadsrc/static/zscript/actors/hexen/demons.zs +++ b/wadsrc/static/zscript/actors/hexen/demons.zs @@ -20,6 +20,7 @@ class Demon1 : Actor DeathSound "DemonDeath"; ActiveSound "DemonActive"; Obituary "$OB_DEMON1"; + HitObituary "$OB_DEMON1HIT"; Tag "$FN_DEMON1"; } @@ -230,6 +231,7 @@ class Demon2 : Demon1 Default { Obituary "$OB_DEMON2"; + HitObituary "$OB_DEMON2HIT"; Species "Demon2"; } States diff --git a/wadsrc/static/zscript/actors/hexen/flechette.zs b/wadsrc/static/zscript/actors/hexen/flechette.zs index cce5784ab6e..0526cebe59b 100644 --- a/wadsrc/static/zscript/actors/hexen/flechette.zs +++ b/wadsrc/static/zscript/actors/hexen/flechette.zs @@ -449,7 +449,7 @@ class PoisonCloud : Actor PSBG D 1; PSBG D 1 A_Scream; PSBG DEEEFFFGGGHHHII 2 A_PoisonBagDamage; - PSBG I 2 A_PoisonBagCheck; + PSBG I 2 A_PoisonBagDamage; PSBG I 1 A_PoisonBagCheck; Goto Spawn + 3; Death: diff --git a/wadsrc/static/zscript/actors/hexen/healingradius.zs b/wadsrc/static/zscript/actors/hexen/healingradius.zs index 852bd642ac3..508595a30cb 100644 --- a/wadsrc/static/zscript/actors/hexen/healingradius.zs +++ b/wadsrc/static/zscript/actors/hexen/healingradius.zs @@ -51,7 +51,7 @@ class ArtiHealingRadius : Inventory case 'Armor': for (int j = 0; j < 4; ++j) { - HexenArmor armor = HexenArmor(Spawn("HexenArmor")); + HexenArmor armor = HexenArmor(Spawn(GetHexenArmorClass())); armor.health = j; armor.Amount = 1; if (!armor.CallTryPickup (mo)) diff --git a/wadsrc/static/zscript/actors/hexen/iceguy.zs b/wadsrc/static/zscript/actors/hexen/iceguy.zs index c09944f17bf..6f4c6ad8ecb 100644 --- a/wadsrc/static/zscript/actors/hexen/iceguy.zs +++ b/wadsrc/static/zscript/actors/hexen/iceguy.zs @@ -169,11 +169,7 @@ class IceGuyFX : Actor { for (int i = 0; i < 8; i++) { - Actor mo = SpawnMissileAngleZ (pos.z+3, "IceGuyFX2", i*45., -0.3); - if (mo) - { - mo.target = target; - } + SpawnMissileAngleZ (pos.z+3, "IceGuyFX2", i*45., -0.3, target); } } } diff --git a/wadsrc/static/zscript/actors/hexen/magelightning.zs b/wadsrc/static/zscript/actors/hexen/magelightning.zs index 9c67b2b39af..764315ca25d 100644 --- a/wadsrc/static/zscript/actors/hexen/magelightning.zs +++ b/wadsrc/static/zscript/actors/hexen/magelightning.zs @@ -147,7 +147,7 @@ class Lightning : Actor tracer = thing; } } - return 1; // lightning zaps through all sprites + return MHIT_PASS; // lightning zaps through all sprites } } @@ -417,7 +417,7 @@ class LightningZap : Actor } } } - return -1; + return MHIT_DEFAULT; } //============================================================================ diff --git a/wadsrc/static/zscript/actors/hexen/magestaff.zs b/wadsrc/static/zscript/actors/hexen/magestaff.zs index 782310c4126..a0935e8c87b 100644 --- a/wadsrc/static/zscript/actors/hexen/magestaff.zs +++ b/wadsrc/static/zscript/actors/hexen/magestaff.zs @@ -260,9 +260,9 @@ class MageStaffFX2 : Actor if (victim != target && !victim.player && !victim.bBoss) { victim.DamageMobj (self, target, 10, 'Fire'); - return 1; // Keep going + return MHIT_PASS; // Keep going } - return -1; + return MHIT_DEFAULT; } override bool SpecialBlastHandling (Actor source, double strength) diff --git a/wadsrc/static/zscript/actors/hexen/pig.zs b/wadsrc/static/zscript/actors/hexen/pig.zs index 45c601c4e2b..95e90722e7e 100644 --- a/wadsrc/static/zscript/actors/hexen/pig.zs +++ b/wadsrc/static/zscript/actors/hexen/pig.zs @@ -145,7 +145,7 @@ class PigPlayer : PlayerPawn override void MorphPlayerThink () { - if (player.morphTics & 15) + if ((player.MorphTics ? player.MorphTics : Random[PigPlayerThink]()) & 15) { return; } diff --git a/wadsrc/static/zscript/actors/hexen/teleportother.zs b/wadsrc/static/zscript/actors/hexen/teleportother.zs index 93608470ed3..200eece06a0 100644 --- a/wadsrc/static/zscript/actors/hexen/teleportother.zs +++ b/wadsrc/static/zscript/actors/hexen/teleportother.zs @@ -163,8 +163,9 @@ class TelOtherFX1 : Actor double destAngle; [dest, destAngle] = level.PickPlayerStart(0, PPS_FORCERANDOM | PPS_NOBLOCKINGCHECK); - dest.Z = ONFLOORZ; - victim.Teleport ((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG); + if (!level.useplayerstartz) + dest.Z = ONFLOORZ; + victim.Teleport (dest, destangle, TELF_SOURCEFOG | TELF_DESTFOG); } //=========================================================================== diff --git a/wadsrc/static/zscript/actors/inventory/ammo.zs b/wadsrc/static/zscript/actors/inventory/ammo.zs index 52b3d8f2279..e30a5de604d 100644 --- a/wadsrc/static/zscript/actors/inventory/ammo.zs +++ b/wadsrc/static/zscript/actors/inventory/ammo.zs @@ -94,7 +94,7 @@ class Ammo : Inventory if (!item.bIgnoreSkill) { // extra ammo in baby mode and nightmare mode - receiving = int(receiving * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + receiving = int(receiving * (G_SkillPropertyFloat(SKILLP_AmmoFactor) * sv_ammofactor)); } int oldamount = Amount; @@ -140,7 +140,7 @@ class Ammo : Inventory // extra ammo in baby mode and nightmare mode if (!bIgnoreSkill) { - amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + amount = int(amount * (G_SkillPropertyFloat(SKILLP_AmmoFactor) * sv_ammofactor)); } let type = GetParentAmmo(); @@ -258,7 +258,7 @@ class BackpackItem : Inventory // extra ammo in baby mode and nightmare mode if (!bIgnoreSkill) { - amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + amount = int(amount * (G_SkillPropertyFloat(SKILLP_AmmoFactor) * sv_ammofactor)); } if (amount < 0) amount = 0; if (ammoitem == NULL) @@ -323,7 +323,7 @@ class BackpackItem : Inventory // extra ammo in baby mode and nightmare mode if (!bIgnoreSkill) { - amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + amount = int(amount * (G_SkillPropertyFloat(SKILLP_AmmoFactor) * sv_ammofactor)); } ammoitem.Amount += amount; if (ammoitem.Amount > ammoitem.MaxAmount && !sv_unlimited_pickup) diff --git a/wadsrc/static/zscript/actors/inventory/armor.zs b/wadsrc/static/zscript/actors/inventory/armor.zs index bc764fc2c56..8509c5bf23b 100644 --- a/wadsrc/static/zscript/actors/inventory/armor.zs +++ b/wadsrc/static/zscript/actors/inventory/armor.zs @@ -106,7 +106,7 @@ class BasicArmor : Armor { // BasicArmor that is in use is stored in the inventory as BasicArmor. // BasicArmor that is in reserve is not. - let copy = BasicArmor(Spawn("BasicArmor")); + let copy = BasicArmor(Spawn(GetBasicArmorClass())); copy.SavePercent = SavePercent != 0 ? SavePercent : 0.33335; // slightly more than 1/3 to avoid roundoff errors. copy.Amount = Amount; copy.MaxAmount = MaxAmount; @@ -127,7 +127,7 @@ class BasicArmor : Armor override bool HandlePickup (Inventory item) { - if (item.GetClass() == "BasicArmor") + if (item is "BasicArmor") { // You shouldn't be picking up BasicArmor anyway. return true; @@ -271,13 +271,13 @@ class BasicArmorBonus : Armor override bool Use (bool pickup) { - let armor = BasicArmor(Owner.FindInventory("BasicArmor")); + let armor = BasicArmor(Owner.FindInventory("BasicArmor", true)); bool result = false; // This should really never happen but let's be prepared for a broken inventory. if (armor == null) { - armor = BasicArmor(Spawn("BasicArmor")); + armor = BasicArmor(Spawn(GetBasicArmorClass())); armor.BecomeItem (); armor.Amount = 0; armor.MaxAmount = MaxSaveAmount; @@ -391,12 +391,12 @@ class BasicArmorPickup : Armor override bool Use (bool pickup) { int SaveAmount = GetSaveAmount(); - let armor = BasicArmor(Owner.FindInventory("BasicArmor")); + let armor = BasicArmor(Owner.FindInventory("BasicArmor", true)); // This should really never happen but let's be prepared for a broken inventory. if (armor == null) { - armor = BasicArmor(Spawn("BasicArmor")); + armor = BasicArmor(Spawn(GetBasicArmorClass())); armor.BecomeItem (); Owner.AddInventory (armor); } @@ -471,7 +471,7 @@ class HexenArmor : Armor // Like BasicArmor, HexenArmor is used in the inventory but not the map. // health is the slot this armor occupies. // Amount is the quantity to give (0 = normal max). - let copy = HexenArmor(Spawn("HexenArmor")); + let copy = HexenArmor(Spawn(GetHexenArmorClass())); copy.AddArmorToSlot (health, Amount); GoAwayAndDie (); return copy; diff --git a/wadsrc/static/zscript/actors/inventory/inv_misc.zs b/wadsrc/static/zscript/actors/inventory/inv_misc.zs index da362574338..7dd374932a9 100644 --- a/wadsrc/static/zscript/actors/inventory/inv_misc.zs +++ b/wadsrc/static/zscript/actors/inventory/inv_misc.zs @@ -33,12 +33,21 @@ class Key : Inventory Default { +DONTGIB; // Don't disappear due to a crusher + +INVENTORY.ISKEYITEM; Inventory.InterHubAmount 0; Inventory.PickupSound "misc/k_pkup"; } + static native clearscope bool IsLockDefined(int locknum); + static native clearscope Color GetMapColorForLock(int locknum); + static native clearscope Color GetMapColorForKey(Key key); static native clearscope int GetKeyTypeCount(); static native clearscope class GetKeyType(int index); + + override bool ShouldShareItem(Actor giver) + { + return sv_coopsharekeys; + } override bool HandlePickup (Inventory item) { @@ -92,18 +101,27 @@ class PuzzleItem : Inventory { meta int PuzzleItemNumber; meta String PuzzFailMessage; + meta Sound PuzzFailSound; property Number: PuzzleItemNumber; property FailMessage: PuzzFailMessage; + property FailSound: PuzzFailSound; Default { +NOGRAVITY +INVENTORY.INVBAR + +INVENTORY.ISKEYITEM Inventory.DefMaxAmount; Inventory.UseSound "PuzzleSuccess"; Inventory.PickupSound "misc/i_pkup"; PuzzleItem.FailMessage("$TXT_USEPUZZLEFAILED"); + PuzzleItem.FailSound "*puzzfail"; + } + + override bool ShouldShareItem(Actor giver) + { + return sv_coopsharekeys; } override bool HandlePickup (Inventory item) @@ -124,7 +142,7 @@ class PuzzleItem : Inventory return true; } // [RH] Always play the sound if the use fails. - Owner.A_StartSound ("*puzzfail", CHAN_VOICE); + Owner.A_StartSound (PuzzFailSound, CHAN_VOICE); if (Owner.CheckLocalView()) { Console.MidPrint (null, PuzzFailMessage, true); diff --git a/wadsrc/static/zscript/actors/inventory/inventory.zs b/wadsrc/static/zscript/actors/inventory/inventory.zs index b4ee7da0028..52009f2e110 100644 --- a/wadsrc/static/zscript/actors/inventory/inventory.zs +++ b/wadsrc/static/zscript/actors/inventory/inventory.zs @@ -10,6 +10,10 @@ class Inventory : Actor const BLINKTHRESHOLD = (4*32); const BONUSADD = 6; + private bool bSharingItem; // Currently being shared (avoid infinite recursions). + private bool pickedUp[MAXPLAYERS]; // If items are set to local, track who already picked it up. + private bool bCreatingCopy; // Tells GoAway that it needs to return true so a new copy of the item is spawned. + deprecated("3.7") private int ItemFlags; Actor Owner; // Who owns this item? NULL if it's still a pickup. int Amount; // Amount of item this instance has @@ -65,6 +69,8 @@ class Inventory : Actor flagdef IsHealth: ItemFlags, 22; flagdef AlwaysPickup: ItemFlags, 23; flagdef Unclearable: ItemFlags, 24; + flagdef NeverLocal: ItemFlags, 25; + flagdef IsKeyItem: ItemFlags, 26; flagdef ForceRespawnInSurvival: none, 0; flagdef PickupFlash: none, 6; @@ -255,6 +261,47 @@ class Inventory : Actor } } + virtual bool ShouldShareItem(Actor giver) + { + return false; + } + + protected void ShareItemWithPlayers(Actor giver) + { + if (bSharingItem) + return; + + int skip = giver && giver.player ? giver.PlayerNumber() : -1; + for (int i; i < MAXPLAYERS; ++i) + { + if (!playerInGame[i] || i == skip) + continue; + + let item = CreateLocalCopy(players[i].mo); + if (!item || item == self) + continue; + + item.ClearCounters(); + item.bSharingItem = true; + item.bDropped = item.bNeverLocal = true; + if (!item.CallTryPickup(players[i].mo)) + { + item.Destroy(); + continue; + } + item.bSharingItem = false; + + if (!bQuiet) + { + PrintPickupMessage(i == consoleplayer, item.PickupMessage()); + + item.PlayPickupSound(players[i].mo); + if (!bNoScreenFlash && players[i].PlayerState != PST_DEAD) + players[i].BonusCount = BONUSADD; + } + } + } + //=========================================================================== // // Inventory :: DoRespawn @@ -371,7 +418,10 @@ class Inventory : Actor { Inventory copy; - Amount = MIN(Amount, MaxAmount); + // Clamping this on local copy creation presents too many possible + // pitfalls (e.g. Health items). + if (!IsCreatingLocalCopy()) + Amount = MIN(Amount, MaxAmount); if (GoAway ()) { copy = Inventory(Spawn (GetClass())); @@ -597,8 +647,17 @@ class Inventory : Actor // unmorphed versions of a currently morphed actor cannot pick up anything. if (bUnmorphed) return false, null; - bool res; - if (CanPickup(toucher)) + // [AA] starting with true, so that CanReceive can unset it, + // if necessary: + bool res = true; + class cls = self.GetClass(); + // [AA] CanReceive lets the actor receiving the item process it first. + if (!toucher.CanReceive(self)) + { + res = false; + } + // CanPickup processes restrictions by player class. + else if (CanPickup(toucher)) { res = TryPickup(toucher); } @@ -637,6 +696,12 @@ class Inventory : Actor } } } + // [AA] Let the toucher do something with the item they've just received: + toucher.HasReceived(self, cls); + + // If the item can be shared, make sure every player gets a copy. + if (multiplayer && !deathmatch && !bDropped && ShouldShareItem(toucher)) + ShareItemWithPlayers(toucher); } return res, toucher; } @@ -758,12 +823,17 @@ class Inventory : Actor override void Touch (Actor toucher) { + bool localPickUp; let player = toucher.player; - - // If a voodoo doll touches something, pretend the real player touched it instead. - if (player != NULL) + if (player) { + // If a voodoo doll touches something, pretend the real player touched it instead. toucher = player.mo; + // Client already picked this up, so ignore them. + if (HasPickedUpLocally(toucher)) + return; + + localPickUp = CanPickUpLocally(toucher) && !ShouldStay() && !ShouldRespawn(); } bool localview = toucher.CheckLocalView(); @@ -771,9 +841,27 @@ class Inventory : Actor if (!toucher.CanTouchItem(self)) return; + Inventory give = self; + if (localPickUp) + { + give = CreateLocalCopy(toucher); + if (!give) + return; + + localPickUp = give != self; + if (localPickUp) + give.ClearCounters(); + } + bool res; - [res, toucher] = CallTryPickup(toucher); - if (!res) return; + [res, toucher] = give.CallTryPickup(toucher); + if (!res) + { + if (give != self) + give.Destroy(); + + return; + } // This is the only situation when a pickup flash should ever play. if (PickupFlash != NULL && !ShouldStay()) @@ -783,13 +871,13 @@ class Inventory : Actor if (!bQuiet) { - PrintPickupMessage(localview, PickupMessage ()); + PrintPickupMessage(localview, give.PickupMessage ()); // Special check so voodoo dolls picking up items cause the // real player to make noise. if (player != NULL) { - PlayPickupSound (player.mo); + give.PlayPickupSound (player.mo); if (!bNoScreenFlash && player.playerstate != PST_DEAD) { player.bonuscount = BONUSADD; @@ -797,7 +885,7 @@ class Inventory : Actor } else { - PlayPickupSound (toucher); + give.PlayPickupSound (toucher); } } @@ -819,6 +907,9 @@ class Inventory : Actor ac.GiveSecret(true, true); } + if (localPickUp) + PickUpLocally(toucher); + //Added by MC: Check if item taken was the roam destination of any bot for (int i = 0; i < MAXPLAYERS; i++) { @@ -853,6 +944,17 @@ class Inventory : Actor } } + //=========================================================================== + // + // Inventory :: PreTravelled + // + // Called when an item in somebody's inventory is about to be carried + // over to another map, in case it needs to do special clean-up. + // + //=========================================================================== + + virtual void PreTravelled() {} + //=========================================================================== // // Inventory :: Travelled @@ -954,6 +1056,9 @@ class Inventory : Actor protected bool GoAway () { + if (IsCreatingLocalCopy()) + return true; + // Dropped items never stick around if (bDropped) { @@ -986,9 +1091,61 @@ class Inventory : Actor if (!GoAway ()) { bSpecial = false; + if (!bNoBlockmap || !bNoSector) // make sure that the item no longer interacts with the world for the short rest of its life. + { + A_ChangeLinkFlags(1, 1); + } SetStateLabel("HoldAndDestroy"); } } + + // Check if the Actor can recieve a local copy of the item instead of outright taking it. + clearscope bool CanPickUpLocally(Actor other) const + { + return other && other.player + && multiplayer && !deathmatch && sv_localitems + && !bNeverLocal && (!bDropped || !sv_nolocaldrops); + } + + // Check if a client has already picked up this item locally. + clearscope bool HasPickedUpLocally(Actor client) const + { + return pickedUp[client.PlayerNumber()]; + } + + // When items are dropped, clear their local pick ups. + void ClearLocalPickUps() + { + DisableLocalRendering(consoleplayer, false); + for (int i; i < MAXPLAYERS; ++i) + pickedUp[i] = false; + } + + // Client picked up this item. Mark it as invisible to that specific player and + // prevent them from picking it up again. + protected void PickUpLocally(Actor client) + { + int pNum = client.PlayerNumber(); + pickedUp[pNum] = true; + DisableLocalRendering(pNum, true); + bCountItem = bCountSecret = false; + } + + // Force spawn a new version of the item. This needs to use CreateCopy so that + // any transferrable properties on the item get correctly set. + Inventory CreateLocalCopy(Actor client) + { + bCreatingCopy = true; + let item = CreateCopy(client); + bCreatingCopy = false; + + return item; + } + + protected clearscope bool IsCreatingLocalCopy() const + { + return bCreatingCopy; + } //=========================================================================== // @@ -1006,6 +1163,10 @@ class Inventory : Actor //=========================================================================== virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive, Actor inflictor = null, Actor source = null, int flags = 0) {} + + virtual Vector2 ModifyBob(Vector2 Bob, double ticfrac) {return Bob;} + + virtual Vector3, Vector3 ModifyBob3D(Vector3 Translation, Vector3 Rotation, double ticfrac) {return Translation, Rotation;} virtual bool Use (bool pickup) { return false; } diff --git a/wadsrc/static/zscript/actors/inventory/powerups.zs b/wadsrc/static/zscript/actors/inventory/powerups.zs index 6ac852aba00..5d0f0d7daaa 100644 --- a/wadsrc/static/zscript/actors/inventory/powerups.zs +++ b/wadsrc/static/zscript/actors/inventory/powerups.zs @@ -64,7 +64,7 @@ class PowerupGiver : Inventory class Powerup : Inventory { - int EffectTics; + int EffectTics, MaxEffectTics; color BlendColor; Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility double Strength; // Meaning depends on powerup - currently used only by Invisibility @@ -121,6 +121,7 @@ class Powerup : Inventory if (power.bAdditiveTime) { EffectTics += power.EffectTics; + MaxEffectTics = Max(EffectTics, MaxEffectTics); BlendColor = power.BlendColor; } // If it's not blinking yet, you can't replenish the power unless the @@ -132,7 +133,7 @@ class Powerup : Inventory // Reset the effect duration. else if (power.EffectTics > EffectTics) { - EffectTics = power.EffectTics; + EffectTics = MaxEffectTics = power.EffectTics; BlendColor = power.BlendColor; } power.bPickupGood = true; @@ -150,7 +151,7 @@ class Powerup : Inventory override Inventory CreateCopy (Actor other) { // Get the effective effect time. - EffectTics = abs (EffectTics); + EffectTics = MaxEffectTics = abs (EffectTics); // Abuse the Owner field to tell the // InitEffect method who started it; // this should be cleared afterwards, @@ -356,7 +357,11 @@ class PowerInvulnerable : Powerup { return; } - + Owner.bInvulnerable = true; + if (Mode == 'Reflective') + { + Owner.bReflective = true; + } if (Mode == 'Ghost') { if (!Owner.bShadow) @@ -565,7 +570,7 @@ class PowerInvisibility : Powerup Super.DoEffect(); // Due to potential interference with other PowerInvisibility items // the effect has to be refreshed each tic. - double ts = (Strength / 100) * (special1 + 1); + double ts = (Strength / 100.) * (special1 + 1); if (ts > 1.) ts = 1.; let newAlpha = clamp((1. - ts), 0., 1.); @@ -759,6 +764,7 @@ class PowerIronFeet : Powerup { Powerup.Duration -60; Powerup.Color "00 ff 00", 0.125; + Powerup.Mode "Normal"; } override void AbsorbDamage (int damage, Name damageType, out int newdamage, Actor inflictor, Actor source, int flags) @@ -950,7 +956,7 @@ class PowerFlight : Powerup Owner.bNoGravity = true; if (Owner.pos.Z <= Owner.floorz) { - Owner.Vel.Z = 4;; // thrust the player in the air a bit + Owner.Vel.Z = 4; // thrust the player in the air a bit } if (Owner.Vel.Z <= -35) { // stop falling scream @@ -1128,22 +1134,12 @@ class PowerWeaponLevel2 : Powerup Super.EndEffect(); if (Owner == null) return; let player = Owner.player; - if (player != NULL) + if (player != NULL && player.mo != null) { - if (player.ReadyWeapon != NULL && player.ReadyWeapon.bPowered_Up) - { - player.ReadyWeapon.EndPowerup (); - } - if (player.PendingWeapon != NULL && player.PendingWeapon != WP_NOCHANGE && - player.PendingWeapon.bPowered_Up && - player.PendingWeapon.SisterWeapon != NULL) - { - player.PendingWeapon = player.PendingWeapon.SisterWeapon; - } + player.mo.bWeaponLevel2Ended = true; } } - } //=========================================================================== @@ -1874,19 +1870,22 @@ class PowerReflection : Powerup //=========================================================================== // // PowerMorph +// Now works with monsters too! // //=========================================================================== class PowerMorph : Powerup { - Class PlayerClass; - Class MorphFlash, UnMorphFlash; + class PlayerClass; + class MonsterClass, MorphFlash, UnmorphFlash; int MorphStyle; PlayerInfo MorphedPlayer; Default { Powerup.Duration -40; + PowerMorph.MorphFlash "TeleportFog"; + PowerMorph.UnmorphFlash "TeleportFog"; } //=========================================================================== @@ -1899,19 +1898,17 @@ class PowerMorph : Powerup { Super.InitEffect(); - if (Owner != null && Owner.player != null && PlayerClass != null) + if (!Owner) + return; + + if (Owner.Morph(Owner, PlayerClass, MonsterClass, int.max, MorphStyle, MorphFlash, UnmorphFlash)) { - let realplayer = Owner.player; // Remember the identity of the player - if (realplayer.mo.MorphPlayer(realplayer, PlayerClass, 0x7fffffff/*INDEFINITELY*/, MorphStyle, MorphFlash, UnMorphFlash)) - { - Owner = realplayer.mo; // Replace the new owner in our owner; safe because we are not attached to anything yet - bCreateCopyMoved = true; // Let the caller know the "real" owner has changed (to the morphed actor) - MorphedPlayer = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) - } - else // morph failed - give the caller an opportunity to fail the pickup completely - { - bInitEffectFailed = true; // Let the caller know that the activation failed (can fail the pickup if appropriate) - } + bCreateCopyMoved = true; // Let the caller know the "real" owner has changed (to the morphed actor). + MorphedPlayer = Owner.player; + } + else + { + bInitEffectFailed = true; // Let the caller know that the activation failed (can fail the pickup if appropriate). } } @@ -1925,24 +1922,16 @@ class PowerMorph : Powerup { Super.EndEffect(); - // Abort if owner already destroyed or unmorphed - if (Owner == null || MorphedPlayer == null || Owner.alternative == null) - { + // Abort if owner already destroyed or unmorphed. + if (!Owner || !Owner.Alternative) return; - } // Abort if owner is dead; their Die() method will // take care of any required unmorphing on death. - if (MorphedPlayer.health <= 0) - { + if (Owner.player ? Owner.player.Health <= 0 : Owner.Health <= 0) return; - } - int savedMorphTics = MorphedPlayer.morphTics; - MorphedPlayer.mo.UndoPlayerMorph (MorphedPlayer, 0, !!(MorphedPlayer.MorphStyle & MRF_UNDOALWAYS)); + Owner.Unmorph(Owner, force: Owner.GetMorphStyle() & MRF_UNDOALWAYS); MorphedPlayer = null; } - - } - diff --git a/wadsrc/static/zscript/actors/inventory/stateprovider.zs b/wadsrc/static/zscript/actors/inventory/stateprovider.zs index 05aa06f22b8..e0228725856 100644 --- a/wadsrc/static/zscript/actors/inventory/stateprovider.zs +++ b/wadsrc/static/zscript/actors/inventory/stateprovider.zs @@ -89,6 +89,7 @@ class StateProvider : Inventory double bangle; double bslope = 0.; int laflags = (flags & FBF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; + FTranslatedLineTarget t; if ((flags & FBF_USEAMMO) && weapon && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { @@ -117,7 +118,7 @@ class StateProvider : Inventory if (!(flags & FBF_NORANDOM)) damage *= random[cabullet](1, 3); - let puff = LineAttack(bangle, range, bslope, damage, 'Hitscan', pufftype, laflags); + let puff = LineAttack(bangle, range, bslope, damage, 'Hitscan', pufftype, laflags, t); if (missile != null) { @@ -130,9 +131,17 @@ class StateProvider : Inventory if (!puff) { temp = true; - puff = LineAttack(bangle, range, bslope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT); + puff = LineAttack(bangle, range, bslope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT, t); } AimBulletMissile(proj, puff, flags, temp, false); + if (t.unlinked) + { + // Arbitary portals will make angle and pitch calculations unreliable. + // So use the angle and pitch we passed instead. + proj.Angle = bangle; + proj.Pitch = bslope; + proj.Vel3DFromAngle(proj.Speed, proj.Angle, proj.Pitch); + } } } } @@ -161,7 +170,7 @@ class StateProvider : Inventory if (!(flags & FBF_NORANDOM)) damage *= random[cabullet](1, 3); - let puff = LineAttack(pangle, range, slope, damage, 'Hitscan', pufftype, laflags); + let puff = LineAttack(pangle, range, slope, damage, 'Hitscan', pufftype, laflags, t); if (missile != null) { @@ -174,9 +183,17 @@ class StateProvider : Inventory if (!puff) { temp = true; - puff = LineAttack(bangle, range, bslope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT); + puff = LineAttack(bangle, range, bslope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT, t); } AimBulletMissile(proj, puff, flags, temp, false); + if (t.unlinked) + { + // Arbitary portals will make angle and pitch calculations unreliable. + // So use the angle and pitch we passed instead. + proj.Angle = bangle; + proj.Pitch = bslope; + proj.Vel3DFromAngle(proj.Speed, proj.Angle, proj.Pitch); + } } } } @@ -190,10 +207,10 @@ class StateProvider : Inventory // //========================================================================== - action Actor A_FireProjectile(class missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0) + action Actor, Actor A_FireProjectile(class missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0) { let player = self.player; - if (!player) return null; + if (!player) return null, null; let weapon = player.ReadyWeapon; @@ -203,7 +220,7 @@ class StateProvider : Inventory if (useammo && weapon && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { if (!weapon.DepleteAmmo(weapon.bAltFire, true)) - return null; // out of ammo + return null, null; // out of ammo } if (missiletype) @@ -217,14 +234,17 @@ class StateProvider : Inventory // Temporarily adjusts the pitch double saved_player_pitch = self.Pitch; self.Pitch += pitch; - let misl = SpawnPlayerMissile (missiletype, shootangle, ofs.X, ofs.Y, spawnheight, t, false, (flags & FPF_NOAUTOAIM) != 0); + + Actor misl, realmisl; + [misl, realmisl] = SpawnPlayerMissile (missiletype, shootangle, ofs.X, ofs.Y, spawnheight, t, false, (flags & FPF_NOAUTOAIM) != 0); self.Pitch = saved_player_pitch; + if (realmisl && flags & FPF_TRANSFERTRANSLATION) + realmisl.Translation = Translation; + // automatic handling of seeker missiles if (misl) { - if (flags & FPF_TRANSFERTRANSLATION) - misl.Translation = Translation; if (t.linetarget && !t.unlinked && misl.bSeekerMissile) misl.tracer = t.linetarget; if (!(flags & FPF_AIMATANGLE)) @@ -235,9 +255,9 @@ class StateProvider : Inventory misl.VelFromAngle(misl.Vel.XY.Length()); } } - return misl; + return misl, realmisl; } - return null; + return null, null; } //========================================================================== diff --git a/wadsrc/static/zscript/actors/inventory/weapons.zs b/wadsrc/static/zscript/actors/inventory/weapons.zs index 06854da9dcf..66a7f8964cb 100644 --- a/wadsrc/static/zscript/actors/inventory/weapons.zs +++ b/wadsrc/static/zscript/actors/inventory/weapons.zs @@ -25,6 +25,7 @@ class Weapon : StateProvider int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + double WeaponScaleX, WeaponScaleY; // [XA] Weapon scale. Defines the scale for the held weapon sprites (PSprite). Defaults to (1.0, 1.2) since that's what Doom does. Ammo Ammo1, Ammo2; // In-inventory instance variables Weapon SisterWeapon; double FOVScale; @@ -36,6 +37,14 @@ class Weapon : StateProvider // AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works meta int SlotNumber; meta double SlotPriority; + + Vector3 BobPivot3D; // Pivot used for BobWeapon3D + + virtual ui Vector2 ModifyBobLayer(Vector2 Bob, int layer, double ticfrac) { return Bob; } + + virtual ui Vector3, Vector3 ModifyBobLayer3D(Vector3 Translation, Vector3 Rotation, int layer, double ticfrac) { return Translation, Rotation; } + + virtual ui Vector3 ModifyBobPivotLayer3D(int layer, double ticfrac) { return BobPivot3D; } property AmmoGive: AmmoGive1; property AmmoGive1: AmmoGive1; @@ -57,9 +66,12 @@ class Weapon : StateProvider property BobSpeed: BobSpeed; property BobRangeX: BobRangeX; property BobRangeY: BobRangeY; + property WeaponScaleX: WeaponScaleX; + property WeaponScaleY: WeaponScaleY; property SlotNumber: SlotNumber; property SlotPriority: SlotPriority; property LookScale: LookScale; + property BobPivot3D : BobPivot3D; flagdef NoAutoFire: WeaponFlags, 0; // weapon does not autofire flagdef ReadySndHalf: WeaponFlags, 1; // ready sound is played ~1/2 the time @@ -80,6 +92,7 @@ class Weapon : StateProvider flagdef NoDeathDeselect: WeaponFlags, 16; // Don't jump to the Deselect state when the player dies flagdef NoDeathInput: WeaponFlags, 17; // The weapon cannot be fired/reloaded/whatever when the player is dead flagdef CheatNotWeapon: WeaponFlags, 18; // Give cheat considers this not a weapon (used by Sigil) + flagdef NoAutoSwitchTo : WeaponFlags, 19; // do not auto switch to this weapon ever! // no-op flags flagdef NoLMS: none, 0; @@ -94,8 +107,11 @@ class Weapon : StateProvider Weapon.BobSpeed 1.0; Weapon.BobRangeX 1.0; Weapon.BobRangeY 1.0; + Weapon.WeaponScaleX 1.0; + Weapon.WeaponScaleY 1.2; Weapon.SlotNumber -1; Weapon.SlotPriority 32767; + Weapon.BobPivot3D (0.0, 0.0, 0.0); +WEAPONSPAWN DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; } @@ -213,6 +229,24 @@ class Weapon : StateProvider // //--------------------------------------------------------------------------- + action void ResetPSprite(PSprite psp) + { + if (!psp) return; + psp.rotation = 0; + psp.baseScale.x = invoker.WeaponScaleX; + psp.baseScale.y = invoker.WeaponScaleY; + psp.scale.x = 1; + psp.scale.y = 1; + psp.pivot.x = 0; + psp.pivot.y = 0; + psp.valign = 0; + psp.halign = 0; + psp.Coord0 = (0,0); + psp.Coord1 = (0,0); + psp.Coord2 = (0,0); + psp.Coord3 = (0,0); + } + action void A_Lower(int lowerspeed = 6) { let player = player; @@ -228,7 +262,7 @@ class Weapon : StateProvider } let psp = player.GetPSprite(PSP_WEAPON); if (!psp) return; - if (player.morphTics || player.cheats & CF_INSTANTWEAPSWITCH) + if (Alternative || player.cheats & CF_INSTANTWEAPSWITCH) { psp.y = WEAPONBOTTOM; } @@ -240,6 +274,8 @@ class Weapon : StateProvider { // Not lowered all the way yet return; } + ResetPSprite(psp); + if (player.playerstate == PST_DEAD) { // Player is dead, so don't bring up a pending weapon // Player is dead, so keep the weapon off screen @@ -278,12 +314,18 @@ class Weapon : StateProvider } let psp = player.GetPSprite(PSP_WEAPON); if (!psp) return; + + if (psp.y <= WEAPONBOTTOM) + { + ResetPSprite(psp); + } psp.y -= raisespeed; if (psp.y > WEAPONTOP) { // Not raised all the way yet return; } psp.y = WEAPONTOP; + psp.SetState(player.ReadyWeapon.GetReadyState()); return; } @@ -428,6 +470,7 @@ class Weapon : StateProvider if (flags & 1) { // Make the zoom instant. player.FOV = player.DesiredFOV * zoom; + player.cheats |= CF_NOFOVINTERP; } if (flags & 2) { // Disable pitch/yaw scaling. @@ -710,13 +753,13 @@ class Weapon : StateProvider // [BC] This behavior is from the original Doom. Give 5/2 times as much ammoitem when // we pick up a weapon in deathmatch. - if (( deathmatch ) && ( gameinfo.gametype & GAME_DoomChex )) + if (( deathmatch && !sv_noextraammo ) && ( gameinfo.gametype & GAME_DoomChex )) amount = amount * 5 / 2; // extra ammoitem in baby mode and nightmare mode if (!bIgnoreSkill) { - amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + amount = int(amount * (G_SkillPropertyFloat(SKILLP_AmmoFactor) * sv_ammofactor)); } ammoitem = Ammo(other.FindInventory (ammotype)); if (ammoitem == NULL) @@ -751,7 +794,7 @@ class Weapon : StateProvider // extra ammo in baby mode and nightmare mode if (!bIgnoreSkill) { - amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + amount = int(amount * (G_SkillPropertyFloat(SKILLP_AmmoFactor) * sv_ammofactor)); } ammo.Amount += amount; if (ammo.Amount > ammo.MaxAmount && !sv_unlimited_pickup) @@ -824,9 +867,10 @@ class Weapon : StateProvider { if (player.PendingWeapon == NULL || player.PendingWeapon == WP_NOCHANGE) { - player.PendingWeapon = SisterWeapon; + player.refire = 0; + player.ReadyWeapon = SisterWeapon; + player.SetPsprite(PSP_WEAPON, SisterWeapon.GetReadyState()); } - player.WeaponState |= WF_REFIRESWITCHOK; } else { @@ -842,9 +886,10 @@ class Weapon : StateProvider if (player.PendingWeapon == NULL || player.PendingWeapon == WP_NOCHANGE) { // Something went wrong. Initiate a regular weapon change. - player.PendingWeapon = SisterWeapon; + player.refire = 0; + player.ReadyWeapon = SisterWeapon; + player.SetPsprite(PSP_WEAPON, SisterWeapon.GetReadyState()); } - player.WeaponState |= WF_REFIRESWITCHOK; } } } @@ -893,6 +938,7 @@ class Weapon : StateProvider int count1, count2; int enough, enoughmask; int lAmmoUse1; + int lAmmoUse2 = AmmoUse2; if (sv_infiniteammo || (Owner.FindInventory ('PowerInfiniteAmmo', true) != null)) { @@ -922,16 +968,17 @@ class Weapon : StateProvider { lAmmoUse1 = 0; } - else if (ammocount >= 0 && bDehAmmo) + else if (ammocount >= 0) { lAmmoUse1 = ammocount; + lAmmoUse2 = ammocount; } else { lAmmoUse1 = AmmoUse1; } - enough = (count1 >= lAmmoUse1) | ((count2 >= AmmoUse2) << 1); + enough = (count1 >= lAmmoUse1) | ((count2 >= lAmmoUse2) << 1); if (useboth) { enoughmask = 3; @@ -967,7 +1014,7 @@ class Weapon : StateProvider // //=========================================================================== - virtual bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1) + virtual bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1, bool forceammouse = false) { if (!(sv_infiniteammo || (Owner.FindInventory ('PowerInfiniteAmmo', true) != null))) { @@ -979,7 +1026,7 @@ class Weapon : StateProvider { if (Ammo1 != null) { - if (ammouse >= 0 && bDehAmmo) + if (ammouse >= 0 && (bDehAmmo || forceammouse)) { Ammo1.Amount -= ammouse; } diff --git a/wadsrc/static/zscript/actors/inventory_util.zs b/wadsrc/static/zscript/actors/inventory_util.zs index 6b65b64205f..011ca134f4c 100644 --- a/wadsrc/static/zscript/actors/inventory_util.zs +++ b/wadsrc/static/zscript/actors/inventory_util.zs @@ -291,6 +291,8 @@ extend class Actor { Inventory drop = item.CreateTossable(amt); if (drop == null) return NULL; + drop.ClearLocalPickUps(); + drop.bNeverLocal = true; drop.SetOrigin(Pos + (0, 0, 10.), false); drop.Angle = Angle; drop.VelFromAngle(5.); @@ -814,7 +816,61 @@ extend class Actor } } + + int GetAmmoCapacity(class type) + { + if (type != NULL) + { + let item = FindInventory(type); + if (item != NULL) + { + return item.MaxAmount; + } + else + { + return GetDefaultByType(type).MaxAmount; + } + } + return 0; + } + + void SetAmmoCapacity(class type, int amount) + { + if (type != NULL) + { + let item = FindInventory(type); + if (item != NULL) + { + item.MaxAmount = amount; + } + else + { + item = GiveInventoryType(type); + if (item != NULL) + { + item.MaxAmount = amount; + item.Amount = 0; + } + } + } + } + + clearscope static class GetBasicArmorClass() + { + class cls = (class)(GameInfo.BasicArmorClass); + if (cls) + return cls; + return "BasicArmor"; + } + clearscope static class GetHexenArmorClass() + { + class cls = (class)(GameInfo.HexenArmorClass); + if (cls) + return cls; + + return "HexenArmor"; + } } diff --git a/wadsrc/static/zscript/actors/mbf21.zs b/wadsrc/static/zscript/actors/mbf21.zs new file mode 100644 index 00000000000..c7fc2a8fb94 --- /dev/null +++ b/wadsrc/static/zscript/actors/mbf21.zs @@ -0,0 +1,513 @@ +// no attempt has been made to merge this with existing code. +extend class Actor +{ + // + // [XA] New mbf21 codepointers + // + + // + // A_SpawnObject + // Basically just A_Spawn with better behavior and more args. + // args[0]: Type of actor to spawn + // args[1]: Angle (degrees, in fixed point), relative to calling actor's angle + // args[2]: X spawn offset (fixed point), relative to calling actor + // args[3]: Y spawn offset (fixed point), relative to calling actor + // args[4]: Z spawn offset (fixed point), relative to calling actor + // args[5]: X velocity (fixed point) + // args[6]: Y velocity (fixed point) + // args[7]: Z velocity (fixed point) + // + deprecated("2.3", "for Dehacked use only") + void MBF21_SpawnObject(class type, double angle, double xofs, double yofs, double zofs, double xvel, double yvel, double zvel) + { + if (type == null) + return; + + // Don't spawn monsters if this actor has been massacred + if (DamageType == 'Massacre' && GetDefaultByType(type).bIsMonster) + { + return; + } + + // calculate position offsets + angle += self.Angle; + double s = sin(angle); + double c = cos(angle); + let pos = Vec2Offset(xofs * c - yofs * s, xofs * s + yofs * c); + + // spawn it, yo + let mo = Spawn(type, (pos, self.pos.Z - Floorclip + GetBobOffset() + zofs), ALLOW_REPLACE); + if (!mo) + return; + + // angle dangle + mo.angle = angle; + + // set velocity + // Same orientation issue here! + mo.vel.X = xvel * c - yvel * s; + mo.vel.Y = xvel * s + yvel * c; + mo.vel.Z = zvel; + + // if spawned object is a missile, set target+tracer + if (mo.bMissile || mo.bMbfBouncer) + { + // if spawner is also a missile, copy 'em + if (default.bMissile || default.bMbfBouncer) + { + mo.target = self.target; + mo.tracer = self.tracer; + } + // otherwise, set 'em as if a monster fired 'em + else + { + mo.target = self; + mo.tracer = self.target; + } + } + + // [XA] don't bother with the dont-inherit-friendliness hack + // that exists in A_Spawn, 'cause WTF is that about anyway? + + // unfortunately this means that this function cannot transfer friendliness at all. Oh well... + } + + // + // A_MonsterProjectile + // A parameterized monster projectile attack. + // args[0]: Type of actor to spawn + // args[1]: Angle (degrees, in fixed point), relative to calling actor's angle + // args[2]: Pitch (degrees, in fixed point), relative to calling actor's pitch; approximated + // args[3]: X/Y spawn offset, relative to calling actor's angle + // args[4]: Z spawn offset, relative to actor's default projectile fire height + // + deprecated("2.3", "for Dehacked use only") + void MBF21_MonsterProjectile(class type, double angle, double pitch, double spawnofs_xy, double spawnofs_z) + { + if (!target || !type) + return; + + A_FaceTarget(); + let mo = SpawnMissile(target, type); + if (!mo) + return; + + // adjust angle + mo.angle += angle; + + Pitch += mo.PitchFromVel(); + let missilespeed = abs(cos(Pitch) * mo.Speed); + mo.Vel3DFromAngle(mo.Speed, mo.angle, Pitch); + + // adjust position + double x = Spawnofs_xy * cos(self.angle); + double y = Spawnofs_xy * sin(self.angle); + mo.SetOrigin(mo.Vec3Offset(x, y, Spawnofs_z), false); + + // always set the 'tracer' field, so this pointer + // can be used to fire seeker missiles at will. + mo.tracer = target; + } + + // + // A_MonsterBulletAttack + // A parameterized monster bullet attack. + // args[0]: Horizontal spread (degrees, in fixed point) + // args[1]: Vertical spread (degrees, in fixed point) + // args[2]: Number of bullets to fire; if not set, defaults to 1 + // args[3]: Base damage of attack (e.g. for 3d5, customize the 3); if not set, defaults to 3 + // args[4]: Attack damage modulus (e.g. for 3d5, customize the 5); if not set, defaults to 5 + // + deprecated("2.3", "for Dehacked use only") + void MBF21_MonsterBulletAttack(double hspread, double vspread, int numbullets, int damagebase, int damagemod) + { + if (!target) + return; + + A_FaceTarget(); + A_StartSound(AttackSound, CHAN_WEAPON); + + let bangle = angle; + let slope = AimLineAttack(bangle, MISSILERANGE); + + for (int i = 0; i < numbullets; i++) + { + int damage = (random[mbf21]() % damagemod + 1) * damagebase; + let pangle = bangle + hspread * Random2[mbf21]() / 255.; + let pslope = slope + vspread * Random2[mbf21]() / 255.; + LineAttack(pangle, MISSILERANGE, pslope, damage, "Hitscan", "Bulletpuff"); + } + } + + // + // A_MonsterMeleeAttack + // A parameterized monster melee attack. + // args[0]: Base damage of attack (e.g. for 3d8, customize the 3); if not set, defaults to 3 + // args[1]: Attack damage modulus (e.g. for 3d8, customize the 8); if not set, defaults to 8 + // args[2]: Sound to play if attack hits + // args[3]: Range (fixed point); if not set, defaults to monster's melee range + // + deprecated("2.3", "for Dehacked use only") + void MBF21_MonsterMeleeAttack(int damagebase, int damagemod, Sound hitsound, double range) + { + let targ = target; + if (!targ) + return; + + if (range == 0) range = meleerange; + else range -= 20; // DSDA always subtracts 20 from the melee range. + + A_FaceTarget(); + if (!CheckMeleeRange(range)) + return; + + A_StartSound(hitsound, CHAN_WEAPON); + + int damage = (random[mbf21]() % damagemod + 1) * damagebase; + int newdam = targ.DamageMobj(self, self, damage, "Melee"); + targ.TraceBleed(newdam > 0 ? newdam : damage, self); + } + + // + // A_NoiseAlert + // Alerts nearby monsters (via sound) to the calling actor's target's presence. + // + void A_NoiseAlert() + { + if (target) SoundAlert(target); + } + + // + // A_HealChase + // A parameterized version of A_VileChase. + // args[0]: State to jump to on the calling actor when resurrecting a corpse + // args[1]: Sound to play when resurrecting a corpse + // + deprecated("2.3", "for Dehacked use only") + void MBF21_HealChase(State healstate, Sound healsound) + { + if (!A_CheckForResurrection(healstate, healsound)) + A_Chase(); + } + + // + // A_FindTracer + // Search for a valid tracer (seek target), if the calling actor doesn't already have one. + // args[0]: field-of-view to search in (degrees, in fixed point); if zero, will search in all directions + // args[1]: distance to search (map blocks, i.e. 128 units) + // + void A_FindTracer(double fov, int dist) + { + // note: mbf21 fov is the angle of the entire cone, while + // zdoom fov is defined as 1/2 of the cone, so halve it. + if (!tracer) tracer = RoughMonsterSearch(dist, fov: fov/2); + } + + // + // A_ClearTracer + // Clear current tracer (seek target). + // + void A_ClearTracer() + { + tracer = NULL; + } + + // + // A_JumpIfHealthBelow + // Jumps to a state if caller's health is below the specified threshold. + // args[0]: State to jump to + // args[1]: Health threshold + // + deprecated("2.3", "for Dehacked use only") + void MBF21_JumpIfHealthBelow(State tstate, int health) + { + if (self.health < health) self.SetState(tstate); + } + + // + // A_JumpIfTargetInSight + // Jumps to a state if caller's target is in line-of-sight. + // args[0]: State to jump to + // args[1]: Field-of-view to check (degrees, in fixed point); if zero, will check in all directions + // + deprecated("2.3", "for Dehacked use only") + void MBF21_JumpIfTargetInSight(State tstate, double fov) + { + if (!target) + return; + + // Check FOV first since it's faster + if (fov > 0 && !CheckFov(target, fov)) + return; + + if (CheckSight(target)) self.SetState(tstate); + } + + // + // A_JumpIfTargetCloser + // Jumps to a state if caller's target is closer than the specified distance. + // args[0]: State to jump to + // args[1]: Distance threshold + // + deprecated("2.3", "for Dehacked use only") + void MBF21_JumpIfTargetCloser(State tstate, double dist) + { + if (!target) + return; + + if (dist > Distance2D(target)) self.SetState(tstate); + } + + // + // A_JumpIfTracerInSight + // Jumps to a state if caller's tracer (seek target) is in line-of-sight. + // args[0]: State to jump to + // args[1]: Field-of-view to check (degrees, in fixed point); if zero, will check in all directions + // + deprecated("2.3", "for Dehacked use only") + void MBF21_JumpIfTracerInSight(State tstate, double fov) + { + if (!tracer) + return; + + // Check FOV first since it's faster + if (fov > 0 && !CheckFov(tracer, fov)) + return; + + if (CheckSight(tracer)) self.SetState(tstate); + } + + // + // A_JumpIfTracerCloser + // Jumps to a state if caller's tracer (seek target) is closer than the specified distance. + // args[0]: State to jump to + // args[1]: Distance threshold (fixed point) + // + deprecated("2.3", "for Dehacked use only") + void MBF21_JumpIfTracerCloser(State tstate, double dist) + { + if (!tracer) + return; + + if (dist > Distance2D(tracer)) self.SetState(tstate); + } + + // These are native to lock away the insanity. + deprecated("2.3", "for Dehacked use only") native void MBF21_JumpIfFlagsSet(State tstate, int flags, int flags2); + deprecated("2.3", "for Dehacked use only") native void MBF21_AddFlags(int flags, int flags2); + deprecated("2.3", "for Dehacked use only") native void MBF21_RemoveFlags(int flags, int flags2); +} + +extend class Weapon +{ + // + // A_WeaponProjectile + // A parameterized player weapon projectile attack. Does not consume ammo. + // args[0]: Type of actor to spawn + // args[1]: Angle (degrees, in fixed point), relative to calling player's angle + // args[2]: Pitch (degrees, in fixed point), relative to calling player's pitch; approximated + // args[3]: X/Y spawn offset, relative to calling player's angle + // args[4]: Z spawn offset, relative to player's default projectile fire height + // + deprecated("2.3", "for Dehacked use only") + void MBF21_WeaponProjectile(class type, double angle, double pitch, double Spawnofs_xy, double Spawnofs_z) + { + if (!player || !type) + return; + + FTranslatedLineTarget t; + + angle += self.angle; + Vector2 ofs = AngleToVector(self.Angle - 90, spawnofs_xy); + + let mo = SpawnPlayerMissile(type, angle, ofs.x, ofs.y, Spawnofs_z, pLineTarget: t); + if (!mo) return; + + Pitch += mo.PitchFromVel(); + mo.Vel3DFromAngle(mo.Speed, mo.angle, Pitch); + + // set tracer to the player's autoaim target, + // so player seeker missiles prioritizing the + // baddie the player is actually aiming at. ;) + mo.tracer = t.linetarget; + } + + // + // A_WeaponBulletAttack + // A parameterized player weapon bullet attack. Does not consume ammo. + // args[0]: Horizontal spread (degrees, in fixed point) + // args[1]: Vertical spread (degrees, in fixed point) + // args[2]: Number of bullets to fire; if not set, defaults to 1 + // args[3]: Base damage of attack (e.g. for 5d3, customize the 5); if not set, defaults to 5 + // args[4]: Attack damage modulus (e.g. for 5d3, customize the 3); if not set, defaults to 3 + // + deprecated("2.3", "for Dehacked use only") + void MBF21_WeaponBulletAttack(double hspread, double vspread, int numbullets, int damagebase, int damagemod) + { + let bangle = angle; + let slope = BulletSlope(); + + for (int i = 0; i < numbullets; i++) + { + int damage = (random[mbf21]() % damagemod + 1) * damagebase; + let pangle = bangle + hspread * Random2[mbf21]() / 255.; + let pslope = slope + vspread * Random2[mbf21]() / 255.; + LineAttack(pangle, PLAYERMISSILERANGE, pslope, damage, "Hitscan", "Bulletpuff"); + } + } + + + // + // A_WeaponMeleeAttack + // A parameterized player weapon melee attack. + // args[0]: Base damage of attack (e.g. for 2d10, customize the 2); if not set, defaults to 2 + // args[1]: Attack damage modulus (e.g. for 2d10, customize the 10); if not set, defaults to 10 + // args[2]: Berserk damage multiplier (fixed point); if not set, defaults to 1.0 (no change). + // args[3]: Sound to play if attack hits + // args[4]: Range (fixed point); if not set, defaults to player mobj's melee range + // + deprecated("2.3", "for Dehacked use only") + void MBF21_WeaponMeleeAttack(int damagebase, int damagemod, double zerkfactor, Sound hitsound, double range) + { + if (range == 0) + range = meleerange; + + int damage = (Random[mbf21]() % damagemod + 1) * damagebase; + if (FindInventory("PowerStrength")) + damage = int(damage * zerkfactor); + + // slight randomization; weird vanillaism here. :P + FTranslatedLineTarget t; + double ang = angle + Random2[mbf21]() * (5.625 / 256); + double pitch = AimLineAttack(ang, range + MELEEDELTA, t, 0., ALF_CHECK3D); + LineAttack(ang, range, pitch, damage, 'Melee', "BulletPuff", LAF_ISMELEEATTACK, t); + + // turn to face target + if (t.linetarget) + { + A_StartSound(hitsound, CHAN_WEAPON); + angle = t.angleFromSource; + } + } + + // + // A_WeaponAlert + // Alerts monsters to the player's presence. Handy when combined with WPF_SILENT. + // + void A_WeaponAlert() + { + SoundAlert(self); + } + + // + // A_WeaponJump + // Jumps to the specified state, with variable random chance. + // Basically the same as A_RandomJump, but for weapons. + // args[0]: State number + // args[1]: Chance, out of 255, to make the jump + // + deprecated("2.3", "for Dehacked use only") + action void MBF21_WeaponJump(State tstate, int chance) + { + if (stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + let player = self.player; + if (player == null) return; + if (random[mbf21]() < chance) + player.SetPSprite(stateinfo.mPSPIndex, tstate); + } + } + + // + // A_ConsumeAmmo + // Subtracts ammo from the player's "inventory". 'Nuff said. + // args[0]: Amount of ammo to consume. If zero, use the weapon's ammo-per-shot amount. + // + deprecated("2.3", "for Dehacked use only") + void MBF21_ConsumeAmmo(int consume) + { + let player = self.player; + if (!player) return; + let weap = player.ReadyWeapon; + if (!weap) return; + + if (consume == 0) consume = -1; + weap.DepleteAmmo(weap.bAltFire, false, consume, true); + } + + // + // A_CheckAmmo + // Jumps to a state if the player's ammo is lower than the specified amount. + // args[0]: State to jump to + // args[1]: Minimum required ammo to NOT jump. If zero, use the weapon's ammo-per-shot amount. + // + deprecated("2.3", "for Dehacked use only") + action void MBF21_CheckAmmo(State tstate, int amount) + { + if (stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + let player = self.player; + if (player == null) return; + let weap = player.ReadyWeapon; + if (!weap) return; + + if (amount == 0) amount = -1; + if (!weap.CheckAmmo(weap.bAltFire ? AltFire : PrimaryFire, false, false, amount)) + player.SetPSprite(stateinfo.mPSPIndex, tstate); + } + } + + // + // A_RefireTo + // Jumps to a state if the player is holding down the fire button + // args[0]: State to jump to + // args[1]: If nonzero, skip the ammo check + // + deprecated("2.3", "for Dehacked use only") + action void MBF21_RefireTo(State tstate, int skipcheck) + { + if (stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + let player = self.player; + if (player == null) return; + let weap = player.ReadyWeapon; + if (!weap) return; + + let pending = player.PendingWeapon != WP_NOCHANGE && (player.WeaponState & WF_REFIRESWITCHOK); + + if (!skipcheck && !weap.CheckAmmo(weap.bAltFire ? AltFire : PrimaryFire, false, false)) return; + + if ((player.cmd.buttons & BT_ATTACK) + && !player.ReadyWeapon.bAltFire && !pending && player.health > 0) + { + player.SetPSprite(stateinfo.mPSPIndex, tstate); + } + } + } + + // + // A_GunFlashTo + // Sets the weapon flash layer to the specified state. + // args[0]: State number + // args[1]: If nonzero, don't change the player actor state + // + deprecated("2.3", "for Dehacked use only") + void MBF21_GunFlashTo(State tstate, int dontchangeplayer) + { + let player = self.player; + if (player == null) return; + Weapon weapon = player.ReadyWeapon; + if (!weapon) return; + + if (!dontchangeplayer) player.mo.PlayAttacking2(); + player.SetPsprite(PSP_FLASH, tstate); + } + + // needed to call A_SeekerMissile with proper defaults. + deprecated("2.3", "for Dehacked use only") + void MBF21_SeekTracer(double threshold, double turnmax) + { + A_SeekerMissile(int(threshold), int(turnmax), flags: SMF_PRECISE); // args get truncated to ints here, but it's close enough + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/actors/morph.zs b/wadsrc/static/zscript/actors/morph.zs index 1dcfb31faff..5ebbb59f0ce 100644 --- a/wadsrc/static/zscript/actors/morph.zs +++ b/wadsrc/static/zscript/actors/morph.zs @@ -23,12 +23,83 @@ extend class Actor { + // Blockmap, sector, and no interaction are the only relevant flags but the old ones are kept around + // for legacy reasons. + enum EPremorphProperty + { + MPROP_SOLID = 1 << 1, + MPROP_SHOOTABLE = 1 << 2, + MPROP_NO_BLOCKMAP = 1 << 3, + MPROP_NO_SECTOR = 1 << 4, + MPROP_NO_INTERACTION = 1 << 5, + MPROP_INVIS = 1 << 6, + } + + native int UnmorphTime; + native int MorphFlags; + native class MorphExitFlash; + native int PremorphProperties; + + // Players still track these separately for legacy reasons. + void SetMorphStyle(EMorphFlags flags) + { + if (player) + player.MorphStyle = flags; + else + MorphFlags = flags; + } + + clearscope EMorphFlags GetMorphStyle() const + { + return player ? player.MorphStyle : MorphFlags; + } + + void SetMorphExitFlash(class flash) + { + if (player) + player.MorphExitFlash = flash; + else + MorphExitFlash = flash; + } + + clearscope class GetMorphExitFlash() const + { + return player ? player.MorphExitFlash : MorphExitFlash; + } + + void SetMorphTics(int dur) + { + if (player) + player.MorphTics = dur; + else + UnmorphTime = Level.Time + dur; + } + + clearscope int GetMorphTics() const + { + if (player) + return player.MorphTics; + + if (UnmorphTime <= 0) + return UnmorphTime; + + return UnmorphTime > Level.Time ? UnmorphTime - Level.Time : 0; + } + + // This function doesn't return anything anymore since allowing so would be too volatile + // for morphing management. Instead it's now a function that lets special actions occur + // when a morphed Actor dies. virtual Actor, int, int MorphedDeath() { + EMorphFlags mStyle = GetMorphStyle(); + if (mStyle & MRF_UNDOBYDEATH) + Unmorph(self, force: mStyle & MRF_UNDOBYDEATHFORCED); + return null, 0, 0; } // [MC] Called when an actor morphs, on both the previous form (!current) and present form (current). + // Due to recent changes, these are now called internally instead of within the virtuals. virtual void PreMorph(Actor mo, bool current) {} virtual void PostMorph(Actor mo, bool current) {} virtual void PreUnmorph(Actor mo, bool current) {} @@ -40,16 +111,12 @@ extend class Actor // //=========================================================================== - virtual bool Morph(Actor activator, class playerclass, class monsterclass, int duration = 0, int style = 0, class morphflash = null, classunmorphflash = null) + virtual bool Morph(Actor activator, class playerClass, class monsterClass, int duration = 0, EMorphFlags style = 0, class morphFlash = "TeleportFog", class unmorphFlash = "TeleportFog") { - if (player != null && player.mo != null && playerclass != null) - { - return player.mo.MorphPlayer(activator? activator.player : null, playerclass, duration, style, morphflash, unmorphflash); - } - else - { - return MorphMonster(monsterclass, duration, style, morphflash, unmorphflash); - } + if (player) + return player.mo.MorphPlayer(activator ? activator.player : null, playerClass, duration, style, morphFlash, unmorphFlash); + + return MorphMonster(monsterClass, duration, style, morphFlash, unmorphFlash); } //=========================================================================== @@ -58,18 +125,9 @@ extend class Actor // //=========================================================================== - bool A_Morph(class type, int duration = 0, int style = 0, class morphflash = null, classunmorphflash = null) + bool A_Morph(class type, int duration = 0, EMorphFlags style = 0, class morphFlash = "TeleportFog", class unmorphFlash = "TeleportFog") { - if (self.player != null) - { - let playerclass = (class)(type); - if (playerclass && self.player.mo != null) return player.mo.MorphPlayer(self.player, playerclass, duration, style, morphflash, unmorphflash); - } - else - { - return MorphMonster(type, duration, style, morphflash, unmorphflash); - } - return false; + return Morph(self, (class)(type), type, duration, style, morphFlash, unmorphFlash); } //=========================================================================== @@ -78,21 +136,18 @@ extend class Actor // //=========================================================================== - virtual bool UnMorph(Actor activator, int flags, bool force) + virtual bool Unmorph(Actor activator, EMorphFlags flags = 0, bool force = false) { if (player) - { - return player.mo.UndoPlayerMorph(activator? activator.player : null, flags, force); - } - else - { - let morphed = MorphedMonster(self); - if (morphed) - return morphed.UndoMonsterMorph(force); - } - return false; + return player.mo.UndoPlayerMorph(activator ? activator.player : null, flags, force); + + return UndoMonsterMorph(force); } + virtual bool CheckUnmorph() + { + return UnmorphTime && UnmorphTime <= Level.Time && Unmorph(self, MRF_UNDOBYTIMEOUT); + } //--------------------------------------------------------------------------- // @@ -102,57 +157,265 @@ extend class Actor // //--------------------------------------------------------------------------- - virtual bool MorphMonster (Class spawntype, int duration, int style, Class enter_flash, Class exit_flash) + virtual bool MorphMonster(class spawnType, int duration, EMorphFlags style, class enterFlash = "TeleportFog", class exitFlash = "TeleportFog") { - if (player || spawntype == NULL || bDontMorph || !bIsMonster || !(spawntype is 'MorphedMonster')) + if (player || !bIsMonster || !spawnType || bDontMorph || Health <= 0 || spawnType == GetClass()) + return false; + + Actor morphed = Spawn(spawnType, Pos, ALLOW_REPLACE); + if (!MorphInto(morphed)) { + if (morphed) + { + morphed.ClearCounters(); + morphed.Destroy(); + } + return false; } - let morphed = MorphedMonster(Spawn (spawntype, Pos, NO_REPLACE)); - // [MC] Notify that we're just about to start the transfer. PreMorph(morphed, false); // False: No longer the current. morphed.PreMorph(self, true); // True: Becoming this actor. - Substitute (morphed); if ((style & MRF_TRANSFERTRANSLATION) && !morphed.bDontTranslate) - { morphed.Translation = Translation; - } - morphed.ChangeTid(tid); - ChangeTid(0); + morphed.Angle = Angle; - morphed.UnmorphedMe = self; morphed.Alpha = Alpha; morphed.RenderStyle = RenderStyle; - morphed.Score = Score; - - morphed.UnmorphTime = level.time + ((duration) ? duration : DEFMORPHTICS) + random[morphmonst](); - morphed.MorphStyle = style; - morphed.MorphExitFlash = (exit_flash) ? exit_flash : (class)("TeleportFog"); - morphed.FlagsSave = bSolid * 2 + bShootable * 4 + bInvisible * 0x40; // The factors are for savegame compatibility - - morphed.special = special; - morphed.args[0] = args[0]; - morphed.args[1] = args[1]; - morphed.args[2] = args[2]; - morphed.args[3] = args[3]; - morphed.args[4] = args[4]; - morphed.CopyFriendliness (self, true); morphed.bShadow |= bShadow; morphed.bGhost |= bGhost; - special = 0; - bSolid = false; - bShootable = false; - bUnmorphed = true; + morphed.Score = Score; + morphed.Special = Special; + for (int i; i < 5; ++i) + morphed.Args[i] = Args[i]; + + if (TID && (style & MRF_NEWTIDBEHAVIOUR)) + { + morphed.ChangeTID(TID); + ChangeTID(0); + } + + morphed.Tracer = Tracer; + morphed.Master = Master; + morphed.CopyFriendliness(self, true); + + // Remove all armor. + if (!(style & MRF_KEEPARMOR)) + { + for (Inventory item = morphed.Inv; item;) + { + Inventory next = item.Inv; + if (item is "Armor") + item.DepleteOrDestroy(); + + item = next; + } + } + + morphed.SetMorphTics((duration ? duration : DEFMORPHTICS) + Random[morphmonst]()); + morphed.SetMorphStyle(style); + morphed.SetMorphExitFlash(exitFlash); + morphed.PremorphProperties = (bSolid * MPROP_SOLID) | (bShootable * MPROP_SHOOTABLE) + | (bNoBlockmap * MPROP_NO_BLOCKMAP) | (bNoSector * MPROP_NO_SECTOR) + | (bNoInteraction * MPROP_NO_INTERACTION) | (bInvisible * MPROP_INVIS); + + // This is just here for backwards compatibility as MorphedMonster used to be required. + let morphMon = MorphedMonster(morphed); + if (morphMon) + { + morphMon.UnmorphedMe = morphMon.Alternative; + morphMon.MorphStyle = morphMon.GetMorphStyle(); + morphMon.FlagsSave = morphMon.PremorphProperties; + } + + Special = 0; + bNoInteraction = true; + A_ChangeLinkFlags(true, true); + + // Legacy bInvisible = true; - let eflash = Spawn(enter_flash ? enter_flash : (class)("TeleportFog"), Pos + (0, 0, gameinfo.TELEFOGHEIGHT), ALLOW_REPLACE); - if (eflash) - eflash.target = morphed; + bSolid = bShootable = false; + PostMorph(morphed, false); morphed.PostMorph(self, true); + + if (enterFlash) + { + Actor fog = Spawn(enterFlash, morphed.Pos.PlusZ(GameInfo.TELEFOGHEIGHT), ALLOW_REPLACE); + if (fog) + fog.Target = morphed; + } + + return true; + } + + //---------------------------------------------------------------------------- + // + // FUNC P_UndoMonsterMorph + // + // Returns true if the monster unmorphs. + // + //---------------------------------------------------------------------------- + + virtual bool UndoMonsterMorph(bool force = false) + { + if (!Alternative || bStayMorphed || Alternative.bStayMorphed) + return false; + + Actor alt = Alternative; + alt.SetOrigin(Pos, false); + if (!force && (PremorphProperties & MPROP_SOLID)) + { + bool altSolid = alt.bSolid; + bool isSolid = bSolid; + bool isTouchy = bTouchy; + + alt.bSolid = true; + bSolid = bTouchy = false; + + bool res = alt.TestMobjLocation(); + + alt.bSolid = altSolid; + bSolid = isSolid; + bTouchy = isTouchy; + + // Didn't fit. + if (!res) + { + SetMorphTics(5 * TICRATE); + return false; + } + } + + if (!MorphInto(alt)) + return false; + + PreUnmorph(alt, false); + alt.PreUnmorph(self, true); + + // Check to see if it had a powerup that caused it to morph. + for (Inventory item = alt.Inv; item;) + { + Inventory next = item.Inv; + if (item is "PowerMorph") + item.Destroy(); + + item = next; + } + + alt.Angle = Angle; + alt.bShadow = bShadow; + alt.bGhost = bGhost; + alt.bSolid = (PremorphProperties & MPROP_SOLID); + alt.bShootable = (PremorphProperties & MPROP_SHOOTABLE); + alt.bInvisible = (PremorphProperties & MPROP_INVIS); + alt.Vel = Vel; + alt.Score = Score; + + alt.bNoInteraction = (PremorphProperties & MPROP_NO_INTERACTION); + alt.A_ChangeLinkFlags((PremorphProperties & MPROP_NO_BLOCKMAP), (PremorphProperties & MPROP_NO_SECTOR)); + + EMorphFlags style = GetMorphStyle(); + if (TID && (style & MRF_NEWTIDBEHAVIOUR)) + { + alt.ChangeTID(TID); + ChangeTID(0); + } + + alt.Special = Special; + for (int i; i < 5; ++i) + alt.Args[i] = Args[i]; + + alt.Tracer = Tracer; + alt.Master = Master; + alt.CopyFriendliness(self, true, false); + if (Health > 0 || (style & MRF_UNDOBYDEATHSAVES)) + alt.Health = alt.SpawnHealth(); + else + alt.Health = Health; + + Special = 0; + + PostUnmorph(alt, false); // From is false here: Leaving the caller's body. + alt.PostUnmorph(self, true); // True here: Entering this body from here. + + if (MorphExitFlash) + { + Actor fog = Spawn(MorphExitFlash, alt.Pos.PlusZ(GameInfo.TELEFOGHEIGHT), ALLOW_REPLACE); + if (fog) + fog.Target = alt; + } + + ClearCounters(); + Destroy(); return true; } } +//=========================================================================== +// +// +// +//=========================================================================== + +class MorphProjectile : Actor +{ + class PlayerClass; + class MonsterClass, MorphFlash, UnmorphFlash; + int Duration, MorphStyle; + + Default + { + Damage 1; + Projectile; + MorphProjectile.MorphFlash "TeleportFog"; + MorphProjectile.UnmorphFlash "TeleportFog"; + + -ACTIVATEIMPACT + -ACTIVATEPCROSS + } + + override int DoSpecialDamage(Actor victim, int dmg, Name dmgType) + { + victim.Morph(Target, PlayerClass, MonsterClass, Duration, MorphStyle, MorphFlash, UnmorphFlash); + return -1; + } +} + +//=========================================================================== +// +// This class is redundant as it's no longer necessary for monsters to +// morph but is kept here for compatibility. Its previous fields either exist +// in the base Actor now or are just a shell for the actual fields +// which either already existed and weren't used for some reason or needed a +// better name. +// +//=========================================================================== + +class MorphedMonster : Actor +{ + Actor UnmorphedMe; + EMorphFlags MorphStyle; + EPremorphProperty FlagsSave; + + Default + { + Monster; + + +FLOORCLIP + -COUNTKILL + } + + // Make sure changes to these are propogated correctly when unmorphing. This is only + // set for monsters since originally players and this class were the only ones + // that were considered valid for morphing. + override bool UndoMonsterMorph(bool force) + { + Alternative = UnmorphedMe; + SetMorphStyle(MorphStyle); + PremorphProperties = FlagsSave; + return super.UndoMonsterMorph(force); + } +} diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index 3a57277393c..69e534b70fc 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -40,15 +40,19 @@ class PlayerPawn : Actor double SideMove1, SideMove2; TextureID ScoreIcon; int SpawnMask; - Name MorphWeapon; + Name MorphWeapon; // This should really be a class but it's too late to change now. double AttackZOffset; // attack height, relative to player center double UseRange; // [NS] Distance at which player can +use double AirCapacity; // Multiplier for air supply underwater. Class FlechetteType; color DamageFade; // [CW] Fades for when you are being damaged. + double FlyBob; // [B] Fly bobbing mulitplier double ViewBob; // [SP] ViewBob Multiplier + double ViewBobSpeed; // [AA] ViewBob speed multiplier + double WaterClimbSpeed; // [B] Speed when climbing up walls in water double FullHeight; double curBob; + double prevBob; meta Name HealingRadiusType; meta Name InvulMode; @@ -74,11 +78,20 @@ class PlayerPawn : Actor property FlechetteType: FlechetteType; property Portrait: Portrait; property TeleportFreezeTime: TeleportFreezeTime; + property FlyBob: FlyBob; property ViewBob: ViewBob; + property ViewBobSpeed: ViewBobSpeed; + property WaterClimbSpeed : WaterClimbSpeed; flagdef NoThrustWhenInvul: PlayerFlags, 0; flagdef CanSuperMorph: PlayerFlags, 1; flagdef CrouchableMorph: PlayerFlags, 2; + flagdef WeaponLevel2Ended: PlayerFlags, 3; + + enum EPrivatePlayerFlags + { + PF_VOODOO_ZOMBIE = 1<<4, + } Default { @@ -115,7 +128,10 @@ class PlayerPawn : Actor Player.MugShotMaxHealth 0; Player.FlechetteType "ArtiPoisonBag3"; Player.AirCapacity 1; + Player.FlyBob 1; Player.ViewBob 1; + Player.ViewBobSpeed 20; + Player.WaterClimbSpeed 3.5; Player.TeleportFreezeTime 18; Obituary "$OB_MPDEFAULT"; } @@ -137,6 +153,21 @@ class PlayerPawn : Actor { if (health > 0) Height = FullHeight; } + + if (player && bWeaponLevel2Ended && !(player.cheats & CF_PREDICTING)) + { + bWeaponLevel2Ended = false; + if (player.ReadyWeapon != NULL && player.ReadyWeapon.bPowered_Up) + { + player.ReadyWeapon.EndPowerup (); + } + if (player.PendingWeapon != NULL && player.PendingWeapon != WP_NOCHANGE && + player.PendingWeapon.bPowered_Up && + player.PendingWeapon.SisterWeapon != NULL) + { + player.PendingWeapon = player.PendingWeapon.SisterWeapon; + } + } Super.Tick(); } @@ -148,6 +179,9 @@ class PlayerPawn : Actor override void BeginPlay() { + // Force create this since players can predict. + SetViewPos((0.0, 0.0, 0.0)); + Super.BeginPlay (); ChangeStatNum (STAT_PLAYER); FullHeight = Height; @@ -237,6 +271,11 @@ class PlayerPawn : Actor invul.EffectTics = 3 * TICRATE; invul.BlendColor = 0; // don't mess with the view invul.bUndroppable = true; // Don't drop self + if (!invul.CallTryPickup(self)) + { + invul.Destroy(); + return; + } bRespawnInvul = true; // [RH] special effect } } @@ -316,8 +355,8 @@ class PlayerPawn : Actor (player.ReadyWeapon == NULL || player.ReadyWeapon.bWimpy_Weapon)) { let best = BestWeapon (ammotype); - if (best != NULL && (player.ReadyWeapon == NULL || - best.SelectionOrder < player.ReadyWeapon.SelectionOrder)) + if (best != NULL && !best.bNoAutoSwitchTo && + (player.ReadyWeapon == NULL || best.SelectionOrder < player.ReadyWeapon.SelectionOrder)) { player.PendingWeapon = best; } @@ -439,8 +478,9 @@ class PlayerPawn : Actor virtual void CheckWeaponChange () { let player = self.player; + if (!player) return; if ((player.WeaponState & WF_DISABLESWITCH) || // Weapon changing has been disabled. - player.morphTics != 0) // Morphed classes cannot change weapons. + Alternative) // Morphed classes cannot change weapons. { // ...so throw away any pending weapon requests. player.PendingWeapon = WP_NOCHANGE; } @@ -537,7 +577,7 @@ class PlayerPawn : Actor } else if (bNoGravity && !player.onground) { - player.bob = 0.5; + player.bob = min(abs(0.5 * FlyBob), MAXBOB); } else { @@ -567,7 +607,11 @@ class PlayerPawn : Actor return; } - if (still) + if (bFly && !GetCVar("FViewBob")) + { + bob = 0; + } + else if (still) { if (player.health > 0) { @@ -581,7 +625,7 @@ class PlayerPawn : Actor } else { - angle = Level.maptime / (20 * TICRATE / 35.) * 360.; + angle = Level.maptime / (ViewBobSpeed * TICRATE / 35.) * 360.; bob = player.bob * sin(angle) * (waterlevel > 1 ? 0.25f : 0.5f); } @@ -610,11 +654,12 @@ class PlayerPawn : Actor } } - if (player.morphTics) + if (Alternative) { bob = 0; } player.viewz = pos.Z + player.viewheight + (bob * clamp(ViewBob, 0. , 1.5)); // [SP] Allow DECORATE changes to view bobbing speed. + if (Floorclip && player.playerstate != PST_DEAD && pos.Z <= floorz) { @@ -743,14 +788,16 @@ class PlayerPawn : Actor Super.Die (source, inflictor, dmgflags, MeansOfDeath); if (player != NULL && player.mo == self) player.bonuscount = 0; - - if (player != NULL && player.mo != self) + + // [RL0] To allow voodoo zombies, don't kill the player together with voodoo dolls if the compat flag is enabled + if (player != NULL && player.mo != self && !(Level.compatflags2 & COMPATF2_VOODOO_ZOMBIES)) { // Make the real player die, too player.mo.Die (source, inflictor, dmgflags, MeansOfDeath); } else { - if (player != NULL && sv_weapondrop) + // [RL0] player.mo == self will always be true if COMPATF2_VOODOO_ZOMBIES is false, so there's no need to check the compatflag here too, just self + if (player != NULL && sv_weapondrop && player.mo == self) { // Voodoo dolls don't drop weapons let weap = player.ReadyWeapon; if (weap != NULL) @@ -823,7 +870,7 @@ class PlayerPawn : Actor // //=========================================================================== - void FilterCoopRespawnInventory (PlayerPawn oldplayer) + void FilterCoopRespawnInventory (PlayerPawn oldplayer, Weapon curHeldWeapon = null) { // If we're losing everything, this is really simple. if (sv_cooploseinventory) @@ -832,6 +879,10 @@ class PlayerPawn : Actor return; } + // Make sure to get the real held weapon before messing with the inventory. + if (curHeldWeapon && curHeldWeapon.bPowered_Up) + curHeldWeapon = curHeldWeapon.SisterWeapon; + // Walk through the old player's inventory and destroy or modify // according to dmflags. Inventory next; @@ -844,7 +895,7 @@ class PlayerPawn : Actor // inventory amount. let defitem = FindInventory (item.GetClass()); - if (sv_cooplosekeys && defitem == NULL && item is 'Key') + if ((sv_cooplosekeys && !sv_coopsharekeys) && defitem == NULL && item is 'Key') { item.Destroy(); } @@ -913,7 +964,15 @@ class PlayerPawn : Actor ObtainInventory (oldplayer); player.ReadyWeapon = NULL; - PickNewWeapon (NULL); + if (curHeldWeapon && curHeldWeapon.owner == self && curHeldWeapon.CheckAmmo(Weapon.EitherFire, false)) + { + player.PendingWeapon = curHeldWeapon; + BringUpWeapon(); + } + else + { + PickNewWeapon (NULL); + } } @@ -927,6 +986,8 @@ class PlayerPawn : Actor { let player = self.player; + if (!player) return; + // [RH] Zoom the player's FOV float desired = player.DesiredFOV; // Adjust FOV using on the currently held weapon. @@ -1026,7 +1087,7 @@ class PlayerPawn : Actor virtual bool CanCrouch() const { - return player.morphTics == 0 || bCrouchableMorph; + return !Alternative || bCrouchableMorph; } //---------------------------------------------------------------------------- @@ -1192,7 +1253,7 @@ class PlayerPawn : Actor side *= SideMove2; } - if (!player.morphTics) + if (!Alternative) { double factor = 1.; for(let it = Inv; it != null; it = it.Inv) @@ -1205,6 +1266,12 @@ class PlayerPawn : Actor return forward, side; } + virtual void ApplyAirControl(out double movefactor, out double bobfactor) + { + movefactor *= level.aircontrol; + bobfactor *= level.aircontrol; + } + //---------------------------------------------------------------------------- // // PROC P_MovePlayer @@ -1248,8 +1315,8 @@ class PlayerPawn : Actor if (!player.onground && !bNoGravity && !waterlevel) { // [RH] allow very limited movement if not on ground. - movefactor *= level.aircontrol; - bobfactor*= level.aircontrol; + // [AA] but also allow authors to override it. + ApplyAirControl(movefactor, bobfactor); } fm = cmd.forwardmove; @@ -1482,15 +1549,15 @@ class PlayerPawn : Actor { let player = self.player; // Morph counter - if (player.morphTics) + if (Alternative) { if (player.chickenPeck) { // Chicken attack counter player.chickenPeck -= 3; } - if (!--player.morphTics) + if (player.MorphTics && !--player.MorphTics) { // Attempt to undo the chicken/pig - player.mo.UndoPlayerMorph(player, MRF_UNDOBYTIMEOUT); + Unmorph(self, MRF_UNDOBYTIMEOUT); } } } @@ -1573,6 +1640,12 @@ class PlayerPawn : Actor { let player = self.player; UserCmd cmd = player.cmd; + + // [RL0] Mark players that became zombies (this stays even if they 'revive' by healing, until a level change) + if((Level.compatflags2 & COMPATF2_VOODOO_ZOMBIES) && player.health <= 0 && player.mo.health > 0) + { + PlayerFlags |= PF_VOODOO_ZOMBIE; + } CheckFOV(); @@ -1609,7 +1682,7 @@ class PlayerPawn : Actor player.jumpTics = 0; } } - if (player.morphTics && !(player.cheats & CF_PREDICTING)) + if (Alternative && !(player.cheats & CF_PREDICTING)) { MorphPlayerThink (); } @@ -1634,6 +1707,8 @@ class PlayerPawn : Actor if (player.hazardcount) { player.hazardcount--; + if (player.hazardinterval <= 0) + player.hazardinterval = 32; // repair invalid hazardinterval if (!(Level.maptime % player.hazardinterval) && player.hazardcount > 16*TICRATE) player.mo.DamageMobj (NULL, NULL, 5, player.hazardtype); } @@ -1654,13 +1729,20 @@ class PlayerPawn : Actor void BringUpWeapon () { + // [RL0] Don't bring up weapon when in a voodoo zombie state + if(PlayerFlags & PF_VOODOO_ZOMBIE) return; + let player = self.player; if (player.PendingWeapon == WP_NOCHANGE) { if (player.ReadyWeapon != null) { let psp = player.GetPSprite(PSP_WEAPON); - if (psp) psp.y = WEAPONTOP; + if (psp) + { + psp.y = WEAPONTOP; + player.ReadyWeapon.ResetPSprite(psp); + } player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); } return; @@ -1824,8 +1906,8 @@ class PlayerPawn : Actor // it provides player class based protection that should not affect // any other protection item. let myclass = GetClass(); - GiveInventoryType('HexenArmor'); - let harmor = HexenArmor(FindInventory('HexenArmor')); + GiveInventoryType(GetHexenArmorClass()); + let harmor = HexenArmor(FindInventory('HexenArmor', true)); harmor.Slots[4] = self.HexenArmor[0]; for (int i = 0; i < 4; ++i) @@ -1836,7 +1918,7 @@ class PlayerPawn : Actor // BasicArmor must come right after that. It should not affect any // other protection item as well but needs to process the damage // before the HexenArmor does. - GiveInventoryType('BasicArmor'); + GiveInventoryType(GetBasicArmorClass()); // Now add the items from the DECORATE definition let di = GetDropItems(); @@ -1863,6 +1945,7 @@ class PlayerPawn : Actor { item = Inventory(Spawn(ti)); item.bIgnoreSkill = true; // no skill multipliers here + item.bDropped = item.bNeverLocal = true; // Avoid possible copies. item.Amount = di.Amount; let weap = Weapon(item); if (weap) @@ -1965,12 +2048,25 @@ class PlayerPawn : Actor void PlayerFinishLevel (int mode, int flags) { + // [RL0] Handle player exit behavior for voodoo zombies + if(PlayerFlags & PF_VOODOO_ZOMBIE) + { + if(player.health > 0) + { + PlayerFlags &= ~PF_VOODOO_ZOMBIE; + } + else + { + bShootable = false; + bKilled = true; + } + } Inventory item, next; let p = player; - if (p.morphTics != 0) + if (Alternative) { // Undo morph - Unmorph(self, 0, true); + Unmorph(self, force: true); } // 'self' will be no longer valid from here on in case of an unmorph let me = p.mo; @@ -2014,7 +2110,7 @@ class PlayerPawn : Actor next = item.Inv; if (item.InterHubAmount < 1) { - item.Destroy (); + item.DepleteOrDestroy (); } item = next; } @@ -2040,7 +2136,7 @@ class PlayerPawn : Actor let it = toDelete[i]; if (!it.bDestroyed) { - item.DepleteOrDestroy(); + it.DepleteOrDestroy(); } } } @@ -2057,8 +2153,17 @@ class PlayerPawn : Actor me.ClearInventory(); me.GiveDefaultInventory(); } + + // [MK] notify self and inventory that we're about to travel + // this must be called here so these functions can still have a + // chance to alter the world before a snapshot is done in hubs + me.PreTravelled(); + for (item = me.Inv; item != NULL; item = item.Inv) + { + item.PreTravelled(); + } } - + //=========================================================================== // // FWeaponSlot :: PickWeapon @@ -2301,8 +2406,6 @@ class PlayerPawn : Actor Vector2 p1, p2, r; Vector2 result; - float bobtarget; - let player = self.player; if (!player) return (0, 0); let weapon = player.ReadyWeapon; @@ -2326,17 +2429,16 @@ class PlayerPawn : Actor // [RH] Smooth transitions between bobbing and not-bobbing frames. // This also fixes the bug where you can "stick" a weapon off-center by // shooting it when it's at the peak of its swing. - bobtarget = double((player.WeaponState & WF_WEAPONBOBBING) ? player.bob : 0.); - if (curbob != bobtarget) + if (curbob != player.bob) { - if (abs(bobtarget - curbob) <= 1) + if (abs(player.bob - curbob) <= 1) { - curbob = bobtarget; + curbob = player.bob; } else { - double zoom = MAX(1., abs(curbob - bobtarget) / 40); - if (curbob > bobtarget) + double zoom = MAX(1., abs(curbob - player.bob) / 40); + if (curbob > player.bob) { curbob -= zoom; } @@ -2347,11 +2449,19 @@ class PlayerPawn : Actor } } + // The weapon bobbing intensity while firing can be adjusted by the player. + double BobIntensity = (player.WeaponState & WF_WEAPONBOBBING) ? 1. : player.GetWBobFire(); + if (curbob != 0) { + double bobVal = player.bob; + if (i == 0) + { + bobVal = prevBob; + } //[SP] Added in decorate player.viewbob checks - double bobx = (player.bob * Rangex * ViewBob); - double boby = (player.bob * Rangey * ViewBob); + double bobx = (bobVal * BobIntensity * Rangex * ViewBob); + double boby = (bobVal * BobIntensity * Rangey * ViewBob); switch (bobstyle) { case Bob_Normal: @@ -2392,6 +2502,12 @@ class PlayerPawn : Actor } return p1 * (1. - ticfrac) + p2 * ticfrac; } + + virtual Vector3 /*translation*/ , Vector3 /*rotation*/ BobWeapon3D (double ticfrac) + { + Vector2 oldBob = BobWeapon(ticfrac); + return (0, 0, 0) , ( oldBob.x / 4, oldBob.y / -4, 0); + } //---------------------------------------------------------------------------- // @@ -2430,6 +2546,30 @@ class PlayerPawn : Actor return wasdrowning; } + //=========================================================================== + // + // PlayerPawn :: PreTravelled + // + // Called before the player moves to another map, in case it needs to do + // special clean-up. This is called right before all carried items + // execute their respective PreTravelled() virtuals. + // + //=========================================================================== + + virtual void PreTravelled() {} + + //=========================================================================== + // + // PlayerPawn :: Travelled + // + // Called when the player moves to another map, in case it needs to do + // special reinitialization. This is called after all carried items have + // executed their respective Travelled() virtuals too. + // + //=========================================================================== + + virtual void Travelled() {} + //---------------------------------------------------------------------------- // // @@ -2536,9 +2676,20 @@ class PSprite : Object native play native double y; native double oldx; native double oldy; + native Vector2 baseScale; + native Vector2 pivot; + native Vector2 scale; + native double rotation; + native int HAlign, VAlign; + native Vector2 Coord0; // [MC] Not the actual coordinates. Just the offsets by A_OverlayVertexOffset. + native Vector2 Coord1; + native Vector2 Coord2; + native Vector2 Coord3; native double alpha; native Bool firstTic; + native bool InterpolateTic; native int Tics; + native TranslationID Translation; native bool bAddWeapon; native bool bAddBob; native bool bPowDouble; @@ -2546,6 +2697,8 @@ class PSprite : Object native play native bool bFlip; native bool bMirror; native bool bPlayerTranslated; + native bool bPivotPercent; + native bool bInterpolate; native void SetState(State newstate, bool pending = false); @@ -2559,13 +2712,23 @@ class PSprite : Object native play { if (processPending) { - // drop tic count and possibly change state - if (Tics != -1) // a -1 tic count never changes + if (Caller) + { + Caller.PSpriteTick(self); + if (bDestroyed) + return; + } + + if (processPending) { - Tics--; - // [BC] Apply double firing speed. - if (bPowDouble && Tics && (Owner.mo.FindInventory ("PowerDoubleFiringSpeed", true))) Tics--; - if (!Tics && Caller != null) SetState(CurState.NextState); + // drop tic count and possibly change state + if (Tics != -1) // a -1 tic count never changes + { + Tics--; + // [BC] Apply double firing speed. + if (bPowDouble && Tics && (Owner.mo.FindInventory ("PowerDoubleFiringSpeed", true))) Tics--; + if (!Tics && Caller != null) SetState(CurState.NextState); + } } } } @@ -2638,8 +2801,8 @@ struct PlayerInfo native play // self is what internally is known as player_t native int killcount; native int itemcount; native int secretcount; - native int damagecount; - native int bonuscount; + native uint damagecount; + native uint bonuscount; native int hazardcount; native int hazardinterval; native Name hazardtype; @@ -2698,43 +2861,37 @@ struct PlayerInfo native play // self is what internally is known as player_t native void SetSubtitleNumber (int text, Sound sound_id = 0); native bool Resurrect(); - native String GetUserName() const; - native Color GetColor() const; - native Color GetDisplayColor() const; - native int GetColorSet() const; - native int GetPlayerClassNum() const; - native int GetSkin() const; - native bool GetNeverSwitch() const; - native int GetGender() const; - native int GetTeam() const; - native float GetAutoaim() const; - native bool GetNoAutostartMap() const; + native clearscope String GetUserName(uint charLimit = 0u) const; + native clearscope Color GetColor() const; + native clearscope Color GetDisplayColor() const; + native clearscope int GetColorSet() const; + native clearscope int GetPlayerClassNum() const; + native clearscope int GetSkin() const; + native clearscope bool GetNeverSwitch() const; + native clearscope int GetGender() const; + native clearscope int GetTeam() const; + native clearscope float GetAutoaim() const; + native clearscope bool GetNoAutostartMap() const; native double GetWBobSpeed() const; + native double GetWBobFire() const; native double GetMoveBob() const; + native bool GetFViewBob() const; native double GetStillBob() const; native void SetFOV(float fov); - native bool GetClassicFlight() const; + native clearscope bool GetClassicFlight() const; native void SendPitchLimits(); native clearscope bool HasWeaponsInSlot(int slot) const; // The actual implementation is on PlayerPawn where it can be overridden. Use that directly in the future. - deprecated("3.7", "MorphPlayer() should be used on a PlayerPawn object") bool MorphPlayer(playerinfo p, Class spawntype, int duration, int style, Class enter_flash = null, Class exit_flash = null) + deprecated("3.7", "MorphPlayer() should be used on a PlayerPawn object") bool MorphPlayer(PlayerInfo activator, class spawnType, int duration, EMorphFlags style, class enterFlash = "TeleportFog", class exitFlash = "TeleportFog") { - if (mo != null) - { - return mo.MorphPlayer(p, spawntype, duration, style, enter_flash, exit_flash); - } - return false; + return mo ? mo.MorphPlayer(activator, spawnType, duration, style, enterFlash, exitFlash) : false; } // This somehow got its arguments mixed up. 'self' should have been the player to be unmorphed, not the activator - deprecated("3.7", "UndoPlayerMorph() should be used on a PlayerPawn object") bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false) + deprecated("3.7", "UndoPlayerMorph() should be used on a PlayerPawn object") bool UndoPlayerMorph(PlayerInfo player, EMorphFlags unmorphFlags = 0, bool force = false) { - if (player.mo != null) - { - return player.mo.UndoPlayerMorph(self, unmorphflag, force); - } - return false; + return player.mo ? player.mo.UndoPlayerMorph(self, unmorphFlags, force) : false; } deprecated("3.7", "DropWeapon() should be used on a PlayerPawn object") void DropWeapon() @@ -2750,7 +2907,7 @@ struct PlayerInfo native play // self is what internally is known as player_t if (mo) mo.BringUpWeapon(); } - bool IsTotallyFrozen() + clearscope bool IsTotallyFrozen() const { return gamestate == GS_TITLELEVEL || @@ -2826,7 +2983,17 @@ struct PlayerSkin native struct Team native { - const NoTeam = 255; - const Max = 16; + const NOTEAM = 255; + const MAX = 16; + native String mName; + + native static bool IsValid(uint teamIndex); + native play static bool ChangeTeam(uint playerNumber, uint newTeamIndex); + + native Color GetPlayerColor() const; + native int GetTextColor() const; + native TextureID GetLogo() const; + native string GetLogoName() const; + native bool AllowsCustomPlayerColor() const; } diff --git a/wadsrc/static/zscript/actors/player/player_cheat.zs b/wadsrc/static/zscript/actors/player/player_cheat.zs index d1e8d269476..3fbb5f30b64 100644 --- a/wadsrc/static/zscript/actors/player/player_cheat.zs +++ b/wadsrc/static/zscript/actors/player/player_cheat.zs @@ -42,6 +42,11 @@ extend class PlayerPawn } native void CheatSuicide(); + + private bool CheckArtifact(class type) + { + return !(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor") && !(type is "Key") && !(type is "Weapon"); + } virtual void CheatGive (String name, int amount) { @@ -134,7 +139,7 @@ extend class PlayerPawn { for (i = 0; i < 4; ++i) { - let armoritem = Inventory(Spawn("HexenArmor")); + let armoritem = Inventory(Spawn(GetHexenArmorClass())); armoritem.health = i; armoritem.Amount = 0; if (!armoritem.CallTryPickup (self)) @@ -175,7 +180,7 @@ extend class PlayerPawn for (i = 0; i < AllActorClasses.Size(); ++i) { let type = (class)(AllActorClasses[i]); - if (type != null && type != "Weapon") + if (type != null && type != "Weapon" && !type.isAbstract()) { // Don't give replaced weapons unless the replacement was done by Dehacked. let rep = GetReplacement(type); @@ -207,8 +212,7 @@ extend class PlayerPawn if (type!= null) { let def = GetDefaultByType (type); - if (def.Icon.isValid() && def.MaxAmount > 1 && - !(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor")) + if (def.Icon.isValid() && (def.MaxAmount > 1 || def.bAutoActivate == false) && CheckArtifact(type)) { // Do not give replaced items unless using "give everything" if (giveall == ALL_YESYES || GetReplacement(type) == type) @@ -364,7 +368,7 @@ extend class PlayerPawn for (int i = 0; i < AllActorClasses.Size(); ++i) { type = (class)(AllActorClasses[i]); - if (type!= null && !(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor")) + if (type!= null && CheckArtifact(type)) { let pack = FindInventory(type); if (pack) pack.Destroy(); @@ -422,35 +426,40 @@ extend class PlayerPawn } - virtual String CheatMorph(class morphClass, bool quickundo) + virtual String CheatMorph(class morphClass, bool undo) { - let oldclass = GetClass(); - // Set the standard morph style for the current game - int style = MRF_UNDOBYTOMEOFPOWER; - if (gameinfo.gametype == GAME_Hexen) style |= MRF_UNDOBYCHAOSDEVICE; + EMorphFlags style = MRF_UNDOBYTOMEOFPOWER; + if (GameInfo.GameType == GAME_Hexen) + style |= MRF_UNDOBYCHAOSDEVICE; - if (player.morphTics) + if (Alternative) { - if (UndoPlayerMorph (player)) + class cls = GetClass(); + Actor mo = Alternative; + if (!undo || Unmorph(self)) { - if (!quickundo && oldclass != morphclass && MorphPlayer (player, morphclass, 0, style)) + if ((!undo && Morph(self, morphClass, null, 0, style)) + || (undo && morphClass != cls && mo.Morph(mo, morphClass, null, 0, style))) { return StringTable.Localize("$TXT_STRANGER"); } - return StringTable.Localize("$TXT_NOTSTRANGE"); + + if (undo) + return StringTable.Localize("$TXT_NOTSTRANGE"); } } - else if (MorphPlayer (player, morphclass, 0, style)) + else if (Morph(self, morphClass, null, 0, style)) { return StringTable.Localize("$TXT_STRANGE"); } + return ""; } virtual void CheatTakeWeaps() { - if (player.morphTics || health <= 0) + if (Alternative || health <= 0) { return; } diff --git a/wadsrc/static/zscript/actors/player/player_morph.zs b/wadsrc/static/zscript/actors/player/player_morph.zs index 66fd0f1d811..85d21d2509a 100644 --- a/wadsrc/static/zscript/actors/player/player_morph.zs +++ b/wadsrc/static/zscript/actors/player/player_morph.zs @@ -2,23 +2,24 @@ extend class PlayerPawn { //=========================================================================== // - // EndAllPowerupEffects + // InitAllPowerupEffects // - // Calls EndEffect() on every Powerup in the inventory list. + // Calls InitEffect() on every Powerup in the inventory list. Since these + // functions can be overridden it's safest to store what's next in the item + // list before calling it. // //=========================================================================== void InitAllPowerupEffects() { - let item = Inv; - while (item != null) + for (Inventory item = Inv; item;) { + Inventory next = item.Inv; let power = Powerup(item); - if (power != null) - { + if (power) power.InitEffect(); - } - item = item.Inv; + + item = next; } } @@ -32,15 +33,14 @@ extend class PlayerPawn void EndAllPowerupEffects() { - let item = Inv; - while (item != null) + for (Inventory item = Inv; item;) { + Inventory next = item.Inv; let power = Powerup(item); - if (power != null) - { + if (power) power.EndEffect(); - } - item = item.Inv; + + item = next; } } @@ -50,43 +50,37 @@ extend class PlayerPawn // //=========================================================================== - virtual void ActivateMorphWeapon () + virtual void ActivateMorphWeapon() { - class morphweaponcls = MorphWeapon; - player.PendingWeapon = WP_NOCHANGE; - - if (player.ReadyWeapon != null) + if (player.ReadyWeapon) { let psp = player.GetPSprite(PSP_WEAPON); - if (psp) psp.y = WEAPONTOP; + psp.y = WEAPONTOP; + player.ReadyWeapon.ResetPSprite(psp); } - - if (morphweaponcls == null || !(morphweaponcls is 'Weapon')) - { // No weapon at all while morphed! + + class morphWeapCls = MorphWeapon; + if (!morphWeapCls) + { player.ReadyWeapon = null; } else { - player.ReadyWeapon = Weapon(FindInventory (morphweaponcls)); - if (player.ReadyWeapon == null) - { - player.ReadyWeapon = Weapon(GiveInventoryType (morphweaponcls)); - if (player.ReadyWeapon != null) - { - player.ReadyWeapon.GivenAsMorphWeapon = true; // flag is used only by new beastweap semantics in UndoPlayerMorph - } - } - if (player.ReadyWeapon != null) + player.ReadyWeapon = Weapon(FindInventory(morphWeapCls)); + if (!player.ReadyWeapon) { - player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); + player.ReadyWeapon = Weapon(GiveInventoryType(morphWeapCls)); + if (player.ReadyWeapon) + player.ReadyWeapon.GivenAsMorphWeapon = true; // Flag is used only by new morphWeap semantics in UndoPlayerMorph } - } - if (player.ReadyWeapon != null) - { - player.SetPsprite(PSP_FLASH, null); + if (player.ReadyWeapon) + player.SetPSprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); } + if (player.ReadyWeapon) + player.SetPSprite(PSP_FLASH, null); + player.PendingWeapon = WP_NOCHANGE; } @@ -101,124 +95,119 @@ extend class PlayerPawn // //--------------------------------------------------------------------------- - virtual bool MorphPlayer(playerinfo activator, Class spawntype, int duration, int style, Class enter_flash = null, Class exit_flash = null) + virtual bool MorphPlayer(PlayerInfo activator, class spawnType, int duration, EMorphFlags style, class enterFlash = "TeleportFog", class exitFlash = "TeleportFog") { - if (bDontMorph) - { - return false; - } - if (bInvulnerable && (player != activator || !(style & MRF_WHENINVULNERABLE))) - { // Immune when invulnerable unless this is a power we activated - return false; - } - if (player.morphTics) - { // Player is already a beast - if ((GetClass() == spawntype) && bCanSuperMorph - && (player.morphTics < (((duration) ? duration : DEFMORPHTICS) - TICRATE)) - && FindInventory('PowerWeaponLevel2', true) == null) - { // Make a super chicken - GiveInventoryType ('PowerWeaponLevel2'); - } - return false; - } - if (health <= 0) - { // Dead players cannot morph - return false; - } - if (spawntype == null) + if (!player || !spawnType || bDontMorph || player.Health <= 0 + || (!(style & MRF_IGNOREINVULN) && bInvulnerable && (player != activator || !(style & MRF_WHENINVULNERABLE)))) { return false; } - if (!(spawntype is 'PlayerPawn')) + + if (!duration) + duration = DEFMORPHTICS; + + if (spawnType == GetClass()) { + // Player is already a beast. + if (Alternative && bCanSuperMorph + && GetMorphTics() < duration - TICRATE + && !FindInventory("PowerWeaponLevel2", true)) + { + // Make a super chicken. + GiveInventoryType("PowerWeaponLevel2"); + } + return false; } - if (spawntype == GetClass()) + + let morphed = PlayerPawn(Spawn(spawnType, Pos, NO_REPLACE)); + if (!MorphInto(morphed)) { + if (morphed) + morphed.Destroy(); + return false; } - let morphed = PlayerPawn(Spawn (spawntype, Pos, NO_REPLACE)); + morphed.EndAllPowerupEffects(); - // Use GetClass in the event someone actually allows replacements. - PreMorph(morphed, false); - morphed.PreMorph(self, true); - - EndAllPowerupEffects(); - Substitute(morphed); if ((style & MRF_TRANSFERTRANSLATION) && !morphed.bDontTranslate) - { morphed.Translation = Translation; - } - if (tid != 0 && (style & MRF_NEWTIDBEHAVIOUR)) - { - morphed.ChangeTid(tid); - ChangeTid(0); - } + morphed.Angle = Angle; - morphed.target = target; - morphed.tracer = tracer; - morphed.alternative = self; + morphed.Pitch = Pitch; // Allow pitch here since mouse look in GZDoom is far more common than Heretic/Hexen. + morphed.Target = Target; + morphed.Tracer = Tracer; + morphed.Master = Master; morphed.FriendPlayer = FriendPlayer; morphed.DesignatedTeam = DesignatedTeam; morphed.Score = Score; - player.PremorphWeapon = player.ReadyWeapon; - - morphed.special2 = bSolid * 2 + bShootable * 4 + bInvisible * 0x40; // The factors are for savegame compatibility - morphed.player = player; - - if (morphed.ViewHeight > player.viewheight && player.deltaviewheight == 0) - { // If the new view height is higher than the old one, start moving toward it. - player.deltaviewheight = player.GetDeltaViewHeight(); + morphed.ScoreIcon = ScoreIcon; + morphed.Health = morphed.SpawnHealth(); + if (TID && (style & MRF_NEWTIDBEHAVIOUR)) + { + morphed.ChangeTid(TID); + ChangeTid(0); } + + // special2 is no longer used here since Actors now have a proper field for it. + morphed.PremorphProperties = (bSolid * MPROP_SOLID) | (bShootable * MPROP_SHOOTABLE) + | (bNoBlockmap * MPROP_NO_BLOCKMAP) | (bNoSector * MPROP_NO_SECTOR) + | (bNoInteraction * MPROP_NO_INTERACTION) | (bInvisible * MPROP_INVIS); + morphed.bShadow |= bShadow; morphed.bNoGravity |= bNoGravity; morphed.bFly |= bFly; morphed.bGhost |= bGhost; - if (enter_flash == null) enter_flash = 'TeleportFog'; - let eflash = Spawn(enter_flash, Pos + (0, 0, gameinfo.telefogheight), ALLOW_REPLACE); - let p = player; - player = null; - alternative = morphed; - bSolid = false; - bShootable = false; - bUnmorphed = true; - bInvisible = true; - - p.morphTics = (duration) ? duration : DEFMORPHTICS; - - // [MH] Used by SBARINFO to speed up face drawing - p.MorphedPlayerClass = spawntype; - - p.MorphStyle = style; - if (exit_flash == null) exit_flash = 'TeleportFog'; - p.MorphExitFlash = exit_flash; - p.health = morphed.health; - p.mo = morphed; - p.vel = (0, 0); - morphed.ObtainInventory (self); - // Remove all armor - for (Inventory item = morphed.Inv; item != null; ) + // Remove all armor. + if (!(style & MRF_KEEPARMOR)) { - let next = item.Inv; - if (item is 'Armor') + for (Inventory item = morphed.Inv; item;) { - item.DepleteOrDestroy(); + Inventory next = item.Inv; + if (item is "Armor") + item.DepleteOrDestroy(); + + item = next; } - item = next; } + + // Players store their morph behavior into their PlayerInfo unlike regular Actors which use the + // morph properties. This is needed for backwards compatibility and to give the HUD info. + let p = morphed.player; + morphed.SetMorphTics(duration); + morphed.SetMorphStyle(style); + morphed.SetMorphExitFlash(exitFlash); + p.MorphedPlayerClass = spawnType; + p.PremorphWeapon = p.ReadyWeapon; + p.Health = morphed.Health; + p.Vel = (0.0, 0.0); + // If the new view height is higher than the old one, start moving toward it. + if (morphed.ViewHeight > p.ViewHeight && !p.DeltaViewHeight) + p.DeltaViewHeight = p.GetDeltaViewHeight(); + + bNoInteraction = true; + A_ChangeLinkFlags(true, true); + + // Legacy + bSolid = bShootable = false; + bInvisible = true; + + morphed.ClearFOVInterpolation(); morphed.InitAllPowerupEffects(); - morphed.ActivateMorphWeapon (); - if (p.camera == self) // can this happen? - { - p.camera = morphed; - } - morphed.ScoreIcon = ScoreIcon; // [GRB] - if (eflash) - eflash.target = morphed; + morphed.ActivateMorphWeapon(); + PostMorph(morphed, false); // No longer the current body morphed.PostMorph(self, true); // This is the current body + + if (enterFlash) + { + Actor fog = Spawn(enterFlash, morphed.Pos.PlusZ(GameInfo.TelefogHeight), ALLOW_REPLACE); + if (fog) + fog.Target = morphed; + } + return true; } @@ -228,397 +217,154 @@ extend class PlayerPawn // //---------------------------------------------------------------------------- - virtual bool UndoPlayerMorph(playerinfo activator, int unmorphflag = 0, bool force = false) + virtual bool UndoPlayerMorph(PlayerInfo activator, EMorphFlags unmorphFlags = 0, bool force = false) { - if (alternative == null) + if (!Alternative || bStayMorphed || Alternative.bStayMorphed) + return false; + + if (!(unmorphFlags & MRF_IGNOREINVULN) && bInvulnerable + && (player != activator || (!(player.MorphStyle & MRF_WHENINVULNERABLE) && !(unmorphFlags & MRF_STANDARDUNDOING)))) { return false; } - let player = self.player; - bool DeliberateUnmorphIsOkay = !!(MRF_STANDARDUNDOING & unmorphflag); + let alt = PlayerPawn(Alternative); + alt.SetOrigin(Pos, false); + // Test if there's room to unmorph. + if (!force && (PremorphProperties & MPROP_SOLID)) + { + bool altSolid = alt.bSolid; + bool isSolid = bSolid; + bool isTouchy = bTouchy; - if ((bInvulnerable) // If the player is invulnerable - && ((player != activator) // and either did not decide to unmorph, - || (!((player.MorphStyle & MRF_WHENINVULNERABLE) // or the morph style does not allow it - || (DeliberateUnmorphIsOkay))))) // (but standard morph styles always allow it), - { // Then the player is immune to the unmorph. - return false; - } + alt.bSolid = true; + bSolid = bTouchy = false; - let altmo = PlayerPawn(alternative); - altmo.SetOrigin (Pos, false); - altmo.bSolid = true; - bSolid = false; - if (!force && !altmo.TestMobjLocation()) - { // Didn't fit - altmo.bSolid = false; - bSolid = true; - player.morphTics = 2*TICRATE; - return false; + bool res = alt.TestMobjLocation(); + + alt.bSolid = altSolid; + bSolid = isSolid; + bTouchy = isTouchy; + + if (!res) + { + SetMorphTics(2 * TICRATE); + return false; + } } - PreUnmorph(altmo, false); // This body's about to be left. - altmo.PreUnmorph(self, true); // This one's about to become current. + if (!MorphInto(alt)) + return false; - // No longer using tracer as morph storage. That is what 'alternative' is for. - // If the tracer has changed on the morph, change the original too. - altmo.target = target; - altmo.tracer = tracer; - self.player = null; - altmo.alternative = alternative = null; + alt.EndAllPowerupEffects(); // Remove the morph power if the morph is being undone prematurely. - for (Inventory item = Inv; item != null;) + for (Inventory item = alt.Inv; item;) { - let next = item.Inv; + Inventory next = item.Inv; if (item is "PowerMorph") - { item.Destroy(); - } - item = next; - } - EndAllPowerupEffects(); - altmo.ObtainInventory (self); - Substitute(altmo); - if ((tid != 0) && (player.MorphStyle & MRF_NEWTIDBEHAVIOUR)) - { - altmo.ChangeTid(tid); - } - altmo.Angle = Angle; - altmo.player = player; - altmo.reactiontime = 18; - altmo.bSolid = !!(special2 & 2); - altmo.bShootable = !!(special2 & 4); - altmo.bInvisible = !!(special2 & 0x40); - altmo.Vel = (0, 0, Vel.Z); - player.Vel = (0, 0); - altmo.floorz = floorz; - altmo.bShadow = bShadow; - altmo.bNoGravity = bNoGravity; - altmo.bGhost = bGhost; - altmo.bUnmorphed = false; - altmo.Score = Score; - altmo.InitAllPowerupEffects(); - - let exit_flash = player.MorphExitFlash; - bool correctweapon = !!(player.MorphStyle & MRF_LOSEACTUALWEAPON); - bool undobydeathsaves = !!(player.MorphStyle & MRF_UNDOBYDEATHSAVES); - - player.morphTics = 0; - player.MorphedPlayerClass = null; - player.MorphStyle = 0; - player.MorphExitFlash = null; - player.viewheight = altmo.ViewHeight; - Inventory level2 = altmo.FindInventory("PowerWeaponLevel2", true); - if (level2 != null) - { - level2.Destroy (); - } - if ((player.health > 0) || undobydeathsaves) - { - player.health = altmo.health = altmo.SpawnHealth(); - } - else // killed when morphed so stay dead - { - altmo.health = player.health; + item = next; } - player.mo = altmo; - if (player.camera == self) - { - player.camera = altmo; - } + alt.Angle = Angle; + alt.Pitch = Pitch; + alt.Target = Target; + alt.Tracer = Tracer; + alt.Master = Master; + alt.FriendPlayer = FriendPlayer; + alt.DesignatedTeam = DesignatedTeam; + alt.Score = Score; + alt.ScoreIcon = ScoreIcon; + alt.ReactionTime = 18; + alt.bSolid = (PremorphProperties & MPROP_SOLID); + alt.bShootable = (PremorphProperties & MPROP_SHOOTABLE); + alt.bInvisible = (PremorphProperties & MPROP_INVIS); + alt.bShadow = bShadow; + alt.bNoGravity = bNoGravity; + alt.bGhost = bGhost; + alt.bFly = bFly; + alt.Vel = (0.0, 0.0, Vel.Z); + + alt.bNoInteraction = (PremorphProperties & MPROP_NO_INTERACTION); + alt.A_ChangeLinkFlags((PremorphProperties & MPROP_NO_BLOCKMAP), (PremorphProperties & MPROP_NO_SECTOR)); + + let p = alt.player; + class exitFlash = alt.GetMorphExitFlash(); + EMorphFlags style = alt.GetMorphStyle(); + Weapon premorphWeap = p.PremorphWeapon; + + if (TID && (style & MRF_NEWTIDBEHAVIOUR)) + { + alt.ChangeTid(TID); + ChangeTID(0); + } + + alt.SetMorphTics(0); + alt.SetMorphStyle(0); + alt.SetMorphExitFlash(null); + p.MorphedPlayerClass = null; + p.PremorphWeapon = null; + p.ViewHeight = alt.ViewHeight; + p.Vel = (0.0, 0.0); + if (p.Health > 0 || (style & MRF_UNDOBYDEATHSAVES)) + p.Health = alt.Health = alt.SpawnHealth(); + else + alt.Health = p.Health; - // [MH] - // If the player that was morphed is the one - // taking events, reset up the face, if any; - // this is only needed for old-skool skins - // and for the original DOOM status bar. - if (player == players[consoleplayer]) - { - if (face != 'None') - { - // Assume root-level base skin to begin with - let skinindex = 0; - let skin = player.GetSkin(); - // If a custom skin was in use, then reload it - // or else the base skin for the player class. - if (skin >= PlayerClasses.Size () && skin < PlayerSkins.Size()) - { - skinindex = skin; - } - else if (PlayerClasses.Size () > 1) - { - let whatami = altmo.GetClass(); - for (int i = 0; i < PlayerClasses.Size (); ++i) - { - if (PlayerClasses[i].Type == whatami) - { - skinindex = i; - break; - } - } - } - } - } + Inventory level2 = alt.FindInventory("PowerWeaponLevel2", true); + if (level2) + level2.Destroy(); - Actor eflash = null; - if (exit_flash != null) + WeaponSlots.SetupWeaponSlots(alt); + let morphWeap = p.ReadyWeapon; + if (premorphWeap) { - eflash = Spawn(exit_flash, Vec3Angle(20., altmo.Angle, gameinfo.telefogheight), ALLOW_REPLACE); - if (eflash) eflash.target = altmo; - } - WeaponSlots.SetupWeaponSlots(altmo); // Use original class's weapon slots. - let beastweap = player.ReadyWeapon; - if (player.PremorphWeapon != null) - { - player.PremorphWeapon.PostMorphWeapon (); + premorphWeap.PostMorphWeapon(); } else { - player.ReadyWeapon = player.PendingWeapon = null; - } - if (correctweapon) - { // Better "lose morphed weapon" semantics - class morphweaponcls = MorphWeapon; - if (morphweaponcls != null && morphweaponcls is 'Weapon') - { - let OriginalMorphWeapon = Weapon(altmo.FindInventory (morphweapon)); - if ((OriginalMorphWeapon != null) && (OriginalMorphWeapon.GivenAsMorphWeapon)) - { // You don't get to keep your morphed weapon. - if (OriginalMorphWeapon.SisterWeapon != null) - { - OriginalMorphWeapon.SisterWeapon.Destroy (); - } - OriginalMorphWeapon.Destroy (); - } - } - } - else // old behaviour (not really useful now) - { // Assumptions made here are no longer valid - if (beastweap != null) - { // You don't get to keep your morphed weapon. - if (beastweap.SisterWeapon != null) - { - beastweap.SisterWeapon.Destroy (); - } - beastweap.Destroy (); - } - } - PostUnmorph(altmo, false); // This body is no longer current. - altmo.PostUnmorph(self, true); // altmo body is current. - Destroy (); - // Restore playerclass armor to its normal amount. - let hxarmor = HexenArmor(altmo.FindInventory('HexenArmor')); - if (hxarmor != null) - { - hxarmor.Slots[4] = altmo.HexenArmor[0]; + p.ReadyWeapon = null; + p.PendingWeapon = WP_NOCHANGE; + p.Refire = 0; } - return true; - } - //=========================================================================== - // - // - // - //=========================================================================== - - override Actor, int, int MorphedDeath() - { - // Voodoo dolls should not unmorph the real player here. - if (player && (player.mo == self) && - (player.morphTics) && - (player.MorphStyle & MRF_UNDOBYDEATH) && - (alternative)) + if (style & MRF_LOSEACTUALWEAPON) { - Actor realme = alternative; - int realstyle = player.MorphStyle; - int realhealth = health; - if (UndoPlayerMorph(player, 0, !!(player.MorphStyle & MRF_UNDOBYDEATHFORCED))) + // Improved "lose morph weapon" semantics. + class morphWeapCls = MorphWeapon; + if (morphWeapCls) { - return realme, realstyle, realhealth; + let originalMorphWeapon = Weapon(alt.FindInventory(morphWeapCls)); + if (originalMorphWeapon && originalMorphWeapon.GivenAsMorphWeapon) + originalMorphWeapon.Destroy(); } } - return null, 0, 0; - } -} - -//=========================================================================== -// -// -// -//=========================================================================== - -class MorphProjectile : Actor -{ - - Class PlayerClass; - Class MonsterClass, MorphFlash, UnMorphFlash; - int Duration, MorphStyle; - - Default - { - Damage 1; - Projectile; - -ACTIVATEIMPACT - -ACTIVATEPCROSS - } - - override int DoSpecialDamage (Actor target, int damage, Name damagetype) - { - if (target.player) - { - // Voodoo dolls forward this to the real player - target.player.mo.MorphPlayer (NULL, PlayerClass, Duration, MorphStyle, MorphFlash, UnMorphFlash); - } - else + else if (morphWeap) // Old behaviour (not really useful now). { - target.MorphMonster (MonsterClass, Duration, MorphStyle, MorphFlash, UnMorphFlash); + morphWeap.Destroy(); } - return -1; - } - - -} - -//=========================================================================== -// -// -// -//=========================================================================== -class MorphedMonster : Actor -{ - Actor UnmorphedMe; - int UnmorphTime, MorphStyle; - Class MorphExitFlash; - int FlagsSave; + // Reset the base AC of the player's Hexen armor back to its default. + let hexArmor = HexenArmor(alt.FindInventory("HexenArmor", true)); + if (hexArmor) + hexArmor.Slots[4] = alt.HexenArmor[0]; - Default - { - Monster; - -COUNTKILL - +FLOORCLIP - } + alt.ClearFOVInterpolation(); + alt.InitAllPowerupEffects(); - override void OnDestroy () - { - if (UnmorphedMe != NULL) - { - UnmorphedMe.Destroy (); - } - Super.OnDestroy(); - } - - override void Die (Actor source, Actor inflictor, int dmgflags, Name MeansOfDeath) - { - Super.Die (source, inflictor, dmgflags, MeansOfDeath); - if (UnmorphedMe != NULL && UnmorphedMe.bUnmorphed) - { - UnmorphedMe.health = health; - UnmorphedMe.Die (source, inflictor, dmgflags, MeansOfDeath); - } - } + PostUnmorph(alt, false); // This body is no longer current. + alt.PostUnmorph(self, true); // altmo body is current. - override void Tick () - { - if (UnmorphTime > level.time || !UndoMonsterMorph()) + if (exitFlash) { - Super.Tick(); + Actor fog = Spawn(exitFlash, alt.Vec3Angle(20.0, alt.Angle, GameInfo.TelefogHeight), ALLOW_REPLACE); + if (fog) + fog.Target = alt; } - } - //---------------------------------------------------------------------------- - // - // FUNC P_UndoMonsterMorph - // - // Returns true if the monster unmorphs. - // - //---------------------------------------------------------------------------- - - virtual bool UndoMonsterMorph(bool force = false) - { - if (UnmorphTime == 0 || UnmorphedMe == NULL || bStayMorphed || UnmorphedMe.bStayMorphed) - { - return false; - } - let unmorphed = UnmorphedMe; - unmorphed.SetOrigin (Pos, false); - unmorphed.bSolid = true; - bSolid = false; - bool save = bTouchy; - bTouchy = false; - if (!force && !unmorphed.TestMobjLocation ()) - { // Didn't fit - unmorphed.bSolid = false; - bSolid = true; - bTouchy = save; - UnmorphTime = level.time + 5*TICRATE; // Next try in 5 seconds - return false; - } - PreUnmorph(unmorphed, false); - unmorphed.PreUnmorph(self, true); - unmorphed.Angle = Angle; - unmorphed.target = target; - unmorphed.bShadow = bShadow; - unmorphed.bGhost = bGhost; - unmorphed.bSolid = !!(flagssave & 2); - unmorphed.bShootable = !!(flagssave & 4); - unmorphed.bInvisible = !!(flagssave & 0x40); - unmorphed.health = unmorphed.SpawnHealth(); - unmorphed.Vel = Vel; - unmorphed.ChangeTid(tid); - unmorphed.special = special; - unmorphed.Score = Score; - unmorphed.args[0] = args[0]; - unmorphed.args[1] = args[1]; - unmorphed.args[2] = args[2]; - unmorphed.args[3] = args[3]; - unmorphed.args[4] = args[4]; - unmorphed.CopyFriendliness (self, true); - unmorphed.bUnmorphed = false; - PostUnmorph(unmorphed, false); // From is false here: Leaving the caller's body. - unmorphed.PostUnmorph(self, true); // True here: Entering this body from here. - UnmorphedMe = NULL; - Substitute(unmorphed); - Destroy (); - let eflash = Spawn(MorphExitFlash, Pos + (0, 0, gameinfo.TELEFOGHEIGHT), ALLOW_REPLACE); - if (eflash) - eflash.target = unmorphed; + Destroy(); return true; } - - //=========================================================================== - // - // - // - //=========================================================================== - - override Actor, int, int MorphedDeath() - { - let realme = UnmorphedMe; - if (realme != NULL) - { - if ((UnmorphTime) && - (MorphStyle & MRF_UNDOBYDEATH)) - { - int realstyle = MorphStyle; - int realhealth = health; - if (UndoMonsterMorph(!!(MorphStyle & MRF_UNDOBYDEATHFORCED))) - { - return realme, realstyle, realhealth; - } - } - if (realme.bBossDeath) - { - realme.health = 0; // make sure that A_BossDeath considers it dead. - realme.A_BossDeath(); - } - } - return null, 0, 0; - } - } - diff --git a/wadsrc/static/zscript/actors/raven/artitele.zs b/wadsrc/static/zscript/actors/raven/artitele.zs index 3f61176a1d5..272ae860295 100644 --- a/wadsrc/static/zscript/actors/raven/artitele.zs +++ b/wadsrc/static/zscript/actors/raven/artitele.zs @@ -23,34 +23,32 @@ class ArtiTeleport : Inventory Loop; } - override bool Use (bool pickup) + override bool Use(bool pickup) { Vector3 dest; - int destAngle; - + double destAngle; if (deathmatch) - { - [dest, destAngle] = level.PickDeathmatchStart(); - } + [dest, destAngle] = Level.PickDeathmatchStart(); else + [dest, destAngle] = Level.PickPlayerStart(Owner.PlayerNumber()); + + if (!Level.UsePlayerStartZ) + dest.Z = ONFLOORZ; + + Owner.Teleport(dest, destAngle, TELF_SOURCEFOG | TELF_DESTFOG); + + bool canLaugh = Owner.player != null; + EMorphFlags mStyle = Owner.GetMorphStyle(); + if (Owner.Alternative && (mStyle & MRF_UNDOBYCHAOSDEVICE)) { - [dest, destAngle] = level.PickPlayerStart(Owner.PlayerNumber()); - } - dest.Z = ONFLOORZ; - Owner.Teleport (dest, destAngle, TELF_SOURCEFOG | TELF_DESTFOG); - bool canlaugh = true; - Playerinfo p = Owner.player; - if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYCHAOSDEVICE)) - { // Teleporting away will undo any morph effects (pig) - if (!p.mo.UndoPlayerMorph (p, MRF_UNDOBYCHAOSDEVICE) && (p.MorphStyle & MRF_FAILNOLAUGH)) - { - canlaugh = false; - } - } - if (canlaugh) - { // Full volume laugh - Owner.A_StartSound ("*evillaugh", CHAN_VOICE, CHANF_DEFAULT, 1., ATTN_NONE); + // Teleporting away will undo any morph effects (pig). + if (!Owner.Unmorph(Owner, MRF_UNDOBYCHAOSDEVICE) && (mStyle & MRF_FAILNOLAUGH)) + canLaugh = false; } + + if (canLaugh) + Owner.A_StartSound("*evillaugh", CHAN_VOICE, attenuation: ATTN_NONE); + return true; } diff --git a/wadsrc/static/zscript/actors/raven/minotaur.zs b/wadsrc/static/zscript/actors/raven/minotaur.zs index b3e71013ca5..6060672761a 100644 --- a/wadsrc/static/zscript/actors/raven/minotaur.zs +++ b/wadsrc/static/zscript/actors/raven/minotaur.zs @@ -109,7 +109,7 @@ class Minotaur : Actor { double ang = AngleTo(target); double thrust = 16 + random[MinotaurSlam]() / 64.; - target.VelFromAngle(ang, thrust); + target.VelFromAngle(thrust, ang); int damage = random[MinotaurSlam](1, 8) * (bSummonedMonster? 4 : 6); int newdam = target.DamageMobj (null, null, damage, 'Melee'); target.TraceBleedAngle (newdam > 0 ? newdam : damage, ang, 0.); @@ -347,7 +347,7 @@ class Minotaur : Actor } else { - if (Floorclip > 0 && (Level.compatflags & COMPAT_MINOTAUR)) + if (Floorclip > 0 && (Level.compatflags & COMPATF_MINOTAUR)) { // only play the sound. A_StartSound ("minotaur/fx2hit", CHAN_WEAPON); diff --git a/wadsrc/static/zscript/actors/raven/ravenartifacts.zs b/wadsrc/static/zscript/actors/raven/ravenartifacts.zs index 443816788e4..daf90767ccd 100644 --- a/wadsrc/static/zscript/actors/raven/ravenartifacts.zs +++ b/wadsrc/static/zscript/actors/raven/ravenartifacts.zs @@ -81,6 +81,7 @@ class ArtiInvulnerability : PowerupGiver { +COUNTITEM +FLOATBOB + +Inventory.BIGPOWERUP Inventory.PickupFlash "PickupFlash"; Inventory.RespawnTics 4230; Inventory.Icon "ARTIINVU"; @@ -105,6 +106,7 @@ class ArtiInvulnerability2 : PowerupGiver { +COUNTITEM +FLOATBOB + +Inventory.BIGPOWERUP Inventory.PickupFlash "PickupFlash"; Inventory.RespawnTics 4230; Inventory.Icon "ARTIDEFN"; diff --git a/wadsrc/static/zscript/actors/shared/camera.zs b/wadsrc/static/zscript/actors/shared/camera.zs index 91923b1335e..463ad617845 100644 --- a/wadsrc/static/zscript/actors/shared/camera.zs +++ b/wadsrc/static/zscript/actors/shared/camera.zs @@ -63,14 +63,17 @@ class AimingCamera : SecurityCamera args[2] = 0; Super.PostBeginPlay (); - MaxPitchChange = double(changepitch / TICRATE); + MaxPitchChange = double(changepitch) / TICRATE; Range /= TICRATE; ActorIterator it = Level.CreateActorIterator(args[3]); tracer = it.Next (); if (tracer == NULL) { - //Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]); + if (args[3] != 0) + { + console.Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]); + } } else { // Don't try for a new target upon losing this one. @@ -125,3 +128,87 @@ class AimingCamera : SecurityCamera } } + +class SpectatorCamera : Actor +{ + + bool chasingtracer; + double lagdistance; // camera gives chase (lazy follow) if tracer gets > lagdistance away from camera.pos + int chasemode; // 0: chase until tracer centered, 1: same but only when tracer is moving, 2: stop chase if tracer within lagdistance + property lagdistance : lagdistance; + property chasingtracer : chasingtracer; + property chasemode : chasemode; + + default + { + +NOBLOCKMAP + +NOGRAVITY + +NOINTERACTION + RenderStyle "None"; + CameraHeight 0; + SpectatorCamera.chasingtracer false; + SpectatorCamera.lagdistance 0.0; + SpectatorCamera.chasemode 0; + } + + void Init(double dist, double yaw, double inpitch, int inflags) + { + + double zshift = 0.0; + if(tracer != NULL) + { + if(player != NULL) zshift = -0.25*tracer.height; + else zshift = 0.5*tracer.height; + } + else if (player != NULL && player.mo != NULL) zshift = -0.5*player.mo.height; + + SetViewPos((-dist*Cos(yaw)*Cos(inpitch), -dist*Sin(yaw)*Cos(inpitch), dist*Sin(inpitch)+zshift), inflags); + LookAtSelf(inpitch); + } + + void LookAtSelf(double inpitch) + { + if(ViewPos.Offset.length() > 0.) + { + Vector3 negviewpos = (-1.0) * ViewPos.Offset; + angle = negviewpos.Angle(); + pitch = inpitch; + } + } + + override void Tick() + { + if(tracer != NULL) + { + Vector3 distvec = tracer.pos - pos; + double dist = distvec.length(); + if((dist <= 4 && chasingtracer) || lagdistance <= 0.0) // Keep tracer centered on screen + { + SetOrigin(tracer.pos, true); + chasingtracer = false; + } + else // Lazy follow tracer + { + if(dist >= 2*lagdistance) + { + SetOrigin(tracer.pos, true); + chasingtracer = false; + } + else if(dist > lagdistance && !chasingtracer) chasingtracer = true; + + if(chasingtracer) + { + speed = tracer.vel.xy.length()/dist; + if((speed == 0.0) && (chasemode == 0)) speed = tracer.speed/dist; + SetOrigin(pos + 2*distvec*speed, true); + if(chasemode > 1) chasingtracer = false; + } + } + } + else if(player != NULL && player.mo != NULL) + { + cameraFOV = player.FOV; + SetOrigin(player.mo.pos, true); + } + } +} diff --git a/wadsrc/static/zscript/actors/shared/corona.zs b/wadsrc/static/zscript/actors/shared/corona.zs new file mode 100644 index 00000000000..996921f8218 --- /dev/null +++ b/wadsrc/static/zscript/actors/shared/corona.zs @@ -0,0 +1,10 @@ +/*class Corona : Actor native +{ + Default + { + RenderStyle "Add"; + RenderRadius 1024.0; + +NOINTERACTION + +FORCEXYBILLBOARD + } +}*/ diff --git a/wadsrc/static/zscript/actors/shared/dynlights.zs b/wadsrc/static/zscript/actors/shared/dynlights.zs index 4f6ada88f9d..8c5d0850dd4 100644 --- a/wadsrc/static/zscript/actors/shared/dynlights.zs +++ b/wadsrc/static/zscript/actors/shared/dynlights.zs @@ -15,6 +15,8 @@ class DynamicLight : Actor flagdef noshadowmap: lightflags, 4; flagdef dontlightactors: lightflags, 5; flagdef spot: lightflags, 6; + flagdef dontlightothers: lightflags, 7; + flagdef dontlightmap: lightflags, 8; enum EArgs { @@ -35,7 +37,9 @@ class DynamicLight : Actor LF_ATTENUATE = 8, LF_NOSHADOWMAP = 16, LF_DONTLIGHTACTORS = 32, - LF_SPOT = 64 + LF_SPOT = 64, + LF_DONTLIGHTOTHERS = 128, + LF_DONTLIGHTMAP = 256, }; enum ELightType @@ -68,6 +72,7 @@ class DynamicLight : Actor +NOGRAVITY +FIXMAPTHINGPOS +INVISIBLE + +NOTONAUTOMAP } //========================================================================== diff --git a/wadsrc/static/zscript/actors/shared/fastprojectile.zs b/wadsrc/static/zscript/actors/shared/fastprojectile.zs index befc4252dd7..88df40a32af 100644 --- a/wadsrc/static/zscript/actors/shared/fastprojectile.zs +++ b/wadsrc/static/zscript/actors/shared/fastprojectile.zs @@ -102,7 +102,7 @@ class FastProjectile : Actor tm.ClearLastRipped(); // [RH] Do rip damage each step, like Hexen } - if (!TryMove (Pos.XY + frac.XY, true, NULL, tm)) + if (!TryMove (Pos.XY + frac.XY, true, false, tm)) { // Blocked move if (!bSkyExplode) { diff --git a/wadsrc/static/zscript/actors/shared/mapmarker.zs b/wadsrc/static/zscript/actors/shared/mapmarker.zs index 25e1973077e..bc372ae7081 100644 --- a/wadsrc/static/zscript/actors/shared/mapmarker.zs +++ b/wadsrc/static/zscript/actors/shared/mapmarker.zs @@ -7,6 +7,9 @@ // args[1] == 0, show the sprite always // == 1, show the sprite only after its sector has been drawn // +// args[2] == 0, show the sprite with a constant scale +// == 1, show the sprite with a scale relative to automap zoom +// // To enable display of the sprite, activate it. To turn off the sprite, // deactivate it. // diff --git a/wadsrc/static/zscript/actors/shared/movingcamera.zs b/wadsrc/static/zscript/actors/shared/movingcamera.zs index 3a254a6152b..8f76bd17904 100644 --- a/wadsrc/static/zscript/actors/shared/movingcamera.zs +++ b/wadsrc/static/zscript/actors/shared/movingcamera.zs @@ -53,6 +53,7 @@ class InterpolationPoint : Actor +NOBLOCKMAP +NOGRAVITY +DONTSPLASH + +NOTONAUTOMAP RenderStyle "None"; } @@ -119,6 +120,7 @@ class InterpolationSpecial : Actor +NOSECTOR +NOGRAVITY +DONTSPLASH + +NOTONAUTOMAP } override void Tick () {} // Does absolutely nothing itself @@ -486,19 +488,19 @@ class ActorMover : PathFollower Super.Activate (activator); let tracer = self.tracer; special1 = tracer.bNoGravity + (tracer.bNoBlockmap<<1) + (tracer.bSolid<<2) + (tracer.bInvulnerable<<4) + (tracer.bDormant<<8); - bNoGravity = true; + tracer.bNoGravity = true; if (args[2] & 128) { LinkContext ctx; tracer.UnlinkFromWorld (ctx); - bNoBlockmap = true; - bSolid = false; + tracer.bNoBlockmap = true; + tracer.bSolid = false; tracer.LinkToWorld (ctx); } if (tracer.bIsMonster) { - bInvulnerable = true; - bDormant = true; + tracer.bInvulnerable = true; + tracer.bDormant = true; } // Don't let the renderer interpolate between the actor's // old position and its new position. diff --git a/wadsrc/static/zscript/actors/shared/randomspawner.zs b/wadsrc/static/zscript/actors/shared/randomspawner.zs index f4c20ec9187..9a73bd35c69 100644 --- a/wadsrc/static/zscript/actors/shared/randomspawner.zs +++ b/wadsrc/static/zscript/actors/shared/randomspawner.zs @@ -235,7 +235,7 @@ class RandomSpawner : Actor } newmobj.AddZ(SpawnPoint.Z); } - if (newmobj.bMissile) + if (newmobj.bMissile && !(newmobj is 'RandomSpawner')) newmobj.CheckMissileSpawn(0); // Bouncecount is used to count how many recursions we're in. if (newmobj is 'RandomSpawner') diff --git a/wadsrc/static/zscript/actors/shared/secrettrigger.zs b/wadsrc/static/zscript/actors/shared/secrettrigger.zs index 7a2a78ef4c1..b664d6b6793 100644 --- a/wadsrc/static/zscript/actors/shared/secrettrigger.zs +++ b/wadsrc/static/zscript/actors/shared/secrettrigger.zs @@ -7,6 +7,7 @@ class SecretTrigger : Actor +NOSECTOR +NOGRAVITY +DONTSPLASH + +NOTONAUTOMAP } override void PostBeginPlay () diff --git a/wadsrc/static/zscript/actors/shared/sectoraction.zs b/wadsrc/static/zscript/actors/shared/sectoraction.zs index 8daada166db..81bf5d48612 100644 --- a/wadsrc/static/zscript/actors/shared/sectoraction.zs +++ b/wadsrc/static/zscript/actors/shared/sectoraction.zs @@ -29,6 +29,7 @@ class SectorAction : Actor +NOSECTOR +NOGRAVITY +DONTSPLASH + +NOTONAUTOMAP } override void OnDestroy () diff --git a/wadsrc/static/zscript/actors/shared/sharedmisc.zs b/wadsrc/static/zscript/actors/shared/sharedmisc.zs index c837f5f1e53..5e146f6c9ac 100644 --- a/wadsrc/static/zscript/actors/shared/sharedmisc.zs +++ b/wadsrc/static/zscript/actors/shared/sharedmisc.zs @@ -31,6 +31,7 @@ class PatrolPoint : Actor +NOGRAVITY +NOBLOCKMAP +DONTSPLASH + +NOTONAUTOMAP RenderStyle "None"; } } @@ -47,6 +48,7 @@ class PatrolSpecial : Actor +NOGRAVITY +NOBLOCKMAP +DONTSPLASH + +NOTONAUTOMAP RenderStyle "None"; } } @@ -61,6 +63,7 @@ class MapSpot : Actor +NOSECTOR +NOGRAVITY +DONTSPLASH + +NOTONAUTOMAP RenderStyle "None"; CameraHeight 0; } @@ -81,6 +84,7 @@ class MapSpotGravity : MapSpot -NOBLOCKMAP -NOSECTOR -NOGRAVITY + +NOTONAUTOMAP } } @@ -93,6 +97,7 @@ class PointPusher : Actor +NOBLOCKMAP +INVISIBLE +NOCLIP + +NOTONAUTOMAP } } @@ -103,6 +108,7 @@ class PointPuller : Actor +NOBLOCKMAP +INVISIBLE +NOCLIP + +NOTONAUTOMAP } } @@ -220,6 +226,7 @@ class SectorFlagSetter : Actor { Super.BeginPlay (); CurSector.Flags |= args[0]; + Destroy(); } } diff --git a/wadsrc/static/zscript/actors/shared/soundenvironment.zs b/wadsrc/static/zscript/actors/shared/soundenvironment.zs index d7317bcbf4b..69aab2ac38d 100644 --- a/wadsrc/static/zscript/actors/shared/soundenvironment.zs +++ b/wadsrc/static/zscript/actors/shared/soundenvironment.zs @@ -7,6 +7,7 @@ class SoundEnvironment : Actor +NOBLOCKMAP +NOGRAVITY +DONTSPLASH + +NOTONAUTOMAP } override void PostBeginPlay () diff --git a/wadsrc/static/zscript/actors/shared/soundsequence.zs b/wadsrc/static/zscript/actors/shared/soundsequence.zs index 9f2d0c3d70e..49a2c28ee7f 100644 --- a/wadsrc/static/zscript/actors/shared/soundsequence.zs +++ b/wadsrc/static/zscript/actors/shared/soundsequence.zs @@ -65,6 +65,7 @@ class AmbientSound : Actor +NOBLOCKMAP +NOSECTOR +DONTSPLASH + +NOTONAUTOMAP } native void MarkAmbientSounds(); @@ -100,6 +101,7 @@ class SoundSequenceSlot : Actor +NOSECTOR +NOBLOCKMAP +DONTSPLASH + +NOTONAUTOMAP } SeqNode sequence; @@ -112,6 +114,7 @@ class SoundSequence : Actor +NOSECTOR +NOBLOCKMAP +DONTSPLASH + +NOTONAUTOMAP } //========================================================================== diff --git a/wadsrc/static/zscript/actors/shared/splashes.zs b/wadsrc/static/zscript/actors/shared/splashes.zs index 8b16d85b864..77f38d6a615 100644 --- a/wadsrc/static/zscript/actors/shared/splashes.zs +++ b/wadsrc/static/zscript/actors/shared/splashes.zs @@ -38,6 +38,7 @@ class WaterSplashBase : Actor +NOGRAVITY +DONTSPLASH +DONTBLAST + +MOVEWITHSECTOR } States { @@ -58,6 +59,7 @@ class LavaSplash : Actor +NOGRAVITY +DONTSPLASH +DONTBLAST + +MOVEWITHSECTOR } States { @@ -121,6 +123,7 @@ class SludgeSplash : Actor +NOCLIP +NOGRAVITY +DONTSPLASH + +MOVEWITHSECTOR } States { @@ -174,6 +177,7 @@ class BloodSplashBase : Actor +NOGRAVITY +DONTSPLASH +DONTBLAST + +MOVEWITHSECTOR } States { @@ -218,6 +222,7 @@ class SlimeSplash : Actor +NOCLIP +NOGRAVITY +DONTSPLASH + +MOVEWITHSECTOR } States { diff --git a/wadsrc/static/zscript/actors/shared/teleport.zs b/wadsrc/static/zscript/actors/shared/teleport.zs index d4615875b2a..fcc55e7abc0 100644 --- a/wadsrc/static/zscript/actors/shared/teleport.zs +++ b/wadsrc/static/zscript/actors/shared/teleport.zs @@ -55,6 +55,7 @@ class TeleportDest : Actor +NOBLOCKMAP +NOSECTOR +DONTSPLASH + +NOTONAUTOMAP } } diff --git a/wadsrc/static/zscript/actors/strife/alienspectres.zs b/wadsrc/static/zscript/actors/strife/alienspectres.zs index 6b2c83dc113..840c0664ef6 100644 --- a/wadsrc/static/zscript/actors/strife/alienspectres.zs +++ b/wadsrc/static/zscript/actors/strife/alienspectres.zs @@ -15,6 +15,7 @@ class AlienSpectre1 : SpectralMonster MinMissileChance 150; RenderStyle "Translucent"; Alpha 0.666; + Tag "$TAG_ALIENSPECTRE"; SeeSound "alienspectre/sight"; AttackSound "alienspectre/blade"; PainSound "alienspectre/pain"; diff --git a/wadsrc/static/zscript/actors/strife/crusader.zs b/wadsrc/static/zscript/actors/strife/crusader.zs index ce2ba6ef8bc..f08d0f847d9 100644 --- a/wadsrc/static/zscript/actors/strife/crusader.zs +++ b/wadsrc/static/zscript/actors/strife/crusader.zs @@ -21,6 +21,7 @@ class Crusader : Actor MinMissileChance 120; MaxDropoffHeight 32; DropItem "EnergyPod", 256, 20; + Tag "$TAG_CRUSADER"; SeeSound "crusader/sight"; PainSound "crusader/pain"; DeathSound "crusader/death"; diff --git a/wadsrc/static/zscript/actors/strife/entityboss.zs b/wadsrc/static/zscript/actors/strife/entityboss.zs index 107442e2815..70e176c4a7f 100644 --- a/wadsrc/static/zscript/actors/strife/entityboss.zs +++ b/wadsrc/static/zscript/actors/strife/entityboss.zs @@ -91,6 +91,7 @@ class EntityBoss : SpectralMonster MinMissileChance 150; RenderStyle "Translucent"; Alpha 0.5; + Tag "$TAG_ENTITY"; SeeSound "entity/sight"; AttackSound "entity/melee"; PainSound "entity/pain"; @@ -241,6 +242,7 @@ class EntitySecond : SpectralMonster MinMissileChance 150; RenderStyle "Translucent"; Alpha 0.25; + Tag "$TAG_ENTITY"; SeeSound "alienspectre/sight"; AttackSound "alienspectre/blade"; PainSound "alienspectre/pain"; diff --git a/wadsrc/static/zscript/actors/strife/inquisitor.zs b/wadsrc/static/zscript/actors/strife/inquisitor.zs index 5ad81d0504c..9b2e37f566f 100644 --- a/wadsrc/static/zscript/actors/strife/inquisitor.zs +++ b/wadsrc/static/zscript/actors/strife/inquisitor.zs @@ -19,6 +19,7 @@ class Inquisitor : Actor +NORADIUSDMG MaxDropOffHeight 32; MinMissileChance 150; + Tag "$TAG_INQUISITOR"; SeeSound "inquisitor/sight"; DeathSound "inquisitor/death"; ActiveSound "inquisitor/active"; diff --git a/wadsrc/static/zscript/actors/strife/klaxon.zs b/wadsrc/static/zscript/actors/strife/klaxon.zs index 6b12593c051..dab56f6cdcb 100644 --- a/wadsrc/static/zscript/actors/strife/klaxon.zs +++ b/wadsrc/static/zscript/actors/strife/klaxon.zs @@ -44,6 +44,8 @@ class CeilingTurret : Actor +NOSPLASHALERT +DONTFALL MinMissileChance 150; + Tag "$TAG_CEILINGTURRET"; + Obituary "$OB_TURRET"; DeathSound "turret/death"; } States diff --git a/wadsrc/static/zscript/actors/strife/peasants.zs b/wadsrc/static/zscript/actors/strife/peasants.zs index 6645c69fa6d..a0952c5d59e 100644 --- a/wadsrc/static/zscript/actors/strife/peasants.zs +++ b/wadsrc/static/zscript/actors/strife/peasants.zs @@ -19,6 +19,7 @@ class Peasant : StrifeHumanoid MinMissileChance 150; MaxStepHeight 16; MaxDropoffHeight 32; + Tag "$TAG_PEASANT"; SeeSound "peasant/sight"; AttackSound "peasant/attack"; PainSound "peasant/pain"; diff --git a/wadsrc/static/zscript/actors/strife/programmer.zs b/wadsrc/static/zscript/actors/strife/programmer.zs index 88e2974c0d6..4a364f23f54 100644 --- a/wadsrc/static/zscript/actors/strife/programmer.zs +++ b/wadsrc/static/zscript/actors/strife/programmer.zs @@ -25,6 +25,7 @@ class Programmer : Actor +NOTARGETSWITCH DamageFactor "Fire", 0.5; MinMissileChance 150; + Tag "$TAG_PROGRAMMER"; AttackSound "programmer/attack"; PainSound "programmer/pain"; DeathSound "programmer/death"; diff --git a/wadsrc/static/zscript/actors/strife/reaver.zs b/wadsrc/static/zscript/actors/strife/reaver.zs index 408fbf89c21..2dd616d993c 100644 --- a/wadsrc/static/zscript/actors/strife/reaver.zs +++ b/wadsrc/static/zscript/actors/strife/reaver.zs @@ -14,6 +14,7 @@ class Reaver : Actor MinMissileChance 150; MaxDropoffHeight 32; Mass 500; + Tag "$TAG_REAVER"; SeeSound "reaver/sight"; PainSound "reaver/pain"; DeathSound "reaver/death"; diff --git a/wadsrc/static/zscript/actors/strife/sentinel.zs b/wadsrc/static/zscript/actors/strife/sentinel.zs index 190111be7bf..0acc8580f02 100644 --- a/wadsrc/static/zscript/actors/strife/sentinel.zs +++ b/wadsrc/static/zscript/actors/strife/sentinel.zs @@ -22,6 +22,7 @@ class Sentinel : Actor +LOOKALLAROUND +NEVERRESPAWN MinMissileChance 150; + Tag "$TAG_SENTINEL"; SeeSound "sentinel/sight"; DeathSound "sentinel/death"; ActiveSound "sentinel/active"; diff --git a/wadsrc/static/zscript/actors/strife/stalker.zs b/wadsrc/static/zscript/actors/strife/stalker.zs index 1677e6a13cd..7efa5e03283 100644 --- a/wadsrc/static/zscript/actors/strife/stalker.zs +++ b/wadsrc/static/zscript/actors/strife/stalker.zs @@ -20,6 +20,7 @@ class Stalker : Actor +NOVERTICALMELEERANGE MaxDropOffHeight 32; MinMissileChance 150; + Tag "$TAG_STALKER"; SeeSound "stalker/sight"; AttackSound "stalker/attack"; PainSound "stalker/pain"; diff --git a/wadsrc/static/zscript/actors/strife/strifebishop.zs b/wadsrc/static/zscript/actors/strife/strifebishop.zs index 32aacd03a3a..f32ba71eb86 100644 --- a/wadsrc/static/zscript/actors/strife/strifebishop.zs +++ b/wadsrc/static/zscript/actors/strife/strifebishop.zs @@ -21,6 +21,7 @@ class StrifeBishop : Actor DamageFactor "Fire", 0.5; MinMissileChance 150; MaxDropoffHeight 32; + Tag "$TAG_BISHOP"; SeeSound "bishop/sight"; PainSound "bishop/pain"; DeathSound "bishop/death"; diff --git a/wadsrc/static/zscript/actors/strife/strifeitems.zs b/wadsrc/static/zscript/actors/strife/strifeitems.zs index f87749315a5..3a67e1479a0 100644 --- a/wadsrc/static/zscript/actors/strife/strifeitems.zs +++ b/wadsrc/static/zscript/actors/strife/strifeitems.zs @@ -559,10 +559,10 @@ class PrisonPass : Key override bool TryPickup (in out Actor toucher) { - Super.TryPickup (toucher); + bool res = Super.TryPickup (toucher); Door_Open(223, 16); toucher.GiveInventoryType ("QuestItem10"); - return true; + return res; } //============================================================================ diff --git a/wadsrc/static/zscript/actors/strife/strifestuff.zs b/wadsrc/static/zscript/actors/strife/strifestuff.zs index 1be3fbc53e2..55cc472febd 100644 --- a/wadsrc/static/zscript/actors/strife/strifestuff.zs +++ b/wadsrc/static/zscript/actors/strife/strifestuff.zs @@ -1786,6 +1786,7 @@ class KneelingGuy : Actor +NOBLOOD +ISMONSTER +INCOMBAT + Tag "$TAG_KNEELINGGUY"; PainSound "misc/static"; DeathSound "misc/static"; ActiveSound "misc/chant"; diff --git a/wadsrc/static/zscript/actors/strife/weaponmauler.zs b/wadsrc/static/zscript/actors/strife/weaponmauler.zs index b805c3ac5e7..227430a9099 100644 --- a/wadsrc/static/zscript/actors/strife/weaponmauler.zs +++ b/wadsrc/static/zscript/actors/strife/weaponmauler.zs @@ -62,7 +62,7 @@ class Mauler : StrifeWeapon Weapon weap = player.ReadyWeapon; if (weap != null) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 2)) + if (!weap.DepleteAmmo (weap.bAltFire, true)) return; } @@ -240,6 +240,7 @@ class MaulerTorpedo : Actor action void A_MaulerTorpedoWave() { + if (target == null) return; readonly wavedef = GetDefaultByType("MaulerTorpedoWave"); double savedz = pos.z; angle += 180.; diff --git a/wadsrc/static/zscript/actors/strife/zombie.zs b/wadsrc/static/zscript/actors/strife/zombie.zs index c7a7cea5931..5bfd0ba6097 100644 --- a/wadsrc/static/zscript/actors/strife/zombie.zs +++ b/wadsrc/static/zscript/actors/strife/zombie.zs @@ -19,6 +19,7 @@ class Zombie : StrifeHumanoid MaxStepHeight 16; MaxDropOffHeight 32; Translation 0; + Tag "$TAG_STRIFEZOMBIE"; DeathSound "zombie/death"; CrushPainSound "misc/pcrush"; } diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs deleted file mode 100644 index 7cbaf8e917d..00000000000 --- a/wadsrc/static/zscript/base.zs +++ /dev/null @@ -1,1105 +0,0 @@ - -struct _ native // These are the global variables, the struct is only here to avoid extending the parser for this. -{ - native readonly Array AllClasses; - native readonly Array > AllActorClasses; - native readonly Array<@PlayerClass> PlayerClasses; - native readonly Array<@PlayerSkin> PlayerSkins; - native readonly Array<@Team> Teams; - native int validcount; - native readonly bool multiplayer; - native @KeyBindings Bindings; - native @KeyBindings AutomapBindings; - native play @DehInfo deh; - native readonly @GameInfoStruct gameinfo; - native readonly ui bool netgame; - - native readonly bool automapactive; - native readonly uint gameaction; - native readonly int gamestate; - native readonly TextureID skyflatnum; - native readonly Font smallfont; - native readonly Font smallfont2; - native readonly Font bigfont; - native readonly Font confont; - native readonly Font NewConsoleFont; - native readonly Font NewSmallFont; - native readonly Font AlternativeSmallFont; - native readonly Font OriginalSmallFont; - native readonly Font OriginalBigFont; - native readonly Font intermissionfont; - native readonly int CleanXFac; - native readonly int CleanYFac; - native readonly int CleanWidth; - native readonly int CleanHeight; - native readonly int CleanXFac_1; - native readonly int CleanYFac_1; - native readonly int CleanWidth_1; - native readonly int CleanHeight_1; - native ui int menuactive; - native readonly @FOptionMenuSettings OptionMenuSettings; - native readonly int gametic; - native readonly bool demoplayback; - native ui int BackbuttonTime; - native ui float BackbuttonAlpha; - native readonly int Net_Arbitrator; - native ui BaseStatusBar StatusBar; - native readonly Weapon WP_NOCHANGE; - deprecated("3.8", "Use Actor.isFrozen() or Level.isFrozen() instead") native readonly bool globalfreeze; - native int LocalViewPitch; - native readonly @MusPlayingInfo musplaying; - native readonly bool generic_ui; - -// sandbox state in multi-level setups: - - native play @PlayerInfo players[MAXPLAYERS]; - native readonly bool playeringame[MAXPLAYERS]; - native readonly int consoleplayer; - native play LevelLocals Level; - -} - -struct MusPlayingInfo native -{ - native String name; - native int baseorder; - native bool loop; -}; - -struct TexMan -{ - enum EUseTypes - { - Type_Any, - Type_Wall, - Type_Flat, - Type_Sprite, - Type_WallPatch, - Type_Build, - Type_SkinSprite, - Type_Decal, - Type_MiscPatch, - Type_FontChar, - Type_Override, // For patches between TX_START/TX_END - Type_Autopage, // Automap background - used to enable the use of FAutomapTexture - Type_SkinGraphic, - Type_Null, - Type_FirstDefined, - }; - - enum EFlags - { - TryAny = 1, - Overridable = 2, - ReturnFirst = 4, - AllowSkins = 8, - ShortNameOnly = 16, - DontCreate = 32, - Localize = 64 - }; - - enum ETexReplaceFlags - { - NOT_BOTTOM = 1, - NOT_MIDDLE = 2, - NOT_TOP = 4, - NOT_FLOOR = 8, - NOT_CEILING = 16, - NOT_WALL = 7, - NOT_FLAT = 24 - }; - - native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny); - deprecated("3.8", "Use Level.ReplaceTextures() instead") static void ReplaceTextures(String from, String to, int flags) - { - level.ReplaceTextures(from, to, flags); - } - native static String GetName(TextureID tex); - native static int, int GetSize(TextureID tex); - native static Vector2 GetScaledSize(TextureID tex); - native static Vector2 GetScaledOffset(TextureID tex); - native static int CheckRealHeight(TextureID tex); - native static bool OkForLocalization(TextureID patch, String textSubstitute); - - native static void SetCameraToTexture(Actor viewpoint, String texture, double fov); -} - -enum DrawTextureTags -{ - TAG_USER = (1<<30), - DTA_Base = TAG_USER + 5000, - DTA_DestWidth, // width of area to draw to - DTA_DestHeight, // height of area to draw to - DTA_Alpha, // alpha value for translucency - DTA_FillColor, // color to stencil onto the destination (RGB is the color for truecolor drawers, A is the palette index for paletted drawers) - DTA_TranslationIndex, // translation table to recolor the source - DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor - DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac - DTA_320x200, // bool: scale texture size and position to fit on a virtual 320x200 screen - DTA_Bottom320x200, // bool: same as DTA_320x200 but centers virtual screen on bottom for 1280x1024 targets - DTA_CleanNoMove, // bool: like DTA_Clean but does not reposition output position - DTA_CleanNoMove_1, // bool: like DTA_CleanNoMove, but uses Clean[XY]fac_1 instead - DTA_FlipX, // bool: flip image horizontally //FIXME: Does not work with DTA_Window(Left|Right) - DTA_ShadowColor, // color of shadow - DTA_ShadowAlpha, // alpha of shadow - DTA_Shadow, // set shadow color and alphas to defaults - DTA_VirtualWidth, // pretend the canvas is this wide - DTA_VirtualHeight, // pretend the canvas is this tall - DTA_TopOffset, // override texture's top offset - DTA_LeftOffset, // override texture's left offset - DTA_CenterOffset, // bool: override texture's left and top offsets and set them for the texture's middle - DTA_CenterBottomOffset,// bool: override texture's left and top offsets and set them for the texture's bottom middle - DTA_WindowLeft, // don't draw anything left of this column (on source, not dest) - DTA_WindowRight, // don't draw anything at or to the right of this column (on source, not dest) - DTA_ClipTop, // don't draw anything above this row (on dest, not source) - DTA_ClipBottom, // don't draw anything at or below this row (on dest, not source) - DTA_ClipLeft, // don't draw anything to the left of this column (on dest, not source) - DTA_ClipRight, // don't draw anything at or to the right of this column (on dest, not source) - DTA_Masked, // true(default)=use masks from texture, false=ignore masks - DTA_HUDRules, // use fullscreen HUD rules to position and size textures - DTA_HUDRulesC, // only used internally for marking HUD_HorizCenter - DTA_KeepRatio, // doesn't adjust screen size for DTA_Virtual* if the aspect ratio is not 4:3 - DTA_RenderStyle, // same as render style for actors - DTA_ColorOverlay, // DWORD: ARGB to overlay on top of image; limited to black for software - DTA_Internal1, - DTA_Internal2, - DTA_Desaturate, // explicit desaturation factor (does not do anything in Legacy OpenGL) - DTA_Fullscreen, // Draw image fullscreen (same as DTA_VirtualWidth/Height with graphics size.) - - // floating point duplicates of some of the above: - DTA_DestWidthF, - DTA_DestHeightF, - DTA_TopOffsetF, - DTA_LeftOffsetF, - DTA_VirtualWidthF, - DTA_VirtualHeightF, - DTA_WindowLeftF, - DTA_WindowRightF, - - // For DrawText calls only: - DTA_TextLen, // stop after this many characters, even if \0 not hit - DTA_CellX, // horizontal size of character cell - DTA_CellY, // vertical size of character cell - - DTA_Color, - DTA_FlipY, // bool: flip image vertically - DTA_SrcX, // specify a source rectangle (this supersedes the poorly implemented DTA_WindowLeft/Right - DTA_SrcY, - DTA_SrcWidth, - DTA_SrcHeight, - DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle - DTA_Internal3, - DTA_Spacing, // Strings only: Additional spacing between characters - DTA_Monospace, // Strings only: Use a fixed distance between characters. - - DTA_FullscreenEx, // advanced fullscreen control. -}; - -class Shape2DTransform : Object native -{ - native void Clear(); - native void Rotate(double angle); - native void Scale(Vector2 scaleVec); - native void Translate(Vector2 translateVec); -} - -class Shape2D : Object native -{ - enum EClearWhich - { - C_Verts = 1, - C_Coords = 2, - C_Indices = 4, - }; - - native void SetTransform(Shape2DTransform transform); - - native void Clear( int which = C_Verts|C_Coords|C_Indices ); - native void PushVertex( Vector2 v ); - native void PushCoord( Vector2 c ); - native void PushTriangle( int a, int b, int c ); -} - -struct Screen native -{ - native static Color PaletteColor(int index); - native static int GetWidth(); - native static int GetHeight(); - native static void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1); - native static void Dim(Color col, double amount, int x, int y, int w, int h); - - native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...); - native static vararg void DrawShape(TextureID tex, bool animate, Shape2D s, ...); - native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...); - native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...); - native static void DrawLine(int x0, int y0, int x1, int y1, Color color, int alpha = 255); - native static void DrawThickLine(int x0, int y0, int x1, int y1, double thickness, Color color, int alpha = 255); - native static void DrawFrame(int x, int y, int w, int h); - native static Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true); - native static double GetAspectRatio(); - native static void SetClipRect(int x, int y, int w, int h); - native static void ClearClipRect(); - native static int, int, int, int GetClipRect(); - native static int, int, int, int GetViewWindow(); - - - // This is a leftover of the abandoned Inventory.DrawPowerup method. - deprecated("2.5", "Use StatusBar.DrawTexture() instead") static ui void DrawHUDTexture(TextureID tex, double x, double y) - { - statusBar.DrawTexture(tex, (x, y), BaseStatusBar.DI_SCREEN_RIGHT_TOP, 1., (32, 32)); - } -} - -struct Font native -{ - enum EColorRange - { - CR_UNDEFINED = -1, - CR_BRICK, - CR_TAN, - CR_GRAY, - CR_GREY = CR_GRAY, - CR_GREEN, - CR_BROWN, - CR_GOLD, - CR_RED, - CR_BLUE, - CR_ORANGE, - CR_WHITE, - CR_YELLOW, - CR_UNTRANSLATED, - CR_BLACK, - CR_LIGHTBLUE, - CR_CREAM, - CR_OLIVE, - CR_DARKGREEN, - CR_DARKRED, - CR_DARKBROWN, - CR_PURPLE, - CR_DARKGRAY, - CR_CYAN, - CR_ICE, - CR_FIRE, - CR_SAPPHIRE, - CR_TEAL, - NUM_TEXT_COLORS - }; - - const TEXTCOLOR_BRICK = "\034A"; - const TEXTCOLOR_TAN = "\034B"; - const TEXTCOLOR_GRAY = "\034C"; - const TEXTCOLOR_GREY = "\034C"; - const TEXTCOLOR_GREEN = "\034D"; - const TEXTCOLOR_BROWN = "\034E"; - const TEXTCOLOR_GOLD = "\034F"; - const TEXTCOLOR_RED = "\034G"; - const TEXTCOLOR_BLUE = "\034H"; - const TEXTCOLOR_ORANGE = "\034I"; - const TEXTCOLOR_WHITE = "\034J"; - const TEXTCOLOR_YELLOW = "\034K"; - const TEXTCOLOR_UNTRANSLATED = "\034L"; - const TEXTCOLOR_BLACK = "\034M"; - const TEXTCOLOR_LIGHTBLUE = "\034N"; - const TEXTCOLOR_CREAM = "\034O"; - const TEXTCOLOR_OLIVE = "\034P"; - const TEXTCOLOR_DARKGREEN = "\034Q"; - const TEXTCOLOR_DARKRED = "\034R"; - const TEXTCOLOR_DARKBROWN = "\034S"; - const TEXTCOLOR_PURPLE = "\034T"; - const TEXTCOLOR_DARKGRAY = "\034U"; - const TEXTCOLOR_CYAN = "\034V"; - const TEXTCOLOR_ICE = "\034W"; - const TEXTCOLOR_FIRE = "\034X"; - const TEXTCOLOR_SAPPHIRE = "\034Y"; - const TEXTCOLOR_TEAL = "\034Z"; - - const TEXTCOLOR_NORMAL = "\034-"; - const TEXTCOLOR_BOLD = "\034+"; - - const TEXTCOLOR_CHAT = "\034*"; - const TEXTCOLOR_TEAMCHAT = "\034!"; - - - native int GetCharWidth(int code); - native int StringWidth(String code); - native int GetMaxAscender(String code); - native bool CanPrint(String code); - native int GetHeight(); - native int GetDisplacement(); - native String GetCursor(); - - native static int FindFontColor(Name color); - native double GetBottomAlignOffset(int code); - native static Font FindFont(Name fontname); - native static Font GetFont(Name fontname); - native BrokenLines BreakLines(String text, int maxlen); -} - -struct Translation version("2.4") -{ - Color colors[256]; - - native int AddTranslation(); - native static bool SetPlayerTranslation(int group, int num, int plrnum, PlayerClass pclass); - native static int GetID(Name transname); - static int MakeID(int group, int num) - { - return (group << 16) + num; - } -} - -struct Console native -{ - native static void HideConsole(); - native static void MidPrint(Font fontname, string textlabel, bool bold = false); - native static vararg void Printf(string fmt, ...); -} - -struct DamageTypeDefinition native -{ - native static bool IgnoreArmor(Name type); -} - -struct CVar native -{ - enum ECVarType - { - CVAR_Bool, - CVAR_Int, - CVAR_Float, - CVAR_String, - CVAR_Color, - }; - - native static CVar FindCVar(Name name); - native static CVar GetCVar(Name name, PlayerInfo player = null); - bool GetBool() { return GetInt(); } - native int GetInt(); - native double GetFloat(); - native String GetString(); - void SetBool(bool b) { SetInt(b); } - native void SetInt(int v); - native void SetFloat(double v); - native void SetString(String s); - native int GetRealType(); - native int ResetToDefault(); -} - -struct GIFont version("2.4") -{ - Name fontname; - Name color; -}; - -struct GameInfoStruct native -{ - // will be extended as needed. - native Name backpacktype; - native double Armor2Percent; - native String ArmorIcon1; - native String ArmorIcon2; - native int gametype; - native bool norandomplayerclass; - native Array infoPages; - native String mBackButton; - native GIFont mStatscreenMapNameFont; - native GIFont mStatscreenEnteringFont; - native GIFont mStatscreenFinishedFont; - native GIFont mStatscreenContentFont; - native GIFont mStatscreenAuthorFont; - native double gibfactor; - native bool intermissioncounter; - native Name mSliderColor; - native Color defaultbloodcolor; - native double telefogheight; - native int defKickback; - native int defaultdropstyle; - native TextureID healthpic; - native TextureID berserkpic; - native double normforwardmove[2]; - native double normsidemove[2]; -} - -class Object native -{ - native bool bDestroyed; - - // These must be defined in some class, so that the compiler can find them. Object is just fine, as long as they are private to external code. - private native static Object BuiltinNew(Class cls, int outerclass, int compatibility); - private native static int BuiltinRandom(voidptr rng, int min, int max); - private native static double BuiltinFRandom(voidptr rng, double min, double max); - private native static int BuiltinRandom2(voidptr rng, int mask); - private native static void BuiltinRandomSeed(voidptr rng, int seed); - private native static int BuiltinCallLineSpecial(int special, Actor activator, int arg1, int arg2, int arg3, int arg4, int arg5); - private native static Class BuiltinNameToClass(Name nm, Class filter); - private native static Object BuiltinClassCast(Object inptr, Class test); - - // These really should be global functions... - native static String G_SkillName(); - native static int G_SkillPropertyInt(int p); - native static double G_SkillPropertyFloat(int p); - deprecated("3.8", "Use Level.PickDeathMatchStart() instead") static vector3, int G_PickDeathmatchStart() - { - return level.PickDeathmatchStart(); - } - deprecated("3.8", "Use Level.PickPlayerStart() instead") static vector3, int G_PickPlayerStart(int pnum, int flags = 0) - { - return level.PickPlayerStart(pnum, flags); - } - deprecated("4.3", "Use S_StartSound() instead") native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM, float pitch = 0.0); - native static void S_StartSound (Sound sound_id, int channel, int flags = 0, float volume = 1, float attenuation = ATTN_NORM, float pitch = 0.0, float startTime = 0.0); - native static void S_PauseSound (bool notmusic, bool notsfx); - native static void S_ResumeSound (bool notsfx); - native static bool S_ChangeMusic(String music_name, int order = 0, bool looping = true, bool force = false); - native static float S_GetLength(Sound sound_id); - native static void MarkSound(Sound snd); - native static uint BAM(double angle); - native static void SetMusicVolume(float vol); - native static uint MSTime(); - native vararg static void ThrowAbortException(String fmt, ...); - - native virtualscope void Destroy(); - - // This does not call into the native method of the same name to avoid problems with objects that get garbage collected late on shutdown. - virtual virtualscope void OnDestroy() {} -} - -class BrokenLines : Object native version("2.4") -{ - native int Count(); - native int StringWidth(int line); - native String StringAt(int line); -} - -class Thinker : Object native play -{ - enum EStatnums - { - // Thinkers that don't actually think - STAT_INFO, // An info queue - STAT_DECAL, // A decal - STAT_AUTODECAL, // A decal that can be automatically deleted - STAT_CORPSEPOINTER, // An entry in Hexen's corpse queue - STAT_TRAVELLING, // An actor temporarily travelling to a new map - STAT_STATIC, - - // Thinkers that do think - STAT_FIRST_THINKING=32, - STAT_SCROLLER=STAT_FIRST_THINKING, // A DScroller thinker - STAT_PLAYER, // A player actor - STAT_BOSSTARGET, // A boss brain target - STAT_LIGHTNING, // The lightning thinker - STAT_DECALTHINKER, // An object that thinks for a decal - STAT_INVENTORY, // An inventory item - STAT_LIGHT, // A sector light effect - STAT_LIGHTTRANSFER, // A sector light transfer. These must be ticked after the light effects. - STAT_EARTHQUAKE, // Earthquake actors - STAT_MAPMARKER, // Map marker actors - STAT_DLIGHT, // Dynamic lights - - STAT_USER = 70, - STAT_USER_MAX = 90, - - STAT_DEFAULT = 100, // Thinkers go here unless specified otherwise. - STAT_SECTOREFFECT, // All sector effects that cause floor and ceiling movement - STAT_ACTORMOVER, // actor movers - STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay - STAT_BOT, // Bot thinker - MAX_STATNUM = 127 - } - - const TICRATE = 35; - - native LevelLocals Level; - - virtual native void Tick(); - virtual native void PostBeginPlay(); - native void ChangeStatNum(int stat); - - static clearscope int Tics2Seconds(int tics) - { - return int(tics / TICRATE); - } - -} - -class ThinkerIterator : Object native -{ - native static ThinkerIterator Create(class type = "Actor", int statnum=Thinker.MAX_STATNUM+1); - native Thinker Next(bool exact = false); - native void Reinit(); -} - -class ActorIterator : Object native -{ - deprecated("3.8", "Use Level.CreateActorIterator() instead") static ActorIterator Create(int tid, class type = "Actor") - { - return level.CreateActorIterator(tid, type); - } - native Actor Next(); - native void Reinit(); -} - -class BlockThingsIterator : Object native -{ - native Actor thing; - native Vector3 position; - native int portalflags; - - native static BlockThingsIterator Create(Actor origin, double checkradius = -1, bool ignorerestricted = false); - native static BlockThingsIterator CreateFromPos(double checkx, double checky, double checkz, double checkh, double checkradius, bool ignorerestricted); - native bool Next(); -} - -class BlockLinesIterator : Object native -{ - native Line CurLine; - native Vector3 position; - native int portalflags; - - native static BlockLinesIterator Create(Actor origin, double checkradius = -1); - native static BlockLinesIterator CreateFromPos(Vector3 pos, double checkh, double checkradius, Sector sec = null); - native bool Next(); -} - -enum ETraceStatus -{ - TRACE_Stop, // stop the trace, returning this hit - TRACE_Continue, // continue the trace, returning this hit if there are none further along - TRACE_Skip, // continue the trace; do not return this hit - TRACE_Abort // stop the trace, returning no hits -} - -enum ETraceFlags -{ - TRACE_NoSky = 0x0001, // Hitting the sky returns TRACE_HitNone - //TRACE_PCross = 0x0002, // Trigger SPAC_PCROSS lines - //TRACE_Impact = 0x0004, // Trigger SPAC_IMPACT lines - TRACE_PortalRestrict = 0x0008, // Cannot go through portals without a static link offset. - TRACE_ReportPortals = 0x0010, // Report any portal crossing to the TraceCallback - //TRACE_3DCallback = 0x0020, // [ZZ] use TraceCallback to determine whether we need to go through a line to do 3D floor check, or not. without this, only line flag mask is used - TRACE_HitSky = 0x0040 // Hitting the sky returns TRACE_HasHitSky -} - - -enum ETraceResult -{ - TRACE_HitNone, - TRACE_HitFloor, - TRACE_HitCeiling, - TRACE_HitWall, - TRACE_HitActor, - TRACE_CrossingPortal, - TRACE_HasHitSky -} - -enum ELineTier -{ - TIER_Middle, - TIER_Upper, - TIER_Lower, - TIER_FFloor -} - -struct TraceResults native -{ - native Sector HitSector; // originally called "Sector". cannot be named like this in ZScript. - native TextureID HitTexture; - native vector3 HitPos; - native vector3 HitVector; - native vector3 SrcFromTarget; - native double SrcAngleFromTarget; - - native double Distance; - native double Fraction; - - native Actor HitActor; // valid if hit an actor. // originally called "Actor". - - native Line HitLine; // valid if hit a line // originally called "Line". - native uint8 Side; - native uint8 Tier; // see Tracer.ELineTier - native bool unlinked; // passed through a portal without static offset. - - native ETraceResult HitType; - native F3DFloor ffloor; - - native Sector CrossedWater; // For Boom-style, Transfer_Heights-based deep water - native vector3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash - native Sector Crossed3DWater; // For 3D floor-based deep water - native vector3 Crossed3DWaterPos; -} - -class LineTracer : Object native -{ - native @TraceResults Results; - native bool Trace(vector3 start, Sector sec, vector3 direction, double maxDist, ETraceFlags traceFlags); - - virtual ETraceStatus TraceCallback() - { - // Normally you would examine Results.HitType (for ETraceResult), and determine either: - // - stop tracing and return the entity that was found (return TRACE_Stop) - // - ignore some object, like noclip, e.g. only count solid walls and floors, and ignore actors (return TRACE_Skip) - // - find last object of some type (return TRACE_Continue) - // - stop tracing entirely and assume we found nothing (return TRACE_Abort) - // TRACE_Abort and TRACE_Continue are of limited use in scripting. - - return TRACE_Stop; // default callback returns first hit, whatever it is. - } -} - -struct DropItem native -{ - native readonly DropItem Next; - native readonly name Name; - native readonly int Probability; - native readonly int Amount; -} - -struct LevelLocals native -{ - enum EUDMF - { - UDMF_Line, - UDMF_Side, - UDMF_Sector, - //UDMF_Thing // not implemented - }; - - const CLUSTER_HUB = 0x00000001; // Cluster uses hub behavior - - - native Array<@Sector> Sectors; - native Array<@Line> Lines; - native Array<@Side> Sides; - native readonly Array<@Vertex> Vertexes; - native internal Array<@SectorPortal> SectorPortals; - - native readonly int time; - native readonly int maptime; - native readonly int totaltime; - native readonly int starttime; - native readonly int partime; - native readonly int sucktime; - native readonly int cluster; - native readonly int clusterflags; - native readonly int levelnum; - native readonly String LevelName; - native readonly String MapName; - native String NextMap; - native String NextSecretMap; - native readonly String F1Pic; - native readonly int maptype; - native readonly String AuthorName; - native readonly String Music; - native readonly int musicorder; - native readonly TextureID skytexture1; - native readonly TextureID skytexture2; - native float skyspeed1; - native float skyspeed2; - native int total_secrets; - native int found_secrets; - native int total_items; - native int found_items; - native int total_monsters; - native int killed_monsters; - native play double gravity; - native play double aircontrol; - native play double airfriction; - native play int airsupply; - native readonly double teamdamage; - native readonly bool noinventorybar; - native readonly bool monsterstelefrag; - native readonly bool actownspecial; - native readonly bool sndseqtotalctrl; - native bool allmap; - native readonly bool missilesactivateimpact; - native readonly bool monsterfallingdamage; - native readonly bool checkswitchrange; - native readonly bool polygrind; - native readonly bool nomonsters; - native readonly bool allowrespawn; - deprecated("3.8", "Use Level.isFrozen() instead") native bool frozen; - native readonly bool infinite_flight; - native readonly bool no_dlg_freeze; - native readonly bool keepfullinventory; - native readonly bool removeitems; - native readonly int fogdensity; - native readonly int outsidefogdensity; - native readonly int skyfog; - native readonly float pixelstretch; - native readonly float MusicVolume; - native name deathsequence; - native readonly int compatflags; - native readonly int compatflags2; -// level_info_t *info cannot be done yet. - - native String GetUDMFString(int type, int index, Name key); - native int GetUDMFInt(int type, int index, Name key); - native double GetUDMFFloat(int type, int index, Name key); - native play int ExecuteSpecial(int special, Actor activator, line linedef, bool lineside, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0, int arg5 = 0); - native void GiveSecret(Actor activator, bool printmsg = true, bool playsound = true); - native void StartSlideshow(Name whichone = 'none'); - native static void MakeScreenShot(); - native static void MakeAutoSave(); - native void WorldDone(); - deprecated("3.8", "This function does nothing") static void RemoveAllBots(bool fromlist) { /* intentionally left as no-op. */ } - native ui Vector2 GetAutomapPosition(); - native void SetInterMusic(String nextmap); - native String FormatMapName(int mapnamecolor); - native bool IsJumpingAllowed() const; - native bool IsCrouchingAllowed() const; - native bool IsFreelookAllowed() const; - native void StartIntermission(Name type, int state) const; - native play SpotState GetSpotState(bool create = true); - native int FindUniqueTid(int start = 0, int limit = 0); - native uint GetSkyboxPortal(Actor actor); - native void ReplaceTextures(String from, String to, int flags); - clearscope native HealthGroup FindHealthGroup(int id); - native vector3, int PickDeathmatchStart(); - native vector3, int PickPlayerStart(int pnum, int flags = 0); - native int isFrozen() const; - native void setFrozen(bool on); - - native clearscope Sector PointInSector(Vector2 pt) const; - - native clearscope bool IsPointInLevel(vector3 p) const; - deprecated("3.8", "Use Level.IsPointInLevel() instead") clearscope static bool IsPointInMap(vector3 p) - { - return level.IsPointInLevel(p); - } - - native clearscope vector2 Vec2Diff(vector2 v1, vector2 v2) const; - native clearscope vector3 Vec3Diff(vector3 v1, vector3 v2) const; - native clearscope vector3 SphericalCoords(vector3 viewpoint, vector3 targetPos, vector2 viewAngles = (0, 0), bool absolute = false) const; - - native clearscope vector2 Vec2Offset(vector2 pos, vector2 dir, bool absolute = false) const; - native clearscope vector3 Vec2OffsetZ(vector2 pos, vector2 dir, double atz, bool absolute = false) const; - native clearscope vector3 Vec3Offset(vector3 pos, vector3 dir, bool absolute = false) const; - - native String GetChecksum() const; - - native void ChangeSky(TextureID sky1, TextureID sky2 ); - - native SectorTagIterator CreateSectorTagIterator(int tag, line defline = null); - native LineIdIterator CreateLineIdIterator(int tag); - native ActorIterator CreateActorIterator(int tid, class type = "Actor"); - - String TimeFormatted(bool totals = false) - { - int sec = Thinker.Tics2Seconds(totals? totaltime : time); - return String.Format("%02d:%02d:%02d", sec / 3600, (sec % 3600) / 60, sec % 60); - } - - native play bool CreateCeiling(sector sec, int type, line ln, double speed, double speed2, double height = 0, int crush = -1, int silent = 0, int change = 0, int crushmode = 0 /*Floor.crushDoom*/); - native play bool CreateFloor(sector sec, int floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool crushmode = false, bool hereticlower = false); - - native void ExitLevel(int position, bool keepFacing); - native void SecretExitLevel(int position); -} - -struct StringTable native -{ - native static String Localize(String val, bool prefixed = true); -} - -// a few values of this need to be readable by the play code. -// Most are handled at load time and are omitted here. -struct DehInfo native -{ - native readonly int MaxSoulsphere; - native readonly uint8 ExplosionStyle; - native readonly double ExplosionAlpha; - native readonly int NoAutofreeze; - native readonly int BFGCells; - native readonly int BlueAC; - native readonly int MaxHealth; -} - -struct State native -{ - native readonly State NextState; - native readonly int sprite; - native readonly int16 Tics; - native readonly uint16 TicRange; - native readonly uint8 Frame; - native readonly uint8 UseFlags; - native readonly int Misc1; - native readonly int Misc2; - native readonly uint16 bSlow; - native readonly uint16 bFast; - native readonly bool bFullbright; - native readonly bool bNoDelay; - native readonly bool bSameFrame; - native readonly bool bCanRaise; - native readonly bool bDehacked; - - native int DistanceTo(state other); - native bool ValidateSpriteFrame(); - native TextureID, bool, Vector2 GetSpriteTexture(int rotation, int skin = 0, Vector2 scale = (0,0)); - native bool InStateSequence(State base); -} - -struct Wads -{ - enum WadNamespace - { - ns_hidden = -1, - - ns_global = 0, - ns_sprites, - ns_flats, - ns_colormaps, - ns_acslibrary, - ns_newtextures, - ns_bloodraw, - ns_bloodsfx, - ns_bloodmisc, - ns_strifevoices, - ns_hires, - ns_voxels, - - ns_specialzipdirectory, - ns_sounds, - ns_patches, - ns_graphics, - ns_music, - - ns_firstskin, - } - - enum FindLumpNamespace - { - GlobalNamespace = 0, - AnyNamespace = 1, - } - - native static int CheckNumForName(string name, int ns, int wadnum = -1, bool exact = false); - native static int CheckNumForFullName(string name); - native static int FindLump(string name, int startlump = 0, FindLumpNamespace ns = GlobalNamespace); - native static string ReadLump(int lump); - - native static int GetNumLumps(); - native static string GetLumpName(int lump); - native static string GetLumpFullName(int lump); - native static int GetLumpNamespace(int lump); -} - -struct TerrainDef native -{ - native Name TerrainName; - native int Splash; - native int DamageAmount; - native Name DamageMOD; - native int DamageTimeMask; - native double FootClip; - native float StepVolume; - native int WalkStepTics; - native int RunStepTics; - native Sound LeftStepSound; - native Sound RightStepSound; - native bool IsLiquid; - native bool AllowProtection; - native bool DamageOnLand; - native double Friction; - native double MoveFactor; -}; - -enum EPickStart -{ - PPS_FORCERANDOM = 1, - PPS_NOBLOCKINGCHECK = 2, -} - -enum EmptyTokenType -{ - TOK_SKIPEMPTY = 0, - TOK_KEEPEMPTY = 1, -} - -// Although String is a builtin type, this is a convenient way to attach methods to it. -struct StringStruct native -{ - native static vararg String Format(String fmt, ...); - native vararg void AppendFormat(String fmt, ...); - - native void Replace(String pattern, String replacement); - native String Left(int len) const; - native String Mid(int pos = 0, int len = 2147483647) const; - native void Truncate(int newlen); - native void Remove(int index, int remlen); - deprecated("4.1", "use Left() or Mid() instead") native String CharAt(int pos) const; - deprecated("4.1", "use ByteAt() instead") native int CharCodeAt(int pos) const; - native int ByteAt(int pos) const; - native String Filter(); - native int IndexOf(String substr, int startIndex = 0) const; - deprecated("3.5.1", "use RightIndexOf() instead") native int LastIndexOf(String substr, int endIndex = 2147483647) const; - native int RightIndexOf(String substr, int endIndex = 2147483647) const; - deprecated("4.1", "use MakeUpper() instead") native void ToUpper(); - deprecated("4.1", "use MakeLower() instead") native void ToLower(); - native String MakeUpper() const; - native String MakeLower() const; - native static int CharUpper(int ch); - native static int CharLower(int ch); - native int ToInt(int base = 0) const; - native double ToDouble() const; - native void Split(out Array tokens, String delimiter, EmptyTokenType keepEmpty = TOK_KEEPEMPTY) const; - native void AppendCharacter(int c); - native void DeleteLastCharacter(); - native int CodePointCount() const; - native int, int GetNextCodePoint(int position) const; -} - -class SectorEffect : Thinker native -{ - native protected Sector m_Sector; - - native Sector GetSector(); -} - -class Mover : SectorEffect native -{} - -class MovingFloor : Mover native -{} - -class MovingCeiling : Mover native -{} - -class Floor : MovingFloor native -{ - // only here so that some constants and functions can be added. Not directly usable yet. - enum EFloor - { - floorLowerToLowest, - floorLowerToNearest, - floorLowerToHighest, - floorLowerByValue, - floorRaiseByValue, - floorRaiseToHighest, - floorRaiseToNearest, - floorRaiseAndCrush, - floorRaiseAndCrushDoom, - floorCrushStop, - floorLowerInstant, - floorRaiseInstant, - floorMoveToValue, - floorRaiseToLowestCeiling, - floorRaiseByTexture, - - floorLowerAndChange, - floorRaiseAndChange, - - floorRaiseToLowest, - floorRaiseToCeiling, - floorLowerToLowestCeiling, - floorLowerByTexture, - floorLowerToCeiling, - - donutRaise, - - buildStair, - waitStair, - resetStair, - - // Not to be used as parameters to DoFloor() - genFloorChg0, - genFloorChgT, - genFloorChg - }; - - deprecated("3.8", "Use Level.CreateFloor() instead") static bool CreateFloor(sector sec, int floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool crushmode = false, bool hereticlower = false) - { - return level.CreateFloor(sec, floortype, ln, speed, height, crush, change, crushmode, hereticlower); - } -} - -class Ceiling : MovingCeiling native -{ - enum ECeiling - { - ceilLowerByValue, - ceilRaiseByValue, - ceilMoveToValue, - ceilLowerToHighestFloor, - ceilLowerInstant, - ceilRaiseInstant, - ceilCrushAndRaise, - ceilLowerAndCrush, - ceil_placeholder, - ceilCrushRaiseAndStay, - ceilRaiseToNearest, - ceilLowerToLowest, - ceilLowerToFloor, - - // The following are only used by Generic_Ceiling - ceilRaiseToHighest, - ceilLowerToHighest, - ceilRaiseToLowest, - ceilLowerToNearest, - ceilRaiseToHighestFloor, - ceilRaiseToFloor, - ceilRaiseByTexture, - ceilLowerByTexture, - - genCeilingChg0, - genCeilingChgT, - genCeilingChg - } - - enum ECrushMode - { - crushDoom = 0, - crushHexen = 1, - crushSlowdown = 2 - } - - deprecated("3.8", "Use Level.CreateCeiling() instead") static bool CreateCeiling(sector sec, int type, line ln, double speed, double speed2, double height = 0, int crush = -1, int silent = 0, int change = 0, int crushmode = crushDoom) - { - return level.CreateCeiling(sec, type, ln, speed, speed2, height, crush, silent, change, crushmode); - } - -} - -struct LookExParams -{ - double Fov; - double minDist; - double maxDist; - double maxHeardist; - int flags; - State seestate; -}; - -class Lighting : SectorEffect native -{ -} - -struct Shader native -{ - native clearscope static void SetEnabled(PlayerInfo player, string shaderName, bool enable); - native clearscope static void SetUniform1f(PlayerInfo player, string shaderName, string uniformName, float value); - native clearscope static void SetUniform2f(PlayerInfo player, string shaderName, string uniformName, vector2 value); - native clearscope static void SetUniform3f(PlayerInfo player, string shaderName, string uniformName, vector3 value); - native clearscope static void SetUniform1i(PlayerInfo player, string shaderName, string uniformName, int value); -} - -struct FRailParams -{ - native int damage; - native double offset_xy; - native double offset_z; - native int color1, color2; - native double maxdiff; - native int flags; - native Class puff; - native double angleoffset; - native double pitchoffset; - native double distance; - native int duration; - native double sparsity; - native double drift; - native Class spawnclass; - native int SpiralOffset; - native int limit; -}; // [RH] Shoot a railgun - diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 64884c01890..b4f2d85b7a3 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -36,6 +36,7 @@ enum ESawFlags SF_NOPULLIN = 32, SF_NOTURN = 64, SF_STEALARMOR = 128, + SF_NORANDOMPUFFZ = 256, }; // Flags for A_BFGSpray @@ -139,6 +140,8 @@ enum EChaseFlags CHF_NODIRECTIONTURN = 64, CHF_NOPOSTATTACKTURN = 128, CHF_STOPIFBLOCKED = 256, + CHF_DONTIDLE = 512, + CHF_DONTLOOKALLAROUND = 1024, CHF_DONTTURN = CHF_NORANDOMTURN | CHF_NOPOSTATTACKTURN | CHF_STOPIFBLOCKED }; @@ -229,6 +232,8 @@ enum EMorphFlags MRF_UNDOBYTIMEOUT = 0x00001000, MRF_UNDOALWAYS = 0x00002000, MRF_TRANSFERTRANSLATION = 0x00004000, + MRF_KEEPARMOR = 0x00008000, + MRF_IGNOREINVULN = 0x00010000, MRF_STANDARDUNDOING = MRF_UNDOBYTOMEOFPOWER | MRF_UNDOBYCHAOSDEVICE | MRF_UNDOBYTIMEOUT, }; @@ -259,7 +264,9 @@ enum EExplodeFlags XF_EXPLICITDAMAGETYPE = 8, XF_NOSPLASH = 16, XF_THRUSTZ = 32, - + XF_THRUSTLESS = 64, + XF_NOALLIES = 128, + XF_CIRCULAR = 256, }; // Flags for A_RadiusThrust @@ -284,6 +291,7 @@ enum EBlastFlags BF_DONTWARN = 2, BF_AFFECTBOSSES = 4, BF_NOIMPACTDAMAGE = 8, + BF_ONLYVISIBLETHINGS = 16, }; // Flags for A_SeekerMissile @@ -362,6 +370,22 @@ enum ERadiusGiveFlags RGF_EITHER = 1 << 17, }; +// SetAnimation flags +enum ESetAnimationFlags +{ + SAF_INSTANT = 1 << 0, + SAF_LOOP = 1 << 1, + SAF_NOOVERRIDE = 1 << 2, +}; + +// Change model flags +enum ChangeModelFlags +{ + CMDL_WEAPONTOPLAYER = 1, + CMDL_HIDEMODEL = 1 << 1, + CMDL_USESURFACESKIN = 1 << 2, +}; + // Activation flags enum EActivationFlags { @@ -394,56 +418,20 @@ enum EActivationFlags }; +// [MC] Flags for SetViewPos. +enum EViewPosFlags +{ + VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles. + VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position. + VPSF_ALLOWOUTOFBOUNDS = 1 << 3, // Allow viewpoint to go out of bounds (hardware renderer only). + VPSF_ORTHOGRAPHIC = 1 << 4, // Use orthographic projection (hardware renderer only). +}; + // Flags for A_TakeInventory and A_TakeFromTarget enum ETakeFlags { TIF_NOTAKEINFINITE = 1 }; - -// constants for A_PlaySound -enum ESoundFlags -{ - CHAN_AUTO = 0, - CHAN_WEAPON = 1, - CHAN_VOICE = 2, - CHAN_ITEM = 3, - CHAN_BODY = 4, - CHAN_5 = 5, - CHAN_6 = 6, - CHAN_7 = 7, - - // modifier flags - CHAN_LISTENERZ = 8, - CHAN_MAYBE_LOCAL = 16, - CHAN_UI = 32, - CHAN_NOPAUSE = 64, - CHAN_LOOP = 256, - CHAN_PICKUP = (CHAN_ITEM|CHAN_MAYBE_LOCAL), // Do not use this with A_StartSound! It would not do what is expected. - CHAN_NOSTOP = 4096, - CHAN_OVERLAP = 8192, - - // Same as above, with an F appended to allow better distinction of channel and channel flags. - CHANF_DEFAULT = 0, // just to make the code look better and avoid literal 0's. - CHANF_LISTENERZ = 8, - CHANF_MAYBE_LOCAL = 16, - CHANF_UI = 32, - CHANF_NOPAUSE = 64, - CHANF_LOOP = 256, - CHANF_NOSTOP = 4096, - CHANF_OVERLAP = 8192, - CHANF_LOCAL = 16384, - - - CHANF_LOOPING = CHANF_LOOP | CHANF_NOSTOP, // convenience value for replicating the old 'looping' boolean. - -}; - -// sound attenuation values -const ATTN_NONE = 0; -const ATTN_NORM = 1; -const ATTN_IDLE = 1.001; -const ATTN_STATIC = 3; - // For SetPlayerProperty action special enum EPlayerProperties { @@ -462,6 +450,12 @@ enum EPlayerProperties PROP_FLIGHT = 12, // (Deprecated) PROP_SPEED = 15, // (Deprecated) PROP_BUDDHA = 16, + PROP_BUDDHA2 = 17, + PROP_FRIGHTENING = 18, + PROP_NOCLIP = 19, + PROP_NOCLIP2 = 20, + PROP_GODMODE = 21, + PROP_GODMODE2 = 22, } // Line_SetBlocking @@ -475,6 +469,10 @@ enum EBlockFlags BLOCKF_EVERYTHING = 32, BLOCKF_RAILING = 64, BLOCKF_USE = 128, + BLOCKF_SIGHT = 256, + BLOCKF_HITSCAN = 512, + BLOCKF_SOUND = 1024, + BLOCKF_LANDMONSTERS = 2048, }; // Pointer constants, bitfield-enabled @@ -547,6 +545,7 @@ enum EAngleFlags { SPF_FORCECLAMP = 1, SPF_INTERPOLATE = 2, + SPF_SCALEDNOLERP = 4, }; // flags for A_CheckLOF @@ -665,6 +664,11 @@ enum EQuakeFlags QF_MAX = 1 << 3, QF_FULLINTENSITY = 1 << 4, QF_WAVE = 1 << 5, + QF_3D = 1 << 6, + QF_GROUNDONLY = 1 << 7, + QF_AFFECTACTORS = 1 << 8, + QF_SHAKEONLY = 1 << 9, + QF_DAMAGEFALLOFF = 1 << 10, }; // A_CheckProximity flags @@ -702,14 +706,23 @@ enum ECheckBlockFlags enum EParticleFlags { - SPF_FULLBRIGHT = 1, - SPF_RELPOS = 1 << 1, - SPF_RELVEL = 1 << 2, - SPF_RELACCEL = 1 << 3, - SPF_RELANG = 1 << 4, - SPF_NOTIMEFREEZE = 1 << 5, - - SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG + SPF_FULLBRIGHT = 1 << 0, + SPF_RELPOS = 1 << 1, + SPF_RELVEL = 1 << 2, + SPF_RELACCEL = 1 << 3, + SPF_RELANG = 1 << 4, + SPF_NOTIMEFREEZE = 1 << 5, + SPF_ROLL = 1 << 6, + SPF_REPLACE = 1 << 7, + SPF_NO_XY_BILLBOARD = 1 << 8, + SPF_LOCAL_ANIM = 1 << 9, + SPF_NEGATIVE_FADESTEP = 1 << 10, + SPF_FACECAMERA = 1 << 11, + SPF_NOFACECAMERA = 1 << 12, + SPF_ROLLCENTER = 1 << 13, + SPF_NOMIPMAP = 1 << 14, + + SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG }; //Flags for A_FaceMovementDirection @@ -738,22 +751,36 @@ enum EWeaponOffsetFlags WOF_KEEPY = 1 << 1, WOF_ADD = 1 << 2, WOF_INTERPOLATE = 1 << 3, + WOF_RELATIVE = 1 << 4, + WOF_ZEROY = 1 << 5, }; // Flags for psprite layers enum EPSpriteFlags { - PSPF_ADDWEAPON = 1 << 0, - PSPF_ADDBOB = 1 << 1, - PSPF_POWDOUBLE = 1 << 2, - PSPF_CVARFAST = 1 << 3, - PSPF_ALPHA = 1 << 4, - PSPF_RENDERSTYLE= 1 << 5, - PSPF_FLIP = 1 << 6, - PSPF_FORCEALPHA = 1 << 7, - PSPF_FORCESTYLE = 1 << 8, - PSPF_MIRROR = 1 << 9, - PSPF_PLAYERTRANSLATED = 1 << 10 + PSPF_ADDWEAPON = 1 << 0, + PSPF_ADDBOB = 1 << 1, + PSPF_POWDOUBLE = 1 << 2, + PSPF_CVARFAST = 1 << 3, + PSPF_ALPHA = 1 << 4, + PSPF_RENDERSTYLE = 1 << 5, + PSPF_FLIP = 1 << 6, + PSPF_FORCEALPHA = 1 << 7, + PSPF_FORCESTYLE = 1 << 8, + PSPF_MIRROR = 1 << 9, + PSPF_PLAYERTRANSLATED = 1 << 10, + PSPF_PIVOTPERCENT = 1 << 11, + PSPF_INTERPOLATE = 1 << 12, +}; + +// Alignment constants for A_OverlayPivotAlign +enum EPSpriteAlign +{ + PSPA_TOP = 0, + PSPA_CENTER, + PSPA_BOTTOM, + PSPA_LEFT = PSPA_TOP, + PSPA_RIGHT = 2 }; // Default psprite layers @@ -762,6 +789,9 @@ enum EPSPLayers PSP_STRIFEHANDS = -1, PSP_WEAPON = 1, PSP_FLASH = 1000, + PSP_TARGETCENTER = int.max - 2, + PSP_TARGETLEFT, + PSP_TARGETRIGHT }; enum EInputFlags @@ -821,6 +851,8 @@ enum EButtons BT_USER2 = 1<<22, BT_USER3 = 1<<23, BT_USER4 = 1<<24, + + BT_RUN = 1<<25, }; // Flags for GetAngle @@ -848,31 +880,6 @@ enum EMaskRotationFlags VRF_NOANGLE = VRF_NOANGLESTART|VRF_NOANGLEEND, VRF_NOPITCH = VRF_NOPITCHSTART|VRF_NOPITCHEND, }; - -enum ERenderStyle -{ - STYLE_None, // Do not draw - STYLE_Normal, // Normal; just copy the image to the screen - STYLE_Fuzzy, // Draw silhouette using "fuzz" effect - STYLE_SoulTrans, // Draw translucent with amount in r_transsouls - STYLE_OptFuzzy, // Draw as fuzzy or translucent, based on user preference - STYLE_Stencil, // Fill image interior with alphacolor - STYLE_Translucent, // Draw translucent - STYLE_Add, // Draw additive - STYLE_Shaded, // Treat patch data as alpha values for alphacolor - STYLE_TranslucentStencil, - STYLE_Shadow, - STYLE_Subtract, // Actually this is 'reverse subtract' but this is what normal people would expect by 'subtract'. - STYLE_AddStencil, // Fill image interior with alphacolor - STYLE_AddShaded, // Treat patch data as alpha values for alphacolor - STYLE_Multiply, // Multiply source with destination (HW renderer only.) - STYLE_InverseMultiply, // Multiply source with inverse of destination (HW renderer only.) - STYLE_ColorBlend, // Use color intensity as transparency factor - STYLE_Source, // No blending (only used internally) - STYLE_ColorAdd, // Use color intensity as transparency factor and blend additively. - -}; - // Type definition for the implicit 'callingstate' parameter that gets passed to action functions. enum EStateType { @@ -997,6 +1004,7 @@ enum EMapThingFlags MTF_SECRET = 0x080000, // Secret pickup MTF_NOINFIGHTING = 0x100000, + MTF_NOCOUNT = 0x200000, // Removes COUNTKILL/COUNTITEM }; enum ESkillProperty @@ -1014,6 +1022,8 @@ enum ESkillProperty SKILLP_SlowMonsters, SKILLP_Infight, SKILLP_PlayerRespawn, + SKILLP_SpawnMulti, + SKILLP_InstantReaction, }; enum EFSkillProperty // floating point properties { @@ -1047,7 +1057,6 @@ enum ETranslationTable TRANSLATION_Blood, TRANSLATION_RainPillar, TRANSLATION_Custom, - TRANSLATION_Font, }; enum EFindFloorCeiling @@ -1109,18 +1118,6 @@ enum PaletteFlashFlags PF_HAZARD = 8, }; -enum EGameState -{ - GS_LEVEL, - GS_INTERMISSION, - GS_FINALE, - GS_DEMOSCREEN, - GS_FULLCONSOLE, - GS_HIDECONSOLE, - GS_STARTUP, - GS_TITLELEVEL, -} - enum EGameAction { ga_nothing, @@ -1169,6 +1166,10 @@ enum EPlayerCheats CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame + CF_INTERPVIEWANGLES = 1 << 15, // [MR] flag for interpolating view angles without interpolating the entire frame + CF_NOFOVINTERP = 1 << 16, // [B] Disable FOV interpolation when instantly zooming + CF_SCALEDNOLERP = 1 << 17, // [MR] flag for applying angles changes in the ticrate without interpolating the frame + CF_NOVIEWPOSINTERP = 1 << 18, // Disable view position interpolation. CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. @@ -1186,40 +1187,6 @@ enum EPlayerCheats CF_INFINITEAMMO = 0, }; -const TEXTCOLOR_BRICK = "\034A"; -const TEXTCOLOR_TAN = "\034B"; -const TEXTCOLOR_GRAY = "\034C"; -const TEXTCOLOR_GREY = "\034C"; -const TEXTCOLOR_GREEN = "\034D"; -const TEXTCOLOR_BROWN = "\034E"; -const TEXTCOLOR_GOLD = "\034F"; -const TEXTCOLOR_RED = "\034G"; -const TEXTCOLOR_BLUE = "\034H"; -const TEXTCOLOR_ORANGE = "\034I"; -const TEXTCOLOR_WHITE = "\034J"; -const TEXTCOLOR_YELLOW = "\034K"; -const TEXTCOLOR_UNTRANSLATED = "\034L"; -const TEXTCOLOR_BLACK = "\034M"; -const TEXTCOLOR_LIGHTBLUE = "\034N"; -const TEXTCOLOR_CREAM = "\034O"; -const TEXTCOLOR_OLIVE = "\034P"; -const TEXTCOLOR_DARKGREEN = "\034Q"; -const TEXTCOLOR_DARKRED = "\034R"; -const TEXTCOLOR_DARKBROWN = "\034S"; -const TEXTCOLOR_PURPLE = "\034T"; -const TEXTCOLOR_DARKGRAY = "\034U"; -const TEXTCOLOR_CYAN = "\034V"; -const TEXTCOLOR_ICE = "\034W"; -const TEXTCOLOR_FIRE = "\034X"; -const TEXTCOLOR_SAPPHIRE = "\034Y"; -const TEXTCOLOR_TEAL = "\034Z"; - -const TEXTCOLOR_NORMAL = "\034-"; -const TEXTCOLOR_BOLD = "\034+"; - -const TEXTCOLOR_CHAT = "\034*"; -const TEXTCOLOR_TEAMCHAT = "\034!"; - enum EWeaponState { WF_WEAPONREADY = 1 << 0, // [RH] Weapon is in the ready state and can fire its primary attack @@ -1270,6 +1237,8 @@ enum SPAC SPAC_MUse = 1<<8, // monsters can use SPAC_MPush = 1<<9, // monsters can push SPAC_UseBack = 1<<10, // Can be used from the backside + SPAC_Damage = 1<<11, // [ZZ] when linedef receives damage + SPAC_Death = 1<<12, // [ZZ] when linedef receives damage and has 0 health SPAC_PlayerActivate = (SPAC_Cross|SPAC_Use|SPAC_Impact|SPAC_Push|SPAC_AnyCross|SPAC_UseThrough|SPAC_UseBack), }; @@ -1281,7 +1250,10 @@ enum RadiusDamageFlags RADF_SOURCEISSPOT = 4, RADF_NODAMAGE = 8, RADF_THRUSTZ = 16, - RADF_OLDRADIUSDAMAGE = 32 + RADF_OLDRADIUSDAMAGE = 32, + RADF_THRUSTLESS = 64, + RADF_NOALLIES = 128, + RADF_CIRCULAR = 256 }; enum IntermissionSequenceType @@ -1319,6 +1291,122 @@ enum EChangeLevelFlags CHANGELEVEL_PRERAISEWEAPON = 64, }; +enum ELevelFlags +{ + LEVEL_NOINTERMISSION = 0x00000001, + LEVEL_NOINVENTORYBAR = 0x00000002, // This effects Doom only, since it's the only one without a standard inventory bar. + LEVEL_DOUBLESKY = 0x00000004, + LEVEL_HASFADETABLE = 0x00000008, // Level uses Hexen's fadetable mapinfo to get fog + + LEVEL_MAP07SPECIAL = 0x00000010, + LEVEL_BRUISERSPECIAL = 0x00000020, + LEVEL_CYBORGSPECIAL = 0x00000040, + LEVEL_SPIDERSPECIAL = 0x00000080, + + LEVEL_SPECLOWERFLOOR = 0x00000100, + LEVEL_SPECOPENDOOR = 0x00000200, + LEVEL_SPECLOWERFLOORTOHIGHEST=0x00000300, + LEVEL_SPECACTIONSMASK = 0x00000300, + + LEVEL_MONSTERSTELEFRAG = 0x00000400, + LEVEL_ACTOWNSPECIAL = 0x00000800, + LEVEL_SNDSEQTOTALCTRL = 0x00001000, + LEVEL_FORCETILEDSKY = 0x00002000, + + LEVEL_CROUCH_NO = 0x00004000, + LEVEL_JUMP_NO = 0x00008000, + LEVEL_FREELOOK_NO = 0x00010000, + LEVEL_FREELOOK_YES = 0x00020000, + + // The absence of both of the following bits means that this level does not + // use falling damage (though damage can be forced with dmflags,. + LEVEL_FALLDMG_ZD = 0x00040000, // Level uses ZDoom's falling damage + LEVEL_FALLDMG_HX = 0x00080000, // Level uses Hexen's falling damage + + LEVEL_HEADSPECIAL = 0x00100000, // Heretic episode 1/4 + LEVEL_MINOTAURSPECIAL = 0x00200000, // Heretic episode 2/5 + LEVEL_SORCERER2SPECIAL = 0x00400000, // Heretic episode 3 + LEVEL_SPECKILLMONSTERS = 0x00800000, + + LEVEL_STARTLIGHTNING = 0x01000000, // Automatically start lightning + LEVEL_FILTERSTARTS = 0x02000000, // Apply mapthing filtering to player starts + LEVEL_LOOKUPLEVELNAME = 0x04000000, // Level name is the name of a language string + LEVEL_USEPLAYERSTARTZ = 0x08000000, // Use the Z position of player starts + + LEVEL_SWAPSKIES = 0x10000000, // Used by lightning + LEVEL_NOALLIES = 0x20000000, // i.e. Inside Strife's front base + LEVEL_CHANGEMAPCHEAT = 0x40000000, // Don't display cluster messages + LEVEL_VISITED = 0x80000000, // Used for intermission map + + // The flags uint64_t is now split into 2 DWORDs + LEVEL2_RANDOMPLAYERSTARTS = 0x00000001, // Select single player starts randomnly (no voodoo dolls) + LEVEL2_ALLMAP = 0x00000002, // The player picked up a map on this level + + LEVEL2_LAXMONSTERACTIVATION = 0x00000004, // Monsters can open doors depending on the door speed + LEVEL2_LAXACTIVATIONMAPINFO = 0x00000008, // LEVEL_LAXMONSTERACTIVATION is not a default. + + LEVEL2_MISSILESACTIVATEIMPACT=0x00000010, // Missiles are the activators of SPAC_IMPACT events, not their shooters + LEVEL2_NEEDCLUSTERTEXT = 0x00000020, // A map with this flag needs to retain its cluster intermission texts when being redefined in UMAPINFO + + LEVEL2_KEEPFULLINVENTORY = 0x00000040, // doesn't reduce the amount of inventory items to 1 + + LEVEL2_PRERAISEWEAPON = 0x00000080, // players should spawn with their weapons fully raised (but not when respawning it multiplayer) + LEVEL2_MONSTERFALLINGDAMAGE = 0x00000100, + LEVEL2_CLIPMIDTEX = 0x00000200, + LEVEL2_WRAPMIDTEX = 0x00000400, + + LEVEL2_CHECKSWITCHRANGE = 0x00000800, + + LEVEL2_PAUSE_MUSIC_IN_MENUS = 0x00001000, + LEVEL2_TOTALINFIGHTING = 0x00002000, + LEVEL2_NOINFIGHTING = 0x00004000, + + LEVEL2_NOMONSTERS = 0x00008000, + LEVEL2_INFINITE_FLIGHT = 0x00010000, + + LEVEL2_ALLOWRESPAWN = 0x00020000, + + LEVEL2_FORCETEAMPLAYON = 0x00040000, + LEVEL2_FORCETEAMPLAYOFF = 0x00080000, + + LEVEL2_CONV_SINGLE_UNFREEZE = 0x00100000, + LEVEL2_NOCLUSTERTEXT = 0x00200000, // ignore intermission texts fro clusters. This gets set when UMAPINFO is used to redefine its properties. + LEVEL2_DUMMYSWITCHES = 0x00400000, + LEVEL2_HEXENHACK = 0x00800000, // Level was defined in a Hexen style MAPINFO + + LEVEL2_SMOOTHLIGHTING = 0x01000000, // Level uses the smooth lighting feature. + LEVEL2_POLYGRIND = 0x02000000, // Polyobjects grind corpses to gibs. + LEVEL2_RESETINVENTORY = 0x04000000, // Resets player inventory when starting this level (unless in a hub) + LEVEL2_RESETHEALTH = 0x08000000, // Resets player health when starting this level (unless in a hub) + + LEVEL2_NOSTATISTICS = 0x10000000, // This level should not have statistics collected + LEVEL2_ENDGAME = 0x20000000, // This is an epilogue level that cannot be quit. + LEVEL2_NOAUTOSAVEHINT = 0x40000000, // tell the game that an autosave for this level does not need to be kept + LEVEL2_FORGETSTATE = 0x80000000, // forget this map's state in a hub + + // More flags! + LEVEL3_FORCEFAKECONTRAST = 0x00000001, // forces fake contrast even with fog enabled + LEVEL3_REMOVEITEMS = 0x00000002, // kills all INVBAR items on map change. + LEVEL3_ATTENUATE = 0x00000004, // attenuate lights? + LEVEL3_NOLIGHTFADE = 0x00000008, // no light fading to black. + LEVEL3_NOCOLOREDSPRITELIGHTING = 0x00000010, // draw sprites only with color-less light + LEVEL3_EXITNORMALUSED = 0x00000020, + LEVEL3_EXITSECRETUSED = 0x00000040, + LEVEL3_FORCEWORLDPANNING = 0x00000080, // Forces the world panning flag for all textures, even those without it explicitly set. + LEVEL3_HIDEAUTHORNAME = 0x00000100, + LEVEL3_PROPERMONSTERFALLINGDAMAGE = 0x00000200, // Properly apply falling damage to the monsters + LEVEL3_SKYBOXAO = 0x00000400, // Apply SSAO to sector skies + LEVEL3_E1M8SPECIAL = 0x00000800, + LEVEL3_E2M8SPECIAL = 0x00001000, + LEVEL3_E3M8SPECIAL = 0x00002000, + LEVEL3_E4M8SPECIAL = 0x00004000, + LEVEL3_E4M6SPECIAL = 0x00008000, + LEVEL3_NOSHADOWMAP = 0x00010000, // disables shadowmaps for a given level. + LEVEL3_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support. + LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag. + LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame +}; + // [RH] Compatibility flags. enum ECompatFlags { @@ -1347,7 +1435,8 @@ enum ECompatFlags COMPATF_MINOTAUR = 1 << 22, // Minotaur's floor flame is exploded immediately when feet are clipped COMPATF_MUSHROOM = 1 << 23, // Force original velocity calculations for A_Mushroom in Dehacked mods. COMPATF_MBFMONSTERMOVE = 1 << 24, // Monsters are affected by friction and pushers/pullers. - COMPATF_CORPSEGIBS = 1 << 25, // Crushed monsters are turned into gibs, rather than replaced by gibs. + COMPATF_CORPSEGIBS = 1 << 25, // only needed for some hypothetical mod checking this flag. + COMPATF_VILEGHOSTS = 1 << 25, // Crushed monsters are resurrected as ghosts. COMPATF_NOBLOCKFRIENDS = 1 << 26, // Friendly monsters aren't blocked by monster-blocking lines. COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code. @@ -1366,26 +1455,52 @@ enum ECompatFlags COMPATF2_EXPLODE1 = 1 << 8, // No vertical explosion thrust COMPATF2_EXPLODE2 = 1 << 9, // Use original explosion code throughout. COMPATF2_RAILING = 1 << 10, // Bugged Strife railings. -}; - -enum EMonospacing -{ - Mono_Off = 0, - Mono_CellLeft = 1, - Mono_CellCenter = 2, - Mono_CellRight = 3 -}; - -enum EPrintLevel -{ - PRINT_LOW, // pickup messages - PRINT_MEDIUM, // death messages - PRINT_HIGH, // critical messages - PRINT_CHAT, // chat messages - PRINT_TEAMCHAT, // chat messages from a teammate - PRINT_LOG, // only to logfile - PRINT_BOLD = 200, // What Printf_Bold used - PRINT_TYPES = 1023, // Bitmask. - PRINT_NONOTIFY = 1024, // Flag - do not add to notify buffer - PRINT_NOLOG = 2048, // Flag - do not print to log file + COMPATF2_SCRIPTWAIT = 1 << 11, // Use old scriptwait implementation where it doesn't wait on a non-running script. + COMPATF2_AVOID_HAZARDS = 1 << 12, // another MBF thing. + COMPATF2_STAYONLIFT = 1 << 13, // yet another MBF thing. + COMPATF2_NOMBF21 = 1 << 14, // disable MBF21 features that may clash with certain maps + COMPATF2_VOODOO_ZOMBIES = 1 << 15, // allow playerinfo, playerpawn, and voodoo health to all be different, and allow monster targetting of 'dead' players that have positive health +}; + +const M_E = 2.7182818284590452354; // e +const M_LOG2E = 1.4426950408889634074; // log_2 e +const M_LOG10E = 0.43429448190325182765; // log_10 e +const M_LN2 = 0.69314718055994530942; // log_e 2 +const M_LN10 = 2.30258509299404568402; // log_e 10 +const M_PI = 3.14159265358979323846; // pi +const M_PI_2 = 1.57079632679489661923; // pi/2 +const M_PI_4 = 0.78539816339744830962; // pi/4 +const M_1_PI = 0.31830988618379067154; // 1/pi +const M_2_PI = 0.63661977236758134308; // 2/pi +const M_2_SQRTPI = 1.12837916709551257390; // 2/sqrt(pi) +const M_SQRT2 = 1.41421356237309504880; // sqrt(2) +const M_SQRT1_2 = 0.70710678118654752440; // 1/sqrt(2) + +// Used by Actor.FallAndSink +const WATER_SINK_FACTOR = 0.125; +const WATER_SINK_SMALL_FACTOR = 0.25; +const WATER_SINK_SPEED = 0.5; +const WATER_JUMP_SPEED = 3.5; + + +// for SetModelFlag/ClearModelFlag +enum EModelFlags +{ + // [BB] Color translations for the model skin are ignored. This is + // useful if the skin texture is not using the game palette. + MDL_IGNORETRANSLATION = 1<<0, + MDL_PITCHFROMMOMENTUM = 1<<1, + MDL_ROTATING = 1<<2, + MDL_INTERPOLATEDOUBLEDFRAMES = 1<<3, + MDL_NOINTERPOLATION = 1<<4, + MDL_USEACTORPITCH = 1<<5, + MDL_USEACTORROLL = 1<<6, + MDL_BADROTATION = 1<<7, + MDL_DONTCULLBACKFACES = 1<<8, + MDL_USEROTATIONCENTER = 1<<9, + MDL_NOPERPIXELLIGHTING = 1<<10, // forces a model to not use per-pixel lighting. useful for voxel-converted-to-model objects. + MDL_SCALEWEAPONFOV = 1<<11, // scale weapon view model with higher user FOVs + MDL_MODELSAREATTACHMENTS = 1<<12, // any model index after 0 is treated as an attachment, and therefore will use the bone results of index 0 + MDL_CORRECTPIXELSTRETCH = 1<<13, // ensure model does not distort with pixel stretch when pitch/roll is applied + MDL_FORCECULLBACKFACES = 1<<14, }; diff --git a/wadsrc/static/zscript/destructible.zs b/wadsrc/static/zscript/destructible.zs index a7e0dc9820a..84861a45a84 100644 --- a/wadsrc/static/zscript/destructible.zs +++ b/wadsrc/static/zscript/destructible.zs @@ -28,7 +28,7 @@ struct Destructible native play static native void DamageLinedef(Line def, Actor source, int damage, Name damagetype, int side, vector3 position, bool isradius); static native void GeometryLineAttack(TraceResults trace, Actor thing, int damage, Name damagetype); - static native void GeometryRadiusAttack(Actor bombspot, Actor bombsource, int bombdamage, int bombdistance, Name damagetype, int fulldamagedistance); + static native void GeometryRadiusAttack(Actor bombspot, Actor bombsource, int bombdamage, double bombdistance, Name damagetype, double fulldamagedistance); static native bool ProjectileHitLinedef(Actor projectile, Line def); static native bool ProjectileHitPlane(Actor projectile, SectorPart part); diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs new file mode 100644 index 00000000000..54c44f82196 --- /dev/null +++ b/wadsrc/static/zscript/doombase.zs @@ -0,0 +1,803 @@ + +extend struct _ +{ + native readonly Array > AllActorClasses; + native readonly Array<@PlayerClass> PlayerClasses; + native readonly Array<@PlayerSkin> PlayerSkins; + native readonly Array<@Team> Teams; + native readonly Array<@TerrainDef> Terrains; + native int validcount; + native play @DehInfo deh; + native readonly ui bool automapactive; // is automap enabled? + native readonly ui bool viewactive; // if automap is active, true = main automap, false = overlay automap. + native readonly TextureID skyflatnum; + native readonly int gametic; + native readonly int Net_Arbitrator; + native ui BaseStatusBar StatusBar; + native readonly Weapon WP_NOCHANGE; + deprecated("3.8", "Use Actor.isFrozen() or Level.isFrozen() instead") native readonly bool globalfreeze; + native int LocalViewPitch; + + // sandbox state in multi-level setups: + native play @PlayerInfo players[MAXPLAYERS]; + native readonly bool playeringame[MAXPLAYERS]; + native play LevelLocals Level; + +} + +extend struct TexMan +{ + native static void SetCameraToTexture(Actor viewpoint, String texture, double fov); + native static void SetCameraTextureAspectRatio(String texture, double aspectScale, bool useTextureRatio = true); + deprecated("3.8", "Use Level.ReplaceTextures() instead") static void ReplaceTextures(String from, String to, int flags) + { + level.ReplaceTextures(from, to, flags); + } +} + +extend struct Screen +{ + native static void DrawFrame(int x, int y, int w, int h); + // This is a leftover of the abandoned Inventory.DrawPowerup method. + deprecated("2.5", "Use StatusBar.DrawTexture() instead") static ui void DrawHUDTexture(TextureID tex, double x, double y) + { + statusBar.DrawTexture(tex, (x, y), BaseStatusBar.DI_SCREEN_RIGHT_TOP, 1., (32, 32)); + } +} + +extend struct Console +{ + native static void MidPrint(Font fontname, string textlabel, bool bold = false); +} + +extend struct Translation +{ + native static bool SetPlayerTranslation(int group, int num, int plrnum, PlayerClass pclass); +} + +// This is needed because Actor contains a field named 'translation' which shadows the above. +struct Translate version("4.5") +{ + static TranslationID MakeID(int group, int num) + { + return Translation.MakeID(group, num); + } + static bool SetPlayerTranslation(int group, int num, int plrnum, PlayerClass pclass) + { + return Translation.SetPlayerTranslation(group, num, plrnum, pclass); + } + static TranslationID GetID(Name transname) + { + return Translation.GetID(transname); + } +} + +struct DamageTypeDefinition native +{ + native static bool IgnoreArmor(Name type); +} + +extend struct CVar +{ + native static CVar GetCVar(Name name, PlayerInfo player = null); +} + +extend struct GameInfoStruct +{ + // will be extended as needed. + native Name backpacktype; + native double Armor2Percent; + native String ArmorIcon1; + native String ArmorIcon2; + native Name BasicArmorClass; + native Name HexenArmorClass; + native bool norandomplayerclass; + native Array infoPages; + native GIFont mStatscreenMapNameFont; + native GIFont mStatscreenEnteringFont; + native GIFont mStatscreenFinishedFont; + native GIFont mStatscreenContentFont; + native GIFont mStatscreenAuthorFont; + native double gibfactor; + native bool intermissioncounter; + native Color defaultbloodcolor; + native double telefogheight; + native int defKickback; + native int defaultdropstyle; + native TextureID healthpic; + native TextureID berserkpic; + native double normforwardmove[2]; + native double normsidemove[2]; + native bool mHideParTimes; +} + +extend class Object +{ + private native static Object BuiltinNewDoom(Class cls, int outerclass, int compatibility); + private native static TranslationID BuiltinFindTranslation(Name nm); + private native static int BuiltinCallLineSpecial(int special, Actor activator, int arg1, int arg2, int arg3, int arg4, int arg5); + // These really should be global functions... + native static String G_SkillName(); + native static int G_SkillPropertyInt(int p); + native static double G_SkillPropertyFloat(int p); + deprecated("3.8", "Use Level.PickDeathMatchStart() instead") static vector3, int G_PickDeathmatchStart() + { + let [a,b] = level.PickDeathmatchStart(); + return a, b; + } + deprecated("3.8", "Use Level.PickPlayerStart() instead") static vector3, int G_PickPlayerStart(int pnum, int flags = 0) + { + let [a,b] = level.PickPlayerStart(pnum, flags); + return a, b; + } + deprecated("4.3", "Use S_StartSound() instead") native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM, float pitch = 0.0, float startTime = 0.0); + native static void S_StartSound (Sound sound_id, int channel, int flags = 0, float volume = 1, float attenuation = ATTN_NORM, float pitch = 0.0, float startTime = 0.0); + native static void S_PauseSound (bool notmusic, bool notsfx); + native static void S_ResumeSound (bool notsfx); + native static bool S_ChangeMusic(String music_name, int order = 0, bool looping = true, bool force = false); + native static float S_GetLength(Sound sound_id); + native static void MarkSound(Sound snd); + native static uint BAM(double angle); + native static void SetMusicVolume(float vol); + native clearscope static Object GetNetworkEntity(uint id); + native play void EnableNetworking(bool enable); + native clearscope uint GetNetworkID() const; +} + +class Thinker : Object native play +{ + enum EStatnums + { + // Thinkers that don't actually think + STAT_INFO, // An info queue + STAT_DECAL, // A decal + STAT_AUTODECAL, // A decal that can be automatically deleted + STAT_CORPSEPOINTER, // An entry in Hexen's corpse queue + STAT_TRAVELLING, // An actor temporarily travelling to a new map + STAT_STATIC, + + // Thinkers that do think + STAT_FIRST_THINKING=32, + STAT_SCROLLER=STAT_FIRST_THINKING, // A DScroller thinker + STAT_PLAYER, // A player actor + STAT_BOSSTARGET, // A boss brain target + STAT_LIGHTNING, // The lightning thinker + STAT_DECALTHINKER, // An object that thinks for a decal + STAT_INVENTORY, // An inventory item + STAT_LIGHT, // A sector light effect + STAT_LIGHTTRANSFER, // A sector light transfer. These must be ticked after the light effects. + STAT_EARTHQUAKE, // Earthquake actors + STAT_MAPMARKER, // Map marker actors + STAT_DLIGHT, // Dynamic lights + + STAT_USER = 70, + STAT_USER_MAX = 90, + + STAT_DEFAULT = 100, // Thinkers go here unless specified otherwise. + STAT_SECTOREFFECT, // All sector effects that cause floor and ceiling movement + STAT_ACTORMOVER, // actor movers + STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay + STAT_BOT, // Bot thinker + MAX_STATNUM = 127 + } + + + native LevelLocals Level; + + virtual native void Tick(); + virtual native void PostBeginPlay(); + native void ChangeStatNum(int stat); + + static clearscope int Tics2Seconds(int tics) + { + return int(tics / TICRATE); + } + +} + +class ThinkerIterator : Object native +{ + native static ThinkerIterator Create(class type = "Actor", int statnum=Thinker.MAX_STATNUM+1); + native Thinker Next(bool exact = false); + native void Reinit(); +} + +class ActorIterator : Object native +{ + deprecated("3.8", "Use Level.CreateActorIterator() instead") static ActorIterator Create(int tid, class type = "Actor") + { + return level.CreateActorIterator(tid, type); + } + native Actor Next(); + native void Reinit(); +} + +class BlockThingsIterator : Object native +{ + native Actor thing; + native Vector3 position; + native int portalflags; + + native static BlockThingsIterator Create(Actor origin, double checkradius = -1, bool ignorerestricted = false); + native static BlockThingsIterator CreateFromPos(double checkx, double checky, double checkz, double checkh, double checkradius, bool ignorerestricted); + native bool Next(); +} + +class BlockLinesIterator : Object native +{ + native Line CurLine; + native Vector3 position; + native int portalflags; + + native static BlockLinesIterator Create(Actor origin, double checkradius = -1); + native static BlockLinesIterator CreateFromPos(Vector3 pos, double checkh, double checkradius, Sector sec = null); + native bool Next(); +} + +enum ETraceStatus +{ + TRACE_Stop, // stop the trace, returning this hit + TRACE_Continue, // continue the trace, returning this hit if there are none further along + TRACE_Skip, // continue the trace; do not return this hit + TRACE_Abort // stop the trace, returning no hits +} + +enum ETraceFlags +{ + TRACE_NoSky = 0x0001, // Hitting the sky returns TRACE_HitNone + //TRACE_PCross = 0x0002, // Trigger SPAC_PCROSS lines + //TRACE_Impact = 0x0004, // Trigger SPAC_IMPACT lines + TRACE_PortalRestrict = 0x0008, // Cannot go through portals without a static link offset. + TRACE_ReportPortals = 0x0010, // Report any portal crossing to the TraceCallback + //TRACE_3DCallback = 0x0020, // [ZZ] use TraceCallback to determine whether we need to go through a line to do 3D floor check, or not. without this, only line flag mask is used + TRACE_HitSky = 0x0040 // Hitting the sky returns TRACE_HasHitSky +} + + +enum ETraceResult +{ + TRACE_HitNone, + TRACE_HitFloor, + TRACE_HitCeiling, + TRACE_HitWall, + TRACE_HitActor, + TRACE_CrossingPortal, + TRACE_HasHitSky +} + +enum ELineTier +{ + TIER_Middle, + TIER_Upper, + TIER_Lower, + TIER_FFloor +} + +struct TraceResults native +{ + native Sector HitSector; // originally called "Sector". cannot be named like this in ZScript. + native TextureID HitTexture; + native vector3 HitPos; + native vector3 HitVector; + native vector3 SrcFromTarget; + native double SrcAngleFromTarget; + + native double Distance; + native double Fraction; + + native Actor HitActor; // valid if hit an actor. // originally called "Actor". + + native Line HitLine; // valid if hit a line // originally called "Line". + native uint8 Side; + native uint8 Tier; // see Tracer.ELineTier + native bool unlinked; // passed through a portal without static offset. + + native ETraceResult HitType; + native F3DFloor ffloor; + + native Sector CrossedWater; // For Boom-style, Transfer_Heights-based deep water + native vector3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash + native F3DFloor Crossed3DWater; // For 3D floor-based deep water + native vector3 Crossed3DWaterPos; +} + +class LineTracer : Object native +{ + native @TraceResults Results; + native bool Trace(vector3 start, Sector sec, vector3 direction, double maxDist, ETraceFlags traceFlags, /* Line::ELineFlags */ uint wallMask = 0xFFFFFFFF, bool ignoreAllActors = false, Actor ignore = null); + + virtual ETraceStatus TraceCallback() + { + // Normally you would examine Results.HitType (for ETraceResult), and determine either: + // - stop tracing and return the entity that was found (return TRACE_Stop) + // - ignore some object, like noclip, e.g. only count solid walls and floors, and ignore actors (return TRACE_Skip) + // - find last object of some type (return TRACE_Continue) + // - stop tracing entirely and assume we found nothing (return TRACE_Abort) + // TRACE_Abort and TRACE_Continue are of limited use in scripting. + + return TRACE_Stop; // default callback returns first hit, whatever it is. + } +} + +struct DropItem native +{ + native readonly DropItem Next; + native readonly name Name; + native readonly int Probability; + native readonly int Amount; +} + +struct LevelInfo native +{ + native readonly int levelnum; + native readonly String MapName; + native readonly String NextMap; + native readonly String NextSecretMap; + native readonly String SkyPic1; + native readonly String SkyPic2; + native readonly String F1Pic; + native readonly int cluster; + native readonly int partime; + native readonly int sucktime; + native readonly int flags; + native readonly int flags2; + native readonly int flags3; + native readonly String LightningSound; + native readonly String Music; + native readonly String LevelName; + native readonly String AuthorName; + native readonly int musicorder; + native readonly float skyspeed1; + native readonly float skyspeed2; + native readonly int cdtrack; + native readonly double gravity; + native readonly double aircontrol; + native readonly int airsupply; + native readonly int compatflags; + native readonly int compatflags2; + native readonly name deathsequence; + native readonly int fogdensity; + native readonly int outsidefogdensity; + native readonly int skyfog; + native readonly float pixelstretch; + native readonly name RedirectType; + native readonly String RedirectMapName; + native readonly double teamdamage; + + native bool isValid() const; + native String LookupLevelName() const; + + native static int GetLevelInfoCount(); + native static LevelInfo GetLevelInfo(int index); + native static LevelInfo FindLevelInfo(String mapname); + native static LevelInfo FindLevelByNum(int num); + native static bool MapExists(String mapname); + native static String MapChecksum(String mapname); +} + +struct FSpawnParticleParams +{ + native Color color1; + native TextureID texture; + native int style; + native int flags; + native int lifetime; + + native double size; + native double sizestep; + + native Vector3 pos; + native Vector3 vel; + native Vector3 accel; + + native double startalpha; + native double fadestep; + + native double startroll; + native double rollvel; + native double rollacc; +}; + +struct LevelLocals native +{ + enum EUDMF + { + UDMF_Line, + UDMF_Side, + UDMF_Sector, + //UDMF_Thing // not implemented + }; + + const CLUSTER_HUB = 0x00000001; // Cluster uses hub behavior + + + native Array<@Sector> Sectors; + native Array<@Line> Lines; + native Array<@Side> Sides; + native readonly Array<@Vertex> Vertexes; + native readonly Array<@LinePortal> LinePortals; + native internal readonly Array<@SectorPortal> SectorPortals; + + native readonly int time; + native readonly int maptime; + native readonly int totaltime; + native readonly int starttime; + native readonly int partime; + native readonly int sucktime; + native readonly int cluster; + native readonly int clusterflags; + native readonly int levelnum; + native readonly String LevelName; + native readonly String MapName; + native String NextMap; + native String NextSecretMap; + native readonly String F1Pic; + native readonly int maptype; + native readonly String AuthorName; + native String LightningSound; + native readonly String Music; + native readonly int musicorder; + native readonly TextureID skytexture1; + native readonly TextureID skytexture2; + native float skyspeed1; + native float skyspeed2; + native int total_secrets; + native int found_secrets; + native int total_items; + native int found_items; + native int total_monsters; + native int killed_monsters; + native play double gravity; + native play double aircontrol; + native play double airfriction; + native play int airsupply; + native readonly double teamdamage; + native readonly bool noinventorybar; + native readonly bool monsterstelefrag; + native readonly bool actownspecial; + native readonly bool sndseqtotalctrl; + native bool allmap; + native readonly bool missilesactivateimpact; + native readonly bool monsterfallingdamage; + native readonly bool checkswitchrange; + native readonly bool polygrind; + native readonly bool nomonsters; + native readonly bool allowrespawn; + deprecated("3.8", "Use Level.isFrozen() instead") native bool frozen; + native readonly bool infinite_flight; + native readonly bool no_dlg_freeze; + native readonly bool keepfullinventory; + native readonly bool removeitems; + native readonly bool useplayerstartz; + native readonly int fogdensity; + native readonly int outsidefogdensity; + native readonly int skyfog; + native readonly float pixelstretch; + native readonly float MusicVolume; + native name deathsequence; + native readonly int compatflags; + native readonly int compatflags2; + native readonly LevelInfo info; + + native String GetUDMFString(int type, int index, Name key); + native int GetUDMFInt(int type, int index, Name key); + native double GetUDMFFloat(int type, int index, Name key); + native play int ExecuteSpecial(int special, Actor activator, line linedef, bool lineside, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0, int arg5 = 0); + native void GiveSecret(Actor activator, bool printmsg = true, bool playsound = true); + native void StartSlideshow(Name whichone = 'none'); + native static void MakeScreenShot(); + native static void MakeAutoSave(); + native void WorldDone(); + deprecated("3.8", "This function does nothing") static void RemoveAllBots(bool fromlist) { /* intentionally left as no-op. */ } + native ui Vector2 GetAutomapPosition(); + native void SetInterMusic(String nextmap); + native String FormatMapName(int mapnamecolor); + native bool IsJumpingAllowed() const; + native bool IsCrouchingAllowed() const; + native bool IsFreelookAllowed() const; + native void StartIntermission(Name type, int state) const; + native play SpotState GetSpotState(bool create = true); + native int FindUniqueTid(int start = 0, int limit = 0); + native uint GetSkyboxPortal(Actor actor); + native void ReplaceTextures(String from, String to, int flags); + clearscope native HealthGroup FindHealthGroup(int id); + native vector3, int PickDeathmatchStart(); + native vector3, int PickPlayerStart(int pnum, int flags = 0); + native int isFrozen() const; + native void setFrozen(bool on); + native string LookupString(uint index); + + native clearscope Sector PointInSector(Vector2 pt) const; + + native clearscope bool IsPointInLevel(vector3 p) const; + deprecated("3.8", "Use Level.IsPointInLevel() instead") clearscope static bool IsPointInMap(vector3 p) + { + return level.IsPointInLevel(p); + } + + native clearscope vector2 Vec2Diff(vector2 v1, vector2 v2) const; + native clearscope vector3 Vec3Diff(vector3 v1, vector3 v2) const; + native clearscope vector3 SphericalCoords(vector3 viewpoint, vector3 targetPos, vector2 viewAngles = (0, 0), bool absolute = false) const; + + native clearscope vector2 Vec2Offset(vector2 pos, vector2 dir, bool absolute = false) const; + native clearscope vector3 Vec2OffsetZ(vector2 pos, vector2 dir, double atz, bool absolute = false) const; + native clearscope vector3 Vec3Offset(vector3 pos, vector3 dir, bool absolute = false) const; + native clearscope Vector2 GetDisplacement(int pg1, int pg2) const; + native clearscope int GetPortalGroupCount() const; + native clearscope int PointOnLineSide(Vector2 pos, Line l, bool precise = false) const; + native clearscope int ActorOnLineSide(Actor mo, Line l) const; + native clearscope int BoxOnLineSide(Vector2 pos, double radius, Line l) const; + + native String GetChecksum() const; + + native void ChangeSky(TextureID sky1, TextureID sky2 ); + native void ForceLightning(int mode = 0, sound tempSound = ""); + + native SectorTagIterator CreateSectorTagIterator(int tag, line defline = null); + native LineIdIterator CreateLineIdIterator(int tag); + native ActorIterator CreateActorIterator(int tid, class type = "Actor"); + + String TimeFormatted(bool totals = false) + { + int sec = Thinker.Tics2Seconds(totals? totaltime : time); + return String.Format("%02d:%02d:%02d", sec / 3600, (sec % 3600) / 60, sec % 60); + } + + native play bool CreateCeiling(sector sec, int type, line ln, double speed, double speed2, double height = 0, int crush = -1, int silent = 0, int change = 0, int crushmode = 0 /*Floor.crushDoom*/); + native play bool CreateFloor(sector sec, int floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool crushmode = false, bool hereticlower = false); + + native void ExitLevel(int position, bool keepFacing); + native void SecretExitLevel(int position); + native void ChangeLevel(string levelname, int position = 0, int flags = 0, int skill = -1); + + native String GetClusterName(); + native String GetEpisodeName(); + + native void SpawnParticle(FSpawnParticleParams p); + native VisualThinker SpawnVisualThinker(Class type); +} + +// a few values of this need to be readable by the play code. +// Most are handled at load time and are omitted here. +struct DehInfo native +{ + native readonly int MaxSoulsphere; + native readonly uint8 ExplosionStyle; + native readonly double ExplosionAlpha; + native readonly int NoAutofreeze; + native readonly int BFGCells; + native readonly int BlueAC; + native readonly int MaxHealth; +} + +struct State native +{ + native readonly State NextState; + native readonly int sprite; + native readonly int16 Tics; + native readonly uint16 TicRange; + native readonly uint8 Frame; + native readonly uint8 UseFlags; + native readonly int Misc1; + native readonly int Misc2; + native readonly uint16 bSlow; + native readonly uint16 bFast; + native readonly bool bFullbright; + native readonly bool bNoDelay; + native readonly bool bSameFrame; + native readonly bool bCanRaise; + native readonly bool bDehacked; + + native int DistanceTo(state other) const; + native bool ValidateSpriteFrame() const; + native TextureID, bool, Vector2 GetSpriteTexture(int rotation, int skin = 0, Vector2 scale = (0,0), int spritenum = -1, int framenum = -1) const; + native bool InStateSequence(State base) const; +} + +struct TerrainDef native +{ + native Name TerrainName; + native int Splash; + native int DamageAmount; + native Name DamageMOD; + native int DamageTimeMask; + native double FootClip; + native float StepVolume; + native int WalkStepTics; + native int RunStepTics; + native Sound LeftStepSound; + native Sound RightStepSound; + native bool IsLiquid; + native bool AllowProtection; + native bool DamageOnLand; + native double Friction; + native double MoveFactor; +}; + +enum EPickStart +{ + PPS_FORCERANDOM = 1, + PPS_NOBLOCKINGCHECK = 2, +} + + +enum EMissileHitResult +{ + MHIT_DEFAULT = -1, + MHIT_DESTROY = 0, + MHIT_PASS = 1, +} + +class SectorEffect : Thinker native +{ + native protected Sector m_Sector; + + native Sector GetSector(); +} + +class Mover : SectorEffect native +{} + +class MovingFloor : Mover native +{} + +class MovingCeiling : Mover native +{} + +class Floor : MovingFloor native +{ + // only here so that some constants and functions can be added. Not directly usable yet. + enum EFloor + { + floorLowerToLowest, + floorLowerToNearest, + floorLowerToHighest, + floorLowerByValue, + floorRaiseByValue, + floorRaiseToHighest, + floorRaiseToNearest, + floorRaiseAndCrush, + floorRaiseAndCrushDoom, + floorCrushStop, + floorLowerInstant, + floorRaiseInstant, + floorMoveToValue, + floorRaiseToLowestCeiling, + floorRaiseByTexture, + + floorLowerAndChange, + floorRaiseAndChange, + + floorRaiseToLowest, + floorRaiseToCeiling, + floorLowerToLowestCeiling, + floorLowerByTexture, + floorLowerToCeiling, + + donutRaise, + + buildStair, + waitStair, + resetStair, + + // Not to be used as parameters to DoFloor() + genFloorChg0, + genFloorChgT, + genFloorChg + }; + + deprecated("3.8", "Use Level.CreateFloor() instead") static bool CreateFloor(sector sec, int floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool crushmode = false, bool hereticlower = false) + { + return level.CreateFloor(sec, floortype, ln, speed, height, crush, change, crushmode, hereticlower); + } +} + +class Ceiling : MovingCeiling native +{ + enum ECeiling + { + ceilLowerByValue, + ceilRaiseByValue, + ceilMoveToValue, + ceilLowerToHighestFloor, + ceilLowerInstant, + ceilRaiseInstant, + ceilCrushAndRaise, + ceilLowerAndCrush, + ceil_placeholder, + ceilCrushRaiseAndStay, + ceilRaiseToNearest, + ceilLowerToLowest, + ceilLowerToFloor, + + // The following are only used by Generic_Ceiling + ceilRaiseToHighest, + ceilLowerToHighest, + ceilRaiseToLowest, + ceilLowerToNearest, + ceilRaiseToHighestFloor, + ceilRaiseToFloor, + ceilRaiseByTexture, + ceilLowerByTexture, + + genCeilingChg0, + genCeilingChgT, + genCeilingChg + } + + enum ECrushMode + { + crushDoom = 0, + crushHexen = 1, + crushSlowdown = 2 + } + + deprecated("3.8", "Use Level.CreateCeiling() instead") static bool CreateCeiling(sector sec, int type, line ln, double speed, double speed2, double height = 0, int crush = -1, int silent = 0, int change = 0, int crushmode = crushDoom) + { + return level.CreateCeiling(sec, type, ln, speed, speed2, height, crush, silent, change, crushmode); + } + +} + +struct LookExParams +{ + double Fov; + double minDist; + double maxDist; + double maxHeardist; + int flags; + State seestate; +}; + +class Lighting : SectorEffect native +{ +} + +struct Shader native +{ + // This interface was deprecated for the pointless player dependency + private static bool IsConsolePlayer(PlayerInfo player) + { + return player && player.mo && player == players[consoleplayer]; + } + deprecated("4.8", "Use PPShader.SetEnabled() instead") clearscope static void SetEnabled(PlayerInfo player, string shaderName, bool enable) + { + if (IsConsolePlayer(player)) PPShader.SetEnabled(shaderName, enable); + } + deprecated("4.8", "Use PPShader.SetUniform1f() instead") clearscope static void SetUniform1f(PlayerInfo player, string shaderName, string uniformName, float value) + { + if (IsConsolePlayer(player)) PPShader.SetUniform1f(shaderName, uniformName, value); + } + deprecated("4.8", "Use PPShader.SetUniform2f() instead") clearscope static void SetUniform2f(PlayerInfo player, string shaderName, string uniformName, vector2 value) + { + if (IsConsolePlayer(player)) PPShader.SetUniform2f(shaderName, uniformName, value); + } + deprecated("4.8", "Use PPShader.SetUniform3f() instead") clearscope static void SetUniform3f(PlayerInfo player, string shaderName, string uniformName, vector3 value) + { + if (IsConsolePlayer(player)) PPShader.SetUniform3f(shaderName, uniformName, value); + } + deprecated("4.8", "Use PPShader.SetUniform1i() instead") clearscope static void SetUniform1i(PlayerInfo player, string shaderName, string uniformName, int value) + { + if (IsConsolePlayer(player)) PPShader.SetUniform1i(shaderName, uniformName, value); + } +} + +struct FRailParams +{ + native int damage; + native double offset_xy; + native double offset_z; + native int color1, color2; + native double maxdiff; + native int flags; + native Class puff; + native double angleoffset; + native double pitchoffset; + native double distance; + native int duration; + native double sparsity; + native double drift; + native Class spawnclass; + native int SpiralOffset; + native int limit; +}; // [RH] Shoot a railgun diff --git a/wadsrc/static/zscript/dynarrays.zs b/wadsrc/static/zscript/dynarrays.zs deleted file mode 100644 index 2e80820cd86..00000000000 --- a/wadsrc/static/zscript/dynarrays.zs +++ /dev/null @@ -1,162 +0,0 @@ -// The VM uses 7 integral data types, so for dynamic array support we need one specific set of functions for each of these types. -// Do not use these structs directly, they are incomplete and only needed to create prototypes for the needed functions. - -struct DynArray_I8 native -{ - native readonly uint Size; - - native void Copy(DynArray_I8 other); - native void Move(DynArray_I8 other); - native void Append (DynArray_I8 other); - native uint Find(int item) const; - native uint Push (int item); - native bool Pop (); - native void Delete (uint index, int deletecount = 1); - native void Insert (uint index, int item); - native void ShrinkToFit (); - native void Grow (uint amount); - native void Resize (uint amount); - native uint Reserve (uint amount); - native uint Max () const; - native void Clear (); -} - -struct DynArray_I16 native -{ - native readonly uint Size; - - native void Copy(DynArray_I16 other); - native void Move(DynArray_I16 other); - native void Append (DynArray_I16 other); - native uint Find(int item) const; - native uint Push (int item); - native bool Pop (); - native void Delete (uint index, int deletecount = 1); - native void Insert (uint index, int item); - native void ShrinkToFit (); - native void Grow (uint amount); - native void Resize (uint amount); - native uint Reserve (uint amount); - native uint Max () const; - native void Clear (); -} - -struct DynArray_I32 native -{ - native readonly uint Size; - - native void Copy(DynArray_I32 other); - native void Move(DynArray_I32 other); - native void Append (DynArray_I32 other); - native uint Find(int item) const; - native uint Push (int item); - native bool Pop (); - native void Delete (uint index, int deletecount = 1); - native void Insert (uint index, int item); - native void ShrinkToFit (); - native void Grow (uint amount); - native void Resize (uint amount); - native uint Reserve (uint amount); - native uint Max () const; - native void Clear (); -} - -struct DynArray_F32 native -{ - native readonly uint Size; - - native void Copy(DynArray_F32 other); - native void Move(DynArray_F32 other); - native void Append (DynArray_F32 other); - native uint Find(double item) const; - native uint Push (double item); - native bool Pop (); - native void Delete (uint index, int deletecount = 1); - native void Insert (uint index, double item); - native void ShrinkToFit (); - native void Grow (uint amount); - native void Resize (uint amount); - native uint Reserve (uint amount); - native uint Max () const; - native void Clear (); -} - -struct DynArray_F64 native -{ - native readonly uint Size; - - native void Copy(DynArray_F64 other); - native void Move(DynArray_F64 other); - native void Append (DynArray_F64 other); - native uint Find(double item) const; - native uint Push (double item); - native bool Pop (); - native void Delete (uint index, int deletecount = 1); - native void Insert (uint index, double item); - native void ShrinkToFit (); - native void Grow (uint amount); - native void Resize (uint amount); - native uint Reserve (uint amount); - native uint Max () const; - native void Clear (); -} - -struct DynArray_Ptr native -{ - native readonly uint Size; - - native void Copy(DynArray_Ptr other); - native void Move(DynArray_Ptr other); - native void Append (DynArray_Ptr other); - native uint Find(voidptr item) const; - native uint Push (voidptr item); - native bool Pop (); - native void Delete (uint index, int deletecount = 1); - native void Insert (uint index, voidptr item); - native void ShrinkToFit (); - native void Grow (uint amount); - native void Resize (uint amount); - native uint Reserve (uint amount); - native uint Max () const; - native void Clear (); -} - -struct DynArray_Obj native -{ - native readonly uint Size; - - native void Copy(DynArray_Obj other); - native void Move(DynArray_Obj other); - native void Append (DynArray_Obj other); - native uint Find(Object item) const; - native uint Push (Object item); - native bool Pop (); - native void Delete (uint index, int deletecount = 1); - native void Insert (uint index, Object item); - native void ShrinkToFit (); - native void Grow (uint amount); - native void Resize (uint amount); - native uint Reserve (uint amount); - native uint Max () const; - native void Clear (); -} - -struct DynArray_String native -{ - native readonly uint Size; - - native void Copy(DynArray_String other); - native void Move(DynArray_String other); - native void Append (DynArray_String other); - native uint Find(String item) const; - native uint Push (String item); - native bool Pop (); - native void Delete (uint index, int deletecount = 1); - native void Insert (uint index, String item); - native void ShrinkToFit (); - native void Grow (uint amount); - native void Resize (uint amount); - native uint Reserve (uint amount); - native uint Max () const; - native void Clear (); -} diff --git a/wadsrc/static/zscript/engine/base.zs b/wadsrc/static/zscript/engine/base.zs new file mode 100644 index 00000000000..f24b71d013d --- /dev/null +++ b/wadsrc/static/zscript/engine/base.zs @@ -0,0 +1,1008 @@ + + +// constants for A_PlaySound +enum ESoundFlags +{ + CHAN_AUTO = 0, + CHAN_WEAPON = 1, + CHAN_VOICE = 2, + CHAN_ITEM = 3, + CHAN_BODY = 4, + CHAN_5 = 5, + CHAN_6 = 6, + CHAN_7 = 7, + + // modifier flags + CHAN_LISTENERZ = 8, + CHAN_MAYBE_LOCAL = 16, + CHAN_UI = 32, + CHAN_NOPAUSE = 64, + CHAN_LOOP = 256, + CHAN_PICKUP = (CHAN_ITEM|CHAN_MAYBE_LOCAL), // Do not use this with A_StartSound! It would not do what is expected. + CHAN_NOSTOP = 4096, + CHAN_OVERLAP = 8192, + + // Same as above, with an F appended to allow better distinction of channel and channel flags. + CHANF_DEFAULT = 0, // just to make the code look better and avoid literal 0's. + CHANF_LISTENERZ = 8, + CHANF_MAYBE_LOCAL = 16, + CHANF_UI = 32, + CHANF_NOPAUSE = 64, + CHANF_LOOP = 256, + CHANF_NOSTOP = 4096, + CHANF_OVERLAP = 8192, + CHANF_LOCAL = 16384, + + + CHANF_LOOPING = CHANF_LOOP | CHANF_NOSTOP, // convenience value for replicating the old 'looping' boolean. + +}; + +// sound attenuation values +const ATTN_NONE = 0; +const ATTN_NORM = 1; +const ATTN_IDLE = 1.001; +const ATTN_STATIC = 3; + + +enum ERenderStyle +{ + STYLE_None, // Do not draw + STYLE_Normal, // Normal; just copy the image to the screen + STYLE_Fuzzy, // Draw silhouette using "fuzz" effect + STYLE_SoulTrans, // Draw translucent with amount in r_transsouls + STYLE_OptFuzzy, // Draw as fuzzy or translucent, based on user preference + STYLE_Stencil, // Fill image interior with alphacolor + STYLE_Translucent, // Draw translucent + STYLE_Add, // Draw additive + STYLE_Shaded, // Treat patch data as alpha values for alphacolor + STYLE_TranslucentStencil, + STYLE_Shadow, + STYLE_Subtract, // Actually this is 'reverse subtract' but this is what normal people would expect by 'subtract'. + STYLE_AddStencil, // Fill image interior with alphacolor + STYLE_AddShaded, // Treat patch data as alpha values for alphacolor + STYLE_Multiply, // Multiply source with destination (HW renderer only.) + STYLE_InverseMultiply, // Multiply source with inverse of destination (HW renderer only.) + STYLE_ColorBlend, // Use color intensity as transparency factor + STYLE_Source, // No blending (only used internally) + STYLE_ColorAdd, // Use color intensity as transparency factor and blend additively. + +}; + + +enum EGameState +{ + GS_LEVEL, + GS_INTERMISSION, + GS_FINALE, + GS_DEMOSCREEN, + GS_FULLCONSOLE, // [RH] Fullscreen console + GS_HIDECONSOLE, // [RH] The menu just did something that should hide fs console + GS_STARTUP, // [RH] Console is fullscreen, and game is just starting + GS_TITLELEVEL, // [RH] A combination of GS_LEVEL and GS_DEMOSCREEN + GS_INTRO, + GS_CUTSCENE, + + GS_MENUSCREEN = GS_DEMOSCREEN, +} + +const TEXTCOLOR_BRICK = "\034A"; +const TEXTCOLOR_TAN = "\034B"; +const TEXTCOLOR_GRAY = "\034C"; +const TEXTCOLOR_GREY = "\034C"; +const TEXTCOLOR_GREEN = "\034D"; +const TEXTCOLOR_BROWN = "\034E"; +const TEXTCOLOR_GOLD = "\034F"; +const TEXTCOLOR_RED = "\034G"; +const TEXTCOLOR_BLUE = "\034H"; +const TEXTCOLOR_ORANGE = "\034I"; +const TEXTCOLOR_WHITE = "\034J"; +const TEXTCOLOR_YELLOW = "\034K"; +const TEXTCOLOR_UNTRANSLATED = "\034L"; +const TEXTCOLOR_BLACK = "\034M"; +const TEXTCOLOR_LIGHTBLUE = "\034N"; +const TEXTCOLOR_CREAM = "\034O"; +const TEXTCOLOR_OLIVE = "\034P"; +const TEXTCOLOR_DARKGREEN = "\034Q"; +const TEXTCOLOR_DARKRED = "\034R"; +const TEXTCOLOR_DARKBROWN = "\034S"; +const TEXTCOLOR_PURPLE = "\034T"; +const TEXTCOLOR_DARKGRAY = "\034U"; +const TEXTCOLOR_CYAN = "\034V"; +const TEXTCOLOR_ICE = "\034W"; +const TEXTCOLOR_FIRE = "\034X"; +const TEXTCOLOR_SAPPHIRE = "\034Y"; +const TEXTCOLOR_TEAL = "\034Z"; + +const TEXTCOLOR_NORMAL = "\034-"; +const TEXTCOLOR_BOLD = "\034+"; + +const TEXTCOLOR_CHAT = "\034*"; +const TEXTCOLOR_TEAMCHAT = "\034!"; + + +enum EMonospacing +{ + Mono_Off = 0, + Mono_CellLeft = 1, + Mono_CellCenter = 2, + Mono_CellRight = 3 +}; + +enum EPrintLevel +{ + PRINT_LOW, // pickup messages + PRINT_MEDIUM, // death messages + PRINT_HIGH, // critical messages + PRINT_CHAT, // chat messages + PRINT_TEAMCHAT, // chat messages from a teammate + PRINT_LOG, // only to logfile + PRINT_BOLD = 200, // What Printf_Bold used + PRINT_TYPES = 1023, // Bitmask. + PRINT_NONOTIFY = 1024, // Flag - do not add to notify buffer + PRINT_NOLOG = 2048, // Flag - do not print to log file +}; + +enum EConsoleState +{ + c_up = 0, + c_down = 1, + c_falling = 2, + c_rising = 3 +}; + +/* +// These are here to document the intrinsic methods and fields available on +// the built-in ZScript types +struct Vector2 +{ + Vector2(x, y); + double x, y; + native double Length(); + native Vector2 Unit(); + // The dot product of two vectors can be calculated like this: + // double d = a dot b; +} + +struct Vector3 +{ + Vector3(x, y, z); + double x, y, z; + Vector2 xy; // Convenient access to the X and Y coordinates of a 3D vector + native double Length(); + native Vector3 Unit(); + // The dot product of two vectors can be calculated like this: + // double d = a dot b; + // The cross product of two vectors can be calculated like this: + // Vector3 d = a cross b; +} +*/ + +struct _ native // These are the global variables, the struct is only here to avoid extending the parser for this. +{ + native readonly Array AllClasses; + native internal readonly Map AllServices; + native readonly bool multiplayer; + native @KeyBindings Bindings; + native @KeyBindings AutomapBindings; + native readonly @GameInfoStruct gameinfo; + native readonly ui bool netgame; + native readonly uint gameaction; + native readonly int gamestate; + native readonly Font smallfont; + native readonly Font smallfont2; + native readonly Font bigfont; + native readonly Font confont; + native readonly Font NewConsoleFont; + native readonly Font NewSmallFont; + native readonly Font AlternativeSmallFont; + native readonly Font AlternativeBigFont; + native readonly Font OriginalSmallFont; + native readonly Font OriginalBigFont; + native readonly Font intermissionfont; + native readonly int CleanXFac; + native readonly int CleanYFac; + native readonly int CleanWidth; + native readonly int CleanHeight; + native readonly int CleanXFac_1; + native readonly int CleanYFac_1; + native readonly int CleanWidth_1; + native readonly int CleanHeight_1; + native ui int menuactive; + native readonly @FOptionMenuSettings OptionMenuSettings; + native readonly bool demoplayback; + native ui int BackbuttonTime; + native ui float BackbuttonAlpha; + native readonly @MusPlayingInfo musplaying; + native readonly bool generic_ui; + native readonly int GameTicRate; + native MenuDelegateBase menuDelegate; + native readonly int consoleplayer; + native readonly double NotifyFontScale; + native readonly int paused; + native readonly ui uint8 ConsoleState; +} + +struct System native +{ + native static void StopMusic(); + native static void StopAllSounds(); + native static bool SoundEnabled(); + native static bool MusicEnabled(); + native static double GetTimeFrac(); + + static bool specialKeyEvent(InputEvent ev) + { + if (ev.type == InputEvent.Type_KeyDown || ev.type == InputEvent.Type_KeyUp) + { + int key = ev.KeyScan; + let binding = Bindings.GetBinding(key); + bool volumekeys = key == InputEvent.KEY_VOLUMEDOWN || key == InputEvent.KEY_VOLUMEUP; + bool gamepadkeys = key > InputEvent.KEY_LASTJOYBUTTON && key < InputEvent.KEY_PAD_LTHUMB_RIGHT; + bool altkeys = key == InputEvent.KEY_LALT || key == InputEvent.KEY_RALT; + if (volumekeys || gamepadkeys || altkeys || binding ~== "screenshot") return true; + } + return false; + } +} + +struct MusPlayingInfo native +{ + native String name; + native int baseorder; + native bool loop; + native voidptr handle; + +}; + +struct TexMan +{ + enum EUseTypes + { + Type_Any, + Type_Wall, + Type_Flat, + Type_Sprite, + Type_WallPatch, + Type_Build, + Type_SkinSprite, + Type_Decal, + Type_MiscPatch, + Type_FontChar, + Type_Override, // For patches between TX_START/TX_END + Type_Autopage, // Automap background - used to enable the use of FAutomapTexture + Type_SkinGraphic, + Type_Null, + Type_FirstDefined, + }; + + enum EFlags + { + TryAny = 1, + Overridable = 2, + ReturnFirst = 4, + AllowSkins = 8, + ShortNameOnly = 16, + DontCreate = 32, + Localize = 64, + ForceLookup = 128, + NoAlias = 256 + }; + + enum ETexReplaceFlags + { + NOT_BOTTOM = 1, + NOT_MIDDLE = 2, + NOT_TOP = 4, + NOT_FLOOR = 8, + NOT_CEILING = 16, + NOT_WALL = 7, + NOT_FLAT = 24 + }; + + native static TextureID CheckForTexture(String name, int usetype = Type_Any, int flags = TryAny); + native static String GetName(TextureID tex); + native static int, int GetSize(TextureID tex); + native static Vector2 GetScaledSize(TextureID tex); + native static Vector2 GetScaledOffset(TextureID tex); + native static int CheckRealHeight(TextureID tex); + native static bool OkForLocalization(TextureID patch, String textSubstitute); + native static bool UseGamePalette(TextureID tex); + native static Canvas GetCanvas(String texture); +} + +/* +// Intrinsic TextureID methods +// This isn't really a class, and can be used as an integer +struct TextureID +{ + native bool IsValid(); + native bool IsNull(); + native bool Exists(); + native void SetInvalid(); + native void SetNull(); +} + +// 32-bit RGBA color - each component is one byte, or 8-bit +// This isn't really a class, and can be used as an integer +struct Color +{ + // Constructor - alpha channel is optional + Color(int alpha, int red, int green, int blue); + Color(int red, int green, int blue); // Alpha is 0 if omitted + int r; // Red + int g; // Green + int b; // Blue + int a; // Alpha +} + +// Name - a string with an integer ID +struct Name +{ + Name(Name name); + Name(String name); +} + +// Sound ID - can be created by casting from a string (name from SNDINFO) or an +// integer (sound ID as integer). +struct Sound +{ + Sound(String soundName); + Sound(int id); +} +*/ + +enum EScaleMode +{ + FSMode_None = 0, + FSMode_ScaleToFit = 1, + FSMode_ScaleToFill = 2, + FSMode_ScaleToFit43 = 3, + FSMode_ScaleToScreen = 4, + FSMode_ScaleToFit43Top = 5, + FSMode_ScaleToFit43Bottom = 6, + FSMode_ScaleToHeight = 7, + + + FSMode_Max, + + // These all use ScaleToFit43, their purpose is to cut down on verbosity because they imply the virtual screen size. + FSMode_Predefined = 1000, + FSMode_Fit320x200 = 1000, + FSMode_Fit320x240, + FSMode_Fit640x400, + FSMode_Fit640x480, + FSMode_Fit320x200Top, + FSMode_Predefined_Max, +}; + +enum DrawTextureTags +{ + TAG_USER = (1<<30), + DTA_Base = TAG_USER + 5000, + DTA_DestWidth, // width of area to draw to + DTA_DestHeight, // height of area to draw to + DTA_Alpha, // alpha value for translucency + DTA_FillColor, // color to stencil onto the destination (RGB is the color for truecolor drawers, A is the palette index for paletted drawers) + DTA_TranslationIndex, // translation table to recolor the source + DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor + DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac + DTA_320x200, // bool: scale texture size and position to fit on a virtual 320x200 screen + DTA_Bottom320x200, // bool: same as DTA_320x200 but centers virtual screen on bottom for 1280x1024 targets + DTA_CleanNoMove, // bool: like DTA_Clean but does not reposition output position + DTA_CleanNoMove_1, // bool: like DTA_CleanNoMove, but uses Clean[XY]fac_1 instead + DTA_FlipX, // bool: flip image horizontally //FIXME: Does not work with DTA_Window(Left|Right) + DTA_ShadowColor, // color of shadow + DTA_ShadowAlpha, // alpha of shadow + DTA_Shadow, // set shadow color and alphas to defaults + DTA_VirtualWidth, // pretend the canvas is this wide + DTA_VirtualHeight, // pretend the canvas is this tall + DTA_TopOffset, // override texture's top offset + DTA_LeftOffset, // override texture's left offset + DTA_CenterOffset, // bool: override texture's left and top offsets and set them for the texture's middle + DTA_CenterBottomOffset,// bool: override texture's left and top offsets and set them for the texture's bottom middle + DTA_WindowLeft, // don't draw anything left of this column (on source, not dest) + DTA_WindowRight, // don't draw anything at or to the right of this column (on source, not dest) + DTA_ClipTop, // don't draw anything above this row (on dest, not source) + DTA_ClipBottom, // don't draw anything at or below this row (on dest, not source) + DTA_ClipLeft, // don't draw anything to the left of this column (on dest, not source) + DTA_ClipRight, // don't draw anything at or to the right of this column (on dest, not source) + DTA_Masked, // true(default)=use masks from texture, false=ignore masks + DTA_HUDRules, // use fullscreen HUD rules to position and size textures + DTA_HUDRulesC, // only used internally for marking HUD_HorizCenter + DTA_KeepRatio, // doesn't adjust screen size for DTA_Virtual* if the aspect ratio is not 4:3 + DTA_RenderStyle, // same as render style for actors + DTA_ColorOverlay, // DWORD: ARGB to overlay on top of image; limited to black for software + DTA_Internal1, + DTA_Internal2, + DTA_Desaturate, // explicit desaturation factor (does not do anything in Legacy OpenGL) + DTA_Fullscreen, // Draw image fullscreen (same as DTA_VirtualWidth/Height with graphics size.) + + // floating point duplicates of some of the above: + DTA_DestWidthF, + DTA_DestHeightF, + DTA_TopOffsetF, + DTA_LeftOffsetF, + DTA_VirtualWidthF, + DTA_VirtualHeightF, + DTA_WindowLeftF, + DTA_WindowRightF, + + // For DrawText calls only: + DTA_TextLen, // stop after this many characters, even if \0 not hit + DTA_CellX, // horizontal size of character cell + DTA_CellY, // vertical size of character cell + + DTA_Color, + DTA_FlipY, // bool: flip image vertically + DTA_SrcX, // specify a source rectangle (this supersedes the poorly implemented DTA_WindowLeft/Right + DTA_SrcY, + DTA_SrcWidth, + DTA_SrcHeight, + DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle + DTA_Internal3, + DTA_Spacing, // Strings only: Additional spacing between characters + DTA_Monospace, // Strings only: Use a fixed distance between characters. + + DTA_FullscreenEx, // advanced fullscreen control. + DTA_FullscreenScale, // enable DTA_Fullscreen coordinate calculation for placed overlays. + + DTA_ScaleX, + DTA_ScaleY, + + DTA_ViewportX, // Defines the viewport on the screen that should be rendered to. + DTA_ViewportY, + DTA_ViewportWidth, + DTA_ViewportHeight, + DTA_CenterOffsetRel, // Apply texture offsets relative to center, instead of top left. This is standard alignment for Build's 2D content. + DTA_TopLeft, // always align to top left. Added to have a boolean condition for this alignment. + DTA_Pin, // Pin a non-widescreen image to the left/right edge of the screen. + DTA_Rotate, + DTA_FlipOffsets, // Flips offsets when using DTA_FlipX and DTA_FlipY, this cannot be automatic due to unexpected behavior with unoffsetted graphics. + DTA_Indexed, // Use an indexed texture combined with the given translation. + DTA_CleanTop, // Like DTA_Clean but aligns to the top of the screen instead of the center. + DTA_NoOffset, // Ignore 2D drawer's offset. + DTA_Localize, // localize drawn string, for DrawText only + +}; + +enum StencilOp +{ + SOP_Keep = 0, + SOP_Increment = 1, + SOP_Decrement = 2 +}; +enum StencilFlags +{ + SF_AllOn = 0, + SF_ColorMaskOff = 1, + SF_DepthMaskOff = 2 +}; + +class Shape2DTransform : Object native +{ + native void Clear(); + native void Rotate(double angle); + native void Scale(Vector2 scaleVec); + native void Translate(Vector2 translateVec); + native void From2D(double m00, double m01, double m10, double m11, double vx, double vy); +} + +class Shape2D : Object native +{ + enum EClearWhich + { + C_Verts = 1, + C_Coords = 2, + C_Indices = 4, + }; + + native void SetTransform(Shape2DTransform transform); + + native void Clear( int which = C_Verts|C_Coords|C_Indices ); + native void PushVertex( Vector2 v ); + native void PushCoord( Vector2 c ); + native void PushTriangle( int a, int b, int c ); +} + +class Canvas : Object native abstract +{ + native void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1); + native void Dim(Color col, double amount, int x, int y, int w, int h, ERenderStyle style = STYLE_Translucent); + + native vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...); + native vararg void DrawShape(TextureID tex, bool animate, Shape2D s, ...); + native vararg void DrawShapeFill(Color col, double amount, Shape2D s, ...); + native vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...); + native vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...); + native void DrawLine(double x0, double y0, double x1, double y1, Color color, int alpha = 255); + native void DrawLineFrame(Color color, int x0, int y0, int w, int h, int thickness = 1); + native void DrawThickLine(double x0, double y0, double x1, double y1, double thickness, Color color, int alpha = 255); + native Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true); + native void SetClipRect(int x, int y, int w, int h); + native void ClearClipRect(); + native int, int, int, int GetClipRect(); + native double, double, double, double GetFullscreenRect(double vwidth, double vheight, int fsmode); + native Vector2 SetOffset(double x, double y); + native void ClearScreen(color col = 0); + native void SetScreenFade(double factor); + + native void EnableStencil(bool on); + native void SetStencil(int offs, int op, int flags = -1); + native void ClearStencil(); + native void SetTransform(Shape2DTransform transform); + native void ClearTransform(); +} + +struct Screen native +{ + native static Color PaletteColor(int index); + native static int GetWidth(); + native static int GetHeight(); + native static Vector2 GetTextScreenSize(); + native static void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1); + native static void Dim(Color col, double amount, int x, int y, int w, int h, ERenderStyle style = STYLE_Translucent); + + native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...); + native static vararg void DrawShape(TextureID tex, bool animate, Shape2D s, ...); + native static vararg void DrawShapeFill(Color col, double amount, Shape2D s, ...); + native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...); + native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...); + native static void DrawLine(double x0, double y0, double x1, double y1, Color color, int alpha = 255); + native static void DrawLineFrame(Color color, int x0, int y0, int w, int h, int thickness = 1); + native static void DrawThickLine(double x0, double y0, double x1, double y1, double thickness, Color color, int alpha = 255); + native static Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true); + native static double GetAspectRatio(); + native static void SetClipRect(int x, int y, int w, int h); + native static void ClearClipRect(); + native static int, int, int, int GetClipRect(); + native static int, int, int, int GetViewWindow(); + native static double, double, double, double GetFullscreenRect(double vwidth, double vheight, int fsmode); + native static Vector2 SetOffset(double x, double y); + native static void ClearScreen(color col = 0); + native static void SetScreenFade(double factor); + + native static void EnableStencil(bool on); + native static void SetStencil(int offs, int op, int flags = -1); + native static void ClearStencil(); + native static void SetTransform(Shape2DTransform transform); + native static void ClearTransform(); +} + +struct Font native +{ + enum EColorRange + { + CR_UNDEFINED = -1, + CR_NATIVEPAL = -1, + CR_BRICK, + CR_TAN, + CR_GRAY, + CR_GREY = CR_GRAY, + CR_GREEN, + CR_BROWN, + CR_GOLD, + CR_RED, + CR_BLUE, + CR_ORANGE, + CR_WHITE, + CR_YELLOW, + CR_UNTRANSLATED, + CR_BLACK, + CR_LIGHTBLUE, + CR_CREAM, + CR_OLIVE, + CR_DARKGREEN, + CR_DARKRED, + CR_DARKBROWN, + CR_PURPLE, + CR_DARKGRAY, + CR_CYAN, + CR_ICE, + CR_FIRE, + CR_SAPPHIRE, + CR_TEAL, + NUM_TEXT_COLORS + }; + + const TEXTCOLOR_BRICK = "\034A"; + const TEXTCOLOR_TAN = "\034B"; + const TEXTCOLOR_GRAY = "\034C"; + const TEXTCOLOR_GREY = "\034C"; + const TEXTCOLOR_GREEN = "\034D"; + const TEXTCOLOR_BROWN = "\034E"; + const TEXTCOLOR_GOLD = "\034F"; + const TEXTCOLOR_RED = "\034G"; + const TEXTCOLOR_BLUE = "\034H"; + const TEXTCOLOR_ORANGE = "\034I"; + const TEXTCOLOR_WHITE = "\034J"; + const TEXTCOLOR_YELLOW = "\034K"; + const TEXTCOLOR_UNTRANSLATED = "\034L"; + const TEXTCOLOR_BLACK = "\034M"; + const TEXTCOLOR_LIGHTBLUE = "\034N"; + const TEXTCOLOR_CREAM = "\034O"; + const TEXTCOLOR_OLIVE = "\034P"; + const TEXTCOLOR_DARKGREEN = "\034Q"; + const TEXTCOLOR_DARKRED = "\034R"; + const TEXTCOLOR_DARKBROWN = "\034S"; + const TEXTCOLOR_PURPLE = "\034T"; + const TEXTCOLOR_DARKGRAY = "\034U"; + const TEXTCOLOR_CYAN = "\034V"; + const TEXTCOLOR_ICE = "\034W"; + const TEXTCOLOR_FIRE = "\034X"; + const TEXTCOLOR_SAPPHIRE = "\034Y"; + const TEXTCOLOR_TEAL = "\034Z"; + + const TEXTCOLOR_NORMAL = "\034-"; + const TEXTCOLOR_BOLD = "\034+"; + + const TEXTCOLOR_CHAT = "\034*"; + const TEXTCOLOR_TEAMCHAT = "\034!"; + // native Font(const String name); // String/name to font casts + // native Font(const Name name); + + native int GetCharWidth(int code); + native int StringWidth(String code, bool localize = true); + native int GetMaxAscender(String code, bool localize = true); + native bool CanPrint(String code, bool localize = true); + native int GetHeight(); + native int GetDisplacement(); + native String GetCursor(); + + native static int FindFontColor(Name color); + native double GetBottomAlignOffset(int code); + native double GetDisplayTopOffset(int code); + native static Font FindFont(Name fontname); + native static Font GetFont(Name fontname); + native BrokenLines BreakLines(String text, int maxlen); + native int GetGlyphHeight(int code); + native int GetDefaultKerning(); +} + +struct Console native +{ + native static void HideConsole(); + native static vararg void Printf(string fmt, ...); + native static vararg void PrintfEx(int printlevel, string fmt, ...); +} + +struct CVar native +{ + enum ECVarType + { + CVAR_Bool, + CVAR_Int, + CVAR_Float, + CVAR_String, + CVAR_Color, + }; + + native static CVar FindCVar(Name name); + bool GetBool() { return GetInt(); } + native int GetInt(); + native double GetFloat(); + native String GetString(); + void SetBool(bool b) { SetInt(b); } + native void SetInt(int v); + native void SetFloat(double v); + native void SetString(String s); + native int GetRealType(); + native int ResetToDefault(); +} + +class CustomIntCVar abstract +{ + abstract int ModifyValue(Name CVarName, int val); +} + +class CustomFloatCVar abstract +{ + abstract double ModifyValue(Name CVarName, double val); +} + +class CustomStringCVar abstract +{ + abstract String ModifyValue(Name CVarName, String val); +} + +class CustomBoolCVar abstract +{ + abstract bool ModifyValue(Name CVarName, bool val); +} + +class CustomColorCVar abstract +{ + abstract Color ModifyValue(Name CVarName, Color val); +} + +struct GIFont version("2.4") +{ + Name fontname; + Name color; +}; + +struct GameInfoStruct native +{ + native int gametype; + native String mBackButton; + native Name mSliderColor; + native Name mSliderBackColor; +} + +struct SystemTime +{ + native static ui int Now(); // This returns the epoch time + native static clearscope String Format(String timeForm, int timeVal); // This converts an epoch time to a local time, then uses the strftime syntax to format it +} + +class Object native +{ + const TICRATE = 35; + native bool bDestroyed; + + // These must be defined in some class, so that the compiler can find them. Object is just fine, as long as they are private to external code. + private native static Object BuiltinNew(Class cls, int outerclass, int compatibility); + private native static int BuiltinRandom(voidptr rng, int min, int max); + private native static double BuiltinFRandom(voidptr rng, double min, double max); + private native static int BuiltinRandom2(voidptr rng, int mask); + private native static void BuiltinRandomSeed(voidptr rng, int seed); + private native static Class BuiltinNameToClass(Name nm, Class filter); + private native static Object BuiltinClassCast(Object inptr, Class test); + private native static Function BuiltinFunctionPtrCast(Function inptr, voidptr newtype); + + native static uint MSTime(); + native static double MSTimeF(); + native vararg static void ThrowAbortException(String fmt, ...); + + native static Function FindFunction(Class cls, Name fn); + + native virtualscope void Destroy(); + + // This does not call into the native method of the same name to avoid problems with objects that get garbage collected late on shutdown. + virtual virtualscope void OnDestroy() {} + // + // Object intrinsics + // Every ZScript "class" inherits from Object, and so inherits these methods as well + // clearscope bool IsAbstract(); // Query whether or not the class of this object is abstract + // clearscope Object GetParentClass(); // Get the parent class of this object + // clearscope Name GetClassName(); // Get the name of this object's class + // clearscope Class GetClass(); // Get the object's class + // clearscope Object new(class type); // Create a new object with this class. This is only valid for thinkers and plain objects, except menus. For actors, use Actor.Spawn(); + // + // + // Intrinsic random number generation functions. Note that the square + // bracket syntax for specifying an RNG ID is only available for these + // functions. + // clearscope void SetRandomSeed[Name rngId = 'None'](int seed); // Set the seed for the given RNG. + // clearscope int Random[Name rngId = 'None'](int min, int max); // Use the given RNG to generate a random integer number in the range (min, max) inclusive. + // clearscope int Random2[Name rngId = 'None'](int mask); // Use the given RNG to generate a random integer number, and do a "union" (bitwise AND, AKA &) operation with the bits in the mask integer. + // clearscope double FRandom[Name rngId = 'None'](double min, double max); // Use the given RNG to generate a random real number in the range (min, max) inclusive. + // clearscope int RandomPick[Name rngId = 'None'](int choices...); // Use the given RNG to generate a random integer from the given choices. + // clearscope double FRandomPick[Name rngId = 'None'](double choices...); // Use the given RNG to generate a random real number from the given choices. + // + // + // Intrinsic math functions - the argument and return types for these + // functions depend on the arguments given. Other than that, they work the + // same way similarly-named functions in other programming languages work. + // Note that trigonometric functions work with degrees instead of radians + // clearscope T abs(T x); + // clearscope T atan2(T y, T x); // NOTE: Returns a value in degrees instead of radians + // clearscope T vectorangle(T x, T y); // Same as Atan2 with the arguments in a different order + // clearscope T min(T x...); + // clearscope T max(T x...); + // clearscope T clamp(T x, T min, T max); + // + // These math functions only work with doubles - they are defined in FxFlops + // clearscope double exp(double x); + // clearscope double log(double x); + // clearscope double log10(double x); + // clearscope double sqrt(double x); + // clearscope double ceil(double x); + // clearscope double floor(double x); + // clearscope double acos(double x); + // clearscope double asin(double x); + // clearscope double atan(double x); + // clearscope double cos(double x); + // clearscope double sin(double x); + // clearscope double tan(double x); + // clearscope double cosh(double x); + // clearscope double sinh(double x); + // clearscope double tanh(double x); + // clearscope double round(double x); +} + +class BrokenLines : Object native version("2.4") +{ + native int Count(); + native int StringWidth(int line); + native String StringAt(int line); +} + +struct StringTable native +{ + native static String Localize(String val, bool prefixed = true); +} + +struct Wads // todo: make FileSystem an alias to 'Wads' +{ + enum WadNamespace + { + ns_hidden = -1, + + ns_global = 0, + ns_sprites, + ns_flats, + ns_colormaps, + ns_acslibrary, + ns_newtextures, + ns_bloodraw, + ns_bloodsfx, + ns_bloodmisc, + ns_strifevoices, + ns_hires, + ns_voxels, + + ns_specialzipdirectory, + ns_sounds, + ns_patches, + ns_graphics, + ns_music, + + ns_firstskin, + } + + enum FindLumpNamespace + { + GlobalNamespace = 0, + AnyNamespace = 1, + } + + native static int CheckNumForName(string name, int ns, int wadnum = -1, bool exact = false); + native static int CheckNumForFullName(string name); + native static int FindLump(string name, int startlump = 0, FindLumpNamespace ns = GlobalNamespace); + native static int FindLumpFullName(string name, int startlump = 0, bool noext = false); + native static string ReadLump(int lump); + native static int GetLumpLength(int lump); + + native static int GetNumLumps(); + native static string GetLumpName(int lump); + native static string GetLumpFullName(int lump); + native static int GetLumpNamespace(int lump); +} + +enum EmptyTokenType +{ + TOK_SKIPEMPTY = 0, + TOK_KEEPEMPTY = 1, +} + +// Although String is a builtin type, this is a convenient way to attach methods to it. +// All of these methods are available on strings +struct StringStruct native +{ + native static vararg String Format(String fmt, ...); + native vararg void AppendFormat(String fmt, ...); + // native int Length(); // Intrinsic + // native bool operator==(String other); // Equality comparison + // native bool operator~==(String other); // Case-insensitive equality comparison + // native String operator..(String other); // Concatenate with another String + native void Replace(String pattern, String replacement); + native String Left(int len) const; + native String Mid(int pos = 0, int len = 2147483647) const; + native void Truncate(int newlen); + native void Remove(int index, int remlen); + deprecated("4.1", "use Left() or Mid() instead") native String CharAt(int pos) const; + deprecated("4.1", "use ByteAt() instead") native int CharCodeAt(int pos) const; + native int ByteAt(int pos) const; + native String Filter(); + native int IndexOf(String substr, int startIndex = 0) const; + deprecated("3.5.1", "use RightIndexOf() instead") native int LastIndexOf(String substr, int endIndex = 2147483647) const; + native int RightIndexOf(String substr, int endIndex = 2147483647) const; + deprecated("4.1", "use MakeUpper() instead") native void ToUpper(); + deprecated("4.1", "use MakeLower() instead") native void ToLower(); + native String MakeUpper() const; + native String MakeLower() const; + native static int CharUpper(int ch); + native static int CharLower(int ch); + native int ToInt(int base = 0) const; + native double ToDouble() const; + native void Split(out Array tokens, String delimiter, EmptyTokenType keepEmpty = TOK_KEEPEMPTY) const; + native void AppendCharacter(int c); + native void DeleteLastCharacter(); + native int CodePointCount() const; + native int, int GetNextCodePoint(int position) const; + native void Substitute(String str, String replace); + native void StripLeft(String junk = ""); + native void StripRight(String junk = ""); + native void StripLeftRight(String junk = ""); +} + +struct Translation version("2.4") +{ + Color colors[256]; + + native TranslationID AddTranslation(); + native static TranslationID MakeID(int group, int num); + native static TranslationID GetID(Name transname); +} + +// Convenient way to attach functions to Quat +struct QuatStruct native +{ + native static Quat SLerp(Quat from, Quat to, double t); + native static Quat NLerp(Quat from, Quat to, double t); + native static Quat FromAngles(double yaw, double pitch, double roll); + native static Quat AxisAngle(Vector3 xyz, double angle); + native Quat Conjugate(); + native Quat Inverse(); + // native double Length(); + // native double LengthSquared(); + // native Quat Unit(); +} + +struct ScriptSavedPos +{ + voidptr SavedScriptPtr; + int SavedScriptLine; +} + +class ScriptScanner native +{ + native void OpenString(String name, String script); + native void OpenLumpNum(int lump); + native void Close(); + + native void SavePos(out ScriptSavedPos pos); + native void RestorePos(out ScriptSavedPos pos); + native void UnGet(); + native bool isText(); + native int GetMessageLine(); + native void SetPrependMessage(String message); + + native vararg void ScriptError(String fmt, ...); + native vararg void ScriptMessage(String fmt, ...); + + native void SetCMode(bool cmode); + native void SetNoOctals(bool cmode); + native void SetEscape(bool esc); + native void SetNoFatalErrors(bool cmode); + native void SkipToEndOfBlock(); + native void StartBraces(out ScriptSavedPos braceend); + native bool FoundEndBrace(out ScriptSavedPos braceend); + + native bool CheckValue(bool allowfloat, bool evaluate = true); + native bool CheckBoolToken(); + native bool CheckNumber(bool evaluate = false); + native bool CheckString(String name); + native bool CheckFloat(bool evaluate = false); + + native bool GetNumber(bool evaluate = false); + native bool GetString(); + native bool GetFloat(bool evaluate = false); + + native void AddSymbol(String name, int value); + native void AddSymbolUnsigned(String name, uint value); + native void AddSymbolFloat(String name, double value); + + native void MustGetValue(bool allowfloat, bool evaluate = true); + native void MustGetFloat(bool evaluate = false); + native void MustGetNumber(bool evaluate = false); + native void MustGetString(); + native void MustGetStringName(String name); + native void MustGetBoolToken(); + + // This DOES NOT advance the parser! This returns the string the parser got. + native String GetStringContents(); + + native readonly bool End; + native readonly bool ParseError; + native readonly bool Crossed; + native readonly int Line; + native readonly int Number; + native readonly double Float; +} + +// this struct does not exist. It is just a type for being referenced by an opaque pointer. +struct VMFunction native version("4.10") +{ +} diff --git a/wadsrc/static/zscript/dictionary.zs b/wadsrc/static/zscript/engine/dictionary.zs similarity index 100% rename from wadsrc/static/zscript/dictionary.zs rename to wadsrc/static/zscript/engine/dictionary.zs diff --git a/wadsrc/static/zscript/engine/dynarrays.zs b/wadsrc/static/zscript/engine/dynarrays.zs new file mode 100644 index 00000000000..f9e6a680d33 --- /dev/null +++ b/wadsrc/static/zscript/engine/dynarrays.zs @@ -0,0 +1,164 @@ +// The VM uses 7 integral data types, so for dynamic array support we need one specific set of functions for each of these types. +// Do not use these structs directly, they are incomplete and only needed to create prototypes for the needed functions. + +struct DynArray_I8 native +{ + native readonly int Size; + + native void Copy(DynArray_I8 other); + native void Move(DynArray_I8 other); + native void Append (DynArray_I8 other); + native int Find(int item) const; + native int Push(int item); + native bool Pop (); + native void Delete (uint index, int deletecount = 1); + native void Insert (uint index, int item); + native void ShrinkToFit (); + native void Grow (uint amount); + native void Resize (uint amount); + native int Reserve(uint amount); + native int Max() const; + native void Clear (); +} + +struct DynArray_I16 native +{ + native readonly int Size; + + native void Copy(DynArray_I16 other); + native void Move(DynArray_I16 other); + native void Append (DynArray_I16 other); + native int Find(int item) const; + native int Push(int item); + native bool Pop (); + native void Delete (uint index, int deletecount = 1); + native void Insert (uint index, int item); + native void ShrinkToFit (); + native void Grow (uint amount); + native void Resize (uint amount); + native int Reserve(uint amount); + native int Max() const; + native void Clear (); +} + +struct DynArray_I32 native +{ + native readonly int Size; + + native void Copy(DynArray_I32 other); + native void Move(DynArray_I32 other); + native void Append (DynArray_I32 other); + native int Find(int item) const; + native int Push(int item); + native vararg uint PushV (int item, ...); + native bool Pop (); + native void Delete (uint index, int deletecount = 1); + native void Insert (uint index, int item); + native void ShrinkToFit (); + native void Grow (uint amount); + native void Resize (uint amount); + native int Reserve(uint amount); + native int Max() const; + native void Clear (); +} + +struct DynArray_F32 native +{ + native readonly int Size; + + native void Copy(DynArray_F32 other); + native void Move(DynArray_F32 other); + native void Append (DynArray_F32 other); + native int Find(double item) const; + native int Push(double item); + native bool Pop (); + native void Delete (uint index, int deletecount = 1); + native void Insert (uint index, double item); + native void ShrinkToFit (); + native void Grow (uint amount); + native void Resize (uint amount); + native int Reserve(uint amount); + native int Max() const; + native void Clear (); +} + +struct DynArray_F64 native +{ + native readonly int Size; + + native void Copy(DynArray_F64 other); + native void Move(DynArray_F64 other); + native void Append (DynArray_F64 other); + native int Find(double item) const; + native int Push(double item); + native bool Pop (); + native void Delete (uint index, int deletecount = 1); + native void Insert (uint index, double item); + native void ShrinkToFit (); + native void Grow (uint amount); + native void Resize (uint amount); + native int Reserve(uint amount); + native int Max() const; + native void Clear (); +} + +struct DynArray_Ptr native +{ + native readonly int Size; + + native void Copy(DynArray_Ptr other); + native void Move(DynArray_Ptr other); + native void Append (DynArray_Ptr other); + native int Find(voidptr item) const; + native int Push(voidptr item); + native bool Pop (); + native void Delete (uint index, int deletecount = 1); + native void Insert (uint index, voidptr item); + native void ShrinkToFit (); + native void Grow (uint amount); + native void Resize (uint amount); + native int Reserve(uint amount); + native int Max() const; + native void Clear (); +} + +struct DynArray_Obj native +{ + native readonly int Size; + + native void Copy(DynArray_Obj other); + native void Move(DynArray_Obj other); + native void Append (DynArray_Obj other); + native int Find(Object item) const; + native int Push(Object item); + native bool Pop (); + native void Delete (uint index, int deletecount = 1); + native void Insert (uint index, Object item); + native void ShrinkToFit (); + native void Grow (uint amount); + native void Resize (uint amount); + native int Reserve(uint amount); + native int Max() const; + native void Clear (); +} + +struct DynArray_String native +{ + native readonly int Size; + + native void Copy(DynArray_String other); + native void Move(DynArray_String other); + native void Append (DynArray_String other); + native int Find(String item) const; + native int Push(String item); + native vararg uint PushV(String item, ...); + native bool Pop (); + native void Delete (uint index, int deletecount = 1); + native void Insert (uint index, String item); + native void ShrinkToFit (); + native void Grow (uint amount); + native void Resize (uint amount); + native int Reserve(uint amount); + native int Max() const; + native void Clear (); +} diff --git a/wadsrc/static/zscript/engine/inputevents.zs b/wadsrc/static/zscript/engine/inputevents.zs new file mode 100644 index 00000000000..ba63b59e9f5 --- /dev/null +++ b/wadsrc/static/zscript/engine/inputevents.zs @@ -0,0 +1,251 @@ +struct UiEvent native ui version("2.4") +{ + // d_gui.h + enum EGUIEvent + { + Type_None, + Type_KeyDown, + Type_KeyRepeat, + Type_KeyUp, + Type_Char, + Type_FirstMouseEvent, // ? + Type_MouseMove, + Type_LButtonDown, + Type_LButtonUp, + Type_LButtonClick, + Type_MButtonDown, + Type_MButtonUp, + Type_MButtonClick, + Type_RButtonDown, + Type_RButtonUp, + Type_RButtonClick, + Type_WheelUp, + Type_WheelDown, + Type_WheelRight, // ??? + Type_WheelLeft, // ??? + Type_BackButtonDown, // ??? + Type_BackButtonUp, // ??? + Type_FwdButtonDown, // ??? + Type_FwdButtonUp, // ??? + Type_LastMouseEvent + } + + // for KeyDown, KeyRepeat, KeyUp + enum ESpecialGUIKeys + { + Key_PgDn = 1, + Key_PgUp = 2, + Key_Home = 3, + Key_End = 4, + Key_Left = 5, + Key_Right = 6, + Key_Alert = 7, // ASCII bell + Key_Backspace = 8, // ASCII + Key_Tab = 9, // ASCII + Key_LineFeed = 10, // ASCII + Key_Down = 10, + Key_VTab = 11, // ASCII + Key_Up = 11, + Key_FormFeed = 12, // ASCII + Key_Return = 13, // ASCII + Key_F1 = 14, + Key_F2 = 15, + Key_F3 = 16, + Key_F4 = 17, + Key_F5 = 18, + Key_F6 = 19, + Key_F7 = 20, + Key_F8 = 21, + Key_F9 = 22, + Key_F10 = 23, + Key_F11 = 24, + Key_F12 = 25, + Key_Del = 26, + Key_Escape = 27, // ASCII + Key_Free1 = 28, + Key_Free2 = 29, + Key_Back = 30, // browser back key + Key_CEscape = 31 // color escape + } + + // + native readonly EGUIEvent Type; + // + native readonly String KeyString; + native readonly int KeyChar; + // + native readonly int MouseX; + native readonly int MouseY; + // + native readonly bool IsShift; + native readonly bool IsCtrl; + native readonly bool IsAlt; +} + +struct InputEvent native play version("2.4") +{ + enum EGenericEvent + { + Type_None, + Type_KeyDown, + Type_KeyUp, + Type_Mouse, + Type_GUI, // unused, kept for completeness + Type_DeviceChange + } + + // ew. + enum EDoomInputKeys + { + Key_Pause = 0xc5, // DIK_PAUSE + Key_RightArrow = 0xcd, // DIK_RIGHT + Key_LeftArrow = 0xcb, // DIK_LEFT + Key_UpArrow = 0xc8, // DIK_UP + Key_DownArrow = 0xd0, // DIK_DOWN + Key_Escape = 0x01, // DIK_ESCAPE + Key_Enter = 0x1c, // DIK_RETURN + Key_Space = 0x39, // DIK_SPACE + Key_Tab = 0x0f, // DIK_TAB + Key_F1 = 0x3b, // DIK_F1 + Key_F2 = 0x3c, // DIK_F2 + Key_F3 = 0x3d, // DIK_F3 + Key_F4 = 0x3e, // DIK_F4 + Key_F5 = 0x3f, // DIK_F5 + Key_F6 = 0x40, // DIK_F6 + Key_F7 = 0x41, // DIK_F7 + Key_F8 = 0x42, // DIK_F8 + Key_F9 = 0x43, // DIK_F9 + Key_F10 = 0x44, // DIK_F10 + Key_F11 = 0x57, // DIK_F11 + Key_F12 = 0x58, // DIK_F12 + Key_Grave = 0x29, // DIK_GRAVE + + KEY_kpad_1 = 0x4f, + KEY_kpad_2 = 0x50, + KEY_kpad_3 = 0x51, + KEY_kpad_4 = 0x4b, + KEY_kpad_5 = 0x4c, + KEY_kpad_6 = 0x4d, + KEY_kpad_7 = 0x47, + KEY_kpad_8 = 0x48, + KEY_kpad_9 = 0x49, + KEY_kpad_0 = 0x52, + KEY_kpad_Minus = 0x4a, + KEY_kpad_Plus = 0x4e, + KEY_kpad_Period = 0x53, + + + Key_Backspace = 0x0e, // DIK_BACK + + Key_Equals = 0x0d, // DIK_EQUALS + Key_Minus = 0x0c, // DIK_MINUS + + Key_LShift = 0x2A, // DIK_LSHIFT + Key_LCtrl = 0x1d, // DIK_LCONTROL + Key_LAlt = 0x38, // DIK_LMENU + + Key_RShift = Key_LSHIFT, + Key_RCtrl = Key_LCTRL, + Key_RAlt = Key_LALT, + + Key_Ins = 0xd2, // DIK_INSERT + Key_Del = 0xd3, // DIK_DELETE + Key_End = 0xcf, // DIK_END + Key_Home = 0xc7, // DIK_HOME + Key_PgUp = 0xc9, // DIK_PRIOR + Key_PgDn = 0xd1, // DIK_NEXT + + KEY_VOLUMEDOWN = 0xAE, // DIK_VOLUMEDOWN + KEY_VOLUMEUP = 0xB0, // DIK_VOLUMEUP + + Key_Mouse1 = 0x100, + Key_Mouse2 = 0x101, + Key_Mouse3 = 0x102, + Key_Mouse4 = 0x103, + Key_Mouse5 = 0x104, + Key_Mouse6 = 0x105, + Key_Mouse7 = 0x106, + Key_Mouse8 = 0x107, + + Key_FirstJoyButton = 0x108, + Key_Joy1 = (Key_FirstJoyButton+0), + Key_Joy2 = (Key_FirstJoyButton+1), + Key_Joy3 = (Key_FirstJoyButton+2), + Key_Joy4 = (Key_FirstJoyButton+3), + Key_Joy5 = (Key_FirstJoyButton+4), + Key_Joy6 = (Key_FirstJoyButton+5), + Key_Joy7 = (Key_FirstJoyButton+6), + Key_Joy8 = (Key_FirstJoyButton+7), + Key_LastJoyButton = 0x187, + Key_JoyPOV1_Up = 0x188, + Key_JoyPOV1_Right = 0x189, + Key_JoyPOV1_Down = 0x18a, + Key_JoyPOV1_Left = 0x18b, + Key_JoyPOV2_Up = 0x18c, + Key_JoyPOV3_Up = 0x190, + Key_JoyPOV4_Up = 0x194, + + Key_MWheelUp = 0x198, + Key_MWheelDown = 0x199, + Key_MWheelRight = 0x19A, + Key_MWheelLeft = 0x19B, + + Key_JoyAxis1Plus = 0x19C, + Key_JoyAxis1Minus = 0x19D, + Key_JoyAxis2Plus = 0x19E, + Key_JoyAxis2Minus = 0x19F, + Key_JoyAxis3Plus = 0x1A0, + Key_JoyAxis3Minus = 0x1A1, + Key_JoyAxis4Plus = 0x1A2, + Key_JoyAxis4Minus = 0x1A3, + Key_JoyAxis5Plus = 0x1A4, + Key_JoyAxis5Minus = 0x1A5, + Key_JoyAxis6Plus = 0x1A6, + Key_JoyAxis6Minus = 0x1A7, + Key_JoyAxis7Plus = 0x1A8, + Key_JoyAxis7Minus = 0x1A9, + Key_JoyAxis8Plus = 0x1AA, + Key_JoyAxis8Minus = 0x1AB, + Num_JoyAxisButtons = 8, + + Key_Pad_LThumb_Right = 0x1AC, + Key_Pad_LThumb_Left = 0x1AD, + Key_Pad_LThumb_Down = 0x1AE, + Key_Pad_LThumb_Up = 0x1AF, + + Key_Pad_RThumb_Right = 0x1B0, + Key_Pad_RThumb_Left = 0x1B1, + Key_Pad_RThumb_Down = 0x1B2, + Key_Pad_RThumb_Up = 0x1B3, + + Key_Pad_DPad_Up = 0x1B4, + Key_Pad_DPad_Down = 0x1B5, + Key_Pad_DPad_Left = 0x1B6, + Key_Pad_DPad_Right = 0x1B7, + Key_Pad_Start = 0x1B8, + Key_Pad_Back = 0x1B9, + Key_Pad_LThumb = 0x1BA, + Key_Pad_RThumb = 0x1BB, + Key_Pad_LShoulder = 0x1BC, + Key_Pad_RShoulder = 0x1BD, + Key_Pad_LTrigger = 0x1BE, + Key_Pad_RTrigger = 0x1BF, + Key_Pad_A = 0x1C0, + Key_Pad_B = 0x1C1, + Key_Pad_X = 0x1C2, + Key_Pad_Y = 0x1C3, + + Num_Keys = 0x1C4 + } + + // + native readonly EGenericEvent Type; + // + native readonly int KeyScan; // as in EDoomInputKeys enum + native readonly String KeyString; + native readonly int KeyChar; // ASCII char (if any) + // + native readonly int MouseX; + native readonly int MouseY; +} + diff --git a/wadsrc/static/zscript/engine/maps.zs b/wadsrc/static/zscript/engine/maps.zs new file mode 100644 index 00000000000..b871edf050c --- /dev/null +++ b/wadsrc/static/zscript/engine/maps.zs @@ -0,0 +1,511 @@ + +struct Map_I32_I8 native +{ + native void Copy(Map_I32_I8 other); + native void Move(Map_I32_I8 other); + native void Swap(Map_I32_I8 other); + native void Clear(); + native uint CountUsed() const; + + native int Get(int key); + native bool CheckKey(int key) const; + + native version("4.11") int GetIfExists(int key) const; + native version("4.11") int, bool CheckValue(int key) const; + + native void Insert(int key, int value); + native void InsertNew(int key); + native void Remove(int key); +} + +struct MapIterator_I32_I8 native +{ + native bool Init(Map_I32_I8 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native int GetKey(); + native int GetValue(); + native void SetValue(int value); +} + +struct Map_I32_I16 native +{ + native void Copy(Map_I32_I16 other); + native void Move(Map_I32_I16 other); + native void Swap(Map_I32_I16 other); + native void Clear(); + native uint CountUsed() const; + + native int Get(int key); + native bool CheckKey(int key) const; + + native version("4.11") int GetIfExists(int key) const; + native version("4.11") int, bool CheckValue(int key) const; + + native void Insert(int key, int value); + native void InsertNew(int key); + native void Remove(int key); +} + +struct MapIterator_I32_I16 native +{ + native bool Init(Map_I32_I16 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native int GetKey(); + native int GetValue(); + native void SetValue(int value); +} + +struct Map_I32_I32 native +{ + native void Copy(Map_I32_I32 other); + native void Move(Map_I32_I32 other); + native void Swap(Map_I32_I32 other); + native void Clear(); + native uint CountUsed() const; + + native int Get(int key); + native bool CheckKey(int key) const; + + native version("4.11") int GetIfExists(int key) const; + native version("4.11") int, bool CheckValue(int key) const; + + native void Insert(int key, int value); + native void InsertNew(int key); + native void Remove(int key); +} + +struct MapIterator_I32_I32 native +{ + native bool Init(Map_I32_I32 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native int GetKey(); + native int GetValue(); + native void SetValue(int value); +} + +struct Map_I32_F32 native +{ + native void Copy(Map_I32_F32 other); + native void Move(Map_I32_F32 other); + native void Swap(Map_I32_F32 other); + native void Clear(); + native uint CountUsed() const; + + native double Get(int key); + native bool CheckKey(int key) const; + + native version("4.11") double GetIfExists(int key) const; + native version("4.11") double, bool CheckValue(int key) const; + + native void Insert(int key, double value); + native void InsertNew(int key); + native void Remove(int key); +} + +struct MapIterator_I32_F32 native +{ + native bool Init(Map_I32_F32 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native int GetKey(); + native double GetValue(); + native void SetValue(double value); +} + +struct Map_I32_F64 native +{ + native void Copy(Map_I32_F64 other); + native void Move(Map_I32_F64 other); + native void Swap(Map_I32_F64 other); + native void Clear(); + native uint CountUsed() const; + + native double Get(int key); + native bool CheckKey(int key) const; + + native version("4.11") double GetIfExists(int key) const; + native version("4.11") double, bool CheckValue(int key) const; + + native void Insert(int key, double value); + native void InsertNew(int key); + native void Remove(int key); +} + +struct MapIterator_I32_F64 native +{ + native bool Init(Map_I32_F64 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native int GetKey(); + native double GetValue(); + native void SetValue(double value); +} + +struct Map_I32_Obj native +{ + native void Copy(Map_I32_Obj other); + native void Move(Map_I32_Obj other); + native void Swap(Map_I32_Obj other); + native void Clear(); + native uint CountUsed() const; + + native Object Get(int key); + native bool CheckKey(int key) const; + + native version("4.11") Object GetIfExists(int key) const; + native version("4.11") Object, bool CheckValue(int key) const; + + native void Insert(int key, Object value); + native void InsertNew(int key); + native void Remove(int key); +} + +struct MapIterator_I32_Obj native +{ + native bool Init(Map_I32_Obj other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native int GetKey(); + native Object GetValue(); + native void SetValue(Object value); +} + +struct Map_I32_Ptr native +{ + native void Copy(Map_I32_Ptr other); + native void Move(Map_I32_Ptr other); + native void Swap(Map_I32_Ptr other); + native void Clear(); + native uint CountUsed() const; + + native voidptr Get(int key); + native bool CheckKey(int key) const; + + native version("4.11") voidptr GetIfExists(int key) const; + native version("4.11") voidptr, bool CheckValue(int key) const; + + native void Insert(int key, voidptr value); + native void InsertNew(int key); + native void Remove(int key); +} + +struct MapIterator_I32_Ptr native +{ + native bool Init(Map_I32_Ptr other); + native bool Next(); + + native int GetKey(); + native voidptr GetValue(); + native void SetValue(voidptr value); +} + +struct Map_I32_Str native +{ + native void Copy(Map_I32_Str other); + native void Move(Map_I32_Str other); + native void Swap(Map_I32_Str other); + native void Clear(); + native uint CountUsed() const; + + native String Get(int key); + native bool CheckKey(int key) const; + + native version("4.11") String GetIfExists(int key) const; + native version("4.11") String, bool CheckValue(int key) const; + + native void Insert(int key, String value); + native void InsertNew(int key); + native void Remove(int key); +} + +struct MapIterator_I32_Str native +{ + native bool Init(Map_I32_Str other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native int GetKey(); + native String GetValue(); + native void SetValue(String value); +} + +// --------------- + +struct Map_Str_I8 native +{ + native void Copy(Map_Str_I8 other); + native void Move(Map_Str_I8 other); + native void Swap(Map_Str_I8 other); + native void Clear(); + native uint CountUsed() const; + + native int Get(String key); + native bool CheckKey(String key) const; + + native version("4.11") int GetIfExists(String key) const; + native version("4.11") int, bool CheckValue(String key) const; + + native void Insert(String key, int value); + native void InsertNew(String key); + native void Remove(String key); +} + +struct MapIterator_Str_I8 native +{ + native bool Init(Map_Str_I8 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native String GetKey(); + native int GetValue(); + native void SetValue(int value); +} + +struct Map_Str_I16 native +{ + native void Copy(Map_Str_I16 other); + native void Move(Map_Str_I16 other); + native void Swap(Map_Str_I16 other); + native void Clear(); + native uint CountUsed() const; + + native int Get(String key); + native bool CheckKey(String key) const; + + native version("4.11") int GetIfExists(String key) const; + native version("4.11") int, bool CheckValue(String key) const; + + native void Insert(String key, int value); + native void InsertNew(String key); + native void Remove(String key); +} + +struct MapIterator_Str_I16 native +{ + native bool Init(Map_Str_I16 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native String GetKey(); + native int GetValue(); + native void SetValue(int value); +} + +struct Map_Str_I32 native +{ + native void Copy(Map_Str_I32 other); + native void Move(Map_Str_I32 other); + native void Swap(Map_Str_I32 other); + native void Clear(); + native uint CountUsed() const; + + native int Get(String key); + native bool CheckKey(String key) const; + + native version("4.11") int GetIfExists(String key) const; + native version("4.11") int, bool CheckValue(String key) const; + + native void Insert(String key, int value); + native void InsertNew(String key); + native void Remove(String key); +} + +struct MapIterator_Str_I32 native +{ + native bool Init(Map_Str_I32 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native String GetKey(); + native int GetValue(); + native void SetValue(int value); +} + +struct Map_Str_F32 native +{ + native void Copy(Map_Str_F32 other); + native void Move(Map_Str_F32 other); + native void Swap(Map_Str_F32 other); + native void Clear(); + native uint CountUsed() const; + + native double Get(String key); + native bool CheckKey(String key) const; + + native version("4.11") double GetIfExists(String key) const; + native version("4.11") double, bool CheckValue(String key) const; + + native void Insert(String key, double value); + native void InsertNew(String key); + native void Remove(String key); +} + +struct MapIterator_Str_F32 native +{ + native bool Init(Map_Str_F32 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native String GetKey(); + native double GetValue(); + native void SetValue(double value); +} + +struct Map_Str_F64 native +{ + native void Copy(Map_Str_F64 other); + native void Move(Map_Str_F64 other); + native void Swap(Map_Str_F64 other); + native void Clear(); + native uint CountUsed() const; + + native double Get(String key); + native bool CheckKey(String key) const; + + native version("4.11") double GetIfExists(String key) const; + native version("4.11") double, bool CheckValue(String key) const; + + native void Insert(String key, double value); + native void InsertNew(String key); + native void Remove(String key); +} + +struct MapIterator_Str_F64 native +{ + native bool Init(Map_Str_F64 other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native String GetKey(); + native double GetValue(); + native void SetValue(double value); +} + +struct Map_Str_Obj native +{ + native void Copy(Map_Str_Obj other); + native void Move(Map_Str_Obj other); + native void Swap(Map_Str_Obj other); + native void Clear(); + native uint CountUsed() const; + + native Object Get(String key); + native bool CheckKey(String key) const; + + native version("4.11") Object GetIfExists(String key) const; + native version("4.11") Object, bool CheckValue(String key) const; + + native void Insert(String key, Object value); + native void InsertNew(String key); + native void Remove(String key); +} + +struct MapIterator_Str_Obj native +{ + native bool Init(Map_Str_Obj other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native String GetKey(); + native Object GetValue(); + native void SetValue(Object value); +} + +struct Map_Str_Ptr native +{ + native void Copy(Map_Str_Ptr other); + native void Move(Map_Str_Ptr other); + native void Swap(Map_Str_Ptr other); + native void Clear(); + native uint CountUsed() const; + + native voidptr Get(String key); + native bool CheckKey(String key) const; + + native version("4.11") voidptr GetIfExists(String key) const; + native version("4.11") voidptr, bool CheckValue(String key) const; + + native void Insert(String key, voidptr value); + native void InsertNew(String key); + native void Remove(String key); +} + +struct MapIterator_Str_Ptr native +{ + native bool Init(Map_Str_Ptr other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native String GetKey(); + native voidptr GetValue(); + native void SetValue(voidptr value); +} + +struct Map_Str_Str native +{ + native void Copy(Map_Str_Str other); + native void Move(Map_Str_Str other); + native void Swap(Map_Str_Str other); + native void Clear(); + native uint CountUsed() const; + + native String Get(String key); + native bool CheckKey(String key) const; + + native version("4.11") String GetIfExists(String key) const; + native version("4.11") String, bool CheckValue(String key) const; + + native void Insert(String key, String value); + native void InsertNew(String key); + native void Remove(String key); +} + +struct MapIterator_Str_Str native +{ + native bool Init(Map_Str_Str other); + native bool ReInit(); + + native bool Valid(); + native bool Next(); + + native String GetKey(); + native String GetValue(); + native void SetValue(String value); +} diff --git a/wadsrc/static/zscript/engine/ppshader.zs b/wadsrc/static/zscript/engine/ppshader.zs new file mode 100644 index 00000000000..5c94e7e2305 --- /dev/null +++ b/wadsrc/static/zscript/engine/ppshader.zs @@ -0,0 +1,8 @@ +struct PPShader native +{ + native clearscope static void SetEnabled(string shaderName, bool enable); + native clearscope static void SetUniform1f(string shaderName, string uniformName, float value); + native clearscope static void SetUniform2f(string shaderName, string uniformName, vector2 value); + native clearscope static void SetUniform3f(string shaderName, string uniformName, vector3 value); + native clearscope static void SetUniform1i(string shaderName, string uniformName, int value); +} diff --git a/wadsrc/static/zscript/engine/screenjob.zs b/wadsrc/static/zscript/engine/screenjob.zs new file mode 100644 index 00000000000..dc50f553562 --- /dev/null +++ b/wadsrc/static/zscript/engine/screenjob.zs @@ -0,0 +1,563 @@ + +class ScreenJob : Object UI +{ + int flags; + float fadetime; // in milliseconds + int fadestate; + + int ticks; + int jobstate; + + bool skipover; + bool nowipe; + + enum EJobState + { + running = 0, // normal operation + skipped = 1, // finished by user skipping + finished = 2, // finished by completing its sequence + stopping = 3, // running ending animations / fadeout, etc. Will not accept more input. + stopped = 4, // we're done here. + }; + enum EJobFlags + { + visible = 0, + fadein = 1, + fadeout = 2, + stopmusic = 4, + stopsound = 8, + transition_shift = 4, + transition_mask = 48, + transition_melt = 16, + transition_burn = 32, + transition_crossfade = 48, + }; + + void Init(int fflags = 0, float fadet = 250.f) + { + flags = fflags; + fadetime = fadet; + jobstate = running; + } + + virtual bool ProcessInput() + { + return false; + } + + virtual void Start() {} + virtual bool OnEvent(InputEvent evt) { return false; } + virtual void OnTick() {} + virtual void Draw(double smoothratio) {} + virtual void OnSkip() {} + + int DrawFrame(double smoothratio) + { + if (jobstate != running) smoothratio = 1; // this is necessary to avoid having a negative time span because the ticker won't be incremented anymore. + Draw(smoothratio); + if (jobstate == skipped) return -1; + if (jobstate == finished) return 0; + return 1; + } + + int GetFadeState() { return fadestate; } + override void OnDestroy() + { + if (flags & stopmusic) System.StopMusic(); + if (flags & stopsound) System.StopAllSounds(); + } + +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class SkippableScreenJob : ScreenJob +{ + void Init(int flags = 0, float fadet = 250.f) + { + Super.Init(flags, fadet); + } + + override bool OnEvent(InputEvent evt) + { + if (evt.type == InputEvent.Type_KeyDown && !System.specialKeyEvent(evt)) + { + jobstate = skipped; + OnSkip(); + } + return true; + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class BlackScreen : ScreenJob +{ + int wait; + bool cleared; + + ScreenJob Init(int w, int flags = 0) + { + Super.Init(flags & ~(fadein|fadeout)); + wait = w; + cleared = false; + return self; + } + + static ScreenJob Create(int w, int flags = 0) + { + return new("BlackScreen").Init(w, flags); + } + + override void OnTick() + { + if (cleared) + { + int span = ticks * 1000 / GameTicRate; + if (span > wait) jobstate = finished; + } + } + + override void Draw(double smooth) + { + cleared = true; + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class ImageScreen : SkippableScreenJob +{ + int tilenum; + TranslationID trans; + int waittime; // in ms. + bool cleared; + TextureID texid; + + ScreenJob Init(TextureID tile, int fade = fadein | fadeout, int wait = 3000, TranslationID translation = 0) + { + Super.Init(fade); + waittime = wait; + texid = tile; + trans = translation; + cleared = false; + return self; + } + + ScreenJob InitNamed(String tex, int fade = fadein | fadeout, int wait = 3000, TranslationID translation = 0) + { + Super.Init(fade); + waittime = wait; + texid = TexMan.CheckForTexture(tex, TexMan.Type_Any, TexMan.TryAny | TexMan.ForceLookup); + trans = translation; + cleared = false; + return self; + } + + static ScreenJob Create(TextureID tile, int fade = fadein | fadeout, int wait = 3000, TranslationID translation = 0) + { + return new("ImageScreen").Init(tile, fade, wait, translation); + } + + static ScreenJob CreateNamed(String tex, int fade = fadein | fadeout, int wait = 3000, TranslationID translation = 0) + { + return new("ImageScreen").InitNamed(tex, fade, wait, translation); + } + + override void OnTick() + { + if (cleared) + { + int span = ticks * 1000 / GameTicRate; + if (span > waittime) jobstate = finished; + } + } + + override void Draw(double smooth) + { + if (texid.IsValid()) Screen.DrawTexture(texid, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, DTA_TranslationIndex, trans); + cleared = true; + } +} + +//--------------------------------------------------------------------------- +// +// internal polymorphic movie player object +// +//--------------------------------------------------------------------------- + +struct MoviePlayer native +{ + enum EMovieFlags + { + NOSOUNDCUTOFF = 1, + FIXEDVIEWPORT = 2, // Forces fixed 640x480 screen size like for Blood's intros. + NOMUSICCUTOFF = 4, + } + + native static MoviePlayer Create(String filename, Array soundinfo, int flags, int frametime, int firstframetime, int lastframetime); + native void Start(); + native bool Frame(double clock); + native void Destroy(); + native TextureID GetTexture(); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class MoviePlayerJob : SkippableScreenJob +{ + MoviePlayer player; + bool started; + int flag; + + ScreenJob Init(MoviePlayer mp, int flags) + { + Super.Init(); + flag = flags; + player = mp; + nowipe = true; // due to synchronization issues wipes must be disabled on any movie. + return self; + } + + override void Start() + { + if (!(flag & MoviePlayer.NOMUSICCUTOFF)) System.StopMusic(); + } + + + static ScreenJob CreateWithSoundInfo(String filename, Array soundinfo, int flags, int frametime, int firstframetime = -1, int lastframetime = -1) + { + let movie = MoviePlayer.Create(filename, soundinfo, flags, frametime, firstframetime, lastframetime); + if (movie) return new("MoviePlayerJob").Init(movie, flags); + return null; + } + static ScreenJob Create(String filename, int flags, int frametime = -1) + { + Array empty; + return CreateWithSoundInfo(filename, empty, flags, frametime); + } + static ScreenJob CreateWithSound(String filename, Sound soundname, int flags, int frametime = -1) + { + Array empty; + empty.Push(1); + empty.Push(int(soundname)); + return CreateWithSoundInfo(filename, empty, flags, frametime); + } + + virtual void DrawFrame() + { + let tex = player.GetTexture(); + let size = TexMan.GetScaledSize(tex); + + if (!(flag & MoviePlayer.FIXEDVIEWPORT) || (size.x <= 320 && size.y <= 200) || size.x >= 640 || size.y >= 480) + { + Screen.DrawTexture(tex, false, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false); + } + else + { + Screen.DrawTexture(tex, false, 320, 240, DTA_VirtualWidth, 640, DTA_VirtualHeight, 480, DTA_CenterOffset, true, DTA_Masked, false); + } + + } + + override void Draw(double smoothratio) + { + if (!player) + { + jobstate = stopped; + return; + } + if (!started) + { + started = true; + player.Start(); + } + double clock = (ticks + smoothratio) * 1000000000. / GameTicRate; + if (jobstate == running && !player.Frame(clock)) + { + jobstate = finished; + } + DrawFrame(); + } + + override void OnDestroy() + { + if (player) + { + player.Destroy(); + } + player = null; + } +} + + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class ScreenJobRunner : Object UI +{ + enum ERunState + { + State_Clear, + State_Run, + State_Fadeout, + } + Array jobs; + //CompletionFunc completion; + int index; + float screenfade; + bool clearbefore; + bool skipall; + bool advance; + int actionState; + int terminateState; + int fadeticks; + int last_paused_tic; + + native static void setTransition(int type); + + void Init(bool clearbefore_, bool skipall_) + { + clearbefore = clearbefore_; + skipall = skipall_; + index = -1; + fadeticks = 0; + last_paused_tic = -1; + } + + override void OnDestroy() + { + DeleteJobs(); + } + + protected void DeleteJobs() + { + // Free all allocated resources now. + for (int i = 0; i < jobs.Size(); i++) + { + if (jobs[i]) jobs[i].Destroy(); + } + jobs.Clear(); + } + + void Append(ScreenJob job) + { + if (job != null) jobs.Push(job); + } + + virtual bool Validate() + { + return jobs.Size() > 0; + } + + bool CanWipe() + { + if (index < jobs.Size()) return !jobs[max(0, index)].nowipe; + return true; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + protected void AdvanceJob(bool skip) + { + if (index == jobs.Size()-1) + { + index++; + return; // we need to retain the last element until the runner is done. + } + + if (index >= 0) jobs[index].Destroy(); + index++; + while (index < jobs.Size() && (jobs[index] == null || (skip && jobs[index].skipover))) + { + if (jobs[index] != null && index < jobs.Size() - 1) jobs[index].Destroy(); // may not delete the last element - we still need it for shutting down. + index++; + } + actionState = clearbefore ? State_Clear : State_Run; + if (index < jobs.Size()) + { + jobs[index].fadestate = !paused && jobs[index].flags & ScreenJob.fadein? ScreenJob.fadein : ScreenJob.visible; + jobs[index].Start(); + if (jobs[index].flags & ScreenJob.transition_mask) + { + setTransition((jobs[index].flags & ScreenJob.transition_mask) >> ScreenJob.Transition_Shift); + } + } + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + virtual int DisplayFrame(double smoothratio) + { + if (jobs.Size() == 0) + { + return 1; + } + int x = index >= jobs.Size()? jobs.Size()-1 : index; + let job = jobs[x]; + bool processed = job.ProcessInput(); + + if (job.fadestate == ScreenJob.fadein) + { + double ms = (job.ticks + smoothratio) * 1000 / GameTicRate / job.fadetime; + double screenfade = clamp(ms, 0., 1.); + Screen.SetScreenFade(screenfade); + if (screenfade == 1.) job.fadestate = ScreenJob.visible; + } + int state = job.DrawFrame(smoothratio); + Screen.SetScreenFade(1.); + return state; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + virtual int FadeoutFrame(double smoothratio) + { + int x = index >= jobs.Size()? jobs.Size()-1 : index; + let job = jobs[x]; + double ms = (fadeticks + smoothratio) * 1000 / GameTicRate / job.fadetime; + float screenfade = 1. - clamp(ms, 0., 1.); + Screen.SetScreenFade(screenfade); + job.DrawFrame(1.); + Screen.SetScreenFade(1.); + return (screenfade > 0.); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + virtual bool OnEvent(InputEvent ev) + { + if (paused || index < 0 || index >= jobs.Size()) return false; + if (jobs[index].jobstate != ScreenJob.running) return false; + return jobs[index].OnEvent(ev); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + virtual bool OnTick() + { + if (paused) return false; + if (index >= jobs.Size() || jobs.Size() == 0) return true; + if (advance || index < 0) + { + advance = false; + AdvanceJob(terminateState < 0); + if (index >= jobs.Size()) + { + return true; + } + } + if (jobs[index].jobstate == ScreenJob.running) + { + jobs[index].ticks++; + jobs[index].OnTick(); + } + else if (jobs[index].jobstate == ScreenJob.stopping) + { + fadeticks++; + } + return false; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + virtual bool RunFrame(double smoothratio) + { + if (index < 0) + { + AdvanceJob(false); + } + // ensure that we won't go back in time if the menu is dismissed without advancing our ticker + if (index < jobs.Size()) + { + bool menuon = paused; + if (menuon) last_paused_tic = jobs[index].ticks; + else if (last_paused_tic == jobs[index].ticks) menuon = true; + if (menuon) smoothratio = 1.; + } + else smoothratio = 1.; + + if (actionState == State_Clear) + { + actionState = State_Run; + } + else if (actionState == State_Run) + { + terminateState = DisplayFrame(smoothratio); + if (terminateState < 1 && index < jobs.Size()) + { + if (jobs[index].flags & ScreenJob.fadeout) + { + jobs[index].fadestate = ScreenJob.fadeout; + jobs[index].jobstate = ScreenJob.stopping; + actionState = State_Fadeout; + fadeticks = 0; + } + else + { + advance = true; + } + } + } + else if (actionState == State_Fadeout) + { + int ended = FadeoutFrame(smoothratio); + if (ended < 1 && index < jobs.Size()) + { + jobs[index].jobstate = ScreenJob.stopped; + advance = true; + } + } + return true; + } + + void AddGenericVideo(String fn, int snd, int framerate) + { + Array sounds; + if (snd > 0) sounds.Pushv(1, snd); + Append(MoviePlayerJob.CreateWithSoundInfo(fn, sounds, 0, framerate)); + } +} diff --git a/wadsrc/static/zscript/engine/service.zs b/wadsrc/static/zscript/engine/service.zs new file mode 100644 index 00000000000..6df17f1268f --- /dev/null +++ b/wadsrc/static/zscript/engine/service.zs @@ -0,0 +1,155 @@ +/** + * This is Service interface. + */ +class Service abstract +{ + deprecated("4.6.1", "Use GetString() instead") virtual play String Get(String request) + { + return ""; + } + + deprecated("4.6.1", "Use GetStringUI() instead") virtual ui String UiGet(String request) + { + return ""; + } + + // Play variants + virtual play String GetString(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ""; + } + + virtual play int GetInt(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return 0; + } + + virtual play double GetDouble(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return 0.0; + } + + virtual play Object GetObject(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return null; + } + + virtual play Name GetName(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ''; + } + + + // UI variants + virtual ui String GetStringUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ""; + } + + virtual ui int GetIntUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return 0; + } + + virtual ui double GetDoubleUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return 0.0; + } + + virtual ui Object GetObjectUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return null; + } + + virtual ui Name GetNameUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ''; + } + + // data/clearscope variants + virtual clearscope String GetStringData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ""; + } + + virtual clearscope int GetIntData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return 0; + } + + virtual clearscope double GetDoubleData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return 0.0; + } + + virtual clearscope Object GetObjectData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return null; + } + + virtual clearscope Name GetNameData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ''; + } + + static Service Find(class serviceName){ + return AllServices.GetIfExists(serviceName.GetClassName()); + } +} + +/** + * Use this class to find and iterate over services. + * + * Example usage: + * + * @code + * ServiceIterator i = ServiceIterator.Find("MyService"); + * + * Service s; + * while (s = i.Next()) + * { + * String request = ... + * String answer = s.Get(request); + * ... + * } + * @endcode + * + * If no services are found, the all calls to Next() will return NULL. + */ +class ServiceIterator +{ + /** + * Creates a Service iterator for a service name. It will iterate over all existing Services + * with names that match @a serviceName or have it as a part of their names. + * + * Matching is case-independent. + * + * @param serviceName class name of service to find. + */ + static ServiceIterator Find(String serviceName) + { + let result = new("ServiceIterator"); + result.mServiceName = serviceName.MakeLower(); + result.it.Init(AllServices); + return result; + } + + /** + * Gets the service and advances the iterator. + * + * @returns service instance, or NULL if no more services found. + */ + Service Next() + { + while(it.Next()) + { + String cName = it.GetKey(); + if(cName.MakeLower().IndexOf(mServiceName) != -1) + return it.GetValue(); + } + return null; + } + + private MapIterator it; + private String mServiceName; +} diff --git a/wadsrc/static/zscript/ui/menu/colorpickermenu.zs b/wadsrc/static/zscript/engine/ui/menu/colorpickermenu.zs similarity index 98% rename from wadsrc/static/zscript/ui/menu/colorpickermenu.zs rename to wadsrc/static/zscript/engine/ui/menu/colorpickermenu.zs index 188d9f2722f..218a215fca5 100644 --- a/wadsrc/static/zscript/ui/menu/colorpickermenu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/colorpickermenu.zs @@ -73,20 +73,20 @@ class ColorpickerMenu : OptionMenu int mStartItem; CVar mCVar; - + double GetColor(int index) { double v = index == 0? mRed : index == 1? mGreen : mBlue; return v; } - + void SetColor(int index, double val) { if (index == 0) mRed = val; else if (index == 1) mGreen = val; else mBlue = val; } - + //============================================================================= // // @@ -119,7 +119,7 @@ class ColorpickerMenu : OptionMenu mDesc.mIndent = 0; mDesc.CalcIndent(); } - + //============================================================================= // // @@ -241,7 +241,6 @@ class ColorpickerMenu : OptionMenu { mGridPosX = cell_x; mGridPosY = cell_y; - //S_Sound (CHAN_VOICE, CHANF_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); } mDesc.mSelectedItem = mStartItem+7; if (type == MOUSE_Release) @@ -274,7 +273,7 @@ class ColorpickerMenu : OptionMenu if (h > fh) h = fh; else if (h < 4) return; // no space to draw it. - + int indent = (screen.GetWidth() / 2); int p = 0; @@ -304,7 +303,7 @@ class ColorpickerMenu : OptionMenu } // Make sure the cursors stand out against similar colors // by pulsing them. - blinky = abs(sin(MSTime()/1000.0)) * 0.5 + 0.5; + blinky = abs(sin(MSTimeF()/1000.0)) * 0.5 + 0.5; col = Color(255, int(r*blinky), int(g*blinky), int(b*blinky)); screen.Clear (box_x, box_y, box_x + w, box_y + 1, col); @@ -329,7 +328,7 @@ class ColorpickerMenu : OptionMenu y += 49*CleanYfac_1; screen.DrawText (SmallFont, Font.CR_GRAY, x+(48-SmallFont.StringWidth("---->")/2)*CleanXfac_1, y, "---->", DTA_CleanNoMove_1, true); } - + override void OnDestroy() { if (mStartItem >= 0) diff --git a/wadsrc/static/zscript/engine/ui/menu/custommessagebox.zs b/wadsrc/static/zscript/engine/ui/menu/custommessagebox.zs new file mode 100644 index 00000000000..948d9046b8e --- /dev/null +++ b/wadsrc/static/zscript/engine/ui/menu/custommessagebox.zs @@ -0,0 +1,264 @@ +/* +** +**--------------------------------------------------------------------------- +** Copyright 2010-2017 Christoph Oelckers +** Copyright 2022 Ricardo Luis Vaz Silva +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +class CustomMessageBoxMenuBase : Menu abstract +{ + BrokenLines mMessage; + uint messageSelection; + int mMouseLeft, mMouseRight, mMouseY; + + Font textFont, arrowFont; + int destWidth, destHeight; + String selector; + + abstract uint OptionCount(); + abstract String OptionName(uint index); + abstract int OptionXOffset(uint index); + + abstract int OptionForShortcut(int char_key, out bool activate); // -1 for no shortcut, activate = true if this executes the option immediately + + //============================================================================= + // + // + // + //============================================================================= + + virtual void Init(Menu parent, String message, bool playsound = false) + { + Super.Init(parent); + messageSelection = 0; + mMouseLeft = 140; + mMouseY = 0x80000000; + textFont = null; + + if (!generic_ui) + { + if (SmallFont && SmallFont.CanPrint(message) && SmallFont.CanPrint("$TXT_YES") && SmallFont.CanPrint("$TXT_NO")) textFont = SmallFont; + else if (OriginalSmallFont && OriginalSmallFont.CanPrint(message) && OriginalSmallFont.CanPrint("$TXT_YES") && OriginalSmallFont.CanPrint("$TXT_NO")) textFont = OriginalSmallFont; + } + + if (!textFont) + { + arrowFont = textFont = NewSmallFont; + int factor = (CleanXfac+1) / 2; + destWidth = screen.GetWidth() / factor; + destHeight = screen.GetHeight() / factor; + selector = "▶"; + } + else + { + arrowFont = ((textFont && textFont.GetGlyphHeight(0xd) > 0) ? textFont : ConFont); + destWidth = CleanWidth; + destHeight = CleanHeight; + selector = "\xd"; + } + + int mr1 = destWidth/2 + 10 + textFont.StringWidth(Stringtable.Localize("$TXT_YES")); + int mr2 = destWidth/2 + 10 + textFont.StringWidth(Stringtable.Localize("$TXT_NO")); + mMouseRight = MAX(mr1, mr2); + mParentMenu = parent; + mMessage = textFont.BreakLines(Stringtable.Localize(message), int(300/NotifyFontScale)); + if (playsound) + { + MenuSound ("menu/prompt"); + } + } + + //============================================================================= + // + // + // + //============================================================================= + + override void Drawer () + { + int i; + double y; + let fontheight = textFont.GetHeight() * NotifyFontScale; + + y = destHeight / 2; + + int c = mMessage.Count(); + y -= c * fontHeight / 2; + + for (i = 0; i < c; i++) + { + screen.DrawText (textFont, Font.CR_UNTRANSLATED, destWidth/2 - mMessage.StringWidth(i)*NotifyFontScale/2, y, mMessage.StringAt(i), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true, + DTA_ScaleX, NotifyFontScale, DTA_ScaleY, NotifyFontScale); + y += fontheight; + } + + y += fontheight; + mMouseY = int(y); + + let n = optionCount(); + for(uint i = 0; i < n; i++) + { + screen.DrawText(textFont, messageSelection == i? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, (destWidth / 2) + OptionXOffset(i), y + (fontheight * i), Stringtable.Localize(optionName(i)), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true, DTA_ScaleX, NotifyFontScale, DTA_ScaleY, NotifyFontScale); + } + + if (messageSelection >= 0) + { + if ((MenuTime() % 8) < 6) + { + screen.DrawText(arrowFont, OptionMenuSettings.mFontColorSelection, + (destWidth/2 - 3 - arrowFont.StringWidth(selector)) + OptionXOffset(messageSelection), y + fontheight * messageSelection, selector, DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); + } + } + } + + + //============================================================================= + // + // + // + //============================================================================= + + protected void CloseSound() + { + MenuSound (GetCurrentMenu() != NULL? "menu/backup" : "menu/dismiss"); + } + + //============================================================================= + // + // + // + //============================================================================= + + abstract void HandleResult(int index); // -1 = escape + + //============================================================================= + // + // + // + //============================================================================= + + override bool OnUIEvent(UIEvent ev) + { + if (ev.type == UIEvent.Type_KeyDown) + { + // tolower + int ch = ev.KeyChar; + ch = ch >= 65 && ch <91? ch + 32 : ch; + + bool activate; + int opt = optionForShortcut(ch,activate); + + if(opt >= 0){ + if(activate || opt == messageSelection) { + HandleResult(messageSelection); + } else { + messageSelection = opt; + } + return true; + } + return false; + } + return Super.OnUIEvent(ev); + } + + override bool OnInputEvent(InputEvent ev) + { + if (ev.type == InputEvent.Type_KeyDown) + { + Close(); + return true; + } + return Super.OnInputEvent(ev); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent(int mkey, bool fromcontroller) + { + if (mkey == MKEY_Up) + { + MenuSound("menu/cursor"); + if (messageSelection == 0) messageSelection = optionCount(); + messageSelection--; + return true; + } + else if (mkey == MKEY_Down) + { + MenuSound("menu/cursor"); + messageSelection++; + if (messageSelection == optionCount()) messageSelection = 0; + return true; + } + else if (mkey == MKEY_Enter) + { + HandleResult(messageSelection); + return true; + } + else if (mkey == MKEY_Back) + { + HandleResult(-1); + return true; + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + int fh = textFont.GetHeight() + 1; + + // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture + x = x * destWidth / screen.GetWidth(); + y = y * destHeight / screen.GetHeight(); + + int n = OptionCount(); + + if (x >= mMouseLeft && x <= mMouseRight && y >= mMouseY && y < mMouseY + (n * fh)) + { + messageSelection = (y - mMouseY) / fh; + } + if (type == MOUSE_Release) + { + return MenuEvent(MKEY_Enter, true); + } + return true; + } + + +} diff --git a/wadsrc/static/zscript/engine/ui/menu/imagescroller.zs b/wadsrc/static/zscript/engine/ui/menu/imagescroller.zs new file mode 100644 index 00000000000..5c7865f0303 --- /dev/null +++ b/wadsrc/static/zscript/engine/ui/menu/imagescroller.zs @@ -0,0 +1,290 @@ +/* +** imagescroller.cpp +** Scrolls through multiple fullscreen image pages, +** +**--------------------------------------------------------------------------- +** Copyright 2019-220 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + +class ImageScrollerDescriptor : MenuDescriptor native +{ + native Array mItems; + native Font textFont; + native TextureID textBackground; + native Color textBackgroundBrightness; + native double textScale; + native bool mAnimatedTransition; + native bool mAnimated; + native bool mDontBlur; + native bool mDontDim; + native int virtWidth, virtHeight; +} + +class ImageScrollerPage : MenuItemBase +{ + int virtWidth, virtHeight; + + protected void DrawText(Font fnt, int color, double x, double y, String text) + { + screen.DrawText(fnt, color, x, y, text, DTA_VirtualWidth, virtWidth, DTA_VirtualHeight, virtHeight, DTA_FullscreenScale, FSMode_ScaleToFit43); + } + + protected void DrawTexture(TextureID tex, double x, double y) + { + screen.DrawTexture(tex, true, x, y, DTA_VirtualWidth, virtWidth, DTA_VirtualHeight, virtHeight, DTA_FullscreenScale, FSMode_ScaleToFit43); + } + + virtual void OnStartPage() + {} + + virtual void OnEndPage() + {} +} + +//============================================================================= +// +// an image page +// +//============================================================================= + +class ImageScrollerPageImageItem : ImageScrollerPage +{ + TextureID mTexture; + + void Init(ImageScrollerDescriptor desc, String patch) + { + Super.Init(); + mTexture = TexMan.CheckForTexture(patch); + } + + override void Drawer(bool selected) + { + Screen.DrawTexture(mTexture, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal); + } +} + +//============================================================================= +// +// a simple text page +// +//============================================================================= + +class ImageScrollerPageTextItem : ImageScrollerPage +{ + Font mFont; + BrokenLines mText; + TextureID mTexture; + Color mBrightness; + double mTextScale; + + void Init(ImageScrollerDescriptor desc, String txt, int y = -1) + { + Super.Init(); + mTexture = desc.textBackground; + mBrightness = desc.textBackgroundBrightness; + mFont = desc.textFont; + mTextScale = desc.textScale; + virtWidth = desc.virtWidth; + virtHeight = desc.virtHeight; + + mText = mFont.BreakLines(Stringtable.Localize(txt.Filter()), int(virtWidth / mTextScale)); + mYpos = y >= 0? y : virtHeight / 2 - mText.Count() * mFont.GetHeight() * mTextScale / 2; + + } + + override void Drawer(bool selected) + { + Screen.DrawTexture(mTexture, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, DTA_Color, mBrightness); + + let fontheight = mFont.GetHeight() * mTextScale; + let y = mYpos; + let c = mText.Count(); + for (int i = 0; i < c; i++) + { + screen.DrawText (mFont, Font.CR_UNTRANSLATED, virtWidth/2 - mText.StringWidth(i) * mTextScale / 2, y, mText.StringAt(i), DTA_ScaleX, mTextScale, DTA_ScaleY, mTextScale, + DTA_VirtualWidth, virtWidth, DTA_VirtualHeight, virtHeight, DTA_FullscreenScale, FSMode_ScaleToFit43); + y += fontheight; + } + } +} + +//============================================================================= +// +// The main class +// +//============================================================================= + +class ImageScrollerMenu : Menu +{ + ImageScrollerPage previous; + ImageScrollerPage current; + + double start; + int length; + int dir; + int index; + ImageScrollerDescriptor mDesc; + + + private void StartTransition(ImageScrollerPage to, int animtype) + { + if (AnimatedTransition) + { + start = MSTimeF() * (120. / 1000.); + length = 30; + dir = animtype; + previous = current; + } + to.onStartPage(); + current = to; + } + + virtual void Init(Menu parent, ImageScrollerDescriptor desc) + { + mParentMenu = parent; + index = 0; + mDesc = desc; + AnimatedTransition = mDesc.mAnimatedTransition; + Animated = mDesc.mAnimated; + DontBlur = mDesc.mDontBlur; + DontDim = mDesc.mDontDim; + current = mDesc.mItems[0]; + current.onStartPage(); + previous = null; + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent(int mkey, bool fromcontroller) + { + if (mDesc.mItems.Size() <= 1) + { + if (mkey == MKEY_Enter) mkey = MKEY_Back; + else if (mkey == MKEY_Right || mkey == MKEY_Left) return true; + } + switch (mkey) + { + case MKEY_Back: + // Before going back the currently running transition must be terminated. + previous = null; + return Super.MenuEvent(mkey, fromcontroller); + + + case MKEY_Left: + if (previous == null) + { + if (--index < 0) index = mDesc.mItems.Size() - 1; + let next = mDesc.mItems[index]; + StartTransition(next, -1); + MenuSound("menu/choose"); + } + return true; + + case MKEY_Right: + case MKEY_Enter: + if (previous == null) + { + int oldindex = index; + if (++index >= mDesc.mItems.Size()) index = 0; + let next = mDesc.mItems[index]; + StartTransition(next, 1); + MenuSound("menu/choose"); + } + return true; + + default: + return Super.MenuEvent(mkey, fromcontroller); + } + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + // Todo: Implement some form of drag event to switch between pages. + if (type == MOUSE_Release) + { + return MenuEvent(MKEY_Enter, false); + } + return Super.MouseEvent(type, x, y); + } + + //============================================================================= + // + // + // + //============================================================================= + + private bool DrawTransition() + { + double now = MSTimeF() * (120. / 1000.); + if (now < start + length) + { + double factor = screen.GetWidth()/2; + double phase = (now - start) / length * 180. + 90.; + + screen.SetOffset(factor * dir * (sin(phase) - 1.), 0); + previous.Drawer(false); + screen.SetOffset(factor * dir * (sin(phase) + 1.), 0); + current.Drawer(false); + screen.SetOffset(0, 0); + return true; + } + previous.OnEndPage(); + previous = null; + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + override void Drawer() + { + if (previous != null) + { + bool wasAnimated = Animated; + Animated = true; + if (DrawTransition()) return; + previous = null; + Animated = wasAnimated; + } + current.Drawer(false); + } +} diff --git a/wadsrc/static/zscript/ui/menu/joystickmenu.zs b/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs similarity index 87% rename from wadsrc/static/zscript/ui/menu/joystickmenu.zs rename to wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs index 48b5840e7a2..02669c1a3af 100644 --- a/wadsrc/static/zscript/ui/menu/joystickmenu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs @@ -41,7 +41,7 @@ class OptionMenuSliderJoySensitivity : OptionMenuSliderBase { JoystickConfig mJoy; - + OptionMenuSliderJoySensitivity Init(String label, double min, double max, double step, int showval, JoystickConfig joy) { Super.Init(label, min, max, step, showval); @@ -71,7 +71,7 @@ class OptionMenuSliderJoyScale : OptionMenuSliderBase int mAxis; int mNeg; JoystickConfig mJoy; - + OptionMenuSliderJoyScale Init(String label, int axis, double min, double max, double step, int showval, JoystickConfig joy) { Super.Init(label, min, max, step, showval); @@ -138,7 +138,7 @@ class OptionMenuItemJoyMap : OptionMenuItemOptionBase { int mAxis; JoystickConfig mJoy; - + OptionMenuItemJoyMap Init(String label, int axis, Name values, int center, JoystickConfig joy) { Super.Init(label, 'none', values, null, center); @@ -191,7 +191,7 @@ class OptionMenuItemInverter : OptionMenuItemOptionBase { int mAxis; JoystickConfig mJoy; - + OptionMenuItemInverter Init(String label, int axis, int center, JoystickConfig joy) { Super.Init(label, "none", "YesNo", NULL, center); @@ -220,10 +220,56 @@ class OptionMenuItemInverter : OptionMenuItemOptionBase // //============================================================================= + +class OptionMenuJoyEnable : OptionMenuItemOptionBase +{ + JoystickConfig mJoy; + + OptionMenuJoyEnable Init(String label, JoystickConfig joy) + { + Super.Init(label,"none","YesNo",null,0); + mJoy = joy; + return self; + } + + override int GetSelection() + { + return mJoy.GetEnabled() ? 1 : 0; + } + + override void SetSelection(int Selection) + { + mJoy.SetEnabled(Selection); + } +} + + +class OptionMenuJoyEnableInBackground : OptionMenuItemOptionBase +{ + JoystickConfig mJoy; + + OptionMenuJoyEnableInBackground Init(String label, JoystickConfig joy) + { + Super.Init(label,"none","YesNo",null,0); + mJoy = joy; + return self; + } + + override int GetSelection() + { + return mJoy.GetEnabledInBackground() ? 1 : 0; + } + + override void SetSelection(int Selection) + { + mJoy.SetEnabledInBackground(Selection); + } +} + class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu { JoystickConfig mJoy; - + OptionMenuItemJoyConfigMenu Init(String label, JoystickConfig joy) { Super.Init(label, "JoystickConfigMenu"); @@ -243,7 +289,7 @@ class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu if (res && joymenu != null) joymenu.mJoy = mJoy; return res; } - + static void SetController(OptionMenuDescriptor opt, JoystickConfig joy) { OptionMenuItem it; @@ -256,8 +302,22 @@ class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu } else { + /* it = new("OptionMenuItemStaticText").Init(joy.GetName(), false); + opt.mItems.Push(it); + it = new("OptionMenuItemStaticText").Init("", false); + opt.mItems.Push(it); + */ + + it = new("OptionMenuJoyEnable").Init("$JOYMNU_JOYENABLE", joy); + opt.mItems.Push(it); + + if(joy.AllowsEnabledInBackground()) + { + it = new("OptionMenuJoyEnableInBackground").Init("$JOYMNU_JOYENABLEINBACKGROUND", joy); + opt.mItems.Push(it); + } it = new("OptionMenuSliderJoySensitivity").Init("$JOYMNU_OVRSENS", 0, 2, 0.1, 3, joy); opt.mItems.Push(it); @@ -296,7 +356,7 @@ class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu opt.mPosition = -25; opt.CalcIndent(); } - + } //============================================================================= diff --git a/wadsrc/static/zscript/engine/ui/menu/listmenu.zs b/wadsrc/static/zscript/engine/ui/menu/listmenu.zs new file mode 100644 index 00000000000..ed3c2ef16bf --- /dev/null +++ b/wadsrc/static/zscript/engine/ui/menu/listmenu.zs @@ -0,0 +1,370 @@ +/* +** listmenu.zs +** The main menu class +** +**--------------------------------------------------------------------------- +** Copyright 2010-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + + + +class ListMenuDescriptor : MenuDescriptor native +{ + enum EScale + { + CleanScale = -1, + OptCleanScale = -2 + }; + native Array mItems; + native int mSelectedItem; + native double mSelectOfsX; + native double mSelectOfsY; + native TextureID mSelector; + native int mDisplayTop; + native double mXpos, mYpos; + native int mWLeft, mWRight; + native int mLinespacing; // needs to be stored for dynamically created menus + native int mAutoselect; // this can only be set by internal menu creation functions + native Font mFont; + native int mFontColor; + native int mFontColor2; + native bool mCenter; + native bool mCenterText; + native bool mAnimatedTransition; + native bool mAnimated; + native bool mDontBlur; + native bool mDontDim; + native int mVirtWidth, mVirtHeight; + + native void Reset(); + int DisplayWidth() + { + if (mVirtWidth == OptCleanScale) return m_cleanscale ? CleanScale : 320; + return mVirtWidth; + } + int DisplayHeight() + { + if (mVirtWidth == OptCleanScale) return m_cleanscale ? CleanScale : 200; + return mVirtHeight; + } +} + +//============================================================================= +// +// list menu class runs a menu described by a DListMenuDescriptor +// +//============================================================================= + +class ListMenu : Menu +{ + ListMenuDescriptor mDesc; + MenuItemBase mFocusControl; + + virtual void Init(Menu parent = NULL, ListMenuDescriptor desc = NULL) + { + Super.Init(parent); + mDesc = desc; + AnimatedTransition = mDesc.mAnimatedTransition; + Animated = mDesc.mAnimated; + DontBlur = mDesc.mDontBlur; + DontDim = mDesc.mDontDim; + if (desc.mCenter) + { + double center = 160; + for(int i=0; i < mDesc.mItems.Size(); i++) + { + double xpos = mDesc.mItems[i].GetX(); + int width = mDesc.mItems[i].GetWidth(); + double curx = mDesc.mSelectOfsX; + + if (width > 0 && mDesc.mItems[i].Selectable()) + { + double left = 160 - (width - curx) / 2 - curx; + if (left < center) center = left; + } + } + for(int i=0;i 0) + { + mDesc.mItems[i].SetX(center); + } + } + } + // notify all items that the menu was just created. + for(int i=0;i 0) + { + // tolower + int ch = ev.KeyChar; + ch = ch >= 65 && ch < 91 ? ch + 32 : ch; + + for(int i = mDesc.mSelectedItem + 1; i < mDesc.mItems.Size(); i++) + { + if (mDesc.mitems[i].Selectable() && mDesc.mItems[i].CheckHotkey(ch)) + { + mDesc.mSelectedItem = i; + MenuSound("menu/cursor"); + return true; + } + } + for(int i = 0; i < mDesc.mSelectedItem; i++) + { + if (mDesc.mitems[i].Selectable() && mDesc.mItems[i].CheckHotkey(ch)) + { + mDesc.mSelectedItem = i; + MenuSound("menu/cursor"); + return true; + } + } + } + return Super.OnUIEvent(ev); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent (int mkey, bool fromcontroller) + { + int oldSelect = mDesc.mSelectedItem; + int startedAt = max(0, mDesc.mSelectedItem); + + switch (mkey) + { + case MKEY_Up: + do + { + if (--mDesc.mSelectedItem < 0) mDesc.mSelectedItem = mDesc.mItems.Size()-1; + } + while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt); + if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect; + MenuSound("menu/cursor"); + return true; + + case MKEY_Down: + do + { + if (++mDesc.mSelectedItem >= mDesc.mItems.Size()) mDesc.mSelectedItem = 0; + } + while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt); + if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect; + MenuSound("menu/cursor"); + return true; + + case MKEY_Enter: + if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate()) + { + MenuSound("menu/advance"); + } + return true; + + default: + return Super.MenuEvent(mkey, fromcontroller); + } + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + int sel = -1; + + int w = mDesc.DisplayWidth(); + double sx, sy; + if (w == ListMenuDescriptor.CleanScale) + { + // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture + x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160; + y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100; + } + else + { + // for fullscreen scale, transform coordinates so that for the given rect the coordinates are within (0, 0, w, h) + int h = mDesc.DisplayHeight(); + double fx, fy, fw, fh; + [fx, fy, fw, fh] = Screen.GetFullscreenRect(w, h, FSMode_ScaleToFit43); + + x = int((x - fx) * w / fw); + y = int((y - fy) * h / fh); + } + + if (mFocusControl != NULL) + { + mFocusControl.MouseEvent(type, x, y); + return true; + } + else + { + if ((mDesc.mWLeft <= 0 || x > mDesc.mWLeft) && + (mDesc.mWRight <= 0 || x < mDesc.mWRight)) + { + for(int i=0;i= 0 && mDesc.mSelectedItem < mDesc.mItems.Size()) + { + if (!menuDelegate.DrawSelector(mDesc)) + mDesc.mItems[mDesc.mSelectedItem].DrawSelector(mDesc.mSelectOfsX, mDesc.mSelectOfsY, mDesc.mSelector, mDesc); + } + Super.Drawer(); + } + + //============================================================================= + // + // + // + //============================================================================= + + override void SetFocus(MenuItemBase fc) + { + mFocusControl = fc; + } + override bool CheckFocus(MenuItemBase fc) + { + return mFocusControl == fc; + } + override void ReleaseFocus() + { + mFocusControl = NULL; + } + + //============================================================================= + // + // + // + //============================================================================= + + void ChangeLineSpacing(int newspace) + { + double top = -32767; + + for (int i = 0; i < mDesc.mItems.Size(); i++) + { + let selitem = ListMenuItemSelectable(mDesc.mItems[i]); + if (selitem) + { + let y = mDesc.mItems[i].GetY(); + if (top == -32767) + { + top = y; + } + else + { + let newy = top + (y - top) / mDesc.mLineSpacing * newspace; + mDesc.mItems[i].SetY(newy); + } + } + } + mDesc.mLineSpacing = newspace; + } +} + + diff --git a/wadsrc/static/zscript/engine/ui/menu/listmenuitems.zs b/wadsrc/static/zscript/engine/ui/menu/listmenuitems.zs new file mode 100644 index 00000000000..66a4d9338cb --- /dev/null +++ b/wadsrc/static/zscript/engine/ui/menu/listmenuitems.zs @@ -0,0 +1,375 @@ +/* +** listmenu.cpp +** A simple menu consisting of a list of items +** +**--------------------------------------------------------------------------- +** Copyright 2010-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + + +class ListMenuItem : MenuItemBase +{ + protected void DrawText(ListMenuDescriptor desc, Font fnt, int color, double x, double y, String text, bool ontop = false) + { + int w = desc ? desc.DisplayWidth() : ListMenuDescriptor.CleanScale; + int h = desc ? desc.DisplayHeight() : -1; + if (w == ListMenuDescriptor.CleanScale) + { + screen.DrawText(fnt, color, x, y, text, ontop? DTA_CleanTop : DTA_Clean, true); + } + else + { + screen.DrawText(fnt, color, x, y, text, DTA_VirtualWidth, w, DTA_VirtualHeight, h, DTA_FullscreenScale, FSMode_ScaleToFit43); + } + } + + protected void DrawTexture(ListMenuDescriptor desc, TextureID tex, double x, double y, bool ontop = false) + { + int w = desc ? desc.DisplayWidth() : ListMenuDescriptor.CleanScale; + int h = desc ? desc.DisplayHeight() : -1; + if (w == ListMenuDescriptor.CleanScale) + { + screen.DrawTexture(tex, true, x, y, ontop ? DTA_CleanTop : DTA_Clean, true); + } + else + { + screen.DrawTexture(tex, true, x, y, DTA_VirtualWidth, w, DTA_VirtualHeight, h, DTA_FullscreenScale, FSMode_ScaleToFit43); + } + } + + virtual void DrawSelector(double xofs, double yofs, TextureID tex, ListMenuDescriptor desc = null) + { + if (tex.isNull()) + { + if ((Menu.MenuTime() % 8) < 6) + { + DrawText(desc, ConFont, OptionMenuSettings.mFontColorSelection, mXpos + xofs, mYpos + yofs + 8, "\xd"); + } + } + else + { + DrawTexture(desc, tex, mXpos + xofs, mYpos + yofs); + } + } + + // We cannot extend Drawer here because it is inherited from the parent class. + virtual void Draw(bool selected, ListMenuDescriptor desc) + { + Drawer(selected); // fall back to the legacy version, if not overridden + } +} + +//============================================================================= +// +// static patch +// +//============================================================================= + +class ListMenuItemStaticPatch : ListMenuItem +{ + TextureID mTexture; + bool mCentered; + String mSubstitute; + Font mFont; + int mColor; + + void Init(ListMenuDescriptor desc, double x, double y, TextureID patch, bool centered = false, String substitute = "") + { + Super.Init(x, y); + mTexture = patch; + mCentered = centered; + mSubstitute = substitute; + mFont = desc.mFont; + mColor = desc.mFontColor; + + } + + override void Draw(bool selected, ListMenuDescriptor desc) + { + if (!mTexture.Exists()) + { + return; + } + + double x = mXpos; + Vector2 vec = TexMan.GetScaledSize(mTexture); + + if (mSubstitute == "" || TexMan.OkForLocalization(mTexture, mSubstitute)) + { + if (mCentered) x -= vec.X / 2; + DrawTexture(desc, mTexture, x, abs(mYpos), mYpos < 0); + } + else + { + let font = generic_ui ? NewSmallFont : mFont; + if (mCentered) x -= font.StringWidth(mSubstitute) / 2; + DrawText(desc, font, mColor, x, abs(mYpos), mSubstitute, mYpos < 0); + } + } +} + +class ListMenuItemStaticPatchCentered : ListMenuItemStaticPatch +{ + void Init(ListMenuDescriptor desc, double x, double y, TextureID patch) + { + Super.Init(desc, x, y, patch, true); + } +} + +//============================================================================= +// +// static text +// +//============================================================================= + +class ListMenuItemStaticText : ListMenuItem +{ + String mText; + Font mFont; + int mColor; + bool mCentered; + + void Init(ListMenuDescriptor desc, double x, double y, String text, int color = -1) + { + Super.Init(x, y); + mText = text; + mFont = desc.mFont; + mColor = color >= 0? color : desc.mFontColor; + mCentered = desc.mCenterText; + } + + void InitDirect(double x, double y, String text, Font font, int color = Font.CR_UNTRANSLATED, bool centered = false) + { + Super.Init(x, y); + mText = text; + mFont = font; + mColor = color; + mCentered = centered; + } + + override void Draw(bool selected, ListMenuDescriptor desc) + { + if (mText.Length() != 0) + { + let font = generic_ui? NewSmallFont : mFont; + + String text = Stringtable.Localize(mText); + + double x = mXpos; + if (mCentered) x -= font.StringWidth(text) / 2; + DrawText(desc, font, mColor, x, abs(mYpos), text, mYpos < 0); + } + } +} + +class ListMenuItemStaticTextCentered : ListMenuItemStaticText +{ + void Init(ListMenuDescriptor desc, double x, double y, String text, int color = -1) + { + Super.Init(desc, x, y, text, color); + mCentered = true; + } +} + +//============================================================================= +// +// selectable items +// +//============================================================================= + +class ListMenuItemSelectable : ListMenuItem +{ + int mHotkey; + int mHeight; + int mParam; + + protected void Init(double x, double y, int height, Name childmenu, int param = -1) + { + Super.Init(x, y, childmenu); + mHeight = height; + mParam = param; + mHotkey = 0; + } + + override bool CheckCoordinate(int x, int y) + { + return mEnabled > 0 && y >= mYpos && y < mYpos + mHeight; // no x check here + } + + override bool Selectable() + { + return mEnabled > 0; + } + + override bool CheckHotkey(int c) + { + return c > 0 && c == mHotkey; + } + + override bool Activate() + { + Menu.SetMenu(mAction, mParam); + return true; + } + + override bool MouseEvent(int type, int x, int y) + { + if (type == Menu.MOUSE_Release) + { + let m = Menu.GetCurrentMenu(); + if (m != NULL && m.MenuEvent(Menu.MKEY_Enter, true)) + { + return true; + } + } + return false; + } + + override Name, int GetAction() + { + return mAction, mParam; + } +} + +//============================================================================= +// +// text item +// +//============================================================================= + +class ListMenuItemTextItem : ListMenuItemSelectable +{ + String mText; + Font mFont; + int mColor; + int mColorSelected; + + void Init(ListMenuDescriptor desc, String text, String hotkey, Name child, int param = 0) + { + Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, child, param); + mText = text; + mFont = desc.mFont; + mColor = desc.mFontColor; + mColorSelected = desc.mFontcolor2; + mHotkey = hotkey.GetNextCodePoint(0); + } + + void InitDirect(double x, double y, int height, String hotkey, String text, Font font, int color, int color2, Name child, int param = 0) + { + Super.Init(x, y, height, child, param); + mText = text; + mFont = font; + mColor = color; + mColorSelected = color2; + int pos = 0; + mHotkey = hotkey.GetNextCodePoint(0); + } + + override void Draw(bool selected, ListMenuDescriptor desc) + { + let font = menuDelegate.PickFont(mFont); + double x = mXpos; + if (desc.mCenterText) + { + x -= font.StringWidth(mText) / 2; + } + DrawText(desc, font, selected ? mColorSelected : mColor, x, mYpos, mText); + } + + override int GetWidth() + { + let font = menuDelegate.PickFont(mFont); + return max(1, font.StringWidth(StringTable.Localize(mText))); + } +} + +//============================================================================= +// +// patch item +// +//============================================================================= + +class ListMenuItemPatchItem : ListMenuItemSelectable +{ + TextureID mTexture; + + void Init(ListMenuDescriptor desc, TextureID patch, String hotkey, Name child, int param = 0) + { + Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, child, param); + mHotkey = hotkey.GetNextCodePoint(0); + mTexture = patch; + } + + void InitDirect(double x, double y, int height, TextureID patch, String hotkey, Name child, int param = 0) + { + Super.Init(x, y, height, child, param); + mHotkey = hotkey.GetNextCodePoint(0); + mTexture = patch; + } + + override void Draw(bool selected, ListMenuDescriptor desc) + { + DrawTexture(desc, mTexture, mXpos, mYpos); + } + + override int GetWidth() + { + return TexMan.GetSize(mTexture); + } + +} + +//============================================================================= +// +// caption - draws a text using the customizer's caption hook +// +//============================================================================= + +class ListMenuItemCaptionItem : ListMenuItem +{ + String mText; + Font mFont; + + void Init(ListMenuDescriptor desc, String text, String fnt = "BigFont") + { + Super.Init(0, 0); + mText = text; + mFont = Font.FindFont(fnt); + } + + override void Draw(bool selected, ListMenuDescriptor desc) + { + let font = menuDelegate.PickFont(desc.mFont); + if (font && mText.Length() > 0) + { + menuDelegate.DrawCaption(mText, font, 0, true); + } + } +} + diff --git a/wadsrc/static/zscript/ui/menu/loadsavemenu.zs b/wadsrc/static/zscript/engine/ui/menu/loadsavemenu.zs similarity index 90% rename from wadsrc/static/zscript/ui/menu/loadsavemenu.zs rename to wadsrc/static/zscript/engine/ui/menu/loadsavemenu.zs index eb9b7143612..e15ca266f4e 100644 --- a/wadsrc/static/zscript/ui/menu/loadsavemenu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/loadsavemenu.zs @@ -87,27 +87,24 @@ class LoadSaveMenu : ListMenu int listboxLeft; int listboxTop; int listboxWidth; - + int listboxRows; int listboxHeight; int listboxRight; - int listboxBottom; int commentLeft; int commentTop; int commentWidth; int commentHeight; - int commentRight; - int commentBottom; int commentRows; bool mEntering; TextEnterMenu mInput; double FontScale; - + BrokenLines BrokenSaveComment; - + //============================================================================= // @@ -120,35 +117,41 @@ class LoadSaveMenu : ListMenu Super.Init(parent, desc); manager = SavegameManager.GetManager(); manager.ReadSaveStrings(); + SetWindows(); + } + + private void SetWindows() + { + bool aspect43 = true; + int Width43 = screen.GetHeight() * 4 / 3; + int Left43 = (screen.GetWidth() - Width43) / 2; - savepicLeft = 10; - savepicTop = 54*CleanYfac; - savepicWidth = 216*screen.GetWidth() / 640; - savepicHeight = 135*screen.GetHeight() / 400; + double wScale = Width43 / 640.; + + savepicLeft = Left43 + int(20 * wScale); + savepicTop = int(mDesc.mYpos * screen.GetHeight() / 200); + savepicWidth = int(240 * wScale); + savepicHeight = int(180 * wScale); FontScale = max(screen.GetHeight() / 480, 1); rowHeight = int(max((NewConsoleFont.GetHeight() + 1) * FontScale, 1)); - - listboxLeft = savepicLeft + savepicWidth + 14; + + listboxLeft = savepicLeft + savepicWidth + int(20*wScale); listboxTop = savepicTop; - listboxWidth = screen.GetWidth() - listboxLeft - 10; - int listboxHeight1 = screen.GetHeight() - listboxTop - 10; + listboxWidth = Width43 + Left43 - listboxLeft - int(30 * wScale); + int listboxHeight1 = screen.GetHeight() - listboxTop - int(20*wScale); listboxRows = (listboxHeight1 - 1) / rowHeight; listboxHeight = listboxRows * rowHeight + 1; listboxRight = listboxLeft + listboxWidth; - listboxBottom = listboxTop + listboxHeight; commentLeft = savepicLeft; - commentTop = savepicTop + savepicHeight + 16; + commentTop = savepicTop + savepicHeight + int(16 * wScale); commentWidth = savepicWidth; - //commentHeight = (51+(screen.GetHeight()>200?10:0))*CleanYfac; - commentHeight = listboxHeight - savepicHeight - 16; - commentRight = commentLeft + commentWidth; - commentBottom = commentTop + commentHeight; + commentHeight = listboxHeight - savepicHeight - int(16 * wScale); commentRows = commentHeight / rowHeight; } - + //============================================================================= // // @@ -167,6 +170,12 @@ class LoadSaveMenu : ListMenu // //============================================================================= + virtual void DrawFrame(int left, int top, int width, int height) + { + let framecolor = Color(255, 80, 80, 80); + Screen.DrawLineFrame(framecolor, left, top, width, height, screen.GetHeight() / 240); + } + override void Drawer () { Super.Drawer(); @@ -182,24 +191,26 @@ class LoadSaveMenu : ListMenu return; } - Screen.DrawFrame (savepicLeft, savepicTop, savepicWidth, savepicHeight); + SetWindows(); + DrawFrame(savepicLeft, savepicTop, savepicWidth, savepicHeight); if (!manager.DrawSavePic(savepicLeft, savepicTop, savepicWidth, savepicHeight)) { - screen.Clear (savepicLeft, savepicTop, savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0); + screen.Dim(0, 0.6, savepicLeft, savepicTop, savepicWidth, savepicHeight); if (manager.SavegameCount() > 0) { + if (Selected >= manager.SavegameCount()) Selected = 0; String text = (Selected == -1 || !manager.GetSavegame(Selected).bOldVersion)? Stringtable.Localize("$MNU_NOPICTURE") : Stringtable.Localize("$MNU_DIFFVERSION"); - int textlen = NewSmallFont.StringWidth(text) * CleanXfac; + int textlen = NewSmallFont.StringWidth(text); - screen.DrawText (NewSmallFont, Font.CR_GOLD, savepicLeft+(savepicWidth-textlen)/2, - savepicTop+(savepicHeight-rowHeight)/2, text, DTA_CleanNoMove, true); + screen.DrawText (NewSmallFont, Font.CR_GOLD, (savepicLeft + savepicWidth / 2) / FontScale - textlen/2, + (savepicTop+(savepicHeight-rowHeight)/2) / FontScale, text, DTA_VirtualWidthF, screen.GetWidth() / FontScale, DTA_VirtualHeightF, screen.GetHeight() / FontScale, DTA_KeepRatio, true); } } // Draw comment area - Screen.DrawFrame (commentLeft, commentTop, commentWidth, commentHeight); - screen.Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0); + DrawFrame (commentLeft, commentTop, commentWidth, commentHeight); + screen.Dim(0, 0.6, commentLeft, commentTop, commentWidth, commentHeight); int numlinestoprint = min(commentRows, BrokenSaveComment? BrokenSaveComment.Count() : 0); for(int i = 0; i < numlinestoprint; i++) @@ -207,11 +218,11 @@ class LoadSaveMenu : ListMenu screen.DrawText(NewConsoleFont, Font.CR_ORANGE, commentLeft / FontScale, (commentTop + rowHeight * i) / FontScale, BrokenSaveComment.StringAt(i), DTA_VirtualWidthF, screen.GetWidth() / FontScale, DTA_VirtualHeightF, screen.GetHeight() / FontScale, DTA_KeepRatio, true); } - + // Draw file area - Screen.DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight); - screen.Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0); + DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight); + screen.Dim(0, 0.6, listboxLeft, listboxTop, listboxWidth, listboxHeight); if (manager.SavegameCount() == 0) { @@ -246,7 +257,7 @@ class LoadSaveMenu : ListMenu } screen.SetClipRect(listboxLeft, listboxTop+rowHeight*i, listboxRight, listboxTop+rowHeight*(i+1)); - + if (j == Selected) { screen.Clear (listboxLeft, listboxTop+rowHeight*i, listboxRight, listboxTop+rowHeight*(i+1), mEntering ? Color(255,255,0,0) : Color(255,0,0,255)); @@ -377,7 +388,7 @@ class LoadSaveMenu : ListMenu return Super.MenuEvent(mkey, fromcontroller); } } - + //============================================================================= // // @@ -411,8 +422,8 @@ class LoadSaveMenu : ListMenu return Super.MouseEvent(type, x, y); } - - + + //============================================================================= // // @@ -455,13 +466,13 @@ class LoadSaveMenu : ListMenu return Super.OnUIEvent(ev); } - + } class SaveMenu : LoadSaveMenu { String mSaveName; - + //============================================================================= // // @@ -497,7 +508,7 @@ class SaveMenu : LoadSaveMenu // // //============================================================================= - + override bool MenuEvent (int mkey, bool fromcontroller) { if (Super.MenuEvent(mkey, fromcontroller)) @@ -592,7 +603,7 @@ class SaveMenu : LoadSaveMenu mSaveName = ""; } } - + } //============================================================================= diff --git a/wadsrc/static/zscript/engine/ui/menu/menu.zs b/wadsrc/static/zscript/engine/ui/menu/menu.zs new file mode 100644 index 00000000000..7a0ef20368f --- /dev/null +++ b/wadsrc/static/zscript/engine/ui/menu/menu.zs @@ -0,0 +1,387 @@ +/* +** menu.zs +** The menu engine core +** +**--------------------------------------------------------------------------- +** Copyright 2010-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +**--------------------------------------------------------------------------- +** +*/ + + +struct KeyBindings native version("2.4") +{ + native static String NameKeys(int k1, int k2); + native static String NameAllKeys(array list, bool colors = true); + + native int, int GetKeysForCommand(String cmd); + native void GetAllKeysForCommand(out array list, String cmd); + native String GetBinding(int key); + + native void SetBind(int key, String cmd); + native void UnbindACommand (String str); +} + +struct OptionValues native version("2.4") +{ + native static int GetCount(Name group); + native static String GetText(Name group, int index); + native static double GetValue(Name group, int index); + native static String GetTextValue(Name group, int index); +} + +struct JoystickConfig native version("2.4") +{ + enum EJoyAxis + { + JOYAXIS_None = -1, + JOYAXIS_Yaw, + JOYAXIS_Pitch, + JOYAXIS_Forward, + JOYAXIS_Side, + JOYAXIS_Up, + // JOYAXIS_Roll, // Ha ha. No roll for you. + NUM_JOYAXIS, + }; + + native float GetSensitivity(); + native void SetSensitivity(float scale); + + native float GetAxisScale(int axis); + native void SetAxisScale(int axis, float scale); + + native float GetAxisDeadZone(int axis); + native void SetAxisDeadZone(int axis, float zone); + + native int GetAxisMap(int axis); + native void SetAxisMap(int axis, int gameaxis); + + native String GetName(); + native int GetNumAxes(); + native String GetAxisName(int axis); + + native bool GetEnabled(); + native void SetEnabled(bool enabled); + + native bool AllowsEnabledInBackground(); + native bool GetEnabledInBackground(); + native void SetEnabledInBackground(bool enabled); + +} + +class Menu : Object native ui version("2.4") +{ + enum EMenuKey + { + MKEY_Up, + MKEY_Down, + MKEY_Left, + MKEY_Right, + MKEY_PageUp, + MKEY_PageDown, + MKEY_Enter, + MKEY_Back, + MKEY_Clear, + NUM_MKEYS, + + // These are not buttons but events sent from other menus + + MKEY_Input, + MKEY_Abort, + MKEY_MBYes, + MKEY_MBNo, + } + + enum EMenuMouse + { + MOUSE_Click, + MOUSE_Move, + MOUSE_Release + }; + + enum EMenuState + { + Off, // Menu is closed + On, // Menu is opened + WaitKey, // Menu is opened and waiting for a key in the controls menu + OnNoPause, // Menu is opened but does not pause the game + }; + + native Menu mParentMenu; + native bool mMouseCapture; + native bool mBackbuttonSelected; + native bool DontDim; + native bool DontBlur; + native bool AnimatedTransition; + native bool Animated; + + native static int MenuTime(); + native static Menu GetCurrentMenu(); + native static clearscope void SetMenu(Name mnu, int param = 0); // This is not 100% safe but needs to be available - but always make sure to check that only the desired player opens it! + native static void StartMessage(String msg, int mode = 0, Name command = 'none'); + native static void SetMouseCapture(bool on); + native void Close(); + native void ActivateMenu(); + + //============================================================================= + // + // + // + //============================================================================= + + void Init(Menu parent) + { + mParentMenu = parent; + mMouseCapture = false; + mBackbuttonSelected = false; + DontDim = false; + DontBlur = false; + AnimatedTransition = false; + Animated = false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual bool MenuEvent (int mkey, bool fromcontroller) + { + switch (mkey) + { + case MKEY_Back: + { + Close(); + let m = GetCurrentMenu(); + MenuSound(m != null ? "menu/backup" : "menu/clear"); + if (!m) menuDelegate.MenuDismissed(); + return true; + } + } + return false; + } + + + //============================================================================= + // + // + // + //============================================================================= + + protected bool MouseEventBack(int type, int x, int y) + { + if (m_show_backbutton >= 0) + { + let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch); + if (tex.IsValid()) + { + Vector2 v = TexMan.GetScaledSize(tex); + int w = int(v.X + 0.5) * CleanXfac; + int h = int(v.Y + 0.5) * CleanYfac; + if (m_show_backbutton&1) x -= screen.GetWidth() - w; + if (m_show_backbutton&2) y -= screen.GetHeight() - h; + mBackbuttonSelected = ( x >= 0 && x < w && y >= 0 && y < h); + if (mBackbuttonSelected && type == MOUSE_Release) + { + if (m_use_mouse == 2) mBackbuttonSelected = false; + MenuEvent(MKEY_Back, true); + } + return mBackbuttonSelected; + } + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual bool OnUIEvent(UIEvent ev) + { + bool res = false; + int y = ev.MouseY; + if (ev.type == UIEvent.Type_LButtonDown) + { + res = MouseEventBack(MOUSE_Click, ev.MouseX, y); + // make the menu's mouse handler believe that the current coordinate is outside the valid range + if (res) y = -1; + res |= MouseEvent(MOUSE_Click, ev.MouseX, y); + if (res) + { + SetCapture(true); + } + + } + else if (ev.type == UIEvent.Type_MouseMove) + { + BackbuttonTime = 4*GameTicRate; + if (mMouseCapture || m_use_mouse == 1) + { + res = MouseEventBack(MOUSE_Move, ev.MouseX, y); + if (res) y = -1; + res |= MouseEvent(MOUSE_Move, ev.MouseX, y); + } + } + else if (ev.type == UIEvent.Type_LButtonUp) + { + if (mMouseCapture) + { + SetCapture(false); + res = MouseEventBack(MOUSE_Release, ev.MouseX, y); + if (res) y = -1; + res |= MouseEvent(MOUSE_Release, ev.MouseX, y); + } + } + return false; + } + + virtual bool OnInputEvent(InputEvent ev) + { + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual void Drawer () + { + if (self == GetCurrentMenu() && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse) + { + let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch); + if (tex.IsValid()) + { + Vector2 v = TexMan.GetScaledSize(tex); + int w = int(v.X + 0.5) * CleanXfac; + int h = int(v.Y + 0.5) * CleanYfac; + int x = (!(m_show_backbutton&1))? 0:screen.GetWidth() - w; + int y = (!(m_show_backbutton&2))? 0:screen.GetHeight() - h; + if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1)) + { + screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, Color(40, 255,255,255), DTA_NOOFFSET, true); + } + else + { + screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha, DTA_NOOFFSET, true); + } + } + } + } + + //============================================================================= + // + // + // + //============================================================================= + + void SetCapture(bool on) + { + if (mMouseCapture != on) + { + mMouseCapture = on; + SetMouseCapture(on); + } + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual bool TranslateKeyboardEvents() { return true; } + virtual void SetFocus(MenuItemBase fc) {} + virtual bool CheckFocus(MenuItemBase fc) { return false; } + virtual void ReleaseFocus() {} + virtual void ResetColor() {} + virtual bool MouseEvent(int type, int mx, int my) { return true; } + virtual void Ticker() {} + virtual void OnReturn() {} + + //============================================================================= + // + // + // + //============================================================================= + + static void MenuSound(Name snd) + { + menuDelegate.PlaySound(snd); + } + + deprecated("4.0") static void DrawConText (int color, int x, int y, String str) + { + screen.DrawText (ConFont, color, x, y, str, DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); + } + + static Font OptionFont() + { + return NewSmallFont; + } + + static int OptionHeight() + { + return OptionFont().GetHeight(); + } + + static int OptionWidth(String s, bool localize = true) + { + return OptionFont().StringWidth(s, localize); + } + + static void DrawOptionText(int x, int y, int color, String text, bool grayed = false, bool localize = true) + { + String label = localize ? Stringtable.Localize(text) : text; + int overlay = grayed? Color(96,48,0,0) : 0; + screen.DrawText (OptionFont(), color, x, y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, DTA_Localize, localize); + } + + +} + +class MenuDescriptor : Object native ui version("2.4") +{ + native Name mMenuName; + native String mNetgameMessage; + native Class mClass; + + native static MenuDescriptor GetDescriptor(Name n); +} + +// This class is only needed to give it a virtual Init method that doesn't belong to Menu itself +class GenericMenu : Menu +{ + virtual void Init(Menu parent) + { + Super.Init(parent); + } +} diff --git a/wadsrc/static/zscript/engine/ui/menu/menucustomize.zs b/wadsrc/static/zscript/engine/ui/menu/menucustomize.zs new file mode 100644 index 00000000000..390a2a703fe --- /dev/null +++ b/wadsrc/static/zscript/engine/ui/menu/menucustomize.zs @@ -0,0 +1,32 @@ +// This class allows global customization of certain menu aspects, e.g. replacing the menu caption. + +class MenuDelegateBase ui +{ + virtual int DrawCaption(String title, Font fnt, int y, bool drawit) + { + if (drawit) screen.DrawText(fnt, OptionMenuSettings.mTitleColor, (screen.GetWidth() - fnt.StringWidth(title) * CleanXfac_1) / 2, 10 * CleanYfac_1, title, DTA_CleanNoMove_1, true); + return (y + fnt.GetHeight()) * CleanYfac_1; // return is spacing in screen pixels. + } + + virtual void PlaySound(Name sound) + { + } + + virtual bool DrawSelector(ListMenuDescriptor desc) + { + return false; + } + + virtual void MenuDismissed() + { + // overriding this allows to execute special actions when the menu closes + } + + virtual Font PickFont(Font fnt) + { + if (generic_ui || !fnt) return NewSmallFont; + if (fnt == SmallFont) return AlternativeSmallFont; + if (fnt == BigFont) return AlternativeBigFont; + return fnt; + } +} diff --git a/wadsrc/static/zscript/ui/menu/menuitembase.zs b/wadsrc/static/zscript/engine/ui/menu/menuitembase.zs similarity index 96% rename from wadsrc/static/zscript/ui/menu/menuitembase.zs rename to wadsrc/static/zscript/engine/ui/menu/menuitembase.zs index 12b13556ced..2169e9fac68 100644 --- a/wadsrc/static/zscript/ui/menu/menuitembase.zs +++ b/wadsrc/static/zscript/engine/ui/menu/menuitembase.zs @@ -8,7 +8,7 @@ class MenuItemBase : Object native ui version("2.4") { protected native double mXpos, mYpos; protected native Name mAction; - native bool mEnabled; + native int mEnabled; void Init(double xpos = 0, double ypos = 0, Name actionname = 'None') { @@ -40,6 +40,7 @@ class MenuItemBase : Object native ui version("2.4") double GetY() { return mYpos; } double GetX() { return mXpos; } void SetX(double x) { mXpos = x; } + void SetY(double x) { mYpos = x; } virtual void OnMenuCreated() {} } diff --git a/wadsrc/static/zscript/ui/menu/messagebox.zs b/wadsrc/static/zscript/engine/ui/menu/messagebox.zs similarity index 90% rename from wadsrc/static/zscript/ui/menu/messagebox.zs rename to wadsrc/static/zscript/engine/ui/menu/messagebox.zs index 68e81192530..a49ff6f3f57 100644 --- a/wadsrc/static/zscript/ui/menu/messagebox.zs +++ b/wadsrc/static/zscript/engine/ui/menu/messagebox.zs @@ -68,7 +68,7 @@ class MessageBoxMenu : Menu if (SmallFont && SmallFont.CanPrint(message) && SmallFont.CanPrint("$TXT_YES") && SmallFont.CanPrint("$TXT_NO")) textFont = SmallFont; else if (OriginalSmallFont && OriginalSmallFont.CanPrint(message) && OriginalSmallFont.CanPrint("$TXT_YES") && OriginalSmallFont.CanPrint("$TXT_NO")) textFont = OriginalSmallFont; } - + if (!textFont) { arrowFont = textFont = NewSmallFont; @@ -79,7 +79,7 @@ class MessageBoxMenu : Menu } else { - arrowFont = ConFont; + arrowFont = ((textFont && textFont.GetGlyphHeight(0xd) > 0) ? textFont : ConFont); destWidth = CleanWidth; destHeight = CleanHeight; selector = "\xd"; @@ -89,7 +89,7 @@ class MessageBoxMenu : Menu int mr2 = destWidth/2 + 10 + textFont.StringWidth(Stringtable.Localize("$TXT_NO")); mMouseRight = MAX(mr1, mr2); mParentMenu = parent; - mMessage = textFont.BreakLines(Stringtable.Localize(message), generic_ui? 600 : 300); + mMessage = textFont.BreakLines(Stringtable.Localize(message), int(300/NotifyFontScale)); mMessageMode = messagemode; if (playsound) { @@ -97,7 +97,7 @@ class MessageBoxMenu : Menu } Handler = native_handler; } - + //============================================================================= // // @@ -106,8 +106,9 @@ class MessageBoxMenu : Menu override void Drawer () { - int i, y; - int fontheight = textFont.GetHeight(); + int i; + double y; + let fontheight = textFont.GetHeight() * NotifyFontScale; y = destHeight / 2; @@ -116,29 +117,30 @@ class MessageBoxMenu : Menu for (i = 0; i < c; i++) { - screen.DrawText (textFont, Font.CR_UNTRANSLATED, destWidth/2 - mMessage.StringWidth(i)/2, y, mMessage.StringAt(i), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); + screen.DrawText (textFont, Font.CR_UNTRANSLATED, destWidth/2 - mMessage.StringWidth(i)*NotifyFontScale/2, y, mMessage.StringAt(i), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true, + DTA_ScaleX, NotifyFontScale, DTA_ScaleY, NotifyFontScale); y += fontheight; } if (mMessageMode == 0) { y += fontheight; - mMouseY = y; - screen.DrawText(textFont, messageSelection == 0? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, destWidth / 2, y, Stringtable.Localize("$TXT_YES"), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); - screen.DrawText(textFont, messageSelection == 1? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, destWidth / 2, y + fontheight, Stringtable.Localize("$TXT_NO"), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); + mMouseY = int(y); + screen.DrawText(textFont, messageSelection == 0? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, destWidth / 2, y, Stringtable.Localize("$TXT_YES"), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true, DTA_ScaleX, NotifyFontScale, DTA_ScaleY, NotifyFontScale); + screen.DrawText(textFont, messageSelection == 1? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, destWidth / 2, y + fontheight, Stringtable.Localize("$TXT_NO"), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true, DTA_ScaleX, NotifyFontScale, DTA_ScaleY, NotifyFontScale); if (messageSelection >= 0) { if ((MenuTime() % 8) < 6) { screen.DrawText(arrowFont, OptionMenuSettings.mFontColorSelection, - destWidth/2 - 11, y + fontheight * messageSelection, selector, DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); + destWidth/2 - 3 - arrowFont.StringWidth(selector), y + fontheight * messageSelection, selector, DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); } } } } - + //============================================================================= // // @@ -225,7 +227,7 @@ class MessageBoxMenu : Menu } return Super.OnUIEvent(ev); } - + override bool OnInputEvent(InputEvent ev) { if (ev.type == InputEvent.Type_KeyDown) @@ -302,10 +304,6 @@ class MessageBoxMenu : Menu { sel = y >= mMouseY + fh; } - if (sel != -1 && sel != messageSelection) - { - //S_Sound (CHAN_VOICE, CHANF_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - } messageSelection = sel; if (type == MOUSE_Release) { diff --git a/wadsrc/static/zscript/ui/menu/optionmenu.zs b/wadsrc/static/zscript/engine/ui/menu/optionmenu.zs similarity index 87% rename from wadsrc/static/zscript/ui/menu/optionmenu.zs rename to wadsrc/static/zscript/engine/ui/menu/optionmenu.zs index 1a27b82651e..7338885bf94 100644 --- a/wadsrc/static/zscript/ui/menu/optionmenu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/optionmenu.zs @@ -55,6 +55,9 @@ class OptionMenuDescriptor : MenuDescriptor native native int mIndent; native int mPosition; native bool mDontDim; + native bool mDontBlur; + native bool mAnimatedTransition; + native bool mAnimated; native Font mFont; void Reset() @@ -65,7 +68,7 @@ class OptionMenuDescriptor : MenuDescriptor native mIndent = 0; mDontDim = 0; } - + //============================================================================= // // @@ -106,6 +109,9 @@ class OptionMenu : Menu mParentMenu = parent; mDesc = desc; DontDim = desc.mDontDim; + DontBlur = desc.mDontBlur; + AnimatedTransition = desc.mAnimatedTransition; + Animated = desc.mAnimated; let itemCount = mDesc.mItems.size(); if (itemCount > 0) @@ -133,7 +139,7 @@ class OptionMenu : Menu } } - + //============================================================================= // // @@ -149,7 +155,7 @@ class OptionMenu : Menu } return NULL; } - + //============================================================================= // @@ -193,7 +199,7 @@ class OptionMenu : Menu mDesc.mScrollPos += 2; VisBottom += 2; } - else + else if (VisBottom < mDesc.mItems.Size()-1) { mDesc.mScrollPos++; VisBottom++; @@ -201,6 +207,30 @@ class OptionMenu : Menu } return true; } + else if (ev.type == UIEvent.Type_Char) + { + int key = String.CharLower(ev.keyChar); + int itemsNumber = mDesc.mItems.Size(); + int direction = ev.IsAlt ? -1 : 1; + for (int i = 0; i < itemsNumber; ++i) + { + int index = (mDesc.mSelectedItem + direction * (i + 1) + itemsNumber) % itemsNumber; + if (!mDesc.mItems[index].Selectable()) continue; + String label = StringTable.Localize(mDesc.mItems[index].mLabel); + int firstLabelCharacter = String.CharLower(label.GetNextCodePoint(0)); + if (firstLabelCharacter == key) + { + mDesc.mSelectedItem = index; + break; + } + } + if (mDesc.mSelectedItem <= mDesc.mScrollTop + mDesc.mScrollPos + || mDesc.mSelectedItem > VisBottom) + { + int pagesize = VisBottom - mDesc.mScrollPos - mDesc.mScrollTop; + mDesc.mScrollPos = clamp(mDesc.mSelectedItem - mDesc.mScrollTop - 1, 0, mDesc.mItems.size() - pagesize - 1); + } + } return Super.OnUIEvent(ev); } @@ -239,17 +269,8 @@ class OptionMenu : Menu if (y <= 0) { - let font = generic_ui || !mDesc.mFont? NewSmallFont : mDesc.mFont; - if (font && mDesc.mTitle.Length() > 0) - { - y = -y + font.GetHeight(); - } - else - { - y = -y; - } + y = DrawCaption(mDesc.mTitle, -y, false); } - y *= CleanYfac_1; int rowheight = OptionMenuSettings.mLinespacing * CleanYfac_1; int maxitems = (screen.GetHeight() - rowheight - y) / rowheight + 1; @@ -269,7 +290,7 @@ class OptionMenu : Menu do { ++mDesc.mSelectedItem; - + if (CanScrollDown && mDesc.mSelectedItem == VisBottom) { mDesc.mScrollPos++; @@ -365,7 +386,7 @@ class OptionMenu : Menu return true; } - + //============================================================================= // // @@ -393,7 +414,6 @@ class OptionMenu : Menu if (yline != mDesc.mSelectedItem) { mDesc.mSelectedItem = yline; - //S_Sound (CHAN_VOICE, CHANF_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); } mDesc.mItems[yline].MouseEvent(type, x, y); return true; @@ -403,7 +423,7 @@ class OptionMenu : Menu return Super.MouseEvent(type, x, y); } - + //============================================================================= // // @@ -418,7 +438,7 @@ class OptionMenu : Menu mDesc.mItems[i].Ticker(); } } - + //============================================================================= // // @@ -431,29 +451,42 @@ class OptionMenu : Menu return screen.GetWidth() / 2 + indent * CleanXfac_1; } + //============================================================================= + // + // draws and/or measures the caption. + // + //============================================================================= + + virtual int DrawCaption(String title, int y, bool drawit) + { + let font = menuDelegate.PickFont(mDesc.mFont); + if (font && mDesc.mTitle.Length() > 0) + { + return menuDelegate.DrawCaption(title, font, y, drawit); + } + else + { + return y; + } + + } + + //============================================================================= + // + // + // + //============================================================================= + override void Drawer () { int y = mDesc.mPosition; if (y <= 0) { - let font = generic_ui || !mDesc.mFont? NewSmallFont : mDesc.mFont; - if (font && mDesc.mTitle.Length() > 0) - { - let tt = Stringtable.Localize(mDesc.mTitle); - screen.DrawText (font, OptionMenuSettings.mTitleColor, - (screen.GetWidth() - font.StringWidth(tt) * CleanXfac_1) / 2, 10*CleanYfac_1, - tt, DTA_CleanNoMove_1, true); - y = -y + font.GetHeight(); - } - else - { - y = -y; - } + y = DrawCaption(mDesc.mTitle, -y, true); } - mDesc.mDrawTop = y; + mDesc.mDrawTop = y / CleanYfac_1; // mouse checks are done in clean space. int fontheight = OptionMenuSettings.mLinespacing * CleanYfac_1; - y *= CleanYfac_1; int indent = GetIndent(); @@ -506,12 +539,12 @@ class OptionMenu : Menu { mFocusControl = OptionMenuItem(fc); } - + override bool CheckFocus(MenuItemBase fc) { return mFocusControl == fc; } - + override void ReleaseFocus() { mFocusControl = NULL; @@ -519,32 +552,6 @@ class OptionMenu : Menu } -class GameplayMenu : OptionMenu -{ - override void Drawer () - { - Super.Drawer(); - - String s = String.Format("dmflags = %d dmflags2 = %d", dmflags, dmflags2); - screen.DrawText (OptionFont(), OptionMenuSettings.mFontColorValue, - (screen.GetWidth() - OptionWidth (s) * CleanXfac_1) / 2, 35 * CleanXfac_1, s, - DTA_CleanNoMove_1, true); - } -} - -class CompatibilityMenu : OptionMenu -{ - override void Drawer () - { - Super.Drawer(); - - String s = String.Format("compatflags = %d compatflags2 = %d", compatflags, compatflags2); - screen.DrawText (OptionFont(), OptionMenuSettings.mFontColorValue, - (screen.GetWidth() - OptionWidth (s) * CleanXfac_1) / 2, 35 * CleanXfac_1, s, - DTA_CleanNoMove_1, true); - } -} - class GLTextureGLOptions : OptionMenu { private int mWarningIndex; diff --git a/wadsrc/static/zscript/ui/menu/optionmenuitems.zs b/wadsrc/static/zscript/engine/ui/menu/optionmenuitems.zs similarity index 86% rename from wadsrc/static/zscript/ui/menu/optionmenuitems.zs rename to wadsrc/static/zscript/engine/ui/menu/optionmenuitems.zs index 0c7c9bb2be1..9fc0d66ffe3 100644 --- a/wadsrc/static/zscript/ui/menu/optionmenuitems.zs +++ b/wadsrc/static/zscript/engine/ui/menu/optionmenuitems.zs @@ -36,23 +36,27 @@ class OptionMenuItem : MenuItemBase { String mLabel; bool mCentered; - - protected void Init(String label, String command, bool center = false) + CVar mGrayCheck; + int mGrayCheckVal; + + protected void Init(String label, String command, bool center = false, CVar graycheck = null, int graycheckVal = 0) { Super.Init(0, 0, command); mLabel = label; mCentered = center; + mGrayCheck = graycheck; + mGrayCheckVal = graycheckVal; } protected void drawText(int x, int y, int color, String text, bool grayed = false) { Menu.DrawOptionText(x, y, color, text, grayed); } - + protected int drawLabel(int indent, int y, int color, bool grayed = false) { String label = Stringtable.Localize(mLabel); - + int x; int w = Menu.OptionWidth(label) * CleanXfac_1; if (!mCentered) x = indent - w; @@ -61,31 +65,35 @@ class OptionMenuItem : MenuItemBase return x; } - protected void drawValue(int indent, int y, int color, String text, bool grayed = false) + protected void drawValue(int indent, int y, int color, String text, bool grayed = false, bool localize = true) { - Menu.DrawOptionText(indent + CursorSpace(), y, color, text, grayed); + Menu.DrawOptionText(indent + CursorSpace(), y, color, text, grayed, localize); } - int CursorSpace() { return (14 * CleanXfac_1); } - + + virtual bool IsGrayed() + { + return mGrayCheck != null && mGrayCheck.GetInt() == mGrayCheckVal; + } + override bool Selectable() { return true; } - + override int GetIndent() { if (mCentered) return 0; if (screen.GetWidth() < 640) return screen.GetWidth() / 2; return Menu.OptionWidth(Stringtable.Localize(mLabel)); } - + override bool MouseEvent(int type, int x, int y) -{ + { if (Selectable() && type == Menu.MOUSE_Release) { return Menu.GetCurrentMenu().MenuEvent(Menu.MKEY_Enter, true); @@ -122,7 +130,7 @@ class OptionMenuItemSubmenu : OptionMenuItem override bool Activate() { - Menu.MenuSound("menu/choose"); + Menu.MenuSound("menu/advance"); Menu.SetMenu(mAction, mParam); return true; } @@ -147,7 +155,7 @@ class OptionMenuItemLabeledSubmenu : OptionMenuItemSubmenu override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor); - + String text = mLabelCVar.GetString(); if (text.Length() == 0) text = Stringtable.Localize("$notset"); drawValue(indent, y, OptionMenuSettings.mFontColorValue, text); @@ -166,7 +174,7 @@ class OptionMenuItemCommand : OptionMenuItemSubmenu private String ccmd; // do not allow access to this from the outside. bool mCloseOnSelect; private bool mUnsafe; - + OptionMenuItemCommand Init(String label, Name command, bool centered = false, bool closeonselect = false) { Super.Init(label, command, 0, centered); @@ -253,16 +261,14 @@ class OptionMenuItemOptionBase : OptionMenuItem { // command is a CVAR Name mValues; // Entry in OptionValues table - CVar mGrayCheck; int mCenter; - + const OP_VALUES = 0x11001; - protected void Init(String label, Name command, Name values, CVar graycheck, int center) + protected void Init(String label, Name command, Name values, CVar graycheck, int center, int graycheckVal = 0) { - Super.Init(label, command); + Super.Init(label, command, false, graycheck, graycheckVal); mValues = values; - mGrayCheck = graycheck; mCenter = center; } @@ -288,11 +294,11 @@ class OptionMenuItemOptionBase : OptionMenuItem { return 0; } - + virtual void SetSelection(int Selection) { } - + //============================================================================= override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { @@ -304,7 +310,7 @@ class OptionMenuItemOptionBase : OptionMenuItem int Selection = GetSelection(); String text = StringTable.Localize(OptionValues.GetText(mValues, Selection)); - if (text.Length() == 0) text = "Unknown"; + if (text.Length() == 0) text = StringTable.Localize("$TXT_UNKNOWN"); drawValue(indent, y, OptionMenuSettings.mFontColorValue, text, isGrayed()); return indent; } @@ -338,11 +344,6 @@ class OptionMenuItemOptionBase : OptionMenuItem } return true; } - - virtual bool isGrayed() - { - return mGrayCheck != null && !mGrayCheck.GetInt(); - } override bool Selectable() { @@ -360,10 +361,13 @@ class OptionMenuItemOption : OptionMenuItemOptionBase { CVar mCVar; - OptionMenuItemOption Init(String label, Name command, Name values, CVar graycheck = null, int center = 0) + private static native void SetCVarDescription(CVar cv, String label); + + OptionMenuItemOption Init(String label, Name command, Name values, CVar graycheck = null, int center = 0, int graycheckVal = 0) { - Super.Init(label, command, values, graycheck, center); + Super.Init(label, command, values, graycheck, center, graycheckVal); mCVar = CVar.FindCVar(mAction); + if (mCVar) SetCVarDescription(mCVar, label); return self; } @@ -465,7 +469,7 @@ class EnterKey : Menu menuactive = Menu.On; SetMenuMessage(0); Close(); - mParentMenu.MenuEvent((ev.KeyScan == InputEvent.KEY_ESCAPE)? Menu.MKEY_Abort : Menu.MKEY_Input, 0); + mParentMenu.MenuEvent((ev.KeyScan == InputEvent.KEY_ESCAPE) || (ev.KeyScan == InputEvent.KEY_JOY2) ? Menu.MKEY_Abort : Menu.MKEY_Input, 0); return true; } return false; @@ -499,14 +503,14 @@ class OptionMenuItemControlBase : OptionMenuItem //============================================================================= override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { - drawLabel(indent, y, mWaiting? OptionMenuSettings.mFontColorHighlight: - (selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor)); + drawLabel(indent, y, mWaiting ? OptionMenuSettings.mFontColorHighlight : + (selected ? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor)); String description; - int Key1, Key2; + Array keys; - [Key1, Key2] = mBindings.GetKeysForCommand(mAction); - description = KeyBindings.NameKeys (Key1, Key2); + mBindings.GetAllKeysForCommand(keys, mAction); + description = KeyBindings.NameAllKeys(keys); if (description.Length() > 0) { drawValue(indent, y, Font.CR_WHITE, description); @@ -539,7 +543,7 @@ class OptionMenuItemControlBase : OptionMenuItem } return false; } - + void SendKey(int key) { mInput = key; @@ -697,9 +701,9 @@ class OptionMenuSliderBase : OptionMenuItem int mDrawX; int mSliderShort; - protected void Init(String label, double min, double max, double step, int showval, Name command = 'none') + protected void Init(String label, double min, double max, double step, int showval, Name command = 'none', CVar graycheck = NULL, int graycheckVal = 0) { - Super.Init(label, command); + Super.Init(label, command, false, graycheck, graycheckVal); mMin = min; mMax = max; mStep = step; @@ -712,23 +716,29 @@ class OptionMenuSliderBase : OptionMenuItem { return 0; } - + virtual void SetSliderValue(double val) { } + override bool Selectable(void) + { + return !IsGrayed(); + } + //============================================================================= // // Draw a slider. Set fracdigits negative to not display the current value numerically. // //============================================================================= - private void DrawSliderElement (int color, int x, int y, String str) + private void DrawSliderElement (int color, int x, int y, String str, bool grayed = false) { - screen.DrawText (ConFont, color, x, y, str, DTA_CellX, 16 * CleanXfac_1, DTA_CellY, 16 * CleanYfac_1); + int overlay = grayed? Color(96, 48, 0, 0) : 0; + screen.DrawText (ConFont, color, x, y, str, DTA_CellX, 16 * CleanXfac_1, DTA_CellY, 16 * CleanYfac_1, DTA_ColorOverlay, overlay); } - protected void DrawSlider (int x, int y, double min, double max, double cur, int fracdigits, int indent) + protected void DrawSlider (int x, int y, double min, double max, double cur, int fracdigits, int indent, bool grayed = false) { String formater = String.format("%%.%df", fracdigits); // The format function cannot do the '%.*f' syntax. String textbuf; @@ -750,21 +760,21 @@ class OptionMenuSliderBase : OptionMenuItem if (!mSliderShort) { - DrawSliderElement(Font.CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12"); - DrawSliderElement(Font.FindFontColor(gameinfo.mSliderColor), x + int((5 + ((ccur * 78) / range)) * 2 * CleanXfac_1), cy, "\x13"); + DrawSliderElement(Font.FindFontColor(gameinfo.mSliderBackColor), x, cy, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12", grayed); + DrawSliderElement(Font.FindFontColor(gameinfo.mSliderColor), x + int((5 + ((ccur * 78) / range)) * 2 * CleanXfac_1), cy, "\x13", grayed); } else { // On 320x200 we need a shorter slider - DrawSliderElement(Font.CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x12"); - DrawSliderElement(Font.FindFontColor(gameinfo.mSliderColor), x + int((5 + ((ccur * 38) / range)) * 2 * CleanXfac_1), cy, "\x13"); + DrawSliderElement(Font.FindFontColor(gameinfo.mSliderBackColor), x, cy, "\x10\x11\x11\x11\x11\x11\x12", grayed); + DrawSliderElement(Font.FindFontColor(gameinfo.mSliderColor), x + int((5 + ((ccur * 38) / range)) * 2 * CleanXfac_1), cy, "\x13", grayed); right -= 5*8*CleanXfac; } if (fracdigits >= 0 && right + maxlen <= screen.GetWidth()) { textbuf = String.format(formater, cur); - drawText(right, y, Font.CR_DARKGRAY, textbuf); + drawText(right, y, Font.CR_DARKGRAY, textbuf, grayed); } } @@ -772,9 +782,9 @@ class OptionMenuSliderBase : OptionMenuItem //============================================================================= override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { - drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor); + drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, IsGrayed()); mDrawX = indent + CursorSpace(); - DrawSlider (mDrawX, y, mMin, mMax, GetSliderValue(), mShowValue, indent); + DrawSlider (mDrawX, y, mMin, mMax, GetSliderValue(), mShowValue, indent, IsGrayed()); return indent; } @@ -846,10 +856,10 @@ class OptionMenuSliderBase : OptionMenuItem class OptionMenuItemSlider : OptionMenuSliderBase { CVar mCVar; - - OptionMenuItemSlider Init(String label, Name command, double min, double max, double step, int showval = 1) + + OptionMenuItemSlider Init(String label, Name command, double min, double max, double step, int showval = 1, CVar graycheck = NULL, int graycheckVal = 0) { - Super.Init(label, min, max, step, showval, command); + Super.Init(label, min, max, step, showval, command, graycheck, graycheckVal); mCVar =CVar.FindCVar(command); return self; } @@ -887,9 +897,9 @@ class OptionMenuItemColorPicker : OptionMenuItem const CPF_RESET = 0x20001; - OptionMenuItemColorPicker Init(String label, Name command) + OptionMenuItemColorPicker Init(String label, Name command, CVar graycheck = null, int graycheckVal = 0) { - Super.Init(label, command); + Super.Init(label, command, false, graycheck, graycheckVal); CVar cv = CVar.FindCVar(command); if (cv != null && cv.GetRealType() != CVar.CVAR_Color) cv = null; mCVar = cv; @@ -899,7 +909,7 @@ class OptionMenuItemColorPicker : OptionMenuItem //============================================================================= override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { - drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor); + drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, isGrayed()); if (mCVar != null) { @@ -925,11 +935,11 @@ class OptionMenuItemColorPicker : OptionMenuItem if (mCVar != null) { Menu.MenuSound("menu/choose"); - + // This code is a bit complicated because it should allow subclassing the // colorpicker menu. // New color pickers must inherit from the internal one to work here. - + let desc = MenuDescriptor.GetDescriptor('Colorpickermenu'); if (desc != NULL && (desc.mClass == null || desc.mClass is "ColorPickerMenu")) { @@ -947,6 +957,11 @@ class OptionMenuItemColorPicker : OptionMenuItem } return false; } + + override bool Selectable() + { + return !isGrayed(); + } } //============================================================================= @@ -959,11 +974,12 @@ class OptionMenuItemColorPicker : OptionMenuItem class OptionMenuFieldBase : OptionMenuItem { - void Init (String label, Name command, CVar graycheck = null) + CVar mCVar; + + void Init (String label, Name command, CVar graycheck = null, int graycheckVal = 0) { - Super.Init(label, command); + Super.Init(label, command, false, graycheck, graycheckVal); mCVar = CVar.FindCVar(mAction); - mGrayCheck = graycheck; } String GetCVarString() @@ -981,9 +997,8 @@ class OptionMenuFieldBase : OptionMenuItem override int Draw (OptionMenuDescriptor d, int y, int indent, bool selected) { - bool grayed = mGrayCheck != null && !mGrayCheck.GetInt(); - drawLabel(indent, y, selected ? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, grayed); - drawValue(indent, y, OptionMenuSettings.mFontColorValue, Represent(), grayed); + drawLabel(indent, y, selected ? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, isGrayed()); + drawValue(indent, y, OptionMenuSettings.mFontColorValue, Represent(), isGrayed(), false); return indent; } @@ -1006,9 +1021,10 @@ class OptionMenuFieldBase : OptionMenuItem return false; } - - CVar mCVar; - CVar mGrayCheck; + override bool Selectable() + { + return !isGrayed(); + } } //============================================================================= @@ -1022,10 +1038,10 @@ class OptionMenuFieldBase : OptionMenuItem class OptionMenuItemTextField : OptionMenuFieldBase { TextEnterMenu mEnter; - - OptionMenuItemTextField Init (String label, Name command, CVar graycheck = null) + + OptionMenuItemTextField Init (String label, Name command, CVar graycheck = null, int graycheckVal = 0) { - Super.Init(label, command, graycheck); + Super.Init(label, command, graycheck, graycheckVal); mEnter = null; return self; } @@ -1048,7 +1064,7 @@ class OptionMenuItemTextField : OptionMenuFieldBase { // reposition the text so that the cursor is visible when in entering mode. String text = Represent(); - int tlen = Menu.OptionWidth(text) * CleanXfac_1; + int tlen = Menu.OptionWidth(text, false) * CleanXfac_1; int newindent = screen.GetWidth() - tlen - CursorSpace(); if (newindent < indent) indent = newindent; } @@ -1095,9 +1111,9 @@ class OptionMenuItemTextField : OptionMenuFieldBase class OptionMenuItemNumberField : OptionMenuFieldBase { - OptionMenuItemNumberField Init (String label, Name command, float minimum = 0, float maximum = 100, float step = 1, CVar graycheck = null) + OptionMenuItemNumberField Init (String label, Name command, float minimum = 0, float maximum = 100, float step = 1, CVar graycheck = null, int graycheckVal = 0) { - Super.Init(label, command, graycheck); + Super.Init(label, command, graycheck, graycheckVal); mMinimum = min(minimum, maximum); mMaximum = max(minimum, maximum); mStep = max(1, step); @@ -1110,7 +1126,6 @@ class OptionMenuItemNumberField : OptionMenuFieldBase return String.format("%.3f", mCVar.GetFloat()); } - override bool MenuEvent (int mkey, bool fromcontroller) { if (mCVar) @@ -1155,10 +1170,10 @@ class OptionMenuItemScaleSlider : OptionMenuItemSlider String TextZero; String TextNegOne; int mClickVal; - - OptionMenuItemScaleSlider Init(String label, Name command, double min, double max, double step, String zero, String negone = "") + + OptionMenuItemScaleSlider Init(String label, Name command, double min, double max, double step, String zero, String negone = "", CVar graycheck = null, int graycheckVal = 0) { - Super.Init(label, command, min, max, step, 0); + Super.Init(label, command, min, max, step, 0, graycheck, graycheckVal); mCVar =CVar.FindCVar(command); TextZero = zero; TextNEgOne = negone; @@ -1175,16 +1190,16 @@ class OptionMenuItemScaleSlider : OptionMenuItemSlider if ((Selection == 0 || Selection == -1) && mClickVal <= 0) { String text = Selection == 0? TextZero : Selection == -1? TextNegOne : ""; - drawValue(indent, y, OptionMenuSettings.mFontColorValue, text); + drawValue(indent, y, OptionMenuSettings.mFontColorValue, text, isGrayed()); } else { mDrawX = indent + CursorSpace(); - DrawSlider (mDrawX, y, mMin, mMax, GetSliderValue(), mShowValue, indent); + DrawSlider (mDrawX, y, mMin, mMax, GetSliderValue(), mShowValue, indent, isGrayed()); } return indent; } - + override bool MouseEvent(int type, int x, int y) { int value = int(GetSliderValue()); @@ -1194,11 +1209,11 @@ class OptionMenuItemScaleSlider : OptionMenuItemSlider mClickVal = value; if (value <= 0) return false; return Super.MouseEvent(type, x, y); - + case Menu.MOUSE_Move: if (mClickVal <= 0) return false; return Super.MouseEvent(type, x, y); - + case Menu.MOUSE_Release: if (mClickVal <= 0) { @@ -1211,45 +1226,68 @@ class OptionMenuItemScaleSlider : OptionMenuItemSlider } return false; } - + } //============================================================================= // -// Placeholder classes for overhauled video mode menu. Do not use! -// Their sole purpose is to support mods with full copy of embedded MENUDEF +// Flag option by Accensus // //============================================================================= -class OptionMenuItemScreenResolution : OptionMenuItem +class OptionMenuItemFlagOption : OptionMenuItemOption { - String mResTexts[3]; - int mSelection; - int mHighlight; - int mMaxValid; + int mBitShift; - enum EValues + OptionMenuItemFlagOption Init(String label, Name command, Name values, int bitShift, CVar greycheck = null, int center = 0, int graycheckVal = 0) { - SRL_INDEX = 0x30000, - SRL_SELECTION = 0x30003, - SRL_HIGHLIGHT = 0x30004, - }; + Super.Init(label, command, values, greycheck, center, graycheckVal); + mBitShift = bitShift; - OptionMenuItemScreenResolution Init(String command) - { return self; } - override bool Selectable() + override int GetSelection() { - return false; + int Selection = 0; + int cnt = OptionValues.GetCount(mValues); + if (cnt > 0 && mCVar != null) + { + if (OptionValues.GetTextValue(mValues, 0).Length() == 0) + { + int CurrentFlags = mCVar.GetInt(); + + for (int i = 0; i < cnt; i++) + { + int OptionValue = int(OptionValues.GetValue(mValues, i)); + if (CurrentFlags & (OptionValue << mBitShift)) + { + Selection = i; + break; + } + } + } + } + return Selection; } -} -class VideoModeMenu : OptionMenu -{ - static bool SetSelectedSize() + override void SetSelection(int Selection) { - return false; + int cnt = OptionValues.GetCount(mValues); + if (cnt > 0 && mCVar != null) + { + if (OptionValues.GetTextValue(mValues, 0).Length() == 0) + { + int OptionValue = int(OptionValues.GetValue(mValues, Selection)); + int CurrentFlags = mCVar.GetInt(); + + switch (OptionValue) + { + case 0: CurrentFlags &= ~(1 << mBitShift); break; + case 1: CurrentFlags |= (1 << mBitShift); break; + } + mCVar.SetInt(CurrentFlags); + } + } } } diff --git a/wadsrc/static/zscript/ui/menu/reverbedit.zs b/wadsrc/static/zscript/engine/ui/menu/reverbedit.zs similarity index 99% rename from wadsrc/static/zscript/ui/menu/reverbedit.zs rename to wadsrc/static/zscript/engine/ui/menu/reverbedit.zs index 65fa5158e37..282fce55d0a 100644 --- a/wadsrc/static/zscript/ui/menu/reverbedit.zs +++ b/wadsrc/static/zscript/engine/ui/menu/reverbedit.zs @@ -15,14 +15,14 @@ class ReverbEdit : OptionMenu super.Init(parent, desc); OnReturn(); } - + override void OnReturn() { string env; int id; - + [env, id] = GetSelectedEnvironment(); - + let li = GetItem('EvironmentName'); if (li != NULL) { @@ -126,7 +126,7 @@ class OptionMenuItemReverbSelect : OptionMenuItemSubMenu return self; } - + override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { int x = drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor); @@ -164,7 +164,7 @@ class OptionMenuItemReverbOption : OptionMenuItemOptionBase { return int(ReverbEdit.GetValue(mValIndex)); } - + override void SetSelection(int Selection) { ReverbEdit.SetValue(mValIndex, Selection); @@ -182,7 +182,7 @@ class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase int mValIndex; String mEditValue; TextEnterMenu mEnter; - + OptionMenuItemSliderReverbEditOption Init(String label, double min, double max, double step, int showval, int valindex) { Super.Init(label, min, max, step, showval); @@ -190,7 +190,7 @@ class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase mEnter = null; return self; } - + override double GetSliderValue() { @@ -201,7 +201,7 @@ class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase { ReverbEdit.SetValue(mValIndex, val); } - + override bool Selectable() { return !ReverbEdit.GrayCheck(); @@ -228,7 +228,7 @@ class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase } return indent; } - + override bool MenuEvent (int mkey, bool fromcontroller) { if (mkey == Menu.MKEY_Enter) @@ -253,6 +253,6 @@ class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase return Super.MenuEvent(mkey, fromcontroller); } - + } diff --git a/wadsrc/static/zscript/ui/menu/search/anyoralloption.zs b/wadsrc/static/zscript/engine/ui/menu/search/anyoralloption.zs similarity index 100% rename from wadsrc/static/zscript/ui/menu/search/anyoralloption.zs rename to wadsrc/static/zscript/engine/ui/menu/search/anyoralloption.zs diff --git a/wadsrc/static/zscript/engine/ui/menu/search/menu.zs b/wadsrc/static/zscript/engine/ui/menu/search/menu.zs new file mode 100644 index 00000000000..17a8a21d327 --- /dev/null +++ b/wadsrc/static/zscript/engine/ui/menu/search/menu.zs @@ -0,0 +1,229 @@ +//============================================================================= +// +// Option Search Menu class. +// This menu contains search field, and is dynamically filled with search +// results. +// +//============================================================================= + +class os_Menu : OptionMenu +{ + override void Init(Menu parent, OptionMenuDescriptor desc) + { + Super.Init(parent, desc); + + mDesc.mItems.clear(); + + addSearchField(); + + mDesc.mScrollPos = 0; + mDesc.mSelectedItem = 0; + mDesc.CalcIndent(); + } + + void search() + { + string text = mSearchField.GetText(); + let query = os_Query.fromString(text); + bool isAnyTermMatches = mIsAnyOfItem.mCVar.GetBool(); + + mDesc.mItems.clear(); + + addSearchField(text); + + Dictionary searchedMenus = Dictionary.Create(); + bool found = listOptions(mDesc, "MainMenu", query, "", isAnyTermMatches, searchedMenus); + + if (!found) { addNoResultsItem(mDesc); } + + mDesc.CalcIndent(); + } + + private void addSearchField(string query = "") + { + string searchLabel = StringTable.Localize("$OS_LABEL"); + + mSearchField = new("os_SearchField").Init(searchLabel, self, query); + mIsAnyOfItem = new("os_AnyOrAllOption").Init(self); + + mDesc.mItems.push(mSearchField); + mDesc.mItems.push(mIsAnyOfItem); + addEmptyLine(mDesc); + } + + private static bool listOptions(OptionMenuDescriptor targetDesc, + string menuName, + os_Query query, + string path, + bool isAnyTermMatches, + Dictionary searchedMenus) + { + if (searchedMenus.At(menuName).length() > 0) + { + return false; + } + + searchedMenus.Insert(menuName, "1"); + + let desc = MenuDescriptor.GetDescriptor(menuName); + let listMenuDesc = ListMenuDescriptor(desc); + + if (listMenuDesc) + { + return listOptionsListMenu(listMenuDesc, targetDesc, query, path, isAnyTermMatches, searchedMenus); + } + + let optionMenuDesc = OptionMenuDescriptor(desc); + + if (optionMenuDesc) + { + return listOptionsOptionMenu(optionMenuDesc, targetDesc, query, path, isAnyTermMatches, searchedMenus); + } + + return false; + } + + private static bool listOptionsListMenu(ListMenuDescriptor sourceDesc, + OptionMenuDescriptor targetDesc, + os_Query query, + string path, + bool isAnyTermMatches, + Dictionary searchedMenus) + { + int nItems = sourceDesc.mItems.size(); + bool found = false; + + for (int i = 0; i < nItems; ++i) + { + let item = sourceDesc.mItems[i]; + string actionN = item.GetAction(); + let textItem = ListMenuItemTextItem(item); + string newPath = textItem + ? makePath(path, StringTable.Localize(textItem.mText)) + : path; + + found |= listOptions(targetDesc, actionN, query, newPath, isAnyTermMatches, searchedMenus); + } + + return found; + } + + private static bool listOptionsOptionMenu(OptionMenuDescriptor sourceDesc, + OptionMenuDescriptor targetDesc, + os_Query query, + string path, + bool isAnyTermMatches, + Dictionary searchedMenus) + { + if (sourceDesc == targetDesc) { return false; } + + int nItems = sourceDesc.mItems.size(); + bool first = true; + bool found = false; + + for (int i = 0; i < nItems; ++i) + { + let item = sourceDesc.mItems[i]; + + if (item is "OptionMenuItemStaticText") { continue; } + + string label = StringTable.Localize(item.mLabel); + + if (!query.matches(label, isAnyTermMatches)) { continue; } + + found = true; + + if (first) + { + addEmptyLine(targetDesc); + addPathItem(targetDesc, path); + + first = false; + } + + let itemOptionBase = OptionMenuItemOptionBase(item); + + if (itemOptionBase) + { + itemOptionBase.mCenter = false; + } + + targetDesc.mItems.push(item); + } + + for (int i = 0; i < nItems; ++i) + { + let item = sourceDesc.mItems[i]; + string label = StringTable.Localize(item.mLabel); + string optionSearchTitle = StringTable.Localize("$OS_TITLE"); + + if (label == optionSearchTitle) { continue; } + + if (item is "OptionMenuItemSubMenu") + { + string newPath = makePath(path, label); + + found |= listOptions(targetDesc, item.GetAction(), query, newPath, isAnyTermMatches, searchedMenus); + } + } + + return found; + } + + private static string makePath(string path, string label) + { + if (path.length() == 0) { return label; } + + int pathWidth = SmallFont.StringWidth(path .. "/" .. label); + int screenWidth = Screen.GetWidth(); + bool isTooWide = (pathWidth > screenWidth / 3); + string newPath = isTooWide + ? path .. "/" .. "\n" .. label + : path .. "/" .. label; + + return newPath; + } + + private static void addPathItem(OptionMenuDescriptor desc, string path) + { + Array lines; + path.split(lines, "\n"); + + int nLines = lines.size(); + + for (int i = 0; i < nLines; ++i) + { + OptionMenuItemStaticText text = new("OptionMenuItemStaticText").Init(lines[i], 1); + + desc.mItems.push(text); + } + } + + private static void addEmptyLine(OptionMenuDescriptor desc) + { + int nItems = desc.mItems.size(); + + if (nItems > 0) + { + let staticText = OptionMenuItemStaticText(desc.mItems[nItems - 1]); + + if (staticText != null && staticText.mLabel == "") { return; } + } + + let item = new("OptionMenuItemStaticText").Init(""); + + desc.mItems.push(item); + } + + private static void addNoResultsItem(OptionMenuDescriptor desc) + { + string noResults = StringTable.Localize("$OS_NO_RESULTS"); + let text = new("OptionMenuItemStaticText").Init(noResults, 0); + + addEmptyLine(desc); + desc.mItems.push(text); + } + + private os_AnyOrAllOption mIsAnyOfItem; + private os_SearchField mSearchField; +} diff --git a/wadsrc/static/zscript/ui/menu/search/query.zs b/wadsrc/static/zscript/engine/ui/menu/search/query.zs similarity index 100% rename from wadsrc/static/zscript/ui/menu/search/query.zs rename to wadsrc/static/zscript/engine/ui/menu/search/query.zs diff --git a/wadsrc/static/zscript/ui/menu/search/searchfield.zs b/wadsrc/static/zscript/engine/ui/menu/search/searchfield.zs similarity index 100% rename from wadsrc/static/zscript/ui/menu/search/searchfield.zs rename to wadsrc/static/zscript/engine/ui/menu/search/searchfield.zs diff --git a/wadsrc/static/zscript/ui/menu/textentermenu.zs b/wadsrc/static/zscript/engine/ui/menu/textentermenu.zs similarity index 99% rename from wadsrc/static/zscript/ui/menu/textentermenu.zs rename to wadsrc/static/zscript/engine/ui/menu/textentermenu.zs index 2f179d0d71b..9a83deb5036 100644 --- a/wadsrc/static/zscript/ui/menu/textentermenu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/textentermenu.zs @@ -38,7 +38,7 @@ class TextEnterMenu : Menu { const INPUTGRID_WIDTH = 13; const INPUTGRID_HEIGHT = 5; - + const Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-=.,!?@'\":;[]()<>^#$%&*/_ \b"; String mEnterString; @@ -50,7 +50,7 @@ class TextEnterMenu : Menu int CursorSize; bool AllowColors; Font displayFont; - + //============================================================================= // // @@ -106,13 +106,13 @@ class TextEnterMenu : Menu { return mEnterString; } - + override bool TranslateKeyboardEvents() { return mInputGridOkay; } - - + + //============================================================================= // // @@ -303,7 +303,7 @@ class TextEnterMenu : Menu return false; } - + //============================================================================= // // @@ -365,7 +365,7 @@ class TextEnterMenu : Menu else if (ch == 8 || ch == 0) { // Draw the backspace and end "characters". - String str = ch == 8 ? "BS" : "ED"; + String str = ch == 8 ? "←" : "↲"; screen.DrawText(displayFont, colr, xx + cell_width/2 - displayFont.StringWidth(str)*CleanXfac_1/2, yy + top_padding, str, DTA_CleanNoMove_1, true); @@ -375,5 +375,5 @@ class TextEnterMenu : Menu } Super.Drawer(); } - + } diff --git a/wadsrc/static/zscript/engine/ui/statusbar/statusbarcore.zs b/wadsrc/static/zscript/engine/ui/statusbar/statusbarcore.zs new file mode 100644 index 00000000000..30635337dda --- /dev/null +++ b/wadsrc/static/zscript/engine/ui/statusbar/statusbarcore.zs @@ -0,0 +1,240 @@ +class HUDFont native ui +{ + native Font mFont; + native static HUDFont Create(Font fnt, int spacing = 0, EMonospacing monospacing = Mono_Off, int shadowx = 0, int shadowy = 0); +} + +class StatusBarCore native ui +{ + enum DI_Flags + { + DI_SKIPICON = 0x1, + DI_SKIPALTICON = 0x2, + DI_SKIPSPAWN = 0x4, + DI_SKIPREADY = 0x8, + DI_ALTICONFIRST = 0x10, + DI_TRANSLATABLE = 0x20, + DI_FORCESCALE = 0x40, + DI_DIM = 0x80, + DI_DRAWCURSORFIRST = 0x100, // only for DrawInventoryBar. + DI_ALWAYSSHOWCOUNT = 0x200, // only for DrawInventoryBar. + DI_DIMDEPLETED = 0x400, + DI_DONTANIMATE = 0x800, // do not animate the texture + DI_MIRROR = 0x1000, // flip the texture horizontally, like a mirror + DI_ITEM_RELCENTER = 0x2000, + DI_MIRRORY = 0x40000000, + + DI_SCREEN_AUTO = 0, // decide based on given offsets. + DI_SCREEN_MANUAL_ALIGN = 0x4000, // If this is on, the following flags will have an effect + + DI_SCREEN_TOP = DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VCENTER = 0x8000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_BOTTOM = 0x10000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VOFFSET = 0x18000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VMASK = 0x18000 | DI_SCREEN_MANUAL_ALIGN, + + DI_SCREEN_LEFT = DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HCENTER = 0x20000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_RIGHT = 0x40000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HOFFSET = 0x60000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HMASK = 0x60000 | DI_SCREEN_MANUAL_ALIGN, + + DI_SCREEN_LEFT_TOP = DI_SCREEN_TOP | DI_SCREEN_LEFT, + DI_SCREEN_RIGHT_TOP = DI_SCREEN_TOP | DI_SCREEN_RIGHT, + DI_SCREEN_LEFT_BOTTOM = DI_SCREEN_BOTTOM | DI_SCREEN_LEFT, + DI_SCREEN_LEFT_CENTER = DI_SCREEN_VCENTER | DI_SCREEN_LEFT, + DI_SCREEN_RIGHT_BOTTOM = DI_SCREEN_BOTTOM | DI_SCREEN_RIGHT, + DI_SCREEN_RIGHT_CENTER = DI_SCREEN_VCENTER | DI_SCREEN_RIGHT, + DI_SCREEN_CENTER = DI_SCREEN_VCENTER | DI_SCREEN_HCENTER, + DI_SCREEN_CENTER_TOP = DI_SCREEN_TOP | DI_SCREEN_HCENTER, + DI_SCREEN_CENTER_BOTTOM = DI_SCREEN_BOTTOM | DI_SCREEN_HCENTER, + DI_SCREEN_OFFSETS = DI_SCREEN_HOFFSET | DI_SCREEN_VOFFSET, + + DI_ITEM_AUTO = 0, // equivalent with bottom center, which is the default alignment. + + DI_ITEM_TOP = 0x80000, + DI_ITEM_VCENTER = 0x100000, + DI_ITEM_BOTTOM = 0, // this is the default vertical alignment + DI_ITEM_VOFFSET = 0x180000, + DI_ITEM_VMASK = 0x180000, + + DI_ITEM_LEFT = 0x200000, + DI_ITEM_HCENTER = 0, // this is the default horizontal alignment + DI_ITEM_RIGHT = 0x400000, + DI_ITEM_HOFFSET = 0x600000, + DI_ITEM_HMASK = 0x600000, + + DI_ITEM_LEFT_TOP = DI_ITEM_TOP|DI_ITEM_LEFT, + DI_ITEM_RIGHT_TOP = DI_ITEM_TOP|DI_ITEM_RIGHT, + DI_ITEM_LEFT_CENTER = DI_ITEM_CENTER|DI_ITEM_LEFT, + DI_ITEM_RIGHT_CENTER = DI_ITEM_CENTER|DI_ITEM_RIGHT, + DI_ITEM_LEFT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_LEFT, + DI_ITEM_RIGHT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_RIGHT, + DI_ITEM_CENTER = DI_ITEM_VCENTER|DI_ITEM_HCENTER, + DI_ITEM_CENTER_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_HCENTER, + DI_ITEM_OFFSETS = DI_ITEM_HOFFSET|DI_ITEM_VOFFSET, + + DI_TEXT_ALIGN_LEFT = 0, + DI_TEXT_ALIGN_RIGHT = 0x800000, + DI_TEXT_ALIGN_CENTER = 0x1000000, + DI_TEXT_ALIGN = 0x1800000, + + DI_ALPHAMAPPED = 0x2000000, + DI_NOSHADOW = 0x4000000, + DI_ALWAYSSHOWCOUNTERS = 0x8000000, + DI_ARTIFLASH = 0x10000000, + DI_FORCEFILL = 0x20000000, + + // These 2 flags are only used by SBARINFO so these duplicate other flags not used by SBARINFO + DI_DRAWINBOX = DI_TEXT_ALIGN_RIGHT, + DI_ALTERNATEONFAIL = DI_TEXT_ALIGN_CENTER, + + }; + + enum ENumFlags + { + FNF_WHENNOTZERO = 0x1, + FNF_FILLZEROS = 0x2, + } + + // These are block properties for the drawers. A child class can set them to have a block of items use the same settings. + native double Alpha; + native Vector2 drawOffset; // can be set by subclasses to offset drawing operations + native double drawClip[4]; // defines a clipping rectangle (not used yet) + native bool fullscreenOffsets; // current screen is displayed with fullscreen behavior. + native int RelTop; + native int HorizontalResolution, VerticalResolution; + native bool CompleteBorder; + native Vector2 defaultScale; // factor for fully scaled fullscreen display. + + + native static String FormatNumber(int number, int minsize = 0, int maxsize = 0, int format = 0, String prefix = ""); + native double, double, double, double StatusbarToRealCoords(double x, double y=0, double w=0, double h=0); + native void DrawTexture(TextureID texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1), ERenderStyle style = STYLE_Translucent, Color col = 0xffffffff, int translation = 0, double clipwidth = -1); + native void DrawImage(String texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1), ERenderStyle style = STYLE_Translucent, Color col = 0xffffffff, int translation = 0, double clipwidth = -1); + + native void DrawTextureRotated(TextureID texid, Vector2 pos, int flags, double angle, double alpha = 1, Vector2 scale = (1, 1), ERenderStyle style = STYLE_Translucent, Color col = 0xffffffff, int translation = 0); + native void DrawImageRotated(String texid, Vector2 pos, int flags, double angle, double alpha = 1, Vector2 scale = (1, 1), ERenderStyle style = STYLE_Translucent, Color col = 0xffffffff, int translation = 0); + + native void DrawString(HUDFont font, String string, Vector2 pos, int flags = 0, int translation = Font.CR_UNTRANSLATED, double Alpha = 1., int wrapwidth = -1, int linespacing = 4, Vector2 scale = (1, 1), int pt = 0, ERenderStyle style = STYLE_Translucent); + native double, double, double, double TransformRect(double x, double y, double w, double h, int flags = 0); + native void Fill(Color col, double x, double y, double w, double h, int flags = 0); + native void SetClipRect(double x, double y, double w, double h, int flags = 0); + + native void SetSize(int height, int vwidth, int vheight, int hwidth = -1, int hheight = -1); + native Vector2 GetHUDScale(); + native void BeginStatusBar(bool forceScaled = false, int resW = -1, int resH = -1, int rel = -1); + native void BeginHUD(double Alpha = 1., bool forcescaled = false, int resW = -1, int resH = -1); + + void ClearClipRect() + { + screen.ClearClipRect(); + } + + //============================================================================ + // + // Returns how much the status bar's graphics extend into the view + // Used for automap text positioning + // The parameter specifies how much of the status bar area will be covered + // by the element requesting this information. + // + //============================================================================ + + virtual int GetProtrusion(double scaleratio) const + { + return 0; + } + +} + +//============================================================================ +// +// a generic value interpolator for status bar elements that can change +// gradually to their new value. +// +//============================================================================ + +class LinearValueInterpolator : Object +{ + int mCurrentValue; + int mMaxChange; + + static LinearValueInterpolator Create(int startval, int maxchange) + { + let v = new("LinearValueInterpolator"); + v.mCurrentValue = startval; + v.mMaxChange = maxchange; + return v; + } + + void Reset(int value) + { + mCurrentValue = value; + } + + // This must be called periodically in the status bar's Tick function. + // Do not call this in the Draw function because that may skip some frames! + void Update(int destvalue) + { + if (mCurrentValue > destvalue) + { + mCurrentValue = max(destvalue, mCurrentValue - mMaxChange); + } + else + { + mCurrentValue = min(destvalue, mCurrentValue + mMaxChange); + } + } + + // This must be called in the draw function to retrieve the value for output. + int GetValue() + { + return mCurrentValue; + } +} + +class DynamicValueInterpolator : Object +{ + int mCurrentValue; + int mMinChange; + int mMaxChange; + double mChangeFactor; + + + static DynamicValueInterpolator Create(int startval, double changefactor, int minchange, int maxchange) + { + let v = new("DynamicValueInterpolator"); + v.mCurrentValue = startval; + v.mMinChange = minchange; + v.mMaxChange = maxchange; + v.mChangeFactor = changefactor; + return v; + } + + void Reset(int value) + { + mCurrentValue = value; + } + + // This must be called periodically in the status bar's Tick function. + // Do not call this in the Draw function because that may skip some frames! + void Update(int destvalue) + { + int diff = int(clamp(abs(destvalue - mCurrentValue) * mChangeFactor, mMinChange, mMaxChange)); + if (mCurrentValue > destvalue) + { + mCurrentValue = max(destvalue, mCurrentValue - diff); + } + else + { + mCurrentValue = min(destvalue, mCurrentValue + diff); + } + } + + // This must be called in the draw function to retrieve the value for output. + int GetValue() + { + return mCurrentValue; + } +} + diff --git a/wadsrc/static/zscript/events.zs b/wadsrc/static/zscript/events.zs index 6f85bc18881..52cf3a7eb23 100644 --- a/wadsrc/static/zscript/events.zs +++ b/wadsrc/static/zscript/events.zs @@ -1,3 +1,60 @@ +enum ENetCmd +{ + NET_INT8 = 1, + NET_INT16, + NET_INT, + NET_FLOAT, + NET_DOUBLE, + NET_STRING, +} + +struct NetworkCommand native play version("4.12") +{ + native readonly int Player; + native readonly Name Command; + + native int ReadInt8(); + native int ReadInt16(); + native int ReadInt(); + native double ReadFloat(); + native double ReadDouble(); + native string ReadString(); + native bool EndOfStream(); + + // Wrappers + native Name ReadName(); + native double ReadMapUnit(); // 16.16 int -> double + native double ReadAngle(); // BAM int -> double + native Vector2 ReadVector2(); + native Vector3 ReadVector3(); + native Vector4 ReadVector4(); + native Quat ReadQuat(); + native void ReadIntArray(out Array values, ENetCmd intSize = NET_INT); + native void ReadDoubleArray(out Array values, bool doublePrecision = true); + native void ReadStringArray(out Array values, bool skipEmpty = false); +} + +class NetworkBuffer native version("4.12") +{ + native void AddInt8(int value); + native void AddInt16(int value); + native void AddInt(int value); + native void AddFloat(double value); + native void AddDouble(double value); + native void AddString(string value); + + // Wrappers + native void AddName(Name value); + native void AddMapUnit(double value); // double -> 16.16 int + native void AddAngle(double value); // double -> BAM int + native void AddVector2(Vector2 value); + native void AddVector3(Vector3 value); + native void AddVector4(Vector4 value); + native void AddQuat(Quat value); + native void AddIntArray(Array values, ENetCmd intSize = NET_INT); + native void AddDoubleArray(Array values, bool doublePrecision = true); + native void AddStringArray(Array values); +} struct RenderEvent native ui version("2.4") { @@ -15,7 +72,9 @@ struct WorldEvent native play version("2.4") native readonly bool IsSaveGame; // this will be true if we are re-entering the hub level. native readonly bool IsReopen; - // for thingspawned/thingdied/thingdestroyed + // for unloaded, name of next map (if any) + native readonly String NextMap; + // for thingspawned/thingdied/thingdestroyed/thingground native readonly Actor Thing; // for thingdied. can be null native readonly Actor Inflictor; @@ -37,6 +96,7 @@ struct WorldEvent native play version("2.4") native readonly vector3 DamagePosition; native readonly bool DamageIsRadius; native int NewDamage; + native readonly State CrushedState; } struct PlayerEvent native play version("2.4") @@ -48,239 +108,6 @@ struct PlayerEvent native play version("2.4") native readonly bool IsReturn; } -struct UiEvent native ui version("2.4") -{ - // d_gui.h - enum EGUIEvent - { - Type_None, - Type_KeyDown, - Type_KeyRepeat, - Type_KeyUp, - Type_Char, - Type_FirstMouseEvent, // ? - Type_MouseMove, - Type_LButtonDown, - Type_LButtonUp, - Type_LButtonClick, - Type_MButtonDown, - Type_MButtonUp, - Type_MButtonClick, - Type_RButtonDown, - Type_RButtonUp, - Type_RButtonClick, - Type_WheelUp, - Type_WheelDown, - Type_WheelRight, // ??? - Type_WheelLeft, // ??? - Type_BackButtonDown, // ??? - Type_BackButtonUp, // ??? - Type_FwdButtonDown, // ??? - Type_FwdButtonUp, // ??? - Type_LastMouseEvent - } - - // for KeyDown, KeyRepeat, KeyUp - enum ESpecialGUIKeys - { - Key_PgDn = 1, - Key_PgUp = 2, - Key_Home = 3, - Key_End = 4, - Key_Left = 5, - Key_Right = 6, - Key_Alert = 7, // ASCII bell - Key_Backspace = 8, // ASCII - Key_Tab = 9, // ASCII - Key_LineFeed = 10, // ASCII - Key_Down = 10, - Key_VTab = 11, // ASCII - Key_Up = 11, - Key_FormFeed = 12, // ASCII - Key_Return = 13, // ASCII - Key_F1 = 14, - Key_F2 = 15, - Key_F3 = 16, - Key_F4 = 17, - Key_F5 = 18, - Key_F6 = 19, - Key_F7 = 20, - Key_F8 = 21, - Key_F9 = 22, - Key_F10 = 23, - Key_F11 = 24, - Key_F12 = 25, - Key_Del = 26, - Key_Escape = 27, // ASCII - Key_Free1 = 28, - Key_Free2 = 29, - Key_Back = 30, // browser back key - Key_CEscape = 31 // color escape - } - - // - native readonly EGUIEvent Type; - // - native readonly String KeyString; - native readonly int KeyChar; - // - native readonly int MouseX; - native readonly int MouseY; - // - native readonly bool IsShift; - native readonly bool IsCtrl; - native readonly bool IsAlt; -} - -struct InputEvent native play version("2.4") -{ - enum EGenericEvent - { - Type_None, - Type_KeyDown, - Type_KeyUp, - Type_Mouse, - Type_GUI, // unused, kept for completeness - Type_DeviceChange - } - - // ew. - enum EDoomInputKeys - { - Key_Pause = 0xc5, // DIK_PAUSE - Key_RightArrow = 0xcd, // DIK_RIGHT - Key_LeftArrow = 0xcb, // DIK_LEFT - Key_UpArrow = 0xc8, // DIK_UP - Key_DownArrow = 0xd0, // DIK_DOWN - Key_Escape = 0x01, // DIK_ESCAPE - Key_Enter = 0x1c, // DIK_RETURN - Key_Space = 0x39, // DIK_SPACE - Key_Tab = 0x0f, // DIK_TAB - Key_F1 = 0x3b, // DIK_F1 - Key_F2 = 0x3c, // DIK_F2 - Key_F3 = 0x3d, // DIK_F3 - Key_F4 = 0x3e, // DIK_F4 - Key_F5 = 0x3f, // DIK_F5 - Key_F6 = 0x40, // DIK_F6 - Key_F7 = 0x41, // DIK_F7 - Key_F8 = 0x42, // DIK_F8 - Key_F9 = 0x43, // DIK_F9 - Key_F10 = 0x44, // DIK_F10 - Key_F11 = 0x57, // DIK_F11 - Key_F12 = 0x58, // DIK_F12 - Key_Grave = 0x29, // DIK_GRAVE - - Key_Backspace = 0x0e, // DIK_BACK - - Key_Equals = 0x0d, // DIK_EQUALS - Key_Minus = 0x0c, // DIK_MINUS - - Key_LShift = 0x2A, // DIK_LSHIFT - Key_LCtrl = 0x1d, // DIK_LCONTROL - Key_LAlt = 0x38, // DIK_LMENU - - Key_RShift = Key_LSHIFT, - Key_RCtrl = Key_LCTRL, - Key_RAlt = Key_LALT, - - Key_Ins = 0xd2, // DIK_INSERT - Key_Del = 0xd3, // DIK_DELETE - Key_End = 0xcf, // DIK_END - Key_Home = 0xc7, // DIK_HOME - Key_PgUp = 0xc9, // DIK_PRIOR - Key_PgDn = 0xd1, // DIK_NEXT - - Key_Mouse1 = 0x100, - Key_Mouse2 = 0x101, - Key_Mouse3 = 0x102, - Key_Mouse4 = 0x103, - Key_Mouse5 = 0x104, - Key_Mouse6 = 0x105, - Key_Mouse7 = 0x106, - Key_Mouse8 = 0x107, - - Key_FirstJoyButton = 0x108, - Key_Joy1 = (Key_FirstJoyButton+0), - Key_Joy2 = (Key_FirstJoyButton+1), - Key_Joy3 = (Key_FirstJoyButton+2), - Key_Joy4 = (Key_FirstJoyButton+3), - Key_Joy5 = (Key_FirstJoyButton+4), - Key_Joy6 = (Key_FirstJoyButton+5), - Key_Joy7 = (Key_FirstJoyButton+6), - Key_Joy8 = (Key_FirstJoyButton+7), - Key_LastJoyButton = 0x187, - Key_JoyPOV1_Up = 0x188, - Key_JoyPOV1_Right = 0x189, - Key_JoyPOV1_Down = 0x18a, - Key_JoyPOV1_Left = 0x18b, - Key_JoyPOV2_Up = 0x18c, - Key_JoyPOV3_Up = 0x190, - Key_JoyPOV4_Up = 0x194, - - Key_MWheelUp = 0x198, - Key_MWheelDown = 0x199, - Key_MWheelRight = 0x19A, - Key_MWheelLeft = 0x19B, - - Key_JoyAxis1Plus = 0x19C, - Key_JoyAxis1Minus = 0x19D, - Key_JoyAxis2Plus = 0x19E, - Key_JoyAxis2Minus = 0x19F, - Key_JoyAxis3Plus = 0x1A0, - Key_JoyAxis3Minus = 0x1A1, - Key_JoyAxis4Plus = 0x1A2, - Key_JoyAxis4Minus = 0x1A3, - Key_JoyAxis5Plus = 0x1A4, - Key_JoyAxis5Minus = 0x1A5, - Key_JoyAxis6Plus = 0x1A6, - Key_JoyAxis6Minus = 0x1A7, - Key_JoyAxis7Plus = 0x1A8, - Key_JoyAxis7Minus = 0x1A9, - Key_JoyAxis8Plus = 0x1AA, - Key_JoyAxis8Minus = 0x1AB, - Num_JoyAxisButtons = 8, - - Key_Pad_LThumb_Right = 0x1AC, - Key_Pad_LThumb_Left = 0x1AD, - Key_Pad_LThumb_Down = 0x1AE, - Key_Pad_LThumb_Up = 0x1AF, - - Key_Pad_RThumb_Right = 0x1B0, - Key_Pad_RThumb_Left = 0x1B1, - Key_Pad_RThumb_Down = 0x1B2, - Key_Pad_RThumb_Up = 0x1B3, - - Key_Pad_DPad_Up = 0x1B4, - Key_Pad_DPad_Down = 0x1B5, - Key_Pad_DPad_Left = 0x1B6, - Key_Pad_DPad_Right = 0x1B7, - Key_Pad_Start = 0x1B8, - Key_Pad_Back = 0x1B9, - Key_Pad_LThumb = 0x1BA, - Key_Pad_RThumb = 0x1BB, - Key_Pad_LShoulder = 0x1BC, - Key_Pad_RShoulder = 0x1BD, - Key_Pad_LTrigger = 0x1BE, - Key_Pad_RTrigger = 0x1BF, - Key_Pad_A = 0x1C0, - Key_Pad_B = 0x1C1, - Key_Pad_X = 0x1C2, - Key_Pad_Y = 0x1C3, - - Num_Keys = 0x1C4 - } - - // - native readonly EGenericEvent Type; - // - native readonly int KeyScan; // as in EDoomInputKeys enum - native readonly String KeyString; - native readonly int KeyChar; // ASCII char (if any) - // - native readonly int MouseX; - native readonly int MouseY; -} - struct ConsoleEvent native version("2.4") { // for net events, this will be the activator. @@ -319,10 +146,12 @@ class StaticEventHandler : Object native play version("2.4") virtual void OnUnregister() {} // actual handlers are here + virtual void OnEngineInitialize() {} virtual void WorldLoaded(WorldEvent e) {} virtual void WorldUnloaded(WorldEvent e) {} virtual void WorldThingSpawned(WorldEvent e) {} virtual void WorldThingDied(WorldEvent e) {} + virtual void WorldThingGround(WorldEvent e) {} virtual void WorldThingRevived(WorldEvent e) {} virtual void WorldThingDamaged(WorldEvent e) {} virtual void WorldThingDestroyed(WorldEvent e) {} @@ -340,6 +169,7 @@ class StaticEventHandler : Object native play version("2.4") // virtual void PlayerEntered(PlayerEvent e) {} + virtual void PlayerSpawned(PlayerEvent e) {} virtual void PlayerRespawned(PlayerEvent e) {} virtual void PlayerDied(PlayerEvent e) {} virtual void PlayerDisconnected(PlayerEvent e) {} @@ -352,7 +182,9 @@ class StaticEventHandler : Object native play version("2.4") // virtual ui void ConsoleProcess(ConsoleEvent e) {} + virtual ui void InterfaceProcess(ConsoleEvent e) {} virtual void NetworkProcess(ConsoleEvent e) {} + version("4.12") virtual void NetworkCommandProcess(NetworkCommand cmd) {} // virtual void CheckReplacement(ReplaceEvent e) {} @@ -376,4 +208,7 @@ class EventHandler : StaticEventHandler native version("2.4") { clearscope static native StaticEventHandler Find(class type); clearscope static native void SendNetworkEvent(String name, int arg1 = 0, int arg2 = 0, int arg3 = 0); + version("4.12") clearscope static native vararg bool SendNetworkCommand(Name cmd, ...); + version("4.12") clearscope static native bool SendNetworkBuffer(Name cmd, NetworkBuffer buffer); + clearscope static native void SendInterfaceEvent(int playerNum, string name, int arg1 = 0, int arg2 = 0, int arg3 = 0); } diff --git a/wadsrc/static/zscript/level_compatibility.zs b/wadsrc/static/zscript/level_compatibility.zs index 44fb88e71d1..acecf7a448f 100644 --- a/wadsrc/static/zscript/level_compatibility.zs +++ b/wadsrc/static/zscript/level_compatibility.zs @@ -964,6 +964,14 @@ class LevelCompatibility : LevelPostProcessor break; } + case 'FAA0550BE9923B3A3332B4F7DB897A4A': // heretic.wad e2m7 + { + // missing texture + TextureID looserck = TexMan.CheckForTexture("LOOSERCK", TexMan.Type_Wall); + SetWallTextureID( 629, Line.back, Side.top, looserck); + break; + } + case 'CA3773ED313E8899311F3DD0CA195A68': // heretic.wad e3m6 { // Quartz flask outside of map @@ -987,6 +995,22 @@ class LevelCompatibility : LevelPostProcessor break; } + case '30D1480A6D4F3A3153739D4CCF659C4E': // heretic.wad E4M8 + { + // multiplayer teleporter prevents exit on cooperative + SetThingFlags(78,MTF_DEATHMATCH); + break; + } + + case '6CDA2721AA1076F063557CF89D88E92B': // hexen.wad map08 + { + // Amulet of warding accidentally shifted outside of map + SetThingXY(256,-1632,2352); + // Icon of the defender outside of map + SetThingSkills(261,0); + break; + } + case '39C594CAC07EE51C80F757DA465FCC94': // strife1.wad map10 { // fix the shooting range by matching sector 138 and 145 properties together @@ -1010,6 +1034,12 @@ class LevelCompatibility : LevelPostProcessor break; } + case '775CBC35C0A58326FE87AAD638FF9E2A': // Strife1.wad map29 + case 'A75099ACB622C7013EE737480FCB0D67': // SVE.wad map29 + // disable teleporter that would always teleport into a blocking position. + ClearLineSpecial(271); + break; + case 'DB31D71B11E3E4393B9C0CCB44A8639F': // rop_2015.wad e1m5 { // Lower floor a bit so secret switch becomes accessible @@ -1031,6 +1061,20 @@ class LevelCompatibility : LevelPostProcessor break; } + case '55BF5BFAF086C904E7258258F9700155': // Eternal Doom map02 + { + // unreachable monsters + SetThingFlags(274, GetThingFlags(274) | MTF_NOCOUNT); + SetThingFlags(275, GetThingFlags(275) | MTF_NOCOUNT); + SetThingFlags(276, GetThingFlags(276) | MTF_NOCOUNT); + SetThingFlags(277, GetThingFlags(277) | MTF_NOCOUNT); + SetThingFlags(278, GetThingFlags(278) | MTF_NOCOUNT); + SetThingFlags(279, GetThingFlags(279) | MTF_NOCOUNT); + SetThingFlags(280, GetThingFlags(280) | MTF_NOCOUNT); + SetThingFlags(281, GetThingFlags(281) | MTF_NOCOUNT); + break; + } + case '5C594C67CF7721005DE71429F9811370': // Eternal Doom map03 { // fix broken staircase. The compatibility option is not sufficient @@ -1038,6 +1082,31 @@ class LevelCompatibility : LevelPostProcessor ClearSectorTags(212); ClearSectorTags(213); ClearSectorTags(214); + // unreachable secret + SetSectorSpecial(551, 0); + break; + } + + case '9A4615498C3451413F1CD3D15099ACC7': // Eternal Doom map05 + { + // an imp and two cyberdemons are located at the softlock area + SetThingFlags(272, GetThingFlags (272) | MTF_NOCOUNT); + SetThingFlags(273, GetThingFlags (273) | MTF_NOCOUNT); + SetThingFlags(274, GetThingFlags (274) | MTF_NOCOUNT); + break; + } + + case '8B55842D5A509902738040AF10B4E787': // Eternal Doom map10 + { + // soulsphere at the end of the level is there merely to replicate the start of the next map + SetThingFlags(548, GetThingFlags (548) | MTF_NOCOUNT); + break; + } + + case 'E5B4379151C2010B966CA37A9818C901': // Eternal Doom map12 + { + // unreachable baron + SetThingFlags(177, GetThingFlags(177) | MTF_NOCOUNT); break; } @@ -1345,7 +1414,6 @@ class LevelCompatibility : LevelPostProcessor case '11EA5B8357DEB70A8F00900117831191': // kdizd_12.pk3 z1m3 { // Fix incorrectly tagged underwater sector which causes render glitches. - ClearSectorTags(7857); AddSectorTag(7857, 82); break; } @@ -1488,6 +1556,16 @@ class LevelCompatibility : LevelPostProcessor SetLineFlags(2040, Line.ML_REPEAT_SPECIAL); break; } + case '145C4DFCF843F2B92C73036BA0E1D98A': // Hell Revealed MAP26 + { + // The 4 archviles that produce the ghost monsters cannot be killed + // Make them not count so they still produce ghosts while allowing 100% kills. + SetThingFlags(320, GetThingFlags (320) | MTF_NOCOUNT); + SetThingFlags(347, GetThingFlags (347) | MTF_NOCOUNT); + SetThingFlags(495, GetThingFlags (495) | MTF_NOCOUNT); + SetThingFlags(496, GetThingFlags (496) | MTF_NOCOUNT); + break; + } case '0E379EEBEB189F294ED122BC60D10A68': // Hellbound MAP29 { @@ -1944,10 +2022,195 @@ class LevelCompatibility : LevelPostProcessor case '2499CF9A9351BE9BC4E9C66FC9F291A7': // Requiem MAP23 { + // Have arch-vile who creates ghost monsters not count as a kill + SetThingFlags(0, GetThingFlags(0) | MTF_NOCOUNT); // Remove secret at switch that can only be scored by crouching SetSectorSpecial(240, 0); break; } + + case '1497894956B3C8EBE8A240B7FDD99C6A': // Memento Mori 2 MAP25 + { + // an imp is used for the lift activation and cannot be killed + SetThingFlags(51, GetThingFlags (51) | MTF_NOCOUNT); + break; + } + + case '51960F3E9D46449E98DBC7D97F49DB23': // Shotgun Symphony E1M1 + { + // harmless cyberdemon included for the 'story' sake + SetThingFlags(158, GetThingFlags (158) | MTF_NOCOUNT); + break; + } + + case '60D362BAE16B4C10A1DCEE442C878CAE': // 50 Shades of Graytall MAP06 + { + // there are four invisibility spheres used for decoration + SetThingFlags(144, GetThingFlags (144) | MTF_NOCOUNT); + SetThingFlags(145, GetThingFlags (145) | MTF_NOCOUNT); + SetThingFlags(194, GetThingFlags (194) | MTF_NOCOUNT); + SetThingFlags(195, GetThingFlags (195) | MTF_NOCOUNT); + break; + } + + case 'C104E740CC3F70BCFD5D2EA8E833318D': // 50 Monsters MAP29 + { + // there are two invisibility spheres used for decoration + SetThingFlags(111, GetThingFlags (111) | MTF_NOCOUNT); + SetThingFlags(112, GetThingFlags (112) | MTF_NOCOUNT); + break; + } + + case '76393C84102480A4C75A4674C9C3217A': // Deadly Standards 2 E2M8 + { + // 923 lost souls are used as environmental hazard + for (int i = 267; i < 275; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 482; i < 491; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 510; i < 522; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 880; i < 1510; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 1622; i < 1660; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + + for (int i = 1682; i < 1820; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 1847; i < 1875; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 2110; i < 2114; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 2243; i < 2293; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + + SetThingFlags(493, GetThingFlags (493) | MTF_NOCOUNT); + SetThingFlags(573, GetThingFlags (573) | MTF_NOCOUNT); + SetThingFlags(613, GetThingFlags (613) | MTF_NOCOUNT); + SetThingFlags(614, GetThingFlags (614) | MTF_NOCOUNT); + SetThingFlags(1679, GetThingFlags (1679) | MTF_NOCOUNT); + SetThingFlags(1680, GetThingFlags (1680) | MTF_NOCOUNT); + break; + } + + case '42B4D294A60BE4E3500AF150291CF6D4': // Hell Ground MAP05 + { + // 5 cyberdemons are located at the 'pain end' sector + for (int i = 523; i < 528; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + break; + } + + case '0C0513A9821F26F3D7997E3B0359A318': // Mayhem 1500 MAP06 + { + // there's an archvile behind the bossbrain at the very end that can't be killed + SetThingFlags(61, GetThingFlags (61) | MTF_NOCOUNT); + break; + } + + case '00641DA23DDE998F6725BC5896A0DBC2': // 20 Years of Doom E1M8 + { + // 32 lost souls are located at the 'pain end' sector + for (int i = 1965; i < 1975; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 2189; i < 2202; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 2311; i < 2320; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + break; + } + + case 'EEBDD9CA280F6FF06C30AF2BEE85BF5F': // 2002ad10.wad E3M3 + { + // swarm of cacodemons at the end meant to be pseudo-endless and not killed + for (int i = 467; i < 547; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + break; + } + + case '988DFF5BB7073B857DEE3957A91C8518': // Speed of Doom MAP14 + { + // you can get only one of the soulspheres, the other, depending on your choice, becomes unavailable + SetThingFlags(1044, GetThingFlags (1044) | MTF_NOCOUNT); + SetThingFlags(1045, GetThingFlags (1045) | MTF_NOCOUNT); + break; + } + + case '361734AC5D78E872A05335C83E4F6DB8': // inf-lutz.wad E3M8 + { + // there is a trap with 10 cyberdemons at the end of the map, you are not meant to kill them + for (int i = 541; i < 546; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + for (int i = 638; i < 643; i++) + SetThingFlags (i, GetThingFlags (i) | MTF_NOCOUNT); + break; + } + + case '8F844B272E7235E82EA78AD2A2EB2D4A': // Serenity E3M7 + { + // two spheres can't be obtained and thus should not count towards 100% items + SetThingFlags(443, GetThingFlags (443) | MTF_NOCOUNT); + SetThingFlags(444, GetThingFlags (444) | MTF_NOCOUNT); + // one secret is unobtainable + SetSectorSpecial (97, 0); + break; + } + + case 'A50AC05CCE4F07413A0C4883C5E24215': // dbimpact.wad e1m7 + { + SetLineFlags(1461, Line.ML_REPEAT_SPECIAL); + SetLineFlags(1468, Line.ML_REPEAT_SPECIAL); + break; + } + + case 'E0D747B9EE58A0CB74B9AD54423AC15C': // return01.wad e1m2 + { + // fix broken switch to raise the exit bridge + SetLineSpecial(1248, Floor_RaiseByValue, 39, 8, 512); + break; + } + + case '1C35384B22BD805F51B3B2C9D17D62E4': // 007ltsd.wad E4M7 + { + // Fix impassable exit line + SetLineFlags(6842, 0, Line.ML_BLOCKING); + break; + } + + case '50E394239FF64264950D11883E933553': // 1024.wad map05 + { + // Change duplicate player 2 start to player 3 start + SetThingEdNum(59, 3); + break; + } + + case '3F0965ADCEB2F4A7BF46FADF6DD941B0': // phocas2.wad map01 + { + // turn map spot into teleport dest. + SetThingEdNum(699, 9044); + break; + } + + case 'C8E727FFBA0BA445666C80340BF3D0AC': // god_.WAD E1M2 + { + // fix bad skill flags for a monster that's required to be killed. + SetThingSkills(1184, 1); + break; + } + + case '3B4AAD34E46443BD505CC6053FCD842A': // pc_cp2.wad map38 + { + // Emulate the effect of the hidden Commander Keen's death + // since the Keen actor is modified by DEHACKED and doesn't work as intended: + + // 1) Replace the Keen with a zombieman + SetThingEdNum(101, 3004); + + // 2) Set its special to emulate A_KeenDie + SetThingSpecial(101, Door_Open); + SetThingArgument(101, 0, 666); + SetThingArgument(101, 1, 16); + } } } } diff --git a/wadsrc/static/zscript/level_postprocessor.zs b/wadsrc/static/zscript/level_postprocessor.zs index 93ee8343de8..930b1753168 100644 --- a/wadsrc/static/zscript/level_postprocessor.zs +++ b/wadsrc/static/zscript/level_postprocessor.zs @@ -12,6 +12,7 @@ class LevelPostProcessor native play protected native void ClearLineIDs(int line); protected native void AddLineID(int line, int tag); protected native void OffsetSectorPlane(int sector, int plane, double offset); + protected native void SetSectorPlane(int sector, int plane, vector3 normal, double d); const SKILLS_ALL = 31; const MODES_ALL = MTF_SINGLE | MTF_COOPERATIVE | MTF_DEATHMATCH; @@ -47,6 +48,9 @@ class LevelPostProcessor native play protected native void SetThingStringArgument(uint thing, Name value); protected native void SetVertex(uint vertex, double x, double y); + protected native double, bool GetVertexZ(uint vertex, int plane); + protected native void SetVertexZ(uint vertex, int plane, double z); + protected native void RemoveVertexZ(uint vertex, int plane); protected native void SetLineVertexes(uint Line, uint v1, uint v2); protected native void FlipLineSideRefs(uint Line); protected native void SetLineSectorRef(uint line, uint side, uint sector); diff --git a/wadsrc/static/zscript/mapdata.zs b/wadsrc/static/zscript/mapdata.zs index 1ac5f12ded1..db217e7cc74 100644 --- a/wadsrc/static/zscript/mapdata.zs +++ b/wadsrc/static/zscript/mapdata.zs @@ -17,22 +17,63 @@ struct SectorPortal native play FLAG_INSKYBOX = 2, // to avoid recursion }; - native int mType; - native int mFlags; - native uint mPartner; - native int mPlane; - native Sector mOrigin; - native Sector mDestination; - native Vector2 mDisplacement; - native double mPlaneZ; - native Actor mSkybox; + native readonly int mType; + native internal readonly int mFlags; + native readonly uint mPartner; + native readonly int mPlane; + native readonly Sector mOrigin; + native internal readonly Sector mDestination; + native readonly Vector2 mDisplacement; + native readonly double mPlaneZ; + native internal readonly Actor mSkybox; }; +struct LinePortal native play +{ + enum EType + { + PORTT_VISUAL, + PORTT_TELEPORT, + PORTT_INTERACTIVE, + PORTT_LINKED, + PORTT_LINKEDEE // Eternity compatible definition which uses only one line ID and a different anchor type to link to. + }; + + enum EFlags + { + PORTF_VISIBLE = 1, + PORTF_PASSABLE = 2, + PORTF_SOUNDTRAVERSE = 4, + PORTF_INTERACTIVE = 8, + PORTF_POLYOBJ = 16, + + PORTF_TYPETELEPORT = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE, + PORTF_TYPEINTERACTIVE = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE | PORTF_INTERACTIVE, + }; + + enum EAlignment + { + PORG_ABSOLUTE, // does not align at all. z-ccoordinates must match. + PORG_FLOOR, + PORG_CEILING, + }; + + native readonly Line mOrigin; + native readonly Line mDestination; + native readonly Vector2 mDisplacement; + native readonly uint8 mType; + native readonly uint8 mFlags; + native readonly uint8 mDefFlags; + native readonly uint8 mAlign; + native readonly double mAngleDiff; + native readonly double mSinRot; + native readonly double mCosRot; +} struct Vertex native play { native readonly Vector2 p; - native clearscope int Index(); + native clearscope int Index() const; } struct Side native play @@ -62,6 +103,14 @@ struct Side native play WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. }; + enum EPartFlags + { + NoGradient = 1, + FlipGradient = 2, + ClampGradient = 4, + UseOwnSpecialColors = 8, + UseOwnAdditiveColor = 16, + }; native readonly Sector sector; // Sector the SideDef is facing. //DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall @@ -69,42 +118,44 @@ struct Side native play native int16 Light; native uint16 Flags; - native TextureID GetTexture(int which); + native clearscope TextureID GetTexture(int which) const; native void SetTexture(int which, TextureID tex); native void SetTextureXOffset(int which, double offset); - native double GetTextureXOffset(int which); + native clearscope double GetTextureXOffset(int which) const; native void AddTextureXOffset(int which, double delta); native void SetTextureYOffset(int which, double offset); - native double GetTextureYOffset(int which); + native clearscope double GetTextureYOffset(int which) const; native void AddTextureYOffset(int which, double delta); native void SetTextureXScale(int which, double scale); - native double GetTextureXScale(int which); + native clearscope double GetTextureXScale(int which) const; native void MultiplyTextureXScale(int which, double delta); native void SetTextureYScale(int which, double scale); - native double GetTextureYScale(int which); + native clearscope double GetTextureYScale(int which) const; native void MultiplyTextureYScale(int which, double delta); - native void SetSpecialColor(int tier, int position, Color scolor); - native Color GetAdditiveColor(int tier); + native clearscope int GetTextureFlags(int tier) const; + native void ChangeTextureFlags(int tier, int And, int Or); + native void SetSpecialColor(int tier, int position, Color scolor, bool useowncolor = true); + native clearscope Color GetAdditiveColor(int tier) const; native void SetAdditiveColor(int tier, Color color); native void EnableAdditiveColor(int tier, bool enable); native void SetColorization(int tier, Name cname); //native DInterpolation *SetInterpolation(int position); //native void StopInterpolation(int position); - native clearscope Vertex V1(); - native clearscope Vertex V2(); + native clearscope Vertex V1() const; + native clearscope Vertex V2() const; - native clearscope int Index(); + native clearscope int Index() const; - int GetUDMFInt(Name nm) + clearscope int GetUDMFInt(Name nm) const { return Level.GetUDMFInt(LevelLocals.UDMF_Side, Index(), nm); } - double GetUDMFFloat(Name nm) + clearscope double GetUDMFFloat(Name nm) const { return Level.GetUDMFFloat(LevelLocals.UDMF_Side, Index(), nm); } - String GetUDMFString(Name nm) + clearscope String GetUDMFString(Name nm) const { return Level.GetUDMFString(LevelLocals.UDMF_Side, Index(), nm); } @@ -152,10 +203,15 @@ struct Line native play ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING }; + enum ELineFlags2 + { + ML2_BLOCKLANDMONSTERS = 1, + } native readonly vertex v1, v2; // vertices, from v1 to v2 native readonly Vector2 delta; // precalculated v2 - v1 for side checking native uint flags; + native uint flags2; native uint activation; // activation type native int special; native int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) @@ -171,46 +227,54 @@ struct Line native play native readonly int health; native readonly int healthgroup; - native bool isLinePortal(); - native bool isVisualPortal(); - native Line getPortalDestination(); - native int getPortalAlignment(); - native clearscope int Index(); + native clearscope bool isLinePortal() const; + native clearscope bool isVisualPortal() const; + native clearscope Line getPortalDestination() const; + native clearscope int getPortalFlags() const; + native clearscope int getPortalAlignment() const; + native clearscope int getPortalType() const; + native clearscope Vector2 getPortalDisplacement() const; + native clearscope double getPortalAngleDiff() const; + native clearscope int Index() const; native bool Activate(Actor activator, int side, int type); native bool RemoteActivate(Actor activator, int side, int type, Vector3 pos); + native bool, double, double GetMidTexturePosition (int side); - int GetUDMFInt(Name nm) + clearscope int GetUDMFInt(Name nm) const { return Level.GetUDMFInt(LevelLocals.UDMF_Line, Index(), nm); } - double GetUDMFFloat(Name nm) + clearscope double GetUDMFFloat(Name nm) const { return Level.GetUDMFFloat(LevelLocals.UDMF_Line, Index(), nm); } - String GetUDMFString(Name nm) + clearscope String GetUDMFString(Name nm) const { return Level.GetUDMFString(LevelLocals.UDMF_Line, Index(), nm); } - native clearscope int GetHealth(); + native clearscope int GetHealth() const; native void SetHealth(int newhealth); + + native int CountIDs() const; + native int GetID(int index) const; } struct SecPlane native play { - native Vector3 Normal; - native double D; - native double negiC; + native readonly Vector3 Normal; + native readonly double D; + native readonly double negiC; - native bool isSlope() const; - native int PointOnSide(Vector3 pos) const; + native clearscope bool isSlope() const; + native clearscope int PointOnSide(Vector3 pos) const; native clearscope double ZatPoint (Vector2 v) const; - native double ZatPointDist(Vector2 v, double dist) const; - native bool isEqual(Secplane other) const; - native void ChangeHeight(double hdiff); - native double GetChangedHeight(double hdiff) const; - native double HeightDiff(double oldd, double newd = 1e37) const; - native double PointToDist(Vector2 xy, double z) const; + native clearscope double ZatPointDist(Vector2 v, double dist) const; + native clearscope bool isEqual(readonly other) const; + //native void ChangeHeight(double hdiff); + native clearscope double GetChangedHeight(double hdiff) const; + native clearscope double HeightDiff(double oldd, double newd = 1e37) const; + native clearscope double PointToDist(Vector2 xy, double z) const; } struct F3DFloor native play @@ -234,7 +298,8 @@ struct F3DFloor native play FF_UPPERTEXTURE = 0x20000, FF_LOWERTEXTURE = 0x40000, FF_THINFLOOR = 0x80000, // EDGE - FF_SCROLLY = 0x100000, // EDGE - not yet implemented!!! + FF_SCROLLY = 0x100000, // old leftover definition + FF_NODAMAGE = 0x100000, // no damage transfers FF_FIX = 0x200000, // use floor of model sector as floor and floor of real sector as ceiling FF_INVERTSECTOR = 0x400000, // swap meaning of sector planes FF_DYNAMIC = 0x800000, // created by partitioning another 3D-floor due to overlap @@ -259,7 +324,7 @@ struct F3DFloor native play native readonly int alpha; - native TextureID GetTexture(int pos); + native clearscope TextureID GetTexture(int pos) const; } // This encapsulates all info Doom's original 'special' field contained - for saving and transferring. @@ -267,7 +332,7 @@ struct SecSpecial play { Name damagetype; int damageamount; - short special; + int special; short damageinterval; short leakydamage; int Flags; @@ -275,11 +340,11 @@ struct SecSpecial play struct FColormap { - Color LightColor; - Color FadeColor; - uint8 Desaturation; - uint8 BlendFactor; - uint16 FogDensity; + readonly Color LightColor; + readonly Color FadeColor; + readonly uint8 Desaturation; + readonly uint8 BlendFactor; + readonly uint16 FogDensity; } struct Sector native play @@ -291,7 +356,7 @@ struct Sector native play native Actor SoundTarget; - native int16 special; + native int special; native int16 lightlevel; native int16 seqType; @@ -407,20 +472,20 @@ struct Sector native play native SectorAction SecActTarget; - native internal uint Portals[2]; - native readonly int PortalGroup; + native internal readonly uint Portals[2]; + native readonly int PortalGroup; native readonly int sectornum; - native clearscope int Index(); + native clearscope int Index() const; - native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); - native double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0); + native clearscope double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0) const; + native clearscope double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0) const; - native F3DFloor Get3DFloor(int index); - native int Get3DFloorCount(); - native Sector GetAttached(int index); - native int GetAttachedCount(); + native clearscope F3DFloor Get3DFloor(int index) const; + native clearscope int Get3DFloorCount() const; + native clearscope Sector GetAttached(int index) const; + native clearscope int GetAttachedCount() const; native void RemoveForceField(); deprecated("3.8", "Use Level.PointInSector instead") static clearscope Sector PointInSector(Vector2 pt) @@ -428,109 +493,110 @@ struct Sector native play return level.PointInSector(pt); } - native bool PlaneMoving(int pos); - native int GetFloorLight(); - native int GetCeilingLight(); - native Sector GetHeightSec(); + native clearscope bool PlaneMoving(int pos) const; + native clearscope int GetFloorLight() const; + native clearscope int GetCeilingLight() const; + native clearscope Sector GetHeightSec() const; native void TransferSpecial(Sector model); - native void GetSpecial(out SecSpecial spec); + native clearscope void GetSpecial(out SecSpecial spec) const; native void SetSpecial( SecSpecial spec); - native int GetTerrain(int pos); + native clearscope int GetTerrain(int pos) const; + native clearscope TerrainDef GetFloorTerrain(int pos) const; // Gets the terraindef from floor/ceiling (see EPlane const). native void CheckPortalPlane(int plane); - native double, Sector HighestCeilingAt(Vector2 a); - native double, Sector LowestFloorAt(Vector2 a); - native double, double GetFriction(int plane); + native clearscope double, Sector HighestCeilingAt(Vector2 a) const; + native clearscope double, Sector LowestFloorAt(Vector2 a) const; + native clearscope double, double GetFriction(int plane) const; native void SetXOffset(int pos, double o); native void AddXOffset(int pos, double o); - native double GetXOffset(int pos); + native clearscope double GetXOffset(int pos) const; native void SetYOffset(int pos, double o); native void AddYOffset(int pos, double o); - native double GetYOffset(int pos, bool addbase = true); + native clearscope double GetYOffset(int pos, bool addbase = true) const; native void SetXScale(int pos, double o); - native double GetXScale(int pos); + native clearscope double GetXScale(int pos) const; native void SetYScale(int pos, double o); - native double GetYScale(int pos); + native clearscope double GetYScale(int pos) const; native void SetAngle(int pos, double o); - native double GetAngle(int pos, bool addbase = true); + native clearscope double GetAngle(int pos, bool addbase = true) const; native void SetBase(int pos, double y, double o); native void SetAlpha(int pos, double o); - native double GetAlpha(int pos); - native int GetFlags(int pos); - native int GetVisFlags(int pos); + native clearscope double GetAlpha(int pos) const; + native clearscope int GetFlags(int pos) const; + native clearscope int GetVisFlags(int pos) const; native void ChangeFlags(int pos, int And, int Or); - native int GetPlaneLight(int pos); + native clearscope int GetPlaneLight(int pos) const; native void SetPlaneLight(int pos, int level); native void SetColor(color c, int desat = 0); native void SetFade(color c); native void SetFogDensity(int dens); - native double GetGlowHeight(int pos); - native color GetGlowColor(int pos); + native clearscope double GetGlowHeight(int pos) const; + native clearscope color GetGlowColor(int pos) const; native void SetGlowHeight(int pos, double height); native void SetGlowColor(int pos, color color); native void SetSpecialColor(int pos, color color); native void SetAdditiveColor(int pos, Color color); native void SetColorization(int tier, Name cname); - native TextureID GetTexture(int pos); + native clearscope TextureID GetTexture(int pos) const; native void SetTexture(int pos, TextureID tex, bool floorclip = true); - native double GetPlaneTexZ(int pos); + native clearscope double GetPlaneTexZ(int pos) const; native void SetPlaneTexZ(int pos, double val, bool dirtify = false); // This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code. native void ChangeLightLevel(int newval); native void SetLightLevel(int newval); - native int GetLightLevel(); + native clearscope int GetLightLevel() const; native void AdjustFloorClip(); - native bool IsLinked(Sector other, bool ceiling); + native clearscope bool IsLinked(Sector other, bool ceiling) const; - native bool PortalBlocksView(int plane); - native bool PortalBlocksSight(int plane); - native bool PortalBlocksMovement(int plane); - native bool PortalBlocksSound(int plane); - native bool PortalIsLinked(int plane); + native clearscope bool PortalBlocksView(int plane) const; + native clearscope bool PortalBlocksSight(int plane) const; + native clearscope bool PortalBlocksMovement(int plane) const; + native clearscope bool PortalBlocksSound(int plane) const; + native clearscope bool PortalIsLinked(int plane) const; native void ClearPortal(int plane); - native double GetPortalPlaneZ(int plane); - native Vector2 GetPortalDisplacement(int plane); - native int GetPortalType(int plane); - native int GetOppositePortalGroup(int plane); - native double CenterFloor(); - native double CenterCeiling(); + native clearscope double GetPortalPlaneZ(int plane) const; + native clearscope Vector2 GetPortalDisplacement(int plane) const; + native clearscope int GetPortalType(int plane) const; + native clearscope int GetOppositePortalGroup(int plane) const; + native clearscope double CenterFloor() const; + native clearscope double CenterCeiling() const; native int MoveFloor(double speed, double dest, int crush, int direction, bool hexencrush, bool instant = false); native int MoveCeiling(double speed, double dest, int crush, int direction, bool hexencrush); - native Sector NextSpecialSector(int type, Sector prev); - native double, Vertex FindLowestFloorSurrounding(); - native double, Vertex FindHighestFloorSurrounding(); - native double, Vertex FindNextHighestFloor(); - native double, Vertex FindNextLowestFloor(); - native double, Vertex FindLowestCeilingSurrounding(); - native double, Vertex FindHighestCeilingSurrounding(); - native double, Vertex FindNextLowestCeiling(); - native double, Vertex FindNextHighestCeiling(); - - native double FindShortestTextureAround(); - native double FindShortestUpperAround(); - native Sector FindModelFloorSector(double floordestheight); - native Sector FindModelCeilingSector(double floordestheight); - native int FindMinSurroundingLight(int max); - native double, Vertex FindLowestCeilingPoint(); - native double, Vertex FindHighestFloorPoint(); + native clearscope Sector NextSpecialSector(int type, Sector prev) const; + native clearscope double, Vertex FindLowestFloorSurrounding() const; + native clearscope double, Vertex FindHighestFloorSurrounding() const; + native clearscope double, Vertex FindNextHighestFloor() const; + native clearscope double, Vertex FindNextLowestFloor() const; + native clearscope double, Vertex FindLowestCeilingSurrounding() const; + native clearscope double, Vertex FindHighestCeilingSurrounding() const; + native clearscope double, Vertex FindNextLowestCeiling() const; + native clearscope double, Vertex FindNextHighestCeiling() const; + + native clearscope double FindShortestTextureAround() const; + native clearscope double FindShortestUpperAround() const; + native clearscope Sector FindModelFloorSector(double floordestheight) const; + native clearscope Sector FindModelCeilingSector(double floordestheight) const; + native clearscope int FindMinSurroundingLight(int max) const; + native clearscope double, Vertex FindLowestCeilingPoint() const; + native clearscope double, Vertex FindHighestFloorPoint() const; native void SetEnvironment(String env); native void SetEnvironmentID(int envnum); native SeqNode StartSoundSequenceID (int chan, int sequence, int type, int modenum, bool nostop = false); native SeqNode StartSoundSequence (int chan, Name seqname, int modenum); - native SeqNode CheckSoundSequence (int chan); + native clearscope SeqNode CheckSoundSequence (int chan) const; native void StopSoundSequence(int chan); - native bool IsMakingLoopingSound (); + native clearscope bool IsMakingLoopingSound () const; - bool isSecret() + clearscope bool isSecret() const { return !!(Flags & SECF_SECRET); } - bool wasSecret() + clearscope bool wasSecret() const { return !!(Flags & SECF_WASSECRET); } @@ -540,15 +606,15 @@ struct Sector native play Flags &= ~SECF_SECRET; } - int GetUDMFInt(Name nm) + clearscope int GetUDMFInt(Name nm) const { return Level.GetUDMFInt(LevelLocals.UDMF_Sector, Index(), nm); } - double GetUDMFFloat(Name nm) + clearscope double GetUDMFFloat(Name nm) const { return Level.GetUDMFFloat(LevelLocals.UDMF_Sector, Index(), nm); } - String GetUDMFString(Name nm) + clearscope String GetUDMFString(Name nm) const { return Level.GetUDMFString(LevelLocals.UDMF_Sector, Index(), nm); } @@ -582,8 +648,11 @@ struct Sector native play } - native clearscope int GetHealth(SectorPart part); + native clearscope int GetHealth(SectorPart part) const; native void SetHealth(SectorPart part, int newhealth); + + native int CountTags() const; + native int GetTag(int index) const; } class SectorTagIterator : Object native diff --git a/wadsrc/static/zscript/scriptutil/scriptutil.zs b/wadsrc/static/zscript/scriptutil/scriptutil.zs index 26f1a2b9dec..b9d13e7b5e0 100644 --- a/wadsrc/static/zscript/scriptutil/scriptutil.zs +++ b/wadsrc/static/zscript/scriptutil/scriptutil.zs @@ -61,7 +61,7 @@ class ScriptUtil play } if (type == 'Armor') { - type = "BasicArmor"; + type = Actor.GetBasicArmorClass().GetClassName(); } if (amount <= 0) { diff --git a/wadsrc/static/zscript/ui/intermission.zs b/wadsrc/static/zscript/ui/intermission.zs new file mode 100644 index 00000000000..657be98bad9 --- /dev/null +++ b/wadsrc/static/zscript/ui/intermission.zs @@ -0,0 +1,61 @@ + + +class IntermissionController native ui +{ + // This is mostly a black box to the native intermission code. + // May be scriptified later, but right now we do not need it. + + native void Start(); + native bool Responder(InputEvent ev); + native bool Ticker(); + native void Drawer(); + native bool NextPage(); +} + +// Wrapper to play the native intermissions within a screen job. +class IntermissionScreenJob : ScreenJob +{ + IntermissionController controller; + + ScreenJob Init(IntermissionController ctrl, bool allowwipe) + { + Super.Init(); + if (allowwipe && wipetype != 0) flags = wipetype << ScreenJob.transition_shift; + controller = ctrl; + return self; + } + + override void Start() { controller.Start(); } + override bool OnEvent(InputEvent evt) { return controller.Responder(evt); } + override void OnTick() { if (!controller.Ticker()) jobstate = finished; } + override void Draw(double smoothratio) { controller.Drawer(); } + + override void OnDestroy() + { + if (controller) + controller.Destroy(); + Super.OnDestroy(); + } +} + + +class DoomCutscenes ui +{ + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + static void BuildMapTransition(ScreenJobRunner runner, IntermissionController inter, StatusScreen status) + { + if (status) + { + runner.Append(status); + } + if (inter) + { + runner.Append(new("IntermissionScreenJob").Init(inter, status != null)); + } + } +} diff --git a/wadsrc/static/zscript/ui/menu/conversationmenu.zs b/wadsrc/static/zscript/ui/menu/conversationmenu.zs index 53c86aed60d..1b1d3c011fc 100644 --- a/wadsrc/static/zscript/ui/menu/conversationmenu.zs +++ b/wadsrc/static/zscript/ui/menu/conversationmenu.zs @@ -93,7 +93,7 @@ class ConversationMenu : Menu int fontScale; int refwidth; int refheight; - double fontfactor; + Array ypositions; int SpeechWidth; int ReplyWidth; @@ -127,7 +127,6 @@ class ConversationMenu : Menu displayWidth = CleanWidth; displayHeight = CleanHeight; fontScale = CleanXfac; - fontFactor = 1; refwidth = 320; refheight = 200; ReplyWidth = 320-50-10; @@ -140,7 +139,6 @@ class ConversationMenu : Menu { displayFont = NewSmallFont; fontScale = (CleanXfac+1) / 2; - fontFactor = double(CleanXfac) / fontScale; refwidth = 640; refheight = 400; ReplyWidth = 640-100-20; @@ -365,26 +363,18 @@ class ConversationMenu : Menu // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture x = ((x - (screen.GetWidth() / 2)) / fontScale) + refWidth/2; - y = ((y - (screen.GetHeight() / 2)) / fontScale) + refHeight/2; - int ypos = int(mYpos * FontFactor); - - if (x >= 24 && x <= refWidth-24 && y >= ypos && y < ypos + fh * mResponseLines.Size()) + if (x >= 24 && x <= refWidth-24) { - sel = (y - ypos) / fh; - for(int i = 0; i < mResponses.Size(); i++) + for (int i = 0; i < ypositions.Size()-1; i++) { - if (mResponses[i] > sel) + if (y > ypositions[i] && y <= ypositions[i+1]) { - sel = i-1; + sel = i; break; } } } - if (sel != -1 && sel != mSelection) - { - //S_Sound (CHAN_VOICE, CHANF_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - } mSelection = sel; if (type == MOUSE_Release) { @@ -498,6 +488,7 @@ class ConversationMenu : Menu int y = mYpos; int response = 0; + ypositions.Clear(); for (int i = 0; i < mResponseLines.Size(); i++) { int width = displayFont.StringWidth(mResponseLines[i]); @@ -506,13 +497,13 @@ class ConversationMenu : Menu double sx = (x - 160.0) * CleanXfac + (screen.GetWidth() * 0.5); double sy = (y - 100.0) * CleanYfac + (screen.GetHeight() * 0.5); - screen.DrawText(displayFont, Font.CR_GREEN, sx / fontScale, sy / fontScale, mResponseLines[i], DTA_KeepRatio, true, DTA_VirtualWidth, displayWidth, DTA_VirtualHeight, displayHeight); if (i == mResponses[response]) { String tbuf; + ypositions.Push(sy); response++; tbuf = String.Format("%d.", response); x = 50 - displayFont.StringWidth(tbuf); @@ -523,13 +514,31 @@ class ConversationMenu : Menu { int colr = ((MenuTime() % 8) < 4) || GetCurrentMenu() != self ? Font.CR_RED : Font.CR_GREY; + // custom graphic cursor color + Color cursorTexColor; + if (colr == Font.CR_RED) cursorTexColor = color(0xFF, 0x00, 0x00); + else if (colr == Font.CR_GREY) cursorTexColor = color(0xCC, 0xCC, 0xCC); + x = (50 + 3 - 160) * CleanXfac + screen.GetWidth() / 2; int yy = (y + ReplyLineHeight / 2 - 5 - 100) * CleanYfac + screen.GetHeight() / 2; - screen.DrawText(ConFont, colr, x, yy, "\xd", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); + + // use a custom graphic (intentionally long-named to reduce collision with existing mods), with the ConFont version as the fallback + let cursorTex = TexMan.CheckForTexture("graphics/DialogReplyCursor.png", TexMan.Type_MiscPatch); + if (cursorTex.IsValid()) + { + screen.DrawTexture(cursorTex, true, x / fontScale, yy / fontScale, DTA_KeepRatio, true, DTA_VirtualWidth, displayWidth, DTA_VirtualHeight, displayHeight); + screen.DrawTexture(cursorTex, true, x / fontScale, yy / fontScale, DTA_KeepRatio, true, DTA_VirtualWidth, displayWidth, DTA_VirtualHeight, displayHeight, DTA_FillColor, cursorTexColor, DTA_LegacyRenderStyle, STYLE_AddShaded); + } + else + { + screen.DrawText(ConFont, colr, x, yy, "\xd", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); + } } } y += ReplyLineHeight; } + double sy = (y - 100.0) * CleanYfac + (screen.GetHeight() * 0.5); + ypositions.Push(sy); } virtual void DrawGold() diff --git a/wadsrc/static/zscript/ui/menu/doommenus.zs b/wadsrc/static/zscript/ui/menu/doommenus.zs new file mode 100644 index 00000000000..9affca2bcb1 --- /dev/null +++ b/wadsrc/static/zscript/ui/menu/doommenus.zs @@ -0,0 +1,74 @@ +class GameplayMenu : OptionMenu +{ + override void Drawer () + { + Super.Drawer(); + + String s = String.Format("dmflags = %d dmflags2 = %d dmflags3 = %d", dmflags, dmflags2, dmflags3); + screen.DrawText (OptionFont(), OptionMenuSettings.mFontColorValue, + (screen.GetWidth() - OptionWidth (s) * CleanXfac_1) / 2, 35 * CleanXfac_1, s, + DTA_CleanNoMove_1, true); + } +} + +class CompatibilityMenu : OptionMenu +{ + override void Drawer () + { + Super.Drawer(); + + String s = String.Format("compatflags = %d compatflags2 = %d", compatflags, compatflags2); + screen.DrawText (OptionFont(), OptionMenuSettings.mFontColorValue, + (screen.GetWidth() - OptionWidth (s) * CleanXfac_1) / 2, 35 * CleanXfac_1, s, + DTA_CleanNoMove_1, true); + } +} + +//============================================================================= +// +// Placeholder classes for overhauled video mode menu. Do not use! +// Their sole purpose is to support mods with full copy of embedded MENUDEF +// +//============================================================================= + +class OptionMenuItemScreenResolution : OptionMenuItem +{ + String mResTexts[3]; + int mSelection; + int mHighlight; + int mMaxValid; + + enum EValues + { + SRL_INDEX = 0x30000, + SRL_SELECTION = 0x30003, + SRL_HIGHLIGHT = 0x30004, + }; + + OptionMenuItemScreenResolution Init(String command) + { + return self; + } + + override bool Selectable() + { + return false; + } +} + +class VideoModeMenu : OptionMenu +{ + static bool SetSelectedSize() + { + return false; + } +} + +class DoomMenuDelegate : MenuDelegateBase +{ + override void PlaySound(Name snd) + { + String s = snd; + S_StartSound (s, CHAN_VOICE, CHANF_UI, snd_menuvolume); + } +} diff --git a/wadsrc/static/zscript/ui/menu/listmenu.zs b/wadsrc/static/zscript/ui/menu/listmenu.zs deleted file mode 100644 index 66d20938129..00000000000 --- a/wadsrc/static/zscript/ui/menu/listmenu.zs +++ /dev/null @@ -1,277 +0,0 @@ - - -class ListMenuDescriptor : MenuDescriptor native -{ - native Array mItems; - native int mSelectedItem; - native double mSelectOfsX; - native double mSelectOfsY; - native TextureID mSelector; - native int mDisplayTop; - native double mXpos, mYpos; - native int mWLeft, mWRight; - native int mLinespacing; // needs to be stored for dynamically created menus - native int mAutoselect; // this can only be set by internal menu creation functions - native Font mFont; - native int mFontColor; - native int mFontColor2; - native bool mCenter; - - void Reset() - { - // Reset the default settings (ignore all other values in the struct) - mSelectOfsX = 0; - mSelectOfsY = 0; - mSelector.SetInvalid(); - mDisplayTop = 0; - mXpos = 0; - mYpos = 0; - mLinespacing = 0; - mNetgameMessage = ""; - mFont = NULL; - mFontColor = Font.CR_UNTRANSLATED; - mFontColor2 = Font.CR_UNTRANSLATED; - } -} - -//============================================================================= -// -// list menu class runs a menu described by a DListMenuDescriptor -// -//============================================================================= - -class ListMenu : Menu -{ - ListMenuDescriptor mDesc; - MenuItemBase mFocusControl; - - virtual void Init(Menu parent = NULL, ListMenuDescriptor desc = NULL) - { - Super.Init(parent); - mDesc = desc; - if (desc.mCenter) - { - double center = 160; - for(int i=0; i < mDesc.mItems.Size(); i++) - { - double xpos = mDesc.mItems[i].GetX(); - int width = mDesc.mItems[i].GetWidth(); - double curx = mDesc.mSelectOfsX; - - if (width > 0 && mDesc.mItems[i].Selectable()) - { - double left = 160 - (width - curx) / 2 - curx; - if (left < center) center = left; - } - } - for(int i=0;i 0) - { - mDesc.mItems[i].SetX(center); - } - } - } - // notify all items that the menu was just created. - for(int i=0;i 0) - { - // tolower - int ch = ev.KeyChar; - ch = ch >= 65 && ch < 91 ? ch + 32 : ch; - - for(int i = mDesc.mSelectedItem + 1; i < mDesc.mItems.Size(); i++) - { - if (mDesc.mitems[i].Selectable() && mDesc.mItems[i].CheckHotkey(ch)) - { - mDesc.mSelectedItem = i; - MenuSound("menu/cursor"); - return true; - } - } - for(int i = 0; i < mDesc.mSelectedItem; i++) - { - if (mDesc.mitems[i].Selectable() && mDesc.mItems[i].CheckHotkey(ch)) - { - mDesc.mSelectedItem = i; - MenuSound("menu/cursor"); - return true; - } - } - } - return Super.OnUIEvent(ev); - } - - //============================================================================= - // - // - // - //============================================================================= - - override bool MenuEvent (int mkey, bool fromcontroller) - { - int oldSelect = mDesc.mSelectedItem; - int startedAt = mDesc.mSelectedItem; - - switch (mkey) - { - case MKEY_Up: - do - { - if (--mDesc.mSelectedItem < 0) mDesc.mSelectedItem = mDesc.mItems.Size()-1; - } - while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt); - if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect; - MenuSound("menu/cursor"); - return true; - - case MKEY_Down: - do - { - if (++mDesc.mSelectedItem >= mDesc.mItems.Size()) mDesc.mSelectedItem = 0; - } - while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt); - if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect; - MenuSound("menu/cursor"); - return true; - - case MKEY_Enter: - if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate()) - { - MenuSound("menu/choose"); - } - return true; - - default: - return Super.MenuEvent(mkey, fromcontroller); - } - } - - //============================================================================= - // - // - // - //============================================================================= - - override bool MouseEvent(int type, int x, int y) - { - int sel = -1; - - // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture - x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160; - y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100; - - if (mFocusControl != NULL) - { - mFocusControl.MouseEvent(type, x, y); - return true; - } - else - { - if ((mDesc.mWLeft <= 0 || x > mDesc.mWLeft) && - (mDesc.mWRight <= 0 || x < mDesc.mWRight)) - { - for(int i=0;i= 0 && mDesc.mSelectedItem < mDesc.mItems.Size()) - mDesc.mItems[mDesc.mSelectedItem].DrawSelector(mDesc.mSelectOfsX, mDesc.mSelectOfsY, mDesc.mSelector); - Super.Drawer(); - } - - //============================================================================= - // - // - // - //============================================================================= - - override void SetFocus(MenuItemBase fc) - { - mFocusControl = fc; - } - override bool CheckFocus(MenuItemBase fc) - { - return mFocusControl == fc; - } - override void ReleaseFocus() - { - mFocusControl = NULL; - } -} - - diff --git a/wadsrc/static/zscript/ui/menu/listmenuitems.zs b/wadsrc/static/zscript/ui/menu/listmenuitems.zs deleted file mode 100644 index 16b75ad0d31..00000000000 --- a/wadsrc/static/zscript/ui/menu/listmenuitems.zs +++ /dev/null @@ -1,339 +0,0 @@ -/* -** listmenu.cpp -** A simple menu consisting of a list of items -** -**--------------------------------------------------------------------------- -** Copyright 2010-2017 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -**--------------------------------------------------------------------------- -** -*/ - - -class ListMenuItem : MenuItemBase -{ - virtual void DrawSelector(double xofs, double yofs, TextureID tex) - { - if (tex.isNull()) - { - if ((Menu.MenuTime() % 8) < 6) - { - screen.DrawText(ConFont, OptionMenuSettings.mFontColorSelection, - (mXpos + xofs - 160) * CleanXfac + screen.GetWidth() / 2, - (mYpos + yofs - 100) * CleanYfac + screen.GetHeight() / 2, - "\xd", - DTA_CellX, 8 * CleanXfac, - DTA_CellY, 8 * CleanYfac - ); - } - } - else - { - screen.DrawTexture (tex, true, mXpos + xofs, mYpos + yofs, DTA_Clean, true); - } - } -} - -//============================================================================= -// -// static patch -// -//============================================================================= - -class ListMenuItemStaticPatch : ListMenuItem -{ - TextureID mTexture; - bool mCentered; - String mSubstitute; - Font mFont; - int mColor; - - void Init(ListMenuDescriptor desc, double x, double y, TextureID patch, bool centered = false, String substitute = "") - { - Super.Init(x, y); - mTexture = patch; - mCentered = centered; - mSubstitute = substitute; - mFont = desc.mFont; - mColor = desc.mFontColor; - - } - - override void Drawer(bool selected) - { - if (!mTexture.Exists()) - { - return; - } - - let font = generic_ui? NewSmallFont : mFont; - - double x = mXpos; - Vector2 vec = TexMan.GetScaledSize(mTexture); - if (mYpos >= 0) - { - if (mSubstitute == "" || TexMan.OkForLocalization(mTexture, mSubstitute)) - { - if (mCentered) x -= vec.X / 2; - screen.DrawTexture (mTexture, true, x, mYpos, DTA_Clean, true); - } - else - { - if (mCentered) x -= font.StringWidth(mSubstitute)/2; - screen.DrawText(font, mColor, x, mYpos, mSubstitute, DTA_Clean, true); - } - } - else - { - x = (mXpos - 160) * CleanXfac + (Screen.GetWidth()>>1); - if (mSubstitute == "" || TexMan.OkForLocalization(mTexture, mSubstitute)) - { - if (mCentered) x -= (vec.X * CleanXfac)/2; - screen.DrawTexture (mTexture, true, x, -mYpos*CleanYfac, DTA_CleanNoMove, true); - } - else - { - if (mCentered) x -= (font.StringWidth(mSubstitute) * CleanXfac)/2; - screen.DrawText(font, mColor, x, mYpos, mSubstitute, DTA_CleanNoMove, true); - } - } - } -} - -class ListMenuItemStaticPatchCentered : ListMenuItemStaticPatch -{ - void Init(ListMenuDescriptor desc, double x, double y, TextureID patch) - { - Super.Init(desc, x, y, patch, true); - } -} - -//============================================================================= -// -// static text -// -//============================================================================= - -class ListMenuItemStaticText : ListMenuItem -{ - String mText; - Font mFont; - int mColor; - bool mCentered; - - void Init(ListMenuDescriptor desc, double x, double y, String text, int color = -1) - { - Super.Init(x, y); - mText = text; - mFont = desc.mFont; - mColor = color >= 0? color : desc.mFontColor; - mCentered = false; - } - - void InitDirect(double x, double y, String text, Font font, int color = Font.CR_UNTRANSLATED, bool centered = false) - { - Super.Init(x, y); - mText = text; - mFont = font; - mColor = color; - mCentered = centered; - } - - override void Drawer(bool selected) - { - if (mText.Length() != 0) - { - let font = generic_ui? NewSmallFont : mFont; - - String text = Stringtable.Localize(mText); - if (mYpos >= 0) - { - double x = mXpos; - if (mCentered) x -= font.StringWidth(text)/2; - screen.DrawText(font, mColor, x, mYpos, text, DTA_Clean, true); - } - else - { - double x = (mXpos - 160) * CleanXfac + (Screen.GetWidth() >> 1); - if (mCentered) x -= (font.StringWidth(text) * CleanXfac)/2; - screen.DrawText (font, mColor, x, -mYpos*CleanYfac, text, DTA_CleanNoMove, true); - } - } - } -} - -class ListMenuItemStaticTextCentered : ListMenuItemStaticText -{ - void Init(ListMenuDescriptor desc, double x, double y, String text, int color = -1) - { - Super.Init(desc, x, y, text, color); - mCentered = true; - } -} - -//============================================================================= -// -// selectable items -// -//============================================================================= - -class ListMenuItemSelectable : ListMenuItem -{ - int mHotkey; - int mHeight; - int mParam; - - protected void Init(double x, double y, int height, Name childmenu, int param = -1) - { - Super.Init(x, y, childmenu); - mHeight = height; - mParam = param; - mHotkey = 0; - } - - override bool CheckCoordinate(int x, int y) - { - return mEnabled && y >= mYpos && y < mYpos + mHeight; // no x check here - } - - override bool Selectable() - { - return mEnabled; - } - - override bool CheckHotkey(int c) - { - return c > 0 && c == mHotkey; - } - - override bool Activate() - { - Menu.SetMenu(mAction, mParam); - return true; - } - - override bool MouseEvent(int type, int x, int y) - { - if (type == Menu.MOUSE_Release) - { - let m = Menu.GetCurrentMenu(); - if (m != NULL && m.MenuEvent(Menu.MKEY_Enter, true)) - { - return true; - } - } - return false; - } - - override Name, int GetAction() - { - return mAction, mParam; - } -} - -//============================================================================= -// -// text item -// -//============================================================================= - -class ListMenuItemTextItem : ListMenuItemSelectable -{ - String mText; - Font mFont; - int mColor; - int mColorSelected; - - void Init(ListMenuDescriptor desc, String text, String hotkey, Name child, int param = 0) - { - Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, child, param); - mText = text; - mFont = desc.mFont; - mColor = desc.mFontColor; - mColorSelected = desc.mFontcolor2; - mHotkey = hotkey.GetNextCodePoint(0); - } - - void InitDirect(double x, double y, int height, String hotkey, String text, Font font, int color, int color2, Name child, int param = 0) - { - Super.Init(x, y, height, child, param); - mText = text; - mFont = font; - mColor = color; - mColorSelected = color2; - int pos = 0; - mHotkey = hotkey.GetNextCodePoint(0); - } - - override void Drawer(bool selected) - { - let font = generic_ui? NewSmallFont : mFont; - screen.DrawText(font, selected ? mColorSelected : mColor, mXpos, mYpos, mText, DTA_Clean, true); - } - - override int GetWidth() - { - let font = generic_ui? NewSmallFont : mFont; - return max(1, font.StringWidth(StringTable.Localize(mText))); - } -} - -//============================================================================= -// -// patch item -// -//============================================================================= - -class ListMenuItemPatchItem : ListMenuItemSelectable -{ - TextureID mTexture; - - void Init(ListMenuDescriptor desc, TextureID patch, String hotkey, Name child, int param = 0) - { - Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, child, param); - mHotkey = hotkey.GetNextCodePoint(0); - mTexture = patch; - } - - void InitDirect(double x, double y, int height, TextureID patch, String hotkey, Name child, int param = 0) - { - Super.Init(x, y, height, child, param); - mHotkey = hotkey.GetNextCodePoint(0); - mTexture = patch; - } - - override void Drawer(bool selected) - { - screen.DrawTexture (mTexture, true, mXpos, mYpos, DTA_Clean, true); - } - - override int GetWidth() - { - return TexMan.GetSize(mTexture); - } - -} - diff --git a/wadsrc/static/zscript/ui/menu/menu.zs b/wadsrc/static/zscript/ui/menu/menu.zs deleted file mode 100644 index eb54eb2744a..00000000000 --- a/wadsrc/static/zscript/ui/menu/menu.zs +++ /dev/null @@ -1,336 +0,0 @@ - -struct KeyBindings native version("2.4") -{ - native static String NameKeys(int k1, int k2); - - native int, int GetKeysForCommand(String cmd); - native void SetBind(int key, String cmd); - native void UnbindACommand (String str); -} - -struct OptionValues native version("2.4") -{ - native static int GetCount(Name group); - native static String GetText(Name group, int index); - native static double GetValue(Name group, int index); - native static String GetTextValue(Name group, int index); -} - -struct JoystickConfig native version("2.4") -{ - enum EJoyAxis - { - JOYAXIS_None = -1, - JOYAXIS_Yaw, - JOYAXIS_Pitch, - JOYAXIS_Forward, - JOYAXIS_Side, - JOYAXIS_Up, - // JOYAXIS_Roll, // Ha ha. No roll for you. - NUM_JOYAXIS, - }; - - native float GetSensitivity(); - native void SetSensitivity(float scale); - - native float GetAxisScale(int axis); - native void SetAxisScale(int axis, float scale); - - native float GetAxisDeadZone(int axis); - native void SetAxisDeadZone(int axis, float zone); - - native int GetAxisMap(int axis); - native void SetAxisMap(int axis, int gameaxis); - - native String GetName(); - native int GetNumAxes(); - native String GetAxisName(int axis); - -} - -class Menu : Object native ui version("2.4") -{ - enum EMenuKey - { - MKEY_Up, - MKEY_Down, - MKEY_Left, - MKEY_Right, - MKEY_PageUp, - MKEY_PageDown, - MKEY_Enter, - MKEY_Back, - MKEY_Clear, - NUM_MKEYS, - - // These are not buttons but events sent from other menus - - MKEY_Input, - MKEY_Abort, - MKEY_MBYes, - MKEY_MBNo, - } - - enum EMenuMouse - { - MOUSE_Click, - MOUSE_Move, - MOUSE_Release - }; - - enum EMenuState - { - Off, // Menu is closed - On, // Menu is opened - WaitKey, // Menu is opened and waiting for a key in the controls menu - OnNoPause, // Menu is opened but does not pause the game - }; - - native Menu mParentMenu; - native bool mMouseCapture; - native bool mBackbuttonSelected; - native bool DontDim; - native bool DontBlur; - - native static int MenuTime(); - native static Menu GetCurrentMenu(); - native static clearscope void SetMenu(Name mnu, int param = 0); // This is not 100% safe but needs to be available - but always make sure to check that only the desired player opens it! - native static void StartMessage(String msg, int mode = 0, Name command = 'none'); - native static void SetMouseCapture(bool on); - native void Close(); - native void ActivateMenu(); - native static void UpdateColorsets(PlayerClass cls); - native static void UpdateSkinOptions(PlayerClass cls); - - //============================================================================= - // - // - // - //============================================================================= - - void Init(Menu parent) - { - mParentMenu = parent; - mMouseCapture = false; - mBackbuttonSelected = false; - DontDim = false; - DontBlur = false; - } - - //============================================================================= - // - // - // - //============================================================================= - - virtual bool MenuEvent (int mkey, bool fromcontroller) - { - switch (mkey) - { - case MKEY_Back: - Close(); - MenuSound (GetCurrentMenu() != null? "menu/backup" : "menu/clear"); - return true; - } - return false; - } - - - //============================================================================= - // - // - // - //============================================================================= - - protected bool MouseEventBack(int type, int x, int y) - { - if (m_show_backbutton >= 0) - { - let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch); - if (tex.IsValid()) - { - Vector2 v = TexMan.GetScaledSize(tex); - int w = int(v.X + 0.5) * CleanXfac; - int h = int(v.Y + 0.5) * CleanYfac; - if (m_show_backbutton&1) x -= screen.GetWidth() - w; - if (m_show_backbutton&2) y -= screen.GetHeight() - h; - mBackbuttonSelected = ( x >= 0 && x < w && y >= 0 && y < h); - if (mBackbuttonSelected && type == MOUSE_Release) - { - if (m_use_mouse == 2) mBackbuttonSelected = false; - MenuEvent(MKEY_Back, true); - } - return mBackbuttonSelected; - } - } - return false; - } - - //============================================================================= - // - // - // - //============================================================================= - - virtual bool OnUIEvent(UIEvent ev) - { - bool res = false; - int y = ev.MouseY; - if (ev.type == UIEvent.Type_LButtonDown) - { - res = MouseEventBack(MOUSE_Click, ev.MouseX, y); - // make the menu's mouse handler believe that the current coordinate is outside the valid range - if (res) y = -1; - res |= MouseEvent(MOUSE_Click, ev.MouseX, y); - if (res) - { - SetCapture(true); - } - - } - else if (ev.type == UIEvent.Type_MouseMove) - { - BackbuttonTime = 4*Thinker.TICRATE; - if (mMouseCapture || m_use_mouse == 1) - { - res = MouseEventBack(MOUSE_Move, ev.MouseX, y); - if (res) y = -1; - res |= MouseEvent(MOUSE_Move, ev.MouseX, y); - } - } - else if (ev.type == UIEvent.Type_LButtonUp) - { - if (mMouseCapture) - { - SetCapture(false); - res = MouseEventBack(MOUSE_Release, ev.MouseX, y); - if (res) y = -1; - res |= MouseEvent(MOUSE_Release, ev.MouseX, y); - } - } - return false; - } - - virtual bool OnInputEvent(InputEvent ev) - { - return false; - } - - //============================================================================= - // - // - // - //============================================================================= - - virtual void Drawer () - { - if (self == GetCurrentMenu() && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse) - { - let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch); - if (tex.IsValid()) - { - Vector2 v = TexMan.GetScaledSize(tex); - int w = int(v.X + 0.5) * CleanXfac; - int h = int(v.Y + 0.5) * CleanYfac; - int x = (!(m_show_backbutton&1))? 0:screen.GetWidth() - w; - int y = (!(m_show_backbutton&2))? 0:screen.GetHeight() - h; - if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1)) - { - screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, Color(40, 255,255,255)); - } - else - { - screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha); - } - } - } - } - - //============================================================================= - // - // - // - //============================================================================= - - void SetCapture(bool on) - { - if (mMouseCapture != on) - { - mMouseCapture = on; - SetMouseCapture(on); - } - } - - //============================================================================= - // - // - // - //============================================================================= - - virtual bool TranslateKeyboardEvents() { return true; } - virtual void SetFocus(MenuItemBase fc) {} - virtual bool CheckFocus(MenuItemBase fc) { return false; } - virtual void ReleaseFocus() {} - virtual void ResetColor() {} - virtual bool MouseEvent(int type, int mx, int my) { return true; } - virtual void Ticker() {} - virtual void OnReturn() {} - - //============================================================================= - // - // - // - //============================================================================= - - static void MenuSound(Sound snd) - { - S_StartSound (snd, CHAN_VOICE, CHANF_MAYBE_LOCAL|CHAN_UI, snd_menuvolume, ATTN_NONE); - } - - deprecated("4.0") static void DrawConText (int color, int x, int y, String str) - { - screen.DrawText (ConFont, color, x, y, str, DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); - } - - static Font OptionFont() - { - return NewSmallFont; - } - - static int OptionHeight() - { - return OptionFont().GetHeight(); - } - - static int OptionWidth(String s) - { - return OptionFont().StringWidth(s); - } - - static void DrawOptionText(int x, int y, int color, String text, bool grayed = false) - { - String label = Stringtable.Localize(text); - int overlay = grayed? Color(96,48,0,0) : 0; - screen.DrawText (OptionFont(), color, x, y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay); - } - - -} - -class MenuDescriptor : Object native ui version("2.4") -{ - native Name mMenuName; - native String mNetgameMessage; - native Class mClass; - - native static MenuDescriptor GetDescriptor(Name n); -} - -// This class is only needed to give it a virtual Init method that doesn't belong to Menu itself -class GenericMenu : Menu -{ - virtual void Init(Menu parent) - { - Super.Init(parent); - } -} \ No newline at end of file diff --git a/wadsrc/static/zscript/ui/menu/newplayermenu.zs b/wadsrc/static/zscript/ui/menu/newplayermenu.zs index 53ae647b467..82214036be5 100644 --- a/wadsrc/static/zscript/ui/menu/newplayermenu.zs +++ b/wadsrc/static/zscript/ui/menu/newplayermenu.zs @@ -408,6 +408,9 @@ class OptionMenuItemPlayerSwitchOnPickupItem : OptionMenuItemOptionBase class NewPlayerMenu : OptionMenu { + protected native static void UpdateColorsets(PlayerClass cls); + protected native static void UpdateSkinOptions(PlayerClass cls); + PlayerClass mPlayerClass; int mRotation; PlayerMenuPlayerDisplay mPlayerDisplay; diff --git a/wadsrc/static/zscript/ui/menu/playercontrols.zs b/wadsrc/static/zscript/ui/menu/playercontrols.zs index 51a59101727..5e96733e0a3 100644 --- a/wadsrc/static/zscript/ui/menu/playercontrols.zs +++ b/wadsrc/static/zscript/ui/menu/playercontrols.zs @@ -505,7 +505,7 @@ class ListMenuItemSlider : ListMenuItemSelectable x = (x - 160) * CleanXfac + screen.GetWidth() / 2; y = (y - 100) * CleanYfac + screen.GetHeight() / 2; - screen.DrawText (ConFont, Font.CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); + screen.DrawText (ConFont, Font.FindFontColor(gameinfo.mSliderBackColor), x, y, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); screen.DrawText (ConFont, Font.FindFontColor(gameinfo.mSliderColor), x + (5 + (int)((cur * 78) / range)) * CleanXfac, y, "\x13", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); } diff --git a/wadsrc/static/zscript/ui/menu/playerdisplay.zs b/wadsrc/static/zscript/ui/menu/playerdisplay.zs index 557185d1d73..acb2f3b0541 100644 --- a/wadsrc/static/zscript/ui/menu/playerdisplay.zs +++ b/wadsrc/static/zscript/ui/menu/playerdisplay.zs @@ -228,7 +228,7 @@ class ListMenuItemPlayerDisplay : ListMenuItem // //============================================================================= - override void Drawer(bool selected) + override void Draw(bool selected, ListMenuDescriptor desc) { if (mMode == 0 && !UpdatePlayerClass()) { @@ -241,12 +241,31 @@ class ListMenuItemPlayerDisplay : ListMenuItem if (portrait != 'None' && !mNoportrait) { TextureID texid = TexMan.CheckForTexture(portrait, TexMan.Type_MiscPatch); - screen.DrawTexture (texid, true, mXpos, mYpos, DTA_Clean, true); + DrawTexture (desc, texid, mXpos, mYpos); } else { - int x = int(mXpos - 160) * CleanXfac + (screen.GetWidth() >> 1); - int y = int(mYpos - 100) * CleanYfac + (screen.GetHeight() >> 1); + // Here we need to calculate the coordinates manually because Screen.DrawFrame only works in window coordinates and have to match the rest to it. + int x, y; + int w = desc.DisplayWidth(); + int h = desc.DisplayHeight(); + double sx, sy; + if (w == ListMenuDescriptor.CleanScale) + { + x = int(mXpos - 160) * CleanXfac + (screen.GetWidth() >> 1); + y = int(mYpos - 100) * CleanYfac + (screen.GetHeight() >> 1); + sx = CleanXfac; + sy = CleanYfac; + } + else + { + double fx, fy, fw, fh; + [fx, fy, fw, fh] = Screen.GetFullscreenRect(w, h, FSMode_ScaleToFit43); + sx = fw / w; + sy = fh / h; + x = int(fx + mXpos * sx); + y = int(fy + mYpos * sy); + } int r = mBaseColor.r + mAddColor.r; int g = mBaseColor.g + mAddColor.g; @@ -258,12 +277,12 @@ class ListMenuItemPlayerDisplay : ListMenuItem Color c = Color(255, r, g, b); screen.DrawTexture(mBackdrop, false, x, y - 1, - DTA_DestWidth, 72 * CleanXfac, - DTA_DestHeight, 80 * CleanYfac, + DTA_DestWidthF, 72. * sx, + DTA_DestHeightF, 80. * sy, DTA_Color, c, DTA_Masked, true); - Screen.DrawFrame (x, y, 72*CleanXfac, 80*CleanYfac-1); + Screen.DrawFrame (x, y, int(72*sx), int(80*sy-1)); if (mPlayerState != NULL) { @@ -275,13 +294,13 @@ class ListMenuItemPlayerDisplay : ListMenuItem if (sprite.IsValid()) { - int trans = mTranslate? Translation.MakeID(TRANSLATION_Players, MAXPLAYERS) : 0; + let trans = mTranslate? Translation.MakeID(TRANSLATION_Players, MAXPLAYERS) : 0; let tscale = TexMan.GetScaledSize(sprite); - Scale.X *= CleanXfac * tscale.X; - Scale.Y *= CleanYfac * tscale.Y; + Scale.X *= sx * tscale.X; + Scale.Y *= sy * tscale.Y; screen.DrawTexture (sprite, false, - x + 36*CleanXfac, y + 71*CleanYfac, + x + 36*sx, y + 71*sy, DTA_DestWidthF, Scale.X, DTA_DestHeightF, Scale.Y, DTA_TranslationIndex, trans, DTA_FlipX, flip); @@ -338,7 +357,7 @@ class PlayerMenuPlayerDisplay : ListMenuItemPlayerDisplay if (sprite.IsValid()) { - int trans = mTranslate? Translation.MakeID(TRANSLATION_Players, MAXPLAYERS) : 0; + let trans = mTranslate? Translation.MakeID(TRANSLATION_Players, MAXPLAYERS) : 0; let tscale = TexMan.GetScaledSize(sprite); Scale.X *= CleanXfac_1 * tscale.X * 2; Scale.Y *= CleanYfac_1 * tscale.Y * 2; diff --git a/wadsrc/static/zscript/ui/menu/playermenu.zs b/wadsrc/static/zscript/ui/menu/playermenu.zs index 6404ac71330..85a4b944bea 100644 --- a/wadsrc/static/zscript/ui/menu/playermenu.zs +++ b/wadsrc/static/zscript/ui/menu/playermenu.zs @@ -33,6 +33,11 @@ ** */ +extend class Menu +{ + static native void StartGameDirect(bool hasPlayerClass, bool randomPlayerClass, Class playerClass, int Episode, int Skill); +} + class PlayerMenu : ListMenu { int mRotation; diff --git a/wadsrc/static/zscript/ui/menu/readthis.zs b/wadsrc/static/zscript/ui/menu/readthis.zs index 58904b0f4e8..59ea658ffc3 100644 --- a/wadsrc/static/zscript/ui/menu/readthis.zs +++ b/wadsrc/static/zscript/ui/menu/readthis.zs @@ -74,7 +74,7 @@ class ReadThisMenu : GenericMenu } screen.Dim(0, 1.0, 0,0, screen.GetWidth(), screen.GetHeight()); - alpha = MIN((gametic - mInfoTic) * (3. / Thinker.TICRATE), 1.); + alpha = MIN((gametic - mInfoTic) * (3. / GameTicRate), 1.); if (alpha < 1. && prevpic.IsValid()) { screen.DrawTexture (prevpic, false, 0, 0, DTA_Fullscreen, true); diff --git a/wadsrc/static/zscript/ui/menu/search/menu.zs b/wadsrc/static/zscript/ui/menu/search/menu.zs deleted file mode 100644 index 46efc0c6a8a..00000000000 --- a/wadsrc/static/zscript/ui/menu/search/menu.zs +++ /dev/null @@ -1,218 +0,0 @@ -//============================================================================= -// -// Option Search Menu class. -// This menu contains search field, and is dynamically filled with search -// results. -// -//============================================================================= - -class os_Menu : OptionMenu -{ - override void Init(Menu parent, OptionMenuDescriptor desc) - { - Super.Init(parent, desc); - - mDesc.mItems.clear(); - - addSearchField(); - - mDesc.mScrollPos = 0; - mDesc.mSelectedItem = 0; - mDesc.CalcIndent(); - } - - void search() - { - string text = mSearchField.GetText(); - let query = os_Query.fromString(text); - bool isAnyTermMatches = mIsAnyOfItem.mCVar.GetBool(); - - mDesc.mItems.clear(); - - addSearchField(text); - - bool found = listOptions(mDesc, "MainMenu", query, "", isAnyTermMatches); - - if (!found) { addNoResultsItem(mDesc); } - - mDesc.CalcIndent(); - } - - private void addSearchField(string query = "") - { - string searchLabel = StringTable.Localize("$OS_LABEL"); - - mSearchField = new("os_SearchField").Init(searchLabel, self, query); - mIsAnyOfItem = new("os_AnyOrAllOption").Init(self); - - mDesc.mItems.push(mSearchField); - mDesc.mItems.push(mIsAnyOfItem); - addEmptyLine(mDesc); - } - - private static bool listOptions(OptionMenuDescriptor targetDesc, - string menuName, - os_Query query, - string path, - bool isAnyTermMatches) - { - let desc = MenuDescriptor.GetDescriptor(menuName); - let listMenuDesc = ListMenuDescriptor(desc); - - if (listMenuDesc) - { - return listOptionsListMenu(listMenuDesc, targetDesc, query, path, isAnyTermMatches); - } - - let optionMenuDesc = OptionMenuDescriptor(desc); - - if (optionMenuDesc) - { - return listOptionsOptionMenu(optionMenuDesc, targetDesc, query, path, isAnyTermMatches); - } - - return false; - } - - private static bool listOptionsListMenu(ListMenuDescriptor sourceDesc, - OptionMenuDescriptor targetDesc, - os_Query query, - string path, - bool isAnyTermMatches) - { - int nItems = sourceDesc.mItems.size(); - bool found = false; - - for (int i = 0; i < nItems; ++i) - { - let item = sourceDesc.mItems[i]; - string actionN = item.GetAction(); - let textItem = ListMenuItemTextItem(item); - string newPath = textItem - ? makePath(path, StringTable.Localize(textItem.mText)) - : path; - - found |= listOptions(targetDesc, actionN, query, newPath, isAnyTermMatches); - } - - return found; - } - - private static bool listOptionsOptionMenu(OptionMenuDescriptor sourceDesc, - OptionMenuDescriptor targetDesc, - os_Query query, - string path, - bool isAnyTermMatches) - { - if (sourceDesc == targetDesc) { return false; } - - int nItems = sourceDesc.mItems.size(); - bool first = true; - bool found = false; - - for (int i = 0; i < nItems; ++i) - { - let item = sourceDesc.mItems[i]; - - if (item is "OptionMenuItemStaticText") { continue; } - - string label = StringTable.Localize(item.mLabel); - - if (!query.matches(label, isAnyTermMatches)) { continue; } - - found = true; - - if (first) - { - addEmptyLine(targetDesc); - addPathItem(targetDesc, path); - - first = false; - } - - let itemOptionBase = OptionMenuItemOptionBase(item); - - if (itemOptionBase) - { - itemOptionBase.mCenter = false; - } - - targetDesc.mItems.push(item); - } - - for (int i = 0; i < nItems; ++i) - { - let item = sourceDesc.mItems[i]; - string label = StringTable.Localize(item.mLabel); - string optionSearchTitle = StringTable.Localize("$OS_TITLE"); - - if (label == optionSearchTitle) { continue; } - - if (item is "OptionMenuItemSubMenu") - { - string newPath = makePath(path, label); - - found |= listOptions(targetDesc, item.GetAction(), query, newPath, isAnyTermMatches); - } - } - - return found; - } - - private static string makePath(string path, string label) - { - if (path.length() == 0) { return label; } - - int pathWidth = SmallFont.StringWidth(path .. "/" .. label); - int screenWidth = Screen.GetWidth(); - bool isTooWide = (pathWidth > screenWidth / 3); - string newPath = isTooWide - ? path .. "/" .. "\n" .. label - : path .. "/" .. label; - - return newPath; - } - - private static void addPathItem(OptionMenuDescriptor desc, string path) - { - Array lines; - path.split(lines, "\n"); - - int nLines = lines.size(); - - for (int i = 0; i < nLines; ++i) - { - OptionMenuItemStaticText text = new("OptionMenuItemStaticText").Init(lines[i], 1); - - desc.mItems.push(text); - } - } - - private static void addEmptyLine(OptionMenuDescriptor desc) - { - int nItems = desc.mItems.size(); - - if (nItems > 0) - { - let staticText = OptionMenuItemStaticText(desc.mItems[nItems - 1]); - - if (staticText != null && staticText.mLabel == "") { return; } - } - - let item = new("OptionMenuItemStaticText").Init(""); - - desc.mItems.push(item); - } - - private static void addNoResultsItem(OptionMenuDescriptor desc) - { - string noResults = StringTable.Localize("$OS_NO_RESULTS"); - let text = new("OptionMenuItemStaticText").Init(noResults, 0); - - addEmptyLine(desc); - desc.mItems.push(text); - } - - private os_AnyOrAllOption mIsAnyOfItem; - private os_SearchField mSearchField; -} diff --git a/wadsrc/static/zscript/ui/statscreen/statscreen.zs b/wadsrc/static/zscript/ui/statscreen/statscreen.zs index 6b7119ae5f8..4b50f0cf7b9 100644 --- a/wadsrc/static/zscript/ui/statscreen/statscreen.zs +++ b/wadsrc/static/zscript/ui/statscreen/statscreen.zs @@ -1,6 +1,6 @@ // Note that the status screen needs to run in 'play' scope! -class InterBackground native play version("2.5") +class InterBackground native ui version("2.5") { native static InterBackground Create(wbstartstruct wbst); native virtual bool LoadBackground(bool isenterpic); @@ -9,7 +9,7 @@ class InterBackground native play version("2.5") } // This is obsolete. Hopefully this was never used... -struct PatchInfo play version("2.5") +struct PatchInfo ui version("2.5") { Font mFont; deprecated("3.8") TextureID mPatch; @@ -39,8 +39,7 @@ struct PatchInfo play version("2.5") }; -// Will be made a class later, but for now needs to mirror the internal version. -class StatusScreen abstract play version("2.5") +class StatusScreen : ScreenJob abstract version("2.5") { enum EValues { @@ -86,7 +85,9 @@ class StatusScreen abstract play version("2.5") int CurState; // specifies current CurState wbstartstruct wbs; // contains information passed into intermission wbplayerstruct Plrs[MAXPLAYERS]; // wbs.plyr[] + int otherkills; int cnt; // used for general timing + int cnt_otherkills; int cnt_kills[MAXPLAYERS]; int cnt_items[MAXPLAYERS]; int cnt_secret[MAXPLAYERS]; @@ -104,7 +105,7 @@ class StatusScreen abstract play version("2.5") float shadowalpha; PatchInfo mapname; - PatchInfo finished; + PatchInfo finishedp; PatchInfo entering; PatchInfo content; PatchInfo author; @@ -127,7 +128,28 @@ class StatusScreen abstract play version("2.5") int player_deaths[MAXPLAYERS]; int sp_state; + + int cWidth, cHeight; // size of the canvas + int scalemode; + int wrapwidth; // size used to word wrap level names + int scaleFactorX, scaleFactorY; + + + //==================================================================== + // + // Set fixed size mode. + // + //==================================================================== + void SetSize(int width, int height, int wrapw = -1, int scalemode = FSMode_ScaleToFit43) + { + cwidth = width; + cheight = height; + scalemode = FSMode_ScaleToFit43; + scalefactorx = 1; + scalefactory = 1; + wrapwidth = wrapw == -1 ? width : wrapw; + } //==================================================================== // @@ -138,9 +160,34 @@ class StatusScreen abstract play version("2.5") int DrawCharPatch(Font fnt, int charcode, int x, int y, int translation = Font.CR_UNTRANSLATED, bool nomove = false) { int width = fnt.GetCharWidth(charcode); - screen.DrawChar(fnt, translation, x, y, charcode, nomove ? DTA_CleanNoMove : DTA_Clean, true); + if (scalemode == -1) screen.DrawChar(fnt, translation, x, y, charcode, nomove ? DTA_CleanNoMove : DTA_Clean, true); + else screen.DrawChar(fnt, translation, x, y, charcode, DTA_FullscreenScale, scalemode, DTA_VirtualWidth, cwidth, DTA_VirtualHeight, cheight); return x - width; } + + //==================================================================== + // + // + // + //==================================================================== + + void DrawTexture(TextureID tex, double x, double y, bool nomove = false) + { + if (scalemode == -1) screen.DrawTexture(tex, true, x, y, nomove ? DTA_CleanNoMove : DTA_Clean, true); + else screen.DrawTexture(tex, true, x, y, DTA_FullscreenScale, scalemode, DTA_VirtualWidth, cwidth, DTA_VirtualHeight, cheight); + } + + //==================================================================== + // + // + // + //==================================================================== + + void DrawText(Font fnt, int color, double x, double y, String str, bool nomove = false, bool shadow = false) + { + if (scalemode == -1) screen.DrawText(fnt, color, x, y, str, nomove ? DTA_CleanNoMove : DTA_Clean, true, DTA_Shadow, shadow); + else screen.DrawText(fnt, color, x, y, str, DTA_FullscreenScale, scalemode, DTA_VirtualWidth, cwidth, DTA_VirtualHeight, cheight, DTA_Shadow, shadow); + } //==================================================================== // @@ -157,25 +204,25 @@ class StatusScreen abstract play version("2.5") if (tex.isValid()) { let size = TexMan.GetScaledSize(tex); - screen.DrawTexture(tex, true, (screen.GetWidth() - size.X * CleanXfac) /2, y, DTA_CleanNoMove, true); + DrawTexture(tex, (cwidth - size.X * scaleFactorX) /2, y, true); if (size.Y > 50) { // Fix for Deus Vult II and similar wads that decide to make these hugely tall // patches with vast amounts of empty space at the bottom. size.Y = TexMan.CheckRealHeight(tex); } - return y + int(Size.Y) * CleanYfac; + return y + int(Size.Y) * scaleFactorY; } else if (levelname.Length() > 0) { int h = 0; - int lumph = mapname.mFont.GetHeight() * CleanYfac; + int lumph = mapname.mFont.GetHeight() * scaleFactorY; - BrokenLines lines = mapname.mFont.BreakLines(levelname, screen.GetWidth() / CleanXfac); + BrokenLines lines = mapname.mFont.BreakLines(levelname, wrapwidth / scaleFactorX); int count = lines.Count(); for (int i = 0; i < count; i++) { - screen.DrawText(mapname.mFont, mapname.mColor, (screen.GetWidth() - lines.StringWidth(i) * CleanXfac) / 2, y + h, lines.StringAt(i), DTA_CleanNoMove, true); + DrawText(mapname.mFont, mapname.mColor, (cwidth - lines.StringWidth(i) * scaleFactorX) / 2, y + h, lines.StringAt(i), true); h += lumph; } return y + h; @@ -185,7 +232,7 @@ class StatusScreen abstract play version("2.5") //==================================================================== // - // Draws a level author's name with the big font + // Draws a level author's name with the given font // //==================================================================== @@ -194,14 +241,14 @@ class StatusScreen abstract play version("2.5") if (levelname.Length() > 0) { int h = 0; - int lumph = author.mFont.GetHeight() * CleanYfac; + int lumph = author.mFont.GetHeight() * scaleFactorY; - BrokenLines lines = author.mFont.BreakLines(levelname, screen.GetWidth() / CleanXfac); + BrokenLines lines = author.mFont.BreakLines(levelname, wrapwidth / scaleFactorX); int count = lines.Count(); for (int i = 0; i < count; i++) { - screen.DrawText(author.mFont, author.mColor, (screen.GetWidth() - lines.StringWidth(i) * CleanXfac) / 2, y + h, lines.StringAt(i), DTA_CleanNoMove, true); + DrawText(author.mFont, author.mColor, (cwidth - lines.StringWidth(i) * scaleFactorX) / 2, y + h, lines.StringAt(i), true); h += lumph; } return y + h; @@ -233,22 +280,21 @@ class StatusScreen abstract play version("2.5") int DrawPatchOrText(int y, PatchInfo pinfo, TextureID patch, String stringname) { String string = Stringtable.Localize(stringname); - int midx = screen.GetWidth() / 2; + int midx = cwidth / 2; if (TexMan.OkForLocalization(patch, stringname)) { let size = TexMan.GetScaledSize(patch); - screen.DrawTexture(patch, true, midx - size.X * CleanXfac/2, y, DTA_CleanNoMove, true); - return y + int(size.Y * CleanYfac); + DrawTexture(patch, midx - size.X * scaleFactorX/2, y, true); + return y + int(size.Y * scaleFactorY); } else { - screen.DrawText(pinfo.mFont, pinfo.mColor, midx - pinfo.mFont.StringWidth(string) * CleanXfac/2, y, string, DTA_CleanNoMove, true); - return y + pinfo.mFont.GetHeight() * CleanYfac; + DrawText(pinfo.mFont, pinfo.mColor, midx - pinfo.mFont.StringWidth(string) * scaleFactorX/2, y, string, true); + return y + pinfo.mFont.GetHeight() * scaleFactorY; } } - //==================================================================== // // Draws " Finished!" @@ -261,7 +307,7 @@ class StatusScreen abstract play version("2.5") virtual int drawLF () { bool ispatch = wbs.LName0.isValid(); - int oldy = TITLEY * CleanYfac; + int oldy = TITLEY * scaleFactorY; int h; if (!ispatch) @@ -269,7 +315,7 @@ class StatusScreen abstract play version("2.5") let asc = mapname.mFont.GetMaxAscender(lnametexts[1]); if (asc > TITLEY - 2) { - oldy = (asc+2) * CleanYfac; + oldy = (asc+2) * scaleFactorY; } } @@ -283,35 +329,34 @@ class StatusScreen abstract play version("2.5") if (authortexts[0].length() == 0) { int h1 = BigFont.GetHeight() - BigFont.GetDisplacement(); - int h2 = (y - oldy) / CleanYfac / 4; + int h2 = (y - oldy) / scaleFactorY / 4; disp = min(h1, h2); if (!TexMan.OkForLocalization(finishedPatch, "$WI_FINISHED")) { - disp += finished.mFont.GetMaxAscender("$WI_FINISHED"); + disp += finishedp.mFont.GetMaxAscender("$WI_FINISHED"); } } else { disp += author.mFont.GetMaxAscender(authortexts[0]); } - y += disp * CleanYfac; + y += disp * scaleFactorY; } y = DrawAuthor(y, authortexts[0]); // draw "Finished!" - int statsy = multiplayer? NG_STATSY : SP_STATSY * CleanYFac; - if (y < (statsy - finished.mFont.GetHeight()*3/4) * CleanYfac) + int statsy = multiplayer? NG_STATSY : SP_STATSY * scaleFactorY; + if (y < (statsy - finishedp.mFont.GetHeight()*3/4) * scaleFactorY) { // don't draw 'finished' if the level name is too tall - y = DrawPatchOrText(y, finished, finishedPatch, "$WI_FINISHED"); + y = DrawPatchOrText(y, finishedp, finishedPatch, "$WI_FINISHED"); } return y; } - //==================================================================== // // Draws "Entering " @@ -324,14 +369,14 @@ class StatusScreen abstract play version("2.5") virtual void drawEL () { bool ispatch = TexMan.OkForLocalization(enteringPatch, "$WI_ENTERING"); - int oldy = TITLEY * CleanYfac; + int oldy = TITLEY * scaleFactorY; if (!ispatch) { let asc = entering.mFont.GetMaxAscender("$WI_ENTERING"); if (asc > TITLEY - 2) { - oldy = (asc+2) * CleanYfac; + oldy = (asc+2) * scaleFactorY; } } @@ -350,7 +395,7 @@ class StatusScreen abstract play version("2.5") { disp += mapname.mFont.GetMaxAscender(lnametexts[1]); } - y += disp * CleanYfac; + y += disp * scaleFactorY; } y = DrawName(y, wbs.LName1, lnametexts[1]); @@ -358,14 +403,13 @@ class StatusScreen abstract play version("2.5") if (wbs.LName1.isValid() && authortexts[1].length() > 0) { // Consdider the ascender height of the following text. - y += author.mFont.GetMaxAscender(authortexts[1]) * CleanYfac; + y += author.mFont.GetMaxAscender(authortexts[1]) * scaleFactorY; } DrawAuthor(y, authortexts[1]); } - //==================================================================== // // Draws a number. @@ -381,9 +425,9 @@ class StatusScreen abstract play version("2.5") String text; int len; - if (nomove) + if (nomove && scalemode == -1) { - fntwidth *= CleanXfac; + fntwidth *= scaleFactorX; } text = String.Format("%d", n); len = text.Length(); @@ -433,35 +477,76 @@ class StatusScreen abstract play version("2.5") if (wi_percents) { - if (nomove) + if (nomove && scalemode == -1) { - x -= fnt.StringWidth("%") * CleanXfac; + x -= fnt.StringWidth("%") * scaleFactorX; } else { x -= fnt.StringWidth("%"); } - screen.DrawText(fnt, color, x, y, "%", nomove? DTA_CleanNoMove : DTA_Clean, true); + DrawText(fnt, color, x, y, "%", nomove); if (nomove) { x -= 2*CleanXfac; } - drawNum(fnt, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color); + drawNum(fnt, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color, nomove); } else { if (show_total) { - x = drawNum(fnt, x, y, b, 2, false, color); + x = drawNum(fnt, x, y, b, 2, false, color, nomove); x -= fnt.StringWidth("/"); - screen.DrawText (fnt, color, x, y, "/", nomove? DTA_CleanNoMove : DTA_Clean, true); + DrawText (fnt, color, x, y, "/", nomove); } - drawNum (fnt, x, y, p, -1, false, color); + drawNum (fnt, x, y, p, -1, false, color, nomove); } } + //==================================================================== // + // Display level completion time and par, or "sucks" message if overflow. + // + //==================================================================== + + void drawTimeFont (Font printFont, int x, int y, int t, int color) + { + bool sucky; + + if (t < 0) + return; + + int hours = t / 3600; + t -= hours * 3600; + int minutes = t / 60; + t -= minutes * 60; + int seconds = t; + + // Why were these offsets hard coded? Half the WADs with custom patches + // I tested screwed up miserably in this function! + int num_spacing = printFont.GetCharWidth("3"); + int colon_spacing = printFont.GetCharWidth(":"); + + x = drawNum (printFont, x, y, seconds, 2, true, color) - 1; + DrawCharPatch (printFont, ":", x -= colon_spacing, y, color); + x = drawNum (printFont, x, y, minutes, 2, hours!=0, color); + if (hours) + { + DrawCharPatch (printFont, ":", x -= colon_spacing, y, color); + drawNum (printFont, x, y, hours, 2, false, color); + } + } + + void drawTime (int x, int y, int t, bool no_sucks=false) + { + drawTimeFont(IntermissionFont, x, y, t, Font.CR_UNTRANSLATED); + } + + //==================================================================== + // + // the 'scaled' drawers are for the multiplayer scoreboard // //==================================================================== @@ -509,14 +594,12 @@ class StatusScreen abstract play version("2.5") //==================================================================== // - // Display level completion time and par, or "sucks" message if overflow. + // Display the completed time scaled // //==================================================================== - void drawTimeFont (Font printFont, int x, int y, int t, int color) + void drawTimeScaled (Font fnt, int x, int y, int t, double scale, int color = Font.CR_UNTRANSLATED) { - bool sucky; - if (t < 0) return; @@ -526,26 +609,10 @@ class StatusScreen abstract play version("2.5") t -= minutes * 60; int seconds = t; - // Why were these offsets hard coded? Half the WADs with custom patches - // I tested screwed up miserably in this function! - int num_spacing = printFont.GetCharWidth("3"); - int colon_spacing = printFont.GetCharWidth(":"); - - x = drawNum (printFont, x, y, seconds, 2, true, color) - 1; - DrawCharPatch (printFont, ":", x -= colon_spacing, y, color); - x = drawNum (printFont, x, y, minutes, 2, hours!=0, color); - if (hours) - { - DrawCharPatch (printFont, ":", x -= colon_spacing, y, color); - drawNum (printFont, x, y, hours, 2, false, color); - } - } + String s = (hours > 0 ? String.Format("%d:", hours) : "") .. String.Format("%02d:%02d", minutes, seconds); - void drawTime (int x, int y, int t, bool no_sucks=false) - { - drawTimeFont(IntermissionFont, x, y, t, Font.CR_UNTRANSLATED); + drawTextScaled(fnt, x - fnt.StringWidth(s) * scale, y, s, scale, color); } - //==================================================================== // @@ -566,7 +633,7 @@ class StatusScreen abstract play version("2.5") bool autoSkip() { - return wi_autoadvance > 0 && bcnt > (wi_autoadvance * Thinker.TICRATE); + return wi_autoadvance > 0 && bcnt > (wi_autoadvance * GameTicRate); } //==================================================================== @@ -614,7 +681,6 @@ class StatusScreen abstract play version("2.5") if (cnt == 0) { End(); - Level.WorldDone(); } } @@ -629,14 +695,13 @@ class StatusScreen abstract play version("2.5") if (wbs.next == "") { // Last map in episode - there is no next location! - End(); - Level.WorldDone(); + jobstate = finished; return; } CurState = ShowNextLoc; acceleratestage = 0; - cnt = SHOWNEXTLOCDELAY * Thinker.TICRATE; + cnt = SHOWNEXTLOCDELAY * GameTicRate; noautostartmap = bg.LoadBackground(true); } @@ -720,7 +785,7 @@ class StatusScreen abstract play version("2.5") // ==================================================================== - // checkForAccelerate + // // Purpose: See if the player has hit either the attack or use key // or mouse button. If so we set acceleratestage to 1 and // all those display routines above jump right to the end. @@ -729,25 +794,24 @@ class StatusScreen abstract play version("2.5") // // ==================================================================== - protected void checkForAccelerate(void) + override bool OnEvent(InputEvent evt) { - int i; - - // check for button presses to skip delays - for (i = 0; i < MAXPLAYERS; i++) + if (evt.type == InputEvent.Type_KeyDown) { - PlayerInfo player = players[i]; - if (playeringame[i]) - { - if ((player.cmd.buttons ^ player.oldbuttons) && - ((player.cmd.buttons & player.oldbuttons) == player.oldbuttons) && player.Bot == NULL) - { - acceleratestage = 1; - playerready[i] = true; - } - player.oldbuttons = player.buttons; - } + accelerateStage = 1; + return true; } + return false; + } + + void nextStage() + { + accelerateStage = 1; + } + + // this one is no longer used, but still needed for old content referencing them. + deprecated("4.8") void checkForAccelerate() + { } // ==================================================================== @@ -766,11 +830,11 @@ class StatusScreen abstract play version("2.5") //==================================================================== // - // + // Two stage interface to allow redefining this class as a screen job // //==================================================================== - virtual void Ticker(void) + protected virtual void Ticker() { // counter for general background animation bcnt++; @@ -780,7 +844,6 @@ class StatusScreen abstract play version("2.5") StartMusic(); } - checkForAccelerate(); bg.updateAnimatedBack(); switch (CurState) @@ -798,18 +861,23 @@ class StatusScreen abstract play version("2.5") break; case LeavingIntermission: - // Hush, GCC. break; } } + override void OnTick() + { + Ticker(); + if (CurState == StatusScreen.LeavingIntermission) jobstate = finished; + } + //==================================================================== // // // //==================================================================== - virtual void Drawer (void) + protected virtual void Drawer() { switch (CurState) { @@ -820,18 +888,21 @@ class StatusScreen abstract play version("2.5") break; case ShowNextLoc: + case LeavingIntermission: // this must still draw the screen once more for the wipe code to pick up. drawShowNextLoc(); break; - case LeavingIntermission: - break; - default: drawNoState(); break; } } + override void Draw(double smoothratio) + { + Drawer(); + } + //==================================================================== // // @@ -844,10 +915,22 @@ class StatusScreen abstract play version("2.5") acceleratestage = 0; cnt = bcnt = 0; me = wbs.pnum; - for (int i = 0; i < MAXPLAYERS; i++) Plrs[i] = wbs.plyr[i]; + otherkills = wbs.totalkills; + for (int i = 0; i < MAXPLAYERS; i++) + { + Plrs[i] = wbs.plyr[i]; + otherkills -= Plrs[i].skills; + } + + if (gameinfo.mHideParTimes) + { + // par time and suck time are not displayed if zero. + wbs.partime = 0; + wbs.sucktime = 0; + } entering.Init(gameinfo.mStatscreenEnteringFont); - finished.Init(gameinfo.mStatscreenFinishedFont); + finishedp.Init(gameinfo.mStatscreenFinishedFont); mapname.Init(gameinfo.mStatscreenMapNameFont); content.Init(gameinfo.mStatscreenContentFont); author.Init(gameinfo.mStatscreenAuthorFont); @@ -870,9 +953,14 @@ class StatusScreen abstract play version("2.5") bg = InterBackground.Create(wbs); noautostartmap = bg.LoadBackground(false); initStats(); + + wrapwidth = cwidth = screen.GetWidth(); + cheight = screen.GetHeight(); + scalemode = -1; + scaleFactorX = CleanXfac; + scaleFactorY = CleanYfac; } - protected virtual void initStats() {} protected virtual void updateStats() {} protected virtual void drawStats() {} diff --git a/wadsrc/static/zscript/ui/statscreen/statscreen_coop.zs b/wadsrc/static/zscript/ui/statscreen/statscreen_coop.zs index 48bf30d93b8..73b397c0754 100644 --- a/wadsrc/static/zscript/ui/statscreen/statscreen_coop.zs +++ b/wadsrc/static/zscript/ui/statscreen/statscreen_coop.zs @@ -23,7 +23,7 @@ class CoopStatusScreen : StatusScreen FontScale = max(screen.GetHeight() / 400, 1); RowHeight = int(max((displayFont.GetHeight() + 1) * FontScale, 1)); - cnt_pause = Thinker.TICRATE; + cnt_pause = GameTicRate; for (int i = 0; i < MAXPLAYERS; i++) { @@ -36,6 +36,8 @@ class CoopStatusScreen : StatusScreen dofrags += fragSum (i); } + cnt_otherkills = 0; + dofrags = !!dofrags; } @@ -53,7 +55,7 @@ class CoopStatusScreen : StatusScreen bool stillticking; bool autoskip = autoSkip(); - if ((acceleratestage || autoskip) && ng_state != 10) + if ((acceleratestage || autoskip) && ng_state != 12) { acceleratestage = 0; @@ -69,8 +71,13 @@ class CoopStatusScreen : StatusScreen if (dofrags) cnt_frags[i] = fragSum (i); } + cnt_otherkills = otherkills; + + cnt_time = Thinker.Tics2Seconds(Plrs[me].stime); + cnt_total_time = Thinker.Tics2Seconds(wbs.totaltime); + PlaySound("intermission/nextstage"); - ng_state = 10; + ng_state = 12; } if (ng_state == 2) @@ -92,7 +99,14 @@ class CoopStatusScreen : StatusScreen else stillticking = true; } - + + cnt_otherkills += 2; + + if (cnt_otherkills > otherkills) + cnt_otherkills = otherkills; + else + stillticking = true; + if (!stillticking) { PlaySound("intermission/nextstage"); @@ -146,7 +160,7 @@ class CoopStatusScreen : StatusScreen if (!stillticking) { PlaySound("intermission/nextstage"); - ng_state += 1 + 2*!dofrags; + ng_state ++; } } else if (ng_state == 8) @@ -156,6 +170,31 @@ class CoopStatusScreen : StatusScreen stillticking = false; + cnt_time += 3; + cnt_total_time += 3; + + int sec = Thinker.Tics2Seconds(Plrs[me].stime); + if (cnt_time > sec) + { + cnt_time = sec; + cnt_total_time = Thinker.Tics2Seconds(wbs.totaltime); + } + else + stillticking = true; + + if (!stillticking) + { + PlaySound("intermission/nextstage"); + ng_state += 1 + 2*!dofrags; + } + } + else if (ng_state == 10) + { + if (!(bcnt&3)) + PlaySound("intermission/tick"); + + stillticking = false; + for (i=0 ; i= 4) @@ -321,5 +358,15 @@ class CoopStatusScreen : StatusScreen drawNumScaled(displayFont, secret_x, y, FontScale, wbs.maxsecret, 0, textcolor); } } + + // Draw "TIME" line + y += height + 3 * CleanYfac; + drawTextScaled(displayFont, name_x, y, Stringtable.Localize("$TXT_IMTIME"), FontScale, textcolor); + + if (ng_state >= 8) + { + drawTimeScaled(displayFont, kills_x, y, cnt_time, FontScale, textcolor); + drawTimeScaled(displayFont, secret_x, y, cnt_total_time, FontScale, textcolor); + } } } diff --git a/wadsrc/static/zscript/ui/statscreen/statscreen_dm.zs b/wadsrc/static/zscript/ui/statscreen/statscreen_dm.zs index 0a6e969dbb0..e768b9db233 100644 --- a/wadsrc/static/zscript/ui/statscreen/statscreen_dm.zs +++ b/wadsrc/static/zscript/ui/statscreen/statscreen_dm.zs @@ -33,7 +33,7 @@ class DeathmatchStatusScreen : StatusScreen total_deaths = 0; ng_state = 1; - cnt_pause = Thinker.TICRATE; + cnt_pause = GameTicRate; for (i=0 ; i= tsec) cnt_total_time = tsec; - int psec = wbs.partime / Thinker.TICRATE; + int psec = wbs.partime / GameTicRate; if (!intermissioncounter || cnt_par >= psec) { cnt_par = psec; @@ -126,7 +126,7 @@ class DoomStatusScreen : StatusScreen if (!--cnt_pause) { sp_state++; - cnt_pause = Thinker.TICRATE; + cnt_pause = GameTicRate; } } } @@ -154,15 +154,18 @@ class DoomStatusScreen : StatusScreen Font textFont = generic_ui? NewSmallFont : content.mFont; int statsx = SP_STATSX; + int timey = SP_TIMEY; + if (wi_showtotaltime) + timey = min(SP_TIMEY, 200 - 2 * lh); if (useGfx) { printFont = IntermissionFont; - screen.DrawTexture (Kills, true, statsx, SP_STATSY, DTA_Clean, true); - screen.DrawTexture (Items, true, statsx, SP_STATSY+lh, DTA_Clean, true); - screen.DrawTexture (P_secret, true, statsx, SP_STATSY+2*lh, DTA_Clean, true); - screen.DrawTexture (Timepic, true, SP_TIMEX, SP_TIMEY, DTA_Clean, true); - if (wbs.partime) screen.DrawTexture (Par, true, 160 + SP_TIMEX, SP_TIMEY, DTA_Clean, true); + DrawTexture (Kills, statsx, SP_STATSY); + DrawTexture (Items, statsx, SP_STATSY+lh); + DrawTexture (P_secret, statsx, SP_STATSY+2*lh); + DrawTexture (Timepic, SP_TIMEX, timey); + if (wbs.partime) DrawTexture (Par, 160 + SP_TIMEX, timey); } else { @@ -178,18 +181,18 @@ class DoomStatusScreen : StatusScreen statsx = max(0, (320 - allwidth) / 2); } - printFont = generic_ui? IntermissionFont : BigFont; - screen.DrawText (textFont, tcolor, statsx, SP_STATSY, "$TXT_IMKILLS", DTA_Clean, true); - screen.DrawText (textFont, tcolor, statsx, SP_STATSY+lh, "$TXT_IMITEMS", DTA_Clean, true); - screen.DrawText (textFont, tcolor, statsx, SP_STATSY+2*lh, "$TXT_IMSECRETS", DTA_Clean, true); - screen.DrawText (textFont, tcolor, SP_TIMEX, SP_TIMEY, "$TXT_IMTIME", DTA_Clean, true); - if (wbs.partime) screen.DrawText (textFont, tcolor, 160 + SP_TIMEX, SP_TIMEY, "$TXT_IMPAR", DTA_Clean, true); + printFont = generic_ui? IntermissionFont : content.mFont; + DrawText (textFont, tcolor, statsx, SP_STATSY, "$TXT_IMKILLS"); + DrawText (textFont, tcolor, statsx, SP_STATSY+lh, "$TXT_IMITEMS"); + DrawText (textFont, tcolor, statsx, SP_STATSY+2*lh, "$TXT_IMSECRETS"); + DrawText (textFont, tcolor, SP_TIMEX, timey, "$TXT_IMTIME"); + if (wbs.partime) DrawText (textFont, tcolor, 160 + SP_TIMEX, timey, "$TXT_IMPAR"); } drawPercent (printFont, 320 - statsx, SP_STATSY, cnt_kills[0], wbs.maxkills, true, tcolor); drawPercent (printFont, 320 - statsx, SP_STATSY+lh, cnt_items[0], wbs.maxitems, true, tcolor); drawPercent (printFont, 320 - statsx, SP_STATSY+2*lh, cnt_secret[0], wbs.maxsecret, true, tcolor); - drawTimeFont (printFont, 160 - SP_TIMEX, SP_TIMEY, cnt_time, tcolor); + drawTimeFont (printFont, 160 - SP_TIMEX, timey, cnt_time, tcolor); // This really sucks - not just by its message - and should have been removed long ago! // To avoid problems here, the "sucks" text only gets printed if the lump is present, this even applies to the text replacement. @@ -197,26 +200,26 @@ class DoomStatusScreen : StatusScreen if (cnt_time >= wbs.sucktime * 60 * 60 && wbs.sucktime > 0 && Sucks.IsValid()) { // "sucks" int x = 160 - SP_TIMEX; - int y = SP_TIMEY; + int y = timey; if (useGfx && TexMan.OkForLocalization(Sucks, "$TXT_IMSUCKS")) { let size = TexMan.GetScaledSize(Sucks); - screen.DrawTexture (Sucks, true, x - size.X, y - size.Y - 2, DTA_Clean, true); + DrawTexture (Sucks, x - size.X, y - size.Y - 2); } else { - screen.DrawText (textFont, tColor, x - printFont.StringWidth("$TXT_IMSUCKS"), y - printFont.GetHeight() - 2, "$TXT_IMSUCKS", DTA_Clean, true); + DrawText (textFont, tColor, x - printFont.StringWidth("$TXT_IMSUCKS"), y - printFont.GetHeight() - 2, "$TXT_IMSUCKS"); } } if (wi_showtotaltime) { - drawTimeFont (printFont, 160 - SP_TIMEX, SP_TIMEY + lh, cnt_total_time, tcolor); + drawTimeFont (printFont, 160 - SP_TIMEX, timey + lh, cnt_total_time, tcolor); } if (wbs.partime) { - drawTimeFont (printFont, 320 - SP_TIMEX, SP_TIMEY, cnt_par, tcolor); + drawTimeFont (printFont, 320 - SP_TIMEX, timey, cnt_par, tcolor); } } } @@ -233,26 +236,26 @@ class RavenStatusScreen : DoomStatusScreen Font textFont = generic_ui? NewSmallFont : content.mFont; let tcolor = content.mColor; - screen.DrawText (textFont, tcolor, 50, 65, "$TXT_IMKILLS", DTA_Clean, true, DTA_Shadow, true); - screen.DrawText (textFont, tcolor, 50, 90, "$TXT_IMITEMS", DTA_Clean, true, DTA_Shadow, true); - screen.DrawText (textFont, tcolor, 50, 115, "$TXT_IMSECRETS", DTA_Clean, true, DTA_Shadow, true); + DrawText (textFont, tcolor, 50, 65, "$TXT_IMKILLS", shadow:true); + DrawText (textFont, tcolor, 50, 90, "$TXT_IMITEMS", shadow:true); + DrawText (textFont, tcolor, 50, 115, "$TXT_IMSECRETS", shadow:true); int countpos = gameinfo.gametype==GAME_Strife? 285:270; if (sp_state >= 2) { - drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs.maxkills, true, tcolor); + drawPercent (textFont, countpos, 65, cnt_kills[0], wbs.maxkills, true, tcolor); } if (sp_state >= 4) { - drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs.maxitems, true, tcolor); + drawPercent (textFont, countpos, 90, cnt_items[0], wbs.maxitems, true, tcolor); } if (sp_state >= 6) { - drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs.maxsecret, true, tcolor); + drawPercent (textFont, countpos, 115, cnt_secret[0], wbs.maxsecret, true, tcolor); } if (sp_state >= 8) { - screen.DrawText (textFont, tcolor, 85, 160, "$TXT_IMTIME", DTA_Clean, true, DTA_Shadow, true); + DrawText (textFont, tcolor, 85, 160, "$TXT_IMTIME", shadow:true); drawTimeFont (textFont, 249, 160, cnt_time, tcolor); if (wi_showtotaltime) { diff --git a/wadsrc/static/zscript/ui/statscreen/types.zs b/wadsrc/static/zscript/ui/statscreen/types.zs index 24084ca73be..761ef231e3e 100644 --- a/wadsrc/static/zscript/ui/statscreen/types.zs +++ b/wadsrc/static/zscript/ui/statscreen/types.zs @@ -30,6 +30,7 @@ struct WBStartStruct native version("2.4") native TextureID LName0; native TextureID LName1; + native int totalkills; native int maxkills; native int maxitems; native int maxsecret; diff --git a/wadsrc/static/zscript/ui/statusbar/alt_hud.zs b/wadsrc/static/zscript/ui/statusbar/alt_hud.zs index 7ddbf902df8..c1c6e72888d 100644 --- a/wadsrc/static/zscript/ui/statusbar/alt_hud.zs +++ b/wadsrc/static/zscript/ui/statusbar/alt_hud.zs @@ -184,22 +184,38 @@ class AltHud ui if (!deathmatch) { - // FIXME: ZDoom doesn't preserve the player's stat counters across hubs so this doesn't - // work in cooperative hub games if (hud_showsecrets) { - DrawStatLine(x, y, "S:", String.Format("%i/%i ", multiplayer? CPlayer.secretcount : Level.found_secrets, Level.total_secrets)); + DrawStatLine(x, y, "S:", multiplayer + ? String.Format("%i/%i/%i ", CPlayer.secretcount, Level.found_secrets, Level.total_secrets) + : String.Format("%i/%i ", Level.found_secrets, Level.total_secrets)); } if (hud_showitems) { - DrawStatLine(x, y, "I:", String.Format("%i/%i ", multiplayer? CPlayer.itemcount : Level.found_items, Level.total_items)); + DrawStatLine(x, y, "I:", multiplayer + ? String.Format("%i/%i/%i ", CPlayer.itemcount, Level.found_items, Level.total_items) + : String.Format("%i/%i ", Level.found_items, Level.total_items)); } if (hud_showmonsters) { - DrawStatLine(x, y, "K:", String.Format("%i/%i ", multiplayer? CPlayer.killcount : Level.killed_monsters, Level.total_monsters)); + DrawStatLine(x, y, "K:", multiplayer + ? String.Format("%i/%i/%i ", CPlayer.killcount, Level.killed_monsters, Level.total_monsters) + : String.Format("%i/%i ", Level.killed_monsters, Level.total_monsters)); } + + if (hud_showtimestat) + { + String s; + let seconds = Thinker.Tics2Seconds(level.time); + if (seconds >= 3600) + s = String.Format("%02i:%02i:%02i", seconds / 3600, (seconds % 3600) / 60, seconds % 60); + else + s = String.Format("%02i:%02i", seconds / 60, seconds % 60); + DrawStatLine(x, y, "T:", s); + } + } } @@ -702,9 +718,10 @@ class AltHud ui // //--------------------------------------------------------------------------- - void DrawCoordinateEntry(int xpos, int ypos, String coordstr) + void DrawCoordinateEntry(int xpos, int ypos, String coordstr, Font fnt = nullptr) { - screen.DrawText(SmallFont, hudcolor_xyco, xpos, ypos, coordstr, + if (fnt == nullptr) fnt = SmallFont; + screen.DrawText(fnt, hudcolor_xyco, xpos, ypos, coordstr, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight); } @@ -713,7 +730,8 @@ class AltHud ui { Vector3 pos; String coordstr; - int h = SmallFont.GetHeight(); + let fnt = generic_ui ? NewSmallFont : SmallFont; + int h = fnt.GetHeight(); let mo = CPlayer.mo; if (!map_point_coordinates || !automapactive) @@ -726,7 +744,7 @@ class AltHud ui pos.z = Level.PointInSector(pos.xy).floorplane.ZatPoint(pos.xy); } - int xpos = hudwidth - SmallFont.StringWidth("X: -00000")-6; + int xpos = hudwidth - fnt.StringWidth("X: -00000")-6; int ypos = 18; if (withmapname) @@ -745,20 +763,20 @@ class AltHud ui ypos += 2 * hh + h; } - DrawCoordinateEntry(xpos, ypos, String.Format("X: %.0f", pos.X)); + DrawCoordinateEntry(xpos, ypos, String.Format("X: %.0f", pos.X), fnt); ypos += h; - DrawCoordinateEntry(xpos, ypos, String.Format("Y: %.0f", pos.Y)); + DrawCoordinateEntry(xpos, ypos, String.Format("Y: %.0f", pos.Y), fnt); ypos += h; - DrawCoordinateEntry(xpos, ypos, String.Format("Z: %.0f", pos.Z)); + DrawCoordinateEntry(xpos, ypos, String.Format("Z: %.0f", pos.Z), fnt); ypos += h; if (hud_showangles) { - DrawCoordinateEntry(xpos, ypos, String.Format("Y: %.0f", Actor.Normalize180(mo.Angle))); + DrawCoordinateEntry(xpos, ypos, String.Format("Y: %.0f", Actor.Normalize180(mo.Angle)), fnt); ypos += h; - DrawCoordinateEntry(xpos, ypos, String.Format("P: %.0f", Actor.Normalize180(mo.Pitch))); + DrawCoordinateEntry(xpos, ypos, String.Format("P: %.0f", Actor.Normalize180(mo.Pitch)), fnt); ypos += h; - DrawCoordinateEntry(xpos, ypos, String.Format("R: %.0f", Actor.Normalize180(mo.Roll))); + DrawCoordinateEntry(xpos, ypos, String.Format("R: %.0f", Actor.Normalize180(mo.Roll)), fnt); } } @@ -770,13 +788,12 @@ class AltHud ui // for meaning of all display modes // //--------------------------------------------------------------------------- - private native static int GetRealTime(); - virtual bool DrawTime(int y) { if (hud_showtime > 0 && hud_showtime <= 9) { int timeSeconds; + String timeString; if (hud_showtime < 8) { @@ -787,33 +804,35 @@ class AltHud ui ? Level.time : Level.totaltime); timeSeconds = Thinker.Tics2Seconds(timeTicks); - } - else - { - timeSeconds = GetRealTime(); - } - int hours = timeSeconds / 3600; - int minutes = (timeSeconds % 3600) / 60; - int seconds = timeSeconds % 60; + int hours = timeSeconds / 3600; + int minutes = (timeSeconds % 3600) / 60; + int seconds = timeSeconds % 60; - bool showMillis = 1 == hud_showtime; - bool showSeconds = showMillis || (0 == hud_showtime % 2); + bool showMillis = 1 == hud_showtime; + bool showSeconds = showMillis || (0 == hud_showtime % 2); - String timeString; - - if (showMillis) - { - int millis = (Level.time % Thinker.TICRATE) * (1000 / Thinker.TICRATE); - timeString = String.Format("%02i:%02i:%02i.%03i", hours, minutes, seconds, millis); + if (showMillis) + { + int millis = (Level.time % GameTicRate) * 1000 / GameTicRate; + timeString = String.Format("%02i:%02i:%02i.%03i", hours, minutes, seconds, millis); + } + else if (showSeconds) + { + timeString = String.Format("%02i:%02i:%02i", hours, minutes, seconds); + } + else + { + timeString = String.Format("%02i:%02i", hours, minutes); + } } - else if (showSeconds) + else if (hud_showtime == 8) { - timeString = String.Format("%02i:%02i:%02i", hours, minutes, seconds); + timeString = SystemTime.Format("%H:%M:%S",SystemTime.Now()); } - else + else //if (hud_showtime == 9) { - timeString = String.Format("%02i:%02i", hours, minutes); + timeString = SystemTime.Format("%H:%M",SystemTime.Now()); } int characterCount = timeString.length(); @@ -907,8 +926,12 @@ class AltHud ui DrawStatus(CPlayer, 5, hudheight-75); DrawFrags(CPlayer, 5, hudheight-70); } - DrawHealth(CPlayer, 5, hudheight-45); - DrawArmor(BasicArmor(CPlayer.mo.FindInventory('BasicArmor')), HexenArmor(CPlayer.mo.FindInventory('HexenArmor')), 5, hudheight-20); + + int armory = hud_swaphealtharmor ? hudheight-45 : hudheight-20; + int healthy = hud_swaphealtharmor ? hudheight-20 : hudheight-45; + DrawHealth(CPlayer, 5, healthy); + DrawArmor(BasicArmor(CPlayer.mo.FindInventory('BasicArmor', true)), HexenArmor(CPlayer.mo.FindInventory('HexenArmor', true)), 5, armory); + int y = DrawKeys(CPlayer, hudwidth-4, hudheight-10); y = DrawAmmo(CPlayer, hudwidth-5, y); if (hud_showweapons) DrawWeapons(CPlayer, hudwidth - 5, y); @@ -956,9 +979,31 @@ class AltHud ui let amstr = Level.FormatMapName(hudcolor_titl); font = generic_ui? NewSmallFont : SmallFont.CanPrint(amstr)? SmallFont : OriginalSmallFont; - screen.DrawText(font, Font.CR_BRICK, 2, hudheight - fonth - 1, amstr, - DTA_KeepRatio, true, - DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight); + bottom = hudheight - fonth - 1; + + screen.DrawText(font, Font.CR_BRICK, 2, bottom, amstr, + DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight); + + if (am_showcluster && (Level.clusterflags & Level.CLUSTER_HUB)) + { + let text = Level.GetClusterName(); + if (text != "") + { + bottom -= fonth; + screen.DrawText(font, Font.CR_ORANGE, 2, bottom, text, + DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight); + } + } + if (am_showepisode) + { + let text = Level.GetEpisodeName(); + if (text != "") + { + bottom -= fonth; + screen.DrawText(font, Font.CR_RED, 2, bottom, text, + DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight); + } + } DrawCoordinates(CPlayer, false); } diff --git a/wadsrc/static/zscript/ui/statusbar/doom_sbar.zs b/wadsrc/static/zscript/ui/statusbar/doom_sbar.zs index 0ea001a3280..7e7496a4145 100644 --- a/wadsrc/static/zscript/ui/statusbar/doom_sbar.zs +++ b/wadsrc/static/zscript/ui/statusbar/doom_sbar.zs @@ -66,7 +66,7 @@ class DoomStatusBar : BaseStatusBar if (CPlayer.mo.InvSel != null && !Level.NoInventoryBar) { - DrawInventoryIcon(CPlayer.mo.InvSel, (160, 198)); + DrawInventoryIcon(CPlayer.mo.InvSel, (160, 198), DI_DIMDEPLETED); if (CPlayer.mo.InvSel.Amount > 1) { DrawString(mAmountFont, FormatNumber(CPlayer.mo.InvSel.Amount), (175, 198-mIndexFont.mFont.GetHeight()), DI_TEXT_ALIGN_RIGHT, Font.CR_GOLD); @@ -146,7 +146,7 @@ class DoomStatusBar : BaseStatusBar DrawImage(berserk? "PSTRA0" : "MEDIA0", (20, -2)); DrawString(mHUDFont, FormatNumber(CPlayer.health, 3), (44, -20)); - let armor = CPlayer.mo.FindInventory("BasicArmor"); + let armor = CPlayer.mo.FindInventory("BasicArmor", true); if (armor != null && armor.Amount > 0) { DrawInventoryIcon(armor, (20, -22)); @@ -169,15 +169,17 @@ class DoomStatusBar : BaseStatusBar } if (!isInventoryBarVisible() && !Level.NoInventoryBar && CPlayer.mo.InvSel != null) { - DrawInventoryIcon(CPlayer.mo.InvSel, (-14, invY + 17)); + DrawInventoryIcon(CPlayer.mo.InvSel, (-14, invY + 17), DI_DIMDEPLETED); DrawString(mHUDFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (-30, invY), DI_TEXT_ALIGN_RIGHT); } if (deathmatch) { DrawString(mHUDFont, FormatNumber(CPlayer.FragCount, 3), (-3, 1), DI_TEXT_ALIGN_RIGHT, Font.CR_GOLD); } - - DrawFullscreenKeys(); + else + { + DrawFullscreenKeys(); + } if (isInventoryBarVisible()) { diff --git a/wadsrc/static/zscript/ui/statusbar/heretic_sbar.zs b/wadsrc/static/zscript/ui/statusbar/heretic_sbar.zs index 28eaf9db4ce..62cc27efa4b 100644 --- a/wadsrc/static/zscript/ui/statusbar/heretic_sbar.zs +++ b/wadsrc/static/zscript/ui/statusbar/heretic_sbar.zs @@ -127,7 +127,7 @@ class HereticStatusBar : BaseStatusBar //inventory box if (CPlayer.mo.InvSel != null) { - DrawInventoryIcon(CPlayer.mo.InvSel, (194, 175), DI_ARTIFLASH|DI_ITEM_CENTER, boxsize:(28, 28)); + DrawInventoryIcon(CPlayer.mo.InvSel, (194, 175), DI_ARTIFLASH|DI_ITEM_CENTER|DI_DIMDEPLETED, boxsize:(28, 28)); if (CPlayer.mo.InvSel.Amount > 1) { DrawString(mIndexFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (209, 182), DI_TEXT_ALIGN_RIGHT); @@ -148,7 +148,7 @@ class HereticStatusBar : BaseStatusBar DrawString(mBigFont, FormatNumber(mHealthInterpolator.GetValue()), (41, -21), DI_TEXT_ALIGN_RIGHT); //armor - let armor = CPlayer.mo.FindInventory("BasicArmor"); + let armor = CPlayer.mo.FindInventory("BasicArmor", true); if (armor != null && armor.Amount > 0) { DrawInventoryIcon(armor, (58, -24)); @@ -205,7 +205,7 @@ class HereticStatusBar : BaseStatusBar // This code was changed to always fit the item into the box, regardless of alignment or sprite size. // Heretic's ARTIBOX is 30x30 pixels. DrawImage("ARTIBOX", (-46, -1), 0, HX_SHADOW); - DrawInventoryIcon(CPlayer.mo.InvSel, (-46, -15), DI_ARTIFLASH|DI_ITEM_CENTER, boxsize:(28, 28)); + DrawInventoryIcon(CPlayer.mo.InvSel, (-46, -15), DI_ARTIFLASH|DI_ITEM_CENTER|DI_DIMDEPLETED, boxsize:(28, 28)); if (CPlayer.mo.InvSel.Amount > 1) { DrawString(mIndexFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (-32, -2 - mIndexFont.mFont.GetHeight()), DI_TEXT_ALIGN_RIGHT); diff --git a/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs b/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs index af410ed701a..ce4d3dc89a6 100644 --- a/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs +++ b/wadsrc/static/zscript/ui/statusbar/hexen_sbar.zs @@ -83,7 +83,7 @@ class HexenStatusBar : BaseStatusBar // This code was changed to always fit the item into the box, regardless of alignment or sprite size. // Heretic's ARTIBOX is 30x30 pixels. DrawImage("ARTIBOX", (-66, -1), 0, HX_SHADOW); - DrawInventoryIcon(CPlayer.mo.InvSel, (-66, -15), DI_ARTIFLASH|DI_ITEM_CENTER, boxsize:(28, 28)); + DrawInventoryIcon(CPlayer.mo.InvSel, (-66, -15), DI_ARTIFLASH|DI_ITEM_CENTER|DI_DIMDEPLETED, boxsize:(28, 28)); if (CPlayer.mo.InvSel.Amount > 1) { DrawString(mIndexFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (-52, -2 - mIndexFont.mFont.GetHeight()), DI_TEXT_ALIGN_RIGHT); @@ -129,8 +129,8 @@ class HexenStatusBar : BaseStatusBar int inthealth = mHealthInterpolator2.GetValue(); DrawGem(Chain, Gem, inthealth, CPlayer.mo.GetMaxHealth(true), (30, 193), -23, 49, 15, (multiplayer? DI_TRANSLATABLE : 0) | DI_ITEM_LEFT_TOP); - DrawImage("LFEDGE", (0, 192), DI_ITEM_OFFSETS); - DrawImage("RTEDGE", (277, 192), DI_ITEM_OFFSETS); + DrawImage("LFEDGE", (0, 193), DI_ITEM_OFFSETS); + DrawImage("RTEDGE", (277, 193), DI_ITEM_OFFSETS); if (!automapactive) { @@ -146,7 +146,7 @@ class HexenStatusBar : BaseStatusBar //inventory box if (CPlayer.mo.InvSel != null) { - DrawInventoryIcon(CPlayer.mo.InvSel, (159.5, 177), DI_ARTIFLASH|DI_ITEM_CENTER, boxsize:(28, 28)); + DrawInventoryIcon(CPlayer.mo.InvSel, (159.5, 177), DI_ARTIFLASH|DI_ITEM_CENTER|DI_DIMDEPLETED, boxsize:(28, 28)); if (CPlayer.mo.InvSel.Amount > 1) { DrawString(mIndexFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (174, 184), DI_TEXT_ALIGN_RIGHT); diff --git a/wadsrc/static/zscript/ui/statusbar/statusbar.zs b/wadsrc/static/zscript/ui/statusbar/statusbar.zs index 131649a2fe8..1cbaeae8717 100644 --- a/wadsrc/static/zscript/ui/statusbar/statusbar.zs +++ b/wadsrc/static/zscript/ui/statusbar/statusbar.zs @@ -15,12 +15,6 @@ struct MugShot } } -class HUDFont native ui -{ - native Font mFont; - native static HUDFont Create(Font fnt, int spacing = 0, EMonospacing monospacing = Mono_Off, int shadowx = 0, int shadowy = 0); -} - class InventoryBarState ui { TextureID box; @@ -108,7 +102,7 @@ class HUDMessageBase native ui virtual native void Draw(int bottom, int visibility); } -class BaseStatusBar native ui +class BaseStatusBar : StatusBarCore native { enum EPop { @@ -157,84 +151,6 @@ class BaseStatusBar native ui HUDMSGLayer_Default = HUDMSGLayer_OverHUD, }; - enum DI_Flags - { - DI_SKIPICON = 0x1, - DI_SKIPALTICON = 0x2, - DI_SKIPSPAWN = 0x4, - DI_SKIPREADY = 0x8, - DI_ALTICONFIRST = 0x10, - DI_TRANSLATABLE = 0x20, - DI_FORCESCALE = 0x40, - DI_DIM = 0x80, - DI_DRAWCURSORFIRST = 0x100, // only for DrawInventoryBar. - DI_ALWAYSSHOWCOUNT = 0x200, // only for DrawInventoryBar. - DI_DIMDEPLETED = 0x400, - DI_DONTANIMATE = 0x800, // do not animate the texture - DI_MIRROR = 0x1000, // flip the texture horizontally, like a mirror - - DI_SCREEN_AUTO = 0, // decide based on given offsets. - DI_SCREEN_MANUAL_ALIGN = 0x4000, // If this is on, the following flags will have an effect - - DI_SCREEN_TOP = DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_VCENTER = 0x8000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_BOTTOM = 0x10000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_VOFFSET = 0x18000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_VMASK = 0x18000 | DI_SCREEN_MANUAL_ALIGN, - - DI_SCREEN_LEFT = DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_HCENTER = 0x20000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_RIGHT = 0x40000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_HOFFSET = 0x60000 | DI_SCREEN_MANUAL_ALIGN, - DI_SCREEN_HMASK = 0x60000 | DI_SCREEN_MANUAL_ALIGN, - - DI_SCREEN_LEFT_TOP = DI_SCREEN_TOP|DI_SCREEN_LEFT, - DI_SCREEN_RIGHT_TOP = DI_SCREEN_TOP|DI_SCREEN_RIGHT, - DI_SCREEN_LEFT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_LEFT, - DI_SCREEN_RIGHT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_RIGHT, - DI_SCREEN_CENTER = DI_SCREEN_VCENTER|DI_SCREEN_HCENTER, - DI_SCREEN_CENTER_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_HCENTER, - DI_SCREEN_OFFSETS = DI_SCREEN_HOFFSET|DI_SCREEN_VOFFSET, - - DI_ITEM_AUTO = 0, // equivalent with bottom center, which is the default alignment. - - DI_ITEM_TOP = 0x80000, - DI_ITEM_VCENTER = 0x100000, - DI_ITEM_BOTTOM = 0, // this is the default vertical alignment - DI_ITEM_VOFFSET = 0x180000, - DI_ITEM_VMASK = 0x180000, - - DI_ITEM_LEFT = 0x200000, - DI_ITEM_HCENTER = 0, // this is the default horizontal alignment - DI_ITEM_RIGHT = 0x400000, - DI_ITEM_HOFFSET = 0x600000, - DI_ITEM_HMASK = 0x600000, - - DI_ITEM_LEFT_TOP = DI_ITEM_TOP|DI_ITEM_LEFT, - DI_ITEM_RIGHT_TOP = DI_ITEM_TOP|DI_ITEM_RIGHT, - DI_ITEM_LEFT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_LEFT, - DI_ITEM_RIGHT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_RIGHT, - DI_ITEM_CENTER = DI_ITEM_VCENTER|DI_ITEM_HCENTER, - DI_ITEM_CENTER_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_HCENTER, - DI_ITEM_OFFSETS = DI_ITEM_HOFFSET|DI_ITEM_VOFFSET, - - DI_TEXT_ALIGN_LEFT = 0, - DI_TEXT_ALIGN_RIGHT = 0x800000, - DI_TEXT_ALIGN_CENTER = 0x1000000, - DI_TEXT_ALIGN = 0x1800000, - - DI_ALPHAMAPPED = 0x2000000, - DI_NOSHADOW = 0x4000000, - DI_ALWAYSSHOWCOUNTERS = 0x8000000, - DI_ARTIFLASH = 0x10000000, - DI_FORCEFILL = 0x20000000, - - // These 2 flags are only used by SBARINFO so these duplicate other flags not used by SBARINFO - DI_DRAWINBOX = DI_TEXT_ALIGN_RIGHT, - DI_ALTERNATEONFAIL = DI_TEXT_ALIGN_CENTER, - - }; - enum IconType { ITYPE_PLAYERICON = 1000, @@ -269,12 +185,6 @@ class BaseStatusBar native ui HUD_HorizCenter } - enum ENumFlags - { - FNF_WHENNOTZERO = 0x1, - FNF_FILLZEROS = 0x2, - } - enum EShade { SHADER_HORZ = 0, @@ -286,36 +196,20 @@ class BaseStatusBar native ui const XHAIRPICKUPSIZE = (2+XHAIRSHRINKSIZE); const POWERUPICONSIZE = 32; - - native int RelTop; - native int HorizontalResolution, VerticalResolution; native bool Centering; native bool FixedOrigin; - native bool CompleteBorder; native double CrosshairSize; native double Displacement; native PlayerInfo CPlayer; native bool ShowLog; - native Vector2 defaultScale; // factor for fully scaled fullscreen display. clearscope native int artiflashTick; clearscope native double itemflashFade; - // These are block properties for the drawers. A child class can set them to have a block of items use the same settings. - native double Alpha; - native Vector2 drawOffset; // can be set by subclasses to offset drawing operations - native double drawClip[4]; // defines a clipping rectangle (not used yet) - native bool fullscreenOffsets; // current screen is displayed with fullscreen behavior. - native void AttachMessage(HUDMessageBase msg, uint msgid = 0, int layer = HUDMSGLayer_Default); native HUDMessageBase DetachMessage(HUDMessageBase msg); native HUDMessageBase DetachMessageID(uint msgid); native void DetachAllMessages(); - native void SetSize(int height, int vwidth, int vheight, int hwidth = -1, int hheight = -1); - native Vector2 GetHUDScale(); - native void BeginStatusBar(bool forceScaled = false, int resW = -1, int resH = -1, int rel = -1); - native void BeginHUD(double Alpha = 1., bool forcescaled = false, int resW = -1, int resH = -1); - native void UpdateScreenGeometry(); virtual void Init() @@ -341,26 +235,15 @@ class BaseStatusBar native ui virtual bool ProcessMidPrint(Font fnt, String msg, bool bold) { return false; } // [MK] let the HUD handle drawing the chat prompt virtual bool DrawChat(String txt) { return false; } + // [MK] let the HUD handle drawing the pause graphics + virtual bool DrawPaused(int player) { return false; } native TextureID GetMugshot(int accuracy, int stateflags=MugShot.STANDARD, String default_face = "STF"); - + native int GetTopOfStatusBar(); + // These functions are kept native solely for performance reasons. They get called repeatedly and can drag down performance easily if they get too slow. native static TextureID, bool GetInventoryIcon(Inventory item, int flags); - native void DrawTexture(TextureID texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1)); - native void DrawImage(String texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1)); - native void DrawString(HUDFont font, String string, Vector2 pos, int flags = 0, int translation = Font.CR_UNTRANSLATED, double Alpha = 1., int wrapwidth = -1, int linespacing = 4, Vector2 scale = (1, 1)); - native double, double, double, double TransformRect(double x, double y, double w, double h, int flags = 0); - native void Fill(Color col, double x, double y, double w, double h, int flags = 0); - native static String FormatNumber(int number, int minsize = 0, int maxsize = 0, int format = 0, String prefix = ""); - native double, double, double, double StatusbarToRealCoords(double x, double y=0, double w=0, double h=0); - native int GetTopOfStatusBar(); - native void SetClipRect(double x, double y, double w, double h, int flags = 0); - - void ClearClipRect() - { - screen.ClearClipRect(); - } - + //--------------------------------------------------------------------------- // // ValidateInvFirst @@ -505,20 +388,6 @@ class BaseStatusBar native ui return icon, scale; } - //============================================================================ - // - // Returns how much the status bar's graphics extend into the view - // Used for automap text positioning - // The parameter specifies how much of the status bar area will be covered - // by the element requesting this information. - // - //============================================================================ - - virtual int GetProtrusion(double scaleratio) const - { - return 0; - } - //============================================================================ // // Convenience functions to retrieve item tags @@ -561,7 +430,7 @@ class BaseStatusBar native ui int GetArmorAmount() { - let armor = CPlayer.mo.FindInventory("BasicArmor"); + let armor = CPlayer.mo.FindInventory("BasicArmor", true); return armor? armor.Amount : 0; } @@ -582,13 +451,13 @@ class BaseStatusBar native ui int GetArmorSavePercent() { double add = 0; - let harmor = HexenArmor(CPlayer.mo.FindInventory("HexenArmor")); + let harmor = HexenArmor(CPlayer.mo.FindInventory("HexenArmor", true)); if(harmor != NULL) { add = harmor.Slots[0] + harmor.Slots[1] + harmor.Slots[2] + harmor.Slots[3] + harmor.Slots[4]; } //Hexen counts basic armor also so we should too. - let armor = BasicArmor(CPlayer.mo.FindInventory("BasicArmor")); + let armor = BasicArmor(CPlayer.mo.FindInventory("BasicArmor", true)); if(armor != NULL && armor.Amount > 0) { add += armor.SavePercent * 100; @@ -886,7 +755,7 @@ class BaseStatusBar native ui // //============================================================================ - int GetTranslation() const + TranslationID GetTranslation() const { if(gameinfo.gametype & GAME_Raven) return Translation.MakeID(TRANSLATION_PlayersExtra, CPlayer.mo.PlayerNumber()); @@ -902,7 +771,7 @@ class BaseStatusBar native ui void DrawHexenArmor(int armortype, String image, Vector2 pos, int flags = 0, double alpha = 1.0, Vector2 boxsize = (-1, -1), Vector2 scale = (1.,1.)) { - let harmor = HexenArmor(statusBar.CPlayer.mo.FindInventory("HexenArmor")); + let harmor = HexenArmor(statusBar.CPlayer.mo.FindInventory("HexenArmor", true)); if (harmor != NULL) { let slotval = harmor.Slots[armorType]; @@ -933,7 +802,7 @@ class BaseStatusBar native ui if((flags & DI_ARTIFLASH) && artiflashTick > 0) { - DrawImage(flashimgs[artiflashTick-1], pos, flags | DI_TRANSLATABLE, alpha, boxsize); + DrawImage(flashimgs[artiflashTick-1], pos, flags, alpha, boxsize); } else if (texture.IsValid()) { @@ -1019,7 +888,7 @@ class BaseStatusBar native ui // //============================================================================ - void DrawBar(String ongfx, String offgfx, double curval, double maxval, Vector2 position, int border, int vertical, int flags = 0) + void DrawBar(String ongfx, String offgfx, double curval, double maxval, Vector2 position, int border, int vertical, int flags = 0, double alpha = 1.0) { let ontex = TexMan.CheckForTexture(ongfx, TexMan.TYPE_MiscPatch); if (!ontex.IsValid()) return; @@ -1050,17 +919,17 @@ class BaseStatusBar native ui for(int i = 0; i < 4; i++) Clip[i] += border; //Draw the whole foreground - DrawTexture(ontex, position, flags | DI_ITEM_LEFT_TOP); + DrawTexture(ontex, position, flags | DI_ITEM_LEFT_TOP, alpha); SetClipRect(position.X + Clip[0], position.Y + Clip[1], texsize.X - Clip[0] - Clip[2], texsize.Y - Clip[1] - Clip[3], flags); } - if (offtex.IsValid() && TexMan.GetScaledSize(offtex) == texsize) DrawTexture(offtex, position, flags | DI_ITEM_LEFT_TOP); - else Fill(color(255,0,0,0), position.X + Clip[0], position.Y + Clip[1], texsize.X - Clip[0] - Clip[2], texsize.Y - Clip[1] - Clip[3]); + if (offtex.IsValid() && TexMan.GetScaledSize(offtex) == texsize) DrawTexture(offtex, position, flags | DI_ITEM_LEFT_TOP, alpha); + else Fill(color(int(255*alpha),0,0,0), position.X + Clip[0], position.Y + Clip[1], texsize.X - Clip[0] - Clip[2], texsize.Y - Clip[1] - Clip[3]); - if (border == 0) + if (border == 0) { SetClipRect(position.X + Clip[0], position.Y + Clip[1], texsize.X - Clip[0] - Clip[2], texsize.Y - Clip[1] - Clip[3], flags); - DrawTexture(ontex, position, flags | DI_ITEM_LEFT_TOP); + DrawTexture(ontex, position, flags | DI_ITEM_LEFT_TOP, alpha); } // restore the previous clipping rectangle screen.SetClipRect(cx, cy, cw, ch); @@ -1114,7 +983,7 @@ class BaseStatusBar native ui } else { - DrawInventoryIcon(item, itempos + (boxsize.X * i, 0), flags | DI_ITEM_CENTER ); + DrawInventoryIcon(item, itempos + (boxsize.X * i, 0), flags | DI_ITEM_CENTER | DI_DIMDEPLETED ); } } @@ -1137,94 +1006,3 @@ class BaseStatusBar native ui } } -//============================================================================ -// -// a generic value interpolator for status bar elements that can change -// gradually to their new value. -// -//============================================================================ - -class LinearValueInterpolator : Object -{ - int mCurrentValue; - int mMaxChange; - - static LinearValueInterpolator Create(int startval, int maxchange) - { - let v = new("LinearValueInterpolator"); - v.mCurrentValue = startval; - v.mMaxChange = maxchange; - return v; - } - - void Reset(int value) - { - mCurrentValue = value; - } - - // This must be called periodically in the status bar's Tick function. - // Do not call this in the Draw function because that may skip some frames! - void Update(int destvalue) - { - if (mCurrentValue > destvalue) - { - mCurrentValue = max(destvalue, mCurrentValue - mMaxChange); - } - else - { - mCurrentValue = min(destvalue, mCurrentValue + mMaxChange); - } - } - - // This must be called in the draw function to retrieve the value for output. - int GetValue() - { - return mCurrentValue; - } -} - -class DynamicValueInterpolator : Object -{ - int mCurrentValue; - int mMinChange; - int mMaxChange; - double mChangeFactor; - - - static DynamicValueInterpolator Create(int startval, double changefactor, int minchange, int maxchange) - { - let v = new("DynamicValueInterpolator"); - v.mCurrentValue = startval; - v.mMinChange = minchange; - v.mMaxChange = maxchange; - v.mChangeFactor = changefactor; - return v; - } - - void Reset(int value) - { - mCurrentValue = value; - } - - // This must be called periodically in the status bar's Tick function. - // Do not call this in the Draw function because that may skip some frames! - void Update(int destvalue) - { - int diff = int(clamp(abs(destvalue - mCurrentValue) * mChangeFactor, mMinChange, mMaxChange)); - if (mCurrentValue > destvalue) - { - mCurrentValue = max(destvalue, mCurrentValue - diff); - } - else - { - mCurrentValue = min(destvalue, mCurrentValue + diff); - } - } - - // This must be called in the draw function to retrieve the value for output. - int GetValue() - { - return mCurrentValue; - } -} - diff --git a/wadsrc/static/zscript/ui/statusbar/strife_sbar.zs b/wadsrc/static/zscript/ui/statusbar/strife_sbar.zs index 3a7c3e0722b..7186d46d4be 100644 --- a/wadsrc/static/zscript/ui/statusbar/strife_sbar.zs +++ b/wadsrc/static/zscript/ui/statusbar/strife_sbar.zs @@ -251,7 +251,7 @@ class StrifeStatusBar : BaseStatusBar { int stopp = 200 - health; FillBar (x, y, 0, stopp, green1, green2); - FillBar (x, y, stopp, 100, blue1, blue2); + FillBar (x + stopp * 2, y, stopp, 100, blue1, blue2); } } } @@ -287,7 +287,7 @@ class StrifeStatusBar : BaseStatusBar DrawHealthBar (points, 49, 175); // Armor - item = CPlayer.mo.FindInventory('BasicArmor'); + item = CPlayer.mo.FindInventory('BasicArmor', true); if (item != NULL && item.Amount > 0) { DrawInventoryIcon(item, (2, 177), DI_ITEM_OFFSETS); @@ -318,10 +318,10 @@ class StrifeStatusBar : BaseStatusBar int flags = item.Amount <= 0? DI_ITEM_OFFSETS|DI_DIM : DI_ITEM_OFFSETS; if (item == CPlayer.mo.InvSel) { - DrawTexture (Images[CursorImage], (42 + 35*i, 180), flags, 1. - itemflashFade); + DrawTexture (Images[CursorImage], (42 + TICRATE*i, 180), flags, 1. - itemflashFade); } - DrawInventoryIcon (item, (48 + 35*i, 182), flags); - DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (75 + 35*i, 191), DI_TEXT_ALIGN_RIGHT); + DrawInventoryIcon (item, (48 + TICRATE*i, 182), flags); + DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (75 + TICRATE*i, 191), DI_TEXT_ALIGN_RIGHT); i++; } } @@ -333,7 +333,7 @@ class StrifeStatusBar : BaseStatusBar DrawImage("I_MDKT", (14, -17)); // Draw armor - let armor = CPlayer.mo.FindInventory('BasicArmor'); + let armor = CPlayer.mo.FindInventory('BasicArmor', true); if (armor != NULL && armor.Amount != 0) { DrawString(mYelFont, FormatNumber(armor.Amount, 3), (35, -10)); @@ -353,8 +353,8 @@ class StrifeStatusBar : BaseStatusBar if (ammo2 != NULL && ammo1!=ammo2) { // Draw secondary ammo just above the primary ammo - DrawString(mGrnFont, FormatNumber(ammo1.Amount, 3), (-23, -48)); - DrawInventoryIcon(ammo1, (-14, -55)); + DrawString(mGrnFont, FormatNumber(ammo2.Amount, 3), (-23, -48)); + DrawInventoryIcon(ammo2, (-14, -55)); } } @@ -388,13 +388,13 @@ class StrifeStatusBar : BaseStatusBar { if (item == CPlayer.mo.InvSel) { - DrawTexture(Images[CursorImage], (-90+i*35, -3), DI_SCREEN_CENTER_BOTTOM, 0.75); + DrawTexture(Images[CursorImage], (-90+i*TICRATE, -3), DI_SCREEN_CENTER_BOTTOM, 0.75); } if (item.Icon.isValid()) { - DrawInventoryIcon(item, (-90+i*35, -5), DI_SCREEN_CENTER_BOTTOM|DI_DIMDEPLETED, 0.75); + DrawInventoryIcon(item, (-90+i*TICRATE, -5), DI_SCREEN_CENTER_BOTTOM|DI_DIMDEPLETED, 0.75); } - DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (-72 + i*35, -8), DI_TEXT_ALIGN_RIGHT|DI_SCREEN_CENTER_BOTTOM); + DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (-72 + i*TICRATE, -8), DI_TEXT_ALIGN_RIGHT|DI_SCREEN_CENTER_BOTTOM); ++i; } } diff --git a/wadsrc/static/zscript/visualthinker.zs b/wadsrc/static/zscript/visualthinker.zs new file mode 100644 index 00000000000..12a8c41d6ad --- /dev/null +++ b/wadsrc/static/zscript/visualthinker.zs @@ -0,0 +1,50 @@ +Class VisualThinker : Thinker native +{ + native Vector3 Pos, + Prev; + native FVector3 Vel; + native Vector2 Scale, + Offset; + native float Roll, + PrevRoll, + Alpha; + native TextureID Texture; + native TranslationID Translation; + native uint16 Flags; + native int16 LightLevel; + native bool bFlipOffsetX, + bFlipOffsetY, + bXFlip, + bYFlip, + bDontInterpolate, + bAddLightLevel; + native Color scolor; + + native Sector CurSector; // can be null! + + native void SetTranslation(Name trans); + native void SetRenderStyle(int mode); // see ERenderStyle + native bool IsFrozen(); + + static VisualThinker Spawn(Class type, TextureID tex, Vector3 pos, Vector3 vel, double alpha = 1.0, int flags = 0, + double roll = 0.0, Vector2 scale = (1,1), Vector2 offset = (0,0), int style = STYLE_Normal, TranslationID trans = 0) + { + if (!Level) return null; + + let p = level.SpawnVisualThinker(type); + if (p) + { + p.Texture = tex; + p.Pos = pos; + p.Vel = vel; + p.Alpha = alpha; + p.Roll = roll; + p.Scale = scale; + p.Offset = offset; + p.SetRenderStyle(style); + p.Translation = trans; + p.Flags = flags; + } + return p; + } +} diff --git a/wadsrc/static/zscript/zscript_license.txt b/wadsrc/static/zscript/zscript_license.txt index 4ab1812d34d..92d01cb31e5 100644 --- a/wadsrc/static/zscript/zscript_license.txt +++ b/wadsrc/static/zscript/zscript_license.txt @@ -1,8 +1,8 @@ -Unless noted differently in the file, the following license applies to all ZScript sources: +Unless noted differently in the file, the following license applies to all ZScript sources *outside* the 'engine' folder: //----------------------------------------------------------------------------- // -// Copyright 1993-2019 id Software, Randy Heit, Christoph Oelckers et.al. +// Copyright 1993-2023 id Software, Randy Heit, Christoph Oelckers et.al. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,4 +18,39 @@ Unless noted differently in the file, the following license applies to all ZScri // along with this program. If not, see http://www.gnu.org/licenses/ // //----------------------------------------------------------------------------- -// \ No newline at end of file +// + +Unless noted differently in the file, the following license applies to all ZScript sources *inside* the 'engine' folder: + +/* +** +**--------------------------------------------------------------------------- +** Copyright 2005-2023 Randy Heit, Christoph Oelckers et.al. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. 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. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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/wadsrc_bm/CMakeLists.txt b/wadsrc_bm/CMakeLists.txt index a76c5dc36b2..639c3314480 100644 --- a/wadsrc_bm/CMakeLists.txt +++ b/wadsrc_bm/CMakeLists.txt @@ -1,3 +1 @@ -cmake_minimum_required( VERSION 2.4 ) - add_pk3(brightmaps.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static) diff --git a/wadsrc_bm/static/filter/doom.id/gldefs.bm b/wadsrc_bm/static/filter/doom.id/gldefs.bm index 78159bddd2a..3a450b5a03e 100644 --- a/wadsrc_bm/static/filter/doom.id/gldefs.bm +++ b/wadsrc_bm/static/filter/doom.id/gldefs.bm @@ -1265,19 +1265,19 @@ brightmap sprite SPIDA1D1 disablefullbright } -brightmap sprite SPIDA2D8 +brightmap sprite SPIDA2A8 { iwad disablefullbright } -brightmap sprite SPIDA3D7 +brightmap sprite SPIDA3A7 { iwad disablefullbright } -brightmap sprite SPIDA4D6 +brightmap sprite SPIDA4A6 { iwad disablefullbright diff --git a/wadsrc_extra/CMakeLists.txt b/wadsrc_extra/CMakeLists.txt index 0eacb8a5323..964a177c6ec 100644 --- a/wadsrc_extra/CMakeLists.txt +++ b/wadsrc_extra/CMakeLists.txt @@ -1,3 +1 @@ -cmake_minimum_required( VERSION 2.8.7 ) - add_pk3(game_support.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static) diff --git a/wadsrc_extra/static/filter/chex.chex3/language.csv b/wadsrc_extra/static/filter/chex.chex3/language.csv index 6cf2e39cb33..b54173fad02 100644 --- a/wadsrc_extra/static/filter/chex.chex3/language.csv +++ b/wadsrc_extra/static/filter/chex.chex3/language.csv @@ -1,63 +1,86 @@ -default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,pl,pt,ptg,ro,ru,sr -,,,,,,,,,,,,,,,,,,,,,,, -Picked up a blue flemkey.,GOTBLUEFLEM,,,,Sebrán modrý slizoklíč.,Blauen Flemschlüssel genommen,,Prenis bluan mukŝlosilon.,Recogiste una flemllave azul.,,Poimit sinisen lima-avaimen,Flemclé bleue récupérée.,Kék flemkulcs felvéve.,Raccolta una chiave-flem blu.,ブルー フレムキー をみつけた,청색 플렘열쇠 획득.,Je hebt een blauwe flemsleutel opgehaald.,Podniesiono niebieski flemowy klucz,Pegou uma flemchave azul.,,Ai ridicat flemcheia albastră.,Получен синий флемключ., -Picked up a yellow flemkey.,GOTYELLOWFLEM,,,,Sebrán žlutý slizoklíč.,Gelben Flemschlüssel genommen,,Prenis flavan mukŝlosilon.,Recogiste una flemllave amarilla.,,Poimit keltaisen lima-avaimen,Flemclé jaune récupérée.,Sárga flemkulcs felvéve.,Raccolta una chiave-flem gialla.,イエローフレムキー をみつけた,황색 플렘열쇠 획득.,Je hebt een gele flemsleutel opgehaald.,Podniesiono żółty flemowy klucz,Pegou uma flemchave amarela.,,Ai ridicat flemcheia galbenă.,Получен жёлтый флемключ., -Picked up a red flemkey.,GOTREDFLEM,,,,Sebrán červený slizoklíč.,Roten Flemschlüssel genommen.,,Prenis ruĝan mukŝlosilon.,Recogiste una flemllave roja.,,Poimit punaisen lima-avaimen,Flemclé rouge récupérée.,Piros flemkulcs felvéve.,Raccolta una chiave-flem rossa.,レッド フレムキー をみつけた,적색 플렘열쇠 획득.,Je hebt een rode flemsleutel opgehaald.,Podniesiono czerwony flemowy klucz,Pegou uma flemchave vermelha.,,Ai ridicat flemcheia roșie.,Получен красный флемключ., -Found Ultra Goggles,GOTGOGGLES,,,,Nalezeny ultrabrýle.,Ultrasichtbrille gefunden,,Trovis Egajn Okulvitrojn.,Encontraste Ultra Gafas,,Löysit ultralasit,Ultra-lunettes récupérées.,Ultraszemüveg felvéve.,,ウルトラゴーグル をみつけた,울트라 고글 사용.,Ultraroggles gevonden,Znaleziono Ultra Gogle,Achou um Ultra Óculos.,,Ai găsit Ultra Ochelarii,Получены Ультра-очки, -You need a blue key to activate this object,PD_BLUECO,,,,Potřebuješ modrý klíč pro aktivaci tohoto objektu,"Du brauchst einen blauen Schlüssel, um dieses Objekt zu aktivieren.",,Vi bezonas bluan ŝlosilon por aktivigi tion objekton.,Necesitas una llave azul para activar este objeto,,Tarvitset sinisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé bleue pour activer cet objet.,Egy kék kulcs szükséges az objektum aktiválásához.,Ti serve una chiave blu per attivare questo oggetto,このそうちは ブルー キー がひつようだ,이걸 작동하려면 청색 열쇠가 필요합니다,Je hebt een blauwe sleutel nodig om dit object te activeren.,"Potrzebujesz niebieskiego klucza, aby aktywować ten przedmiot",Você precisa de uma chave azul para ativar este objeto,,Ai nevoie de o cheie albastră pentru a activa acest obiect,Для активации нужен синий ключ,Треба вам плави кључ да би активирали овај предмет -You need a red key to activate this object,PD_REDCO,,,,Potřebuješ červený klíč pro aktivaci tohoto objektu,"Du brauchst einen roten Schlüssel, um dieses Objekt zu aktivieren.",,Vi bezonas ruĝan ŝlosilon por aktivigi tion objekton.,Necesitas una llave roja para activar este objeto,,Tarvitset punaisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé rouge pour activer cet objet.,Egy piros kulcs szükséges az objektum aktiválásához.,Ti serve una chiave rossa per attivare questo oggetto,このそうちは レッド キー がひつようだ,이걸 작동하려면 적색 열쇠가 필요합니다,Je hebt een rode sleutel nodig om dit object te activeren.,"Potrzebujesz czerwonego klucza, aby aktywować ten przedmiot",Você precisa de uma chave vermelha para ativar este objeto,,Ai nevoie de o cheie roșie pentru a activa acest obiect,Для активации нужен красный ключ,Треба вам црвени кључ да би активирали овај предмет -You need a yellow key to activate this object,PD_YELLOWCO,,,,Potřebuješ žlutý klíč pro aktivaci tohoto objektu,"Du brauchst einen gelben Schlüssel, um dieses Objekt zu aktivieren.",,Vi bezonas flavan ŝlosilon por aktivigi tion objekton.,Necesitas una llave amarilla para activar este objeto,,Tarvitset keltaisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé jaune pour activer cet objet.,Egy sárga kulcs szükséges az objektum aktiválásához.,Ti serve una chiave gialla per attivare questo oggetto,このそうちは イエローキー がひつようだ,이걸 작동하려면 황색 열쇠가 필요합니다,Je hebt een gele sleutel nodig om dit object te activeren.,"Potrzebujesz żółtego klucza, aby aktywować ten przedmiot",Você precisa de uma chave amarela para ativar este objeto,,Ai nevoie de o cheie galbenă pentru a activa acest obiect,Для активации нужен жёлтый ключ,Треба вам жути кључ да би активирали овај предмет -You need a blue flemkey to activate this object,PD_BLUEFO,,,,Potřebuješ modrý slizoklíč pro aktivaci tohoto objektu.,"Du brauchst einen blauen Flemschlüssel, um dieses Objekt zu aktivieren.",,Vi bezonas bluan mukŝlosilon por aktivigi tion objekton.,Necesitas una flemllave azul para activar este objeto,,Tarvitset sinisen lima-avaimen aktivoidaksesi tämän kappaleen,Il vous faut une flemclé bleue pour activer cet objet.,Egy kék flemkulcs szükséges az objektum aktiválásához.,Ti serve una chiave-flem blu per attivare questo oggetto,このそうちは ブルー キーがひつようだ,이걸 작동하려면 청색 플렘열쇠가 필요합니다,Je hebt een blauwe flemsleutel nodig om dit object te activeren.,"Potrzebujesz niebieskiego flemowego klucza, aby aktywować ten przedmiot",Você precisa de uma flemchave azul para ativar este objeto,,Ai nevoie de o flemcheie albastră pentru a activa acest obiect,Для активации нужен синий флемключ, -You need a red flemkey to activate this object,PD_REDFO,,,,Potřebuješ červený slizoklíč pro aktivaci tohoto objektu.,"Du brauchst einen roten Flemschlüssel, um dieses Objekt zu aktivieren.",,Vi bezonas ruĝan mukŝlosilon por aktivigi tion objekton.,Necesitas una flemllave roja para activar este objeto,,Tarvitset punaisen lima-avaimen aktivoidaksesi tämän kappaleen,Il vous faut une flemclé rouge pour activer cet objet.,Egy piros flemkulcs szükséges az objektum aktiválásához.,Ti serve una chiave-flem rossa per attivare questo oggetto,このそうちは レッド キーがひつようだ,이걸 작동하려면 적색 플렘열쇠가 필요합니다,Je hebt een rode flemsleutel nodig om dit object te activeren.,"Potrzebujesz czerwonego flemowego klucza, aby aktywować ten przedmiot",Você precisa de uma flemchave vermelha para ativar este objeto,,Ai nevoie de o flemcheie roșie pentru a activa acest obiect,Для активации нужен красный флемключ, -You need a yellow flemkey to activate this object,PD_YELLOWFO,,,,Potřebuješ žlutý slizoklíč pro aktivaci tohoto objektu.,"Du brauchst einen gelben Flemschlüssel, um dieses Objekt zu aktivieren.",,Vi bezonas flavan mukŝlosilon por aktivigi tion objekton.,Necesitas unaflemllave amarilla para activar este objeto,,Tarvitset keltaisen lima-avaimen aktivoidaksesi tämän kappaleen,Il vous faut une flemclé jaune pour activer cet objet.,Egy sárga flemkulcs szükséges az objektum aktiválásához.,Ti serve una chiave-flem gialla per attivare questo oggetto,このそうちは イエローキーがひつようだ,이걸 작동하려면 황색 플렘열쇠가 필요합니다,Je hebt een gele flemsleutel nodig om dit object te activeren.,"Potrzebujesz żółtego flemowego klucza, aby aktywować ten przedmiot",Você precisa de uma flemchave amarela para ativar este objeto,,Ai nevoie de o flemcheie galbenă pentru a activa acest obiect,Для активации нужен жёлтый флемключ, -Picked up a zorcher.,PICKUP_PISTOL_DROPPED,,,,Sebrán bzukr.,Zorcher genommen.,,Prenis zorĉilon.,Recogiste un zorcher.,,Poimit zorcherin,Zorcheur récupéré.,,Ho preso uno zorcher.,ゾーチャー をひろった,자쳐 습득.,Je hebt een zorcher opgehaald.,Podniesiono Zorcher,Pegou um zorcher.,,Ai ridicat un zorcher.,Получен Зорчер., -Zorch and keys added,STSTR_KFAADDED,,,,Bzukr a klíče přidány,Zorch und Schlüssel hinzugefügt.,,Zorĉaĵo kaj ŝlosiloj aldonitaj.,Zorch y llaves añadidas,,Zorch ja avaimet lisätty,Zorch et clés ajoutées.,,Zorch e chiavi aggiunte,ゾーチ と キーがとどいた,저치와 열쇠,Zorch en sleutels toegevoegd,Dodano amunicję Zorch i klucze,Zorch e chaves adicionadas,,Zorcher și chei adăugate,Зорч и ключи получены, -E1M1: Landing Zone,HUSTR_E1M1,,,,E1M1: Přistávací zóna,E1M1: Landezone,,E1M1: Surterejo,E1M1: Zona de Aterrizaje,,E1M1: Laskeutumisalue,E1M1: Zone D'Atterissage,E1M1: Landoló Zóna,E1M1: Zona di Atterraggio,E1M1: ちゃくち ちてん,E1M1: 착륙 지점,E1M1: Landingzone,E1M1: Strefa Lądowania,E1M1: Zona de Pouso,,E1M1: Zona de Aterizare,E1M1: Зона высадки, -E1M2: Storage Facility,HUSTR_E1M2,,,,E1M2: Skladiště,E1M2: Lagerhalle,,E1M2: Stokejo,E1M2: Instalación de Almacenamiento,,E1M2: Varastolaitos,E1M2: Centre de Stockage,E1M2: Raktárépület,E1M2: Struttura di Immagazzinamento,E1M2: ちょぞう しせつ,E1M2: 저장 시설,E1M2: Opslagfaciliteit,E1M2: Magazyn,E1M2: Depósito,,E1M2: Depozitul,E1M2: Хранилище, -E1M3: Laboratory,HUSTR_E1M3,,,,E1M3: Testovací laboratoř,E1M3: Labor,,E1M3: Laboratorio,E1M3: Laboratorio,,E1M3: Laboratorio,E1M3: Laboratoire,E1M3: Laboratórium,E1M3: Laboratorio,E1M3: ラボラトリー,E1M3: 연구소,E1M3: Laboratorium,E1M3: Laboratorium Eksperymentalne,E1M3: Laboratório de Experimentos,,E1M3: Laboratorul,E1M3: Лаборатория, -E1M4: Arboretum,HUSTR_E1M4,,,,,,,E1M4: Arbejo,E1M4: Arboreto,,,E1M4: Arboretum,E1M4: Arborétum,E1M4: Arboreto,E1M4: じゅもく園,E1M4: 수목원,,E1M4: Arboretum,E1M4: Arvoredo,,E1M4: Arboretum,E1M4: Дендрарий, -E1M5: Caverns of Bazoik,HUSTR_E1M5,,,,E1M5: Bazoikské jeskyně,E1M5: Die Höhlen von Bazoik,,E1M5: Kavernoj de Bazojko,E1M5: Cavernas de Bazoik,,E1M5: Bazoikin luolastot,E1M5: Cavernes de Bazoik,E1M5: Bazoik barlangjai,E1M5: Caverne di Bazoik,E1M5: バゾイクのどうくつ,E1M5: 바조이크의 대동굴,E1M5: Grotten van Bazoik,E1M5: Jaskinie Bazoik,E1M5: Cavernas de Bazoik,,E1M5: Cavernele lui Bazoik,E1M5: Пещеры Базоика, -E2M1: Spaceport,HUSTR_E2M1,,,,E2M1: Kosmodrom,E2M1: Raumhafen,,E2M1: Kosmo-haveno,E2M1: Puerto Espacial,,E2M1: Avaruussatama,E2M1: Spatioport,E2M1: Űrkikötő,E2M1: Spazioporto,E2M1: スペースポート,E2M1: 우주공항,E2M1: Ruimtehaven,E2M1: Port Kosmiczny,E2M1: Espaçoporto,,E2M1: Portul Spațial,E2M1: Космодром, -E2M2: Cinema,HUSTR_E2M2,,,,E2M2: Kino,E2M2: Kino,,E2M2: Kinejo,E2M2: Cine,,E2M2: Elokuvateatteri,E2M2: Cinéma,E2M2: Mozi,,E2M2: シネマ,E2M2: 극장,E2M2: Bioscoop,E2M2: Kino,E2M2: Cinema,,E2M2: Cinema,E2M2: Кинотеатр, -E2M3: Chex Museum,HUSTR_E2M3,,,,E2M3: Muzem Chex,,,E2M3: Chex-muzeo,E2M3: Museo de Chex,,E2M3: Chex-museo,E2M3: Musée Chex,E2M3: Chex-múzeum,E2M3: Museo di Chex,E2M3: チェックス ミュージアム,E2M3: 첵스 박물관,,E2M3: Muzeum Chex,E2M3: Museu Chex,,E2M3: Muzeul Chex,E2M3: Музей Chex, -E2M4: City Streets,HUSTR_E2M4,,,,E2M4: Městské ulice,E2M4: städtische Straßen,,E2M4: Urbstratoj,E2M4: Calles de la Ciudad,,E2M4: Kaupungin kadut,E2M4: Rues de la Ville,E2M4: Városi utcák,E2M4: Strade della città,E2M4: シティーストリート,E2M4: 도시 거리,E2M4: Stadsstraten,E2M4: Ulice Miasta,E2M4: Ruas da Cidade,,E2M4: Străzile Orașului,E2M4: Городские улицы, -E2M5: Sewer System,HUSTR_E2M5,,,,E2M5: Kanalizace,E2M5: Kanalisation,,E2M5: Defluilego-sistemo,E2M5: Alcantarillado,,E2M5: Viemärijärjestelmä,E2M5: Système d'égouts,E2M5: Csatornarendszer,E2M5: Rete fognaria,E2M5: サワーシステム,E2M5: 하수도,E2M5: Rioleringssysteem,E2M5: System Ścieków,E2M5: Rede de Esgoto,,E2M5: Sistemul de Canalizare,E2M5: Канализация, -E3M1: Central Command,HUSTR_E3M1,,,,E3M1: Centrální velení,E3M1: Kommandozentrale,,E3M1: Centra Komandejo,E3M1: Comando central,,E3M1: Komentokeskus,E3M1: Commandement,E3M1: Központi parancsnokság,E3M1: Comando centrale,E3M1: 中央しれいとう,E3M1: 중앙 사령부,E3M1: Centraal Commando,E3M1: Centrum Dowodzenia,E3M1: Comando Central,,E3M1: Centrul de Comanda,E3M1: Командный центр, -E3M2: United Cereals,HUSTR_E3M2,,,,E3M2: Spojené cereálie,E3M2: Vereinigte Zerealien,,E3M2: Uniaj Cerealoj,E3M2: Cereales unidos,,E3M2: Yhdistyneet murot,E3M2: Céréales Unies,E3M2: Egyesült Gabonapelyhek,E3M2: Cereali uniti,E3M2: ユナイテッド シリアル,E3M2: 시리얼 연합,E3M2: Verenigde granen,E3M2: Zjednoczone Płatki,E3M2: Cereais Unidos,,E3M2: Cereale Unite,E3M2: Организация Объединённых Хлопьев, -E3M3: Villa Chex,HUSTR_E3M3,,,,,,,E3M3: Vilao Chex,,,,E3M3: Villa Chex,,,E3M3: チェックスのべっそう,E3M3: 책스 주택,,E3M3: Willa Chex,E3M3: Villa Chex,,E3M3: Vila Chex,E3M3: Вилла Chex, -E3M4: Provincial Park,HUSTR_E3M4,,,,E3M4: Provinciální park,E3M4: Provinzpark,,E3M4: Provinca Parko,E3M4: Parque provincial,,E3M4: Provinssipuisto,E3M4: Parc Naturel,,E3M4: Parco provinciale,E3M4: 州立公園,E3M4: 주립공원,E3M4: Provinciaal Park,E3M4: Prowincjonalny Park,E3M4: Parque Natural,,E3M4: Parcul Provincial,E3M4: Провинциальный парк, -E3M5: Meteor Spaceship,HUSTR_E3M5,,,,E3M5: Meteorová vesmírná loď,E3M5: Meteor-Raumschiff,,E3M5: Meteor-kosmoŝipo,E3M5: Nave Meteoro,,E3M5: Meteoriavaruusalus,E3M5: Vaisseau Météore,E3M5: Meteor űrhajó,E2M5: Astronave meteorica,E3M5: メテオスペースシップ,E3M5: 거대 유성호,E3M5: Ruimteschip,"E3M5: Statek Kosmiczny ""Meteor""",E3M5: Espaçonave Meteoro,,E3M5: Nava Spațială Meteor,E3M5: Космический корабль “Метеор”, -Commonus,CC_ZOMBIE,,,,Obecnýs,,,Oftmukulo,,,,,Általánusz,,コモンズ,커머누스,,Pospolitus,,,Comun,Обыкновеннус, -Bipedicus,CC_SHOTGUN,,,,Dvojnožus,,,Dupiedmukulo,,,,,Kétlábikusz,,バイピディクス,바이피디쿠스,,,,,Biped,Двуножка, -Bipedicus with Armor,CC_IMP,,,,Dvojnožus s brněním,Bipedicus mit Panzerung,,Kirasa Dupiedmukulo,Bipedicus con Armadura,,Panssaroitu bipedicus,Bipedicus avec Armure,Páncélozott kétlábikusz,Bipedicus corazzato,アーマードバイピディクス,정예 바이피디쿠스,Bipedicus met harnas,Opancerzony Bipedicus,Bipedicus de Armadura,,Biped cu Armură,Бронированная двуножка, -Stridicus,CC_DEMON,,,,Běhakus,,,Paŝmukulo,,,,,Lépkedüsz,,ステュリクス,스트리디쿠스,,,,,Picioare-Lungi,Длинноножка, -Flem Mine,CC_LOST,,,,Slizná mina,,,Muksentinelo,Flem-Mina,,Limamiina,,Flem-akna,Bomba a Flem,フレムマイン,플렘 지뢰,Flemmijn,Flemowa Mina,Mina Flem,,Flem Mină,Флем-мина, -Super Cycloptis,CC_CACO,,,,Superkykloptus,,,Supera Ciklopmukulo,,,Supercycloptis,,Szuper Kükloptisz,,スーパーサイクロプティス,슈퍼 사이클롭티스,,Super Cykloptis,,,Super Cicloptic,Супер-циклоптис, -Maximus,CC_BARON,,,,,,,Mukulestro,,,,,Maximusz,,マクシムス,맥시무스,,,,,Maxim,Максимус, -The Flembomination,CC_SPIDER,,,,Slizavnost,Die Flembomination,,Mukabomeno,La Flembominación,,Limaoikku,La Flembomination,Flemdormány,La Flembominio,フレンボミネーション,플렘보미네이션,De Flembominatie,Flembominacja,A Flembominação,,Flembominație,Флемомерзость, -Lord Snotfolus,CC_CYBER,,,,Lord Hlenfujus,,,Lordo Mukplenulo,Lord Mocofolus,,Herra Räkänokka,Seigneur Morvator,Lord Takony,,ロード スノフォールス,스놋폴러스 마왕,,Lord Smarkofolus,Lorde Snotfolus,,Lordul Snotfolus,Лорд Соплезелёнус, -Chex Warrior,CC_HERO,,,,Bojovník Chex,Chex Krieger,,Chex-batalisto,Guerrero Chex,,Chex-soturi,Guerrier Chex,Chex harcos,Guerriero Chex,チェックスのせんし,첵스 전사,Chex Krijger,Wojownik Chex,,,Războinic Chex,Воин Chex, -You need a blue key to open this door,PD_BLUEC,,,,Potřebuješ modrý klíč pro otevření těchto dveří,"Du brauchst einen blauen Schlüssel, um diese Tür zu öffnen.",,Vi bezonas bluan ŝlosilon por malfermi ĉi tion pordon.,Necesitas una llave azul para abrir esta puerta,,Tarvitset sinisen avaimen avataksesi tämän oven,Il vous faut une clé bleue pour ouvrir cette porte.,Az ajtót a kék kulcs nyitja.,Ti serve una chiave blu per aprire questa porta,このとびらは ブルー キー がひつようだ,이 문을 열려면 청색 열쇠가 필요합니다,Je hebt een blauwe sleutel nodig om deze deur te openen.,"Potrzebujesz niebieskiego klucza, aby otworzyć te drzwi",Você precisa de uma chave azul para abrir essa porta,,Ai nevoie de o cheie albastră pentru a deschide ușa aceasta,"Нужен синий ключ, чтобы открыть",Треба вам плави кључ да би отворили ова врата -You need a red key to open this door,PD_REDC,,,,Potřebuješ červený klíč pro otevření těchto dveří,"Du brauchst einen roten Schlüssel, um diese Tür zu öffnen.",,Vi bezonas ruĝan ŝlosilon por malfermi ĉi tion pordon.,Necesitas una llave roja para abrir esta puerta,,Tarvitset punaisen avaimen avataksesi tämän oven,Il vous faut une clé rouge pour ouvrir cette porte.,"Piros kulcs szükséges, hogy az ajtót kinyithasd.",Ti serve una chiave rossa per aprire questa porta,このとびらは レッド キー がひつようだ,이 문을 열려면 적색 열쇠가 필요합니다,Je hebt een rode sleutel nodig om deze deur te openen.,"Potrzebujesz czerwonego klucza, aby otworzyć te drzwi",Você precisa de uma chave vermelha para abrir essa porta,,Ai nevoie de o cheie roșie pentru a deschide ușa aceasta,"Нужен красный ключ, чтобы открыть",Треба вам црвени кључ да би отворили ова врата -You need a yellow key to open this door,PD_YELLOWC,,,,Potřebuješ žlutý klíč pro otevření těchto dveří,"Du brauchst einen gelben Schlüssel, um diese Tür zu öffnen.",,Vi bezonas flavan ŝlosilon por malfermi ĉi tion pordon.,Necesitas una llave amarilla para abrir esta puerta,,Tarvitset keltaisen avaimen avataksesi tämän oven,Il vous faut une clé jaune pour ouvrir cette porte.,Kell egy sárga kulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave gialla per aprire questa porta,このとびらは イエローキー がひつようだ,이 문을 열려면 황색 열쇠가 필요합니다,Je hebt een gele sleutel nodig om deze deur te openen.,"Potrzebujesz żółtego klucza, aby otworzyć te drzwi",Você precisa de uma chave amarela para abrir essa porta,,Ai nevoie de o cheie galbenă pentru a deschide ușa aceasta,"Нужен жёлтый ключ, чтобы открыть",Треба вам жути кључ да би отворили ова врата -You need a blue flemkey to open this door,PD_BLUEF,,,,Potřebuješ modrý slizoklíč pro otevření těchto dveří,"Du brauchst einen blauen Flemschlüssel, um diese Tür zu öffnen.",,Vi bezonas bluan mukŝlosilon por malfermi ĉi tion pordon.,Necesitas una flemllave azul para abrir esta puerta,,Tarvitset sinisen lima-avaimen avataksesi tämän oven,Il vous faut une flemclé bleue pour ouvrir cette porte.,,Ti serve una chiave-flem blu per aprire questa porta,このとびらは ブルー キーがひつようだ,이 문을 열려면 청색 플렘열쇠가 필요합니다,Je hebt een blauwe flemsleutel nodig om deze deur te openen.,"Potrzebujesz niebieskiego flemowego klucza, aby otworzyć te drzwi",Você precisa de uma flemchave azul para ativar este objeto,,Ai nevoie de o flemcheie albastră pentru a deschide ușa aceasta,"Нужен синий флемключ, чтобы открыть", -You need a red flemkey to open this door,PD_REDF,,,,Potřebuješ červený slizoklíč pro otevření těchto dveří,"Du brauchst einen roten Flemschlüssel, um diese Tür zu öffnen.",,Vi bezonas ruĝan mukŝlosilon por malfermi ĉi tion pordon.,Necesitas una flemllave roja para abrir esta puerta,,Tarvitset punaisen lima-avaimen avataksesi tämän oven,Il vous faut une flemclé rouge pour ouvrir cette porte.,,Ti serve una chiave-flem rossa per aprire questa porta,このとびらは レッド キーがひつようだ,이 문을 열려면 적색 플렘열쇠가 필요합니다,Je hebt een rode flemsleutel nodig om deze deur te openen.,"Potrzebujesz czerwonego flemowego klucza, aby otworzyć te drzwi",Você precisa de uma flemchave vermelha para ativar este objeto,,Ai nevoie de o flemcheie roșie pentru a deschide ușa aceasta,"Нужен красный флемключ, чтобы открыть", -You need a yellow flemkey to open this door,PD_YELLOWF,,,,Potřebuješ žlutý slizoklíč pro otevření těchto dveří,"Du brauchst einen gelben Flemschlüssel, um diese Tür zu öffnen.",,Vi bezonas flavan mukŝlosilon por malfermi ĉi tion pordon.,Necesitas una flemllave amarilla para abrir esta puerta,,Tarvitset keltaisen lima-avaimen avataksesi tämän oven,Il vous faut une flemclé jaune pour ouvrir cette porte.,,Ti serve una chiave-flem gialla per aprire questa porta,このとびらは イエローキーがひつようだ,이 문을 열려면 황색 플렘열쇠가 필요합니다,Je hebt een gele flemsleutel nodig om deze deur te openen.,"Potrzebujesz żółtego flemowego klucza, aby otworzyć te drzwi",Você precisa de uma flemchave amarela para ativar este objeto,,Ai nevoie de o flemcheie galbenă pentru a deschide ușa aceasta,"Нужен жёлтый флемключ, чтобы открыть", -%o sinks into some slime.,OB_SLIME,,,,%o se propadl@[ao_cs] do slizu.,%o versank im Schleim,,%o malflosas subeniras en kelkan ŝlimon.,%o se hunde en lodo.,,%o uppoaa limaan,%o se noie dans la morve.,%o elsüllyedt a trutyiban.,%o affonda in qualche melma.,%o はスライムにしずんだ。,%o 는(은) 점액 속으로 가라앉았습니다.,%o zinkt in wat slijm.,%o topi się w szlamie.,%o afundou na gosma.,,%o se scufundă în mâzgă.,Игрок %o утонул в слизи., -%o sinks into some slime.,OB_LAVA,,,,%o se propadl@[ao_cs] do slizu.,%o versank im Schleim,,%o malflosas subeniras en kelkan ŝlimon.,%o se hunde en lodo.,,%o uppoaa limaan,%o se noie dans la morve.,%o elsüllyedt a trutyiban.,%o affonda in qualche melma.,%o はスライムにしずんだ。,%o 는(은) 질척하게 가라앉았습니다.,%o zinkt in wat slijm.,%o topi się w szlamie.,%o afundou na gosma.,,%o se scufundă în mâzgă.,Игрок %o утонул в слизи., -%o was hit by inter-dimensional slime!,OB_POWERSTRAND,,,,%o byl@[ao_cs] zasažen@[ao_cs] mezidimenzionálním slizem!,%o wurde von interdimensionalem Schleim getroffen,,%o estas trafita de interdimensia ŝlimo!,¡%o fue alcanzad@[ao_esp] por lodo interdimensional!,,%o parkaan osui interdimensionaalista limaa!,%o s'est fait@[e_fr] toucher par de la morve interdimensionelle!,,%o è stato colpito da melma interdimensionale!,%o は いじげんスライムまみれになった!,%o 는(은) 차원균열 점액에 맞았습니다!,%o werd geraakt door interdimensionaal slijm!,%o został@[ao_pl] uderzon@[adj_pl] przez międzywymiarowy szlam!,%o foi atingid@[ao_ptb] por gosma interdimensional!,,%o a fost lovit de mâzgă interdimensională!,В игрока %o попала межпространственная слизь!, -%o was hit by inter-dimensional slime!,OB_KILLEDSELF,,,,%o byl@[ao_cs] zasažen@[ao_cs] mezidimenzionálním slizem!,%o wurde von interdimensionalem Schleim getroffen,,%o estas trafita de interdimensia ŝlimo!,¡%o fue alcanzad@[ao_esp] por lodo interdimensional!,,%o parkaan osui interdimensionaalista limaa!,%o s'est fait@[e_fr] toucher par de la morve interdimensionelle!,,%o è stato colpito da melma interdimensionale!,%o は いじげんスライムまみれになった!,%o 는(은) 모르는 사이에 점액에 당했습니다!,%o werd geraakt door interdimensionaal slijm!,%o został@[ao_pl] uderzon@[adj_pl] przez międzywymiarowy szlam!,%o foi atingid@[ao_ptb] por gosma interdimensional!,,%o a fost lovit de mâzgă interdimensională!,В игрока %o попала межпространственная слизь!, -%o was boogered by a stridicus.,OB_STRIDICUS,,,,%o dostal@[ao_cs] holuby od běhakem.,%o wurde von einem Stridicus bepopelt.,,%o estas mukiga de paŝmukulo.,%o fue moquead@[ao_esp] por un stridicus.,,%o joutui stridicuksen räkäämäksi.,%o s'est fait@[e_fr] engluer par un stridicus.,,%o è stato colpito da uno Stridicus.,%o は ステュリクスに おびやかされた。,%o 는(은) 스트리디쿠스의 코딱지에 당했습니다.,%o werd door een stridicus gezoomd.,%o został@[ao_pl] zaglutowan@[adj_pl] przez stridicusa.,%o foi melecad@[ao_ptb] por um stridicus.,,%o a fost speriat de către un picioare-lungi.,Игрока %o облепила соплями длинноножка. , -%o was gooed by a flem mine.,OB_FLEMMINE,,,,%o byl@[ao_cs] zablácen@[ao_cs] sliznou minou.,%o wurde von einer Flem-Mine beschmiert.,,%o estas ŝlimiga de muksentinelo.,%o fue pegotead@[ao_esp] por una flem-mina.,,%o joutui limamiinan mönjäämäksi.,%o s'est fait@[e_fr] éclabousser par une flem mine.,,%o è stata colpita da una bomba a flem.,%o はフレムマインに ヒドいめにあった。,%o 는(은) 플렘 지뢰에 의해 점액 범벅이 됐습니다.,%o werd door een Flemmijn getreiterd.,"%o został@[ao_pl] zabrejowan@[adj_pl] przez flemową minę. -",%o foi engosmad@[ao_ptb] por uma mina flem.,,%o a fost lovit de mâzga unei flem mine.,Игрока %o забрызгала флем-мина., -%o was slimed by a super cycloptis.,OB_SUPERCYCLOPTIS,,,,%o byl@[ao_cs] osliznut@[ao_cs] superkykloptem.,%o wurde von einem Super Cycloptis vollgeschleimt.,,%o estas ŝlimiga de supera ciklopmukulo.,%o fue enlodad@[ao_esp] por un super cycloptis.,,%o joutui supercycloptiksen limaamaksi.,%o s'est fait@[e_fr] gélifier par un super cycloptis.,,%o è stato snellito da una Super Ciyloptis.,%o はスーパーサイクロプティスに とかされた。,%o 는(은) 슈퍼 사이클롭티스의 점액에 당했습니다.,%o werd afgeslankt door een Super Cycloptis.,%o został@[ao_pl] oszlamion@[adj_pl] przez super cykloptisa.,%o foi lambuzad@[ao_ptb] por um super cyclóptis.,,%o a fost transformat în mâzgă de către un super cicloptic.,Игрока %o обслюнявил супер-циклоптис., -%o was defeated by a Maximus.,OB_MAXIMUS,,,,%o byl@[ao_cs] poražen@[ao_cs] Maximem.,%o wurde von einem Maximus besiegt.,,%o estas venkita de ĉefmukulo.,%o fue derrotad@[ao_esp] por un Maximus.,,%o joutui Maximuksen päihittämäksi.,%o s'est fait@[e_fr] battre par un Maximus.,,%o è stato sconfitto da un Maximus.,%o はマクシムスに 敗北した。,%o 는(은) 맥시무스에게 패배했습니다.,%o werd verslagen door een Maximus.,%o został@[ao_pl] pokonan@[adj_pl] przez Maximusa.,%o foi derrotad@[ao_ptb] por um Maximus.,,%o a fost înfrânt de către un Maxim.,Игрок %o проиграл Максимусу., -%o was gooed by a larva.,OB_LARVA,,,,%o byl@[ao_cs] zacáknut@[ao_cs] larvou.,%o wurde von einer Larve beschmiert.,,%o estas ŝlimiga de larvo.,%o fue pegotead@[ao_esp] por una larva.,,%o joutui toukan mönjäämäksi.,%o s'est fait@[e_fr] tacher par une larve.,,%o è stato colpito da una larva.,%o はラーバに ヒドいめにあわされた。,%o 는(은) 애벌레에 의해 점액 범벅이 됐습니다.,%o werd door een Larve weggegooid.,%o został@[ao_pl] zabrejowan@[adj_pl] przez larwę.,%o foi engosmad@[ao_ptb] por uma larva.,,%o a fost lovit de mâzga unei larve.,Игрока %o обслюнявила личинка., -%o was slimed by a Quadrumpus.,OB_QUADRUMPUS,,,,%o byl@[ao_cs] zahleněn@[ao_cs] Čtyřzadkem.,%o wurde von einem Quadrumpus vollgeschleimt.,,%o estas ŝlimiga de kvarbrakmukulo.,%o fue enlodad@[ao_esp] por un Quadrumpus.,,%o joutui Neliperän limaamaksi.,%o s'est fait@[e_fr] morver par un quadrumpus.,,%o è stato ridotto da un Quadrumpus.,%o はクワッドロンプスに スライムにされた。,%o 는(은) 쿼드럼푸스의 점액에 당했습니다.,%o werd afgeslankt door een Quadrumpus.,%o został@[ao_pl] oszlamion@[adj_pl] przez Quadrumpusa.,%o foi melecad@[ao_ptb] por um Quadrumpus.,,%o a fost transformat în mâzgă de către o creatură cu patru mâini,Игрока %o обслюнявила многоручка. , -%o was defeated by the Flembomination.,OB_FLEMBOMINATION,,,,%o byl@[ao_cs] poražen@[ao_cs] Slizavností.,%o wurde von der Flembomination besiegt.,,%o estas venkita de la Mukabomeno.,%o fue derrotad@[ao_esp] por la Flembominación.,,%o joutui Limaoikun päihittämäksi.,%o s'est fait@[e_fr] éliminer par la Flembomination.,,%o è stato sconfitto dalla Flembomination.,%o はフレンボミネーションに敗北した。,%o 는(은) 플렘보미네이션으로부터 벗어날 수 없었습니다.,%o werd verslagen door de Flembominatie.,%o został@[ao_pl] pokonan@[adj_pl] przez Flembominację.,%o foi derrotad@[ao_ptb] pela Flembominação.,,%o a fost învins de către Flembominație.,Игрока %o победила Флемомерзость., -%o was defeated by Lord Snotfolus.,OB_SNOTFOLUS,,,,%o byl@[ao_cs] poražen@[ao_cs] Lordem Hlenfujem.,%o wurde von Lord Snotfolus besiegt.,,%o estas venkita de Lordo Mukplenulo.,%o fue derrotad@[ao_esp] por Lord Mocofolus.,,%o joutui herra Räkänokan päihittämäksi.,%o est tombé@[e_fr] face au Seigneur Morvator.,,%o è stato sconfitto da Lord Snotfolus.,%o はロード スノフォールスに敗北した。,%o 는(은) 스놋폴러스 마왕과 싸울 준비를 제대로 하지 못했습니다.,%o werd verslagen door Lord Snotfolus.,%o został@[ao_pl] pokonan@[adj_pl] przez Lorda Smarkofolusa.,%o foi derrotad@[ao_ptb] pelo Lorde Snotfolus.,,%o a fost pus la pământ de către Lordul Snotfolus.,Игрока %o победил лорд Соплезелёнус., -%o was hit by %k's propulsor.,OB_MPR_SPLASH,,,,%o byl@[ao_cs] zasažen@[ao_cs] propulzorem hráče %k.,%o wurde von %ks Propeller getroffen,,%o estas trafita de la propulsilo de %k.,%o fue alcanzad@[ao_esp] por el propulsor de %k.,,%k osui %o parkaan työntimellään.,%o s'est fait@[e_fr] propulser par %k.,,%o è stato colpito dal propulsore di %k.,%o に %k のロケットゾーチがとどいた。,%o 는(은) %k 의 추진력에 휘말렸습니다.,%o werd geraakt door %k's propulsor.,%o został@[ao_pl] uderzon@[adj_pl] przez pędnik %k.,%o foi atingid@[ao_ptb] pelo propulsor de %k.,,%o a fost lovit de către propulsorul lui %k.,Игрок %o подстрелен из Ускорителя Зорча %k., -%o was lazzed by %k.,OB_MPBFG_SPLASH,,,,%o byl@[ao_cs] odlazován@[ao_cs] hráčem %k.,%o wurde von %o weggezorcht.,,%o estas LAZ-ita de %k.,%o fue lazead@[ao_esp] por %k.,,%k sazzasi pelaajaan %o.,%o est entré@[e_fr] dans la zone de zorchage large de %k.,,%o è stato lazzato da %k.,%o は %k にとかされた。,%o 는(은) %k 에게 레이져를 쐬였습니다.,%o werd gelazzed door %k.,%o został@[ao_pl] zLAZowan@[adj_pl] przez %k.,%o foi LAZead@[ao_ptb] por %k.,,%k a folosit dispozitivul LAZ pe %o.,Игрок %o получил заряд из «ЗБР» игрока %k., +default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,da,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,no nb,pl,pt,ptg,ro,ru,sr,sv,tr +Picked up a blue flemkey.,GOTBLUEFLEM,Flem = phlegm,,,Sebrán modrý slizoklíč.,Du samlede en blå flemkey op.,Blauen Flemschlüssel genommen,,Vi trovis bluan mukŝlosilon.,Encuentras una flemllave azul.,,Poimit sinisen lima-avaimen,Flemclé bleue récupérée.,Kék slejmkulcs felvéve.,Raccolta una chiave-flem blu.,ブルー フレムキー をみつけた,청색 플렘열쇠 획득.,Je hebt een blauwe flemsleutel opgehaald.,Plukket opp en blå flemkey.,Zebrano niebieski flemowy klucz,Pegou uma flemchave azul.,,Ai ridicat flemcheia albastră.,Получен синий флемключ.,,Plockade upp en blå flemnyckel.,Mavi bir flemkey aldım. +Picked up a yellow flemkey.,GOTYELLOWFLEM,,,,Sebrán žlutý slizoklíč.,Du samlede en gul flemkey op.,Gelben Flemschlüssel genommen,,Vi trovis flavan mukŝlosilon.,Encuentras una flemllave amarilla.,,Poimit keltaisen lima-avaimen,Flemclé jaune récupérée.,Sárga slejmkulcs felvéve.,Raccolta una chiave-flem gialla.,イエローフレムキー をみつけた,황색 플렘열쇠 획득.,Je hebt een gele flemsleutel opgehaald.,Plukket opp en gul flemkey.,Zebrano żółty flemowy klucz,Pegou uma flemchave amarela.,,Ai ridicat flemcheia galbenă.,Получен жёлтый флемключ.,,Plockade upp en gul flemnyckel.,Sarı bir flemkey aldı. +Picked up a red flemkey.,GOTREDFLEM,,,,Sebrán červený slizoklíč.,Du samlede en rød flemkey op.,Roten Flemschlüssel genommen.,,Vi trovis ruĝan mukŝlosilon.,Encuentras una flemllave roja.,,Poimit punaisen lima-avaimen,Flemclé rouge récupérée.,Piros slejmkulcs felvéve.,Raccolta una chiave-flem rossa.,レッド フレムキー をみつけた,적색 플렘열쇠 획득.,Je hebt een rode flemsleutel opgehaald.,Plukket opp en rød flemkey.,Zebrano czerwony flemowy klucz,Pegou uma flemchave vermelha.,,Ai ridicat flemcheia roșie.,Получен красный флемключ.,,Plockade upp en röd flemnyckel.,Kırmızı bir flemkey aldı. +Found Ultra Goggles,GOTGOGGLES,,,,Nalezeny ultrabrýle.,Fandt Ultra Goggles,Ultrasichtbrille gefunden,,Vi trovis plejajn okulvitrojn.,Encuentras ultragafas,Encuentras ultralentes,Löysit ultralasit,Ultra-lunettes récupérées.,Ultraszemüveg felvéve.,,ウルトラゴーグル をみつけた,울트라 고글 사용.,Ultraroggles gevonden,Fant Ultra Goggles,Znaleziono Ultra Gogle,Achou um Ultra Óculos.,,Ai găsit Ultra Ochelarii,Получены ультра-очки,,Hittade Ultra Goggles,Ultra Gözlük bulundu +You need a blue key to activate this object,PD_BLUECO,,,,Potřebuješ modrý klíč pro aktivaci tohoto objektu,Du skal bruge en blå nøgle for at aktivere dette objekt,"Du brauchst einen blauen Schlüssel, um dieses Objekt zu aktivieren.",,"Vi bezonas bluan ŝlosilon +por aktivigi ĉi tiun objekton.","Necesitas una llave azul +para activar este objeto",,Tarvitset sinisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé bleue pour activer cet objet.,Egy kék kulcs szükséges az objektum aktiválásához.,Ti serve una chiave blu per attivare questo oggetto,このそうちは ブルー キー がひつようだ,이걸 작동하려면 청색 열쇠가 필요합니다,Je hebt een blauwe sleutel nodig om dit object te activeren.,Du trenger en blå nøkkel for å aktivere dette objektet,"Potrzebujesz niebieskiego klucza, aby aktywować ten przedmiot",Você precisa de uma chave azul para ativar este objeto,,Ai nevoie de o cheie albastră pentru a activa acest obiect,Для открытия требуется синий ключ,Треба вам плави кључ да бисте активирали овај предмет,Du behöver en blå nyckel för att aktivera det här objektet.,Bu nesneyi etkinleştirmek için mavi bir anahtara ihtiyacınız var +You need a red key to activate this object,PD_REDCO,,,,Potřebuješ červený klíč pro aktivaci tohoto objektu,Du skal bruge en rød nøgle for at aktivere dette objekt,"Du brauchst einen roten Schlüssel, um dieses Objekt zu aktivieren.",,"Vi bezonas ruĝan ŝlosilon +por aktivigi ĉi tiun objekton.","Necesitas una llave roja +para activar este objeto",,Tarvitset punaisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé rouge pour activer cet objet.,Egy piros kulcs szükséges az objektum aktiválásához.,Ti serve una chiave rossa per attivare questo oggetto,このそうちは レッド キー がひつようだ,이걸 작동하려면 적색 열쇠가 필요합니다,Je hebt een rode sleutel nodig om dit object te activeren.,Du trenger en rød nøkkel for å aktivere denne gjenstanden,"Potrzebujesz czerwonego klucza, aby aktywować ten przedmiot",Você precisa de uma chave vermelha para ativar este objeto,,Ai nevoie de o cheie roșie pentru a activa acest obiect,Для открытия требуется красный ключ,Треба вам црвени кључ да бисте активирали овај предмет,Du behöver en röd nyckel för att aktivera det här objektet.,Bu nesneyi etkinleştirmek için kırmızı bir anahtara ihtiyacınız var +You need a yellow key to activate this object,PD_YELLOWCO,,,,Potřebuješ žlutý klíč pro aktivaci tohoto objektu,Du skal bruge en gul nøgle for at aktivere dette objekt,"Du brauchst einen gelben Schlüssel, um dieses Objekt zu aktivieren.",,"Vi bezonas flavan ŝlosilon +por aktivigi ĉi tiun objekton.","Necesitas una llave amarilla +para activar este objeto",,Tarvitset keltaisen avaimen aktivoidaksesi tämän kappaleen,Il vous faut une clé jaune pour activer cet objet.,Egy sárga kulcs szükséges az objektum aktiválásához.,Ti serve una chiave gialla per attivare questo oggetto,このそうちは イエローキー がひつようだ,이걸 작동하려면 황색 열쇠가 필요합니다,Je hebt een gele sleutel nodig om dit object te activeren.,Du trenger en gul nøkkel for å aktivere denne gjenstanden,"Potrzebujesz żółtego klucza, aby aktywować ten przedmiot",Você precisa de uma chave amarela para ativar este objeto,,Ai nevoie de o cheie galbenă pentru a activa acest obiect,Для открытия требуется жёлтый ключ,Треба вам жути кључ да бисте активирали овај предмет,Du behöver en gul nyckel för att aktivera det här objektet.,Bu nesneyi etkinleştirmek için sarı bir anahtara ihtiyacınız var +You need a blue flemkey to activate this object,PD_BLUEFO,,,,Potřebuješ modrý slizoklíč pro aktivaci tohoto objektu.,Du skal bruge en blå flemkey for at aktivere dette objekt,"Du brauchst einen blauen Flemschlüssel, um dieses Objekt zu aktivieren.",,"Vi bezonas bluan mukŝlosilon +por aktivigi ĉi tiun objekton.","Necesitas una flemllave azul +para activar este objeto",,Tarvitset sinisen lima-avaimen aktivoidaksesi tämän kappaleen,Il vous faut une flemclé bleue pour activer cet objet.,Egy kék slejmkulcs szükséges az objektum aktiválásához.,Ti serve una chiave-flem blu per attivare questo oggetto,このそうちは ブルー キーがひつようだ,이걸 작동하려면 청색 플렘열쇠가 필요합니다,Je hebt een blauwe flemsleutel nodig om dit object te activeren.,Du trenger en blå flemkey for å aktivere denne gjenstanden.,"Potrzebujesz niebieskiego flemowego klucza, aby aktywować ten przedmiot",Você precisa de uma flemchave azul para ativar este objeto,,Ai nevoie de o flemcheie albastră pentru a activa acest obiect,Для открытия требуется синий флемключ,,Du behöver en blå flemnyckel för att aktivera det här objektet.,Bu nesneyi etkinleştirmek için mavi bir flemkey'e ihtiyacınız var +You need a red flemkey to activate this object,PD_REDFO,,,,Potřebuješ červený slizoklíč pro aktivaci tohoto objektu.,Du skal bruge en rød flemkey for at aktivere dette objekt,"Du brauchst einen roten Flemschlüssel, um dieses Objekt zu aktivieren.",,"Vi bezonas ruĝan mukŝlosilon +por aktivigi ĉi tiun objekton.","Necesitas una flemllave roja +para activar este objeto",,Tarvitset punaisen lima-avaimen aktivoidaksesi tämän kappaleen,Il vous faut une flemclé rouge pour activer cet objet.,Egy piros slejmkulcs szükséges az objektum aktiválásához.,Ti serve una chiave-flem rossa per attivare questo oggetto,このそうちは レッド キーがひつようだ,이걸 작동하려면 적색 플렘열쇠가 필요합니다,Je hebt een rode flemsleutel nodig om dit object te activeren.,Du trenger en rød flemkey for å aktivere dette objektet.,"Potrzebujesz czerwonego flemowego klucza, aby aktywować ten przedmiot",Você precisa de uma flemchave vermelha para ativar este objeto,,Ai nevoie de o flemcheie roșie pentru a activa acest obiect,Для открытия требуется красный флемключ,,Du behöver en röd flemnyckel för att aktivera det här objektet.,Bu nesneyi etkinleştirmek için kırmızı bir flemkey'e ihtiyacınız var +You need a yellow flemkey to activate this object,PD_YELLOWFO,,,,Potřebuješ žlutý slizoklíč pro aktivaci tohoto objektu.,Du skal bruge en gul flemkey for at aktivere dette objekt,"Du brauchst einen gelben Flemschlüssel, um dieses Objekt zu aktivieren.",,"Vi bezonas flavan mukŝlosilon +por aktivigi ĉi tiun objekton.","Necesitas unaflemllave amarilla +para activar este objeto",,Tarvitset keltaisen lima-avaimen aktivoidaksesi tämän kappaleen,Il vous faut une flemclé jaune pour activer cet objet.,Egy sárga slejmkulcs szükséges az objektum aktiválásához.,Ti serve una chiave-flem gialla per attivare questo oggetto,このそうちは イエローキーがひつようだ,이걸 작동하려면 황색 플렘열쇠가 필요합니다,Je hebt een gele flemsleutel nodig om dit object te activeren.,Du trenger en gul flemkey for å aktivere dette objektet.,"Potrzebujesz żółtego flemowego klucza, aby aktywować ten przedmiot",Você precisa de uma flemchave amarela para ativar este objeto,,Ai nevoie de o flemcheie galbenă pentru a activa acest obiect,Для открытия требуется жёлтый флемключ,,Du behöver en gul flemnyckel för att aktivera det här objektet.,Bu nesneyi etkinleştirmek için sarı bir flemkey'e ihtiyacınız var +Picked up a zorcher.,PICKUP_PISTOL_DROPPED,,,,Sebrán bzukr.,Du samlede en zorcher op.,Zorcher genommen.,,Vi trovis zorĉilon.,Encuentras un zorcher.,,Poimit zorcherin,Zorcheur récupéré.,Szörcsölő felvéve.,Ho preso uno zorcher.,ゾーチャー をひろった,자쳐 습득.,Je hebt een zorcher opgehaald.,Plukket opp en zorcher.,Zebrano Zorcher,Pegou um zorcher.,,Ai ridicat un zorcher.,Получен зорчер.,,Plockade upp en zorcher.,Bir zorcher aldım. +Zorch and keys added,STSTR_KFAADDED,,,,Bzukr a klíče přidány,Zorch og nøgler tilføjet,Zorch und Schlüssel hinzugefügt.,,Zorĉaĵo kaj ŝlosiloj aldonitaj,Zorch y llaves añadidas,,Zorch ja avaimet lisätty,Zorch et clés ajoutées.,Szörcs és kulcsok hozzáadva.,Zorch e chiavi aggiunte,ゾーチ と キーがとどいた,저치와 열쇠,Zorch en sleutels toegevoegd,Zorch og nøkler lagt til,Dodano amunicję Zorch i klucze,Zorch e chaves adicionadas,,Zorcher și chei adăugate,Зорч и ключи получены,,Zorch och nycklar har lagts till,Zorch ve anahtarlar eklendi +E1M1: Landing Zone,HUSTR_E1M1,,,,E1M1: Přistávací zóna,E1M1: Landingszone,E1M1: Landezone,,E1M1: Surteriĝejo,E1M1: Zona de aterrizaje,,E1M1: Laskeutumisalue,E1M1: Zone D'Atterissage,E1M1: Leszállópálya,E1M1: Zona di Atterraggio,E1M1: ちゃくち ちてん,E1M1: 착륙 지점,E1M1: Landingzone,E1M1: Landingssone,E1M1: Strefa Lądowania,E1M1: Zona de Pouso,,E1M1: Zona de Aterizare,E1M1: Зона высадки,,E1M1: Landningszon,E1M1: İniş Bölgesi +E1M2: Storage Facility,HUSTR_E1M2,,,,E1M2: Skladiště,E1M2: Opbevaringsanlæg,E1M2: Lagerhalle,,E1M2: Stokejo,E1M2: Instalación de almacenamiento,,E1M2: Varastolaitos,E1M2: Centre de Stockage,E1M2: Raktárépület,E1M2: Struttura di Immagazzinamento,E1M2: ちょぞう しせつ,E1M2: 저장 시설,E1M2: Opslagfaciliteit,E1M2: Lagringsanlegg,E1M2: Magazyn,E1M2: Depósito,,E1M2: Depozitul,E1M2: Хранилище,,E1M2: Förvaringsanläggning,E1M2: Depolama Tesisi +E1M3: Laboratory,HUSTR_E1M3,,,,E1M3: Testovací laboratoř,E1M3: Laboratorium,E1M3: Labor,,E1M3: Laboratorio,E1M3: Laboratorio,,E1M3: Laboratorio,E1M3: Laboratoire,E1M3: Laboratórium,E1M3: Laboratorio,E1M3: ラボラトリー,E1M3: 연구소,E1M3: Laboratorium,E1M3: Laboratorium,E1M3: Laboratorium,E1M3: Laboratório de Experimentos,,E1M3: Laboratorul,E1M3: Лаборатория,,E1M3: Laboratorium,E1M3: Laboratuvar +E1M4: Arboretum,HUSTR_E1M4,,,,,,,,E1M4: Arbejo,E1M4: Arboreto,,,,E1M4: Arborétum,E1M4: Arboreto,E1M4: じゅもく園,E1M4: 수목원,,E1M4: Arboretet,E1M4: Arboretum,E1M4: Arvoredo,,,E1M4: Дендрарий,,, +E1M5: Caverns of Bazoik,HUSTR_E1M5,,,,E1M5: Bazoikské jeskyně,E1M5: Bazoiks grotter,E1M5: Die Höhlen von Bazoik,,E1M5: Kavernoj de Bazojko,E1M5: Cavernas de Bazoik,,E1M5: Bazoikin luolastot,E1M5: Cavernes de Bazoik,E1M5: Bazoik barlangjai,E1M5: Caverne di Bazoik,E1M5: バゾイクのどうくつ,E1M5: 바조이크의 대동굴,E1M5: Grotten van Bazoik,E1M5: Grottene i Bazoik,E1M5: Jaskinie Bazoik,E1M5: Cavernas de Bazoik,,E1M5: Cavernele lui Bazoik,E1M5: Пещеры Базоика,,E1M5: Bazoiks grottor,E1M5: Bazoik Mağaraları +E2M1: Spaceport,HUSTR_E2M1,,,,E2M1: Kosmodrom,E2M1: Rumhavn,E2M1: Raumhafen,,E2M1: Kosmo-haveno,E2M1: Puerto espacial,,E2M1: Avaruussatama,E2M1: Spatioport,E2M1: Űrkikötő,E2M1: Spazioporto,E2M1: スペースポート,E2M1: 우주공항,E2M1: Ruimtehaven,E2M1: Romhavn,E2M1: Port Kosmiczny,E2M1: Espaçoporto,,E2M1: Portul Spațial,E2M1: Космодром,,E2M1: Rymdflygplats,E2M1: Uzay Limanı +E2M2: Cinema,HUSTR_E2M2,,,,E2M2: Kino,,E2M2: Kino,,E2M2: Kinejo,E2M2: Cine,,E2M2: Elokuvateatteri,E2M2: Cinéma,E2M2: Mozi,,E2M2: シネマ,E2M2: 극장,E2M2: Bioscoop,E2M2: Kino,E2M2: Kino,,,,E2M2: Кинотеатр,,,E2M2: Sinema +E2M3: Chex Museum,HUSTR_E2M3,,,,E2M3: Muzem Chex,,,,E2M3: Chex-muzeo,E2M3: Museo de Chex,,E2M3: Chex-museo,E2M3: Musée Chex,E2M3: Chex-múzeum,E2M3: Museo di Chex,E2M3: チェックス ミュージアム,E2M3: 첵스 박물관,,,E2M3: Muzeum Chex,E2M3: Museu Chex,,E2M3: Muzeul Chex,E2M3: Музей Chex,,,E2M3: Chex Müzesi +E2M4: City Streets,HUSTR_E2M4,,,,E2M4: Městské ulice,E2M4: Byens gader,E2M4: städtische Straßen,,E2M4: Urbstratoj,E2M4: Calles de la ciudad,,E2M4: Kaupungin kadut,E2M4: Rues de la Ville,E2M4: Városi utcák,E2M4: Strade della città,E2M4: シティーストリート,E2M4: 도시 거리,E2M4: Stadsstraten,E2M4: Byens gater,E2M4: Ulice Miasta,E2M4: Ruas da Cidade,,E2M4: Străzile Orașului,E2M4: Городские улицы,,E2M4: Stadens gator,E2M4: Şehir Sokakları +E2M5: Sewer System,HUSTR_E2M5,,,,E2M5: Kanalizace,E2M5: Kloaksystem,E2M5: Kanalisation,,E2M5: Defluilego-sistemo,E2M5: Alcantarillado,,E2M5: Viemärijärjestelmä,E2M5: Système d'égouts,E2M5: Csatornarendszer,E2M5: Rete fognaria,E2M5: サワーシステム,E2M5: 하수도,E2M5: Rioleringssysteem,E2M5: Avløpssystem,E2M5: System Ścieków,E2M5: Rede de Esgoto,,E2M5: Sistemul de Canalizare,E2M5: Канализация,,E2M5: Avloppssystem,E2M5: Kanalizasyon Sistemi +E3M1: Central Command,HUSTR_E3M1,,,,E3M1: Centrální velení,E3M1: Centralkommando,E3M1: Kommandozentrale,,E3M1: Centra komandejo,E3M1: Comando central,,E3M1: Komentokeskus,E3M1: Commandement,E3M1: Központi parancsnokság,E3M1: Comando centrale,E3M1: 中央しれいとう,E3M1: 중앙 사령부,E3M1: Centraal Commando,E3M1: Sentral kommando,E3M1: Centrum Dowodzenia,E3M1: Comando Central,,E3M1: Centrul de Comanda,E3M1: Командный центр,,E3M1: Centrala kommandot,E3M1: Merkez Komutanlığı +E3M2: United Cereals,HUSTR_E3M2,,,,E3M2: Spojené cereálie,,E3M2: Vereinigte Zerealien,,E3M2: Uniaj Cerealoj,E3M2: Cereales Unidos,,E3M2: Yhdistyneet murot,E3M2: Céréales Unies,E3M2: Egyesült Gabonapelyhek,E3M2: Cereali uniti,E3M2: ユナイテッド シリアル,E3M2: 시리얼 연합,E3M2: Verenigde granen,,E3M2: Zjednoczone Płatki,E3M2: Cereais Unidos,,E3M2: Cereale Unite,E3M2: Организация Объединённых Хлопьев,,E3M2: United Cereals,E3M2: Birleşik Tahıllar +E3M3: Villa Chex,HUSTR_E3M3,,,,,,,,E3M3: Vilao Chex,,,,E3M3: Villa Chex,,,E3M3: チェックスのべっそう,E3M3: 책스 주택,,,E3M3: Willa Chex,,,E3M3: Vila Chex,E3M3: Вилла Chex,,, +E3M4: Provincial Park,HUSTR_E3M4,,,,E3M4: Provinciální park,,E3M4: Provinzpark,,E3M4: Provinca parko,E3M4: Parque provincial,,E3M4: Provinssipuisto,E3M4: Parc Naturel,E3M4: Tartományi park,E3M4: Parco provinciale,E3M4: 州立公園,E3M4: 주립공원,E3M4: Provinciaal Park,,E3M4: Prowincjonalny Park,E3M4: Parque Natural,,E3M4: Parcul Provincial,E3M4: Провинциальный парк,,,E3M4: İl Parkı +E3M5: Meteor Spaceship,HUSTR_E3M5,,,,E3M5: Meteorová vesmírná loď,E3M5: Meteor rumskib,E3M5: Meteor-Raumschiff,,E3M5: Meteor-kosmoŝipo,E3M5: Nave meteoro,,E3M5: Meteoriavaruusalus,E3M5: Vaisseau Météore,E3M5: Meteor űrhajó,E2M5: Astronave meteorica,E3M5: メテオスペースシップ,E3M5: 거대 유성호,E3M5: Ruimteschip,E3M5: Meteor-romskipet,"E3M5: Statek Kosmiczny ""Meteor""",E3M5: Espaçonave Meteoro,,E3M5: Nava Spațială Meteor,E3M5: Космический корабль «Метеор»,,E3M5: Rymdskeppet Meteor,E3M5: Meteor Uzay Gemisi +Commonus,CC_ZOMBIE,,,,Obecnýs,,,,Oftmukulo,Comunis,,,,Általánusz,,コモンズ,커머누스,,,Pospolitus,,,Comun,Обыкновеннус,,, +Bipedicus,CC_SHOTGUN,,,,Dvojnožus,,,,Dupiedmukulo,Bipedico,,,,Kétlábusz,,バイピディクス,바이피디쿠스,,,,,,Biped,Двуножка,,, +Bipedicus with Armor,CC_IMP,,,,Dvojnožus s brněním,Bipedicus med rustning,Bipedicus mit Panzerung,,Kirasa Dupiedmukulo,Bipedico con armadura,,Panssaroitu bipedicus,Bipedicus avec Armure,Páncélozott kétlábusz,Bipedicus corazzato,アーマードバイピディクス,정예 바이피디쿠스,Bipedicus met harnas,Bipedicus med rustning,Opancerzony Bipedicus,Bipedicus de Armadura,,Biped cu Armură,Бронированная двуножка,,Bipedicus med rustning,Zırhlı Bipedicus +Stridicus,CC_DEMON,,,,Běhakus,,,,Paŝmukulo,Zancadico,,,,Lépkedüsz,,ステュリクス,스트리디쿠스,,,,,,Picioare-Lungi,Длинноножка,,, +Flem Mine,CC_LOST,,,,Slizná mina,,,,Muksentinelo,Flem-Mina,,Limamiina,,Slejmakna,Bomba a Flem,フレムマイン,플렘 지뢰,Flemmijn,,Flemowa Mina,Mina Flem,,Flem Mină,Флем-мина,,Flem-gruva,Flem Madeni +Super Cycloptis,CC_CACO,,,,Superkykloptus,,,,Supera Ciklopmukulo,Supercícloptis,,Supercycloptis,,Szuper Kükloptisz,,スーパーサイクロプティス,슈퍼 사이클롭티스,,Supersykloptis.,Super Cykloptis,,,Super Cicloptic,Супер-циклоптис,,,Süper Cycloptis +Maximus,CC_BARON,,,,,,,,Mukulestro,Máximus,,,,Maximusz,,マクシムス,맥시무스,,,,,,Maxim,Максимус,,, +The Flembomination,CC_SPIDER,,,,Slizavnost,Flembominationen,Die Flembomination,,Mukabomeno,La Flembominación,,Limaoikku,La Flembomination,Slejmdormány,La Flembominio,フレンボミネーション,플렘보미네이션,De Flembominatie,Flembominationen,Flembominacja,A Flembominação,,Flembominație,Флемомерзость,,Flammbomineringen,Flembomination +Lord Snotfolus,CC_CYBER,,,,Lord Hlenfujus,,,,Lordo Mukplenulo,Lord Mocofolus,,Herra Räkänokka,Seigneur Morvator,Lord Takony,,ロード スノフォールス,스놋폴러스 마왕,,,Lord Smarkofolus,Lorde Snotfolus,,Lordul Snotfolus,Правитель Соплезелёнус,,, +Chex Warrior,CC_HERO,,,,Bojovník Chex,Chex Kriger,Chex Krieger,,Chex-batalisto,,,Chex-soturi,Guerrier Chex,Chex harcos,Guerriero Chex,チェックスのせんし,첵스 전사,Chex Krijger,Chex-krigeren,Wojownik Chex,Guerreiro Chex,,Războinic Chex,Воин Chex,,Chex krigare,Chex Savaşçısı +You need a blue key to open this door,PD_BLUEC,,,,Potřebuješ modrý klíč pro otevření těchto dveří,Du skal bruge en blå nøgle for at åbne denne dør,"Du brauchst einen blauen Schlüssel, um diese Tür zu öffnen.",,"Vi bezonas bluan ŝlosilon +por malfermi ĉi tiun pordon.","Necesitas una llave azul +para abrir esta puerta",,Tarvitset sinisen avaimen avataksesi tämän oven,Il vous faut une clé bleue pour ouvrir cette porte.,Kell egy kék kulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave blu per aprire questa porta,このとびらは ブルー キー がひつようだ,이 문을 열려면 청색 열쇠가 필요합니다,Je hebt een blauwe sleutel nodig om deze deur te openen.,Du trenger en blå nøkkel for å åpne denne døren,"Potrzebujesz niebieskiego klucza, aby otworzyć te drzwi",Você precisa de uma chave azul para abrir essa porta,,Ai nevoie de o cheie albastră pentru a deschide ușa aceasta,"Нужен синий ключ, чтобы открыть",Треба вам плави кључ да бисте отворили ова врата,Du behöver en blå nyckel för att öppna den här dörren.,Bu kapıyı açmak için mavi bir anahtara ihtiyacın var. +You need a red key to open this door,PD_REDC,,,,Potřebuješ červený klíč pro otevření těchto dveří,Du skal bruge en rød nøgle for at åbne denne dør,"Du brauchst einen roten Schlüssel, um diese Tür zu öffnen.",,"Vi bezonas ruĝan ŝlosilon +por malfermi ĉi tiun pordon.","Necesitas una llave roja +para abrir esta puerta",,Tarvitset punaisen avaimen avataksesi tämän oven,Il vous faut une clé rouge pour ouvrir cette porte.,Kell egy piros kulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave rossa per aprire questa porta,このとびらは レッド キー がひつようだ,이 문을 열려면 적색 열쇠가 필요합니다,Je hebt een rode sleutel nodig om deze deur te openen.,Du trenger en rød nøkkel for å åpne denne døren,"Potrzebujesz czerwonego klucza, aby otworzyć te drzwi",Você precisa de uma chave vermelha para abrir essa porta,,Ai nevoie de o cheie roșie pentru a deschide ușa aceasta,"Нужен красный ключ, чтобы открыть",Треба вам црвени кључ да бисте отворили ова врата,Du behöver en röd nyckel för att öppna den här dörren,Bu kapıyı açmak için kırmızı bir anahtara ihtiyacın var. +You need a yellow key to open this door,PD_YELLOWC,,,,Potřebuješ žlutý klíč pro otevření těchto dveří,Du skal bruge en gul nøgle for at åbne denne dør,"Du brauchst einen gelben Schlüssel, um diese Tür zu öffnen.",,"Vi bezonas flavan ŝlosilon +por malfermi ĉi tiun pordon.","Necesitas una llave amarilla +para abrir esta puerta",,Tarvitset keltaisen avaimen avataksesi tämän oven,Il vous faut une clé jaune pour ouvrir cette porte.,Kell egy sárga kulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave gialla per aprire questa porta,このとびらは イエローキー がひつようだ,이 문을 열려면 황색 열쇠가 필요합니다,Je hebt een gele sleutel nodig om deze deur te openen.,Du trenger en gul nøkkel for å åpne denne døren,"Potrzebujesz żółtego klucza, aby otworzyć te drzwi",Você precisa de uma chave amarela para abrir essa porta,,Ai nevoie de o cheie galbenă pentru a deschide ușa aceasta,"Нужен жёлтый ключ, чтобы открыть",Треба вам жути кључ да бисте отворили ова врата,Du behöver en gul nyckel för att öppna den här dörren,Bu kapıyı açmak için sarı bir anahtara ihtiyacınız var +You need a blue flemkey to open this door,PD_BLUEF,,,,Potřebuješ modrý slizoklíč pro otevření těchto dveří,Du skal bruge en blå flemkey for at åbne denne dør,"Du brauchst einen blauen Flemschlüssel, um diese Tür zu öffnen.",,"Vi bezonas bluan mukŝlosilon +por malfermi ĉi tiun pordon.","Necesitas una flemllave azul +para abrir esta puerta",,Tarvitset sinisen lima-avaimen avataksesi tämän oven,Il vous faut une flemclé bleue pour ouvrir cette porte.,Kell egy kék slejmkulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave-flem blu per aprire questa porta,このとびらは ブルー キーがひつようだ,이 문을 열려면 청색 플렘열쇠가 필요합니다,Je hebt een blauwe flemsleutel nodig om deze deur te openen.,Du trenger en blå flemkey for å åpne denne døren,"Potrzebujesz niebieskiego flemowego klucza, aby otworzyć te drzwi",Você precisa de uma flemchave azul para ativar este objeto,,Ai nevoie de o flemcheie albastră pentru a deschide ușa aceasta,"Нужен синий флемключ, чтобы открыть",,Du behöver en blå flemnyckel för att öppna den här dörren.,Bu kapıyı açmak için mavi bir flemkey'e ihtiyacın var. +You need a red flemkey to open this door,PD_REDF,,,,Potřebuješ červený slizoklíč pro otevření těchto dveří,Du skal bruge en rød flemkey for at åbne denne dør,"Du brauchst einen roten Flemschlüssel, um diese Tür zu öffnen.",,"Vi bezonas ruĝan mukŝlosilon +por malfermi ĉi tiun pordon.","Necesitas una flemllave roja +para abrir esta puerta",,Tarvitset punaisen lima-avaimen avataksesi tämän oven,Il vous faut une flemclé rouge pour ouvrir cette porte.,Kell egy piros slejmkulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave-flem rossa per aprire questa porta,このとびらは レッド キーがひつようだ,이 문을 열려면 적색 플렘열쇠가 필요합니다,Je hebt een rode flemsleutel nodig om deze deur te openen.,Du trenger en rød flemkey for å åpne denne døren,"Potrzebujesz czerwonego flemowego klucza, aby otworzyć te drzwi",Você precisa de uma flemchave vermelha para ativar este objeto,,Ai nevoie de o flemcheie roșie pentru a deschide ușa aceasta,"Нужен красный флемключ, чтобы открыть",,Du behöver en röd flemnyckel för att öppna den här dörren.,Bu kapıyı açmak için kırmızı bir flemkey'e ihtiyacın var. +You need a yellow flemkey to open this door,PD_YELLOWF,,,,Potřebuješ žlutý slizoklíč pro otevření těchto dveří,Du har brug for en gul flemkey for at åbne denne dør,"Du brauchst einen gelben Flemschlüssel, um diese Tür zu öffnen.",,"Vi bezonas flavan mukŝlosilon +por malfermi ĉi tiun pordon.","Necesitas una flemllave amarilla +para abrir esta puerta",,Tarvitset keltaisen lima-avaimen avataksesi tämän oven,Il vous faut une flemclé jaune pour ouvrir cette porte.,Kell egy sárga slejmkulcs hogy kinyisd ezt az ajtót.,Ti serve una chiave-flem gialla per aprire questa porta,このとびらは イエローキーがひつようだ,이 문을 열려면 황색 플렘열쇠가 필요합니다,Je hebt een gele flemsleutel nodig om deze deur te openen.,Du trenger en gul flemkey for å åpne denne døren,"Potrzebujesz żółtego flemowego klucza, aby otworzyć te drzwi",Você precisa de uma flemchave amarela para ativar este objeto,,Ai nevoie de o flemcheie galbenă pentru a deschide ușa aceasta,"Нужен жёлтый флемключ, чтобы открыть",,Du behöver en gul flemnyckel för att öppna den här dörren.,Bu kapıyı açmak için sarı bir flemkey'e ihtiyacın var. +%o sinks into some slime.,OB_SLIME,,,,%o se propadl@[ao_cs] do slizu.,%o synker ned i noget slim.,%o versank im Schleim,,%o sinkas en ŝlimon.,%o se hunde en babas.,,%o uppoaa limaan,%o se noie dans la morve.,%o elsüllyedt a trutyiban.,%o affonda in qualche melma.,%o はスライムにしずんだ。,%o 는(은) 점액 속으로 가라앉았습니다.,%o zinkt in wat slijm.,%o synker ned i noe slim.,%o topi się w szlamie.,%o afundou na gosma.,,%o se scufundă în mâzgă.,Игрок %o утонул в слизи.,,%o sjunker ner i lite slem.,%o balçığın içine battı. +%o sinks into some slime.,OB_LAVA,,,,%o se propadl@[ao_cs] do slizu.,%o synker ned i noget slim.,%o versank im Schleim,,%o sinkas en ŝlimon.,%o se hunde en babas.,,%o uppoaa limaan,%o se noie dans la morve.,%o elsüllyedt a trutyiban.,%o affonda in qualche melma.,%o はスライムにしずんだ。,%o 는(은) 질척하게 가라앉았습니다.,%o zinkt in wat slijm.,%o synker ned i noe slim.,%o topi się w szlamie.,%o afundou na gosma.,,%o se scufundă în mâzgă.,Игрок %o утонул в слизи.,,%o sjunker ner i lite slem.,%o balçığın içine battı. +%o was hit by inter-dimensional slime!,OB_POWERSTRAND,,,,%o byl@[ao_cs] zasažen@[ao_cs] mezidimenzionálním slizem!,%o blev ramt af interdimensionalt slim!,%o wurde von interdimensionalem Schleim getroffen,,%o estis trafita de interdimensia ŝlimo!,¡A %o l@[ao_esp] ha alcanzado baba interdimensional!,¡A %o l@[ao_esp] alcanzó baba interdimensional!,%o parkaan osui interdimensionaalista limaa!,%o s'est fait@[e_fr] toucher par de la morve interdimensionelle!,%o interdimenzionális trutyi áldozata lett!,%o è stato colpito da melma interdimensionale!,%o は いじげんスライムまみれになった!,%o 는(은) 차원균열 점액에 맞았습니다!,%o werd geraakt door interdimensionaal slijm!,%o ble truffet av interdimensjonalt slim!,%o został@[ao_pl] uderzon@[adj_pl] przez międzywymiarowy szlam!,%o foi atingid@[ao_ptb] por gosma interdimensional!,,%o a fost lovit de mâzgă interdimensională!,В игрока %o попала межпространственная слизь!,,%o träffades av interdimensionellt slem!,%o boyutlar arası balçık tarafından vuruldu! +%o was hit by inter-dimensional slime!,OB_KILLEDSELF,,,,%o byl@[ao_cs] zasažen@[ao_cs] mezidimenzionálním slizem!,%o blev ramt af interdimensionalt slim!,%o wurde von interdimensionalem Schleim getroffen,,%o estis trafita de interdimensia ŝlimo!,¡A %o l@[ao_esp] ha alcanzado baba interdimensional!,¡A %o l@[ao_esp] alcanzó baba interdimensional!,%o parkaan osui interdimensionaalista limaa!,%o s'est fait@[e_fr] toucher par de la morve interdimensionelle!,%o interdimenzionális trutyi áldozata lett!,%o è stato colpito da melma interdimensionale!,%o は いじげんスライムまみれになった!,%o 는(은) 모르는 사이에 점액에 당했습니다!,%o werd geraakt door interdimensionaal slijm!,%o ble truffet av interdimensjonalt slim!,%o został@[ao_pl] uderzon@[adj_pl] przez międzywymiarowy szlam!,%o foi atingid@[ao_ptb] por gosma interdimensional!,,%o a fost lovit de mâzgă interdimensională!,В игрока %o попала межпространственная слизь!,,%o träffades av interdimensionellt slem!,%o boyutlar arası balçık tarafından vuruldu! +%o was boogered by a stridicus.,OB_STRIDICUS,,,,%o dostal@[ao_cs] holuby od běhakem.,%o blev buogered af en stridicus.,%o wurde von einem Stridicus bepopelt.,,%o estis mukigita de Paŝmukulo.,A %o l@[ao_esp] ha moqueado un Zancadico.,A %o l@[ao_esp] moqueó un Zancadico.,%o joutui stridicuksen räkäämäksi.,%o s'est fait@[e_fr] engluer par un stridicus.,%o taknyos lett egy lépkedüsztől.,%o è stato colpito da uno Stridicus.,%o は ステュリクスに おびやかされた。,%o 는(은) 스트리디쿠스의 코딱지에 당했습니다.,%o werd door een stridicus gezoomd.,%o ble bæsjet av en stridicus.,%o został@[ao_pl] zaglutowan@[adj_pl] przez stridicusa.,%o foi melecad@[ao_ptb] por um stridicus.,,%o a fost speriat de către un picioare-lungi.,Игрока %o облепила соплями длинноножка. ,,%o blev utskälld av en stridicus.,%o bir stridicus tarafından avlandı. +%o was gooed by a flem mine.,OB_FLEMMINE,,,,%o byl@[ao_cs] zablácen@[ao_cs] sliznou minou.,%o blev smittet af en flem mine.,%o wurde von einer Flem-Mine beschmiert.,,%o estis glukovrita de Muksentinelo.,A %o l@[ao_esp] ha pegoteado una Flem-Mina.,A %o l@[ao_esp] pegoteó una Flem-Mina.,%o joutui limamiinan mönjäämäksi.,%o s'est fait@[e_fr] éclabousser par une flem mine.,%o-t összenyálkázta egy slejmakna.,%o è stato colpito da una bomba a flem.,%o はフレムマインに ヒドいめにあった。,%o 는(은) 플렘 지뢰에 의해 점액 범벅이 됐습니다.,%o werd door een Flemmijn getreiterd.,%o ble gooed av en flem mine.,"%o został@[ao_pl] zabrejowan@[adj_pl] przez flemową minę. +",%o foi engosmad@[ao_ptb] por uma mina flem.,,%o a fost lovit de mâzga unei flem mine.,Игрока %o забрызгала флем-мина.,,%o blev gooad av en loppgruva.,%o bir flem mayını tarafından yapışkan hale getirildi. +%o was slimed by a super cycloptis.,OB_SUPERCYCLOPTIS,,,,%o byl@[ao_cs] osliznut@[ao_cs] superkykloptem.,%o blev slimet af en super cycloptis.,%o wurde von einem Super Cycloptis vollgeschleimt.,,%o estis ŝlimigita de Supera Ciklopmukulo.,A %o l@[ao_esp] ha enlodado un Supercícloptis.,A %o l@[ao_esp] enlodó un Supercícloptis.,%o joutui supercycloptiksen limaamaksi.,%o s'est fait@[e_fr] gélifier par un super cycloptis.,%o-t összenyálkázta egy Szuper Kükloptisz.,%o è stato snellito da una Super Ciyloptis.,%o はスーパーサイクロプティスに とかされた。,%o 는(은) 슈퍼 사이클롭티스의 점액에 당했습니다.,%o werd afgeslankt door een Super Cycloptis.,%o ble slimet av en supersykloptis.,%o został@[ao_pl] oszlamion@[adj_pl] przez super cykloptisa.,%o foi lambuzad@[ao_ptb] por um super cyclóptis.,,%o a fost transformat în mâzgă de către un super cicloptic.,Игрока %o обслюнявил супер-циклоптис.,,%o blev slemmig av en supercykloptis.,%o bir süper sikloptis tarafından sümüklendi. +%o was defeated by a Maximus.,OB_MAXIMUS,,,,%o byl@[ao_cs] poražen@[ao_cs] Maximem.,%o blev besejret af en Maximus.,%o wurde von einem Maximus besiegt.,,%o estis venkita de Mukulestro.,A %o l@[ao_esp] ha derrotado un Máximus.,A %o l@[ao_esp] derrotó un Máximus.,%o joutui Maximuksen päihittämäksi.,%o s'est fait@[e_fr] battre par un Maximus.,%o-t legyőzte egy Maximusz.,%o è stato sconfitto da un Maximus.,%o はマクシムスに 敗北した。,%o 는(은) 맥시무스에게 패배했습니다.,%o werd verslagen door een Maximus.,%o ble beseiret av en Maximus.,%o został@[ao_pl] pokonan@[adj_pl] przez Maximusa.,%o foi derrotad@[ao_ptb] por um Maximus.,,%o a fost înfrânt de către un Maxim.,Игрок %o проиграл Максимусу.,,%o besegrades av en Maximus.,%o bir Maximus tarafından yenildi. +%o was gooed by a larva.,OB_LARVA,,,,%o byl@[ao_cs] zacáknut@[ao_cs] larvou.,%o blev smurt af en larve.,%o wurde von einer Larve beschmiert.,,%o estis glukovrita de larvo.,A %o l@[ao_esp] ha pegoteado una larva.,A %o l@[ao_esp] pegoteó una larva.,%o joutui toukan mönjäämäksi.,%o s'est fait@[e_fr] tâcher par une larve.,%o lárvatrutyit kapott a nyakába.,%o è stato colpito da una larva.,%o はラーバに ヒドいめにあわされた。,%o 는(은) 애벌레에 의해 점액 범벅이 됐습니다.,%o werd door een Larve weggegooid.,%o ble gooed av en larve.,%o został@[ao_pl] zabrejowan@[adj_pl] przez larwę.,%o foi engosmad@[ao_ptb] por uma larva.,,%o a fost lovit de mâzga unei larve.,Игрока %o обслюнявила личинка.,,%o blev göad av en larv.,%o bir larva tarafından öldürüldü. +%o was slimed by a Quadrumpus.,OB_QUADRUMPUS,,,,%o byl@[ao_cs] zahleněn@[ao_cs] Čtyřzadkem.,%o blev slimet af en Quadrumpus.,%o wurde von einem Quadrumpus vollgeschleimt.,,%o estis ŝlimigita de kvarbrakmukulo.,A %o l@[ao_esp] ha enlodado un Quadrumpus.,A %o l@[ao_esp] enlodó un Quadrumpus.,%o joutui Neliperän limaamaksi.,%o s'est fait@[e_fr] morver par un quadrumpus.,%o-t összenyálkázta egy Négylábusz.,%o è stato ridotto da un Quadrumpus.,%o はクワッドロンプスに スライムにされた。,%o 는(은) 쿼드럼푸스의 점액에 당했습니다.,%o werd afgeslankt door een Quadrumpus.,%o ble slimet av en Quadrumpus.,%o został@[ao_pl] oszlamion@[adj_pl] przez Quadrumpusa.,%o foi melecad@[ao_ptb] por um Quadrumpus.,,%o a fost transformat în mâzgă de către o creatură cu patru mâini,Игрока %o обслюнявила многоручка. ,,%o blev slemmad av en Quadrumpus.,%o bir Quadrumpus tarafından zayıflatıldı. +%o was defeated by the Flembomination.,OB_FLEMBOMINATION,,,,%o byl@[ao_cs] poražen@[ao_cs] Slizavností.,%o blev besejret af Flembomination.,%o wurde von der Flembomination besiegt.,,%o estis venkita de la Mukabomeno.,A %o l@[ao_esp] ha derrotado la Flembominación.,A %o l@[ao_esp] derrotó la Flembominación.,%o joutui Limaoikun päihittämäksi.,%o s'est fait@[e_fr] éliminer par la Flembomination.,%o-t legyőzte a Slejmdormány.,%o è stato sconfitto dalla Flembomination.,%o はフレンボミネーションに敗北した。,%o 는(은) 플렘보미네이션으로부터 벗어날 수 없었습니다.,%o werd verslagen door de Flembominatie.,%o ble beseiret av Flembominationen.,%o został@[ao_pl] pokonan@[adj_pl] przez Flembominację.,%o foi derrotad@[ao_ptb] pela Flembominação.,,%o a fost învins de către Flembominație.,Игрока %o победила Флемомерзость.,,%o besegrades av Flembomination.,"%o, Flembomination tarafından yenildi." +%o was defeated by Lord Snotfolus.,OB_SNOTFOLUS,,,,%o byl@[ao_cs] poražen@[ao_cs] Lordem Hlenfujem.,%o blev besejret af Lord Snotfolus.,%o wurde von Lord Snotfolus besiegt.,,%o estis venkita de Lordo Mukplenulo.,A %o l@[ao_esp] ha derrotado Lord Mocofolus.,A %o l@[ao_esp] derrotó Lord Mocofolus.,%o joutui herra Räkänokan päihittämäksi.,%o est tombé@[e_fr] face au Seigneur Morvator.,%o legyőzetett Lord Takony által.,%o è stato sconfitto da Lord Snotfolus.,%o はロード スノフォールスに敗北した。,%o 는(은) 스놋폴러스 마왕과 싸울 준비를 제대로 하지 못했습니다.,%o werd verslagen door Lord Snotfolus.,%o ble beseiret av Lord Snotfolus.,%o został@[ao_pl] pokonan@[adj_pl] przez Lorda Smarkofolusa.,%o foi derrotad@[ao_ptb] pelo Lorde Snotfolus.,,%o a fost pus la pământ de către Lordul Snotfolus.,Игрока %o победил правитель Соплезелёнус.,,%o besegrades av Lord Snotfolus.,"%o, Lord Snotfolus tarafından yenildi." +%o was hit by %k's propulsor.,OB_MPR_SPLASH,,,,%o byl@[ao_cs] zasažen@[ao_cs] propulzorem hráče %k.,%o blev ramt af %ks propulsor.,%o wurde von %ks Propeller getroffen,,%o estis trafita de la propulsilo de %k.,A %o l@[ao_esp] ha alcanzado el propulsor de %k.,A %o l@[ao_esp] alcanzó el propulsor de %k.,%k osui %o parkaan työntimellään.,%o s'est fait@[e_fr] propulser par %k.,%o-t eltalálta %k hajtóműve.,%o è stato colpito dal propulsore di %k.,%o に %k のロケットゾーチがとどいた。,%o 는(은) %k 의 추진력에 휘말렸습니다.,%o werd geraakt door %k's propulsor.,%o ble truffet av %ks propulsor.,%o został@[ao_pl] uderzon@[adj_pl] przez pędnik %k.,%o foi atingid@[ao_ptb] pelo propulsor de %k.,,%o a fost lovit de către propulsorul lui %k.,Игрок %o подстрелен из ускорителя зорча %k.,,%o träffades av %ks propulsor.,"%o, %k tarafından vuruldu." +%o was lazzed by %k.,OB_MPBFG_SPLASH,,,,%o byl@[ao_cs] odlazován@[ao_cs] hráčem %k.,%o blev lazzed af %k.,%o wurde von %o weggezorcht.,,%o estis LAZ-ita de %k.,A %o l@[ao_esp] ha «lazeado» %k.,A %o l@[ao_esp] «lazeó» %k.,%k sazzasi pelaajaan %o.,%o est entré@[e_fr] dans la zone de zorchage large de %k.,%o-t szörcsölődött %k által.,%o è stato lazzato da %k.,%o は %k にとかされた。,%o 는(은) %k 에게 레이져를 쐬였습니다.,%o werd gelazzed door %k.,%o ble lazzed av %k.,%o został@[ao_pl] zLAZowan@[adj_pl] przez %k.,%o foi LAZead@[ao_ptb] por %k.,,%k a folosit dispozitivul LAZ pe %o.,Игрок %o получил заряд из «ЗБР» игрока %k.,,%o blev lurad av %k.,"%o, %k tarafından lazzlandı." "After sending the monstrous Flembrane back to his own dimension, you free the captives. Yet flemoids are everywhere! @@ -84,7 +107,22 @@ Ještě jsme neviděli Sliznatce naposledy. Bohužel máš pravdu. Při návratu domů vidíš, že tě nějakým způsobem sliznatci následovali. -Připrav se na Misi Chex 2: Hrůzu v Chex City!","Nachdem du die monströse Flembrane +Připrav se na Misi Chex 2: Hrůzu v Chex City!","Når du har sendt den uhyrlige Flembrane +tilbage til sin egen dimension, befrier +du fangerne. Men der er flemoider overalt! + +Du og fangerne flygter mod dit rumskib. +Flemoiderne slimer dit skib, men du +undslipper med nød og næppe i kredsløb. +Under hjemrejsen bliver du lykønsket for +den dristige redning, men du udsender en +advarsel... +Vi har ikke set det sidste af Flemoids. + +Desværre har du ret. For da du vender hjem, +finder du ud af, at Flemoiderne på en eller +anden måde har fulgt dig hertil. Forbered +dig på Chex Quest 2: Terror i Chex City!","Nachdem du die monströse Flembrane in ihre eigene Dimension zurückgeschickt hast, befreist du die Gefangenen. Und dennoch sind die Flemoiden @@ -115,7 +153,7 @@ de vuelta a su dimensión, liberas a los rehenes. ¡Pero los flemoides están por todas partes! Tú y los rehenes escapais hacia tu nave. Los flemoides cubren de -lodo tu nave, pero escapas en órbita por +babas tu nave, pero escapas en órbita por los pelos. Durante el regreso eres felicitad@[ao_esp] por tu valiente rescate, pero mandas una advertencia... @@ -168,21 +206,32 @@ Malheureusement, vous avez raison. Quand vous retournez sur votre planète, vous découvrez que les flémoïdes vous ont suivi jusqu'ici. Préparez vous pour -Chex Quest 2: Terreur à Chex City!",,"Dopo aver rispedito il mostruoso Flembrane -nella sua dimensione, si liberano i prigionieri. +Chex Quest 2: Terreur à Chex City!","Miután visszaküldted a szörnyű Slejmbránt +a saját dimenziójába, kiszabadítod a foglyokat. +De a slejmoidok még mindenütt ott vannak! +A foglyokkal együtt az űrhajóhoz szaladtok. +A slejmoidok összenyálkázták az űrhajódat, +azonban épphogy, de sikerül kiszöknötök az űrbe. +A hazaút során gratulálnak a vakmerő mentőakcióhoz, +azonban figyelmeztetsz mindenkit: nem utoljára láttuk a slejmoidokat. + +Sajnos igazad lett. Amint megérkeztél, szembesülsz azzal, +hogy a slejmoidok valahogy hazáig követtek. +Készülj fel a terrorra Chexvárosban, jön a Chex Quest 2!","Dopo aver rispedito il mostruoso Flembrane +nella sua dimensione, puoi liberare i prigionieri. Eppure i flemoidi sono ovunque! Tu e i -prigionieri fare una pausa per la vostra -astronave. I flemoidi melma la vostra nave, -ma si fuggire di poco in orbita. -Durante il ritorno ci si congratula per -l'audace salvataggio, ma si emette un +prigionieri vi avviate per la tua astronave. +I flemoidi coprono di melma la tua astronave, +ma riuscite per poco a scappare in orbita. +Dopo il vostro ritorno vieni congratulato per +l'audace salvataggio, ma comunicate un avvertimento... -Non abbiamo visto l'ultimo dei Flemoidi. +Troveremo ancora i Flemoidi... -Purtroppo hai ragione. Infatti, al vostro -ritorno a casa, vi accorgerete che le -flotte vi hanno in qualche modo seguito qui. -Preparatevi per +Purtroppo hai ragione. Infatti, al tuo +ritorno a casa, ti accorgi che le loro +flotte ti hanno in qualche modo seguito qui. +Preparati per Chex Quest 2: Terrore a Chex City!","巨大なフレムブレンを元の次元に送り ほりょを解放した。 けれども、フレモイドはまだまだいる! フレモイドは 君の宇宙船を スライムまみれにしたため、 @@ -223,7 +272,26 @@ naar huis, zie je dat de Flemoids je op de een of andere manier gevolgd zijn. Bereid je voor op -Chex Quest 2: Terreur in Chex City!","Po wysłaniu Flembrany do jej własnego +Chex Quest 2: Terreur in Chex City!","Etter å ha sendt den monstrøse +Flembrane tilbake til sin egen +dimensjon, frigjør du fangene. +Men flemoider er overalt! +Du og fangene gjør en pause +for romskipet ditt. Flemoidene +slimer skipet ditt, men du +unnslipper så vidt i bane. +Under returen blir du gratulert +med den dristige redningen, +men du utsteder en advarsel ... +Vi har ikke sett det siste av +flemoidene. + +Dessverre har du rett. For når du +kommer hjem, oppdager du at +flemoidene på en eller annen +måte har fulgt etter deg hit. +Forbered dere på Chex Quest 2: +Terror i Chex City!","Po wysłaniu Flembrany do jej własnego wymiaru, uwolniłeś jeńców. Ale flemoidy są wszędzie! Ty razem z jeńcami przebijacie się do statku kosmicznego. Flemoidy oszlamiły @@ -277,7 +345,47 @@ Orașul Chex!","Изгнав чудовищную Флембрану назад К сожалению, ты оказал@[refl_rus] прав@[ao_rus]. Вернувшись домой, ты обнаружил@[ao_rus], что Флемоиды добрались и сюда. -Тебя ждёт Chex Quest 2: Террор в Городе Chex!", +Тебя ждёт Chex Quest 2: Террор в Городе Chex!",,"Efter att ha skickat tillbaka den +monstruösa Flembrane till sin +egen dimension befriar du +fångarna. Ändå finns flemoider +överallt! +Du och fångarna gör en +utbrytning till ditt rymdskepp. +Flemoiderna slevar ditt skepp, +men du lyckas med nöd och +näppe fly i omloppsbana. +Under återresan gratuleras du +till den djärva räddningen, men +du utfärdar en varning... +Vi har inte sett det sista av +flemoiderna. + +Tyvärr har du rätt. För när du +återvänder hem upptäcker du +att Flemoiderna på något sätt +har följt dig hit. Förbered dig på +Chex Quest 2: Terror i Chex City!","Canavar Flembrane'i kendi boyutuna +geri gönderdikten sonra tutsakları +serbest bırakıyorsunuz. Yine de +flemoidler her yerde! +Sen ve tutsaklar uzay geminize +doğru kaçıyorsunuz. Flemoidler +geminizi balçıkla sıvıyor, ama +yörüngeye girmekten kıl payı +kurtuluyorsunuz. +Dönüş sırasında cesur kurtarışınız +için tebrik ediliyorsunuz ama bir +uyarıda bulunuyorsunuz... +Flemoidlerin sonuncusunu +görmedik. + +Ne yazık ki haklısınız. Çünkü eve +döndüğünüzde, Flemoidlerin bir +şekilde sizi buraya kadar takip +ettiğini görüyorsunuz. +Chex Quest 2: Chex Şehrinde Terör +için hazırlanın!" "You zorch the remaining flemoids who had gathered in the sewers. Chex City has been saved. It seems that the Flemoid threat @@ -309,7 +417,25 @@ vesmírnou trhlinu a nyní se na planetu cereálií řítí obrovská koule slizu! Připrav se na -Misi Chex 3: Invazi!","Du zorchst die verbleibenden +Misi Chex 3: Invazi!","Du zorch de resterende flemoider, der +havde samlet sig i kloakkerne. Chex City +er blevet reddet. Det ser ud til, +at Flemoid-truslen endelig er slut. + +Ti år går i fred og velstand. +Men Flemoiderne blev ikke besejret, +og deres ønske om at kontrollere den +næringsrige cerealdimension er ikke +blevet mindre. + +De har samlet alle deres kræfter, +åbnet en gigantisk interdimensionel +revne i rummet, og nu er en stor +slimkugle på vej direkte mod +cerealplaneten! + +Gør dig klar til +Chex Quest 3: Invasion!","Du zorchst die verbleibenden Flemoiden, die sich noch in der Kanalisation aufhielten, weg. Chex City ist gerettet. Es sieht aus, als ob die @@ -356,8 +482,8 @@ cereales ricos en nutrientes no ha disminuido. ¡Han reunido todas sus fuerzas, abierto un gigantesco túnel interdimensional en el espacio y ahora -una gran bola de lodo se dirige derecha -al planeta de los cereales! +una gran bola de baba se dirige hacia +el planeta de los cereales! Prepárate para Chex Quest 3: ¡Invasión!",,"Zorchaat jäljelle jääneet viemäreihin @@ -393,9 +519,19 @@ géante se dirige vers la planète des céréales! Préparez vous pour Chex Quest 3: -Invasion!",,"Hai zorch il restante flemoidi che si erano +Invasion!","A csatornában összegyűlt maradék slejmoidokat is szörcsölöd. +Chexváros megmenekült. Úgy tűnik, a slejmoidveszély végre megszűnt. + + +Tíz év telt el békében és jólétben. Azonban a slejmoidok nem lettek legyőzve, +és a vágyuk a tápanyagokban gazdag gabonapehely-dimenzió irányítására +mit sem csökkent. +Összegyűlt erőik gigantikus interdimenzionális rést ütöttek az űrben, +és most egy óriási trutyilabda száguld egyenesen a gabonapelyhek bolygója felé! + +Készülj fel az invázióra a Chex Quest 3-ban!","Hai neutralizzato restante flemoidi che si erano riuniti nelle fogne. Chex City è stata -salvata. Sembra che la minaccia Flemoid è +salvata. Sembra che la minaccia Flemoid sia finalmente finita. Dieci anni passano in pace e prosperità. @@ -408,8 +544,7 @@ spaccatura interdimensionale nello spazio e ora una grande palla di melma è diretta direttamente verso il pianeta dei cereali! Preparati per -Chex Quest 3: Invasione! -","君は 下水道に集まっていたフレモイドを +Chex Quest 3: Invasione!","君は 下水道に集まっていたフレモイドを ぶっとばして、チェックス シティーを守った。 フレモイドの きょういはようやく なくなったようだ。 @@ -448,7 +583,26 @@ interdimensionale kloof in de ruimte geopend en nu gaat er een grote bal slijm recht op weg naar de planeet van het graan! -Maak je klaar voor Chex Quest 3: Invasion!","Zorchujesz pozostałe flemoidy, które zebrały się +Maak je klaar voor Chex Quest 3: Invasion!","Du svir av de gjenværende +flemoidene som hadde samlet +seg i kloakken. Chex City er +reddet. Det ser ut til at Flemoid- +trusselen endelig er over. + + +Ti år går i fred og velstand. +Men flemoidene ble ikke beseiret, +og deres ønske om å kontrollere +den næringsrike korn- +dimensjonen har ikke blitt mindre. +De har samlet alle kreftene sine, +åpnet en gigantisk inter- +dimensjonal rift i verdensrommet, +og nå er en stor slimkule på +vei rett mot kornplaneten! + +Gjør deg klar for Chex Quest 3: +Invasjon!","Zorchujesz pozostałe flemoidy, które zebrały się w ściekach. Miasto Chex zostało uratowane. Wygląda na to, że zagrożenie flemoidami zostało zakończone. @@ -491,13 +645,13 @@ interdimensională gigantă, iar acum o bilă enormă de mâzgă e îndreptată drept către planeta cerealelor! -Pregătește-te pentru Chex Quest 3: Invazia!","С помощью Зорчера, ты освободил@[ao_rus] +Pregătește-te pentru Chex Quest 3: Invazia!","С помощью зорчера, ты освободил@[ao_rus] канализацию от оставшихся флемоидов. Город Chex спасён. Казалось, что с -угрозой Флемоидов наконец-то покончено. +угрозой флемоидов наконец-то покончено. Десять лет прошли в мире и процветании. -Но Флемоиды не были побеждены, им всё +Но флемоиды не были побеждены, им всё ещё хотелось править измерением полезных и питательных хлопьев. Они собрали все силы и открыли @@ -505,7 +659,45 @@ Pregătește-te pentru Chex Quest 3: Invazia!","С помощью Зорчера разлом в космосе. Над планетой хлопьев навис огромный шар из слизи! -Приготовься к Chex Quest 3: Вторжение!", +Приготовься к Chex Quest 3: Вторжение!",,"Du zorch de återstående +flemoiderna som hade samlats +i kloakerna. Chex City har +räddats. Det verkar som om +Flemoid-hotet äntligen har +upphört. + +Tio år går i fred och välstånd. +Men Flemoiderna besegrades +inte och deras önskan att +kontrollera den näringsrika +spannmålsdimensionen har inte +minskat. +De har samlat alla sina styrkor, +öppnat en gigantisk inter- +dimensionell spricka i rymden +och nu är en stor boll av slem på +väg rakt mot spannmålens planet! + +Gör dig redo för +Chex Quest 3: Invasion!","Kanalizasyonda toplanmış olan kalan +flemoidleri zorluyorsun. Chex Şehri +kurtarıldı. Görünüşe göre Flemoid +tehdidi nihayet sona erdi. + + +On yıl barış ve refah içinde geçti. +Ancak Flemoidler yenilmedi ve +besin açısından zengin tahıl +boyutunu kontrol etme +arzuları azalmadı. +Tüm güçlerini topladılar, uzayda +devasa bir boyutlar arası yarık +açtılar ve şimdi büyük bir balçık +topu doğrudan tahılların +gezegenine doğru ilerliyor! + +Chex Quest 3: +İstila için hazır olun!" "With one final blast, you zorch Lord Snotfolus back to his own dimension! Against all the odds you have single- @@ -531,7 +723,17 @@ vrátit do dimenze cereálií. Ale jestli se o to pokusí, víš, -že na ně budeš připraven@[adj_cs]!","Mit einem letzten Schuss zorchst du +že na ně budeš připraven@[adj_cs]!","Med et sidste slag zorcherer du +Lord Snotfolus tilbage til sin egen +dimension! Mod alle odds har du +egenhændigt forpurret invasionen! + +Du håber virkelig, at Flemoids endelig +har lært lektien og aldrig mere vil +vende tilbage til cerealdimensionen. + +Men hvis de gør det, ved du, at du +vil være klar til at tage imod dem!","Mit einem letzten Schuss zorchst du Lord Snotfolus zurück in seine eigene Dimension! Gegen alle Widerstände hast du eigenhändiig die Invasion @@ -591,18 +793,26 @@ revenir envahir la dimension des céréales. Mais vous savez que vous serez -prêt pour eux!",,"Con un ultimo colpo, hai zorch Lord Snotfolus -torna alla sua dimensione! contro tutte -le probabilità che hai sventato -l'invasione con una sola mano! +prêt pour eux!","Egy utolsó dördüléssel visszaszörcsölöd Lord Takonyt +a saját dimenziójába! Minden várakozás ellenére egymagad +megakadályoztad az inváziót! -Speri davvero che i flemoidi hanno -finalmente imparato la lezione e non -torneranno mai più alla dimensione dei cereali. +Reménykedsz abban, hogy a slejmoidok végre megtanulták +a leckét és soha többé nem térnek vissza a gabonapelyhek +dimenziójába. -Ma se lo sai che sarai pronto per loro! -","さいごのいちげきで、ロード スノフォールスを元の次元に +De ha mégis visszatérnek, te készen állsz majd! +","Con un ultimo colpo, hai neutralizzato Lord +Snotfolus, che ritorna alla sua dimensione! +Contro tutte le probabilità hai sventato +l'invasione tutto da solo! + +Speri davvero che i flemoidi abbiano +finalmente imparato la lezione e non +torneranno mai più nella dimensione dei cereali. + +Ma se lo faranno, sai che sarai pronto per loro!","さいごのいちげきで、ロード スノフォールスを元の次元に もどした。君一人で全てのオーズのしゅうげきを 阻止した! 君は フレモイド達のことを みんなに教え、再び @@ -627,7 +837,20 @@ hun lesje geleerd hebben en nooit meer terug zullen keren naar de graandimensie. Maar als ze dat doen, weet je dat je -er klaar voor bent!","Z ostatnim strzałem zorchujesz Lorda +er klaar voor bent!","Med en siste eksplosjon svir +du Lord Snotfolus tilbake til +sin egen dimensjon! +Mot alle odds har du egen- +hendig avverget invasjonen! + +Du håper virkelig at flemoidene +endelig har lært leksen sin og aldr +mer vil vende tilbake til +korndimensjonen. + + +Men hvis de gjør det, vet du +at du vil være klar for dem!","Z ostatnim strzałem zorchujesz Lorda Smarkofolusa z powrotem do jego wymaru! Po wszystkim udało ci się w pojedynkę powstrzymać inwazję! @@ -659,19 +882,45 @@ Speri cu adevărat că Flemoizii și-au învățat lecția cerealelor. -Dar dacă o vor face, vei fi pregătit pentru ei!","Последним метким выстрелом из Зорчера, -лорд Снотфолус был изгнан в назад своё измерение. +Dar dacă o vor face, vei fi pregătit pentru ei!","Последним метким выстрелом из зорчера, +правитель Снотфолус был изгнан в назад своё измерение. Всем бедам вопреки, ты собственноручно покончил@[ao_rus] со вторжением! Остаётся лишь надеяться, что теперь флемоиды усвоят урок, и больше никогда не проникнут -в измерение Хлопьев. +в измерение хлопьев. Но если всё-таки проникнут, -ты уже будешь к этому готов@[ao_rus]!", -Rescue on Bazoik,M_EPI1,,,,Záchrana na Bazoiku,Rettung auf Bazoik,,Savo sur Bazojko,Rescate en Bazoik,,Pelastustehtävä Bazoikissa,Sauvetage sur Bazoik,Mentőakció a Bazoik-on,Salvataggio su Bazoik,バゾイクからのきゅうしゅつ,바조이크의 대동굴,Redding op Bazoik,Ratunek na Bazoik,Resgate em Bazoik,,Misiune de Salvare pe Bazoik,Спасение на Базоике, -Terror in Chex City,M_EPI2,,,,Hrůza v Chex City,,,Teruro en Chex-urbo,Terror en Chex City,,Kauhua Chex-kaupungissa,Terreur à Chex City,Terror Chexvárosban,Terrore a Chex City,チェックスシティーのきょうふ,첵스 시티의 공포,Terreur in Chex City,Terror w Mieście Chex,Terror em Chexópolis,,Teroare în Orașul Chex,Террор в Городе Chex, -Invasion!,M_EPI3,,,,Invaze!,,,Invado!,¡Invasión!,,Invaasio!,,Invázió!,Invasione!,しんにゅう!,대침공!,,Inwazja,A Invasão!,,Invazie!,Вторжение!, \ No newline at end of file +ты уже будешь к этому готов@[ao_rus]!",,"Med en sista smäll zorchar +du Lord Snotfolus tillbaka till +sin egen dimension! +Mot alla odds har du på egen +hand förhindrat invasionen! + +Du hoppas verkligen att +Flemoiderna äntligen har lärt sig +sin läxa och aldrig mer kommer +att återvända till +spannmålsdimensionen. + +Men om de gör det vet du att dukommer att vara redo för dem!","Son bir patlamayla Lord +Snotfolus'u kendi boyutuna +geri döndürüyorsunuz! +Tüm olasılıklara rağmen +istilayı tek başına engelledin! + +Flemoidlerin sonunda derslerini +aldıklarını ve bir daha asla tahıl +boyutuna geri dönmeyeceklerini +umuyorsun. + + + +Ama dönerlerse, onlar için +hazır olacağınızı biliyorsunuz!" +Rescue on Bazoik,M_EPI1,,,,Záchrana na Bazoiku,Redning på Bazoik,Rettung auf Bazoik,,Savo sur Bazojko,Rescate en Bazoik,,Pelastustehtävä Bazoikissa,Sauvetage sur Bazoik,Mentőakció a Bazoik-on,Salvataggio su Bazoik,バゾイクからのきゅうしゅつ,바조이크의 대동굴,Redding op Bazoik,Redning på Bazoik,Ratunek na Bazoik,Resgate em Bazoik,,Misiune de Salvare pe Bazoik,Спасение на Базоике,,Räddning på Bazoik,Bazoik'te Kurtarma +Terror in Chex City,M_EPI2,,,,Hrůza v Chex City,Terror i Chex City,,,Teruro en Chex-Urbo,Terror en Chex City,,Kauhua Chex-kaupungissa,Terreur à Chex City,Terror Chexvárosban,Terrore a Chex City,チェックスシティーのきょうふ,첵스 시티의 공포,Terreur in Chex City,Terror i Chex City,Terror w Mieście Chex,Terror em Chexópolis,,Teroare în Orașul Chex,Террор в городе Chex,,Terror i Chex City,Chex Şehrinde Terör +Invasion!,M_EPI3,,,,Invaze!,,,,Invado!,¡Invasión!,,Invaasio!,,Invázió!,Invasione!,しんにゅう!,대침공!,,Invasjon!,Inwazja,A Invasão!,,Invazie!,Вторжение!,,,İstila! \ No newline at end of file diff --git a/wadsrc_extra/static/filter/doom.id.doom1.unity/sndinfo.txt b/wadsrc_extra/static/filter/doom.id.doom1.unity/sndinfo.txt new file mode 100644 index 00000000000..1f2fb5e7ad6 --- /dev/null +++ b/wadsrc_extra/static/filter/doom.id.doom1.unity/sndinfo.txt @@ -0,0 +1,9 @@ +$musicalias d_inter d_e2m3 +$musicalias d_e2m5 d_e1m7 +$musicalias d_e3m5 d_e1m7 +$musicalias d_e3m1 d_e2m9 +$musicalias d_e3m4 d_e1m8 +$musicalias d_e3m5 d_e1m7 +$musicalias d_e3m6 d_e1m6 +$musicalias d_e3m7 d_e2m7 +$musicalias d_e3m9 d_e1m9 \ No newline at end of file diff --git a/wadsrc_extra/static/filter/doom.id.doom2.unity/sndinfo.txt b/wadsrc_extra/static/filter/doom.id.doom2.unity/sndinfo.txt new file mode 100644 index 00000000000..4f6596aaa78 --- /dev/null +++ b/wadsrc_extra/static/filter/doom.id.doom2.unity/sndinfo.txt @@ -0,0 +1,14 @@ +$musicalias d_count2 d_countd +$musicalias d_ddtbl2 d_ddtblu +$musicalias d_ddtbl3 d_ddtblu +$musicalias d_dead2 d_dead +$musicalias d_doom2 d_doom +$musicalias d_messg2 d_messag +$musicalias d_romer2 d_romero +$musicalias d_runni2 d_runnin +$musicalias d_shawn2 d_shawn +$musicalias d_stlks2 d_stalks +$musicalias d_theda2 d_the_da +$musicalias d_shawn3 d_shawn +$musicalias d_stlks3 d_stalks +$musicalias d_theda3 d_the_da \ No newline at end of file diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0100.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0100.lmp new file mode 100644 index 00000000000..ec5879e8597 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/010A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/010A.lmp new file mode 100644 index 00000000000..1e951e746c6 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0112.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0112.lmp new file mode 100644 index 00000000000..593e1a6d984 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0116.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0116.lmp new file mode 100644 index 00000000000..a1d8302f127 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/011E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/011E.lmp new file mode 100644 index 00000000000..83e4b77ca55 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0120.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0120.lmp new file mode 100644 index 00000000000..b1e8d26071e Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0122.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0122.lmp new file mode 100644 index 00000000000..7305bbc688a Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0126.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0126.lmp new file mode 100644 index 00000000000..ca63458dd07 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/012A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/012A.lmp new file mode 100644 index 00000000000..760fb438a0f Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/012E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/012E.lmp new file mode 100644 index 00000000000..26453246824 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0130.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0130.lmp new file mode 100644 index 00000000000..c8f8d79f42e Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0136.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0136.lmp new file mode 100644 index 00000000000..9fb95b3fb50 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0139.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0139.lmp new file mode 100644 index 00000000000..0d66119bdfc Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/013B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/013B.lmp new file mode 100644 index 00000000000..8f6137574f2 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/013D.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/013D.lmp new file mode 100644 index 00000000000..892a6b03429 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0145.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0145.lmp new file mode 100644 index 00000000000..c2a3268a805 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/014A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/014A.lmp new file mode 100644 index 00000000000..efaa51f934b Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/014C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/014C.lmp new file mode 100644 index 00000000000..90b4fb11e20 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0154.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0154.lmp new file mode 100644 index 00000000000..80e105523b4 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0166.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0166.lmp new file mode 100644 index 00000000000..998776eb004 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/016A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/016A.lmp new file mode 100644 index 00000000000..195a8da668b Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0172.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0172.lmp new file mode 100644 index 00000000000..0f3898b3eff Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0174.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0174.lmp new file mode 100644 index 00000000000..a25e7a36995 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0176.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0176.lmp new file mode 100644 index 00000000000..4443deed608 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/018F.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/018F.lmp new file mode 100644 index 00000000000..9bde0a18e14 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/01FC.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/01FC.lmp new file mode 100644 index 00000000000..444102cce5d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/01FE.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/01FE.lmp new file mode 100644 index 00000000000..d6621dbb066 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0402.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0402.lmp index a00a09d0998..e159c4c17fa 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0402.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/0402.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/040B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/040B.lmp index 474c6333291..875b2d72d6f 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/040B.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/040B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E80.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E80.lmp new file mode 100644 index 00000000000..9a4901d0b73 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E82.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E82.lmp new file mode 100644 index 00000000000..c4fed22fbb6 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E84.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E84.lmp new file mode 100644 index 00000000000..db3bc848900 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1EF2.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1EF2.lmp new file mode 100644 index 00000000000..f1c3ff3dc03 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0080.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0080.lmp new file mode 100644 index 00000000000..605be1f699d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0080.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0100.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0100.lmp new file mode 100644 index 00000000000..42e8c054e27 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0100.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0101.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0101.lmp new file mode 100644 index 00000000000..38ad7983cbb Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0101.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/010A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/010A.lmp new file mode 100644 index 00000000000..22fcad4a48c Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/010A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/010B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/010B.lmp new file mode 100644 index 00000000000..b8f04f3dfc3 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/010B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0113.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0113.lmp new file mode 100644 index 00000000000..67e4b9aeb6f Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0113.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0116.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0116.lmp new file mode 100644 index 00000000000..641f308808d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0116.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0117.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0117.lmp new file mode 100644 index 00000000000..23661e81547 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0117.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/011E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/011E.lmp new file mode 100644 index 00000000000..cb48c3cdaa3 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/011E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/011F.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/011F.lmp new file mode 100644 index 00000000000..d3b2bb6101d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/011F.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0120.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0120.lmp new file mode 100644 index 00000000000..6fe630d710c Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0120.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0121.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0121.lmp new file mode 100644 index 00000000000..1bb18fc94e8 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0121.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0122.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0122.lmp new file mode 100644 index 00000000000..e8902ddf21f Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0122.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0123.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0123.lmp new file mode 100644 index 00000000000..3465300b284 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0123.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0126.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0126.lmp new file mode 100644 index 00000000000..c3639324fd5 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0126.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0127.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0127.lmp new file mode 100644 index 00000000000..2058ce51d26 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0127.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012A.lmp new file mode 100644 index 00000000000..3dfa6cf059d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012B.lmp new file mode 100644 index 00000000000..4105077ecac Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012E.lmp new file mode 100644 index 00000000000..191fa08355a Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012F.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012F.lmp new file mode 100644 index 00000000000..c4dbf13d550 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/012F.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0130.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0130.lmp new file mode 100644 index 00000000000..a5f604cd7f6 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0130.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0131.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0131.lmp new file mode 100644 index 00000000000..4a6c9ed1937 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0131.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0136.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0136.lmp new file mode 100644 index 00000000000..0379fdc8586 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0136.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0137.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0137.lmp new file mode 100644 index 00000000000..12c81c57e1d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0137.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0139.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0139.lmp new file mode 100644 index 00000000000..ebf2c19ac36 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0139.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013A.lmp new file mode 100644 index 00000000000..9442bda428d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013B.lmp new file mode 100644 index 00000000000..24bbdeed8b7 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013C.lmp new file mode 100644 index 00000000000..1447c271a84 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013D.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013D.lmp new file mode 100644 index 00000000000..082403de5f1 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013D.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013E.lmp new file mode 100644 index 00000000000..37410a40f49 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/013E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0145.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0145.lmp new file mode 100644 index 00000000000..1d295143579 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0145.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0146.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0146.lmp new file mode 100644 index 00000000000..1e94f22822d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0146.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014A.lmp new file mode 100644 index 00000000000..cdabc8c5006 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014B.lmp new file mode 100644 index 00000000000..a64778632db Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014C.lmp new file mode 100644 index 00000000000..142d81443aa Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014D.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014D.lmp new file mode 100644 index 00000000000..54ac913dc93 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/014D.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0154.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0154.lmp new file mode 100644 index 00000000000..b53f295c89c Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0154.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0155.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0155.lmp new file mode 100644 index 00000000000..82565bd58d2 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0155.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0166.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0166.lmp new file mode 100644 index 00000000000..2d0110ccf70 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0166.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0167.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0167.lmp new file mode 100644 index 00000000000..65885c56dfd Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0167.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/016A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/016A.lmp new file mode 100644 index 00000000000..683195052f6 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/016A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/016B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/016B.lmp new file mode 100644 index 00000000000..dcc5a6d8547 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/016B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0172.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0172.lmp new file mode 100644 index 00000000000..1bde186acd3 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0172.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0173.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0173.lmp new file mode 100644 index 00000000000..0fff3ca8f17 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0173.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0174.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0174.lmp new file mode 100644 index 00000000000..29e1ad5189d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0174.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0175.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0175.lmp new file mode 100644 index 00000000000..3fddfe9e9ce Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0175.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0176.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0176.lmp new file mode 100644 index 00000000000..421d58402ed Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0176.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0177.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0177.lmp new file mode 100644 index 00000000000..e0dbd102cb9 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0177.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/018F.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/018F.lmp new file mode 100644 index 00000000000..394afe239d9 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/018F.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FC.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FC.lmp new file mode 100644 index 00000000000..bd4263ee144 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FE.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FE.lmp new file mode 100644 index 00000000000..624fb0a883c Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FF.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FF.lmp new file mode 100644 index 00000000000..ce81871c544 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01FF.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01fD.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01fD.lmp new file mode 100644 index 00000000000..2ad6e40344e Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/01fD.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0259.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0259.lmp new file mode 100644 index 00000000000..33b4ccefcf8 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0259.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0402.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0402.lmp index 4f72414a26a..23ca1421525 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0402.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0402.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/040B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/040B.lmp index 33b4ea06fde..686572ecb0a 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/040B.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/040B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0452.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0452.lmp index d029013b641..4147794ac10 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0452.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/0452.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/045B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/045B.lmp index 4687f235651..cd1b9de3747 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/045B.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/045B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E80.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E80.lmp new file mode 100644 index 00000000000..ebd8ba7c80c Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E81.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E81.lmp new file mode 100644 index 00000000000..ad4c3e4c6fb Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E81.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E82.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E82.lmp new file mode 100644 index 00000000000..b98f58b99b2 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E83.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E83.lmp new file mode 100644 index 00000000000..fc57087f144 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E83.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E84.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E84.lmp new file mode 100644 index 00000000000..05e93ee240f Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E85.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E85.lmp new file mode 100644 index 00000000000..c6c468e4aaa Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1E85.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1EF2.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1EF2.lmp new file mode 100644 index 00000000000..2b040d4bc41 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1EF3.lmp b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1EF3.lmp new file mode 100644 index 00000000000..94b6450ec7a Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/bigupper/1EF3.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C0.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C0.lmp index 27fe843b173..a4e06caa8f2 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C0.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C0.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C1.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C1.lmp index fb2bb63c08d..a3d16589601 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C1.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C1.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C2.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C2.lmp index 82e78ce8605..c1157da6015 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C2.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C2.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C3.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C3.lmp index 8a6752b1364..2d47965d754 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C3.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C3.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C4.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C4.lmp index 63df556b7aa..db8142bcb09 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C4.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C4.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C5.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C5.lmp index fb2bb63c08d..3dc94ef4ee3 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C5.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C5.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C8.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C8.lmp index 1a5025b11cd..91947b7f924 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C8.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C8.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C9.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C9.lmp index 8c7ac365271..32af8885730 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C9.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00C9.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CA.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CA.lmp index ef965c4a398..7fad909b0fd 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CA.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CA.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CB.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CB.lmp index c21bac1b565..3e63a67c175 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CB.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CB.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CC.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CC.lmp index 18fe3d2b97d..11ff1511b48 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CC.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CC.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CD.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CD.lmp index 9b5645ab8bc..0171d4e6bea 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CD.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CD.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CE.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CE.lmp index 574bd7f8589..30e2b0d3be7 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CE.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CE.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CF.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CF.lmp index df13e960a28..bf0359c3165 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CF.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00CF.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D1.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D1.lmp index dffc67522c0..7eb9f80f279 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D1.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D1.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D2.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D2.lmp index 90796119cb2..4d0011457d0 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D2.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D2.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D3.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D3.lmp index 55ff8b5a7f2..f804135ac90 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D3.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D3.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D4.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D4.lmp index c077040027f..6ee0aafd144 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D4.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D4.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D5.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D5.lmp index b2143f1b409..794004991fa 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D5.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D5.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D6.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D6.lmp index 738ad156ec8..31d4dc1cb4a 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D6.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D6.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D9.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D9.lmp index 7b4089f5447..862d01742f1 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D9.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00D9.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DA.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DA.lmp index 63bbf679a4d..11e6942039f 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DA.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DA.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DB.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DB.lmp index fe75e412b16..2d9aaddd64d 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DB.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DB.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DC.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DC.lmp index 60534ab2a98..21c1f43b4ba 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DC.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DC.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DD.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DD.lmp index 9dea9034891..28ede22bc4b 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DD.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/00DD.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0100.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0100.lmp index e7c8e33e747..c8833c41215 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0100.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0102.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0102.lmp index 999e2b95a7d..cb2ed1c0f59 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0102.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0102.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0106.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0106.lmp index b1451f6ffa7..d7d715cd4a2 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0106.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0106.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0108.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0108.lmp index 86bf6f332f5..2bea57c4b7f 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0108.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0108.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010A.lmp new file mode 100644 index 00000000000..49e9055786f Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010C.lmp index 3f5e45b52c4..4f7dbf92726 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010C.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010E.lmp index 8ee4f7c5ea3..f92d5a0ad66 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010E.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/010E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0112.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0112.lmp index ccd193567c3..4e7c1fe388f 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0112.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0114.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0114.lmp index 38e34f098a3..8f190e6d22c 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0114.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0114.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0116.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0116.lmp new file mode 100644 index 00000000000..635e3cf72dc Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011A.lmp index 10354234275..099d7ff453b 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011A.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011C.lmp index e41e832a2ae..f134fdb5ab4 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011C.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011E.lmp new file mode 100644 index 00000000000..aa4af38b89e Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0120.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0120.lmp new file mode 100644 index 00000000000..16cd7f6e752 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0122.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0122.lmp new file mode 100644 index 00000000000..057c1ef0f7c Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0124.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0124.lmp index 6d287876343..78039dd5c8b 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0124.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0124.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0126.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0126.lmp new file mode 100644 index 00000000000..043de10c4c7 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/012A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/012A.lmp new file mode 100644 index 00000000000..0eaa06e06d4 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/012E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/012E.lmp new file mode 100644 index 00000000000..c4a7effd7e5 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0130.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0130.lmp new file mode 100644 index 00000000000..d7618c330ea Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0134.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0134.lmp index d00f8ec8bb0..c12a8752412 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0134.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0134.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0136.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0136.lmp new file mode 100644 index 00000000000..ae3589e31da Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0139.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0139.lmp new file mode 100644 index 00000000000..4ba4962e48d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/013B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/013B.lmp new file mode 100644 index 00000000000..eb90e106962 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/013D.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/013D.lmp new file mode 100644 index 00000000000..17fccdc69b5 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0143.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0143.lmp index 02d47abfe0f..933540fa5de 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0143.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0143.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0147.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0147.lmp index 0a14fba587a..5d9d4bbb4e8 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0147.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0147.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/014A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/014A.lmp new file mode 100644 index 00000000000..9426b56c17f Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/014C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/014C.lmp new file mode 100644 index 00000000000..34d6c8e8269 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0150.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0150.lmp index bdcf8ee3bc7..0b48dea3002 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0150.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0150.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0154.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0154.lmp index 697477bc1a4..03c641101bc 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0154.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0158.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0158.lmp index 10e9de4141c..b42175e63f3 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0158.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0158.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/015A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/015A.lmp index d2776657704..ee9fe1768ca 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/015A.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/015A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/015C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/015C.lmp index a41a7af1b6f..af52cd062ce 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/015C.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/015C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0160.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0160.lmp index 30bd7979c17..8d720b6129b 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0160.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0160.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0164.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0164.lmp index f1b03f98e42..6cb69d60ba4 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0164.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0164.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0166.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0166.lmp new file mode 100644 index 00000000000..618c9106def Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016A.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016A.lmp new file mode 100644 index 00000000000..e1a0925151d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016C.lmp index fb43845b1b9..a986db5ba18 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016C.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016E.lmp index 7557f1a8cf3..0e3a5cc70c1 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016E.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/016E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0170.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0170.lmp index f0dbe3dce00..04e3a0131a3 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0170.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0170.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0172.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0172.lmp new file mode 100644 index 00000000000..54b92066e91 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0174.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0174.lmp new file mode 100644 index 00000000000..96dfa9c0ca7 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0176.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0176.lmp new file mode 100644 index 00000000000..10e05edb80b Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0178.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0178.lmp index cfaf871570d..1f2b949f378 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0178.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0178.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0179.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0179.lmp index 7482f061890..f1a92ba6925 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0179.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0179.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/017B.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/017B.lmp index 49b3050cd72..cc9d2f978e4 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/017B.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/017B.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/017D.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/017D.lmp index 13f4fba4346..c0037b473e5 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/017D.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/017D.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/018F.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/018F.lmp new file mode 100644 index 00000000000..a2138aa5bc6 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/01FC.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/01FC.lmp new file mode 100644 index 00000000000..cb119be2681 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/01FE.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/01FE.lmp new file mode 100644 index 00000000000..37b0be19483 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/03AA.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/03AA.lmp deleted file mode 100644 index df13e960a28..00000000000 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/03AA.lmp and /dev/null differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/03AB.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/03AB.lmp deleted file mode 100644 index cfaf871570d..00000000000 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/03AB.lmp and /dev/null differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0401.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0401.lmp deleted file mode 100644 index c21bac1b565..00000000000 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0401.lmp and /dev/null differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0403.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0403.lmp new file mode 100644 index 00000000000..d3c6d81abd1 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0404.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0404.lmp new file mode 100644 index 00000000000..fd61ad5539a Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040C.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040C.lmp new file mode 100644 index 00000000000..46423d78f08 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040D.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040D.lmp index 30f1c79d8f4..2f5ee22b76a 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040D.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040E.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040E.lmp new file mode 100644 index 00000000000..dcc70712a4b Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0419.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0419.lmp index 950f91656cd..a861df892f1 100644 Binary files a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0419.lmp and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0419.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0490.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0490.lmp new file mode 100644 index 00000000000..d7c9420ae82 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E80.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E80.lmp new file mode 100644 index 00000000000..7b014bdb185 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E82.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E82.lmp new file mode 100644 index 00000000000..7acbe05fb6d Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E84.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E84.lmp new file mode 100644 index 00000000000..04a05df7541 Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1EF2.lmp b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1EF2.lmp new file mode 100644 index 00000000000..a0336a5f82f Binary files /dev/null and b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/font.inf b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/font.inf new file mode 100644 index 00000000000..b3c8f497809 --- /dev/null +++ b/wadsrc_extra/static/filter/doom.id/fonts/defsmallfont/font.inf @@ -0,0 +1,2 @@ +FontHeight 9 + diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0100.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0100.lmp new file mode 100644 index 00000000000..4a30406e09b Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0106.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0106.lmp new file mode 100644 index 00000000000..b02e7678e32 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0106.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/010A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/010A.lmp new file mode 100644 index 00000000000..8c96b231414 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0112.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0112.lmp new file mode 100644 index 00000000000..d2489bbee02 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0116.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0116.lmp new file mode 100644 index 00000000000..3a08c488dba Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/011E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/011E.lmp new file mode 100644 index 00000000000..f9fac5cf6bf Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0120.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0120.lmp new file mode 100644 index 00000000000..e1330142e39 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0122.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0122.lmp new file mode 100644 index 00000000000..102ba34bc1a Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0126.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0126.lmp new file mode 100644 index 00000000000..abbd91bf8f3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/012A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/012A.lmp new file mode 100644 index 00000000000..712862f57db Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/012E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/012E.lmp new file mode 100644 index 00000000000..3523c925433 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0130.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0130.lmp new file mode 100644 index 00000000000..54aab284041 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0136.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0136.lmp new file mode 100644 index 00000000000..1a2c9b2a884 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0139.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0139.lmp new file mode 100644 index 00000000000..bbd0a226202 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/013B.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/013B.lmp new file mode 100644 index 00000000000..cc85598acd5 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/013D.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/013D.lmp new file mode 100644 index 00000000000..d00e5e1c953 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0145.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0145.lmp new file mode 100644 index 00000000000..942b8efd673 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/014A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/014A.lmp new file mode 100644 index 00000000000..9ff38e39ff9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/014C.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/014C.lmp new file mode 100644 index 00000000000..bbc1521b0cd Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0154.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0154.lmp new file mode 100644 index 00000000000..c8e8a5422df Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0166.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0166.lmp new file mode 100644 index 00000000000..2f5489d610d Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/016A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/016A.lmp new file mode 100644 index 00000000000..6b82c559ddc Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0172.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0172.lmp new file mode 100644 index 00000000000..516c0b7fd24 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0174.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0174.lmp new file mode 100644 index 00000000000..0543416155f Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0176.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0176.lmp new file mode 100644 index 00000000000..87f664bfd33 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/018F.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/018F.lmp new file mode 100644 index 00000000000..d6c950eae38 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/01FC.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/01FC.lmp new file mode 100644 index 00000000000..428dfc3f530 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/01FE.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/01FE.lmp new file mode 100644 index 00000000000..79bcd8be222 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0394.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0394.lmp new file mode 100644 index 00000000000..aabedbe96fc Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0398.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0398.lmp new file mode 100644 index 00000000000..9519ac304ee Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/039B.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/039B.lmp new file mode 100644 index 00000000000..2b38112281b Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/039E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/039E.lmp new file mode 100644 index 00000000000..469bc934a5a Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A3.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A3.lmp new file mode 100644 index 00000000000..a02e8288036 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A8.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A8.lmp new file mode 100644 index 00000000000..0e18cf18ac3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A9.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A9.lmp new file mode 100644 index 00000000000..683eb62bbea Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0403.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0403.lmp new file mode 100644 index 00000000000..5ed69b50b9a Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0404.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0404.lmp new file mode 100644 index 00000000000..7a1a2101485 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040C.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040C.lmp new file mode 100644 index 00000000000..88dcc15d7c7 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040D.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040D.lmp new file mode 100644 index 00000000000..4d6cc265143 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040E.lmp new file mode 100644 index 00000000000..1795000b7b2 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0490.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0490.lmp new file mode 100644 index 00000000000..5a7d5477ee8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E80.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E80.lmp new file mode 100644 index 00000000000..92c55e1e84e Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E82.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E82.lmp new file mode 100644 index 00000000000..cc2cef3dc9a Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E84.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E84.lmp new file mode 100644 index 00000000000..cc908f17cf3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1EF2.lmp b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1EF2.lmp new file mode 100644 index 00000000000..b1db517d473 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/bigfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C0.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C0.lmp index 884bcaa95e8..aa99a481e5b 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C0.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C0.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C1.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C1.lmp index 2aa1be2edcb..385ae4d1dd5 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C1.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C1.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C2.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C2.lmp index 7e52626d678..c5555b8e898 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C2.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C2.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C3.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C3.lmp index 110a3b03e82..15386ed7363 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C3.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C3.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C4.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C4.lmp index 523ad846671..ee368cab69d 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C4.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C4.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C5.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C5.lmp index 2aa1be2edcb..7942a0ae5b6 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C5.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C5.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C6.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C6.lmp index e57b956d2c1..9c8787c8722 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C6.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C6.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C7.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C7.lmp index 4e04a428007..7db6990a896 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C7.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C7.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C8.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C8.lmp index 71af557f698..09b05f64b29 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C8.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C8.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C9.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C9.lmp index f9f88c083fa..017cbe06970 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C9.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00C9.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CA.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CA.lmp index 0b0f7dad1cf..432fece0283 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CA.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CA.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CB.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CB.lmp index 663367e721c..9d1884202ce 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CB.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CB.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CC.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CC.lmp index 40c19edf87d..f6d87539d47 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CC.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CC.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CD.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CD.lmp index c0f817cfb44..f6d87539d47 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CD.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CD.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CE.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CE.lmp index 471198d0f91..637ef12d384 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CE.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CE.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CF.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CF.lmp index 0a46b3bb137..c421a71dda2 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CF.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00CF.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D0.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D0.lmp index 2f37093ae89..b6b404c9073 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D0.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D0.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D1.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D1.lmp index 900a80f4524..980757e8562 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D1.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D1.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D2.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D2.lmp index 29bb39ffa35..860ba274756 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D2.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D2.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D3.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D3.lmp index e1b3e850bbb..4da412af143 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D3.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D3.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D4.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D4.lmp index c6153e0d147..01115dd9e11 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D4.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D4.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D5.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D5.lmp index b16fd6e5a7f..9b1b69a209d 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D5.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D5.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D6.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D6.lmp index 681436fec67..359d4599531 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D6.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D6.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D8.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D8.lmp index 17639fa7b74..673c1acc3d9 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D8.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D8.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D9.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D9.lmp index 9e72a15c03f..ac293675d10 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D9.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00D9.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DA.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DA.lmp index 254af0dbe17..12354cb7500 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DA.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DA.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DB.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DB.lmp index 77b2f76a0ec..e50d77b03da 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DB.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DB.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DC.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DC.lmp index f1f5eb227b1..2c778c014ca 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DC.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DC.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DD.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DD.lmp index 47a47dc9817..4cbf5f9bd23 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DD.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/00DD.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0100.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0100.lmp index c2b210ae0a8..65cbc975a59 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0100.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0102.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0102.lmp index 2677c491efc..0e2f7121e96 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0102.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0102.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0104.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0104.lmp index 233ba892756..43ed6cf42c9 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0104.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0104.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0106.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0106.lmp index f7e5393fe44..cac14faa6f6 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0106.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0106.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0108.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0108.lmp index 7121c4d62b4..90c05e96c0b 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0108.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0108.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010A.lmp new file mode 100644 index 00000000000..063d00cb7f6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010C.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010C.lmp index 3a1e5d973f9..cc9a82ade6e 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010C.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010C.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010E.lmp index 3cd7c8cbf7b..807bc5b38f5 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010E.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/010E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0110.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0110.lmp new file mode 100644 index 00000000000..b6b404c9073 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0110.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0112.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0112.lmp index cd64f26c065..3318add4e76 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0112.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0114.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0114.lmp index 25f25e86487..391314b4502 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0114.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0114.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0116.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0116.lmp new file mode 100644 index 00000000000..8124e9a4fe7 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0118.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0118.lmp index f524889f91d..419300a4b0a 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0118.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0118.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011A.lmp index cc5aac045d6..2757bdc5a0f 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011A.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011C.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011C.lmp index 6e3ba19b5cf..eafddd01ef4 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011C.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011C.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011E.lmp new file mode 100644 index 00000000000..d328f9c5cd6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0120.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0120.lmp new file mode 100644 index 00000000000..02947b75a84 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0122.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0122.lmp new file mode 100644 index 00000000000..fd552da5a8b Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0124.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0124.lmp index ff278602074..0150b6daabe 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0124.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0124.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0126.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0126.lmp new file mode 100644 index 00000000000..5ad02058691 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/012A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/012A.lmp new file mode 100644 index 00000000000..948372cd0c8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/012E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/012E.lmp new file mode 100644 index 00000000000..62adab21aa3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0130.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0130.lmp new file mode 100644 index 00000000000..393c72e970e Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0134.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0134.lmp index c6790f0cd50..9c24bbb4853 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0134.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0134.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0136.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0136.lmp new file mode 100644 index 00000000000..4c112aaa300 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0139.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0139.lmp new file mode 100644 index 00000000000..1170d290794 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/013B.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/013B.lmp new file mode 100644 index 00000000000..07690c69d2c Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/013D.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/013D.lmp new file mode 100644 index 00000000000..a71a9d0601a Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0141.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0141.lmp index 989c1eb4547..0cde44e5ea8 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0141.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0141.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0143.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0143.lmp index 61955342bf2..4b009b879b0 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0143.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0143.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0145.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0145.lmp new file mode 100644 index 00000000000..cdf35933774 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0147.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0147.lmp index 10dbd95864b..6fadf8d4cf3 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0147.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0147.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/014A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/014A.lmp new file mode 100644 index 00000000000..f0a4bd384e6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/014C.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/014C.lmp new file mode 100644 index 00000000000..e12201acd83 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0150.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0150.lmp index be16428719d..4985bfe6bcd 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0150.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0150.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0152.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0152.lmp index 2b4e6d9d78f..5e4f77d1f26 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0152.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0152.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0154.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0154.lmp index 1ab2598578c..9fe1c981304 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0154.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0158.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0158.lmp index 4735a980144..0a9b55c882b 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0158.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0158.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015A.lmp index bc4dbc74333..7ebd5058042 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015A.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015C.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015C.lmp index 611ef6506c6..551e0a207ed 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015C.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015C.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015E.lmp index aabeb6bc8c8..0a08ca342da 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015E.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/015E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0160.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0160.lmp index 90fa7ae4504..c59edb28f96 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0160.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0160.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0162.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0162.lmp index 641ea31dca1..f0a560993c6 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0162.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0162.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0164.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0164.lmp index 57d4d0ad4ea..a0f3e9e1a50 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0164.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0164.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0166.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0166.lmp new file mode 100644 index 00000000000..2ec1b446ac4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016A.lmp new file mode 100644 index 00000000000..6a4c3fa513e Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016C.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016C.lmp index a0e7aefb846..f9aa31814ff 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016C.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016C.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016E.lmp index b234e501f74..7c059abd347 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016E.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/016E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0170.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0170.lmp index 00bd29b6f0d..04f00c74e6a 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0170.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0170.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0172.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0172.lmp new file mode 100644 index 00000000000..f148abaae37 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0174.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0174.lmp new file mode 100644 index 00000000000..381fe388f78 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0176.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0176.lmp new file mode 100644 index 00000000000..e784101c4b9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0178.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0178.lmp index b522f104ac0..09f8cc3af0d 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0178.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0178.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0179.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0179.lmp index e740a85c149..9ff01b43cc0 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0179.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0179.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/017B.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/017B.lmp index 5eb19c77341..1ecdf2d7b76 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/017B.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/017B.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/017D.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/017D.lmp index 37667c6ef9b..d4ba2d88261 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/017D.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/017D.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/018F.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/018F.lmp new file mode 100644 index 00000000000..e16b17c3df7 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/01FC.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/01FC.lmp new file mode 100644 index 00000000000..a2a088b9e3b Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/01FE.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/01FE.lmp new file mode 100644 index 00000000000..62e35117ebb Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0218.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0218.lmp new file mode 100644 index 00000000000..9d6f3b7b68f Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0218.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/021A.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/021A.lmp new file mode 100644 index 00000000000..d7da55c2903 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/021A.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0400.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0400.lmp new file mode 100644 index 00000000000..5a41b45e3e0 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0400.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0403.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0403.lmp new file mode 100644 index 00000000000..57af0f283f3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0404.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0404.lmp new file mode 100644 index 00000000000..f175981b474 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040C.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040C.lmp new file mode 100644 index 00000000000..5a9a3e1cb6a Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040D.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040D.lmp index adf4cac406d..2f5ee22b76a 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040D.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040E.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040E.lmp new file mode 100644 index 00000000000..8237f79070a Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0419.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0419.lmp index 42e4217262c..753d00587df 100644 Binary files a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0419.lmp and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0419.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0490.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0490.lmp new file mode 100644 index 00000000000..5b12eba74fd Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E80.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E80.lmp new file mode 100644 index 00000000000..c11c5aa7322 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E82.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E82.lmp new file mode 100644 index 00000000000..008105ac881 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E84.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E84.lmp new file mode 100644 index 00000000000..c1f21bffc26 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1EF2.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1EF2.lmp new file mode 100644 index 00000000000..208ffd9e7da Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2012.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2012.lmp new file mode 100644 index 00000000000..c9b6cf5af54 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2012.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2013.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2013.lmp new file mode 100644 index 00000000000..b3bf1609d83 Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2013.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2026.lmp b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2026.lmp new file mode 100644 index 00000000000..c3a5a81984d Binary files /dev/null and b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/2026.lmp differ diff --git a/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/font.inf b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/font.inf new file mode 100644 index 00000000000..b3c8f497809 --- /dev/null +++ b/wadsrc_extra/static/filter/game-chex/fonts/defsmallfont/font.inf @@ -0,0 +1,2 @@ +FontHeight 9 + diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0100.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0100.lmp new file mode 100644 index 00000000000..57c4a72c61a Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/010A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/010A.lmp new file mode 100644 index 00000000000..a8981fed27f Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0110.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0110.lmp new file mode 100644 index 00000000000..d5c5b9fad85 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0110.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0112.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0112.lmp new file mode 100644 index 00000000000..d8dad1d8b1f Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0116.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0116.lmp new file mode 100644 index 00000000000..ff2e351ff9f Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/011E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/011E.lmp new file mode 100644 index 00000000000..c7e049dc117 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0120.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0120.lmp new file mode 100644 index 00000000000..c0f74355b31 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0122.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0122.lmp new file mode 100644 index 00000000000..0d19617fcdb Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0126.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0126.lmp new file mode 100644 index 00000000000..948cd6ebeda Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/012A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/012A.lmp new file mode 100644 index 00000000000..ce77ef94256 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/012E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/012E.lmp new file mode 100644 index 00000000000..26643bd4c8c Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0130.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0130.lmp new file mode 100644 index 00000000000..96690ddae2d Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0131.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0131.lmp new file mode 100644 index 00000000000..b9a4c10c4fd Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0131.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0136.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0136.lmp new file mode 100644 index 00000000000..b0c82bfacbb Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0139.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0139.lmp new file mode 100644 index 00000000000..24fc57aeb2c Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/013B.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/013B.lmp new file mode 100644 index 00000000000..c4533077ae3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/013D.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/013D.lmp new file mode 100644 index 00000000000..52c0d9a3347 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0145.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0145.lmp new file mode 100644 index 00000000000..c6d412bef24 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/014A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/014A.lmp new file mode 100644 index 00000000000..a9d76146a87 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/014C.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/014C.lmp new file mode 100644 index 00000000000..a6959792931 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0154.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0154.lmp new file mode 100644 index 00000000000..7faedc0ae82 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0166.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0166.lmp index b2f10f4233d..d3f0bf1e415 100644 Binary files a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0166.lmp and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/016A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/016A.lmp new file mode 100644 index 00000000000..33c33c8d555 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0172.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0172.lmp new file mode 100644 index 00000000000..f5fc73cad28 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0174.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0174.lmp new file mode 100644 index 00000000000..d7bff55d26d Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0176.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0176.lmp new file mode 100644 index 00000000000..14eb9cb492a Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/018F.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/018F.lmp new file mode 100644 index 00000000000..06749e306f8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/01FC.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/01FC.lmp new file mode 100644 index 00000000000..cb3708dfd37 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/01FE.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/01FE.lmp new file mode 100644 index 00000000000..99ba6a8ac7d Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0386.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0386.lmp new file mode 100644 index 00000000000..604b2c951f9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0386.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0388.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0388.lmp new file mode 100644 index 00000000000..1b1d5b2c022 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0388.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0389.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0389.lmp new file mode 100644 index 00000000000..d7280397e96 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0389.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038A.lmp new file mode 100644 index 00000000000..f926e3c5cc6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038C.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038C.lmp new file mode 100644 index 00000000000..e2ab7ce533b Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038C.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038E.lmp new file mode 100644 index 00000000000..ddfef6422a7 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038F.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038F.lmp new file mode 100644 index 00000000000..1b99b7726a2 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/038F.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0390.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0390.lmp new file mode 100644 index 00000000000..3c21280e5d3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0390.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0391.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0391.lmp new file mode 100644 index 00000000000..1ae6220a4fd Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0391.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0392.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0392.lmp new file mode 100644 index 00000000000..129e55a0ae8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0392.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0393.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0393.lmp new file mode 100644 index 00000000000..6afaa084b65 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0393.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0394.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0394.lmp new file mode 100644 index 00000000000..4e4ccd8c322 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0395.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0395.lmp new file mode 100644 index 00000000000..de94e70e3b3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0395.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0396.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0396.lmp new file mode 100644 index 00000000000..6ec7c0b981e Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0396.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0397.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0397.lmp new file mode 100644 index 00000000000..8337a9de0e0 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0397.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0398.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0398.lmp new file mode 100644 index 00000000000..3f38e6cc050 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0399.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0399.lmp new file mode 100644 index 00000000000..4483df11492 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0399.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039A.lmp new file mode 100644 index 00000000000..4bd902ac352 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039B.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039B.lmp new file mode 100644 index 00000000000..db4e6a236f6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039C.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039C.lmp new file mode 100644 index 00000000000..053112c8580 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039C.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039D.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039D.lmp new file mode 100644 index 00000000000..fa3b95cc8b3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039D.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039E.lmp new file mode 100644 index 00000000000..aaef3d00625 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039F.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039F.lmp new file mode 100644 index 00000000000..ca055a7cf82 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/039F.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A0.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A0.lmp new file mode 100644 index 00000000000..4ddd2fc5b54 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A0.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A1.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A1.lmp new file mode 100644 index 00000000000..ba8bbb1bbf9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A1.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A3.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A3.lmp new file mode 100644 index 00000000000..a9915dfbfcd Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A4.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A4.lmp new file mode 100644 index 00000000000..615cf9b3187 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A4.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A5.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A5.lmp new file mode 100644 index 00000000000..471b6d98096 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A5.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A6.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A6.lmp new file mode 100644 index 00000000000..a67a842bc78 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A6.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A7.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A7.lmp new file mode 100644 index 00000000000..2b876dffaa9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A7.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A8.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A8.lmp new file mode 100644 index 00000000000..a9a2f9e36ae Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A9.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A9.lmp new file mode 100644 index 00000000000..8f86d1f6b58 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03AA.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03AA.lmp new file mode 100644 index 00000000000..6a47fcab2d8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03AA.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03AB.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03AB.lmp new file mode 100644 index 00000000000..ead64964b68 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03AB.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03B0.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03B0.lmp new file mode 100644 index 00000000000..fc0b5f0c48b Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03B0.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03C2.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03C2.lmp new file mode 100644 index 00000000000..32e96d0ab76 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/03C2.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0403.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0403.lmp new file mode 100644 index 00000000000..d56fbe56a41 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0404.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0404.lmp new file mode 100644 index 00000000000..622e15ea5af Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040C.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040C.lmp new file mode 100644 index 00000000000..d889e7bc438 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040D.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040D.lmp new file mode 100644 index 00000000000..0f713269363 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040E.lmp new file mode 100644 index 00000000000..f5c12b72060 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0419.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0419.lmp index 6076140729e..482f24cc40d 100644 Binary files a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0419.lmp and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0419.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0490.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0490.lmp new file mode 100644 index 00000000000..171c645c354 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E80.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E80.lmp new file mode 100644 index 00000000000..7a9cfc57553 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E82.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E82.lmp new file mode 100644 index 00000000000..4e567705d6d Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E84.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E84.lmp new file mode 100644 index 00000000000..dbb4712d7fc Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1Ef2.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1Ef2.lmp new file mode 100644 index 00000000000..b6029d9f378 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defbigfont/1Ef2.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/010A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/010A.lmp new file mode 100644 index 00000000000..520e1aa8ef7 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0110.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0110.lmp new file mode 100644 index 00000000000..c1e67404071 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0110.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0112.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0112.lmp new file mode 100644 index 00000000000..ad1c85122ce Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0116.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0116.lmp new file mode 100644 index 00000000000..fdc08e4fed1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/011E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/011E.lmp new file mode 100644 index 00000000000..3175666b06a Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0120.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0120.lmp new file mode 100644 index 00000000000..f1e38a2f0af Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0122.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0122.lmp new file mode 100644 index 00000000000..f964aaa116b Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0126.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0126.lmp new file mode 100644 index 00000000000..937b9b9edd4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/012A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/012A.lmp new file mode 100644 index 00000000000..2e52582b88b Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/012E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/012E.lmp new file mode 100644 index 00000000000..fa5aa10a032 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0130.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0130.lmp new file mode 100644 index 00000000000..3c2dcfcfe7d Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0131.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0131.lmp new file mode 100644 index 00000000000..bdf2e7cda5e Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0131.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0136.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0136.lmp new file mode 100644 index 00000000000..f33899cf6fd Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0139.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0139.lmp new file mode 100644 index 00000000000..c6aa25d3c95 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/013B.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/013B.lmp new file mode 100644 index 00000000000..355cfff159a Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/013D.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/013D.lmp new file mode 100644 index 00000000000..5510ce2afc5 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0145.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0145.lmp new file mode 100644 index 00000000000..033df53d35f Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/014A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/014A.lmp new file mode 100644 index 00000000000..608cb7c4f8b Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/014C.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/014C.lmp new file mode 100644 index 00000000000..9a103c84fc1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0154.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0154.lmp new file mode 100644 index 00000000000..771c2883a44 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0166.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0166.lmp new file mode 100644 index 00000000000..cb7c658b767 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/016A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/016A.lmp new file mode 100644 index 00000000000..c2fe53a16c4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0172.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0172.lmp new file mode 100644 index 00000000000..4e09a5a9b37 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0174.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0174.lmp new file mode 100644 index 00000000000..1644ce95f90 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0176.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0176.lmp new file mode 100644 index 00000000000..873d83c6b91 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/018F.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/018F.lmp new file mode 100644 index 00000000000..108e1b19125 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/01FC.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/01FC.lmp new file mode 100644 index 00000000000..b887cd5b2fa Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/01FE.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/01FE.lmp new file mode 100644 index 00000000000..4e199474a81 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0386.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0386.lmp new file mode 100644 index 00000000000..84c8d5204ee Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0386.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0388.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0388.lmp new file mode 100644 index 00000000000..60f8425ec8d Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0388.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0389.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0389.lmp new file mode 100644 index 00000000000..bec36058dc1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0389.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038A.lmp new file mode 100644 index 00000000000..19abaaea45e Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038C.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038C.lmp new file mode 100644 index 00000000000..03ab7ec8495 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038C.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038E.lmp new file mode 100644 index 00000000000..1166ddc53bc Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038F.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038F.lmp new file mode 100644 index 00000000000..75f792f96b8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/038F.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0390.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0390.lmp new file mode 100644 index 00000000000..e9666cd1943 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0390.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0391.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0391.lmp new file mode 100644 index 00000000000..f04b969b0b5 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0391.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0392.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0392.lmp new file mode 100644 index 00000000000..de02bb79e42 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0392.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0393.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0393.lmp new file mode 100644 index 00000000000..0cba22412de Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0393.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0394.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0394.lmp new file mode 100644 index 00000000000..773fa00b649 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0395.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0395.lmp new file mode 100644 index 00000000000..32ef02d054a Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0395.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0396.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0396.lmp new file mode 100644 index 00000000000..aa74189b4f6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0396.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0397.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0397.lmp new file mode 100644 index 00000000000..4871b1f5ad1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0397.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0398.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0398.lmp new file mode 100644 index 00000000000..2c021198511 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0399.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0399.lmp new file mode 100644 index 00000000000..ec3fbb0ae15 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0399.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039A.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039A.lmp new file mode 100644 index 00000000000..a99d51da597 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039A.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039B.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039B.lmp new file mode 100644 index 00000000000..eed8ed97928 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039C.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039C.lmp new file mode 100644 index 00000000000..0666bb24117 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039C.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039D.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039D.lmp new file mode 100644 index 00000000000..f2e5a6406a9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039D.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039E.lmp new file mode 100644 index 00000000000..3a24193f970 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A0.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A0.lmp new file mode 100644 index 00000000000..7267a76488d Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A0.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A1.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A1.lmp new file mode 100644 index 00000000000..22069370023 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A1.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A2.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A2.lmp new file mode 100644 index 00000000000..12346bce914 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A2.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A3.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A3.lmp new file mode 100644 index 00000000000..6503e3dc5d4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A4.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A4.lmp new file mode 100644 index 00000000000..80a02b2649d Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A4.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A5.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A5.lmp new file mode 100644 index 00000000000..3ea41fdf081 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A5.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A6.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A6.lmp new file mode 100644 index 00000000000..6b5781db5ff Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A6.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A7.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A7.lmp new file mode 100644 index 00000000000..69b67189058 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A7.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A8.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A8.lmp new file mode 100644 index 00000000000..787892cff8c Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A9.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A9.lmp new file mode 100644 index 00000000000..a885a24b623 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03AA.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03AA.lmp new file mode 100644 index 00000000000..7fddb83d5e9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03AA.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03AB.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03AB.lmp new file mode 100644 index 00000000000..9976525f70a Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03AB.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03B0.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03B0.lmp new file mode 100644 index 00000000000..a2380b810a4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/03B0.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0403.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0403.lmp new file mode 100644 index 00000000000..83e801dc690 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0404.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0404.lmp new file mode 100644 index 00000000000..af549dd86f3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040C.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040C.lmp new file mode 100644 index 00000000000..692b75d9666 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040D.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040D.lmp new file mode 100644 index 00000000000..58d8d005309 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040E.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040E.lmp new file mode 100644 index 00000000000..b78f824d4da Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0490.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0490.lmp new file mode 100644 index 00000000000..945b1c6bd28 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E80.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E80.lmp new file mode 100644 index 00000000000..94c95039fff Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E82.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E82.lmp new file mode 100644 index 00000000000..75f792f96b8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E84.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E84.lmp new file mode 100644 index 00000000000..9d766f5c17b Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1EF2.lmp b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1EF2.lmp new file mode 100644 index 00000000000..4e7d1521426 Binary files /dev/null and b/wadsrc_extra/static/filter/game-heretic/fonts/defsmallfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0100.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0100.lmp new file mode 100644 index 00000000000..8582704a602 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/010A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/010A.lmp new file mode 100644 index 00000000000..adfe00a90d1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0110.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0110.lmp new file mode 100644 index 00000000000..5f075ac391b Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0110.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0112.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0112.lmp new file mode 100644 index 00000000000..05d79563192 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0116.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0116.lmp new file mode 100644 index 00000000000..bed5b6b3e22 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/011E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/011E.lmp new file mode 100644 index 00000000000..561aec7a0e1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0120.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0120.lmp new file mode 100644 index 00000000000..b054d3d611a Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0122.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0122.lmp new file mode 100644 index 00000000000..601a1d50965 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0126.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0126.lmp new file mode 100644 index 00000000000..bca8cb346c3 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/012A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/012A.lmp new file mode 100644 index 00000000000..655c9e4eb17 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/012E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/012E.lmp new file mode 100644 index 00000000000..fe2d281e04f Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0130.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0130.lmp new file mode 100644 index 00000000000..e699c07b6e8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0131.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0131.lmp new file mode 100644 index 00000000000..9d6f9259446 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0131.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0136.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0136.lmp new file mode 100644 index 00000000000..406db53410e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0139.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0139.lmp new file mode 100644 index 00000000000..cdd0a1b20b0 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/013B.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/013B.lmp new file mode 100644 index 00000000000..f022fc8cf66 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/013D.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/013D.lmp new file mode 100644 index 00000000000..79a1ac501e4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0145.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0145.lmp new file mode 100644 index 00000000000..47f5964a816 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/014A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/014A.lmp new file mode 100644 index 00000000000..b601d6bfee5 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/014C.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/014C.lmp new file mode 100644 index 00000000000..2fdf4a01798 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0154.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0154.lmp new file mode 100644 index 00000000000..748fb8a4e17 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0166.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0166.lmp index df8cf63f5cb..8ca103412ab 100644 Binary files a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0166.lmp and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/016A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/016A.lmp new file mode 100644 index 00000000000..ca1b54b4404 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0172.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0172.lmp new file mode 100644 index 00000000000..8639fd159fb Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0174.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0174.lmp new file mode 100644 index 00000000000..2294edb8653 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0176.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0176.lmp new file mode 100644 index 00000000000..6dd3d9175d6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/018F.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/018F.lmp new file mode 100644 index 00000000000..74920c3c4cd Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/01FC.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/01FC.lmp new file mode 100644 index 00000000000..6805fe57982 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/01FE.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/01FE.lmp new file mode 100644 index 00000000000..f01ea3d74b6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0386.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0386.lmp new file mode 100644 index 00000000000..5c2663f42ae Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0386.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0388.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0388.lmp new file mode 100644 index 00000000000..5d8f4e966be Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0388.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0389.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0389.lmp new file mode 100644 index 00000000000..98ae83df5ee Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0389.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038A.lmp new file mode 100644 index 00000000000..ac468a0c51e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038C.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038C.lmp new file mode 100644 index 00000000000..84c3d9c4fe8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038C.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038E.lmp new file mode 100644 index 00000000000..3ad350d2479 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038F.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038F.lmp new file mode 100644 index 00000000000..f94dafd6c04 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/038F.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0390.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0390.lmp new file mode 100644 index 00000000000..077797ec4d0 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0390.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0391.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0391.lmp new file mode 100644 index 00000000000..48c51dd9e1e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0391.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0392.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0392.lmp new file mode 100644 index 00000000000..bea21d2f245 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0392.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0393.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0393.lmp new file mode 100644 index 00000000000..37af0032b85 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0393.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0394.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0394.lmp new file mode 100644 index 00000000000..acd3cd2eb2d Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0395.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0395.lmp new file mode 100644 index 00000000000..1bfd3416e3a Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0395.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0396.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0396.lmp new file mode 100644 index 00000000000..22dec13f3d6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0396.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0397.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0397.lmp new file mode 100644 index 00000000000..a0b10abde65 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0397.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0398.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0398.lmp new file mode 100644 index 00000000000..2a4edb3d79c Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0399.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0399.lmp new file mode 100644 index 00000000000..7519f147b6d Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0399.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039A.lmp new file mode 100644 index 00000000000..36a9bd62b74 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039B.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039B.lmp new file mode 100644 index 00000000000..2e6a6cc9f43 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039C.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039C.lmp new file mode 100644 index 00000000000..8ebc7c4002a Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039C.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039D.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039D.lmp new file mode 100644 index 00000000000..97f2d9d87a4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039D.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039E.lmp new file mode 100644 index 00000000000..e96f772ea37 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039F.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039F.lmp new file mode 100644 index 00000000000..4a91c8130c0 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/039F.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A0.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A0.lmp new file mode 100644 index 00000000000..0c31e640dfc Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A0.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A1.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A1.lmp new file mode 100644 index 00000000000..154d377ea3f Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A1.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A3.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A3.lmp new file mode 100644 index 00000000000..7023c3acbcc Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A4.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A4.lmp new file mode 100644 index 00000000000..b7c93c39cf4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A4.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A5.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A5.lmp new file mode 100644 index 00000000000..64eb2cbe23e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A5.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A6.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A6.lmp new file mode 100644 index 00000000000..5096da4d93c Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A6.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A7.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A7.lmp new file mode 100644 index 00000000000..e3a8b7db957 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A7.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A8.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A8.lmp new file mode 100644 index 00000000000..f39020f6532 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A9.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A9.lmp new file mode 100644 index 00000000000..f500ec8e7f2 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03AA.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03AA.lmp new file mode 100644 index 00000000000..3215e7d9ae7 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03AA.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03AB.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03AB.lmp new file mode 100644 index 00000000000..041229353cb Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03AB.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03B0.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03B0.lmp new file mode 100644 index 00000000000..6398f0525fc Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03B0.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03C2.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03C2.lmp new file mode 100644 index 00000000000..c6092a255cf Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/03C2.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0403.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0403.lmp new file mode 100644 index 00000000000..bfbdf3e4078 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0404.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0404.lmp new file mode 100644 index 00000000000..ea11cc4ccb6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040C.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040C.lmp new file mode 100644 index 00000000000..e37ef33526a Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040D.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040D.lmp new file mode 100644 index 00000000000..a39697f30c8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040E.lmp new file mode 100644 index 00000000000..154569491bc Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0419.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0419.lmp index a46915f32e5..ca1937f7d0f 100644 Binary files a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0419.lmp and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0419.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0490.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0490.lmp new file mode 100644 index 00000000000..0cf9b98f0b9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E80.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E80.lmp new file mode 100644 index 00000000000..5beed5c24ff Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E82.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E82.lmp new file mode 100644 index 00000000000..698ae1d674d Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E84.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E84.lmp new file mode 100644 index 00000000000..cff95382a5b Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1EF2.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1EF2.lmp new file mode 100644 index 00000000000..7c48f212268 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defbigfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/010A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/010A.lmp new file mode 100644 index 00000000000..cf715b901ac Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0110.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0110.lmp new file mode 100644 index 00000000000..90a7861f002 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0110.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0112.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0112.lmp new file mode 100644 index 00000000000..2b741543665 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0116.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0116.lmp new file mode 100644 index 00000000000..e4115f4ff38 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/011E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/011E.lmp new file mode 100644 index 00000000000..48ba1b9cd6a Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0120.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0120.lmp new file mode 100644 index 00000000000..af93dc8ca27 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0122.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0122.lmp new file mode 100644 index 00000000000..1192f66fd5b Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0126.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0126.lmp new file mode 100644 index 00000000000..0c14bfae47d Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/012A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/012A.lmp new file mode 100644 index 00000000000..5fd14a56ffe Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/012E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/012E.lmp new file mode 100644 index 00000000000..f56885f0586 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0130.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0130.lmp new file mode 100644 index 00000000000..6bbdceaeee9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0131.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0131.lmp new file mode 100644 index 00000000000..6390b5ec86c Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0131.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0136.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0136.lmp new file mode 100644 index 00000000000..fe8038bd1ec Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0139.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0139.lmp new file mode 100644 index 00000000000..f256be38864 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/013B.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/013B.lmp new file mode 100644 index 00000000000..ddbd7852d68 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/013D.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/013D.lmp new file mode 100644 index 00000000000..23c81a98baa Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0145.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0145.lmp new file mode 100644 index 00000000000..48701ab19bb Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/014A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/014A.lmp new file mode 100644 index 00000000000..3a2b59ff009 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/014C.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/014C.lmp new file mode 100644 index 00000000000..69933727708 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0154.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0154.lmp new file mode 100644 index 00000000000..c6803aec8b6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0166.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0166.lmp new file mode 100644 index 00000000000..3587a93bcc4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/016A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/016A.lmp new file mode 100644 index 00000000000..fe41adc168d Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0172.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0172.lmp new file mode 100644 index 00000000000..51a5c24ae82 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0174.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0174.lmp new file mode 100644 index 00000000000..ab049227ee4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0176.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0176.lmp new file mode 100644 index 00000000000..bb43c3fa22e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/018F.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/018F.lmp new file mode 100644 index 00000000000..455a1e58ffd Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/01FC.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/01FC.lmp new file mode 100644 index 00000000000..2ce42004a79 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/01FE.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/01FE.lmp new file mode 100644 index 00000000000..b8154051ca2 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0386.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0386.lmp new file mode 100644 index 00000000000..e2dc0b79aed Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0386.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0388.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0388.lmp new file mode 100644 index 00000000000..43661a1f5de Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0388.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0389.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0389.lmp new file mode 100644 index 00000000000..50f42294fac Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0389.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038A.lmp new file mode 100644 index 00000000000..3c1924ee3f5 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038C.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038C.lmp new file mode 100644 index 00000000000..a263e79249e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038C.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038E.lmp new file mode 100644 index 00000000000..d640f815bd1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038F.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038F.lmp new file mode 100644 index 00000000000..bb1d34337ed Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/038F.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0390.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0390.lmp new file mode 100644 index 00000000000..eb207e65fef Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0390.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0391.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0391.lmp new file mode 100644 index 00000000000..1f0a1bb2701 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0391.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0392.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0392.lmp new file mode 100644 index 00000000000..eef936a67bd Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0392.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0393.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0393.lmp new file mode 100644 index 00000000000..0a3aa900f9e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0393.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0394.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0394.lmp new file mode 100644 index 00000000000..340965a82b4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0395.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0395.lmp new file mode 100644 index 00000000000..cf7c9e07c10 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0395.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0396.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0396.lmp new file mode 100644 index 00000000000..fc4cf42c81a Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0396.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0397.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0397.lmp new file mode 100644 index 00000000000..e61564213bd Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0397.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0398.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0398.lmp new file mode 100644 index 00000000000..2845dee86ce Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0399.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0399.lmp new file mode 100644 index 00000000000..12d174b8b32 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0399.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039A.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039A.lmp new file mode 100644 index 00000000000..6c3796137bf Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039A.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039B.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039B.lmp new file mode 100644 index 00000000000..d3d7e53b015 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039C.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039C.lmp new file mode 100644 index 00000000000..e0c10fd95de Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039C.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039D.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039D.lmp new file mode 100644 index 00000000000..ec52167af93 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039D.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039E.lmp new file mode 100644 index 00000000000..de1da42be7f Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A0.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A0.lmp new file mode 100644 index 00000000000..5e709e5a11e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A0.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A1.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A1.lmp new file mode 100644 index 00000000000..3835f62cbbb Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A1.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A2.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A2.lmp new file mode 100644 index 00000000000..e806962083b Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A2.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A3.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A3.lmp new file mode 100644 index 00000000000..afd4767a417 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A4.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A4.lmp new file mode 100644 index 00000000000..db269314b1f Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A4.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A5.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A5.lmp new file mode 100644 index 00000000000..d95f6e4586d Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A5.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A6.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A6.lmp new file mode 100644 index 00000000000..da3bf8ddd45 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A6.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A7.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A7.lmp new file mode 100644 index 00000000000..d592ff6b2cb Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A7.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A8.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A8.lmp new file mode 100644 index 00000000000..09a6efc882f Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A9.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A9.lmp new file mode 100644 index 00000000000..26a962febad Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03AA.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03AA.lmp new file mode 100644 index 00000000000..d70d07ff781 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03AA.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03AB.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03AB.lmp new file mode 100644 index 00000000000..57cd98d483f Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03AB.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03B0.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03B0.lmp new file mode 100644 index 00000000000..e6efb4def7e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/03B0.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0403.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0403.lmp new file mode 100644 index 00000000000..641c6a088ae Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0404.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0404.lmp new file mode 100644 index 00000000000..cec6e159655 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040C.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040C.lmp new file mode 100644 index 00000000000..4b1ed48d0f9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040D.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040D.lmp new file mode 100644 index 00000000000..5d32f37da25 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040E.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040E.lmp new file mode 100644 index 00000000000..085fc1a7cba Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0490.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0490.lmp new file mode 100644 index 00000000000..16033384e9e Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E80.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E80.lmp new file mode 100644 index 00000000000..2f7641ba385 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E82.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E82.lmp new file mode 100644 index 00000000000..bb1d34337ed Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E84.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E84.lmp new file mode 100644 index 00000000000..762316e7909 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1EF2.lmp b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1EF2.lmp new file mode 100644 index 00000000000..1d8e39e4cf6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-hexen/fonts/defsmallfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0100.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0100.lmp new file mode 100644 index 00000000000..fe1c533580b Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/010A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/010A.lmp new file mode 100644 index 00000000000..57ec84ce421 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0110.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0110.lmp new file mode 100644 index 00000000000..37982f9057e Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0110.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0112.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0112.lmp new file mode 100644 index 00000000000..0a425e9f102 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0116.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0116.lmp new file mode 100644 index 00000000000..43ec9fd41b4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/011E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/011E.lmp new file mode 100644 index 00000000000..65dd0508b91 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0120.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0120.lmp new file mode 100644 index 00000000000..03e84897b7d Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0122.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0122.lmp new file mode 100644 index 00000000000..b37afe5886a Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0126.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0126.lmp new file mode 100644 index 00000000000..1251551fc77 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/012A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/012A.lmp new file mode 100644 index 00000000000..b4da0a46e13 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/012E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/012E.lmp new file mode 100644 index 00000000000..0e7ad1a1919 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0130.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0130.lmp new file mode 100644 index 00000000000..7dafa44d953 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0136.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0136.lmp new file mode 100644 index 00000000000..5c66a1a907c Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0139.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0139.lmp new file mode 100644 index 00000000000..3a3ee638211 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/013B.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/013B.lmp new file mode 100644 index 00000000000..9dfd3c23207 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/013D.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/013D.lmp new file mode 100644 index 00000000000..6de4a1a398a Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0145.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0145.lmp new file mode 100644 index 00000000000..579fe81929c Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/014A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/014A.lmp new file mode 100644 index 00000000000..f9a779c0031 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/014C.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/014C.lmp new file mode 100644 index 00000000000..100194060a2 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0154.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0154.lmp new file mode 100644 index 00000000000..c058e4162ea Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0166.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0166.lmp new file mode 100644 index 00000000000..5d9d7c158fa Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/016C.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/016C.lmp new file mode 100644 index 00000000000..0905106ff0a Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/016C.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0172.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0172.lmp new file mode 100644 index 00000000000..25ab01a768f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0174.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0174.lmp new file mode 100644 index 00000000000..396ba8ba75b Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0176.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0176.lmp new file mode 100644 index 00000000000..01c19aa0a0a Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/018F.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/018F.lmp new file mode 100644 index 00000000000..4944d23992c Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/01FC.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/01FC.lmp new file mode 100644 index 00000000000..39b2fa6c106 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/01FE.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/01FE.lmp new file mode 100644 index 00000000000..01721da64c8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0403.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0403.lmp new file mode 100644 index 00000000000..f12597c55cb Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0404.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0404.lmp new file mode 100644 index 00000000000..ad5074e955f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040C.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040C.lmp new file mode 100644 index 00000000000..4066ccf5529 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040D.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040D.lmp new file mode 100644 index 00000000000..cc28b2ed9b5 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040E.lmp new file mode 100644 index 00000000000..030c462dcfe Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0418.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0418.lmp index 38e9ad6e72c..28c61407f4e 100644 Binary files a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0418.lmp and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0418.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0419.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0419.lmp index 25f15957d42..8d7fbe288b2 100644 Binary files a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0419.lmp and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0419.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0490.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0490.lmp new file mode 100644 index 00000000000..ff7b9d70804 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E80.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E80.lmp new file mode 100644 index 00000000000..6c7fea0536c Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E82.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E82.lmp new file mode 100644 index 00000000000..8933214d12a Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E84.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E84.lmp new file mode 100644 index 00000000000..8b5d4b7b78a Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1EF2.lmp b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1EF2.lmp new file mode 100644 index 00000000000..b487e4c313e Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/bigfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0100.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0100.lmp new file mode 100644 index 00000000000..5f014fabcee Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/010A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/010A.lmp new file mode 100644 index 00000000000..7d451d9d120 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0112.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0112.lmp new file mode 100644 index 00000000000..073e3518ff1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0116.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0116.lmp new file mode 100644 index 00000000000..80e6be9f391 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/011E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/011E.lmp new file mode 100644 index 00000000000..59640157cea Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0120.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0120.lmp new file mode 100644 index 00000000000..1c511cf40c9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0122.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0122.lmp new file mode 100644 index 00000000000..431ff7af6c5 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0126.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0126.lmp new file mode 100644 index 00000000000..638fdd36938 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/012A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/012A.lmp new file mode 100644 index 00000000000..64d4f46fb2d Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/012E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/012E.lmp new file mode 100644 index 00000000000..b3ae49ac135 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0130.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0130.lmp new file mode 100644 index 00000000000..0b5971aae22 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0136.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0136.lmp new file mode 100644 index 00000000000..88b6ad7c030 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0139.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0139.lmp new file mode 100644 index 00000000000..d3fb0e6d991 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/013B.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/013B.lmp new file mode 100644 index 00000000000..1acc7d8f330 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/013D.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/013D.lmp new file mode 100644 index 00000000000..791dc24f8a8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0145.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0145.lmp new file mode 100644 index 00000000000..3625f61c28f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/014A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/014A.lmp new file mode 100644 index 00000000000..a1372c87fa9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/014C.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/014C.lmp new file mode 100644 index 00000000000..0094c3a0e6f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0154.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0154.lmp new file mode 100644 index 00000000000..a0645556f5c Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0166.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0166.lmp new file mode 100644 index 00000000000..ff97d2806ce Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/016A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/016A.lmp new file mode 100644 index 00000000000..6d5a7443594 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0172.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0172.lmp new file mode 100644 index 00000000000..a67b1b169dd Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0174.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0174.lmp new file mode 100644 index 00000000000..8042cdf3281 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0176.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0176.lmp new file mode 100644 index 00000000000..d8eddeaac6c Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/018F.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/018F.lmp new file mode 100644 index 00000000000..006b9a0d805 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/01FC.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/01FC.lmp new file mode 100644 index 00000000000..665c35fdaf4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/01FE.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/01FE.lmp new file mode 100644 index 00000000000..a5e32dcb45b Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0403.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0403.lmp new file mode 100644 index 00000000000..18bf0a3bcd1 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0404.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0404.lmp new file mode 100644 index 00000000000..dd130d30eb6 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040C.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040C.lmp new file mode 100644 index 00000000000..ee4221968bd Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040D.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040D.lmp new file mode 100644 index 00000000000..6ff93f413a8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040E.lmp new file mode 100644 index 00000000000..9a985d6619b Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0418.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0418.lmp index faafe75294b..98b6d332226 100644 Binary files a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0418.lmp and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0418.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0419.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0419.lmp index a600fbb37e5..0c215f8ed66 100644 Binary files a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0419.lmp and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0419.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0490.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0490.lmp new file mode 100644 index 00000000000..99488568674 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E80.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E80.lmp new file mode 100644 index 00000000000..9e5a5825907 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E82.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E82.lmp new file mode 100644 index 00000000000..62f019659d4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E84.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E84.lmp new file mode 100644 index 00000000000..65074fd8f17 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1EF2.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1EF2.lmp new file mode 100644 index 00000000000..b3be9e2a4d9 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0100.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0100.lmp new file mode 100644 index 00000000000..a099d76cb7e Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0100.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/010A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/010A.lmp new file mode 100644 index 00000000000..b757360816a Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/010A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0112.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0112.lmp new file mode 100644 index 00000000000..c1d4292fe68 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0112.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0116.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0116.lmp new file mode 100644 index 00000000000..2ed5a80937f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0116.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/011E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/011E.lmp new file mode 100644 index 00000000000..538672a2a5c Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/011E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0120.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0120.lmp new file mode 100644 index 00000000000..f718ac14e40 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0120.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0122.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0122.lmp new file mode 100644 index 00000000000..9b4257e973b Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0122.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0126.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0126.lmp new file mode 100644 index 00000000000..ab01e847522 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0126.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/012A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/012A.lmp new file mode 100644 index 00000000000..20cda16d928 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/012A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/012E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/012E.lmp new file mode 100644 index 00000000000..63117a5ff1b Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/012E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0130.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0130.lmp new file mode 100644 index 00000000000..a3bff704171 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0130.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0136.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0136.lmp new file mode 100644 index 00000000000..b8703abfe32 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0136.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0139.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0139.lmp new file mode 100644 index 00000000000..50746cc2642 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0139.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/013B.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/013B.lmp new file mode 100644 index 00000000000..d7bf17d2e57 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/013B.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/013D.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/013D.lmp new file mode 100644 index 00000000000..ad1b9b827d4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/013D.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0145.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0145.lmp new file mode 100644 index 00000000000..e7ee0d2e45d Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0145.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/014A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/014A.lmp new file mode 100644 index 00000000000..792bbaafcce Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/014A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/014C.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/014C.lmp new file mode 100644 index 00000000000..05af1387e5e Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/014C.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0154.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0154.lmp new file mode 100644 index 00000000000..b7450cf8237 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0154.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0166.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0166.lmp new file mode 100644 index 00000000000..73453c10b5e Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0166.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/016A.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/016A.lmp new file mode 100644 index 00000000000..b5376546bfd Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/016A.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0172.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0172.lmp new file mode 100644 index 00000000000..ecf1ecc2750 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0172.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0174.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0174.lmp new file mode 100644 index 00000000000..fd8ac58b73f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0174.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0176.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0176.lmp new file mode 100644 index 00000000000..51ce57141e4 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0176.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/018F.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/018F.lmp new file mode 100644 index 00000000000..59b7b125a8f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/018F.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/01FC.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/01FC.lmp new file mode 100644 index 00000000000..fe0eac8f64f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/01FE.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/01FE.lmp new file mode 100644 index 00000000000..75a1f3425d8 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0403.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0403.lmp new file mode 100644 index 00000000000..0729bc6df3a Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0403.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0404.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0404.lmp new file mode 100644 index 00000000000..8d7d533643d Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0404.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040C.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040C.lmp new file mode 100644 index 00000000000..1c8ceb01f95 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040C.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040D.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040D.lmp new file mode 100644 index 00000000000..6350bfa415f Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040D.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040E.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040E.lmp new file mode 100644 index 00000000000..cfc19d817ad Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/040E.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0490.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0490.lmp new file mode 100644 index 00000000000..0d726dbf2ac Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/0490.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E80.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E80.lmp new file mode 100644 index 00000000000..159760e929c Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E82.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E82.lmp new file mode 100644 index 00000000000..7db88414393 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E84.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E84.lmp new file mode 100644 index 00000000000..d01ceadd766 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1EF2.lmp b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1EF2.lmp new file mode 100644 index 00000000000..be114ed3f23 Binary files /dev/null and b/wadsrc_extra/static/filter/game-strife/fonts/defsmallfont2/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/after_iwad/language.csv b/wadsrc_extra/static/filter/hacx.hacx1/after_iwad/language.csv new file mode 100644 index 00000000000..e163f788508 --- /dev/null +++ b/wadsrc_extra/static/filter/hacx.hacx1/after_iwad/language.csv @@ -0,0 +1,1408 @@ +default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,da,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,no nb,pl,pt,ptg,ro,ru,sr,sv,tr +These bugs too tough for ya?,QUITMSG1,,,,Jsou ty bugy na tebe moc tvrdé?,Er disse bugs for hårde for dig?,Sind diese Bugs zu viel für dich?,,Ĉu ĉi tiuj cimoj estas tro forta por vi?,¿Son estos bichos demasiado duros para ti?,,Taitavat nämä ötökät olla liikaa sulle?,Ces bestioles sont trop fortes pour vous?,Túl erősek neked a bogarak is?,Questi errori sono troppo difficili per te?,テメェにはあんなバグ 厳しかないだろ?,고작 버그들 상대하는 것도 버거운 건가?,Zijn deze bugs te hard voor je?,Er disse insektene for tøffe for deg?,To robactwo jest za twarde dla ciebie?,"Tá achando difícil eliminar esses bugs, é?",,Sunt prea duri gândacii pentru tine?,Эти баги крутоваты для тебя?,,Är dessa bugs för svåra för dig?,Bu böcekler senin için çok mu zor? +Are you sure you want to\njack out of the action?,QUITMSG,,,,"Jsi si jistý, že se chceš +zdáchnout z akce?","Er du sikker på, at du vil holdeop med at deltage?","Bist du sicher, dass du den\nStecker ziehen willst?",,"Ĉu vi certas, ke vi volas +malkonektiĝi el la batalo?",¿Estás segur@[ao_esp] de que\nquieres desconectarte de la acción?,,Haluatko varmasti irrottaa\npiuhan toiminnasta?,Etes-vous sûr de vouloir\nvous déconnecter de l'action?,"Biztos vagy benne, hogy kihúzod a kábelt?",Sei sicuro di voler uscire?,もしかして逃げ出そうとしてないよな?,"지금 종료하겠다고? + +진심이냐?",Weet je zeker dat je de actie wilt staken?,Er du sikker på at du vil trekke deg ut av handlingen?,Na pewo chcesz wyjść w środku akcji?,Quer mesmo se desconectar de toda a ação? ,,Ești sigur că vrei să\npărăsești acțiunea?,Ты правда хочешь улизнуть\nс поля боя?,,Är du säker på att du inte vill vara med?,İşin dışında kalmak istediğine emin misin? +Trying to quit? And you call yourself a hacker?,QUITMSG2,,,,Snažíš se skončit? To si říkáš hacker?,Prøver du at holde op? Og du kalder dig selv en hacker?,Du willst gehen? Bist du wirklich ein Hacker?,,Vi provas rezigni? Kaj vi nomas vin kodrompisto?,¿Intentando salir? ¿Y te haces llamar hacker?,,Yritätkö lopettaa? Ja sinäkö muka hakkeri?,On essaye de quitter?\nvous prétendez être un hacker?,Próbálasz kilépni? És még te nevezed magad hekkernek?,Stai cercando di smettere?\nE ti definisci un hacker?,終了させる? それでハッカー自称してたのか?,그만두려고? 해커라는 이름이 아깝군그래.,Proberen te stoppen? En je noemt jezelf een hacker?,Prøver du å slutte? Og du kaller deg en hacker?,Próbujesz wyjść? I nazywasz siebie hakerem?,Tá querendo sair? E você ainda se acha um hacker?,,Încerci să ieși? Și te mai numești hacker?,Хочешь убежать? А ещё зовёшь себя хакером!,,Försöker du sluta? Och du kallar dig för hackare?,Bırakmaya mı çalışıyorsun? Bir de kendine hacker mı diyorsun? +Get back here before I send a virus up your tailpipe!,QUITMSG3,,,,"Vrať se, než ti do zadku pošlu virus!","Kom tilbage, før jeg sender en virus op i dit udstødningsrør!","Komm zurück, oder ich schick dir 'nen Virus!",,"Revenu ĉi tien antaŭ ol mi sendos +viruson en vian posttubon!","¡Vuelve aquí antes de que +te meta un virus de través!","¡Vuelve antes de que te mande +un virus al tubo de escape!","Heti takaisin tänne, ennen kuin lähetän viruksen pitkin takaputkeasi!",Reviens ici avant que je t'envoie un virus là où ça fait mal!,"Gyere csak vissza, mielőtt feldugok neked egy vírust.",Torna indietro o ti\nmanderò un virus!,さっさと戻らねえと そのケツ穴にウィルスぶっこむぞ!,"돌아와, 네 전선에 바이러스 주입해버리기 전에!",Kom terug voordat ik een virus in je uitlaatpijp stuur!,Kom tilbake før jeg sender et virus opp eksosrøret ditt!,Wróć tu zanim wyślę ci wirusa!,Volta aqui antes que eu te mande um vírus!,,Treci înapoi aici până nu-ți trimit un virus!,"Вернись, пока я не посадил вирус тебе на хвост!",,Kom tillbaka innan jag skickar ett virus upp i ditt avgasrör!,Egzozuna bir virüs göndermeden önce buraya geri dön! +Real hackers never jack out of the action.,QUITMSG4,,,,Skuteční hackeři nikdy neprchají z akce.,Rigtige hackere går aldrig ud af spillet.,Echte Hacker geben nicht auf!,,"Veraj kodrompistoj +neniam fuĝas el batalo.","Los verdaderos hackers no +se desconectan de la acción.",,Todelliset hakkerit eivät ikinä kytkeydy irti toiminnasta.,Un vrai hacker ne se déconnecte pas en pleine action.,Az igazi hekkerek sosem húzzák ki a kábelt.,I veri hacker non si arrendono!,本物のハッカーなら頭を銃で撃ち抜くことはしない。,진정한 해커는 이렇게 포기하지 않는다고!,Echte hackers komen nooit uit de actie.,Ekte hackere trekker seg aldri ut av kampen.,Prawdziwi hakerzy nigdy nie uciekają z akcji.,Hackers de verdade nunca vazam da ação!,,Adevărații hackeri nu fug de acțiune.,Настоящие хакеры не пытаются улизнуть с поля боя.,,Riktiga hackare hoppar aldrig av.,Gerçek hackerlar asla aksiyondan kaçmazlar. +C'mon! You haven't seen the best part yet!,QUITMSG5,,,,No tak! Ještě jsi neviděl to nejlepší!,Kom nu! Du har ikke set det bedste endnu!,Komm schon. Du hast das Beste noch gar nicht gesehen!,,"Nu! Vi ankoraŭ ne vidis +la plej bonan parton!","¡Venga! ¡Aún no has +visto la mejor parte!","¡Venga! ¡Aún no +viste la mejor parte!",Älä viitsi! Et ole edes vielä nähnyt parasta kohtaa!,"Allez, on arrive presque à la meilleure partie!",Nemár! Még nem is láttad a legjobb részt!,"Andiamo, forza! Non hai ancora\nvisto la parte migliore!",おいおい! お楽しみはこれからだぜ!,이봐! 아직 재밌는 부분은 시작도 안 했다고!,Kom op! Je hebt het beste deel nog niet gezien!,Kom igjen! Du har ikke sett det beste ennå!,No weź! Jeszcze nie widziałeś najlepszej części!,Qual é! Você nem viu a melhor parte ainda!,,Haide! Nu ai văzut partea cea mai bună încă!,"Да ладно, ты ещё не видел самое крутое!",,Kom igen! Du har inte sett det bästa ännu!,Hadi ama! Daha en iyi kısmını görmedin! +"Give up now, and cyberspace is toast!",QUITMSG6,,,,Vzdej se a s kyberprostorem je konec!,"Giv op nu, og cyberspace er ristet!",Wenn du jetzt aufgibst ist der Cyberspace am Ende.,,"Se vi rezignas nun, tiam +Interret-spaco estos detruita!","¡Ríndete ahora y el ciberespacio +está frito!",,Luovuta nyt ja kyberavaruus kärtsää!,"Abandonne, et le cyberespace est foutu!","Ha most feladod, akkor a cyberspacenek lőttek.","Se ti arrendi ora,\nil cyberspazio è finito.",さっさと止めて、サイバースペースに乾杯だ!,포기하면 사이버 공간은 결국엔 사라질걸?,"Geef het nu op, en cyberspace is een toast!","Gi opp nå, og cyberspace er ferdig!","Poddaj się, a cyberprzestrzeń zmieni się w tosta!","Se você desistir agora, o ciberespaço já era!",,"Te dai bătut acum, și spațiul cibernetic e prăjit!","Если ты сейчас сдашься, киберпространству конец!",,Om du ger upp nu är cyberrymden död!,"Şimdi pes edersen, siber uzay kızarır!" +"GENIE sends its best regards, scumbag!",QUITMSG7,,,,"GENIE posílá své pozdravy, hajzle!","GENIE sender dig sine bedste hilsner, skiderik!","GENIE sendet seine besten Grüße, Mistkerl!",,"ĜINIO sendas plej siajn konsiderojn, fiulo!","¡GENIE te envía saludos, desgraciado!",,"GENIE lähettää terveisensä, mäntti!","GENIE t'envoie ses salutations, salaud!","GENIE üdvözletét küldi, te mocsok!","GENIE ti manda i suoi\nmigliori saluti, bastardo!",GENIEがベストの挨拶を送るぜ、カス野郎!,어이 등신! 지니에서 안부를 전해 달라더군.,"GENIE doet je de groeten, klootzak!","GENIE sender sine beste hilsener, drittsekk!","GENIE przysyła pozdrowienia, łajzo!","GENIE manda lembranças, seu lixo!",,"GENIE își transmite condoleanțele, ticălosule!","Наилучшие пожелания от ДЖИННа, ублюдок!",,"GENIE skickar sina bästa hälsningar, skitstövel!","GENIE selamlarını yolladı, pislik!" +"Hmm. So much for being a hero, Hacker.",QUITMSG8,,,,"Hmm. To by bylo pro hrdinství, Hackeře.","Hmm. Så meget for at være en helt, Hacker.","Hmm. So viel zum Thema ""Held"", Hacker.",,"Ĥaa. Kia domaĝo, ke vi estas hero, Kodrompisto.","Hmm. Poco tienes de héroe, hacker.",,"Höh, se siitä sankarina olemisesta sitten, hakkeri.","Eh bien, on est pas vraiment un héros, hacker.","Hmm. Ennyit a hős karrieredről, hekker barátom.","Hmm. E io che pensavo fossi un eroe, Hacker.",うーん。英雄とはこの程度だったのか、ハッカー。,영웅이 될 그릇은 아닌 거 같군. 안 그래? 해커 형씨.,"Hmm. Tot zover de held, Hacker.","Hmm. Så mye for å være en helt, Hacker.","Hmm. Tak wiele by być bohaterem, Hakerze.","Hmm. Não é tão herói assim, pelo visto.",,"Hmm. Asta a fost cu eroismele, Hacker.","Хм-м. Вот тебе и герой, хакер!",,"Hmm. Så mycket för att vara en hjälte, Hacker.","Hmm. Kahraman olmak için çok fazla, Hacker." +What? You'd rather go back to the pen?,QUITMSG9,,,,Co? Radši by ses vrátil do basy?,Hvad? Vil du hellere gå tilbage til fængslet?,Was? Du willst in den Knast zurück?,,"Kio? Ĉu vi preferas, ke vi revenu al la plumon?",¿Qué? ¿Prefieres volver al corral?,,Täh? Menisit mieluummin takaisin kynän ääreen?,Quoi? Tu préfère retourner dans ta cellule?,Hogy micsoda? inkább visszamennél a tolladhoz?,Cosa? Vuoi tornare in prigione?,何? 今更ペンで計算するのか?,펜이나 끄적거리는 인생으로 돌아가겠다. 이건가?,Wat? Ga je liever terug naar de pen?,Hva? Vil du heller tilbake til kasjotten?,Co? Wolisz wrócić do więzienia?,O quê? Prefere voltar pro xilindró?,,Ce? Vrei să te întorci la captivitate?,Что? Ты хочешь вернуться в неволю?,,Vad? Vill du hellre gå tillbaka till pennan?,Ne? Kalemine geri dönmeyi mi tercih ediyorsun? +Shoulda taken the blue pill.,QUITMSG10,,,,Měl sis vzít modrou pilulku.,Du skulle have taget den blå pille.,Du hättest die blaue Pille nehmen sollen...,,"Vi estus devinta preni +la bluan pilolon.",Deberías haber tomado la pastilla azul.,,Olis pitäny ottaa sininen pilleri.,T'aurais du prendre la pilule bleue.,Inkább a kék pirulát kellett volna választanod.,Avresti dovuto prendere la pillola blu ...,青いピルを採るべきではなかったな。,넌 파란 알약을 골랐어야 했어.,Je had de blauwe pil moeten nemen.,Skulle tatt den blå pillen.,Trzeba było wziąć niebieską pigułkę.,Devia ter tomado a pílula azul.,,Trebuia să iei pastila albastră.,Надо было принять синюю таблетку.,,Du borde ha tagit det blå pillret.,Mavi hapı almalıydın. +The name of the game ain't Twitch n' Run!,QUITMSG11,,,,V názvu hry není napsané „uteč“!,"Spillets navn er ikke ""at flygte""!","Das Spiel heißt nicht ""wegrennen""!",,La nomo de la ludo ne estas Tiku kaj Kuru!,¡El nombre del juego no es Tirar a Correr!,,Pelin nimi ei oo Paniikkipako!,"Le jeu s'appelle pas ""Panique et cours!""",A játék neve nem Twitch n' Megfutamodás.,"Il gioco non significa ""scappare""!",ゲーム名は 萎え落ち小僧 じゃねえぞ!,"이봐, 이 게임은 때리고 도망가는 게임이 아니라고!",De naam van het spel is niet Twitch n' Run!,Navnet på spillet er ikke Twitch n' Run!,"Nazwą gry nie jest ""Drżyj i Uciekaj""!",O nome do jogo não é Trema nas Bases e Fuja!,,Numele jocului nu e Tremură și Ascunde-te!,Эта игра называется не «Дрожи и прячься»!,,"Spelet heter inte ""Twitch n' Run""!",Oyunun adı Twitch n' Run değil! +"No worries. Saving the world can wait, right?",QUITMSG12,,,,"Žádný problém. Záchrana světa může počkat, ne?","Det er ikke noget problem. At redde verden kan vente, ikke?","Also, die Welt zu retten kann warten, richtig?",,"Ne zorgu. Savi la mondon povas atendi, ĉu ne?","No te preocupes. Salvar el mundo puede esperar, ¿verdad?",,"Ei huolta; maailman pelastaminen voi odottaa, eikö niin?","Oh, pas de problème. Le monde peut attendre\nd'être sauvé, non?","Semmi pánik. A világmegmentés várhat, nemde?","Salvare il mondo può\naspettare, giusto?",気にはしない、世界を救うのは何時でも出来る、だろ?,걱정 말라고. 세상이 위험한데 급할 것 있나. 안 그래?,"Het redden van de wereld kan wachten, toch?","Slapp av. Å redde verden kan vente, ikke sant?","Bez obaw. Ratowanie świata może poczekać, prawda?","Sem problemas. O mundo pode esperar, não é mesmo?",,"Nicio problemă. Salvarea lumii poate aștepta, nu?","Не парься. Спасение мира подождёт, ведь так?",,"Det är ingen fara. Att rädda världen kan vänta, eller hur?","Endişelenme. Dünyayı kurtarmak bekleyebilir, değil mi?" +Guess it's time to make like the 'net and split!,QUITMSG13,,,,"Hádám, že je čas vypojit server!",Så er det vist på tide at gøre som nettet og smutte!,"Also ist es soweit, dass sich unsere Wege trennen.",,"Tempas, ke niaj vojoj agu kiel la reto kaj dividu.",¡Supongo que es hora de cortar con esta mala conexión!,,Kai sitten on aika katkaista palvelinyhteydet!,Ca doit être temps de partir comme une mauvaise connection!,Kettéváglak mint a netsplit a kapcsolatot.,Quindi è il momento per i\nnostri modi di separarsi.,ネット切断している暇は無いだろ!,벌써 서버를 다운시키는 '척' 할 시간인가?,Denk dat het tijd is om het te maken als het 'net en splitsen!,Det er vel på tide å gjøre som nettet og stikke!,"Wygląda na to, że trzeba się rozłączyć jak netsplit!","Acho que tá na hora de cair, que nem uma conexão ruim.",,Cred că e timpul de separare!,"Кажется, настало время устроить netsplit!",,Det är nog dags att göra som nätet och dra sig ur!,Sanırım 'net gibi yapıp ayrılmanın zamanı geldi! +"Don't go off and forget about HacX, now!",QUITMSG14,,,,Ať tě nenapadne odejít a zapomenout na HacX!,Glem nu ikke HacX!,Bitte vergesse HacX nicht!,,Ne iru forgesi HacX nun!,¡Ahora no vayas y te olvides de Hacx!,,Älä nyt mene pois ja unohda HacX:ä!,Va pas oublier HacX maintenant!,"Ha elkalandozol, ne feletkezz meg a HacX-ről!","Non andartene e dimenticarti di HacX, ora!",HacXを忘れんじゃねえぞ、な!,부디 나가지 말고 HacX를 잊지 말아줘!,"Ga niet af en vergeet HacX niet, nu!","Ikke gå og glem HacX, nå!","Nie wyłączaj i nie zapominaj o HacX, teraz!","Não vai se esquecer do HacX, hein!",,Nu pleca și uita de HacX!,"Только посмей уйти и забыть про HacX, ты!",,Gå inte iväg och glömma HacX nu!,"HacX'i unutup gitme, şimdi!" +%o deleted %hself from the universe.,OB_SUICIDE,,,,%o se smazal@[ao_cs] z vesmíru.,%o slettede sig selv fra universet.,%o entfernte sich aus dem Universum.,,%o forigis sin el la universo.,%o se borró a si mism@[ao_esp] del universo.,,%o poisti itsensä maailmankaikkeudesta.,%o s'est effacé@[e_fr] de l'univers.,%o kitörölte magát az univerzumból,%o si è cancellato dall'universo.,%o はこの宇宙から消滅した。,%o 은(는) 자기 자신의 존재를 소멸시켰다.,%o verwijderd zichzelf uit het universum.,%o slettet seg selv fra universet.,%o usun@[irreg_2_pl] się ze świata.,%o se apagou deste universo.,,%o s-a sters pe sine din univers.,Игрок %o стёр себя с лица вселенной.,,%o raderade sig själv från universum.,%o kendini evrenden sildi. +%o formed a crater the size of Kansas.,OB_FALLING,,,,%o utvořil@[ao_cs] kráter velikosti Kansasu.,%o dannede et krater på størrelse med Kansas.,%o wurde zu einem Krater in der Größe von Kansas.,,%o formis krateron grandan kiel Kansaso.,%o formó un cráter del tamaño de Kansas.,,%o muodosti Kansasin kokoisen kraaterin.,%o a formé un cratère de la taille du Kansas.,%o egy Kansas méretű krátert hagyott maga után.,%o ha formato un cratere delle dimensioni del Kansas.,%o はカンザス州程のクレーターを生成した。,%o 은(는) 땅바닥에 캔자스만큼 커다란 구멍을 뚫었다.,%o vormde een krater ter grootte van Kansas.,%o dannet et krater på størrelse med Kansas.,%o utworzył@[ao_pl] krater wielkości Kansas.,%o abriu uma cratera do tamanho do Kansas.,,%o a format un crater de dimensiunile statului Kansas.,На месте падения игрока %o образовался кратер размером с Канзас.,,%o bildade en krater lika stor som Kansas.,%o Kansas büyüklüğünde bir krater oluşturdu. +%o became a human pancake.,OB_CRUSH,,,,%o se změnil@[ao_cs] v lidskou palačinku.,%o blev en menneskelig pandekage.,%o wurde zu einem menschlichen Pfannkuchen.,,%o Iĝis homa patkuko.,%o se convirtió en un crepe humano.,,%o tuli ihmispannukakun muotoiseksi.,%o est devenu@[e_fr] une crêpe.,%o palacsintává lapult,%o è diventato un pancake umano.,%o は人肉パンケーキになった。,%o 은(는) 인간 빈대떡이 되었다.,%o werd een menselijke pannenkoek.,%o ble en menneskelig pannekake.,%o stał@[ao_pl] się ludzkim plackiem.,%o virou uma panqueca humana.,,%o a devenit o clătită umană.,Игрока %o сплющило в лепешку.,,%o blev en mänsklig pannkaka.,%o insan bir krep oldu. +%o tried to jack out.,OB_EXIT,,,,%o se pokusil@[ao_cs] prchnout.,%o forsøgte at stikke af.,%o hat sich ausgeloggt.,,%o provis malkonektiĝi.,%o intentó desconectarse.,,%o yritti irrottaa piuhan.,%o a tenté de se déconnecter.,%o ki akarta húzni a kábelét,%o è uscito.,%o は逃げ出そうとした。,%o 은(는) 로그아웃하려고 시도했다.,%o probeerde zich terug te trekken.,%o prøvde å jekke seg ut.,%o chciał@[ao_pl] się wydostać.,%o tentou se desconectar.,,%o a încercat să o taie.,Игрок %o хотел улизнуть.,,%o försökte ta sig ut.,%o kaçmaya çalıştı. +%o swam like a brick.,OB_WATER,,,,%o uměl@[ao_cs] plavat jako cihla.,%o svømmede som en mursten.,%o schwamm wie ein Stein.,,%o naĝis kiel briko.,%o nadó como un ladrillo.,,%o ui kuin tiiliskivi.,%o nage comme une brique.,%o úgy úszik mint egy tégla.,%o nuotava come una pietra.,%o はカナヅチだった。,%o 은(는) 웹서핑을 못 하는 타입이었다.,%o zwom als een baksteen.,%o svømte som en murstein.,%o popłyn@[irreg_2_pl] jak cegła.,%o foi nadar como um tijolo.,,%o a înotat ca o cărămidă.,Игрок %o поплыл как топор.,,%o simmade som en tegelsten.,%o bir tuğla gibi yüzdü. +%o went nuclear.,OB_SLIME,,,,%o se rozpadl@[ao_cs] na atom.,%o blev nuklear.,%o wurde verstrahlt.,,%o iĝis nuklea,%o se volvió radioactiv@[ao_esp].,,%o kiinnostui ydinasioista.,%o s'est fait fissionner.,%o felrobbant mérgében.,%o è stato irradiato.,%o はニュークリアーと化した。,%o 은(는) 방사능 바람을 좀 쐬고 왔다.,%o werd nucleair.,%o ble nuklear.,%o został@[ao_pl] napromieniowan@[adj_pl].,%o ficou radioativ@[ao_ptb].,,%o a devenit radioactiv.,Игрок %o светится в темноте.,,%o blev kärnvapenfri.,%o nükleer oldu. +%o took a hot bath.,OB_LAVA,,,,%o si dal@[ao_cs] horkou koupel.,%o tog et varmt bad.,%o nahm ein heißes Bad.,,%o spertis varman banon.,%o tomó un baño caliente.,,%o otti kuuman kylvyn.,% prend un bain chaud.,%o vett egy forró fürdőt.,%o ha fatto un bagno caldo.,%o は熱湯風呂に浸かった。,%o 은(는) 시원하게 용암 일광욕을 즐겼다.,%o nam een warm bad.,%o tok et varmt bad.,%o wzi@[irreg_2_pl] gorącą kąpiel.,%o tomou um banho bem quente.,,%o a făcut o baie fierbinte.,Игрок %o принял горячую ванну.,,%o tog ett varmt bad.,%o sıcak bir banyo yaptı. +%o overdosed on nitro glycerine.,OB_BARREL,,,,%o se předávkoval@[ao_cs] nitroglycerinem.,%o fik en overdosis nitroglycerin.,%o nahm eine Überdosis Nitroglyzerin.,,%o trodozis nitroglicerinon.,%o tuvo una sobredosis de nitroglicerina.,,%o sai yliannostuksen nitroglyseriiniä.,%o a fait une overdose de nitroglycérine.,%o túladagolta a nitro-glicerint.,%o ha assunto un sovradosaggio di nitroglicerina.,%o はニトロを過剰摂取した。,%o 은(는) 니트로글리세린을 훅 가게 흡입했다.,%o overdosering op nitroglycerine.,%o tok en overdose nitroglyserin.,%o przedawkował@[ao_pl] nitroglicerynę.,%o teve overdose de nitroglicerina.,,%o a luat o supradoză de nitroglicerină.,Игрок %o перебрал нитроглицерина.,,%o tog en överdos av nitroglycerin.,%o aşırı dozda nitro gliserin aldı. +%o is flayed into tiny little pieces.,OB_SPLASH,,,,%o byl@[ao_cs] sedřen@[ao_cs] na kousíčky.,%o er flået i småstykker.,%o wurde zerkleinert.,,%o estas senhaŭtiga en malgrandetaj pecoj.,%o es despellejad@[ao_esp] en trocitos pequeños.,,%o silpoutui riekaleiksi.,%o s'est fait éparpiller en petits morceaux.,%o ripityára szakadt szét.,%o è stato schiacciato.,%o は細かい粒をぶち撒けられた。,%o 은(는) 작은 입자로 분해되었다.,%o wordt gevild in kleine stukjes.,%o er flådd i bittesmå biter.,%o został@[ao_pl] roztrzaskan@[adj_pl] na małe kawałeczki.,%o foi detonad@[ao_ptb] em vários pedacinhos.,,%o s-a spart în mii de bucățele.,Игрока %o разодрали на мелкие клочки.,,%o är flådd i pyttesmå bitar.,%o küçük parçalara ayrıldı. +%o wanted to see what %g looked like inside-out.,OB_R_SPLASH,,,,"%o chtěl@[ao_cs] vědět, jak vypadá zevnitř.","%o ville se, hvordan han så ud indefra.",%o wollte @[pp_de] Innereien sehen.,,"%o volis vidi, kiel %g aspektus kun la interno ekstere.",%o quería ver que pinta tenía por dentro.,,%o halusi nähdä itsensä nurinperin.,%o voulait voir comment ses organes fonctionnent.,%o meg akarta tudni %g hogy néz ki belülről.,%o voleva vedere le sue interiora.,%o は %g が裏返しになるのを望んだ。,%o 은(는) 인체의 신비를 감상했다.,%o wilde zien hoe %g er binnenstebuiten uitzag.,%o ville se hvordan han så ut på innsiden.,%o chciał@[ao_pl] zobaczyć jak %g wygląda od środka.,%o queria ver como são os orgãos internos de %g.,,%o a vrut să vadă cum arăta %g întors pe dos.,"Игрок %o хотел посмотреть, что у него внутри.",,%o ville se hur @[pro_sv] såg ut på insidan.,"%o, içinin dışının nasıl göründüğünü görmek istedi." +%o wanted to see what %g looked like inside-out.,OB_ROCKET,,,,"%o chtěl@[ao_cs] vědět, jak vypadá zevnitř.","%o ville se, hvordan han så ud indvfra.",%o wollte @[pp_de] Innereien sehen.,,"%o volis vidi, kiel %g aspektus kun la interno ekstere.",%o quería ver que pinta tenía por dentro.,,%o halusi nähdä itsensä nurinperin.,%o voulait voir comment ses organes fonctionnent.,%o meg akarta tudni %g hogy néz ki belülről.,%o voleva vedere le sue interiora.,%o は %g が裏返しになるのを望んだ。,%o 은(는) 퀀텀 여행을 즐겼다.,%o wilde zien hoe %g er binnenstebuiten uitzag.,%o ville se hvordan han så ut utenpå.,%o chciał@[ao_pl] zobaczyć jak %g wygląda od środka.,%o queria ver como são os orgãos internos de %g.,,%o a vrut să vadă cum arăta %g întors pe dos.,"Игрок %o хотел посмотреть, что у него внутри.",,%o ville se hur @[pro_sv] såg ut på insidan.,%o içten dışa nasıl göründüğünü görmek istedi. +%o deleted %hself from the universe.,OB_KILLEDSELF,,,,%o se smazal@[ao_cs] z vesmíru.,%o slettede sig selv fra universet.,%o entfernte sich aus dem Universum.,,%o forigis sin el la universo.,%o se borró a si mism@[ao_esp] del universo.,,%o poisti itsensä maailmankaikkeudesta.,%o s'est effacé@[e_fr] de l'univers.,%o kitörölte magát az univerzumból,%o si è cancellato dall'universo.,%o はこの宇宙から消滅した。,%o 은(는) 자기 자신을 해킹했다.,%o schrapte zichzelf uit het universum.,%o slettet seg selv fra universet.,%o usun@[irreg_2_pl] się ze świata.,%o se deletou deste universo.,,%o s-a șters pe sine din univers.,Игрок %o стёр себя с лица вселенной.,,%o raderade sig själv från universum.,%o kendini evrenden sildi. +%o is no longer the dominant species.,OB_THUG,,,,%o už není vládnoucím živočichem.,%o er ikke længere den dominerende art.,%o ist nicht länger die dominante Spezies.,,%o ne estas la supera specio plu.,%o ya no es la especie dominante.,,%o ei ole enää vallitsevaa lajia.,%o n'est plus l'espèce dominante.,Már nem %o a csúcsragadozó.,%o non è più la specie dominante.,%o はもはや優性種ではなくなった。,%o 은(는) 그들의 시다바리가 아니였다.,%o is niet langer de dominante soort.,%o er ikke lenger den dominerende arten.,%o nie jest już dominującym gatunkiem.,%o não é mais a espécie dominante.,,%o nu mai e specia dominantă.,Игрок %o больше не доминантная форма жизни.,,%o är inte längre den dominerande arten.,%o artık baskın tür değil. +%o plugged in to the wrong machine.,OB_ANDROID,,,,%o se zapojil@[ao_cs] ke špatnému stroji.,%o har tilsluttet sig den forkerte maskine.,%o verband sich mit der falschen Maschine.,,%o konektiĝis en la eraran maŝinon.,%o se enchufó en la máquina equivocada.,,%o kytkeytyi väärään koneeseen.,%o s'est branché@[e_fr] à la mauvaise machine.,%o a rossz gépet dugta be.,%o connesso alla macchina sbagliata.,%o は違うマシンに接続してしまった。,%o 은(는) 잘못된 기계를 작동시켰다.,%o aangesloten op de verkeerde machine.,%o koblet seg til feil maskin.,%o podłączył@[ao_pl] się do złej maszyny.,%o se conectou na máquina errada.,,%o s-a conectat la mașina greșită.,Игрока %o подключили не к тому заряднику.,,%o anslöt sig till fel maskin.,%o yanlış makineye bağlandı. +%o got %hself a monster of a cyber-jockey-derriere-kicking.,OB_MONSTRUCT,,,,%o dostal@[ao_cs] šíleně kybernakopáno.,%o fik sig et monster af et cyber-jockey-derriere-spark.,%o bekam einen monströsen Cyber-Arschtritt verpasst.,,%o ricevis monstran cybernetik-raydist-postaĵ-piedbaton.,%o se ganó la madre de todas las patadas en el culo.,,%o sai hirviömäisen kyberlöylytyksen.,%o s'est fait@[e_fr] botter le cul de manière monumentale.,%o segge meg lett rugdosva.,% o ho avuto un mostruoso calcio cibernetico mancato.,%o は己に サイバー-ジョッキー-デリエレ-キッキング を取り入れた。,%o 은(는) 저 괴물의 슈퍼-울트라-캡쑝-파워를 맛봤다.,%o kreeg een monsterlijke cybertrap in @[zijn_haar_nl] kont.,%o fikk seg et monster av en cyber-jockey-derriere-sparking.,%o dostał@[ao_pl] cyber-kopa w dupę.,%o levou um cibercoice monstruoso nas fuças.,,%o s-a făcut praf în stil cibernetic.,Игрок %o получил поджопника от кибердиджея.,,%o fick sig ett monster av en cyber-jockey-derriärspark.,%o kendine canavar gibi bir dayak attı. +%o got ICEd.,OB_ICE,,,,%o byl@[ao_cs] zmražen@[ao_cs] ICEm.,%o blev ICEd.,%o wurde verEISt.,,%o iĝis ICE-ita,%o fue ICEad@[ao_esp].,,%o raukkaa nyt varmaankin kICEmittää.,%o s'est fait@[e_fr] ICEr.,%o-t jégre tették.,% o è stato ghiacciato.,%o は冷えた。,%o 은(는) 지독하게 물어뜯겼다.,%o was IJS'd.,%o ble ICEd.,%o został@[ao_pl] zamrożon@[adj_pl].,%o foi peg@[ao_ptb] por um ICE. AI SE ferrou!,,%o a ÎNGHEȚat.,Игрок %o вляпался в ЛЁД.,,%o blev ICEd.,%o buzlandı. +%o feels a little buzzed.,OB_BUZZER,,,,%o dostal@[ao_cs] malou pecku.,%o føler sig lidt svimmel.,%o fühlt sich etwas gekitzelt.,,%o sentas sin iomete vibretita.,%o se siente algo zumbad@[ao_esp].,,%o raukan päässä hieman surisee.,%o sent le buzz.,%o-nak még mindig zúg a füle.,%o si sente solleticato un po '.,%o は少し賑やかになった。,%o 은(는) 짜릿하게 찔렸다.,%o voelt een beetje gezoemd.,%o føler seg litt beruset.,%o poczuł@[ao_pl] brzęczenie.,%o se sente meio chocad@[ao_ptb].,,%o se simte puțin șocat.,Игрок %o лёг спать в компании вертолётиков.,,%o känner sig lite uppslukad.,%o biraz kafayı bulmuş gibi hissediyor. +%o uncovers a rather shocking development.,OB_STEALTH,,,,%o odhalil@[ao_cs] šokující informace.,%o opdager en temmelig chokerende udvikling.,%o machte eine schockierende Entdeckung.,,%o malkovras tre ŝokantan aferon.,%o descubre algo bastante chocante.,,%o raukalle paljastuu sangen sähköistävä uutinen.,%o a fait une découverte choquante.,"%o rájön, hogy az áram nem játék.",%o ha fatto una scoperta scioccante.,%o はかなり衝撃的な開発を発見した。,%o 은(는) 비밀리에 만들어진 병기를 발견했다.,%o ontdekt een nogal schokkende ontwikkeling.,%o avdekker en ganske sjokkerende utvikling.,%o odkrywa coś szokującego.,%o descobre uma revelação chocante.,,%o dezvăluie o schimbare șocantă.,Игрока %o встретил довольно серьёзный поворот событий.,,%o upptäcker en ganska chockerande utveckling.,%o oldukça şok edici bir gelişmeyi ortaya çıkardı. +%o was erased from cyberspace.,OB_DMAN,,,,%o byl@[ao_cs] vymazán@[ao_cs] z kyberprostoru.,%o blev slettet fra cyberspace.,%o wurde aus dem Cyberspace gelöscht.,,%o estas viŝita el cyberspaco.,%o fue borrad@[ao_esp] del ciberespacio.,,%o poistettiin kyberavaruudesta.,%o s'est fait@[e_fr] effacer du cyberespace.,%o-t kitörölték a kibertérből.,%o è stato eliminato dal cyberspazio.,%o はサイバースペースに消去された。,%o 은(는) 영구차단을 당했다.,%o werd gewist uit cyberspace.,%o ble slettet fra cyberspace.,%o został@[ao_pl] usunięt@[adj_pl] z cyber przestrzeni.,%o foi deletad@[ao_ptb] do ciberespaço.,,%o a fost șters din spațiul cibernetic.,Игрока %o удалили из киберпространства.,,%o raderades från cyberrymden.,%o siber uzaydan silindi. +%o gave %hself a glass jaw.,OB_GLASS,,,,%o si přidělal@[ao_cs] skleněnou čelist.,%o gav sig selv en glaskæbe.,%o bekam ein Glaskinn.,,%o donis al si vitran makzelon.,%o se estampó contra un cristal.,,%o antoi itsellensä lasileuan.,%o s'est fait@[e_fr] vitrifier la figure.,%o állon vágta magát.,%o ha un mento di vetro.,%o は自身にグラスジョーを取り付けた。,%o 은(는) 유리창을 깨고 등장하는 액션 배우가 아니였다.,%o gaf zichzelf een glazen kaak.,%o ga seg selv en glasskjeve.,%o był@[ao_pl] zbyt delikatn@[adj_pl] ze szkłem.,%o tem um queixo de vidro.,,%o și-a făcut un maxilar de sticlă.,У игрока %o оказалась стеклянная челюсть.,,%o gav sig själv en glaskäke.,%o kendine cam çene taktı. +%o's life membership was terminated.,OB_MANIAC,,,,%o@[psn_cs] členství v klubu živých bylo přerušeno.,%os medlemskab på livstid blev opsagt.,%os Mitgliedschaft im Leben wurde beendet.,,La vivo-membrecon de %o estas finigita,%o tuvo su afiliación a la vida terminada.,,%o raukan elämänjäsenyys päätettiin.,L'abonnement à vie de %o est arrivé à sa fin.,%o elfelejtette befizetni az élők tagdíját.,L'appartenenza di %o alla vita è finita.,%o のメンバーシップ生活は終幕した。,%o 의 계정은 영원히 삭제되었다.,%o's levenslange lidmaatschap werd beëindigd.,%os livstidsmedlemskap ble avsluttet.,Członkowstwo %o w klubie żywych się skończyło.,%o não está mais afiliad@[ao_ptb] à vida.,,%o nu mai e membru al clubului celor vii.,Игрока %o исключили из клуба живых.,,%os medlemskap på livstid avslutades.,%o hayata veda etti. +%o died in some random method I cannot fathom.,OB_MANIACHIT,,,,"%o umřel@[ao_cs] nějakým způsobem, který ani nemůžu pochopit.","%o døde på en eller anden tilfældig måde, som jeg ikke kan gennemskue.",%o starb auf eine unvorstellbare Art und Weise.,,"%o mortis per iu malcerta maniero, kiun mi ne povas kompreni.",%o murió de alguna manera que no llego a comprender.,,"%o kuoli jollakin sattumanvaraisella tavalla, jota en voi käsittää.",%o est mort@[e_fr] d'une manière que je n'arrive même pas à décrire.,Ötletem since hogy halt meg %o.,%o è morto in un modo inimmaginabile.,%o は計算外の乱数で死んだ。,%o 은(는) 의미불명의 이유로 잠수를 타게 되었다.,%o stierf op een of andere willekeurige manier die ik me niet kan voorstellen.,%o døde på en eller annen tilfeldig måte jeg ikke fatter.,"%o zgin@[irreg_2_pl] pod wpływem metody, której nie mogę pojąć.",%o morreu de alguma forma aleatória que nem consigo imaginar.,,%o a murit într-un mod aleatoriu pe care nu mi-l pot închipui.,Игрок %o внезапно умер по непостижимой для меня причине.,,%o dog på något slumpmässigt sätt som jag inte kan förstå.,%o anlayamadığım rastgele bir yöntemle öldü. +%o was fried by a femme fatale freak.,OB_TERMIN,,,,%o byl@[ao_cs] usmažen@[ao_cs] šílenou femme fatale.,%o blev stegt af en femme fatale freak.,%o wurde von einem Femme-Fatale Freak gebraten.,,%o estis fritita de femme-fatale-groteskulo.,%o fue tostad@[ao_esp] por una femme fatale.,,%o joutui kohtalokkaan kimman kärtsäämäksi.,%o s'est fait@[e_fr] frire par une femme fatale.,%o-t lebombázta egy bomba nő.,% o è stato fritto da una femme fatale.,%o はファム ファタル フリークに揚げられた。,%o 은(는) 미인계에 발을 들였다.,%o werd gebakken door een femme fatale freak.,%o ble stekt av en femme fatale-freak.,%o został@[ao_pl] usmażon@[adj_pl] przez szaloną femme fatale.,%o foi fritad@[ao_ptb] por uma femme fatale psicótica.,,%o a fost prăjit de către o femme fatale psihopată.,Игрока %o поджарила чокнутая роковая женщина.,,%o stektes av en femme fatale-freak.,%o bir femme fatale ucubesi tarafından kızartıldı. +%o got a little close to the opposite sex.,OB_TERMINHIT,"This text is not gender neutral, obviously...",,,%o se moc přiblížil@[ao_cs] k opačnému pohlaví.,%o kom lidt tæt på det modsatte køn.,%o kam dem anderen Geschlecht zu nahe.,,%o iĝis iomete proksime al la mala sekso.,%o se acercó demasiado a la persona equivocada.,,%o meni hieman liian lähelle vastakkaista sukupuolta.,%o s'est trop rapproché@[e_fr] de la mauvaise personne.,%o túl közel került az ellenkező nemhez.,%o è arrivato troppo vicino all'altro sesso.,%o は少し異性に成り果てた。,%o 의 남자다운 자존심은 쪼그라들었다.,%o kwam een beetje in de buurt van het andere geslacht.,%o kom litt nær det motsatte kjønn.,%o pod@[irreg_1_pl] zbyt blisko do płci pięknej.,%o chegou perto demais do sexo oposto.,,%o s-a apropriat prea mult de sexul opus.,Игрок %o почти сблизился с противоположным полом.,,%o kom lite väl nära det motsatta könet.,%o karşı cinsle biraz yakınlaştı. +%o said goodbye to an old friend.,OB_REPLI,,,,%o řekl@[ao_cs] sbohem starému příteli.,%o sagde farvel til en gammel ven.,%o verabschiedete sich von einem alten Freund.,,"%o diris ""Ĝis la revido"" al malnova amiko.",%o se despidió de un viejo amigo.,,%o sanoi hyvästit vanhalle ystävälle.,%o dit au revoir à un vieil ami.,%o búcsút intett egy régi barátjának.,%o ha detto addio a un vecchio amico.,%o は古い友人に別れを告げた。,%o 은(는) 오랜 친구와 작별인사를 했다.,%o nam afscheid van een oude vriendin.,%o tok farvel med en gammel venn.,%o pożegnał@[ao_pl] się ze starym znajomym.,%o disse adeus a um velho amigo.,,%o a spus adio unui vechi prieten.,Игрок %o распрощался со старым другом.,,%o tog farväl av en gammal vän.,%o eski bir arkadaşına veda etti. +%o was stabbed in the back by an old friend.,OB_REPLIHIT,,,,%o byl@[ao_cs] bodnuta do zad starým přítelem.,%o blev stukket i ryggen af en gammel ven.,%o wurde von einem alten Freund in den Rücken gestochen.,,%o estis pikita en la dorson de malnova amiko.,%o fue apuñalad@[ao_esp] en la espalda por un viejo amigo.,,%o joutui vanhan ystävän selkäänpuukottamaksi.,%o s'est fait@[e_fr] planter une lame dans le dos par un vieil ami.,%o-t hátba szúrta egy régi barát.,%o è stato pugnalato alla schiena da un vecchio amico.,%o は古い友人に背中を刺された。,%o 은(는) 오랜 친구에게 배신을 당했다.,%o werd in de rug gestoken door een oude vriend.,%o ble dolket i ryggen av en gammel venn.,%o został@[ao_pl] dźgnięt@[adj_pl] w plecy przez starego znajomego.,%o foi apunhalad@[ao_ptb] pelas costas por um velho amigo.,,%o a fost înjunghiat pe la spate de către un vechi prieten.,Игрок %o получил нож в спину от старого друга.,,%o blev knivhuggen i ryggen av en gammal vän.,%o eski bir arkadaşı tarafından sırtından bıçaklandı. +%o was weeded out by natural selection.,OB_PHAGE,,,,%o byl@[ao_cs] vyčištěna přirozeným výběrem.,%o blev sorteret fra ved naturlig udvælgelse.,%o fiel der natürlichen Auslese zum Opfer.,,%o estis foriga de natura elektado.,%o fue eliminad@[ao_esp] por selección natural.,,%o joutui luonnonvalinnan kitkemäksi.,%o a été éliminé@[e_fr] par la sélection naturelle.,A természetes kiválasztás áldozata lett %o.,%o cadde vittima della selezione naturale.,%o は自然淘汰によって除草された。,%o 은(는) 약육강식을 지금까진 모르고 있었다.,%o werd door natuurlijke selectie weggehaald.,%o ble luket ut av naturlig seleksjon.,%o został@[ao_pl] przesian@[adj_pl] przez naturalną selekcję.,%o foi eliminad@[ao_ptb] por seleção natural.,,%o a fost eliminat prin selecție naturală.,Игрок %o был отсеян естественным отбором.,,%o blev utsorterad av det naturliga urvalet.,%o doğal seleksiyon tarafından ayıklandı. +%o couldn't escape a thorny death.,OB_THORN,,,,%o nemohl@[ao_cs] utéct bodlavé smrti.,%o kunne ikke undslippe en tornedød.,%o konnte einem dornigen Tod nicht entkommen.,,%o ne povis eskapi dornan morton.,%o no pudo escapar una muerte espinosa.,,%o ei kyennyt välttämään piikikästä kuolemaa.,%o n'a pu éviter une mort piquante.,Lyukasra szúrták %o-t a tövisek.,%o non poteva sfuggire a una morte spinosa.,%o は棘のある死から逃げられなかった。,%o 은(는) 따가운 죽음을 피할 수 없었다.,%o kon niet ontsnappen aan een netelige dood.,%o kunne ikke unnslippe en tornefull død.,%o nie m@[irreg_4_pl] uciec przed cierniową śmiercią.,%o não conseguiu escapar de uma morte espinhosa.,,%o nu a putut scăpa de o moarte spinoasă.,Игрока %o поджидала смерть на его тернистом пути.,,%o kunde inte undgå en taggig död.,%o dikenli bir ölümden kaçamadı. +%o took a sumo punch to the groin.,OB_SUMATIC,,,,%o dostal@[ao_cs] sumo ránu pod pás.,%o fik et sumo-slag i lysken.,%o bekam einen Sumo-Schlag an @[pp_de] empfindlichste Stelle.,,%o prenis sumoan baton en la ingveno.,%o recibió un puñetazo de sumo en la entrepierna.,,%o otti vastaan sumoiskun nivusiin.,%o s'est pris le poing d'un sumo dans l'entrejambe.,%o szerszámjával tompította az jobb horgot.,%o ha ricevuto un soffio su un punto sensibile.,%o は股座にスモウ ハリテを食らった。,%o 은(는) 가랑이 사이에 정권을 찔렀다.,%o nam een sumo punch in de lies.,%o fikk et sumoslag i skrittet.,%o dostał@[ao_pl] cios sumo w pachwinę.,%o tomou um golpe de sumô na virilha.,,%o a primit un pumn sumo în vintre.,Игрок %o отхватил удар в пах от сумоиста.,,%o tog emot ett sumoslag i ljumsken.,%o kasıklarına bir sumo yumruğu yedi. +%o didn't get %p three wishes.,OB_GENIE,,,,%o nedostal@[ao_cs] svá tři přání.,%o fik ikke sine tre ønsker.,%o bekam @[pp_de] drei Wünsche nicht erfüllt.,,%o ne ricevis siajn tri petojn.,%o no recibió sus tres deseos.,,%o ei saanut kolmea toivettaan.,%o n'a pas préparé ses trois vœux.,%o nem teljesítette %p 3 kívánságát.,%o non ha soddisfatto i suoi tre desideri.,%o は %p に三願を望まなかった。,%o 은(는) 세 가지 소원을 빌 수 없었다.,%o kreeg niet drie wensen.,%o fikk ikke oppfylt tre ønsker.,%o nie dostał@[ao_pl] swoich trzech życzeń.,%o não concedeu três desejos a %p.,,%o nu a putut să-și pună cele trei dorințe.,Игрок %o не загадает трёх желаний.,,%o fick inte sina tre önskningar uppfyllda.,%o üç dileğini yerine getiremedi. +%o tried to pet a mine.,OB_MINE,,,,%o se pokusil@[ao_cs] pohladit minu.,%o forsøgte at kæle for en mine.,"%o versuchte, eine Mine zu streicheln.",,%o provis glatumi minon.,%o intentó acariciar una mina.,,%o yritti silittää miinaa.,%o a essayé de caresser une mine.,%o meg akart simogatni egy aranyos aknát.,%o ha provato ad accarezzare una mina.,%o は地雷を愛撫しようとした。,%o 은(는) 기뢰와 친구가 되고 싶었다.,%o probeerde een mijn te aaien.,%o prøvde å klappe en mine.,%o próbował@[ao_pl] pogłaskać minę.,%o tentou fazer carinho numa mina.,,%o a încercat să mângâie o mină.,Игрок %o хотел погладить мину.,,%o försökte klappa en mina.,%o bir mayını sevmeye çalıştı. +%o took %k's Bruce Lee fu-kick to the face.,OB_MPKICK,,,,%o dostal@[ao_cs] kopanec do obličeje od kung-fuistou %k.,%o fik %ks Bruce Lee fu-kick i ansigtet.,%o bekam einen Bruce-Lee-Fußtritt ins Gesicht.,,%o ricevis la Bruce Lee piedbaton de %k en sia vizaĝo.,%o se comió una patada de kung-fu a lo Bruce Lee de %k.,,%k potkaisi %o raukkaa päin naamaa Bruce Leen kung fu-tyyliin.,%o s'est mangé@[e_fr] un coup de pied à la Bruce Lee de la part de %k.,%o arccal vette le %k pörgőrugását.,%o ha un calcio in faccia.,%o の顔に %k のブルースリーキックを当てた。,%o 은(는) %k 의 거침없는 하이킥을 받았다.,%o nam %k's Bruce Lee fu-kick in het gezicht.,%o tok %ks Bruce Lee fu-kick i ansiktet.,%o dostał@[ao_pl] kopniakiem w stylu Bruce'a Lee od %k.,%o tomou uma voadora de %k na cara.,,%o a primit un șut în stil Bruce Lee.,"Игрок %o отхватил от игрока %k удар в лицо, достойный Брюса Ли.",,%o tog emot %ks Bruce Lee fu-kick i ansiktet.,"%o, %k tarafından tekmelendi." +%o fell apart via %k's shocking revelation.,OB_MPREZNATOR,,,,%o se rozpadl@[ao_cs] šokujícím odhalením hráče %k.,%o faldt fra hinanden via %ks chokerende åbenbaring.,%o erhielt eine schockierende Enthüllung von %k.,,%o diseriĝis pro la ŝokantan revelaĉio de %k.,%o cayó ante la revelación chocante de %k.,,%o romahti käyttäjän %k sähköistävästä ilmestyksestä.,%o a été témoin de la révélation choquante de %k.,%k megrázó élmányben részesítette %o-t.,%o ricevette una scioccante rivelazione da %k.,%o は %k の衝撃的な啓示によりバラバラになった。,%o 은(는) %k 이(가) 선사한 전기 찜질을 맛봤다.,%o viel uit elkaar via %k's schokkende onthulling.,%o falt fra hverandre via %ks sjokkerende åpenbaring.,%o rozpadł@[ao_pl] się pod wpływem szokującego objawienia %k.,%o ficou arrasad@[ao_ptb] pela revelação chocante de %p.,,%o s-a făcut praf la revelația șocantă a lui %k.,Игрок %o шокирован откровениями %k.,,%o föll sönder genom %ks chockerande avslöjande.,"%o, %k tarafından kızartıldı." +%o took a double-dose of %k's punishment.,OB_MPXPISTOL,,,,%o dostal@[ao_cs] dvojitou dávku potrestání hráče %k.,%o fik en dobbeltdosis af %ks straf.,%o bekam eine doppelte Dosis von %ks Bestrafung.,,%o duoble dozis la puno de %k.,%o recibió una doble dosis del castigo de %k.,,%o otti tupla-annoksen käyttäjän %k kuritusta.,%o a mangé une double dose de la furie de %k.,%o ólom túladagolást kapott %k-tól.,%o ha ottenuto una doppia dose della punizione di %k.,%o は %k の懲罰を二度受けた。,%o 은(는) %k 의 2총신 사격을 받았다.,%o nam een dubbele dosis van %k's straf.,%o tok en dobbel dose av %ks straff.,%o dostał@[ao_pl] podwójną dawkę kary %k.,%o tomou uma dose dupla da punição de %k.,,%o a luat o doză dublă din pedeapsa lui %k.,Игрок %o принял двойную дозу возмездия от %k.,,%o fick en dubbel dos av %ks straff.,"%o, %k tarafından cezalandırıldı." +%o was shut down by %k's shock-stick.,OB_MPTAZER,,,,%o byl@[ao_cs] vypnut@[ao_cs] šokádou hráče %k.,%o blev lukket ned af %ks chok-stick.,%o wurde von %ks Schockstab ausgeschaltet.,,%o estis malŝaltita de la ŝokbateno de %k.,%o fue noquead@[ao_esp] por la vara eléctrica de %k.,,%o joutui käyttäjän %k sähkökepin sammuttamaksi.,%o s'est fait mettre K.O par le bâton électrique de %k.,"%o-t sokkolta a hír, hogy %k-t megölte.",%o è stato spento dalla bacchetta di %k.,%o は %k のショックスティックでシャットダウンした。,%o 은(는) %k 의 무력행사에 아예 포기했다.,%o werd uitgeschakeld door %k's schokstick.,%o ble stengt av %ks sjokkpinne.,%o został@[ao_pl] wyłączon@[adj_pl] przez szokującą pałkę %k.,%o foi desligado pelo espeto chocante de %k.,,%o a fost dezactivat de arma cu șocuri a lui %k.,Игрок %o выведен из строя электродубинкой %k.,,%o blev nedsläckt av %ks chockpinne.,"%o, %k tarafından kapatıldı." +%o got a face-full of %k's ice-cold wrath.,OB_MPCRYOGUN,,,,%o se zabořil@[ao_cs] do mrazivého hněvu hráče %k.,%o fik et ansigt fuld af %ks iskolde vrede.,%o bekam eine Ladung von %ks eiskaltem Zorn ins Gesicht.,,%o ricevis la glacie malvarman koleregon de %k.,%o recibió la ira gélida de %k en toda la cara.,,%o sai saamansa täyteen käyttäjän %k jääkylmää vihaa.,%o s'est fait congeler la figure par la colère glaciale de %k.,%k jégre tette %o-t,%o ha un carico di freddo gelido di %k in faccia.,%o は %k の冷めた表情で凍った。,%o 은(는) %k 덕분에 맛있게 냉동 보존되었다.,%o kreeg een gezicht vol met %k's ijskoude toorn.,%o fikk ansiktet fullt av %ks iskalde vrede.,%o dostał@[ao_pl] wielką dawkę mroźnego gniewu %k.,%o tomou um gelo de %k. ,,%o a simțit din plin furia rece a lui %k.,Игрок %o столкнулся с ледяной ненавистью %k.,,%o fick en ansiktsfyllning av %ks iskalla vrede.,"%o, %k tarafından donduruldu." +"%o was drilled full of holes by %k, gangsta-style.",OB_MPUZI,,,,%o byl@[ao_cs] prostřílen@[ao_cs] skrz na skrz gangsterem %k.,"%o blev boret fuld af huller af %k, på gangsta-stil.",%o wurde von %k im Gangsta-Stil perforiert.,,"%o estis borita truplena de %k, ganstere.","%o fue acribillad@[ao_esp] por %k, al estilo gangster.",,%k porasi %o raukan täyteen reikiä gangsta-tyyliin.,"%o s'est fait perforer dans tous les sens par %k, Gangsta style.",%o gengszter stílusban sajttá lyuggatta %k,%o è stato perforato da %k in stile gangsta.,%o はギャングの様な %k に蜂の巣にされた。,%o 은(는) %k 이(가) 선사한 갱스터 스타일 난사를 막지 못했다.,"%o werd vol gaten geboord met %k, in gangsta-stijl.","%o ble boret full av hull av %k, i gangsta-stil.",%o został@[ao_pl] podziurawion@[adj_pl] przez %k niczym gangster.,%o tomou pipoco de %k.,,%o a fost umplut de găuri în stil mafiot de către %k.,Игрок %o покрылся дырками после гангста-стрельбы игрока %k.,,"%o borrades full av hål av %k, på gangstermanér.","%o, %k tarafından gangsta tarzı delik deşik edildi." +%o ate %k's photon bomb.,OB_MPZOOKA,,,,%o sežral@[ao_cs] fotonovou bombu hráče %k.,%o spiste %ks fotobombe.,%o nahm %ks Photonenbombe.,,%o manĝis la fotonbombon de %k.,%o se comió la bomba de fotones de %k.,,%o söi käyttäjän %k fotonipommin.,%o a bouffé la bombe photonique de %k.,%o megette %k foton bombáját,%o ha preso la bomba fotonica di %k.,%o は %k のフォトンボムを食らった。,%o 은(는) %k 의 광자탄을 봤는데도 피하지 못했다.,%o at %o %k's fotonbom.,%o spiste %ks fotonbombe.,%o zjadł@[ao_pl] fotonową bombę %k.,%o engoliu a bomba de fótons de %k.,,%o a mâncat bomba fotonică a lui %k.,Игрок %o съел фотонную бомбу %k.,,%o åt upp %ks fotobomb.,"%o, %k tarafından atomize edildi." +%o was reduced to a neat pile of photons by %k.,OB_MPZ_SPLASH,,,,%o byl@[ao_cs] zredukován@[ao_cs] na hromádku fotonů hráčem %k.,%o blev reduceret til en ordentlig bunke fotoner af %k.,%o wurde von %k zu einem Haufen Photonen verarbeitet.,,%o estis reduktita en ordeman amason da fotonoj de %k.,%o fue reducid@[ao_esp] a una pila de fotones por %k.,,%k redusoi %o raukan sieväksi fotonipinoksi.,%o s'est fait@[e_fr] réduire en une jolie pile de photons par %k.,%o-ból csak egy marokni fotont hagyott hátra %k,%o è stato elaborato da %k in un mucchio di fotoni.,%o は %k によって蛍光灯にされた。,%o 은(는) %k 의 광자력을 탐냈다. 죽기 전까지는.,%o werd gereduceerd tot een nette stapel fotonen met %k.,%o ble redusert til en pen haug med fotoner av %k.,%o został@[ao_pl] zredukowan@[adj_pl] do maleńkiej kupki fotonów przez %k.,%o foi reduzido à uma bela pilha de fótons por %k.,,%o a fost transformat într-o grămadă simpatică de fotoni de către %k.,Игрок %o был разложен игроком %k в аккуратную кучку фотонов.,,%o reducerades till en prydlig hög fotoner av %k.,"%o, %k tarafından düzgün bir foton yığınına indirgendi." +%o was reduced to antimatter by %k.,OB_MPANTIGUN,"Physically this is utter nonsense, of course.",,,%o byl@[ao_cs] zredukován@[ao_cs] na antihmotu hráčem %k.,%o blev reduceret til antimaterie af %k.,%o wurde von %k zu Antimaterie reduziert.,,%o estis reduktita en antimaterion de %k.,%o fue reducid@[ao_esp] a antimateria por %k.,,%k redusoi %o raukan antimateriaksi..,%o s'est fait inverser les atomes par %k.,%k antianyaggá lőttte %o-t,%o è stato ridotto all'antimateria da %k,%o は %k のにより反物質に変換された。,%o 은(는) %k 의 반물질의 힘에 의해 소멸되었다.,%o werd gereduceerd tot antimaterie met %k.,%o ble redusert til antimaterie av %k.,%o został@[ao_pl] zredukowan@[adj_pl] do antymaterii przez %k.,%o foi transformado em antimatéria por %k.,,%o a fost transformat în antimaterie de către %k.,Игрок %o был разложен игроком %k до антиматерии.,,%o reducerades till antimateria av %k.,"%o, %k tarafından atomlara indirgendi." +%o swallowed %k's nuke.,OB_MPNUKE,,,,%o spolkl@[ao_cs] atomovku hráče %k.,%o slugte %ks atombombe.,%o verschluckte sich an %ks Atomrakete.,,%o glutis la nuklean bombon de %k.,%o se tragó la bomba atómica de %k.,,%o nieli käyttäjän %k ydinpommin.,%o s'est pris@[e_fr] la bombe thermonucléaire de %k dans la figure.,%o megette %k atombomáját,%o soffocò sul missile nucleare di %k.,%o は %k の核を飲み干した。,%o 은(는) %k 덕분에 하늘을 뚫을 버섯구름이 되었다.,%o geslikt %o nuke %k's nuke.,%o svelget %ks atombombe.,%o połkn@[irreg_2_pl] atomówkę %k.,%o engoliu o míssil núclear de %k.,,%o a înghițit proiectilul lui %k.,Игрок %o проглотил ядерный заряд %k.,,%o svalde %ks atombomb.,"%o, %k tarafından bombalandı." +%o went nuclear from %k's mass destruction spree.,OB_MPNUKESPLASH,,,,%o si zkrátil@[ao_cs] svůj poločas rozpadu při zabijačce hráče %k.,%o blev atomvåben af %ks masseødelæggelser.,%o wurde von %ks Massenzerstörungsaktion verstrahlt.,,%o iĝis nuklea pro la amasdetruado de %k.,%o se volvió radioactiv@[ao_esp] por la racha de destrucción masiva de %k.,,%o muuttui radioaktiiviseksi käyttäjän %k massatuhoputken takia.,%o s'est fait@[e_fr] irradier par la folie destructrice de %k.,%o felrobbant az idegtől amikor meglátta %k bombáját,%o fu irradiato dall'azione di distruzione di massa di %k.,%o は %k の虐殺ごっこの犠牲者になった。,%o 은(는) %k 의 핵실험에 참여했다.,%o werd nucleair van de massavernietigingswoede van %k's massavernietigingswoede.,%o ble nuklear av %ks masseødeleggelse.,%o został@[ao_pl] napromieniowan@[adj_pl] przez masową destrukcję %k.,%o virou picadinho radioativo por causa da destruição em massa causada por %k.,,%o a devenit radioactiv în urma distrugerii în masă a lui %k.,Игрок %o светится в темноте от оружия массового поражения %k.,,%o blev kärnvapenfri av %ks massförstörelse.,"%o, %k tarafından bombalandı." +%o was turned inside-out by %k.,OB_MPTELEFRAG,,,,%o byl@[ao_cs] obrácen@[ao_cs] naruby hráčem %k.,%o blev vendt ud og ind af %k.,%o wurde von %k zerfetzt.,,La interno de %o estis eksteriga de %k.,%o fue puest@[ao_esp] del revés por %k.,,%k käänsi %o raukan nurinpäin.,%o s'est fait@[e_fr] inverser par %k.,%k kifordította %o-t,%o fu fatto a pezzi da %k,%o は %k に裏返しにされた。,%o 은(는) %k 에 의해 자신이 분해되는 꼴을 못 봤다.,%o werd binnenstebuiten gekeerd met %k.,%o ble snudd på hodet av %k.,%o został@[ao_pl] wywrócon@[adj_pl] na lewą stronę przez %k.,%o foi virad@[ao_ptb] ao avesso por %k.,,%o a fost întors pe dos de către %k.,Игрок %o вывернут наизнанку игроком %k.,,%o vändes ut och in av %k.,"%o, %k tarafından parçalandı." +%o's atomic structure was split apart.,OB_MONTELEFRAG,,,,Struktura atomů hráče %o se rozpadla.,%os atomstruktur blev splittet op.,%os Atomstruktur wurde vernichtet.,,La atoma strukturo de %o estis disfendita.,%o fue desintegrad@[ao_esp] al nivel atómico.,,%o raukan atomirakenne hajosi.,%o s'est fait@[e_fr] désassembler au niveau atomique.,%o atomjaira esett szét,La struttura atomica di %o fu distrutta.,%o の原子構造は分解された。,%o 의 원자 마디마디가 흩어졌다.,De atoomstructuur van %o werd gesplitst.,%o's atomstruktur ble splittet fra hverandre.,Atomy %o zostały od siebie oddzielone.,A estrutura atômica de %o foi separada.,,Structura atomică a lui %o a fost spulberată.,Атомная структура игрока %o разрушена.,,%os atomstruktur splittrades.,%o atomik düzeyde parçalara ayrıldı. +%o spontaneously expired.,OB_DEFAULT,,,,%o samovolně vypršel@[ao_cs].,%o udåndede spontant.,%o hörte spontan auf zu existieren.,,%o spontane finiĝis.,%o tuvo una muerte espontánea.,,%o spontaanisti kupsahti.,%o a spontanément expiré.,%o hirtelenjében elérte a lejárati időt,%o ha smesso spontaneamente di esistere.,%o の有効期限が自発的に切れた,%o 은(는) 파란만장하게 사라졌다.,%o is spontaan verlopen.,%o gikk spontant til grunne.,%o spontanicznie umarł@[ao_pl].,%o pereceu expontâneamente.,,%o a expirat în mod spontan.,Время игрока %o неожиданно вышло.,,%o dog spontant.,%o kendiliğinden öldü. +You grab a NUKER! Suck on this!,GOTNUKER,,,,Sebral@[ao_cs] jsi ATOMOVKÁTOR! Pojď na to!,Du tager en NUKER! Sut på den!,Ein NUKER! Verschluck dich daran.,,Vi prenis NUKER! Jen havu!,¡Has pillado un NUKER! ¡Chupaos esa!,¡Has recogido un NUKER! ¡Chúpate esa!,%Kahmaiset YDÄRIN! Ime tätä!,Vous découvrez le NUKER! Ca va en chier!,Meglelted a NUKER-t! Ezt kapd ki!,Prendi un NUKER! Succhia su questo!,NUEKR を奪った! 覚悟しろ!,누커 획득! 한바탕 쓸어볼까!,Je pakt een NUKER! Zuig hier maar aan!,Ta en NUKER! Sug på denne!,Podniosłeś ATOMÓWKĘ! Ssijcie to!,Você pegou um NUKER! Chupa essa manga!,,Ai ridicat Lansatorul Nuclear! Ia de-aici!,Заполучен ЯДЕРНЫЙ ГРАНАТОМЁТ! Отсосите!,,Du tar en NUKER! Sug på den här!,Sen bir NÜKER kap! Bunu em! +You got an UZI!!,GOTUZI,,,,Získal@[ao_cs] jsi UZI!,Du har en UZI!!,UZI genommen!,,Vi prenis UZI!!,¡¡Has obtenido una UZI!!,,Sait UZIn!!,Vous chopez un UZI!,Meglelted az UZI-t!,Hai un UZI !!,UZI をゲットした!!,우지 기관단총 획득!,Je hebt een UZI!!,Du har en UZI!,Zdobyłeś UZI!!,Você pegou uma UZI!!,,Ai ridicat un UZI!!,Заполучен УЗИ!!,,Du har en UZI!!,Bir UZI'n var! +A HOIG Reznator - FRY some butt,GOTREZNATOR,,,,HOIG Reznátor - pár jich upeč,En HOIG Reznator - Fritér noget røv,Ein HOIG Reznator.,,HOIG-Reznilo - FRITU pugon!,Un Reznator HOIG. ¡Hora de freir traseros!,,HOIG-reznaattori - KÄRISTÄ takamuksia,"Un Reznator HOIG, allez frire du monde!",Egy HOIG Reznator - okozz pár megrázó élményt,Un Reignator HOIG - friggere un po 'di carne,HOIGレジネイター - ぶっ潰してやれ,HOIG 전자무력기 획득! 전기 통구이를 만들자고!,Een HOIG Reznator - FRY sommige kont,En HOIG Reznator - FRY litt rumpe!,Reznator HOIG - skop trochę tyłków,Um Reznador HOIG - Hora de fritar,,Un Rezonator HOIG - Arde-i!,ХОЙГ Резнатор,,En HOIG Reznator - FRY några rumpor,Bir HOIG Reznator - Biraz kıç kızartın +You got a Photon 'Zooka!,GOTPHOTONZOOKA,,,,Sebral@[ao_cs] jsi Fotonovou bazuku!,Du har en Photon 'Zooka!,Photonen-'zooka genommen!,,Vi prenis Fotonbazukon!,¡Has obtenido un Bazooka de Fotones!,,Sait fotonisingon!,Vous récupérez un Bazooka Photonique!,Meglelted a Foton Ágyút!,Hai un cannone Photon!,フォトン'ゾーカ をゲットした!,광자 바주카 획득!,Je hebt een Photon 'Zooka!,Du har en Photon 'Zooka!,Zdobyłeś Fotonozukę!,Você pegou uma Bazuca de Fótons!,,Ai ridicat o Bazooka Fotonică!,Заполучена фотон-базука!,,Du har en Photon 'Zooka'!,Bir Foton 'Zooka'n var! +You carry a Big Stick!,GOTBIGSTICK,,,,Nosíš velkou bouchačku!,Du har en Big Stick!,Du trägst einen langen Stock.,,Vi portas grandan bastonon!,¡Llevas un Gran Palo!,,Kannat isoa keppiä!,Vous avez un gros bâton!,Nagy bottal jársz öcsém!,Porti un grosso bastone!,ビッグスティック を手に取った!,반물질 봉 획득!,Je draagt een Big Stick!,Du har en Big Stick!,Podnosisz Wielką Pałkę!,Você pegou um Grande Bastão!,,Ai ridicat un Băț Lung!,Заполучена длинная палка!,,Du har en stor käpp!,Büyük bir sopa taşıyorsun! +You got a Tazer!!,GOTTAZER,,,,Získal@[ao_cs] jsi tazer!,Du har en Tazer!!,Tazer genommen!,,Vi prenis Elektropafilon!!,¡¡Has obtenido un Taser!!,,Sait etälamauttimen!!,Vous trouvez un Taser!,Meglelted a Sokkolót!,Hai un Taser !!,テイザー をゲットした!,테이져 획득!,Je hebt een Tazer!!,Du har en Tazer!,Zdobyłeś Tazer!!,Você pegou um Tazer!!,,Ai ridicat un Taser!!,Заполучен тазер!,,Du har en Tazer!,Bir Tazer'ın var!! +You grab a Cryogun! FREEZE!,GOTCRYOGUN,,,,Sebral@[ao_cs] jsi krypušku! ANI SE NEHNI!,Du har en Cryogun! Frys!,Cryowaffe genommen! GEFRIER!,,Vi prenis Kriogenikpafilon! FROSTIĜU!,¡Has pillado un Criogenizador!! ¡Todos quietos!,¡Has recogido un Criogenizador!! ¡Quietos todos!,Kahmaiset kryopyssyn! PYSÄHDY!,Vous prenez un Cryogun! On s'arrête!,Felkapod a Cryogun-t! Induljon a fagyasztás!,Prendi un Cryogun! CONGELARE!,クライォガン を奪った! フリーズ!,크라이로건 획득! 그대로 멈춰라!,Je pakt een Cryogun! FREEZE!,Du har en Cryogun! FREEZE!,Podniosłeś Zamrażarkę! STAĆ!,Você pegou uma Cryogun! FICA FRIO AÍ!,,Ai ridicat o Crio-armă! ÎNGHEAȚĂ!,Заполучена замораживающая пушка! НИ С МЕСТА!,,Du har en Cryogun! FRIAS!,Bir Cryogun al! DONDUR! +You grab some rounds!,GOTROUNDS,,,,Sebral@[ao_cs] jsi nějaké náboje!,Du tager nogle patroner!,Munition genommen.,,Vi prenis kuglojn!,¡Has pillado unas balas!,¡Has recogido unas balas!,Kahmaiset patruunoita!,Vous prenez des balles!,Felkapsz pár lőszert!,Prendi delle munizioni!,幾つかのラウンド を奪った!,권총 탄약을 주웠다!,Je pakt wat rondes!,Du tar noen runder!,Podniosłeś trochę naboi!,Você pegou munição!,,Ai ridicat niște muniție!,Заполучена обойма патронов!,,Du tar några patroner!,Biraz mermi al! +You grab a case of rounds!,GOTROUNDSCASE,,,,Sebral@[ao_cs] jsi krabici nábojů!,Du tager en kasse med patroner!,Munitionskiste genommen.,,Vi prenis skatolon da kugloj!,¡Has pillado una caja de balas!,¡Has recogido una caja de balas!,Kahmaiset patruunalaatikon!,Vous prenez une bôite de balles!,Felkapsz egy doboz lőszert!,Prendi un caso di munizioni!,ケースのラウンド を奪った!,권총 탄약 상자를 주웠다!,Je pakt een kist met rondes!,Du tar en kasse med patroner!,Podniosłeś skrzynkę naboi!,Você pegou uma caixa de munição!,,Ai ridicat un cartuș de muniție!,Заполучена коробка патронов!,,Du tar en låda med patroner!,Bir kutu mermi al! +You grab a Torpedo!,GOTTORPEDO,"Was ""grap"" for some reason.",,,Sebral@[ao_cs] jsi torpédo!,Du tager en Torpedo!,Torpedo genommen.,,Vi prenis Torpedon!,¡Has pillado un torpedo!,¡Has recogido un torpedo!,Kahmaiset torpedon!,Vous prenez une torpille!,Felkapsz egy Torpedót!,Prendi un siluro!,トルペード を奪った!,광자탄을 주웠다!,Je pakt een Torpedo!,Du tar en Torpedo!,Podniosłeś Torpedę!,Você pegou um Torpedo!,,Ai ridicat o Torpilă!,Заполучена торпеда!,,Du tar en torped!,Bir Torpido al! +You grab a case of Torpedos!,GOTTORPEDOS,,,,Sebral@[ao_cs] jsi krabici torpéd!,Du tager en kasse med torpedoer!,Torpedokiste genommen.,,Vi prenis skatolon da Torpedoj!,¡Has pillado una caja de torpedos!,¡Has recogido una caja de torpedos!,Kahmaiset torpedolaatikon!,Vous prenez une bôite de torpilles!,Felkapsz egy doboz Torpedót!,Prendi un caso di siluri!,トルペードのケース を奪った!,광자탄 무더기를 주웠다!,Je pakt een kist Torpedo's!,Du tar en kasse med torpedoer!,Podniosłeś skrzynkę Torped!,Você pegou uma caixa de Torpedos!,,Ai ridicat o cutie de Torpile!,Заполучен ящик торпед!,,Du tar en låda med torpeder!,Bir kasa Torpido al! +You grab a molecule module!,GOTMOLECULES,,,,Sebral@[ao_cs] jsi molekulový modul!,Du tager et molekylmodul!,Molekülmodul genommen,,Vi prenis molekulmodulon!,¡Has pillado un módulo molecular!,¡Has recogido un módulo molecular!,Kahmaiset molekyylimoduulin!,Vous prenez un module moléculaire!,Felkapsz egy molekula modult!,Prendi un modulo molecolare!,モーレキュールモヂュール を奪った!,분자 모듈을 주웠다!,Je pakt een molecuulmodule!,Du tar en molekylmodul!,Podniosłeś molekularny moduł!,Você pegou um módulo molecular!,,Ai ridicat un modul molecular!,Заполучен молекулярный модуль!,,Du tar en molekylmodul!,Bir molekül modülü kap! +You grab a tank full of molecules!,GOTMOLECULESTANK,,,,Sebral@[ao_cs] jsi sud plný molekul!,Du tager en tank fuld af molekyler!,Tank mit Molekülmodulen genommen.,,Vi prenis reservujon da molekulojn!,¡Has pillado un tanque lleno de moléculas!,¡Has recogido un tanque lleno de moléculas!,Kahmaiset tankin täynnä molekyylejä!,Vous prenez un réservoir de molécules!,Felkapsz egy teli tank molekulát!,Prendi un serbatoio pieno di molecole!,タンク満タンのモーレキュール を奪った!,분자 탱크를 주웠다!,Je pakt een tank vol met moleculen!,Du tar en tank full av molekyler!,Podniosłeś zbiornik pełen molekuł!,Você pegou um tanque cheio de moléculas!,,Ai ridicat un rezervor plin cu molecule!,Заполучен контейнер с молекулами!,,Du tar en tank full av molekyler!,Moleküllerle dolu bir tank al! +You grab some Cartridges!,GOTCARTRIDGES,,,,Sebral@[ao_cs] jsi nějaké kazety!,Du tager nogle patroner!,Magazin genommen.,,Vi prenis iom da kartoĉoj!,¡Has pillado unos cartuchos!,¡Has recogido unos cartuchos!,Kahmaiset kasetteja!,Vous prenez des cartouches!,Felkapsz pár Töltényt!,Prendi alcune cartucce!,残弾のカートリッジ を奪った!,카트리지 한 줌을 주웠다!,Je pakt een paar patronen!,Du tar noen patroner!,Podniosłeś trochę pocisków!,Você pegou alguns Carregadores!,,Ai ridicat niște Cartușe!,Заполучены картриджи!,,Du tar några patroner!,Fişekleri al! +You grab a case of Cartridges!,GOTCARTRIDGESCASE,,,,Sebral@[ao_cs] jsi krabici kazet!,Du tager en kasse med patroner!,Magazinkiste genommen.,,Vi prenis skatolon da kartoĉoj!,¡Has pillado una caja de cartuchos!,¡Has recogido una caja de cartuchos!,Kahmaiset laatikollisen kasetteja!,Vous prenez une bôite de cartouches!,Felkapsz egy doboz Töltényt!,Prendi un caso di cartucce!,カートリッジケース を奪った!,카트리지 박스를 주웠다!,Je pakt een kist patronen!,Du tar en kasse med patroner!,Podniosłeś skrzynkę pocisków!,Você pegou uma caixa de Carregadores!,,Ai ridicat o cutie de Cartușe!,Заполучен ящик картриджей!,,Du tar en låda med patroner!,Bir kutu fişek al! +You grab a Valise stuffed with goods!,GOTVALISE,,,,Sebral@[ao_cs] jsi kufr plný munice!,Du tager en kuffert fyldt med varer!,Munitionstasche genommen.,,Vi prenis valizon plenan de municiojn!,¡Has pillado una maleta llena de equipamiento!,¡Has recogido una maleta llena de equipamiento!,Kahmaiset laukullisen täynnä tavaraa!,Vous récupérez une valise pleine d'équipement!,Felkapsz egy Poggyásznyi Muníciót!,Prendi una Valigia piena di merci!,代物を詰めたバリス を奪った!,탄약이 든 서류 가방을 주웠다!,Je pakt een Valise gevuld met goederen!,Du tar en koffert fylt med varer!,Podniosłeś Walizkę z wieloma dobrami!,Você pegou uma Mala cheia de equipamento!,,Ai ridicat o Valiză plină cu bunătăți!,Заполучена полная сумка боеприпасов!,,Du tar en valise fylld med varor!,İçi mal dolu bir valiz al! +Force Field!,GOTFORCEFIELD,,,,Silové pole!,Kraftfelt!,Kraftfeld!,,Fortkampo!,¡Campo de fuerza!,,Voimakenttä!,Champ de force!,Erőtér!,Campo di forza!,フォースフィールド!,방어막!,Krachtveld!,Kraftfelt!,Pole Siłowe!,Campo de Força!,,Câmp de Forță!,Силовое поле!,,Kraftfält!,Güç Alanı! +007Microtel,GOTMICROTEL,,,,,,,,007 Microtel!,Microtel 007,,,007 Microtel,,,007マイクロテル,007마이크로텔 근력 향상 칩!,,,,,,Microtel 007,Микрочип 007,,,007Microtel +You are EnK Blind!,GOTENKBLIND,,,,Jsi EnK-slep@[adj_cs]!,Du er EnK Blind!,Du bist EnK-blind!,,Vi estas ENK-Blinda,¡Tienes Ceguera EnK!,,Olet EnK-sokea!,Vous êtes aveugle à l'EnK!,EnK védett lettél!,Sei EnK-cieco!,EnKブラインドみてえだ!,EnK 투명 위장 장치!,Jij bent EnK Blind!,Du er EnK Blind!,Jesteś oślepiony przez EnK!,Você está vendado por EnK!,,Acum ești nedetectabil pentru Enk!,У тебя EnK-видимость!,,Du är EnK Blind!,Sen EnK Blind'sın! +Vulcan rubber Boots!,GOTRUBBERBOOTS,,,,Gumové boty!,Vulkaniske gummistøvler!,Gummistiefel!,,Vulkanaj Kauŭĉukaj Botoj!,¡Botas de goma vulcanizada!,,Vulkanoidut kumisaappaat!,Bottes en caoutchouc vulcanisé!,Vulkanizált gumi talp!,Stivali di gomma vulcanica!,バルカンラバーブーツ!,벌컨 방화 부츠!,Vulcan rubber Laarzen!,Vulcan gummistøvler!,Gumowe Buty Vulcan!,Botas Vulcanizadas!,,Bocanci din cauciuc Vulcan!,Резиновые сапоги!,,Vulkaniska gummistövlar!,Vulcan lastik botları! +SI Array mapping!,GOTSIARRAY,,,,Mapa pole SI!,SI Array kortlægning!,SI-Feld Karte!,,SI-matric-mapado!,¡Mapeado de Tabla SI!,,SI-kenttäkartta!,Carte du tableau SI!,SI pálya Felderítő!,Mappatura di array SI!,SIアーレイ マッピング!,Si 어레이 지도!,,SI Array kartlegging!,Mapa Pola SI!,Mapeamento por Campo de SI!,,Hartă SI compilată!,Составлена карта SI-массива!,,SI Array kartläggning!,SI Dizi eşlemesi! +Infrared Visor!,GOTINFRARED,,,,Infračervené brýle!,Infrarødt visir!,Infrarotbrille!,,Transruĝa Viziero!,¡Visor infrarrojo!,,Infrapunavisiiri!,Viseur infrarouge!,Infravörös Sisak!,Visore a infrarossi!,赤外線バイザー!,적외선 바이져!,Infrarood vizier!,Infrarødt visir!,Wizjer na Podczerwień!,Visor Infravermelho!,,Vedere Infraroșie!,Инфракрасный визор!,,Infrarött visir!,Kızılötesi Vizör! +"Breathe deep, Inhaler!",GOTINHALER,,,,"Pořádně se nadechni, inhalátor!","Træk vejret dybt, Inhalator!","Atme tief, Inhalierer!",,"Spiru profunde, inhalo!","¡Un inhalador, inspira fuerte!",,"Hengitä syvään, inhalaattori!","Respire, inhaleur!","Mély lélegzet, Inhaláló!","Respirare profondamente, inalatore!",深呼吸だ、インヘイラー!,각성제를 주웠다. 잘 들이마셔!,"Adem diep in, inhalator!","Pust dypt, Inhalator!",Weź głęboki wdech! Inhalator!,Inalador! Respira fundo!,,"Inspiră adânc, Inhalatorule!",Ингалятор! Вдыхай глубже!,,"Andas djupt, Inhalator!","Derin nefes al, Inhaler!" +A dose of Hydergine from a Hypo saves you!,GOTHYPONEED,,,,Jsi zachráněn@[ao_cs] dávkou Hyderginu z Hypa!,En dosis Hydergine fra en Hypo redder dig!,Eine Dosis Hydergine rettet dich!,,,¡Una dosis de Hydergina te salva la vida!,,Hyderginepiikkiannos pelastaa sinut!,Une bonne dose d'hydergine vous sauve la vie!,Egy adag Hydergine megmenti az irhád!,Una dose di Hydergine di un Hypo ti salva!,ハイポで ヒデルギン をキメた!,하이포의 하이데르진이 당신을 살렸다!,Een dosis Hydergine van een Hypo redt je!,En dose Hydergine fra en Hypo redder deg!,Dawka Hyderginy z Hypo ratuje cię!,Uma dose de hidergina do Hypo para te salvar!,,O doză de Hidrogine dintr-o seringă te salvează!,Доза Редергина из шприца спасла тебя!,,En dos Hydergine från en Hypo räddar dig!,Hypo'dan bir doz Hydergine seni kurtarır! +You grab a Hypo!,GOTHYPO,,,,Sebral@[ao_cs] jsi Hypo!,Du tager en Hypo!,Hypo!,,Vi prenis Injektilon!,¡Has pillado una jeringa hipodérmica!,,Kahmaiset piikin!,Vous prenez une seringue!,Felkapsz egy Hypo-t!,Prendi un Hypo!,ハイポ を奪った!,하이포를 주웠다!,Je pakt een Hypo!,Du tar en Hypo!,Podniosłeś Hypo!,Você pegou um Hypo!,,Ai ridicat o Seringă!,Заполучен шприц!,,Du tar en Hypo!,Bir Hypo kaptın! +You found a KeyCard!,GOTKEYCARD,,,,Nalezl@[ao_cs] jsi přístupovou kartu!,Du har fundet et Nøglekort!,Schlüsselkarte gefunden!,,Vi trovis Ŝlosilkarton!,¡Has encontrado una Tarjeta Llave!,,Löysit avainkortin!,Vous trouvez une clé magnétique!,Leltél egy Kulcskártyát!,Hai trovato una chiave magnetica!,キーカードを見つけた!,키 카드를 찾았다!,U heeft een sleutelkaart gevonden!,Du har funnet et nøkkelkort!,Znalazłeś Kartę Dostępu!,Você achou um Cartão de Passe!,,Ai găsit un Card-Cheie!,Найдена ключ-карта!,,Du hittade ett nyckelkort!,Bir Anahtar Kart buldun! +You found a C-Key!,GOTCKEY,,,,Nalezl@[ao_cs] jsi kyberklíč!,Du har fundet en C-nøgle!,C-Schlüssel gefunden!,,Vi trovis C-Ŝlosilon!,¡Has encontrado una Llave-C!,,Löysit C-avaimen!,Vous trouvez une C-Clé!,Leltél egy C-Kulcsot!,Hai trovato una chiave C!,C-keyを見つけた!,C-키를 찾았다!,Je hebt een C-sleutel gevonden!,Du har funnet en C-nøkkel!,Znalazłeś Klucz C!,Você achou uma Chave-C!,,Ai găsit o Cheie-C!,Найден C-образный ключ!,,Du hittade en C-nyckel!,Bir C-Anahtarı buldun! +You found a Password!,GOTPASSWORD,,,,Nalezl@[ao_cs] jsi heslo!,Du har fundet et kodeord!,Passwort gefunden!,,Vi trovis Pasvorton!,¡Has encontrado una Contraseña!,,Löysit salasanan!,Vous trouvez un mot de passe!,Leltél egy Jelszót!,Hai trovato una parola d'ordine!,パスワードを見つけた!,암호를 찾았다!,U heeft een wachtwoord gevonden!,Du har funnet et passord!,Znalazłeś Hasło!,Você achou uma Senha!,,Ai găsit o Parolă!,Найден пароль!,,Du hittade ett lösenord!,Bir Şifre buldun! +You found a blue Z-Key!,GOTBLUEZKEY,,,,Nalezl@[ao_cs] jsi modrý Z-klíč!,Du fandt en blå Z-nøgle!,Blauen Z-Schlüssel gefunden!,,Vi trovis bluan Z-ŝlosilon!,¡Has encontrado una Llave-Z azul!,,Löysit sinisen Z-avaimen!,Vous trouvez une Z-Clé bleue!,Leltél egy kék Z-Kulcsot!,Hai trovato una chiave Z blu!,ブルー Z-Key を見つけた!,청색 Z-키를 찾았다!,Je hebt een blauwe Z-sleutel gevonden!,Du har funnet en blå Z-nøkkel!,Znalazłeś niebieski Klucz Z!,Você achou uma Chave-Z azul!,,Ai găsit o Z-Cheie albastră!,Найден синий Z-образный ключ!,,Du hittade en blå Z-nyckel!,Mavi bir Z-Anahtarı buldun! +You found a yellow Z-Key!,GOTYELWZKEY,,,,Nalezl@[ao_cs] jsi žlutý Z-klíč!,Du fandt en gul Z-nøgle!,Gelben Z-Schlüssel gefunden!,,Vi trovis flavan Z-ŝlosilon!,¡Has encontrado una Llave-Z amarilla!,,Löysit keltaisen Z-avaimen!,Vous trouvez une Z-Clé jaune!,Leltél egy sárga Z-Kulcsot!,Hai trovato una chiave Z gialla!,イエローZ-Key を見つけた!,황색 Z-키를 찾았다!,Je hebt een gele Z-sleutel gevonden!,Du har funnet en gul Z-nøkkel!,Znalazłeś żółty Klucz Z!,Você achou uma Chave-Z amarela!,,Ai găsit o Z-Cheie galbenă!,Найден жёлтый Z-образный ключ!,,Du hittade en gul Z-nyckel!,Sarı bir Z-Anahtarı buldun! +You found a red Z-Key!,GOTREDZKEY,,,,Nalezl@[ao_cs] jsi červený Z-klíč!,Du fandt en rød Z-nøgle!,Roten Z-Schlüssel gefunden!,,Vi trovis ruĝan Z-ŝlosilon!,¡Has encontrado una Llave-Z roja!,,Löysit punaisen Z-avaimen!,Vous trouvez une Z-Clé rouge!,Leltél egy piros Z-Kulcsot!,Hai trovato una chiave Z rossa!,レッド Z-Key を見つけた!,적색 Z-키를 찾았다!,Je hebt een rode Z-sleutel gevonden!,Du har funnet en rød Z-nøkkel!,Znalazłeś czerwony Klucz Z!,Você achou uma Chave-Z vermelha!,,Ai găsit o Z-Cheie roșie!,Найден красный Z-образный ключ!,,Du hittade en röd Z-nyckel!,Kırmızı bir Z-Anahtarı buldun! +Body Armor!,GOTBODYARMOR,,,,Brnění!,Kropsrustning!,Körperpanzerung!,,Kiraso!,¡Armadura!,,Suojavarustus!,Armure!,Testpáncél!,Giubbotti antiproiettile!,ボディーアーマー!,강화복!,Kogelvrije vesten!,Skuddsikker vest!,Pancerz!,Colete a Prova de Balas!,,Armură de Corp!,Бронежилет!,,Kroppspansar!,Vücut Zırhı! +Centrophenoxine,GOTCENTROPHENOXINE,,,,Centrofenoxin,Centrophenoxine,,,Centrofenoksino!,¡Centrofenoxina!,,Sentrofenoksiinia,Centrophenoxine!,,,セントロフェノキシン!,메클로페녹세이트!,,Centrophenoxine,Centrofenoxina,Centrofenoxina,,Centrofenoxine,Центрофеноксин,,, +You grab a Kevlar vest!,GOTKEVLARVEST,,,,Sebral@[ao_cs] jsi kevlarovou vestu!,Du får fat i en kevlarvest!,Kevlarweste!,,Vi prenis kevlaran veŝton!,¡Has pillado un traje de Kevlar!,¡Has recogido un traje de Kevlar!,Kahmaiset Kevlar-liivit!,Veste en Kevlar!,Felkapsz egy Golyóálló Mellényt!,Prendi una maglia di kevlar!,ケブラーベスト を奪った!,방탄복을 주웠다!,Pak een Kevlar vest!,Du tar en Kevlar-vest!,Podniosłeś kamizelkę kuloodporną!,Você pegou um Colete de Kevlar!,,Ai ridicat o vestă din Kevlar!,Заполучен кевларовый жилет!,,Du tar en kevlarväst!,Kevlar yeleği al! +You grab Super Kevlar vest!,GOTSKEVLARVEST,,,,Sebral@[ao_cs] jsi superkevlarovou vestu!,Du tager Super Kevlar vest!,Super-Kevlarweste!,,Vi prenis superan kevlaran veŝton!,¡Has pillado un supertraje de Kevlar!,¡Has recogido un supertraje de Kevlar!,Kahmaiset Superkevlar-liivit!,Super Veste en Kevlar!,Felkapsz egy Szuper Golyóálló Mellényt!,Prendi una maglia super kevlar!,スーパーケブラーベスト を奪った!,중 방탄복을 주웠다!,Je pakt een Super Kevlar vest!,Du tar en Super Kevlar vest!,Podniosłeś superkamizelkę kuloodporną!,Você pegou um Super Colete de Kevlar!,,Ai ridicat o Super Vestă din Kevlar!,Заполучен усиленный кевларовый жилет!,,Du tar tag i Super Kevlar väst!,Süper Kevlar yeleği al! +You grab a MicroKit!,GOTMICROKIT,,,,Sebral@[ao_cs] jsi mikrosadu!,Du får fat i et MicroKit!,MicroKit genommen!,,Vi prenis Kompleteton!,¡Has pillado un MicroKit!,¡Has recogido un MicroKit!,Kahmaiset Microkitin!,Microkit!,Felkapsz egy Mikorkit-et!,Prendi un MicroKit!,マイクロキット を奪った!,마이크로킷을 주웠다!,Je pakt een MicroKit!,Du tar en MicroKit!,Podniosłeś MikroZestaw!,Você pegou um MicroKit!,,Ai ridicat un MicroKit!,Заполучена мини-аптечка!,,Du tar en MicroKit!,Bir MicroKit al! +You grab a Dampener!,GOTDAMPENER,,,,Sebral@[ao_cs] jsi tlumič!,Du får fat i en Dampener!,Dämpfer genommen!,,Vi prenis Dampilon!,¡Has pillado un Amortiguador!,¡Has recogido un Amortiguador!,Kahmaiset vaimentimen!,Amortisseur!,Felkapsz egy Tompítót!,Prendi un antivento!,ダンプナー を奪った!,완충 장치를 주웠다!,Je pakt een Demper!,Du tar en Dampener!,Podniosłeś Tłumik!,Você pegou um Amortecedor!,,Ai ridicat un Amortizor!,Заполучен глушитель!,,Du tar en Dämpare!,Bir Sönümleyici al! +You need a C-Key to access this item!,PD_CKEY,,,,K přístupu potřebuješ kyberklíč!,Du skal bruge en C-nøgle for at få adgang til dette objekt!,Du brauchst einen C-Schlüssel um das hier zu bedienen.,,Vi bezonas C-ŝlosilon por aliri ĉi tiun objekton!,¡Necesitas una Llave-C para acceder a este objeto!,,Tarvitset C-avaimen saadaksesi pääsyn tähän kohteeseen!,Il vous faut une C-Clé pour accéder à cet objet!,Egy C-Kulcs szükséges a hozzáféréshez!,Hai bisogno di una chiave C per accedere a questo oggetto!,アクセスには C-key が必要だ!,C-키가 있어야 작동이 가능하다!,Je hebt een C-sleutel nodig om toegang te krijgen tot dit item!,Du trenger en C-nøkkel for å få tilgang til dette elementet!,Potrzebujesz Klucza C by uruchomić ten przedmiot.,Você precisa de uma Chave-C para acessar!,,Ai nevoie de o Cheie-C pentru a accesa acest obiect!,"Нет доступа, нужен C-образный ключ!",,Du behöver en C-nyckel för att få tillgång till detta objekt!,Bu eşyaya erişmek için bir C-Anahtarına ihtiyacın var! +You need a KeyCard to access this item!,PD_KEYCARD,,,,K přístupu potřebuješ přístupovou kartu!,Du skal bruge et Nøglekort for at få adgang til dette objekt!,Du brauchst eine Schlüsselkarte um das hier zu bedienen.,,Vi bezonas Slosilkarton por aliri ĉi tiun objekton!,¡Necesitas una Tarjeta Llave para acceder a este objeto!,,Tarvitset avainkortin saadaksesi pääsyn tähän kohteeseen!,Il vous faut une carte magnétique pour accéder à cet objet!,Egy kulcskártya szükséges a hozzáféréshez!,Hai bisogno di una chiave magnetica per accedere a questo oggetto!,アクセスには キーカード が必要だ!,키 카드가 있어야 작동이 가능하다!,U heeft een sleutelkaart nodig om toegang te krijgen tot dit item!,Du trenger et nøkkelkort for å få tilgang til dette elementet!,Potrzebujesz Karty Dostępu by uruchomić ten przedmiot!,Você precisa de uma Chave de Passe para acessar!,,Ai nevoie de un Card-Cheie pentru a accesa acest obiect!,"Нет доступа, нужен ключ-карта!",,Du behöver ett KeyCard för att komma åt det här objektet!,Bu öğeye erişmek için bir KeyCard'a ihtiyacınız var! +You need a Password to access this item!,PD_PASSWORD,,,,K přístupu potřebuješ heslo!,Du skal bruge et kodeord for at få adgang til dette objekt!,Du brauchst eine Passwort um das hier zu bedienen.,,Vi bezonas Pasvorton por aliri ĉi tiun objekton!,¡Necesitas una Contraseña para acceder a este objeto!,,Tarvitset salasanan saadaksesi pääsyn tähän kohteeseen!,Il vous faut un mot de passe pour accéder à cet objet!,Egy Jelszó szükséges a hozzáféréshez!,Hai bisogno di una parola d'ordine per accedere a questo oggetto!,アクセスには パスワード が必要だ!,암호를 입력해야 작동이 가능하다!,Je hebt een wachtwoord nodig om toegang te krijgen tot dit item!,Du trenger et passord for å få tilgang til dette elementet!,Potrzebujesz Hasła by uruchomić ten przedmiot!,Você precisa de uma Senha para acessar!,,Ai nevoie de Parolă pentru a accesa acest obiect!,"Нет доступа, нужен пароль!",,Du behöver ett lösenord för att få tillgång till detta objekt!,Bu öğeye erişmek için bir Şifreye ihtiyacınız var! +You need a Blue Z-Key to make this work,PD_BLUEZKEY,,,,Tohle bude fungovat jen s modrým Z-klíčem.,Du skal bruge en blå Z-nøgle for at få dette til at fungere!,Du brauchst einen blauen Z-Schlüssel um das hier zu bedienen.,,Vi bezonas Bluan Z-ŝlosilon por funkciigi ĉi tiun!,¡Necesitas una Llave-Z azul para hacer funcionar esto!,,Tarvitset sinisen Z-avaimen saadaksesi tämän toimimaan!,Il vous faut une Z-Clé bleue pour faire fonctionner cela.,Egy Kék Z-Kulcs szükséges a hozzáféréshez!,Hai bisogno di una chiave Z blu per accedere a questo oggetto!,アクセスには ブルーZ-key が必要だ!,청색 Z-키가 있어야 작동이 가능하다!,Je hebt een blauwe Z-sleutel nodig om dit te laten werken.,Du trenger en blå Z-nøkkel for å få dette til å fungere!,Potrzebujesz Niebieskiego Klucza Z by zadziałało!,Você precisa de uma Chave-Z azul para fazer isto funcionar!,,Ai nevoie de o Cheie-Z albastră pentru a face asta să funcționeze!,"Не работает, нужен синий Z-образный ключ!",,Du behöver en blå Z-nyckel för att få detta att fungera.,Bunu çalıştırmak için bir Mavi Z-Anahtarına ihtiyacınız var +You need a Red Z-Key to make this work!,PD_REDZKEY,,,,Tohle bude fungovat jen s červeným Z-klíčem.,Du skal bruge en rød Z-nøgle for at få dette til at fungere!,Du brauchst einen roten Z-Schlüssel um das hier zu bedienen.,,Vi bezonas Ruĝan Z-ŝlosilon por funkciigi ĉi tiun!,¡Necesitas una Llave-Z roja para hacer funcionar esto!,,Tarvitset punaisen Z-avaimen saadaksesi tämän toimimaan!,Il vous faut une Z-Clé rouge pour faire fonctionner cela.,Egy Piros Z-Kulcs szükséges a hozzáféréshez!,Hai bisogno di una chiave Z gialla per accedere a questo oggetto!,アクセスには レッドZ-key が必要だ!,적색 Z-키가 있어야 작동이 가능하다!,Je hebt een rode Z-sleutel nodig om dit te laten werken!,Du trenger en rød Z-nøkkel for å få dette til å fungere!,Potrzebujesz Czerwonego Klucza Z by zadziałało!,Você precisa de uma Chave-Z vermelha para fazer isto funcionar!,,Ai nevoie de o Cheie-Z roșie pentru a face asta să funcționeze!,"Не работает, нужен красный Z-образный ключ!",,Du behöver en röd Z-nyckel för att detta ska fungera!,Bunu çalıştırmak için Kırmızı Z-Anahtarına ihtiyacınız var! +You need a Yellow Z-Key to make this work!,PD_YELWZKEY,,,,Tohle bude fungovat jen se žlutým Z-klíčem.,Du skal bruge en gul Z-nøgle for at få dette til at fungere!,Du brauchst einen gelben Z-Schlüssel um das hier zu bedienen.,,Vi bezonas Flavan Z-ŝlosilon por funkciigi ĉi tiun!,¡Necesitas una Llave-Z amarilla para hacer funcionar esto!,,Tarvitset keltaisen Z-avaimen saadaksesi tämän toimimaan!,Il vous faut une Z-Clé jaune pour faire fonctionner cela.,Egy Sárga Z-Kulcs szükséges a hozzáféréshez!,Hai bisogno di una chiave Z rossa per accedere a questo oggetto!,アクセスには イエローZ-key が必要だ!,황색 Z-키가 있어야 작동이 가능하다!,Je hebt een gele Z-sleutel nodig om dit te laten werken!,Du trenger en gul Z-nøkkel for å få dette til å fungere!,Potrzebujesz Żółtego Klucza Z by zadziałało!,Você precisa de uma Chave-Z amarela para fazer isto funcionar!,,Ai nevoie de o Cheie-Z galbenă pentru a face asta să funcționeze!,"Не работает, нужен жёлтый Z-образный ключ!",,Du behöver en gul Z-nyckel för att detta ska fungera!,Bunu yapmak için Sarı Z-Anahtarına ihtiyacın var! +"Twenty mill in gold doesn't seem worth all +this aggravation, does it, hacker? Makes +the pen look like a freakin' picnic! + +Butt-ugly bio-mutations and your fellow +Humans hung from a ceiling like +food sacks. + +What the hell is this GENIE? Like no +computer you've ever hacked! + +You better find the next terminal, slice +a ride through c-space, dice some mutant +butt, and get the hell out of Dodge! + +",X1TEXT,,,,"Dvacet miliónů ve zlatě nevypadá, že by +stálo za všechnu tuhle otravu, co, hackeře? +Basa teď vypadá jako krásný hotel! + +Ošklivé bio-mutace a tví lidští společníci +visící ze stropu jako pytle masa. + +Co je sakra tenhle GENIE? Takový počítač +jsi ještě nenaboural@[ao_cs]! + +Měl@[ao_cs] bys najít další terminál, projet +se kyberprostorem, vysekat pár mutantům +střeva a rychle z Dodge vypadnout!","Tyve millioner i guld er vist ikke al +denne besværlighed værd, vel, hacker? +Laver +fængslet som en skide picnic! + +Butt-ugly bio-mutationer og dine +medmennesker hænger fra loftet som +madposer. + +Hvad fanden er denne GENIE? Som ingen +computer, du nogensinde har hacket! + +Du må hellere finde den næste terminal, +snitte en tur gennem c-space, skære +nogle mutant-røvhuller i småstykker +og komme væk fra Dodge!","Zwanzig Millionen in Gold sind nicht +wirklich so viel wert, Hacker, nicht wahr? +Das hier lässt den Knast wie ein +Picknick erscheinen. + +Hässliche Bio-Mutationen und deine +menschlichen Artgenossen hängen von +der Decke wir Futtersäcke. + +Was zur Hölle ist dieses GENIE? Das ist +wie kein anderer Computer den du +jemals gehackt hast. + +Du findest besser das nächste Terminal, +erledigst einige Mutantenärsche und +siehst zu, aus Dodge herauszukommen!",,"Dudek milionoj en oro ne ŝajnas valori +ĉi tiun ĝenon, ĉu ne, kodrompisto? Fek! +Faras la karceron aspekti kiel pikniko! + +Turpaĉaj bio-mataciuloj kaj viaj +homaj kunuloj pendis de la plafono +kiel sakoj da manĝajo. + +Kio diable estas ĉi tiu GENIE? Ĝi estas +kiel neniu komputilo, kiun vi kodrompis! +... nek kiel ia ĝino! + +Vi devas trovi la sekvan stacion, preni +rajdon tra ciberspaco, haki iom da +mutaciulo-pugo, kaj eliru de ĉi tie!","Veinte millones en oro no parece que valgan +la pena por todo este lío, ¿no crees, hacker? +¡Hace que el corral parezca un picnic! + +Horripilantes biomutaciones y tus compañeros +humanos cuelgan del techo como sacos. + +¿Qué demonios es GENIE? ¡No se parece a +cualquier computadora que hayas hackeado! + +¡Más te vale encontrar la próxima terminal, dar +un viaje por el ciberespacio, rebanar unos +cuantos traseros mutantes, y pirarte de Dodge!","Veinte millones en oro no parece que valgan +la pena por todo este lío, ¿no crees, hacker? +¡Hace que el corral parezca un picnic! + +Horripilantes biomutaciones y tus compañeros +humanos cuelgan del techo como sacos. + +¿Qué demonios es GENIE? ¡No se parece a +cualquier computadora que hayas hackeado! + +¡Más te vale encontrar la próxima terminal, dar +un viaje por el ciberespacio, rebanar unos +cuantos traseros mutantes, y largarte de Dodge!","20 miltsiä kultaa ei taida olla kaiken tämän +vaivan väärti, eihän, hakkeri? Saa kynän sen +rinnalla tuntumaan perhanan piknikiltä! + +Karsean rumia biomutaatioita ja kanssa- +ihmisiäsi roikkumassa katosta kuin mitkäkin +ruokakassit. + +Mikä helvetti on tämä GENIE? Ei minkään +ennen hakkeroimasi tietokoneen kaltainen! + +Parasta löytää seuraava pääte, napata kyyti +c-avaruuden läpi, piestä vähän mutantteja +ja häipyä hittoon Dodgesta!","Vingt Millions en or ne semblent +plus valoir tout ces problèmes +maintenant, Hacker? Tout ce bordel +donne un air de pique-nique +à la prison! + +De mutations hideuses et vos +frèrs humains pendant du plafond +comme des sacs de nourriture. + +C'est quoi comme foutoir, ce GENIE? +Aucune ordinateur que vous avez +piraté auparavant était comme ça! + +Il faut que vous trouvez le prochain +terminal, traversez le cyberespace, +découpez du mutant et barrez-vous +d'ici!","Húsz milka nem ér meg ennyi bosszankodás, ugye hekker? A cella ehhez képest egy francos piknik! + +Baromi ocsmány bio-mutációk és embertársaid úgy lógnak le a mennyezetről, mintha csak a hentesnél lennénk. + +Mi az ördög ez a GENIE? Semmilyen más számítógépre nem hasonlít amit hekkelni próbáltál! + +Jobban jársz ha megkeresed a következő terminált, végig rombolsz a kibertéren mutánsokat gázolva, és minél előbb itt hagyod Dodge-ot!","Venti milioni in oro non sembra valere tutta +questa esasperazione , vero, hacker? +Fa sembrare la prigione come un +cavolo di picnic! + +Le enormi bio-mutazioni e i tuoi +compagni umani appesi a un soffitto +come sacchi di cibo. + +Che diavolo è questo GENIE? +Come nessun computer che +tu abbia mai hackerato! + +Faresti meglio a trovare il terminale +successivo, a fare un giro nel c-spazio, +a tagliare a dadi qualche culo mutante, +e ad uscire da Dodge! +","20ミリの金塊にこの重大な事態の価値を見出せない、 +それとも、ハッカーの仕業か? +幻覚のピクニックってワケでもねえ! +グロいバイオミュータントと人間の仲間が食肉のように +天井から吊るされている。 + +GENIEとは一体何なんだ? 少なくともこれまで +ハックしたことのないコンピューターだってことだ! + +次のターミナルを抜け、c-spaceに乗り込み、 +ミュータントのダニ共を切り裂いて、このふざけた +場所から抜け出すんだ!","2000만 달러 보상금 가지고는 턱도 없을 정도의 개판이었어! 안 그런가, +해커 양반? 펜이나 끄적거리는 게 이것보다는 훨씬 쉬울 테니 말이야. + +이 더럽게 못생긴 돌연변이들이며, 천장에 마늘꾸러미처럼 매달려있는 +사람들을 볼 일도 없고 말이야. + +그리고... 이 지니란 녀석은 도대체 뭐지? 네가 해킹했던 다른 컴퓨터들과는 +완전 차원이 다른 녀석이야. 어서 다른 단말기를 찾아서 C-Space를 타고 +접속하는 게 좋을 것 같아. + +돌연변이들을 몇 마리 썰어버리면서, 이곳을 빠져나가 는 것도 잊지 말고!","Twintig miljoen in goud lijkt al die verergering +niet waard, of wel, hacker? Het laat de gevangenis +eruit zien als een verdomde picknick! +Lelijk bio-mutaties en je medemensen hingen +als voedselzakken aan een plafond. + +Wat is dit GENIE in godsnaam? Als geen enkele +computer die je ooit hebt gehackt! +Je kunt maar beter de volgende terminal vinden, +een ritje door de c-ruimte maken, een paar +gemuteerde kontdobbelstenen dobbelen, +en Dodge in hemelsnaam verlaten!","Tjue millioner i gull virker ikke +verdt alt dette bryet, gjør det vel, +hacker? Får pennen til å se ut +som en jævla piknik! + +Stygge bio-mutasjoner og dine +medmennesker hengende fra +taket som matsekker! + +Hva i helvete er denne GENIE? +Som ingen datamaskin du +noensinne har hacket! + +Du bør finne neste terminal, +skjære en tur gjennom c-space, +terning noen mutant rumpe, og +kom deg til helvete ut av Dodge!","Dwadzieścia milionów w złocie nie jest warte +tych kłopotów, prawda hakerze? Przy tym +więzienie wygląda jak cholerny piknik! + +Ohydne bio-mutacje i inni ludzie zwisają +z sufitu jak przekąski. + +Czym u diabła jest to GENIE? Nie jest jak inne +komputery, które hakowałeś! + +Lepiej znajdź kolejny terminal, przeleć przez +Przestrzeń C, skop trochę zmutowanych tyłków +i wynoś się z tego piekielnego Uskoku! +","Vinte milhões em ouro não parecem valer +toda essa incomodação, não é mesmo, hacker? +O xilindró é um piquenique perto disso! + +Biomutações feias pra caramba estão penduradas +no teto junto com seres humanos como se +fossem sacos de alimento. + +Que diabos é esse tal de GENIE? Não é como nenhum +outro computador que você já tenha hackeado! + +É melhor achar o próximo terminal, pegar uma +carona pelo ciberespaço, fazer picadinho de +mutante e vazar deste lugar de uma vez!",,"Douăzeci de milioane în aur nu par să fie +suficienți pentru tot dezastrul acesta, nu-i așa, +hacker? Totul pare un fleac pe lângă asta! + +Mutanți urâți foc, împreună cu oamenii tăi +atârnă de tavan asemeni unor saci de mâncare. + +Ce naiba mai e și acest GENIE? E ca un computer +pe care nu l-ai mai spart în viața ta! + +Mai bine găsești următorul terminal, prinzi o +mașină în spațiul cibernetic, feliezi niște mutanți, +și îți iei tălpășița!","Стоят ли двадцать лимонов золотом таких +трудностей, а, хакер? Теперь тебе тюрьма +грёбаным санаторием покажется! + +Толстозадые биомутанты и такие же люди, +как ты, лежат рядком, как мешки с едой. + +Что за хрень этот ДЖИНН? Он не похож ни +на один из компьютеров, что ты уже +взламывал! + +Найди терминал, прокатись по +киберпространству, надери всем мутантам +задницы и выберись из этой чёртовой +передряги! + +",,"Tjugo miljoner i guld verkar inte vara värt allt detta besvär, eller hur, hackare? Det får pennan att se ut som en jäkla picknick! + +Röviga biomutationer och dina medmänniskor hängde från taket som matsäckar. + +Vad i helvete är det här för GENIE? Som ingen dator du någonsin hackat! + +Det är bäst att du hittar nästa terminal, tar en tur genom c-rymden, skär några mutantrumpor och sticker härifrån!","Yirmi milyon altın bu kadar +zahmete değmez, değil mi +hacker? Hapishane piknik yeri +gibi görünüyor! + +Çirkin biyo-mutasyonlar ve +tavandan yiyecek çuvalları gibi +sarkıtılmış İnsan dostlarınız. + +Bu GENIE de neyin nesi? Daha +önce hacklediğin hiçbir +bilgisayara benzemiyor! + +Bir sonraki terminali bulsanız +iyi olur, c-uzayında bir yolculuk +yapın, biraz mutant kıçı doğrayın +ve Dodge'dan defolup gidin!" +"Where are all the people?! + +Paris is a ghost town, unless you consider +mutant bugs outstanding citizens. + +You've hit bloody resistance. Man, can +these bugs fight! Lucky for you they're not +the brightest porch lights on the block. + +But you've gotten some of the informatics +the subcommittee wants. And it's nasty! + +Human neural fluids feed these bugs! No +wonder the neighborhood's getting kind of +sparse. Report to the subcommittee. And +watch your back... +",X2TEXT,,,,"Kde jsou všichni!? + +Z Paříže je město duchů, leda že bys +zmutované bugy považoval@[ao_cs] za vzorné občany. + +Narazil@[ao_cs] jsi na tvrdý odpor. Sakra, tyhle +bugy umí bojovat! Naštěstí ale nejsou +zrovna nejchytřejší. + +Ale dostal@[ao_cs] jsi některé ty informace, který +podvýbor chtěl. A je to pěkný hnus! + +Tyhle bugy se krmí lidským mozkovým mokem! +Není divu, že je ve čtvrti nějak prázdno. +Nahlaš se zpátky u výboru. A dávej pozor...","Hvor er alle de mennesker?! + +Paris er en spøgelsesby, medmindre +man betragter mutante insekter som +enestående borgere. + +Du har ramt den blodige modstand. +Mand, hvor de kan slås. +Heldigt for dig, at de ikke er de +mest lysende dørlamper i kvarteret. + +Men du har fået noget af den +information, som underudvalget vil +have. Og det er ulækkert! + +Menneskers neurale væsker fodrer disse +insekter! Ikke underligt, at kvarteret +er ved at blive lidt tyndt. Rapport til +underudvalget. Og pas på dig selv...","Wo sind all die Menschen!? + +Paris ist eine Geisterstadt, es sei denn, +du zählst die Mutanten als Musterbürger. + +Du bist auf blutigen Widerstand getroffen. +Mann können diese Viecher kämpfen. +Glücklicherweise sind sie nicht die hellsten +Leuchten. + +Aber du hast einige Informationen, die +das Subkommitee haben will. Und es ist +übel. + +Menschliche Nervenflüssigkeit ist was +diese Viecher antreibt. Kein Wunder, dass +die Nachbarschaft am Aussterben ist. +Das musst du dem Subkommitee +mitteilen. Und pass auf!",,"Kie estas ĉiuj homoj?! + +Parizo estas senhoma urbo, se vi ne +konsideras mutaciajn cimojn elstaraj +urbanoj. + +Vi kontraŭstaras sangan reziston. Ve, +ĉu tiuj cimoj povas batali! Bonsorte, +ili ne estas la plej granda saĝulo. + +Tamen, vi akiris iom el la informaĵoj, +kiujn la komisiono volas. Kaj ĝi estas fia! + +Homaj neŭraj likvaĵoj nutras la cimojn! +Ne mirinde, ke la urbo ŝajnas iĝi iomete +neloĝata. Raportu al la kimisiono. +Singardu...","¡¿Dónde está toda la gente?! + +Paris es una ciudad fantasma, a menos que +consideres que los bichos mutantes sean +unos buenos ciudadanos. + +Has encontrado resistencia sangrienta. Tío, ¡si +que pelean estos bichos! Por suerte para ti no +son los más brillantes del barrio. + +Pero has conseguido algunos materiales +informáticos que el subcomité quiere. +¡Y tienen mala pinta! + +¡Fluidos neuronales humanos alimentan a +estos bichos! No es de extrañar que el +vecindario esté algo despoblado. Personate +ante el subcomité. Y vigila tus espaldas...","¡¿Dónde está toda la gente?! + +Paris es una ciudad fantasma, a menos que +consideres que los bichos mutantes sean +unos buenos ciudadanos. + +Has encontrado resistencia sangrienta. Tío, ¡si +que pelean estos bichos! Por suerte para ti no +son los más brillantes del barrio. + +Pero has conseguido algunos materiales +informáticos que el subcomité quiere. +¡Y tienen mala pinta! + +¡Fluidos neuronales humanos alimentan a +estos bichos! No es de extrañar que el +vecindario esté algo despoblado. Repórtate +ante el subcomité. Y vigila tus espaldas...","Missä kaikki ovat?! + +Pariisi on aavekaupunki, ellei mutantti- +öttiäisiä sitten lasketa mallikansalaisiksi. + +Olet iskenyt hitonmoiseen vastukseen. Vitsi +nämä ötökät tappelevat! Onneksesi ne eivät +ole korttelin kirkkaimpia ulkovaloja. + +Mutta olet saanut osan informatiikasta, jota +alakomitea kaipaa, ja se on pahaa luettavaa! + +Ihmisen hermonesteet ruokkivat ötököitä! Ei +ihme, että tienoo alkaa tuntua väljältä. +Raportoi alakomitealle ja vahdi selustaasi...","Où se trouve trout le monde? +Paris est une ville fantôme, sauf si +vous considérez que les insectes +mutants sont des citoyens. +Vous avez rencontré une sacrée +résistance, ces sales bestioles +savent se battre! Heureusement, +il ne sont pas les plus malins du +coin.. +Vous avez récupéré une partie de +l'informatique que le sous-comité +demande. Ca a un sale air! +Des fluides neuraux humains +alimentent ces insectes! Pas +de surprise que le coin est +désert. Retournez au sous-comité +et faites gaffe à vous!","Hol vannak az emberek? + +Párizs egy szellemváros, kivétel ha a mutáns óriás bogarakat nem vesszük számba mint mintapolgár. + +Komoly ellenállásba ütköztél. Ezek a bogarak aztán tudnak harcolni! Szerencsédre nem a legélesebb kések a fiókban. + +Szerencsére meg sikerült kerítened az információkat, amit az albizottság akart...és igen piszkos! + +Kiszívják ezek a dögök az emberek gerincvelejét! Nem is csoda, hogy a szomszédság igen megritkult. Jelezz vissza az albizottságnak, és vigyázz magadra...","Dove sono tutte le persone?! +Parigi è una città fantasma, a meno +che non si considerino questi +mutanti come cittadini eccezionali. + +Hai trovato resistenza feroce. +Amico, questi mutanti sanno combattere! +Fortunatamente per te non sono le +luci dei portici più brillanti del blocco. + +Ma hai ottenuto un po' delle informazioni +che il sottocomitato vuole. E sono brutte! + +I fluidi neurali umani alimentano +questi mutanti! Non c'è da stupirsi +che il quartiere sia sempre più spopolato. +Riporta al sottocomitato. + +E guardati le spalle ...","皆何処に行った?! + +パリはゴーストタウンと化した、突然変異したバグ共が +未解決なまま自分以外の住民はいなくなった。 + +マジな敵対にぶち当たった。野郎、こんなバグ共と戦えと! +幸運なことに先行きの見えない事態ではない。 +だがここでインフォーマティクスとサブコミッティが +望んでいた物を探し当てた。厄介なことにな! + +人の神経液をバグ共が餌にしている! 近くに転がっていた +者が損壊していたのも納得がいく、サブコミッティに +報告しなければ。背中に気をつけながらな... +","여기 사람들은 도대체 어디로 간 거지?! + +프랑스 파리도 완전히 유령도시가 되어버렸군, 저 돌아다니는 돌연변이 +버그들이 시민은 아닐 테니까. + +방금 전투는 정말 위험했어. 빌어먹을 버그들 생각보다 잘 싸우더군. +머리가 좋은 놈들은 아니라서 다행이야. 그래도 위원회 놈들이 원하는 +정보는 얻었으니 다행이야. 놈들 꽤 더러운 걸 숨기고 있더군. + +인간의 척수를 빨아먹는 버그들이라니! 이 주변 대가 허허벌판인 것도 +당연할 수밖에. 어서 위원회 놈들한테 보고하자고. 그리고 언제나 +등 뒤를 조심해.","Waar zijn alle mensen?! +Parijs is een spookstad, tenzij je mutanten +als uitstekende burgers beschouwt. + +Je hebt bloedige weerstand geraakt. Man, kan +deze beestjes vechten! Gelukkig voor jou +zijn ze niet de helderste lichten op het blok. + +Maar je hebt een aantal van de informatica +gekregen die de subcommissie wil. En het is +vervelend! +Menselijke neurale vloeistoffen voeden deze +beestjes! Geen wonder dat de buurt een +beetje schaarser wordt. Rapporteer aan +de subcommissie. En let op je rug...","Hvor er alle menneskene?! + +Paris er en spøkelsesby, med mindre +du anser muterte insekter som +fremragende borgere. + +Du har møtt blodig motstand. +Jøss, som disse insektene kan +slåss! Flaks for deg at de ikke +er de smarteste i nabolaget. + +Men du har fått noe av informatikken +underkomiteen vil ha. +Og det er ekkelt! + +Menneskelige nervevæsker mater +disse insektene! Ikke rart at +nabolaget begynner å bli tynt. +Rapporter til underkomiteen. +Og pass deg...","Gdzie wszyscy ludzie? + +Paryż stał się miastem duchów, no chyba że +uznasz zmutowane robale za jego mieszkańców. + +Napotkałeś cholerny opór. Kurde, te robale +umieją przywalić! Na szczęście nie są +najświetlejsze w tym lokalu. + +Ale zdobyłeś trochę informacji, które chciał +podkomitet. I nie są dobre! + +Ludzkie płyny neuronowe są pokarmem dla +tych robali! Nic dziwnego, że okolica jest +spustoszona. Zgłoś się do podkomitetu. +I uważaj na siebie...","Cadê todo mundo? + +Paris é uma cidade fantasma, a não ser que você +considere os mutantes como cidadãos especiais. + +Você enfrenta uma baita resistência. Cara, esses +bichos sabem brigar! Sorte sua que eles não são +as criaturas mais espertas do local. + +Mas você conseguiu pegar algumas informações +que o subcomitê estava querendo. E a coisa é feia! + +Esses bichos se alimentam de fluídos neurais +humanos! Não é a toa que a vizinhança anda ficando +meio vazia ultimamente. Entre em contato com +o subcomitê. E fique de olho...",,"Unde e toată lumea?! + +Parisul e un oraș fantomă, asta dacă nu consideri +mutanții cetățeni nemaipomeniți. + +Ai întâmpinat opoziție serioasă! Mamă, gândacii +aceștia știu să lupte, nu glumă! Din fericire nu +sunt cei mai tari din parcare. + +Dar deții niște informații pe care comitetul vrea +să le vadă! Și nu sunt prea încântătoare! + +Fluidele neuro umane hrănesc acești gândaci! +Nu-i de mirare că vecinătatea devine cam pustie. +Raportează înapoi la comitet. Și păzește-ți +spatele...","Где все люди?! + +Париж опустел, не считая уродливых +багов, заменивших горожан. + +Ты столкнулся с ожесточённым +сопротивлением. Чёрт, эти баги слетаются +к тебе, как мухи на свет! К счастью, ты не +самый яркий фонарь в этом городе. + +Но теперь в твоих руках кое-какая +информация, которая нужна подкомитету. +И это скверно! + +Эти баги подпитываются нервными +импульсами людей! Понятно, почему +вокруг не осталось никого живого. +Передай эти сведения подкомитету. +И будь осторожен... +",,"Var är alla människor?! + +Paris är en spökstad, om man inte anser att mutantbaggar är enastående medborgare. + +Du har stött på blodigt motstånd. De här insekterna kan verkligen slåss! Tur för dig att de inte är de ljusaste verandalamporna i kvarteret. + +Men ni har fått fram en del av den information som underkommittén vill ha. Och det är otäckt! + +Mänskliga neurala vätskor matar dessa insekter! Inte undra på att grannskapet börjar bli glesare. Rapportera till underkommittén. Och se upp för din rygg...","Bütün insanlar nerede?! + +Paris hayalet bir şehir, tabii +mutant böcekleri seçkin +vatandaşlar olarak +görmüyorsanız. + +Kanlı bir direnişle karşılaştınız. +Adamım, bu böcekler +savaşabilir! Şanslısın ki +mahallenin en parlak ışıkları +değiller. + +Ama alt komitenin istediği bazı +bilgileri elde ettiniz. Ve bu iğrenç! + +İnsan sinir sıvıları bu böcekleri +besliyor! Mahallenin seyrekleş- +mesine şaşmamalı. Alt komiteye +rapor ver. Ve arkanı kolla..." +"Civilization as you knew it is nada! + +No friends, no family. No more people. +Not normal people, anyway. + +Only one thing left...GENIE! +And if you have to go to the end of the +universe you'll find its mutant butt! +'cause now you're pissed! + +And the gold? Hell, this is for free. + +.....(to be continued).....",X3TEXT,,,,"Civilizace, tak jak ji známe, je pryč. +Nada. Nilch. + +Bez přátel, bez rodiny. Bez lidí. +Alespoň těch normálních. + +Jediná zbylá věc... GENIE! +I kdybys musel@[ao_cs] jít až na konec vesmíru, +najdeš jeho zmutovaný ksicht! +Protože teď jsi fakt nasran@[adj_cs]! + +A to zlato? Sakra, tohle děláš zadarmo. + +.....(pokračování příště).....","Civilisationen, som du kendte den, er nada! + +Ingen venner, ingen familie. +Ikke flere mennesker. +Ikke normale mennesker, i hvert fald. + +Kun én ting er tilbage... GENIE! +Og hvis du er nødt til at gå til enden +af universet, vil du finde dens +mutant røv! +For nu er du pissed! + +Og guldet? For fanden, det er gratis. + +.....(fortsættelse følger).....","Die Zivilisation, wie du sie kanntest, +ist Nada. Keine Freunde, keine Familie. +Keine Menschen mehr. Zumindest +keine normalen. + +Nur eine Sache verbleibt: GENIE! +Und wenn du ans Ende des Universum +reisen müsstest, du wirst seinen +Mutantenarsch finden, denn jetzt +bist du sauer! + +Und das Gold? Das gibt's als Zugabe... + +... (Fortsetzung folgt) ... + +",,"La civilizoj, kiun vi konis, estas nulita! + +Neniuj amikoj, neniu familio, neniuj +homoj plu. Neniu normaj homoj, ĉiuokaze. + +Nur unu aĵo restas... GENIE! +Kaj eĉ se vi bezonos iri la limo de +la universo, vi trovos ĝian mutacian pugon! +Ĉar vi furiozas! + +Pri la oro? Diable, ĉi tio estas senpaga. + +.....(Daŭrigota).....","¡La civilización como la conoces ya no es nada! + +Sin amigos, ni familia. No más gente. +No gente normal, de todos modos. + +Solo queda una cosa... ¡GENIE! +¡Y si tienes que ir hasta el fin del universo +encontrarás su trasero mutante! +¡Porque ahora si que estás cabread@[ao_esp]! + +¿Y el oro? Para nada, esto es gratis. + +... (continuará) ...",,"Tuntemasi sivilisaatio on mennyttä! + +Ei ystäviä, ei perhettä, ei enää ihmisiä; +tai ainakaan ei normaaleja ihmisiä. + +Vain yksi asia jäljellä... GENIE! +Ja vaikka joutuisit menemään universumin +ääriin, löydät sen mutanttipersauksen! +Sillä nyt sinua ottaa päähän! + +Ja kulta? Hitto, teen tämän ilmaiseksi. + +.....(jatkuu).....","La société humaine a disparu! + +Plus d'amis, plus de famille, plus +personne de normal, du moins. + +Une chose reste.. GENIE! +Si il le faut, vous irez jusqu'au +bout de l'univers pour lui botter +le cul! Ca va en chier! + +Oh, et l'Or? Non, ça, c'est gratuit... + +... A suivre!","A civilizáció mint olyan már nem létezik! + +Se barátok, se család. Nincs több ember. Legalábbis nem normális emberek. + +Csak egy dolog van hátra...GENIE! Már olyan zabos vagy, hogy ha a világ végére is kell mened érte, akkor is megkeresed és végzel vele. + +És az arany? A fenébe is, ingyen van. + +.....(folytatjuk).....","La civiltà come la conoscevi è nada! +Nessun amico, nessuna famiglia. +Niente più persone. +Non persone normali, comunque. + +Solo una cosa è rimasta...GENIE! +E se dovessi andare alla fine +dell'universo troveresti il suo +culo mutante! + +Perché ora sei incazzato! +E l'oro? Al diavolo, questo è gratis... + + +.....(continua).....","俺の知っている文明は崩壊した! + +友も。家族も。住民も。まともなヤツは何もかも +消え失せた。 + +だがまだ一つ残っている...GENIE! +このまま銀河の終焉を迎えたらミュータントのクソになる! +それだけは御免だ! + +それで金は? 有り得ん、これはフリーだ。 + +...だがこれ以上続くことはない...","자네도 알다시피 이제 문명이란 건 존재하지 않아! + +친구들, 가족, 그리고 사람들도 다 사라졌지. 돌연변이들이 있긴 하지만. + +이제 유일하게 남은 건... 지니일 거야. 그 빌어먹을 녀석을 우주 끝까지 +쫓아가서 박살 내 버리자고! 자네를 화나게 한 값은 톡톡히 치르게 해줘야지? + +보상금? 이번엔 필요 없어, 이번 일은 공짜로 해줄 테니. + +...(다음에 계속)...","De beschaving zoals je die kende is nada! + +Geen vrienden, geen familie. Geen mensen meer. +In ieder geval geen normale mensen. +Nog maar één ding over...GENIE! + +En als je naar het einde van het universum +moet gaan, vind je de gemuteerde kont! +want nu ben je boos! + +En het goud? Hel, dit is gratis. + +... (wordt vervolgd)...","Sivilisasjonen slik du kjente +den er nada! + +Ingen venner, ingen familie. +Ikke flere mennesker. +Ikke normale mennesker, +i alle fall. + +Bare én ting igjen... GENIE! +Og hvis du må gå til enden av +universet vil du finne dens +mutant rumpe! +For nå er du forbanna! + +Og gullet? Helvete, dette +er gratis. + +.....(fortsettelse følger).....","Cywilizacja, którą znałeś zniknęła! + +Nie ma przyjaciół i rodziny. Już nie ma ludzi. +Przynajmniej normalnych ludzi. + +Została tylko jedna rzecz...GENIE! +I nawet jeśli musisz dotrzeć na sam kraniec +świata, znajdziesz jego zmutowane dupsko! +Ponieważ wiesz, że będziesz wkurzony! + +A złoto? Jest kurde za darmo. + +.....(ciąg dalszy nastąpi).....","A civilização como você conhecia já era! + +Sem amigos, sem família. Sem mais ninguém. +Ninguém normal, pelo menos. + +A única coisa que resta...é GENIE! +E nem que você tenha que ir até o fim do +universo, você vai encontranr a fuça mutante dele! +Agora você está furios@[ao_ptb] pra caramba! + +E o ouro? Que se dane, essa é por conta da casa. + +....(continua)....",,"Civilizația așa cum o știai e dusă! + +Fără prieteni, fără familie. Nu mai sunt oameni. +Nu oameni obișnuiți, în orice caz. + +Un singur lucru rămas... GENIE! +Și îi vei găsi hoitul împuțit chiar dacă va trebui +să traversezi până în celălalt capăt al universului! +Pentru că acum ești mânios! + +Iar aurul? La naiba cu el, asta e din partea casei. + +.....(va urma).....","Цивилизация, которую ты знал, исчезла! + +Ни друзей, ни родных. Не осталось никого. +Нормальных людей — точно. + +Осталось только одно существо. ДЖИНН! +Ты надерёшь зад этому уроду, даже если +придётся дойти до края вселенной. Теперь +это личное! + +Что насчёт золота? К чёрту, это не ради +денег. + +.....(продолжение следует)..... +",,"Civilisationen som du kände till den är nada! + +Inga vänner, ingen familj. Inga fler människor. +Inte normala människor i alla fall. + +Bara en sak kvar... GENIE! +Och om du måste gå till slutet av +universum kommer du att hitta dess muterade rumpa! +För nu är du förbannad! + +Och guldet? Det här är gratis. + +.....(fortsättning).....","Bildiğiniz medeniyet artık yok! + +Arkadaş yok, aile yok. +Artık insan yok. +En azından normal insanlar. + +Geriye tek bir şey kaldı... GENIE! +Ve eğer sonuna kadar gitmek +zorunda kalırsan mutant +kıçını bulacaksın! +Çünkü şimdi kızgınsın! + +Peki ya altın? +Lanet olsun, bu bedava. + +.....(devam edecek)....." +"You're alive! + +What are those odds, hacker?! +'cause it's crawling with bugs. + +You can't reach the subcommittee, which +means it's been compromised. + + +You... are alone.",X5TEXT,,,,"Jsi naživu! + +Jaké byly naděje, hackeře!? +Protože se to tu hemží bugy. + +Nemůžeš se dostat k podvýboru, což +znamená, že byl kompromitován. + + +Jsi... @[self_cs].","Du er i live! + +Hvad er oddsene, hacker?! +for det vrimler med insekter. + +Du kan ikke nå underudvalget, hvilket +betyder, at det er blevet +kompromitteret. + +Du... er alene.","Du lebst! + +War waren die Chancen, Hacker?! + +Du kannst das Subkommitee nicht +erreichen, was bedeutet, dass es +kompromittiert ist. + +Du... bist alleine.",,"Vi vivas! + +Kia estas la ŝancoj, kodrompisto?! +Ĉar en ĝi svarmas cimoj. + +Vi ne povas atingi la komisionon, +kio signifas, ke ĝi estas okupata. + + +Vi... estas sola.","¡Estás viv@[ao_esp]! + +¡¿Que probabilidades había, hacker?! +Porque esto está lleno de bichos. + +No puedes llegar al subcomité, lo que +significa que ha sido comprometido. + + +Tú... estás sol@[ao_esp].",,"Sinä olet elossa! + +Mitkä todennäköisyydet, hakkeri?! +Sillä se kuhisee ötököitä. + +Et saa tavoitettua alakomiteaa, mikä +tarkoittaa sitä, että se on murrettu. + + +Sinä... olet yksin.","Vous êtes vivant! + +Quelle chance, Hacker! Avec toutes +ces bestioles partout! + +Vous ne pouvez pas contacter le +sous-comité. Cela signifie qu'il est +compromis. + +Vous.. êtes seul.","Még életben vagy! + +Mik voltak az esélyeid hekkerem?! Még a csapból is a bogarak folynak. + +Nem tudod elérni az albizottságot, ami azt jelenti hogy kompromittálódtak. + +Már...csak Te maradtál.","Sei vivo! +Quali sono queste probabilità, hacker?! +Perché i mutanti sono ovunque +Non puoi raggiungere il sottocomitato, +Il che significa che è stato compromesso. +Tu... sei solo.","俺は生きている! + +何か勝ち目はあるか、ハッカー?! +バグ共がそこいらを蠢いている。 +サブコミッティに繋がらないのは、侵入されたと +思っていいだろう。 + +俺は...また一人だ。","아직도 살아있었네! + +귀신 곡할 노릇이야. 안 그래, 해커 친구? 버그 놈들이 그렇게나 +들끓어댔는데 말이지. + +위원회들도 더는 응답을 하지 않아, 아마 놈들도 다 당한 거겠지. + +그래... 자넨 이제 혼자야.","Je leeft nog! +Wat zijn die kansen, hacker?! + +Je kunt het subcommissie niet bereiken, +wat betekent dat het in gevaar is gebracht. + +Je... bent alleen.","Du lever! + +Hva er de oddsene, hacker?! +fordi det kryr av bugs. + +Du kan ikke nå underkomiteen, +noe som betyr at den er +kompromittert. + + +Du... er alene.","Żyjesz! + +Co to za dziwo hakerze?! +Ponieważ pełza wraz z robactwem. + +Nie możesz dotrzeć do podkomitetu, co +oznacza, że musi być kompromis. + +Jesteś... sam.","Você sobreviveu! + +Quais são as chances, hacker?! +Pois há criaturas por toda a parte. + +Você não consegue entrar em contato com +o subcomitê, o que significa que eles estão +em perigo. + + +Você...está sozinh@[ao_ptb].",,"Ești viu! + +Care sunt șansele, hacker?! Pentru că colcăie de +gândaci. + +Nu poți ajunge la comitet, ceea ce înseamnă că +a fost compromis. + + +Ești... singur.","Ты выжил! + +Какая теперь разница, хакер? Это место +просто кишит багами. + +Ты не можешь связаться с подкомитетом. +Похоже, ваш канал связи раскрыт. + + +Ты... остался один. +",,"Du lever! + +Vad är oddsen, hackare?! +Det är en dator som är full av buggar. + +Du kan inte nå underkommittén, vilket betyder att den har blivit komprometterad. + + +Du... är ensam.","Yaşıyorsun! + +Bu ihtimaller nedir, hacker?! +Çünkü böceklerle dolu. + +Alt komiteye ulaşamıyorsunuz, +bu da tehlikeye atıldığı +anlamına geliyor. + + +Sen... yalnızsın." +,,,,,,,,,,,,,,,,,,,,,,,,,,, +GenEmp Corp.,TXT_HACXMAP01,,,,Sídlo GenEmp,,,,Korporacio GenEmp,,,GenEmp-yhtiö,,,,GenEmpコーポ,ZONE 1: 진엠프 주식회사 본부,,,,,,Corporația GenEmp,Корпорация «ГенИмп»,,, +Tunnel Town,TXT_HACXMAP02,,,,Tunelové město,tunnelbyen,Tunnelstadt,,Tunelo Urbeto,Pueblo Túnel,,Tunnelikaupunki,Ville Tunnel,Kanális Község,Città del tunnel,トンネル タウン,ZONE 2: 터널 도시,Tunnelstad,Tunnelbyen,Miasto Tuneli,Cidade Túnel,,Orașul Subteran,Подземный город,,Tunnelstaden,Tünel Kasabası +Lava Annex,TXT_HACXMAP03,,,,Lávová přístavba,,Lavaanbau,,Lafa Anekso,Anexo de Lava,,Laavalaajennus,Annexe de Lave,Láva Szárny,Annesso di lava,ラバ アネックス,ZONE 3: 용암 속 건물,Lava Bijlage,Lava Vedlegg,Aneks Lawy,Anexo de Lava,,Anexa de Lavă,Лавовая электростанция,,, +Alcatraz,TXT_HACXMAP04,,,,,,,,Alkatrazo,,,,,Alkatraz,,アルカトラズ,ZONE 4: 알카트라즈,,,,,,,Алькатрас,,, +Cyber Circus,TXT_HACXMAP05,,,,Kybercirkus,Cybercirkus,Cyberzirkus,,Cibernetika Cirko,Circo Cibernético,,Kybersirkus,,Kiber Cirkusz,Circo Cyber,サイバーサークル,ZONE 5: 사이버 서커스,,Cyber sirkus,Cyber Cyrk,Circo Cibernético,,Circ Cibernetic,Киберцирк,,Cybercirkus,Siber Sirk +Digi-Ota,TXT_HACXMAP06,,,,,,,,,,,,,,,デジ - オータ,ZONE 6: 디지-오타,,,,,,,Диджитал-Ота,,, +The Great Wall,TXT_HACXMAP07,,,,Velká zeď,Den store mur,Die große Mauer,,La Grandega Muro,La Gran Muralla,,Suuri muuri,La grande Muraille,A Nagy Fal,Il grande muro,ザ - グレート ウォール,ZONE 7: 만리장성,De grote muur,Den kinesiske mur,Wielka Ściana,A Grande Muralha,,Marele Zid,Великая стена,,Den stora muren,Büyük Duvar +Garden of Delights,TXT_HACXMAP08,,,,Zahrada rozkoše,Dejlighedernes have,Lustgarten,,Ĝardeno de Ĝuoj,Jardin de las Delicias,,Nautintojen puutarha,Jardin de Délices,A Gyönyör Kertje,Giardino delle delizie,ガーデン オブ デライト,ZONE 8: 쾌락의 정원,Tuin van lekkernijen,Gledenes hage,Ogród Zachwytu,Jardim dos Prazeres,,Grădina Plăcerilor,Сад наслаждений,,Lustarnas trädgård,Lezzet Bahçesi +Hidden Fortress,TXT_HACXMAP09,,,,Skrytá pevnost,Skjulte fæstning,Versteckte Festung,,Kaŝita Fortreso,Fortaleza Oculta,,Salainen linnoitus,Forteresse Secrète,Eltitkolt Erőd,Fortezza nascosta,ヒドゥン フォートレス,ZONE 9: 숨겨진 요새,Verborgen Vesting,Skjult festning,Ukryta Forteca,Fortaleza Oculta,,Fortăreața Ascunsă,Скрытая крепость,,Dolda fästningen,Gizli Kale +Anarchist Dream,TXT_HACXMAP10,,,,Anarchistův sen,Anarkistisk drøm,Anarchistentraum,,Anarkia Sonĝo,Sueño Anarquista,,Anarkistin unelma,Rève d'Anarchiste,Anarchista Álom,Sogno anarchico,アナーキスト ドリーム,ZONE 10: 아나키스트의 꿈,Anarchistische droom,Anarkistisk drøm,Sen Anarchisty,Sonho Anarquista,,Vis Anarhist,Анархистская утопия,,Anarkistisk dröm,Anarşist Rüya +Notus Us!,TXT_HACXMAP11,,,,,,,,,¡Notus Us!,,Pane merkille mEIdät!,,,,ワレラノ ノータス,ZONE 11: 노터스 어스!,,,,,,Nu ne vor uita!,Нас не забудут!,,, +Gothik Gauntlet,TXT_HACXMAP12,,,,Gotický trest,,,,Gotika Spaliro,Guantelete Gótiko,,Goottinen kujanjuoksu,Gantelet Gothik,Gótikus Vesszőfutás,,ゴシック ガントレット,ZONE 12: 고딕풍 결투장,,Gothik hanske,Gotycka Rękawica,Punição Gótika,,Mănușa Gotică,Готическая перчатка,,Gotik Utmaning, +The Sewers,TXT_HACXMAP13,,,,Kanály,Kloakkerne,Die Kanäle,,La Kanaloj,Las Alcantarillas,,Viemärit,Les Egouts,A Kanális,Le fogne,ザ・サワー,ZONE 13: 하수 처리장,De Riolen,Kloakken,Ścieki,Os Esgotos,,Canale,Канализация,,Avloppen,Kanalizasyonlar +Trode Wars,TXT_HACXMAP14,,,,Válka elektrod,,Elektrodenkrieg,,Milito de Elektrodoj,Guerra de Electrodos,,Trodisodat,Guerre des Trodes,Trode Háborúk,Guerra degli elettrodi,トレード ウォーズ,ZONE 14: 전격의 전쟁,Trode oorlogen,Trode-krigene,Wojna Elektrod,Guerra de Eletrodos,,Război cu Electrozi,Торговые войны,,Elektrodekrig,Elektrot Savaşları +Twilight of Enk's,TXT_HACXMAP15,,,,Soumrak EnKu,Enk's tusmørke,Zwielicht von EnK,,Krespusko de EnK-oj,Crepúsculo de los Enk,,EnKin illankoitto,Crépuscule des Enk's,Enk Alkonya,Crepuscolo di Enk,Enkタチ ノ トワイライト,ZONE 15: 전자황혼,Schemering van Enk's,Skumring av Enk's,Zmierzch Enk,Crepúsculo de Enk's,,Amurgul lui Enk,Сумерки EnK,,Skymning av Enks,Enk'in Alacakaranlığı +Protean Cybex,TXT_HACXMAP16,,,,Proměnlivý Cybex,,Proteanischer Cybex,,Protea Cybex,Cybex Proteico,,Muuntuvainen Kybex,,,,プロテアン サイベックス,ZONE 16: 변화무쌍한 사이벡스,Proteanische Cybex,,Zmienny Cybex,Cybex Proteano,,Cybex Caleidoscopic,Многоликий Сайбэкс,,Proteanska Cybexen, +River of Blood,TXT_HACXMAP17,,,,Řeka krve,Blodets flod,Blutfluss,,Rivero de Sango,Río de Sangre,,Verivirta,Rivière de Sang,Vérfolyó,Fiume di sangue,リバー オブ ブラッド,ZONE 17: 학살의 강,Rivier van bloed,Blodets elv,Rzeka Krwi,Rio de Sangue,,Râu de Sânge,Река крови,,Blodets flod,Kan Nehri +Bizarro,TXT_HACXMAP18,,,,Bizár,,,,,,,,,,,ビザロ,ZONE 18: 요상한 곳,,,,,,,Бизарро,,, +The War Rooms,TXT_HACXMAP19,,,,Válečné kabinety,Krigsrummene,Kriegsräume,,La Militĉambroj,Las Salas de Guerra,,Sotahuoneet,La Salle des Commandes,Háborús Terem,Le stanze della guerra,ザ・ウォー ルーム,ZONE 19: 전략 회의실,De oorlogskamers,Krigsrommene,Pokoje Wojny,As Salas de Comando,,Camerele de Control,Генеральный штаб,,Krigsrummen,Savaş Odaları +Intruder Alert!,TXT_HACXMAP20,,,,"Pozor, vetřelec!",Advarsel om ubudne gæster!,Eindringlingsalarm!,,Alarmo pri Entrudanto!,¡Alerta de Intruso!,,Murtohälytys!,"Alerte, Intrus!",Betolakodó Riadó!,Allarme intruso!,シンニュウシャ アリ!,ZONE 20: 칩입자 경보!,Inbreker alarm!,Inntrengeralarm!,Alarm Intruz!,Alerta de Intruso!,,Alertă Intrus!,Тревога! Нарушитель!,,Inkräktare!,Hırsız Alarmı! +Desiccant Room,TXT_HACXMAP31,,,,Sušící místnost,Tørremiddel-rummet,Trocknungsraum,,Ĉambro de Elsekigo,Sala del Desecante,,Kuivatesali,Salle du Desiccant,Szárító Szoba,Stanza disseccante,ダスキン ルーム,ZONE 31: 건조한 곳,Drogende kamer,Tørkerommet,Śluza Osuszająca,Sala do Dessecante,,Camera Desicanților,Сушильная комната,,Sorptionsmedel rum,Kurutucu Oda +"Now Arriving At... +",STSTR_CLEV,,,,Příjezd do...,"Nu ankommer vi til... +",Angekommen bei...,,Nun Ĝisirante...,Ahora llegando a...,,Seuraavana...,On arrive maintenant à:,Következő állomás...,Arrivando a...,今到着した...,이동하는 중...,Nu we aankomen bij....,"Nå ankommer... +",Wchodzisz do...,Agora chegando em ...,,Acum Sosiți La...,Переходим на...,,"Nu anländer vi till... +","Şimdi Geliyor... +" +...gonna fry your ass!,STSTR_CHOPPERS,"Printed when entering the idchoppers cheat, which gives the player a chainsaw",,,...ti upeče prdel!,...vil stege din røv!,...ich brate deinen Arsch!,,...fritos vian pugon!,... ¡voy a freirte el trasero!,,...kärtsää takalistosi!,...C'est l'heure de botter du cul!,...indulhat a sütögetés!,....ti friggerà il culo!,...ケツまくれ!,... 지져버리겠어!,...gaat je kont bakken!,...kommer til å steke ræva di!,...skopię ci dupę!,...vou fritar teu rabo!,,...te voi prăji!,...поджарит твою задницу!,,...kommer att steka ditt arsle!,...kıçınızı kızartacak! +"inVuln, Str, Inviso, Rad, Allmap, or Lite-amp?",STSTR_BEHOLD,"Hacx's content here was totally useless so it got removed. However, this string has to be defined and minimally altered so that the Dehacked replacement is not being triggered.",,,"nesmrt(V), Síla, nevId, Rad, mApa nebo světLo","inVuln, Str, Inviso, Rad, Allmap, eller Lite-amp?","inVuln, Str, Inviso, Rad, Allmap, oder Lite-amp",,"inVuln, Str, Inviso, Rad, Allmap, aŭ Lite-amp?","inVuln, Str, Inviso, Rad, Allmap, o Lite-amp.",,"haavoittumattomuus (V), voima (S), näkymättömyys (I), koko kartta (A) tai valonvahvistus (L)?","in V ulnérable, S urpuissance, I nvisible, p R otection, c A rte, où L umière?","Sérthet (V), Berz (S), Láthat(i), Sugár(R), Térkép(A), vagy Fény Sisak(L)","inVuln, berSerk, Invisib, tuta anti-Rad, mAppa tutta, o amplif-Luce","V,I,S,R,A,Lのどれだ?","무적, 광전사, 투명, 보호복, 지도, 아니면 바이저?",,"inVuln, Str, Inviso, Rad, Allmap eller Lite-amp?","niezniszczalność (V), siła (S), niewidzialność (I), kombinezon (R), mapa (A) lub gogle noktowizyjne (L)","inVuln., berSerk, Invisib., anti-Rad., mApa completo ou amplificação de Luz",,"inVul, Forță ampl, Invizib, Hartă compl, sau Vedere amplificată?","Бессм. (V), берс. (S), нев. (I), кос. (R), крт. (A), виз (L).","нерањ., снага, невидљ., радиј., мапа или ноћ. визор","inVuln, Str, Inviso, Rad, Allmap eller Lite-amp?","inVuln, Str, Inviso, Rad, Allmap veya Lite-amp?" +Let's Get Serious!,STSTR_BEHOLDX,,,,Teď je to vážné!,Lad os blive seriøse!,Es wird ernst!,,Ni Serioziĝu!,¡Vamos en Serio!,,Otetaanpa tosissaan!,Passons aux choses sérieuses!,Ennek fele sem Tréfa!,Prendiamoci sul serio!,マジになったぜ!,철들 때다!,Laten we serieus worden!,La oss bli seriøse!,Bądźmy Poważni!,Agora a Coisa Fica Séria!,,Să Devenim Serioși!,А теперь серьёзно!,,Nu blir det allvar!,Ciddileşelim! +Cyberslicer Mode ON,STSTR_NCON,,,,Režim kybersekače ZAP,Cyberslicer tilstand TIL,Cyberschnetzelmodus AN,,Cibernetika Tranĉila Reĝimo AKTIVA,Modo Cibercorte ACTIVADO,,Kyberviipaloijatila PÄÄLLÄ,,Kibervágó Mód BE,Modalità Cyberslicer ATTIVADA,サイバースライサーモード オン,전자마귀 모드 ON,Cyberslicer-modus AAN,Cyberslicer-modus PÅ,Tryb Cybercięcia WŁĄCZONY,Cibercortador ATIVADO,,Modul Cibertăietor ACTIVAT,Режим киберрезака ВКЛЮЧЁН,,Cyberslicer-läge PÅ,Siber dilimleyici Modu AÇIK +Cyberslicer Mode OFF,STSTR_NCOFF,,,,Režim kybersekače VYP,Cyberslicer tilstand FRA,Cyberschnetzelmodus AUS,,Cibernetika Tranĉila Reĝimo NEAKTIVA,Modo Cibercorte DESACTIVADO,,Kyberviipaloijatila POIS PÄÄLTÄ,,Kibervágó Mód KI,Modalità Cyberslicer DISATTIVADA,サイバースライサーモード オフ,전자마귀 모드 OFF,Cyberslicer-modus UIT,Cyberslicer-modus AV,Tryb Cybercięcia WYŁĄCZONY,Cibercortador DESATIVADO,,Modul Cibertăietor DEZACTIVAT,Режим киберрезака ОТКЛЮЧЁН,,Cyberslicer-läge AV,Siber dilimleyici Modu KAPALI +Selection: Impossible ,STSTR_NOMUS,,,,Nemožný výběr,Forkert valg,Falsche Auswahl,,Elekto: Malebla,Selección impossible,,Valinta ei mahdollinen,Séléction Impossible!,Lehetetlen Kiválasztás,Selezione impossibile,選択: 不可能,선택 불가능,Selectie: Onmogelijk,Valg: Umulig,Niemożliwy wybór,Seleção: Impossível,,Selectare: Imposibilă,Выбор: Невозможен,НЕМОГУЋИ ИЗБОР,Urval: Impossible,Seçim: İmkansız +"Pump Up The Volume +",STSTR_MUS,Should probably not be translated...,,,Zesil to!,,,,,,,Nuppi kaakkoon,,Csavard Fel a Szőnyeget,,音量を上げろよ,볼륨을 올려라!,,"Pump opp volumet +",Podkręć Audio,"Som na Caixa, DJ!",,Mărește Volumul,Подкрутите громкость,,"Pumpa upp volymen +","Sesi Yükseltin +" +INIT-Twitch n'Kill Mode,STSTR_KFAADDED,,,,Inicializuji režim Twitch and Kill,INIT-Twitch n'Kill Mode,Initiiere Twitch'n Kill-Modus,,INIC-Modo de Tiku kaj Buĉu,INIT-Modo Tirar a Matar,,INIT-Nykäise ja nylje -tila,,Twitch n'Kill Mód Betöltése,Iniziare Twitch n'Kill Mode,INIT-Twitch n'Killモード,때리고 죽이는 모드 ON,,INIT-Twitch n'Kill-modus,Inicjacja Trybu Drżenia I Zabijania,Inicializando Modo Chumbo Grosso,,INIT-Modul Click-și-Elimină,ИНИЦ: режим «Дрожи и убивай»,,INIT-Twitch n'Kill Mode,INIT-Twitch n'Kill Modu +"So be it, Hacker.",STSTR_FAADDED,,,,"Budiž, Hackeře.","Sådan skal det være, Hacker.","So sei es, Hacker.",,"Tiel estu, Kodrompisto.","Que así sea, Hacker.",,"Olkoon niin, hakkeri.","Qu'il en soit ainsi, hacker.","Akkor hát legyen, hekker.","Cosi' sia, Hacker.",好きにしろ、ハッカー。,"마음대로 해, 해커 양반.","Het zij zo, Hacker.","Som du vil, Hacker.","Niech tak będzie, Hakerze.","Que assim seja, Hacker.",,"Așa să fie, Hacker.","Да будет так, хакер.",,"Så får det bli, Hacker.","Öyle olsun, Hacker." +Cyberpotence Mode ON,STSTR_DQDON,,,,Režim kybermoci ZAP,Cyberpotens-tilstand TIL,Cyberpotenzmodus AN,,Cibernetikpova Reĝimo AKTIVA,Modo Ciberpotencia ACTIVADO,,Kyberpotenssitila PÄÄLLÄ,,Kibererő Mód BE,Modo Cyberpotenza ATTIVADA,サイバーポテンスモード オン,전지전능 모드 ON,Cyberpotentiemodus AAN,Cyberpotensmodus PÅ,Tryb Cyberpotencji WŁĄCZONY,Ciberpotência ATIVADA,,Ciberpotență ACTIVATĂ,Режим киберулучшения ВКЛЮЧЁН,,Cyberpotens-läge PÅ,Siber güç Modu AÇIK +Cyberpotence Mode OFF,STSTR_DQDOFF,,,,Režim kybermoci VYP,Cyberpotens-tilstand FRA,Cyberpotenzmodus AUS,,Cibernetikpova Reĝimo NEAKTIVA,Modo Ciberpotencia DESACTIVADO,,Kyberpotenssitila POIS PÄÄLTÄ,,Kibererő Mód KI,Modo Cyberpotenza DISATTIVADA,サイバーポテンスモード オフ,전지전능 모드 OFF,Cyberpotentiemodus UIT,Cyberpotensmodus AV,Tryb Cyberpotencji WYŁĄCZONY,Ciberpotência DESATIVADA,,Ciberpotență DEZACTIVATĂ,Режим киберулучшения ОТКЛЮЧЁН,,Cyberpotens-läge AV,Siber güç Modu KAPALI +Tracking ON,AMSTR_FOLLOWON,,,,Sledování ZAP,Sporing TIL,Verfolgung AN,,Spurdado AKTIVA,Seguimiento ACTIVADO,,Seuranta PÄÄLLÄ,,Követés BE,Mappa scorribile DISATTIVATA,トラッキング オン,추적 모드 ON,Tracking AAN,Sporing PÅ,Namierzanie WŁĄCZONE,Seguimento ATIVADO,,Urmărire ACTIVATĂ,Сопровождение ВКЛЮЧЕНО,,Spårning PÅ,İzleme AÇIK +Tracking OFF,AMSTR_FOLLOWOFF,,,,Sledování VYP,Sporing FRA,Verfolgung AUS,,Spurdado NEAKTIVA,Seguimiento DESACTIVADO,,Seuranta POIS PÄÄLTÄ,,Követés KI,Mappa scorribile ATTIVATA,トラッキング オフ,추적 모드 OFF,Tracking UIT,Sporing AV,Namierzanie WYŁĄCZONE,Seguimento DESATIVADO,,Urmărire DEZACTIVATĂ,Сопровождение ОТКЛЮЧЕНО,,Spårning AV,İzleme KAPALI +- press Y to run away! -,DOSY,,,,- stiskni Y pro útěk! -,- Tryk på Y for at løbe væk! -,- drücke Y um wegzurennen -,,- premu Y por forkuri! -,- ¡pulsa Y para escapar! - ,,- Paina Y paetaksesi! -,-Appuie sur Y pour t'échapper!-,- nyomj Y-t a nyúlcipő felhúzáshoz -,- premere Y per scappare! -,-Y でトンズラだ!-,- 달아날려먼 Y 키를 눌러! -,- druk op Y om weg te lopen! -,- trykk Y for å stikke av! -,- wciśnij Y by uciec! -,- Aperte Y para fugir! -,- Carrega Y para fugir! -,- apasă Y pentru a fugi! -,"- нажми «Y», чтобы сбежать! -",,- Tryck på Y för att springa iväg! -,- Kaçmak için Y'ye basın! - +"Are you insane or maladjusted? +Well? Yes or No!",ENDGAME,,,,"Jsi blb@[adj_cs] nebo jen naveden@[adj_cs]? +Tak? Jo nebo ne?","Er du sindssyg eller utilpasset? +Nå? Ja eller nej!","Bist du verrückt oder mies gelaunt? +Also? Ja oer Nein?",,"Ĉu vi estas freneza aŭ misagordita? +Ĉu? Jes aŭ Ne!?","¿Estás loc@[ao_esp] o descolocad@[ao_esp]? +¿Y bien? ¿Sí o No?",,"Oletko hullu tai häiriintynyt? +No? Y tai N!",Vous êtes fou où malajusté? Eh bien? Oui où non?,"Őrült vagy, vagy csak simán rosszul vagy összerakva? Nos? Igen vagy Nem!","Sei pazzo o disadattato? +Allora? Sì o no!","お前はイカれた社会不適合者だろ? +あぁ?イエスかノーか言え!","부적응은 안 하겠지? 그렇겠지? +자신 있으면 선택해!","Ben je gek of onaangepast? +Nou? Ja of Nee!",Er du sinnssyk eller mistilpasset? Nå? Ja eller Nei!,"Oszalałeś czy się nie dostosowałeś? +Więc? Tak czy Nie!","Você é doido ou desregulado? +Hein? Sim ou Não!",,"Ești nebun sau doar prost calibrat? +Deci? Da sau Nu?","Ты дурак или родом так? +Отвечай! Да (Y) или нет (N)?",,Är du galen eller missanpassad? Nå? Ja eller nej!,Deli misin yoksa uyumsuz mu? Evet mi? Evet ya da hayır! +"Are you sure? You can't handle +this skill, hacker! + +Press Y to die. +",NIGHTMARE,,,,"Jseš si jist@[adj_cs]? Takový +skill nemáš, hackeře!","Er du sikker? Du kan ikke klare +denne færdighed, hacker! + +Tryk på Y for at dø. ","Bist du sicher? Du kannst das nicht bewältigen, Hacker! + +Drücke Y um zu sterben.",,"Ĉu vi certas? Vi ne povas stari +kontraŭ ĉi tiu malfacileco, kodrompisto! + +Premu Y por morti.","¿Estás segur@[ao_esp]? ¡No puedes soportar esta dificultad, hacker! + +Pulsa Y para morir.",,"Oletko varma? Et pysty käsittelemään +tätä taitotasoa, hakkeri! + +Paina Y kuollaksesi. +","Vous êtes sûr? Vous n'arriverez pas à tenir le coup, hacker! + +Appuyez sur Y pour mourir.","Biztos vagy benne? Nem hinném hogy elbírsz ezzel a fokozattal hekker. + +Nyomj Y-t a halálhoz.","Sei sicuro? Non puoi gestire +questa abilità, hacker! + +Premere Y per morire. ","本気か? +アンタの手に負えないぞ、ハッカー! + +死にたきゃYを押せ。","그렇게 만만하다면 말리지는 않을게. +어차피 너에겐 복잡할 테니까, 해커 양반. + +준비됐으면 Y 키를 눌러.","Weet u het zeker? Je kunt niet omgaan met +deze vaardigheid, hacker! + +Druk op Y om te sterven.","Er du sikker? Du kan ikke håndtere denne ferdigheten, hacker! Trykk Y for å dø.","Na pewno? Nie dasz +sobie rady hakerze! + +Wciśnij Y by zginąć.","Tem certeza? Você não vai conseguir +aguentar essa dificuldade, hacker! + +Aperte Y para morrer.","Tem certeza? Você não pode lidar +essa habilidade, hacker! + +Carrega Y para morrer.","Ești sigur? Nu poți face față dificultății, hacker! + +Apasă Y ca să mori.","Ты уверен? С этим уровнем сложности ты не справишься, хакер! + +Нажми «Y», чтобы умереть.",,"Är du säker? Du klarar inte av den här färdigheten, hackare! Tryck på Y för att dö.","Emin misin? Bu yetenekle başa çıkamazsın, hacker! Ölmek için Y'ye bas." +"Quicksave over your data named + +'%s'? + +Press Y or N.",QSPROMPT,For most languages the original Doom text should suffice.,,,"Rychle uložit přes tvá data s názvem + +'%s'? + +Stiskni Y nebo N.","Quicksave over dit spil navngivet + +'%s'? + +Tryk på Y eller N.","Überschreibe %s mit einem Schnellspeicherdatenstand? + +Drücke Y oder N.",,"Ĉu rapidkonservi anstataŭigante vian ludadon nomitan + +'%s'? + +Premu Y aŭ N.","¿Deseas guardar sobre tu partida llamada + +'%s'? + +Presiona Y ó N.",,"Haluatko pikatallentaa pelin %s päälle? + +Paina Y tai N.","Sauvegarde rapide sur le fichier + +'%s'? + +Appuyez sur Y ou N.","Gyorsmenteni akarsz az alábbi mentésed alatt + +'%s'? + +Nyomj Y-t vagy N-t.","Sovrascrivere il salvataggio + +'%s'? + +Premi Y oppure N.","この名称で上書きするのか? + +'%s' + +YかNで答えろ。","빠른 저장? + +'%s' + +Y키 또는 N키를 입력.","Snel opslaan over je spel genaamd + +'%s'? + +Druk op Y of N.","Overskrive %s med en hurtiglagring? + +Trykk på Y eller N.","Szybko nadpisać grę + +„%s”? + +Wciśnij Y lub N.","Salvar sobre seu jogo chamado + +'%s'? + +Aperte Y ou N.","Gravar sobre o seu jogo chamado + +'%s'? + +Carrega Y ou N.","Salvare rapidă peste fișierul numit + +'%s'? + +Apasă Y sau N.","Перезаписать файл + +«%s»? + +Нажмите «Y» или «N».","Желите брзо чување за игру под именом + +„%s“? + +Притисните Y или N.",, +"Do you want to quickload the data named + +'%s'? + +Press Y or N.",QLPROMPT,,,,"Přeješ si rychle načíst data s názvem + +'%s'? + +Stiskni Y nebo N.","Ønsker du at quickloade spillet ved navn + +'%s'? + +Tryk på Y eller N.","Möchtest du den Datenstand %s schnellladen? + +Drücke Y oder N.",,"Ĉu vi volas rapidŝargi la ludadon nomitan + +'%s'? + +Premu Y aŭ N.","¿Deseas cargar la partida llamada + +'%s'? + +Presiona Y ó N.",,"Haluatko pikaladata pelin %s? + +Paina Y tai N.","Voulez-vous charger la sauvegarde + +'%s'? + +Appuyez sur Y ou N.","Gyorstölteni akarod ezt a mentést + +'%s'? + +Nyomj Y-t vagy N-t.","Vuoi fare un quickload della partita + +'%s'? + +Premi Y oppure N.","この名称をすぐロードするのか? + +'%s' + +YかNで答えろ。","빠른 불러오기? + +'%s' + +Y키 또는 N키를 입력.","Wil je het spel snel laden met de naam + +'%s'? + +Druk op Y of N.",,"Czy chcesz wczytać szybki zapis + +„%s”? + +Wciśnij Y lub N.","Deseja carregar o jogo chamado + +'%s'? + +Aperte Y ou N.","Deseja carregar o jogo chamado + +'%s'? + +Carrega Y ou N.","Vrei să încarci rapid fișierul numit + +'%s'? + +Apasă Y sau N.","Загрузить файл + +«%s»? + +Нажмите «Y» или «N».","Желите брзо учитавање за игру под именом + +„%s“? + +Притисните Y или N.",, +Thug,CC_THUG,,,,Pobuda,Bølle,Scherge,,Perfortuloj,Matón,,Roisto,Brute,Bandatag,Tazza,チンピラ,서그,Schurk,Kjeltring,Zbir,Bandido,,Bandit,Головорез,,Buse,Eşkıya +Android,CC_ANDROID,,,,,,,,Androido,Androide,,Androidi,Androïde,,,アンドロイド,안드로이드,Androïde,,,Andróide,,,Андроид,,, +ICE,CC_ICE,,,,,,,,,,,,,,,アイス,아이스,,,,,,,ЛЁД,,,BUZ +Buzzer,CC_BUZZER,,,,Bzučák,,Summer,,Zumilo,Zumbador,,Surisija,,Sokkoló,Cicalino,ブザー,버저,Zoemer,Summer,Brzęczyk,,,Dronă,Летун,,Summer,Şok Uçağı +D-Man,CC_DMAN,,,,,,,,D-Vir',,,D-mies,,,,,디-맨,,,,,,,Ди-Мэн,,, +Phage,CC_PHAGE,,,,Fág,,,,Faĝo,Fago,,Fagi,,Fekély,Fago,ファージ,페이지,Faag,Phage,Fag,Fago,,Mâncător,Пожиратель,,,Faj +Monstruct,CC_MONSTRUCT,,,,Monstrukce,,Monstrukt,,Monstrukto,,,Keinohirviö,,Monstrum,Mostrutto,モンストラクト,몬스트럭트,Monstructie,,Monstrukt,,,,Монструкт,,, +Mecha Maniac,CC_MECH,,,,Mechamaniak,,,,Mekanika Frenezulo,Meca-Maníaco,,Mechamaanikko,Mécha-maniaque,Mecha Megszállott,Mecha Maniaco,メカマニア,메카 메니악,Mecha Maniak,,Mechaniczny Maniak,Meca-Maníaco,,Meca-Maniac,Механоман,,,Meka Manyağı +Terminatrix,CC_TERMI,,,,,,,,,,,,,,,ターミネイトリクス,터미네트릭스,,,,,,,Терминатриса,,, +Thorn Thing,CC_THORN,,,,Bodlák,Torn ting,Dornending,,Dorna Aĵo,Cosa Espinosa,,Okaolio,Truc épineux,Tövis Úrnő,,ソーンツィン,쏜 씽,Doornding,Torneting,Cierniowe Coś,Coisa Espinhosa,,Spinos,Тернистая тварь,,Tornen ting,Dikenli Şey +Majong 7,CC_MAJONG,,,,,,,,Maĝango 7,,,Mahjong 7,,,,マージャン 7,마작 7호,,,,,,,Маджонг 7,,, +Dan Evanger,CC_HERO,,,,,,,,Dan Evanĝer,,,,,,,ダン エブァンガー,댄 에반저,,,,,,,Дэн Эвенджер,,, +Please don't shoot!,SKILL_BABY,,,,"Nestřílej, prosím!",Lad være med at skyde!,Bitte schieß nicht!,,Bonvolu ne pafi!,¡Por favor no dispares!,,"Pyydän, älä ammu!","Pitié, ne tirez pas!",Kérlek ne lőj!,"Ti prego, non sparare!",撃たないでくれ!,쏘지 마세요!,"Niet schieten, alsjeblieft!","Vær så snill, ikke skyt!",Proszę nie strzelaj!,"Por favor, não atire!",,Te rog nu trage!,"Не стреляй, пожалуйста!",,"Snälla, skjut inte!",Lütfen ateş etmeyin! +"Aargh, I need health!",SKILL_EASY,,,,Potřebuju zdraví!,"Aargh, jeg har brug for sundhed!",Ich brauche Gesundheit!,,"Aargh, mi bezonas sanon!","¡Aargh, necesito salud!",,"Aargh, tarvitsen terveyttä!","Aargh, des soins!","Á, kell egy kis életerő!","Aargh, ho bisogno di salute!",キメてくれ!,체력이 필요해!,"Aargh, ik heb gezondheid nodig!","Aargh, jeg trenger helse!","Ałć, potrzebuję apteczki!","Aargh, preciso de saúde!",,"Aarș, am nevoie de un medic!","А-а-ргх, аптечку!",,"Aargh, jag behöver hälsa!","Aargh, sağlığa ihtiyacım var!" +Let's rip them apart!,SKILL_NORMAL,,,,Rozsekejme je na kusy!,Lad os flå dem i stykker!,Lass uns sie zerfetzen!,,Ni disŝiru ilin!,¡Rompámoslos en pedazos!,,Revitään ne kappaleiksi!,J'en fais de la bouillie!,Tépjük csak szét őket!,Facciamoli a pezzi!,ばらまいてやれ!,갈기갈기 찢어버려!,Laten we ze uit elkaar scheuren!,La oss rive dem i filler!,Czas ich rozerwać!,Vamos despedaçá-los!,,Să-i facem zob!,Разорвём их на куски!,,Låt oss slita dem i bitar!,Hadi onları parçalayalım! +I am immortal!,SKILL_HARD,,,,Jsem nesmrtelný!,Jeg er udødelig!,Ich bin unsterblich!,,Mi estas senmorta!,¡Soy inmortal!,,Olen kuolemation!,Je suis immortel!,Halhatatlan vagyok!,Sono immortale!,とっととくたばれ!,난 무적이다!,Ik ben onsterfelijk!,Jeg er udødelig!,Jestem nieśmiertelny!,Eu sou imortal!,,Sunt nemuritor!,Я бессмертен!,,Jag är odödlig!,Ben ölümsüzüm! +Insanity!,SKILL_NIGHTMARE,,,,Šílenství!,Sindssyge!,Wahnsinn!,,Frenezo!,¡Locura!,,Mielettömyys!,Folie!,Téboly!,Follia!,イカれてやがる!,코드명: 광기!,Waanzin!,Galskap!,Szaleństwo!,Insanidade!,,Demență!,Безумие!,,Galenskap!,Delilik! \ No newline at end of file diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0100.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0100.lmp new file mode 100644 index 00000000000..5d439a0de27 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/010A.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/010A.lmp new file mode 100644 index 00000000000..595ff68bd16 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0112.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0112.lmp new file mode 100644 index 00000000000..550db7bacc3 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0116.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0116.lmp new file mode 100644 index 00000000000..5e782d64e7a Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/011E.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/011E.lmp new file mode 100644 index 00000000000..f485f317e18 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0120.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0120.lmp new file mode 100644 index 00000000000..ee4c9e5d6ec Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0122.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0122.lmp new file mode 100644 index 00000000000..d1ec70f8c6c Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0126.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0126.lmp new file mode 100644 index 00000000000..6382420abef Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/012A.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/012A.lmp new file mode 100644 index 00000000000..7e1d343f70b Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/012E.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/012E.lmp new file mode 100644 index 00000000000..1e45e311cde Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0130.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0130.lmp new file mode 100644 index 00000000000..cdf0d5cd98a Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0136.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0136.lmp new file mode 100644 index 00000000000..9ac46a52c03 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0139.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0139.lmp new file mode 100644 index 00000000000..9dc19f7cc08 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/013B.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/013B.lmp new file mode 100644 index 00000000000..4a381c9dc4a Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/013D.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/013D.lmp new file mode 100644 index 00000000000..9f696adc401 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0145.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0145.lmp new file mode 100644 index 00000000000..34a5e0aa8da Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/014A.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/014A.lmp new file mode 100644 index 00000000000..f1b05e29ba4 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/014C.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/014C.lmp new file mode 100644 index 00000000000..8d3ca3d2847 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0154.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0154.lmp new file mode 100644 index 00000000000..f138eb4e7f5 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0166.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0166.lmp new file mode 100644 index 00000000000..ee5f4eb7986 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/016A.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/016A.lmp new file mode 100644 index 00000000000..3309409550d Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0172.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0172.lmp new file mode 100644 index 00000000000..aa54dfa4867 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0174.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0174.lmp new file mode 100644 index 00000000000..1bce22ad43d Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0176.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0176.lmp new file mode 100644 index 00000000000..ce175d33d32 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/018F.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/018F.lmp new file mode 100644 index 00000000000..d2b2993bbfa Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/01FC.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/01FC.lmp new file mode 100644 index 00000000000..e156bd1cac2 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/01FE.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/01FE.lmp new file mode 100644 index 00000000000..ee28a8d1dc7 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0394.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0394.lmp new file mode 100644 index 00000000000..a3d128a48ce Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0398.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0398.lmp new file mode 100644 index 00000000000..3b8fdb43cb8 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/039B.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/039B.lmp new file mode 100644 index 00000000000..626847e2bc0 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/039E.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/039E.lmp new file mode 100644 index 00000000000..14d9ae1b323 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A3.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A3.lmp new file mode 100644 index 00000000000..005903b8a19 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A8.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A8.lmp new file mode 100644 index 00000000000..2eeb5d739f2 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A9.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A9.lmp new file mode 100644 index 00000000000..93d9e1fca17 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0403.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0403.lmp new file mode 100644 index 00000000000..857efd6fdb1 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0404.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0404.lmp new file mode 100644 index 00000000000..071b831bc1a Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040C.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040C.lmp new file mode 100644 index 00000000000..67545e95220 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040D.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040D.lmp new file mode 100644 index 00000000000..8c49345bbf8 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040E.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040E.lmp new file mode 100644 index 00000000000..c63a01d2230 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0490.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0490.lmp new file mode 100644 index 00000000000..c1dc8133aca Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E80.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E80.lmp new file mode 100644 index 00000000000..27c3dba5984 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E82.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E82.lmp new file mode 100644 index 00000000000..2eaa9858aec Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E84.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E84.lmp new file mode 100644 index 00000000000..afed22c824f Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1EF2.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1EF2.lmp new file mode 100644 index 00000000000..568aee18af4 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/bigfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0100.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0100.lmp new file mode 100644 index 00000000000..f57d9264071 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0106.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0106.lmp new file mode 100644 index 00000000000..046d14d8648 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0106.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/010A.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/010A.lmp new file mode 100644 index 00000000000..27e371f293e Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0112.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0112.lmp new file mode 100644 index 00000000000..67e8e0c2fb7 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0116.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0116.lmp new file mode 100644 index 00000000000..40c8fca216e Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/011E.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/011E.lmp new file mode 100644 index 00000000000..0c55ec33cc2 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0120.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0120.lmp new file mode 100644 index 00000000000..6c35c652cb5 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0122.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0122.lmp new file mode 100644 index 00000000000..96d7535cf7f Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0126.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0126.lmp new file mode 100644 index 00000000000..03237d91351 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/012A.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/012A.lmp new file mode 100644 index 00000000000..7ea731f8d4c Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/012E.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/012E.lmp new file mode 100644 index 00000000000..31c4f992e94 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0130.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0130.lmp new file mode 100644 index 00000000000..eabc03cd5e4 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0136.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0136.lmp new file mode 100644 index 00000000000..2c0b906bb59 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0139.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0139.lmp new file mode 100644 index 00000000000..78b60fa7a7d Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/013B.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/013B.lmp new file mode 100644 index 00000000000..4cd422ed9fb Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/013D.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/013D.lmp new file mode 100644 index 00000000000..5df97a99110 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0145.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0145.lmp new file mode 100644 index 00000000000..aa1134e4746 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/014A.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/014A.lmp new file mode 100644 index 00000000000..b91ea31e4d2 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/014C.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/014C.lmp new file mode 100644 index 00000000000..e408dc0894d Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0154.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0154.lmp new file mode 100644 index 00000000000..6ad81054739 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0166.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0166.lmp new file mode 100644 index 00000000000..a800fdf6eb5 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/016A.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/016A.lmp new file mode 100644 index 00000000000..a3f55342828 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0172.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0172.lmp new file mode 100644 index 00000000000..bcb5d761dcb Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0174.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0174.lmp new file mode 100644 index 00000000000..a18978d4172 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0176.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0176.lmp new file mode 100644 index 00000000000..1a1475d1428 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/018F.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/018F.lmp new file mode 100644 index 00000000000..b37877ec073 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/01FC.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/01FC.lmp new file mode 100644 index 00000000000..7c7f8b8335d Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/01FE.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/01FE.lmp new file mode 100644 index 00000000000..123a8a6eb7f Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0394.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0394.lmp new file mode 100644 index 00000000000..02ac3a1ad8e Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0398.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0398.lmp new file mode 100644 index 00000000000..95400e265d8 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/039B.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/039B.lmp new file mode 100644 index 00000000000..24c10a6f36d Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/039E.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/039E.lmp new file mode 100644 index 00000000000..dd38ef8bc2a Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A3.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A3.lmp new file mode 100644 index 00000000000..9bf5ff06fd6 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A8.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A8.lmp new file mode 100644 index 00000000000..8e5ca146d30 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A9.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A9.lmp new file mode 100644 index 00000000000..cc5d49f38b0 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0403.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0403.lmp new file mode 100644 index 00000000000..f961b1354c1 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0404.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0404.lmp new file mode 100644 index 00000000000..b4264c336f8 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040C.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040C.lmp new file mode 100644 index 00000000000..4a46b44a893 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040D.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040D.lmp new file mode 100644 index 00000000000..eb90281747a Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040E.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040E.lmp new file mode 100644 index 00000000000..65211722e51 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0490.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0490.lmp new file mode 100644 index 00000000000..d4c05051362 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E80.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E80.lmp new file mode 100644 index 00000000000..3a1c3d729b2 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E82.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E82.lmp new file mode 100644 index 00000000000..5daf394ad06 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E84.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E84.lmp new file mode 100644 index 00000000000..bee8bcebe92 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1EF2.lmp b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1EF2.lmp new file mode 100644 index 00000000000..dfbf7dab1d6 Binary files /dev/null and b/wadsrc_extra/static/filter/hacx.hacx1/fonts/defsmallfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/hacx.hacx1/language.csv b/wadsrc_extra/static/filter/hacx.hacx1/language.csv deleted file mode 100644 index 869793d0bde..00000000000 --- a/wadsrc_extra/static/filter/hacx.hacx1/language.csv +++ /dev/null @@ -1,1141 +0,0 @@ -default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,pl,pt,ptg,ro,ru,sr -,,,,,,,,,,,,,,,,,,,,,,, -These bugs too tough for ya?,QUITMSG1,,,,Jsou ty bugy na tebe moc tvrdé?,Sind diese Bugs zu viel für dich?,,Ĉu ĉi tiuj cimoj estas tro forta por vi?,¿Son estos bichos demasiado duros para ti?,,Taitavat nämä ötökät olla liikaa sulle?,Ces bestioles sont trop fortes pour vous?,,Questi errori sono troppo difficili per te?,テメェにはあんなバグ 厳しかないだろ?,고작 버그들 상대하는 것도 버거운 건가?,Zijn deze bugs te hard voor je?,To robactwo jest za ciężkie dla ciebie?,"Tá achando difícil eliminar esses bugs, é?",,Sunt prea duri gândacii pentru tine?,Эти баги крутоваты для тебя?, -Are you sure you want to\njack out of the action?,QUITMSG,,,,"Jsi si jistý, že se chceš -zdáchnout z akce?","Bist du sicher, dass du den\nStecker ziehen willst?",,"Ĉu vi certas, ke vi volas -malkonektiĝi el la batalo?",¿Estás segur@[ao_esp] de que\nquieres desconectarte de la acción?,,Haluatko varmasti irrottaa\npiuhan toiminnasta?,Etes-vous sûr de vouloir\nvous déconnecter de l'action?,,Sei sicuro di voler uscire?,もしかして逃げ出そうとしてないよな?,"지금 종료하겠다고? - -진심이냐?",Weet je zeker dat je de actie wilt staken?,Na pewo chcesz wyjść w środku akcji?,Tem certeza que quer se desconectar de toda a ação? ,,Ești sigur că vrei să\npărăsești acțiunea?,Ты правда хочешь улизнуть\nс поля боя?, -Trying to quit? And you call yourself a hacker?,QUITMSG2,,,,Snažíš se skončit? To si říkáš hacker?,Du willst gehen? Bist du wirklich ein Hacker?,,Vi provas rezigni? Kaj vi nomas vin kodrompisto?,¿Intentando salir? ¿Y te haces llamar hacker?,,Yritätkö lopettaa? Ja sinäkö muka hakkeri?,On essaye de quitter?\nvous prétendez être un hacker?,,Stai cercando di smettere?\nE ti definisci un hacker?,終了させる? それでハッカー自称してたのか?,그만두려고? 해커라는 이름이 아깝군그래.,Proberen te stoppen? En je noemt jezelf een hacker?,Próbujesz wyjść? I nazywasz siebie hakerem?,Tá querendo sair? E você ainda se acha um hacker?,,Încerci să ieși? Și te mai numești hacker?,Хочешь убежать? А ещё зовёшь себя хакером!, -Get back here before I send a virus up your tailpipe!,QUITMSG3,,,,"Vrať se, než ti do zadku pošlu virus!","Komm zurück, oder ich schick dir 'nen Virus!",,"Revenu ĉi tien antaŭ mi sendos viruson -supren en vian posttubo!",¡Vuelve aquí antes de que te meta un virus de través!,,"Heti takaisin tänne, ennen kuin lähetän viruksen pitkin takaputkeasi!",Reviens ici avant que je t'envoie un virus là où ça fait mal!,,Torna indietro o ti\nmanderò un virus!,さっさと戻らねえと そのケツ穴にウィルスぶっこむぞ!,"돌아와, 네 전선에 바이러스 주입해버리기 전에!",Kom terug voordat ik een virus in je uitlaatpijp stuur!,Wróć tu zanim wyślę ci wirusa!,Volta aqui antes que eu te mande um vírus!,,Treci înapoi aici până nu-ți trimit un virus!,"Вернись, пока я не посадил вирус тебе на хвост!", -Real hackers never jack out of the action.,QUITMSG4,,,,Skuteční hackeři nikdy neprchají z akce.,Echte Hacker geben nicht auf!,,"Veraj kodrompistoj neniam -malkonektiĝi el la batalo.",Los verdaderos hackers no se desconectan de la acción.,,Todelliset hakkerit eivät ikinä kytkeydy irti toiminnasta.,Un vrai hacker ne se déconnecte pas en pleine action.,,I veri hacker non si arrendono!,本物のハッカーなら頭を銃で撃ち抜くことはしない。,진정한 해커는 이렇게 포기하지 않는다고!,Echte hackers komen nooit uit de actie.,Prawdziwi hakerzy nigdy nie uciekają z akcji.,Hackers de verdade nunca vazam da ação!,,Adevărații hackeri nu fug de acțiune.,Настоящие хакеры не пытаются улизнуть с поля боя., -C'mon! You haven't seen the best part yet!,QUITMSG5,,,,No tak! Ještě jsi neviděl to nejlepší!,Komm schon. Du hast das Beste noch gar nicht gesehen!,,Venu! Vi ne ankoraŭ vidis la plej bonan parton!,¡Venga! ¡Aún no has visto la mejor parte!,,Älä viitsi! Et ole edes vielä nähnyt parasta kohtaa!,"Allez, on arrive presque à la meilleure partie!",,"Andiamo, forza! Non hai ancora\nvisto la parte migliore!",おいおい! お楽しみはこれからだぜ!,이봐! 아직 재밌는 부분은 시작도 안 했다고!,Kom op! Je hebt het beste deel nog niet gezien!,No weź! Jeszcze nie widziałeś najlepszej części!,Qual é! Você nem viu a melhor parte ainda!,,Haide! Nu ai văzut partea cea mai bună încă!,"Да ладно, ты ещё не видел самое крутое!", -"Give up now, and cyberspace is toast!",QUITMSG6,,,,Vzdej se a s kyberprostorem je konec!,Wenn du jetzt aufgibst ist der Cyberspace am Ende.,,"Se vi ĉesas nun, tiam retumejo estos detruiĝita!",¡Ríndete ahora y el ciberespacio está frito!,,Luovuta nyt ja kyberavaruus kärtsää!,"Abandonne, et le cyberespace est foutu!",,"Se ti arrendi ora,\nil cyberspazio è finito.",さっさと止めて、サイバースペースに乾杯だ!,포기하면 사이버 공간은 결국엔 사라질걸?,"Geef het nu op, en cyberspace is een toast!","Poddaj się, a cyberprzestrzeń zmieni się w tosta!","Se você desistir agora, o ciberespaço já era!",,"Te dai bătut acum, și spațiul cibernetic e prăjit!","Если ты сейчас сдашься, киберпространству конец!", -"GENIE sends its best regards, scumbag!",QUITMSG7,,,,"GENIE posílá své pozdravy, hajzle!","GENIE sendet seine besten Grüße, Mistkerl!",,"ĜINIO sendas plej siajn konsiderojn, fiulo!","¡GENIE te envía saludos, desgraciado!",,"GENIE lähettää terveisensä, mäntti!","GENIE t'envoie ses salutations, salaud!",,"GENIE manda i suoi\nmigliori saluti, bastardo!",GENIEがベストの挨拶を送るぜ、カス野郎!,어이 등신! 지니에서 안부를 전해 달라더군.,"GENIE doet je de groeten, klootzak!","GENIE przysyła pozdrowienia, łajzo!","GENIE manda lembranças, seu lixo!",,"GENIE își transmite condoleanțele, ticălosule!","Наилучшие пожелания от ДЖИННа, ублюдок!", -"Hmm. So much for being a hero, Hacker.",QUITMSG8,,,,"Hmm. To by bylo pro hrdinství, Hackeře.","Hmm. So viel zum Thema ""Held"", Hacker.",,"Ĥaa. Kia domaĝo, ke vi estas hero, Kodrompisto.","Hmm. Poco tienes de héroe, hacker.",,"Höh, se siitä sankarina olemisesta sitten, hakkeri.","Eh bien, on est pas vraiment un héros, hacker.",,"Hmm. Così tanto per essere un eroe, Hacker.",うーん。英雄とはこの程度だったのか、ハッカー。,영웅이 될 그릇은 아닌 거 같군. 안 그래? 해커 형씨.,"Hmm. Tot zover de held, Hacker.","Hmm. Tak wiele by być bohaterem, Hakerze.","Hmm. Não é tão herói assim, pelo visto.",,"Hmm. Asta a fost cu eroismele, Hacker.","Хм-м. Вот тебе и герой, Хакер!", -What? You'd rather go back to the pen?,QUITMSG9,,,,Co? Radši by ses vrátil do basy?,Was? Du willst in den Knast zurück?,,"Kio? Ĉu vi preferas, ke vi revenu al la plumon?",¿Qué? ¿Prefieres volver al corral?,,Täh? Menisit mieluummin takaisin kynän ääreen?,Quoi? Tu préfère retourner dans ta cellule?,,Cosa? Vuoi tornare in prigione?,何? 今更ペンで計算するのか?,펜이나 끄적거리는 인생으로 돌아가겠다. 이건가?,Wat? Ga je liever terug naar de pen?,Co? Wolisz wrócić do więzienia?,O quê? Prefere voltar pro xilindró?,,Ce? Vrei să te întorci la captivitate?,Что? Ты хочешь вернуться в неволю?, -Shoulda taken the blue pill.,QUITMSG10,,,,Měl sis vzít modrou pilulku.,Du hättest die blaue Pille nehmen sollen...,,Devintu preni la bluan pilolon.,Deberías haber tomado la pastilla azul.,,Olis pitäny ottaa sininen pilleri.,T'aurais du prendre la pilule bleue.,,Avresti dovuto prendere la pillola blu ...,青いピルを採るべきではなかったな。,넌 파란 알약을 골랐어야 했어.,Je had de blauwe pil moeten nemen.,Trzeba było wziąć niebieską pigułkę.,Devia ter tomado a pílula azul.,,Trebuia să iei pastila albastră.,Надо было принять синюю таблетку., -The name of the game ain't Twitch n' Run!,QUITMSG11,,,,V názvu hry není napsané „uteč“!,"Das Spiel heißt nicht ""wegrennen""!",,La nomo de la ludo ne estas Tiku kaj Kuru!,¡El nombre del juego no es Tirar a Correr!,,Pelin nimi ei oo Paniikkipako!,"Le jeu s'appelle pas ""Panique et cours!""",,"Il gioco non significa ""scappare""!",ゲーム名は 萎え落ち小僧 じゃねえぞ!,"이봐, 이 게임은 때리고 도망가는 게임이 아니라고!",De naam van het spel is niet Twitch n' Run!,"Nazwą gry nie jest ""Drżyj i Uciekaj""!",O nome do jogo não é Trema nas Bases e Fuja!,,Numele jocului nu e Tremură și Ascunde-te!,Эта игра называется не «Дрожи и прячься»!, -"No worries. Saving the world can wait, right?",QUITMSG12,,,,"Žádný problém. Záchrana světa může počkat, ne?","Also, die Welt zu retten kann warten, richtig?",,"Ne zorgu. Savi la mondon povas atendi, ĉu ne?","No te preocupes. Salvar el mundo puede esperar, ¿verdad?",,"Ei huolta; maailman pelastaminen voi odottaa, eikö niin?","Oh, pas de problème. Le monde peut attendre\nd'être sauvé, non?",,"Salvare il mondo può\naspettare, giusto?",気にはしない、世界を救うのは何時でも出来る、だろ?,걱정 말라고. 세상이 위험한데 급할 것 있나. 안 그래?,"Het redden van de wereld kan wachten, toch?","Bez obaw. Ratowanie świata może poczekać, prawda?","Sem problemas. O mundo pode esperar, não é mesmo?",,"Nicio problemă. Salvarea lumii poate aștepta, nu?","Не парься. Спасение мира подождёт, ведь так?", -Guess it's time to make like the 'net and split!,QUITMSG13,,,,"Hádám, že je čas vypojit server!","Also ist es soweit, dass sich unsere Wege trennen.",,"Tempas, ke niaj vojoj agu kiel la reto kaj dividu.",¡Supongo que es hora de cortar con esta mala conexión!,,Kai sitten on aika katkaista palvelinyhteydet!,Ca doit être temps de partir comme une mauvaise connection!,,Quindi è il momento per i\nnostri modi di separarsi.,ネット切断している暇は無いだろ!,벌써 서버를 다운시키는 '척' 할 시간인가?,Denk dat het tijd is om het te maken als het 'net en splitsen!,"Wygląda na to, że trzeba się rozłączyć jak netsplit!","Acho que tá na hora de cair, que nem uma conexão ruim.",,Cred că e timpul de separare!,"Кажется, настало время устроить netsplit!", -"Don't go off and forget about HacX, now!",QUITMSG14,,,,Ať tě nenapadne odejít a zapomenout na HacX!,Bitte vergesse HacX nicht!,,Ne iru forgesi HacX nun!,¡Ahora no vayas y te olvides de Hacx!,,Älä nyt mene pois ja unohda HacX:ä!,Va pas oublier HacX maintenant!,,"Non andartene e dimenticati di HacX, ora!",HacXを忘れんじゃねえぞ、な!,부디 나가지 말고 HacX를 잊지 말아줘!,"Ga niet af en vergeet HacX niet, nu!","Nie wyłączaj i nie zapominaj o HacX, teraz!","Não vai se esquecer do HacX, hein!",,Nu pleca și uita de HacX!,"Только посмей уйти и забыть про HacX, ты!", -%o deleted %hself from the universe.,OB_SUICIDE,,,,%o se smazal@[ao_cs] z vesmíru.,%o entfernte sich aus dem Universum.,,%o forigis sin el la universo.,%o se borró a si mism@[ao_esp] del universo.,,%o poisti itsensä maailmankaikkeudesta.,%o s'est effacé@[e_fr] de l'univers.,,%o si è cancellato dall'universo.,%o はこの宇宙から消滅した。,%o 은(는) 자기 자신의 존재를 소멸시켰다.,%o verwijderd zichzelf uit het universum.,%o usun@[irreg_2_pl] się ze świata.,%o se deletou deste universo.,,%o s-a sters pe sine din univers.,%o стёр себя с лица Вселенной., -%o formed a crater the size of Kansas.,OB_FALLING,,,,%o utvořil@[ao_cs] kráter velikosti Kansasu.,%o wurde zu einem Krater in der Größe von Kansas.,,%o formis krateron grandan kiel Kansaso.,%o formó un cráter del tamaño de Kansas.,,%o muodosti Kansasin kokoisen kraaterin.,%o a formé un cratère de la taille du Kansas.,,%o ha formato un cratere delle dimensioni del Kansas.,%o はカンザス州程のクレーターを生成した。,%o 은(는) 땅바닥에 캔자스만큼 커다란 구멍을 뚫었다.,%o vormde een krater ter grootte van Kansas.,%o utworzył@[ao_pl] krater wielkości Kansas.,%o abriu uma cratera do tamanho de Minas Gerais.,,%o a format un crater de dimensiunile statului Kansas.,На месте падения %o образовался кратер размером с Канзас., -%o became a human pancake.,OB_CRUSH,,,,%o se změnil@[ao_cs] v lidskou palačinku.,%o wurde zu einem menschlichen Pfannkuchen.,,%o Iĝis homa patkuko.,%o se convirtió en un crepe humano.,,%o tuli ihmispannukakun muotoiseksi.,%o est devenu@[e_fr] une crêpe.,,%o è diventato un pancake umano.,%o は人肉パンケーキになった。,%o 은(는) 인간 빈대떡이 되었다.,%o werd een menselijke pannenkoek.,%o stał@[ao_pl] się ludzkim plackiem.,%o virou uma panqueca humana.,,%o a devenit o clătită umană.,Игрока %o сплющило в лепешку., -%o tried to jack out.,OB_EXIT,,,,%o se pokusil@[ao_cs] prchnout.,%o hat sich ausgeloggt.,,%o provis malkonektiĝi.,%o intentó desconectarse.,,%o yritti irrottaa piuhan.,%o a tenté de se déconnecter.,,%o è uscito.,%o は逃げ出そうとした。,%o 은(는) 로그아웃하려고 시도했다.,%o probeerde zich terug te trekken.,%o chciał@[ao_pl] się wydostać.,%o tentou se desconectar.,,%o a încercat să o taie.,%o хотел улизнуть., -%o swam like a brick.,OB_WATER,,,,%o uměl@[ao_cs] plavat jako cihla.,%o schwamm wie ein Stein.,,%o naĝis kiel briko.,%o nadó como un ladrillo.,,%o ui kuin tiiliskivi.,%o nage comme une brique.,,%o nuotava come una pietra.,%o はカナヅチだった。,%o 은(는) 웹서핑을 못 하는 타입이었다.,%o zwom als een baksteen.,%o popłyn@[irreg_2_pl] jak cegła.,%o foi nadar como um tijolo.,,%o a înotat ca o cărămidă.,%o поплыл как топор., -%o went nuclear.,OB_SLIME,,,,%o se rozpadl@[ao_cs] na atom.,%o wurde verstrahlt.,,%o iĝis nuklea,%o se volvió radioactiv@[ao_esp].,,%o kiinnostui ydinasioista.,%o s'est fait fissionner.,,%o è stato irradiato.,%o はニュークリアーと化した。,%o 은(는) 방사능 바람을 좀 쐬고 왔다.,%o werd nucleair.,%o został@[ao_pl] napromieniowan@[adj_pl].,%o ficou radioativ@[ao_ptb].,,%o a devenit radioactiv.,%o светится в темноте., -%o took a hot bath.,OB_LAVA,,,,%o si dal@[ao_cs] horkou koupel.,%o nahm ein heißes Bad.,,%o spertis varman banon.,%o tomó un baño caliente.,,%o otti kuuman kylvyn.,% o ha fatto un bagno caldo.,,%o ha fatto un bagno caldo.,%o は熱湯風呂に浸かった。,%o 은(는) 시원하게 용암 일광욕을 즐겼다.,%o nam een warm bad.,%o wzi@[irreg_2_pl] gorącą kąpiel.,%o tomou um banho bem quente.,,%o a făcut o baie fierbinte.,%o принял@[ao_rus] горячую ванну., -%o overdosed on nitro glycerine.,OB_BARREL,,,,%o se předávkoval@[ao_cs] nitroglycerinem.,%o nahm eine Überdosis Nitroglyzerin.,,%o trodozis nitroglicerinon.,%o tuvo una sobredosis de nitroglicerina.,,%o sai yliannostuksen nitroglyseriiniä.,%o a fait une overdose de nitroglycérine.,,%o ha assunto un sovradosaggio di nitroglicerina.,%o はニトロを過剰摂取した。,%o 은(는) 니트로글리세린을 훅 가게 흡입했다.,%o overdosering op nitroglycerine.,%o przedawkował@[ao_pl] nitroglicerynę.,%o overdosou em nitroglicerina.,,%o a luat o supradoză de nitroglicerină.,%o перебрал@[ao_rus] нитроглицерина., -%o is flayed into tiny little pieces.,OB_SPLASH,,,,%o byl@[ao_cs] sedřen@[ao_cs] na kousíčky.,%o wurde zerkleinert.,,%o estas senhaŭtiga en malgrandetaj pecoj.,%o es despellejad@[ao_esp] en trocitos pequeños.,,%o silpoutui riekaleiksi.,%o s'est fait éparpiller en petits morceaux.,,%o è stato schiacciato.,%o は細かい粒をぶち撒けられた。,%o 은(는) 작은 입자로 분해되었다.,%o wordt gevild in kleine stukjes.,%o został@[ao_pl] roztrzaskan@[adj_pl] na małe kawałeczki.,%o foi detonad@[ao_ptb] em vários pedacinhos.,,%o s-a spart în mii de bucățele.,Игрока %o разодрали на мелкие клочки., -%o wanted to see what %g looked like inside-out.,OB_R_SPLASH,,,,"%o chtěl@[ao_cs] vědět, jak vypadá zevnitř.",%o wollte @[pp_de] Innereien sehen.,,"%o volis vidi, kiel %g aspektus kun la interno ekstere.",%o quería ver que pinta tenía por dentro.,,%o halusi nähdä itsensä nurinperin.,%o voulait voir comment ses organes fonctionnent.,,%o voleva vedere le sue interiora.,%o は %g が裏返しになるのを望んだ。,%o 은(는) 인체의 신비를 감상했다.,%o wilde zien hoe %g er binnenstebuiten uitzag.,%o chciał@[ao_pl] zobaczyć jak %g wygląda od środka.,%o queria ver como são os orgãos internos de %g.,,%o a vrut să vadă cum arăta %g întors pe dos.,"%o хотел посмотреть, что у @[pron_rus] внутри.", -%o wanted to see what %g looked like inside-out.,OB_ROCKET,,,,"%o chtěl@[ao_cs] vědět, jak vypadá zevnitř.",%o wollte @[pp_de] Innereien sehen.,,"%o volis vidi, kiel %g aspektus kun la interno ekstere.",%o quería ver que pinta tenía por dentro.,,%o halusi nähdä itsensä nurinperin.,%o voulait voir comment ses organes fonctionnent.,,%o voleva vedere le sue interiora.,%o は %g が裏返しになるのを望んだ。,%o 은(는) 퀀텀 여행을 즐겼다.,%o wilde zien hoe %g er binnenstebuiten uitzag.,%o chciał@[ao_pl] zobaczyć jak %g wygląda od środka.,%o queria ver como são os orgãos internos de %g.,,%o a vrut să vadă cum arăta %g întors pe dos.,"%o хотел посмотреть, что у @[pron_rus] внутри.", -%o deleted %hself from the universe.,OB_KILLEDSELF,,,,%o se smazal@[ao_cs] z vesmíru.,%o entfernte sich aus dem Universum.,,%o forigis sin el la universo.,%o se borró a si mism@[ao_esp] del universo.,,%o poisti itsensä maailmankaikkeudesta.,%o s'est effacé@[e_fr] de l'univers.,,%o si è cancellato dall'universo.,%o はこの宇宙から消滅した。,%o 은(는) 자기 자신을 해킹했다.,%o schrapte zichzelf uit het universum.,%o usun@[irreg_2_pl] się ze świata.,%o se deletou deste universo.,,%o s-a șters pe sine din univers.,%o стёр@[irreg_2_rus] себя с лица Вселенной., -%o is no longer the dominant species.,OB_THUG,,,,%o už není vládnoucím živočichem.,%o ist nicht länger die dominante Spezies.,,%o ne estas la supera specio plu.,%o ya no es la especie dominante.,,%o ei ole enää vallitsevaa lajia.,%o n'est plus l'espèce dominante.,,%o non è più la specie dominante.,%o はもはや優性種ではなくなった。,%o 은(는) 그들의 시다바리가 아니였다.,%o is niet langer de dominante soort.,%o nie jest już dominującym gatunkiem.,%o não é mais a espécie dominante.,,%o nu mai e specia dominantă.,%o больше не доминантная форма жизни., -%o plugged in to the wrong machine.,OB_ANDROID,,,,%o se zapojil@[ao_cs] ke špatnému stroji.,%o verband sich mit der falschen Maschine.,,%o konektiĝis en la eraran maŝinon.,%o se enchufó en la máquina equivocada.,,%o kytkeytyi väärään koneeseen.,%o s'est branché@[e_fr] à la mauvaise machine.,,%o connesso alla macchina sbagliata.,%o は違うマシンに接続してしまった。,%o 은(는) 잘못된 기계를 작동시켰다.,%o aangesloten op de verkeerde machine.,%o podłączył@[ao_pl] się do złej maszyny.,%o se conectou na máquina errada.,,%o s-a conectat la mașina greșită.,Игрока %o подключили не к тому заряднику., -%o got %hself a monster of a cyber-jockey-derriere-kicking.,OB_MONSTRUCT,,,,%o dostal@[ao_cs] šíleně kybernakopáno.,%o bekam einen monströsen Cyber-Arschtritt verpasst.,,%o ricevis monstran cybernetik-raydist-postaĵ-piedbaton.,%o se ganó la madre de todas las patadas en el culo.,,%o sai hirviömäisen kyberlöylytyksen.,%o s'est fait@[e_fr] botter le cul de manière monumentale.,,% o ho avuto un mostruoso calcio cibernetico mancato.,%o は己に サイバー-ジョッキー-デリエレ-キッキング を取り入れた。,%o 은(는) 저 괴물의 슈퍼-울트라-캡쑝-파워를 맛봤다.,%o kreeg een monsterlijke cybertrap in @[zijn_haar_nl] kont.,%o dostał@[ao_pl] cyber-kopa w dupę.,%o se ferrou cibernéticamente.,,%o s-a făcut praf în stil cibernetic.,%o получил@[ao_rus] поджопника от кибер-диджея., -%o got ICEd.,OB_ICE,,,,%o byl@[ao_cs] zmražen@[ao_cs] ICEm.,%o wurde verEISt.,,%o iĝis ICE-ita,%o fue ICEad@[ao_esp].,,%o raukkaa nyt varmaankin kICEmittää.,%o s'est fait@[e_fr] ICEr.,,% o è stato ghiacciato.,%o は冷えた。,%o 은(는) 지독하게 물어뜯겼다.,%o was IJS'd.,%o został@[ao_pl] zamrożon@[adj_pl].,%o foi peg@[ao_ptb] por um ICE. AI SE ferrou!,,%o a ÎNGHEȚat.,%o вляпал@[refl_rus] в ЛЁД., -%o feels a little buzzed.,OB_BUZZER,,,,%o dostal@[ao_cs] malou pecku.,%o fühlt sich etwas gekitzelt.,,%o sentas sin iomete vibretita.,%o se siente algo zumbad@[ao_esp].,,%o raukan päässä hieman surisee.,%o sent le buzz.,,%o si sente solleticato un po '.,%o は少し賑やかになった。,%o 은(는) 짜릿하게 찔렸다.,%o voelt een beetje gezoemd.,%o poczuł@[ao_pl] brzęczenie.,%o se sente meio chocad@[ao_ptb].,,%o se simte puțin șocat.,%o л@[irreg_3_rus] спать в компании вертолётиков., -%o uncovers a rather shocking development.,OB_STEALTH,,,,%o odhalil@[ao_cs] šokující informace.,%o machte eine schockierende Entdeckung.,,%o malkovras tre ŝokantan aferon.,%o descubre algo bastante chocante.,,%o raukalle paljastuu sangen sähköistävä uutinen.,%o a fait une découverte choquante.,,%o ha fatto una scoperta scioccante.,%o はかなり衝撃的な開発を発見した。,%o 은(는) 비밀리에 만들어진 병기를 발견했다.,%o ontdekt een nogal schokkende ontwikkeling.,%o odkrywa coś szokującego.,%o descobre uma revelação chocante.,,%o dezvăluie o schimbare șocantă.,%o встретил@[ao_rus] довольно серьёзный поворот событий., -%o was erased from cyberspace.,OB_DMAN,,,,%o byl@[ao_cs] vymazán@[ao_cs] z kyberprostoru.,%o wurde aus dem Cyberspace gelöscht.,,%o estas viŝita el cyberspaco.,%o fue borrad@[ao_esp] del ciberespacio.,,%o poistettiin kyberavaruudesta.,%o s'est fait@[e_fr] effacer du cyberespace.,,%o è stato eliminato dal cyberspazio.,%o はサイバースペースに消去された。,%o 은(는) 영구차단을 당했다.,%o werd gewist uit cyberspace.,%o został@[ao_pl] usunięt@[adj_pl] z cyber przestrzeni.,%o foi deletad@[ao_ptb] do ciberespaço.,,%o a fost șters din spațiul cibernetic.,Игрока %o удалили из киберпространства., -%o gave %hself a glass jaw.,OB_GLASS,,,,%o si přidělal@[ao_cs] skleněnou čelist.,%o bekam ein Glaskinn.,,%o donis al si vitran makzelon.,%o se estampó contra un cristal.,,%o antoi itsellensä lasileuan.,%o s'est fait@[e_fr] vitrifier la figure.,,%o ha un mento di vetro.,%o は自身にグラスジョーを取り付けた。,%o 은(는) 유리창을 깨고 등장하는 액션 배우가 아니였다.,%o gaf zichzelf een glazen kaak.,%o był@[ao_pl] zbyt delikatn@[adj_pl] ze szkłem.,%o tem um queixo de vidro.,,%o și-a făcut un maxilar de sticlă.,У игрока %o оказалась стеклянная челюсть., -%o's life membership was terminated.,OB_MANIAC,,,,%o@[psn_cs] členství v klubu živých bylo přerušeno.,%os Mitgliedschaft im Leben wurde beendet.,,La vivo-membrecon de %o estas finigita,%o tuvo su afiliación a la vida terminada.,,%o raukan elämänjäsenyys päätettiin.,L'abonnement à vie de %o est arrivé à sa fin.,,L'appartenenza di %o alla vita è finita.,%o のメンバーシップ生活は終幕した。,%o 의 계정은 영원히 삭제되었다.,%o's levenslange lidmaatschap werd beëindigd.,Członkowstwo %o w klubie żywych się skończyło.,%o não está mais afiliad@[ao_ptb] à vida.,,%o nu mai e membru al clubului celor vii.,Игрока %o исключили из клуба живых., -%o died in some random method I cannot fathom.,OB_MANIACHIT,,,,"%o umřel@[ao_cs] nějakým způsobem, který ani nemůžu pochopit.",%o starb auf eine unvorstellbare Art und Weise.,,"%o mortis per iu malcerta maniero, kiun mi ne povas kompreni.",%o murió de alguna manera que no llego a comprender.,,"%o kuoli jollakin sattumanvaraisella tavalla, jota en voi käsittää.",%o est mort@[e_fr] d'une manière que je n'arrive même pas à décrire.,,%o è morto in un modo inimmaginabile.,%o は計算外の乱数で死んだ。,%o 은(는) 의미불명의 이유로 잠수를 타게 되었다.,%o stierf op een of andere willekeurige manier die ik me niet kan voorstellen.,"%o zgin@[irreg_2_pl] pod wpływem metody, której nie mogę pojąć.",%o morreu de algum método aleatório que nem consigo imaginar.,,%o a murit într-un mod aleatoriu pe care nu mi-l pot închipui.,%o внезапно умер@[irreg_2_rus] по непостижимой для меня причине., -%o was fried by a femme fatale freak.,OB_TERMIN,,,,%o byl@[ao_cs] usmažen@[ao_cs] šílenou femme fatale.,%o wurde von einem Femme-Fatale Freak gebraten.,,%o estis fritita de femme-fatale-groteskulo.,%o fue tostad@[ao_esp] por una femme fatale.,,%o joutui kohtalokkaan kimman kärtsäämäksi.,%o s'est fait@[e_fr] frire par une femme fatale.,,% o è stato fritto da una femme fatale.,%o はファム ファタル フリークに揚げられた。,%o 은(는) 미인계에 발을 들였다.,%o werd gebakken door een femme fatale freak.,%o został@[ao_pl] usmażon@[adj_pl] przez szaloną femme fatale.,%o foi fritad@[ao_ptb] por uma femme fatale psicótica.,,%o a fost prăjit de către o femme fatale psihopată.,Игрока %o поджарила чокнутая роковая женщина., -%o got a little close to the opposite sex.,OB_TERMINHIT,"This text is not gender neutral, obviously...",,,%o se moc přiblížil@[ao_cs] k opačnému pohlaví.,%o kam dem anderen Geschlecht zu nahe.,,%o iĝis iomete proksime al la mala sekso.,%o se acercó demasiado a la persona equivocada.,,%o meni hieman liian lähelle vastakkaista sukupuolta.,%o s'est trop rapproché@[e_fr] de la mauvaise personne.,,%o è arrivato troppo vicino all'altro sesso.,%o は少し異性に成り果てた。,%o 의 남자다운 자존심은 쪼그라들었다.,%o kwam een beetje in de buurt van het andere geslacht.,%o pod@[irreg_1_pl] zbyt blisko do płci pięknej.,%o se aproximou da pessoa errada. Ninguém sabe o quanto que está sofrendo.,,%o s-a apropriat prea mult de sexul opus.,%o почти сблизил@[refl_rus] с противоположным полом., -%o said goodbye to an old friend.,OB_REPLI,,,,%o řekl@[ao_cs] sbohem starému příteli.,%o verabschiedete sich von einem alten Freund.,,"%o diris ""Ĝis la revido"" al malnova amiko.",%o se despidió de un viejo amigo.,,%o sanoi hyvästit vanhalle ystävälle.,%o dit au revoir à un vieil ami.,,%o ha detto addio a un vecchio amico.,%o は古い友人に別れを告げた。,%o 은(는) 오랜 친구와 작별인사를 했다.,%o nam afscheid van een oude vriendin.,%o pożegnał@[ao_pl] się ze starym znajomym.,%o disse adeus a um velho amigo.,,%o a spus adio unui vechi prieten.,%o распрощал@[refl_rus] со старым другом., -%o was stabbed in the back by an old friend.,OB_REPLIHIT,,,,%o byl@[ao_cs] bodnuta do zad starým přítelem.,%o wurde von einem alten Freund in den Rücken gestochen.,,%o estis pikita en la dorson de malnova amiko.,%o fue apuñalad@[ao_esp] en la espalda por un viejo amigo.,,%o joutui vanhan ystävän selkäänpuukottamaksi.,%o s'est fait@[e_fr] planter une lame dans le dos par un vieil ami.,,%o è stato pugnalato alla schiena da un vecchio amico.,%o は古い友人に背中を刺された。,%o 은(는) 오랜 친구에게 배신을 당했다.,%o werd in de rug gestoken door een oude vriend.,%o został@[ao_pl] dźgnięt@[adj_pl] w plecy przez starego znajomego.,%o foi apunhalad@[ao_ptb] pelas costas por um velho amigo.,,%o a fost înjunghiat pe la spate de către un vechi prieten.,%o получил@[ao_rus] нож в спину от старого друга., -%o was weeded out by natural selection.,OB_PHAGE,,,,%o byl@[ao_cs] vyčištěna přirozeným výběrem.,%o fiel der natürlichen Auslese zum Opfer.,,%o estis foriga de natura elektado.,%o fue eliminad@[ao_esp] por selección natural.,,%o joutui luonnonvalinnan kitkemäksi.,%o a été éliminé@[e_fr] par la sélection naturelle.,,%o cadde vittima della selezione naturale.,%o は自然淘汰によって除草された。,%o 은(는) 약육강식을 지금까진 모르고 있었다.,%o werd door natuurlijke selectie weggehaald.,%o został@[ao_pl] przesian@[adj_pl] przez naturalną selekcję.,%o foi eliminado por seleção natural.,,%o a fost eliminat prin selecție naturală.,%o был@[ao_rus] отсеян@[ao_rus] естественным отбором., -%o couldn't escape a thorny death.,OB_THORN,,,,%o nemohl@[ao_cs] utéct bodlavé smrti.,%o konnte einem dornigen Tod nicht entkommen.,,%o ne povis eskapi dornan morton.,%o no pudo escapar una muerte espinosa.,,%o ei kyennyt välttämään piikikästä kuolemaa.,%o n'a pu éviter une mort piquante.,,%o non poteva sfuggire a una morte spinosa.,%o は棘のある死から逃げられなかった。,%o 은(는) 따가운 죽음을 피할 수 없었다.,%o kon niet ontsnappen aan een netelige dood.,%o nie m@[irreg_4_pl] uciec przed cierniową śmiercią.,%o não conseguiu escapar de uma morte espinhosa.,,%o nu a putut scăpa de o moarte spinoasă.,Игрока %o поджидала смерть на его тернистом пути., -%o took a sumo punch to the groin.,OB_SUMATIC,,,,%o dostal@[ao_cs] sumo ránu pod pás.,%o bekam einen Sumo-Schlag an @[pp_de] empfindlichste Stelle.,,%o prenis sumoan baton en la ingveno.,%o recibió un puñetazo de sumo en la entrepierna.,,%o otti vastaan sumoiskun nivusiin.,%o s'est pris le poing d'un sumo dans l'entrejambe.,,%o ha ricevuto un soffio su un punto sensibile.,%o は股座にスモウ ハリテを食らった。,%o 은(는) 가랑이 사이에 정권을 찔렀다.,%o nam een sumo punch in de lies.,%o dostał@[ao_pl] cios sumo w pachwinę.,%o levou um golpe de sumô no saco.,,%o a primit un pumn sumo în vintre.,%o отхватил@[ao_rus] удар в пах от сумоиста., -%o didn't get %p three wishes.,OB_GENIE,,,,%o nedostal@[ao_cs] svá tři přání.,%o bekam @[pp_de] drei Wünsche nicht erfüllt.,,%o ne ricevis siajn tri petojn.,%o no recibió sus tres deseos.,,%o ei saanut kolmea toivettaan.,%o n'a pas préparé ses trois vœux.,,%o non ha soddisfatto i suoi tre desideri.,%o は %p に三願を望まなかった。,%o 은(는) 세 가지 소원을 빌 수 없었다.,%o kreeg niet drie wensen.,%o nie dostał@[ao_pl] swoich trzech życzeń.,%o não concedeu três desejos a %p.,,%o nu a putut să-și pună cele trei dorințe.,%o не загадает трёх желаний., -%o tried to pet a mine.,OB_MINE,,,,%o se pokusil@[ao_cs] pohladit minu.,"%o versuchte, eine Mine zu streicheln.",,%o provis glatumi minon.,%o intentó acariciar una mina.,,%o yritti silittää miinaa.,%o a essayé de caresser une mine.,,%o ha provato ad accarezzare una mina.,%o は地雷を愛撫しようとした。,%o 은(는) 기뢰와 친구가 되고 싶었다.,%o probeerde een mijn te aaien.,%o próbował@[ao_pl] pogłaskać minę.,%o tentou fazer carinho na mina.,,%o a încercat să mângâie o mină.,%o хотел@[ao_rus] погладить мину., -%o took %k's Bruce Lee fu-kick to the face.,OB_MPKICK,,,,%o dostal@[ao_cs] kopanec do obličeje od kung-fuistou %k.,%o bekam einen Bruce-Lee-Fußtritt ins Gesicht.,,%o ricevis la Bruce Lee piedbaton de %k en sia vizaĝo.,%o se comió una patada de kung-fu a lo Bruce Lee de %k.,,%k potkaisi %o raukkaa päin naamaa Bruce Leen kung fu-tyyliin.,%o s'est mangé@[e_fr] un coup de pied à la Bruce Lee de la part de %k.,,%o ha un calcio in faccia.,%o の顔に %k のブルースリーキックを当てた。,%o 은(는) %k 의 거침없는 하이킥을 받았다.,%o nam %k's Bruce Lee fu-kick in het gezicht.,%o dostał@[ao_pl] kopniakiem w stylu Bruce'a Lee od %k prosto w twarz.,%o tomou uma voadora de %k na cara.,,%o a primit un șut în stil Bruce Lee.,"%o отхватил@[ao_rus] от игрока %k удар в лицо, достойный Брюса Ли.", -%o fell apart via %k's shocking revelation.,OB_MPREZNATOR,,,,%o se rozpadl@[ao_cs] šokujícím odhalením hráče %k.,%o erhielt eine schockierende Enthüllung von %k.,,%o diseriĝis pro la ŝokantan revelaĉio de %k.,%o cayó ante la revelación chocante de %k.,,%o romahti käyttäjän %k sähköistävästä ilmestyksestä.,%o a été témoin de la révélation choquante de %k.,,%o ricevette una scioccante rivelazione da %k.,%o は %k の衝撃的な啓示によりバラバラになった。,%o 은(는) %k 이(가) 선사한 전기 찜질을 맛봤다.,%o viel uit elkaar via %k's schokkende onthulling.,%o rozpadł@[ao_pl] się pod wpływem szokującego objawienia %k.,%o ficou arrasad@[ao_ptb] pela revelação chocante de %p.,,%o s-a făcut praf la revelația șocantă a lui %k.,%o шокирован@[ao_rus] откровениями %k., -%o took a double-dose of %k's punishment.,OB_MPXPISTOL,,,,%o dostal@[ao_cs] dvojitou dávku potrestání hráče %k.,%o bekam eine doppelte Dosis von %ks Bestrafung.,,%o duoble dozis la puno de %k.,%o recibió una doble dosis del castigo de %k.,,%o otti tupla-annoksen käyttäjän %k kuritusta.,%o a mangé une double dose de la furie de %k.,,%o ha ottenuto una doppia dose della punizione di %k.,%o は %k の懲罰を二度受けた。,%o 은(는) %k 의 2총신 사격을 받았다.,%o nam een dubbele dosis van %k's straf.,%o dostał@[ao_pl] podwójną dawkę kary %k.,%o tomou uma dose dupla da punição de %k.,,%o a luat o doză dublă din pedeapsa lui %k.,%o принял@[ao_rus] двойную дозу возмездия от %k., -%o was shut down by %k's shock-stick.,OB_MPTAZER,,,,%o byl@[ao_cs] vypnut@[ao_cs] šokádou hráče %k.,%o wurde von %ks Schockstab ausgeschaltet.,,%o estis malŝaltita de la ŝokbateno de %k.,%o fue noquead@[ao_esp] por la vara eléctrica de %k.,,%o joutui käyttäjän %k sähkökepin sammuttamaksi.,%o s'est fait mettre K.O par le bâton électrique de %k.,,%o è stato spento dalla bacchetta di %k.,%o は %k のショックスティックでシャットダウンした。,%o 은(는) %k 의 무력행사에 아예 포기했다.,%o werd uitgeschakeld door %k's schokstick.,%o został@[ao_pl] wyłączon@[adj_pl] przez szokującą pałkę %k.,%o foi desligado pelo espeto chocante de %k.,,%o a fost dezactivat de arma cu șocuri a lui %k.,%o выведен из строя электродубинкой %k., -%o got a face-full of %k's ice-cold wrath.,OB_MPCRYOGUN,,,,%o se zabořil@[ao_cs] do mrazivého hněvu hráče %k.,%o bekam eine Ladung von %ks eiskaltem Zorn ins Gesicht.,,%o ricevis la glacie malvarman koleregon de %k.,%o recibió la ira gélida de %k en toda la cara.,,%o sai saamansa täyteen käyttäjän %k jääkylmää vihaa.,%o s'est fait congeler la figure par la colère glaciale de %k.,,%o ha un carico di freddo gelido di %k in faccia.,%o は %k の冷めた表情で凍った。,%o 은(는) %k 덕분에 맛있게 냉동 보존되었다.,%o kreeg een gezicht vol met %k's ijskoude toorn.,%o dostał@[ao_pl] wielką dawkę mroźnego gniewu %k.,%o tomou um gelo de %k. ,,%o a simțit din plin furia rece a lui %k.,%o столкнулся с ледяной ненавистью %k., -"%o was drilled full of holes by %k, gangsta-style.",OB_MPUZI,,,,%o byl@[ao_cs] prostřílen@[ao_cs] skrz na skrz gangsterem %k.,%o wurde von %k im Gangsta-Stil perforiert.,,"%o estis borita truplena de %k, ganstere.","%o fue acribillad@[ao_esp] por %k, al estilo gangster.",,%k porasi %o raukan täyteen reikiä gangsta-tyyliin.,"%o s'est fait perforer dans tous les sens par %k, Gangsta style.",,%o è stato perforato da %k in stile gangsta.,%o はギャングの様な %k に蜂の巣にされた。,%o 은(는) %k 이(가) 선사한 갱스터 스타일 난사를 막지 못했다.,"%o werd vol gaten geboord met %k, in gangsta-stijl.",%o został@[ao_pl] podziurawion@[adj_pl] przez %k niczym gangster.,%o tomou pipoco de %k.,,%o a fost umplut de găuri în stil mafiot de către %k.,%o покрылся дырками после гангста-стрельбы игрока %k., -%o ate %k's photon bomb.,OB_MPZOOKA,,,,%o sežral@[ao_cs] fotonovou bombu hráče %k.,%o nahm %ks Photonenbombe.,,%o manĝis la fotonbombon de %k.,%o se comió la bomba de fotones de %k.,,%o söi käyttäjän %k fotonipommin.,%o a bouffé la bombe photonique de %k.,,%o ha preso la bomba fotonica di %k.,%o は %k のフォトンボムを食らった。,%o 은(는) %k 의 광자탄을 봤는데도 피하지 못했다.,%o at %o %k's fotonbom.,%o zjadł@[ao_pl] fotonową bombę %k.,%o engoliu a bomba de fótons de %k.,,%o a mâncat bomba fotonică a lui %k.,%o съел@[ao_rus] фотонную бомбу %k., -%o was reduced to a neat pile of photons by %k.,OB_MPZ_SPLASH,,,,%o byl@[ao_cs] zredukován@[ao_cs] na hromádku fotonů hráčem %k.,%o wurde von %k zu einem Haufen Photonen verarbeitet.,,%o estis reduktita en ordeman amason da fotonoj de %k.,%o fue reducid@[ao_esp] a una pila de fotones por %k.,,%k redusoi %o raukan sieväksi fotonipinoksi.,%o s'est fait@[e_fr] réduire en une jolie pile de photons par %k.,,%o è stato elaborato da %k in un mucchio di fotoni.,%o は %k によって蛍光灯にされた。,%o 은(는) %k 의 광자력을 탐냈다. 죽기 전까지는.,%o werd gereduceerd tot een nette stapel fotonen met %k.,%o został@[ao_pl] zredukowan@[adj_pl] do maleńkiej kupki fotonów przez %k.,%o foi reduzido à uma bela pilha de fótons por %k.,,%o a fost transformat într-o grămadă simpatică de fotoni de către %k.,%o был@[ao_rus] разложен@[ao_rus] игроком %k в аккуратную кучку фотонов., -%o was reduced to antimatter by %k.,OB_MPANTIGUN,"Physically this is utter nonsense, of course.",,,%o byl@[ao_cs] zredukován@[ao_cs] na antihmotu hráčem %k.,%o wurde von %k zu Antimaterie reduziert.,,%o estis reduktita en antimaterion de %k.,%o fue reducid@[ao_esp] a antimateria por %k.,,%k redusoi %o raukan antimateriaksi..,%o s'est fait inverser les atomes par %k.,,%o è stato ridotto all'antimateria da %k,%o は %k のにより反物質に変換された。,%o 은(는) %k 의 반물질의 힘에 의해 소멸되었다.,%o werd gereduceerd tot antimaterie met %k.,%o został@[ao_pl] zredukowan@[adj_pl] do antymaterii przez %k.,%o foi transformado em antimatéria por %k.,,%o a fost transformat în antimaterie de către %k.,%o был@[ao_rus] разложен@[ao_rus] игроком %k до антиматерии., -%o swallowed %k's nuke.,OB_MPNUKE,,,,%o spolkl@[ao_cs] atomovku hráče %k.,%o verschluckte sich an %ks Atomrakete.,,%o glutis la nuklean bombon de %k.,%o se tragó la bomba atómica de %k.,,%o nieli käyttäjän %k ydinpommin.,%o s'est pris@[e_fr] la bombe thermonucléaire de %k dans la figure.,,%o soffocò sul missile nucleare di %k.,%o は %k の核を飲み干した。,%o 은(는) %k 덕분에 하늘을 뚫을 버섯구름이 되었다.,%o geslikt %o nuke %k's nuke.,%o połkn@[irreg_2_pl] atomówkę %k.,%o engoliu o míssil núclear de %k.,,%o a înghițit proiectilul lui %k.,%o проглотил@[ao_rus] ядерный заряд %k., -%o went nuclear from %k's mass destruction spree.,OB_MPNUKESPLASH,,,,%o si zkrátil@[ao_cs] svůj poločas rozpadu při zabijačce hráče %k.,%o wurde von %ks Massenzerstörungsaktion verstrahlt.,,%o iĝis nuklea pro la amasdetruado de %k.,%o se volvió radioactiv@[ao_esp] por la racha de destrucción masiva de %k.,,%o muuttui radioaktiiviseksi käyttäjän %k massatuhoputken takia.,%o s'est fait@[e_fr] irradier par la folie destructrice de %k.,,%o fu irradiato dall'azione di distruzione di massa di %k.,%o は %k の虐殺ごっこの犠牲者になった。,%o 은(는) %k 의 핵실험에 참여했다.,%o werd nucleair van de massavernietigingswoede van %k's massavernietigingswoede.,%o został@[ao_pl] napromieniowan@[adj_pl] przez masową destrukcję %k.,%o virou picadinho radioativo por causa da destruição em massa causada por %k.,,%o a devenit radioactiv în urma distrugerii în masă a lui %k.,%o светится в темноте от оружия массового поражения %k., -%o was turned inside-out by %k.,OB_MPTELEFRAG,,,,%o byl@[ao_cs] obrácen@[ao_cs] naruby hráčem %k.,%o wurde von %k zerfetzt.,,La interno de %o estis eksteriga de %k.,%o fue puest@[ao_esp] del revés por %k.,,%k käänsi %o raukan nurinpäin.,%o s'est fait@[e_fr] inverser par %k.,,%o fu fatto a pezzi da %k,%o は %k に裏返しにされた。,%o 은(는) %k 에 의해 자신이 분해되는 꼴을 못 봤다.,%o werd binnenstebuiten gekeerd met %k.,%o został@[ao_pl] wywrócon@[adj_pl] na lewą stronę przez %k.,%o foi virad@[ao_ptb] ao avesso por %k.,,%o a fost întors pe dos de către %k.,Игрока %o вывернут наизнанку игроком %k., -%o's atomic structure was split apart.,OB_MONTELEFRAG,,,,Struktura atomů hráče %o se rozpadla.,%os Atomstruktur wurde vernichtet.,,La atoma strukturo de %o estis disfendita.,%o fue desintegrad@[ao_esp] al nivel atómico.,,%o raukan atomirakenne hajosi.,%o s'est fait@[e_fr] désassembler au niveau atomique.,,La struttura atomica di %o fu distrutta.,%o の原子構造は分解された。,%o 의 원자 마디마디가 흩어졌다.,De atoomstructuur van %o werd gesplitst.,Atomy %o zostały od siebie oddzielone.,A estrutura atômica de %o foi separada.,,Structura atomică a lui %o a fost spulberată.,Атомная структура игрока %o разрушена., -%o spontaneously expired.,OB_DEFAULT,,,,%o samovolně vypršel@[ao_cs].,%o hörte spontan auf zu existieren.,,%o spontane finiĝis.,%o tuvo una muerte espontánea.,,%o spontaanisti kupsahti.,%o a spontanément expiré.,,%o ha smesso spontaneamente di esistere.,%o の有効期限が自発的に切れた,%o 은(는) 파란만장하게 사라졌다.,%o is spontaan verlopen.,%o spontanicznie umarł@[ao_pl].,%o pereceu expontâneamente.,,%o a expirat în mod spontan.,Время игрока %o неожиданно вышло., -You grab a NUKER! Suck on this!,GOTNUKER,,,,Sebral@[ao_cs] jsi ATOMOVKÁTOR! Pojď na to!,Ein NUKER! Verschluck dich daran.,,Vi prenis NUKER! Jen havu!,¡Has pillado un NUKER! ¡Chupaos esa!,¡Has recogido un NUKER! ¡Chúpate esa!,%Kahmaiset YDÄRIN! Ime tätä!,Vous découvrez le NUKER! Ca va en chier!,,Prendi un NUKER! Succhia su questo!,NUEKR を奪った! 覚悟しろ!,누커 획득! 한바탕 쓸어볼까!,Je pakt een NUKER! Zuig hier maar aan!,Podniosłeś ATOMÓWKĘ! Ssijcie to!,Você pegou um NUKER! Chupa essa manga!,,Ai ridicat Lansatorul Nuclear! Ia de-aici!,Заполучен ЯДЕРНЫЙ ГРАНАТОМЁТ! Отсосите!, -You got an UZI!!,GOTUZI,,,,Získal@[ao_cs] jsi UZI!,UZI genommen!,,Vi prenis UZI!!,¡¡Has obtenido una UZI!!,,Sait UZIn!!,Vous chopez un UZI!,,Hai un UZI !!,UZI をゲットした!!,우지 기관단총 획득!,Je hebt een UZI!!,Zdobyłeś UZI!!,Você pegou uma UZI!!,,Ai ridicat un UZI!!,Заполучен УЗИ!, -A HOIG Reznator - FRY some butt,GOTREZNATOR,,,,HOIG Reznátor - pár jich upeč,Ein HOIG Reznator.,,HOIG-Reznilo - FRITU pugon!,Un Reznator HOIG. ¡Hora de freir traseros!,,HOIG-reznaattori - KÄRISTÄ takamuksia,"Un Reznator HOIG, allez frire du monde!",,Un Reignator HOIG - friggere un po 'di carne,HOIGレジネイター - ぶっ潰してやれ,HOIG 전자무력기 획득! 전기 통구이를 만들자고!,Een HOIG Reznator – FRY sommige kont,Reznator HOIG - skop trochę tyłków,Um Reznador HOIG - Hora de fritar,,Un Rezonator HOIG - Arde-i!,ХОЙГ Резнатор, -You got a Photon 'Zooka!,GOTPHOTONZOOKA,,,,Sebral@[ao_cs] jsi Fotonovou bazuku!,Photonen-'zooka genommen!,,Vi prenis Fotonbazukon!,¡Has obtenido un Bazooka de Fotones!,,Sait fotonisingon!,Vous récupérez un Bazooka Photonique!,,Hai un cannone Photon!,フォトン'ゾーカ をゲットした!,광자 바주카 획득!,Je hebt een Photon 'Zooka!,Zdobyłeś Fotonozukę!,Você pegou uma Bazuca de Fótons!,,Ai ridicat o Bazooka Fotonică!,Заполучена Фотон-базука!, -You carry a Big Stick!,GOTBIGSTICK,,,,Nosíš velkou bouchačku!,Du trägst einen langen Stock.,,Vi portas grandan bastonon!,¡Llevas un Gran Palo!,,Kannat isoa keppiä!,Vous avez un gros bâton!,,Porti un grosso bastone!,ビッグスティック を手に取った!,반물질 봉 획득!,Je draagt een Big Stick!,Podnosisz Wielką Pałkę!,Você pegou um Grande Bastão!,,Ai ridicat un Băț Lung!,Заполучена Длинная палка!, -You got a Tazer!!,GOTTAZER,,,,Získal@[ao_cs] jsi tazer!,Tazer genommen!,,Vi prenis Elektropafilon!!,¡¡Has obtenido un Taser!!,,Sait etälamauttimen!!,Vous trouvez un Taser!,,Hai un Taser !!,テイザー をゲットした!,테이져 획득!,Je hebt een Tazer!!,Zdobyłeś Tazer!!,Você pegou um Tazer!!,,Ai ridicat un Taser!!,"Заполучен Тазер! -", -You grab a Cryogun! FREEZE!,GOTCRYOGUN,,,,Sebral@[ao_cs] jsi krypušku! ANI SE NEHNI!,Cryowaffe genommen! GEFRIER!,,Vi prenis Kriogenikpafilon! FROSTIĜU!,¡Has pillado un Criogenizador!! ¡Todos quietos!,¡Has recogido un Criogenizador!! ¡Quietos todos!,Kahmaiset kryopyssyn! PYSÄHDY!,Vous prenez un Cryogun! On s'arrête!,,Prendi un Cryogun! CONGELARE!,クライォガン を奪った! フリーズ!,크라이로건 획득! 그대로 멈춰라!,Je pakt een Cryogun! FREEZE!,Podniosłeś Zamrażarkę! STAĆ!,Você pegou uma Cryogun! FICA FRIO AÍ!,,Ai ridicat o Crio-armă! ÎNGHEAȚĂ!,Заполучена Замораживающая пушка! НИ С МЕСТА!, -You grab some rounds!,GOTROUNDS,,,,Sebral@[ao_cs] jsi nějaké náboje!,Munition genommen.,,Vi prenis kuglojn!,¡Has pillado unas balas!,¡Has recogido unas balas!,Kahmaiset patruunoita!,Vous prenez des balles!,,Prendi delle munizioni!,幾つかのラウンド を奪った!,권총 탄약을 주웠다!,Je pakt wat rondes!,Podniosłeś trochę naboi!,Você pegou munição!,,Ai ridicat niște muniție!,Заполучена обойма патронов!, -You grab a case of rounds!,GOTROUNDSCASE,,,,Sebral@[ao_cs] jsi krabici nábojů!,Munitionskiste genommen.,,Vi prenis skatolon da kugloj!,¡Has pillado una caja de balas!,¡Has recogido una caja de balas!,Kahmaiset patruunalaatikon!,Vous prenez une bôite de balles!,,Prendi un caso di munizioni!,ケースのラウンド を奪った!,권총 탄약 상자를 주웠다!,Je pakt een kist met rondes!,Podniosłeś skrzynkę naboi!,Você pegou uma caixa de munição!,,Ai ridicat un cartuș de muniție!,Заполучена коробка патронов!, -You grab a Torpedo!,GOTTORPEDO,"Was ""grap"" for some reason.",,,Sebral@[ao_cs] jsi torpédo!,Torpedo genommen.,,Vi prenis Torpedon!,¡Has pillado un torpedo!,¡Has recogido un torpedo!,Kahmaiset torpedon!,Vous prenez une torpille!,,Prendi un siluro!,トルペード を奪った!,광자탄을 주웠다!,Je pakt een Torpedo!,Podniosłeś Torpedę!,Você pegou um Torpedo!,,Ai ridicat o Torpilă!,Заполучена торпеда!, -You grab a case of Torpedos!,GOTTORPEDOS,,,,Sebral@[ao_cs] jsi krabici torpéd!,Torpedokiste genommen.,,Vi prenis skatolon da Torpedoj!,¡Has pillado una caja de torpedos!,¡Has recogido una caja de torpedos!,Kahmaiset torpedolaatikon!,Vous prenez une bôite de torpilles!,,Prendi un caso di siluri!,トルペードのケース を奪った!,광자탄 무더기를 주웠다!,Je pakt een kist Torpedo's!,Podniosłeś skrzynkę Torped!,Você pegou uma caixa de Torpedos!,,Ai ridicat o cutie de Torpile!,Заполучен ящик торпед!, -You grab a molecule module!,GOTMOLECULES,,,,Sebral@[ao_cs] jsi molekulový modul!,Molekülmodul genommen,,Vi prenis molekulmodulon!,¡Has pillado un módulo molecular!,¡Has recogido un módulo molecular!,Kahmaiset molekyylimoduulin!,Vous prenez un module moléculaire!,,Prendi un modulo molecolare!,モーレキュールモヂュール を奪った!,분자 모듈을 주웠다!,Je pakt een molecuulmodule!,Podniosłeś molekularny moduł!,Você pegou um módulo molecular!,,Ai ridicat un modul molecular!,Заполучен молекулярный модуль!, -You grab a tank full of molecules!,GOTMOLECULESTANK,,,,Sebral@[ao_cs] jsi sud plný molekul!,Tank mit Molekülmodulen genommen.,,Vi prenis reservujon da molekulojn!,¡Has pillado un tanque lleno de moléculas!,¡Has recogido un tanque lleno de moléculas!,Kahmaiset tankin täynnä molekyylejä!,Vous prenez un réservoir de molécules!,,Prendi un serbatoio pieno di molecole!,タンク満タンのモーレキュール を奪った!,분자 탱크를 주웠다!,Je pakt een tank vol met moleculen!,Podniosłeś zbiornik pełen molekuł!,Você pegou um tanque cheio de moléculas!,,Ai ridicat un rezervor plin cu molecule!,Заполучен контейнер с молекулами!, -You grab some Cartridges!,GOTCARTRIDGES,,,,Sebral@[ao_cs] jsi nějaké kazety!,Magazin genommen.,,Vi prenis iom da kartoĉoj!,¡Has pillado unos cartuchos!,¡Has recogido unos cartuchos!,Kahmaiset kasetteja!,Vous prenez des cartouches!,,Prendi alcune cartucce!,残弾のカートリッジ を奪った!,카트리지 한 줌을 주웠다!,Je pakt een paar patronen!,Podniosłeś trochę pocisków!,Você pegou alguns Carregadores!,,Ai ridicat niște Cartușe!,Заполучены картриджи!, -You grab a case of Cartridges!,GOTCARTRIDGESCASE,,,,Sebral@[ao_cs] jsi krabici kazet!,Magazinkiste genommen.,,Vi prenis skatolon da kartoĉoj!,¡Has pillado una caja de cartuchos!,¡Has recogido una caja de cartuchos!,Kahmaiset laatikollisen kasetteja!,Vous prenez une bôite de cartouches!,,Prendi un caso di cartucce!,カートリッジケース を奪った!,카트리지 박스를 주웠다!,Je pakt een kist patronen!,Podniosłeś skrzynkę pocisków!,Você pegou uma caixa de Carregadores!,,Ai ridicat o cutie de Cartușe!,Заполучен ящик картриджей!, -You grab a Valise stuffed with goods!,GOTVALISE,,,,Sebral@[ao_cs] jsi kufr plný munice!,Munitionstasche genommen.,,Vi prenis valizon plenan de municiojn!,¡Has pillado una maleta llena de equipamiento!,¡Has recogido una maleta llena de equipamiento!,Kahmaiset laukullisen täynnä tavaraa!,Vous récupérez une valise pleine d'équipement!,,Prendi una Valigia piena di merci!,代物を詰めたバリス を奪った!,탄약이 든 서류 가방을 주웠다!,Je pakt een Valise gevuld met goederen!,Podniosłeś Walizkę z wieloma dobrami!,Você pegou uma Mala cheia de equipamento!,,Ai ridicat o Valiză plină cu bunătăți!,Заполучена полная сумка боеприпасов!, -Force Field!,GOTFORCEFIELD,,,,Silové pole!,Kraftfeld!,,Fortkampo!,¡Campo de fuerza!,,Voimakenttä!,Champ de force!,,Campo di forza!,フォースフィールド!,방어막!,Krachtveld!,Pole Siłowe!,Campo de Força!,,Câmp de Forță!,Силовое поле!, -007Microtel,GOTMICROTEL,,,,,,,007 Microtel!,Microtel 007,,,007 Microtel,,,007マイクロテル,007마이크로텔 근력 향상 칩!,,,,,Microtel 007,Микрочип 007, -You are EnK Blind!,GOTENKBLIND,,,,Jsi EnK-slep@[adj_cs]!,Du bist EnK-blind!,,Vi estas ENK-Blinda,¡Tienes Ceguera EnK!,,Olet EnK-sokea!,Vous êtes aveugle à l'EnK!,,Sei EnK-cieco!,EnKブラインドみてえだ!,EnK 투명 위장 장치!,Jij bent EnK Blind!,Jesteś oślepiony przez EnK!,Você está vendado por EnK!,,Acum ești nedetectabil pentru Enk!,"У тебя EnK-видимость! -", -Vulcan rubber Boots!,GOTRUBBERBOOTS,,,,Gumové boty!,Gummistiefel!,,Vulkanaj Kauŭĉukaj Botoj!,¡Botas de goma vulcanizada!,,Vulkanoidut kumisaappaat!,Bottes en caoutchouc vulcanisé!,,Stivali di gomma vulcanica!,バルカンラバーブーツ!,벌컨 방화 부츠!,Vulcan rubber Laarzen!,Gumowe Buty Vulcan!,Botas Vulcanizadas!,,Bocanci din cauciuc Vulcan!,Резиновые сапоги!, -SI Array mapping!,GOTSIARRAY,,,,Mapa pole SI!,SI-Feld Karte!,,SI-matric-mapado!,¡Mapeado de Tabla SI!,,SI-kenttäkartta!,Carte du tableau SI!,,Mappatura di array SI!,SIアーレイ マッピング!,Si 어레이 지도!,,Mapa Pola SI!,Mapeamento por Campo de SI!,,Hartă SI compilată!,Составлена карта SI-массива!, -Infrared Visor!,GOTINFRARED,,,,Infračervené brýle!,Infrarotbrille!,,Transruĝa Viziero!,¡Visor infrarrojo!,,Infrapunavisiiri!,Viseur infrarouge!,,Visore a infrarossi!,赤外線バイザー!,적외선 바이져!,Infrarood vizier!,Wizjer na Podczerwień!,Visor Infravermelho!,,Vedere Infraroșie!,Инфракрасный визор!, -"Breathe deep, Inhaler!",GOTINHALER,,,,"Pořádně se nadechni, inhalátor!","Atme tief, Inhalierer!",,"Spiru profunde, inhalo!","¡Un inhalador, inspira fuerte!",,"Hengitä syvään, inhalaattori!","Respire, inhaleur!",,"Respirare profondamente, inalatore!",深呼吸だ、インヘイラー!,각성제를 주웠다. 잘 들이마셔!,"Adem diep in, inhalator!",Weź głęboki wdech! Inhalator!,Inalador! Respira fundo!,,"Inspiră adânc, Inhalatorule!",Ингалятор! Вдыхай глубже!, -A dose of Hydergine from a Hypo saves you!,GOTHYPONEED,,,,Jsi zachráněn@[ao_cs] dávkou Hyderginu z Hypa!,Eine Dosis Hydergine rettet dich!,,,¡Una dosis de Hydergina te salva la vida!,,Hyderginepiikkiannos pelastaa sinut!,Une bonne dose d'hydergine vous sauve la vie!,,Una dose di Hydergine di un Hypo ti salva!,ハイポで ヒデルギン をキメた!,하이포의 하이데르진이 당신을 살렸다!,Een dosis Hydergine van een Hypo redt je!,Dawka Hyderginy z Hypo ratuje cię!,Uma dose de hidergina do Hypo para te salvar!,,O doză de Hidrogine dintr-o seringă te salvează!,Доза Редергина из шприца спасла тебя!, -You grab a Hypo!,GOTHYPO,,,,Sebral@[ao_cs] jsi Hypo!,Hypo!,,Vi prenis Injektilon!,¡Has pillado una jeringa hipodérmica!,,Kahmaiset piikin!,Vous prenez une seringue!,,Prendi un Hypo!,ハイポ を奪った!,하이포를 주웠다!,Je pakt een Hypo!,Podniosłeś Hypo!,Você pegou um Hypo!,,Ai ridicat o Seringă!,Заполучен шприц!, -You found a KeyCard!,GOTKEYCARD,,,,Nalezl@[ao_cs] jsi přístupovou kartu!,Schlüsselkarte gefunden!,,Vi trovis Ŝlosilkarton!,¡Has encontrado una Tarjeta Llave!,,Löysit avainkortin!,Vous trouvez une clé magnétique!,,Hai trovato una chiave magnetica!,キーカードを見つけた!,키 카드를 찾았다!,U heeft een sleutelkaart gevonden!,Znalazłeś Kartę Dostępu!,Você achou um Cartão de Passe!,,Ai găsit un Card-Cheie!,Найдена ключ-карта!, -You found a C-Key!,GOTCKEY,,,,Nalezl@[ao_cs] jsi kyberklíč!,C-Schlüssel gefunden!,,Vi trovis C-Ŝlosilon!,¡Has encontrado una Llave-C!,,Löysit C-avaimen!,Vous trouvez une C-Clé!,,Hai trovato una chiave C!,C-keyを見つけた!,C-키를 찾았다!,Je hebt een C-sleutel gevonden!,Znalazłeś Klucz C!,Você achou uma Chave-C!,,Ai găsit o Cheie-C!,Найден C-образный ключ!, -You found a Password!,GOTPASSWORD,,,,Nalezl@[ao_cs] jsi heslo!,Passwort gefunden!,,Vi trovis Pasvorton!,¡Has encontrado una Contraseña!,,Löysit salasanan!,Vous trouvez un mot de passe!,,Hai trovato una parola d'ordine!,パスワードを見つけた!,암호를 찾았다!,U heeft een wachtwoord gevonden!,Znalazłeś Hasło!,Você achou uma Senha!,,Ai găsit o Parolă!,Найден пароль!, -You found a blue Z-Key!,GOTBLUEZKEY,,,,Nalezl@[ao_cs] jsi modrý Z-klíč!,Blauen Z-Schlüssel gefunden!,,Vi trovis bluan Z-ŝlosilon!,¡Has encontrado una Llave-Z azul!,,Löysit sinisen Z-avaimen!,Vous trouvez une Z-Clé bleue!,,Hai trovato una chiave Z blu!,ブルー Z-Key を見つけた!,청색 Z-키를 찾았다!,Je hebt een blauwe Z-sleutel gevonden!,Znalazłeś niebieski Klucz Z!,Você achou uma Chave-Z azul!,,Ai găsit o Z-Cheie albastră!,Найден синий Z-образный ключ!, -You found a yellow Z-Key!,GOTYELWZKEY,,,,Nalezl@[ao_cs] jsi žlutý Z-klíč!,Gelben Z-Schlüssel gefunden!,,Vi trovis flavan Z-ŝlosilon!,¡Has encontrado una Llave-Z amarilla!,,Löysit keltaisen Z-avaimen!,Vous trouvez une Z-Clé jaune!,,Hai trovato una chiave Z gialla!,イエローZ-Key を見つけた!,황색 Z-키를 찾았다!,Je hebt een gele Z-sleutel gevonden!,Znalazłeś żółty Klucz Z!,Você achou uma Chave-Z amarela!,,Ai găsit o Z-Cheie galbenă!,Найден жёлтый Z-образный ключ!, -You found a red Z-Key!,GOTREDZKEY,,,,Nalezl@[ao_cs] jsi červený Z-klíč!,Roten Z-Schlüssel gefunden!,,Vi trovis ruĝan Z-ŝlosilon!,¡Has encontrado una Llave-Z roja!,,Löysit punaisen Z-avaimen!,Vous trouvez une Z-Clé rouge!,,Hai trovato una chiave Z rossa!,レッド Z-Key を見つけた!,적색 Z-키를 찾았다!,Je hebt een rode Z-sleutel gevonden!,Znalazłeś czerwony Klucz Z!,Você achou uma Chave-Z vermelha!,,Ai găsit o Z-Cheie roșie!,Найден красный Z-образный ключ!, -Body Armor!,GOTBODYARMOR,,,,Brnění!,Körperpanzerung!,,Kiraso!,¡Armadura!,,Suojavarustus!,Armure!,,Giubbotti antiproiettile!,ボディーアーマー!,강화복!,Kogelvrije vesten!,Pancerz!,Colete a Prova de Balas!,,Armură de Corp!,Бронежилет!, -Centrophenoxine,GOTCENTROPHENOXINE,,,,Centrofenoxin,,,Centrofenoksino!,¡Centrofenoxina!,,Sentrofenoksiinia,Centrophenoxine!,,,セントロフェノキシン!,메클로페녹세이트!,,Centrofenoxina,Centrofenoxina,,Centrofenoxine,Центрофеноксин, -You grab a Kevlar vest!,GOTKEVLARVEST,,,,Sebral@[ao_cs] jsi kevlarovou vestu!,Kevlarweste!,,Vi prenis kevlaran veŝton!,¡Has pillado un traje de Kevlar!,¡Has recogido un traje de Kevlar!,Kahmaiset Kevlar-liivit!,Veste en Kevlar!,,Prendi una maglia di kevlar!,ケブラーベスト を奪った!,방탄복을 주웠다!,Pak een Kevlar vest!,Podniosłeś kamizelkę kuloodporną!,Você pegou um Colete de Kevlar!,,Ai ridicat o vestă din Kevlar!,Заполучен кевларовый жилет!, -You grab Super Kevlar vest!,GOTSKEVLARVEST,,,,Sebral@[ao_cs] jsi superkevlarovou vestu!,Super-Kevlarweste!,,Vi prenis superan kevlaran veŝton!,¡Has pillado un supertraje de Kevlar!,¡Has recogido un supertraje de Kevlar!,Kahmaiset Superkevlar-liivit!,Super Veste en Kevlar!,,Prendi una maglia super kevlar!,スーパーケブラーベスト を奪った!,중 방탄복을 주웠다!,Je pakt een Super Kevlar vest!,Podniosłeś superkamizelkę kuloodporną!,Você pegou um Super Colete de Kevlar!,,Ai ridicat o Super Vestă din Kevlar!,Заполучен усиленный кевларовый жилет!, -You grab a MicroKit!,GOTMICROKIT,,,,Sebral@[ao_cs] jsi mikrosadu!,MicroKit genommen!,,Vi prenis Kompleteton!,¡Has pillado un MicroKit!,¡Has recogido un MicroKit!,Kahmaiset Microkitin!,Microkit!,,Prendi un MicroKit!,マイクロキット を奪った!,마이크로킷을 주웠다!,Je pakt een MicroKit!,Podniosłeś MikroZestaw!,Você pegou um MicroKit!,,Ai ridicat un MicroKit!,Заполучена мини-аптечка!, -You grab a Dampener!,GOTDAMPENER,,,,Sebral@[ao_cs] jsi tlumič!,Dämpfer genommen!,,Vi prenis Dampilon!,¡Has pillado un Amortiguador!,¡Has recogido un Amortiguador!,Kahmaiset vaimentimen!,Amortisseur!,,Prendi un antivento!,ダンプナー を奪った!,완충 장치를 주웠다!,Je pakt een Demper!,Podniosłeś Tłumik!,Você pegou um Amortecedor!,,Ai ridicat un Amortizor!,Заполучен глушитель!, -You need a C-Key to access this item!,PD_CKEY,,,,K přístupu potřebuješ kyberklíč!,Du brauchst einen C-Schlüssel um das hier zu bedienen.,,Vi bezonas C-ŝlosilon por aliri ĉi tiun objekton!,¡Necesitas una Llave-C para acceder a este objeto!,,Tarvitset C-avaimen saadaksesi pääsyn tähän kohteeseen!,Il vous faut une C-Clé pour accéder à cet objet!,,Hai bisogno di una chiave C per accedere a questo oggetto!,アクセスには C-key が必要だ!,C-키가 있어야 작동이 가능하다!,Je hebt een C-sleutel nodig om toegang te krijgen tot dit item!,Potrzebujesz Klucza C by uruchomić ten przedmiot.,Você precisa de uma Chave-C para acessar!,,Ai nevoie de o Cheie-C pentru a accesa acest obiect!,"Нет доступа, нужен C-образный ключ!", -You need a KeyCard to access this item!,PD_KEYCARD,,,,K přístupu potřebuješ přístupovou kartu!,Du brauchst eine Schlüsselkarte um das hier zu bedienen.,,Vi bezonas Slosilkarton por aliri ĉi tiun objekton!,¡Necesitas una Tarjeta Llave para acceder a este objeto!,,Tarvitset avainkortin saadaksesi pääsyn tähän kohteeseen!,Il vous faut une carte magnétique pour accéder à cet objet!,,Hai bisogno di una chiave magnetica per accedere a questo oggetto!,アクセスには キーカード が必要だ!,키 카드가 있어야 작동이 가능하다!,U heeft een sleutelkaart nodig om toegang te krijgen tot dit item!,Potrzebujesz Karty Dostępu by uruchomić ten przedmiot!,Você precisa de uma Chave de Passe para acessar!,,Ai nevoie de un Card-Cheie pentru a accesa acest obiect!,"Нет доступа, нужен ключ-карта!", -You need a Password to access this item!,PD_PASSWORD,,,,K přístupu potřebuješ heslo!,Du brauchst eine Passwort um das hier zu bedienen.,,Vi bezonas Pasvorton por aliri ĉi tiun objekton!,¡Necesitas una Contraseña para acceder a este objeto!,,Tarvitset salasanan saadaksesi pääsyn tähän kohteeseen!,Il vous faut un mot de passe pour accéder à cet objet!,,Hai bisogno di una parola d'ordine per accedere a questo oggetto!,アクセスには パスワード が必要だ!,암호를 입력해야 작동이 가능하다!,Je hebt een wachtwoord nodig om toegang te krijgen tot dit item!,Potrzebujesz Hasła by uruchomić ten przedmiot!,Você precisa de uma Senha para acessar!,,Ai nevoie de Parolă pentru a accesa acest obiect!,"Нет доступа, нужен пароль!", -You need a Blue Z-Key to make this work,PD_BLUEZKEY,,,,Tohle bude fungovat jen s modrým Z-klíčem.,Du brauchst einen blauen Z-Schlüssel um das hier zu bedienen.,,Vi bezonas Bluan Z-ŝlosilon por funkciigi ĉi tiun!,¡Necesitas una Llave-Z azul para hacer funcionar esto!,,Tarvitset sinisen Z-avaimen saadaksesi tämän toimimaan!,Il vous faut une Z-Clé bleue pour faire fonctionner cela.,,Hai bisogno di una chiave Z blu per accedere a questo oggetto!,アクセスには ブルーZ-key が必要だ!,청색 Z-키가 있어야 작동이 가능하다!,Je hebt een blauwe Z-sleutel nodig om dit te laten werken.,Potrzebujesz Niebieskiego Klucza Z by zadziałało!,Você precisa de uma Chave-Z azul para fazer isto funcionar!,,Ai nevoie de o Cheie-Z albastră pentru a face asta să funcționeze!,"Не работает, нужен синий Z-образный ключ!", -You need a Red Z-Key to make this work!,PD_REDZKEY,,,,Tohle bude fungovat jen s červeným Z-klíčem.,Du brauchst einen roten Z-Schlüssel um das hier zu bedienen.,,Vi bezonas Ruĝan Z-ŝlosilon por funkciigi ĉi tiun!,¡Necesitas una Llave-Z roja para hacer funcionar esto!,,Tarvitset punaisen Z-avaimen saadaksesi tämän toimimaan!,Il vous faut une Z-Clé rouge pour faire fonctionner cela.,,Hai bisogno di una chiave Z gialla per accedere a questo oggetto!,アクセスには レッドZ-key が必要だ!,적색 Z-키가 있어야 작동이 가능하다!,Je hebt een rode Z-sleutel nodig om dit te laten werken!,Potrzebujesz Czerwonego Klucza Z by zadziałało!,Você precisa de uma Chave-Z vermelha para fazer isto funcionar!,,Ai nevoie de o Cheie-Z roșie pentru a face asta să funcționeze!,"Не работает, нужен красный Z-образный ключ!", -You need a Yellow Z-Key to make this work!,PD_YELWZKEY,,,,Tohle bude fungovat jen se žlutým Z-klíčem.,Du brauchst einen gelben Z-Schlüssel um das hier zu bedienen.,,Vi bezonas Flavan Z-ŝlosilon por funkciigi ĉi tiun!,¡Necesitas una Llave-Z amarilla para hacer funcionar esto!,,Tarvitset keltaisen Z-avaimen saadaksesi tämän toimimaan!,Il vous faut une Z-Clé jaune pour faire fonctionner cela.,,Hai bisogno di una chiave Z rossa per accedere a questo oggetto!,アクセスには イエローZ-key が必要だ!,황색 Z-키가 있어야 작동이 가능하다!,Je hebt een gele Z-sleutel nodig om dit te laten werken!,Potrzebujesz Żółtego Klucza Z by zadziałało!,Você precisa de uma Chave-Z amarela para fazer isto funcionar!,,Ai nevoie de o Cheie-Z galbenă pentru a face asta să funcționeze!,"Не работает, нужен жёлтый Z-образный ключ!", -"Twenty mill in gold doesn't seem worth all -this aggravation, does it, hacker? Makes -the pen look like a freakin' picnic! - -Butt-ugly bio-mutations and your fellow -Humans hung from a ceiling like -food sacks. - -What the hell is this GENIE? Like no -computer you've ever hacked! - -You better find the next terminal, slice -a ride through c-space, dice some mutant -butt, and get the hell out of Dodge! - -",X1TEXT,,,,"Dvacet miliónů ve zlatě nevypadá, že by -stálo za všechnu tuhle otravu, co, hackeře? -Basa teď vypadá jako krásný hotel! - -Ošklivé bio-mutace a tví lidští společníci -visící ze stropu jako pytle masa. - -Co je sakra tenhle GENIE? Takový počítač -jsi ještě nenaboural@[ao_cs]! - -Měl@[ao_cs] bys najít další terminál, projet -se kyberprostorem, vysekat pár mutantům -střeva a rychle z Dodge vypadnout!","Zwanzig Millionen in Gold sind nicht -wirklich so viel wert, Hacker, nicht wahr? -Das hier lässt den Knast wie ein -Picknick erscheinen. - -Hässliche Bio-Mutationen und deine -menschlichen Artgenossen hängen von -der Decke wir Futtersäcke. - -Was zur Hölle ist dieses GENIE? Das ist -wie kein anderer Computer den du -jemals gehackt hast. - -Du findest besser das nächste Terminal, -erledigst einige Mutantenärsche und -siehst zu, aus Dodge herauszukommen!",,"Dudek milionoj en oro ne ŝajnas valori -ĉi tiun ĝenon, ĉu ne, kodrompisto? Fek! -Faras la karceron aspekti kiel pikniko! - -Turpaĉaj bio-mataciuloj kaj viaj -homaj kunuloj pendis de la plafono -kiel sakoj da manĝajo. - -Kio diable estas ĉi tiu GENIE? Ĝi estas -kiel neniu komputilo, kiun vi kodrompis! -... nek kiel ia ĝino! - -Vi devas trovi la sekvan stacion, preni -rajdon tra ciberspaco, haki iom da -mutaciulo-pugo, kaj eliru de ĉi tie!","Veinte millones en oro no parece que valgan -la pena por todo este lío, ¿no crees, hacker? -¡Hace que el corral parezca un picnic! - -Horripilantes biomutaciones y tus compañeros -humanos cuelgan del techo como sacos. - -¿Qué demonios es GENIE? ¡No se parece a -cualquier computadora que hayas hackeado! - -¡Más te vale encontrar la próxima terminal, dar -un viaje por el ciberespacio, rebanar unos -cuantos traseros mutantes, y pirarte de Dodge!","Veinte millones en oro no parece que valgan -la pena por todo este lío, ¿no crees, hacker? -¡Hace que el corral parezca un picnic! - -Horripilantes biomutaciones y tus compañeros -humanos cuelgan del techo como sacos. - -¿Qué demonios es GENIE? ¡No se parece a -cualquier computadora que hayas hackeado! - -¡Más te vale encontrar la próxima terminal, dar -un viaje por el ciberespacio, rebanar unos -cuantos traseros mutantes, y largarte de Dodge!","20 miltsiä kultaa ei taida olla kaiken tämän -vaivan väärti, eihän, hakkeri? Saa kynän sen -rinnalla tuntumaan perhanan piknikiltä! - -Karsean rumia biomutaatioita ja kanssa- -ihmisiäsi roikkumassa katosta kuin mitkäkin -ruokakassit. - -Mikä helvetti on tämä GENIE? Ei minkään -ennen hakkeroimasi tietokoneen kaltainen! - -Parasta löytää seuraava pääte, napata kyyti -c-avaruuden läpi, piestä vähän mutantteja -ja häipyä hittoon Dodgesta!","Vingt Millions en or ne semblent -plus valoir tout ces problèmes -maintenant, Hacker? Tout ce bordel -donne un air de pique-nique -à la prison! - -De mutations hideuses et vos -frèrs humains pendant du plafond -comme des sacs de nourriture. - -C'est quoi comme foutoir, ce GENIE? -Aucune ordinateur que vous avez -piraté auparavant était comme ça! - -Il faut que vous trouvez le prochain -terminal, traversez le cyberespace, -découpez du mutant et barrez-vous -d'ici!",,"Venti mulini d'oro non sembra valere tutto -questo peggioramento, vero, hacker? -Fa sembrare la penna come un -cavolo di picnic! - -Le enormi bio-mutazioni e i tuoi -compagni umani appesi a un soffitto -come sacchi di cibo. - -Che diavolo è questo GENIE? -Come nessun computer che -tu abbia mai hackerato! - -Faresti meglio a trovare il terminale -successivo, a fare un giro nel c-spazio, -a tagliare a dadi qualche culo mutante, -e ad uscire da Dodge! - -","20ミリの金塊にこの重大な事態の価値を見出せない、 -それとも、ハッカーの仕業か? -幻覚のピクニックってワケでもねえ! -グロいバイオミュータントと人間の仲間が食肉のように -天井から吊るされている。 - -GENIEとは一体何なんだ? 少なくともこれまで -ハックしたことのないコンピューターだってことだ! - -次のターミナルを抜け、c-spaceに乗り込み、 -ミュータントのダニ共を切り裂いて、このふざけた -場所から抜け出すんだ!","2000만 달러 보상금 가지고는 턱도 없을 정도의 개판이었어! 안 그런가, -해커 양반? 펜이나 끄적거리는 게 이것보다는 훨씬 쉬울 테니 말이야. - -이 더럽게 못생긴 돌연변이들이며, 천장에 마늘꾸러미처럼 매달려있는 -사람들을 볼 일도 없고 말이야. - -그리고... 이 지니란 녀석은 도대체 뭐지? 네가 해킹했던 다른 컴퓨터들과는 -완전 차원이 다른 녀석이야. 어서 다른 단말기를 찾아서 C-Space를 타고 -접속하는 게 좋을 것 같아. - -돌연변이들을 몇 마리 썰어버리면서, 이곳을 빠져나가 는 것도 잊지 말고!","Twintig miljoen in goud lijkt al die verergering -niet waard, of wel, hacker? Het laat de gevangenis -eruit zien als een verdomde picknick! -Lelijk bio-mutaties en je medemensen hingen -als voedselzakken aan een plafond. - -Wat is dit GENIE in godsnaam? Als geen enkele -computer die je ooit hebt gehackt! -Je kunt maar beter de volgende terminal vinden, -een ritje door de c-ruimte maken, een paar -gemuteerde kontdobbelstenen dobbelen, -en Dodge in hemelsnaam verlaten!","Dwadzieścia milionów w złocie nie jest warte -tych kłopotów, prawda hakerze? Przy tym -więzienie wygląda jak cholerny piknik! - -Ohydne bio-mutacje i inni ludzie zwisają -z sufitu jak przekąski. - -Czym u diabła jest to GENIE? Nie jest jak inne -komputery, które hakowałeś! - -Lepiej znajdź kolejny terminal, przeleć przez -Przestrzeń C, skop trochę zmutowanych tyłków -i wynoś się z tego piekielnego Uskoku! -","Vinte milhões em ouro não parecem valer -toda essa incomodação, não é mesmo, hacker? -O xilindró é um piquenique perto disso! - -Biomutações feias pra caramba estão penduradas -no teto junto com seres humanos como se -fossem sacos de alimento. - -Que diabos é esse tal de GENIE? Não é como nenhum -outro computador que você já tenha hackeado! - -É melhor achar o próximo terminal, pegar uma -carona pelo ciberespaço, fazer picadinho de -mutante e vazar deste lugar de uma vez!",,"Douăzeci de milioane în aur nu par să fie -suficienți pentru tot dezastrul acesta, nu-i așa, -hacker? Totul pare un fleac pe lângă asta! - -Mutanți urâți foc, împreună cu oamenii tăi -atârnă de tavan asemeni unor saci de mâncare. - -Ce naiba mai e și acest GENIE? E ca un computer -pe care nu l-ai mai spart în viața ta! - -Mai bine găsești următorul terminal, prinzi o -mașină în spațiul cibernetic, feliezi niște mutanți, -și îți iei tălpășița!","Стоят ли двадцать лимонов золотом таких -трудностей, а, хакер? Теперь тебе тюрьма -грёбаным санаторием покажется! - -Толстозадые биомутанты и такие же люди, -как ты, лежат рядком, как мешки с едой. - -Что за хрень этот ДЖИНН? Он не похож ни -на один из компьютеров, что ты уже -взламывал! - -Найди терминал, прокатись по -киберпространству, надери всем мутантам -задницы и выберись из этой чёртовой -передряги! - -", -"Where are all the people?! - -Paris is a ghost town, unless you consider -mutant bugs outstanding citizens. - -You've hit bloody resistance. Man, can -these bugs fight! Lucky for you they're not -the brightest porch lights on the block. - -But you've gotten some of the informatics -the subcommittee wants. And it's nasty! - -Human neural fluids feed these bugs! No -wonder the neighborhood's getting kind of -sparse. Report to the subcommittee. And -watch your back... -",X2TEXT,,,,"Kde jsou všichni!? - -Z Paříže je město duchů, leda že bys -zmutované bugy považoval@[ao_cs] za vzorné občany. - -Narazil@[ao_cs] jsi na tvrdý odpor. Sakra, tyhle -bugy umí bojovat! Naštěstí ale nejsou -zrovna nejchytřejší. - -Ale dostal@[ao_cs] jsi některé ty informace, který -podvýbor chtěl. A je to pěkný hnus! - -Tyhle bugy se krmí lidským mozkovým mokem! -Není divu, že je ve čtvrti nějak prázdno. -Nahlaš se zpátky u výboru. A dávej pozor...","Wo sind all die Menschen!? - -Paris ist eine Geisterstadt, es sei denn, -du zählst die Mutanten als Musterbürger. - -Du bist auf blutigen Widerstand getroffen. -Mann können diese Viecher kämpfen. -Glücklicherweise sind sie nicht die hellsten -Leuchten. - -Aber du hast einige Informationen, die -das Subkommitee haben will. Und es ist -übel. - -Menschliche Nervenflüssigkeit ist was -diese Viecher antreibt. Kein Wunder, dass -die Nachbarschaft am Aussterben ist. -Das musst du dem Subkommitee -mitteilen. Und pass auf!",,"Kie estas ĉiuj homoj?! - -Parizo estas senhoma urbo, se vi ne -konsideras mutaciajn cimojn elstaraj -urbanoj. - -Vi kontraŭstaras sangan reziston. Ve, -ĉu tiuj cimoj povas batali! Bonsorte, -ili ne estas la plej granda saĝulo. - -Tamen, vi akiris iom el la informaĵoj, -kiujn la komisiono volas. Kaj ĝi estas fia! - -Homaj neŭraj likvaĵoj nutras la cimojn! -Ne mirinde, ke la urbo ŝajnas iĝi iomete -neloĝata. Raportu al la kimisiono. -Singardu...","¡¿Dónde está toda la gente?! - -Paris es una ciudad fantasma, a menos que -consideres que los bichos mutantes sean -unos buenos ciudadanos. - -Has encontrado resistencia sangrienta. Tío, ¡si -que pelean estos bichos! Por suerte para ti no -son los más brillantes del barrio. - -Pero has conseguido algunos materiales -informáticos que el subcomité quiere. -¡Y tienen mala pinta! - -¡Fluidos neuronales humanos alimentan a -estos bichos! No es de extrañar que el -vecindario esté algo despoblado. Personate -ante el subcomité. Y vigila tus espaldas...","¡¿Dónde está toda la gente?! - -Paris es una ciudad fantasma, a menos que -consideres que los bichos mutantes sean -unos buenos ciudadanos. - -Has encontrado resistencia sangrienta. Tío, ¡si -que pelean estos bichos! Por suerte para ti no -son los más brillantes del barrio. - -Pero has conseguido algunos materiales -informáticos que el subcomité quiere. -¡Y tienen mala pinta! - -¡Fluidos neuronales humanos alimentan a -estos bichos! No es de extrañar que el -vecindario esté algo despoblado. Repórtate -ante el subcomité. Y vigila tus espaldas...","Missä kaikki ovat?! - -Pariisi on aavekaupunki, ellei mutantti- -öttiäisiä sitten lasketa mallikansalaisiksi. - -Olet iskenyt hitonmoiseen vastukseen. Vitsi -nämä ötökät tappelevat! Onneksesi ne eivät -ole korttelin kirkkaimpia ulkovaloja. - -Mutta olet saanut osan informatiikasta, jota -alakomitea kaipaa, ja se on pahaa luettavaa! - -Ihmisen hermonesteet ruokkivat ötököitä! Ei -ihme, että tienoo alkaa tuntua väljältä. -Raportoi alakomitealle ja vahdi selustaasi...","Où se trouve trout le monde? -Paris est une ville fantôme, sauf si -vous considérez que les insectes -mutants sont des citoyens. -Vous avez rencontré une sacrée -résistance, ces sales bestioles -savent se battre! Heureusement, -il ne sont pas les plus malins du -coin.. -Vous avez récupéré une partie de -l'informatique que le sous-comité -demande. Ca a un sale air! -Des fluides neuraux humains -alimentent ces insectes! Pas -de surprise que le coin est -désert. Retournez au sous-comité -et faites gaffe à vous!",,"Dove sono tutte le persone?! -Parigi è una città fantasma, a meno -che non si consideri mutante -bug cittadini eccezionali. - -Hai colpito resistenza sanguinosa. -Amico, questi insetti possono combattere! -Fortunatamente per voi non sono le -luci dei portici più brillanti del blocco. - -Ma hai ottenuto un po' dell'informatica -che il sottocomitato vuole. Ed è brutto! - -I fluidi neurali umani alimentano -questi insetti! Non c'è da stupirsi -che il quartiere sia sempre più rado. -Segnala al sottocomitato. - -E guardatevi le spalle ... -","皆何処に行った?! - -パリはゴーストタウンと化した、突然変異したバグ共が -未解決なまま自分以外の住民はいなくなった。 - -マジな敵対にぶち当たった。野郎、こんなバグ共と戦えと! -幸運なことに先行きの見えない事態ではない。 -だがここでインフォーマティクスとサブコミッティが -望んでいた物を探し当てた。厄介なことにな! - -人の神経液をバグ共が餌にしている! 近くに転がっていた -者が損壊していたのも納得がいく、サブコミッティに -報告しなければ。背中に気をつけながらな... -","여기 사람들은 도대체 어디로 간 거지?! - -프랑스 파리도 완전히 유령도시가 되어버렸군, 저 돌아다니는 돌연변이 -버그들이 시민은 아닐 테니까. - -방금 전투는 정말 위험했어. 빌어먹을 버그들 생각보다 잘 싸우더군. -머리가 좋은 놈들은 아니라서 다행이야. 그래도 위원회 놈들이 원하는 -정보는 얻었으니 다행이야. 놈들 꽤 더러운 걸 숨기고 있더군. - -인간의 척수를 빨아먹는 버그들이라니! 이 주변 대가 허허벌판인 것도 -당연할 수밖에. 어서 위원회 놈들한테 보고하자고. 그리고 언제나 -등 뒤를 조심해.","Waar zijn alle mensen?! -Parijs is een spookstad, tenzij je mutanten -als uitstekende burgers beschouwt. - -Je hebt bloedige weerstand geraakt. Man, kan -deze beestjes vechten! Gelukkig voor jou -zijn ze niet de helderste lichten op het blok. - -Maar je hebt een aantal van de informatica -gekregen die de subcommissie wil. En het is -vervelend! -Menselijke neurale vloeistoffen voeden deze -beestjes! Geen wonder dat de buurt een -beetje schaarser wordt. Rapporteer aan -de subcommissie. En let op je rug...","Gdzie wszyscy ludzie? - -Paryż stał się miastem duchów, no chyba że -uznasz zmutowane robale za jego mieszkańców. - -Napotkałeś cholerny opór. Kurde, te robale -umieją przywalić! Na szczęście nie są -najświetlejsze w tym lokalu. - -Ale zdobyłeś trochę informacji, które chciał -podkomitet. I nie są dobre! - -Ludzkie płyny neuronowe są pokarmem dla -tych robali! Nic dziwnego, że okolica jest -spustoszona. Zgłoś się do podkomitetu. -I uważaj na siebie...","Cadê todo mundo? - -Paris é uma cidade fantasma, a não ser que você -considere os mutantes como cidadãos especiais. - -Você enfrenta uma baita resistência. Cara, esses -bichos sabem brigar! Sorte sua que eles não são -as criaturas mais espertas do local. - -Mas você conseguiu pegar algumas informações -que o subcomitê estava querendo. E a coisa é feia! - -Esses bichos se alimentam de fluídos neurais -humanos! Não é a toa que a vizinhança anda ficando -meio vazia ultimamente. Entre em contato com -o subcomitê. E fique de olho...",,"Unde e toată lumea?! - -Parisul e un oraș fantomă, asta dacă nu consideri -mutanții cetățeni nemaipomeniți. - -Ai întâmpinat opoziție serioasă! Mamă, gândacii -aceștia știu să lupte, nu glumă! Din fericire nu -sunt cei mai tari din parcare. - -Dar deții niște informații pe care comitetul vrea -să le vadă! Și nu sunt prea încântătoare! - -Fluidele neuro umane hrănesc acești gândaci! -Nu-i de mirare că vecinătatea devine cam pustie. -Raportează înapoi la comitet. Și păzește-ți -spatele...","Где все люди?! - -Париж опустел, не считая уродливых -багов, заменивших горожан. - -Ты столкнулся с ожесточённым -сопротивлением. Чёрт, эти баги слетаются -к тебе, как мухи на свет! К счастью, ты не -самый яркий фонарь в этом городе. - -Но теперь в твоих руках кое-какая -информация, которая нужна подкомитету. -И это скверно! - -Эти баги подпитываются нервными -импульсами людей! Понятно, почему -вокруг не осталось никого живого. -Передай эти сведения подкомитету. -И будь осторожен... -", -"Civilization as you knew it is nada! - -No friends, no family. No more people. -Not normal people, anyway. - -Only one thing left...GENIE! -And if you have to go to the end of the -universe you'll find its mutant butt! -'cause now you're pissed! - -And the gold? Hell, this is for free. - -.....(to be continued)..... -",X3TEXT,,,,"Civilizace, tak jak ji známe, je pryč. -Nada. Nilch. - -Bez přátel, bez rodiny. Bez lidí. -Alespoň těch normálních. - -Jediná zbylá věc... GENIE! -I kdybys musel@[ao_cs] jít až na konec vesmíru, -najdeš jeho zmutovaný ksicht! -Protože teď jsi fakt nasran@[adj_cs]! - -A to zlato? Sakra, tohle děláš zadarmo. - -.....(pokračování příště).....","Die Zivilisation, wie du sie kanntest, -ist Nada. Keine Freunde, keine Familie. -Keine Menschen mehr. Zumindest -keine normalen. - -Nur eine Sache verbleibt: GENIE! -Und wenn du ans Ende des Universum -reisen müsstest, du wirst seinen -Mutantenarsch finden, denn jetzt -bist du sauer! - -Und das Gold? Das gibt's als Zugabe... - -... (Fortsetzung folgt) ... - -",,"La civilizoj, kiun vi konis, estas nulita! - -Neniuj amikoj, neniu familio, neniuj -homoj plu. Neniu normaj homoj, ĉiuokaze. - -Nur unu aĵo restas... GENIE! -Kaj eĉ se vi bezonos iri la limo de -la universo, vi trovos ĝian mutacian pugon! -Ĉar vi furiozas! - -Pri la oro? Diable, ĉi tio estas senpaga. - -.....(Daŭrigota).....","¡La civilización como la conoces ya no es nada! - -Sin amigos, ni familia. No más gente. -No gente normal, de todos modos. - -Solo queda una cosa... ¡GENIE! -¡Y si tienes que ir hasta el fin del universo -encontrarás su trasero mutante! -¡Porque ahora si que estás cabread@[ao_esp]! - -¿Y el oro? Para nada, esto es gratis. - -... (continuará) ...",,"Tuntemasi sivilisaatio on mennyttä! - -Ei ystäviä, ei perhettä, ei enää ihmisiä; -tai ainakaan ei normaaleja ihmisiä. - -Vain yksi asia jäljellä... GENIE! -Ja vaikka joutuisit menemään universumin -ääriin, löydät sen mutanttipersauksen! -Sillä nyt sinua ottaa päähän! - -Ja kulta? Hitto, teen tämän ilmaiseksi. - -.....(jatkuu).....","La société humaine a disparu! - -Plus d'amis, plus de famille, plus -personne de normal, du moins. - -Une chose reste.. GENIE! -Si il le faut, vous irez jusqu'au -bout de l'univers pour lui botter -le cul! Ca va en chier! - -Oh, et l'Or? Non, ça, c'est gratuit... - -... A suivre!",,"Civiltà come lo sapevi che è nada! -Nessun amico, nessuna famiglia. -Niente più persone. -Non persone normali, comunque. - -Solo una cosa è rimasta...GENIE! -E se dovete andare alla fine -dell'universo troverete il suo -culo mutante! - -Perché ora sei incazzato! -E l'oro? Diavolo, questo è gratis... -","俺の知っている文明は崩壊した! - -友も。家族も。住民も。まともなヤツは何もかも -消え失せた。 - -だがまだ一つ残っている...GENIE! -このまま銀河の終焉を迎えたらミュータントのクソになる! -それだけは御免だ! - -それで金は? 有り得ん、これはフリーだ。 - -...だがこれ以上続くことはない...","자네도 알다시피 이제 문명이란 건 존재하지 않아! - -친구들, 가족, 그리고 사람들도 다 사라졌지. 돌연변이들이 있긴 하지만. - -이제 유일하게 남은 건... 지니일 거야. 그 빌어먹을 녀석을 우주 끝까지 -쫓아가서 박살 내 버리자고! 자네를 화나게 한 값은 톡톡히 치르게 해줘야지? - -보상금? 이번엔 필요 없어, 이번 일은 공짜로 해줄 테니. - -...(다음에 계속)...","De beschaving zoals je die kende is nada! - -Geen vrienden, geen familie. Geen mensen meer. -In ieder geval geen normale mensen. -Nog maar één ding over...GENIE! - -En als je naar het einde van het universum -moet gaan, vind je de gemuteerde kont! -want nu ben je boos! - -En het goud? Hel, dit is gratis. - -... (wordt vervolgd)...","Cywilizacja, którą znałeś zniknęła! - -Nie ma przyjaciół i rodziny. Już nie ma ludzi. -Przynajmniej normalnych ludzi. - -Została tylko jedna rzecz...GENIE! -I nawet jeśli musisz dotrzeć na sam kraniec -świata, znajdziesz jego zmutowane dupsko! -Ponieważ wiesz, że będziesz wkurzony! - -A złoto? Jest kurde za darmo. - -.....(ciąg dalszy nastąpi).....","A civilização como você conhecia já era! - -Sem amigos, sem família. Sem mais ninguém. -Ninguém normal, pelo menos. - -A única coisa que resta...é GENIE! -E nem que você tenha que ir até o fim do -universo, você vai encontranr a fuça mutante dele! -Agora você está furios@[ao_ptb] pra caramba! - -E o ouro? Que se dane, essa é por conta da casa. - -....(continua)....",,"Civilizația așa cum o știai e dusă! - -Fără prieteni, fără familie. Nu mai sunt oameni. -Nu oameni obișnuiți, în orice caz. - -Un singur lucru rămas... GENIE! -Și îi vei găsi hoitul împuțit chiar dacă va trebui -să traversezi până în celălalt capăt al universului! -Pentru că acum ești mânios! - -Iar aurul? La naiba cu el, asta e din partea casei. - -.....(va urma).....","Цивилизация, которую ты знал, исчезла! - -Ни друзей, ни родных. Не осталось никого. -Нормальных людей – точно. - -Осталось только одно существо. ДЖИНН! -Ты надерёшь зад этому уроду, даже если -придётся дойти до края Вселенной. Теперь -это личное! - -Что насчёт золота? К чёрту, это не ради -денег. - -.....(продолжение следует)..… -", -"You're alive! - -What are those odds, hacker?! -'cause it's crawling with bugs. - -You can't reach the subcommittee, which -means it's been compromised. - - -You... are alone.",X5TEXT,,,,"Jsi naživu! - -Jaké byly naděje, hackeře!? -Protože se to tu hemží bugy. - -Nemůžeš se dostat k podvýboru, což -znamená, že byl kompromitován. - - -Jsi... @[self_cs].","Du lebst! - -War waren die Chancen, Hacker?! - -Du kannst das Subkommitee nicht -erreichen, was bedeutet, dass es -kompromittiert ist. - -Du... bist alleine.",,"Vi vivas! - -Kia estas la ŝancoj, kodrompisto?! -Ĉar en ĝi svarmas cimoj. - -Vi ne povas atingi la komisionon, -kio signifas, ke ĝi estas okupata. - - -Vi... estas sola.","¡Estás viv@[ao_esp]! - -¡¿Que probabilidades había, hacker?! -Porque esto está lleno de bichos. - -No puedes llegar al subcomité, lo que -significa que ha sido comprometido. - - -Tú... estás sol@[ao_esp].",,"Sinä olet elossa! - -Mitkä todennäköisyydet, hakkeri?! -Sillä se kuhisee ötököitä. - -Et saa tavoitettua alakomiteaa, mikä -tarkoittaa sitä, että se on murrettu. - - -Sinä... olet yksin.","Vous êtes vivant! - -Quelle chance, Hacker! Avec toutes -ces bestioles partout! - -Vous ne pouvez pas contacter le -sous-comité. Cela signifie qu'il est -compromis. - -Vous.. êtes seul.",,"Sei vivo! -Quali sono queste probabilità, hacker?! -Perché strisciano di insetti. -Non puoi raggiungere il sottocomitato, -Il che significa che è stato compromesso. -Tu... sei solo. -","俺は生きている! - -何か勝ち目はあるか、ハッカー?! -バグ共がそこいらを蠢いている。 -サブコミッティに繋がらないのは、侵入されたと -思っていいだろう。 - -俺は...また一人だ。","아직도 살아있었네! - -귀신 곡할 노릇이야. 안 그래, 해커 친구? 버그 놈들이 그렇게나 -들끓어댔는데 말이지. - -위원회들도 더는 응답을 하지 않아, 아마 놈들도 다 당한 거겠지. - -그래... 자넨 이제 혼자야.","Je leeft nog! -Wat zijn die kansen, hacker?! - -Je kunt het subcommissie niet bereiken, -wat betekent dat het in gevaar is gebracht. - -Je... bent alleen.","Żyjesz! - -Co to za dziwo hakerze?! -Ponieważ pełza wraz z robactwem. - -Nie możesz dotrzeć do podkomitetu, co -oznacza, że musi być kompromis. - -Jesteś... sam.","Você sobreviveu! - -Quais são as chances, hacker?! -Pois há criaturas por toda a parte. - -Você não consegue entrar em contato com -o subcomitê, o que significa que eles estão -em perigo. - - -Você...está sozinh@[ao_ptb].",,"Ești viu! - -Care sunt șansele, hacker?! Pentru că colcăie de -gândaci. - -Nu poți ajunge la comitet, ceea ce înseamnă că -a fost compromis. - - -Ești... singur.","Ты выжил! - -Какая теперь разница, Хакер? Это место -просто кишит багами. - -Ты не можешь связаться с подкомитетом. -Похоже, ваш канал связи раскрыт. - - -Ты... остался один. -", -,,,,,,,,,,,,,,,,,,,,,,, -GenEmp Corp.,TXT_HACXMAP01,,,,Sídlo GenEmp,,,Korporacio GenEmp,,,GenEmp-yhtiö,,,,GenEmpコーポ,ZONE 1: 진엠프 주식회사 본부,,,,,Corporația GenEmp,Корпорация ГенИмп, -Tunnel Town,TXT_HACXMAP02,,,,Tunelové město,Tunnelstadt,,Tunelo Urbeto,Pueblo Túnel,,Tunnelikaupunki,Ville Tunnel,,Città del tunnel,トンネル タウン,ZONE 2: 터널 도시,Tunnelstad,Miasto Tuneli,Cidade Túnel,,Orașul Subteran,Подземный город, -Lava Annex,TXT_HACXMAP03,,,,Lávová přístavba,Lavaanbau,,Lafa Anekso,Anexo de Lava,,Laavalaajennus,Annexe de Lave,,Annesso di lava,ラバ アネックス,ZONE 3: 용암 속 건물,Lava Bijlage,Aneks Lawy,Anexo de Lava,,Anexa de Lavă,Лавовая электростанция, -Alcatraz,TXT_HACXMAP04,,,,,,,Alkatrazo,,,,,,,アルカトラズ,ZONE 4: 알카트라즈,,,,,,Алькатрас, -Cyber Circus,TXT_HACXMAP05,,,,Kybercirkus,Cyberzirkus,,Cibernetika Cirko,Circo Cibernético,,Kybersirkus,,,Circo Cyber,サイバーサークル,ZONE 5: 사이버 서커스,,Cyber Cyrk,Circo Cibernético,,Circ Cibernetic,Кибер-Цирк, -Digi-Ota,TXT_HACXMAP06,,,,,,,,,,,,,,デジ - オータ,ZONE 6: 디지-오타,,,,,,Диджитал-Ота, -The Great Wall,TXT_HACXMAP07,,,,Velká zeď,Die große Mauer,,La Grandega Muro,La Gran Muralla,,Suuri muuri,La grande Muraille,,Il grande muro,ザ - グレート ウォール,ZONE 7: 만리장성,De grote muur,Wielka Ściana,A Grande Muralha,,Marele Zid,Великая стена, -Garden of Delights,TXT_HACXMAP08,,,,Zahrada rozkoše,Lustgarten,,Ĝardeno de Ĝuoj,Jardin de las Delicias,,Nautintojen puutarha,Jardin de Délices,,Giardino delle delizie,ガーデン オブ デライト,ZONE 8: 쾌락의 정원,Tuin van lekkernijen,Ogród Zachwytu,Jardim dos Prazeres,,Grădina Plăcerilor,Сад наслаждений, -Hidden Fortress,TXT_HACXMAP09,,,,Skrytá pevnost,Versteckte Festung,,Kaŝita Fortreso,Fortaleza Oculta,,Salainen linnoitus,Forteresse Secrète,,Fortezza nascosta,ヒドゥン フォートレス,ZONE 9: 숨겨진 요새,Verborgen Vesting,Ukryta Forteca,Fortaleza Oculta,,Fortăreața Ascunsă,Скрытая крепость, -Anarchist Dream,TXT_HACXMAP10,,,,Anarchistův sen,Anarchistentraum,,Anarkia Sonĝo,Sueño Anarquista,,Anarkistin unelma,Rève d'Anarchiste,,Sogno anarchico,アナーキスト ドリーム,ZONE 10: 아나키스트의 꿈,Anarchistische droom,Sen Anarchisty,Sonho Anarquista,,Vis Anarhist,Анархистская утопия, -Notus Us!,TXT_HACXMAP11,,,,,,,,¡Notus Us!,,Pane merkille mEIdät!,,,,ワレラノ ノータス,ZONE 11: 노터스 어스!,,,,,Nu ne vor uita!,Нас не забудут!, -Gothik Gauntlet,TXT_HACXMAP12,,,,Gotický trest,,,Gotika Spaliro,Guantelete Gótiko,,Goottinen kujanjuoksu,Gantelet Gothik,,,ゴシック ガントレット,ZONE 12: 고딕풍 결투장,,Gotycka Rękawica,Punição Gótika,,Mănușa Gotică,Готическая перчатка, -The Sewers,TXT_HACXMAP13,,,,Kanály,Die Kanäle,,La Kanaloj,Las Alcantarillas,,Viemärit,Les Egouts,,Le fogne,ザ・サワー,ZONE 13: 하수 처리장,De Riolen,Ścieki,Os Esgotos,,Canale,Канализация, -Trode Wars,TXT_HACXMAP14,,,,Válka elektrod,Elektrodenkrieg,,Milito de Elektrodoj,Guerra de Electrodos,,Trodisodat,Guerre des Trodes,,Guerra degli elettrodi,トレード ウォーズ,ZONE 14: 전격의 전쟁,Trode oorlogen,Wojna Elektrod,Guerra de Eletrodos,,Război cu Electrozi,Торговые войны, -Twilight of Enk's,TXT_HACXMAP15,,,,Soumrak EnKu,Zwielicht von EnK,,Krespusko de EnK-oj,Crepúsculo de los Enk,,EnKin illankoitto,Crépuscule des Enk's,,Crepuscolo di Enk,Enkタチ ノ トワイライト,ZONE 15: 전자황혼,Schemering van Enk's,Zmierzch Enk,Crepúsculo de Enk's,,Amurgul lui Enk,Сумерки EnK, -Protean Cybex,TXT_HACXMAP16,,,,Proměnlivý Cybex,Proteanischer Cybex,,Protea Cybex,Cybex Protéico,,Muuntuvainen Kybex,,,,プロテアン サイベックス,ZONE 16: 변화무쌍한 사이벡스,Proteanische Cybex,Zmienny Cybex,Cybex Proteano,,Cybex Caleidoscopic,Многоликий Сайбэкс, -River of Blood,TXT_HACXMAP17,,,,Řeka krve,Blutfluss,,Rivero de Sango,Río de Sangre,,Verivirta,Rivière de Sang,,Fiume di sangue,リバー オブ ブラッド,ZONE 17: 학살의 강,Rivier van bloed,Rzeka Krwi,Rio de Sangue,,Râu de Sânge,Река крови, -Bizarro,TXT_HACXMAP18,,,,Bizár,,,,,,,,,,ビザロ,ZONE 18: 요상한 곳,,,,,,Бизарро, -The War Rooms,TXT_HACXMAP19,,,,Válečné kabinety,Kriegsräume,,La Militĉambroj,Las Salas de Guerra,,Sotahuoneet,La Salle des Commandes,,Le stanze della guerra,ザ・ウォー ルーム,ZONE 19: 전략 회의실,De oorlogskamers,Pokoje Wojny,As Salas de Comando,,Camerele de Control,Генеральный штаб, -Intruder Alert!,TXT_HACXMAP20,,,,"Pozor, vetřelec!",Eindringlingsalarm!,,Alarmo pri Entrudanto!,¡Alerta de Intruso!,,Murtohälytys!,"Alerte, Intrus!",,Allarme intruso!,シンニュウシャ アリ!,ZONE 20: 칩입자 경보!,Inbreker alarm!,Alarm Intruz!,Alerta de Intruso!,,Alertă Intrus!,Тревога! Нарушитель!, -Desiccant Room,TXT_HACXMAP31,,,,Sušící místnost,Trocknungsraum,,Ĉambro de Elsekigo,Sala del Desecante,,Kuivatesali,Salle du Desiccant,,Stanza disseccante,ダスキン ルーム,ZONE 31: 건조한 곳,Drogende kamer,Śluza Osuszająca,Sala do Dessecante,,Camera Desicanților,Сушильная комната, -"Now Arriving At... -",STSTR_CLEV,,,,Příjezd do...,Angekommen bei...,,Nun Ĝisirante...,Ahora llegando a...,,Seuraavana...,On arrive maintenant à:,,Arrivando a...,今到着した...,이동하는 중...,Nu we aankomen bij....,Wchodzisz do...,Agora chegando em ...,,Acum Sosiți La...,Переходим на..., -...gonna fry your ass!,STSTR_CHOPPERS,"Printed when entering the idchoppers cheat, which gives the player a chainsaw",,,...ti upeče prdel!,...ich brate deinen Arsch!,,...fritos vian pugon!,... ¡voy a freirte el trasero!,,...kärtsää takalistosi!,...C'est l'heure de botter du cul!,,....ti friggerà il culo!,...ケツまくれ!,... 지져버리겠어!,...gaat je kont bakken!,...skopię ci dupę!,...vou fritar teu rabo!,,...te voi prăji!,...поджарит твою задницу!, -"inVuln, Str, Inviso, Rad, Allmap, or Lite-amp?",STSTR_BEHOLD,"Hacx's content here was totally useless so it got removed. However, this string has to be defined and minimally altered so that the Dehacked replacement is not being triggered.",,,"nesmrt(V), Síla, nevId, Rad, mApa nebo světLo","inVuln, Str, Inviso, Rad, Allmap, oder Lite-amp",,"inVuln, Str, Inviso, Rad, Allmap, aŭ Lite-amp?","inVuln, Str, Inviso, Rad, Allmap, o Lite-amp.",,"haavoittumattomuus (V), voima (S), näkymättömyys (I), koko kartta (A) tai valonvahvistus (L)?","in V ulnérable, S urpuissance, I nvisible, p R otection, c A rte, où L umière?","Sérthet (V), Berz (S), Láthat(i), Sugár(R), Térkép(A), vagy Fény Sisak(L)","inVuln, berSerk, Invisib, tuta anti-Rad, mAppa tutta, o amplif-Luce","V,I,S,R,A,Lのどれだ?","무적, 광전사, 투명, 보호복, 지도, 아니면 바이저?",,"niezniszczalność (V), siła (S), niewidzialność (I), kombinezon (R), mapa (A) lub gogle noktowizyjne (L)","inVuln., berSerk, Invisib., anti-Rad., mApa completo ou amplificação de Luz",,"inVul, Forță ampl, Invizib, Hartă compl, sau Vedere amplificată?","Бессм. (V), берс. (S), нев. (I), кос. (R), крт. (A), виз (L).","нерањ., снага, невидљ., радиј., мапа или ноћ. визор" -Let's Get Serious!,STSTR_BEHOLDX,,,,Teď je to vážné!,Es wird ernst!,,Ni Serioziĝu!,¡Vamos en Serio!,,Otetaanpa tosissaan!,Passons aux choses sérieuses!,,Prendiamoci sul serio!,マジになったぜ!,철들 때다!,Laten we serieus worden!,Bądźmy Poważni!,Agora a Coisa Fica Séria!,,Să Devenim Serioși!,А теперь серьёзно!, -Cyberslicer Mode ON,STSTR_NCON,,,,Režim kybersekače ZAP,Cyberschnetzelmodus AN,,Cibernetika Tranĉila Reĝimo AKTIVA,Modo Cibercorte ACTIVADO,,Kyberviipaloijatila PÄÄLLÄ,,,Modalità Cyberslicer ATTIVADA,サイバースライサーモード オン,전자마귀 모드 ON,Cyberslicer-modus AAN,Tryb Cybercięcia WŁĄCZONY,Cibercortador ATIVADO,,Modul Cibertăietor ACTIVAT,Режим кибер-резака вкл., -Cyberslicer Mode OFF,STSTR_NCOFF,,,,Režim kybersekače VYP,Cyberschnetzelmodus AUS,,Cibernetika Tranĉila Reĝimo MALAKTIVA,Modo Cibercorte DESACTIVADO,,Kyberviipaloijatila POIS PÄÄLTÄ,,,Modalità Cyberslicer DISATTIVADA,サイバースライサーモード オフ,전자마귀 모드 OFF,Cyberslicer-modus UIT,Tryb Cybercięcia WYŁĄCZONY,Cibercortador DESATIVADO,,Modul Cibertăietor DEZACTIVAT,Режим кибер-резака откл., -Selection: Impossible ,STSTR_NOMUS,,,,Nemožný výběr,Falsche Auswahl,,Elekto: Malebla,Selección impossible,,Valinta ei mahdollinen,Séléction Impossible!,Lehetetlen Kiválasztás,Selezione impossibile,選択: 不可能,선택 불가능,Selectie: Onmogelijk,Niemożliwy wybór,Seleção: Impossível,,Selectare: Imposibilă,Выбор: Невозможен,НЕМОГУЋИ ИЗБОР -"Pump Up The Volume -",STSTR_MUS,Should probably not be translated...,,,Zesil to!,,,,,,Nuppi kaakkoon,,,,音量を上げろよ,볼륨을 올려라!,,,"Som na Caixa, DJ!",,Mărește Volumul,Подкрутите громкость, -INIT-Twitch n'Kill Mode,STSTR_KFAADDED,,,,Inicializuji režim Twitch and Kill,Initiiere Twitch'n Kill-Modus,,INIC-Modo de Tiku kaj Buĉu,INIT-Modo Tirar a Matar,,INIT-Nykäise ja nylje -tila,,,Iniziare Twitch n'Kill Mode,INIT-Twitch n'Killモード,때리고 죽이는 모드 ON,,Inicjacja Trybu Drżenia I Zabijania,Inicializando Modo Chumbo Grosso,,INIT-Modul Click-și-Elimină,ИНИЦ: режим Кликай-И-Убивай, -"So be it, Hacker.",STSTR_FAADDED,,,,"Budiž, Hackeře.","So sei es, Hacker.",,"Tiel estu, Kodrompisto.","Que así sea, Hacker.",,"Olkoon niin, hakkeri.","Qu'il en soit ainsi, hacker.",,"Cosi' sia, Hacker.",好きにしろ、ハッカー。,"마음대로 해, 해커 양반.","Het zij zo, Hacker.","Niech tak będzie, Hakerze.","Que assim seja, Hacker.",,"Așa să fie, Hacker.","Да будет так, Хакер.", -Cyberpotence Mode ON,STSTR_DQDON,,,,Režim kybermoci ZAP,Cyberpotenzmodus AN,,Cibernetikpova Reĝimo AKTIVA,Modo Ciberpotencia ACTIVADO,,Kyberpotenssitila PÄÄLLÄ,,,Modo Cyberpotenza ATTIVADA,サイバーポテンスモード オン,전지전능 모드 ON,Cyberpotentiemodus AAN,Tryb Cyberpotencji WŁĄCZONY,Ciberpotência ATIVADA,,Ciberpotență ACTIVATĂ,Режим Кибер-улучшения вкл., -Cyberpotence Mode OFF,STSTR_DQDOFF,,,,Režim kybermoci VYP,Cyberpotenzmodus AUS,,Cibernetikpova Reĝimo MALAKTIVA,Modo Ciberpotencia DESACTIVADO,,Kyberpotenssitila POIS PÄÄLTÄ,,,Modo Cyberpotenza DISATTIVADA,サイバーポテンスモード オフ,전지전능 모드 OFF,Cyberpotentiemodus UIT,Tryb Cyberpotencji WYŁĄCZONY,Ciberpotência DESATIVADA,,Ciberpotență DEZACTIVATĂ,Режим Кибер-улучшения откл., -Tracking ON,AMSTR_FOLLOWON,,,,Sledování ZAP,Verfolgung AN,,Spurdado AKTIVA,Seguimiento ACTIVADO,,Seuranta PÄÄLLÄ,,,Mappa scorribile DISATTIVATA,トラッキング オン,추적 모드 ON,Tracking AAN,Namierzanie WŁĄCZONE,Seguimento ATIVADO,,Urmărire ACTIVATĂ,Сопровождение вкл., -Tracking OFF,AMSTR_FOLLOWOFF,,,,Sledování VYP,Verfolgung AUS,,Spurdado MALAKTIVA,Seguimiento DESACTIVADO,,Seuranta POIS PÄÄLTÄ,,,Mappa scorribile ATTIVATA,トラッキング オフ,추적 모드 OFF,Tracking UIT,Namierzanie WYŁĄCZONE,Seguimento DESATIVADO,,Urmărire DEZACTIVATĂ,Сопровождение откл., -- press Y to run away! -,DOSY,,,,- stiskni Y pro útěk! -,- drücke Y um wegzurennen -,,- premu Y por forkuri! -,- ¡pulsa Y para escapar! - ,,- Paina Y paetaksesi! -,-Appuie sur Y pour t'échapper!-,,- premere Y per scappare! -,-Y でトンズラだ!-,- 달아날려먼 Y 키를 눌러! -,- druk op Y om weg te lopen! -,- wciśnij Y by uciec! -,- Aperte Y para fugir! -,- Carrega Y para fugir! -,- apasă Y pentru a fugi! -,"- нажми «Y», чтобы сбежать! -", -"Are you insane or maladjusted? -Well? Yes or No!",ENDGAME,,,,"Jsi blb@[adj_cs] nebo jen naveden@[adj_cs]? -Tak? Jo nebo ne?","Bist du verrückt oder mies gelaunt? -Also? Ja oer Nein?",,"Ĉu vi estas freneza aŭ misagordita? -Ĉu? Jes aŭ Ne!?","¿Estás loc@[ao_esp] o descolocad@[ao_esp]? -¿Y bien? ¿Sí o No?",,"Oletko hullu tai häiriintynyt? -No? Y tai N!",Vous êtes fou où malajusté? Eh bien? Oui où non?,,"Sei pazzo o disadattato? -Allora? Sì o no!","お前はイカれた社会不適合者だろ? -あぁ?イエスかノーか言え!","부적응은 안 하겠지? 그렇겠지? -자신 있으면 선택해!","Ben je gek of onaangepast? -Nou? Ja of Nee!","Oszalałeś czy się nie dostosowałeś? -Więc? Tak czy Nie!","Você é doido ou desregulado? -Hein? Sim ou Não!",,"Ești nebun sau doar prost calibrat? -Deci? Da sau Nu?","Ты дурак или родом так? -Отвечай! Да (Y) или нет (N)?", -"Are you sure? You can't handle -this skill, hacker! - -Press Y to die. -",NIGHTMARE,,,,"Jseš si jist@[adj_cs]? Takový -skill nemáš, hackeře!","Bist du sicher? Du kannst das nicht bewältigen, Hacker! - -Drücke Y um zu sterben.",,"Ĉu vi certas? Vi ne povas stari -kontraŭ ĉi tiu malfacileco, kodrompisto! - -Premu Y por morti.","¿Estás segur@[ao_esp]? ¡No puedes soportar esta dificultad, hacker! - -Pulsa Y para morir.",,"Oletko varma? Et pysty käsittelemään -tätä taitotasoa, hakkeri! - -Paina Y kuollaksesi. -","Vous êtes sûr? Vous n'arriverez pas à tenir le coup, hacker! - -Appuyez sur Y pour mourir.",,"Sei sicura? Non puoi gestire -questa abilità, hacker! - -Premere Y per morire. ","本気か? -アンタの手に負えないぞ、ハッカー! - -死にたきゃYを押せ。","그렇게 만만하다면 말리지는 않을게. -어차피 너에겐 복잡할 테니까, 해커 양반. - -준비됐으면 Y 키를 눌러.","Weet u het zeker? Je kunt niet omgaan met -deze vaardigheid, hacker! - -Druk op Y om te sterven.","Na pewno? Nie dasz -sobie rady hakerze! - -Wciśnij Y by zginąć.","Tem certeza? Você não vai conseguir -lidar com essa dificuldade, hacker! - -Aperte Y para morrer.","Tem certeza? Você não pode lidar -essa habilidade, hacker! - -Carrega Y para morrer.","Ești sigur? Nu poți face față dificultății, hacker! - -Apasă Y ca să mori.","Ты уверен? С этим уровнем сложности ты не справишься, хакер! - -Нажми «Y», чтобы умереть.", -"Quicksave over your data named - -'%s'? - -Press Y or N.",QSPROMPT,For most languages the original Doom text should suffice.,,,"Rychle uložit přes tvá data s názvem - -'%s'? - -Stiskni Y nebo N.","Überschreibe %s mit einem Schnellspeicherdatenstand? - -Drücke Y oder N.",,"Ĉu rapidkonservu super via ludo nomita - -'%s'? - -Premu Y aŭ N.","¿Deseas guardar sobre tu partida llamada - -'%s'? - -Presiona Y ó N.",,"Haluatko pikatallentaa pelin %s päälle? - -Paina Y tai N.","Sauvegarde rapide sur le fichier - -'%s'? - -Appuyez sur Y ou N.","Gyorsmenteni akarsz az alábbi mentésed alatt - -'%s'? - -Nyomj Y-t vagy N-t.","Sovrascrivere il salvataggio - -'%s'? - -Premi Y oppure N.","この名称で上書きするのか? - -'%s' - -YかNで答えろ。","빠른 저장? - -'%s' - -Y키 또는 N키를 입력.","Snel opslaan over je spel genaamd - -'%s'? - -Druk op Y of N.","Szybko nadpisać grę - -„%s”? - -Wciśnij Y lub N.","Salvar sobre seu jogo chamado - -'%s'? - -Aperte Y ou N.","Gravar sobre o seu jogo chamado - -'%s'? - -Carrega Y ou N.","Salvare rapidă peste fișierul numit - -'%s'? - -Apasă Y sau N.","Перезаписать файл - -«%s»? - -Нажмите «Y» или «N».","Желите брзо чување за игру под именом - -„%s“? - -Притисните Y или N." -"Do you want to quickload the data named - -'%s'? - -Press Y or N.",QLPROMPT,,,,"Přeješ si rychle načíst data s názvem - -'%s'? - -Stiskni Y nebo N.","Möchtest du den Datenstand %s schnellladen? - -Drücke Y oder N.",,"Ĉu vi volas rapidkonservi la konservo nomita - -'%s'? - -Premu Y-on aŭ N-on.","¿Quieres cargar la partida llamada - -'%s'? - -Presiona Y ó N.",,"Haluatko pikaladata pelin %s? - -Paina Y tai N.","Voulez-vous charger la sauvegarde - -'%s'? - -Appuyez sur Y ou N.","Gyorstölteni akarod ezt a mentést - -'%s'? - -Nyomj Y-t vagy N-t.","Vuoi fare un quickload della partita - -'%s'? - -Premi Y oppure N.","この名称をすぐロードするのか? - -'%s' - -YかNで答えろ。","빠른 불러오기? - -'%s' - -Y키 또는 N키를 입력.","Wil je het spel snel laden met de naam - -'%s'? - -Druk op Y of N.","Czy chcesz wczytać szybki zapis - -„%s”? - -Wciśnij Y lub N.","Deseja carregar o jogo chamado - -'%s'? - -Aperte Y ou N.","Deseja carregar o jogo chamado - -'%s'? - -Carrega Y ou N.","Vrei să încarci rapid fișierul numit - -'%s'? - -Apasă Y sau N.","Загрузить файл - -«%s»? - -Нажмите «Y» или «N».","Желите брзо учитавање за игру под именом - -„%s“? - -Притисните Y или N." -Thug,CC_THUG,,,,Pobuda,Scherge,,Perfortuloj,Matón,,Roisto,Brute,,Tazza,チンピラ,서그,Schurk,Zbir,Bandido,,Bandit,Головорез, -Android,CC_ANDROID,,,,,,,Androido,Androide,,Androidi,Androïde,,,アンドロイド,안드로이드,Androïde,Android,Andróide,,,Андроид, -ICE,CC_ICE,,,,,,,,,,,,,,アイス,아이스,,,,,,ЛЁД, -Buzzer,CC_BUZZER,,,,Bzučák,Summer,,Zumilo,Zumbador,,Surisija,,,Cicalino,ブザー,버저,Zoemer,Brzęczyk,,,Dronă,Летун, -D-Man,CC_DMAN,,,,,,,D-Vir',,,D-mies,,,,D-Man,디-맨,,,,,,Д-Мэн, -Phage,CC_PHAGE,,,,Fág,,,Faĝo,Fago,,Fagi,,,Fago,ファージ,페이지,Faag,Fag,Fago,,Mâncător,Пожиратель, -Monstruct,CC_MONSTRUCT,,,,Monstrukce,Monstrukt,,Monstrukto,,,Keinohirviö,,,Mostrutto,モンストラクト,몬스트럭트,Monstructie,Monstrukt,,,,Монструкт, -Mecha Maniac,CC_MECH,,,,Mechamaniak,,,Mekanika Frenezulo,Meca-Maníaco,,Mechamaanikko,Mécha-maniaque,,Mecha Maniaco,メカマニア,메카 메니악,Mecha Maniak,Mechaniczny Maniak,Meca-Maníaco,,Meca-Maniac,Механоман, -Terminatrix,CC_TERMI,,,,,,,,,,,,,,ターミネイトリクス,터미네트릭스,,,,,,Терминатриса, -Thorn Thing,CC_THORN,,,,Bodlák,Dornending,,Dorna Aĵo,Cosa Espinosa,,Okaolio,Truc épineux,,,ソーンツィン,쏜 씽,Doornding,Cierniowe Coś,Coisa Espinhosa,,Spinos,Тернистая тварь, -Majong 7,CC_MAJONG,,,,,,,Maĝango 7,,,Mahjong 7,,,,マージャン 7,마작 7호,,,,,,Маджонг 7, -Dan Evanger,CC_HERO,,,,,,,Dan Evanĝer,,,,,,,ダン エブァンガー,댄 에반저,,,,,,Дэн Эвенджер, -Please don't shoot!,SKILL_BABY,,,,"Nestřílej, prosím!",Bitte schieß nicht!,,Bonvolu ne pafi!,¡Por favor no dispares!,,"Pyydän, älä ammu!","Pitié, ne tirez pas!",,"Ti prego, non sparare!",撃たないでくれ!,쏘지 마세요!,"Niet schieten, alsjeblieft!",Proszę nie strzelaj!,"Por favor, não atire!",,Te rog nu trage!,"Не стреляй, пожалуйста!", -"Aargh, I need health!",SKILL_EASY,,,,Potřebuju zdraví!,Ich brauche Gesundheit!,,"Aargh, mi bezonas sanon!","¡Aargh, necesito salud!",,"Aargh, tarvitsen terveyttä!","Aargh, des soins!",,"Aargh, ho bisogno di salute!",キメてくれ!,체력이 필요해!,"Aargh, ik heb gezondheid nodig!","Ałć, potrzebuję apteczki!","Aargh, preciso de saúde!",,"Aarș, am nevoie de un medic!","А-а-ргх, аптечку!", -Let's rip them apart!,SKILL_NORMAL,,,,Rozsekejme je na kusy!,Lass uns sie zerfetzen!,,Ni disŝiru ilin!,¡Rompámoslos en pedazos!,,Revitään ne kappaleiksi!,J'en fais de la bouillie!,,Facciamoli a pezzi!,ばらまいてやれ!,갈기갈기 찢어버려!,Laten we ze uit elkaar scheuren!,Czas ich rozerwać!,Vamos despedaçá-los!,,Să-i facem zob!,Разорвём их на куски!, -I am immortal!,SKILL_HARD,,,,Jsem nesmrtelný!,Ich bin unsterblich!,,Mi estas senmorta!,¡Soy inmortal!,,Olen kuolemation!,Je suis immortel!,,Sono immortale!,とっととくたばれ!,난 무적이다!,Ik ben onsterfelijk!,Jestem nieśmiertelny!,Eu sou imortal!,,Sunt nemuritor!,Я бессмертен!, -Insanity!,SKILL_NIGHTMARE,,,,Šílenství!,Wahnsinn!,,Frenezo!,¡Locura!,,Mielettömyys!,Folie!,,Follia!,イカれてやがる!,코드명: 광기!,Waanzin!,Szaleństwo!,Insanidade!,,Demență!,Безумие!, \ No newline at end of file diff --git a/wadsrc_extra/static/filter/harmony/decaldef.txt b/wadsrc_extra/static/filter/harmony/decaldef.txt index 44abfe5e430..83fb0117f49 100644 --- a/wadsrc_extra/static/filter/harmony/decaldef.txt +++ b/wadsrc_extra/static/filter/harmony/decaldef.txt @@ -388,7 +388,7 @@ generator Beastling BulletChip generator Follower BulletChip generator Soldier BulletChip generator WalkingPhage2 BulletChip -generator Echida BulletChip +generator Echidna BulletChip generator PhageNeutron ArachnotronScorch generator GrenadeExplosion CacoScorch diff --git a/wadsrc_extra/static/filter/harmony/decorate.txt b/wadsrc_extra/static/filter/harmony/decorate.txt index db173e8d83b..94178aeb4de 100644 --- a/wadsrc_extra/static/filter/harmony/decorate.txt +++ b/wadsrc_extra/static/filter/harmony/decorate.txt @@ -548,7 +548,7 @@ actor Mine replaces LostSoul } } -actor Echida replaces SpiderMastermind +actor Echidna replaces SpiderMastermind { scale 0.33 health 5000 @@ -1274,51 +1274,6 @@ actor HarmonyBackpack : Backpack replaces Backpack scale 0.30 } -actor TimeBombWeapon : Weapon replaces BFG9000 -{ - scale 0.30 - weapon.kickback 100 - weapon.selectionorder 2800 - weapon.ammouse 1 - weapon.ammogive 2 - weapon.ammotype "TimeBombAmmo" - inventory.pickupmessage "$GOTBFG9000" - inventory.icon "BFUGA0" - +WEAPON.NOAUTOFIRE - +WEAPON.NOAUTOAIM - states - { - Select: - BFGG A 1 A_Raise - loop - Deselect: - BFGG A 1 A_Lower - loop - Ready: - BFGG A 1 A_WeaponReady - loop - Fire: - SHT2 A 3 - SHT2 A 7 A_CheckReload - SHT2 B 1 A_BFGSound - SHT2 B 7 - SHT2 C 6 - SHT2 D 7 A_FireBFG - SHT2 E 7 - SHT2 F 7 A_Light0 - SHT2 H 6 A_Light0 - SHT2 A 5 A_Refire - goto Ready - Flash: - BFGF A 11 bright A_Light1 - BFGF B 6 bright A_Light2 - SHTG E 0 A_Light0 - stop - Spawn: - BFUG A -1 - stop - } -} // The player should start with the hand grenades weapon, but no ammo. // TimeBombWeapon is used as the pickup which should only be picked up once // in multi player. diff --git a/wadsrc_extra/static/filter/harmony/endoom.bin b/wadsrc_extra/static/filter/harmony/endoom.bin new file mode 100644 index 00000000000..62f2b00bab0 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/endoom.bin differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0100.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0100.lmp new file mode 100644 index 00000000000..943569d4b28 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/010A.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/010A.lmp new file mode 100644 index 00000000000..4f89ebc06f3 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0112.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0112.lmp new file mode 100644 index 00000000000..84bf6a42d72 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0116.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0116.lmp new file mode 100644 index 00000000000..0c93d802471 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/011E.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/011E.lmp new file mode 100644 index 00000000000..d4ce8f14c63 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0120.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0120.lmp new file mode 100644 index 00000000000..d4ce8f14c63 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0122.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0122.lmp new file mode 100644 index 00000000000..2dfa5050439 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0126.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0126.lmp new file mode 100644 index 00000000000..101436c2bb8 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/012A.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/012A.lmp new file mode 100644 index 00000000000..93eb6b24294 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/012E.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/012E.lmp new file mode 100644 index 00000000000..2238b61f527 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0130.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0130.lmp new file mode 100644 index 00000000000..6503b97feff Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0136.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0136.lmp new file mode 100644 index 00000000000..5d0884608d2 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0139.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0139.lmp new file mode 100644 index 00000000000..1b60f50cf08 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/013B.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/013B.lmp new file mode 100644 index 00000000000..957e27e7d92 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/013D.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/013D.lmp new file mode 100644 index 00000000000..fb6a937a4a4 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0145.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0145.lmp new file mode 100644 index 00000000000..4e70d4acf73 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/014A.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/014A.lmp new file mode 100644 index 00000000000..0edb7491eca Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/014C.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/014C.lmp new file mode 100644 index 00000000000..2d63b1c324c Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0154.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0154.lmp new file mode 100644 index 00000000000..91906ea6453 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0166.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0166.lmp new file mode 100644 index 00000000000..9599db9429d Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/016A.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/016A.lmp new file mode 100644 index 00000000000..488d8af05f2 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0172.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0172.lmp new file mode 100644 index 00000000000..df39a2448ac Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0174.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0174.lmp new file mode 100644 index 00000000000..662a2415648 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0176.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0176.lmp new file mode 100644 index 00000000000..d75e1f504cc Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/018F.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/018F.lmp new file mode 100644 index 00000000000..528784fb56f Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/01FC.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/01FC.lmp new file mode 100644 index 00000000000..66fa281c4f5 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/01FE.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/01FE.lmp new file mode 100644 index 00000000000..dcbfb97dc84 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0394.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0394.lmp new file mode 100644 index 00000000000..17bc8a97741 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0398.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0398.lmp new file mode 100644 index 00000000000..c956af2ebda Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/039B.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/039B.lmp new file mode 100644 index 00000000000..eeba3b24d64 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/039E.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/039E.lmp new file mode 100644 index 00000000000..e4920fbcc20 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A3.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A3.lmp new file mode 100644 index 00000000000..4acb7c8c702 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A8.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A8.lmp new file mode 100644 index 00000000000..aab4c803627 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A9.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A9.lmp new file mode 100644 index 00000000000..ca0b5635a68 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0403.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0403.lmp new file mode 100644 index 00000000000..b0f2e3ab6a5 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0404.raw b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0404.raw new file mode 100644 index 00000000000..e010cb6ccf9 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0404.raw differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/040C.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/040C.lmp new file mode 100644 index 00000000000..fb837b2db16 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/040D.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/040D.lmp new file mode 100644 index 00000000000..faf008c07a1 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/040E.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/040E.lmp new file mode 100644 index 00000000000..aed9d396140 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/0490.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0490.lmp new file mode 100644 index 00000000000..0353569ef98 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E80.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E80.lmp new file mode 100644 index 00000000000..a8179dd2b14 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E82.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E82.lmp new file mode 100644 index 00000000000..b97cdd1dd60 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E84.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E84.lmp new file mode 100644 index 00000000000..0d9804210d0 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/bigfont/1EF2.lmp b/wadsrc_extra/static/filter/harmony/fonts/bigfont/1EF2.lmp new file mode 100644 index 00000000000..4bf3d6badc4 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/bigfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0100.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0100.lmp new file mode 100644 index 00000000000..0dd8b510e2f Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0100.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/010A.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/010A.lmp new file mode 100644 index 00000000000..743601ca9bb Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/010A.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0112.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0112.lmp new file mode 100644 index 00000000000..8897dc49da3 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0112.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0116.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0116.lmp new file mode 100644 index 00000000000..83083d13e1c Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0116.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/011E.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/011E.lmp new file mode 100644 index 00000000000..bb35ce1541a Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/011E.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0120.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0120.lmp new file mode 100644 index 00000000000..ae4ea3863d9 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0120.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0122.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0122.lmp new file mode 100644 index 00000000000..b979a1e565c Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0122.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0126.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0126.lmp new file mode 100644 index 00000000000..7ce93fb9e7f Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0126.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/012A.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/012A.lmp new file mode 100644 index 00000000000..4e53fc07c28 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/012A.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/012E.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/012E.lmp new file mode 100644 index 00000000000..39799c91920 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/012E.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0130.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0130.lmp new file mode 100644 index 00000000000..6a4703a0801 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0130.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0136.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0136.lmp new file mode 100644 index 00000000000..bb355c748cb Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0136.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0139.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0139.lmp new file mode 100644 index 00000000000..93c4212a1c9 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0139.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/013B.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/013B.lmp new file mode 100644 index 00000000000..ca4e38c7b1c Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/013B.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/013D.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/013D.lmp new file mode 100644 index 00000000000..503a98a47b5 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/013D.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0145.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0145.lmp new file mode 100644 index 00000000000..a427a7aaf33 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0145.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/014A.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/014A.lmp new file mode 100644 index 00000000000..19881b09c63 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/014A.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/014C.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/014C.lmp new file mode 100644 index 00000000000..2961f417446 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/014C.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0154.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0154.lmp new file mode 100644 index 00000000000..c6a6024d6ca Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0154.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0166.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0166.lmp new file mode 100644 index 00000000000..94f5183e453 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0166.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/016A.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/016A.lmp new file mode 100644 index 00000000000..d166eb7766f Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/016A.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0172.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0172.lmp new file mode 100644 index 00000000000..21882910354 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0172.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0174.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0174.lmp new file mode 100644 index 00000000000..9611c8f2508 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0174.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0176.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0176.lmp new file mode 100644 index 00000000000..6905035baa9 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0176.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/018F.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/018F.lmp new file mode 100644 index 00000000000..f77a48d1da7 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/018F.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/01FC.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/01FC.lmp new file mode 100644 index 00000000000..a4249a81aa3 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/01FC.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/01FE.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/01FE.lmp new file mode 100644 index 00000000000..290de29c598 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/01FE.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0394.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0394.lmp new file mode 100644 index 00000000000..a835867207d Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0394.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0398.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0398.lmp new file mode 100644 index 00000000000..2fc67e333d9 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0398.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/039B.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/039B.lmp new file mode 100644 index 00000000000..e464d6123c0 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/039B.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/039E.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/039E.lmp new file mode 100644 index 00000000000..cbd2b322781 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/039E.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A3.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A3.lmp new file mode 100644 index 00000000000..066748f5fe2 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A3.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A8.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A8.lmp new file mode 100644 index 00000000000..183eeb81200 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A8.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A9.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A9.lmp new file mode 100644 index 00000000000..b78a6f9d4be Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/03A9.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0403.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0403.lmp new file mode 100644 index 00000000000..6ce99ca21b1 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0403.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0404.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0404.lmp new file mode 100644 index 00000000000..a26b8009c4f Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0404.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040C.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040C.lmp new file mode 100644 index 00000000000..d378a53937b Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040C.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040D.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040D.lmp new file mode 100644 index 00000000000..6fd42f35995 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040D.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040E.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040E.lmp new file mode 100644 index 00000000000..fd7b4c13d97 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/040E.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0490.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0490.lmp new file mode 100644 index 00000000000..9fcdd23ca55 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/0490.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E80.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E80.lmp new file mode 100644 index 00000000000..6b0ba9d8a69 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E80.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E82.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E82.lmp new file mode 100644 index 00000000000..62575f30103 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E82.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E84.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E84.lmp new file mode 100644 index 00000000000..f6e6151f8ce Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1E84.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1EF2.lmp b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1EF2.lmp new file mode 100644 index 00000000000..cd69d3b41e0 Binary files /dev/null and b/wadsrc_extra/static/filter/harmony/fonts/defsmallfont/1EF2.lmp differ diff --git a/wadsrc_extra/static/filter/harmony/language.csv b/wadsrc_extra/static/filter/harmony/language.csv index 046c2edc89d..2343c0cecb0 100644 --- a/wadsrc_extra/static/filter/harmony/language.csv +++ b/wadsrc_extra/static/filter/harmony/language.csv @@ -1,14 +1,15 @@ -default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,pl,pt,ptg,ro,ru,sr -,,,,,,,,,,,,,,,,,,,,,,, +default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,da,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,no nb,pl,pt,ptg,ro,ru,sr,sv,tr Do you really think you can handle that?\n\npress 'Y' or 'N'...,NIGHTMARE,,,,"Opravdu si myslíš, že to zvládneš? -Zmáčkni Y nebo N.","Bist du sicher, dass du das bewältigen kannst? +Zmáčkni Y nebo N.","Tror du virkelig, at du kan klare det? + +Tryk på Y eller N...","Bist du sicher, dass du das bewältigen kannst? Drücke Y oder N.",,"Ĉu vi vere pensas, ke vi povas trakti tion? -Premu ""Y"" aŭ ""N""...","¿Realmente crees que puedes con eso? +Premu ""Y"" aŭ ""N""...","¿Realmente crees poder con eso? -Pulsa Y ó N...",,Uskotko todella pystyväsi tähän?\n\nPaina 'Y' tai 'N'...,Vous pensez sérieusement que vous pourrez tenir le coup?\n\nAppuyez sur Y ou N...,,"Pensi davvero di poterlo fare? +Pulsa Y o N...",,Uskotko todella pystyväsi tähän?\n\nPaina 'Y' tai 'N'...,Vous pensez sérieusement que vous pourrez tenir le coup?\n\nAppuyez sur Y ou N...,Biztos vagy abban hogy megbírkózol vele?\n\nnyomj 'Y'-t vagy 'N'-t,"Pensi davvero di poterlo fare? premere 'Y' o 'N'","ホントウニ タイショデキルト オモッテイマスカ? @@ -17,56 +18,55 @@ premere 'Y' o 'N'","ホントウニ タイショデキルト Y키, 아니면 N키를 누르시오...","Denk je echt dat je dat aankunt? -Druk op 'Y' of 'N'...","Czy ty naprawdę myślisz, że temu podołasz? - -Wciśnij 'Y' lub 'N'...","Você acha que é capaz de aguentar? - -Aperte Y ou N...",,Chiar crezi că poți face față?\n\napasă 'Y' sau 'N'...,"Уверены, что справитесь?\n\nНажмите «Y» или «N»...", -Spot marked,AMSTR_MARKEDSPOT,,,,Bod označen,Punkt markiert,,Punkto markita,Punto marcado,,Paikka merkitty,Repère marqué.,Hely megjelölve.,Posizione segnata,スポットヲ マーク シタ,마커 표시함,Vlek gemarkeerd,Miejsce zaznaczone,Posição marcada,,Loc marcat,Отметка,Означено место -Requires the GREEN keycard,PD_BLUEO,,,,Vyžaduje ZELENOU kartu,Benötigt die GRÜNE Schlüsselkarte,,Bezonas la VERDAN ŝlosilkarton,Requiere la tarjeta llave VERDE,,Tarvitsee VIHREÄN avainkortin,Carte VERTE demandée.,,Richiede la card d'accesso VERDE,グリーン キーカード ガ ヒツヨウダ,필요함: 초록색 키카드,Vereist de GROENE sleutelkaart,Wymaga ZIELONEJ karty,Você precisa do cartão de passe VERDE,,Necesită cardul VERDE,Требуется ЗЕЛЁНАЯ ключ-карта, -Requires the PURPLE keycard,PD_REDO,,,,Vyžaduje FIALOVOU kartu,Benötigt die VIOLETTE Schlüsselkarte,,Bezonas la PURPURAN ŝlosilkarton,Requiere la tarjeta llave VIOLETA,,Tarvitsee VIOLETIN avainkortin,Carte VIOLETTE demandée.,,Richiede la card d'accesso VIOLA,イエロー キーカード ガ ヒツヨウダ,필요함: 보라색 키카드,Vereist de PAARSE sleutelkaart,Wymaga FIOLETOWEJ karty,Você precisa do cartão de passe ROXO,,Necesită cardul MOV,Требуется ФИОЛЕТОВАЯ ключ-карта, -Requires the YELLOW keycard,PD_YELLOWO,,,,Vyžaduje ŽLUTOU kartu,Benötigt die GELBE Schlüsselkarte,,Bezonas la FLAVAN ŝlosilkarton,Requiere la tarjeta llave AMARILLA,,Tarvitsee KELTAISEN avainkortin,Carte JAUNE demandée.,,Richiede la card d'accesso GIALLA,パープル キーカード ガ ヒツヨウダ,필요함: 노란색 키카드,Vereist de GELE sleutelkaart,Wymaga ŻÓŁTEJ karty,Você precisa do cartão de passe AMARELO,,Necesită cardul GALBEN,Требуется ЖЁЛТАЯ ключ-карта, -Requires the GREEN key,PD_BLUEK,,,,Vyžaduje ZELENÝ klíč,Benötigt den GRÜNEN Schlüssel,,Bezonas la VERDAN ŝlosilon,Requiere la llave VERDE,,Tarvitsee VIHREÄN avaimen,Clé VERTE demandée.,,Richiede la chiave VERDE,グリーン キー ガ ヒツヨウダ,필요함: 초록색 열쇠,Vereist de GROENE sleutel,Wymaga ZIELONEGO klucza,Você precisa da chave VERDE,,Necesită cheia VERDE,Требуется ЗЕЛЁНЫЙ ключ, -Requires the YELLOW key,PD_YELLOWK,,,,Vyžaduje ŽLUTÝ klíč,Benötigt den GELBEN Schlüssel,,Bezonas la PURPURAN ŝlosilon,Requiere la llave AMARILLA,,Tarvitsee KELTAISEN avaimen,Clé JAUNE demandée.,,Richiede la chiave GIALLO,イエロー キー ガ ヒツヨウダ,필요함: 노란색 열쇠,Vereist de GEELE sleutel,Wymaga ŻÓŁTEGO klucza,Você precisa da chave AMARELA,,Necesită cheia GALBENĂ,Требуется ЖЁЛТЫЙ ключ, -Requires the PURPLE key,PD_REDK,,,,Vyžaduje FIALOVÝ klíč,Benötigt den VIOLETTEN Schlüssel,,Bezonas la FLAVAN ŝlosilon,Requiere la llave VIOLETA,,Tarvitsee VIOLETIN avaimen,Clé VIOLETTE demandée.,,Richiede la chiave VIOLA,パープル キー ガ ヒツヨウダ,필요함: 보라색 열쇠,Vereist de PAARSE sleutel,Wymaga FIOLETOWEGO klucza,Você precisa da chave ROXA,,Necesită cheia MOV,Требуется ФИОЛЕТОВЫЙ ключ, -Picked up armor.,GOTARMOR,,,Picked up armour.,Sebráno brnění.,Panzer genommen.,,Prenis kirason.,Recogiste la armadura.,,Panssari poimittu.,Armure récupérée.,Páncél felvéve.,Raccolto un'armatura.,アーマー ニュウシュ,획득: 전투복.,Je hebt een harnas opgehaald.,Podniesiono pancerz.,Pegou uma armadura.,,Ai ridicat Armura.,Получена броня.,Покупили сте панцир. -Picked up Combat Armor.,GOTMEGAARMOR,,,Picked up Combat Armour.,Sebráno bojové brnění.,Super-Panzer genommen.,,Prenis Batalkirason.,Recogiste la Armadura de Combate.,,Taistelupanssari poimittu.,Armure de combat récupérée.,,Raccolto Armatura da combattimento.,コンバット アーマー ニュウシュ,획득: 강화된 전투복.,Je hebt een gevechtsharnas opgehaald.,Podniesiono pancerz bojowy.,Pegou uma Armadura de Combate.,,Ai ridicat Armura de Luptă.,Получена боевая броня., -Superhealth,GOTMSPHERE,,,,Superzdraví,Super-Gesundheit,,Supersano,Supersalud,,Superterveys,Super-Santé,,Super salute,スーパー ヘルス,사용: 체력강화 버섯.,,Superzdrowie,Supersaúde,,Supersănătate,Суперздоровье, -Obtained the GREEN keycard.,GOTBLUECARD,,,,Sebrána ZELENÁ karta.,GRÜNE Schlüsselkarte erhalten,,Akiris la VERDAN ŝlosilkarton.,Obtenida la tarjeta llave VERDE.,,VIHREÄ avainkortti poimittu.,Carte VERTE obtenue.,,Ottenuta la card d'accesso VERDE.,グリーン キーカード ニュウシュ,획득: 초록색 키카드.,GROENE sleutelkaart ontvangen,Zdobyto ZIELONĄ kartę.,Pegou o cartão de passe VERDE.,,Ai achiziționat cardul VERDE.,Получена ЗЕЛЁНАЯ ключ-карта., -Obtained the YELLOW keycard.,GOTYELWCARD,,,,Sebrána ŽLUTÁ karta.,GELBE Schlüsselkarte erhalten,,Akiris la FLAVAN ŝlosilkarton.,Obtenida la tarjeta llave AMARILLA.,,KELTAINEN avainkortti poimittu.,Carte JAUNE obtenue.,,Ottenuta la card d'accesso GIALLA.,イエロー キーカード ニュウシュ,획득: 노란색 키카드.,GELE sleutelkaart ontvangen,Zdobyto ŻÓŁTĄ kartę.,Pegou o cartão de passe AMARELO.,,Ai achiziționat cardul GALBEN.,Получена ЖЁЛТАЯ ключ-карта., -Obtained the PURPLE keycard.,GOTREDCARD,,,,Sebrána FIALOVÁ karta.,VIOLETTE Schlüsselkarte erhalten,,Akiris la PURPURO ŝlosilkarton.,Obtenida la tarjeta llave VIOLETA.,,VIOLETTI avainkortti poimittu.,Carte VIOLETTE obtenue.,,Ottenuta la card d'accesso VIOLA.,パープル キーカード ニュウシュ,획득: 보라색 키카드.,PAARSE sleutelkaart ontvangen,Zdobyto FIOLETOWĄ kartę.,Pegou o cartão de passe ROXO.,,Ai achiziționat cardul MOV.,Получена ФИОЛЕТОВАЯ ключ-карта., -Obtained the GREEN key.,GOTBLUESKUL,,,,Sebrán ZELENÝ klíč.,GRÜNEN Schlüssel erhalten,,Akiris la VERDAN ŝlosilon.,Obtenida la llave VERDE.,,VIHREÄ avain poimittu.,Clé VERTE obtenue.,,Ottenuta la chiave VERDE.,グリーン キー ニュウシュ,획득: 초록색 열쇠.,GROENE sleutel ontvangen,Zdobyto ZIELONY klucz.,Pegou a chave VERDE.,,Ai achiziționat cheia VERDE.,Получен ЗЕЛЁНЫЙ ключ., -Obtained the YELLOW key.,GOTYELWSKUL,,,,Sebrán ŽLUTÝ klíč.,GELBEN Schlüssel erhalten,,Akiris la FLAVAN ŝlosilon.,Obtenida la llave AMARILLA.,,KELTAINEN avain poimittu.,Clé JAUNE obtenue.,,Ottenuta la chiave GIALLA.,イエロー キー ニュウシュ,획득: 노란색 열쇠.,GELE sleutel ontvangen,Zdobyto ŻÓŁTY klucz.,Pegou a chave AMARELA.,,Ai achiziționat cheia GALBENĂ.,Получен ЖЁЛТЫЙ ключ., -Obtained the PURPLE key.,GOTREDSKUL,,,,Sebrán FIALOVÝ klíč.,VIOLETTEN Schlüssel erhalten,,Akiris la PURPURO ŝlosilon.,Obtenida la llave VIOLETA.,,VIOLETTI avain poimittu.,Clé VIOLETTE obtenue.,,Ottenuta la chiave VIOLA.,パープル キー ニュウシュ,획득: 보라색 열쇠.,PAARSE sleutel ontvangen,Zdobyto FIOLETOWY klucz.,Pegou a chave ROXA.,,Ai achiziționat cheia MOV.,Получен ФИОЛЕТОВЫЙ ключ., -Healing mushroom,GOTSTIM,,,,Léčivka,Heilpilz,,Saniga fungo,Seta medicinal,,Lääkesieni,Champignon médicinal,,Funghi curativi,ヒーリング マッシュルーム,사용: 체력회복 버섯.,Genezende paddenstoel,Leczący grzyb,Cogumelo medicinal,,Ciupercă vindecătoare,Целебный гриб, -Acquired: medical kit.,GOTMEDIKIT,,,,Získána lékárnička.,Erhalten: Medikit,,Akiris: medicinan kompleton.,Adquirido: kit medicinal.,,Saatu: lääkintälaukku.,Acquis: Kit médical.,,Acquisito: kit medico.,シュトク: メディカルキット,사용: 의료 키트.,Verworven: medische kit.,Zdobyto: apteczkę.,Pegou um kit médico.,,Ridicat: Kit de Prim-Ajutor.,Получена: Аптечка., -Acquired: medical kit that you REALLY need.,GOTMEDINEED,,,,"Získána lékárnička, kterou OPRAVDU potřebuješ.","Erhalten: Medikit, das du WIRKLICH brauchst",,"Akiris: medicinan kompleton, kion vi TRE bezonas.",Adquirido: kit medicinal que REALMENTE necesitabas.,,"Saatu: lääkintälaukku, jota TODELLA tarvitsit.",Acquis: Kit médical. Besoin critique.,,Acquisito: kit medico di cui VERAMENTE avete bisogno.,シュトク: キンキュウジタイヲ スクウ メディカルキット,사용: 당신을 살려줄 의료 키트.,Verworven: medische kit die je ECHT nodig heeft.,"Zdobyto: apteczkę, której NAPRAWDĘ potrzebujesz.",Pegou um kit médico que você REALMENTE precisa.,,Ridicat: Kit de Prim-Ajutor de care CHIAR AI nevoie.,Получена: Аптечка (КРАЙНЕ необходимая)., -Map,GOTMAP,,,,Mapa,Karte,,Mapon,Mapa,,Kartta,Carte,Térkép,Mappa,コノ クイキノ マップダ ,획득: 지도.,Kaart,Mapa,Mapa,,Hartă,Карта, -Acquired: case of bullets.,GOTCLIPBOX,,,,Získána krabice nábojů.,Erhalten: Munitionskiste,,Akiris: Kuglujon.,Adquirido: Caja de balas.,Pegou uma caixa de balas.,Saatu: luotilaatikko.,Acquis: Boîte de balles.,,Acquisito: caso di proiettili.,シュトク: バレット ケース,획득: 회전포 탄약.,Verworven: geval van kogels.,Zdobyto: pudełko naboi.,Pegou uma caixa de balas,,Achiziționat: Cutie de gloanțe.,Получен: Ящик с пулями., -Acquired: Grenade.,GOTROCKET,,,,Ziskán granát.,Erhalten: Granate,,Akiris: Grenadon.,Adquirido: Granada.,,Saatu: kranaatti.,Acquis: Grenade.,,Acquisito: Granata.,シュトク: グレネード,획득: 세열탄.,Verworven: Granaat.,Zdobyto: Granat.,Pegou uma granada.,,Achiziționat: Grenadă.,Получена: Граната., -Acquired: Grenades.,GOTROCKBOX,,,,Ziskány granáty.,Erhalten: Granaten,,Akiris: Grenadojn.,Adquirido: Granadas.,,Saatu: kranaatteja.,Acquis: Grenades.,,Acquisito: Granate.,シュトク: グレネード セット,획득: 세열탄 여러 개.,Verworven: Granaten.,Zdobyto: Granaty.,Pegou granadas.,,Achiziționat: Grenade.,Получены: Гранаты., -Acquired: box of shotgun shells.,GOTSHELLBOX,,,,Získána krabice broků.,Erhalten: Schrotpatronen,,Akiris: Skatolon da kartoĉoj.,Adquirido: Caja de cartuchos de escopeta.,,Saatu: laatikollinen haulikon patruunoita.,Acquis: Boîte de cartouches.,,Acquisito: scatola di cartucce per fucile.,シュトク: シェル ボックス,획득: 산탄총 탄약.,Verworven: doos met shotgun schelpen.,Zdobyto: pudełko loftek do strzelby.,Pegou uma caixa de cartuchos de espingarda.,,Achiziționat: Cutie de muniție pentru pușcă.,Получена: Коробка патронов для дробовика., -Acquired: ammo backpack.,GOTBACKPACK,,,,Ziskán batoh s municí.,Erhalten: Munitionsrucksack,,Akiris: Tornistron da municioj.,Adquirido: Mochila de municiones.,,Saatu: ammusreppu.,Acquis: Sac de munitions.,,Acquisito: zaino munizioni.,シュトク: バックパック,획득: 탄약 가방.,Verworven: munitie rugzak.,Zdobyto: plecak z amunicją.,Pegou uma mochila de munição.,,Achiziționat: Raniță.,Получен: Ранец для боеприпасов., -Acquired: Grenade.,GOTBFG9000,,,,Získán granát.,Erhalten: Granate,,Akiris: Grenadon.,Adquirido: Granada.,,Saatu: kranaatti.,Acquis: Grenade.,,Acquisito: Granata.,シュトク: グレネード,획득: 세열탄.,Verworven: Granaat.,Zdobyto: Granat.,Pegou uma granada.,,Achiziționat: Grenadă.,Получена: Граната., -Acquired: Minigun.,GOTCHAINGUN,,,,Získán kulomet.,Erhalten: Minigun,,Akiris: Maŝinpafilon.,Adquirido: Miniarma.,,Saatu: minigun.,Acquis: Minigun.,,Acquisito: Minigun.,シュトク: ミニガン,획득: 회전포.,Verworven: Minigun.,Zdobyto: Minigun.,Pegou uma metralhadora giratória.,,Achiziționat: Minimitralieră.,Получен: Миниган., -Acquired: Grenade launcher.,GOTLAUNCHER,,,,Získán granátomet.,Erhalten: Granatwerfer,,Akiris: Grenadlanĉilon.,Adquirido: Lanzagranadas.,,Saatu: kranaatinheitin.,Acquis: Lance-Grenades,,Acquisito: Lanciagranate.,シュトク: グレネードランチャー,획득: 세열탄 추진기.,Verworven: Granaatwerper.,Zdobyto: Wyrzutnię granatów.,Pegou um lança-granadas.,,Achiziționat: Lansator de grenade.,Получен: Гранатомёт., -Entropy thrower!,GOTPLASMA,,,,Vrhač entropie!,Entropiewerfer,,Entropi-ĵetilon!,¡Lanzador de Entropía!,,Entropianheitin!,Acquis: Lanceur d'Entropie!,,Lancia entropia!,エントロピースロワー!,획득: 엔트로피 방사기!,Entropiewerper!,Miotacz Entropii!,Lançador de entropia!,,Aruncător entropic!,Энтропиемёт!, -Acquired: Shotgun.,GOTSHOTGUN,,,,Získána brokovnice.,Erhalten: Schrotflinte,,Akiris: Ĉaspafilon.,Adquirido: Escopeta.,,Saatu: haulikko.,Acquis: Fusil à pompe.,,Acquisito: Fucile.,シュトク: ショットガン,획득: 산탄총.,Verworven: Shotgun.,Zdobyto: Strzelbę.,Pegou uma espingarda.,,Achiziționat: Pușcă.,Получен: Дробовик., -God Mode ON,STSTR_DQDON,,,,Nesmrtelnost ZAP,Gott-Modus AN,,Dio-Reĝimo AKTIVA,Modo Dios ACTIVADO,,Kuolemattomuustila PÄÄLLÄ,Mode invulnérable ON,,Modo Dio ATTIVADA,ゴッドモード オン,무적 치트: ON,God Modus AAN,Tryb Boga WŁĄCZONY,Modo Deus LIGADO,,Modul Invincibil PORNIT,Режим Бога вкл., -God Mode OFF,STSTR_DQDOFF,,,,Nesmrtelnost VYP,Gott-Modus AUS,,Dio-Reĝimo MALAKTIVA,Modo Dios DESACTIVADO,,Kuolemattomuustila POIS PÄÄLTÄ,Mode invulnérable OFF,,Modo Dio DISATTIVADA,ゴッドモード オフ,무적 치트: OFF,God Modus UIT,Tryb Boga WYŁĄCZONY,Modo Deus DESLIGADO,,Modul Invincibil OPRIT,Режим Бога откл., -All weapons/ ammo/ keys,STSTR_KFAADDED,,,,Všechny zbraně/munice/klíče,"Alle Waffen, Munition und Schlüssel",,Ĉiuj armiloj/municioj/ŝlosiloj,Todas las armas/municiones/llaves,,Kaikki aseet/ ammukset/ avaimet,Toutes les armes/munitions/clés,,Tutte le armi / munizioni / chiavi,スベテノ ブキ/カギ/ダンヤク,추가: 모든 무기/탄약/열쇠 치트,Alle wapens / munitie / sleutels,Wszystkie bronie/amunicja/klucze,Todas as armas/munição/chaves,,Toate armele/muniție/chei,Всё оружие/боеприпасы/ключи, -All weapons and ammo,STSTR_FAADDED,,,,Všechny zbraně a munice,Alle Waffen und Munition,,Ĉiuj armiloj kaj municioj,Todas las armas y municiones,,Kaikki aseet ja ammukset,Toutes les armes et munitions,,Tutte le armi e le munizioni,スベテノ ブキ/ダンヤク,추가: 모든 무기/탄약 치트,Alle wapens en munitie,Wszystkie bronie i amunicja,Todas as armas e munição completa,,Toate armele și muniție,Всё оружие и боеприпасы, -Abduction,TXT_HARMMAP01,,,,Únos,Entführung,,Forkapto,Abducción,,Sieppaus,Enlèvement,,Il rapimento,アブダクション,유괴,Ontvoering,Porwanie,Abdução,,Răpire,Похищение, -Harm's Way,TXT_HARMMAP02,,,,Nebezpečí,In Gefahr,,Vojo de Danĝero,En Peligro,,Vaara,Mise en Danger,,La via del danno,ハーム'ズ ウェイ,해함의 길,,Niebezpieczeństwo,No Caminho do Perigo,,Calea pericolului,Опасный путь, -Owt Mood,TXT_HARMMAP03,,,,Špatný pocit,Missstimmung,,Sentaĉo,Buen humor,,Nollatunnelma,Scontento,,Scontento,ヤバイムード,이상한 분위기,,Paskudny Nastrój,Atrito,,Fricțiune,Нестроение, -Megalapolis,TXT_HARMMAP04,,,,Megalopole,Megalopolis,,Megtropolo,Megalópolis,,Megalopoli,Mégalopole,,Megalapoli,メガラポリス,거대 도시,Megalopolis,Megalapolis,Megalópole,,Megalopolis,Мегалаполис, -The Hospital,TXT_HARMMAP05,,,,Nemocnice,Das Hospital,,La Malsanulejo,El Hospital,,Sairaala,L'Hôpital,Kórház,L'ospedale,ホスピタル,병동,Het ziekenhuis,Szpital,O Hospital,,Spitalul,Больница, -The Weapons Factory,TXT_HARMMAP06,,,,Továrna na zbraně,Die Waffenfabrik,,La Arm-fabrikejo,La Fábrica de Armas,,Asetehdas,L'Usine d'Armes,Fegyvergyár,La fabbrica di armi,ウェポンファクトリー,무기 공장,De Wapenfabriek,Fabryka Broni,A Fábrica de Armamento,,Fabrica de Arme,Оружейный завод, -The Underwater Lab,TXT_HARMMAP07,,,,Podvodní laboratoř,Das Unterwasserlabor,,La Subakva Labotorio,El Laboratorio Submarino,,Vedenalainen laboratorio,Le Laboratoire Sous-marin,Vízalatti labor,Il laboratorio subacqueo,アンダーウォーターラボ,해저 연구소,Het onderwaterlaboratorium,Podwodne Laboratorium,O Laboratório Submarino,,Laboratorul Subacvatic,Подводная лаборатория, -Airstrip One,TXT_HARMMAP08,,,,Přistávací dráha jedna,Flugplatz Eins,,Surteriĝejo Numero Unu,Pista de Aterrizaje Uno,,Kiitorata Yksi,Piste D'Atterrisage Un,,Pista di atterraggio Uno,エアーシップ ワン,활주로 1호,Vliegveld Een,Lądowisko Numer Jeden,Base Aérea Um,,Pista Unu,Взлётная полоса №1, -The Launch Base,TXT_HARMMAP09,,,,Vzletová základna,Die Startbasis,,La Lanĉbazo,La Base de Despegue,,Laukaisutukikohta,La Base de Lancement,,La base di lancio,ランチャーベース,발진기지,De lanceerbasis,Baza Startowa,A Base de Lançamento,,Baza de Lansare,Пусковая площадка, -The Radioactive Zone,TXT_HARMMAP10,,,,Radioaktivní zóna,Die radioaktive Zone,,La Radioaktiva Zono,La Zona Radioactiva,,Radioaktiivinen vyöhyke,La Zone Radioactive,,La zona radioattiva,ラディオアクティブ ゾーン,방사능 처리소,De Radioactieve Zone,Radioaktywna Strefa,A Zona Radioativa,,Zona Radioactivă,Заражённая зона, -Echidna,TXT_HARMMAP11,,,,,,,Ekidno,,,Nokkasiili,,Ekhidna,,エキドナ,에키드나,,,Equidna,,,Ехидна, +Druk op 'Y' of 'N'...",Tror du virkelig at du kan håndtere det? Trykk 'Y' eller 'N'...,"Czy ty naprawdę myślisz, że temu podołasz? + +Wciśnij 'Y' lub 'N'...",Você acha que dá conta?\n\nAperte Y ou N...,,Chiar crezi că poți face față?\n\napasă 'Y' sau 'N'...,"Уверены, что справитесь?\n\nНажмите «Y» или «N»...",,"Tror du verkligen att du klarar av det? +Tryck på ""Y"" eller ""N""...",Gerçekten bununla başa çıkabileceğini düşünüyor musun? 'Y' veya 'N' tuşuna basın... +Spot marked,AMSTR_MARKEDSPOT,,,,Bod označen,Pletmærket,Punkt markiert,,Punkto markita,Punto marcado,,Paikka merkitty,Repère marqué.,Hely megjelölve.,Posizione segnata,スポットヲ マーク シタ,마커 표시함,Vlek gemarkeerd,Punkt markert,Miejsce zaznaczone,Posição marcada,,Loc marcat,Отметка,Означено место,Markerad punkt,İşaretli nokta +Requires the GREEN keycard,PD_BLUEO,,,,Vyžaduje ZELENOU kartu,Kræver det GRØNNE nøglekort,Benötigt die GRÜNE Schlüsselkarte,,Vi bezonas la VERDAN ŝlosilkarton,Requiere la tarjeta llave VERDE,,Tarvitsee VIHREÄN avainkortin,Carte VERTE demandée.,ZÖLD kulcskártya szükséges,Richiede la card d'accesso VERDE,グリーン キーカード ガ ヒツヨウダ,필요함: 초록색 키카드,Vereist de GROENE sleutelkaart,Krever det GRØNNE nøkkelkortet,Wymaga ZIELONEJ karty,Você precisa do cartão de passe VERDE,,Necesită cardul VERDE,Требуется ЗЕЛЁНАЯ ключ-карта,,Kräver det GRÖNA nyckelkortet.,YEŞİL anahtar kartı gerektirir +Requires the PURPLE keycard,PD_REDO,,,,Vyžaduje FIALOVOU kartu,Kræver det LILLA nøglekort,Benötigt die VIOLETTE Schlüsselkarte,,Vi bezonas la PURPURAN ŝlosilkarton,Requiere la tarjeta llave VIOLETA,,Tarvitsee VIOLETIN avainkortin,Carte VIOLETTE demandée.,LILA kulcskártya szükséges,Richiede la card d'accesso VIOLA,イエロー キーカード ガ ヒツヨウダ,필요함: 보라색 키카드,Vereist de PAARSE sleutelkaart,Krever det LILLA nøkkelkortet,Wymaga FIOLETOWEJ karty,Você precisa do cartão de passe ROXO,,Necesită cardul MOV,Требуется ФИОЛЕТОВАЯ ключ-карта,,Kräver det LILA nyckelkortet,MOR anahtar kartı gerektirir +Requires the YELLOW keycard,PD_YELLOWO,,,,Vyžaduje ŽLUTOU kartu,Kræver det GULLE nøglekort,Benötigt die GELBE Schlüsselkarte,,Vi bezonas la FLAVAN ŝlosilkarton,Requiere la tarjeta llave AMARILLA,,Tarvitsee KELTAISEN avainkortin,Carte JAUNE demandée.,SÁRGA kulcskártya szükséges,Richiede la card d'accesso GIALLA,パープル キーカード ガ ヒツヨウダ,필요함: 노란색 키카드,Vereist de GELE sleutelkaart,Krever det GULT nøkkelkortet,Wymaga ŻÓŁTEJ karty,Você precisa do cartão de passe AMARELO,,Necesită cardul GALBEN,Требуется ЖЁЛТАЯ ключ-карта,,Kräver det GULLA nyckelkortet,SARI anahtar kartı gerektirir +Requires the GREEN key,PD_BLUEK,,,,Vyžaduje ZELENÝ klíč,Kræver den GRØNNE nøgle,Benötigt den GRÜNEN Schlüssel,,Vi bezonas la VERDAN ŝlosilon,Requiere la llave VERDE,,Tarvitsee VIHREÄN avaimen,Clé VERTE demandée.,ZÖLD kulcs szükséges,Richiede la chiave VERDE,グリーン キー ガ ヒツヨウダ,필요함: 초록색 열쇠,Vereist de GROENE sleutel,Krever den GRØNNE nøkkelen,Wymaga ZIELONEGO klucza,Você precisa da chave VERDE,,Necesită cheia VERDE,Требуется ЗЕЛЁНЫЙ ключ,,Kräver det GRÖNA nyckeln,YEŞİL tuş gerektirir +Requires the YELLOW key,PD_YELLOWK,,,,Vyžaduje ŽLUTÝ klíč,Kræver den GULLE nøgle,Benötigt den GELBEN Schlüssel,,Vi bezonas la PURPURAN ŝlosilon,Requiere la llave AMARILLA,,Tarvitsee KELTAISEN avaimen,Clé JAUNE demandée.,SÁRGA kulcs szükséges,Richiede la chiave GIALLO,イエロー キー ガ ヒツヨウダ,필요함: 노란색 열쇠,Vereist de GEELE sleutel,Krever den GUL nøkkelen,Wymaga ŻÓŁTEGO klucza,Você precisa da chave AMARELA,,Necesită cheia GALBENĂ,Требуется ЖЁЛТЫЙ ключ,,Kräver den GULLA nyckeln,SARI tuş gerektirir +Requires the PURPLE key,PD_REDK,,,,Vyžaduje FIALOVÝ klíč,Kræver den LILLA nøgle,Benötigt den VIOLETTEN Schlüssel,,Vi bezonas la FLAVAN ŝlosilon,Requiere la llave VIOLETA,,Tarvitsee VIOLETIN avaimen,Clé VIOLETTE demandée.,LILA kulcs szükséges,Richiede la chiave VIOLA,パープル キー ガ ヒツヨウダ,필요함: 보라색 열쇠,Vereist de PAARSE sleutel,Krever den LILLA nøkkelen,Wymaga FIOLETOWEGO klucza,Você precisa da chave ROXA,,Necesită cheia MOV,Требуется ФИОЛЕТОВЫЙ ключ,,Kräver den LILA nyckeln,MOR tuş gerektirir +Picked up armor.,GOTARMOR,,,Picked up armour.,Sebráno brnění.,Hentede rustning.,Panzer genommen.,,Vi trovis armaĵon.,Encuentras una armadura.,,Panssari poimittu.,Armure récupérée.,Vért felvéve,Raccolto un'armatura.,アーマー ニュウシュ,획득: 전투복.,Je hebt een harnas opgehaald.,Plukket opp rustning.,Zebrano pancerz.,Pegou uma armadura.,,Ai ridicat Armura.,Получена броня.,Покупили сте панцир.,Plockade upp en rustning.,Zırhı aldım. +Picked up Combat Armor.,GOTMEGA,,,Picked up Combat Armour.,Sebráno bojové brnění.,Samlet Combat Armor op.,Super-Panzer genommen.,,Vi trovis batal-armaĵon.,Encuentras una armadura de combate.,,Taistelupanssari poimittu.,Armure de combat récupérée.,Harci vért felvéve,Raccolto Armatura da combattimento.,コンバット アーマー ニュウシュ,획득: 강화된 전투복.,Je hebt een gevechtsharnas opgehaald.,Plukket opp kamprustning.,Zebrano pancerz bojowy.,Pegou uma Armadura de Combate.,,Ai ridicat Armura de Luptă.,Получена боевая броня.,,Plockade upp kampen rustning.,Savaş Zırhı aldı. +Superhealth,GOTMSPHERE,,,,Superzdraví,,Super-Gesundheit,,Supersano,Supersalud,,Superterveys,Super-Santé,Szuperéleterő,Super salute,スーパー ヘルス,사용: 체력강화 버섯.,,Superhelse,Superzdrowie,Superssaúde,,Supersănătate,Суперздоровье,,Supersundhet,Süper Sağlık +Obtained the GREEN keycard.,GOTBLUECARD,,,,Sebrána ZELENÁ karta.,Opnået det GRØNNE nøglekort.,GRÜNE Schlüsselkarte erhalten,,Vi trovis la VERDAN ŝlosilkarton.,Encuentras la tarjeta llave VERDE.,,VIHREÄ avainkortti poimittu.,Carte VERTE obtenue.,Megszerezted a ZÖLD kulcskártyát.,Ottenuta la card d'accesso VERDE.,グリーン キーカード ニュウシュ,획득: 초록색 키카드.,GROENE sleutelkaart ontvangen,Fått det GRØNNE nøkkelkortet.,Zdobyto ZIELONĄ kartę.,Pegou o cartão de passe VERDE.,,Ai achiziționat cardul VERDE.,Получена ЗЕЛЁНАЯ ключ-карта.,,Skaffade det GRÖNA nyckelkortet.,YEŞİL anahtar kartı elde edildi. +Obtained the YELLOW keycard.,GOTYELWCARD,,,,Sebrána ŽLUTÁ karta.,Opnået det GULLE nøglekort.,GELBE Schlüsselkarte erhalten,,Vi trovis la FLAVAN ŝlosilkarton.,Encuentras la tarjeta llave AMARILLA.,,KELTAINEN avainkortti poimittu.,Carte JAUNE obtenue.,Megszerezted a SÁRGA kulcskártyát.,Ottenuta la card d'accesso GIALLA.,イエロー キーカード ニュウシュ,획득: 노란색 키카드.,GELE sleutelkaart ontvangen,Fått det GUL nøkkelkortet.,Zdobyto ŻÓŁTĄ kartę.,Pegou o cartão de passe AMARELO.,,Ai achiziționat cardul GALBEN.,Получена ЖЁЛТАЯ ключ-карта.,,Skaffade det GULLA nyckelkortet.,SARI anahtar kartı elde edildi. +Obtained the PURPLE keycard.,GOTREDCARD,,,,Sebrána FIALOVÁ karta.,Opnået det LILLA nøglekort.,VIOLETTE Schlüsselkarte erhalten,,Vi trovis la PURPURAN ŝlosilkarton.,Encuentras la tarjeta llave VIOLETA.,,VIOLETTI avainkortti poimittu.,Carte VIOLETTE obtenue.,Megszerezted a LILA kulcskártyát.,Ottenuta la card d'accesso VIOLA.,パープル キーカード ニュウシュ,획득: 보라색 키카드.,PAARSE sleutelkaart ontvangen,Fikk det LILLA nøkkelkortet.,Zdobyto FIOLETOWĄ kartę.,Pegou o cartão de passe ROXO.,,Ai achiziționat cardul MOV.,Получена ФИОЛЕТОВАЯ ключ-карта.,,Skaffade det LILA nyckelkortet.,MOR anahtar kartı elde edildi. +Obtained the GREEN key.,GOTBLUESKUL,,,,Sebrán ZELENÝ klíč.,Opnået den GRØNNE nøgle.,GRÜNEN Schlüssel erhalten,,Vi trovis la VERDAN ŝlosilon.,Encuentras la llave VERDE.,,VIHREÄ avain poimittu.,Clé VERTE obtenue.,Megszerezted a ZÖLD kulcsot.,Ottenuta la chiave VERDE.,グリーン キー ニュウシュ,획득: 초록색 열쇠.,GROENE sleutel ontvangen,Fikk den GRØNNE nøkkelen.,Zdobyto ZIELONY klucz.,Pegou a chave VERDE.,,Ai achiziționat cheia VERDE.,Получен ЗЕЛЁНЫЙ ключ.,,Skaffade den GRÖNA nyckeln.,YEŞİL anahtar elde edildi. +Obtained the YELLOW key.,GOTYELWSKUL,,,,Sebrán ŽLUTÝ klíč.,Opnået den GULLE nøgle.,GELBEN Schlüssel erhalten,,Vi trovis la FLAVAN ŝlosilon.,Encuentras la llave AMARILLA.,,KELTAINEN avain poimittu.,Clé JAUNE obtenue.,Megszerezted a SÁRGA kulcsot.,Ottenuta la chiave GIALLA.,イエロー キー ニュウシュ,획득: 노란색 열쇠.,GELE sleutel ontvangen,Fikk den GULA nøkkelen.,Zdobyto ŻÓŁTY klucz.,Pegou a chave AMARELA.,,Ai achiziționat cheia GALBENĂ.,Получен ЖЁЛТЫЙ ключ.,,Skaffade den GULLA nyckeln.,SARI anahtar elde edildi. +Obtained the PURPLE key.,GOTREDSKUL,,,,Sebrán FIALOVÝ klíč.,Opnået den LILLA nøgle.,VIOLETTEN Schlüssel erhalten,,Vi trovis la PURPURAN ŝlosilon.,Encuentras la llave VIOLETA.,,VIOLETTI avain poimittu.,Clé VIOLETTE obtenue.,Megszerezted a LILA kulcsot.,Ottenuta la chiave VIOLA.,パープル キー ニュウシュ,획득: 보라색 열쇠.,PAARSE sleutel ontvangen,Fikk den LILLA nøkkelen.,Zdobyto FIOLETOWY klucz.,Pegou a chave ROXA.,,Ai achiziționat cheia MOV.,Получен ФИОЛЕТОВЫЙ ключ.,,Skaffade den LILA nyckeln.,MOR anahtar elde edildi. +Healing mushroom,GOTSTIM,,,,Léčivka,Helbredende svamp,Heilpilz,,Saniga fungo,Seta medicinal,Hongo medicinal,Lääkesieni,Champignon médicinal,Gyógyító gomba,Funghi curativi,ヒーリング マッシュルーム,사용: 체력회복 버섯.,Genezende paddenstoel,Helbredende sopp,Leczący grzyb,Cogumelo medicinal,,Ciupercă vindecătoare,Целебный гриб,,Helande svamp,İyileştirici mantar +Acquired: medical kit.,GOTMEDIKIT,,,,Získána lékárnička.,Erhvervet: medicinsk kit.,Erhalten: Medikit,,Vi trovis sukurkeston.,Encuentras un botiquín.,,Saatu: lääkintälaukku.,Acquis: Kit médical.,Megszerezve: orvosi csomag,Acquisito: kit medico.,シュトク: メディカルキット,사용: 의료 키트.,Verworven: medische kit.,Ervervet: medisinsk sett.,Zdobyto: apteczkę.,Pegou um kit médico.,,Ridicat: Kit de Prim-Ajutor.,Получена: Аптечка.,,Förvärvad: medicinsk utrustning.,Elde edilen: tıbbi kit. +Acquired: medical kit that you REALLY need.,GOTMEDINEED,,,,"Získána lékárnička, kterou OPRAVDU potřebuješ.","Erhvervet: medicinsk kit, som du VIRKELIG har brug for.","Erhalten: Medikit, das du WIRKLICH brauchst",,"Vi trovis sukurkeston, kiun vi VERE bezonas.",Encuentras un botiquín que REALMENTE necesitabas.,,"Saatu: lääkintälaukku, jota TODELLA tarvitsit.",Acquis: Kit médical. Besoin critique.,Megszerezve: már NAGYON hiányzott orvosi csomag,Acquisito: kit medico di cui VERAMENTE avete bisogno.,シュトク: キンキュウジタイヲ スクウ メディカルキット,사용: 당신을 살려줄 의료 키트.,Verworven: medische kit die je ECHT nodig heeft.,Ervervet: medisinsk sett som du virkelig trenger.,"Zdobyto: apteczkę, której NAPRAWDĘ potrzebujesz.",Pegou um kit médico que você REALMENTE precisa.,,Ridicat: Kit de Prim-Ajutor de care CHIAR AI nevoie.,Получена: Аптечка (КРАЙНЕ необходимая).,,Förvärvad: medicinsk utrustning som du verkligen behöver.,Elde edilen: GERÇEKTEN ihtiyacınız olan tıbbi kit. +Map,GOTMAP,,,,Mapa,Kort,Karte,,Vi trovis la mapon,Mapa,,Kartta,Carte,Térkép,Mappa,コノ クイキノ マップダ ,획득: 지도.,Kaart,Kart,Mapa,Mapa,,Hartă,Карта,,Karta,Harita +Acquired: case of bullets.,GOTCLIPBOX,,,,Získána krabice nábojů.,Erhvervet: kasse med kugler.,Erhalten: Munitionskiste,,Vi trovis skatolon da kugloj.,Encuentras una caja de balas.,,Saatu: luotilaatikko.,Acquis: Boîte de balles.,Megszerezve: doboznyi lőszer.,Acquisito: caso di proiettili.,シュトク: バレット ケース,획득: 회전포 탄약.,Verworven: geval van kogels.,Ervervet: tilfelle av kuler.,Zdobyto: pudełko naboi.,Pegou uma caixa de balas,,Achiziționat: Cutie de gloanțe.,Получен: Ящик с пулями.,,Förvärvad: väska med kulor.,Elde edilen: mermi kovanı. +Acquired: Grenade.,GOTROCKET,,,,Ziskán granát.,Erhvervet: Granat.,Erhalten: Granate,,Vi trovis grenadon.,Encuentras una granada.,,Saatu: kranaatti.,Acquis: Grenade.,Megszerezve: Gránát.,Acquisito: Granata.,シュトク: グレネード,획득: 세열탄.,Verworven: Granaat.,Ervervet: Granat.,Zdobyto: Granat.,Pegou uma granada.,,Achiziționat: Grenadă.,Получена: Граната.,,Förvärvad: Granat.,Elde edildi: El bombası. +Acquired: Grenades.,GOTROCKBOX,,,,Ziskány granáty.,Erhvervet: Granater.,Erhalten: Granaten,,Vi trovis grenadojn.,Encuentras unas granadas.,,Saatu: kranaatteja.,Acquis: Grenades.,Megszerezve: Gránátok.,Acquisito: Granate.,シュトク: グレネード セット,획득: 세열탄 여러 개.,Verworven: Granaten.,Ervervet: Granater.,Zdobyto: Granaty.,Pegou granadas.,,Achiziționat: Grenade.,Получены: Гранаты.,,Förvärvad: Granater.,Elde edildi: El bombaları. +Acquired: box of shotgun shells.,GOTSHELLBOX,,,,Získána krabice broků.,Erhvervet: kasse med haglpatroner.,Erhalten: Schrotpatronen,,Vi trovis skatolon da kartoĉoj.,Encuentras una caja de cartuchos de escopeta.,,Saatu: laatikollinen haulikon patruunoita.,Acquis: Boîte de cartouches.,Megszerezve: doboznyi puska sörét,Acquisito: scatola di cartucce per fucile.,シュトク: シェル ボックス,획득: 산탄총 탄약.,Verworven: doos met shotgun schelpen.,Ervervet: eske med haglepatroner.,Zdobyto: pudełko loftek do strzelby.,Pegou uma caixa de cartuchos de espingarda.,,Achiziționat: Cutie de muniție pentru pușcă.,Получена: Коробка патронов дробовика.,,Förvärvad: låda med hagelpatroner.,Edinildi: Bir kutu av tüfeği fişeği. +Acquired: ammo backpack.,GOTBACKPACK,,,,Ziskán batoh s municí.,Erhvervet: ammunitionsrygsæk.,Erhalten: Munitionsrucksack,,Vi trovis tornistron da municioj.,Encuentras una mochila de municiones.,,Saatu: ammusreppu.,Acquis: Sac de munitions.,Megszerezve: lőszeres hátizsák,Acquisito: zaino munizioni.,シュトク: バックパック,획득: 탄약 가방.,Verworven: munitie rugzak.,Ervervet: ryggsekk med ammunisjon.,Zdobyto: plecak z amunicją.,Pegou uma mochila de munição.,,Achiziționat: Raniță.,Получен: Ранец боеприпасов.,,Förvärvad: Ammunitionsryggsäck.,Edinildi: Cephane çantası. +Acquired: Grenade.,GOTBFG9000,,,,Získán granát.,Erhvervet: Granat.,Erhalten: Granate,,Vi trovis grenadon.,Encuentras una granada.,,Saatu: kranaatti.,Acquis: Grenade.,Megszerezve: Gránát.,Acquisito: Granata.,シュトク: グレネード,획득: 세열탄.,Verworven: Granaat.,Ervervet: Granat.,Zdobyto: Granat.,Pegou uma granada.,,Achiziționat: Grenadă.,Получена: Граната.,,Förvärvad: Granat.,Elde edildi: El bombası. +Acquired: Minigun.,GOTCHAINGUN,,,,Získán kulomet.,Erhvervet: Minigun.,Erhalten: Minigun,,Vi trovis maŝinpafilon.,Encuentras una ametralladora.,,Saatu: minigun.,Acquis: Minigun.,Megszerezve: Gépfegyver.,Acquisito: Minigun.,シュトク: ミニガン,획득: 회전포.,Verworven: Minigun.,Ervervet: Minigun.,Zdobyto: Minigun.,Pegou uma metralhadora giratória.,,Achiziționat: Minimitralieră.,Получен: Пулемёт.,,Förvärvad: Minigun.,Elde edildi: Minigun. +Acquired: Grenade launcher.,GOTLAUNCHER,,,,Získán granátomet.,Erhvervet: Granatkaster.,Erhalten: Granatwerfer,,Vi trovis grenadĵetilon.,Encuentras un lanzagranadas.,,Saatu: kranaatinheitin.,Acquis: Lance-Grenades,Megszerezve: Gránátvető,Acquisito: Lanciagranate.,シュトク: グレネードランチャー,획득: 세열탄 추진기.,Verworven: Granaatwerper.,Ervervet: Granatkaster.,Zdobyto: Wyrzutnię granatów.,Pegou um lança-granadas.,,Achiziționat: Lansator de grenade.,Получен: Гранатомёт.,,Förvärvad: Granatkastare.,Elde edildi: El bombası fırlatıcı. +Entropy thrower!,GOTPLASMA,,,,Vrhač entropie!,Entropi-lancer!,Entropiewerfer,,Entropi-ĵetilon!,¡Lanzador de entropía!,,Entropianheitin!,Acquis: Lanceur d'Entropie!,Entrópiavető!,Lancia entropia!,エントロピースロワー!,획득: 엔트로피 방사기!,Entropiewerper!,Entropikaster!,Miotacz Entropii!,Lançador de entropia!,,Aruncător entropic!,Энтропиемёт!,,,Entropi fırlatıcı! +Acquired: Shotgun.,GOTSHOTGUN,,,,Získána brokovnice.,Erhvervet: Shotgun.,Erhalten: Schrotflinte,,Vi trovis kartoĉan fusilon.,Encuentras una escopeta.,,Saatu: haulikko.,Acquis: Fusil à pompe.,Megszerezve: Sörétes puska,Acquisito: Fucile.,シュトク: ショットガン,획득: 산탄총.,Verworven: Shotgun.,Ervervet: Haglgevær.,Zdobyto: Strzelbę.,Pegou uma espingarda.,,Achiziționat: Pușcă.,Получен: Дробовик.,,Förvärvad: Hagelgevär,Edinildi: Av tüfeği. +God Mode ON,STSTR_DQDON,,,,Nesmrtelnost ZAP,Gud-tilstand PÅ,Gott-Modus AN,,Dio-Reĝimo AKTIVA,Modo Dios ACTIVADO,,Kuolemattomuustila PÄÄLLÄ,Mode invulnérable ON,Isten mód BE,Modalità Dio ATTIVATA,ゴッドモード オン,무적 치트: ON,God Modus AAN,Gudsmodus PÅ,Tryb Boga WŁĄCZONY,Modo Deus LIGADO,,Modul Invincibil PORNIT,Режим Бога ВКЛЮЧЁН,,Gud läge PÅ,Tanrı Modu AÇIK +God Mode OFF,STSTR_DQDOFF,,,,Nesmrtelnost VYP,Gud-tilstand FRA,Gott-Modus AUS,,Dio-Reĝimo NEAKTIVA,Modo Dios DESACTIVADO,,Kuolemattomuustila POIS PÄÄLTÄ,Mode invulnérable OFF,Isten mód KI,Modalità Dio DISATTIVATA,ゴッドモード オフ,무적 치트: OFF,God Modus UIT,Gudsmodus AV,Tryb Boga WYŁĄCZONY,Modo Deus DESLIGADO,,Modul Invincibil OPRIT,Режим Бога ОТКЛЮЧЁН,,Gud läge AV,Tanrı Modu KAPALI +All weapons/ ammo/ keys,STSTR_KFAADDED,,,,Všechny zbraně/munice/klíče,Alle våben/ ammunition/ nøgler,"Alle Waffen, Munition und Schlüssel",,Ĉiuj armiloj/municioj/ŝlosiloj,Todas las armas/municiones/llaves,,Kaikki aseet/ ammukset/ avaimet,Toutes les armes/munitions/clés,Minden fegyver / lőszer / kulcs,Tutte le armi / munizioni / chiavi,スベテノ ブキ/カギ/ダンヤク,추가: 모든 무기/탄약/열쇠 치트,Alle wapens / munitie / sleutels,Alle våpen / ammunisjon / nøkler,Wszystkie bronie/amunicja/klucze,Todas as armas/munição/chaves,,Toate armele/muniție/chei,Всё оружие/боеприпасы/ключи,,Alla vapen/ammunition/nycklar,Tüm silahlar/ cephane/ anahtarlar +All weapons and ammo,STSTR_FAADDED,,,,Všechny zbraně a munice,Alle våben og ammunition,Alle Waffen und Munition,,Ĉiuj armiloj kaj municioj,Todas las armas y municiones,,Kaikki aseet ja ammukset,Toutes les armes et munitions,Minden fegyver és lőszer,Tutte le armi e le munizioni,スベテノ ブキ/ダンヤク,추가: 모든 무기/탄약 치트,Alle wapens en munitie,Alle våpen og ammunisjon,Wszystkie bronie i amunicja,Todas as armas e munição completa,,Toate armele și muniție,Всё оружие и боеприпасы,,Alla vapen och all ammunition,Tüm silahlar ve cephane +Abduction,TXT_HARMMAP01,,,,Únos,Bortførelse,Entführung,,Forkapto,Abducción,,Sieppaus,Enlèvement,Elrablás,Il rapimento,アブダクション,유괴,Ontvoering,Bortføring,Porwanie,Sequestro,,Răpire,Похищение,,Bortförande,Kaçırılma +Harm's Way,TXT_HARMMAP02,,,,Nebezpečí,,In Gefahr,,Vojo de danĝero,En peligro,,Vaara,Mise en Danger,Baj,La via del danno,ハーム'ズ ウェイ,해함의 길,,,Niebezpieczeństwo,No Caminho do Perigo,,Calea pericolului,Опасный путь,,Harms väg,Zarar Görebilecek Durumda +Owt Mood,TXT_HARMMAP03,,,,Špatný pocit,,Missstimmung,,Sentaĉo,Buen humor,,Nollatunnelma,Scontento,Túlterhelve,Scontento,ヤバイムード,이상한 분위기,,,Paskudny Nastrój,Mau Humor,,Fricțiune,Нестроение,,Dåligt stämning,Kötü Ruh Hali +Megalapolis,TXT_HARMMAP04,,,,Megalopole,,Megalopolis,,Megtropolo,Megalópolis,,Megalopoli,Mégalopole,Megalopolisz,Megalapoli,メガラポリス,거대 도시,Megalopolis,,Megalapolis,Megalópole,,Megalopolis,Мегалаполис,,,Megalapolis +The Hospital,TXT_HARMMAP05,,,,Nemocnice,Hospitalet,Das Hospital,,La malsanulejo,El hospital,,Sairaala,L'Hôpital,Kórház,L'ospedale,ホスピタル,병동,Het ziekenhuis,Sykehuset,Szpital,O Hospital,,Spitalul,Больница,,Sjukhuset,Hastane +The Weapons Factory,TXT_HARMMAP06,,,,Továrna na zbraně,Våbenfabrikken,Die Waffenfabrik,,La armil-fabriko,La fábrica de armas,,Asetehdas,L'Usine d'Armes,Fegyvergyár,La fabbrica di armi,ウェポンファクトリー,무기 공장,De Wapenfabriek,Våpenfabrikken,Fabryka Broni,A Fábrica de Armamentos,,Fabrica de Arme,Оружейный завод,,Vapenfabriken,Silah Fabrikası +The Underwater Lab,TXT_HARMMAP07,,,,Podvodní laboratoř,Undervandslaboratoriet,Das Unterwasserlabor,,La subakva labotorio,El laboratorio submarino,,Vedenalainen laboratorio,Le Laboratoire Sous-marin,Vízalatti labor,Il laboratorio subacqueo,アンダーウォーターラボ,해저 연구소,Het onderwaterlaboratorium,Undervannslaboratoriet,Podwodne Laboratorium,O Laboratório Submarino,,Laboratorul Subacvatic,Подводная лаборатория,,Undervattenslaboratoriet,Sualtı Laboratuvarı +Airstrip One,TXT_HARMMAP08,,,,Přistávací dráha jedna,Landingsbane et,Flugplatz Eins,,Surteriĝejo numero unu,Pista de aterrizaje uno,,Kiitorata Yksi,Piste D'Atterrisage Un,1-es kifutó,Pista Uno,エアーシップ ワン,활주로 1호,Vliegveld Een,Flystripe én,Lądowisko Numer Jeden,Base Aérea Um,,Pista Unu,Взлётная полоса №1,,Landningsbana ett,Birinci Pist +The Launch Base,TXT_HARMMAP09,,,,Vzletová základna,Affyringsbasen,Die Startbasis,,La lanĉbazo,La base de despegue,,Laukaisutukikohta,La Base de Lancement,Kilövő Állomás,La base di lancio,ランチャーベース,발진기지,De lanceerbasis,Utskytningsbasen,Baza Startowa,A Base de Lançamento,,Baza de Lansare,Пусковая площадка,,Avfyrningsbasen,Fırlatma Üssü +The Radioactive Zone,TXT_HARMMAP10,,,,Radioaktivní zóna,Den radioaktive zone,Die radioaktive Zone,,La radioaktiva zono,La zona radioactiva,,Radioaktiivinen vyöhyke,La Zone Radioactive,Radioaktív Zóna,La zona radioattiva,ラディオアクティブ ゾーン,방사능 처리소,De Radioactieve Zone,Den radioaktive sonen,Radioaktywna Strefa,A Zona Radioativa,,Zona Radioactivă,Заражённая зона,,Den radioaktiva zonen,Radyoaktif Bölge +Echidna,TXT_HARMMAP11,,,,,,,,Ekidno,Equidna,,Nokkasiili,,Hangyászsün,,エキドナ,에키드나,,,,Equidna,,,Ехидна,,,Echidna "You feel sick to your stomach... Looking in the face of the mutant queen... That thing... That used to be... @@ -101,7 +101,26 @@ zabít svou přítelkyni... „Není běsu většího než hněv ženy zhrzené!“ - = K O N E C =","Dir ist speiübel... + = K O N E C =","Du har kvalme i maven... +Du ser mutantdronningen i øjnene... +Den tingest... Det plejede at være... +din ven... Amira! + +De monstre må have fundet en måde at +mutere hende på og forvandle hende til +dette afskyelige væsen, så hun kan føde +deres afkom. + +-suk- + +Du tager dig sammen... +De kommer til at betale for at få dig til +at dræbe din ven... + +""Helvede har ingen vrede som en +forsmået kvinde!"" + + = T H E E N D =","Dir ist speiübel... Als du in das Gesicht der Mutanten- königin siehst... Das Ding... Das war mal... Deine Freundin... Amira! @@ -190,25 +209,34 @@ tuer votre amie.. ""L'Enfer n'a pas de fureur qui égale celle d'une femme dédaignée!"" - = F I N =",,"Ti senti male allo stomaco... + = F I N =","Felkavarodik a gyomrod...Ahogy a mutáns királynő szemébe nézel...Az az izé...nemrég még...A barátod volt...Amira! + +Ezek a szörnyek minden bizonnyal meglelték a módját, hogy ezzé a borzasztó lénnyé mutálják, aki később az ivadékukat hordja ki. + +-sóhaj- + +Össze kell szedned magad...meg fognak lakolni azért, amiért megölették veled a barátodat... + +""A pokolnál csak egy gyászoló nő haragja borzasztóbb!"" + + = V É G E =","Ti senti male allo stomaco... Guardando in faccia alla regina mutante... -Quella cosa... Quello era... +Quella cosa... Quella era... La tua amica... Amira! Quei mostri devono aver trovato il modo di mutarla e trasformarla in questa -orrenda creatura per portare i loro figli. +orrenda creatura per generare i loro figli. -- sospiro - +*sospiro* -Ti riunisci... -Pagheranno per farti uccidere la tuo amica... +Ti ricomponi... +Pagheranno per averti farti uccidere la tua amica... -""L'inferno non ha furia come una donna disprezzata!"" +""L'inferno non ha furia come una donna oltraggiata!"" = L A F I N E = - -","貴方はミュータントの女王の顔を見た時 + ","貴方はミュータントの女王の顔を見た時 気分が凄まじく悪くなった... その顔は... 見覚えがあった... 私の親友... アミラ! @@ -250,23 +278,40 @@ vermoorden door je vriend... ""De hel heeft geen woede zoals een vrouw die wordt geminacht!"" - = EINDE =","Czujesz się niedobrze... -Patrząc na twarz królowej mutantów... -Ale rzecz w tym, że... to była kiedyś... + = EINDE =","Du føler deg kvalm i magen... +Å se inn i ansiktet til mutantdronningen... +Den tingen... Det pleide å være... +Din venn... Amira! + +De monstrene må ha funnet en måte +å mutere henne på og gjøre henne +til denne avskyelige skapningen +for å bære deres avkom. + +...sukk... + +Ta deg sammen... +De skal få svi for at de fikk +deg til å drepe vennen din... + +""Helvete har ingen raseri +som en forsmådd kvinne!""","Jest ci niedobrze... +Patrzysz królowej mutantów prosto w twarz... +Ta maszkara... to tak naprawdę... Twoja przyjaciółka... Amira! Te potwory znalazły sposób, aby ją zmutować i zamienić ją w tą ohydną poczwarę, by mogły się rozmnażać. -Ehh... +Ech... Bierzesz się w garść... Zapłacą za to, że musiałaś zabić swoją przyjaciółkę... -""Nawet piekło nie może być tak wściekłe -jak zlekceważnona kobieta!"" +""Nawet piekło nie powstrzyma +zlekceważnonej kobiety!"" =K O N I E C=","Você sente vontade de vomitar... Vendo o rosto da rainha mutante... @@ -293,8 +338,8 @@ Acel lucru... Acel lucru obișnuia să fie... Prietena ta... Amira! Moștrii trebuie să fii reușit cumva să o -transforme în această creatură hidoasă care să -le poarte descendenții... +transforme în această creatură hidoasă capabilă +să le care progeniturile... -oftat- @@ -302,12 +347,12 @@ Te aduni... Îi vei face să plătească pentru că te-au făcut să îți omori prietena... -""Iadul nu are furie precum o femeie batjocorită!"" +""Infernul nu are furie precum o femeie batjocorită!"" = S F Â R Ș I T =","Вы почувствовали тошноту, присмотревшись к лицу королевы мутантов. -Эта тварь. Когда-то она была… вашей +Эта тварь. Когда-то она была... вашей подругой Амирой! Эти монстры смогли изменить её. Они @@ -320,17 +365,58 @@ Te aduni... Они заставили вас убить свою подругу, и они поплатятся за это! -«Ад – ничто в сравнении с отвергнутой +«Ад — ничто в сравнении с отвергнутой женщиной!» = К О Н Е Ц = -", -,WI_FINISHED,This text is deliberately empty,,,,,,,,,,,,,,,,,,,,, -Loading,WI_ENTERING,Yellow needs retranslation,,,Načítá se,Lade,,Ŝargante,Cargando,,Ladattavana,Chargement,Betöltés,Caricamento,ローディング,불러오는 중,Laden van,Ładowanie,Carregando,,Se încarcă,Загрузка уровня, -Very Easy,SKILL_BABY,,,,Velmi snadné,Sehr einfach,,Tre Facila,Muy facil,,Erittäin helppo,Trés facile,Nagyon könnyű,Molto facile,ベリーイージー,아주 쉬움,Zeer gemakkelijk,Bardzo Łatwy,Muito facil,,Foarte Ușor,Очень лёгкий, -Easy,SKILL_EASY,,,,Snadný,Einfach,,Facila,Facil,,Helppo,Facile,Könnyű,Facile,イージー,쉬움,Gemakkelijk,Łatwy,Fácil,,Ușor,Лёгкий, -Medium,SKILL_NORMAL,,,,Střední,Mittel,,Meza,Medio,,Keskivaikea,Moyen,Normál,Medio,ミディアム,중간,Middel,Średni,Médio,,Mediu,Средний, -Hard,SKILL_HARD,,,,Obtížný,Schwer,,Malfacila,Difícil,,Vaikea,Difficile,Nehéz,Difficile,ハード,어려움,Moeilijk,Trudny,Difícil,,Greu,Тяжёлый, -Very Hard,SKILL_NIGHTMARE,,,,Velmi obtížné,Sehr schwer,,Tre Malfacila,Muy difícil,,Erittäin vaikea,Très difficile,Nagyon nehéz,Molto difficile,ベリーハード,아주 어려윰,Zeer moeilijk,Bardzo Trudny,Muito difícil,,Foarte Greu,Очень тяжёлый, -Thanks for playing,HARMQUITMSG,,,,Díky za hraní,Danke fürs Spielen,,Dankon pro ludado,Gracias por jugar,,Kiitos pelaamisesta,Merci d'avoir joué,"Köszönjük, hogy játszottál!",Grazie per aver giocato,プレイ シテクレテ カンシャスル,플레이 해주셔서 감사드립니다,Bedankt voor het spelen,Dziękuję za grę,Obrigado por jogar,,Mulțumim că ai jucat,"Спасибо, что сыграли в Harmony", -Harmony,TXT_D2E1,,,,,,,Harmonio,,,Harmonia,,,,,,,,,,,, \ No newline at end of file +",,"Du mår illa i magen... +När du ser mutantdrottningen i ansiktet... +Den där saken... Som brukade vara... +Din vän... Amira! + +De där monstren måste ha hittat ett +sätt att mutera henne och förvandla +henne till den här avskyvärda +varelsen för att föda sin avkomma. + +-suck- + +Ta dig samman... +De kommer att få betala för att de +tvingade dig att döda din vän... + +""Helvetet har ingen vrede som +en kvinna som är föraktad!"" + + + = S L U T E T =","Kendini mutsuz hissediyorsun... +Mutant kraliçenin yüzüne bakarken. +O şey. O eskiden... +Arkadaşın. Amira'ydı! + +O canavarlar onu mutasyona +uğratmanın ve yavrularını doğurması +için bu iğrenç yaratığa +dönüştürmenin bir yolunu +bulmuş olmalılar. + +-İç çek- + +Kendini topla. +Sana arkadaşını öldürtmenin +bedelini ödeyecekler. + +""Cehennemde hor görülen +bir kadın gibi öfke yoktur!"" + + += SON =" +,WI_FINISHED,This text is deliberately empty,,,,,,,,,,,,,,,,,,,,,,,,, +Loading,WI_ENTERING,Yellow needs retranslation,,,Načítá se,Indlæsning,Lade,,Ŝargante,Cargando,,Ladattavana,Chargement,Betöltés,Caricamento,ローディング,불러오는 중,Laden van,Laster,Ładowanie,Carregando,,Se încarcă,Загрузка уровня,,Laddar,Yükleniyor +Very Easy,SKILL_BABY,,,,Velmi snadné,Meget let,Sehr einfach,,Tre facila,Muy fácil,,Erittäin helppo,Trés facile,Nagyon könnyű,Molto facile,ベリーイージー,아주 쉬움,Zeer gemakkelijk,Veldig lett,Bardzo Łatwy,Muito fácil,,Foarte Ușor,Очень легко,,Mycket lätt,Çok Kolay +Easy,SKILL_EASY,,,,Snadný,Let,Einfach,,Facila,Fácil,,Helppo,Facile,Könnyű,Facile,イージー,쉬움,Gemakkelijk,Lett,Łatwy,Fácil,,Ușor,Легко,,Lätt,Kolay +Medium,SKILL_NORMAL,,,,Střední,Middel,Mittel,,Meza,Normal,,Keskivaikea,Moyen,Normál,Medio,ミディアム,중간,Middel,Middels,Średni,Médio,,Mediu,Средне,,Medel,Orta +Hard,SKILL_HARD,,,,Obtížný,Svær,Schwer,,Malfacila,Difícil,,Vaikea,Difficile,Nehéz,Difficile,ハード,어려움,Moeilijk,Vanskelig,Trudny,Difícil,,Greu,Тяжело,,Svårt,Sert +Very Hard,SKILL_NIGHTMARE,,,,Velmi obtížné,Meget svær,Sehr schwer,,Tre malfacila,Muy difícil,,Erittäin vaikea,Très difficile,Nagyon nehéz,Molto difficile,ベリーハード,아주 어려윰,Zeer moeilijk,Svært vanskelig,Bardzo Trudny,Muito difícil,,Foarte Greu,Очень тяжело,,Mycket svårt,Çok Zor +Thanks for playing,HARMQUITMSG,,,,Díky za hraní,Tak for at spille,Danke fürs Spielen,,Dankon pro ludado,Gracias por jugar,,Kiitos pelaamisesta,Merci d'avoir joué,"Köszönjük, hogy játszottál!",Grazie per aver giocato,プレイ シテクレテ カンシャスル,플레이 해주셔서 감사드립니다,Bedankt voor het spelen,Takk for at du spilte,Dziękuję za grę,Obrigado por jogar,,Mulțumim că ai jucat,"Спасибо, что сыграли в Harmony",,Tack för att du spelar,Oynadığınız için teşekkürler +Harmony,TXT_D2E1,,,,,,,,Harmonio,,,Harmonia,,Harmónia,,,,,,Harmonia,,,,,,, \ No newline at end of file diff --git a/wadsrc_extra/static/filter/harmony/mapinfo.txt b/wadsrc_extra/static/filter/harmony/mapinfo.txt index 059469773b7..4c534ff3a6d 100644 --- a/wadsrc_extra/static/filter/harmony/mapinfo.txt +++ b/wadsrc_extra/static/filter/harmony/mapinfo.txt @@ -193,5 +193,5 @@ clusterdef 1 // exittext, background flat is DEM1_1 and music is titletrack flat = DEM1_1 music = "d_dm2ttl" - exittext = "CLUSTEREXIT1" + exittext = lookup, "CLUSTEREXIT1" } diff --git a/wadsrc_extra/static/filter/harmony/zscript.txt b/wadsrc_extra/static/filter/harmony/zscript.txt index 339942ecbd7..de34b25c0ec 100644 --- a/wadsrc_extra/static/filter/harmony/zscript.txt +++ b/wadsrc_extra/static/filter/harmony/zscript.txt @@ -1,2 +1,3 @@ -version "4.2" -#include "zscript/harm_sbar.zs" \ No newline at end of file +version "4.5" +#include "zscript/harm_sbar.zs" +#include "zscript/decorate_replacement.zs" diff --git a/wadsrc_extra/static/filter/harmony/zscript/decorate_replacement.zs b/wadsrc_extra/static/filter/harmony/zscript/decorate_replacement.zs new file mode 100644 index 00000000000..24b82350a24 --- /dev/null +++ b/wadsrc_extra/static/filter/harmony/zscript/decorate_replacement.zs @@ -0,0 +1,65 @@ +class TimeBombWeapon : Weapon replaces BFG9000 +{ + default + { + scale 0.30; + weapon.kickback 100; + weapon.selectionorder 2800; + weapon.ammouse 1; + weapon.ammogive 2; + weapon.ammotype "TimeBombAmmo"; + inventory.pickupmessage "$GOTBFG9000"; + inventory.icon "BFUGA0"; + +WEAPON.NOAUTOFIRE; + +WEAPON.NOAUTOAIM; + } + + states + { + Select: + BFGG A 1 A_Raise; + loop; + Deselect: + BFGG A 1 A_Lower; + loop; + Ready: + BFGG A 1 A_WeaponReady; + loop; + Fire: + SHT2 A 3; + SHT2 A 7 A_CheckReload; + SHT2 B 1 A_BFGSound; + SHT2 B 7; + SHT2 C 6; + SHT2 D 7 A_FireGrenade; + SHT2 E 7; + SHT2 F 7 A_Light0; + SHT2 H 6 A_Light0; + SHT2 A 5 A_Refire; + goto Ready; + Flash: + BFGF A 11 bright A_Light1; + BFGF B 6 bright A_Light2; + SHTG E 0 A_Light0; + stop; + Spawn: + BFUG A -1; + stop; + } + + action void A_FireGrenade() + { + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, weap.ammouse1)) + return; + } + + SpawnPlayerMissile("BFGBall", angle, nofreeaim:sv_nobfgaim); + } +} diff --git a/wadsrc_extra/static/filter/hexen/sprofs.txt b/wadsrc_extra/static/filter/hexen/sprofs.txt index 4408e3b95d9..f82b65aca90 100644 --- a/wadsrc_extra/static/filter/hexen/sprofs.txt +++ b/wadsrc_extra/static/filter/hexen/sprofs.txt @@ -375,3 +375,12 @@ THRWE0, 6, 16, iwad THRWF0, 8, 19, iwad THRWG0, 8, 19, iwad THRWH0, 11, 19, iwad +WFR1A0, 6, 50, iwad +WFR2A0, 10, 28, iwad +WFR3A0, 6, 28, iwad +WMS1A0, 6, 28, iwad +WMS2A0, 6, 35, iwad +WMS3A0, 6, 32, iwad +WCH1A0, 15, 29, iwad +WCH2A0, 9, 30, iwad +WCH3A0, 11, 30, iwad diff --git a/wadsrc_extra/static/iwadinfo.txt b/wadsrc_extra/static/iwadinfo.txt index 56a04444513..8eb7f1522cb 100644 --- a/wadsrc_extra/static/iwadinfo.txt +++ b/wadsrc_extra/static/iwadinfo.txt @@ -227,6 +227,7 @@ IWad Config = "Heretic" IWADName = "blasphemer.wad" Mapinfo = "mapinfo/heretic.txt" + Compatibility = "Extended" MustContain = "E1M1", "E2M1", "TITLE", "BLASPHEM" BannerColors = "73 00 00", "00 00 00" } @@ -264,7 +265,7 @@ IWad Name = "Heretic Shareware" Game = "Heretic" Config = "Heretic" - Mapinfo = "mapinfo/heretic.txt" + Mapinfo = "mapinfo/hereticshareware.txt" Compatibility = "Shareware" MustContain = "E1M1", "TITLE", "MUS_E1M1" BannerColors = "fc fc 00", "a8 00 00" @@ -281,6 +282,7 @@ IWad Mapinfo = "mapinfo/doom2.txt" MustContain = "MAP01", "FREEDM" BannerColors = "32 54 43", "c6 dc d1" + SkipBexStringsIfLanguage } IWad @@ -293,6 +295,7 @@ IWad Mapinfo = "mapinfo/doom2.txt" MustContain = "MAP01", "FREEDOOM" BannerColors = "32 54 43", "c6 dc d1" + SkipBexStringsIfLanguage } IWad @@ -305,6 +308,7 @@ IWad Mapinfo = "mapinfo/doom1.txt" MustContain = "E1M1", "E2M1", "E3M1", "FREEDOOM" BannerColors = "32 54 43", "c6 dc d1" + SkipBexStringsIfLanguage } IWad @@ -316,6 +320,7 @@ IWad Mapinfo = "mapinfo/doom1.txt" MustContain = "E1M1", "FREEDOOM" BannerColors = "32 54 43", "c6 dc d1" + SkipBexStringsIfLanguage } IWad @@ -324,9 +329,9 @@ IWad Autoname = "doom.id.doom1.bfg" Game = "Doom" Config = "Doom" - IWADName = "doom.wad", 2 + IWADName = "doombfg.wad", 2 Mapinfo = "mapinfo/ultdoom.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", @@ -335,6 +340,24 @@ IWad IgnoreTitlePatches = 1 } +IWad +{ + Name = "DOOM: KEX Edition" + Autoname = "doom.id.doom1.kex" + Game = "Doom" + Config = "Doom" + IWADName = "doomkex.wad", 2 + Mapinfo = "mapinfo/ultdoom.txt" + Compatibility = "Shorttex", "nosectionmerge" + MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", + "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", + "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", + "DMENUPIC", "GAMECONF" + Load = "extras.wad" + BannerColors = "00 7c 00", "a8 a8 a8" + IgnoreTitlePatches = 1 +} + IWad { Name = "DOOM: Unity Edition" @@ -343,11 +366,12 @@ IWad Config = "Doom" IWADName = "doomunity.wad", 2 Mapinfo = "mapinfo/ultdoom.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", "DMENUPIC" + Load = "extras.wad", "soundtrack" BannerColors = "00 7c 00", "a8 a8 a8" IgnoreTitlePatches = 1 } @@ -355,10 +379,11 @@ IWad IWad { Name = "DOOM: Complete: WadSmoosh" - Autoname = "doom.id.doom2.wadsmoosh" + Autoname = "doom.id.wadsmoosh" Game = "Doom" Config = "Doom" Mapinfo = "mapinfo/doom2.txt" + IWADName = "doom_complete.pk3" Compatibility = "Shorttex" MustContain = "SMOOSHED", "ANIMDEFS", "LANGUAGE", "MAPINFO", "ENDOOM", "M_DOOM", "TITLEPIC", "TEXTURES" BannerColors = "a8 00 00", "a8 a8 a8" @@ -371,9 +396,9 @@ IWad Autoname = "doom.id.doom1.ultimate.xbox" Game = "Doom" Config = "Doom" - IWADName = "doom.wad" + IWADName = "doomxbox.wad" Mapinfo = "mapinfo/doomxbox.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", "E1M10", "SEWERS" @@ -389,7 +414,7 @@ IWad Config = "Doom" IWADName = "doom.wad" Mapinfo = "mapinfo/ultdoom.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2" @@ -405,7 +430,7 @@ IWad Config = "Doom" IWADName = "doom.wad", 1 Mapinfo = "mapinfo/doom1.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1" @@ -420,7 +445,7 @@ IWad Game = "Doom" Config = "Doom" Mapinfo = "mapinfo/doom1.txt" - Compatibility = "Shareware", "Shorttex" + Compatibility = "Shareware", "Shorttex", "nosectionmerge" MustContain = "E1M1" BannerColors = "54 54 54", "a8 a8 a8" IgnoreTitlePatches = 1 @@ -432,7 +457,7 @@ IWad Autoname = "doom.id.doom2.tnt.unity" Game = "Doom" Config = "Doom" - IWADName = "tnt.wad" + IWADName = "tntunity.wad", 2 Mapinfo = "mapinfo/tnt.txt" Compatibility = "Shorttex", "Stairs" MustContain = "MAP01", "REDTNT2", "DMAPINFO" @@ -440,6 +465,21 @@ IWad IgnoreTitlePatches = 1 } +IWad +{ + Name = "Final Doom: TNT - Evilution: KEX Edition" + Autoname = "doom.id.doom2.tnt.kex" + Game = "Doom" + Config = "Doom" + IWADName = "tntkex.wad" + Mapinfo = "mapinfo/tnt.txt" + Compatibility = "Shorttex", "Stairs" + MustContain = "MAP01", "REDTNT2", "GAMECONF" + BannerColors = "a8 00 00", "a8 a8 a8" + Load = "extras.wad" + IgnoreTitlePatches = 1 +} + IWad { Name = "Final Doom: TNT - Evilution" @@ -460,7 +500,7 @@ IWad Autoname = "doom.id.doom2.plutonia.unity" Game = "Doom" Config = "Doom" - IWADName = "plutonia.wad" + IWADName = "plutoniaunity.wad", 2 Mapinfo = "mapinfo/plutonia.txt" Compatibility = "Shorttex" MustContain = "MAP01", "CAMO1", "DMAPINFO" @@ -468,6 +508,21 @@ IWad IgnoreTitlePatches = 1 } +IWad +{ + Name = "Final Doom: Plutonia Experiment: KEX Edition" + Autoname = "doom.id.doom2.plutonia.kex" + Game = "Doom" + Config = "Doom" + IWADName = "plutoniakex.wad" + Mapinfo = "mapinfo/plutonia.txt" + Compatibility = "Shorttex" + MustContain = "MAP01", "CAMO1", "GAMECONF" + BannerColors = "a8 00 00", "a8 a8 a8" + Load = "extras.wad" + IgnoreTitlePatches = 1 +} + IWad { Name = "Final Doom: Plutonia Experiment" @@ -488,28 +543,43 @@ IWad Autoname = "doom.id.doom2.bfg" Game = "Doom" Config = "Doom" - IWADName = "doom2.wad" + IWADName = "doom2bfg.wad" Mapinfo = "mapinfo/doom2bfg.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01", "DMENUPIC", "M_ACPT", "M_CAN", "M_EXITO", "M_CHG" BannerColors = "a8 00 00", "a8 a8 a8" Load = "nerve.wad" IgnoreTitlePatches = 1 } +IWad +{ + Name = "DOOM 2: KEX Edition" + Autoname = "doom.id.doom2.kex" + Game = "Doom" + Config = "Doom" + IWADName = "doom2kex.wad", 2 + Mapinfo = "mapinfo/doom2.txt" + Compatibility = "Shorttex", "nosectionmerge" + MustContain = "MAP01", "DMENUPIC", "GAMECONF" + BannerColors = "00 7c 00", "a8 a8 a8" + IgnoreTitlePatches = 1 + Load = "extras.wad" +} + IWad { Name = "DOOM 2: Unity Edition" Autoname = "doom.id.doom2.unity" Game = "Doom" Config = "Doom" - IWADName = "doom2unity.wad" + IWADName = "doom2unity.wad", 2 Mapinfo = "mapinfo/doom2unity.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01", "DMENUPIC" BannerColors = "00 7c 00", "a8 a8 a8" IgnoreTitlePatches = 1 - Load = "nerveunity.wad" + Load = "nerveunity.wad", "extras.wad", "soundtrack" } IWad @@ -518,9 +588,9 @@ IWad Autoname = "doom.id.doom2.commercial.xbox" Game = "Doom" Config = "Doom" - IWADName = "doom2.wad", 1 + IWADName = "doom2xbox.wad", 1 Mapinfo = "mapinfo/doom2xbox.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01", "MAP33", "CWILV32" BannerColors = "18 18 18", "a8 a8 a8" IgnoreTitlePatches = 1 @@ -536,7 +606,7 @@ IWad Config = "Doom" IWADName = "doom2f.wad", 1 Mapinfo = "mapinfo/doom2.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01", "WIOBJ" BannerColors = "ff ff ff", "a8 00 00" } @@ -550,7 +620,7 @@ IWad Config = "Doom" IWADName = "doom2.wad", 1 Mapinfo = "mapinfo/doom2.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01" BannerColors = "a8 00 00", "a8 a8 a8" IgnoreTitlePatches = 1 @@ -561,23 +631,28 @@ Names { "doom_complete.pk3" "doom2.wad" + "doom2xbox.wad" + "doom2unity.wad" + "doom2kex.wad" "doom2f.wad" - "plutonia.wad" - "tnt.wad" "doomu.wad" "doom.wad" + "doomxbox.wad" + "doomunity.wad" + "doomkex.wad" "doom1.wad" - "bfgdoom2.wad" - "doom2bfg.wad" "bfgdoom.wad" + "bfgdoom2.wad" "doombfg.wad" + "doom2bfg.wad" "doomxbox.wad" "doom2xbox.wad" - "doomunity.wad" - "doom2unity.wad" - "doom2f.wad" - "tntunity.wad" + "plutonia.wad" "plutoniaunity.wad" + "plutoniakex.wad" + "tnt.wad" + "tntunity.wad" + "tntkex.wad" "freedoom1.wad" "freedoom2.wad" "freedoomu.wad" @@ -612,19 +687,23 @@ Order // Order in the IWAD selection box "DOOM: Complete: WadSmoosh" "DOOM 2: Hell on Earth" "DOOM 2: L'Enfer sur Terre" - "Final Doom: Plutonia Experiment" - "Final Doom: TNT - Evilution" + "DOOM 2: BFG Edition" + "DOOM 2: XBox Edition" + "DOOM 2: KEX Edition" + "DOOM 2: Unity Edition" "The Ultimate DOOM" "DOOM Registered" "DOOM Shareware" - "DOOM 2: BFG Edition" "DOOM: BFG Edition" "DOOM: XBox Edition" - "DOOM 2: XBox Edition" + "DOOM: KEX Edition" "DOOM: Unity Edition" - "DOOM 2: Unity Edition" + "Final Doom: Plutonia Experiment" "Final Doom: Plutonia Experiment: Unity Edition" + "Final Doom: Plutonia Experiment: KEX Edition" + "Final Doom: TNT - Evilution" "Final Doom: TNT - Evilution: Unity Edition" + "Final Doom: TNT - Evilution: KEX Edition" "Freedoom: Phase 1" "Freedoom: Phase 2" "FreeDM" diff --git a/wadsrc_extra/static/language.csv b/wadsrc_extra/static/language.csv index 0b6a3de556b..a4e0b005347 100644 --- a/wadsrc_extra/static/language.csv +++ b/wadsrc_extra/static/language.csv @@ -1,316 +1,316 @@ -default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,pl,pt,ptg,ro,ru,sr -,,Doom Episode names,,,,,,,,,,,,,,,,,"As long as there is no other Portuguese variant, the language ID should be two letters only!",,,, -Knee-Deep in the Dead,TXT_D1E1,,,,Po kolena v mrtvých,Knietief im Tod,Βουτηγμένος στους Νεκρούς μέχρι τα γόνατα,Ĝisgenue en La Mortintoj,Hasta las Rodillas entre Muertos,,Polvia myöten vainajissa,Plongé dans la Mort,Térdig a halálban,Nella morte fino al collo,膝元迫る亡者,끝없이 밀려오는 죽음,Knie-diep in de doden,Po kolana w trupach,Na Morte até os Joelhos,,Îngropat printre Cadavre,По колено в трупах,До колена у лешевима -The Shores of Hell,TXT_D1E2,,,,Břehy pekla,Die Ufer der Hölle,Οι Ακτές της Κόλασης,La Bordoj de Infero,Las Orillas del Infierno,,Hornan rannat,Les Portes de l'Enfer,A pokol tornáca,Le rive dell'Inferno,地獄の瀬戸際,지옥의 해변,De oevers van de hel,Przedsionek Piekieł,As Margens do Inferno,,Țărmurile Iadului,Берега Ада,Обале пакла -Inferno,TXT_D1E3,,,,,,Πυρ το Εξώτερον,,,,,,,,インフェルノ,연옥,,Piekło,,,Infernul,Инферно,Инферно +default,Identifier,Remarks,Filter,eng enc ena enz eni ens enj enb enl ent enw,cs,da,de,el,eo,es,esm esn esg esc esa esd esv eso esr ess esf esl esy esz esb ese esh esi esu,fi,fr,hu,it,jp,ko,nl,no nb,pl,pt,ptg,ro,ru,sr,sv,tr +,,Doom Episode names,,,,,,,,,,,,,,,,,,,"As long as there is no other Portuguese variant, the language ID should be two letters only!",,,,,, +Knee-Deep in the Dead,TXT_D1E1,,,,Po kolena v mrtvých,Knæet dybt i de døde,Knietief im Tod,Βουτηγμένος στους Νεκρούς μέχρι τα γόνατα,Ĝiskole inter mortintoj,Hasta el cuello entre muertos,,Polvia myöten vainajissa,Plongé dans la Mort,Térdig halálban,Nella morte fino al collo,膝元迫る亡者,끝없이 밀려오는 죽음,Knie-diep in de Doden,Knedyp i de døde,Po kolana w trupach,Corpos até os Joelhos,,Îngropat printre Cadavre,По колено в трупах,До колена у лешевима,Knä-djupt i de döda,Ölüme Diz Boyu +The Shores of Hell,TXT_D1E2,,,,Břehy pekla,Helvedes kyster,Die Ufer der Hölle,Οι Ακτές της Κόλασης,La Infer-bordoj,Las orillas del Infierno,,Hornan rannat,Les Portes de l'Enfer,A pokol tornáca,Le rive dell'Inferno,地獄の瀬戸際,지옥의 해변,De Oevers van de Hel,Helvetes kyster,Przedsionek piekieł,As Margens do Abismo,,Țărmurile Iadului,Прибрежье преисподней,Обале пакла,Helvetets stränder,Cehennem Kıyıları +Inferno,TXT_D1E3,,,,,,,Πυρ το Εξώτερον,,,,,,Alvilág,,インフェルノ,연옥,,,,,,Infernul,Инферно,Инферно,,İnferno Thy Flesh Consumed,TXT_D1E4,"The episode and levels' names in E4 are taken from the Bible. -Proverbs 5:11",,,Tvé tělo pozřeto,Dein Leib verzehrt,Η Σάρκα σου θα Καταναλωθεί,Via Karno Konsumita,Tu Carne Consumida,,Lihasi kulutettu,Votre Chair Consumée,Húsod megemésztetik,La tua Carne Consumata,焦がす汝の身,쇠패해진 그대의 육신,Uw verbruikte vlees,Ciało Twe Zwiotczeje,Tua Carne Consumida,No Consumir-se da Carne,Carnea ta Fără de Vlagă,Твоя плоть истощена,Твоје месо строшено -Hell On Earth,TXT_D2E1,,,,Peklo na zemi,Hölle auf Erden,Αρμαγεδδών,Infero Sur La Tero,Infierno en la Tierra,,Helvetti maan päällä,Enfer sur Terre,Pokol a Földön,Inferno sulla Terra,第三惑星:地獄,지상에 강림한 지옥,De hel op aarde,Piekło na Ziemi,Inferno na Terra,,Iadul pe Pământ,Ад на Земле,Пакао на Земљи -No Rest for the Living,TXT_D2E2,"References ""No rest for the wicked"" in Isaiah 48:22",,,Nemajíť živí pokoje,Keine Ruhe für die Lebenden,Καμία Ανάπαυση για τους Ζωντανούς,Nenia Ripozo por la Vivantoj,No hay Descanso para los Vivos,,Ei lepoa eläville,Pas de repos pour les vivants,Nincs békesség az élőnek,Nessun Riposo per i Vivi,休息なき生計,산 자에게 휴식은 없다,Geen rust voor de levenden,Brak Wytchnienia Dla Żywych,Não Há Descanso Para os Vivos,,Cei vii Fără de Odihnă,Нет покоя для живых,Нема одмора живима -The Plutonia Experiment,TXT_PLUT_EP,,,,Experiment Plutonia,Das Plutonia Experiment,Το Πείραμα Πλουτώνια,La Eksperimento de Plutonia,El Experimento Plutonia,,Plutoniakokemus,L'expérience Plutonia,A Plutonia-kísérlet,L'Esperimento di Plutonia,プルトニア記,플루토니아 익스페리먼트,Het Plutonia experiment,Eksperyment Plutonia,O Experimento Plutonia,A Experiência Plutonia,Experimentul Plutonia,Эксперимент «Плутония»,Експеримент Плутонија -TNT: Evilution,TXT_TNT_EP,,,,TNT: Zlovoluce,,ΤΝΤ: Κακοξέλιξη,TNT: Mavalucio,TNT: Malvolución,,TNT: Paholuutio,,,TNT: Malvoluzione,TNT:邪神化,TNT: 이블루션,Tnt: Evilutie,TNT: Ewolucja Zła,TNT: Malvolução,,TNT: Diavoluția,TNT: Дьяволюция,TNT: Евилуција -Chex Quest,TXT_CHEX_EP,,,,Mise Chex,,Η Περιπέτεια του Chex,Aventuro de Chex,,,Chex-seikkailu,,,,チェックス クエスト,첵스 퀘스트,,Misja Chex,,,,,Чекс Квест -,,Level names,,,,,,,,,,,,,,,,,,,,, -,,Doom 1,,,,,,,,,,,,,,,,,,,,, -E1M1: Hangar,HUSTR_E1M1,,,,E1M1: Hangár,,E1Χ1: Υπόστεγο,E1M1: Hangaro,,,E1M1: Lentoalushalli,,E1M1: Hangár,,E1M1: 格納庫,E1M1: 격납고,,E1M1: Hangar,,,E1M1: Hangar,E1M1: Ангар,E1M1: Хангар -E1M2: Nuclear Plant,HUSTR_E1M2,,,,E1M2: Jaderná elektrárna,E1M2: Nuklearfabrik,E1Χ2: Πυρηνικό Εργοστάσιο,E1M2: Nuklea Centralo,E1M2: Planta Nuclear,,E1M2: Ydinvoimala,E1M2: Centrale Nucléaire,E1M2: Atomerőmű,E1M2: Centrale Nucleare,E1M2: 原子力発電所,E1M2: 원자력 발전소,E1m2: Kerncentrale,E1M2: Elektrownia Jądrowa,E1M2: Usina Nuclear,E1M2: Central Nuclear,E1M2: Uzina Nucleară,E1M2: Атомная электростанция,E1M2: Нуклеарна електрана -E1M3: Toxin Refinery,HUSTR_E1M3,,,,E1M3: Chemická rafinerie,E1M3: Giftraffinerie,E1Χ3: Διυλιστήριο Τοξινών,E1M3: Toksinrafinejo,E1M3: Refinería de Toxinas,,E1M3: Myrkkyjalostamo,E1M3: Raffinerie de Toxines,E1M3: Méregfinomító,E1M3: Raffineria delle Tossine,E1M3: 毒素精錬所 ,E1M3: 폐기물 정제소,E1m3: Giftstof raffinaderij,E1M3: Rafineria Toksyn,E1M3: Refinaria de Toxinas,,E1M3: Rafinăria de Toxine,E1M3: Завод по переработке токсинов,E1M3: Рафинерија за токсине -E1M4: Command Control,HUSTR_E1M4,,,,E1M4: Řídící velení,E1M4: Betriebssteuerung,E1Χ4: Κέντρο Ελέγχου,E1M4: Kontrolcentro,E1M4: Control de Mando,,E1M4: Komentohallinta,E1M4: Centre de Contrôle,E1M4: Parancsvezérlő,E1M4: Centrale di Comando,E1M4: 指令管制塔,E1M4: 지휘 통제소,E1m4: Commando controle,E1M4: Kontrola Dowodzenia,E1M4: Controle de Comando,E1M4: Controlo de Comando,E1M4: Comandă și Control,E1M4: Командный пункт,E1M4: Заповедни центар -E1M5: Phobos Lab,HUSTR_E1M5,,,,E1M5: Phobosská laboratoř,E1M5: Phobos-Labor,E1Χ5: Εργαστήριο Φόβου,E1M5: Fobo-Laboratorio,E1M5: Laboratorio de Phobos,,E1M5: Phoboksen laboratorio,E1M5: Laboratoires Phobos,E1M5: Phoboszi laboratórium,E1M5: Laboratorio di Phobos,E1M5: フォボス研究所,E1M5: 포보스 연구소,E1m5: Phobos laboratorium,E1M5: Laboratoria Fobosa,E1M5: Laboratório de Fobos,,E1M5: Laboratorul Phobos,E1M5: Лаборатория на Фобосе,E1M5: Лабораторија на Фобосу -E1M6: Central Processing,HUSTR_E1M6,,,,E1M6: Centrální zpracování,E1M6: Zentralverarbeitung,E1Χ6: Κεντρική Επεξεργασία,E1M6: Centra Traktejo,E1M6: Procesador Central,,E1M6: Käsittelykeskus,E1M6: Centre de Traitement,E1M6: Központi feldolgozó,E1M6: Zona Elaboratori,E1M6: 中央処理施設,E1M6: 중앙 처리 본부,E1m6: Centrale verwerking,E1M6: Centralne Przetwarzanie,E1M6: Processamento Central,,E1M6: Prelucrare Centrală,E1M6: Центральный пункт обработки,E1M6: Централна обрада -E1M7: Computer Station,HUSTR_E1M7,,,,E1M7: Počítačová stanice,E1M7: Computerstation,E1Χ7: Σταθμός Υπολογιστών,E1M7: Komputilo-stacio,E1M7: Estación de Cómputo,,E1M7: Tietokoneasema,E1M7: Station Informatique,E1M7: Számítógépközpont,E1M7: Stazione dei Computer,E1M7: コンピューターステーション,E1M7: 컴퓨터 기지,E1m7: Computerstation,E1M7: Stacja Komputerowa,E1M7: Estação de Computadores,,E1M7: Stația de Calculatoare,E1M7: Вычислительный центр,E1M7: Компјутерска станица -E1M8: Phobos Anomaly,HUSTR_E1M8,,,,E1M8: Phobosská anomálie,E1M8: Phobos-Anomalie,E1Χ8: Ανωμαλία στον Φόβο,E1M8: Nenormalaĵo de Fobo,E1M8: Anomalía de Phobos,,E1M8: Phoboksen poikkeama,E1M8: Anomalie de Phobos,E1M8: Phoboszi anomália,E1M8: L'anomalia di Phobos,E1M8: フォボスの変則,E1M8: 포보스 이상거점,E1m8: Phobos anomalie,E1M8: Anomalia Fobosa,E1M8: Anomalia de Fobos,,E1M8: Anomalia Phobos,E1M8: Аномалия Фобоса,E1M8: Аномалија на Фобосу -E1M9: Military Base,HUSTR_E1M9,,,,E1M9: Vojenská základna,E1M9: Militärbasis,E1Χ9: Στρατιωτική Βάση,E1M9: Militbazo,E1M9: Base Militar,,E1M9: Sotilastukikohta,E1M9: Base Militaire ,E1M9: Katonai bázis,E1M9: Base militare,E1M9: 軍事基地,E1M9: 군사 기지,E1m9: Militaire basis,E1M9: Baza Wojskowa,E1M9: Base Militar,,E1M9: Baza Militară,E1M9: Военная база,E1M9: Војна база -E1M10: Sewers,HUSTR_E1M10,,,,E1M10: Kanály,E1M10: Kanalisation,,E1M10: Kanalo,E1M10: Las Alcantarillas,,E1M10: Viemärit,E1M10: Egouts,E1M10: A csatornák,E1M10: Le Fogne,E1M10: 下水道,E1M10: 하수구,E1M10: De rioleringen,E1M10: Ścieki,E1M10: Os Esgotos,,E1M10: Canalizarea,E1M10: Канализация,E1M10: Канализација -E2M1: Deimos Anomaly,HUSTR_E2M1,,,,E2M1: Deimosská anomálie,E2M1: Deimos-Anomalie,E2Χ1: Ανωμαλία στον Δείμο,E2M1: Nenormalaĵo de Dejmo,E2M1: Anomalía de Deimos,,E2M1: Deimoksen poikkeama,E2M1: Anomalie de Déimos,E2M1: Deimoszi anomália,E2M1: L'anomalia di Deimos,E2M1: 異常なるダイモス,E2M1: 데이모스 이상거점,E2m1: Deimos anomalie,E2M1: Anomalia Deimosa,E2M1: Anomalia de Deimos,,E2M1: Anomalia Deimos,E2M1: Аномалия Деймоса,E2M1: Аномалија на Дејмосу -E2M2: Containment Area,HUSTR_E2M2,,,,E2M2: Kontrolní oblast,E2M2: Lagerhalle,E2Χ2: Ζώνη Περιορισμού,E2M2: Enhavarejo,E2M2: Área de Confinamiento,,E2M2: Säilöntäalue,E2M2: Zone de Stockage,E2M2: Raktár,E2M2: Area di contenimento,E2M2: 収容エリア,E2M2: 화물 보관구역,E2m2: Inperkingsgebied,E2M2: Obszar Zastrzeżony,E2M2: Area de Contenção,E2M2: Área de Confinamento,E2M2: Zona de Izolare,E2M2: Хранилище,E2M2: Складишта -E2M3: Refinery,HUSTR_E2M3,,,,E2M3: Rafinerie,E2M3: Raffinerie,E2Χ3: Διυλιστήριο,E2M3: Refinejo,E2M3: Refinería,,E2M3: Jalostamo,E2M3: Raffinerie,E2M3: Finomító,E2M3: Raffineria,E2M3: 精製所,E2M3: 정제소,E2m3: Raffinaderij,E2M3: Rafineria,E2M3: Refinaria,,E2M3: Rafinărie,E2M3: Очистительный завод,E2M3: Рафинерија -E2M4: Deimos Lab,HUSTR_E2M4,,,,E2M4: Deimosská laboratoř,E2M4: Deimos Labor,E2Χ4: Εργαστήριο Δείμου,E2M4: Dejmo-Laboratorio,E2M4: Laboratorio de Deimos,,E2M4: Deimoksen laboratorio,E2M4: Laboratoires Déimos,E2M4: Deimoszi laboratórium,E2M4: Laboratorio di Deimos,E2M4: ダイモス研究所,E2M4: 데이모스 연구소,E2m4: Deimos laboratorium,E2M4: Laboratoria Deimosa,E2M4: Laboratório de Deimos,,E2M4: Laboratorul Deimos,E2M4: Лаборатория на Деймосе,E2M4: Лабораторија на Дејмосу -E2M5: Command Center,HUSTR_E2M5,,,,E2M5: Řídící centrum,E2M5: Kommandozentrum,E2Χ5: Κέντρο Διοίκησης,E2M5: Komandcentro,E2M5: Centro de Mando,,E2M5: Komentokeskus,E2M5: Centre de Commandement,E2M5: Parancsnoki központ,E2M5: Centro di Comando,E2M5: 指令本部,E2M5: 사령부,E2m5: Commando centrum,E2M5: Centrum Dowodzenia,E2M5: Centro de Comando,,E2M5: Centru de Comandă,E2M5: Командный центр,E2M5: Командни центар -E2M6: Halls of the Damned,HUSTR_E2M6,,,,E2M6: Chodby zatracených,E2M6: Säle der Verdammten,E2X6: Διάδρομοι των Κολασμένων,E2M6: Koridoroj de La Damnitaj,E2M6: Salones de los Malditos,,E2M6: Kirottujen salit,E2M6: Halls des Damnés,E2M6: Az átkozottak csarnokai,E2M6: Sale dei Dannati,E2M6: ダムドの会堂,E2M6: 저주받은 회랑,E2m6: Zalen van de verdoemden,E2M6: Korytarze Przeklętych,E2M6: Salões dos Condenados,,E2M6: Camerele Blestemaților,E2M6: Залы проклятых,E2M6: Дворана проклетих -E2M7: Spawning Vats,HUSTR_E2M7,,,,E2M7: Plodné kádě,E2M7: Materialisationskammern,E2X7: Δεξαμενές Γέννησης,E2M7: Nasko-kuvegoj,E2M7: Silos de Materialización,,E2M7: Sikiämissammiot,E2M7: Cuves de Reproduction,E2M7: Szaporító tartályok,E2M7: Vasche di Riproduzione,E2M7: 産卵桶,E2M7: 산란독,E2m7: Materialisatie kamers,E2M7: Kadzie Reprodukcyjne,E2M7: Cubas de Desova,,E2M7: Cuve de Reproducere,E2M7: Нерестилище,E2M7: Размножавалишта -E2M8: Tower of Babel,HUSTR_E2M8,,,,E2M8: Babylonská věž,E2M8: Turmbau zu Babel,E2Χ8: Πύργος της Βαβέλ,E2M8: Turo de Babelo,E2M8: Torre de Babel,,E2M8: Baabelin torni,E2M8: Tour de Babel,E2M8: Bábel tornya,E2M8: Torre di Babele,E2M8: バベルの塔,E2M8: 바벨탑,E2m8: Toren van Babel,E2M8: Wieża Babel,E2M8: Torre de Babel,,E2M8: Turnul Babel,E2M8: Вавилонская башня,E2M8: Вавилонска кула -E2M9: Fortress of Mystery,HUSTR_E2M9,,,,E2M9: Pevnost záhad,E2M9: Geheimnisvolle Festung,E2Χ9: Φρούριο του Μυστηρίου,E2M9: Fortreso de Mistero,E2M9: Fortaleza del Misterio,,E2M9: Salaperäisyyden linnake,E2M9: Mystérieuse Forteresse,E2M9: A rejtélyek erődje,E2M9: Fortezza del Mistero,E2M9: 神秘の要塞,E2M9: 신비의 요새,E2m9: Vesting van mysterie,E2M9: Forteca Tajemnic,E2M9: Fortaleza do Mistério,,E2M9: Fortăreața Misterelor,E2M9: Крепость тайн,E2M9: Тврђава тајни -E3M1: Hell Keep,HUSTR_E3M1,,,,E3M1: Pekelná tvrz,E3M1: Höllenbollwerk,E3Χ1: Ακροπύργιο της Κολάσεως,E3M1: Infera Fortikaĵo,E3M1: Torreón del Infierno,E3M1: Torre del Infierno,E3M1: Hornantorni,E3M1: Donjon Infernal,E3M1: A pokol bástyái,E3M1: Bastioni dell'Inferno,E3M1: 牢獄,E3M1: 지옥 성채,E3m1: De hel bollwerk,E3M1: Twierdza Piekieł,E3M1: Torre do Inferno,,E3M1: Fortul Iadului,E3M1: Крепость Ада,E3M1: Тврђава пакла -E3M2: Slough of Despair,HUSTR_E3M2,,,,E3M2: Bažina zoufalství,E3M2: Sumpf der Verzweiflung,E3Χ2: Έλος της Απελπισίας,E3M2: Ŝlimejo de Malespero,E3M2: Ciénaga de la Desesperación,,E3M2: Epätoivon räme,E3M2: Bourbier du Désespoir,E3M2: A kétségbeesés mocsara,E3M2: Palude della Disperazione,E3M2: 絶望の大地,E3M2: 절망의 심연,E3m2: Moeras van wanhoop,E3M2: Bagno Rozpaczy,E3M2: Pântano do Desespero,,E3M2: Mlaștinile Disperării,E3M2: Трясина отчаяния,E3M2: Блато очајања -E3M3: Pandemonium,HUSTR_E3M3,,,,,E3M3: Pandämonium,E3Χ3: Πανδαιμόνιο,E3M3: Pandemonio,,,,E3M3: Pandémonium,E3M3: Zűrzavar,E3M3: Pandemonio,E3M3: 伏魔殿,E3M3: 복마전,,E3M3: Piekło,E3M3: Pandemônio,,E3M3: Pandemoniu,E3M3: Пандемониум,E3M3: Пандемонијум -E3M4: House of Pain,HUSTR_E3M4,,,,E3M4: Dům bolesti,E3M4: Haus des Schmerzes,E3Χ4: Σπίτι του Πόνου,E3M4: Domo de Doloro,E3M4: Casa del Dolor,,E3M4: Tuskanmaja,E3M4: Maison de la Douleur,E3M4: A kínok háza,E3M4: Casa del Dolore,E3M4: 苦痛の館,E3M4: 고통의 집,E3m4: Huis van de pijn,E3M4: Dom Bólu,E3M4: Casa da Dor,,E3M4: Casa Durerii,E3M4: Дом боли,E3M4: Кућа патње -E3M5: Unholy Cathedral,HUSTR_E3M5,,,,E3M5: Bezbožná katedrála,E3M5: Unheilige Kathedrale,E3X5: Ανίερος Καθεδρικός,E3M5: Malsankta Katedralo,E3M5: Catedral Profana,,E3M5: Epäpyhä katedraali,E3M5: Cathédrale Profane,E3M5: Az istentelen katedrális ,E3M5: Cattedrale Blasfema,E3M5: 邪教の大聖堂,E3M5: 불경한 성당,E3m5: Onheilige kathedraal,E3M5: Bluźniercza Katedra,E3M5: Catedral Profana,,E3M5: Catedrala Necurată,E3M5: Нечестивый собор,E3M5: Несвета катедрала -E3M6: Mt. Erebus,HUSTR_E3M6,,,,E3M6: Hora Erebus,,E3X6: Όρος Έρεβος,E3M6: Monto Erebo,E3M6: Monte Erebus,,E3M6: Erebusvuori,E3M6: Mont Erèbe,E3M6: Erebus-hegy,E3M6: Monte Erebus,E3M6: エレボス山,E3M6: 에레버스 산,,E3M6: Góra Erebus,E3M6: Monte Érebo,,E3M6: M. Erebus,E3M6: Гора Эребус,E3M6: Планина Еребус -E3M7: Limbo,HUSTR_E3M7,,,,E3M7: Předpeklí,,E3Χ7: Είσοδος της Κολάσεως,,,,E3M7: Limbus,E3M7: Limbes,E3M7: Limbus,E3M7: Limbo,E3M7: 忘却の地,E3M7: 고성소,,E3M7: Otchłań,E3M7: Limbo,,E3M7: Limb,E3M7: Врата в Лимб,E3M7: Лимбо -E3M8: Dis,HUSTR_E3M8,"Based on the City of Dis, located on the sixth circle of Hell, according to Dante Alighieri's The Divine Comedy",,,,,E3Χ8: Δίτα,,,,,,,E3M8: Dite,E3M8: 死,E3M8: 디스,,E3M8: Dis,E3M8: Dite,,E3M8: Dite,E3M8: Дит,E3M8: Дис -E3M9: Warrens,HUSTR_E3M9,,,,E3M9: Brlohy,E3M9: Rattennest,E3X9: Λαγούμια,E3M9: Nestego,E3M9: Madrigueras,,E3M9: Sokkelot,E3M9: Clapiers,E3M9: Nyúlkert,E3M9: Le Garenne,E3M9: 兎小屋,E3M9: 토끼굴,E3M9: Stallen,E3M9: Królikarnia,E3M9: Tocas,,E3M9: Vizuini,E3M9: Кроличий сад,E3M9: Одгајалиште -E4M1: Hell Beneath,HUSTR_E4M1,Proverbs 15:24,,,E4M1: Peklo v hlubinách,E4M1: Die Hölle unterwärts,E4Χ1: Κάτω Κόσμος,E4M1: Ŝeolo Malsupre,E4M1: Bajo el Infierno,,E4M1: Tuonela alhaalla,E4M1: Le Séjour des Morts,E4M1: A holtak hazája odalent,E4M1: In Basso,E4M1: 地獄の下へ,E4M1: 지옥의 밑에서,E4m1: Hel beneden,E4M1: Piekło Najgłębsze,E4M1: Inferno Abaixo,E4M1: Inferno Profundo,E4M1: Iadul de Jos,E4M1: Преисподняя внизу,E4M1: Свет мртвих -E4M2: Perfect Hatred,HUSTR_E4M2,Psalm 139:22,,,E4M2: Naprostá nenávist,E4M2: Perfekter Hass,E4Χ2: Τέλειο Μίσος,E4M2: Perfekta Malamo,E4M2: Odio Perfecto,,E4M2: Kaikella vihalla,E4M2: Une Parfaite Haine,E4M2: Teljes gyűlölettel,E4M2: Odio Perfetto,E4M2: 完全なる憎悪,E4M2: 완벽한 증오,E4m2: Perfecte haat,E4M2: Pełnia Nienawiści,E4M2: Ódio Perfeito,,E4M2: Ură Desăvârșită,E4M2: Полная ненависть,E4M2: Крајња мржња -E4M3: Sever The Wicked,HUSTR_E4M3,Matthew 13:49,,,E4M3: Oddělit zkažené,E4M3: Scheidet die Bösen,E4Χ3: Ξερίζωσε τους Πονηρούς,E4M3: Apartigi la Malbonulojn,E4M3: Cercena a los impíos,,E4M3: Erottavat pahat,E4M3: Séparer les Vicieux,E4M3: Felnégyelni a bűnösöket,E4M3: Separeranno I Cattivi,E4M3: 邪悪を絶つ,E4M3: 악령처단,E4m3: Scheid de goddelozen af,E4M3: Oddzielą Niegodziwych,E4M3: Separarão os Perversos,E4M3: Separarão o Mal,E4M3: Să Desparți pe Cei Răi,E4M3: Отделить злых,E4M3: Издвојити зле -E4M4: Unruly Evil,HUSTR_E4M4,James 3:8,,,E4M4: Nezkrotitelné zlo,E4M4: Schandbare Worte,E4X4: Ασυγκράτητο Κακό,E4M4: Neretenebla Malbono,E4M4: Maldad Incontrolable,,E4M4: Levotointa pahuutta,E4M4: Un Mal Irrépréssible,E4M4: Féktelen gonosz,E4M4: Male Senza Posa,E4M4: 手に負えない悪,E4M4: 광폭한 악마,E4m4: Het weerbarstige kwaad,E4M4: Niepohamowane Zło,E4M4: Mal Irrefreável,E4M4: Mal que não Refreia,E4M4: Un Rău fără Astâmpăr,E4M4: Неудержимое зло,Е4М4: Немирно зло -E4M5: They Will Repent,HUSTR_E4M5,Luke 16:30,,,E4M5: Budou činit pokání,E4M5: Sie werden bereuen,E4X5: Θα Μετανοήσουν,E4M5: Ili Pentos,E4M5: Se Arrepentirán,,E4M5: He parannuksen tekisivät,E4M5: Ils se repentiront,E4M5: Megtérnek majd,E4M5: Si Ravvederanno,E4M5: 奴等に後悔を,E4M5: 그들은 회개할 지어다,E4m5: Ze zullen berouw hebben,E4M5: Nawrócą Się,E4M5: Eles se Arrependerão,E4M5: Eles Arrepender-se-iam,E4M5: Se vor Pocăi,E4M5: Они покаются,E4M5: Покајаће се -E4M6: Against Thee Wickedly,HUSTR_E4M6,Psalm 139:20,,,E4M6: Při svých pletichách,E4M6: Feinde erheben sich,E4X6: Κακόβουλα Εναντίον Σου,E4M6: Kontraŭ Vi Malvirte,E4M6: Perversamente Contra Tí,,E4M6: Sinusta petollisesti,E4M6: D'une manière criminelle,E4M6: Hitványul ellened,E4M6: Contro di te Malvagiamente,E4M6: 汝への悪逆,E4M6: 그대와 짖궂게 맞서다,E4m6: Tegen de goddeloze,E4M6: Podstępnie Przeciw Tobie,E4M6: Contra Ti Perversamente,E4M6: Malvadamente Contra Ti,E4M6: Te Grăiesc de Rău,E4M6: Против тебя нечестиво,E4M6: Против тебе сплеткаре -E4M7: And Hell Followed,HUSTR_E4M7,Revelation 6:8,,,E4M7: A peklo šlo za ním,E4M7: Und die Hölle folgte,E4X7: Και η Κόλαση Ακολούθησε,E4M7: Kaj Hades Sekvis,E4M7: Y el Infierno Continuó,E4M7: E o Inferno Seguiu,E4M7: Ja Tuonela seurasi,E4M7: Et l'Enfer Suivit,E4M7: És a pokol követé azt,E4M7: E l'inferno seguitava,E4M7: そして地獄は従った,E4M7: 그리고 지옥이 뒤따른다,E4m7: En de hel volgde,E4M7: A Piekło Szło Za Nim,E4M7: E o Inferno Seguiu,E4M7: Inferno o Seguia,E4M7: Iadul se Ținea după El,E4M7: И последовал Ад,E4M7: И пакао иђаше -E4M8: Unto The Cruel,HUSTR_E4M8,Proverbs 5:9,,,E4M8: Ukrutníku odevzdáš,E4M8: Deine Jahre dem Grausamen,E4X8: Προς Τους Ανελεήμονες,E4M8: Al La Kruelulo,E4M8: En lo Cruel,,E4M8: Armottomalle,E4M8: A un Homme cruel,E4M8: A kegyetlennek,E4M8: Al Crudele,E4M8: 容赦なき者へ,E4M8: 잔혹한 자에게로,E4m8: Naar de wrede,E4M8: Kto Nie Zna Litości,E4M8: Para os Cruéis,E4M8: Entregue a Cruéis,E4M8: Unuia Fără de Milă,E4M8: К мучителю,E4M8: Окрутним људима -E4M9: Fear,HUSTR_E4M9,,,,E4M9: Strach,E4M9: Angst,E4Χ9: Τρόμος,E4M9: Timo,E4M9: Miedo,,E4M9: Pelko,E4M9: Terreur,E4M9: Félelem,E4M9: Paura,E4M9: 恐怖,E4M9: 공포,E4m9: Angst,E4M9: Strach,E4M9: Medo,,E4M9: Frica,E4M9: Страх,E4M9: Страх -,,Doom 2,,,,,,,,,,,,,,,,,,,,, -Level 1: Entryway,HUSTR_1,"Note that the ""LEVEL"" part of the string will be stripped so it shouldn't be translated",,,Level 1: Vchod,Level 1: Eingangshalle,Επίπεδο 1: Είσοδος,Nivelo 1: Enirvojo,Nivel 1: Entrada,,Taso 1: Eteiskäytävä,NIVEAU 1: Hall D'Entrée,Bejárat,Level 1: Ingresso,Level 1: 入口,레벨 1: 초입,Level 1: Ingang,Level 1: Wejście,Nível 1: Entrada,,Nivelul 1: Intrarea,Level 1: Вход,Level 1: Улаз -Level 2: Underhalls,HUSTR_2,,,,Level 2: Podzemí,Level 2: Kellergewölbe,,Nivelo 2: Subtervojoj,Nivel 2: Salones subterráneos,,Taso 2: Maanalaiset käytävät,NIVEAU 2: Souterrains,Alagutak,Level 2: Sotterranei,Level 2: 下水道,레벨 2: 지하수로,Level 2: Onderhallen,Level 2: Podziemia,Nível 2: Subterrâneo,,Nivelul 2: Pasaje subterane,Level 2: Подземные ходы,Level 2: Подземни ходници -Level 3: The Gantlet,HUSTR_3,“a form of punishment in which a person is forced to run between two lines of men facing each other and armed with clubs or whips to beat the victim”,,,Level 3: Trest,Level 3: Spießrutenlauf,,Nivelo 3: La Spaliroj de Doloro,Nivel 3: El Guantelete,,Taso 3: Kujanjuoksu,NIVEAU 3: Parcours du Combatant,Vesszőfutás,Level 3: Le fustigazioni,Level 3: ガントレット,레벨 3: 건틀릿,Level 3: De gantlet,Level 3: Praszczęta,Nível 3: A Punição,,Nivelul 3: Stroiul,Level 3: Вызов брошен,Level 3: Казна -Level 4: The Focus,HUSTR_4,,,,Level 4: Ohnisko,Level 4: Der Fokus,,Nivelo 4: La Fokuso,Nivel 4: El Foco,,Taso 4: Polttopiste,NIVEAU 4: Le Focus,A középpont,Level 4: L'Epicentro,Level 4: フォーカス,레벨 4: 초점,Level 4: De focus,Level 4: Skupisko,Nível 4: O Foco,,Nivelul 4: Focarul,Level 4: Средоточие,Level 4: Средиште -Level 5: The Waste Tunnels,HUSTR_5,,,,Level 5: Odpadní tunely,Level 5: Die Abfall-Tunnel,Επίπεδο 5: Οι Σήραγγες Αποβλήτων,Nivelo 5: La Elĵetaĵtuneloj,Nivel 5: Los Túneles de Desechos,,Taso 5: Jätetunnelit,NIVEAU 5: Les Egouts,Hulladékalagutak,Level 5: I Tunnel dei Rifiuti,Level 5: 廃棄トンネル,레벨 5: 하수도,Level 5: De afvaltunnels,Level 5: Kanały,Nível 5: Os Túneis de Resíduos,,Nivelul 5: Tuneluri pentru deșeuri,Level 5: Сточные туннели,Level 5: Отпадни тунели -Level 6: The Crusher,HUSTR_6,,,,Level 6: Drtička,Level 6: Die Presse,Επίπεδο 6: Ο Συνθλιπτής,Nivelo 6: La Dispistilo,Nivel 6: La Trituradora,,Taso 6: Murskaaja,NIVEAU 6: Le Broyeur,A zúzda,Level 6: La Pressa,Level 6: クラッシャー,레벨 6: 분쇄기,Level 6: De maalmachine,Level 6: Zgniatarka,Nível 6: O Esmagador,,Nivelul 6: Zdrobitorul,Level 6: Пресс,Level 6: Разбијач -Level 7: Dead Simple,HUSTR_7,,,,Level 7: Smrtelně prosté,Level 7: Tödlich einfach,Επίπεδο 7: Πανεύκολο,Nivelo 7: Morte Simpla,Nivel 7: Simplemente Muerto,,Taso 7: Kuolettavan yksinkertainen,NIVEAU 7: Mortellement Simple,Halál egyszerű,Level 7: Morte Pura,Level 7: 死ぬほど単純,레벨 7: 죽여주는 단순함,Level 7: Dodelijk eenvoudig,Level 7: Śmiertelnie Proste,Nível 7: Mortalmente Simples,Nível 7: Simplesmente Mortal,Nivelul 7: Mortal de simplu,Level 7: Смертельно просто,Level 7: Смртно једноставно -Level 8: Tricks and Traps,HUSTR_8,,,,Level 8: Lesti a léčky,Level 8: Tricks und Fallen,Επίπεδο 8: Κόλπα και Παγίδες,Nivelo 8: Trokoj de Timo,Nivel 8: Trucos y Trampas,,Taso 8: Metkuja ja pauloja,NIVEAU 8: Ruses et Pièges,Fortélyos csapdák,Level 8: Trucchi e Trappole,Level 8: 悪戯と罠,레벨 8: 속임수와 함정들,Level 8: Trucs en vallen,Level 8: Sztuczki i Pułapki,Nível 8: Truques e Armadilhas,,Nivelul 9: Surprize și capcane,Level 8: Уловки и ловушки,Level 8: Замке и смицалице -Level 9: The Pit,HUSTR_9,,,,Level 9: Jáma,Level 9: Die Grube,Επίπεδο 9: Λάκκος,Nivelo 9: La Fosaĵo,Nivel 9: El Pozo,,Taso 9: Monttu,NIVEAU 9: La Fosse,A gödör,Level 9: Il Pozzo,Level 9: 大穴,레벨 9: 구덩이,Level 9: De groeve,Level 9: Dół,Nível 9: O Fosso,,Nivelul 9: Groapa,Level 9: Яма,Level 9: Јама -Level 10: Refueling Base,HUSTR_10,,,,Level 10: Tankovací základna,Level 10: Treibstoffbunker,Επίπεδο 10: Βάση Ανεφοδιασμού,Nivelo 10: Refuelbazo,Nivel 10: Base de Reabastecimiento,,Taso 10: Tankkausasema,NIVEAU 10: Base de Ravitaillement,Tankolóállomás,Level 10: Base di Rifornimento,Level 10: 補給基地,레벨 10: 연료 충전소,Level 10: Tankstation,Level 10: Stacja Tankowania,Nível 10: Base de Reabastecimento,,Nivelul 10: Baza de alimentare,Level 10: Заправочная база,Level 10: Бензинска база +Proverbs 5:11",,,Tvé tělo pozřeto,Dit kød er fortæret,Dein Leib verzehrt,Η Σάρκα σου θα Καταναλωθεί,Kiam konsumiĝos via karno,Cuando tu carne se consuma,,Lihasi kulutettu,Votre Chair Consumée,Megemésztetik a te húsod,La tua Carne Consumata,滅びし汝の身,쇠패해진 그대의 육신,Uw Vlees Geconsumeerd,Ditt kjøtt fortæres,Ciało twe zwiotczeje,No Consumir-se da Tua Carne,,Carnea ta Fără de Vlagă,Твоя плоть поглощена,Твоје месо строшено,Ditt kött är uppslukat,Etin Tükendi +Hell On Earth,TXT_D2E1,,,,Peklo na zemi,Helvede på jorden,Hölle auf Erden,Αρμαγεδδών,Infero sur la Tero,Infierno en la Tierra,,Helvetti maan päällä,Enfer sur Terre,Földi pokol,Inferno sulla Terra,第三惑星:地獄,지상에 강림한 지옥,Hel op Aarde,Helvete på jorden,Piekło na Ziemi,Inferno na Terra,,Iadul pe Pământ,Ад на Земле,Пакао на Земљи,Helvetet på jorden,Yeryüzündeki Cehennem +No Rest for the Living,TXT_D2E2,"References ""No rest for the wicked"" in Isaiah 48:22",,,Nemajíť živí pokoje,Ingen hvile for de levende,Keine Ruhe für die Lebenden,Καμία Ανάπαυση για τους Ζωντανούς,Nenia ripozo por la vivantoj,No hay descanso para los vivos,,Ei lepoa eläville,Pas de repos pour les vivants,Nincs nyugodalom az élőnek,Nessun Riposo per i Vivi,休息なき生計,산 자에게 휴식은 없다,Geen Rust voor de Levenden,Ingen hvile for de levende,Nie ma pokoju dla żywych,Não Há Descanso Para os Vivos,,Cei vii Fără de Odihnă,Не будет покоя живым,Нема одмора живима,Ingen vila för de levande,Yaşayanlara Huzur Yok +The Plutonia Experiment,TXT_PLUT_EP,,,,Experiment Plutonia,Plutonia-eksperimentet,Das Plutonia Experiment,Το Πείραμα Πλουτώνια,La eksperimento de Plutonia,El experimento Plutonia,,Plutoniakokemus,L'expérience Plutonia,A Plutonia-kísérlet,L'Esperimento di Plutonia,プルトニア記,플루토니아 익스페리먼트,Het Plutonia Experiment,Plutonia-eksperimentet,Eksperyment Plutonia,O Experimento Plutonia,A Experiência Plutonia,Experimentul Plutonia,Эксперимент «Плутония»,Експеримент Плутонија,Plutonia-experimentet,Plutonia Deneyi +TNT: Evilution,TXT_TNT_EP,,,,TNT: Zlovoluce,,,ΤΝΤ: Κακοξέλιξη,TNT: Mavalucio,TNT: Diabolución,,TNT: Paholuutio,,,TNT: Malvoluzione,TNT:邪神化,TNT: 이블루션,Tnt: Evilutie,,TNT: Ewolucja zła,TNT: Malvolução,,TNT: Diavoluția,TNT: Дьяволюция,TNT: Ђаволуција,, +Chex Quest,TXT_CHEX_EP,,,,Mise Chex,,,Η Περιπέτεια του Chex,Aventuro de Chex,,,Chex-seikkailu,,,,チェックス クエスト,첵스 퀘스트,,,Misja Chex,,,,,Чекс Квест,, +,,Level names,,,,,,,,,,,,,,,,,,,,,,,,, +,,Doom 1,,,,,,,,,,,,,,,,,,,,,,,,, +E1M1: Hangar,HUSTR_E1M1,,,,E1M1: Hangár,,,E1Χ1: Υπόστεγο,E1M1: Hangaro,,,E1M1: Lentoalushalli,,E1M1: Hangár,,E1M1: 格納庫,E1M1: 격납고,,,,,,,E1M1: Ангар,E1M1: Хангар,, +E1M2: Nuclear Plant,HUSTR_E1M2,,,,E1M2: Jaderná elektrárna,E1M2: Atomkraftværk,E1M2: Kernkraftwerk,E1Χ2: Πυρηνικό Εργοστάσιο,E1M2: Nuklea centralo,E1M2: Central nuclear,,E1M2: Ydinvoimala,E1M2: Centrale Nucléaire,E1M2: Atomerőmű,E1M2: Centrale Nucleare,E1M2: 原子力発電所,E1M2: 원자력 발전소,E1M2: Kerncentrale,E1M2: Kjernekraftverk,E1M2: Elektrownia Jądrowa,E1M2: Usina Nuclear,E1M2: Central Nuclear,E1M2: Uzina Nucleară,E1M2: Атомная электростанция,E1M2: Нуклеарна електрана,E1M2: Kärnkraftverk,E1M2: Nükleer Santral +E1M3: Toxin Refinery,HUSTR_E1M3,,,,E1M3: Chemická rafinerie,E1M3: Giftraffinaderi,E1M3: Giftraffinerie,E1Χ3: Διυλιστήριο Τοξινών,E1M3: Toksin-rafinejo,E1M3: Refinería de toxinas,,E1M3: Myrkkyjalostamo,E1M3: Raffinerie de Toxines,E1M3: Méregfinomító,E1M3: Raffineria delle Tossine,E1M3: 毒素精錬所 ,E1M3: 폐기물 정제소,E1M3: Giftstofraffinaderij,E1M3: Giftraffineri,E1M3: Rafineria Toksyn,E1M3: Refinaria de Toxinas,,E1M3: Rafinăria de Toxine,E1M3: Очистной завод,E1M3: Рафинерија за токсине,E1M3: Toxinraffinaderi,E1M3: Toksin Rafinerisi +E1M4: Command Control,HUSTR_E1M4,,,,E1M4: Řídící velín,E1M4: Kommandokontrol,E1M4: Betriebssteuerung,E1Χ4: Κέντρο Ελέγχου,E1M4: Komando kaj kontrolo,E1M4: Mando y control,,E1M4: Komentohallinta,E1M4: Centre de Contrôle,E1M4: Parancsnoki vezérlő,E1M4: Centrale di Comando,E1M4: 指令管制塔,E1M4: 지휘 통제소,E1M4: Controlecentrum,E1M4: Kommandokontroll,E1M4: Kontrola Dowodzenia,E1M4: Controle de Comando,E1M4: Controlo de Comando,E1M4: Comandă și Control,E1M4: Пункт управления,E1M4: Заповедни центар,E1M4: Kommandokontroll,E1M4: Komuta Kontrol +E1M5: Phobos Lab,HUSTR_E1M5,,,,E1M5: Phobosská laboratoř,E1M5: Phobos-laboratorium,E1M5: Phobos-Labor,E1Χ5: Εργαστήριο Φόβου,E1M5: Laboratorio sur Fobo,E1M5: Laboratorio de Fobos,,E1M5: Phoboksen laboratorio,E1M5: Laboratoires Phobos,E1M5: Phoboszi laboratórium,E1M5: Laboratorio di Phobos,E1M5: フォボス研究所,E1M5: 포보스 연구소,E1M5: Phobos Laboratorium,E1M5: Phobos-laboratorium,E1M5: Laboratoria Fobosa,E1M5: Laboratório de Fobos,,E1M5: Laboratorul Phobos,E1M5: Лаборатория Фобоса,E1M5: Лабораторија на Фобосу,E1M5: Phobos-laboratorium,E1M5: Phobos Laboratuvarı +E1M6: Central Processing,HUSTR_E1M6,,,,E1M6: Centrální zpracování,E1M6: Central behandling,E1M6: Zentralverarbeitung,E1Χ6: Κεντρική Επεξεργασία,E1M6: Procesorad-centralo,E1M6: Central de procesamiento,,E1M6: Käsittelykeskus,E1M6: Centre de Traitement,E1M6: Központi feldolgozó,E1M6: Zona Elaboratori,E1M6: 中央処理施設,E1M6: 중앙 처리 본부,E1M6: Centrale Verwerking,E1M6: Sentral prosessering,E1M6: Centralne Przetwarzanie,E1M6: Processamento Central,,E1M6: Prelucrare Centrală,E1M6: Центральный пункт обработки,E1M6: Централна обрада,E1M6: Central bearbetning,E1M6: Merkezi İşlem +E1M7: Computer Station,HUSTR_E1M7,,,,E1M7: Počítačová stanice,E1M7: Computerstation,E1M7: Computerstation,E1Χ7: Σταθμός Υπολογιστών,E1M7: Komputila stacio,E1M7: Estación de cómputo,,E1M7: Tietokoneasema,E1M7: Station Informatique,E1M7: Számítógépes központ,E1M7: Stazione dei Computer,E1M7: コンピューターステーション,E1M7: 컴퓨터 기지,E1M7: Computerstation,E1M7: Datastasjon,E1M7: Stacja Komputerowa,E1M7: Estação de Computadores,,E1M7: Stația de Calculatoare,E1M7: Вычислительный центр,E1M7: Компјутерска станица,E1M7: Datorstation,E1M7: Bilgisayar İstasyonu +E1M8: Phobos Anomaly,HUSTR_E1M8,,,,E1M8: Phobosská anomálie,E1M8: Phobos-anomali,E1M8: Phobos-Anomalie,E1Χ8: Ανωμαλία στον Φόβο,E1M8: Nenormalaĵo sur Fobo,E1M8: Anomalía de Fobos,,E1M8: Phoboksen poikkeama,E1M8: Anomalie de Phobos,E1M8: Phoboszi anomália,E1M8: L'anomalia di Phobos,E1M8: フォボス アノマリー,E1M8: 포보스 이상거점,E1M8: Phobos Anomalie,E1M8: Phobos-anomali,E1M8: Anomalia Fobosa,E1M8: Anomalia de Fobos,,E1M8: Anomalia Phobos,E1M8: Аномалия Фобоса,E1M8: Аномалија на Фобосу,E1M8: Phobos anomali,E1M8: Phobos Anomalisi +E1M9: Military Base,HUSTR_E1M9,,,,E1M9: Vojenská základna,E1M9: Militærbase,E1M9: Militärbasis,E1Χ9: Στρατιωτική Βάση,E1M9: Militbazo,E1M9: Base militar,,E1M9: Sotilastukikohta,E1M9: Base Militaire ,E1M9: Katonai bázis,E1M9: Base militare,E1M9: 軍事基地,E1M9: 군사 기지,E1M9: Militaire Basis,E1M9: Militærbase,E1M9: Baza Wojskowa,E1M9: Base Militar,,E1M9: Baza Militară,E1M9: Военная база,E1M9: Војна база,E1M9: Militärbas,E1M9: Askeri Üs +E1M10: Sewers,HUSTR_E1M10,,,,E1M10: Kanály,E1M10: Kloakkerne,E1M10: Kanalisation,,E1M10: Kloako,E1M10: Alcantarillas,,E1M10: Viemärit,E1M10: Egouts,E1M10: Kanálisok,E1M10: Le Fogne,E1M10: 下水道,E1M10: 하수구,E1M10: De Rioleringen,E1M10: Kloakk,E1M10: Ścieki,E1M10: Os Esgotos,,E1M10: Canalizarea,E1M10: Канализация,E1M10: Канализација,E1M10: Avloppsledningar,E1M10: Kanalizasyonlar +E2M1: Deimos Anomaly,HUSTR_E2M1,,,,E2M1: Deimosská anomálie,E2M1: Deimos Anomali,E2M1: Deimos-Anomalie,E2Χ1: Ανωμαλία στον Δείμο,E2M1: Nenormalaĵo sur Dejmo,E2M1: Anomalía de Deimos,,E2M1: Deimoksen poikkeama,E2M1: Anomalie de Déimos,E2M1: Deimoszi anomália,E2M1: L'anomalia di Deimos,E2M1: 異常なるダイモス,E2M1: 데이모스 이상거점,E2M1: Deimos Anomalie,E2M1: Deimos-anomali,E2M1: Anomalia Deimosa,E2M1: Anomalia de Deimos,,E2M1: Anomalia Deimos,E2M1: Аномалия Деймоса,E2M1: Аномалија на Дејмосу,E2M1: Deimos-anomali,E2M1: Deimos Anomalisi +E2M2: Containment Area,HUSTR_E2M2,,,,E2M2: Skladiště,E2M2: Indespærringsområde,E2M2: Lagerhalle,E2Χ2: Ζώνη Περιορισμού,E2M2: Magazeno,E2M2: Área de almacenamiento,,E2M2: Säilöntäalue,E2M2: Zone de Stockage,E2M2: Raktár,E2M2: Area di contenimento,E2M2: 収容エリア,E2M2: 화물 보관구역,E2M2: Inperkingsgebied,E2M2: Innesperringsområde,E2M2: Obszar Zastrzeżony,E2M2: Area de Contenção,E2M2: Área de Confinamento,E2M2: Zona de Izolare,E2M2: Зона сдерживания,E2M2: Складишта,E2M2: Lagringsområde,E2M2: Çevreleme Alanı +E2M3: Refinery,HUSTR_E2M3,,,,E2M3: Rafinerie,E2M3: Raffinaderi,E2M3: Raffinerie,E2Χ3: Διυλιστήριο,E2M3: Rafinejo,E2M3: Refinería,,E2M3: Jalostamo,E2M3: Raffinerie,E2M3: Finomító,E2M3: Raffineria,E2M3: 精製所,E2M3: 정제소,E2M3: Raffinaderij,E2M3: Raffineri,E2M3: Rafineria,E2M3: Refinaria,,E2M3: Rafinărie,E2M3: Перерабатывающий завод,E2M3: Рафинерија,E2M3: Raffinaderi,E2M3: Rafineri +E2M4: Deimos Lab,HUSTR_E2M4,,,,E2M4: Deimosská laboratoř,E2M4: Deimos-laboratorium,E2M4: Deimos Labor,E2Χ4: Εργαστήριο Δείμου,E2M4: Laboratorio sur Dejmo,E2M4: Laboratorio de Deimos,,E2M4: Deimoksen laboratorio,E2M4: Laboratoires Déimos,E2M4: Deimoszi laboratórium,E2M4: Laboratorio di Deimos,E2M4: ダイモス研究所,E2M4: 데이모스 연구소,E2M4: Deimos Laboratorium,E2M4: Deimos-laboratoriet,E2M4: Laboratoria Deimosa,E2M4: Laboratório de Deimos,,E2M4: Laboratorul Deimos,E2M4: Лаборатория Деймоса,E2M4: Лабораторија на Дејмосу,E2M4: Deimos Lab,E2M4: Deimos Laboratuvarı +E2M5: Command Center,HUSTR_E2M5,,,,E2M5: Řídící středisko,E2M5: Kommandocentral,E2M5: Kommandozentrum,E2Χ5: Κέντρο Διοίκησης,E2M5: Komandcentro,E2M5: Centro de mando,,E2M5: Komentokeskus,E2M5: Centre de Commandement,E2M5: Központi parancsnokság,E2M5: Centro di Comando,E2M5: 指令本部,E2M5: 사령부,E2M5: Commandocentrum,E2M5: Kommandosentralen,E2M5: Centrum Dowodzenia,E2M5: Centro de Comando,,E2M5: Centru de Comandă,E2M5: Командный центр,E2M5: Командни центар,E2M5: Kommandocentrum,E2M5: Komuta Merkezi +E2M6: Halls of the Damned,HUSTR_E2M6,,,,E2M6: Chodby zatracených,E2M6: De Forbandedes haller,E2M6: Säle der Verdammten,E2X6: Διάδρομοι των Κολασμένων,E2M6: Koridoroj de la damnitoj,E2M6: Salones de los malditos,,E2M6: Kirottujen salit,E2M6: Halls des Damnés,E2M6: Az átkozottak termei,E2M6: Sale dei Dannati,E2M6: ダムドの会堂,E2M6: 저주받은 회랑,E2M6: Zalen der Verdoemden,E2M6: De fordømtes haller,E2M6: Korytarze Przeklętych,E2M6: Salões dos Condenados,,E2M6: Camerele Blestemaților,E2M6: Залы проклятых,E2M6: Дворана проклетих,E2M6: De fördömdas salar,E2M6: Lanetliler Salonu +E2M7: Spawning Vats,HUSTR_E2M7,,,,E2M7: Plodné kádě,E2M7: Spirebassiner,E2M7: Materialisationskammern,E2X7: Δεξαμενές Γέννησης,E2M7: Nasko-kuvegoj,E2M7: Silos de materialización,,E2M7: Sikiämissammiot,E2M7: Cuves de Reproduction,E2M7: Szaporító tartályok,E2M7: Vasche di Riproduzione,E2M7: 産卵桶,E2M7: 산란독,E2M7: Materialisatietanks,E2M7: Gytekarene,E2M7: Kadzie Reprodukcyjne,E2M7: Tanques de Criação,,E2M7: Cuve de Reproducere,E2M7: Нерестилище,E2M7: Размножавалиште,E2M7: Växthus för spädning,E2M7: Yumurtlama Fıçıları +E2M8: Tower of Babel,HUSTR_E2M8,,,,E2M8: Babylonská věž,E2M8: Babelstårn,E2M8: Turmbau zu Babel,E2Χ8: Πύργος της Βαβέλ,E2M8: Turo de Babelo,E2M8: Torre de Babel,,E2M8: Baabelin torni,E2M8: Tour de Babel,E2M8: Bábel tornya,E2M8: Torre di Babele,E2M8: バベルの塔,E2M8: 바벨탑,E2M8: Toren van Babel,E2M8: Babels tårn,E2M8: Wieża Babel,E2M8: Torre de Babel,,E2M8: Turnul Babel,E2M8: Вавилонская башня,E2M8: Вавилонска кула,E2M8: Babels torn,E2M8: Babil Kulesi +E2M9: Fortress of Mystery,HUSTR_E2M9,,,,E2M9: Pevnost záhad,E2M9: Mysteriets fæstning,E2M9: Geheimnisvolle Festung,E2Χ9: Φρούριο του Μυστηρίου,E2M9: Fortreso de mistero,E2M9: Fortaleza del misterio,,E2M9: Salaperäisyyden linnake,E2M9: Mystérieuse Forteresse,E2M9: A rejtélyek erődje,E2M9: Fortezza del Mistero,E2M9: 神秘の要塞,E2M9: 신비의 요새,E2M9: Vesting der Mysterie,E2M9: Mysteriets festning,E2M9: Forteca Tajemnic,E2M9: Fortaleza do Mistério,,E2M9: Fortăreața Misterelor,E2M9: Крепость тайн,E2M9: Тврђава тајни,E2M9: Mysteriets fästning,E2M9: Gizem Kalesi +E3M1: Hell Keep,HUSTR_E3M1,,,,E3M1: Pekelná tvrz,E3M1: Helvedesborg,E3M1: Höllenbollwerk,E3Χ1: Ακροπύργιο της Κολάσεως,E3M1: Infera ĉefturo,E3M1: Torreón del Infierno,,E3M1: Hornantorni,E3M1: Donjon Infernal,E3M1: A pokol bástyái,E3M1: Bastioni dell'Inferno,E3M1: 牢獄,E3M1: 지옥 성채,E3M1: Helleslot,E3M1: Helvetes borg,E3M1: Twierdza Piekieł,E3M1: Torre do Inferno,,E3M1: Fortul Iadului,E3M1: Крепость Ада,E3M1: Тврђава пакла,E3M1: Helvetesborg,E3M1: Cehennem Kalesi +E3M2: Slough of Despair,HUSTR_E3M2,,,,E3M2: Bažina zoufalství,E3M2: Fortvivlelsens sump,E3M2: Sumpf der Verzweiflung,E3Χ2: Έλος της Απελπισίας,E3M2: Ŝlimejo de malespero,E3M2: Ciénaga de la desesperación,,E3M2: Epätoivon räme,E3M2: Bourbier du Désespoir,E3M2: A kétségbeesés mocsara,E3M2: Palude della Disperazione,E3M2: 絶望の大地,E3M2: 절망의 심연,E3M2: Moeras der Wanhoop,E3M2: Fortvilelsens sump,E3M2: Bagno Rozpaczy,E3M2: Lamaçal do Desespero,,E3M2: Mlaștinile Disperării,E3M2: Трясина отчаяния,E3M2: Блато очајања,E3M2: Förtvivlans svackor,E3M2: Umutsuzluk Slough'u +E3M3: Pandemonium,HUSTR_E3M3,,,,,E3M3: Pandemonium,E3M3: Pandämonium,E3Χ3: Πανδαιμόνιο,E3M3: Pandemonio,E3M3: Pandemonio,,,E3M3: Pandémonium,E3M3: Zűrzavar,E3M3: Pandemonio,E3M3: 伏魔殿,E3M3: 복마전,,,E3M3: Piekło,E3M3: Pandemônio,,E3M3: Pandemoniu,E3M3: Пандемоний,E3M3: Пандемонијум,E3M3: Pandemonium,E3M3: Pandemonium +E3M4: House of Pain,HUSTR_E3M4,,,,E3M4: Dům bolesti,E3M4: Hus af smerte,E3M4: Haus des Schmerzes,E3Χ4: Σπίτι του Πόνου,E3M4: Domo de doloro,E3M4: Casa del dolor,,E3M4: Tuskanmaja,E3M4: Maison de la Douleur,E3M4: A kínok háza,E3M4: Casa del Dolore,E3M4: 苦痛の館,E3M4: 고통의 집,E3M4: Huis van Pijn,E3M4: Smertens hus,E3M4: Dom Bólu,E3M4: Casa da Dor,,E3M4: Casa Durerii,E3M4: Обитель боли,E3M4: Кућа патње,E3M4: Smärtans hus,E3M4: Acı Evi +E3M5: Unholy Cathedral,HUSTR_E3M5,,,,E3M5: Bezbožná katedrála,E3M5: Uhellig katedral,E3M5: Unheilige Kathedrale,E3X5: Ανίερος Καθεδρικός,E3M5: Malsankta katedralo,E3M5: Catedral profana,,E3M5: Epäpyhä katedraali,E3M5: Cathédrale Profane,E3M5: Az istentelen katedrális ,E3M5: Cattedrale Blasfema,E3M5: 邪教の大聖堂,E3M5: 불경한 성당,E3M5: Onheilige Kathedraal,E3M5: Den vanhellige katedralen,E3M5: Bluźniercza Katedra,E3M5: Catedral Profana,,E3M5: Catedrala Necurată,E3M5: Нечестивый собор,E3M5: Несвета катедрала,E3M5: Den oheliga katedralen,E3M5: Kutsal Olmayan Katedral +E3M6: Mt. Erebus,HUSTR_E3M6,Volcano in Antarctica,,,E3M6: Hora Erebus,,,E3X6: Όρος Έρεβος,E3M6: Monto de Erebo,E3M6: Monte Erebus,,E3M6: Erebusvuori,E3M6: Mont Erèbe,E3M6: Erebus-hegy,E3M6: Monte Erebus,E3M6: エレボス山,E3M6: 에레버스 산,,E3M6: Erebus-fjellet,E3M6: Góra Erebus,E3M6: Monte Érebo,,E3M6: M. Erebus,E3M6: Гора Эребус,E3M6: Планина Еребус,,E3M6: Erebus Dağı +E3M7: Limbo,HUSTR_E3M7,,,,E3M7: Předpeklí,,,E3Χ7: Είσοδος της Κολάσεως,,,,E3M7: Limbus,E3M7: Limbes,E3M7: Limbus,,E3M7: 忘却の地,E3M7: 고성소,,,E3M7: Otchłań,,,E3M7: Limb,E3M7: Чистилище,E3M7: Лимбо,,E3M7: Araf +E3M8: Dis,HUSTR_E3M8,"Based on the City of Dis, located on the sixth circle of Hell, according to Dante Alighieri's The Divine Comedy",,,,,,E3Χ8: Δίτα,E3M8: Danteca,E3M8: Ciudad de Dite,,,E3M8: Dité,,E3M8: Dite,E3M8: 死,E3M8: 디스,,,,E3M8: Dite,,E3M8: Dite,E3M8: Дит,E3M8: Дис,, +E3M9: Warrens,HUSTR_E3M9,,,,E3M9: Brlohy,E3M9: Rotteboet,E3M9: Rattennest,E3X9: Λαγούμια,E3M9: Nestego,E3M9: Madrigueras,,E3M9: Sokkelot,E3M9: Clapiers,E3M9: Nyúlkert,E3M9: Le Garenne,E3M9: 兎小屋,E3M9: 토끼굴,E3M9: Doolhof,E3M9: Rottebo,E3M9: Królikarnia,E3M9: Tocas,,E3M9: Vizuini,E3M9: Изнорье,E3M9: Одгајалиште,E3M9: Vildmark,E3M9: Sıçan yuvası +E4M1: Hell Beneath,HUSTR_E4M1,Proverbs 15:24,,,E4M1: Peklo v hlubinách,E4M1: Helvede nedenunder,E4M1: Die Hölle unterwärts,E4Χ1: Κάτω Κόσμος,E4M1: Ŝeolo malsupre,E4M1: Seol abajo,,E4M1: Tuonela alhaalla,E4M1: Le Séjour des Morts,E4M1: A holtak hazája odalent,E4M1: In Basso,E4M1: 地獄の下へ,E4M1: 지옥의 밑에서,E4M1: Hel beneden,E4M1: Helvete under,E4M1: Piekło Najgłębsze,E4M1: Inferno Abaixo,E4M1: Inferno Profundo,E4M1: Iadul de Jos,E4M1: Преисподняя под ногами,E4M1: Пакао одоздо,E4M1: Helvetet under,E4M1: Cehennem Altında +E4M2: Perfect Hatred,HUSTR_E4M2,Psalm 139:22,,,E4M2: Naprostá nenávist,E4M2: Perfekt had,E4M2: Perfekter Hass,E4Χ2: Τέλειο Μίσος,E4M2: Ekstrema malamo,E4M2: Aborrecer por completo,,E4M2: Kaikella vihalla,E4M2: Une Parfaite Haine,E4M2: Teljes gyűlölettel,E4M2: Odio Perfetto,E4M2: 完全なる憎悪,E4M2: 완벽한 증오,E4M2: Perfecte Haat,E4M2: Perfekt hat,E4M2: Pełnia Nienawiści,E4M2: Ódio Perfeito,,E4M2: Ură Desăvârșită,E4M2: Полная ненависть,E4M2: Пуном мрзошћу,E4M2: Perfekt Hass,E4M2: Kusursuz Nefret +E4M3: Sever The Wicked,HUSTR_E4M3,Matthew 13:49,,,E4M3: Oddělit zkažené,E4M3: Afskære de onde,E4M3: Scheidet die Bösen,E4Χ3: Ξερίζωσε τους Πονηρούς,E4M3: Apartigi la malbonulojn,E4M3: Apartarán a los malos,,E4M3: Erottavat pahat,E4M3: Séparer les Vicieux,E4M3: Felnégyelni a bűnösöket,E4M3: Separeranno I Cattivi,E4M3: 邪悪を絶つ,E4M3: 악령처단,E4M3: Scheid de goddelozen af,E4M3: Skille ut de onde,E4M3: Oddzielą Niegodziwych,E4M3: Separarão os Maus,E4M3: Separarão o Mal,E4M3: Să Desparți pe Cei Răi,E4M3: Отделить злых,E4M3: Одлучи зле,E4M3: Separera de onda,E4M3: Kötüleri Kesin +E4M4: Unruly Evil,HUSTR_E4M4,James 3:8,,,E4M4: Nezkrotitelné zlo,E4M4: Ustyrlig ondskab,E4M4: Schandbare Worte,E4X4: Ασυγκράτητο Κακό,E4M4: Malkvieta malbono,E4M4: Mal irrefrenable,,E4M4: Levotointa pahuutta,E4M4: Un Mal Irrépréssible,E4M4: Féktelen gonosz,E4M4: Male Senza Posa,E4M4: 手に負えない邪悪,E4M4: 광폭한 악마,E4M4: Het weerbarstige kwaad,E4M4: Uregjerlig ondskap,E4M4: Niepohamowane Zło,E4M4: Mal Irrefreável,E4M4: Mal que não Refreia,E4M4: Un Rău fără Astâmpăr,E4M4: Неудержимое зло,Е4М4: Немирно зло,E4M4: Den oregerliga ondskan,E4M4: Asi Kötülük +E4M5: They Will Repent,HUSTR_E4M5,Luke 16:30,,,E4M5: Budou činit pokání,E4M5: De vil omvende sig,E4M5: Sie werden bereuen,E4X5: Θα Μετανοήσουν,E4M5: Ili pentos,E4M5: Se arrepentirán,,E4M5: He parannuksen tekisivät,E4M5: Ils se repentiront,E4M5: Megtérnek majd,E4M5: Si Ravvederanno,E4M5: 奴等に後悔を,E4M5: 그들은 회개할 지어다,E4M5: Ze zullen berouw hebben,E4M5: De vil omvende seg,E4M5: Nawrócą Się,E4M5: Arrepender-se,E4M5: Eles Arrepender-se-iam,E4M5: Se vor Pocăi,E4M5: Они покаются,E4M5: Покајаће се,E4M5: De kommer att ångra sig,E4M5: Tövbe Edecekler +E4M6: Against Thee Wickedly,HUSTR_E4M6,Psalm 139:20,,,E4M6: Při svých pletichách,E4M6: Mod dig ondskabsfuldt,E4M6: Feinde erheben sich,E4X6: Κακόβουλα Εναντίον Σου,E4M6: Pri Vi malice,E4M6: Blasfemias contra ti,,E4M6: Sinusta petollisesti,E4M6: D'une manière criminelle,E4M6: Hitványul ellened,E4M6: Contro di te Malvagiamente,E4M6: 汝への悪逆,E4M6: 그대와 짖궂게 맞서다,E4M6: Tegen de goddeloze,E4M6: Mot deg ondskapsfullt,E4M6: Podstępnie Przeciw Tobie,E4M6: Malvadamente Contra Ti,,E4M6: Te Grăiesc de Rău,E4M6: Против тебя нечестиво,E4M6: Ружно на тебе,E4M6: Mot dig ondskan,E4M6: Sana Karşı Kötüce +E4M7: And Hell Followed,HUSTR_E4M7,Revelation 6:8,,,E4M7: A peklo šlo za ním,E4M7: Og Helvede fulgte efter,E4M7: Und die Hölle folgte,E4X7: Και η Κόλαση Ακολούθησε,E4M7: Kaj Hades sekvis,E4M7: El Hades le seguía,E4M7: El Hades lo seguía,E4M7: Ja Tuonela seurasi,E4M7: Et l'Enfer Suivit,E4M7: És a pokol követé azt,E4M7: E l'inferno seguitava,E4M7: そして地獄は従った,E4M7: 그리고 지옥이 뒤따른다,E4M7: En de hel volgde,E4M7: Og helvete fulgte,E4M7: A Piekło Szło Za Nim,E4M7: E o Inferno Seguia,E4M7: Inferno o Seguia,E4M7: Iadul se Ținea după El,E4M7: И последовал Ад,E4M7: И пакао иђаше,E4M7: Och helvetet följde,E4M7: Ve Cehennem Takip Etti +E4M8: Unto The Cruel,HUSTR_E4M8,Proverbs 5:9,,,E4M8: Ukrutníku odevzdáš,E4M8: Til de grusomme,E4M8: Deine Jahre dem Grausamen,E4X8: Προς Τους Ανελεήμονες,E4M8: Al la kruelulo,E4M8: Tus años al cruel,,E4M8: Armottomalle,E4M8: A un Homme cruel,E4M8: A kegyetlennek,E4M8: Al Crudele,E4M8: 容赦なき者へ,E4M8: 잔혹한 자에게로,E4M8: Naar de wrede,E4M8: Til de grusomme,E4M8: Kto Nie Zna Litości,E4M8: Aos Cruéis,E4M8: Entregue a Cruéis,E4M8: Unuia Fără de Milă,E4M8: К мучителю,E4M8: Немилостивоме,E4M8: Mot de grymma,E4M8: Zalimlere Karşı +E4M9: Fear,HUSTR_E4M9,,,,E4M9: Strach,E4M9: Frygt,E4M9: Angst,E4Χ9: Τρόμος,E4M9: Timo,E4M9: Miedo,,E4M9: Pelko,E4M9: Terreur,E4M9: Félelem,E4M9: Paura,E4M9: 恐怖,E4M9: 공포,E4M9: Angst,E4M9: Frykt,E4M9: Strach,E4M9: Medo,,E4M9: Frica,E4M9: Страх,E4M9: Страх,E4M9: Rädsla,E4M9: Korku +,,Doom 2,,,,,,,,,,,,,,,,,,,,,,,,, +Level 1: Entryway,HUSTR_1,"Note that the ""LEVEL"" part of the string will be stripped so it shouldn't be translated",,,Level 1: Vchod,Level 1: Indgang,Level 1: Eingangshalle,Επίπεδο 1: Είσοδος,Nivelo 1: Enirejo,Nivel 1: Entrada,,Taso 1: Eteiskäytävä,NIVEAU 1: Hall D'Entrée,1. Pálya: Bejárat,Livello 1: Ingresso,Level 1: 入口,레벨 1: 초입,Level 1: Ingang,Nivå 1: Inngangen,Level 1: Wejście,Fase 1: Entrada,Nível 1: Entrada,Nivelul 1: Intrarea,Уровень №1: Вход,Level 1: Улаз,Nivå 1: Ingång,Seviye 1: Giriş Yolu +Level 2: Underhalls,HUSTR_2,,,,Level 2: Podzemí,Level 2: Underbukser,Level 2: Kellergewölbe,,Nivelo 2: Subteraj vojoj,Nivel 2: Salones subterráneos,,Taso 2: Maanalaiset käytävät,NIVEAU 2: Souterrains,2. Pálya: Alagutak,Livello 2: Sotterranei,Level 2: 地下堂,레벨 2: 지하수로,Level 2: Onderhallen,Nivå 2: Underhaller,Level 2: Podziemia,Fase 2: Subterrâneo,Nível 2: Subterrâneo,Nivelul 2: Pasaje subterane,Уровень №2: Подземные ходы,Level 2: Подземни ходници,Nivå 2: Underhallar,Seviye 2: Tulumlar +Level 3: The Gantlet,HUSTR_3,“a form of punishment in which a person is forced to run between two lines of men facing each other and armed with clubs or whips to beat the victim”,,,Level 3: Trest,Level 3: Spidsrod,Level 3: Spießrutenlauf,,Nivelo 3: La vergokuro,Nivel 3: Carrera de baquetas,,Taso 3: Kujanjuoksu,NIVEAU 3: Parcours du Combatant,3. Pálya: Vesszőfutás,Livello 3: Le Forche,Level 3: ガントレット,레벨 3: 건틀릿,Level 3: De gantlet,Nivå 3: Hansken,Level 3: Praszczęta,Fase 3: A Punição,Nível 3: A Punição,Nivelul 3: Stroiul,Уровень №3: Сквозь строй,Level 3: Казна,Nivå 3: Utmaningen,Seviye 3: Zorluk +Level 4: The Focus,HUSTR_4,,,,Level 4: Ohnisko,Level 4: Fokus,Level 4: Der Fokus,,Nivelo 4: La fokuso,Nivel 4: El foco,,Taso 4: Polttopiste,NIVEAU 4: Le Focus,4. Pálya: A középpont,Livello 4: L'Epicentro,Level 4: フォーカス,레벨 4: 초점,Level 4: De focus,Nivå 4: Fokus,Level 4: Skupisko,Fase 4: O Foco,Nível 4: O Foco,Nivelul 4: Focarul,Уровень №4: Средоточие,Level 4: Средиште,Nivå 4: Fokus,Seviye 4: Odaklanma +Level 5: The Waste Tunnels,HUSTR_5,,,,Level 5: Odpadní tunely,Level 5: Affaldstunnellerne,Level 5: Die Abfall-Tunnel,Επίπεδο 5: Οι Σήραγγες Αποβλήτων,Nivelo 5: La rubtuneloj,Nivel 5: Los túneles de desechos,,Taso 5: Jätetunnelit,NIVEAU 5: Les Egouts,5. Pálya: Szennyvízalagutak,Livello 5: I Tunnel dei Rifiuti,Level 5: 廃棄トンネル,레벨 5: 하수도,Level 5: De afvaltunnels,Nivå 5: Avfallstunnelene,Level 5: Kanały,Fase 5: Os Túneis de Dejetos,Nível 5: Os Túneis de Dejetos,Nivelul 5: Tuneluri de deșeuri,Уровень №5: Сточные туннели,Level 5: Отпадни тунели,Nivå 5: Avfallstunnlarna,Seviye 5: Atık Tünelleri +Level 6: The Crusher,HUSTR_6,,,,Level 6: Drtička,Level 6: Knuseren,Level 6: Die Presse,Επίπεδο 6: Ο Συνθλιπτής,Nivelo 6: La dispistilo,Nivel 6: La trituradora,,Taso 6: Murskaaja,NIVEAU 6: Le Broyeur,6. Pálya: A zúzda,Livello 6: La Pressa,Level 6: クラッシャー,레벨 6: 분쇄기,Level 6: De maalmachine,Nivå 6: Knuseren,Level 6: Zgniatarka,Fase 6: O Esmagador,Nível 6: O Esmagador,Nivelul 6: Zdrobitorul,Уровень №6: Давилка,Level 6: Разбијач,Nivå 6: krossen,Seviye 6: Kırıcı +Level 7: Dead Simple,HUSTR_7,,,,Level 7: Smrtelně prosté,Level 7: Død simpel,Level 7: Tödlich einfach,Επίπεδο 7: Πανεύκολο,Nivelo 7: Morte simpla,Nivel 7: Simplemente muerto,,Taso 7: Kuolettavan yksinkertainen,NIVEAU 7: Mortellement Simple,7. Pálya: Halálegyszerű,Livello 7: Morte Pura,Level 7: 死ぬほど単純,레벨 7: 죽여주는 단순함,Level 7: Dodelijk eenvoudig,Nivå 7: Helt enkelt,Level 7: Śmiertelnie Proste,Fase 7: Mortalmente Simples,Nível 7: Simplesmente Mortal,Nivelul 7: Mortal de simplu,Уровень №7: Смертельно просто,Level 7: Смртно једноставно,Nivå 7: Död enkel,Seviye 7: Ölü Basit +Level 8: Tricks and Traps,HUSTR_8,,,,Level 8: Lesti a léčky,Level 8: Tricks og fælder,Level 8: Tricks und Fallen,Επίπεδο 8: Κόλπα και Παγίδες,Nivelo 8: Trompoj kaj embuskoj,Nivel 8: Trucos y trampas,,Taso 8: Metkuja ja pauloja,NIVEAU 8: Ruses et Pièges,8. Pálya: Cselek és csapdák,Livello 8: Trucchi e Trappole,Level 8: 悪戯と罠,레벨 8: 속임수와 함정들,Level 8: Trucs en vallen,Nivå 8: Triks og feller,Level 8: Sztuczki i Pułapki,Fase 8: Truques e Armadilhas,Nível 8: Truques e Armadilhas,Nivelul 9: Surprize și capcane,Уровень №8: Уловки и ловушки,Level 8: Замке и смицалице,Nivå 8: Tricks och fällor,Seviye 8: Hileler ve Tuzaklar +Level 9: The Pit,HUSTR_9,,,,Level 9: Jáma,Level 9: Gruben,Level 9: Die Grube,Επίπεδο 9: Λάκκος,Nivelo 9: La fosaĵo,Nivel 9: El pozo,,Taso 9: Monttu,NIVEAU 9: La Fosse,9. Pálya: A gödör,Livello 9: Il Pozzo,Level 9: 大穴,레벨 9: 구덩이,Level 9: De groeve,Nivå 9: Gropen,Level 9: Jama,Fase 9: O Fosso,Nível 9: O Fosso,Nivelul 9: Groapa,Уровень №9: Яма,Level 9: Јама,Nivå 9: Grottan,Seviye 9: Çukur +Level 10: Refueling Base,HUSTR_10,,,,Level 10: Tankovací základna,Level 10: Tankstation,Level 10: Treibstoffbunker,Επίπεδο 10: Βάση Ανεφοδιασμού,Nivelo 10: Refuelbazo,Nivel 10: Base de reabastecimiento,,Taso 10: Tankkausasema,NIVEAU 10: Base de Ravitaillement,10. Pálya: Tankolóállomás,Livello 10: Base di Rifornimento,Level 10: 補給基地,레벨 10: 연료 충전소,Level 10: Tankstation,Nivå 10: Påfyllingsbasen,Level 10: Stacja Tankowania,Fase 10: Base de Reabastecimento,Nível 10: Base de Reabastecimento,Nivelul 10: Baza de alimentare,Уровень №10: Заправочная база,Level 10: Бензинска база,Nivå 10: Tankningsbasen,Seviye 10: Yakıt İkmal Üssü Level 11: 'O' of Destruction!,HUSTR_11,"Alternative title: -Circle of Death ",,,Level 11: Kruh smrti,Level 11: 'O' der Zerstörung!,Επίπεδο 11: Ο Κύκλος της Καταστροφής,Nivelo 11: 'O' de Detruo,Nivel 11: 'O' de Destrucción,,Taso 11: Hävityksen 'O',NIVEAU 11: Le Cercle de la Mort!,A pusztulás köre,Level 11: Il Cerchio della Morte,Level 11: 破滅の'O'!,레벨 11: 파괴의 고리,Level 11: 'O' van vernietiging!,Level 11: Krąg Śmierci,Nível 11: 'O' da Destruição!,,Nivelul 11: Cercul distrugerii,Level 11: Круг разрушения!,Level 11: Круг уништења -Level 12: The Factory,HUSTR_12,,,,Level 12: Továrna,Level 12: Die Fabrik,Επίπεδο 12: To Εργοστάσιο,Nivelo 12: La Fabrikejo,Nivel 12: La Fábrica,,Taso 12: Tehdas,NIVEAU 12: L'Usine,A gyár,Level 12: La Fabbrica,Level 12: 工場,레벨 12: 공장,Level 12: De fabriek,Level 12: Fabryka,Nível 12: A Fábrica,,Nivelul 12: Fabrica,Level 12: Фабрика,Level 12: Фабрика -Level 13: Downtown,HUSTR_13,,,,Level 13: Centrum,Level 13: Stadtzentrum,Επίπεδο 13: Κέντρο,Nivelo 13: La Urbocentro,Nivel 13: Centro de la Ciudad,,Taso 13: Keskikaupunki,NIVEAU 13: Centre-Ville,Belváros,Level 13: Periferia,Level 13: 市内,레벨 13: 번화가,Level 13: De binnenstad,Level 13: Śródmieście,Nível 13: Centro Urbano,,Nivelul 13: Centru urban,Level 13: Деловой район,Level 13: Центар града -Level 14: The Inmost Dens,HUSTR_14,,,,Level 14: Nejhlubší doupata,Level 14: Die innersten Bauten,Επίπεδο 14: Οι Ενδότερες Φωλιές,Nivelo 14: La Internaj Kavernoj,Nivel 14: Los Antros más Recónditos,,Taso 14: Sisimmät piilot,NIVEAU 14: Les Antres Profondes,A legmélyebb rejtekek,Level 14: Gli Antri Profondi,Level 14: 最深巣窟,레벨 14: 깊숙한 동굴들,Level 14: De binnenste gebouwen,Level 14: Najgłębsze Nory,Nível 14: Os Antros Profundos,,Nivelul 14: Cele mai intime bârloguri,Level 14: Глубочайшие логовища,Level 14: Најдубље јазбине -Level 15: Industrial Zone,HUSTR_15,,,,Level 15: Průmyslová zóna,Level 15: Industriegebiet,Επίπεδο 15: Βιομηχανική Ζώνη,Nivelo 15: Industria Zono,Nivel 15: Zona Industrial,,Taso 15: Teollisuusalue,NIVEAU 15: Zone Industrielle,Ipari zóna,Level 15: Zona Industriale,Level 15: 工業地帯,레벨 15: 공업 지대,Level 15: Industriegebied,Level 15: Strefa Przemysłowa,Nível 15: Zona Industrial,,Nivelul 15: Zona industrială,Level 15: Промышленная зона,Level 15: Индустријска зона -Level 16: Suburbs,HUSTR_16,,,,Level 16: Předměstí,Level 16: Vororte,Επίπεδο 16: Προάστια,Nivelo 16: Antaŭurboj,Nivel 16: Suburbios,,Taso 16: Lähiö,NIVEAU 16: Banlieue,Külváros,Level 16: Sobborghi,Level 16: 郊外,레벨 16: 교외,Level 16: Buitenwijken,Level 16: Przedmieścia,Nível 16: Subúrbios,,Nivelul 16: Suburbii,Level 16: Пригород,Level 16: Предграђе -Level 17: Tenements,HUSTR_17,,,,Level 17: Sídliště,Level 17: Wohnbezirk,Επίπεδο 17: Καταλύματα,Nivelo 17: Loĝejoj,Nivel 17: Viviendas,,Taso 17: Vuokratalot,NIVEAU 17: Immeubles,Bérházak,Level 17: Possedimenti,Level 17: 安アパート,레벨 17: 공동주택,Level 17: Huurwoningen,Level 17: Kamienice,Nível 17: Habitações,,Nivelul 17: Proprietăți,Level 17: Владения,Level 17: Станови -Level 18: The Courtyard,HUSTR_18,,,,Level 18: Nádvoří,Level 18: Der Innenhof,Επίπεδο 18: Η Αυλή,Nivelo 18: La Korto,Nivel 18: El Patio,,Taso 18: Esipiha,NIVEAU 18: La Cour,Az udvar,Level 18: Il cortile,Level 18: 中庭,레벨 18: 중정,Level 18: De binnenplaats,Level 18: Dziedziniec,Nível 18: O Pátio,,Nivelul 18: Curtea,Level 18: Внутренний двор,Level 18: Двориште -Level 19: The Citadel,HUSTR_19,,,,Level 19: Citadela,Level 19: Die Zizadelle,Επίπεδο 19: Το Κάστρο,Nivelo 19: La Citadelo,Nivel 19: La Ciudadela,,Taso 19: Linnoitus,NIVEAU 19: La Citadelle,Fellegvár,Level 19: La cittadella,Level 19: 要塞,레벨 19: 성채,Level 19: De citadel,Level 19: Cytadela,Nível 19: A Cidadela,,Nivelul 19: Cetatea,Level 19: Цитадель,Level 19: Цитадела -Level 20: Gotcha!,HUSTR_20,,,,Level 20: Mám tě!,Level 20: Erwischt!,Επίπεδο 20: Σ'έπιασα!,Nivelo 20: Trovis Vin!,Nivel 20: ¡Te Pillé!,,Taso 20: Sainpas sinut!,NIVEAU 20: Je t'ai eu!,Megvagy!,Level 20: Preso!,Level 20: 捉らえた!,레벨 20: 잡았다!,Level 20: Ik heb je!,Level 20: Mam Cię!,Nível 20: Te Peguei!,Nível 20: Apanhei-te!,Nivelul 20: Te-am prins!,Level 20: Попался!,Level 20: Имају те! -Level 21: Nirvana,HUSTR_21,,,,Level 21: Nirvána,,Επίπεδο 21: Νιρβάνα,Nivelo 21: Nirvano,Nivel 21: Nirvana,,,NIVEAU 21: Nirvana,Nirvána,Level 21: Nirvana,Level 21: 涅槃,레벨 21: 열반,,Level 21: Nirvana,Nível 21: Nirvana,,Nivelul 21: Nirvana,Level 21: Нирвана,Level 21: Нирвана -Level 22: The Catacombs,HUSTR_22,,,,Level 22: Katakomby,Level 22: Katakomben,Επίπεδο 22: Οι Κατακόμβες,Nivelo 22: Katakombo,Nivel 22: Las Catacumbas,,Taso 22: Katakombit,NIVEAU 22: Les Catacombes,A katakombák,Level 22: Le Catacombe,Level 22: 地下悪霊墓所,레벨 22: 지하 묘지,Level 22: De catacomben,Level 22: Katakumby,Nível 22: As Catacumbas,Nível 22: Os Calabouços,Nivelul 22: Catacombe,Level 22: Катакомбы,Level 22: Катакомбе -Level 23: Barrels O' Fun,HUSTR_23,,,,Level 23: Barely srandy,Level 23: Lustige Fässer,,Nivelo 23: Bareloj de Amuzo,Nivel 23: Barriles de Diversión,,Taso 23: Huvitynnyrit,NIVEAU 23: Une Tonne-eau de plaisir,Mókás hordók,Level 23: Barili da Sballo,Level 23: 戯れのバレル,레벨 23: 신나는 폭발통들,Level 23: Grappige vaten,Level 23: Beczki Śmiechu,Nível 23: Barris de Diversão,,Nivelul 23: Butoaiele veseliei,Level 23: Бочки веселья,Level 23: Бачве забаве -Level 24: The Chasm,HUSTR_24,,,,Level 24: Rokle,Level 24: Die Kluft,Επίπεδο 24: Το Χάσμα,Nivelo 24: La Fendego,Nivel 24: El Desfiladero,,Taso 24: Rotko,NIVEAU 24: Le Gouffre,A szakadék,Level 24: L'Abisso,Level 24: 裂け目,레벨 24: 협곡,Level 24: De afgrond,Level 24: Przepaść,Nível 24: O Abismo,,Nivelul 24: Hăul,Level 24: Пропасть,Level 24: Провалија -Level 25: Bloodfalls,HUSTR_25,,,,Level 25: Krvopády,Level 25: Blutfälle,Επίπεδο 25: Καταρράκτες Αίματος,Nivelo 25: Sangfaloj,Nivel 25: Cataratas de Sangre,,Taso 25: Veriputoukset,NIVEAU 25: Chutes de Sang,Véresések,Level 25: Cascate di Sangue,Level 25: 血の滝,레벨 25: 혈폭포,Level 25: Bloeddruppels,Level 25: Wodospad Krwi,Nível 25: Cataratas de Sangue,Nível 25: Cascatas de Sangue,Nivelul 25: Cascade de sânge,Level 25: Кровопады,Level 25: Крвопади -Level 26: The Abandoned Mines,HUSTR_26,,,,Level 26: Opuštěné doly,Level 26: Die aufgegebene Mine,Επίπεδο 26: Τα Εγκαταλελειμμένα Ορυχεία,Nivelo 26: Forlasitaj Minoj,Nivel 26: Las Minas Abandonadas,,Taso 26: Hylätyt kaivokset,NIVEAU 26: Les Mines Abandonnées,Az elhagyatott bányák,Level 26: Le Miniere Abbandonate,Level 26: 廃鉱山,레벨 26: 버려진 광산,Level 26: De verlaten mijnen,Level 26: Opuszczone Kopalnie,Nível 26: As Minas Abandonadas,,Nivelul 26: Minele părăsite,Level 26: Заброшенные шахты,Level 26: Напуштени рудници -Level 27: Monster Condo,HUSTR_27,,,,Level 27: Netvoří dům,Level 27: Monsterbehausung,,Nivelo 27: Monstro-domo,Nivel 27: Condominio de Monstruos,,Taso 27: Hirviöhuoneisto,NIVEAU 27: Monstrueuse Résidence,A szörnyek háza,Level 27: Casa dei Mostri,Level 27: モンスターマンション,레벨 27: 괴물 콘도,,Level 27: Mieszkanie Potworów,Nível 27: Mansão dos Monstros,Nível 27: Condomínio Monstruoso,Nivelul 27: Casa monștrilor,Level 27: Жилище монстров,Level 27: Боравишта монструма -Level 28: The Spirit World,HUSTR_28,,,,Level 28: Onen svět,Level 28: Die Geisterwelt,Επίπεδο 28: Ο Κόσμος των Πνευμάτων,Nivelo 28: Animo-mondo,Nivel 28: El Mundo Espiritual,,Taso 28: Henkimaailma,NIVEAU 28: Le Monde Spirituel,A lelkek világa,Level 28: Il Mondo dello Spirito,Level 28: 悪霊の世界,레벨 28: 영령의 세계,Level 28: De geestenwereld,Level 28: Świat Dusz,Nível 28: O Mundo Espiritual,,Nivelul 28: Lumea duhurilor,Level 28: Мир духов,Level 28: Духовни свет -Level 29: The Living End,HUSTR_29,,,,Level 29: Živoucí konec,Level 29: Das lebende Ende,Επίπεδο 29: Το Ζωντανό Τέλος,Nivelo 29: La Viva Fino,Nivel 29: El Final Viviente,,Taso 29: Elävä loppu,NIVEAU 29: La Limite,Az élő Végzet,Level 29: La Fine Imminente,Level 29: 極限の存在,레벨 29: 최종점,Level 29: Het levende einde,Level 29: Żywy Koniec,Nível 29: O Fim Iminente,,Nivelul 29: Sfârșitul întregii vieți,Level 29: Конец всего живого,Level 29: Крај живота -Level 30: Icon of Sin,HUSTR_30,,,,Level 30: Ikona hříchu,Level 30: Symbol der Sünde,Επίπεδο 30: Σύμβολο της Αμαρτίας,Nivelo 30: Ikono de Peko,Nivel 30: Icono del Pecado,Nivel 30: Ícono del Pecado,Taso 30: Synnin ikoni,NIVEAU 30: L'Icône du Péché,A megtestesült bűn,Level 30: Icona del Peccato,Level 30: 罪の象徴,레벨 30: 죄악의 상징,Level 30: Pictogram van de zonde,Level 30: Ikona Grzechu,Nível 30: Ícone do Pecado,,Nivelul 30: Icoana păcatelor,Level 30: Икона греха,Level 30: Икона греха -Level 31: Wolfenstein,HUSTR_31,,,,,,,Nivelo 31: Wolfenstein,Nivel 31: Wolfenstein,,,,Wolfenstein,Level 31: Wolfenstein,Level 31: ウルフェンシュタイン,레벨 31: 울펜슈타인,,Level 31: Wolfenstein,Nível 31: Wolfenstein,,Nivelul 31: Wolfenstein,Level 31: Вольфенштайн,Level 31: Волфенштајн -Level 32: Grosse,HUSTR_32,,,,,,,Nivelo 32: Grosse,Nivel 32: Grosse,,,,Grosse,Level 32: Grosse,Level 32: グローシュ,레벨 32: 그로세,,Level 32: Grosse,Nível 32: Grosse,,Nivelul 32: Grosse,Level 32: Гросс,Level 32: Гроссе -Level 31: IDKFA,HUSTR_31B,,,,,,,Nivelo 31: IDKFA,Nivel 31: IDKFA,,,NIVEAU 31: IDKFQ,IDKFA,Level 31: IDKFA,Level 31: IDKFA,레벨 31: IDKFA,,Level 31: IDKFA,Nível 31: IDKFA,,Nivelul 31: IDKFA,Level 31: IDKFA, -Level 32: Keen,HUSTR_32B,,,,,,,Nivelo 32: Keen,Nivel 32: Keen,,,,Keen,Level 32: Keen,Level 32: キーン,레벨 32: 킨,,Level 32: Keen,Nível 32: Keen,,Nivelul 32: Keen,Level 32: Кин,Level 32: Кин -Level 33: Betray,HUSTR_33,,,,Level 33: Zraď,Level 33: Verrat,,Nivelo 33: Perfidi,Nivel 33: Traición,,Taso 33: Petä,NIVEAU 33: Trahison,Árulás,Level 33: Tradimento ,Level 33: 裏切り,레벨 33: 배반,Level 33: Verraad,Level 33: Zdrada,Nível 33: Traição,,Nivelul 33: Trădare,Level 33: Предательство,Level 33: Издаја -,,No Rest For The Living,,,,,,,,,,,,,,,,,,,,, -Level 1: The Earth Base,NHUSTR_1,,,,Level 1: Pozemská základna,Level 1: Die Erd-Basis,,Nivelo 1: La Tera Bazo,Nivel 1: La Base Terrestre,,Taso 1: Maatukikohta,NIVEAU 1: La Base Terrienne,A földi bázis,Level 1: La Base Terrestre ,Level 1: 地球基地,레벨 1: 지구 기지,Level 1: De basis van de aarde,Level 1: Ziemska Baza,Nível 1: A Base Terrestre,,Nivelul 1: Baza terestră,Level 1: База на земле,Level 1: Земаљска база -Level 2: The Pain Labs,NHUSTR_2,,,,Level 2: Laboratoře bolesti,Level 2: Die Folterlabore,,Nivelo 2: La Doloro-Laboratorio,Nivel 2: Los Laboratorios del Dolor,,Taso 2: Tuskalaboratoriot,NIVEAU 2: Les Laboratoires de la Douleur,A kínok laboratóriuma,Level 2: I Laboratori del Dolore,Level 2: 生物工学実験室,레벨 2: 고통의 연구소,Level 2: De pijnlaboratoria,Level 2: Laboratoria Bólu,Nível 2: Os Laboratórios da Dor,,Nivelul 2: Laboratoarele durerii,Level 2: Лаборатории боли,Level 2: Лабораторије патње -Level 3: Canyon of The Dead,NHUSTR_3,,,,Level 3: Kaňon mrtvých,Level 3: Schlucht der Toten,,Nivelo 3: Kanjono de La Mortitaj,Nivel 3: Cañón de los Muertos,,Taso 3: Kalmankanjoni,NIVEAU 3: Canyon des Morts,A holtak szurdoka,Level 3: Il Canyon dei Morti,Level 3: 死の渓谷,레벨 3: 죽음의 계곡,Level 3: Canyon van de doden,Level 3: Kanion Umarłych,Nível 3: Desfiladeiro dos Mortos,,Nivelul 3: Canionul morților,Level 3: Каньон мертвецов,Level 3: Кањон мртваца -Level 4: Hell Mountain,NHUSTR_4,,,,Level 4: Pekelná hora,Level 4: Höllenberg,,Nivelo 4: Monto Infero,Nivel 4: Montaña Infernal,,Taso 4: Hornanvuori,NIVEAU 4: Montagne Infernale,Pokolhegy,Level 4: Promontorio Infernale ,Level 4: 地獄山脈,레벨 4: 지옥의 산,Level 4: Helleberg,Level 4: Piekielna Góra,Nível 4: Montanha Infernal,,Nivelul 4: Muntele infernal,Level 4: Адская гора,Level 4: Планина пакла -Level 5: Vivisection,NHUSTR_5,,,,Level 5: Vivisekce,Level 5: Vivisektion,,Nivelo 5: Vivisekcio,Nivel 5: Vivisección,,Taso 5: Vivisektio,NIVEAU 5: Vivisection,Élveboncolás,Level 5: Vivisezione ,Level 5: 生体解剖,레벨 5: 생체 해부,Level 5: Vivisectie,Level 5: Wiwisekcja,Nível 5: Vivissecção,,Nivelul 5: Vivisecție,Level 5: Вивисекция,Level 5: Вивисекција -Level 6: Inferno of Blood,NHUSTR_6,,,,Level 6: Krvavé inferno,Level 6: Blutiges Inferno,,Nivelo 6: Brulego de Sango,Nivel 6: Hoguera de Sangre,,Taso 6: Veri-inferno,NIVEAU 6: Enfer Sanglant,Véres alvilág,Level 6: Inferno di Sangue ,Level 6: 血のインフェルノ,레벨 6: 연옥의 피,Level 6: Bloederige inferno,Level 6: Piekło Krwi,Nível 6: Inferno de Sangue,,Nivelul 6: Infern sângeriu,Level 6: Кровавая преисподняя,Level 6: Ватре крви -Level 7: Baron's Banquet,NHUSTR_7,,,,Level 7: Baronní hostina,Level 7: Das Bankett des Barons,,Nivelo 7: Festeno de Barono,Nivel 7: Banquete del Barón,,Taso 7: Paronin pidot,NIVEAU 7: Banquet du Baron,A báró bankettje,Level 7: Il Banchetto del Barone ,Level 7: バロンの晩餐,레벨 7: 남작의 연회,Level 7: Baron's banket,Level 7: Bankiet Barona,Nível 7: O Banquete do Barão,,Nivelul 7: Banchetul baronilor,Level 7: Банкет у барона,Level 7: Баронова Гозба -Level 8: Tomb of Malevolence,NHUSTR_8,,,,Level 8: Hrobka zlovolnosti,Level 8: Feindselige Gruft,,Nivelo 8: Tombo de Malbonvolo,Nivel 8: Tumba de Malevolencia,,Taso 8: Pahantahdon hauta,NIVEAU 8: Tombe Maléfique,A Rosszindulat sírja,Level 8: Tomba della Malevolenza,Level 8: 悪意の墓,레벨 8: 증오의 무덤,Level 8: Graf van kwaadwilligheid,Level 8: Grobowiec Zła,Nível 8: Tumba da Malevolência,Nível 8: Túmulo da Malevolência,Nivelul 8: Mormântul răutății,Level 8: Гробница злобы,Level 8: Гроб злобе -Level 9: March of The Demons,NHUSTR_9,,,,Level 9: Pochod démonů,Level 9: Marsch der Dämonen,,Nivelo 9: Marŝo de La Demonoj,Nivel 9: Marcha de los Demonios,,Taso 9: Demonien marssi,NIVEAU 9: Marche des Démons,A démonok menete,Level 9: La Marcia dei Demoni ,Level 9: デーモンの行進,레벨 9: 악마들의 행진,Level 9: Maart van de demonen,Level 9: Marsz Demonów,Nível 9: Marcha dos Demônios,,Nivelul 9: Marșul demonilor,Level 9: Шествие демонов,Level 9: Марш демона -,,Plutonia,,,,,,,,,,,,,,,,,,,,, -Level 1: Congo,PHUSTR_1,,,,Level 1: Kongo,Level 1: Kongo,,Nivelo 1: Kongo,Nivel 1: Congo,,Taso 1: Kongo,NIVEAU 1: Congo,Kongó,Level 1: Congo,Level 1: コンゴ川,레벨 1: 콩고,Level 1: Kongo,Level 1: Kongo,Nível 1: Congo,,Nivelul 1: Congo,Level 1: Конго,Level 1: Конго -Level 2: Well of Souls,PHUSTR_2,,,,Level 2: Studna duší,Level 2: Seelenbrunnen,,Nivelo 2: Puto de Animoj,Nivel 2: Pozo de las Almas,,Taso 2: Sielujen lähde,NIVEAU 2: Puits des Ames,A lelkek kútja,Level 2: Pozzo delle Anime,Level 2: 魂の井戸,레벨 2: 영혼의 우물,Level 2: Bron van zielen,Level 2: Studnia Dusz,Nível 2: Poço das Almas,Nível 2: Poço de Almas,Nivelul 2: Fântâna sufletelor,Level 2: Колодец душ,Level 2: Бунар душа -Level 3: Aztec,PHUSTR_3,,,,Level 3: Azték,Level 3: Aztekisch,,Nivelo 3: Azteko,Nivel 3: Azteca,,Taso 3: Asteekki,NIVEAU 3: Aztèque,Azték,Level 3: Aztec,Level 3: アステカ,레벨 3: 아즈텍,Level 3: Azteken,Level 3: Aztek,Nível 3: Asteca,,Nivelul 3: Aztec,Level 3: Ацтек,Level 3: Астек -Level 4: Caged,PHUSTR_4,,,,Level 4: V kleci,Level 4: Eingesperrt,,Nivelo 4: Enkaĝigita,Nivel 4: Enjaulado,,Taso 4: Häkissä,NIVEAU 4: Enfermé,Ketrecbe zárva,Level 4: Ingabbiato,Level 4: 檻の中,레벨 4: 갇히다,Level 4: Gekooid,Level 4: W Klatce,Nível 4: Enjaulado,,Nivelul 4: Încarcerat,Level 4: Запертый в клетке,Level 4: Заробљен -Level 5: Ghost Town,PHUSTR_5,,,,Level 5: Město duchů,Level 5: Geisterstadt,,Nivelo 5: Fantomurbeto,Nivel 5: Pueblo Fantasma,,Taso 5: Aavekaupunki,NIVEAU 5: Ville Fantôme,Szellemváros,Level 5: Città Fantasma,Level 5: ゴーストタウン,레벨 5: 유령 도시,Level 5: Spookstad,Level 5: Miasto Duchów,Nível 5: Cidade Fantasma,,Nivelul 5: Orașul fantomă,Level 5: Город-призрак,Level 5: Град духова -Level 6: Baron's Lair,PHUSTR_6,,,,Level 6: Baronovo doupě,Level 6: Lager des Barons,,Nivelo 6: Nestego de Barono,Nivel 6: Guarida del Barón,,Taso 6: Paronin luola,NIVEAU 6: Repaire du Baron,A báró rejteke,Level 6: Tana del Barone,Level 6: バロンの隠れ家,레벨 6: 남작의 은신처,Level 6: Baron's kamp,Level 6: Legowisko Barona,Nível 6: Covil do Barão,,Nivelul 6: Claustrul Baronului,Level 6: Обитель барона,Level 6: Баронова јазбина -Level 7: Caughtyard,PHUSTR_7,,,,Level 7: Karcer,Level 7: Gehege,,Nivelo 7: Kaptkorto,Nivel 7: Campo de Concentración,,Taso 7: Posenpiha,NIVEAU 7: Pris de court,A foglyok udvara,Level 7: Cortile della Prigione,Level 7: 囚われの庭,레벨 7: 포획마당,Level 7: Omheining,Level 7: Dziedziniec Więzienny,Nível 7: Campo de Concentração,,Nivelul 7: Capcana curții,Level 7: Двор-ловушка,Level 7: Замчиште -Level 8: Realm,PHUSTR_8,,,,Level 8: Říše,Level 8: Bereich,,Nivelo 8: Regno,Nivel 8: Reino,,Taso 8: Valtapiiri,NIVEAU 8: Royaume,Birodalom,Level 8: Regno,Level 8: 領地,레벨 8: 왕국,Level 8: Rijk,Level 8: Królestwo,Nível 8: Reino,,Nivelul 8: Tărâm,Level 8: Царство,Level 8: Царство -Level 9: Abattoire,PHUSTR_9,,,,Level 9: Jatka,Level 9: Schlachthaus,,Nivelo 9: Buĉejo,Nivel 9: Matadero,,Taso 9: Teurastamo,NIVEAU 9: Abattoir,Vágóhíd,Level 9: Mattatoio,Level 9: 屠殺場,레벨 9: 도축장,Level 9: Abattoir,Level 9: Rzeźnia,Nível 9: Matadouro,,Nivelul 9: Abator,Level 9: Аббатство,Level 9: Кланица -Level 10: Onslaught,PHUSTR_10,,,,Level 10: Nájezd,Level 10: Angriff,,Nivelo 10: Buĉado,Nivel 10: Arremetida,,Taso 10: Ryntäys,NIVEAU 10: Assaut,Támadás,Level 10: Assalto,Level 10: 猛襲,레벨 10: 맹공격,Level 10: Aanval,Level 10: Szturm,Nível 10: Investida,,Nivelul 10: Năvala,Level 10: Натиск,Level 10: Јуриш -Level 11: Hunted,PHUSTR_11,,,,Level 11: Loven,Level 11: Gehetzt,,Nivelo 11: Ĉasata,Nivel 11: Cazado,,Taso 11: Metsästetty,NIVEAU 11: Traque,Üldözve,Level 11: Braccato,Level 11: 逃走,레벨 11: 사냥당함,Level 11: Gejaagd,Level 11: Nawiedzony,Nível 11: Caçado,,Nivelul 11: Vânătoarea,Level 11: Преследуемый,Level 11: Уловљен -Level 12: Speed,PHUSTR_12,,,,Level 12: Rychlost,Level 12: Tempo,,Nivelo 12: Rapido,Nivel 12: Velocidad,,Taso 12: Vauhti,NIVEAU 12: Vitesse,Iram,Level 12: Velocità,Level 12: スピード,레벨 12: 스피드,Level 12: Haast,Level 12: Pęd,Nível 12: Velocidade,,Nivelul 12: Viteză,Level 12: Скорость,Level 12: Брзина -Level 13: The Crypt,PHUSTR_13,,,,Level 13: Krypta,Level 13: Die Gruft,,Nivelo 13: Tombokelo,Nivel 13: La Cripta,,Taso 13: Krypta,NIVEAU 13: La Crypte,A kripta,Level 13: La Cripta,Level 13: 地下聖堂,레벨 13: 봉안당,Level 13: De crypte,Level 13: Krypta,Nível 13: A Cripta,,Nivelul 13: Cripta,Level 13: Склеп,Level 13: Гробница -Level 14: Genesis,PHUSTR_14,,,,,,,Nivelo 14: Genezo,Nivel 14: Génesis,,Taso 14: Luominen,NIVEAU 14: Genèse,Teremtés,Level 14: Genesi,Level 14: 創世記,레벨 14: 창세기,,Level 14: Geneza,Nível 14: Gênese,,Nivelul 14: Geneza,Level 14: Зарождение,Level 14: Постанак -Level 15: The Twilight,PHUSTR_15,,,,Level 15: Soumrak,Level 15: Zwielicht,,Nivelo 15: La Krepusko,Nivel 15: El Ocaso,,Taso 15: Hämärä,NIVEAU 15: Le Crépuscule,Alkonyat,Level 15: Il crepuscolo,Level 15: 黄昏,레벨 15: 황혼,Level 15: De schemering,Level 15: Zmierzch,Nível 15: O Crepúsculo,,Nivelul 15: Amurgul,Level 15: Сумерки,Level 15: Сумрак -Level 16: The Omen,PHUSTR_16,,,,Level 16: Znamení,Level 16: Das Omen,,Nivelo 16: La Aŭguro,Nivel 16: El Presagio,,Taso 16: Enne,NIVEAU 16: Le Présage,Ómen,Level 16: Il presagio,Level 16: 予兆,레벨 16: 징조,Level 16: De omen,Level 16: Omen,Nível 16: O Presságio,,Nivelul 16: Prevestirea,Level 16: Предзнаменование,Level 16: Знамење -Level 17: Compound,PHUSTR_17,,,,Level 17: Ústav,Level 17: Anlage,,Nivelo 17: Konstruaĵaro,Nivel 17: Complejo,,Taso 17: Laitos,NIVEAU 17: Installation,Létesítmény,Level 17: Recinto,Level 17: 調合,레벨 17: 복합체,Level 17: Faciliteit,Level 17: Mieszanka,Nível 17: O Complexo,,Nivelul 17: Complexul,Level 17: Компаунд,Level 17: Једињење -Level 18: Neurosphere,PHUSTR_18,,,,Level 18: Neurosféra,Level 18: Neurosphäre,,Nivelo 18: Neŭrosfero,Nivel 18: Neuroesfera,,Taso 18: Neurosfääri,NIVEAU 18: Neurosphère,Neuroszféra,Level 18: Neurosfera,Level 18: ニューロスフィア,레벨 18: 뉴로스피어,Level 18: Neurosferen,Level 18: Neurosfera,Nível 18: Neurosfera,,Nivelul 18: Neurosferă,Level 18: Нейросфера,Level 18: Неуросфера -Level 19: NME,PHUSTR_19,"“NME” read out loud means “enemy”, so translators should consider the translation of “enemy” into their language.",,,Level 19: Nepřítel,,,Nivelo 19: Mal-BN,Nivel 19: NME,,Taso 19: VHLLNN,NIVEAU 19: NMI,L. N. SÉG,Level 19: NMIC,Level 19: 野郎,레벨 19: NOM,,Level 19: WRG,Nível 19: N-MIGO,,Nivelul 19: INMIC,Level 19: В.Р.А.Г.,Level 19: Н.Е.П.Р. -Level 20: The Death Domain,PHUSTR_20,,,,Level 20: Panství smrti,Level 20: Die Todeszone,,Nivelo 20: La Regno de Morto,Nivel 20: El Dominio Mortal,,Taso 20: Kuoleman piiri,NIVEAU 20: Le Domaine de la Mort,A holtak birtoka,Level 20: Il Dominio della Morte,Level 20: 死の領域,레벨 20: 죽음의 영역,Level 20: Het domein van de dood,Level 20: Domena Śmierci,Nível 20: O Domínio da Morte,,Nivelul 20: Domeniul morții,Level 20: Обитель смерти,Level 20: Подручије смрти -Level 21: Slayer,PHUSTR_21,,,,Level 21: Zabiják,Level 21: Töter,,Nivelo 21: Mortigisto,Nivel 21: Asesino,,Taso 21: Tappaja,NIVEAU 21: Pourfendeur,Halálosztó,Level 21: Uccisore,Level 21: スレイヤー,레벨 21: 슬레이어,Level 21: Doder,Level 21: Pogromca,Nível 21: Matador,,Nivelul 21: Ucigător,Level 21: Убийца,Level 21: Убица -Level 22: Impossible Mission,PHUSTR_22,,,,Level 22: Nemožná mise,Level 22: Unmögliche Mission,,Nivelo 22: Malebla Misio,Nivel 22: Misión Imposible,,Taso 22: Mahdoton tehtävä,NIVEAU 22: Mission Impossible,Lehetetlen küldetés,Level 22: Missione Impossibile,Level 22: 不可能な任務,레벨 22: 임파서블 미션,Level 22: Onmogelijke missie,Level 22: Niemożliwa Misja,Nível 22: Missão Impossível,,Nivelul 22: Misiune imposibilă,Level 22: Невыполнимое задание,Level 22: Немогућа мисија -Level 23: Tombstone,PHUSTR_23,,,,Level 23: Náhrobek,Level 23: Grabstein,,Nivelo 23: Tombŝtono,Nivel 23: Lápida,,Taso 23: Hautakivi,NIVEAU 23: Pierre Tombale,Sírkő,Level 23: Pietra Tombale,Level 23: 墓石,레벨 23: 묘비,Level 23: Grafsteen,Level 23: Nagrobek,Nível 23: Lápide,,Nivelul 23: Piatra de mormânt,Level 23: Надгробие,Level 23: Надгробни споменик -Level 24: The Final Frontier,PHUSTR_24,,,,Level 24: Poslední hranice,Level 24: Die letzte Grenze,,Nivelo 24: La Fina Limo,Nivel 24: La Frontera Final,Nivel 24: La Última Frontera,Taso 24: Viimeinen rajamaa,NIVEAU 24: La Frontière Finale,A végső határ,Level 24: La Frontiera Finale,Level 24: 最後のフロンティア,레벨 24: 최후의 개척지,Level 24: De eindgrens,Level 24: Ostateczna Granica,Nível 24: A Fronteira Final,,Nivelul 24: Ultima frontieră,Level 24: Последний рубеж,Level 24: Коначна граница -Level 25: The Temple of Darkness,PHUSTR_25,,,,Level 25: Chrám temna,Level 25: Der Tempel der Dunkelheit,,Nivelo 25: La Idolejo de Mallumo,Nivel 25: El Templo de la Oscuridad,,Taso 25: Pimeyden temppeli,NIVEAU 25: Le Temple des Ténèbres,A sötétség temploma,Level 25: Il Tempio dell'Oscurità,Level 25: 暗黒の神殿,레벨 25: 어둠의 신전,Level 25: De tempel van de duisternis,Level 25: Świątynia Mroku,Nível 25: O Templo da Escuridão,,Nivelul 25: Templul tenebros,Level 25: Храм тьмы,Level 25: Храм таме -Level 26: Bunker,PHUSTR_26,,,,Level 26: Bunkr,Level 26: Bunker,,Nivelo 26: Bunkro,Nivel 26: Búnker,,Taso 26: Bunkkeri,NIVEAU 26: Bunker,Bunker,Level 26: Bunker,Level 26: バンカー,레벨 26: 방공호,,Level 26: Bunkier,Nível 26: Casamata,Nível 26: Bunker,Nivelul 26: Buncăr,Level 26: Бункер,Level 26: Бункер -Level 27: Anti-christ,PHUSTR_27,,,,Level 27: Antikrist,Level 27: Antichrist,,Nivelo 27: Antikristo,Nivel 27: Anti-cristo,,Taso 27: Antikristus,NIVEAU 27: Anti-Christ,Antikrisztus,Level 27: Anticristo,Level 27: アンチキリスト,레벨 27: 적그리스도,Level 27: Antichrist,Level 27: Antychryst,Nível 27: Anticristo,,Nivelul 27: Antihrist,Level 27: Антихрист,Level 27: Антихрист -Level 28: The Sewers,PHUSTR_28,,,,Level 28: Kanály,Level 28: Kanäle,,Nivelo 28: La Kanalo,Nivel 28: Las Alcantarillas,,Taso 28: Viemärit,NIVEAU 28: Les Egouts,A csatornák,Level 28: Le Fogne,Level 28: 下水道,레벨 28: 하수구,Level 28: De rioleringen,Level 28: Ścieki,Nível 28: Os Esgotos,,Nivelul 28: Canalizarea,Level 28: Канализация,Level 28: Канализација -Level 29: Odyssey of Noises,PHUSTR_29,,,,Level 29: Odysea křiku,Level 29: Odyssee der Geräusche,,Nivelo 29: Vojaĝo de Sonoj,Nivel 29: Odisea de Ruidos,,Taso 29: Äänten harharetki,NIVEAU 29: Odysée de Bruits,A zajok bolyongása,Level 29: Odissea di Rumori,Level 29: オデッセイのノイズ,레벨 29: 속삭임의 여정,Level 29: Odyssee van geluiden,Level 29: Odyseja Wrzawy,Nível 29: Odisséia de Ruidos,,Nivelul 29: Odiseea zgomotelor,Level 29: Одиссея шумов,Level 29: Одисеја шумова -Level 30: The Gateway of Hell,PHUSTR_30,,,,Level 30: Brána pekla,Level 30: Tor zur Hölle,,Nivelo 30: La Pordego de Inferno,Nivel 30: La Puerta del Infierno,,Taso 30: Helvetin porttikäytävä,NIVEAU 30: La Porte des Enfers,Átjáró a pokolba,Level 30: La Porta dell'Inferno,Level 30: 地獄の関門,레벨 30: 지옥의 차원문,Level 30: De poort van de hel,Level 30: Brama Piekieł,Nível 30: O Portão do Inferno,,Nivelul 30: Poarta spre infern,Level 30: Врата ада,Level 30: Пролаз пакла -Level 31: Cyberden,PHUSTR_31,,,,Level 31: Kyberdoupě,Level 31: Cyberbau,,Nivelo 31: Cibornesto,Nivel 31: Ciber-guarida,,Taso 31: Kyberpesä,NIVEAU 31: Cyber-Antre,Kiberodú,Level 31: Cybergabbia,Level 31: サイバーの巣,레벨 31: 사이버소굴,,Level 31: Cybernora,Nível 31: Ciberantro,,Nivelul 31: Cibervizuină,Level 31: Киберлогово,Level 31: Сајбер-јазбина -Level 32: Go 2 It,PHUSTR_32,,,,Level 32: Jdi do toho,,,Nivelo 32: 2m Muĝo!,Nivel 32: ¡Ve A x Ello!,Nivel 32: ¡Ve Adelante!,Taso 32: Iske kii,NIVEAU 32: Go 2 It,Menj oda!,Level 32: Dacci Dentro,Level 32: 逝ってこい,레벨 32: 함 해 봐,Level 32: Ga ervoor,Level 32: Do Dzieła,Nível 32: Vai Fundo,Nível 32: Siga em Frente,Nivelul 32: Du-te la ei,Level 32: Иди к сему,Level 32: Иди ка њему -,,TNT: Evilution,,,,,,,,,,,,,,,,,,,,, -Level 1: System Control,THUSTR_1,,,,Level 1: Administrace,Level 1: Systemkontrolle,,Nivelo 1: Sistemregilo,Nivel 1: Control del Sistema,,Taso 1: Järjestelmäohjaamo,NIVEAU 1: Système de Contrôle,Rendszervezérlés,Level 1: Controllo del Sistema,Level 1: 制御システム,레벨 1: 시스템 제어시설,Level 1: Systeemcontrole,Level 1: Kontrola Systemu,Nível 1: Controle do Sistema,Nível 1: Controlo de Sistema,Nivelul 1: Control sisteme,Level 1: Центр управления системой,Level 1: Контролна система -Level 2: Human BBQ,THUSTR_2,,,,Level 2: Člověčí grilovačka,Level 2: Menschliches Barbecue,,Nivelo 2: Homo-Kradrostado,Nivel 2: Barbacoa Humana,,Taso 2: Ihmisgrilli,NIVEAU 2: Barbecue Humain,Emberi barbecue,Level 2: Barbecue Umano,Level 2: 人肉晩餐会,레벨 2: 인간 바비큐,Level 2: Menselijke BBQ,Level 2: Ludzki Grill,Nível 2: Churrasco Humano,,Nivelul 2: Oameni la grătar,Level 2: Барбекю из человечины,Level 2: Људски роштиљ -Level 3: Power Control,THUSTR_3,,,,Level 3: Napájecí vedení,Level 3: Energiekontrolle,,Nivelo 3: Energiregilo,Nivel 3: Control de Energía,,Taso 3: Voimalan ohjaamo,NIVEAU 3: Contrôle Energétique,Energiavezérlés,Level 3: Centrale Energetica,Level 3: 制御室,레벨 3: 전력 통제소,Level 3: Machtscontrole,Level 3: Kontrola Zasilania,Nível 3: Controle de Energia,Nível 3: Controlo Energético,Nivelul 3: Uzina,Level 3: Центр управления питанием,Level 3: Контролна моћ -Level 4: Wormhole,THUSTR_4,,,,Level 4: Červí díra,Level 4: Wurmloch,,Nivelo 4: Vermtruo,Nivel 4: Agujero de Gusano,,Taso 4: Madonreikä,NIVEAU 4: Trou de Ver,Féreglyuk,Level 4: Wormhole,Level 4: 虫喰い穴,레벨 4: 웜홀,Level 4: Wormgat,Level 4: Tunel,Nível 4: Buraco de Minhoca,,Nivelul 4: Gaura de vierme,Level 4: Червоточина,Level 4: Црвоточина -Level 5: Hanger,THUSTR_5,,,,Level 5: Hangár,Level 5: Hangar,,Nivelo 5: Hangaro,Nivel 5: Hangar,Nivel 5: Colgador,Taso 5: Lentoalushalli,NIVEAU 5: Hangar,Horog,Level 5: Gancio,Level 5: 格納庫,레벨 5: 격납고,Level 5: Hangar,Level 5: Haczyk,Nível 5: Hangar,,Nivelul 5: Hangar,Level 5: Виселица,Level 5: Вешалица -Level 6: Open Season,THUSTR_6,,,,Level 6: Lovecká sezóna,Level 6: Jagdsaison,,Nivelo 6: Ĉasosezono,Nivel 6: Temporada Abierta,,Taso 6: Avoin sesonki,NIVEAU 6: La Chasse Est Ouverte,Vadászszezon,Level 6: Stagione Aperta,Level 6: 狩猟解禁,레벨 6: 사냥철,Level 6: Open seizoen,Level 6: Otwarty Sezon,Nível 6: Temporada Aberta,Nível 6: Época Aberta,Nivelul 6: Sezon deschis,Level 6: Открытый сезон,Level 6: Отворена сезона -Level 7: Prison,THUSTR_7,,,,Level 7: Vězení,Level 7: Gefängnis,,Nivelo 7: Malliberejo,Nivel 7: Prisión,,Taso 7: Vankila,NIVEAU 7: Prison,Börtön,Level 7: Prigione,Level 7: 監獄,레벨 7: 감옥,Level 7: Gevangenis,Level 7: Więzienie,Nível 7: Prisão,,Nivelul 7: Închisoare,Level 7: Тюрьма,Level 7: Затвор -Level 8: Metal,THUSTR_8,,,,Level 8: Kov,Level 8: Metall,,Nivelo 8: Metalo,Nivel 8: Metal,,Taso 8: Metalli,NIVEAU 8: Métal,Fém,Level 8: Metallo,Level 8: メタル,레벨 8: 강철,Level 8: Metaal,Level 8: Metal,Nível 8: Metal,,Nivelul 8: Metal,Level 8: Металл,Level 8: Метал -Level 9: Stronghold,THUSTR_9,,,,Level 9: Pevnost,Level 9: Festung,,Nivelo 9: Fuorto,Nivel 9: Fortaleza,,Taso 9: Linnake,NIVEAU 9: Forteresse,Erőd,Level 9: Fortezza,Level 9: 牙城,레벨 9: 요새,Level 9: Vesting,Level 9: Warownia,Nível 9: Fortaleza,,Nivelul 9: Bastion,Level 9: Крепость,Level 9: Упориште -Level 10: Redemption,THUSTR_10,,,,Level 10: Vykoupení,Level 10: Erlösung,,Nivelo 10: Elaĉeto,Nivel 10: Redención,,Taso 10: Lunastus,NIVEAU 10: Rédemption,Megváltás,Level 10: Redenzione,Level 10: 償還,레벨 10: 구원,Level 10: Aflossing,Level 10: Odkupienie,Nível 10: Redenção,,Nivelul 10: Răscumpărare,Level 10: Искупление,Level 10: Искупљење -Level 11: Storage Facility,THUSTR_11,,,,Level 11: Skladiště,Level 11: Lagerstätte,,Nivelo 11: Konservejo,Nivel 11: Complejo de Almacenes,,Taso 11: Varastolaitos,NIVEAU 11: Complexe de Stockage,Raktárépület,Level 11: Impianto di Stoccaggio,Level 11: 貯蔵施設,레벨 11: 저장소,Level 11: Opslagfaciliteit,Level 11: Magazyn,Nível 11: Instalação de Armazenamento,,Nivelul 11: Stația de depozitare,Level 11: Склад,Level 11: Складиште -Level 12: Crater,THUSTR_12,,,,Level 12: Kráter,Level 12: Krater,,Nivelo 12: Kratero,Nivel 12: Cráter,,Taso 12: Kraateri,NIVEAU 12: Cratère,Kráter,Level 12: Cratere,Level 12: 火口,레벨 12: 분화구,Level 12: Krater,Level 12: Krater,Nível 12: Cratera,,Nivelul 12: Crater,Level 12: Кратер,Level 12: Кратер -Level 13: Nukage Processing,THUSTR_13,,,,Level 13: Jaderné zpracování,Level 13: Nuklearverarbeitung,,Nivelo 13: Nukleaĵo-traktejo,Nivel 13: Procesamiento Nuclear,,Taso 13: Ydinjätekäsittely,NIVEAU 13: Traitement Nucléaire,Atomhulladék-feldolgozó,Level 13: Trattamento Nucleare,Level 13: 核廃棄物加工所,레벨 13: 폐기물 처리소,Level 13: Nucleaire verwerking,Level 13: Przetwórstwo Jądrowe,Nível 13: Processamento Nuclear,,Nivelul 13: Prelucrarea deșeurilor nucleare,Level 13: Переработка ядерных отходов,0 -Level 14: Steel Works,THUSTR_14,,,,Level 14: Ocelárna,Level 14: Stahlwerk,,Nivelo 14: Ŝtalejo,Nivel 14: Siderúrgica,,Taso 14: Terästehdas,NIVEAU 14: Aciérie,Acélművek,Level 14: Acciaieria,Level 14: 製鉄所,레벨 14: 제강소,Level 14: Staalfabrieken,Level 14: Huta,Nível 14: Siderúrgica,,Nivelul 14: Oțelărie,Level 14: Сталелитейный завод,Level 14: Челичана -Level 15: Dead Zone,THUSTR_15,,,,Level 15: Mrtvá zóna,Level 15: Tote Zone,,Nivelo 15: Mortzono,Nivel 15: Zona Muerta,,Taso 15: Kuollut alue,NIVEAU 15: Zone Morte,A holtak zónája,Level 15: Zona Morta,Level 15: 危険地帯,레벨 15: 사각지대,Level 15: Dode zone,Level 15: Martwa Strefa,Nível 15: Zona Morta,,Nivelul 15: Zonă moartă,Level 15: Мёртвая зона,Level 15: Зона смрти -Level 16: Deepest Reaches,THUSTR_16,,,,Level 16: Nejhlubší sluje,Level 16: Tiefe,,Nivelo 16: Plejsubejo,Nivel 16: Recodos profundos,,Taso 16: Syvyydet,NIVEAU 16: Profondeurs,Mélység,Level 16: Profondità,Level 16: 最深部,레벨 16: 깊숙한 강,Level 16: Diepste reiken,Level 16: Głębiny,Nível 16: Profundezas,,Nivelul 16: În adâncuri,Level 16: Глубочайшие достижения,Level 16: Најдубља дубина -Level 17: Processing Area,THUSTR_17,,,,Level 17: Kombinát,Level 17: Verarbeitungsbereich,,Nivelo 17: Traktregiono,Nivel 17: Área de Procesamiento,,Taso 17: Käsittelyalue,NIVEAU 17: Zone de Traitement,Feldolgozó,Level 17: Area di Elaborazione,Level 17: 処理地帯,레벨 17: 처리 구역,Level 17: Verwerkingsgebied,Level 17: Strefa Przerobowa,Nível 17: Área de Processamento,,Nivelul 17: Aria de procesare,Level 17: Зона обработки,Level 17: Подручје обраде -Level 18: Mill,THUSTR_18,,,,Level 18: Mlýn,Level 18: Mühle,,Nivelo 18: Muelejo,Nivel 18: Molino,,Taso 18: Mylly,NIVEAU 18: Fonderie,Malom,Level 18: Fonderia,Level 18: 製粉所,레벨 18: 제분소,Level 18: Molen,Level 18: Młyn,Nível 18: Moinho,,Nivelul 18: Moara,Level 18: Завод,Level 18: Млин -Level 19: Shipping/respawning,THUSTR_19,,,,Level 19: Přeprava,Level 19: Versandlager,,Nivelo 19: Ekspedo/Revivado,Nivel 19: Enviando/Reapareciendo,,Taso 19: Huolinta/Ylösnostatus,NIVEAU 19: Envoi/Réapparition,Szállítás/újraéledés,Level 19: Consegna/Respawn,Level 19: 出荷と再生成,레벨 19: 운송/리스폰 장소,Level 19: Verzendingscentrum,Level 19: Wysyłka/Reprodukcja,Nível 19: Expedição/reaparecimento,,Nivelul 19: Livrare/reapariție,Level 19: Погрузка/отправка,Level 19: Отпремање/оживљавање -Level 20: Central Processing,THUSTR_20,,,,Level 20: Centrální zpracování,Level 20: Zentralverarbeitung,,Nivelo 20: Centra Traktejo,Nivel 20: Procesamiento Central,,Taso 20: Käsittelykeskus,NIVEAU 20: Organisme Central,Központi feldolgozó,Level 20: Centrale di Elaborazione,Level 20: 中央処理所,레벨 20: 중앙 처리소,Level 20: Centrale verwerking,Level 20: Centralny Proces,Nível 20: Processamento Central,,Nivelul 20: Prelucrare centrală,Level 20: Центральный пункт обработки,Level 20: Централна обрада -Level 21: Administration Center,THUSTR_21,,,,Level 21: Administrativní centrum,Level 21: Verwaltungszentrum,,Nivelo 21: Administracicentro,Nivel 21: Centro de Administración,,Taso 21: Keskushallinto,NIVEAU 21: Centre Administratif,Adminisztrációs központ,Level 21: Centro Amministrativo,Level 21: 行政センター,레벨 21: 관리 센터,Level 21: Administratief centrum,Level 21: Centrum Administracyjne,Nível 21: Centro de Administração,,Nivelul 21: Centru administrativ,Level 21: Административный центр,Level 21: Административни центар -Level 22: Habitat,THUSTR_22,,,,,,,Nivelo 22: Habitato,Nivel 22: Hábitat,,Taso 22: Asuinpaikka,NIVEAU 22: Habitat,Élőhely,Level 22: Habitat,Level 22: 生息地,레벨 22: 서식지,,Level 22: Siedlisko,Nível 22: Habitat,,Nivelul 22: Habitat,Level 22: Обиталище,Level 22: Станиште -Level 23: Lunar Mining Project,THUSTR_23,,,,Level 23: Lunární těžební projekt,Level 23: Mondbergbauprojekt,,Nivelo 23: Luna Mino-projekto,Nivel 23: Proyecto de Minería Lunar,,Taso 23: Kuukaivosprojekti,NIVEAU 23: Projet Minier Lunaire,Holdbánya-projekt,Level 23: Progetto Minerario Lunare,Level 23: 月面探鉱計画,레벨 23: 월석 채광 계획,Level 23: Maanmijnbouw project,Level 23: Projekt Księżycowe Górnictwo,Nível 23: Projeto de Mineração Lunar,Nível 23: Projeto de Escavação Lunar,Nivelul 23: Proiect minier satelitar,Level 23: Лунный горный проект,Level 23: Пројекат лунарног рударства -Level 24: Quarry,THUSTR_24,,,,Level 24: Lom,Level 24: Steinbruch,,Nivelo 24: Ŝtonejo,Nivel 24: Cantera,,Taso 24: Louhos,NIVEAU 24: Carrière,Kőbánya,Level 24: Caccia,Level 24: 採石場,레벨 24: 채석장,Level 24: Steengroeve,Level 24: Kamieniołom,Nível 24: Pedreira,,Nivelul 24: Carieră,Level 24: Карьер,Level 24: Каменолом -Level 25: Baron's Den,THUSTR_25,,,,Level 25: Baronovo doupě,Level 25: Der Bau des Barons,,Nivelo 25: Nestego de Barono,Nivel 25: Guarida del Barón,,Taso 25: Paronin pesä,NIVEAU 25: l'Antre des Barons,A báró odúja,Level 25: Antro del Barone,Level 25: バロンの巣窟,레벨 25: 남작의 소굴,Level 25: Het baron's gebouw,Level 25: Legowisko Barona,Nível 25: Covil do Barão,,Nivelul 25: Cuibul Baronului,Level 25: Логово барона,Level 25: Баронова јазбина -Level 26: Ballistyx,THUSTR_26,,,,Level 26: Balistika,,,Nivelo 26: Balistikso,Nivel 26: Balístige,,Taso 26: Ballistyks,NIVEAU 26: Ballistyx,Ballisztüx,Level 26: Ballistige,Level 26: バリステュクス,레벨 26: 탄도스틱스,,Level 26: Balistyka,Nível 26: Ballistige,,Nivelul 26: Ballistyx,Level 26: Баллистикс,Level 26: Билистичкикс -Level 27: Mount Pain,THUSTR_27,,,,Level 27: Hora bolesti,Level 27: Berg des Schmerzes,,Nivelo 27: Monto Doloro,Nivel 27: Monte Dolor,,Taso 27: Tuskavuori,NIVEAU 27: Mont Souffrance,Szenvedés-hegy,Level 27: Monte del Dolore,Level 27: 苦しみの山,레벨 27: 등신같은 등산,Level 27: Pijn in de bergen,Level 27: Góra Bólu,Nível 27: Monte Dor,,Nivelul 27: Muntele Durerii,Level 27: Гора боль,Level 27: Планина боли -Level 28: Heck,THUSTR_28,,,,Level 28: Sakra,Level 28: Zum Teufel,,Nivelo 28: Fek',Nivel 28: Diablos,,Taso 28: Hemmetti,NIVEAU 28: Que Diable?,Rosseb,Level 28: Grata,Level 28: 苛立ち,레벨 28: 젠장함,,Level 28: Do Diabła,Nível 28: Capeta,Nível 28: Inferno,Nivelul 28: Naiba,Level 28: Чертовщина,Level 28: Пакао -Level 29: River Styx,THUSTR_29,,,,Level 29: Řeka Styx,Level 29: Fluss Styx,,Nivelo 29: Rivero Stikso,Nivel 29: Río Estige,,Taso 29: Styksjoki,NIVEAU 29: Fleuve Styx,A Sztüx folyó,Level 29: Fiume Stige,Level 29: 三途の川,레벨 29: 스틱스 강,Level 29: Rivier Styx,Level 29: Styks,Nível 29: Rio Estige,,Nivelul 29: Râul Styx,Level 29: Река стикс,Level 29: Река Стикс -Level 30: Last Call,THUSTR_30,,,,Level 30: Poslední mise,Level 30: Letzter Aufruf,,Nivelo 30: Fina Voko,Nivel 30: Última Llamada,,Taso 30: Viimeinen koollehuuto,NIVEAU 30: Dernier Appel,Utolsó lehetőség,Level 30: Ultima Chiamata,Level 30: 最終指令,레벨 30: 최후의 호출,Level 30: Laatste oproep,Level 30: Ostatni Zew,Nível 30: Última Chamada,,Nivelul 30: Ultimul apel,Level 30: Последний вызов,Level 30: Последњи позив -Level 31: Pharaoh,THUSTR_31,,,,Level 31: Faraón,Level 31: Pharao,,Nivelo 31: Faraono,Nivel 31: Faraón,,Taso 31: Faarao,NIVEAU 31: Pharaon,Fáraó,Level 31: Faraone,Level 31: ファラオ,레벨 31: 파라오,Level 31: Farao,Level 31: Faraon,Nível 31: Faraó,,Nivelul 31: Faraon,Level 31: Фараон,Level 31: Фараон -Level 32: Caribbean,THUSTR_32,,,,Level 32: Karibik,Level 32: Karibik,,Nivelo 32: Karibio,Nivel 32: Caribeño,,Taso 32: Karibia,NIVEAU 32: Caraïbes,Karib-térség,Level 32: Caraibi,Level 32: カリビアン,레벨 32: 카리브해,Level 32: Caribisch,Level 32: Karaiby,Nível 32: Caribe,Nível 32: Caraíbas,Nivelul 32: Caraibe,Level 32: Карибы,Level 32: Кариби -,,Heretic,,,,,,,,,,,,,,,,,,,,, -The Docks,HHUSTR_E1M1,,,,Přístav,Die Docks,,La Havenoj,Los Muelles,,Satamat,Les Docks,A Kikötő,Il Molo,埠頭,항구,De dokken,Doki,As Docas,,Docul,Доки,Лука -The Dungeons,HHUSTR_E1M2,,,,Žaláře,Die Kerker,,La Malliberejoj,Los Calabozos,,Tyrmät,Le Donjon,A Kazamaták,I Sotterranei,地下牢,지하감옥,De kerkers,Lochy,As Masmorras,,Temnița,Темницы,Тамнице -The Gatehouse,HHUSTR_E1M3,,,,Vrátnice,Das Pförtnerhaus,,La Pordegejo,El Cuerpo de Guardia,,Porttitalo,Le Corps de Garde,A Kapuház,L'ingresso,門塔,문루,Het poortgebouw,Stróżówka,O Portão de Entrada,,Casa portarului,Привратницкая,Стражарница -The Guard Tower,HHUSTR_E1M4,,,,Strážní věž,Der Wachturm,,La Gardturo,La Torre de Guardia,,Vartiotorni,La Tour de Garde,Az Őrtorony,La Torre di Guardia,監視塔,보초 누대,De wachttoren,Wieża Strażnicza,A Torre de Guarda,,Turnul de veghe,Сторожевая башня,Извидница -The Citadel,HHUSTR_E1M5,,,,Citadela,Die Festung,,La Citadelo,La Ciudadela,,Linnake,La Citadelle,A Citadella,La Cittadella,要塞,거점,De citadel,Cytadela,A Cidadela,,Cetatea,Цитадель,Цитадела -The Cathedral,HHUSTR_E1M6,,,,Katedrála,Die Kathedrale,,La Katedralo,La Catedral,,Katedraali,La Cathédrale,A Katedrális,La Cattedrale,大聖堂,대성당,De kathedraal,Katedra,A Catedral,,Catedrala,Кафедральный собор,Катедрала -The Crypts,HHUSTR_E1M7,,,,Krypty,Die Krypten,,La Kriptoj,Las Criptas,,Kryptat,La Crypte,A Kripták,Le Cripte,地下聖堂,지하 묘실,De grafkelders,Krypty,As Criptas,,Criptele,Склепы,Крипта -Hell's Maw,HHUSTR_E1M8,,,,Chřtán pekla,Der Höllenschlund,,La Faŭko de Infero,Fauces del Infierno,,Helvetin kita,La Geule de l'Enfer,A Pokol Szája,La Bocca dell'Inferno,地獄の肚,지옥의 목구멍,De helmouth,Paszcza Piekieł,A Boca do Inferno,,Gura iadului,Адская утроба,Паклено ждрело -The Graveyard,HHUSTR_E1M9,,,,Hřbitov,Der Friedhof,,La Tombejo,El Cementerio,,Hautausmaa,Le Cimetière,A Temető,Il Cimitero,墓場,공동묘지,De begraafplaats,Cmentarz,O Cemitério,,Cimitirul,Кладбище,Гробље -The Crater,HHUSTR_E2M1,,,,Kráter,Der Krater,,La Kratero,El Cráter,,Kraateri,Le Cratère,A Kráter,Il Cratere,噴火口,깊은 혈,De krater,Krater,A Cratera,,Craterul,Кратер,Кратер -The Lava Pits,HHUSTR_E2M2,,,,Lávové jámy,Die Lavagruben,,La Lafo-fosaĵo,Las Canteras de Lava,,Laavamontut,Les Puits de Lave,A Lávagödrök,I Pozzi della Lava,溶岩の竪穴,용암 구덩이,De lavaputten,Szyb Lawy,Os Fossos de Lava,,Gropile cu lavă,Лавовые очаги,Понор лаве -The River of Fire,HHUSTR_E2M3,,,,Ohnivá řeka,Der Feuerfluss,,La Rivero de Fajro,El Río de Fuego,,Tulijoki,La Rivière de Feu,A Tűz Folyama,Il Fiume di Fuoco,火の河,화염의 강,De rivier van vuur,Rzeka Ognia,O Rio de Fogo,,Râul de foc,Река огня,Река од ватре -The Ice Grotto,HHUSTR_E2M4,,,,Ledová grotta,Die Eisgrotte,,La Glacigroto,La Gruta de Hielo,,Jääluola,La Grotte de Glace,A Jégbarlang,La Grotta del Ghiaccio,氷の洞窟,얼음 동굴,De ijsgrot,Lodowa Grota,A Gruta de Gelo,,Grota de gheață,Ледяной грот,Ледена пећина -The Catacombs,HHUSTR_E2M5,,,,Katakomby,Die Katakomben,,La Katakombo,Las Catacumbas,,Katakombit,Les Catacombes,A Katakombák,Le Catacombe,地下墓所,태고의 무덤,De catacomben,Katakumby,As Catacumbas,Os Túmulos,Catacombele,Катакомбы,Катакомбе -The Labyrinth,HHUSTR_E2M6,,,,Labyrint,Das Labyrinth,,La Labirinto,El Laberinto,,Labyrintti,Le Labyrinthe,A Labirintus,Il Labirinto,迷宮,미궁,Het labyrint,Labirynt,O Labirinto,,Labirintul,Лабиринт,Лавиринт -The Great Hall,HHUSTR_E2M7,,,,Velký sál,Die große Halle,,La Granda Halo,El Gran Salón,,Suuri halli,Le Grand Hall,A Nagy Folyosó,La Grande Sala,大公会堂,대회관,De grote zaal,Wielki Hol,O Grande Salão,,Sala cea mare,Большой зал,Велика дворана -The Portals of Chaos,HHUSTR_E2M8,,,,Portály chaosu,Das Portal des Chaos,,La Portaloj de Ĥaoso,Los Portales del Caos,,Kaaoksen portaalit,Le Portail du Chaos,A Káosz Portáljai,I Portali del Caos,混沌への門,혼돈의 차원문,De portalen van chaos,Portale Chaosu,Os Portais do Caos,,Portalurile haosului,Порталы хаоса,Портали хаоса -The Glacier,HHUSTR_E2M9,,,,Ledovec,Der Gletscher,,La Glaciejo,El Glaciar,,Jäätikkö,Le Glacier,A Gleccser,Il Ghiacciaio,氷河,빙하 구역,De gletsjer,Lodowiec,A Geleira,O Glaciar,Ghețarul,Ледник,Глечер -The Storehouse,HHUSTR_E3M1,,,,Skladiště,Die Lagerhalle,,La Stokejo,El Almacén,,Varasto,L'Entrepôt,A Raktár,Il Magazzino,倉庫,저장고,Het pakhuis,Magazyn,O Armazém,,Depozitul,Кладовая,Складиште -The Cesspool,HHUSTR_E3M2,,,,Žumpa,Die Latrine,,La Kloako,El Pozo,,Likakaivo,Le Bourbier,A Pöcegödör,Il Pozzo Nero,汚水層,불결한 장소,De zinkput,Szambo,A Fossa,,Haznaua,Сточный колодец,Септичка јама -The Confluence,HHUSTR_E3M3,,,,Soutok,Die Vereinigung,,La Kunfluiĝo,La Confluencia,,Yhtymäkohta,La Confluence,A Kereszteződés,La Confluenza,合流点,합류점,De samenvloeiing,Spływ,A Confluência,,Confluența,Слияние,Ушће -The Azure Fortress,HHUSTR_E3M4,,,,Azurová pevnost,Die himmelblaue Festung,,La Lazurfortikaĵo,La Fortaleza de Azur,,Sininen linnoitus,La Fortresse d'Azur,Az Azúr Erőd,La Fortezza Azzurra,紺碧の要塞,청천의 요새,De azuurblauwe vesting,Lazurowa Forteca,A Fortaleza Azul,,Fortăreața de azur,Лазурная крепость,Азурна дврђава -The Ophidian Lair,HHUSTR_E3M5,,,,Hadí doupě,Das Schlangennest,,La Nestego de Ophidia,La Guarida Ofídica,,Käärmeiden pesä,Le Repaire des Ophidiens,Az Opfidiánok Fészke,L'antro degli Ophidian,オフィディアンの塒,오피디안의 소굴,Het slangennest,Gniazdo Węży,A Cova dos Ofídios,,Cuibul ofidienilor,Логово офидианов,Змијска јазбина -The Halls of Fear,HHUSTR_E3M6,,,,Chodby strachu,Die Hallen der Angst,,La Koridoroj de Timo,Los Salones del Miedo,,Pelon salit,Les Couloirs de la Peur,A Félelem Folyosói,Le Sale della Paura,恐怖の館,공포의 회관,De zalen van angst,Korytarze Strachu,Os Salões do Medo,,Sălile groazei,Залы страха,Дворана страха -The Chasm,HHUSTR_E3M7,,,,Propast,Der Abgrund,,La Fendego,El Abismo,,Rotko,Le Gouffre,A Szakadék,L'abisso,裂け目,깊은 골,De kloof,Przepaść,O Abismo,,Prăpastia,Пропасть,Понор лаве -D'Sparil's Keep,HHUSTR_E3M8,,,,D'Sparilova pevnost,D'Sparils Außenposten,,Ĉefturo de Desparilo,Guarida de D'Sparil,,D'Sparilin linna,Le Donjon de D'Sparil,D'Sparil Terme,La Dimora di D'sparil,デ’スパリルの間,드'스파릴의 초소,D'Sparil's voorpost,Baszta D'Sparila,Fortaleza de D'Sparil,,Palatul lui D'sparil,Крепость Д'Спарила,Д'Спарилова кула -The Aquifer,HHUSTR_E3M9,,,,Zvodeň,Der Wasserspeicher,,La Akvigilo,El Acuífero,,Akviferi,L'Aquifère,A Víztorony,L'acquedotto,帯水層,대수층,Het water reservoir,Wodociąg,O Aquífero,,Galerii acvifere,Водоносный слой,Водоносник -Catafalque,HHUSTR_E4M1,,,,Katafalk,Katafalk,,Katafalko,Catafalco,,Katafalkki,Le Catafalque,Ravatal,Catafalco,棺台,관대,Catafalk,Katafalk,Catafalco,,Catafalc,Катафалк,Одар -Blockhouse,HHUSTR_E4M2,,,,Tvrzka,Blockhaus,,Blokhaŭso,Fortín,,Linnoitus,Le Fortin,Gerendaház,Blocco di Case,丸太小屋,특화점,Blokhuis,Blokhauz,O Forte,,Fort,Укрытие,Бункер -Ambulatory,HHUSTR_E4M3,,,,Ochoz,Wandelgang,,Ĥorĉirkaŭirejo,Ambulatorio,,Kuorikäytävä,Le Déambulatoire,Kerengő,Ambulatorio,遊歩道,유보장,Kloostergang,Krużganek,Ambulatório,,Clinică,Монастырская галерея,Амбуланта -Sepulcher,HHUSTR_E4M4,,,,Hrobka,Grabstätte,,Tombo,Sepulcro,,Hautakammio,Le Sépulcre,Síremlék,Sepolcro,埋葬所,매장소,Grafsteen,Grób,Sepulcro,,Sepulcru,Гробница,Гробница -Great Stair,HHUSTR_E4M5,,,,Velké schodiště,Große Treppe,,Granda Ŝtupo,Gran Escalera,,Suuret portaat,Le Grand Escalier,Nagy Lépcső,Grande Scala,大階段,특급 계단,Grote trap,Wielka Gwiazda,Grande Escada,,Scara cea mare,Великая лестница,Велики степеник -Halls of the Apostate,HHUSTR_E4M6,,,,Chodby odpadlictví,Halle des Abtrünnigen,,Haloj de la Apostato,Salas de los Apóstatas,,Luopioiden salit,Les Halls de l'Apôtre,A Hitehagyott Átjárója,Sale dell'Apostata,背教者の館,배교자의 회관,Zalen van de afvallige,Korytarze Odszczepieńca,Os Salões dos Apóstatas,,Sălile apostatului,Залы отступников,Дворана апостола -Ramparts of Perdition,HHUSTR_E4M7,,,,Náspy zatracení,Wälle der Verdammnis,,Muregoj de Pereo,Murallas de la Perdición,,Kadotuksen vallit,Les Remparts de la Perdition,A Kárhozat Támasza,Torrioni della Perdizione,破滅の塁壁,파멸의 성벽,Wallen van de verdoemenis,Wał Potępienia,Muralhas da Perdição,,Meterezele pierzaniei,Твердыни погибели,Бедем пропасти -Shattered Bridge,HHUSTR_E4M8,,,,Rozbitý most,Zerstörte Brücke,,Frakasita Ponto,Puente Destrozado,,Särkynyt silta,Le Pont effondré,A Szétesett Híd,Ponte Distrutto,崩落の橋,붕괴된 다리,Verbrijzelde brug,Zniszczony Most,Ponte Despedaçada,,Podul dărâmat,Разрушенный мост,Поломљен мост -Mausoleum,HHUSTR_E4M9,,,,Mauzoleum,,,Maŭzoleo,Mausoleo,,Mausoleumi,Le Mausolée,Mauzóleum,Mausoleo,霊廟,대영묘,,Mauzoleum,Mausoléu,,Mausoleu,Мавзолей,Маузолеј -Ochre Cliffs,HHUSTR_E5M1,,,,Okrové útesy,Ockerfarbene Klippen,,Okro-klifo,Acantilados Ocres,,Okrajyrkänteet,Les Falaises Ochre,Okker Szakadékok,Colline Ocra,黄土絶壁,황토 산맥,Okerkliffen,Ochrowe Klify,Penhascos Ocres,,Stâncile de ocru,Охровые утёсы,Окер брда -Rapids,HHUSTR_E5M2,,,,Peřeje,Stromschnellen,,Rapidfluoj,Rápidos,,Koski,Les Rapides,Zuhatagok,Rapide,奔流,여울,Stroomversnellingen,Katarakty,Corredeiras,,Ape repezi,Стремнина,Брзак -Quay,HHUSTR_E5M3,,,,Nábřeží,Kai,,Kajo,Muelle,,Satamalaituri,Le Quai,Rakpart,Banchina,岸壁,부두,Kade,Wir,Cais,,Chei,Причал,10 -Courtyard,HHUSTR_E5M4,,,,Nádvoří,Schlosshof,,Korto,Patio,,Linnanpiha,La Cour,Pitvar,Cortile,中庭,안마당,Binnenplaats,Dziedziniec,Pátio,,Curte,Внутренний двор,Двориште -Hydratyr,HHUSTR_E5M5,,,,Hydratýr,,,Akvotyr,Hydratyr,,,L'Hydratyr,Hidratáló,Hydratyr,ヒュドラテュール,식수공급처,,Hydratyr,Reservatório,,Hidratir,Гидротир,Канализација -Colonnade,HHUSTR_E5M6,,,,Kolonáda,Kolonnaden,,Kolonaro,Columnata,,Pylväikkö,La Colonnade,Kolonnád,Colonnato,柱廊,열주의 길,Zuilengalerij,Kolumnada,Colunata,,Colonadă,Колоннада,Колонада -Foetid Manse,HHUSTR_E5M7,,,,Smrdutá vila,Stinkendes Pfarrhaus,,Haladza Domego,Mansión Fétida,,Löyhkäävä kartano,Le Presbytère Fétide,Bűzös Parókia,Fetido Castello,悪臭の牧師館,역겨운 목사관,Stinkende pastorie,Cuchnąca Plebania,Mansão Fétida,,Conac Fetid,Зловонный особняк,Фетидна кућа -Field of Judgement,HHUSTR_E5M8,,,,Soudná pole,Richtstätte,,Kampo de Juĝo,Campo de Juicio,,Tuomion kenttä,Les Champs du Jugement,Az Itélet Mezeje,Campo del Giudizio,審判之地,심판의 평야,Plaats van oordeelsvorming,Pole Sądu,Campo de Julgamento,,Câmpul de Judecată,Поле высшего суда,Чистилиште -Skein of D'sparil,HHUSTR_E5M9,,,,Hejno D'Sparilovo,DSparils Bau,,Fadenaro de D'Sparil,Madeja de D'Sparil,,D'Sparilin vyyhti,L'échevaux de D'Sparil,D'Sparil Káosza,Groviglio di D'sparil,デ'スパリルの枷,드'스파릴의 타래,D'Sparil's gebouw,Motek D'Sparila,Meada de D'Sparil,,Jurubița lui D'Sparil,Путаница Д'Спарила,Реке Д'Спарила -,,Strife,,,,,,,,,,,,,,,,,,,,, -AREA 1: Sanctuary,TXT_STRIFE_MAP01,,,,ZÓNA 1: Svatyně,ZONE 1: Heiligtum,,AREO 1: Sanktejo,ÁREA 1: Santuario,,ALUE 1: Turvapaikka,ZONE 1: Sanctuaire,1. Terület: Szentély,AREA 1: Santuario,エリア 1: 聖域,구역 1: 성소,Zone 1: Heiligdom,Strefa 1: Sanktuarium,Área 1: Santuário,,ZONA 1: Sanctuar,МЕСТНОСТЬ 1: Святилище, -AREA 2: Town,TXT_STRIFE_MAP02,,,,ZÓNA 2: Město,ZONE 2: Stadt,,AREO 2: Urbeto,ÁREA 2: Pueblo,,ALUE 2: Kylä,ZONE 2: Ville,2. Terület: Város,AREA 2: Città,"エリア 2: 町 -",구역 2: 마을,Zone 2: Stad,Strefa 2: Miasto,Área 2: Vila,,ZONA 2: Oraș,МЕСТНОСТЬ 2: Город, -AREA 3: Front Base,TXT_STRIFE_MAP03,,,,ZÓNA 3: Základna Fronty,ZONE 3: Basis der Front,,AREO 3: Front-Bazo,ÁREA 3: Base del Frente,,ALUE 3: Rintaman tukikohta,ZONE 3: Base du Front,3. Terület: Elülső bázis,AREA 3: Base del Fronte,エリア 3: フロント基地,구역 3: 프론트 기지,Zone 3: Front basis,Strefa 3: Baza Frontu,Área 3: Base da Frente,,ZONA 3: Baza Frontului,МЕСТНОСТЬ 3: База Сопротивления, -AREA 4: Power Station,TXT_STRIFE_MAP04,,,,ZÓNA 4: Elektrárna,ZONE 4: Kraftwerk,,AREO 4: Elektrocentralo,ÁREA 4: Central Eléctrica,,ALUE 4: Voimalaitos,ZONE 4: Centrale,4. Terület: Erőmű,AREA 4: Centrale Elettrica,エリア 4: 発電所,구역 4: 발전소,Zone 4: Energiecentrale,Strefa 4: Elektrownia,Área 4: Usina de Energia,Área 4: Central Energética,ZONA 4: Centrala,МЕСТНОСТЬ 4: Электростанция, -AREA 5: Prison,TXT_STRIFE_MAP05,,,,ZÓNA 5: Vězení,ZONE 5: Gefängnis,,AREO 5: Malliberejo,ÁREA 5: Prisión,,ALUE 5: Vankila,ZONE 5: Prison,5. Terület: Börtön,AREA 5: Carcere,エリア 5: 刑務所,구역 5: 감옥,Zone 5: Gevangenis,Strefa 5: Więzienie,Área 5: Prisão,,ZONA 5: Închisoare,МЕСТНОСТЬ 5: Тюрьма, -AREA 6: Sewers,TXT_STRIFE_MAP06,,,,ZÓNA 6: Stoky,ZONE 6: Kanalisation,,AREO 6: Kloako,ÁREA 6: Alcantarillas,,ALUE 6: Viemärit,ZONE 6: Egouts,6. Terület: Szennyvízcsatornák,AREA 6: Fogne,エリア 6: 下水道,구역 6: 하수도,Zone 6: Riolering,Strefa 6: Kanały,Área 6: Esgoto,,ZONA 6: Canal,МЕСТНОСТЬ 6: Канализация, -AREA 7: Castle,TXT_STRIFE_MAP07,,,,ZÓNA 7: Hrad,ZONE 7: Burg,,AREO 7: Kastelo,ÁREA 7: Castillo,,ALUE 7: Linna,ZONE 7: Château,7. Terület: Vár,AREA 7: Castello,エリア 7: 城,구역 7: 성,Zone 7: Kasteel,Strefa 7: Zamek,Área 7: Castelo,,ZONA 7: Castel,МЕСТНОСТЬ 7: Замок, -AREA 8: Audience Chamber,TXT_STRIFE_MAP08,,,,ZÓNA 8: Audienční sál,ZONE 8: Audienzsaal,,AREO 8: Aŭdicencejo,ÁREA 8: Cámara de Audiencias,,ALUE 8: Yleisösali,ZONE 8: Chambre d'Audience,8. Terület: Nézőtér,AREA 8: Sala delle Udienze,エリア 8: 観客席,구역 8: 알현실,Zone 8: Auditorium,Strefa 8: Izba Audiencji,Área 8: Câmara de Audiências,,ZONA 8: Camera de audiențe,МЕСТНОСТЬ 8: Приёмная, -AREA 9: Castle: Programmer's Keep,TXT_STRIFE_MAP09,,,,ZÓNA 9: Hrad: Programátorovo doupě,ZONE 9: Burg: Unterkunft des Programmierers,,AREO 9: Kastelo: Fortikaĵo de Programisto,ÁREA 9: Castillo: Guarida del Programador,,ALUE 9: Linna: Ohjelmoijan asema,ZONE 9: Château: Donjon du Programmeur,9. Terület: Vár: Programozó parcellája,AREA 9: Castello: Dimora del Programmatore,エリア 9: 城内:プログラマーの間,구역 9: 성: 프로그래머의 성채,Zone 9: Kasteel: Onderdak van de programmeur,Strefa 9: Zamek: Baszta Programisty,Área 9: Castelo: Torre do Programador,,ZONA 9: Castel: Cetatea programatorului,МЕСТНОСТЬ 9: Замок (Цитадель Программиста), -AREA 10: New Front Base,TXT_STRIFE_MAP10,,,,ZÓNA 10: Nová základna Fronty,ZONE 10: Neue Basis der Front,,AREO 10: Nova Frontbazo,ÁREA 10: Nueva Base del Frente,,ALUE 10: Uusi Rintaman tukikohta,ZONE 10: Nouvelle Base du Front,10. Terület: Új első bázis,AREA 10: Nuova Base del Fronte,エリア 10: 新フロント基地,구역 10: 새 프론트 기지,Zone 10: Nieuwe Front basis,Strefa 10: Nowa Baza Frontu,Área 10: Nova Base da Frente,,ZONA 10: Noua bază a Frontului,МЕСТНОСТЬ 10: Новая база Сопротивления, -AREA 11: Borderlands,TXT_STRIFE_MAP11,,,,ZÓNA 11: Pohraničí,ZONE 11: Grenzgebiete,,AREO 11: Limlando,ÁREA 11: Tierras Fronterizas,,ALUE 11: Rajamaat,ZONE 11: Terres Sauvages,11. Terület: Peremvidék,AREA 11: Lande di Confine,エリア 11: 国境地帯,구역 11: 접경지,Zone 11: Grensgebieden,Strefa 11: Pogranicze,Área 11: Fronteira,,ZONA 11: Frontiere,МЕСТНОСТЬ 11: Пограничье, -AREA 12: The Temple of the Oracle,TXT_STRIFE_MAP12,,,,ZÓNA 12: Věštcův chrám,ZONE 12: Der Tempel des Orakels,,AREO 12: La Templo de La Oraklo,ÁREA 12: El Templo del Oráculo,,ALUE 12: Oraakkelin temppeli,ZONE 12: Temple de l'Oracle,12. Terület: Az Orákulum Temploma,AREA 12: Il Tempio dell'Oracolo,エリア 12: オラクルの神殿,구역 12: 오라클의 신전,Zone 12: De tempel van het Orakel,Strefa 12: Świątynia Wyroczni,Área 12: O Templo do Oráculo,,ZONA 12: Templul Oracolului,МЕСТНОСТЬ 12: Храм Оракула, -AREA 13: Catacombs,TXT_STRIFE_MAP13,,,,ZÓNA 13: Katakomby,ZONE 13: Katakomben,,AREO 13: Katakombo,ÁREA 13: Catacumbas,,ALUE 13: Katakombit,ZONE 13: Catacombes,13. Terület: Katakombák,AREA 13: Catacombe,エリア 13: 地下墓所,구역 13: 고대 묘지,Zone 13: Catacomben,Strefa 13: Katakumby,Área 13: Catacumbas,Área 13: Túmulos,ZONA 13: Catacombe,МЕСТНОСТЬ 13: Катакомбы, -AREA 14: Mines,TXT_STRIFE_MAP14,,,,ZÓNA 14: Doly,ZONE 14: Die Minen,,AREO 14: Minejo,ÁREA 14: Minas,,ALUE 14: Kaivokset,ZONE 14: Mines,14. Terület: Bánya,AREA 14: Miniere,エリア 14: 鉱山,구역 14: 광산,Zone 14: De mijnen,Strefa 14: Kopalnia,Área 14: Minas,,ZONA 14: Mine,МЕСТНОСТЬ 14: Шахты, -AREA 15: Fortress: Administration,TXT_STRIFE_MAP15,,,,ZÓNA 15: Pevnost: Administrace,ZONE 15: Festung: Administration,,AREO 15: Fortreso: Administrejo,ÁREA 15: Fortaleza: Administración,,ALUE 15: Linnoitus: hallinto,ZONE 15: Forteresse: Administration,15. Terület: Erőd: Adminisztráció,AREA 15: Fortezza: Amministrazione,エリア 15: 要塞:管理室,구역 15: 요새: 중앙 관리소,Zone 15: Vesting: Administratieve organisatie,Strefa 15: Forteca: Administracja,Área 15: Fortaleza: Administração,,ZONA 15: Fortăreața: Administrația,МЕСТНОСТЬ 15: Крепость (Администрация), -AREA 16: Fortress: Bishop's Tower,TXT_STRIFE_MAP16,,,,ZÓNA 16: Pevnost: Biskupova věž,ZONE 16: Festung: Bischofsturm,,AREO 16: Fortreso: Turo de Episkopo,ÁREA 16: Fortaleza: Torre del Obispo,,ALUE 16: Linnoitus: Piispan torni,ZONE 16: Forteresse: Tour de l'évèque,16. Terület: Erőd: Püspök tornya,AREA 16: Fortezza: Torre del Vescovo,エリア 16: 要塞:ビショップの塔,구역 16: 요새: 비숍의 탑,Zone 16: Vesting: Bisschopstoren,Strefa 16: Forteca: Wieża Biskupa,Área 16: Fortaleza: Torre do Bispo,,ZONA 16: Fortăreața: Turnul Episcopului,МЕСТНОСТЬ 16: Крепость (Башня Епископа), -AREA 17: Fortress: The Bailey,TXT_STRIFE_MAP17,,,,ZÓNA 17: Pevnost: Předhradí,ZONE 17: Festung: Vorhof,,AREO 17: Fortreso: La Murego,ÁREA 17: Fortaleza: El Patio,,ALUE 17: Linnoitus: ulkomuuri,ZONE 17: Forteresse: Mur d'enceinte,17. Terület: Erőd: Várfal,AREA 17: Fortezza: Bastione,エリア 17: 要塞:ベイリー,구역 17: 요새: 안뜰,Zone 17: Vesting: Voorplein,Strefa 17: Forteca: Mur Obronny,Área 17: Fortaleza: O Pátio,,ZONA 17: Fortăreața: Curte,МЕСТНОСТЬ 17: Крепость (Двор), -AREA 18: Fortress: Stores,TXT_STRIFE_MAP18,,,,ZÓNA 18: Pevnost: Sklady,ZONE 18: Festung: Lager,,AREO 18: Fortreso: Stokejoj,ÁREA 18: Fortaleza: Almacenes,,ALUE 18: Linnoitus: varastot,ZONE 18: Forteresse: Réserves,18. Terület: Erőd: Üzletek,AREA 18: Fortezza: Negozi,エリア 18: 要塞:商店,구역 18: 요새: 격납고,Zone 18: Vesting: Lager,Strefa 18: Forteca: Sklepy,Área 18: Fortaleza: Reservas,,ZONA 18: Fortăreața: Depozite,МЕСТНОСТЬ 18: Крепость (Склады), -AREA 19: Fortress: Security Complex,TXT_STRIFE_MAP19,,,,ZÓNA 19: Pevnost: Bezpečnostní komplex,ZONE 19: Festung: Sicherheitsanlage,,AREO 19: Fortreso: Sekurkomplekso,ÁREA 19: Fortaleza: Complejo de Seguridad,,ALUE 19: Linnoitus: turvakompleksi,ZONE 19: Forteresse: Complexe Sécurité,19. Terület: Erőd: Biztonsági Komplexum,AREA 19: Fortezza: Complesso di Sicurezza,エリア 19: 要塞:複合警備所,구역 19: 요새: 보안 담당 기지,Zone 19: Vesting: Beveiligingssysteem,Strefa 19: Forteca: Kompleks Ochronny,Área 19: Fortaleza: Complexo de Segurança,,ZONA 19: Fortăreața: Complex de securitate,МЕСТНОСТЬ 19: Крепость (Охранный комплекс), -AREA 20: Factory: Receiving,TXT_STRIFE_MAP20,,,,ZÓNA 20: Továrna: Příjem,ZONE 20: Fabrik: Empfang,,AREO 20: Fabrikejo: Ricevejo,ÁREA 20: Fábrica: Recepción,,ALUE 20: Tehdas: vastaanotto,ZONE 20: Usine: Réception,20. Terület: Gyár: Beszállítás,AREA 20: Fabbrica: Ricevimento,"エリア 20: 工場:受取所 -",구역 20: 공장: 수납구역,Zone 20: Fabriek: Ontvangst,Strefa 20: Fabryka: Odbiór,Área 20: Fábrica: Recebimento,,ZONA 20: Fabrica: Recepție,МЕСТНОСТЬ 20: Фабрика (Приём), -AREA 21: Factory: Manufacturing,TXT_STRIFE_MAP21,,,,ZÓNA 21: Továrna: Výroba,ZONE 21: Fabrik: Herstellung,,AREO 21: Fabrikejo,ÁREA 21: Fábrica: Manufactura,,ALUE 21: Tehdas: valmistus,ZONE 21: Usine: Manufacture,21. Terület: Gyár: Sorozatgyártás,AREA 21: Fabbrica: Manifattura,エリア 21: 工場:製造機関,구역 21: 공장: 조립시설,Zone 21: Fabriek: Productie,Strefa 21: Fabryka: Przetwórstwo,Área 21: Fábrica: Manufatura,,ZONA 21: Fabrica: Procesare,МЕСТНОСТЬ 21: Фабрика (Обработка), -AREA 22: Factory: Forge,TXT_STRIFE_MAP22,,,,ZÓNA 22: Továrna: Kovárna,ZONE 22: Fabrik: Schmiede,,AREO 22: Fabrikejo: Forĝejo,ÁREA 22: Fábrica: Forja,,ALUE 22 Tehdas: paja,ZONE 22: Usine: Forge,22. Terület: Gyár: Kohó,AREA 22: Fabbrica: Fucina,エリア 22: 工場:鉄工所,구역 22: 공장: 제련소,Zone 22: Fabriek: Smederij,Strefa 22: Fabryka: Kuźnia,Área 22: Fábrica: Forja,,ZONA 22: Fabrica: Forja,МЕСТНОСТЬ 22: Фабрика (Кузня), -AREA 23: Order Commons,TXT_STRIFE_MAP23,,,,ZÓNA 23: Náměstí Řádu,ZONE 23: Mensa des Ordens,,AREO 23: Komunejo de La Ordeno,ÁREA 23: Condominios de la Orden,,ALUE 23: Veljeskunnan alahuone,ZONE 23: Mess de l'Ordre,23. Terület: Rendi köztér,AREA 23: Camera dell'Ordine,エリア 23: オーダーコモンズ,구역 23: 오더 식당가,Zone 23: Mensa van de orde,Strefa 23: Wikt Zakonu,Área 23: Câmara da Ordem,,ZONA 23: Decontare comenzi,МЕСТНОСТЬ 23: Поселение Ордена, -AREA 24: Factory: Conversion Chapel,TXT_STRIFE_MAP24,,,,ZÓNA 24: Továrna: Kaple konverze,ZONE 24: Umwandlungskapelle,,AREO 24: Fabrikejo: Konvert-Kapelo,ÁREA 24: Fábrica: Capilla de Conversión,,ALUE 24: Tehdas: käännytyskappeli,ZONE 24: Usine: Chapelle de Conversion,24. Terület: A megtérés kápolnája,AREA 24: Fabbrica: Cappella di Conversione,エリア 24: 工場:改宗礼拝堂,구역 24: 공장: 전향실,Zone 24: Verbouwingskapel,Strefa 24: Fabryka: Kaplica Przemiany,Área 24: Fábrica: Capela de Conversão,,ZONA 24: Fabrica: Capela de conversie,МЕСТНОСТЬ 24: Часовня обращения, -AREA 25: Catacombs: Ruined Temple,TXT_STRIFE_MAP25,,,,ZÓNA 25: Katakomby: Zničený chrám,ZONE 25: Katakomben: Zerstörter Tempel,,AREO: 25: Katakombo: Ruiniga Templo,ÁREA 25: Catacumbas: Templo Arruinado,,ALUE 25: Katakombit: temppeliraunio,ZONE 25: Catacombes: Temple Ruiné,25. Terület: Katakombák: Romtemplom,AREA 25: Catacombe: Tempio in Rovina,エリア 25: 地下墓所:没落した寺院,구역 25: 고대 묘지: 무너진 사원,Zone 25: Catacomben: Vernietigde tempel,Strefa 25: Katakumby: Zrujnowana Świątynia,Área 25: Catacumbas: Templo Arruinado,Área 25: Túmulos: Templo Arruinado,ZONA 25: Catacombe: Templu în ruine,МЕСТНОСТЬ 25: Катакомбы (Руины храма), -AREA 26: Proving Grounds,TXT_STRIFE_MAP26,,,,ZÓNA 26: Vojenský újezd,ZONE 26: Testgelände,,AREO 26: Provejo,ÁREA 26: Campo de Pruebas,,ALUE 26: Koetuspaikka,ZONE 26: Terrain d'entraînement,26. Terület: Ígéretes föld,AREA 26: Banco di Prova,エリア 26: 試練場,구역 26: 증명의 전장,Zone 26: Testgebied,Strefa 26: Poligon Wojskowy,Área 26: Campo de Treinamento,Área 26: Campo de Treino,ZONA 26: Tabăra de instruire,МЕСТНОСТЬ 26: Испытательный полигон, -AREA 27: The Lab,TXT_STRIFE_MAP27,,,,ZÓNA 27: Laboratoř,ZONE 27: Das Labor,,AREO 27: La Labotorio,ÁREA 27: El Laboratorio,,ALUE 27: Laboratorio,ZONE 27: Laboratoire,27. Terület: A labor,AREA 27: Il Laboratorio,エリア 27: 研究所,구역 27: 연구소,Zone 27: Het laboratorium,Strefa 27: Laboratorium,Área 27: O Laboratório,,ZONA 27: Laboratorul,МЕСТНОСТЬ 27: Лаборатория, -AREA 28: Alien Ship,TXT_STRIFE_MAP28,,,,ZÓNA 28: Mimozemská Loď,ZONE 28: Außerirdisches Schiff,,AREO 28: Alilanda Ŝipo,ÁREA 28: Nave Alienígena,,ALUE 28: Muukalaisalus,ZONE 28: Vaisseau Alien,28. Terület: Idegen űrhajó,AREA 28: Nave Aliena,エリア 28: エイリアンの船,구역 28: 외계 우주선,Zone 28: Buitenaards schip,Strefa 28: Statek Obcych,Área 28: Nave Alienígena,,ZONA 28: Nava extraterestră,МЕСТНОСТЬ 28: Корабль пришельцев, -AREA 29: Entity's Lair,TXT_STRIFE_MAP29,,,,ZÓNA 29: Doupě Bytosti,ZONE 29: Das Nest der Entität,,AREO 29: Nestego de Estulo,ÁREA 29: Escondite de la Entidad,,ALUE 29: Tosiolevan maja,ZONE 29: Demeure de L'Entité,,AREA 29: Tana dell'Entità,エリア 29: エンティティの隠れ家,구역 29: 엔티티의 소굴,Zone 29: Het nest van de entiteit,Strefa 29: Leże Bytu,Área 29: Covil da Entidade,,ZONA 29: Cuibul Entității,МЕСТНОСТЬ 29: Логово Сущности, -AREA 30: Abandoned Front Base,TXT_STRIFE_MAP30,,,,ZÓNA 30: Opuštěná základna Fronty,ZONE 30: Verlassene Basis der Front,,AREO 30: Forlasita Front-Bazo,ÁREA 30: Base Abandonada del Frente,,ALUE 30: Hylätty Rintaman tukikohta,ZONE 30: Base Abandonnée du Front,30. Terület: Elhagyatott Előbázis,AREA 30: Base del Fronte abbandonata,エリア 30: 放棄された基地,구역 30: 버려진 프론트 기지,Zone 30: Verlaten frontbasis,Strefa 30: Opuszczona Baza Frontu,Área 30: Base da Frente Abandonada,,ZONA 30: Baza abandonată a Frontului,МЕСТНОСТЬ 30: Заброшенная база Сопротивления, -AREA 31: Training Facility,TXT_STRIFE_MAP31,,,,ZÓNA 31: Výcvikové zařízení,ZONE 31: Trainingseinrichtung,,AREO 31: Trejnejo,ÁREA 31: Facilidad de Entrenamiento,,ALUE 31: Koulutuslaitos,ZONE 31: Complexe d'Entraînement,31. Terület: Képzési létesítmény,AREA 31: Struttura di Addestramento,エリア 31: 研修施設,구역 31: 훈련 시설,Zone 31: Trainingsfaciliteit,Strefa 31: Centrum Szkoleniowe,Área 31: Instalação de Treinamento,,ZONA 31: Spațiul de antrenament,МЕСТНОСТЬ 31: Тренировочный корпус, -AREA 1: Sanctuary,TXT_STRIFE_MAP32,,,,ZÓNA 1: Útočiště,ZONE 1: Heiligtum,,AREO 1: Sanktejo,ÁREA 1: Santuario,,ALUE 1: Turvapaikka,ZONE 1: Sanctuaire,1. Terület: Szentély,AREA 1: Santuario,エリア 1: 聖域 ,구역 1: 성소,Zone 1: Heiligdom,Strefa 1: Sanktuarium,Área 1: Santuário,,ZONA 1: Sanctuar,МЕСТНОСТЬ 1: Святилище, -AREA 2: Town,TXT_STRIFE_MAP33,,,,ZÓNA 2: Město,ZONE 2: Stadt,,AREO 2: Urbeto,ÁREA 2: Pueblo,,ALUE 2: Kylä,ZONE 2: Ville,2. Terület: Város,AREA 2: Città,エリア 2: 町,구역 2: 마을,Zone 2: Stad,Strefa 2: Miasto,Área 2: Vila,,ZONA 2: Oraș,МЕСТНОСТЬ 2: Город, -AREA 3: Movement Base,TXT_STRIFE_MAP34,,,,ZÓNA 3: Rebelská základna,ZONE 3: Rebellenbasis,,AREO 3: Movad-Bazo,ÁREA 3: Base del Movimiento,,ALUE 3: Liikkeen tukikohta,ZONE 3: Base du Front,3. Terület: Mozgalmi Bázis,AREA 3: Base del Movimento,エリア 3: 移転基地,구역 3: 반군 기지,Zone 3: Front basis,Strefa 3: Baza Ruchu Oporu,Área 3: Base do Movimento,,ZONA 3: Baza rezistenței,МЕСТНОСТЬ 3: База Сопротивления, -AREA 35: Factory: Production,TXT_STRIFE_MAP35,,,,ZÓNA 35: Továrna: Produkce,ZONE 35: Fabrik: Produktion,,AREO 35: Fabrikejo: Produktejo,ÁREA 35: Fábrica: Producción,,ALUE 35: Tehdas: tuotanto,ZONE 35: Usine: Production,35. Terület: Gyár: Termelés,AREA 35: Fabbrica: Produzione,エリア 35: 工場 : 生産ライン,구역 35: 공장: 제작실,Zone 35: Fabriek: Productie,Strefa 35: Fabryka: Produkcja,Área 35: Fábrica: Produção,,ZONA 35: Fabrica: Producție,МЕСТНОСТЬ 35: Фабрика (Производство), -AREA 36: Castle Clash,TXT_STRIFE_MAP36,,,,ZÓNA 36: Střet na hradě,ZONE 36: Burg-Konflikt,,AREO 36: Batalo ĉe Kastelo,ÁREA 36: Ataque al Castillo,,ALUE 36: Linnayhteenotto,ZONE 36: Bataille du Château,36: Terület: Vári ütközet,AREA 36: Collisione di Castello,エリア 36: キャッスルクラッシュ,구역 36: 성채간의 충돌,Zone 36: Kasteelconflict,Strefa 36: Potyczka w Zamku,Área 36: Ataque ao Castelo,,ZONA 36: Bătălia castelului,МЕСТНОСТЬ 36: Битва в замке, -AREA 37: Killing Grounds,TXT_STRIFE_MAP37,,,,ZÓNA 37: Zabíjecí zahrady,ZONE 37: Kampfgelände,,AREO 37: Tereno de Mortigado,ÁREA 37: Campo de Matanza,,ALUE 37: Tappotanner,ZONE 37: Zone de Chasse,37. Terület: Gyilkos Vidék,AREA 37: Campi di Uccisione,エリア 37: 殺害者の地,구역 37: 살육의 전장,Zone 37: Slagveld,Strefa 37: Śmiercionośny Grunt,Área 37: Campo de Matança,,ZONA 37: Teren de ucis,МЕСТНОСТЬ 37: Секторы обстрела, -AREA 38: Ordered Chaos,TXT_STRIFE_MAP38,,,,ZÓNA 38: Nařízený chaos,ZONE 38: Geordnetes Chaos,,AREO 38: Orda Kaoso,ÁREA 38: Caos Ordenado,,ALUE 38: Järjestynyt kaaos,ZONE 38: Chaos Ordonné,38. Terület: Rendezett Káosz,AREA 38: Caos Ordinato,エリア 38: カオスの秩序,구역 38: 정돈된 혼란,Zone 38: Ordelijke chaos,Strefa 38: Uporządkowany Chaos,Área 38: Caos Ordenado,,ZONA 38: Haos controlat,МЕСТНОСТЬ 38: Управляемый хаос, -,,Hexen,,,,,,,,,,,,,,,,,,,,, -Winnowing Hall,TXT_HEXEN_MAP01,,,,Sál prosetí,Trennungshalle,,Solenejo de Separado,Sala de los Vientos,,Viskaussali,Chambre de la Séparation,Huzatos Folyosó,Camera di separazione,選抜の間,바람 회관,Scheidingszaal,Hala Przesiewu,Sala de Separação,,Sala de Separare,Зал отсеивания,Овејана дворана -Seven Portals,TXT_HEXEN_MAP02,,,,Sedmero portálů,Sieben Portale,,Sep Portaloj,Siete Portales,,Seitsemän portaalia,Les Sept Portails,Hét Portál,I Sette Portali,漆之門,일곱 차원문,Zeven portalen,Siedem Portali,Sete Portais,,Șapte Portaluri,Семь порталов,Седам портала -Guardian of Ice,TXT_HEXEN_MAP03,,,,Strážce ledu,Wächter des Eises,,Gardanto de Glacio,Guardián de Hielo,,Jään vartija,Gardien de Glace,A Jég Őre,Guardiano del Ghiaccio,氷の守護者,얼음의 수호자,Bewaker van ijs,Strażnik Lodu,Guardião de Gelo,,Străjerul Gheții,Страж льда,Чувар леда -Guardian of Fire,TXT_HEXEN_MAP04,,,,Strážce ohně,Wächter des Feuers,,Gardanto de Fajro,Guardián de Fuego,,Tulen vartija,Gardien de Feu,A Tűz Őre,Guardiano del Fuoco,炎の守護者,화염의 수호자,Bewaker van vuur,Strażnik Ognia,Guardião de Fogo,,Străjerul Focului,Страж огня,Чувар ватре -Guardian of Steel,TXT_HEXEN_MAP05,,,,Strážce oceli,Wächter des Stahls,,Gardanto de Ŝtalo,Guardián de Acero,,Teräksen vartija,Gardien d'Acier,Az Acél Őre,Guardiano dell'Acciaio,鋼の守護者,강철의 수호자,Bewaker van staal,Strażnik Stali,Guardião de Aço,,Străjerul Oțelului,Страж стали,Чувар челика -Bright Crucible,TXT_HEXEN_MAP06,,,,Světlý očistec,Glänzende Feuerprobe,,Luma Krisolo,Crisol de Luz,,Kirkas tulikoe,Creuset Radiant,,Crogiolo Luminoso,光の坩堝,빛나는 고난,Heldere beproeving,Próba Światła,Crisol de Luz,,Creuzet Luminos,Испытание света,Испитивање светла -Shadow Wood,TXT_HEXEN_MAP13,,,,Temný hvozd,Schattenwald,,Ombro-arbareto,Bosque de la Sombra,,Varjosalo,Forêt des Ombres,Árnyék Erdő,Foresta Oscura,陰影樹,그림자 숲,Schaduwbos,Las Cieni,Floresta das Sombras,,Pădurea Umbrelor,Лес теней,Шума сена -Darkmere,TXT_HEXEN_MAP08,,,,Černý močál,Düstersee,,Malluma Marĉo,Pantano,,Pikiräme,Marais Noir,,Palude Nera,暗黒の地,흙빛호수,Sombermeer,Mroczne Bagno,Pantâno Negro,,Mlaștinile Întunecate,Болотная топь,Мочваре -Caves of Circe,TXT_HEXEN_MAP09,,,,Jeskyně Kirké,Circes Höhle,,Kavernoj de Circe,Cuevas de Circe,,Circeluolat,Caves de Circé,Körök Barlangja,Grotte di Circe,キルケーの洞窟,키르케의 동굴,Grotten van Circe,Jaskinie Kirke,Cavernas de Circe,,Peșterile lui Circe,Пещеры цирцеи,Пећине цирке -Wastelands,TXT_HEXEN_MAP10,,,,Pustiny,Ödland,,Senvivejo,Yermo,,Erämaat,Terres Ruinées,Senkiföldje,Terre in rovina,荒野,황무지,Woestenij,Pustkowia,Terras Desoladas,,Tărâmurile Pustii,Пустоши,Пустаре -Sacred Grove,TXT_HEXEN_MAP11,,,,Posvátný háj,Heiliger Hain,,Sankta Bosketo,Arboleda Sagrada,,Pyhä metsikkö,Bosquet Sacré,,Boschetto Sacro,神聖なる園,성스러운 수풀,Heilig bosje,Święty Gaj,Bosque Sagrado,,Crângul Sacru,Священная роща,Свети шумарак -Hypostyle,TXT_HEXEN_MAP12,,,,Hypostyl,Säulenhalle,,Kolonejo,Hipóstila,,Hypostyyli,Hypostyle,,Ipostilo,多柱の間,다주실,Zuilenhal,Hypostyl,Hipostilo,,Hipostil,Гипостильный зал,Хипостил -Heresiarch's Seminary,TXT_HEXEN_MAP27,,,,Arcikacířův alumnát,Seminar des Erzketzers,,Seminario de Ĉefherezulo,Seminario del Heresiarca,,Kerettiarkin seminaari,Séminaire de l'Hérésiarche,,Seminario dell'Heresiarch,ヘレシアークの神学舎,헤러시아크의 신학교,Seminarie van ketterij,Seminarium Herezjarchy,Seminário do Heresiarca,,Seminarul Ereziarhului,Семинария Ересиарха,Јересијархов семинар -Dragon Chapel,TXT_HEXEN_MAP28,,,,Dračí kaple,Drachenkapelle,,Drakkapelo,Capilla Dragón,,Lohikäärmekappeli,Chapelle du Dragon,Sárkány Szentély,Cappella del Drago,ドラゴンの庵寺,드래곤 예배실,Drakenkapel,Kaplica Smoka,Capela do Dragão,,Capela dragonilor,Часовня дракона,Змајева капела -Griffin Chapel,TXT_HEXEN_MAP30,,,,Gryfova kaple,Greifenkapelle,,Grifkapelo,Capilla Grifo,,Aarnikotkakappeli,Chapelle du Grifon,Griff Szentély,Cappella del Grifone,グリフィンの庵寺,그리핀 예배실,Griffioenenkapel,Kaplica Gryfa,Capela do Grifo,,Capela grifonilor,Часовня грифона,Грифинова капела -Deathwind Chapel,TXT_HEXEN_MAP31,,,,Kaple mrakosmrtě,Todeswindkapelle,,Mortvento-kapelo,Capilla Viento de Muerte,,Kuolontuulikappeli,Chapelle du Vent Tueur,,Cappella del Vento Assassino,デスウィンドの庵寺,죽음바람 예배실,Dodenwind kapel,Kaplica Wiatru Śmierci,Capela do Vento da Morte,,Capela suflului morții,Часовня ветра смерти,Капела ветра смрти -Orchard of Lamentations,TXT_HEXEN_MAP32,,,,Sad nářků,Garten der Wehklagen,,Horto de Lamentoj,Huerto de los Lamentos,,Valitusvirtten tarha,Verger des Lamentations,,Frutteto delle Lamentazioni,哀悼茂る園,통탄의 과수원,Boomgaard van klaagliederen,Płaczący Sad,Pomar das Lamentações,,Livada amărăciunii,Сады плача,Воћњак тужбалица -Silent Refectory,TXT_HEXEN_MAP33,,,,Tichý refektář,Stilles Refektorium,,Silenta Manĝejo,Refectorio Silencioso,,Hiljainen ruokasali,Réfectoire Silencieux,,Refettorio silenzioso,寡黙なる食堂,침묵의 식당,Stil refectory,Cichy Refektarz,Refeitório Silencioso,,Refectoriul tăcerii,Безмолвная трапезная,Тиха трпезарија -Wolf Chapel,TXT_HEXEN_MAP34,,,,Vlčí kaple,Wolfskapelle,,Lupkapelo,Capilla Lobo,,Susikappeli,Chapelle du Loup,Farkas Szentély,Cappella del Lupo,狼の庵寺,늑대 예배실,Wolvenkapel,Kaplica Wilka,Capela do Lobo,,Capela lupilor,Часовня волка,Вучја капела -Forsaken Outpost,TXT_HEXEN_MAP21,,,,Opuštěné stanoviště,Verlassener Vorposten,,Forlasita Posteno,Puesto de Avanzada Abandonado,,Hylätty etuvartio,Base Abandonnée,,Avamposto Abbandonato,荒れ果てた前哨地,버려진 초소,Verwaarloosde buitenpost,Opuszczony Posterunek,Posto Abandonado,,Avanpostul părăsit,Покинутая застава,Напуштена постаја -Castle of Grief,TXT_HEXEN_MAP22,,,,Hrad smutku,Leidensburg,,Kastelo de Funebro,Castillo del Pesar,,Surulinna,Château de la Souffrance,,Castello della Sofferenza,嘆きの城,비탄의 성,Kasteel van verdriet,Zamek Smutku,Castelo da Aflição,,Castelul întristării,Замок скорби,Замак жалости -Gibbet,TXT_HEXEN_MAP23,,,,Šibenice,Richtstätte,,Pendigilo,Horca,,Hirsipuu,Gibet,,Forca,晒し台,교수대,,Szubienica,Forca,,Eșafodul,Виселица,Вешала -Effluvium,TXT_HEXEN_MAP24,,,,Výpary,Effluvium,,Efluvo,Efluvio,,Katku,Effluvium,,Effluvio,腐臭漂う残骸,악취,,Odór,Eflúvio,,Efluviu,Зловонный сток,Ефлувиум -Dungeons,TXT_HEXEN_MAP25,,,,Žalář,Kerker,,Karceroj,Calabozos,,Tyrmät,Donjons,Kazamaták,I Dungeon,地下牢,지하감옥,Kerkers,Lochy,Masmorras,,Temnițe,Подземелья,Тамнице -Desolate Garden,TXT_HEXEN_MAP26,,,,Zpustošená zahrada,Verwildeter Garten,,Dezerta Ĝardeno,Jardín Desolado,,Autio puutarha,Jardin de la Désolation,,Giardino Desolato,荒涼とした庭,황폐한 정원,Woeste tuin,Spustoszały Ogród,Jardim Desolado,,Grădina dezolantă,Заброшенный сад,Пуста башта -Necropolis,TXT_HEXEN_MAP35,,,,Nekropole,Nekropole,,Nekropolo,Necrópolis,,Nekropoli,Nécropole,Halottak Városa,Necropoli,ネクロポリス,망자의 도시,,Nekropolia,Necrópole,,Necropola,Некрополь,Некрополис -Zedek's Tomb,TXT_HEXEN_MAP36,,,,Zedekova hrobka,Zedeks Gruft,,Tombo de Zedek,Tumba de Zedek,,Sedekin hauta,Tombeau de Zedek,Zedek Sírja,Tomba di Zedek,ゼデクの墓,제닥의 무덤,Zedek's graf,Grobowiec Zedeka,Tumba de Zedek,Túmulo de Zedek,Mormântul lui Zedek,Гробница Зедека,Зедеков гроб -Menelkir's Tomb,TXT_HEXEN_MAP37,,,,Menelkirova hrobka,Menelkirs Gruft,,Tombo de Menelkir,Tumba de Menelkir,,Menelkirin hauta,Tombeau de Menelkir,Menelkir Sírja,Tomba di Menelkir,メネルキルの墓,메넬키어의 무덤,Menelkir's graf,Grobowiec Menelkira,Tumba de Menelkir,Túmulo de Menelkir,Mormântul lui Menelkir,Гробница Менелкира,Менелкиров гроб -Traductus' Tomb,TXT_HEXEN_MAP38,,,,Traduktova hrobka,Traductus' Gruft,,Tombo de Traductus,Tumba de Traductus,,Traduktuksen hauta,Tombeau de Traductus,Traductus Sírja,Tomba di Traductus,トダクティスの墓,트라닥투스의 무덤,Traductus' graf,Grobowiec Traductusa,Tumba de Traductus,Túmulo de Traductus,Mormântul lui Traductus,Гробница Традактуса,Традуктусов гроб -Vivarium,TXT_HEXEN_MAP39,,,,Vivárium,Vivarium,,Vivario,Vivario,,Vivaario,Vivarium,Vivárium,Vivario,ビバリウム,사육장,,Wiwarium,Viveiro,,Vivariu,Виварий,Зверињак -Dark Crucible,TXT_HEXEN_MAP40,,,,Temný očistec,Dunkle Feuerprobe,,Malluma Krisolo,Crisol de Oscuridad,,Pimeä tulikoe,Creuset Sombre,,Crogiolo Buio,"暗黒の坩堝 -",어두운 고난,Donkere beproeving,Próba Mroku,Crisol das Trevas,,Creuzet Întunecat,Испытание тьмы,Испитивање мрака -,,Hexen Deathkings,,,,,,,,,,,,,,,,,,,,, -Ruined Village,TXT_HEXDD_MAP41,,,,Zničená vesnice,Zerstörtes Dorf,,Ruiniga Vilaĝo,Pueblo en Ruinas,,Rauniokylä,Village en Ruines,Az Elpusztult Falu,Villagio in Rovine,廃村,파괴된 마을,Ruïneerd dorp,Zrujnowana Wioska,Aldeia Destruída,Aldeia em Ruinas,Sat ruinat,Разрушенная деревня,Уништено село -Blight,TXT_HEXDD_MAP42,,,,Pohroma,Fäule,,Pesto,Decaimiento,,Turmelus,Peste,,Peste,疫病,황폐화,Ziekte,Zaraza,Peste,,Cotropit,Упадок,Пошаст -Sump,TXT_HEXDD_MAP43,,,,Žumpa,Sumpf,,Fekaĵputo,Pozo de Barro,,Likakaivo,Puisard,,Pozzetto,汚水槽,웅덩이,Moeras,Studzienka,Poço de Lama,,Joampă,Грязеотстойник,Сливник -Catacomb,TXT_HEXDD_MAP44,,,,Katakomby,Katakombe,,Katakombo,Catacumba,,Katakombi,Catacombe,,Catacombe,カタコンベ,지하 묘실,Katacombe,Katakumba,Catacumba,,Catacombă,Катакомба,Катакомба -Badlands,TXT_HEXDD_MAP45,,,,Pustiny,Ödland,,Mislando,Páramos,,Autiomaa,Terres Sauvages,,Terre Selvagge,不毛地帯,불모지,Woestijn,Nieurodzaj,Ermo,,Deșert,Бесплодные земли,Пустош -Brackenwood,TXT_HEXDD_MAP46,,,,Prales,Moorwald,,Pteridejo,Brackenwood,,Saniaissalo,Forêt de Bracken,,Foresta di Felce,ワラビの樹,고사리숲,Moorbos,Las Paproci,Floresta de Samambaias,,Pădure de ferigi,Брекенвуд,Папрат -Pyre,TXT_HEXDD_MAP47,,,,Hranice,Scheiterhaufen,,Kremaciejo,Pira Funeraria,,Rovio,Brasier,,Pira,火葬薪,화장,Brandstapel,Stos,Pira,,Rug,Погребальный костёр,Ломача -Constable's Gate,TXT_HEXDD_MAP48,,,,Konstáblova brána,Wachtor,,Pordego de Ĝendarmo,Puerta del Alguacil,,Konstaapelin portti,Portail du Constable,,Porta del Conestabile,城守達の門,무관장의 문,Constable's poort,Brama Posterunkowego,Portão do Condestável,,Poarta ofițerului,Комендантские врата,Чиновникова капија -Treasury,TXT_HEXDD_MAP49,,,,Pokladnice,Schatzkammer,,Trezorejo,Tesorería,,Rahasto,Trésorerie,,Tesoreria,宝庫,국고,Schatkist,Skarbiec,Tesouraria,,Vistierie,Сокровищница,Трезор -Market Place,TXT_HEXDD_MAP50,,,,Tržnice,Marktplatz,,Foirejo,Plaza del Mercado,,Markkinat,Place du Marché,,Piazza del Mercato,市場,시장,Markt,Rynek,Feira,,Piață,Рыночная площадь,Пијаца -Locus Requiescat,TXT_HEXDD_MAP51,,,,,Locus Requiescat,,Locus Requiescat,Lugar de Descanso Eterno,,,Locus Requiescat,,,祈祷師の軌跡,명복의 장소,,Locus Requiescat,,,,Место вечного упокоения,Место починка -Ordeal,TXT_HEXDD_MAP52,,,,Utrpení,Heimsuchung,,Provo Per Aflikto,Prueba,,Koettelemus,Supplice,,Supplizio,試練,시죄의 시련,Orde,Męka,Suplício,,Supliciu,Испытание,Изазов -Armory,TXT_HEXDD_MAP53,,,Armoury,Zbrojnice,Waffenkammer,,Armilejo,Armería,,Asehuone,Amurerie,Fegyverraktár,Armeria,武器庫,무기고,Wapenkamer,Zbrojownia,Arsenal,,Arsenal,Оружейная,Оружарница -Nave,TXT_HEXDD_MAP54,,,,Chrámová loď,Kirchenschiff,,Navo,La Nave,,Laiva,Nef,,Navata,身廊,본당,Naaf,Nawa,,,Naos,Неф,Брод -Chantry,TXT_HEXDD_MAP55,,,,Modlitebna,Kantorei,,Kapelo,Capilla,,Kappeli,Chapelle,,Cappella,小礼拝堂,예배당,,Kaplica Wotywna,Capela,,Capelă,Часовня,Капела -Abattoir,TXT_HEXDD_MAP56,,,,Jatka,Schlachthaus,,Buĉejo,Matadero,,Teurastamo,Abbatoire,,Mattatoio,屠殺場,도살장,Slachthuis,Rzeźnia,Matadouro,,Abator,Бойня,Кланица -Dark Watch,TXT_HEXDD_MAP57,,,,Tmavá hlídka,Dunkle Wache,,Gardisto Ombra,Guardia Oscura,,Pimeä vartio,Garde Noire,,Guardia Oscura,闇の刻計,어둠의 감시초소,Donkere horloge,Ciemna Straż,Guarda Negra,,Gardian întunecat,Тёмный страж,Мрачни чувар -Cloaca,TXT_HEXDD_MAP58,,,,Kloaka,Kloake,,Cloaca,Cloaca,,Kloaakki,Cloaque,,,排泄腔,하수구,,Kloaka,,,,Клоака,Клоака -Ice Hold,TXT_HEXDD_MAP59,,,,Ledová pevnost,Eiskammer,,Fuorto el Glacio,Tierra de Hielo,,Jääsäilö,Fort de Glace,,Fortezza di Ghiaccio,氷結,빙고,Ijskamer,Lodowa Twierdza,Fortaleza de Gelo,,Fort glaciar,Ледяная твердь,Ледена утврда -Dark Citadel,TXT_HEXDD_MAP60,,,,Temná citadela,Dunkle Festung,,Citadelo Ombra,Fortaleza Oscura,,Pimeä linnake,Citadelle Sombre,,Cittadella Oscura,暗黒の城塞,어둠의 요새,Donkere citadel,Mroczna Cytadela,Cidadela Negra,,Cetatea întunecată,Тёмная цитадель,Мрачна цитадела -Transit,TXT_HEXDD_MAP33,,,,Převoz,,,Vojo,Sala de Espera,,Läpikulku,Transit,,Passaggio,変遷,통로,Doorvoer,Tranzyt,Sala de Espera,,Tranzit,Комната ожидания,Прелаз -Over'n Under,TXT_HEXDD_MAP34,,,,Nad a Pod,Drunter und Drüber,,Sub kaj Supre,Arriba y Abajo,,Yli ja ali,Sens Dessus Dessous,,Sopra e Sotto,天と地,높낮이,Over'n under,Nad I Pod,Sobre e Sob,,Mai sus și Mai jos,Выше и ниже,Изнад и испод -Deathfog,TXT_HEXDD_MAP35,,,,Mha skonu,Todesnebel,,Mortnebulo,Niebla de Muerte,,Kuolonsumu,Brume Mortelle,Halálköd,Nebbia di Morte,死の霧,죽음의 안개,Dodenmist,Mgła Śmierci,Névoa da Morte,,Ceața morții,Туман смерти,Магла смрти -Castle of Pain,TXT_HEXDD_MAP36,,,,Hrad bolesti,Burg der Angst,,Kastelo de Doloro,Castillo del Dolor,,Tuskan linna,Château de la Douleur,,Castello del Dolore,苦しみの城,고통의 성,Kasteel van pijn,Zamek Bólu,Castelo da Dor,,Castelul durerii,Замок боли,Тврђава бола -Sewer Pit,TXT_HEXDD_MAP37,,,,Odpadní jáma,Kanalgrube,,Fekaĵputo,Pozo de Residuos,,Viemärimonttu,Trou d'Egout,,Fossa della Fogna,地下溝穴,하수도,Rioolput,Ściek,Fossa de Esgoto,,Groapa de scurgere,Сточная яма,Канализациона јама -The Rose,TXT_HEXDD_MAP38,,,,Růže,Die Rose,,La Rozo,La Rosa,,Ruusu,La Rose,A Rózsa,La Rosa,薔薇,장밋빛,De roos,Róża,A Rosa,,Roza,Роза,Ружа -,,Intermission texts,,,,,,,,,,,,,,,,,,,,, +Circle of Death ",,,Level 11: Kruh smrti,Level 11: Ødelæggelsens cirkel!,Level 11: 'O' der Zerstörung!,Επίπεδο 11: Ο Κύκλος της Καταστροφής,Nivelo 11: Morta cirklo,Nivel 11: Círculo de la muerte,,Taso 11: Hävityksen 'O',NIVEAU 11: Le Cercle de la Mort!,11. Pálya: A pusztulás köre,Livello 11: Il Cerchio della Morte,Level 11: 破滅の'O'!,레벨 11: 파괴의 고리,Level 11: 'O' van vernietiging!,Nivå 11: Ødeleggelsens 'O'!,Level 11: Krąg Śmierci,Fase 11: Círculo da Morte,Nível 11: Círculo da Morte,Nivelul 11: Cercul distrugerii,Уровень №11: Круг разрушения!,Level 11: Круг уништења,"Nivå 11: ""O"" av förstörelse!",Seviye 11: Yıkımın 'O'su! +Level 12: The Factory,HUSTR_12,,,,Level 12: Továrna,Level 12: Fabrikken,Level 12: Die Fabrik,Επίπεδο 12: To Εργοστάσιο,Nivelo 12: La fabriko,Nivel 12: La fábrica,,Taso 12: Tehdas,NIVEAU 12: L'Usine,12. Pálya: A gyár,Livello 12: La Fabbrica,Level 12: 工場,레벨 12: 공장,Level 12: De fabriek,Nivå 12: Fabrikken,Level 12: Fabryka,Fase 12: A Fábrica,Nível 12: A Fábrica,Nivelul 12: Fabrica,Уровень №12: Фабрика,Level 12: Фабрика,Nivå 12: Fabriken,Seviye 12: Fabrika +Level 13: Downtown,HUSTR_13,,,,Level 13: Centrum,Level 13: Centrum,Level 13: Stadtzentrum,Επίπεδο 13: Κέντρο,Nivelo 13: Urbocentro,Nivel 13: Centro de la ciudad,,Taso 13: Keskikaupunki,NIVEAU 13: Centre-Ville,13. Pálya: Belváros,Livello 13: Periferia,Level 13: 市内,레벨 13: 번화가,Level 13: De binnenstad,Nivå 13: Sentrum,Level 13: Śródmieście,Fase 13: Centro Urbano,Nível 13: Centro Urbano,Nivelul 13: Centru urban,Уровень №13: Центр города,Level 13: Центар града,Nivå 13: Centrum,Seviye 13: Şehir Merkezi +Level 14: The Inmost Dens,HUSTR_14,,,,Level 14: Nejhlubší doupata,Level 14: Den inderste hule,Level 14: Die innersten Bauten,Επίπεδο 14: Οι Ενδότερες Φωλιές,Nivelo 14: La Internaj Kavernoj,Nivel 14: Los Antros más Recónditos,,Taso 14: Sisimmät piilot,NIVEAU 14: Les Antres Profondes,14. Pálya: A legmélyebb rejtekek,Livello 14: Gli Antri Profondi,Level 14: 最深巣窟,레벨 14: 깊숙한 동굴들,Level 14: De binnenste gebouwen,Nivå 14: De innerste huler,Level 14: Najgłębsze Nory,Fase 14: Os Antros Profundos,Nível 14: Os Antros Profundos,Nivelul 14: Cele mai intime bârloguri,Уровень №14: Глубочайшие логовища,Level 14: Најдубље јазбине,Nivå 14: Den innersta täkten,Seviye 14: En İçteki İnler +Level 15: Industrial Zone,HUSTR_15,,,,Level 15: Průmyslová zóna,Level 15: Industriområde,Level 15: Industriegebiet,Επίπεδο 15: Βιομηχανική Ζώνη,Nivelo 15: Industria Zono,Nivel 15: Zona Industrial,,Taso 15: Teollisuusalue,NIVEAU 15: Zone Industrielle,15. Pálya: Ipari zóna,Livello 15: Zona Industriale,Level 15: 工業地帯,레벨 15: 공업 지대,Level 15: Industriegebied,Nivå 15: Industriområdet,Level 15: Strefa Przemysłowa,Fase 15: Zona Industrial,Nível 15: Zona Industrial,Nivelul 15: Zona industrială,Уровень №15: Промышленный район,Level 15: Индустријска зона,Nivå 15: Industriområde,Seviye 15: Sanayi Bölgesi +Level 16: Suburbs,HUSTR_16,,,,Level 16: Předměstí,Level 16: Forstæderne,Level 16: Vororte,Επίπεδο 16: Προάστια,Nivelo 16: Antaŭurboj,Nivel 16: Suburbios,,Taso 16: Lähiö,NIVEAU 16: Banlieue,16. Pálya: Külváros,Livello 16: Sobborghi,Level 16: 郊外,레벨 16: 교외,Level 16: Buitenwijken,Nivå 16: Forstedene,Level 16: Przedmieścia,Fase 16: Subúrbios,Nível 16: Subúrbios,Nivelul 16: Suburbi,Уровень №16: Пригород,Level 16: Предграђе,Nivå 16: Förorter,Seviye 16: Banliyöler +Level 17: Tenements,HUSTR_17,,,,Level 17: Sídliště,Level 17: Lejligheder,Level 17: Wohnbezirk,Επίπεδο 17: Καταλύματα,Nivelo 17: Loĝejoj,Nivel 17: Viviendas,,Taso 17: Vuokratalot,NIVEAU 17: Immeubles,17. Pálya: Bérházak,Livello 17: Possedimenti,Level 17: 安アパート,레벨 17: 공동주택,Level 17: Huurwoningen,Nivå 17: Leiegårder,Level 17: Kamienice,Fase 17: Habitações,Nível 17: Habitações,Nivelul 17: Proprietăți,Уровень №17: Владения,Level 17: Станови,Nivå 17: Hyreshus,Seviye 17: Kiralık Evler +Level 18: The Courtyard,HUSTR_18,,,,Level 18: Nádvoří,Level 18: Gårdspladsen,Level 18: Der Innenhof,Επίπεδο 18: Η Αυλή,Nivelo 18: La Korto,Nivel 18: El Patio,,Taso 18: Esipiha,NIVEAU 18: La Cour,18. Pálya: Az udvar,Livello 18: Il Cortile,Level 18: 中庭,레벨 18: 중정,Level 18: De binnenplaats,Nivå 18: Gårdsplassen,Level 18: Dziedziniec,Fase 18: O Átrio,Nível 18: O Átrio,Nivelul 18: Curtea,Уровень №18: Внутренний двор,Level 18: Двориште,Nivå 18: Gården,Seviye 18: Avlu +Level 19: The Citadel,HUSTR_19,,,,Level 19: Citadela,Level 19: Citadellet,Level 19: Die Zizadelle,Επίπεδο 19: Το Κάστρο,Nivelo 19: La Citadelo,Nivel 19: La Ciudadela,,Taso 19: Linnoitus,NIVEAU 19: La Citadelle,19. Pálya: Fellegvár,Livello 19: La Cittadella,Level 19: 要塞,레벨 19: 성채,Level 19: De citadel,Nivå 19: Citadellet,Level 19: Cytadela,Fase 19: A Cidadela,Nível 19: A Cidadela,Nivelul 19: Cetatea,Уровень №19: Цитадель,Level 19: Цитадела,Nivå 19: Citadellet,Seviye 19: Hisar +Level 20: Gotcha!,HUSTR_20,,,,Level 20: Mám tě!,,Level 20: Erwischt!,Επίπεδο 20: Σ'έπιασα!,Nivelo 20: Kaptis Vin!,Nivel 20: ¡Te pillé!,Nivel 20: ¡Te tengo!,Taso 20: Sainpas sinut!,NIVEAU 20: Je t'ai eu!,20. Pálya: Megvagy!,Livello 20: Preso!,Level 20: 捉らえた!,레벨 20: 잡았다!,Level 20: Ik heb je!,Nivå 20: Fikk deg!,Level 20: Mam Cię!,Fase 20: Te Peguei!,Nível 20: Apanhei-te!,Nivelul 20: Te-am prins!,Уровень №20: Попался!,Level 20: Имају те!,Nivå 20: Gotcha!,Seviye 20: Yakaladım! +Level 21: Nirvana,HUSTR_21,,,,Level 21: Nirvána,,,Επίπεδο 21: Νιρβάνα,Nivelo 21: Nirvano,Nivel 21: Nirvana,,,NIVEAU 21: Nirvana,21. Pálya: Nirvána,Livello 21: Nirvana,Level 21: 涅槃,레벨 21: 열반,,,,Fase 21: Nirvana,Nível 21: Nirvana,Nivelul 21: Nirvana,Уровень №21: Нирвана,Level 21: Нирвана,Nivå 21: Nirvana,Seviye 21: Nirvana +Level 22: The Catacombs,HUSTR_22,,,,Level 22: Katakomby,Level 22: Katakomberne,Level 22: Katakomben,Επίπεδο 22: Οι Κατακόμβες,Nivelo 22: La Katakombo,Nivel 22: Las Catacumbas,,Taso 22: Katakombit,NIVEAU 22: Les Catacombes,22. Pálya: A katakombák,Livello 22: Le Catacombe,Level 22: 地下悪霊墓所,레벨 22: 지하 묘지,Level 22: De catacomben,Nivå 22: Katakombene,Level 22: Katakumby,Fase 22: As Catacumbas,Nível 22: Os Calabouços,Nivelul 22: Catacombe,Уровень №22: Катакомбы,Level 22: Катакомбе,Nivå 22: Katakomberna,Seviye 22: Yeraltı Mezarları +Level 23: Barrels O' Fun,HUSTR_23,,,,Level 23: Barely srandy,Level 23: Tønder af sjov,Level 23: Lustige Fässer,,Nivelo 23: Bareloj de Amuzo,Nivel 23: Barriles de Diversión,,Taso 23: Huvitynnyrit,NIVEAU 23: Une Tonne-eau de plaisir,23. Pálya: Mókás hordók,Livello 23: Barili da Sballo,Level 23: 戯れのバレル,레벨 23: 신나는 폭발통들,Level 23: Grappige vaten,Nivå 23: Tønner med moro,Level 23: Beczki Śmiechu,Fase 23: Barris de Diversão,Nível 23: Barris de Diversão,Nivelul 23: Butoaiele veseliei,Уровень №23: Бочки веселья,Level 23: Бачве забаве,Nivå 23: Tunnor med kul,Seviye 23: Eğlence Fıçıları +Level 24: The Chasm,HUSTR_24,,,,Level 24: Rokle,Level 24: Kløften,Level 24: Die Kluft,Επίπεδο 24: Το Χάσμα,Nivelo 24: La Fendego,Nivel 24: El Desfiladero,,Taso 24: Rotko,NIVEAU 24: Le Gouffre,24. Pálya: A szakadék,Livello 24: L'Abisso,Level 24: 裂け目,레벨 24: 협곡,Level 24: De afgrond,Nivå 24: Avgrunnen,Level 24: Przepaść,Fase 24: O Abismo,Nível 24: O Abismo,Nivelul 24: Hăul,Уровень №24: Пропасть,Level 24: Провалија,Nivå 24: Klyftan,Seviye 24: Uçurum +Level 25: Bloodfalls,HUSTR_25,,,,Level 25: Krvopády,Level 25: Blodfald,Level 25: Blutfälle,Επίπεδο 25: Καταρράκτες Αίματος,Nivelo 25: Sangfaloj,Nivel 25: Cataratas de Sangre,,Taso 25: Veriputoukset,NIVEAU 25: Chutes de Sang,25. Pálya: Véresések,Livello 25: Cascate di Sangue,Level 25: 血の滝,레벨 25: 혈폭포,Level 25: Bloeddruppels,Nivå 25: Blodfall,Level 25: Wodospad Krwi,Fase 25: Cataratas de Sangue,Nível 25: Cascatas de Sangue,Nivelul 25: Cascade de sânge,Уровень №25: Кровопады,Level 25: Крвопади,Nivå 25: Blodfall,Seviye 25: Kan Düşüşleri +Level 26: The Abandoned Mines,HUSTR_26,,,,Level 26: Opuštěné doly,Level 26: De forladte miner,Level 26: Die aufgegebene Mine,Επίπεδο 26: Τα Εγκαταλελειμμένα Ορυχεία,Nivelo 26: La Forlasitaj Minoj,Nivel 26: Las Minas Abandonadas,,Taso 26: Hylätyt kaivokset,NIVEAU 26: Les Mines Abandonnées,26. Pálya: Az elhagyatott bányák,Livello 26: Le Miniere Abbandonate,Level 26: 廃鉱山,레벨 26: 버려진 광산,Level 26: De verlaten mijnen,Nivå 26: De forlatte gruvene,Level 26: Opuszczone Kopalnie,Fase 26: As Minas Abandonadas,Nível 26: As Minas Abandonadas,Nivelul 26: Minele părăsite,Уровень №26: Заброшенные шахты,Level 26: Напуштени рудници,Nivå 26: De övergivna gruvorna,Seviye 26: Terk Edilmiş Madenler +Level 27: Monster Condo,HUSTR_27,,,,Level 27: Netvoří dům,,Level 27: Monsterbehausung,,Nivelo 27: Monstro-Domo,Nivel 27: Condominio de Monstruos,,Taso 27: Hirviöasuntola,NIVEAU 27: Monstrueuse Résidence,27. Pálya: A szörnyek háza,Livello 27: Casa dei Mostri,Level 27: モンスターマンション,레벨 27: 괴물 콘도,,Nivå 27: Monsterleiligheten,Level 27: Apartament Potworów,Fase 27: Mansão dos Monstros,Nível 27: Condomínio Monstruoso,Nivelul 27: Casa monștrilor,Уровень №27: Жилище монстров,Level 27: Боравишта монструма,Nivå 27: Monster Condo,Seviye 27: Canavar Dairesi +Level 28: The Spirit World,HUSTR_28,,,,Level 28: Onen svět,Level 28: Åndeverdenen,Level 28: Die Geisterwelt,Επίπεδο 28: Ο Κόσμος των Πνευμάτων,Nivelo 28: La Animo-Mondo,Nivel 28: El Mundo Espiritual,,Taso 28: Henkimaailma,NIVEAU 28: Le Monde Spirituel,28. Pálya: A lelkek világa,Livello 28: Il Mondo dello Spirito,Level 28: 悪霊の世界,레벨 28: 영령의 세계,Level 28: De geestenwereld,Nivå 28: Åndeverdenen,Level 28: Świat Dusz,Fase 28: O Mundo Espiritual,Nível 28: O Mundo Espiritual,Nivelul 28: Lumea duhurilor,Уровень №28: Мир духов,Level 28: Духовни свет,Nivå 28: Den andliga världen,Seviye 28: Ruhlar Dünyası +Level 29: The Living End,HUSTR_29,,,,Level 29: Živoucí konec,Level 29: Den levende ende,Level 29: Das lebende Ende,Επίπεδο 29: Το Ζωντανό Τέλος,Nivelo 29: La Viva Fino,Nivel 29: El Final Viviente,,Taso 29: Elävä loppu,NIVEAU 29: La Limite,29. Pálya: Az élő Végzet,Livello 29: La Fine Imminente,Level 29: 極限の存在,레벨 29: 최종점,Level 29: Het levende einde,Nivå 29: Den levende enden,Level 29: Żywy Koniec,Fase 29: O Cúmulo da Existência,Nível 29: O Cúmulo da Existência,Nivelul 29: Sfârșitul întregii vieți,Уровень №29: Конец всего живого,Level 29: Крај живота,Nivå 29: Det levande slutet,Seviye 29: Yaşamın Sonu +Level 30: Icon of Sin,HUSTR_30,,,,Level 30: Ikona hříchu,Level 30: Syndens ikon,Level 30: Symbol der Sünde,Επίπεδο 30: Σύμβολο της Αμαρτίας,Nivelo 30: Ikono de Peko,Nivel 30: Icono del pecado,Nivel 30: Ícono del pecado,Taso 30: Synnin ikoni,NIVEAU 30: L'Icône du Péché,30. Pálya: A megtestesült bűn,Livello 30: Icona del Peccato,Level 30: 罪の聖像,레벨 30: 죄악의 상징,Level 30: Pictogram van de zonde,Nivå 30: Syndens ikon,Level 30: Ikona Grzechu,Fase 30: Ícone do Pecado,Nível 30: Ícone do Pecado,Nivelul 30: Icoana păcatelor,Уровень №30: Икона греха,Level 30: Икона греха,Nivå 30: Syndens ikon,Seviye 30: Günah Simgesi +Level 31: Wolfenstein,HUSTR_31,,,,,,,,Nivelo 31: Wolfenstein,Nivel 31: Wolfenstein,,,,31. Pálya: Wolfenstein,Livello 31: Wolfenstein,Level 31: ウルフェンシュタイン,레벨 31: 울펜슈타인,,,,Fase 31: Wolfenstein,Nível 31: Wolfenstein,Nivelul 31: Wolfenstein,Уровень №31: Вольфенштайн,Level 31: Волфенштајн,Nivå 31: Wolfenstein,Seviye 31: Wolfenstein +Level 32: Grosse,HUSTR_32,,,,,,,,Nivelo 32: Grosse,Nivel 32: Grosse,,,,32. Pálya: Grosse,Livello 32: Grosse,Level 32: グローシュ,레벨 32: 그로세,,,,Fase 32: Grosse,Nível 32: Grosse,Nivelul 32: Grosse,Уровень №32: Гросс,Level 32: Гроссе,Nivå 32: Grosse,Seviye 32: Grosse +Level 31: IDKFA,HUSTR_31B,,,,,,,,Nivelo 31: IDKFA,Nivel 31: IDKFA,,,NIVEAU 31: IDKFQ,31. Pálya: IDKFA,Livello 31: IDKFA,Level 31: IDKFA,레벨 31: IDKFA,,,,Fase 31: IDKFA,Nível 31: IDKFA,Nivelul 31: IDKFA,Уровень №31: IDKFA,,Nivå 31: IDKFA,Seviye 31: IDKFA +Level 32: Keen,HUSTR_32B,,,,,,,,Nivelo 32: Keen,Nivel 32: Keen,,,,32. Pálya: Keen,Livello 32: Keen,Level 32: キーン,레벨 32: 킨,,,,Fase 32: Keen,Nível 32: Keen,Nivelul 32: Keen,Уровень №32: Кин,Level 32: Кин,Nivå 32: Keen,Seviye 32: Keen +Level 33: Betray,HUSTR_33,,,,Level 33: Zraď,Level 33: Forræderi,Level 33: Verrat,,Nivelo 33: Perfido,Nivel 33: Traición,,Taso 33: Petä,NIVEAU 33: Trahison,33. Pálya: Árulás,Livello 33: Tradimento ,Level 33: 裏切り,레벨 33: 배반,Level 33: Verraad,Nivå 33: Forråde,Level 33: Zdrada,Fase 33: Traição,Nível 33: Traição,Nivelul 33: Trădare,Уровень №33: Предай,Level 33: Издаја,Nivå 33: Förråda,Seviye 33: İhanet +,,No Rest For The Living,,,,,,,,,,,,,,,,,,,,,,,,, +Level 1: The Earth Base,NHUSTR_1,,,,Level 1: Pozemská základna,Level 1: Jordbasen,Level 1: Die Erd-Basis,,Nivelo 1: La Tera Bazo,Nivel 1: La Base Terrestre,,Taso 1: Maatukikohta,NIVEAU 1: La Base Terrienne,1. Pálya: A földi bázis,Livello 1: La Base Terrestre ,Level 1: 地球基地,레벨 1: 지구 기지,Level 1: De basis van de aarde,Nivå 1: Jordbasen,Level 1: Ziemska Baza,Fase 1: A Base Terrestre,Nível 1: A Base Terrestre,Nivelul 1: Baza terestră,Уровень №1: База на Земле,Level 1: Земаљска база,Nivå 1: Jordbasen,Seviye 1: Dünya Üssü +Level 2: The Pain Labs,NHUSTR_2,,,,Level 2: Laboratoře bolesti,Level 2: Smerte laboratorier,Level 2: Die Folterlabore,,Nivelo 2: La Doloro-Laboratorio,Nivel 2: Los Laboratorios del Dolor,,Taso 2: Tuskalaboratoriot,NIVEAU 2: Les Laboratoires de la Douleur,2. Pálya: A kínok laboratóriuma,Livello 2: I Laboratori del Dolore,Level 2: 生物工学実験室,레벨 2: 고통의 연구소,Level 2: De pijnlaboratoria,Nivå 2: Smertelaboratoriet,Level 2: Laboratoria Bólu,Fase 2: Os Laboratórios da Dor,Nível 2: Os Laboratórios da Dor,Nivelul 2: Laboratoarele durerii,Уровень №2: Лаборатории боли,Level 2: Лабораторије патње,Nivå 2: Smärtlaboratorierna,Seviye 2: Ağrı Laboratuvarları +Level 3: Canyon of The Dead,NHUSTR_3,,,,Level 3: Kaňon mrtvých,Level 3: De dødes kløft,Level 3: Schlucht der Toten,,Nivelo 3: Kanjono de La Mortintoj,Nivel 3: Cañón de los Muertos,,Taso 3: Kalmankanjoni,NIVEAU 3: Canyon des Morts,3. Pálya: A holtak szurdoka,Livello 3: Il Canyon dei Morti,Level 3: 死の渓谷,레벨 3: 죽음의 계곡,Level 3: Canyon van de doden,Nivå 3: De dødes kløft,Level 3: Kanion Umarłych,Fase 3: Desfiladeiro dos Mortos,Nível 3: Desfiladeiro dos Mortos,Nivelul 3: Canionul morților,Уровень №3: Каньон мертвецов,Level 3: Кањон мртваца,Nivå 3: De dödas kanjon,Seviye 3: Ölüler Kanyonu +Level 4: Hell Mountain,NHUSTR_4,,,,Level 4: Pekelná hora,Level 4: Helvede bjerg,Level 4: Höllenberg,,Nivelo 4: Monto de Infero,Nivel 4: Montaña Infernal,,Taso 4: Hornanvuori,NIVEAU 4: Montagne Infernale,4. Pálya: Pokol-hegy,Livello 4: Montagna Infernale ,Level 4: 地獄山脈,레벨 4: 지옥의 산,Level 4: Helleberg,Nivå 4: Helvetesfjellet,Level 4: Piekielna Góra,Fase 4: Montanha Infernal,Nível 4: Montanha Infernal,Nivelul 4: Muntele infernal,Уровень №4: Адская гора,Level 4: Планина пакла,Nivå 4: Helvetesberget,Seviye 4: Cehennem Dağı +Level 5: Vivisection,NHUSTR_5,,,,Level 5: Vivisekce,Level 5: Vivisektion,Level 5: Vivisektion,,Nivelo 5: Vivisekcio,Nivel 5: Vivisección,,Taso 5: Vivisektio,NIVEAU 5: Vivisection,5. Pálya: Élveboncolás,Livello 5: Vivisezione ,Level 5: 生体解剖,레벨 5: 생체 해부,Level 5: Vivisectie,Nivå 5: Viviseksjon,Level 5: Wiwisekcja,Fase 5: Vivissecção,Nível 5: Vivissecção,Nivelul 5: Vivisecție,Уровень №5: Вивисекция,Level 5: Вивисекција,Nivå 5: Vivisektion,Seviye 5: Canlı Kesim +Level 6: Inferno of Blood,NHUSTR_6,,,,Level 6: Krvavé inferno,Level 6: Blodets inferno,Level 6: Blutiges Inferno,,Nivelo 6: Brulego de Sango,Nivel 6: Hoguera de Sangre,,Taso 6: Veri-inferno,NIVEAU 6: Enfer Sanglant,6. Pálya: Véres alvilág,Livello 6: Inferno di Sangue ,Level 6: 血のインフェルノ,레벨 6: 연옥의 피,Level 6: Bloederige inferno,Nivå 6: Blodets inferno,Level 6: Piekło Krwi,Fase 6: Inferno de Sangue,Nível 6: Inferno de Sangue,Nivelul 6: Infern sângeriu,Уровень №6: Кровавая преисподняя,Level 6: Ватре крви,Nivå 6: Blodets inferno,Seviye 6: Kan Cehennemi +Level 7: Baron's Banquet,NHUSTR_7,,,,Level 7: Baronova hostina,Level 7: Baron's Banquet,Level 7: Das Bankett des Barons,,Nivelo 7: Festeno de Barono,Nivel 7: Banquete del Barón,,Taso 7: Paronin pidot,NIVEAU 7: Banquet du Baron,7. Pálya: A báró bankettje,Livello 7: Il Banchetto del Barone ,Level 7: バロンの晩餐,레벨 7: 남작의 연회,Level 7: Baron's banket,Nivå 7: Baronens bankett,Level 7: Bankiet Barona,Fase 7: Banquete do Barão,Nível 7: Banquete do Barão,Nivelul 7: Banchetul baronilor,Уровень №7: Банкет у барона,Level 7: Баронова Гозба,Nivå 7: Baronens bankett,Seviye 7: Baron'un Ziyafeti +Level 8: Tomb of Malevolence,NHUSTR_8,,,,Level 8: Hrobka zlovolnosti,Level 8: Ondskabens grav,Level 8: Feindselige Gruft,,Nivelo 8: Tombo de Malbonvolo,Nivel 8: Tumba de Malevolencia,,Taso 8: Pahantahdon hauta,NIVEAU 8: Tombe Maléfique,8. Pálya: A Gátlástalanság sírja,Livello 8: Tomba della Malevolenza,Level 8: 悪意の墓,레벨 8: 증오의 무덤,Level 8: Graf van kwaadwilligheid,Nivå 8: Ondskapens grav,Level 8: Grobowiec Zła,Fase 8: Tumba da Malevolência,Nível 8: Túmulo da Malevolência,Nivelul 8: Mormântul răutății,Уровень №8: Гробница злобы,Level 8: Гроб злобе,Nivå 8: Ondskans grav,Seviye 8: Kötülük Mezarı +Level 9: March of The Demons,NHUSTR_9,,,,Level 9: Pochod démonů,Level 9: Dæmonernes march,Level 9: Marsch der Dämonen,,Nivelo 9: Marŝo de La Demonoj,Nivel 9: Marcha de los Demonios,,Taso 9: Demonien marssi,NIVEAU 9: Marche des Démons,9. Pálya: A démonok parádéja,Livello 9: La Marcia dei Demoni ,Level 9: デーモンの行進,레벨 9: 악마들의 행진,Level 9: Maart van de demonen,Nivå 9: Demonenes marsj,Level 9: Marsz Demonów,Fase 9: Marcha dos Demônios,Nível 9: Marcha dos Demônios,Nivelul 9: Marșul demonilor,Уровень №9: Шествие демонов,Level 9: Марш демона,Nivå 9: Demonernas marsch,Seviye 9: Şeytanların Yürüyüşü +,,Plutonia,,,,,,,,,,,,,,,,,,,,,,,,, +Level 1: Congo,PHUSTR_1,,,,Level 1: Kongo,,Level 1: Kongo,,Nivelo 1: Kongo,Nivel 1: Congo,,Taso 1: Kongo,NIVEAU 1: Congo,1. Pálya: Kongó,Livello 1: Congo,Level 1: コンゴ川,레벨 1: 콩고,Level 1: Kongo,Nivå 1: Kongo,Level 1: Kongo,Fase 1: Congo,Nível 1: Congo,Nivelul 1: Congo,Уровень №1: Конго,Level 1: Конго,Nivå 1: Kongo,Seviye 1: Kongo +Level 2: Well of Souls,PHUSTR_2,,,,Level 2: Studna duší,Level 2: Sjælebrønden,Level 2: Seelenbrunnen,,Nivelo 2: Puto de animoj,Nivel 2: Pozo de almas,,Taso 2: Sielujen lähde,NIVEAU 2: Puits des Ames,2. Pálya: A lelkek kútja,Livello 2: Pozzo delle Anime,Level 2: 魂の井戸,레벨 2: 영혼의 우물,Level 2: Bron van zielen,Nivå 2: Sjelenes brønn,Level 2: Studnia Dusz,Fase 2: Poço das Almas,Nível 2: Poço de Almas,Nivelul 2: Fântâna sufletelor,Уровень №2: Колодец душ,Level 2: Бунар душа,Nivå 2: Själarnas brunn,Seviye 2: Ruhlar Kuyusu +Level 3: Aztec,PHUSTR_3,,,,Level 3: Azték,Level 3: Azteker,Level 3: Aztekisch,,Nivelo 3: Azteko,Nivel 3: Azteca,,Taso 3: Asteekki,NIVEAU 3: Aztèque,3. Pálya: Azték,Livello 3: Aztec,Level 3: アステカ,레벨 3: 아즈텍,Level 3: Azteken,Nivå 3: Aztekisk,Level 3: Aztek,Fase 3: Asteca,Nível 3: Asteca,Nivelul 3: Aztec,Уровень №3: Ацтек,Level 3: Астек,Nivå 3: Azteker,Seviye 3: Aztek +Level 4: Caged,PHUSTR_4,,,,Level 4: V kleci,Level 4: Låst op,Level 4: Eingesperrt,,Nivelo 4: Enkaĝigita,Nivel 4: Enjaulado,,Taso 4: Häkissä,NIVEAU 4: Enfermé,4. Pálya: Ketrecbe zárva,Livello 4: Ingabbiato,Level 4: 檻の中,레벨 4: 갇히다,Level 4: Gekooid,Nivå 4: Buret,Level 4: W Klatce,Fase 4: Na Jaula,Nível 4: Na Jaula,Nivelul 4: Încarcerat,Уровень №4: В клетке,Level 4: Заробљен,Nivå 4: Burad,Seviye 4: Kafesli +Level 5: Ghost Town,PHUSTR_5,,,,Level 5: Město duchů,Level 5: Spøgelsesby,Level 5: Geisterstadt,,Nivelo 5: Fantoma urbeto,Nivel 5: Pueblo Fantasma,,Taso 5: Aavekaupunki,NIVEAU 5: Ville Fantôme,5. Pálya: Szellemváros,Livello 5: Città Fantasma,Level 5: ゴーストタウン,레벨 5: 유령 도시,Level 5: Spookstad,Nivå 5: Spøkelsesbyen,Level 5: Miasto Duchów,Fase 5: Cidade Fantasma,Nível 5: Cidade Fantasma,Nivelul 5: Orașul fantomă,Уровень №5: Город-призрак,Level 5: Град духова,Nivå 5: Spökstad,Seviye 5: Hayalet Kasaba +Level 6: Baron's Lair,PHUSTR_6,,,,Level 6: Baronovo doupě,Level 6: Baronens hule,Level 6: Lager des Barons,,Nivelo 6: Kaŝejo de Barono,Nivel 6: Guarida del Barón,,Taso 6: Paronin luola,NIVEAU 6: Repaire du Baron,6. Pálya: A báró rejteke,Livello 6: Tana del Barone,Level 6: バロンの隠れ家,레벨 6: 남작의 은신처,Level 6: Baron's kamp,Nivå 6: Baronens hule,Level 6: Legowisko Barona,Fase 6: Covil do Barão,Nível 6: Covil do Barão,Nivelul 6: Claustrul Baronului,Уровень №6: Обитель барона,Level 6: Баронова јазбина,Nivå 6: Baronens lya,Seviye 6: Baron'un İni +Level 7: Caughtyard,PHUSTR_7,,,,Level 7: Karcer,,Level 7: Gehege,,Nivelo 7: Kaptkorto,Nivel 7: Campo de Concentración,,Taso 7: Posenpiha,NIVEAU 7: Pris de court,7. Pálya: A foglyok udvara,Livello 7: Cortile Prigione,Level 7: 囚われの庭,레벨 7: 포획마당,Level 7: Omheining,Nivå 7: Fangegården,Level 7: Dziedziniec Więzienny,Fase 7: Campo de Concentração,Nível 7: Campo de Concentração,Nivelul 7: Capcana curții,Уровень №7: Ловчий двор,Level 7: Замчиште,Nivå 7: Fångården,Seviye 7: Caughtyard +Level 8: Realm,PHUSTR_8,,,,Level 8: Říše,Level 8: Rige,Level 8: Bereich,,Nivelo 8: Regno,Nivel 8: Reino,,Taso 8: Valtapiiri,NIVEAU 8: Royaume,8. Pálya: Uradalom,Livello 8: Regno,Level 8: 領地,레벨 8: 왕국,Level 8: Rijk,Nivå 8: Riket,Level 8: Królestwo,Fase 8: Reino,Nível 8: Reino,Nivelul 8: Tărâm,Уровень №8: Царство,Level 8: Царство,Nivå 8: Riket,Seviye 8: Diyar +Level 9: Abattoire,PHUSTR_9,,,,Level 9: Jatka,,Level 9: Schlachthaus,,Nivelo 9: Buĉejo,Nivel 9: Matadero,,Taso 9: Teurastamo,NIVEAU 9: Abattoir,9. Pálya: Vágóhíd,Livello 9: Mattatoio,Level 9: 屠殺場,레벨 9: 도축장,Level 9: Abattoir,Nivå 9: Slakteriet,Level 9: Rzeźnia,Fase 9: Matadouro,Nível 9: Matadouro,Nivelul 9: Abator,Уровень №9: Абатство,Level 9: Кланица,Nivå 9: Slakthus,Seviye 9: Abattoire +Level 10: Onslaught,PHUSTR_10,,,,Level 10: Nájezd,Level 10: Stormløb,Level 10: Angriff,,Nivelo 10: Buĉado,Nivel 10: Arremetida,,Taso 10: Ryntäys,NIVEAU 10: Assaut,10. Pálya: Roham,Livello 10: Assalto,Level 10: 猛襲,레벨 10: 맹공격,Level 10: Aanval,Nivå 10: Angrep,Level 10: Szturm,Fase 10: Investida,Nível 10: Investida,Nivelul 10: Năvala,Уровень №10: Натиск,Level 10: Јуриш,Nivå 10: Angrepp,Seviye 10: Saldırı +Level 11: Hunted,PHUSTR_11,,,,Level 11: Loven,Level 11: Jaget,Level 11: Gehetzt,,Nivelo 11: Ĉasata,Nivel 11: Cazado,,Taso 11: Metsästetty,NIVEAU 11: Traque,11. Pálya: Űzött vad,Livello 11: Braccato,Level 11: 逃走,레벨 11: 사냥당함,Level 11: Gejaagd,Nivå 11: Jaget,Level 11: Nawiedzony,Fase 11: Perseguição,Nível 11: Perseguição,Nivelul 11: Vânătoarea,Уровень №11: Преследуемый,Level 11: Уловљен,Nivå 11: Jaktad,Seviye 11: Avlanmış +Level 12: Speed,PHUSTR_12,,,,Level 12: Rychlost,Level 12: Fart,Level 12: Tempo,,Nivelo 12: Rapido,Nivel 12: Velocidad,,Taso 12: Vauhti,NIVEAU 12: Vitesse,12. Pálya: Iram,Livello 12: Velocità,Level 12: スピード,레벨 12: 스피드,Level 12: Haast,Nivå 12: Hastighet,Level 12: Pęd,Fase 12: Velocidade,Nível 12: Velocidade,Nivelul 12: Viteză,Уровень №12: Скорость,Level 12: Брзина,Nivå 12: Hastighet,Seviye 12: Hız +Level 13: The Crypt,PHUSTR_13,,,,Level 13: Krypta,Level 13: Krypten,Level 13: Die Gruft,,Nivelo 13: La kripto,Nivel 13: La cripta,,Taso 13: Krypta,NIVEAU 13: La Crypte,13. Pálya: A kripta,Livello 13: La Cripta,Level 13: 地下聖堂,레벨 13: 봉안당,Level 13: De crypte,Nivå 13: Krypten,Level 13: Krypta,Fase 13: A Cripta,Nível 13: A Cripta,Nivelul 13: Cripta,Уровень №13: Склеп,Level 13: Гробница,Nivå 13: Kryptan,Seviye 13: Mahzen +Level 14: Genesis,PHUSTR_14,,,,,,,,Nivelo 14: Genezo,Nivel 14: Génesis,,Taso 14: Luominen,NIVEAU 14: Genèse,14. Pálya: Teremtés,Livello 14: Genesi,Level 14: 創世記,레벨 14: 창세기,,,Level 14: Geneza,Fase 14: Gênese,Nível 14: Gênese,Nivelul 14: Geneza,Уровень №14: Зарождение,Level 14: Постанак,Nivå 14: Genesis,Seviye 14: Yaratılış +Level 15: The Twilight,PHUSTR_15,,,,Level 15: Soumrak,Level 15: Tusmørket,Level 15: Zwielicht,,Nivelo 15: La krepusko,Nivel 15: El ocaso,,Taso 15: Hämärä,NIVEAU 15: Le Crépuscule,15. Pálya: Alkonyat,Livello 15: Il Crepuscolo,Level 15: 黄昏,레벨 15: 황혼,Level 15: De schemering,Nivå 15: Skumringen,Level 15: Zmierzch,Fase 15: O Crepúsculo,Nível 15: O Crepúsculo,Nivelul 15: Amurgul,Уровень №15: Сумерки,Level 15: Сумрак,Nivå 15: Skymningen,Seviye 15: Alacakaranlık +Level 16: The Omen,PHUSTR_16,,,,Level 16: Znamení,Level 16: Omenet,Level 16: Das Omen,,Nivelo 16: La Aŭguro,Nivel 16: El Presagio,,Taso 16: Enne,NIVEAU 16: Le Présage,16. Pálya: Az Ómen,Livello 16: Il Presagio,Level 16: 予兆,레벨 16: 징조,Level 16: De omen,Nivå 16: Varselet,Level 16: Omen,Fase 16: O Presságio,Nível 16: O Presságio,Nivelul 16: Prevestirea,Уровень №16: Предзнаменование,Level 16: Знамење,Nivå 16: Omen,Seviye 16: Omen +Level 17: Compound,PHUSTR_17,,,,Level 17: Ústav,Level 17: Forbindelsen,Level 17: Anlage,,Nivelo 17: Konstruaĵaro,Nivel 17: Complejo,,Taso 17: Laitos,NIVEAU 17: Installation,17. Pálya: Létesítmény,Livello 17: Recinto,Level 17: 調合,레벨 17: 복합체,Level 17: Faciliteit,Nivå 17: Forbindelsen,Level 17: Mieszanka,Fase 17: Complexo,Nível 17: Complexo,Nivelul 17: Complexul,Уровень №17: Комплекс,Level 17: Једињење,Nivå 17: Förbandet,Seviye 17: Bileşik +Level 18: Neurosphere,PHUSTR_18,,,,Level 18: Neurosféra,Level 18: Neurosfæren,Level 18: Neurosphäre,,Nivelo 18: Neŭrosfero,Nivel 18: Neuroesfera,,Taso 18: Neurosfääri,NIVEAU 18: Neurosphère,18. Pálya: Neuroszféra,Livello 18: Neurosfera,Level 18: ニューロスフィア,레벨 18: 뉴로스피어,Level 18: Neurosferen,Nivå 18: Nevrosfæren,Level 18: Neurosfera,Fase 18: Neurosfera,Nível 18: Neurosfera,Nivelul 18: Neurosferă,Уровень №18: Нейросфера,Level 18: Неуросфера,Nivå 18: Neurosfären,Seviye 18: Nörosfer +Level 19: NME,PHUSTR_19,"“NME” read out loud means “enemy”, so translators should consider the translation of “enemy” into their language.",,,Level 19: Nepřítel,,,,Nivelo 19: Mal-BN,Nivel 19: N-MIGO,,Taso 19: VHLLNN,NIVEAU 19: NMI,19. Pálya: LNSG,Livello 19: NMIC,Level 19: 野郎,레벨 19: NOM,,,Level 19: WRG,Fase 19: N-MIGO,Nível 19: N-MIGO,Nivelul 19: INMIC,Уровень №19: В.Р.А.Г.,Level 19: Н.Е.П.Р.,Nivå 19: FiND,Seviye 19: NME +Level 20: The Death Domain,PHUSTR_20,,,,Level 20: Panství smrti,Level 20: Dødsdomænet,Level 20: Die Todeszone,,Nivelo 20: La morta regno,Nivel 20: El Dominio Mortal,,Taso 20: Kuoleman piiri,NIVEAU 20: Le Domaine de la Mort,20. Pálya: A holtak birtoka,Livello 20: Il Dominio della Morte,Level 20: 死の領域,레벨 20: 죽음의 영역,Level 20: Het domein van de dood,Nivå 20: Dødens domene,Level 20: Domena Śmierci,Fase 20: O Domínio da Morte,Nível 20: O Domínio da Morte,Nivelul 20: Domeniul morții,Уровень №20: Владения смерти,Level 20: Подручије смрти,Nivå 20: Dödsdomänen,Seviye 20: Ölüm Alanı +Level 21: Slayer,PHUSTR_21,,,,Level 21: Zabiják,Level 21: Slagter,Level 21: Töter,,Nivelo 21: Mortigisto,Nivel 21: Descuatizador,,Taso 21: Tappaja,NIVEAU 21: Pourfendeur,21. Pálya: Halálosztó,Livello 21: Assassino,Level 21: スレイヤー,레벨 21: 슬레이어,Level 21: Doder,Nivå 21: Slakteren,Level 21: Pogromca,Fase 21: Matador,Nível 21: Matador,Nivelul 21: Ucigător,Уровень №21: Истребитель,Level 21: Убица,Nivå 21: Jägare,Seviye 21: Avcı +Level 22: Impossible Mission,PHUSTR_22,,,,Level 22: Nemožná mise,Level 22: Umulig mission,Level 22: Unmögliche Mission,,Nivelo 22: Neebla tasko,Nivel 22: Misión imposible,,Taso 22: Mahdoton tehtävä,NIVEAU 22: Mission Impossible,22. Pálya: Lehetetlen küldetés,Livello 22: Missione Impossibile,Level 22: 不可能な任務,레벨 22: 임파서블 미션,Level 22: Onmogelijke missie,Nivå 22: Umulig oppdrag,Level 22: Niemożliwa Misja,Fase 22: Missão Impossível,Nível 22: Missão Impossível,Nivelul 22: Misiune imposibilă,Уровень №22: Невыполнимое задание,Level 22: Немогућа мисија,Nivå 22: Omöjligt uppdrag,Seviye 22: İmkansız Görev +Level 23: Tombstone,PHUSTR_23,,,,Level 23: Náhrobek,Level 23: Gravsten,Level 23: Grabstein,,Nivelo 23: Tombŝtono,Nivel 23: Lápida,,Taso 23: Hautakivi,NIVEAU 23: Pierre Tombale,23. Pálya: Sírkő,Livello 23: Pietra Tombale,Level 23: 墓石,레벨 23: 묘비,Level 23: Grafsteen,Nivå 23: Gravstein,Level 23: Nagrobek,Fase 23: Lápide,Nível 23: Lápide,Nivelul 23: Piatra de mormânt,Уровень №23: Надгробие,Level 23: Надгробни споменик,Nivå 23: Gravsten,Seviye 23: Mezar Taşı +Level 24: The Final Frontier,PHUSTR_24,,,,Level 24: Poslední hranice,Level 24: Den endelige grænse,Level 24: Die letzte Grenze,,Nivelo 24: La Fina Limo,Nivel 24: La Frontera Final,Nivel 24: La Última Frontera,Taso 24: Viimeinen rajamaa,NIVEAU 24: La Frontière Finale,24. Pálya: A végső határ,Livello 24: La Frontiera Finale,Level 24: 最後のフロンティア,레벨 24: 최후의 개척지,Level 24: De eindgrens,Nivå 24: Den siste grensen,Level 24: Ostateczna Granica,Fase 24: A Fronteira Final,Nível 24: A Fronteira Final,Nivelul 24: Ultima frontieră,Уровень №24: Последний рубеж,Level 24: Коначна граница,Nivå 24: Den sista gränsen,Seviye 24: Son Sınır +Level 25: The Temple of Darkness,PHUSTR_25,,,,Level 25: Chrám temna,Level 25: Mørkets tempel,Level 25: Der Tempel der Dunkelheit,,Nivelo 25: La Idolejo de Mallumo,Nivel 25: El Templo de la Oscuridad,,Taso 25: Pimeyden temppeli,NIVEAU 25: Le Temple des Ténèbres,25. Pálya: A sötétség temploma,Livello 25: Il Tempio dell'Oscurità,Level 25: 暗黒の神殿,레벨 25: 어둠의 신전,Level 25: De tempel van de duisternis,Nivå 25: Mørkets tempel,Level 25: Świątynia Mroku,Fase 25: O Templo da Escuridão,Nível 25: O Templo da Escuridão,Nivelul 25: Templul tenebros,Уровень №25: Храм тьмы,Level 25: Храм таме,Nivå 25: Mörkrets tempel,Seviye 25: Karanlığın Tapınağı +Level 26: Bunker,PHUSTR_26,,,,Level 26: Bunkr,,,,Nivelo 26: Bunkro,Nivel 26: Búnker,,Taso 26: Bunkkeri,NIVEAU 26: Bunker,26. Pálya: Bunker,Livello 26: Bunker,Level 26: バンカー,레벨 26: 방공호,,,Level 26: Bunkier,Fase 26: Casamata,Nível 26: Bunker,Nivelul 26: Buncăr,Уровень №26: Бункер,Level 26: Бункер,Nivå 26: Bunker,Seviye 26: Sığınak +Level 27: Anti-christ,PHUSTR_27,,,,Level 27: Antikrist,,Level 27: Antichrist,,Nivelo 27: Antikristo,Nivel 27: Anticristo,,Taso 27: Antikristus,NIVEAU 27: Anti-Christ,27. Pálya: Antikrisztus,Livello 27: Anticristo,Level 27: アンチキリスト,레벨 27: 적그리스도,Level 27: Antichrist,Nivå 27: Antikrist,Level 27: Antychryst,Fase 27: Anticristo,Nível 27: Anticristo,Nivelul 27: Antihrist,Уровень №27: Антихрист,Level 27: Антихрист,Nivå 27: Antikrist,Seviye 27: Mesih Karşıtı +Level 28: The Sewers,PHUSTR_28,,,,Level 28: Kanály,Level 28: Kloakkerne,Level 28: Kanäle,,Nivelo 28: La Kanalo,Nivel 28: Las Alcantarillas,,Taso 28: Viemärit,NIVEAU 28: Les Egouts,28. Pálya: A kanális,Livello 28: Le Fogne,Level 28: 下水道,레벨 28: 하수구,Level 28: De rioleringen,Nivå 28: Kloakken,Level 28: Ścieki,Fase 28: Os Esgotos,Nível 28: Os Esgotos,Nivelul 28: Canalizarea,Уровень №28: Канализация,Level 28: Канализација,Nivå 28: Sjukhusen,Seviye 28: Kanalizasyonlar +Level 29: Odyssey of Noises,PHUSTR_29,,,,Level 29: Odysea křiku,Level 29: Lydenes odyssé,Level 29: Odyssee der Geräusche,,Nivelo 29: Vojaĝo de Sonoj,Nivel 29: Odisea de Ruidos,,Taso 29: Äänten harharetki,NIVEAU 29: Odysée de Bruits,29. Pálya: A moraj ösvénye,Livello 29: Odissea dei Rumori,Level 29: オデッセイのノイズ,레벨 29: 속삭임의 여정,Level 29: Odyssee van geluiden,Nivå 29: Lydenes odyssé,Level 29: Odyseja Wrzawy,Fase 29: Odisséia de Ruidos,Nível 29: Odisséia de Ruidos,Nivelul 29: Odiseea zgomotelor,Уровень №29: Одиссея шумов,Level 29: Одисеја шумова,Nivå 29: Ljudets odyssé,Seviye 29: Seslerin Odyssey'i +Level 30: The Gateway of Hell,PHUSTR_30,,,,Level 30: Brána pekla,Level 30: Helvedes port,Level 30: Tor zur Hölle,,Nivelo 30: La Pordego de Inferno,Nivel 30: La Puerta del Infierno,,Taso 30: Helvetin porttikäytävä,NIVEAU 30: La Porte des Enfers,30. Pálya: Átjáró a pokolba,Livello 30: La Porta dell'Inferno,Level 30: 地獄の関門,레벨 30: 지옥의 차원문,Level 30: De poort van de hel,Nivå 30: Porten til helvete,Level 30: Brama Piekieł,Fase 30: O Portão do Inferno,Nível 30: O Portão do Inferno,Nivelul 30: Poarta spre infern,Уровень №30: Врата ада,Level 30: Пролаз пакла,Nivå 30: Helvetets port,Seviye 30: Cehennem Kapısı +Level 31: Cyberden,PHUSTR_31,,,,Level 31: Kyberdoupě,,Level 31: Cyberbau,,Nivelo 31: Cibernesto,Nivel 31: Ciber-guarida,,Taso 31: Kyberpesä,NIVEAU 31: Cyber-Antre,31. Pálya: Kiberodú,Livello 31: Cybergabbia,Level 31: サイバーの巣,레벨 31: 사이버소굴,,,Level 31: Cybernora,Fase 31: Ciberantro,Nível 31: Ciberantro,Nivelul 31: Cibervizuină,Уровень №31: Киберлогово,Level 31: Сајбер-јазбина,Nivå 31: Cyberden,Seviye 31: Siber'in ini +Level 32: Go 2 It,PHUSTR_32,,,,Level 32: Jdi do toho,,,,Nivelo 32: Iru al ĝi!,Nivel 32: Ve a x ello,Nivel 32: Ve x eso,Taso 32: Iske kii,NIVEAU 32: Go 2 It,32. Pálya: Menj oda!,Livello 32: Dacci Dentro,Level 32: 逝ってこい,레벨 32: 함 해 봐,Level 32: Ga ervoor,,Level 32: Do Dzieła,Fase 32: Vai Fundo,Nível 32: Siga em Frente,Nivelul 32: Du-te la ei,Уровень №32: П0лный вп3рёд,Level 32: Иди ка њему,Nivå 32: Gå till det,Seviye 32: Devam Et +,,TNT: Evilution,,,,,,,,,,,,,,,,,,,,,,,,, +Level 1: System Control,THUSTR_1,,,,Level 1: Administrace,Level 1: Systemkontrol,Level 1: Systemkontrolle,,Nivelo 1: Sistema Kontrolo,Nivel 1: Control del Sistema,,Taso 1: Järjestelmäohjaamo,NIVEAU 1: Système de Contrôle,1. Pálya: Rendszervezérlő,Livello 1: Controllo del Sistema,Level 1: 制御システム,레벨 1: 시스템 제어시설,Level 1: Systeemcontrole,Nivå 1: Systemkontroll,Level 1: Kontrola Systemu,Fase 1: Controle do Sistema,Nível 1: Controlo de Sistema,Nivelul 1: Control sisteme,Уровень №1: Центр управления системой,Level 1: Контролна система,Nivå 1: Systemkontroll,Seviye 1: Sistem Kontrolü +Level 2: Human BBQ,THUSTR_2,,,,Level 2: Člověčí grilovačka,Level 2: Menneskelig grill,Level 2: Menschliches Barbecue,,Nivelo 2: Homo-Kradrostado,Nivel 2: Barbacoa Humana,,Taso 2: Ihmisgrilli,NIVEAU 2: Barbecue Humain,2. Pálya: Emberi grill,Livello 2: Barbecue Umano,Level 2: 人肉晩餐会,레벨 2: 인간 바비큐,Level 2: Menselijke BBQ,Nivå 2: Menneskelig BBQ,Level 2: Ludzki Grill,Fase 2: Churrasco Humano,Nível 2: Churrasco Humano,Nivelul 2: Oameni la grătar,Уровень №2: Барбекю из человечины,Level 2: Људски роштиљ,Nivå 2: Människogrill,Seviye 2: İnsan Barbekü +Level 3: Power Control,THUSTR_3,,,,Level 3: Napájecí vedení,Level 3: Kontrol med magten,Level 3: Energiekontrolle,,Nivelo 3: Energia Kontrolo,Nivel 3: Control de Energía,,Taso 3: Voimalan ohjaamo,NIVEAU 3: Contrôle Energétique,3. Pálya: Energiavezérlő,Livello 3: Centrale Energetica,Level 3: 制御室,레벨 3: 전력 통제소,Level 3: Machtscontrole,Nivå 3: Kraftkontroll,Level 3: Kontrola Zasilania,Fase 3: Controle de Energia,Nível 3: Controlo Energético,Nivelul 3: Uzina,Уровень №3: Центр управления питанием,Level 3: Контролна моћ,Nivå 3: Maktkontroll,Seviye 3: Güç Kontrolü +Level 4: Wormhole,THUSTR_4,,,,Level 4: Červí díra,Level 4: Ormehul,Level 4: Wurmloch,,Nivelo 4: Vermtruo,Nivel 4: Agujero de Gusano,,Taso 4: Madonreikä,NIVEAU 4: Trou de Ver,4. Pálya: Féreglyuk,Livello 4: Wormhole,Level 4: 虫喰い穴,레벨 4: 웜홀,Level 4: Wormgat,Nivå 4: Ormehull,Level 4: Tunel,Fase 4: Buraco de Minhoca,Nível 4: Buraco de Minhoca,Nivelul 4: Gaura de vierme,Уровень №4: Червоточина,Level 4: Црвоточина,Nivå 4: Maskhål,Seviye 4: Solucan Deliği +Level 5: Hanger,THUSTR_5,"Not ""Hangar""",,,Level 5: Hangár,,Level 5: Hangar,,Nivelo 5: Pendigejo,Nivel 5: Colgador,,Taso 5: Lentoalushalli,NIVEAU 5: Hengar,5. Pálya: Horog,Livello 5: Hanga,Level 5: 格納庫,레벨 5: 격납고,Level 5: Hangar,Nivå 5: Hanger,Level 5: Hangar,Fase 5: Hangar,Nível 5: Hangar,Nivelul 5: Hangar,Уровень №5: Ангар,Level 5: Вешалица,Nivå 5: Hängare,Seviye 5: Askı +Level 6: Open Season,THUSTR_6,,,,Level 6: Lovecká sezóna,Level 6: Åben sæson,Level 6: Jagdsaison,,Nivelo 6: Ĉasosezono,Nivel 6: Temporada Abierta,,Taso 6: Avoin sesonki,NIVEAU 6: La Chasse Est Ouverte,6. Pálya: Vadászszezon,Livello 6: Stagione Aperta,Level 6: 狩猟解禁,레벨 6: 사냥철,Level 6: Open seizoen,Nivå 6: Åpen sesong,Level 6: Otwarty Sezon,Fase 6: Temporada Aberta,Nível 6: Época Aberta,Nivelul 6: Sezon deschis,Уровень №6: Сезон охоты,Level 6: Отворена сезона,Nivå 6: Öppen säsong,Seviye 6: Açık Sezon +Level 7: Prison,THUSTR_7,,,,Level 7: Vězení,Level 7: Fængsel,Level 7: Gefängnis,,Nivelo 7: Malliberejo,Nivel 7: Prisión,,Taso 7: Vankila,NIVEAU 7: Prison,7. Pálya: Börtön,Livello 7: Prigione,Level 7: 監獄,레벨 7: 감옥,Level 7: Gevangenis,Nivå 7: Fengsel,Level 7: Więzienie,Fase 7: Prisão,Nível 7: Prisão,Nivelul 7: Închisoare,Уровень №7: Тюрьма,Level 7: Затвор,Nivå 7: Fängelse,Seviye 7: Hapishane +Level 8: Metal,THUSTR_8,,,,Level 8: Kov,,Level 8: Metall,,Nivelo 8: Metalo,Nivel 8: Metal,,Taso 8: Metalli,NIVEAU 8: Métal,8. Pálya: Fém,Livello 8: Metallo,Level 8: メタル,레벨 8: 강철,Level 8: Metaal,Nivå 8: Metall,,Fase 8: Metal,Nível 8: Metal,Nivelul 8: Metal,Уровень №8: Металл,Level 8: Метал,Nivå 8: Metall,Seviye 8: Metal +Level 9: Stronghold,THUSTR_9,,,,Level 9: Pevnost,Level 9: Borgen,Level 9: Festung,,Nivelo 9: Fuorto,Nivel 9: Fortaleza,,Taso 9: Linnake,NIVEAU 9: Forteresse,9. Pálya: Erőd,Livello 9: Fortezza,Level 9: 牙城,레벨 9: 요새,Level 9: Vesting,Nivå 9: Festning,Level 9: Warownia,Fase 9: Fortaleza,Nível 9: Fortaleza,Nivelul 9: Bastion,Уровень №9: Твердыня,Level 9: Упориште,Nivå 9: Fästning,Seviye 9: Kale +Level 10: Redemption,THUSTR_10,,,,Level 10: Vykoupení,Level 10: Forløsning,Level 10: Erlösung,,Nivelo 10: Elaĉeto,Nivel 10: Redención,,Taso 10: Lunastus,NIVEAU 10: Rédemption,10. Pálya: Megváltás,Livello 10: Redenzione,Level 10: 償還,레벨 10: 구원,Level 10: Aflossing,Nivå 10: Innløsning,Level 10: Odkupienie,Fase 10: Redenção,Nível 10: Redenção,Nivelul 10: Răscumpărare,Уровень №10: Искупление,Level 10: Искупљење,Nivå 10: Inlösen,Seviye 10: Kefaret +Level 11: Storage Facility,THUSTR_11,,,,Level 11: Skladiště,Level 11: Opbevaringsanlæg,Level 11: Lagerstätte,,Nivelo 11: Stokejo,Nivel 11: Complejo de Almacenes,Nivel 11: Almacenes,Taso 11: Varastolaitos,NIVEAU 11: Complexe de Stockage,11. Pálya: Raktárépület,Livello 11: Impianto di Stoccaggio,Level 11: 貯蔵施設,레벨 11: 저장소,Level 11: Opslagfaciliteit,Nivå 11: Lagringsanlegg,Level 11: Magazyn,Fase 11: Centro de Armazenamento,Nível 11: Centro de Armazenamento,Nivelul 11: Stația de depozitare,Уровень №11: Склад,Level 11: Складиште,Nivå 11: Förvaringsanläggning,Seviye 11: Depolama Tesisi +Level 12: Crater,THUSTR_12,,,,Level 12: Kráter,Level 12: Krater,Level 12: Krater,,Nivelo 12: Kratero,Nivel 12: Cráter,,Taso 12: Kraateri,NIVEAU 12: Cratère,12. Pálya: Kráter,Livello 12: Cratere,Level 12: 火口,레벨 12: 분화구,Level 12: Krater,Nivå 12: Krater,Level 12: Krater,Fase 12: Cratera,Nível 12: Cratera,Nivelul 12: Crater,Уровень №12: Кратер,Level 12: Кратер,Nivå 12: Krater,Seviye 12: Krater +Level 13: Nukage Processing,THUSTR_13,,,,Level 13: Jaderné zpracování,Level 13: Nukageforarbejdning,Level 13: Nuklearverarbeitung,,Nivelo 13: Nukleaĵo-Traktejo,Nivel 13: Procesamiento de Residuos Nucleares,,Taso 13: Ydinjätekäsittely,NIVEAU 13: Traitement Nucléaire,13. Pálya: Atomhulladék-feldolgozó,Livello 13: Trattamento Nucleare,Level 13: 核廃棄物加工所,레벨 13: 폐기물 처리소,Level 13: Nucleaire verwerking,Nivå 13: Nukage-prosessering,Level 13: Przetwórstwo Jądrowe,Fase 13: Processamento Nuclear,Nível 13: Processamento Nuclear,Nivelul 13: Prelucrarea deșeurilor nucleare,Уровень №13: Переработка ядерных отходов,Level 13: Прерада нуклеарног отпада,Nivå 13: Kärnavfall Behandling,Seviye 13: Nukage İşleme +Level 14: Steel Works,THUSTR_14,,,,Level 14: Ocelárna,Level 14: Stålværk,Level 14: Stahlwerk,,Nivelo 14: Ŝtalejo,Nivel 14: Siderúrgica,Nivel 14: Siderurgia,Taso 14: Terästehdas,NIVEAU 14: Aciérie,14. Pálya: Acélművek,Livello 14: Acciaieria,Level 14: 製鉄所,레벨 14: 제강소,Level 14: Staalfabrieken,Nivå 14: Stålverk,Level 14: Huta,Fase 14: Siderúrgica,Nível 14: Siderúrgica,Nivelul 14: Oțelărie,Уровень №14: Сталелитейный завод,Level 14: Челичана,Nivå 14: Stålverk,Seviye 14: Çelik İşleri +Level 15: Dead Zone,THUSTR_15,,,,Level 15: Mrtvá zóna,Level 15: Død zone,Level 15: Tote Zone,,Nivelo 15: Senvivzono,Nivel 15: Zona Muerta,,Taso 15: Kuollut alue,NIVEAU 15: Zone Morte,15. Pálya: A holtak zónája,Livello 15: Zona Morta,Level 15: 危険地帯,레벨 15: 사각지대,Level 15: Dode zone,Nivå 15: Død sone,Level 15: Martwa Strefa,Fase 15: Zona Morta,Nível 15: Zona Morta,Nivelul 15: Zona moartă,Уровень №15: Мёртвая зона,Level 15: Зона смрти,Nivå 15: Dödszon,Seviye 15: Ölü Bölge +Level 16: Deepest Reaches,THUSTR_16,,,,Level 16: Nejhlubší sluje,Level 16: De dybeste afkroge,Level 16: Tiefe,,Nivelo 16: Plejsubejo,Nivel 16: Recodos profundos,,Taso 16: Syvyydet,NIVEAU 16: Profondeurs,16. Pálya: A legmélyebb pont,Livello 16: Profondità,Level 16: 最深部,레벨 16: 깊숙한 강,Level 16: Diepste reiken,Nivå 16: De dypeste områdene,Level 16: Głębiny,Fase 16: Profundezas,Nível 16: Profundezas,Nivelul 16: În adâncuri,Уровень №16: Глубочайшие достижения,Level 16: Најдубља дубина,Nivå 16: De djupaste hålen,Seviye 16: En Derin Erişimler +Level 17: Processing Area,THUSTR_17,,,,Level 17: Kombinát,Level 17: Forarbejdningsområde,Level 17: Verarbeitungsbereich,,Nivelo 17: Traktadareo,Nivel 17: Área de Procesamiento,,Taso 17: Käsittelyalue,NIVEAU 17: Zone de Traitement,17. Pálya: Feldolgozó,Livello 17: Area di Elaborazione,Level 17: 処理地帯,레벨 17: 처리 구역,Level 17: Verwerkingsgebied,Nivå 17: Behandlingsområde,Level 17: Strefa Przerobowa,Fase 17: Área de Processamento,Nível 17: Área de Processamento,Nivelul 17: Aria de procesare,Уровень №17: Зона обработки,Level 17: Подручје обраде,Nivå 17: Bearbetningsområde,Seviye 17: İşleme Alanı +Level 18: Mill,THUSTR_18,,,,Level 18: Mlýn,Level 18: Mølle,Level 18: Mühle,,Nivelo 18: Muelejo,Nivel 18: Molino,,Taso 18: Mylly,NIVEAU 18: Fonderie,18. Pálya: Malom,Livello 18: Fonderia,Level 18: 製粉所,레벨 18: 제분소,Level 18: Molen,Nivå 18: Mølle,Level 18: Młyn,Fase 18: Moinho,Nível 18: Moinho,Nivelul 18: Moara,Уровень №18: Завод,Level 18: Млин,Nivå 18: Kvarn,Seviye 18: Değirmen +Level 19: Shipping/respawning,THUSTR_19,,,,Level 19: Přeprava,Level 19: Forsendelsescenter,Level 19: Versandlager,,Nivelo 19: Ekspedo/Revivado,Nivel 19: Enviando/Reapareciendo,,Taso 19: Huolinta/Ylösnostatus,NIVEAU 19: Envoi/Réapparition,19. Pálya: Szállítás/újraéledés,Livello 19: Consegna/Respawn,Level 19: 出荷と再生成,레벨 19: 운송/리스폰 장소,Level 19: Verzendingscentrum,Nivå 19: Frakt/omlasting,Level 19: Wysyłka/Reprodukcja,Fase 19: Expedição/reaparecimento,Nível 19: Expedição/reaparecimento,Nivelul 19: Livrare/reapariție,Уровень №19: Погрузка и отправка,Level 19: Отпремање/оживљавање,Nivå 19: Skeppning,Seviye 19: Nakliye Merkezi +Level 20: Central Processing,THUSTR_20,,,,Level 20: Centrální zpracování,Level 20: Central forarbejdning,Level 20: Zentralverarbeitung,,Nivelo 20: Centra Eskpedado,Nivel 20: Procesamiento Central,,Taso 20: Käsittelykeskus,NIVEAU 20: Organisme Central,20. Pálya: Központi feldolgozó,Livello 20: Centrale di Elaborazione,Level 20: 中央処理所,레벨 20: 중앙 처리소,Level 20: Centrale verwerking,Nivå 20: Sentral behandling,Level 20: Centralny Proces,Fase 20: Processamento Central,Nível 20: Processamento Central,Nivelul 20: Prelucrare centrală,Уровень №20: Центральный пункт обработки,Level 20: Централна обрада,Nivå 20: Centralt bearbetningsområde,Seviye 20: Merkezi İşlem +Level 21: Administration Center,THUSTR_21,,,,Level 21: Administrativní centrum,Level 21: Administrationscenter,Level 21: Verwaltungszentrum,,Nivelo 21: Administracia Centro,Nivel 21: Centro de Administración,,Taso 21: Keskushallinto,NIVEAU 21: Centre Administratif,21. Pálya: Adminisztrációs központ,Livello 21: Centro Amministrativo,Level 21: 行政センター,레벨 21: 관리 센터,Level 21: Administratief centrum,Nivå 21: Administrasjonssenter,Level 21: Centrum Administracyjne,Fase 21: Centro de Administração,Nível 21: Centro de Administração,Nivelul 21: Centru administrativ,Уровень №21: Административный центр,Level 21: Административни центар,Nivå 21: Administrationscenter,Seviye 21: Yönetim Merkezi +Level 22: Habitat,THUSTR_22,,,,,Level 22: Levested,,,Nivelo 22: Habitato,Nivel 22: Hábitat,,Taso 22: Asuinpaikka,NIVEAU 22: Habitat,22. Pálya: Élőhely,Livello 22: Habitat,Level 22: 生息地,레벨 22: 서식지,,Nivå 22: Habitat,Level 22: Siedlisko,Fase 22: Habitat,Nível 22: Habitat,Nivelul 22: Habitat,Уровень №22: Ареал,Level 22: Станиште,Nivå 22: Livsområde,Seviye 22: Habitat +Level 23: Lunar Mining Project,THUSTR_23,,,,Level 23: Lunární těžební projekt,Level 23: Projekt for månens minedrift,Level 23: Mondbergbauprojekt,,Nivelo 23: Luna Mino-Projekto,Nivel 23: Proyecto de Minería Lunar,,Taso 23: Kuukaivosprojekti,NIVEAU 23: Projet Minier Lunaire,23. Pálya: Holdbánya-projekt,Livello 23: Progetto Minerario Lunare,Level 23: 月面探鉱計画,레벨 23: 월석 채광 계획,Level 23: Maanmijnbouw project,Nivå 23: Månegruveprosjekt,Level 23: Projekt Księżycowe Górnictwo,Fase 23: Projeto de Mineração Lunar,Nível 23: Projeto de Escavação Lunar,Nivelul 23: Proiect minier satelitar,Уровень №23: Лунный проект горной добычи,Level 23: Пројекат лунарног рударства,Nivå 23: Gruvprojekt på månen,Seviye 23: Ay Madenciliği Projesi +Level 24: Quarry,THUSTR_24,,,,Level 24: Kamenolom,Level 24: Stenbrud,Level 24: Steinbruch,,Nivelo 24: Ŝtonejo,Nivel 24: Cantera,,Taso 24: Louhos,NIVEAU 24: Carrière,24. Pálya: Kőbánya,Livello 24: Caccia,Level 24: 採石場,레벨 24: 채석장,Level 24: Steengroeve,Nivå 24: Steinbrudd,Level 24: Kamieniołom,Fase 24: Pedreira,Nível 24: Pedreira,Nivelul 24: Carieră,Уровень №24: Карьер,Level 24: Каменолом,Nivå 24: Stenbrott,Seviye 24: Taş Ocağı +Level 25: Baron's Den,THUSTR_25,,,,Level 25: Baronovo doupě,Level 25: Baronens hule,Level 25: Der Bau des Barons,,Nivelo 25: Nestego de Barono,Nivel 25: Guarida del Barón,,Taso 25: Paronin pesä,NIVEAU 25: l'Antre des Barons,25. Pálya: A báró odúja,Livello 25: Antro del Barone,Level 25: バロンの巣窟,레벨 25: 남작의 소굴,Level 25: Het baron's gebouw,Nivå 25: Baronens hule,Level 25: Legowisko Barona,Fase 25: Covil do Barão,Nível 25: Covil do Barão,Nivelul 25: Cuibul Baronului,Уровень №25: Логово барона,Level 25: Баронова јазбина,Nivå 25: Baronens lya,Seviye 25: Baron'un İni +Level 26: Ballistyx,THUSTR_26,,,,Level 26: Balistika,,,,Nivelo 26: Balistikso,Nivel 26: Balístige,,Taso 26: Ballistyks,NIVEAU 26: Ballistyx,26. Pálya: Ballisztüx,Livello 26: Ballistige,Level 26: バリステュクス,레벨 26: 탄도스틱스,,,Level 26: Balistyka,Fase 26: Ballistige,Nível 26: Ballistige,Nivelul 26: Ballistyx,Уровень №26: Баллистикс,Level 26: Билистичкикс,Nivå 26: Ballistyx,Seviye 26: Balistyx +Level 27: Mount Pain,THUSTR_27,,,,Level 27: Hora bolesti,Level 27: Smertefjellet,Level 27: Berg des Schmerzes,,Nivelo 27: Monto de Doloro,Nivel 27: Monte Dolor,,Taso 27: Tuskavuori,NIVEAU 27: Mont Souffrance,27. Pálya: A Gyötrelem Hegye,Livello 27: Monte del Dolore,Level 27: 苦しみの山,레벨 27: 등신같은 등산,Level 27: Pijn in de bergen,Nivå 27: Smertefjellet,Level 27: Góra Bólu,Fase 27: Monte Dor,Nível 27: Monte Dor,Nivelul 27: Muntele Durerii,Уровень №27: Гора Боль,Level 27: Планина боли,Nivå 27: Smärta på berget,Seviye 27: Acı Dağı +Level 28: Heck,THUSTR_28,,,,Level 28: Sakra,,Level 28: Zum Teufel,,Nivelo 28: Diable,Nivel 28: Diablos,,Taso 28: Hemmetti,NIVEAU 28: Que Diable?,28. Pálya: Rosseb,Livello 28: Al Diavolo,Level 28: 苛立ち,레벨 28: 젠장함,,Nivå 28: Helvete,Level 28: Do Diabła,Fase 28: Capeta,Nível 28: Inferno,Nivelul 28: Naiba,Уровень №28: Чертовщина,Level 28: Пакао,Nivå 28: Heck,Seviye 28: Cehennem +Level 29: River Styx,THUSTR_29,,,,Level 29: Řeka Styx,Level 29: Floden Styx,Level 29: Fluss Styx,,Nivelo 29: Rivero de Stikso,Nivel 29: Río Estige,,Taso 29: Styksjoki,NIVEAU 29: Fleuve Styx,29. Pálya: A Sztüx folyó,Livello 29: Fiume Stige,Level 29: 三途の川,레벨 29: 스틱스 강,Level 29: Rivier Styx,Nivå 29: Elven Styx,Level 29: Styks,Fase 29: Rio Estige,Nível 29: Rio Estige,Nivelul 29: Râul Styx,Уровень №29: Река Стикс,Level 29: Река Стикс,Nivå 29: Floden Styx,Seviye 29: Styx Nehri +Level 30: Last Call,THUSTR_30,,,,Level 30: Poslední mise,Level 30: Sidste opkald,Level 30: Letzter Aufruf,,Nivelo 30: Fina Voko,Nivel 30: Última Llamada,,Taso 30: Viimeinen koollehuuto,NIVEAU 30: Dernier Appel,30. Pálya: Utolsó esély,Livello 30: Ultima Chiamata,Level 30: 最終指令,레벨 30: 최후의 호출,Level 30: Laatste oproep,Nivå 30: Siste innkalling,Level 30: Ostatni Zew,Fase 30: Última Chamada,Nível 30: Última Chamada,Nivelul 30: Ultimul apel,Уровень №30: Последний вызов,Level 30: Последњи позив,Nivå 30: Sista kallelsen,Seviye 30: Son Çağrı +Level 31: Pharaoh,THUSTR_31,,,,Level 31: Faraón,Level 31: Farao,Level 31: Pharao,,Nivelo 31: Faraono,Nivel 31: Faraón,,Taso 31: Faarao,NIVEAU 31: Pharaon,31. Pálya: Fáraó,Livello 31: Faraone,Level 31: ファラオ,레벨 31: 파라오,Level 31: Farao,Nivå 31: Farao,Level 31: Faraon,Fase 31: Faraó,Nível 31: Faraó,Nivelul 31: Faraon,Уровень №31: Фараон,Level 31: Фараон,Nivå 31: Farao,Seviye 31: Firavun +Level 32: Caribbean,THUSTR_32,,,,Level 32: Karibik,Level 32: Caribien,Level 32: Karibik,,Nivelo 32: Karibio,Nivel 32: Caribeño,,Taso 32: Karibia,NIVEAU 32: Caraïbes,32. Pálya: Karib-térség,Livello 32: Caraibi,Level 32: カリビアン,레벨 32: 카리브해,Level 32: Caribisch,Nivå 32: Karibia,Level 32: Karaiby,Fase 32: Caribe,Nível 32: Caraíbas,Nivelul 32: Caraibe,Уровень №32: Карибы,Level 32: Кариби,Nivå 32: Karibien,Seviye 32: Karayipler +,,Heretic,,,,,,,,,,,,,,,,,,,,,,,,, +The Docks,HHUSTR_E1M1,,,,Přístav,Havnene,Die Docks,,La Havenoj,Los Muelles,,Satamat,Les Docks,A Kikötő,Il Molo,埠頭,항구,De dokken,Havnen,Doki,As Docas,,Docul,Доки,Лука,Hamnarna,Rıhtım +The Dungeons,HHUSTR_E1M2,,,,Žaláře,Fangehullerne,Die Kerker,,La Malliberejoj,Los Calabozos,,Tyrmät,Le Donjon,A Kazamaták,I Sotterranei,地下牢,지하감옥,De kerkers,Fangehullene,Lochy,As Masmorras,,Temnița,Темницы,Тамнице,Fästningarna,Zindanlar +The Gatehouse,HHUSTR_E1M3,,,,Vrátnice,Portens hus,Das Pförtnerhaus,,La Pordegejo,El Cuerpo de Guardia,,Porttitalo,Le Corps de Garde,A Kapuház,L'ingresso,門塔,문루,Het poortgebouw,Porthuset,Stróżówka,O Portão de Entrada,,Casa portarului,Привратницкая,Стражарница,Porthuset,Kapı Evi +The Guard Tower,HHUSTR_E1M4,,,,Strážní věž,Vagttårnet,Der Wachturm,,La Gardturo,La Torre de Guardia,,Vartiotorni,La Tour de Garde,Az Őrtorony,La Torre di Guardia,監視塔,보초 누대,De wachttoren,Vakttårnet,Wieża Strażnicza,A Torre de Guarda,,Turnul de veghe,Сторожевая башня,Извидница,Vakttornet,Muhafız Kulesi +The Citadel,HHUSTR_E1M5,,,,Citadela,Citadellet,Die Festung,,La Citadelo,La Ciudadela,,Linnake,La Citadelle,A Citadella,La Cittadella,要塞,거점,De citadel,Citadellet,Cytadela,A Cidadela,,Cetatea,Цитадель,Цитадела,Citadellet,Hisar +The Cathedral,HHUSTR_E1M6,,,,Katedrála,Katedralen,Die Kathedrale,,La Katedralo,La Catedral,,Katedraali,La Cathédrale,A Katedrális,La Cattedrale,大聖堂,대성당,De kathedraal,Katedralen,Katedra,A Catedral,,Catedrala,Кафедральный собор,Катедрала,Katedralen,Katedral +The Crypts,HHUSTR_E1M7,,,,Krypty,Krypterne,Die Krypten,,La Kriptoj,Las Criptas,,Kryptat,La Crypte,A Kripták,Le Cripte,地下聖堂,지하 묘실,De grafkelders,Kryptene,Krypty,As Criptas,,Criptele,Склепы,Крипта,Krypten,Mahzenler +Hell's Maw,HHUSTR_E1M8,,,,Chřtán pekla,Helvedes gab,Der Höllenschlund,,Faŭko de Infero,Fauces del Infierno,,Helvetin kita,La Geule de l'Enfer,A Pokol Szája,La Bocca dell'Inferno,地獄の肚,지옥의 목구멍,De helmouth,Helvetes gap,Paszcza Piekieł,A Boca do Inferno,,Gura iadului,Адская утроба,Паклено ждрело,Helvetets gap,Cehennem Ağzı +The Graveyard,HHUSTR_E1M9,,,,Hřbitov,Kirkegården,Der Friedhof,,La Tombejo,El Cementerio,,Hautausmaa,Le Cimetière,A Temető,Il Cimitero,墓場,공동묘지,De begraafplaats,Kirkegården,Cmentarz,O Cemitério,,Cimitirul,Кладбище,Гробље,Kyrkogården,Mezarlık +The Crater,HHUSTR_E2M1,,,,Kráter,Krateret,Der Krater,,La Kratero,El Cráter,,Kraateri,Le Cratère,A Kráter,Il Cratere,噴火口,깊은 혈,De krater,Krateret,Krater,A Cratera,,Craterul,Кратер,Кратер,Kratern,Krater +The Lava Pits,HHUSTR_E2M2,,,,Lávové jámy,Lavagruberne,Die Lavagruben,,La Lafo-Fosaĵo,Las Canteras de Lava,,Laavamontut,Les Puits de Lave,A Lávaárok,I Pozzi della Lava,溶岩の竪穴,용암 구덩이,De lavaputten,Lavagropene,Szyb Lawy,Os Fossos de Lava,,Gropile cu lavă,Лавовые очаги,Понор лаве,Lavagruvorna,Lav Çukurları +The River of Fire,HHUSTR_E2M3,,,,Ohnivá řeka,Ildfloden,Der Feuerfluss,,La Rivero de Fajro,El Río de Fuego,,Tulijoki,La Rivière de Feu,A Tűzfolyó,Il Fiume di Fuoco,火の河,화염의 강,De rivier van vuur,Elven av ild,Rzeka Ognia,O Rio de Fogo,,Râul de foc,Река огня,Река од ватре,Eldfloden,Ateş Nehri +The Ice Grotto,HHUSTR_E2M4,,,,Ledová grotta,Isgrotten,Die Eisgrotte,,La Glacigroto,La Gruta de Hielo,,Jääluola,La Grotte de Glace,A Jégbarlang,La Grotta del Ghiaccio,氷の洞窟,얼음 동굴,De ijsgrot,Isgrotten,Lodowa Grota,A Gruta de Gelo,,Grota de gheață,Ледяной грот,Ледена пећина,Isgrottan,Buz Mağarası +The Catacombs,HHUSTR_E2M5,,,,Katakomby,Katakomberne,Die Katakomben,,La Katakomboj,Las Catacumbas,,Katakombit,Les Catacombes,A Katakombák,Le Catacombe,地下墓所,태고의 무덤,De catacomben,Katakombene,Katakumby,As Catacumbas,Os Túmulos,Catacombele,Катакомбы,Катакомбе,Katakomberna,Yeraltı Mezarları +The Labyrinth,HHUSTR_E2M6,,,,Labyrint,Labyrinten,Das Labyrinth,,La Labirinto,El Laberinto,,Labyrintti,Le Labyrinthe,A Labirintus,Il Labirinto,迷宮,미궁,Het labyrint,Labyrinten,Labirynt,O Labirinto,,Labirintul,Лабиринт,Лавиринт,Labyrinten,Labirent +The Great Hall,HHUSTR_E2M7,,,,Velký sál,Den store sal,Die große Halle,,La Granda Halo,El Gran Salón,,Suuri halli,Le Grand Hall,A Nagy Folyosó,La Grande Sala,大公会堂,대회관,De grote zaal,Den store salen,Wielki Hol,O Grande Salão,,Sala cea mare,Большой зал,Велика дворана,Den stora hallen,Büyük Salon +The Portals of Chaos,HHUSTR_E2M8,,,,Portály chaosu,Kaosets portaler,Das Portal des Chaos,,La Portaloj de Ĥaoso,Los Portales del Caos,,Kaaoksen portaalit,Le Portail du Chaos,A Káosz Portáljai,I Portali del Caos,混沌への門,혼돈의 차원문,De portalen van chaos,Kaosets portaler,Portale Chaosu,Os Portais do Caos,,Portalurile haosului,Порталы хаоса,Портали хаоса,Kaosets portaler,Kaos Kapıları +The Glacier,HHUSTR_E2M9,,,,Ledovec,Gletsjeren,Der Gletscher,,La Glaciejo,El Glaciar,,Jäätikkö,Le Glacier,A Gleccser,Il Ghiacciaio,氷河,빙하 구역,De gletsjer,Isbreen,Lodowiec,A Geleira,O Glaciar,Ghețarul,Ледник,Глечер,Glaciären,Buzul +The Storehouse,HHUSTR_E3M1,,,,Skladiště,Magasinet,Die Lagerhalle,,La Stokejo,El Almacén,,Varasto,L'Entrepôt,A Raktár,Il Magazzino,倉庫,저장고,Het pakhuis,Forrådshuset,Magazyn,O Armazém,,Depozitul,Кладовая,Складиште,Magasinet,Depo +The Cesspool,HHUSTR_E3M2,,,,Žumpa,Kedelbassinet,Die Latrine,,La Kloako,El Pozo,,Likakaivo,Le Bourbier,A Pöcegödör,Il Pozzo Nero,汚水層,불결한 장소,De zinkput,Søledammen,Szambo,A Fossa,,Haznaua,Сточный колодец,Септичка јама,Rännstenen,Lağım Çukuru +The Confluence,HHUSTR_E3M3,,,,Soutok,Sammenløbet,Die Vereinigung,,La Kunfluiĝo,La Confluencia,,Yhtymäkohta,La Confluence,A Kereszteződés,La Confluenza,合流点,합류점,De samenvloeiing,Sammenløpet,Spływ,A Confluência,,Confluența,Слияние,Ушће,Sammanflödet,Confluence +The Azure Fortress,HHUSTR_E3M4,,,,Azurová pevnost,Den azurblå fæstning,Die himmelblaue Festung,,La Lazurfortikaĵo,La Fortaleza de Azur,,Sininen linnoitus,La Fortresse d'Azur,Az Azúr Erőd,La Fortezza Azzurra,紺碧の要塞,청천의 요새,De azuurblauwe vesting,Den azurblå festningen,Lazurowa Forteca,A Fortaleza Azul,,Fortăreața de azur,Лазурная крепость,Азурна дврђава,Den azurblå fästningen,Azure Kalesi +The Ophidian Lair,HHUSTR_E3M5,,,,Hadí doupě,Ophidian Hulen,Das Schlangennest,,La Nestego de Ofidia,La Guarida Ofídica,,Käärmeiden pesä,Le Repaire des Ophidiens,Az Opfidiánok Fészke,L'antro degli Ophidian,オフィディアンの塒,오피디안의 소굴,Het slangennest,Ophidian-hulen,Gniazdo Węży,A Cova dos Ofídios,,Cuibul ofidienilor,Логово офидианов,Змијска јазбина,Den Ophidiska hålan,Ophidian İni +The Halls of Fear,HHUSTR_E3M6,,,,Chodby strachu,Frygtens haller,Die Hallen der Angst,,La Koridoroj de Timo,Los Salones del Miedo,,Pelon salit,Les Couloirs de la Peur,A Félelem Folyosói,Le Sale della Paura,恐怖の館,공포의 회관,De zalen van angst,Fryktens haller,Korytarze Strachu,Os Salões do Medo,,Sălile groazei,Залы страха,Дворана страха,Skräckens hallar,Korku Salonları +The Chasm,HHUSTR_E3M7,,,,Propast,Kløften,Der Abgrund,,La Fendego,El Abismo,,Rotko,Le Gouffre,A Szakadék,L'abisso,裂け目,깊은 골,De kloof,Kløften,Przepaść,O Abismo,,Prăpastia,Пропасть,Понор лаве,Klyftan,Uçurum +D'Sparil's Keep,HHUSTR_E3M8,,,,D'Sparilova pevnost,D'Sparils borg,D'Sparils Außenposten,,Ĉefturo de Desparilo,Guarida de D'Sparil,,D'Sparilin linna,Le Donjon de D'Sparil,D'Sparil Terme,La Dimora di D'Sparil,デ’スパリルの間,드'스파릴의 초소,D'Sparil's voorpost,D'Sparils borg,Baszta D'Sparila,Fortaleza de D'Sparil,,Palatul lui D'sparil,Крепость Д'Спарила,Д'Спарилова кула,D'Sparils borg,D'Sparil'in Kalesi +The Aquifer,HHUSTR_E3M9,,,,Zvodeň,Akvifer,Der Wasserspeicher,,La Akvigilo,El Acuífero,,Akviferi,L'Aquifère,A Víztorony,L'acquedotto,帯水層,대수층,Het water reservoir,Akviferen,Wodociąg,O Aquífero,,Galerii acvifere,Водоносный слой,Водоносник,Akvifer,Akifer +Catafalque,HHUSTR_E4M1,,,,Katafalk,Katafalken,Katafalk,,Katafalko,Catafalco,,Katafalkki,Le Catafalque,Ravatal,Catafalco,棺台,관대,Catafalk,Katafalken,Katafalk,Catafalco,,Catafalc,Катафалк,Одар,Katafalken,Katafalk +Blockhouse,HHUSTR_E4M2,,,,Tvrzka,Blokhuset,Blockhaus,,Blokhaŭso,Fortín,,Linnoitus,Le Fortin,Gerendaház,Blocco di Case,丸太小屋,특화점,Blokhuis,Blokkhuset,Blokhauz,O Forte,,Fort,Блокгауз,Бункер,Blockhuset,Blok ev +Ambulatory,HHUSTR_E4M3,,,,Ochoz,Ambulatory,Wandelgang,,Ĥorĉirkaŭirejo,Ambulatorio,,Kuorikäytävä,Le Déambulatoire,Kerengő,Ambulatorio,遊歩道,유보장,Kloostergang,Gangen,Krużganek,Ambulatório,,Clinică,Амбулатория,Амбуланта,Ambulerande,Ambulatuvar +Sepulcher,HHUSTR_E4M4,,,,Hrobka,Graven,Grabstätte,,Tombo,Sepulcro,,Hautakammio,Le Sépulcre,Síremlék,Sepolcro,埋葬所,매장소,Grafsteen,Graven,Grób,Sepulcro,,Sepulcru,Гробница,Гробница,Gravskålen,Mezar +Great Stair,HHUSTR_E4M5,,,,Velké schody,Den store trappe,Große Treppe,,Granda Ŝtuparo,Gran Escalera,,Suuret portaat,Le Grand Escalier,Nagy Lépcső,Grande Scala,大階段,특급 계단,Grote trap,Den store trappen,Wielka Gwiazda,Grande Escada,,Scara cea mare,Великая лестница,Велики степеник,Stora trappan,Büyük Merdiven +Halls of the Apostate,HHUSTR_E4M6,,,,Chodby odpadlictví,Apostaternes haller,Halle des Abtrünnigen,,Haloj de la Apostato,Salas de los Apóstatas,,Luopioiden salit,Les Halls de l'Apôtre,A Hitehagyott Csarnoka,Sale dell'Apostata,背教者の館,배교자의 회관,Zalen van de afvallige,De frafalnes haller,Korytarze Odszczepieńca,Os Salões dos Apóstatas,,Sălile apostatului,Залы отступников,Дворана апостола,Apostaternas salar,Mürted Salonları +Ramparts of Perdition,HHUSTR_E4M7,,,,Náspy zatracení,Fortabelsens ramper,Wälle der Verdammnis,,Muregoj de Pereo,Murallas de la Perdición,,Kadotuksen vallit,Les Remparts de la Perdition,A Kárhozat Támasza,Torrioni della Perdizione,破滅の塁壁,파멸의 성벽,Wallen van de verdoemenis,Fortapelsens voller,Wał Potępienia,Muralhas da Perdição,,Meterezele pierzaniei,Твердыни погибели,Бедем пропасти,Fördärvets ramper,Azap Surları +Shattered Bridge,HHUSTR_E4M8,,,,Rozbitý most,Den ødelagte bro,Zerstörte Brücke,,Frakasita Ponto,Puente Destrozado,,Särkynyt silta,Le Pont effondré,Az Összeomlott Híd,Ponte Distrutto,崩落の橋,붕괴된 다리,Verbrijzelde brug,Den knuste broen,Zniszczony Most,Ponte Despedaçada,,Podul dărâmat,Разрушенный мост,Поломљен мост,Förstörd bro,Parçalanmış Köprü +Mausoleum,HHUSTR_E4M9,,,,Mauzoleum,,,,Maŭzoleo,Mausoleo,,Mausoleumi,Le Mausolée,Mauzóleum,Mausoleo,霊廟,대영묘,,Mausoleet,Mauzoleum,Mausoléu,,Mausoleu,Мавзолей,Маузолеј,,Anıt Mezar +Ochre Cliffs,HHUSTR_E5M1,,,,Okrové útesy,Okkerklipper,Ockerfarbene Klippen,,Klifoj de Okro,Acantilados Ocres,,Okrajyrkänteet,Les Falaises Ochre,Okker Szakadékok,Colline Ocra,黄土絶壁,황토 산맥,Okerkliffen,Oker-klippene,Ochrowe Klify,Penhascos Ocres,,Stâncile de ocru,Охровые утёсы,Окер брда,Ockerfärgade klippor,Ochre Kayalıkları +Rapids,HHUSTR_E5M2,,,,Peřeje,Rapider,Stromschnellen,,Rapidfluoj,Rápidos,,Koski,Les Rapides,Zuhatagok,Rapide,奔流,여울,Stroomversnellingen,Strykene,Katarakty,Corredeiras,,Ape repezi,Стремнина,Брзак,Forsar,Akıntıları +Quay,HHUSTR_E5M3,,,,Nábřeží,Kaj,Kai,,Kajo,Muelle,,Satamalaituri,Le Quai,Rakpart,Banchina,岸壁,부두,Kade,Kai,Wir,Cais,,Chei,Причал,Пристаниште,Kajen,Rıhtım +Courtyard,HHUSTR_E5M4,,,,Nádvoří,Slotsgården,Schlosshof,,Korto,Patio,,Linnanpiha,La Cour,Pitvar,Cortile,中庭,안마당,Binnenplaats,Gårdsplass,Dziedziniec,Pátio,,Curte,Внутренний двор,Двориште,Gården,Avlu +Hydratyr,HHUSTR_E5M5,,,,Hydratýr,,,,Akvotjr,Hydratyr,,,L'Hydratyr,Hidratáló,,ヒュドラテュール,식수공급처,,,Hydratyr,Reservatório,,Hidratir,Гидротир,Канализација,Hydratyr,Hydratyr +Colonnade,HHUSTR_E5M6,,,,Kolonáda,Kolonnader,Kolonnaden,,Kolonaro,Columnata,,Pylväikkö,La Colonnade,Kolonnád,Colonnato,柱廊,열주의 길,Zuilengalerij,Kolonnade,Kolumnada,Colunata,,Colonadă,Колоннада,Колонада,Colonnade,Kolonat +Foetid Manse,HHUSTR_E5M7,,,,Smrdutá vila,Stinkende præstegård,Stinkendes Pfarrhaus,,Haladza Domego,Mansión Fétida,,Löyhkäävä kartano,Le Presbytère Fétide,Bűzös Parókia,Fetido Castello,悪臭の牧師館,역겨운 목사관,Stinkende pastorie,Stinkende prestegård,Cuchnąca Plebania,Mansão Fétida,,Conac Fetid,Зловонный особняк,Фетидна кућа,Foetid Manse,Foetid Manse +Field of Judgement,HHUSTR_E5M8,,,,Soudná pole,Dommervældet,Richtstätte,,Kampo de Juĝo,Campo de Juicio,,Tuomion kenttä,Les Champs du Jugement,Az Itélet Mezeje,Campo del Giudizio,審判之地,심판의 평야,Plaats van oordeelsvorming,Dømmekraftsområde,Pole Sądu,Campo de Julgamento,,Câmpul de Judecată,Поле высшего суда,Чистилиште,Domarplatsen,Yargı Alanı +Skein of D'sparil,HHUSTR_E5M9,,,,Hejno D'Sparilovo,D'sparils skein,DSparils Bau,,Fadenaro de D'Sparil,Madeja de D'Sparil,,D'Sparilin vyyhti,L'échevaux de D'Sparil,D'Sparil Káosza,Groviglio di D'Sparil,デ'スパリルの枷,드'스파릴의 타래,D'Sparil's gebouw,Garn av D'sparil,Motek D'Sparila,Meada de D'Sparil,,Jurubița lui D'Sparil,Путаница Д'Спарила,Реке Д'Спарила,D'sparils skein,D'sparil Çileği +,,Strife,,,,,,,,,,,,,,,,,,,,,,,,, +AREA 1: Sanctuary,TXT_STRIFE_MAP01,,,,ZÓNA 1: Svatyně,AREA 1: Fristedet,ZONE 1: Heiligtum,,AREO 1: Sanktejo,ÁREA 1: Santuario,,ALUE 1: Pyhäkkö,ZONE 1: Sanctuaire,1. Terület: Szentély,AREA 1: Santuario,エリア 1: 聖域,구역 1: 성소,Zone 1: Heiligdom,OMRÅDE 1: Helligdom,Strefa 1: Sanktuarium,Área 1: Santuário,,ZONA 1: Sanctuar,МЕСТНОСТЬ 1: Святилище,,OMRÅDE 1: Fristad,ALAN 1: Sığınak +AREA 2: Town,TXT_STRIFE_MAP02,,,,ZÓNA 2: Město,AREA 2: By,ZONE 2: Stadt,,AREO 2: Urbeto,ÁREA 2: Pueblo,,ALUE 2: Kylä,ZONE 2: Ville,2. Terület: Város,AREA 2: Città,"エリア 2: 町 +",구역 2: 마을,Zone 2: Stad,OMRÅDE 2: Byen,Strefa 2: Miasto,Área 2: Vila,,ZONA 2: Oraș,МЕСТНОСТЬ 2: Город,,OMRÅDE 2: Staden,ALAN 2: Şehir +AREA 3: Front Base,TXT_STRIFE_MAP03,,,,ZÓNA 3: Základna Fronty,AREA 3: Front Basis,ZONE 3: Basis der Front,,AREO 3: Front-Bazo,ÁREA 3: Base del Frente,,ALUE 3: Rintaman tukikohta,ZONE 3: Base du Front,3. Terület: Elülső bázis,AREA 3: Base del Fronte,エリア 3: フロント基地,구역 3: 프론트 기지,Zone 3: Front basis,OMRÅDE 3: Frontbase,Strefa 3: Baza Frontu,Área 3: Base da Frente,,ZONA 3: Baza Frontului,МЕСТНОСТЬ 3: База сопротивления,,OMRÅDE 3: Frontbasen,ALAN 3: Ön Taban +AREA 4: Power Station,TXT_STRIFE_MAP04,,,,ZÓNA 4: Elektrárna,AREA 4: Kraftværk,ZONE 4: Kraftwerk,,AREO 4: Elektrocentralo,ÁREA 4: Central eléctrica,,ALUE 4: Voimalaitos,ZONE 4: Centrale,4. Terület: Erőmű,AREA 4: Centrale Elettrica,エリア 4: 発電所,구역 4: 발전소,Zone 4: Energiecentrale,OMRÅDE 4: Kraftstasjon,Strefa 4: Elektrownia,Área 4: Usina de Energia,Área 4: Central Energética,ZONA 4: Centrala,МЕСТНОСТЬ 4: Электростанция,,OMRÅDE 4: Kraftverk,ALAN 4: Elektrik Santrali +AREA 5: Prison,TXT_STRIFE_MAP05,,,,ZÓNA 5: Vězení,AREA 5: Fængsel,ZONE 5: Gefängnis,,AREO 5: Malliberejo,ÁREA 5: Prisión,,ALUE 5: Vankila,ZONE 5: Prison,5. Terület: Börtön,AREA 5: Carcere,エリア 5: 刑務所,구역 5: 감옥,Zone 5: Gevangenis,OMRÅDE 5: Fengsel,Strefa 5: Więzienie,Área 5: Prisão,,ZONA 5: Închisoare,МЕСТНОСТЬ 5: Тюрьма,,OMRÅDE 5: Fängelse,ALAN 5: Cezaevi +AREA 6: Sewers,TXT_STRIFE_MAP06,,,,ZÓNA 6: Stoky,AREA 6: Kloakkerne,ZONE 6: Kanalisation,,AREO 6: Kloako,ÁREA 6: Alcantarillas,,ALUE 6: Viemärit,ZONE 6: Egouts,6. Terület: Kanális,AREA 6: Fogne,エリア 6: 下水道,구역 6: 하수도,Zone 6: Riolering,OMRÅDE 6: Kloakk,Strefa 6: Kanały,Área 6: Esgoto,,ZONA 6: Canal,МЕСТНОСТЬ 6: Канализация,,OMRÅDE 6: Avloppsledningar,ALAN 6: Kanalizasyonlar +AREA 7: Castle,TXT_STRIFE_MAP07,,,,ZÓNA 7: Hrad,AREA 7: Slot,ZONE 7: Burg,,AREO 7: Kastelo,ÁREA 7: Castillo,,ALUE 7: Linna,ZONE 7: Château,7. Terület: Vár,AREA 7: Castello,エリア 7: 城,구역 7: 성,Zone 7: Kasteel,OMRÅDE 7: Slottet,Strefa 7: Zamek,Área 7: Castelo,,ZONA 7: Castel,МЕСТНОСТЬ 7: Замок,,OMRÅDE 7: Slott,ALAN 7: Kale +AREA 8: Audience Chamber,TXT_STRIFE_MAP08,,,,ZÓNA 8: Audienční sál,AREA 8: Audience Chamber,ZONE 8: Audienzsaal,,AREO 8: Juĝejo,ÁREA 8: Sala de audiencias,,ALUE 8: Yleisösali,ZONE 8: Chambre d'Audience,8. Terület: Nézőtér,AREA 8: Sala delle Udienze,エリア 8: 観客席,구역 8: 알현실,Zone 8: Auditorium,OMRÅDE 8: Audienssalen,Strefa 8: Izba Audiencji,Área 8: Câmara de Audiências,,ZONA 8: Camera de audiențe,МЕСТНОСТЬ 8: Приёмная,,OMRÅDE 8: Publikrum,ALAN 8: İzleyici Odası +AREA 9: Castle: Programmer's Keep,TXT_STRIFE_MAP09,,,,ZÓNA 9: Hrad: Programátorovo doupě,AREA 9: Slot: Programmørens værelse,ZONE 9: Burg: Unterkunft des Programmierers,,AREO 9: Kastelo: Fortikaĵo de Programisto,ÁREA 9: Castillo: Guarida del Programador,,ALUE 9: Linna: Ohjelmoitsijan linnake,ZONE 9: Château: Donjon du Programmeur,9. Terület: Vár: Programozó parcellája,AREA 9: Castello: Dimora del Programmatore,エリア 9: 城内:プログラマーの間,구역 9: 성: 프로그래머의 성채,Zone 9: Kasteel: Onderdak van de programmeur,OMRÅDE 9: Slottet: Programmørens tårn,Strefa 9: Zamek: Baszta Programisty,Área 9: Castelo: Torre do Programador,,ZONA 9: Castel: Cetatea programatorului,МЕСТНОСТЬ 9: Цитадель Программиста,,OMRÅDE 9: Programmerarens behållning,ALAN 9: Kale: Programcının Kalesi +AREA 10: New Front Base,TXT_STRIFE_MAP10,,,,ZÓNA 10: Nová základna Fronty,AREA 10: Ny frontbase,ZONE 10: Neue Basis der Front,,AREO 10: Nova Frontbazo,ÁREA 10: Nueva base del Frente,,ALUE 10: Uusi Rintaman tukikohta,ZONE 10: Nouvelle Base du Front,10. Terület: Új első bázis,AREA 10: Nuova Base del Fronte,エリア 10: 新フロント基地,구역 10: 새 프론트 기지,Zone 10: Nieuwe Front basis,OMRÅDE 10: Den nye frontbasen,Strefa 10: Nowa Baza Frontu,Área 10: Nova Base da Frente,,ZONA 10: Noua bază a Frontului,МЕСТНОСТЬ 10: Новая база сопротивления,,OMRÅDE 10: Ny frontbas,ALAN 10: Yeni Ön Taban +AREA 11: Borderlands,TXT_STRIFE_MAP11,,,,ZÓNA 11: Pohraničí,AREA 11: Grænseland,ZONE 11: Grenzgebiete,,AREO 11: Limlando,ÁREA 11: Tierras fronterizas,,ALUE 11: Rajamaat,ZONE 11: Terres Sauvages,11. Terület: Peremvidék,AREA 11: Lande di Confine,エリア 11: 国境地帯,구역 11: 접경지,Zone 11: Grensgebieden,OMRÅDE 11: Grenseland,Strefa 11: Pogranicze,Área 11: Fronteira,,ZONA 11: Frontiere,МЕСТНОСТЬ 11: Пограничье,,OMRÅDE 11: Gränsområde,ALAN 11: Sınır Bölgeleri +AREA 12: The Temple of the Oracle,TXT_STRIFE_MAP12,,,,ZÓNA 12: Věštcův chrám,AREA 12: Oraklets tempel,ZONE 12: Der Tempel des Orakels,,AREO 12: La templo de la Orakolo,ÁREA 12: El templo del Oráculo,,ALUE 12: Oraakkelin temppeli,ZONE 12: Temple de l'Oracle,12. Terület: Az Orákulum Temploma,AREA 12: Il Tempio dell'Oracolo,エリア 12: オラクルの神殿,구역 12: 오라클의 신전,Zone 12: De tempel van het Orakel,OMRÅDE 12: Orakelets tempel,Strefa 12: Świątynia Wyroczni,Área 12: O Templo do Oráculo,,ZONA 12: Templul Oracolului,МЕСТНОСТЬ 12: Храм Оракула,,OMRÅDE 12: Oraklets tempel,ALAN 12: Kahin Tapınağı +AREA 13: Catacombs,TXT_STRIFE_MAP13,,,,ZÓNA 13: Katakomby,AREA 13: Katakomberne,ZONE 13: Katakomben,,AREO 13: Katakombo,ÁREA 13: Catacumbas,,ALUE 13: Katakombit,ZONE 13: Catacombes,13. Terület: Katakombák,AREA 13: Catacombe,エリア 13: 地下墓所,구역 13: 고대 묘지,Zone 13: Catacomben,OMRÅDE 13: Katakombene,Strefa 13: Katakumby,Área 13: Catacumbas,Área 13: Túmulos,ZONA 13: Catacombe,МЕСТНОСТЬ 13: Катакомбы,,OMRÅDE 13: Katakomberna,ALAN 13: Yeraltı Mezarları +AREA 14: Mines,TXT_STRIFE_MAP14,,,,ZÓNA 14: Doly,AREA 14: Miner,ZONE 14: Die Minen,,AREO 14: Minejo,ÁREA 14: Minas,,ALUE 14: Kaivokset,ZONE 14: Mines,14. Terület: Bánya,AREA 14: Miniere,エリア 14: 鉱山,구역 14: 광산,Zone 14: De mijnen,OMRÅDE 14: Minene,Strefa 14: Kopalnia,Área 14: Minas,,ZONA 14: Mine,МЕСТНОСТЬ 14: Шахты,,OMRÅDE 14: Gruvor,ALAN 14: Madenler +AREA 15: Fortress: Administration,TXT_STRIFE_MAP15,,,,ZÓNA 15: Pevnost: Administrace,AREA 15: Fæstning: Administration,ZONE 15: Festung: Administration,,AREO 15: Fortreso: Administrejo,ÁREA 15: Fortaleza: Administración,,ALUE 15: Linnoitus: hallinto,ZONE 15: Forteresse: Administration,15. Terület: Erőd: Elbírálás,AREA 15: Fortezza: Amministrazione,エリア 15: 要塞:管理室,구역 15: 요새: 중앙 관리소,Zone 15: Vesting: Administratieve organisatie,OMRÅDE 15: Festningen: Administrasjon,Strefa 15: Forteca: Administracja,Área 15: Fortaleza: Administração,,ZONA 15: Fortăreața: Administrația,МЕСТНОСТЬ 15: Крепость (администрация),,OMRÅDE 15: Fästning: Administration,ALAN 15: Kale: Yönetim +AREA 16: Fortress: Bishop's Tower,TXT_STRIFE_MAP16,,,,ZÓNA 16: Pevnost: Biskupova věž,AREA 16: Fæstning: Biskoppens tårn,ZONE 16: Festung: Bischofsturm,,AREO 16: Fortreso: Turo de la Episkopo,ÁREA 16: Fortaleza: Torre del Obispo,,ALUE 16: Linnoitus: Piispan torni,ZONE 16: Forteresse: Tour de l'évèque,16. Terület: Erőd: Püspök tornya,AREA 16: Fortezza: Torre del Vescovo,エリア 16: 要塞:ビショップの塔,구역 16: 요새: 비숍의 탑,Zone 16: Vesting: Bisschopstoren,OMRÅDE 16: Festningen: Biskopens tårn,Strefa 16: Forteca: Wieża Biskupa,Área 16: Fortaleza: Torre do Bispo,,ZONA 16: Fortăreața: Turnul Episcopului,МЕСТНОСТЬ 16: Крепость (башня Епископа),,OMRÅDE 16: Fästningen: Biskopens torn,ALAN 16: Kale: Piskopos Kulesi +AREA 17: Fortress: The Bailey,TXT_STRIFE_MAP17,,,,ZÓNA 17: Pevnost: Předhradí,AREA 17: Fæstning: Bailey,ZONE 17: Festung: Vorhof,,AREO 17: Fortreso: Ĉirkaŭmurigita korto,ÁREA 17: Fortaleza: Patio cerrado,,ALUE 17: Linnoitus: linnanpiha,ZONE 17: Forteresse: Mur d'enceinte,17. Terület: Erőd: Várfal,AREA 17: Fortezza: Bastione,エリア 17: 要塞:ベイリー,구역 17: 요새: 안뜰,Zone 17: Vesting: Voorplein,OMRÅDE 17: Festningen: Borggården,Strefa 17: Forteca: Mur Obronny,Área 17: Fortaleza: O Pátio,,ZONA 17: Fortăreața: Curte,МЕСТНОСТЬ 17: Крепость (двор),,OMRÅDE 17: Fästning: Bailey,ALAN 17: Kale: Dış avlu +AREA 18: Fortress: Stores,TXT_STRIFE_MAP18,,,,ZÓNA 18: Pevnost: Sklady,AREA 18: Fæstning: Magasiner,ZONE 18: Festung: Lager,,AREO 18: Fortreso: Magazeno,ÁREA 18: Fortaleza: Almacenes,,ALUE 18: Linnoitus: varastot,ZONE 18: Forteresse: Réserves,18. Terület: Erőd: Üzletek,AREA 18: Fortezza: Negozi,エリア 18: 要塞:商店,구역 18: 요새: 격납고,Zone 18: Vesting: Lager,OMRÅDE 18: Festningen: Lagrene,Strefa 18: Forteca: Sklepy,Área 18: Fortaleza: Reservas,,ZONA 18: Fortăreața: Depozite,МЕСТНОСТЬ 18: Крепость (склады),,OMRÅDE 18: Fästning: Butiker,ALAN 18: Kale: Mağazalar +AREA 19: Fortress: Security Complex,TXT_STRIFE_MAP19,,,,ZÓNA 19: Pevnost: Bezpečnostní komplex,AREA 19: Fæstning: Sikkerhedskompleks,ZONE 19: Festung: Sicherheitsanlage,,AREO 19: Fortreso: Sekurkomplekso,ÁREA 19: Fortaleza: Complejo de seguridad,,ALUE 19: Linnoitus: turvallisuuskeskus,ZONE 19: Forteresse: Complexe Sécurité,19. Terület: Erőd: Biztonsági Részleg,AREA 19: Fortezza: Complesso di Sicurezza,エリア 19: 要塞:複合警備所,구역 19: 요새: 보안 담당 기지,Zone 19: Vesting: Beveiligingssysteem,OMRÅDE 19: Festningen: Sikkerhetskomplekset,Strefa 19: Forteca: Kompleks Ochronny,Área 19: Fortaleza: Complexo de Segurança,,ZONA 19: Fortăreața: Complex de securitate,МЕСТНОСТЬ 19: Крепость (охранный комплекс),,OMRÅDE 19: Fästning: Säkerhetskomplex,ALAN 19: Kale: Güvenlik Kompleksi +AREA 20: Factory: Receiving,TXT_STRIFE_MAP20,,,,ZÓNA 20: Továrna: Příjem,AREA 20: Fabrik: Modtagelse,ZONE 20: Fabrik: Empfang,,AREO 20: Fabriko: Ricevejo,ÁREA 20: Fábrica: Recepción,,ALUE 20: Tehdas: vastaanotto,ZONE 20: Usine: Réception,20. Terület: Gyár: Beérkeztető,AREA 20: Fabbrica: Ricevimento,"エリア 20: 工場:受取所 +",구역 20: 공장: 수납구역,Zone 20: Fabriek: Ontvangst,OMRÅDE 20: Fabrikken: Mottak,Strefa 20: Fabryka: Odbiór,Área 20: Fábrica: Recebimento,,ZONA 20: Fabrica: Recepție,МЕСТНОСТЬ 20: Фабрика (приём),,OMRÅDE 20: Fabrik: Mottagning,ALAN 20: Fabrika: Teslim Alma +AREA 21: Factory: Manufacturing,TXT_STRIFE_MAP21,,,,ZÓNA 21: Továrna: Výroba,AREA 21: Fabrik: Fremstilling,ZONE 21: Fabrik: Herstellung,,AREO 21: Fabriko: Manufakturo,ÁREA 21: Fábrica: Manufactura,,ALUE 21: Tehdas: tuotanto,ZONE 21: Usine: Manufacture,21. Terület: Gyár: Gyártósor,AREA 21: Fabbrica: Manifattura,エリア 21: 工場:製造機関,구역 21: 공장: 조립시설,Zone 21: Fabriek: Productie,OMRÅDE 21: Fabrikk: Produksjon,Strefa 21: Fabryka: Przetwórstwo,Área 21: Fábrica: Manufatura,,ZONA 21: Fabrica: Procesare,МЕСТНОСТЬ 21: Фабрика (производство),,OMRÅDE 21: Fabrik: Tillverkning,ALAN 21: Fabrika: İmalat +AREA 22: Factory: Forge,TXT_STRIFE_MAP22,,,,ZÓNA 22: Továrna: Slévárna,AREA 22: Fabrik: Smedje,ZONE 22: Fabrik: Schmiede,,AREO 22: Fabriko: Forĝejo,ÁREA 22: Fábrica: Forja,,ALUE 22 Tehdas: paja,ZONE 22: Usine: Forge,22. Terület: Gyár: Kohó,AREA 22: Fabbrica: Fucina,エリア 22: 工場:鉄工所,구역 22: 공장: 제련소,Zone 22: Fabriek: Smederij,OMRÅDE 22: Fabrikk: Smie,Strefa 22: Fabryka: Kuźnia,Área 22: Fábrica: Forja,,ZONA 22: Fabrica: Forja,МЕСТНОСТЬ 22: Фабрика (кузня),,OMRÅDE 22: Fabrik: Smedja,ALAN 22: Fabrika: Demirhane +AREA 23: Order Commons,TXT_STRIFE_MAP23,,,,ZÓNA 23: Náves Řádu,AREA 23: Bestillingscentral,ZONE 23: Mensa des Ordens,,AREO 23: Komunumo de La Ordeno,ÁREA 23: Comuna de La Orden,,ALUE 23: Veljeskunnan messi,ZONE 23: Mess de l'Ordre,23. Terület: Rendi köztér,AREA 23: Camera dell'Ordine,エリア 23: オーダーコモンズ,구역 23: 오더 식당가,Zone 23: Mensa van de orde,OMRÅDE 23: Bestillingsallmenning,Strefa 23: Wikt Zakonu,Área 23: Câmara da Ordem,,ZONA 23: Decontare comenzi,МЕСТНОСТЬ 23: Поселение Ордена,,OMRÅDE 23: Beställningscentraler,ALAN 23: Siparişin ortak alanı +AREA 24: Factory: Conversion Chapel,TXT_STRIFE_MAP24,,,,ZÓNA 24: Továrna: Kaple konverze,AREA 24: Fabrik: Omdannelseskapel,ZONE 24: Umwandlungskapelle,,AREO 24: Fabriko: Konvert-kapelo,ÁREA 24: Fábrica: Capilla de conversión,,ALUE 24: Tehdas: käännytyskappeli,ZONE 24: Usine: Chapelle de Conversion,24. Terület: A megtérés kápolnája,AREA 24: Fabbrica: Cappella di Conversione,エリア 24: 工場:改宗礼拝堂,구역 24: 공장: 전향실,Zone 24: Verbouwingskapel,OMRÅDE 24: Fabrikk: Konverteringskapell,Strefa 24: Fabryka: Kaplica Przemiany,Área 24: Fábrica: Capela de Conversão,,ZONA 24: Fabrica: Capela de conversie,МЕСТНОСТЬ 24: Фабрика (часовня обращения),,OMRÅDE 24: Fabrik: Omvandlingskapell,ALAN 24: Fabrika: Dönüşüm Şapeli +AREA 25: Catacombs: Ruined Temple,TXT_STRIFE_MAP25,,,,ZÓNA 25: Katakomby: Zničený chrám,AREA 25: Katakomberne: Ruineret tempel,ZONE 25: Katakomben: Zerstörter Tempel,,AREO: 25: Katakombo: Ruina templo,ÁREA 25: Catacumbas: Templo arruinado,,ALUE 25: Katakombit: temppeliraunio,ZONE 25: Catacombes: Temple Ruiné,25. Terület: Katakombák: Romtemplom,AREA 25: Catacombe: Tempio in Rovina,エリア 25: 地下墓所:没落した寺院,구역 25: 고대 묘지: 무너진 사원,Zone 25: Catacomben: Vernietigde tempel,OMRÅDE 25: Katakombene: Ruinert tempel,Strefa 25: Katakumby: Zrujnowana Świątynia,Área 25: Catacumbas: Templo Arruinado,Área 25: Túmulos: Templo Arruinado,ZONA 25: Catacombe: Templu în ruine,МЕСТНОСТЬ 25: Катакомбы (руины храма),,OMRÅDE 25: Katakomber: Förfallet tempel,ALAN 25: Yeraltı Mezarları: Yıkık Tapınak +AREA 26: Proving Grounds,TXT_STRIFE_MAP26,,,,ZÓNA 26: Vojenský újezd,AREA 26: Prøvesteder,ZONE 26: Testgelände,,AREO 26: Provejo,ÁREA 26: Campo de pruebas,,ALUE 26: Koetuspaikka,ZONE 26: Terrain d'entraînement,26. Terület: Próbatételek Földje,AREA 26: Banco di Prova,エリア 26: 試練場,구역 26: 증명의 전장,Zone 26: Testgebied,OMRÅDE 26: Prøveplassen,Strefa 26: Poligon Wojskowy,Área 26: Campo de Treinamento,Área 26: Campo de Treino,ZONA 26: Tabăra de instruire,МЕСТНОСТЬ 26: Испытательный полигон,,OMRÅDE 26: Provningsområden,ALAN 26: Kanıtlama Alanları +AREA 27: The Lab,TXT_STRIFE_MAP27,,,,ZÓNA 27: Laboratoř,AREA 27: Laboratoriet,ZONE 27: Das Labor,,AREO 27: La laboratorio,ÁREA 27: El laboratorio,,ALUE 27: Laboratorio,ZONE 27: Laboratoire,27. Terület: A labor,AREA 27: Il Laboratorio,エリア 27: 研究所,구역 27: 연구소,Zone 27: Het laboratorium,OMRÅDE 27: Laboratoriet,Strefa 27: Laboratorium,Área 27: O Laboratório,,ZONA 27: Laboratorul,МЕСТНОСТЬ 27: Лаборатория,,OMRÅDE 27: Labbet,ALAN 27: Laboratuvar +AREA 28: Alien Ship,TXT_STRIFE_MAP28,,,,ZÓNA 28: Mimozemská loď,AREA 28: Fremmed skib,ZONE 28: Außerirdisches Schiff,,AREO 28: Aliplaneda ŝipo,ÁREA 28: Nave alienígena,,ALUE 28: Muukalaisalus,ZONE 28: Vaisseau Alien,28. Terület: Idegen űrhajó,AREA 28: Nave Aliena,エリア 28: エイリアンの船,구역 28: 외계 우주선,Zone 28: Buitenaards schip,OMRÅDE 28: Det fremmede skipet,Strefa 28: Statek Obcych,Área 28: Nave Alienígena,,ZONA 28: Nava extraterestră,МЕСТНОСТЬ 28: Корабль пришельцев,,OMRÅDE 28: Främmande skepp,ALAN 28: Uzaylı Gemisi +AREA 29: Entity's Lair,TXT_STRIFE_MAP29,,,,ZÓNA 29: Doupě Bytosti,AREA 29: Entitetsnesten,ZONE 29: Das Nest der Entität,,AREO 29: Nestego de Estulo,ÁREA 29: Escondite de la Entidad,,ALUE 29: Tosiolevan maja,ZONE 29: Demeure de L'Entité,29. Terület: A Teremtvény Búvóhelye,AREA 29: Tana dell'Entità,エリア 29: エンティティの隠れ家,구역 29: 엔티티의 소굴,Zone 29: Het nest van de entiteit,OMRÅDE 29: Enhetens hule,Strefa 29: Leże Bytu,Área 29: Covil da Entidade,,ZONA 29: Cuibul Entității,МЕСТНОСТЬ 29: Логово Сущности,,OMRÅDE 29: Väsendets lya,ALAN 29: Varlığın İni +AREA 30: Abandoned Front Base,TXT_STRIFE_MAP30,,,,ZÓNA 30: Opuštěná základna Fronty,AREA 30: Forladt frontbase,ZONE 30: Verlassene Basis der Front,,AREO 30: Forlasita Front-Bazo,ÁREA 30: Base abandonada del Frente,,ALUE 30: Hylätty Rintaman tukikohta,ZONE 30: Base Abandonnée du Front,30. Terület: Elhagyatott Előbázis,AREA 30: Base del Fronte abbandonata,エリア 30: 放棄された基地,구역 30: 버려진 프론트 기지,Zone 30: Verlaten frontbasis,OMRÅDE 30: Forlatt frontbase,Strefa 30: Opuszczona Baza Frontu,Área 30: Base da Frente Abandonada,,ZONA 30: Baza abandonată a Frontului,МЕСТНОСТЬ 30: Заброшенная база сопротивления,,OMRÅDE 30: Övergiven frontbas,ALAN 30: Terk Edilmiş Ön Üs +AREA 31: Training Facility,TXT_STRIFE_MAP31,,,,ZÓNA 31: Výcvikové zařízení,AREA 31: Træningsanlæg,ZONE 31: Trainingseinrichtung,,AREO 31: Trejnejo,ÁREA 31: Zona de entrenamiento,,ALUE 31: Koulutuslaitos,ZONE 31: Complexe d'Entraînement,31. Terület: Kiképzőbázis,AREA 31: Struttura di Addestramento,エリア 31: 研修施設,구역 31: 훈련 시설,Zone 31: Trainingsfaciliteit,OMRÅDE 31: Treningsanlegg,Strefa 31: Centrum Szkoleniowe,Área 31: Instalação de Treinamento,,ZONA 31: Spațiul de antrenament,МЕСТНОСТЬ 31: Тренировочный корпус,,OMRÅDE 31: Utbildningsanläggning,ALAN 31: Eğitim Tesisi +AREA 1: Sanctuary,TXT_STRIFE_MAP32,,,,ZÓNA 1: Svatyně,AREA 1: Fristedet,ZONE 1: Heiligtum,,AREO 1: Sanktejo,ÁREA 1: Santuario,,ALUE 1: Pyhäkkö,ZONE 1: Sanctuaire,1. Terület: Szentély,AREA 1: Santuario,エリア 1: 聖域 ,구역 1: 성소,Zone 1: Heiligdom,OMRÅDE 1: Fristedet,Strefa 1: Sanktuarium,Área 1: Santuário,,ZONA 1: Sanctuar,МЕСТНОСТЬ 1: Святилище,,OMRÅDE 1: Fristad,ALAN 1: Sığınak +AREA 2: Town,TXT_STRIFE_MAP33,,,,ZÓNA 2: Město,AREA 2: By,ZONE 2: Stadt,,AREO 2: Urbeto,ÁREA 2: Pueblo,,ALUE 2: Kylä,ZONE 2: Ville,2. Terület: Város,AREA 2: Città,エリア 2: 町,구역 2: 마을,Zone 2: Stad,OMRÅDE 2: By,Strefa 2: Miasto,Área 2: Vila,,ZONA 2: Oraș,МЕСТНОСТЬ 2: Город,,OMRÅDE 2: Stad,ALAN 2: Şehir +AREA 3: Movement Base,TXT_STRIFE_MAP34,,,,ZÓNA 3: Rebelská základna,AREA 3: Front Basis,ZONE 3: Rebellenbasis,,AREO 3: Movad-bazo,ÁREA 3: Base del Movimiento,,ALUE 3: Liikkeen tukikohta,ZONE 3: Base du Front,3. Terület: Mozgalmi Bázis,AREA 3: Base del Movimento,エリア 3: 移転基地,구역 3: 반군 기지,Zone 3: Front basis,OMRÅDE 3: Bevegelsesbase,Strefa 3: Baza Ruchu Oporu,Área 3: Base do Movimento,,ZONA 3: Baza rezistenței,МЕСТНОСТЬ 3: База сопротивления,,OMRÅDE 3: Förflyttningsbas,ALAN 3: Hareket Üssü +AREA 35: Factory: Production,TXT_STRIFE_MAP35,,,,ZÓNA 35: Továrna: Produkce,AREA 35: Fabrik: Produktion,ZONE 35: Fabrik: Produktion,,AREO 35: Fabriko: Produktejo,ÁREA 35: Fábrica: Producción,,ALUE 35: Tehdas: tuotanto,ZONE 35: Usine: Production,35. Terület: Gyár: Termelés,AREA 35: Fabbrica: Produzione,エリア 35: 工場 : 生産ライン,구역 35: 공장: 제작실,Zone 35: Fabriek: Productie,OMRÅDE 35: Fabrikk: Produksjon,Strefa 35: Fabryka: Produkcja,Área 35: Fábrica: Produção,,ZONA 35: Fabrica: Producție,МЕСТНОСТЬ 35: Фабрика (производство),,OMRÅDE 35: Fabrik: Produktion,ALAN 35: Fabrika: Üretim +AREA 36: Castle Clash,TXT_STRIFE_MAP36,,,,ZÓNA 36: Střet na hradě,AREA 36: Slotskampe,ZONE 36: Burg-Konflikt,,AREO 36: Batalo en la kastelo,ÁREA 36: Ataque al castillo,,ALUE 36: Linnayhteenotto,ZONE 36: Bataille du Château,36: Terület: Vári ütközet,AREA 36: Collisione di Castello,エリア 36: キャッスルクラッシュ,구역 36: 성채간의 충돌,Zone 36: Kasteelconflict,OMRÅDE 36: Slottskampen,Strefa 36: Potyczka w Zamku,Área 36: Ataque ao Castelo,,ZONA 36: Bătălia castelului,МЕСТНОСТЬ 36: Битва в замке,,OMRÅDE 36: Slottet Clash,ALAN 36: Kale Çatışması +AREA 37: Killing Grounds,TXT_STRIFE_MAP37,,,,ZÓNA 37: Popravčí zahrady,AREA 37: Drabsområder,ZONE 37: Kampfgelände,,AREO 37: Tereno de mortigado,ÁREA 37: Campo de matanza,,ALUE 37: Tappotanner,ZONE 37: Zone de Chasse,37. Terület: Gyilkos Vidék,AREA 37: Campi di Uccisione,エリア 37: 殺害者の地,구역 37: 살육의 전장,Zone 37: Slagveld,OMRÅDE 37: Drapsplasser,Strefa 37: Śmiercionośny Grunt,Área 37: Campo de Matança,,ZONA 37: Teren de ucis,МЕСТНОСТЬ 37: Сектора обстрела,,OMRÅDE 37: Dödsmark,ALAN 37: Öldürme Alanları +AREA 38: Ordered Chaos,TXT_STRIFE_MAP38,,,,ZÓNA 38: Nařízený chaos,AREA 38: Ordnet kaos,ZONE 38: Geordnetes Chaos,,AREO 38: Orda kaoso,ÁREA 38: Caos ordenado,,ALUE 38: Järjestynyt kaaos,ZONE 38: Chaos Ordonné,38. Terület: Rendezett Káosz,AREA 38: Caos Ordinato,エリア 38: カオスの秩序,구역 38: 정돈된 혼란,Zone 38: Ordelijke chaos,OMRÅDE 38: Ordnet kaos,Strefa 38: Uporządkowany Chaos,Área 38: Caos Ordenado,,ZONA 38: Haos controlat,МЕСТНОСТЬ 38: Управляемый хаос,,OMRÅDE 38: Ordnat kaos,ALAN 38: Düzenli Kaos +,,Hexen,,,,,,,,,,,,,,,,,,,,,,,,, +Winnowing Hall,TXT_HEXEN_MAP01,,,,Sál prosetí,Separationshal,Trennungshalle,,Solenejo de Separado,Sala de los Vientos,,Viskaussali,Chambre de la Séparation,Huzatos Folyosó,Camera di separazione,選抜の間,바람 회관,Scheidingszaal,Vinnersalen,Hala Przesiewu,Sala de Separação,,Sala de Separare,Зал отсеивания,Предсобље просејавања,Hallen för avräkning,Ayrılma Salonu +Seven Portals,TXT_HEXEN_MAP02,,,,Sedmero portálů,Syv portaler,Sieben Portale,,Sep Portaloj,Siete Portales,,Seitsemän portaalia,Les Sept Portails,Hét Portál,I Sette Portali,漆之門,일곱 차원문,Zeven portalen,Syv portaler,Siedem Portali,Sete Portais,,Șapte Portaluri,Семь порталов,Седам портала,Sju portaler,Yedi Portal +Guardian of Ice,TXT_HEXEN_MAP03,,,,Strážce ledu,Vogter af is,Wächter des Eises,,Gardanto de Glacio,Guardián de Hielo,,Jään vartija,Gardien de Glace,A Jég Őre,Guardiano del Ghiaccio,氷の守護者,얼음의 수호자,Bewaker van ijs,Isens vokter,Strażnik Lodu,Guardião de Gelo,,Străjerul Gheții,Страж льда,Чувар леда,Isens väktare,Buz Muhafızı +Guardian of Fire,TXT_HEXEN_MAP04,,,,Strážce ohně,Vogter af ild,Wächter des Feuers,,Gardanto de Fajro,Guardián de Fuego,,Tulen vartija,Gardien de Feu,A Tűz Őre,Guardiano del Fuoco,炎の守護者,화염의 수호자,Bewaker van vuur,Ildens vokter,Strażnik Ognia,Guardião de Fogo,,Străjerul Focului,Страж огня,Чувар огња,Elds väktare,Ateşin Koruyucusu +Guardian of Steel,TXT_HEXEN_MAP05,,,,Strážce oceli,Vogter af stål,Wächter des Stahls,,Gardanto de Ŝtalo,Guardián de Acero,,Teräksen vartija,Gardien d'Acier,Az Acél Őre,Guardiano dell'Acciaio,鋼の守護者,강철의 수호자,Bewaker van staal,Stålets vokter,Strażnik Stali,Guardião de Aço,,Străjerul Oțelului,Страж стали,Чувар челика,Stålets väktare,Çelik Muhafız +Bright Crucible,TXT_HEXEN_MAP06,,,,Světlý očistec,Lys udfordring,Glänzende Feuerprobe,,Luma Krisolo,Crisol de Luz,,Kirkas tulikoe,Creuset Radiant,Fényes Ketrec,Crogiolo Luminoso,光の坩堝,빛나는 고난,Heldere beproeving,Lys utfordring,Tygiel Światła,Crisol de Luz,,Creuzet Luminos,Горнило света,Испит светла,Ljus utmaning,Parlak Pota +Shadow Wood,TXT_HEXEN_MAP13,,,,Temný hvozd,Skyggetræ,Schattenwald,,Ombro-Arbareto,Bosque de la Sombra,,Varjosalo,Forêt des Ombres,Árnyék Erdő,Foresta Oscura,陰影樹,그림자 숲,Schaduwbos,Skyggeskogen,Las Cieni,Floresta das Sombras,,Pădurea Umbrelor,Лес теней,Шума сенки,Skuggskog,Gölge Ahşap +Darkmere,TXT_HEXEN_MAP08,,,,Černý močál,,Düstersee,,Malluma Marĉo,Pantano,,Pikiräme,Marais Noir,Fekete Mocsár,Palude Nera,暗黒の地,흙빛호수,Sombermeer,,Mroczne Bagno,Pantâno Negro,,Mlaștinile Întunecate,Болотная топь,Мочварна земља,Mörkträsk,Koyu göl +Caves of Circe,TXT_HEXEN_MAP09,,,,Kirčiny jeskyně,Circes' grotter,Circes Höhle,,Kavernoj de Circe,Cuevas de Circe,,Circeluolat,Caves de Circé,Körök Barlangja,Grotte di Circe,キルケーの洞窟,키르케의 동굴,Grotten van Circe,Circes grotter,Jaskinie Kirke,Cavernas de Circe,,Peșterile lui Circe,Пещеры Цирцеи,Киркине пећине,Circes grottor,Kirke Mağaraları +Wastelands,TXT_HEXEN_MAP10,,,,Pustiny,Ødemarker,Ödland,,Senvivejo,Yermo,,Erämaat,Terres Ruinées,Senkiföldje,Terre in rovina,荒野,황무지,Woestenij,Ødemarken,Pustkowia,Terras Desoladas,,Tărâmurile Pustii,Пустоши,Пустоши,Ödemarken,Çorak Topraklar +Sacred Grove,TXT_HEXEN_MAP11,,,,Posvátný háj,Helliglund,Heiliger Hain,,Sankta Bosketo,Arboleda Sagrada,,Pyhä metsikkö,Bosquet Sacré,Szent Liget,Boschetto Sacro,神聖なる園,성스러운 수풀,Heilig bosje,Hellig lund,Święty Gaj,Bosque Sagrado,,Crângul Sacru,Священная роща,Свети шумарак,Heliga lunden,Kutsal Koru +Hypostyle,TXT_HEXEN_MAP12,,,,Hypostyl,,Säulenhalle,,Kolonejo,Hipóstila,,Hypostyyli,,Oszlopterem,Ipostilo,多柱の間,다주실,Zuilenhal,,Hypostyl,Hipostilo,,Hipostil,Гипостильный зал,Хипостил,Hypostil,Hipostil +Heresiarch's Seminary,TXT_HEXEN_MAP27,,,,Arcikacířův alumnát,Heresiarkens seminarium,Seminar des Erzketzers,,Seminario de Ĉefherezulo,Seminario del Heresiarca,,Kerettiarkin seminaari,Séminaire de l'Hérésiarche,A Főeretnek Neveldéje,Seminario dell'Heresiarch,ヘレシアークの神学舎,헤러시아크의 신학교,Seminarie van ketterij,Heresiarkens seminar,Seminarium Herezjarchy,Seminário do Heresiarca,,Seminarul Ereziarhului,Семинария Ересиарха,Јересијархов семинар,Heresiarkens seminarium,Heresiark'ın Ruhban Okulu +Dragon Chapel,TXT_HEXEN_MAP28,,,,Dračí kaple,Dragekapel,Drachenkapelle,,Drakkapelo,Capilla Dragón,,Lohikäärmekappeli,Chapelle du Dragon,Sárkány Szentély,Cappella del Drago,ドラゴンの庵寺,드래곤 예배실,Drakenkapel,Dragekapell,Kaplica Smoka,Capela do Dragão,,Capela dragonilor,Часовня дракона,Капела змајева,Drakens kapell,Ejderha Şapeli +Griffin Chapel,TXT_HEXEN_MAP30,,,,Gryfova kaple,Griffinkapel,Greifenkapelle,,Grifkapelo,Capilla Grifo,,Aarnikotkakappeli,Chapelle du Grifon,Griff Szentély,Cappella del Grifone,グリフィンの庵寺,그리핀 예배실,Griffioenenkapel,Griffon kapell,Kaplica Gryfa,Capela do Grifo,,Capela grifonilor,Часовня грифона,Капела грифонова,Griffins kapell,Griffin Şapeli +Deathwind Chapel,TXT_HEXEN_MAP31,,,,Kaple mrakosmrtě,Dødens vind kapel,Todeswindkapelle,,Mortvento-Kapelo,Capilla Viento de Muerte,,Kuolontuulikappeli,Chapelle du Vent Tueur,Halál Szentély,Cappella del Vento Assassino,デスウィンドの庵寺,죽음바람 예배실,Dodenwind kapel,Dødens vind kapell,Kaplica Wiatru Śmierci,Capela do Vento da Morte,,Capela suflului morții,Часовня ветра смерти,Капела ветра смрти,Dödsblåsans kapell,Ölüm Rüzgarı Şapeli +Orchard of Lamentations,TXT_HEXEN_MAP32,,,,Sad nářků,Klagesangens frugthave,Garten der Wehklagen,,Horto de Lamentoj,Huerto de los Lamentos,,Valitusvirtten tarha,Verger des Lamentations,Siránkozás Kertje,Frutteto delle Lamentazioni,哀悼茂る園,통탄의 과수원,Boomgaard van klaagliederen,Klagesangens hage,Płaczący Sad,Pomar das Lamentações,,Livada amărăciunii,Сады плача,Воћњак плача,Klagovisornas trädgård,Ağıtlar Bahçesi +Silent Refectory,TXT_HEXEN_MAP33,,,,Tichý refektář,Stilhedens refektorium,Stilles Refektorium,,Silenta Manĝejo,Refectorio Silencioso,,Hiljainen ruokasali,Réfectoire Silencieux,Néma Refektórium,Refettorio silenzioso,寡黙なる食堂,침묵의 식당,Stil refectory,Stille refektorium,Cichy Refektarz,Refeitório Silencioso,,Refectoriul tăcerii,Безмолвная трапезная,Безгласна трпезарија,Tyst matsal,Sessiz Yemekhane +Wolf Chapel,TXT_HEXEN_MAP34,,,,Vlčí kaple,Ulvekapel,Wolfskapelle,,Lupkapelo,Capilla Lobo,,Susikappeli,Chapelle du Loup,Farkas Szentély,Cappella del Lupo,狼の庵寺,늑대 예배실,Wolvenkapel,Ulvens kapell,Kaplica Wilka,Capela do Lobo,,Capela lupilor,Часовня волка,Капела вучја,Vargkapellet,Kurt Şapeli +Forsaken Outpost,TXT_HEXEN_MAP21,,,,Opuštěné stanoviště,Forladt forpost,Verlassener Vorposten,,Forlasita Posteno,Puesto de Avanzada Abandonado,,Hylätty etuvartio,Base Abandonnée,Elhagyott Őrség,Avamposto Abbandonato,荒れ果てた前哨地,버려진 초소,Verwaarloosde buitenpost,Forlatt utpost,Opuszczony Posterunek,Posto Abandonado,,Avanpostul părăsit,Покинутая застава,Напуштена постаја,Försvunnen utpost,Unutulmuş Karakol +Castle of Grief,TXT_HEXEN_MAP22,,,,Hrad smutku,Sorgens slot,Leidensburg,,Kastelo de Funebro,Castillo del Pesar,,Surulinna,Château de la Souffrance,A Gyász Kastélya,Castello della Sofferenza,嘆きの城,비탄의 성,Kasteel van verdriet,Sorgens slott,Zamek Smutku,Castelo da Aflição,,Castelul întristării,Замок скорби,Замак жалости,Sorgens slott,Keder Kalesi +Gibbet,TXT_HEXEN_MAP23,,,,Šibenice,,Richtstätte,,Pendigilo,Horca,,Hirsipuu,Gibet,Akasztófa,Forca,晒し台,교수대,,Galgen,Szubienica,Forca,,Eșafodul,Виселица,Вешала,,İnfaz yeri +Effluvium,TXT_HEXEN_MAP24,,,,Výpary,,Effluvium,,Efluvo,Efluvio,,Katku,,A Bűz Börtöne,Effluvio,腐臭漂う残骸,악취,,,Odór,Eflúvio,,Efluviu,Зловонный сток,Воњави одвод,,Atık Su +Dungeons,TXT_HEXEN_MAP25,,,,Žalář,Fangehuller,Kerker,,Karceroj,Calabozos,,Tyrmät,Donjons,Kazamaták,I Dungeon,地下牢,지하감옥,Kerkers,Fangehull,Lochy,Masmorras,,Temnițe,Подземелья,Лагуми,Kerker,Zindanlar +Desolate Garden,TXT_HEXEN_MAP26,,,,Zpustošená zahrada,Ødelagt have,Verwildeter Garten,,Dezerta Ĝardeno,Jardín Desolado,,Autio puutarha,Jardin de la Désolation,Sivár Kert,Giardino Desolato,荒涼とした庭,황폐한 정원,Woeste tuin,Øde hage,Spustoszały Ogród,Jardim Desolado,,Grădina dezolantă,Заброшенный сад,Напуштени врт,Ödslig trädgård,Issız Bahçe +Necropolis,TXT_HEXEN_MAP35,,,,Nekropole,Nekropolis,Nekropole,,Nekropolo,Necrópolis,,Nekropoli,Nécropole,Nekropolisz,Necropoli,ネクロポリス,망자의 도시,,Nekropolis,Nekropolia,Necrópole,,Necropola,Некрополь,Некропола,Nekropolis,Nekropol +Zedek's Tomb,TXT_HEXEN_MAP36,,,,Zedekova hrobka,Zedeks grav,Zedeks Gruft,,Tombo de Zedek,Tumba de Zedek,,Sedekin hauta,Tombeau de Zedek,Zedek Sírja,Tomba di Zedek,ゼデクの墓,제닥의 무덤,Zedek's graf,Zedeks grav,Grobowiec Zedeka,Tumba de Zedek,Túmulo de Zedek,Mormântul lui Zedek,Гробница Зедека,Гробница Зедекова,Zedeks grav,Zedek'in Mezarı +Menelkir's Tomb,TXT_HEXEN_MAP37,,,,Menelkirova hrobka,Menelkirs grav,Menelkirs Gruft,,Tombo de Menelkir,Tumba de Menelkir,,Menelkirin hauta,Tombeau de Menelkir,Menelkir Sírja,Tomba di Menelkir,メネルキルの墓,메넬키어의 무덤,Menelkir's graf,Menelkirs grav,Grobowiec Menelkira,Tumba de Menelkir,Túmulo de Menelkir,Mormântul lui Menelkir,Гробница Менелкира,Гробница Менелкирова,Menelkirs grav,Menelkir'in Mezarı +Traductus' Tomb,TXT_HEXEN_MAP38,,,,Traduktova hrobka,Traductus' grav,Traductus' Gruft,,Tombo de Traductus,Tumba de Traductus,,Traduktuksen hauta,Tombeau de Traductus,Traductus Sírja,Tomba di Traductus,トダクティスの墓,트라닥투스의 무덤,Traductus' graf,Traductus' grav,Grobowiec Traduktusa,Tumba de Traductus,Túmulo de Traductus,Mormântul lui Traductus,Гробница Традактуса,Гробница Традуктусова,Traductus' grav,Traductus'un Mezarı +Vivarium,TXT_HEXEN_MAP39,,,,Vivárium,,,,Vivario,Vivario,,Vivaario,,Vivárium,Vivario,ビバリウム,사육장,,,Wiwarium,Viveiro,,Vivariu,Виварий,Виваријум,, +Dark Crucible,TXT_HEXEN_MAP40,,,,Temný očistec,Mørk udfordring,Dunkle Feuerprobe,,Malluma Krisolo,Crisol de Oscuridad,,Pimeä tulikoe,Creuset Sombre,Sötét Ketrec,Crogiolo Buio,"暗黒の坩堝 +",어두운 고난,Donkere beproeving,Mørkets utfordring,Tygiel Mroku,Crisol das Trevas,,Creuzet Întunecat,Испытание тьмы,Испит таме,Mörk utmaning,Karanlık Pota +,,Hexen Deathkings,,,,,,,,,,,,,,,,,,,,,,,,, +Ruined Village,TXT_HEXDD_MAP41,,,,Zničená vesnice,Ødelagt landsby,Zerstörtes Dorf,,Ruina vilaĝo,Pueblo en ruinas,,Rauniokylä,Village en Ruines,Az Elpusztított Falu,Villagio in Rovine,廃村,파괴된 마을,Ruïneerd dorp,Den ødelagte landsbyen,Zrujnowana Wioska,Aldeia Destruída,Aldeia em Ruinas,Sat ruinat,Разрушенная деревня,Уништено село,Ruinerad by,Yıkık Köy +Blight,TXT_HEXDD_MAP42,,,,Pohroma,Skylle,Fäule,,Pesto,Decaimiento,,Turmelus,Peste,Penész,Peste,疫病,황폐화,Ziekte,Skade,Zaraza,Peste,,Cotropit,Упадок,Пошаст,Sköldpest,Yanıklık +Sump,TXT_HEXDD_MAP43,,,,Žumpa,Sump,Sumpf,,Olekuvo,Pozo de Barro,,Likakaivo,Puisard,Tócsa,Pozzetto,汚水槽,웅덩이,Moeras,,Studzienka,Poço de Lama,,Joampă,Грязеотстойник,Сливник,,Karter +Catacomb,TXT_HEXDD_MAP44,,,,Katakomby,Katakomb,Katakombe,,Katakombo,Catacumba,,Katakombi,Catacombe,Katakomba,Catacombe,カタコンベ,지하 묘실,Katacombe,Katakombe,Katakumba,Catacumba,,Catacombă,Катакомба,Катакомба,Katakomb,Katakomb +Badlands,TXT_HEXDD_MAP45,,,,Pustiny,Ødemarker,Ödland,,Badlandoj,Páramos,,Autiomaa,Terres Sauvages,Terméketlen Föld,Terre Selvagge,不毛地帯,불모지,Woestijn,Dårlige land,Pustkowia,Ermo,,Deșert,Бесплодные земли,Пустош,Dåliga marker,Çorak Topraklar +Brackenwood,TXT_HEXDD_MAP46,,,,Prales,,Moorwald,,Pteridejo,Brackenwood,,Saniaissalo,Forêt de Bracken,Páfrány Erdő,Foresta di Felce,ワラビの樹,고사리숲,Moorbos,,Las Paproci,Floresta de Samambaias,,Pădure de ferigi,Брекенвуд,Папрат,Brackenwood,Bataklık orman +Pyre,TXT_HEXDD_MAP47,,,,Hranice,Bål,Scheiterhaufen,,Kremaciejo,Pira Funeraria,,Rovio,Brasier,Máglya,Pira,火葬薪,화장,Brandstapel,Bål,Ognisko,Pira,,Rug,Погребальный костёр,Ломача,Bål,Ateş Yakmak +Constable's Gate,TXT_HEXDD_MAP48,,,,Konstáblova brána,Vagtport,Wachtor,,Pordego de Ĝendarmo,Puerta del Alguacil,,Konstaapelin portti,Portail du Constable,Csendőr Kapu,Porta del Conestabile,城守達の門,무관장의 문,Constable's poort,Konstabelporten,Brama Posterunkowego,Portão do Condestável,,Poarta ofițerului,Комендантские врата,Чиновникова капија,Konstapelns port,Muhafız Kapısı +Treasury,TXT_HEXDD_MAP49,,,,Pokladnice,Skatkammer,Schatzkammer,,Trezorejo,Tesorería,,Rahasto,Trésorerie,Kincstár,Tesoreria,宝庫,국고,Schatkist,Skattkammeret,Skarbiec,Tesouraria,,Vistierie,Сокровищница,Трезор,Skattkammaren,Hazine Müsteşarlığı +Market Place,TXT_HEXDD_MAP50,,,,Tržnice,Markedspladsen,Marktplatz,,Foirejo,Plaza del Mercado,,Markkinat,Place du Marché,Piactér,Piazza del Mercato,市場,시장,Markt,Markedsplassen,Rynek,Feira,,Piață,Рыночная площадь,Пијаца,Marknadsplats,Pazar Yeri +Locus Requiescat,TXT_HEXDD_MAP51,,,,,,Locus Requiescat,,Locus Requiescat,Lugar de Descanso Eterno,,,Locus Requiescat,,,祈祷師の軌跡,명복의 장소,,,Locus Requiescat,,,,Место вечного упокоения,Место починка,,Locus Requiescat +Ordeal,TXT_HEXDD_MAP52,,,,Utrpení,Forbandelse,Heimsuchung,,Provo Per Aflikto,Prueba,,Koettelemus,Supplice,Megpróbáltatás,Supplizio,試練,시죄의 시련,Orde,Prøvelsen,Męka,Suplício,,Supliciu,Испытание,Изазов,Rättegång,Çile +Armory,TXT_HEXDD_MAP53,,,Armoury,Zbrojnice,Våbenkammer,Waffenkammer,,Armilejo,Armería,,Asehuone,Amurerie,Fegyvertár,Armeria,武器庫,무기고,Wapenkamer,Våpenkammer,Zbrojownia,Arsenal,,Arsenal,Оружейная,Оружарница,Vapenförråd,Cephanelik +Nave,TXT_HEXDD_MAP54,,,,Chrámová loď,,Kirchenschiff,,Navo,La Nave,,Laiva,Nef,Templomhajó,Navata,身廊,본당,Naaf,Skipet,Nawa,,,Naos,Неф,Брод,,Nef +Chantry,TXT_HEXDD_MAP55,,,,Modlitebna,Korskirke,Kantorei,,Kapelo,Capilla,,Kappeli,Chapelle,Gyászkápolna,Cappella,小礼拝堂,예배당,,Minnekapellet,Kaplica Wotywna,Capela,,Capelă,Часовня,Капела,Kyrkogård,Dua Odası +Abattoir,TXT_HEXDD_MAP56,,,,Jatka,Slagteriet,Schlachthaus,,Buĉejo,Matadero,,Teurastamo,Abbatoire,Vágóhíd,Mattatoio,屠殺場,도살장,Slachthuis,Slakteriet,Rzeźnia,Matadouro,,Abator,Бойня,Кланица,Slakthus,Mezbaha +Dark Watch,TXT_HEXDD_MAP57,,,,Tmavá hlídka,Mørk vagt,Dunkle Wache,,Ombra Gardisto,Guardia Oscura,,Pimeä vartio,Garde Noire,Éjjeli Őrség,Guardia Oscura,闇の刻計,어둠의 감시초소,Donkere horloge,Mørkets vakt,Ciemna Strażnica,Guarda Negra,,Gardian întunecat,Тёмный страж,Мрачни чувар,Mörk vakt,Karanlık Saat +Cloaca,TXT_HEXDD_MAP58,,,,Kloaka,,Kloake,,Kloako,Cloaca,,Kloaakki,Cloaque,Kloáka,,排泄腔,하수구,,,Kloaka,,,,Клоака,Клоака,,Kloaka +Ice Hold,TXT_HEXDD_MAP59,,,,Ledová pevnost,Isrum,Eiskammer,,Fuorto el Glacio,Tierra de Hielo,,Jääsäilö,Fort de Glace,Jégtorony,Fortezza di Ghiaccio,氷結,빙고,Ijskamer,Ishall,Lodowa Twierdza,Fortaleza de Gelo,,Fort glaciar,Ледяная твердь,Ледена утврда,Ishållet,Buz Tutucu +Dark Citadel,TXT_HEXDD_MAP60,,,,Temná citadela,Mørkt citadel,Dunkle Festung,,Ombra Citadelo,Fortaleza Oscura,,Pimeä linnake,Citadelle Sombre,Sötét Torony,Cittadella Oscura,暗黒の城塞,어둠의 요새,Donkere citadel,Mørkets citadell,Mroczna Cytadela,Cidadela Negra,,Cetatea întunecată,Тёмная цитадель,Мрачна цитадела,Mörkt citadell,Karanlık Kale +Transit,TXT_HEXDD_MAP33,,,,Převoz,,,,Vojo,Sala de Espera,,Läpikulku,,Tranzit,Passaggio,変遷,통로,Doorvoer,Transitt,Tranzyt,Sala de Espera,,Tranzit,Переход,Прелаз,,Transit +Over'n Under,TXT_HEXDD_MAP34,,,,Nad a Pod,,Drunter und Drüber,,Sub kaj Supre,Arriba y Abajo,,Yli ja ali,Sens Dessus Dessous,Fent és Lent,Sopra e Sotto,天と地,높낮이,Over'n under,Over og under,Nad I Pod,Sobre e Sob,,Mai sus și Mai jos,Выше и ниже,Изнад и испод,Över'n Under,Üst ve Alt +Deathfog,TXT_HEXDD_MAP35,,,,Mha skonu,Dødens tåge,Todesnebel,,Mortnebulo,Niebla de Muerte,,Kuolonsumu,Brume Mortelle,Halálköd,Nebbia di Morte,死の霧,죽음의 안개,Dodenmist,Dødståke,Mgła Śmierci,Névoa da Morte,,Ceața morții,Туман смерти,Магла смрти,Dödsfog,Ölüm Sisi +Castle of Pain,TXT_HEXDD_MAP36,,,,Hrad bolesti,Frygtens slot,Burg der Angst,,Kastelo de Doloro,Castillo del Dolor,,Tuskan linna,Château de la Douleur,Fájdalom Kastélya,Castello del Dolore,苦しみの城,고통의 성,Kasteel van pijn,Smertens slott,Zamek Bólu,Castelo da Dor,,Castelul durerii,Замок боли,Тврђава бола,Slottet av smärta,Acı Kalesi +Sewer Pit,TXT_HEXDD_MAP37,,,,Odpadní jáma,Kloakgrube,Kanalgrube,,Fekaĵputo,Pozo de Residuos,,Viemärimonttu,Trou d'Egout,Kanális akna,Fossa della Fogna,地下溝穴,하수도,Rioolput,Kloakkgropen,Ściek,Fossa de Esgoto,,Groapa de scurgere,Сточная яма,Канализациона јама,Avloppsgrop,Kanalizasyon Çukuru +The Rose,TXT_HEXDD_MAP38,,,,Růže,Rosen,Die Rose,,La Rozo,La Rosa,,Ruusu,La Rose,A Rózsa,La Rosa,薔薇,장밋빛,De roos,Rosen,Róża,A Rosa,,Roza,Роза,Ружа,Rosen,Gül +,,Intermission texts,,,,,,,,,,,,,,,,,,,,,,,,, "Once you beat the big badasses and clean out the moon base you're supposed to win, aren't you? Aren't you? Where's @@ -338,7 +338,21 @@ Zdá se, že jsi ztroskotal@[ao_cs] na březích pekla. Jediná cesta ven je skrz. DOOM pokračuje v epizodách Břehy pekla -a jejím úžasném pokračování, Infernu!","Nachdem du die großen Schurken besiegt und in +a jejím úžasném pokračování, Infernu!","Når du har slået de store skurke og +ryddet månebasen, er det meningen, +at du skal vinde, ikke sandt? Hvor er +din fede belønning og din billet hjem? +Hvad fanden er det her? Det er ikke +meningen, at det skal ende på denne måde! + +Den stinker som råddent kød, men ligner +den forsvundne Deimos-base. Det ser ud +til, at du sidder fast på Helvedes kyster. +Den eneste vej ud er gennem. + +Hvis du vil fortsætte DOOM-oplevelsen, +kan du spille Helvedes kyster +og den fantastiske efterfølger, Inferno!","Nachdem du die großen Schurken besiegt und in der Mondbasis aufgeräumt hast, hättest du sicher erwartet, zu gewinnen, nicht wahr? Nicht wahr? Wo ist deine fette Belohnung und @@ -352,48 +366,48 @@ Der einzige Weg hier raus ist durch. Um das DOOM-Erlebnis fortzusetzen, spiele „Die Ufer der Hölle“ und die erstaunliche -Fortsetzung, „Inferno“!",,"Kiam vi venkus la grandajn malbonulojn -kaj purigus la lunbazon, vi onidire -gajnus, ĉu ne? Ĉu ne? Kie estas -via granda rekompenco kaj bileto hejmen? -Kio diable estas ĉi tio? Ne devas fini tiel! - -Odoraĉas kiel putra karno, sed aspektas -kiel la perdita Dejmo-bazo. Ŝajnas ke -vi estas kaptita sur La Bordoj de Infero. -La sola eliro estas tra. - -Por daŭrigi travivi DOOM, ludu -""La Bordoj de Infero"" kaj -ĝian mirigan sekvon — ""Inferno""!","Una vez has vencido a los tremendos bastardos -y limpiado la base lunar se supone -que deberías ganar, ¿verdad? ¡¿Verdad?! -¿Dónde esta tu suculenta recompensa -y tu pasaje a casa? ¿Qué diablos es esto? -¡Esto no debería terminar así! - -Huele a carne podrida, pero se ve como -la base perdida de Deimos. Parece que estás -atrapad@[ao_esp] en las Orillas del Infierno. -La única salida es atravesarlo. - -Para continuar la experiencia de DOOM, -juega Las Orillas del Infierno y su -sorprendente secuela, ¡Inferno!","Una vez que venciste a los tremendos bastardos -y limpiaste la base lunar se supone -que habrías ganado ¿verdad? ¡¿Verdad?! -¿Dónde esta tu suculenta recompensa -y tu pasaje a casa? ¿Qué diablos es esto? -¡No se supone que termine así! - -Huele a carne podrida, pero se ve como -la base perdida de Deimos. Parece que estás -atrapad@[ao_esp] en las orillas del infierno. -La única salida es por ahí. - -Para continuar la experiencia de DOOM, -juega Las orillas del infierno y su -sorprendente secuela, ¡Averno! ","Päihitettyäsi isot pahikset ja raivattuasi +Fortsetzung, „Inferno“!",,"Post kiam vi elpurigis la bazon +en Fobo je tiuj maliculoj, vi logike +venkus, ĉu? Ĉu!? Kie estas via granda +rekompenco kaj bileto hejmen? Kio diable +okazis? Ĉi tio ne devus finiĝi ĉi tiel! + +Odoras putran karnon, sed ĝi aspektas +kiel la perdita bazo en Dejmo. Ŝajnas, +ke vi estas kaptita ĉe la Infer-bordoj: +por espaki oni transiru la Inferon. + +Por daŭrigi la DOOM-sperton, ludu +la epizodon «La Infer-bordoj» kaj +ĝian bonegan sekvon: «Inferno»!","Tras vencer a esos perversos y +limpiar la base de Fobos se supone +que deberías ganar, ¿no?, ¿¡no!? +¿Qué diablos ha pasado?, ¿dónde están tu +suculenta recompensa y tu pasaje a casa? +¡Esto no debería terminar así! + +Huele a carne podrida, pero se ve como +la base perdida de Deimos. Pareces estar +atrapado en las orillas del Infierno: +la única forma de salir es atravesarlo. + +Para seguir con la experiencia de DOOM, +¡juega a «Las orillas del Infierno» y +a su sorprendente secuela: «Inferno»!","Tras vencer a esos perversos y +limpiar la base de Fobos se supone +que deberías ganar, ¿no?, ¿¡no!? +¿Qué diablos pasó?, ¿dónde están tu +suculenta recompensa y tu pasaje a casa? +¡Esto no debería terminar así! + +Huele a carne podrida, pero se ve como +la base perdida de Deimos. Pareces estar +atrapado en las orillas del Infierno: +la única forma de salir es atravesarlo. + +Para seguir con la experiencia de DOOM, +¡juega a «Las orillas del Infierno» y +a su sorprendente secuela: «Inferno»!","Päihitettyäsi isot pahikset ja raivattuasi kuutukikohdan sinunhan pitäisi voittaa, eikö niin? Eikö niin? Missä on mehevä palkkiosi ja paluulippusi kotiin? Mitä @@ -421,22 +435,21 @@ La seule sortie est de l'autre côté. Pour continuer à découvrir DOOM, jouez à « LES PORTES DE L'ENFER » et à son incroyable suite, « INFERNO »! -","Most, hogy elbántál a rosszfiúkkal és +","Most, hogy elbántál a rohadékokkal és kitakarítottad a holdbázist, elvileg győznöd kéne, nem? Nem? Hol van a zsíros jutalmad meg a retúrjegyed? Mégis mi a fene ez? Ennek nem így kéne végződnie! -Bűzlik, mint a rothadt hús, de ez az -elveszett Deimos bázisnak látszik. +Úgy bűzlik, mint a rothadt hús, de ez az +eltűnt Deimos bázisnak látszik. Úgy tűnik, a pokol tornácán ragadtál. Az egyetlen kiút előre vezet. A DOOM élmény folytatásához játszd ""A pokol tornáca"" fejezetet, és annak -elképesztő folytatását, az ""Inferno""-t! -","Una volta che hai eliminato i cattivi e +elképesztő folytatását, az ""Alvilág""-ot!","Una volta che hai eliminato i cattivi e liberato la base lunare dovresti aver vinto, vero? Vero? Dove sono la tua ricca ricompensa e il biglietto per @@ -450,8 +463,8 @@ sulle Coste dell'Inferno. L'unica uscita ci passa in mezzo. Per continuare l'esperienza di DOOM -gioca 'The Shores of Hell' e il suo -incredibile seguito, 'Infernò! +gioca ""Le rive dell'Inferno"" e il suo +incredibile seguito: ""Inferno""! ","火星基地から巨悪をこの手で一掃し 勝利を収めたはずだ。だがこれはいったい何だ? 巨額の報酬と帰還チケットは? @@ -461,7 +474,7 @@ incredibile seguito, 'Infernò! そのまま沈むしかないようだ。 肉の腐敗臭がする、滅んだダイモス基地に。 -この運命を受け入れ 地獄の瀬戸際か +この運命を受け入れ、地獄の瀬戸際か 或いは脅威なる インフェルノ へ立ち向かえ! ","당신이 악당 보스를 처치하고 달기지를 청소했다면, 당신은 이겨야 한다. 안 그런가? 안 그런가? 그 잘난 보상금과 집으로 가는 티켓은 어딨단 말인가? @@ -481,43 +494,45 @@ huis? Wat is dat, verdomme? Zo zou het niet moeten eindigen! Het stinkt naar rot vlees, maar lijkt -op de vergeten Deimos basis. Het lijkt erop -dat je vastzit aan de oevers van de hel. -De enige uitweg is door. +op de vergeten Deimosbasis. Het lijkt erop +dat je vastzit aan de Oevers van de Hel. +De enige uitweg is erdoor. Om de DOOM-ervaring voort te zetten, speel -je ""De oevers van de hel"" en het -geweldige vervolg, ""Inferno!"". -","Kiedy już pokonałeś tych wielkich -skurczybyków i wyczyściłeś bazę na -księżycu powinieneś wygrać, prawda? -Prawda? Gdzie jest twoja wielka -wygrana i bilet powrotny do domu? -Co to ma być u diabła? +De Oevers van de Hel en het +geweldige vervolg Inferno! +","Når du slår de store tøffingene og renser månebasen, skal du vinne, ikke sant? Ikke sant? Hvor er den fete belønningen din og billetten hjem? Hva i helvete er dette? Det skulle ikke ende slik! + +Det stinker som råttent kjøtt, men ser ut som den tapte Deimos-basen. Ser ut som du sitter fast på Helvetes bredder. Den eneste veien ut er gjennom. + +For å fortsette DOOM-opplevelsen, spill Helvetes kyster og dets fantastiske oppfølger, Inferno!","Pokonałeś wielkich bydlaków +i wyczyściłeś bazę na księżycu, +więc powinieneś wygrać, prawda? +Prawda? Gdzie twoja wielka +nagroda i bilet powrotny do domu? +Co to ma być do diabła? To nie miało się tak skończyć! -Śmierdzi jak zgniłe mięso, ale wygląda -na opuszczoną bazę na Deimosie. +Śmierdzi jak zgniłe mięso, ale przypomina +opuszczoną bazę na Deimosie. Wygląda na to, że utknąłeś w -Przedsionku Piekieł. Jedyną drogą -jest iść naprzód. +Przedsionku Piekieł. Nie ma już odwrotu. -Aby kontynuować przygodę z DOOMem, -zagraj w epizod Przedsionek Piekieł -oraz jego wspaniałą kontynuację, -Piekło!","Após derrotar essas criaturas miseráveis e +Aby kontynuować przygodę z DOOM-em, +zagraj w ""Przedsionek piekieł"" +oraz jego niesamowitą kontynuację - ""Inferno""!","Após derrotar essas criaturas miseráveis e limpar a base lunar você deveria ter vencido, não é mesmo? Não é mesmo? Cadê a sua grande recompensa e a passagem de volta para casa? Não deveria acabar desse jeito! -Fede a carne podre, mas deve ser a base -perdida de Deimos. Parece que você está -preso nas Margens do Inferno. O único -jeito de sair é através dela. +O cheiro é de carne podre, mas parece ser +a base perdida de Deimos. Parece que você +está preso nas Margens do Abismo. +O único jeito de sair é através dela. Para continuar a experiência ""DOOM"", -jogue As Margens do Inferno e sua +jogue As Margens do Abismo e sua incrível sequência, Inferno!","Após derrotar as criaturas miseráveis e limpar a base lunar devias ter ganho, É, não é? Não é? Onde está a tua @@ -530,7 +545,7 @@ preso nas Margens do Inferno. O único maneira de sair é por aqui. Para continuar a experiência ""DOOM"", -jogue As Margens do Inferno e sua +jogue As Margens do Abismo e sua incrível sequência, Inferno!","Odată ce-i învingi pe ticăloși și cureți baza de pe Phobos, se presupune că ai câștigat, nu-i așa? Nu-i așa? Unde-ți sunt @@ -544,20 +559,22 @@ mergând tot înainte. Ca să continui experiența DOOM, joacă „Țărmurile Iadului” și continuarea sa nemaipomenită, -„Infernul”!","Уничтожив Баронов Ада и зачистив лунную -базу, Вы должны были победить, не так ли? -Не так ли? Где заслуженная награда и -билет домой? Что это за чертовщина? -Всё должно было закончиться не так! - -Это место пахнет как гнилое мясо, а -выглядит как потерянная база на Деймосе. -Похоже, Вы застряли на берегах Ада, и -единственный путь теперь — пройти через них. - -Чтобы продолжить погружение в игру, -пройдите эпизод «Берега Ада» и его -замечательный сиквел «Инферно»!","Једном када средите велике момке и +„Infernul”!","После победы над крутыми злодеями и +зачистки фобосской базы на вашей улице +должен быть праздник, ведь так? Ведь так? +А где же большой приз и билет домой? Какого +дьявола? Всё должно было закончиться не так! + +Полная тухлятина, похоже на потерянную базу на +Деймосе. Кажется, вы застряли на +прибрежье преисподней. Путь только +один — вперёд. + +Чтобы продолжить путешествие по DOOM, +сыграйте в «Прибрежье преисподней» +и его замечательное продолжение, +«Инферно»! +","Једном када средите велике момке и очистите базу месеца, требало би да победите, зар не? Зар не? Где је ваша грандиозна награда и карта кyћи? Шта @@ -572,7 +589,39 @@ Iadului” și continuarea sa nemaipomenită, Да бисте наставили искуство DOOM-а, играјте Обале пакла и његов невероватни наставак, Инферно! -" +","När du har besegrat de stora +skurkarna och rensat månbasen +är det meningen att du ska vinna, +eller hur? Eller hur? Var är din feta +belöning och din biljett hem? Vad +i helvete är det här? Det är inte +meningen att det ska sluta så här! + +Det stinker som ruttet kött, men ser +ut som den förlorade Deimosbasen. +Det ser ut som om du är fast på +helvetets stränder. +Den enda vägen ut är genom. + +För att fortsätta DOOM-upplevelsen +kan du spela Helvetets stränder och +dess fantastiska uppföljare Inferno!","Büyük belalıları yendikten ve ay +üssünü temizledikten sonra +Kazanmak için, değil mi? Değil +misin? Nerede? büyük ödülün +ve eve dönüş biletin? Ne? Bu da +ne böyle? Bunun olması gerek- +miyordu. Bu şekilde bitecek! + +Çürümüş et gibi kokuyor ama +Kayıp Deimos üssü gibi. +Görünüşe göre Cehennem +Kıyıları'nda sıkışıp kaldınız. +Tek çıkış yolu içinden geçmek. + +DOOM deneyimine devam etmek +için Cehennem Kıyıları ve +muhteşem Devam filmi, İnferno!" "You've done it! The hideous cyber- demon lord that ruled the lost Deimos moon base has been slain and you @@ -603,7 +652,22 @@ litovat, že o tobě kdy slyšeli! Rychle ses slanil@[ao_cs] dolů na povrch pekla. Teď už zbývá poslední epizoda DOOMU: -Inferno.","Du hast es geschafft! Der fiese Cyber- +Inferno.","Du har gjort det! Den afskyelige cyberdæmon- +herre, der herskede over den forsvundne +Deimos-månebase, er blevet dræbt, og du +er triumferende! Men ... hvor er du? +Du klatrer op på månens kant og kigger +ned for at se den frygtelige sandhed. + +Deimos svæver over selve helvede! +Du har aldrig hørt om nogen, der er +undsluppet fra Helvede, men du vil +få de svin til at fortryde, at de +nogensinde har hørt om dig! Hurtigt +stiger du ned til Helvedes overflade. + +Nu går det videre til det sidste +kapitel af DOOM! -- Inferno.","Du hast es geschafft! Der fiese Cyber- dämonenlord, der die vergessene Deimos-Basis beherrschte, ist tot und du triumphierst. Aber ... wo bist du? @@ -618,37 +682,51 @@ den Bastarden schon zeigen, dass sie wünschten, nie von dir gehört zu haben. Nun geht es weiter zum letzten Kapitel von -DOOM - Inferno.",,"Vi sukcesis! La malbelega cibordemono -lordo kiu regis la perditan Deimos lunan -bazamenton estis mortigita kaj vi estas -triumfa! Sed ... kie vi estas? -Vi suprenrampas al rando de la luno -kaj rigardas malsupren por vidi la -malbonegan veron. - -Dejmo flosas super Infero mem! -Vi neniam sciiĝis pri iu ajn eskapi Inferon, -sed vi igos la bastardojn bedaŭri pri iam -ajn renkonti vin! Rapide, vi rapelas -malsupren al la surfaco de Infero. - -Nun estas la fina ĉapitro de DOOM! - -- Inferno.","¡Lo hiciste! ¡El horrendo ciber-demonio que -regía la base lunar perdida de Deimos -ha sido asesinado y has triunfado! -Pero... ¿Dónde estás? Trepas hasta el -borde de la luna y miras abajo para -ver la horrorosa verdad. - -¡Deimos flota sobre el mismísimo infierno! -Nunca has oído de alguien escapar del -infierno, ¡pero harás que los bastardos -lamenten no haber escuchado sobre tí! -Rápidamente, desciendes a rapel +DOOM - Inferno.",,"Vi sukcesis! La malbelega Ciberdemono, +kiu regis la perditan lunbazon en Dejmo, +estis mortigita kaj vi triumfis! +Sed... Kie vi estas? Vi grimpas al la +rando de la luno kaj rigardas malsupren +por vidi la malbonegan veron: + +Dejmo ŝvebas super la Infero mem! +Vi neniam sciiĝis pri eskapinto el la +Infero, sed nun tiuj aĉuloj bedaŭros, +ke ili ja sciiĝis pri vi! Vi surteriĝas +per ŝnuro sur la surfacon de la Infero. + +Nun ek al la fina ĉapitro de +DOOM: «Inferno»!","¡Enhorabuena! ¡El horrendo Ciberdemonio +que regía la base lunar perdida de Deimos +ha sido aniquilado y has triunfado! +Pero... ¿Y dónde estás? +Trepas hasta el borde de la luna y +miras abajo para ver la horrorosa verdad: + +¡Deimos flota sobre el mismísimo Infierno! +Nunca has escuchado de alguien escapar del +Infierno, ¡pero harás que esos malnacidos +se lamenten de sí haber oído sobre ti! +Rápidamente desciendes a rapel +hacia la superficie del Infierno. + +¡Ahora al capítulo final de +DOOM: «Inferno»!","¡Lo lograste! ¡El horrendo Ciberdemonio +que regía la base lunar perdida de Deimos +fue aniquilado y saliste triunfando! +Pero... ¿Y dónde estás? +Trepas hasta el borde de la luna y +miras abajo para ver la horrorosa verdad: + +¡Deimos flota sobre el mismísimo Infierno! +Nunca has escuchado de alguien escapar del +Infierno, ¡pero harás que esos malnacidos +se lamenten de sí haber oído sobre ti! +Rápidamente desciendes a rapel hacia la superficie del Infierno. -¡Ahora, estás en el capitulo final de -DOOM! -- Inferno.",,"Teit sen! Menetettyä Deimoksen kuutukikohtaa +¡Ahora al capítulo final de +DOOM: «Inferno»!","Teit sen! Menetettyä Deimoksen kuutukikohtaa hallinnut kauhistuttava kyberdemoni on surmattu ja olet voittoisa! Mutta... missä olet? Kapuat kuun kielekkeelle ja @@ -677,12 +755,12 @@ vous descendez en rappel aux enfers. Il est maintenant temps pour le chapitre final de DOOM! -- INFERNO.","Megcsináltad! Győzedelmeskedtél az -elveszett Deimos bázist uraló förtelmes +elveszett Deimosz bázist uraló förtelmes Kiberdémon felett! De... hol is vagy most? Felkapaszkodsz a Hold szélére, és lenézel, hogy megtudd a szörnyű igazságot. -A Deimos a pokol fölött lebeg! +A Deimosz a pokol fölött lebeg! Még nem hallottál arról, hogy bárki megszökött volna a pokolból, de te úgy meg fogod leckéztetni a rohadékokat, @@ -691,7 +769,7 @@ rólad! Gyorsan leereszkedsz a pokol felszínére. Most pedig jöjjön a DOOM utolsó -fejezete, az ""Inferno""!","Ce l'hai fatta! Il malvagio cyber- +fejezete, az ""Alvilág""!","Ce l'hai fatta! Il malvagio cyber- demonio che governava la dispersa base di Deimos è stato ucciso e tu sei trionfante! Ma... dove ti trovi? @@ -706,8 +784,8 @@ sentito parlare di te! Velocemente scendi verso la superficie dell'Inferno. -è ora del capitolo finale di -DOOM! - 'Infernò.","よくやった! 滅んだダイモス基地を支配していた +È ora del capitolo finale di +DOOM: ""Inferno""!","よくやった! 滅んだダイモス基地を支配していた サイバーデーモンはナマクラの鉄屑と化した! だが...ここは一体何処だ? 外壁の縁をよじ登りその鉄屑にも劣る現実に直面にした。 @@ -717,7 +795,7 @@ DOOM! - 'Infernò.","よくやった! 滅んだダイモス基地を支配して 誰の手も借りず地獄から逃げ出せた人間の話を 聞いたことも無いが、誰がここへ来たか奴等に思い知らせ、 -後悔させる為にも 今すぐ インフェルノ へ降り立て! +後悔させる為にも今すぐ インフェルノ へ降り立て! ","당신이 해냈다! 데이모스 기지를 통치하던 마왕, 사이버데몬이 파괴되었고 당신이 이겼다! 하지만... 지금 당신은 어디 있는가? 당신은 데이모스의 @@ -728,39 +806,53 @@ DOOM! - 'Infernò.","よくやった! 滅んだダイモス基地を支配して 바꿔 놓을 수 있다! 재빠르게 당신은 데이모스에서 내려와 지옥의 표면으로 내려왔다. -이제... 둠의 마지막 탄- 연옥이다!","Het is je gelukt! De gemene cyberdemon heer -die de verloren Deimos maanbasis regeerde -is dood en jij triomfeert. Maar ... waar ben je? +이제... 둠의 마지막 탄- 연옥이다!","Het is je gelukt! Het afschuwelijke cyberdemoon +dat de heerste over de verloren maanbasis van +Deimos is dood en jij triomfeert. Maar ... waar ben je? Je klautert naar de rand van de maan en kijkt naar beneden om de vreselijke waarheid te zien. -Deimos drijft boven de hel zelf! Je hebt +Deimos zweeft boven de hel zelf! Je hebt nog nooit gehoord van iemand die uit de hel is ontsnapt, maar de klootzakken zullen er spijt van krijgen dat ze ooit van je gehoord -hebben! Snel, je stapt naar beneden naar de +hebben! Snel stap je naar beneden, naar de oppervlakte van de hel. -Nu, het is op naar het laatste hoofdstuk -van DOOM! -- ""Inferno"". - -","Udało ci się! Paskudny lord cyberdemon, +Nu is het op naar het laatste hoofdstuk +van DOOM! -- Inferno. +","Du har klart det! Den avskyelige +cyberdemonherren som styrte +den tapte månebasen Deimos +har blitt drept, og du har triumfert! +Men ... hvor er du? Du klatrer ti + kanten av månen og ser ned for +å se den forferdelige sannheten. + +Deimos svever over selve helvete! +Du har aldri hørt om noen som +har rømt fra helvete, men du skal +få de jævlene til å angre på at de +noen gang har hørt om deg! Fort, +rappeller ned til helvetes overflate. + +Nå er det tid for siste kapittel i +DOOM! -- Inferno.","Udało się! Zabiłeś paskudnego cyberdemona, który rządził opuszczoną bazą na -Deimosie został zabity i zwyciężyłeś! +Deimosie! Ale... gdzie jesteś? Wspinasz się na -krawędź księżyca i patrzysz w dół -aby ujrzeć straszną prawdę. +krawędź księżyca i patrzysz w dół, +by ujrzeć straszliwą prawdę. Deimos unosi się nad samym Piekłem! Jeszcze nigdy nie słyszałeś o kimś, -kto uciekł z Piekła, ale sprawisz, że -tym sukinsynom będzie przykro, że -kiedykolwiek usłyszeli o tobie! Prędko -schodzisz na powierzchnię Piekła. +kto by uciekł z Piekła. Te sukinsyny zapłacą za to, +że kiedykolwiek usłyszały o tobie! +Prędko schodzisz na powierzchnię Piekła. -Teraz czas na finałowy rozdział -DOOMa! -- Piekło.","Você conseguiu! O hediondo líder +Czas na finałowy rozdział +DOOM-a: ""Inferno""!","Você conseguiu! O hediondo líder ciberdemônio que comandava a base lunar de Deimos foi morto e você triunfou! Mas... onde você está? @@ -803,23 +895,20 @@ auzit de nimeni să scape din infern, dar tu o să-i faci pe ticăloși să regrete că te-au cunoscut! Faci rapel până jos pe suprafața iadului. -Urmează ultimul capitol din DOOM! -- „Infernul”.","У Вас получилось! Ужасный Лорд- -Кибердемон, правивший потерянной -деймосовской базой, был повержен -и Вы ликуете! Но... Где Вы? -Подобравшись к краю спутника, Вы -обращаете взор вниз, и видите -ужасную правду. - -Деймос парит над самим Адом! -Вы никогда не слышали, чтобы кто-нибудь -сбегал из Ада, но Вы заставите ублюдков -пожалеть о том, что когда-либо слышали -о Вас! Поспешно обвязавшись верёвкой, Вы -спускаетесь на поверхность Ада. - -Теперь наступает время последней главы -— «Инферно».","Успели сте! Грозни сајбер-демонски +Urmează ultimul capitol din DOOM! -- „Infernul”.","Получилось! Ужасающий владыка-кибердемон, +повелевавший потерянной базой на Деймосе, +пал от вашей руки с триумфом! Но... где вы? +Подобравшись к краю луны вы смотрите вниз, +только чтобы узреть страшную правду. + +Деймос парит над самим Адом! Вы не слыхали +о том, чтобы кто-то сбегал из пекла, но +эти сволочи ещё пожалеют, что связались +с вами! Недолго думая, вы спускаетесь +по верёвке к поверхности преисподней. + +Настало время заключительной главы +DOOM — «Инферно».","Успели сте! Грозни сајбер-демонски владар који је владао изгубљеном базом Деимосовог месеца је убијен и ви сте победили! Али ... где сте? @@ -835,7 +924,39 @@ Urmează ultimul capitol din DOOM! -- „Infernul”.","У Вас получил пакла. Сада, остатак је на последњем поглављу -DOOM! -- Инферно." +DOOM! -- Инферно.","Du har gjort det! Den avskyvärda +cyberdemonherren som styrde den +förlorade Deimos månbasen har +dödats och du är triumferande! Men ... +var är du? Du klättrar till månens +kant och tittar ner för att se de + hemska sanningen. + +Deimos svävar över själva helvetet! +Du har aldrig hört talas om någon +som har lyckats fly från helvetet, men +du kommer att få de jävlarna att ångra +att de någonsin hört talas om dig! +Snabbt stiger du ner till helvetets yta. + +Nu är det dags för det sista +kapitlet i DOOM! -- Inferno.","Başardınız! İğrenç siber Kayıp +Deimos'u yöneten iblis lordu ay +üssü öldürüldü ve sen muzafferdir! +Ama ... nerede Sen mi? Kenarına +tırmanıyorsun Ay'a ve aşağıya +bakıp korkunç Gerçek. + +Deimos cehennemin üzerinde +yüzüyor! +Cehennemden kaçan birini hiç +duymadın mı? Cehennemden, +ama piçleri yapacaksın Seni +duydukları için üzgünler! Çabuk +ol, yüzeye iniyorsun Cehennem. + +Şimdi, DOOM'un son bölümüne +geçiyoruz! -- İnferno." "The loathsome spiderdemon that masterminded the invasion of the moon bases and caused so much death has had @@ -854,7 +975,7 @@ unleashed. It's good that no Hell- spawn could have come through that door with you ...",E3TEXT,Doom Ep.3,,,"Odporný pavoučí démon, který vedl invazi na měsíční základny a způsobil tolik -utrpení, dostal navěky za vyučenou. +utrpení, dostal navěky na prdel. Otevřely se skryté dveře a ty vejdeš. Dokázal@[ao_cs] jsi, že i na peklo jsi příliš @@ -866,7 +987,24 @@ Zajímalo by tě, co se mezitím na Zemi dělo, když jsi bojoval@[ao_cs] s rozběsněným zlem. Je dobře, že žádný splozenec pekelný nemohl s tebou těmi dveřmi projít... -","Der widerwärtige Spinnendämon, der die +","Den modbydelige edderkoppedæmon, +der stod bag invasionen af månebaserne +og forårsagede så mange dødsfald, +har fået tæsk for evigt. + +En skjult dør åbner sig, og du træder ind. +Du har vist dig at være for hårdfør til, +at Helvede kunne holde dig inde, +og nu spiller Helvede endelig fair - +for du kommer ud af døren og ser +Jordens grønne marker! +Endelig er du hjemme. + +Du undrer dig over, hvad der er sket +på Jorden, mens du kæmpede mod den +uhæmmede ondskab. Det er godt, at +ingen Hellspawn kunne være kommet +gennem den dør med dig ...","Der widerwärtige Spinnendämon, der die Invasion der Mondbasen erdacht und so viel Tod verursacht hat, hat für alle Zeiten einen Tritt in den Arsch erhalten. @@ -884,35 +1022,51 @@ während du gegen das Böse gekämpft hast. Wie gut, dass keine Höllenkreatur mit dir durch das Tor gekommen ist... ",,"La abomena aranedemono, kiu kondukis -la invadon de la lunbazoj kaj igis tiom -da morto, estas tuttempe pugbatita. - -Kaŝpordo malfermiĝas kaj vi eniras. -Vi demonstris, ke vi estas tro fortika -por Infero deteni vin, kaj nun Infero -fine justludas, ĉar vi eliras la pordon -kaj vidas la verdajn kampojn de la Tero! -Ĉe hejm' fine. - -Vi pensas pri tio, kio okazis sur la Tero -dum vi batalis malicon deĉenigan. -Bonas, ke neniu inferido eblis veni -tra la pordo kun vi...","El abominable demonio arácnido que orquestó -la invasión de las bases lunares y causó +la invadon de la lunbazoj kaj kaŭzis tiom +da morto, havis ĝian pugon piedbatita +por ĉiam. + +Kaŝita pordo malfermiĝas kaj vi eniras. +Vi pruvis, ke vi estas tro forta por +Infero deteni vin, kaj nun Infero fine +ludas honeste -- ĉar vi eliras el la pordo +por vidi la verdajn kampojn de la Tero! +Hejme fine. + +Vi scivolas, kio okazis sur la Tero dum vi +bataladis malbonon deĉenigitan. Bonas, +ke neniu Inferido povintus veni tra la +pordo kun vi...","El abominable demonio arácnido que orquestó +la invasión a las bases lunares y causó innumerables muertes ha recibido una patada -en el trasero para siempre. +en el culo de una vez por todas. Una puerta oculta se abre y entonces entras. -Has demostrado ser demasiado rud@[ao_esp] para -el infierno para contener, y ahora el -infierno al final juega limpio -- ¡emerges -desde la puerta para ver los campos verdes -de la Tierra! Hogar al fin. +Has demostrado ser lo bastante dur@[ao_esp] como +para que el Infierno te contenga y ahora el +mismo al fin juega limpio. ¡Emerges por +la puerta para ver los campos verdes +de la Tierra! Por fin en casa. Te preguntas qué ha sucedido en la Tierra mientras combatías a la maldad desatada. -Menos mal que ningún ser infernal ha podido -entrar a través de esa puerta contigo...",,"Hirvittävä hämähäkkipaholainen, joka juoni +Menos mal que ningún ser infernal +ha podido pasar contigo por esa puerta...","El abominable demonio arácnido que planeó +la invasión a las bases lunares y causó +incontables muertes recibió una patada +en el culo de una vez por todas. + +Una puerta oculta se abre y entonces entras. +Demostraste ser lo bastante duro como +para que el Infierno te contenga y ahora el +mismo por fin juega limpio. ¡Emerges por +la puerta para ver los campos verdes +de la Tierra! Por fin en casa. + +Te preguntas qué habrá pasado en la Tierra +mientras combatías a la maldad desatada. +Menos mal que ningún ser infernal +ha podido pasar contigo por esa puerta...","Hirvittävä hämähäkkipaholainen, joka juoni kuutukikohtien invaasion ja aiheutti niin paljon kuolemaa, on saanut kaikkien aikojen selkäsaunan. @@ -943,7 +1097,7 @@ Enfin rentré à la maison. Vous vous demandez ce qu'il se passait ici tandis que vous vous battiez contre les forces du mal. C'est bien de savoir -qu'aucun démon ne vous a suivi..","Az undorító pókdémon, aki kitervelte +qu'aucun démon ne vous a suivi..","Az undorító pókvezér, aki kitervelte a holdbázisok elleni inváziót és annyi ember halálát okozta, végre megkapta a magáét. @@ -955,7 +1109,7 @@ lesznek veled. Az átjáróból felbukkanva végre megpillantod a Föld zöld mezőit! Otthon, édes otthon. -Elgondolkodsz azon, vajon mi történhetett +Arra gondolsz, vajon mi történhetett a Földön, amíg a gonosz ellen küzdöttél. Még jó, hogy egyetlen pokoli lény sem jött át veled együtt azon az átjárón...","Il terribile demone-ragno che aveva @@ -995,39 +1149,57 @@ con te...","火星基地の侵略を企て多くの死をもたらした 당신은 지옥과 싸울 동안 지구에서 무슨 일이 있었을지 궁금할 것이다. 그리고 당신과 함께 지옥의 무리가 그 문으로 들어가지 않길 -진심으로 바랄 뿐이다...","De afschuwelijke spindemon die de invasie +진심으로 바랄 뿐이다...","Het afschuwelijke spindemoon, die de invasie van de maanbases heeft geleid en zoveel doden heeft veroorzaakt, is voor altijd in de kont geschopt. Een verborgen doorgang gaat open en je komt binnen. Je hebt bewezen dat je te -moeilijk bent om de hel te bevatten, -en nu speelt de hel eindelijk eerlijk - +taai bent voor de hel om te beteugelen, +en nu speelt de hel eindelijk eerlijk spel - want je komt uit de deur om de groene velden van de aarde te zien! Eindelijk thuis. -Je vraagt je af wat er op aarde gebeurt -terwijl je tegen het kwaad vecht. Het is -goed dat er geen Hellbrood met jou door -die deur kon zijn gekomen ... - -","Odrażający pajęczy demon, który był -mózgiem tej inwazji, i który spowodował -tyle śmierci, ma raz na zawsze skopane dupsko. - -Ukryte drzwi się otwierają, wchodzisz. -Udowodniłeś, że jesteś za twardy aby -Piekło mogło cię powstrzymać, a Piekło -w końcu gra fair -- wyłaniasz się z drzwi, -by ujrzeć zielone ziemskie pola! -W końcu dom. - -Zastanawiasz się co się działo na Ziemi, -kiedy ty walczyłeś z szerzącym się złem. -To dobrze, że żadne diabelstwo nie -mogło przejść przez te drzwi za tobą...","A detestável aranha demoníaca que +Je vraagt je af wat er op aarde is gebeurd +terwijl je het ontketende kwaad bevocht. +Het is maar goed dat er geen tuig van de hel +met jou mee door die deur kon ... + +","Den avskyelige edderkoppdemonen +som planla invasjonen av måne- +basene og forårsaket så mye død, +har fått juling for all fremtid. + +En skjult dør åpner seg, og du går +inn. Du har vist deg å være for +tøff for helvete å holde på, og nå +spiller helvete endelig rettferdig - +for du kommer ut av døren og ser +de grønne jordene på jorden! +Endelig hjemme. + +Du lurer på hva som har skjedd på +Jorden mens du kjempet mot +ondskapen sluppet løs. Det er bra +at ingen helvetesyngel kunne ha +kommet gjennom den døren +sammen med deg ...","Odrażający pajęczy demon, mózg +inwazji, odebrał życie wielu śmiałkom, +ale w końcu skopałeś mu dupsko. + +Twym oczom ukazuje się sekretne przejście. +Udowodniłeś, że jesteś za silny, by +demony mogły cię powstrzymać. Piekło +poddało się. Przechodzisz przez portal +i widzisz piękne ziemskie łąki! +Nareszcie w domu. + +Zastanawiasz się co cię ominęło na Ziemi, +kiedy walczyłeś z szerzącym się złem. +Całe szczęście, że żadne diabelstwo nie +poszło twoim tropem...","A detestável aranha demoníaca que esquematizou a invasão das bases lunares e causou tanta morte foi detonada para sempre. @@ -1071,23 +1243,21 @@ Acasă, în sfârșit. Te întrebi ce s-a întâmplat pe Pământ în timp ce tu erai ocupat cu oprirea răului dezlănțuit. E bine că nici o creatură infernală nu a putut să te însoțească -odată ce ai trecut prin acea ușă ...","Омерзительный паукодемон, -руководивший вторжением на лунные -базы и принёсший столь много -смертей, получил окончательный пинок под зад. - -Открывается потайная дверь и Вы -входите в неё. Вы доказали, что -слишком круты для ада, и поэтому -Ад, наконец, поступает справедливо — -Вы выходите из двери прямо на -зелёные поля Земли. Наконец-то дом. - -Вы спрашиваете себя: что случилось -на Земле, пока Вы сражались с -высвободившимся злом? Хорошо, что ни -одно порождение Ада не смогло пройти -через эту дверь вместе с Вами...","Гадни спајдердемон, који је +odată ce ai trecut prin acea ușă ...","Омерзительной демонической паучихе, +стоявшей за вторжением на базы и повинной +в стольких смертях надрали задницу раз +и навсегда. + +Открывается тайный проход и вы заходите +внутрь. Аду вы оказались не по зубам +и он в кои-то веки сыграл по-честному — +ибо на выходе вы видите зелёные поля +Земли! Наконец-то, вы дома. + +Вы гадаете, а что же происходило на Земле, +пока вы сражались с необузданным злом. +Какое же счастье, что ни одно исчадие ада +не могло последовать за вами...","Гадни спајдердемон, који је управљао инвазијом на месечевим базама и изазвао толико смрти, добио је по дупету једном за свагда. @@ -1103,7 +1273,29 @@ odată ce ai trecut prin acea ușă ...","Омерзительный пауко док сте се борили против зла. Добро је што ниједно створење пакла не може проћи кроз та врата -с вама..." +с вама...","Den avskyvärda spindeldemon som +ledde invasionen av månbaserna och +orsakade så mycket död har fått +stryk för all framtid. + +En dold dörr öppnas och du går in. +Du har visat dig vara för tuff för att +helvetet skulle kunna hålla dig kvar, +och nu spelar helvetet äntligen rättvist - +för du kommer ut genom dörren och +ser jordens gröna fält! Äntligen hemma. + +Du undrar vad som har hänt på jorden +medan du har kämpat mot ondskan +som släppts lös. Det är bra att inga +demoner kunde ha kommit in genom +dörren med dig ...","Ay üslerinin istilasını planlayan ve bu kadar çok ölüme neden olan iğrenç örümcek iblisin kıçı tüm zamanlar için tekmelendi. + +Gizli bir kapı açılıyor ve içeri giriyorsunuz. +Cehennem'in zapt edemeyeceği kadar güçlü olduğunu kanıtladın ve şimdi Cehennem nihayet adil davranıyor - çünkü kapıdan çıktığında Dünya'nın yeşil tarlalarını görüyorsun! +Sonunda evdesin. + +Siz serbest bırakılan kötülükle savaşırken Dünya'da neler olduğunu merak ediyorsunuz. İyi ki Cehennem yok spawn o yoldan gelebilirdi kapı seninle ..." "The spider mastermind must have sent forth its legions of hellspawn before your final confrontation with that terrible @@ -1135,7 +1327,22 @@ krvedrásajícího utrpení, dívaj@[tgs_pr1_cs] se na hemžící se národ démonů, v amoku pobíhající našimi městy. -Další zastávka, Peklo na Zemi!","Der Spinnenmeister muss seine Legionen +Další zastávka, Peklo na Zemi!","Edderkoppens hjerne må have sendt sine +legioner af helvedesyngel ud før din +endelige konfrontation med det frygtelige +bæst fra helvede, men du trådte frem og +bragte evig fordømmelse og lidelse over +horden, som en sand helt ville gøre +det over for noget så ondt. + +Desuden var der nogen, der skulle betale +for det, der skete med Daisy, din kanin. + +Men nu ser du, at der er mere potentiel +smerte og fortvivlelse foran dig, når +en nation af dæmoner går amok i vores byer. + +Næste stop: Helvede på Jorden!","Der Spinnenmeister muss seine Legionen der Höllenbrut vor deiner Konfrontation mit ihm ausgesandt haben. Aber du hast ja ewige Verdammnis und Leiden @@ -1150,20 +1357,20 @@ Aber jetzt siehst du noch mehr Schmerz und Blutvergießen vor dir, da die Dämonen in unseren Städten Amok laufen. -Nächster Halt, Hölle auf Erden!",,"La Elektronaraneo-mastro verŝajne sendis +Nächster Halt, Hölle auf Erden!",,"La elektraraneo-mastro verŝajne sendis siajn legiojn de inferidoj antaŭ via fina -konflikto kun tio malbonega aĉbesto kun -Infero, sed vi marŝis antaŭen kaj venigis -ĉiaman damnon kaj suferadon al la hordo, -kiel vera heroo farus, kiam frontanta ion -tiel peka. +konflikto kun tiu terura bestaĉo el +Infero. Sed vi paŝis antaŭen kaj venigis +eternan damnon kaj suferadon sur la +hordon, kiel vera heroo farus, kiam fronte +al io tiel malbona. -Cetere, iu pagos pro kio okazis je Daisy — -via doma kuniklo +Cetere, iu devis pagi pro tio, kio okazis al +Daisy, via dombesta kuniklo. -Sed nun, vi vidas, disvastigan antaŭ vi, pli -eblajn doloron kaj buĉadon, dum popolo -de demonoj amoke kuras en nia urboj. +Sed nun, vi vidas, sternite antaŭ vi, pli +eblan doloron kaj buĉadon, dum popolo +de demonoj kuras amoke en niaj urboj. Sekva haltejo: Infero Sur La Tero!","La mente-maestra arácnida debió haber enviado sus legiones de seres infernales @@ -1182,7 +1389,7 @@ el dolor potencial y la carnicería exacerbada al ver como una nación de demonios corre sin control sobre nuestras ciudades. -Próxima parada, ¡infierno en la tierra!",,"Ovelan hämähäkkimestarin oli varmaankin +Próxima parada, ¡Infierno en la Tierra!",,"Ovelan hämähäkkimestarin oli varmaankin täytynyt lähettää pirulaislegioonansa ennen lopullista kohtaamistasi tuon kamalan hornanpedon kanssa. Mutta sinä @@ -1216,7 +1423,7 @@ devant vous encore plus de douleur et de massacre potentiels: une nation de démons se déversent dans nos cités! -Prochain arrèt: L'enfer sur terre!","Biztosan a Pók Agytröszt küldte eléd démoni +Prochain arrèt: L'enfer sur terre!","Biztosan a pókdémon küldte eléd démoni hadseregét, mielőtt utoljára szembeszálltál ezzel a borzalmas pokolbéli szörnyeteggel. De te egy lépéssel előttük jártál, és örök @@ -1224,12 +1431,12 @@ kárhozatot és szenvedést küldtél a hordára, ahogy ezt egy hős teszi a gonosszal szemben állva. -Amúgy meg valakinek meg kellett fizetnie +Amúgy is, valakinek meg kellett fizetnie azért, ami a nyuladdal, Daisyvel történt. Most azonban szenvedést és vérontást látsz magad előtt, miközben városainkat -ámokfutó démonok népessége lepi el. +ámokfutó démonok hadseregként rohanják le. Következő megálló: Pokol a Földön!","Il demone ragno doveva aver mandato avanti le sue legioni infernali prima @@ -1286,23 +1493,40 @@ op hol slaan. Volgende halte, de hel op aarde! -","Pajęczy Mistrz musiał wysłać swe -diabelskie legiony tuż przed twoim -finałowym starciem z bestią z Piekła. -Ale wykroczyłeś naprzód i przyniosłeś -wieczne potępienie i ból całej tej hordzie, -tak jakby zrobił to prawdziwy bohater -w obliczu czegoś tak złego. - -Oprócz tego, ktoś musi zapłacić za to -co się stało z Daisy - twoim króliczkiem. - -Ale teraz, widzisz rozprzestrzeniający się -przed tobą ból i rozlew krwi podczas gdy -nacja demonów szaleńczo biega pośród -naszych miast. - -Następny przystanek, Piekło na Ziemi!","A aranha-mestra deve ter enviado +","Edderkopphjernen må ha sendt +ut sine legioner av helvetesyngel +før din endelige konfrontasjon +med det forferdelige beistet +fra helvete. men du gikk frem +og brakte evig fordømmelse +og lidelse over horden som en +sann helt ville gjort i møte med +noe så ondt. + +Dessuten skulle noen betale for +det som skjedde med Daisy, +kaninen din. + +Men nå ser du mer potensiell +smerte og lidelse spre seg +foran deg når en nasjon av +demoner går amok i byene våre. + +Neste stopp, helvete på jorden!","Pajęczy Mistrz wysłał swe +diabelskie legiony tuż przed twym +ostatecznym starciem z piekielną bestią. +Jednak nie poddałeś się i przyniosłeś +wieczne potępienie hordzie demonów, +niczym prawdziwy bohater. + +Ktoś musiał też pomścić +śmierć Daisy - twojego króliczka. + +Teraz rozumiesz ile bólu i zniszczenia +mogą wyrządzić demony hulające +po ulicach naszych miast. + +Następny przystanek: Piekło na Ziemi!","A aranha-mestra deve ter enviado suas legiões de demônios antes do seu confronto final com aquela terrível besta do inferno. Mas você @@ -1351,23 +1575,22 @@ Dar acum, observi un potențial și mai mare pentru durere si măcel întrucât o nație întreagă de demoni fuge prin orașele noastre. -Următoarea oprire, Iadul pe Pământ!","Паук-предводитель, должно быть, послал -свои легионы порождений Ада -перед вашим последним сражением с этим -ужасным отродьем. Но Вы дошли до конца -и принесли вечное проклятье и страдание -этой орде, как настоящий -герой перед лицом смертельной опасности. +Următoarea oprire, Iadul pe Pământ!","Скорее всего паучиха-владычица выслала +легионы адских отродий ещё до ваше противостояния с этим ужасающим порождением +Преисподней. Но вы выступили вперёд и +подвергли адские полчища незабвенному +проклятию и вечным мучениям, как и подобает +истинному герою пред ликом такого зла. -Кроме того, кто-то ведь должен был заплатить -за то, что случилось с Дэйзи, вашей -домашней крольчихой. +К тому же, нельзя было оставлять +безнаказанными тех, кто сотворил такое с +Дейзи, вашей домашней крольчихой. -Теперь Вы видите, сколь много боли и -крови Вам пророчат полчища демонов, -неистовствующих в наших городах. +Но теперь вам предстоит ещё больше резни и +мясища, ведь бесовское племя бесчинствует +в наших городах. -Следующая остановка — Ад на земле!","Паук-руководилац је вероватно послао своје +Следующая остановка — Ад на Земле!","Паук-руководилац је вероватно послао своје легије из пакла пред ваш последњи сукоб са том страшном звери из пакла. Али ви сте кренули напред и довели вечно @@ -1383,7 +1606,29 @@ Următoarea oprire, Iadul pe Pământ!","Паук-предводитель, до док се хорда демона креће међу нашим градовима. -Следећа станица: пакао на земљи!" +Следећа станица: пакао на земљи!","""Spindelhjärnan måste ha skickat ut +sina legioner av helvetesgudar före din +slutliga konfrontation med det +fruktansvärda odjuret från helvetet, men +du klev fram och förde fram evig +fördömelse och lidande över horden, +som en sann hjälte skulle göra inför +något så ondskefullt. + +Dessutom skulle någon få betala för vad +som hände Daisy, din husdjurskanin. + +Men nu ser du framför dig mer potentiell +smärta och död när en nation av demoner +löper amok bland våra städer. + +Nästa stopp: Helvetet på jorden!","Örümcek beyni, siz cehennemden gelen o korkunç canavarla yüzleşmeden önce cehennem lejyonlarını göndermiş olmalı. Ama sen öne çıktın. ve ebedi laneti getirdi ve gerçek bir kahraman gibi sürünün üzerine bu kadar şeytani bir şeyle yüzleşmek. + +Ayrıca, birileri bunun bedelini ödeyecekti. evcil tavşanınız Daisy'nin başına geldi. + +Ama şimdi, önünüze daha fazla yayıldığını görüyorsunuz. ulus olarak potansi̇yel aci ve sikinti iblisler şehirlerimizde cirit atıyor. + +Bir sonraki durak, Yeryüzündeki Cehennem!" "You have entered deeply into the infested starport. But something is wrong. The monsters have brought their own reality @@ -1404,7 +1649,19 @@ V dáli vidíš opevněné stanoviště pekla. Jestli se ti podaří dostat se skrz, mohl@[ao_cs] bys proniknout do hrůzného srdce základny a najít ono tlačítko, které -drží populaci Země jako rukojmí.","Du bist tief in den verseuchten Sternenhafen +drží populaci Země jako rukojmí.","Du er kommet dybt ind i den inficerede +stjernehavn. Men der er noget galt. +Monstrene har bragt deres egen virkelighed +med sig, og stjernehavnens teknologi er +ved at blive undergravet af deres +tilstedeværelse. + +Foran dig ser du en forpost af helvede, +en befæstet zone. Hvis du kan komme forbi +den, kan du trænge ind i det hjemsøgte +hjerte af stjernebasen og finde den +kontrollerende kontakt, der holder +Jordens befolkning som gidsel.","Du bist tief in den verseuchten Sternenhafen eingedrungen. Aber etwas stimmt nicht. Die Monster haben ihre eigene Realität mitgebracht und die Technologie wird @@ -1414,17 +1671,17 @@ Voraus siehst du einen Vorposten der Hölle, eine befestigte Zone. Wenn du daran vorbei kommst, kannst du in das Herz der Basis eindringen und den Schalter finden, -der die Menschheit als Geiseln hält.",,"Vi eniris profunden en la infestitan kosmo- -havenon, sed io estas misa. La monstroj +der die Menschheit als Geiseln hält.",,"Vi eniris profunde en la infestitan kosmo- +havenon. Sed io estas misa. La monstroj alportis sian propran realon kun ili, kaj la teknologio de la kosmo-haveno estas -kontraŭata de ilia ĉeesto. +subfosata de ilia ĉeesto. -Antaŭe, vi vidas postenon de infero — -fortika regiono. Se vi eblos iri preter ĝi, -vi eblus penetri en la hantatan koron de +Antaŭe, vi vidas antaŭpostenon de infero, +fortika regiono. Se vi povus iri preter ĝi, +vi povus penetri en la hantitan koron de la kosmo-bazo kaj trovi la kontrolŝaltilon, -kiu kaptas la popolon de la Tero.","Te has introducido profundamente en el +kiu ostaĝigas la loĝantaron de la Tero.","Te has introducido profundamente en el infestado puerto espacial. Pero algo está mal. Los monstruos han traído su propia realidad con ellos, y la tecnología del @@ -1458,17 +1715,15 @@ une zone fortifiée. Si vous pouvez la traverser, vous pénétrerez dans le cœur hanté de la base spatiale et trouverez la commande qui garde les terriens en -otage.","Beléptél jó mélyen a fertőzött csillagkikötőbe. -De valami nem stimmel. A szörnyek elhozták -a saját valóságukat magukkal, és a csillagkikötő -technológiái fel lettek forgatva ezáltal a -jelenlétük miatt. - -Elől, a pokol egy előőrse csillan meg, egy megerősített -zónát. Ha túl tudsz menni rajta, akkor -be tudsz hatolni a csillagkikötő kísérteties szívébe -és meg tudod keresni az irányító kapcsolót mely fogságban -tartja a föld populációját.","Sei entrato profondamente nel spazioporto +otage.","Behatoltál a démonoktól hemzsegő csillagkikötő mélyére. +De valami nem stimmel. A szörnyek magukkal hozták a saját valóságukat, +és csupán a jelenlétükkel megbolygatják a kikötő technológiáját. + +Előtted a pokol egy előőrse csillan meg, egy erődített +zóna. Ha túljutsz rajta, akkor +be tudsz hatolni a csillagkikötő elátkozott szívébe +és meg tudod keresni az irányító kapcsolót, mely fogságban +tartja a Föld teljes lakosságát.","Sei entrato profondamente nel spazioporto infestato. Ma qualcosa non va. I mostri hanno portato la loro realtà con sè e la tecnologia dello spazioporto @@ -1505,19 +1760,32 @@ komen, kun je doordringen in het besmette centrum van de sterhaven en de controle- schakelaar vinden die de bevolking van de aarde gegijzeld houdt. -","Wszedłeś w głąb zaatakowanego portu -gwiezdnego. Ale coś jest nie tak. Potwory -sprowadziły ze sobą swoją własną -rzeczywistość i technologia portu jest -zdominowana przez ich obecność. - -Przed sobą widzisz posterunek piekła, -ufortyfikowaną strefę. Jeśli możesz przez -nią przejść, będziesz mógł spenetrować -nawiedzone serce bazy i znaleźć przycisk -kontrolny, przez który cała populacja -Ziemi jest trzymana w niewoli. -","Você entrou profundamente no +","Du har kommet dypt inn i den +infiserte stjernehavnen. Men +noe er galt. Monstrene har +brakt med seg sin egen +virkelighet, og stjernehavnens +teknologi undergraves av deres +tilstedeværelse. + +Foran deg ser du en utpost av +helvete, en befestet sone. Hvis +du kan komme forbi den, kan +du trenge inn i stjernebasens +hjemsøkte hjerte og finne +kontrollbryteren som holder +jordens befolkning som gisler.","Wszedłeś w głąb zaatakowanego gwiezdnego +portu. Ale coś jest nie tak. Potwory +sprowadziły ze sobą własną +rzeczywistość i technologia portu +została przez nie opętana. + +Widzisz przed sobą piekielny posterunek, +strzeżony niczym twierdza. Jeśli uda ci się +przejść, będziesz mógł dostać się do +nawiedzonego serca bazy i znaleźć panel +kontrolny, który wyzwoli populację +Ziemi.","Você entrou profundamente no espaçoporto infestado. Mas há algo errado. Os monstros trouxeram consigo a sua própria realidade, e a tecnologia @@ -1549,18 +1817,17 @@ datorită prezenței lor. În fața ta, vezi un avanpost al infernului, o zonă fortificată. Dacă poți trece de ea, poți străpunge inima bazei stelare bântuite si să găsești panoul -de control care ține captivă populația Pământului.","Вы прошли вглубь заражённого космопорта, -но что-то здесь не так. Монстры принесли -с собой свою собственную реальность, -и техника космопорта -трансформируется от их присутствия. - -Впереди вы видите аванпост Ада. -Если вам удастся пробраться через него, -Вы сможете проникнуть в населённый -демонами центр базы и найти пульт -управления, держащий население земли -в заложниках.","Дубоко сте зашли у опустошен старпорт. +de control care ține captivă populația Pământului.","Вы проникли в самую глубь кишащего +демонами космопорта. Но что-то здесь не +так. Монстры принесли с собой и свою +реальность, и их аура искажает технологии +космодрома. + +Впереди вы видите укреплённую зону, +заставу войск преисподней. Пройдя сквозь +неё, вы сможете прорваться в самое сердце +космобазы и отыскать пульт управления, +удерживающий в неволе население Земли.","Дубоко сте зашли у опустошен старпорт. Нешто није било у реду, додуше. Чудовишта су донелу своју сопствену реалност са собом, а старпортова технологија @@ -1571,10 +1838,35 @@ de control care ține captivă populația Pământului.","Вы прошли вг кроз њега, моћи ћете да се пробијете до самог уклетог срца старбазе и да нађете контролишyће дугме које држи све -становништво земље таоце." +становништво земље таоце.","""Du har gått djupt in i den infekterade +stjärnhamnen. Men något är fel. +Monstren har fört med sig sin egen +verklighet, och stjärnhamnens teknik +undergrävs av deras närvaro. + +Framför dig ser du en utpost av helvetet, +en befäst zon. Om du kan ta dig förbi +den kan du tränga in i stjärnbasens +hemsökta hjärta och hitta den +kontrollbrytare som håller jordens +befolkning som gisslan.","İstila edilmiş yıldız üssünün +derinliklerine girdiniz. Ama yanlış +giden bir şeyler var. Canavarlar +kendi gerçekliklerini de +beraberlerinde getirdiler ve yıldız +limanının teknolojisi onların +varlığıyla altüst oluyor. + +İleride, cehennemin bir ileri +karakolunu, müstahkem bir +bölgeyi görüyorsunuz. Eğer onu +geçebilirsen, yıldız üssünün +lanetli kalbine girebilir ve dünya +nüfusunu rehin tutan kontrol +düğmesini bulabilirsin." "You have won! Your victory has enabled Humankind to evacuate earth and escape -the nightmare. Now you are the only +the nightmare. Now you are the only Human left on the face of the planet. Cannibal mutations, carnivorous aliens, and evil spirits are your only neighbors. @@ -1585,7 +1877,7 @@ But then, Earth Control beams down a message from space: ""Sensors have located the source of the alien invasion. If you go there, you may be able to block their -entry. The alien base is in the heart of +entry. The alien base is in the heart of your own home city, not far from the starport."" Slowly and painfully you get up and return to the fray.",C2TEXT,Doom2 after MAP11,,"You have won! Your victory has enabled @@ -1620,7 +1912,25 @@ mohl@[ao_cs] byste jim zamezit ve vstupu. Vetřelecká základna leží v centru Vašeho rodného města, nedaleko hvězdné základny.“ Pomalu a bolestivě se zvedneš a vracíš se -zpět do boje.","Du hast gewonnen! Dein Sieg hat der +zpět do boje.","Du har vundet! Jeres sejr har gjort det +muligt for menneskeheden at evakuere +jorden og undslippe mareridtet. Nu er +du det eneste menneske, der er tilbage +på planeten. Kannibale mutationer, +kødædende rumvæsener og onde ånder er +dine eneste naboer. Du læner dig tilbage +og venter på døden, tilfreds med, +at du har reddet din art. + +Men så stråler Earth Control en besked +ned fra rummet: ""Sensorerne har lokaliseret +kilden til den fremmede invasion. Hvis du +tager derhen, kan du måske blokere deres +indtrængen. Den fremmede base er i hjertet +af din egen hjemby, ikke langt fra +stjernehavnen."" +Langsomt og smertefuldt rejser du dig +op og vender tilbage til kampen.","Du hast gewonnen! Dein Sieg hat der Menschheit die Evakuation der Erde ermöglicht. Jetzt bist du der einzige Mensch auf der Planetenoberfläche. @@ -1638,29 +1948,29 @@ weiteres Eindringen blockieren. Die Basis liegt im Herzen von deiner Heimatstadt, nicht weit vom Hafen.“ Langsam und schmerzerfüllt kommst -du hoch und gehst zurück in den Kampf.",,"Vi gajnis! Via venko ebligis homaron -evakui La Teron kaj eskapi la teruron. +du hoch und gehst zurück in den Kampf.",,"Vi gajnis! Via venko ebligis al la homaro +evakui la Teron kaj eskapi el la teruraĵo. Nun vi estas la sola homo sur la supraĵo -de la Tero. Kanibalaj mutaciuloj, karno- -manĝaj eksterteranoj, kaj malvirtaj -fantomoj estas viaj nur najboroj. Vi -sidas kaj atendas morton, kontenta ĉar -vi savis vian specion. - -Tamen poste, la kontrolcentro transigas -mesaĝon el kosmo: ""Sensiloj trovis la -fonton de la eksterteran invadon. +de la Tero. Kanibalaj mutaciuloj, +karnovoraj eksterteranoj, kaj malbonaj +fantomoj estas viaj nur najbaroj. +Vi sidas kaj atendas morton, kontenta, +ke vi savis vian specion. + +Sed tiam, la Tero-Kontrolcentro +transsendas mesaĝon el kosmo: ""Sensiloj +trovis la fonton de la ekstertera invado. Se vi irus tien, vi eble povas bari ilian eniron. La ekstertera bazo estas en la -koro de via propra hejm-urbo, ne fora -de la kosmo-haveno."" malrapide kaj -dolore, vi leviĝas kaj revenas al la -batalo.","¡Has ganado! Tu victoria ha permitido a la +koro de via propra hejmurbo, ne fora +de la kosmo-haveno."" +Malrapide kaj dolore, vi leviĝas kaj +revenas al la batalo.","¡Has ganado! Tu victoria ha permitido a la humanidad evacuar la Tierra y escapar de la pesadilla. Ahora tú eres el único ser humano que queda sobre la faz del planeta. Mutaciones caníbales, alienígenas -carnívoros, y espíritus malvados son tus +carnívoros, y espíritus malignos son tus únicos vecinos. Te sientas y esperas la muerte, content@[ao_esp] de haber salvado a tu especie. @@ -1726,39 +2036,38 @@ se trouve au cœur de votre ville natale, non loin de l'astroport. » Lentement et douloureusement, vous vous levez et retournez au combat.","Nyertél! A győzelmed utat nyitott -emberiségnek, hogy kiüríthessék a Földet, és -megmeneküljenek a rémálomtól. Most te vagy -az egyetlen ember a föld felszínén. -Kannibál mutációk, húsevő űrlények, és a -gonosz lelkek az egyetlen szomszédjaid. -Hátra dőlsz, és vársz a halálra, büszkén amiért -megmentetted fajodat. - -De aztán, a Föld Vezérlő lesugároz egy üzenetet +az emberiségnek, hogy kiüríthessék a Földet, és +megmeneküljenek a rémálomtól. Te maradtál +az egyetlen ember a Föld felszínén. +Szomszédaid csupán mutáns kannibálok, húsevő űrlények, és +gonosz lelkek. +Elégedetten hátradőlsz, és a halálodat várod, miután megmentetted a fajodat. + +De aztán a földi vezérlő lesugároz egy üzenetet az űrből: ""Szenzoraink megtalálták az űrlény invázió forrását. Ha odamész, talán te képes leszel -elhárítani özönlésüket. Az űrlény bázis pontosan +elhárítani az áradatot. Az űrlény bázis pontosan a te városodban van, nem messze a -csillagkikötőtől."" lassan, és fájdalmasan felállsz +csillagkikötőtől."" Lassan és szenvedve felállsz, majd folytatod a küzdelmet.","Hai vinto! La tua vittoria ha permesso al genere umano di evacuare la terra e di fuggire dall'incubo. Ora sei il solo umano rimasto sulla faccia del pianeta. Mutazioni cannibali, alieni carnivori e -spiriti malvagi sono I tuoi soli vicini. +spiriti malvagi sono i tuoi soli vicini. Ti siedi e aspetti la morte, felice di aver salvato la tua specie. Proprio allora, il controllo della terra -rimanda un messaggio dallo spazio: ""I +trasmette un messaggio dallo spazio: ""I sensori hanno localizzato la fonte dell'invasione aliena. Se andrai lì -potrai forse bloccare il loro +forse potrai bloccare il loro ingresso. La base aliena è nel cuore della tua città natale, non lontano dallo spazioporto."" Lentamente e dolorosamente ti alzi -è ritorni alla battaglia.","勝利した! 人類をこの世の地獄から脱出させ絶滅の悪夢から救ったのだ。 +e ritorni alla battaglia.","勝利した!人類をこの世の地獄から脱出させ絶滅の悪夢から救ったのだ。 そして自分が最後の地球人となった。 デーモンもとい人食いエイリアン、共食いミュータント、 くどい怨嗟のゴースト、そして死体だけが隣人だ。 @@ -1798,24 +2107,43 @@ sterhaven."" Langzaam en pijnlijk sta je op en keer je terug naar de strijd. -","Wygrałeś! Twa wygrana umożliwiła -ludzkości ewakuację Ziemi i ucieczkę -z tego koszmaru. Jesteś teraz jedynym -człowiekiem, który został na powierzchni -planety. Ludożercze mutacje, mięsożerni -obcy, złe duchy są twoimi jedynymi +","Du har vunnet! Din seier har gjort +det mulig for menneskeheten å +evakuere jorden og unnslippe +marerittet. Nå er du det eneste +mennesket som er igjen på planeten. Kannibalmutasjoner, kjøttetende +romvesener og onde ånder er +dine eneste naboer. Du lener deg +tilbake og venter på døden, fornøyd +med at du har reddet arten din. + +Men så stråler Jordkontrollen ned +en melding fra verdensrommet: +Sensorer har lokalisert kilden til +den utenomjordiske invasjonen."" +Hvis du drar dit, kan du kanskje +blokkere inngangen deres. Den utenomjordiske basen ligger i +hjertet av din egen hjemby, ikke +langt fra stjernehavnen."""" ""Sakte +og smertefullt reiser du deg og +vender tilbake til kampen.""","Wygrałeś! Dzięki twej brawurze populacja +Ziemi mogła uciec z tego koszmaru. +Jesteś teraz jedynym +człowiekiem na planecie. +Ludożercze mutacje, krwiożerczy +obcy oraz złe duchy są twymi jedynymi sąsiadami. Siadasz i czekasz na śmierć, -zadowolony z tego, że uratowałeś swój +ciesząc się, że uratowałeś swój gatunek. -Nagle, kontrola ziemska wysyła +Nagle... Centrum dowodzenia wysyła wiadomość z kosmosu: ""Sensory -zlokalizowały źródło inwazji obcych. Jeśli -tam pójdziesz, będziesz mógł zablokować -im wejśce. Baza obcych znajduje się +zlokalizowały źródło inwazji obcych. +Pójdź tam, a zdusisz inwazję w zarodku. +Baza obcych znajduje się w centrum twojego rodzinnego miasta, -niedaleko portu kosmicznego."" Powoli -i z bólem wstajesz i wracasz do boju.","Você venceu! Sua vitória permitiu que a +niedaleko portu kosmicznego"". +Wstajesz cały obolały i wracasz do boju.","Você venceu! Sua vitória permitiu que a humanidade evacuasse a Terra e escapasse desse pesadelo. Agora você é @[ao_ptb] únic@[ao_ptb] human@[ao_ptb] que resta na face do planeta. @@ -1864,23 +2192,23 @@ extraterestre. Dacă te duci acolo s-ar putea să poți să le blochezi intrarea. Baza extraterestră este în inima orașului tău natal, nu foarte departe de portul stelar."" Încet și îndurerat, te ridici și te întorci -la luptă.","Вы победили! Ваш успех позволил -человечеству эвакуироваться с земли -и спастись от кошмара. Теперь Вы — -единственный человек, оставшийся на -планете, и людоеды-мутанты, хищные -пришельцы и злые духи — Ваши -единственные соседи. Удовлетворённый -спасением своего вида, Вы спокойно -дожидаетесь неминуемой гибели. - -Но вскоре руководство земли передаёт -сообщение с орбиты: «Сенсоры обнаружили -источник инопланетного вторжения. Ваша -задача — ликвидировать его». Инопланетная -база находится в центре вашего города, -недалеко от космопорта. Медленно и -мучительно Вы возвращаетесь в бой. +la luptă.","Вы победили! Благодаря вашему триумфу, +человечество смогло эвакуироваться с Земли +и сбежать от этого кошмара. Теперь вы — +единственный его представитель, оставшийся +на планете. Мутанты-каннибалы, плотоядные +чужаки и злые духи отныне ваши единственные +соседи. Вы садитесь и ждёте смерти, +довольствуясь тем, что спасли человечество. + +Но внезапно земное командование отправляет +сообщение из космоса: «Сенсоры засекли +источник вторжения. Дойдя до него, ты +можешь найти способ закрыть им проход. +База чужаков находится в центре твоего +родного города, неподалёку от космопорта». +Медленно и превозмогая боль, вы поднимаетесь и вновь +идёте в бой. ","Победили сте! Ваша победа дозволила је човечанству да евакуише земљу и побегне из те ноћне море. Ви сте сад једино људско @@ -1897,7 +2225,43 @@ la luptă.","Вы победили! Ваш успех позволил ванземаљска база се налази у вашем родном граду, недалеко од старпорта.“ Полако и безвољно устајете да би се вратили -у окршај." +у окршај.","Du har vunnit! Er seger har gjort det +möjligt för mänskligheten att eva- +kuera jorden och fly från mardrömmen. +Nu är du den enda människan som +finns kvar på planeten. Kannibalmutationer, +köttätande utomjordingar och onda andar +är dina enda grannar. Du sitter tillbaka och +väntar på döden, nöjd med att du har +räddat din art. + +Men så strålar Earth Control ner ett +meddelande från rymden: ""Sensorerna +har lokaliserat källan till den utomjordiska +invasionen."" Om du går dit kan du kanske +blockera deras inträde. Den utomjordiska +basen ligger i hjärtat av din egen +hemstad, inte långt från stjärnhamnen."" +Långsamt och smärtsamt reser du +dig upp och återvänder till striden.","Siz kazandınız! Zaferiniz sayesinde +İnsanlık dünyayı boşaltıp kaçacak +kabus. Şimdi tek sen varsın +Gezegende insan kalmadı. +Yamyam mutasyonlar, etobur +uzaylılar, ve kötü ruhlar tek +komşunuzdur. Arkanıza yaslanıp +ölümü beklersiniz. Türünüzü +kurtardığınızı. + +Ama sonra, Dünya Kontrol bir ışın +gönderiyor Uzaydan gelen mesaj: +""Algılayıcılar uzaylı istilasının +kaynağını buldu. Oraya giderseniz, +kapılarını kapatabilirsiniz. Uzaylı +üssü kendi şehrinizin kalbinde. +Yıldız üssünden çok uzakta değil."" +Yavaşça ve acı çekerek ve +savaşa geri dönün." "You are at the corrupt heart of the city, surrounded by the corpses of your enemies. You see no way to destroy the creatures' @@ -1914,7 +2278,17 @@ vchod. Zatínaj@[tgs_pr1_cs] zuby procházíš skrz. Na druhé straně musí být nějaký způsob, jak jim zabránit v cestě. Co tě zajímá, že kvůli tomu musíš projít peklem? -","Du bist im korrupten Herzen der Stadt, +","Du befinder dig i byens korrupte hjerte, +omgivet af dine fjenders lig. +Du kan ikke se nogen måde at ødelægge +væsenernes indgang på denne side, så du +bider tænderne sammen og kaster dig +igennem den. + +Der må være en måde at lukke den på den +anden side. Hvad rager det dig, hvis +du skal gå gennem helvede for at nå +frem til den?","Du bist im korrupten Herzen der Stadt, umgeben von den Leichen deiner Feinde. Du siehst keine Möglichkeit, das Tor der Kreaturen von dieser Seite zu zerstören. @@ -1925,13 +2299,13 @@ Es muss einen Weg geben, um es auf der anderen Seite zu schließen. Und wenn du dafür durch die Hölle gehen musst!",,"Vi estas ĉe la malvirta koro de la urbo, ĉirkaŭita de la kadavroj de viaj malamikoj. -Vi vidas neniun manieron por detrui la -enirejon de la estaĵoj ĉe tiu flanko, do vi -grincas viajn dentojn kaj plonĝas tra ĝin. +Vi vidas nenian manieron por detrui la +enirejon de la estaĵoj ĉe tiu ĉi flanko, do vi +kunpremas la dentojn kaj plonĝas tra ĝi. -Verŝajne estas maniero por fermi ĝin +Devas esti maniero por fermi ĝin ĉe la alia flanko. Kial vi zorgu, ĉu vi -bezonas iri tra Infero por trovi ĝin?","Estas en el corazón corrompido de la +bezonas iri tra Infero por atingi ĝin?","Estas en el corazón corrompido de la ciudad, rodead@[ao_esp] por los cadáveres de tus enemigos. No ves otra manera de destruir la entrada de las criaturas @@ -1958,15 +2332,14 @@ travers. Il doit y avoir un moyen de l'autre côté. En quoi ça importe d'avoir à traverser -les enfers pour y arriver?","A városnak a korrupt szívén tartózkodsz, -beborítva az ellenségeid hulláival. Nem találsz +les enfers pour y arriver?","A város elátkozott szívéhez értél, +körülvéve az ellenségeid hulláival. Nem találsz módot arra, hogy megsemmisítsd a lények átjáróját -ezen az oldalon, szóval összeszorítod a fogaidat, -és átvergődsz azon. +ezen az oldalon, így összeszorítod a fogaidat, +és fejest ugrasz bele. -Muszáj lennie egy módnak, hogy bezárjad a másik -oldalon is. Miért érdekel ez, ha már a poklon keresztül -mentél, csak hogy eljuss hozzá?","Sei nel cuore infestato della città, +Kell hogy legyen módja, hogy bezárd a másik +oldalon. Mit érdekel téged, hogy a poklon keresztül kell verekedned magad hogy eljuss célodhoz?","Sei nel cuore infestato della città, Circondato dai corpi dei tuoi nemici. Non vedi il modo di distruggere l'ingresso delle creature da questo lato, così @@ -1997,15 +2370,26 @@ Er moet een manier zijn om het aan de andere kant te sluiten. Wat kan het je schelen als je door de hel moet gaan om er bij te komen? -","Jesteś w skażonym sercu miasta, otoczony -przez zwłoki twoich wrogów. Nie widzisz -sposobu aby zniszczyć bramę tych kreatur -z tej strony więc zaciskasz zęby -i wskakujesz przez nią. - -Musi być sposób, aby ją zamknąć z drugiej -strony. Co cię obchodzi, że musisz przejść -przez piekło, aby się do niego dostać?","Você consegue chegar no centro infestado +","Du er i det korrupte hjertet av +byen, omgitt av likene av dine +fiender. Du ser ingen måte å +ødelegge skapningenes inngang +på denne siden, så du biter +tennene sammen og stuper +gjennom den. + +Det må være en måte å lukke +den på den andre siden. Hva +bryr det deg om du må gå +gjennom helvete for å +komme til den?","Jesteś w skażonym sercu miasta, otoczony +przez zwłoki swych wrogów. Nie wiesz +jak zniszczyć bramę więc zaciskasz zęby +i przez nią przechodzisz. + +Musisz jakoś ją zamknąć z drugiej +strony. Czy to takie straszne, +że najpierw musisz przejść przez piekło?","Você consegue chegar no centro infestado da cidade, cercado pelos cadáveres de seus inimigos. Você percebe que não há como destruir a passagem de entrada @@ -2030,16 +2414,15 @@ că strângi din dinți si treci prin portal. Trebuie să existe o cale de a opri invazia pe cealaltă parte. Ce-ți pasă că va trebui să treci prin infern ca -să o descoperi?","Вы находитесь в разлагающемся сердце -города, в окружении трупов своих врагов. -Вы не видите никакого способа уничтожить -портал на этой стороне, и поэтому, стиснув -зубы, проходите сквозь него. - -Должен быть способ закрыть портал -с другой стороны. И какая Вам разница, -что придётся пройти через ад, чтобы -добраться до него?","Налазите се у самом корумпираном срцу +să o descoperi?","Вы стоите в осквернённом сердце города, в +окружении трупов своих врагов. Не найдя как +закрыть тварям проход с этой стороны, вы, +стиснув зубы, бросаетесь в портал. + +Должен же быть способ затворить его +изнутри. И какая разница, что вам придётся +пройти через пекло, чтобы добраться до +него?","Налазите се у самом корумпираном срцу града, окружени лешевима својих непријатеља. @@ -2049,7 +2432,28 @@ să o descoperi?","Вы находитесь в разлагающемся се Мора постојати начин да се пролаз уништи са друге стране. Шта вас брига ако -морате проћи пакао да би сте га нашли?" +морате проћи пакао да би сте га нашли?","""Du befinner dig i stadens korrupta hjärta, +omgiven av dina fienders lik. Du ser inget +sätt att förstöra varelsernas ingång på +den här sidan, så du biter ihop tänderna +och kastar dig igenom den. + +Det måste finnas ett sätt att stänga den +på andra sidan. Vad bryr du dig om du +måste gå igenom helvetet för att +komma dit?","Şehrin yozlaşmış kalbindesiniz, +etrafınız düşmanlarınızın +cesetleriyle çevrili. Bu taraftaki +geçidi yok etmenin bir yolunu +göremiyorsun, bu yüzden +dişlerini sıkıp geçitten +geçiyorsun. + +Diğer tarafta onu kapatmanın +bir yolu olmalı. Ona ulaşmak +için cehennemden geçmen +gerekiyorsa neden +umursuyorsun?" "The horrendous visage of the biggest demon you've ever seen crumbles before you, after you pump your rockets into @@ -2078,8 +2482,23 @@ Země je zachráněna. Z pekla jsou trosky. Napadá tě, kam teď špatní lidé po smrti půjdou. Utíraj@[tgs_pr1_cs] pot z čela se vydáváš na dlouhou cestu zpět domů. -Přetvoření Země by mělo být hezčí, -než ji ničit.","Das schreckliche Antlitz des größten +Přebudovávání Země by mělo být hezčí, +než její ničení.","Det forfærdelige ansigt af den største +dæmon, du nogensinde har set, smuldrer +foran dig, efter at du har pumpet dine +raketter ind i hans blottede hjerne. +Monsteret skrumper sammen og dør, mens +dets smældende lemmer ødelægger utallige +kilometer af helvedes overflade. + +Du har gjort det. Invasionen er forbi. +Jorden er reddet. Helvede er et vrag. +Du spekulerer på, hvor de onde folk vil +tage hen, når de dør nu. Du tørrer sveden +af din pande og begynder den lange +vandring hjemad. Det burde være meget +sjovere at genopbygge Jorden end at +ødelægge den.","Das schreckliche Antlitz des größten Dämonen, den du jemals gesehen hast, zerbröckelt, nachdem du deine Raketen in sein Hirn gepumpt hast. @@ -2095,20 +2514,20 @@ Du wischst den Schweiß von deiner Stirn und begibst dich auf den langen Weg nach Hause. Der Wiederaufbau der Erde dürfte erfreulicher sein, als ihre Zerstörung.",,"La horora vizaĝo de la plej granda -demono, kiun vi vidis iam ajn, -pecetiĝas antaŭ vi, post vi pumpis -raketojn en lian nudan cerbon. Dum -la monstro ŝrumpas kaj mortas, ĝiaj -draŝantaj membroj ruinigas nenumerablajn -kilometrojn da la supraĵo de Infero. +demono, kiun vi iam ajn vidis, pecetiĝas +antaŭ vi, post vi pumpis la raketojn +en lian nudan cerbon. La monstro +ŝrumpas kaj mortas, ĝiaj draŝantaj +membroj ruinigante nenombreblajn +kilometrojn de la supraĵo de Infero. Vi sukcesis. La invado estas finita. -La tero estas savita. Infero estas pereo. -Vi pripensas, kien malbonuloj nun iros, -kiam ili mortos. Vi forviŝas la ŝviton de -la frunto kaj komencas la longan vojaĝon -hejmen. Refari la Teron devus esti multe pli -amuze ol ruinigi ĝin estis.","El horrendo rostro del demonio más grande +La Tero estas savita. Infero estas ruino. +Vi scivolas, kien malbonuloj nun iros, +kiam ili mortos. Forviŝante la ŝviton de +la frunto, vi komencas la longan vojaĝon +hejmen. Rekonstrui la Teron devus esti +multe pli amuze ol ruinigi ĝin.","El horrendo rostro del demonio más grande que hayas visto se derrumba ante ti, después de bombear tus cohetes en su cerebro expuesto. El monstruo se @@ -2116,8 +2535,8 @@ desintegra y muere, sus miembros azotan el suelo devastando incontables kilómetros de suelo infernal. -Lo has hecho. La invasión se acabó. La tierra -está a salvo. El infierno es una ruina. Te +Lo has conseguido. La invasión ha terminado. La Tierra +ha sido salvada. El Infierno es una ruina. Te preguntas adónde irán los malos cuando mueran ahora. Secándote el sudor de la frente comienzas el largo camino de vuelta @@ -2152,19 +2571,19 @@ iront quand ils seront morts maintenant. Essuyant la sueur de votre front, vous entreprenez le long chemin du retour. Reconstruire la Terre devrait être plus -amusant que de la détruire.","A borzalmas tekintete a legnagyobb démonnak +amusant que de la détruire.","A borzalmas ábrázata a legnagyobb démonnak amit valaha láttál összeomlik előtted, amikor -betömködted a rakétáidat a védtelen agyába. +betömködted a rakétáidat a kilátszódó agyába. A szörny összeroncsolodik és meghal, a végtagjai szanaszét repülnek a pokol felszínén. Megcsináltad. Az inváziónak vége. -A föld megmenekült. A Pokolnak annyi. -Elgondolkodsz azon, hogy hova mennek a rossz -fiúk, amikor meghalnak most. Letörlöd az -izzadtságot a homlokodról mielőtt +A Föld megmenekült. A pokol romba dőlt. +Elgondolkodsz azon, hogy mostantól hová kerülnek a rossz +fiúk, amikor meghalnak. Letörlöd az +izzadtságot a homlokodról, mielőtt hazacammogsz. Újjáépíteni a Földet -szórakoztatóbb lesz, mint elpusztítani volt.","L'orrendo viso del demone più grosso +szórakoztatóbb lesz, mint az elpusztítása volt.","L'orrendo viso del demone più grosso che tu abbia mai visto si sfascia davanti a te, dopo che hai sparato I tuoi razzi nel suo cervello esposto. Il mostro si @@ -2215,23 +2634,39 @@ Als je het zweet van je voorhoofd veegt, begin je aan de lange tocht terug naar huis. Het herbouwen zou veel leuker moeten zijn dan het verpesten van de aarde. -","Przerażające oblicze największego -demona, którego kiedykolwiek widziałeś, -rozpada się przed tobą tuż po tym jak -napompowałeś rakietami jego obnażony -mózg. Potwór usycha i umiera, jego -zniszczone kończyny niszczące niezliczoną -ilość mil powierzchni piekła. - -Udało ci się. To koniec inwazji. Ziemia +","Det fryktelige ansiktet til den +største demonen du noensinne +har sett smuldrer opp foran deg, +etter at du har pumpet rakettene +dine inn i den eksponerte hjernen +hans. Monsteret skrumper inn og +dør, og dets knusende lemmer +ødelegger utallige kilometer av +helvetes overflate. + +Du har klart det. Invasjonen er over. +Jorden er reddet. Helvete er et vrak. +Du lurer på hvor slemme folk vil gå +når de dør, nå. Du tørker svetten av +pannen og begynner den lange +vandringen hjem. Det burde være +mye morsommere å gjenoppbygge +jorden enn å ødelegge den.","Przerażające oblicze największego +demona, jakiego kiedykolwiek spotkałeś, +rozpada się po tym jak wysadziłeś +jego obnażony mózg. +Potwór usycha i umiera, a jego +obumierające kończyny niszczą +piekło wzdłuż i wszerz. + +Udało ci się. Koniec inwazji. Ziemia jest uratowana. Piekło jest w rozsypce. -Zastanawiasz się gdzie teraz się -zła rodzinka podzieje kiedy teraz zginie. +Zastanawiasz się gdzie teraz +całe zło się podzieje. Wycierając pot z czoła zaczynasz długą wedrówkę do domu. Odbudowa Ziemi powinna być większą frajdą niż jej -niszczenie. -","A visão horrenda do maior demônio que +niszczenie.","A visão horrenda do maior demônio que você já viu desmorona na sua frente depois de você lançar alguns foguetes dentro do seu cérebro exposto. Ele @@ -2275,22 +2710,19 @@ Infernul e făcut zob. Acum te întrebi unde merg oamenii răi după ce mor. Stergându-ți transpirația de pe frunte începi expediția lungă de întoarcere spre casă. Reconstruirea Pământului va fi cu -siguranță mai distractivă decât a fost ruinarea lui.","Жутчайший лик самого большого демона, -которого вы когда-либо видели, рушится -на ваших глазах после того, как вы -нашпиговали ракетами его незащищённый -мозг. Монстр угасает и гибнет, -разрушая бесчисленные мили поверхности -Ада. - -Вы справились. Вторжению конец. Земля -спасена. Ад повержен. Вы спрашиваете -себя: куда теперь после смерти будут -попадать грешники? Утерев пот -со лба, вы начинаете долгое путешествие -обратно домой. Восстановление земли -должно быть гораздо более интересным -занятием, нежели её разрушение.","Катастрофална прилика највећег демона +siguranță mai distractivă decât a fost ruinarea lui.","Леденящий душу лик самого крупного демона, +что вы когда-либо видели, падает пред +вами, после того, как вы пичкаете ракетами его обнажённый мозг. Чудище +корчится и умирает, мятущимися лапами +обращая в руины бесчисленную площадь поверхности преисподней. + +У вас получилось. Вторжение остановлено. В +аду и камня на камне не осталось. Вы +задаётесь вопросом, куда же теперь после +смерти отправятся плохие люди, и, вытерев +пот со лба, начинаете долгий путь домой. +Восстанавливать Землю наверняка будет куда +веселее, чем разрушать её.","Катастрофална прилика највећег демона кога сте икад видели рађа се пред вама, и одмах након палите своје ракете и гађате га у откривени део мозга. Чудовиште @@ -2304,28 +2736,64 @@ siguranță mai distractivă decât a fost ruinarea lui.","Жутчайший л зној са чела, почињете дугачак пут кyћи. Поновна изградња земље би требала бити забавнија од уништења исте. -" +","""Den största demonen som du någonsin +har sett faller ihop framför dig efter att +du har pumpat in dina raketer i hans +utsatta hjärna. Monstret skrumpnar +ihop och dör, dess slående lemmar +ödelägger otaliga mil av helvetets yta. + +Du har gjort det. Invasionen är över. +Jorden är räddad. Helvetet är ett vrak. +Du undrar vart de onda människorna +tar vägen när de dör, nu. Du torkar +svetten från pannan och börjar den +långa vandringen hemåt. Att +återuppbygga jorden borde vara mycket +roligare än vad det var att förstöra den.","Gördüğünüz en büyük iblisin +korkunç görüntüsü, roketlerinizi +açıktaki beynine pompaladıktan +sonra önünüzde parçalanıyor. +Canavar büzüşür ve ölür, +çırpınan uzuvları cehennem +yüzeyinin sayısız milini harap +eder. + +Başardınız. İstila sona erdi. +Dünya kurtuldu. Cehennem bir +enkaz. Şimdi kötü insanların +öldüklerinde nereye gideceklerini +merak ediyorsunuz. Alnınızdaki +teri silerek eve doğru uzun bir +yürüyüşe başlıyorsunuz. Dünyayı +yeniden inşa etmek, onu +mahvetmekten çok daha +eğlenceli olmalı." "Congratulations, you've found the secret level! Looks like it's been built by Humans, rather than demons. You wonder who the inmates of this corner of hell will be.",C5TEXT,Doom2 before MAP31,,,"Gratulujeme, objevil@[ao_cs] jsi tajný level! Zdá se, že tohle místo bylo postaveno -lidmi, ne démony. Zajímalo by tě, kdo -v tomhle rohu pekla bude vězněn.","Herzlichen Glückwunsch, du hast den +lidmi, ne démony. Zajímalo by tě, koho +v tomhle rohu pekla vězní.","Tillykke, du har fundet det hemmelige +niveau! Det ser ud til at være bygget +af mennesker og ikke af dæmoner. Du +spekulerer på, hvem de indsatte i +dette hjørne af helvede vil være.","Herzlichen Glückwunsch, du hast den Geheimlevel gefunden. Sieht so aus, als ob es von Menschen gebaut wurde, und nicht von Dämonen. Du fragst dich, wer wohl in diesem Bereich der Hölle zuhause ist. ",,"Gratulon! Vi trovis la sekretan nivelon! -Ŝajnas, ke ĝi estas konstruita de homoj -ol demonoj. Vi pripensas, kiu estos la -loĝantoj de ĉi angulo de Infero.","¡Enhorabuena, has encontrado el nivel +Ŝajnas, ke ĝi estis konstruita de homoj +anstataŭ demonoj. Vi scivolas, kiuj estos +la loĝantoj de ĉi tiu angulo de Infero.","¡Enhorabuena, has encontrado el nivel secreto! Parece que fue creado por seres humanos, en lugar de demonios. Te preguntas quienes serán los inquilinos -de este rincón del infierno.","¡Felicitaciones, has encontrado el nivel +de este rincón del Infierno.","¡Felicitaciones, has encontrado el nivel secreto! Parece que fue creado por seres humanos, en lugar de demonios. Te preguntas quienes serán los inquilinos @@ -2341,11 +2809,10 @@ prisonnier des enfers ici...","Gratulálunk, megtaláltad a titkos pályát! Úgy tűnik, hogy ezt emberek építették, és nem démonok. Elgondolkodsz azon, hogy miféle lények tartózkodnak a pokol eme szegletében.","Congratulazioni, hai trovato il livello -degreto! Sembra essere stato edificato +segreto! Sembra essere stato edificato da umani più che da demoni. Ti chiedi chi siano gli abitanti di questo angolo -dell'inferno. -","おめでとう、君は隠しステージを発見した! +dell'inferno.","おめでとう、君は隠しステージを発見した! どうやらこの場所は悪魔ではなく、人間たちによって作られたようだ。 地獄の片隅には、どんな罪人がいるのだろうか?","축하한다. 당신은 비밀 레벨을 찾아냈다! 여기는 악마들보다는 인간들이 건설한 곳 같다. 그러나 당신은 구석에 있는 죄수들이 지옥에 있던 놈들임을 @@ -2354,9 +2821,14 @@ gevonden! Het lijkt erop dat het is gebouwd door mensen, in plaats van demonen. Je vraagt je af wie de bewoners van deze hoek van de hel zullen zijn. -","Gratulacje, znalazłeś sekretny poziom! -Wygląda na to, że został on raczej -zbudowany przez ludzi niż przez demony. +","Gratulerer, du har funnet det +hemmelige nivået! Ser ut som +det er bygget av mennesker, ikke +demoner. Du lurer på hvem +fangene i dette hjørnet av +helvete vil være.","Gratulacje, znalazłeś sekretny poziom! +Wygląda na to, że został on zbudowany +przez ludzi, a nie demony. Zastanawiasz się kim będą mieszkańcy tego zakątka piekła.","Parabéns, você achou a fase secreta! Parece ter sido construído por humanos, @@ -2369,22 +2841,33 @@ são os habitantes desta parte do inferno. ","Felicitări, ai găsit nivelul secret! Pare să fii fost construit de oameni mai degrabă decât demoni. Te întrebi cine ar putea fi deținuții -acestuit colț de infern.","Поздравляем — Вы нашли секретный -уровень! Похоже, он был построен -людьми, а не демонами. Любопытно, -кто же населяет этот уголок Ада?","Честитамо, пронашли сте скривени ниво! +acestuit colț de infern.","Поздравляем, вы нашли секретный уровень! Похоже, это место построено людьми, а не +демонами. Вы гадаете, кто же заключён +в этом уголке преисподней.","Честитамо, пронашли сте скривени ниво! Изгледа да је био изграђен од стране људи, а не монструма. Размишљате ко -ће бити становници овог дела пакла." +ће бити становници овог дела пакла.","Grattis, du har hittat den hemliga nivån! +Det ser ut som om den har byggts av +människor, snarare än demoner. Du +undrar vilka de intagna i detta hörn +av helvetet kommer att vara.","Tebrikler. Gizli seviyeyi buldunuz! +Şeytanlar değil de İnsanlar +tarafından inşa edilmiş gibi +görünüyor. Cehennemin bu +köşesinin sakinlerinin kim +olacağını merak ediyorsunuz." "Congratulations, you've found the super secret level! You'd better -blaze through this one!",C6TEXT,Doom2 before MAP32,,,"Gratulujeme, objevil@[ao_cs] jsi supertajný level! -Radši bys tímhle místem měl@[ao_cs] prosvištět!","Herzlichen Glückwunsch, du hast den +blaze through this one! +",C6TEXT,Doom2 before MAP32,,,"Gratulujeme, objevil@[ao_cs] jsi supertajný level! +Radši bys tímhle místem měl@[ao_cs] prosvištět!","Tillykke, du har fundet det +superhemmelige niveau! Du må hellere +komme hurtigt igennem denne!","Herzlichen Glückwunsch, du hast den Super-Geheimlevel gefunden. Sieh zu, dass du hier schnellstens rauskommst! ",,"Gratulon! Vi trovis la super-sekretan -nivelon! Vi povu kuri tra ĉi tio!","¡Enorabuena, has encontrado el nivel +nivelon! Prefere kuru tra ĉi tiu!","¡Enorabuena, has encontrado el nivel súper secreto! ¡Será mejor que eches lumbre a través de este!","¡Felicitaciones, has encontrado el nivel súper secreto! ¡Será mejor que eches @@ -2403,15 +2886,20 @@ che tu lo percorra di corsa! 통과하는 게 좋을 것이다!","Gefeliciteerd, je hebt het super geheime niveau gevonden! Zorg dat je hier zo snel mogelijk weg bent! -","Gratulacje, znalazłeś super sekretny -poziom! Lepiej jak najszybciej go przejdź!","Parabéns! Você achou a fase super secreta! +","Gratulerer, du har funnet det +superhemmelige nivået! +Du bør brenne gjennom denne!","Gratulacje, znalazłeś super sekretny +poziom! Przejdziesz go w mgnieniu oka!","Parabéns! Você achou a fase super secreta! É melhor meter fogo por ela!","Parabéns! Achaste o nível super secreta! É bom que seja canja passar este aqui.","Felicitări, ai găsit nivelul super secret! Ai face bine -să termini rapid cu el!","Поздравляем — Вы нашли сверхсекретный -уровень! Лучше бы Вам стремительно -прорваться сквозь него!","Честитамо, пронашли сте +să termini rapid cu el!","Поздравляем, вы нашли сверхсекретный +уровень! И здесь вас вновь ждут кин-о и +немцы.","Честитамо, пронашли сте супер скривени ниво! -Боље да пролетите кроз ово!" +Боље да пролетите кроз ово!","Grattis, du har hittat den superhemliga +nivån! Det är bäst att du tar dig igenom +den här!","Tebrikler, süper gizli seviyeyi +buldunuz! Bunu geçsen iyi olur!" "You gloat over the steaming carcass of the Guardian. With its death, you've wrested the Accelerator from the stinking claws @@ -2431,10 +2919,22 @@ Zatraceně! Měl tu být alespoň jeden funkční prototyp, ale nikde ho nevidíš. Démoni jej museli ukrást. -Musíš najít ten prototyp, jinak veškeré -tvé snahy byly zbytečné. Jdi dál, bij +Musíš najít ten prototyp, jinak byly veškeré +tvé snahy zbytečné. Jdi dál, bij se dál, zabíjej dál. -Jo, a taky žij dál.","Du ergötzt dich an dem dampfenden Kadaver +Jo, a taky žij dál.","Du fryder dig over det dampende kadaver +af den Vogter. Med dens død har du vristet +Acceleratoren ud af Helvedes stinkende +kløer. Du slapper af og kigger rundt i +rummet. Fandens! Der skulle være mindst +én fungerende prototype, men du kan ikke +se den. Dæmonerne må have taget den. + +Du må finde prototypen, ellers vil al +din kamp have været forgæves. Bliv +ved med at bevæge dig, bliv ved med +at kæmpe, bliv ved med at dræbe. +Åh ja, bliv også ved med at leve.","Du ergötzt dich an dem dampfenden Kadaver des Wächters. Nach seinem Tod hast du ihm den Beschleuniger aus seinen stinkenden Höllen- klauen gerungen. Du entspannst dich und @@ -2454,12 +2954,12 @@ almenaŭ unu funkcia prototipo, sed vi ne vidas ĝin. La demonoj verŝajne prenis ĝin. Vi bezonas trovi la prototipon, alie viaj -baraktoj estos tute neefika. daŭru iri, daŭru +baraktoj estos vanitaj. Daŭru iri, daŭru batali, daŭru mortigi. Ho jes, ankaŭ daŭru vivi.","Te regocijas sobre el cadáver humeante del Guardián. Con su muerte, has arrebatado el acelerador de las pestilentes garras del -infierno. Te relajas y echas un vistazo a la +Infierno. Te relajas y echas un vistazo a la habitación. ¡Maldición! Se suponía que al menos había un prototipo en funcionamiento, pero no puedes verlo. Los @@ -2508,10 +3008,10 @@ tous vos combats auront été vains. continez à avancer, à vous battre, à tuer. Oh oui, à vivre, aussi.","Kéjsóvár tekintettel nézel az áramló Őrző hulláján. A halálával kicsavartad a -gyorsítót a Pokol büdös karmaiból. Ellazulsz és -egy pillantást teszel körül a szobában. Az istenit! -Kellett volna lennie legalább egy működő -prototípusnak, de te nem találod sehol. +Gyorsítót a Pokol büdös karmaiból. Ellazulsz és +egy pillantást teszel körül a szobában. Francba! +Itt kéne lennie legalább egy működő +prototípusnak, de nem találod sehol. A démonok talán elvihették. Meg kell találnod a prototípust, vagy az összes @@ -2530,7 +3030,7 @@ sforzi saranno stati vani. Continua a muoverti, continua a combattere, continua a uccidere. E continua a restare vivo.","蒸し焼きになった地獄の番人を見てほくそ笑み、 アクセラレーターを遺体の手からもぎ取った。 -駄目だ! 1つぐらい稼働している試作機があると思ったが +駄目だ!1つぐらい稼働している試作機があると思ったが 全て奴等が奪ったに違いない。 どうにかして試作機を見つけなければ今までの闘争が無駄になってしまう。 @@ -2557,19 +3057,34 @@ Je moet het prototype vinden, anders zijn al je gevechten verloren gegaan. Blijf in beweging, blijf vechten, blijf doden. Oh ja, blijf ook leven. -","Triumfujesz nad stygnącymi zwłokami -strażnika. Z jego śmiercią wyrwałeś +","Du fryder deg over det dampende +kadaveret av Vokteren. Med dens +død har du vristet Akseleratoren +fra helvetes stinkende klør. Du +slapper av og ser deg rundt i +rommet. Fy søren! Det skulle være +minst én fungerende prototype, +men du kan ikke se den. +Demonene må ha tatt den. + +Du må finne prototypen, ellers vil +alle kampene dine ha vært +bortkastet. Fortsett å bevege +deg, fortsett å kjempe, fortsett +å drepe. Å ja, fortsett å leve +også.","Triumfujesz nad stygnącymi zwłokami +strażnika. Dzięki jego śmierci wyrwałeś akcelerator ze śmierdzących szponów piekła. Odpoczywasz i rozglądasz się po pokoju. Kurde! Powinien tu być przynajmniej jeden działający prototyp, -ale go nie widzisz. Demony musiały +ale nie możesz go znaleźć. Demony musiały go zabrać ze sobą. Musisz znaleźć prototyp w przeciwnym razie cały twój wysiłek pójdzie na marne. Ruszaj się, walcz, zabijaj. -O... i pamiętaj by żyć.","Você se vangloria em cima da carcaça fumegante +Ach i jeszcze jedno... uważaj na siebie.","Você se vangloria em cima da carcaça fumegante do Guardião. Apos matá-lo, você arranca o Acelerador das garras fétidas do Inferno. Você relaxa e olha em volta da sala. Droga! @@ -2601,19 +3116,19 @@ nicăieri. Probabil că l-au luat demonii. Trebuie să găsești prototipul, altminteri toată munca ta se va duce de râpă. Continuă să te miști, continuă să lupți, continuă să omori. Ah, da, continuă și să -trăiești, de asemenea.","Вы со злорадством смотрите на горящий -каркас Стража. С его смертью Вы вырвали -Ускоритель из зловонных когтей Ада. -Расслабившись, Вы окидываете взглядом -помещение. Проклятье! Тут должен был быть -хотя бы один рабочий прототип, но -демоны, должно быть, забрали его с собой. - -Вы должны найти прототип, иначе все Ваши -прошлые усилия окажутся напрасными. -Продолжайте двигаться, продолжайте -сражаться, продолжайте убивать. И да, -продолжайте жить.","Пиљите над испаравајући леш Чувара. +trăiești, de asemenea.","Вы злорадствуете над дымящимися останками +стража. Убив его, вы вырвали ускоритель +из вонющих лап преисподней. Вы вздыхаете с +облегчением и осматриваете комнату. Чёрт! +Здесь должен был остаться как минимум один +рабочий прототип, но вы его не видите. +Должно быть, его забрали демоны. + +Вам нужно найти прототип, иначе все ваши +старания пойдут прахом. Продолжайте +двигаться, продолжайте сражаться, +продолжайте убивать. Ах, да, и продолжайте +жить при этом.","Пиљите над испаравајући леш Чувара. Са његовом смрћу, отргнули сте акцелератора ван смрдљивих канџа пакла. Опустивши се гледате унаоколо у @@ -2626,7 +3141,35 @@ trăiești, de asemenea.","Вы со злорадством смотрите н муке протраћене. Наставите да се крећете, наставите да се борите, наставите да убијате. -И да, наставите и да живите." +И да, наставите и да живите.","Ni gläds åt Väktarens rykande kadaver. +Med dess död har du vridit Acceleratorn +ur helvetets stinkande klor. Du slappnar +av och tittar runt i rummet. Fan! Det +skulle finnas åtminstone en fungerande +prototyp, men du kan inte se den. +Demonerna måste ha tagit den. + + Du måste hitta prototypen, annars har +all din kamp varit bortkastad. Fortsätt +röra på dig, fortsätt kämpa, fortsätt +döda. Åh ja, fortsätt att leva också.","Muhafız'ın dumanı tüten leşi +üzerinde kına yakıyorsunuz. +Onun ölümüyle Hızlandırıcı'yı +Cehennem'in kokuşmuş +pençelerinden kurtardınız. +Rahatlıyorsun ve odanın +etrafına bakıyorsun. Lanet +olsun! En azından bir tane +çalışan prototip olması +gerekiyordu ama onu +göremiyorsun. İblisler almış +olmalı. + +Prototipi bulmalısın, yoksa tüm +çabaların boşa gidecek. +Devam edin, savaşmaya devam +edin, öldürmeye devam edin. +Oh evet, yaşamaya da devam edin." "Even the deadly Arch-Vile labyrinth could not stop you, and you've gotten to the prototype Accelerator which is soon @@ -2637,16 +3180,22 @@ tě nemohl zastavit a ty ses dostal@[ao_cs] k prototypu Akcelerátoru, který je už brzy účinně a permanentně deaktivován. -Tyhle věci by ti šly.","Sogar das tödliche Labyrinth der Scheusale +Tyhle věci by ti šly.","Selv den dødbringende ærkevile-labyrint +kunne ikke stoppe dig, og du er nået +frem til prototypen af acceleratoren, +som snart er effektivt og permanent +deaktiveret. + +Du er god til den slags ting.","Sogar das tödliche Labyrinth der Scheusale konnte dich nicht aufhalten und du hast den Beschleuniger-Prototypen erreicht, der kurz darauf effizient und dauerhaft deaktiviert ist. -Darin bist du gut.",,"Eĉ la mortiga labirinto de Ĉefaĉbestoj ne +Darin bist du gut.",,"Eĉ la mortiga labirinto de Ĉef-Fiuloj ne povis haltigi vin, kaj vi iris al la prototipa -Akcelilon, kiu estas rapide kaj neripareble -deaktivigita. +Akcelilo, kiu estas rapide kaj neripareble +malaktivigita. Vi faras bone tian ion.","Ni siquiera el laberinto mortal de los Arch-Viles te ha podido detener y @@ -2673,9 +3222,9 @@ et vous obtenez le prototype d'accélérateur que vous parvenez à désactiver efficacement et pour toujours. -Vous êtes doué pour ces choses là.","Még a halálos Arch-Ördög labirintus sem tudott +Vous êtes doué pour ces choses là.","Még a halálos Ősálnok-labirintus sem tudott megállítani, és eljutottál a Gyorsító prototípushoz, -ami hamarosan végleg kilesz kapcsolva. +ami hamarosan végleg ki lesz iktatva. Te jó vagy az ilyesmiben.","Neanche il letale labirinto degli Arch-Vile ti ha fermato e sei arrivato al prototipo @@ -2696,10 +3245,17 @@ handen, dat snel efficiënt en permanent wordt gedeactiveerd. Daar ben je goed in. -","Nawet śmiercionośny labirynt -Arcy-Bestii nie mógł cię zatrzymać +","Selv den dødelige Erkefiende- +labyrinten kunne ikke stoppe +deg, og du har kommet til +prototypen Accelerator som +snart er effektivt og +permanent deaktivert. + +Du er flink til sånt.","Nawet śmiercionośny labirynt +Arcypodleców nie mógł cię zatrzymać i dotarłeś do prototypu akceleratora, który ma -być skutecznie i trwale dezaktywowany. +być trwale dezaktywowany. Jesteś dobry w te klocki.","Nem mesmo o labirinto mortal do Arch-Vile pôde te deter. Você consegue chegar ao @@ -2712,17 +3268,28 @@ stare să îți vină de hac, iar acum ai pus mâna pe prototipul Acceleratorului care va fi dezactivat în mod eficient și permanent curând. -Te pricepi la chestii de genul.","Даже смертельный лабиринт арчвайлов не -смог остановить Вас. Вы добрались до -прототипа Ускорителя, который вскоре -был уничтожен Вами раз и навсегда. +Te pricepi la chestii de genul.","Даже смертоносный лабиринт архвилей не +смог вас остановить, и вы добрались до +прототипа ускорителя, сразу же +деактивировав его раз и навсегда. -Уничтожение — Ваша специальность.","Чак ни смртоносан арчвилов лавиринт +Что вы очень даже хорошо умеете.","Чак ни смртоносан арчвилов лавиринт вас није могао зауставити, и узели сте прототип акцелератора који ће ускоро ефикасно бити деактивиран заувек. -Добри сте у таквим стварима." +Добри сте у таквим стварима.","Inte ens den dödliga Ärkevild-labyrinten +kunde stoppa dig, och du har nått fram +till prototypen av Acceleratorn som +snart är effektivt och permanent +avaktiverad. + +Du är bra på den typen av saker.","Ölümcül Baş Aşağılık labirenti bile +seni durduramaz, ve sen prototip +Hızlandırıcı yakında etkili ve +kalıcı olarak devre dışı bırakıldı. + +Bu tür şeylerde iyisin." "You've bashed and battered your way into the heart of the devil-hive. Time for a Search-and-Destroy mission, aimed at the @@ -2734,14 +3301,25 @@ Grinning evilly, you check your gear, and get ready to give the bastard a little Hell of your own making!",P3TEXT,Plutonia after MAP20,,,"Prorval@[ao_cs] a promlátil@[ao_cs] sis svou cestu do srdce roje démonů. Je čas na -starou dobrou misi „najdi a znič“, mířenou +starou dobrou misi najdi a znič, mířenou na Vrátného démona, jehož odporní potomci se řítí na Zem. Jo, je zlý. Ale ty víš, kdo je zlejší! Se zlým úšklebkem si překontroluješ výstroj a připravíš se tomu bastardovi @[self_cs] -trochu zatopit!","Du hast dich bis ins Herz dieses Höllenbaus +trochu zatopit!","Du har slået og slået dig vej ind i +hjertet af djævlehulen. Det er tid +til en Search-and-Destroy-mission, +der er rettet mod Gatekeeperen, +hvis fæle afkom strømmer til Jorden. +Ja, han er slem. Men du ved, hvem +der er værre! + +Med et ondt grin tjekker du dit udstyr +og gør dig klar til at give den +skiderik et lille helvede af din egen +skuffe!","Du hast dich bis ins Herz dieses Höllenbaus durchgeschlagen. Zeit für eine Such- und Zerstörungsmission gegen den Torwächter, dessen stinkende Abkommen auf @@ -2753,15 +3331,15 @@ Ausrüstung und machst dich bereit, dem Bastard einen höllischen Empfang zu bereiten. ",,"Vi bategis kaj disbatis vian vojon en la koron -de la diablujo. Trovado-detruado-misio -tempas, celante La Cerberon, kies aĉaj idoj +de la diablujo. Tempas por Trovado-Detruado- +Mision, celante La Cerberon, kies aĉaj idoj dispeliĝas al La Tero. Jes, li estas mava, sed vi konas iun pli mavan! Grimacante malice, vi kontrolas vian ilaron, -kaj pretas doni al la bastardo Iom da Infero -de via farado mem!","Has golpeado y vapuleado tú camino al -corazón de la colmena diabólica. Es +kaj pretiĝas doni al la bastardo iom da Infero +de via farado mem!","Has golpeado y vapuleado abriéndote camino hacia +el corazón de la colmena diabólica. Es hora de una misión de búsqueda y destrucción, con el guardián del portal como objetivo, cuyos viles vástagos se @@ -2791,16 +3369,15 @@ Mais vous savez qui est pire! Souriant malicieusement, vous vérifiez l'équipement et vous vous préparez a faire voir a ce fumier un petit enfer -fait de vos propres mains!","Áttörted magad az ördög-fészek szívébe. -Itt az idő egy kis Keresés-és-Lerombol -küldetéshez, a Kapuőrző felé, akinek a rohadt -kölykei a föld felé zuhognak. Igen, ő rossz. De -te tudod hogy ki a rosszabb! - -Gonoszan mosolyogva, ellenőrzöd a felszerelésed, -és felkészülsz hogy adj annak a mitugrásznak egy -kis sajátos poklot!","Ti sei aperto la via nel cuore del nido -dei demoni. è ora di una missione +fait de vos propres mains!","Beverekedted magad az ördögkaptár szívébe. +Itt az idő arra, hogy felderítsd és kiiktasd a Kapuőrzőt, +aki piszkos kölykeit a Földre zúdítja. +Igen, ő rossz. De te tudod, hogy nála ki rosszabb! + +Gonosz vigyorral az arcodon ellenőrzöd a felszerelésed, +és felkészülsz arra, hogy megmutasd a rohadéknak, hogy +mi is az a pokol!","Ti sei aperto la via nel cuore del nido +dei demoni. È ora di una missione Cerca e Distruggi con obiettivo il Guardiano del cancello le cui malvage creature si riversano sulla Terra. Sì, @@ -2832,16 +3409,27 @@ is slecht. Maar je weet wie erger is! Je controleert je spullen en maakt je klaar om de klootzak een beetje de hel van je eigen makelij te geven! -","Wywalczyłeś sobie drogę do serca -diabelskiej kolonii. Czas na misję typu -""Znajdź i zniszcz"" wymierzoną w +","Du har slått og banket deg vei +inn i hjertet av djevelhulen. På +tide med et søk-og-ødelegg- +oppdrag, rettet mot port- +vokteren, hvis fæle avkom +strømmer til jorden. Ja, han er +slem. Men du vet hvem som +er verre! + +Du gliser ondt, sjekker utstyret +ditt og gjør deg klar til å gi +jævelen et lite helvete du +selv har laget!","Wywalczyłeś sobie drogę do serca +diabelskiej kolonii. Czas zniszczyć strażnika bramy, którego cuchnące potomstwo zalewa Ziemię. -Taa... jest zły, ale wiesz kto jest gorszy! +Taa... jest zły, ale pokażesz mu kto jest gorszy! Złowieszczo się uśmiechasz, sprawdzasz -swe uzbrojenie i przygotowujesz się aby -trochę dać popalić temu sukinsynowi.","Você batalhou e fez de tudo para chegar +swe uzbrojenie i przygotowujesz się, by +dać popalić temu sukinsynowi.","Você batalhou e fez de tudo para chegar no meio da colméia dos demônios. Está na hora de localizar e destruir o Protetor do Portão, cuja prole repugnante está vindo aos montes @@ -2859,19 +3447,16 @@ asemeni cascadelor pe Pământ. Mda, e dur. Dar tu știi cine e și mai dur! Zâmbind malefic, îți verifici echipamentul și te -pregătești să-i dai o mamă de bătaie ticălosului.","Вы пробили путь в самое -сердце дьявольского улья. Настало время -для миссии «найти и уничтожить», -объектом которой станет Привратник, -чьи нечестивые отпрыски низвергаются -на Землю. - -Да, он страшен. Но Вы знаете, кто ещё страшней! - -Злобно ухмыляясь, Вы проверяете своё -снаряжение, и готовитесь преподать -ублюдку немного Ада Вашего -собственного изготовления!","Изударали и изубијали сте свој пут до срца +pregătești să-i dai o mamă de bătaie ticălosului.","С боем и грохотом вы добрались до самого +сердца дьявольского рассадника. Пора +устроить миссию по поиску и уничтожению +Привратника, ниспославшего на Землю своих +мерзостных отпрысков. Да, он крут. Но +вы-то знаете, кто круче! + +Злобно ухмыляясь, вы проверяете свою +выкладку и готовитесь устроить этому гаду +пекло собственного приготовления!","Изударали и изубијали сте свој пут до срца ђаволске кошнице. Време је за мисију Претражити-и-Уништити, усмерен ка Вратару, чије се гадно потомство спушта @@ -2881,7 +3466,28 @@ pregătești să-i dai o mamă de bătaie ticălosului.","Вы пробили п Са злобним изразом проверавате опрему, и припремате се да дате том кучкином сину мало пакла од -сопственог стварања!" +сопственог стварања!","Du har slagit och slagit dig in i +djävulskyrkans hjärta. Dags för ett +uppdrag att söka och förstöra, +riktat mot Portvakten, vars avkommor +som sprider sig till jorden. Ja, han är +ond. Men du vet vem som är värre! + +Med ett illvilligt flin kontrollerar du din +utrustning och gör dig redo att ge +jäveln ett litet helvete som du själv +har skapat!","İblis kovanının kalbine giden yolda +savaştınız. İğrenç köleleri Dünya'yı +istila eden Kapı Bekçisi'ni hedef +alan bir Arama ve Yok Etme +görevinin zamanı geldi. Evet, o +kötü biri. Ama kimin daha kötü +olduğunu biliyorsun! + +Şeytani bir sırıtışla teçhizatınızı +kontrol edin ve piç kurusuna kendi +yarattığı cehennemi yaşatmaya +hazır olun!" "The Gatekeeper's evil face is splattered all over the place. As its tattered corpse collapses, an inverted Gate forms and @@ -2903,7 +3509,18 @@ k trestání zlých, mrtvých lidí, místo těch dobrých a živých. Nezapomeň svým vnoučatům říct, aby ti do rakve přidali raketomet. Jestli po smrti půjdeš do pekla, budeš ho -pro poslední úklid potřebovat.","Das böse Gesicht des Wächters ist mit +pro poslední úklid potřebovat.","Portvogterens onde ansigt er spredt ud +over det hele. Da dens flossede lig +falder sammen, dannes en omvendt port, +som suger stumperne af den sidste prototype +Accelerator ned, for ikke at nævne de få +tilbageværende dæmoner. Du er færdig. +Helvede er gået tilbage til at banke onde +døde folk i stedet for gode levende folk. +Husk at bede dine børnebørn om at lægge +en raketkaster i din kiste. Hvis du +kommer til Helvede, når du dør, får +du brug for den til en sidste oprydning ...","Das böse Gesicht des Wächters ist mit Blut besudelt. Als seine zerfledderte Leiche kollabiert, bildet sich ein inverses Tor und saugt die letzten Überreste des @@ -2920,25 +3537,25 @@ eine letzte Reinigung vornehmen kannst...",,"La mava vizaĝo de La Cerbero estas ŝprucetiga ĉirkaŭe. Dum ĝia disŝirita kadavro disfalas, inversa pasejo formiĝas kaj sorbas la nemultajn ceterajn demonojn. -Vi finis. La Infero rekomencis pisti mavajn -mortajn uloj, anstataŭ bonajn vivajn ulojn. +Vi finis. Infero rekomencis pisti mavajn +mortintojn, anstataŭ bonajn vivulojn. Memoru peti viajn genepojn meti raketlanĉilon en vian ĉerkon. Sed vi iros al -La Infero, kiam vi mortos, vi bezonos ĝin -por kelka purigado...","El malvado rostro del guardián del +Infero, kiam vi mortos, vi bezonos ĝin +por kelka fina purigado...","El malvado rostro del guardián del portal está repartido por todo el lugar. Conforme su andrajoso cadáver se desmorona, se forma un portal invertido y absorbe los restos del último prototipo del acelerador, sin mencionar a los pocos demonios -que quedan. Lo lograste. El infierno +que quedan. Lo lograste. El Infierno nuevamente va a castigar a los muertos que hacen el mal, en vez de hacerlo con los vivos que obran bien. Recuerda decirle a tus nietos que pongan un lanzacohetes en tú -ataúd. Si al morir vas al infierno, +ataúd. Si al morir vas al Infierno, lo necesitarás para hacer la última ronda de limpieza...",,"Portinvartijan häijyt kasvot roiskuvat yltympäri. Kun sen revitty ruumis luhistuu, @@ -3008,17 +3625,32 @@ niet om je kleinkinderen te vertellen dat ze een raketwerper in je kist moeten stoppen zodat je nog een laatste keer kunt opruimen als je naar de hel gaat. -","Zła twarz strażnika bramy została rozbryzgana -po całym pokoju. Podczas gdy jego -rozszarpane zwłoki opadają, odwrócona -brama formuje się i zasysa odłamki ostatniego -prototypu akceleratora, nie zapominając o -pozostałych demonach. Jesteś wykończony. -Piekło wraca do tłuczenia tych złych -umarlaków zamiast cnotliwych żywych ludzi. -Pamiętaj, aby powiedzieć twoim wnukom, by +","Portvokterens onde ansikt er +sprutet ut over det hele. Når +det fillete liket kollapser, +dannes en omvendt port som +suger ned fragmentene av den +siste prototypen av +akseleratoren, for ikke å nevne +de få gjenværende demonene. +Du er ferdig. Helvete har gått +tilbake til å banke dårlige døde +folk i stedet for gode levende. +Husk å be barnebarna dine +om å legge en rakettkaster i +kisten din. Hvis du havner i +helvete når du dør, trenger du +den til den siste oppryddingen...","Okrutna twarz strażnika bramy została +rozbryzgana po całym pokoju. Jego +rozszarpane zwłoki opadają, a odwrócona +brama formuje się i wciąga odłamki ostatniego +prototypu akceleratora wraz z pozostałościami +demonów. Jesteś wykończony. +Piekło wróciło do torturowania dusz złoczyńców +zamiast cnotliwych żywych ludzi. +Pamiętaj, by powiedzieć swoim wnukom, by włożyły wyrzutnię rakiet do twojej trumny. -Kiedy po śmierci trafisz do piekła, będziesz jej +Jeśli po śmierci trafisz do piekła, będziesz jej potrzebował by dokonczyć sprzątanie.","O rosto maligno do Protetor do Portão está espalhada em pedaços por toda parte. Seu corpo entra em colapso, um portal invertido se forma @@ -3040,20 +3672,18 @@ oamenilor răi în locul celor buni, și vii. Nu uita să le amintești nepoților să îți pună un lansator de rachete în mormânt. Dacă te duci în Infern când mori, vei avea nevoie de el pentru a face curățenie -pentru ultima dată ...","После уничтожения лика Привратника -начинают формироваться инвертированные -Врата, которые затягивают в себя -последние обломки Ускорителя и -нескольких оставшихся демонов. - -Готово. Ад вернулся на круги своя, -поглощая лишь мертвых грешных людей, а не -живых праведных. - -Не забудьте попросить внуков положить -ракетницу в Ваш гроб. Если после смерти -Вы попадёте в Ад, она понадобится -для небольшой последней зачистки...","Чуварово зло лице је смрвљено свугде. +pentru ultima dată ...","От зловещего лика Привратника остались одни +лишь ошмётки. Как только его изорванные +останки с грохотом падают оземь, образуются +обратные врата и засасывают обломки +последнего прототипа ускорителя, не +говоря уже о немногих оставшихся демонах. +Вы закончили. Ад снова будет мучить плохих +и мёртвых, а не хороших и живых. +Не забудьте сказать внукам, чтобы положили +вам в гроб ракетомёт. Если после смерти вы +попадёте в ад, он вам понадобится для +окончательной зачистки...","Чуварово зло лице је смрвљено свугде. Док његов дроњав леш пада, инвертована капија се образује и увлачи делиће последњег акцелератора, камо @@ -3063,7 +3693,32 @@ pentru ultima dată ...","После уничтожения лика Привр Не заборавите да кажете својим унучади да вам ставе ракетни бацач у ковчег. Ако одете у пакао када умрете, треба ће вам -за последње чишћење..." +за последње чишћење...","Portvaktens onda ansikte är utspridd +överallt. När dess söndertrasade lik +kollapsar bildas en inverterad port +som suger ner skärvorna av den sista +prototypen av acceleratorn, för att inte +nämna de få återstående demonerna. +Du är klar. Helvetet har återgått till att +slå på dåliga döda människor i stället +för goda levande. Kom ihåg att be dina +barnbarn att lägga en raketkastare i din +kista. Om du kommer till helvetet när +du dör kommer du att behöva den +för att göra en sista städning ...","Kapı Bekçisi'nin şeytani yüzü her +yerde. Parçalanmış cesedi gibi +çöker, ters bir geçit oluşur ve son +parçalarını emer prototip +Hızlandırıcı'dan bahsetmiyorum +bile. kalan birkaç iblis. İşin bitti. +Cehennem kötü ölü insanları +dövmeye geri döndü iyi canlı +olanlar yerine. Unutmayın ki +torunlarına bir roket koymalarını +söyle tabutunda fırlatıcı. Eğer +cehenneme gidersen öldüğünde, +bazılarına ihtiyacın olacak son +temizlik ..." "You've found the second-hardest level we got. Hope you have a saved game a level or two previous. If not, be prepared to die @@ -3071,20 +3726,24 @@ aplenty. For master marines only.",P5TEXT,Plutonia before MAP31,,,"Nalezl@[ao_cs máme. Doufej, že sis jeden či dva levely zpátky hru uložil@[ao_cs]. Pokud ne, připrav se umírat, a to hodně. Tohle je -pouze pro mistry mariňáky.","Du hast den zweitschwersten Level gefunden, +pouze pro mistry mariňáky.","Du har fundet det næsthårdeste niveau, +vi har. Håber du har et gemt spil et +niveau eller to tidligere. Hvis ikke, +skal du være forberedt på at dø masser +af gange. Kun for master marines.","Du hast den zweitschwersten Level gefunden, den wir haben. Lass uns hoffen, dass du noch einen Spielstand vom letzten oder vorletzten Level hast. Falls nicht, bereite dich darauf vor, oft zu sterben. Nur für Top-Soldaten! -",,"Vi trovis la due plej malfacilan nivelon, kion +",,"Vi trovis la duan plej malfacilan nivelon, kiun ni havas. Mi esperas, ke vi havas konservitan ludon antaŭ unu aŭ du niveloj. Sed ne, pretu -morti multe. Por nur majstraj soldatoj.","Has encontrado el segundo nivel más +morti multe. Nur por majstraj soldatoj.","Has encontrado el segundo nivel más difícil que tenemos. Esperemos que hayas guardado la partida con uno o dos niveles de anticipación. De lo -contrario, prepárate a morir a placer. -Sólo para soldados profesionales.",,"Olet löytänyt toiseksi vaikeimman +contrario, prepárate a morir de placer. +Solo para marines profesionales.",,"Olet löytänyt toiseksi vaikeimman tasoistamme. Toivottavasti sinulla on tallennettuna peli edelliseltä tai sitä edelliseltä tasolta. Jos ei, valmistaudu @@ -3113,10 +3772,16 @@ een opgeslagen spel een of twee eerdere niveaus. Zo niet, wees bereid om te sterven in overvloed. Alleen voor meesterlijke mariniers. -","Znalazłeś drugi najtrudniejszy poziom jaki +","Du har funnet det nest +vanskeligste nivået vi har. +Håper du har et lagret spill +et nivå eller to tidligere. +Hvis ikke, vær forberedt på +å dø mange ganger. Kun for +mestermarinesoldater.","Znalazłeś drugi najtrudniejszy poziom jaki mieliśmy dla ciebie. Mamy nadzieję, że -zapisałeś jeden lub dwa poziomy wstecz. -Jeśli nie, badź gotów by wiele razy ginąć. +zapisałeś grę jeden lub dwa poziomy wstecz. +Jeśli nie, badź gotów na śmierć. Tylko dla najlepszych żołnierzy.","Você achou a segunda fase mais difícil que temos. Espero que tenha salvo o jogo a uma ou duas fases antes. Esta é só @@ -3124,37 +3789,41 @@ para quem é mestre.",,"Ai găsit al doilea cel mai dificil nivel creat de noi. Sper că ai o salvare cu o hartă sau două în urmă. Dacă nu, pregătește-te să mori din plin. Doar pentru -soldați marini maeștri.","Вы нашли второй по сложности уровень, -который у нас есть. Надеемся, Вы -сохранили игру на предыдущем уровне -или ещё раньше. Если нет, приготовьтесь -много умирать. - -Уровень рассчитан исключительно на -профессионалов.","Нашли сте другопласирани најтежи ниво +soldați marini maeștri.","Вы нашли второй по сложности уровень, что +у нас был. Мы надеемся, что у вас осталось +сохранение уровнем-двумя ранее. Если нет, +готовьтесь к множеству смертей. Только для +морпехов-мастеров.","Нашли сте другопласирани најтежи ниво који имамо. Надамо се да сте сачували игру ниво или два назад. Ако нисте, припремите се да умрете пуно пута. -Само за маестро маринце." +Само за маестро маринце.","Du har hittat den näst svåraste nivån +vi har. Hoppas att du har ett sparat +spel en nivå eller två tidigare. Om inte, +var beredd på att dö i mängder. +Endast för master marines.","Elimizdeki en zor ikinci seviyeyi buldun. +Umarım bir ya da iki seviye öncesine +ait kayıtlı bir oyununuz vardır. Eğer +yoksa, bolca ölmeye hazır olun. +Sadece usta savaşçılar için." "Betcha wondered just what WAS the hardest level we had ready for ya? Now you know. No one gets out alive.",P6TEXT,Plutonia before MAP32,,,"Určitě sis říkal@[ao_cs], CO byl ten nejtěžší level, který jsme pro tebe měli připravený? Teď už víš. -Ven se nikdo živ nedostane.","Du hast dich sicher gefragt, was denn nun +Ven se nikdo živý nedostane.","Du undrede dig sikkert over, +hvad der var det sværeste niveau, +vi havde klar til dig? Nu ved du det. +Ingen kommer ud i live.","Du hast dich sicher gefragt, was denn nun der schwerste Level ist, nicht wahr? Jetzt weißt du es - niemand kommt hier lebend raus! -",,"Vetis, ke vi scivolis, kion ja estas la plej -malfacila nivelo, kion ni pretigis por vi. -Nun vi scias. Neniu eskapas viva.","¿Apostamos a que te preguntabas -cuál SERÍA el nivel más difícil que -teníamos preparado para ti? Ahora -lo sabes. Nadie sale con vida de aquí.","¿Apostamos a que te preguntabas -cuál SERÍA el nivel más difícil que -teníamos preparado para ti?. -Ahora lo sabes. -Nadie ha salido con vida de aquí.","Lyönpä vetoa, että mietit, MIKÄ nyt olikaan +",,"Mi vetis, ke vi scivolis, kiu JA estas la plej +malfacila nivelo, kiun ni pretigis por vi. +Nun vi scias. Neniu eskapas viva.","A que te preguntabas cuál +SERÍA el nivel más difícil que +teníamos para ti; ahora lo sabes. +Nadie sale con vida de aquí.",,"Lyönpä vetoa, että mietit, MIKÄ nyt olikaan vaikein sinulle valmistamistamme tasoista. Nyt sinä tiedät. Kukaan ei pääse ulos elävänä.","Alors, vous vous demandiez quel @@ -3162,10 +3831,10 @@ elävänä.","Alors, vous vous demandiez quel avions préparé pour vous? Maintenant, vous savez. Nul n'en sortira vivant. -","Nos talán elgondolkodtál azon hogy MELYIK a -legnehezebb szint amit felkészítettünk neked? +","Feltetted magadban a kérdést, hogy mi a +legnehezebb pálya, amit kínálunk neked? Most már tudod. -Senki sem megy ki innen élve.","Scommetto che ti chiedevi quale fosse il +Senki sem jut ki innen élve.","Scommetto che ti chiedevi quale fosse il livello più duro che avessimo per te. Adesso lo sai. Nessuno ne esce vivo.","もっとも困難な場所が何なのか気になっているだろう。 @@ -3175,19 +3844,30 @@ Nessuno ne esce vivo.","もっとも困難な場所が何なのか気になっ niveau was dat we voor je hadden? Nu weet je het. Niemand komt er levend uit. -","Założę się, że zastanawiałeś się który poziom -BYŁ najtrudniejszy spośród tych które -mieliśmy dla ciebie? Teraz wiesz. Nikt nie +","Jeg vedder på at du lurte på +hva som var det vanskeligste +nivået vi hadde klart for deg? +Nå vet du det. +Ingen kommer ut i live.","Pewnie się zastanawiasz, który poziom jest +najtrudniejszy spośród tych, które +przygotowaliśmy, prawda? Teraz wiesz. Nikt nie wyjdzie stąd żywy.","Aposto que você estava pensando qual ERA a fase mais dificíl que preparamos. Agora você sabe. Ninguem sai vivo daqui.",,"Punem pariu că te întrebai CARE era nivelul nostru cel mai dificil? Ei, acum știi. -Nimeni nu scapă viu.","Спорим, Вы задавались вопросом, какой же -уровень САМЫЙ сложный? Теперь Вы знаете. -Никто не выберётся живым.","Гладимо се да сте се питали који је +Nimeni nu scapă viu.","Вы наверняка гадали, каков же самый +сложный уровень, что мы для вас +приготовили? Ну, теперь вы знаете. Никто +не уйдёт живым.","Гладимо се да сте се питали који је НАЈТЕЖИ ниво који смо спремили за -вас? Сада знате. Нико не излази жив." +вас? Сада знате. Нико не излази жив.","Du undrade säkert vad som var den +svåraste nivån vi hade redo för dig? +Nu vet du det. +Ingen kommer ut levande.","Eminim elimizdeki en zor seviyenin +ne olduğunu merak etmişsinizdir. +Artık biliyorsunuz. +Kimse canlı çıkamayacak." "You've fought your way out of the infested experimental labs. It seems that UAC has once again gulped it down. With their @@ -3201,15 +3881,26 @@ their teeth into you. With luck, the complex still has some warlike ordnance laying around.",T1TEXT,TNT after MAP06,,,"Probojoval@[ao_cs] sis svou cestu skrz zamořené laboratoře. Zdá se, že to v UAC zase -podělali. S takovou fluktuací pracovní -síly musí být pro chudáky z UAC těžké -najít si zdravotní pojištění... +podělali. S takovou fluktuací zaměstnanců +musí být pro chudáky z UAC těžké +najít si životní pojištění... V dáli leží vojenský komplex, ve kterém -se to hemží nakaženými příšerami +se to hemží nakaženými příšerami, horlivými se do tebe zakousnout. S trochou štěstí se tam taky stále -válí nějaké těžké kalibry.","Du hast dich aus den heimgesuchten Experi- +válí nějaké těžké kalibry.","Du har kæmpet dig ud af de inficerede +forsøgslaboratorier. Det ser ud til, +at UAC endnu en gang har slugt det hele. +Med deres høje omsætning må det være +svært for stakkels gamle UAC at købe +sygeforsikring nu om dage... + +Foran ligger det militære kompleks, +der nu vrimler med syge rædsler, +der er varme på at sætte tænderne i dig. +Med lidt held har komplekset stadig +noget krigsmateriel liggende.","Du hast dich aus den heimgesuchten Experi- mentier-Laboren herausgekämpft. Es sieht so aus, als ob die UAC es wieder mal ver- geigt hätte. Mit solchen Verlusten dürfte @@ -3222,16 +3913,17 @@ Kreaturen, die nur darauf warten, dich zu zerreißen. Wenn du Glück hast, liegen hier vielleicht noch einige Kampfmittel herum. ",,"Vi batalis vojante tra la infestitaj -eksperimentaj laboratorioj. Ŝajnas, ke La UAC +eksperimentaj laboratorioj. Ŝajnas, ke la UAC denove glutis ĝin malsupren. Kun iliaj multaj maldungadoj, certe malfacilas aĉeti por kompatinda UAC korporacian sanasekuron nuntempe... -Antaŭe situas la militkomplekso, nun plena -de malsanaj abomenoj atendantaj manĝi vin. -Per iomete da fortuno, la komplekso ankoraŭ -havas militan artilerion ĉirkaŭkuŝantan.","Has luchado por salir de los infestados +Antaŭe situas la militkomplekso, nun +svarmante kun malsanaj abomenoj atendantaj +mordi vin. Per iomete da fortuno, la komplekso +ankoraŭ havas kelkan militan artilerion +ĉirkaŭkuŝantan.","Has luchado por salir de los infestados laboratorios experimentales. Parece que la UAC una vez más ha vuelto a estropearlo todo. Con la alta rotación @@ -3270,17 +3962,14 @@ militaire, cela grouille d'horreurs morbides prêtes a vous estropier. Avec un peu de chance, le complexe a encore quelques armes de guerre -aux alentours.","Végig vergődtél a fertőzött kísérleti -laboratóriumokon. Úgy néz ki hogy a UAC -még utóljára lenyelte ezt. -A nagy irányváltásuk miatt, -eléggé nehéz lehet a régi szegény UAC-nek cégi -egészségbiztosítást venni a mai napokban... - -Elől található a Katonaság, rajozó beteg -borzalmakkal van tele hogy megkaparintsák a -fogad fehérjét. Szerencsével, a Katonaságnak még -mindig akadt némi lőszer ami szerteszét van.","Ti sei aperto la via fuori dai laboratori +aux alentours.","Végig küzdötted magad a fertőzött kísérleti laborokon. +Úgy néz ki a UAC épületek láttak jobb napokat is. +Szegény UAC gondokba fog ütközni amikor a +munkavállalókra akar majd kötni egészségbiztosítást. + +Előtted tornyosul a katonai-ipari komplexum, amelynek +borzasztó lakói alig várják, hogy beléd kóstolhassanak. +Némi szerencsével maradt még ellenük felhasználható fegyverzet.","Ti sei aperto la via fuori dai laboratori sperimentali infestati. Sembra che la UAC abbia fatto il passo più lungo della gamba di nuovo. Con questi continui turnover, @@ -3290,7 +3979,7 @@ impiegati di questi tempi... Più avanti si trova il complesso militare, ora infestato da orrori malati, ansiosi di -mettere i loro denti su di te. Con un pò +mettere i loro denti su di te. Con un po' di fortuna nel complesso potrebbero ancora esserci delle armi in giro.","侵略された研究施設を抜け出すことが出来た。 UACはまたもやられてしまったようだ。 @@ -3317,18 +4006,22 @@ Voor je ligt het militaire complex, nu wemelt het van de zieke gruwelen om hun tanden in je te krijgen. Met een beetje geluk heeft het complex nog wat wapens liggen. -","Wywalczyłeś sobie drogę wyjścia z -zaatakowanych laboratoriów doświadczalnych. -Wygląda na to, że UAC znów się tym zajęło. -Z ich ogromymi obrotami, musiało to być -trudne dla starego biednego UAC, by wykupić +","Du har kjempet deg ut av de infiserte forsøkslaboratoriene. Det ser ut til at UAC nok en gang har slukt det. Med deres høye omsetning må det være vanskelig for stakkars gamle UAC å kjøpe helseforsikring... +...nå for tiden. + +Foran oss ligger det militære komplekset, som nå vrimler av sykdomsskrekk som er ute etter å sette tennene i deg. Med litt flaks har komplekset fortsatt noe krigslignende krigsmateriell liggende.","Wywalczyłeś sobie drogę ucieczki z +okupowanych laboratoriów. +Wygląda na to, że UAC znów narobiło +sobie kłopotów. +Mając tyle kasy w kieszeniach, musiało to być +trudne dla biednego UAC, by wykupić w tych czasach ubezpieczenie zdrowotne... Przed tobą leży kompleks militarny rojący się -teraz od chorych horrorów gotowych, -by zanurzyć w tobie swe zęby. Na szczęście -kompleks wciąż ma trochę wojennego -uzbrojenia.","Você lutou para sair dos laboratórios infestados. +teraz od chorych straszydeł gotowych, +by zanurzyć w tobie swe kły. Na szczęście +kompleks wciąż ma trochę broni +w zapasie.","Você lutou para sair dos laboratórios infestados. Parece que a UAC pisou na bola mais uma vez. Com tanta rotatividade de funcionários, deve ser complicado para a pobre empresa conseguir @@ -3346,18 +4039,17 @@ asigurare de sănătate corporatistă bună. În față este complexul militar, care acum roiește de orori bolnave care abia așteaptă să-și înfigă dinții în tine. Cu ceva noroc, complexul mai are -niște artilerie de război pe undeva.","Сражаясь, Вы выбрались из заражённых -экспериментальных лабораторий. -Похоже, ОАК вновь облажались. С такой -текучестью кадров, нынче должно быть -сложно заполучить страховку -для своих сотрудников... - -Впереди расположен военный комплекс, -кишащий гадкими ужасами, только ждущими -как бы вгрызться в Вашу плоть. Что ж, -если повезёт, в комплексе всё ещё -должны быть боеприпасы.","Изборили сте се из роњевите +niște artilerie de război pe undeva.","Вам удалось вырваться из наводнённых +демонами экспериментальных лабораторий. +Похоже, ОАК опять села в лужу. Учитывая +высокую текучку кадров, бедной ОАК +сейчас, должно быть, сложно покупать +корпоративную медстраховку… + +Впереди вас ждёт военный комплекс, ныне +кишащий мерзостными ужасами, жаждущими +вогнать в вас клыки. Если вам повезёт, то +в нём ещё остались боеприпасы.","Изборили сте се из роњевите експерименталне лабораторије. Изгледа да је УАЦ опет прогутао. Са њиховом великим реноворирањем, @@ -3368,7 +4060,30 @@ niște artilerie de război pe undeva.","Сражаясь, Вы выбралис најежден мртвим хорорима који једва чекају да уроне зубе у вама. Са срећом, комплекс идаље има неко оружје које -лежи унаоколо." +лежи унаоколо.","Du har kämpat dig ut ur de infekterade +experimentlaboratorierna. Det verkar +som om UAC återigen har ställt till det. +Med sin höga omsättning måste det +vara svårt för stackars UAC att köpa +en företagsförsäkring nuförtiden... + +Framför oss ligger militärkomplexet, +som nu kryllar av sjuka skräckinjagare +som är heta på att sätta tänderna i dig. +Med lite tur har komplexet fortfarande +lite krigsmateriel som ligger kvar.","İstilaya uğradığın yerden savaşarak +çıktın. deneysel laboratuarlar. +Görünüşe göre UAC bir kez daha +yuttu. Onların yüksek ciro, yoksullar +için zor olmalı kurumsal sağlık +sigortası satın almak için eski +UAC Bugünlerde. + +Önümüzde askeri kompleks uzanıyor, +şimdi hastalıklı dehşetlerle kaynıyor +dişlerini sana geçirirler. Şansın varsa +kompleksinde hala bazı savaş +mühimmatları var etrafta yatıyor." "You hear the grinding of heavy machinery ahead. You sure hope they're not stamping out new hellspawn, but you're ready to @@ -3385,7 +4100,18 @@ Oni se možná chystají na krvavé hody, ty se ale cítíš jako tisíc šílenců narvaných do jednoho šíleného zabijáka. -Tak snadno jít k zemi v plánu nemáš.","Du hörst das Mahlen schwerer Maschinen. +Tak snadno jít k zemi v plánu nemáš.","Du kan høre det kværnen fra tunge +maskiner forude. Du håber virkelig +ikke, at de lader nye helvede- +synder, men du er klar til at +udrydde en hel flok, hvis du +er nødt til det. +De planlægger måske en blodfest, +men du føler dig lige så ondskabsfuld +som to tusinde galninge, der er samlet +i én gal morder. + +Du har ikke tænkt dig at gå let ned.","Du hörst das Mahlen schwerer Maschinen. Man kann nur hoffen, dass sie keine neue Höllenbrut produzieren. Aber du würdest die ganze Herde ausrotten, wenn nötig. @@ -3394,11 +4120,11 @@ du fühlst dich so stark wie zweitausend Wahnsinnige, zusammengepackt in einen verrückten Killer. -Du wirst es ihnen nicht einfach machen.",,"Vi aŭdas la grincado de amasa maŝinaro +Du wirst es ihnen nicht einfach machen.",,"Vi aŭdas la grincadon de amasa maŝinaro antaŭe. Vi certe esperas, ke ili ne fabrikas novajn inferidojn, sed vi pretas alezi tutan -brutaron se vi bezonas. Ili eble planas -sangfesteno, sed vi sentas proksimume +brutaron, se vi devas. Ili eble planas +sangfestenon, sed vi sentas vin proksimume aĉa, kiel du mil frenezuloj pakitaj en unu rabian mortiganton. @@ -3434,15 +4160,14 @@ un festin de sang, mais vous vous sentez comme deux milliers de fous dans le corps d'un seul et même tueur. -Vous ne pensez pas mourir si facilement.","Hallod ahogy a golyószóró dübörög elől. -Te halál biztos vagy benne hogy már nem jelenik -meg több pokoli lény, de te készen állsz arra hogy -szembeszállj egy hordával ha kellene. -Talán egy véres lakomát terverznek, de te -úgy érzel mintha kétezer őrjöngős szembeszáll -egyetlen őrült gyilkossal szemben. +Vous ne pensez pas mourir si facilement.","Már messziről hallod az üzemi gépek zaját. +Csak mered remélni, hogy a gépsorok nem +démonfajzatokat gyártanak. Legbelül azonban +készen állsz arra is hogy tömegével zúzod össze őket. +Valószínűleg te vagy a potenciális díszlakoma, +de érzed magadban kétezer másik katona erejét. -Nem tervezel elbukni olyan könnyen.","Senti lo sferragliare di grossi macchinari +Nem fogod könnyen adni az irhádat.","Senti lo sferragliare di grossi macchinari più avanti. Ti auguri che non stiano producendo nuovi demoni, ma sei pronto per farne fuori un intero branco se fosse @@ -3473,15 +4198,25 @@ net zo stark als tweeduizend maniakken die verpakt zijn in een gekke moordenaar. Je maakt het hen niet gemakkelijk. -","Słyszysz zgrzytajanie ciężkiej maszynerii. -Masz nadzieję, że nie tworzą kolejnego -diabelstwa, ale jesteś gotów by rozerwać całą -hordę jeśli zajdzie na to potrzeba. Mogą -planować krwistą ucztę, ale czujesz się -tak surowy jak dwa tysiące maniaków -zapakowanych w jednego wściekłego zabójcę. - -Nie planujesz tak łatwo dać się pokonać.","Você escuta o barulho de máquinas pesadas +","Du hører lyden av tungt maskineri +foran deg. Du håper virkelig at de +ikke slipper ut nye helvetesyngel, +men du er klar til å utslette en hel +flokk om du må. +De planlegger kanskje en +blodfest, men du føler deg +omtrent like slem som to tusen +galninger pakket inn i en gal +morder. + +Du har ikke tenkt å gi deg så lett.","Słyszysz zgrzytanie ciężkiej maszynerii. +Masz nadzieję, że nie tworzą tu kolejnego +diabelstwa, ale jesteś gotów by zniszczyć całą +hordę jeśli zajdzie taka potrzeba. Mogą +planować krwistą ucztę, ale czujesz taką złość +jakby siedziało w tobie dwa tysiące maniaków. + +Nie planujesz tak łatwo się poddać.","Você escuta o barulho de máquinas pesadas mais adiante. Você espera que eles não estejam gerando mais criaturas infernais, mas está pront@[ao_ptb] para aniquilar um bando inteiro se for necessário. @@ -3496,20 +4231,17 @@ gata să arzi o întreagă turmă dacă e necesar. Posibil să planifice un festin sângeros, dar te simți la fel de dur precum două mii de maniaci vârâți -într-un singur ucigaș nebun. +într-un singur ucigaș dement. -N-ai de gând să cazi la pământ prea ușor.","Впереди слышен металлический скрежет -тяжёлых механизмов. Вы надеетесь, что они -не штампуют очередную партию -дьявольских отродий, но даже если -и так, Вы готовы устроить им побоище. +N-ai de gând să cazi la pământ prea ușor.","Впереди вы слышите грохот тяжёлых станков. +Вы очень надеетесь, что они не штампуют +новые исчадия ада, но готовы выносить их +пачками, если придётся. Может, они и +планируют устроить кровавый пир, но в вас +злобы как в двух сотнях маньяков, +упакованных в одного полоумного убийцу. -Эти звуки могут означать очередной -кровавый фестиваль, но Вы чувствуете -себя как тысячи головорезов, -собранных в одном безумном убийце. - -Вы так просто не сдадитесь.","Чујете брушење тешке машинерије +Умирать без боя вы не намерены.","Чујете брушење тешке машинерије напред. Надате се да не штампају нове утваре, али сте спремни да покољете цело стадо ако требаш. Можда спремају @@ -3517,7 +4249,27 @@ N-ai de gând să cazi la pământ prea ușor.","Впереди слышен м спакована две хиљада манијака у једног побеснолог убицу. -Не планирате да паднете тако лако." +Не планирате да паднете тако лако.","Du hör slipandet av tunga maskiner i +huvudet. Du hoppas verkligen att de +inte stampar fram nya helvetesdjur, +men du är redo att slå ut en hel +hjord om du måste. +De kanske planerar en blodfest, men +du känner dig ungefär lika elak som +två tusen galningar packade i en +enda galen mördare. + +Du planerar inte att gå ner lätt.","İleride ağır makinelerin gıcırtılarını +duyuyorsunuz. Yeni iblisler +üretmediklerini umuyorsunuz ama +gerekirse bütün bir sürüyü ortadan +kaldırmaya hazırsınız. +Bir kan ziyafeti planlıyor olabilirler, +ama sen kendini iki bin manyağın +tek bir çılgın katilde toplanması +kadar kötü hissediyorsun. + +Kolayca ölmeyi planlamıyorsun." "The vista opening ahead looks real damn familiar. Smells familiar, too -- like fried excrement. You didn't like this @@ -3532,7 +4284,17 @@ se ti tu nelíbilo a rozhodně nemáš v plánu mít to tu rád teď. Čím déle nad tím uvažuješ, tím rozzuřenější se cítíš. Zvedaj@[tgs_pr1_cs] svou zbraň cítíš zlý škleb, vlévající se ti do tváře. -Je čas vyřídit si účty.","Der Blick voraus zeigt etwas sehr Vertrautes. +Je čas vyřídit si účty.","Udsigten, der åbner sig forude, ser +fandeme bekendt ud. Den lugter også +bekendt - som stegt ekskrementer. +Du kunne ikke lide det her sted før, +og du har helt sikkert ikke tænkt +dig at kunne lide det nu. Jo mere du +grubler over det, jo mere vred bliver du. + +Du løfter din pistol og får et ondt +grin på dit ansigt. +Tid til at rydde op.","Der Blick voraus zeigt etwas sehr Vertrautes. Und es riecht auch bekannt - wie verbrannte Exkremente. Dieser Ort hat die schon vorher nicht gefallen, und du wirst deine Meinung @@ -3541,14 +4303,14 @@ nachdenkst, desto wütender wirst du. Also du deine Waffe bereitmachst, überzieht ein böses Grinsen dein Gesicht. Zeit um aufzuräumen. -",,"La malfermo antaŭe aspektas tre diable -kutima. Ĝi ankaŭ odoras kutima, kiel -fritita fekon. Vi ne ŝatis tion placon +",,"La vidaĵo malfermante antaŭe aspektas tre +diable familiara. Ĝi ankaŭ odoras familiare, +kiel fritita fekon. Vi ne ŝatis tiun placon antaŭe, kaj vi diable certe ne planos nun -ŝati ĝin. Ju pli vi cerbumas, des vi fariĝas -pli kolera. Levante vian pafilon, malica -gimaco gutetas sur vian vizaĝon. -Tempas senrubigi.","El paisaje que tienes ante tus ojos te +ŝati ĝin. Ju pli vi cerbumas, des pli vi fariĝas +freneza. Levante vian pafilon, malica +grimaco gutetas sur vian vizaĝon. +Tempas por eltiri la rubon.","El paisaje que tienes ante tus ojos te resulta demasiado familiar. Incluso el olor se hace conocido... Como a excremento frito. No te gustó este @@ -3576,14 +4338,12 @@ Plus vous pensiez a cette idée, plus vous sombrez dans la folie. Saisissant votre arme, un sourire maléfique apparait sur votre visage. -Il est l'heure de buter du démon....","Az a kilátás elől rohadtul ismerősnek látszik. -És a szaga is -- égetett ürülék. Nem szeretted ezt -a helyet előtte, és egyáltalán nem is fogod -tervezni azt. Sokáig gondolkodsz rajta, annál -dühősebb leszel. -Jól megfogod a fegyvered, egy gonosz mosoly -tántorog az arcodon. Itt az idő hogy csináljunk -néhány nevet.","Il panorama visibile sembra dannatamente +Il est l'heure de buter du démon....","Az előtted heverő kilátás rohadtul ismerősnek tűnik. +És a szaga is -- égetett ürülék. Eddig sem voltál oda a helyért, +de immáron kifejezetten gyűlölöd. Minél jobban agyalsz rajta, +annál jobban felborzolja az idegeidet. +Ahogy előveszed a fegyvered, egy gonosz mosoly ül ki az arcodra. +Ideje, hogy megmutasd nekik ki az úr.","Il panorama visibile sembra dannatamente familiare. Ha pure un puzzo familiare, da escrementi fritti. Non ti piaceva questo posto prima e non pensi di fartelo piace- @@ -3591,7 +4351,7 @@ re proprio adesso. Più ci pensi e più diventi nervoso. Soppesando l'arma, un sorriso maligno si fa strada sul tuo volto. -è ora di prendere un pò di nomi.","前方に開けている景色は見飽きたものだ。 +È ora di fargliela vedere.","前方に開けている景色は見飽きたものだ。 臭いもよく知っている -- 煮えた排泄物のようなヤツ。 この場所は気に入らないし、気に入る予定もない。 考えれば考える程、気が滅入る。 @@ -3614,13 +4374,23 @@ hoe booser je wordt. Dus je bereidt je wapen voor, een slechte grijns bedekt je gezicht. Tijd om op te ruimen. -","Widok rozpościerający się przed tobą +","Utsikten som åpner seg foran +oss ser veldig kjent ut. Lukter +kjent også - som stekt +ekskrementer. Du likte ikke dette +stedet før, og du kommer ikke +til å like det nå heller. Jo mer +du grubler på det, jo sintere +blir du. +Når du hever pistolen din, +får du et ondt glis i ansiktet. +På tide å ta noen navn.","Widok rozpościerający się przed tobą wygląda cholernie znajomo. Zapach też -znajomy -- jak przepalone odchody. Wtedy -nie lubiłeś tego miejsca i jesteś pewien jak -diabli, że teraz też go nie polubisz. Im dalej -brodzisz, tym bardziej się wściekasz. Trzymając -swoją broń, zły uśmiech gości na twojej twarzy. +znajomy - jakby przepalone odchody. Już wtedy +nie lubiłeś tego miejsca i masz pewność, że teraz +też go nie polubisz. Im dalej brodzisz, tym bardziej się +wściekasz. Podnosisz swoją broń, a na twej twarzy +pojawia się upiorny uśmiech. Czas zabić parę demonów. ","A paisagem que se revela a sua frente parece muito familiar. Assim como o cheiro -- lembra @@ -3634,22 +4404,18 @@ uns demônios.",,"Peisajul care se întinde deasupra propriilor tăi ochi arată al naibii de familiar. Miroase și cunoscut -- asemeni excrementului prăjit. Nu ți-a plăcut locul acesta nici înainte, și în mod categoric nu -intenționezi să ajungi să îți placă acum. +intenționezi să ajungi să îți placă nici acum. Cu cât clocește mai mult, cu atât mai nervos devii. Scuturând arma, un rânjet malefic îți gâdilă fața. -Timpul să notezi niște nume.","Открывающийся вид выглядит -чертовски знакомым и пахнет, -словно зажаренные экскременты. -Это место не нравилось Вам раньше, -и Вы чертовски уверены, что не -понравится и сейчас. Чем больше Вы -размышляете над этим, тем больше Вас -охватывает ярость. - -Взвесив своё оружие, Вы зловеще -ухмыляетесь. Настало время всерьёз -надрать кое-кому задницу.","Видик који се напред отвара изгледа +Timpul să notezi niște nume.","Открывшийся вашему взору пейзаж выглядит +чертовски знакомо. И знакомо пахнет — +словно жареные экскременты. Вы не любили +это местечко раньше и чёрта с два полюбите +теперь. Чем больше вы о нём думаете, тем +злее становитесь. Вскинув ружьё, вы +сверкаете недоброй ухмылкой. Пора задать +жару.","Видик који се напред отвара изгледа стварно познато. Чак и мирише познато... као похован измет. Није вам се свиђало ово место пре, и сто посто @@ -3657,7 +4423,22 @@ Timpul să notezi niște nume.","Открывающийся вид выгляд Што више зиљите у њега, то више сте љути. Подижући своју пишку, зао кез се оформио на вашем лицу. -Време је за убијање." +Време је за убијање.","Utsikten som öppnar sig framför oss +ser jävligt bekant ut. Den luktar också +bekant - som stekt avföring. Du +gillade inte det här stället förut, och +du planerar inte att gilla det nu. Ju +mer du grubblar på det, desto +argare blir du. +Du lyfter din pistol och får ett +ondskefullt flin i ansiktet. +Dags att ta några namn.","İleride açılan manzara gerçekten +çok tanıdık geliyor. Kokusu da +tanıdık, kızarmış dışkı gibi. Bundan +hoşlanmayacağın kesin. Düşündükçe +daha da sinirleniyorsun. +Silahını çekerken yüzünde şeytani bir +sırıtma beliriyor. Biraz hareket zamanı." "Suddenly, all is silent, from one horizon to the other. The agonizing echo of Hell fades away, the nightmare sky turns to @@ -3679,7 +4460,17 @@ Opravdu jsi vyhrál@[ao_cs]? V dáli něco zahřmí. Z rozborcené lebky plivače démonů začíná zářit -jakési modré světlo...","Plötzlich ist alles still, von einem Horizont +jakési modré světlo...","Pludselig er alt stille, fra den ene +horisont til den anden. Helvedes +kvalfulde ekko forsvinder, mareridtshimlen +bliver blå, bunkerne af monsterkadavere +begynder at fordampe sammen med den onde +stank, der fyldte luften. Jøsses, måske +har du gjort det. Har du virkelig vundet? + +Noget rumler i det fjerne. +Et blåt lys begynder at gløde inde i +dæmonspytterens ødelagte kranie.","Plötzlich ist alles still, von einem Horizont zum anderen. Das quälende Echo der Hölle verblasst, der Albtraumhimmel wird wieder blau, der Haufen Monsterleichen beginnt sich @@ -3690,16 +4481,16 @@ gewonnen? In der Ferne rumpelt etwas. Ein blaues Licht beginnt im Inneren -des Schädels zu leuchten.",,"Ĉio subite silentas de unu horizonto ĝis -la alia. La agoniantaj eĥoj de La Infero +des Schädels zu leuchten.",,"Subite, ĉio silentas, de unu horizonto al +la alia. La agonianta eĥo de Infero malaperas, la inkub-ĉielo fariĝas blua, -la amaso de monstro-kadavroj ekas -vaporiĝi kun la mava odoro, kiu plenigis -la aeron. Ho, eble vi finis. -Ĉu vi vere sukcesis? +la amaso da monstro-kadavroj komencas +vaporiĝi kune kun la mava odoro, kiu +plenigis la aeron. Ho, eble vi sukcesis. +Ĉu vi vere gajnis? Io vibrosonas malproksime. Blua lumo -ekas brili en la ruiniga kranio de la +komencas brili en la ruinigita kranio de la demonsputisto. ","De repente, todo está en silencio, de un horizonte hasta el otro. El agonizante @@ -3735,16 +4526,15 @@ Avez vous réellement gagné? Quelque chose gronde au loin. une lumière bleue a commence a luire dans le crâne défoncé du cracheur -de démons.","Hirtelen, minden néma lett, az egyik horizontból -a másikra. A kínzó Pokoli visszhang fokozatosan -elhalkul, a rémálom ég kékké válik, a szörnyeknek -a hullái elpárolog a gonosz bűzzel együtt ami a -levegőben volt. Végre, talán megcsináltad. -Biztos hogy győztél? - -Valami rezeg a távolban. -Egy kék fény kezd izzítani egy démon -romos koponyájában.","Improvvisamente tutto si fa silenzioso, da +de démons.","Hirtelen minden elcsendesül amerra a szem ellát. +A pokol kínzó visszahangja immáron a múlté, +a rémálomszerű égbolt kékre változik, a halmokba +mészárolt démon hullák kezdenek elpárologni a terjengő bűzzel együtt. +Úristen, talán mégis sikerült. Tényleg győztél? + +Valami dörgést hallasz a távolban. +Egy kék fény kezd világítani a legyőzött démon-köpő +koponyájának romjai közül.","Improvvisamente tutto si fa silenzioso, da un orizzonte all'altro. L'agonizzante eco dell'inferno svanisce, il cielo da incubo diventa blu, le pile dei cadaveri dei @@ -3780,16 +4570,30 @@ Iets rommelt in de verte. Een blauw licht begint te schijnen in de geruïneerde schede van de demonenspuwer. -","Nagle następuje cisza, aż po horyzont. -Agonalne echo Piekieł zanika, koszmarne niebo -znów staje się niebieskie, hałdy ciał potworów -zaczynają się ulatniać razem ze złym smrodem, -który wypełniał powietrze. Jezu... może ci się -udało. Czy na pewno wygrałeś? +","Plutselig er alt stille, fra den +ene horisonten til den andre. +Det pinefulle ekkoet av helvete +forsvinner, mareritthimmelen +blir blå, haugene med monsterlik +begynner å fordampe sammen +med den onde stanken som +fylte luften. Jøss, kanskje du +har gjort det. Har du virkelig +vunnet? + +Noe buldrer i det fjerne. +Et blått lys begynner å gløde +inne i den ødelagte hodeskallen +til demonspytteren.","Nagle następuje cisza, jak makiem zasiał. +Agonalne jęki Piekieł zanikają, a koszmarne niebo +znów staje się niebieskie. Hałdy ciał potworów +zaczynają się ulatniać razem z całym tym smrodem, +który wypełniał powietrze. Jezu... czyżby ci się udało? +Czy na pewno wygrałeś? Coś łomocze w oddali. Niebieskie światło zaczyna świecić w środku zniszczonej czaszki -demonicznej plujki.","De repente, tudo fica quieto, de um horizonte +demonicznej maszkary.","De repente, tudo fica quieto, de um horizonte ao outro. O eco agonizante do Inferno se cala aos poucos, o céu que parece sair de pesadelos vai ficando azul, as pilhas de corpos dos monstros @@ -3808,16 +4612,17 @@ chiar să fii triumfat? Ceva vuiește în depărtare. O lumină albastră începe să strălucească în craniul zdrobit al scupătorului -de demoni.","Внезапно всё окуталось тишиной до -самого горизонта. Мучительное эхо Ада -стихло, кошмарное небо стало вновь -голубым, трупы монстров начали -испаряться вместе со своим зловонным смрадом. -Боже, неужели Вы и правда победили? - -Вдалеке, что-то грохочет. Из разгромленного -черепа Изрыгателя Демонов начинает -пробиваться яркое синее свечение.","Изненада, све је тихо, од једног +de demoni.","Внезапно всё умолкает, с одного края +горизонта до другого. Агонизирующее эхо +ада стихает, кошмарный небосвод вновь +синеет, горы трупов чудовищ начинают +испаряться вместе с витавшим в воздухе +зловонием. Блин, а вдруг у вас и правда +получилось. Вы что, реально победили? + +Что-то грохочет вдали. В изломанном черепе +демона-извергателя начинает сверкать синий +огонёк.","Изненада, све је тихо, од једног хоризонта до другог. Очајнички ехо пакла нестаје, небо ноћне море постаје плаво, гомиле леша чудовишта @@ -3828,30 +4633,56 @@ de demoni.","Внезапно всё окуталось тишиной до Нешто тутњи у даљини. Плава светлост почиње да светли унутар -уништене лобање избацивача демона." +уништене лобање избацивача демона.","Plötsligt är allt tyst, från den ena +horisonten till den andra. Helvetets +plågsamma eko bleknar bort, +mardrömshimlen blir blå, högarna av +monsterkadaver börjar avdunsta +tillsammans med den onda stanken +som fyllde luften. Jösses, du kanske +har gjort det. Har du verkligen vunnit? + +Något mullrar i fjärran. +Ett blått ljus börjar glöda inuti +demonspridarens förstörda skalle.","Birdenbire, bir ufuktan diğerine her şey +sessizleşir. Cehennemin acı veren +yankısı kaybolur. Kabus gökyüzü +maviye döner. Canavar ceset yığınları, +havayı dolduran kötü kokuyla birlikte +buharlaşmaya başlar. Tanrım, belki +de başardın. Gerçekten kazandın mı? + +Uzaktan bir şey gürlüyor. +İblis-yaratığın yıkık kafatasının +içinde mavi bir ışık parlamaya başlar." "What now? Looks totally different. Kind of like King Tut's condo. Well, whatever's here can't be any worse than usual. Can it? Or maybe it's best to let sleeping gods lie..",T5TEXT,TNT before MAP31,,,"A co teď? Tohle vypadá úplně jinak. -Trochu jako sídlo krále Tuta. +Trochu jako sídlo krále Tutanchamona. Ať už je tu cokoliv, nemůže to být horší než obvykle. Nebo může? Možná -je lepší nechat spící bohy odpočívat.","Was jetzt? Sieht ganz anders aus. Fast +je lepší nechat spící bohy odpočívat.","Hvad nu? Det ser helt anderledes ud. +Lidt ligesom King Tut's lejlighed. +Hvad end der er her, kan det ikke +være værre end normalt. Kan det? +Eller måske er det bedst at +lade sovende guder ligge...","Was jetzt? Sieht ganz anders aus. Fast wie die Wohnung von König Tut. Gut, was auch immer hier ist, kann nicht schlimmer sein als, was du bisher erlebt hast. Oder kann es? Oder vielleicht ist es besser, die -schlafenden Götter ruhen zu lassen ..",,"Nun kio? Aspektas tute malsama, iom -kiel la leĝejo de Reĝo Tut. Nu, Kio ajn, -kio estas ĉi tie ne povas esti pli malbona -ol la kutima, ĉu ne? Aŭ eble bonas +schlafenden Götter ruhen zu lassen ..",,"Nun kio? Aspektas tute malsame, iom +kiel la loĝejo de Reĝo Tut. Nu, kio ajn +estas ĉi tie ne povas esti pli malbona +ol kutime, ĉu ne? Aŭ eble plibonas lasi dormantajn diojn kuŝi...","¿Y ahora qué? Esto se ve totalmente diferente. Se parece a la choza del rey Tut. Bueno, sea lo que sea no puede ser peor que los sitios -usuales. ¿O sí? O tal vez sería mejor +usuales. ¿O quizás sí? O tal vez sería mejor dejar dormir a los dioses que permanecen ahí...",,"Mitä nyt? Näyttää täysin erilaiselta. Vähän niin kuin Tutankhamonin lukaalilta. @@ -3866,9 +4697,9 @@ Bon, rien ne peut être pire que d'habitude. N'est-ce pas? Ou peut être est-ce mieux de laisser dormir les dieux.. -","Most mi lesz? Nagyon másnak tűnik. Olyan mint -Tutanhamon Király kongója. Legalább, bármi -ami itt tartozkodik csak nem lehet rosszabb +","Most mi lesz? Teljesen megváltozott. Olyan mint +Tutanhamon Király lakosztálya. Legalább, bármi +ami itt tartózkodik csak nem lehet rosszabb a szokásosnál. Vagy mégis? Vagy talán az a legjobb ha hagyjuk hogy a fekvő istenek aludjanak..","E ora? Tutto sembra differente. Tipo dimora del faraone Tutankamon. Bè, @@ -3886,31 +4717,45 @@ non disturbare le divinità dormienti...","今度は何だ? 何もかも別物 zoals het appartement van Koning Tut. Nou, wat hier ook is, het kan niet erger zijn dan normaal. Kan dat? Of misschien is het het beste om -slapende goden te laten liggen… -","Co teraz? Wygląda całkiem inaczej. Trochę +slapende goden te laten liggen...","Hva skjer nå? Ser helt +annerledes ut. Litt som kong +Tuts leilighet. Det som er her, +kan ikke være verre enn vanlig. +Kan det vel? +Eller kanskje det er best å la +sovende guder ligge...","Co teraz? Wygląda całkiem inaczej. Trochę jak mieszkanie Tutanchamona. Cóż... Cokolwiek tu jest, nie może być gorzej niż zazwyczaj. Prawda? A może lepiej dać spokój pogrążonym we śnie bogom...","O que foi desta vez? Parece algo totalmente -diferente. Tipo o apartamento do Rei Tutancâmon. +diferente. Algo como o apê do Rei Tutancâmon. Bom, seja lá o que tiver aqui não deve ser pior que o normal. Ou pode? Ou talvez seja melhor não perturbar os deuses...",,"Acum ce mai e? Arată total diferit. Asemănător oarecum cu casa Regelui Tut. Păi, orice ar fi aici n-are cum să fie mai rău ca de obicei. Sau poate ar -fi cel mai bine să lași zeii adormiți să zacă ...","И что теперь? Всё выглядит совершенно -по-другому, словно покои владыки -Тутанхамона. - -Что ж, что бы не ожидало Вас внутри, -хуже уже быть не может, правда ведь? -Или может лучше не тревожить -спящих богов...","Шта сад? Изгледа тотално другачије. +fi cel mai bine să lași zeii adormiți să zacă...","Ну что теперь? Здесь всё выглядит совсем +по-другому. Смахивает на дачу царя +Тутанхамона. Ну, что бы тут ни было, вряд +ли оно будет хуже обычного. Так ведь? Или, +быть может, лучше всё же не будить +дремлющих богов…","Шта сад? Изгледа тотално другачије. Као краљ Тутова рупчага. Па штагод овде било не може бити горе од убичајеног. Или може? Или је можда најбоље да се допусти да успавани -богови леже..." +богови леже...","Vad händer nu? +Det ser helt annorlunda ut. +Ungefär som King Tut's lägenhet. +Det som finns här kan inte vara +värre än vanligt. Eller hur? +Eller så är det kanske bäst att låta +sovande gudar ligga...","Şimdi ne oldu? Tamamen farklı +görünüyor. Kral Tut'un evi gibi. +Burada her ne varsa normalden +daha kötü olamaz. Değil mi? +Belki de en iyisi uyuyan tanrıların +dinlenmesine izin vermektir." "Time for a vacation. You've burst the bowels of hell and by golly you're ready for a break. You mutter to yourself, @@ -3929,7 +4774,16 @@ hladinami vod, malebnými budovami a, podle všeho, bez žádných splozenců pekelných. Vystoupiv@[tgs_past_cs] z transportu, slyšíš -rachot kyberdémonovy železné podkovy.","Zeit für einen Urlaub. Du hast die +rachot kyberdémonovy železné podkovy.","Det er tid til en ferie. Du har sprængt +helvedes indvolde, og du er klar til at +tage en pause. Du mumler for dig selv, at +måske kan en anden give Helvede røvfuld +næste gang. Forude ligger en stille by +med fredeligt rindende vand, maleriske +bygninger og formentlig ingen dæmoner. + +Da du træder ud af transporten, hører +du en cyberdæmons jernsko trampe.","Zeit für einen Urlaub. Du hast die Eingeweide der Hölle platzen lassen und verdammt, du hast dir eine Pause verdient. Du murmelst zu dir selbst, vielleicht sollte @@ -3940,21 +4794,21 @@ einfachen Gebäuden, und hoffentlich keinen Höllenkreaturen. Als du den Transporter verlässt, hörst du -das Stampfen eines Cyberdämonen.",,"Tempas ferio. Vi kreviĝis la internaĵojn -de La Infero, kaj ve, vi estas preta paŭzi. -Vi murmuras al vin, ke iu alia eble pubatos -La Inferon venonfoje. Antaŭas silenta -urbeto kun trankvila flua akvo, bonstrangaj -arĥitekturo, kaj supozeble, nenioj inferidoj. - -Dum vi paŝas for la veturilo, vi aŭdas la -laŭtan paŝon de la ŝuo de ciborgdemono.","Hora de tomarse unas vacaciones. +das Stampfen eines Cyberdämonen.",,"Tempas ferio. Vi kreviĝis la internaĵoj +de Infero, kaj ve, vi estas preta paŭzi. +Vi murmuras al vi mem, ke iu alia eble +pugbatos Inferon venontfoje. Antaŭe kuŝas +kvieta urbeto, kun trankvila flua akvo, kuriozaj +konstruaĵoj, kaj supozeble, neniuj inferidoj. + +Dum vi eliras el la veturilo, vi aŭdas la +laŭtan paŝon de fera ŝuo de ciberdemono.","Hora de tomarse unas vacaciones. Arrasaste con las entrañas del Infierno y por Dios que estás list@[ao_esp] para un descanso. Murmuras a tí mism@[ao_esp], tal vez alguien más debería ir a -patear traseros infernales la próxima +patear culos infernales la próxima vez. Más adelante se encuentra un pueblo tranquilo, con agua tranquila, construcciones pintorescas, y @@ -3989,12 +4843,12 @@ de l'enfer. Quand vous descendez du transport, vous entendez le bruit du sabot d'acier -d'un Cyberdémon.","Itt az idő a vakációra. Felrobbantottad a Pokol -beleit, és a kutyafáját, megérdemled a pihenést! +d'un Cyberdémon.","Itt az idő a vakációra. Szétrepesztetted a Pokol +beleit, és a fenébe is, megérdemled a pihenést! Magadhoz motyogsz, -Talán valaki más seggberúghatná a Pokol valagát -legközelebb. Elől egy csendes város tartozkodik, -békés áramló vizzel, furcsa épületekkel, és +Talán legközelebb valaki más rúghatná seggbe a Pokol valagát. +Elől egy csendes város rajzolódik ki, +békésen csobogó vízzel, furcsa épületekkel, és --talán-- szörnyek nélkül. Ahogy kiszállsz a járműből, hallod egy @@ -4030,17 +4884,23 @@ gebouwen en waarschijnlijk geen Hellbrood. Als je uit het transport stapt, hoor je het stampen van de ijzeren schoen van een cyberdemon. -","Czas na wakacje. Przedzierasz się przez trzewia -piekieł i jesteś już kurczę gotowy na przerwę. +","På tide med ferie. Du har sprengt +helvetes innvoller, og du er klar +for en pause. Du mumler for +degselv: Kanskje noen andre +kan sparke helvete i ræva neste +gang. Foran deg ligger en rolig by, +med fredelig rennende vann, +sjarmerende bygninger og +antagelig ingen helvetesyngel.","Czas na wakacje. Przedzierasz się przez trzewia +piekieł i chciałbyś w końcu zrobić sobie przerwę. Mruczysz do siebie, może ktoś inny mógłby -następnym razem skopać Piekłu tyłek. Przed -tobą leży ciche miasteczko ze spokojną -falującą wodą, osobliwymi budowlami -i prawdopodobnie bez jakiegokolwiek -diabelstwa. - -Schodząc ze swojej podwózki słyszysz tupnięcie -żelaznej nogi cyberdemona.","Hora de tirar umas férias. Você arrebenta as +teraz skopać Piekłu tyłek. +Przed tobą leży ciche nadmorskie miasteczko +pełne pięknych budowli, i miejmy nadzieję, że bez +jakiegokolwiek diabelstwa. + +Nagle słyszysz tupnięcie żelaznej nogi cyberdemona.","Hora de tirar umas férias. Você arrebenta as tripas do inferno e com certeza está precisando de um descanso. Você resmunga para si mesm@[ao_ptb], bem que outra pessoa poderia dar um jeito @@ -4048,29 +4908,27 @@ no Inferno da próxima vez. Mais adiante há uma cidadezinha sossegada, com um riacho tranquilo, casinhas pacatas e, a princípio, sem demônios. -Ao sair do teletransportador, você ouve as -pisoteadas da pata de ferro de um ciberdemônio.",,"Timpul pentru o vacanță. Ai sfărâmat intestinele +Ao desembarcar, você ouve as pisoteadas +da pata de ferro de um ciberdemônio.",,"Timpul pentru o vacanță. Ai sfărâmat intestinele infernului și vai, în sfărșit ești pregătit să iei o pauză. Murmuri în sine, poate ar putea și altcineva să trimită Infernul la plimbare data viitoare. -În față e un oras liniștit, cu ape curgătoare liniștite, -si cel mai probabil fără creaturi infernale. +În față e un oras tăcut, cu ape curgătoare line, și +cel mai probabil fără creaturi infernale. În timp ce pășești în afara transportului, auzi pașii -grei ai pantofilor de fier ai ciberdemonului.","Пришло время для отпуска. Ей-богу, -вороша недра Ада, Вы только о нём -и мечтали! Пусть кто-нибудь другой -теперь борется с полчищами демонов. - -Впереди располагается тихий городок с -неспешно текущей водой, причудливыми -домиками, и, вероятно, не населённый -адским отродьем. - -Покинув транспортное средство, -Вы слышите топот железного копыта -кибердемона.","Време је за одмор. Уништили сте утробу +grei ai pantofilor de fier ai ciberdemonului.","Пора устроить отпуск. Вы разорвали нутро +преисподней, и отдых вам нужен до чёртиков. +«Пускай кто-нибудь другой надирает ей +зад в следующий раз», бормочете вы себе +под нос. Перед вами раскинулся тихий +городок, с безмятежной речкой, приятными +старинными домиками и, предположительно, +без адских отродий. + +Едва сойдя с транспорта, вы слышите топот +железных копыт кибердемона.","Време је за одмор. Уништили сте утробу пакла и заслужено сте спремни за одмор. Промумљате сами себи. Можда неко други може да растури тур паклу @@ -4079,7 +4937,29 @@ grei ai pantofilor de fier ai ciberdemonului.","Пришло время для зградама, и вероватно нема демона. Корачате ван својег транспорта, и чујете -удар челичног копита сајбердемона." +удар челичног копита сајбердемона.","Dags för semester. Du har sprängt +helvetets inälvor och du är redo för +en paus. Du mumlar för dig själv, +Kanske någon annan kan spöa +helvetet nästa gång. Framför dig +ligger en lugn stad, med fridfullt +rinnande vatten, pittoreska byggnader +och förmodligen inga Hellspawn. + +När du kliver av transporten hör du +stampandet av en cyberdemons +järnsko.","Tatil zamanı. Cehennemin +bağırsaklarını patlattınız ve bir mola +için hazırsınız. Belki bir dahaki +sefere başka biri Cehennem'in kıçını +tekmeleyebilir. Önünüzde huzurlu +akan suları, şirin binaları olan ve +muhtemelen iblislerin olmadığı +sakin bir kasaba uzanıyor. + +Taşıttan indiğinizde, bir siber +iblisin demir ayakkabısının +sesini duyuyorsunuz." "Trouble was brewing again in your favorite vacation spot... Hell. Some Cyberdemon punk thought he could turn Hell into a @@ -4118,7 +4998,7 @@ This ride is closed. ","V tvém oblíbeném resortu zase bujely problémy... v pekle. Nějaký neposedný -kyberdémon si mylel, že si peklo změní +kyberdémon si myslel, že si peklo změní ve vlastní zábavní park a ze Země si udělá vrátnici. @@ -4132,7 +5012,24 @@ končetin, padajících na zem. Jeho smrtelné zurčení klokotá z toho, co tvým dočiněním kdysi bývala jeho tvář. -Tahle jízda skončila.","Und wieder mal gab es Ärger an deinem +Tahle jízda skončila.","Der var igen ballade på vej i dit +yndlingsferieområde... Helvede. En eller +anden cyberdemon troede, at han kunne +forvandle Helvede til en personlig +forlystelsespark og gøre Jorden til +billetluge. + +Nå, men den halv-robot freak show vidste +ikke hvem der kom til tivoli. Der er intet +som en skydebane fuld af dæmoner til at +få blodet til at pumpe... + +Nu ekkoede væggene i dæmonens labyrint med +lyden af hans metalliske lemmer, der ramte +gulvet. Hans dødsstøn gisper ud gennem det +rod, du har efterladt af hans ansigt. + +Denne tur er lukket.","Und wieder mal gab es Ärger an deinem liebsten Urlaubsort... der Hölle. Irgend so ein Cyberdämonen-Punk glaubte doch tat- sächlich, er könnte die Hölle in seinen @@ -4152,35 +5049,35 @@ Sein Stöhnen tönt durch das Chaos, das du hier hinterlassen hast. Der Jahrmarkt ist geschlossen. -",,"Problemoj bolis en via favorata feriejo... -Diable. Kelka ciborgdemono huligano -pensis, ke li povis fari personan amuzejon -el La Infero, kaj fari La Teron -wn la biletvendejon. +",,"Problemoj estis kreskinta denove en via ŝatata +feriejo... Infero. Iu ciberdemono-huligano +pensis, ke li povis farigi Inferon en +personan amuzparkon, kaj farigi la Teron +la biletejo. -Nu, tiu duon-robota grotekulo ne sciis tiun, -kiu estis venonta al la foiro. Nenio estas -pli bona ol pafejo plena da inferidoj por -fari sangon pumpata... +Nu, tiu duon-robota groteskulo ne sciis, +kiu estis venanta al la foiro. Estas nenio +pli bona ol pafejo plena de inferidoj por +fari la sangon pumpata... Nun la muroj de la labirinto de la demono -resonas la sonon de liaj metalaj membroj -trafantaj la plankon. Lia mortĝemo gluglas +resonas kun la sono de liaj metalaj membroj +trafantaj la plankon. Lia mortoĝemo gluglas tra la kaĉo, kiun vi faris el lia vizaĝo. -Ĉi tiu rajdo estas fermita.","Otra vez se avecinan problemas en +Ĉi tiu atrakcio estas fermita.","Otra vez se avecinan problemas en tu lugar de vacaciones favorito... -El infierno. A un bruto ciberdemonio -se le ocurrió convertir el infierno -en su parque de diversiones -personal, y hacer a la Tierra la -taquilla de entradas. +El Infierno. Algún ciberdemonio mocoso +pensó que podría convertir el Infierno +en su parque de atracciones +personal, y hacer de la Tierra la +taquilla. Bien, ese fenómeno de circo -mitad-robot no sabía quien vendría a +medio-robot no sabía quien vendría a la feria. No hay nada como una galería de tiro repleta de engendros -provenientes del infierno para ver +del averno para ver correr sangre a borbotones... Ahora las paredes del laberinto @@ -4191,7 +5088,7 @@ salen a duras penas por la mezcla de cables y carne que solía ser su rostro. -Esta atracción se ha cerrado. +Esta atracción está cerrada. ","Otra vez se avecinan problemas en tu lugar de vacaciones favorito... Demonios. A un ciberdemonio @@ -4249,23 +5146,20 @@ gémissements d'agonie se déversent de son visage que vous avez laissé en charpie. Le manège est fermé! -","Megint csak a baj történik a kedvenc vakáció -helyeden... Pokol. Néhány Kiborgdémon -fajankó jónak hitte hogy áttudják változtatni a -Pokolt személyes vidámparkká, és a Föld lesz a -jegyfülke. +","Megint csak a baj van a kedvenc vakáció +helyeddel...a Pokollal. Valami Kiborgdémon +tapló azt hitte, hogy a Poklot átalakíthatja a személyes +vidámparkjává, és a Föld lesz a jegyszedő fülke. -Hát, ez a félig-robot szörnyszülött nem tudta -hogy kijön ide. Nincs annál jobb mint amikor -szétlősz néhány szörnyet csak hogy felmenjen -a vérben a pumpa... +Nos, ez a félig-robot szörnyszülött nem tudta +hogy kivel számol a vásárban. Nincs annál jobb, mint +amikor céllövöldét játszol a démonfajzatokkal, és +érzed a vér pumpálását a testedben. -Most a démon labirintus falai visszhangoznak -az acél végtagjai miatt ahogy leér a földre. -A halál nyögése kicsörgedezik azon a -rendetlenségen amit hagytál az arcán. +A démon labirintusának falai visszhangzanak a +fém paták dobogásától. Halálnyögése feltör a szétzilált szájából. -Ez a menet zárva van.","C'era di nuovo odore di guai nella tua meta di vacanze preferita... L'inferno. Questo teppista di un cyberdemonio pensava di poter fare dell'inferno il proprio parco giochi personale. E rendere la terra la bancarella dei biglietti di ingresso. +Démonunk parkja immáron bezár.","C'era di nuovo odore di guai nella tua meta di vacanze preferita... L'inferno. Questo teppista di un cyberdemonio pensava di poter fare dell'inferno il proprio parco giochi personale. E rendere la terra la bancarella dei biglietti di ingresso. Beh, quel fenomeno mezzo-robot non sapeva chi sarebbe venuto alla festa. Non c'è niente di meglio di un po' di tiro a segno con della prole Infernale per sentire il sangue pompare nelle vene... @@ -4310,21 +5204,40 @@ de rotzooi die je nog van zijn gezicht hebt achtergelaten. Deze rit is gesloten. -","Zanosiło się znów na kłopoty w twoim -ulubionym miejscu do wypoczynku... Piekle. +","Det brygget opp til trøbbel igjen på +favorittferiestedet ditt... Helvete. +En Cyberdemon-punk trodde han +kunne gjøre helvete til en personlig +fornøyelsespark og gjøre jorden +til billettluken. + +Den halvrobot-freakshowet visste +ikke hvem som kom til tivoliet. +Det er ingenting som en +skytebane full av helvetesyngel +for å få blodet til å pumpe... + +Nå runger veggene i demonens +labyrint av lyden av hans +metalliske lemmer som treffer +gulvet. Dødsstønnet hans gurgler +ut gjennom rotet du etterlot avansiktet hans. + +Denne turen er stengt.","Zanosiło się znów na kłopoty w twoim +ulubionym kurorcie... Piekle. Jakiś dupek Cyberdemon myślał, że może zmienić Piekło w swój osobisty park rozrywki i przerobić Ziemię na budkę z biletami. Coż... ta wpół robotyczna pokraka nie wiedziała kto się zbiliża na festyn. -Nie ma to jak strzelnica pełna diabelstwa by +Nie ma to jak strzelnica pełna diabelstwa, by pobudzić krew w żyłach... -Teraz ściany labiryntu tego demona odbijają -dźwięk jego metalowych kończyn upadających -na ziemię. Jego jęk rozdziera się pośród -bałaganu, który mu zostawiłeś na twarzy. +Pośród ścian labiryntu słychać echo +upadających metalowych kończyn demona. +Wydobywa on swój ostatni jęk, z czegoś +co kiedyś było jego twarzą. Ta przejażdżka jest zamknięta.","Mais uma vez estava começando a dar encrenca no seu local de descanso @@ -4351,7 +5264,7 @@ propriul parc de distracție, și să facă Pământul chioșc de bilete. Ei, acea urâțenie de jumătate de robot nu a realizat -cine urma să se alăture. Nimic nu e mai bun decât +cine urma să li se alăture. Nimic nu e mai bun decât un poligon plin cu creaturi infernale pentru a pune sângele în mișcare... @@ -4360,22 +5273,26 @@ zgomotul membrelor metalice ale matahalei care se prăbușesc la pământ. Ultimul său geamăt gâlgâie prin dezastrul pe care l-ai lăsat pe fața lui. -Călătoria s-a încheiat.","Ваше любимое место отдыха, казалось, вновь -настигли неприятности... Какой-то чёртов -кибердемон решил, что может превратить Ад -в свой собственный парк развлечений, -а Землю сделать билетной кассой. - -Вот только этот полумеханический урод не знал, -кто придет развлекаться! Нет ничего лучше тира -с отродьями Ада, чтобы разогнать кровь в жилах. - -Теперь же, от стен лабиринта демона раздается -лязг его металлических конечностей. Его -последний стон булькает из того, -что осталось от его лица. - -Этот аттракцион закрыт.","Опет се кувала невоља на вашем +Călătoria s-a încheiat.","Очередная заварушка наметилась в вашем +любимом месте отдыха... Тьфу ты. +Какой-то сопляк-кибердемон решил, что +может превратить ад в свой личный парк +аттракционов, а Землю сделать билетным +киоском. + +Ну, эта наполовину железная страхолюдина +не знала, кто придёт на праздник. Ничто +так не разгоняет кровь, как тир, полный +исчадий ада... + +Теперь в стенах бесовского лабиринта эхом +раздаётся звук его металлических +конечностей, с грохотом падающих на пол. +Его предсмертный стон с бульканьем исходит +из месива, в которое вы превратили его +рожу. + +Аттракцион закрыт.","Опет се кувала невоља на вашем омиљеном месту за одмор... Пакао. Неки сајбердемон је мислио да може да претвори пакао у луна парк, а земља @@ -4392,7 +5309,44 @@ Călătoria s-a încheiat.","Ваше любимое место отдыха, к посмртни јаук грогори из збрке од лице са којем сте га вам оставили. -Ова атракција је затворена." +Ова атракција је затворена.","""Det var återigen oroligt på din +favoritsemesterplats... Helvetet. +Någon Cyberdemon-punk trodde att +han kunde förvandla helvetet till en +personlig nöjespark och göra +jorden till biljettkassan. + +Tja, den där halvrobot-freakshowen +visste inte vem som skulle komma till +tivoli. Det finns inget bättre än en +skjutbana full av helvetesgödsel +för att få blodet att pumpa... + +Nu ekar väggarna i demonens labyrint +med ljudet av hans metalliska lemmar +som slår i golvet. Hans dödsstön gurglar +ut genom den röra du lämnade av hans +ansikte. + +Den här föreställningen är stängt.","En sevdiğin tatil yerinde yine sorun +çıkıyordu... Cehennem'de. Siber iblisin +teki Cehennem'i kişisel bir eğlence +parkına dönüştürebileceğini ve +Dünya'yı da bilet gişesi +yapabileceğini düşündü. + +O yarı robot ucube fuara kimin +geldiğini bilmiyordu. Kan pompalamak +için cehennem zebanileriyle dolu +bir atış poligonu gibisi yoktur... + +Şimdi iblisin labirentinin duvarları, +yere çarpan metalik uzuvlarının +sesiyle yankılanıyor. Ölüm iniltisi +yüzünde bıraktığın karmaşanın +içinden fışkırıyor. + +Bu yolculuk kapandı." "With the destruction of the Iron Liches and their minions, the last of the undead are cleared from this @@ -4425,7 +5379,24 @@ neprojde skrz, budeš muset zapečetit Pekelný chřtán z druhé strany. Samozřejmě by to mohlo znamenat, že navždy zůstaneš ve velmi nehostinném světě, ale nikdo -nikdy neřekl, že býti heretikem je snadné!","Mit der Vernichtung der Eisernen Leichen +nikdy neřekl, že býti heretikem je snadné!","Med udslettelsen af jernlicherne og deres +håndlangere er de sidste udøde blevet +fjernet fra dette eksistensplan. + +Disse skabninger måtte dog komme et eller +andet sted fra, og du har en lumsk +mistanke om, at den brændende portal i +Helvedes gab åbner sig mod deres +hjemlige dimension. + +For at sikre dig, at der ikke kommer +flere udøde (eller endnu værre ting) +igennem, skal du forsegle Helvedes gab +fra den anden side. Det betyder +selvfølgelig, at du kan komme til at sidde +fast i en meget uvenlig verden, men ingen +har nogensinde sagt, at det er let at +være kætter!","Mit der Vernichtung der Eisernen Leichen und ihrer Untergebenen hat der letzte Untote diese Existenzebene verlassen. @@ -4443,20 +5414,20 @@ dass in einer sehr unfreundlichen Welt festsitzen wirst, aber hat jemals jemand behauptet, dass das Leben eines Ketzers einfach ist?",,"Per la detruo de la ferliĉoj kaj iliaj -servistoj, la revivantaj ceteraj estas -foriga el ĉi tiu ebeno de ekzisto. +servistoj, la revivantoj ceteraj estas +forigaj el ĉi tiu ebeno de ekzisto. -Tamen, tiuj estuloj devis veni de ie, +Tamen, tiuj estuloj devis veni el ie, kaj vi suspektas, ke la pordego fajra -de la faŭko de infero kondukas en +de la faŭko de infero malfermas en ilian dimension hejman. -Por certi, ke pli revivantaj (aŭ eĉ pli -malbona aĵoj) ne travenos, vi bezonas +Por certigi, ke pli revivantoj (aŭ eĉ pli +malbonaj aĵoj) ne travenos, vi devos fermi la faŭkon de infero ĉe la flanko alia. -Nature, tio signifas, ke vi eble estos -kaptita en mondo tre malamika, sed -neniu diris, ke esti herezulo estas facila! +Kompreneble, tio signifas, ke vi eble estos +kaptita en mondo tre malamika, sed neniu +iam diris, ke esti herezulo estis facila! ","Con la destrucción de los Liches de Hierro y sus lacayos, los últimos no-muertos son limpiados de este plano @@ -4465,13 +5436,13 @@ de existencia. Sin embargo, esas criaturas debieron venir de alguna parte, y tienes la ligera sospecha de que el fiero portal -de las fauces del infierno se abre en +de las fauces del Infierno se abre en su propia dimensión. Para asegurarte de que más no-muertos (o cosas aún peores) no lleguen a través de él, tendrás que sellar las fauces del -infierno desde el otro lado. Esto +Infierno desde el otro lado. Esto significa por supuesto que podrías quedarte atrapad@[ao_esp] en un mundo muy desagradable, ¡pero nadie ha dicho @@ -4509,43 +5480,42 @@ Bien sûr cela veut dire que vous auriez pû rester coincé dans un monde très hostile, mais personne n'a jamais dit qu'être un hérétique -soit facile!","Az Ezüst Lich-ek és szolgálóik +soit facile!","Az Ezüst Félholtak és szolgái elpusztításával együtt az utolsó élőhalott is el lett törölve a létsík ezen szintjéről. -Ezeknek a teremtményeknek valahol át -kellett jönniük, és neked az a sanda +Ezeknek a teremtményeknek azonban valahonnan +jönniük kellett, és az a sanda gyanúd támadt hogy a pokol szájának -kénköves portálja az ő világuk felé nyílik. - -Annak érdekében hogy több élőhalott -(vagy mégrosszabb) nem jusson át, neked -el kell zárnod a pokol száját a -másik oldalról. Persze hogy -ez azt jelenti hogy valószínű -egy barátságtalan világban ragadsz - de ki mondta hogy ertneknek lenni könnyű?","con la distruzione degli iron lich +izzó portálja az ő világuk felé visz. + +Annak érdekében hogy ne tudjon több élőhalott +(vagy valami mégrosszabb) átjutni, +be kell rekesztened a pokol száját a túloldalról. +Ez persze azt jelenti, hogy valószínű +egy barátságtalan világban ragadhatsz +node ki mondta hogy ertneknek lenni könnyű?","Con la distruzione degli iron lich e dei loro servi, gli ultimi non- morti vengono rimossi da questo piano dell'esistenza. -quelle creature dovevano venire da +Quelle creature dovevano venire da qualche parte, pensi, e hai il sospetto che l'ardente portale delle fauci dell'inferno si apra sul loro posto di provenienza. -per assicurarti che altri non-morti +Per assicurarti che altri non-morti (o altro di peggio) non vi passino attraverso, devi sigillare la porta dell'inferno dall'altro lato. -certo, questo significa che rischi +Certo, questo significa che rischi di rimanere bloccato in un posto poco amichevole, ma chi ha detto che essere un eretico fosse facile!","アイアンリッチとその手下たちが滅ぼされたことにより、 アンデッドは一匹残らずこの世界から消滅した。 -この化物達は、別の場所から此処へ来る必要があったらしい、 +この怪物達は、別の場所から此処へ来る必要があったらしい、 故に、地獄の肚と呼ばれる燃え盛るポータルが 奴等の住処と繋がっているのではという不審感を覚えた。 @@ -4579,7 +5549,26 @@ komt te zitten in een zeer onvriendelijke wereld, maar niemand heeft ooit gezegd dat het gemakkelijk is om ketter te zijn! -","Ze zniszczeniem Żelaznych Liszy i ich sług, +","Med ødeleggelsen av Jernliches og +deres håndlangere, er de siste av de +udøde fjernet fra dette +eksistensnivået. + +Disse skapningene måtte imidlertid +komme fra et sted, og du har en +snikende mistanke om at den +brennende portalen til helvetes gap +åpner seg mot hjemdimensjonen +deres. + +For å sørge for at ikke flere levende +døde (eller enda verre ting) kommer +gjennom, må du forsegle helvetes gap +fra den andre siden. Dette betyr +selvfølgelig at du kan bli sittende fast i +en veldig uvennlig verden, men ingen +har noen gang sagt at det er lett å +være kjetter!","Ze zniszczeniem Żelaznych Liszy i ich sług, ostatni z umarłych zostali wyczyszczeni z tego świata. @@ -4609,7 +5598,7 @@ outro lado. Claro que isso significa que você pode ficar pres@[ao_ptb] num lugar nada amigável, mas ninguém jamais disse que ser herége era fácil.",,"Odată cu distrugerea Cadavrelor de Fier și ai -minionilor lor, ultimii nemorți dispar din acest +minionilor, ultimii nemorți dispar din acest plan al existenței. Aceste creaturi trebuie să fii venit de undeva, și ai @@ -4621,25 +5610,19 @@ mai oribile) nu trec prin ea, va trebui să închizi gura infernului de pe cealaltă parte. Firește că asta poate să însemne că vei rămâne blocat într-o lume extrem de neprimitoare, dar n-a spus nimeni că e ușor să -fii un eretic!","С уничтожением Железных Личей +fii un eretic!","С уничтожением железных личей и их приспешников, окрестные земли очистились от омерзительной нежити. -Эта нежить, должна была как-то проникнуть -в наш мир, и у Вас есть подозрение, -что пылающий портал Утробы Ада ведет +Эта нежить должна была как-то проникнуть +в наш мир, и у вас есть подозрение, +что пылающий портал Утробы ада ведёт в их измерение. -Угроза исходит из Огненного Портала — -порождения Ада и чёрной магии могут -изринуться из него. Ваша цель — -сойти в Ад и запечатать проклятый -портал. - -Это смертельно опасное деяние, и Вы -рискуете навсегда увязнуть во Тьме. -Но кто говорил, что путь истинного -Еретика лёгок и прост?","Са уништењем челичних личева и +Чтобы нежить или что похуже не прошло оттуда, вам придётся +сойти в ад и запечатать проклятый портал. Очевидно, что вы +рискуете навсегда увязнуть во тьме, но кто говорил, что быть +еретиком легко и просто?","Са уништењем челичних личева и његових пратиоца, последњи немртви су очишћени са равнице постојања. @@ -4654,7 +5637,41 @@ fii un eretic!","С уничтожением Железных Личей друге стране. Наравно то значи да ћете можда заглавити у непријатељском свету, али нико није реко да је лако бити -јеретик." +јеретик.","I och med förintelsen av järnlicherna +och deras hantlangare har de sista +odöda försvunnit från det här +existensplanet. + +Dessa varelser måste dock ha +kommit någonstans ifrån, och du har +en lömsk misstanke om att den eldiga +portalen i helvetets gap öppnar sig på +deras hemdimension. + +För att se till att inte fler odöda (eller +ännu värre saker) kommer igenom +måste du försegla Helvetets gap +från andra sidan. Naturligtvis innebär +detta att du kan fastna i en mycket +ovänlig värld, men ingen har någonsin +sagt att det är lätt att vara kättare!","Demir cesetlerin ve yardakçılarının +yok edilmesiyle, son yaşayan ölüler +de bu âlemden uzaklaştırılmış oldu. + +Bu yaratıkların bir yerde, yine de, ve +sen var sinsi şüphesi Cehennemin +ağzının kapısı açılıyor kendi +boyutlarında. + +Daha fazla ölümsüzün (ya da daha +kötü şeyler) gelmiyor Cehennem'i +mühürlemek zorunda kalacaksın. +diğer taraftan maw. Elbette. bu da, +bir güvenlik duvarı nda sıkışıp +kalabileceğiniz anlamına gelir. çok +düşmanca bir dünya, ama kimse +Kafir olmanın kolay olduğunu hiç +söylemedim!" "The mighty maulotaurs have proved to be no match for you, and as their steaming corpses slide to the @@ -4688,7 +5705,23 @@ Mohla by se snad za touto bránou nacházet ještě horší stvoření? Oblouk křišťálového dómu nad tvou hlavou tam, kde by se mělo nacházet nebe, rozhodně nevěstí nic -dobrého...","Die mächtigen Minotauren waren keine +dobrého...","De mægtige maulotaurer har vist sig ikke +at være nogen match for dig, og mens +deres dampende lig glider ned på jorden, +føler du en følelse af grum tilfredshed +med, at de er blevet udslettet. + +De porte, som de bevogtede, er blevet +åbnet og har afsløret det, som du håber +er vejen hjem. Men da du træder igennem, +lyder hånlig latter i dine ører. + +Var der en anden kraft, der kontrollerede +maulotaurerne? Kunne der være endnu mere +rædselsvækkende væsener bag denne port? +En krystalkupel over himlen, der er i +vejret, hvor himlen burde være, er +bestemt ikke et godt tegn...","Die mächtigen Minotauren waren keine Herausforderung für dich, und als ihre dampfenden Kadaver zusammenbrechen, fühlst du eine grimmige Genugtuung @@ -4709,19 +5742,19 @@ Seite dieser Tore? Die Krümmung einer riesigen Kuppel, dort wo der Himmel sein sollte, ist jedenfalls kein gutes Zeichen.",,"La bategtaŭroj potencaj montriĝis -tro malforta kontraŭ vi, kaj dum iliaj +tro malfortaj kontraŭ vi, kaj dum iliaj kadavroj vaporantaj falas sur la teron, -vi sentas kontenton malafablan, pro -ke ili estas detruita. +vi sentas kontenton malafablan, +ke ili estas detruitaj. -La pordegoj, kiojn ili gardis, malfermiĝas -en, kion espereble estas hejmo, sed -dum vi trapaŝas, ridado mokanta -resonas en viaj oreloj. +La pordegoj, kiujn ili gardis, malfermiĝas, +rivelante tion, kion espereble estas la vojo +hejmen, sed dum vi trapaŝas, ridado +mokanta resonas en viaj oreloj. -Ĉu forto alia kontrolis la bategtaŭrojn? +Ĉu forto alia regis la bategtaŭrojn? Ĉu estas eble eĉ pli estuloj hororaj tra -ĉi tiu pordego? La kupolo kristala vasta +ĉi tiu pordego? La balao de kupolo kristala supre, kie la ĉielo devas esti, certe ne estas antaŭsigno bona...","Los poderosos maulotauros han probado no ser un encuentro difícil para ti, y mientras @@ -4792,38 +5825,34 @@ plus atroce que les créatures de ce portail? La forme d'un dôme de cristal dépasse de l'horizon, couvrant le ciel, ce n'est pas -de bon augure....","Nyílvánvalóvá vált hogy a hatalmas -maulotaurok nem szálhattak veled szemben, -és ahogy a bűzölgő holtestük összeesik -érzed a szelét a gonosz elégedettségnek -mit a pusztulásuk okozott. - -A kapuk melyeket ők őriztek -kinyiltak, feltárva az utat ami reményeid -szerint hazavisz. De amint átlépsz, -gúnyos kacaj üti meg a füledet. - -Talán egy másik erő irányította -a malotaurokat? Talán náluk is -rémisztőbb lények vannak a kapun -túl. A kristály dóm íve fenn ahol az égnek -kellene lenni már messze nem egy -jó jel...","nemmeno i possenti maulotaur erano +de bon augure....","Immáron nyílvánvaló, hogy a hatalmas +maulotaurok nem a te súlycsoportodban voltak, +és ahogy a bűzölgő holtestük összeesik, +egyfajta morbid elégedettséget érzel kimúlásuk láttán. + +Az általuk őrzött kapuk kinyíltak, és a haza vezető +utat sejtetik maguk mögött. Azonban amikor átlépsz, +egy gúnyos kacaj nyilall a füledbe. + +Talán egy másik erő irányította mindvégig a maulotaurokat? +Létezne, hogy még ennél is borzasztóbb teremtmények +várnak a kapu másik túloldalán? A tiszta égbolt helyett feléd +tornyosuló kristály kupola íve nem jelent semmi biztatót...","Nemmeno i possenti Maulotauri erano alla tua altezza e mentre le loro carcasse fumanti cadono al suolo provi una feroce soddisfazione nell'averli distrutti. -i portali cui facevano la guardia +I portali cui facevano la guardia si sono aperti rivelando quella che -speri sia la via di casa. ma mentre -la attraversi, odi risa di scherno +speri sia la via di casa. Ma mentre +la attraversi, percepisci risa di scherno echeggiare nelle tue orecchie. -una qualche altra forza controllava -i maulotaur? che possano esserci +Una qualche altra forza controllava +i Maulotauri? Che possano esserci altri più spaventosi esseri oltre -questo portale? il baluginio di una +questo portale? Il baluginio di una volta cristallina là dove dovrebbe esserci il cielo non è certo un buon segno...","強靭と自負していたマウロタウロスは貴方に肩を並べるほど @@ -4862,7 +5891,23 @@ controleerde? Kunnen er nog meer gruwelijke wezens door deze poort komen? Het vegen van een kristallen koepel op de plek waar de hemel zou moeten staan is zeker geen goed teken... -","Potężne młototaury udowodniły, że nie mają +","De mektige maulotaurene har vist seg å +ikke være noen match for deg, og når de +dampende likene deres glir mot bakken, +føler du en dyster tilfredshet over at de +har blitt tilintetgjort. + +Portene som de voktet har åpnet seg, +og avslører det du håper er veien hjem. +Men når du går gjennom, ringer hånlig +latter i ørene dine. + +Var det en annen kraft som kontrollerte +maulotaurene? Kan det være enda mer +forferdelige vesener gjennom denne +porten? Sveipet av en krystallkuppel +over hodet der himmelen burde være, +er absolutt ikke et godt tegn...","Potężne młototaury udowodniły, że nie mają z tobą żadnych szans i jak ich stygnące zwłoki opadają na ziemię czujesz ponurą satysfakcję, że zostały zniszczone. @@ -4900,30 +5945,26 @@ crudă că au fost distruși. Poarta care era păzită de ei e acum deschisă, dezvăluind ceea ce tu sperai să fie drumul spre casă. Dar o dată ce pășești prin ea, râset batjocoritor -îți sună în urechi. +îți răsună în urechi. Să fii fost o altă forță în spatele maulotaurilor? Să fie oare creaturi și mai oribile dincolo de acest portal? Un dom de cristal în locul unde trebuia să fie cerul cu -siguranță nu e un semn bun...","Могучие Молотавры повержены. -Их дымящиеся трупы падают, -разваливаясь на куски, к Вашим -ногам, и мрачное удовлетворение -наполняет Вас. - -Врата, которые они охраняли, открылись. -Вы шагнули в них, думая, что -вернётесь в родной мир, но лишь -громкий, насмешливый хохот был -ответом на Вашу надежду. - -Чей это злобный хохот? Быть может -это голос демонических сил, -управляющих Молотаврами? Какие -чудовищные создания ожидают Вас +siguranță nu e un semn bun...","Могучие избитавры повержены, а их дымящиеся трупы падают, +разваливаясь на куски, к вашим +ногам, и мрачное удовлетворение их уничтожением +наполняет вас. + +Врата, которые они охраняли, открылись, даря надежду, что +вы вернётесь в родной мир, но лишь +громкий, насмешливый хохот стал +ответом на вашу надежду, как только вы ступили за порог. + +Кто-то ещё управлял избитаврами? Какие +чудовищные создания ожидают вас за этими вратами? Не голубое небо родного мира над головой, а -кристальный купол, — это плохой знак...","Моћни маулотаури су доказали да +кристальный купол — это плохой знак...","Моћни маулотаури су доказали да вам нису ни до колена, и док његови лешеви испаравају и падају на земљу ви осећате огорченено задовољство да @@ -4938,7 +5979,41 @@ siguranță nu e un semn bun...","Могучие Молотавры поверж минотауре? Да ли су још ужасавајуће ствари кроз ову капију? Замах кристалне куполе где би требало да буде небо -сигурно није добар знак." +сигурно није добар знак.","De mäktiga maulotaurerna har visat +sig inte vara någon match för er, och +när deras ångande lik glider ner på +marken känner du en känsla av grym +tillfredsställelse över att de har +förintats. + +Portarna som de vaktade har öppnats +och avslöjat vad du hoppas är vägen +hem. Men när du kliver igenom ringer +ett hånfullt skratt i dina öron. + +Var det någon annan kraft som +kontrollerade maulotaurerna? Kan det +finnas ännu mer hemska varelser +bakom den här porten? En +kristallkupol över himlen där himlen +borde vara är verkligen inget bra +tecken...","Kudretli maulotorlar kanıtladı seninle +boy ölçüşemez, ve dumanı tüten +cesetleri acımasızlık hissi uyandırır +oldukları için memnuniyet yok edildi. + +Korudukları geçitler açtınız, neyi +açığa çıkardınız umut eve giden +yoldur. Ama sen adım at, alaycı +kahkahalar kulaklarında çınlıyor. + +Maulotorları kontrol eden başka +bir güç mü vardı? Bu geçidin ardında +daha da korkunç varlıklar olabilir +miydi? Gökyüzünün olması gereken +yerde kristal bir kubbenin +yükselmesi kesinlikle iyi bir işaret +değil...." "The death of D'Sparil has loosed the magical bonds holding his creatures on this plane, their @@ -4981,7 +6056,25 @@ opravdu být jist, možná to byl jen řev. Na druhou stranu, co pak s -ostatními Hadími jezdci?","D'Sparils Tod hat die magischen Fesseln, +ostatními Hadími jezdci?","D'Sparils død har løsnet de magiske bånd, +der holder hans skabninger på dette plan, +og deres døende skrig overdøver hans +egne smertefulde skrig. + +Din hævnsed er opfyldt, og du træder ind +i portalen til din egen verden, blot få +øjeblikke før kuplen splintres i en +million stykker. + +Men hvis D'Sparils magt er brudt for evigt, +hvorfor føler du dig så ikke sikker? +Var det det sidste råb lige før hans død, +det råb, der lød som en forbandelse? +Eller en tilkaldelse? Du kan ikke være +helt sikker, men det kan bare have +været et skrig. + +Men igen, hvad med de andre slange ryttere?","D'Sparils Tod hat die magischen Fesseln, die diese Kreaturen banden, gelöst, und ihre Todesschreie übertönen sogar seine eigenen Schmerzenslaute. @@ -5007,7 +6100,7 @@ sorĉajn, kiuj tenis lian estulojn sur tion ĉi ebeno, dum iliaj kriegoj mortaj sonas super liaj kriegoj propraj de agonio. -Nun via ĵuro de venĝo estas veriga, do +Via ĵuro de venĝo verigita, vi eniras la portalon al vian mondon propran nur momentojn antaŭ la kupolo disfrakasiĝas en milionojn @@ -5015,12 +6108,12 @@ da pecoj Sed se la povo de D'Sparil estas eterne detruita, kial vi ne sentas sekura? Ĉu -estas ĉar la fina kriego tuj antaŭ lia -morto — tiu, kiu sonis, kiel malbeno? +estis pro la fina kriego tuj antaŭ lia +morto — tiu, kiu sonis kiel malbeno? Aŭ alvoko? Vi vere ne povas certi, sed ĝi eble estis nur kriego. -Tamen, kio pri la aliaj serpentrajdistoj?","La muerte de D'Sparil ha soltado +Tamen, kio pri la aliaj Serpentrajdistoj?","La muerte de D'Sparil ha soltado los vínculos mágicos que mantenían a sus criaturas en este plano, sus gritos moribundos abrumando sus @@ -5100,46 +6193,45 @@ ce n'est peut être qu un cri. De plus, qu'adviendra-il des autres chevaucheurs de serpent?","D'Sparil halála megszüntette a varázslatos köteléket mely -a lényeket ezen a szinten tartotta, +a lényeket ezen a szinten tartotta. A végső sikolyaik túlharsogják -az ő saját fájdalmas sírását. +az ő saját gyötrelmes sírását. Az esküd a bosszúról beteljesült, belépsz a hazafelé vezető -portálba, pillanatokkal a dóm -millió kis darabra esése előtt. +portálba, pillanatokkal a kupola +millió kis szilánkra esése előtt. De ha D'Sparil erejének -örökidőkre végre, miért nem -érzed magad biztonságban. +örökidőkre vége, miért nem +érzed magad biztonságban? Talán az utolsó kiáltása mielőtt -meghalt, azt ami egy átoknak -hallatszott. Vagy egy megidézésnek? -Nem lehetsz biztos benne, de -talán csak egy orditás volt. +meghalt, egy átok lehetett valójában? +Vagy egy megidézés? Nem lehetsz biztos +benne, de reméled hogy csak egy +egyszerű kiáltás volt. -De most, mi lesz a másik kettő -kígyóharcossal","la morte di d'sparil ha spezzato i +Másfelől mi lesz majd a többi kígyólovaggal?","La morte di D'Sparil ha spezzato i magici legami che tenevano le sue creature in questa dimensione, e i loro lamenti di morte coprono le sue urla di agonia. -il tuo voto di vendetta è sciolto, +Il tuo voto di vendetta è sciolto, ed entri nel portale che conduce al tuo mondo pochi secondi prima che la cupola vada in mille pezzi. -ma se il potere di d'sparil è +Ma se il potere di D'Sparil è infranto per sempre, perchè non ti -senti al sicuro? è a causa del suo +senti al sicuro? È a causa del suo ultimo urlo prima di morire, quello -che suonava come una maledizione? o +che suonava come una maledizione? O un'invocazione? non puoi esserne certo, poteva essere solo un urlo. -ma allora, cosa ne è degli altri -serpent rider?","デ'スパリルの死によって魔法による従僕達は解放され +Ma allora, cosa ne è degli altri +Cavalcatori dei Serpenti?","デ'スパリルの死によって魔法による従僕達は解放され その風靡なる死の悲鳴に貴方は圧倒された。 復讐の誓いは成し遂げられ、元の世界へ戻るポータルを 通った瞬間、ドームが崩壊し数百万の破片と化した。 @@ -5183,7 +6275,27 @@ een schreeuw zijn geweest. Maar hoe zit het dan met de andere servenrijders? -","Śmierć D'Sparila wypuściła magiczną więź +","D'Sparils død har løsnet de magiske +båndene som holder skapningene +hans på dette planet, og deres +døende skrik overvelder hans egne +smerteskrik. + +Din hevned er oppfylt, og du går inn +i portalen til din egen verden, bare +noen øyeblikk før kuppelen knuses +i en million biter. + +Men hvis D'Sparils makt er brutt for +alltid, hvorfor føler du deg ikke trygg? +Var det det siste ropet like før han +døde, det som hørtes ut som en +forbannelse? Eller en påkallelse? +Du kan ikke være sikker, men det +kan bare ha vært et skrik. + +Men igjen, hva med de andre +Slangerytterne?","Śmierć D'Sparila wypuściła magiczną więź trzymającą jego kreatury w tej krainie, ich ostatnie krzyki zagłuszają jego własny płacz agonii. @@ -5239,24 +6351,23 @@ blestem? Sau o chemare? Nu poți fi tocmai sigur, dar e posibil să fii fost un simplu strigăt. Dar din nou, cu ceilalți Călăreți cum rămâne?","С гибелью Д'Спарила исчезла магия, -сохранявшая жизнь порождениям Тьмы. +сохранявшая жизнь порождениям тьмы. Стоны умирающих демонов заглушили вопль агонии самого Д'Спарила. -Вы исполнили свою клятву. Месть -свершилась. И за секунду до -разрушения хрустального купола, -Вы наконец-то, входите во врата, +Вы исполнили свою клятву мщения. И за секунду до +разрушения хрустального купола +вы, наконец-то, входите во врата, ведущие в родной мир. Но и теперь, после гибели Д'Спарила, -душа Ваша не спокойна, и её +душа ваша не спокойна, и её одолевают плохие предчувствия. Не был ли проклятием его предсмертный -крик? Или призывом тёмных сил? +крик? Или призывом тёмных сил? Или просто — криком? -И где таятся другие Змеиные -Всадники?","Смрт Д'Спарила је олабавила магичне +И где таятся другие змеиные +всадники?","Смрт Д'Спарила је олабавила магичне окове који су држали његова створења за ову равницу, њихови предсмртни врисци пренеражују његов плач у @@ -5275,7 +6386,46 @@ Dar din nou, cu ceilalți Călăreți cum rămâne?","С гибелью Д'Сп можда је само био врисак. Али ипак, шта је са осталим јахачима -змија?" +змија?","D'Sparils död har lossat de magiska +band som håller hans varelser på detta +plan, deras dödliga skrik överväldigade +hans egna skrik av plågor. + +Din hämndens ed uppfylld, går du in i +portalen till din egen värld, bara några +ögonblick innan kupolen splittras i +en miljon bitar. + +Men om D'Sparils makt är bruten för +alltid, varför känner du dig då inte +trygg? Var det det sista ropet strax +före hans död, det som lät som en +förbannelse? Eller en kallelse? Du kan +inte riktigt vara säker, men det kan +ha varit ett skrik. + +Men å andra sidan, +hur är det med de andra ormryttarna?","D'Sparil'in ölümü, yaratıklarını bu +alemde tutan büyülü bağları kopardı, +onların ölüm çığlıkları kendi acı +çığlıklarını bastırdı. + +İntikam yeminini yerine getirdin ve +kubbenin milyonlarca parçaya +ayrılmasından sadece birkaç dakika +önce kendi dünyana açılan kapıdan +girdin. + +Ama eğer D'Sparil'in gücü kırılırsa +Sonsuza dek, neden güvende +hissetmiyorsun? O son bağırış mıydı? +Onun ölümü, o ses Lanet gibi mi? +Ya da bir çağırma? Sen emin +olamıyorum, ama olabilir sadece +bir çığlık olabilirdi. + +Sonra tekrar, +peki ya diğer Yılan Süvarileri mi?" "You thought you would return to your own world after D'Sparil died, but his final act banished you to his @@ -5319,7 +6469,25 @@ musíš vkročit do té díry doufaj@[tgs_pr1_cs], že nějak najdeš cestu ven. A někde tam, v nejhlubších útrobách D'Sparilova panství, čekají jeho osobní strážci -na tvůj příchod...","Du dachtest, du würdest in deine eigene +na tvůj příchod...","Du troede, at du ville vende tilbage til +din egen verden, efter at D'Sparil døde, +men hans sidste handling forviste dig +til hans eget plan. Her kom du ind i de +ødelagte rester af de lande, som D'Sparil +erobrede. Du besejrede de sidste vogtere +af disse lande, men nu står du foran +portene til d'Sparils fæstning. +Indtil dette øjeblik var du ikke i tvivl om +din evne til at klare alt, hvad du måtte +møde, men bag denne portal ligger selve +hjertet af den ondskab, som invaderede +din verden. D'Sparil er måske død, men +den grube, hvor han blev skabt, er stadig +tilbage. Nu må du gå ind i dette hul i håb +om at finde en vej ud. Og et eller andet +sted i det mørkeste hjørne af D'Sparils +domæne venter hans personlige +bodyguards på din ankomst ...","Du dachtest, du würdest in deine eigene Welt zurückkehren nach D'Sparils Tod, aber seine letzte Tat hat dich in diese Existenzebene verbannt. Hier hast du @@ -5346,16 +6514,17 @@ eniris la restaĵojn frakasitajn el landoj konkeritaj de D'Sparil. Vi venkis la finajn gardistojn de ĉi tiuj landoj, sed nun vi staras antaŭ la pordegoj inter vi kaj la -fuorto de D'Sparil. Antaŭ ĉi tiu momento, +fuorto de D'Sparil. Ĝis tiu ĉi momento, vi ne dubis, ke vi povus kontraŭi ĉion ajn, kioj vi eble trovos, sed preter ĉi tiu pordego estas la koro de mavo mem, kio invadis vian mondon. D'Sparil estas -mortinta, sed le truo, kie li naskiĝis, -restas. Nun vi bezonas eniri tiun truon, +mortinta, sed la truo, kie li naskiĝis, +restas. Nun vi devas eniri tiun truon, esperante trovi elirejon. Kaj ie, en la plej -malhela ejoj de la posedaĵo de D'Sparil, -liaj personaj gardistoj atendas vian venon...","Creíste que volverías a tu propio +malhela angulo de la posedaĵo de D'Sparil, +liaj gardistoj personaj atendas vian +alvenon...","Creíste que volverías a tu propio mundo después de que D'Sparil hubiera muerto, pero su acto final te ha desterrado hacia su propio @@ -5437,45 +6606,38 @@ l'espoir de trouver une sortie, quelque part, dans la plus sombre partie du royaume de D'Sparil. Sa garde personnelle attend votre -arrivée ...","Azt hitter D'Sparil halála után -visszatérhetsz a saját világodba, -de az utolsó erejével az ős saját -szintjére száműzött. Te itt beléptél -a D'Sparil meghódította föld -szétzúzott maradványaiba. Te -legyőzted az utolsó őrzőket is, de -most D'Sparil erődjének kapuja -előtt állsz. Eddig a pillanatig nem volt -kétséged a képességedről hogy, bárki -ellen kiállsz aki szembejön, de e kapu -mögött nyugszik a gonosznak szíve -mi megszállta a világodat. D'Sparil -halott talán, de a gödör hol előjött -megmaradt. Most neked be kell -menned, reménykedve a kiút -megtalálásában. De valahol -D'Sparil birtokának legsötétebb -sarkában, a testőrei várják -érkeztedet...","pensavi di tornare nel tuo mondo -dopo la morte di d'sparil, ma il +arrivée ...","Azt hitted, hogy D'Sparil halála után visszatérhetsz +a saját világodba, de utolsó lehelletével száműzött +a saját dimenziójába. Belépbe megpillantod a +D'Sparil által leigázott romos vidéket. Legyőzted a vidék +védelmezőit, és immáron D'Sparil erődjének kapujában állsz. +Ezidáig nem volt szívedben kétség afelől, hogy legyőzöl +bármit amit a sors eléd vet, azonban itt magával a +világodra törő gonosz szívével van dolgod. +D'Sparil ugyan meghalt, de a völgy ahol született +továbbra is fennáll. Belépsz a völgybe annak reményében, +hogy találsz egy kiutat. Valahol, ennek a birtoknak is a legsötétebb +sarkában, a személyi testőrei várnak a revansra... +","Pensavi di tornare nel tuo mondo +dopo la morte di D'Sparil, ma il il suo ultimo atto ti ha esiliato -in questo posto. sei quindi entrato +in questo posto. Sei quindi entrato nei resti infranti delle terre -conquistate da d'sparil. Ne hai poi +conquistate da D'Sparil. Ne hai poi abbattuto gli ultimi guardiani, ma ora ti trovi davanti ai cancelli -della fortezza di d'sparil. finora +della fortezza di D'Sparil. Fino ad ora non avevi avuto dubbi sulla tua abilità nel fronteggiare di tutto, ma oltre questo portale si trova il cuore del male che ha invaso -il tuo mondo. d'sparil sarà anche -morto, ma il pozzo dove è apparso -esiste ancora. devi entrare in quel +il tuo mondo. D'Sparil sarà anche +morto, ma il pozzo dal quale è apparso +esiste ancora. Devi entrare in quel pozzo nella speranza di trovare -un'uscita. e da qualche parte, +un'uscita. E da qualche parte, negli oscuri angoli del dominio -di d'sparil le sue guardie del +di D'Sparil le sue guardie del corpo aspettano il tuo arrivo...","貴方はデ'スパリルの死後、元の世界に戻れるはずだったが あの死に際の呪文により既に征服され破壊された古蹟へ 送られてしまった。先程その守護者を打ち倒し、次いで @@ -5516,20 +6678,37 @@ blijft bestaan. Nu moet je die kuil betreden in de hoop een uitweg te vinden. En ergens, in de donkerste hoek van D'Sparil's rijk, wachten zijn persoonlijke lijfwachten op je komst... -","Myślałeś, że po śmierci D'Sparila wrócisz do -swego świata, ale jego ostatni czyn zesłał cię +","Du trodde du skulle vende tilbake til din +egen verden etter at D'Sparil døde, men +hans siste handling forviste deg til hans +eget plan. Her gikk du inn i de knuste +restene av land erobret av D'Sparil. Du +beseiret de siste vokterne av disse +landene, men nå står du foran portene +til D'Sparils festning. Inntil dette øye- +blikket hadde du ingen tvil om din evne +til å møte alt du måtte møte, men borten- +for denne portalen ligger selve hjertet av +ondskapen som invaderte din verden. +D'Sparil er kanskje død, men gropen der +han ble skapt, finnes fortsatt. Nå må du +gå inn i den gropen i håp om å finne en +vei ut. Og et sted, i det mørkeste hjørnet +av D'Sparils demesne, venter hans +personlige livvakter på din ankomst ...","Myślałeś, że po śmierci D'Sparila wrócisz do +swego świata, ale jego ostatni czar zesłał cię do jego własnego wymiaru. Wkroczyłeś w pozostałości krain podbitych przez D'Sparila. Pokonałeś ostatnich strażników tych ziem, ale teraz stoisz przed bramami do twierdzy D'Sparila. Do tego momentu nie miałeś -wątpliwości o swojej umiejętności do -stawienia czoła czemukolwiek co napotkasz, +wątpliwości o swoich zdolnościach do +stawiania czoła czemukolwiek co napotkasz, ale poza tym portalem leży serce zła, które nawiedziło twój świat. D'Sparil może i jest -martwy, ale dół, w którym powstał -uchował się. Musisz teraz teraz wejść do tego -dołu mając nadzieję, że znajdziesz drogę +martwy, ale nora, z której wypełzł +uchowała się. Musisz teraz teraz wejść do tej +nory mając nadzieję, że znajdziesz drogę wyjścia. I gdzieś w ciemnych zakątkach włości D'Sparila jego osobista straż czeka na twoje przybycie...","Você achou que retornaria ao seu mundo @@ -5563,27 +6742,18 @@ Poate că D'Sparil s-a dus, dar groapa în care s-a născut rămâne. Acum trebuie să intri în acea groapa în speranța că vei găsi și o cale de ieșire. Și undeva, în defensiva celui mai întunecat colț al locului, -proprii lui gardieni îți așteaptă sosirea ...","С гибелью Д'Спарила умерла и Ваша +proprii lui gardieni îți așteaptă sosirea ...","С гибелью Д'Спарила умерла и ваша надежда вернуться в родной мир. Своим предсмертным проклятьем -он отправил Вас в те немногие, -ещё оставшиеся подвластными -ему земли. Вы разбили последних +он изгнал вас в разбитые останки +подвластных ему земель. Вы разбили последних хранителей этих земель и стоите перед опустевшим замком Д'Спарила, -оплотом его тёмных сил. - -Само Сердце Зла растворило перед -Вами врата. И хотя Д'Спарил -повержен, глубины, породившие его, -стоят нерушимы. - -Вы сойдёте в эту преисподнюю, ибо -единственный способ вернуться в -родной мир — отыскать вход в него -в тёмных глубинах опустевшей вотчины -Д'Спарила. Личные стражи мёртвого -господина уже дожидаются Вас...","Мислили сте да ћете се вратити +оплотом его тёмных сил. До сих пор вы не сомневались в том, что +сможете противостоять всему, что увидите, но за этим порталом само сердце зла, что захватило ваш мир. И хотя Д'Спарилповержен, глубины, породившие его, +стоят нерушимы. Вам придётся пройти в эту преисподнюю, надеясь найти там путь назад. И где-то там личные стражи мёртвого +господина уже дожидаются вас в самых тёмных уголках... +","Мислили сте да ћете се вратити сверту после Д'Спарилове смрти, али његов последњи кец у рукаву вас је прогнао у његов свет. Овде сте ушли у @@ -5601,7 +6771,45 @@ proprii lui gardieni îți așteaptă sosirea ...","С гибелью Д'Спа нађете излаз. И негде, у најмрачнијим ћошковима Д'Спариловог поседа, његови лишни телохранитељи -чекају ваш долазак." +чекају ваш долазак.","Du trodde att du skulle återvända till +din egen värld efter D'Sparils död, men +hans sista handling förvisade dig till +hans eget plan. Här gick du in i +krossade resterna av de länder som +D'Sparil erövrade. Du besegrade de +sista väktarna av dessa länder, men +nu står du framför portarna till D'Sparils +fäste. Fram till det här ögonblicket hade +du inga tvivel om din förmåga att möta +allt som du skulle kunna möta, men +bortom den här portalen ligger själva +hjärtat av den ondska som invaderade +din värld. D'Sparil må vara död, men +gropen där han föddes finns kvar. Nu +måste du gå in i den gropen i hopp om +att hitta en väg ut. Och någonstans, i +det mörkaste hörnet av D'Sparils rike, +väntar hans personliga livvakter på +din ankomst ...","Kendi evine döneceğini sanıyordun. +D'Sparil öldükten sonra kendi +dünyasına döndü. son eylemi seni +sürgüne gönderdi kendi uçağı. İşte +burada parçalanmış toprak kalıntıları +D'Sparil tarafından fethedildi. Sen +yendin Bu toprakların son +koruyucuları, ama şimdi kapıların +önünde duruyorsun D'Sparil'in kalesine. +Ta ki bu hakkında hiçbir şüphen +olmadığı an her şeyle yüzleşebilme +yeteneği karşılaşma, ama bu portalın +ötesinde kötülüğün tam kalbinde +yatıyor dünyanızı işgal eden. D'Sparil +ölmüş olabilir, ama çukurda doğduğu +yer kalır. Şimdi yapman gereken o +çukura girme umuduyla bir çıkış yolu +bulmak. Ve bir yerlerde, D'Sparil'in +krallığının en karanlık köşesinde, +kişisel korumaları gelişinizi bekliyor ..." "As the final maulotaur bellows his death-agony, you realize that you have never come so close to your own @@ -5635,13 +6843,31 @@ nějaké další nemyslitelné noční můře. Začínáš přemýšlet, jestli máš sílu pokračovat, jestliže na tebe nečeká nic, než smrt a utrpení. Co jiného ti zbývá, -když je vůle bojovat pryč? Mohl@[ao_cs] by +když vůle bojovat vyprchala? Mohl@[ao_cs] by ses přinutit kráčet dál v takovou beznaděj? Máš na to odvahu? Nakonec pochopíš, že v tobě není toho, vzdát se bez boje. S očima -dokořán jdeš potkat svůj osud.","Als der letzte Minotaurus seinen +dokořán jdeš potkat svůj osud.","Da den sidste maulotaur brøler sin +dødssang, indser du, at du aldrig +harværet så tæt på din egen undergang. +Ikke engang kampen mod D'Sparil og +hans disciple havde været så desperat. +Du stirrer dystert på portene, der +åbner sig foran dig, og du spekulerer +på, om de fører hjem, eller om de +åbner sig mod en uanede rædsel. Du +spekulerer på, om du har kræfter nok +til at fortsætte, om der ikke venter +dig andet end død og smerte. +Men hvad kan man ellers gøre, hvis +viljen til at kæmpe er væk? Kan man +tvinge sig selv til at fortsætte i en +sådan fortvivlelse? Har du modet til +det? Til sidst finder du ud af, at det +ikke er i dig at overgive dig uden kamp. +Med store øjne går du din skæbne i møde.","Als der letzte Minotaurus seinen Todesschrei herausbellt, wird dir bewusst, dass du niemals zuvor deinem Ende so nahe warst. Nicht mal der Kampf @@ -5665,22 +6891,22 @@ dich mit offenen Augen deinem Schicksal stellen.",,"Dum la bategtaŭro fina blekas lian agonion, vi konscias, ke vi neniam estis tiom prokisme de via detruo -propra. Eĉ ne la batalo kun D'Sparil -kaj liaj disĉiploj estis tiom aflikta. -Vi malgaje rigardas la pordegon, +propra. Ne eĉ la batalo kun D'Sparil +kaj liaj disĉiploj estis tiom afliktaj. +Malgaje, vi rigardas la pordegon, kiu malfermiĝas antaŭ vi, scivolante -ĉu ĝi kondukas hejmen, aŭ ĉu ĝi -kondukas al iu teruro neprirevita. -Vi troviĝas scivolanta ĉu vi havas -forton pro daŭri plu, se nenio krom +ĉu ĝi gvidas hejmen, aŭ ĉu ĝi +gvidas al iu teruro neprirevita. +Vi troviĝas vin scivolanta ĉu vi havas +forton por daŭri plu, se nenio krom morto kaj doloro atendas vin. Sed -kion vi povas fari, se la volo batali +kion alian vi povas fari, se la volo batali estas for? Ĉu vi povas devigi vin daŭri -kontraŭ tia malespero? Ĉu vi havas -tiom bravecon? Vi vine trovis, ke vi -ne havas la povo por rezigni sen -batalo. Kun malfermitaj okuloj, -vi iras por renkonti vian destinon.","Mientras el último maulotauro brama +fronte al tia malespero? Ĉu vi havas +la kuraĝon? Vi trovas, fine, ke vi +ne havas la povo rezigni sen batalo. +Kun okuloj malfermegitaj, vi iras +por renkonti vian destinon.","Mientras el último maulotauro brama su muerte agonizante, te das cuenta que nunca has estado tan cerca de tu propia destrucción. Ni la pelea con @@ -5737,25 +6963,46 @@ En avez vous le courage? Vous pensez a la fin que ce n'est pas dans votre nature de vous rendre sans combattre. Les yeux larges, vous -partez rencontrer votre destinée.",,"mentre l'ultimo maulotaur muggisce +partez rencontrer votre destinée.","Amikor az utolsó maulotaur végső +lehelletével felbőg, tudatosul benned, +hogy még sosem voltál ennyire közel +a halálhoz. Talán még a D'Sparil és +tanítványai elleni harc sem volt +ennyire kétségbeejtően nehéz. +Elkeseredetten tekintesz az előtted +kinyíló kapura, azon morfondírozva, +hogy haza vezet e, vagy valami olyan +horror van mögötte amiről álmodni +se mernél. Azon veszed észre magad, +hogy elgondolkozol érdemes e ennyi +fájdalom és öldöklés árán is +továbbmenni. Azonban mi mást +tehetszha elfogyott az akaratod? +Mégis rá tudod erőltetni magad, hogy +folytasd reménytelen utad? Megvan +hozzá a kellő bátorságod? A végén +ráébredsz, hogy nem olyan fából +faragtak aki harc nélkül feladja. +Tágra nyílt szemekkel várod a +végzettel való találkát.","Mentre l'ultimo Maulotauro muggisce agonizzante, comprendi che non eri mai stato così vicino alla tua -distruzione. nemmeno la lotta con -d'sparil e i suoi discepoli fu -così disperata. triste, guardi i +distruzione. Nemmeno la lotta con +D'Sparil e i suoi discepoli fu +così disperata. Cupo, guardi i cancelli che ti si aprono innanzi, chiedendoti se portino a casa o se conducano a un altro inimmaginabile -orrore. ti chiedi se avrai la forza +orrore. Ti chiedi se avrai la forza di andare avanti, se niente tranne dolore e morte ti attendano, ma che altro puoi fare se la forza di -combattere se ne va? puoi sforzarti +combattere se ne va? Puoi sforzarti di continuare, nonostante la disperazione? -ne hai il coraggio? decidi infine +Ne hai il coraggio? decidi infine che non è da te arrendersi senza -combattere. ad occhi aperti +combattere. Ad occhi aperti vai incontro al tuo destino.","最後のマウロタウロスが死際の咆哮を放った時、 貴方の所業が無謀ではないと証明された。 デ'スパリルとその従僕達との闘いでさえ @@ -5794,20 +7041,38 @@ door te gaan in deze wanhoop? Heb je de moed? Uiteindelijk vind je dat het niet in jou is om je over te geven zonder een gevecht. Ogen wijd open, je gaat je lot tegemoet. -","Podczas gdy ostatni młototaur ryczy w agoni, +","Når den siste maulotauren brøler sin +dødsangst, innser du at du aldri har +kommet så nær din egen ødeleggelse. +Ikke engang kampen med D'Sparil og +disiplene hans hadde vært så desperat. +Du stirrer dystert på portene som åpner +seg foran deg, og lurer på om de fører +hjem, eller om de åpner seg mot en +eller annen ufattelig skrekk. Du lurer +på om du har styrke til å fortsette, omdet +bare er død og smerte som venter deg. +Men hva annet kan du gjøre hvis viljen til +å kjempe er borte? Kan du tvinge deg +selv til å fortsette i møte med slik +fortvilelse? Har du mot til det? Du +finner til slutt ut at det ikke ligger i deg å +overgi deg uten kamp. Med store øyne +går du din skjebne i møte.","Podczas gdy ostatni młototaur ryczy w agonii, zdajesz sobie sprawę, że nie byłeś jeszcze -tak blisko swojego unicestwienia. Nawet -walka z D'Sparilem i jego uczniami nie była +tak blisko unicestwienia samego siebie. +Nawet walka z D'Sparilem i jego uczniami nie była aż tak desperacka. Ponuro wpatrujesz się w bramy, które otwierają się przed tobą, -myśląc czy prowadzą do domu, czy do -niewyobrażalnego horroru. Przyłapujesz się -na zastanawianiu się czy masz siłę, by iść dalej, -jeśli nic oprócz śmierci i bólu czeka na ciebie. -Ale co innego możesz jeszcze zrobić, jeśli -chęć walki zniknęła? Czy możesz się zmusić, -by kontynuować w obliczu rozpaczy? Czy masz -siłę? W końcu zauważasz, że nie jest w twoim +zastanawiając się czy prowadzą do domu, czy do +kolejnego niewyobrażalnego horroru. +Zastanawiasz się czy masz siłę, by iść +dalej, jeśli nic oprócz śmierci i bólu +czeka na ciebie. Co innego możesz +jeszcze zrobić, jeśli chęć walki zniknęła? +Czy w obliczu rozpaczy możesz +się zmusić, by iść dalej? Czy masz siłę? +W końcu zauważasz, że nie jest w twoim stylu poddać się bez walki. Miej oczy szeroko otwarte, idziesz spotkać się ze swoim przeznaczeniem. ","Enquanto o último marretauro agoniza @@ -5845,25 +7110,15 @@ să continui în ciuda disperării? Ai curajul necesar? fire. Cu privirea larg deschisă, te duci să-ți întâmpini destinul.","Наблюдая с мрачным отвращением предсмертную агонию последнего -сражённого Молотавра, Вы только +сражённого избитавра, вы только теперь понимаете, что смерть ещё никогда не была так близка. Даже -во время яростной битвы с самим -Д'Спарилом и его тёмными слугами. - +яростная битва с самим +Д'Спарилом и его тёмными слугами не было такой отчаянной. С угрюмым отчаянием приближаетесь -Вы к открытым порталам. Слабая -надежда теплится в Вашей душе, — -быть может за ними скрыта дорога -домой, а не бездны чужих миров? - -Отчаяние наделяет Вас мрачной -решимостью. Ничто не способно -остановить Вас, одна только — смерть. -Не сдавайтесь без боя, взгляните в -глаза своей судьбе. Знайте, если Вы -упали на самое дно, есть лишь один -путь — наверх.","Са падом последњег минотаура у +вы к открытым порталам, гадая, что там — +дорога домой, или некий ещё непознанный кошмар? +Вы ловите себя на том, что спрашиваете себя, осталась ли у вас сила для пути, если окажется, что только смерть и страдание ждут вас. Но что можно сделать, если воля к победе истощилась? Сможете ли вы заставить себя продолжить путь назло отчаянию? Что с вашей отвагой? Вы решаете наконец, что не в вашем характере сдаться без боя. С широко открытыми глазами вы идёте навстречу судьбе.","Са падом последњег минотаура у очајничку смрт, схватате да никад нисте стигли толико близу своје пропасти. Чак ни борба против Д'Спарила и његових @@ -5879,23 +7134,59 @@ destinul.","Наблюдая с мрачным отвращением у лице очајања? Да ли имате храброст? Налазите, да у себи није да се предате без борбе. Широких очију, идете да -упознате своју судбину." -"having passed the seven portals +упознате своју судбину.","När den sista maulotauren ropar sin +dödsagoni inser du att du aldrig har +varit så nära din egen förintelse. Inte +ens kampen mot D'Sparil och hans +lärjungar hade varit så desperat. Grimt +stirrar du på portarna som öppnar +sig framför dig och undrar om de leder +hem eller om de öppnar sig mot någon +oanade skräck. Du finner dig själv +undra om du har styrkan att fortsätta, +om inget annat än död och smärta +väntar dig. Men vad kan man göra om +viljan att kämpa är borta? Kan du +tvinga dig själv att fortsätta när du +står inför en sådan förtvivlan? Har du +modet? Till slut upptäcker du att det +inte finns inom dig att ge upp utan strid. +Med stora ögon går du ditt öde till +mötes.","Son maulotor kükrerken ölüm acısı, +fark edersin ki hiç bu kadar yaklaş- +mamıştın. Yıkım. Savaş bile değil +D'Sparil ve müritleri bu kadar çaresiz. +Acımasızca bakıyorsun Önünüzde +açılan kapıları, eve mi götürüyorlar +yoksa hayal bile edilemeyen Korku. +Kendinizi merak ederken bulursunuz. +eğer devam edecek gücün varsa, +ölüm ve acıdan başka bir şey +beklemiyorsa Sen. Ama başka +ne yapabilirsin ki? Savaşma isteğinin +gittiğini mi? Böyle bir umutsuzluk +karşısında kendinizi devam etmeye +zorlayabilir misiniz? Cesaretiniz var +mı? Sonunda, savaşmadan teslim +olmanın içinizde olmadığını +görürsünüz. Gözlerinizi dört açarak +kaderinizle buluşmaya gidiyorsunuz." +"Having passed the seven portals which sealed this realm, a vast domain of harsh wilderness stretches -before you. fire, ice and steel have +before you. Fire, ice and steel have tested you, but greater challenges -remain ahead. the dense tangle of +remain ahead. The dense tangle of forest surely hides hostile eyes, but what lies beyond will be worse. -barren desert, dank swamps and +Barren desert, dank swamps and musty caverns bar your way, but you cannot let anything keep you from your fate, even if you might come to wish that it would. -and beyond, flickering in the +And beyond, flickering in the distance, the ever-shifting walls of the hypostyle seem to mock your every effort.",TXT_HEXEN_CLUS1MSG,,,,"Procháziv@[tgs_past_cs] sedmerem portálů, které @@ -5915,7 +7206,25 @@ by sis možná přál@[ao_cs], aby tomu tak bylo. A ještě dál, mihotajíce se v dáli, neustále se přetvářející zdi hypostylu zdánlivě se -smějí veškerému tvému úsilí.","Nachdem du die Sieben Portale passiert +smějí veškerému tvému úsilí.","Når du har passeret de syv portaler, +der forseglede dette rige, ligger der +et stort område med barske vildmarker +foran dig. Ild, is og stål har sat dig +på prøve, men der er stadig større +udfordringer forude. Det tætte +skovtæppe skjuler sikkert fjendtlige +øjne, men det, der ligger bagved, +vil være værre. + +Tørre ørken, fugtige sumpe og mugne +huler spærrer din vej, men du kan ikke +lade noget holde dig fra din skæbne, +selv om du måske kommer til at ønske, +at det ville gøre det. + +Og på den anden side, der flimrer i det +fjerne, synes hypostolens evigt skiftende +vægge at håne dine anstrengelser.","Nachdem du die Sieben Portale passiert hast, die dieses Reich versiegelten, erstreckt sich vor dir das weite Land einer rauen Wildnis. Feuer, Eis und @@ -5934,13 +7243,13 @@ du es dir wünschen könntest. Und dahinter, flackernd in der Ferne, scheinen die sich ständig verändernen Wände der Säulenhalle all -deinen Fortschritt zu verspotten.",,"Pasinde la sep portalojn, kiuj obturis -ĉi tion regionon, vi staras antaŭ vasta +deinen Fortschritt zu verspotten.",,"Pasinte la sep portalojn, kiuj sigelis +ĉi tiun regionon, vi staras antaŭ vasta regno de severa sovaĝejo. Fajro, glacio, kaj ŝtelo provis vin. Tamen, pli grandaj provoj restas antaŭe. La densa ĥaoso de la arbaro nepre kaŝas kontraŭajn -okulojn, sed tio, kiu situas antaŭe, +okulojn, sed tio, kio situas antaŭe, estos pli malbona. Senvivaj dezertoj, humidaj marĉoj, @@ -6020,7 +7329,27 @@ cas. Plus loin, brillant à l'horizon, les murs toujours changeants de l'Hypostyle -semblent moquer vos efforts.",,"Dopo aver superato i sette portali che +semblent moquer vos efforts.","Elhaladva a birodalmat bezáró Hét +Portálnál előtt, egy kíméletlen vadon +látványa tárul eléd. A tűzes, jeges, és +acélozott próbatételeket kiálltad, de +még most jön a java. A sűrűn +összenőtt erdő bizonyára ellenséges +szempárokat rejt, de ami rád vár, még +ennél is hitványabb. + +Terméketlen sivatag, nyírkos +mocsarak,és dohos barlangok +gátolták utadat, de semmi sem tart +vissza a sorsodtól, még akkor sem ha +legbelül úgy érzed jobb lenne ha +visszatartana. + +A távolban káprázó, feléd magasló +hirhedt oszlopterem falai mintha +gúnyt űznének belőled és minden +erőfeszítésedből. +","Dopo aver superato i sette portali che sigillavano questo regno, un vasto dominio di aspre terre selvagge si estende davanti a te. Fuoco, ghiaccio e acciaio ti hanno @@ -6044,7 +7373,7 @@ sembrano prendere in giro ogni tuo sforzo.","この地を封印していた漆 不毛の砂漠、湿った沼地、そしてカビの生えた洞窟が 行く先を妨げているが、貴方が例えそれを望んでいても -己の運命から遠ざかることは出来ない。 +己の運命から遠ざけることは出来ない。 故に、遠くでちらつく、聳え立つ柱の間は貴方のあらゆる 努力を嘲ている様にも思える。","일곱 차원문을 거치고 이 영역을 봉쇄하자, 당신 앞에 혹독한 황폐지가 @@ -6076,10 +7405,26 @@ dat het zou gebeuren. En verder, flikkerend in de afstand, schijnen de steeds veranderende muren van de zuilenhal om uw elke inspanning te bespotten. -","Po przejściu przez siedem portali, które -zapieczętowały ten świat, ogromna przestrzeń -srogiej dziczy rozciąga się przed tobą. Ogień, -lód i stal przetestowały cię, ale większe +","Etter å ha passert de syv portalene som +forseglet dette riket, strekker et stort +område med barsk villmark seg foran +deg. Ild, is og stål har satt deg på prøve, +men større utfordringer gjenstår. Det +tette virvaret av skog skjuler sikkert +fiendtlige øyne, men det som +ligger bortenfor vil være verre. + +Ufruktbar ørken, fuktige sumper og +mugne huler sperrer veien, men du kan +ikke la noe holde deg unna skjebnen din, +selv om du kanskje skulle ønske det. + +Og bortenfor, flimrende i det fjerne, ser +hypostylens stadig skiftende vegger ut +til å håne alle dine anstrengelser.","Po przejściu przez siedem portali, które +zapieczętowały ten świat, ogromna, sroga dzicz +rozciąga się przed tobą. Ogień, lód i stal +przetestowały cię, ale większe wyzwania pozostają przed tobą. Gęsta plątanina lasów z pewnością ukrywa wrogie oczy, ale to co leży za nimi będzie gorsze. @@ -6088,11 +7433,12 @@ Jałowa pustynia, wilgotne bagna i stęchłe jaskinie zagradzają ci drogę, ale nie możesz niczemu pozwolić by trzymało cię z dala od twojego przeznaczenia, nawet jeśli -życzyłbyś by mogło. +życzyłbyś by to zrobiło. -A dalej, migające światła w oddali, zmieniające -się hipostylowe ściany drwią z każdego -twojego wysiłku.","Após passar pelos Sete Portais que +A poza tym wszystkim, migające +światła w oddali i zmieniające +się co chwila hipostylowe ściany +drwią z każdego twojego wysiłku.","Após passar pelos Sete Portais que selavam este domínio, uma vasta região de terras selvagens se extende na sua frente. Fogo, gelo e aço testaram você, @@ -6125,10 +7471,10 @@ ajunge să îți dorești acest lucru. Iar dincolo, strălucind în zare, zidurile veșnic schimbătoare ale hipostilei par să își bată joc de tine -la fiecare efort pe care îl faci.","Вы прошли Семь порталов, что +la fiecare efort pe care îl faci.","Вы прошли семь порталов, что властвовали над этими землями, и зловещая бескрайняя местность -простирается теперь перед Вами. +простирается теперь перед вами. Вас испытывали огонь, лёд и сталь, но впереди ожидают и более тяжкие испытания. Неведомые и коварные @@ -6138,34 +7484,67 @@ la fiecare efort pe care îl faci.","Вы прошли Семь порталов Бесплодные пустоши, гнилые болота и затхлые подземелья преграждают -Ваш путь, но ничто не сможет +ваш путь, но ничто не сможет изменить предначертанную судьбу, -хотите Вы того или нет. +хотите вы того или нет. И где-то далеко, в глубинах бесконечных гипостильных залов сами стены ожили, чтобы отяготить -каждый Ваш шаг.","Након што сте прошли седам -портала који су запечатили овај -свет, пространи домен грубе -дивљине протеже се пред вама. -Ватра, лед и челик су вас испитали, -али већи изазови остају пред вама. -Густи завој шуме сигурно сакрива -непријатељске очи, али оно што -лежи изван тога ће бити још горе. - -Празна пустиња, мрачне мочваре -и устајале пећине вам препречују пут, -али не можете дозволити да вас -ишта задржава од своје судбине, -чак и ако би вам дошло да то пожелите. - -И изван, треперући у даљини, -изгледа да се стално померајући -зидови хипостола исмевају сваком -вашем напору. -" +каждый ваш шаг.","Прошли сте Седам портала који су +владали над овим земљама, +и сада се пред Вама простире +злосутно, бескрајно подручје. +Испитивали су Вас огањ, лед и +челик, али предстоје и тежи испити. +У шуми сенки се крију непознате и +подмукле претње, а страх од +непознатог није најужасније од +онога што би Вам се могло десити. + +Неплодне пустоши, гњиле мочваре +и устајале пећине Вам препречују +пут, али ништа не може изменити +предодређену судбу, хтели Ви то +или не. + +А негде далеко, у дубинама +бесконачног хипостила, оживели +су и сами зидови како би +оптеретили сваки Ваш корак.","Efter att ha passerat de sju portaler +som förseglade den här världen, +sträcker sig ett stort område med hård +vildmark framför dig. Eld, is och stål har +testat dig, men större utmaningar +återstår. Det täta virrvarret av skog +döljer säkert fientliga ögon, men det som +ligger bortom kommer att vara värre. + +Karg öken, fuktiga träsk och mossiga +grottor spärrar din väg, men du kan inte +låta något hindra dig från ditt öde, även +om du kanske önskar att det skulle +göra det. + +Och bortom, flimrande i fjärran, tycks +hypostilens ständigt skiftande +väggar håna dina ansträngningar.","Bu diyarı mühürleyen yedi kapıyı +geçtikten sonra, önünüzde uçsuz +bucaksız bir vahşi doğa uzanıyor. +Ateş, buz ve çelik sizi sınadı ama +önünüzde daha büyük zorluklar var. +Ormanın sık karmaşası kesinlikle +düşman gözleri gizliyor, Ama ötesi +daha da kötü olacak. + +Çorak çöller, nemli bataklıklar ve küflü +mağaralar yolunuzu kesiyor, ama siz +hiçbir şeyin sizi kaderiniz, gelseniz +bile olmasını dilemek için. + +Ve ötesinde, titreyen mesafe, sürekli +değişen duvarlar hipostil alay ediyor +gibi görünüyor her türlü çabanı." "Your mind still reeling from your encounters within the hypostyle, you stagger toward what you hope is @@ -6174,12 +7553,12 @@ and faster, your vision blurs and begins to fade... As the world collapses around you, the brightness of a teleportal -engulfs you. a flash of light, and then +engulfs you. A flash of light, and then you climb wearily to your feet. You stand atop a high tower, and from below come the screams of the -damned. you step forward, and +damned. You step forward, and instantly the sound of demonic chanting chills your blood. By all the gods of death! what place @@ -6201,7 +7580,24 @@ Vykráčíš vpřed a ze hřmotu pekelného skandování ti okamžitě tuhne krev v žilách. U všech bohů smrti! Do jakých končin ses to dostal@[ao_cs]? U všech bohů utrpení, -jak se kdy odsud dostaneš?","Während deine Gedanken immer noch +jak se kdy odsud dostaneš?","Dit sind er stadig i sving efter dine +møder i hypostylet, og du vakler mod +det, du håber er en vej ud. Tingene +synes at bevæge sig hurtigere og +hurtigere, dit syn bliver sløret +og begynder at falme... +Mens verden kollapser omkring dig, +opsluges du af en teleportals lysstyrke. +Et lysglimt, og så kravler du træt +op på dine fødder. + +Du står på toppen af et højt tårn, +og nedefra lyder de fordømtes skrig. +Du træder fremad, og straks får du +koldt blod i blodet af dæmonisk sang. +Ved alle dødens guder, hvilket sted er +du kommet til? Ved alle smertens guder, +hvordan vil du nogensinde finde ud?","Während deine Gedanken immer noch um die Begegnungen in der Säulenhalle kreisen, taumelst du auf etwas zu, von dem du hoffst, dass es ein Ausweg ist. @@ -6292,26 +7688,41 @@ les cris des damnés. Vous vous avancez et les chants démoniaques vous glacent le sang. Par les dieux de la douleur, où -êtes vous arrivé? Comment sortir d'ici?",,"La tua mente che ancora vacilla dai tuoi -incontri all'interno dell'ipostilo, devi -barcollare verso quella che speri sia una -via d'uscita. Le cose sembrano muoversi +êtes vous arrivé? Comment sortir d'ici?","A küzdelemtől zsongó elméddel +támolyogsz előre, a kiút reményében. +Hirtelen a minden felgyorsul +körülötted, elmosódik a világ majd el +is sötétül... +Ahogy a világ összeomlik a szemed +láttára, egy előtted megjelenő átjáró +fénye áraszt el. Egyszercsak egy +villanás vakít meg, majd kis idő múlva +feltápászkodsz. + +Egy magas tornyon találod magad, és +lentről csak a holtak sikolyait hallani. +Ahogy elindulsz megfagy a véred a +démoni kántálás hallatán. A halálisten +szerelmére! Miféle hely ez? Hogyan +fogsz kijutni innen?","La tua mente ancora vacilla dai tuoi +incontri all'interno dell'ipostilo, e barcolli +verso quella che speri sia una via d'uscita. +Le cose sembrano muoversi sempre più velocemente, la tua visione si confonde e comincia a svanire... -Quando il mondo crolla intorno a te, +Mentre il mondo crolla intorno a te, la luminosità di un teleportale ti inghiotte. Un lampo di luce, e poi -si sale stancamente ai piedi. +ti alzi faticosamente in piedi. -Si sta in cima ad una torre alta, e dal +Ti trovi in cima ad una torre alta, e dal basso arrivano le grida dei dannati. -Si fa un passo avanti, e immediatamente il -suono del canto demoniaco raffredda il sangue. +Fai un passo avanti, e immediatamente il +suono del canto demoniaco ti gela il sangue. Per tutti gli dei della morte! In che posto sei arrivato? Per tutti gli dei del dolore, -come troverai mai la tua via d'uscita? -","貴方は聳え立つ柱の間での遭遇に動揺したが +come troverai mai la tua via d'uscita?","貴方は聳え立つ柱の間での遭遇に動揺したが よろめきながら出口らしき所に向かった。 そして視界がぼやけ始め、物が目まぐるしく回り出す... 周りの世界が崩れ、転移門の光が貴方を飲み込んだ。 @@ -6321,8 +7732,8 @@ come troverai mai la tua via d'uscita? 響いてくる。貴方は一歩踏み出し、その悪魔達の詠唱を聞き 血の気が引いた。 -全ては死神達によって! 何処から連れてこられた? -神々の苦痛から、どうやって逃げ出す方法を見出せるのか?","다주실에서의 대전 때문에 당신의 생각이 여전히 어지럽지만, 당신은 +何処から来たというのだ?死の神々よ! +苦痛の神々から、どうやって逃げ出せるだろうか?","다주실에서의 대전 때문에 당신의 생각이 여전히 어지럽지만, 당신은 출구이길 바라는 곳으로 비틀거리며 나아갔다. 모든 것이 점점 빠르게 움직이고, 당신의 눈앞이 캄캄해지기 시작한다... 당신 주변의 세상이 무너져 내리는 사이에, 차원문의 빛이 당신을 감싸 안았다. 한 줄기 빛이 @@ -6350,21 +7761,39 @@ demonisch gezang koelt je bloed. door alle goden van de dood! tot welke plaats ben je gekomen? door alle goden van de pijn, hoe zal je ooit je weg naar buiten vinden? -","Wciąż kręci ci się w głowie po twoich -potyczkach pośród hipostylu, zataczasz się -w stronę czegoś co masz nadzieję, że jest -drogą wyjścia. Wszystko wydaje się ruszać +","Sinnet ditt er fortsatt rystet etter +møtene dine i hypostylen, og du vakler +mot det du håper er en vei ut. Ting ser +ut til å bevege seg raskere og raskere, +synet ditt sløres og begynner å falme... +Mens verden kollapser rundt deg, +oppslukes du av lyset fra en teleportal. +Et lysglimt, og så klatrer du trøtt +på beina. + +Du står på toppen av et høyt tårn, og +nedenfra kommer de fordømtes skrik. +Du trer frem, og med ett får lyden av +demonisk sang blodet til å fryse i deg. +Ved alle dødens guder! hvilket sted har +du kommet til? Ved alle smertens +guder, hvordan skal du noensinne finne +veien ut?","Wciąż kręci ci się w głowie po twoich +potyczkach pośród hipostylu, chwiejnym +krokiem podążasz w stronę czegoś +co masz nadzieję, że jest drogą wyjścia. +Wszystko wydaje się ruszać szybciej i szybciej, twój wzrok się pogarsza i zaczyna zanikać... Podczas gdy dookoła ciebie świat się zawala, -blask teleportalu pochłania cię. Błysk światła -i potem ociężale stajesz na nogi. +blask portalu pochłania cię. Ociężale +stajesz na nogi. -Stoisz na szczycie wysokiej wieży i z dołu +Stoisz na szczycie wysokiej wieży, a z dołu dochodzą krzyki potępionych. Stawiasz krok naprzód i nagle demoniczny śpiew mrozi ci krew w żyłach. Na wszystkich bogów -śmierci! Do jakiego miejsca trafiłeś? +śmierci! Gdzie ty trafiłeś? Na wszytskich bogów bólu, jakim cudem w końcu znajdziesz drogę wyjścia?","Com a sua mente ainda nebulosa após seus confrontos dentro do hipostilo, @@ -6420,38 +7849,83 @@ cum vei putea ieși de aici vreodată?","Едва переведя дух пос Вашего слуха, наполняя кровь леденящим ужасом. О, боги смерти, что это за место? -О, боги боли, как выбраться из него?","Твојим умом још увек обмотаним око -твојих прошлих сусрета унутра хипостила, -ти се тетураш ка ономе чему се надаш -да је излаз напоље. Предмети се чине -да се покрећу брже и брже, твој вид -се мути и почиње нестајати... Док свет -пропада око тебе, светлост телепортала -те обухвата. Блесак светлости, и онда -се уморно пењеш на своје ноге. - -Стојиш на врху високе куле, и од доле -стижу крици проклетих. Ти корачиш напред, -и моментално звуци демонског певања леде -твоју крв. Од свих богова смрти! На какво -место си дошао? Од свих богова бола, -како ћеш ти икада наћи свој пут ка излазу?" +О, боги боли, как выбраться из него?","Једва дошавши до даха након +исцрпљујуће борбе у хипостилу, +тетурате напред у потрази излаза +из ових проклетих земаља. Одједном +се простор унаоколо почиње брзо +мењати, светло нестаје и тама Вас +обавија... + +Све се распада. Сјајан бљесак пробада +таму и портал Вас преноси у нову +стварност. За тренутак поново чврсто +стојите на ногама. + +Доспели сте на врх огромног торња. +Од поножја долазе звукови и проклетства +неког ђаволског потомка. Само корак +напред па Вам демонске чаролије +допиру до слуха, пунећи Вам крв +страховитим ужасом. + +О богови смрти, какво је ово место? +О богови бола, како се може изићи +из њега?","Ditt sinne är fortfarande i upplösning +efter dina möten i hypostylen. Du +vacklar mot vad du hoppas är en väg +ut. Saker och ting verkar gå snabbare +och snabbare, din syn suddas ut och +börjar blekna... +Medan världen kollapsar runt omkring +dig, uppslukas du av ljuset från en +teleportal. En ljusblixt, och sedan +klättrar du trött på dina fötter. + +Du står på toppen av ett högt torn, och +underifrån kommer de fördömdas skrik. +Du kliver fram, och genast får ljudet av +demonisk sång ditt blod att rysa. +Vid alla dödsgudar, till vilken plats har +du kommit? Vid alla smärtans gudar, +hur ska du någonsin hitta ut?","Zihniniz hâlâ hipostil içindeki karşı- +laşmalarınızdan dolayı sersemlemiş +durumda. Bir çıkış yolu olduğunu +umduğun şeye doğru sendeliyorsun. +Her şey gittikçe daha hızlı hareket +ediyor gibi görünüyor, görüşünüz +bulanıklaşıyor ve solmaya başlıyor... +Dünya etrafınızda çökerken, bir +ışınlanma aracının parlaklığı sizi +sarmalıyor. Bir ışık parlaması ve +ardından yorgun bir şekilde +ayağa kalkıyorsunuz. + +Yüksek bir kulenin tepesinde duru- +yorsunuz ve aşağıdan lanetlen mişlerin +çığlıkları geliyor. İleriye doğru bir adım +atıyorsun ve anında şeytani ilahilerin +sesi kanını donduruyor. +Tüm ölüm tanrıları adına! Nereye geldin +sen? Tüm acı tanrıları adına, çıkış +yolunu nasıl bulacaksın? +" "The mightiest weapons and artifacts of the ancients barely sufficed to defeat the heresiarch and his minions, but now their foul remains -lie strewn at your feet. gathering +lie strewn at your feet. Gathering the last of your strength, you prepare to enter the portal which leads from the Heresiarch's inner sanctum. Above you, the ramparts of an -immense castle loom. silent towers +immense castle loom. Silent towers and bare walls surround a single spire of black stone, which squats in the center of the castle like a -brooding giant. fire and shadow +brooding giant. Fire and shadow twist behind gaping windows, dozens of baleful eyes glaring down upon you. @@ -6470,7 +7944,23 @@ osamocenou věž z černého kamene, stojící uprostřed hradu, vypadající jako přemítající obr. Za zejícími okny tančí ohně a stíny a desítky zlověstných očí na tě zhoubně zírají. -Někde tam uvnitř nepřátelé čekají.","Die mächtigsten Waffen und Artefakte +Někde tam uvnitř nepřátelé čekají.","De mægtigste våben og artefakter fra de +gamle dage var knap nok til at besejre +Heresiarkens og hans håndlangere, men nu +ligger deres modbydelige rester spredt for +dine fødder. Du samler dine sidste kræfter +og gør dig klar til at gå ind i portalen, +der fører fra Heresiarkens indre helligdom. + +Over dig dukker voldene af et enormt slot op. +Tavse tårne og nøgne mure omgiver et enkelt +tårn af sort sten, der sidder i midten af +slottet som en grublende gigant. Ild og +skygge snor sig bag gabende vinduer, +og dusinvis af ondskabsfulde øjne stirrer +ned på dig. +Et eller andet sted indenfor venter +dine fjender...","Die mächtigsten Waffen und Artefakte der Alten reichte kaum aus um den Erzketzer und seine Schergen zu besiegen. Aber jetzt liegen ihre @@ -6565,13 +8055,33 @@ des douzaines d'yeux sinistres vous observant. Quelque part ici, vos enemis vous attendent... -",,"Le armi più potenti e gli artefatti degli +","Az ősök legerősebb fegyverei és +varázstárgyai éppen elég erősek +voltak a Főeretnek és követői +legyőzésére, és immáron a lábad előtt +hevernek szétszórva az undorító +maradványaik. Összegyűjtve maradék +erődet, belépsz a Főeretnek belső +szentélye felé vezető portálba. + +Vészjóslóan megjelennek előtted egy +kastély sáncai. Kietlen tornyok és +csupasz falak vesznek körbe egy +spirális fekete követ, mely a kastély +közepén csücsül, mint egy tűnődő +óriás. Tűz és árnyék tánca látszik egy +nyitott ablak résén keresztül, +miközben tucatnyi baljós szempár +méregetve figyel téged. + +Valahol odabent várnak +ellenlábasaid...","Le armi più potenti e gli artefatti degli antichi erano appena sufficienti per sconfiggere l'eresiarca e i suoi servi, -ma ora i loro resti di fallo giacciono -ai tuoi piedi. Raccogliendo l'ultima +ma ora i loro immondi resti giacciono +ai tuoi piedi. Con quel poco che rimane delle tue forze, ti prepari a entrare -nel portale che conduce dal santuario +nel portale che si trova nel santuario interno dell'eresiarca. Sopra di te, i bastioni di un immenso @@ -6618,9 +8128,27 @@ tientallen onheilspellende ogen die op je neer schijnen. Ergens binnenin wachten je vijanden... -","Najpotężniejsze bronie i artefakty starożytnych -ledwo wystarczyły by pokonać herezjarchę -i jego sługi, ale ich śmierdzące truchło +","De eldgamles mektigste våpen og +artefakter var knapt nok til å beseire +heresiarken og hans håndlangere, +men nå ligger deres skitne levninger +strødd for dine føtter. Du samler de +siste kreftene dine og gjør deg klar til +å gå inn i portalen som fører fra +heresiarkens indre helligdom. + +Over deg ruver vollene til en enorm +borg. Tause tårn og nakne murer +omgir et enkelt spir av svart stein, +som sitter på huk i midten av borgen +som en grublende kjempe. Ild og +skygge vrir seg bak gapende +vinduer, dusinvis av ondskapsfulle +øyne stirrer ned på deg. +Et eller annet sted der inne +venter fiendene dine...","Najpotężniejsze bronie i artefakty starożytnych +ledwo co wystarczyły, by pokonać herezjarchę +i jego sługi. Ich śmierdzące truchło pozostaje rozrzucone u twoich stóp. Zbierając swe ostatnie siły, przygotowujesz się by przejść przez portal, który prowadzi z wewnętrznego @@ -6630,7 +8158,7 @@ Nad tobą, wał ogromnego zamkowego warsztatu krawieckiego. Ciche wieże i gołe ściany otaczają pojedynczą iglicę z ciemnego kamienia, która stoi jak zadumany gigant. -Ogień i cień skręcają się za otwartymi oknami, +Ogień i cień migają za otwartymi oknami, tuziny złowrogich oczu spoglądają na ciebie. Gdzieś w środku, twoi wrogowie czekają...","As mais poderosas armas e artefatos dos Antigos quase não foram o suficiente @@ -6674,39 +8202,74 @@ tine. Undeva în interior, dușmanii te așteaptă...","Сил могущест портал внутренних покоев обители Ересиарха. -Перед Вами величественный замок. -мрачные стены с тёмными бойницами +Перед вами величественный замок. +Мрачные стены с тёмными бойницами окружают одинокую башню. Она высится за ними словно зловещий, безмолвный гигант. За смотровыми щелями дьявольского замка извиваются языки адского пламени, мелькают тени, -десятки злобных глаз смотрят на Вас +десятки злобных глаз смотрят на вас неотрывно из темноты. -Притаившиеся враги уже ждут внутри...","Најмоћније оружје и артифакти античких -народа једва да су били довољни да -поразе јересијарха и његове следбенике, -али сада њихова гадост остаје на поду -крај ваших стопала. Прикупљајући своју -последњу снагу, припремате се за улазак -на портал који води од Јересијарховог -унутрашњег храма. - -Бедеми огромног замка се назиру -изнад вас. Тихи торњеви и големи -зидови окружују јединствену спиралу -црног камена који у центру дворца -стоји као уснули гигант. Ватра и -сенка се увијају иза прозрачних прозора, -а на десетине мрачних очију вас -продиру погледом. - -Негде унутра, ваши непријатељи чекају..." +Притаившиеся враги уже ждут внутри...","Снага моћног оружја и чаролија +древних артефаката једва беше +довољно да оборите Јересијарха и +његове поданике. Њихови раскидани +остаци Вам леже под ногама. Исцрпљени +сте од битке, али сабравши остатке +своје воље улазите у портал унутрашњих +одаја Јересијарховог обивалишта. + +Пред Вама се назире величанствен +замак. Тмурне зидине с мрачним +стрелницама окружују усамљен торањ. +Уздиже се иза њих попут злосутног, +нечујног дива. Иза отвора ђаволског +замка се извијају огњени језици, +трепере сенке, гледају Вас десетине +злобних очију из таме. + +Непријатељи, чекајући Ваш долазак, +вребају унутра...","De mäktigaste vapnen och arte- +fakterna från de forntida räckte knappt +till för att besegra heresiarken och +hans hantlangare, men nu ligger deras +vidriga kvarlevor utspridda vid dina +fötter. Genom att samla dina sista +krafter förbereder du dig för att gå in i +portalen som leder från heresiarkens +inre helgedom. + +Ovanför dig skymtar vallarna till ett +enormt slott. Tysta torn och kala +väggar omger en enda spira av svart +sten, som sitter i mitten av slottet +som en grubblande jätte. Eld och +skugga vrider sig bakom gapande +fönster, dussintals ondskefulla +ögon stirrar ner på dig. +Någonstans där inne väntar dina +fiender...","Kadimlerin en güçlü silahları ve eserleri +kâfir hükümdarı ve yardakçılarını +yenmeye ancak yetti, ama şimdi onların +iğrenç kalıntıları ayaklarınızın dibine +serilmiş durumda. Son gücünüzü +toplayarak, geçide girmeye hazırlanıyor- +sunuz. Heresiark'ın iç mabedinden çıkıyor. + +Üstünüzde muazzam bir kalenin surları +yükseliyor. Sessiz kuleler ve çıplak +duvarlar, kalenin ortasına düşünceli bir +dev gibi çömelen siyah taştan tek bir +kuleyi çevreliyor. Açık pencerelerinardında +ateş ve gölge kıvrılıyor, düzinelerce +uğursuz göz size dik dik bakıyor. +İçeride bir yerlerde düşmanlarınız bekliyor..." """... and he shall journey into the realms of the dead, and contest with the forces therein, unto the very -gates of despair. but whether he +gates of despair. But whether he shall return again to the world of light, no man knows."" @@ -6725,7 +8288,17 @@ nikdo neví.“ -Zatraceně.","„... und er soll reisen in das Reich der +Zatraceně.","""... og han skal rejse ind i de dødes +riger og kæmpe med de kræfter deri, +indtil fortvivlelsens porte. +Men om han skal vende tilbage til +lysets verden igen, ved ingen."" + + + + + +Fandens.","„... und er soll reisen in das Reich der Toten und die Mächte darin bekämpfen, bis hin zu den wahrhaftigen Toren der Verzweiflung. Aber ob er @@ -6737,7 +8310,7 @@ mag niemand vorraussagen.“ Verdammt.",,"""... kaj li veturos en la regnon de la -mortinta, kaj kontraŭos la fortojn en +mortintoj, kaj kontraŭos la fortojn en tie, eĉ ĉe la pordegoj de malespero, sed neniu scias, ĉu vi revenos refoje al la mondo de lumo."" @@ -6746,7 +8319,7 @@ al la mondo de lumo."" -diable.","""... y él viajará hasta el reino +Diable.","""... y él viajará hasta el reino de los muertos y competirá contra las fuerzas que estén en él, hasta las mismísimas puertas de la @@ -6757,7 +8330,7 @@ nadie lo puede saber."" -¡Demonios!",,"""... ja hän on kulkeva kuolleitten maahan +Maldición.",,"""... ja hän on kulkeva kuolleitten maahan ja mittelöivä siellä olevain valtain kanssa peräti epätoivon porteille asti. Mutta onko hän jälleen palajava valon maailmaan, kukaan @@ -6776,7 +8349,14 @@ de la lumière, personne ne le sait. » -Merde!",,"""... Ed egli andrà nei regni dei morti, +Merde!","""...majd a hős belép a holtak +királyságába, és az ott portyázó +sereget lekaszabolja egészen a +Kétség Kapujáig. Azonban senki sem +tudja visszatér e onnan a fény +világába."" + +Francba.","""... Ed egli andrà nei regni dei morti, e si scontrerà con le forze che vi si trovano, fino alle porte stesse della disperazione. Ma se tornerà di nuovo al mondo di luce, @@ -6811,10 +8391,23 @@ naar de wereld van het licht, weet niemand."". Verdomme. -","""... i pójdzie on do świata zmarłych, i będzie +","""... og han skal reise inn i dødsrikene +og kjempe med kreftene der, helt til +fortvilelsens porter. Men om han +skal vende tilbake til lysets verden +igjen, vet ingen."" + + + + + +Pokker.","""... i pójdzie on do świata zmarłych, i będzie konkurować z tamtejszymi siłami, do samych bram rozpaczy. Ale czy on wróci znów do -świata światła, nikt nie wie.""","""...e assim deverá fazer a sua jornada +świata światła, nikt nie wie."" + + +A niech to szlag...","""...e assim deverá fazer a sua jornada pelo reino dos mortos e desafiar as forças que lá habitam, até os portões do desespero. No entanto, se retornará ou não ao mundo @@ -6846,17 +8439,37 @@ Firar să fie.","«...И сойдёт он в царство мёртвых, -Проклятье.","„...И он ће путовати у светове -мртвих, и оспорити се са тим силама, -све док не дође до саме капије очајања. -али да ли ће се икада вратити у свет -светлости, ниједан човек не зна.“ +Проклятье.","„...И отићи ће у царство мртвих, +и очистиће га од сила таме, и доћи ће +у жестокој борби до самих врата +очајавања. Да ли му је суђено да се +врати, у царство светлости, није +знано никоме...“ + + +Проклетство.",""".... och han skall resa in i de dödas +rike och tävla med krafterna där, +till själva porten till förtvivlan. +Men om han skall återvända +till ljusets värld vet ingen."" + + + + + + Fan.","""... ve ölüler diyarına yolculuk edecek +ve oradaki güçlerle umutsuzluğun +kapılarına kadar mücadele edecek. +Ama tekrar ışık dünyasına dönüp +dönmeyeceğini kimse bilemez."" -Проклетство." + + +Lanet olsun." "With a scream of agony you are wrenched from this world into another, every part of your body @@ -6864,7 +8477,7 @@ wreathed in mystic fire. When your vision clears, you find yourself standing in a great hall, filled with ghostly echoes and menacing -shadows. in the distance you can +shadows. In the distance you can see a raised dais, and upon it the only source of light in this world.",TXT_HEXEN_WIN1MSG,,,,"Se zmučeným výkřikem jsi vyrván@[ao_cs] z tohoto světa do jiného, každičký @@ -6874,7 +8487,15 @@ ohni. Když se ti navrátí zrak, zjišťuješ, strašidelnými ozvěnami a děsuplnými stíny. V dálce vidíš vyvýšené pódium a na něm jediný zdroj světla -v tomto světě.","Mit einem Schmerzensschrei wirst du +v tomto světě.","Med et skrig af smerte bliver du +revet ud af denne verden og ind i +en anden, hvor alle dele af din krop +er omgivet af mystisk ild. Da dit syn +klarer sig, står du i en stor sal, +fyldt med spøgelsesagtige ekkoer og +truende skygger. I det fjerne kan +du se en hævet platform og på den +den eneste lyskilde i denne verden.","Mit einem Schmerzensschrei wirst du aus dieser Welt in eine andere gerissen, jeder Teil deines Körpers in mystisches Feuer gehüllt. Nachdem du wieder klar @@ -6919,15 +8540,23 @@ un grand hall, rempli d'échos spectraux et d'ombres menaçantes. Plus loin, vous pouvez voir une estrade sur laquelle se trouve la seule source -de lumière dans ce monde.",,"Con un grido di agonia sei strappato da +de lumière dans ce monde.","A tested köré csavarodó tűzcsóvák +szinte kitépnek ebből a világból, a +környék csendjét csak a gyötrelmes +ordításod töri meg. Amikor látásod +kitisztul, megpillantod eme gigászi +csarnokot, mely hemzseg a szellemek +hörgésétől és fenyegető árnyaikkal. +A messzeségben megpillantasz egy +emelvényt, amelyen ragyog a vidék +egyetlen fényforrása.","Con un grido di agonia sei strappato da questo mondo in un altro, ogni parte del tuo corpo avvolto nel fuoco mistico. Quando la tua visione si libera, ti ritrovi in piedi in una grande sala, piena di echi spettrali e ombre minacciose. -In lontananza è possibile e su di essa -l'unica fonte di luce in questo mondo. -","悲痛な叫びと共に貴方は別の世界に追いやられ +In lontananza vedi una pedana e su di essa +l'unica fonte di luce in questo mondo.","悲痛な叫びと共に貴方は別の世界に追いやられ 自分の体が神秘的な炎により癒されていった。 視界が戻ると、霊の威嚇する声と影が蔓延る壮観な広間に 立っていた。遠くには盛り上がった大皿が見え、 @@ -6945,10 +8574,18 @@ schaduwen. in de verte kun je in de verte zie een verhoogde madeliefje, en daarop de enige bron van licht in deze wereld. -","Z krzykiem agonii wyrwałeś się z tego świata +","Med et skrik av smerte blir du revet +fra denne verden til en annen, hver del +av kroppen din er innhyllet i mystisk +ild. Når synet ditt klarner, befinner du +deg i en stor hall, fylt med spøkel- +sesaktige ekko og truende skygger. +I det fjerne kan du se et hevet podium, +og på det den eneste lyskilden +i denne verden.","Z krzykiem agonii wyrwałeś się z tego świata do innego, każda część twojego ciała zanużyła się w mistycznym ogniu. Kiedy odzyskujesz -wzrok, widzisz, że stoisz w wielkim hallu +wzrok, widzisz, że stoisz w wielkim holu wypełnionym echami duchów i groźnymi cieniami. W oddali widzisz podwyższone podium, a na nim jedyne źródło światła @@ -6966,32 +8603,52 @@ de foc mistic. Odată ce vederea redevine limpede, te regăsești stând într-o sală imensă, plină de ecouri fantomatice și umbre amenințătoare. În depărtare vezi un podium ridicat, și pe el, singura -sursă de lumină din această lume.","Внезапно Вас окутал огонь. -С воплем боли и страха Вы +sursă de lumină din această lume.","Внезапно вас окутал огонь. +С воплем боли и страха вы перемещаетесь в другой мир, и -каждая часть Вашего тела пронизана +каждая часть вашего тела пронизана мистическим пламенем. Видения отступили, взор снова ясен. Вы в огромном зале, наполненном призрачным эхом и грозными, неведомыми тенями. Одинокий свет струится с возвышения неподалёку -от Вас.","Са вриском агоније ви сте пренесени -са овог света до другог, сваки део вашег -тела бива обухваћен мистичном ватром. -Када се ваша визија разјасни, видите -да стојите у великој сали, испуњени -одјецима духова и застрашујућим сенкама. -У даљини можете видети подигнути подијум, -а на њему извор светлости за овај свет." +от вас.","Одједном Вас окружи огањ. +Уз врисак бола и страха +премештате се у други свет, и +сваки део Вашег тела је прожет +мистичном пламеном. Виђења +се повлаче, и поглед је поново +јасан. У огромној сте дворани, +напуњеној сабласним одјецима +и грозним, непознатим сенкама. +С уздигнутог положаја, близу Вас, +тече усамљено светло.","Med ett skrik av smärta slits du från +den här världen till en annan, varenda +del av din kropp är omgiven av +mystisk eld. När din syn klarnar +finner du dig själv stå i en stor hall, +fylld av spöklika ekon och hotfulla +skuggor. I fjärran kan du se en +upphöjd dais, och på den den +enda ljuskällan i den här världen.","Acı dolu bir çığlıkla bu dünyadan +başka bir dünyaya savruluyorsunuz, +vücudunuzun her parçası mistik bir +ateşle kaplanıyor. Görüşünüz +açıldığında, kendinizi hayaletimsi +yankılar ve tehditkâr gölgelerle dolu +büyük bir salonda buluyorsunuz. +Uzakta yükseltilmiş bir kürsü ve onun +üzerinde bu dünyadaki tek +ışık kaynağını görüyorsunuz." "This can only be the chaos sphere, the source of korax's power. with this, you can create worlds... or -destroy them. by rights of battle +destroy them. By rights of battle and conquest it is yours, and with trembling hands you reach to grasp it. Perhaps, now, a new player will -join the cosmic game of power. like +join the cosmic game of power. Like the pawn who is promoted to queen, suddenly the very reaches of the board seem to be within your grasp.",TXT_HEXEN_WIN2MSG,,,,"Toto může být jedině Sféra chaosu, @@ -7003,7 +8660,17 @@ ji uchytit. Možná, že se teď ke jsoucné hře moci přidá někdo další. Jako pěšákovi přeměněnému na královnu ti teď připadá, -že máš všechny kraje šachovnice na dosah.","Dies kann nur die Chaossphäre sein, +že máš všechny kraje šachovnice na dosah.","det kan kun være kaoskuglen, kilden til +korax' kraft. med den kan du skabe +verdener... eller ødelægge dem. I kraft +af kampens og erobringens rettigheder +er den din, og med bævende hænder +rækker du ud efter den. Måske vil en +ny spiller nu deltage i det kosmiske +spil om magt. Ligesom den bonde, der +bliver forfremmet til dronning, synes +brættets yderste rækkevidde pludselig +at være inden for din rækkevidde.","Dies kann nur die Chaossphäre sein, die Quelle von Korax' Macht. Mit ihr kannst du Welten erschaffen... oder sie zerstören. Durch Kampf und @@ -7054,16 +8721,27 @@ un nouveau joueur va rejoindre le jeu cosmique du pouvoir. Comme un pion promu au rang de reine, les extrêmités de l'échiquier sont -maintenant à votre portée.",,"Questa può essere solo la sfera del caos, +maintenant à votre portée.","Ez nem lehet más, csak a Káosz +Gömb, mely Korax hatalmának +forrása. Ezzel a hatalommal egész +világokat lehet teremteni...vagy éppen +elpusztítani őket. A győzelem jogán +immáron ez a tied, így reszkető kézzel +nyúlsz felé. Talán ezzel egy új játékos +lép be a kozmikus méretű hatalmi +játékba. Mint a sakkban a parasztból +hirtelen avanzsált királynő, egyszerre +az egész sakktábla elérhetővé vált +számodra.","Questa può essere solo la sfera del caos, la fonte del potere di Korax. Con questo, è possibile creare mondi ... O distruggerli. Con i diritti di battaglia e conquista è tuo, -e con le mani tremanti si raggiunge per afferrarlo. +e con le mani tremanti vai per afferrarlo. Forse, ora, un nuovo giocatore si unirà al gioco cosmico del potere. Come il pedone che viene promosso regina, all'improvviso -le stesse portate del tabellone +le stesse caselle della scacchiera sembrano essere alla tua portata.","カオススフィア、コラックスの魔力の源だ。 これを使えば世界を創造することが出来る...または破壊することも。 征服者の権利を得た貴方は震える手をそれに伸ばした。 @@ -7082,7 +8760,17 @@ nieuwe speler zich aansluiten bij het kosmische spel van de macht. Net als de pion die gepromoveerd is tot koningin, het hele bord is nu binnen handbereik. -","To może być tylko Sfera Chaosu, źródło mocy +","Dette kan bare være kaossfæren, +kilden til korax' kraft. med dette kan +du skape verdener... eller ødelegge +dem. Med rett til kamp og erobring +er den din, og med skjelvende hender +strekker du deg for å gripe den. +Kanskje vil en ny spiller nå bli med i +det kosmiske maktspillet. Som +bonden som blir forfremmet til +dronning, ser det plutselig ut til at +hele brettet er innen rekkevidde.","To może być tylko Sfera Chaosu, źródło mocy Korax'a. Możesz nią tworzyć światy... lub je niszczyć. Według praw walki i podboju jest twoja i drżącymi rękami próbujesz ją @@ -7109,27 +8797,54 @@ tabla e în mâinile tale.","Это сфера хаоса, источник си Коракса. С её помощью можно создавать миры... или разрушать их. Дрогнувшей рукой вы берёте её. -Теперь она Ваша по праву силы. +Теперь она ваша по праву силы. Должно быть, новый игрок теперь вступит в космическую битву за власть, хитро ведя свою партию на вселенской шахматной доске. -словно ничтожная пешка, услужающая +Словно ничтожная пешка, услужающая своему королю, и, предав его, -вышедшая в дамки.","То може бити само сфера хаоса, извор -Кораксове моћи. Овиме можете -створити светове... или их уништити. -Путем битке и освајања то је ваше, -а дрхтавим рукама грабите да га ухватите. -Можда ће се сада нови играч придружити -космичкој игри моћи. Као пешак који се -промовише у краљицу, чини се да су -изненада твоја достигнућа у вашем домету." +вышедшая в дамки.","Ово је сфера хаоса, извор Кораксове +силе. Помоћу ње се могу стварати +светови... или уништавати. Дрхтавом +руком је узимате. Сада је Ваша по +праву моћи. + +Вероватно ће се сада нови играч +придружити космичкој бици за власт, +лукаво водећи своју партију на +васељенску шаховску таблу, +попут ништавног пешака који служи +своме краљу и, издавши га, заузме +улогу краљице.","Detta kan bara vara kaos-sfären, +källan till Korax kraft. Med denna +kan du skapa världar... eller förstöra +dem. Genom stridens och erö- +vringens rättigheter är den din, och +med darrande händer sträcker du dig +för att ta tag i den. Kanske kommer +nu en ny spelare att ansluta sig till +det kosmiska spelet om makt. Likt +en bonde som befordras till drottning +verkar plötsligt brädans yttersta +räckvidd vara inom räckhåll för dig.","Bu sadece Korax'ın gücünün kaynağı +olan kaos küresi olabilir. Bununla +dünyalar yaratabilirsin... ya da onları +yok edebilirsin. Savaş ve fetih +haklarıyla sizindir ve titreyen ellerinizle +onu kavramak için uzanırsınız. Belki +de şimdi, kozmik güç oyununa yeni +bir oyuncu katılacak. Vezirliğe terfi +eden piyon gibi, aniden tahtanın en +uç noktaları avucunuzun içindeymiş +gibi görünür." "\nbut there are other players mightier than you, and who can know their next moves?",TXT_HEXEN_WIN3MSG,,,,"\nAle jsou tu i jiní hráči, mocnější než ty, -a kdo může předvídat jejich další tahy?","\nAber es gibt andere Spieler, die +a kdo může předvídat jejich další tahy?","\nmen der er andre spillere, der er +mægtigere end dig, og hvem kan +kende deres næste træk?","\nAber es gibt andere Spieler, die mächtiger sind als du, und wer kann schon deren nächste Züge erahnen?",,"\nTamen, estas aliaj ludantoj pli @@ -7141,35 +8856,43 @@ mahtavampia, ja kuka voi tietää heidän seuraavat liikkeensä?","Mais il y a encore des joueurs plus puissants que vous encore, et qui peut prédire ce qu'ils feront pendant -leur tour?",,"\nMa ci sono altri giocatori più potentidi te, +leur tour?","\nvannak ám nagyobb hatalmú +játékosok is, és ki tudná előre a +következő lépésüket?","""\nMa ci sono altri giocatori più potenti di te, e chi può conoscere le loro prossime mosse? -","\nしかし貴方より上手の挑戦者はいる、 +""","\nしかし貴方より上手の挑戦者はいる、 そして誰が彼らの一手を読めるだろうか?","\n하지만 분명 어딘가에 당신보다 강력한 도전자들이 있을 것이며, 그 누가 그들의 수를 짐작할 수 있겠는가?","\nmaar er zijn andere spelers machtiger dan jij, en wie kan hun volgende stappen kennen? -","\nAle są też inni gracze silniejsi od ciebie, +","\Men det finnes andre spillere som er +mektigere enn deg, og hvem kan +vite deres neste trekk?","\nAle są też inni gracze silniejsi od ciebie, a kto może znać ich następne ruchy?","\nMas existem outros jogadores mais poderosos do que você. E quem sabe quais são os seus próximos movimentos?",,"\ndar mai există și alți jucători care sunt mai puternici decât tine, și cine le-ar putea anticipa următoarele mișcări?","\n...Но есть более опытные игроки, и -кому ведомы их дальнейшие ходы?","\nАли постоје и други играчи моћнији -од вас, и ко може знати њихове -следеће потезе?" -"wiping a trembling hand across your +кому ведомы их дальнейшие ходы?","\nАли постоје и искуснији играчи, +а коме су познати њихови даљњи +потези?","Men det finns andra spelare som +är mäktigare än du, och vem kan +känna till deras nästa drag?","\nAma senden daha güçlü başka +oyuncular da var. +Sonraki hamleler?" +"Wiping a trembling hand across your bleeding face, you try to clear your mind for what lies ahead... ...and forget what lies behind. -in the distance, the stark ramparts +In the distance, the stark ramparts of a great castle complex seem to rend the sky above, and the stench of decay wafts from the violated graves of uncounted dead. -carefully counting what little +Carefully counting what little remains of your artifacts, you try to reassure yourself that it will be enough. after all, it has to be @@ -7188,7 +8911,7 @@ rend the sky above, and the stench of decay wafts from the violated graves of uncounted dead. -carefully counting what little +Carefully counting what little remains of your artefacts, you try to reassure yourself that it will be enough. after all, it has to be @@ -7214,7 +8937,22 @@ ubezpečit sebe sama, že to bude stačit. Konec konců, musí to stačit, nebo ne? -Nebo ne?","Mit zitternden Händen wischst du dir +Nebo ne?","Du tørrer en rystende hånd hen over +dit blødende ansigt og forsøger at gøre +dig klar til det, der venter forude... + +...og glemme, hvad der ligger bagved. + +I det fjerne ser det ud til, at de +barske volde af et stort slotskompleks +river himlen op, og stanken af +forrådnelse vifter fra de krænkede +grave af utallige døde. + +Du tæller omhyggeligt de få rester af +dine artefakter og forsøger at forsikre +dig selv om, at det vil være nok. det +må trods alt være nok, ikke sandt?","Mit zitternden Händen wischst du dir über dein blutiges Gesicht und versuchst, einen klaren Kopf für das zu bekommen, was vor dir liegt... @@ -7311,20 +9049,40 @@ essayez de vous rassurer. Cela suffira, après tout, cela doit suffir, n'est-ce pas? -N'est-ce pas?",,"Spazzandosi una mano tremante sul tuo viso +N'est-ce pas?","Megtörlöd még mindig reszkető +kezeddel a véres homlokod, és +próbálod kitisztítani a gondolataidat, +hogy rájöjj mi jön most... + +...egyuttal próbálod elfelejteni mi is +történt. + +A messzi távolban megpillantod a +komor körvonalú kastély sáncait, mely +olyan magas hogy szinte széthasítja +az eget. Az elmúlás szaga terjeng a +meggyalázott sírokban fekvő +megszámlálhatatlan holttestből. + +Óvatosan megszámolva maradék +erekjéidet, próbálod magad biztatni, +hogy elég lesz. Végülis elégnek +kellene lennie, ugye? + +...ugye?","Spazzandosi una mano tremante sul tuo viso sanguinante, cerchi di liberare la mente da ciò che ti aspetta... ...e dimenticare cosa c'è dietro. In lontananza, gli aspri bastioni di un -grande complesso castellano sembrano -rendere il cielo in alto, e l'odore di -decadenza si diffonde dalle tombe -violate di morti non contesi. - -Contare con attenzione ciò che poco -rimane dei vostri manufatti, cercate di -rassicurarvi che sarà sufficiente. +grande complesso del castello +sembrano spezzare il cielo, e l'odore di +decadimento si diffonde dalle tombe +violate di innumerevoli morti. + +Dopo aver controllato ciò che poco +rimane dei tuoi manufatti, cerchi di +rassicurarti che sarà sufficiente. Dopo tutto, deve essere sufficiente, non è vero? @@ -7373,7 +9131,26 @@ verzekeren dat het genoeg zal zijn. het moet toch genoeg zijn, nietwaar? Nietwaar? -","Wycierając drżącą ręką swoją zakrwawioną +","Du stryker en skjelvende hånd over det +blødende ansiktet og prøver å klarne +tankene for det som ligger foran deg... + +...og glemme det som ligger bak. + +I det fjerne ser det ut til at de nakne +vollene til et stort slottskompleks +flenger himmelen over deg, og stanken +av forråtnelse svever fra de krenkede +gravene til utallige døde. + +mens du nøye teller det lille som er +igjen av gjenstandene dine, prøver du +å forsikre deg selv om at det vil være +nok. det må tross alt være nok, +ikke sant? + + +ikke sant?","Wycierając drżącą ręką swoją zakrwawioną twarz, próbujesz przygotować swój umysł na to co leży przed tobą... @@ -7385,8 +9162,8 @@ nad tobą, i fetor ulatnia się z naruszonych grobów niezliczonej śmierci . Ostrożnie licząc co zostało z twoich artefaktów, -próbujesz upewnić się, że wystarczy. W końcu -musi wystarczyć, prawda? +próbujesz upewnić się czy ci ich starczy. +W końcu musi wystarczyć, prawda? Prawda?","Passando a mão trêmula pelo seu @@ -7415,12 +9192,12 @@ continuare... ...și să uiți ce ai lăsat în urmă. În depărtare, meterezele unui falnic castel par -să spintece cerul de deasupra, iar mirosul +să spintece cerul, iar mirosul decadenței se răspândește de la mormintele profanate ale nenumăraților morți. Numărând atent ce mai rămâne din artefactele tale, -încerci să te reasiguri ca vor fi suficiente. Până la +încerci să te reasiguri că vor fi suficiente. Până la urmă, vor trebui să fie de ajuns, nu-i așa? @@ -7430,7 +9207,7 @@ Nu-i așa?","Отерев кровь с лица дрожащей рукой, ...и забыть ужас, оставшийся позади. -Вдали, в легкой дымке, виден +Вдали, в лёгкой дымке, виден величественный замок, подпирающий небо своими мрачными башнями. От разоренных могил веет зловонием @@ -7453,16 +9230,51 @@ Nu-i așa?","Отерев кровь с лица дрожащей рукой, Пажљиво бројите шта ти је остало од артефакта и пробате се поново уверити да ће бити довољно. На крају крајева, треба да буде довољно, је ли тако? -Је ли тако?" -"surely the souls of the damned inhabit +Је ли тако?","Du stryker en darrande hand över ditt +blödande ansikte och försöker rensa +ditt sinne för det som väntar dig... + +...och glömma det som ligger bakom. + +I fjärran tycks de karga vallarna till +ett stort slottsanläggning slita sönder +himlen ovanför, och stanken av +förruttnelse vajar från de våldtagna +gravarna av oräkneliga döda. + +När du noggrant räknar det som +återstår av dina artefakter försöker du +försäkra dig själv om att det kommer +att räcka. Det måste ju räcka, eller hur? + + + eller hur?","Titreyen elinizi kanayan yüzünüze silerek, +önünüzdekiler için zihninizi temizlemeye +çalışıyorsunuz... + +...ve geride kalanları unutmaya çalışıyorsun. + +Uzakta, büyük bir kale kompleksinin sert +surları gökyüzünü parçalıyor gibi görünüyor +ve sayısız ölünün ihlal edilmiş mezar- +larından çürümenin pis kokusu yayılıyor. + +Eserlerinizden geriye kalanları dikkatlice +sayarak, her şeyin yolunda gideceğine +dair kendinizi rahatlatmaya çalışıyorsunuz. +Yeterli olacaktır. Yeterli, değil mi? + + +Değil mi?" +"Surely the souls of the damned inhabit this world, for nothing fair or good could survive here for long. -but what has passed before can only +But what has passed before can only be a pale shadow of what bars your passage now: the dark citadel itself. -the grim bulk of the cathedral blocks +The grim bulk of the cathedral blocks all but fragmentary glimpses of the citadel proper, but what can be seen speaks in sibilant whispers of cold, @@ -7476,7 +9288,7 @@ lingering death... tento svět, neboť nic bohulibého tu nemá šanci dlouho přežít. -Vše, čím jsi doteď prošel, však +Vše, co jsi doteď překonal@[ao_cs], však bledne v porovnání s tím, co ti nyní zahrazuje cestu: temná citadela sama. @@ -7490,7 +9302,25 @@ syčí a šeptá o vleklé, studené smrti... -...pro ty šťastlivé.","Es sind sicherlich die Seelen der +...pro ty šťastlivé.","De fordømtes sjæle bor sikkert i denne +verden, for intet godt eller +retfærdigt kan overleve her længe. + +Men det, der er gået før, kan kun +være en bleg skygge af det, der +spærrer din passage nu: selve +det mørke citadel. + +Katedralens dystre masse blokerer alt +andet end fragmentariske glimt af selve +citadellet, men det, der kan ses, taler +med hvislende hvisken om kold, +dvælende død... + + + + +...for de heldige.","Es sind sicherlich die Seelen der Verdammten, die diese Welt be- wohnen, denn nichts Gutes oder Ehrliches könnte hier lange überleben. @@ -7597,23 +9427,38 @@ de mort.. -...pour les fortunés.",,"Sicuramente le anime dei dannati abitano +...pour les fortunés.","Az már biztos számodra, hogy miután +csak az átkozottak lakják a vidéket, +semmiféle jó nem maradhat életben. + +Ami azonban eddig történt veled, +csak egy halvány árnyéka az +elkövetkezendőnek: maga a Sötét +Fellegvár. + +A katedrális izmos építőköveitől csak +futó pillantást tudsz vetni a fellegvárra +a repedéseken keresztül, de a látottak +sziszegő hideg suttogásról és sóvár +halálról tanuskodnak... + + +...a szerencsésebbeknek.","Sicuramente le anime dei dannati abitano questo mondo, perché niente di giusto -o buono potrebbe sopravvivere a lungo. +o buono potrebbe sopravvivere a lungo qui. -Ma ciò che è passato prima non può +Ma ciò che hai passato prima non può che essere una pallida ombra di ciò -che impedisce il vostro passaggio ora: -la scura cittadella stessa. +che blocca il tuo passaggio ora: +la stessa Cittadella Oscura. -La cupa mole della cattedrale blocca -tutti gli scorci, ma frammentari, ma -ciò che si può vedere parla in -sibilanti sussurri di morte -fredda e persistente... +La cupa mole della cattedrale fa si che +solo scorci frammentari della cittadella +stessa si possano vedere, ma ciò che +tu puoi vedere parla insibilanti sussurri +di morte fredda e persistente... -...per i fortunati. -","この世界には地獄に堕とされた善人や親切であろう +...per i fortunati.","この世界には地獄に堕とされた善人や親切であろう 人々の魂が居着いている。 しかし通過する際には前方を遮る薄いもやでしかない @@ -7651,24 +9496,42 @@ te zien is spreekt in sibilant gefluister van de koude, slepende dood... ...voor de gelukkigen. -","Dusze potępionych na pewno zamieszkują -ten świat, za coś uczciwego lub dobrego -nic nie mogłoby przetrwać tu tak długo. +","Sjelene til de fordømte bebor sikkert +denne verden, for ingenting rettferdig +eller godt kan overleve her lenge. + +Men det som har passert før kan bare +være en blek skygge av det som +sperrer passasjen din nå: det +mørke citadellet selv. + +katedralens dystre masse blokkerer +alt annet enn fragmentariske glimt av +selve citadellet, men det som kan sees, +taler i hviskende hvisker om kald, +dvelende død... + + + + +...for de heldige.","Dusze potępionych na pewno zamieszkują +ten świat, coś uczciwego i dobrego +nie mogłoby przetrwać tu tak długo. Ale co przyszło wcześniej, może być tylko wyblakłym cieniem tego co zagradza ci drogę: sama mroczna cytadela. Ponura masa bloków katedry to tylko -częściowe przebłyski właściwej cytadeli, ale -to co może być ujrzane mówi świszczącymi +część właściwej cytadeli, ale już +to co widzisz mówi świszczącymi szeptami zimnej, powolnej śmierci... -...dla szczęściarzy.","Certamente as almas dos condenados +...którą tylko szczęściarze mogą skończyć.","Certamente as almas dos condenados habitam este mundo, pois nada bom ou justo poderia sobreviver aqui por muito tempo. @@ -7686,7 +9549,7 @@ morte fria e prolongada... -...para os fortunados.",,"Cu siguranță că sufletele blestemaților habituează +...para os fortunados.",,"Cu siguranță că sufletele blestemaților populează această lume, considerând faptul că nimic drept și bun nu poate supraviețui aici pentru multă vreme. @@ -7697,7 +9560,7 @@ slabă față de ceea ce îți blochează calea acum: Groasele blocuri ale catedralei stopează totul, mai puțin întrezăririle citadelei însăși, dar ceea ce poate fi văzut vorbesțe doar în șoapte siflante ale -lentei, recii morți... +lentei, reci morți... @@ -7705,9 +9568,9 @@ lentei, recii morți... мир, ибо ничто доброе и справедливое не может здесь выжить. -Страдания, пережитые Вами, — ничто, +Страдания, пережитые вами, — ничто, бледная тень тех испытаний, что ждут -в тёмной цитадели, стоящей на Вашем +в тёмной цитадели, стоящей на вашем пути. Силуэт тёмной цитадели едва виден за @@ -7736,13 +9599,47 @@ lentei, recii morți... -...за срећнике." -"once again you find yourself in the +...за срећнике.","Säkert bor de fördömdas själar i denna +värld, för inget rättvist eller gott skulle +kunna överleva här länge. + + Men det som har passerat tidigare +kan bara vara en blek skugga av det +som hindrar din passage nu: själva +det mörka citadellet. + +Katedralens dystra massa blockerar +alla utom fragmentariska glimtar av +själva citadellet, men det som kan ses +talar i svischande viskningar om kall, +kvardröjande död... + + + + + + ...för de lyckligt lottade.","kesinlikle lanetlenmişlerin ruhları bu +dünya, hiçbir şey için adil ya da iyi +burada uzun süre hayatta kalabilirdi. + +ama daha önce geçenler sadece soluk +bir gölge olacak Şimdi geçit: Karanlık +kalenin kendisi. + +Katedral bloklarının acımasız kütlesi +parçalı bakışlar dışında ama +görülebilenler soğuk fısıltılarla +konuşuyor, kalıcı ölüm. + + + +...talihliler için." +"Once again you find yourself in the great hall of the chaos sphere, as if no time had passed from when last you moved among these shadows. -but something is eerily different, +But something is eerily different, a silence where once had been soft whispers, a sense of being watched by hidden eyes... @@ -7758,7 +9655,18 @@ se předtím ozýval nehlasný šepot, se nyní line jen ticho a pocit toho, že nať spočívají skryté oči... -...oči, jež skrývají zlé úmysly.","Wieder findest du dich in der großen +...oči, jež skrývají zlé úmysly.","Du befinder dig igen i kaoskuglens store +hal, som om der ikke er gået nogen tid +siden sidste gang, du bevægede dig +blandt disse skygger. + +Men noget er uhyggeligt anderledes, en +stilhed, hvor der før var bløde +hviskener, en følelse af at blive +overvåget af skjulte øjne... + +... øjne, der skjuler en +ondskabsfuld hensigt.","Wieder findest du dich in der großen Halle der Chaossphäre, als wenn seit dem letzten Mal, als du dich zwischen diesen Schatten bewegtest, keine Zeit @@ -7780,7 +9688,7 @@ Silento tie, kie estis mallaŭtaj flustroj, sento, ke mi estas observata de kaŝitaj okuloj... -...Okuloj, kioj ŝildas malican celon.","Una vez más te encuentras en el +...Okuloj, kiuj ŝildas malican celon.","Una vez más te encuentras en el gran salón de la esfera del caos, como si no hubiera pasado el tiempo desde la última vez que @@ -7819,25 +9727,35 @@ d'être observé par des yeux tapis dans l'ombre.. ..des yeux dissimulant des -maléfiques volontés.",,"Ancora una volta ti ritrovi nella +maléfiques volontés.","Újra a Káosz Gömb csarnokában +találod magad ugyanazon árnyékok +között, mintha megállt volna itt az idő. + +Egy hátborzongató különbség +azonban jelentős. Gyanús csönd +váltotta fel a korábbi lágy suttogást, +árgus szemek figyelik minden +lépésed... + +...szemek melyek mögött gonosz +szándék lapul.","Ancora una volta ti ritrovi nella grande sala della sfera del caos, -come se non fosse passato alcun tempo +come se non fosse passato alcun istante da quando per l'ultima volta ti sei mosso tra queste ombre. Ma c'è qualcosa di diverso, un silenzio -dove un tempo si sussurrava dolcemente, +dove un tempo vi erano deboli sussurri, un senso di essere osservati da occhi nascosti... -...occhi che proteggono un intento malefico. -","貴方は今一度、あたかも最後の時が止まったままである +...occhi che proteggono un intento malefico.","貴方は今一度、あたかも最後の時が止まったままである カオススフィアの影の広間に立った。 しかしかつては柔らかい囁きによる静かな場所だったが 何か影から不気味な視線がある。 -...悪意を遮蔽する目線が。","다시 한번 당신은 혼돈의 구체가 있는 회당에 이르렀다. 마치 당신이 처음 +...悪意を遮蔽する目が。","다시 한번 당신은 혼돈의 구체가 있는 회당에 이르렀다. 마치 당신이 처음 이곳의 그림자에 발을 들인 이후로 아무런 일도 없었다는 듯이 말이다. 그러나 무언가가 기분 나쁘게 달라졌다. 부드러운 속삭임이 들리던 곳에서는 @@ -7855,16 +9773,28 @@ een gevoel van door verborgen ogen bekeken te worden... ...ogen die een kwaadaardige bedoeling verbergen. -","Po raz kolejny znajdujesz się w wielkim hallu +","Nok en gang befinner du deg i kaos- +sfærens store sal, som om det ikke +hadde gått noen tid siden sist du +beveget deg blant disse skyggene. + +...men noe er uhyggelig annerledes, +en stillhet der det en gang var stille +hvisking, en følelse av å bli iakttatt +av skjulte øyne... + +...øyne som skjuler en ondskapsfull +...onde hensikter.","Po raz kolejny znajdujesz się w wielkim holu Sfery Chaosu tak, jakby wogóle czas nie upłynął od kiedy ostatnio się poruszałeś pośród tych cieni. -Ale jest tu znacznie inaczej. Cisza, w której kiedyś -było słychać ciche szepty, a także uczucie bycia -obserwowanym przez ukryte oczy... +Ale jest tu zupełnie inaczej. Kiedyś +słychać było ciche szepty, a teraz tylko cisza +i także uczucie bycia obserwowanym +przez ukryte oczy... -...oczy któte skrywają zgubne zamiary.","Mais uma vez você se encontra no +...oczy które skrywają zgubne zamiary.","Mais uma vez você se encontra no grande salão da Esfera do Caos, como se não tivesse passado tempo nenhum desde a última vez que você passou no @@ -7886,7 +9816,7 @@ ești urmărit de ochi ascunși... ...ochi care ascund intenții nefaste.","Вы вновь в зале сферы хаоса. Ничего Не изменилось здесь с последнего -Вашего посещения. время застыло. +вашего посещения. время застыло. И всё же... Тихий шёпот в темноте. Вы чувствуете, что невидимые @@ -7902,15 +9832,36 @@ ești urmărit de ochi ascunși... било тихо шапутање, осећај да вас неко посматра скривеним очима... -...очи које штите злобну намеру." -"once before you grasped the chaos +...очи које штите злобну намеру.","Ännu en gång befinner du dig i den +stora salen i kaos-sfären, som om +ingen tid hade gått sedan du senast +rörde dig bland dessa skuggor. + +Men något är kusligt annorlunda, +en tystnad där det en gång hade +varit mjuka viskningar, en känsla +av att bli iakttagen av dolda ögon... + +...ögon som skyddar en ondskefull +avsikt.","Kendinizi bir kez daha kaos küresinin +büyük salonu üzerinden hiç zaman +geçmemiş olsaydı en son bu gölgeler +arasında hareket etmiştin. + +Ama bir şeyler ürkütücü bir şekilde +farklı, bir zamanlar yumuşak fısıltıların +olduğu yerde bir sessizlik, gizli gözler +tarafından izlenme hissi... + +...kötücül bir niyeti koruyan gözler." +"Once before you grasped the chaos sphere, held it within trembling hands. now your hands tremble with something more than avarice, and dread meshes with the hunger for power. -if even the power of the sphere is +If even the power of the sphere is not enough to protect you from the forces of darkness, perhaps it is better left untouched, its promise @@ -7918,7 +9869,7 @@ left unkept. -but then, you never were one to +But then, you never were one to back down from a challenge...",TXT_HEXDD_WIN2MSG,,,,"Jen jednou předtím jsi spočinul@[ao_cs] své ruce na Sféře chaosu a držel@[ao_cs] ji ve svých třesoucích se dlaních. @@ -7934,7 +9885,20 @@ a její přísliby nenaplněné. Na druhou stranu, ty jsi arci nikdy -nebyl@[ao_cs] někdo, kdo by se ostal výzvy...","Schon einmal hast du die Chaossphäre +nebyl@[ao_cs] někdo, kdo by se ostal výzvy...","Førhen greb du fat i kaossfæren, holdt +den i dine bævende hænder. nu bæver dine +hænder af noget mere end grådighed, +og frygt blander sig med hunger eftermagt. + +Hvis selv kuglens magt ikke er nok til +at beskytte dig mod mørkets kræfter, +er det måske bedre at lade den forblive +urørt, og dens løfte forblive uindfriet. + + +Men du har jo aldrig været en af dem, +der har vendt tilbage fra en +udfordring...","Schon einmal hast du die Chaossphäre in deinen zitternden Händen gehalten. Doch dieses mal erzittert du durch mehr als nur Gier, denn Furcht vermischt sich @@ -8007,21 +9971,33 @@ des mains de tous, ses promesses laissées à l'abandon. Mais vous n'êtes pas le type de -personne à avoir peur d'un défi..",,"Una volta che avete afferrato la sfera -del caos, l'avete tenuta in mani tremanti. +personne à avoir peur d'un défi..","Korábban félelemtől reszkető kézzel +fogtad a gömböt, most azonban a +hatalomtól megrészegedve reszketsz. +Úgy érzed maga a hatalom fog tőrbe +csalni. + +Ha ez a mérhetetlenül óriási hatalom +sem teljesen elég arra, hogy +megvédjen a sötétség erőitől, talán +érdemes békében hagyni és +megszegni a gömbnek tett ígéreted. + +Mindazonáltal, sosem voltál olyan, aki +könnyen kihátrál a kihívás elől...","Quando avevi afferrato precedentemente +la sfera del caos, l'avevi tenuta tremando. Ora le tue mani tremano con qualcosa di più che avarizia, e la paura si intreccia con la fame di potere. Se anche il potere della sfera -non è sufficiente a proteggervi dalla +non è sufficiente a proteggerti dalla le forze delle tenebre, forse è meglio lasciarla intatta, la sua promessa non mantenuta. Ma poi, non sei mai stato uno -che si è tirato indietro da una sfida... -","貴方はカオススフィアを掴む前に、一度震える手を握りしめた。 +che si tira indietro da una sfida...","貴方はカオススフィアを掴む前に、一度震える手を握りしめた。 今この手は貪欲に何かを超える権力を渇望している。 スフィアの魔力でさえ貴方を暗黒の軍勢から守護するのに 十分でないならば、恐らくそれに手を出さなければ、 @@ -8049,19 +10025,33 @@ beter om hem onaangeroerd te laten en zijn belofte onbewaakt te laten. Maar dan, je was er nooit een om je terug -te trekken van een uitdaging...","Jak już zdołałeś chwycić Sferę Chaosu, trzymałeś +te trekken van een uitdaging...","en gang før grep du kaos-sfæren, holdt +den i skjelvende hender. nå skjelver +hendene dine av noe mer enn +grådighet, og frykt blander seg +med hungeren etter makt. + +hvis ikke engang sfærens kraft er nok +til å beskytte deg mot mørkets krefter, +er det kanskje bedre å la den stå +urørt, la løftet stå uinnfridd. + + + +men så har du aldri vært den som +har veket tilbake for en utfordring...","Jak już zdołałeś chwycić Sferę Chaosu, trzymałeś ją przy sobie swoimi drżącymi rękami. Teraz twoje ręce trzęsą się z czegoś więcej niż chciwości, a strach miesza się z głodem siły. -Jeśli nawet siła Sfery nie jest wystarczająca, by +Nawet jeśli siła Sfery nie jest wystarczająca, by cię chronić przed siłami ciemności, może lepiej będzie zostawić ją nietkniętą i nie decydować się na jej obietnice. -Ale wtedy nie byłeś tym co miał się wycofać +Nie byłeś jednak tym co miał się wycofać z wyzwania... ","Você já tinha pego a Esfera do Caos anteriormente, segurando-a em suas @@ -8091,9 +10081,9 @@ neținută. Dar apoi, tu n-ai fost niciodată cineva care să se -dea înlături de la o provocare...","Когда-то Вы уже владели сферой +dea înlături de la o provocare...","Когда-то вы уже владели сферой хаоса и держали её в трепещущих -руках. Теперь Ваши руки дрожат не +руках. Теперь ваши руки дрожат не только от алчности, и чувство ужаса сливается с жаждой власти. @@ -8101,11 +10091,11 @@ dea înlături de la o provocare...","Когда-то Вы уже владели защитить вас от демонов тьмы, может быть, не следует брать её? Ведь её истинное предназначение осталось -для Вас тайной. +для вас тайной. -И всё же, Вы не устоите перед +И всё же, вы не устоите перед искушением и примете вызов...","Једном пре сте зграбили сферу хаоса дрхтећим рукама. Сада ваше руке дрхте са нечим што је више од похлепе, и ужасне мреже које су @@ -8117,2235 +10107,2635 @@ dea înlături de la o provocare...","Когда-то Вы уже владели Али још увек, нисте били од оних који се повлаче од изазова... -" +","En gång i tiden greppade du kaos- +sfären, höll den i darrande händer. Nu +darrar dina händer av något mer än +girighet, och rädsla förenas med +hunger efter makt. + +Om inte ens sfärens kraft är tillräcklig +för att skydda dig från mörkrets krafter +är det kanske bättre att lämna den +orörd, att inte hålla dess löfte. + + + +Men du var aldrig den som +backade från en utmaning...","Bir zamanlar kaos küresini kavradın, +titreyen ellerinde tuttun. şimdi ellerin +açgözlülükten daha fazla bir şeyle +titriyor ve dehşet güç açlığıyla birleşiyor. + +Küreni̇n gücü bi̇le seni̇ karanliğin +güçleri̇nden korumaya yetmi̇yorsa, +belki̇ de dokunulmamasi, vaadi̇ni̇n +tutulmamasi daha i̇yi̇di̇r. + + + +Ama sen hiçbir zaman meydan +okumalardan geri adım atan biri +olmadın..." "\n...and other players await. -",TXT_HEXDD_WIN3MSG,,,,\n...a ostatní hráči už čekají.,\n...und andere Spieler warten.,,\n...kaj aliaj ludantoj atendas.,\n...y otros jugadores esperan.,,\n...ja muut pelaajat odottavat.,\n...Et d'autres joueurs attendent.,,\n...e altri giocatori aspettano.,"\n...更なる挑戦者を待ち構えながら。 +",TXT_HEXDD_WIN3MSG,,,,\n...a ostatní hráči už čekají.,\n...og andre spillere venter.,\n...und andere Spieler warten.,,\n...kaj aliaj ludantoj atendas.,\n...y otros jugadores esperan.,,\n...ja muut pelaajat odottavat.,\n...Et d'autres joueurs attendent.,"\n...és a többi játékos a te +lépésedre vár.",\n...e altri giocatori aspettano.,"\n...更なる挑戦者を待ち構えながら。 -",\n...그리고 다른 도전자들이 기다리고 있다.,\n...en andere spelers wachten op je.,\n...a inni gracze czekają.,\n...e os outros jogadores aguardam.,,\n...și alți jucători așteaptă.,"\n...В то время как другие игроки будут +",\n...그리고 다른 도전자들이 기다리고 있다.,\n...en andere spelers wachten op je.,"\n... og andre aktører venter. + +",\n...a inni gracze czekają.,\n...e os outros jogadores aguardam.,,\n...și alți jucători așteaptă.,"\n...В то время как другие игроки будут ждать своего часа, чтобы совершить свой ход.","\n...и други играчи вас чекају. +",\n... och andra spelare väntar.,"\n...ve diğer oyuncular bekliyor. + " -,,Hexen script texts,,,,,,,,,,,,,,,,,,,,, -The door is locked,TXT_ACS_MAP01_5_THEDO,,,,Dveře jsou zamčené.,Die Tür ist verschlossen,,La pordo estas ŝlosita.,La puerta está cerrada,,Ovi on lukittu,Cette porte est verouillée.,Az ajtó zárva van.,La porta è bloccata,扉は施錠されている,문이 잠겨 있다,De deur is op slot,Drzwi są zablokowane,A porta está trancada,,Ușa e încuiată,Дверь заблокирована,Врата су закључана -"Greetings, mortal",TXT_ACS_MAP02_9_GREET,,,,"Vítej, smrtelníče,","Sei gegrüßt, Sterblicher",,"Salutojn, mortemul'.","Saludos, mortal",,"Tervehdys, kuolevainen","Salutations, humain.","Üdvözöllek, halandó!","Salve, mortale",御機嫌よう、小僧,"환영한다, 필멸자여.","Groeten, sterfelijk",Witaj śmiertelniku,"Saudações, mortal",,"Salutări, muritorule","Приветствую, смертный","Поздрав, смртниче" -Are you ready to die?,TXT_ACS_MAP02_11_AREYO,,,,jsi připraven@[ao_cs] zemřít?,Bist du bereit zu sterben?,,Ĉu vi pretas morti?,¿Estás listo para morir?,,Oletko valmis kuolemaan?,Êtes-vous prêt à mourir?,Készen állsz a halálra?,Sei pronto a morire?,死に急ぐ仕度は整ったか?,죽을 준비는 됐는가?,Ben je klaar om te sterven?,Czy jesteś gotów na śmierć?,Você está pront@[ao_ptb] para morrer?,,Ești pregătit să mori?,Готов ли ты умереть?,Да ли си спреман за смрт? -A door opened on the Guardian of Ice,TXT_ACS_MAP02_20_ADOOR,,,,U strážce ledu se otevřely dveře.,Eine Tür öffnet sich zum Wächter des Eises,,Pordo malfermiĝis ĉe la Gardanto de Glacia.,Se abrió una puerta en el Guardián de Hielo,,Ovi avautui jään vartijan luona,Une porte s'est ouverte dans le Gardien de Glace.,,Una porta è stata aperta sul Guardiano di Ghiaccio,氷の守護者にある扉は開かれた,얼음의 수호자에서 문이 열렸다,Een deur opende op de bewaker van ijs,Drzwi przy Strażniku Lodu otworzyły się,Uma porta se abriu no Guardião de Gelo,,O ușă s-a deschis pe Gardianul de Foc,Дверь открыта у Стража льда,Врата су се отворила на Чувару леда -This path is barred,TXT_ACS_MAP03_12_THISP,,,,Cesta je zatarasená.,Dieser Pfad ist blockiert,,Ĉi vojo estas barita.,Este camino está atrancado,,Tämä polku on teljetty,Ce chemin est barré.,,Questo percorso è sbarrato,この道は塞がれている,이 통로는 빗장이 걸려있다,Dit pad is geblokkeerd,Ścieżka jest zablokowana,Este caminho está bloqueado,,Această cale e blocată,Сейчас этот путь закрыт,Овај пут је забрањен -One half of the puzzle has been solved,TXT_ACS_MAP04_9_ONEHA,,,,Jedna polovina rébusu byla vyřešena,Eine Hälfte des Rätsels wurde gelöst,,Unu duono de la puzlo estas solvita,Una mitad del acertijo se ha resuelto,,Puolet pulmasta on ratkaistu,La moitié du puzzle à été résolu,A rejtvény egyik fele meg lett fejtve,Metà del puzzle è stato risolto,パズルの一つが解かれた,수수께끼의 절반이 풀렸다,De helft van de puzzel is opgelost,Połowa zagadki rozwiązana,Metade do quebra-cabeça foi resolvido,,O jumătate din puzzle e rezolvată,Половина головоломки разгадана,Једна половина загонетке је решена -on the Seven Portals,TXT_ACS_MAP04_10_ONTHE,,,,u Sedmera portálů.,bei den Sieben Portalen,,ĉe la Sep Portaloj.,en los Siete Portales,,seitsemän portaalin luona,pour les Sept Portails.,a Hét Portálon,nei Sette Portali,漆之門に影響を与えた,... 일곱 차원문에서,op de Zeven Portalen,przy Siedmiu Portalach,nos Sete Portais,,pe cele Șapte Portaluri,на Семи порталах,на Седам портала -One third of the puzzle has been solved,TXT_ACS_MAP04_11_ONETH,,,,Jedna třetina rébusu byla vyřešena,Ein Drittel des Rätsels wurde gelöst,,Unu triono de la puzlo estas solvita,Un tercio del acertijo se ha resuelto,,Kolmannes pulmasta on ratkaistu,Un tiers du puzzle à été résolu,A rejtvény egyharmada megfejtődött,Un terzo del puzzle è stato risolto,三種のパズルの一つが解かれた,수수께끼의 3분의 1이 풀렸다,Een derde van de puzzel is opgelost,Jedna trzecia zagadki rozwiązana,Um terço do quebra-cabeça foi resolvido,,O treime din puzzle a fost rezolvată,Треть головоломки разгадана,Једна трећина загонетке је решена -Stairs have risen on the Seven Portals,TXT_ACS_MAP04_12_STAIR,,,,u Sedmera portálů.,Stufen bei den Sieben Portale wurden erbaut,,Ŝtupoj leviĝis ĉe la Sep Portaloj.,Unas escaleras se han erguido en los Siete Portales,,Portaat ovat kohonneet seitsemän portaalin luona,Des escaliers sont apparus dans les Sept Portails.,,Sono sorte le scale nei Sette Portali,漆之門に階段が立ち昇った,일곱 차원문에서 계단이 솟아났다,Trappen zijn gestegen op de Zeven Portalen,Schody przy Siedmiu Portalach podniosły się,As escadas se ergueram nos Sete Portais,,S-au ridicat scări pe cele Șapte Portaluri,Лестница воздвигнется на Семи порталах,Степенице су се подигле између Седам портала -One third of the puzzle has been solved,TXT_ACS_MAP05_6_ONETH,,,,Jedna třetina rébusu byla vyřešena,Ein Drittel des Rätsels wurde gelöst,,Unu triono de la puzlo estas solvita,Un tercio del acertijo se ha resuelto,,Kolmannes pulmasta on ratkaistu,Un tiers du puzzle à été résolu,A rejtvény egyharmada meg lett fejtve,Un terzo del puzzle è stato risolto,三種のパズルの一つが解かれた,수수께끼의 3분의 1이 풀렸다,Een derde van de puzzel is opgelost,Jedna trzecia zagadki rozwiązana,Um terço do quebra-cabeça foi resolvido,,O treime din puzzle a fost rezolvată,Треть головоломки разгадана,Једна трећина загонетке је решена -on the Seven Portals,TXT_ACS_MAP05_7_ONTHE,,,,u Sedmera portálů.,bei den Sieben Portalen,,ĉe la Sep Portaloj.,en los Siete Portales,,seitsemän portaalin luona,pour les Sept Portails.,A Hét Portálon belül,nei Sette Portali,漆之門 に影響を与えた,... 일곱 차원문에서,op de Zeven Portalen,przy Siedmiu Portalach,nos Sete Portais,,pe cele Șapte Portaluri,на Семи порталах,на Седам портала -Stairs have risen on the Seven Portals,TXT_ACS_MAP05_8_STAIR,,,,Schody se zvedly u Sedmera portálů.,Stufen bei den Sieben Portale wurden erbaut,,Ŝtupoj leviĝis ĉe la Sep Portaloj.,Unas escaleras se han erguido en los Siete Portales,,Portaat ovat kohonneet seitsemän portaalin luona,Des escaliers sont apparus dans les Sept Portails.,A Hét Portálon belül egy lépcsősor emlekedett,Sono sorte le scale nei Sette Portali,漆之門 に階段が立ち昇った,일곱 차원문에서 계단이 솟아났다,Trappen zijn gestegen op de Zeven Portalen,Schody przy Siedmiu Portalach podniosły się,Escadas se ergueram nos Sete Portais,,S-au ridicat scări pe cele Șapte Portaluri,Лестница воздвигнется на Семи порталах,Степенице су се подигле између Седам портала -You have to find another switch...,TXT_ACS_MAP05_9_YOUHA,,,,Musíš najít další spínač.,Du must einen weiteren Schalter finden...,,Vi bezonas trovi alian ŝaltilon...,Debes encontrar otro interruptor...,Debes encontrar otro switch...,Sinun on löydettävä toinen vipu...,Vous devez trouver un autre bouton..,Egy másik kapcsolót kell találnod,Devi trovare un altro interruttore...,他のスイッチも探す必要がある...,다른 개폐기를 찾아야 한다,Je moet een andere schakelaar vinden...,Musisz znaleźć inny przełącznik...,Você precisa encontrar outro interruptor...,,Trebuie să găsești alt buton...,Остался ещё один переключатель...,Требате наћи још један прекидач... -Stones grind on the Seven Portals,TXT_ACS_MAP05_10_STONE,,,,Kameny dřou u Sedmera portálů.,Steine schleifen bei den Sieben Portalen,,Ŝtonoj grincas ĉe la Sep Portaloj.,Las piedras giran en los Siete Portales,,Kiviä vierii seitsemän portaalin luona,Des pierres grincent dans les Sept Portails.,,Le pietre si sono frantumate nei Sette Portali,漆之門 の石壁が砕かれた,일곱 차원문에서 바위 부딪히는 소리가 들려왔다,Stenen slijpen op de Zeven Portalen,Kamienie przy Siedmiu Portalach zgrzytają,As pedras giram nos Sete Portais,,Pietrele încep să macine pe cele Șapte Portaluri,каменная преграда отступила,Камени се мељу на Седам портала -One sixth of the puzzle has been solved,TXT_ACS_MAP08_6_ONESI,,,,Jedna šestina rébusu byla vyřešena,Ein Sechstel des Rätsels wurde gelöst,,Unu sesono de la puzlo estas solvita,Un sexto del acertijo se ha resuelto,,Kuudennes pulmasta on ratkaistu,Un sixième du puzzle à été résolu,A feladványok egyhatoda meg lett fejtve,Un sesto del puzzle è stato risolto,六種のパズルの一つが解かれた,수수께끼의 6분의 1이 풀렸다,Een zesde van de puzzel is opgelost,Jedna szósta zagadki rozwiązana,Um sexto do quebra-cabeça foi resolvido,,O șesime din puzzle a fost rezolvată,Одна шестая головоломки разгадана,Једна шестина загонетке је решена -on the Shadow Wood,TXT_ACS_MAP08_7_ONTHE,,,,v Temném hvozdu.,Im Schattenwald,,en la Ombro-arbareto.,En el Bosque de Sombras,,Varjosalossa,dans le Bois des Ombres.,A Sötét Erdőben,Nel Bosco d'Ombra,陰影樹 に少し影響を与えた,... 그림자 숲에서,op het Schaduwbos,w Lesie Cieni,na Floresta das Sombras,,în Pădurea Umbrelor,в Лесу теней,у Шуми сена -The door is barred from the inside,TXT_ACS_MAP08_10_THEDO,,,,Dveře jsou zatarasené zevnitř.,Die Tür ist von innen verriegelt,,La pordo estas barita interne.,La puerta está atrancada desde el interior,,Ovi on teljetty sisältä,Cette porte est bloquée de l'intérieur.,Az ajtó el van reteszelve belülről,La porta è sbarrata da dentro,この扉は内側から塞がれている,이 문은 안에 빗장이 걸려있다,De deur is van binnenuit geblokkeerd.,Drzwi są zabarykadowane od środka,A porta está barrada por dentro,,Ușa e blocată dinăuntru,Дверь заблокирована изнутри,Врата су закључана изнутра -You hear a door open in the distance,TXT_ACS_MAP08_11_YOUHE,,,,Slyšíš v dálce otevírající se dveře.,"Du hörst, wie sich in der Ferne eine Tür öffnet",,Vi aŭdas pordon malfermiĝantan malproksime.,Escuchas que una puerta se abre a la distancia,,Kuulet oven avautuvan etäällä,Vous entendez une porte s'ouvrir au loin.,Hallod ahogy ajtó nyílik a távolban,Senti una porta aprirsi a distanza,遠くから扉が開く音が聞こえる,멀리서 문이 열리는 소리가 들린다,In de verte hoor je een deur openstaan.,Słyszysz odgłos otwierających się w oddali drzwi,Você ouve de longe uma porta se abrindo,,Auzi o ușă deschizându-se în depărtare,Слышен звук открывающейся двери,Чује се отварање врата из даљине -One sixth of the puzzle has been solved,TXT_ACS_MAP09_6_ONESI,,,,Jedna šestina rébusu byla vyřešena,Ein Sechstel des Rätsels wurde gelöst,,Unu sesono de la puzlo estas solvita,Un sexto del acertijo se ha resuelto,,Kuudennes pulmasta on ratkaistu,Un sixième du puzzle à été résolu,A feladványok egyhatoda meg lett fejtve,Un sesto del puzzle è stato risolto,六種のパズルの一つが解かれた,수수께끼의 6분의 1이 풀렸다,Een zesde van de puzzel is opgelost,Jedna szósta zagadki rozwiązana,Um sexto do quebra-cabeça foi resolvido,,O șesime din puzzle a fost rezolvată,Одна шестая головоломки разгадана,Једна шестина загонетке је решена -on the Shadow Wood,TXT_ACS_MAP09_7_ONTHE,,,,v Temném hvozdu.,Im Schattenwald,,en la Ombro-arbareto.,En el Bosque de Sombras,,Varjosalossa,dans le Bois des Ombres.,A Sötét Erdőben,Nel Bosco d'Ombra,陰影樹 に少し影響を与えた,... 그림자 숲에서,op het Schaduwbos,w Lesie Cieni,na Floresta das Sombras,,în Pădurea Umbrelor,в Лесу теней,у Шуми сена -One sixth of the puzzle has been solved,TXT_ACS_MAP10_6_ONESI,,,,Jedna šestina rébusu byla vyřešena,Ein Sechstel des Rätsels wurde gelöst,,Unu sesono de la puzlo estas solvita,Un sexto del acertijo se ha resuelto,,Kuudennes pulmasta on ratkaistu,Un sixième du puzzle à été résolu,A feladványok egyhatoda meg lett fejtve,Un sesto del puzzle è stato risolto,六種のパズルの一つが解かれた,수수께끼의 6분의 1이 풀렸다,Een zesde van de puzzel is opgelost,Jedna szósta zagadki rozwiązana,Um sexto do quebra-cabeça foi resolvido,,O șesime din puzzle a fost rezolvată,Одна шестая головоломки разгадана,Једна шестина загонетке је решена -on the Shadow Wood,TXT_ACS_MAP10_7_ONTHE,,,,v Temném hvozdu.,Im Schattenwald,,en la Ombro-arbareto.,En el Bosque de Sombras,,Varjosalossa,dans le Bois des Ombres.,A Sötét Erdőben,Nel Bosco d'Ombra,陰影樹 に少し影響を与えた,... 그림자 숲에서,op het Schaduwbos,w Lesie Cieni,na Floresta das Sombras,,în Pădurea Umbrelor,в Лесу теней,у Шуми сена -\ ettins left,TXT_ACS_MAP11_0_ETTIN,"rus -Нужно придумать что-то получше.",,,\ etinů zbývá.,\ Ettins übrig,,\ aĉgigantoj ceteraj,\ Ettins restantes,,\ ettiniä jäljellä,\ ettins restants,\ az ettonek feladják,\ Ettins rimasti,\ 匹のエティンが残っている,\ 마리 에틴이 남았음,\ overgebleven Ettins,\ pozostałych ettinów,\ ettins restantes,,\ etini rămași,\ оставшихся эттинов,\ еттина је остало -"You waited too long, now you die!",TXT_ACS_MAP11_1_YOUWA,,,,"Čekal@[ao_cs] jsi moc dlouho, teď zemřeš!","Du hast zu lange gewartet, jetzt stirbst du!",,"Vi atendis tro longe, nun vi mortos!","Esperaste demasiado, ¡ahora morirás!",,"Odotit liian pitkään, nyt kuolet!","Vous avez attendu trop longtemps, maintenant, mourrez!","Sokáig vártál, most meghalsz!","Hai atteso troppo a lungo, ora muori!",長居をしたな、命を奪うには十分な程に!,시간을 너무 오래 끌었다. 이제 죽어라!,"Je hebt te lang gewacht, nu ga je dood!",Czekałeś zbyt długo. Teraz giń!,Você esperou demais. Agora morrerá!,,"Ți-a luat prea mult, acum mori!",Слишком долго! Готовься к смерти!,Предуго си чекао! Припреми се за смрт! -A door opened on the Forsaken Outpost,TXT_ACS_MAP11_7_ADOOR,,,,Dveře se otevřely na Opuštěném stanovišti.,Eine Tür im verlassenen Vorposten hat sich geöffnet,,Pordo malfermiĝis ĉe la Forlasita Posteno.,Una puerta se abrió en el Puesto de Avanzada Abandonado,,Ovi avautui hylätyssä etuvartiossa,Une porte s'est ouverte dans la base abandonnée.,Az Elhagyot Őrállás ajtaja kinyilt.,Una porta è stata aperta nell'Avamposto Abbandonato,荒れ果てた前哨地 への扉が開いた,버려진 초소에서 문이 열렸다,Een deur opende een deur op de Verwaarloosde buitenpost,Drzwi przy Opuszczonym Posterunku otworzyły się,Uma porta se abriu no Posto Abandonado,,O ușă s-a deschis pe Avanpostul Părăsit,Дверь открылась на покинутой заставе,Врата су се отворила у Напуштеној постаји -This door won't open yet,TXT_ACS_MAP12_9_THISD,,,,Tyto dveře se ještě neotevřou.,Die Tür öffnet sich noch nicht,,Ĉi pordo ne jam malfermiĝos.,Esta puerta no se abrirá todavía,,Tämä ovi ei aukea vielä,Cette porte ne s'ouvre pas pour l'instant.,Ez az ajtó még nem fog kitárulni.,Questa porta non è aperta ancora,扉はまだ開かない,이 문은 아직 열 수 없다,Deze deur gaat nog niet open.,Te drzwi jeszcze się nie otwierają,Esta porta não se abrirá ainda,,Ușa n-o să se deschidă încă,Сейчас эта дверь закрыта,Ова врата још се не отварају -"My servants can smell your blood, human",TXT_ACS_MAP13_11_MYSER,,,,"Mí služebníci cítí tvou krev, člověče.","Meine Diener riechen dein Blut, Menschling",,"Miajn servantoj povas flari vian sangon, homo.","Mis sirvientes pueden oler tú sangre, humano",,"Palvelijani voivat haistaa veresi, ihminen","Mes servants peuvent sentir votre sang, humain.","Szolgáim érzik a véred szagát, ember","I miei servi possono annusare il tuo sangue, umano",我が下僕が貴様の血を嗅ぎ付けた様だぞ、小童,"이 몸의 하인들은 네 피 냄새를 맏고 따라온다, 인간.","Mijn bedienden kunnen jouw bloed ruiken, mens",Moje sługi czują twą krew śmiertelniku,"Meus servos sentem o cheiro do seu sangue, human@[ao_ptb]",,"Servitorii mei îți pot adulmeca sângele, muritorule","Мои прислужники чуют твою кровь, человек","Моје слуге миришу твоју крв, смртниче" -A door opened in the Gibbet,TXT_ACS_MAP21_0_ADOOR,,,,Dveře se otevřely na Šibenici.,Eine Tür in der Richtstätte wurde geöffnet,,Pordo malfermiĝis ĉe la Pendigilo.,Una puerta se abrió en la horca,,Ovi avautui hirsipuulla,Une porte s'est ouverte dans le gibet.,,Una porta è stata aperta nella Forca,晒し台 への扉が開いた,교수대에서 문이 열렸다,Een deur geopend in de Gibbet,Drzwi przy Szubienicy otworzyły się,Uma porta se abriu na Forca,,O ușă s-a deschis pe Eșafod,Проход будет открыт возле виселицы,Врата су се отворили у вешалима -The door is barred from the inside,TXT_ACS_MAP21_2_THEDO,,,,Dveře jsou zatarasené zevnitř.,Die Tür ist von innen verriegelt,,La pordo estas barita interne.,La puerta está atrancada desde el interior,,Ovi on teljetty sisältä,Cette porte est bloquée de l'intérieur.,,La porta è sbarrata da dentro,この扉は内側から塞がれている,이 문은 안에 빗장이 걸려있다,De deur is van binnenuit geblokkeerd.,Drzwi są zabarykadowane od środka,A porta está barrada por dentro,,Ușa e blocată dinăuntru,Дверь заблокирована изнутри,Врата су закључана изнутра -A platform has lowered in the tower,TXT_ACS_MAP22_3_APLAT,,,,Plošina ve věži sjela dolů.,Im Turm hat sich eine Plattform gesenkt,,Plataĵo malleviĝis en la turo.,Una plataforma ha bajado en la torre,,Lava on laskeutunut tornissa,Une plateforme est descendue dans la tour.,,Una piattaforma si è abbassata nella torre,塔内の昇降機が下りた,성 안에서 보행판이 내려왔다,Een platform is in de toren neergelaten in de toren,Platforma w wieży obniżyła się,Uma plataforma desceu na torre,,O platformă a coborât în turn,Площадка опустилась в центральной башне,Спустио се платформ у централној кули -"You have played this game too long, mortal...",TXT_ACS_MAP22_27_YOUHA,,,,"Tuhle partii jsi už hrál@[ao_cs] moc dlouho, smrtelníče,","Du spielst schon zu lange, Sterblicher...",,"Ludis ĉi ludon vi tro longe, mortemul'...","Has jugado este juego demasiado tiempo, mortal...",,"Olet pelannut tätä peliä liian pitkään, kuolevainen...","Vous avez joué à ce jeu trop longtemps, mortel..","Túl sokat játszadoztál, halandó...","Ha giocato a questo gioco troppo a lungo, mortale...",遊びはここまでだ、小僧,"네 놈은 오랫동안 놀았도다, 필멸자여...","Je hebt dit spel te lang gespeeld, sterfelijke...",Już za długo grasz w tą grę śmiertelniku...,"Você jogou este jogo por tempo demais, mortal...",,"Ai jucat acest joc prea multă vreme, muritorule...","Ты слишком заигрался, смертный...","Заиграо си се, смртниче..." -I think I shall remove you from the board,TXT_ACS_MAP22_29_ITHIN,,,,"myslím, že bych tě měl odstranit ze šachovnice.",Ich denke ich sollte dich vom Brett entfernen,,"Mi kredas, ke mi vin forigos el la tabul'.",Creo que te retiraré del tablero,,Ajattelenpa poistaa sinut pelilaudalta,Je pense qu'il est l'heure de vous retirer de l'échiquier.,"Azt hiszem le kell, hogy üsselek a tábláról",Penso che ti rimuoverò dal tavolo da gioco,盤上から貴様を排除する,이 몸이 너를 말 치우듯이 제거하겠다.,Ik denk dat ik u van het bord zal verwijderen,"Myślę, że usunę cię z planszy",Acho que irei removê-l@[ao_ptb] do tabuleiro,,Cred că e timpul să te înlătur de pe tablă,Пришло время завершить твою партию,Мислим да би требао да те уклоним са листе -You hear a door open upstairs,TXT_ACS_MAP23_10_YOUHE,,,,Z patra slyšíš otevírající se dveře.,"Du hörst, wie sich oben eine Tür öffnet",,Vi aŭdas pordon malfermiĝantan superŝtupare.,Escuchas una puerta que se abre arriba,,Kuulet oven avautuvat yläkerrassa,Vous entendez une porte s'ouvrir à l'étage.,Hallod ahogy ajtó nyílik az emeleten,Senti una porta aprirsi a distanza,上層階の扉が開いた,윗층에서 문이 열리는 소리가 들린다,Je hoort een deur boven opengaan,Słyszysz odgłos otwierających się na górze drzwi,Você ouve uma porta se abrir lá em cima,,Auzi o ușă deschizându-se sus,Из северного зала доносится звук,Чује се отварање врата на горњем спрату -"Worship me, and I may yet be merciful",TXT_ACS_MAP27_8_WORSH,,,,"Uctívej mě a ještě možná budu milosrdný,",Verehre mich und ich könnte gnädig sein,,"Kultu min, tiam mi ankoraŭ eble kompatos.","Adórame, y aun puedo ser misericordioso",,"Palvo minua, ja saatan vielä olla armahtavainen","Prosternez vous devant moi, et je pourrai considérer de vous épargner.","Hódolj be, és talán kegyelmes leszek","Venerami, e potrei essere ancora misericordioso",我を崇めろ、慈悲を残している内に,"이 몸에게 경배하라, 그럼 자비를 베풀 것이다.","Aanbid me, en ik mag dan nog genadig zijn","Wielb mnie, a może będę miłosierny","Venere-me, e eu poderei ser piedoso",,"Venerează-mă, și s-ar putea să mai fiu milostiv încă","Преклонись предо мной, и, может быть, я буду милосерден","Преклони се преда мноме, и можда ћу бити милостив" -"Then again, maybe not",TXT_ACS_MAP27_10_THENA,,,,"na druhou stranu, možná ne.","Andererseits, vielleicht aber auch nicht",,"Tamen, eble ne.","Aunque, tal vez no",,"Mutta toisaalta, ehken sittenkään",Quoi que cela soit peu probable.,"Aztán megint, talán nem","Poi di nuovo, forse no",まあ、有り得ないな,허나... 그러지는 않겠지.,"Maar nogmaals, misschien niet","Z drugiej strony, może nie...","Pensando melhor, talvez não",,"Dar apoi, poate că nu","А может быть, и нет",А можда и нећу -One ninth of the puzzle has been solved,TXT_ACS_MAP28_6_ONENI,,,,Jedna devítina rébusu byla vyřešena,Ein Neuntel des Rätsels wurde gelöst,,Unu naŭono de la puzlo estas solvita,Un noveno del acertijo se ha resuelto,,Yhdeksäsosa pulmasta on ratkaistu,Un neuvième du puzzle à été résolu,A rejtvény egy kilencede meg lett fejtve.,Un nono del puzzle è stato risolto,九種のパズルの一つが解かれた,수수께끼의 9분의 1이 풀렸다,Een negende van de puzzel is opgelost.,Jedna dziewiąta zagadki rozwiązana,Um nono do quebra-cabeça foi resolvido,,O noime din puzzle a fost rezolvată,Одна девятая головоломки разгадана,Једна деветина загонетке је решена -On the Monastery,TXT_ACS_MAP28_7_ONTHE,,,,v Klášteře.,Im Kloster,,en la Monaĥejo.,En el Monasterio,,luostarissa,dans le monastère.,A Monostorban,Nel Monastero,修道院 にわずかに影響を与えた,... 헤러시아크의 신학교에서,Op het klooster,w Klasztorze,No Mosteiro,,pe Mănăstire,в Семинарии Ересиарха,у манастиру -One ninth of the puzzle has been solved,TXT_ACS_MAP30_6_ONENI,,,,Jedna devítina rébusu byla vyřešena,Ein Neuntel des Rätsels wurde gelöst,,Unu naŭono de la puzlo estas solvita,Un noveno del acertijo se ha resuelto,,Yhdeksäsosa pulmasta on ratkaistu,Un neuvième du puzzle à été résolu,A rejtvény egy kilencede megvan.,Un nono del puzzle è stato risolto,九種のパズルの一つが解かれた,수수께끼의 9분의 1이 풀렸다,Een negende van de puzzel is opgelost.,Jedna dziewiąta zagadki rozwiązana,Um nono do quebra-cabeça foi resolvido,,O noime din puzzle a fost rezolvată,Одна девятая головоломки разгадана,Једна деветина загонетке је решена -On the Monastery,TXT_ACS_MAP30_7_ONTHE,,,,v Klášteře.,Im Kloster,,en la Monaĥejo.,En el Monasterio,,luostarissa,dans le monastère.,,Nel Monastero,修道院 にわずかに影響を与えた,... 헤러시아크의 신학교에서,Op het klooster,w Klasztorze,No Mosteiro,,pe Mănăstire,в Семинарии Ересиарха,у манастиру -One ninth of the puzzle has been solved,TXT_ACS_MAP34_1_ONENI,,,,Jedna devítina rébusu byla vyřešena,Ein Neuntel des Rätsels wurde gelöst,,Unu naŭono de la puzlo estas solvita,Un noveno del acertijo se ha resuelto,,Yhdeksäsosa pulmasta on ratkaistu,Un neuvième du puzzle à été résolu,Egy kilencede a rejtvénynek kész.,Un nono del puzzle è stato risolto,九種のパズルの一つが解かれた,수수께끼의 9분의 1이 풀렸다,Een negende van de puzzel is opgelost.,Jedna dziewiąta zagadki rozwiązana,Um nono do quebra-cabeça foi resolvido,,O noime din puzzle a fost rezolvată,Одна девятая головоломки разгадана,Једна деветина загонетке је решена -On the Monastery,TXT_ACS_MAP34_2_ONTHE,,,,v Klášteře.,Im Kloster,,en la Monaĥejo.,En el Monasterio,,luostarissa,dans le monastère.,,Nel Monastero,修道院 にわずかに影響を与えた,... 헤러시아크의 신학교에서,Op het klooster,w Klasztorze,No Mosteiro,,pe Mănăstire,в Семинарии Ересиарха,у манастиру -The portal has been sealed,TXT_ACS_MAP35_0_THEPO,,,,Portál byl zapečeťen.,Das Portal wurde versiegelt,,La portalo estas obturita.,El portal se ha sellado,,Portaali on sinetöity,Le portail est scellé.,Az átjáró bezárult.,Il portale è stato sigillato,ポータルは封印された,차원문은 봉인되었다,Het portaal is verzegeld,Portal został zapieczętowany,O portal foi selado,,Portalul a fost închis,Врата закрылись,Портал је затворен -Choose your fate,TXT_ACS_MAP35_1_CHOOS,,,,Vyber si svůj osud.,Wähle dein Schicksal,,Elektu vian fatalon.,Escoge tu destino,Escoge tú destino,Valitse kohtalosi,Choisissez votre sort.,Dönts sorsod felöl,Scegli la tua sorte,運命を撰べ,그대의 운명을 정해라,Kies uw lot,Wybierz swoje przeznaczenie,Escolha o seu destino,,Alegeți destinul,Сделай свой выбор,Изабери своју судбину -The door is barred from the inside,TXT_ACS_MAP35_3_THEDO,,,,Dveře jsou zatarasené zevnitř.,Die Tür ist von innen verriegelt,,La pordo estas barita interne.,La puerta está atrancada desde el interior,,Ovi on teljetty sisältä,Cette porte est bloquée de l'intérieur.,Az ajtót belülről torlaszolták el.,La porta è sbarrata da dentro,この扉は内側から塞がれている,이 문은 안에 빗장이 걸려있다,De deur is van binnenuit geblokkeerd.,Drzwi są zabarykadowane od środka,A porta está barrada por dentro,,Ușa e blocată dinăuntru,Дверь заблокирована изнутри,Врата су закључана изнутра -Are you strong enough,TXT_ACS_MAP35_12_AREYO,,,,Jsi dost siln@[adj_cs],Bist du stark genug,,Ĉu vi estas sufiĉe forta,Eres lo suficientemente fuerte,,Olet riittävän vahva,Etes vous suffisamment fort,Elég erős vagy,Sei forte abbastanza,お前がどれだけ強かろうと,네 놈은 주인들을 대면할 힘이...,Ben je sterk genoeg,Czy jesteś wystarczająco silny,Você é forte o suficiente,,Ești întradevăr suficient de puternic,"Достаточно ли ты силён,",Да ли си довољно снажан -To face your own masters?,TXT_ACS_MAP35_14_TOFAC,,,,čelit svým vlastním pánům?,Dich deinen eigenen Meistern zu stellen?,,por stari kontraŭ viaj propraj mastroj?,¿Para enfrentarte a tus maestros?,,kohtaamaan omat mestarisi?,pour faire face à vos maîtres?,Hogy saját mestereiddel nézz szembe?,Per affrontare i tuoi stessi maestri?,お前の師に立ち向かえるのか?,진심으로 있는 것인가?,Om je eigen meesters onder ogen te komen?,By stawić czoła swoim mistrzom?,Para enfrentar os seus próprios mestres?,,Să îți înfrunți proprii stăpâni?,чтобы сразиться со своими наставниками?,да се суочиш са својим господарима? -,,Hexen: Deathkings script texts,,,,,,,,,,,,,,,,,,,,, -You dare battle in the ready room?,TXT_ACS_MAP33_6_YOUDA,,,,Ty si dovoluješ rvát se v přípravné místnosti?,Du wagst es im Bereitschaftsraum zu kämpfen?,,Vi aŭdacas batali en la pretĉambro?,¿Te atreves a luchar en la sala de preparación?,,Kuinka kehtaat taistella valmistautumishuoneessa?,Vous osez faire escarmouche dans la salle de préparation?,,Hai il coraggio di combattere nella sala di aspetto?,挑戦する準備は整ったか?,감히 준비의 방에서 전투를 벌이다니...,Durf jij te vechten in de readyroom?,Śmiesz walczyć w pokoju przygotowań?,Como ousa batalhar na sala de espera?,,Îndrăznești să lupți în camera de așteptare?,Ты посмел сражаться в комнате ожидания?,Усуђујеш се борити у припремној соби? -"For that, you shall die!",TXT_ACS_MAP33_7_FORTH,,,,Pro to zemřeš!,Dafür sollst du sterben!,,"Pro tio, vi mortos!","Por eso, ¡Deberás morir!",,Siitä hyvästä kuolet!,"Pour cette insulte, vous trépasserez!",Ezért meghalsz!,"Per quello, morirai!",ならば、死へ進め!,죽어서 값을 치러라!,Daarvoor zal je sterven!,Umrzesz za to!,"Por causa disso, deverá morrer!",,"Pentru asta, vei muri!",Так умри же!,За то ћеш умрети! -The waterfall is open,TXT_ACS_MAP41_6_THEWA,,,,Vodopád je otevřen.,Der Wasserfall ist geöffnet,,La akvofalo estas malferma.,La cascada se ha abierto,,Vesiputous on auki,La cascade s'est ouverte.,A vizesés nyitva,La cascata è aperta,滝 は開いた,폭포가 멈췄다,De waterval is open,Wodospad jest otwarty,A cascata está aberta,,Cascada e deschisă,Поток воды остановлен,Водопад је отворен -The waterfall is blocked,TXT_ACS_MAP41_7_THEWA,,,,Vodopád je zatarasen.,Der Wasserfall ist blockiert,,La akvofalo estas barita.,La cascada está bloqueada,,Vesiputous on tukittu,La cascade est bloquée.,A vizesés zárva,La cascata è bloccata,滝 は塞がっている,폭포에 의해 막혔다,De waterval is geblokkeerd,Wodospad jest zablokowany,A cascata está bloqueada,,Cascada e închisă,Поток воды преграждает путь,Водопад је блокиран -A door has opened in the chapel,TXT_ACS_MAP41_8_ADOOR,,,,Dveře se otevřely v kapli.,Eine Tür in der Kapelle hat sich geöffnet,,Pordo malfermis en la kapelo.,Una puerta se abrió en la Capilla,,Ovi on avautunut kappelissa,Une porte s'est ouverte dans la chapelle.,Egy ajtó tárult ki a kápolnában,Una porta si è aperta nella cappella,庵寺 への扉が開いた,교외 근처에서 문이 열렸다,Een deur is geopend in de kapel,Drzwi w kaplicy zostały otwarte,Uma porta se abriu na capela,,O ușă s-a deschis în capelă,Дверь открылась в часовне,Врата су се отворила у катедрали -Now that's odd...,TXT_ACS_MAP42_4_NOWTH,,,,Tak to je divné…,Hm. Das ist merkwürdig...,,Nun tio estas stranga...,Eso es extraño...,,Onpa kummallista...,Ca c'est étrange....,Most ez különös...,Ora questo è strano...,何かがおかしい...,무언가가 이상하다...,Dat is vreemd....,Dziwne...,Que estranho...,,Asta e ciudat...,Как странно...,То је чудно... -Three more parts of the puzzle remain,TXT_ACS_MAP44_1_THREE,,,,Zbývají tři části rébusu.,Drei weitere Teile des Rätsels verbleiben,,Nur tri partoj de la puzlo restas.,Quedan tres partes más del acertijo,,Kolme pulman palasta jäljellä,Trois parties du puzzle restent à résoudre.,Három rész maradt a rejtvényből,Rimangono altre tre parti del puzzle,パズルの部品は残り 3つ,3개의 수수께끼가 아직 풀리지 않았다,Er blijven nog drie onderdelen van de puzzel over,Pozostały jeszcze trzy części zagadki,Faltam mais três partes do quebra-cabeça,,Trei părți din puzzle încă rămân,Осталось три части головоломки,Остају још три дела загонетке -Two more parts of the puzzle remain,TXT_ACS_MAP44_2_TWOMO,,,,Zbývají dvě části rébusu.,Zwei weitere Teile des Rätsels verbleiben,,Nur du partoj de la puzlo restas.,Quedan dos partes más del acertijo,,Kaksi pulman palasta jäljellä,Deux parties du puzzle restent à résoudre.,Kettő rész maradt a rejtvényből,Rimangono altre due parti del puzzle,パズルの部品は残り 2つ,2개의 수수께끼가 아직 풀리지 않았다,Twee andere delen van de puzzel blijven over,Pozostały jeszcze dwie części zagadki,Faltam mais duas partes do quebra-cabeça,,Două părți din puzzle încă rămân,Осталось две части головоломки,Остају још два дела загонетке -One more part of the puzzle remains,TXT_ACS_MAP44_3_ONEMO,,,,Zbývá jedna část rébusu.,Ein weiteres Teil des Rätsels ist übrig,,Nur unu parto de la puzlo restas.,Queda una parte más del acertijo,,Yksi pulman palanen jäljellä,Il reste une partie du puzzle à résoudre.,Egy rész maradt a rejtvényből,Rimane un'altra parte del puzzle,パズルの部品は残り 1つ,마지막 수수께끼가 아직 풀리지 않았다,Nog een deel van de puzzel blijft over,Pozostała jeszcze jedna część zagadki,Falta mais uma parte do quebra-cabeça,,O parte din puzzle încă rămâne,Осталась одна часть головоломки,Остаје још један део загонетке -The puzzle is complete,TXT_ACS_MAP44_4_THEPU,,,,Rébus je kompletní.,Das Rätsel ist abgeschlossen,,La puzlo estas kompleta.,El acertijo está completo,,Pulma on ratkaistu,Le puzzle est résolu.,A rejtvény megoldódott,Il puzzle è completo,パズルは完成した,모든 수수께끼가 풀렸다,De puzzel is compleet,Zagadka ukończona,O quebra-cabeça está completo,,Puzzle-ul e rezolvat,Головоломка разгадана,Загонетка је решена -You have not completed the puzzle,TXT_ACS_MAP44_6_YOUHA,,,,Nesplnil jsi rébus.,Du hast das Rätsel noch nicht gelöst,,Vi ne kompletis la puzlon.,No has completado el acertijo,,Et ole ratkaissut pulmaa,Vous n'avez pas résolu le puzzle.,Nem fejtetted meg a rejtvényt,Non hai completato il puzzle,パズルはまだ完成していない,모든 수수께끼를 풀지 못했다,Je hebt de puzzel nog niet voltooid.,Nie ukończyłeś zagadki,Você não completou o quebra-cabeça,,Nu ai rezolvat puzzle-ul,Головоломка не разгадана,Нисте решили загонетку -The floor is not safe!,TXT_ACS_MAP44_8_THEFL,,,,Podlaha není bezpečná!,Der Boden hier ist nicht sicher!,,La planko ne estas sendanĝera!,¡El suelo no es seguro!,,Kerros ei ole turvallinen!,Le sol est dangereux!,A padló nem biztonságos!,Il pavimento è pericoloso!,この場は安全ではない!,이 층은 안전하지 않다!,De vloer is niet veilig!,Ta podłoga nie jest bezpieczna!,O chão não está seguro!,,Podeaua nu e sigură!,Пол совсем прогнил!,Под није безбедан! -One third of the puzzle is solved,TXT_ACS_MAP44_10_ONETH,,,,Jedna třetina rébusu je vyřešena.,Ein Drittel des Rätsels ist gelöst,,Unu triono de la puzlo estas solvita.,Un tercio del acertijo se ha resuelto,,Kolmannes pulmasta on ratkaistu,Un tiers du puzzle à été résolu,Egyharmada a rejtvénynek megoldva,Un terzo del puzzle è stato risolto,パズルの 三分の一 が解かれた,수수께끼의 3분의 1이 풀렸다,Een derde van de puzzel is opgelost.,Jedna trzecia zagadki rozwiązana,Um terço do quebra-cabeça foi resolvido,,O treime din puzzle e rezolvată,Одна треть головоломки разгадана,Једна трећина загонетке је решена -Two thirds of the puzzle is solved,TXT_ACS_MAP44_11_TWOTH,,,,Dvě třetiny rébusu jsou vyřešeny.,Zwei Drittel des Rätsels sind gelöst,,Du trionoj de la puzlo estas solvita.,Dos tercios del acertijo se han resuelto,,Kaksi kolmannesta pulmasta on ratkaistu,Deux tiers du puzzle ont été résolus,Kétharmada a rejtvénynek megoldva,Due terzi del puzzle è stato risolto,パズルの 三分の二 が解かれた,수수께끼의 3분의 2가 풀렸다,Tweederde van de puzzel is opgelost,Dwie trzecie zagadki rozwiązane,Dois terços do quebra-cabeça foi resolvido,,Două treimi din puzzle sunt rezolvate,Две трети головоломки разгаданы,Две трећине загонетке су решене -You hear a platform moving in the distance,TXT_ACS_MAP45_1_YOUHE,,,,Slyšíš v dálce pohybující se plošinu.,"Du hörst, wie sich in der Ferne eine Platform bewegt",,Vi aŭdas plataĵon movantan malproksime.,Escuchas una plataforma moverse a la distancia,,Kuulet lavan liikkuvan etäällä,Vous entendez une plateforme se déplacer au loin,Egy emelvény mozgását hallod a távolban,Senti una piattaforma muoversi a distanza,昇降機の音が遠くで聞こえる,멀리서 보행판이 움직이는 소리가 들려왔다,Je hoort een platform bewegen in de verte,Słyszysz odgłos poruszającej się w oddali platformy,Você ouve de longe uma plataforma se movendo,,Auzi o platformă mișcându-se în depărtare,"Неподалёку раздаётся звук -движущейся деревянной площадки",Чујете како се платформа помера у даљини -It is done...,TXT_ACS_MAP46_0_ITISD,,,,Je to dokonáno…,Es ist getan...,,Ĝi estas farita...,Está terminado...,,Se on tehty...,C'est terminé...,Megvan...,Fatto...,これで完了だ...,이제 끝났다...,Het is gebeurd,"Zrobione... -",Está terminado...,,E gata...,Готово...,Готово је... -You have not completed the puzzle,TXT_ACS_MAP46_1_YOUHA,,,,Nesplnil@[ao_cs] jsi rébus.,Du hast das Rätsel noch nicht gelöst,,Vi ne kompletis la puzlon.,No has completado el acertijo,,Et ole ratkaissut pulmaa,Vous n'avez pas résolu le puzzle.,Nem fejtetted meg a rejtvényt.,Non hai completato il puzzle,パズルはまだ完成していない,모든 수수께끼를 풀지 못했다,Je hebt de puzzel nog niet voltooid...,Nie ukończyłeś zagadki,Você não completou o quebra-cabeça,,Nu ai rezolvat puzzle-ul,Головоломка не разгадана,Ниси решио загонетку -I'm warning you...,TXT_ACS_MAP46_2_IMWAR,,,,Varuju tě…,Ich warne dich...,,Mi avertas vin...,Te lo advierto...,,Varoitan sinua...,Je vous avertis...,Figyelmeztetlek...,Ti avverto...,お前に警告しよう...,나는 경고했다...,Ik waarschuw je...,Ostrzegam cię...,Estou te avisando...,,Te avertizez...,Я тебя предупреждаю...,Упозоравам те... -"Stubborn, aren't you?",TXT_ACS_MAP46_3_STUBB,,,,"Ty jsi ale tvrdohlav@[adj_cs], nejsi?","Du bist aber stur, was?",,"Vi estas obstina, ĉu ne?","Eres obstinado, ¿verdad?",,Oletpa itsepäinen,"Obstiné, n'est-ce pas?","Makacs vagy, nem igaz?","Testardo, no?",頑固だと、自らも思わないか?,정말 끈질기군.,"Koppig, nietwaar?","Jesteś uparty, prawda?","Você é teimos@[ao_ptb], não é mesmo?",,"Încăpățânat, nu-i așa?",Не слишком ли ты упрямый?,"Тврдоглав си, зар не?" -"And stupid, too",TXT_ACS_MAP46_4_ANDST,,,,A taky hloupý.,Und auch noch dumm,,Kaj ankaŭ stulta.,"Y estúpido, también",,Ja vieläpä tyhmä,"Et stupide, aussi.",És hülye is.,E pure stupido,そして、あまりにも愚か者だ,어리석기도 하고.,En ook dom,Głupi też,E estúpid@[ao_ptb] também,,"Și prost, pe deasupra",И не слишком-то разумный!,А још си и глуп -One fourth of this puzzle is complete,TXT_ACS_MAP46_8_ONEFO,,,,Jedna čtvrtina rébusu je vyřešena.,Ein Viertel des Rätsels ist gelöst,,Unu kvarono de la puzlo estas kompleta.,Un cuarto del acertijo se ha resuelto,,Neljännes pulmasta on ratkaistu,Un quart du puzzle à été résolu,Egy negyede e rejtvénynek megvan.,Un quarto del puzzle è completo,パズルの 四分の一 が解かれた,수수께끼의 4분의 1만 풀렸다,Een vierde van deze puzzel is compleet,Jedna czwarta tej zagadki ukończona,Um quarto deste quebra-cabeça está completo,,O pătrime din puzzle e rezolvată,Одна четвёртая этой головоломки разгадана,Једна четвртина загонетке је решена -Bad choice...,TXT_ACS_MAP46_9_BADCH,,,,Špatná volba.,Falsche Wahl...,,Malbona elekto...,Mala decisión...,,Huono valinta...,Mauvaise décision...,Rossz választás...,Scelta sbagliata...,拙い選択だ...,서투른 선택이다...,Slechte keuze....,Zły wybór...,Péssima escolha...,,Proastă alegere...,Плохой выбор...,Лош избор... -The symbols are not aligned,TXT_ACS_MAP47_2_THESY,,,,Symboly nejsou zarovnány.,Die Symbole sind nicht ausgerichtet,,La simboloj ne estas liniiga.,Los símbolos no están alineados,,Symbolit eivät ole järjestyksessä,Les symboles ne sont pas alignés.,A jelek rendezetlenek.,I simboli non sono allineati,シンボルが揃っていない,상징이 정렬되지 않았다,De symbolen zijn niet uitgelijnd,Symbole nie są wyrównane,Os símbolos não estão alinhados,,Simbolurile nu sunt aliniate,Символы не совпадают,Симболи нису поравнати -The door won't open from this side,TXT_ACS_MAP48_2_THEDO,,,,Dveře se z této strany neotevřou.,Die Tür kann sich von dieser Seite nicht öffnen,,La pordo ne malfermiĝas.,La puerta no abrirá por este lado,,Ovi ei aukea tältä puolelta,La porte ne s'ouvre pas de ce côté.,Az ajtó nem fog kinyílni innen.,La porta non si apre da questo lato,扉はこちら側から開けられない,이 문은 이 방향으로는 열리지 않는다,De deur gaat niet open van deze kant,Drzwi nie otworzą się z tej strony,A porta não se abrirá deste lado,,Ușile nu se vor deschide de pe partea asta,С этой стороны дверь не открыть,Врата неће да се отворе са стране -The door is barred from the outside,TXT_ACS_MAP50_1_THEDO,,,,Dveře jsou zatarasené zvenku.,Die Tür ist von außen verriegelt,,La pordo estas barita ekstere.,La puerta está atrancada por fuera,,Ovi on teljetty ulkopuolelta,Cette porte est bloquée de l'extérieur.,Az ajtó kívülről van eltorlaszolva.,La porta è sbarrata da fuori,この扉は外側から塞がれている,이 문은 바깥에 빗장이 걸려있다,De deur is van buitenaf uitgesloten,Drzwi są zabarykadowane od zewnątrz,A porta está barrada por fora,,Ușa e încuiată pe dinafară,Дверь заблокирована снаружи,Врата су блокирана споља -Sacrilege !,TXT_ACS_MAP51_5_SACRI,,,,Svatokrádež!,Gotteslästerung!,,Sakrilegio !,¡Sacrilegio!,,Pyhäinhäväistys !,Sacrilège!,,Sacrilegio !,罰当たりが!,신성모독이다!,Heiligschennis!,Świętokradztwo !,Sacrilégio!,,Sacrilegiu!,Святотатство !,Светогрђе ! -You have defiled Eric's tomb !!,TXT_ACS_MAP51_6_YOUHA,,,,Znesvětil@[ao_cs] jsi Erikovu hrobku!!,Du hast Erics Gruft entehrt!!,,Vi malpurigis la tombon de Eric !!,¡Has profanado la tumba de Erick!,,Olet turmellut Ericin haudan !!,Vous avez vandalisé la tombe d'Eric!,Megszentségtelenítetted Eric sírját !!,Adesso hai profanato la tomba di eric !!,貴様はエリックの墓を荒らしたな!!,네 놈은 성 에릭의 무덤을 더렵혔다!!,Je hebt Eric's graf bevlekt!!,Zhańbiłeś grób Erica !!,Você violou a tumba de Eric!,,Ai profanat mormântul lui Eric!!,Ты осквернил могилу Эрика !!,Оскрнавио си Ерикову гробницу !! -And now you die !!!,TXT_ACS_MAP51_7_ANDNO,,,,Teď zemřeš!!!,Und nun stirbst du!,,Kaj nun vi mortos !!!,¡Y ahora muere!,¡Y ahora morirás!,Ja nyt sinä kuolet !!!,"Pour cela, vous allez mourir!",És most meghalsz !!!,E ora muori !!!,万死に値する!!!,그 댓가로 목숨을 바쳐라!!!,En nu ga je dood!!!!!,I teraz zginiesz !!!,E agora você morrerá!!!,,"Iar acum, mori!!",И умрёшь за это страшной смертью !!!,И сада умиреш !!! -One third of the puzzle is solved,TXT_ACS_MAP51_8_ONETH,,,,Jedna třetina rébusu je vyřešena.,Ein Drittel des Rätsels ist gelöst,,Unu triono de la puzlo estas solvita.,Un tercio del acertijo se ha resuelto,,Kolmannes pulmasta on ratkaistu,Un tiers du puzzle à été résolu,A rejtvény egyharmada megoldva,Un terzo del puzzle è stato risolto,パズルの 三分の一 が解かれた,수수께끼의 3분의 1이 풀렸다,Een derde van de puzzel is opgelost.,Jedna trzecia zagadki rozwiązana,Um terço do quebra-cabeça foi resolvido,,O treime din puzzle e rezolvată,Одна треть головоломки разгадана,Једна трећина загонетке је решена -Two thirds of the puzzle is solved,TXT_ACS_MAP51_9_TWOTH,,,,Dvě třetiny rébusu jsou vyřešeny.,Zwei Drittel des Rätsels sind gelöst,,Du trionoj de la puzlo estas solvita.,Dos tercios del acertijo se han resuelto,,Kaksi kolmannesta pulmasta on ratkaistu,deux tiers du puzzle ont été résolus,A rejtvény kétharmada megoldva,Due terzi del puzzle è stato risolto,パズルの 三分の二 が解かれた,수수께끼의 3분의 2가 풀렸다,Tweederde van de puzzel is opgelost,Dwie trzecie zagadki rozwiązane,Dois terços do quebra-cabeça foi resolvido,,Două treimi din puzzle sunt rezolvate,Две трети головоломки разгаданы,Две трећине загонетке су решене -The crypt is open,TXT_ACS_MAP51_10_THECR,,,,Krypta je otevřena.,Die Gruft ist offen,,La kripto estas malfermita.,La cripta ahora está abierta,,Krypta on auki,La crypte est ouverte,A kripta nyitva,La cripta è aperta,地下聖堂 が開いた,지하 묘실의 입구가 열렸다.,De crypte is open,Krypta jest otwarta,A cripta está aberta,,Cripta e deschisă,Склеп открыт,Гробница је отворена -Beware the spider's tomb,TXT_ACS_MAP51_11_BEWAR,,,,Vyvaruj se pavoučí hrobky.,Hüte dich vor dem Grab der Spinne,,Singardu en la tombo de la araneo.,Cuidado con la tumba de la araña,,Varo hämähäkin hautaa,Attention à la tombe de l'araignée.,,Attento alla tomba del ragno,スパイダーの墓,거미의 무덤을 조심하라,Pas op voor het graf van de spin,Strzeż się grobowca pająków,Cuidado com a tumba da aranha,,Păzește-te de mormântul păianjenului,Опасайся гробницы паука,Чувај се паукове гробнице -You hear a platform rise outside,TXT_ACS_MAP51_13_YOUHE,,,,Slyšíš zvenku zvedající se platformu.,"Du hörst, wie sich draußen eine Plattform erhebt",,Vi aŭdas plataĵon leviĝantan ekstere.,Escuchas una plataforma erguirse afuera,,Kuulet lavan kohoavan ulkopuolella,Vous entendez une platforme s'élever dehors,Egy emelvényt hallasz emelkedni odakinn,Senti una piattaforma alzarsi a distanza,外で昇降機の音が聞こえる,밖에서 보행판이 올라오는 소리가 들려왔다,Je hoort een platform buiten opstijgen,Słyszysz odgłos unoszącej się na zewnątrz platformy,Você ouve uma plataforma subir lá fora,,Auzi o platformă ridicându-se în afară,"Снаружи слышен звук -поднимающегося камня",Чујете како се платформа диже споља -Do you feel lucky?,TXT_ACS_MAP51_14_DOYOU,,,,"Zdá se ti, že máš štěstí?",Denkst du das heute dein Glückstag ist?,,Ĉu vi sentas vin bonŝanca?,¿Te sientes afortunado?,,Tunnetko olosi onnekkaaksi?,Vous pensez être chanceux?,Szerencsésnek érzed magad?,Ti senti fortunato?,運が良かったと思うか?,그대는 운수가 좋은가?,Heb je geluk?,Masz szczęście?,Está se sentindo com sorte?,,Te simți norocos?,Чувствуешь ли ты себя везучим?,Да ли се осећаш срећним? -You guessed wrong!,TXT_ACS_MAP51_15_YOUGU,,,,To máš smůlu!,Du hast falsch geraten!,,Vi divenis malĝuste!,¡Adivinaste incorrectamente!,,Arvasi väärin!,Et bien non!,Hát rosszul érzed!,Non hai indovinato!,それは違うな!,잘못된 판단이다!,Je hebt het verkeerd geraden!,Źle zgadłeś!,Adivinhou errado!,,N-ai ghicit!,Неправильное предположение!,Погодио си погрешно! -Good guess,TXT_ACS_MAP51_16_GOODG,,,,Dobré zdání.,Gut geraten,,Bona diveno.,¡Buena elección!,,Hyvä arvaus,Vous avez deviné!,Jól sejtetted,Hai indovinato,良い推測だ,옳은 판단이다,Goede gok,Dobrze zgadłeś,Certa resposta,,Ai ghicit,Правильное предположение,Добар погодак -Can you do all the scripting for my level?,TXT_ACS_MAP51_17_CANYO,,,,Můžeš všechno skriptování udělat za mě?,Kannst du die Skripte für all meine Level schreiben?,,Ĉu vi povas fari ĉiom da la skriptoj por mia nivelo?,¿Podrías hacer todo el script para mi nivel?,,Voitko tehdä kaikki tasoni skriptaukset?,Vous pouvez faire tout le script de mon niveau?,Meg tudnád csinálni az egészt scriptelést a pályámhoz?,Puoi fare tutto lo scripting per il mio livello?,この階層を全て書き換える事は可能かな?,어쩔 수 없이 살아간다. 태어났기 때문에...,Kun je al het scripten doen voor mijn niveau?,Czy możesz zrobić cały skrypt do mojego poziomu?,Poderia fazer todo o scripting da minha fase?,,Te poți ocupa de scripting pentru nivelul meu?,Можешь написать за меня все скрипты?,Можеш ли да напишеш све скриптове за мој ниво? -Don't touch my gloppy,TXT_ACS_MAP51_18_DONTT,,,,Nesahej mi na slimáka!,Berühr mein Ding nicht!,,Ne tuŝas mian gloppy-on.,No toques mi gloppy,,Älä koske mönjääni,Ne touche pas mon gloppy,,Non toccare la mia caramella,汚らしい手で触れるな,"에틴을 쳐죽인 것까지 신경 쓰다간, 걸을 수도 없을걸.",Raak mijn gloppy niet aan,Nie ruszaj moich słodyczy,Não toca no meu docinho!,,Nu-mi atinge bomboana,Не трогай мою вкусняшку,Не дирај мој слаткиш -Vorpal ?!?!?!,TXT_ACS_MAP51_19_VORPA,,,,Šaršoun?!?!?!,Tödlich ?!?!?!,,Vorpal ?!?!?!,¡¿¡¿¡¿ Vorpal ?!?!?!,,Tappava ?!?!?!,,,,ボーパル ?!?!?!,드래곤 슬레이어 인가?!,,Śmiercionośny ?!?!?!,,,Vorpal?!?!?!,Остренько ?!?!?!,Вајтолни мач ?!?!?! -"Gimme some sugar, baby",TXT_ACS_MAP51_20_GIMME,,,,"Dej mi trochu cukru, zlato.","Gib mir etwas Zucker, Baby",,"Donas al mi iom da sukeron, bebo.","Dame un poco de azúcar, baby","Dame algo de azúcar, bebe","Anna vähän sokeria, beibi",,,,砂糖が欲しいかい、ベイビー,등짝을 보자!...,"Geef me wat suiker, schatje.",Daj mi torchę cukru skarbie,"Me dá um pouco de açúcar, baby",,"Dă-mi niște zahăr, dulceață","Подай-ка мне сахар, детка","Дај ми мало шећера, бебо" -Duh-uhhh...,TXT_ACS_MAP51_21_DUHUH,,,,A jéje.,,,Da-aaaa...,,,Daa-aaa....,,,,えぇーとぉー...,낙원이란 있을 수 없는거야.,,Coooooo...,Dãããã-ããã...,,,Ага-а-а-а...,Дух-уххх... -Film in an hour?,TXT_ACS_MAP51_22_FILMI,,,,Film za hodinu?,Film in einer Stunde?,,Kinon post horo?,¿Película en una hora?,¿Una película en una hora?,Filmi tunnissa?,Un film dans une heure?,,Un film in un'ora?,数時間のフィルム?,신은 운명을 주셨죠. 만남이라는 운명을.,Film in een uur?,Za godzinę film?,Quer ver um filme daqui a pouco?,,Film într-o oră?,Фильм на час?,Снимамо за сат времена? -I don't even get my own tombstone - cf,TXT_ACS_MAP51_23_IDONT,,,,Ani nemám svůj vlastní náhrobek. -CF,Ich bekomme noch nicht einmal meinen eigenen Grabstein - cf,,Mi ne eĉ ekhavis mian propran tombŝtonon. - cf,Ni siquiera tengo mi propia lápida - cf,,En saa edes omaa hautakiveäni - cf,J'ai même pas le droit à ma propre tombe - cf,,Non ho potuto avere la mia pietra tombale - cf,私は自分の墓標すら得られない - cf,내 묘비를 세우지도 않았네 -cf,Ik krijg niet eens mijn eigen grafsteen – cf,Nawet nie dostałem swojego nagrobka - cf,Eu nem ganhei a minha própria lápide - cf,,Nici măcar nu primesc propria piatră de mormânt - cf,У меня даже нет своего надгробия (к.ф.),Ја чак и не добијам свој надгробни споменик - cf -Let no blood be spilt,TXT_ACS_MAP51_24_LETNO,,,,Nechť není prolita žádná krev.,Lass kein Blut vergossen sein,,Lasu neniom da sango elflui.,Que no se derrame sangre,,Älköön yhtään verta vuodatettako,Qu'aucune goutte de sang ne soit tirée,,Si cerchi di non spargere sangue,血を零さないように,피 한 방울도 흘리지 말라,Laat geen bloed worden vergoten,Nie pozwól by krew została przelana,Que sangue nenhum seja derramado,,Fie ca sângele să nu fie vărsat,Да не прольётся кровь,Нека се не пролије крв -Let no hand be raised in anger,TXT_ACS_MAP51_25_LETNO,,,,Nechť není žádná ruka hněvem zvednuta.,Lass keine Hand in Wut erhoben sein,,Lasu nenion manon estas levita pro kolero.,Que ninguna mano se levante con ira,,Ei yhtäkään kättä kohotettako vihassa,Qu'aucune main de se lève avec colère,,Si cerchi di non alzare le mani per rabbia,怒りで拳を振るわないように,분노하여 주먹을 휘두르지 말라,Laat geen hand worden opgestoken in woede...,Nie pozwól by ręka została uniesiona w gniewie,Que mão nenhuma seja erguida por raiva,,Fie ca nicio mână să nu fie ridicată în furie,И да не поднимется рука во гневе,Нека се ниједна рука подигне из беса -Who dares disturb our slumber?,TXT_ACS_MAP52_9_WHODA,,,,Kdo se opovažuje narušit náš spánek?,Wer wagt es unseren Schlummer zu stören?,,Kiu aŭdacas interrompi nian dormon? ,¿Quién se atreve a perturbar nuestro sueño?,,Kuka kehtaa häiritä untamme?,Qui ose troubler notre sommeil?,,Chi osa disturbare il nostro riposo?,誰が、我々の眠りを妨げる勇気があるかな?,감히 우리의 숙면을 방해하는가?,Wie durft onze slaap te verstoren?,Kto śmie przeszkadzać nam w drzemce?,Quem ousa perturbar o nosso descanso?,,Cine cutează să-mi perturbe odihna?,Кто осмелился потревожить наш покой?,Ко се усуђује узнемиравати наш сан? -The way is open,TXT_ACS_MAP52_10_THEWA,,,,Cesta je otevřena.,Der Weg ist offen,,La vojo estas malfermita.,El camino está abierto,,Tie on auki,Le chemin est ouvert.,,La via è aperta,道は開いた,길이 열렸다,De weg is open,Droga jest otwarta,O caminho está aberto,,Calea e deschisă,Путь открыт,Пролаз је отворен -You have ,TXT_ACS_MAP53_2_YOUHA,,,,Zbývají ti ,Du hast,,Vi havas,Tienes,,Sinulla on,Vous avez,,hai,スイッチはまだ,지금 ,Je hebt,Masz,Faltam ainda,,Mai ai,Осталось,Остало је -\x20switches left,TXT_ACS_MAP53_3_SWITC,,,,\x20spínače.,\x20Schalter übrig,,\x20ŝaltilojn ceterajn.,\x20interruptores restantes,\x20switches restantes,\x20vipua jäljellä,\x20boutons à trouver,,\x20interuttori rimanenti,残っている,개의 개폐기들이 남았다,\x20schakelaars over,\x20pozostałych przełączników,\x20interruptores,,\x20butoane rămase,\x20Переключателей,\x20прекидача -You have only ,TXT_ACS_MAP53_4_YOUHA,,,,Zbývá ti jen ,Du hast nur,,Vi nur havas,Tienes solo,,Sinulla on vain,Vous avez seulement,,Hai solamente,スイッチは,이제 오로지 ,Je hebt alleen,Masz tylko,Falta somente,,Mai ai doar,Остался всего,Остао је само -\x20switch left,TXT_ACS_MAP53_5_SWITC,,,,\x20spínač.,\x20Schalter übrig,,\x20ŝaltilon ceteran.,\x20interruptor restante,\x20switch restante,\x20vipu jäljellä,\x20outon à trouver,,\x20interruttore rimanente,"だけ残っている -",개의 개폐기가 남았다,\x20schakelaar over,\x20przełącznik,\x20interruptor,,\x20buton rămas,\x20переключатель,\x20прекидач -The exit is open,TXT_ACS_MAP53_6_THEEX,,,,Východ je otevřen.,Der Ausgang ist offen,,La elirejo estas malfermita,La salida está abierta,,Ulospääsy on auki,La sortie est ouverte,,L'uscita è aperta,出口が開いた,출구가 열렸다,De uitgang is open,Wyjście jest otwarte,A saída está aberta,,Ieșirea e deschisă,Выход открыт,Излаз је отворен -The doors won't open from this side,TXT_ACS_MAP54_1_THEDO,,,,Dveře se z této strany neotevřou.,Die Türen werden sich nicht von dieser Seite öffnen,,La pordo ne malfermos de ĉi tio flanko.,Las puertas no abrirán de este lado,,Ovet eivät aukea tältä puolelta,Les portes ne s'ouvrent pas de ce côté,,Le porte non si aprono da questo lato,扉はこちらから開けない,이 문들은 이 방향으로는 열리지 않는다,De deuren gaan niet open van deze kant....,Drzwi nie otworzą się z tej strony,As portas não se abrirão deste lado,,Ușile nu se vor deschide de pe partea asta,С этой стороны дверь не открыть,Врата неће да се отворе са стране -The doors are open...,TXT_ACS_MAP54_4_THEDO,,,,Dveře jsou otevřené…,Die Türen sind offen,,La pordoj estas malfermitaj...,Las puertas están abiertas...,,Ovet ovat auki...,Les portes sont ouvertes...,,Le porte sono aperte...,ドアは開いている...,문이 열렸다...,De deuren zijn open....,Drzwi są otwarte...,As portas estão abertas...,,Ușile sunt deschise...,Путь в цитадель открыт...,Врата су отворена... -...if you are ready,TXT_ACS_MAP54_5_IFYOU,,,,jestli jsi připraven.,...Wenn du bereit bist,,...se vi pretas.,...si estás listo,,...jos olet valmis,...si vous êtes prêt.,,...Se sei pronto,...準備が良いなら,... 준비 되었다면,...als je er klaar voor bent...,...jeśli jesteś gotów,...se você estiver preparad@[ao_ptb],,...dacă ești pregătit,...Осмелишься ли ты войти?,...ако си спреман -A door has opened,TXT_ACS_MAP54_9_ADOOR,,,,Dveře se otevřely,Eine Tür hat sich geöffnet,,Pordo malfermiĝis,Una puerta se abrió,,Ovi on auennut,Une porte est ouverte,,Una porta è stata aperta,先へ進むドアは開いた,지금 문이 열렸다...,Een deur is geopend,Drzwi otworzyły się,Uma porta se abriu,,O ușă s-a deschis,Дверь откроется,Врата су се отворила -on the Chantry,TXT_ACS_MAP54_10_ONTHE,,,,v Modlitebně.,In der Kantorei,,en la Kapelo.,En la capilla,,kappelissa,dans la chapelle.,,Nella Cappella,小礼拝堂 へ向かえ,... 예배당에서,op de Chantry,w Kaplicy Wotywnej,na Capela,,la Capelă,в Часовне,у Капели -A bridge has been built,TXT_ACS_MAP54_11_ABRID,,,,Most byl postaven,Eine Brücke wurde errichtet,,Ponto estis konstruita,Se construyó un puente,,Silta on rakennettu,Une pont a été construit,,È stato costruito un ponte,先へ進む橋が架かった,다리가 건설되었다...,Er is een brug gebouwd,Most został utworzony,Uma ponte foi construída,,Un pod a fost construit,Мост воздвигнется,Мост се саградио -on the Abattoir,TXT_ACS_MAP54_12_ONTHE,,,,na Jatkách.,Im Schlachthaus,,en la Buĉejo.,En el matadero,,teurastamolla,dans l'abbatoir.,,Nella Macelleria, 屠殺場 へ向かえ,... 도살장에서,op het slachthuis,w Rzeźni,no Matadouro,,pe Abator,на Бойне,на Кланици -A stair has been built,TXT_ACS_MAP54_13_ASTAI,,,,Schody byly postaveny,Eine Treppe wurde errichtet,,Ŝtuparo estis konstruita,Se construyó una escalera,,Portaat on rakennettu,Un escalier a été construit,,È stata costruita una scalinata,先へ進む階段が出来た,계단이 건설되었다...,Er is een trap gebouwd,Schody zostały utworzone,Uma escada foi construída,,O scară a fost construită,Лестница воздвигнется,Степенице су се саградиле -on the Dark Watch,TXT_ACS_MAP54_14_ONTHE,,,,na Temné hlídce.,auf der Dunklen Wache,,en la Gardisto Ombra.,En la guardia oscura,,pimeällä vartiolla,dans la Garde Noire.,,Nella Guardia Oscura, 闇の刻計 へ向かえ,... 어둠의 감시초소에서,op de donkere wacht,w Ciemnej Straży,na Guarda Negra,,pe Gardianul Întunecat,у Тёмного стража,на Црној стажи -One gear has been placed,TXT_ACS_MAP54_15_ONEGE,,,,Jedno kolo bylo umístěno.,Ein Zahnrad wurde eingesetzt,,Dentrado estis metita.,Un engranaje se ha puesto,Un engrane se ha puesto,Ratas on asetettu,Un engrenage a été placé,,Un ingranaggio è stato piazzato,歯車を一つ配置した,톱니바퀴 1개가 배치되었다,Een tandwiel is geplaatst,Jedna zębatka została umieszczona,Uma engrenagem foi colocada,,Un mecanism a fost introdus,Шестерня установлена,Један зупчаник је постављен -\x20gears have been placed,TXT_ACS_MAP54_16_GEARS,,,,\x20kola byla umístěna.,\x20Zahnräder wurden eingesetzt,,\x20dentradoj estis metitaj.,\x20engranajes se han puesto,\x20engranes se han puesto,\x20ratasta on asetettu,\x20engrenages ont été placés,,\x20ingranaggi sono stati piazzati,歯車を配置した,톱니바퀴들이 배치되었다,\x20tandwielen zijn geplaatst,\x20zębatki zostały umieszczone,\x20engrenagens foram colocadas,,\x20mecanisme au fost introduse,\x20шестернёй установлено,\x20зупчаника су постављена -A barricade has opened,TXT_ACS_MAP54_17_ABARR,,,,Barikáda se otevřela,Eine Barrikade wurde geöffnet,,Barikado malfermiĝis,La barricada se ha abierto,,Tiesulku on auennut,Une barricade s'est ouverte,,Una barricata è stata aperta,バリケードは開かれた,방벽이 열렸다...,Er is een barricade geopend,Barykada została otwarta,Uma barricada se abriu,,O baricadă s-a deschis,Преграда поднимется,Барикада је отворена -On the Cloaca,TXT_ACS_MAP54_18_ONTHE,,,,v Kloace.,In der Kloake,,en la Cloaca.,En la Cloaca,,kloaakilla,dans le cloaque,,Nella Cloaca,排泄腔 へ向かえ,... 하수구에서,Op de Cloaca,W Kloace,Na Cloaca,,pe Cloaca,в Клоаке,у клоаци -The way back is open,TXT_ACS_MAP54_20_THEWA,,,,Cesta zpět je otevřena.,Der Weg zurück ist offen,,La vojo reen estas malfermita.,El camino está abierto,,Tie takaisin on auki,Un chemin s'est ouvert,,La via del ritorno è aperta,裏口は開いた,돌아가는 길이 열렸다,De terugweg is open,Droga powrotna jest otwarta,O caminho de volta está aberto,,Calea e deschisă,Путь назад открыт,Пролаз назад је отворен -The door is barred from the inside,TXT_ACS_MAP55_9_THEDO,,,,Dveře jsou zatarasené zevnitř.,Die Tür ist von innen verriegelt,,La pordo estas barita interne.,La puerta está atrancada desde el interior,,Ovi on teljetty sisältä,La porte est bloquée de ce côté,,La porta è stata aperta da dentro,この扉は内側から塞がれている,이 문은 안에 빗장이 걸려있다,De deur is van binnenuit geblokkeerd.,Drzwi są zabarykadowane od wewnątrz,A porta está barrada por dentro,,Ușa e încuiată din interior,Дверь заблокирована изнутри,Врата су затворена изнутра -You dare plunder the tomb,TXT_ACS_MAP56_0_YOUDA,,,,Ty se opovažuješ rabovat,Wagst du es,,Vi aŭdacas rabi la tombo,¿Te atreves a saquear la tumba,,Kuinka kehtaat ryöstää,Vous osez piller la tombe,,Osi saccheggiare la tomba,お前はあえて 執行人達の墓を,배짱이 두둑하구나...,Je durft de graftombe te plunderen,Śmiesz plądrować grobowiec,Como ousa saquear a tumba,,Cutezi să jefuiești mormântul,Ты посмел ограбить могилу,Усуђујеш се пљачкати -of the executioner?,TXT_ACS_MAP56_1_OFTHE,,,,hrobku popravčího?,das Grab des Henkers zu plündern?,,de la ekzekutisto?,del ejecutor?,,teloittajan haudan?,du bourreau?,,dell'esecutore?,荒らすつもりか?,사형 집행자의 무덤을 도굴하다니.,van de beul?,kata?,do executor?,,călăului?,верховного палача?,желатову гробницу? -Prepare to die,TXT_ACS_MAP56_2_PREPA,,,,Připrav se zemřít.,Bereite dich vor zu sterben,,Pretiĝu por morti!,¡Prepárate para morir!,,Valmistaudu kuolemaan,Préparez vous à mourir!,,Preparati a morire,死ぬ準備をしろ,죽어서 회계하라.,Bereid je voor om te sterven,Przygotuj się na śmierć,Prepare-se para morrer,,Pregătește-te să mori,Готовься к смерти,Припреми се да умреш -You have ,TXT_ACS_MAP59_1_YOUHA,,,,Zbývají ti ,Du musst,,Vi havas,Aún tienes,,Sinulla on,Vous avez,,Hai ancora altri,スイッチはまだ,당신은,Je hebt,Masz,Faltam mais,,Mai ai,Осталось,Остало је -\x20more switches to find,TXT_ACS_MAP59_2_MORES,,,,\x20spínače k nalezení.,\x20weitere Schalter finden,,\x20pliajn ŝaltilojn por trovi.,\x20interruptores más que encontrar,\x20switches más que encontrar,\x20lisää vipua löydettävänä,\x20boutons à trouver,,\x20interruttori da trovare,残っている,개의 개폐기들을 더 찾아야 한다,\x20meer schakelaars te vinden,\x20przełączników do znalezienia,\x20interruptores para encontrar,,\x20butoane de găsit,\x20переключателей,\x20прекидача да се нађе -You have only ,TXT_ACS_MAP59_3_YOUHA,,,,Zbývá ti jen ,Du musst nur,,Vi nur havas,Tienes solo,,Sinulla on vain,Vous avez seulement,,Hai solamente,スイッチは,이제 당신은 ,Je hebt alleen,Masz tylko,Falta somente,,Mai ai doar,Остался всего,Oстао је само -\x20switch left,TXT_ACS_MAP59_4_SWITC,,,,\x20spínač.,\x20Schalter finden,,\x20ŝaltilon ceteran.,\x20interruptor restante,\x20switch restante,\x20vipu jäljellä,\x20bouton a trouver,,\x20interruttore rimanente,"だけ残っている -",개의 개폐기만 찾으면 된다,\x20schakelaar over,\x20przełącznik,\x20interruptor,,\x20buton rămas,\x20переключатель,\x20прекидач -The way to the tower is open,TXT_ACS_MAP59_5_THEWA,,,,Cesta do věže je otevřena.,Der Weg zum Turm ist offen,,La vojo al la turo estas malfermita.,El camino a la torre está abierto,,Tie tornin luo on auki,Le chemin vers la tour est ouvert.,,La via alla torre è stata aperta,塔への道 が開いた,탑으로 가는 길이 열렸다,De weg naar de toren is open,Droga do wieży jest otwarta,O caminho para a torre está aberto,,Calea către turn e deschisă,Путь к башне открыт,Пролаз до куле је отворен -The way is open,TXT_ACS_MAP60_3_THEWA,,,,Cesta je otevřena.,Der Weg ist offen,,La vojo estas malfermita.,El camino está abierto,,Tie on auki,Le chemin est ouvert.,,La via è aperta,道は開いた,길이 열렸다,De weg is open,Droga jest otwarta,O caminho está aberto,,Calea e deschisă,Портал открыт,Пролаз је отворен -,,Strife dialogue,,,,,,,,,,,,,,,,,,,,, -"I don't want any trouble, stay away from me. I've had enough trouble with what that bastard Harris did to me. He promised me money, instead I get to look forward to being Questioned by the Programmer.",TXT_DLG_SCRIPT01_D0_IDONT,,,,"Nechci žádný trable, jdi ode mě. Už tak mám dost potíží s tím, co mi ten hajzl Harris provedl. Slíbil mi peníze a místo toho se můžu těšit na výslech od Programátora.","Ich möchte keinen Ärger, bleib weg von mir. Ich hatte genug Ärger mit dem was der Bastard Harris mir angetan hat. Er hat mir Geld versprochen, stattdessen musste ich mich darauf vorbereiten von dem Programmierer ausgefragt zu werden.",,,"No quiero ningún problema, aléjate de mí. He tenido suficientes problemas con lo que me hizo Harris. Me prometió dinero, en lugar de eso, ahora espero a ser cuestionado por El Programador.",,,"Je ne veux pas d'embrouilles. Laissez moi tranquille. J'ai déjà assez de problèmes avec ce que ce salaud d'Harris ma fait. Il m'a promis de l'argent, maintenant, je risque de me faire interroger par le Programmeur.","Én nem akarok semmi gondot, maradj távol tőlem. Elég baj nekem az amit az a barom Harris okozott. Pénzt ígért, ehelyett az vár rám, hogy A Programozó kételkedik bennem.","Non voglio problemi, stammi lontano. Ho già avuto abbastanza problemi con quello che quel bastardo di Harris ha fatto a me. Mi aveva promesso soldi, invece mi ritrovo ad avere l'opportunità di essere Interrogato dal Programmatore.","もう面倒事には御免だ、私に近づくな。 +,,Hexen script texts,,,,,,,,,,,,,,,,,,,,,,,,, +The door is locked,TXT_ACS_MAP01_5_THEDO,,,,Dveře jsou zamčené.,Døren er låst,Die Tür ist verschlossen,,La pordo estas ŝlosita.,La puerta está cerrada,,Ovi on lukittu,Cette porte est verouillée.,Az ajtó zárva van.,La porta è bloccata,扉は施錠されている,문이 잠겨 있다,De deur is op slot,Døren er låst,Drzwi są zablokowane,A porta está trancada,,Ușa e încuiată,Дверь заперта,Врата су закључана,Dörren är låst,Kapı kilitli +"Greetings, mortal",TXT_ACS_MAP02_9_GREET,,,,"Vítej, smrtelníče,","Vær hilset, dødelige","Sei gegrüßt, Sterblicher",,"Salutojn, mortemul'.","Saludos, mortal",,"Tervehdys, kuolevainen","Salutations, humain.","Üdvözöllek, halandó!","Salve, mortale",御機嫌よう、小僧,"환영한다, 필멸자여.","Groeten, sterfelijk","Vær hilset, dødelige",Witaj śmiertelniku,"Saudações, mortal.",,"Salutări, muritorule","Приветствую, смертный","Поздрав, смртниче","Hälsningar, dödliga","Selamlar, ölümlü" +Are you ready to die?,TXT_ACS_MAP02_11_AREYO,,,,jsi připraven@[ao_cs] zemřít?,Er du klar til at dø?,Bist du bereit zu sterben?,,Ĉu vi pretas morti?,¿Estás listo para morir?,,Oletko valmis kuolemaan?,Êtes-vous prêt à mourir?,Készen állsz a halálra?,Sei pronto a morire?,死に急ぐ仕度は整ったか?,죽을 준비는 됐는가?,Ben je klaar om te sterven?,Er du klar til å dø?,Czy jesteś gotów na śmierć?,Você está pront@[ao_ptb] para morrer?,,Ești pregătit să mori?,Готов ли ты умереть?,Јеси ли спреман да умреш?,Är du redo att dö?,Ölmeye hazır mısın? +A door opened on the Guardian of Ice,TXT_ACS_MAP02_20_ADOOR,,,,Ve Strážci ledu se otevřely dveře.,En dør åbnede sig på isens vogter,Eine Tür öffnet sich zum Wächter des Eises,,Pordo malfermiĝis ĉe la Gardanto de Glacia.,Se abrió una puerta en el Guardián de Hielo,,Ovi avautui jään vartijan luona,Une porte s'est ouverte dans le Gardien de Glace.,Egy ajtó kinyillott a Jég Őrzőjénél,Una porta è stata aperta sul Guardiano di Ghiaccio,氷の守護者にある扉は開かれた,얼음의 수호자에서 문이 열렸다,Een deur opende op de bewaker van ijs,En dør åpnet seg på Isens vokter,Drzwi w Strażniku Lodu otworzyły się,Uma porta se abriu no Guardião de Gelo,,O ușă s-a deschis pe Gardianul de Foc,Дверь открыта у стража льда,Врата су отворена код Чувара леда,En dörr öppnades på isens väktare,Buz Muhafızı'nda bir kapı açıldı +This path is barred,TXT_ACS_MAP03_12_THISP,,,,Cesta je zatarasená.,Denne vej er spærret,Dieser Pfad ist blockiert,,Ĉi tiu vojo estas barita.,Este camino está atrancado,,Tämä polku on teljetty,Ce chemin est barré.,Ez az út el van torlaszolva.,Questo percorso è sbarrato,この道は塞がれている,이 통로는 빗장이 걸려있다,Dit pad is geblokkeerd,Denne veien er sperret,Ścieżka jest zablokowana,Este caminho está bloqueado,,Această cale e blocată,Сейчас этот путь закрыт,Овај пут је тренутно забрањен,Denna väg är spärrad,Bu yol yasaklandı +One half of the puzzle has been solved,TXT_ACS_MAP04_9_ONEHA,,,,U Sedmera portálů byla vyřešena,Den ene halvdel af puslespillet er blevet løst,Eine Hälfte des Rätsels wurde gelöst,,Unu duono de la puzlo estas solvita,Una mitad del acertijo se ha resuelto,,Puolet pulmasta on ratkaistu,La moitié du puzzle à été résolu,A rejtvény egyik fele meg lett fejtve,Metà del puzzle è stato risolto,パズルの一つが解かれた,수수께끼의 절반이 풀렸다,De helft van de puzzel is opgelost,Den ene halvdelen av gåten er løst,Połowa zagadki rozwiązana,Metade do quebra-cabeça foi resolvido,,O jumătate din puzzle e rezolvată,Половина головоломки разгадана,Половина загонетке је решена,En halva av pusslet har lösts,Bulmacanın bir yarısı çözüldü +on the Seven Portals,TXT_ACS_MAP04_10_ONTHE,,,,jedna třetina rébusu.,på de syv portaler,bei den Sieben Portalen,,ĉe la Sep Portaloj.,en los Siete Portales,,seitsemän portaalin luona,pour les Sept Portails.,a Hét Portálon,nei Sette Portali,漆之門に影響を与えた,... 일곱 차원문에서,op de Zeven Portalen,på de syv portaler,przy Siedmiu Portalach,nos Sete Portais,,pe cele Șapte Portaluri,на Семи порталах,на Седам портала,på de sju portalerna,Yedi Portalda +One third of the puzzle has been solved,TXT_ACS_MAP04_11_ONETH,,,,U Sedmera portálů byla vyřešena,En tredjedel af gåden er blevet løst,Ein Drittel des Rätsels wurde gelöst,,Unu triono de la puzlo estas solvita,Un tercio del acertijo se ha resuelto,,Kolmannes pulmasta on ratkaistu,Un tiers du puzzle à été résolu,A rejtvény egyharmada megfejtésre került,Un terzo del puzzle è stato risolto,三種のパズルの一つが解かれた,수수께끼의 3분의 1이 풀렸다,Een derde van de puzzel is opgelost,En tredjedel av puslespillet er løst,Jedna trzecia zagadki rozwiązana,Um terço do quebra-cabeça foi resolvido,,O treime din puzzle a fost rezolvată,Треть головоломки разгадана,Трећина загонетке је решена,En tredjedel av pusslet har lösts,Bulmacanın üçte biri çözüldü +Stairs have risen on the Seven Portals,TXT_ACS_MAP04_12_STAIR,,,,jedna třetina rébusu.,Der er kommet en trappe op på de syv portaler,Stufen bei den Sieben Portale wurden erbaut,,Ŝtupoj leviĝis ĉe la Sep Portaloj.,Unas escaleras se han erguido en los Siete Portales,,Portaat ovat kohonneet seitsemän portaalin luona,Des escaliers sont apparus dans les Sept Portails.,A Hét Portálon belül egy lépcsősor emlekedett,Sono sorte le scale nei Sette Portali,漆之門に階段が立ち昇った,일곱 차원문에서 계단이 솟아났다,Trappen zijn gestegen op de Zeven Portalen,Trapper har reist seg på De syv portaler,Schody przy Siedmiu Portalach podniosły się,As escadas se ergueram nos Sete Portais,,S-au ridicat scări pe cele Șapte Portaluri,Лестница воздвигнулась на Семи порталах,Степенице се подижу на Седам портала,En trappa har stigit upp i de sju portalerna,Yedi Portalda merdivenler yükseldi +One third of the puzzle has been solved,TXT_ACS_MAP05_6_ONETH,,,,U Sedmera portálů byla vyřešena,En tredjedel af puslespillet er blevet løst,Ein Drittel des Rätsels wurde gelöst,,Unu triono de la puzlo estas solvita,Un tercio del acertijo se ha resuelto,,Kolmannes pulmasta on ratkaistu,Un tiers du puzzle à été résolu,A rejtvény egyharmada megfejtésre került,Un terzo del puzzle è stato risolto,三種のパズルの一つが解かれた,수수께끼의 3분의 1이 풀렸다,Een derde van de puzzel is opgelost,En tredjedel av puslespillet er løst,Jedna trzecia zagadki rozwiązana,Um terço do quebra-cabeça foi resolvido,,O treime din puzzle a fost rezolvată,Треть головоломки разгадана,Трећина загонетке је решена,En tredjedel av pusslet har lösts,Bulmacanın üçte biri çözüldü +on the Seven Portals,TXT_ACS_MAP05_7_ONTHE,,,,jedna třetina rébusu.,på de syv portaler,bei den Sieben Portalen,,ĉe la Sep Portaloj.,en los Siete Portales,,seitsemän portaalin luona,pour les Sept Portails.,a Hét Portálon,nei Sette Portali,漆之門 に影響を与えた,... 일곱 차원문에서,op de Zeven Portalen,på de syv portaler,przy Siedmiu Portalach,nos Sete Portais,,pe cele Șapte Portaluri,на Семи порталах,на Седам портала,på de sju portalerna,Yedi Portalda +Stairs have risen on the Seven Portals,TXT_ACS_MAP05_8_STAIR,,,,Schody se zvedly u Sedmera portálů.,Trappen er steget op på de syv portaler,Stufen bei den Sieben Portale wurden erbaut,,Ŝtupoj leviĝis ĉe la Sep Portaloj.,Unas escaleras se han erguido en los Siete Portales,,Portaat ovat kohonneet seitsemän portaalin luona,Des escaliers sont apparus dans les Sept Portails.,A Hét Portálon belül egy lépcsősor emlekedett,Sono sorte le scale nei Sette Portali,漆之門 に階段が立ち昇った,일곱 차원문에서 계단이 솟아났다,Trappen zijn gestegen op de Zeven Portalen,Trappene har reist seg på De syv portaler,Schody przy Siedmiu Portalach podniosły się,Escadas se ergueram nos Sete Portais,,S-au ridicat scări pe cele Șapte Portaluri,Лестница воздвигнулась на Семи порталах,Степенице се подижу на Седам портала,Trappor har stigit upp på de sju portalerna,Yedi Portalda merdivenler yükseldi +You have to find another switch...,TXT_ACS_MAP05_9_YOUHA,,,,Musíš najít další spínač.,Du skal finde en anden kontakt...,Du must einen weiteren Schalter finden...,,Vi bezonas trovi alian ŝaltilon...,Debes encontrar otro interruptor...,Debes encontrar otro switch...,Sinun on löydettävä toinen vipu...,Vous devez trouver un autre bouton..,Egy másik kapcsolót kell találnod...,Devi trovare un altro interruttore...,他のスイッチも探す必要がある...,다른 개폐기를 찾아야 한다,Je moet een andere schakelaar vinden...,Du må finne en annen bryter...,Musisz znaleźć inny przełącznik...,Você precisa encontrar outro interruptor...,,Trebuie să găsești alt buton...,Остался ещё один переключатель...,Остао је још један прекидач...,Du måste hitta en annan omkopplare...,Başka bir anahtar bulmalısın... +Stones grind on the Seven Portals,TXT_ACS_MAP05_10_STONE,,,,Kameny dřou u Sedmera portálů.,Stenene knirker på de syv portaler,Steine schleifen bei den Sieben Portalen,,Ŝtonoj grincas ĉe la Sep Portaloj.,Las piedras giran en los Siete Portales,,Kiviä vierii seitsemän portaalin luona,Des pierres grincent dans les Sept Portails.,Kövek örlődnek a Hét Portálnál,Le pietre si sono frantumate nei Sette Portali,漆之門 の石壁が砕かれた,일곱 차원문에서 바위 부딪히는 소리가 들려왔다,Stenen slijpen op de Zeven Portalen,Steiner knuser på De syv portaler,Kamienie przy Siedmiu Portalach zgrzytają,As pedras giram nos Sete Portais,,Pietrele încep să macine pe cele Șapte Portaluri,Каменная преграда отступила на Семи порталах,Камена препрека се повлачи,Stenar slipar på de sju portalerna,Taşlar Yedi Portalda öğütülüyor +One sixth of the puzzle has been solved,TXT_ACS_MAP08_6_ONESI,,,,V Temném hvozdu byla vyřešena,En sjettedel af puslespillet er blevet løst,Ein Sechstel des Rätsels wurde gelöst,,Unu sesono de la puzlo estas solvita,Un sexto del acertijo se ha resuelto,,Kuudennes pulmasta on ratkaistu,Un sixième du puzzle à été résolu,A feladványok egyhatoda megfejtésre került,Un sesto del puzzle è stato risolto,六種のパズルの一つが解かれた,수수께끼의 6분의 1이 풀렸다,Een zesde van de puzzel is opgelost,En sjettedel av puslespillet er løst,Jedna szósta zagadki rozwiązana,Um sexto do quebra-cabeça foi resolvido,,O șesime din puzzle a fost rezolvată,Одна шестая головоломки разгадана,Шестина загонетке је решена,En sjättedel av pusslet har lösts,Bulmacanın altıda biri çözüldü +on the Shadow Wood,TXT_ACS_MAP08_7_ONTHE,,,,jedna šestina rébusu.,i Skyggetræet,Im Schattenwald,,en la Ombro-Arbareto.,En el Bosque de Sombras,,Varjosalossa,dans le Bois des Ombres.,a Sötét Erdőben,Nel Bosco d'Ombra,陰影樹 に少し影響を与えた,... 그림자 숲에서,op het Schaduwbos,på Skyggeskogen,w Lesie Cieni,na Floresta das Sombras,,în Pădurea Umbrelor,в лесу теней,у Шуми сенки,i skuggskogen,Gölge Ormanı'nda +The door is barred from the inside,TXT_ACS_MAP08_10_THEDO,,,,Dveře jsou zatarasené zevnitř.,Døren er spærret indefra,Die Tür ist von innen verriegelt,,La pordo estas barita interne.,La puerta está atrancada desde el interior,,Ovi on teljetty sisältä,Cette porte est bloquée de l'intérieur.,Az ajtó be van reteszelve belülről,La porta è sbarrata da dentro,この扉は内側から塞がれている,이 문은 안에 빗장이 걸려있다,De deur is van binnenuit geblokkeerd.,Døren er sperret fra innsiden,Drzwi są zabarykadowane od środka,A porta está barrada por dentro,,Ușa e blocată dinăuntru,Дверь заблокирована изнутри,Врата су забрављена изнутра,Dörren är spärrad från insidan,Kapı içeriden kilitli. +You hear a door open in the distance,TXT_ACS_MAP08_11_YOUHE,,,,Slyšíš v dálce otevírající se dveře.,Du hører en dør åbne i det fjerne,"Du hörst, wie sich in der Ferne eine Tür öffnet",,Vi aŭdas pordon malfermiĝantan malproksime.,Escuchas que una puerta se abre a la distancia,,Kuulet oven avautuvan etäällä,Vous entendez une porte s'ouvrir au loin.,Hallod ahogy egy ajtó kinyílik a távolban,Senti una porta aprirsi in lontananza,遠くから扉が開く音が聞こえる,멀리서 문이 열리는 소리가 들린다,In de verte hoor je een deur openstaan.,Du hører en dør åpnes i det fjerne,Słyszysz odgłos otwierających się w oddali drzwi,Você ouve de longe uma porta se abrindo,,Auzi o ușă deschizându-se în depărtare,Слышен звук открывающейся двери,Чује се звук отварања врата,Du hör en dörr som öppnas i fjärran,Uzakta bir kapının açıldığını duyuyorsun. +One sixth of the puzzle has been solved,TXT_ACS_MAP09_6_ONESI,,,,V Temném hvozdu byla vyřešena,En sjettedel af puslespillet er blevet løst,Ein Sechstel des Rätsels wurde gelöst,,Unu sesono de la puzlo estas solvita,Un sexto del acertijo se ha resuelto,,Kuudennes pulmasta on ratkaistu,Un sixième du puzzle à été résolu,A feladványok egyhatoda megfejtésre került,Un sesto del puzzle è stato risolto,六種のパズルの一つが解かれた,수수께끼의 6분의 1이 풀렸다,Een zesde van de puzzel is opgelost,En sjettedel av gåten er løst,Jedna szósta zagadki rozwiązana,Um sexto do quebra-cabeça foi resolvido,,O șesime din puzzle a fost rezolvată,Одна шестая головоломки разгадана,Шестина загонетке је решена,En sjättedel av pusslet har lösts.,Bulmacanın altıda biri çözüldü +on the Shadow Wood,TXT_ACS_MAP09_7_ONTHE,,,,jedna šestina rébusu.,i Skyggetræet,Im Schattenwald,,en la Ombro-Arbareto.,En el Bosque de Sombras,,Varjosalossa,dans le Bois des Ombres.,a Sötét Erdőben,Nel Bosco d'Ombra,陰影樹 に少し影響を与えた,... 그림자 숲에서,op het Schaduwbos,på Skyggeskogen,w Lesie Cieni,na Floresta das Sombras,,în Pădurea Umbrelor,в лесу теней,у Шуми сенки,i skuggskogen,Gölge Ormanı'nda +One sixth of the puzzle has been solved,TXT_ACS_MAP10_6_ONESI,,,,V Temném hvozdu byla vyřešena,En sjettedel af puslespillet er blevet løst,Ein Sechstel des Rätsels wurde gelöst,,Unu sesono de la puzlo estas solvita,Un sexto del acertijo se ha resuelto,,Kuudennes pulmasta on ratkaistu,Un sixième du puzzle à été résolu,A feladványok egyhatoda megfejtésre került,Un sesto del puzzle è stato risolto,六種のパズルの一つが解かれた,수수께끼의 6분의 1이 풀렸다,Een zesde van de puzzel is opgelost,En sjettedel av puslespillet har blitt løst,Jedna szósta zagadki rozwiązana,Um sexto do quebra-cabeça foi resolvido,,O șesime din puzzle a fost rezolvată,Одна шестая головоломки разгадана,Шестина загонетке је решена,En sjättedel av pusslet har lösts.,Bulmacanın altıda biri çözüldü +on the Shadow Wood,TXT_ACS_MAP10_7_ONTHE,,,,jedna šestina rébusu.,i Skyggetræet,Im Schattenwald,,en la Ombro-Arbareto.,En el Bosque de Sombras,,Varjosalossa,dans le Bois des Ombres.,a Sötét Erdőben,Nel Bosco d'Ombra,陰影樹 に少し影響を与えた,... 그림자 숲에서,op het Schaduwbos,på Skyggeskogen,w Lesie Cieni,na Floresta das Sombras,,în Pădurea Umbrelor,в лесу теней,у Шуми сенки,i skuggskogen,Gölge Ormanı'nda +\ ettins left,TXT_ACS_MAP11_0_ETTIN,Yellow needs better translation,,,\ etinů zbývá.,\ ettins venstre,\ Ettins übrig,,\ gigantaĉoj ceteraj,\ Ettins restantes,,\ ettiniä jäljellä,\ ettins restants,\ ettin maradt,\ Ettins rimasti,\ 匹のエティンが残っている,\ 마리 에틴이 남았음,\ overgebleven Ettins,\ ettins igjen,\ pozostałych ettinów,\ ettins restantes,,\ etini rămași,\ оставшихся эттинов,Остало је \ еттина,\ ettins lämnade,\ ettins ayrıldı +"You waited too long, now you die!",TXT_ACS_MAP11_1_YOUWA,,,,"Čekal@[ao_cs] jsi moc dlouho, teď zemřeš!","Du ventede for længe, nu dør du!","Du hast zu lange gewartet, jetzt stirbst du!",,"Vi atendis tro longe, nun vi mortas!","Esperaste demasiado, ¡ahora morirás!",,"Odotit liian pitkään, nyt kuolet!","Vous avez attendu trop longtemps, maintenant, mourrez!","Túl sokáig vártál, most meghalsz!","Hai atteso troppo a lungo, ora muori!",長居をしたな、命を奪うには十分な程に!,시간을 너무 오래 끌었다. 이제 죽어라!,"Je hebt te lang gewacht, nu ga je dood!","Du ventet for lenge, nå dør du!",Czekałeś zbyt długo. Teraz giń!,Você esperou demais. Agora morrerá!,,"Ți-a luat prea mult, acum mori!",Слишком долго! Готовься к смерти!,Предуго! Припреми се за смрт!,"Du väntade för länge, nu dör du!","Çok bekledin, şimdi öleceksin!" +A door opened on the Forsaken Outpost,TXT_ACS_MAP11_7_ADOOR,,,,Dveře se otevřely na Opuštěném stanovišti.,En dør blev åbnet i forladt forpost,Eine Tür im verlassenen Vorposten hat sich geöffnet,,Pordo malfermiĝis ĉe la Forlasita Posteno.,Una puerta se abrió en el Puesto de Avanzada Abandonado,,Ovi avautui hylätyssä etuvartiossa,Une porte s'est ouverte dans la base abandonnée.,Egy ajtó kinyílik az Elátkozott Őrportyán,Una porta è stata aperta nell'Avamposto Abbandonato,荒れ果てた前哨地 への扉が開いた,버려진 초소에서 문이 열렸다,Een deur opende een deur op de Verwaarloosde buitenpost,En dør åpnet seg på den forlatte utposten,Drzwi przy Opuszczonym Posterunku otworzyły się,Uma porta se abriu no Posto Abandonado,,O ușă s-a deschis pe Avanpostul Părăsit,Дверь открылась на покинутой заставе,Врата су се отворила у Напуштеној постаји,En dörr har öppnats på försvunnen utposten,Unutulmuş Karakol'da bir kapı açıldı +This door won't open yet,TXT_ACS_MAP12_9_THISD,,,,Tyto dveře se ještě neotevřou.,Denne dør vil ikke åbne sig endnu,Die Tür öffnet sich noch nicht,,Ĉi tiu pordo ne jam malfermiĝos.,Esta puerta no se abrirá todavía,,Tämä ovi ei aukea vielä,Cette porte ne s'ouvre pas pour l'instant.,Ez az ajtó még nem fog kitárulni.,Questa porta non è aperta ancora,扉はまだ開かない,이 문은 아직 열 수 없다,Deze deur gaat nog niet open.,Denne døren vil ikke åpne seg ennå,Te drzwi jeszcze się nie otwierają,Esta porta não se abrirá ainda,,Ușa n-o să se deschidă încă,Сейчас эта дверь закрыта,Ова врата су тренутно закључана,Den här dörren kommer inte att öppnas än.,Bu kapı henüz açılmayacak. +"My servants can smell your blood, human",TXT_ACS_MAP13_11_MYSER,,,,"Mí služebníci cítí tvou krev, člověče.","Mine tjenere kan lugte dit blod, menneske","Meine Diener riechen dein Blut, Menschling",,"Miajn servantoj povas flari vian sangon, homo.","Mis sirvientes pueden oler tu sangre, humano",,"Palvelijani voivat haistaa veresi, ihminen","Mes servants peuvent sentir votre sang, humain.","Szolgáim érzik a véred szagát, emberfattya","I miei servi possono annusare il tuo sangue, umano",我が下僕が貴様の血を嗅ぎ付けた様だぞ、小童,"이 몸의 하인들은 네 피 냄새를 맏고 따라온다, 인간.","Mijn bedienden kunnen jouw bloed ruiken, mens","Mine tjenere kan lukte blodet ditt, menneske",Moje sługi czują twą krew śmiertelniku,"Meus servos sentem o cheiro do seu sangue, human@[ao_ptb]",,"Servitorii mei îți pot adulmeca sângele, muritorule","Мои прислужники чуют твою кровь, человек","Моје слуге миришу твоју крв, човече","Mina tjänare kan känna lukten av ditt blod, människa.","Hizmetçilerim kanının kokusunu alabiliyor, insan." +A door opened in the Gibbet,TXT_ACS_MAP21_0_ADOOR,,,,Dveře se otevřely na Šibenici.,En dør blev åbnet i Gibbet,Eine Tür in der Richtstätte wurde geöffnet,,Pordo malfermiĝis ĉe la Pendigilo.,Una puerta se abrió en la horca,,Ovi avautui hirsipuulla,Une porte s'est ouverte dans le gibet.,Egy ajtó kinyílik az Akasztófánál,Una porta è stata aperta nella Forca,晒し台 への扉が開いた,교수대에서 문이 열렸다,Een deur geopend in de Gibbet,En dør åpnet seg i galgen,Drzwi przy Szubienicy otworzyły się,Uma porta se abriu na Forca,,O ușă s-a deschis pe Eșafod,Проход будет открыт возле виселицы,Пролаз је отворен код вешала,En dörr öppnades i Gibbet,İnfaz yerinde bir kapı açıldı +The door is barred from the inside,TXT_ACS_MAP21_2_THEDO,,,,Dveře jsou zatarasené zevnitř.,Døren er spærret indefra,Die Tür ist von innen verriegelt,,La pordo estas barita interne.,La puerta está atrancada desde el interior,,Ovi on teljetty sisältä,Cette porte est bloquée de l'intérieur.,Az ajtó belülről van eltorlaszolva,La porta è sbarrata da dentro,この扉は内側から塞がれている,이 문은 안에 빗장이 걸려있다,De deur is van binnenuit geblokkeerd.,Døren er sperret fra innsiden,Drzwi są zabarykadowane od środka,A porta está barrada por dentro,,Ușa e blocată dinăuntru,Дверь заблокирована изнутри,Врата су забрављена изнутра,Dörren är spärrad från insidan,Kapı içeriden kilitli. +A platform has lowered in the tower,TXT_ACS_MAP22_3_APLAT,,,,Plošina ve věži sjela dolů.,En platform er sænket i tårnet,Im Turm hat sich eine Plattform gesenkt,,Plataĵo malleviĝis en la turo.,Una plataforma ha bajado en la torre,,Lava on laskeutunut tornissa,Une plateforme est descendue dans la tour.,Egy platform leereszkedett a toronyban,Una piattaforma si è abbassata nella torre,塔内の昇降機が下りた,성 안에서 보행판이 내려왔다,Een platform is in de toren neergelaten in de toren,En plattform har senket seg i tårnet,Platforma w wieży obniżyła się,Uma plataforma desceu na torre,,O platformă a coborât în turn,Площадка опустилась в центральной башне,Спустио се платформ у централном торњу,En plattform har sänkts i tornet,Kuleye bir platform indirildi +"You have played this game too long, mortal...",TXT_ACS_MAP22_27_YOUHA,,,,"Tuhle partii jsi už hrál@[ao_cs] moc dlouho, smrtelníče,","Du har spillet dette spil for længe, dødelige...","Du spielst schon zu lange, Sterblicher...",,"Ludis ĉi tiun ludon vi tro longe, mortemul'...","Has jugado este juego demasiado tiempo, mortal...",,"Olet pelannut tätä peliä liian pitkään, kuolevainen...","Vous avez joué à ce jeu trop longtemps, mortel..","Túl sokat játszadoztál, halandó...","Ha giocato a questo gioco troppo a lungo, mortale...",遊びはここまでだ、小僧,"네 놈은 오랫동안 놀았도다, 필멸자여...","Je hebt dit spel te lang gespeeld, sterfelijke...","Du har spilt dette spillet for lenge, dødelige...",Już za długo grasz w tą grę śmiertelniku...,"Você jogou este jogo por tempo demais, mortal...",,"Ai jucat acest joc prea multă vreme, muritorule...","Ты слишком заигрался, смертный...","Превише си се заиграо, смртниче...","Du har spelat det här spelet för länge, dödlig...","Bu oyunu çok uzun oynadın, ölümlü." +I think I shall remove you from the board,TXT_ACS_MAP22_29_ITHIN,,,,"myslím, že bych tě měl odstranit ze šachovnice.","Jeg tror, jeg vil fjerne dig fra brættet.",Ich denke ich sollte dich vom Brett entfernen,,"Mi kredas, ke mi vin forigos el la tabul'.",Creo que te retiraré del tablero,,Ajattelenpa poistaa sinut pelilaudalta,Je pense qu'il est l'heure de vous retirer de l'échiquier.,"Azt hiszem le kell, hogy üsselek a tábláról",Penso che ti rimuoverò dalla scacchiera,盤上から貴様を排除する,이 몸이 너를 말 치우듯이 제거하겠다.,Ik denk dat ik u van het bord zal verwijderen,Jeg tror jeg skal fjerne deg fra brettet,"Myślę, że usunę cię z planszy",Acho que irei removê-l@[ao_ptb] do tabuleiro,,Cred că e timpul să te înlătur de pe tablă,Пришло время завершить твою партию,Дошло је време да се заврши твоја партија,Jag tror att jag ska ta bort dig från spelplanen.,Sanırım seni tahtadan kaldırmalıyım. +You hear a door open upstairs,TXT_ACS_MAP23_10_YOUHE,,,,Z patra slyšíš otevírající se dveře.,Du hører en dør blive åbnet ovenpå.,"Du hörst, wie sich oben eine Tür öffnet",,Vi aŭdas pordon malfermiĝantan superŝtupare.,Escuchas una puerta que se abre arriba,,Kuulet oven avautuvat yläkerrassa,Vous entendez une porte s'ouvrir à l'étage.,Hallod ahogy egy ajtó kinyílik az emeleten,Senti una porta aprirsi al piano di sopra,上層階の扉が開いた,윗층에서 문이 열리는 소리가 들린다,Je hoort een deur boven opengaan,Du hører en dør åpnes ovenpå,Słyszysz odgłos otwierających się na górze drzwi,Você ouve uma porta se abrir lá em cima,,Auzi o ușă deschizându-se sus,Слышен звук открывающейся двери наверху,Од северне дворане зачује се звук,Du hör en dörr öppnas på övervåningen.,Üst katta bir kapının açıldığını duyuyorsun. +"Worship me, and I may yet be merciful",TXT_ACS_MAP27_8_WORSH,,,,Uctívej mě a možná ještě budu milosrdný.,"Tilbeder du mig, så er jeg måske barmhjertig.",Verehre mich und ich könnte gnädig sein,,"Kultu min, tiam mi ankoraŭ eble kompatos.","Adórame, y aun puedo ser misericordioso",,"Palvo minua, ja saatan vielä olla armahtavainen","Prosternez vous devant moi, et je pourrai considérer de vous épargner.","Hódolj be, és talán kegyelmes leszek","Venerami, e potrei essere ancora misericordioso",我を崇めろ、慈悲を残している内に,"이 몸에게 경배하라, 그럼 자비를 베풀 것이다.","Aanbid me, en ik mag dan nog genadig zijn","Tilbe meg, og jeg kan ennå være barmhjertig.","Wielb mnie, a może będę miłosierny","Venere-me, e eu poderei ser piedoso",,"Venerează-mă, și s-ar putea să mai fiu milostiv încă","Преклонись предо мной, и, может быть, я буду милосерден","Преклони се преда мноме, и можда ћу бити милостив","Dyrka mig, så kanske jag är barmhärtig.","Bana ibadet et, belki merhamet ederim" +"Then again, maybe not",TXT_ACS_MAP27_10_THENA,,,,"Na druhou stranu, možná ne.",Men måske heller ikke,"Andererseits, vielleicht aber auch nicht",,"Tamen, eble ne.","Aunque, tal vez no",,"Mutta toisaalta, ehken sittenkään",Quoi que cela soit peu probable.,"Jól átgondolva, inkább nem",O potrei anche non esserlo,まあ、有り得ないな,허나... 그러지는 않겠지.,"Maar nogmaals, misschien niet",Men kanskje ikke,"Z drugiej strony, może nie...","Pensando melhor, talvez não",,"Dar apoi, poate că nu","А может быть, и нет",А можда и нећу,"Men å andra sidan, kanske inte.","Sonra tekrar, belki de değil" +One ninth of the puzzle has been solved,TXT_ACS_MAP28_6_ONENI,,,,V Klášteru byla vyřešena,En niende del af puslespillet er blevet løst,Ein Neuntel des Rätsels wurde gelöst,,Unu naŭono de la puzlo estas solvita,Un noveno del acertijo se ha resuelto,,Yhdeksäsosa pulmasta on ratkaistu,Un neuvième du puzzle à été résolu,A rejtvény egy kilencede megfejtésre került,Un nono del puzzle è stato risolto,九種のパズルの一つが解かれた,수수께끼의 9분의 1이 풀렸다,Een negende van de puzzel is opgelost.,En niende del av puslespillet er løst.,Jedna dziewiąta zagadki rozwiązana,Um nono do quebra-cabeça foi resolvido,,O noime din puzzle a fost rezolvată,Одна девятая головоломки разгадана,Деветина загонетке је решена,En niondel av pusslet har lösts.,Bulmacanın dokuzda biri çözüldü +On the Monastery,TXT_ACS_MAP28_7_ONTHE,,,,jedna devítina rébusu.,På klosteret,Im Kloster,,en la Monaĥejo.,En el Monasterio,,luostarissa,dans le monastère.,A Monostorban,Nel Monastero,修道院 にわずかに影響を与えた,... 헤러시아크의 신학교에서,Op het klooster,på klosteret,w Klasztorze,No Mosteiro,,pe Mănăstire,в семинарии Ересиарха,у Јересијарховој семинарији,På klostret,Manastır Üzerine +One ninth of the puzzle has been solved,TXT_ACS_MAP30_6_ONENI,,,,V Klášteru byla vyřešena,En niende del af puslespillet er blevet løst,Ein Neuntel des Rätsels wurde gelöst,,Unu naŭono de la puzlo estas solvita,Un noveno del acertijo se ha resuelto,,Yhdeksäsosa pulmasta on ratkaistu,Un neuvième du puzzle à été résolu,A rejtvény egy kilencede megfejtésre került,Un nono del puzzle è stato risolto,九種のパズルの一つが解かれた,수수께끼의 9분의 1이 풀렸다,Een negende van de puzzel is opgelost.,En niende del av gåten er løst.,Jedna dziewiąta zagadki rozwiązana,Um nono do quebra-cabeça foi resolvido,,O noime din puzzle a fost rezolvată,Одна девятая головоломки разгадана,Деветина загонетке је решена,En niondel av pusslet har lösts.,Bulmacanın dokuzda biri çözüldü +On the Monastery,TXT_ACS_MAP30_7_ONTHE,,,,jedna devítina rébusu.,På klosteret,Im Kloster,,en la Monaĥejo.,En el Monasterio,,luostarissa,dans le monastère.,A Monostorban,Nel Monastero,修道院 にわずかに影響を与えた,... 헤러시아크의 신학교에서,Op het klooster,på klosteret,w Klasztorze,No Mosteiro,,pe Mănăstire,в семинарии Ересиарха,у Јересијарховој семинарији,På klostret,Manastır Üzerine +One ninth of the puzzle has been solved,TXT_ACS_MAP34_1_ONENI,,,,V Klášteru byla vyřešena,En niende del af puslespillet er blevet løst,Ein Neuntel des Rätsels wurde gelöst,,Unu naŭono de la puzlo estas solvita,Un noveno del acertijo se ha resuelto,,Yhdeksäsosa pulmasta on ratkaistu,Un neuvième du puzzle à été résolu,A rejtvény egy kilencede megfejtésre került,Un nono del puzzle è stato risolto,九種のパズルの一つが解かれた,수수께끼의 9분의 1이 풀렸다,Een negende van de puzzel is opgelost.,En niendedel av puslespillet er løst,Jedna dziewiąta zagadki rozwiązana,Um nono do quebra-cabeça foi resolvido,,O noime din puzzle a fost rezolvată,Одна девятая головоломки разгадана,Деветина загонетке је решена,En nionde del av pusslet har lösts.,Bulmacanın dokuzda biri çözüldü +On the Monastery,TXT_ACS_MAP34_2_ONTHE,,,,jedna devítina rébusu.,På klosteret,Im Kloster,,en la Monaĥejo.,En el Monasterio,,luostarissa,dans le monastère.,A Monostorban,Nel Monastero,修道院 にわずかに影響を与えた,... 헤러시아크의 신학교에서,Op het klooster,på klosteret,w Klasztorze,No Mosteiro,,pe Mănăstire,в семинарии Ересиарха,у Јересијарховој семинарији,På klostret,Manastır Üzerine +The portal has been sealed,TXT_ACS_MAP35_0_THEPO,,,,Portál byl zapečeťen.,Portalen er blevet forseglet,Das Portal wurde versiegelt,,La portalo estas obturita.,El portal se ha sellado,,Portaali on sinetöity,Le portail est scellé.,Az átjáró bezárult.,Il portale è stato sigillato,ポータルは封印された,차원문은 봉인되었다,Het portaal is verzegeld,Portalen har blitt forseglet,Portal został zapieczętowany,O portal foi selado,,Portalul a fost închis,Портал закрылся,Врата су затворена,Portalen har förseglats.,Geçit mühürlendi +Choose your fate,TXT_ACS_MAP35_1_CHOOS,,,,Vyber si svůj osud.,Vælg din skæbne,Wähle dein Schicksal,,Elektu vian fatalon.,Escoge tu destino,Escoge tú destino,Valitse kohtalosi,Choisissez votre sort.,Dönts sorsod felől,Scegli la tua sorte,運命を撰べ,그대의 운명을 정해라,Kies uw lot,Velg din skjebne,Wybierz swoje przeznaczenie,Escolha o seu destino,,Alegeți destinul,Сделай свой выбор,Донеси своју одлуку,Välj ditt öde,Kaderinizi seçin +The door is barred from the inside,TXT_ACS_MAP35_3_THEDO,,,,Dveře jsou zatarasené zevnitř.,Døren er spærret indefra,Die Tür ist von innen verriegelt,,La pordo estas barita interne.,La puerta está atrancada desde el interior,,Ovi on teljetty sisältä,Cette porte est bloquée de l'intérieur.,Az ajtót belülről torlaszolták el.,La porta è sbarrata da dentro,この扉は内側から塞がれている,이 문은 안에 빗장이 걸려있다,De deur is van binnenuit geblokkeerd.,Døren er sperret fra innsiden,Drzwi są zabarykadowane od środka,A porta está barrada por dentro,,Ușa e blocată dinăuntru,Дверь заблокирована изнутри,Врата су забрављена изнутра,Dörren är spärrad från insidan,Kapı içeriden kilitli. +Are you strong enough,TXT_ACS_MAP35_12_AREYO,,,,"Jsi dost siln@[adj_cs],",Er du stærk nok?,Bist du stark genug,,Ĉu vi estas sufiĉe forta,Eres lo suficientemente fuerte,,Olet riittävän vahva,Etes vous suffisamment fort,"Elég erős vagy,",Sei abbastanza forte,お前がどれだけ強かろうと,네 놈은 주인들을 대면할 힘이...,Ben je sterk genoeg,Er du sterk nok,Czy jesteś wystarczająco silny,Você é forte o suficiente,,Ești întradevăr suficient de puternic,"Достаточно ли ты силён,",Јеси ли довољно снажан,Är du stark nog?,Yeterince güçlü müsün? +To face your own masters?,TXT_ACS_MAP35_14_TOFAC,,,,čelit svým vlastním pánům?,Til at møde dine egne mestre?,Dich deinen eigenen Meistern zu stellen?,,por stari kontraŭ viaj propraj mastroj?,¿Para enfrentarte a tus maestros?,,kohtaamaan omat mestarisi?,pour faire face à vos maîtres?,Hogy saját mestereiddel nézz szembe?,Da affrontare i tuoi stessi maestri?,お前の師に立ち向かえるのか?,진심으로 있는 것인가?,Om je eigen meesters onder ogen te komen?,Til å møte dine egne mestere?,By stawić czoła swoim mistrzom?,Para enfrentar os seus próprios mestres?,,Să îți înfrunți proprii stăpâni?,чтобы сразиться со своими наставниками?,да се суочиш са својим господарима?,För att möta dina egna mästare?,Kendi efendilerinizle yüzleşmek için mi? +,,Hexen: Deathkings script texts,,,,,,,,,,,,,,,,,,,,,,,,, +You dare battle in the ready room?,TXT_ACS_MAP33_6_YOUDA,,,,Ty si dovoluješ rvát se v přípravné místnosti?,Tør du kæmpe i beredskabsrummet?,Du wagst es im Bereitschaftsraum zu kämpfen?,,Vi aŭdacas batali en la pretĉambro?,¿Te atreves a luchar en la sala de preparación?,,Kuinka kehtaat taistella valmistautumishuoneessa?,Vous osez faire escarmouche dans la salle de préparation?,Hogy merészelsz harcolni a váróteremben?,Hai il coraggio di combattere in questa sala?,挑戦する準備は整ったか?,감히 준비의 방에서 전투를 벌이다니...,Durf jij te vechten in de readyroom?,Våger du å kjempe i det klare rommet?,Śmiesz walczyć w pokoju przygotowań?,Como ousa batalhar na sala de espera?,,Îndrăznești să lupți în camera de așteptare?,Ты посмел сражаться в комнате ожидания?,Усуђујеш се борити у припремној соби?,Vågar du slåss i det färdiga rummet?,Hazırlanma odasında savaşmaya mı cüret ediyorsun? +"For that, you shall die!",TXT_ACS_MAP33_7_FORTH,,,,Pro to zemřeš!,For det skal du dø!,Dafür sollst du sterben!,,"Pro tio, vi mortos!","Por eso, ¡deberás morir!",,Siitä hyvästä kuolet!,"Pour cette insulte, vous trépasserez!",Ezért meghalsz!,"Per questo, morirai!",ならば、死へ進め!,죽어서 값을 치러라!,Daarvoor zal je sterven!,For det skal du dø!,Umrzesz za to!,Você morrerá por isso!,,"Pentru asta, vei muri!",Так умри же!,За то ћеш умрети!,För det ska du dö!,Bunun için öleceksin! +The waterfall is open,TXT_ACS_MAP41_6_THEWA,,,,Vodopád je otevřen.,Vandfaldet er åbent,Der Wasserfall ist geöffnet,,La akvofalo estas malferma.,La cascada se ha abierto,,Vesiputous on auki,La cascade s'est ouverte.,A vizesés nyitva,La cascata è aperta,滝 は開いた,폭포가 멈췄다,De waterval is open,Fossen er åpen,Wodospad jest otwarty,A cascata está aberta,,Cascada e deschisă,Поток воды остановлен,Водопад је отворен,Vattenfallet är öppet,Şelale açık +The waterfall is blocked,TXT_ACS_MAP41_7_THEWA,,,,Vodopád je zatarasen.,Vandfaldet er blokeret,Der Wasserfall ist blockiert,,La akvofalo estas barita.,La cascada está bloqueada,,Vesiputous on tukittu,La cascade est bloquée.,A vizesés zárva,La cascata è bloccata,滝 は塞がっている,폭포에 의해 막혔다,De waterval is geblokkeerd,Fossen er blokkert,Wodospad jest zablokowany,A cascata está bloqueada,,Cascada e închisă,Поток воды преграждает путь,Водопад је блокиран,Vattenfallet är blockerat,Şelale tıkalı +A door has opened in the chapel,TXT_ACS_MAP41_8_ADOOR,,,,Dveře se otevřely v kapli.,Der er åbnet en dør i kapellet,Eine Tür in der Kapelle hat sich geöffnet,,Pordo malfermis en la kapelo.,Una puerta se abrió en la Capilla,,Ovi on avautunut kappelissa,Une porte s'est ouverte dans la chapelle.,Egy ajtó kitárult a kápolnában,Una porta si è aperta nella cappella,庵寺 への扉が開いた,교외 근처에서 문이 열렸다,Een deur is geopend in de kapel,En dør har åpnet seg i kapellet,Drzwi w kaplicy zostały otwarte,Uma porta se abriu na capela,,O ușă s-a deschis în capelă,Дверь открылась в часовне,Врата су се отворила у катедрали,En dörr har öppnats i kapellet.,Şapelde bir kapı açıldı. +Now that's odd...,TXT_ACS_MAP42_4_NOWTH,,,,Tak to je divné...,Det er mærkeligt...,Hm. Das ist merkwürdig...,,Nun tio estas stranga...,Eso es extraño...,,Onpa kummallista...,Ca c'est étrange....,Ez felettébb különös...,Questo sì che è strano...,何かがおかしい...,무언가가 이상하다...,Dat is vreemd....,Det var merkelig...,Dziwne...,Que estranho...,,Asta e ciudat...,Как странно...,То је чудно...,Det där är konstigt...,İşte bu garip. +Three more parts of the puzzle remain,TXT_ACS_MAP44_1_THREE,,,,Zbývají tři části rébusu.,Der er endnu tre dele af gåden tilbage,Drei weitere Teile des Rätsels verbleiben,,Nur tri partoj de la puzlo restas.,Quedan tres partes más del acertijo,,Kolme pulman palasta jäljellä,Trois parties du puzzle restent à résoudre.,Három rész maradt a rejtvényből,Rimangono altre tre parti del puzzle,パズルの部品は残り 3つ,3개의 수수께끼가 아직 풀리지 않았다,Er blijven nog drie onderdelen van de puzzel over,Tre deler av puslespillet gjenstår,Pozostały jeszcze trzy części zagadki,Faltam mais três partes do quebra-cabeça,,Trei părți din puzzle încă rămân,Остались три части головоломки,Остају још три дела загонетке ,Det återstår tre delar av pusslet.,Bulmacanın üç parçası daha kaldı. +Two more parts of the puzzle remain,TXT_ACS_MAP44_2_TWOMO,,,,Zbývají dvě části rébusu.,Der er endnu to dele af puslespillet tilbage,Zwei weitere Teile des Rätsels verbleiben,,Nur du partoj de la puzlo restas.,Quedan dos partes más del acertijo,,Kaksi pulman palasta jäljellä,Deux parties du puzzle restent à résoudre.,Kettő rész maradt a rejtvényből,Rimangono altre due parti del puzzle,パズルの部品は残り 2つ,2개의 수수께끼가 아직 풀리지 않았다,Twee andere delen van de puzzel blijven over,To deler av puslespillet gjenstår,Pozostały jeszcze dwie części zagadki,Faltam mais duas partes do quebra-cabeça,,Două părți din puzzle încă rămân,Остались две части головоломки,Остају још два дела загонетке,Ytterligare två delar av pusslet återstår,Bulmacanın iki parçası daha kaldı +One more part of the puzzle remains,TXT_ACS_MAP44_3_ONEMO,,,,Zbývá jedna část rébusu.,Der er endnu en del af puslespillet tilbage,Ein weiteres Teil des Rätsels ist übrig,,Nur unu parto de la puzlo restas.,Queda una parte más del acertijo,,Yksi pulman palanen jäljellä,Il reste une partie du puzzle à résoudre.,Egy rész maradt a rejtvényből,Rimane un'altra parte del puzzle,パズルの部品は残り 1つ,마지막 수수께끼가 아직 풀리지 않았다,Nog een deel van de puzzel blijft over,En del av puslespillet gjenstår,Pozostała jeszcze jedna część zagadki,Falta mais uma parte do quebra-cabeça,,O parte din puzzle încă rămâne,Осталась одна часть головоломки,Остаје још један део загонетке,Ytterligare en del av pusslet återstår,Bulmacanın bir parçası daha kaldı +The puzzle is complete,TXT_ACS_MAP44_4_THEPU,,,,Rébus je kompletní.,Puslespillet er færdigt,Das Rätsel ist abgeschlossen,,La puzlo estas kompleta.,El acertijo está completo,,Pulma on ratkaistu,Le puzzle est résolu.,A rejtvény végleg megoldódott,Il puzzle è completo,パズルは完成した,모든 수수께끼가 풀렸다,De puzzel is compleet,Puslespillet er komplett,Zagadka ukończona,O quebra-cabeça está concluído,,Puzzle-ul e rezolvat,Головоломка разгадана,Загонетка је решена,Pusslet är komplett,Bulmaca tamamlandı +You have not completed the puzzle,TXT_ACS_MAP44_6_YOUHA,,,,Nesplnil jsi rébus.,Du har ikke fuldført puslespillet,Du hast das Rätsel noch nicht gelöst,,Vi ne kompletis la puzlon.,No has completado el acertijo,,Et ole ratkaissut pulmaa,Vous n'avez pas résolu le puzzle.,Nem fejtetted meg a rejtvényt,Non hai completato il puzzle,パズルはまだ完成していない,모든 수수께끼를 풀지 못했다,Je hebt de puzzel nog niet voltooid.,Du har ikke fullført puslespillet,Nie ukończyłeś zagadki,Você não concluiu o quebra-cabeça,,Nu ai rezolvat puzzle-ul,Головоломка не разгадана,Нисте решили загонетку,Du har inte fullbordat pusslet,Bulmacayı tamamlamadınız +The floor is not safe!,TXT_ACS_MAP44_8_THEFL,,,,Podlaha není bezpečná!,Gulvet er ikke sikkert!,Der Boden hier ist nicht sicher!,,La planko ne estas sendanĝera!,¡El suelo no es seguro!,,Kerros ei ole turvallinen!,Le sol est dangereux!,A padló nem biztonságos!,Il pavimento è pericoloso!,この場は安全ではない!,이 층은 안전하지 않다!,De vloer is niet veilig!,Gulvet er ikke trygt!,Ta podłoga nie jest bezpieczna!,O chão não está seguro!,,Podeaua nu e sigură!,Пол совсем прогнил!,Под није безбедан!,Golvet är inte säkert!,Zemin güvenli değil! +One third of the puzzle is solved,TXT_ACS_MAP44_10_ONETH,,,,Jedna třetina rébusu je vyřešena.,En tredjedel af puslespillet er løst,Ein Drittel des Rätsels ist gelöst,,Unu triono de la puzlo estas solvita.,Un tercio del acertijo se ha resuelto,,Kolmannes pulmasta on ratkaistu,Un tiers du puzzle à été résolu,A rejtvény egyharmada megoldásra került,Un terzo del puzzle è stato risolto,パズルの 三分の一 が解かれた,수수께끼의 3분의 1이 풀렸다,Een derde van de puzzel is opgelost.,En tredjedel av puslespillet er løst,Jedna trzecia zagadki rozwiązana,Um terço do quebra-cabeça foi resolvido,,O treime din puzzle e rezolvată,Одна треть головоломки разгадана,Трећина загонетке је решена,En tredjedel av pusslet är löst,Bulmacanın üçte biri çözüldü +Two thirds of the puzzle is solved,TXT_ACS_MAP44_11_TWOTH,,,,Dvě třetiny rébusu jsou vyřešeny.,To tredjedele af puslespillet er løst,Zwei Drittel des Rätsels sind gelöst,,Du trionoj de la puzlo estas solvita.,Dos tercios del acertijo se han resuelto,,Kaksi kolmannesta pulmasta on ratkaistu,Deux tiers du puzzle ont été résolus,A rejtvény kétharmada megoldásra került,Due terzi del puzzle sono stati risolto,パズルの 三分の二 が解かれた,수수께끼의 3분의 2가 풀렸다,Tweederde van de puzzel is opgelost,To tredjedeler av puslespillet er løst.,Dwie trzecie zagadki rozwiązane,Dois terços do quebra-cabeça foi resolvido,,Două treimi din puzzle sunt rezolvate,Две трети головоломки разгаданы,Две трећине загонетке су решене,Två tredjedelar av pusslet är löst.,Bulmacanın üçte ikisi çözüldü +You hear a platform moving in the distance,TXT_ACS_MAP45_1_YOUHE,,,,Slyšíš v dálce pohybující se plošinu.,Du hører en platform bevæge sig i det fjerne,"Du hörst, wie sich in der Ferne eine Platform bewegt",,Vi aŭdas plataĵon movantan malproksime.,Escuchas una plataforma moverse a la distancia,,Kuulet lavan liikkuvan etäällä,Vous entendez une plateforme se déplacer au loin,Egy emelvény mozgását hallod a távolban,Senti una piattaforma muoversi in lontananza,昇降機の音が遠くで聞こえる,멀리서 보행판이 움직이는 소리가 들려왔다,Je hoort een platform bewegen in de verte,Du hører en plattform bevege seg i det fjerne,Słyszysz odgłos poruszającej się w oddali platformy,Você ouve de longe uma plataforma se movendo,,Auzi o platformă mișcându-se în depărtare,"Неподалёку раздаётся звук +движущейся деревянной площадки",Чујете како се платформа помера у даљини,Du hör en plattform som rör sig på avstånd.,Uzakta bir platformun hareket ettiğini duyuyorsunuz. +It is done...,TXT_ACS_MAP46_0_ITISD,,,,Je to dokonáno...,Det er gjort...,Es ist getan...,,Ĝi estas farita...,Está terminado...,,Se on tehty...,C'est terminé...,Készen van...,È fatto...,これで完了だ...,이제 끝났다...,Het is gebeurd,Det er gjort...,"Zrobione... +",Pronto...,,E gata...,Готово...,Готово је...,Det är gjort...,Bitti... +You have not completed the puzzle,TXT_ACS_MAP46_1_YOUHA,,,,Nesplnil@[ao_cs] jsi rébus.,Du har ikke løst puslespillet,Du hast das Rätsel noch nicht gelöst,,Vi ne kompletis la puzlon.,No has completado el acertijo,,Et ole ratkaissut pulmaa,Vous n'avez pas résolu le puzzle.,Nem fejtetted meg a rejtvényt.,Non hai completato il puzzle,パズルはまだ完成していない,모든 수수께끼를 풀지 못했다,Je hebt de puzzel nog niet voltooid...,Du har ikke fullført puslespillet,Nie ukończyłeś zagadki,Você não terminou o quebra-cabeça,,Nu ai rezolvat puzzle-ul,Головоломка не разгадана,Ниси решио загонетку,Du har inte fullbordat pusslet.,Bulmacayı tamamlamadınız +I'm warning you...,TXT_ACS_MAP46_2_IMWAR,,,,Varuju tě...,Jeg advarer dig...,Ich warne dich...,,Mi avertas vin...,Te lo advierto...,,Varoitan sinua...,Je vous avertis...,Figyelmeztetlek...,Ti avverto...,お前に警告しよう...,나는 경고했다...,Ik waarschuw je...,Jeg advarer deg...,Ostrzegam cię...,Estou te avisando...,,Te avertizez...,Я тебя предупреждаю...,Упозоравам те...,Jag varnar dig...,Seni uyarıyorum. +"Stubborn, aren't you?",TXT_ACS_MAP46_3_STUBB,,,,"Ty jsi ale tvrdohlav@[adj_cs], ne?","Du er stædig, ikke sandt?","Du bist aber stur, was?",,"Vi estas obstina, ĉu ne?","Eres obstinado, ¿verdad?",,Oletpa itsepäinen,"Obstiné, n'est-ce pas?","Makacs vagy, ugye?",Sei proprio così testardo?,頑固だと、自らも思わないか?,정말 끈질기군.,"Koppig, nietwaar?","Du er sta, ikke sant?","Jesteś uparty, prawda?","Você é teimos@[ao_ptb], não é mesmo?",,"Încăpățânat, nu-i așa?",Не слишком ли ты упрямый?,"Тврдоглав си, зар не?","Du är envis, eller hur?","İnatçısın, değil mi?" +"And stupid, too",TXT_ACS_MAP46_4_ANDST,,,,A taky hloup@[adj_cs].,Og også dum,Und auch noch dumm,,Kaj ankaŭ stulta.,"Y estúpido, también",,Ja vieläpä tyhmä,"Et stupide, aussi.",És oktondi is.,"E stupido, pure",そして、あまりにも愚か者だ,어리석기도 하고.,En ook dom,Og dum også.,Głupi też,E estúpid@[ao_ptb] também,,"Și prost, pe deasupra",И не слишком-то разумный!,А још си и глуп,Och dum också.,Ve de aptal. +One fourth of this puzzle is complete,TXT_ACS_MAP46_8_ONEFO,,,,Jedna čtvrtina rébusu je vyřešena.,En fjerdedel af dette puslespil er fuldført,Ein Viertel des Rätsels ist gelöst,,Unu kvarono de la puzlo estas kompleta.,Un cuarto del acertijo se ha resuelto,,Neljännes pulmasta on ratkaistu,Un quart du puzzle à été résolu,Egy negyede e rejtvénynek megvan.,Un quarto del puzzle è completo,パズルの 四分の一 が解かれた,수수께끼의 4분의 1만 풀렸다,Een vierde van deze puzzel is compleet,En fjerdedel av dette puslespillet er ferdig,Jedna czwarta tej zagadki ukończona,Um quarto deste quebra-cabeça está completo,,O pătrime din puzzle e rezolvată,Одна четвёртая этой головоломки разгадана,Четвртина загонетке је решена,En fjärdedel av pusslet är klart.,Bu bulmacanın dörtte biri tamamlandı +Bad choice...,TXT_ACS_MAP46_9_BADCH,,,,Špatná volba.,Dårligt valg...,Falsche Wahl...,,Malbona elekto...,Mala decisión...,,Huono valinta...,Mauvaise décision...,Rossz választás...,Scelta sbagliata...,拙い選択だ...,서투른 선택이다...,Slechte keuze....,Dårlig valg...,Zły wybór...,Péssima escolha...,,Proastă alegere...,Плохой выбор...,Лош избор...,Dåligt val...,Kötü seçim... +The symbols are not aligned,TXT_ACS_MAP47_2_THESY,,,,Symboly nejsou zarovnány.,Symbolerne er ikke på linje med hinanden.,Die Symbole sind nicht ausgerichtet,,La simboloj ne estas liniiga.,Los símbolos no están alineados,,Symbolit eivät ole järjestyksessä,Les symboles ne sont pas alignés.,A jelek nincsenek vonalban,I simboli non sono allineati,シンボルが揃っていない,상징이 정렬되지 않았다,De symbolen zijn niet uitgelijnd,Symbolene er ikke på linje.,Symbole nie są wyrównane,Os símbolos não estão alinhados,,Simbolurile nu sunt aliniate,Символы не совпадают,Симболи нису поравнати,Symbolerna är inte i linje med varandra.,Semboller aynı hizada değil +The door won't open from this side,TXT_ACS_MAP48_2_THEDO,,,,Dveře se z této strany neotevřou.,Døren kan ikke åbnes fra denne side.,Die Tür kann sich von dieser Seite nicht öffnen,,La pordo ne malfermiĝas.,La puerta no abrirá por este lado,,Ovi ei aukea tältä puolelta,La porte ne s'ouvre pas de ce côté.,Az ajtó nem fog kinyílni innen.,La porta non si apre da questo lato,扉はこちら側から開けられない,이 문은 이 방향으로는 열리지 않는다,De deur gaat niet open van deze kant,Døren kan ikke åpnes fra denne siden,Drzwi nie otworzą się z tej strony,A porta não se abrirá deste lado,,Ușile nu se vor deschide de pe partea asta,С этой стороны дверь не открыть,Врата неће да се отворе са стране,Dörren öppnas inte från den här sidan.,Kapı bu taraftan açılmıyor. +The door is barred from the outside,TXT_ACS_MAP50_1_THEDO,,,,Dveře jsou zatarasené zvenku.,Døren er spærret udefra,Die Tür ist von außen verriegelt,,La pordo estas barita ekstere.,La puerta está atrancada por fuera,,Ovi on teljetty ulkopuolelta,Cette porte est bloquée de l'extérieur.,Az ajtó kívülről van eltorlaszolva.,La porta è sbarrata da fuori,この扉は外側から塞がれている,이 문은 바깥에 빗장이 걸려있다,De deur is van buitenaf uitgesloten,Døren er sperret fra utsiden,Drzwi są zabarykadowane od zewnątrz,A porta está barrada por fora,,Ușa e încuiată pe dinafară,Дверь заблокирована снаружи,Врата су блокирана споља,Dörren är spärrad från utsidan,Kapı dışarıdan parmaklıklı. +Sacrilege !,TXT_ACS_MAP51_5_SACRI,,,,Svatokrádež!,Helligbrøde!,Gotteslästerung!,,Sakrilegio !,¡Sacrilegio!,,Pyhäinhäväistys !,Sacrilège!,Szentségtörés!,Sacrilegio !,罰当たりが!,신성모독이다!,Heiligschennis!,Helligbrøde!,Świętokradztwo !,Sacrilégio!,,Sacrilegiu!,Святотатство!,Светогрђе !,Helgerån!,Kutsala saygısızlık! +You have defiled Eric's tomb !!,TXT_ACS_MAP51_6_YOUHA,,,,Znesvětil@[ao_cs] jsi Erikovu hrobku!!,Du har besudlet Erics grav!!,Du hast Erics Gruft entehrt!!,,Vi malpurigis la tombon de Eric !!,¡Has profanado la tumba de Erick!,,Olet turmellut Ericin haudan !!,Vous avez vandalisé la tombe d'Eric!,Megszentségtelenítetted Eric sírját!,Hai profanato la tomba di Eric !!,貴様はエリックの墓を荒らしたな!!,네 놈은 성 에릭의 무덤을 더렵혔다!!,Je hebt Eric's graf bevlekt!!,Du har vanhelliget Erics grav !!!,Zhańbiłeś grób Erica !!,Você violou a tumba de Eric!,,Ai profanat mormântul lui Eric!!,Ты осквернил@[ao_rus] могилу Эрика!!,Оскрнавио си Ерикову гробницу !!,Du har besudlat Erics grav!!,Eric'in mezarını kirlettin! +And now you die !!!,TXT_ACS_MAP51_7_ANDNO,,,,Teď zemřeš!!!,Og nu skal du dø!!!!,Und nun stirbst du!,,Kaj nun vi mortas !!!,¡Y ahora morirás!,,Ja nyt sinä kuolet !!!,"Pour cela, vous allez mourir!",És most meghalsz!,E ora muori !!!,万死に値する!!!,그 댓가로 목숨을 바쳐라!!!,En nu ga je dood!!!!!,Og nå dør du!!!,I teraz zginiesz !!!,E agora você morrerá!!!,,"Iar acum, mori!!",И умрёшь за это страшной смертью!!!,И због тога ћеш умрети !!!,Och nu dör du !!!,Ve şimdi öleceksin!!! +One third of the puzzle is solved,TXT_ACS_MAP51_8_ONETH,,,,Jedna třetina rébusu je vyřešena.,En tredjedel af gåden er løst,Ein Drittel des Rätsels ist gelöst,,Unu triono de la puzlo estas solvita.,Un tercio del acertijo se ha resuelto,,Kolmannes pulmasta on ratkaistu,Un tiers du puzzle à été résolu,A rejtvény egyharmada megoldásra került.,Un terzo del puzzle è stato risolto,パズルの 三分の一 が解かれた,수수께끼의 3분의 1이 풀렸다,Een derde van de puzzel is opgelost.,En tredjedel av gåten er løst,Jedna trzecia zagadki rozwiązana,Um terço do quebra-cabeça foi resolvido,,O treime din puzzle e rezolvată,Одна треть головоломки разгадана,Трећина загонетке је решена,En tredjedel av pusslet är löst,Bulmacanın üçte biri çözüldü. +Two thirds of the puzzle is solved,TXT_ACS_MAP51_9_TWOTH,,,,Dvě třetiny rébusu jsou vyřešeny.,To tredjedele af gåden er løst,Zwei Drittel des Rätsels sind gelöst,,Du trionoj de la puzlo estas solvita.,Dos tercios del acertijo se han resuelto,,Kaksi kolmannesta pulmasta on ratkaistu,deux tiers du puzzle ont été résolus,A rejtvény kétharmada megoldásra került.,Due terzi del puzzle è stato risolto,パズルの 三分の二 が解かれた,수수께끼의 3분의 2가 풀렸다,Tweederde van de puzzel is opgelost,To tredjedeler av puslespillet er løst.,Dwie trzecie zagadki rozwiązane,Dois terços do quebra-cabeça foi resolvido,,Două treimi din puzzle sunt rezolvate,Две трети головоломки разгаданы,Две трећине загонетке су решене,Två tredjedelar av pusslet är löst.,Bulmacanın üçte ikisi çözüldü +The crypt is open,TXT_ACS_MAP51_10_THECR,,,,Krypta je otevřena.,Krypten er åben,Die Gruft ist offen,,La kripto estas malfermita.,La cripta ahora está abierta,,Krypta on auki,La crypte est ouverte,A kripta kinyílt.,La cripta è aperta,地下聖堂 が開いた,지하 묘실의 입구가 열렸다.,De crypte is open,Krypten er åpen,Krypta jest otwarta,A cripta está aberta,,Cripta e deschisă,Склеп открыт,Гробница је отворена,Kryptan är öppen.,Mahzen açık +Beware the spider's tomb,TXT_ACS_MAP51_11_BEWAR,,,,Vyvaruj se pavoučí hrobky.,Pas på edderkoppens grav,Hüte dich vor dem Grab der Spinne,,Singardu en la tombo de la araneo.,Cuidado con la tumba de la araña,,Varo hämähäkin hautaa,Attention à la tombe de l'araignée.,Óvakodj a pók sírjától!,Attento alla tomba del ragno,スパイダーの墓,거미의 무덤을 조심하라,Pas op voor het graf van de spin,Se opp for edderkoppens grav,Strzeż się grobowca pająków,Cuidado com a tumba da aranha,,Păzește-te de mormântul păianjenului,Опасайся гробницы паука,Чувај се паукове гробнице,Akta dig för spindelns grav,Örümceğin mezarına dikkat edin +You hear a platform rise outside,TXT_ACS_MAP51_13_YOUHE,,,,Slyšíš zvenku zvedající se platformu.,Du hører en platform rejse sig udenfor,"Du hörst, wie sich draußen eine Plattform erhebt",,Vi aŭdas plataĵon leviĝantan ekstere.,Escuchas una plataforma erguirse afuera,,Kuulet lavan kohoavan ulkopuolella,Vous entendez une platforme s'élever dehors,Egy emelvényt hallasz emelkedni odakinn,Senti una piattaforma alzarsi in lontananza,外で昇降機の音が聞こえる,밖에서 보행판이 올라오는 소리가 들려왔다,Je hoort een platform buiten opstijgen,Du hører en plattform stige utenfor,Słyszysz odgłos unoszącej się na zewnątrz platformy,Você ouve uma plataforma subir lá fora,,Auzi o platformă ridicându-se afară,"Снаружи слышен звук +поднимающегося камня",Чујете како се платформа диже споља,Du hör en plattform stiga upp utanför.,Dışarıda bir platformun yükseldiğini duyarsınız +Do you feel lucky?,TXT_ACS_MAP51_14_DOYOU,,,,"Zdá se ti, že máš štěstí?",Føler du dig heldig?,Denkst du das heute dein Glückstag ist?,,Ĉu vi sentas vin bonŝanca?,¿Te sientes afortunado?,,Tunnetko olosi onnekkaaksi?,Vous pensez être chanceux?,Szerencsésnek érzed magad?,Ti senti fortunato?,運が良かったと思うか?,그대는 운수가 좋은가?,Heb je geluk?,Føler du deg heldig?,Masz szczęście?,Está se sentindo com sorte?,,Te simți norocos?,Чувствуешь ли ты себя везучим?,Да ли се осећаш срећним?,Känner du dig lycklig?,Kendinizi şanslı mı hissediyorsunuz? +You guessed wrong!,TXT_ACS_MAP51_15_YOUGU,,,,To máš smůlu!,Du gættede forkert!,Du hast falsch geraten!,,Vi divenis malĝuste!,¡Adivinaste incorrectamente!,,Arvasi väärin!,Et bien non!,Hát rosszul érzed!,Non hai indovinato!,それは違うな!,잘못된 판단이다!,Je hebt het verkeerd geraden!,Du gjettet feil!,Źle zgadłeś!,Adivinhou errado!,,N-ai ghicit!,Неправильное предположение!,Погрешно си погодио!,Du gissade fel!,Yanlış tahmin ettin! +Good guess,TXT_ACS_MAP51_16_GOODG,,,,Dobré zdání.,Godt gættet.,Gut geraten,,Bona diveno.,Buena elección,,Hyvä arvaus,Vous avez deviné!,Jól sejtetted,Hai indovinato,良い推測だ,옳은 판단이다,Goede gok,Godt gjettet,Dobrze zgadłeś,Certa resposta,,Ai ghicit,Правильное предположение,Добар погодак,Bra gissning,İyi tahmin +Can you do all the scripting for my level?,TXT_ACS_MAP51_17_CANYO,,,,Můžeš všechno skriptování udělat za mě?,Kan du lave alt scripting til mit niveau?,Kannst du die Skripte für all meine Level schreiben?,,Ĉu vi povas fari ĉiom da la skriptoj por mia nivelo?,¿Podrías hacer todo el script para mi nivel?,,Voitko tehdä kaikki tasoni skriptaukset?,Vous pouvez faire tout le script de mon niveau?,Meg tudnád csinálni az egészt scriptelést a pályámhoz?,Puoi fare tutto lo scripting per il mio livello?,この階層を全て書き換える事は可能かな?,어쩔 수 없이 살아간다. 태어났기 때문에...,Kun je al het scripten doen voor mijn niveau?,Kan du gjøre alt skriptet for mitt nivå?,Czy możesz zrobić cały skrypt do mojego poziomu?,Poderia fazer todo o scripting da minha fase?,,Te poți ocupa de scripting pentru nivelul meu?,"Может, напишешь за меня все скрипты для моего уровня?",Можеш ли да напишеш све скриптове за мој ниво?,Kan du göra alla skript för min nivå?,Benim seviyem için tüm senaryoyu yazabilir misin? +Don't touch my gloppy,TXT_ACS_MAP51_18_DONTT,,,,Nesahej mi na slimáka!,Rør ikke ved min gloppy,Berühr mein Ding nicht!,,Ne tuŝas mian gloppy-on.,No toques mi gloppy,,Älä koske mönjääni,Ne touche pas mon gloppy,Ne nyúlj a bizémhez,Non toccare la mia caramella,汚らしい手で触れるな,"에틴을 쳐죽인 것까지 신경 쓰다간, 걸을 수도 없을걸.",Raak mijn gloppy niet aan,Ikke rør min gloppy,Nie ruszaj moich słodyczy,Não toca no meu docinho!,,Nu-mi atinge bomboana,Не трогай мою вкусняшку,Не дирај мој слаткиш,Rör inte min glittriga,Benim cıvıklığıma dokunma. +Vorpal ?!?!?!,TXT_ACS_MAP51_19_VORPA,,,,Šaršoun?!?!?!,,Tödlich ?!?!?!,,Vorpal ?!?!?!,¡¿¡¿¡¿ Vorpal ?!?!?!,,Tappava ?!?!?!,,,,ボーパル ?!?!?!,드래곤 슬레이어 인가?!,,,Śmiercionośny ?!?!?!,Vorpal?!?!?!,,Vorpal?!?!?!,Остренько???!!!,Вајтолни мач ?!?!?!,,Vorpal?!?!?! +"Gimme some sugar, baby",TXT_ACS_MAP51_20_GIMME,,,,"Dej mi trochu cukru, zlato.","Giv mig noget sukker, baby","Gib mir etwas Zucker, Baby",,"Donu al mi iom da sukeron, knanjo.","Dame un poco de azúcar, baby","Dame algo de azúcar, bebe","Anna vähän sokeria, beibi",,"Tégy magadévá, kislány!",,砂糖が欲しいかい、ベイビー,등짝을 보자!...,"Geef me wat suiker, schatje.","Gi meg litt sukker, baby",Daj mi całusa skarbie,"Me dá um pouco de açúcar, baby",,"Dă-mi niște zahăr, dulceață","Подай-ка мне сахар, детка","Дај ми мало шећера, душо","Ge mig lite socker, baby","Bana biraz şeker ver, bebeğim." +Duh-uhhh...,TXT_ACS_MAP51_21_DUHUH,,,,A jéje.,,,,Da-aaaa...,,,Daa-aaa....,,Nyílván...,,えぇーとぉー...,낙원이란 있을 수 없는거야.,,,Oooooo...,Dãããã-ããã...,,,Ага-а-а-а...,Дух-уххх...,,Duh-uhhh... +Film in an hour?,TXT_ACS_MAP51_22_FILMI,,,,Film za hodinu?,Film om en time?,Film in einer Stunde?,,Kino post horo?,¿Película en una hora?,¿Una película en una hora?,Filmi tunnissa?,Un film dans une heure?,Egy film egy óra múlva?,Un film in un'ora?,数時間のフィルム?,신은 운명을 주셨죠. 만남이라는 운명을.,Film in een uur?,Film på en time?,Za godzinę film?,Quer ver um filme daqui a pouco?,,Film într-o oră?,Фильм за час?,Снимамо за сат времена?,Filma om en timme?,Bir saat içinde film mi? +I don't even get my own tombstone - cf,TXT_ACS_MAP51_23_IDONT,,,,Ani nemám svůj vlastní náhrobek. -CF,Jeg får ikke engang min egen gravsten - cf,Ich bekomme noch nicht einmal meinen eigenen Grabstein - cf,,Mi ne eĉ ekhavis mian propran tombŝtonon. - cf,Ni siquiera tengo mi propia lápida - cf,,En saa edes omaa hautakiveäni - cf,J'ai même pas le droit à ma propre tombe - cf,Még saját sírt sem kaptam - cf,Non ho potuto avere la mia pietra tombale - cf,私は自分の墓標すら得られない - cf,내 묘비를 세우지도 않았네 -cf,Ik krijg niet eens mijn eigen grafsteen - cf,Jeg får ikke engang min egen gravstein - cf...,Nawet nie dostałem swojego nagrobka - cf,Eu nem ganhei a minha própria lápide - cf,,Nici măcar nu primesc propria piatră de mormânt - cf,У меня даже нет своего надгробия (К. Ф.),Ја ни немам свој надгробни споменик - cf,Jag får inte ens min egen gravsten - cf,Kendi mezar taşımı bile alamıyorum - cf +Let no blood be spilt,TXT_ACS_MAP51_24_LETNO,,,,Nechť není prolita žádná krev.,Lad intet blod blive spildt,Lass kein Blut vergossen sein,,Lasu neniom da sango elflui.,Que no se derrame sangre,,Älköön yhtään verta vuodatettako,Qu'aucune goutte de sang ne soit tirée,Ne ontsunk ki vért,Si cerchi di non spargere sangue,血を零さないように,피 한 방울도 흘리지 말라,Laat geen bloed worden vergoten,La ikke noe blod bli spilt,Nie pozwól by krew została przelana,Que sangue nenhum seja derramado,,Fie ca sângele să nu fie vărsat,Да не прольётся кровь,Нека се не пролије крв,Låt inget blod spillas,Kan dökülmesin +Let no hand be raised in anger,TXT_ACS_MAP51_25_LETNO,,,,Nechť není žádná ruka hněvem zvednuta.,Lad ingen hånd blive løftet i vrede,Lass keine Hand in Wut erhoben sein,,Lasu nenion manon estas levita pro kolero.,Que ninguna mano se levante con ira,,Ei yhtäkään kättä kohotettako vihassa,Qu'aucune main de se lève avec colère,Ne emeljünk kezet haragból,Si cerchi di non alzare le mani per rabbia,怒りで拳を振るわないように,분노하여 주먹을 휘두르지 말라,Laat geen hand worden opgestoken in woede...,La ingen hånd bli løftet i sinne,Nie pozwól by ręka została uniesiona w gniewie,Que mão nenhuma seja erguida por raiva,,Fie ca nicio mână să nu fie ridicată în furie,И да не поднимется рука во гневе,Нека се ни рука из беса не подигне,Låt ingen hand höjas i ilska,Öfkeyle el kaldırmayın +Who dares disturb our slumber?,TXT_ACS_MAP52_9_WHODA,,,,Kdo se opovažuje narušit náš spánek?,Hvem vover at forstyrre vores slummer?,Wer wagt es unseren Schlummer zu stören?,,Kiu aŭdacas interrompi nian dormon? ,¿Quién se atreve a perturbar nuestro sueño?,,Kuka kehtaa häiritä untamme?,Qui ose troubler notre sommeil?,Ki meri megzavarni a szunyókálásunkat?,Chi osa disturbare il nostro riposo?,誰が、我々の眠りを妨げる勇気があるかな?,감히 우리의 숙면을 방해하는가?,Wie durft onze slaap te verstoren?,Hvem våger å forstyrre vår søvn?,Kto śmie przeszkadzać nam w drzemce?,Quem ousa perturbar o nosso descanso?,,Cine cutează să-mi perturbe odihna?,Кто осмелился потревожить наш покой?,Ко се усуђује узнемиравати наш спокој?,Vem vågar störa vår slummer?,Uykumuzu bölmeye kim cüret eder? +The way is open,TXT_ACS_MAP52_10_THEWA,,,,Cesta je otevřena.,Vejen er åben,Der Weg ist offen,,La vojo estas malfermita.,El camino está abierto,,Tie on auki,Le chemin est ouvert.,Az út kinyílt,La via è aperta,道は開いた,길이 열렸다,De weg is open,Veien er åpen,Droga jest otwarta,O caminho está aberto,,Calea e deschisă,Путь открыт,Пролаз је отворен,Vägen är öppen,Yol açık +You have ,TXT_ACS_MAP53_2_YOUHA,,,,Zbývají ti ,Du har,Du hast,,Vi havas,Tienes,,Sinulla on,Vous avez,Már csak,Hai,スイッチはまだ,지금 ,Je hebt,Du har,Masz,Restam ainda,,Mai ai,Осталось,Остало је ,Du har, +\x20switches left,TXT_ACS_MAP53_3_SWITC,,,,\x20spínače.,\x20kontakter tilbage,\x20Schalter übrig,,\x20ŝaltilojn ceterajn.,\x20interruptores restantes,\x20switches restantes,\x20vipua jäljellä,\x20boutons à trouver,\x20kallantyú van hátra,\x20interuttori rimanenti,残っている,개의 개폐기들이 남았다,\x20schakelaars over,\x20brytere igjen,\x20pozostałych przełączników,\x20interruptores,,\x20butoane rămase,\x20переключателей,\x20прекидача,\x20växlar kvar,\x20anahtarınız kaldı +You have only ,TXT_ACS_MAP53_4_YOUHA,,,,Zbývá ti jen ,Du har kun,Du hast nur,,Vi nur havas,Tienes solo,,Sinulla on vain,Vous avez seulement,Már csak,Hai solamente,スイッチは,이제 오로지 ,Je hebt alleen,Du har bare,Masz tylko,Resta somente,,Mai ai doar,Остался всего,Остао је само ,Du har bara, +\x20switch left,TXT_ACS_MAP53_5_SWITC,,,,\x20spínač.,\x20kontakter tilbage,\x20Schalter übrig,,\x20ŝaltilon ceteran.,\x20interruptor restante,\x20switch restante,\x20vipu jäljellä,\x20outon à trouver,\x20kallantyú van hátra,\x20interruttore rimanente,"だけ残っている +",개의 개폐기가 남았다,\x20schakelaar over,\x20bryter igjen,\x20przełącznik,\x20interruptor,,\x20buton rămas,\x20переключатель,\x20прекидач,\x20växel kvar,\x20anahtarınız kaldı +The exit is open,TXT_ACS_MAP53_6_THEEX,,,,Východ je otevřen.,Udgangen er åben,Der Ausgang ist offen,,La elirejo estas malfermita,La salida está abierta,,Ulospääsy on auki,La sortie est ouverte,A kijárat kinyílt,L'uscita è aperta,出口が開いた,출구가 열렸다,De uitgang is open,Utgangen er åpen,Wyjście jest otwarte,A saída está aberta,,Ieșirea e deschisă,Выход открыт,Излаз је отворен,Utgången är öppen,Çıkış açık +The doors won't open from this side,TXT_ACS_MAP54_1_THEDO,,,,Dveře se z této strany neotevřou.,Dørene kan ikke åbnes fra denne side,Die Türen werden sich nicht von dieser Seite öffnen,,La pordo ne malfermos de ĉi tio flanko.,Las puertas no se abren desde este lado,,Ovet eivät aukea tältä puolelta,Les portes ne s'ouvrent pas de ce côté,Az ajtó nem nyílik erről az oldalról,Le porte non si aprono da questo lato,扉はこちらから開けない,이 문들은 이 방향으로는 열리지 않는다,De deuren gaan niet open van deze kant....,Dørene kan ikke åpnes fra denne siden,Drzwi nie otworzą się z tej strony,As portas não se abrirão deste lado,,Ușile nu se vor deschide de pe partea asta,С этой стороны дверь не открыть,Врата неће да се отворе са стране,Dörrarna öppnas inte från den här sidan,Kapılar bu taraftan açılmıyor. +The doors are open...,TXT_ACS_MAP54_4_THEDO,,,,Dveře jsou otevřené...,Dørene er åbne...,Die Türen sind offen,,La pordoj estas malfermitaj...,Las puertas están abiertas...,,Ovet ovat auki...,Les portes sont ouvertes...,Az ajtók kitárultak...,Le porte sono aperte...,ドアは開いている...,문이 열렸다...,De deuren zijn open....,Dørene er åpne...,Drzwi są otwarte...,As portas estão abertas...,,Ușile sunt deschise...,Двери открыты...,Врата су отворена...,Dörrarna är öppna...,Kapılar açık. +...if you are ready,TXT_ACS_MAP54_5_IFYOU,,,,...jestli jsi připraven@[ao_cs].,...hvis du er klar,...Wenn du bereit bist,,...se vi pretas.,...si estás listo,,...jos olet valmis,...si vous êtes prêt.,...csak rád várunk.,...Se sei pronto,...準備が良いなら,... 준비 되었다면,...als je er klaar voor bent...,...hvis du er klar,...jeśli jesteś gotów,...se você estiver preparad@[ao_ptb],,...dacă ești pregătit,...осмелишься ли ты войти?,...ако си спреман,...om du är redo,...eğer hazırsanız +A door has opened,TXT_ACS_MAP54_9_ADOOR,,,,Dveře se otevřely,En dør er blevet åbnet,Eine Tür hat sich geöffnet,,Pordo malfermiĝis,Se ha abierto una puerta,Se abrió una puerta,Ovi on auennut,Une porte est ouverte,Egy ajtó kinyílt,Una porta è stata aperta,先へ進むドアは開いた,지금 문이 열렸다...,Een deur is geopend,En dør har åpnet seg,Drzwi otworzyły się,Uma porta se abriu,,O ușă s-a deschis,Дверь открылась,Врата су се отворила,En dörr har öppnats,Bir kapı açıldı +on the Chantry,TXT_ACS_MAP54_10_ONTHE,,,,v Modlitebně.,på Kirkerummet,In der Kantorei,,en la Kapelo.,En la capilla,,kappelissa,dans la chapelle.,a kápolnánál,Nella Cappella,小礼拝堂 へ向かえ,... 예배당에서,op de Chantry,på Minnekapellet,w Kaplicy Wotywnej,na Capela,,la Capelă,в часовне,у Капели,på Chantry,Chantry'de +A bridge has been built,TXT_ACS_MAP54_11_ABRID,,,,Most byl postaven,En bro er blevet bygget,Eine Brücke wurde errichtet,,Ponto estis konstruita,Se ha construido un puente,Se construyó un puente,Silta on rakennettu,Une pont a été construit,Egy hidat támasztottak fel,È stato costruito un ponte,先へ進む橋が架かった,다리가 건설되었다...,Er is een brug gebouwd,En bro har blitt bygget,Most został utworzony,Uma ponte foi construída,,Un pod a fost construit,Мост воздвигнут,Мост се саградио,En bro har byggts,Bir köprü inşa edildi +on the Abattoir,TXT_ACS_MAP54_12_ONTHE,,,,na Jatkách.,på Slagteriet,Im Schlachthaus,,en la Buĉejo.,En el matadero,,teurastamolla,dans l'abbatoir.,a vágóhídnál,Nella Macelleria, 屠殺場 へ向かえ,... 도살장에서,op het slachthuis,på slakteriet,w Rzeźni,no Matadouro,,pe Abator,у аббатства,на Кланици,på slakthuset,Mezbahada +A stair has been built,TXT_ACS_MAP54_13_ASTAI,,,,Schody byly postaveny,Der er bygget en trappe,Eine Treppe wurde errichtet,,Ŝtuparo estis konstruita,Se ha construido una escalera,Se construyó una escalera,Portaat on rakennettu,Un escalier a été construit,Lépcső emelkedett ki,È stata costruita una scalinata,先へ進む階段が出来た,계단이 건설되었다...,Er is een trap gebouwd,En trapp har blitt bygget,Schody zostały utworzone,Uma escada foi construída,,O scară a fost construită,Лестница воздвигнута,Степенице су се саградиле,En trappa har byggts,Bir merdiven inşa edildi +on the Dark Watch,TXT_ACS_MAP54_14_ONTHE,,,,na Temné hlídce.,på den mørke vagt,auf der Dunklen Wache,,en la Gardisto Ombra.,En la guardia oscura,,pimeällä vartiolla,dans la Garde Noire.,a Sötét Őrségnél,Nella Guardia Oscura, 闇の刻計 へ向かえ,... 어둠의 감시초소에서,op de donkere wacht,på den mørke vakten,w Ciemnej Strażnicy,na Guarda Negra,,pe Gardianul Întunecat,у тёмной стражи,на Црној стражи,på den mörka vakten,Karanlık Nöbet'te +One gear has been placed,TXT_ACS_MAP54_15_ONEGE,,,,Jedno kolo bylo umístěno.,Der er blevet placeret et redskab,Ein Zahnrad wurde eingesetzt,,Dentrado estis metita.,Un engranaje en su lugar,,Ratas on asetettu,Un engrenage a été placé,Egy fogaskerék a helyére került,Un ingranaggio è stato piazzato,歯車を一つ配置した,톱니바퀴 1개가 배치되었다,Een tandwiel is geplaatst,Ett tannhjul har blitt plassert,Jedna zębatka została umieszczona,Uma engrenagem foi colocada,,Un mecanism a fost introdus,Шестерня установлена,Један зупчаник је постављен,En kugghjul har placerats,Bir dişli yerleştirildi +\x20gears have been placed,TXT_ACS_MAP54_16_GEARS,,,,\x20kola byla umístěna.,\x20gear er blevet placeret,\x20Zahnräder wurden eingesetzt,,\x20dentradoj estis metitaj.,\x20engranajes en su lugar,,\x20ratasta on asetettu,\x20engrenages ont été placés,\x20fogaskerék a helyére került,\x20ingranaggi sono stati piazzati,歯車を配置した,톱니바퀴들이 배치되었다,\x20tandwielen zijn geplaatst,\x20 tannhjul har blitt plassert,\x20zębatki zostały umieszczone,\x20engrenagens foram colocadas,,\x20mecanisme au fost introduse,\x20шестерней установлено,\x20зупчаника су постављена,\x20 kugghjul har placerats,\x20dişliler yerleştirildi +A barricade has opened,TXT_ACS_MAP54_17_ABARR,,,,V Kloace se otevřela barikáda.,En barrikade er blevet åbnet,Eine Barrikade wurde geöffnet,,Barikado malfermiĝis,La barricada se ha abierto,Se abrió la barricada,Tiesulku on auennut,Une barricade s'est ouverte,Egy barikád megszűnt,Una barricata è stata aperta,バリケードは開かれた,방벽이 열렸다...,Er is een barricade geopend,En barrikade har åpnet seg,Barykada została otwarta,Uma barricada se abriu,,O baricadă s-a deschis,Преграда опустилась,Барикада је отворена,En barrikad har öppnats,Bir barikat açıldı +On the Cloaca,TXT_ACS_MAP54_18_ONTHE,,,,V Kloace se otevřela barikáda.,På Cloaca,In der Kloake,,En la Kloako.,En la Cloaca,,kloaakilla,dans le cloaque,a Kloákánál,Nella Cloaca,排泄腔 へ向かえ,... 하수구에서,Op de Cloaca,på Cloaca,W Kloace,Na Cloaca,,pe Cloaca,в клоаке,у клоаци,På Cloaca,Kloaka Üzerine +The way back is open,TXT_ACS_MAP54_20_THEWA,,,,Cesta zpět je otevřena.,Vejen tilbage er åben,Der Weg zurück ist offen,,La vojo reen estas malfermita.,El camino está abierto,,Tie takaisin on auki,Un chemin s'est ouvert,A visszavezető út kinyílt,La via del ritorno è aperta,裏口は開いた,돌아가는 길이 열렸다,De terugweg is open,Veien tilbake er åpen,Droga powrotna jest otwarta,O caminho de volta está aberto,,Calea e deschisă,Путь назад открыт,Пролаз назад је отворен,Vägen tillbaka är öppen,Dönüş yolu açık +The door is barred from the inside,TXT_ACS_MAP55_9_THEDO,,,,Dveře jsou zatarasené zevnitř.,Døren er spærret indefra,Die Tür ist von innen verriegelt,,La pordo estas barita interne.,La puerta está trabada desde el otro lado,,Ovi on teljetty sisältä,La porte est bloquée de ce côté,Az ajtó bentről van bereteszelve,La porta è stata aperta da dentro,この扉は内側から塞がれている,이 문은 안에 빗장이 걸려있다,De deur is van binnenuit geblokkeerd.,Døren er sperret fra innsiden,Drzwi są zabarykadowane od wewnątrz,A porta está barrada por dentro,,Ușa e încuiată din interior,Дверь заблокирована изнутри,Врата су забрављена изнутра,Dörren är spärrad från insidan,Kapı içeriden kilitli. +You dare plunder the tomb,TXT_ACS_MAP56_0_YOUDA,,,,Ty se opovažuješ rabovat,Du vover at plyndre graven,Wagst du es,,Ĉu vi aŭdacas rabi de la tombo,¿Te atreves a saquear la tumba,,Kuinka kehtaat ryöstää,Vous osez piller la tombe,A hóhér sírját,Osi saccheggiare la tomba,お前はあえて 執行人達の墓を,배짱이 두둑하구나...,Je durft de graftombe te plunderen,Våger du å plyndre graven,Śmiesz plądrować grobowiec,Como ousa saquear a tumba,,Cutezi să jefuiești mormântul,Ты посмел ограбить могилу,Усуђујеш се пљачкати,Du vågar plundra graven,Mezarı yağmalamaya cüret ediyorsun +of the executioner?,TXT_ACS_MAP56_1_OFTHE,,,,hrobku popravčího?,af bødlen?,das Grab des Henkers zu plündern?,,de la ekzekutisto?,del ejecutor?,,teloittajan haudan?,du bourreau?,próbálod fosztogatni?,dell'esecutore?,荒らすつもりか?,사형 집행자의 무덤을 도굴하다니.,van de beul?,til bøddelen?,kata?,do executor?,,călăului?,верховного палача?,желатову гробницу?,av bödeln?,Celladın mı? +Prepare to die,TXT_ACS_MAP56_2_PREPA,,,,Připrav se zemřít.,Forbered dig på at dø,Bereite dich vor zu sterben,,Pretiĝu por morti!,¡Prepárate para morir!,,Valmistaudu kuolemaan,Préparez vous à mourir!,Készülj a halálra,Preparati a morire,死ぬ準備をしろ,죽어서 회계하라.,Bereid je voor om te sterven,Forbered deg på å dø,Przygotuj się na śmierć,Prepare-se para morrer,,Pregătește-te să mori,Готовься к смерти,Припреми се да умреш,Förbered dig på att dö,Ölmeye hazırlanın +You have ,TXT_ACS_MAP59_1_YOUHA,,,,Zbývají ti ,Du har,Du musst,,Vi ankoraŭ havas,Aún tienes,,Sinulla on,Vous avez,Még kell találnod,Hai ancora altri,スイッチはまだ,당신은,Je hebt,Du har,Masz,Faltam mais,,Mai ai,Осталось,Остало је ,Du har,Bulmanız gereken\x20 +\x20more switches to find,TXT_ACS_MAP59_2_MORES,,,,\x20spínače k nalezení.,\x20flere kontakter at finde,\x20weitere Schalter finden,,\x20trovindajn ŝaltilojn.,\x20interruptores más que encontrar,,\x20lisää vipua löydettävänä,\x20boutons à trouver,\x20darab kallantyút,\x20interruttori da trovare,残っている,개의 개폐기들을 더 찾아야 한다,\x20meer schakelaars te vinden,\x20 brytere til å finne,\x20przełączników do znalezienia,\x20interruptores para encontrar,,\x20butoane de găsit,\x20переключателей,\x20прекидача да се нађе,\x20fler växlar att hitta.,\x20anahtar daha var. +You have only ,TXT_ACS_MAP59_3_YOUHA,,,,Zbývá ti jen ,Du har kun,Du musst nur,,Vi nur havas,Tienes solo,,Sinulla on vain,Vous avez seulement,Már csak,Hai solamente,スイッチは,이제 당신은 ,Je hebt alleen,Du har bare,Masz tylko,Falta somente,,Mai ai doar,Остался всего,Oстао је само ,Du har bara,Bulmanız gereken\x20 +\x20switch left,TXT_ACS_MAP59_4_SWITC,,,,\x20spínač.,\x20kontakter tilbage,\x20Schalter finden,,\x20ŝaltilon ceteran.,\x20interruptor restante,,\x20vipu jäljellä,\x20bouton a trouver,\x20darab kallantyút kell találnod,\x20interruttore rimanente,"だけ残っている +",개의 개폐기만 찾으면 된다,\x20schakelaar over,1 bryter igjen,\x20przełącznik,\x20interruptor,,\x20buton rămas,\x20переключатель,\x20прекидач,1 växel kvar,\x20anahtar daha var. +The way to the tower is open,TXT_ACS_MAP59_5_THEWA,,,,Cesta do věže je otevřena.,Vejen til tårnet er åben,Der Weg zum Turm ist offen,,La vojo al la turo estas malfermita.,El camino a la torre está abierto,,Tie tornin luo on auki,Le chemin vers la tour est ouvert.,A toronyba vezető út kinyílt,La via alla torre è stata aperta,塔への道 が開いた,탑으로 가는 길이 열렸다,De weg naar de toren is open,Veien til tårnet er åpen,Droga do wieży jest otwarta,O caminho para a torre está aberto,,Calea către turn e deschisă,Путь к башне открыт,Пут до куле је отворен,Vägen till tornet är öppen.,Kuleye giden yol açık. +The way is open,TXT_ACS_MAP60_3_THEWA,,,,Cesta je otevřena.,Vejen er åben,Der Weg ist offen,,La vojo estas malfermita.,El camino está abierto,,Tie on auki,Le chemin est ouvert.,Az út kinyílt,La via è aperta,道は開いた,길이 열렸다,De weg is open,Veien er åpen,Droga jest otwarta,O caminho está aberto,,Calea e deschisă,Портал открыт,Портал је отворен,Vägen är öppen.,Yol açık +,,Strife dialogue,,,,,,,,,,,,,,,,,,,,,,,,, +"I don't want any trouble, stay away from me. I've had enough trouble with what that bastard Harris did to me. He promised me money, instead I get to look forward to being Questioned by the Programmer.",TXT_DLG_SCRIPT01_D0_IDONT,MAP01: Beldin.,,,"Nechci žádný trable, jdi ode mě. Už tak mám dost potíží s tím, co mi ten hajzl Harris provedl. Slíbil mi peníze a místo toho se můžu těšit na výslech od Programátora.","Jeg vil ikke have ballade, hold dig væk fra mig. Jeg har haft nok problemer med det, den skiderik Harris gjorde mod mig. Han lovede mig penge, men i stedet skal jeg se frem til at blive udspurgt af programmøren.","Ich möchte keinen Ärger, bleib weg von mir. Ich hatte genug Ärger mit dem was der Bastard Harris mir angetan hat. Er hat mir Geld versprochen, stattdessen musste ich mich darauf vorbereiten von dem Programmierer ausgefragt zu werden.",,"Malproksimiĝu de mi; mi ne volas pliajn problemojn. Mi jam havis sufiĉajn pro tio, kion Harriso faris: li promesis monon al mi, kaj anstataŭ tio mi nun atendas, ke La Progamisto pridemandu min.","No te me acerques, que ya no quiero más problemas. He tenido suficientes con lo que me hizo Harris: me prometió dinero, y en lugar de eso, ahora me toca esperar a ser interrogado por El Programador.",,"En kaipaa ikävyyksiä; pysy pois luotani. Olen saanut kärsiä jo riittävästi vaivaa Harris-paskiaisen tekosista. Hän lupasi minulle rahaa, mutta sen sijaan pääsenkin Ohjelmoitsijan kuulusteltavaksi.","Je ne veux pas d'embrouilles. Laissez moi tranquille. J'ai déjà assez de problèmes avec ce que ce salaud d'Harris ma fait. Il m'a promis de l'argent, maintenant, je risque de me faire interroger par le Programmeur.","Én nem akarok semmi problémát, maradj távol tőlem. Elég baj nekem az amit az a barom Harris okozott. Pénzt ígért, ehelyett az vár rám, hogy a Programozó ki fog kérdezni.","Non voglio problemi, stai alla larga. Ho già avuto abbastanza problemi con quello che quel bastardo di mi ha fatto. Mi aveva promesso soldi, invece mi ritrovo ad avere l'opportunità di essere interrogato dal Programmatore.","もう面倒事には御免だ、私に近づくな。 あのハリスのクズのせいでもう十分面倒な目に 遭ったんだ。ヤツは私に金を渡すと約束したのに、 裏切られて私がプログラマーに尋問されることに -なってしまったんだ。","난 문제를 더 일으키고 싶지 않아, 나에게서 떨어져! 해리스 그 자식이 나를 속였어. 녀석이 돈을 준다고 해서 도와줬더니 도망치고 없었고 결국엔 붙잡혀서 프로그래머에게 심문을 받을 처지에 놓였다고!","Ik wil geen problemen, blijf uit mijn buurt. Ik heb genoeg problemen gehad met wat die klootzak Harris me heeft aangedaan. Hij beloofde me geld, maar in plaats daarvan kan ik me verheugen op een Ondervraging door de programmeur.","Nie chcę żadnych kłopotów, zostaw mnie w spokoju. Miałem już wystarczająco dużo problemów z tym co ten drań Harris mi zrobił. Obiecał mi pieniądze, ale zamiast tego muszę czekać na to, by być Przesłuchanym przez Programistę.","Não quero me meter em problemas, fique longe de mim. Já tive problemas demais com o que aquele desgraçado do Harris fez comigo. Ele me prometeu dinheiro, mas ao invés disso vou ser Questionado pelo Programador.",,"Nu vreau să am probleme, stai departe de mine. Am avut suficiente probleme din cauza a ceea ce -mi-a făcut ticălosul de Harris. Mi-a promis niște bani, dar în schimb, acum aștept cu nerăbdare să fiu interogat de către Programator.","Не подходи ко мне — мне не нужны неприятности! У меня их и так достаточно из-за этого мерзавца Харриса. Он обещал мне деньги, а вместо этого меня ожидает «допрос» у Программиста.","Не желим невољу, одмакни се од мене. Имао сам довољно невоље са оним што је онај кретен Харис урадио мени. Обећао ми је новац, у ствари требам се надати испитивању Програмера." -I'll help you if you help me. Five pieces of gold and I'll tell all I know.,TXT_DLG_SCRIPT02_D0_ILLHE,,,,"Pomůžu ti, když pomůžeš ty mě. Pět zlaťáků a řeknu ti vše, co vím.",Ich helfe dir wenn du mir hilfst. Fünf Goldstücke und ich erzähle alles was ich weiß.,,,Te ayudaré si me ayudas. Cinco piezas de oro y te cuento todo lo que sé.,,,"Tu m'aide, je t'aide. Cinq pièces et je te dis ce que je sais.","Segítek, ha segítesz. 5 arany és mindent elmondok, amit tudok.",Ti aiuterò se tu mi aiuti. Cinque pezzi d'oro e ti dirò tutto quello che so.,"助けてくれるなら援助する。 -5ゴールドで知っている情報を全て教えよう",저를 도와준다면 당신을 돕겠습니다. 5 골드를 줌으로써 말이죠.,Ik zal je helpen als je me helpt. Vijf goudstukken en ik vertel alles wat ik weet.,Pomogę ci jeśli ty mi pomożesz. Pięć sztuk złota i powiem ci wszytsko co wiem.,Eu te ajudo se você me ajudar. Cinco moedas de ouro e te digo tudo que eu sei.,,"O să te ajut dacă și tu mă ajuți. Cinci bucăți de aur -și-ți voi spune tot ce știu.","Я помогу тебе, если ты поможешь мне. Пять золотых, и я расскажу всё, что знаю.",Помоћи ћу ти ако ти помогнеш мени. Пет златника и рећи ћу ти све што знам. -Here's the gold.,TXT_RPLY0_SCRIPT02_D0_HERES,,,,Tady máš to zlato.,Hier ist dein Gold.,,,Aquí está el oro.,,,Voilà l'argent.,Íme az arany.,Ecco l'oro.,金はこれだ。,여기 골드입니다.,Hier is het goud.,Oto złoto.,Aqui está o ouro.,,Poftiți aurul.,Вот золото.,Ево га злато. -"Be stealthy when you kill, you won't set off alarms.",TXT_RYES0_SCRIPT02_D0_BESTE,,,,"Když zabíjíš, dělej to potichu - nevyhlásíš tak poplach.","Sei leise, wenn du jemanden tötest, damit du keinen Alarm auslöst.",,,Sé cauteloso cuando mates y no activarás las alarmas.,,,Tuez discrètement et vous n'aurez pas de problème avec les alarmes.,"Lopakodva, halkan gyilkolj, kézzel, így nem indul be a riasztó.","Sii furtivo quando uccidi, non farai scattare l'allarme.",始末する際は隠密に、警報を鳴らさないように。,"조용히 은신해서 암살만 한다면, 경보를 울리지 않을 겁니다.","Wees sluipend als je doodt, je zult geen alarmbellen laten afgaan.","Bądź cicho kiedy zabijasz, nie włączysz wtedy alarmu.",Seja cauteloso quando for matar e não ativará os alarmes.,,"Fii discret când ucizi, nu vei declanșa alarma astfel.","Убивай бесшумно, чтобы не поднять тревогу.","Буди нечујан када убијаш, и нећеш активирати аларм." -"Well, I won't be telling you anything for free!",TXT_RNO0_SCRIPT02_D0_WELLI,,,,Zadarmo ti nic říkat nebudu!,"Na ja, für umsonst werde ich dir nichts erzählen!",,,"Bueno, ¡No te diré nada gratis!",,,Je ne vous dirai rien si vous ne me donnez rien!,"Figyelj, ingyen semmit sem mondok el neked.",Io non ti dirò un bel niente a gratis!,いや、タダで情報は渡せない!,세상에 공짜가 어딨습니까? 먼저 돈을 주세요!,"Nou, ik zal je niets gratis vertellen!","Cóż, nie będę ci mówił niczego za darmo!","Bom, não vou te dar informação de graça!",,"Păi, n-o să-ți zic nimic pe gratis!","Что ж, я ничего не скажу даром!","Па, нећу ништа да ти кажем џабе!" -Have you by any chance got another 5 gold on you?,TXT_DLG_SCRIPT02_D1516_HAVEY,,,,Neměl bys u sebe náhodou dalších pět zlatek?,Hast du vielleicht 5 weitere Goldmünzen dabei?,,,¿Por casualidad has conseguido otros 5 de oro?,,,T'aurais pas 5 pièces en plus sur toi?,"Van bármi esély arra, hogy még 5 aranyad azért van?",Hai per caso altri 5 pezzi d'oro con te?,もしかして5ゴールド稼いだのか?,5 골드 더 있습니까? 그러면 아주 좋을 텐데.,Heb je toevallig nog 5 goud bij je?,Czy przypadkiem masz może kolejne 5 monet przy sobie?,Por acaso teria mais 5 de ouro aí?,,"Ai cumva, din întâmplare, 5 monezi de aur?",У тебя случайно не найдётся ещё 5 монеток?,Да ли имаш још 5 златника? -5 gold.,TXT_RPLY0_SCRIPT02_D1516_5GOLD,,,,Pět zlatých.,5 Gold.,,,5 de oro.,,,5 pièces.,5 arany.,5 pezzi d'oro.,5ゴールドだ。,5 골드.,5 goud.,5 monet.,5 de ouro.,,5 monezi de aur.,5 золотых.,5 златника. -"Well, poison bolts can kill the guards instantly and won't set off the alarms.",TXT_RYES0_SCRIPT02_D1516_WELLP,,,,"No, otrávené šípy okamžitě zabijí stráže a nevyhlásí poplach.",Also Giftpfeile können die Wachen sofort töten und lösen keinen Alarm aus.,,,"Bien, las saetas envenenadas pueden matar a los guardias al instante sin activar las alarmas.",,,Les carreaux empoisonnés tuent les gardes instantanément et discrètement.,"Hát, a mérgező nyilak azonnal a túlvilágra küldik az őröket, és a riasztó sem kapcsol be.",Le frecce avvelenate possono uccidere le guardie istantaneamente e non faranno scattare l'allarme.,"そうだな、ポイズンボルトは警備員を簡単に殺せるし、 -警報を作動させることもない。",아시나요? 맹독 볼트만 있으면 경보를 울리지 않고 경비병을 죽일 수 있다는거?,"Nou, gifbouten kunnen de bewakers onmiddellijk doden en zullen het alarm niet laten afgaan.","Więc, zatrute bełty mogą od razu zabić strażników i nie włączą alarmu.","Bem, setas venenosas podem matar os guardas instantâneamente e não ativarão os alarmes.",,"Păi, bolțurile otrăvite pot omorâ gardienii instant -și nu vor declanșa alarma.","Что ж, отравленными болтами можно убивать охранников быстро и бесшумно.","Па, отровне стреле ће убити стражаре одмах и неће активирати аларм" -"No sir, I won't be telling you anything for free!",TXT_RNO0_SCRIPT02_D1516_NOSIR,,,,"Ne, pane, nic vám zadarmo říkat nebudu!","Nein, ich werde dir nichts für umsonst erzählen!",,,"No, ¡No diré nada gratis!",,,"Non, monsieur, je ne vous dirai rien si je ne me fais pas payer!","Nem uram, tudja, semmi sincs ingyen.","No signore, non ti dirò nulla gratis!",いやいや、タダでは話せないな!,"죄송합니다만, 전 아무것도 무료로 말해주지 않을 겁니다!","Nee meneer, ik zal u niets gratis vertellen!","Nie panie, nie będę ci mówił niczego za darmo!","Não senhor, não vou te dizer nada de graça!",,"Nu domnule, n-o să-ți zic nimic pe gratis!","Нет, товарищ! Даром — только за амбаром!","Не господине, нећу ништа да ти кажем џабе!" -You've wrung the last bit of gossip out of me already!,TXT_DLG_SCRIPT02_D3032_YOUVE,,,,"Už jsi ze mě vyždímal všechny klepy, co jsem měl!",Du hast bereits das letzte bisschen Klatsch aus mir herausgequetscht!,,,¡Ya me has sacado hasta el último chisme!,,,Vous m'avez tiré tous les vers du nez!,Már a legutolsó pletykát is kiszedted belőlem.,Mi hai già spremuto fino all'ultimo pettegolezzo! ,既にイキのいい噂は聞かせたぞ!,가십거리를 이미 다 털어놓았습니다. 더 뭘 바랍니까?,Je hebt de laatste roddels al uit me uitgewrongen!,Wyciągnąłeś już ze mnie ostatnią plotkę!,Você já ouviu todos os boatos que posso te contar!,,Ai stors ultimele bârfe din mine deja!,"Ты уже вытянул из меня всё, что только можно!",Већ сте исцедили задњу трунку трача из мене! -What can I get for you?,TXT_DLG_SCRIPT02_D4548_WHATC,,,,Co si budeš přát?,Was kann ich für dich tun?,,,¿Qué puedo ofrecerte?,,,Qu'est ce que je peux pour vous?,Mit tehetnék érted?,Cosa posso offrirti?,何か必要か?,무엇을 구매하고 싶어?,Wat kan ik voor u halen?,Co mogę dla ciebie zrobić?,Como posso te ajudar?,,Ce pot să-ți aduc?,Что я могу тебе предложить?,Шта ти могу учинити? -Assault gun,TXT_RPLY0_SCRIPT02_D4548_ASSAU,,,,Útočnou pušku,Sturmgewehr,,,Fusil de Asalto,,,Fusil d'Assaut,Gépfegyver,Fucile d'assalto,アサルトガン,돌격소총,Aanvalswapen,Karabin Szturmowy,Fuzil de assalto,,Pușcă de asalt,Штурмовую винтовку,Аутоматска пушка -Here you go.,TXT_RYES0_SCRIPT02_D4548_HEREY,,,,Tu máš.,Bitte sehr!,,,Aquí tienes.,,,Voilà pour vous.,Tessék,Ecco per te.,毎度あり。,여기 있어.,Alsjeblieft.,Proszę bardzo.,Aqui está.,,Poftiți.,Держи.,Изволи. -You can't afford that right now.,TXT_RNO0_SCRIPT02_D4548_YOUCA,,,,Tu si teď nemůžeš dovolit.,Das kannst du dir momentan nicht leisten.,,,No puedes adquirir esto ahora.,,,Vous n'avez pas assez d'argent.,Erre most nincs pénzed.,Non hai abbastanza soldi.,今それを買える余裕は無い。,그걸 사기엔 여유가 없는 것 같네.,Dat kunt je zich nu niet veroorloven.,Nie możesz teraz tego kupić.,Você não pode comprar isso no momento.,,Nu-ți poți permite asta încă.,Ты пока не можешь себе это позволить.,Немате довољно новца за то сада. -Clip of bullets,TXT_RPLY1_SCRIPT02_D4548_CLIPO,,,,Zásobník nábojů,Gewehrmunition.,,,Cargador con balas,,,Chargeur de balles,Egy tár töltény,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Magazynek,Carregador de balas,,Cartuș de gloanțe,Обойму патронов,Шанжер -Thanks.,TXT_RYES1_SCRIPT02_D4548_THANK,,,,Díky.,Danke.,,,Gracias.,,,Merci.,Köszi.,Grazie.,どうも。,고맙다!,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Благодарю.,Хвала. -"Come on, 10 gold.",TXT_RNO1_SCRIPT02_D4548_COMEO,,,,"No tak, je to deset zlatých.","Na komm, 10 Gold.",,,¡Vamos! 10 de oro.,,,"Allez, 10 pièces.","Rajta, 10 aranyat.","Avanti, 10 pezzi d'oro.",頼むぜ、10ゴールドだぞ。,10 골드만 있으면 되는데...,"Kom op, 10 goud.","No weź, 10 monet.","Vamos lá, 10 de ouro.",,"Haide, 10 monezi de aur.","Ну же, 10 золотых.","Хајде, 10 златника." -Ammo box,TXT_RPLY2_SCRIPT02_D4548_AMMOB,,,,Krabici nábojů,Munitionsschachtel,,,Caja de balas,,,Bôite de balles,Egy doboz lőszer,Scatole di munizioni,銃弾倉箱,돌격소총 탄약 박스,Munitie doos,Pudło z amunicją,Caixa de balas,,Cutie cu muniție,Коробку патронов,Кутија муниције -Here's your ammo.,TXT_RYES2_SCRIPT02_D4548_HERES,,,,Tady je tvá munice.,Hier ist deine Munition.,,,Aquí tienes tus municiones.,,,Voilà vos munitions.,Itt a lőszered.,Ecco le tue munizioni.,これでアンタのブツだ。,탄약 여기 있어!,Hier is je munitie.,Oto twoja amunicja.,Aqui está a sua munição.,,Poftiți muniția.,Вот твои патроны.,Ево ти муниције. -Maybe some other time.,TXT_RNO2_SCRIPT02_D4548_MAYBE,,,,Možná někdy jindy.,Vielleicht ein anderes Mal.,,,Tal vez en otra ocasión.,,,Peut être une autre fois.,Talán majd máskor.,Forse qualche altra volta.,また後でな。,아마도 나중에...,Misschien een andere keer.,Może innym razem.,Talvez outra hora.,,Poate altădată.,"Может, в другой раз.",Можда неки други пут. -Good news from the Front for a change. Macil sent you for a reward and training. He's instructed me to give them to you.,TXT_DLG_SCRIPT02_D6064_GOODN,,,,"Pro jednou dobré zprávy od Fronty. Macil tě poslal pro odměnu a trénink. Řekl mi, že ti to mám předat.","Gute Nachrichten von der Front zur Abwechslung. Macil lässt dir eine Belohnung und Training zukommen. Er hat mir aufgetragen, es dir zu geben.",,,"Buenas noticias desde el Frente, para variar. Macil mandó una recompensa y entrenamiento para ti. Me solicitó dártelos.",,,Des bonnes nouvelles du Front pour une fois. Macil t'a envoyé pour une récompense et de l'entraînement. Il m'a instruit de te les procurer.,"Jó hírek a Fronttól a változások miatt! Macil jutalom és kiképzés gyanánt küldött. Arra kért, hogy ezeket én adjam át neked.",Buone notizie dal Fronte per una volta. Macil ti ha inviato una ricompensa e allenamento. Mi ha istruito che te li dovevo procurare.,"フロントから朗報だ。 +なってしまったんだ。","난 문제를 더 일으키고 싶지 않아, 나에게서 떨어져! 해리스 그 자식이 나를 속였어. 녀석이 돈을 준다고 해서 도와줬더니 도망치고 없었고 결국엔 붙잡혀서 프로그래머에게 심문을 받을 처지에 놓였다고!","Ik wil geen problemen, blijf uit mijn buurt. Ik heb genoeg problemen gehad met wat die klootzak Harris me heeft aangedaan. Hij beloofde me geld, maar in plaats daarvan kan ik me verheugen op een Ondervraging door de programmeur.","Jeg vil ikke ha trøbbel. Hold deg unna meg. Jeg har hatt nok trøbbel med det den jævelen Harris gjorde mot meg. Han lovet meg penger, i stedet kan jeg se frem til å bli avhørt av programmereren.","Nie chcę żadnych kłopotów, zostaw mnie w spokoju. Miałem już wystarczająco dużo problemów z tym co ten drań Harris mi zrobił. Obiecał mi pieniądze, ale zamiast tego muszę czekać na to, by być Przesłuchanym przez Programistę.","Não quero me meter em problemas, fique longe de mim. Já tive problemas demais com o que aquele desgraçado do Harris fez comigo. Ele me prometeu dinheiro, mas ao invés disso vou ser Questionado pelo Programador.",,"Nu vreau să am probleme, stai departe de mine. Am avut suficiente probleme din cauza a ceea ce +mi-a făcut ticălosul de Harris. Mi-a promis niște bani, dar în schimb, acum aștept cu nerăbdare să fiu interogat de către Programator.","Не подходи ко мне — мне не нужны неприятности! У меня их и так достаточно из-за этого мерзавца Харриса. Он обещал мне деньги, а вместо этого меня ожидает «допрос» у Программиста.",,"Jag vill inte ha några problem, håll dig borta från mig. Jag har haft tillräckligt med problem med vad den jäveln Harris gjorde mot mig. Han lovade mig pengar, istället får jag se fram emot att bli förhörd av Programmeraren.","Bela istemiyorum, benden uzak dur. O piç Harris'in bana yaptıkları yüzünden yeterince sorun yaşadım. Bana para sözü verdi, onun yerine Programcı tarafından sorgulanmayı dört gözle bekliyorum." +I'll help you if you help me. Five pieces of gold and I'll tell all I know.,TXT_DLG_SCRIPT02_D0_ILLHE,MAP02: Guy next to Norwall Prison.,,,"Pomůžu ti, když pomůžeš ty mě. Pět zlaťáků a řeknu ti vše, co vím.","Jeg vil hjælpe dig, hvis du hjælper mig. Fem guldmønter, og jeg fortæller alt, hvad jeg ved.",Ich helfe dir wenn du mir hilfst. Fünf Goldstücke und ich erzähle alles was ich weiß.,,"Mi helpos vin se vi helpos min. Donu kvin da oro kaj mi rakontos ĉion, kion mi scias.",Te ayudo si me ayudas. Cinco monedas de oro y te cuento todo lo que sé.,,"Autan sinua, jos autat minua. Viidestä kultakolikosta kerron kaiken, minkä tiedän.","Tu m'aide, je t'aide. Cinq pièces et je te dis ce que je sais.","Segítek, ha segítesz. 5 arany és mindent elmondok, amit tudok.",Ti aiuterò se tu aiuti me. Cinque pezzi d'oro e ti dirò tutto quello che so.,"助けてくれるなら援助する。 +5ゴールドで知っている情報を全て教えよう",저를 도와준다면 당신을 돕겠습니다. 5 골드를 줌으로써 말이죠.,Ik zal je helpen als je me helpt. Vijf goudstukken en ik vertel alles wat ik weet.,"Jeg hjelper deg hvis du hjelper meg. Fem gullstykker, så forteller jeg alt jeg vet.",Pomogę ci jeśli ty mi pomożesz. Pięć sztuk złota i powiem ci wszytsko co wiem.,Eu te ajudo se você me ajudar. Cinco moedas de ouro e te digo tudo que eu sei.,,"O să te ajut dacă și tu mă ajuți. Cinci bucăți de aur +și-ți voi spune tot ce știu.","Я помогу тебе, если ты поможешь мне. Пять золотых, и я расскажу всё, что знаю.",,Jag hjälper dig om du hjälper mig. Fem guldmynt och jag berättar allt jag vet.,Bana yardım edersen ben de sana yardım ederim. Beş altın ve tüm bildiklerimi anlatacağım. +Here's the gold.,TXT_RPLY0_SCRIPT02_D0_HERES,〃,,,Tady jsou.,Her er guldet.,Hier ist dein Gold.,,Jen la oro.,Aquí está el oro.,,Tässä on kulta.,Voilà l'argent.,Itt az arany.,Ecco l'oro.,金はこれだ。,여기 골드입니다.,Hier is het goud.,Her er gullet.,Oto złoto.,Aqui está o ouro.,,Poftiți aurul.,Вот золото.,,Här är guldet.,İşte altın. +"Be stealthy when you kill, you won't set off alarms.",TXT_RYES0_SCRIPT02_D0_BESTE,〃,,,"Když zabíjíš, dělej to potichu - nespustíš tak poplach.","Vær snigende når du dræber, så du ikke udløser alarmer.","Sei leise, wenn du jemanden tötest, damit du keinen Alarm auslöst.",,"Mortigu silente por +ne ekagigi alarmojn.","Sé sigiloso al matar para +no activar las alarmas.",,"Jos tapat vihollisesi salaa, vältyt hälytyksiltä.",Tuez discrètement et vous n'aurez pas de problème avec les alarmes.,"Lopakodva, halkan gyilkolj, kézzel, így nem indul be a riasztó.","Sii furtivo quando uccidi, non farai scattare l'allarme.",始末する際は隠密に、警報を鳴らさないように。,"조용히 은신해서 암살만 한다면, 경보를 울리지 않을 겁니다.","Wees sluipend als je doodt, je zult geen alarmbellen laten afgaan.","Vær snikende når du dreper, så du ikke utløser alarmer.","Bądź cicho kiedy zabijasz, nie włączysz wtedy alarmu.",Seja cauteloso quando for matar e não ativará os alarmes.,,"Fii discret când ucizi, nu vei declanșa alarma astfel.","Убивай бесшумно, чтобы не поднять тревогу.",,"Var smygande när du dödar, du kommer inte att utlösa larm.","Öldürürken gizli ol, alarmları çalıştırmazsın." +"Well, I won't be telling you anything for free!",TXT_RNO0_SCRIPT02_D0_WELLI,〃,,,Zadarmo ti nic říkat nebudu!,Jeg vil ikke fortælle dig noget gratis!,"Na ja, für umsonst werde ich dir nichts erzählen!",,"Nu, mi ne parolos senpage!","Bueno, ¡no te diré +nada gratis!","Bueno, ¡no voy a decir +nada gratis!","No, en aio kertoa mitään ilmaiseksi!",Je ne vous dirai rien si vous ne me donnez rien!,"Figyelj, ingyen semmit sem mondok el neked.","Beh, io non ti dirò un bel niente senza compenso!",いや、タダで情報は渡せない!,세상에 공짜가 어딨습니까? 먼저 돈을 주세요!,"Nou, ik zal je niets gratis vertellen!","Vel, jeg vil ikke fortelle deg noe gratis!","Cóż, nie będę ci mówił niczego za darmo!","Bom, não vou te dar informação de graça!",,"Păi, n-o să-ți zic nimic pe gratis!","Что ж, я ничего не скажу даром!",,Jag kommer inte att berätta något gratis!,Sana bedavaya hiçbir şey anlatmayacağım! +Have you by any chance got another 5 gold on you?,TXT_DLG_SCRIPT02_D1516_HAVEY,〃,,,Neměl bys u sebe náhodou dalších pět zlatek?,Har du tilfældigvis fem guldstykker mere på dig?,Hast du vielleicht 5 weitere Goldmünzen dabei?,,Ĉu eble vi havas aliajn kvin da oro?,"¿No tendrás otros cinco de oro, por casualidad?",,Sattuisiko sinulla olemaan toiset viisi kolikkoa?,T'aurais pas 5 pièces en plus sur toi?,Nincs véletlenül nálad még 5 arany?,Hai per caso altri 5 pezzi d'oro con te?,もしかして5ゴールド稼いだのか?,5 골드 더 있습니까? 그러면 아주 좋을 텐데.,Heb je toevallig nog 5 goud bij je?,Har du tilfeldigvis fem gull til på deg?,Czy przypadkiem masz może kolejne 5 monet przy sobie?,Por acaso teria mais 5 de ouro aí?,,"Ai cumva, din întâmplare, 5 monezi de aur?",У тебя случайно не найдётся ещё 5 монеток?,,Har du av en slump 5 guldpengar till på dig?,Yanında 5 altın daha var mı acaba? +5 gold.,TXT_RPLY0_SCRIPT02_D1516_5GOLD,〃,,,Pět zlatých.,5 guld.,5 Gold.,,Kvin da oro.,Cinco de oro.,,5 kolikkoa.,5 pièces.,5 arany.,5 pezzi d'oro.,5ゴールドだ。,5 골드.,5 goud.,5 gull.,5 monet.,5 de ouro.,,5 monezi de aur.,5 золотых.,,Fem guld.,5 altın. +"Well, poison bolts can kill the guards instantly and won't set off the alarms.",TXT_RYES0_SCRIPT02_D1516_WELLP,〃,,,"No, otrávené šípy okamžitě zabijí stráže a nikdo nevyhlásí poplach.","Nå, giftpile kan dræbe vagterne med det samme og vil ikke udløse alarmen.",Also Giftpfeile können die Wachen sofort töten und lösen keinen Alarm aus.,,"Mortigi per venenaj sagoj +estas tuje kaj silente.","Matar con flechas envenenadas +es instantáneo y sin alarmas.",,No niin; myrkkynuolilla voi tappaa vartijat välittömästi hälytystä laukaisematta.,Les carreaux empoisonnés tuent les gardes instantanément et discrètement.,"Hát, a mérgező nyilak azonnal a túlvilágra küldik az őröket, és a riasztó sem kapcsol be.",Le frecce avvelenate possono uccidere le guardie istantaneamente e non faranno scattare l'allarme.,"そうだな、ポイズンボルトは警備員を簡単に殺せるし、 +警報を作動させることもない。",아시나요? 맹독 볼트만 있으면 경보를 울리지 않고 경비병을 죽일 수 있다는거?,"Nou, gifbouten kunnen de bewakers onmiddellijk doden en zullen het alarm niet laten afgaan.","Vel, giftbolter kan drepe vaktene øyeblikkelig og vil ikke utløse alarmen.","Więc, zatrute bełty mogą od razu zabić strażników i nie włączą alarmu.","Bem, setas venenosas podem matar guardas na hora e não disparam alarmes.",,"Păi, bolțurile otrăvite pot omorâ gardienii instant +și nu vor declanșa alarma.","Что ж, отравленными болтами можно убивать охранников быстро и бесшумно.",,"Tja, giftbultar kan döda vakterna omedelbart och kommer inte att utlösa larmen.",Zehirli oklar muhafızları anında öldürebilir ve alarmı çalıştırmaz. +"No sir, I won't be telling you anything for free!",TXT_RNO0_SCRIPT02_D1516_NOSIR,〃,,,"Ne, ne, zadarmo ti nic říkat nebudu!","Nej, sir, jeg vil ikke fortælle dig noget gratis!","Nein, ich werde dir nichts für umsonst erzählen!",,"Ne, mi diros nenion senpage!","¡No, no diré nada gratis!","¡No, no voy a decir nada gratis!","Ehei, en kerro mitään ilmaiseksi!","Non, monsieur, je ne vous dirai rien si je ne me fais pas payer!","Nem uram, nem árulok el semmit ingyen!","No signore, non ti dirò nulla senza avere qualcosa in cambio!",いやいや、タダでは話せないな!,"죄송합니다만, 전 아무것도 무료로 말해주지 않을 겁니다!","Nee meneer, ik zal u niets gratis vertellen!","Nei, sir, jeg vil ikke fortelle deg noe gratis!","Nie panie, nie będę ci mówił niczego za darmo!","Nada disso, senhor, não vou te dizer nada de graça!",,"Nu domnule, n-o să-ți zic nimic pe gratis!","Нет, товарищ! Даром — только за амбаром!",,"Nej, sir, jag tänker inte berätta något gratis för dig!","Hayır efendim, size bedava bir şey söylemeyeceğim!" +You've wrung the last bit of gossip out of me already!,TXT_DLG_SCRIPT02_D3032_YOUVE,〃,,,"Už jsi ze mě vyždímal všechny klepy, co jsem měl!",Du har allerede vredet den sidste smule sladder ud af mig!,Du hast bereits das letzte bisschen Klatsch aus mir herausgequetscht!,,Vi jam eltiris de mi eĉ la lastan klaĉon.,Ya me has sacado hasta el último cotilleo.,Ya me sacaste hasta el último chisme.,Olet jo puristanut minusta kaikki juorut!,Vous m'avez tiré tous les vers du nez!,Már a legutolsó pletykát is kiszedted belőlem.,Mi hai già spremuto fino all'ultimo pettegolezzo! ,既にイキのいい噂は聞かせたぞ!,가십거리를 이미 다 털어놓았습니다. 더 뭘 바랍니까?,Je hebt de laatste roddels al uit me uitgewrongen!,Du har allerede vrengt det siste sladderet ut av meg!,Wyciągnąłeś już ze mnie ostatnią plotkę!,Você já ouviu todos os boatos que posso te contar!,,Ai stors ultimele bârfe din mine deja!,"Ты уже вытянул из меня всё, что только можно!",,Du har redan pressat ut det sista skvallret ur mig!,Benden son dedikodumu da aldınız zaten! +What can I get for you?,TXT_DLG_SCRIPT02_D4548_WHATC,MAP02: Irale.,,,Co si budeš přát?,Hvad kan jeg få for dig?,Was kann ich für dich tun?,,Kion mi donu al vi?,¿Qué puedo ofrecerte?,,Mitä saisi olla?,Qu'est ce que je peux pour vous?,Mit tehetnék érted?,Cosa posso offrirti?,何か必要か?,무엇을 구매하고 싶어?,Wat kan ik voor u halen?,Hva vil du ha?,Co mogę dla ciebie zrobić?,Como posso te ajudar?,,Ce pot să-ți aduc?,Что я могу тебе предложить?,,Vad kan jag få för dig?,Sizin için ne alabilirim? +Assault gun,TXT_RPLY0_SCRIPT02_D4548_ASSAU,〃,,,Útočnou pušku,En pistol til angreb,Sturmgewehr,,Sturmofusilon,Fusil de asalto,,Rynnäkkökivääri,Fusil d'Assaut,Gépfegyver,Fucile d'assalto,アサルトガン,돌격소총,Aanvalswapen,En automatpistol.,Karabin Szturmowy,Fuzil de assalto,,Pușcă de asalt,Штурмовую винтовку,,En attackpistol,Saldırı silahı. +Here you go.,TXT_RYES0_SCRIPT02_D4548_HEREY,〃,,,Tu máš.,Værsgo.,Bitte sehr!,,Jen.,Toma.,,"Tässä, ole hyvä.",Voilà pour vous.,Tessék,Ecco a te.,毎度あり。,여기 있어.,Alsjeblieft.,Vær så god.,Proszę bardzo.,Aqui está.,,Poftiți.,Держи.,,Här får du.,Al bakalım. +You can't afford that right now.,TXT_RNO0_SCRIPT02_D4548_YOUCA,〃,,,Tu si teď nemůžeš dovolit.,Det har du ikke råd til lige nu.,Das kannst du dir momentan nicht leisten.,,"Vi nun ne havas +sufiĉe da oro.",No te alcanza por ahora.,,Sinulla ei ole siihen juuri nyt varaa.,Vous n'avez pas assez d'argent.,Erre most nincs pénzed.,Non hai abbastanza soldi.,今それを買える余裕は無い。,그걸 사기엔 여유가 없는 것 같네.,Dat kunt je zich nu niet veroorloven.,Det har du ikke råd til akkurat nå.,Nie możesz teraz tego kupić.,Você não pode comprar isso no momento.,,Nu-ți poți permite asta încă.,Ты пока не можешь себе это позволить.,,Du har inte råd med den just nu.,Şu anda bunu karşılayamazsın. +Clip of bullets,TXT_RPLY1_SCRIPT02_D4548_CLIPO,〃,,,Zásobník nábojů,Et magasin med kugler,Gewehrmunition.,,Magazenon,Un cargador,,Luotilipas,Chargeur de balles,Egy tár töltény,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Et magasin med kuler.,Magazynek,Carregador de balas,,Cartuș de gloanțe,Обойму патронов,,Kulor.,Mermi şarjörü +Thanks.,TXT_RYES1_SCRIPT02_D4548_THANK,〃,,,Díky.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Köszi.,Grazie.,どうも。,고맙다!,Bedankt.,Takk skal du ha.,Dzięki.,Agradeço.,,Mulțumesc.,Благодарю.,,Tack.,Teşekkürler. +"Come on, 10 gold.",TXT_RNO1_SCRIPT02_D4548_COMEO,〃,,,"No tak, jen deset zlatých.","Kom nu, 10 guld.","Na komm, 10 Gold.",,"Nu, ĝi kostas dek da oro.","Vamos, que son diez de oro.",,"Antaa tulla, 10 kolikkoa.","Allez, 10 pièces.","Gyerünk, 10 arany.","Avanti, 10 pezzi d'oro.",頼むぜ、10ゴールドだぞ。,10 골드만 있으면 되는데...,"Kom op, 10 goud.","Kom igjen, 10 gull.","No weź, 10 monet.","Vamos lá, 10 de ouro.",,"Haide, 10 monezi de aur.","Ну же, 10 золотых.",,"Kom igen, 10 guld.","Hadi, 10 altın." +Ammo box,TXT_RPLY2_SCRIPT02_D4548_AMMOB,〃,,,Krabici nábojů,Ammo kasse,Munitionsschachtel,,Munici-keston,Caja de municiones,,Ammuslaatikko,Bôite de balles,Egy doboz lőszer,Scatola di munizioni,銃弾倉箱,돌격소총 탄약 박스,Munitie doos,Ammunisjonsboks,Pudło z amunicją,Caixa de balas,,Cutie cu muniție,Коробку патронов,,Ammunitionslåda,Cephane kutusu +Here's your ammo.,TXT_RYES2_SCRIPT02_D4548_HERES,〃,,,Tady je tvá munice.,Her er din ammunition.,Hier ist deine Munition.,,Jen via municio.,Aquí está tu munición.,,Tässä ammuksesi.,Voilà vos munitions.,Itt a lőszered.,Ecco le tue munizioni.,これでアンタのブツだ。,탄약 여기 있어!,Hier is je munitie.,Her er ammunisjonen din.,Oto twoja amunicja.,Aqui está a sua munição.,,Poftiți muniția.,Вот твои патроны.,,Här är din ammunition.,İşte cephanen. +Maybe some other time.,TXT_RNO2_SCRIPT02_D4548_MAYBE,〃,,,Možná někdy jindy.,Måske en anden gang.,Vielleicht ein anderes Mal.,,Eble alimomente.,"Puede que en +otro momento.",,Ehkä joku toinen kerta.,Peut être une autre fois.,Talán majd máskor.,Magari un'altra volta.,また後でな。,아마도 나중에...,Misschien een andere keer.,Kanskje en annen gang.,Może innym razem.,Talvez outra hora.,,Poate altădată.,"Может, в другой раз.",,Kanske en annan gång.,Belki başka bir zaman. +Good news from the Front for a change. Macil sent you for a reward and training. He's instructed me to give them to you.,TXT_DLG_SCRIPT02_D6064_GOODN,〃 (After destroying the crystal in the Power Station),,,"Pro jednou dobré zprávy od Fronty. Macil tě poslal pro odměnu a trénink. Řekl mi, že ti to mám předat.",Gode nyheder fra fronten til en forandring. Macil har sendt dig for at få en belønning og træning. Han har instrueret mig om at give dig dem.,"Gute Nachrichten von der Front zur Abwechslung. Macil lässt dir eine Belohnung und Training zukommen. Er hat mir aufgetragen, es dir zu geben.",,"Estas bonaj novaĵoj el la Fronto, laŭ la kutimo. Macil sendis oron kaj trejniĝon por vi. Li instrukciis, ke mi donu ilin al vi.","Buenas noticias desde el Frente, para variar. Macil te manda oro y entrenamiento. Me ha solicitado dártelos.","Buenas noticias desde el Frente, para variar. Macil te manda oro y entrenamiento. Me solicitó dártelos.",Hyviä uutisia Rintamalta vaihteeksi. Macil kutsui sinut saamaan minun kauttani palkkion ja koulutusta.,Des bonnes nouvelles du Front pour une fois. Macil t'a envoyé pour une récompense et de l'entraînement. Il m'a instruit de te les procurer.,"Jó hírekkel szolgálhatok a +frontról a változatosság kedvéért. +Macil érted küldött egy kis jutalommal +a kiképzésért cserébe. Azt +parancsolta, hogy adjam oda őket.",Buone notizie dal Fronte per una volta. Macil ti ha inviato una ricompensa e predisposto per l'addestramento. Mi ha raccomandato di procurarteli.,"フロントから朗報だ。 マシルは貴方に報酬と訓練の許可を送った。 -私はそれらを貴方に渡す為に持って来た。","프론트로부터 좋은 소식을 들었어. 마실 사령관님이 보상과 훈련받을 특권을 당신에게 전해주라는군. 이미 준비된 것 같으니, 시작할까?",Goed nieuws van het Front voor de verandering. Macil heeft je gestuurd voor een beloning en training. Hij heeft me geïnstrueerd om ze aan jou te geven.,"Dobre wieści od Frontu dla odmiany. Macil wysłał cię po nagrodę i na trening. Poinstruował mnie, aby ci je dostarczyć.",Boas notícias da Frente pra variar. O Macil enviou uma recompensa e treinamento para você. Ele me deu ordens para passá-los a você.,,"În sfârșit, niște vești bune venite de pe Front. Ai venit de la Macil pentru o recompensă și niste instruire este? Mi-a ordonat ca eu să ți le ofer.","Наконец-то, хорошие новости от Сопротивления. Ты пришёл от Мэйсила за наградой и обучением? Он распорядился, чтобы ты получил их от меня.",Добре вести са фронта за промену. Мацил те је послао да добијеш награду и тренинг. Наредио ми је да ти их дам. -Thanks.,TXT_RPLY0_SCRIPT02_D6064_THANK,,,,Díky.,Danke.,,,Gracias.,,,Merci.,Köszi.,Grazie.,ありがとう。,고맙습니다.,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Спасибо.,Хвала. -Glad to be of service.,TXT_RYES0_SCRIPT02_D6064_GLADT,,,,Rád jsem pomohl.,Es war mir eine Freude dir zu Diensten zu sein,,,Un placer atenderte.,,,Ravi de vous avoir servi.,Szíves örömest segítek.,Felice di essere al servizio.,感謝する。,도와줄 수 있어서 영광이야.,Blij om van dienst te zijn.,"Cieszę się, że mogłem pomóc.",É um prazer serví-los.,,Mă bucur să fiu util.,Рад помочь.,Драго ми је да сам од помоћи. -"All right, here's a few pointers on what to do: don't get in the way of Crusaders: firing short bursts from your assault gun keeps it on target.",TXT_DLG_SCRIPT02_D7580_ALLRI,,,,"Jistě, tady je pár rad, co dělat: Nepleť se do cesty Křižákům. Střílení krátkých dávek z pušky ti zaručí přesnost.","Also, hier hast du ein paar Hinweise: Gerate nicht ins Visier der Ordensritter: Wenn du kurze Feuerstöße mit deinem Sturmgewehr abgibst, triffst du besser.",,,"De acuerdo, aquí algunos consejos: No te cruces en el camino de los Cruzados: disparar rachas cortas del Fusil de Asalto lo mantendrá en el objetivo.",,,"Bon, voilà quelques conseils sur ce que tu devrais faire: Ne vas pas te mêler aux croisés. Tirer en courte rafales avec le fusil d'assaut te permet de rester sur ta cible.","Na jól van, itt egy kis útbaigazítás neked: Ne kerülj a keresztesek útjába: Gépfegyveredből rövid sorozatokat leadva pontosabban tudsz célozni.","Bene, ecco alcuni consigli sul da farsi: non mischiarti ai Crociati: scattare a raffiche con il tuo fucile d'assalto ti tiene sul bersaglio.","オーライ、 +私はそれらを貴方に渡す為に持って来た。","프론트로부터 좋은 소식을 들었어. 마실 사령관님이 보상과 훈련받을 특권을 당신에게 전해주라는군. 이미 준비된 것 같으니, 시작할까?",Goed nieuws van het Front voor de verandering. Macil heeft je gestuurd voor een beloning en training. Hij heeft me geïnstrueerd om ze aan jou te geven.,Gode nyheter fra fronten til en forandring. Macil sendte deg for belønning og trening. Han ba meg gi dem til deg.,"Dobre wieści od Frontu dla odmiany. Macil wysłał cię po nagrodę i na trening. Poinstruował mnie, aby ci je dostarczyć.",Boas notícias da Frente pra variar. O Macil enviou uma recompensa e treinamento para você. Ele me deu ordens para passá-los a você.,,"În sfârșit, niște vești bune venite de pe Front. Ai venit de la Macil pentru o recompensă și niste instruire este? Mi-a ordonat ca eu să ți le ofer.","Наконец-то, хорошие новости от Сопротивления. Ты пришёл от Мэйсила за наградой и обучением. Он распорядился, чтобы я дал тебе их.",,Goda nyheter från fronten för en gångs skull. Macil skickade dig för en belöning och utbildning. Han har instruerat mig att ge dig dem.,Değişiklik olsun diye cepheden iyi haberler var. Macil seni ödül ve eğitim için gönderdi. Onları sana vermemi emretti. +Thanks.,TXT_RPLY0_SCRIPT02_D6064_THANK,〃 (〃),,,Díky.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Köszi.,Grazie.,ありがとう。,고맙습니다.,Bedankt.,Takk skal du ha.,Dzięki.,Agradeço.,,Mulțumesc.,Спасибо.,,Tack.,Teşekkürler. +Glad to be of service.,TXT_RYES0_SCRIPT02_D6064_GLADT,〃 (〃),,,Rád jsem pomohl.,Glad for at være til tjeneste.,Es war mir eine Freude dir zu Diensten zu sein,,Estas plezuro esti serva.,Un placer atenderte.,,Onneksi voin olla avuksi.,Ravi de vous avoir servi.,Szíves örömest segítek.,Felice di essere utile.,感謝する。,도와줄 수 있어서 영광이야.,Blij om van dienst te zijn.,Glad for å stå til tjeneste.,"Cieszę się, że mogłem pomóc.",É um prazer serví-los.,,Mă bucur să fiu util.,Рад помочь.,,Glad att vara till tjänst.,Hizmet edebildiğime sevindim. +"All right, here's a few pointers on what to do: don't get in the way of Crusaders: firing short bursts from your assault gun keeps it on target.",TXT_DLG_SCRIPT02_D7580_ALLRI,〃 (〃),,,"Jistě, tady je pár rad, co dělat: Nepleť se do cesty Křižákům. Střílení krátkých dávek z pušky ti zaručí přesnost.",,"Also, hier hast du ein paar Hinweise: Gerate nicht ins Visier der Ordensritter: Wenn du kurze Feuerstöße mit deinem Sturmgewehr abgibst, triffst du besser.",,"Bone, jen kelkaj konsiloj. Ne staru antaŭ Krucistoj; pafi mallongajn ŝprucojn per la sturmofusilo estas sufiĉe por teni vian celon.","Muy bien, aquí algunos consejos. No te pongas frente a los Cruzados: disparar ráfagas cortas con el fusil de asalto basta para mantenerte en el blanco.",,"No niin, ihan vain ohjeeksi: Pysy pois ristiretkeläisten tieltä; hallituilla rynnäkkökiväärin sarjoilla pidät kiväärin tähtäimissäsi.","Bon, voilà quelques conseils sur ce que tu devrais faire: Ne vas pas te mêler aux croisés. Tirer en courte rafales avec le fusil d'assaut te permet de rester sur ta cible.","Na jól van, itt egy kis útbaigazítás neked: Ne kerülj a keresztesek útjába: Gépfegyveredből rövid sorozatokat leadva pontosabban tudsz célozni.","Bene, ecco alcuni consigli sul da farsi: non metterti davanti ai Crociati: sparare singole raffiche con il tuo fucile d'assalto fa si che l'arma rimane sul bersaglio.","オーライ、 それで何をすべきかについて説明がある :クルセイダーの斜線に立つな -:アサルトガンを遠くから的に向かって撃て",좋아. 먼저 배워둬야 할 것은: 크루세이더를 제압하기 위해선 가능한 한 멀리서 상대해야 해. 그리고 돌격소총의 방아쇠를 한 번 누르면 정확한 3 점발사격이 가능하지. ,"Oké, hier zijn een paar tips over wat je moet doen: sta kruisvaarders niet in de weg: korte uitbarstingen van je aanvalsgeweer houden het doelwit.","W porządku, oto kilka wskazówek co trzeba robić: nie wchodzić w drogę Krzyżowcom: strzelanie krótkimi seriami z karabinu szturmowego utrzymuje cel.","Muito bem, tenho alguns conselhos pra te dar: não se meta na frente dos Cruzados: atire rajadas curtas com o seu fuzil de assalto para ter mais precisão.",,"În regulă, uite niște puncte de reper: Nu te băga în calea Cruciaților: Focurile scurte ale armei tale de asalt sunt cele mai eficiente.","Отлично, вот несколько советов: не попадайся под ноги крестоносцам. Из штурмовой винтовки лучше всего стрелять короткими очередями.","Добро, ево пар смерница за тебе: -немој стајати на пут Крсташима:испаљивање кратких рафала из јуришног оружја држи га на мети -" -Is that it?,TXT_RPLY0_SCRIPT02_D7580_ISTHA,,,,To je všechno?,War es das?,,,¿Eso es todo?,,,C'est tout?,Ennyi?,Questo è?,そうなのか?,그게 답니까?,Is dat het?,To wszystko?,Só isso?,,Asta e?,И всё?,Да ли је то све? -"Look, you'll learn more later.",TXT_RYES0_SCRIPT02_D7580_LOOKY,,,,"Hele, víc se toho naučíš pak.",Fürs Erste ja. Du wirst später noch mehr lernen.,,,"Mira, aprenderás más tarde.",,,Tu en apprendras davantage plus tard.,"Nézd, később majd többet fogsz tanulni.","Guarda, imparerai di più dopo.",良し、後でもっと学べるぞ。,나중에 알려줄게.,"Kijk, je komt er later meer over te weten.","Zobacz, później nauczysz się więcej.","Olha, você vai aprender mais depois.",,"Uite, o să afli mai multe mai târziu.","Позже узнаешь больше, хорошо?","Гледај, учићеш више касније." -"I think I can convert a flamethrower from one of the Crusaders for use by a human. Oh, anything else I can get you?",TXT_DLG_SCRIPT02_D9096_ITHIN,,,,"Myslím, že bych mohl předělat plamenomet z jednoho z těch Křižáků pro lidské použití. Oh, mohu ti sehnat ještě něco?","Ich denke ich kann einen Flammenwerfer von einen der Ordensritter umbauen, damit ein Mensch ihn benutzen kann. Oh, kann ich dir sonst noch etwas besorgen?",,,"Creo que puedo convertir un lanzallamas de uno de los cruzados para que un humano pueda utilizarlo. Oh, ¿Algo más que pueda ofrecerte?",,,Je crois que je peux convertir un lance-flammes de croisé pour être utilisé par un humain. Je peux faire quelque chose d'autre pour vous?,"Azt hiszem, ha az egyik keresztesről leszednénk egy lángszórót, azt át tudnám alakítani emberi használatra. Ó, még valamit tehetek érted?","Penso posso convertire un lanciafiamme da uno dei Crociati per essere usato da un umano. Oh, desideri qualcos'altro?","俺ならクルセイダー専用の火炎放射器を +:アサルトガンを遠くから的に向かって撃て",좋아. 먼저 배워둬야 할 것은: 크루세이더를 제압하기 위해선 가능한 한 멀리서 상대해야 해. 그리고 돌격소총의 방아쇠를 한 번 누르면 정확한 3 점발사격이 가능하지. ,"Oké, hier zijn een paar tips over wat je moet doen: sta kruisvaarders niet in de weg: korte uitbarstingen van je aanvalsgeweer houden het doelwit.","Greit, her er noen tips om hva du skal gjøre: Ikke kom i veien for korsfarerne. Korte salver fra angrepsgeværet holder det på målet.","W porządku, oto kilka wskazówek co trzeba robić: nie wchodzić w drogę Krzyżowcom: strzelanie krótkimi seriami z karabinu szturmowego utrzymuje cel.","Muito bem, tenho alguns conselhos pra te dar: não se meta na frente dos Cruzados: atire rajadas curtas com o seu fuzil de assalto para ter mais precisão.",,"În regulă, uite niște puncte de reper: Nu te băga în calea Cruciaților: Focurile scurte ale armei tale de asalt sunt cele mai eficiente.","Отлично, вот несколько советов: не попадайся под ноги крестоносцам; из штурмовой винтовки лучше всего стрелять короткими очередями.",,"Okej, här är några tips om vad du ska göra: Ställ dig inte i vägen för korsfarare: Genom att avfyra korta salvor från ditt stormgevär håller du det i mål.","Pekala, işte size ne yapmanız gerektiğine dair birkaç ipucu: Haçlıların yoluna çıkmayın: saldırı silahınızla kısa aralıklarla ateş etmek onu hedefte tutar." +Is that it?,TXT_RPLY0_SCRIPT02_D7580_ISTHA,〃 (〃),,,To je všechno?,Er det det?,War es das?,,Ĉu nenio alia?,¿Eso es todo?,,Siinä kaikki?,C'est tout?,Ennyi?,Tutto qui?,そうなのか?,그게 답니까?,Is dat het?,Var det alt?,To wszystko?,Só isso?,,Asta e?,И всё?,,Är det så?,Bu kadar mı? +"Look, you'll learn more later.",TXT_RYES0_SCRIPT02_D7580_LOOKY,〃 (〃),,,"Hele, víc se toho naučíš pak.","Hør, du vil få mere at vide senere.",Fürs Erste ja. Du wirst später noch mehr lernen.,,"Nu, vi lernos pli poste.","Ya aprenderás +más después.","Ya vas a aprender +más después.",Saat oppia kyllä lisää myöhemmin.,Tu en apprendras davantage plus tard.,"Nézd, később majd többet fogsz megtudni.","Guarda, imparerai di più dopo.",良し、後でもっと学べるぞ。,나중에 알려줄게.,"Kijk, je komt er later meer over te weten.",Du får vite mer senere.,"Zobacz, później nauczysz się więcej.","Olha, você vai aprender mais depois.",,"Uite, o să afli mai multe mai târziu.","Позже узнаешь больше, хорошо?",,Du kommer att få veta mer senare.,"Bak, daha sonra daha fazlasını öğreneceksin." +"I think I can convert a flamethrower from one of the Crusaders for use by a human. Oh, anything else I can get you?",TXT_DLG_SCRIPT02_D9096_ITHIN,〃 (〃),,,"Myslím, že bych mohl předělat plamenomet z jednoho z těch Křižáků pro použití člověkem. No, budeš si ještě něco přát?","Jeg tror, jeg kan omdanne en flammekaster fra en af korsfarerne til brug for et menneske. Er der andet, jeg kan skaffe dig?","Ich denke ich kann einen Flammenwerfer von einen der Ordensritter umbauen, damit ein Mensch ihn benutzen kann. Oh, kann ich dir sonst noch etwas besorgen?",,"Mi kredas, ke mi povas modifi la flamĵetilon de Krucisto, por ke homo povu uzi ĝin. Ha, ĉu io alia, kion mi povas doni al vi?","Creo poder modificar el lanzallamas de alguno de los Cruzados para que lo pueda usar un humano. Ah, ¿algo más para ofrecerte?",,Luulen pystyväni tekemään ristiretkeläisen liekinheittimestä ihmiskäyttöisen. Voinko olla vielä jotenkin muuten avuksi?,Je crois que je peux convertir un lance-flammes de croisé pour être utilisé par un humain. Je peux faire quelque chose d'autre pour vous?,"Azt hiszem, ha az egyik keresztesről leszednénk egy lángszórót, azt át tudnám alakítani emberi használatra. Ó, még valamit tehetek érted?","Penso di poter convertire un lanciafiamme da uno dei Crociati per essere usato da un umano. Oh, desideri qualcos'altro?","俺ならクルセイダー専用の火炎放射器を 誰でも使える様に作り変えられるだろう。 -ああ、他に何か必要か?",크루세이더가 사용하는 화염방사기를 사람들이 다룰 수 있도록 개조할 수 있을 것 같아. 그래서... 뭘 원해?,"Ik denk dat ik een vlammenwerper van een van de kruisvaarders kan bekeren voor gebruik door een mens. Oh, kan ik nog iets anders voor je halen?","Myślę, że mogę przerobić miotacz ognia jednego z Krzyżowców, by mógł z niego korzystać człowiek. Oh, czy mogę coś jeszcze dla ciebie zrobić?","Acho que eu consigo converter o lança-chamas de um dos Cruzados para ser usado por um humano. Ah, posso te ajudar com mais alguma coisa?",,"Cred că pot converti aruncătorul de flăcări de la un Cruciat pentru a putea fi folosit de oameni. Oh, mai pot să-ți aduc ceva?","Думаю, я смогу приспособить огнемёт для ручного использования. А, ты что-то ещё хотел? -","Мислим да могу претворити бацач пламена са једног од Крсташа за употребу од стране човјека. Ох, још нешто што могу да ти донесем?" -Flamethrower.,TXT_RPLY0_SCRIPT02_D9096_FLAME,,,,Plamenomet.,Flammenwerfer,,,Lanzallamas.,,,Lance-flammes.,Lángszóró.,Lanciafiamme.,火炎放射器,화염방사기?,Vlammenwerper.,Miotacz Ognia,Lança-chamas.,,Aruncător de flăcări.,Огнемёт.,Бацач пламена -"I knew that'd work! Here you go, take her for a spin!",TXT_RYES0_SCRIPT02_D9096_IKNEW,,,,"Věděl jsem, že to bude fungovat! Tady máš, pořádně ji rozpal!","Ich wusste das würde funktionieren! Bitte sehr, probiere ihn mal aus!",,,"¡Sabía que eso funcionaría! Aquí tienes, ¡Dale un paseo!","¡Sabía que eso funcionaría! Aquí tienes, ¡Dale una vuelta!",,Je savais que ça marcherait! Prends-le et va donc l'essayer!,"Tudtam, hogy ez működni fog! Nesze vidd el egy körre!",Lo sapevo che avrebbe funzionato! Prendila e vai a provarla!,よくやってくれた! どうよ、このアツアツな子を!,"역시 잘 작동할 줄 알았어! 여기, 화염방사기야. 한번 놈들에게 사용해봐!","Ik wist dat dat zou werken! Alsjeblieft, neem haar mee voor een ritje!","Wiedziałem, że zadziała! Masz, przetestuj ją!","Eu sabia que daria certo! Toma, leva pra testar!",,"Stiam că va funcționa! Uite, ia-o la o tură!","Я и не сомневался, что всё получится! Держи, испробуй его на ком-нибудь!","Знао сам да ће то успети! Изволи, испробај је мало!" -"Listen, I can't make anything without the right parts!",TXT_RNO0_SCRIPT02_D9096_LISTE,,,,"Poslyš, bez těch správných komponent ti nic nesestavím!","Hör zu, ohne die richtigen Teile kann ich dir nichts machen!",,,"Escucha, ¡No puedo hacer nada sin las partes correctas!",,,"Ecoute, je ne peux pas faire quoi que ce soit si je n'ai pas les pièces dont j'ai besoin!","Figyu, az alkatrészek nélkül semmit sem tudok tenni.","Senti, non posso creare nulla senza i giusti pezzi!",部品が無ければ何も出来ない!,"이봐, 제대로 된 부품 없이는 아무 것도 할 수 없다고!","Luister, ik kan niets maken zonder de juiste onderdelen!","Słuchaj, nie mogę nic zrobić bez właściwych części!","Escuta, eu não consigo fazer qualquer coisa sem as peças certas!",,"Ascultă, nu pot face nimic fără părțile corespunzătoare!","Слушай, у меня нет нужных деталей!","Слушај, не могу ништа да направим без одговарајућих делова!" -Assault gun,TXT_RPLY1_SCRIPT02_D9096_ASSAU,,,,Útočnou pušku,Sturmgewehr,,,Fusil de Asalto,,,Fusil d'Assaut,Gépfegyver,Fucile d'assalto,アサルトガン,돌격소총,Aanvalswapen,Karabin Szturmowy,Fuzil de assalto,,Armă de asalt,Штурмовую винтовку,Аутоматска пушка -"Well, here you go sir!",TXT_RYES1_SCRIPT02_D9096_WELLH,,,,"Tak tady máte, pane!","Alles klar, bitteschön!",,,"Bien, ¡Aquí tiene, caballero!",,,"Voilà pour vous, monsieur!","Nos, íme, lásson csodát Uram!",Ecco qua signore!,ほら、毎度あり!,여기 대령이요!,"Nou, alsjeblieft, meneer!",Oto jest proszę pana!,"Bem, aqui está, senhor!",,"Poftiți, domnule!",Забирай!,"Па, изволите господине!" -"Obviously, you can't afford that right now.",TXT_RNO1_SCRIPT02_D9096_OBVIO,,,,"Je nabíledni, že tohle si teď nemůžeš dovolit.",Offensichtlich kannst du dir das im Moment nicht leisten.,,,"Obviamente, no puedes adquirir esto por ahora.",,,"Manifestement, vous ne pouvez pas vous l'offrir.","Egyértelmű, hogy ezt nem tudod most kifizetni.","Ovviamente, ora non hai abbastanza soldi.",明らかに、今買える余裕は無い。,"당연하겠지만, 아직 가질 수가 없겠네.",Dat kunt je zich natuurlijk nu niet veroorloven.,"Oczywiście, nie możesz teraz tego kupić.",Obviamente você não pode comprar isso agora.,,"Evident, nu-ți poți permite asta chiar acum.","Похоже, тебе это не по карману.",Очигледно немате довољно новца за то сада. -Clip of bullets,TXT_RPLY2_SCRIPT02_D9096_CLIPO,,,,Zásobník nábojů,Gewehrmunition.,,,Cargador con balas,,,Chargeur de balles,Egy tár töltény.,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Magazynek,Carregador de balas,,Cartuș de gloanțe,Обойму патронов,Исјечак метака -Thanks.,TXT_RYES2_SCRIPT02_D9096_THANK,,,,Díky.,Danke.,,,Gracias.,,,Merci.,Köszi.,Grazie.,どうも。,고마워.,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Благодарю.,Хвала. -"Come on, 10 gold.",TXT_RNO2_SCRIPT02_D9096_COMEO,,,,"No tak, je to deset zlatých.","Na komm, 10 Gold.",,,¡Vamos! 10 de oro.,,,"Allez, 10 pièces.","Rajta, 10 arnyat.","Avanti, 10 pezzi d'oro.",頼むぜ、10ゴールドだぞ。,"이봐, 그건 10 골드짜리라고.","Kom op, 10 goud.","No weź, 10 monet.","Vamos lá, 10 de ouro.",,"Haide, 10 monezi de aur.","Ну же, 10 золотых.","Хајде, 10 златника." -Ammo box,TXT_RPLY3_SCRIPT02_D9096_AMMOB,,,,Krabici nábojů,Munitionsschachtel,,,Caja de balas,,,Bôite de balles,Lőszeres doboz.,Scatole di munizioni,弾薬箱,돌격소총 탄약 박스,Munitie doos,Pudło z amunicją,Caixa de balas,,Cutie cu muniție,Коробку патронов,Сандук са муницијом -Here's your ammo.,TXT_RYES3_SCRIPT02_D9096_HERES,,,,Tady je tvá munice.,Hier ist deine Munition.,,,Aquí tienes tus municiones.,,,Voilà vos munitions.,Íme a lőszered.,Ecco le tue munizioni.,これでアンタのブツだ。,여기 탄약.,Hier is je munitie.,Oto twoja amunicja.,Aqui está a sua munição.,,Poftiți muniția.,Вот твои патроны.,Изволи муницију -Maybe some other time. Goodbye!,TXT_RNO3_SCRIPT02_D9096_MAYBE,,,,Možná někdy jindy. Nashledanou!,Vielleicht ein anderes mal. Auf Wiedersehen!,,,Tal vez en otra ocasión. ¡Adiós!,,,"Peut être une autre fois, au revoir!",Talán majd valamikor máskor. Viszontlátásra!,Forse qualche altra volta. Arrivederci!,またの機会に、じゃあな!,다음번에 돈을 챙기고 예기하자. 잘 가!,Misschien een andere keer. Tot ziens!,Może innym razem. Do widzenia!,Talvez outra hora. Até mais!,,Poate altădată. La revedere!,"Может, в другой раз. Пока!",Можда неки други пут. Довиђења! -"Now that you have the flamethrower, is there anything else I can get you?",TXT_DLG_SCRIPT02_D10612_NOWTH,,,,"Teď když máš ten plamenomet, můžu pro tebe udělat něco jiného?","Jetzt wo du den Flammenwerfer hast, gibt es etwas anderes was ich dir besorgen kann?",,,"Ahora que tienes el lanzallamas, ¿Hay algo más que pueda ofrecerte?",,,"Maintenant que vous avez le lance-flammes, est-ce que je peux faire quelque chose pour vous?","Most, hogy megkaptad a lángszórót is, tehetek még valamit érted?","Ora che hai il lanciafiamme, c'è qualcos'altro che ti posso dare?","火炎放射器を手に入れたが、 -他に必要な物はあるか?","이제 화염방사기를 얻었으니, 더 원하는 물품이 있나?","Nu je de vlammenwerper hebt, is er nog iets anders dat ik je kan bezorgen?","Jak już masz miotacz ognia, mogę coś jeszcze dla ciebie zrobić?","Agora que você tem o lança-chamas, deseja mais alguma coisa?",,"Acum că ai aruncătorul de flăcări, mai pot să-ți aduc ceva?","Теперь, когда у тебя есть огнемёт, могу я ещё чем-нибудь тебе помочь?","Сада када имаш бацач пламена, има ли још нешто шта ти могу донети?" -Assault gun,TXT_RPLY0_SCRIPT02_D10612_ASSAU,,,,Útočnou pušku,Sturmgewehr,,,Fusil de Asalto,,,Fusil d'Assaut,Gépfegyver,Fucile d'assalto,アサルトガン,돌격소총,Aanvalswapen,Karabin Szturmowy,Fuzil de assalto,,Armă de asalt,Штурмовую винтовку,Аутоматска пушка -Here you go.,TXT_RYES0_SCRIPT02_D10612_HEREY,,,,Tu máš.,Bitte sehr!,,,Aquí tienes.,,,Voilà pour vous.,Itt is van!,Ecco qua.,毎度あり。,여기 있어.,Alsjeblieft.,Proszę bardzo.,Aqui está.,,Poftiți.,Забирай!,Изволи. -You can't afford that right now.,TXT_RNO0_SCRIPT02_D10612_YOUCA,,,,Tu si teď nemůžeš dovolit.,Das kannst du dir im Moment nicht leisten.,,,No puedes adquirir esto ahora.,,,Vous n'avez pas assez d'argent.,Erre jelenleg nincs pénzed.,Non hai abbastanza soldi.,今それを買える余裕は無い。,그럴 여유가 전혀 없는 것 같은데 말이지.,Dat kunt u zich nu niet veroorloven.,Nie możesz teraz tego kupić.,Você não pode comprar isso no momento.,,Nu-ți poți permite asta încă.,"Похоже, тебе это не по карману.",Не можете то сада себи приуштити. -Clip of bullets,TXT_RPLY1_SCRIPT02_D10612_CLIPO,,,,Zásobník nábojů,Gewehrmunition.,,,Cargador con balas,,,Chargeur de balles,egy tárnyi töltény,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Magazynek,Carregador de balas,,Cartuș de gloanțe,Обойму патронов,Исјечак метака -Thanks.,TXT_RYES1_SCRIPT02_D10612_THANK,,,,Díky.,Danke.,,,Gracias.,,,Merci.,Köszi.,Grazie.,どうも。,고마워.,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Благодарю.,Хвала. -"Come on, 10 gold.",TXT_RNO1_SCRIPT02_D10612_COMEO,,,,"No tak, je to deset zlatých.","Komm schon, 10 Gold.",,,¡Vamos! 10 de oro.,,,"Allez, 10 pièces.","Gyerünk, 10 aranyat.","Avanti, 10 pezzi d'oro.",頼むぜ、10ゴールドだぞ。,"이봐, 10 골드를 먼저 달라고.","Kom op, 10 goud.","No weź, 10 monet.","Vamos lá, 10 de ouro.",,"Haide, 10 monezi de aur.","Ну же, 10 золотых.","Хајде, 10 златника." -Ammo box,TXT_RPLY2_SCRIPT02_D10612_AMMOB,,,,Krabici nábojů,Munitionsschachtel,,,Caja de balas,,,Boîte de balles,Töltényes doboz,Scatole di munizioni,銃弾倉箱,돌격소총 탄약 박스,Munitie doos,Pudło z amunicją,Caixa de balas,,Cutie cu muniție,Коробку патронов,Сандук са муницијом -Here's your ammo.,TXT_RYES2_SCRIPT02_D10612_HERES,,,,Tady je tvá munice.,Hier ist deine Munition.,,,Aquí tienes tus municiones.,,,Voilà vos munitions.,Itt a töltényed.,Ecco le tue munizioni.,これでアンタのブツだ。,여기 네 탄약이야.,Hier is je munitie.,Oto twoja amunicja.,Aqui está a sua munição.,,Poftiți muniția.,Вот твои патроны.,Изволи муницију. -Maybe some other time.,TXT_RNO2_SCRIPT02_D10612_MAYBE,,,,Možná někdy jindy.,Vielleicht ein anderes mal.,,,Tal vez en otra ocasión.,,,Peut être une autre fois.,Talán Máskor.,Forse un'altra volta.,また後でな。,지금 말고. 아마도 나중에?,Misschien een andere keer.,Może innym razem.,Talvez outra hora.,,Poate altădată.,"Может, в другой раз.",Можда неки други пут. -"Now that you have the flamethrower, is there anything else I can get you?",TXT_DLG_SCRIPT02_D12128_NOWTH,,,,"Teď, když máš ten plamenomet, můžu pro tebe udělat něco jiného?","Jetzt wo du den Flammenwerfer hast, gibt es etwas anderes was ich dir besorgen kann?",,,"Ahora que tienes el lanzallamas, ¿Hay algo más que pueda ofrecerte?",,,"Maintenant que vous avez le lance-flammes, est-ce que je peux faire quelque chose pour vous?","Most, hogy van egy lángszóród, van bármi más, amivel szolgáhatok?","Ora che hai il lanciafiamme, c'è qualcos'altro che ti posso dare?","火炎放射器を手に入れたが、 -他に必要な物はあるか?","이제 화염방사기를 얻었으니, 더 원하는 물품이 있나?","Nu je de vlammenwerper hebt, is er nog iets anders dat ik je kan bezorgen?","Jak już masz miotacz ognia, mogę coś jeszcze dla ciebie zrobić?","Agora que você tem o lança-chamas, deseja mais alguma coisa?",,"Acum că ai aruncătorul de flăcări, mai pot să-ți aduc ceva?","Теперь, когда у тебя есть огнемёт, могу я ещё чем-нибудь тебе помочь?","Сада када имаш бацач пламена, има ли још нешто шта ти могу донети?" -Clip of bullets,TXT_RPLY0_SCRIPT02_D12128_CLIPO,,,,Zásobník nábojů,Gewehrmunition.,,,Caja de balas,,,Chargeur de balles,egy tárnyi töltény,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Magazynek,Carregador de balas,,Cartuș de gloanțe,Обойму патронов,Исјечак метака -Thanks.,TXT_RYES0_SCRIPT02_D12128_THANK,,,,Díky.,Danke.,,,Gracias.,,,Merci.,Köszönöm,Grazie.,どうも。,고맙네.,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Благодарю.,Хвала. -"Come on, 10 gold.",TXT_RNO0_SCRIPT02_D12128_COMEO,,,,"No tak, je to deset zlatých.","Na komm, 10 Gold.",,,¡Vamos! 10 de oro.,,,"Allez, 10 pièces.","Gyerünk már, 10 aranyat.","Avanti, 10 pezzi d'oro.",頼むぜ、10ゴールドだぞ。,"이봐, 그건 10 골드라고.","Kom op, 10 goud.","No weź, 10 monet.","Vamos lá, 10 de ouro.",,"Haide, 10 monezi de aur.","Ну же, 10 золотых.","Хајде, 10 златника." -Ammo box,TXT_RPLY1_SCRIPT02_D12128_AMMOB,,,,Krabici nábojů,Munitionsschachtel,,,Caja de balas,,,Bôite de balles,Lőszeres doboz.,Scatole di munizioni,銃弾倉箱,돌격소총 탄약 박스,Munitie doos,Pudło z amunicją,Caixa de balas,,Cutie cu muniție,Коробку патронов,Сандук са муницијом -Here's your ammo.,TXT_RYES1_SCRIPT02_D12128_HERES,,,,Tady je tvá munice.,Hier ist deine Munition.,,,Aquí tienes tus municiones.,,,Voilà vos munitions.,Itt a lőszered.,Ecco le tue munizioni.,これでアンタのブツだ。,여기 탄약이야.,Hier is je munitie.,Oto twoja amunicja.,Aqui está a sua munição.,,Poftiți muniția.,Вот твои патроны.,Изволи муницију. -Maybe some other time.,TXT_RNO1_SCRIPT02_D12128_MAYBE,,,,Možná někdy jindy.,Vielleicht ein anderes Mal.,,,Tal vez en otra ocasión.,,,Peut être une autre fois.,Talán majd máskor.,Forse un'altra volta.,また後でな。,다음 번에 찾아와서 알려줘.,Misschien een andere keer.,Może innym razem.,Talvez outra hora.,,Poate altădată.,"Может, в другой раз.",Можда неки други пут. -Phosphor grenades,TXT_RPLY2_SCRIPT02_D12128_PHOSP,,,,Fosforečné granáty,Phosphorgranaten,,,Granadas de Fósforo,,,Grenades phosphoriques,Foszforgránátok,Granate al Fosforo.,白リングレネード弾,소이 유탄,Fosforgranaten,Fosforowe granaty,Granadas de fósforo,,Grenade cu fosfor,Фосфорные гранаты,Фосфор гранате -Thanks.,TXT_RYES2_SCRIPT02_D12128_THANK,,,,Díky.,Danke.,,,Gracias.,,,Merci.,Kösz.,Grazie.,どうも。,고마워.,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Благодарю.,Хвала. -You don't have enough,TXT_RNO2_SCRIPT02_D12128_YOUDO,,,,Nemáš u sebe dost.,Du hast nicht genug,,,No tienes suficiente,,,Vous n'avez pas assez d'argent.,Nincs elég pénzed more,Non hai abbastanza soldi.,十分な額じゃない,충분치 않아.,Je hebt niet genoeg...,Nie wystarczy ci.,Você não tem o suficiente.,,Nu ai suficiente,Тебе не хватает на них.,Немаш довољно -Poison bolts,TXT_RPLY3_SCRIPT02_D12128_POISO,,,,Otrávené šípy,Giftbolzen,,,Saetas envenenadas,,,Carreaux Empoisonnés,Mérgezett nyilak,Frecce avvelenate.,ポイズンボルト,맹독 볼트,Giftige bouten,Zatrute bełty,Setas venenosas,,Bolțuri cu otravă,Отравленные болты,Отровне стреле -Worth every gold!,TXT_RYES3_SCRIPT02_D12128_WORTH,,,,Ty se vyplatí!,Jedes Goldstück wert!,,,¡Valen cada moneda de oro!,,,Ca vaut son prix!,Minden aranyat megér,Ne vale la pena!,値段に合う価値だぜ!,아주 가치가 있는 것이지!,Elk goud waard!,Warte każdych pieniędzy!,Vale cada moeda de ouro!,,Merită fiecare bănuț!,Они того стоят!,Вредно сваког златника! -"Come on, 200 gold!",TXT_RNO3_SCRIPT02_D12128_COMEO,,,,"No tak, 200 zlatých!","Na komm, 200 Gold!",,,¡Vamos! 200 de oro.,,,"Allez, 200 pièces!","Rajta, 200 arany!","Avanti, 200 pezzi d'oro.",頼むぜ、200ゴールドだぞ!,"이봐, 이건 200 골드라고!","Kom op, 200 goud!","No weź, 200 monet!","Vamos lá, 200 de ouro!",,"Haide, 200 monezi de aur!","Ну же, 200 золотых!","Хајде, 200 златника!" -I can't believe that I got stuck with this duty. They say that something evil came up out of this sewer gate... Now I get to stand here until it comes up again!,TXT_DLG_SCRIPT02_D13644_ICANT,,,,"Nemůžu uvěřit, že jsem zkysnul s touhle prací. Řekli mi, že z téhle brány vylezlo něco zlého... A teď tady mám stát dokud to znovu nevyleze!","Ich kann's nicht glauben dass ich diesen Dienst hier machen muss. Sie haben gesagt, dass etwas Böses aus dem Kanalisationstor gekommen ist... Nun muss ich hier stehen, bis es wieder kommt!",,,No puedo creer que me quedara con esta tarea. Dicen que algo maligno salió de esta compuerta de alcantarilla... ¡Ahora tengo que quedarme aquí hasta que salga de nuevo!,,,J'arrive pas à croire que je me retrouve coincé ici. On me raconte qu'une chose maléfique est sortie de cette barrière des égouts.. Maintenant je me retrouve planté ici jusqu'a ce qu'elle revienne!,"El sem hiszem, hogy még mindig ennél a melónál rekedtem. Úgy hírlik, hogy valami gonosz bukkant fel itt a csatorna kapuja felől... Most addig fogok itt állni, amíg újra fel nem bukkan.",Non posso credere di aver accettato questo lavoro. Dicono che qualcosa di malvagio sia sbucato dalla chiusa delle fogne... E io devo stare qui finché non ritorna! ,"私がこの勤務で足止めとは信じられん。 +ああ、他に何か必要か?",크루세이더가 사용하는 화염방사기를 사람들이 다룰 수 있도록 개조할 수 있을 것 같아. 그래서... 뭘 원해?,"Ik denk dat ik een vlammenwerper van een van de kruisvaarders kan bekeren voor gebruik door een mens. Oh, kan ik nog iets anders voor je halen?",Jeg tror jeg kan konvertere en flammekaster fra en av korsfarerne til å brukes av et menneske. Noe annet jeg kan gi deg?,"Myślę, że mogę przerobić miotacz ognia jednego z Krzyżowców, by mógł z niego korzystać człowiek. Oh, czy mogę coś jeszcze dla ciebie zrobić?","Acho que eu consigo converter o lança-chamas de um dos Cruzados para ser usado por um humano. Ah, posso te ajudar com mais alguma coisa?",,"Cred că pot converti aruncătorul de flăcări de la un Cruciat pentru a putea fi folosit de oameni. Oh, mai pot să-ți aduc ceva?","Думаю, я смогу приспособить огнемёт для ручного использования. А, ты что-то ещё хотел? +",,"Jag tror att jag kan konvertera en eldkastare från en av korsfararna så att den kan användas av en människa. Åh, något annat jag kan ge dig?",Sanırım Haçlılardan birinin alev silahını bir insan tarafından kullanılmak üzere dönüştürebilirim. Sana verebileceğim başka bir şey var mı? +Flamethrower.,TXT_RPLY0_SCRIPT02_D9096_FLAME,〃 (〃),,,Plamenomet.,Flammekaster.,Flammenwerfer,,Flamĵetilon,Lanzallamas.,,Liekinheitin.,Lance-flammes.,Lángszóró.,Lanciafiamme.,火炎放射器,화염방사기?,Vlammenwerper.,Flammekaster.,Miotacz Ognia,Lança-chamas.,,Aruncător de flăcări.,Огнемёт.,,Flamkastare,Alev makinesi. +"I knew that'd work! Here you go, take her for a spin!",TXT_RYES0_SCRIPT02_D9096_IKNEW,〃 (〃),,,"Věděl jsem, že to bude fungovat! Tady máš, pořádně ho rozpal!","Jeg vidste, at det ville virke! Værsgo, tag en tur med hende!","Ich wusste das würde funktionieren! Bitte sehr, probiere ihn mal aus!",,"Mi sciis, ke tio sukcesus! +Jen ĝi. Provu ĝin!","¡Sabía que iba a resultar! +Toma. ¡Pruébalo!",,"Tiesin sen toimivan! Anna palaa, vie se kierrokselle!",Je savais que ça marcherait! Prends-le et va donc l'essayer!,"Tudtam, hogy ez működni fog! Nesze vidd el egy körre!",Lo sapevo che avrebbe funzionato! Prendilo e vai a provarlo!,よくやってくれた! どうよ、このアツアツな子を!,"역시 잘 작동할 줄 알았어! 여기, 화염방사기야. 한번 놈들에게 사용해봐!","Ik wist dat dat zou werken! Alsjeblieft, neem haar mee voor een ritje!","Jeg visste det ville fungere! Vær så god, ta en tur med den!","Wiedziałem, że zadziała! Masz, przetestuj ją!","Eu sabia que daria certo! Toma, leva pra testar!",,"Stiam că va funcționa! Uite, ia-o la o tură!","Я и не сомневался, что всё получится! Держи, испробуй его на ком-нибудь!",,"Jag visste att det skulle fungera! Varsågod, ta en sväng med henne!","Bunun işe yarayacağını biliyordum! Al bakalım, bir tur at!" +"Listen, I can't make anything without the right parts!",TXT_RNO0_SCRIPT02_D9096_LISTE,〃 (〃),,,"Poslyš, bez použitelných součástek ti nic nepostavím!","Hør, jeg kan ikke lave noget uden de rigtige dele!","Hör zu, ohne die richtigen Teile kann ich dir nichts machen!",,"Nu, mi povas fari nenion +sen la ĝustaj partoj!","A ver, ¡no puedo hacer nada +sin las partes correctas!",,"Kuules, ilman oikeita osia en pysty tekemään mitään!","Ecoute, je ne peux pas faire quoi que ce soit si je n'ai pas les pièces dont j'ai besoin!","Figyu, a megfelelő alkatrészek nélkül semmit sem tudok tenni.","Senti, non posso creare nulla senza i pezzi che mi servono!",部品が無ければ何も出来ない!,"이봐, 제대로 된 부품 없이는 아무 것도 할 수 없다고!","Luister, ik kan niets maken zonder de juiste onderdelen!",Jeg kan ikke lage noe uten de rette delene!,"Słuchaj, nie mogę nic zrobić bez właściwych części!","Escuta, eu não consigo fazer qualquer coisa sem as peças certas!",,"Ascultă, nu pot face nimic fără părțile corespunzătoare!","Слушай, у меня нет нужных деталей!",,"Lyssna, jag kan inte göra något utan rätt delar!","Dinle, doğru parçalar olmadan hiçbir şey yapamam!" +Assault gun,TXT_RPLY1_SCRIPT02_D9096_ASSAU,〃 (〃),,,Útočnou pušku,Angrebsvåben,Sturmgewehr,,Sturmofusilon,Fusil de asalto,,Rynnäkkökivääri,Fusil d'Assaut,Gépfegyver,Fucile d'assalto,アサルトガン,돌격소총,Aanvalswapen,Flammekaster.,Karabin Szturmowy,Fuzil de assalto,,Armă de asalt,Штурмовую винтовку,,Anfallspistol,Saldırı silahı +"Well, here you go sir!",TXT_RYES1_SCRIPT02_D9096_WELLH,〃 (〃),,,"Tak tady máte, pane!","Værsgo, sir!","Alles klar, bitteschön!",,"Nu, jen, sinjoro!","¡Bueno, aquí tiene, caballero!",,"Kas tässä, hyvä herra!","Voilà pour vous, monsieur!","Nos, parancsoljon!","Bene, ecco qua signore!",ほら、毎度あり!,여기 대령이요!,"Nou, alsjeblieft, meneer!",Vær så god!,Oto jest proszę pana!,"Bem, aqui está, senhor!",,"Poftiți, domnule!",Забирай!,,"Här har du, sir!",Buyurun efendim! +"Obviously, you can't afford that right now.",TXT_RNO1_SCRIPT02_D9096_OBVIO,〃 (〃),,,Tu si teď opravdu nemůžeš dovolit.,Du har tydeligvis ikke råd til den lige nu.,Offensichtlich kannst du dir das im Moment nicht leisten.,,"Evidente vi nun ne +havas sufiĉe da mono.","Obviamente no te +alcanza por ahora.",,Sinulla ei selvästikään ole siihen nyt varaa.,"Manifestement, vous ne pouvez pas vous l'offrir.","Egyértelmű, hogy ezt nem tudod most kifizetni.","Ovviamente, ora non te lo puoi permettere.",明らかに、今買える余裕は無い。,"당연하겠지만, 아직 가질 수가 없겠네.",Dat kunt je zich natuurlijk nu niet veroorloven.,Det har du selvsagt ikke råd til akkurat nå!,"Oczywiście, nie możesz teraz tego kupić.",Obviamente você não pode comprar isso agora.,,"Evident, nu-ți poți permite asta chiar acum.","Похоже, тебе это не по карману.",,Uppenbarligen har du inte råd med den just nu.,Belli ki şu anda bunu karşılayamazsınız. +Clip of bullets,TXT_RPLY2_SCRIPT02_D9096_CLIPO,〃 (〃),,,Zásobník nábojů,Et patron-klip,Gewehrmunition.,,Magazenon,Un cargador,,Luotilipas,Chargeur de balles,Egy tár töltény.,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Et magasin med kuler.,Magazynek,Carregador de balas,,Cartuș de gloanțe,Обойму патронов,,Kulor i ett klipp,Mermi şarjörü +Thanks.,TXT_RYES2_SCRIPT02_D9096_THANK,〃 (〃),,,Díky.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Köszi.,Grazie.,どうも。,고마워.,Bedankt.,Takk skal du ha.,Dzięki.,Agradeço.,,Mulțumesc.,Благодарю.,,Tack.,Teşekkürler. +"Come on, 10 gold.",TXT_RNO2_SCRIPT02_D9096_COMEO,〃 (〃),,,"No tak, jen deset zlatých.","Kom nu, 10 guld.","Na komm, 10 Gold.",,"Nu, ĝi kostas dek da oro.","Vamos, que son diez de oro.",,"Antaa tulla, 10 kolikkoa.","Allez, 10 pièces.","Rajta, 10 aranyat.","Avanti, 10 pezzi d'oro.",頼むぜ、10ゴールドだぞ。,"이봐, 그건 10 골드짜리라고.","Kom op, 10 goud.","Kom igjen, 10 gull.","No weź, 10 monet.","Vamos lá, 10 de ouro.",,"Haide, 10 monezi de aur.","Ну же, 10 золотых.",,"Kom igen, 10 guld.","Hadi, 10 altın." +Ammo box,TXT_RPLY3_SCRIPT02_D9096_AMMOB,〃 (〃),,,Krabici nábojů,Ammo kasse,Munitionsschachtel,,Munici-keston,Caja de municiones,,Ammuslaatikko,Bôite de balles,Lőszeres doboz.,Scatola di munizioni,弾薬箱,돌격소총 탄약 박스,Munitie doos,Ammunisjonsboks,Pudło z amunicją,Caixa de balas,,Cutie cu muniție,Коробку патронов,,Ammunitionslåda,Cephane kutusu +Here's your ammo.,TXT_RYES3_SCRIPT02_D9096_HERES,〃 (〃),,,Tady je tvá munice.,Her er din ammunition.,Hier ist deine Munition.,,Jen via municio.,Aquí está tu munición.,,Tässä ammuksesi.,Voilà vos munitions.,Itt a lőszered.,Ecco le tue munizioni.,これでアンタのブツだ。,여기 탄약.,Hier is je munitie.,Her er ammunisjonen din.,Oto twoja amunicja.,Aqui está a sua munição.,,Poftiți muniția.,Вот твои патроны.,,Här är din ammunition.,İşte cephanen. +Maybe some other time. Goodbye!,TXT_RNO3_SCRIPT02_D9096_MAYBE,〃 (〃),,,Možná někdy jindy. Nashledanou!,Måske en anden gang. Farvel!,Vielleicht ein anderes mal. Auf Wiedersehen!,,Eble alimomente. Ĝis!,"Puede que en +otro momento. ¡Adiós!","Puede que en otro +momento. ¡Nos vemos!",Ehkä jokin toinen aika. Näkemiin!,"Peut être une autre fois, au revoir!",Talán majd valamikor máskor. Viszlát!,Sarà per un'altra volta. Arrivederci!,またの機会に、じゃあな!,다음번에 돈을 챙기고 예기하자. 잘 가!,Misschien een andere keer. Tot ziens!,Kanskje en annen gang. Adjø!,Może innym razem. Do widzenia!,Talvez outra hora. Até mais!,,Poate altădată. La revedere!,"Может, в другой раз. Пока!",,Kanske en annan gång. Adjö!,Belki başka bir zaman. Güle güle! +"Now that you have the flamethrower, is there anything else I can get you?",TXT_DLG_SCRIPT02_D10612_NOWTH,〃 (With flamethrower),,,"Teď když máš ten plamenomet, můžu pro tebe udělat něco jiného?","Nu hvor du har flammekasteren, er der så noget andet, jeg kan skaffe dig?","Jetzt wo du den Flammenwerfer hast, gibt es etwas anderes was ich dir besorgen kann?",,"Nun kiam vi havas la flamĵetilon, ĉu estas io alia, kion mi povus doni al vi?","Ahora que tienes el lanzallamas, ¿hay algo más que pueda ofrecerte?",,"Voisinko vielä jotenkin auttaa, nyt kun sinulla on liekinheitin?","Maintenant que vous avez le lance-flammes, est-ce que je peux faire quelque chose pour vous?","Most, hogy megkaptad a lángszórót is, tehetek még valamit érted?","Ora che hai il lanciafiamme, c'è qualcos'altro che ti posso dare?","火炎放射器を手に入れたが、 +他に必要な物はあるか?","이제 화염방사기를 얻었으니, 더 원하는 물품이 있나?","Nu je de vlammenwerper hebt, is er nog iets anders dat ik je kan bezorgen?","Nå som du har flammekasteren, er det noe annet jeg kan skaffe deg?","Jak już masz miotacz ognia, mogę coś jeszcze dla ciebie zrobić?",Agora que você tem o lança-chamas. Deseja mais alguma coisa?,,"Acum că ai aruncătorul de flăcări, mai pot să-ți aduc ceva?","Ну, огнемёт у тебя теперь есть. Могу я ещё чем-нибудь помочь?",,"Nu när du har flamkastaren, finns det något annat jag kan ge dig?","Artık alev makinen olduğuna göre, sana verebileceğim başka bir şey var mı?" +Assault gun,TXT_RPLY0_SCRIPT02_D10612_ASSAU,〃 (〃),,,Útočnou pušku,Angrebsvåben,Sturmgewehr,,Sturmofusilon,Fusil de asalto,,Rynnäkkökivääri,Fusil d'Assaut,Gépfegyver,Fucile d'assalto,アサルトガン,돌격소총,Aanvalswapen,Stormgevær.,Karabin Szturmowy,Fuzil de assalto,,Armă de asalt,Штурмовую винтовку,,Anfallspistol,Saldırı silahı +Here you go.,TXT_RYES0_SCRIPT02_D10612_HEREY,〃 (〃),,,Tu máš.,Værsgo.,Bitte sehr!,,Jen.,Toma.,,Ole hyvä.,Voilà pour vous.,Itt is van!,Ecco a te.,毎度あり。,여기 있어.,Alsjeblieft.,Vær så god.,Proszę bardzo.,Aqui está.,,Poftiți.,Забирай!,,Varsågod.,Al bakalım. +You can't afford that right now.,TXT_RNO0_SCRIPT02_D10612_YOUCA,〃 (〃),,,Tu si teď nemůžeš dovolit.,Den har du ikke råd til lige nu.,Das kannst du dir im Moment nicht leisten.,,"Vi nun ne havas +sufiĉe da oro.",No te alcanza por ahora.,,Sinulla ei ole siihen juuri nyt varaa.,Vous n'avez pas assez d'argent.,Erre jelenleg nincs pénzed.,Non hai abbastanza soldi.,今それを買える余裕は無い。,그럴 여유가 전혀 없는 것 같은데 말이지.,Dat kunt u zich nu niet veroorloven.,Det har du ikke råd til akkurat nå.,Nie możesz teraz tego kupić.,Você não pode comprar isso no momento.,,Nu-ți poți permite asta încă.,"Похоже, тебе это не по карману.",,Du har inte råd med den just nu.,Şu anda bunu karşılayamazsın. +Clip of bullets,TXT_RPLY1_SCRIPT02_D10612_CLIPO,〃 (〃),,,Zásobník nábojů,Et patron-klip,Gewehrmunition.,,Magazenon,Un cargador,,Luotilipas,Chargeur de balles,Egy tárnyi töltény,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Et magasin med kuler.,Magazynek,Carregador de balas,,Cartuș de gloanțe,Обойму патронов,,Kulor.,Mermi şarjörü +Thanks.,TXT_RYES1_SCRIPT02_D10612_THANK,〃 (〃),,,Díky.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Köszi.,Grazie.,どうも。,고마워.,Bedankt.,Takk skal du ha.,Dzięki.,Agradeço.,,Mulțumesc.,Благодарю.,,Tack.,Teşekkürler. +"Come on, 10 gold.",TXT_RNO1_SCRIPT02_D10612_COMEO,〃 (〃),,,"No tak, jen deset zlatých.","Kom nu, 10 guld.","Komm schon, 10 Gold.",,"Nu, ĝi kostas dek da oro.","Vamos, que son diez de oro.",,"Antaa tulla, 10 kolikkoa.","Allez, 10 pièces.","Gyerünk, 10 aranyat.","Avanti, 10 pezzi d'oro.",頼むぜ、10ゴールドだぞ。,"이봐, 10 골드를 먼저 달라고.","Kom op, 10 goud.","Kom igjen, 10 gull.","No weź, 10 monet.","Vamos lá, 10 de ouro.",,"Haide, 10 monezi de aur.","Ну же, 10 золотых.",,"Kom igen, 10 guld.","Hadi, 10 altın." +Ammo box,TXT_RPLY2_SCRIPT02_D10612_AMMOB,〃 (〃),,,Krabici nábojů,Ammo kasse,Munitionsschachtel,,Munici-keston,Caja de municiones,,Ammuslaatikko,Boîte de balles,Töltényes doboz,Scatola di munizioni,銃弾倉箱,돌격소총 탄약 박스,Munitie doos,Ammunisjonsboks,Pudło z amunicją,Caixa de balas,,Cutie cu muniție,Коробку патронов,,Ammunitionslåda,Cephane kutusu +Here's your ammo.,TXT_RYES2_SCRIPT02_D10612_HERES,〃 (〃),,,Tady je tvá munice.,Her er din ammunition.,Hier ist deine Munition.,,Jen via municio.,Aquí está tu munición.,,Tässä ammuksesi.,Voilà vos munitions.,Itt a töltényed.,Ecco le tue munizioni.,これでアンタのブツだ。,여기 네 탄약이야.,Hier is je munitie.,Her er ammunisjonen din.,Oto twoja amunicja.,Aqui está a sua munição.,,Poftiți muniția.,Вот твои патроны.,,Här är din ammunition.,İşte cephanen. +Maybe some other time.,TXT_RNO2_SCRIPT02_D10612_MAYBE,〃 (〃),,,Možná někdy jindy.,Måske en anden gang.,Vielleicht ein anderes mal.,,Eble alimomente.,"Puede que en +otro momento.",,Ehkä joku toinen kerta.,Peut être une autre fois.,Talán Máskor.,Magari un'altra volta.,また後でな。,지금 말고. 아마도 나중에?,Misschien een andere keer.,Kanskje en annen gang.,Może innym razem.,Talvez outra hora.,,Poate altădată.,"Может, в другой раз.",,Kanske en annan gång.,Belki başka bir zaman. +"Now that you have the flamethrower, is there anything else I can get you?",TXT_DLG_SCRIPT02_D12128_NOWTH,〃 (〃),,,"Teď, když máš ten plamenomet, můžu pro tebe udělat něco jiného?","Nu hvor du har flammekasteren, er der så noget andet, jeg kan give dig?","Jetzt wo du den Flammenwerfer hast, gibt es etwas anderes was ich dir besorgen kann?",,"Nun kiam vi havas la flamĵetilon, ĉu estas io alia, kion mi povus doni al vi?","Ahora que tienes el lanzallamas, ¿hay algo más que pueda ofrecerte?",,"Nyt kun sinulla on liekinheitin, saisiko sinulle vielä olla jotain muuta?","Maintenant que vous avez le lance-flammes, est-ce que je peux faire quelque chose pour vous?","Most, hogy van egy lángszóród, van bármi más, amivel szolgáhatok?","Ora che hai il lanciafiamme, c'è qualcos'altro che ti posso dare?","火炎放射器を手に入れたが、 +他に必要な物はあるか?","이제 화염방사기를 얻었으니, 더 원하는 물품이 있나?","Nu je de vlammenwerper hebt, is er nog iets anders dat ik je kan bezorgen?","Nå som du har flammekasteren, er det noe annet jeg kan gi deg?","Jak już masz miotacz ognia, mogę coś jeszcze dla ciebie zrobić?",Agora que você tem o lança-chamas. Deseja mais alguma coisa?,,"Acum că ai aruncătorul de flăcări, mai pot să-ți aduc ceva?","Ну, огнемёт у тебя теперь есть. Могу я ещё чем-нибудь помочь?",,"Nu när du har flamkastaren, finns det något annat jag kan ge dig?","Artık alev silahın olduğuna göre, sana verebileceğim başka bir şey var mı?" +Clip of bullets,TXT_RPLY0_SCRIPT02_D12128_CLIPO,〃 (〃),,,Zásobník nábojů,Et patron-klip,Gewehrmunition.,,Magazenon,Un cargador,,Luotilipas,Chargeur de balles,Egy tárnyi töltény,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Et magasin med kuler.,Magazynek,Carregador de balas,,Cartuș de gloanțe,Обойму патронов,,Magasin med kulor,Bir şarjör mermi +Thanks.,TXT_RYES0_SCRIPT02_D12128_THANK,〃 (〃),,,Díky.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Köszönöm,Grazie.,どうも。,고맙네.,Bedankt.,Takk skal du ha.,Dzięki.,Agradeço.,,Mulțumesc.,Благодарю.,,Tack.,Teşekkürler. +"Come on, 10 gold.",TXT_RNO0_SCRIPT02_D12128_COMEO,〃 (〃),,,"No tak, jen deset zlatých.","Kom nu, 10 guld.","Na komm, 10 Gold.",,"Nu, ĝi kostas dek da oro.","Vamos, que son diez de oro.",,"Antaa tulla, 10 kolikkoa.","Allez, 10 pièces.","Gyerünk már, 10 aranyat.","Avanti, 10 pezzi d'oro.",頼むぜ、10ゴールドだぞ。,"이봐, 그건 10 골드라고.","Kom op, 10 goud.","Kom igjen, 10 gull.","No weź, 10 monet.","Vamos lá, 10 de ouro.",,"Haide, 10 monezi de aur.","Ну же, 10 золотых.",,"Kom igen, 10 guld.","Hadi, 10 altın." +Ammo box,TXT_RPLY1_SCRIPT02_D12128_AMMOB,〃 (〃),,,Krabici nábojů,Ammo kasse,Munitionsschachtel,,Munici-keston,Caja de municiones,,Ammuslaatikko,Bôite de balles,Lőszeres doboz.,Scatola di munizioni,銃弾倉箱,돌격소총 탄약 박스,Munitie doos,Ammunisjonsboks,Pudło z amunicją,Caixa de balas,,Cutie cu muniție,Коробку патронов,,Ammunitionslåda,Cephane kutusu +Here's your ammo.,TXT_RYES1_SCRIPT02_D12128_HERES,〃 (〃),,,Tady je tvá munice.,Her er din ammunition.,Hier ist deine Munition.,,Jen via municio.,Aquí está tu munición.,,Tässä ammuksesi.,Voilà vos munitions.,Itt a lőszered.,Ecco le tue munizioni.,これでアンタのブツだ。,여기 탄약이야.,Hier is je munitie.,Her er ammunisjonen din.,Oto twoja amunicja.,Aqui está a sua munição.,,Poftiți muniția.,Вот твои патроны.,,Här är din ammunition.,İşte cephanen. +Maybe some other time.,TXT_RNO1_SCRIPT02_D12128_MAYBE,〃 (〃),,,Možná někdy jindy.,Måske en anden gang.,Vielleicht ein anderes Mal.,,Eble alimomente.,"Puede que en +otro momento.",,Ehkä joku toinen kerta.,Peut être une autre fois.,Talán majd máskor.,Magari un'altra volta.,また後でな。,다음 번에 찾아와서 알려줘.,Misschien een andere keer.,Kanskje en annen gang.,Może innym razem.,Talvez outra hora.,,Poate altădată.,"Может, в другой раз.",,Kanske en annan gång.,Belki başka bir zaman. +Phosphor grenades,TXT_RPLY2_SCRIPT02_D12128_PHOSP,,,,Fosforové granáty,Phosphor granater,Phosphorgranaten,,Fosforajn grenadojn,Granadas de fósforo,,Fosforikranaatteja,Grenades phosphoriques,Foszforgránátok,Granate al Fosforo.,白リングレネード弾,소이 유탄,Fosforgranaten,Fosforgranater,Fosforowe granaty,Granadas de fósforo,,Grenade cu fosfor,Фосфорные гранаты,,Fosforgranater,Fosfor bombaları +Thanks.,TXT_RYES2_SCRIPT02_D12128_THANK,,,,Díky.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Kösz.,Grazie.,どうも。,고마워.,Bedankt.,Takk skal du ha.,Dzięki.,Agradeço.,,Mulțumesc.,Благодарю.,,Tack.,Teşekkürler. +You don't have enough,TXT_RNO2_SCRIPT02_D12128_YOUDO,,,,Nemáš u sebe dost.,Du har ikke nok,Du hast nicht genug,,Vi ne havas sufiĉe da mono.,No te alcanza.,,Sinulla ei ole riittävästi,Vous n'avez pas assez d'argent.,Nincs elég pénzed,Non hai abbastanza soldi.,十分な額じゃない,충분치 않아.,Je hebt niet genoeg...,Du har ikke nok,Nie wystarczy ci.,Você não tem o suficiente.,,Nu ai suficiente,Тебе не хватает на них.,,Du har inte tillräckligt med,Sende yeterince +Poison bolts,TXT_RPLY3_SCRIPT02_D12128_POISO,,,,Otrávené šípy,Giftbolte,Giftbolzen,,Venenajn sagojn,Flechas envenenadas,,Myrkkynuolia,Carreaux Empoisonnés,Mérgezett nyilak,Frecce avvelenate.,ポイズンボルト,맹독 볼트,Giftige bouten,Giftbolter,Zatrute bełty,Setas venenosas,,Bolțuri cu otravă,Отравленные болты,,Giftbultar.,Zehirli cıvatalar +Worth every gold!,TXT_RYES3_SCRIPT02_D12128_WORTH,,,,Ty se vyplatí!,Hvert et guld værd!,Jedes Goldstück wert!,,"Ili valoras po +ĉiu monero!","¡Lo vale cada +moneda de oro!",,Joka kolikon väärti!,Ca vaut son prix!,Minden aranyat megér,Ne vale la pena!,値段に合う価値だぜ!,아주 가치가 있는 것이지!,Elk goud waard!,Verdt hvert gull!,Warte każdych pieniędzy!,Vale cada moeda de ouro!,,Merită fiecare bănuț!,Они того стоят!,,Värda varje guld!,Her altına değer! +"Come on, 200 gold!",TXT_RNO3_SCRIPT02_D12128_COMEO,,,,"No tak, 200 zlatých!","Kom nu, 200 guld!","Na komm, 200 Gold!",,"Nu, ili kostas 200 da oro.","Vamos, que son 200 de oro.",,"Antaa tulla, 200 kolikkoa!","Allez, 200 pièces!","Rajta, 200 arany!","Avanti, 200 pezzi d'oro!",頼むぜ、200ゴールドだぞ!,"이봐, 이건 200 골드라고!","Kom op, 200 goud!","Kom igjen, 200 gull!","No weź, 200 monet!","Vamos lá, 200 de ouro!",,"Haide, 200 monezi de aur!","Ну же, 200 золотых!",,"Kom igen, 200 guld!","Hadi, 200 altın!" +I can't believe that I got stuck with this duty. They say that something evil came up out of this sewer gate... Now I get to stand here until it comes up again!,TXT_DLG_SCRIPT02_D13644_ICANT,MAP02: Between governor's mansion and town hall.,,,"Nemůžu uvěřit, že jsem zkysnul s touhle prací. Řekli mi, že z téhle brány vylezlo něco zlého... A teď tady mám stát, dokud to znovu nevyleze!","Jeg kan ikke tro, at jeg blev sat til at have denne opgave. De siger, at noget ondt kom op af denne kloakport... Nu skal jeg stå her, indtil det kommer op igen!","Ich kann's nicht glauben dass ich diesen Dienst hier machen muss. Sie haben gesagt, dass etwas Böses aus dem Kanalisationstor gekommen ist... Nun muss ich hier stehen, bis es wieder kommt!",,"Mi ne povas kredi, ke mi estas blokita kun ĉi tiu tasko: Oni diras, ke malbonaĵo aperis el ĉi tiu pordo... kaj mi nun devas resti ĉi tie ĝis ĝi reaperos!",No puedo creer que haya quedado esclavizado con esta tarea: Dicen que algo maligno salió de esta compuerta... ¡y ahora tengo que quedarme aquí hasta que salga de nuevo!,,"Uskomatonta, että minulle tungettiin tämä tehtävä. Sanovat, että jokin paha nousi ylös tästä viemäriluukusta... Ja minä saan seistä tässä, kunnes se nousee jälleen!",J'arrive pas à croire que je me retrouve coincé ici. On me raconte qu'une chose maléfique est sortie de cette barrière des égouts.. Maintenant je me retrouve planté ici jusqu'a ce qu'elle revienne!,"Nem hiszem el, hogy én kaptam ezt a melót. Úgy hírlik, hogy valami gonosz bukkant fel itt a csatorna kapuja felől... Most addig fogok itt állni, amíg újra fel nem bukkan.",Non posso credere di aver accettato questo lavoro. Dicono che qualcosa di malvagio sia sbucato dalla chiusa delle fogne... E io devo stare qui finché non ritorna! ,"私がこの勤務で足止めとは信じられん。 皆が下水ゲートから悪しきものが来たと言う。 -再びドアが開くまで、ここで立ち往生だ!",내가 이 임무에 얽매였다는 게 믿기지 않아요. 사람들이 하수도 입구에서 뭔가 나타났다고 하던데... 이제 그게 다시 올 때까지 여기에서 서 있어야 한다니!,Ik kan niet geloven dat ik met deze plicht vast kwam te zitten. Ze zeggen dat er iets kwaadaardigs uit deze rioolpoort is gekomen.... Nu mag ik hier blijven staan tot het weer opduikt!,"Nie mogę uwierzyć, że zostałem z tym obowiązkiem. Mówią, że coś złego wyszło z tej bramy do kanałów... Teraz muszę tu stać aż się znów pojawi.",Não acredito que fiquei com essa tarefa. Dizem que algo horrível saiu dessa comporta de esgoto... Agora tenho que ficar aqui até que saia de novo!,,Nu-mi vine să cred că am rămas blocat cu meseria asta. Se zvonește că ceva malefic a ieșit la suprafată prin poarta canalului... Acum am ocazia să stau aici până se întoarce!,"Не могу поверить, что застрял на дежурстве. Они говорят, что какая-то пакость поднимается из этого люка... и теперь я должен стоять тут и ждать, пока она не появится снова!",Не могу да верујем да сам се заглавио на овој дужности. Кажу да је некакво зло изашло из те канализације... Сада морам да стојим овде док се опет не појави! -What gate?,TXT_RPLY0_SCRIPT02_D13644_WHATG,,,,Jaké brány?,Welches Tor?,,,¿Qué compuerta?,,,Quelle barrière?,Milyen Kapu?,Quale chiusa? ,何のゲートだ?,무슨 입구?,Welk hek?,Jakiej bramy?,Que comporta?,,Care poartă?,Какого люка?,Каква капија? -The sewer overflow gate.,TXT_RYES0_SCRIPT02_D13644_THESE,,,,Odpadní přepadové brány.,Das Überlauftor der Kanalisation.,,,La compuerta de desagüe de alcantarillado.,,,La barrière de débordement des égouts.,A csatorna kiárasztó kapuja.,La chiusa di contenimento delle fogne. ,下水道の溢水ゲートだ。,하수도 입구 말이에요.,Het riooloverloophek.,Bramy do kanałów.,A comporta de transborda de esgoto.,,Poarta de revărsare.,Канализационного люка.,Одводни канал за канализацију. -Hello friend. What can I get for you?,TXT_DLG_SCRIPT02_D15160_HELLO,,,,"Ahoj, příteli. Co pro tebe můžu udělat?","Hallo, Freund. Was darf es sein?",,,Saludos amigo. ¿Qué puedo ofrecerte?,,,"Bonjour mon ami, que puis-je faire pour vous?","Szervusz barátom, mit tehetnék érted?",Ehilà amico. Che posso prenderti? ,どうも同士よ。何か必要か?,안녕하십니까. 뭘 드릴까요?,Hallo vriend. Wat kan ik voor je halen?,Witaj kolego. Co mogę dla ciebie zrobić?,Olá amigo. Como posso ajudá-lo?,,Salut prietene. Ce pot să-ți aduc?,Здравствуй. Что-нибудь интересует?,Здраво пријатељу. Шта могу да учиним за тебе? -Electric bolts,TXT_RPLY0_SCRIPT02_D15160_ELECT,,,,Elektrické šípy,Elektrische Bolzen,,,Virotes eléctricos,,,Carreaux électriques,Elektromos nyilak.,Dardi elettrificati ,エレクトリックボルト,전격 볼트,Elektrische bouten,Elektryczne bełty,Setas elétricas,,Bolțuri electrice,Электрические болты,Електричне стреле -You got the electric bolts.,TXT_RYES0_SCRIPT02_D15160_YOUGO,,,,Tady máš své šípy.,Du hast die elektrischen Bolzen erhalten.,,,Obtuviste los virotes eléctricos.,,,Vous recevez les carreaux électriques.,Megkaptad az elektromos nyilakat.,Hai preso dei dardi elettrificati ,エレクトリックボルト 入手。,전격 볼트를 받았습니다.,Je hebt de elektrische bouten.,Masz elektryczne bełty.,Você pegou as setas elétricas,,Ai ridicat bolțurile electrice.,Вот твои электрические болты.,Добио си електричне стреле. -Ammo satchel,TXT_RPLY1_SCRIPT02_D15160_AMMOS,,,,Brašnu na munici,Munitionstasche,,,Bolsa de Municiones,,,Sacoche de Munitions,Lőszeres zsák.,Sacca di munizioni ,弾薬鞄,탄약 배낭,Munitie tasje,Torba z amunicją,Mochila de munição,,Sacoșă cu muniție,Ранец для боеприпасов,Торба за муницију -No. You don't have what I want for the electric bolts!,TXT_RNO0_SCRIPT02_D15160_NOYOU,,,,"Ne. Nemáš, co za ně chci!","Nein. Du hast nicht das, was ich für die elektrischen Pfeile haben möchte!",,,No. ¡No tienes lo que quiero por las saetas eléctricas!,,,"Non, vous n'avez pas ce qu'il me faut pour les carreaux électriques!","Nem. Neked nincs olyanod, ami nekem kéne az elektromos nyilakért.",No. Non hai quello che mi serve per i dardi elettrificati! ,いや。エレクトリックボルトに必要な物が足りない!,전격 볼트의 가격에 해당하는 게 전혀 없구먼!,Nee. Je hebt niet wat ik wil voor de elektrische bouten!,"Nie. Nie masz tego co ja chcę, by dać ci elektryczne bełty.",Não. Você não tem o que eu quero pelas setas elétricas!,,Nu. Nu ai ceea ce doresc pentru bolțurile electrice!,Нет. У тебя нет денег на электрические болты!,Не. Ти немаш шта мени треба за електричне стреле! -No. You don't have what I want for the electric bolts!,TXT_RNO0_SCRIPT02_D16676_NOYOU,,,,"Ne. Nemáš, co za ně chci!","Nein. Du hast nicht das, was ich für die elektrischen Pfeile haben möchte!",,,No. ¡No tienes lo que quiero por las saetas eléctricas!,,,"Non, vous n'avez pas ce qu'il me faut pour les carreaux électriques!","Nem. Neked nincs olyanod, ami nekem kéne az elektromos nyilakért.",No. Non hai quello che mi serve per i dardi elettrificati! ,いや。エレクトリックボルトに必要な物が足りない!,전격 볼트의 가격에 맞춰서 흥정하시길.,Nee. Je hebt niet wat ik wil voor de elektrische bouten!,"Nie. Nie masz tego co ja chcę, by dać ci elektryczne bełty.",Não. Você não tem o que eu quero pelas setas elétricas!,,Nu. Nu ai ceea ce doresc pentru bolțurile electrice!,Нет. У тебя нет денег на электрические болты!,Не. Ти немаш шта мени треба за електричне стреле! -Thank you. Anything else?,TXT_RYES1_SCRIPT02_D15160_THANK,,,,Děkuji. Něco dalšího?,Danke. Sonst noch etwas?,,,Gracias. ¿Algo más?,,,"Merci, Autre chose?",Köszönöm. Még valamit?,Grazie. Qualcos'altro? ,ありがとう。 他に何か?,감사합니다. 다른 건 없나요?,"Bedankt, nog iets anders?",Dziękuję. Coś jeszcze?,Obrigado. Mais alguma coisa?,,Mulțumesc. Mai dorești ceva?,Благодарю. Что-нибудь ещё?,Хвала. Још нешто? -"You can't afford that, good day.",TXT_RNO1_SCRIPT02_D15160_YOUCA,,,,"To si nemůžeš dovolit, přeji hezký den.",Das kannst du dir nicht leisten. Guten Tag.,,,"No puedes adquirir esto, buen día.",,,Vous n'avez pas assez d'argent. Bonne journée.,Ezt most nem tudod kifizetni. Szép napot!,Non puoi permettertelo. Buona giornata. ,それを買える余裕は無い、また今度。,가질 수가 없는 것 같으니... 그럼 이만!,"Dat kun je je je niet veroorloven, goede dag.","Nie możesz tego kupić, miłego dnia.",Você não pode comprar isso. Tenha um bom dia.,,Nu îți permiți asta. O zi bună.,У тебя не хватает денег. Всего доброго.,"Не можете то приуштити, довиђења." -What can I get for you?,TXT_DLG_SCRIPT02_D16676_WHATC,,,,Co bych ti mohl sehnat?,Was darf es sein?,,,¿Qué puedo ofrecerte?,,,Que puis-je faire pour vous?,Mivel szolgáhatok?,Cosa ti offro? ,何か必要か?,"무엇을 구매하고 싶으신가요, 좋은 친구여?",Wat kan ik voor je halen?,Co mogę dla ciebie zrobić?,Como posso te ajudar?,,Ce pot să-ți aduc?,Чем могу быть полезен?,Шта ти могу учинити? -Electric bolts,TXT_RPLY0_SCRIPT02_D16676_ELECT,,,,Elektrické šípy,Elektrische Bolzen,,,Saetas eléctricas,,,Carreaux électriques,Elektromos nyilak.,Dardi elettrificati ,エレクトリックボルト,전격 볼트,Elektrische bouten,Elektryczne bełty,Setas elétricas,,Bolțuri electrice,Электрические болты,Електричне стреле -You got the electric bolts.,TXT_RYES0_SCRIPT02_D16676_YOUGO,,,,Tady máš své šípy.,Du hast die elektrischen Bolzen erhalten.,,,Obtuviste las saetas eléctricas.,,,Vous recevez les carreaux électriques.,Elektromos nyilakra tettél szert.,Hai preso dei dardi elettrificati ,エレクトリックボルト 入手。,전격 볼트를 구매했습니다.,Je hebt de elektrische bouten.,Masz elektryczne bełty.,Você pegou as setas elétricas,,Ai ridicat bolțurile electrice.,Вот твои электрические болты.,Ево ти електричне стреле. -Ammo satchel,TXT_RPLY1_SCRIPT02_D16676_AMMOS,,,,Brašnu na munici,Munitionstasche,,,Bolsa de Municiones,,,Sacoche de Munitions,Lőszeres hátizsák,,弾薬鞄,탄약 배낭,Munitie tasje,Torba z amunicją,Mochila de munição,,Sacoșă cu muniție,Ранец для боеприпасов,Торба за муницију -"Thank you, anything else?",TXT_RYES1_SCRIPT02_D16676_THANK,,,,Děkuji. Něco dalšího?,Danke. Sonst noch etwas?,,,Gracias. ¿Algo más?,,,"Merci, Autre chose?","Köszönöm, bármi mást?",,ありがとう。 他に何か?,감사합니다. 다른 건 더 없나요?,"Bedankt, nog iets anders?","Dziękuję, coś jeszcze?",Obrigado. Mais alguma coisa?,,"Mulțumesc, mai dorești ceva?",Благодарю. Что-нибудь ещё?,"Хвала, још нешто?" -"You can't afford that, good day to you!",TXT_RNO1_SCRIPT02_D16676_YOUCA,,,,"To si nemůžeš dovolit, přeji hezký den.",Das kannst du dir nicht leisten. Guten Tag!,,,"No puedes adquirir esto, buen día.",,,Vous n'avez pas assez d'argent. Bonne journée.,"Nincs elég pénzed arra, további jó napot neked!",,それを買える余裕は無い、また今度。,살 돈이 부족하신가요? 그럼 갈 길 가시길!,"Dat kunt u zich niet veroorloven, een goede dag voor je!","Nie możesz tego kupić, życzę miłego dnia!",Você não pode comprar isso. Um bom dia pra você!,,Nu-ți poți permite asta. O zi bună îți doresc!,У тебя не хватает денег. Всего доброго!,"Не можете то приуштити, довиђења." -Welcome. What may I show you?,TXT_DLG_SCRIPT02_D18192_WELCO,,,,Vítej. Co bych ti mohl nabídnout?,Willkommen. Was kann ich dirZeigen.,,,Bienvenido. ¿Qué puedo mostrarte?,,,"Bienvenue, que souhaitez vous?",Üdvözletem! Mit is mutassak neked?,,ようこそ、何を見ていきますか?,환영합니다! 보여드릴 게 아주 많아요.,Welkom. Wat kan ik je laten zien?,"Witaj. Co mogę ci pokazać? -",Seja bem-vindo. O que posso te mostrar?,,Bun venit. Ce aș putea să-ți arăt?,Здравствуй. Что-нибудь интересует?,Добродошли. Шта вам могу показати? -Environmental suit,TXT_RPLY0_SCRIPT02_D18192_ENVIR,,,,Ochranný oblek,Schutzanzug.,,,Traje Ambiental,,,Combinaison hazmat,Természetálló öltözet,,耐環境スーツ,환경 방호복,Milieupak,Skafander Ochronny,Traje de proteção,,Costum de protecție,Защитный костюм,Заштитно одело -"Well, here you are.",TXT_RYES0_SCRIPT02_D18192_WELLH,,,,"Tak, tady to je.",Bitte sehr.,,,"Bien, aquí tienes.",,,Voilà pour vous.,"Nos, tessék.",,はい、これをどうぞ。,"자, 여기있습니다.","Nou, hier ben je dan.","Proszę, masz.","Muito bem, aqui está.",,Poftiți.,"Хорошо, бери.","Па, изволите." -I'm sorry but you don't have enough money for that.,TXT_RNO0_SCRIPT02_D18192_IMSOR,,,,"Promiň, ale na ten nemáš dost peněz.","Es tut mir Leid, aber du hast nicht genug Geld dabei.",,,"Lo siento, no tienes suficiente dinero para esto.",,,Je suis désolé mais vous n'avez pas assez d'argent.,"Sajnálom, de nincs elég pénzed erre.",,すみませんが、貴方は十分なお金を持っていません。,"죄송합니다만, 그걸 사기엔 돈이 부족해 보입니다.","Het spijt me, maar daar heb je niet genoeg geld voor.","Przepraszam, ale nie masz wystarczająco dużo monet, aby to kupić.",Sinto muito mas você não tem dinheiro o suficiente para isso.,,"Îmi pare rău, dar nu ai suficienți bani pentru asta.","Извини, но у тебя не хватает денег.",Жао ми је али немате довољно пара за то. -Leather armor,TXT_RPLY1_SCRIPT02_D18192_LEATH,,,Leather armour,Kožené brnění,Lederrüstung,,,Armadura de Cuero,,,Armure en cuir,Bőr páncél,,レザーアーマー,가죽 갑옷,Leren pantser,Skórzany Pancerz,Armadura de couro,,Armură din piele,Кожаная броня,Кожни оклоп -Here you are.,TXT_RYES1_SCRIPT02_D18192_HEREY,,,,Tady máš.,Bitte sehr.,,,Aquí tienes.,,,Voilà pour vous.,Tessék.,,これをどうぞ。,여기 있습니다.,Hier ben je dan.,Proszę bardzo.,Aqui está.,,Poftiți.,Держи.,Изволите. -Perhaps some other time?,TXT_RNO1_SCRIPT02_D18192_PERHA,,,,Možná někdy jindy?,Vielleicht ein anderes Mal?,,,¿Quizás en otra ocasión?,,,Peut être une autre fois?,Esetleg talán máskor?,,また別の機会に?,아마 나중에 사야 할 것 같은데?,Misschien een andere keer?,Może innym razem?,Talvez uma outra hora?,,Poate altădată?,"Может, в следующий раз?",Можда неки други пут? -Metal armor,TXT_RPLY2_SCRIPT02_D18192_METAL,,,Metal armour,Kovové brnění,Metallrüstung,,,Armadura de Metal,,,Armure en Métal,Fémpáncél,,メタルアーマー,강철 갑옷,Metalen harnas,Metalowy Pancerz,Armadura de metal,,Armură din metal,Металлическая броня,Метални оклоп -Wear it in good health.,TXT_RYES2_SCRIPT02_D18192_WEARI,,,,Nes ho ve zdraví.,Trage sie mit Stolz.,,,Úsala con buena salud.,,,Portez la en bonne santé.,Viseld jó egészséggel!,,着ると安心しますよ。,건강하게 입으세요.,Draag het in goede gezondheid.,Bądź zdrów nosząc go.,Vista ela com orgulho.,,Să o porți sănătos.,Носи на здоровье.,Носите га са добрим здрављем. -Come back when you can afford to buy something you lout!,TXT_RNO2_SCRIPT02_D18192_COMEB,,,,"Vrať se, až si budeš moct něco dovolit, troubo!","Komm zurück wenn du dir etwas leisten kannst, du Rüpel!",,,"¡Vuelve cuando puedas comprar algo, patán! ",,,"Revenez quand vous avez de l'argent, rustre!","Majd akkor gyere vissza, ha lesz pénzed megvenni bármit is, te fajankó!",,余裕がある時にまたどうぞ!,뭔가를 살 여유가 있을 때 오세요!,Kom terug wanneer je het je kunt veroorloven om iets te kopen wat je louteren kunt!,Wróć kiedy będziesz mógł coś kupić prostaku!,"Volte quando você puder comprar algo, seu caloteiro!",,"Revin-o când o să ai bani să poți cumpăra ceva, secătură!","Вернёшься, когда поднакопишь на то, что хочешь!",Врати се када будеш могао приуштити нешто што не знаш! -Welcome. What may I show you?,TXT_DLG_SCRIPT02_D19708_WELCO,,,,Vítej. Co bych ti mohl nabídnout?,Willkommen. Was kann ich dir zeigen.,,,Bienvenido. ¿Qué puedo mostrarte?,,,"Bienvenue, que souhaitez vous?","Üdvözlet, mire volnál kíváncsi?",,ようこそ、何をお探しで?,어서 오십시오. 어떤 걸 보여드릴까요?,Welkom. Wat kan ik je laten zien?,"Witaj. Co mogę ci pokazać? - -",Seja bem-vindo. O que posso te mostrar?,,Bun venit. Ce aș putea să-ți arăt?,Здравствуй. Что-нибудь интересует?,Добродошли. Шта вам могу показати? -Environmental suit,TXT_RPLY0_SCRIPT02_D19708_ENVIR,,,,Ochranný oblek,Schutzanzug.,,,Traje Ambiental,,,Combinaison hazmat,Természetálló öltözet,,耐環境スーツ,환경 방호복,Beschermend Pak,Skafander Ochronny,Traje de proteção,,Costum de protecție,Защитный костюм,Заштитно одело -"Well, here you are.",TXT_RYES0_SCRIPT02_D19708_WELLH,,,,"Tak, tady to je.",Bitte sehr.,,,"Bien, aquí tienes.",,,Voilà pour vous.,"Nos, íme.",,では、これをどうぞ。,"자, 여기 있습니다.","Nou, hier ben je dan.","Proszę, masz.","Muito bem, aqui está.",,Poftiți.,"Хорошо, бери.","Па, изволите." -I'm sorry but you don't have enough money for that.,TXT_RNO0_SCRIPT02_D19708_IMSOR,,,,"Promiň, ale na ten nemáš dost peněz.","Es tut mir Leid, aber du hast nicht genug Geld dabei.",,,"Lo siento, no tienes suficiente dinero para esto.",,,Je suis désolé mais vous n'avez pas assez d'argent.,"Sajnálom, de Önnek nem áll módjában kifizetni ezt.",,すみませんが、貴方は十分なお金を持っていません。,"미안하지만, 구매하기 위한 돈이 부족하신 것 같군요.","Het spijt me, maar daar heb je niet genoeg geld voor.","Przepraszam, ale nie masz wystarczająco dużo monet, aby to kupić.",Sinto muito mas você não tem dinheiro o suficiente para isso.,,"Îmi pare rău, dar nu ai suficienți bani pentru asta.","Извини, но у тебя не хватает денег.",Извините али немате довољно пара за то. -Leather armor,TXT_RPLY1_SCRIPT02_D19708_LEATH,,,Leather armour,Kožené brnění,Lederrüstung,,,Armadura de Cuero,,,Armure en cuir,Bőr páncél,,レザーアーマー,가죽 갑옷,Leren harnas,Skórzany Pancerz,Armadura de couro,,Armură din piele,Кожаная броня,Кожни оклоп -Here you are.,TXT_RYES1_SCRIPT02_D19708_HEREY,,,,Tady máš.,Bitte sehr.,,,Aquí tienes.,,,Voilà pour vous.,Tessék,,これをどうぞ。,여기 있습니다.,Hier ben je dan.,Proszę bardzo.,Aqui está.,,Poftiți.,Держи.,Изволите -Perhaps some other time?,TXT_RNO1_SCRIPT02_D19708_PERHA,,,,Možná někdy jindy?,Vielleicht ein anderes Mal?,,,¿Quizás en otra ocasión?,,,Peut être une autre fois?,Talán majd máskor?,,また別の機会に?,나중에 돈을 모아서 구매하세요.,Misschien een andere keer?,Może innym razem?,Talvez uma outra hora?,,Poate altădată?,"Может, в следующий раз?",Можда неки други пут? -Metal armor,TXT_RPLY2_SCRIPT02_D19708_METAL,,,Metal armour,Kovové brnění,Metallrüstung,,,Armadura de Metal,,,Armure en Métal,Fém páncél,,メタルアーマー,강철 갑옷,Metalen harnas,Metalowy Pancerz,Armadura de metal,,Armură din metal,Металлическая броня,Метални оклоп -Wear it in good health.,TXT_RYES2_SCRIPT02_D19708_WEARI,,,,Nes ho ve zdraví.,Trage sie mit Stolz.,,,Úsala con buena salud.,,,Portez la en bonne santé.,Viseld jó egészséggel!,,着ると安心しますよ。,믿고 입으셔도 됩니다.,Draag het in goede gezondheid.,Bądź zdrów nosząc go.,Vista ela com orgulho.,,Să o porți sănătos.,Носи на здоровье.,Носите га са добрим здрављем. -Come back when you can afford to buy something you lout!,TXT_RNO2_SCRIPT02_D19708_COMEB,,,,"Vrať se, až si budeš moct něco dovolit, troubo!","Komm zurück wenn du dir etwas leisten kannst, du Rüpel!",,,"¡Vuelve cuando puedas comprar algo, patán! ",,,"Revenez quand vous avez de l'argent, rustre!","Majd akkor gyere vissza, ha lesz pénzed megvenni bármit is, te fajankó!",,余裕がある時にまたどうぞ!,이런 거래는 못 하겠습니다. 돈을 모아서 다시 찾아오시길!,Kom terug wanneer je het je kunt veroorloven om iets te kopen wat je louteren kunt!,Wróć kiedy będziesz mógł coś kupić prostaku!,"Volte quando você puder comprar algo, seu caloteiro!",,"Revin-o când o să ai bani să poți cumpăra ceva, secătură!","Вернёшься, когда поднакопишь на то, что хочешь!",Врати се када будеш могао приуштити нешто што не знаш! -How may I assist you?,TXT_DLG_SCRIPT02_D21224_HOWMA,,,,Jak ti mohu pomoci?,Wie kann ich dir helfen?,,,¿Cómo puedo ayudarte?,,,Comment puis-je vous assister?,Hogyan tudnék segíteni neked?,,何かお困りですか?,제가 어떻게 도와드릴까요?,Hoe kan ik u helpen?,Jak mogę ci pomóc?,Como posso ajudá-lo?,,Cu ce vă pot ajuta?,Чем могу помочь?,Како вам могу помоћи? -Med patch,TXT_RPLY0_SCRIPT02_D21224_MEDPA,,,,Obvazy,Medizinische Bandage,,,Parche Médico,,,Pansement,Ragtapasz,,医薬パッチ,의료 붕대,Med-patch,Bandaż,Compressa médica,,Trusă de Prim-Ajutor,Бинтами,Фластери -Here's your patch.,TXT_RYES0_SCRIPT02_D21224_HERES,,,,Tady je tvůj obvaz.,Hier ist deine Bandage,,,Aquí tienes tu parche.,,,Voilà votre pansement.,Itt a tapaszod,,これをどうぞ。,의료 붕대 여깄습니다.,Hier is je patch.,Oto twój bandaż.,Aqui está sua compressa,,Poftiți trusa.,Вот они.,Ево ваших фластера -You need 10 gold for that.,TXT_RNO0_SCRIPT02_D21224_YOUNE,,,,Na ty potřebuješ deset zlatých.,Dafür brauchst du 10 Gold.,,,Necesitarás 10 de oro para esto.,,,Il vous faut 10 pièces pour cela.,10 Aranyra lesz szükséged ehhez.,,10 ゴールド必要です。,10 골드가 필요합니다.,Daar heb je 10 goud voor nodig.,Potrzebujesz 10 monet aby to kupić.,Você precisa de 10 de ouro pra isso.,,Ai nevoie de 10 monezi de aur pentru asta.,Тебе не хватает 10 золотых.,Треба вам 10 златника за то. -Medical kit,TXT_RPLY1_SCRIPT02_D21224_MEDIC,,,,Lékárničku,Verbandskasten,,,Kit Médico,,,Kit médical,Elsősegély készlet,,医療用キット,구급 키트,Medische kit,Apteczka,Kit médico.,,Kit de Prim-Ajutor,Аптечкой,Медицински комплет -Thank you.,TXT_RYES1_SCRIPT02_D21224_THANK,,,,Děkuji.,Danke.,,,Gracias.,,,Merci.,Köszönöm,,ありがとうございます。,이용 감사드려요.,Bedankt.,Dziękuję.,Obrigado.,,Mulțumesc.,Спасибо.,Хвала. -"I wish I could give them away, but they cost 25 gold.",TXT_RNO1_SCRIPT02_D21224_IWISH,,,,"Přál bych si je dávat zadarmo, ale stojí 25 zlatých.","Ich wünschte ich könnte sie weggeben, aber sie kosten 25 Gold.",,,"Ojalá pudiera regalarlos, pero cuestan 25 de oro.",,,"J'aimerais vraiment les donner gratuitement, mais cela côute 25 pièces.",,,譲渡したい所ですが、25 ゴールド必要です。,"주고 싶지만, 이것의 가격은 25 골드입니다.","Ik wou dat ik ze kon weggeven, maar ze kosten 25 goud.","Chciałbym móc je rozdać, ale one kosztują 25 monet.","Bem que eu queria poder dar de graça, mas custam 25 de ouro.",,"Mi-aș dori să le pot da pe gratis, dar costă 25 de monezi de aur.","С радостью бы отдал, но они по 25 золотых.","Волео бих да их могу дати, али коштају 25 златника." -Field surgery kit,TXT_RPLY2_SCRIPT02_D21224_FIELD,,,,Chirurgickou soupravu,Erste-Hilfe-Kasten,,,Kit Quirúrgico,,,Kit de chirurgie,Harctéri műtéti felszerelés,,手術キット,수술 키트,Veld chirurgie kit,Polowy zestaw chirurga,Kit de cirurgia,,Trusă de chirurgie de teren,Медкомплектом,Комплет за операцију на терену -There you go. Take care now.,TXT_RYES2_SCRIPT02_D21224_THERE,,,,Tady máš. Buď opatrný.,Bitte schön. Mach's gut.,,,Aquí tienes. Cuídate.,,,Voilà pour vous. Faites attention à vous maintenant.,"Tessék, minden jót most már!",,こちらになります、お気をつけて。,여기 있습니다. 잘 쓰세요.,Daar ga je. Pas goed op jezelf.,Proszę bardzo. Trzymaj się.,Aqui está. Se cuida.,,Poftiți. Aveți grijă.,Пожалуйста. Береги себя!,Изволите. Чувајте се. -"Well, maybe you can afford some med patches?",TXT_RNO2_SCRIPT02_D21224_WELLM,,,,"No, možná by sis mohl spíš dovolit nějaké obvazy?","Nun, vielleicht kannst du dir ein paar medizinische Bandagen leisten?",,,"Bien, ¿Quizás te alcance para algunos parches médicos?",,,"Eh bien, peut être que vous pouvez vous acheter quelques pansements?",Talán némi ragtapaszra tudnál költeni?,,ところで、医薬パッチを買う余裕はありますか?,"글쎄요, 아마 의료 붕대 정돈 살 수 있을걸요?","Nou ja, misschien kunt je zich wat med-patches veroorloven?","Cóż, może stać cię na jakieś bandaże?","Bem, talvez você possa comprar algumas compressas?",,"Păi, poate îți permiți niște truse de prim-ajutor?","Тогда, может быть, купишь несколько бинтов?","Па, можда бих могао приуштити фластере?" -"I hope Macil knows what he's doing. If the Order finds out I'm helping the Front I'm as good as dead... Not that this matters to you any. The Front's medic gave me an upgrade chip for you, are you ready? ",TXT_DLG_SCRIPT02_D22740_IHOPE,,,,"Doufám, že Macil ví, co dělá. Jestli Řád zjistí, že pomáhám Frontě, jsem mrtvý... Ne, že by tě to mělo trápit. Medik Fronty mi pro tebe dal vylepšovací čip, jsi připravený?","Ich hoffe Macil weiß was er tut. Wenn der Orden herausfindet das ich der Front helfe, bin ich so gut wie tot... auch wenn es für dich keine Rolle spielt. Ein Sanitäter der Front hat mir einen Verbesserungschip für dich mitgegeben, bist du bereit?",,,"Espero que Macil sepa lo que está haciendo. Si la Orden descubre que ayudo al Frente, estoy muerto... Tampoco es que te importe nada. El médico del Frente me dio un chip para ti, ¿Estás listo?",,,"J'espère que Macil sait ce qu'il fait. Si l'Ordre se rend compte que j'aide le Front, c'est comme si j'étais mort.. bon, cela ne vous importe pas. Le médecin du Front m'a donné une puce d'augmentation pour vous. Etes vous prêt?","Remélem Macil tudja, mit csinál. Ha a Rend rájön, hogy a Frontot segítem, alulról szagolom majd az ibolyát. Nem mintha ez neked most lényeges lenne. A Front orvosa egy fejlesztési chipet küldött neked. Készen állsz?",,"マシルの行いが正しければ良いですが。 +再びドアが開くまで、ここで立ち往生だ!",내가 이 임무에 얽매였다는 게 믿기지 않아요. 사람들이 하수도 입구에서 뭔가 나타났다고 하던데... 이제 그게 다시 올 때까지 여기에서 서 있어야 한다니!,Ik kan niet geloven dat ik met deze plicht vast kwam te zitten. Ze zeggen dat er iets kwaadaardigs uit deze rioolpoort is gekomen.... Nu mag ik hier blijven staan tot het weer opduikt!,Jeg kan ikke tro at jeg ble sittende fast med denne plikten. De sier at noe ondt kom opp av denne kloakkporten... Nå må jeg stå her til det kommer opp igjen!,"Nie mogę uwierzyć, że zostałem z tym obowiązkiem. Mówią, że coś złego wyszło z tej bramy do kanałów... Teraz muszę tu stać aż się znów pojawi.",Não acredito que fiquei com essa tarefa. Dizem que algo horrível saiu dessa comporta de esgoto... Agora tenho que ficar aqui até que saia de novo!,,Nu-mi vine să cred că am rămas blocat cu meseria asta. Se zvonește că ceva malefic a ieșit la suprafată prin poarta canalului... Acum am ocazia să stau aici până se întoarce!,"Не могу поверить, что застрял на дежурстве. Они говорят, что какая-то пакость поднялась из этого люка... и теперь я должен стоять тут и ждать, пока она не появится снова!",,Jag kan inte fatta att jag fick den här uppgiften. Det sägs att något ondskefullt kom upp ur den här kloakporten... Nu får jag stå här tills det kommer upp igen!,Bu görevin bana kaldığına inanamıyorum. Bu kanalizasyon kapısından kötü bir şeyin çıktığını söylüyorlar. Şimdi o şey tekrar ortaya çıkana kadar burada duracağım! +What gate?,TXT_RPLY0_SCRIPT02_D13644_WHATG,〃,,,Jaké brány?,Hvilken port?,Welches Tor?,,Kio estas post la pordo?,¿De qué es la compuerta?,,Mikä luukku?,Quelle barrière?,Milyen Kapu?,Quale chiusa? ,何のゲートだ?,무슨 입구?,Welk hek?,Hvilken port?,Jakiej bramy?,Que comporta?,,Care poartă?,Какого люка?,,Vilken port?,Ne kapısı? +The sewer overflow gate.,TXT_RYES0_SCRIPT02_D13644_THESE,〃,,,Odpadní přepadové brány.,Kloakoverløbsporten.,Das Überlauftor der Kanalisation.,,"La elflua truo +de la kloako.",Del pozo de la red cloacal.,,Viemärin ylivuotoluukku.,La barrière de débordement des égouts.,A csatorna kiárasztó kapuja.,La chiusa di contenimento delle fogne. ,下水道の溢水ゲートだ。,하수도 입구 말이에요.,Het riooloverloophek.,Kloakkoverløpsporten.,Bramy do kanałów.,A comporta de transborda de esgoto.,,Poarta de revărsare.,Канализационного люка перелива.,,Kloakens överflödsgrind.,Kanalizasyon taşma kapısı. +Hello friend. What can I get for you?,TXT_DLG_SCRIPT02_D15160_HELLO,MAP02: Weapons.,,,"Zdravím, příteli. Co pro vás můžu udělat?","Hej, min ven. Hvad kan jeg hjælpe dig med?","Hallo, Freund. Was darf es sein?",,"Saluton, amiko. Kion mi donu al vi?","Saludos, amigo. ¿Qué puedo ofrecerte?",,"Tervehdys, ystävä. Mitä saisi olla?","Bonjour mon ami, que puis-je faire pour vous?","Szervusz barátom, mit tehetnék érted?",Ehilà amico. Che posso darti? ,どうも同士よ。何か必要か?,안녕하십니까. 뭘 드릴까요?,Hallo vriend. Wat kan ik voor je halen?,"Hallo, min venn. Hva vil du ha?",Witaj kolego. Co mogę dla ciebie zrobić?,"Olá, amigo. Como posso ajudá-lo?",,Salut prietene. Ce pot să-ți aduc?,Здравствуй. Что-нибудь интересует?,,"Hej, min vän. Vad kan jag ge dig?",Merhaba dostum. Senin için ne yapabilirim? +Electric bolts,TXT_RPLY0_SCRIPT02_D15160_ELECT,〃,,,Elektrické šípy,Elektriske bolte,Elektrische Bolzen,,Elektrajn sagojn,Flechas eléctricas,,Sähkönuolia,Carreaux électriques,Elektromos nyilak.,Dardi elettrificati ,エレクトリックボルト,전격 볼트,Elektrische bouten,Elektriske bolter.,Elektryczne bełty,Setas elétricas,,Bolțuri electrice,Электрические болты,,Elektriska bultar,Elektrikli cıvata. +You got the electric bolts.,TXT_RYES0_SCRIPT02_D15160_YOUGO,〃,,,Tady je máte.,Du fik de elektriske bolte.,Du hast die elektrischen Bolzen erhalten.,,Jen la sagoj.,Aquí están las flechas.,,Sait sähkönuolet.,Vous recevez les carreaux électriques.,Megkaptad az elektromos nyilakat.,Hai preso dei dardi elettrificati ,エレクトリックボルト 入手。,전격 볼트를 받았습니다.,Je hebt de elektrische bouten.,Du har de elektriske boltene.,Masz elektryczne bełty.,Você pegou as setas elétricas,,Ai ridicat bolțurile electrice.,Вот твои электрические болты.,,Du fick elektriska bultar.,Elektrikli cıvatalar sende. +Ammo satchel,TXT_RPLY1_SCRIPT02_D15160_AMMOS,〃,,,Brašnu na munici,Ammotaske,Munitionstasche,,Sako da municioj,Bolso de municiones,,Ammusreppu,Sacoche de Munitions,Lőszeres táska.,Sacca di munizioni ,弾薬鞄,탄약 배낭,Munitie tasje,Ammunisjonsveske,Torba z amunicją,Mochila de munição,,Sacoșă cu muniție,Ранец боеприпасов,,Ammunitionsväska,Cephane çantası +No. You don't have what I want for the electric bolts!,TXT_RNO0_SCRIPT02_D15160_NOYOU,〃,,,"Ne. Nemáte, co za ně chci!","Nej. Du har ikke det, jeg vil have for de elektriske bolte!","Nein. Du hast nicht das, was ich für die elektrischen Pfeile haben möchte!",,"Ne, vi ne havas tiom, +kiom mi petas.","No, no tienes lo que pido.",,"Ei. Sinulla ei ole, mitä haluan sähkönuolista!","Non, vous n'avez pas ce qu'il me faut pour les carreaux électriques!","Nem. Neked nincs olyanod, ami nekem kéne az elektromos nyilakért.",No. Non hai quello che mi serve per i dardi elettrificati! ,いや。エレクトリックボルトに必要な物が足りない!,전격 볼트의 가격에 해당하는 게 전혀 없구먼!,Nee. Je hebt niet wat ik wil voor de elektrische bouten!,Nei. Du har ikke det jeg vil ha for de elektriske boltene!,"Nie. Nie masz tego co ja chcę, by dać ci elektryczne bełty.",Não. Você não tem o que eu quero pelas setas elétricas!,,Nu. Nu ai ceea ce doresc pentru bolțurile electrice!,Нет. У тебя нет денег на электрические болты!,,"Nej, du har inte det jag vill ha för elbultarna!",Hayır. Elektrikli cıvatalar için istediğim şey sizde yok! +No. You don't have what I want for the electric bolts!,TXT_RNO0_SCRIPT02_D16676_NOYOU,〃,,,"Ne. Nemáte, co za ně chci!","Nej. Du har ikke det, jeg vil have til de elektriske bolte!","Nein. Du hast nicht das, was ich für die elektrischen Pfeile haben möchte!",,"Ne, vi ne havas tiom, +kiom mi petas.","No, no tienes lo que pido.",,"Ei. Sinulla ei ole, mitä haluan sähkönuolista!","Non, vous n'avez pas ce qu'il me faut pour les carreaux électriques!","Nem. Neked nincs olyanod, ami nekem kéne az elektromos nyilakért.",No. Non hai quello che mi serve per i dardi elettrificati! ,いや。エレクトリックボルトに必要な物が足りない!,전격 볼트의 가격에 맞춰서 흥정하시길.,Nee. Je hebt niet wat ik wil voor de elektrische bouten!,Nei. Du har ikke det jeg vil ha for de elektriske boltene!,"Nie. Nie masz tego co ja chcę, by dać ci elektryczne bełty.",Não. Você não tem o que eu quero pelas setas elétricas!,,Nu. Nu ai ceea ce doresc pentru bolțurile electrice!,Нет. У тебя нет денег на электрические болты!,,"Nej, du har inte det jag vill ha för elbultarna!",Hayır. Elektrikli cıvatalar için istediğim şey sizde yok! +Thank you. Anything else?,TXT_RYES1_SCRIPT02_D15160_THANK,〃,,,Děkuji. Něco dalšího?,Tak. Er der andet?,Danke. Sonst noch etwas?,,Dankon. Ĉu ion alian?,Gracias. ¿Algo más?,,Kiitos. Jotain muuta?,"Merci, Autre chose?",Köszönöm. Még valamit?,Grazie. Qualcos'altro? ,ありがとう。 他に何か?,감사합니다. 다른 건 없나요?,"Bedankt, nog iets anders?",Takk skal du ha. Var det noe mer?,Dziękuję. Coś jeszcze?,Agradeço. Mais alguma coisa?,,Mulțumesc. Mai dorești ceva?,Благодарю. Что-нибудь ещё?,,Tack. Något annat?,Teşekkür ederim. Başka bir şey var mı? +"You can't afford that, good day.",TXT_RNO1_SCRIPT02_D15160_YOUCA,〃,,,"To si nemůžete dovolit, přeji hezký den.","Det har du ikke råd til, god dag.",Das kannst du dir nicht leisten. Guten Tag.,,"Vi ne povas sen mono. +Havu bonan tagon!","No te alcanza. +¡Ten un buen día!",,"Sinulla ei ole siihen varaa, hyvää päivänjatkoa.",Vous n'avez pas assez d'argent. Bonne journée.,Ezt most nem tudod kifizetni. Szép napot!,Non puoi permettertelo. Buona giornata. ,それを買える余裕は無い、また今度。,가질 수가 없는 것 같으니... 그럼 이만!,"Dat kun je je je niet veroorloven, goede dag.","Det har du ikke råd til, adjø.","Nie możesz tego kupić, miłego dnia.",Você não pode comprar isso. Tenha um bom dia.,,Nu îți permiți asta. O zi bună.,У тебя не хватает денег. Всего доброго.,,"Du har inte råd med det, god dag.","Bunu karşılayamazsınız, iyi günler." +What can I get for you?,TXT_DLG_SCRIPT02_D16676_WHATC,〃,,,Co vám mohu nabídnout?,Hvad kan jeg skaffe til dig?,Was darf es sein?,,Kion mi donu al vi?,¿Qué puedo ofrecerte?,,Mitä saisi olla?,Que puis-je faire pour vous?,Mivel szolgáhatok?,Che cosa posso darti? ,何か必要か?,"무엇을 구매하고 싶으신가요, 좋은 친구여?",Wat kan ik voor je halen?,Hva vil du ha?,Co mogę dla ciebie zrobić?,Como posso te ajudar?,,Ce pot să-ți aduc?,Чем могу быть полезен?,,Vad kan jag ge dig?,Sizin için ne alabilirim? +Electric bolts,TXT_RPLY0_SCRIPT02_D16676_ELECT,〃,,,Elektrické šípy,Elektriske bolte,Elektrische Bolzen,,Elektrajn sagojn,Flechas eléctricas,,Sähkönuolia,Carreaux électriques,Elektromos nyilak.,Dardi elettrificati ,エレクトリックボルト,전격 볼트,Elektrische bouten,Elektriske bolter.,Elektryczne bełty,Setas elétricas,,Bolțuri electrice,Электрические болты,,Elektriska bultar,Elektrikli cıvatalar. +You got the electric bolts.,TXT_RYES0_SCRIPT02_D16676_YOUGO,〃,,,Tady je máte.,Du fik de elektriske bolte.,Du hast die elektrischen Bolzen erhalten.,,Jen la sagoj.,Aquí están las flechas.,,Sait sähkönuolet.,Vous recevez les carreaux électriques.,Elektromos nyilakra tettél szert.,Hai preso dei dardi elettrificati ,エレクトリックボルト 入手。,전격 볼트를 구매했습니다.,Je hebt de elektrische bouten.,Du har elektriske bolter.,Masz elektryczne bełty.,Você pegou as setas elétricas,,Ai ridicat bolțurile electrice.,Вот твои электрические болты.,,Du har elektriska bultar.,Elektrikli cıvatalar sende. +Ammo satchel,TXT_RPLY1_SCRIPT02_D16676_AMMOS,〃,,,Brašnu na munici,Ammotaske.,Munitionstasche,,Sako da municioj,Bolso de municiones,,Ammusreppu,Sacoche de Munitions,Lőszeres hátizsák,Sacca di munizioni ,弾薬鞄,탄약 배낭,Munitie tasje,Ammunisjonsveske.,Torba z amunicją,Mochila de munição,,Sacoșă cu muniție,Ранец боеприпасов,,Ammunitionsväska,Cephane çantası +"Thank you, anything else?",TXT_RYES1_SCRIPT02_D16676_THANK,〃,,,Děkuji. Něco dalšího?,"Tak, andet?",Danke. Sonst noch etwas?,,Dankon. Ĉu ion alian?,Gracias. ¿Algo más?,,Kiitos. Jotain muuta?,"Merci, Autre chose?","Köszönöm, bármi mást?","Grazie, ti serve qualcos'altro?",ありがとう。 他に何か?,감사합니다. 다른 건 더 없나요?,"Bedankt, nog iets anders?","Takk, noe mer?","Dziękuję, coś jeszcze?",Agradeço. Mais alguma coisa?,,"Mulțumesc, mai dorești ceva?",Благодарю. Что-нибудь ещё?,,"Tack, något annat?","Teşekkürler, başka bir şey var mı?" +"You can't afford that, good day to you!",TXT_RNO1_SCRIPT02_D16676_YOUCA,〃,,,"To si nemůžete dovolit, přeji hezký den.","Det har du ikke råd til, god dag til dig!",Das kannst du dir nicht leisten. Guten Tag!,,"Vi ne povas sen mono. +Havu bonan tagon!","No te alcanza. +¡Ten un buen día!",,"Sinulla ei ole siihen varaa, hyvää päivänjatkoa.",Vous n'avez pas assez d'argent. Bonne journée.,"Nincs elég pénzed arra, további jó napot neked!",Non puoi permettertelo. Buona giornata a te!,それを買える余裕は無い、また今度。,살 돈이 부족하신가요? 그럼 갈 길 가시길!,"Dat kunt u zich niet veroorloven, een goede dag voor je!","Det har du ikke råd til, ha en god dag!","Nie możesz tego kupić, życzę miłego dnia!",Você não pode comprar isso. Um bom dia pra você!,,Nu-ți poți permite asta. O zi bună îți doresc!,У тебя не хватает денег. Всего доброго!,,"Du har inte råd med det, god dag till dig!","Bunu karşılayamazsınız, size iyi günler!" +Welcome. What may I show you?,TXT_DLG_SCRIPT02_D18192_WELCO,MAP02: Armory.,,,Vítejte. Co vám mohu nabídnout?,Velkommen. Hvad må jeg vise dig?,Willkommen. Was kann ich dirZeigen.,,Bonvenon. Kion mi montru al vi?,Bienvenido. ¿Qué te muestro?,,Tervetuloa. Mitä haluaisitte vilkaista?,"Bienvenue, que souhaitez vous?",Üdvözletem! Miben segíthetek?,Benvenuto. Cosa posso mostrarti?,ようこそ、何を見ていきますか?,환영합니다! 보여드릴 게 아주 많아요.,Welkom. Wat kan ik je laten zien?,Velkommen. Hva kan jeg vise deg?,"Witaj. Co mogę ci pokazać? +",Saudações. O que posso te mostrar?,,Bun venit. Ce aș putea să-ți arăt?,Здравствуй. Что-нибудь интересует?,,Välkommen. Vad får jag visa dig?,Hoş geldiniz. Size ne gösterebilirim? +Environmental suit,TXT_RPLY0_SCRIPT02_D18192_ENVIR,〃,,,Ochranný oblek,Miljødragt,Schutzanzug.,,Medi-ŝirman veston,Traje NBQ,,Ympäristösuojapuku,Combinaison hazmat,Természetálló öltözet,Tuta ambientale,耐環境スーツ,환경 방호복,Milieupak,Miljødrakt,Skafander Ochronny,Traje de proteção,,Costum de protecție,Защитный костюм,,Miljödräkt,Çevre kıyafeti. +"Well, here you are.",TXT_RYES0_SCRIPT02_D18192_WELLH,〃,,,"Tak, tady to je.","Nå, værsgo.",Bitte sehr.,,"Nu, jen.","Bueno, toma.",,"Kas tässä, olkaa hyvä.",Voilà pour vous.,"Nos, tessék.","Bene, ecco a te.",はい、これをどうぞ。,"자, 여기있습니다.","Nou, hier ben je dan.",Vær så god.,"Proszę, masz.","Muito bem, aqui está.",,Poftiți.,"Хорошо, бери.",,"Ja, här är du.",İşte buradasın. +I'm sorry but you don't have enough money for that.,TXT_RNO0_SCRIPT02_D18192_IMSOR,〃,,,"Promiňte, ale na ten nemáte dost peněz.","Jeg beklager, men du har ikke penge nok til det.","Es tut mir Leid, aber du hast nicht genug Geld dabei.",,"Pardonon, sed vi ne +havas sufiĉe da mono.","Lo siento, pero no te alcanza.",,Valitettavasti teillä ei ole siihen riittävästi rahaa.,Je suis désolé mais vous n'avez pas assez d'argent.,"Sajnálom, de nincs elég pénzed erre.","Mi spiace, ma non hai abbastanza soldi per questo.",すみませんが、貴方は十分なお金を持っていません。,"죄송합니다만, 그걸 사기엔 돈이 부족해 보입니다.","Het spijt me, maar daar heb je niet genoeg geld voor.","Beklager, men du har ikke nok penger til det.","Przepraszam, ale nie masz wystarczająco dużo monet, aby to kupić.","Sinto muito, mas você não tem dinheiro suficiente para isso.",,"Îmi pare rău, dar nu ai suficienți bani pentru asta.","Извини, но у тебя не хватает денег.",,Jag är ledsen men du har inte tillräckligt med pengar för det.,Üzgünüm ama bunun için yeterli paranız yok. +Leather armor,TXT_RPLY1_SCRIPT02_D18192_LEATH,〃,,Leather armour,Kožené brnění,Læderrustning,Lederrüstung,,Ledan armaĵon,Armadura de cuero,,Nahkasuojus,Armure en cuir,Bőr páncél,Armatura di cuoio,レザーアーマー,가죽 갑옷,Leren pantser,Skinnpanser,Skórzany Pancerz,Armadura de couro,,Armură din piele,Кожаная броня,,Läderrustning,Deri zırh +Here you are.,TXT_RYES1_SCRIPT02_D18192_HEREY,〃,,,Tady máte.,Værsgo.,Bitte sehr.,,Jen.,Toma.,,"Tässä, olkaa hyvä.",Voilà pour vous.,Tessék.,Ecco qua.,これをどうぞ。,여기 있습니다.,Hier ben je dan.,Vær så god.,Proszę bardzo.,Aqui está.,,Poftiți.,Держи.,,Här har du.,Buyurun. +Perhaps some other time?,TXT_RNO1_SCRIPT02_D18192_PERHA,〃,,,Možná někdy jindy?,Måske en anden gang?,Vielleicht ein anderes Mal?,,Ĉu eble alian fojon?,¿Quizás en otra ocasión?,¿Tal vez en otra ocasión?,Ehkä joskus toiste?,Peut être une autre fois?,Esetleg talán máskor?,"Magari un'altra volta, va bene?",また別の機会に?,아마 나중에 사야 할 것 같은데?,Misschien een andere keer?,Kanskje en annen gang?,Może innym razem?,Talvez uma outra hora?,,Poate altădată?,"Может, в следующий раз?",,Kanske en annan gång?,Belki başka bir zaman? +Metal armor,TXT_RPLY2_SCRIPT02_D18192_METAL,〃,,Metal armour,Kovové brnění,Metal rustning,Metallrüstung,,Metalan armaĵon,Armadura de metal,,Metallihaarniska,Armure en Métal,Fémpáncél,Armatura di metallo,メタルアーマー,강철 갑옷,Metalen harnas,Metall rustning,Metalowy Pancerz,Armadura de metal,,Armură din metal,Металлическая броня,,Metallrustning,Metal zırh +Wear it in good health.,TXT_RYES2_SCRIPT02_D18192_WEARI,"〃 +(in good health = enjoy)",,,Noste jej ve zdraví.,Bær den ved godt helbred.,Trage sie mit Stolz.,,Ĝuu ĝin.,Disfrútala.,,Kaikin voimin pukeutukaa.,Portez la bien.,Viseld jó egészséggel!,Che possa esserti utile!,着ると安心しますよ。,건강하게 입으세요.,Draag het in goede gezondheid.,Bruk den med god helse.,Bądź zdrów nosząc go.,Vista ela com orgulho.,,Să o porți sănătos.,Носи на здоровье.,,Bär den vid god hälsa.,Sağlıkla giy. +Come back when you can afford to buy something you lout!,TXT_RNO2_SCRIPT02_D18192_COMEB,〃,,,"Vrať se, až si budeš moct něco dovolit, troubo!","Kom tilbage, når du har råd til at købe noget, din slyngel!","Komm zurück wenn du dir etwas leisten kannst, du Rüpel!",,"Revenu kiam vi povos +aĉeti ion, stultulo!","¡Vuelve cuando puedas +comprar algo, zopenco! ",,"Palataan asiaan, kun teidän on mahdollista ostaa jotain himoitsemaanne.","Revenez quand vous avez de l'argent, rustre!","Majd akkor gyere vissza, ha lesz pénzed megvenni bármit is, te fajankó!","Ritorna quando potrai permetterti di comprare le cose, cafone!",余裕がある時にまたどうぞ!,뭔가를 살 여유가 있을 때 오세요!,Kom terug wanneer je het je kunt veroorloven om iets te kopen wat je louteren kunt!,"Kom tilbake når du har råd til å kjøpe noe, din lømmel!",Wróć kiedy będziesz mógł coś kupić prostaku!,"Volte quando você puder comprar algo, seu caloteiro!",,"Revin-o când o să ai bani să poți cumpăra ceva, secătură!","Возвращайся, когда сможешь позволить себе купить что-нибудь, придурок!",,"Kom tillbaka när du har råd att köpa något, din tölp!",Bir şeyler almaya gücün yettiğinde geri gel! +Welcome. What may I show you?,TXT_DLG_SCRIPT02_D19708_WELCO,,,,Vítejte. Co vám mohu nabídnout?,Velkommen. Hvad må jeg vise dig?,Willkommen. Was kann ich dir zeigen.,,Bonvenon. Kion mi montru al vi?,Bienvenido. ¿Qué te muestro?,,Tervetuloa. Mitä haluaisitte vilkaista?,"Bienvenue, que souhaitez vous?","Üdvözlet, mire volnál kíváncsi?",Benvenuto. Cosa posso mostrarti?,ようこそ、何をお探しで?,어서 오십시오. 어떤 걸 보여드릴까요?,Welkom. Wat kan ik je laten zien?,Velkommen. Hva kan jeg vise deg?,"Witaj. Co mogę ci pokazać? + +",Saudações. O que posso te mostrar?,,Bun venit. Ce aș putea să-ți arăt?,Здравствуй. Что-нибудь интересует?,,Välkommen. Vad får jag visa dig?,Hoş geldiniz. Size ne gösterebilirim? +Environmental suit,TXT_RPLY0_SCRIPT02_D19708_ENVIR,,,,Ochranný oblek,Miljødragt,Schutzanzug.,,Medi-ŝirman veston,Traje NBQ,,Ympäristösuojapuku,Combinaison hazmat,Természetálló öltözet,Tuta ambientale,耐環境スーツ,환경 방호복,Beschermend Pak,Miljødrakt,Skafander Ochronny,Traje de proteção,,Costum de protecție,Защитный костюм,,Miljödräkt,Çevre kıyafeti +"Well, here you are.",TXT_RYES0_SCRIPT02_D19708_WELLH,,,,"Tak, tady to je.","Nå, værsgo.",Bitte sehr.,,"Nu, jen.","Bueno, toma.",,"Kas tässä, olkaa hyvä.",Voilà pour vous.,"Nos, íme.","Bene, ecco a te.",では、これをどうぞ。,"자, 여기 있습니다.","Nou, hier ben je dan.",Vær så god.,"Proszę, masz.","Muito bem, aqui está.",,Poftiți.,"Хорошо, бери.",,"Ja, här är du.",İşte buradasın. +I'm sorry but you don't have enough money for that.,TXT_RNO0_SCRIPT02_D19708_IMSOR,,,,"Promiňte, ale na ten nemáte dost peněz.","Jeg beklager, men du har ikke penge nok til det.","Es tut mir Leid, aber du hast nicht genug Geld dabei.",,"Pardonon, sed vi ne +havas sufiĉe da mono.","Lo siento, pero no te alcanza.",,Valitettavasti teillä ei ole siihen riittävästi rahaa.,Je suis désolé mais vous n'avez pas assez d'argent.,"Sajnálom, de Önnek nem áll módjában kifizetni ezt.","Mi spiace, ma non hai abbastanza soldi per questo.",すみませんが、貴方は十分なお金を持っていません。,"미안하지만, 구매하기 위한 돈이 부족하신 것 같군요.","Het spijt me, maar daar heb je niet genoeg geld voor.","Beklager, men du har ikke nok penger til det.","Przepraszam, ale nie masz wystarczająco dużo monet, aby to kupić.","Sinto muito, mas você não tem dinheiro suficiente para isso.",,"Îmi pare rău, dar nu ai suficienți bani pentru asta.","Извини, но у тебя не хватает денег.",,"Jag är ledsen, men du har inte tillräckligt med pengar för det.",Üzgünüm ama bunun için yeterli paranız yok. +Leather armor,TXT_RPLY1_SCRIPT02_D19708_LEATH,,,Leather armour,Kožené brnění,Læderrustning,Lederrüstung,,Ledan armaĵon,Armadura de cuero,,Nahkasuojus,Armure en cuir,Bőr páncél,Armatura di cuoio,レザーアーマー,가죽 갑옷,Leren harnas,Lær rustning,Skórzany Pancerz,Armadura de couro,,Armură din piele,Кожаная броня,,Läderrustning,Deri zırh +Here you are.,TXT_RYES1_SCRIPT02_D19708_HEREY,,,,Tady máte.,Værsgo.,Bitte sehr.,,Jen.,Toma.,,"Tässä, olkaa hyvä.",Voilà pour vous.,Tessék,Ecco qua.,これをどうぞ。,여기 있습니다.,Hier ben je dan.,Vær så god.,Proszę bardzo.,Aqui está.,,Poftiți.,Держи.,,Här har du.,Buyurun. +Perhaps some other time?,TXT_RNO1_SCRIPT02_D19708_PERHA,,,,Možná někdy jindy?,Måske en anden gang?,Vielleicht ein anderes Mal?,,Ĉu eble alian fojon?,¿Quizás en otra ocasión?,¿Tal vez en otra ocasión?,Ehkä joskus toiste?,Peut être une autre fois?,Talán majd máskor?,"Magari un'altra volta, va bene?",また別の機会に?,나중에 돈을 모아서 구매하세요.,Misschien een andere keer?,Kanskje en annen gang?,Może innym razem?,Talvez uma outra hora?,,Poate altădată?,"Может, в следующий раз?",,Kanske en annan gång?,Belki başka bir zaman? +Metal armor,TXT_RPLY2_SCRIPT02_D19708_METAL,,,Metal armour,Kovové brnění,Metal rustning,Metallrüstung,,Metalan armaĵon,Armadura de metal,,Metallihaarniska,Armure en Métal,Fém páncél,Armatura di metallo,メタルアーマー,강철 갑옷,Metalen harnas,Metall rustning,Metalowy Pancerz,Armadura de metal,,Armură din metal,Металлическая броня,,Metallrustning,Metal zırh +Wear it in good health.,TXT_RYES2_SCRIPT02_D19708_WEARI,(in good health = enjoy),,,Noste jej ve zdraví.,Bær den ved godt helbred.,Trage sie mit Stolz.,,Ĝuu ĝin.,Disfrútala.,,Käyttäkää hyvällä omallatunnolla.,Portez la bien.,Viseld jó egészséggel!,Che possa esserti utile!,着ると安心しますよ。,믿고 입으셔도 됩니다.,Draag het in goede gezondheid.,Bruk den med god helse.,Bądź zdrów nosząc go.,Vista ela com orgulho.,,Să o porți sănătos.,Носи на здоровье.,,Bär den vid god hälsa.,Sağlıkla giy. +Come back when you can afford to buy something you lout!,TXT_RNO2_SCRIPT02_D19708_COMEB,,,,"Vrať se, až si budeš moct něco dovolit, troubo!","Kom tilbage, når du har råd til at købe noget, din slyngel!","Komm zurück wenn du dir etwas leisten kannst, du Rüpel!",,"Revenu kiam vi povos +aĉeti ion, stultulo!","¡Vuelve cuando puedas +comprar algo, zopenco! ",,"Palataan asiaan, kun teidän on mahdollista ostaa jotain himoitsemaanne.","Revenez quand vous avez de l'argent, rustre!","Majd akkor gyere vissza, ha lesz pénzed megvenni bármit is, te fajankó!","Ritorna quando potrai permetterti di comprare le cose, cafone!",余裕がある時にまたどうぞ!,이런 거래는 못 하겠습니다. 돈을 모아서 다시 찾아오시길!,Kom terug wanneer je het je kunt veroorloven om iets te kopen wat je louteren kunt!,"Kom tilbake når du har råd til å kjøpe noe, din lømmel!",Wróć kiedy będziesz mógł coś kupić prostaku!,"Volte quando você puder comprar algo, seu caloteiro!",,"Revin-o când o să ai bani să poți cumpăra ceva, secătură!","Возвращайся, когда сможешь позволить себе купить что-нибудь, придурок!",,"Kom tillbaka när du har råd att köpa något, din tölp!",Bir şeyler satın almaya gücün yettiğinde geri gel! +How may I assist you?,TXT_DLG_SCRIPT02_D21224_HOWMA,MAP02: Hospital.,,,Jak vám mohu pomoci?,Hvordan kan jeg hjælpe dig?,Wie kann ich dir helfen?,,Kiel mi helpu vin?,¿Cómo puedo ayudarte?,,Kuinka voin olla avuksi?,Comment puis-je vous assister?,Miben segíthetek?,Come posso aiutarti?,何かお困りですか?,제가 어떻게 도와드릴까요?,Hoe kan ik u helpen?,Hva kan jeg hjelpe deg med?,Jak mogę ci pomóc?,Como posso ajudar?,,Cu ce vă pot ajuta?,Чем могу помочь?,,Hur kan jag hjälpa dig?,Size nasıl yardımcı olabilirim? +Med patch,TXT_RPLY0_SCRIPT02_D21224_MEDPA,〃,,,Obvaz,Medicinsk plaster,Medizinische Bandage,,Kuracbendoj,Tiritas,Curitas,Sidekääre,Pansement,Ragtapasz,Bende,医薬パッチ,의료 붕대,Med-patch,Medisinplaster,Bandaż,Compressa médica,,Trusă de Prim-Ajutor,Бинтами,,Medicinsk plåster,Tıbbi yama +Here's your patch.,TXT_RYES0_SCRIPT02_D21224_HERES,〃,,,Jeden obvaz.,Her er dit plaster.,Hier ist deine Bandage,,Jen viaj kuracbendoj,Aquí tienes tus tiritas.,Aquí tienes tus curitas.,Tässä kääreenne.,Voilà votre pansement.,Itt a tapaszod,Ecco le bende.,これをどうぞ。,의료 붕대 여깄습니다.,Hier is je patch.,Her er medisinplasteret ditt.,Oto twój bandaż.,Aqui está sua compressa.,,Poftiți trusa.,Вот они.,,Här är ditt plåster.,İşte yamanız. +You need 10 gold for that.,TXT_RNO0_SCRIPT02_D21224_YOUNE,〃,,,Na ten potřebujete deset zlatých.,Du skal bruge 10 guld for det.,Dafür brauchst du 10 Gold.,,Vi bezonas dek da oro.,Necesitas diez de oro.,,Siihen tarvitset 10 kolikkoa.,Il vous faut 10 pièces pour cela.,10 Aranyra lesz szükséged ehhez.,Ti servono 10 pezzi d'oro per quello.,10 ゴールド必要です。,10 골드가 필요합니다.,Daar heb je 10 goud voor nodig.,Du trenger 10 gull for det.,Potrzebujesz 10 monet aby to kupić.,Você precisa de 10 de ouro para isso.,,Ai nevoie de 10 monezi de aur pentru asta.,Тебе не хватает 10 золотых.,,Du behöver 10 guld för den.,Bunun için 10 altına ihtiyacın var. +Medical kit,TXT_RPLY1_SCRIPT02_D21224_MEDIC,〃,,,Lékárničku,Medicinsk kit,Verbandskasten,,Sukurkesto,Botiquín,,Lääkintälaukku,Kit médical,Elsősegély készlet,Kit medico,医療用キット,구급 키트,Medische kit,Medisinsk utstyr,Apteczka,Kit médico,,Kit de Prim-Ajutor,Аптечкой,,Medicinsk utrustning,Tıbbi kit +Thank you.,TXT_RYES1_SCRIPT02_D21224_THANK,〃,,,Děkuji.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Köszönöm,Grazie.,ありがとうございます。,이용 감사드려요.,Bedankt.,Takk skal du ha.,Dziękuję.,Agradeço.,,Mulțumesc.,Спасибо.,,Tack.,Teşekkür ederim. +"I wish I could give them away, but they cost 25 gold.",TXT_RNO1_SCRIPT02_D21224_IWISH,〃,,,"Přál bych si je dávat zadarmo, ale stojí 25 zlatých.","Jeg ville ønske, jeg kunne give dem væk, men de koster 25 guld.","Ich wünschte ich könnte sie weggeben, aber sie kosten 25 Gold.",,"Mi donacus ĝin, sed +ĝi kostas 25 da oro.","Ojalá pudiera regalarlo, +pero cuesta 25 de oro.",,"Mielelläni antaisin ilmaiseksi, mutta ne maksavat 25 kultakolikkoa.","J'aimerais vraiment les donner gratuitement, mais cela côute 25 pièces.","Bárcsak ingyen osztogathatnám, de 25 aranyba kerül.","Mi piacerebbe darli via, ma costano 25 pezzi d'oro.",譲渡したい所ですが、25 ゴールド必要です。,"주고 싶지만, 이것의 가격은 25 골드입니다.","Ik wou dat ik ze kon weggeven, maar ze kosten 25 goud.","Jeg skulle ønske jeg kunne gi dem bort, men de koster 25 gull.","Chciałbym móc je rozdać, ale one kosztują 25 monet.","Bem que eu queria poder dar de graça, mas custam 25 de ouro.",,"Mi-aș dori să le pot da pe gratis, dar costă 25 de monezi de aur.","С радостью бы отдал, но они по 25 золотых.",,"Jag önskar att jag kunde ge bort dem, men de kostar 25 guld.",Keşke onları verebilseydim ama 25 altına mal oluyorlar. +Field surgery kit,TXT_RPLY2_SCRIPT02_D21224_FIELD,〃,,,Chirurgickou soupravu,Kirurgisæt,Erste-Hilfe-Kasten,,Kirurgia kesto,Kit quirúrgico,,Kenttäkirurgilaukku,Kit de chirurgie,Harctéri műtéti felszerelés,Kit chirurgico,手術キット,수술 키트,Veld chirurgie kit,Kirurgisett,Polowy zestaw chirurga,Kit de cirurgia,,Trusă de chirurgie de teren,Медкомплектом,,Fältkirurgisk utrustning,Saha ameliyat kiti +There you go. Take care now.,TXT_RYES2_SCRIPT02_D21224_THERE,〃,,,Tady máte. Buďte opatrný.,Værsgo. Pas godt på dig selv nu.,Bitte schön. Mach's gut.,,Jen. Estu atenta.,Toma. Cuídate.,,Olkaa hyvä. Pitäkää itsestänne huoli.,Voilà pour vous. Faites attention à vous maintenant.,"Tessék, minden jót!",Ecco qua. Stammi bene.,こちらになります、お気をつけて。,여기 있습니다. 잘 쓰세요.,Daar ga je. Pas goed op jezelf.,Vær så god. Ta vare på deg selv.,Proszę bardzo. Trzymaj się.,Aqui está. Se cuida.,,Poftiți. Aveți grijă.,Пожалуйста. Береги себя!,,Här har du det. Ta hand om dig nu.,Al bakalım. Kendine iyi bak. +"Well, maybe you can afford some med patches?",TXT_RNO2_SCRIPT02_D21224_WELLM,〃,,,"No, spíš byste si mohl dovolit nějaké obvazy?","Nå, måske har du råd til nogle medicinske plastre?","Nun, vielleicht kannst du dir ein paar medizinische Bandagen leisten?",,"Nu, ĉu vi eble povas +aĉeti kuracbendojn?","Bueno, ¿quizás tengas +para comprar tiritas?","Bueno, ¿tal vez tengas +para comprar curitas?",Olisiko teillä kuitenkin sidekääreisiin ehkä varaa?,"Eh bien, peut être que vous pouvez vous acheter quelques pansements?",Talán némi ragtapaszra tudnál költeni?,"Niente da fare, ma forse puoi permetterti delle bende?",ところで、医薬パッチを買う余裕はありますか?,"글쎄요, 아마 의료 붕대 정돈 살 수 있을걸요?","Nou ja, misschien kunt je zich wat med-patches veroorloven?",Kanskje du har råd til noen medisinplaster?,"Cóż, może stać cię na jakieś bandaże?","Bem, talvez você possa comprar algumas compressas?",,"Păi, poate îți permiți niște truse de prim-ajutor?","Тогда, может быть, купишь несколько бинтов?",,Du kanske har råd med några medicinska plåster?,Belki ilaç yamalarını karşılayabilirsin? +"I hope Macil knows what he's doing. If the Order finds out I'm helping the Front I'm as good as dead... Not that this matters to you any. The Front's medic gave me an upgrade chip for you, are you ready? ",TXT_DLG_SCRIPT02_D22740_IHOPE,〃 (After destroying the crystal in the Power Station),,,"Doufám, že Macil ví, co dělá. Jestli Řád zjistí, že pomáhám Frontě, jsem mrtvý... Ne, že by vás to mělo trápit. Medik Fronty mi pro vás dal vylepšovací čip, připraven?","Jeg håber, at Macil ved, hvad han laver. Hvis Ordenen finder ud af, at jeg hjælper fronten, er jeg så godt som død... Ikke at det har nogen betydning for dig. Frontens læge gav mig en opgraderingschip til dig, er du klar?","Ich hoffe Macil weiß was er tut. Wenn der Orden herausfindet das ich der Front helfe, bin ich so gut wie tot... auch wenn es für dich keine Rolle spielt. Ein Sanitäter der Front hat mir einen Verbesserungschip für dich mitgegeben, bist du bereit?",,"Mi esperas, ke Macil scias tion, kion li faras. Se La Ordeno malkovras, ke mi helpas la Fronton, mi estos sufiĉe mortinta... Ne kvazaŭ vi zorgus pri tio. La kuracisto de la Fronto donis al mi plibonigan icon por vi. Ĉu vi estas preta?","Espero que Macil sepa lo que está haciendo. Si La Orden se entera de que estoy ayudando al Frente, estoy bien muerto... No es como si te importara. El médico del Frente me dio un chip de mejora para ti. ¿Estás listo?",,"Toivottavasti Macil tietää, mitä tekee. Jos Veljeskunta saa kuulla minun auttavan Rintamaa, olen mennyttä... Ei siinä, että tieto sinua mitenkään kiinnostaisi. Sain Rintaman lääkintämieheltä sinulle päivityssirun; oletko valmis?","J'espère que Macil sait ce qu'il fait. Si l'Ordre se rend compte que j'aide le Front, c'est comme si j'étais mort.. bon, cela ne vous importe pas. Le médecin du Front m'a donné une puce d'augmentation pour vous. Etes vous prêt?","Remélem Macil tudja, mit csinál. Ha a Rend rájön, hogy a Frontot segítem, alulról szagolom majd az ibolyát...Nem mintha ez számítana számodra. A Front orvosa egy fejlesztési chipet küldött neked. Készen állsz?","Spero che Macil sappia quello che sta facendo. Se l'Ordine scopre che sto aiutando il Fronte sarò bello che morto... Non che questo importi ormai. Il medico del Fronte mi ha dato un upgrade chip per te, sei pronto?","マシルの行いが正しければ良いですが。 私がフロントを援助しているとオーダーが 知ったら、私は...これは貴方には関係無いか。 フロントのメディックが貴方へ アップグレードチップを送ってくれました、 装着しますか? -",마실 사령관님이 하는 일이 무엇인지 알고 있기를... 만약 오더가 내가 프론트를 위해 일한다는 걸 눈치챈다면 절 죽일 거예요. 물론 당신이 알 바는 아니지만. 프론트 의무관님이 업그레이드 칩을 당신에게 이식하라고 여기까지 가져왔더군요. 준비되셨습니까?,"Ik hoop dat Macil weet wat hij doet. Als de Orde erachter komt dat ik het Front help, ben ik zo goed als dood.... Niet dat dit belangrijk voor je is. De dokter van het Front heeft me een upgradechip voor je gegeven, ben je er klaar voor?","Mam nadzieję, że Macil wie co robi. Jeśli Zakon odkryje, że pomagam Frontowi, będę martwy... Nie to, że kogokolwiek to obchodzi. Medyk frontu dał mi czip ulepszający dla ciebie, jesteś gotowy?","Espero que Macil saiba o que está fazendo. Se a Ordem descobrir que estou ajudando a Frente, estou morto... Não que isso importe para vocês. O médico da Frente me passou um chip de upgrade pra você, está preparado?",,"Sper că Macil știe ce face. Dacă Ordinul află că ajut Frontul sunt ca și mort. Nu-i ca și cum te-ar interesa asta. Medicul Frontului mi-a dat un cip pentru upgrade, ești pregătit?","Надеюсь, Мэйсил знает, что делает. Если Орден обнаружит, что я помогаю повстанцам, я не жилец... хотя тебе-то какое дело. Медик Сопротивления передал мне этот чип для тебя. Ты готов? -","Надам се да Мацил зна шта ради. Ако одред сазна да помажем Фронту мртав сам... Није да вам је то битно. Лекар ми је дао за тебе чип за надоградњу, јеси спреман? " -"Yes, I'm ready.",TXT_RPLY0_SCRIPT02_D22740_YESIM,,,,"Ano, jsem připravený.","Ja, ich bin bereit.",,,"Si, estoy listo.",,,"Oui, je suis prêt.","Igen, készen állok.",,ああ、準備良しだ。,"좋아요, 준비 됐습니다.","Ja, ik ben er klaar voor.","Tak, jestem gotowy.","Sim, estou preparado.",,"Da, sunt pregătit.","Да, готов.",Да. Спреман сам. -"Well then, this won't take but a second. There, done already.",TXT_RYES0_SCRIPT02_D22740_WELLT,,,,"Tak dobře, měla by to být jen vteřinka. Tak, a je hotovo.","Nun dann, das wird nicht mal eine Sekunde dauern. So, bereits erledigt.",,,"Bueno entonces. Esto no tomará sino un segundo. Bien, hecho.",,,"Bon, cela ne prendra qu'une seconde. Voilà, c'est fait.","Jól van hát, nem fog csak egy pár másodpercig tartani... És kész is.",,それでは、これに時間は掛かりません。はい、完了しました。,"그럼 잠깐이면 됩니다. 자, 다 됐어요.","Nou dan, dit duurt maar een seconde. Daar, al klaar.","Dobrze więc, to zajmie tylko sekundę. Już, gotowe.","Muito bem, isso vai levar um segundo. Pronto, já terminei.",,"Bine atunci, va dura doar o secundă. Așa, e gata deja.","Хорошо. Секундочку... Всё, готово.","Па, ово ће трајати једну секунду. Ето, већ завршено." -How may I assist you?,TXT_DLG_SCRIPT02_D24256_HOWMA,,,,Jak ti mohu pomoci?,Wie kann ich dir helfen?,,,¿Cómo puedo ayudarte?,,,Comment puis-je vous assister?,Miben segíthetek?,,何かお困りですか?,어떻게 도와드릴까요?,Hoe kan ik je helpen?,Jak mogę ci pomóc?,Como posso ajudá-lo?,,Cu ce vă pot ajuta?,Чем могу тебе помочь?,Како вам могу помоћи? -Med patch,TXT_RPLY0_SCRIPT02_D24256_MEDPA,,,,Obvazy,Medizinische Bandage,,,Parche Médico,,,Pansement,,,医薬パッチ,의료 붕대,Med-patch,Bandaż,Compressa médica,,Trusă de Prim-Ajutor,Бинтами,Фластери -Here's your patch.,TXT_RYES0_SCRIPT02_D24256_HERES,,,,Tady je tvůj obvaz.,Hier ist deine Bandage,,,Aquí tienes tu parche.,,,Voilà votre pansement.,,,これをどうぞ。,여기 의료 붕대입니다.,Hier is je patch.,Oto twój bandaż.,Aqui está sua compressa,,Poftiți trusa.,Вот они.,Ево ваших фластера -You need 10 gold for that.,TXT_RNO0_SCRIPT02_D24256_YOUNE,,,,Na ty potřebuješ deset zlatých.,Dafür brauchst du 10 Gold.,,,Necesitarás 10 de oro para esto.,,,Il vous faut 10 pièces pour cela.,,,10 ゴールド必要です。,10 골드가 필요한데.,Daar heb je 10 goud voor nodig.,Potrzebujesz 10 monet aby to kupić.,Você precisa de 10 de ouro pra isso.,,Ai nevoie de 10 monezi de aur pentru asta.,Тебе не хватает 10 золотых.,Треба вам 10 златника за то. -Medical kit,TXT_RPLY1_SCRIPT02_D24256_MEDIC,,,,Lékárničku,Verbandskasten,,,Kit Médico,,,Kit médical,,,医療用キット,구급 키트,Medische kit,Apteczka,Kit médico.,,Kit de Prim-Ajutor,Аптечкой,Медицински комплет -Thank you.,TXT_RYES1_SCRIPT02_D24256_THANK,,,,Děkuji.,Danke.,,,Gracias.,,,Merci.,,,ありがとうございます。,또 오세요.,Bedankt.,Dziękuję.,Obrigado.,,Mulțumesc.,Спасибо.,Хвала. -"I wish I could give them away, but they cost 25 gold.",TXT_RNO1_SCRIPT02_D24256_IWISH,,,,"Přál bych si je dávat zadarmo, ale stojí 25 zlatých.","Ich wünschte ich könnte sie weggeben, aber sie kosten 25 Gold.",,,"Ojalá pudiera regalarlos, pero cuestan 25 de oro.",,,"J'aimerais vraiment les donner gratuitement, mais cela côute 25 pièces.",,,譲渡したい所ですが、25 ゴールド必要です。,25 골드만 있다면 이건 당신 것인데 말이죠.,"Ik wou dat ik ze kon weggeven, maar ze kosten 25 goud.","Chciałbym móc je rozdać, ale one kosztują 25 monet.","Bem que eu queria poder dar de graça, mas custam 25 de ouro.",,"Mi-aș dori să le pot da pe gratis, dar costă 25 de monezi de aur.","С радостью бы отдал, но они по 25 золотых.","Волео бих да их могу дати, али коштају 25 златника" -Field surgery kit,TXT_RPLY2_SCRIPT02_D24256_FIELD,,,,Chirurgickou soupravu,Erste-Hilfe-Kasten,,,Kit Quirúrgico,,,Kit de chirurgie,,,手術キット,수술 키트,Veld chirurgie kit,Polowy zestaw chirurga,Kit de cirurgia,,Trusă de chirurgie de teren,Медкомплект,Комплет за операцију на терену -There you go. Take care now.,TXT_RYES2_SCRIPT02_D24256_THERE,,,,Tady máš. Buď opatrný.,Bitte schön. Mach's gut.,,,Aquí Tienes. Cuídate.,,,Voilà pour vous. Faites attention à vous maintenant.,,,こちらになります、お気をつけて。,여기 있습니다. 잘 쓰세요.,Daar ga je. Pas goed op jezelf.,Proszę bardzo. Trzymaj się.,Aqui está. Se cuida.,,Poftiți. Aveți grijă.,Пожалуйста. Береги себя!,Изволите. Чувајте се. -"Well, maybe you can afford some med patches?",TXT_RNO2_SCRIPT02_D24256_WELLM,,,,"No, možná by sis mohl spíš dovolit nějaké obvazy?","Nun, vielleicht kannst du dir ein paar medizinische Bandagen leisten?",,,"Bien, ¿Quizás te alcance para algunos parches médicos?",,,"Eh bien, peut être que vous pouvez vous acheter quelques pansements?",,,ところで、医薬パッチを買う余裕はありますか?,글쎄요... 의료 붕대는 어떻습니까?,"Nou ja, misschien kunt je zich wat med-patches veroorloven?","Cóż, może stać cię na jakieś bandaże?","Bem, talvez você possa comprar algumas compressas?",,"Păi, poate îți permiți niște truse de prim-ajutor?","Тогда, может быть, купишь несколько бинтов?","Па, можда можете да приуштите нешто фластера?" -"Hello stranger, I haven't seen you around here before. Let me give you a piece of free advice. I'd be careful if I were you. The Order does not tolerate free will, and their justice is swift.",TXT_DLG_SCRIPT02_D25772_HELLO,,,,"Vítej, cizinče, tebe jsem tu ještě neviděl. Tady je drobná rada na začátek grátis: Být tebou, byl bych opatrný. Řád netoleruje svobodnou vůli a jejich spravedlnost je hbitá. ","Hallo, Fremder. Ich habe dich hier vorher noch nie gesehen. Lass mich dir einen kostenlosen Rat geben. An deiner Stelle wäre ich vorsichtig. Der Orden duldet keinen freien Willen und sie greifen hart durch.",,,"Hola extranjero, no te he visto por aquí antes. Déjame darte un consejo gratis. Tendría cuidado si fuera tú. La orden no tolera el libre albedrío, y su justicia es veloz.",,,"Bien le bonjour, étranger. On ne vous a pas encore vu dans ce coin. Laissez-moi vous donner un petit conseil. Je ferais attention si j'étais vous. L'Ordre ne tolère pas le libre arbitre et leur justice est fulgurante.",,,"どうも余所者、この辺では見かけない顔だな。 +",마실 사령관님이 하는 일이 무엇인지 알고 있기를... 만약 오더가 내가 프론트를 위해 일한다는 걸 눈치챈다면 절 죽일 거예요. 물론 당신이 알 바는 아니지만. 프론트 의무관님이 업그레이드 칩을 당신에게 이식하라고 여기까지 가져왔더군요. 준비되셨습니까?,"Ik hoop dat Macil weet wat hij doet. Als de Orde erachter komt dat ik het Front help, ben ik zo goed als dood.... Niet dat dit belangrijk voor je is. De dokter van het Front heeft me een upgradechip voor je gegeven, ben je er klaar voor?","Jeg håper Macil vet hva han gjør. Hvis Ordenen finner ut at jeg hjelper Fronten, er jeg så godt som død... Ikke at det betyr noe for deg. Frontens lege ga meg en oppgraderingsbrikke til deg. Er du klar?","Mam nadzieję, że Macil wie co robi. Jeśli Zakon odkryje, że pomagam Frontowi, będę martwy... Nie to, że kogokolwiek to obchodzi. Medyk frontu dał mi czip ulepszający dla ciebie, jesteś gotowy?","Espero que Macil saiba o que está fazendo. Se a Ordem descobrir que estou ajudando a Frente, estou morto... Não que isso importe para vocês. O médico da Frente me passou um chip de upgrade pra você, está preparado?",,"Sper că Macil știe ce face. Dacă Ordinul află că ajut Frontul sunt ca și mort. Nu-i ca și cum te-ar interesa asta. Medicul Frontului mi-a dat un cip pentru upgrade, ești pregătit?","Надеюсь, Мэйсил знает, что делает. Если Орден обнаружит, что я помогаю повстанцам, я не жилец... хотя тебе-то какое дело. Медик Сопротивления передал мне этот чип для тебя. Ты готов? +",,"Jag hoppas att Macil vet vad han gör. Om Orden får reda på att jag hjälper fronten är jag så gott som död... Inte för att det spelar någon roll för dig. Frontens läkare gav mig ett uppgraderingschip till dig, är du redo?","Umarım Macil ne yaptığını biliyordur. Tarikat Cephe'ye yardım ettiğimi öğrenirse ölmüş sayılırım. Bu senin için önemli değil. Cephe'nin doktoru bana senin için bir yükseltme çipi verdi, hazır mısın?" +"Yes, I'm ready.",TXT_RPLY0_SCRIPT02_D22740_YESIM,〃,,,"Ano, jsem připravený.","Ja, jeg er klar.","Ja, ich bin bereit.",,"Jes, mi estas preta.","Sí, estoy listo.",,"Kyllä, olen valmis.","Oui, je suis prêt.","Igen, készen állok.","Sì, sono pronto.",ああ、準備良しだ。,"좋아요, 준비 됐습니다.","Ja, ik ben er klaar voor.","Ja, jeg er klar.","Tak, jestem gotowy.","Sim, estou preparado.",,"Da, sunt pregătit.","Да, готов.",,"Ja, jag är redo.","Evet, hazırım." +"Well then, this won't take but a second. There, done already.",TXT_RYES0_SCRIPT02_D22740_WELLT,〃,,,"Tak dobře, měla by to být jen vteřinka. Tak, a je hotovo.","Nå, så tager det kun et øjeblik. Sådan, det er allerede gjort.","Nun dann, das wird nicht mal eine Sekunde dauern. So, bereits erledigt.",,"Bone, mi bezonos nur +unu sekundon... kaj finite.","Muy bien, solo un +segundo... Y listo.",,"Siinä tapauksessa tähän ei mene paria sekuntia pidempään. Kas näin, valmista jo.","Bon, cela ne prendra qu'une seconde. Voilà, c'est fait.","Jól van hát, nem fog csak egy pár másodpercig tartani... És kész is.","Bene, non ci vorrà molto. Ecco fatto.",それでは、これに時間は掛かりません。はい、完了しました。,"그럼 잠깐이면 됩니다. 자, 다 됐어요.","Nou dan, dit duurt maar een seconde. Daar, al klaar.","Da tar det bare et øyeblikk. Sånn, ferdig.","Dobrze więc, to zajmie tylko sekundę. Już, gotowe.","Muito bem, isso vai levar um segundo. Pronto, já terminei.",,"Bine atunci, va dura doar o secundă. Așa, e gata deja.","Хорошо. Секундочку... Всё, готово.",,"Då tar det här bara en sekund. Där, redan gjort.","O zaman bir saniye bile sürmez. İşte, bitti bile." +How may I assist you?,TXT_DLG_SCRIPT02_D24256_HOWMA,〃,,,Jak vám mohu pomoci?,Hvordan kan jeg hjælpe dig?,Wie kann ich dir helfen?,,Kiel mi helpu vin?,¿Cómo puedo ayudarte?,,Kuinka voin olla avuksi?,Comment puis-je vous assister?,Miben segíthetek?,Come posso aiutarti?,何かお困りですか?,어떻게 도와드릴까요?,Hoe kan ik je helpen?,Hva kan jeg hjelpe deg med?,Jak mogę ci pomóc?,Como posso ajudar?,,Cu ce vă pot ajuta?,Чем могу тебе помочь?,,Hur kan jag hjälpa dig?,Size nasıl yardımcı olabilirim? +Med patch,TXT_RPLY0_SCRIPT02_D24256_MEDPA,〃,,,Obvaz,Medicinsk plaster,Medizinische Bandage,,Kuracbendoj,Tiritas,Curitas,Sidekääre,Pansement,Ragtapasz,Bende,医薬パッチ,의료 붕대,Med-patch,Medisinplaster.,Bandaż,Compressa médica,,Trusă de Prim-Ajutor,Бинтами,,Med patch,Tıbbi yama +Here's your patch.,TXT_RYES0_SCRIPT02_D24256_HERES,〃,,,Jeden obvaz.,Her er dit plaster.,Hier ist deine Bandage,,Jen viaj kuracbendoj,Aquí tienes tus tiritas.,Aquí tienes tus curitas.,Tässä kääreenne.,Voilà votre pansement.,Itt a tapaszod.,Ecco le bende.,これをどうぞ。,여기 의료 붕대입니다.,Hier is je patch.,Her er plasteret ditt.,Oto twój bandaż.,Aqui está sua compressa.,,Poftiți trusa.,Вот они.,,Här är ditt plåster.,İşte yamanız. +You need 10 gold for that.,TXT_RNO0_SCRIPT02_D24256_YOUNE,〃,,,Na ten potřebujete deset zlatých.,Du skal bruge 10 guld for det.,Dafür brauchst du 10 Gold.,,Vi bezonas dek da oro.,Necesitas diez de oro.,,Tarvitset siihen 10 kolikkoa.,Il vous faut 10 pièces pour cela.,10 aranyra van szükséged ehhez.,Ti servono 10 pezzi d'oro per quello.,10 ゴールド必要です。,10 골드가 필요한데.,Daar heb je 10 goud voor nodig.,Du trenger 10 gull for det.,Potrzebujesz 10 monet aby to kupić.,Você precisa de 10 de ouro pra isso.,,Ai nevoie de 10 monezi de aur pentru asta.,Тебе не хватает 10 золотых.,,Du behöver 10 guld för det.,Bunun için 10 altına ihtiyacın var. +Medical kit,TXT_RPLY1_SCRIPT02_D24256_MEDIC,〃,,,Lékárničku,Medicinsk kit,Verbandskasten,,Sukurkesto,Botiquín,,Lääkintälaukku,Kit médical,Orvosi csomag.,Kit medico,医療用キット,구급 키트,Medische kit,Medisinsk utstyr,Apteczka,Kit médico,,Kit de Prim-Ajutor,Аптечкой,,Medicinsk utrustning,Tıbbi kit +Thank you.,TXT_RYES1_SCRIPT02_D24256_THANK,〃,,,Děkuji.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Köszönöm.,Grazie.,ありがとうございます。,또 오세요.,Bedankt.,Takk skal du ha.,Dziękuję.,Agradeço.,,Mulțumesc.,Спасибо.,,Tack.,Teşekkür ederim. +"I wish I could give them away, but they cost 25 gold.",TXT_RNO1_SCRIPT02_D24256_IWISH,〃,,,"Přál bych si je dávat zadarmo, ale stojí 25 zlatých.","Jeg ville ønske, jeg kunne give dem væk, men de koster 25 guld.","Ich wünschte ich könnte sie weggeben, aber sie kosten 25 Gold.",,"Mi donacus ĝin, sed +ĝi kostas 25 da oro.","Ojalá pudiera regalarlo, +pero cuesta 25 de oro.",,"Kunpa voisinkin antaa niitä ilmaiseksi, mutta ne maksavat 25 kultakolikkoa.","J'aimerais vraiment les donner gratuitement, mais cela côute 25 pièces.","Bárcsak ingyen osztogathatnám, de 25 aranyba kerül.","Mi piacerebbe darli via, ma costano 25 pezzi d'oro.",譲渡したい所ですが、25 ゴールド必要です。,25 골드만 있다면 이건 당신 것인데 말이죠.,"Ik wou dat ik ze kon weggeven, maar ze kosten 25 goud.","Jeg skulle ønske jeg kunne gi dem bort, men de koster 25 gull.","Chciałbym móc je rozdać, ale one kosztują 25 monet.","Bem que eu queria poder dar de graça, mas custam 25 de ouro.",,"Mi-aș dori să le pot da pe gratis, dar costă 25 de monezi de aur.","С радостью бы отдал, но они по 25 золотых.",,"Jag önskar att jag kunde ge bort dem, men de kostar 25 guld.",Keşke onları verebilseydim ama 25 altına mal oluyorlar. +Field surgery kit,TXT_RPLY2_SCRIPT02_D24256_FIELD,〃,,,Chirurgickou soupravu,Kirurgisæt,Erste-Hilfe-Kasten,,Kirurgia kesto,Kit quirúrgico,,Kenttäkirurgilaukku,Kit de chirurgie,Harctéri műtéti felszerelés,Kit chirurgico,手術キット,수술 키트,Veld chirurgie kit,Kirurgisett,Polowy zestaw chirurga,Kit de cirurgia,,Trusă de chirurgie de teren,Медкомплект,,Fältkirurgisk utrustning,Saha ameliyat kiti +There you go. Take care now.,TXT_RYES2_SCRIPT02_D24256_THERE,〃,,,Tady máte. Buďte opatrný.,Værsgo. Pas godt på dig selv nu.,Bitte schön. Mach's gut.,,Jen. Estu atenta.,Toma. Cuídate.,,Olkaa hyvä. Pitäkää itsestänne huoli.,Voilà pour vous. Faites attention à vous maintenant.,Parancsolj! Aztán vigyázz magadra!,Ecco qua. Stammi bene.,こちらになります、お気をつけて。,여기 있습니다. 잘 쓰세요.,Daar ga je. Pas goed op jezelf.,Vær så god. Ta vare på deg selv.,Proszę bardzo. Trzymaj się.,Aqui está. Se cuida.,,Poftiți. Aveți grijă.,Пожалуйста. Береги себя!,,Här har du det. Ta hand om dig nu.,Al bakalım. Kendine iyi bak. +"Well, maybe you can afford some med patches?",TXT_RNO2_SCRIPT02_D24256_WELLM,〃,,,"No, spíš byste si mohl dovolit nějaké obvazy?","Nå, måske har du råd til nogle medicinske plastre?","Nun, vielleicht kannst du dir ein paar medizinische Bandagen leisten?",,"Nu, ĉu vi eble povas +aĉeti kuracbendojn?","Bueno, ¿quizás tengas +para comprar tiritas?","Bueno, ¿tal vez tengas +para comprar curitas?",Olisiko teillä ehkä varaa sidekääreisiin?,"Eh bien, peut être que vous pouvez vous acheter quelques pansements?","Nos, talán telik pár ragtapaszra is?","Niente da fare, ma forse puoi permetterti delle bende?",ところで、医薬パッチを買う余裕はありますか?,글쎄요... 의료 붕대는 어떻습니까?,"Nou ja, misschien kunt je zich wat med-patches veroorloven?",Kanskje du har råd til noen medisinplaster?,"Cóż, może stać cię na jakieś bandaże?","Bem, talvez você possa comprar algumas compressas?",,"Păi, poate îți permiți niște truse de prim-ajutor?","Тогда, может быть, купишь несколько бинтов?",,Du kanske har råd med några medicinska plåster?,Belki birkaç ilaç yamasını karşılayabilirsin? +"Hello stranger, I haven't seen you around here before. Let me give you a piece of free advice. I'd be careful if I were you. The Order does not tolerate free will, and their justice is swift.",TXT_DLG_SCRIPT02_D25772_HELLO,MAP02: Barkeep.,,,"Vítejte, cizinče, vás jsem tu ještě neviděl. Dám vám drobnou radu na začátek grátis: Být vámi, byl bych opatrný. Řád netoleruje svobodnou vůli a jejich spravedlnost je hbitá. ","Hej fremmede, jeg har ikke set dig her før. Lad mig give dig et gratis råd. Jeg ville være forsigtig, hvis jeg var dig. Ordenen tolererer ikke fri vilje, og deres retfærdighed er hurtig.","Hallo, Fremder. Ich habe dich hier vorher noch nie gesehen. Lass mich dir einen kostenlosen Rat geben. An deiner Stelle wäre ich vorsichtig. Der Orden duldet keinen freien Willen und sie greifen hart durch.",,"Saluton, fremdulo, mi ne vidis vin ĉi tie antaŭe. Jen senpaga konsilo: mi estus atenta se mi estus vi; La Ordeno ne toleras liberan volon kaj havas rapidan «juston».","Hola, extranjero, no te he visto por aquí antes. Te daré un consejo gratis: tendría cuidado si fuera tú; La Orden no tolera el libre albedrío y su justicia es veloz.","Hola, extranjero, es la primera vez que te veo por aquí. Te voy a dar un consejo gratis: tendría cuidado si fuera tú; La Orden no tolera el libre albedrío y su justicia es veloz.","Päivää. En olekaan nähnyt teitä täällä ennen. Teinä neuvoisin olemaan varuillanne. Veljeskunta ei suvaitse vapaata tahtoa, ja heidän tuomionsa ovat pikaiset.","Bien le bonjour, étranger. On ne vous a pas encore vu dans ce coin. Laissez-moi vous donner un petit conseil. Je ferais attention si j'étais vous. L'Ordre ne tolère pas le libre arbitre et leur justice est fulgurante.","Üdvözöllek idegen, nem láttalak még itt a környéken. Hadd adjak egy ingyen tanácsot. Én óvatos lennék a helyedben. A Rend nem tolerálja a szabad akaratot, és elég fürge az igazságszolgáltatás.","Salve straniero, non ti ho mai visto da queste parti prima. Lascia che ti dia un consiglio. Io starei attento se fossi in te. L'Ordine non tollera il libero arbitrio, e la loro ""giustizia"" è repentina.","どうも余所者、この辺では見かけない顔だな。 では一杯アドバイスをおごろう。この付近が 自由な発言を許さないからって下手な真似は するなよ。オーダーという自警団がすぐに -駆けつけてくるぞ。","안녕하신가 이방인이여, 자네는 이곳에서 처음 보는 얼굴이군. 내가 자네에게 공짜 조언을 해주지. 내가 자네라면 조심할 거야. 오더는 자유의지를 용납하지 않아. 그리고 그들의 정의는 신속하지.","Hallo vreemdeling, ik heb je hier nog niet eerder gezien. Laat me je een stukje gratis advies geven. Ik zou voorzichtig zijn als ik jou was. De Orde tolereert geen vrije wil en hun gerechtigheid is snel.","Witaj nieznajomy, nigdy cie tu wcześniej nie widziałem. Dam ci darmową radę. Na twoim miejscu bym uważał. Zakon nie toleruje wolnej woli, a ich prawo działa prędko.","Olá, forasteiro. Nunca vi você por aqui antes. Deixa eu te dar um conselho de graça. Eu tomaria cuidado se eu fosse você. A Ordem não tolera livre arbítrio e a justiça deles é rápida.",,"Salutări străine, nu te-am mai văzut pe-aici. Permite-mi să-ți dau un sfat. Aș fi grijuliu în locul tău. Ordinul nu tolerează voința liberă, iar justiția lor e rapidă.","Привет, незнакомец. Что-то я не видел тебя тут раньше. Позволь дать тебе бесплатный совет: я на твоём месте был бы поосторожнее. Орден не терпит неповиновения, и они быстры на правосудие.","Здраво странче, нисам те раније виђао овде. Дај да ти дам савет. Да сам ти био бих опрезан. Одред не толерише слободну вољу, и њихова правда је брза." -What's the word?,TXT_RPLY0_SCRIPT02_D25772_WHATS,,,,Nějaké zvěsti?,Was erzählt man sich so?,,,¿Qué se dice por aquí?,,,C'est quoi la rumeur?,,,他には?,무슨 뜻이죠?,Wat is het woord?,Jakieś wieści?,Quais são as últimas?,,Ai vreo veste?,Есть новости?,Која је реч? -The word is... The sewers hold more than just rats and robots.,TXT_RYES0_SCRIPT02_D25772_THEWO,,,,Zvěsti jsou... že stoky ukrývají víc než jen krysy a roboty.,"Man erzählt sich, dass die Kanalisation mehr als Ratten und Roboter zu bieten hat.",,,Se dice que... Las alcantarillas albergan más que solo ratas y robots.,,,La rumeur est.. Que les égouts cachent quelque chose de plus gros que des rats et des robots.,,,他は...下水道には鼠やロボが沢山だ。,"무슨 말이냐 하면, 하수도 안에는 시궁쥐만 있는 게 아니라 로봇들도 숨어 있다는 거지.",Het woord is.... De riolen bevatten meer dan alleen ratten en robots.,"Wieści są takie, że... kanały skrywają coś więcej niż tylko szczury i roboty.",As ultimas são... Que os esgotos abrigam mais do que apenas ratos e robôs.,,Vestea e că... Canalele ascund mai mult decât roboți și șoareci.,В канализации водятся не только крысы и роботы.,Реч је... Канализација садржи више сем пацова и робота. -What can I do for you now?,TXT_DLG_SCRIPT02_D27288_WHATC,,,,Co pro tebe můžu udělat teď?,Was kann ich jetzt für dich tun?,,,¿Qué puedo hacer por ti?,,,Que puis-je faire pour vous?,Mit tehetek ma Önért?,,何か用か?,이제 자네에게 무엇을 해드릴까?,Wat kan ik nu voor je doen?,Co mogę dla ciebie zrobić?,O que posso fazer por você agora?,,Cu ce te mai pot ajuta?,Тебе что-нибудь нужно?,Како вам могу помоћи сада? -More info.,TXT_RPLY0_SCRIPT02_D27288_MOREI,,,,Další informace,Mehr Informationen.,,,Más información.,,,Plus d'infos.,Több információt.,,話のネタ。,더 많은 정보를 주세요.,Meer info.,Więcej informacji.,Mais informações.,,Mai multe informații.,Расскажи больше,Више информације. -The Governor is a simple reminder to us that we aren't free people anymore.,TXT_RYES0_SCRIPT02_D27288_THEGO,,,,"Náš guvernér je hezkou přípomínkou toho, že už nejsme svobodní.","Der Gouverneur ist eine einfache Erinnerung daran, das wir keine freien Menschen mehr sind.",,,El gobernador es un simple recordatorio de que ya no somos personas libres.,,,Le gouverneur n'est qu'un exemple parmi d'autres pour nous montrer que ne nous somme plus un peuple libre.,"A Kormányzó egy egyszerű emlékeztető számunkra, hogy többé nem vagyunk szabad emberek.",,知事は俺達に自由はないと思い出させる象徴さ。,모렐 총독은 우리들이 자유롭게 남들을 도울 수 없는 이유 중 하나이기도 하다네.,De gouverneur herinnert ons er eenvoudigweg aan dat we geen vrije mensen meer zijn.,"Gubernator jest dla nas przypomnieniem, że już nie jesteśmy wolnymi ludźmi.",O Governador é um simples lembrete para nós de que não somos mais um povo livre.,,Guvernatorul e un simplu memento că nu mai suntem oameni liberi.,"Губернатор — живое напоминание, что мы больше не свободные люди.",Гувернер нам је једноставан подсетник да ми више нисмо слободни људи. -Come back when you get some gold.,TXT_RNO0_SCRIPT02_D27288_COMEB,,,,"Vrať se, až budeš mít trochu zlata.","Komm zurück, wenn du etwas Gold hast.",,,Vuelve cuando hayas obtenido algo de oro.,,,Revenez quand vous avez de l'argent.,"Majd akkor térj vissza, ha szeretél egy kis aranyat.",,銭を一杯分持って戻ってきな。,골드가 더 있다면 더 알려주지.,Kom terug als je wat goud krijgt.,Wróć kiedy będziesz miał więcej monet.,Volte quando tiver ouro.,,Revin-o când ai niște aur.,"Возвращайся, когда у тебя будет золото.",Врати се када имаш више златника. -"Well, you're asking a lot of questions for someone who's not trying to die. Make sure you don't go and get yourself killed, or worse.",TXT_DLG_SCRIPT02_D28804_WELLY,,,,"Na někoho, kdo se nesnaží zemřít, se hodně ptáš. Dej si pozor a nenech se zabít, nebo něco horšího.","Hmm, du stellst aber ziemlich viele Fragen für jemand der nicht versucht zu sterben. Lass dich nicht umbringen, oder schlimmeres.",,,"Bueno, estás haciendo muchas preguntas para ser alguien que no está tratando de morir. Asegúrate que no vayas a hacer que te maten o algo peor.",,,"Vous posez beaucoup de questions pour quelqu'un qui n'essaie pas de se faire tuer. Essayez donc de ne pas vous faire descendre, ou pire.","Figyelj, elég sok kérdést teszel fel, ahhoz képest, hogy elvileg nem akarsz meghalni. Igyekezz nem kinyiratni magad a továbbiakban, vagy rosszabb.",,"所で、アンタは死に行かない人達に +駆けつけてくるぞ。","안녕하신가 이방인이여, 자네는 이곳에서 처음 보는 얼굴이군. 내가 자네에게 공짜 조언을 해주지. 내가 자네라면 조심할 거야. 오더는 자유의지를 용납하지 않아. 그리고 그들의 정의는 신속하지.","Hallo vreemdeling, ik heb je hier nog niet eerder gezien. Laat me je een stukje gratis advies geven. Ik zou voorzichtig zijn als ik jou was. De Orde tolereert geen vrije wil en hun gerechtigheid is snel.","Hei, fremmede, jeg har ikke sett deg her før. La meg gi deg et gratis råd. Jeg ville vært forsiktig hvis jeg var deg. Ordenen tolererer ikke fri vilje, og deres rettferdighet er rask.","Witaj nieznajomy, nigdy cie tu wcześniej nie widziałem. Dam ci darmową radę. Na twoim miejscu bym uważał. Zakon nie toleruje wolnej woli, a ich prawo działa prędko.","Olá, forasteiro. Nunca vi você por aqui antes. Deixa eu te dar um conselho de graça. Eu tomaria cuidado se eu fosse você. A Ordem não tolera livre arbítrio e a justiça deles é rápida.",,"Salutări străine, nu te-am mai văzut pe-aici. Permite-mi să-ți dau un sfat. Aș fi grijuliu în locul tău. Ordinul nu tolerează voința liberă, iar justiția lor e rapidă.","Привет, незнакомец. Что-то я не видел тебя тут раньше. Позволь дать тебе бесплатный совет: я на твоём месте был бы поосторожнее. Орден не терпит неповиновения, и они скоры на суд.",,"Hej främling, jag har inte sett dig här förut. Låt mig ge dig ett gratis råd. Jag skulle vara försiktig om jag var du. Orden tolererar inte fri vilja och deras rättvisa är snabb.","Merhaba yabancı, seni daha önce buralarda görmemiştim. Sana bedava bir tavsiye vereyim. Yerinde olsam dikkatli olurdum. Tarikat'ın özgür iradeye tahammülü yoktur ve adaletleri çok hızlıdır." +What's the word?,TXT_RPLY0_SCRIPT02_D25772_WHATS,〃,,,Nějaké zvěsti?,Hvad er ordet?,Was erzählt man sich so?,,Kion oni diras ĉi tie?,¿Qué se dice por aquí?,,Mikä on päivän sana?,C'est quoi la rumeur?,Mi a hír?,Che si dice in giro?,他には?,무슨 뜻이죠?,Wat is het woord?,Hva heter det?,Jakieś wieści?,Quais são as últimas?,,Ai vreo veste?,Есть новости?,,Vad heter det?,Neydi o kelime? +The word is... The sewers hold more than just rats and robots.,TXT_RYES0_SCRIPT02_D25772_THEWO,〃,,,Kolují zvěsti... že stoky ukrývají víc než jen krysy a roboty.,Ordet er... Kloakkerne rummer mere end bare rotter og robotter.,"Man erzählt sich, dass die Kanalisation mehr als Ratten und Roboter zu bieten hat.",,"Oni diras... ke en la kloako +ne estas nur ratoj kaj robotoj.","Se dice... que en las alcantarillas +hay más que solo ratas y robots.",,Sana on... että viemärit pitävät sisällään muutakin kuin vain rottia ja robotteja.,La rumeur est.. Que les égouts cachent quelque chose de plus gros que des rats et des robots.,Az a hír...hogy a kanális nem csak patkányokat és robotokat rejteget.,In giro si dice che... Le fogne contengono molto di più che ratti e robot.,他は...下水道には鼠やロボが沢山だ。,"무슨 말이냐 하면, 하수도 안에는 시궁쥐만 있는 게 아니라 로봇들도 숨어 있다는 거지.",Het woord is.... De riolen bevatten meer dan alleen ratten en robots.,Ordet er... Kloakken rommer mer enn bare rotter og roboter.,"Wieści są takie, że... kanały skrywają coś więcej niż tylko szczury i roboty.",As últimas são... Que os esgotos abrigam mais do que apenas ratos e robôs.,,Vestea e că... Canalele ascund mai mult decât roboți și șoareci.,"Говорят, в канализации водятся не только крысы и роботы.",,Ordet är... Kloakerna innehåller mer än bara råttor och robotar.,Kelime şu. Lağımlarda fareler ve robotlardan daha fazlası var. +What can I do for you now?,TXT_DLG_SCRIPT02_D27288_WHATC,〃,,,Co pro vás můžu udělat teď?,Hvad kan jeg gøre for dig nu?,Was kann ich jetzt für dich tun?,,Kion mi faru por vi?,¿Qué puedo hacer por ti?,,"No niin, miten voin olla teille avuksi?",Que puis-je faire pour vous?,Mit tehetek ma Önért?,E ora cosa posso fare per te?,何か用か?,이제 자네에게 무엇을 해드릴까?,Wat kan ik nu voor je doen?,Hva kan jeg gjøre for deg nå?,Co mogę dla ciebie zrobić?,O que posso fazer por você agora?,,Cu ce te mai pot ajuta?,Тебе что-нибудь нужно?,,Vad kan jag göra för dig nu?,Şimdi senin için ne yapabilirim? +More info.,TXT_RPLY0_SCRIPT02_D27288_MOREI,〃,,,Další informace,Mere info.,Mehr Informationen.,,Pliaj informoj,Más información,,Muuta tietoa.,Plus d'infos.,Több információt.,Altre informazioni.,話のネタ。,더 많은 정보를 주세요.,Meer info.,Mer informasjon.,Więcej informacji.,Mais informações.,,Mai multe informații.,Расскажи больше,,Mer information.,Daha fazla bilgi. +The Governor is a simple reminder to us that we aren't free people anymore.,TXT_RYES0_SCRIPT02_D27288_THEGO,〃,,,"Náš guvernér je hezkou přípomínkou toho, že už nejsme svobodní.","Guvernøren er en simpel påmindelse til os om, at vi ikke længere er frie mennesker.","Der Gouverneur ist eine einfache Erinnerung daran, das wir keine freien Menschen mehr sind.",,"La registo ekzistas +nur por memorigi, ke +ne plu estas libereco.","El gobernador solo es +un recordatorio de +que ya no somos libres.",,"Kuvernööri toimii meille pienenä muistutuksena, ettemme ole enää vapaita ihmisiä.",Le gouverneur n'est qu'un exemple parmi d'autres pour nous montrer que ne nous somme plus un peuple libre.,"A Kormányzó egy egyszerű emlékeztető számunkra, hogy többé nem vagyunk szabad emberek.",Il governatore serve solo a farci ricordare che non siamo più delle persone libere.,知事は俺達に自由はないと思い出させる象徴さ。,모렐 총독은 우리들이 자유롭게 남들을 도울 수 없는 이유 중 하나이기도 하다네.,De gouverneur herinnert ons er eenvoudigweg aan dat we geen vrije mensen meer zijn.,Guvernøren er en enkel påminnelse om at vi ikke er frie mennesker lenger.,"Gubernator jest dla nas przypomnieniem, że już nie jesteśmy wolnymi ludźmi.",O Governador é um simples lembrete para nós de que não somos mais um povo livre.,,Guvernatorul e un simplu memento că nu mai suntem oameni liberi.,"Губернатор — живое напоминание, что мы больше не свободные люди.",,Guvernören är en enkel påminnelse om att vi inte längre är fria människor.,Vali bize artık özgür insanlar olmadığımızı hatırlatıyor. +Come back when you get some gold.,TXT_RNO0_SCRIPT02_D27288_COMEB,〃,,,"Vrať se, až budeš mít trochu zlata.","Kom tilbage, når du får noget guld.","Komm zurück, wenn du etwas Gold hast.",,"Revenu kiam vi havos +sufiĉe da oro.","Vuelve cuando +tengas suficiente oro.",,"Palatkaa takaisin, kun teillä on kultaa.",Revenez quand vous avez de l'argent.,"Majd akkor térj vissza, ha szeretél egy kis aranyat.",Ritorna quando avrai più oro.,銭を一杯分持って戻ってきな。,골드가 더 있다면 더 알려주지.,Kom terug als je wat goud krijgt.,Kom tilbake når du har gull.,Wróć kiedy będziesz miał więcej monet.,Volte quando tiver ouro.,,Revin-o când ai niște aur.,"Возвращайся, когда у тебя будет золото.",,Kom tillbaka när du får lite guld.,Biraz altın bulduğunda geri gel. +"Well, you're asking a lot of questions for someone who's not trying to die. Make sure you don't go and get yourself killed, or worse.",TXT_DLG_SCRIPT02_D28804_WELLY,〃,,,"Na někoho, kdo se nesnaží zemřít, se hodně ptáš. Dej si pozor a nenech se zabít, nebo něco horšího.","Du stiller mange spørgsmål af en, der ikke prøver at dø. Sørg for, at du ikke går hen og bliver dræbt, eller det der er værre.","Hmm, du stellst aber ziemlich viele Fragen für jemand der nicht versucht zu sterben. Lass dich nicht umbringen, oder schlimmeres.",,"Nu, vi faras multe da demandoj por esti iu, kiu ne intencas morti. Certiĝu, ke vi ne kaŭzos al vi mortigon... aŭ ion pli malbonan.","Bueno, estás haciendo muchas preguntas para ser alguien que no está tratando de morir. Asegúrate de que no vayas a hacer que te maten... o algo peor.",,"Kylläpäs te kysytte paljon ollaksenne joku, joka ei yritä tappaa itsensä. Pitäkää vain huoli, ettei niin edelleenkään käy, tai pahemmin.","Vous posez beaucoup de questions pour quelqu'un qui n'essaie pas de se faire tuer. Essayez donc de ne pas vous faire descendre, ou pire.","Figyelj, elég sok kérdést teszel fel, ahhoz képest, hogy elvileg nem akarsz meghalni. Igyekezz nem kinyiratni magad a továbbiakban, vagy rosszabb.","Lo sai, fai davvero tante domande per uno che cerca di sopravvivere. Fai attenzione a non farti uccidere, o peggio...","所で、アンタは死に行かない人達に 聞き回ってる様だが。悪いことは言わねえ、 -あんまし死に急ぐんじゃねえぞ。",죽지 않으려고 발버둥 치듯이 질문을 많이 하는구먼. 무장한 곳에 무모하게 가서 죽지나 말게.,"Nou, je stelt veel vragen voor iemand die niet probeert te sterven. Zorg ervoor dat je niet gaat en jezelf niet dood laat gaan, of erger nog.","Cóż, zadajesz dużo pytań jak na kogoś, kto próbuje nie zginąć. Upewnij się, że nie dasz się zabić jak pójdziesz. Lub gorzej.","Bom, você está fazendo um monte de perguntas pra alguém que não está tentando morrer. Procure não acabar sendo morto por aí, ou coisa pior.",,"Păi, pui multe întrebări pentru cineva care încearcă să nu moară. Ai grijă să nu ajungi un om mort, sau mai rău.","Ты задаёшь слишком много вопросов для того, кто не хочет сдохнуть. Перед тем, как выйти отсюда, проверь своё оружие.","Па, постаљате много питања за некога ко не жели да умре. Побрините се да не идете и погинете, или горе. " -More info.,TXT_RPLY0_SCRIPT02_D28804_MOREI,,,,Další informace,Mehr Informationen.,,,Más información.,,,Plus d'infos.,Több infót.,,話のネタ。,정보를 좀 더 알려주시오.,Meer info.,Więcej informacji.,Mais informações.,,Mai multe informații.,Говори дальше,Више информације. -There's more to the Order than meets the eye.,TXT_RYES0_SCRIPT02_D28804_THERE,,,,"Za Řádem se toho skrývá víc, než se zdá.",An dem Orden ist mehr dran als man auf den ersten Blick denkt.,,,Hay más de la Orden de lo que parece.,,,L'Ordre cache bien son jeu.,"Több van a Rend mögött, mint amit a szemünk lát.",,オーダーは見えてる以上に強大だ。,오더의 뒤에는 더 많은 것들이 숨겨져 있다네. 비밀 같은 것들 말일세.,De Orde heeft meer te bieden dan je op het eerste gezicht zou denken.,"Zakonu jest więcej, niż się wydaje.",Há mais sobre a Ordem do que aparenta.,,Este ceva mai mult la Ordin decât ceea ce se poate vedea cu ochiul liber.,"Орден — нечто большее, чем кажется.",Има више од Одреда него што се види -We'll talk when you get gold!,TXT_RNO0_SCRIPT02_D28804_WELLT,,,,"Popovídáme si, když budeš mít zlato!","Wir werden reden, wenn du Gold hast!",,,¡Hablaremos cuando traigas oro!,,,On parlera quand tu auras des sous!,"Majd beszélünk, ha lesz aranyad.",,銭を持ってたら話すさ!,골드를 더 가져오면 의논을 시작해보지.,We praten wel als je goud krijgt!,Pomówimy jeśli masz złoto.,Conversaremos quando você tiver ouro!,,Vorbim când aduci aur!,"Поговорим, когда принесешь золото!",Разговараћемо када имаш златнике! -"That's it friend, the well of knowledge has run dry. I've told you more than I should have anyway. Good luck... And don't come back.",TXT_DLG_SCRIPT02_D30320_THATS,,,,"A to je vše, příteli, studnice mé moudrosti vyschla. Stejně jsem ti řekl víc, než jsem měl. Hodně štěstí... a už se nevracej.","Das war's mein Freund, der Brunnen der Weisheit ist versiegt. Ich habe dir sowieso mehr erzählt als ich sollte. Viel Glück... und komm nicht zurück.",,,Ya está amigo. El pozo del conocimiento se ha secado. De todas formas te he dicho más de lo que debería. Buena suerte ... y no vuelvas.,,,"Eh bien voilà, mon ami, le puits de la connaîssance s'est enfin asséché.. Je t'en ai dit plus que je n'aurai du, de toutes manières! Bonne chance.. Et ne reviens pas!","Ez az, barátom. A tudás kútja kiszáradt. Többször mondtam neked kelleténél amúgy. Sok szerencsét... És ne gyere vissza.",,"これはこれは親友、心得の瓶は切らしてるぞ。 +あんまし死に急ぐんじゃねえぞ。",죽지 않으려고 발버둥 치듯이 질문을 많이 하는구먼. 무장한 곳에 무모하게 가서 죽지나 말게.,"Nou, je stelt veel vragen voor iemand die niet probeert te sterven. Zorg ervoor dat je niet gaat en jezelf niet dood laat gaan, of erger nog.",Du stiller mange spørsmål til å være en som ikke prøver å dø. Pass på at du ikke blir drept eller det som verre er.,"Cóż, zadajesz dużo pytań jak na kogoś, kto próbuje nie zginąć. Upewnij się, że nie dasz się zabić jak pójdziesz. Lub gorzej.","Bom, você está fazendo um monte de perguntas pra alguém que não está tentando morrer. Procure não acabar sendo morto por aí, ou coisa pior.",,"Păi, pui multe întrebări pentru cineva care încearcă să nu moară. Ai grijă să nu ajungi un om mort, sau mai rău.","Ты задаёшь слишком много вопросов для того, кто не хочет сдохнуть. Убедись, что не идёшь на верную смерть или чего похуже.",,"Du ställer många frågor för någon som inte försöker dö. Se till att du inte går och blir dödad, eller värre.",Ölmeye çalışmayan biri için çok fazla soru soruyorsun. Gidip kendini öldürtmediğinden ya da daha kötüsünü yapmadığından emin ol. +More info.,TXT_RPLY0_SCRIPT02_D28804_MOREI,〃,,,Další informace,Mere info.,Mehr Informationen.,,Pliaj informoj,Más información,,Muuta tietoa.,Plus d'infos.,Több infót.,Altre informazioni.,話のネタ。,정보를 좀 더 알려주시오.,Meer info.,Mer informasjon.,Więcej informacji.,Mais informações.,,Mai multe informații.,Говори дальше.,,Mer information.,Daha fazla bilgi. +There's more to the Order than meets the eye.,TXT_RYES0_SCRIPT02_D28804_THERE,〃,,,"Za Řádem se toho skrývá víc, než se zdá.","Der er mere i Ordenen, end man umiddelbart tror.",An dem Orden ist mehr dran als man auf den ersten Blick denkt.,,"Estas pli pri La Ordeno, +ol kiom ili ŝajnigas.","Hay más de La Orden +de lo que aparenta.",,"Veljeskunta ei ole sitä, miltä päältä päin näyttää.",L'Ordre cache bien son jeu.,"Több van a Rend mögött, mint ami a külső sejtet.",C'è sotto molto di più sull'Ordine rispetto a come possa sembrare.,オーダーは見えてる以上に強大だ。,오더의 뒤에는 더 많은 것들이 숨겨져 있다네. 비밀 같은 것들 말일세.,De Orde heeft meer te bieden dan je op het eerste gezicht zou denken.,Det er mer ved Ordenen enn det som møter øyet.,"Zakonu jest więcej, niż się wydaje.",Há mais sobre a Ordem do que aparenta.,,Este ceva mai mult la Ordin decât ceea ce se poate vedea cu ochiul liber.,"Орден больше, чем кажется.",,Det finns mer i Orden än vad man kan tro.,Tarikat'ta göründüğünden daha fazlası var. +We'll talk when you get gold!,TXT_RNO0_SCRIPT02_D28804_WELLT,〃,,,"Popovídáme si, když budeš mít zlato!","Vi taler sammen, når du får guld!","Wir werden reden, wenn du Gold hast!",,"Ni parolos kiam +vi alportos oron!",¡Hablamos cuando traigas oro!,,"Puhutaan, kun sinulla on kultaa.",On parlera quand tu auras des sous!,"Majd beszélünk, ha lesz aranyad.",Ne parleremo quando avrai più soldi!,銭を持ってたら話すさ!,골드를 더 가져오면 의논을 시작해보지.,We praten wel als je goud krijgt!,Vi snakkes når du får gull!,Pomówimy jeśli masz złoto.,Conversaremos quando você tiver ouro!,,Vorbim când aduci aur!,"Поговорим, когда принесёшь золото!",,Vi pratar när du får guld!,Altın aldığında konuşuruz! +"That's it friend, the well of knowledge has run dry. I've told you more than I should have anyway. Good luck... And don't come back.",TXT_DLG_SCRIPT02_D30320_THATS,〃,,,"A to je vše, příteli, studnice mé moudrosti vyschla. Stejně jsem ti řekl víc, než jsem měl. Hodně štěstí... a už se nevracej.","Det var det, ven, vidensbrønden er tørlagt. Jeg har alligevel fortalt dig mere, end jeg burde have gjort. Held og lykke... Og kom ikke tilbage.","Das war's mein Freund, der Brunnen der Weisheit ist versiegt. Ich habe dir sowieso mehr erzählt als ich sollte. Viel Glück... und komm nicht zurück.",,"Jen ĉio, amiko, la fonto de scio sekiĝis. Malgraŭ tio, mi diris al vi pli ol tiom, kiom mi devus. Ŝancon... kaj ne revenu.","Ya está, amigo, el pozo del conocimiento ya se ha secado. De todas formas ya te he dicho más de lo que debería. Suerte... y no vuelvas.","Ya está, amigo, el pozo del conocimiento ya se secó. De todas formas ya te dije más de lo que debería. Suerte... y no vuelvas.","Siinä kaikki, ystävä; tiedon lähde on ehtynyt. Olen kertonut sinulle enemmän kuin olisin edes saanutkaan. Onnea matkaan... äläkä tule takaisin.","Eh bien voilà, mon ami, le puits de la connaîssance s'est enfin asséché.. Je t'en ai dit plus que je n'aurai du, de toutes manières! Bonne chance.. Et ne reviens pas!","Ez az, barátom. A tudás kútja kiszáradt. Többször mondtam neked kelleténél amúgyis. Sok szerencsét... És ne gyere vissza.","È tutto, amico, ho esaurito le cose che avevo da dirti. Ti ho già detto più di quanto avrei dovuto. Buona fortuna... e non tornare più.","これはこれは親友、心得の瓶は切らしてるぞ。 とにかく俺が知ってる話はこれで全部だ。 -頑張りな...それともう来なくていいぞ。","친구여... 안타깝게도 지식의 우물은 이제 고갈됐다네. 내가 알려줄 수 있는 걸 다 알려줬거든. 건투를 빌겠네, 그리고 다시 돌아오지는 말고.","Dat is het vriend, de bron van kennis is uitgeput. Ik heb je meer verteld dan ik zou moeten hebben. Veel succes.... En kom niet terug.","To wszystko kolego, studnia wiedzy wyschła. Powiedziałem ci więcej niż powinienem. Powodzenia... I nie wracaj.","Isso é tudo, amigo. O poço de conhecimento está seco. Já te contei tudo o que eu deveria, de qualquer forma. Boa sorte... E não volte mais aqui.",,"Asta a fost prietene, fântâna cunoștiințelor a secat. Ți-am spus mai multe decât ar fi trebuit oricum. Baftă... Și nu te întoarce.","Это всё, дружище. Кладезь мудрости исчерпан. Я и так рассказал тебе больше, чем следовало. Удачи... и не возвращайся.","То је то пријатељу, бунар мудрости се исушио. Свакако сам ти рекао више него што сам требао. Срећно... И немој се враћати." -"Hey, I'm only here in case of an emergency. If the core breaches, then I make sure no one gets in... or out.",TXT_DLG_SCRIPT02_D31836_HEYIM,,,,"Hej, já jsem tu jen pro případ nouze. Jestli se něco stane s jádrem, zajistím, že se nikdo nedostane dovnitř... ani ven.","Hey, ich bin nur für den Fall eines Notfalls hier. Im Falle eines Kernbruchs sorge ich dafür das niemand rein kommt... oder raus.",,,"Oye, sólo estoy aquí en caso de una emergencia. Si el núcleo se rompe, entonces me aseguro de que nadie entre... o salga.",,,"Hé, je ne suis là qu'en cas d'urgence. Si le coeur a une brèche, il faut que je fasse en sorte que rien ne rentre.. Ou ne sorte.","Hé, én csak vészhelyzet esetén vagyok itt. Ha a mag kitör, akkor elintázem, hogy senki ne jöjjön be... vagy ki.",,"おう、俺は緊急時の為にここにいる。 +頑張りな...それともう来なくていいぞ。","친구여... 안타깝게도 지식의 우물은 이제 고갈됐다네. 내가 알려줄 수 있는 걸 다 알려줬거든. 건투를 빌겠네, 그리고 다시 돌아오지는 말고.","Dat is het vriend, de bron van kennis is uitgeput. Ik heb je meer verteld dan ik zou moeten hebben. Veel succes.... En kom niet terug.","Det var det, min venn. Kunnskapens brønn har tørket ut. Jeg har fortalt deg mer enn jeg burde uansett. Lykke til... Og ikke kom tilbake.","To wszystko kolego, studnia wiedzy wyschła. Powiedziałem ci więcej niż powinienem. Powodzenia... I nie wracaj.","Isso é tudo, camarada. O poço de conhecimento está seco. Já te contei tudo o que eu deveria, de qualquer forma. Boa sorte... E não volte mais aqui.",,"Asta a fost prietene, fântâna cunoștiințelor a secat. Ți-am spus mai multe decât ar fi trebuit oricum. Baftă... Și nu te întoarce.","Это всё, дружище. Кладезь мудрости исчерпана. Я и так рассказал тебе больше, чем следовало. Удачи... и не возвращайся.",,"Det var det vän, kunskapsbrunnen har tagit slut. Jag har berättat mer än jag borde ha gjort i alla fall. Lycka till... Och kom inte tillbaka.","Bu kadar dostum, bilgi kuyusu kurudu. Zaten sana söylemem gerekenden fazlasını söyledim. İyi şanslar. Ve sakın geri gelme." +"Hey, I'm only here in case of an emergency. If the core breaches, then I make sure no one gets in... or out.",TXT_DLG_SCRIPT02_D31836_HEYIM,MAP02: Power Station guard.,,,"Hej, já jsem tu jen pro případ nouze. Jestli se něco stane s jádrem, jsem tu, abych zajistil, že se nikdo nedostane dovnitř... ani ven.","Hey, jeg er her kun i nødstilfælde. Hvis kernen bryder sammen, så sørger jeg for, at ingen kommer ind... eller ud.","Hey, ich bin nur für den Fall eines Notfalls hier. Im Falle eines Kernbruchs sorge ich dafür das niemand rein kommt... oder raus.",,"Mi nur estas krizokaza gardisto: se la kerno rompiĝus, mi certiĝus, ke neniu eniru... aŭ eliru.","Solo estoy aquí en caso de emergencia: si el núcleo se rompe, me aseguro de que nadie entre... o salga.",,"Hei, olen täällä vain hätätilanteen varalta. Jos ytimeen tulee murtuma, tehtäväni on varmistaa, ettei kukaan pääse sisään... tai ulos.","Hé, je ne suis là qu'en cas d'urgence. Si le coeur a une brèche, il faut que je fasse en sorte que rien ne rentre.. Ou ne sorte.","Hé, én csak vészhelyzet esetére vagyok itt. Ha a mag kitör, akkor elintézem, hogy senki ne jöjjön be... vagy ki.","Ehi, io sono qua solo in caso di emergenza. Se c'è una falla nel nucleo, allora mi assicuro che nessuno possa entrare... o uscire.","おう、俺は緊急時の為にここにいる。 コアが破壊されないか、誰が入っているかを -確認している...出ていくのもな。","이봐, 난 비상사태를 대비해서 여기에 있는 거라고. 만약 중심부가 파괴되면, 그 누구도 들어올 수 없게 막을 거야... 도망치는 사람도 포함해서.","Hé, ik ben hier alleen in geval van nood. Als de kern breekt, dan zorg ik ervoor dat er niemand binnenkomt... of buitenkomt.","Hej, jestem tu tylko w razie wypadku. Jeśli rdzeń zostanie naruszony, wtedy upewniam się, że nikt tam nie wejdzie... lub stamtąd nie wyjdzie.","Ei, só estou aqui em caso de uma emergência. Se o núcleo se romper, preciso garantir que ninguém entre... ou saia.",,"Hei, sunt aici doar în caz de urgență. Dacă apare o breșă în nucleu, mă asigur că nimeni nu intră... sau iese.","Слушай, меня сюда поставили на всякий случай. Если реактор даст течь, я позабочусь, чтобы никто не вошёл... и не вышел.","Хеј, ја сам овде само у случају нужде. Ако се језгро пробије, онда се ја постарам да нико не уђе... или изађе." -"Watch your step, peasant!",TXT_DLG_SCRIPT02_D33352_WATCH,,,,"Dávej si na sebe pozor, poddaný! -","Pass auf wo du hintrittst, Bauer!",,,"¡Cuida por donde caminas, campesino!",,,"Regarde où tu va, paysan!","Nézz a lábad elé, jobbágy!",,気を付けろ、田舎モン!,"똑바로 보고 다녀라, 시민!","Kijk uit waar je loopt, boer!",Uważaj jak leziesz kmiocie!,"Cuida por onde anda, plebeu!",,"Ai grijă pe unde calci, plebeule!","Смотри, куда прёшь, рабочий!","Пази се, сељаку!" -We're going to kill you! ,TXT_DLG_SCRIPT02_D34868_WEREG,,,,Zabijeme tě!,Wir werden dich umbringen!,,,"¡Vamos a matarte! -",,,On va te descendre!,Megdöglesz!,,お前を粛正する!,우린 널 죽일거야!,We gaan je vermoorden!,Zabijemy cię!,Nós vamos matar você!,,O să te omorâm!,Готовься к смерти!,Спреми се да умреш! -Who in the blazes are you? No one's supposed to be loitering about in this area!,TXT_DLG_SCRIPT02_D36384_WHOIN,,,,Kdo k čertu jsi? Tady se nikdo nemá potloukat!,Wer zum Teufel bist du? Hier soll doch eigentlich niemand rumschnüffeln!,,,¿Quién diantres eres tú? ¡Se supone que nadie debería de estar merodeando por esta área!,¿Quién demonios eres tú? ¡Se supone que nadie debería de estar merodeando por esta área!,,Qu'est ce que c'est ça? Que faites vous ici? Personne n'est sensé se trouver dans cette zone!,Te meg ki az Isten nyila vagy? Senki sem csavaroghat ebben a körzetben.,,"誰だお前は?この区域を立ち入ることは +確認している...出ていくのもな。","이봐, 난 비상사태를 대비해서 여기에 있는 거라고. 만약 중심부가 파괴되면, 그 누구도 들어올 수 없게 막을 거야... 도망치는 사람도 포함해서.","Hé, ik ben hier alleen in geval van nood. Als de kern breekt, dan zorg ik ervoor dat er niemand binnenkomt... of buitenkomt.","Hei, jeg er bare her i nødstilfeller. Hvis kjernen brister, sørger jeg for at ingen kommer inn... eller ut.","Hej, jestem tu tylko w razie wypadku. Jeśli rdzeń zostanie naruszony, wtedy upewniam się, że nikt tam nie wejdzie... lub stamtąd nie wyjdzie.","Ei, só estou aqui em caso de uma emergência. Se o núcleo se romper, preciso garantir que ninguém entre... ou saia.",,"Hei, sunt aici doar în caz de urgență. Dacă apare o breșă în nucleu, mă asigur că nimeni nu intră... sau iese.","Слушай, меня сюда поставили на всякий случай. Если целостность ядра нарушится, я позабочусь, чтобы никто не вошёл... и не вышел.",,"Jag är bara här i nödfall. Om kärnan bryter igenom, ser jag till att ingen kommer in... eller ut.","Hey, ben sadece acil bir durumda buradayım. Çekirdek kırılırsa, kimsenin içeri girmediğinden emin olurum... ya da dışarı." +"Watch your step, peasant!",TXT_DLG_SCRIPT02_D33352_WATCH,MAP02: Rust guards.,,,"Dávej si na sebe pozor, poddaný! +","Pas på hvor du træder, bonde!","Pass auf wo du hintrittst, Bauer!",,"Atentu tie, kie vi piediras, kampulo!","¡Cuida por donde caminas, campesino!","¡Cuidado por donde caminas, campesino!","Katso, mihin astut, maallikko!","Regarde où tu va, paysan!","Nézz a lábad elé, paraszt!",Guarda dove metti i piedi!,気を付けろ、田舎モン!,"똑바로 보고 다녀라, 시민!","Kijk uit waar je loopt, boer!","Se deg for, bonde!",Uważaj jak leziesz kmiocie!,"Cuida por onde anda, plebeu!",,"Ai grijă pe unde calci, plebeule!","Смотри, куда прёшь, холоп!",,"Se upp, bonde!","Adımına dikkat et, köylü!" +We're going to kill you! ,TXT_DLG_SCRIPT02_D34868_WEREG,MAP02: Gray guards.,,,Zabijeme tě!,Vi slår dig ihjel!,Wir werden dich umbringen!,,Ni mortigos vin!,¡Te vamos a matar!,,Tapamme sinut!,On va te descendre!,Megdöglesz!,Adesso ti ammazziamo!,お前を粛正する!,우린 널 죽일거야!,We gaan je vermoorden!,Vi skal drepe deg!,Zabijemy cię!,Vamos matar você!,,O să te omorâm!,Готовься к смерти!,,Vi kommer att döda dig!,Seni öldüreceğiz! +Who in the blazes are you? No one's supposed to be loitering about in this area!,TXT_DLG_SCRIPT02_D36384_WHOIN,MAP02: Green guard.,,,Kdo k čertu jsi? Tady se nikdo nemá potloukat!,Hvem i helvede er du? Ingen skal slentre rundt i dette område!,Wer zum Teufel bist du? Hier soll doch eigentlich niemand rumschnüffeln!,,Kiu diable vi estas? Neniu supozeble devas vagi ĉi tie!,¿Quién diantres eres tú? ¡Se supone que nadie tiene que estar merodeando por esta área!,¿Quién demonios eres tú? ¡Se supone que nadie tiene que estar curioseando por esta zona!,Kuka ihme sinä olet? Kenelläkään ei ole lupaa kuljeksia tällä alueella!,Qu'est ce que c'est ça? Que faites vous ici? Personne n'est sensé se trouver dans cette zone!,Te meg ki az Isten nyila vagy? Senki sem csavaroghat ebben a körzetben.,E tu chi diavolo saresti? Nessuno dovrebbe aggirarsi in quest'area!,"誰だお前は?この区域を立ち入ることは 許されていないぞ! -",너는 누구지? 아무도 이 지역에서 어슬렁거릴 수 없다!,Wie ben jij in vredesnaam? Niemand wordt verondersteld op dit gebied rond te hangen!,Kim u diaska jesteś? Nikt nie powinien się tu włóczyć!,Quem diabos é você? Não pode ficar perambulando por aqui!,,Cine naiba mai ești tu? Nimeni nu ar trebui să zăbovească în zona asta!,"Кто ты, чёрт побери, такой? Никому не разрешено тут шляться!",Ко си па сад ти? Нико не би требао да лута у овој области! -"You there, nobody's allowed in here. Move along!",TXT_DLG_SCRIPT02_D37900_YOUTH,,,,"Hej ty, sem nikdo nesmí. Jdi dál!","Hey, du da. Hier darfst du nicht rein. Geh weiter!",,,"¡Oye tú! No está permitido que estés aquí, ¡Muévete!",,,"Vous, là, personne n'est autorisé à traîner ici, dégagez!","Te ott, ide senki sem jöhet be, kotródj!",,お前は許可していないぞ。立ち去れ!,"거기 너, 아무도 이곳에 지나갈 수 없다. 가던 길이나 가!","Jij daar, niemand mag hier naar binnen. Ga verder!","Ty tutaj, nikt nie ma prawa tu przebywać. Wynocha!","Ei você, não pode ficar aqui. Vá embora!",,"Tu, nimeni nu are voie aici. Mișcă-te!","Эй, ты! Никому не позволено тут ошиваться. Проваливай!","Хеј, ти, никоме није дозвољено да дође овђе. Мрдај одавде!" -Irale will set you right up!,TXT_DLG_SCRIPT02_D39416_IRALE,,,,Irale tě hned vyzbrojí!,Irale wird sich darum kümmern!,,,¡Irale te pondrá a punto!,¡Irale te pondrá listo!,,Irale a ce qu'il te faut!,,,イラールが貴方を手助けします!,여기 이롤리가 중요한 물품을 판매할 거야.,Irale zal je er goed in luizen!,Irale dobrze cię przygotuje!,O Irale vai te ajudar!,,Irale te va pregăti adecvat!,Ирэйл снабдит тебя всем необходимым!,Ирале ће се одмах постарати за вас! -I'm kinda a talent broker for the rebels. A guy who's as good as you could make a lot of gold... if you hooked up with the right people.,TXT_DLG_SCRIPT02_D40932_IMKIN,,,,Jsem takový hledač talentů pro rebely. Někdo tak dobrý jako ty by si mohl vydělat hodně zlata... pokud by se spojil s těmi správnými lidmi.,"Ich bin sowas wie ein Talentsucher für die Rebellen. Jemand, der so gut ist wie du kann hier eine Menge Gold verdienen... wenn du mit den richtigen Leuten in Verbindung stehst.",,,Soy algo así como un buscador de talento para los rebeldes. Alguien que es tan bueno como tú podría ganar mucho oro... Si te juntas con las personas adecuadas.,,,"Je suis une sorte de chasseur de têtes pour les rebelles. Un type comme toi pourrait se faire pas mal de fric... Avec les bons contacts, bien entendu.",,,"俺は反乱者への斡旋屋さ。才能を生かして +",너는 누구지? 아무도 이 지역에서 어슬렁거릴 수 없다!,Wie ben jij in vredesnaam? Niemand wordt verondersteld op dit gebied rond te hangen!,Hvem i all verden er du? Ingen har lov til å drive rundt i dette området!,Kim u diaska jesteś? Nikt nie powinien się tu włóczyć!,Mas quem é você? Não pode ficar perambulando por aqui!,,Cine naiba mai ești tu? Nimeni nu ar trebui să zăbovească în zona asta!,"Кто ты, чёрт побери, такой? Никому не разрешено тут шляться!",,Vem i helvete är du? Det är inte meningen att någon ska gå omkring i det här området!,Sen de kimsin be? Kimsenin bu bölgede dolaşmaması gerekiyor! +"You there, nobody's allowed in here. Move along!",TXT_DLG_SCRIPT02_D37900_YOUTH,MAP02: Golden guards.,,,"Hej ty, sem nikdo nesmí. Jdi dál!","Du der, ingen må komme ind her. Af sted med jer!","Hey, du da. Hier darfst du nicht rein. Geh weiter!",,"He, neniu rajtas esti ĉi tie. Plue movu vin!","Oye, este lugar está restringido. ¡Sigue moviéndote!",,"Sinä siellä, tämä on kielletty alue. Tiehesi!","Vous, là, personne n'est autorisé à traîner ici, dégagez!","Te ott, ide senki sem jöhet be, kotródj!","Ehi, tu! A nessuno è permesso di stare qua. Vai via!",お前は許可していないぞ。立ち去れ!,"거기 너, 아무도 이곳에 지나갈 수 없다. 가던 길이나 가!","Jij daar, niemand mag hier naar binnen. Ga verder!","Du der, ingen har lov til å være her. Gå videre!","Ty tutaj, nikt nie ma prawa tu przebywać. Wynocha!","Ei, você, não pode ficar aqui. Vá embora!",,"Tu, nimeni nu are voie aici. Mișcă-te!","Эй, ты! Никому не позволено тут ошиваться. Проваливай!",,"Du där, ingen får komma in här. Flytta på er!","Sen oradaki, kimsenin buraya girmesine izin yok. İlerleyin!" +Irale will set you right up!,TXT_DLG_SCRIPT02_D39416_IRALE,MAP02: Irale's shop.,,,Irale tě hned vyzbrojí!,Irale vil sætte dig på plads!,Irale wird sich darum kümmern!,,"Irale vendos al vi ĉion, kion vi bezonas!",¡Irale te venderá lo necesario!,¡Irale te va a vender lo necesario!,Irale järkkää sinulle varusteet!,Irale a ce qu'il te faut!,Irale majd ellát.,Irale ti darà quello che ti serve!,イラールが貴方を手助けします!,여기 이롤리가 중요한 물품을 판매할 거야.,Irale zal je er goed in luizen!,Irale skal ordne opp for deg!,Irale dobrze cię przygotuje!,O Irale vai te ajudar!,,Irale te va pregăti adecvat!,Ирэйл снабдит тебя всем необходимым!,,Irale kommer att sätta dig på plats!,İrale seni hemen ayarlayacak! +I'm kinda a talent broker for the rebels. A guy who's as good as you could make a lot of gold... if you hooked up with the right people.,TXT_DLG_SCRIPT02_D40932_IMKIN,MAP02: Harris.,,,Jsem takový hledač talentů pro rebely. Někdo tak dobrý jako ty by si mohl vydělat hodně zlata... pokud by se spojil s těmi správnými lidmi.,"Jeg er en slags talentmægler for oprørerne. En fyr, der er lige så god som dig, kan tjene en masse guld ... hvis du kommer i kontakt med de rigtige folk.","Ich bin sowas wie ein Talentsucher für die Rebellen. Jemand, der so gut ist wie du kann hier eine Menge Gold verdienen... wenn du mit den richtigen Leuten in Verbindung stehst.",,"Mi estas speco de talentul-serĉanto por la ribelantoj. Iu tiel lerta, kiel vi povus gajni multe da oro… se vi ligas vin kun la ĝustaj homoj.",Soy algo así como un cazatalentos para los rebeldes. Alguien tan bueno como tú podría ganar mucho oro... Si te juntas con las personas adecuadas.,,Olen eräänlainen kykyjenvälittäjä kapinallisille. Kaltaisesi kaveri voisi tienata paljon kultaa... oikeiden kumppaneiden kanssa.,"Je suis une sorte de chasseur de têtes pour les rebelles. Un type comme toi pourrait se faire pas mal de fric... Avec les bons contacts, bien entendu.","Egyfajta toborzó vagyok a lázadóknál. Egy ürge aki ilyen jó mint te, elég sok aranyat kereshet...ha megfelelő emberekkel jösz össze.",Sono sempre alla ricerca di persone talentuose per i ribelli. Una persona come te potrebbe ricevere molto oro... se fosse in contatto con le persone giuste.,"俺は反乱者への斡旋屋さ。才能を生かして 誰よりも儲けたいと思ってるなら... 相応しい人と関係を持つことさ。 -",난 반란군을 위한 일종의 재능 중개인이야. 당신만큼 좋은 사람이라면 많은 돈을 벌 수 있겠지... 당신이 제대로 된 사람들과 연결되어 있다면.,Ik ben een soort van een talent makelaar voor de rebellen. Een man die zo goed is als je zou kunnen maken veel goud .... als je aangesloten met de juiste mensen.,Jestem tak jakby pośrednikiem rebeliantów. Człowiek tak dobry jak ty może zarobić dużo pieniędzy... jeśli trzymasz z właściwymi ludźmi.,Sou tipo um olheiro de talentos para rebeldes. Um cara tão bom quanto você poderia fazer bastante grana... se você se juntar às pessoas certas.,,Sunt un fel de broker de talent pentru rebeli. Un tip la fel de priceput precum ești tu ar putea face bani frumoși... dacă s-ar lega de cine trebuie.,"Я, скажем так, вербовщик повстанцев. Такой парень, как ты, может неплохо заработать... если состыкуется с нужными людьми.",Ја сам као талентовани трговац за побуњенике. Човек који је добар као ти би могао да заради доста златника... Ако се спетља са правим људима. -I'm interested.,TXT_RPLY0_SCRIPT02_D40932_IMINT,,,,Mám zájem.,Ich bin interessiert.,,,Me interesa.,,,Je suis intéressé.,Érdekel.,,興味ある。,흥미롭군.,Ik ben geïnteresseerd.,Jestem zainteresowany.,Estou interessado.,,Sunt interesat.,Я заинтригован.,Заинтересован сам. -Screw the rebels!,TXT_RPLY1_SCRIPT02_D40932_SCREW,,,,Kašlu na rebely!,Scheiß auf die Rebellen!,,,¡Al demonio los rebeldes!,,,Je m'en fous des rebelles!,Francba a lázadókkal!,,何が反逆だ!,반란군은 집어치워!,De pot op met de rebellen!,Pieprzyć rebeliantów!,Que se danem os rebeldes!,,La naiba cu rebelii!,К чёрту повстанцев!,Јеби побуњенике! -"No, no second chance. Oh guards, kill him.",TXT_DLG_SCRIPT02_D42448_NONOS,,,,"Ne, žádná druhá šance. Á, stráže, zabte ho.","Nein, keine zweite Chance. Oh, Wachen, tötet ihn.",,,"No, no hay otra oportunidad. Oh guardias, mátenlo.",,,"Non, non, pas de deuxième chance. Gardes, tuez-le.","Nem, nincs második esély. Őrök, intézzétek el!",,"次はねえな。おぅガードの旦那、 -やっちゃってくだせえ。","안 돼, 두 번째 기회는 없어. 경비원, 저놈을 죽여.","Nee, geen tweede kans. Oh bewakers, dood hem.","Nie, nie będzie drugiej szansy. Oh... strażnicy, zabijcie go.","Não, sem segundas chances. Ah, guardas, matem ele.",,"Nu, nici o altă șansă. Oh gardienilor, omorâți-l.","Нет, никакого второго шанса. Эй, стража, убейте его.","Не, нема друге шансе. Стражари, побијте их." -Good choice. The Order's sanctuary by the river is their unofficial torture chamber. Hidden inside there's a golden chalice. You swipe it and reap your reward.,TXT_DLG_SCRIPT02_D43964_GOODC,,,,Dobrá volba. Svatyně Řádu u řeky je jejich tajná mučírna. Uvnitř je skrytý zlatý kalich. Ukradni ho a převezmi si svou odměnu.,Gute Wahl. Das Heiligtum des Ordens bei dem Fluss ist ihre inoffiziele Folterkammer. Darin versteckt ist ein goldener Kelch. Du klaust ihn und erntest deinen Lohn.,,,Buena elección. El santuario de la Orden junto al río es su cámara de tortura no oficial. Escondido adentro hay un cáliz dorado. Tráemelo y recoges tú recompensa.,,,Bon choix. Le sanctuaire de l'ordre près de la rivière est leur chambre torture.. officieusement. A l'intérieur se trouve un calice en or. Récupérez le et venez prendre votre récompense.,"Jó választás. A Rend Szentélye a folyónál az ő nem hivatalos kínzókamrájuk. Odabent elrejtve található egy arany kehely. Elcsened, és learatod a dicsőséged",,"良い判断だ。川沿いにあるオーダーの聖域は +",난 반란군을 위한 일종의 재능 중개인이야. 당신만큼 좋은 사람이라면 많은 돈을 벌 수 있겠지... 당신이 제대로 된 사람들과 연결되어 있다면.,Ik ben een soort van een talent makelaar voor de rebellen. Een man die zo goed is als je zou kunnen maken veel goud .... als je aangesloten met de juiste mensen.,Jeg er en slags talentmegler for opprørerne. En fyr som er så god som deg kan tjene mye gull... hvis du kommer i kontakt med de rette folkene.,Jestem tak jakby pośrednikiem rebeliantów. Człowiek tak dobry jak ty może zarobić dużo pieniędzy... jeśli trzymasz z właściwymi ludźmi.,Sou tipo um olheiro de talentos para rebeldes. Um cara tão bom quanto você poderia fazer bastante grana... se você se juntar às pessoas certas.,,Sunt un fel de broker de talent pentru rebeli. Un tip la fel de priceput precum ești tu ar putea face bani frumoși... dacă s-ar lega de cine trebuie.,"Я, скажем так, вербовщик повстанцев. Такой парень, как ты, может неплохо заработать... если состыкуется с нужными людьми.",,Jag är en slags talangmäklare för rebellerna. En kille som är lika bra som du kan tjäna en massa guld... om du kopplar ihop dig med rätt personer.,Ben asiler için yetenek simsarı sayılırım. Senin kadar iyi bir adam çok altın kazanabilir... eğer doğru insanlarla bağlantı kurarsan. +I'm interested.,TXT_RPLY0_SCRIPT02_D40932_IMINT,〃,,,Mám zájem.,Jeg er interesseret.,Ich bin interessiert.,,Tio interesas min.,Me interesa.,,Olen kiinnostunut.,Je suis intéressé.,Érdekel.,Sono interessato.,興味ある。,흥미롭군.,Ik ben geïnteresseerd.,Jeg er interessert.,Jestem zainteresowany.,Tenho interesse.,,Sunt interesat.,Я заинтригован.,,Jag är intresserad.,İlgileniyorum. +Screw the rebels!,TXT_RPLY1_SCRIPT02_D40932_SCREW,〃,,,Kašlu na rebely!,Skide være med rebellerne!,Scheiß auf die Rebellen!,,Fi al la ribelantoj!,¡Al demonio los rebeldes!,¡Al carajo los rebeldes!,Paskat kapinallisista!,Je m'en fous des rebelles!,Francba a lázadókkal!,Fanculo i ribelli!,何が反逆だ!,반란군은 집어치워!,De pot op met de rebellen!,Til helvete med opprørerne!,Pieprzyć rebeliantów!,Que se danem os rebeldes!,,La naiba cu rebelii!,К чёрту повстанцев!,,Skit i rebellerna!,Asilerin canı cehenneme! +"No, no second chance. Oh guards, kill him.",TXT_DLG_SCRIPT02_D42448_NONOS,〃,,,"Druhou šanci už nedostaneš. Á, stráže, zabte ho.","Nej, ingen ny chance. Åh vagter, dræb ham.","Nein, keine zweite Chance. Oh, Wachen, tötet ihn.",,"Ne, ne estas alia ŝanco. Gardistoj, mortigu lin!","No, no hay otra oportunidad. ¡Guardias, matadlo!","No, no hay otra oportunidad. ¡Guardias, mátenlo!","Ei, ei toista mahdollisuutta. Vartijat, tappakaa hänet.","Non, non, pas de deuxième chance. Gardes, tuez-le.","Nem, nincs második esély. Őrök, intézzétek el!","Nessuna seconda chance. Guardie, uccidetelo.","次はねえな。おぅガードの旦那、 +やっちゃってくだせえ。","안 돼, 두 번째 기회는 없어. 경비원, 저놈을 죽여.","Nee, geen tweede kans. Oh bewakers, dood hem.","Nei, ingen ny sjanse. Vakter, drep ham.","Nie, nie będzie drugiej szansy. Oh... strażnicy, zabijcie go.","Não, sem segundas chances. Ah, guardas, matem ele.",,"Nu, nici o altă șansă. Oh gardienilor, omorâți-l.","Нет, никакого второго шанса. Эй, стража, убейте его.",,"Nej, ingen andra chans. Åh vakter, döda honom.","Hayır, ikinci bir şans yok. Muhafızlar, öldürün onu." +Good choice. The Order's sanctuary by the river is their unofficial torture chamber. Hidden inside there's a golden chalice. You swipe it and reap your reward.,TXT_DLG_SCRIPT02_D43964_GOODC,〃,,,Dobrá volba. Svatyně Řádu u řeky je jejich tajná mučírna. Uvnitř je skrytý zlatý kalich. Ukradni ho a převezmi si svou odměnu.,Godt valg. Ordenens fristed ved floden er deres uofficielle torturkammer. Der er en gylden bæger gemt derinde. Du tager den og høster din belønning.,Gute Wahl. Das Heiligtum des Ordens bei dem Fluss ist ihre inoffiziele Folterkammer. Darin versteckt ist ein goldener Kelch. Du klaust ihn und erntest deinen Lohn.,,Bona elekto. La sanktejo de La Ordeno ĉe la rojo estas ĝia neoficiala torturejo. En ĝi estas kaŝita ora kaliko. Alportu ĝin al mi kaj vi havos rekompencon.,Buena elección. El santuario de La Orden junto al arroyo es su cámara de tortura extraoficial. Dentro hay un cáliz dorado escondido. Tráemelo y tendrás tu recompensa.,"Buena elección. El santuario de La Orden junto al río es su cámara de tortura extraoficial. Adentro hay un cáliz dorado escondido. Si me lo traes, tu recompensa.","Viisas päätös. Veljeskunnan pyhäkkö joen varrella on heidän epävirallinen kidutuskammionsa, jonka kätköissä piilee kultakalkki. Kähvellä se ja saat vaivannäöstäsi palkan.",Bon choix. Le sanctuaire de l'ordre près de la rivière est leur chambre torture.. officieusement. A l'intérieur se trouve un calice en or. Récupérez le et venez prendre votre récompense.,"Jó választás. A Rend Szentélye a folyónál a nem hivatalos kínzókamrájuk. Odabent elrejtve található egy arany kehely. Elcsened, és learatod a dicsőséged.",Ottima scelta. Il santuario dell'Ordine vicino al fiume è la loro camera della tortura. Vi è un calice d'oro nascosto là dentro. Prendilo e avrai una lauta ricompensa.,"良い判断だ。川沿いにあるオーダーの聖域は あいつらの非公式の拷問室だ。中には黄金の 聖杯が隠してある。そいつを持ってくれば 報酬をやるぜ。 -",좋은 선택이야. 강가 근처에 있는 성소가 바로 오더의 비공식적인 고문실이야. 그리고 그 안에는 숨겨진 금색 성배가 있지. 넌 그것을 훔치고 보상을 받으면 돼.,Goede keuze. Het heiligdom van de Orde bij de rivier is hun onofficiële martelkamer. Verborgen in de kelk zit een gouden kelk. Je haalt hem weg en plukt je beloning.,Dobry wybór. Sanktuarium Zakonu nad rzeką to ich nieoficjalna sala tortur. Jest w niej ukryty złoty kielich. Zwijasz go i dostajesz swoją nagrodę.,Boa escolha. O santuário da Ordem perto do rio é a câmara de tortura não-oficial deles. Há um cálice dourado escondido dentro. Pegue-o e você recebe a sua recompensa.,,Bună alegere. Sanctuarul Ordinului de lângă râu e camera lor de tortură neoficială. Ascuns în interior e un potir auriu. Îl înhați și culegi recompensa.,Правильный выбор. В святилище Ордена у реки — там у них негласная камера пыток — спрятана золотая чаша. Ты крадёшь её и получаешь свою награду.,Добар избор. Одредово светилиште поред реке представља њихову незваничну собу за мучење. Сакривено унутра је златни пехар. Повучеш га и добијеш награду. -How am I supposed to do that?,TXT_RPLY0_SCRIPT02_D43964_HOWAM,,,,Jak to mám udělat?,Wie soll ich das anstellen?,,,¿Cómo se supone que debo hacer eso?,,,Comment est-ce que je suis sensé faire ça?,Mégis hogy kéne hozzálássak ehhez?,,どうすればいい?,내가 그걸 어떻게 하지?,Hoe moet ik dat doen?,Jak powinienem to zrobić?,Como eu vou conseguir fazer isso?,,Și cum ar trebui să fac asta?,И как я это сделаю?,Како бих ја то требао урадити? -"Here's a crossbow, just aim straight and --splat--. Remember, grab the fancy cup and get to the tavern.",TXT_DLG_SCRIPT02_D45480_HERES,,,,"Tady máš kuši, prostě zamiř rovně a --plesk--. Nezapomeň, popadni fešný hrnek a přijď do taverny.","Hier ist eine Armbust, einfach gerade zielen und --Platsch--. Denk dran, schnapp dir den schicken Kelch und dann ab zur Taverne.",,,"Toma una ballesta, solo apunta en línea recta y --splat--. Recuerda, toma la bonita copa y ven a la taberna.",,,Voilà une arbalète. Vous avez juste à viser droit et paf! Souvenez-vous. Prenez le goblet et ramenez le à la taverne.,"Itt a számszeríj. Csak célozz előre és -placcs- . Vésd az eszedbe, fogd a pofás kis csészét és menj a fogadóba!",,"このクロスボウを使いな、狙いを定めて +",좋은 선택이야. 강가 근처에 있는 성소가 바로 오더의 비공식적인 고문실이야. 그리고 그 안에는 숨겨진 금색 성배가 있지. 넌 그것을 훔치고 보상을 받으면 돼.,Goede keuze. Het heiligdom van de Orde bij de rivier is hun onofficiële martelkamer. Verborgen in de kelk zit een gouden kelk. Je haalt hem weg en plukt je beloning.,Godt valg. Ordenens helligdom ved elven er deres uoffisielle torturkammer. Gjemt der inne er det et gyllent beger. Ta det og høste belønningen din.,Dobry wybór. Sanktuarium Zakonu nad rzeką to ich nieoficjalna sala tortur. Jest w niej ukryty złoty kielich. Zwijasz go i dostajesz swoją nagrodę.,Boa escolha. O santuário da Ordem perto do rio é a câmara de tortura não-oficial deles. Há um cálice dourado escondido dentro. Pegue-o e você recebe a sua recompensa.,,Bună alegere. Sanctuarul Ordinului de lângă râu e camera lor de tortură neoficială. Ascuns în interior e un potir auriu. Îl înhați și culegi recompensa.,Правильный выбор. В святилище Ордена у реки — там у них негласная камера пыток — спрятана золотая чаша. Ты крадёшь её и получаешь свою награду.,,Bra val. Ordens helgedom vid floden är deras inofficiella tortyrkammare. Gömd inuti finns en gyllene kalk. Du tar den och skördar din belöning.,İyi seçim. Tarikat'ın nehir kenarındaki sığınağı onların gayri resmi işkence odası. İçinde altın bir kadeh saklı. Onu araklarsın ve ödülünü alırsın. +How am I supposed to do that?,TXT_RPLY0_SCRIPT02_D43964_HOWAM,〃,,,Jak to mám udělat?,Hvordan skal jeg gøre det?,Wie soll ich das anstellen?,,Kiel mi supozeble faru tion?,¿Cómo se supone que debo hacer eso?,,Miten ihmeessä minä sen teen?,Comment est-ce que je suis sensé faire ça?,Mégis hogy kéne hozzálássak ehhez?,E come posso fare tutto ciò?,どうすればいい?,내가 그걸 어떻게 하지?,Hoe moet ik dat doen?,Hvordan skal jeg gjøre det?,Jak powinienem to zrobić?,E como eu vou fazer isso?,,Și cum ar trebui să fac asta?,И как я это сделаю?,,Hur ska jag göra det?,Bunu nasıl yapacağım? +"Here's a crossbow, just aim straight and --splat--. Remember, grab the fancy cup and get to the tavern.",TXT_DLG_SCRIPT02_D45480_HERES,〃,,,"Tady máš kuši, prostě zamiř rovně a --plesk--. Ještě jednou: popadni fešný hrnek a přijď do taverny.","Her er en armbrøst, bare sigt lige ud og -splat--. Husk, tag det fine bæger og gå til tavernaen.","Hier ist eine Armbust, einfach gerade zielen und --Platsch--. Denk dran, schnapp dir den schicken Kelch und dann ab zur Taverne.",,Jen arbalesto. Vi nur celu laŭ rekta linio kaj «pum». Ne forgesu preni la belan pokalon kaj tiam reveni al la taverno.,Aquí tengo una ballesta. Solo apunta en línea recta y «plaf». Recuerda: toma la bonita copa y luego vuelve aquí a la taberna.,,"Tässä sinulle jousipyssy; tähtää vain eteenpäin ja ""pläts""! Tärkeintä vain, että muistat kahmaista fiinin maljan ja sitten palata kapakkaan.",Voilà une arbalète. Vous avez juste à viser droit et paf! Souvenez-vous. Prenez le goblet et ramenez le à la taverne.,"Itt a számszeríj. Csak célozz előre és -placcs- . Vésd az eszedbe, fogd a pofás kis csészét és menj a fogadóba!","Ecco una balestra, basta mirare e --splat--. Ricorda, prendi il calice e ritorna alla taverna.","このクロスボウを使いな、狙いを定めて --シュッとな。覚えておけ、 -ファンシーなカップを持ってここに戻ってこい。","여기 석궁이야, 똑바로 겨냥해, 그리고... '철퍼덕'. 기억해, 멋진 컵을 들고 선술집에 와.","Hier is een kruisboog, mik gewoon recht en --splat--. Vergeet niet, pak de mooie beker en ga naar de herberg.","Oto kusza, tylko wyceluj i --plask--. Pamiętaj, weź ozdobny puchar i wróć do tawerny.","Aqui está uma besta. Só mirar reto e --splat--. Lembre-se, pegue o copo bonito e vá pra taverna.",,"Uite o arbaletă, doar țintești drept și --pleoșc--. Ține minte, ia cana scumpă și du-te la tavernă.",Вот арбалет — просто прицеливаешься и «шлёп!» Запомни — хватаешь чашку и возвращаешься в таверну.,"Ево ти самострел, само циљај право и --пљуц--. Запамти, зграби фенси пехар и иди у крчму." -Cool. I'll get it.,TXT_RPLY0_SCRIPT02_D45480_COOLI,,,,"Fajn, přinesu ho.",Cool. Ich werde ihn holen.,,,Genial. La conseguiré.,,,Ok. Je m'en occupe.,Király. Meglesz majd.,,良い物だ、貰っとく。,"멋지군, 이해 했어.",Cool. Ik zal het krijgen.,Fajnie. Wchodzę w to.,Beleza. Vou lá pegar.,,Tare. O voi lua.,"Класс. Я достану её. -",Одлично. Скапираћу. -What are you waiting for? Bring me that chalice.,TXT_DLG_SCRIPT02_D46996_WHATA,,,,Na co čekáš? Přines mi ten kalich.,Worauf wartest du noch? Bring mir den Kelch.,,,¿A que estas esperando? Tráeme ese cáliz.,¿Qué estas esperando? Tráeme ese cáliz.,,Qu'attendez vous? Récupérez-moi ce calice.,Mire vársz? Hozd ide azt a kelyhet.,,何ボーっとしてんだ?とっとと聖杯を持ってこい。,뭘 기다리는 거야? 가서 성배를 찾아.,Waar wacht je nog op? Breng me die kelk.,Na co czekasz? Przynieś mi ten kielich.,Está esperando o quê? Me traga o cálice.,,Ce mai aștepți? Adu-mi potirul acela.,Чего ты ждёшь? Принеси мне эту чашу.,На шта чекаш? Донеси ми тај пехар. -"Hey, I know, kinda looks like a set-up. I would never do that to such a great killing machine. Got the item? Great! Now get ready, gold and glory just like I promised. Take this key and the Governor will reward you.",TXT_DLG_SCRIPT02_D48512_HEYIK,,,,"Hej, vím, že to vypadá jako bouda. Takovému zabijákovi bych nikdy nic takového neudělal. Máš ten kalich? Fajn! Tak teď se připrav, zlato a sláva, jak jsem slíbil. Vem si tenhle klíč a samotný guvernér tě odmění.","Hey, ich weiß, es sieht anscheinend wie eine Falle aus, aber so etwas würde ich einer so großeartigen Tötungsmaschine nicht antun. Hast du ddas Ding? Großartig! Nun mach dich bereit, Geld und Ruhm, genau wie ich es dir versprochen habe. Nimm diesen Schlüssel und der Gouverneur wird dich belohnen.",,,"Si, lo sé, esto parece un timo. Nunca le haría eso a una gran máquina de matar. ¿Tienes el objeto? ¡Genial! Ahora prepárate, oro y gloria tal como lo prometí. Toma esta llave y el gobernador te recompensará.",,,"Hé, je sais que ça à l'air d'être un coup monté, mais je ne ferais jamais ça à une aussi bonne machine à tuer. Vous avez le butin? Excellent! Préparez vous, l'or et la gloire vous attend, comme promis. Prenez cette clé et le gouverneur vous récompensera.",,,"おう、罠みたいだと思ったか。 +ファンシーなカップを持ってここに戻ってこい。","여기 석궁이야, 똑바로 겨냥해, 그리고... '철퍼덕'. 기억해, 멋진 컵을 들고 선술집에 와.","Hier is een kruisboog, mik gewoon recht en --splat--. Vergeet niet, pak de mooie beker en ga naar de herberg.","Her er en armbrøst, bare sikt rett og --splat--. Husk å ta det fine begeret og gå til vertshuset.","Oto kusza, tylko wyceluj i --plask--. Pamiętaj, weź ozdobny puchar i wróć do tawerny.","Aqui está uma besta. Só mirar reto e --splat--. Lembre-se, pegue o copo bonito e vá pra taverna.",,"Uite o arbaletă, doar țintești drept și --pleoșc--. Ține minte, ia cana scumpă și du-te la tavernă.",Вот арбалет — просто прицеливаешься и «шлёп!» Запомни — хватаешь чашку и возвращаешься в таверну.,,"Här är ett armborst, sikta bara rakt och --splat--. Kom ihåg att ta den fina bägaren och gå till tavernan.","İşte bir arbalet, sadece düz nişan al ve --splat--. Unutma, süslü kupayı al ve tavernaya git." +Cool. I'll get it.,TXT_RPLY0_SCRIPT02_D45480_COOLI,〃,,,"Fajn, přinesu ho.",Det er fedt. Jeg henter den.,Cool. Ich werde ihn holen.,,Bonege. Mi trovos ĝin.,Genial. Ya lo traigo.,,Selvä. Saan sen.,Ok. Je m'en occupe.,Király. Meglesz majd.,Va bene. Vado a prenderlo.,良い物だ、貰っとく。,"멋지군, 이해 했어.",Cool. Ik zal het krijgen.,Kult. Jeg henter den.,Fajnie. Wchodzę w to.,Beleza. Vou lá pegar.,,Tare. O voi lua.,"Класс. Я достану её. +",,Coolt. Jag hämtar den.,Güzel. Ben alırım. +What are you waiting for? Bring me that chalice.,TXT_DLG_SCRIPT02_D46996_WHATA,〃,,,Na co čekáš? Přines mi ten kalich.,Hvad venter du på? Giv mig det bæger.,Worauf wartest du noch? Bring mir den Kelch.,,Kion vi atendas? Alportu tiun kalikon.,¿A qué estás esperando? Tráeme ese cáliz.,¿Qué estás esperando? Tráeme ese cáliz.,Mitä oikein jahkailet? Tuo minulle se kalkki.,Qu'attendez vous? Récupérez-moi ce calice.,Mire vársz? Hozd ide azt a kelyhet.,Cosa stai aspettando? Portami il calice.,何ボーっとしてんだ?とっとと聖杯を持ってこい。,뭘 기다리는 거야? 가서 성배를 찾아.,Waar wacht je nog op? Breng me die kelk.,Hva venter du på? Gi meg det begeret.,Na co czekasz? Przynieś mi ten kielich.,Está esperando o quê? Me traga o cálice.,,Ce mai aștepți? Adu-mi potirul acela.,Чего ты ждёшь? Принеси мне эту чашу.,,Vad väntar du på? Ge mig den där bägaren.,Ne bekliyorsun? Bana o kadehi getir. +"Hey, I know, kinda looks like a set-up. I would never do that to such a great killing machine. Got the item? Great! Now get ready, gold and glory just like I promised. Take this key and the Governor will reward you.",TXT_DLG_SCRIPT02_D48512_HEYIK,〃,,,"Hej, já vím, že tohle vypadá jako bouda. Takovému zabijákovi jako ty bych nikdy nic takového neudělal! Máš ten kalich? Fajn! Tak teď se připrav, zlato a sláva, jak jsem slíbil. Vem si tenhle klíč a samotný guvernér tě odmění.","Jeg ved det godt, det ligner en fælde. Jeg ville aldrig gøre det mod sådan en stor dræbermaskine. Har du genstanden? Fedt! Gør dig nu klar, guld og ære, som jeg lovede. Tag denne nøgle, og guvernøren vil belønne dig.","Hey, ich weiß, es sieht anscheinend wie eine Falle aus, aber so etwas würde ich einer so großeartigen Tötungsmaschine nicht antun. Hast du ddas Ding? Großartig! Nun mach dich bereit, Geld und Ruhm, genau wie ich es dir versprochen habe. Nimm diesen Schlüssel und der Gouverneur wird dich belohnen.",,"Jes, mi scias, ĉi tio ŝajnas trompo, sed mi neniam farus tion al bonega mortig-maŝino. Ĉu vi havas la kalikon? Bonege! Pretiĝu: oro kaj gloro, tiel, kiel mi promesis. Prenu ĉi tiun ŝlosilon kaj la registo rekompencos vin.","Sí, ya lo sé, esto parece un timo, pero nunca le haría eso a una gran máquina de matar. ¿Tienes el cáliz? ¡Genial! Ahora prepárate: oro y gloria, tal y como he prometido. Toma esta llave y el gobernador te recompensará.","Sí, ya lo sé, esto parece una estafa, pero nunca le haría eso a una gran máquina de matar. ¿Tienes el cáliz? ¡Genial! Ahora prepárate: oro y gloria, tal y como prometí. Toma esta llave y el gobernador te va a recompensar.","Joo joo, tiedän, että on vähän väijytyksen makua. En kuitenkaan ikinä tekisi sellaista niin kovalle tappokoneelle. Saitko tavaran? Loistavaa! No niin, valmistaudu kultaan ja kunniaan, juuri niin kuin lupasinkin. Ota tämä avain ja kuvernööri palkitsee sinut.","Hé, je sais que ça à l'air d'être un coup monté, mais je ne ferais jamais ça à une aussi bonne machine à tuer. Vous avez le butin? Excellent! Préparez vous, l'or et la gloire vous attend, comme promis. Prenez cette clé et le gouverneur vous récompensera.","Tudom, hogy olyan szaga van mint egy csapdának. Sosem tennék ilyet egy ilyen kiváló gyilkológéppel. Megvan a cuccos? Zsír! Most készülj fel, arany és hírnév, mint ahogy ígértem. Vidd ezt a kulcsot és a kormányzó megjutalmaz.","Ehi, so che può sembrare una trappola. Ma io non tradirei mai a un killer abile come te. Hai il calice? Benissimo! Ora preparati, oro e gloria ti aspettano come promesso. Prendi questa chiave e il Governatore in persona ti ricompenserà.","おう、罠みたいだと思ったか。 俺に暴れん坊みたいな芸当出来るわきゃねえ。 ブツはあるか?そりゃいい!じゃあ準備しな。 金と栄光は約束された。この鍵で知事に合えば 報酬をありったけくれるさ。 -","이봐, 알겠어. 확실히 뭔가 꾸며 놓은 것 같다는 거. 난 훌륭한 학살 기계에게 그런 짓을 할 사람이 아니야. 그래서 그걸 가져왔나? 좋아! 그럼 약속한 대로 골드와 영광을 줄 테니 준비해. 이 열쇠를 총독에게 가져다주면 보상해 줄 거야.","Hé, ik weet het, het ziet er een beetje uit als een valstrik. Dat zou ik nooit met zo'n grote moordmachine doen. Heb je het item? Geweldig! Maak je nu klaar, goud en glorie, net zoals ik beloofd heb. Neem deze sleutel en de gouverneur zal je belonen.","Hej, wiem, wygląda to jak zasadzka. Nigdy bym czegoś takiego nie zrobił wspaniałej maszynie do zabijania. Masz przedmiot? Wspaniale! Przygotuj się teraz, złoto i chwała tak jak obiecywałem. Weź ten klucz, a Gubernator cię nagrodzi.","Olha, eu sei, meio que parece uma cilada. Eu nunca faria aquilo a uma grande máquina mortífera. Conseguiu o item? Ótimo! Agora se prepare, ouro e glória conforme prometido. Pegue esta chave e o Governador irá te recompensar.",,"Hei, știu că pare o capcană. Nu aș face așa ceva niciodată unei mașini ucigașe atât de tare. Ai obiectul? Perfect! Acum pregătește-te, aur și glorie cum ți-am promis. Ia cheia asta și Guvernatorul te va răsplătii.","Слушай, я знаю, о чём ты думаешь. Ты думаешь, что это подстава. Но я бы никогда не сделал этого с такой машиной для убийств, как ты. Достал то, что я просил? Отлично! Тебя ждёт золото и слава, как я и обещал. Возьми этот ключ — губернатор лично наградит тебя.","Хеј, знам, некако изгледа као намештаљка. Никада не бих урадио тако нешто невероватној машини за убијање. Имаш ли предмет? Одлично! Сада се припреми, злато и слава као што сам и обећао. Узми овај кључ и Гувернер ће те наградити." -He'd better. For your sake!,TXT_RPLY0_SCRIPT02_D48512_HEDBE,,,,"To by tedy měl, pro tvoje vlastní dobro!",Das macht er besser. Deinetwillen!,,,Más le vale. ¡Por tu propio bien!,Será lo mejor. ¡Por tu propio bien!,,"Il a intérêt, pour votre bien!",Jobban teszi. Miattad.,,戻せ、お前の為だ!,"살고 싶으면, 이 말이 사실이야 할 거다!",Dat is hem maar beter gelukt. Voor uw eigen bestwil!,Mam nadzieję. Dla twojego dobra!,Acho bom mesmo. Pro seu bem!,,Ar face bine. De dragul tău!,Надеюсь. Это в твоих интересах!,Боље би му било. За твоје добро! -What! Where's my money?,TXT_RPLY1_SCRIPT02_D48512_WHATW,,,,Co! Kde jsou moje peníze?,Was! Wo ist mein Geld?,,,¡Qué! ¿Dónde está mi dinero?,,,Quoi? Où est mon argent!,Mi a! Hol van a pénzem?,,何だと! 金はどこだ?,뭐라고! 내 돈은 어디있지?,Wat! Waar is mijn geld?,Co! Gdzie moje pieniądze?,Como é? Cadê o meu dinheiro!,,Ce! Unde sunt banii mei?,Что? Где мои деньги?,Шта! Где је мој новац? -"Get lost kid, you bother me.",TXT_DLG_SCRIPT02_D50028_GETLO,,,,"Odprejskni, mladej, otravuješ mě.","Verzieh dich Jungchen, du störst mich.",,,"Piérdete mocoso, me molestas.",,,"Dégage, gamin, tu m'agaces.","Kopj le kölyök, ne itt lábatlankodj.",,失せろ、うざってえ。,사라져. 신경 거슬리게 하지 말고.,"Rot op, jongen, je stoort me.","Spadaj mały, przeszkadzasz mi.","Some daqui, garoto. Você está me incomodando.",,"Cară-te puștiule, mă deranjezi.","Пропади, малой. Ты меня раздражаешь.","Губи се клинац, смараш ме." -"No second chance. Oh guards, kill him.",TXT_DLG_SCRIPT02_D51544_NOSEC,,,,"Žádná druhá šance. Á, stráže, zabte ho.","Keine zweite Chance. Oh Wachen, tötet ihn.",,,"No hay otra oportunidad. Oh guardias, mátenlo.",,,"Pas de deuxième chance. Gardes, tuez-le.","Nincs második esély. Ó, őrök, öljétek meg.",,"次はねえな。おぅガードの旦那、 -やっちゃってくだせえ。","너에게는 기회 따윈 없었어. 경비원, 저놈을 죽여.","Geen tweede kans. Oh bewakers, dood hem.","Nie będzie drugiej szansy. Oh... strażnicy, zabijcie go.","Sem segunda chance. Ah, guardas, matem ele.",,"Nicio altă șansă. Oh gardienilor, omorâți-l.","Нет, никакого второго шанса. Эй, стража, убейте его.","Нема друге шансе. Стражари, побијте их." -"First they slaughter thousands, now they want all able-bodied peasants for unspecified 'tests'. How does the Order expect me to keep the peace? What the hell do you want?",TXT_DLG_SCRIPT02_D53060_FIRST,,,,"Nejprve povraždí tisíce a teď po mě chtějí všechny schopné poddané pro neupřesněné 'testy'. Jak Řád očekává, že mám zachovat mír? Co sakra chceš?",Zuerst metzeln sie Tausende nieder und nun wollen sie alle gesunden Bauern für unspezifierte „Tests“. Wie kann es der Orden nur so von mir verlangen Frieden zu bewahren? Was zum Teufel willst du?,,,"Primero matan a miles, ahora quieren a todos los campesinos sanos para 'Pruebas' no especificadas. ¿Cómo espera la orden que yo guarde la paz? ¿Qué demonios quieres?",,,"D'abord ils en massacrent des miliers, maintenant ils veulent tous les paysans en bonne santé pour leur « tests » dont personne ne sait rien. Comment est-ce que l'ordre veut que je garde la paix? Qu'est-ce que vous voulez?","Először ezreket kaszabolnak le, most meg minden ép testű jobbágyot nem részletezett ""kísérletekhez"" akarnak. Hogy várhatja el a Rend, hogy fenntartsam a békét? Mi a francot akarsz?",,"あいつら散々大量虐殺しといて、今度は'実験' +","이봐, 알겠어. 확실히 뭔가 꾸며 놓은 것 같다는 거. 난 훌륭한 학살 기계에게 그런 짓을 할 사람이 아니야. 그래서 그걸 가져왔나? 좋아! 그럼 약속한 대로 골드와 영광을 줄 테니 준비해. 이 열쇠를 총독에게 가져다주면 보상해 줄 거야.","Hé, ik weet het, het ziet er een beetje uit als een valstrik. Dat zou ik nooit met zo'n grote moordmachine doen. Heb je het item? Geweldig! Maak je nu klaar, goud en glorie, net zoals ik beloofd heb. Neem deze sleutel en de gouverneur zal je belonen.","Jeg vet at det ser ut som en felle. Jeg ville aldri gjort det mot en så flott drapsmaskin. Har du gjenstanden? Flott! Gjør deg klar. Gull og ære, som jeg lovte. Ta denne nøkkelen, så vil guvernøren belønne deg.","Hej, wiem, wygląda to jak zasadzka. Nigdy bym czegoś takiego nie zrobił wspaniałej maszynie do zabijania. Masz przedmiot? Wspaniale! Przygotuj się teraz, złoto i chwała tak jak obiecywałem. Weź ten klucz, a Gubernator cię nagrodzi.","Olha, eu sei, meio que parece uma cilada. Eu nunca faria aquilo a uma grande máquina mortífera. Conseguiu o item? Ótimo! Agora se prepare, ouro e glória conforme prometido. Pegue esta chave e o Governador irá te recompensar.",,"Hei, știu că pare o capcană. Nu aș face așa ceva niciodată unei mașini ucigașe atât de tare. Ai obiectul? Perfect! Acum pregătește-te, aur și glorie cum ți-am promis. Ia cheia asta și Guvernatorul te va răsplătii.","Слушай, я знаю, о чём ты думаешь. Ты думаешь, что это подстава. Но я бы никогда не сделал этого с такой машиной для убийств, как ты. Достал то, что я просил? Отлично! Тебя ждёт золото и слава, как я и обещал. Возьми этот ключ — губернатор лично наградит тебя.",,"Jag vet, det ser ut som en uppställning. Jag skulle aldrig göra det mot en så stor mördarmaskin. Har du föremålet? Bra! Gör dig nu redo, guld och ära precis som jag lovade. Ta den här nyckeln och guvernören kommer att belöna dig.","Hey, biliyorum, biraz tuzağa benziyor. Böyle büyük bir ölüm makinesine bunu asla yapmazdım. Eşyayı aldın mı? Harika! Şimdi hazır ol, söz verdiğim gibi altın ve şan. Bu anahtarı al ve Vali seni ödüllendirecek." +He'd better. For your sake!,TXT_RPLY0_SCRIPT02_D48512_HEDBE,〃,,,"To by tedy měl, pro tvoje vlastní dobro!",Det har han bare at gøre. For din skyld!,Das macht er besser. Deinetwillen!,,Li devus. Por via bono!,Más le vale. ¡Por tu propio bien!,,Parasta palkitakin! Sinun kannaltasi!,"Il a intérêt, pour votre bien!",Jobban teszi. A Te érdekedben!,È meglio che lo faccia... per il tuo bene!,戻せ、お前の為だ!,"살고 싶으면, 이 말이 사실이야 할 거다!",Dat is hem maar beter gelukt. Voor uw eigen bestwil!,Det bør han. For din skyld!,Mam nadzieję. Dla twojego dobra!,Acho bom mesmo. Pro seu bem!,,Ar face bine. De dragul tău!,Надеюсь. Это в твоих интересах!,,Det är bäst att han gör det. För din skull!,Öyle olsa iyi olur. Senin hatırın için! +What! Where's my money?,TXT_RPLY1_SCRIPT02_D48512_WHATW,〃,,,Cože? Kde jsou moje peníze?,Hvad! Hvor er mine penge?,Was! Wo ist mein Geld?,,Kio!? Kie estas mia mono?,¿¡Qué!? ¿Y mi dinero?,,Mitä! Missä on rahani?,Quoi? Où est mon argent!,Mi a túró! Hol van a pénzem?,Aspetta! Dove sono i miei soldi?,何だと! 金はどこだ?,뭐라고! 내 돈은 어디있지?,Wat! Waar is mijn geld?,Hva! Hvor er pengene mine?,Co! Gdzie moje pieniądze?,Como é? Cadê o meu dinheiro?,,Ce! Unde sunt banii mei?,Что? Где мои деньги?,,Vad! Var är mina pengar?,Ne! Param nerede? +"Get lost kid, you bother me.",TXT_DLG_SCRIPT02_D50028_GETLO,〃,,,"Odprejskni, mladej, otravuješ mě.","Forsvind, knægt, du generer mig.","Verzieh dich Jungchen, du störst mich.",,"Foriru, junulo; vi ĝenas min.","Ya vete, chaval, que eres pesado.","Ya vete de una vez, que eres pesado.","Häivy nulikka, häiritset minua.","Dégage, gamin, tu m'agaces.","Kopj le kölyök, ne itt lábatlankodj.","Sparisci, ragazzo, mi stai infastidendo.",失せろ、うざってえ。,사라져. 신경 거슬리게 하지 말고.,"Rot op, jongen, je stoort me.","Forsvinn, gutt, du plager meg.","Spadaj mały, przeszkadzasz mi.","Some daqui, garoto. Você está me incomodando.",,"Cară-te puștiule, mă deranjezi.","Пропади, малой. Ты меня раздражаешь.",,"Stick, grabben, du stör mig.","Kaybol evlat, beni rahatsız ediyorsun." +"No second chance. Oh guards, kill him.",TXT_DLG_SCRIPT02_D51544_NOSEC,〃,,,"Žádná druhá šance. Á, stráže, zabte ho.","Ingen ny chance. Åh vagter, dræb ham.","Keine zweite Chance. Oh Wachen, tötet ihn.",,"Ne estas alia ŝanco. Gardistoj, mortigu lin!","No hay otra oportunidad. ¡Guardias, matadlo!","No hay otra oportunidad. ¡Guardias, mátenlo!","Ei uutta tilaisuutta. Vartijat, tappakaa hänet.","Pas de deuxième chance. Gardes, tuez-le.","Nincs második esély. Ó, őrök, öljétek meg.","Nessuna seconda chance. Guardie, uccidetelo.","次はねえな。おぅガードの旦那、 +やっちゃってくだせえ。","너에게는 기회 따윈 없었어. 경비원, 저놈을 죽여.","Geen tweede kans. Oh bewakers, dood hem.","Ingen ny sjanse. Vakter, drep ham.","Nie będzie drugiej szansy. Oh... strażnicy, zabijcie go.","Sem segunda chance. Ah, guardas, matem ele.",,"Nicio altă șansă. Oh gardienilor, omorâți-l.","Нет, никакого второго шанса. Эй, стража, убейте его.",,"Ingen andra chans. Åh vakter, döda honom.","İkinci bir şans yok. Muhafızlar, öldürün onu." +"First they slaughter thousands, now they want all able-bodied peasants for unspecified 'tests'. How does the Order expect me to keep the peace? What the hell do you want?",TXT_DLG_SCRIPT02_D53060_FIRST,MAP02: Mourel.,,,"Tak oni nejdříve povraždí tisíce a teď po mě chtějí všechny schopné poddané pro neupřesněné 'testování'. Jak Řád očekává, že mám zachovat mír? Co ty sakra chceš?","Først slagter de tusinder, nu vil de have alle raske bønder til uspecificerede ""tests"". Hvordan forventer ordenen, at jeg skal opretholde freden? Hvad fanden vil du?",Zuerst metzeln sie Tausende nieder und nun wollen sie alle gesunden Bauern für unspezifierte „Tests“. Wie kann es der Orden nur so von mir verlangen Frieden zu bewahren? Was zum Teufel willst du?,,"Ili unue buĉis milojn, kaj nun volas ĉiujn sanegajn kamparanojn por nespecifaj «provoj». Kiel La Ordeno esperas, ke mi ankoraŭ povos teni la pacon?... Kion diable vi volas?",Primero matan a miles y ahora quieren a todos los campesinos sanos para «pruebas» no especificadas. ¿Cómo espera La Orden que yo pueda seguir manteniendo la paz?... ¿Y tú qué demonios quieres?,Primero matan a miles y ahora quieren a todos los campesinos sanos para «pruebas» no especificadas. ¿Cómo espera La Orden que yo pueda seguir manteniendo la paz?... ¿Y tú qué carajo quieres?,"Ensiksi ne lahtaavat tuhansia, nyt ne haluavat kaikki kynnelle kykenevät maallikot määrittelemättömiin ""kokeisiin""'. Miten veljeskunta odottaa minun pitävän järjestystä? Mitä helvettiä sinä haluat?","D'abord ils en massacrent des miliers, maintenant ils veulent tous les paysans en bonne santé pour leur « tests » dont personne ne sait rien. Comment est-ce que l'ordre veut que je garde la paix? Qu'est-ce que vous voulez?","Először ezreket kaszabolnak le, most meg minden ép testű jobbágyot ismeretlen ""kísérletekhez"" akarnak. Hogy várhatja el a Rend, hogy fenntartsam a békét? Mi a francot akarsz?","Prima massacrano migliaia di persone, poi vogliono cittadini in buona condizione fisica per ""test"" non meglio specificati. Come può l'Ordine aspettarsi che io riesca a mantenere la pace? E tu che diavolo vuoi?","あいつら散々大量虐殺しといて、今度は'実験' の為に健康な庶民を用意しろとか。オーダーは 本当に平和を維持してくれるのか? で、君は何用で来たのかね? -","먼저 오더가 수천 명을 죽여놓고, 이젠 힘 좋은 시민들을 불러서 생각지도 않은 시험을 하라고 시키는구먼. 그놈들이 나한테 바라는 게 뭔지 전혀 모르겠네. 넌 원하는 게 뭐야?","Eerst slachten ze duizenden mensen af, nu willen ze alle valide boeren voor ongespecificeerde 'tests'. Hoe verwacht de Orde dat ik de vrede bewaar? Wat wil je verdomme?","Najpierw mordują tysiące, a teraz chcą wszystkich krzepkich chłopów do nieokreślonych ""testów"". Jak Zakon oczekuje ode mnie abym utrzymywał pokój? Czego chcesz u diabła?","Primeiro eles massacram milhares, agora querem que todos os plebeus saudáveis façam ""provas"" não especificadas. Como que a Ordem quer que eu mantenha a paz? Que diabos você quer?",,"Mai întâi măcelăresc cu miile, apoi vor toți sărmanii capabili de muncă pentru 'teste' nespecificate. Cum se așteaptă Ordinul să mențin pacea? Ce naiba vrei?","Сначала они убивают людей тысячами, а теперь им нужны все пригодные рабочие для каких-то «экспериментов»! И Орден ещё хочет, чтобы я поддерживал мир? Какого чёрта тебе нужно?","Прво их покољу на хиљаде, сада желе све способне сељаке за неспецифиране ""testove"". Како Одред очекује од мене да очувам мир? Шта ког врага желиш?" -"A prison pass, let's deal.",TXT_RPLY0_SCRIPT02_D53060_APRIS,,,,"Propustku do vězení, dohodněme se.",Ein Gefängnispass. Lassen Sie uns verhandeln.,,,"Un pase de la prisión, negociemos.",,,Un passe de la prison. Faisons affaires.,Egy börtön belépő. Üzleteljünk.,,刑務所の許可証だ、取引をしよう。,감옥 통행증만 있으면 돼.,"Een gevangenispasje, laten we dealen.","Przepustkę do więzienia, ponegocjujmy.","Um passe da prisão, vamos negociar.",,O legitimație pentru închisoare. Să facem un târg.,Пропуск в тюрьму. Заключим сделку.,"Затворска прпусница, хајде да дилујемо." -"I like you already. I have two chores that I don't want to do myself. One is messy, the other bloody.",TXT_DLG_SCRIPT02_D54576_ILIKE,,,,"Už teď se mi líbíš. Mám dvě prácičky, které nechci dělat sám. Jedna je špinavá, druhá je krvavá.","Du gefällst mir bereits. Ich habe zwei lästige Angelegenheiten, um die ich mich nicht selber kümmern möchte. Die eine davon ist dreckig, die andere blutig.",,,"Ya me caes bien. Tengo dos tareas que no quiero hacer yo mismo. Una es sucia, la otra -sangrienta.",,,"Vous me plaisez déjà. J'ai deux corvées que je n'ai pas envie de faire. Une est.. Sale, l'autre est sanglante.","Kedvellek már most. Van két rigojám, amit nem szeretek magam végezni. Az egyik a koszos, a másik a véres.",,"いいだろう。仕事は二つあるのだが -一つは面倒で、もう一つは血を見ることになる。",이제야 말길이 가네. 지금 너에게 맡을 시험이 두 가지 있거든. 더러운 거랑... 잔인한 거.,"Ik vind je nu al leuk. Ik heb twee taken die ik zelf niet wil doen. De ene is rommelig, de andere bloedig.","Już cię lubię. Mam dwa zadania, których sam nie chcę wykonać. Jedno jest brudne, a drugie krwawe.","Estou gostando de você. Tenho mais duas tarefas chatas que eu particularmente não estou a fim de fazer. Uma é suja, a outra sangrenta.",,"Deja îmi placi. Am două treburi nasoale pe care nu vreau să le fac eu însumi. Una e haotică, cealalta sângeroasă.","Мне нравится твой настрой! У меня есть два неприятных дела, которыми я не хочу заниматься сам. Одно грязное, а другое кровавое.","Већ ми се допадаш. Имам два посла која не желим да радим сам. Један је прљав, а други је крвав." -Call me the cleaner,TXT_RPLY0_SCRIPT02_D54576_CALLM,,,,Říkej mi pan uklízeč.,Nennen Sie mich den Säuberer,,,Llámame el limpiador,,,Appelez-moi le nettoyeur.,Hívj csak takarítónak.,,まだ手は汚したくない,청소부라 불러줘.,Noem me de schoonmaakster,Nazywaj mnie czyścicielem.,Pode me chamar de limpador,,Spune-mi curățătorul,Я — лучший чистильщик!,Можеш ме звати чистачем -I'm not squeamish,TXT_RPLY1_SCRIPT02_D54576_IMNOT,,,,Mám silný žaludek.,Ich bin nicht zimperlich.,,,No soy escrupuloso,,,J'ai pas peur de me tacher les mains.,,,汚れ仕事でも構わない,나는 비위가 약하지 않아.,Ik ben niet katholiek.,Nie jestem wybredny.,Não tenho medo de sujar as mãos,,Nu sunt mofturos,Я не боюсь крови.,Нисам гадљив -One of my minions is stealing power with a tap on the mains somewhere. Find it and truncate his supply and I'll provide you with what you want. Bring me something as a token.,TXT_DLG_SCRIPT02_D56092_ONEOF,,,,"Jeden z mých poddaných stáčedlem někde z hlavního vedení krade energii. Najdi jej a odřízni dotyčného od zásoby a já ti dám, co chceš. Přines mi něco jako důkaz.","Einer meiner Untertanen zapft irgendwo Strom ab. Finde die Anzapfung und kappe sie. Falls du Erfolg hast, kriegst du was du brauchst. Aber bring mir einen Beweis mit!",,,"Uno de mis secuaces está robando energía interviniendo la red en algún lugar. Encuéntralo, trunca su suministro y te proporcionaré lo que quieras. Tráeme algo como prueba de que está hecho.",,,Un de mes larbins pompe de l'électricité avec une connection pirate dans les transformateurs là haut. Trouvez là et coupez sa connection. Je vous donnerai ce que vous voulez. Ramenez moi une preuve.,"Az egyik alattvalóm áramot lop egy dugasszal a központi hálózatnál valahol. Találd meg, majd válaszd el az ellátását, és én adok neked amit akarsz. Hozz nekem valamit bizonyítékként",,"私の手下の一人が水力発電から電力を盗んで +","먼저 오더가 수천 명을 죽여놓고, 이젠 힘 좋은 시민들을 불러서 생각지도 않은 시험을 하라고 시키는구먼. 그놈들이 나한테 바라는 게 뭔지 전혀 모르겠네. 넌 원하는 게 뭐야?","Eerst slachten ze duizenden mensen af, nu willen ze alle valide boeren voor ongespecificeerde 'tests'. Hoe verwacht de Orde dat ik de vrede bewaar? Wat wil je verdomme?","Først slakter de tusenvis, og nå vil de ha alle arbeidsføre bønder til uspesifiserte ""tester"". Hvordan forventer ordenen at jeg skal bevare freden? Hva i helvete vil du ha?","Najpierw mordują tysiące, a teraz chcą wszystkich krzepkich chłopów do nieokreślonych ""testów"". Jak Zakon oczekuje ode mnie abym utrzymywał pokój? Czego chcesz u diabła?","Primeiro eles massacram milhares, agora querem que todos os plebeus saudáveis façam ""provas"" não especificadas. Como que a Ordem quer que eu mantenha a paz? Que diabos você quer?",,"Mai întâi măcelăresc cu miile, apoi vor toți sărmanii capabili de muncă pentru 'teste' nespecificate. Cum se așteaptă Ordinul să mențin pacea? Ce naiba vrei?","Сначала они убивают людей тысячами, а теперь им нужны все пригодные рабочие для каких-то «экспериментов»! И Орден ещё хочет, чтобы я поддерживал мир? Какого чёрта тебе нужно?",,"Först slaktar de tusentals, nu vill de ha alla dugliga bönder för ospecificerade ""tester"". Hur förväntar sig orden att jag ska kunna upprätthålla freden? Vad i helvete vill ni?","Önce binlercesini katlettiler, şimdi de tüm sağlıklı köylüleri belirsiz 'testler' için istiyorlar. Tarikat benden barışı korumamı nasıl bekler? Ne halt istiyorsun?" +"A prison pass, let's deal.",TXT_RPLY0_SCRIPT02_D53060_APRIS,〃,,,"Propustku do vězení, udělejme dohodu.","Et fængselskort, lad os lave en aftale.",Ein Gefängnispass. Lassen Sie uns verhandeln.,,Malliberejan enirpermeson. Ni intertraktu.,Un pase a la prisión. Negociemos.,,Vankilan pääsyluvan; hierotaan diili.,Un passe de la prison. Faisons affaires.,Egy börtön belépő. Üzleteljünk.,"Un pass per la prigione, trattiamo.",刑務所の許可証だ、取引をしよう。,감옥 통행증만 있으면 돼.,"Een gevangenispasje, laten we dealen.","Et fengselspass, la oss gjøre en avtale.","Przepustkę do więzienia, ponegocjujmy.","Um passe da prisão, vamos negociar.",,O legitimație pentru închisoare. Să facem un târg.,Пропуск в тюрьму. Заключим сделку.,,"Ett fängelsepass, låt oss göra upp.","Bir hapishane izni, anlaşalım." +"I like you already. I have two chores that I don't want to do myself. One is messy, the other bloody.",TXT_DLG_SCRIPT02_D54576_ILIKE,〃,,,"Už teď se mi líbíš. Mám dvě prácičky, které nechci dělat sám. Jedna je špinavá, druhá je krvavá.","Jeg kan allerede godt lide dig. Jeg har to pligter, som jeg ikke selv vil gøre. Den ene er rodet, den anden er blodig.","Du gefällst mir bereits. Ich habe zwei lästige Angelegenheiten, um die ich mich nicht selber kümmern möchte. Die eine davon ist dreckig, die andere blutig.",,"Mi jam ŝatas vin. Estas du farotaĵoj, kiujn mi mem ne volas fari: unu estas malpura kaj la alia estas sanga.",Ya me caes bien. Hay dos tareas que no quiero hacer por mi cuenta: una es sucia y la otra sangrienta.,,"Minähän pidän sinusta. Minulla olisi kyllä pari askaretta, joita en itse haluaisi tehdä. Yksi niistä on sotkuinen, toinen hurmeinen.","Vous me plaisez déjà. J'ai deux corvées que je n'ai pas envie de faire. Une est.. Sale, l'autre est sanglante.","Kedvellek már most. Van két feladatom, amit nem akarok magam végezni. Az egyik a koszos, a másik a véres.","Già mi piaci. Ho due faccende da sbrigare che non voglio fare di persona. Una è un po' complicata, e l'altra da risolvere col sangue.","いいだろう。仕事は二つあるのだが +一つは面倒で、もう一つは血を見ることになる。",이제야 말길이 가네. 지금 너에게 맡을 시험이 두 가지 있거든. 더러운 거랑... 잔인한 거.,"Ik vind je nu al leuk. Ik heb twee taken die ik zelf niet wil doen. De ene is rommelig, de andere bloedig.","Jeg liker deg allerede. Jeg har to plikter jeg ikke vil gjøre selv. Det ene er rotete, det andre blodig.","Już cię lubię. Mam dwa zadania, których sam nie chcę wykonać. Jedno jest brudne, a drugie krwawe.","Estou gostando de você. Tenho mais duas tarefas chatas que eu particularmente não estou a fim de fazer. Uma é suja, a outra sangrenta.",,"Deja îmi placi. Am două treburi nasoale pe care nu vreau să le fac eu însumi. Una e haotică, cealalta sângeroasă.","Мне нравится твой настрой! У меня есть два неприятных дела, которыми я не хочу заниматься сам. Одно грязное, а другое кровавое.",,"Jag gillar dig redan. Jag har två sysslor som jag inte vill göra själv. Den ena är smutsig, den andra är blodig.","Seni şimdiden sevdim. Kendi başıma yapmak istemediğim iki işim var. Biri pis, diğeri kanlı." +Call me the cleaner,TXT_RPLY0_SCRIPT02_D54576_CALLM,〃,,,Říkej mi pan uklízeč.,Kald mig rengøringsmanden.,Nennen Sie mich den Säuberer,,Purigado estas mia specialo.,Limpiar es mi especialidad.,,Olen siivoojasi,Appelez-moi le nettoyeur.,Hívj csak takarítónak.,Risolvere problemi è la mia specialità,まだ手は汚したくない,청소부라 불러줘.,Noem me de schoonmaakster,Kall meg renholderen.,Nazywaj mnie czyścicielem.,Pode me chamar de faxineiro,,Spune-mi curățătorul,Я — лучший чистильщик!,,Kalla mig städaren.,Bana temizlikçi de. +I'm not squeamish,TXT_RPLY1_SCRIPT02_D54576_IMNOT,〃,,,Mám silný žaludek.,Jeg er ikke squeamish,Ich bin nicht zimperlich.,,Sango estas nenio.,La sangre no es nada.,,En ole heikkohermoinen,J'ai pas peur de me tacher les mains.,Nem vagyok finnyás,Non mi impressiono facilmente,汚れ仕事でも構わない,나는 비위가 약하지 않아.,Ik ben niet katholiek.,Jeg er ikke pysete,Nie jestem wybredny.,Não sou muito escrupuloso,,Nu sunt mofturos,Я не боюсь крови.,,Jag är inte känslig.,Ben alıngan değilim. +One of my minions is stealing power with a tap on the mains somewhere. Find it and truncate his supply and I'll provide you with what you want. Bring me something as a token.,TXT_DLG_SCRIPT02_D56092_ONEOF,"〃 +(""messy"" chore)",,,"Jeden z mých poddaných stáčedlem někde z hlavního vedení krade energii. Najdi jej a odřízni dotyčného od zásoby a já ti dám, co chceš. Přines mi něco jako důkaz.","En af mine håndlangere stjæler strøm med en vandhane et sted. Find den og afbryd hans forsyning, så skal jeg give dig, hvad du vil have. Bring mig noget som et symbol.","Einer meiner Untertanen zapft irgendwo Strom ab. Finde die Anzapfung und kappe sie. Falls du Erfolg hast, kriegst du was du brauchst. Aber bring mir einen Beweis mit!",,"Unu el miaj sbiroj metis konektilon ien por ŝteli energion de la elektriza sistemo. Ĝin trovu kaj detruu, kaj mi donos al vi tion, kion vi petis. Alportu pruvon kiam vi finos.","Uno de mis secuaces puso en algún lado una toma en la red eléctrica para robar energía. Encuéntrala, trunca su suministro y te daré lo que pides. Tráeme algo como prueba una vez que termines.","Uno de mis secuaces puso en algún lado una toma en la red eléctrica para robar energía. Encuéntrala, destruye su suministro y te voy a dar lo que pides. Tráeme algo como prueba una vez que termines.","Yksi alamaisistani varastaa verkkovirtaa jossakin sijaitsevalla salaisella kytkennällä. Löydä se ja katkaise hänen jakelunsa, niin annan sinulle haluamasi. Tuo minulle jotain todisteeksi.",Un de mes larbins pompe de l'électricité avec une connection pirate dans les transformateurs là haut. Trouvez là et coupez sa connection. Je vous donnerai ce que vous voulez. Ramenez moi une preuve.,"Az egyik alattvalóm áramot lop egy dugasszal a központi hálózatnál valahol. Találd meg, majd válaszd el az ellátását, és én adok neked amit akarsz. Hozz nekem valamit bizonyítékként","Uno dei miei tirapiedi sta rubando energia con un suo aggeggio attaccato alla rete elettrica da qualche parte. Trova questo aggeggio e staccalo dalla rete, e ti darò quello che desideri. Portami qualcosa come prova.","私の手下の一人が水力発電から電力を盗んで いるらしい。それを見つけ供給を切って くれれば君の望む物をやろう。 -その象徴となるのも持ってきてほしい。",내 부하 중 한 명이 어딘가에 있는 동력선에 추출기를 꽂아 동력을 훔치고 있다는군. 그것을 찾아내서 그의 공급을 자르면 네가 원하는 것을 제공하지. 증거가 될만한 그것을 가져와.,Een van mijn acolieten steelt stroom met een kraan op het lichtnet ergens. Zoek het en snoei zijn aansluiting in en ik zal je voorzien van wat je wilt. Breng me iets als teken.,"Jeden z moich sług kradnie gdzieś moc w przewodach za pomocą przełącznika. Znajdź go i odetnij jego dostawę mocy, a dam ci co chcesz. Przynieś mi coś jako dowód.",Um dos meus capangas está roubando energia por uma ligação clandestina em algum lugar. Encontre-o e corte essa ligação e conseguirei o que você quer. Traga algo como prova.,,"Unul dintre slujitorii mei fură electricitate cu robinetul pe undeva. Află cum face asta, distruge-i proviziile, și îți voi oferi ceea ce vrei. Adu-mi și ceva ca dovadă.","Кто-то из моих подчинённых отводит энергию откуда-то из питающей сети. Найди и отключи эту установку — тогда получишь то, за чем пришёл. И принеси мне что-нибудь в качестве доказательства.","Један од мојих слуга краде електрицитет са славином на копну негде. Нађите то и уништите му залихе, а ја ћу вам дати оно што желите. Донесите ми нешто као знак. " -Where do I find this tap?,TXT_RPLY0_SCRIPT02_D56092_WHERE,,,,Kde najdu tohle stáčedlo?,Wo finde ich die Anzapfung?,,,¿Dónde encuentro la intervención?,,,Où est-ce que je trouve cette connection?,Hol találom ezt a dugaszt?,,どうやって突き止めたらいい?,그 추출기는 어디에 찾을 수 있지?,Waar vind ik deze kraan?,Gdzie znajdę ten przełącznik?,Onde encontro essa ligação clandestina?,,Unde-i găsesc robinetul?,Где может находиться эта установка?, -"If I knew, it wouldn't be a chore now would it? Use your charm, but shut off his supply.",TXT_DLG_SCRIPT02_D57608_IFIKN,,,,"Kdybych věděl, nebyla by to práce, ne? Použij svůj šarm, ale vypni mu přívod.","Wenn ich das wüsste, wäre das keine lästige Angelegenheit, nicht wahr? Benutze deinen Charme, aber schalte seine Versorgung aus.",,,"Si lo supiera, no sería un recado, ¿no? Usa tu encanto, pero corta su suministro. -","Si lo supiera, no sería un problema ahora, ¿verdad? Usa tu encanto, pero corta su suministro. -",,"Si je le savais, ce ne serait pas une corvée, non? Utiliser votre charme si il le faut, mais coupez cette connection.","Ha tudnám, nem lenne ez a feladat már. Használd a bájodat, de állítsd le az ellátást.",,"私が知っていたら、こんな雑用はさせない +その象徴となるのも持ってきてほしい。",내 부하 중 한 명이 어딘가에 있는 동력선에 추출기를 꽂아 동력을 훔치고 있다는군. 그것을 찾아내서 그의 공급을 자르면 네가 원하는 것을 제공하지. 증거가 될만한 그것을 가져와.,Een van mijn acolieten steelt stroom met een kraan op het lichtnet ergens. Zoek het en snoei zijn aansluiting in en ik zal je voorzien van wat je wilt. Breng me iets als teken.,"En av håndlangerne mine stjeler strøm med en kran på strømnettet et sted. Finn den og kutt forsyningen hans, så gir jeg deg det du vil ha. Gi meg noe som et symbol.","Jeden z moich sług kradnie gdzieś moc w przewodach za pomocą przełącznika. Znajdź go i odetnij jego dostawę mocy, a dam ci co chcesz. Przynieś mi coś jako dowód.",Um dos meus capangas está roubando energia por uma ligação clandestina em algum lugar. Encontre e corte essa ligação e conseguirei o que você quer. Traga algo como prova.,,"Unul dintre slujitorii mei fură electricitate cu robinetul pe undeva. Află cum face asta, distruge-i proviziile, și îți voi oferi ceea ce vrei. Adu-mi și ceva ca dovadă.","Кто-то из моих подчинённых отводит энергию откуда-то из питающей сети. Найди и отключи эту установку — тогда получишь то, за чем пришёл. И принеси мне что-нибудь в качестве доказательства.",,En av mina hantlangare stjäl ström med en kran på elnätet någonstans. Hitta den och avbryta hans leverans så ska jag förse dig med det du vill ha. Ta med dig något som ett tecken.,"Kölelerimden biri bir yerdeki şebekeden güç çalıyor. Onu bul ve kaynağını kes, ben de sana istediğini vereyim. Bana simge olarak bir şey getir." +Where do I find this tap?,TXT_RPLY0_SCRIPT02_D56092_WHERE,"〃 +(〃)",,,Kde najdu to stáčedlo?,Hvor kan jeg finde denne vandhane?,Wo finde ich die Anzapfung?,,Kie estas la konektilo?,¿Dónde está la toma?,,Mistä tämä kytkentä löytyy?,Où est-ce que je trouve cette connection?,Hol találom ezt a dugaszt?,E dove lo trovo questo aggeggio?,どうやって突き止めたらいい?,그 추출기는 어디에 찾을 수 있지?,Waar vind ik deze kraan?,Hvor finner jeg denne kranen?,Gdzie znajdę ten przełącznik?,Onde encontro essa ligação clandestina?,,Unde-i găsesc robinetul?,Где может находиться эта установка?,,Var hittar jag den här kranen?,Bu musluğu nerede bulabilirim? +"If I knew, it wouldn't be a chore now would it? Use your charm, but shut off his supply.",TXT_DLG_SCRIPT02_D57608_IFIKN,"〃 +(〃)",,,"Kdybych věděl, nebyla by to práce, ne? Použij svůj šarm, ale vypni dotyčnému přívod.","Hvis jeg vidste det, ville det ikke være så besværligt, vel? Brug din charme, men luk for hans forsyning.","Wenn ich das wüsste, wäre das keine lästige Angelegenheit, nicht wahr? Benutze deinen Charme, aber schalte seine Versorgung aus.",,"Se mi scius tion, mi ne petus ĉi tion al vi, ĉu ne? Uzu vian ĉarmon, sed interrompu lian provizadon.","Si lo supiera no te lo estaría pidiendo, ¿no? Usa tu encanto, pero corta su suministro. +",,"Jos tietäisin sen, eihän se silloin enää olisi askare, eihän? Käytä sulokkuutasi, mutta katkaise hänen sähkönsä.","Si je le savais, ce ne serait pas une corvée, non? Utiliser votre charme si il le faut, mais coupez cette connection.","Ha tudnám, nem lenne ez a feladat már. Használd a bájodat, de állítsd le az ellátást.","E se lo sapessi, non sarebbe mica una faccenda scomoda! Usa il tuo fascino, ma metti fine al suo schema.","私が知っていたら、こんな雑用はさせない だろう?誰かをでっちあげるか、 聞き込みでもするんだ。","만약 내가 그 위치를 알았다면 지루한 심부름이 됐겠지, 그렇지 않아? 네 머리를 써! 그리고 그 추출기를 찾아. - \cy배부른 돼지 같은 녀석. 난 이 추출기에 대해서 아무것도 몰라. 너무 급하게 하지 말자.","Als ik het wist, zou het nu geen karwei zijn, toch? Gebruik je charme, maar schakel zijn voorraad uit.","Gdybym wiedział, to nie byłby problem, prawda? Wykorzystaj swój spryt, ale pamiętaj by odciąć mu dostawę.","Se eu soubesse, não seria uma tarefa chata, não é mesmo? Use seu charme, mas corte essa ligação.",,"Dacă știam, n-ar mai fi fost o corvoadă, este? Folosește-ți farmecul, dar distruge-i proviziile.","Если бы я знал, то справился бы с этим сам, как считаешь? Делай что хочешь, но прекрати утечку энергии. ", -"Tell you what, there's a lying sack named Derwin who has been selling children to the Order. I won't tolerate that kind of depravity. Not without my cut. Derwin works in the warehouse. Kill him and bring me his, ear, and I'll see what I can do.",TXT_DLG_SCRIPT02_D59124_TELLY,,,,"Mám problém s pupkáčem jménem Derwin, který prodává děti Řádu. Takovou odpornost nemůžu tolerovat, ne bez mého podílu. Derwin pracuje ve skladišti. Zab ho a přines mi jeho ucho. Uvidím, co pro tebe budu moci udělat.","Ich sag dir was, da gibt es so einen lügenden Kerl namens Derwin, der Kinder an den Orden verkauft hat. Ich kann so eine Verdorbenheit nicht tolerieren. Nicht ohne meinen Anteil. Derwin arbeitet im Lagerhaus. Töte ihn und bring mir sein Ohr und ich werde sehen was ich tun kann.",,,"Te diré qué, hay un saco mentiroso llamado Derwin que ha estado vendiendo niños a La Orden. No toleraré ese tipo de depravación. No sin mi parte. Derwin trabaja en el almacén. Mátalo y tráeme su, oreja, y veré qué puedo hacer.",,,"Eh bien, il y a une raclure appelée Derwin qui vend des enfants à l'Ordre. Je ne tolère pas ce type d'atrocité, du moins pas sans ma part des frais. Derwin travaille dans l'entrepôt. Tuez-le et ramenez moi son oreille, je verrais ce que je peux faire pour vous.",,,"教えよう、ダーウィンとかいう恥知らずが + \cy배부른 돼지 같은 녀석. 난 이 추출기에 대해서 아무것도 몰라. 너무 급하게 하지 말자.","Als ik het wist, zou het nu geen karwei zijn, toch? Gebruik je charme, maar schakel zijn voorraad uit.","Hvis jeg visste det, ville det ikke være et ork, ville det vel? Bruk sjarmen din, men steng av tilførselen hans.","Gdybym wiedział, to nie byłby problem, prawda? Wykorzystaj swój spryt, ale pamiętaj by odciąć mu dostawę.","Se eu soubesse, não seria uma tarefa chata, não é mesmo? Use seu charme, mas corte essa ligação.",,"Dacă știam, n-ar mai fi fost o corvoadă, este? Folosește-ți farmecul, dar distruge-i proviziile.","Если бы я знал, то справился бы с этим сам, как считаешь? Пусти в ход свои таланты, но прекрати утечку энергии.",,"Om jag visste det skulle det inte vara så jobbigt, eller hur? Använd din charm, men stäng av hans förråd.","Eğer bilseydim, bu bir angarya olmazdı, değil mi? Cazibeni kullan ama onun kaynağını kapat." +"Tell you what, there's a lying sack named Derwin who has been selling children to the Order. I won't tolerate that kind of depravity. Not without my cut. Derwin works in the warehouse. Kill him and bring me his, ear, and I'll see what I can do.",TXT_DLG_SCRIPT02_D59124_TELLY,"〃 +(""bloody"" chore)",,,"Mám problém s pupkáčem jménem Derwin, který Řádu prodává děti. Takovou odpornost nemůžu tolerovat, ne bez mého podílu. Derwin pracuje ve skladišti. Zab ho a přines mi jeho ucho a já uvidím, co pro tebe budu moci udělat.","Ved du hvad, der er en løgnagtig sæk ved navn Derwin, der har solgt børn til Ordenen. Jeg vil ikke tolerere den slags fordærv. Ikke uden min andel. Derwin arbejder i lageret. Dræb ham og giv mig hans øre, så skal jeg se, hvad jeg kan gøre.","Ich sag dir was, da gibt es so einen lügenden Kerl namens Derwin, der Kinder an den Orden verkauft hat. Ich kann so eine Verdorbenheit nicht tolerieren. Nicht ohne meinen Anteil. Derwin arbeitet im Lagerhaus. Töte ihn und bring mir sein Ohr und ich werde sehen was ich tun kann.",,"Aŭskultu ĉi tion. Estas fimensogulo nomata Derwin, kiu kutimas vendi infanojn al La Ordeno, kaj mi ne toleros tian perversecon: ne se li ne donos parton de la gajnoj. Derwin laboras en la magazeno. Mortigu lin, alportu lian orelon kaj mi vidos tion, kion mi povas fari.","A ver, te cuento. Hay un sucio mentiroso llamado Derwin que ha estado vendiendo niños a La Orden, y no toleraré ese tipo de perversión: no si no me da mi parte. Derwin trabaja en el almacén. Mátalo, tráeme su oreja y veré qué puedo hacer.","A ver, te cuento. Hay un sucio mentiroso llamado Derwin que ha estado vendiendo niños a La Orden, y no puedo tolerar ese tipo de perversión: no si no me da mi parte. Derwin trabaja en el almacén. Mátalo, tráeme su oreja y voy a ver qué puedo hacer.","Annapa, kun kerron valepukista nimeltä Derwin, joka myy lapsia Veljeskunnalle. En voi suvaita sellaista turmeltuneisuutta... jossa en pääse itse osingoille. Derwin työskentelee varastolla. Tapa hänet ja tuo minulle hänen... korvansa, ja katson sitten, jos voin olla avuksi.","Eh bien, il y a une raclure appelée Derwin qui vend des enfants à l'Ordre. Je ne tolère pas ce type d'atrocité, du moins pas sans ma part des frais. Derwin travaille dans l'entrepôt. Tuez-le et ramenez moi son oreille, je verrais ce que je peux faire pour vous.","Na figyusz, van egy Derwin nevű hazug genya, aki gyerekeket árul a Rend számára. Nem tolerálom az ilyen romlottságot. Legalábbis a részesedésem nélkül. Derwin a raktárban dolgozik. Intézd el, és hozdd el a fülét, meglátom mit tehetek érted.","Senti questa, ci sta questo sporco bugiardo chiamato Derwin che sta vendendo bambini all'Ordine. Non tollero queste azioni depravate. Non senza che io riceva una fetta dei soldi. Derwin lavora al magazzino. Fallo fuori e portami un suo, orecchio, e vedrò cosa posso fare.","教えよう、ダーウィンとかいう恥知らずが 子供をオーダーへ売りつけているようだ。 私に分け前無しに、そんな恥ずべき行為を 許すわけには行かん。ダーウィンは倉庫で 勤務している。殺った証拠として奴の、耳を、 -持ってきたまえ。","그렇담, 더윈이라는 뚱땡이가 지금 아이들을 붙잡아 오더에 팔아넘기는 짓을 일삼고 있어. 너무나도 괘씸해... 내게 이득이 전혀 없으니. 더윈은 발전소 주변 창고에서 일하고 있어. 그를 죽이고, 그의, 귀를 뜯어서 가져와. 그럼 거래를 진행하지.","Weet je wat, er is een leugenachtige zak genaamd Derwin die kinderen aan de Orde heeft verkocht. Dat soort verdorvenheid tolereer ik niet. Niet zonder mijn deel. Derwin werkt in het magazijn. Dood hem en breng me zijn oor, en ik zal zien wat ik kan doen.","Słuchaj, jest tu pewien worek kłamstw, który nazywa się Derwin. Sprzedaje on Zakonowi dzieci. Nie będę tolerował takiego zepsucia. Nie bez moich udziałów. Derwin pracuje w magazynie. Zabij go i przynieś mi jego... ucho, a zobaczę co da się zrobić.","É o seguinte, tem um mentiroso desgraçado chamado Derwin que anda vendendo crianças para a Ordem. Não vou tolerar esse tipo de depravação. Não sem a minha parte. Derwin trabalha no depósito. Mate-o e traga a...orelha dele e verei o que posso fazer.",,"Să-ți zic ceva, un gunoi mincinos pe nume Derwin vinde copii Ordinului. Nu tolerez ceva atât de depravat. Nu fără să primesc și eu ceva. Derwin lucrează în depozit. Omoară-l și adu-mi... urechea lui, și-o să văd ce pot face.","Лживый мешок дерьма по имени Дервин продаёт Ордену детей. Я не терплю такой безнравственности, особенно когда меня не берут в долю. Дервин работает на складе. Убей его и принеси мне его... ухо, и я посмотрю, чем cмогу тебе помочь.", -How do I get in?,TXT_RPLY0_SCRIPT02_D59124_HOWDO,,,,Jak se dostanu dovnitř?,Wie komme ich hinein?,,,¿Cómo entro?,,,Comment j'y rentre?,,,どうすれば入れる?,어떻게 들어가지?,Hoe kom ik binnen?,Jak się tam dostanę?,Como faço para entrar?,,Cum ajung înăuntru?,Как мне туда попасть?, -"This key will get you into the power station. On second thought, cut off the ear and then kill him. Much better.",TXT_DLG_SCRIPT02_D60640_THISK,,,,"Tímhle klíčem se dostaneš do elektrárny. Na druhou stranu, nejprve mu uřízni ucho, pak ho zabij. Mnohem lepší.","Dieser Schlüssel wird dich ins Kraftwerk bringen. Andererseits, schneide ihm erst das Ohr ab und dann töte ihn. Viel besser.",,,"Esta llave te llevará a la central eléctrica. Pensándolo bien, córtale la oreja y luego mátalo. Mucho mejor.",,,"Cette clé vous laissera entrer dans la centrale électrique. Maintenant que j'y pense, coupez-lui l'oreille, puis tuez-le. Ca me plaît plus comme ça.",,,"この鍵で発電所に入るんだ。出来れば、 +持ってきたまえ。","그렇담, 더윈이라는 뚱땡이가 지금 아이들을 붙잡아 오더에 팔아넘기는 짓을 일삼고 있어. 너무나도 괘씸해... 내게 이득이 전혀 없으니. 더윈은 발전소 주변 창고에서 일하고 있어. 그를 죽이고, 그의, 귀를 뜯어서 가져와. 그럼 거래를 진행하지.","Weet je wat, er is een leugenachtige zak genaamd Derwin die kinderen aan de Orde heeft verkocht. Dat soort verdorvenheid tolereer ik niet. Niet zonder mijn deel. Derwin werkt in het magazijn. Dood hem en breng me zijn oor, en ik zal zien wat ik kan doen.","Det er en løgnhals ved navn Derwin som har solgt barn til Ordenen. Jeg tolererer ikke den slags fordervelse. Ikke uten min andel. Derwin jobber på lageret. Drep ham og gi meg hans øre, så skal jeg se hva jeg kan gjøre.","Słuchaj, jest tu pewien worek kłamstw, który nazywa się Derwin. Sprzedaje on Zakonowi dzieci. Nie będę tolerował takiego zepsucia. Nie bez moich udziałów. Derwin pracuje w magazynie. Zabij go i przynieś mi jego... ucho, a zobaczę co da się zrobić.","É o seguinte, tem um mentiroso desgraçado chamado Derwin que anda vendendo crianças para a Ordem. Não vou tolerar esse tipo de depravação. Não sem a minha parte. Derwin trabalha no depósito. Mate-o e traga a...orelha dele e verei o que posso fazer.",,"Să-ți zic ceva, un gunoi mincinos pe nume Derwin vinde copii Ordinului. Nu tolerez ceva atât de depravat. Nu fără să primesc și eu ceva. Derwin lucrează în depozit. Omoară-l și adu-mi... urechea lui, și-o să văd ce pot face.","Лживый мешок дерьма по имени Дервин продаёт Ордену детей. Я не терплю такой безнравственности, особенно когда меня не берут в долю. Дервин работает в складе. Убей его и принеси мне его ухо, и я посмотрю, чем можно помочь.",,"Vet du vad, det finns en ljugande säck vid namn Derwin som har sålt barn till Orden. Jag tolererar inte den sortens fördärv. Inte utan min andel. Derwin arbetar i lagret. Döda honom och ge mig hans öra så ska jag se vad jag kan göra.","Bak ne diyeceğim, Tarikat'a çocuk satan Derwin adında yalancı bir çuval var. Bu tür bir ahlaksızlığa müsamaha göstermeyeceğim. Benim payım olmadan olmaz. Derwin depoda çalışıyor. Onu öldürüp kulağını bana getir, ne yapabileceğime bakarım." +How do I get in?,TXT_RPLY0_SCRIPT02_D59124_HOWDO,"〃 +(〃)",,,Jak se dostanu dovnitř?,Hvordan kommer jeg ind?,Wie komme ich hinein?,,Kiel mi eniru tien?,¿Cómo entro?,,Miten pääsen sisään?,Comment j'y rentre?,Hogy jutok be?,Come ci arrivo?,どうすれば入れる?,어떻게 들어가지?,Hoe kom ik binnen?,Hvordan kommer jeg inn?,Jak się tam dostanę?,Como faço para entrar?,,Cum ajung înăuntru?,Как мне туда попасть?,,Hur kommer jag in?,İçeri nasıl gireceğim? +"This key will get you into the power station. On second thought, cut off the ear and then kill him. Much better.",TXT_DLG_SCRIPT02_D60640_THISK,"〃 +(〃)",,,"Tímhle klíčem se dostaneš do elektrárny. Víš ty co, nejprve mu uřízni ucho, až pak ho zabij. Mnohem lepší.","Med denne nøgle kan du komme ind i kraftværket. Ved nærmere eftertanke, skær øret af og dræb ham så. Det er meget bedre.","Dieser Schlüssel wird dich ins Kraftwerk bringen. Andererseits, schneide ihm erst das Ohr ab und dann töte ihn. Viel besser.",,"Jen ŝlosilo de la elektrocentralo. Repensante pri tio, fortranĉu lian orelon kaj tiam mortigu lin. Multe plibone.","Aquí tengo una llave de la central eléctrica. Pensándolo bien, córtale la oreja y luego mátalo. Mucho mejor.",,"Tällä avaimella pääset voimalaitokseen. Nyt, kun tarkemmin ajattelen, niin sivalla ensin hänen korvansa, ja sitten tapa hänet. Paljon parempi.","Cette clé vous laissera entrer dans la centrale électrique. Maintenant que j'y pense, coupez-lui l'oreille, puis tuez-le. Ca me plaît plus comme ça.","Ezzel a kulccsal bejuthatsz az erőműbe. Jobban átgondolva, vádg le a fülét és öld meg. Sokkal jobb. ","Questa chiave ti farà entrare nella centrale energetica. Ora che ci penso, prima tagliagli l'orecchio, e poi uccidilo. Molto meglio.","この鍵で発電所に入るんだ。出来れば、 先に耳を切り落としてから殺してくれ。 -その方が良い。","이 열쇠만 있으면 발전소에 들어갈 수 있을 거야. 그리고 다시 생각해보니, 그 자식을 죽이기 전에, 먼저 귀를 뜯어. 그럼 더 나을 거 같군.","Met deze sleutel kom je in de centrale. Bij nader inzien, snij je het oor eraf en vermoord je hem. Veel beter.","Ten klucz pozwoli ci wejść do elektrowni. Z drugiej strony, najpierw odetnij mu ucho, a potem go zabij. Tak będzie lepiej.","Esta chave vai te ajudar a entrar na usina de energia. Pensando melhor, corte fora a orelha e depois mate ele. Muito melhor.",,"Cheia asta îți va oferi acces la stația electrică. Dacă mă gândesc mai bine, mai întâi taie-i urechea și abia apoi omoară-l. Mult mai bine.","С этим ключом ты пройдёшь на электростанцию. А, да, я тут подумал — сначала отрежь ему ухо, а затем убей. Так будет намного лучше.", -"Oh, I just love souvenirs. Here, this will get you into the prison. Talk to Warden Montag. Whatever you do after that, I don't want to know.",TXT_DLG_SCRIPT02_D62156_OHIJU,,,,"Ó, já prostě zbožňuju suvenýry. Tady, tohle tě dostane do vězení. Promluv si s dozorčím Montagem. Co máš v plánu dělat po tom, to už vědět nechci.","Oh, ich liebe Souvenirs. Hier, damit kommst du in das Gefängnis. Sprich mit Direktor Montag. Was du danach machen musst, weiß ich nicht.",,,"Oh, me encantan los recuerdos. Toma, esto te llevará a la prisión. Habla con el director Montag. Lo que hagas después de eso, no quiero saberlo.",,,"Oh, j'adore les souvenirs. Voilà, ça vous laissera entrer dans la prison. Parlez au gardien Montag. Ce que vous faites après, je m'en fous complètement.",,,"嬉しい手土産だ。では、これがあれば +その方が良い。","이 열쇠만 있으면 발전소에 들어갈 수 있을 거야. 그리고 다시 생각해보니, 그 자식을 죽이기 전에, 먼저 귀를 뜯어. 그럼 더 나을 거 같군.","Met deze sleutel kom je in de centrale. Bij nader inzien, snij je het oor eraf en vermoord je hem. Veel beter.","Denne nøkkelen får deg inn i kraftstasjonen. Ved nærmere ettertanke, skjær av øret og drep ham. Mye bedre.","Ten klucz pozwoli ci wejść do elektrowni. Z drugiej strony, najpierw odetnij mu ucho, a potem go zabij. Tak będzie lepiej.","Esta chave vai te ajudar a entrar na usina de energia. Pensando melhor, corte fora a orelha e depois mate ele. Muito melhor.",,"Cheia asta îți va oferi acces la stația electrică. Dacă mă gândesc mai bine, mai întâi taie-i urechea și abia apoi omoară-l. Mult mai bine.","С этим ключом ты пройдёшь на электростанцию. А, да, я тут подумал — сначала отрежь ему ухо, а затем убей. Так будет намного лучше.",,"Den här nyckeln tar dig in i kraftverket. Vid närmare eftertanke, skär av örat och döda honom sedan. Mycket bättre.","Bu anahtar seni elektrik santraline sokacak. Bir daha düşündüm de, kulağını kes ve sonra onu öldür. Çok daha iyi olur." +"Oh, I just love souvenirs. Here, this will get you into the prison. Talk to Warden Montag. Whatever you do after that, I don't want to know.",TXT_DLG_SCRIPT02_D62156_OHIJU,"〃 +(after completing ""messy"" chore)",,,"Ó, já prostě zbožňuju suvenýry. Tady, tohle tě dostane do vězení. Promluv si s dozorčím Montagem. Co máš v plánu dělat potom, to už vědět nechci.","Åh, jeg elsker souvenirs. Her, med den her kan du komme ind i fængslet. Tal med fængselsinspektør Montag. Hvad du end gør efter det, vil jeg ikke vide det.","Oh, ich liebe Souvenirs. Hier, damit kommst du in das Gefängnis. Sprich mit Direktor Montag. Was du danach machen musst, weiß ich nicht.",,"Ha, mi ŝategas memoraĵojn. Havu ĉi tion, kio ebligos al vi eniri la malliberejon. Parolu kun la provoso Montag. Tion ajn, kion vi faros poste, mi ne volas scii.","Ah, me encantan los recuerdos. Ten, con esto podrás entrar en la prisión. Habla con el carcelero Montag. Lo que hagas después de eso no quiero saberlo.","Ah, me encantan los recuerdos. Toma, con esto vas a poder entrar a la prisión. Habla con el carcelero Montag. Lo que hagas después de eso no quiero saberlo.","Minä siis niin rakastan matkamuistoja. Kas näin, pääset tällä vankilaan. Puhu vankilanjohtaja Montagin kanssa. Mitä teetkään sen jälkeen, en halua tietää.","Oh, j'adore les souvenirs. Voilà, ça vous laissera entrer dans la prison. Parlez au gardien Montag. Ce que vous faites après, je m'en fous complètement.","Oh, imádom az ajándékokat. Nesze, ezzel be fogsz tudni jutni a börtönbe. Beszélj Mondtag igazgatóval. Nem akarok tudni arról, mit teszel utána.","Ah, adoro i souvenir! Ecco qua, con questo potrai entrare nella prigione. Parla con Montag, il direttore del carcere. Quello che farai dopo, a me non interessa.","嬉しい手土産だ。では、これがあれば 刑務所に入れる。モンターグ所長と話すんだ。 -君がそこで何をしようが、私の管轄外だ。","오오, 난 기념품이 정말 좋아. 여기, 네가 원했던 감옥 통행증이야. 감옥으로 가서 몬탕 간수장에게 이야기해봐. 네가 어떤 짓을 저지르든, 그 후엔 절대로 알고 싶지 않아!","Oh, ik hou gewoon van souvenirs. Hier, dit zal je in de gevangenis brengen. Spreek met directeur Montag. Wat je daarna ook doet, ik wil het niet weten.","Oh, po prostu kocham pamiątki. Masz, to pozwoli ci wejść do więzienia. Pogadaj z Naczelnikiem Montagiem. Nie chcę wiedzieć co potem zrobisz.","Ah, eu simplesmente adoro suvenires. Tome, isto vai te ajudar a entrar na prisão. Fale com o carcereiro, Montag. O que você fizer depois disso, não quero saber.",,"Oh, ce mai ador suvenirurile. Aici, asta îți va permite să ajungi în interiorul închisorii. Vorbește cu gardianul Montag. Ce faci după aceea, nu vreau să știu.","О, как я люблю сувениры! Вот твой пропуск в тюрьму. Обратись к тюремщику Монтагу, а что ты будешь делать потом, я и знать не желаю.", -Thanks.,TXT_RPLY0_SCRIPT02_D62156_THANK,,,,Díky.,Danke.,,,Gracias.,,,Merci.,,,ありがとう。,고마워.,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Спасибо., -"Give you a hint. When I stop talking to you, you leave.",TXT_DLG_SCRIPT02_D63672_GIVEY,,,,"Dám ti radu: Když s tebou přestanu mluvit, odejdeš.","Hier mal ein Tipp. Wenn ich aufgehört habe mit dir zu reden, dann gehst du.",,,"Un consejo. Cuando dejo de hablarte, te vas.",,,"Petit conseil. Quand j'arrète de vous parler, vous sortez d'ici.",,,ヒントを出そう。話すのを止めたら去りたまえ。,"힌트를 하나 주지. 나랑 대화가 끝났으면, 넌 떠나는 거야.","Ik geef je een hint. Als ik niet meer met je praat, ga je weg.",Dam ci wskazówkę. Jak przestanę mówić to wyjdź.,"Uma dica. Quando eu terminar de falar contigo, você vai embora.",,"Îți dau un sfat. Când termin de discutat cu tine, pleci.","Дам тебе подсказку: когда я закончу говорить, ты уходишь.", -Do you have good news for me? I'm all ears.,TXT_DLG_SCRIPT02_D65188_DOYOU,,,,Máš pro mě dobré zprávy? Uši mám nastražené.,Hast du gute Neuigkeiten für mich? Ich bin ganz Ohr.,,,¿Tienes buenas noticias para mí? Soy todo oídos.,,,De bonnes nouvelles? Mes oreilles sont à vous.,,,私の耳に吉報を伝えに来たかね?,날 위한 좋은 소식이 있나? 열심히 듣고 있다구.,Heb je goed nieuws voor mij? Ik ben een en al oor.,Masz dobre wieści dla mnie? Zamieniam się w słuch.,Alguma notícia boa pra mim? Sou todo ouvidos.,,Ai vești bune pentru mine? Sunt numai urechi.,Есть для меня хорошие новости? Слушаю во все уши., -The deed is done!,TXT_RPLY0_SCRIPT02_D65188_THEDE,,,,Skutek je dokonán!,Es ist geschehen!,,,¡El trato está hecho!,,,C'est bel est bien fait.,,,やることはヤった,임무 완료!,De daad is gedaan!,Wszystko zrobione!,Está feito!,,Fapta e făcută.,Дело сделано!, -"Oh, I just love souvenirs. Here, this will get you into the prison. Talk to Warden Montag. Whatever you do after that, I don't want to know.",TXT_DLG_SCRIPT02_D66704_OHIJU,,,,"Ó, já prostě zbožňuju suvenýry. Tady, tohle tě dostane do vězení. Promluv si s dozorčím Montagem. Co máš v plánu dělat po tom, to už vědět nechci.","Oh, ich liebe Souvenirs. Hier, damit kommst du in das Gefängnis. Sprich mit Direktor Montag. Was du danach machen musst, weiß ich nicht.",,,"Oh, me encantan los recuerdos. Toma, esto te llevará a la prisión. Habla con el director Montag. Que hagas después de eso, no quiero saberlo.",,,"Oh, j'adore les souvenirs. Voilà, ça vous laissera entrer dans la prison. Parlez au gardien Montag. Ce que vous faites après, je m'en fous complètement.",,,"嬉しい手土産だ。では、これがあれば +君がそこで何をしようが、私の管轄外だ。","오오, 난 기념품이 정말 좋아. 여기, 네가 원했던 감옥 통행증이야. 감옥으로 가서 몬탕 간수장에게 이야기해봐. 네가 어떤 짓을 저지르든, 그 후엔 절대로 알고 싶지 않아!","Oh, ik hou gewoon van souvenirs. Hier, dit zal je in de gevangenis brengen. Spreek met directeur Montag. Wat je daarna ook doet, ik wil het niet weten.","Jeg elsker suvenirer. Denne får deg inn i fengselet. Snakk med fengselsdirektør Montag. Uansett hva du gjør etter det, vil jeg ikke vite det.","Oh, po prostu kocham pamiątki. Masz, to pozwoli ci wejść do więzienia. Pogadaj z Naczelnikiem Montagiem. Nie chcę wiedzieć co potem zrobisz.","Ah, eu simplesmente adoro suvenires. Tome, isto vai te ajudar a entrar na prisão. Fale com o carcereiro, Montag. O que você for fazer depois não me interessa.",,"Oh, ce mai ador suvenirurile. Aici, asta îți va permite să ajungi în interiorul închisorii. Vorbește cu gardianul Montag. Ce faci după aceea, nu vreau să știu.","О, как я люблю сувениры! Вот твой пропуск в тюрьму. Обратись к тюремщику Монтагу, а что ты будешь делать потом, я и знать не желаю.",,"Jag älskar souvenirer. Här, den här tar dig in i fängelset. Prata med fängelsedirektör Montag. Vad du än gör efter det vill jag inte veta.","Hatıra eşyalarına bayılırım. İşte, bu seni hapishaneye sokacak. Müdür Montag ile konuş. Ondan sonra ne yaparsan yap, bilmek istemiyorum." +Thanks.,TXT_RPLY0_SCRIPT02_D62156_THANK,"〃 +(〃)",,,Díky.,Jeg vil ikke vide det. Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Kösz.,Grazie.,ありがとう。,고마워.,Bedankt.,Takk skal du ha.,Dzięki.,Agradeço.,,Mulțumesc.,Спасибо.,,Jag vill inte veta. Tack.,Teşekkürler. +"Give you a hint. When I stop talking to you, you leave.",TXT_DLG_SCRIPT02_D63672_GIVEY,〃,,,"Dám ti radu: Když s tebou přestanu mluvit, znamená to odchod.","Jeg giver dig et hint. Når jeg holder op med at tale med dig, går du.","Hier mal ein Tipp. Wenn ich aufgehört habe mit dir zu reden, dann gehst du.",,"Jen konsilo: Kiam mi ĉesas paroli al vi, vi foriras.","Un consejo: Cuando dejo de hablarte, te vas.",,"Pienenä vinkkinä, että kun lakkaan puhumasta sinulle, sinä lähdet.","Petit conseil. Quand j'arrète de vous parler, vous sortez d'ici.","Csak egy tanács. Amikor már nem beszélek hozzád, húzz el.","Ti do un consiglio. Quando io smetto di parlare, tu vai via.",ヒントを出そう。話すのを止めたら去りたまえ。,"힌트를 하나 주지. 나랑 대화가 끝났으면, 넌 떠나는 거야.","Ik geef je een hint. Als ik niet meer met je praat, ga je weg.","Jeg skal gi deg et hint. Når jeg slutter å snakke med deg, drar du.",Dam ci wskazówkę. Jak przestanę mówić to wyjdź.,"Uma dica. Quando eu terminar de falar contigo, você vai embora.",,"Îți dau un sfat. Când termin de discutat cu tine, pleci.","Дам тебе подсказку: когда я закончу говорить, ты уходишь.",,"Jag ger dig en ledtråd. När jag slutar prata med dig, går du.","Sana bir ipucu vereyim. Seninle konuşmayı bıraktığımda, gideceksin." +Do you have good news for me? I'm all ears.,TXT_DLG_SCRIPT02_D65188_DOYOU,"〃 +(after completing ""bloody"" chore)",,,Máš pro mě dobré zprávy? Uši mám nastražené.,Har du gode nyheder til mig? Jeg er lutter ører.,Hast du gute Neuigkeiten für mich? Ich bin ganz Ohr.,,Ĉu vi alportas bonajn novaĵojn? Mi estas tute aŭskultema.,¿Tienes buenas noticias para mí? Soy todo oídos.,,Onko sinulla minulle hyviä uutisia? Olen pelkkänä korvana.,De bonnes nouvelles? Mes oreilles sont à vous.,Van valami jó híred számomra? Csupa fül vagyok.,Hai buone notizie per me? Sono tutto orecchi...,私の耳に吉報を伝えに来たかね?,날 위한 좋은 소식이 있나? 열심히 듣고 있다구.,Heb je goed nieuws voor mij? Ik ben een en al oor.,Har du gode nyheter til meg? Jeg er lutter øre.,Masz dobre wieści dla mnie? Zamieniam się w słuch.,Alguma notícia boa pra mim? Sou todo ouvidos.,,Ai vești bune pentru mine? Sunt numai urechi.,Есть для меня хорошие новости? Слушаю во все уши.,,Har du goda nyheter till mig? Jag är alldeles nyfiken.,Benim için iyi haberlerin var mı? Can kulağıyla dinliyorum. +The deed is done!,TXT_RPLY0_SCRIPT02_D65188_THEDE,"〃 +(〃)",,,Skutek je dokonán!,Det er gjort!,Es ist geschehen!,,Interkonsento plenumita!,¡El trato está hecho!,,Se on tehty!,C'est bel est bien fait.,Véghezvittem a büntettet.,È fatta!,やることはヤった,임무 완료!,De daad is gedaan!,Gjerningen er utført!,Wszystko zrobione!,Está feito!,,Fapta e făcută.,Дело сделано!,,Det är gjort!,İş tamamdır! +"Oh, I just love souvenirs. Here, this will get you into the prison. Talk to Warden Montag. Whatever you do after that, I don't want to know.",TXT_DLG_SCRIPT02_D66704_OHIJU,"〃 +(〃)",,,"Ó, já prostě zbožňuju suvenýry. Tady, tohle tě dostane do vězení. Promluv si s dozorčím Montagem. Co máš v plánu dělat po tom, to už vědět nechci.","Åh, jeg elsker bare souvenirs. Her, det her vil få dig ind i fængslet. Tal med fængselsinspektør Montag. Hvad du end gør efter det, vil jeg ikke vide det.","Oh, ich liebe Souvenirs. Hier, damit kommst du in das Gefängnis. Sprich mit Direktor Montag. Was du danach machen musst, weiß ich nicht.",,"Ha, mi ŝategas memoraĵojn. Havu ĉi tion, kio ebligos al vi eniri la malliberejon. Parolu kun la provoso Montag. Tion ajn, kion vi faros poste, mi ne volas scii.","Ah, me encantan los recuerdos. Ten, con esto podrás entrar en la prisión. Habla con el carcelero Montag. Lo que hagas después de eso no quiero saberlo.","Ah, me encantan los recuerdos. Toma, con esto vas a poder entrar a la prisión. Habla con el carcelero Montag. Lo que hagas después de eso no quiero saberlo.","Voi, kun minä rakastan matkamuistoja. Kas näin, pääset tällä vankilaan. Puhu vankilanjohtaja Montagin kanssa. Mitä teetkään sen jälkeen, en halua tietää.","Oh, j'adore les souvenirs. Voilà, ça vous laissera entrer dans la prison. Parlez au gardien Montag. Ce que vous faites après, je m'en fous complètement.","Oh, imádom az ajándékokat. Nesze, ezzel be fogsz tudni jutni a börtönbe. Beszélj Mondtag igazgatóval. Nem akarok tudni arról, mit teszel utána.","Ah, adoro i souvenir! Ecco qua, con questo potrai entrare nella prigione. Parla con Montag, il direttore del carcere. Quello che farai dopo, a me non interessa.","嬉しい手土産だ。では、これがあれば 刑務所に入れる。モンターグ所長と話すんだ。 -君がそこで何をしようが、私の管轄外だ。","오오, 난 기념품이 정말 좋아. 여기, 네가 원했던 감옥 통행증이야. 감옥으로 가서 몬탕 간수장에게 이야기해봐. 네가 어떤 짓을 저지르든, 그 후엔 절대로 알고 싶지 않아!","Oh, ik hou gewoon van souvenirs. Hier, dit zal je in de gevangenis brengen. Praat met directeur Montag. Wat je daarna ook doet, ik wil het niet weten.","Oh, po prostu kocham pamiątki. Masz, to pozwoli ci wejść do więzienia. Pogadaj z Naczelnikiem Montagiem. Nie chcę wiedzieć co potem zrobisz.","Ah, eu simplesmente adoro suvenires. Tome, isto vai te ajudar a entrar na prisão. Fale com o carcereiro, Montag. O que você fizer depois disso, não quero saber.",,"Oh, ce mai ador suvenirurile. Aici, asta îți va permite să ajungi în interiorul închisorii. Vorbește cu gardianul Montag. Ce faci după aceea, nu vreau să știu.","О, как я люблю сувениры! Вот твой пропуск в тюрьму. Обратись к тюремщику Монтагу, а что ты будешь делать потом, я и знать не желаю.", -Fine by me.,TXT_RPLY0_SCRIPT02_D66704_FINEB,,,,To je dobře.,Ist mir recht.,,,Bien por mi.,,,Ca me convient.,,,良好だ。,난 괜찮아.,Ik vind het prima.,"Jak dla mnie, w porządku.","Por mim, sem problemas.",,Mie-mi convine.,По рукам!, -"So you're the fool who stole the chalice? I'm going to have you arrested as a rebel thief... Thereby enhancing my position with the Order. How does it feel to be an unwitting pawn? I'll give you a hint, it's gonna hurt. ",TXT_DLG_SCRIPT02_D68220_SOYOU,,,,"Tak ty jsi ten blázen, který ukradl kalich? Teď tě nechám zatknout jako rebelského zloděje... a tím si upevním svou pozici s Řádem. Jaký je to pocit, být bezděčnou figurkou? Dám ti radu: Bude to bolet.","So, du bist also der Narr der den Kelch gestohlen hat? Ich werde dich als Dieb der Rebellen verhaften lassen und dadurch meine Position im Orden verbessern. Wie fühlt es sich an als ahnungslose Schachfigur? Ich geb' dir einen Tipp: Es wird wehtun.",,,"¿Así que tú eres el necio que robó el cáliz? Voy a arrestarte como ladrón rebelde... Con ello mejorando mi posición con la Orden. ¿Cómo se siente ser un inconsciente peón? Te daré una pista, va a doler.","¿Tú eres quién robó el cáliz? Voy a arrestarte como ladrón rebelde... Con ello, mejoraré mi posición con La Orden. ¿Cómo se siente ser un peón? Te daré una pista, te va a doler.",,"Vous êtes l'abruti qui a volé le calice? Maintenant il faut que je vous arrète comme voleur rebelle.. Ca va aider ma position dans l'Ordre. Comment ça fait d'être un pion ignorant? Petite idée, ça va faire mal.",,,"それで、お前が聖杯を盗んだ愚か者か? +君がそこで何をしようが、私の管轄外だ。","오오, 난 기념품이 정말 좋아. 여기, 네가 원했던 감옥 통행증이야. 감옥으로 가서 몬탕 간수장에게 이야기해봐. 네가 어떤 짓을 저지르든, 그 후엔 절대로 알고 싶지 않아!","Oh, ik hou gewoon van souvenirs. Hier, dit zal je in de gevangenis brengen. Praat met directeur Montag. Wat je daarna ook doet, ik wil het niet weten.","Jeg elsker suvenirer. Denne får deg inn i fengselet. Snakk med fengselsdirektør Montag. Uansett hva du gjør etter det, vil jeg ikke vite det.","Oh, po prostu kocham pamiątki. Masz, to pozwoli ci wejść do więzienia. Pogadaj z Naczelnikiem Montagiem. Nie chcę wiedzieć co potem zrobisz.","Ah, eu simplesmente adoro suvenires. Tome, isto vai te ajudar a entrar na prisão. Fale com o carcereiro, Montag. O que você for fazer depois não me interessa.",,"Oh, ce mai ador suvenirurile. Aici, asta îți va permite să ajungi în interiorul închisorii. Vorbește cu gardianul Montag. Ce faci după aceea, nu vreau să știu.","О, как я люблю сувениры! Вот твой пропуск в тюрьму. Обратись к тюремщику Монтагу, а что ты будешь делать потом, я и знать не желаю.",,"Jag älskar souvenirer. Här, den här tar dig in i fängelset. Prata med Warden Montag. Vad du än gör efter det vill jag inte veta.","Hatıra eşyalarına bayılırım. İşte, bu seni hapishaneye sokacak. Müdür Montag ile konuş. Ondan sonra ne yaparsan yap, bilmek istemiyorum." +Fine by me.,TXT_RPLY0_SCRIPT02_D66704_FINEB,"〃 +(〃)",,,To je dobře.,Det er fint med mig.,Ist mir recht.,,Mi ne malkonsentas.,Por mí está bien.,,Sopii minulle.,Ca me convient.,Felőlem rendben van.,Per me va bene.,良好だ。,난 괜찮아.,Ik vind het prima.,Greit for meg.,"Jak dla mnie, w porządku.","Por mim, sem problemas.",,Mie-mi convine.,По рукам!,,Det är okej för mig.,Bana uyar. +"So you're the fool who stole the chalice? I'm going to have you arrested as a rebel thief... Thereby enhancing my position with the Order. How does it feel to be an unwitting pawn? I'll give you a hint, it's gonna hurt. ",TXT_DLG_SCRIPT02_D68220_SOYOU,〃,,,"Tak ty jsi ten blázen, který ukradl kalich? Teď tě nechám zatknout jako rebelského zloděje... a tím si upevním svou pozici s Řádem. Jaký je to pocit, být bezděčnou figurkou? Dám ti radu: Bude to bolet.","Så du er det fjols, der stjal bægeret? Jeg vil få dig arresteret som oprørstyv... og derved forbedre min position i ordenen. Hvordan føles det at være en uvidende brik? Jeg skal give dig et hint, det kommer til at gøre ondt.","So, du bist also der Narr der den Kelch gestohlen hat? Ich werde dich als Dieb der Rebellen verhaften lassen und dadurch meine Position im Orden verbessern. Wie fühlt es sich an als ahnungslose Schachfigur? Ich geb' dir einen Tipp: Es wird wehtun.",,"Vi do estas la stultulo, kiu ŝtelis la kalikon, ĉu? Mi kaptos vin kiel ribelan ŝteliston, tiel mi plibonigos mian statuson kun La Ordeno. Kiel vi sentas, ke vi estas nevola marioneto? Jen aludeto: tio doloros vin.","¿Así que tú eres el necio que ha robado el cáliz? Te capturaré como ladrón rebelde, mejorando así mi posición con La Orden. ¿Qué se siente ser un peón involuntario? Una pista: te dolerá.","¿Así que tú eres el tonto que se robó el cáliz? Te voy a capturar como ladrón rebelde, mejorando así mi posición con La Orden. ¿Qué se siente ser un peón involuntario? Una pista: te va a doler.","Vai sinä olet se houkka, joka varasti kalkin? Pidätytän sinut kapinallisvarkaana, siten parantaen asemaani Veljeskunnassa. Miltäpä tuntuu olla tahaton pelinappula? Annanpa vihjeen, se tulee sattumaan.","Vous êtes l'abruti qui a volé le calice? Maintenant il faut que je vous arrète comme voleur rebelle.. Ca va aider ma position dans l'Ordre. Comment ça fait d'être un pion ignorant? Petite idée, ça va faire mal.",Szóval te vagy az isten barma aki ellopta a kelyhet? Jól letartóztatlak mint lázadó tolvaj...ezzel megerősítve a pozíciómat a Rendben. Milyen érzés egy tudatlan parasztnak lenni? Adok egy tippet: marhára fájni fog.,"Quindi sei tu il folle che ha rubato il calice? Ti farò arrestare come un ladro ribelle... E così facendo salirò nei ranghi dell'Ordine. Come ci si sente ad essere un'inconsapevole pedina? Ti do un consiglio, farà male.","それで、お前が聖杯を盗んだ愚か者か? 私は反賊としてお前を逮捕するつもりだ... そうすればオーダーの地位は上がる。 捨て駒に成るというのはどんな感じだ? -ヒントを教えよう、お前はもう助からない。","그래서 네가 그 성배를 훔친 바보로군? 반군 절도범으로 체포해주지... 오더에서의 내 위치도 올리는 겸. 모르는 사이에 장물아비가 된 기분이 어떤가? 힌트를 주지, 정말 아플 거야.","Dus jij bent de dwaas die de kelk heeft gestolen? Ik ga je laten arresteren als een rebellendief.... Daardoor verbeter ik mijn positie bij de Orde. Hoe voelt het om een onwetende pion te zijn? Ik zal je een hint geven, het gaat pijn doen.","Więc... to ty jesteś tym głupcem, który ukradł kielich? Aresztuję cię jako złodzieja-buntownika... A tym samym zwiększając swe uznanie u Zakonu. Jakie to uczucie jak się jest nieświadomym pionkiem? Podpowiedź, będzie bolało.","Então você é o imbecil que roubou o cálice? Eu vou mandar prender você como um ladrão rebelde... E assim a minha posição na Ordem vai melhorar. Como se sente sendo um plebeu ignorante? Vou te dar uma pista, vai doer.",,"Deci tu ești prostul care a furat potirul? Te voi aresta, hoț rebel... Prin urmare avansând în rangurile Ordinului. Cum e să fii un pion neștiutor? Îți dau un indiciu, o șă doară.","Так это ты тот недоумок, что украл чашу? Я передам тебя Ордену, как вора повстанцев... Это укрепит мои отношения с ним. Каково чувствовать себя безмозглой пешкой? Дам тебе подсказку: очень больно! -", -It sucks!,TXT_RPLY0_SCRIPT02_D68220_ITSUC,,,,Je to na hovno!,Scheiße!,,,¡Apesta!,,,Quelle merde!,Szopás!,,クソが!,이거 정말 난감한데?,Het is klote!,Cholera!,Que merda!,,E nașpa!,Чтоб ты сдох!, -For you it does.,TXT_RYES0_SCRIPT02_D68220_FORYO,,,,Pro tebe určitě.,Du steckst ganz tief drin.,,,Para ti si.,,,"Pour vous, en effet.",,,私もそう思う。,너한테는 더욱 그럴걸.,Voor jou wel.,Dla ciebie tak.,"Pra você, sim.",,"Pentru tine, cu siguranță.",Скоро сдохнешь ты., -Harris promised me money!,TXT_RPLY1_SCRIPT02_D68220_HARRI,,,,Harris mi slíbil peníze!,Harris hat mir Geld versprochen!,,,¡Harris me prometió dinero!,,,Harris m'a promis de l'argent!,,,ハリスは俺に金を渡すと約束したのに!,해리스는 내게 돈을 약속했어!,Harris beloofde me geld!,Harris obiecał mi pieniądze!,O Harris prometeu me pagar!,,Harris mi-a promis bani!,Харрис обещал мне деньги!, -Too bad. The only thing you're getting is dead!,TXT_RYES1_SCRIPT02_D68220_TOOBA,,,,"Smůla. Jediné, co dostaneš, je smrt.",Jammerschade. Das Einzige was du bekommen wirst ist der Tod!,,,Que mal. ¡Lo único que vas a tener es la muerte!,Que mal. ¡Lo único que obtendrás es la muerte!,,"C'est dommage. Tout ce que vous gagnez, c'est une mort rapide!",,,残念だな、お前にやれるものは死のみだ!,그거 안됐네. 네가 얻는 거라곤 죽음뿐이니까!,Wat jammer. Het enige dat je zult krijgen is de dood!,Szkoda. Jedyne co dostaniesz to śmierć!,Que pena. A única coisa que você vai receber é a morte!,,Păcat. Tot ceea ce primești e moarte!,"Увы. Всё, что ты получишь, — это смерть!", -"In a small world, word travels fast. I hear you just removed some obstacles from your path. Nice work. Are you interested in some more lucrative projects?",TXT_DLG_SCRIPT02_D69736_INASM,,,,"V malém světě se zprávy šíří rychle. Slyšel jsem, že sis právě odstranil z cesty pár překážek. Pěkná práce. Měl bys zájem o nějaké lukrativnější zakázky?","Mir sind da Gerüchte zu Ohren gekommen, dass du gerade ein paar Hindernisse aus dem Weg geräumt hast. Gute Arbeit. Bist du an lukrativeren Angeboten interessiert?",,,"En un mundo pequeño, las palabras viajan rápido. Escuché que acabas de quitar algunos obstáculos de tu camino. Buen trabajo. ¿Estás interesado en proyectos más lucrativos?",,,"Dans un petit monde, les rumeurs courent vite. J'entends que vous avez.. enlevé certains obstacles de votre chemin. Bon travail. Vous seriez intéressé par des projets plus lucratifs?",,,"この小さな世界では噂が広まるのは早いもんだ。 +ヒントを教えよう、お前はもう助からない。","그래서 네가 그 성배를 훔친 바보로군? 반군 절도범으로 체포해주지... 오더에서의 내 위치도 올리는 겸. 모르는 사이에 장물아비가 된 기분이 어떤가? 힌트를 주지, 정말 아플 거야.","Dus jij bent de dwaas die de kelk heeft gestolen? Ik ga je laten arresteren als een rebellendief.... Daardoor verbeter ik mijn positie bij de Orde. Hoe voelt het om een onwetende pion te zijn? Ik zal je een hint geven, het gaat pijn doen.","Så du er idioten som stjal begeret? Jeg skal få deg arrestert som en opprørsk tyv... Og dermed styrke min posisjon i Ordenen. Hvordan føles det å være en uvitende brikke? Jeg skal gi deg et hint, det kommer til å gjøre vondt.","Więc... to ty jesteś tym głupcem, który ukradł kielich? Aresztuję cię jako złodzieja-buntownika... A tym samym zwiększając swe uznanie u Zakonu. Jakie to uczucie jak się jest nieświadomym pionkiem? Podpowiedź, będzie bolało.",Então você é o imbecil que roubou o cálice? Eu vou mandar prender você como um ladrão rebelde... E assim a minha posição na Ordem vai melhorar. Como se sente sendo um plebeu ignorante? Só pra te dar uma ideia: vai doer.,,"Deci tu ești prostul care a furat potirul? Te voi aresta, hoț rebel... Prin urmare avansând în rangurile Ordinului. Cum e să fii un pion neștiutor? Îți dau un indiciu, o șă doară.","Так это ты тот недоумок, что украл чашу? Я передам тебя Ордену, как вора повстанцев... Это укрепит мои отношения с ним. Каково чувствовать себя безмозглой пешкой? Дам тебе подсказку: очень больно! +",,"Så du är idioten som stal kalken? Jag ska låta arrestera dig som en upprorisk tjuv... och på så sätt förbättra min ställning i orden. Hur känns det att vara en ovetande bricka? Jag ska ge dig en ledtråd, det kommer att göra ont.","Demek kadehi çalan aptal sensin? Seni asi bir hırsız olarak tutuklatacağım. Böylece Tarikat'taki konumumu güçlendireceğim. Farkında olmadan bir piyon olmak nasıl bir duygu? Sana bir ipucu vereyim, acıtacak." +It sucks!,TXT_RPLY0_SCRIPT02_D68220_ITSUC,〃,,,Je to na hovno!,Det stinker!,Scheiße!,,Tio estas aĉa!,¡Apesta!,,Ihan syvältä!,Quelle merde!,Szopás!,È uno schifo!,クソが!,이거 정말 난감한데?,Het is klote!,Det suger!,Cholera!,Que merda!,,E nașpa!,Это отстой!,,Det suger!,Berbat bir şey! +For you it does.,TXT_RYES0_SCRIPT02_D68220_FORYO,〃,,,Pro tebe určitě.,For dig gør det.,Du steckst ganz tief drin.,,Por vi ja.,Para ti sí.,,"Kyllä, sinun tilanteesi.","Pour vous, en effet.","Igen, neked.",A te lo farà.,私もそう思う。,너한테는 더욱 그럴걸.,Voor jou wel.,For deg gjør det det.,Dla ciebie tak.,"Pra você, sim.",,"Pentru tine, cu siguranță.",Для тебя — да.,,För dig gör det det.,Senin için öyle. +Harris promised me money!,TXT_RPLY1_SCRIPT02_D68220_HARRI,〃,,,Harris mi slíbil peníze!,Harris lovede mig penge!,Harris hat mir Geld versprochen!,,Harris promesis monon al mi!,¡Harris me prometió dinero!,,Harris lupasi minulle rahaa!,Harris m'a promis de l'argent!,Harris pénzt igért!,Harris mi ha promesso dei soldi!,ハリスは俺に金を渡すと約束したのに!,해리스는 내게 돈을 약속했어!,Harris beloofde me geld!,Harris lovet meg penger!,Harris obiecał mi pieniądze!,O Harris prometeu me pagar!,,Harris mi-a promis bani!,Харрис обещал мне деньги!,,Harris lovade mig pengar!,Harris bana para sözü verdi! +Too bad. The only thing you're getting is dead!,TXT_RYES1_SCRIPT02_D68220_TOOBA,〃,,,"Smůla. Jediné, co dostaneš, je smrt.","Det var ærgerligt. Det eneste, du får, er død!",Jammerschade. Das Einzige was du bekommen wirst ist der Tod!,,"Kiel domaĝe. Ĉio, kion +vi havos estas morto!","Qué mal. ¡Lo único que +tendrás es la muerte!","Qué mal. ¡Lo único que +vas a tener es la muerte!","Voi voi. Sen kyllä voin sinulle luvata, että kuolet!","C'est dommage. Tout ce que vous gagnez, c'est une mort rapide!","Sajna, inkább ólmot kapsz helyette!",Peccato. L'unica cosa che otterrai è la morte!,残念だな、お前にやれるものは死のみだ!,그거 안됐네. 네가 얻는 거라곤 죽음뿐이니까!,Wat jammer. Het enige dat je zult krijgen is de dood!,"Synd for deg. Det eneste du får, er død!",Szkoda. Jedyne co dostaniesz to śmierć!,Que pena. A única coisa que você vai receber é a morte!,,Păcat. Tot ceea ce primești e moarte!,"Увы. Всё, что ты получишь — это смерть!",,Det var synd. Det enda du får är en död!,Çok yazık. Elde edeceğin tek şey ölüm! +"In a small world, word travels fast. I hear you just removed some obstacles from your path. Nice work. Are you interested in some more lucrative projects?",TXT_DLG_SCRIPT02_D69736_INASM,MAP02: Rowan.,,,"V malém světě se zprávy šíří rychle. Slyšel jsem, že sis právě odstranil z cesty pár překážek. Pěkná práce. Měl bys zájem o nějaké lukrativnější zakázky?","I en lille verden spreder ordet sig hurtigt. Jeg hører, at du lige har fjernet nogle forhindringer fra din vej. Godt arbejde. Er du interesseret i nogle mere lukrative projekter?","Mir sind da Gerüchte zu Ohren gekommen, dass du gerade ein paar Hindernisse aus dem Weg geräumt hast. Gute Arbeit. Bist du an lukrativeren Angeboten interessiert?",,"En malgranda mondo novaĵoj vojaĝas rapide. Mi aŭdis, ke vi ĵus forigis kelkajn obstaklojn de via vojo. Bone farite. Ĉu interesas vin partopreni pli lukrajn projektojn?",El mundo es un pañuelo y las noticias vuelan. He oido que acabas de quitarte un par de obstáculos de encima. Bien hecho. ¿Te interesaría participar en proyectos más lucrativos?,El mundo es un pañuelo y las noticias vuelan. Oí que acabas de quitarte un par de obstáculos de encima. Bien hecho. ¿Te interesaría participar en proyectos más lucrativos?,"Pienessä maailmassa sana kiirii nopeasti. Sana kuuluu, että olet juuri poistanut esteitä tieltäsi. Hyvin tehty. Olisitko kiinnostunut tuottoisammista projekteista?","Dans un petit monde, les rumeurs courent vite. J'entends que vous avez.. enlevé certains obstacles de votre chemin. Bon travail. Vous seriez intéressé par des projets plus lucratifs?",Ilyen kis helyen gyorsan terjednek a hírek. Úgy hírlik eltávolítottál pár akadályt az utadból. Szép munka. Nem érdekel valami jövedelmezőbb projekt?,"In un piccolo mondo, le voci si spargono in fretta... Ho sentito che hai appena rimosso alcuni ostacoli dal tuo percorso. Ottimo lavoro. Sei interessato a progetti un po' più lucrativi?","この小さな世界では噂が広まるのは早いもんだ。 あんたが素早く厄介事を片付けたと聞いたぞ。 もっと儲かる仕事をやってみる気はないかね?","이처럼 작은 세상엔, 소문이 빨리 전해지지. 방금 자네가 장애물들을 처리한 걸 들었다네. 수고했어. 수익이 아주 짭짤한 일자리에 관심이 있나? -",In een kleine wereld gaat het woord snel. Ik hoor dat je net wat obstakels van je pad hebt verwijderd. Goed werk. Ben je geïnteresseerd in wat lucratievere projecten?,"W małym świecie wieści szybko się rozchodzą. Usłyszałem, że właśnie usunąłeś parę rzeczy ze swojej drogi. Dobra robota. Jesteś zainteresowany jakimiś bardziej korzystnymi projektami?","Neste mundo pequeno, as notícias viajam rápido. Fiquei sabendo que você removeu alguns obstáculos de seu caminho. Bom trabalho. Está interessado em alguns projetos mais lucrativos?",,"Într-o lume mică, vorba circulă repede. Aud că tocmai ai înlăturat niște obstacole din drum. Bună treabă. Mai ești interesat de alte proiecte profitabile?","Мир тесен, и новости разлетаются быстро. Я слышал, как ты только что убрал пару препятствий со своего пути. Хорошая работа. Заинтересован в более прибыльных занятиях?", -"Sure, why not.",TXT_RPLY0_SCRIPT02_D69736_SUREW,,,,"Klidně, proč ne.","Sicher, warum nicht.",,,"Por supuesto, por que no.",,,"Ouais, pourquoi pas.",,,ああ、もちろんだ。,그거 좋군요.,"Tuurlijk, waarom niet.","Jasne, czemu nie.","Claro, por que não?",,"Da, de ce nu.","Конечно, почему бы и нет.", -No thanks.,TXT_RPLY1_SCRIPT02_D69736_NOTHA,,,,"Ne, díky.",Nein danke.,,,No gracias.,,,Non merci.,,,やめとくよ。,필요 없어요.,"Nee, dank je wel.","Nie, dziękuję.","Não, obrigado.",,Nu mulțumesc.,"Нет, спасибо.", -Then get lost!,TXT_RYES1_SCRIPT02_D69736_THENG,,,,Tak vypadni!,Dann verzieh dich!,,,¡Entonces piérdete!,,,Alors dégage!,,,じゃあ失せるんだな!,그럼 꺼져!,Dan verdwalen!,W takim razie spadaj!,Então suma daqui!,,Atunci valea!,Тогда проваливай!, -"Fool! Guards, rid me of this meddlesome peon.",TXT_DLG_SCRIPT02_D71252_FOOLG,,,,"Blázne! Stráže, zbavte se tohohle zbytečného nuzáka.","Du Narr! Wachen, entledigt mich dieses lästigen Tagelöhners.",,,"¡Insensato! Guardias, líbrenme de este entrometido peón.","¡Tonto! Guardias, líbrenme de este entrometido peón.",,"Idiot! Gardes, débarassez-moi de ce pion embêtant!",,,"なんと愚かな! -衛兵、この厄介な奴を始末してくれ。","멍청한 것! 경비병, 이 걸리적거리는 난동꾼을 치워라.","Dwaas! Bewakers, bevrijd me van deze bemoeizuchtige pioen.","Głupcze! Straż, uwolnijcie mnie od tego wścibskiego robola.","Idiota! Guardas, tirem esse peão intrometido daqui.",,"Prostule! Gardieni, scăpați-mă de acest pion băgăreț.","Глупец! Стража, избавьте меня от этого недоумка.", -"Good. Some uh, friends of mine need someone silenced. Beldin is being held by the Order in their sanctuary. There's a rarely used entrance by a small pier off the river which is unguarded. Get in, shut him up, and bring his ring back to me as proof.",TXT_DLG_SCRIPT02_D72768_GOODS,,,,"Dobře. Někteří mí... přátelé potřebují někoho umlčet. Beldin je držen Řádem v jejich svatyni. Na malém molu u řeky je málo používaný vchod, který nikdo nehlídá. Dostaň se dovnitř, umlč ho a přines mi jeho prsten jako důkaz.","Gut. Einige, äh, Freunde von mir müssen zum Schweigen gebracht werden. Beldin wird vom Orden im Heiligtum gefangen gehalten. Es gibt dort einen selten benutzen Eingang bei einem kleinen Pier am Fluss, welcher unbewacht ist. Geh rein, mach ihn kalt und bringe mir seinen Ring als Beweis zurück.",,,"Bien. Algunos uh, amigos míos necesitan a alguien silenciado. Beldin es retenido por La Orden en su santuario. Hay una entrada rara vez utilizada por un pequeño muelle frente al río que está sin vigilancia. Entra, cállalo y tráeme su anillo como prueba.",,,"Bien. Certains... amis à moi demandent à ce que quelqu'un arrète de parler. Beldin est retenu par l'Ordre dans leur sanctuaire. Il y a une entrée rarement utilisée près d'un ponton près de la rivière qui n'est pas gardée. Entrez, coupez-lui le sifflet et ramenez moi son anneau comme preuve.",,,"それでいい。ええと、私の友人がある人物を +",In een kleine wereld gaat het woord snel. Ik hoor dat je net wat obstakels van je pad hebt verwijderd. Goed werk. Ben je geïnteresseerd in wat lucratievere projecten?,I en liten verden sprer rykter seg fort. Jeg hører du har fjernet noen hindringer fra veien din. Bra jobbet. Er du interessert i flere lukrative prosjekter?,"W małym świecie wieści szybko się rozchodzą. Usłyszałem, że właśnie usunąłeś parę rzeczy ze swojej drogi. Dobra robota. Jesteś zainteresowany jakimiś bardziej korzystnymi projektami?","Neste mundo pequeno, as notícias viajam rápido. Fiquei sabendo que você tirou alguns obstáculos de seu caminho. Bom trabalho. Está interessado em alguns projetos mais lucrativos?",,"Într-o lume mică, vorba circulă repede. Aud că tocmai ai înlăturat niște obstacole din drum. Bună treabă. Mai ești interesat de alte proiecte profitabile?","Мир тесен, и новости разлетаются быстро. Я слышал, как ты только что убрал пару препятствий со своего пути. Хорошая работа. Заинтересован в более прибыльных занятиях?",,I en liten värld går ryktet fort. Jag hörde att du just avlägsnade några hinder från din väg. Bra jobbat. Är du intresserad av några mer lukrativa projekt?,"Küçük bir dünyada, laf çabuk yayılır. Yolundaki bazı engelleri kaldırdığını duydum. İyi iş çıkardın. Daha kazançlı projelerle ilgileniyor musun?" +"Sure, why not.",TXT_RPLY0_SCRIPT02_D69736_SUREW,〃,,,"Klidně, proč ne.","Selvfølgelig, hvorfor ikke.","Sicher, warum nicht.",,"Jes, kial ne?","Por supuesto, ¿por qué no?","Claro, ¿por qué no?",Miksipä ei.,"Ouais, pourquoi pas.","Persze, miért is ne.","Certo, perché no.",ああ、もちろんだ。,그거 좋군요.,"Tuurlijk, waarom niet.","Ja, hvorfor ikke.","Jasne, czemu nie.","Claro, por que não?",,"Da, de ce nu.","Конечно, почему бы и нет.",,"Visst, varför inte.","Elbette, neden olmasın." +No thanks.,TXT_RPLY1_SCRIPT02_D69736_NOTHA,〃,,,"Ne, díky.",Nej tak.,Nein danke.,,"Ne, dankon.","No, gracias.",,Ei kiitos.,Non merci.,Nem kösz.,"No, grazie.",やめとくよ。,필요 없어요.,"Nee, dank je wel.",Nei takk.,"Nie, dziękuję.","Não, obrigado.",,Nu mulțumesc.,"Нет, спасибо.",,Nej tack.,"Hayır, teşekkürler." +Then get lost!,TXT_RYES1_SCRIPT02_D69736_THENG,,,,Tak vypadni!,Så forsvind!,Dann verzieh dich!,,Tiuokaze malaperu!,¡Entonces piérdete!,,Sitten häivy!,Alors dégage!,Akkor húzz el innen!,E allora sparisci!,じゃあ失せるんだな!,그럼 꺼져!,Dan verdwalen!,Så stikk!,W takim razie spadaj!,Então suma daqui!,,Atunci valea!,Тогда проваливай!,,Försvinn då!,O zaman kaybol! +"Fool! Guards, rid me of this meddlesome peon.",TXT_DLG_SCRIPT02_D71252_FOOLG,Rowan.,,,"Blázne! Stráže, zbavte se tohohle zbytečného nuzáka.","Fjols! Vagter, befri mig for denne uopmærksomme bondeknold.","Du Narr! Wachen, entledigt mich dieses lästigen Tagelöhners.",,"Stultulo! Gardistoj, liberigu min de ĉi tiu entrudiĝema peono.","¡Insensato! Guardias, libérenme de este entrometido peón.","¡Tonto! Guardias, libérenme de este entrometido peón.","Sinä mieletön! Vartijat, hankkiutukaa eroon tästä tungettelevasta moukasta.","Idiot! Gardes, débarassez-moi de ce pion embêtant!","Barom! Őrök, takarítsátok el a színem elől ezt a kotnyeleskedő pondrót!","Sciocco! Guardie, liberatemi da questo ficcanaso.","なんと愚かな! +衛兵、この厄介な奴を始末してくれ。","멍청한 것! 경비병, 이 걸리적거리는 난동꾼을 치워라.","Dwaas! Bewakers, bevrijd me van deze bemoeizuchtige pioen.","Idiot! Vakter, kvitt meg med denne innpåslitne trellen.","Głupcze! Straż, uwolnijcie mnie od tego wścibskiego robola.","Idiota! Guardas, tirem esse peão intrometido daqui.",,"Prostule! Gardieni, scăpați-mă de acest pion băgăreț.","Глупец! Стража, избавьте меня от этого недоумка.",,"Dumbom! Vakter, gör mig av med den här besvärliga pingsten.","Aptal! Muhafızlar, beni bu işgüzar piyondan kurtarın." +"Good. Some uh, friends of mine need someone silenced. Beldin is being held by the Order in their sanctuary. There's a rarely used entrance by a small pier off the river which is unguarded. Get in, shut him up, and bring his ring back to me as proof.",TXT_DLG_SCRIPT02_D72768_GOODS,〃,,,"Dobře. Někteří mí... přátelé potřebují někoho umlčet. Beldin je držen Řádem v jejich svatyni. Na malém molu u řeky je málo používaný vchod, který nikdo nehlídá. Dostaň se dovnitř, umlč ho a přines mi jeho prsten jako důkaz.","Godt. Nogle af mine venner har brug for at få nogen til at tie stille. Beldin bliver tilbageholdt af Ordenen i deres fristed. Der er en sjældent brugt indgang ved en lille mole ud for floden, som er ubevogtet. Gå ind, luk munden på ham, og giv mig hans ring som bevis.","Gut. Einige, äh, Freunde von mir müssen zum Schweigen gebracht werden. Beldin wird vom Orden im Heiligtum gefangen gehalten. Es gibt dort einen selten benutzen Eingang bei einem kleinen Pier am Fluss, welcher unbewacht ist. Geh rein, mach ihn kalt und bringe mir seinen Ring als Beweis zurück.",,"Bone. Kelkaj... hm, amikoj bezonas «silentigi» iun. Beldin estas retenita en la sanktejo de La Ordeno. Estas malofte uzata enirejo ĉe malgranda kajo sen viglado apud la rojo. Eniru tien, silentigu lin kaj alportu lian ringon kiel pruvon.","Bien. Algunos... este, amigos míos necesitan «silenciar» a alguien. Beldin es retenido por La Orden en su santuario. Hay una entrada rara vez utilizada por un pequeño muelle junto al arroyo que está sin vigilancia. Entra, cállalo y tráeme su anillo como prueba.",,"Hyvä. Eräät, öh, ystäväni kaipaavat erään henkilön hiljentämistä. Veljeskunta pitää Beldiniä vankinaan pyhäkössään. Jokea vierustavalta vartioimattomalta pikkulaiturilta on harvoin käytetty sisäänkäynti. Mene sisään, vaienna hänet ja tuo hänen sormuksensa takaisin todisteena.","Bien. Certains... amis à moi demandent à ce que quelqu'un arrète de parler. Beldin est retenu par l'Ordre dans leur sanctuaire. Il y a une entrée rarement utilisée près d'un ponton près de la rivière qui n'est pas gardée. Entrez, coupez-lui le sifflet et ramenez moi son anneau comme preuve.","Kiváló. Néhány barátom el akar valakit némítani. Beldint a Rend szentélyében tartják fogva. Van egy ritkán használt bejárat egy kis mólónál, amit nem védenek katonák. Hatolj be, csitícsd el örökre, és hozdd el a gyűrűjét bizonyítékként.","Ottimo. Alcuni uh, amici miei hanno bisogno che qualcuno venga messo a tacere. Beldin è sotto custodia dell'Ordine nel loro santuario. C'è un ingresso poco utilizzato e non sorvegliato tramite un piccolo molo accanto al fiume. Entra, fallo tacere, e portami il suo anello come prova.","それでいい。ええと、私の友人がある人物を 黙らせて欲しいと望んでいるんだ。 ベルディンはオーダーの連中の聖域に 囚われている。建物への入り口は川に掛かった 桟橋の先にあり、そこは誰も警備してないし ほぼ使われていない。潜入してヤツを黙らせて、 -仕事をした証拠としてヤツの指輪を見せてくれ。","좋구만... 그래서, 내 지인이 말하기를 벨딘이라는 사람의 입을 다물게 만들라는군. 그는 지금 오더에 의해 성소에 감금됐네. 그 근처 강가에 있는 작은 부두 옆에 자주 쓰이지 않는 입구가 있다네. 거기로 향해서, 그의 입을 막게. 그리고 그의 반지를 증거로 가져오게.","Goed. Sommige uh, vrienden van mij hebben iemand nodig die het zwijgen oplegt. Beldin wordt vastgehouden door de Orde in hun heiligdom. Er is een zelden gebruikte ingang bij een kleine pier van de rivier die onbewaakt is. Stap in, sluit hem op en breng zijn ring terug als bewijs.","Dobrze. Paru moich... ehmm... przyjaciół potrzebuje kogoś uciszyć. Beldin jest trzymany przez Zakon w ich sanktuarium. Jest tu gdzieś rzadko używane wejście przy małej przystani przy rzece, które jest niestrzeżone. Wejdź tam, ucisz go i przynieś mi jego pierścień jako dowód.","Ótimo. Alguns hã, amigos meus precisam silenciar alguém. Beldin foi detido pela Ordem no santuário deles. Há uma entrada pouco usada perto de um pequeno pier pelo rio que está sem guardas. Entre lá, cale a boca dele e traga o seu anel de volta pra mim como prova.",,"Bun. Niște um... prieteni de-ai mei au nevoie de cineva redus la tăcere. Beldin e ținut de Ordin în sanctuarul lor. E o intrare rar folosită pe niște chei lângă râu care e nepăzită. Intră, fă-l să tacă pe veci, și adu-mi inelul lui ca dovadă.","Хорошо. Некоторые мои, э-э-э, приятели, хотят, чтобы кое-кто замолчал. Орден держит предателя по имени Белдин в своём святилище. На берегу реки есть вход, который редко используется, а потому не охраняется. Проберись внутрь, заставь предателя замолчать навсегда и принеси мне его кольцо в качестве доказательства.", -Will it be worth the effort?,TXT_RPLY0_SCRIPT02_D72768_WILLI,,,,Bude mi to stát za to?,Wird es die Mühe denn wert sein?,,,¿Valdrá la pena el esfuerzo?,,,Est-ce que ça en vaudra l'effort?,Megéri az erőfeszítést?,,苦労に見合った報酬だろうな?,노력할만한 가치가 있나요?,Zal het de moeite waard zijn?,Czy będzie to warte moich starań?,Será que vale a pena o esforço?,,O să merite efortul?,Оно того стоит?, -"I'll guarantee 50 gold and if you return without setting off every alarm in town, there's the chance to earn much, much more, and here's a little helper that should give you an edge.",TXT_DLG_SCRIPT02_D74284_ILLGU,,,,"Garantuji ti padesát zlatých a jestliže se vrátíš bez toho, abys spustil každý poplach ve městě, je tu šance vydělat si mnohem, mnohem víc. Tady je malý pomocník, který by ti měl pomoci.","Ich garantiere dir 50 Gold und wenn du zurückkehrst ohne den Alarm in der Stadt ausgelöst zu haben, dann hast du noch die Chance, viel, viel mehr zu verdienen und hier ist noch ein kleiner Helfer der dir einen Vorteil verschaffen wird.",,,"Te garantizo 50 de oro y si vuelves sin activar todas las alarmas del pueblo, existe la posibilidad de ganar mucho, mucho más, y aquí hay un pequeño ayudante que debería darte una ventaja.",,,"Je vous garantis 50 pièces et si vous revenez sans déclencher toutes les alarmes de la ville, vous avez la possibilité de gagner bien plus. Voilà une petite avance qui pourra vous aider.",,,"50ゴールドは保証するし街の警報を鳴らさず +仕事をした証拠としてヤツの指輪を見せてくれ。","좋구만... 그래서, 내 지인이 말하기를 벨딘이라는 사람의 입을 다물게 만들라는군. 그는 지금 오더에 의해 성소에 감금됐네. 그 근처 강가에 있는 작은 부두 옆에 자주 쓰이지 않는 입구가 있다네. 거기로 향해서, 그의 입을 막게. 그리고 그의 반지를 증거로 가져오게.","Goed. Sommige uh, vrienden van mij hebben iemand nodig die het zwijgen oplegt. Beldin wordt vastgehouden door de Orde in hun heiligdom. Er is een zelden gebruikte ingang bij een kleine pier van de rivier die onbewaakt is. Stap in, sluit hem op en breng zijn ring terug als bewijs.","Fint. Noen venner av meg trenger å få noen til å tie. Beldin holdes av Ordenen i deres helligdom. Det er en sjelden brukt inngang ved en liten brygge ved elven som er ubevoktet. Gå inn, få ham til å holde kjeft, og gi meg ringen hans som bevis.","Dobrze. Paru moich... ehmm... przyjaciół potrzebuje kogoś uciszyć. Beldin jest trzymany przez Zakon w ich sanktuarium. Jest tu gdzieś rzadko używane wejście przy małej przystani przy rzece, które jest niestrzeżone. Wejdź tam, ucisz go i przynieś mi jego pierścień jako dowód.","Ótimo. Alguns hã... amigos meus precisam silenciar alguém. Beldin foi detido pela Ordem no santuário deles. Há uma entrada pouco usada perto de um pequeno pier pelo rio que está sem guardas. Entre lá, cale a boca dele e traga o seu anel de volta pra mim como prova.",,"Bun. Niște um... prieteni de-ai mei au nevoie de cineva redus la tăcere. Beldin e ținut de Ordin în sanctuarul lor. E o intrare rar folosită pe niște chei lângă râu care e nepăzită. Intră, fă-l să tacă pe veci, și adu-mi inelul lui ca dovadă.","Хорошо. Некоторые мои, э-э-э, приятели, хотят, чтобы кое-кто замолчал. Орден держит Белдина в своём святилище. У небольшого пира рядом с рекой есть редко используемый вход, что не охраняется. Проберись внутрь, заставь его замолчать навсегда и принеси мне его кольцо в качестве доказательства.",,"Jag är glad att du är här. Några av mina vänner behöver få någon tystad. Beldin hålls av orden i deras helgedom. Det finns en sällan använd ingång vid en liten brygga vid floden som är obevakad. Gå in, få tyst på honom och ge mig hans ring som bevis.","Güzel. Bazı arkadaşlarımın birinin susturulmasına ihtiyacı var. Beldin, Tarikat tarafından sığınaklarında tutuluyor. Nehir kıyısındaki küçük iskelede korumasız, nadiren kullanılan bir giriş var. İçeri gir, onu sustur ve yüzüğünü kanıt olarak bana geri getir." +Will it be worth the effort?,TXT_RPLY0_SCRIPT02_D72768_WILLI,〃,,,Bude mi to stát za to?,Vil det være indsatsen værd?,Wird es die Mühe denn wert sein?,,Ĉu la strebo estos valora?,¿Valdrá la pena el esfuerzo?,¿Va a valer la pena el esfuerzo?,Onko väärti vaivannäköni?,Est-ce que ça en vaudra l'effort?,Megéri az erőfeszítést?,Ne varrà la pena?,苦労に見合った報酬だろうな?,노력할만한 가치가 있나요?,Zal het de moeite waard zijn?,Er det verdt innsatsen?,Czy będzie to warte moich starań?,Será que vale a pena o esforço?,,O să merite efortul?,Оно того стоит?,,Kommer det att vara värt besväret?,Bu çabaya değecek mi? +"I'll guarantee 50 gold and if you return without setting off every alarm in town, there's the chance to earn much, much more, and here's a little helper that should give you an edge.",TXT_DLG_SCRIPT02_D74284_ILLGU,〃,,,"Garantuji ti padesát zlatých a jestliže se vrátíš bez toho, abys spustil každý poplach ve městě, je tu šance vydělat si mnohem, mnohem víc. Tady je malý pomocník, který by ti měl pomoci.","Jeg garanterer dig 50 guld, og hvis du vender tilbage uden at udløse alle alarmer i byen, er der mulighed for at tjene meget, meget mere, og her er en lille hjælper, der burde give dig en fordel.","Ich garantiere dir 50 Gold und wenn du zurückkehrst ohne den Alarm in der Stadt ausgelöst zu haben, dann hast du noch die Chance, viel, viel mehr zu verdienen und hier ist noch ein kleiner Helfer der dir einen Vorteil verschaffen wird.",,"Mi garantias al vi 50 monerojn da oro, kaj se vi revenos ne ekagiginte ĉiun alarmon en la urbo, estas eblo gajni multe, multe pliajn. Kaj jen malgranda helpilo por faciligi vian takson.","Te garantizo 50 de oro, y si vuelves sin activar todas las alarmas del pueblo, existe la posibilidad de ganar mucho, mucho más. Y aquí hay un pequeño ayudante que debería darte una ventaja.",,"Takaan sinulle 50 kultakolikkoa, ja jos palaat ilman, että soitatat jokaista kaupungin hälytyskelloa, voit mahdollisesti tienata paljon paljon enemmän. Tässä vielä pikkuapuri, jonka pitäisi antaa sinulle pienen kilpailuedun.","Je vous garantis 50 pièces et si vous revenez sans déclencher toutes les alarmes de la ville, vous avez la possibilité de gagner bien plus. Voilà une petite avance qui pourra vous aider.","50 arany garantáltan a markodat üti, és ha nem indítod be a riasztót a városban, akkor esélyed van többet is kapni, sokkal többet. Itt van egy kis segítség, hogy előnyhöz juss.","Ti garantisco 50 pezzi d'oro e se ritorni qua senza far scattare ogni allarme in città, ci sarà l'opportunità di guadagnare molto, molto di più, ed ecco qua anche un piccolo aggeggio che ti aiuterà.","50ゴールドは保証するし街の警報を鳴らさず 戻ってこれたら、もっと金を得られる機会が -あるぞ。それと、お前の力となる物も渡そう。","만약 이 마을의 경보를 울리지 않고 조용히 완수하면 50 골드를 보상으로 주지. 이 외에도 더 많은 보상을 받을 수 있는 일들이 아주 많이 있다네. 그리고 여기, 모험에 도움이 될 만한 무기를 가져가게.","Ik garandeer 50 goud en als je terugkeert zonder elke alarmbel in de stad af te laten gaan, is er de kans om veel, veel meer te verdienen, en hier is een kleine helper die je een voordeel zou moeten geven.","Gwarantuję 50 monet, a jeśli wrócisz bez włączania wszystkich alarmów w mieście, jest szansa, że mógłbyś dostać więcej. Znacznie więcej. Oto mały pomocnik, który da ci przewagę.","Garanto que você será pago 50 de ouro e se você retornar sem ativar todos os alarmes na cidade haverá uma chance de ganhar muito, muito mais. E aqui tem algo que pode te ajudar um pouco.",,"Garantez 50 de monezi de aur, și dacă nu declanșezi vreo alarmă în oraș, e o șansă de câștig mult, mult mai mare, iar aici e un mic ajutător care să-ți facă treaba mai ușoară.","Я обещаю тебе 50 золотых. И ты сможешь заработать куда больше, если выполнишь задание, не переполошив всю стражу в городе. А чтобы у тебя было некоторое преимущество, вот тебе небольшой помощник. -", -"Thanks, I'll need it.",TXT_RPLY0_SCRIPT02_D74284_THANK,,,,"Díky, budu ho potřebovat.","Danke, das werde ich brauchen.",,,"Gracias, lo necesitaré.",,,"Merci, j'en aurais besoin.",,,ありがとよ、これは後々必要になるな。,고마워요. 도움이 될 것 같습니다.,"Bedankt, ik zal het nodig hebben.",Dzięki. Będę go potrzebował.,"Obrigado, vou precisar.",,"Merci, voi avea nevoie de el.",Спасибо. Он мне пригодится., -"Good. Remember, his silence is golden.",TXT_DLG_SCRIPT02_D75800_GOODR,,,,"Dobře. Pamatuj, že jeho mlčení je zlaté.",Gut. Denke dran. Sein Schweigen ist Gold wert.,,,"Bien. Recuerda, su silencio es oro.",,,Bien. Souvenez-vous. Le silence est d'or.,,,いいぞ。覚えておけ、彼が沈黙したら金だ。,천만에. 그리고 기억하게. 그를 입막음하는 게 유일한 희망일세.,"Goed. Vergeet niet, zijn stilte is goud waard.","Dobrze. Pamiętaj, jego cisza jest cenna.","Ótimo. Lembre-se, o silêncio dele vale ouro.",,"Bun. Reține, tăcerea e de aur.","Превосходно. Запомни, его молчание — золото.", -I'll get him.,TXT_RPLY0_SCRIPT02_D75800_ILLGE,,,,Dostanu ho.,Ich krieg ihn.,,,Lo encontraré.,,,Je m'occupe de lui.,,,始末してみせる。,그를 잡겠어요.,Ik krijg hem wel.,Dorwę go.,Vou pegá-lo.,,O să-l aduc.,Я прикончу его., -Mission accomplished? You have the ring of the traitor?,TXT_DLG_SCRIPT02_D77316_MISSI,,,,Mise splněna? Máš zrádcův prsten?,Mission ausgeführt? Hast du den Ring des Verräters?,,,¿Misión cumplida? ¿Tienes el anillo del traidor?,,,Mission accomplie? Vous avez l'anneau du traître?,Küldetés sikeres? Nálad van az áruló gyűrűje?,,"任務完了か? -あの裏切り者の指輪は持っているんだろうな?",임무를 완수 한 건가? 배신자의 반지를 가지고 있어?,Missie volbracht? Heb je de ring van de verrader?,Misja ukończona? Masz pierścień zdrajcy?,Missão cumprida? Está com o anel do traidor?,,Misiune îndeplinită? Ai inelul trădătorului?,Задание выполнено? Ты принёс кольцо предателя?, -"He's dead, where's my money?",TXT_RPLY0_SCRIPT02_D77316_HESDE,,,,"Je mrtvý, kde jsou moje peníze?","Er ist tot, wo ist mein Geld?",,,"Está muerto, ¿dónde está mi dinero?",,,"Il est mort, où est mon argent?",,,奴は死んだ、報酬はあるんだろうな?,"그는 죽었습니다, 제 보상은요?","Hij is dood, waar is mijn geld?",Jest martwy. Gdzie moje pieniądze?,"Ele está morto, cadê o meu dinheiro?",,"E mort, unde sunt banii?",Он мёртв. Где мои деньги?, -Liar! Go get the ring!,TXT_RNO0_SCRIPT02_D77316_LIARG,,,,Lháři! Jdi pro jeho prsten!,Lügner! Hol' den Ring!,,,¡Mentiroso! ¡Ve por el anillo!,,,Mensonges! Ramenez-moi l'anneau!,,,嘘をつくな、指輪を取ってこい!,거짓말쟁이! 가서 반지를 가져오게!,Leugenaar! Ga de ring halen!,Kłamca! Idź po pierścień!,Mentiroso! Vá pegar o anel!,,Mincinos! Adu inelul!,Лжец! Принеси мне кольцо!, -"Here, you earned it. The traitor you killed was about to reveal the location of the Front. You saved lives. How would you like to earn more gold, and a future free from tyranny?",TXT_DLG_SCRIPT02_D78832_HEREY,,,,"Tady máš, zasloužil sis je. Zrádce, kterého jsi zabil, by vyzradil lokaci Fronty. Zachránil jsi životy. Jak by se ti líbilo vydělat si víc zlata spolu s budoucností bez tyranie?","Hier, das hast du dir verdient. Der Verräter den du getötet hast war dabei über die Position der Front auszupacken. Du hast Leben gerettet. Wie würde es dir gefallen noch mehr Gold zu verdienen und eine tyrannenfreie Zukunft zu haben?",,,"Toma, te lo ganaste. El traidor que mataste estaba a punto de revelar la ubicación del frente. Salvaste vidas. ¿Te gustaría ganar más oro y un futuro libre de tiranía?",,,"Voilà, vous l'avez bien mérité. Ce traître que vous avez tué allait révéler la base du Front. Vous avez sauvé de nombreuses vies. Est-ce que ça vous intéresserait de vous faire plus d'argent et garantir un futur libre de la tyrannie?",,,"よし、報酬はお前のものだ。お前が殺した +あるぞ。それと、お前の力となる物も渡そう。","만약 이 마을의 경보를 울리지 않고 조용히 완수하면 50 골드를 보상으로 주지. 이 외에도 더 많은 보상을 받을 수 있는 일들이 아주 많이 있다네. 그리고 여기, 모험에 도움이 될 만한 무기를 가져가게.","Ik garandeer 50 goud en als je terugkeert zonder elke alarmbel in de stad af te laten gaan, is er de kans om veel, veel meer te verdienen, en hier is een kleine helper die je een voordeel zou moeten geven.","Jeg garanterer 50 gull, og hvis du kommer tilbake uten å utløse alle alarmer i byen, kan du tjene mye, mye mer, og her er en liten hjelper som bør gi deg en fordel.","Gwarantuję 50 monet, a jeśli wrócisz bez włączania wszystkich alarmów w mieście, jest szansa, że mógłbyś dostać więcej. Znacznie więcej. Oto mały pomocnik, który da ci przewagę.","Garanto que você receberá 50 de ouro e se você retornar sem ativar todos os alarmes na cidade haverá uma chance de ganhar muito, muito mais. E aqui tem algo que pode te ajudar um pouco.",,"Garantez 50 de monezi de aur, și dacă nu declanșezi vreo alarmă în oraș, e o șansă de câștig mult, mult mai mare, iar aici e un mic ajutător care să-ți facă treaba mai ușoară.","Я обещаю тебе 50 золотых. И ты сможешь заработать куда больше, если выполнишь задание, не переполошив всю стражу в городе. А чтобы у тебя было некоторое преимущество, вот тебе небольшой помощник. +",,"Jag garanterar 50 guld och om du återvänder utan att utlösa alla larm i staden finns chansen att tjäna mycket, mycket mer, och här är en liten hjälpreda som borde ge dig en fördel.","50 altın garanti ediyorum ve eğer kasabadaki tüm alarmları çalıştırmadan geri dönerseniz, çok daha fazlasını kazanma şansınız var ve işte size avantaj sağlayacak küçük bir yardımcı." +"Thanks, I'll need it.",TXT_RPLY0_SCRIPT02_D74284_THANK,〃,,,"Díky, budu ho potřebovat.","Tak, jeg får brug for den.","Danke, das werde ich brauchen.",,Dankon. Mi bezonos ĝin.,Gracias. Lo necesitaré.,Gracias. Lo voy a necesitar.,"Kiitos, tarvitsen sitä.","Merci, j'en aurais besoin.","Köszönöm, kelleni is fog.","Grazie, ne avrò bisogno.",ありがとよ、これは後々必要になるな。,고마워요. 도움이 될 것 같습니다.,"Bedankt, ik zal het nodig hebben.","Takk, jeg trenger det.",Dzięki. Będę go potrzebował.,"Obrigado, vou precisar.",,"Merci, voi avea nevoie de el.",Спасибо. Он мне пригодится.,,"Tack, jag kommer att behöva den.","Teşekkürler, ihtiyacım olacak." +"Good. Remember, his silence is golden.",TXT_DLG_SCRIPT02_D75800_GOODR,〃,,,"Dobře. Pamatuj, že jeho mlčení má cenu zlata.","Godt. Husk, at hans tavshed er guld.",Gut. Denke dran. Sein Schweigen ist Gold wert.,,Bone. Memoru: lia silento estas el oro.,Bien. Recuerda: su silencio es de oro.,,"Hyvä. Muista, että hänen vaikenemisensa on kultaa.",Bien. Souvenez-vous. Le silence est d'or.,"Remek, a hallgatása arany.","Bene. Ricorda, il suo silenzio è d'oro.",いいぞ。覚えておけ、彼が沈黙したら金だ。,천만에. 그리고 기억하게. 그를 입막음하는 게 유일한 희망일세.,"Goed. Vergeet niet, zijn stilte is goud waard.",Bra. Husk at hans taushet er gull verdt.,"Dobrze. Pamiętaj, jego cisza jest cenna.","Ótimo. Lembre-se, o silêncio dele vale ouro.",,"Bun. Reține, tăcerea e de aur.","Превосходно. Запомни, его молчание — золото.",,Bra. Kom ihåg att hans tystnad är av guld.,"Güzel. Unutma, onun sessizliği altındır." +I'll get him.,TXT_RPLY0_SCRIPT02_D75800_ILLGE,〃,,,Dostanu ho.,Jeg henter ham.,Ich krieg ihn.,,Mi trovos lin.,Lo encontraré.,Lo voy a encontrar.,Saan hänet.,Je m'occupe de lui.,Elintézem.,Lo vado a prendere.,始末してみせる。,그를 잡겠어요.,Ik krijg hem wel.,Jeg skal ta ham.,Dorwę go.,Vou pegá-lo.,,O să-l aduc.,Я прикончу его.,,Jag hämtar honom.,Onu yakalayacağım. +Mission accomplished? You have the ring of the traitor?,TXT_DLG_SCRIPT02_D77316_MISSI,〃,,,Mise splněna? Máš zrádcův prsten?,Mission fuldført? Har du forræderens ring?,Mission ausgeführt? Hast du den Ring des Verräters?,,Ĉu vi finis? Ĉu vi havas la ringon de la perfidulo?,¿Misión cumplida? ¿Tienes el anillo del traidor?,,Tehtävä suoritettu? Sinulla on petturin sormus?,Mission accomplie? Vous avez l'anneau du traître?,Sikeres küldetés? Nálad van az áruló gyűrűje?,Missione compiuta? Hai l'anello del traditore?,"任務完了か? +あの裏切り者の指輪は持っているんだろうな?",임무를 완수 한 건가? 배신자의 반지를 가지고 있어?,Missie volbracht? Heb je de ring van de verrader?,Oppdrag utført? Har du forræderens ring?,Misja ukończona? Masz pierścień zdrajcy?,Missão cumprida? Está com o anel do traidor?,,Misiune îndeplinită? Ai inelul trădătorului?,Задание выполнено? Ты принёс кольцо предателя?,,Uppdraget slutfört? Har du förrädarens ring?,Görev tamamlandı mı? Hainin yüzüğü sende mi? +"He's dead, where's my money?",TXT_RPLY0_SCRIPT02_D77316_HESDE,〃,,,"Je mrtvý, kde jsou moje peníze?","Han er død, hvor er mine penge?","Er ist tot, wo ist mein Geld?",,Mi mortigis lin. Kie estas mia mono?,Ya está muerto. ¿Y mi dinero?,,"Hän on kuollut, missä on rahani?","Il est mort, où est mon argent?","Meghalt, hol a pénzem?","Lui è morto, dove sono i miei soldi?",奴は死んだ、報酬はあるんだろうな?,"그는 죽었습니다, 제 보상은요?","Hij is dood, waar is mijn geld?","Han er død, hvor er pengene mine?",Jest martwy. Gdzie moje pieniądze?,"Ele está morto, cadê o meu dinheiro?",,"E mort, unde sunt banii?",Он мёртв. Где мои деньги?,,"Han är död, var är mina pengar?","O öldü, param nerede?" +Liar! Go get the ring!,TXT_RNO0_SCRIPT02_D77316_LIARG,〃,,,Lháři! Jdi pro jeho prsten!,Løgner! Hent ringen!,Lügner! Hol' den Ring!,,"Ne mensongu! +Forprenu lian ringon!","¡Mentiroso! +¡Ve a por el anillo!","¡Mentiroso! +¡Ve por el anillo!",Valehtelija! Mene hakemaan sormus!,Mensonges! Ramenez-moi l'anneau!,Hazug! Menj és szerezd meg a gyűrűt!,Bugiardo! Vai a prendere l'anello!,嘘をつくな、指輪を取ってこい!,거짓말쟁이! 가서 반지를 가져오게!,Leugenaar! Ga de ring halen!,Løgner! Hent ringen!,Kłamca! Idź po pierścień!,Mentiroso! Vá pegar o anel!,,Mincinos! Adu inelul!,Лжец! Принеси мне кольцо!,,Lögnare! Hämta ringen!,Yalancı! Git yüzüğü al! +"Here, you earned it. The traitor you killed was about to reveal the location of the Front. You saved lives. How would you like to earn more gold, and a future free from tyranny?",TXT_DLG_SCRIPT02_D78832_HEREY,〃,,,"Tady máš, zasloužil sis je. Zrádce, kterého jsi zabil, by vyzradil lokaci Fronty. Zachránil jsi životy. Jak by se ti líbilo vydělat si víc zlata spolu s budoucností bez tyranie?","Her, du har fortjent det. Den forræder, du dræbte, var ved at afsløre frontens placering. Du reddede liv. Hvad ville du sige til at tjene mere guld og en fremtid uden tyranni?","Hier, das hast du dir verdient. Der Verräter den du getötet hast war dabei über die Position der Front auszupacken. Du hast Leben gerettet. Wie würde es dir gefallen noch mehr Gold zu verdienen und eine tyrannenfreie Zukunft zu haben?",,"Jen ĝi, vi gajnis ĝin. La perfidulo, kiun vi mortigis, estis malkaŝonta la pozicion de la Fronto. Vi savis vivojn. Ĉu vi ŝatus gajni plian oron kaj estontecon liberan de tiranio?","Toma, te lo ganaste. El traidor que has matado estaba a punto de revelar la ubicación del Frente. Has salvado vidas. ¿Te gustaría ganar más oro y un futuro libre de tiranía?","Toma, te lo ganaste. El traidor que mataste estaba a punto de revelar la ubicación del Frente. Salvaste vidas. ¿Te gustaría ganar más oro y un futuro libre de tiranía?","Tässä, olet sen ansainnut. Tappamasi petturi oli lähellä paljastaa Rintaman sijainnin. Pelastit henkiä. Haluaisitko tienata lisää kultaa, ja tyranniasta vapaan tulevaisuuden?","Voilà, vous l'avez bien mérité. Ce traître que vous avez tué allait révéler la base du Front. Vous avez sauvé de nombreuses vies. Est-ce que ça vous intéresserait de vous faire plus d'argent et garantir un futur libre de la tyrannie?","Tessék, megérdemelted. Az áruló akit eltettél láb alól közel járt ahhoz, hogy felfedje a Front bázisát. Életeket mentettél. Mit szólnál ahhoz, ha még több arany is ütné a mancsod, és még egy zsarnok mentes jövőd is lenne?","Ecco qua, te li sei guadagnati. Il traditore che hai ucciso stava per rivelare il nascondiglio del Fronte. Hai salvato molte vite. Che ne diresti di guadagnare altro oro, e un futuro libero dalla tirannia?","よし、報酬はお前のものだ。お前が殺した あの裏切り者は、フロントの隠れ家をバラそうと していたんだ。おかげで大勢の命が救われた。 もっと多くの金と、奴等の支配から解放された -未来を得たいとは思わないか?",여기 보상일세. 그는 프론트의 비밀장소를 알리려던 참이었네. 자네가 우리들의 목숨을 구했어. 폭정을 타도해서 이처럼 더 많은 보상을 얻을 준비가 되어있나?,"Hier heb je het verdiend. De verrader die je vermoordde stond op het punt om de locatie van het Front te onthullen. Je hebt levens gered. Hoe zou je het vinden om meer goud te verdienen, en een toekomst vrij van tirannie?","Masz, zasłużyłeś sobie. Zdrajca, którego zabiłeś zamierzał ujawnić gdzie znajduje się baza Frontu. Uratowałeś wiele żyć. Chcesz zarobić więcej pieniędzy i mieć przyszłość wolną od tyranii?","Tome, você merece. O traidor que você matou estava prestes a revelar a localização da Frente. Você salvou vidas. Que tal ganhar mais ouro e um futuro livre de tirania?",,"Aici, o meriți. Trădătorul pe care l-ai omorât urma să dezvăluie locația Frontului. Ai salvat vieți. Cum ai vrea să câștigi mai mult aur, și un viitor fără tiranie?","Вот, ты их заслужил. Убитый тобой предатель мог выдать Ордену местоположение базы Сопротивления. Ты спас много жизней. Тебе бы не хотелось ещё золота и будущего, свободного от тирании?", -Tell me more.,TXT_RPLY0_SCRIPT02_D78832_TELLM,,,,Řekni mi víc.,Erzähl mir mehr.,,,Dime más.,,,Dites-moi en plus.,,,もっと教えてくれ。,더 말해주시오.,Vertel me meer.,Mów dalej.,Me conte mais.,,Spune-mi mai multe.,Расскажи мне больше., -Not my style.,TXT_RPLY1_SCRIPT02_D78832_NOTMY,,,,To není můj styl.,Nicht mein Stil.,,,No es mi estilo.,,,Pas mon genre.,,,俺の趣味じゃないな。,내 취향은 아닌데.,Niet mijn stijl.,To nie w moim stylu.,Não faz o meu estilo.,,Nu-i genul meu.,Не в моём вкусе., -"I have a business relationship with the Front's leader, Macil. I know he needs an incisive fellow like yourself, and he pays well. Take this recovered com unit and you'll be led to, shall we say, opportunities.",TXT_DLG_SCRIPT02_D80348_IHAVE,,,,"Mám obchodní vztah s vůdcem Fronty, Macilem. Vím, že potřebuje schopného člověka jako ty a platí dobře. Vem si tenhle spravený komunikátor, zavede tě k, řekněme, příležitostem.","Ich habe Geschäftsbeziehungen mit dem Anführer der Front, Macil. Er braucht einen pfiffigen Typen wie dich und er bezahlt gut. Nimm dieses erbeutete Kommunikationsgerät und es wird dich zu, sagen wir mal, Möglichkeiten führen.",,,"Tengo una relación de negocios con el líder del frente, Macil. Sé que necesita un compañero incisivo como tú, y paga bien. Toma esta unidad de comunicaciones recuperada y serás conducido a, digamos, oportunidades.",,,"J'ai une relation d'affaires avec le leader du Front, Macil. Je sais qu'il a besoin de quelqu'un d'incisif comme vous, et il paye bien. Prenez ce communicateur avec vous, et vous serez mené à des.. on va dire des opportunités.",,,"私はフロントのリーダー、マシルと取引を +未来を得たいとは思わないか?",여기 보상일세. 그는 프론트의 비밀장소를 알리려던 참이었네. 자네가 우리들의 목숨을 구했어. 폭정을 타도해서 이처럼 더 많은 보상을 얻을 준비가 되어있나?,"Hier heb je het verdiend. De verrader die je vermoordde stond op het punt om de locatie van het Front te onthullen. Je hebt levens gered. Hoe zou je het vinden om meer goud te verdienen, en een toekomst vrij van tirannie?","Her, du har fortjent den. Forræderen du drepte var i ferd med å avsløre hvor Fronten er. Du reddet liv. Hva sier du til å tjene mer gull og en fremtid uten tyranni?","Masz, zasłużyłeś sobie. Zdrajca, którego zabiłeś zamierzał ujawnić gdzie znajduje się baza Frontu. Uratowałeś wiele żyć. Chcesz zarobić więcej pieniędzy i mieć przyszłość wolną od tyranii?","Tome, você merece. O traidor que você matou estava prestes a revelar a localização da Frente. Você salvou vidas. Que tal ganhar mais ouro e um futuro livre de tirania?",,"Aici, o meriți. Trădătorul pe care l-ai omorât urma să dezvăluie locația Frontului. Ai salvat vieți. Cum ai vrea să câștigi mai mult aur, și un viitor fără tiranie?","Вот, ты их заслужил. Убитый тобой предатель мог выдать Ордену местоположение базы Сопротивления. Ты спас много жизней. Тебе бы не хотелось ещё золота и будущего, свободного от тирании?",,"Här, du har förtjänat den. Förrädaren du dödade skulle avslöja var fronten finns. Du räddade liv. Hur skulle du vilja tjäna mer guld och en framtid fri från tyranni?","İşte, onu hak ettin. Öldürdüğün hain Cephe'nin yerini açıklamak üzereydi. Hayat kurtardın. Daha fazla altın ve zorbalıktan uzak bir gelecek kazanmaya ne dersin?" +Tell me more.,TXT_RPLY0_SCRIPT02_D78832_TELLM,〃,,,Řekni mi víc.,Fortæl mig mere.,Erzähl mir mehr.,,Mi aŭskultas vin.,Dime más.,,Kerro lisää.,Dites-moi en plus.,Mesélj még.,Dimmi di più.,もっと教えてくれ。,더 말해주시오.,Vertel me meer.,Fortell meg mer.,Mów dalej.,Me conte mais.,,Spune-mi mai multe.,Расскажи мне больше.,,Berätta mer.,Biraz daha anlat. +Not my style.,TXT_RPLY1_SCRIPT02_D78832_NOTMY,〃,,,To není můj styl.,Ikke min stil.,Nicht mein Stil.,,Tio ne estas mia stilo.,No es mi estilo.,,Ei kuulu tyyliini.,Pas mon genre.,Nem az Én stílusom.,Non fa per me.,俺の趣味じゃないな。,내 취향은 아닌데.,Niet mijn stijl.,Ikke min stil.,To nie w moim stylu.,Não faz o meu estilo.,,Nu-i genul meu.,Не в моём вкусе.,,Inte min stil.,Benim tarzım değil. +"I have a business relationship with the Front's leader, Macil. I know he needs an incisive fellow like yourself, and he pays well. Take this recovered com unit and you'll be led to, shall we say, opportunities.",TXT_DLG_SCRIPT02_D80348_IHAVE,〃,,,"Mám obchodní vztah s vůdcem Fronty, Macilem. Vím, že potřebuje schopného člověka jako ty a dobře platí. Vem si tenhle spravený komunikátor; zavede tě k, řekněme, příležitostem.","Jeg har et forretningsmæssigt forhold til frontens leder, Macil. Jeg ved, han har brug for en skarp fyr som dig, og han betaler godt. Tag denne genvundne com-enhed, og du vil blive ført til, skal vi sige, muligheder.","Ich habe Geschäftsbeziehungen mit dem Anführer der Front, Macil. Er braucht einen pfiffigen Typen wie dich und er bezahlt gut. Nimm dieses erbeutete Kommunikationsgerät und es wird dich zu, sagen wir mal, Möglichkeiten führen.",,"Mi havas negoco-ligon kun Macil la frontestro. Mi scias, ke li bezonas lertan kunulon kiel vi, aldone al tio, ke li pagas bone. Prenu ĉi tiun rekuperitan interfonon kaj vi havos la vojon al... ni diru, ŝancoj.","Tengo una relación de negocios con Macil el líder del Frente. Sé que necesita un compañero hábil como tú, además de que paga bien. Toma este intercomunicador recuperado para que te guíe a... digamos, oportunidades.",,"Minulla on liikesuhteita Rintaman johtaja Maciliin. Tiedän hänen tarvitsevan kaltaistasi terävää kaveria, ja hän maksaa hyvin. Ota tämä talteenkerätty viestintälaite, ja tiesi johtaa, sanottaisiinko, mahdollisuuksien äärelle.","J'ai une relation d'affaires avec le leader du Front, Macil. Je sais qu'il a besoin de quelqu'un d'incisif comme vous, et il paye bien. Prenez ce communicateur avec vous, et vous serez mené à des.. on va dire des opportunités.","Van egy üzleti megállapodásom Macil-lal, a Front vezetőjével. pont egy ilyen belevaló embert keres mint te, és kiváló fizetést is adna. Használd ezt a kommunikációs egységet és - mondjuk úgy - odavezet a lehetőségekhez.","Ho dei rapporti d'affari col capo del Fronte, Macil. So che è alla ricerca di una persona diretta e precisa come te, e lui paga molto bene. Tieni questa unità di comunicazione che abbiamo recuperato, e sarai condotto verso, come dire, nuove opportunità.","私はフロントのリーダー、マシルと取引を しているんだ。彼は君のような切れる人物を 必要としていて、金払いも良い。 この修理された無線機を持っていけば、 -好機に出会えるだろう。","나는 프론트의 사령관, 마실과 깊은 관계를 가지고 있다네. 그리고 그는 자네를 비롯한 예리한 사람들을 원하고 말이지. 그리고 보상도 아주 잘 준다네. 이 수리된 통신기를 받고 이동하게나. 그럼 희망은 물론 기회가 아주 많아질 거야.","Ik heb een zakelijke relatie met de leider van het Front, Macil. Ik weet dat hij een scherpzinnige kerel als jij nodig heeft, en hij betaalt goed. Neem deze herstelde com-unit en u zult worden geleid tot, laten we zeggen, kansen.","Mam relacje biznesowe z dowódcą Frontu, Macilem. Wiem, że potrzebuje on kogoś z takim zapałem jak ty, i dobrze płaci. Weź ten komunikator, a poprowadzi cię do, powiedzmy, pewnych korzyści.","Tenho uma relação de negócios com o líder da Frente, Macil. Eu sei que ele anda precisando de um sujeito incisivo como você e ele paga bem. Leve este comunicador e você será conduzido para, digamos, oportunidades.",,"Fac afaceri cu liderul Frontului, Macil. Știu că are nevoie de băieți deștepți ca tine, și plătește bine. Ia acest emițător recuperat și vei fi dus, să zicem, spre oportunități.","Я веду дела c лидером повстанцев, Мэйсилом. Я знаю, что ему нужны толковые парни вроде тебя, и он неплохо платит. Возьми этот передатчик, и перед тобой откроются, скажем так, новые перспективы.", -Thanks.,TXT_RPLY0_SCRIPT02_D80348_THANK,,,,Díky.,Danke.,,,Gracias.,,,Merci.,,,ありがとう。,알겠어요.,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Спасибо., -"Get going. If you hang around here, we're both dead.",TXT_DLG_SCRIPT02_D81864_GETGO,,,,"Měl bys jít. Jestli se tu budeš potloukat, jsme mrtví oba.","Beweg dich. Wenn wir beide hier rumhängen, dann sind wir beide tot.",,,"Ponte en marcha. Si te quedas por aquí, los dos estamos muertos.",,,"Partez maintenant, si vous traînez ici, nous serons morts tous les deux.",,,"うまくやれよ。こんな所でもたもたしていると -二人揃ってお陀仏だ。","어서 가게. 여기에 계속 있으면, 우리 둘 다 죽는다네.","Ga aan de slag. Als je hier rondhangt, zijn we allebei dood.",Rusz się. Jak będziesz się tu kręcił to obaj będziemy martwi.,"Ande logo. Se você ficar por aqui, nós dois seremos mortos.",,"Timpul să pleci. Dacă mai stai pe-aici, o să fim amândoi morți.","Двигай. Если продолжишь тут ошиваться, нас обоих убьют.", -"A pity, but now that you know about my friends, I must kill you. Guards, take out this trash!",TXT_DLG_SCRIPT02_D83380_APITY,,,,"Škoda, teď když víš o mých známých tě musím zabít. Stráže, zbavte mě tohohle smetí!","Ein Jammer, aber nun, da du über meine Freunde Bescheid weißt, muss ich dich umbringen. Wachen? Entsorgt ihn!",,,"Una pena, pero ahora que sabes de mis amigos, debo matarte. ¡Guardias, saquen esta basura!",,,"Dommage. Mais maintenant que vous savez qui sont mes amis, je dois me débarasser de vous. Garde, débarassez moi de mes ordures!",,,"残念だ、だがお前は私の友の事を知った以上 +好機に出会えるだろう。","나는 프론트의 사령관, 마실과 깊은 관계를 가지고 있다네. 그리고 그는 자네를 비롯한 예리한 사람들을 원하고 말이지. 그리고 보상도 아주 잘 준다네. 이 수리된 통신기를 받고 이동하게나. 그럼 희망은 물론 기회가 아주 많아질 거야.","Ik heb een zakelijke relatie met de leider van het Front, Macil. Ik weet dat hij een scherpzinnige kerel als jij nodig heeft, en hij betaalt goed. Neem deze herstelde com-unit en u zult worden geleid tot, laten we zeggen, kansen.","Jeg har et forretningsforhold til Frontens leder, Macil. Jeg vet at han trenger en skarp fyr som deg, og han betaler godt. Ta denne gjenfunne kommunikasjonsenheten og du vil bli ledet til, skal vi si, muligheter.","Mam relacje biznesowe z dowódcą Frontu, Macilem. Wiem, że potrzebuje on kogoś z takim zapałem jak ty, i dobrze płaci. Weź ten komunikator, a poprowadzi cię do, powiedzmy, pewnych korzyści.","Tenho uma relação de negócios com o líder da Frente, Macil. Eu sei que ele anda precisando de um sujeito incisivo como você e ele paga bem. Leve este comunicador e você será conduzido para, digamos, oportunidades.",,"Fac afaceri cu liderul Frontului, Macil. Știu că are nevoie de băieți deștepți ca tine, și plătește bine. Ia acest emițător recuperat și vei fi dus, să zicem, spre oportunități.","Я веду дела c лидером повстанцев, Мэйсилом. Я знаю, что ему нужны толковые парни вроде тебя, и он неплохо платит. Возьми этот передатчик, и перед тобой откроются, скажем так, новые перспективы.",,"Jag har en affärsrelation med frontens ledare, Macil. Jag vet att han behöver en skarpsinnig kille som du, och han betalar bra. Ta den här återvunna kom-enheten och du kommer att ledas till, ska vi säga, möjligheter.","Cephe'nin lideri Macil ile bir iş ilişkim var. Senin gibi keskin zekalı bir adama ihtiyacı olduğunu biliyorum ve iyi para ödüyor. Bu kurtarılmış iletişim birimini alın ve size, diyelim ki, fırsatlar sunulacak." +Thanks.,TXT_RPLY0_SCRIPT02_D80348_THANK,〃,,,Díky.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Kösz.,Grazie.,ありがとう。,알겠어요.,Bedankt.,Takk skal du ha.,Dzięki.,Obrigado.,,Mulțumesc.,Спасибо.,,Tack.,Teşekkürler. +"Get going. If you hang around here, we're both dead.",TXT_DLG_SCRIPT02_D81864_GETGO,〃,,,"Měl bys jít. Jestli se tu budeš potloukat, jsme mrtví oba.","Kom i gang. Hvis du bliver hængende her, er vi begge døde.","Beweg dich. Wenn wir beide hier rumhängen, dann sind wir beide tot.",,"Ekmovu vin. Se vi restos ĉi tie, ni ambaŭ mortos.","Ponte en marcha. Si te quedas por aquí, los dos estamos muertos.",,"Jatka matkaasi. Jos viivyttelet täällä, kuolemme molemmat.","Partez maintenant, si vous traînez ici, nous serons morts tous les deux.","Mozgás! Ha sokáig lébucolsz itt, mindkettőnket megölnek.","Ti conviene andartene. Se bazzichi troppo qua, siamo entrambi morti.","うまくやれよ。こんな所でもたもたしていると +二人揃ってお陀仏だ。","어서 가게. 여기에 계속 있으면, 우리 둘 다 죽는다네.","Ga aan de slag. Als je hier rondhangt, zijn we allebei dood.","Sett i gang. Hvis du blir her, er vi begge døde.",Rusz się. Jak będziesz się tu kręcił to obaj będziemy martwi.,"Ande logo. Se você ficar por aqui, nós dois seremos mortos.",,"Timpul să pleci. Dacă mai stai pe-aici, o să fim amândoi morți.","Двигай. Если продолжишь тут ошиваться, нас обоих убьют.",,Sätt igång. Om du stannar här är vi båda döda.,"Gidin hadi. Eğer burada takılırsan, ikimiz de ölürüz." +"A pity, but now that you know about my friends, I must kill you. Guards, take out this trash!",TXT_DLG_SCRIPT02_D83380_APITY,〃,,,"Škoda. Teď, když víš o mých známých, tě ale musím zabít. Stráže, zbavte mě tohohle smetí!","En skam, men nu hvor du kender til mine venner, må jeg slå dig ihjel. Vagter, tag det affald ud!","Ein Jammer, aber nun, da du über meine Freunde Bescheid weißt, muss ich dich umbringen. Wachen? Entsorgt ihn!",,"Nun kiam vi scias pri miaj amikoj, mi bedaŭrinde devas mortigi vin. Gardistoj, forprenu ĉi tiun rubon!","Una lástima, pero ahora que sabes de mis amigos, no me queda de otra que matarte. ¡Guardias, a sacar la basura!","Una pena, pero ahora que sabes de mis amigos, no me queda de otra que matarte. ¡Guardias, a sacar la basura!","Sääli, mutta nyt, kun tiedät ystävistäni, minun on tapettava sinut. Vartijat, heittäkää tämä roska ulos!","Dommage. Mais maintenant que vous savez qui sont mes amis, je dois me débarasser de vous. Garde, débarassez moi de mes ordures!","Kár érted, de sajnos miután kiderítetted a barátaim kilétét, meg kell hogy halj. Őrök, vigyétek ki ezt a szemetet!","Un vero peccato, ma ora che sai dei miei amici, non posso certo lasciarti vivo. Guardie, buttate via questa spazzatura!","残念だ、だがお前は私の友の事を知った以上 生きて帰す事はできない。 -衛兵、このゴミを片付けてくれ!","유감이군. 내 친구들을 이제 알고 있으니, 어쩔 수 없이 죽어줘야겠군. 경비병! 이 인간을 체포하라!","Jammer, maar nu je van mijn vrienden weet, moet ik je vermoorden. Bewakers, haal dit vuilnis eruit!","Szkoda, ale skoro wiesz coś o moich przyjaciołach, muszę cię zabić. Straż, wyrzućcie tego śmiecia!","É uma pena, mas agora que você sabe sobre os meus amigos, preciso matar você. Guardas, levem esse lixo daqui!",,"Păcat, dar acum că-mi cunoști prietenii, voi fi nevoit să te omor. Gardieni, duceți gunoiul!","Жаль, но теперь, когда ты знаешь о моих друзьях, мне придётся убить тебя. Стража, уберите его!", -Fool. Guards! Rid me of meddlesome peon.,TXT_DLG_SCRIPT02_D84896_FOOLG,,,,"Blázne! Stráže, zbavte se tohohle zbytečného nuzáka.",Du Narr! Wachen! Entledigt mich von diesem lästigen Tagelöhner.,,,"¡Insensato! Guardias, líbrenme de este entrometido peón.","¡Tonto! Guardias, líbrenme de este entrometido peón.",,"Idiot! Gardes, débarassez-moi de ce pion embêtant!",,,"愚かな。 -衛兵!この厄介な奴を始末してくれ。","한심한 놈! 경비병, 이 소동피우는 불량배를 잡아라.",Dwaas. Bewakers! Verloste me van bemoeizuchtige pioen.,Głupcze! Straż! Uwolnijcie mnie od tego wścibskiego robola.,"Idiota! Guardas, tirem esse peão intrometido daqui.",,"Prostule! Gardieni, scăpați-mă de acest pion băgăreț.","Глупец! Стража, избавьте меня от этого недоумка.", -"Walk away, boy, just walk away.",TXT_DLG_SCRIPT02_D86412_WALKA,,,,"Jdi pryč, chlapče, prostě jdi pryč.","Geh weg Jungchen, geh einfach weg.",,,"Aléjate, muchacho, sólo aléjate.",,,"Pars, gamin, pars.",,,どっか行け、若造、とっとと行け。,"지나가라고 친구, 그냥 지나가.","Loop weg, jongen, loop gewoon weg.","Odejdź stąd mały, po prostu odejdź.","Suma daqui, garoto. Apenas suma daqui.",,"Pleacă, băiete, pleacă.","Иди своей дорогой, парень.", -What are you doing here?,TXT_DLG_SCRIPT02_D87928_WHATA,,,,Co ty tu děláš?,Was machst du hier?,,,¿Qué estás haciendo aquí?,,,Qu'est-ce que vous foutez ici?,,,ここで何をしている?,여기서 뭘 하는거야?,Wat doe jij hier?,Co ty tu robisz?,O que você está fazendo aqui?,,Ce cauți aici?,Что ты тут делаешь?, -"Hey, I need gold!",TXT_RPLY0_SCRIPT02_D87928_HEYIN,,,,"Hej, potřeboval bych zlato!","Hey, ich brauche Gold!",,,"¡Hey, necesito oro!",,,"Hé, j'ai besoin de sous!",,,よう、金が必要だ!,"이봐, 난 골드가 필요해!","Hé, ik heb goud nodig!","Hej, potrzebuję złota!","Ei, eu preciso de ouro!",,"Hei, am nevoie de aur!","Эй, мне нужно золото!", -"Blackbird told you the code, huh? Let me shut off the alarm. Macil is one flight down.",TXT_DLG_SCRIPT02_D89444_BLACK,,,,"Straka ti řekla heslo, co? Jen vypnu alarmy. Macil je o podlaží níž.","Blackbird hat dir den Code gegeben, wie? Lass mich mal eben den Alarm abschalten. Macil ist eine Etage tiefer.",,,"Blackbird te dijo el código, ¿eh? Déjame apagar la alarma. Macil está un vuelo hacia abajo.",,,"Blackbird t'as donné le code, hein? Bon, laisse moi désactiver l'alarme. Macil est en bas des escaliers.",,,"ブラックバードに教えてもらったんだな? -警報は切っておこう。マシルはこの先だ。","블랙버드가 암호를 알려줬나 보군? 흠, 그럼 경보를 꺼둬야겠군. 마실은 계단 저 밑에 있어.","Blackbird vertelde je de code, huh? Laat me de wekker uitzetten. Macil is een vlucht naar beneden.","Blackbird podała ci hasło, co? Pozwól, że wyłączę alarm. Macil jest piętro niżej.","A Blackbird te passou o código, é? Deixa eu desligar o alarme. Macil está no andar debaixo.",,"Blackbird ți-a spus codul, huh? Permite-mi să opresc alarma, Macil e cu un etaj mai jos.","Чёрный дрозд сказал тебе пароль, так? Давай я отключу сигнализацию. Мэйсил этажом ниже.", -Thanks.,TXT_RPLY0_SCRIPT02_D89444_THANK,,,,Díky.,Danke.,,Dankon.,Gracias.,,,Merci.,,,ありがとう。,고맙다.,Bedankt.,Dzięki.,Obrigado.,,Mulțumesc.,Спасибо., -"Walk away, boy, just walk away.",TXT_DLG_SCRIPT02_D90960_WALKA,,,,"Jdi pryč, chlapče, prostě jdi pryč.","Geh weg Jungchen, geh einfach weg.",,,"Aléjate, muchacho, sólo aléjate.",,,"Pars, gamin, pars.",,,向こうへ行け、新入り、急ぐんだ。,"지나가라고 친구, 그냥 지나가.","Loop weg, jongen, loop gewoon weg.","Odejdź stąd mały, po prostu odejdź.","Suma daqui, garoto. Apenas suma daqui.",,"Pleacă, băiete, pleacă.","Иди своей дорогой, парень.", -Do you have an appointment with the Governor? ,TXT_DLG_SCRIPT02_D92476_DOYOU,,,,Máte domluvený termín schůzky s guvernérem?,Hast du einen Termin bei dem Gouverneur?,,,¿Tienes una cita con el gobernador?,,,Avez-vous un rendez-vous avec le gouverneur?,,,知事とアポイントメントは取ってますか?,총독과 약속이 있으십니까?,Heb je een afspraak met de gouverneur?,Masz spotkanie z Gubernatorem?,Você tem hora marcada com o Governador?,,Ai o programare cu Guvernatorul?,У Вас назначена встреча с губернатором?, -Of course!,TXT_RPLY0_SCRIPT02_D92476_OFCOU,,,,Samozřejmě!,Natürlich!,,,¡Claro que sí!,,,Bien sûr!,,,問題ない!,당연하지!,Natuurlijk!,Oczywiście!,Claro que sim!,,Desigur!,Конечно!, -"No, and I don't need one!",TXT_RPLY1_SCRIPT02_D92476_NOAND,,,,Ne a žádný nepotřebuju!,"Nein, und ich brauche auch keinen!",,,"¡No, y no la necesito!",,,"Non, et j'en ai pas besoin!",,,いや、必要ない!,아니. 없는데?,"Nee, en die heb ik niet nodig!","Nie mam, i nie chcę mieć!",Não e eu não preciso de hora marcada!,,"Nu, nici n-am nevoie de una!","Нет, и я в ней не нуждаюсь!", -Sorry! I didn't mean... Please go right up.,TXT_DLG_SCRIPT02_D93992_SORRY,,,,"Pardon! Nechtěl jsem... jeďte tady nahoru, prosím.",Entschuldigung! Das war nicht so gemeint... Bitte geh durch.,,,"¡Lo siento! No quise decir ... Por favor, sube.",,,"Désolé, je.. Vous pouvez monter, bien sûr.",,,"すいません!知らずに... -そのまま上がって下さい。",이런! 기다리게 할 생각은 없었는데... 부디 위로 올라가시길 바랍니다.,Sorry! Ik bedoelde niet.... Ga alsjeblieft meteen naar boven.,"Przepraszam! Nie chciałem... Proszę, idź na górę.",Desculpe! Eu não queria... Por favor pode subir.,,"Scuze! Te rog, poftește sus.","Простите! Я не думал... Пожалуйста, проходите наверх.", -I knew you'd say that.,TXT_RPLY0_SCRIPT02_D93992_IKNEW,,,,"Věděl jsem, že to řekneš.","Ich dachte mir schon, das du das sagen würdest.",,,Sabía que dirías eso.,,,Je savais que vous diriez ceci.,,,そう言うと思った。,그렇게 말할 줄 알았어.,Ik wist dat je dat zou zeggen.,"Wiedziałem, że to powiesz.",Eu sabia que você diria isso.,,Știam că vei spune asta.,"Я знал, что ты это скажешь.", -"If you're in such a hurry, don't waste your time with me.",TXT_DLG_SCRIPT02_D95508_IFYOU,,,,"Jestli tolik spěcháš, neztrácej čas se mnou.","Wenn du so in Eile bist, dann verschwende deine Zeit nicht mit mir.",,,"Si tienes tanta prisa, no pierdas el tiempo conmigo.",,,"Si vous êtes tellement pressé, ne perdez pas votre temps avec moi.",,,"そんなに急いでいるなら、 -お互い時間を大切にしましょう。","아주 급하시다면, 저하고 예기하는 건 시간 낭비일 뿐이에요.","Als je zo'n haast hebt, verspil dan geen tijd met mij.","Jeśli się tak spieszysz, nie marnuj czasu tu ze mną.","Se você está com tanta pressa, não gaste seu tempo comigo.",,"Dacă te grăbești așa tare, nu-ți pierde vremea cu mine.","Если вы так торопитесь, не тратьте на меня время.", -"Release me, leave an old man alone.",TXT_DLG_SCRIPT02_D97024_RELEA,,,,"Drž se dál, nech starce na pokoji.","Pack mich nicht an, lass einen alten Mann in Ruhe",,,"Suéltame, deja en paz a un anciano.",,,"Laissez moi tranquille, un vieil homme a le droit d'être seul.",,,ほっといてくれ、年寄り一人にしてくれ。,부탁일세. 이 노인을 내버려 두게.,"Laat me vrij, laat een oude man met rust.","Nie zbliżaj się, zostaw starca w spokoju.","Me solte, deixe um velho em paz.",,"Lasă-mă, lasă bătrânii în pace.",Оставь старика в покое!, -"You seek wisdom, my son? The order has seen to it that we only ask one question, 'Why?'",TXT_DLG_SCRIPT02_D98540_YOUSE,,,,"Hledáš moudrost, chlapče? Řád dohlédl na to, abychom se ptali jen na jedno: „Proč?“","Du suchst Weisheit, mein Sohn? Der Orden hat zugesehen das wir nur noch eine Frage stellen, „Warum?“",,,"¿Buscas sabiduría, hijo mío? La orden se ha asegurado de que solo hagamos una pregunta, '¿Por qué?'",,,"Vous cherchez ma sagesse, jeune homme? L'Ordre ne pose qu'une seule question: « Pourquoi? »",,,"知恵が欲しそうだな、ボウズ? +衛兵、このゴミを片付けてくれ!","유감이군. 내 친구들을 이제 알고 있으니, 어쩔 수 없이 죽어줘야겠군. 경비병! 이 인간을 체포하라!","Jammer, maar nu je van mijn vrienden weet, moet ik je vermoorden. Bewakers, haal dit vuilnis eruit!","Synd, men nå som du vet om vennene mine, må jeg drepe deg. Vakter, ta ut dette søppelet!","Szkoda, ale skoro wiesz coś o moich przyjaciołach, muszę cię zabić. Straż, wyrzućcie tego śmiecia!","É uma pena, mas agora que você sabe sobre os meus amigos, preciso matar você. Guardas, levem esse lixo daqui!",,"Păcat, dar acum că-mi cunoști prietenii, voi fi nevoit să te omor. Gardieni, duceți gunoiul!","Жаль, но раз уж ты узнал о моих друзьях, мне придётся тебя убить. Стража, уберите его!",,"Synd, men nu när du vet om mina vänner måste jag döda dig. Vakter, ta ut det här skräpet!","Yazık, ama artık arkadaşlarımı bildiğine göre, seni öldürmeliyim. Muhafızlar, şu çöpü dışarı çıkarın!" +Fool. Guards! Rid me of meddlesome peon.,TXT_DLG_SCRIPT02_D84896_FOOLG,〃,,,"Blázne! Stráže, zbavte se tohohle zbytečného nuzáka.",Fjols. Vagter! Fjern den besværlige bondeknold fra mig.,Du Narr! Wachen! Entledigt mich von diesem lästigen Tagelöhner.,,"Stultulo! Gardistoj, liberigu min de ĉi tiu entrudiĝema peono.","¡Insensato! Guardias, libérenme de este entrometido peón.","¡Idiota! Guardias, libérenme de este entrometido peón.",Järjetöntä. Vartijat! Hankkiutukaa eroon tästä tungettelevasta moukasta.,"Idiot! Gardes, débarassez-moi de ce pion embêtant!","Barom! Őrök, takarítsátok el a színem elől ezt a kotnyeleskedő pondrót!","Sciocco! Guardie, liberatemi da questo ficcanaso.","愚かな。 +衛兵!この厄介な奴を始末してくれ。","한심한 놈! 경비병, 이 소동피우는 불량배를 잡아라.",Dwaas. Bewakers! Verloste me van bemoeizuchtige pioen.,Idiot. Vakter! Kvitt meg med den innpåslitne bondetampen.,Głupcze! Straż! Uwolnijcie mnie od tego wścibskiego robola.,"Idiota! Guardas, tirem esse peão intrometido daqui.",,"Prostule! Gardieni, scăpați-mă de acest pion băgăreț.","Глупец! Стража, избавьте меня от этого недоумка.",,Dumbom. Vakter! Befria mig från den besvärliga pingsten.,Aptal. Muhafızlar! Beni işgüzar piyondan kurtarın. +"Walk away, boy, just walk away.",TXT_DLG_SCRIPT02_D86412_WALKA,Geoff.,,,"Jdi pryč, chlapče, prostě odejdi.","Gå væk, dreng, bare gå væk.","Geh weg Jungchen, geh einfach weg.",,"Foriru, ulo. Vi nur foriru.","Vete, chaval. Solo vete.","Vete, muchacho. Solo vete.","Kävele pois vain, poju, kävele pois.","Pars, gamin, pars.","Csak sétálj el innen, sétálj el szépen.","Muoviti, ragazzo, muoviti...",どっか行け、若造、とっとと行け。,"지나가라고 친구, 그냥 지나가.","Loop weg, jongen, loop gewoon weg.","Gå vekk, gutt, bare gå vekk.","Odejdź stąd mały, po prostu odejdź.","Suma daqui, garoto. Apenas suma daqui.",,"Pleacă, băiete, pleacă.","Иди своей дорогой, парень, иди.",,"Gå iväg, pojke, bara gå iväg.","Yürü git evlat, yürü git." +What are you doing here?,TXT_DLG_SCRIPT02_D87928_WHATA,〃,,,Co ty tu děláš?,Hvad laver du her?,Was machst du hier?,,Kion vi volas ĉi tie?,¿Qué es lo que quieres?,,Mitäs sinä täällä teet?,Qu'est-ce que vous foutez ici?,Mit művelsz itt?,Che cosa fai qua?,ここで何をしている?,여기서 뭘 하는거야?,Wat doe jij hier?,Hva gjør du her?,Co ty tu robisz?,O que você está fazendo aqui?,,Ce cauți aici?,Что ты тут делаешь?,,Vad gör du här?,Ne yapıyorsun burada? +"Hey, I need gold!",TXT_RPLY0_SCRIPT02_D87928_HEYIN,〃,,,"Hej, potřeboval bych zlato!","Hey, jeg har brug for guld!","Hey, ich brauche Gold!",,"Saluton, mi bezonas oron!","¡Buenas, necesito oro!",,"Hei, tarvitsen kultaa!","Hé, j'ai besoin de sous!","Héj, nekem arany kell!","Ehi, mi serve dell'oro!",よう、金が必要だ!,"이봐, 난 골드가 필요해!","Hé, ik heb goud nodig!",Jeg trenger gull!,"Hej, potrzebuję złota!","Ei, eu preciso de ouro!",,"Hei, am nevoie de aur!","Эй, мне нужно золото!",,Jag behöver guld!,"Hey, altına ihtiyacım var!" +"Blackbird told you the code, huh? Let me shut off the alarm. Macil is one flight down.",TXT_DLG_SCRIPT02_D89444_BLACK,〃,,,"Straka ti řekla heslo, co? Jen vypnu alarmy. Macil je o podlaží níž.","Blackbird fortalte dig koden, hva'? Lad mig slukke for alarmen. Macil er en etage længere nede.","Blackbird hat dir den Code gegeben, wie? Lass mich mal eben den Alarm abschalten. Macil ist eine Etage tiefer.",,"Merlo diris la pasfrazon al vi, ĉu? Tiuokaze mi sensonigos la alarmon. Macil estas malsupre.","Conque Blackbird te ha dado la clave, ¿eh? Ya apago la alarma, entonces. Macil está bajando las escaleras.","Así que Blackbird te dio la clave, ¿eh? Ya apago la alarma, entonces. Macil está bajando las escaleras.","Vai että Blackbird kertoi sinulle koodin? Anna, kun kytken hälyttimen pois päältä. Macil on yhdet rappuset alas.","Blackbird t'as donné le code, hein? Bon, laisse moi désactiver l'alarme. Macil est en bas des escaliers.","Feketerigó mondta el a kódot, mi? Hadd kapcosljam ki a riasztót. macil egy kőhajintásra van innen.","Blackbird ti ha detto qual'è il codice, eh? Fammi disattivare l'allarme. Macil è oltre le scale.","ブラックバードに教えてもらったんだな? +警報は切っておこう。マシルはこの先だ。","블랙버드가 암호를 알려줬나 보군? 흠, 그럼 경보를 꺼둬야겠군. 마실은 계단 저 밑에 있어.","Blackbird vertelde je de code, huh? Laat me de wekker uitzetten. Macil is een vlucht naar beneden.",Fortalte Blackbird deg koden? La meg slå av alarmen. Macil er en etasje ned.,"Blackbird podała ci hasło, co? Pozwól, że wyłączę alarm. Macil jest piętro niżej.","A Blackbird te passou o código, é? Deixa eu desligar o alarme. Macil está no andar debaixo.",,"Blackbird ți-a spus codul, huh? Permite-mi să opresc alarma, Macil e cu un etaj mai jos.","«Чёрный дрозд» сообщила тебе пароль, так? Давай я отключу сигнализацию. Мэйсил этажом ниже.",,"Blackbird berättade koden för dig, va? Låt mig stänga av larmet. Macil är en trappa ner.","Karatavuk sana kodu söyledi, ha? Alarmı kapatayım. Macil bir kat aşağıda." +Thanks.,TXT_RPLY0_SCRIPT02_D89444_THANK,〃,,,Díky.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitos.,Merci.,Kösz.,Grazie.,ありがとう。,고맙다.,Bedankt.,Takk skal du ha.,Dzięki.,Obrigado.,,Mulțumesc.,Спасибо.,,Tack.,Teşekkürler. +"Walk away, boy, just walk away.",TXT_DLG_SCRIPT02_D90960_WALKA,〃,,,"Jdi pryč, chlapče, prostě odejdi.","Gå væk, knægt, bare gå væk.","Geh weg Jungchen, geh einfach weg.",,"Foriru, ulo. Vi nur foriru.","Vete, chaval. Solo vete.","Vete, muchacho. Solo vete.","Kävele pois vain, poju, kävele pois.","Pars, gamin, pars.","Csak sétálj el innen, sétálj el szépen.","Muoviti, ragazzo, muoviti...",向こうへ行け、新入り、急ぐんだ。,"지나가라고 친구, 그냥 지나가.","Loop weg, jongen, loop gewoon weg.","Gå vekk, gutt. Bare gå vekk.","Odejdź stąd mały, po prostu odejdź.","Suma daqui, garoto. Apenas suma daqui.",,"Pleacă, băiete, pleacă.","Иди своей дорогой, парень, иди.",,"Gå iväg, pojke, bara gå iväg.","Yürü git evlat, yürü git." +Do you have an appointment with the Governor? ,TXT_DLG_SCRIPT02_D92476_DOYOU,Arion.,,,Máte domluvený termín schůzky s guvernérem?,Har du en aftale med guvernøren?,Hast du einen Termin bei dem Gouverneur?,,Ĉu vi supozeble havas rendevuon kun la registo?,¿Acaso tienes una cita con el gobernador?,,Onko teillä varattu tapaaminen kuvernöörin kanssa?,Avez-vous un rendez-vous avec le gouverneur?,Van időpontod a kormányzóval?,Hai un appuntamento con il governatore?,知事とアポイントメントは取ってますか?,총독과 약속이 있으십니까?,Heb je een afspraak met de gouverneur?,Har du en avtale med guvernøren?,Masz spotkanie z Gubernatorem?,Você tem hora marcada com o Governador?,,Ai o programare cu Guvernatorul?,У Вас назначена встреча с губернатором?,,Har du ett möte med guvernören?,Vali ile randevunuz var mı? +Of course!,TXT_RPLY0_SCRIPT02_D92476_OFCOU,〃,,,Samozřejmě!,"Ja, selvfølgelig!",Natürlich!,,Kompreneble!,¡Por supuesto!,,Totta kai!,Bien sûr!,Persze!,Certo!,問題ない!,당연하지!,Natuurlijk!,Selvsagt!,Oczywiście!,Claro que sim!,,Desigur!,Конечно!,,Självklart!,Tabii ki var! +"No, and I don't need one!",TXT_RPLY1_SCRIPT02_D92476_NOAND,〃,,,Ne a žádný nepotřebuju!,"Nej, og jeg har ikke brug for en!","Nein, und ich brauche auch keinen!",,"Ne, kaj mi ne bezonas ĝin!",¡No y no la necesito!,,"Ei, enkä sellaista tarvitsekaan!","Non, et j'en ai pas besoin!","Nincs, és nem is kell!","No, e non ne ho bisogno!",いや、必要ない!,아니. 없는데?,"Nee, en die heb ik niet nodig!","Nei, og jeg trenger ingen!","Nie mam, i nie chcę mieć!",Não e eu não preciso de hora marcada!,,"Nu, nici n-am nevoie de una!","Нет, и я в ней не нуждаюсь!",,"Nej, och jag behöver ingen!","Hayır, ihtiyacım da yok!" +Sorry! I didn't mean... Please go right up.,TXT_DLG_SCRIPT02_D93992_SORRY,〃,,,"Pardon! Nechtěl jsem... jeďte tady nahoru, prosím.",Undskyld! Jeg mente ikke... Vær venlig at gå op.,Entschuldigung! Das war nicht so gemeint... Bitte geh durch.,,"Ha, pardonon, mi ne intencis... Uzu la lifton.","Ah, perdón, no quería... Ve al piso de arriba.",,"Pahoittelut! En tarkoittanut... Menkää suoraan ylös, olkaa hyvä.","Désolé, je.. Vous pouvez monter, bien sûr.",Elnézést! Nem akartam...kérem menjen fel az emeletre.,Scusa! Non intendevo... Vai al piano di sopra.,"すいません!知らずに... +そのまま上がって下さい。",이런! 기다리게 할 생각은 없었는데... 부디 위로 올라가시길 바랍니다.,Sorry! Ik bedoelde niet.... Ga alsjeblieft meteen naar boven.,Unnskyld! Unnskyld! Jeg mente ikke... Vær så snill å gå opp.,"Przepraszam! Nie chciałem... Proszę, idź na górę.",Desculpe! Eu não queria... Por favor pode subir.,,"Scuze! Te rog, poftește sus.","Простите! Я не думал... Пожалуйста, проходите наверх.",,Jag är ledsen! Jag menade inte... Var snäll och gå upp.,Özür dilerim! Öyle demek istemedim. Lütfen yukarı çıkın. +I knew you'd say that.,TXT_RPLY0_SCRIPT02_D93992_IKNEW,〃,,,"Věděl jsem, že to řekneš.","Jeg vidste, at du ville sige det.","Ich dachte mir schon, das du das sagen würdest.",,"Mi sciis, ke vi dirus tion.",Sabía que dirías eso.,Sabía que ibas a decir eso.,"Arvasin, että sanoisit noin.",Je savais que vous diriez ceci.,"Tudtam, hogy ezt mondod.",Sapevo che l'avresti detto.,そう言うと思った。,그렇게 말할 줄 알았어.,Ik wist dat je dat zou zeggen.,Jeg visste du ville si det.,"Wiedziałem, że to powiesz.",Eu sabia que você diria isso.,,Știam că vei spune asta.,"Я знал, что ты это скажешь.",,Jag visste att du skulle säga det.,Bunu söyleyeceğini biliyordum. +"If you're in such a hurry, don't waste your time with me.",TXT_DLG_SCRIPT02_D95508_IFYOU,〃,,,"Jestli tolik spěcháte, neztrácejte čas se mnou.","Hvis du har så travlt, skal du ikke spilde din tid med mig.","Wenn du so in Eile bist, dann verschwende deine Zeit nicht mit mir.",,"Se vi vere hastas renkonti lin, ne perdu vian tempo kun mi.","Si realmente tienes tanta prisa, no pierdas el tiempo conmigo.","Si realmente estás tan apurado, no pierdas el tiempo conmigo.","Jos kerta olet niin kovassa kiireessä, älä haaskaa aikaasi minun kanssani.","Si vous êtes tellement pressé, ne perdez pas votre temps avec moi.","Ha ennyire sietsz, ne pocsékold az idődet velem.","Se vai così di fretta, non sprecare il tuo tempo con me.","そんなに急いでいるなら、 +お互い時間を大切にしましょう。","아주 급하시다면, 저하고 예기하는 건 시간 낭비일 뿐이에요.","Als je zo'n haast hebt, verspil dan geen tijd met mij.","Hvis du har det så travelt, ikke kast bort tiden din på meg.","Jeśli się tak spieszysz, nie marnuj czasu tu ze mną.","Se você está com tanta pressa, não gaste seu tempo comigo.",,"Dacă te grăbești așa tare, nu-ți pierde vremea cu mine.","Если вы так торопитесь, не тратьте на меня время.",,"Om du har så bråttom, slösa inte bort din tid med mig.","Madem bu kadar aceleniz var, benimle vakit kaybetmeyin." +"Release me, leave an old man alone.",TXT_DLG_SCRIPT02_D97024_RELEA,MAP02: MacGuffin,,,"Drž se dál, nech starce na pokoji.","Slip mig fri, lad en gammel mand være i fred.","Pack mich nicht an, lass einen alten Mann in Ruhe",,"Sufiĉe, ne ĝenu maljunulon.",Déjame en paz. No molestes a un anciano.,,"Päästä minut, jätä vanha mies rauhaan.","Laissez moi tranquille, un vieil homme a le droit d'être seul.","Engedj el, hagyd békén öreg csontjaimat.","Lasciami stare, non inquietare un vecchio.",ほっといてくれ、年寄り一人にしてくれ。,부탁일세. 이 노인을 내버려 두게.,"Laat me vrij, laat een oude man met rust.","Slipp meg, la en gammel mann være i fred.","Nie zbliżaj się, zostaw starca w spokoju.","Me solte, deixe um velho em paz.",,"Lasă-mă, lasă bătrânii în pace.",Оставь старика в покое!,,"Släpp mig, låt en gammal man vara ifred.","Bırak beni, yaşlı bir adamı yalnız bırak." +"You seek wisdom, my son? The order has seen to it that we only ask one question, 'Why?'",TXT_DLG_SCRIPT02_D98540_YOUSE,"〃 (after accepting ""messy"" chore)",,,"Hledáš moudrost, chlapče? Řád dohlédl na to, abychom se ptali jen na jedno: „Proč?“","Søger du visdom, min søn? Ordenen har sørget for, at vi kun stiller ét spørgsmål: ""Hvorfor?","Du suchst Weisheit, mein Sohn? Der Orden hat zugesehen das wir nur noch eine Frage stellen, „Warum?“",,"Ĉu vi serĉas saĝon, filo? La Ordeno certiĝis, ke ni nur faru unu demandon: «Kial?».","¿Buscas sabiduría, hijo mío? La Orden se ha asegurado de que hagamos solo una pregunta: «¿Por qué?».",,"Etsitkö viisautta, poikani? Veljeskunta on pitänyt huolen, että ainoa kysymys, jonka kysymme, on ""Miksi"".","Vous cherchez ma sagesse, jeune homme? L'Ordre ne pose qu'une seule question: « Pourquoi? »","Tudásra vágsz, fiam? A Rend gondoskodott róla, hogy az egyetlen kérdés amit felteszünk a 'Miért?'","Cerchi saggezza, figliolo? L'Ordine ha fatto si che noi possiamo chiedere una sola domanda. ""Perché?""","知恵が欲しそうだな、ボウズ? オーダーが勘付かないよう一つだけ質問しよう、 -'何故?'","지혜를 찾고 싶은가, 젊은이여? 오더도 이 사실을 알고 있어서 우리들을 '왜?' 하고 묻게 했다네. 자네도 '왜' 그러나?","Je zoekt wijsheid, mijn zoon? De orde heeft ervoor gezorgd dat we maar één vraag stellen: 'Waarom?","Poszukujesz wiedzy mój synu? Zakon stara się dopilnować nas abyśmy zadawali sobie tylko jedno pytanie, ""Czemu?""","Está atrás de sabedoria, meu filho? A ordem se certificou de que a gente só fizesse uma única pergunta, ""por quê?""",,"Cauți înțelepciune, fiul meu? Ordinul a avut grijă ca noi să putem fi în stare să punem o singură întrebare: 'De ce?'","Ищешь совета, сын мой? Орден заботится о том, чтобы нас занимал только один вопрос: «За что?»", -Where's the power coupling?,TXT_RPLY0_SCRIPT02_D98540_WHERE,,,,Kde je elektrická spojka?,Wo ist der Stromabnehmer?,,,¿Dónde está el acoplamiento eléctrico?,,,Où est le coupleur énergétique?,,,配電機 は何処だ?,동력선은 어디있나요?,Waar is de krachtkoppeling?,Gdzie jest odbierak prądu?,Cadê a conexão de energia?,,Unde e cuplajul energiei?,Где соединительная муфта?, -Where's the Order's main?,TXT_RPLY1_SCRIPT02_D98540_WHERE,,,,Kde má Řád napájecí síť?,Wo ist die Stromleitung des Ordens?,,,¿Dónde está la red principal de la Orden?,,,Où est le transformateur de l'Ordre?,,,オーダーの本管 は何処だ?,오더의 동력 공급 시설은 어디있나요?,Waar is de hoofdopdracht van de Orde?,Gdzie jest przewód Zakonu?,Cadê o transformador da Ordem?,,Unde e linia electrică a Ordinului?,Где линия электропередачи Ордена?, -Where's the illegal tap?,TXT_RPLY2_SCRIPT02_D98540_WHERE,,,,Kde je nelegální stáčedlo?,Wo ist die illegale Anzapfung?,,,¿Dónde está la intervención ilegal?,,,Où est la connection pirate?,,,違法供給源 は何処だ?,불법 추출기는 어디있나요?,Waar is de illegale kraan?,Gdzie jest nielegalny przełącznik prądu?,Cadê a ligação clandestina?,,Unde e conexiunea ilegală?,Где нелегальное подключение?, -"I'll tell you where it is, but I don't know whose coupling you'll be tampering with. It's right here in the sewage plant.",TXT_DLG_SCRIPT02_D100056_ILLTE,,,,"Řeknu ti kde je, ale nevím s čí spojkou budeš manipulovat. Je přímo tady v čističce.","Ich sage dir wo er ist, aber ich weiß nicht, an wessen Anzapfung du herummanipulieren willst. Er ist genau hier in der Kläranlage.",,,"Te diré dónde está, pero no sé de quién será la línea eléctrica que estarás manipulando. Está justo aquí en la planta de aguas residuales.",,,"Je peux vous dire où il est, mais je ne peux pas vous dire à qui il appartient. Il se trouve dans le traitement des égouts.",,,"それが何処にあるかは話そう、だがオレには +'何故?'","지혜를 찾고 싶은가, 젊은이여? 오더도 이 사실을 알고 있어서 우리들을 '왜?' 하고 묻게 했다네. 자네도 '왜' 그러나?","Je zoekt wijsheid, mijn zoon? De orde heeft ervoor gezorgd dat we maar één vraag stellen: 'Waarom?","Søker du visdom, min sønn? Ordenen har sørget for at vi bare stiller ett spørsmål. Hvorfor?","Poszukujesz wiedzy mój synu? Zakon stara się dopilnować nas abyśmy zadawali sobie tylko jedno pytanie, ""Czemu?""","Está atrás de sabedoria, meu filho? A ordem se certificou de que a gente só fizesse uma única pergunta, ""por quê?""",,"Cauți înțelepciune, fiul meu? Ordinul a avut grijă ca noi să putem fi în stare să punem o singură întrebare: 'De ce?'","Ищешь совета, сын мой? Орден заботится о том, чтобы нас занимал только один вопрос: «За что?»",,"Du söker visdom, min son? Ordern har sett till att vi bara ställer en fråga: ""Varför?","Bilgelik mi istiyorsun, oğlum? Düzen sadece tek bir soru sormamızı sağladı, ""Neden?" +Where's the power coupling?,TXT_RPLY0_SCRIPT02_D98540_WHERE,〃 (〃),,,Kde je elektrická spojka?,Hvor er kraftkoblingen?,Wo ist der Stromabnehmer?,,Kie estas la elektra kuplado?,¿Dónde está el acoplamiento eléctrico?,,Missä virtaliitin on?,Où est le coupleur énergétique?,Hol van az áram kapcsoló?,Dov'è il giunto dell'impianto energetico?,配電機 は何処だ?,동력선은 어디있나요?,Waar is de krachtkoppeling?,Hvor er kraftkoblingen?,Gdzie jest odbierak prądu?,Cadê a conexão de energia?,,Unde e cuplajul energiei?,Где соединительная муфта?,,Var är kraftkopplingen?,Güç bağlantısı nerede? +Where's the Order's main?,TXT_RPLY1_SCRIPT02_D98540_WHERE,〃 (〃),,,Kde má Řád napájecí síť?,Hvor er ordenens vigtigste?,Wo ist die Stromleitung des Ordens?,,Kie estas la elektriza sistemo de La Ordeno?,¿Dónde está la red eléctrica de La Orden?,,Missä on Veljeskunnan pääsähkölinja?,Où est le transformateur de l'Ordre?,Hol a Rend fővonala?,Dov'è il giunto dell'Ordine?,オーダーの本管 は何処だ?,오더의 동력 공급 시설은 어디있나요?,Waar is de hoofdopdracht van de Orde?,Hvor er Ordenens hovedledning?,Gdzie jest przewód Zakonu?,Cadê o transformador da Ordem?,,Unde e linia electrică a Ordinului?,Где линия электропередачи Ордена?,,Var är orderns huvudledning?,Tarikat'ın ana hattı nerede? +Where's the illegal tap?,TXT_RPLY2_SCRIPT02_D98540_WHERE,〃 (〃),,,Kde je nelegální stáčedlo?,Hvor er den ulovlige aftapning?,Wo ist die illegale Anzapfung?,,Kie estas la kontraŭleĝa konektilo?,¿Dónde está la toma eléctrica ilegal?,,Missä laiton kytkentä on?,Où est la connection pirate?,Hol az illegális lék?,Dov'è l'aggeggio illegale che sta rubando l'energia?,違法供給源 は何処だ?,불법 추출기는 어디있나요?,Waar is de illegale kraan?,Hvor er den ulovlige kranen?,Gdzie jest nielegalny przełącznik prądu?,Cadê a ligação clandestina?,,Unde e conexiunea ilegală?,Где нелегальное подключение?,,Var är den olagliga kranen?,Yasadışı musluk nerede? +"I'll tell you where it is, but I don't know whose coupling you'll be tampering with. It's right here in the sewage plant.",TXT_DLG_SCRIPT02_D100056_ILLTE,〃 (〃),,,"Řeknu ti kde je, ale nevím s čí spojkou budeš manipulovat. Je přímo tady v čističce.","Jeg skal fortælle dig, hvor den er, men jeg ved ikke, hvis kobling du vil pille ved. Den er lige her i kloakanlægget.","Ich sage dir wo er ist, aber ich weiß nicht, an wessen Anzapfung du herummanipulieren willst. Er ist genau hier in der Kläranlage.",,"Mi respondos, sed mi ne scias, kies elektrizan sistemon vi intencas perturbi. Ĝi estas ĉi tie, en la kloakpurigejo.","Te diré donde, aunque no sé de quién será la red eléctrica que quieres manipular. Está justo aquí en la planta de aguas residuales.","Te voy a decir, aunque no sé de quién será la red eléctrica que quieres manipular. Está justo aquí en la planta de aguas residuales.","Kerron kyllä, missä se on, mutten tiedä, kenen kytkentään aiot sekaantua. Se on täällä jätelaitoksella.","Je peux vous dire où il est, mais je ne peux pas vous dire à qui il appartient. Il se trouve dans le traitement des égouts.","Elárom hol van, de pontosan nem tudom kinek a kapcsolójával fogsz babrálni. Itt van rögtön a szennyvíz tisztítóban.","Ti dirò dov'è, ma non so con quale giunto in particolare tu voglia maneggiare. Sta proprio qua nell'impianto fognario.","それが何処にあるかは話そう、だがオレには どれをイジるかまでは知らん。 -配電機はここの下水処理場にある。",그게 어딨는지 말해주지. 왜 그 동력선에 손을 대려고 하는지는 모르겠지마는. 저 앞 하수도 안에 있다네.,"Ik zal je vertellen waar hij is, maar ik weet niet met wie je met de koppeling zult knoeien. Het is hier in de rioolwaterzuiveringsinstallatie.","Powiem ci gdzie jest, ale nie wiem czyj to odbierak, przy którym będziesz majstrować. Jest w oczyszczalni ścieków.","Vou te dizer onde está, mas não sei em qual ligação você vai acabar mexendo. Fica bem aqui na usina de tratamento de esgoto.",,"Îți voi spune unde este, dar nu știu de care cuplaj te vei lega. Este chiar aici, în sistemul de canalizare.","Я скажу тебе, где она, но не знаю, которая тебе нужна. Она прямо здесь, в очистной системе.", -Thanks,TXT_RPLY0_SCRIPT02_D100056_THANK,,,,Díky.,Danke,,Dankon,Gracias,,,Merci.,,,ありがとう。,그렇군요.,Bedankt,Dzięki,Obrigado,,Mulțumesc,Спасибо., -That's right here in the sewage plant. But it's the Front's coupling. Whoever told you that it was the Order's was wrong.,TXT_DLG_SCRIPT02_D101572_THATS,,,,"Síť je přímo tady, v čističce. Ale je to spojka Fronty. Kdo ti řekl, že je Řádu, se mýlil.","Genau hier, in der Kläranlage. Aber sie gehört der Front. Wer auch immer dir gesagt hat, sie gehöre dem Orden, hat gelogen.",,,"Eso es justo aquí en la planta de aguas residuales. Pero es el acoplamiento del frente. Quien te dijo que era de la Orden estaba equivocado. -",,,"Il se trouve ici dans le traitement des égouts, mais c'est le coupleur du Front . Celui qui vous a dit qu'il appartient à l'Ordre se plante.",,,"正にここの下水処理場にあるさ。 +配電機はここの下水処理場にある。",그게 어딨는지 말해주지. 왜 그 동력선에 손을 대려고 하는지는 모르겠지마는. 저 앞 하수도 안에 있다네.,"Ik zal je vertellen waar hij is, maar ik weet niet met wie je met de koppeling zult knoeien. Het is hier in de rioolwaterzuiveringsinstallatie.","Jeg skal si deg hvor den er, men jeg vet ikke hvem sin kobling du skal tukle med. Den er her i kloakkanlegget.","Powiem ci gdzie jest, ale nie wiem czyj to odbierak, przy którym będziesz majstrować. Jest w oczyszczalni ścieków.","Vou te dizer onde está, mas não sei em qual ligação você vai acabar mexendo. Fica bem aqui na usina de tratamento de esgoto.",,"Îți voi spune unde este, dar nu știu de care cuplaj te vei lega. Este chiar aici, în sistemul de canalizare.","Я скажу тебе, где она, но не знаю, которая тебе нужна. Она прямо здесь, в очистной системе.",,"Jag ska berätta var den är, men jag vet inte vems koppling du kommer att mixtra med. Den finns här i reningsverket.","Nerede olduğunu söyleyeceğim, ama kimin bağlantılarını kurcalayacağınızı bilmiyorum. Tam burada, kanalizasyon tesisinde." +Thanks,TXT_RPLY0_SCRIPT02_D100056_THANK,〃 (〃),,,Díky.,Tak,Danke,,Dankon.,Gracias.,,Kiitos,Merci.,Kösz.,Grazie,ありがとう。,그렇군요.,Bedankt,Takk skal du ha.,Dzięki,Obrigado,,Mulțumesc,Спасибо.,,Tack,Teşekkürler. +That's right here in the sewage plant. But it's the Front's coupling. Whoever told you that it was the Order's was wrong.,TXT_DLG_SCRIPT02_D101572_THATS,〃 (〃),,,"Síť je přímo tady, v čističce. Ale je to spojka Fronty. Kdo ti řekl, že je Řádu, se mýlil.","Det er lige her i kloakanlægget. Men det er Fronts kobling. Den, der fortalte dig, at det var Ordenens, tog fejl.","Genau hier, in der Kläranlage. Aber sie gehört der Front. Wer auch immer dir gesagt hat, sie gehöre dem Orden, hat gelogen.",,"Ĝi estas ĉi tie, en la kloakpurigejo, sed ĝi estas la kuplado de la Fronto. Tiu ajn, kiu diris, ke ĝi estas de La Ordeno, eraris.","Está justo aquí en la planta de aguas residuales, pero es el acoplamiento del Frente. Quien te haya dicho que era de La Orden se ha equivocado. +","Está justo aquí en la planta de aguas residuales, pero es el acoplamiento del Frente. Quien te haya dicho que era de La Orden te dijo mal. +","Se on täällä jätelaitoksella. Mutta se on Rintaman kytkentä. Kuka sinulle kertoikaan sen kuuluvan Veljeskunnalle, oli väärässä.","Il se trouve ici dans le traitement des égouts, mais c'est le coupleur du Front . Celui qui vous a dit qu'il appartient à l'Ordre se plante.","Igen, jól hallottad, a szennyvíz tisztítóban. Ez azonban a Front kapcsolója. Akárki mondta, hogy a Rendé, hazudott neked.",È proprio qui nell'impianto fognario. Ma è il giunto del Fronte. Chiunque ti abbia detto che fosse il giunto dell'Ordine si sbagliava.,"正にここの下水処理場にあるさ。 だがそれはフロントにも繋いでいる。 そいつがオーダーの所有物と言われてたが、 -そりゃ間違いだ。",저 앞 하수도 안에 있다네. 프론트가 설치한 동력선일세. 저게 오더 소유라고 우기던 사람은 거짓말을 한 게야.,"Dat is hier in de rioolwaterzuiveringsinstallatie. Maar het is de koppeling van de voorkant. Degene die je vertelde dat het de Order's waren, had het mis.","Jest w oczyszczalni ścieków. Ale to jest odbierak Frontu. Ktokolwiek ci powiedział, że należy do Zakonu, był w błędzie.",Fica bem aqui na usina de tratamento de esgoto. Mas é a ligação da Frente. Quem te falou que era da Ordem estava enganado.,,Este chiar aici în sistemul de canalizare. Dar este cuplajul Frontului. Oricine ți-a spus că e al Ordinului a greșit.,"Она прямо здесь, в очистном сооружении. Но это линия Сопротивления. Тот, кто сказал тебе, что она принадлежит Ордену, ошибся. -", -Thanks,TXT_RPLY0_SCRIPT02_D101572_THANK,,,,Díky.,Danke.,,Dankon,Gracias,,,Merci.,,,ありがとう。,고맙습니다.,Bedankt,Dzięki,Obrigado,,Mulțumesc,Спасибо., -If you say it's illegal I want nothing to do with you. I have enough trouble as it is.,TXT_DLG_SCRIPT02_D103088_IFYOU,,,,"Jestli říkáš nelegální, nechci s tebou mít nic do činění. Už tak mám svých problémů dost.","Wenn du sagst, es sei illegal, möchte ich nichts damit zu tun haben. Ich habe schon genug Probleme.",,,Si dices que es ilegal no quiero tener nada que ver contigo. Ya tengo suficientes problemas.,,,"Si vous dites que c'est un truc illégal, alors je ne veux pas m'en mêler. J'ai déjà assez de problèmes.",,,"それが違法だっつうんならオレには関係無い。 -トラブルは御免だ。",저게 불법이라고 말한다면 난 이제 더는 모른다네. 관련 문제도 원치 않고 말일세.,"Als je zegt dat het illegaal is, wil ik niets met je te maken hebben. Ik heb al genoeg problemen.","Jeśli mówisz, że jest nielegalny, to nie chcę mieć z tobą nic wspólnego. Mam wystarczająco dużo kłopotów.",Se você diz que isso é ilegal então eu não quero envolvimento nenhum contigo. Já tenho problemas o suficiente.,,"Dacă zici că e ilegal, nu vreau să am nimic de-aface cu tine. Am destule probleme deja.","Раз ты говоришь, что оно нелегально, я не хочу иметь с тобой дел. Мне и так хватает проблем.", -Thanks,TXT_RPLY0_SCRIPT02_D103088_THANK,,,,Díky.,Danke,,Dankon,Gracias,,,Merci.,,,ありがとう。,감사합니다.,Bedankt,Dzięki,Obrigado,,Mulțumesc,Спасибо., -"Release me, leave an old man alone.",TXT_DLG_SCRIPT02_D104604_RELEA,,,,"Drž se dál, nech starce na pokoji.",Bitte lass einen alten Mann in Ruhe,,,"Suéltame, deja en paz a un anciano.",,,"Laissez moi tranquille, un vieil homme a le droit d'être seul.",,,ほっといてくれ、年寄り一人にしてくれ。,보내주게. 이 노인은 이제 아무것도 몰라.,"Laat me vrij, laat een oude man met rust.","Nie zbliżaj się, zostaw starca w spokoju.","Me solte, deixe um velho em paz.",,"Lasă-mă, lasă bătrânii în pace.",Оставь старика в покое!, -"Welcome to the last flicker of hope. Only we have the free will to oppose the Order. We have the sharpest scientific minds, and many able bodies, but we lack that one real, uh... Problemsolver, who will give us the edge we need. Help us.",TXT_DLG_SCRIPT03_D0_WELCO,,,,"Vítej u posledního plamínku naděje. Jen my máme svobodnou vůli vzdorovat Řádu. Máme sice nejčilejší vědecké génie a mnoho schopných vojáků, ale chybí nám ten jeden... řešitel problémů, který by nás posunul vpřed. Pomoz nám.","Wilkommen beim letzten Hoffnungsschimmer. Nur wir haben noch den freien Willen, um gegen den Orden zu arbeiten. Wir haben die besten Wissenschaftler und viele fähige Kämpfer aber was uns fehlt ist ein spezieller... äh... Problemlöser, der uns den nötigen Vorteil verschafft. Bitte hilf uns.",,,"Bienvenido al último destello de esperanza. Solo nosotros tenemos el libre albedrío para oponernos a la Orden. Tenemos las mentes científicas más inteligentes y muchos cuerpos capaces, pero nos falta un, uh ... solucionador de problemas, quien nos dará la ventaja que necesitamos. Ayúdanos.",,,"Bienvenue au dernier lieu d'espoir. Nous seuls avons la liberté d'esprit pour opposer l'Ordre. Nous avons les esprits scientifiques les plus aiguisés et de nombreux hommes habiles et sains.. Mais il nous manque quelqu'un qui pourrait.. résoudre nos problèmes. Nous donner un peu d'aide, nous permettre de prendre l'avantage.",,,"ようこそ、ここは我々の僅かな希望が集まる +そりゃ間違いだ。",저 앞 하수도 안에 있다네. 프론트가 설치한 동력선일세. 저게 오더 소유라고 우기던 사람은 거짓말을 한 게야.,"Dat is hier in de rioolwaterzuiveringsinstallatie. Maar het is de koppeling van de voorkant. Degene die je vertelde dat het de Order's waren, had het mis.","Det er her i kloakkanlegget. Men det er Fronts kobling. Den som sa at det var Ordenens, tok feil.","Jest w oczyszczalni ścieków. Ale to jest odbierak Frontu. Ktokolwiek ci powiedział, że należy do Zakonu, był w błędzie.",Fica bem aqui na usina de tratamento de esgoto. Mas é a ligação da Frente. Quem te falou que era da Ordem estava enganado.,,Este chiar aici în sistemul de canalizare. Dar este cuplajul Frontului. Oricine ți-a spus că e al Ordinului a greșit.,"Она прямо здесь, в очистном сооружении. Но это линия Сопротивления. Тот, кто сказал тебе, что она принадлежит Ордену, ошибся. +",,Det är precis här i reningsverket. Men det är Fronts koppling. Den som sa till dig att det var ordens koppling hade fel.,"Tam burada, kanalizasyon tesisinde. Ama bu Cephe'nin bağlantısı. Size kim Tarikat'ın olduğunu söylediyse yanılmış." +Thanks,TXT_RPLY0_SCRIPT02_D101572_THANK,〃 (〃),,,Díky.,Tak,Danke.,,Dankon.,Gracias.,,Kiitos,Merci.,Kösz.,Grazie,ありがとう。,고맙습니다.,Bedankt,Takk.,Dzięki,Obrigado,,Mulțumesc,Спасибо.,,Tack,Teşekkürler. +If you say it's illegal I want nothing to do with you. I have enough trouble as it is.,TXT_DLG_SCRIPT02_D103088_IFYOU,〃 (〃),,,"Jestli říkáš nelegální, nechci s tebou nic mít. Už tak mám svých problémů dost.","Hvis du siger, det er ulovligt, vil jeg ikke have noget med dig at gøre. Jeg har problemer nok i forvejen.","Wenn du sagst, es sei illegal, möchte ich nichts damit zu tun haben. Ich habe schon genug Probleme.",,"Se vi diras, ke ĝi estas kontraŭleĝa, mi volas nenian rilaton kun vi. Mi jam havas sufiĉe da problemoj.",Si dices que es ilegal no quiero tener nada que ver contigo. Ya tengo suficientes problemas.,,"Jos sanot sen olevan laiton, en halua olla kanssasi missään tekemisissä. On jo riitämiin pärjäämistä nykyhuolteni kanssa.","Si vous dites que c'est un truc illégal, alors je ne veux pas m'en mêler. J'ai déjà assez de problèmes.","Ha azt mondod, hogy illegális, nem akarok benne lenni. Van már így is elég bajom.","Se dici che è illegale, non voglio averci nulla a che fare. Ho già abbastanza problemi di mio.","それが違法だっつうんならオレには関係無い。 +トラブルは御免だ。",저게 불법이라고 말한다면 난 이제 더는 모른다네. 관련 문제도 원치 않고 말일세.,"Als je zegt dat het illegaal is, wil ik niets met je te maken hebben. Ik heb al genoeg problemen.","Hvis du sier det er ulovlig, vil jeg ikke ha noe med deg å gjøre. Jeg har nok problemer som det er.","Jeśli mówisz, że jest nielegalny, to nie chcę mieć z tobą nic wspólnego. Mam wystarczająco dużo kłopotów.",Se você diz que isso é ilegal então eu não quero envolvimento nenhum contigo. Já tenho problemas o suficiente.,,"Dacă zici că e ilegal, nu vreau să am nimic de-aface cu tine. Am destule probleme deja.","Раз ты говоришь, что оно нелегально, я не хочу иметь с тобой дел. Мне и так хватает проблем.",,Om du säger att det är olagligt vill jag inte ha något med dig att göra. Jag har tillräckligt med problem som det är.,"Eğer bunun yasadışı olduğunu söylüyorsanız, sizinle hiçbir şey yapmak istemiyorum. Başımda yeterince bela var zaten." +Thanks,TXT_RPLY0_SCRIPT02_D103088_THANK,〃 (〃),,,Díky.,Tak,Danke,,Dankon.,Gracias.,,Kiitos,Merci.,Kösz,Grazie,ありがとう。,감사합니다.,Bedankt,Takk.,Dzięki,Obrigado,,Mulțumesc,Спасибо.,,Tack,Teşekkürler. +"Release me, leave an old man alone.",TXT_DLG_SCRIPT02_D104604_RELEA,〃 (〃),,,"Drž se dál, nech starce na pokoji.","Slip mig fri, lad en gammel mand være i fred.",Bitte lass einen alten Mann in Ruhe,,"Sufiĉe, ne ĝenu maljunulon.",Déjame en paz. No molestes a un anciano.,,"Päästä minut, jätä vanha mies rauhaan.","Laissez moi tranquille, un vieil homme a le droit d'être seul.","Engedj el, hagyd békén öreg csontjaimat.","Lasciami stare, non inquietare un vecchio.",ほっといてくれ、年寄り一人にしてくれ。,보내주게. 이 노인은 이제 아무것도 몰라.,"Laat me vrij, laat een oude man met rust.","Slipp meg fri, la en gammel mann være i fred.","Nie zbliżaj się, zostaw starca w spokoju.","Me solte, deixe um velho em paz.",,"Lasă-mă, lasă bătrânii în pace.",Оставь старика в покое!,,"Släpp mig, låt en gammal man vara ifred.","Bırakın beni, yaşlı bir adamı yalnız bırakın." +"Welcome to the last flicker of hope. Only we have the free will to oppose the Order. We have the sharpest scientific minds, and many able bodies, but we lack that one real, uh... Problemsolver, who will give us the edge we need. Help us.",TXT_DLG_SCRIPT03_D0_WELCO,MAP03: Macil.,,,"Vítej u posledního plamínku naděje. Jen my máme svobodnou vůli vzdorovat Řádu. Máme sice nejčilejší vědecké génie a mnoho schopných vojáků, ale chybí nám ten jeden... pomocník, který by nás posunul vpřed. Pomoz nám.","Velkommen til det sidste lille håb. Kun vi har den frie vilje til at modsætte os Ordenen. Vi har de skarpeste videnskabelige hjerner og mange dygtige kroppe, men vi mangler den ene rigtige, øh... Problemløser, som vil give os den fordel, vi har brug for. Hjælp os.","Wilkommen beim letzten Hoffnungsschimmer. Nur wir haben noch den freien Willen, um gegen den Orden zu arbeiten. Wir haben die besten Wissenschaftler und viele fähige Kämpfer aber was uns fehlt ist ein spezieller... äh... Problemlöser, der uns den nötigen Vorteil verschafft. Bitte hilf uns.",,"Bonvenon en la lasta fajrero da espero. Nur ni havas liberan volon por kontraŭstari al La Ordeno. Ni havas la plej inteligentajn mensojn kaj multe da kapablaj homoj, sed mankas tiu, kiu estus, hm... vera problem-solvanto, por ke li donu al ni la necesan avantaĝon. Helpu nin.","Bienvenido al último destello de esperanza. Solo nosotros tenemos el libre albedrío para oponernos a La Orden. Tenemos las mentes científicas más brillantes y muchas personas capaces, pero nos falta el que sería, este... todo un solucionador de problemas para que nos dé la ventaja que necesitamos. Ayúdanos.",,"Tervetuloa viimeisen toivonpilkahduksen äärelle. Ainoastaan meillä on vapaa tahto vastustaa Veljeskuntaa. Meillä on tieteen terävimmät mielet ja monia ruumiiltaan vahvoja, mutta meiltä puuttuu se yksi todellinen, sanottaisiinko, Ongelmanratkoja, joka antaisi meille kaipaamamme etulyöntiaseman. Auta meitä.","Bienvenue au dernier lieu d'espoir. Nous seuls avons la liberté d'esprit pour opposer l'Ordre. Nous avons les esprits scientifiques les plus aiguisés et de nombreux hommes habiles et sains.. Mais il nous manque quelqu'un qui pourrait.. résoudre nos problèmes. Nous donner un peu d'aide, nous permettre de prendre l'avantage.","Köszöntelek a remény utolsó pislákoló fényénél. Már csak mi merünk szembeszállni a Renddel. Itt vannak a legélesebb elmék, életerős emberek, de hiányzik egy igazi...probléma megoldó, aki előnyt szerez számunkra. Segíts nekünk!","Benvenuto nell'ultimo barlume di speranza. Noi siamo i soli ad avere la determinazione per combattere l'Ordine. Abbiamo brillanti scienziati e molti soldati capaci, ma ci manca quel vero e proprio... risolutore di problemi, che ci può dare quel vantaggio che cerchiamo. Aiutaci!","ようこそ、ここは我々の僅かな希望が集まる 最後の場所だ。オーダーへと立ち向かう意思を 持っているのは我々くらいだ。 ここには素晴らしい頭脳を持つ学者たち、そして 丈夫な体を持った戦士たちがいる。 だがしかし、我々には問題解決に優れた者、 つまり私達の力となる者が足りていないんだ。 -我々に手を貸してくれ。","최후의 희망 한 가닥을 잡은 것을 환영합니다. 우리만이 오더를 거부할 수 있는 의지를 갖추고 있죠. 뛰어난 과학력과 전투력은 다 갖추고 있습니다만, 정작 '해결사' 몫을 해주는 인물이 없어서 말입니다... 부디 우리를 도와주시길 바랍니다.","Welkom bij het laatste sprankje hoop. Alleen wij hebben de vrije wil om ons te verzetten tegen de Orde. We hebben de scherpste wetenschappelijke geesten en veel bekwame lichamen, maar we missen die ene echte, uh.... probleemoplosser, die ons de voorsprong zal geven die we nodig hebben. Help ons.","Witaj w ostatniej iskierce nadziei. Tylko my mamy wolną wolę, aby sprzeciwić się Zakonowi. Mamy najmądrzejszych naukowców i wielu ludzi, ale brakuje nam kogoś porządnego by, ehmm... rozwiązać parę problemów, kogoś kto da nam przewagę, której potrzebujemy. Pomóż nam.","Seja bem-vindo à última ponta de esperança. Somente nós temos o livre arbítrio para combater a Ordem. Temos as mentes científicas mais afiadas e muitas pessoas capazes, mas nos falta aquele verdadeiro, hã... quebra-galho, que nos dará o impulso que precisamos. Ajude-nos.",,"Bun venit la ultima fărâmă de speranță. Numai noi avem voința liberă necesară pentru a ne opune Ordinului. Avem cele mai ascuțite minți științifice, și mulți oameni capabili de muncă, dar ne lipsește acel um... adevărat Salvator de la probleme, care să ne ofere avantajul de care avem nevoie. Ajută-ne.","Добро пожаловать в последний оплот надежды. Только мы обладаем свободной волей, чтобы противостоять Ордену. С нами лучшие учёные умы, и у нас есть много толковых людей, но нам не хватает одного-единственного, э... «разрешителя проблем», который поможет нам получить необходимое преимущество. Помоги нам.", -"All right, I accept.",TXT_RPLY0_SCRIPT03_D0_ALLRI,,,,"Dobře, příjimám.","Klar, ich bin dabei.",,,"De acuerdo, acepto.",,,Très bien. J'accepte.,,,いいぞ、引き受けよう。,좋아요. 받아들이죠.,"Oké, ik accepteer het.","Dobrze, zgadzam się.","Tá certo, eu aceito.",,"În reglă, accept.",Хорошо. Я согласен., -No thanks!,TXT_RPLY1_SCRIPT03_D0_NOTHA,,,,"Ne, díky.","Nein, danke!",,,¡No gracias!,,,Non merci.,,,断る!,사양할게요!,"Nee, dank je wel!","Nie, dziękuję!","Não, obrigado!",,Nu merci!,"Нет уж, спасибо!", -"You might want to reconsider, seeing that you're surrounded by heavily armed angry rebels.",TXT_DLG_SCRIPT03_D1516_YOUMI,,,,"Možná bys o tom měl popřemýšlet, soudě podle toho, že jsi obklopen po zuby ozbrojenými, naštvanými rebely.","Bitte überdenke das nochmal, angesichts der Tatsache, dass du von befaffneten und zornigen Rebellen umgeben bist.",,,"Es posible que desees reconsiderar, ya que estas rodeado de rebeldes enojados fuertemente armados.",,,"J'espère que vous pouvez y réfléchir. Après tout, vous êtes entouré de rebelles lourdement armés et prêts à se défendre.",,,"少し考え直したほうが良さそうだぞ、 +我々に手を貸してくれ。","최후의 희망 한 가닥을 잡은 것을 환영합니다. 우리만이 오더를 거부할 수 있는 의지를 갖추고 있죠. 뛰어난 과학력과 전투력은 다 갖추고 있습니다만, 정작 '해결사' 몫을 해주는 인물이 없어서 말입니다... 부디 우리를 도와주시길 바랍니다.","Welkom bij het laatste sprankje hoop. Alleen wij hebben de vrije wil om ons te verzetten tegen de Orde. We hebben de scherpste wetenschappelijke geesten en veel bekwame lichamen, maar we missen die ene echte, uh.... probleemoplosser, die ons de voorsprong zal geven die we nodig hebben. Help ons.","Velkommen til det siste glimt av håp. Bare vi har den frie viljen til å motsette oss Ordenen. Vi har de skarpeste vitenskapelige hodene, og mange dyktige kropper, men vi mangler den ene virkelige... problemløseren, som vil gi oss det forspranget vi trenger. Hjelp oss.","Witaj w ostatniej iskierce nadziei. Tylko my mamy wolną wolę, aby sprzeciwić się Zakonowi. Mamy najmądrzejszych naukowców i wielu ludzi, ale brakuje nam kogoś porządnego by, ehmm... rozwiązać parę problemów, kogoś kto da nam przewagę, której potrzebujemy. Pomóż nam.","Seja bem-vindo à última ponta de esperança. Somente nós temos o livre arbítrio para combater a Ordem. Temos as mentes científicas mais afiadas e muitas pessoas capazes, mas nos falta aquele verdadeiro, hã... quebra-galho, que nos dará o impulso que precisamos. Ajude-nos.",,"Bun venit la ultima fărâmă de speranță. Numai noi avem voința liberă necesară pentru a ne opune Ordinului. Avem cele mai ascuțite minți științifice, și mulți oameni capabili de muncă, dar ne lipsește acel um... adevărat Salvator de la probleme, care să ne ofere avantajul de care avem nevoie. Ajută-ne.","Добро пожаловать в последний оплот надежды. Только мы обладаем свободной волей, чтобы противостоять Ордену. С нами лучшие учёные умы, и у нас есть много толковых людей, но нам не хватает одного-единственного, э... «решателя проблем», который поможет нам получить необходимое преимущество. Помоги нам.",,"Välkommen till den sista flimret av hopp. Endast vi har den fria viljan att motsätta oss Orden. Vi har de skarpaste vetenskapliga hjärnorna och många dugliga kroppar, men vi saknar den där riktiga... Problemlösaren, som kan ge oss det övertag vi behöver. Hjälp oss.","Son umut ışığına hoş geldiniz. Tarikat'a karşı koyacak özgür irade sadece bizde var. En keskin bilimsel zihinlere ve birçok yetenekli bedene sahibiz, ancak bize ihtiyacımız olan avantajı sağlayacak gerçek bir Problem Çözücüden yoksunuz. Bize yardım edin." +"All right, I accept.",TXT_RPLY0_SCRIPT03_D0_ALLRI,〃,,,"Dobře, příjimám.","Okay, jeg accepterer.","Klar, ich bin dabei.",,"Bone, mi akceptas.","Muy bien, acepto.",,"Hyvä on, suostun auttamaan.",Très bien. J'accepte.,"Rendben, elfogadom.","Va bene, accetto.",いいぞ、引き受けよう。,좋아요. 받아들이죠.,"Oké, ik accepteer het.","Greit, jeg aksepterer.","Dobrze, zgadzam się.","Tá certo, eu aceito.",,"În regulă, accept.",Хорошо. Я согласен.,,"Okej, jag accepterar.","Pekala, kabul ediyorum." +No thanks!,TXT_RPLY1_SCRIPT03_D0_NOTHA,〃,,,"Ne, díky.",Nej tak!,"Nein, danke!",,"Ne, dankon!","¡No, gracias!",,Ei kiitos!,Non merci.,Nem kösz!,"No, grazie!",断る!,사양할게요!,"Nee, dank je wel!",Nei takk!,"Nie, dziękuję!","Não, obrigado!",,Nu merci!,"Нет уж, спасибо!",,"Nej, tack!","Hayır, teşekkürler!" +"You might want to reconsider, seeing that you're surrounded by heavily armed angry rebels.",TXT_DLG_SCRIPT03_D1516_YOUMI,〃,,,"Možná bys o tom měl popřemýšlet, soudě podle toho, že jsi obklopen po zuby ozbrojenými, naštvanými rebely.","Du bør måske genoverveje det, når du er omgivet af tungt bevæbnede vrede oprørere.","Bitte überdenke das nochmal, angesichts der Tatsache, dass du von befaffneten und zornigen Rebellen umgeben bist.",,"Vi eble volos rekonsideri tion, se ni konsideras, ke vi estas ĉirkaŭita de ege armitaj kaj koleraj ribelantoj.","Puede que quieras reconsiderarlo, ya que estás rodeado de rebeldes ya hartos y bien armados.",,"Haluannet ehkä harkita uudelleen, ottaen huomioon, että ympärilläsi on vihainen joukko raskaasti aseistettuja kapinallisia.","J'espère que vous pouvez y réfléchir. Après tout, vous êtes entouré de rebelles lourdement armés et prêts à se défendre.","Azt ajánlanám, hogy gondold újra, lévén hogy mérges fegyveres lázadók vesznek körbe.","Forse faresti meglio a ripensarci, considerato che sei circondato da ribelli arrabbiati e armati.","少し考え直したほうが良さそうだぞ、 君が重装備の怒れる兵士たちに -囲まれているのはわかるだろう?",다시... 생각을 해보는 게 좋을 것 같군요. 우리 병사들을 당황하게 만든 것 같은데 말이죠.,"Misschien wil je er nog eens over nadenken, aangezien je omringd wordt door zwaar bewapende, boze rebellen.","Może zmienisz zdanie, kiedy zauważysz, że jesteś otoczony przez ciężko uzbrojonych, wściekłych rebeliantów.","Talvez você queira reconsiderar, já que está cercado de rebeldes furiosos armados até os dentes.",,"S-ar putea să vrei să reconsideri, având în vedere că ești înconjurat de rebeli nervoși înarmați până în dinți.","Возможно, при виде нервных и вооружённых до зубов повстанцев ты передумаешь.", -"All right, I'm in!",TXT_RPLY0_SCRIPT03_D1516_ALLRI,,,,"Dobře, jdu do toho!","Na gut, ich bin dabei.",,,"De acuerdo, ¡quiero entrar!",,,"Ok, d'accord, j'accepte!",,,わかった、乗ろう!,그럼 도와주도록 하죠.,"Oké, ik doe mee!","Dobra, wchodzę w to!","Tá certo, estou dentro!",,"Bine, mă bag!","Хорошо, я с вами!", -No thanks.,TXT_RPLY1_SCRIPT03_D1516_NOTHA,,,,"Ne, díky.","Nein, danke!",,,No gracias.,,,Non merci.,,,断る。,싫어요! 당신은 낯선 사람이잖아요!,"Nee, bedankt.","Nie, dziękuję.","Não, obrigado.",,Nu merci.,"Нет, спасибо.", -Then die in shame and dishonor.,TXT_DLG_SCRIPT03_D3032_THEND,,,Then die in shame and dishonour.,Pak zemři v hanbě a potupě!,Dann wirst du in Schande und Unehre sterben.,,,Entonces muere en vergüenza y deshonra.,,,Périssez dans la honte et le déshonneur.,,,では、恥と不名誉と共に死ぬがいい。,그럼 불명예스럽고 초라하게 죽어버리시길!,Sterf dan in schaamte en oneer.,Więc giń we wstydzie i hańbie.,Então morra com desonra e vergonha!,,Atunci mori în rușine și dezonoare.,Тогда умри в бесчестии и позоре., -"Good, Blackbird will continue to be your guide. She's taken quite a shine to you. Together you've got to unlock the secrets of the Order and their inhuman servants. Get inside and take them down.",TXT_DLG_SCRIPT03_D4548_GOODB,,,,"Dobře, Straka ti bude dále dávat pokyny. Docela ses jí zalíbil. Společně budete muset odkrýt tajemství Řádu a jeho nelidských služebníků. Pronikněte dovnitř a sejměte je.","Gut so! Blackbird wird weiter deine Leiterin sein, sie scheint dich zu mögen. Zusammen müsst ihr die Geheimnisse des Ordens und ihrer unmenschlichen Diener ergründen. Dann haben wir eine Chance, sie niederzuringen.",,,"Bien, Blackbird continuará siendo tu guía. Parece que le caes bien. Juntos debéis descubrir los secretos de la Orden y sus sirvientes inhumanos. Entrad y echadlos abajo.","Bien, Blackbird continuará siendo tu guía. Parece que le caes bien. Juntos deberán descubrir los secretos de la Orden y sus sirvientes inhumanos. Penetrar y echarlos abajo.",,"Parfait. Blackbird continuera à être votre guide. Elle semble vous apprécier. Ensemble, vous allez découvrir les secrets de l'Ordre et leurs servants inhumains. Infiltrez-les et détruisez-les.",,,"よし、君のガイドをブラックバードが今後務める +囲まれているのはわかるだろう?",다시... 생각을 해보는 게 좋을 것 같군요. 우리 병사들을 당황하게 만든 것 같은데 말이죠.,"Misschien wil je er nog eens over nadenken, aangezien je omringd wordt door zwaar bewapende, boze rebellen.","Du bør kanskje revurdere det, siden du er omringet av tungt bevæpnede, sinte opprørere.","Może zmienisz zdanie, kiedy zauważysz, że jesteś otoczony przez ciężko uzbrojonych, wściekłych rebeliantów.","Talvez você queira reconsiderar, já que está cercado de rebeldes furiosos armados até os dentes.",,"S-ar putea să vrei să reconsideri, având în vedere că ești înconjurat de rebeli nervoși înarmați până în dinți.","Возможно, при виде нервных и вооружённых до зубов повстанцев ты передумаешь.",,"Du kanske vill tänka om, eftersom du är omgiven av tungt beväpnade arga rebeller.",Etrafınız ağır silahlı kızgın asilerle çevrili olduğuna göre tekrar düşünmek isteyebilirsiniz. +"All right, I'm in!",TXT_RPLY0_SCRIPT03_D1516_ALLRI,〃,,,"Dobře, jdu do toho!","Okay, jeg er med!","Na gut, ich bin dabei.",,"Bone, mi aliĝos!","De acuerdo, ¡quiero entrar!",,"Hyvä on, olen messissä!","Ok, d'accord, j'accepte!","Rendben, benne vagyok!","Va bene, vi aiuterò!",わかった、乗ろう!,그럼 도와주도록 하죠.,"Oké, ik doe mee!","Greit, jeg er med!","Dobra, wchodzę w to!","Tá certo, estou dentro!",,"Bine, mă bag!","Хорошо, я с вами!",,"Okej, jag är med!","Pekala, ben varım!" +No thanks.,TXT_RPLY1_SCRIPT03_D1516_NOTHA,〃,,,"Ne, díky.",Nej tak.,"Nein, danke!",,"Ne, dankon.","No, gracias.",,Ei kiitos.,Non merci.,Nem kösz.,No grazie.,断る。,싫어요! 당신은 낯선 사람이잖아요!,"Nee, bedankt.",Nei takk.,"Nie, dziękuję.","Não, obrigado.",,Nu merci.,"Нет, спасибо.",,"Nej, tack.","Hayır, teşekkürler." +Then die in shame and dishonor.,TXT_DLG_SCRIPT03_D3032_THEND,〃,,Then die in shame and dishonour.,Pak zemři v hanbě a potupě!,Så dø i skam og vanære.,Dann wirst du in Schande und Unehre sterben.,,Tiuokaze mortu honte kaj senhonore.,Entonces muere en vergüenza y deshonra.,,Sitten kuole häpeässä vailla kunniaa.,Périssez dans la honte et le déshonneur.,Akkor szégyenteljes halál vár rád.,"E allora muori, con vergogna e disonore!",では、恥と不名誉と共に死ぬがいい。,그럼 불명예스럽고 초라하게 죽어버리시길!,Sterf dan in schaamte en oneer.,Så dø i skam og vanære.,Więc giń we wstydzie i hańbie.,Então morra com desonra e vergonha!,,Atunci mori în rușine și dezonoare.,Тогда умри в бесчестии и позоре.,,Dö då i skam och vanära.,O zaman utanç ve onursuzluk içinde öl. +"Good, Blackbird will continue to be your guide. She's taken quite a shine to you. Together you've got to unlock the secrets of the Order and their inhuman servants. Get inside and take them down.",TXT_DLG_SCRIPT03_D4548_GOODB,〃,,,"Dobře, Straka ti bude dále dávat pokyny. Docela ses jí zalíbil. Společně budete muset odkrýt tajemství Řádu a jeho nelidských služebníků. Pronikněte dovnitř a sejměte je.","Godt, Blackbird vil fortsat være din guide. Hun er blevet ret glad for dig. Sammen skal I løse hemmelighederne om Ordenen og deres umenneskelige tjenere. Kom ind og nedlæg dem.","Gut so! Blackbird wird weiter deine Leiterin sein, sie scheint dich zu mögen. Zusammen müsst ihr die Geheimnisse des Ordens und ihrer unmenschlichen Diener ergründen. Dann haben wir eine Chance, sie niederzuringen.",,"Bone. Merlo plue estos via gvidanto; ŝajnas, ke ŝi jam simpatias vin. Vi kune devas malkaŝi la sekretojn de La Ordeno kaj de ĝiaj nehomaj servantoj. Enŝoviĝu kaj detruu ilin.",Bien. Blackbird seguirá siendo tu guía; parece que ya le caes bien. Juntos debéis descubrir los secretos de La Orden y de sus sirvientes inhumanos. Infiltraos y acabad con ellos.,Bien. Blackbird va a seguir siendo tu guía; parece que ya le caes bien. Juntos deben descubrir los secretos de La Orden y de sus sirvientes inhumanos. Infíltrense y destrúyanlos.,Hyvä; Blackbird jatkaa opastajanasi. Hän vaikuttaa pitävän sinusta. Teidän on yhdessä paljastettava Veljeskunnan ja heidän epäinhimillisten palvelijoinsa salat. Murtaudu sisään ja aja heidät alas.,"Parfait. Blackbird continuera à être votre guide. Elle semble vous apprécier. Ensemble, vous allez découvrir les secrets de l'Ordre et leurs servants inhumains. Infiltrez-les et détruisez-les.","Helyes, Feketerigó továbbra is az irányítód lesz. Eléggé megtetszettél neki. Együtt meg fogjátok fejteni a Rend és kegyetlen szolgáinak titkait. Hatoljatok be és intézzétek el őket.",Bene. Blackbird continuerà ad essere la tua guida. Sembra ti abbia preso in simpatia. Insieme dovrete scoprire i segreti dell'Ordine e dei loro servi inumani. Bisognerà infiltrarlo e distruggerlo.,"よし、君のガイドをブラックバードが今後務める 彼女は君に感心しているようだぞ。 君達の二人で、オーダーとその人間離れした 手下たちが持っている秘密を暴いてもらいたい。 奴等の基地に潜り込んで、倒すんだ。","좋군요. 블랙버드가 당신에게 지시를 계속 내려줄 겁니다. 당신을 꽤 신뢰하는 듯하더군요. 우리는 오더와 그들의 잔혹한 심복들의 실체를 파헤치고 폭로할 겁니다. 비밀을 헤집고 그들을 몰락시켜 버리세요. - \cy듣기만 해도 꿈에 그리던 일만 같네, 그렇지?","Goed, Blackbird zal je gids blijven. Ze heeft een behoorlijke glans aan je genomen. Samen moeten jullie de geheimen van de Orde en hun onmenselijke dienaren ontrafelen. Ga naar binnen en haal ze naar beneden.","Dobrze, Blackbird dalej będzie twoją przewodniczką. Chyba przepada za tobą. Wspólnie musicie odkryć sekrety zakonu i ich nieludzkich sług. Idź tam i załatw ich.",Ótimo. Blackbird continuará sendo a sua guia. Parece que ela vai com a sua cara. Juntos vocês desvendarão os segredos da Ordem e de seus discípulos desumanos. Entre lá e elimine eles.,,"Bun, Blackbird va fi ghidul tău în continuare. A luat ceva înteres în tine. Împreună trebuie să descoperiți secretele Ordinului și slujitorii lor inumani. Dați buzna ți puneții la pământ.",Хорошо. Чёрный дрозд останется твоим проводником. Она тебе несколько симпатизирует. Вместе вы раскроете секреты Ордена и его бесчеловечных слуг. Проникни на их территорию и ударь по ним как следует! , -Where do I start?,TXT_RPLY0_SCRIPT03_D4548_WHERE,,,,Kde mám začít?,Wo fange ich an?,,,¿Por dónde empiezo?,,,Où est-ce que je commence?,,,どこから始めればいいんだ?,어디서부터 시작하면 되죠?,Waar moet ik beginnen?,Gdzie zaczynam?,Por onde eu começo?,,Unde încep?,С чего мне начать?, -Frankly the situation is a mess. You must accomplish several missions to prepare the way for more attacks on the Order. Our last raid was a disaster and most of our troops were captured. I need you to free these prisoners.,TXT_DLG_SCRIPT03_D6064_FRANK,,,,"Upřímně, současná situace je úděsná. Musíš splnit několik misí před dalšími útoky na Řád. Náš poslední nájezd byla katastrofa a většina našich vojáků byla zajata. Potřebuju, abys tyto vězně vysvobodil.","Ehrlich gesagt, die Situation ist eine Sauerei. Du musst mehrere Aufgaben erfüllen um den Weg für weitere Angriffe vorzubereiten. Der letzte Überfall war ein Desaster und die meisten unserer Leute wurden gefangengenommen. Du musst sie wieder befreien.",,,Fráncamente la situación es un lío. Debes completar varias misiones para preparar el camino a más ataques contra la Orden. Nuestra última incursión fue un desastre y la mayoría de nuestras tropas fueron capturadas. Necesito que liberes a estos prisioneros.,,,"Franchement, nous sommes dans un bazar sans précédent. Vous devez accomplir de nombreuses missions pour préparer nos futures attaques contre l'Ordre. Notre dernier raid à été un désastre et la majorité de nos troupes ont été capturées. Il faut que vous les libérez.",,,"はっきり言えば、今の状況は全く良くない。 + \cy듣기만 해도 꿈에 그리던 일만 같네, 그렇지?","Goed, Blackbird zal je gids blijven. Ze heeft een behoorlijke glans aan je genomen. Samen moeten jullie de geheimen van de Orde en hun onmenselijke dienaren ontrafelen. Ga naar binnen en haal ze naar beneden.","Bra, Blackbird vil fortsette å være din guide. Hun har blitt ganske betatt av deg. Sammen må dere avsløre hemmelighetene til Ordenen og deres umenneskelige tjenere. Gå inn og ta dem.","Dobrze, Blackbird dalej będzie twoją przewodniczką. Chyba przepada za tobą. Wspólnie musicie odkryć sekrety zakonu i ich nieludzkich sług. Idź tam i załatw ich.",Ótimo. Blackbird continuará sendo a sua guia. Parece que ela vai com a sua cara. Juntos vocês desvendarão os segredos da Ordem e de seus discípulos desumanos. Entre lá e elimine eles.,,"Bun, Blackbird va fi ghidul tău în continuare. A luat ceva înteres în tine. Împreună trebuie să descoperiți secretele Ordinului și slujitorii lor inumani. Dați buzna ți puneții la pământ.",Хорошо. Чёрный дрозд останется твоим проводником. Она тебе несколько симпатизирует. Вместе вы раскроете секреты Ордена и его нечеловеческих слуг. Проникни туда и покончи с ними! ,,"Bra, Blackbird kommer att fortsätta att vara din guide. Hon har blivit ganska förtjust i dig. Tillsammans måste ni avslöja hemligheterna om Orden och deras omänskliga tjänare. Gå in och ta ner dem.","Güzel, Karatavuk rehberiniz olmaya devam edecek. Senden oldukça hoşlandı. Birlikte Tarikat'ın ve insanlık dışı hizmetkârlarının sırlarını çözmelisiniz. İçeri gir ve onları alaşağı et." +Where do I start?,TXT_RPLY0_SCRIPT03_D4548_WHERE,〃,,,Kde mám začít?,Hvor skal jeg begynde?,Wo fange ich an?,,Kie mi komencu?,¿Por dónde empiezo?,,Mistä aloitan?,Où est-ce que je commence?,Hol kezdjem?,Da dove comincio?,どこから始めればいいんだ?,어디서부터 시작하면 되죠?,Waar moet ik beginnen?,Hvor skal jeg begynne?,Gdzie zaczynam?,Por onde eu começo?,,Unde încep?,С чего мне начать?,,Var börjar jag?,Nereden başlayacağım? +Frankly the situation is a mess. You must accomplish several missions to prepare the way for more attacks on the Order. Our last raid was a disaster and most of our troops were captured. I need you to free these prisoners.,TXT_DLG_SCRIPT03_D6064_FRANK,〃 (Prison mission),,,"Upřímně, současná situace je úděsná. Musíš splnit několik misí před dalšími útoky na Řád. Náš poslední nájezd byla katastrofa a většina našich vojáků byla zajata. Potřebuju, abys tyto vězně vysvobodil.","Helt ærligt, situationen er et rod. Du skal udføre flere missioner for at bane vejen for flere angreb på Ordenen. Vores sidste angreb var en katastrofe, og de fleste af vores tropper blev taget til fange. Jeg har brug for, at du befrier disse fanger.","Ehrlich gesagt, die Situation ist eine Sauerei. Du musst mehrere Aufgaben erfüllen um den Weg für weitere Angriffe vorzubereiten. Der letzte Überfall war ein Desaster und die meisten unserer Leute wurden gefangengenommen. Du musst sie wieder befreien.",,"Sincere la situacio estas malordo. Vi devas plenumi diversajn misiojn, por ke ni povu prepari pliajn atakojn kontraŭ La Ordeno. Ni malvenkis la lastan kaj tial La Ordeno kaptis la plimulton de niaj trupoj; mi bezonas, ke vi liberigu ilin.","La situación es un lío, a decir verdad. Debes completar varias misiones para poder preparar más ataques contra La Orden. Nuestra última incursión fue un desastre y la mayoría de nuestras tropas fueron capturadas; necesito que las liberes.",,"Rehellisesti sanoen tilanne on sekasortoinen. Sinun on suoritettava lukuisia tehtäviä valmistaaksesi tien lisähyökkäyksille Veljeskuntaa vastaan. Viimeisin hyökkäyksemme oli katastrofi, ja suurin osa joukoistamme vangittiin. Tarvitsen sinua vapauttamaan nämä vangit.","Franchement, nous sommes dans un bazar sans précédent. Vous devez accomplir de nombreuses missions pour préparer nos futures attaques contre l'Ordre. Notre dernier raid à été un désastre et la majorité de nos troupes ont été capturées. Il faut que vous les libérez.","Őszintén szólva a szituáció elég zűrzavaros. Több küldetést is véghez kell vinned, hogy előkészítsd a támadás következő hullámát a Rend ellen. A legutolsó portyánk egy óriási kudarc volt, és a legtöbb egységünket elfogták. Ki kell, hogy engedd őket!","Francamente, la situazione è critica. Dovrai completare diverse missioni per far si da poter preparare nuovi attacchi contro l'Ordine. La nostra ultima incursione è stata in disastro, e la maggiorparte delle nostre truppe sono state catturate. Ho bisogno che tu liberi questi prigionieri.","はっきり言えば、今の状況は全く良くない。 君は複数の任務をこなし、オーダーへの 攻撃態勢を整える必要がある。 我々が行ったこの前の襲撃は大失敗で、 ほとんどの兵たちは捕らえられてしまった。 君にはその捕らえられた者たちを -救助してもらいたい。","애석하게도, 현재 상황은 엉망입니다. 우리가 오더를 공습하기 전에 당신이 수행해야 할 일이 몇 가지 있습니다. 몇 주 전 공습은 비참한 결과로 끝났고, 대부분의 병사가 감금당했습니다. 그들을 풀어주어야만 합니다.",Eerlijk gezegd is de situatie een puinhoop. Je moet verschillende missies volbrengen om de weg te bereiden voor meer aanvallen op de Orde. Onze laatste inval was een ramp en de meeste van onze troepen werden gevangen genomen. Ik heb je nodig om deze gevangenen te bevrijden.,"Szczerze to mamy tu bałagan. Musisz ukończyć kilka misji, by przygotować drogę na więcej ataków na Zakon. Nasz ostatni nalot był porażką i większość naszych żołnierzy została złapana. Potrzebuję cię, byś uwolnił tych więźniów.",Sinceramente a situação é uma bagunça. Você precisa cumprir algumas missões para preparar o caminho para mais ataques contra a Ordem. Nossa última invasão foi um desastre e muitas das nossas tropas foram capturadas. Preciso que você liberte esses prisioneiros.,,Sincer situația e nasoală. Trebuie să îndepliniți câteva misiune pentru a pregătii calea pentru mai multe atacuri asupra Ordinului. Ultimul nostru raid a fost un dezastru și majoritatea trupelor noastre au fost capturate. Am nevoie ca voi să eliberați prizonierii.,"Честно говоря, наши дела идут не лучшим образом. Тебе предстоит выполнить несколько заданий, чтобы подготовить почву для дальнейших атак на Орден. Наша последняя вылазка обернулась катастрофой, и большинство наших бойцов были схвачены. Мне нужно, чтобы ты освободил их.", -I think I can handle it.,TXT_RPLY0_SCRIPT03_D6064_ITHIN,,,,"Myslím, že to zvládnu.","Ich denke, das kann ich schaffen.",,,Creo que puedo hacerlo.,,,Je pense pouvoir m'en occuper.,,,俺ならできるはずだ。,아마도 제가 할 수 있을 것 같군요.,Ik denk dat ik het aankan.,"Myślę, że dam sobie z tym radę.",Acho que eu posso dar conta disso.,,Cred că mă pot descurca.,"Думаю, справлюсь.", -"Take this money and visit Irale who supplies our weapons. Then, this key will get you in to see the Governor. He's a corrupt puppet of the Order, but he loves to make deals. Do whatever you need to free our brothers in arms.",TXT_DLG_SCRIPT03_D7580_TAKET,,,,"Vem si tohle zlato a navštiv Iraleho, který nás zásobuje zbraněmi. Tento klíč tě pak dostane ke guvernérovi. Je to jen zkorumpovaná loutka Řádu, ale zbožňuje nabídky. Udělej cokoliv je třeba, abys osvobodil naše bratry ve zbrani.","Nimm das Geld hier und geh zu Irale, der und mit Waffen versorgt. Und dieser Schlüssel erlaubt die Zutritt zum Haus des Gouverneurs. Er ist eine korrupte Marionette des Ordens aber er liebt es, Deals zu machen. Mach was nötig ist um unsere Waffenbrüder zu befreien.",,,"Toma este dinero y ve a ver a Irale, que suministra nuestras armas. Después, esta llave te servirá para ver al gobernador. Es una marioneta corrupta de la Orden, pero le encantan los tratos. Haz lo que creas necesario para liberar a nuestros compatriotas.",,,Prenez cet argent et allez voir Irale qui nous approvisionne en armes. Utilisez ensuite cette clé pour aller voir le gouverneur. Il est un pantin de l'Ordre mais il adore faire affaires. Faites ce qu'il faut pour libérer nos compatriotes.,,,"この金で、我らの武器を調達してくれている +救助してもらいたい。","애석하게도, 현재 상황은 엉망입니다. 우리가 오더를 공습하기 전에 당신이 수행해야 할 일이 몇 가지 있습니다. 몇 주 전 공습은 비참한 결과로 끝났고, 대부분의 병사가 감금당했습니다. 그들을 풀어주어야만 합니다.",Eerlijk gezegd is de situatie een puinhoop. Je moet verschillende missies volbrengen om de weg te bereiden voor meer aanvallen op de Orde. Onze laatste inval was een ramp en de meeste van onze troepen werden gevangen genomen. Ik heb je nodig om deze gevangenen te bevrijden.,"Ærlig talt er situasjonen et rot. Du må utføre flere oppdrag for å bane vei for flere angrep på Ordenen. Vårt siste angrep var en katastrofe, og de fleste av våre tropper ble tatt til fange. Du må befri disse fangene.","Szczerze to mamy tu bałagan. Musisz ukończyć kilka misji, by przygotować drogę na więcej ataków na Zakon. Nasz ostatni nalot był porażką i większość naszych żołnierzy została złapana. Potrzebuję cię, byś uwolnił tych więźniów.",Sinceramente a situação é uma bagunça. Você precisa cumprir algumas missões para preparar o caminho para mais ataques contra a Ordem. Nossa última invasão foi um desastre e muitas das nossas tropas foram capturadas. Preciso que você liberte esses prisioneiros.,,Sincer situația e nasoală. Trebuie să îndepliniți câteva misiune pentru a pregătii calea pentru mai multe atacuri asupra Ordinului. Ultimul nostru raid a fost un dezastru și majoritatea trupelor noastre au fost capturate. Am nevoie ca voi să eliberați prizonierii.,"Честно говоря, наши дела идут не лучшим образом. Тебе предстоит выполнить несколько заданий, чтобы подготовить почву для дальнейших атак на Орден. Наша последняя вылазка обернулась катастрофой, и большинство наших бойцов были схвачены. Мне нужно, чтобы ты освободил их.",,Ärligt talat är situationen en enda röra. Du måste utföra flera uppdrag för att bereda vägen för fler attacker mot Orden. Vår senaste räd var en katastrof och de flesta av våra trupper blev tillfångatagna. Jag behöver dig för att befria dessa fångar.,Açıkçası durum tam bir karmaşa. Tarikat'a daha fazla saldırının yolunu hazırlamak için birkaç görevi tamamlamalısınız. Son baskınımız bir felaketti ve askerlerimizin çoğu esir alındı. Bu esirleri serbest bırakmanı istiyorum. +I think I can handle it.,TXT_RPLY0_SCRIPT03_D6064_ITHIN,〃 (〃),,,"Myslím, že to zvládnu.","Jeg tror, jeg kan klare det.","Ich denke, das kann ich schaffen.",,"Mi pensas, ke mi povos fari tion.",Creo poder hacerlo.,,Eiköhän se onnistu.,Je pense pouvoir m'en occuper.,Azt hiszem el tudom intézni.,Penso di potercela fare.,俺ならできるはずだ。,아마도 제가 할 수 있을 것 같군요.,Ik denk dat ik het aankan.,Jeg tror jeg kan klare det.,"Myślę, że dam sobie z tym radę.",Acho que eu posso dar conta disso.,,Cred că mă pot descurca.,"Думаю, справлюсь.",,Jag tror att jag klarar av det.,Sanırım ben halledebilirim. +"Take this money and visit Irale who supplies our weapons. Then, this key will get you in to see the Governor. He's a corrupt puppet of the Order, but he loves to make deals. Do whatever you need to free our brothers in arms.",TXT_DLG_SCRIPT03_D7580_TAKET,〃 (〃),,,"Vem si tohle zlato a navštiv Iraleho, který nás zásobuje zbraněmi. Tento klíč tě pak dostane ke guvernérovi. Je to jen zkorumpovaná loutka Řádu, ale zbožňuje nabídky. Udělej cokoliv je třeba, abys osvobodil naše bratry ve zbrani.","Tag disse penge og besøg Irale, som leverer vores våben. Så vil denne nøgle give dig adgang til guvernøren. Han er en korrupt marionet af Ordenen, men han elsker at lave aftaler. Gør hvad du skal gøre for at befri vores våbenbrødre.","Nimm das Geld hier und geh zu Irale, der und mit Waffen versorgt. Und dieser Schlüssel erlaubt die Zutritt zum Haus des Gouverneurs. Er ist eine korrupte Marionette des Ordens aber er liebt es, Deals zu machen. Mach was nötig ist um unsere Waffenbrüder zu befreien.",,"Prenu ĉi tiun monon kaj renkontu Irale-n, la provizanto de niaj armiloj. Poste ĉi tiu ŝlosilo ebligos al vi renkonti la registon. Li estas koruptita marioneto de La Ordeno, sed li ŝategas intertraktadojn. Faru tion ajn, kion vi bezonas por liberigi niajn soldatojn.","Toma este dinero y ve a ver a Irale, que suministra nuestras armas. Después, esta llave te servirá para ver al gobernador. Es una marioneta corrupta de La Orden, pero le encantan los tratos. Haz lo que creas necesario para liberar a nuestros conmilitones.","Toma este dinero y ve a ver a Irale, que suministra nuestras armas. Después, esta llave te va a servir para ver al gobernador. Es una marioneta corrupta de La Orden, pero le encantan los tratos. Haz lo que creas necesario para liberar a nuestros conmilitones.","Ota tästä rahaa ja käväise Iralen luona, joka toimittaa meidän aseemme. Sitten tällä avaimella pääset tapaamaan kuvernööriä. Hän on Veljeskunnan läpimätä sätkynukke, mutta hän rakastaa tehdä kauppoja. Tee kaikkesi vapauttaaksesi aseveljemme.",Prenez cet argent et allez voir Irale qui nous approvisionne en armes. Utilisez ensuite cette clé pour aller voir le gouverneur. Il est un pantin de l'Ordre mais il adore faire affaires. Faites ce qu'il faut pour libérer nos compatriotes.,"Fogd ezt a pénzt, és látogasd meg Irale-t a fegyverellátónkat. Azután, ezzel a kulccsal be tudsz jutni a kormányzóhoz. Ő a Rend egy korrupt bábja, de imád üzletet kötni. Tegyél meg mindent, hogy kiszabadítsd a bajtársainkat.","Prendi questo denaro e vai da Irale, uno dei nostri fornitori d'armi. Dopodiché, con questa chiave potrai entrare nella dimora del governatore. È un pupazzo corrotto dell'Ordine, ma adora trattare sottobanco. Fai tutto il necessario per liberare i nostri compagni d'arme.","この金で、我らの武器を調達してくれている イラールの元を訪ねて行け。 その次に、この鍵を使って知事に会え。 知事はオーダーの腐敗した傀儡だが取引には 興味を持ってくれる。我々の仲間を助けるために どんな手でも使ってくれ。","이 돈을 가지고 마을의 무기상인 이롤리를 찾아가시길 바랍니다. 그리고 이 열쇠만 있으면 모렐 총독을 쉽게 만날 수 있을 겁니다. 그는 부패한 오더의 앞잡이지만, 거래에 미쳐있죠. 우리 요원들을 풀어줄 무슨 수단이든 강구해 보시길. - \cy그리고 내가 너와 함께 있어 줄께.","Neem dit geld en bezoek Irale die onze wapens levert. Dan zal deze sleutel je naar binnen brengen om de Gouverneur te zien. Hij is een corrupte marionet van de Orde, maar hij houdt ervan om deals te sluiten. Doe alles wat je nodig hebt om onze broeders te bevrijden.","Weź te pieniądze i idź do Irale, który dostarcza nam bronie. Potem, ten klucz pozwoli ci spotkać się z Gubernatorem. Jest on skorumpowaną marionetką Zakonu, ale lubi robić interesy. Rób co musisz by uwolnić naszych towarzyszy broni.","Pegue este dinheiro e visite o Irale, nosso fornecedor de armas. Depois use esta chave para entrar e falar com o Governador. Ele é um fantoche corrupto da Ordem mas ele adora negociar. Faça o que for necessário para libertar os nossos irmãos de armas.",,"Ia acești bani și vizitează pe Irale, cel care ne aprovizionează cu arme. Apoi, cheia asta îți va permite să intri să îl vezi pe Guvernator. El este o marionetă coruptă a Ordinului, dar adoră să facă târguri. Fă orice e necesar pentru a ne putea elibera frații.","Возьми эти деньги и посети Ирэйла, нашего поставщика оружия. Затем, с этим ключом, ты пройдёшь к губернатору. Он — продажная марионетка Ордена, но обожает торговаться. Делай всё, что сочтёшь нужным, но освободи наших братьев по оружию.", -I'll see to it.,TXT_RPLY0_SCRIPT03_D7580_ILLSE,,,,Dohlédnu na to.,"Ich seh, was ich machen kann.",,,Veré que hacer.,,,Je m'y attelle.,,,了解した。,한 번 확인하러 가보겠습니다.,Ik zal ervoor zorgen.,Zajmę się tym.,Vou dar um jeito nisso.,,O să mă ocup.,Я позабочусь об этом., -Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT03_D9096_FIGHT,,,,Bojuj za Frontu a svobodu! Odchod.,Kämpfe für die Front und die Freiheit. Nun geh.,,,Lucha por el frente y la libertad. En marcha.,,,Battez vous pour le Front et pour la liberté. Repos.,,,フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het Front en vrijheid. Verhuizen.,Walcz dla Frontu i wolności. Wykonać.,Lute pela Frente e pela liberdade. Agora vá.,,Luptă pentru Front și libertate. Acum pleacă.,Сражайся за свободу и справедливость. Вперёд., -"The prisoners have been welcomed back, thanks to you. Here's some gold, go visit the medic and the weapons trainer and then, I have higher goals for you.",TXT_DLG_SCRIPT03_D10612_THEPR,,,,"Vězni byli přivítáni zpět, díky tobě. Tady je nějaké zlato, jdi navštívit zdravotníka a zbraňmistra, a pak mám pro tebe vyšší cíle.","Die Gefangenen sind zu uns zrückgekehrt, dank dir. Hier hast du etwas Gold, schau mal beim Sanitäter und beim Waffentrainer rein, danach sind höhere Ziele in Aussicht.",,,"Los prisioneros han sido bienvenidos de vuelta, gracias a ti. Aquí tienes algo de oro, ve a ver al médico y al entrenador de armamento y después, tengo mayores metas para ti.",,,"Les prisonniers sont revenus à bon port, grâce à vous. Voici de l'argent, allez voir le médecin et le maître d'armes, puis j'aurais d'autres missions pour vous.",,,"逃げ出した囚人たちを迎え入れた。 + \cy그리고 내가 너와 함께 있어 줄께.","Neem dit geld en bezoek Irale die onze wapens levert. Dan zal deze sleutel je naar binnen brengen om de Gouverneur te zien. Hij is een corrupte marionet van de Orde, maar hij houdt ervan om deals te sluiten. Doe alles wat je nodig hebt om onze broeders te bevrijden.","Ta disse pengene og besøk Irale som leverer våpnene våre. Med denne nøkkelen kommer du inn til guvernøren. Han er en korrupt nikkedukke for Ordenen, men han elsker å inngå avtaler. Gjør det du må for å befri våre våpenbrødre.","Weź te pieniądze i idź do Irale, który dostarcza nam bronie. Potem, ten klucz pozwoli ci spotkać się z Gubernatorem. Jest on skorumpowaną marionetką Zakonu, ale lubi robić interesy. Rób co musisz by uwolnić naszych towarzyszy broni.","Pegue este dinheiro e visite o Irale, nosso fornecedor de armas. Depois use esta chave para entrar e falar com o Governador. Ele é um fantoche corrupto da Ordem mas ele adora negociar. Faça o que for necessário para libertar os nossos irmãos de armas.",,"Ia acești bani și vizitează pe Irale, cel care ne aprovizionează cu arme. Apoi, cheia asta îți va permite să intri să îl vezi pe Guvernator. El este o marionetă coruptă a Ordinului, dar adoră să facă târguri. Fă orice e necesar pentru a ne putea elibera frații.","Возьми эти деньги и посети Ирэйла, нашего поставщика оружия. Затем, с этим ключом, ты пройдёшь к губернатору. Он продажная марионетка Ордена, но обожает торговаться. Делай всё, что сочтёшь нужным, но освободи наших братьев по оружию.",,"Ta de här pengarna och besök Irale som levererar våra vapen. Sedan kommer den här nyckeln att ge dig tillträde till guvernören. Han är en korrupt marionett för Orden, men han älskar att göra affärer. Gör vad du behöver för att befria våra vapenbröder.","Bu parayı al ve silahlarımızı tedarik eden İrale'yi ziyaret et. Sonra, bu anahtar seni valiyi görmeye götürecek. Tarikat'ın yozlaşmış bir kuklasıdır ama anlaşma yapmayı sever. Silah arkadaşlarımızı serbest bırakmak için ne gerekiyorsa yap." +I'll see to it.,TXT_RPLY0_SCRIPT03_D7580_ILLSE,〃 (〃),,,Dohlédnu na to.,Jeg skal nok sørge for det.,"Ich seh, was ich machen kann.",,"Mi vidos tion, kion mi faru.",Veré qué hacer.,Voy a ver qué hacer.,Hoidan asian.,Je m'y attelle.,Megteszem.,Mi darò da fare.,了解した。,한 번 확인하러 가보겠습니다.,Ik zal ervoor zorgen.,Jeg skal sørge for det.,Zajmę się tym.,Vou dar um jeito nisso.,,O să mă ocup.,Я позабочусь об этом.,,Jag ska se till det.,Ben halledeceğim. +Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT03_D9096_FIGHT,〃 (〃),,,Bojuj za Frontu a svobodu! Odchod.,Kæmp for fronten og friheden. Af sted.,Kämpfe für die Front und die Freiheit. Nun geh.,,Bataladu pro la Fronto kaj libereco. Ekagu.,Pelea por el Frente y la libertad. En marcha.,,Taistele Rintaman ja vapauden puolesta. Liikkeelle mars.,Battez vous pour le Front et pour la liberté. Repos.,Együtt a Frontért és a szabadságért! Indulás!,"Lotta, per il Fronte e per la libertà! E ora, al lavoro.",フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het Front en vrijheid. Verhuizen.,Kjemp for Fronten og friheten. Av sted.,Walcz dla Frontu i wolności. Wykonać.,Lute pela Frente e pela liberdade. Agora vá.,,Luptă pentru Front și libertate. Acum pleacă.,Сражайся за свободу и справедливость. Выдвигайся.,,Kämpa för fronten och friheten. Gå ut.,Cephe ve özgürlük için savaşın. Dışarı çıkın. +"The prisoners have been welcomed back, thanks to you. Here's some gold, go visit the medic and the weapons trainer and then, I have higher goals for you.",TXT_DLG_SCRIPT03_D10612_THEPR,〃 (Crystal mission),,,"Vězně jsme, díky tobě, přivítali zpět. Tady je nějaké zlato, jdi navštívit zdravotníka a zbraňmistra. Pak mám pro tebe vyšší cíle.","Fangerne er blevet budt velkommen tilbage, takket være dig. Her er lidt guld, besøg lægen og våbentræneren, og så har jeg højere mål for dig.","Die Gefangenen sind zu uns zrückgekehrt, dank dir. Hier hast du etwas Gold, schau mal beim Sanitäter und beim Waffentrainer rein, danach sind höhere Ziele in Aussicht.",,"Ni povis rebonveni la ekskaptitojn danke al vi. Jen iom da oro; iru renkonti la kuraciston kaj la armilan trejniston, kaj tiam mi havas pli altajn celojn por vi.","Los prisioneros ya han sido bienvenidos de vuelta gracias a ti. Toma este oro, ve a ver al médico y al entrenador de armas, y después... tengo mayores metas para ti.","Los prisioneros ya fueron bienvenidos de vuelta gracias a ti. Toma este oro, ve a ver al médico y al entrenador de armas, y después... tengo mayores metas para ti.","Vangit on otettu takaisin vastaan, kiitos sinun. Tässä kultaa; mene tapaamaan lääkintämiestä ja asekouluttajaa, minkä jälkeen minulla on sinulle korkeampia tavoitteita.","Les prisonniers sont revenus à bon port, grâce à vous. Voici de l'argent, allez voir le médecin et le maître d'armes, puis j'aurais d'autres missions pour vous.","A foglyok visszatértek hála neked. Itt van valamennyi arany, látogasd meg a szanitécot és a fegyverkereskedőt, aztán térj vissza mert nagy céljaim vannak veled.","I prigionieri sono stati riportati sani e salvi, grazie a te. Ecco dell'oro. Visita il dottore e l'istruttore d'armi, e poi, ho altri obiettivi per te.","逃げ出した囚人たちを迎え入れた。 君の活躍に感謝する。幾つか報酬を与えよう。 それとメディックと訓練師も訪ねるといい、 -その後に頼みたいことがある。",감금된 병사들이 당신 덕에 다시 돌아왔습니다. 정말 감사드립니다! 이 보상을 받으시고 의무관이랑 무기 담당관을 찾아뵈시길 바랍니다. 또 다른 임무가 기다리고 있으니까요.,"De gevangenen zijn dankzij u weer welkom teruggekomen. Hier is wat goud, ga naar de dokter en de wapentrainer en dan heb ik hogere doelen voor je.","Więźniowie zostali ponownie powitani, wszystko dzięki tobie. Masz tu trochę złota, idź do medyka i instruktora broni, a potem powiem ci jakie większe zadania mam dla ciebie.","Recebemos os prisioneiros de volta, graças a você. Pegue este dinheiro, visite o médico, o treinador de armas e depois eu vou te dar uns objetivos mais importantes.",,"Prizonierii au fost primiți înapoi, mulțumită ție. Uite niște aur, vizitează medicul și antrenorul de arme, după aceea, am planuri mai mărețe pentru tine.","Благодаря тебе, пленники вернулись к нам. Вот немного золота. Посети медика и инструктора по стрельбе, а потом тебя ждут ещё более ответственные задания.", -I will. What's next?,TXT_RPLY0_SCRIPT03_D10612_IWILL,,,,Půjdu. Co dál?,"Alles klar, was gibt's als Nächstes?",,,Lo haré. ¿Qué es lo siguiente?,Lo haré. ¿Qué sigue?,,"Très bien, quoi maintenant?",,,次は何だ?,그렇군요. 그 다음은 뭐죠?,Dat zal ik doen. Wat is het volgende?,Dobrze. Co dalej?,Farei isso. Qual a próxima missão?,,Mă voi conforma. Ce facem mai departe?,Хорошо. Что дальше?, -"A single crystal runs the power grid which drives the Order's shields. Destroy that crystal and you will punch huge holes in the Order's defenses. Blackbird will lead you to a spy who has a way in, good luck.",TXT_DLG_SCRIPT03_D12128_ASING,,,,"Elektrická síť, kterou jsou poháněné štíty Řádu, je napájena z jednoho krystalu. Znič ten krystal a zasadíš obří ránu obranám Řádu. Straka tě navede ke špiónovi, který zná cestu dovnitř. Hodně štěstí.","Ein einziger Kristall kontrolliert das gesamte Energiesystem für die Kraftschilde des Ordens. Zerstöre diesen Kristall und du wirst riesige Löcher in die Verteidigungsanlagen des Ordens schlagen. Blackbird führt dich zu einem Spion, der dir Einlass verschaffen kann. Viel Glück.",,,"Un único cristal alimenta la red eléctrica que mantiene los escudos de la Orden. Destruye ese cristal y abrirás grandes brechas en las defensas de la Orden. Blackbird te guiará hacia un espía que tiene una forma de entrar, buena suerte.",,,Un seul cristal fait fonctionner la grille énergétique qui alimente les boucliers de l'Ordre. Détruisez ce cristal et vous créez des énormes failles dans les défenses de l'Ordre. Blackbird va vous mener à un espion qui a un moyen de vous faire rentrer. Bonne chance.,,,"とあるパワークリスタルがオーダー基地の +その後に頼みたいことがある。",감금된 병사들이 당신 덕에 다시 돌아왔습니다. 정말 감사드립니다! 이 보상을 받으시고 의무관이랑 무기 담당관을 찾아뵈시길 바랍니다. 또 다른 임무가 기다리고 있으니까요.,"De gevangenen zijn dankzij u weer welkom teruggekomen. Hier is wat goud, ga naar de dokter en de wapentrainer en dan heb ik hogere doelen voor je.","Fangene har blitt ønsket velkommen tilbake, takket være deg. Her er litt gull, gå og besøk saniteten og våpentreneren, og så har jeg høyere mål for deg.","Więźniowie zostali ponownie powitani, wszystko dzięki tobie. Masz tu trochę złota, idź do medyka i instruktora broni, a potem powiem ci jakie większe zadania mam dla ciebie.","Recebemos os prisioneiros de volta, graças a você. Pegue este dinheiro, visite o médico, o treinador de armas e depois eu vou te dar uns objetivos mais importantes.",,"Prizonierii au fost primiți înapoi, mulțumită ție. Uite niște aur, vizitează medicul și antrenorul de arme, după aceea, am planuri mai mărețe pentru tine.","Благодаря тебе, пленники вернулись к нам. Вот немного золота. Посети медика и инструктора по стрельбе, а потом тебя ждут ещё более ответственные задания.",,"Fångarna har välkomnats tillbaka, tack vare dig. Här är lite guld, besök läkaren och vapentränaren och sedan har jag högre mål för dig.","Sayende mahkumlar geri döndü. İşte biraz altın, sıhhiyeciyi ve silah eğitmenini ziyaret et ve sonra, senin için daha yüksek hedeflerim var." +I will. What's next?,TXT_RPLY0_SCRIPT03_D10612_IWILL,〃 (〃),,,Půjdu. Co dál?,Det vil jeg gøre. Hvad er det næste?,"Alles klar, was gibt's als Nächstes?",,Kompreneble. Kio sekvas?,Lo haré. ¿Qué sigue?,Claro. ¿Qué sigue?,Menen. Mitä seuraavaksi on luvassa?,"Très bien, quoi maintenant?",Így teszek. Mi a következő lépés?,Lo farò. Qual'è la prossima mossa?,次は何だ?,그렇군요. 그 다음은 뭐죠?,Dat zal ik doen. Wat is het volgende?,Det skal jeg gjøre. Hva er det neste?,Dobrze. Co dalej?,Farei isso. Qual a próxima missão?,,Mă voi conforma. Ce facem mai departe?,Хорошо. Что дальше?,,Det kommer jag att göra. Vad kommer härnäst?,Yapacağım. Sırada ne var? +"A single crystal runs the power grid which drives the Order's shields. Destroy that crystal and you will punch huge holes in the Order's defenses. Blackbird will lead you to a spy who has a way in, good luck.",TXT_DLG_SCRIPT03_D12128_ASING,〃 (〃),,,"Elektrická síť, kterou jsou poháněné štíty Řádu, je napájena z jednoho krystalu. Znič ten krystal a zasaď tak obří ránu obranám Řádu. Straka tě navede ke špiónovi, který zná cestu dovnitř. Hodně štěstí.","En enkelt krystal driver det kraftnet, der driver ordenens skjolde. Ødelæg det krystal, og du vil slå store huller i Ordenens forsvar. Blackbird vil føre dig til en spion, der har en vej ind, held og lykke.","Ein einziger Kristall kontrolliert das gesamte Energiesystem für die Kraftschilde des Ordens. Zerstöre diesen Kristall und du wirst riesige Löcher in die Verteidigungsanlagen des Ordens schlagen. Blackbird führt dich zu einem Spion, der dir Einlass verschaffen kann. Viel Glück.",,"Ununura kristalo nutras la elektrizan sistemon, kiu tenas la ŝildojn de la kastelo. Detruu ĝin por fari grandegan «breĉon» en la defendojn de La Ordeno. Merlo gvidos vin al spiono, kiu havas manieron eniri. Ŝancon.",Un único cristal alimenta la red eléctrica que mantiene los escudos del castillo. Destruye ese cristal para abrir grandes brechas en las defensas de La Orden. Blackbird te guiará hacia un espía que tiene una forma de entrar. Buena suerte.,Un único cristal alimenta la red eléctrica que mantiene los escudos del castillo. Destruye ese cristal para abrir grandes brechas en las defensas de La Orden. Blackbird te va a guiar hacia un espía que tiene una forma de entrar. Buena suerte.,"Kaupungin sähköverkon voimanlähteenä toimii yksittäinen kristalli, jonka voimaa Veljeskunnan kilvet käyttävät. Tuhoamalla kristallin puhkot valtavia reikiä Veljeskunnan puolustuksiin. Blackbird opastaa sinut vakoojan luo, jolla on sisäänpääsykeino. Lykkyä tykö.",Un seul cristal fait fonctionner la grille énergétique qui alimente les boucliers de l'Ordre. Détruisez ce cristal et vous créez des énormes failles dans les défenses de l'Ordre. Blackbird va vous mener à un espion qui a un moyen de vous faire rentrer. Bonne chance.,"Egyetlen krisztály hajtja az energia hálózatot, erre van rákötve a Rend pajzsa. Semmisítsd meg ezt a kristályt, és hatalmas lyukakat fogsz vágni a Rend védelmébe. Feketerigó elvezet egy spionhoz, aki tudja hogyan kell bejutni, sok sikert.","Un singolo cristallo alimenta l'impianto energetico che controlla gli scudi dell'Ordine. Distruggendo quel cristallo causerai enormi danni alle difese dell'Ordine. Blackbird ti porterà da una spia che ha indicazioni su come accedere al cristallo, buona fortuna.","とあるパワークリスタルがオーダー基地の シールドを維持している。それを破壊して 奴等の防壁に巨大な穴を開けるのだ。 潜入する為の情報を持ったスパイを ブラックバードが導いてくれる。","오더의 방어막을 생성하는 수정체가 그들의 발전소 안에 있습니다. 그것을 파괴할 수만 있다면, 오더의 방어 체계를 약화할 수 있을 겁니다. 블랙버드가 길을 알려줄 첩자의 위치를 알려줄 것입니다. 건투를 빌어요. - \cy워너는 우리가 모집한 첩자야. 그는 발전소 창고에 있어.","Een enkel kristal loopt over het elektriciteitsnet dat de schilden van de Orde aandrijft. Vernietig dat kristal en je zult grote gaten slaan in de verdediging van de Orde. Blackbird leidt je naar een spion die een weg naar binnen heeft, veel geluk.","Pojedynczy kryształ napędza sieć energetyczną, która zasila osłony Zakonu. Zniszcz kryształ, a Zakon będzie miał ogromne luki w ochronie. Blackbird zaprowadzi cię do szpiega, który ma sposób, aby się tam dostać, powodzenia.",Há um cristal que fornece energia à rede elétrica que mantém os escudos da Ordem em funcionamento. Destrua esse cristal e você abrirá brechas grandes nas defesas da Ordem. Blackbird guiará você a um espião que sabe como entrar lá. Boa sorte.,,"Un cristal unic alimentează grila de putere care acționează scuturile Ordiului. Distruge cristalul și veți provoca daune imense sistemului de apărare al Ordinului. Blackbird vă va introduce unui spion care să vă ofere o cale în interior, multă baftă.","Энергосеть, которая питает щиты Ордена, работает от одного кристалла. Уничтожь этот кристалл, и ты пробьёшь огромную брешь в их обороне. Чёрный дрозд приведёт тебя к шпиону, который знает, как проникнуть на станцию. Удачи!", -We'll get it.,TXT_RPLY0_SCRIPT03_D12128_WELLG,,,,Dostaneme ho.,Das werden wir hinkriegen.,,,Lo conseguiremos.,,,Je m'en occupe.,,,すぐ始めよう。,그 수정체를 파괴하겠습니다.,We krijgen het wel.,Poradzimy sobie.,Vamos conseguir.,,Vom ajunge în interior.,Мы справимся., -Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT03_D13644_FIGHT,,,,Bojuj za Frontu a svobodu! Odchod.,Kämpfe für die Front und die Freiheit. Nun geh.,,,Lucha por el frente y la libertad. En marcha.,,,Battez vous pour le Front et pour la liberté. Repos.,,,フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het front en vrijheid. Verhuizen.,Walcz dla Frontu i wolności. Wykonać.,Lute pela Frente e pela liberdade. Agora vá.,,Luptați pentru Front și libertate. Acum plecați.,Сражайся за свободу и справедливость. Вперёд., -"You've exceeded all of our expectations. Because of your daring our troops are on the move. I want you two to join the assault, with a specific target. Take out the Programmer. It's time to reveal what we've found out about this layer of the Order.",TXT_DLG_SCRIPT03_D15160_YOUVE,,,,"Překonal jsi všechny naše představy. Díky tvé odvaze se naše vojska vydala na pochod. Chci, abyste se vy dva připojili k útoku se zvláštním cílem. Zabijte Programátora. Je čas odhalit, co jsme se dozvěděli o Řádu.","Du hast alle unsere Erwartungen übertroffen. Dank dir sind unsere Truppen auf dem Vormarsch. Ich möchte, dass du auch an dem Angriff teilnimmst, aber mit einer Spezialmission. Eliminiere den Programmierer. Es ist Zeit zu enthüllen, was wir über dien Teil des Ordens herausgefunden haben.",,,"Has superado todas nuestras expectativas. Por tú hazaña nuestras tropas están en movimiento. Quiero que los dos os unais al asalto, con un objetivo específico. Acabar con el Programador. Es hora de revelar lo que hemos encontrado de esta capa de la Orden.","Has superado todas nuestras expectativas. Por tú hazaña nuestras tropas están en movimiento. Quiero que ambos se unan al asalto, con un objetivo específico. Acabar con el Programador. Es hora de revelar lo que hemos encontrado de esta capa de la Orden.",,"Vous avez dépassé toutes nos attentes. Grâce à votre audace, nos troupes sont sur le pied de guerre. Je que vous rejoignez l'assaut tous les deux, avec une cible précise. Eliminez le Programmeur. Il est l'heure de révéler ce que nous avons découvert sur cette facette de l'Ordre.",,,"君達は我々の期待を超える活躍を行ってくれた。 + \cy워너는 우리가 모집한 첩자야. 그는 발전소 창고에 있어.","Een enkel kristal loopt over het elektriciteitsnet dat de schilden van de Orde aandrijft. Vernietig dat kristal en je zult grote gaten slaan in de verdediging van de Orde. Blackbird leidt je naar een spion die een weg naar binnen heeft, veel geluk.","En enkelt krystall driver kraftnettet som driver Ordenens skjold. Ødelegg den krystallen, og du vil slå store hull i Ordenens forsvar. Blackbird vil føre dere til en spion som har en vei inn. Lykke til.","Pojedynczy kryształ napędza sieć energetyczną, która zasila osłony Zakonu. Zniszcz kryształ, a Zakon będzie miał ogromne luki w ochronie. Blackbird zaprowadzi cię do szpiega, który ma sposób, aby się tam dostać, powodzenia.",Há um cristal que fornece energia à rede elétrica que mantém os escudos da Ordem em funcionamento. Destrua esse cristal e você abrirá brechas grandes nas defesas da Ordem. Blackbird guiará você a um espião que sabe como entrar lá. Boa sorte.,,"Un cristal unic alimentează grila de putere care acționează scuturile Ordiului. Distruge cristalul și veți provoca daune imense sistemului de apărare al Ordinului. Blackbird vă va introduce unui spion care să vă ofere o cale în interior, multă baftă.","Энергосеть, которая питает щиты Ордена, работает от одного кристалла. Уничтожь этот кристалл, и ты пробьёшь огромную брешь в их обороне. «Чёрный дрозд» приведёт тебя к шпиону, который знает, как проникнуть на станцию. Удачи!",,"En enda kristall driver kraftnätet som driver ordens sköldar. Förstör den kristallen och du kommer att slå enorma hål i ordens försvar. Blackbird kommer att leda dig till en spion som har en väg in, lycka till.","Tarikat'ın kalkanlarını çalıştıran güç şebekesini tek bir kristal çalıştırıyor. O kristali yok edersen Tarikat'ın savunmasında büyük delikler açacaksın. Karatavuk seni içeri girmenin bir yolunu bulan bir casusa götürecek, iyi şanslar." +We'll get it.,TXT_RPLY0_SCRIPT03_D12128_WELLG,〃 (〃),,,Zničíme jej.,Vi skal nok få fat i den.,Das werden wir hinkriegen.,,Ni sukcesos.,Lo conseguiremos.,Lo vamos a lograr.,Saamme sen.,Je m'en occupe.,Megszerezzük.,Ce la faremo.,すぐ始めよう。,그 수정체를 파괴하겠습니다.,We krijgen het wel.,Vi får tak i den.,Poradzimy sobie.,Vamos conseguir.,,Vom ajunge în interior.,Мы справимся.,,Vi kommer att hitta den.,Onu yakalayacağız. +Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT03_D13644_FIGHT,〃 (〃),,,Bojuj za Frontu a svobodu! Odchod.,Kæmp for fronten og friheden. Af sted.,Kämpfe für die Front und die Freiheit. Nun geh.,,Bataladu pro la Fronto kaj libereco. Ekagu.,Pelea por el Frente y la libertad. En marcha.,,Taistele Rintaman ja vapauden puolesta. Liikkeelle mars.,Battez vous pour le Front et pour la liberté. Repos.,Együtt a Frontért és a szabadságért! Indulás!,"Lotta, per il Fronte e per la libertà! E ora, al lavoro.",フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het front en vrijheid. Verhuizen.,Kjemp for Fronten og friheten. Av sted.,Walcz dla Frontu i wolności. Wykonać.,Lute pela Frente e pela liberdade. Agora vá.,,Luptați pentru Front și libertate. Acum plecați.,Сражайся за свободу и справедливость. Выдвигайся.,,Kämpa för fronten och friheten. Gå ut.,Cephe ve özgürlük için savaşın. Çıkın. +"You've exceeded all of our expectations. Because of your daring our troops are on the move. I want you two to join the assault, with a specific target. Take out the Programmer. It's time to reveal what we've found out about this layer of the Order.",TXT_DLG_SCRIPT03_D15160_YOUVE,〃 (Progammer mission),,,"Překonal jsi všechny naše představy. Díky tvé odvaze se naše vojska vydala na pochod. Chci, abyste se vy dva připojili k útoku se zvláštním cílem: zabít Programátora. Je čas odhalit, co jsme se dozvěděli o Řádu.","Du har overgået alle vores forventninger. På grund af jeres mod er vores tropper på vej. Jeg vil have jer to til at deltage i angrebet, med et specifikt mål. Udrydd programmereren. Det er tid til at afsløre, hvad vi har fundet ud af om dette lag af Ordenen.","Du hast alle unsere Erwartungen übertroffen. Dank dir sind unsere Truppen auf dem Vormarsch. Ich möchte, dass du auch an dem Angriff teilnimmst, aber mit einer Spezialmission. Eliminiere den Programmierer. Es ist Zeit zu enthüllen, was wir über dien Teil des Ordens herausgefunden haben.",,"Vi superis ĉiujn niajn atendojn. Pro viaj heroaĵoj, niaj trupoj jam ekagis. Mi volas, ke vi ambaŭ aliĝu al la sturmo kun specifa celo: mortigi La Programiston. Estas tempo malkaŝi tion, kion ni malkovris pri tiu aspekto de La Ordeno.",Has superado todas nuestras expectativas. Por tu hazaña nuestras tropas ya están en movimiento. Quiero que los dos os unáis al asalto con un objetivo específico: acabar con el Programador. Ya es hora de revelar lo que hemos descubierto sobre ese lado de La Orden.,Superaste todas nuestras expectativas. Por tu hazaña nuestras tropas ya están en movimiento. Quiero que los dos se unan al asalto con un objetivo específico: matar al Programador. Ya es hora de revelar lo que descubrimos sobre ese lado de La Orden.,"Olet ylittänyt kaikki odotuksemme. Rohkeutesi ansiosta joukkomme ovat liikkeellä. Haluan teidän molempien osallistuvan hyökkäykseen erityistehtävällä: Tuhotkaa Ohjelmoitsija. On aika paljastaa, mitä olemme saaneet selville Veljeskunnan tästä kerroksesta.","Vous avez dépassé toutes nos attentes. Grâce à votre audace, nos troupes sont sur le pied de guerre. Je que vous rejoignez l'assaut tous les deux, avec une cible précise. Eliminez le Programmeur. Il est l'heure de révéler ce que nous avons découvert sur cette facette de l'Ordre.",Túltettetek az elvárásaimon. Merész tetteitek inspirálóan hatottak katonáinkra. Mindkettőtöket szánok egy speciális feladatot a roham során. Iktassátok ki a Programozót. Ideje világosságra hozni amit találtunk a Rend ezen ágáról.,"Hai superato tutte le nostre aspettative. Grazie al vostro coraggio, le nostre truppe sono in movimento. Voglio che voi due vi uniate all'assalto, con un obiettivo specifico. Elimina il Programmatore. È giunto il momento di rivelare quello che abbiamo scoperto di questo strato dell'Ordine.","君達は我々の期待を超える活躍を行ってくれた。 君の勇猛さに私の部隊が動き出した。 今度は君達二人にある目的の為、強襲部隊に 加わって欲しい。プログラマーを討ち取るのだ。 オーダーに纏わる様々な事情について -明らかにする時が来た。",당신의 성과는 우리가 예상했던 것보다 훨씬 굉장하더군요. 당신의 노고 덕에 이제 우리가 활동을 본격적으로 개시할 수 있게 되었습니다. 자네와 블랙버드가 이번 공격에 참여했으면 합니다. 그리고 프로그래머를 없애버리세요. 지금이야말로 오더의 실체가 어떠한지를 폭로할 절호의 기회입니다.,"Je hebt al onze verwachtingen overtroffen. Door jouw durf zijn onze troepen in beweging. Ik wil dat jullie twee zich bij de aanval aansluiten, met een specifiek doelwit. Schakel de programmeur uit. Het is tijd om te onthullen wat we hebben ontdekt over deze laag van de Orde.","Przekroczyłeś nasze wszelkie oczekiwania. Dzięki twej odwadze nasi żołnierze są w drodze. Chciałbym, abyście razem dołączyli do szturmu, mając konkretny cel. Zabijcie Programistę. Czas pokazać co odkryliśmy na temat tego pionka Zakonu.","Você superou todas as nossas expectativas. Graças à sua audácia as nossas tropas estão em movimento. Quero que vocês dois participem do ataque, com um alvo específico. Elimine o Programador. Já está na hora de revelar o que descobrimos a respeito dessa parte da Ordem. ",,"Ne-ați depășit toate așteptările. Datorită îndrăznelii voastre trupele noastre s-au putut pune în mișcare. Vreau să vă alăturați asaltului, cu o țintă specifică. Eliminați-l pe Programator. E timpul să dezvăluim ce am descoperit despre acest nivel al Ordinului.","Ты превзошёл все наши ожидания. Благодаря твоей отваге, наши войска уже в пути. Я хочу, чтобы вы двое присоединились к атаке, с особой целью — уничтожить Программиста. Настало время рассказать всё, что мы смогли узнать об этом уровне власти в Ордене.", -Tell me what we know.,TXT_RPLY0_SCRIPT03_D15160_TELLM,,,,"Řekni mi, co víme.",Sag mir was du weißt.,,,Dime lo que sabemos.,,,Donnez-moi ce que vous savez.,,,こちらに知っている事を教えてくれ。,그 비밀에 대해서 알려주세요.,Vertel me wat we weten.,Powiedz co wiadomo.,Conte-me o que sabemos.,,Spune-mi ce știi.,Расскажи мне всё., -"The Programmer's lair is in the castle. Now, see the medic, grab some ammo and go get him.",TXT_DLG_SCRIPT03_D16676_THEPR,,,,"Programátorovo doupě je v hradu. Jdi navštívit zdravotníka, vem si munici a jdi ho dostat.",Der Programmierer hät sich irgendwo in der Burg auf. Und nun gehe bitter zum Sanitäter und beschaff dir neue Munition - und dann mach ihn fertig.,,,"La guarida del Programador está en el castillo. Ahora, ve a ver al médico, toma algo de munición y ve a por él.","La guarida del Programador está en el castillo. Ahora, ve a ver al médico, toma algo de munición y ve por él.",,"Le repaire du Programmeur est dans le château. Allez voir le médecin, rechargez vos armes, et allez vous occuper de lui.",,,"プログラマーの居場所は城内だ。それと、 +明らかにする時が来た。",당신의 성과는 우리가 예상했던 것보다 훨씬 굉장하더군요. 당신의 노고 덕에 이제 우리가 활동을 본격적으로 개시할 수 있게 되었습니다. 자네와 블랙버드가 이번 공격에 참여했으면 합니다. 그리고 프로그래머를 없애버리세요. 지금이야말로 오더의 실체가 어떠한지를 폭로할 절호의 기회입니다.,"Je hebt al onze verwachtingen overtroffen. Door jouw durf zijn onze troepen in beweging. Ik wil dat jullie twee zich bij de aanval aansluiten, met een specifiek doelwit. Schakel de programmeur uit. Het is tijd om te onthullen wat we hebben ontdekt over deze laag van de Orde.","Du har overgått alle våre forventninger. På grunn av deres dristighet er troppene våre i bevegelse. Jeg vil at dere to skal bli med på angrepet, med et spesifikt mål. Drep programmereren. Det er på tide å avsløre hva vi har funnet ut om dette laget av Ordenen.","Przekroczyłeś nasze wszelkie oczekiwania. Dzięki twej odwadze nasi żołnierze są w drodze. Chciałbym, abyście razem dołączyli do szturmu, mając konkretny cel. Zabijcie Programistę. Czas pokazać co odkryliśmy na temat tego pionka Zakonu.","Você superou todas as nossas expectativas. Graças à sua audácia as nossas tropas estão em movimento. Quero que vocês dois participem do ataque, com um alvo específico. Elimine o Programador. Já está na hora de revelar o que descobrimos a respeito dessa parte da Ordem. ",,"Ne-ați depășit toate așteptările. Datorită îndrăznelii voastre trupele noastre s-au putut pune în mișcare. Vreau să vă alăturați asaltului, cu o țintă specifică. Eliminați-l pe Programator. E timpul să dezvăluim ce am descoperit despre acest nivel al Ordinului.","Ты превзошёл все наши ожидания. Благодаря твоей отваге наши войска уже в пути. Я хочу, чтобы вы двое присоединились к атаке, с особой целью — уничтожить Программиста. Настало время рассказать всё, что мы смогли узнать об этом уровне власти в Ордене.",,"Du har överträffat alla våra förväntningar. På grund av er djärvhet är våra trupper på väg. Jag vill att ni två ansluter er till anfallet, med ett specifikt mål. Ta ut programmeraren. Det är dags att avslöja vad vi har kommit fram till om det här skiktet av Orden.","Tüm beklentilerimizi aştınız. Cesaretiniz sayesinde birliklerimiz harekete geçti. İkinizin saldırıya katılmanızı istiyorum, belirli bir hedefle. Programcıyı ortadan kaldırın. Tarikat'ın bu katmanı hakkında ne bulduğumuzu açıklamanın zamanı geldi." +Tell me what we know.,TXT_RPLY0_SCRIPT03_D15160_TELLM,〃 (〃),,,"Řekni mi, co víme.","Fortæl mig, hvad vi ved.",Sag mir was du weißt.,,"Diru tion, kion vi scias.",Dime lo que se sabe.,,"Kerro, mitä tiedämme.",Donnez-moi ce que vous savez.,Mondd el mit tudtunk meg.,Dimmi cosa sappiamo.,こちらに知っている事を教えてくれ。,그 비밀에 대해서 알려주세요.,Vertel me wat we weten.,Fortell meg hva vi vet.,Powiedz co wiadomo.,Conte-me o que sabemos.,,Spune-mi ce știi.,Расскажи мне всё.,,Berätta vad vi vet.,Bana ne bildiğimizi söyle. +"The Programmer's lair is in the castle. Now, see the medic, grab some ammo and go get him.",TXT_DLG_SCRIPT03_D16676_THEPR,〃 (〃),,,"Programátorovo doupě je v hradu. Jdi navštívit zdravotníka, vem si munici a jdi ho dostat.","Programmørens hule er i slottet. Gå hen til lægen, tag noget ammunition og hent ham.",Der Programmierer hät sich irgendwo in der Burg auf. Und nun gehe bitter zum Sanitäter und beschaff dir neue Munition - und dann mach ihn fertig.,,"La kaŝejo de la Programisto estas en la kastelo. Vi nun renkontu la kuraciston, prenu municiojn kaj iru mortigi lin.","La guarida del Programador está en el castillo. Ahora ve a ver al médico, coge munición y ve a por él.","La guarida del Programador está en el castillo. Ahora ve a ver al médico, toma munición y ve por él.","Ohjelmoitsijan piilopaikka on linnassa. Käy nyt tapaamassa lääkintämiestä, ota panoksia matkaan ja napatkaa hänet.","Le repaire du Programmeur est dans le château. Allez voir le médecin, rechargez vos armes, et allez vous occuper de lui.","A Programozó búvóhelye a kastélyban található. Látogasd meg a szanitécot, vegyél magadhoz egy kis ammot, és irány a kastély.","La tana del Programmatore è nel castello. Ora, fai una visita al medico, prendi un po' di munizione, e vallo a predendere.","プログラマーの居場所は城内だ。それと、 メディックと訓練士に会い弾薬を補給したら 奴を倒せ。","프로그래머가 거주하는 곳은 성채 안에 있습니다. 의무관과 무기 담당관을 찾아뵈서 준비를 당당히 하시길 바랍니다. - \cy일생일대의 격전에 대비해. 돈 아끼지 말고 있는 대로 다 써.","Het hol van de programmeur is in het kasteel. Ga nu naar de dokter, pak wat munitie en ga hem halen.","Kryjówka Programisty jest w zamku. Teraz idź do medyka, weź trochę amunicji i załatw go.","O covil do Programador fica no castelo. Agora vá ver o médico, pegue munição e vá atrás dele.",,"Bârlogul Programatorului e în castel. Acum, dute la medic, ia niște muniție, și prindeți-l.","Программист устроил себе логово в замке. Теперь проверь снаряжение, возьми всё, что тебе понадобится, и расправься с ним.", -Let me at 'em!,TXT_RPLY0_SCRIPT03_D16676_LETME,,,,Pusť mě na ně!,Lass mich das nur machen.,,,¡Voy a por ellos!,¡Voy por ellos!,,Je vais me le faire!,,,任せろ!,한 번 저질러 봅시다!,Laat me er naartoe gaan!,Niech ja go dorwę!,Pode deixar!,,Le voi arăta eu lor!,Я им покажу!, -Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT03_D18192_FIGHT,,,,Bojuj za Frontu a svobodu! Odchod.,Kämpfe für die Front und die Freiheit. Nun geh.,,,Lucha por el frente y la libertad. En marcha.,,,Battez vous pour le Front et pour la liberté. Repos.,,,フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het front en vrijheid. Verhuizen.,Walcz dla Frontu i wolności. Wykonać.,Lute pela Frente e pela liberdade. Agora vá.,,Luptă pentru Front și libertate. Acum pleacă.,Сражайся за свободу и справедливость. Вперёд., -Remember what the town hall looked like? That's a gentle reminder of what they're willing to do to get at us. Be careful.,TXT_DLG_SCRIPT03_D19708_REMEM,,,,"Pamatuješ si, jak dřív vypadala radnice? To je jemná přípomínka toho, co jsou schopni nám udělat. Buď opatrný.","Denk daran, wie unser Rathaus aussieht. Das ist nur ein Dankzettel dafür, wie weit sie gehen würden um uns zu finden. Sei vorsichtig.",,,¿Recuerdas cómo se ve el ayuntamiento? Ese es un pequeño recordatorio de lo que son capaces de hacer contra nosotros. Ten cuidado.,,,Souvenez-vous de l'hôtel de ville avant tout cela? C'est une manière gentille de nous montrer ce qu'ils sont capables de faire pour se débarasser de nous. Faites attention.,,,"市庁舎の外観を見たか?あれが我々に対する -奴等の所業を思い出させる。気をつけろ。",시청이 박살난 걸 보았지? 저건 오더의 심기를 무모하게 건드린 결과같은 거야. 그러니 조심해.,Weet je nog hoe het stadhuis eruit zag? Dat is een vriendelijke herinnering aan wat ze bereid zijn te doen om ons te pakken te krijgen. Wees voorzichtig.,"Pamiętasz jak ratusz wyglądał? To delikatne przypomnienie co chcą zrobić, aby nas dorwać. Uważaj na siebie.",Lembra como era a prefeitura? Aquilo é um simples lembrete do que eles estão dispostos a fazer para nos pegar. Tome cuidado.,,Mai ții minte cum arăta primăria? Asta e o reamintire ușoară de ceea ce sunt dispuși să facă pentru a ajunge la noi. Ai grijă.,"Видел, что стало с городской ратушей? Это мягкий намёк на то, что они сделают, если доберутся до нас. Будь осторожен.", -Talk to Macil. He'll be able to help you.,TXT_DLG_SCRIPT03_D21224_TALKT,,,,Promluv si s Macilem. On ti pomůže.,Rede mit Macil. Er kann dir helfen.,,,Habla con Macil. Él te podrá ayudar.,,,Parlez à Macil. Il pourra vous aider.,,,マシルと話すんだ。彼から援助が得られるはず。,도움이 필요한가? 그럼 마실 사령관님을 찾아.,Praat met Macil. Hij zal je kunnen helpen.,Porozmawiaj z Macilem. Pomoże ci.,Fale com Macil. Ele vai poder te ajudar.,,Discută cu Macil. Te va ajuta el.,Поговори с Мэйсилом. Он сможет тебе помочь., -I've heard that Macil's got a plan to subvert the Order. It had better be good. One more failure and we're all just dead meat.,TXT_DLG_SCRIPT03_D22740_IVEHE,,,,"Slyšel jsem, že Macil má plán, jak porazit Řád. Doufejme, že dobrý. Ještě jeden nezdar a všichni jsme mrtví.","Ich habe gehört, Macil hätte einen Plan um den Orden zu unterwandern. Ich hoffe mal, er taugt was. Noch ein Fehlschlag und wir können uns gleich begraben lassen.",,,He oído que Macil tiene un plan para desestabilizar a la Orden. Más vale que sea bueno. Un fallo más y somos carne muerta.,,,J'ai entendu que Macil a un plan pour repousser l'Ordre. Il a intérêt à être bon. Une erreur de plus et nous sommes tous morts.,,,"私はマシルがオーダーを転覆させる計画を + \cy일생일대의 격전에 대비해. 돈 아끼지 말고 있는 대로 다 써.","Het hol van de programmeur is in het kasteel. Ga nu naar de dokter, pak wat munitie en ga hem halen.","Programmererens skjulested er i slottet. Gå til legen, hent ammunisjon og hent ham.","Kryjówka Programisty jest w zamku. Teraz idź do medyka, weź trochę amunicji i załatw go.","O covil do Programador fica no castelo. Agora vá ver o médico, pegue munição e vá atrás dele.",,"Bârlogul Programatorului e în castel. Acum, dute la medic, ia niște muniție, și prindeți-l.","Программист устроил себе логово в замке. Теперь наведайся к врачу, пополни боезапас, и расправься с ним.",,"Programmerarens gömställe finns i slottet. Gå till läkaren, ta lite ammunition och hämta honom.","Programcı'nın sığınağı kalenin içinde. Şimdi, doktoru gör, biraz cephane al ve gidip onu getir." +Let me at 'em!,TXT_RPLY0_SCRIPT03_D16676_LETME,〃 (〃),,,Pusť mě na ně!,Lad mig tage dem!,Lass mich das nur machen.,,Mi faros tion!,¡Voy a por ellos!,¡Voy por ellos!,Päästä minut niiden kimppuun!,Je vais me le faire!,Elkapom mindet!,Lasciali a me!,任せろ!,한 번 저질러 봅시다!,Laat me er naartoe gaan!,La meg ta dem!,Niech ja go dorwę!,Pode deixar!,,Le voi arăta eu lor!,Я им покажу!,,Låt mig ta dem!,Bana bırakın! +Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT03_D18192_FIGHT,〃 (〃),,,Bojuj za Frontu a svobodu! Odchod.,Kæmp for fronten og friheden. Af sted.,Kämpfe für die Front und die Freiheit. Nun geh.,,Bataladu pro la Fronto kaj libereco. Ekagu.,Pelea por el Frente y la libertad. En marcha.,,Taistele Rintaman ja vapauden puolesta. Liikkeelle mars.,Battez vous pour le Front et pour la liberté. Repos.,Együtt a Frontért és a szabadságért! Indulás!,"Lotta, per il Fronte e per la libertà! E ora, al lavoro.",フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het front en vrijheid. Verhuizen.,Kjemp for Fronten og friheten. Kom igjen.,Walcz dla Frontu i wolności. Wykonać.,Lute pela Frente e pela liberdade. Agora vá.,,Luptă pentru Front și libertate. Acum pleacă.,Сражайся за свободу и справедливость. Выдвигайся.,,Kämpa för fronten och friheten. Gå ut.,Cephe ve özgürlük için savaşın. Dışarı çıkın. +Remember what the town hall looked like? That's a gentle reminder of what they're willing to do to get at us. Be careful.,TXT_DLG_SCRIPT03_D19708_REMEM,MAP03: Barracks.,,,"Pamatuješ si, jak dřív vypadala radnice? To je jemná přípomínka toho, co jsou schopni nám udělat. Buď opatrný.","Kan du huske, hvordan rådhuset så ud? Det er en blid påmindelse om, hvad de er villige til at gøre for at få fat i os. Vær forsigtig.","Denk daran, wie unser Rathaus aussieht. Das ist nur ein Dankzettel dafür, wie weit sie gehen würden um uns zu finden. Sei vorsichtig.",,"Ĉu vi memoras, kiel la urbodomo aspektis antaŭe? Ĝi nun estas afabla ekzemplo de tio, kion ili estas pretaj fari por forigi nin. Estu atenta.",¿Recuerdas como era antes el ayuntamiento? Ahora es una muestra amable de lo que son capaces de hacer contra nosotros. Ten cuidado.,,"Muistatko, miltä kaupungintalo näytti? Se on hienovarainen muistutus siitä, mitä he ovat valmiita tekemään saadakseen meidät. Ole varuillasi.",Souvenez-vous de l'hôtel de ville avant tout cela? C'est une manière gentille de nous montrer ce qu'ils sont capables de faire pour se débarasser de nous. Faites attention.,"Emlékszel, hogy nézett ki a vársoháza? Jó példa arra, hogy mire képesek, hogy elintézzenek minket. Légy óvatos.",Ti ricordi com'era il municipio una volta? Adesso è un piccolo ricordo di cosa sono disposti a fare per attaccarci. Fai attenzione.,"市庁舎の外観を見たか?あれが我々に対する +奴等の所業を思い出させる。気をつけろ。",시청이 박살난 걸 보았지? 저건 오더의 심기를 무모하게 건드린 결과같은 거야. 그러니 조심해.,Weet je nog hoe het stadhuis eruit zag? Dat is een vriendelijke herinnering aan wat ze bereid zijn te doen om ons te pakken te krijgen. Wees voorzichtig.,Husker du hvordan rådhuset så ut? Det er en påminnelse om hva de er villige til å gjøre for å ta oss. Vær forsiktig.,"Pamiętasz jak ratusz wyglądał? To delikatne przypomnienie co chcą zrobić, aby nas dorwać. Uważaj na siebie.",Lembra como era a prefeitura? Aquilo é um simples lembrete do que eles estão dispostos a fazer para nos pegar. Tome cuidado.,,Mai ții minte cum arăta primăria? Asta e o reamintire ușoară de ceea ce sunt dispuși să facă pentru a ajunge la noi. Ai grijă.,"Видел, что стало с городской ратушей? Это мягкий намёк на то, что они сделают, если доберутся до нас. Будь осторожен.",,Minns du hur stadshuset såg ut? Det är en mild påminnelse om vad de är villiga att göra för att komma åt oss. Var försiktig.,Belediye binasının neye benzediğini hatırlıyor musun? Bu bize ulaşmak için neler yapabileceklerini hatırlatıyor. Dikkatli olun. +Talk to Macil. He'll be able to help you.,TXT_DLG_SCRIPT03_D21224_TALKT,"MAP03: Upstairs, corridor.",,,Promluv si s Macilem. On ti pomůže.,Tal med Macil. Han vil kunne hjælpe dig.,Rede mit Macil. Er kann dir helfen.,,Parolu kun Macil. Li povos helpi vin.,Habla con Macil. Él te podrá ayudar.,Habla con Macil. Él te va a poder ayudar.,Puhu Macilille. Hän pystyy auttamaan sinua.,Parlez à Macil. Il pourra vous aider.,Beszélj Macil-lal. Ő tud segíteni neked.,Parla con Macil. Sarà in grado di aiutarti.,マシルと話すんだ。彼から援助が得られるはず。,도움이 필요한가? 그럼 마실 사령관님을 찾아.,Praat met Macil. Hij zal je kunnen helpen.,Snakk med Macil. Han kan hjelpe deg.,Porozmawiaj z Macilem. Pomoże ci.,Fale com Macil. Ele vai poder te ajudar.,,Discută cu Macil. Te va ajuta el.,Поговори с Мэйсилом. Он сможет тебе помочь.,,Prata med Macil. Han kan hjälpa dig.,Macil ile konuş. Sana yardım edebilir. +I've heard that Macil's got a plan to subvert the Order. It had better be good. One more failure and we're all just dead meat.,TXT_DLG_SCRIPT03_D22740_IVEHE,"MAP03: Barracks. +(dead meat = corpse)",,,"Slyšel jsem, že Macil má plán, jak porazit Řád. Doufejme, že dobrý. Ještě jeden nezdar a všichni jsme mrtví.","Jeg har hørt, at Macil har en plan om at undergrave Ordenen. Den har bare at være god. En fiasko mere, og vi er alle bare dødt kød.","Ich habe gehört, Macil hätte einen Plan um den Orden zu unterwandern. Ich hoffe mal, er taugt was. Noch ein Fehlschlag und wir können uns gleich begraben lassen.",,"Mi aŭdis, ke Macil havas planon por malstabiligi La Ordenon. Pli bone, ke ĝi estas bona. Unu plua eraro kaj ni estos kadavroj.",He oído que Macil tiene un plan para desestabilizar a La Orden. Más vale que sea bueno. Un fallo más y somos fiambres.,Oí que Macil tiene un plan para desestabilizar a La Orden. Más vale que sea bueno. Un fallo más y somos fiambres.,"Kuulin, että Macililla on suunnitelma kukistaa Veljeskunta. Parasta ollakin hyvä. Vielä yksikin epäonnistuminen, ja olemme kaikki mennyttä.",J'ai entendu que Macil a un plan pour repousser l'Ordre. Il a intérêt à être bon. Une erreur de plus et nous sommes tous morts.,"Úgy tudom Macilnak van valami terve a Rend felforgatására. Remélem valami ütős terv. Még egy kudarc, és nekünk lőttek.",Ho sentito che Macil ha un piano per sovvertire l'Ordine. E spero proprio che sia un buon piano. Un altro fallimento e saremo tutti carne morta.,"私はマシルがオーダーを転覆させる計画を 持っていると聞いた。そうだと良かったが。 -我々は一度大敗し全滅しかけた。",오더를 괴멸할 방법을 마실 사령관님이 찾아냈대. 잘 먹혀야 하는데 말이야... 안 그럼 우리들이 잡아먹힐 거라고.,Ik heb gehoord dat Macil een plan heeft om de Orde te ondermijnen. Het kan maar beter goed zijn. Nog een mislukking en we zijn allemaal gewoon dood vlees.,"Słyszałem, że Macil ma plan obalenia Zakonu. Oby był dobry. Jeszcze jedna porażka, a będziemy martwi.",Fiquei sabendo que Macil tem um plano para desestabilizar a Ordem. Espero que seja bom. Mais um fracasso e estaremos todos mortos.,,Am auzit că Macil are un plan pentru a submina Ordinul. Ar face bine să fie grozav. Încă un eșec și vom fi toți carne ambalată.,"Я слышал, что Мэйсил разработал план свержения Ордена. Лучше бы ему сработать. Ещё одна ошибка, и мы все покойники.", -A few of these barrels dumped into their water supply should even the odds a little.,TXT_DLG_SCRIPT03_D24256_AFEWO,,,,Pár těhle sudů v jejich zásobách vody by nám mělo alespoň trochu pomoct.,"Wenn wir ein paar von diesen Fässern in die Wasserversorgung kippen, sollte das unsere Chancen etwas verbessern.",,,Unos cuantos de estos barriles arrojados en su suministro de agua deberían igualar las probabilidades un poco.,,,Quelques uns de ces tonneaux vidés dans leur réserve d'eau devrait équilibrer le terrain de jeu.,,,"ここの樽は捨てられていた物で -彼らの給水を補っている。",그들의 배수관에서 버려진 이 통들 일부는 분명히 약간의 승산이 있을거야.,"Een paar van deze vaten die in hun waterleiding gedumpt zijn, zullen de kans dat ze een beetje gelijk zijn.",Parę tych beczek wrzuconcyh do ich zapasu wody powinno narobić wiele kłopotów.,"Se despejarmos alguns destes barris no estoque de água deles, vamos igualar as chances um pouco. ",,Câteva butoaie vărsate în rezerva lor de apă ar trebui să echilibreze balanța.,"Несколько таких бочек, сброшенных в их водоснабжение, причинят немало неприятностей.", -"So you're the new operative? Thanks, without you, we'd all be dead right now.",TXT_DLG_SCRIPT03_D25772_SOYOU,,,,"Takže ty jsi ten nový agent? Díky, bez tebe bychom všichni byli mrtví.","So, du bist der neue Agent? Danke, ohne dich wären wir schon alle tot.",,,"¿Así que eres el nuevo operativo? Gracias, sin ti, estaríamos todos muertos.",,,"Vous êtes le nouvel agent? Merci, sans vous, nous serions tous morts.",,,"貴方が新しい工作員かい? それはありがたい、 -貴方がいなければ皆死んでいた所だ。","그래서, 네가 그 요원이지? 고맙다. 네가 없었으면 우리들은 이미 죽고 없었을걸.","Dus jij bent de nieuwe agent? Bedankt, zonder jou waren we nu allemaal dood geweest.","Więc jesteś tu nowy? Dzięki, bez ciebie bylibyśmy już martwi.","Então você é o novo agente? Obrigado. Sem você, estaríamos todos mortos neste momento.",,"Deci tu ești noul operator? Merci, dacă nu erai tu, am fi fost cu toții morți deja.","Так это ты наш новый агент? Спасибо. Если бы не ты, мы бы все уже были мертвы.", -I'm working on something that will give us an edge. It will increase your stamina and completely jack you up. I've almost got all the bugs worked out. Can I do something for you?,TXT_DLG_SCRIPT03_D27288_IMWOR,,,,"Pracuju na něčem, co by nám mělo pomoci. Přidá ti to výdrž a naprosto tě to napumpuje. Už jsem skoro vychytal všechny mouchy. Co pro tebe mohu udělat?","Ich arbeite an etwas, das uns einen Vorteil verschaffen kann. Es würde deine Ausdauer erhöhen und dir Superkräfte verleihen. Kann ich was für dich tun?",,,Estoy trabajando en algo que nos dará una ventaja. Aumentará tu aguante y te pondrá las pilas. Casi tengo todos los fallos corregidos. ¿Puedo hacer algo por ti?,,,Je travaille sur quelque chose qui nous donnera un peu d'avance. Ca devrait augmenter votre endurance et vous donner un sacré coup de jus. Je crois que j'ai corrigé presque tous les bugs. Je peux vous aider?,,,"私は研究にも取り組んでいる。貴方のスタミナを +我々は一度大敗し全滅しかけた。",오더를 괴멸할 방법을 마실 사령관님이 찾아냈대. 잘 먹혀야 하는데 말이야... 안 그럼 우리들이 잡아먹힐 거라고.,Ik heb gehoord dat Macil een plan heeft om de Orde te ondermijnen. Het kan maar beter goed zijn. Nog een mislukking en we zijn allemaal gewoon dood vlees.,"Jeg har hørt at Macil har en plan for å undergrave Ordenen. Den bør være god. Én fiasko til, og vi er ferdige.","Słyszałem, że Macil ma plan obalenia Zakonu. Oby był dobry. Jeszcze jedna porażka, a będziemy martwi.",Fiquei sabendo que Macil tem um plano para desestabilizar a Ordem. Espero que seja bom. Mais um fracasso e estaremos todos mortos.,,Am auzit că Macil are un plan pentru a submina Ordinul. Ar face bine să fie grozav. Încă un eșec și vom fi toți carne ambalată.,"Я слышал, что Мэйсил разработал план свержения Ордена. Лучше бы он сработал. Ещё одна ошибка, и мы все покойники.",,Jag har hört att Macil har en plan för att omstörta Orden. Det är bäst att den är bra. Ett misslyckande till och vi är alla bara döda kött.,Macil'in Tarikat'ı yıkmak için bir planı olduğunu duydum. İyi olsa iyi olur. Bir başarısızlık daha olursa hepimiz ölürüz. +A few of these barrels dumped into their water supply should even the odds a little.,TXT_DLG_SCRIPT03_D24256_AFEWO,〃,,,Pár těhle sudů v jejich zásobách vody by nám mělo alespoň trochu pomoct.,Et par af disse tønder dumpet i deres vandforsyning burde udligne oddsene lidt.,"Wenn wir ein paar von diesen Fässern in die Wasserversorgung kippen, sollte das unsere Chancen etwas verbessern.",,Ĵeti kelkajn el ĉi tiuj bareloj en ilian akvo-provizadon devus egaligi iomete la eblojn.,Tirar unos cuantos de estos barriles a su suministro de agua debería igualar un poco las probabilidades.,,Muutaman tällaisen tynnyrin kaataminen heidän vedenjakeluunsa varmaankin hieman tasoittaisi tilannetta.,Quelques uns de ces tonneaux vidés dans leur réserve d'eau devrait équilibrer le terrain de jeu.,Ezzel a pár víztározóba borított hordóval kiegyenlítjük az erőviszonyokat.,Un paio di questi barili rovesciati dentro la loro fornitura d'acqua dovrebbero bilanciare un po' le cose.,"ここの樽は捨てられていた物で +彼らの給水を補っている。",그들의 배수관에서 버려진 이 통들 일부는 분명히 약간의 승산이 있을거야.,"Een paar van deze vaten die in hun waterleiding gedumpt zijn, zullen de kans dat ze een beetje gelijk zijn.",Et par av disse tønnene dumpet i vannforsyningen deres burde jevne ut oddsen litt.,Parę tych beczek wrzuconcyh do ich zapasu wody powinno narobić wiele kłopotów.,"Se despejarmos alguns destes barris no estoque de água deles, vamos igualar as chances um pouco. ",,Câteva butoaie vărsate în rezerva lor de apă ar trebui să echilibreze balanța.,"Несколько таких бочек, сброшенных в их водоснабжение, немного уровняют шансы.",,Några av de här tunnorna dumpade i deras vattenförsörjning borde jämna ut oddsen lite.,Bu varillerden birkaçı su kaynaklarına atılırsa ihtimaller biraz olsun eşitlenir. +"So you're the new operative? Thanks, without you, we'd all be dead right now.",TXT_DLG_SCRIPT03_D25772_SOYOU,〃,,,"Takže ty jsi ten nový agent? Díky, bez tebe bychom všichni byli mrtví.","Så du er den nye agent? Tak, uden dig ville vi alle være døde lige nu.","So, du bist der neue Agent? Danke, ohne dich wären wir schon alle tot.",,"Do ĉu vi estas la nova ano? Dankon. Sen vi, ni ĉiuj jam estus mortintaj.",¿O sea que tú eres el nuevo miembro? Gracias. Sin ti ya estaríamos todos muertos.,,Sinä siis olet se uusi agentti? Kiitos; ilman sinua olisimme nyt kaikki kuolleita.,"Vous êtes le nouvel agent? Merci, sans vous, nous serions tous morts.","Szóval te vagy az új kolléga? Köszi, nélküled már mind alulról szagolnánk az ibolyát.","Quindi sei tu il nuovo agente? Grazie, se non fosse per te, saremo tutti morti ora.","貴方が新しい工作員かい? それはありがたい、 +貴方がいなければ皆死んでいた所だ。","그래서, 네가 그 요원이지? 고맙다. 네가 없었으면 우리들은 이미 죽고 없었을걸.","Dus jij bent de nieuwe agent? Bedankt, zonder jou waren we nu allemaal dood geweest.","Så du er den nye agenten? Takk, uten deg ville vi alle vært døde nå.","Więc jesteś tu nowy? Dzięki, bez ciebie bylibyśmy już martwi.","Então você é o novo agente? Obrigado. Sem você, estaríamos todos mortos neste momento.",,"Deci tu ești noul operator? Merci, dacă nu erai tu, am fi fost cu toții morți deja.","Так это ты наш новый оперативник? Спасибо. Если бы не ты, мы бы все уже были мертвы.",,"Så du är den nya agenten? Tack, utan dig hade vi alla varit döda nu.","Demek yeni ajan sensin? Teşekkürler, sen olmasaydın şu anda hepimiz ölmüş olurduk." +I'm working on something that will give us an edge. It will increase your stamina and completely jack you up. I've almost got all the bugs worked out. Can I do something for you?,TXT_DLG_SCRIPT03_D27288_IMWOR,MAP03: Gerald (no implant),,,"Pracuju na něčem, co by nám mělo pomoci. Přidá ti to výdrž a naprosto tě to nakopne. Už jsem skoro vychytal všechny mouchy. Co pro tebe mohu udělat?","Jeg arbejder på noget, der vil give os en fordel. Det vil øge din udholdenhed og gøre dig helt oppe at køre. Jeg har næsten fået styr på alle fejlene. Må jeg gøre noget for dig?","Ich arbeite an etwas, das uns einen Vorteil verschaffen kann. Es würde deine Ausdauer erhöhen und dir Superkräfte verleihen. Kann ich was für dich tun?",,"Mi laboras super io, kio donos avantaĝon al ni: ĝi pliigos vian energion kaj korpan forton. Mi jam korektis la plimulton de la cimoj. Ĉu mi povas fari ion por vi?",Estoy trabajando en algo que nos dará una ventaja: aumentará tu aguante y fuerza física. Ya casi tengo todos los fallos corregidos. ¿Puedo hacer algo por ti?,Estoy trabajando en algo que nos va a dar una ventaja: va a aumentar tu aguante y fuerza física. Ya casi tengo todos los fallos corregidos. ¿Puedo hacer algo por ti?,"Olen paraikaa työstämässä jotain, joka antaa meille etulyöntiaseman. Se kasvattaa kuntoasi ja täydellisesti virittää lihaksesi. Olen melkein saanut hiottua kaikki viat. Voinko olla jotenkin avuksi?",Je travaille sur quelque chose qui nous donnera un peu d'avance. Ca devrait augmenter votre endurance et vous donner un sacré coup de jus. Je crois que j'ai corrigé presque tous les bugs. Je peux vous aider?,"Dolgozok valamin, ami egy jelentősebb előnyhöz juttat minket. Megerősíti az állóképességedet és teljesen felpumpálja a tested. Már majdnem kiküszöböltem a hibákat. Amúgy tudok valamiben segíteni?",Sto lavorando a qualcosa che ci darà un notevole vantaggio. Aumenterà la tua resistenza e ti farà sentire molto più forte. Ho quasi risolto tutti gli effetti collaterali. Posso fare qualcosa per te?,"私は研究にも取り組んでいる。貴方のスタミナを 増強し完璧な体にすることも可能だ。 そのインプラントのバグも殆ど取り除かれている -ところで何か必要かい?","지금 우리들에게 승산이 갈 만한 연구를 하고 있습니다. 지구력 향상 이식 칩인데, 이 것만 있으면 당신의 체력과 힘을 더 불어넣어줄 겁니다. 오류를 거의 잡기도 했구요. 이제, 뭘 도와드릴까요?",Ik werk aan iets dat ons een voorsprong geeft. Het zal je uithoudingsvermogen verhogen en je volledig opkrikken. Ik heb bijna alle bugs uitgewerkt. Kan ik iets voor je doen?,"Pracuję nad czymś dla ciebie co da nam przewagę. Zwiększy ci to wytrzymałość i sprawi, że poczujesz się lepiej. Już prawie naprawiłem wszystkie błędy. Mogę coś dla ciebie zrobić?",Estou trabalhando em algo que vai nos dar um impulso. É algo que vai aumentar sua resistência e te deixar bem mais forte. Estou com quase todos os bugs resolvidos. Posso te ajudar com algo?,,Lucrez la ceva care ne va oferi un avantaj. Îți va mării rezistența fizică și întări. Aproape am rezolvat toate problemele. Pot face ceva pentru tine?,"Я работаю кое над чем, что может нам пригодиться. Оно увеличит твою выносливость и улучшит самочувствие. Я уже исправил почти все дефекты. Или тебе нужно что-то ещё?", -Patch me up.,TXT_RPLY0_SCRIPT03_D27288_PATCH,,,,Dej mě do hromady.,Flick mich zusammen.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료가 필요합니다.,Patch me op.,Opatrz mnie.,Trate meus ferimentos.,,Bandajează-mă.,Перебинтуй меня., -"Boy, you're a real mess. I'll see what I can do.",TXT_RYES0_SCRIPT03_D27288_BOYYO,,,,"Tebe teda zřídili, kluku. Uvidím, co s tebou.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,,"Chico, estás hecho un desastre. Veré que puedo hacer.",,,"Mon petit, vous êtes dans un sale état. Je vais voir ce que je peux faire.",,,君、滅茶苦茶だな。なんとかしよう。,"당신, 정말 엉망이네요... 어떻게든 치료해줄게요.","Jongen, je bent een echte puinhoop. Ik zal zien wat ik kan doen.","Chłopie, ależ ty jesteś poszarpany. Zobaczę co da się zrobić.","Rapaz, você está arrebentado. Vou ver o que posso fazer.",,"Măi să fie, ești un dezastru. O să văd ce pot face.","Парень, да на тебя смотреть страшно. Приступим...", -Stamina implant?,TXT_RPLY1_SCRIPT03_D27288_STAMI,,,,Implantát pro výdrž?,Ausdauerimplantat?,,,¿Implante de aguante?,,,Implant d'endurance?,,,スタミナインプラント?,지구력 향상 이식?,Stamina implantaat?,Implant zwiększający wytrzymałość?,Implante de resistência?,,Implant pentru rezistență?,Выносливостный имплант?, -"All right, this won't take but a moment.",TXT_RYES1_SCRIPT03_D27288_ALLRI,,,,"Dobře, tohle potrvá jen chvilku.","Alles klar, das haben wir sofort.",,,"Muy bien, esto solo tomará un momento.",,,"Pas de problème, ça ne prendra qu'un moment.",,,いいでしょう、これは時間を取りません。,좋습니다. 시간이 오래 걸리진 않을 거예요.,"Oké, dit duurt maar een momentje.","Dobra, to zajmie tylko chwilę.","Ok, só um momento.",,"În regulă, va dura doar un moment.","Отлично, это займёт всего пару секунд.", -It's not done yet.,TXT_RNO1_SCRIPT03_D27288_ITSNO,,,,Ještě není hotový.,Es ist noch nicht soweit.,,,Aún no está listo.,,,Ce n'est pas encore terminé.,,,まだ完成していません。,아직 완료되지는 않았어요.,Het is nog niet klaar.,Jeszcze nie jest gotowy.,Ainda não terminei.,,Încă nu e gata.,Он ещё не готов., -"Hey, I'm working on an updated version of your implant. Is there anything else I can do?",TXT_DLG_SCRIPT03_D28804_HEYIM,,,,"Hej, pracuju na vylepšené verzi tvého implantátu. Můžu pro tebe udělat něco jiného?","He, ich arbeite an einer verbesserten Version deines Implantats. Gibt es sonst etwas, das ich für dich tun kann?",,,"Hey, estoy trabajando en una versión mejorada de tu implante. ¿Hay algo más que pueda hacer?",,,"Hé, je travaille sur une version améliorée de l'implant. Qu'est-ce que je peux faire pour vous?",,,"どうも、私は今最新版のインプラントに -取り組んでいる。何か用かな?","당신의 이식 칩을 위한 향상 개조가 준비되었습니다. 그런 이유로 온게 아니면, 무엇을 도와드릴까요?","Hé, ik ben bezig met een bijgewerkte versie van je implantaat. Is er nog iets anders dat ik kan doen?","Hej, pracuję nad ulepszoną wersją twojego implantu. Mogę coś jeszcze dla ciebie zrobić?",E aí. Estou trabalhando numa versão aprimorada do seu implante. Posso te ajudar com algo?,,"Hei, lucrez la o variantă îmbunătățită a implantului tău. Mai e ceva cu care să te ajut?","Я работаю над улучшенной версией твоего импланта. А пока, что-нибудь ещё?", -Patch me up.,TXT_RPLY0_SCRIPT03_D28804_PATCH,,,,Dej mě do hromady.,Flick mich zusammen.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료가 필요합니다.,Patch me op.,Opatrz mnie.,Trate meus ferimentos.,,Bandajează-mă.,Перебинтуй меня., -Well at least your seeing action.,TXT_RYES0_SCRIPT03_D28804_WELLA,,,,"No, alespoň jsi v akci.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,,Bueno al menos estás viendo algo de acción.,,,"Eh bien, au moins vous en voyez, de l'action.",,,貴方の働きは聞き届いてるよ。,이제 전장에 힘을 발휘해보세요!,"Nou ja, in ieder geval uw zien actie.",Przynajmniej będziesz mógł wrócić do akcji.,"Bem, pelo menos tá tendo um pouco de ação.",,"Eh, măcar tu ai parte de acțiune.","Что ж, зато ты участвуешь в операциях.", -Implant upgrade?,TXT_RPLY1_SCRIPT03_D28804_IMPLA,,,,Vylepšení implantátu?,Implantatsupgrade?,,,¿Mejora de implante?,,,Mise à jour de l'implant?,,,インプラント アップグレード?,지구력 업그레이드?,Implantaat upgrade?,Ulepszenie implantu?,Versão aprimorada do implante?,,Upgrade pentru implant?,Улучшение импланта?, -"Good thing, never can be too safe.",TXT_RYES1_SCRIPT03_D28804_GOODT,,,,"Dobrá věcička, nikdy si nemůžeš být moc jistý.","Alles klar, das haben wir sofort.",,,"Bien, nunca se puede estar del todo seguro.",,,Bonne idée. On ne peut jamais être trop sûr.,,,良いことだ、安全すぎることはない。,좋은 선택입니다. 이거 없이는 안전할 수가 없죠.,"Goede zaak, kan nooit te veilig zijn.","Dobra rzecz, nigdy za mało bezpieczeństwa.",Boa idéia. Segurança nunca é demais.,,"Recomand cu mare drag, nu poți fi niciodată prea sigur.","Очень советую, ни в чём нельзя быть уверенным до конца.", -"I'm almost finished, but not quite.",TXT_RNO1_SCRIPT03_D28804_IMALM,,,,"Už je skoro hotový, ale ne úplně.",Es ist noch nicht soweit.,,,"Casi he terminado, pero no del todo.",,,"Presque fini, mais pas encore.",,,もうすぐ出来上がる、それほど掛からない。,"거의 다 돼가지만, 아직 완성된 게 아니에요.","Ik ben bijna klaar, maar niet helemaal.","Prawie skończyłem, ale nie do końca.",Estou quase terminando. Só mais um pouco.,,"Sunt aproape gata, dar nu tocmai.",Я почти закончил. Ещё немного., -"All right, I've almost got everything working perfectly. There were a few problems left to get rid of. Do you need anything else? ",TXT_DLG_SCRIPT03_D30320_ALLRI,,,,"Tak dobře, už mi skoro všechno perfektně funguje. Ještě tam bylo pár problémů. Potřebuješ ještě něco?","He, ich arbeite an einer verbesserten Version deines Implantats. Gibt es sonst etwas, das ich für dich tun kann?",,,"Muy bien, tengo casi todo funcionando a la perfección. Solo quedaron algunos problemas que eliminar. ¿Necesitas algo mas?",,,"Très bien, je crois que j'ai réussi à tout faire marcher parfaitement. Il y avait quelques problèmes dont je devais me débarrasser. Vous voulez quelque chose?",,,"大丈夫、全て順調だ。残っていた問題も -全て取り除かれた。他に何が必要かな?",연구가 거의 다 끝나갑니다. 연구 도중에 오류를 좀 잡았어요. 기다리는 동안 뭐 필요한 게 있나요?,"Oke, ik heb bijna alles wat perfect werkt. Er waren nog een paar problemen over om van af te komen. Heeft u nog iets anders nodig?","Dobra, prawie wszystko działa dobrze. Zostało jeszcze parę rzeczy do zrobienia. Czy coś jeszcze potrzebujesz?","Ok, tenho quase tudo funcionando perfeitamente. Ainda faltam alguns probleminhas para tirar de você. Precisa de mais alguma coisa?",,,"Итак, тут оставалась пара проблем, но теперь всё работает почти идеально. Что-нибудь ещё?", -Patch me up.,TXT_RPLY0_SCRIPT03_D30320_PATCH,,,,Dej mě do hromady.,Flick mich zusammen.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료가 필요합니다.,Patch me op.,Opatrz mnie.,Trate meus ferimentos.,,,Перебинтуй меня., -What have you been trying to do? Go head to head with a Crusader?,TXT_RYES0_SCRIPT03_D30320_WHATH,,,,Co jsi dělal? Šel zmlátit Křižáka?,"Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,,¿Qué has intentado hacer? ¿Encabezonarte con un Cruzado?,¿Qué has intentado hacer? ¿Pelear cabeza a cabeza con un Cruzado?,,Qu'est-ce que vous avez fait? Vous avez essayé de faire ami avec un Croisé?,,,"今度は何を始めるんだ? -クルセイダーと向かい合うのか?",뭘 하다 왔나요? 크루세이더랑 한판 뜨기라도 했나요?,Wat heb je geprobeerd te doen? Hoofd aan hoofd gaan met een kruisvaarder?,Co ty próbowałeś zrobić? Walczyć oko w oko z Krzyżowcem?,O que você andou tentando fazer? Partiu pro soco contra um Cruzado?,,,"Ты что, бился один на один с крестоносцем?", -Implant upgrade?.,TXT_RPLY1_SCRIPT03_D30320_IMPLA,,,,Vylepšení implantátu?,Implantatsupgrade?,,,¿Mejora de implante?,,,Mise à jour de l'implant?,,,インプラント アップグレード?,지구력 업그레이드?,Implantaat upgrade?,Ulepszenie implantu?,Versão melhorada do implante?,,,Улучшение импланта?, -That should do it for you.,TXT_RYES1_SCRIPT03_D30320_THATS,,,,Tohle by mělo fungovat.,"Alles klar, das haben wir sofort.",,,Con esto debería estar.,,,Ca devrait faire l'affaire.,,,今取り掛かっている。,이것만 있음 될 겁니다.,Dat zou het voor u moeten doen.,To powinno ci wystarczyć.,Isso deve funcionar.,,,Вот оно., -Let me run some more tests first.,TXT_RNO1_SCRIPT03_D30320_LETME,,,,Ještě ho musím dál otestovat.,Es ist noch nicht soweit.,,,Déjame hacer algunas pruebas primero.,,,Laissez moi faire quelques tests d'abord.,,,もう少しテストしてからにしよう。,"우선, 시험을 좀 거쳐야 해요.",Laat me eerst nog wat testen doen.,Pozwól mi zrobić jeszcze parę testów.,Deixe eu fazer alguns testes primeiro.,,,Дай мне ещё времени на тесты., -That's all I can do on the implant right now. Maybe some healing?,TXT_DLG_SCRIPT03_D31836_THATS,,,,"Tak, to je všechno co teď můžu s tím implantátem udělat. Potřebuješ léčení?","Das ist alles, was ich im Moment mit dem Implantat machen kann. Vielleicht etwas medizinische Versorgung?",,,Eso es todo lo que puedo hacer con el implante por ahora. ¿Qué tal una cura?,,,C'est tout ce que je peux faire pour l'implant. Vous voulez que je vous soigne?,,,"インプラントはこれ以上ない程完成した。 -それとも治療か?",지구력 향상 관련은 이게 다입니다. 이제 치료가 좀 필요하신가요?,Dat is alles wat ik nu kan doen op het implantaat. Misschien wat genezing?,To wszystko co mogę zrobić w sprawie implantu. Może chcesz się podleczyć?,Isso é tudo que posso fazer com o implante no momento. Não quer um tratamento nesses ferimentos?,,,Пока что я больше ничего не могу сделать с имплантом. Как насчёт лечения?, -Yeah.,TXT_RPLY0_SCRIPT03_D31836_YEAH,,,,Jo.,Ja.,,,Sí.,,,Ouais.,,,ああ。,네.,Ja.,Pewnie.,Pode ser.,,,Давай., -"Boy, you're a real mess. I'll see what I can do.",TXT_RYES0_SCRIPT03_D31836_BOYYO,,,,"Tebe teda zřídili, kluku. Uvidím, co s tebou.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,,"Chico, estás hecho un desastre. Veré que puedo hacer.",,,"Mon petit, vous êtes dans un sale état. Je vais voir ce que je peux faire.",,,君、滅茶苦茶だな。なんとかしよう。,심각한 부상을 입은 것 같군요. 치료하겠습니다.,"Jongen, je bent een echte puinhoop. Ik zal zien wat ik kan doen.","Chłopie, ależ ty jesteś poszarpany. Zobaczę co da się zrobić.","Rapaz, você está arrebentado. Vou ver o que posso fazer.",,,"Ты просто месиво. Посмотрим, что я смогу сделать.", -What can I do for you?,TXT_DLG_SCRIPT03_D33352_WHATC,,,,Co pro tebe můžu udělat?,Was kann ich für dich tun?,,,¿Qué puedo hacer por ti?,,,Que puis-je faire pour vous?,,,どういったご用件で?,필요한 게 있으면 말씀하세요.,Wat kan ik voor je doen?,Co mogę dla ciebie zrobić?,Como posso te ajudar?,,,Чем я могу тебе помочь?, -I'm out of bullets.,TXT_RPLY0_SCRIPT03_D33352_IMOUT,,,,Došly mi náboje.,Ich habe keine Munition mehr.,,,No me quedan balas.,,,Je suis à cours de munitions.,,,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Nie mam nabojów.,Estou sem balas.,,,У меня кончились патроны., -Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT03_D33352_HERES,,,,"Tady máš nějakou munici, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,Aquí tienes algo de munición. No la desperdicies.,,,"En voilà pour vous, ne les gaspillez pas.",,,この弾をどうぞ、無駄遣いしないように。,여기 조금의 탄약을 나눠줄게요. 낭비하지 마시길.,Hier is wat munitie voor je. Verspil het niet.,Masz tu trochę amunicji. Nie zmarnuj jej.,Tome um pouco de munição. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -Teach me.,TXT_RPLY1_SCRIPT03_D33352_TEACH,,,,Uč mě.,Unterrichte mich.,,,Entréname.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,Ucz mnie.,Me ensine.,,,Обучи меня., -"All right, I'll just show you a few little pointers.",TXT_RYES1_SCRIPT03_D33352_ALLRI,,,,"Dobře, ukážu ti pár triků.","Alles klar, ich zeige dir ein paar Kniffe.",,,"Muy bien, te daré algunos pequeños consejos.",,,Pas de problème. Laissez moi vous montrer quelques trucs.,,,わかった、貴方にやり方を幾つか教えよう。,좋아요. 훈련에 도움이 될 만한 표적을 보여주겠습니다.,"Oké, ik zal je gewoon een paar kleine tips laten zien.","Dobrze, podam ci parę wskazówek.","Ok, vou te dar algumas dicas.",,,Хорошо. Покажу тебе пару приёмов., -You're not ready yet.,TXT_RNO1_SCRIPT03_D33352_YOURE,,,,Ještě nejsi připravený.,Du bist noch nicht so weit.,,,Aun no estás listo.,,,Vous n'êtes pas encore prêt.,,,貴方の準備がまだ整ってないように思えます。,아직 준비가 안 됐어요.,Je bent nog niet klaar.,Nie jesteś jeszcze gotowy.,Você ainda não está pronto.,,,Ты ещё не готов., -Back again? What do you need?,TXT_DLG_SCRIPT03_D34868_BACKA,,,,Zase zpátky? Co potřebuješ?,Scxhon zurück? Was brauchst du?,,,¿Ya de vuelta? ¿Qué necesitas?,,,Déjà de retour? De quoi avez-vous besoin?,,,もう戻りましたか?何が必要ですか?,또 왔네? 뭐가 필요합니까?,Weer terug? Wat heb je nodig?,Wróciłeś? Czego chcesz?,Você novamente? Do que precisa?,,,Ты вернулся? Что тебе нужно?, -I'm out of bullets.,TXT_RPLY0_SCRIPT03_D34868_IMOUT,,,,Došly mi náboje.,Ich habe keine Munition mehr.,,,No me quedan balas.,,,Je suis à cours de munitions.,,,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Nie mam nabojów.,Estou sem balas.,,,У меня кончились патроны., -Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT03_D34868_HERES,,,,"Tady máš nějakou munici, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,Aquí tienes algo de munición. No la desperdicies.,,,"En voilà pour vous, ne les gaspillez pas.",,,この弾をどうぞ、無駄遣いしないように。,뭘 하다 탄약을 낭비한 겁니까? 여기 조금 줄게요.,Hier is wat munitie voor je. Verspil het niet.,Masz tu trochę amunicji. Nie zmarnuj jej.,Tome um pouco de munição. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -You've got enough ammo.,TXT_RNO0_SCRIPT03_D34868_YOUVE,,,,Vždyť jich máš dost.,Du hast genug.,,,Tienes suficiente munición.,,,Vous avez assez de munitions.,,,弾は十分に見えます。,당신은 충분한 탄약을 가졌어요.,Je hebt genoeg munitie.,Masz już wystarczająco dużo amunicji.,Você já tem munição o suficiente.,,,У тебя их достаточно., -Teach me.,TXT_RPLY1_SCRIPT03_D34868_TEACH,,,,Uč mě.,Unterrichte mich.,,,Entréname.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,Ucz mnie.,Me ensine.,,,Обучи меня., -"All right, this should keep you going for a while.",TXT_RYES1_SCRIPT03_D34868_ALLRI,,,,"Dobře, tohle by ti mělo pomoct.","Alles klar, das sollte fürs erste reichen.",,,"Muy bien, esto te mantendrá por un tiempo.",,,"Bien, ça devrait vous suffir pour un bon moment.",,,わかりました、これで長くやり合えるでしょう。,그렇군요. 가능한 오래 싸울 수 있을겁니다.,"Oké, dit zou je een tijdje op de been moeten houden.","Dobrze, to powinno ci pomóc na pewien czas.","Ok, isso deve te ajudar no momento.",,,"Хорошо, это не раз спасёт тебе жизнь.", -"Sorry, can't. I'm just following Macil's orders.",TXT_RNO1_SCRIPT03_D34868_SORRY,,,,"Promiň, nemůžu. Řídím se rozkazy od Macila.","Tut mir leid, aber ich kann nicht. Ich folge nur Macils Befehlen.",,,"Lo siento, no puedo. Solo sigo las órdenes de Macil.",,,"Désolé, pas possible. Je ne fais que suivre les ordres de Macil.",,,すまないが、できません。マシルの命令です。,미안합니다. 마실 사령관님의 명령을 따라야해요.,"Sorry, dat kan niet. Ik volg gewoon de orders van Macil op.","Przepraszam, ale nie mogę. Ja tylko wykonuję rozkazy Macila.",Desculpe mas não posso. Estou apenas seguindo as ordens de Macil.,,,"Увы, не могу. Я подчиняюсь Мэйсилу.", -"Well which is it, bullets or training? I can't wait to get my hands on those new weapons we captured. A little bit of training and then a lot of revenge.",TXT_DLG_SCRIPT03_D36384_WELLW,,,,"Tak co to bude, náboje nebo trénink? Nemůžu se dočkat, až se dostanu k těm novým zbraním, které jsme zabavili. Trocha cvičení a pak hodně odplaty.","Also, was willst du? Munition oder Training? Ich kann kaum erwarten, diese neuen Waffen, die wir erbeutet haben, in die Finger zu kriegen. ein bisschen Training und dann jede Menge Vergeltung.",,,"Bien, ¿Qué va a ser?, ¿Balas o entrenamiento? No puedo esperar a poner mis manos en esas nuevas armas que hemos capturado. Un poco de entrenamiento y luego mucha venganza.",,,"Qu'est-ce qu'il vous faut? Des munitions ou de l'entraînement? J'ai hâte d'essayer ces nouvelles armes que l'on a capturé, un peu d'entraînement et beaucoup de vengeance.",,,"弾薬と訓練、どっちの用件ですか? +ところで何か必要かい?","지금 우리들에게 승산이 갈 만한 연구를 하고 있습니다. 지구력 향상 이식 칩인데, 이 것만 있으면 당신의 체력과 힘을 더 불어넣어줄 겁니다. 오류를 거의 잡기도 했구요. 이제, 뭘 도와드릴까요?",Ik werk aan iets dat ons een voorsprong geeft. Het zal je uithoudingsvermogen verhogen en je volledig opkrikken. Ik heb bijna alle bugs uitgewerkt. Kan ik iets voor je doen?,Jeg jobber med noe som vil gi oss en fordel. Det vil øke utholdenheten din og løfte deg helt opp. Jeg har nesten funnet ut av alle problemene. Kan jeg gjøre noe for deg?,"Pracuję nad czymś dla ciebie co da nam przewagę. Zwiększy ci to wytrzymałość i sprawi, że poczujesz się lepiej. Już prawie naprawiłem wszystkie błędy. Mogę coś dla ciebie zrobić?",Estou trabalhando em algo que vai nos dar um impulso. É algo que vai aumentar sua resistência e te deixar bem mais forte. Estou com quase todos os bugs resolvidos. Posso te ajudar com algo?,,Lucrez la ceva care ne va oferi un avantaj. Îți va mării rezistența fizică și întări. Aproape am rezolvat toate problemele. Pot face ceva pentru tine?,"Я работаю кое над чем, что может нам пригодиться. Оно увеличит твою выносливость и улучшит самочувствие. Я уже исправил почти все дефекты. Что тебе нужно?",,Jag jobbar på något som kommer att ge oss en fördel. Det kommer att öka din uthållighet och göra dig helt upprymd. Jag har nästan löst alla buggar. Kan jag göra något för dig?,Bize avantaj sağlayacak bir şey üzerinde çalışıyorum. Dayanıklılığını arttıracak ve seni tamamen uçuracak. Neredeyse tüm hataları çözdüm. Senin için bir şey yapabilir miyim? +Patch me up.,TXT_RPLY0_SCRIPT03_D27288_PATCH,〃 (〃),,,Dej mě dohromady.,Giv mig et plaster på såret.,Flick mich zusammen.,,Kuracu min.,Cúrame.,,Hoida minut kuntoon.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료가 필요합니다.,Patch me op.,Lappe meg sammen.,Opatrz mnie.,Trate meus ferimentos.,,Bandajează-mă.,Подлатай меня.,,Laga mig.,Beni yamala. +"Boy, you're a real mess. I'll see what I can do.",TXT_RYES0_SCRIPT03_D27288_BOYYO,〃 (〃),,,"Tebe teda zřídili, kluku. Uvidím, co s tebou.","Du er et rigtigt rod. Jeg skal se, hvad jeg kan gøre.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,"Ulo, vi estas iomege en malordo. +Mi vidos tion, kion mi faru.","Tío, estás hecho un desastre. +A ver qué puedo hacer.","Chico, estás hecho un desastre. +A ver qué puedo hacer.","Voi pojat, oletpa hajalla. Katsotaan, mihin pystyn.","Mon petit, vous êtes dans un sale état. Je vais voir ce que je peux faire.","Öregem, elég rossz passzban vagy. Megnézem mit tudok tenni.","Ragazzo, sei messo proprio male. Vediamo cosa posso fare.",君、滅茶苦茶だな。なんとかしよう。,"당신, 정말 엉망이네요... 어떻게든 치료해줄게요.","Jongen, je bent een echte puinhoop. Ik zal zien wat ik kan doen.","Jøss, du ser forferdelig ut. Jeg skal se hva jeg kan gjøre.","Chłopie, ależ ty jesteś poszarpany. Zobaczę co da się zrobić.","Rapaz, você está arrebentado. Vou ver o que posso fazer.",,"Măi să fie, ești un dezastru. O să văd ce pot face.","Парень, да на тебя смотреть страшно. Приступим...",,Du är en riktig röra. Jag ska se vad jag kan göra.,"Evlat, gerçekten berbat durumdasın. Ne yapabileceğime bir bakayım." +Stamina implant?,TXT_RPLY1_SCRIPT03_D27288_STAMI,〃 (〃),,,Implantát pro výdrž?,Udholdenhedsimplantat?,Ausdauerimplantat?,,Ĉu energidona enplantaĵo?,¿Implante de aguante?,,Kuntoistute?,Implant d'endurance?,Állóképesség implantátum?,Impianto stamina?,スタミナインプラント?,지구력 향상 이식?,Stamina implantaat?,Utholdenhetsimplantat?,Implant zwiększający wytrzymałość?,Implante de resistência?,,Implant pentru rezistență?,Выносливостный имплант?,,Ett uthållighetsimplantat?,Dayanıklılık implantı mı? +"All right, this won't take but a moment.",TXT_RYES1_SCRIPT03_D27288_ALLRI,〃 (〃),,,"Dobře, tohle potrvá jen chvilku.","Okay, det tager kun et øjeblik.","Alles klar, das haben wir sofort.",,"Bonege, ĉi tio +estos rapidega.","Muy bien, solo +tomará un momento.","Muy bien, solo va a +tomar un momento.","Hyvä on, tähän ei mene hetkeä pidempään.","Pas de problème, ça ne prendra qu'un moment.","Rendben, egy pillanat és kész.","Va bene, ci vorrà solo un momento.",いいでしょう、これは時間を取りません。,좋습니다. 시간이 오래 걸리진 않을 거예요.,"Oké, dit duurt maar een momentje.",Dette tar bare et øyeblikk.,"Dobra, to zajmie tylko chwilę.","Ok, só um momento.",,"În regulă, va dura doar un moment.","Отлично, это займёт всего пару секунд.",,"Okej, det här tar bara ett ögonblick.","Pekala, bu bir dakikadan fazla sürmez." +It's not done yet.,TXT_RNO1_SCRIPT03_D27288_ITSNO,〃 (〃),,,Ještě není hotový.,Det er ikke færdigt endnu.,Es ist noch nicht soweit.,,"Mi ankoraŭ +prilaboras ĝin.",Aún no está listo.,,Se ei ole valmis vielä.,Ce n'est pas encore terminé.,Még nincs kész.,Non è ancora pronto.,まだ完成していません。,아직 완료되지는 않았어요.,Het is nog niet klaar.,Det er ikke ferdig ennå.,Jeszcze nie jest gotowy.,Ainda não terminei.,,Încă nu e gata.,Он ещё не готов.,,Det är inte klart än.,Henüz bitmedi. +"Hey, I'm working on an updated version of your implant. Is there anything else I can do?",TXT_DLG_SCRIPT03_D28804_HEYIM,〃 (one upgrade),,,"Hej, pracuju na vylepšené verzi tvého implantátu. Můžu pro tebe udělat něco jiného?","Jeg arbejder på en opdateret version af dit implantat. Er der andet, jeg kan gøre?","He, ich arbeite an einer verbesserten Version deines Implantats. Gibt es sonst etwas, das ich für dich tun kann?",,"Mi laboras super plibonigita versio de via enplantaĵo. Ĉu estas io alia, kion mi povas fari por vi?",Estoy trabajando en una versión mejorada de tu implante. ¿Hay algo más que pueda hacer?,,"Hei, olen työstämässä päivitettyä versiota istutteestasi. Voinko olla muuten avuksi?","Hé, je travaille sur une version améliorée de l'implant. Qu'est-ce que je peux faire pour vous?",Az implantátum újabb verzióján dolgozok. Tudok még valamiben segíteni?,"Ehi, sto lavorando ad un aggiornamento per l'impianto stamina. Posso fare qualcos'altro per te?","どうも、私は今最新版のインプラントに +取り組んでいる。何か用かな?","당신의 이식 칩을 위한 향상 개조가 준비되었습니다. 그런 이유로 온게 아니면, 무엇을 도와드릴까요?","Hé, ik ben bezig met een bijgewerkte versie van je implantaat. Is er nog iets anders dat ik kan doen?",Jeg jobber med en oppdatert versjon av implantatet ditt. Er det noe annet jeg kan gjøre?,"Hej, pracuję nad ulepszoną wersją twojego implantu. Mogę coś jeszcze dla ciebie zrobić?",E aí. Estou trabalhando numa versão aprimorada do seu implante. Posso te ajudar com algo?,,"Hei, lucrez la o variantă îmbunătățită a implantului tău. Mai pot să te ajut cu ceva?","Я работаю над улучшенной версией твоего импланта. А пока, что-нибудь ещё?",,Jag jobbar på en uppdaterad version av ditt implantat. Finns det något annat jag kan göra?,"Hey, implantının güncellenmiş bir versiyonu üzerinde çalışıyorum. Yapabileceğim başka bir şey var mı?" +Patch me up.,TXT_RPLY0_SCRIPT03_D28804_PATCH,〃 (〃),,,Dej mě dohromady.,Gør mig klar.,Flick mich zusammen.,,Kuracu min.,Cúrame.,,Pistä minut kuntoon.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료가 필요합니다.,Patch me op.,Lappe meg sammen.,Opatrz mnie.,Trate meus ferimentos.,,Bandajează-mă.,Подлатай меня.,,Laga mig.,Yama yap. +Well at least your seeing action.,TXT_RYES0_SCRIPT03_D28804_WELLA,〃 (〃),,,"No, alespoň se nenudíš.",I det mindste kan du se noget.,"Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,"Nu, almenaŭ vi ne havas +enuigajn komisiojn.","Bueno, al menos estás +teniendo algo de acción.",,"No, ainakin näet toimintaa.","Eh bien, au moins vous en voyez, de l'action.",Legalább neked jut valami akció.,"Beh, almeno ti stai dando da fare.",貴方の働きは聞き届いてるよ。,이제 전장에 힘을 발휘해보세요!,"Nou ja, in ieder geval uw zien actie.",Du ser i det minste noe.,Przynajmniej będziesz mógł wrócić do akcji.,"Bem, pelo menos tá tendo um pouco de ação.",,"Eh, măcar tu ai parte de acțiune.","Что ж, зато ты участвуешь в операциях.",,Du får åtminstone se handling.,En azından hareket görüyorsun. +Implant upgrade?,TXT_RPLY1_SCRIPT03_D28804_IMPLA,〃 (〃),,,Vylepšený implantát?,Opgradering af implantater?,Implantatsupgrade?,,Ĉu plibonigo de enplantaĵo?,¿Mejora de implante?,,Istutteen päivitys?,Mise à jour de l'implant?,Implantátum fejlesztés?,Aggiornamento dell'impianto?,インプラント アップグレード?,지구력 업그레이드?,Implantaat upgrade?,Implantatoppgradering?,Ulepszenie implantu?,Versão aprimorada do implante?,,Upgrade pentru implant?,Улучшение импланта?,,Implantatuppgradering?,İmplant güncellemesi mi? +"Good thing, never can be too safe.",TXT_RYES1_SCRIPT03_D28804_GOODT,〃 (〃),,,"Dobrá věcička, nikdy si nemůžeš být moc jistý.","Godt nok, man kan aldrig være for sikker.","Alles klar, das haben wir sofort.",,"Bone. Neniam estas +sufiĉe da sekureco.","Bien. Nunca se puede +estar del todo seguro.",,"Hyvä, koskaan ei voi olla liian turvallista.",Bonne idée. On ne peut jamais être trop sûr.,"Helyes, sosem lehetünk elég elővigyázatosak.","Ottimo, non si può mai essere troppo al sicuro.",良いことだ、安全すぎることはない。,좋은 선택입니다. 이거 없이는 안전할 수가 없죠.,"Goede zaak, kan nooit te veilig zijn.","Bra, man kan aldri være for sikker.","Dobra rzecz, nigdy za mało bezpieczeństwa.",Boa idéia. Segurança nunca é demais.,,"Recomand cu mare drag, nu poți fi niciodată prea sigur.","Очень советую, ни в чём нельзя быть уверенным до конца.",,"Bra, man kan aldrig vara för säker.","İyi bir şey, asla çok güvenli olamaz." +"I'm almost finished, but not quite.",TXT_RNO1_SCRIPT03_D28804_IMALM,〃 (〃),,,"Už je skoro hotový, ale ne úplně.","Jeg er næsten færdig, men ikke helt.",Es ist noch nicht soweit.,,"Mi preskaŭ finis, +sed ne tute.","Casi he terminado, +pero no del todo.",,"Olen melkein valmis, mutten ihan vielä.","Presque fini, mais pas encore.","Már majdnem végeztem, még egy kicsi híja van.","Ho quasi finito, ma non ancora.",もうすぐ出来上がる、それほど掛からない。,"거의 다 돼가지만, 아직 완성된 게 아니에요.","Ik ben bijna klaar, maar niet helemaal.","Jeg er nesten ferdig, men ikke helt.","Prawie skończyłem, ale nie do końca.",Estou quase terminando. Só mais um pouco.,,"Sunt aproape gata, dar nu tocmai.",Я почти закончил. Ещё немного.,,"Jag är nästan klar, men inte riktigt.",Neredeyse bitirdim ama tam olarak değil. +"All right, I've almost got everything working perfectly. There were a few problems left to get rid of. Do you need anything else? ",TXT_DLG_SCRIPT03_D30320_ALLRI,〃 (two upgrades),,,"Tak dobře, už mi skoro všechno perfektně funguje. Ještě tam bylo pár problémů. Potřebuješ ještě něco?","Okay, jeg har næsten fået det hele til at fungere perfekt. Der var et par problemer tilbage at slippe af med. Har du brug for noget andet?","He, ich arbeite an einer verbesserten Version deines Implantats. Gibt es sonst etwas, das ich für dich tun kann?",,"Bone, preskaŭ ĉio funkcias perfekte. Restis nur kelkaj korektindaj problemoj. Ĉu vi bezonas ion alian?","Muy bien, tengo casi todo funcionando a la perfección. Solo quedaban algunos problemas que corregir. ¿Necesitas algo más?",,"No niin, olen melkein saanut kaiken toimimaan täydellisesti. Vain muutamia vikoja oli enää jäljellä. Tarvitsetko mitään muuta?","Très bien, je crois que j'ai réussi à tout faire marcher parfaitement. Il y avait quelques problèmes dont je devais me débarrasser. Vous voulez quelque chose?","Nos, már majdnem minden tökéletesen működik. Volt néhány kijavítandó hiba. Tudok még valamiben segíteni?","Allora, sono riuscito a far funzionare quasi tutto benissimo. C'erano giusto un paio di problemi rimasti da risolvere. Ti serve qualcos'altro?","大丈夫、全て順調だ。残っていた問題も +全て取り除かれた。他に何が必要かな?",연구가 거의 다 끝나갑니다. 연구 도중에 오류를 좀 잡았어요. 기다리는 동안 뭐 필요한 게 있나요?,"Oke, ik heb bijna alles wat perfect werkt. Er waren nog een paar problemen over om van af te komen. Heeft u nog iets anders nodig?",Jeg har nesten fått alt til å fungere perfekt. Det var et par problemer igjen å bli kvitt. Trenger du noe mer?,"Dobra, prawie wszystko działa dobrze. Zostało jeszcze parę rzeczy do zrobienia. Czy coś jeszcze potrzebujesz?","Ok, tenho quase tudo funcionando perfeitamente. Ainda faltam alguns probleminhas para tirar de você. Precisa de mais alguma coisa?",,"În regulă, totul funcționează aproape perfect. Au mai fost niște probleme care trebuiau rezolvate. Mai ai nevoie de altceva?","Итак, тут оставалась пара проблем, но теперь всё работает почти идеально. Что-нибудь ещё?",,"Okej, jag har nästan fått allt att fungera perfekt. Det fanns några problem kvar att bli av med. Behöver du något annat?","Pekala, neredeyse her şey mükemmel çalışıyor. Kurtulmam gereken birkaç sorun kaldı. Başka bir şeye ihtiyacın var mı?" +Patch me up.,TXT_RPLY0_SCRIPT03_D30320_PATCH,〃 (〃),,,Dej mě dohromady.,Lav mig om.,Flick mich zusammen.,,Kuracu min.,Cúrame.,,Paikkaa minut.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료가 필요합니다.,Patch me op.,Lapp meg sammen.,Opatrz mnie.,Trate meus ferimentos.,,Tratează-mă.,Подлатай меня.,,Laga mig.,Beni yamala. +What have you been trying to do? Go head to head with a Crusader?,TXT_RYES0_SCRIPT03_D30320_WHATH,〃 (〃),,,Co jsi dělal? Šel zmlátit Křižáka?,Hvad har du forsøgt at gøre? At gå i kamp mod en korsfarer?,"Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,"Kion vi intencis fari? +Ĉu piki Kruciston?","¿Qué has intentado hacer? +¿Ir cara a cara con un Cruzado?","¿Qué anduviste haciendo? +¿Ir cara a cara con un Cruzado?",Mitä olet oikein yrittänyt tehdä? Mennä nokittain ristiretkeläisen kanssa?,Qu'est-ce que vous avez fait? Vous avez essayé de faire ami avec un Croisé?,Mi a francot képzeltél? Egymagad nekimész egy keresztesnek?,Ma cosa hai cercato di fare? Lottare da solo contro un Crociato?,"今度は何を始めるんだ? +クルセイダーと向かい合うのか?",뭘 하다 왔나요? 크루세이더랑 한판 뜨기라도 했나요?,Wat heb je geprobeerd te doen? Hoofd aan hoofd gaan met een kruisvaarder?,Hva har du prøvd å gjøre? Kjempe mot en korsfarer?,Co ty próbowałeś zrobić? Walczyć oko w oko z Krzyżowcem?,O que você andou tentando fazer? Partiu pro soco contra um Cruzado?,,Ce ai încercat să faci? Să dai cap în cap cu un Cruciat?,Что было у тебя на уме? Биться один на один с крестоносцем?,,Vad har du försökt göra? Gå mot en korsriddare?,Ne yapmaya çalışıyordun? Bir Haçlı ile kafa kafaya mı? +Implant upgrade?.,TXT_RPLY1_SCRIPT03_D30320_IMPLA,〃 (〃),,,Vylepšený implantát?,Implantat opgradering?,Implantatsupgrade?,,Ĉu plibonigo de enplantaĵo?,¿Mejora de implante?,,Istutteen päivitys?,Mise à jour de l'implant?,Implantátum fejlesztés?,Aggiornamento dell'impianto?,インプラント アップグレード?,지구력 업그레이드?,Implantaat upgrade?,Implantatoppgradering?,Ulepszenie implantu?,Melhoria de implante?,,Upgrade pentru implant?,Улучшение импланта?,,Implantatuppgradering?,İmplant yükseltmesi mi? +That should do it for you.,TXT_RYES1_SCRIPT03_D30320_THATS,〃 (〃),,,Tohle by mělo fungovat.,Det burde gøre det for dig.,"Alles klar, das haben wir sofort.",,Ĉi tio devus esti sufiĉa.,Con esto debería estar.,,Eiköhän tällä ala tepsiä.,Ca devrait faire l'affaire.,Ez már így jó lesz.,Questo dovrebbe andare.,今取り掛かっている。,이것만 있음 될 겁니다.,Dat zou het voor u moeten doen.,Det burde gjøre det for deg.,To powinno ci wystarczyć.,Isso deve funcionar.,,Ar trebui să fie bine acum.,Вот оно.,,Det borde göra det för dig.,Bu senin işini görür. +Let me run some more tests first.,TXT_RNO1_SCRIPT03_D30320_LETME,〃 (〃),,,Ještě ho musím dál otestovat.,Lad mig køre nogle flere tests først.,Es ist noch nicht soweit.,,"Unue mi faru +kelkajn provojn.","Déjame hacer algunas +pruebas primero.",,Anna minun ajaa muutamia kokeita ensin.,Laissez moi faire quelques tests d'abord.,Hadd futtassak pár tesztet előtte.,Devo fare ancora qualche test.,もう少しテストしてからにしよう。,"우선, 시험을 좀 거쳐야 해요.",Laat me eerst nog wat testen doen.,La meg kjøre noen flere tester først.,Pozwól mi zrobić jeszcze parę testów.,Deixe eu fazer alguns testes primeiro.,,Lasă-mă să mai fac niște teste mai întâi.,Дай мне ещё времени на тесты.,,Låt mig köra några fler tester först.,Önce birkaç test daha yapayım. +That's all I can do on the implant right now. Maybe some healing?,TXT_DLG_SCRIPT03_D31836_THATS,〃 (?),,,"Tak, to je všechno co teď můžu s tím implantátem udělat. Potřebuješ léčení?","Det er alt, hvad jeg kan gøre på implantatet lige nu. Måske noget healing?","Das ist alles, was ich im Moment mit dem Implantat machen kann. Vielleicht etwas medizinische Versorgung?",,"Tio estas ĉio, kion mi momente povas fari super la enplantaĵo. Ĉu vi bezonas kuracon?",Eso es todo lo que puedo hacer con el implante por ahora. ¿Necesitas curarte?,,Tätä enempää en voi istutteelle enää juuri nyt tehdä. Mutta oletko hoidon tarpeessa?,C'est tout ce que je peux faire pour l'implant. Vous voulez que je vous soigne?,Csak ennyit tudok most kezdeni az implantátummal. Talán egy kis gyógyítás?,È tutto per quanto riguarda l'impianto. Però posso sempre curarti.,"インプラントはこれ以上ない程完成した。 +それとも治療か?",지구력 향상 관련은 이게 다입니다. 이제 치료가 좀 필요하신가요?,Dat is alles wat ik nu kan doen op het implantaat. Misschien wat genezing?,Det er alt jeg kan gjøre med implantatet akkurat nå. Kanskje litt helbredelse?,To wszystko co mogę zrobić w sprawie implantu. Może chcesz się podleczyć?,Isso é tudo que posso fazer com o implante no momento. Não quer um tratamento nesses ferimentos?,,Asta e tot ce îi pot face implantului pentru moment. Poate niște tratament?,Пока что я больше ничего не могу сделать с имплантом. Как насчёт лечения?,,Det är allt jag kan göra med implantatet just nu. Kanske lite läkning?,Şu anda implant üzerinde yapabileceğim tek şey bu. Belki biraz iyileşme? +Yeah.,TXT_RPLY0_SCRIPT03_D31836_YEAH,〃 (〃),,,Jo.,Ja.,Ja.,,Jes.,Sí.,,Kyllä.,Ouais.,Igen.,Sì.,ああ。,네.,Ja.,Ja.,Pewnie.,Pode ser.,,Da.,Давай.,,"Ja, det är det.","Evet, belki." +"Boy, you're a real mess. I'll see what I can do.",TXT_RYES0_SCRIPT03_D31836_BOYYO,〃 (〃),,,"Tebe teda zřídili, kluku. Uvidím, co s tebou.","Mand, du er et rigtigt rod. Jeg skal se, hvad jeg kan gøre.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,"Ulo, vi estas iomege en malordo. +Mi vidos tion, kion mi faru.","Tío, estás hecho un desastre. +A ver qué puedo hacer.","Chico, estás hecho un desastre. +A ver qué puedo hacer.","Kylläpä olet huonossa jamassa. Katsotaan, mitä voin tehdä.","Mon petit, vous êtes dans un sale état. Je vais voir ce que je peux faire.","Öregem, elég rossz passzban vagy. Megnézem mit tudok tenni.","Ragazzo, sei messo proprio male. Vediamo cosa posso fare.",君、滅茶苦茶だな。なんとかしよう。,심각한 부상을 입은 것 같군요. 치료하겠습니다.,"Jongen, je bent een echte puinhoop. Ik zal zien wat ik kan doen.","Jøss, du er et skikkelig rot. Jeg skal se hva jeg kan gjøre.","Chłopie, ależ ty jesteś poszarpany. Zobaczę co da się zrobić.","Rapaz, você está arrebentado. Vou ver o que posso fazer.",,"Mamă, ești un dezastru. O să văd ce pot face.","Парень, да на тебя смотреть страшно. Приступим...",,Du är en riktig röra. Jag ska se vad jag kan göra.,Çok dağınıksın. Ne yapabileceğime bir bakayım. +What can I do for you?,TXT_DLG_SCRIPT03_D33352_WHATC,MAP03: Feris (no training).,,,Co pro tebe můžu udělat?,Hvad kan jeg gøre for dig?,Was kann ich für dich tun?,,Kion mi faru por vi?,¿Qué puedo hacer por ti?,,Mitä voin tehdä sinulle?,Que puis-je faire pour vous?,Miben segíthetek?,Cosa posso fare per te?,どういったご用件で?,필요한 게 있으면 말씀하세요.,Wat kan ik voor je doen?,Hva kan jeg gjøre for deg?,Co mogę dla ciebie zrobić?,Como posso te ajudar?,,Ce pot face pentru tine?,Чем я могу тебе помочь?,,Vad kan jag göra för dig?,Senin için ne yapabilirim? +I'm out of bullets.,TXT_RPLY0_SCRIPT03_D33352_IMOUT,〃 (〃),,,Došly mi náboje.,Jeg er løbet tør for kugler.,Ich habe keine Munition mehr.,,Mi ne havas kuglojn.,No me quedan balas.,,Minulta on luodit loppu.,Je suis à cours de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Jeg er tom for kuler.,Nie mam nabojów.,Estou sem balas.,,Nu mai am gloanțe.,У меня кончились патроны.,,Jag har slut på kulor.,Mermim bitti. +Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT03_D33352_HERES,〃 (〃),,,"Tady máš nějakou munici, neplýtvej s ní.",Her er noget ammunition til dig. Spild det ikke.,Hier hast du welche. Verschwende sie nicht.,,"Jen iom da municio. +Ne malŝparu ĝin.","Aquí tienes algo de munición. +No la desperdicies.",,Tässä sinulle panoksia. Älä tuhlaa niitä.,"En voilà pour vous, ne les gaspillez pas.",Itt van egy kis muníció számodra. Ne pazarold el.,Ecco un po' di munizioni per te. Non sprecarle.,この弾をどうぞ、無駄遣いしないように。,여기 조금의 탄약을 나눠줄게요. 낭비하지 마시길.,Hier is wat munitie voor je. Verspil het niet.,Her er litt ammunisjon til deg. Ikke sløs den bort.,Masz tu trochę amunicji. Nie zmarnuj jej.,Tome um pouco de munição. Não desperdice.,,Uite niște muniție. N-o risipi.,Можешь взять немного. Не трать их понапрасну.,,Här är lite ammunition till dig. Slösa inte bort den.,Al sana biraz mermi. Boşa harcama. +Teach me.,TXT_RPLY1_SCRIPT03_D33352_TEACH,〃 (〃),,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Mutasd meg.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Ucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +"All right, I'll just show you a few little pointers.",TXT_RYES1_SCRIPT03_D33352_ALLRI,〃 (〃),,,"Dobře, ukážu ti pár triků.","Okay, jeg vil bare vise dig et par små tips.","Alles klar, ich zeige dir ein paar Kniffe.",,"Bone, jen kelkaj konsiletoj...","Muy bien, aquí van +un par de consejos...",,"Hyvä on, annan sinulle vain muutamia pikkuvinkkejä.",Pas de problème. Laissez moi vous montrer quelques trucs.,Akkor addok pár hasznos tanácsot.,"Va bene, ti darò un paio di dritte molto utili.",わかった、貴方にやり方を幾つか教えよう。,좋아요. 훈련에 도움이 될 만한 표적을 보여주겠습니다.,"Oké, ik zal je gewoon een paar kleine tips laten zien.","Greit, jeg skal bare vise deg noen små tips.","Dobrze, podam ci parę wskazówek.","Ok, vou te dar algumas dicas.",,"În regulă, o să îți arăt niște repere.",Хорошо. Покажу тебе пару приёмов.,,"Okej, jag ska bara visa dig några små tips.","Pekala, sana birkaç küçük ipucu göstereceğim." +You're not ready yet.,TXT_RNO1_SCRIPT03_D33352_YOURE,〃 (〃),,,Ještě nejsi připravený.,Du er ikke klar endnu.,Du bist noch nicht so weit.,,"Vi ankoraŭ +ne estas preta.",Aún no estás listo.,,Et ole vielä valmis.,Vous n'êtes pas encore prêt.,Még nem állsz készen.,Non sei ancora pronto.,貴方の準備がまだ整ってないように思えます。,아직 준비가 안 됐어요.,Je bent nog niet klaar.,Du er ikke klar ennå.,Nie jesteś jeszcze gotowy.,Você ainda não está pronto.,,Nu ești pregătit încă.,Ты ещё не готов.,,Du är inte redo än.,Henüz hazır değilsin. +Back again? What do you need?,TXT_DLG_SCRIPT03_D34868_BACKA,〃 (one training),,,Zase zpátky? Co potřebuješ?,Tilbage igen? Hvad har du brug for?,Scxhon zurück? Was brauchst du?,,Do vi revenis. Kion vi bezonas?,¿Ya de vuelta? ¿Qué necesitas?,,Täällä taas? Mitä tarvitset?,Déjà de retour? De quoi avez-vous besoin?,Már vissza is tértél? Mire van szükséged?,Già di ritorno? Che cosa ti serve?,もう戻りましたか?何が必要ですか?,또 왔네? 뭐가 필요합니까?,Weer terug? Wat heb je nodig?,Tilbake igjen? Hva trenger du?,Wróciłeś? Czego chcesz?,Você novamente? Do que precisa?,,Te-ai întors iar? De ce ai nevoie?,Ты вернулся? Что тебе нужно?,,Tillbaka igen? Vad behöver du?,Yine mi? Neye ihtiyacın var? +I'm out of bullets.,TXT_RPLY0_SCRIPT03_D34868_IMOUT,〃 (〃),,,Došly mi náboje.,Jeg er løbet tør for kugler.,Ich habe keine Munition mehr.,,Mi ne havas kuglojn.,No me quedan balas.,,Minulta on ammukset loppu.,Je suis à cours de munitions.,Kifogytam a golyókból.,Ho finito le munizioni.,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Jeg er tom for kuler.,Nie mam nabojów.,Estou sem balas.,,Nu mai am gloanțe.,У меня кончились патроны.,,Jag har slut på kulor.,Mermim bitti. +Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT03_D34868_HERES,〃 (〃),,,"Tady máš nějakou munici, neplýtvej s ní.",Her er lidt ammunition til dig. Spild det ikke.,Hier hast du welche. Verschwende sie nicht.,,"Jen iom da municio. +Ne malŝparu ĝin.","Aquí tienes algo de munición. +No la desperdicies.",,Tässä vähän lisää. Älä haaskaa niitä.,"En voilà pour vous, ne les gaspillez pas.",Itt van egy kis muníció számodra. Ne pazarold el.,Ecco un po' di munizioni per te. Non sprecarle.,この弾をどうぞ、無駄遣いしないように。,뭘 하다 탄약을 낭비한 겁니까? 여기 조금 줄게요.,Hier is wat munitie voor je. Verspil het niet.,Her er litt ammunisjon til deg. Ikke sløs den bort.,Masz tu trochę amunicji. Nie zmarnuj jej.,Tome um pouco de munição. Não desperdice.,,Uite niște muniție. N-o risipi.,Можешь взять немного. Не трать их понапрасну.,,Här är lite ammunition till dig. Slösa inte bort den.,İşte sana biraz cephane. Boşa harcama. +You've got enough ammo.,TXT_RNO0_SCRIPT03_D34868_YOUVE,〃 (〃),,,Vždyť jich máš dost.,Du har ammunition nok.,Du hast genug.,,Vi havas sufiĉe da municio.,Tienes suficiente munición.,,Sinulla on riittävästi ammuksia.,Vous avez assez de munitions.,Van elég lőszered.,Ma veramente ne hai a sufficienza.,弾は十分に見えます。,당신은 충분한 탄약을 가졌어요.,Je hebt genoeg munitie.,Du har nok ammunisjon.,Masz już wystarczająco dużo amunicji.,Você já tem munição o suficiente.,,Au destulă muniție.,У тебя их достаточно.,,Du har tillräckligt med ammunition.,Yeterince mermin var. +Teach me.,TXT_RPLY1_SCRIPT03_D34868_TEACH,〃 (〃),,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Mutasd meg.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Ucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +"All right, this should keep you going for a while.",TXT_RYES1_SCRIPT03_D34868_ALLRI,〃 (〃),,,"Dobře, tohle by ti mělo pomoct.","Okay, det her burde holde dig i gang et stykke tid.","Alles klar, das sollte fürs erste reichen.",,"Bone, ĉi tio devus esti +sufiĉe utila nuntempe.","Muy bien, esto debería +servirte por el momento.",,"Selvä on, tällä sinun pitäisi pötkiä aika pitkälle.","Bien, ça devrait vous suffir pour un bon moment.","Rendben van, ezzel el leszel egy darabig.","Va bene, con questo dovresti andare sul sicuro per un po'.",わかりました、これで長くやり合えるでしょう。,그렇군요. 가능한 오래 싸울 수 있을겁니다.,"Oké, dit zou je een tijdje op de been moeten houden.","Greit, dette burde holde deg gående en stund.","Dobrze, to powinno ci pomóc na pewien czas.","Ok, isso deve te ajudar no momento.",,"În regulă, asta ar trebui să te ajute pentru moment.","Хорошо, это не раз спасёт тебе жизнь.",,"Okej, det här borde hålla dig igång ett tag.","Pekala, bu seni bir süre idare eder." +"Sorry, can't. I'm just following Macil's orders.",TXT_RNO1_SCRIPT03_D34868_SORRY,〃 (〃),,,"Promiň, nemůžu. Řídím se rozkazy od Macila.","Beklager, jeg kan ikke. Jeg følger bare Macils ordrer.","Tut mir leid, aber ich kann nicht. Ich folge nur Macils Befehlen.",,"Pardonon, mi ne rajtas. +Mi nur observas Macil-on.","Lo siento, no puedo. +Solo sigo órdenes de Macil.",,Valitettavasti en voi. Noudatan vain Macilin käskyjä.,"Désolé, pas possible. Je ne fais que suivre les ordres de Macil.","Sajnálom, de nem tehetem. Macil utasítása.","Mi spiace, ma non posso. Ordini dall'alto.",すまないが、できません。マシルの命令です。,미안합니다. 마실 사령관님의 명령을 따라야해요.,"Sorry, dat kan niet. Ik volg gewoon de orders van Macil op.","Beklager, jeg kan ikke. Jeg følger bare Macils ordre.","Przepraszam, ale nie mogę. Ja tylko wykonuję rozkazy Macila.",Desculpe mas não posso. Estou apenas seguindo as ordens de Macil.,,"Scuze, nu merge. Doar urmez ordinele lui Macil.","Увы, не могу. Я подчиняюсь Мэйсилу.",,"Tyvärr, jag kan inte. Jag följer bara Macils order.","Üzgünüm, yapamam. Macil'in emirlerini uyguluyorum." +"Well which is it, bullets or training? I can't wait to get my hands on those new weapons we captured. A little bit of training and then a lot of revenge.",TXT_DLG_SCRIPT03_D36384_WELLW,〃 (two trainings),,,"Tak co to bude, náboje nebo trénink? Nemůžu se dočkat, až se dostanu k těm novým zbraním, které jsme zabavili. Trocha cvičení a pak hodně odplaty.","Nå, hvad er det, kugler eller træning? Jeg kan ikke vente med at få fingrene i de nye våben, vi har taget til fange. En lille smule træning og så en masse hævn.","Also, was willst du? Munition oder Training? Ich kann kaum erwarten, diese neuen Waffen, die wir erbeutet haben, in die Finger zu kriegen. ein bisschen Training und dann jede Menge Vergeltung.",,"Nu, ĉu kugloj aŭ trejnado ĉi-foje? Mi sopire atendas provi tiujn novajn kaptitajn armilojn. Iom da trejnado kaj tiam multe da venĝo.","Bueno, ¿qué va a ser?, ¿balas o entrenamiento? No puedo esperar a poner mis manos en esas nuevas armas que hemos capturado. Un poco de entrenamiento y luego mucha venganza.","Bueno, ¿qué va a ser?, ¿balas o entrenamiento? No puedo esperar a poner mis manos en esas nuevas armas que capturamos. Un poco de entrenamiento y luego mucha venganza.","No niin, kumpaa saisi olla: luoteja vai koulutusta? En voi malttaa olla tarttumasta vasta kaappaamiimme aseisiin. Hieman perehdytystä, ja sitten paljon kostamista.","Qu'est-ce qu'il vous faut? Des munitions ou de l'entraînement? J'ai hâte d'essayer ces nouvelles armes que l'on a capturé, un peu d'entraînement et beaucoup de vengeance.","Akkor döntsd el, lőszer vagy kiképzés? Már alig várom hogy rátegyem a kezem a lefoglalt fegyverekre. Egy kis kiképzés, és jó sok bosszú.","Bene, che cosa ti serve, munizioni o addestramento? Non vedo l'ora di mettere le mani su quelle nuove armi che abbiamo preso. Un po' di addestramento e poi molta vendetta.","弾薬と訓練、どっちの用件ですか? 奪った新しい武器が届くのを待ち切れないです。 -少しの訓練でデカい復讐を。","무엇을 원하십니까? 보급? 아니면 훈련? 방금 전달된 새로운 무기들을 만지고 싶습니다! 아무튼, 훈련을 거치면 복수를 멋지게 해내실 거에요.","Wat is het dan wel, kogels of training? Ik kan niet wachten om die nieuwe wapens in handen te krijgen die we gevangen genomen hebben. Een beetje training en dan veel wraak.","Więc czego chcesz, naboje czy trening? Nie mogę się doczekać, aż dostanę jedną z tych nowych broni, które udało nam się przejąć. Trochę treningu, a potem zemsta.","Bem, o que vai ser? Munição ou treinamento? Mal posso esperar para pegar nessas novas armas que capturamos. Um pouquinho de treinamento e depois muita vingança.",,,"Что скажешь, патроны или тренировка? Мне не терпится опробовать это новое трофейное оружие. Небольшая подготовка, и они за всё заплатят.", -I'm out of ammo.,TXT_RPLY0_SCRIPT03_D36384_IMOUT,,,,Došly mi náboje.,Ich habe keine Munition mehr.,,,No me quedan balas.,,,Je suis à cours de munitions.,,,弾切れだ。,탄약이 떨어졌어요.,Ik heb geen munitie meer.,Nie mam amunicji.,Estou sem munição.,,,У меня кончились боеприпасы., -Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT03_D36384_HERES,,,,"Tady máš nějakou munici, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,Aquí tienes algo de munición. No la desperdicies.,,,"En voilà pour vous, ne les gaspillez pas.",,,この弾をどうぞ、無駄遣いしないように。,여기 탄약입니다. 부디 열심히 싸우고 정확하게 쏘시길.,Hier is wat munitie voor je. Verspil het niet.,Masz tu trochę amunicji. Nie zmarnuj jej.,Tome um pouco de munição. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -You've got enough ammo.,TXT_RNO0_SCRIPT03_D36384_YOUVE,,,,Vždyť jich máš dost.,Du hast genug.,,,Tienes suficiente munición.,,,Vous avez assez de munitions.,,,弾は十分に見えます。,거짓말. 탄약을 충분히 가졌잖아요.,Je hebt genoeg munitie.,Masz już wystarczająco dużo amunicji.,Você já tem munição o suficiente.,,,У тебя хватает патронов., -Teach me.,TXT_RPLY1_SCRIPT03_D36384_TEACH,,,,Uč mě.,Unterrichte mich.,,,Entréname.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,Ucz mnie.,Me ensine.,,,Обучи меня., -O.K. Take what you've learned here and show those Order clods the way to hell.,TXT_RYES1_SCRIPT03_D36384_OKTAK,,,,"Oukej. Pamatuj, co ses tady naučil, a ukaž těm hajzlům z Řádu cestu do pekla.","OK. Nutze, was du hier gelernt hast um diesen Tölpeln vom Orden den Weg in die Hölle zu zeigen.",,,OK. Toma lo que has aprendido y muéstrales a esos patanes de la Orden el camino al infierno.,,,OK. Utilisez ce que vous avez appris et envoyez ces abrutis de l'Ordre en enfer.,,,"オーケー、ここで学んだ事を生かして -オーダー共を地獄に送って上げなさい。",좋아요! 훈련을 통해서 얻은 실력으로 저 오더 돌대가리들을 박살을 내버려요!,"Oké, neem wat je hier geleerd hebt en laat die Ordekluiten de weg naar de hel zien.",Ok. Bierz to czego się nauczyłeś i pokaż tym durniom z Zakonu drogę do piekła.,Ok. Use o que você aprendeu aqui para mostrar o caminho pro inferno a esses desgraçados da Ordem.,,,"Запоминай внимательно, покажешь этим прихвостням Ордена быструю дорогу в ад.", -"Come back later, when Macil says it's time.",TXT_RNO1_SCRIPT03_D36384_COMEB,,,,"Přijď někdy jindy, až řekne Macil.","Komm wieder, wenn Macil dir Bescheid gibt.",,,"Vuelve más tarde, cuando Macil diga que es la hora.",,,Revenez plus tard quand Macil décide qu'il est temps.,,,マシルの命令を受けてから、また来なさい。,사령관님은 인내심이 많은 분입니다. 나중에 확인해주시길.,"Kom later terug, als Macil zegt dat het tijd is.","Przyjdź później, kiedy Macil powie, że już czas.","Volte mais tarde, quando Macil disser que está na hora.",,,"Приходи позже, когда прикажет Мэйсил.", -I've taught you everything I can right now. Give me some time to put the new weapons through their paces. That is unless you're out of bullets.,TXT_DLG_SCRIPT03_D37900_IVETA,,,,"Naučil jsem tě vše, co teď můžu. Dej mi nějaký čas, abych vyzkoušel ty nové zbraně. Jedině, že bys potřeboval náboje.","Ich habe dir alles gezeigt, was ich momentan kann. Gib mir etwas Zeit um die neuen Waffen zu testen. Munition kriegst du natürlich auch so.",,,"Te he enseñado todo lo que puedo por ahora. Dame un tiempo para poner las nuevas armas a punto. Claro está, si no es que te has quedado sin balas.",,,"Je vous ai enseigné tout ce que je sais. Laissez moi un peu de temps pour tester ces nouvelles armes. Sauf si vous n'avez plus de munitions, bien sûr.",,,"私が教えられる事はもうありません。 +少しの訓練でデカい復讐を。","무엇을 원하십니까? 보급? 아니면 훈련? 방금 전달된 새로운 무기들을 만지고 싶습니다! 아무튼, 훈련을 거치면 복수를 멋지게 해내실 거에요.","Wat is het dan wel, kogels of training? Ik kan niet wachten om die nieuwe wapens in handen te krijgen die we gevangen genomen hebben. Een beetje training en dan veel wraak.","Hva er det, kuler eller trening? Jeg gleder meg til å få tak i de nye våpnene vi tok. Litt trening, og så mye hevn.","Więc czego chcesz, naboje czy trening? Nie mogę się doczekać, aż dostanę jedną z tych nowych broni, które udało nam się przejąć. Trochę treningu, a potem zemsta.","Bem, o que vai ser? Munição ou treinamento? Mal posso esperar para pegar nessas novas armas que capturamos. Um pouquinho de treinamento e depois muita vingança.",,"Deci ce alegi, gloanțe sau antrenament? Abia aștept să pun mâna pe noile arme pe care le-am capturat. Puțin antrenament, iar apoi multă răzbunare.","Что скажешь, патроны или тренировка? Мне не терпится опробовать это новое трофейное оружие. Небольшая подготовка, и они за всё заплатят.",,"Vad är det, kulor eller träning? Jag kan inte vänta på att få ta del av de nya vapnen som vi tog till fånga. Lite träning och sedan en massa hämnd.","Hangisi, mermi mi eğitim mi? Yakaladığımız yeni silahları elime almak için sabırsızlanıyorum. Biraz eğitim ve sonra bolca intikam." +I'm out of ammo.,TXT_RPLY0_SCRIPT03_D36384_IMOUT,〃 (〃),,,Došly mi náboje.,Jeg er løbet tør for ammunition.,Ich habe keine Munition mehr.,,Mi estas sen municio.,No me queda munición.,,Minulta on panokset loppu.,Je suis à cours de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾切れだ。,탄약이 떨어졌어요.,Ik heb geen munitie meer.,Jeg er tom for ammunisjon.,Nie mam amunicji.,Estou sem munição.,,Nu mai am muniție.,У меня кончились боеприпасы.,,Jag har slut på ammunition.,Cephanem bitti. +Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT03_D36384_HERES,〃 (〃),,,"Tady máš nějakou munici, neplýtvej s ní.",Her er noget ammunition til dig. Spild det ikke.,Hier hast du welche. Verschwende sie nicht.,,"Jen iom da municio. +Ne malŝparu ĝin.","Aquí tienes algo de munición. +No la desperdicies.",,Tässä ammuksia. Älä tuhlaa niitä.,"En voilà pour vous, ne les gaspillez pas.",Itt van egy kis muníció számodra. Ne pazarold el.,Ecco un po' di munizioni per te. Non sprecarle.,この弾をどうぞ、無駄遣いしないように。,여기 탄약입니다. 부디 열심히 싸우고 정확하게 쏘시길.,Hier is wat munitie voor je. Verspil het niet.,Her er litt ammunisjon til deg. Ikke sløs den bort.,Masz tu trochę amunicji. Nie zmarnuj jej.,Tome um pouco de munição. Não desperdice.,,Uite niște muniție. N-o risipi.,Можешь взять немного. Не трать их понапрасну.,,Här är lite ammunition till dig. Slösa inte bort den.,İşte sana biraz cephane. Boşa harcama. +You've got enough ammo.,TXT_RNO0_SCRIPT03_D36384_YOUVE,〃 (〃),,,Vždyť jich máš dost.,Du har ammunition nok.,Du hast genug.,,Vi havas sufiĉe da municio.,Tienes suficiente munición.,,Sinulla on riittävästi ammuksia.,Vous avez assez de munitions.,Van elég lőszered.,Ma veramente ne hai a sufficienza.,弾は十分に見えます。,거짓말. 탄약을 충분히 가졌잖아요.,Je hebt genoeg munitie.,Du har nok ammunisjon.,Masz już wystarczająco dużo amunicji.,Você já tem munição o suficiente.,,Ai destulă muniție.,У тебя хватает патронов.,,Du har tillräckligt med ammunition.,Yeterince cephanen var. +Teach me.,TXT_RPLY1_SCRIPT03_D36384_TEACH,〃 (〃),,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Mutasd meg.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Ucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +O.K. Take what you've learned here and show those Order clods the way to hell.,TXT_RYES1_SCRIPT03_D36384_OKTAK,〃 (〃),,,"Oukej. Pamatuj, co ses tady naučil, a ukaž těm hajzlům z Řádu kudy do pekla.","O.K. Tag det, du har lært her, og vis de ordensklodser vejen til helvede.","OK. Nutze, was du hier gelernt hast um diesen Tölpeln vom Orden den Weg in die Hölle zu zeigen.",,"Bone. Uzu ĉi tion por gvidi tiujn +aĉulojn de La Ordeno al la infero.","Bien. Usa lo aprendido para guiar a esos +majaderos de La Orden al infierno.","Bien. Usa lo aprendido para guiar a esos +desgraciados de La Orden al infierno.","OK. Hyödynnä täällä oppimaasi, ja näytä niille Veljeskunnan valopäille tie helvettiin.",OK. Utilisez ce que vous avez appris et envoyez ces abrutis de l'Ordre en enfer.,Akkor rendben is vagyunk. Mutasd meg a Rend barmainak hol lakik az isten.,O.K. Usa ciò che hai imparato qua per mostrare all'Ordine la via dell'Inferno.,"オーケー、ここで学んだ事を生かして +オーダー共を地獄に送って上げなさい。",좋아요! 훈련을 통해서 얻은 실력으로 저 오더 돌대가리들을 박살을 내버려요!,"Oké, neem wat je hier geleerd hebt en laat die Ordekluiten de weg naar de hel zien.","OK. Ta det du har lært her, og vis de ordenstullingene veien til helvete.",Ok. Bierz to czego się nauczyłeś i pokaż tym durniom z Zakonu drogę do piekła.,Ok. Use o que você aprendeu aqui para mostrar o caminho pro inferno a esses desgraçados da Ordem.,,În regulă. Folosește ce ai învățat aici si aratăle nătărăilor din Ordin calea spre infern.,"Запоминай внимательно, покажешь этим прихвостням Ордена быструю дорогу в ад.",,O.K. Ta det du lärt dig här och visa de där ordenskloddarna vägen till helvetet.,Tamam. Burada öğrendiklerini al ve o tarikatçılara cehenneme giden yolu göster. +"Come back later, when Macil says it's time.",TXT_RNO1_SCRIPT03_D36384_COMEB,〃 (〃),,,"Přijď někdy jindy, až řekne Macil.","Kom tilbage senere, når Macil siger, det er tid.","Komm wieder, wenn Macil dir Bescheid gibt.",,"Revenu post kiam +Macil ordonis tion.","Vuelve más tarde cuando +Macil diga que ya es la hora.",,"Palaa asiaan myöhemmin, kun Macil näyttää vihreää valoa.",Revenez plus tard quand Macil décide qu'il est temps.,"Gyere vissza akkor, ha azt mondja Macil hogy ideje van.","Ritorna più tardi, quando Macil dirà che è il momento.",マシルの命令を受けてから、また来なさい。,사령관님은 인내심이 많은 분입니다. 나중에 확인해주시길.,"Kom later terug, als Macil zegt dat het tijd is.","Kom tilbake senere, når Macil sier det er på tide.","Przyjdź później, kiedy Macil powie, że już czas.","Volte mais tarde, quando Macil disser que está na hora.",,"Revin-o mai târziu, când Macil spune că e timpul.","Приходи позже, когда прикажет Мэйсил.",,"Kom tillbaka senare, när Macil säger att det är dags.",Macil zamanı geldiğini söylediğinde geri gel. +I've taught you everything I can right now. Give me some time to put the new weapons through their paces. That is unless you're out of bullets.,TXT_DLG_SCRIPT03_D37900_IVETA,〃 (three trainings),,,"Naučil jsem tě vše, co teď můžu. Dej mi nějaký čas, abych vyzkoušel ty nové zbraně. Jedině, že bys potřeboval náboje.","Jeg har lært dig alt, hvad jeg kan lige nu. Giv mig lidt tid til at sætte de nye våben på prøve. Medmindre du er løbet tør for kugler.","Ich habe dir alles gezeigt, was ich momentan kann. Gib mir etwas Zeit um die neuen Waffen zu testen. Munition kriegst du natürlich auch so.",,"Mi instruis al vi ĉion, kion mi ĉi-momente povas. Donu tempon al mi por elprovi la novajn armilojn... krom se vi nur bezonas pliajn kuglojn.","Te he enseñado todo lo que puedo por ahora. Dame tiempo para probar al 100% las nuevas armas... a menos que solo necesites más balas, claro.","Ya te enseñé todo lo que puedo por ahora. Dame tiempo para probar al 100% las nuevas armas... a menos que solo necesites más balas, claro.","Olen opettanut sinulle kaiken, mitä itse juuri nyt osaan. Anna minulle vähän aikaa käydä läpi uusien aseiden askelkuvioita. Ellei sinulla sitten ole luodit lopussa.","Je vous ai enseigné tout ce que je sais. Laissez moi un peu de temps pour tester ces nouvelles armes. Sauf si vous n'avez plus de munitions, bien sûr.","Megtanítottam mindent amit jelenleg tudtam. Adj egy kis időt, hogy leteszteljem a fegyvereket. Kivétel persze ha lőszer kell.",Ti ho insegnato tutto quello che potevo per ora. Dammi dell'altro tempo per mettere le nuove armi alla prova. A meno che non ti servano altre munizioni.,"私が教えられる事はもうありません。 今後新しい武器は時間が掛かるが自分のペースで -学びなさい。弾切れでなければの話ですが。",제가 제공할 수 있을 만큼의 훈련을 배우셨습니다. 부디 무기를 다룰 시간을 주세요. 보급 때문에 찾아오신 게 아니라면 말이죠.,Ik heb je alles geleerd wat ik nu kan. Geef me wat tijd om de nieuwe wapens op de proef te stellen. Tenzij je geen kogels meer hebt.,"Nauczyłem cię wszystkiego co mogę na chwilę obecną. Daj mi trochę czasu, aby przetestować nowe bronie. No chyba, że brakuje ci nabojów.",Já te ensinei tudo o que pude. Me dê um tempo para eu testar as novas armas. A não ser que você esteja sem munição.,,,Пока что я не могу научить тебя ничему новому. Дай мне время разобраться в этом новом оружии. Или у тебя закончились патроны?, -Yes I am.,TXT_RPLY0_SCRIPT03_D37900_YESIA,,,,"Ano, potřebuju.","Ja, bin ich.",,,Eso mismo.,,,"En effet, je le suis.",,,ああ、そうだ。,알겠습니다. 그럼 탄약이라도?,"Ja, dat ben ik wel.",Zgadza się.,"Sim, estou.",,,"Да, закончились.", -Here you go.,TXT_RYES0_SCRIPT03_D37900_HEREY,,,,Tady máš.,Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,どうぞ。,여기 있어요!,Alsjeblieft.,Masz.,Aqui está.,,,Держи., -Don't get trigger happy in the town. You'll set off the alarm and they'll start sending in guards from the castle. ,TXT_DLG_SCRIPT03_D39416_DONTG,,,,Ať tě nenapadne střílet ve městě. Spustil bys poplach a přivolal stráže z hradu.,"Fang nicht an, hier in der Stadt herumzuballern. Wenn du hier den Alarm auslöst, senden sie gleich die Truppen aus der Burg.",,,No te líes a tiros en el pueblo. Activarás las alarmas y empezarán a enviar guardias desde el castillo.,,,Ne tirez pas partout en ville. Vous risquez de déclencher l'alarme et ils enverront tous les gardes du château à vos trousses.,,,"街の中で銃をバンバン撃ったりするんじゃないぞ +学びなさい。弾切れでなければの話ですが。",제가 제공할 수 있을 만큼의 훈련을 배우셨습니다. 부디 무기를 다룰 시간을 주세요. 보급 때문에 찾아오신 게 아니라면 말이죠.,Ik heb je alles geleerd wat ik nu kan. Geef me wat tijd om de nieuwe wapens op de proef te stellen. Tenzij je geen kogels meer hebt.,Jeg har lært deg alt jeg kan nå. Gi meg litt tid til å teste de nye våpnene. Med mindre du er tom for kuler.,"Nauczyłem cię wszystkiego co mogę na chwilę obecną. Daj mi trochę czasu, aby przetestować nowe bronie. No chyba, że brakuje ci nabojów.",Já te ensinei tudo o que pude. Me dê um tempo para eu testar as novas armas. A não ser que você esteja sem munição.,,Te-am învățat tot ce stiu. Dă-mi niște timp să pun noile arme la treabă. Asta dacă nu ai rămas fără gloanțe.,Пока что я не могу научить тебя ничему новому. Дай мне время разобраться в этом новом оружии. Или у тебя закончились патроны?,,Jag har lärt dig allt jag kan just nu. Ge mig lite tid att sätta de nya vapnen på prov. Det vill säga om du inte har slut på kulor.,Şu anda sana öğretebileceğim her şeyi öğrettim. Yeni silahları denemem için bana biraz zaman ver. Tabii mermin bitmediyse. +Yes I am.,TXT_RPLY0_SCRIPT03_D37900_YESIA,〃 (〃),,,"Ano, potřebuju.","Ja, det er jeg.","Ja, bin ich.",,Ĝuste.,Eso mismo.,,Kyllä on.,"En effet, je le suis.","Igen, az vagyok.",Sì che mi servono.,ああ、そうだ。,알겠습니다. 그럼 탄약이라도?,"Ja, dat ben ik wel.","Ja, det er jeg.",Zgadza się.,"Sim, estou.",,"Da, am rămas fără.","Да, закончились.",,"Ja, det är jag.","Evet, bitti." +Here you go.,TXT_RYES0_SCRIPT03_D37900_HEREY,〃 (〃),,,Tady máš.,Værsgo.,Bitteschön.,,Jen.,Toma.,,"Tässä, ole hyvä.",Voilà pour vous.,Parancsolj.,Ecco qua.,どうぞ。,여기 있어요!,Alsjeblieft.,Vær så god.,Masz.,Aqui está.,,Iată.,Держи.,,Här har du.,Al bakalım. +Don't get trigger happy in the town. You'll set off the alarm and they'll start sending in guards from the castle. ,TXT_DLG_SCRIPT03_D39416_DONTG,MAP03: Upstairs.,,,Ať tě nenapadne střílet ve městě. Spustil bys poplach a přivolal stráže z hradu.,"Bliv ikke skydeglad i byen. Du vil udløse alarmen, og de vil sende vagter fra slottet.","Fang nicht an, hier in der Stadt herumzuballern. Wenn du hier den Alarm auslöst, senden sie gleich die Truppen aus der Burg.",,Ne uzu pafilon en la urbo; vi ekagigus la alarmon kaj ili eksendus gardistojn el la kastelo.,"No te líes a tiros en el pueblo, que activarás la alarma y empezarán a enviar guardias desde el castillo.","No andes a los tiros en el pueblo, que vas a activar la alarma y van a empezar a mandar guardias desde el castillo.","Älä ala turhan liipaisinherkäksi kaupungilla. Aiheutat vielä hälytyksen, ja ne alkavat lähettää linnasta vartijoita.",Ne tirez pas partout en ville. Vous risquez de déclencher l'alarme et ils enverront tous les gardes du château à vos trousses.,"Ne keresd a bajt a városban. Beindítod a riasztót, és kiküldik érted a kastély őröket.",Non ti consiglio di avere il grilletto facile in città. Finiresti per attivare l'allarme e inizierebbero a mandare guardie dal castello.,"街の中で銃をバンバン撃ったりするんじゃないぞ 警報を鳴らしてしまえば、奴等が衛兵共を -城から送り込んでくるぞ。","아무 마을에서나 총을 갈겨대지 마세요. 알람을 울릴 거고, 성안에 있는 병력을 다 끄집어내서라도 당신을 잡을 테니까요.",Laat de trekker niet gelukkig worden in de stad. Je laat het alarm afgaan en ze sturen bewakers van het kasteel naar binnen.,Nie bądź taki impulsywny na mieście. Włączysz alarm i zaczną po ciebie wysyłać straże z zamku.,Não fique atirando por toda parte na cidade. Você vai ativar o alarme e eles mandarão os guardas do castelo.,,,"Когда будешь в городе, не стреляй направо и налево. Если ты поднимешь тревогу, они вызовут подкрепление из замка.", -"Welcome, we can always use more help.",TXT_DLG_SCRIPT03_D40932_WELCO,,,,"Vítej, pomoc se nám vždycky hodí.","Willkommen, wir können immer etwas Hilfe gebrauchen.",,,"Bienvenido, siempre nos viene bien algo más de ayuda.",,,Bienvenue. Nous apprécions toute l'aide que nous pouvons recevoir.,,,ようこそ、我々が貴方の助けに成ります。,환영합니다. 당신 같은 사람들이 더 있었더라면...,"Welkom, we kunnen altijd meer hulp gebruiken.","Witaj, każda pomoc się przyda.",Seja bem-vindo. Qualquer ajuda é sempre bem-vinda.,,,Добро пожаловать. Нам всегда пригодится помощь., -"When I was still in action we had the chance to examine an acolyte before the reinforcements arrived. Listen, they're not human.",TXT_DLG_SCRIPT03_D42448_WHENI,,,,"Když jsem byl ještě v akci, měli jsme možnost prozkoumat mrtvého akolytu předtím, než přišly posily. Poslyš, nejsou to lidé.","Als ich noch aktiv war, hatten wir mal die Möglichkeit, einen der Ministranten zu untersuchen, bevor Verstärkung eintraf. Hör zu, sie sind nicht menschlich!",,,"Cuando aún estaba en acción tuvimos la oportunidad de examinar a un acólito antes de que llegaran los refuerzos. Escucha, no son humanos.",,,"Quand j'étais encore en service, j'ai eu l'opportunité d'examiner un acolyte avant que les renforts n'arrivent. Vous savez, ils ne sont pas humains.",,,"私がまだ活動していた時、我々が増援に +城から送り込んでくるぞ。","아무 마을에서나 총을 갈겨대지 마세요. 알람을 울릴 거고, 성안에 있는 병력을 다 끄집어내서라도 당신을 잡을 테니까요.",Laat de trekker niet gelukkig worden in de stad. Je laat het alarm afgaan en ze sturen bewakers van het kasteel naar binnen.,"Ikke bli skyteglad i byen. Du utløser alarmen, og de vil sende inn vakter fra slottet.",Nie bądź taki impulsywny na mieście. Włączysz alarm i zaczną po ciebie wysyłać straże z zamku.,Não fique atirando por toda parte na cidade. Você vai ativar o alarme e eles mandarão os guardas do castelo.,,Nu deveni încântat să apeși pe trăgaci în oraș. Vor declanșa alarma și vor trimite gardieni din castel.,"Когда будешь в городе, не стреляй направо и налево. Если ты поднимешь тревогу, они вызовут подкрепление из замка.",,Bli inte skjutglad i stan. Du kommer att utlösa larmet och de kommer att skicka in vakter från slottet.,Kasabada tetiğe basma. Alarmı çalıştırırsın ve kaleden muhafızlar göndermeye başlarlar. +"Welcome, we can always use more help.",TXT_DLG_SCRIPT03_D40932_WELCO,MAP03: Near Macil.,,,"Vítej, pomoc se nám vždycky hodí.","Velkommen, vi kan altid bruge mere hjælp.","Willkommen, wir können immer etwas Hilfe gebrauchen.",,Bonvenon. Plia helpo ĉiam estas utilega.,"Bienvenido, siempre nos viene bien algo más de ayuda.",,Tervetuloa; voisimme aina kaivata lisää apua.,Bienvenue. Nous apprécions toute l'aide que nous pouvons recevoir.,"Üdv nálunk, mindig jól jön a segítség.","Benvenuto, ci serve tutto l'aiuto che possiamo ottenere.",ようこそ、我々が貴方の助けに成ります。,환영합니다. 당신 같은 사람들이 더 있었더라면...,"Welkom, we kunnen altijd meer hulp gebruiken.","Velkommen, vi kan alltid trenge mer hjelp.","Witaj, każda pomoc się przyda.",Seja bem-vindo. Qualquer ajuda é sempre bem-vinda.,,"Bun venit, mereu putem primi o mână de ajutor.",Добро пожаловать. Нам всегда пригодится помощь.,,"Välkommen, vi kan alltid behöva mer hjälp.","Hoş geldiniz, her zaman daha fazla yardıma ihtiyacımız olabilir." +"When I was still in action we had the chance to examine an acolyte before the reinforcements arrived. Listen, they're not human.",TXT_DLG_SCRIPT03_D42448_WHENI,〃,,,"Když jsem byl ještě v akci, měli jsme možnost prozkoumat mrtvého akolytu předtím, než přišly posily. Poslyš, nejsou to lidé.","Da jeg stadig var i aktion, havde vi mulighed for at undersøge en akolyt, inden forstærkningerne ankom. Hør, de er ikke menneskelige.","Als ich noch aktiv war, hatten wir mal die Möglichkeit, einen der Ministranten zu untersuchen, bevor Verstärkung eintraf. Hör zu, sie sind nicht menschlich!",,"Kiam mi ankoraŭ estis en misio, ni havis okazon ekzameni akoliton antaŭ ol pliaj malamikoj alvenis. Aŭskultu, ili ne estas homoj.","Cuando aún estaba en acción tuvimos la oportunidad de examinar a un acólito antes de que llegaran los refuerzos. Escucha, no son humanos.",,"Kun itse olin vielä mukana taistelemassa, saimme tilaisuuden tutkia akoluuttia ennen lisäjoukkojen saapumista. Ja kuule tarkkaan, ne eivät ole ihmisiä.","Quand j'étais encore en service, j'ai eu l'opportunité d'examiner un acolyte avant que les renforts n'arrivent. Vous savez, ils ne sont pas humains.","A harc után volt alkalmunk megvizsgálni egy oltárszolgát még mielőtt megjelent volna az erősítés. Esküszöm, hogy ezek nem emberek.","Quando ero ancora sul campo di battaglia, abbiamo avuto l'occasione di esaminare uno degli accoliti prima che arrivassero i rinforzi. Ascoltami, non sono umani.","私がまだ活動していた時、我々が増援に 囲まれる前にアコライトを調べる機会が あったんだ。聞いてくれ、奴等は人間では -なかったんだ。","제가 임무 수행 중이었을 때, 생포한 아콜라이트들을 조사한 적이 있었어요. 요점은, 그 들은 인간이 절대로 아닙니다.","Toen ik nog in actie was hadden we de kans om een acoliet te onderzoeken voordat de versterkingen kwamen. Luister, ze zijn niet menselijk.","Kiedy byłem jeszcze na chodzie, mieliśmy szansę się przyjrzeć akolitom zanim wezwano posiłki. Słuchaj, to nie są ludzie.","Quando eu estava na ativa, tivemos a oportunidade de examinar um acólito antes dos reforços chegarem. Ouça bem, eles não são humanos.",,,"Пока я был в оперативной группе, нам удалось вскрыть одного из служителей, прежде чем прибыло подкрепление. Так вот, они не люди.", -"We're trying to find where the castle gate mechanisms are, but so far we've had no luck.",TXT_DLG_SCRIPT03_D43964_WERET,,,,"Snažíme se zjistit, kde jsou mechanismy hradní brány, ale zatím jsme nic nenašli.","Wir versuchen herauszufinden, von wo das Burgtor kontrolliert wird, aber bisher hatten wir kein Glück.",,,"Estamos intentando encontrar donde se encuentran los mecanismos de la puerta del castillo, pero de momento no hemos tenido suerte.",,,"On essaie de trouver où se trouvent les contrôles de la porte du château, mais pour l'instant, on les a pas encore localisés.",,,"我々は城門のメカニズムが何処にあるか -探し続けているが、あまり良い結果は出ていない","성의 정문이 어떻게 작동하는지, 어떻게 하면 열 수 있는지 연구를 했습니다만... 아직은 희망이 없어요.","We proberen te vinden waar de mechanismen van de kasteelpoort zich bevinden, maar tot nu toe hebben we geen geluk gehad.","Próbowaliśmy znaleźć mechanizm bramy zamku, ale nam się nie udało.","Estamos tentando localizar os mecanismos do portão do castelo, mas até agora não tivemos sorte.",,,"Мы ищем механизм управления воротами замка, но пока безуспешно.", -Don't get caught. I've heard horror stories about what they do to our people after they're imprisoned. They just disappear... Without a trace.,TXT_DLG_SCRIPT03_D45480_DONTG,,,,"Nenech se chytit. Slyšel jsem děsivé příběhy o tom, co dělají našim lidem, když je uvězní. Prostě zmizí... beze stopy.","Lass dich nicht erwischen. Ich habe Horrorgeschichten darüber gehört, was sie unseren Leuten antun, die sie gefangengenommen haben. Sie verschwinden einfach... ohne jede Spur.",,,Que no te atrapen. He oído historias terroríficas sobre lo que hacen con nuestra gente después de ser detenidos. Símplemente desaparecen... sin dejar rastro alguno.,,,Ne vous faites pas avoir. J'ai entendu des choses horribles sur ce qu'ils font à ceux qu'ils emprisonnent. Ils disparaîssent... Sans laisser de trace.,,,"決して捕まるな。投獄されると奴等が +なかったんだ。","제가 임무 수행 중이었을 때, 생포한 아콜라이트들을 조사한 적이 있었어요. 요점은, 그 들은 인간이 절대로 아닙니다.","Toen ik nog in actie was hadden we de kans om een acoliet te onderzoeken voordat de versterkingen kwamen. Luister, ze zijn niet menselijk.","Da jeg fortsatt var i tjeneste, fikk vi sjansen til å undersøke en akolytt før forsterkningene kom. Hør her, de er ikke mennesker.","Kiedy byłem jeszcze na chodzie, mieliśmy szansę się przyjrzeć akolitom zanim wezwano posiłki. Słuchaj, to nie są ludzie.","Quando eu estava na ativa, tivemos a oportunidade de examinar um acólito antes dos reforços chegarem. Ouça bem, eles não são humanos.",,"Când încă eram în acțiune am avut șansa de a examina un acolit până să apară întăririle. Ascultă, nu sunt oameni.","Пока я был в оперативной группе, нам удалось изучить одного из служителей, прежде чем прибыло подкрепление. Так вот, они не люди.",,"När jag fortfarande var i aktion hade vi chansen att undersöka en akolyt innan förstärkningarna kom. Lyssna, de är inte mänskliga.","Ben hala görevdeyken, takviye birlikler gelmeden önce bir yardımcı inceleme şansımız oldu. Dinle, onlar insan değil." +"We're trying to find where the castle gate mechanisms are, but so far we've had no luck.",TXT_DLG_SCRIPT03_D43964_WERET,MAP03: Downstairs.,,,"Snažíme se zjistit, kde jsou mechanismy hradní brány, ale zatím jsme nic nenašli.","Vi prøver at finde ud af hvor slottets portmekanismer er, men indtil videre har vi ikke haft held.","Wir versuchen herauszufinden, von wo das Burgtor kontrolliert wird, aber bisher hatten wir kein Glück.",,"Ni provas malkovri, kie troviĝas la mekanismoj de la pordo de la kastelo, sed ni ankoraŭ ne sukcesis.","Estamos intentando descubrir la ubicación de los mecanismos de la puerta del castillo, pero de momento no ha habido suerte.","Estamos tratando de descubrir la ubicación de los mecanismos de la puerta del castillo, pero por ahora no hubo suerte.","Yritämme löytää linnanportin koneistoa, mutta toistaiseksi laihoin tuloksin.","On essaie de trouver où se trouvent les contrôles de la porte du château, mais pour l'instant, on les a pas encore localisés.","Próbáljuk megtalálni a kastély kapu irányító mechanikáját, de eddig nem jártunk sikerrel.","Stiamo cercando di capire dove si trovano i meccanismi di apertura dell'entrata del castello, ma ancora niente.","我々は城門のメカニズムが何処にあるか +探し続けているが、あまり良い結果は出ていない","성의 정문이 어떻게 작동하는지, 어떻게 하면 열 수 있는지 연구를 했습니다만... 아직은 희망이 없어요.","We proberen te vinden waar de mechanismen van de kasteelpoort zich bevinden, maar tot nu toe hebben we geen geluk gehad.","Vi prøver å finne ut hvor slottets portmekanismer er, men så langt har vi ikke hatt noe hell.","Próbowaliśmy znaleźć mechanizm bramy zamku, ale nam się nie udało.","Estamos tentando localizar os mecanismos do portão do castelo, mas até agora não tivemos sorte.",,"Încercăm să găsim mecanismele castelului, dar până acum nu am avut noroc.","Мы ищем механизм управления воротами замка, но пока безуспешно.",,"Vi försöker ta reda på var slottets portmekanismer finns, men hittills har vi inte haft någon tur.",Kalenin kapı mekanizmalarının nerede olduğunu bulmaya çalışıyoruz ama şu ana kadar şansımız yaver gitmedi. +Don't get caught. I've heard horror stories about what they do to our people after they're imprisoned. They just disappear... Without a trace.,TXT_DLG_SCRIPT03_D45480_DONTG,〃,,,"Nenech se chytit. Slyšel jsem děsivé příběhy o tom, co dělají našim lidem, když je uvězní. Prostě zmizí... beze stopy.","Bliv ikke fanget. Jeg har hørt skrækhistorier om, hvad de gør ved vores folk, når de er blevet fængslet. De forsvinder bare... Uden et spor.","Lass dich nicht erwischen. Ich habe Horrorgeschichten darüber gehört, was sie unseren Leuten antun, die sie gefangengenommen haben. Sie verschwinden einfach... ohne jede Spur.",,"Oni ne kaptu vin. Mi aŭdis terurajn historiojn pri tio, kio okazas al niaj homoj post ilia aresto: ili simple malaperas, lasinte nenian restaĵon.",Que no te atrapen. He oído historias terroríficas de lo que hacen con nuestros hombres una vez detenidos: simplemente desaparecen sin dejar rastro alguno.,,"Älä jää kiinni. Olen kuullut kauhukertomuksia siitä, mitä ne tekevät meidän omillemme, kun he jäävät vangiksi. He yksinkertaisesti katoavat, jälkeä jättämättä.",Ne vous faites pas avoir. J'ai entendu des choses horribles sur ce qu'ils font à ceux qu'ils emprisonnent. Ils disparaîssent... Sans laisser de trace.,Csak ne fogasd el magad. Hallottam horror történténeteket azokról akiket mégis elfognak. Csak úgy eltünnek...mindenféle nyom nélkül.,Non farti prendere. Ho sentito storie orribili su quello che fanno alle persone dopo che le catturano. Spariscono... senza traccia.,"決して捕まるな。投獄されると奴等が 何をしでかすか怪談として聞く程だ。 -跡形もなく...消される。",절대로 붙잡히지 마세요. 그 녀석들이 수감된 사람들에게 한 일에 대한 무서운 이야기를 들었어요. 흔적도 없이 그냥 사라져 버린 겁니다.,Laat je niet vangen. Ik heb horrorverhalen gehoord over wat ze onze mensen na hun gevangenschap aandoen. Ze verdwijnen gewoon.... Zonder een spoor.,"Nie daj się złapać. Słyszałem straszne historie co robią naszym ludziom, kiedy ich złapią. Oni po prostu znikają... Bez śladu.",Não deixe eles te pegarem. Ouvi histórias de terror sobre o que eles fazem com o nosso pessoal depois que são aprisionados. Eles desaparecem... sem deixar rastros.,,,"Не дай себя схватить. Я слышал ужасные истории о том, что они делают с арестованными. Те просто исчезают... без следа.", -"Here's some advice, if you ever see any of the Order's Tinsoldiers go in the other direction. They're fast and brutal.",TXT_DLG_SCRIPT03_D46996_HERES,,,,"Dám ti radu: Jestli někdy uvidíš jednoho z plecháčků Řádu, otoč se a jdi. Jsou rychlí a suroví.","Hier ist ein guter Rat, falls du jemals einen dieser Zinnsoldaten des Ordens vorbeigehen siehst. Sie sind schnell und brutal. ",,,"Un consejo, si ves ir alguno de los soldaditos de la Orden ve para otro lado. Son rápidos y brutales.",,,"Voilà un conseil. Si vous voyez un des soldats mécanisés de l'Ordre, retournez vous et courez. Ils sont rapides et brutaux.",,,"伝えておく、オーダーの錫兵は +跡形もなく...消される。",절대로 붙잡히지 마세요. 그 녀석들이 수감된 사람들에게 한 일에 대한 무서운 이야기를 들었어요. 흔적도 없이 그냥 사라져 버린 겁니다.,Laat je niet vangen. Ik heb horrorverhalen gehoord over wat ze onze mensen na hun gevangenschap aandoen. Ze verdwijnen gewoon.... Zonder een spoor.,Ikke bli tatt. Jeg har hørt skrekkhistorier om hva de gjør med folket vårt etter at de blir fengslet. De bare forsvinner... Sporløst.,"Nie daj się złapać. Słyszałem straszne historie co robią naszym ludziom, kiedy ich złapią. Oni po prostu znikają... Bez śladu.",Não deixe eles te pegarem. Ouvi histórias de terror sobre o que eles fazem com o nosso pessoal depois que são aprisionados. Eles desaparecem... sem deixar rastros.,,Să nu te prindă. Am auzit povești de groază despre ce le fac oamenilor în închisoare. Dispar pur și simplu... fără nicio urmă.,"Не дай себя схватить. Я слышал ужасные истории о том, что они делают с арестованными. Те просто исчезают... без следа.",,Bli inte fångade. Jag har hört skräckhistorier om vad de gör med vårt folk efter att de blivit fängslade. De bara försvinner... Utan ett spår.,Sakın yakalanmayın. Hapsedildikten sonra insanlarımıza ne yaptıklarına dair korku hikayeleri duydum. Öylece ortadan kayboluyorlar. İz bırakmadan. +"Here's some advice, if you ever see any of the Order's Tinsoldiers go in the other direction. They're fast and brutal.",TXT_DLG_SCRIPT03_D46996_HERES,〃,,,"Dám ti radu: Jestli někdy uvidíš jednoho z plecháčků Řádu, otoč se a utíkej. Jsou rychlí a suroví.",Her er et godt råd: Hvis du nogensinde ser nogen af Ordenens Tinsoldater gå i den anden retning. De er hurtige og brutale.,"Hier ist ein guter Rat, falls du jemals einen dieser Zinnsoldaten des Ordens vorbeigehen siehst. Sie sind schnell und brutal. ",,Jen konsilo: estu ĉiam fore de la artefaritaj soldatoj de La Ordeno. Ili estas rapidaj kaj brutalaj.,Un consejo: mantente siempre alejado de los soldados artificiales de La Orden. Son rápidos y brutales.,,"Annan pienen vinkin: Jos koskaan näet Veljeskunnan tinasotilaita, mene toiseen suuntaan. Ne ovat nopeita ja raakoja.","Voilà un conseil. Si vous voyez un des soldats mécanisés de l'Ordre, retournez vous et courez. Ils sont rapides et brutaux.","Az a tanácsom számodra, hogy ha meglátod a Rend ólomkatonáit, vedd az utad az ellentétes irányba. Gyorsak és brutálisak.","Ecco un consiglio. Se vedi uno dei soldatini di latta dell'Ordine, vai nella direzione opposta. Sono veloci e brutali.","伝えておく、オーダーの錫兵は 他方から呼び出され押し寄せてくる。 -奴等は素早く残忍だ。","조언 하나 하겠습니다. 만약 오더 출신의 깡통로봇들이 당신에게 향하고 있다면, 얼른 피하세요. 그놈들은 훨씬 무섭고 잔혹합니다.","Hier is een advies, als je ooit een van de Tinsoldiers van de Orde de andere kant op ziet gaan. Ze zijn snel en wreed.","Dam ci radę. Jeśli zobaczysz jakiegokolwiek Blaszanego Żołnierza Zakonu, idź w przeciwnym kierunku. Są szybcy i brutalni.","Tenho um conselho pra você. Se você ver algum soldadinho da Ordem, vá para outra direção. Eles são rápidos e brutais.",,,"Небольшой совет: если увидишь «оловянных солдатиков» Ордена, сворачивай в другую сторону. Они быстры и жестоки.", -Leave me be. I'm doing something for Macil.,TXT_DLG_SCRIPT03_D48512_LEAVE,,,,"Teď mě nech, dělám něco pro Macila.",Lass mich in Ruhe. Ich muss etwas für Macil erledigen.,,,Déjame. Estoy haciendo algo para Macil.,,,Laissez moi. Je suis en train de faire quelque chose pour Macil.,,,"すまないが忙しい。 -私はマシルの雑用を請け負っている。",방해하지 마세요. 사령관님을 위해 중요한 일을 하고 있으니.,Laat me met rust. Ik doe iets voor Macil.,Zostaw mnie. Robię coś dla Macila.,Me deixe em paz. Estou fazendo algo pro Macil.,,,"Не отвлекай меня. Я выполняю поручение Мэйсила. -", -"Sorry, no. You do not have clearance.",TXT_DLG_SCRIPT04_D0_SORRY,,,,"Pardon, ne. Sem nemůžete.","Tut mir leid, aber Sie haben keine Berechtigung.",,,"Lo siento, no. No tienes permiso.",,,"Non, désolé. Vous n'avez pas d'autorisation.",,,すまないが、お前にクリアランスはない。,"유감이지만, 신분 휘장 없이는 보내줄 수 없어.","Sorry, nee. Je hebt geen toestemming.","Wybacz, ale nie. Nie masz zezwolenia.",Desculpe mas não. Você não tem permissão.,,,"Увы, нет. У тебя нет пропуска.", -Stop! Show me your ID badge.,TXT_DLG_SCRIPT04_D1516_STOPS,,,,Stát! Ukažte mi svůj identifikační průkaz.,Halt. Zeigen Sie mir Ihre Identitätskarte.,,,¡Alto! Muéstrame tu insignia de identificación.,,,Stop! Montrez moi votre carte d'identité.,,,待て! IDバッジを見せろ。,멈춰라! 너의 신분 휘장을 보여줘.,Stop! Laat me je ID-badge zien.,Stój! Pokaż mi swoją odznakę identyfikacyjną.,Alto! Mostre a sua identificação.,,,Стой! Покажи мне своё удостоверение., -Here's my I.D.,TXT_RPLY0_SCRIPT04_D1516_HERES,,,,Tady je moje průkazka.,Hier ist sie.,,,Aquí está mi identificación.,,,La voilà.,,,これだ。,"여기, 휘장.",Hier is mijn ID.,Oto ona.,Aqui está ela.,,,Вот оно., -"Oh, ok. Sure go ahead. Have a nice day.",TXT_DLG_SCRIPT04_D3032_OHOKS,,,,"Aha, dobře. Jistě, jděte dál. Přeji hezký den.","Alles klar, ich wünsche einen schönen Tag.",,,"Oh, ok. Vale, adelante. Ten un buen día.",,,"Bon, ok. Allez-y. Passez une bonne journée.",,,あぁ、宜しい。通れ。良い一日を。,"오, 정말이네. 환영한다. 좋은 하루 보내고.","Oh, oké. Ga je gang. Nog een prettige dag.","Oh, ok. Proszę, wchodź. Miłego dnia.","Ah, ok. Pode passar. Tenha um bom dia.",,,"Ладно, проходи. Всего доброго.", -"Derwin? Yeah, he's down in the warehouse, but you're not getting in unless you're cleared.",TXT_DLG_SCRIPT04_D4548_DERWI,,,,"Derwin? Jo, ten je dole ve skladu, ale ty nikam nejdeš jestliže nemáš povolení.","Derwin? Ja, der ist unten im Lagerhaus, aber da kommst du nicht rein ohne Berechtigung.",,,"¿Derwin? Si, está abajo en el almacén, pero no puedes entrar a menos que tengas permiso.",,,"Derwin? Ouais, il est dans l'entrepôt. Vous ne pouvez pas y entrer sans autorisation.",,,"ダーウィン? ああ、奴はこの倉庫内にいるが、 -片付かない限りお前は入れん。",더윈? 녀석은 저 창고 밑에 있다. 그러나 허가 없이는 못 보내준다.,"Derwin? Ja, hij is in het magazijn, maar je komt er niet in tenzij je vrij bent.","Derwin? Tak, jest w magazynie, ale tam nie wejdziesz bez zgody.","Derwin? Sim, ele está lá embaixo no depósito, mas você não pode entrar enquanto não tiver permissão.",,,"Дервин? Да, он внизу, на складе, но тебя туда не пустят, если у тебя нет пропуска.", -I've got clearance.,TXT_RPLY0_SCRIPT04_D4548_IVEGO,,,,Mám povolení.,Ich habe eine Berechtigung.,,,Tengo permiso.,,,J'ai une autorisation.,,,クリアランスはある。,허가를 받았어.,Ik heb toestemming.,Mam zezwolenie.,Eu tenho permissão.,,,У меня есть пропуск., -Go on.,TXT_DLG_SCRIPT04_D6064_GOON,,,,Tak jdi.,Alles klar.,,,Ve entonces.,,,Allez-y.,,,続けろ。,그럼 가도 좋다.,Ga door.,Wchodź.,Pode passar.,,,Проходи., -Do you know where he is?,TXT_RPLY0_SCRIPT04_D6064_DOYOU,,,,"Nevíš, kde je?","Weißt du, wo er ist?",,,¿Sabes donde está?,,,Vous savez où il est?,,,ソイツが何処にいるか知っているか?,그가 어디 있는지 아는가?,Weet je waar hij is?,Wiesz gdzie on jest?,Você sabe onde ele está?,,,"Вы знаете, где Дервин?", -I don't know where anybody is. I just keep the lid on the rat trap.,TXT_DLG_SCRIPT04_D7580_IDONT,,,,Já nevím kde kdo je. Já jen dohlížím na pastičku na myši.,"Ich weiß von niemandem, wo er ist. Ich kümmere mich nur um die Rattenfalle.",,,No se donde está nadie. Solo mantengo la tapa de la trampa de ratones.,,,Je ne sais pas où se trouve qui que ce soit. Je ne fais que garder le couvercle de ce trou à rats.,,,"俺には何処にいるかは分からない。 -俺はただネズミ捕りにフタを被せているだけだ。",그가 정확히 어디 있는지는 모른다. 난 도망자를 그냥 감시할 뿐이다.,Ik weet niet waar iemand is. Ik hou gewoon het deksel op de rattenval.,Nie wiem gdzie kto jest. Ja tylko plinuję tej pułapki na szczury.,Não sei onde ninguém está. Apenas mantenho a tampa neste bueiro.,,,"Ничего я не знаю. Я просто слежу, чтобы никто из них не сбежал из западни.", -You are an unpleasant distraction.,TXT_DLG_SCRIPT04_D9096_YOUAR,,,,Jsi nepříjemná otrava.,Du bist eine unerwünschte Ablenkung,,,Eres una distracción incómoda.,,,Vous êtes une distraction déplaisante.,,,お前は不快で目障りだ。,당신은 지금 내 감시일을 방해하고 있다.,Je bent een onaangename afleiding.,Bardzo mnie rozpraszasz.,Você é uma distração bem incômoda.,,,Ты — досадная помеха., -Move along or taste metal.,TXT_DLG_SCRIPT04_D10612_MOVEA,,,,"Jdi dál, nebo okus ocel.",Beweg dich oder du schmeckst Metall.,,,Muévete o prueba metal.,,,Circulez ou préparez vous à manger de l'acier.,,,同行か鉄を味わうかだ。,어서 움직여. 총알 먹기 싫으면.,Ga verder of proef metaal.,Odejdź stąd albo posmakujesz mojej pukawki.,Vá embora ou vai tomar chumbo grosso.,,,"Прочь, или отведаешь металла.", -Pass your ID through here for access.,TXT_DLG_SCRIPT04_D12128_PASSY,,,,Pro přístup tady nahrajte svou legitimaci.,Reichen Sie Ihre Identitätskarte hier durch!,,,Pasa tu identificación por aquí para acceder.,,,Faites passer votre carte d'identité ici pour continuer.,,,彼方のI.D.をここに提示してください。,신분증을 보여줘. 입장하고 싶으면.,Geef je ID hier door voor toegang.,"Pokaż tu swój identyfikator, aby otrzymać dostęp.",Passe a sua identificação por aqui para acessar.,,,"Покажи своё удостоверение, чтобы получить допуск.", -"Get back to work, now!",TXT_DLG_SCRIPT04_D13644_GETBA,,,,"Vrať se do práce, hned!",Gehen Sie sofort zurück an die Arbeit!,,,"Vuelve al trabajo, ¡Ahora!",,,"Retournez au boulot, maintenant!",,,仕事へ戻れ、今すぐ!,당장 일해. 어서.,"Ga terug aan het werk, nu!","Do roboty, już!","Volte ao trabalho, agora!",,,Немедленно за работу!, -"Get back to work, now!",TXT_DLG_SCRIPT04_D15160_GETBA,,,,"Vrať se do práce, hned!",Gehen Sie sofort zurück an die Arbeit!,,,"Vuelve al trabajo, ¡Ahora!",,,"Retournez au boulot, maintenant!",,,今すぐ仕事へ戻れ!,쉬면 알지? 어서 일해.,"Ga terug aan het werk, nu!","Do roboty, już!","Volte ao trabalho, agora!",,,Немедленно за работу!, -We've been running around the clock for weeks with no down time. I'd say that the Order is planning a suppression raid on the Front.,TXT_DLG_SCRIPT04_D16676_WEVEB,,,,"Celé týdny makáme bez přestávek. Řekl bych, že Řád má v plánu nějaký útok na Frontu.","Die Station hier läuft seit Wochen ohne Stillstand. Ich vermute mal, der Orden bereitet einen großen Schlag gegen die Front vor.",,,"Hemos trabajado todo el tiempo durante semanas, sin descanso. Diría que la Orden está planeando una incursión para suprimir al frente.",,,J'ai fait le tour de l'horloge depuis des semaines sans temps de repos. Je pense que l'Ordre prépare un raid de suppression sur le Front.,,,"もう数週間も休日返上で働いているんだ。 +奴等は素早く残忍だ。","조언 하나 하겠습니다. 만약 오더 출신의 깡통로봇들이 당신에게 향하고 있다면, 얼른 피하세요. 그놈들은 훨씬 무섭고 잔혹합니다.","Hier is een advies, als je ooit een van de Tinsoldiers van de Orde de andere kant op ziet gaan. Ze zijn snel en wreed.","Her er noen råd, hvis du noen gang ser noen av Ordenens Tinsoldater gå i den andre retningen. De er raske og brutale.","Dam ci radę. Jeśli zobaczysz jakiegokolwiek Blaszanego Żołnierza Zakonu, idź w przeciwnym kierunku. Są szybcy i brutalni.","Tenho um conselho pra você. Se você ver algum soldadinho da Ordem, vá para outra direção. Eles são rápidos e brutais.",,Uite un sfat: Dacă vezi vreun soldat din staniu du-te în direcția opusă. Sunt rapizi și brutali.,"Небольшой совет: если увидишь «оловянных солдатиков» Ордена, сворачивай в другую сторону. Они быстры и жестоки.",,"Här är ett råd, om du någonsin ser någon av Ordens Tinsoldater gå åt andra hållet. De är snabba och brutala.","İşte size bir tavsiye, eğer Tarikat'ın teneke askerlerinden birini görürseniz diğer yöne gidin. Hızlı ve acımasızdırlar." +Leave me be. I'm doing something for Macil.,TXT_DLG_SCRIPT03_D48512_LEAVE,〃,,,"Teď mě nech, dělám něco pro Macila.",Lad mig være. Jeg gør noget for Macil.,Lass mich in Ruhe. Ich muss etwas für Macil erledigen.,,Lasu min. Mi faras ion por Macil.,"Déjame, que estoy haciendo algo para Macil.",,Anna minun olla. Palvelen parhaillani Macilia.,Laissez moi. Je suis en train de faire quelque chose pour Macil.,Hagyj békén. Épp macil számára csinálok valamit.,"Ora non ho tempo, sto sbrigando un incarico per Macil.","すまないが忙しい。 +私はマシルの雑用を請け負っている。",방해하지 마세요. 사령관님을 위해 중요한 일을 하고 있으니.,Laat me met rust. Ik doe iets voor Macil.,La meg være i fred. Jeg gjør noe for Macil.,Zostaw mnie. Robię coś dla Macila.,Me deixe em paz. Estou fazendo algo pro Macil.,,Lasă-mă. Fac ceva pentru Macil.,"Не отвлекай меня. Я выполняю поручение Мэйсила. +",,Låt mig vara. Jag gör något för Macil.,Beni rahat bırak. Macil için bir şey yapıyorum. +"Sorry, no. You do not have clearance.",TXT_DLG_SCRIPT04_D0_SORRY,MAP04: Reactor Core red guard.,,,"Pardon, ne. Sem nemůžete.","Beklager, nej. Du har ikke tilladelse.","Tut mir leid, aber Sie haben keine Berechtigung.",,"Pardonon, sed ne, vi ne rajtas eniri.","Lo siento, pero no, no tienes permiso.",,"Anteeksi, ei. Sinulla ei ole kulkulupaa.","Non, désolé. Vous n'avez pas d'autorisation.",Sajnálom de nem. Nincs hozzá jogosultságod.,"Mi spiace, ma non hai l'autorizzazione.",すまないが、お前にクリアランスはない。,"유감이지만, 신분 휘장 없이는 보내줄 수 없어.","Sorry, nee. Je hebt geen toestemming.","Beklager, nei. Du har ikke klarering.","Wybacz, ale nie. Nie masz zezwolenia.",Desculpe mas não. Você não tem permissão.,,"Scuze, nu. Nu ai acces.","Увы, нет. У тебя нет пропуска.",,"Tyvärr, nej. Du har inget tillstånd.","Üzgünüm, olmaz. Yetkiniz yok." +Stop! Show me your ID badge.,TXT_DLG_SCRIPT04_D1516_STOPS,〃,,,Stát! Ukažte mi svůj identifikační průkaz.,Stop! Vis mig dit ID-skilt.,Halt. Zeigen Sie mir Ihre Identitätskarte.,,Haltu! Montru vian identigilon de la centralo.,¡Alto! Muéstrame tu identificación de la central.,,Seis! Näytä minulle henkilötunnisteesi.,Stop! Montrez moi votre carte d'identité.,Állj! Mutasd az igazolványod.,Fermo! Mostrami il tesserino d'identificazione.,待て! IDバッジを見せろ。,멈춰라! 너의 신분 휘장을 보여줘.,Stop! Laat me je ID-badge zien.,Stopp! Vis meg ID-kortet ditt.,Stój! Pokaż mi swoją odznakę identyfikacyjną.,Alto! Mostre a sua identificação.,,Stop! Arată-mi cardul de identitate.,Стой! Покажи мне своё удостоверение.,,Stopp! Visa mig din ID-bricka.,Dur! Bana kimliğini göster. +Here's my I.D.,TXT_RPLY0_SCRIPT04_D1516_HERES,〃,,,Tady je moje průkazka.,Her er mit id-kort.,Hier ist sie.,,Jen la identigilo.,Aquí está mi identificación.,,Tässä.,La voilà.,Itt az igazolványom.,Eccolo qua.,これだ。,"여기, 휘장.",Hier is mijn ID.,Her er legitimasjonen min.,Oto ona.,Aqui está ela.,,Aici e cardul.,Вот оно.,,Här är mitt ID-kort.,İşte kimliğim. +"Oh, ok. Sure go ahead. Have a nice day.",TXT_DLG_SCRIPT04_D3032_OHOKS,〃,,,"Aha, dobře. Jistě, jděte dál. Přeji hezký den.","Åh, okay. Selvfølgelig, værsgo. Hav en god dag.","Alles klar, ich wünsche einen schönen Tag.",,"Ha, bone. Kompreneble, eniru. Havu bonan tagon.","Ah, vale. Claro, adelante. Ten un buen día.","Ah, bueno. Claro, adelante. Ten un buen día.","Aa, hyvä. Selvä, voit mennä. Hyvää päivänjatkoa.","Bon, ok. Allez-y. Passez une bonne journée.","Oh, rendben. Mehetsz is tovább. További szép napot.","Ah, va bene. Vai pure avanti. Buona giornata.",あぁ、宜しい。通れ。良い一日を。,"오, 정말이네. 환영한다. 좋은 하루 보내고.","Oh, oké. Ga je gang. Nog een prettige dag.","Å, ok. Vær så god. Ha en fin dag.","Oh, ok. Proszę, wchodź. Miłego dnia.","Ah, ok. Pode passar. Tenha um bom dia.",,"Ah, în regulă. Mergi mai departe. O zi bună.","Ладно, проходи. Всего доброго.",,"Åh, okej. Visst, fortsätt. Ha en trevlig dag.","Oh, tamam. Tabii, devam edin. İyi günler dilerim." +"Derwin? Yeah, he's down in the warehouse, but you're not getting in unless you're cleared.",TXT_DLG_SCRIPT04_D4548_DERWI,MAP04: Warehouse red guard.,,,"Derwin? Jo, ten je dole ve skladu, ale ty nikam nejdeš jestliže nemáš povolení.","Derwin? Ja, han er nede i lageret, men du kommer ikke ind, medmindre du er godkendt.","Derwin? Ja, der ist unten im Lagerhaus, aber da kommst du nicht rein ohne Berechtigung.",,"Ĉu Derwin? Jes, li estas malsupre en la magazeno, sed vi ne rajtas iri tien, krom se vi havas paspermeson.","¿Derwin? Sí, está abajo en el almacén, pero no puedes entrar a menos que tengas permiso.",,"Derwin? Joo, hän on varastolla, muttet pääse sisään ilman kulkulupaa.","Derwin? Ouais, il est dans l'entrepôt. Vous ne pouvez pas y entrer sans autorisation.","Derwin? Igen, Ő épp a raktárban van, de jogosultság nélkül nem jutsz be oda.","Derwin? Sì, è giù nel magazzino, ma non puoi entrare senza autorizzazione.","ダーウィン? ああ、奴はこの倉庫内にいるが、 +片付かない限りお前は入れん。",더윈? 녀석은 저 창고 밑에 있다. 그러나 허가 없이는 못 보내준다.,"Derwin? Ja, hij is in het magazijn, maar je komt er niet in tenzij je vrij bent.","Derwin? Ja, han er nede på lageret, men du kommer ikke inn med mindre du er klarert.","Derwin? Tak, jest w magazynie, ale tam nie wejdziesz bez zgody.","Derwin? Sim, ele está lá embaixo no depósito, mas você não pode entrar enquanto não tiver permissão.",,"Darwin? Da, e în depozit, dar nu intri înăuntru dacă nu ai acces.","Дервин? Да, он внизу, на складе, но тебя туда не пустят, если у тебя нет пропуска.",,"Derwin? Ja, han är nere i lagret, men du kommer inte in om du inte har fått tillstånd.","Derwin? Evet, depoda ama izin almadan içeri giremezsin." +I've got clearance.,TXT_RPLY0_SCRIPT04_D4548_IVEGO,〃,,,Mám povolení.,Jeg har fået tilladelse.,Ich habe eine Berechtigung.,,Mi havas ĝin.,Tengo permiso.,,Minulla on lupa.,J'ai une autorisation.,Van jogosultságom.,Ce l'ho l'autorizzazione.,クリアランスはある。,허가를 받았어.,Ik heb toestemming.,Jeg har klarering.,Mam zezwolenie.,Eu tenho permissão.,,Am acces.,У меня есть пропуск.,,Jag har tillstånd.,İznim var. +Go on.,TXT_DLG_SCRIPT04_D6064_GOON,〃,,,Tak jdi.,Jeg har tilladelse.,Alles klar.,,Vi rajtas iri.,Entonces ve.,,Jatkakaa.,Allez-y.,Mesélj csak.,Va pure.,続けろ。,그럼 가도 좋다.,Ga door.,Jeg har klarering.,Wchodź.,Pode passar.,,Intră.,Проходи.,,Fortsätt.,Devam et. +Do you know where he is?,TXT_RPLY0_SCRIPT04_D6064_DOYOU,〃,,,"Nevíš, kde je?","Ved du, hvor han er?","Weißt du, wo er ist?",,"Ĉu vi scias, kie li estas?",¿Sabes dónde está?,,"Tiedätkö, missä hän on?",Vous savez où il est?,Tudod hol találom meg?,Sai dov'è?,ソイツが何処にいるか知っているか?,그가 어디 있는지 아는가?,Weet je waar hij is?,Vet du hvor han er?,Wiesz gdzie on jest?,Você sabe onde ele está?,,Știi unde e?,"Вы знаете, где Дервин?",,Vet du var han är?,Nerede olduğunu biliyor musun? +I don't know where anybody is. I just keep the lid on the rat trap.,TXT_DLG_SCRIPT04_D7580_IDONT,〃,,,Já nevím kde kdo je. Já jen dohlížím na pastičku na myši.,"Jeg ved ikke, hvor nogen er. Jeg holder bare låget på rottefælden.","Ich weiß von niemandem, wo er ist. Ich kümmere mich nur um die Rattenfalle.",,Mi scias nenies pozicion. Mi nur estas komisiito de la pordoj de ĉi tiu ratkaptilo.,No me sé la ubicación de nadie. Solo estoy a cargo de las puertas de esta ratonera.,,"En tiedä, missä kukaan on. Huolehdin vain rotanloukun kannesta.",Je ne sais pas où se trouve qui que ce soit. Je ne fais que garder le couvercle de ce trou à rats.,Ötletem sincs merre vannak az emberek. Én csak a patkány csapda tetejéért vagyok felelős.,Non so dove sia nessuno di quelli che stanno nel magazzino. A me interessa solo che non scappino.,"俺には何処にいるかは分からない。 +俺はただネズミ捕りにフタを被せているだけだ。",그가 정확히 어디 있는지는 모른다. 난 도망자를 그냥 감시할 뿐이다.,Ik weet niet waar iemand is. Ik hou gewoon het deksel op de rattenval.,Jeg vet ikke hvor noen er. Jeg holder bare lokket på rottefella.,Nie wiem gdzie kto jest. Ja tylko plinuję tej pułapki na szczury.,Não sei onde ninguém está. Apenas mantenho a tampa neste bueiro.,,"Nu știu unde e nimeni, eu doar țin ochii pe capcana pentru șoareci.","Ничего я не знаю. Я просто слежу, чтобы никто из них не сбежал из западни.",,Jag vet inte var någon är. Jag håller bara locket på råttfällan.,Kimsenin nerede olduğunu bilmiyorum. Ben sadece fare kapanının kapağını tutuyorum. +You are an unpleasant distraction.,TXT_DLG_SCRIPT04_D9096_YOUAR,〃,,,Jsi nepříjemná otrava.,Du er en ubehagelig distraktion.,Du bist eine unerwünschte Ablenkung,,Vi estas malagrabla distraĵo.,Eres una distracción incómoda.,,Oletpa epämiellyttävä häiriötekijä.,Vous êtes une distraction déplaisante.,Egy kellemetlen zavaró tényező vagy.,Sei una sgradevole distazione.,お前は不快で目障りだ。,당신은 지금 내 감시일을 방해하고 있다.,Je bent een onaangename afleiding.,Du er en ubehagelig distraksjon.,Bardzo mnie rozpraszasz.,Você é uma distração bem incômoda.,,Ești o distragere neplăcută.,Ты — досадная помеха.,,Du är en obehaglig distraktion.,Hoş olmayan bir dikkat dağıtıcısın. +Move along or taste metal.,TXT_DLG_SCRIPT04_D10612_MOVEA,MAP04: Reactor Core gray guard.,,,"Jdi dál, nebo okus ocel.",Gå videre eller smag på metal.,Beweg dich oder du schmeckst Metall.,,Plue movu vin aŭ gustumu kuglojn.,Esfúmate o come plomo.,,"Ala vetää, tai maista metallia.",Circulez ou préparez vous à manger de l'acier.,"Haladj tovább, vagy ízleld meg a kardom.",Sparisci o ti finisce male.,同行か鉄を味わうかだ。,어서 움직여. 총알 먹기 싫으면.,Ga verder of proef metaal.,Gå videre eller smak på metall.,Odejdź stąd albo posmakujesz mojej pukawki.,Vá embora ou vai tomar chumbo grosso.,,Mșcă-te sau înghiți metal.,"Прочь, или отведаешь металла.",,Gå vidare eller smaka på metall.,İlerle yoksa metalin tadına bakarsın. +Pass your ID through here for access.,TXT_DLG_SCRIPT04_D12128_PASSY,,,,Pro přístup tady nahrajte svou legitimaci.,Giv dit ID her igennem for at få adgang.,Reichen Sie Ihre Identitätskarte hier durch!,,Ŝovu vian identigilon sur la legilon por eniri.,Pasa tu identificación por aquí para acceder.,,Vedä tunnisteesi tästä päästäksesi läpi.,Faites passer votre carte d'identité ici pour continuer.,Add le az igazolványod itt a belépéshez.,Mostra il tesserino per accedere.,彼方のI.D.をここに提示してください。,신분증을 보여줘. 입장하고 싶으면.,Geef je ID hier door voor toegang.,Før legitimasjonen din gjennom her for å få adgang.,"Pokaż tu swój identyfikator, aby otrzymać dostęp.",Passe a sua identificação por aqui para acessar.,,Trece cardul de acces pe aici.,"Покажи своё удостоверение, чтобы получить допуск.",,Ge ditt ID-kort här för att få tillträde.,Giriş için kimliğinizi buradan geçirin. +"Get back to work, now!",TXT_DLG_SCRIPT04_D13644_GETBA,MAP04: Green guard.,,,"Vrať se do práce, hned!","Tilbage til arbejdet, nu!",Gehen Sie sofort zurück an die Arbeit!,,"Reiru al via laborposteno, tuje!","Vuelve al trabajo, ¡ahora!",,"No niin, takaisin töihisi!","Retournez au boulot, maintenant!",Nyomás vissza dolgozni!,Ora torna a lavoro!,仕事へ戻れ、今すぐ!,당장 일해. 어서.,"Ga terug aan het werk, nu!","Tilbake til arbeidet, nå!","Do roboty, już!","Volte ao trabalho, agora!",,"Treci înapoi la muncă, acum!",Немедленно за работу!,,"Tillbaka till arbetet, nu!","İşinizin başına dönün, hemen!" +"Get back to work, now!",TXT_DLG_SCRIPT04_D15160_GETBA,〃,,,"Vrať se do práce, hned!","Tilbage til arbejdet, nu!",Gehen Sie sofort zurück an die Arbeit!,,"Reiru al via laborposteno, tuje!","Vuelve al trabajo, ¡ahora!",,"No niin, takaisin töihisi!","Retournez au boulot, maintenant!",Nyomás vissza dolgozni!,Ora torna a lavoro!,今すぐ仕事へ戻れ!,쉬면 알지? 어서 일해.,"Ga terug aan het werk, nu!","Tilbake til arbeidet, nå!","Do roboty, już!","Volte ao trabalho, agora!",,"Treci înapoi la muncă, acum!",Немедленно за работу!,,"Tillbaka till arbetet, nu!","İşinizin başına dönün, hemen!" +We've been running around the clock for weeks with no down time. I'd say that the Order is planning a suppression raid on the Front.,TXT_DLG_SCRIPT04_D16676_WEVEB,MAP04: Warehouse → Northeast (worker in red),,,"Celé týdny makáme bez přestávek. Řekl bych, že Řád má v plánu nějaký útok na Frontu.","Vi har kørt døgnet rundt i ugevis uden at have nogen pause. Jeg vil sige, at Ordenen planlægger et undertrykkelsesangreb på fronten.","Die Station hier läuft seit Wochen ohne Stillstand. Ich vermute mal, der Orden bereitet einen großen Schlag gegen die Front vor.",,"Ni senhalte laboras 24 horojn ĉiutage de antaŭ semajnoj. Mi dirus, ke La Ordeno planas atakon por subpremi la Fronton.",Llevamos semanas trabajando 24 horas al día sin parar. Diría que La Orden está planeando una incursión para suprimir al Frente.,,"Olemme työskennelleet viikkoja kellon ympäri ilman silmällistäkään. Sanoisin, että Veljeskunta on suunnittelemassa ehkäisevää iskua Rintamaa vastaan.",J'ai fait le tour de l'horloge depuis des semaines sans temps de repos. Je pense que l'Ordre prépare un raid de suppression sur le Front.,"A nap minden órájában dolgoztunk szünet nélkül. Az a gyanúm, hogy a Rend sorsdöntő támadást akar indítani a Front ellen.",Stiamo lavorando senza sosta per settimane oramai. Secondo me l'Ordine sta preparando un nuovo attacco contro il Fronte.,"もう数週間も休日返上で働いているんだ。 オーダーがまたフロントを攻撃する準備を -しているんだろうな。","일주일 동안 쉬지도 않고 일하느라 정신이 날아갈 것 같아요... 아무튼, 오더가 프론트 저항군을 제압할 작전을 준비한다는군요.","We rennen al weken rond de klok, zonder uitvaltijd. Ik zou zeggen dat de Orde een onderdrukkingsinval aan de voorkant plant.","Od kilku tygodni pracujemy przez całą dobę bez przerwy. Powiedziałbym, że Zakon planuje zniszczyć Front.",Estamos trabalhando noite e dia por semanas sem descanso. Eu diria que a Ordem está planjeando um ataque para suprimir a Frente.,,,"Мы работаем круглые сутки без перерыва уже несколько недель. Мне кажется, Орден готовит решительный рейд, чтобы окончательно покончить с Сопротивлением.", -"Oh, damn. The governor sent you. I was going to give him his cut, really I was. OK, listen. I've got a bundle stashed. It's yours if you look the other way.",TXT_DLG_SCRIPT04_D18192_OHDAM,,,,"A sakra. Guvernér tě poslal. Měl jsem v plánu dát mu jeho podíl, opravdu. Dobře, poslouchej. Mám schované nějaké zlaťáky, můžou být tvoje, když přimhouříš oko.","Verdammt, der Gouverneur hat dich geschickt. Ich wollte ihm seinen Anteil geben - wirklich ich wollte das. Hör zu, ich habe hier was zur Seite geschafft, es gehört die wenn du die Sache auf sich beruhen läßt.",,,"Oh, maldición. El gobernador te ha enviado. Iba a darle su parte, en serio. Ok, escucha. Tengo un puñado escondido. Es tuyo si miras a otro lado.",,,"Oh, merde. Le gouverneur t'a envoyé? J'allais lui donner sa part, si, vraiment. Ok, écoute. J'en ai un paquet de mis de côté. Si tu veux, tu peux le prendre, si tu m'oublies.",,,"クソッ、知事の回し者だな。 +しているんだろうな。","일주일 동안 쉬지도 않고 일하느라 정신이 날아갈 것 같아요... 아무튼, 오더가 프론트 저항군을 제압할 작전을 준비한다는군요.","We rennen al weken rond de klok, zonder uitvaltijd. Ik zou zeggen dat de Orde een onderdrukkingsinval aan de voorkant plant.",Vi har kjørt døgnet rundt i ukevis uten pause. Jeg vil si at Ordenen planlegger et undertrykkelsesangrep på Fronten.,"Od kilku tygodni pracujemy przez całą dobę bez przerwy. Powiedziałbym, że Zakon planuje zniszczyć Front.",Estamos trabalhando noite e dia por semanas sem descanso. Eu diria que a Ordem está planjeando um ataque para suprimir a Frente.,,Muncim non-stop de săptămăni fără niciun fel de pauză. Aș zice că Ordinul plănuiește un atac de reprimare asupra Frontului.,"Мы работаем круглые сутки без перерыва уже несколько недель. Мне кажется, Орден готовит решительный рейд, чтобы окончательно покончить с Сопротивлением.",,Vi har kört dygnet runt i flera veckor utan några avbrott. Jag skulle säga att Orden planerar en attack mot fronten.,Haftalardır hiç ara vermeden gece gündüz çalışıyoruz. Tarikat'ın Cephe'ye bir baskın planladığını söyleyebilirim. +"Oh, damn. The governor sent you. I was going to give him his cut, really I was. OK, listen. I've got a bundle stashed. It's yours if you look the other way.",TXT_DLG_SCRIPT04_D18192_OHDAM,MAP04: Derwin.,,,"A sakra. Guvernér tě poslal. Měl jsem v plánu dát mu jeho podíl, opravdu. Dobře, poslouchej. Mám schované nějaké zlaťáky, můžou být tvoje, když přimhouříš oko.","Åh, for pokker. Guvernøren har sendt dig. Jeg ville give ham sin andel, det ville jeg virkelig. Okay, hør her. Jeg har en bunke gemt. Det er dit, hvis du ser den anden vej.","Verdammt, der Gouverneur hat dich geschickt. Ich wollte ihm seinen Anteil geben - wirklich ich wollte das. Hör zu, ich habe hier was zur Seite geschafft, es gehört die wenn du die Sache auf sich beruhen läßt.",,"Ha, fek, la registo venigis vin; mi estis pagonta lin, serioze. Nu, aŭskultu, mi havas kelke da kaŝita mono; ĝi estas via se vi rigardos aliloken.","Ah, maldición, el gobernador te ha enviado; iba a darle su parte, en serio. Bueno, escucha, tengo un puñado escondido; es tuyo si miras para otro lado.","Ah, no puede ser, te manda el gobernador; iba a darle su parte, en serio. Bueno, escucha, tengo un puñado escondido; es tuyo si miras para otro lado.","Voi helvetti, kuvernööri on lähettänyt sinut. Meinasin antaa hänelle hänen siivunsa, ihan totta. Hei, kuuntele. Minulla on jemma kätkettynä. Se on sinun, jos katsot asiaa läpi sormiesi.","Oh, merde. Le gouverneur t'a envoyé? J'allais lui donner sa part, si, vraiment. Ok, écoute. J'en ai un paquet de mis de côté. Si tu veux, tu peux le prendre, si tu m'oublies.","Szóval a kormányzó küldött...francba. Oda akartam adni a megillető részét, hidd el tényleg. Figyelj, itt egy köteg eldugva. A tied ha képes vagy szemet hunyni felette.","Ah, dannazione... Ti ha mandato il governatore. Gli avrei dato la sua parte, giuro che l'avrei fatto. Ok, ascolta. Ho una parcella qua con me. È tua se chiudi un occhio.","クソッ、知事の回し者だな。 本当はあいつに分け前を渡そうとしてたんだがな。 よし、聞いてくれ。金はあるから、 -見逃してくれりゃお前にも分けてやる。","이런 제길... 총독 새끼가 널 보낸 거지? 하필 그 녀석의 몫을 보내기 전에. 좋아, 잘 들어. 날 살려주면 내가 숨긴 비상금을 줄게!","Oh, verdomme. De gouverneur heeft je gestuurd. Ik wilde hem zijn deel geven, echt waar. Oké, luister. Ik heb een bundel verstopt. Het is van jou als je de andere kant op kijkt.","Kurde. Przysłał cię gubernator. Chciałem się z nim podzielić udziałami, naprawdę. Ok, słuchaj. Mam tu ukryty pewien pakunek. Będzie twój jeśli zawrócisz.","Ah, merda. O governador enviou você. Eu ja ia passar a parte dele, sério mesmo. Ok, ouça. Eu tenho um pacote escondido aqui. Ele é seu se você deixar passar.",,,"Ох, чёрт. Ты от губернатора. Я собирался отдать ему его долю — клянусь. Слушай, я поднакопил изрядно денег — они твои, если найдёшь иной выход из ситуации.", -"All right, I'll let you go.",TXT_RPLY0_SCRIPT04_D18192_ALLRI,,,,"Dobře, nechám tě jít.","Ok, ich lass dich gehen.",,,"Muy bien, te dejaré ir.",,,"D'accord, tu peux y aller.",,,分かった、見逃そう。,좋아. 그럼 널 살려주지.,"Oké, ik laat je gaan.","Dobra, zostawię cię w spokoju.","Ok, vou te deixar em paz.",,,"Ладно, я дам тебе уйти.", -"Sorry, nothing personal.",TXT_RPLY1_SCRIPT04_D18192_SORRY,,,,"Promiň, nic osobního.","Tut mir leid, nimm es nicht persönlich",,,"Lo siento, no es nada personal.",,,"Désolé, rien de personnel.",,,悪いが、仕事なんでね。,"미안해, 사적인 건 아니야.","Sorry, niets persoonlijks.","Wybacz, nic osobistego.",Desculpe. Não é nada pessoal.,,,"Прости, ничего личного.", -"Nuts, if I'm going down, then so are you. Guards!!",TXT_DLG_SCRIPT04_D19708_NUTSI,,,,"K čertu, jestli mám zemřít, tak ty taky. Stráže!","Scheiße, aber wenn ich dran bin, bist du es auch. Wärter!",,,"Cuernos, si caigo, tú lo harás conmigo. ¡¡Guardias!!",,,"Putain, si je crève ici, alors tu y passe aussi! Gardes!",,,"社会の厳しさを分けてやるよ、お前もそうなれ。 -ガード!","썅! 아니야, 네가 가질 수 있는 건 전혀 없어! 경비병!!","Noten, als ik naar beneden ga, dan ben jij dat ook. Bewakers!!","Szlag, jeśli mam zginąć, to ty też. Straże!!","Porra, se eu vou morrer então você também vai. Guardas!!",,,"К чёрту — раз уж я сдохну, то и ты со мной. Стража!", -"Business my ass. Help, guards, I've got a live one.",TXT_DLG_SCRIPT04_D21224_BUSIN,,,,"Do hajzlu s nabídkami. Pomoc, stráže, mám tu živého!","Scheiß' aufs Geschäft. Wärter, ich habe hier einen Eindringling.",,,"¿Negocios? Al demonio. Ayuda, guardias, tengo uno vivo.",,,"Une affaire, mon cul! Gardes, à l'aide, j'en ai un de vivant ici!",,,"クソ野郎が、タダでは死なねえ。 +見逃してくれりゃお前にも分けてやる。","이런 제길... 총독 새끼가 널 보낸 거지? 하필 그 녀석의 몫을 보내기 전에. 좋아, 잘 들어. 날 살려주면 내가 숨긴 비상금을 줄게!","Oh, verdomme. De gouverneur heeft je gestuurd. Ik wilde hem zijn deel geven, echt waar. Oké, luister. Ik heb een bundel verstopt. Het is van jou als je de andere kant op kijkt.","Å, pokker. Guvernøren sendte deg. Jeg skulle gi ham hans andel, det skulle jeg virkelig. OK, hør her. Jeg har gjemt en bunke. Den er din hvis du ser den andre veien.","Kurde. Przysłał cię gubernator. Chciałem się z nim podzielić udziałami, naprawdę. Ok, słuchaj. Mam tu ukryty pewien pakunek. Będzie twój jeśli zawrócisz.","Ah, merda. O governador enviou você. Eu ja ia passar a parte dele, sério mesmo. Ok, ouça. Eu tenho um pacote escondido aqui. Ele é seu se você deixar passar.",,"Of, firar. Guvernatorul te-a trimis. Urma să îi dau partea lui din câștig, chiar urma, pe cuvânt. În regulă, ascultă. Am un pachet ascuns. E al tău dacă alegi să ignori ceea ce s-a întâmplat.","Ох, чёрт. Ты от губернатора. Я собирался отдать ему его долю — нет, правда. Слушай, я поднакопил изрядно денег — они твои, если найдёшь иной выход из ситуации.",,"Fan också. Guvernören skickade dig. Jag tänkte ge honom hans andel, verkligen. Okej, lyssna. Jag har en bunt gömt. Det är ditt om du tittar åt andra hållet.","Oh, kahretsin. Seni vali gönderdi. Ona payını verecektim, gerçekten. Tamam, dinle. Sakladığım bir paket var. Diğer tarafa bakarsan senindir." +"All right, I'll let you go.",TXT_RPLY0_SCRIPT04_D18192_ALLRI,〃,,,"Dobře, nechám tě jít.","Okay, jeg lader dig gå.","Ok, ich lass dich gehen.",,"Bone, vi rajtas foriri.","Muy bien, te dejaré ir.","Muy bien, te dejo ir.","Hyvä on, päästän sinut.","D'accord, tu peux y aller.","Rendben, elengedlek.","Va bene, ti lascerò andare.",分かった、見逃そう。,좋아. 그럼 널 살려주지.,"Oké, ik laat je gaan.","Greit, jeg skal la deg gå.","Dobra, zostawię cię w spokoju.","Ok, vou te deixar em paz.",,"În regulă, te las în pace.","Ладно, я дам тебе уйти.",,"Okej, jag låter dig gå.","Pekala, gitmene izin vereceğim." +"Sorry, nothing personal.",TXT_RPLY1_SCRIPT04_D18192_SORRY,〃,,,"Promiň, nic osobního.","Undskyld, det er ikke personligt.","Tut mir leid, nimm es nicht persönlich",,"Pardonon, mi nur laboras.","Lo siento, no es nada personal.",,"Pahoittelut, ei mitään henkilökohtaista.","Désolé, rien de personnel.","Sajnálom, nem személyes.","Mi spiace, nulla di personale.",悪いが、仕事なんでね。,"미안해, 사적인 건 아니야.","Sorry, niets persoonlijks.","Unnskyld, ikke ta det personlig.","Wybacz, nic osobistego.",Desculpe. Não é nada pessoal.,,"Scuze, nimic personal.","Прости, ничего личного.",,"Ledsen, inget personligt.","Üzgünüm, kişisel bir şey değil." +"Nuts, if I'm going down, then so are you. Guards!!",TXT_DLG_SCRIPT04_D19708_NUTSI,〃,,,"K čertu, jestli mám zemřít, tak ty taky. Stráže!","Fandens, hvis jeg ryger ned, så ryger du også ned. Vagter!!","Scheiße, aber wenn ich dran bin, bist du es auch. Wärter!",,"Al mil diabloj. Se mi falos, ankaŭ vi. Gardistoj!!","A tomar por saco. Si yo caigo, tú también. ¡¡Guardias!!","Al carajo. Si yo caigo, tú también. ¡¡Guardias!!","Vittu, jos kuolen nyt, niin sinäkin. Vartijat!!","Putain, si je crève ici, alors tu y passe aussi! Gardes!","Őrület! Ha Én lebukok, akkor rántalak magammal. Őrök!","Al diavolo, se devo andare al fondo, ti porterò con me. Guardie!!","社会の厳しさを分けてやるよ、お前もそうなれ。 +ガード!","썅! 아니야, 네가 가질 수 있는 건 전혀 없어! 경비병!!","Noten, als ik naar beneden ga, dan ben jij dat ook. Bewakers!!","Faen, hvis jeg går ned, så gjør du det også. Vakter!","Szlag, jeśli mam zginąć, to ty też. Straże!!","Porra, se eu vou morrer então você também vai. Guardas!!",,"Nebunie - dacă o iau la vale, atunci o să te iau cu mine. Gardieni!!","К чёрту — раз уж я сдохну, то и ты со мной. Стража!",,"Nuts, om jag åker ner, så gör du det också. Vakter!","Fındık, eğer ben batıyorsam, sen de batacaksın. Gardiyanlar!!" +"Business my ass. Help, guards, I've got a live one.",TXT_DLG_SCRIPT04_D21224_BUSIN,〃,,,"Do hajzlu s nabídkami. Pomoc, stráže, mám tu živého!","Skide være med forretningen! Hjælp, vagter, jeg har en indtrængende.","Scheiß' aufs Geschäft. Wärter, ich habe hier einen Eindringling.",,"«Intertraktadoj», kia feka ŝerco. Helpu min, gardistoj, estas viva ribelanto!","«Negocios» mis cojones. ¡Ayuda, guardias, tengo uno vivo!","«Negocios» las pelotas. ¡Ayuda, guardias, tengo uno vivo!","Ja paskat mitään kauppoja. Vartijat, apua. Tämä elää vielä.","Une affaire, mon cul! Gardes, à l'aide, j'en ai un de vivant ici!","Francokat üzlet. Segítség, őrök, itt van egy.","Alla faccia degli affari. Aiuto, guardie, c'è un intruso.","クソ野郎が、タダでは死なねえ。 助けてくれガード!イカれた奴がいる!","사적인 건 지랄하네. 경비병! 여기 노예가 도망친다! - \cy실례지만, 이거 좀 골때리겠는데?","Zaken mijn kont. Help, bewakers, ik heb een levende.","Do dupy z takim biznesem. Pomocy, straże, mamy tu kogoś żywego.","Negócios coisa nenhuma. Guardas, me ajudem, tenho um vivo aqui.",,,"Дело дрянь. Стража, на помощь! Тут живой повстанец.", -"Ah, I got word from Macil that you'd be coming. I have a way to get you inside the power station, but it's on the risky side.",TXT_DLG_SCRIPT04_D22740_AHIGO,,,,"Á, doneslo se mi od Macila, že přijdeš. Mám pro tebe cestu, jak se dostat do elektrárny, ale je trochu riskantní.","Ah, Macil hat mir mitgeteilt, dass du kommst. Ich kenne einen Weg, um in das Werk reinzukommen, aber es ist etwas riskant.",,,"Ah, tengo palabra de Macil de que vendrías. Tengo una forma de meterte en la estación eléctrica, pero es algo arriesgada.",,,"Ah, Macil m'a prévenu que vous viendriez. J'ai une entrée dans la centrale pour vous mais elle est un peu risquée.",,,"ああ、マシルから話は聞いたよ。 + \cy실례지만, 이거 좀 골때리겠는데?","Zaken mijn kont. Help, bewakers, ik heb een levende.","Drit i forretningene. Hjelp, vakter, jeg har en inntrenger!","Do dupy z takim biznesem. Pomocy, straże, mamy tu kogoś żywego.","Negócios coisa nenhuma. Guardas, me ajudem, tenho um vivo aqui.",,"Afaceri pe naiba. Ajutor, gardieni, am prins unul.","Дело дрянь. Стража, на помощь! Тут живой повстанец.",,"Affärer i min röv. Hjälp, vakter, jag har en levande.","Kıçımın işi. Yardım edin gardiyanlar, canlı bir tane var." +"Ah, I got word from Macil that you'd be coming. I have a way to get you inside the power station, but it's on the risky side.",TXT_DLG_SCRIPT04_D22740_AHIGO,MAP04: Worner.,,,"Á, doneslo se mi od Macila, že přijdeš. Mám pro tebe cestu, jak se dostat do elektrárny, ale je trochu riskantní.","Jeg fik besked fra Macil om, at du ville komme. Jeg har en måde at få dig ind i kraftværket på, men det er lidt risikabelt.","Ah, Macil hat mir mitgeteilt, dass du kommst. Ich kenne einen Weg, um in das Werk reinzukommen, aber es ist etwas riskant.",,"Ha, Macil diris al mi, ke vi estis venonta. Mi havas manieron meti vin en la centralon, sed ĝi estas riska.","Ah, Macil me ha dicho que ibas a venir. Tengo una forma de meterte en la central eléctrica, pero es algo arriesgada.","Ah, Macil me dijo que ibas a venir. Tengo una forma de meterte a la central eléctrica, pero es algo arriesgada.","Aah, sainkin Macililta viestin, että olisit tulossa. Minulla on keino saada sinut sisään voimalaitokseen, mutta se ei ole varmimmasta päästä.","Ah, Macil m'a prévenu que vous viendriez. J'ai une entrée dans la centrale pour vous mais elle est un peu risquée.","Ah, kaptam infót Maciltól hogy érkezni fogsz. Igazából van egy mód bejutni az erőműbe, de elég rizikós.","Ah, ho sentito da Macil che saresti arrivato. Ho un modo per farti entrare nella centrale energetica, ma è rischioso.","ああ、マシルから話は聞いたよ。 君を発電所に入れてやれるが -かなりリスキーな方法だぞ。","아! 마실 사령관님으로부터 당신이 여기로 온다는 소식을 들었습니다. 발전소로 깊숙이 향하는 지름길을 알고 있어요. 다만, 좀 위험하답니다.","Ah, ik heb van Macil gehoord dat je zou komen. Ik heb een manier om je in de centrale te krijgen, maar het is aan de riskante kant.","Ah, słyszałem od Macila, że przyjdziesz. Mam sposób, aby cię przedostać do środka elektrowni, ale jest to ryzykowne.","Ah, Macil me contou que você viria. Tenho um jeito de fazer você entrar na usina elétrica, mas é bem arriscado.",,,"А-а, мне сообщили, что ты от Мэйсила. Я знаю способ проникнуть на станцию, но он довольно рискованный.", -I'll take my chances.,TXT_RPLY0_SCRIPT04_D22740_ILLTA,,,,Já to zkusím.,Ich riskiere es.,,,Puedo asumir el riesgo.,,,Je suis prêt à prendre ces risques.,,,大丈夫だ。,그 정도야 각오하고 있습니다.,Ik neem mijn kansen.,Zaryzykuję.,Estou disposto a arriscar.,,,Я рискну., -"All right, I stole an I.D. from the corpse of some fool who fell into the reactor's coolant pit. --blat-- instant deep fry.",TXT_DLG_SCRIPT04_D24256_ALLRI,,,,"Tak dobře. Ukradl jsem identifikační kartu z mrtvoly nějakého chudáka, co spadl do reaktorové nádrže s chladivem. --Plesk--, okamžitě ho to upeklo.","Alles klar. Ich habe hier die Identitätskarte von so 'nem Trottel, der in die Kühlanlage des Reaktors reingefallen ist. --platsch-- hat ihn schockgefrostet.",,,"Muy bien, he robado la idenficiación del cadaver de un inútil que cayó en el pozo de refrigeración del reactor. --blat-- frito al instante.",,,Très vien. J'ai volé la carte d'identité d'un idiot qui est tombé dans le puits de refroidissement du réacteur. Plouf! Instantanément frit.,,,"わかった、このIDを受け取れ。 +かなりリスキーな方法だぞ。","아! 마실 사령관님으로부터 당신이 여기로 온다는 소식을 들었습니다. 발전소로 깊숙이 향하는 지름길을 알고 있어요. 다만, 좀 위험하답니다.","Ah, ik heb van Macil gehoord dat je zou komen. Ik heb een manier om je in de centrale te krijgen, maar het is aan de riskante kant.","Jeg fikk beskjed fra Macil om at du ville komme. Jeg har en måte å få deg inn i kraftverket på, men det er risikabelt.","Ah, słyszałem od Macila, że przyjdziesz. Mam sposób, aby cię przedostać do środka elektrowni, ale jest to ryzykowne.","Ah, Macil me contou que você viria. Tenho um jeito de fazer você entrar na usina elétrica, mas é bem arriscado.",,"Ah, am primit știrea de la Macil că urma să vii. Am o cale de a te infiltra în uzină, dar e riscantă.","А-а, мне сообщили, что ты от Мэйсила. Я знаю способ проникнуть на станцию, но он довольно рискованный.",,"Macil berättade att du skulle komma. Jag har ett sätt att få in dig i kraftverket, men det är lite riskabelt.",Macil'den geleceğin haberini aldım. Seni güç istasyonuna sokmanın bir yolunu buldum ama biraz riskli. +I'll take my chances.,TXT_RPLY0_SCRIPT04_D22740_ILLTA,〃,,,Já to zkusím.,Jeg tager mine chancer.,Ich riskiere es.,,Mi povas preni sur min la riskon.,Puedo asumir el riesgo.,,Kokeilen onneani.,Je suis prêt à prendre ces risques.,Vállalom a kockázatot.,Correrò il rischio.,大丈夫だ。,그 정도야 각오하고 있습니다.,Ik neem mijn kansen.,Jeg tar sjansen.,Zaryzykuję.,Estou disposto a arriscar.,,Voi risca.,Я рискну.,,Jag tar mina chanser.,Şansımı deneyeceğim. +"All right, I stole an I.D. from the corpse of some fool who fell into the reactor's coolant pit. --blat-- instant deep fry.",TXT_DLG_SCRIPT04_D24256_ALLRI,〃,,,"Tak dobře. Ukradl jsem identifikační kartu z mrtvoly nějakého chudáka, co spadl do reaktorové nádrže s chladivem. --Plesk--, okamžitě ho to upeklo.","Okay, jeg stjal et ID fra liget af et fjols, der faldt ned i reaktorens kølemiddelgrav. --blat-- øjeblikkelig friturestegning.","Alles klar. Ich habe hier die Identitätskarte von so 'nem Trottel, der in die Kühlanlage des Reaktors reingefallen ist. --platsch-- hat ihn schockgefrostet.",,"Bone. Mi ŝtelis la identigilon de la kadavro de stultulo, kiu falis en la malvarmigan truon de la reaktoro; «blat», tuje fritita.","Muy bien. He robado la identificación del cadáver de un inútil que cayó en el pozo refrigerante del reactor; «blat», frito al instante.","Muy bien. Me robé la identificación del cadáver de un inútil que se cayó al pozo refrigerante del reactor; «blat», frito al instante.","Hyvä on, varastin henkilötunnisteen joltain idiootilta, joka oli pudonnut reaktorin jäähdytyskuiluun. Pläts, pikauppopaisto.",Très vien. J'ai volé la carte d'identité d'un idiot qui est tombé dans le puits de refroidissement du réacteur. Plouf! Instantanément frit.,"Rendben van, elcsórtam egy szerencsétlen hullájáról az igazolványt aki beleesett a reaktor hűtőfolyadékába. --placcs-- rögtön ropogósra sült.","Molto bene allora, ho rubato una tessera d'identificazione da uno sciocco che è caduto nel pozzo refrigerante del reattore. --blat-- fritto instantaneamente.","わかった、このIDを受け取れ。 これはリアクターの冷却炉に落ちた間抜けが 持っていたものだ。 -バチッ!と一瞬で黒焦げになっちまったよ。",좋습니다. 이 신분증은 조심하지도 못하고 냉각 회로로 떨어진 한 불쌍한 녀석에게서 훔쳐온 겁니다. “뿌직”! 완전히 터졌죠.,"Oké, ik heb een I.D. gestolen van het lijk van een dwaas die in de koelvloeistofput van de reactor is gevallen. --Blat-- onmiddellijk frituren.","Dobra, ukradłem identyfikator ze zwłok pewnego durnia, który wpadł do chłodnicy reaktora. --puf-- i się usmażył.",Beleza. Eu roubei uma identificação do cadáver de algum otário que caiu no poço de refrigeração do reator. Pluft! Frito na hora. ,,,"Очень хорошо. Я украл удостоверение с трупа одного идиота, который упал прямо в котёл реактора. «Шмяк!» Моментальное прожаривание до костей.", -What should I do once I'm in?,TXT_RPLY0_SCRIPT04_D24256_WHATS,,,,Co mám udělat uvnitř?,"Was soll ich machen, wenn ich drin bin?",,,¿Qué debo hacer una vez dentro?,,,Qu'est ce que je fais une fois que je suis rentré?,,,中に入ったらどうすればいい?,그곳으로 들어간 후엔 뭘 해야 하죠?,Wat moet ik doen als ik eenmaal binnen ben?,Co mam zrobić jak wejdę?,O que devo fazer depois de entrar?,,,И что дальше?, -"Tell whoever asks that you're the replacement worker for Mr. Crispy. It's just dumb enough to work. Oh, and you might want to check out the storeroom that's right above us.",TXT_DLG_SCRIPT04_D25772_TELLW,,,,"Řekni komukoliv, kdo se zeptá, že jsi náhrada za pana Pečínku. Je to dost pitomé na to, aby to fungovalo. Jo, a možná bys mohl mít zájem podívat se do skladu, který je přímo nad námi.","Sage jedem, der dich fragt, dass du der Ersatz für Mister Crispy bist. Es ist idiotisch genug, um zu funktionieren. Oh, du solltest auch mal einen Blick in den Lagerraum auf der oberen Etage werfen.",,,"Dile a quien pregunte que eres el sustituto del Sr. Crujiente. Es suficientemente estúpido para que funcione. Oh, y puede que quieras comprobar el cuarto de alacenamiento justo sobre nosotros.",,,"Expliquez à qui veut l'entrendre que vous remplacez Mr. Frite. C'et suffisamment stupide pour marcher. Oh, et pensez à fouiller la salle de stockage au dessus de nous.",,,"誰かに聞かれたら、クリスピーの代わりに来た +バチッ!と一瞬で黒焦げになっちまったよ。",좋습니다. 이 신분증은 조심하지도 못하고 냉각 회로로 떨어진 한 불쌍한 녀석에게서 훔쳐온 겁니다. “뿌직”! 완전히 터졌죠.,"Oké, ik heb een I.D. gestolen van het lijk van een dwaas die in de koelvloeistofput van de reactor is gevallen. --Blat-- onmiddellijk frituren.",Jeg stjal et ID-kort fra liket til en idiot som falt ned i reaktorens kjølegrop. --...blat... øyeblikkelig frityrsteking.,"Dobra, ukradłem identyfikator ze zwłok pewnego durnia, który wpadł do chłodnicy reaktora. --puf-- i się usmażył.",Beleza. Eu roubei uma identificação do cadáver de algum otário que caiu no poço de refrigeração do reator. Pluft! Frito na hora. ,,Bine. Am furat un card de acces de pe cadavrul unui nătăfleț care a căzut în groapa sistemului de răcire al reactorului. --pleoșc--făcut scrum instant.,"Очень хорошо. Я украл удостоверение с трупа одного идиота, который упал прямо в охлаждающий бассейн реактора. «Шмяк!» — моментальное прожаривание до костей.",,Jag stal ett ID från en dåre som föll ner i reaktorns kylvattengrop. --blat-- omedelbar fritering.,"Pekala, reaktörün soğutucu çukuruna düşen bir aptalın cesedinden kimliğini çaldım. --Anında derin kızartma." +What should I do once I'm in?,TXT_RPLY0_SCRIPT04_D24256_WHATS,〃,,,Co mám udělat uvnitř?,"Hvad skal jeg gøre, når jeg er inde?","Was soll ich machen, wenn ich drin bin?",,Kion mi faru post mia eniro?,¿Qué debo hacer una vez dentro?,¿Qué hago una vez adentro?,Mitä teen päästyäni sisään?,Qu'est ce que je fais une fois que je suis rentré?,Mit tegyek amikor bejutottam?,E cosa devo fare una volta dentro?,中に入ったらどうすればいい?,그곳으로 들어간 후엔 뭘 해야 하죠?,Wat moet ik doen als ik eenmaal binnen ben?,Hva skal jeg gjøre når jeg er inne?,Co mam zrobić jak wejdę?,O que devo fazer depois de entrar?,,Ce trebuie să fac odată ce ajung în interior?,И что дальше?,,Vad ska jag göra när jag väl är inne?,İçeri girdiğimde ne yapmalıyım? +"Tell whoever asks that you're the replacement worker for Mr. Crispy. It's just dumb enough to work. Oh, and you might want to check out the storeroom that's right above us.",TXT_DLG_SCRIPT04_D25772_TELLW,〃,,,"Řekni komukoliv, kdo se zeptá, že jsi náhrada za pana Pečínku. Je to dost pitomé na to, aby to fungovalo. Jo, a možná bys mohl mít zájem podívat se do skladu, který je přímo nad námi.","Fortæl dem, der spørger, at du er afløseren for Mr Crispy. Det er lige dumt nok til at virke. Åh, og du vil måske tjekke lagerrummet lige over os.","Sage jedem, der dich fragt, dass du der Ersatz für Mister Crispy bist. Es ist idiotisch genug, um zu funktionieren. Oh, du solltest auch mal einen Blick in den Lagerraum auf der oberen Etage werfen.",,"Diru al tiu, kiu demandos, ke vi estas la anstataŭanto de la S-ro Krakulo; li estas sufiĉe stulta por kredi tion. Ha, kaj vi eble volas trarigardi la deponejon super ni.","A quien pregunte, dile que eres el sustituto del Sr. Crujiente; es lo bastante estúpido como para que funcione. Ah, y puede que quieras revisar el cuarto de almacenamiento que está justo sobre nosotros.",,"Jos joku kysyy, kerro olevasi herra Crispyn korvaaja. Saattaa olla jo niin tyhmä idea, että jopa toimii. Ai niin, ja saattanet haluta vilkaista varastohuonetta, joka sijaitsee suoraan yläpuolellamme.","Expliquez à qui veut l'entrendre que vous remplacez Mr. Frite. C'et suffisamment stupide pour marcher. Oh, et pensez à fouiller la salle de stockage au dessus de nous.","Akárki is kérdezi, mondd azt, hogy Kétszersült úr helyettesítése vagy. Akkora böszmeség, hogy még müködhet is. Ja, és érdemes lenne körbenézned a fölöttünk levő tárolóban.","Basta che tu dica a chiunque lo chieda che tu sei il rimpiazzo per il Signor Fritto. È abbastanza stupido da funzionare. Ah, e potrebbe anche interessarti il deposito che si trova proprio sopra di noi.","誰かに聞かれたら、クリスピーの代わりに来た と言え。皆疑うことなく信じるだろうさ。 あと、上の階にある倉庫も行けるなら 見てみた方がいいぞ。","누군가가 물어보면 통구이 씨의 후임으로 들어왔다고 하시면 됩니다. 별로 어려운 일은 아닐 거에요. 아, 그리고 우리 바로 위에 있는 창고도 한번 확인해보세요. - \cy으음. 왠지 무기 같은데. 화력이야 더 많으면 좋지.","Vertel degene die vraagt of jij de vervanger bent van Mr. Crispy. Het is net dom genoeg om te werken. Oh, en misschien wilt je eens kijken naar het magazijn dat vlak boven ons is.","Jak ktoś się będzie pytał, powiedz, że przyszedłeś na zastępstwo za Pana Chrupka. Jest to tak głupie, ale zadziała. Oh, i na pewno chciałbyś sprawdzić co jest w magazynie nad nami.","Diga pra quem perguntar que você é o substituto do Sr. Fritinho. É idiota o suficiente pra funcionar. Ah, e talvez você queira dar uma olhada no depósito lá em cima.",,,"Говори всем, что тебя прислали заменить г-на Поджаренного. Это так глупо, что должно сработать. И ещё, наверное, тебе захочется наведаться на склад, прямо над нами.", -Boy I hope this I.D. Works.,TXT_RPLY0_SCRIPT04_D25772_BOYIH,,,,Snad tahle karta funguje.,"Mann, ich hoffe, dass diese Karte auch funktioniert.",,,"Vaya, espero que esta identificación funcione.",,,"Eh bien, j'espère que cette carte fonctionnera.",,,このIDで上手くいけばいいが。,이 방법이 통했으면 좋겠네요.,"Jongen, ik hoop dat deze I.D. werkt.","Mam nadzieję, że ten identyfikator zadziała.","Olha, espero que esta identificação funcione.",,,"Ох. Надеюсь, это сработает.", -"Get out of here, unless you want to end up Mr. Dead.",TXT_DLG_SCRIPT04_D27288_GETOU,,,,"Jdi odsud, leda že by z tebe chtěl být pan Mrtvý.","Und nun verschwinde, wenn du nicht als Mister Tot enden willst.",,,"Lárgate de aqui, a menos que quieras acabar Sr. Muerto.",,,"Sortez de là, sauf si vous voulez être Mr. Mort.",,,"ここを離れた方がいい、君がミスターポックリに -成らない為に。",어서 가세요. 여기 계속 있다간 고인이 될 겁니다.,"Maak dat je wegkomt, tenzij je wilt eindigen als meneer de Dood.","Idź stąd, jeśli nie chcesz skończyć jako Pan Truposz.","Saia daqui, a não ser que você queria comer capim pela raiz.",,,"Уходи сейчас же, если не хочешь получить имя «г-н Покойник».", -"Hey, leave me alone. If they catch us wasting time we get dead, or extra work.",TXT_DLG_SCRIPT04_D28804_HEYLE,,,,"Hej, nech mě bejt. Jestli nás chytěj ztrácet čas, dostanem kulku, nebo práci navíc.","Lass mich in Ruhe. Wenn sie uns beim Quatschen erwischen, sind wir entweder beide tot oder kriegen Extraarbeit aufgebrummt.",,,"Hey, déjame en paz. Si nos pillan perdiendo el tiempo nos matan, o nos dan más trabajo.",,,"Hé, foutez-moi la paix, si ils nous attrappent ici à nous tourner les pouces, on y passe où c'est le travail forcé.",,,"話しかけないでくれ、 -奴等にバレたら処分されるか、残業させられる。","이봐, 나 좀 내버려 둬. 우리가 이렇게 농땡이 치는 걸 들키면 둘 다 죽는다고... 아님 추가 근무를 받는다든지!","Hé, laat me met rust. Als ze ons betrappen op tijdverspilling worden we dood, of extra werk.","Hej, zostaw mnie. Jeśli nas przyłapią na marnowaniu czasu to nas zabiją lub dadzą więcej pracy.","Ei, me deixe em paz. Se eles pegarem a gente fazendo corpo mole, a gente vai morrer ou receber trabalho extra.",,,"Эй, оставь меня в покое. Если они увидят, что мы болтаем, нас убьют... или добавят работы.", -"Such pressure, at this rate we'll be back to normal shifts soon. We're pumping tons of power to the castle and I'm almost finished logging those new weapons.",TXT_DLG_SCRIPT04_D30320_SUCHP,,,,"Takový tlak, tímhle tempem brzy budeme zase pracovat normální směny. Lijeme takové množství energie do hradu a já už jsem skoro hotov se zapisováním těch nových zbraní.","So viel Druck. Wenn es so weiter geht, gibt es bald wieder normale Schichten. Wir pumpen Tonnen von Energie in die Burg und ich habe die neuen Waffen fast alle verstaut.",,,"Cuanta presión, a este ritmo podremos volver pronto a turnos normales. Estamos dando montones de potencia al castillo y casi he terminado el registro de esas nuevas armas.",,,"Quelle pression. Si ça continue, on devrait revenir au rhytme de travail de base. On pompe des tonnes d'énergies pour le château et j'ai presque fini d'enregistrer toutes ces nouvelles armes.",,,"この圧力、この速さならすぐ通常のシフトに + \cy으음. 왠지 무기 같은데. 화력이야 더 많으면 좋지.","Vertel degene die vraagt of jij de vervanger bent van Mr. Crispy. Het is net dom genoeg om te werken. Oh, en misschien wilt je eens kijken naar het magazijn dat vlak boven ons is.",Si til alle som spør at du er vikar for Mr. Crispy. Det er dumt nok til å fungere. Og du vil kanskje sjekke lageret som er rett over oss.,"Jak ktoś się będzie pytał, powiedz, że przyszedłeś na zastępstwo za Pana Chrupka. Jest to tak głupie, ale zadziała. Oh, i na pewno chciałbyś sprawdzić co jest w magazynie nad nami.","Diga pra quem perguntar que você é o substituto do Sr. Fritinho. É idiota o suficiente pra funcionar. Ah, e talvez você queira dar uma olhada no depósito lá em cima.",,"Spune-i oricui te întreabă că ești înlocuitorul dl. Crispy. E suficient de stupid cât să funcționeze. Ah, și probabil vrei să verifici depozitul care se află chiar deasupra noastră.","Говори всем, что тебя прислали заменить г-на Поджаренного. Это так глупо, что должно сработать. И ещё, наверное, тебе захочется наведаться на склад, прямо над нами.",,"Säg till den som frågar att du är ersättare för Mr Crispy. Det är tillräckligt dumt för att fungera. Åh, och du kanske vill kolla in förrådet som ligger precis ovanför oss.","Soran kişiye Bay Çıtır'ın yerine gelen işçi olduğunu söyle. İşe yarayacak kadar aptalca. Oh, ve hemen üstümüzdeki depoya bakmak isteyebilirsin." +Boy I hope this I.D. Works.,TXT_RPLY0_SCRIPT04_D25772_BOYIH,〃,,,Snad tahle karta funguje.,"Jeg håber, at det her ID virker.","Mann, ich hoffe, dass diese Karte auch funktioniert.",,Espereble ĉi tiu identigilo funkcios.,"Vaya, espero que esta identificación funcione.",,"Toivon todellakin, että tämä tunniste toimii.","Eh bien, j'espère que cette carte fonctionnera.",Merem remélni hogy ez az igazolvány működni fog.,Spero proprio che questo tesserino funzioni.,このIDで上手くいけばいいが。,이 방법이 통했으면 좋겠네요.,"Jongen, ik hoop dat deze I.D. werkt.",Jeg håper denne legitimasjonen virker.,"Mam nadzieję, że ten identyfikator zadziała.","Olha, espero que esta identificação funcione.",,Mamă frate sper ca legitimația să funcționeze.,"Ох. Надеюсь, это сработает.",,Jag hoppas att det här ID-kortet fungerar.,Umarım bu kimlik işe yarar. +"Get out of here, unless you want to end up Mr. Dead.",TXT_DLG_SCRIPT04_D27288_GETOU,〃,,,"Vypadni odsud, leda že by z tebe chtěl být pan Mrtvý.","Forsvind herfra, medmindre du vil ende som Mr. Død.","Und nun verschwinde, wenn du nicht als Mister Tot enden willst.",,"Foriru, krom se vi volas iĝi S-ro Mortinto.","Ya vete, a menos que quieras ser el Sr. Muerto.",,"Ala liikkua, ellet sitten mieluummin halua ryhtyä herra Kalmon korvaajaksi.","Sortez de là, sauf si vous voulez être Mr. Mort.","Na húzz innen, ha nem akarod úgy végezni mint Halott úr.","Ora ti conviene andare, a meno che tu non voglia diventare Signor Morto.","ここを離れた方がいい、君がミスターポックリに +成らない為に。",어서 가세요. 여기 계속 있다간 고인이 될 겁니다.,"Maak dat je wegkomt, tenzij je wilt eindigen als meneer de Dood.","Kom deg ut herfra, med mindre du vil ende opp som Mr. Død.","Idź stąd, jeśli nie chcesz skończyć jako Pan Truposz.","Saia daqui, a não ser que você queria comer capim pela raiz.",,"Valea de aici, dacă nu vrei să devii dl. Mort.","Уходи сейчас же, если не хочешь стать «г-ном покойником».",,"Försvinn härifrån, om du inte vill bli herr Död.",Sonunun Bay Ölü olmasını istemiyorsan git buradan. +"Hey, leave me alone. If they catch us wasting time we get dead, or extra work.",TXT_DLG_SCRIPT04_D28804_HEYLE,MAP04: Warehouse → Dock Worker.,,,"Hej, nech mě bejt. Jestli nás chytěj ztrácet čas, dostanem kulku, nebo práci navíc.","Hey, lad mig være. Hvis de fanger os i at spilde tiden, bliver vi dræbt eller får ekstra arbejde.","Lass mich in Ruhe. Wenn sie uns beim Quatschen erwischen, sind wir entweder beide tot oder kriegen Extraarbeit aufgebrummt.",,"He, ne distru min. Se ili vidas, ke ni perdas tempon, ni estos mortigitaj... aŭ kun plia laboro.","Oye, déjame en paz. Si nos pillan perdiendo el tiempo nos matan... o nos dan más trabajo.","Oye, déjame en paz. Si nos ven perdiendo el tiempo nos matan... o nos dan más trabajo.","Hei, jätä minut rauhaan. Jos ne äkkäävät meidän tuhlaavan aikaa, saamme kuolla, tai lisää työtä.","Hé, foutez-moi la paix, si ils nous attrappent ici à nous tourner les pouces, on y passe où c'est le travail forcé.","Héj, hagyj engem békén. Ha meglátják, hogy itt lopjuk a napot, akkor vagy elintéznek vagy túlórát sóznak ránk.","Ehi, lasciami stare. Se ci beccano a perdere tempo ci ammazzano, o ci danno lavoro extra.","話しかけないでくれ、 +奴等にバレたら処分されるか、残業させられる。","이봐, 나 좀 내버려 둬. 우리가 이렇게 농땡이 치는 걸 들키면 둘 다 죽는다고... 아님 추가 근무를 받는다든지!","Hé, laat me met rust. Als ze ons betrappen op tijdverspilling worden we dood, of extra werk.","Hei, la meg være i fred. Hvis de tar oss i å kaste bort tid, blir vi drept, eller får ekstraarbeid.","Hej, zostaw mnie. Jeśli nas przyłapią na marnowaniu czasu to nas zabiją lub dadzą więcej pracy.","Ei, me deixe em paz. Se eles pegarem a gente fazendo corpo mole, a gente vai morrer ou receber trabalho extra.",,"Hei, lasă-mă în pace. Dacă ne prind pierzând vremea fie primim muncă în plus, fie moarte.","Эй, оставь меня в покое. Если они увидят, что мы болтаем, нас убьют, или добавят работы.",,Lämna mig ifred. Om de kommer på oss med att slösa tid blir vi dödade eller får extra arbete.,"Hey, beni yalnız bırak. Bizi boşa zaman harcarken yakalarlarsa ya ölürüz ya da fazladan iş alırız." +"Such pressure, at this rate we'll be back to normal shifts soon. We're pumping tons of power to the castle and I'm almost finished logging those new weapons.",TXT_DLG_SCRIPT04_D30320_SUCHP,MAP04: Reactor Core → Northern alarm green door → Level 2 door,,,"Takový tlak, tímhle tempem brzy budeme zase pracovat normální směny. Lijeme takové množství energie do hradu a já už jsem skoro hotov se zapisováním těch nových zbraní.","Sikke et pres, i dette tempo er vi snart tilbage på normale vagter. Vi pumper tonsvis af strøm til slottet, og jeg er næsten færdig med at logge de nye våben.","So viel Druck. Wenn es so weiter geht, gibt es bald wieder normale Schichten. Wir pumpen Tonnen von Energie in die Burg und ich habe die neuen Waffen fast alle verstaut.",,"Kia premo. Laŭ ĉi tia kadenco, la normalaj deĵoroj baldaŭ revenos. Ni pumpas tunojn da energio al la kastelo kaj mi preskaŭ finis registri tiujn novajn armilojn.",Cuanta presión. A este ritmo volveremos pronto a turnos normales. Estamos dándole toneladas de energía al castillo y ya casi termino de registrar esas nuevas armas.,Cuanta presión. A este ritmo vamos a volver pronto a turnos normales. Estamos dándole toneladas de energía al castillo y ya casi termino de registrar esas nuevas armas.,"Kovat paineet. Tällä tahdilla palaamme tuota pikaa normaaleihin työvuoroihin. Pumppaamme rutkasti voimaa linnaan, ja olen melkein saanut kirjattua uudet aseet.","Quelle pression. Si ça continue, on devrait revenir au rhytme de travail de base. On pompe des tonnes d'énergies pour le château et j'ai presque fini d'enregistrer toutes ces nouvelles armes.","Micsoda nyomás, ezzel az irammal vissza fogunk tudni térni a régi műszakba. Iszonyat áramot pumpálunk a kastélyba, és majdnem végeztem az új fegyverek nyílvántartásával. is.","Che pressione, a questo punto ritorneremo presto ai normali turni di lavoro. Stiamo indirizzando molta energia verso il castello, e ho quasi finito di catalogare quelle nuove armi.","この圧力、この速さならすぐ通常のシフトに 戻るだろう。私達は城へ大量の電気を供給して -いるし、新しい武器の切り出しも殆ど済んだ。","이런 압박감 속에 있다가는 다시 일반 교대 조로 복귀될 것 같아. 우린 지금 성 쪽으로 막대한 동력을 공급하고 있고, 난 저 신무기에 관한 일지를 거의 다 썼어.","Zulke druk, in dit tempo zullen we snel weer terug zijn bij normale diensten. We pompen tonnen energie naar het kasteel en ik ben bijna klaar met het kappen van die nieuwe wapens.","Tyle nacisku, w ten sposób wkrótce będziemy mieli znów normalne zmiany. Pompujemy tony energii do zamku, a ja prawie skończyłem załadowywać te nowe bronie.",Quanta pressão. Desse jeito voltaremos a fazer turnos normais logo. Estamos mandando bastante energia para o castelo e estou quase terminando de registrar essas novas armas.,,,"Такая нагрузка! С такими темпами мы вернёмся к нормальному графику совсем скоро. Мы направляем массу энергии в замок, и я почти закончил с погрузкой нового оружия.", -Weapons?,TXT_RPLY0_SCRIPT04_D30320_WEAPO,,,,Zbraní?,Waffen?,,,¿Armas?,,,Des armes?,,,武器?,신무기?,Wapens?,Bronie?,Armas?,,,Оружия?, -"What do you think, we're backed up on socks?",TXT_DLG_SCRIPT04_D31836_WHATD,,,,"Co si myslíš, že ve zbrojnici máme ponožky?","Was dachtest du denn, glaubst du wir verteidigen uns mit Socken?",,,"¿Qué crees, que vamos con calcetines?",,,Vous croyez quoi? Qu'on a un surplus de chausettes?,,,どう思う、ズボンがずり落ちないか?,"무슨 생각해? 양말 더 지급 받는 거? - \cy쉬운 일은 아니겠지만, 일단 한번 해보자고.","Wat denk je, dat we op sokken staan?","Co ty myślisz, że wysyłamy skarpetki?","Ora, você acha que usamos só as nossas meias?",,,"А ты думал, мы носки грузим?", -What kind of weapons?,TXT_RPLY0_SCRIPT04_D31836_WHATK,,,,Jaké zbraně?,Was für Waffen?,,,¿Qué clase de armas?,,,Quel type d'armes?,,,どんな武器だ?,어떤 신무기?,Wat voor wapens?,Jakie bronie?,Que tipo de armas?,,,Какое оружие?, -Are you deaf? I just told you how busy I am. Get back to work.,TXT_DLG_SCRIPT04_D33352_AREYO,,,,"Jsi hluchý? Už jsem ti řekl, jak jsem zaneprázdněný. Vrať se do práce.","Bist du taub? Ich hab dir dock gerade gesagt, wie beschäftigt ich bin. Geh zurück an die Arbeit.",,,¿Estás sordo? Ya te he dicho lo ocupado que estoy. Vuelve al trabajo.,,,"Vous êtes sourd? Je viens de vous dire que je suis occupé, retournez au travail!",,,難聴か? 私は、忙しい、から、仕事に、戻れ。,귀머거리야? 조금 전에 내가 얼마나 바쁜지 설명 했을 텐데? 일이나 해.,Ben je doof? Ik heb je net verteld hoe druk ik het heb. Ga terug aan het werk.,"Głuchy jesteś? Mówiłem ci, że jestem zajęty. Wracaj do pracy.",Você é surdo? Já te disse que estou bem ocupado. Volte ao trabalho.,,,"Ты глухой, что ли? Я же сказал тебе, что я занят. Иди работать!", -Who are you? Only clearance level two personnel are permitted in this area.,TXT_DLG_SCRIPT04_D34868_WHOAR,,,,Kdo jsi? Pouze pracovníci druhé úrovně sem mají povolen přístup.,Wer bist du? Nur Personal mit Zugangsstufe 2 hst hier Zutritt.,,,¿Quién eres? Solo el personal con permiso de nivel dos puede estar aquí.,,,Qui êtes vous? Seuls les personnes avec un niveau d'autorisation deux peuvent accéder à cette zone.,,,"誰だ? レベル2のクリアランスを持たない者は -ここに来てはいけないが。",넌 누구지? 이곳은 2급 인원만이 출입할 수 있다.,Wie ben jij? Alleen ontruimingsniveau twee personeel is toegestaan in dit gebied.,Kim jesteś? Tylko personel posiadający zezwolenie poziomu drugiego może tu przebywać.,Quem é você? Só funcionários com permissão nível 2 podem entrar nesta área.,,,Ты кто такой? Только персоналу второго уровня допуска разрешено находиться в этой зоне., -I'm the replacement worker.,TXT_RPLY0_SCRIPT04_D34868_IMTHE,,,,Jsem náhradník.,Ich bin der Ersatzarbeiter.,,,Soy el sustituto.,,,Je suis le remplaçant.,,,代替要員だ。,후임 근무자로 왔습니다.,Ik ben de vervanger.,Jestem tu na zastępstwo.,Eu sou o operário substituto.,,,Я замещаю рабочего., -"About time you showed up. Go talk with Ketrick in the core. Oh, and take this key card. Don't want you getting shot on your first day, huh?",TXT_DLG_SCRIPT04_D36384_ABOUT,,,,"Už bylo na čase, aby ses objevil. Jdi si promluvit s Ketrickem v jádře. A vezmi si tuhle kartu. Přece by ses nechtěl nechat zastřelit hned svůj první den, ne?","Wird auch Zeit, dass du hier erscheinst. Rede mit Ketrick im Reaktorkern, Und nimm diesen Schlüssel. Du willst ja wohl nicht gleich am ersten Tag erschossen werden, oder?",,,"Ya era hora. Ve a hablar con Ketrick en el núcleo. Oh, y toma esta tarjeta llave. No querrás que te peguen un tiro en tu primer día, ¿eh?",,,"Ah. Enfin. Il vous en a fallu, du temps! Allez parler avec Ketrick dans la section du cœur. Oh, et prenez ce passe. Vous ne voulez pas vous faire tirer dessus lors de votre premier jour, non?",,,"そろそろ来ると思っていたよ。コアにいる +いるし、新しい武器の切り出しも殆ど済んだ。","이런 압박감 속에 있다가는 다시 일반 교대 조로 복귀될 것 같아. 우린 지금 성 쪽으로 막대한 동력을 공급하고 있고, 난 저 신무기에 관한 일지를 거의 다 썼어.","Zulke druk, in dit tempo zullen we snel weer terug zijn bij normale diensten. We pompen tonnen energie naar het kasteel en ik ben bijna klaar met het kappen van die nieuwe wapens.","Med dette presset er vi snart tilbake til normale skift. Vi pumper masse strøm til slottet, og jeg er nesten ferdig med de nye våpnene.","Tyle nacisku, w ten sposób wkrótce będziemy mieli znów normalne zmiany. Pompujemy tony energii do zamku, a ja prawie skończyłem załadowywać te nowe bronie.",Quanta pressão. Desse jeito voltaremos a fazer turnos normais logo. Estamos mandando bastante energia para o castelo e estou quase terminando de registrar essas novas armas.,,"Ce presiuni, în ritmul ăsta o să revenim la turele obișnuite curând. Pompăm o tonă de energie către castel și aproape că am terminat să înregistrez aceste arme noi.","Такая нагрузка! С такими темпами мы вернёмся к нормальному графику совсем скоро. Мы направляем массу энергии в замок, и я почти закончил с погрузкой нового оружия.",,"Vilken press, i den här takten är vi snart tillbaka på normala skift. Vi pumpar tonvis med ström till slottet och jag är nästan klar med att logga de nya vapnen.","Ne baskı ama, bu gidişle yakında normal vardiyaya döneceğiz. Kaleye tonlarca güç pompalıyoruz ve yeni silahları kaydetmeyi neredeyse bitirdim." +Weapons?,TXT_RPLY0_SCRIPT04_D30320_WEAPO,〃,,,Zbraní?,Våben?,Waffen?,,Ĉu armiloj?,¿Armas?,,Aseet?,Des armes?,Fegyverek?,Armi?,武器?,신무기?,Wapens?,Våpen?,Bronie?,Armas?,,Arme?,Оружия?,,Vapen?,Silahlar mı? +"What do you think, we're backed up on socks?",TXT_DLG_SCRIPT04_D31836_WHATD,〃,,,"Co si myslíš, že ve zbrojnici máme ponožky?","Hvad tror du, vi er bagud med sokker?","Was dachtest du denn, glaubst du wir verteidigen uns mit Socken?",,Kion vi pensas? Ĉu ke ni agos per ŝtrumpetoj?,"¿Qué crees?, ¿que vamos con calcetines?","¿Qué crees?, ¿que vamos con medias o calcetines?","No mitä luulet meidän varastoineen, sukkia?",Vous croyez quoi? Qu'on a un surplus de chausettes?,"Mit gondolsz, zoknikkal vagyunk felfegyverkezve?","E che pensi, che ci difendiamo con dei calzini?",どう思う、ズボンがずり落ちないか?,"무슨 생각해? 양말 더 지급 받는 거? + \cy쉬운 일은 아니겠지만, 일단 한번 해보자고.","Wat denk je, dat we op sokken staan?","Hva tror du, at vi har sokker?","Co ty myślisz, że wysyłamy skarpetki?","Ora, você acha que usamos só as nossas meias?",,"Ce crezi, că suntem apărați pe șosete?","А ты думал, мы носки грузим?",,"Vad tror du, vi har inte tillräckligt med strumpor?","Ne düşünüyorsun, çorapları yedekledik mi?" +What kind of weapons?,TXT_RPLY0_SCRIPT04_D31836_WHATK,〃,,,Jaké zbraně?,Hvilken slags våben?,Was für Waffen?,,Kiu speco de armiloj?,¿Qué clase de armas?,,Minkälaisia aseita?,Quel type d'armes?,Miféle fegyverek?,Che tipo di armi?,どんな武器だ?,어떤 신무기?,Wat voor wapens?,Hva slags våpen?,Jakie bronie?,Que tipo de armas?,,Ce fel de arme?,Какое оружие?,,Vilken typ av vapen?,Ne tür silahlar? +Are you deaf? I just told you how busy I am. Get back to work.,TXT_DLG_SCRIPT04_D33352_AREYO,〃,,,"Jsi hluchý? Už jsem ti řekl, jak jsem zaneprázdněný. Vrať se do práce.","Er du døv? Jeg har lige fortalt dig, hvor travlt jeg har. Kom tilbage til arbejdet.","Bist du taub? Ich hab dir dock gerade gesagt, wie beschäftigt ich bin. Geh zurück an die Arbeit.",,"Ĉu vi estas surda? Mi ĵus diris, kiel okupata mi estas. Reiru al via laboro.",¿Estás sordo? Ya te he dicho lo ocupado que estoy. Vuelve al trabajo.,¿Estás sordo? Ya te dije lo ocupado que estoy. Vuelve al trabajo.,"Kuuroko olet? Juurihan kerroin, kuinka kiire minulla on. Mene takaisin töihisi.","Vous êtes sourd? Je viens de vous dire que je suis occupé, retournez au travail!",Süket vagy? Most mondtam el mennyire elfoglalt vagyok. Húzz vissza dolgozni!,Ma sei sordo? Ti ho appena detto quanto sono occupato. Torna al lavoro.,難聴か? 私は、忙しい、から、仕事に、戻れ。,귀머거리야? 조금 전에 내가 얼마나 바쁜지 설명 했을 텐데? 일이나 해.,Ben je doof? Ik heb je net verteld hoe druk ik het heb. Ga terug aan het werk.,Er du døv? Jeg sa nettopp hvor opptatt jeg er. Tilbake til arbeidet.,"Głuchy jesteś? Mówiłem ci, że jestem zajęty. Wracaj do pracy.",Você é surdo? Já te disse que estou bem ocupado. Volte ao trabalho.,,Ești surd? Tocmai ți-am spus că sunt ocupat. Întoarce-te la muncă.,"Ты глухой, что ли? Я же сказал тебе, что я занят. Иди работать!",,Är du döv? Jag berättade precis hur upptagen jag är. Fortsätt jobba.,Sağır mısın sen? Sana ne kadar meşgul olduğumu söyledim. İşinin başına dön. +Who are you? Only clearance level two personnel are permitted in this area.,TXT_DLG_SCRIPT04_D34868_WHOAR,MAP04: Reactor Core → Southern alarm green door,,,Kdo jsi? Pouze pracovníci druhé úrovně sem mají povolen přístup.,Hvem er du? Kun personale på sikkerhedsniveau to har adgang til dette område.,Wer bist du? Nur Personal mit Zugangsstufe 2 hst hier Zutritt.,,Kiu vi estas? Nur dunivelaj laboristoj estas permesataj ĉi tie.,¿Quién eres? Solo el personal con permiso de nivel dos puede estar aquí.,,Kuka sinä olet? Vain kakkoskulkuluvan omaavalla henkilöstöllä on pääsy tälle alueelle.,Qui êtes vous? Seuls les personnes avec un niveau d'autorisation deux peuvent accéder à cette zone.,Te meg ki vagy? Csak kettes szintű engedéllyel rendekezők jöhetnek be ide.,Chi sei? Solo il personale con l'autorizzazione di livello due può stare in questa sezione.,"誰だ? レベル2のクリアランスを持たない者は +ここに来てはいけないが。",넌 누구지? 이곳은 2급 인원만이 출입할 수 있다.,Wie ben jij? Alleen ontruimingsniveau twee personeel is toegestaan in dit gebied.,Hvem er du? Bare personell med klareringsnivå to har adgang til dette området.,Kim jesteś? Tylko personel posiadający zezwolenie poziomu drugiego może tu przebywać.,Quem é você? Só funcionários com permissão nível 2 podem entrar nesta área.,,Cine ești? Doar personalul cu nivel 2 de acces are voie în zona aceasta.,Ты кто такой? Только персоналу второго уровня допуска разрешено находиться в этой зоне.,,Vem är du? Endast personal på nivå två får vistas i det här området.,Kimsin sen? Bu bölgeye sadece ikinci seviye personel girebilir. +I'm the replacement worker.,TXT_RPLY0_SCRIPT04_D34868_IMTHE,〃,,,Jsem náhradník.,Jeg er afløseren.,Ich bin der Ersatzarbeiter.,,Mi estas la anstataŭanto.,Soy el sustituto.,,Olen täydennystyöntekijä.,Je suis le remplaçant.,Én vagyok a helyettes.,Sono il lavoratore sostitutivo.,代替要員だ。,후임 근무자로 왔습니다.,Ik ben de vervanger.,Jeg er vikaren.,Jestem tu na zastępstwo.,Eu sou o operário substituto.,,Sunt înlocuitorul muncitorului.,Я замещаю рабочего.,,Jag är ersättningsarbetaren.,Ben yedek işçiyim. +"About time you showed up. Go talk with Ketrick in the core. Oh, and take this key card. Don't want you getting shot on your first day, huh?",TXT_DLG_SCRIPT04_D36384_ABOUT,〃,,,"Už bylo na čase, aby ses objevil. Jdi si promluvit s Ketrickem v jádře. A vezmi si tuhle kartu. Přece by ses nechtěl nechat zastřelit hned svůj první den, ne?","Det var på tide, du dukkede op. Gå hen og snak med Ketrick i kernen. Åh, og tag dette nøglekort. Du skal ikke blive skudt på din første dag, hva'?","Wird auch Zeit, dass du hier erscheinst. Rede mit Ketrick im Reaktorkern, Und nimm diesen Schlüssel. Du willst ja wohl nicht gleich am ersten Tag erschossen werden, oder?",,"Vi finfine aperis. Iru paroli kun Ketrick en la kerno. Ha, kaj prenu ĉi tiun ŝlosil-karton; vi ne volas ricevi pafon dum via unua tago, ĉu?","Ya era hora. Ve a hablar con Ketrick en el núcleo. Ah, y toma esta tarjeta llave; no querrás que te peguen un tiro en tu primer día, ¿eh?",,"Jo oli aikakin ilmaantua. Mene ytimeen puhumaan Ketrickin kanssa. Ai niin, ja ota tämä avainkortti. Ei parane joutua ammutuksi heti ensimmäisenä työpäivänä, eikö niin?","Ah. Enfin. Il vous en a fallu, du temps! Allez parler avec Ketrick dans la section du cœur. Oh, et prenez ce passe. Vous ne voulez pas vous faire tirer dessus lors de votre premier jour, non?","Már ideje volt. Menj és beszélj Kettickkel a magban. Ja, és vidd magaddal ezt a mágneskártyát. Gondolom nem akarod magadat agyonlövetni az első napodon.","Finalmente sei arrivato. Vai a parlare a Ketrick nel nucleo. Ah, e prendi questa tessera chiave. Non è il caso di farsi sparare il primo giorno di lavoro, eh?","そろそろ来ると思っていたよ。コアにいる ケトリックに話しかけてくれ。 あとこのキーカードを受け取ってくれ。 -初日で撃たれたくないならな。","마침 잘 와주었군. 중심부에 있는 케트릭에게 가서 얘기하라. 아, 그리고 여기 키카드를 받아라. 첫날부터 총에 맞고 싶지는 않겠지, 응?","Het werd tijd dat je kwam opdagen. Ga praten met Ketrick in de kern. Oh, en neem deze sleutelkaart. Wil je niet dat je op je eerste dag wordt neergeschoten, huh?","W końcu jesteś. Idź, porozmawiaj z Ketrickiem przy rdzeniu. Oh, weź tą kartę-klucz. Nie chcesz chyba być zastrzelony podczas pierwszego dnia w pracy, co?","Já era hora de você aparecer. Vá falar com o Ketrick lá no núcleo. Ah, e leve este cartão de acesso. Você não vai querer levar um tiro no primeiro dia, hein?",,,"Как раз вовремя. Иди поговори с Кетриком возле ядра реактора. О, и возьми эту карточку. Мы ведь не хотим, чтобы тебя подстрелили в первый же рабочий день?", -Where's the power crystal?,TXT_RPLY0_SCRIPT04_D36384_WHERE,,,,Kde je energetický krystal?,Wo ist der Energiekristall?,,,¿Dónde está el cristal de poder?,,,Où se trouve le cristal du réacteur?,,,パワークリスタルは何処だ?,동력 수정체는 어디에 있죠?,Waar is het energiekristal?,Gdzie jest kryształ mocy?,Onde fica o cristal de energia?,,,Где энергетический кристалл?, -"If you don't get to work, you'll get shot anyway. Move your tunic.",TXT_DLG_SCRIPT04_D37900_IFYOU,,,,"Jestli se nepustíš do práce, zastřelí tě tak jako tak. Pohni tunikou!","Wenn du nicht arbeitest, wirst du eh erschossen. Und nun beweg deinen Arsch!",,,"Si no te pones a trabajar, te pegarán un tiro igual. Mueve tu túnica.",,,"Si vous ne partez pas travailler, vous allez vous faire tirer dessus de toutes manières. Bougez-vous les miches.",,,"今すぐ作業しないと奴等にバレて撃たれるぞ。 -さあ行け。",근무하러 안 가면 어차피 총살이야. 어서 일하러 가!,"Als je niet aan het werk gaat, wordt je toch al neergeschoten. Verplaats je tuniek.","Jeśli się nie weźmiesz do roboty, to tak czy siak cię zastrzelą. Rusz się.","Se você não trabalhar, você vai levar um tiro de qualquer jeito. Mexa-se.",,,"Если ты не приступишь к работе, тебя всё равно пристрелят. Шевелись!", -"I don't mean to sound alarmist, but if they keep pushing the power crystal this hard it's gonna flaw, and then shatter, and then *boom*! ...Just a thought.",TXT_DLG_SCRIPT04_D39416_IDONT,,,,"Nechci plašit, ale jestli budou krystal dál takhle protěžovat, tak se nalomí a pak roztříští a pak BUM! ...Jen tak přemýšlím.","Ich will ja nicht herumunken, aber wenn sie den Kristall weiter so überstrapazieren, nimmt er Schaden, und dann *bumm*! ...nur so ein Gedanke.",,,"No quiero sonar alarmante, pero ¡Si siguen forzando tanto el cristal de poder se rallará, y luego se partirá, y luego *boom*! ... Solo una idea.",,,"Je n'ai pas envie d'être alarmiste, mais si ils continuent de mettre autant de tension sur le cristal du réacteur, il risque d'être endommagé, éclater, et puis boum! Enfin, c'est juste ce que je pense.",,,"オーダーがもしパワークリスタルに負荷を +初日で撃たれたくないならな。","마침 잘 와주었군. 중심부에 있는 케트릭에게 가서 얘기하라. 아, 그리고 여기 키카드를 받아라. 첫날부터 총에 맞고 싶지는 않겠지, 응?","Het werd tijd dat je kwam opdagen. Ga praten met Ketrick in de kern. Oh, en neem deze sleutelkaart. Wil je niet dat je op je eerste dag wordt neergeschoten, huh?",På tide du dukket opp. Gå og snakk med Ketrick i kjernen. Og ta dette nøkkelkortet. Du vil vel ikke bli skutt på din første dag?,"W końcu jesteś. Idź, porozmawiaj z Ketrickiem przy rdzeniu. Oh, weź tą kartę-klucz. Nie chcesz chyba być zastrzelony podczas pierwszego dnia w pracy, co?","Já era hora de você aparecer. Vá falar com o Ketrick lá no núcleo. Ah, e leve este cartão de acesso. Você não vai querer levar um tiro no primeiro dia, hein?",,"Era și timpul. Du-te și vorbește cu Ketrick în interiorul nucleului. Ah, și ia și cardul ăsta. Nu cred că vrei să fii împușcat în prima zi de lucru, eh?","Как раз вовремя. Иди поговори с Кетриком возле ядра реактора. О, и возьми эту карточку. Мы ведь не хотим, чтобы тебя подстрелили в первый же рабочий день?",,"Det var på tiden att du dök upp. Gå och prata med Ketrick i kärnan. Och ta det här nyckelkortet. Jag vill inte att du blir skjuten på din första dag, va?","Tam zamanında geldin. Git merkezdeki Ketrick ile konuş. Bu anahtar kartını da al. İlk gününde vurulmanı istemeyiz, değil mi?" +Where's the power crystal?,TXT_RPLY0_SCRIPT04_D36384_WHERE,〃,,,Kde je energetický krystal?,Hvor er kraftkrystallen?,Wo ist der Energiekristall?,,Kie estas la energia kristalo?,¿Dónde está el cristal de poder?,,Missä voimakristalli on?,Où se trouve le cristal du réacteur?,Hol van az erőkristály?,Dov'è il cristallo?,パワークリスタルは何処だ?,동력 수정체는 어디에 있죠?,Waar is het energiekristal?,Hvor er kraftkrystallen?,Gdzie jest kryształ mocy?,Onde fica o cristal de energia?,,Unde e cristalul de alimentare?,Где энергетический кристалл?,,Var är kraftkristallen?,Güç kristali nerede? +"If you don't get to work, you'll get shot anyway. Move your tunic.",TXT_DLG_SCRIPT04_D37900_IFYOU,〃,,,"Jestli se nepustíš do práce, zastřelí tě tak jako tak. Pohni tunikou!","Hvis du ikke går på arbejde, bliver du skudt alligevel. Flyt din kittel.","Wenn du nicht arbeitest, wirst du eh erschossen. Und nun beweg deinen Arsch!",,Vi ricevos pafon ankaŭ se vi ne eklaboras. Movu vian tunikon.,"Si no te pones a trabajar, te pegarán igual un tiro. Mueve el culo.","Si no te pones a trabajar, te van a pegar igual un tiro. Ya muévete.","Jos et ryhdy töihin, sinut ammutaan kumminkin. Liikuta sitä ruhoasi.","Si vous ne partez pas travailler, vous allez vous faire tirer dessus de toutes manières. Bougez-vous les miches.","Ha nem dolgozol így is, úgy is agyonlőnek. Haladj már!","Se non ti metti subito a lavorare, ti spareranno ugualmente. Muovi la tua tuta.","今すぐ作業しないと奴等にバレて撃たれるぞ。 +さあ行け。",근무하러 안 가면 어차피 총살이야. 어서 일하러 가!,"Als je niet aan het werk gaat, wordt je toch al neergeschoten. Verplaats je tuniek.","Hvis du ikke kommer deg på jobb, blir du skutt uansett. Flytt tunikaen din.","Jeśli się nie weźmiesz do roboty, to tak czy siak cię zastrzelą. Rusz się.","Se você não trabalhar, você vai levar um tiro de qualquer jeito. Mexa-se.",,"Dacă nu te apuci de muncă, o să fii împuscat oricum. Miscă-ți tunica.","Если ты не приступишь к работе, тебя всё равно пристрелят. Шевелись!",,Om du inte börjar jobba blir du skjuten ändå. Flytta din tunika.,İşe gitmezsen zaten vurulacaksın. Tuniğini çek. +"I don't mean to sound alarmist, but if they keep pushing the power crystal this hard it's gonna flaw, and then shatter, and then *boom*! ...Just a thought.",TXT_DLG_SCRIPT04_D39416_IDONT,MAP04: Reactor Core → Northern alarm green door,,,"Nechci plašit, ale jestli budou krystal dál takhle protěžovat, tak se nalomí a pak roztříští a pak BUM! ...Jen tak přemýšlím.","Jeg vil ikke lyde alarmerende, men hvis de bliver ved med at presse energikrystallen så hårdt, så vil den flække, og så splintre, og så *bum*! ...Bare en tanke.","Ich will ja nicht herumunken, aber wenn sie den Kristall weiter so überstrapazieren, nimmt er Schaden, und dann *bumm*! ...nur so ein Gedanke.",,"Mi ne intencas soni alarme, sed se ili plue superŝargas la energian kristalon tiel multe, ĝi misfunkcios, poste ĝi rompiĝos kaj tiam «Bum!»... Por ke vi havu ian ideon.","No quiero sonar alarmante, pero si siguen forzando tanto el cristal de poder, primero fallará, luego se partirá y luego «¡Pum!»... Para que te hagas una idea.","No quiero sonar alarmante, pero si siguen forzando tanto el cristal de poder, primero va a fallar, luego se va a partir y luego «¡Pum!»... Para que te hagas una idea.","En halua kuulostaa pelon lietsojalta, mutta jos ne vaan jatkavat voimakristallin ajamista näin lujille, se säröytyy, sitten pirstoutuu, ja sitten pam! Ihan vain heittona.","Je n'ai pas envie d'être alarmiste, mais si ils continuent de mettre autant de tension sur le cristal du réacteur, il risque d'être endommagé, éclater, et puis boum! Enfin, c'est juste ce que je pense.","Nem akarok vészmadár lenni, de ha ennyire hajtják az erőkristályt, akkor megreped és eltörik, aztán meg *bumm*!...csak egy gondolat.","Non voglio sembrare un allarmista, ma se continuano a sovraccaricare il cristallo così tanto, ci sarà un errore, e il cristallo si spaccherà, e poi *boom*! ...Solo un pensiero.","オーダーがもしパワークリスタルに負荷を かけ続けていたら、いずれ限界でヒビが入って、 -砕けて、*ボーン*!...だと思うよ。","불안감을 조장하긴 싫지만, 동력 수정체를 지금처럼 심하게 다루면, 갑자기 균열이 나고, 조각나면서, 그리고 '쾅!' ... 그냥 그렇다고.","Ik wil geen paniekzaaier zijn, maar als ze zo hard op het energiekristal blijven duwen, gaat het scheuren, en dan versplinteren, en dan *boom*! ...Gewoon een gedachte.","Nie chcę brzmieć jak panikarz, ale jeśli dalej tak bardzo będą zużywać kryształ mocy, to się zepsuje, pęknie, a potem *bum*! ...Tak myślę.","Não quero parecer alarmista, mas se eles continuarem pressionando tanto esse cristal de energia ele vai falhar, depois vai quebrar e então bum! ...Só minha opinião.",,,"Не хочу показаться паникёром, но если продолжать так же сильно нагружать кристалл, он треснет, потом расколется, а потом «бум!».. Просто предположение.", -"Let me be quite clear. If this terminal locks up again, the coolant level will drop and we'll all have to answer to the Programmer. If we survive.",TXT_DLG_SCRIPT04_D40932_LETME,,,,"Abych byl přesný: Jestli tenhle terminál znovu zamrzne, hladina chladiva poklesne a všichni se budeme muset zodpovídat Programátorovi. Pokud přežijeme.","Lass es mich klar und deutlich sagen. Wenn dieses Terminal nochmal abstürzt, sinkt der Kühlungsflüssigkeitspegel und wir dürfen uns vor dem Programmierer verantworten - wenn wir überleben.",,,"Que quede claro. Si esta terminal vuelve a bloquearse, el nivel de refrigerante caerá y todos tendremos que responderle al Programador. Si sobrevivimos.",,,"Je vais être clair. Si ce terminal plante encore, les niveaux de liquide de refroidissement vont descendre et on aura tous à faire face au Programmeur. Si on survit, bien entendu.",,,"万が一このターミナルがフリーズしたら、 +砕けて、*ボーン*!...だと思うよ。","불안감을 조장하긴 싫지만, 동력 수정체를 지금처럼 심하게 다루면, 갑자기 균열이 나고, 조각나면서, 그리고 '쾅!' ... 그냥 그렇다고.","Ik wil geen paniekzaaier zijn, maar als ze zo hard op het energiekristal blijven duwen, gaat het scheuren, en dan versplinteren, en dan *boom*! ...Gewoon een gedachte.","Jeg mener ikke å høres alarmistisk ut, men hvis de fortsetter å presse kraftkrystallen så hardt, vil den sprekke, og så *boom*! ...Bare en tanke.","Nie chcę brzmieć jak panikarz, ale jeśli dalej tak bardzo będą zużywać kryształ mocy, to się zepsuje, pęknie, a potem *bum*! ...Tak myślę.","Não quero parecer alarmista, mas se eles continuarem pressionando tanto esse cristal de energia ele vai falhar, depois vai quebrar e então bum! ...Só minha opinião.",,"Nu vreau să par alarmist, dar... dacă o să continui să împingi cristalul atât de tare o să se crape, apoi sparge, iar apoi *bum*! ...Doar ziceam.","Не хочу показаться паникёром, но если продолжать так же сильно нагружать кристалл, он треснет, потом расколется, а потом «бум!».. Просто подумалось.",,"Jag vill inte låta alarmistisk, men om de fortsätter att trycka på kraftkristallen så här hårt kommer den att flaga, och sedan splittras, och sedan *boom*! ...Bara en tanke.","Endişeli görünmek istemem ama güç kristalini bu kadar zorlamaya devam ederlerse kusurlu olacak, sonra paramparça olacak ve sonra *boom*! ...Sadece bir düşünce." +"Let me be quite clear. If this terminal locks up again, the coolant level will drop and we'll all have to answer to the Programmer. If we survive.",TXT_DLG_SCRIPT04_D40932_LETME,MAP04: Reactor Core → Southern alarm green door,,,"Vyjádřím se jasně: Jestli tenhle terminál znovu zamrzne, hladina chladiva poklesne a všichni se budeme muset zodpovídat Programátorovi. Pokud přežijeme.","Lad mig gøre det helt klart. Hvis denne terminal låser sig igen, vil kølevæskeniveauet falde, og vi vil alle skulle stå til ansvar over for programmøren. Hvis vi overlever.","Lass es mich klar und deutlich sagen. Wenn dieses Terminal nochmal abstürzt, sinkt der Kühlungsflüssigkeitspegel und wir dürfen uns vor dem Programmierer verantworten - wenn wir überleben.",,"Mi klarigu: se ĉi tiu terminalo paneas denove, la malvarmiga nivelo falos kaj ni ĉiuj devos respondeci pri tio al la Programisto... se ni supervivis.","Que quede claro: si esta terminal vuelve a colgarse, el nivel de refrigerante caerá y todos tendremos que dar la cara ante el Programador... si no morimos antes.","Que quede claro: si esta terminal vuelve a bloquearse, el nivel de refrigerante va a caer y todos vamos a tener que dar la cara ante el Programador... si no morimos antes.","Tehdäänpä asia selväksi. Jos tämä pääte vielä hyytyy, jäähdytysnestetaso laskee ja meillä on vähän selittelemistä Ohjelmoitsijalle. Sillä ehdolla, että selviämme.","Je vais être clair. Si ce terminal plante encore, les niveaux de liquide de refroidissement vont descendre et on aura tous à faire face au Programmeur. Si on survit, bien entendu.","Lényegretörő leszek. Ha a terminál még egyszer lezár, a hűtő folyadék szintje visszaesik, és felelülnek kell majd a Programozó színe előtt. Már ha túléljük.","Voglio essere chiaro su questo. Se questa console si blocca di nuovo, il livello di refrigerazione calerà bruscamente e dovremo risponderne di ciò al Programmtore. Se sopravviveremo.","万が一このターミナルがフリーズしたら、 冷却液の水位が下がってプログラマーと 対面しなければならないだろうな。 メルトダウンから生還すればの話だが。","이거 하나만 확실히 말하지. 이 시설이 또 고장 난다면, 냉각수 수치가 떨어질 거고 우리 둘 다 프로그래머에게 문책을 받을 거야. 만약 살아남는다면 말이지. - \cy어쩌라고. 아무도 프로그래머들 이야기는 안 듣는데.","Laat ik heel duidelijk zijn. Als deze terminal weer vastloopt, zal het koelmiddelniveau dalen en zullen we ons allemaal moeten verantwoorden tegenover de programmeur. Als we het overleven.","Wyrażę się jasno. Jeśli terminal znów się zablokuje, to poziom płynu w chłodnicy spadnie i będziemy musieli za to odpowiadać przed Programistą. Jeśli wogóle przeżyjemy.","Só pra ficar bem claro. Se este terminal travar de novo, o nível de refrigeração vai cair e vamos nos ver com o Programador. Se nós sobrevivermos.",,,"Давай говорить начистоту. Если этот терминал опять заклинит, то уровень охлаждения упадёт, и нам всем придётся отвечать перед Программистом — если выживем.", -"You! Yeah, you. You aren't cleared for this area. Let me have your key card, fast. I'm in such a bad mood!",TXT_DLG_SCRIPT04_D42448_YOUYE,,,,"Ty! Jo, ty. Pro tuhle oblast nemáš povolení. Ukaž mi svou kartu, hned. Mám hodně špatnou náladu!","Du da! Ja, du. Du hast keine Berechtigung für diesen Bereich. Gib mir deine Schlüsselkarte, und zwar schnell! Ich bin ja sowas von sauer!",,,"¡Tú! Si, tú. No tienes permiso en esta área. Déjame tu tarjeta llave, rápido. ¡Estoy de tan mal humor!",,,"Vous! Oui, vous, vous, vous n'avez pas l'autorisation d'être dans cette zone! Donnez moi votre passe maintenant, et vite, je suis de sale humeur aujourd'hui!",,,"お前!そうだお前だ。ここは立入禁止だ。 -IDカードを見せろ、早く。今機嫌が悪いんだ!","너! 그래, 너 말이야. 넌 여기에 들어올 수 있는 권한이 없어. 당장 네 키카드를 내놔. 나 지금 기분 더럽다고!","Jij! Ja, jij. Je bent niet vrij voor dit gebied. Geef me je sleutelkaart, snel. Ik ben in zo'n slecht humeur!","Ty! Tak, ty. Nie masz pozwolenia, aby tu przebywać. Pokaż mi swoją kartę-klucz, szybko. Nie jestem dziś w dobrym nastroju!","Você aí! É, você mesmo. Você não tem permissão para estar aqui. Me passa esse cartão logo de uma vez. Estou de péssimo humor.",,,"Ты! Да, ты. У тебя нет сюда допуска. Давай свою карточку, быстро. Я сегодня в плохом настроении!", -"Here, here's my card.",TXT_RPLY0_SCRIPT04_D42448_HEREH,,,,"Tady, to je moje karta.","Hier, hier ist meine Karte.",,,"Toma, aquí está mi tarjeta.",,,Voilà mon passe.,,,ほら、これがカードだ。,"자, 카드 여기 있어요.","Hier, hier is mijn kaart.",Oto moja karta.,"Tome, aqui está o cartão.",,,"Вот, вот моя карта.", -This is garbage! Wait here. Oh screw it. Guards kill this intruder!,TXT_DLG_SCRIPT04_D43964_THISI,,,,"Blbost! Počkej tady. Á, kašlu na to. Stráže, zabte tohohle vetřelce!","Das ist ja wohl die Höhe! Warte hier. Ach was. Wärter, tötet hn!",,,"¡Esto es basura! Espera aquí. Oh que más da. Guardias, ¡Maten a este intruso!",,,"C'est quoi cette blague? Attendez ici. Non, en fait, Gardes! Descendez cet intrus!",,,"なんだこのゴミは! いや待て。ああ、畜生。 -ガード、侵入者を殺せ!","이게 뭐야?! 잠깐... 이런 젠장. 경비, 여기 침입자를 쏴버려!","Dit is vuilnis! Wacht hier. Oh, laat maar. Bewakers doden deze indringer!","To nie karta, to śmieć! Czekaj. Pieprzyć to. Straże zabijcie tego intruza!","Que merda é essa? Fique aqui. Ah, que se dane. Guardas, matem este intruso!",,,"Этой карточкой можно только подтереться! Жди здесь. А, к чёрту. Стража, здесь нарушитель! Убейте его!", -"Work, sleep, get tortured, what a life. Say, you the replacement for the careless pit diver?",TXT_DLG_SCRIPT04_D45480_WORKS,,,,"Práce, spánek, poležení si na skřipci, dobrej život. Hele, ty jsi ta náhrada za toho neopatrného skokana?","Arbeiten, schlafen, gefoltert werden, was für ein Leben. Sag mal, bist du der Ersatz für diesen sorglosen Grubentaucher?",,,"Trabajar, dormir, ser torturado, vaya vida. Dime, ¿eres el sustituto del imprudente buceador?",,,"Travail, sommeil, torture, quelle vie! Dites, vous êtes le remplaçant de l'unfortuné plongeur?",,,"働いて、寝て、処罰されて、なんて人生だ。 + \cy어쩌라고. 아무도 프로그래머들 이야기는 안 듣는데.","Laat ik heel duidelijk zijn. Als deze terminal weer vastloopt, zal het koelmiddelniveau dalen en zullen we ons allemaal moeten verantwoorden tegenover de programmeur. Als we het overleven.","La meg gjøre det helt klart. Hvis denne terminalen låser seg igjen, vil kjølevæskenivået synke, og vi må alle stå til ansvar for programmereren. Hvis vi overlever.","Wyrażę się jasno. Jeśli terminal znów się zablokuje, to poziom płynu w chłodnicy spadnie i będziemy musieli za to odpowiadać przed Programistą. Jeśli wogóle przeżyjemy.","Só pra ficar bem claro. Se este terminal travar de novo, o nível de refrigeração vai cair e vamos nos ver com o Programador. Se nós sobrevivermos.",,"Ca să fiu înțeles. Dacă terminalul ăsta se blochează iar, nivelul răcirii va scădea și vom fi trași la răspundere de Programator. Dacă supraviețuim.","Давай говорить начистоту. Если этот терминал опять заклинит, то уровень охлаждения упадёт, и нам всем придётся отвечать перед Программистом — если выживем.",,Låt mig vara helt tydlig. Om terminalen låser sig igen kommer kylvattennivån att sjunka och vi kommer alla att få stå till svars inför programmeraren. Om vi överlever.,"Açık konuşayım. Eğer bu terminal tekrar kilitlenirse, soğutma sıvısı seviyesi düşecek ve hepimiz Programcı'ya hesap vermek zorunda kalacağız. Eğer hayatta kalırsak." +"You! Yeah, you. You aren't cleared for this area. Let me have your key card, fast. I'm in such a bad mood!",TXT_DLG_SCRIPT04_D42448_YOUYE,MAP04: Ketrick.,,,"Ty! Jo, ty. Pro tuhle oblast nemáš povolení. Ukaž mi svou kartu, hned. Mám hodně špatnou náladu!","Dig! Ja, dig. Du er ikke godkendt til dette område. Giv mig dit nøglekort, hurtigt. Jeg er i så dårligt humør!","Du da! Ja, du. Du hast keine Berechtigung für diesen Bereich. Gib mir deine Schlüsselkarte, und zwar schnell! Ich bin ja sowas von sauer!",,"Vi! Jes, vi! Vi ne laboras en ĉi tiu sektoro. Montru vian ŝlosil-karton, rapide! Mi estas en tre malbona humoro!","¡Tú! Sí, tú. No tienes permiso en esta área. A ver tu tarjeta llave, ¡y rápido, que estoy de muy mal humor!",,"Sinä! Niin, sinä. Sinulla ei ole lupaa tälle alueelle. Anna minulle avainkorttisi, joutuin. Olen niin huonolla päällä!","Vous! Oui, vous, vous, vous n'avez pas l'autorisation d'être dans cette zone! Donnez moi votre passe maintenant, et vite, je suis de sale humeur aujourd'hui!","Te! Igen, Te. Nincs jogod itt lenni. Add csak ide az igazolványodat. Nem jó kedvemben találtál meg.","Tu! Si, tu. Non hai l'autorizzazione per quest'area. Dammi la tua chiave tessera, presto! Ho un diavolo per capello!","お前!そうだお前だ。ここは立入禁止だ。 +IDカードを見せろ、早く。今機嫌が悪いんだ!","너! 그래, 너 말이야. 넌 여기에 들어올 수 있는 권한이 없어. 당장 네 키카드를 내놔. 나 지금 기분 더럽다고!","Jij! Ja, jij. Je bent niet vrij voor dit gebied. Geef me je sleutelkaart, snel. Ik ben in zo'n slecht humeur!","Du! Ja, du. Du er ikke klarert for dette området. Gi meg nøkkelkortet ditt, fort. Jeg er i så dårlig humør!","Ty! Tak, ty. Nie masz pozwolenia, aby tu przebywać. Pokaż mi swoją kartę-klucz, szybko. Nie jestem dziś w dobrym nastroju!","Você aí! É, você mesmo. Você não tem permissão para estar aqui. Me passa esse cartão logo de uma vez. Estou de péssimo humor.",,"Tu! Da, tu! Nu ai acces în zona asta. Dă-mi cardul tău, rapid. Sunt extrem de indispus!","Ты! Да, ты. У тебя нет сюда допуска. Давай свою карточку, быстро. Я сегодня в плохом настроении!",,"Du! Ja, du. Du är inte godkänd för det här området. Ge mig ditt nyckelkort, snabbt. Jag är på så dåligt humör!","Sen! Evet, sen. Bu bölgeye giriş iznin yok. Anahtar kartını ver, çabuk. Çok kötü bir ruh halindeyim!" +"Here, here's my card.",TXT_RPLY0_SCRIPT04_D42448_HEREH,〃,,,"Tady, to je moje karta.","Her, her er mit kort.","Hier, hier ist meine Karte.",,Jen mia karto.,"Toma, aquí está mi tarjeta.",,Tässä on minun korttini.,Voilà mon passe.,"Parancsolj, itt a kártyám.",Ecco qua la mia tessera.,ほら、これがカードだ。,"자, 카드 여기 있어요.","Hier, hier is mijn kaart.","Her, her er kortet mitt.",Oto moja karta.,"Tome, aqui está o cartão.",,"Aici, aici e cardul.","Вот, вот моя карта.",,"Här, här är mitt kort.","İşte, işte kartım." +This is garbage! Wait here. Oh screw it. Guards kill this intruder!,TXT_DLG_SCRIPT04_D43964_THISI,〃,,,"Blbost! Počkej tady. Á, kašlu na to. Stráže, zabte tohohle vetřelce!","Det her er affald! Vent her. Åh, pis. Vagter dræber denne ubudne gæst!","Das ist ja wohl die Höhe! Warte hier. Ach was. Wärter, tötet hn!",,"Ĉi tio estas rubaĵo! Atendu ĉi tie... Ba, al mil diabloj. Gardistoj, mortigu ĉi tiun entrudiĝanton!","¡Esto es basura! Espera aquí... Bah, ¿que más da? ¡Guardias, maten a este intruso!","¡Esto es basura! Espera aquí... Bah, al carajo. ¡Guardias, maten a este intruso!","Mitä pötyä tämä on? Odota tässä. Äh, ja paskat. Vartijat, tappakaa tämä tunkeilija!","C'est quoi cette blague? Attendez ici. Non, en fait, Gardes! Descendez cet intrus!","Ez egy szemét! Várj meg itt. Najó, nem kínlódok vele. Őrök nyírjátok ki a behatolót!","Questa è spazzatura! Aspetta qui. Ah, dannazione. Guardie, uccidete questo intruso!","なんだこのゴミは! いや待て。ああ、畜生。 +ガード、侵入者を殺せ!","이게 뭐야?! 잠깐... 이런 젠장. 경비, 여기 침입자를 쏴버려!","Dit is vuilnis! Wacht hier. Oh, laat maar. Bewakers doden deze indringer!","Dette er søppel! Vent her. Drit i det. Vakter, drep inntrengeren!","To nie karta, to śmieć! Czekaj. Pieprzyć to. Straże zabijcie tego intruza!","Que merda é essa? Fique aqui. Ah, que se dane. Guardas, matem este intruso!",,"Ăsta e gunoi! Așteaptă aici. Oh las-o baltă. Gardieni, ucideți intrusul!","Этой карточкой можно только подтереться! Жди здесь. А, к чёрту. Стража, здесь нарушитель! Убейте его!",,"Det här är skräp! Vänta här. Åh, skit i det. Vakterna dödar den här inkräktaren!",Bu çöp! Burada bekle. Siktir et. Gardiyanlar bu davetsiz misafiri öldürün! +"Work, sleep, get tortured, what a life. Say, you the replacement for the careless pit diver?",TXT_DLG_SCRIPT04_D45480_WORKS,MAP04: Reactor Core → Sammis,,,"Práce, spánek, poležení si na skřipci, dobrej život. Hele, ty jsi ta náhrada za toho neopatrného skokana?","Arbejde, sove, blive tortureret. Sikke et liv. Er du afløseren for den skødesløse pit dykker?","Arbeiten, schlafen, gefoltert werden, was für ein Leben. Sag mal, bist du der Ersatz für diesen sorglosen Grubentaucher?",,"Labori, dormi, esti torturata; kia vivo. Do ĉu vi venis anstataŭi la senatentan tru-plonĝinton?","Trabajar, dormir, ser torturado; qué vida. A ver, ¿eres el sustituto del distraído que hizo un clavado al pozo?",,"Raada, nuku, joudu kidutetuksi, mikä elämä. Sanopa, sinäkö olet sen huolimattoman kuilusukeltajan korvaaja?","Travail, sommeil, torture, quelle vie! Dites, vous êtes le remplaçant de l'unfortuné plongeur?","Munka, alvás, kínzás, milyen jó kis élet is ez. Figyelj csak, Te nem a figyelmetlen akna búvár helyettese vagy?","Lavoro, dormire e venire torturati, che vita. Dì un po', sei tu il sostituto per l'incauto palombaro del pozzo?","働いて、寝て、処罰されて、なんて人生だ。 で、お前はあの冷却炉に落ちたアイツの -代替要員か?","일하고, 자고, 고문받고, 인생 참 멋지네. 자, 네가 그 부주의하게 추락사한 친구의 후임 맞지?","Werk, slaap, word gemarteld, wat een leven. Zeg, ben jij de vervanger van de onzorgvuldige pitduiker?","Spanie, praca, tortury, co za życie. Więc, jesteś tu na zastępstwo za tego co skoczył w przepaść?","Trabalhar, dormir, ser torturado. Que vida. Me diz uma coisa, você é o substituto daquele mergulhador de poço distraído?",,,"Работа, сон и пытки, что за жизнь. Так ты заменяешь нашего беспечного ныряльщика?", -"Yeah, can't wait to start.",TXT_RPLY0_SCRIPT04_D45480_YEAHC,,,,"Jo, už se nemůžu dočkat.","Ja, ich kanns kaum erwarten, hier anzufangen.",,,"Sí, tengo ganas de empezar.",,,"Oui, j'ai hâte de commencer.",,,そうだ、もう待てない。,"네, 일이 정말 기대됩니다.","Ja, ik kan niet wachten om te beginnen.","Tak, nie mogę się już doczekać.","É, mal posso esperar pra começar.",,,"Да, поскорей бы уже за дело.", -"Yeah, right. OK, get your ass to work.",TXT_DLG_SCRIPT04_D46996_YEAHR,,,,"Jo, jasně. Dobře, začni makat.","Na gut, schwing deinen Arsch zur Arbeit.",,,"Sí, claro. Ok, ponte a trabajar.",,,"Ouais, bien sûr. OK, allez bosser.",,,わかった。さっさと働け。,"그래, 좋아. 일이나 하라고.","Ja, juist. Oké, ga aan het werk.","Dobra. Ok, rusz swoją dupę do roboty.","Sim, sei. Tá, comece a trabalhar de uma vez.",,,"Да, конечно. Ладно, шуруй работать.", -Where's the crystal?,TXT_RPLY0_SCRIPT04_D46996_WHERE,,,,Kde je krystal?,Wo ist der Kristall?,,,¿Dónde está el cristal?,,,Où est le cristal?,,,クリスタルは何処だ?,수정체는 어디에 있죠?,Waar is het kristal?,Gdzie kryształ?,Onde fica o cristal?,,,Где кристалл?, -"Go talk to Ketrick. Bring the walkway up using the switches, then use this I.D. For the elevator.",TXT_DLG_SCRIPT04_D48512_GOTAL,,,,Promluv si s Ketrickem. Zvedni tlačítky schodiště a pak ve výtahu použij tuhle kartu.,"Rede mit Ketrick. Hebe den Steg mit den Schaltern an, dann benutze dies ID für den Lift.",,,"Habla con Ketrick. Alza la pasarela usando los interruptores, luego usa esta identificación para el ascensor.","Habla con Ketrick. Alza la pasarela usando los interruptores, luego usa esta identificación para el elevador.",,"Parlez à Ketrick. Vous pouvez étendre la coursive avec les boutons, puis utilisez ce passe pour l'ascenseur.",,,"ケトリックと話をしろ。 +代替要員か?","일하고, 자고, 고문받고, 인생 참 멋지네. 자, 네가 그 부주의하게 추락사한 친구의 후임 맞지?","Werk, slaap, word gemarteld, wat een leven. Zeg, ben jij de vervanger van de onzorgvuldige pitduiker?","Jobbe, sove, bli torturert, for et liv! Er du avløseren for den uforsiktige dykkeren?","Spanie, praca, tortury, co za życie. Więc, jesteś tu na zastępstwo za tego co skoczył w przepaść?","Trabalhar, dormir, ser torturado. Que vida. Me diz uma coisa, você é o substituto daquele mergulhador de poço distraído?",,"Muncă, odihnă, tortură, ce mai viață. Și, zici că ești înlocuitorul înotătorului neatent?","Работа, сон и пытки, что за жизнь. Так ты заменяешь нашего беспечного ныряльщика?",,"Jobba, sova, bli torterad, vilket liv. Säg, är du ersättaren för den slarviga gropdykaren?","Çalış, uyu, işkence gör, ne hayat ama. Söylesene, dikkatsiz çukur dalgıcının yerine sen mi geldin?" +"Yeah, can't wait to start.",TXT_RPLY0_SCRIPT04_D45480_YEAHC,〃,,,"Jo, už se nemůžu dočkat.","Ja, jeg kan ikke vente med at begynde.","Ja, ich kanns kaum erwarten, hier anzufangen.",,"Yes, kaj mi vere volas komenci.","Sí, y tengo ganas de empezar.",,"Kyllä, en malta odottaa.","Oui, j'ai hâte de commencer.","Igen, már alig várom, hogy kezdhessek.","Sì, non vedo l'ora di iniziare.",そうだ、もう待てない。,"네, 일이 정말 기대됩니다.","Ja, ik kan niet wachten om te beginnen.","Ja, jeg gleder meg til å begynne.","Tak, nie mogę się już doczekać.","É, mal posso esperar pra começar.",,"Deah, abia aștept să încep.","Да, поскорей бы уже за дело.",,"Ja, jag längtar efter att få börja.","Evet, başlamak için sabırsızlanıyorum." +"Yeah, right. OK, get your ass to work.",TXT_DLG_SCRIPT04_D46996_YEAHR,〃,,,"Jo, jasně. Dobře, začni makat.","Ja, det er rigtigt. OK, få din røv på arbejde.","Na gut, schwing deinen Arsch zur Arbeit.",,"Jes, kompreneble. Nu, eklaboru.","Sí, claro. Bueno, ponte a trabajar.",,"Just joo. Selvä, raahaa ahterisi töiden ääreen.","Ouais, bien sûr. OK, allez bosser.","Ja persze már. Na, húzzál dolgozni inkább.","Già, certo. OK, muovi il culo e vai a lavorare.",わかった。さっさと働け。,"그래, 좋아. 일이나 하라고.","Ja, juist. Oké, ga aan het werk.","Ja, sikkert. OK, få ræva di på jobb.","Dobra. Ok, rusz swoją dupę do roboty.","Sim, sei. Tá, comece a trabalhar de uma vez.",,"Deah, sigur. Bine, hai, la muncă.","Да, конечно. Ладно, шуруй работать.",,"Ja, visst. Okej, sätt dig i arbete.","Evet, doğru. Tamam, kıçını kaldır da işe koyul." +Where's the crystal?,TXT_RPLY0_SCRIPT04_D46996_WHERE,〃,,,Kde je krystal?,Hvor er krystallen?,Wo ist der Kristall?,,Kie estas la kristalo?,¿Dónde está el cristal?,,Missä kristalli on?,Où est le cristal?,Hol van a kristály?,Dov'è il cristallo?,クリスタルは何処だ?,수정체는 어디에 있죠?,Waar is het kristal?,Hvor er krystallen?,Gdzie kryształ?,Onde fica o cristal?,,Unde e cristalul?,Где кристалл?,,Var är kristallen?,Kristal nerede? +"Go talk to Ketrick. Bring the walkway up using the switches, then use this I.D. For the elevator.",TXT_DLG_SCRIPT04_D48512_GOTAL,〃,,,Promluv si s Ketrickem. Tlačítkem zvedni schodiště a ve výtahu pak použij tuhle kartu.,"Gå hen og snak med Ketrick. Få gangbroen op ved hjælp af kontakterne, og brug så dette ID til elevatoren.","Rede mit Ketrick. Hebe den Steg mit den Schaltern an, dann benutze dies ID für den Lift.",,Parolu al Ketrick. Levu la ponton per ĉi tiuj ŝaltiloj kaj tiam ekagigu la lifton per ĉi tiu identigilo.,Habla con Ketrick. Usa estos interruptores para alzar la pasarela y luego esta identificación con el ascensor.,,Mene puhumaan Ketrickin kanssa. Tuo kulkusilta vivuilla ylös ja sitten käytä hissiin tätä tunnistetta.,"Parlez à Ketrick. Vous pouvez étendre la coursive avec les boutons, puis utilisez ce passe pour l'ascenseur.","Menj és beszélj Ketrickkel. A kapcoslókkal emeld meg a szerelőhidat, majd használd ezt az igazolványt a lifthez.","Devi parlare con Ketrick. Usa i pulsanti per alzare la passarella, dopodiché usa questa tessera d'identificazione per l'ascensore. ","ケトリックと話をしろ。 隣のスイッチで道を上げこのカードで -エレベーターに乗るんだ。","케트릭에게 물어봐. 스위치를 눌러서 진입로를 올리고, 이 신분증을 써서 승강기를 타고 올라가.",Ga met Ketrick praten. Breng de loopbrug naar boven met behulp van de schakelaars en gebruik dan deze I.D. voor de lift.,"Idź porozmawiać z Ketrickiem. Podnieś chodnik za pomocą przełączników, potem użyj tego identyfikatora do windy.",Fale com o Ketrick. Use os interruptores para fazer a passarela subir e depois use esta identificação para o elevador.,,,"Сходи поговори с Кетриком. Используй переключатели на стене, чтобы подняться наверх, потом запусти лифт этой карточкой.", -Where's the crystal again?,TXT_RPLY0_SCRIPT04_D48512_WHERE,,,,"Můžeš mi znovu říct, kde je krystal?","Wo ist der Kristall, nochmal?",,,"De nuevo, ¿Dónde está el cristal?",,,Mais où est le cristal?,,,いいからクリスタルは何処だ?,수정체가 어디에 있다고요?,Waar is het kristal ook alweer?,"Jeszcze raz, gdzie kryształ?",Onde fica o cristal mesmo?,,,Ещё раз: где кристалл?, -"None of your business, go talk to Ketrick.",TXT_DLG_SCRIPT04_D50028_NONEO,,,,"Do toho ti nic není, jdi si promluvit s Ketrickem.","Geht dich nichts an, und jetzt rede mit Ketrick.",,,"No es asunto tuyo, ve a hablar con Ketrick.",,,Ca ne vous concerne pas. Allez voir Ketrick.,,,大きなお世話だ、ケトリックと話をしろ。,"상관 말고, 케트릭에게 물어봐.","Gaat je niets aan, ga met Ketrick praten.","Nie twój interes, idź porozmawiać z Ketrickiem.",Não é da sua conta. Vá falar com o Ketrick.,,,Не твоё дело. Иди поговори с Кетриком., -OK.,TXT_RPLY0_SCRIPT04_D50028_OK,,,,Dobře.,Ok.,,,Ok.,,,OK.,,,オーケー,알겠습니다.,OKÉ.,Ok.,Ok.,,,Понял., -"If it's busy work you want, go stare at that screen for a while, it'll bore you to tears.",TXT_DLG_SCRIPT04_D51544_IFITS,,,,"Jestli chceš tvrdou práci, jdi na chvíli zírat na tamtu obrazovku, unudí tě to k slzám.","Wenn du richtige Arbeit willst, dann starre mal für längere Zeit auf den Bildschirm. Das langweilt zu Tränen.",,,"Si es trabajo ocioso lo que buscas, ve a mirar esa pantalla un rato, te aburrirá hasta llorar.",,,"Si vous voulez un boulot éreintant, allez fixer cet écran pour quelques heures. Ca va vous ennuyer jusqu'a en pleurer.",,,"忙しい仕事を望んでいるなら、 +エレベーターに乗るんだ。","케트릭에게 물어봐. 스위치를 눌러서 진입로를 올리고, 이 신분증을 써서 승강기를 타고 올라가.",Ga met Ketrick praten. Breng de loopbrug naar boven met behulp van de schakelaars en gebruik dan deze I.D. voor de lift.,"Snakk med Ketrick. Få gangbroen opp med bryterne, og bruk dette kortet til heisen.","Idź porozmawiać z Ketrickiem. Podnieś chodnik za pomocą przełączników, potem użyj tego identyfikatora do windy.",Fale com o Ketrick. Use os interruptores para fazer a passarela subir e depois use esta identificação para o elevador.,,"Discută cu Ketrick. Ridică pasarela cu ajutorul butoanelor, apoi folosește legitimația asta pentru lift.","Сходи поговори с Кетриком. Используй переключатели на стене, чтобы подняться наверх, потом запусти лифт этой карточкой.",,"Gå och prata med Ketrick. Ta upp gångvägen med hjälp av växlarna, använd sedan det här ID-kortet för hissen.","Git Ketrick'le konuş. Anahtarları kullanarak geçidi yukarı getir, sonra asansör için bu kimliği kullan." +Where's the crystal again?,TXT_RPLY0_SCRIPT04_D48512_WHERE,〃,,,"Můžeš mi znovu říct, kde je krystal?",Hvor er krystallen igen?,"Wo ist der Kristall, nochmal?",,"Mi demandis, kie estas la kristalo.","De nuevo, ¿dónde está el cristal?",,Missä kristalli olikaan?,Mais où est le cristal?,Hol is van a kristály?,E il cristallo dov'è?,いいからクリスタルは何処だ?,수정체가 어디에 있다고요?,Waar is het kristal ook alweer?,Hvor er krystallen igjen?,"Jeszcze raz, gdzie kryształ?",Onde fica o cristal mesmo?,,Unde ziceai că e cristalul?,Ещё раз: где кристалл?,,Var är kristallen igen?,Kristal yine nerede? +"None of your business, go talk to Ketrick.",TXT_DLG_SCRIPT04_D50028_NONEO,〃,,,"Do toho ti nic není, jdi si promluvit s Ketrickem.","Det rager ikke dig, gå hen og snak med Ketrick.","Geht dich nichts an, und jetzt rede mit Ketrick.",,Tio ne estas via afero. Iru paroli al Ketrick.,No es asunto tuyo. Ve a hablar con Ketrick.,,"Ei kuulu sinulle, puhu Ketrickille.",Ca ne vous concerne pas. Allez voir Ketrick.,"Semmi közöd hozzá, menj beszélj Ketrickkel.","Non sono affari tuoi, vai a parlare con Ketrick.",大きなお世話だ、ケトリックと話をしろ。,"상관 말고, 케트릭에게 물어봐.","Gaat je niets aan, ga met Ketrick praten.",Ikke din sak. Snakk med Ketrick.,"Nie twój interes, idź porozmawiać z Ketrickiem.",Não é da sua conta. Vá falar com o Ketrick.,,Nu-i treaba ta. Discută cu Ketrick.,Не твоё дело. Иди поговори с Кетриком.,,"Det angår inte dig, gå och prata med Ketrick.","Seni ilgilendirmez, git Ketrick'le konuş." +Ok.,TXT_RPLY0_SCRIPT04_D50028_OK,〃,,,Dobře.,,,,Bone.,Bueno.,,OK.,OK.,OK.,OK.,オーケー,알겠습니다.,OKÉ.,GREIT.,,,,Bine.,Понял.,,OKEJ.,TAMAM. +"If it's busy work you want, go stare at that screen for a while, it'll bore you to tears.",TXT_DLG_SCRIPT04_D51544_IFITS,"〃 +(bored to tears = extremely bored)",,,"Jestli chceš tvrdou práci, jdi na chvíli zírat na tamtu obrazovku. Unudí tě to k pláči.","Hvis det er travlt arbejde du vil have, så gå hen og stirr på den skærm i et stykke tid, den vil kede dig til tårer.","Wenn du richtige Arbeit willst, dann starre mal für längere Zeit auf den Bildschirm. Das langweilt zu Tränen.",,"Se penigan laboron vi serĉas, iru rigardi tiun ekranon dum momento: vi mortos de enuo.","Si es trabajo duro lo que buscas, ve a mirar esa pantalla un rato: te morirás de aburrimiento.","Si es trabajo duro lo que buscas, ve a mirar esa pantalla un rato: te vas a morir de aburrimiento.","Jos puuhastelua kaipaat, niin mene tuijottamaan tuota ruutua joksikin aikaa. Eiköhän se ikävystytä sinut kuoliaaksi.","Si vous voulez un boulot éreintant, allez fixer cet écran pour quelques heures. Ca va vous ennuyer jusqu'a en pleurer.","Ha nagyon el akarod magad foglalni, akkor bámuld azt a monitort egy darabig. Halálra fog untatni.","Se vuoi un lavoro pesante, ti basta guardare quello schermo per un po', e ti annoierai a morte.","忙しい仕事を望んでいるなら、 そのスクリーンをしばらく見ていなさい、 -飽きて涙が浮かぶでしょう。",만약 더 쉬운 일을 원한다면 저 차단기를 계속 쳐다봐봐. 눈물 나도록 지루해 죽을걸.,"Als het druk werk is dat je wilt, ga dan een tijdje naar dat scherm staren, het zal je tot tranen toe vervelen.","Jeśli szukasz ciężkiej pracy, to idź pogapić się przez chwilę w ten ekran, zanudzi cię to na śmierć.","Se você quer ficar bem ocupado, fique olhando para essa tela por um tempo. Você vai morrer de tédio.",,,Если ты хочешь муравьиной работы — попялься какое-то время на тот экран... Наскучит до слёз., -The almighty Programmer is so paranoid of infiltration that he's locked up the computer core. How am I supposed to get my work done? The only way in is the suicide run.,TXT_DLG_SCRIPT04_D53060_THEAL,,,,"Všemocný Programátor je tak paranoidní, že uzamknul počítačové jádro. Jak mám takhle pracovat? Jediná cesta tam je skrz běh pro sebevrahy.","Der allmächtige Programmierer ist so paranoid, dass er den Computer blockiert hat. Wie soll ich so meine Arbeit machen? Der einzige weg wäre über den Selbstmordpfad.",,,El todopoderoso Programador tiene tal paranoia de infiltración que ha cerrado el núcleo de la computadora. ¿Cómo se supone que voy a hacer mi trabajo? La única entrada es la vía suicida.,,,"Ce tout-puissant Programmeur est tellement paranoïaque au sujet des infiltrations qu'il a mis le cœur informatique sous les verrous. Comment je peux faire mon travail maintenant? Si je veux essayer d'y entrer, faut que j'utilise le couloir du suicide!",,,"プログラマー様は潜入されるのを +飽きて涙が浮かぶでしょう。",만약 더 쉬운 일을 원한다면 저 차단기를 계속 쳐다봐봐. 눈물 나도록 지루해 죽을걸.,"Als het druk werk is dat je wilt, ga dan een tijdje naar dat scherm staren, het zal je tot tranen toe vervelen.","Hvis du vil ha mye å gjøre, kan du stirre på skjermen en stund. Den kjeder deg i hjel.","Jeśli szukasz ciężkiej pracy, to idź pogapić się przez chwilę w ten ekran, zanudzi cię to na śmierć.","Se você quer ficar bem ocupado, fique olhando para essa tela por um tempo. Você vai morrer de tédio.",,"Dacă vrei treabă pe bune, du-te holbează-te la ecranul ăla o vreme, te va plictisii până la lacrimi.","Если ты хочешь работы от ушей до пят, попялься какое-то время на тот экран... Наскучит до слёз.",,"Om du vill ha ett arbete, gå och stirra på den där skärmen ett tag, den kommer att tråka ut dig till tårar.","Eğer meşgul olmak istiyorsan, git bir süre şu ekrana bak, seni gözyaşlarına boğacak." +The almighty Programmer is so paranoid of infiltration that he's locked up the computer core. How am I supposed to get my work done? The only way in is the suicide run.,TXT_DLG_SCRIPT04_D53060_THEAL,MAP04: Reactor Core → Southern alarm green door,,,"Náš všemocný Programátor je tak paranoidní, že uzamknul počítačové jádro. Jak mám takhle pracovat? Jediná cesta tam je skrz běh pro sebevrahy.","Den almægtige programmør er så paranoid over for infiltration, at han har låst computerkernen inde. Hvordan skal jeg få mit arbejde gjort? Den eneste vej ind er selvmordsruten.","Der allmächtige Programmierer ist so paranoid, dass er den Computer blockiert hat. Wie soll ich so meine Arbeit machen? Der einzige weg wäre über den Selbstmordpfad.",,"La ĉiopova Programisto estas tiel paranoja pri ebla enŝoviĝo, ke li ŝlosis la komputilan kernon. Kiel mi supozeble laboros? La ununura ŝlosilo estas la vivo-riska vojo.",El todopoderoso Programador tiene tanta paranoia de infiltración que hasta ha cerrado el núcleo del ordenador. ¿Cómo se supone que voy a hacer mi trabajo? La única forma es por la vía suicida.,El todopoderoso Programador tiene tanta paranoia de infiltración que hasta cerró el núcleo de la computadora. ¿Cómo se supone que voy a hacer mi trabajo? La única forma es por la vía suicida.,"Kaikkivoipa Ohjelmoitsija on niin vainoharhainen soluttautujista, että on lukinnut tietokoneen ytimen. Miten minä muka työni saan tehdyksi? Ainoa tie sisään on itsemurhareitti.","Ce tout-puissant Programmeur est tellement paranoïaque au sujet des infiltrations qu'il a mis le cœur informatique sous les verrous. Comment je peux faire mon travail maintenant? Si je veux essayer d'y entrer, faut que j'utilise le couloir du suicide!","A mindenható Programozó annyira tart a behatolóktól, hogy elzárta a számítógép magot. Hogy kéne így végeznem a munkámat. Az egyetlen lehetőség a halál inga.","L'onnipotente Programmatore è così paranoico per le infiltrazioni che ha bloccato l'ingresso al nucleo del computer. Come posso finire il mio lavoro? L'unico modo per entrare è tramite il ""percorso suicida"".","プログラマー様は潜入されるのを 非常に恐れているらしく、コンピューターコアの ロックを厳重にするよう命じたんだ。 -どうやってあんな危ない所で仕事するんだ?",위대하신 프로그래머님이 침입에 대해 너무나도 불안해하셔서 컴퓨터 중심부를 락다운 시켰어. 일이 점점 더 어려워지고 있는 것 같아. 내 생각엔 자살기행을 또 해봐야겠어.,De almachtige Programmeur is zo paranoïde van infiltratie dat hij de computerkern heeft afgesloten. Hoe moet ik mijn werk gedaan krijgen? De enige manier om binnen te komen is de zelfmoordactie.,"Wszechmocny Programista ma paranoję na punkcie infiltracji tak bardzo, że zamknął rdzeń komputera. Jakim cudem mam skończyć pracę? Jedyną drogą, by tam się dostać jest ścieżka samobójców.",O todo-poderoso Programador é tão paranóico com infiltração que ele travou o núcleo de computação. Como que eu vou fazer o meu trabalho? A único jeito é a maneira suicida.,,,"Всемогущий Программист настолько боится диверсии, что закрыл компьютерную комнату. И как мне теперь выполнять свою работу? Есть один способ пройти туда, но это чистое самоубийство.", -Suicide run? What's that?,TXT_RPLY0_SCRIPT04_D53060_SUICI,,,,Běh pro sebevrahy? Co to je?,"Selbstmordpfad, was ist das?",,,¿Vía suicida? ¿Qué es eso?,,,Couloir du suicide? Comment ça?,,,危ない?どういう事だ?,자살기행? 그건 뭡니까?,Zelfmoordactie? Wat is dat?,Ścieżka samobójców? Co to?,Maneira suicida? O que é isso?,,,Самоубийство? О чём ты?, -"It's a sure-fire way to get killed, but that's not important right now. Go down the lift if you're so inclined.",TXT_DLG_SCRIPT04_D54576_ITSAS,,,,"Je to zaručený způsob, jak zemřít, ale to teď není důležité. Sjeď výtahem dolů, jestli tě to tak zajímá.","Es ist ein todsicherer weg um das Zeitliche zu segnen, aber das ist jetzt nicht wichtig. Nimm den Lift da drüben, wenn du Lust hast,und sieh selbst unten nach.",,,"Es una forma segura de matarte, pero eso no importa ahora. Baja por el ascensor si te atreves.",,,C'est un moyen garanti de se tuer. Mais ce n'est pas important pour l'instant. Descendez avec l'acsenseur si vous voulez absolument essayer.,,,"下手に立ち入ると射殺されるが、 +どうやってあんな危ない所で仕事するんだ?",위대하신 프로그래머님이 침입에 대해 너무나도 불안해하셔서 컴퓨터 중심부를 락다운 시켰어. 일이 점점 더 어려워지고 있는 것 같아. 내 생각엔 자살기행을 또 해봐야겠어.,De almachtige Programmeur is zo paranoïde van infiltratie dat hij de computerkern heeft afgesloten. Hoe moet ik mijn werk gedaan krijgen? De enige manier om binnen te komen is de zelfmoordactie.,Den allmektige programmereren er så paranoid for infiltrasjon at han har låst datakjernen. Hvordan skal jeg få arbeidet mitt gjort? Den eneste veien inn er selvmordsløpet.,"Wszechmocny Programista ma paranoję na punkcie infiltracji tak bardzo, że zamknął rdzeń komputera. Jakim cudem mam skończyć pracę? Jedyną drogą, by tam się dostać jest ścieżka samobójców.",O todo-poderoso Programador é tão paranóico com infiltração que ele travou o núcleo de computação. Como que eu vou fazer o meu trabalho? A único jeito é a maneira suicida.,,Atotputernicul Programator e atât de paranoic în privința infiltrărilor încât a încuiat nucleul calculatorului. Cum mi-aș putea face treaba? Singura cale de intrare e sinucidere.,"Всемогущий Программист настолько боится проникновения, что закрыл компьютерную комнату. И как мне теперь выполнять свою работу? Есть один способ пройти туда, но это чистое самоубийство.",,Den allsmäktige programmeraren är så paranoid för infiltration att han har låst in datorkärnan. Hur ska jag kunna få mitt arbete gjort? Den enda vägen in är självmordsresan.,Yüce Programcı sızma konusunda o kadar paranoyak ki bilgisayar çekirdeğini kilitledi. İşimi nasıl yapacağım? İçeri girmenin tek yolu intihar koşusu. +Suicide run? What's that?,TXT_RPLY0_SCRIPT04_D53060_SUICI,〃,,,Běh pro sebevrahy? Co to je?,Selvmordsruten? Hvad er det?,"Selbstmordpfad, was ist das?",,Ĉu vivo-riska vojo? Kio estas tio?,¿Vía suicida? ¿Cómo es eso?,,Itsemurhareitti? Mikä se on?,Couloir du suicide? Comment ça?,Halál inga? Az meg mi a fene?,"""Percorso suicida""? Che roba è?",危ない?どういう事だ?,자살기행? 그건 뭡니까?,Zelfmoordactie? Wat is dat?,Selvmordsløp? Hva er det?,Ścieżka samobójców? Co to?,Maneira suicida? O que é isso?,,O cale sinucigașă? Cum așa?,Самоубийство? О чём ты?,,Självmordslopp? Vad är det för något?,İntihar koşusu mu? O da ne? +"It's a sure-fire way to get killed, but that's not important right now. Go down the lift if you're so inclined.",TXT_DLG_SCRIPT04_D54576_ITSAS,〃,,,"Je to zaručený způsob, jak zemřít, ale to teď není důležité. Sjeď výtahem dolů, jestli tě to tak zajímá.","Det er en sikker måde at blive dræbt på, men det er ikke vigtigt lige nu. Gå ned i elevatoren, hvis du har lyst til det.","Es ist ein todsicherer Weg um das Zeitliche zu segnen, aber das ist jetzt nicht wichtig. Nimm den Lift da drüben, wenn du Lust hast,und sieh selbst unten nach.",,"Ĝi estas neeraripova maniero morti, sed tio nun ne estas grava. Iru malsupren per la lifto se vi estas inklina al tio.","Es una forma segura de matarte, pero eso no importa ahora. Baja por el ascensor si te apetece.",,"Se on taattu keino tapattaa itsensä, mutta sillä ei ole nyt väliä. Mene hissillä alas, jos niin haluat.",C'est un moyen garanti de se tuer. Mais ce n'est pas important pour l'instant. Descendez avec l'acsenseur si vous voulez absolument essayer.,"Egy holtbiztos módja, hogy kinyírasd magadat, de ez most nem lényeges. Menj le a lifttel, ha annyira érdekel.","È un ottimo metodo per rimanere uccisi, ma questo non è importante al momento. Scendi con l'ascensore, se sei così incline.","下手に立ち入ると射殺されるが、 今それどころではない。 そんなに行きたいならリフトを降りるんだな。","말 그대로 죽기 쉬운 방법인데, 더 알 필요는 없어. 궁금해 미치겠다면 밑으로 내려가 봐. - \cy오, 내가 숨어있어서 다행이야. 무슨 뜻인지 알겠지?","Het is een zekere manier om gedood te worden, maar dat is nu niet belangrijk. Ga de lift af als je zo geneigd bent.","To jest niezawodna droga, by dać się zabić, ale to nie jest teraz ważne. Zjedź windą, jeśli jesteś w stanie to zrobić.","É uma forma garantida de ser morto, mas isso não importa agora. Desça pelo elevador se você está tão curioso.",,,"Сунуться туда — верная гибель. Впрочем, сейчас это уже не важно. Спускайся на лифте, если не боишься.", -Halt. No one gets through here without authorization from the Warden or the Governor.,TXT_DLG_SCRIPT05_D0_HALTN,,,,Stát. Nikdo tudy nesmí projít bez povolení dozorce nebo guvernéra.,Halt. Niemand kommt hier ohne Autorisierung des Direktors durch.,,,Alto. Nadie entra aquí sin autorización del Carcelero o el Gobernador.,Alto. Nadie entra aquí sin autorización del Director o del Gobernador.,,Halte! Personne ne passe sans autorisation du gardien ou du gouverneur.,,,"止まれ。所長か知事の許可が無い限り -立ち入る事は許さん。",멈춰라. 총독이나 간수장의 허락을 받지 않은 이상 그 누구도 입장할 수 없다.,Stop. Niemand komt hier door zonder toestemming van de directeur of de gouverneur.,Stop. Nikt tu nie wejdzie bez zgody Naczelnika lub Gubernatora.,Alto. Ninguém passa por aqui sem autorização do Carcereiro ou do Governador.,,,Стой. Никто не может пройти сюда без разрешения от тюремщика или губернатора., -"Here's my pass, let me in.",TXT_RPLY0_SCRIPT05_D0_HERES,,,,"Tady je moje propustka, pusť mě dál.","Hier is mein Pass, lassen Sie mich rein.",,,"Aquí está mi pase, déjame entrar.",,,Voilà mon passe. Laissez-moi entrer.,,,これが許可証だ、入れてくれ。,여기 통행증입니다. 들여보내 주세요.,"Hier is mijn pas, laat me binnen.",Oto moja przepustka. Wpuść mnie.,Aqui está o meu passe. Deixe-me entrar.,,,Вот мой пропуск. Дай войти., -"OK, but talk only to the Warden.",TXT_DLG_SCRIPT05_D1516_OKBUT,,,,"Dobře, ale mluvte pouze s dozorcem.","Ok, aber reden Sie nur mit dem Direktor.",,,"Ok, pero habla solo con el Carcelero.","Ok, pero habla solo con el Director.",,"D'accord, mais vous ne vous pouvez parler qu'au gardien.",,,良いだろう、ただし話すのは所長とだけだ。,"알겠다. 하지만 간수장에게만 대화해라. - \cy뭐가 이리 불만이야. 나중에 얘 좀 꼭 처리해줘.","OK, maar praat alleen met de directeur.","Ok, ale rozmawiaj tylko z Naczelnikiem.","Ok, mas você só pode falar com o Carcereiro.",,,"Проходи, но говори только с тюремщиком.", -"Do I look like the Warden to you? Keep moving, this area's off limits.",TXT_DLG_SCRIPT05_D3032_DOILO,,,,"Vypadám snad jako dozorce? Pokračuj dál, do této oblasti je vstup zakázán.","Sehe ich wie ein Direktor aus? Beweg dich, du hast hier nichts zu suchen.",,,"¿Te parezco el Carcelero? Sigue andando, esta área está fuera de límite.","¿Te parezco el Director? Sigue moviéndote, esta área está fuera de límite.",,"Je ressemble au gardien, à ton avis? Bouge, cette zone est hors-limites!",,,"俺がワーデンに見えるか? どっか行け、 + \cy오, 내가 숨어있어서 다행이야. 무슨 뜻인지 알겠지?","Het is een zekere manier om gedood te worden, maar dat is nu niet belangrijk. Ga de lift af als je zo geneigd bent.","Det er en sikker måte å bli drept på, men det er ikke viktig akkurat nå. Ta heisen hvis du vil.","To jest niezawodna droga, by dać się zabić, ale to nie jest teraz ważne. Zjedź windą, jeśli jesteś w stanie to zrobić.","É uma forma garantida de ser morto, mas isso não importa agora. Desça pelo elevador se você está tão curioso.",,"E un mod garantat de a muri, dar nu contează acum. Ia liftul jos dacă ești curios.","Сунуться туда — верная гибель, но на данный момент это не важно. Спускайся на лифте, если не боишься.",,"Det är ett säkert sätt att bli dödad, men det är inte viktigt just nu. Gå ner i hissen om du vill.",Öldürülmek için kesin bir yol ama şu an bunun bir önemi yok. İstiyorsan asansörden aşağı in. +Halt. No one gets through here without authorization from the Warden or the Governor.,TXT_DLG_SCRIPT05_D0_HALTN,MAP05: Door Guard.,,,Stát. Nikdo tudy nesmí projít bez povolení dozorce nebo guvernéra.,Stop. Ingen kommer igennem her uden tilladelse fra direktøren eller guvernøren.,Halt. Niemand kommt hier ohne Autorisierung des Direktors durch.,,Haltu. Neniu eniras sen permeso el la provoso aŭ la registo.,Alto. Nadie entra aquí sin autorización del carcelero o del gobernador.,,Seis. Kukaan ei pääse tästä läpi ilman vankilanjohtajan tai kuvernöörin lupaa.,Halte! Personne ne passe sans autorisation du gardien ou du gouverneur.,Áljj! Nem haladhat át senki sem az Igazgató vagy Kormányzó engedélye nélkül.,Fermo lì. Nessuno passa qua senza l'autorizzazione del direttore o del governatore.,"止まれ。所長か知事の許可が無い限り +立ち入る事は許さん。",멈춰라. 총독이나 간수장의 허락을 받지 않은 이상 그 누구도 입장할 수 없다.,Stop. Niemand komt hier door zonder toestemming van de directeur of de gouverneur.,Stopp. Ingen kommer gjennom her uten tillatelse fra direktøren eller guvernøren.,Stop. Nikt tu nie wejdzie bez zgody Naczelnika lub Gubernatora.,Alto. Ninguém passa por aqui sem autorização do Carcereiro ou do Governador.,,Stop. Nimeni nu trece pe aici fără autorizație de la Director sau Guvernator.,Стой. Никто не может пройти сюда без разрешения от тюремщика или губернатора.,,Halt. Ingen kommer igenom här utan tillstånd från föreståndaren eller guvernören.,Durun. Müdür ya da Vali'nin izni olmadan kimse buradan geçemez. +"Here's my pass, let me in.",TXT_RPLY0_SCRIPT05_D0_HERES,〃,,,"Tady je moje propustka, pusť mě dál.","Her er mit pas, luk mig ind.","Hier is mein Pass, lassen Sie mich rein.",,Jen mia enirpermeso; lasu min eniri.,Aquí está mi pase; déjeme entrar.,,Tässä lupani; päästäkää minut sisään.,Voilà mon passe. Laissez-moi entrer.,"Itt az igazolásom, engedj be.","Ecco la mia autorizzazione, fammi entrare.",これが許可証だ、入れてくれ。,여기 통행증입니다. 들여보내 주세요.,"Hier is mijn pas, laat me binnen.","Her er passet mitt, slipp meg inn.",Oto moja przepustka. Wpuść mnie.,Aqui está o meu passe. Deixe-me entrar.,,"Aici e legitimația, lasă-mă să intru.",Вот мой пропуск. Дай войти.,,"Här är mitt passerkort, släpp in mig.","İşte kartım, beni içeri alın." +"OK, but talk only to the Warden.",TXT_DLG_SCRIPT05_D1516_OKBUT,〃,,,"Dobře, ale mluvte pouze s dozorcem.","Okay, men tal kun med direktøren.","Ok, aber reden Sie nur mit dem Direktor.",,"Bone, sed limu vin paroli kun la provoso.","Entendido, pero limítate a hablar con el carcelero.",,"Selvä, mutta puhu ainoastaan vankilanjohtajan kanssa.","D'accord, mais vous ne vous pouvez parler qu'au gardien.","OK, de csak az igazgatóval beszélj.","OK, ma parla solo con il direttore.",良いだろう、ただし話すのは所長とだけだ。,"알겠다. 하지만 간수장에게만 대화해라. + \cy뭐가 이리 불만이야. 나중에 얘 좀 꼭 처리해줘.","OK, maar praat alleen met de directeur.","OK, men snakk bare med direktøren.","Ok, ale rozmawiaj tylko z Naczelnikiem.","Ok, mas você só pode falar com o Carcereiro.",,"Bine, dar vorbești doar cu Directorul.","Проходи, но говори только с тюремщиком.",,"Okej, men prata bara med fängelsedirektören.","Tamam, ama sadece müdürle konuş." +"Do I look like the Warden to you? Keep moving, this area's off limits.",TXT_DLG_SCRIPT05_D3032_DOILO,〃 (After killing Montag),,,"Vypadám snad jako dozorce? Pokračuj dál, do této oblasti je vstup zakázán.","Ligner jeg direktøren? Fortsæt, dette område er forbudt område.","Sehe ich wie ein Direktor aus? Beweg dich, du hast hier nichts zu suchen.",,"Ĉu mi aspektas kiel la provoso laŭ vi? Foriru, ĉi tiu zono estas ekster la limoj.","¿Te parezco el carcelero? Ya vete, que esta área está fuera de los límites.",,Näytänkö minä sinulle vankilanjohtajalta? Jatka matkaasi; tähän alueeseen on pääsy kielletty.,"Je ressemble au gardien, à ton avis? Bouge, cette zone est hors-limites!","Úgy nézek ki, mint egy igazgató? Haladj tovább, ez a terület nem látogatható.","Ti sembro forse il direttore? Non stare fermo qua, quest'area è riservata al personale autorizzato.","俺がワーデンに見えるか? どっか行け、 この区域は立入禁止だ。","내가 친히 나서서 간수장을 찾아야겠나? 어서 움직여. 이곳은 통행 금지야. - \cy“이곳은 통행 금지야!” 웃기고 앉아있네.","Zie ik eruit als de directeur? Blijf bewegen, dit gebied is verboden terrein.","Czy według ciebie wyglądam na Naczelnika? Rusz się, nikt nie ma wstępu na ten obszar.",Está achando que eu sou o Carcereiro? Suma daqui. Você não pode andar por aqui.,,,"Я что, похож на тюремщика? Двигай отсюда! Здесь закрытая территория!", -The Order's wrath will rain down on these servants until they beg for death.,TXT_DLG_SCRIPT05_D4548_THEOR,,,,Hněv Řádu dopadne na ty služebníky dokud nebudou prosit o smrt.,"Der Zorn des Ordens wird auf diese Untergebenen herabregnen, bis sie um den Tod betteln.",,,La ira de la Orden caerá sobre estos sirvientes hasta que supliquen por su muerte.,,,La colère de l'Ordre s'abattrera sur ces serviles miséreux jusqu'a ce qu'ils pleurent pour leur propre mort.,,,"オーダーの怒りは、奴等が死を望むまで + \cy“이곳은 통행 금지야!” 웃기고 앉아있네.","Zie ik eruit als de directeur? Blijf bewegen, dit gebied is verboden terrein.","Ser jeg ut som direktøren? Gå videre, dette området er forbudt område.","Czy według ciebie wyglądam na Naczelnika? Rusz się, nikt nie ma wstępu na ten obszar.",Está achando que eu sou o Carcereiro? Suma daqui. Você não pode andar por aqui.,,"Ți se pare că eu sunt Directorul? Continuă să mergi, asta e o zonă fără acces.","Я что, похож на тюремщика? Двигай отсюда. Здесь закрытая территория!",,"Ser jag ut som fängelsedirektören? Fortsätt gå, det här området är förbjudet område.","Sana Müdür gibi mi görünüyorum? Devam edin, bu bölge yasak bölge." +The Order's wrath will rain down on these servants until they beg for death.,TXT_DLG_SCRIPT05_D4548_THEOR,MAP05: Prison Guard.,,,Hněv Řádu dopadne na ty služebníky dokud nebudou prosit o smrt.,"Ordenens vrede vil regne ned over disse tjenere, indtil de tigger om at dø.","Der Zorn des Ordens wird auf diese Untergebenen herabregnen, bis sie um den Tod betteln.",,La tondro de La Ordeno pluvos sur tiujn servantojn ĝis ili petegos pri morto.,La ira de La Orden caerá sobre estos sirvientes hasta que supliquen por su muerte.,La ira de La Orden va a caer sobre estos sirvientes hasta que supliquen por su muerte.,"Veljeskunnan viha säilyy näiden palvelijoiden yllä siihen asti, kunnes rukoilevat kuolemaa.",La colère de l'Ordre s'abattrera sur ces serviles miséreux jusqu'a ce qu'ils pleurent pour leur propre mort.,"A Rend haragja fog lesújtani ezekre a szolgákra, egészen addig amíg nem könyörögnek a halálért.",La furia dell'Ordine si riverserà su questi servi finché non chiederanno pietà!,"オーダーの怒りは、奴等が死を望むまで 止む事はない。","이 죄인들이 죽음을 바라기 전까지는 오더의 심판과 응징을 받을 것이다. - \cy아주 들떠있는 녀석이네.",De toorn van de Orde zal op deze bedienden neerdalen tot ze om de dood smeken.,Gniew Zakonu spadnie jak deszcz na te sługi dopóki nie będą błagać o śmierć.,A ira da Ordem descerá a esses servos até eles implorarem pela morte.,,,"Гнев Ордена обрушится на этих рабов, и они будут молить о смерти.", -"I don't care if Mourel gave you a pass. This is my prison. My key is the only way in or out, and I'm not taking any chances. The Order does not tolerate mistakes.",TXT_DLG_SCRIPT05_D6064_IDONT,,,,"Mě je jedno, že ti Mourel dal propustku. Tohle je moje vězení. Můj klíč je jediná cesta dovnitř a ven a já nehodlám nic riskovat. Řád netoleruje chyby.","Es ist mir egal ob Mourel Ihnen einen Pass gegeben hat. Das ist mein Gefängnis. Mein Schlüssel ist die einzige Möglichkeit, herein- oder herauszukommen, und ich riskiere da gar nichts. Der Orden toleriert keine Fehler.",,,"No me importa que Mourel te diera un pase. Ésta es mi prisión. Mi llave es la única forma de entrar o salir, y no voy a arriesgarme. La Orden no tolera los fallos.",,,"Je m'en fous que Mourel t'ai donné un passe. C'est ma prison. Ma clé est la seule façon d'entrer ou de sortir, et je ne prends pas de risques. L'Ordre ne tolère pas les erreurs.",,,"モーレルが許可しようが構わん。 + \cy아주 들떠있는 녀석이네.",De toorn van de Orde zal op deze bedienden neerdalen tot ze om de dood smeken.,Ordenens vrede vil regne over disse tjenerne til de trygler om å dø.,Gniew Zakonu spadnie jak deszcz na te sługi dopóki nie będą błagać o śmierć.,A ira da Ordem descerá a esses servos até eles implorarem pela morte.,,Furia Ordinului se va năpusti asupra servitorilor aceștia până vor cerși după moarte.,"Гнев Ордена обрушится на этих рабов, и они будут молить о смерти.",,Ordens vrede kommer att regna över dessa tjänare tills de ber om döden.,"Tarikat'ın gazabı, ölüm için yalvarana kadar bu hizmetkarların üzerine yağacak." +"I don't care if Mourel gave you a pass. This is my prison. My key is the only way in or out, and I'm not taking any chances. The Order does not tolerate mistakes.",TXT_DLG_SCRIPT05_D6064_IDONT,MAP05: Montag.,,,"Mě je jedno, že ti Mourel dal propustku. Tohle je moje vězení. Můj klíč je jediná cesta dovnitř a ven a já nehodlám nic riskovat. Řád netoleruje chyby.","Jeg er ligeglad med, om Mourel gav dig et fripas. Dette er mit fængsel. Min nøgle er den eneste vej ind eller ud, og jeg tager ingen chancer. Ordenen tolererer ikke fejltagelser.","Es ist mir egal ob Mourel Ihnen einen Pass gegeben hat. Das ist mein Gefängnis. Mein Schlüssel ist die einzige Möglichkeit, herein- oder herauszukommen, und ich riskiere da gar nichts. Der Orden toleriert keine Fehler.",,"Mi ne zorgas, ke Mourel donis enirpermeson al vi. Ĉi tiu estas mia malliberejo; mia ŝlosilo estas la ununura maniero eniri aŭ eliri, kaj mi ne riskos min. La Ordeno toleras nenian eraron.","No me importa que Mourel te haya dado un pase. Esta es mi prisión; mi llave es la única forma de entrar o salir, y no me arriesgaré. La Orden no tolera los fallos.","No me importa que Mourel te haya dado un pase. Esta es mi prisión; mi llave es la única forma de entrar o salir, y no me voy a arriesgar. La Orden no tolera los fallos.","En välitä mistään Mourelin luvista. Tämä on minun vankilani. Vain minun avaimellani pääsee sisään tai ulos, enkä aio ottaa yhtäkään riskiä. Veljeskunta ei suvaitse virheitä.","Je m'en fous que Mourel t'ai donné un passe. C'est ma prison. Ma clé est la seule façon d'entrer ou de sortir, et je ne prends pas de risques. L'Ordre ne tolère pas les erreurs.","Az sem érdekel ha Mourel adta a belépőt. Ez az Én börtönöm. Az Én kulcsom az egyetlen ami ki és bejutást enged, nem kockáztatok. A Rend nem igazán tolerálja a hibákat.","Non mi interessa se Mourel ti ha fatto entrare qua. Questa è la mia prigione. La mia chiave è l'unico modo per entrare o per uscire, e non ho intenzione di lasciare nulla al caso. L'Ordine non tollera errori.","モーレルが許可しようが構わん。 ここは私の刑務所だ。この鍵でしか絶対出入りは 出来ないし、渡すつもりも無い。 オーダーは失敗を許さないからな。 -",모렐 녀석이 너에게 통행증을 줬다 해도 신경 안 써. 이곳은 이 몸이 통치하는 감옥이다! 내가 가지고 있는 열쇠만 있으면 죄인들의 자유를 맘껏 조종할 수 있지. 오더는 절대로 실수 같은걸 용납하지 않아!,Het kan me niet schelen of Mourel je een pasje heeft gegeven. Dit is mijn gevangenis. Mijn sleutel is de enige weg naar binnen of buiten en ik neem geen enkel risico. De Orde tolereert geen fouten.,"Nie obchodzi mnie to, że Mourel dał ci przepustkę. To moje więzienie. Tylko mój klucz pozwala wejść lub wyjść, i nie mam zamiaru ryzykować. Zakon nie toleruje błędów.",Eu não estou nem aí se o Mourel te deu um passe. Esta é a minha prisão. A única forma de entrar ou sair é com a minha chave e eu não estou a fim de arriscar. A Ordem não tolera erros.,,,"Мне плевать, дал ли тебе Морел пропуск или нет. Это моя тюрьма, и без моего ключа не войти и не выйти. И я не хочу рисковать — Орден не прощает ошибок!", -Give me the damn key!,TXT_RPLY0_SCRIPT05_D6064_GIVEM,,,,Dej mi ten zatracený klíč!,Geben Sie mir den verdammten Schlüssel!,,,¡Dame la maldita llave!,,,Donne moi cette putain de clé!,,,いいからとっととキーを寄越せ!,그 망할 놈의 키를 건네!,Geef me die verdomde sleutel!,Daj mi ten cholerny klucz!,Me dê a droga da chave!,,,Дай мне чёртов ключ!, -Over my dead body!,TXT_DLG_SCRIPT05_D7580_OVERM,,,,Jen přes mou mrtvolu!,Nur über meine Leiche!,,,¡Sobre mi tumba!,,,Il faudra me passer sur le corps!,,,欲しけりゃ取りに来い。,"내 시체를 밟고 얻어라! - \cy아마 네가 “부탁”을 안 해서 이러나 봐.",Over mijn lijk!,Po moim trupie!,Só sobre o meu cadáver!,,,Только через мой труп!, -Great idea!,TXT_RPLY0_SCRIPT05_D7580_GREAT,,,,Skvělý nápad!,Gute Idee!,,,¡Buena idea!,,,Excellente idée!,,,良い案だ!,좋은 생각이야!,Geweldig idee!,Dobry pomysł!,Boa idéia!,,,Хорошая мысль!, -"Shackles or chains, I want you to hang around.",TXT_DLG_SCRIPT05_D9096_SHACK,,,,"Pouta či řetězy, chci tě tu vidět viset.",Fesseln oder Ketten - ich will dich hier herumhängen sehen.,,,"Grilletes o cadenas, te quiero ver colgado.",,,Chaînes ou menottes? J'ai vraiment envie de vous retenir!,,,鎖や手錠で、繋いだ方が良いな。,"동아줄, 아님 쇠사슬... 네 목에 잘 어울리겠네. 으하하하!","Sluitingen of kettingen, ik wil dat je blijft hangen.",Kajdany czy łańcuchy? Chcę byś na chwilę tu został.,Algemas ou correntes? Quero que você fique aqui por um tempo.,,,"Кандалы или цепи? Я хочу, чтобы ты подольше тут задержался.", -"I don't know how you managed to get past the guards and the Warden, but I hope you like the decor, because you just moved in.",TXT_DLG_SCRIPT05_D10612_IDONT,,,,"Nemám tušení, jak se ti podařilo dostat se přes stráže a dozorce, ale doufám že se ti líbí naše výzdoba, protože jsi se právě nastěhoval.","Ich habe keine Ahnung, wie du an den Wachen und dem Direktor vorbeigekommen bist, aber ich hoffe du magst das Dekor, denn du bist gerade eingezogen.",,,"No sé como has logrado pasar por los guardias y el Carcelero, pero espero que te guste la decoración, porque te acabas de mudar aquí.","No sé como has logrado pasar por los guardias y el Director, pero espero que te guste la decoración, porque te acabas de mudar aquí.",,"Je ne sais pas comment vous êtes passé à travers les gardes et le gardien, mais j'espère que vous aimez le décor car ceci sera votre nouveau domicile.",,,"どうやってガードやセキュリティを +",모렐 녀석이 너에게 통행증을 줬다 해도 신경 안 써. 이곳은 이 몸이 통치하는 감옥이다! 내가 가지고 있는 열쇠만 있으면 죄인들의 자유를 맘껏 조종할 수 있지. 오더는 절대로 실수 같은걸 용납하지 않아!,Het kan me niet schelen of Mourel je een pasje heeft gegeven. Dit is mijn gevangenis. Mijn sleutel is de enige weg naar binnen of buiten en ik neem geen enkel risico. De Orde tolereert geen fouten.,"Jeg blåser i om Mourel ga deg et passerseddel. Dette er mitt fengsel. Min nøkkel er den eneste veien inn eller ut, og jeg tar ingen sjanser. Ordenen tolererer ikke feil.","Nie obchodzi mnie to, że Mourel dał ci przepustkę. To moje więzienie. Tylko mój klucz pozwala wejść lub wyjść, i nie mam zamiaru ryzykować. Zakon nie toleruje błędów.",Eu não estou nem aí se o Mourel te deu um passe. Esta é a minha prisão. A única forma de entrar ou sair é com a minha chave e eu não estou a fim de arriscar. A Ordem não tolera erros.,,"Nu-mi pasă că Mourel ți-a dat o legitimație. Asta e închisoarea mea. Cheia mea e singura cale de intrare sau ieșire, și nu risc nimic. Ordinul nu tolerează greșeli.","Мне плевать, дал ли тебе Морел пропуск или нет. Это моя тюрьма, и без моего ключа не войти и не выйти. И я не хочу рисковать — Орден не прощает ошибок!",,"Jag bryr mig inte om Mourel gav dig ett passerkort. Det här är mitt fängelse. Min nyckel är den enda vägen in eller ut, och jag tar inga risker. Orden tolererar inga misstag.",Mourel'in sana izin vermesi umurumda değil. Burası benim hapishanem. İçeri girip çıkmanın tek yolu benim anahtarım ve işimi şansa bırakmayacağım. Tarikatın hataya tahammülü yoktur. +Give me the damn key!,TXT_RPLY0_SCRIPT05_D6064_GIVEM,〃,,,Dej mi ten zatracený klíč!,Giv mig den forbandede nøgle!,Geben Sie mir den verdammten Schlüssel!,,Donu la fekan ŝlosilon!,¡Dame la maldita llave!,,Anna minulle se pahuksen avain!,Donne moi cette putain de clé!,Add ide az istenverte kulcsot!,Dammi quella dannata chiave!,いいからとっととキーを寄越せ!,그 망할 놈의 키를 건네!,Geef me die verdomde sleutel!,Gi meg den jævla nøkkelen!,Daj mi ten cholerny klucz!,Me dê a droga da chave!,,Dă-mi afurisita de cheie!,Дай мне чёртов ключ!,,Ge mig den förbannade nyckeln!,Ver şu lanet anahtarı bana! +Over my dead body!,TXT_DLG_SCRIPT05_D7580_OVERM,〃,,,Jen přes mou mrtvolu!,Over mit lig!,Nur über meine Leiche!,,Nur post mia morto!,¡Primero muerto!,,Vain kuolleen ruumiini yli!,Il faudra me passer sur le corps!,Csak a holttestemen át!,Sul mio cadavere!,欲しけりゃ取りに来い。,"내 시체를 밟고 얻어라! + \cy아마 네가 “부탁”을 안 해서 이러나 봐.",Over mijn lijk!,Over mitt lik!,Po moim trupie!,Só sobre o meu cadáver!,,Doar peste cadavrul meu!,Только через мой труп!,,Över min döda kropp!,Cesedimi çiğneyin! +Great idea!,TXT_RPLY0_SCRIPT05_D7580_GREAT,〃,,,Skvělý nápad!,God idé!,Gute Idee!,,Bonega ideo!,¡Qué buena idea!,,Loistoidea!,Excellente idée!,Kiváló ötlet!,Ottima idea!,良い案だ!,좋은 생각이야!,Geweldig idee!,God idé!,Dobry pomysł!,Boa idéia!,,Grozavă idee!,Хорошая мысль!,,Bra idé!,Harika bir fikir! +"Shackles or chains, I want you to hang around.",TXT_DLG_SCRIPT05_D9096_SHACK,〃,,,"Pouta či řetězy, chci tě tu vidět viset.","Lænker eller kæder, jeg vil have dig til at blive hængende.",Fesseln oder Ketten - ich will dich hier herumhängen sehen.,,"Ĉu vi volas katenojn aŭ ŝeklojn? Mi volas, ke vi ĝuu vian restadon.",¿Grilletes o cadenas? Quiero que disfrutes de tu estancia.,,"Olipa sitten kahleissa tai ketjuissa, haluan sinun jäävän pysyäksesi.",Chaînes ou menottes? J'ai vraiment envie de vous retenir!,"Mindegy hogy béklyó vagy lánc, csak lógj itt szépen.","Ferri o catene, potrai starci benissimo qua!",鎖や手錠で、繋いだ方が良いな。,"동아줄, 아님 쇠사슬... 네 목에 잘 어울리겠네. 으하하하!","Sluitingen of kettingen, ik wil dat je blijft hangen.","Lenker eller lenker, jeg vil at du skal bli her.",Kajdany czy łańcuchy? Chcę byś na chwilę tu został.,Algemas ou correntes? Quero que você fique aqui por um tempo.,,"Cătușe sau lanțuri, vreau să rămăi pe-aici.","Кандалы или цепи? Я хочу, чтобы ты подольше тут задержался.",,"Fängsel eller kedjor, jag vill att du stannar kvar.","Kelepçe ya da zincir, buralarda olmanı istiyorum." +"I don't know how you managed to get past the guards and the Warden, but I hope you like the decor, because you just moved in.",TXT_DLG_SCRIPT05_D10612_IDONT,MAP05: Wolenick.,,,"Nemám tušení, jak se ti podařilo dostat se přes stráže a dozorce, ale doufám že se ti líbí naše výzdoba, protože jsi se právě nastěhoval.","Jeg ved ikke, hvordan det lykkedes dig at komme forbi vagterne og direktøren, men jeg håber, du kan lide indretningen, for du er lige flyttet ind.","Ich habe keine Ahnung, wie du an den Wachen und dem Direktor vorbeigekommen bist, aber ich hoffe du magst das Dekor, denn du bist gerade eingezogen.",,"Mi ne komprenas, kiel vi superis la gardistojn kaj la provoson, sed mi esperas, ke vi ŝatas la dekoracion, ĉar vi ĵus transloĝiĝis.","No sé cómo habrás pasado por los guardias y el carcelero, pero espero que te guste la decoración, porque te acabas de mudar aquí.",,"En tiedä, miten onnistuit pääsemään vartijoiden ja vankilanjohtajan läpi, mutta toivon, että pidät sisustuksesta; olethan sentään tänne juuri muuttanut.","Je ne sais pas comment vous êtes passé à travers les gardes et le gardien, mais j'espère que vous aimez le décor car ceci sera votre nouveau domicile.","Nem tudom, hogyan jutottál át az őrökön és az igazgatón, de remélem szimpatikus a hely, mert még sokáig leszel itt.","Non so come tu abbia fatto a superare il direttore o le guardie, ma spero che tu apprezzi l'ambiente, perché adesso questa sarà anche la tua prigione.","どうやってガードやセキュリティを 抜けてきたかは知らんが、私の部署に移れば、 -この素晴らしい装飾を堪能できるぞ。","그 많은 경비와 간수장을 어떻게 해서 격파한 건지는 모르겠다만, 빠른 재판을 추천하겠네. 왜냐하면 자네는 헛수고했으니까.","Ik weet niet hoe je langs de bewakers en de directeur bent gekomen, maar ik hoop dat je het decor leuk vindt, want je bent er net ingetrokken.","Nie wiem jak ominąłeś strażników i Naczelnika, ale mam nadzieję, że podoba ci się wystrój, bo właśnie tu zostaniesz.","Eu não sei como você conseguiu passar pelos guardas e pelo Carcereiro, mas espero que goste da decoração, porque você acabou de se mudar pra cá.",,,"Не знаю, как тебе удалось миновать стражу и Монтага. Но, я надеюсь, тебе нравится интерьер? Потому что отсюда ты уже не выйдешь.", -Free my comrades or die!,TXT_RPLY0_SCRIPT05_D10612_FREEM,,,,"Osvoboď mé druhy, nebo zemři!",Befreien Sie meine Kameraden oder sterben Sie!,,,¡Libera a mis camaradas o muere!,,,Libère mes camarades ou meurs!,,,命が惜しければ仲間を解放しろ!,"내 전우를 풀어주든지, 죽든지!",Bevrijd mijn kameraden of sterf!,Uwolnij moich towarzyszy lub giń!,Liberte meus companheiros ou morra!,,,"Освободи моих товарищей, или ты умрёшь!", -Kill me and you'll never set anyone free. I possess the only pattern key that will unlock the cells.,TXT_DLG_SCRIPT05_D12128_KILLM,,,,"Zab mě a neosvobodíš nikoho. Jenom já mám vzor, který otevře cely.","Töte mich und du befreist niemanden. Ich bin der einzige, der autorisiert ist, die Gefangenen freizulassen.",,,Mátame y nunca liberarás a nadie. Poseo la única huella digital que abre las celdas.,,,Tuez moi et personne ne sera libéré. Je suis le seul qui possède la clé qui peut ouvrir les cellules.,,,"私を殺せば誰も助かる事はない。 -私の指紋だけが檻を開けられるからな。",날 죽이면 일이 더 최악으로 변질될 것일세. 나에게 감옥 문을 열 수 있는 유일한 지문이 있으니 말이지.,Dood me en je zult nooit iemand vrijlaten. Ik bezit de enige patroonsleutel die de cellen zal ontsluiten.,"Zabij mnie, a już nigdy nikogo nie uwolnisz. Tylko ja mam klucz do ich cel.",Mate-me e você nunca libertará ninguém. Eu possuo a única chave que destranca as celas.,,,"Убив меня, ты никого не освободишь. Только у меня есть ключ, которым можно открыть камеры.", -Can you lend me a hand then?,TXT_RPLY0_SCRIPT05_D12128_CANYO,,,,Mohl bys mi tedy půjčit ruku?,Können Sie mir Ihre Hand leihen?,,,¿Me puedes echar una mano entonces?,,,"Tu peux me prêter main forte, alors?",,,じゃあ 手を貸して くれるか?,그럼 네 손길이 좀 필요할 것 같아...,Kun je me dan een handje helpen?,Więc może podasz mi pomocną dłoń?,Pode me dar uma mão então?,,,"Может быть, ты дашь мне руку помощи?", -Move along or join your friends.,TXT_DLG_SCRIPT05_D13644_MOVEA,,,,"Jdi, nebo se přidej ke svým kamarádům.",Hau ab oder zieh bei deinen Freunden ein.,,,Muévete o únete a tus amigos.,,,Bougez ou rejoignez vos amis.,,,共に行こう友よ。,"무죄, 아니면 사형 선고. 정하시게.",Ga mee of sluit je aan bij je vrienden.,Idź stąd lub dołączysz do swoich przyjaciół.,Suma daqui ou junte-se aos seus amigos.,,,"Не подходи ко мне, или присоединишься к своим друзьям.", -"Don't just stand there, get us out of here!",TXT_DLG_SCRIPT05_D15160_DONTJ,,,,"Nestůj tam tak, dostaň nás odsud!","Steh da nicht so rum, hol uns raus!",,,"No te quedes ahí, ¡sácanos de aquí!",,,"Ne vous tenez pas là, sortez nous d'ici!",,,もう待てない、早くここを出よう!,"거기 서 있지 말고, 어서 우릴 내보내 줘!","Blijf daar niet staan, haal ons hier weg!","Nie stój tak, uwolnij nas stąd!",Não fique parado aí. Nos tire daqui!,,,Не стой просто так — вытащи нас отсюда!, -"The sky, I want to see the sky.",TXT_DLG_SCRIPT05_D16676_THESK,,,,"Nebe, chci vidět nebe.","Der Himmel, ich möchte den Himmel sehen.",,,"El cielo, quiero ver el cielo.",,,"Le ciel, je veux voir le ciel!",,,空を、空を見たい。,"하늘, 하늘을 보고 싶어.","De lucht, ik wil de lucht zien.",Niebo... tak bardzo chcę zobaczyć niebo.,O céu. Eu quero ver o céu.,,,Небо. Я хочу увидеть небо., -"Five feet by four feet, five feet by four feet, five feet by four feet.",TXT_DLG_SCRIPT05_D18192_FIVEF,,,,"Pět kroků, čtyři kroky, pět kroků, čtyři kroky, pět kroků, čtyři kroky.","Fünf Fuß mal vier Fuß, fünf Fuß mal vier Fuß, fünf Fuß mal vier Fuß...",,,"Cinco pies por cuatro pies, cinco pies por cuatro pies, cinco pies por cuatro pies.",,,Un mètre cinquante par un mètre trente. Un mètre cinquante par un mètre trente. Un mètre cinquante par un mètre trente.,,,"ファイブフィート バイ フォーフィート、 +この素晴らしい装飾を堪能できるぞ。","그 많은 경비와 간수장을 어떻게 해서 격파한 건지는 모르겠다만, 빠른 재판을 추천하겠네. 왜냐하면 자네는 헛수고했으니까.","Ik weet niet hoe je langs de bewakers en de directeur bent gekomen, maar ik hoop dat je het decor leuk vindt, want je bent er net ingetrokken.","Jeg vet ikke hvordan du kom deg forbi vaktene og direktøren, men jeg håper du liker innredningen, for du har nettopp flyttet inn.","Nie wiem jak ominąłeś strażników i Naczelnika, ale mam nadzieję, że podoba ci się wystrój, bo właśnie tu zostaniesz.","Eu não sei como você conseguiu passar pelos guardas e pelo Carcereiro, mas espero que goste da decoração, porque você acabou de se mudar pra cá.",,"Nu știu cum ai reușit să treci de gardieni și de Director, dar sper că îți place noul decor, pentru că tocmai te-ai mutat aici.","Не знаю, как тебе удалось миновать стражу и Монтага, но, я надеюсь, тебе нравится интерьер? Потому что отсюда ты уже не выйдешь.",,"Jag vet inte hur du lyckades ta dig förbi vakterna och fängelsedirektören, men jag hoppas att du gillar inredningen, för du har just flyttat in.",Muhafızları ve Müdür'ü nasıl atlattın bilmiyorum ama umarım dekoru beğenmişsindir çünkü yeni taşındın. +Free my comrades or die!,TXT_RPLY0_SCRIPT05_D10612_FREEM,〃,,,"Osvoboď mé druhy, nebo zemři!",Befri mine kammerater eller dø!,Befreien Sie meine Kameraden oder sterben Sie!,,Liberigu miajn samideanojn aŭ mortu!,¡Libera a mis camaradas o muere!,¡Libera a mis compañeros o muere!,Vapauta toverini tai kuole!,Libère mes camarades ou meurs!,"Engedd el a társaimat, vagy meghalsz!",Libera i miei compagni o muori!,命が惜しければ仲間を解放しろ!,"내 전우를 풀어주든지, 죽든지!",Bevrijd mijn kameraden of sterf!,Befri kameratene mine eller dø!,Uwolnij moich towarzyszy lub giń!,Liberte meus companheiros ou morra!,,"Eliberează-mi camarazii, sau mori!","Освободи моих товарищей, или ты умрёшь!",,Befria mina kamrater eller dö!,Yoldaşlarımı serbest bırak ya da öl! +Kill me and you'll never set anyone free. I possess the only pattern key that will unlock the cells.,TXT_DLG_SCRIPT05_D12128_KILLM,〃,,,"Zab mě a neosvobodíš nikoho. Jenom já mám vzor, který otevře cely.","Dræb mig, og du vil aldrig sætte nogen fri. Jeg besidder den eneste mønsternøgle, der kan låse cellerne op.","Töte mich und du befreist niemanden. Ich bin der einzige, der autorisiert ist, die Gefangenen freizulassen.",,"Vi liberigos neniun se vi mortigos min: mi havas la ununuran manspuron, kiu ebligas malŝlosi la ĉelojn.",Mátame y no liberarás a nadie: poseo la única huella digital que abre las celdas.,Mátame y no vas a liberar a nadie: poseo la única huella digital que abre las celdas.,Tappamalla minut et vapauta ketään. Vain minun käsissäni ovat avaimet sellien avaamiseen.,Tuez moi et personne ne sera libéré. Je suis le seul qui possède la clé qui peut ouvrir les cellules.,"Ha megölsz, akkor senkit sem fogsz tudni kiszabadítani. Az egyetlen biztonsági kulcs az Én tulajdonomban van.",Uccidi e non libererai proprio nessuno. Posseggo l'unica chiave d'identificazione che può aprire le celle.,"私を殺せば誰も助かる事はない。 +私の指紋だけが檻を開けられるからな。",날 죽이면 일이 더 최악으로 변질될 것일세. 나에게 감옥 문을 열 수 있는 유일한 지문이 있으니 말이지.,Dood me en je zult nooit iemand vrijlaten. Ik bezit de enige patroonsleutel die de cellen zal ontsluiten.,"Dreper du meg, får du aldri satt noen fri. Jeg har den eneste mønsternøkkelen som låser opp cellene.","Zabij mnie, a już nigdy nikogo nie uwolnisz. Tylko ja mam klucz do ich cel.",Mate-me e você nunca libertará ninguém. Eu possuo a única chave que destranca as celas.,,Omoară-mă și nu vei elibera pe nimeni în veci. Eu posed singura cheie care poate deschide celulele.,"Убив меня, ты никого не освободишь. Только у меня есть ключ, которым можно открыть камеры.",,Om du dödar mig kommer du aldrig att befria någon. Jag besitter den enda mönsternyckeln som kan låsa upp cellerna.,Beni öldürürsen kimseyi özgür bırakamazsın. Hücrelerin kilidini açacak tek desen anahtarı bende. +Can you lend me a hand then?,TXT_RPLY0_SCRIPT05_D12128_CANYO,〃,,,Mohl bys mi tedy půjčit ruku?,Kan du så give mig en hånd med?,Können Sie mir Ihre Hand leihen?,,Tiuokaze mi «enmanigos» ilin al vi.,"¿Me echas una mano, entonces?","¿Me das una mano, entonces?",Voisitko sitten ojentaa auttavaa kättäsi?,"Tu peux me prêter main forte, alors?",Tudsz nekem segíteni?,"Che ne dici di darmi una mano, allora?",じゃあ 手を貸して くれるか?,그럼 네 손길이 좀 필요할 것 같아...,Kun je me dan een handje helpen?,"Kan du hjelpe meg, da?",Więc może podasz mi pomocną dłoń?,Pode me dar uma mão então?,,Poți da o mână de ajutor atunci?,"Может быть, ты протянешь мне руку помощи?",,Kan du ge mig en hand med det då?,O zaman bana yardım edebilir misin? +Move along or join your friends.,TXT_DLG_SCRIPT05_D13644_MOVEA,〃,,,"Jdi, nebo se přidej ke svým kamarádům.",Gå videre eller slut dig til dine venner.,Hau ab oder zieh bei deinen Freunden ein.,,Foriru aŭ alliĝu al viaj amikoj.,Vete o únete a tus amigos.,,"Jatka eteenpäin, tai liity ystäviesi joukkoon.",Bougez ou rejoignez vos amis.,"Mozogj tovább, vagy csatlakozz a barátaidhoz.","Togliti dai piedi, o ti unirai ai tuoi amici.",共に行こう友よ。,"무죄, 아니면 사형 선고. 정하시게.",Ga mee of sluit je aan bij je vrienden.,Gå videre eller bli med vennene dine.,Idź stąd lub dołączysz do swoich przyjaciół.,Suma daqui ou junte-se aos seus amigos.,,Cară-te sau te vei alătura prietenilor tăi.,"Не подходи ко мне, или присоединишься к своим друзьям.",,Gå vidare eller gå till dina vänner.,İlerleyin ya da arkadaşlarınıza katılın. +"Don't just stand there, get us out of here!",TXT_DLG_SCRIPT05_D15160_DONTJ,MAP05: Prisoner.,,,"Nestůj tam tak, dostaň nás odsud!","Stå ikke bare der, få os ud herfra!","Steh da nicht so rum, hol uns raus!",,"Ne staru tie, liberigu nin!","No te quedes ahí, ¡sácanos de aquí!",,Älä vain siinä seisoskele; päästä meidät ulos täältä!,"Ne vous tenez pas là, sortez nous d'ici!","Ne csak bámészkodj, szabadíts ki minket!","Non stare lì fermo, facci uscire da qui!",もう待てない、早くここを出よう!,"거기 서 있지 말고, 어서 우릴 내보내 줘!","Blijf daar niet staan, haal ons hier weg!","Ikke bare stå der, få oss ut herfra!","Nie stój tak, uwolnij nas stąd!",Não fique parado aí. Nos tire daqui!,,"Nu sta acolo, scoate-ne de aici!",Не стой просто так. Вытащи нас отсюда!,,"Stå inte bara där, ta oss härifrån!","Orada öylece durmayın, bizi buradan çıkarın!" +"The sky, I want to see the sky.",TXT_DLG_SCRIPT05_D16676_THESK,〃,,,"Nebe, chci vidět nebe.","Himlen, jeg vil se himlen.","Der Himmel, ich möchte den Himmel sehen.",,"La ĉielon, mi volas vidi la ĉielon.","El cielo, quiero ver el cielo.",,"Taivas, haluan nähdä taivaan.","Le ciel, je veux voir le ciel!","Az eget, szeretném újra látni az eget.","Il cielo, voglio vedere il cielo.",空を、空を見たい。,"하늘, 하늘을 보고 싶어.","De lucht, ik wil de lucht zien.","Himmelen, jeg vil se himmelen.",Niebo... tak bardzo chcę zobaczyć niebo.,O céu. Eu quero ver o céu.,,"Cerul, vreau să văd cerul!",Небо. Я хочу увидеть небо.,,"Himlen, jag vill se himlen.","Gökyüzü, gökyüzünü görmek istiyorum." +"Five feet by four feet, five feet by four feet, five feet by four feet.",TXT_DLG_SCRIPT05_D18192_FIVEF,〃,,,"Pět kroků, čtyři kroky, pět kroků, čtyři kroky, pět kroků, čtyři kroky.","Fem fod gange fire fod, fem fod gange fire fod, fem fod gange fire fod...","Fünf Fuß mal vier Fuß, fünf Fuß mal vier Fuß, fünf Fuß mal vier Fuß...",,"1,2 oble 1,5 metroj. +1,2 oble 1,5 metroj. +1,2 oble 1,5 metroj...","Un metro y medio por un metro veinte. +Un metro y medio por un metro veinte. +Un metro y medio por un metro veinte...",,"Viisi kertaa neljä jalkaa, viisi kertaa neljä jalkaa, viisi kertaa neljä jalkaa.",Un mètre cinquante par un mètre trente. Un mètre cinquante par un mètre trente. Un mètre cinquante par un mètre trente.,"Öt lábszor négy láb, öt lábszor négy láb, öt lábszor négy láb.",Un metro e cinquanta per un metro e trenta. Un metro e cinquanta per un metro e trenta. Un metro e cinquanta per un metro e trenta.,"ファイブフィート バイ フォーフィート、 ファイブフィート バイ フォーフィート、 -ファイブフィート バイ フォーフィート。",나가려면 나갈 생각을 하고 나갈 준비를 해야 되는데 나갈 수가 없어 왜냐하면 나가는 걸 막는 놈들이...,"Vijf voet bij vier voet, vijf voet bij vier voet, vijf voet bij vier voet, vijf voet bij vier voet.","Pięć stóp na cztery, pięć stóp na cztery, pięć stóp na cztery.",Um metro e meio por um metro e vinte. Um metro e meio por um metro e vinte. Um metro e meio por um metro e vinte. ,,,Пять шагов на четыре шага. Пять шагов на четыре шага. Пять шагов на четыре шага., -Don't release me if the Order's still in charge. I can't stand the terror.,TXT_DLG_SCRIPT05_D19708_DONTR,,,,"Nevysvobozuj mě, jestli ještě vládne Řád. Tu hrůzu nemůžu snést.","Bitte befreie mich nicht, wenn der Orden hier noch herrscht, ich halte den Horror nicht aus.",,,No me dejes ir si la Orden sigue al mando. No puedo soportar el terror.,,,Laissez moi ici si l'Ordre est toujours au pouvoir. Je ne veux pas voir cette horreur.,,,"まだオーダーがいる内は出たくない。 -恐怖に打ち拉がれそうだ。",오더 놈들이 아직도 설치고 있다면 절 내보내지 마세요. 죽을까 봐 두려워요...,Laat me niet los als de Orde nog steeds de leiding heeft. Ik kan niet tegen de terreur.,Nie uwalniaj mnie jeśli Zakon jest wciąż u władzy. Nie mogę znieść tego terroru.,Não me solte se a Ordem ainda estiver no comando. Eu não suporto o horror.,,,"Не освобождай меня, если Орден всё ещё у власти. Я не вынесу преследования.", -"I don't want to bitch, but it's about time Macil sent someone to get us out.",TXT_DLG_SCRIPT05_D21224_IDONT,,,,"Nechci nadávat, ale už bylo na čase, aby Macil někoho poslal nás vysvobodit.","Ich möchte ja nicht meckern, aber es wurde auch Zeit, dass Macil jemanden schickt, der uns hier rausholt",,,"No quiero quejarme, pero ya era hora de que Macil enviara a alguien a sacarnos.",,,"J'ai pas envie de me plaindre, mais Macil a vraiment pris son temps pour envoyer quelqu'un nous sortir d'ici!",,,"意地が悪いな、だがマシルが解放の為に -誰か送ったのは大体わかる。","투정부리기는 싫지만, 드디어 사령관님이 구출작전을 실시한 것 같군요.","Ik wil niet zeuren, maar het wordt tijd dat Macil iemand stuurt om ons eruit te krijgen.","Nie chcę psioczyć, ale najwyższa pora, aby Macil wysłał kogoś, by nas uwolnić.","Não quero encher o saco, mas já era hora do Macil enviar alguém para nos tirar daqui.",,,"Не хочу ныть, но пора бы Мэйсилу уже послать кого-нибудь освободить нас.", -I'd give anything for just a crust of bread. I'm so hungry.,TXT_DLG_SCRIPT05_D22740_IDGIV,,,,Dal bych cokoliv jen za kůrku chleba. Mám takový hlad.,Ich gäbe alles für eine Brotkruste. Ich habe so einen Hunger.,,,Daría lo que fuera por una migaja de pan. Tengo tanta hambre.,,,Je donnerai n'importe quoi pour une bouchée de pain. J'ai tellement faim!,,,"いつもパンの耳ばかりだったんだ。 -すごく腹減った。",빵 한 조각이라도 먹고 싶습니다... 너무 배고파요...,Ik zou alles geven voor een korstje brood. Ik heb zo'n honger.,Oddałbym wszystko za kromkę chleba. Jestem taki głodny.,Eu daria qualquer coisa por uma migalha de pão. Estou tão faminto.,,,Я бы всё отдал просто за ломоть хлеба. Я так голоден., -"Ah, a surfacer in need of a favor. Down here you do a favor to get a favor and I need the town entrance that is our path to food opened. The Order has it sealed and guarded.",TXT_DLG_SCRIPT06_D0_AHASU,,,"Ah, a surfacer in need of a favour. Down here you do a favour to get a favour and I need the town entrance that is our path to food opened. The Order has it sealed and guarded.","Á, nadzemník, který potřebuje službu. Tady dole prokazuješ službu, abys dostal službu, a já potřebuju otevřít vchod do města, abychom měli cestu k jídlu. Řád ji nechal zapečetit a hlídat.","Oh, ein Oberflächler, der Hilfe braucht. Hier unten musst du uns einen Gefallen erweisen, bevor wir dir helfen können. Der Ausgang zur Stadt, der unser Zugang zu Nahrung ist, muss wieder freigemacht werden. Der Orden hat ihn verschlossen und lässt ihn bewachen.",,,"Ah, alguien de la superficie que necesita un favor. Aquí abajo se ofrece un favor a cambio de otro favor y necesito abierta la entrada al pueblo que es nuestro camino a la comida. La Orden lo tiene sellado y guardado.",,,"Ah, quelqu'un de la surface qui a besoin d'une faveur. Ici, on en fait une pour en avoir une, et j'ai besoin que l'entrée de la ville qui est notre chemin pour les vivres ouverte. L'Ordre l'a scellée et mise sous garde.",,,"あー、何か用があって上から来たんだな。 +ファイブフィート バイ フォーフィート。",나가려면 나갈 생각을 하고 나갈 준비를 해야 되는데 나갈 수가 없어 왜냐하면 나가는 걸 막는 놈들이...,"Vijf voet bij vier voet, vijf voet bij vier voet, vijf voet bij vier voet, vijf voet bij vier voet.","Fem fot ganger fire fot, fem fot ganger fire fot, fem fot ganger fire fot!","Pięć stóp na cztery, pięć stóp na cztery, pięć stóp na cztery.",Um metro e meio por um metro e vinte. Um metro e meio por um metro e vinte. Um metro e meio por um metro e vinte. ,,"Din 5 pași 4, din 5 pași 4, din 5 pași 4.","Пять футов на четыре, пять футов на четыре, пять футов на четыре.",,"Fem fot på fyra fot, fem fot på fyra fot, fem fot på fyra fot, fem fot på fyra fot.","Bir metreye bir metre, bir metreye bir metre, bir metreye bir metre." +Don't release me if the Order's still in charge. I can't stand the terror.,TXT_DLG_SCRIPT05_D19708_DONTR,〃,,,"Nevysvobozuj mě, jestli ještě vládne Řád. Tu hrůzu nemůžu snést.","Slip mig ikke fri, hvis Ordenen stadig har kommandoen. Jeg kan ikke klare terroren.","Bitte befreie mich nicht, wenn der Orden hier noch herrscht, ich halte den Horror nicht aus.",,Ne liberigu min se La Ordeno ankoraŭ regas: mi ne eltenas la teruron.,No me sueltes si La Orden sigue al mando: no soporto el terror.,,"Älä vapauta minua, jos Veljeskunta on vielä vallassa. En kestä enää sitä hirveyttä.",Laissez moi ici si l'Ordre est toujours au pouvoir. Je ne veux pas voir cette horreur.,Ne engedj ki míg a Rend hatalmon van. Nem bírom ezt az elnyomást.,Non liberarmi se l'Ordine è ancora al potere. Non voglio vedere questo orrore.,"まだオーダーがいる内は出たくない。 +恐怖に打ち拉がれそうだ。",오더 놈들이 아직도 설치고 있다면 절 내보내지 마세요. 죽을까 봐 두려워요...,Laat me niet los als de Orde nog steeds de leiding heeft. Ik kan niet tegen de terreur.,Ikke slipp meg ut hvis Ordenen fortsatt har kommandoen. Jeg holder ikke ut terroren.,Nie uwalniaj mnie jeśli Zakon jest wciąż u władzy. Nie mogę znieść tego terroru.,Não me solte se a Ordem ainda estiver no comando. Eu não suporto o horror.,,Nu mă elibera dacă Ordinul incă e tot la putere.,"Не освобождай меня, если Орден всё ещё у власти. Я не вынесу устрашения.",,Släpp inte ut mig om Orden fortfarande har befälet. Jag står inte ut med skräcken.,Tarikat hâlâ yetkiliyse beni bırakmayın. Dehşete dayanamıyorum. +"I don't want to bitch, but it's about time Macil sent someone to get us out.",TXT_DLG_SCRIPT05_D21224_IDONT,〃,,,"Nechci nadávat, ale už bylo na čase, aby Macil někoho poslal nás vysvobodit.","Jeg vil ikke brokke mig, men det er på tide, at Macil sender nogen ud for at få os ud.","Ich möchte ja nicht meckern, aber es wurde auch Zeit, dass Macil jemanden schickt, der uns hier rausholt",,"Mi ne intencas plendi, sed Macil finfine venigis iun por liberigi nin.","No es por quejarme, pero ya era hora de que Macil enviara alguien a sacarnos.",,"En halua ruikuttaa, mutta jo oli aikakin, että Macil lähetti jonkun päästämään meidät pois.","J'ai pas envie de me plaindre, mais Macil a vraiment pris son temps pour envoyer quelqu'un nous sortir d'ici!","Nem akarnék picsogni, de már ideje volt hogy Macil küldött értünk valakit.","Non è che voglio lamentarmi, però era ora che Macil mandasse qualcuno a liberarci.","意地が悪いな、だがマシルが解放の為に +誰か送ったのは大体わかる。","투정부리기는 싫지만, 드디어 사령관님이 구출작전을 실시한 것 같군요.","Ik wil niet zeuren, maar het wordt tijd dat Macil iemand stuurt om ons eruit te krijgen.","Jeg vil ikke klage, men det er på tide at Macil sender noen for å få oss ut.","Nie chcę psioczyć, ale najwyższa pora, aby Macil wysłał kogoś, by nas uwolnić.","Não quero encher o saco, mas já era hora do Macil enviar alguém para nos tirar daqui.",,"Nu vreau să mă smiorcăi, dar era și timpul ca Macil să trimită pe cineva să ne scoată afară.","Не хочу ныть, но Мэйсил мог бы и пораньше послать кого-нибудь освободить нас.",,"Jag vill inte vara taskig, men det är på tiden att Macil skickar någon för att få ut oss.",Şikâyet etmek istemiyorum ama Macil'in bizi çıkarması için birini göndermesinin zamanı gelmişti. +I'd give anything for just a crust of bread. I'm so hungry.,TXT_DLG_SCRIPT05_D22740_IDGIV,〃,,,Dal bych cokoliv jen za kůrku chleba. Mám takový hlad.,Jeg ville give alt for bare en brødskorpe. Jeg er så sulten.,Ich gäbe alles für eine Brotkruste. Ich habe so einen Hunger.,,Mi interŝanĝus ion ajn kontraŭ panero. Mi malsategas.,Daría lo que fuera por una migaja de pan. Tengo tanta hambre.,Daría lo que fuera por una miga de pan. Tengo tanta hambre.,Antaisin mitä vain yhdestäkin leivän murenesta. Minulla on niin nälkä.,Je donnerai n'importe quoi pour une bouchée de pain. J'ai tellement faim!,"Bármit megadnék egy falat kenyérért, annyira nagyon éhes vagyok.",Darei qualsiasi cosa per una crosta di pane. Ho una grande fame.,"いつもパンの耳ばかりだったんだ。 +すごく腹減った。",빵 한 조각이라도 먹고 싶습니다... 너무 배고파요...,Ik zou alles geven voor een korstje brood. Ik heb zo'n honger.,Jeg ville gitt hva som helst for en brødskive. Jeg er så sulten.,Oddałbym wszystko za kromkę chleba. Jestem taki głodny.,Eu daria qualquer coisa por uma migalha de pão. Estou tão faminto.,,Aș da orice pentru o coajă de pâine. Sunt așa flămând.,Я бы всё отдал просто за ломоть хлеба. Я так голоден.,,Jag skulle ge vad som helst för bara en skorpa bröd. Jag är så hungrig.,Bir lokma ekmek için her şeyimi verirdim. Çok acıktım. +"Ah, a surfacer in need of a favor. Down here you do a favor to get a favor and I need the town entrance that is our path to food opened. The Order has it sealed and guarded.",TXT_DLG_SCRIPT06_D0_AHASU,MAP06: Weran.,,"Ah, a surfacer in need of a favour. Down here you do a favour to get a favour and I need the town entrance that is our path to food opened. The Order has it sealed and guarded.","Á, nadzemník, který potřebuje službu. Tady dole prokazuješ službu, abys dostal službu, a já potřebuju otevřít vchod do města, abychom měli cestu k jídlu. Řád ji nechal zapečetit a hlídat.","Ah, en overfladebeboer, der har brug for en tjeneste. Her nede gør man en tjeneste for at få en tjeneste, og jeg har brug for at få åbnet byens indgang, som er vores vej til mad. Ordenen har den forseglet og bevogtet.","Oh, ein Oberflächler, der Hilfe braucht. Hier unten musst du uns einen Gefallen erweisen, bevor wir dir helfen können. Der Ausgang zur Stadt, der unser Zugang zu Nahrung ist, muss wieder freigemacht werden. Der Orden hat ihn verschlossen und lässt ihn bewachen.",,"Ha, surfaco-loĝanto bezonas komplezon. Ĉi-malsupre oni faras servon por gajni reservon, kaj mi bezonas remalfermi la enirejon al la urbo, kiu estas nia fonto de manĝaĵoj: La Ordeno ĝin ŝlosis kaj gardas.","Ah, alguien de la superficie que necesita un favor. Aquí abajo se ofrece un favor a cambio de otro, y necesito abierta la entrada al pueblo que es nuestro camino a la comida: La Orden la tiene cerrada y con vigilancia.",,"Jaahas, maanpintalainen palveluksen tarpeessa. Täällä alhaalla on tapana tehdä palvelus palveluksesta, ja minä haluan, että kaupungin sisäänkäynti, tiemme ruuan pariin, avataan. Se on salvattu ja vartioitu Veljeskunnan toimesta.","Ah, quelqu'un de la surface qui a besoin d'une faveur. Ici, on en fait une pour en avoir une, et j'ai besoin que l'entrée de la ville qui est notre chemin pour les vivres ouverte. L'Ordre l'a scellée et mise sous garde.","Nahát, egy felszínlakó aki szívességet kér. Itt az a szokás, hogy egy szívességért cserébe szívesség dukál. Ahhoz, hogy elérhetővé válljon mindenki számára a élelem, kell egy biztonságos belépő a városba. A Rend nagy biztonságban őrzi.","Ah, un abitante della superficie che ha bisogno di un favore. Quaggiù tu fai un favore per ottenere un favore, e io ho bisogno che l'ingresso alla città venga aperto visto che è il nostro accesso al cibo. L'Ordine l'ha chiuso e lo sorveglia.","あー、何か用があって上から来たんだな。 だがここでは物々交換が常識だ、 オーダーが町の出口を封鎖しやがったから -メシが手に入り辛くなったんだ。","아아... 도움이 필요한 지상인이구려. 도움을 받고 싶으면, 우리에게 도움이 되어야 할 것이야. 식량을 구할 수 있는 마을로 향하는 입구가 오더에 의해 막혔거단.","Ah, een verharder die een gunst nodig heeft. Hier beneden doe je een gunst om een gunst te krijgen en ik heb de stadstoegang nodig die onze weg naar eten is geopend. De Orde heeft het verzegeld en bewaakt.","Ah, powierzchniowiec potrzebujący pomocy. Tutaj na dole robi się to tak: przysługa za przysługę, a ja potrzebuję otworzyć wyjście do miasta, które jest naszą jedyną drogą by zdobyć jedzenie. Zakon je zablokował i pilnie go strzeże.","Ah, um cara da superfície precisando de um favor. Aqui embaixo você faz um favor para conseguir um favor e eu preciso da entrada da cidade aberta para pegar a nossa comida. A Ordem mantém ela fechada e guardada.",,,"А-а, гостю с поверхности нужно одолжение. Здесь, внизу, ты должен что-то сделать, прежде чем о чём-то попросить, и мне нужно, чтобы дверь в город, наш путь к пище, была открыта. Орден закрыл её и поставил охрану.", -Where is the gate mechanism?,TXT_RPLY0_SCRIPT06_D0_WHERE,,,,Kde je mechanismus brány?,Wo ist der Tormechanismus?,,,¿Dónde está el mecanismo de la puerta?,,,Où se trouve le mécanisme d'ouverture de la porte?,,,ゲートメカニズムは何処だ?,성문 관리 장치는 어딨지?,Waar is het poortmechanisme?,Gdzie jest mechanizm sterujący bramą?,Onde fica o mecanismo do portão?,,,Где механизм управления воротами?, -"Do my favor first, or you'll get squat from me.",TXT_DLG_SCRIPT06_D1516_DOMYF,,,"Do my favour first, or you'll get squat from me.","Prokaž mi službu, nebo ode mne nedostaneš nic.",Tu erst mir einen Gefallen oder ich sage gar nichts.,,,"Cumple mi favor primero, o no tendrás nada de mi.",,,Faites moi une faveur ou vous n'aurez rien.,,,俺の言った問題が先だ、でないと手助けできねえ。,"나를 도와주려, 아니면 너를 도륙할 거랴! - \cy다들 참 궁색하게 사네.","Doe me eerst een plezier, of je krijgt een hurkzitje van mij.",Zrób najpierw to o co cię prosiłem lub figę dostaniesz.,"Faça o meu favor primeiro, ou você não recebe coisa nenhuma de mim.",,,"Сначала выполни мою просьбу, или ты ничего не получишь.", -How will you know it's open?,TXT_RPLY0_SCRIPT06_D1516_HOWWI,,,,"Jak budeš vědět, že je otevřená?","Wodurch wirst du wissen, ob er offen ist?",,,¿Cómo sabrás si está abierto?,,,Comment est-ce que je saurais qu'elle est ouverte?,,,開放を知らせるには?,어떻게 도와주면 방법을 알 수 있지?,Hoe weet je dat het open is?,"Skąd będziesz wiedział, że jest już otwarta?",Como você vai saber que ela está aberta?,,,"Как ты узнаешь, что дверь открыта?", -Bring me back the guard's uniform. That way one of my ratfellows can wear it and no one will try to shut the door again.,TXT_DLG_SCRIPT06_D3032_BRING,,,,"Přines mi uniformu stráže, pak ji jeden z mých krysaříků může nosit a nikdo se už nepokusí ty dveře zavřít.","Bring mir die Uniform des Wächters. So kann einer meiner Rattenkumpel sie tragen und niemand wird wieder versuchen, die Tür zu schließen.",,,Tráeme el uniforme del guardia. Así uno de mis rateros lo llevará y nadie intentará cerrar la puerta de nuevo.,,,"Ramenez moi l'uniforme du garde. Comme ça, un de mes amis rats pourra le porter et personne n'essaiera de fermer cette porte.",,,"ガードの制服を持ってくればいい。 +メシが手に入り辛くなったんだ。","아아... 도움이 필요한 지상인이구려. 도움을 받고 싶으면, 우리에게 도움이 되어야 할 것이야. 식량을 구할 수 있는 마을로 향하는 입구가 오더에 의해 막혔거단.","Ah, een verharder die een gunst nodig heeft. Hier beneden doe je een gunst om een gunst te krijgen en ik heb de stadstoegang nodig die onze weg naar eten is geopend. De Orde heeft het verzegeld en bewaakt.","Ah, en overflateboer som trenger en tjeneste. Her nede gjør man en tjeneste for å få en tjeneste, og jeg må få åpnet inngangen til byen som er vår vei til mat. Ordenen har den forseglet og bevoktet.","Ah, powierzchniowiec potrzebujący pomocy. Tutaj na dole robi się to tak: przysługa za przysługę, a ja potrzebuję otworzyć wyjście do miasta, które jest naszą jedyną drogą by zdobyć jedzenie. Zakon je zablokował i pilnie go strzeże.","Ah, um cara da superfície precisando de um favor. Aqui embaixo você faz um favor para conseguir um favor e eu preciso da entrada da cidade aberta para pegar a nossa comida. A Ordem mantém ela fechada e guardada.",,"Ah, un locuitor de la suprafață care are nevoie de o favoare. Aici jos faci o favoare, primești o favoare, iar eu am nevoie de o cale pentru a ajunge la intrarea din oraș, să putem avea acces la provizii. Ordinul a închis-o și acum e bine păzită.","А-а, гостю с поверхности нужно одолжение. Здесь, внизу, ты должен что-то сделать, прежде чем о чём-то попросить, и мне нужно, чтобы дверь в город, наш путь к пище, была открыта. Орден закрыл её и поставил охрану.",,"Ah, en ytmänniska i behov av en tjänst. Här nere gör man en tjänst för att få en tjänst och jag behöver öppna stadens ingång som är vår väg till mat. Orden har förseglat och bevakat den.",İyiliğe ihtiyacı olan bir yüzey araştırmacısı. Burada bir iyilik için bir iyilik yaparsın ve ben de yiyecek yolumuz olan kasaba girişinin açılmasını istiyorum. Tarikat orayı mühürledi ve koruyor. +Where is the gate mechanism?,TXT_RPLY0_SCRIPT06_D0_WHERE,〃,,,Kde je mechanismus brány?,Hvor er portmekanismen?,Wo ist der Tormechanismus?,,Kie estas la mekanismo de la pordo de la kastelo?,¿Dónde está el mecanismo de la puerta?,,Missä on portin koneisto?,Où se trouve le mécanisme d'ouverture de la porte?,Hol van a kapu szerkezet?,Dov'è il meccanismo per il cancello?,ゲートメカニズムは何処だ?,성문 관리 장치는 어딨지?,Waar is het poortmechanisme?,Hvor er portmekanismen?,Gdzie jest mechanizm sterujący bramą?,Onde fica o mecanismo do portão?,,Unde e mecanismul de acționare al porții?,Где механизм управления воротами?,,Var är grindmekanismen?,Kapı mekanizması nerede? +"Do my favor first, or you'll get squat from me.",TXT_DLG_SCRIPT06_D1516_DOMYF,〃,,"Do my favour first, or you'll get squat from me.","Prokaž mi službu, nebo ode mne nedostaneš nic.","Gør mig en tjeneste først, ellers får du ikke en skid af mig.",Tu erst mir einen Gefallen oder ich sage gar nichts.,,Vi unue faru mian komplezon se vi volas ricevi ion de mi.,Cumple mi favor primero o no tendrás nada de mí.,Cumple mi favor primero o no vas a tener nada de mí.,"Tee minun palveluspyyntöni ensin, tai et saa minulta mitään.",Faites moi une faveur ou vous n'aurez rien.,"Jobban jársz ha az én szívességemet teljesíted, mert különben lópikulát se kapsz.","Fai il mio favore prima, o da me non otterrai nulla.",俺の言った問題が先だ、でないと手助けできねえ。,"나를 도와주려, 아니면 너를 도륙할 거랴! + \cy다들 참 궁색하게 사네.","Doe me eerst een plezier, of je krijgt een hurkzitje van mij.","Gjør meg en tjeneste først, ellers får du ikke en dritt av meg.",Zrób najpierw to o co cię prosiłem lub figę dostaniesz.,"Faça o meu favor primeiro, ou você não recebe coisa nenhuma de mim.",,"Fă-mi favoarea mai întâi, sau nu-ți zic nimic.","Сначала выполни мою просьбу, или ты ничего не получишь.",,"Gör mig en tjänst först, annars får du inget från mig.","Önce benim iyiliğimi yap, yoksa benden hiçbir şey alamazsın." +How will you know it's open?,TXT_RPLY0_SCRIPT06_D1516_HOWWI,〃,,,"Jak budeš vědět, že je otevřená?","Hvordan vil du vide, at den er åben?","Wodurch wirst du wissen, ob er offen ist?",,Kiel vi scios ĉu mi malfermis ĝin?,¿Cómo sabrás si está abierta?,¿Cómo vas a comprobar si la abrí?,"Mistä tiedät, että se on auki?",Comment est-ce que je saurais qu'elle est ouverte?,"Honnan tudod, hogy nyitva lesz?",Come farai a sapere che è aperto?,開放を知らせるには?,어떻게 도와주면 방법을 알 수 있지?,Hoe weet je dat het open is?,Hvordan vet du at den er åpen?,"Skąd będziesz wiedział, że jest już otwarta?",Como você vai saber que ela está aberta?,,Cum vei știi că e deschisă?,"Как ты узнаешь, что дверь открыта?",,Hur vet du att den är öppen?,Açık olduğunu nereden bileceksin? +Bring me back the guard's uniform. That way one of my ratfellows can wear it and no one will try to shut the door again.,TXT_DLG_SCRIPT06_D3032_BRING,〃,,,"Přines mi uniformu stráže, pak ji jeden z mých krysaříků může nosit a nikdo se už nepokusí ty dveře zavřít.","Giv mig vagtens uniform tilbage. På den måde kan en af mine rottefæller bære den, og ingen vil forsøge at lukke døren igen.","Bring mir die Uniform des Wächters. So kann einer meiner Rattenkumpel sie tragen und niemand wird wieder versuchen, die Tür zu schließen.",,"Alportu la uniformon de la gardisto, tiel unu el miaj «kamaratoj» surhavos ĝin kaj tiam neniu provos reŝlosi la pordon.","Tráeme el uniforme del guardia, así uno de mis «camarratas» podrá ponérselo para que nadie intente cerrarla de nuevo.","Tráeme el uniforme del guardia, así uno de mis «camarratas» va a poder ponérselo para que nadie intente cerrarla de nuevo.","Tuo minulle vartijan univormu. Silloin yksi rottakumppaneistani voi pitää sitä yllään, eikä kukaan yritä sulkea ovea enää uudelleen.","Ramenez moi l'uniforme du garde. Comme ça, un de mes amis rats pourra le porter et personne n'essaiera de fermer cette porte.","Hozd nekem vissza az őr egyenruháját. Az egyik besúgom felveszi, és nem lesz többé zárt ajtó előtte.",Portami l'uniforme della guardia. In questo modo uno dei nostri può indossarla e nessuno proverà più a chiudere la porta.,"ガードの制服を持ってくればいい。 そうすりゃ成り代わったラットの仲間が もう封鎖されないよう監視するだろうさ。 ","오더 병사가 입고 있는 전투복을 가져오려. 내 걸인 동료가 그걸 입고 입구를 걱정 없이 영원히 열 수 있게. - \cy끝내준다. 이제 시궁쥐 왕의 심부름도 해야 한다니.",Breng me het uniform van de bewaker terug. Op die manier kan een van mijn rattenvrienden het dragen en niemand zal proberen de deur weer te sluiten.,Przynieś mi mundur strażnika. Tym sposobem jeden z moich szczurokolegów będzie mógł go założyć i nikt nie spróbuje znowu zamknąć drzwi.,Me traga de volta o uniforme do guarda. Dessa forma um dos meus companheiros pode vestí-la e ninguém vai tentar fechar a porta novamente.,,,"Принеси мне униформу стражника. Тогда один из моих приятелей сможет носить её, и никто не попытается снова закрыть дверь.", -You want his uniform?,TXT_RPLY0_SCRIPT06_D3032_YOUWA,,,,Ty chceš jeho uniformu?,Du möchtest seine Uniform haben?,,,¿Quieres su uniforme?,,,Vous voulez son uniforme?,,,あんたに制服を渡せばいいか?,그 전투복이 정말로 필요한가?,Wil je zijn uniform?,Chcesz jego mundur?,Você quer o uniforme dele?,,,Тебе нужна его форма?, -"Open the door, bring me the uniform and we trade. Otherwise, piss off.",TXT_DLG_SCRIPT06_D4548_OPENT,,,,"Otevři dveře, přines mi uniformu a budeme obchodovat. Jinak se jdi vycpat.","Öffne die Tür, bring mir die Uniform und wir können handeln. Ansonsten verschwinde.",,,"Abre la puerta, tráeme el uniforme y negociamos. Si no, que te den.",,,"Ouvrez la porte, ramenez moi l'uniforme et nous ferons affaire. Sinon, barrez-vous.",,,"そうだ、ゲートを開いて制服を奪うんだ。 + \cy끝내준다. 이제 시궁쥐 왕의 심부름도 해야 한다니.",Breng me het uniform van de bewaker terug. Op die manier kan een van mijn rattenvrienden het dragen en niemand zal proberen de deur weer te sluiten.,"Gi meg vaktuniformen. På den måten kan en av mine rottekamerater ha den på seg, og ingen vil prøve å lukke døren igjen.",Przynieś mi mundur strażnika. Tym sposobem jeden z moich szczurokolegów będzie mógł go założyć i nikt nie spróbuje znowu zamknąć drzwi.,Me traga de volta o uniforme do guarda. Dessa forma um dos meus companheiros pode vestí-la e ninguém vai tentar fechar a porta novamente.,,"Adu-mi uniforma gardianului. Așa, unui dintre noi o va putea purta și nimeni nu va încerca să mai închidă poata vreodată.","Принеси мне униформу стражника. Тогда один из моих приятелей сможет носить её, и никто не попытается снова закрыть дверь.",,Ge mig vaktens uniform. På så sätt kan en av mina råttföljeslagare bära den och ingen kommer att försöka stänga dörren igen.,Bana muhafız üniformasını geri getir. Böylece hain dostlarımdan biri onu giyebilir ve kimse kapıyı tekrar kapatmaya çalışmaz. +You want his uniform?,TXT_RPLY0_SCRIPT06_D3032_YOUWA,〃,,,Ty chceš jeho uniformu?,Vil du have hans uniform?,Du möchtest seine Uniform haben?,,Ĉu vi volas lian uniformon?,¿Quieres su uniforme?,,Haluat siis tämän univormun?,Vous voulez son uniforme?,Kell az egyenruhája?,Vuoi la sua uniforme?,あんたに制服を渡せばいいか?,그 전투복이 정말로 필요한가?,Wil je zijn uniform?,Vil du ha uniformen hans?,Chcesz jego mundur?,Você quer o uniforme dele?,,Vrei uniforma lui?,Тебе нужна его форма?,,Vill du ha hans uniform?,Üniformasını mı istiyorsun? +"Open the door, bring me the uniform and we trade. Otherwise, piss off.",TXT_DLG_SCRIPT06_D4548_OPENT,〃,,,"Otevři dveře, přines mi uniformu a budeme obchodovat. Jinak se jdi vycpat.","Åbn døren, giv mig uniformen, og vi bytter. Ellers skal du gå ud.","Öffne die Tür, bring mir die Uniform und wir können handeln. Ansonsten verschwinde.",,"Malfermu la pordon, alportu la uniformon kaj tiam ni intertraktos. Alie, malaperu.","Abre la puerta, tráeme el uniforme y negociamos. Si no, pírate.","Abre la puerta, tráeme el uniforme y negociamos. Caso contrario, esfúmate.","Avaa ovi, tuo minulle univormu ja teemme vaihtokaupan. Muuten suksi suohon.","Ouvrez la porte, ramenez moi l'uniforme et nous ferons affaire. Sinon, barrez-vous.","Nyisd k iaz ajtót, add ide az egyenruhát és üzletelhetünk. Ha nem, akkor húzz a túróba.","Apri l'ingresso, portami l'uniforme e allora possiamo trattare. Altrimenti, non abbiamo nulla da dirci.","そうだ、ゲートを開いて制服を奪うんだ。 それまで戻ってくるんじゃねえぞ。","입구를 열고, 전투복을 구해서, 교환 하자구려! 아님... 꺼지시라. - \cy얘도 분명 냄새 하나는 죽여줄 거야.","Open de deur, breng me het uniform en we handelen. Anders, piss off.",Otwórz drzwi i przynieś mundur to się dogadamy. Jeśli nie to spadaj.,"Abra a porta, traga o uniforme e nós negociaremos. Caso contrário, vaza daqui.",,,"Открой эту дверь, принеси мне униформу и мы сторгуемся. Иначе, отвали.", -Have you brought me what I want?,TXT_DLG_SCRIPT06_D6064_HAVEY,,,,"Přinesl jsi mi, co chci?",Hast du mir was mitgebracht?,,,¿Me has traído lo que quiero?,,,Avez-vous ramené ce dont j'ai besoin?,,,必要な物は持ってきたか?,내가 원하는 것을 가지고 왔나랴?,Heb je me gebracht wat ik wil?,Przyniosłeś to o co cię prosiłem?,Você trouxe o que eu quero?,,,"Ты принёс мне то, что я просил?", -How about this uniform?,TXT_RPLY0_SCRIPT06_D6064_HOWAB,,,,Co tahle uniforma?,Wie findest du diese Uniform?,,,¿Qué tal este uniforme?,,,"Il vous convient, cet uniforme?",,,この制服はどうだ?,이 전투복은 어때?,Hoe zit het met dit uniform?,Może być ten mundur?,Que tal este uniforme?,,,Эта униформа подойдёт?, -Bring me the uniform.,TXT_RNO0_SCRIPT06_D6064_BRING,,,,Přines mi tu uniformu.,Bring mir seine Uniform.,,,Tráeme el uniforme.,,,Amenez moi l'uniforme.,,,制服を持ってこい。,전투복을 가져와랴...,Breng me het uniform.,Przynieś mi mundur.,Me traga o uniforme.,,,Принеси мне униформу., -"Good. Here's something extra. My fellows tore this off of a fallen Crusader, it's the parts that make up a flamethrower. Now Irale can make one for you. You can have such fun.",TXT_DLG_SCRIPT06_D7580_GOODH,,,,"Dobře. Tady je něco navíc. Mí stoupenci urvali tohle ze zničeného Křižáka, jsou to části, ze kterých se skládá plamenomet. Teď ti jeden může Irale vytvořit. Můžeš mít takové legrace.",Gut so. Hier ist ein kleiner Bonus. Meine Kumpel haben das hier von einem gefallenen Ordensritter abgerissen. Es sind die Teile seines Flammenwerfers. Jetzt kann Irale dir auch einen machen. Du kannst so viel Spaß damit haben...,,,"Bien. Aquí tienes algo extra. Mis compañeros arrancaron esto de un Cruzado caído, son las partes que componen un lanzallamas. Ahora Irale puede hacer uno para ti. Te vas a divertir cantidad.","Bien. Aquí tienes algo extra. Mis compañeros arrancaron esto de un Cruzado caído, son las partes que componen un lanzallamas. Ahora Irale puede hacer uno para ti. ¡Tendrás tanta diversión!",,Bien. Voilà un petit bonus. Mes amis ont arraché ceci à un croisé. C'est les pièces nécessaires à monter un lance-flammes. Irale peut en assembler un pour vous. Vous allez vraiment vous amuser.,,,"良し。礼は果たそう。 + \cy얘도 분명 냄새 하나는 죽여줄 거야.","Open de deur, breng me het uniform en we handelen. Anders, piss off.","Åpne døra, gi meg uniformen, så bytter vi. Ellers kan du dra til helvete.",Otwórz drzwi i przynieś mundur to się dogadamy. Jeśli nie to spadaj.,"Abra a porta, traga o uniforme e nós negociaremos. Caso contrário, vaza daqui.",,"Deschide poarta, adu-mi uniforma, și facem schimbul. Altfel, șterge-o de aici.","Открой эту дверь, принеси мне униформу и мы сторгуемся. Иначе, отвали.",,"Öppna dörren, ge mig uniformen och vi byter. Annars kan du dra åt helvete.","Kapıyı aç, bana üniformayı getir ve takas edelim. Yoksa defol git." +Have you brought me what I want?,TXT_DLG_SCRIPT06_D6064_HAVEY,〃,,,"Přinesl jsi mi, co chci?","Har du bragt mig det, jeg vil have?",Hast du mir was mitgebracht?,,"Ĉu vi alportis tion, kion mi volas?",¿Me has traído lo que quiero?,¿Trajiste lo que quiero?,"Oletko tuonut minulle sen, mitä haluan?",Avez-vous ramené ce dont j'ai besoin?,"Elhoztad, amit kértem?",Mi hai portato ciò che volevo?,必要な物は持ってきたか?,내가 원하는 것을 가지고 왔나랴?,Heb je me gebracht wat ik wil?,Har du det jeg vil ha?,Przyniosłeś to o co cię prosiłem?,Você trouxe o que eu quero?,,Mi-ai adus ceea ce doresc?,"Ты принёс мне то, что я просил?",,Har du gett mig det jag vill ha?,İstediğim şeyi getirdin mi? +How about this uniform?,TXT_RPLY0_SCRIPT06_D6064_HOWAB,〃,,,Co tahle uniforma?,Hvad med denne uniform?,Wie findest du diese Uniform?,,Kion pri ĉi tiu uniformo?,¿Qué tal este uniforme?,¿Qué hay de este uniforme?,Miten olisi tämä univormu?,"Il vous convient, cet uniforme?",És mi az újság ezzel az egyenruhával?,Che ne dici di questa uniforme?,この制服はどうだ?,이 전투복은 어때?,Hoe zit het met dit uniform?,Hva med denne uniformen?,Może być ten mundur?,Que tal este uniforme?,,Ce zici de uniforma asta?,Эта униформа подойдёт?,,Vad sägs om den här uniformen?,Bu üniformaya ne dersin? +Bring me the uniform.,TXT_RNO0_SCRIPT06_D6064_BRING,,,,Přines mi tu uniformu.,Giv mig hans uniform.,Bring mir seine Uniform.,,Alportu la uniformon.,Tráeme el uniforme.,,Tuo univormu minulle.,Amenez moi l'uniforme.,Hozdd ide az egyenruhát.,Portami l'uniforme.,制服を持ってこい。,전투복을 가져와랴...,Breng me het uniform.,Gi meg uniformen.,Przynieś mi mundur.,Me traga o uniforme.,,Adu-mi uniforma.,Принеси мне униформу.,,Ge mig uniformen.,Bana üniformayı getir. +"Good. Here's something extra. My fellows tore this off of a fallen Crusader, it's the parts that make up a flamethrower. Now Irale can make one for you. You can have such fun.",TXT_DLG_SCRIPT06_D7580_GOODH,MAP06: Weran.,,,"Dobře. Tady je něco navíc. Mí stoupenci tohle urvali ze zničeného Křižáka, jsou to části, ze kterých se skládá plamenomet. Teď ti jeden může Irale postavit. Můžeš mít takové legrace.","Godt. Her er noget ekstra. Mine kammerater rev den af en faldet korsfarer, det er de dele, der udgør en flammekaster. Nu kan Irale lave en til dig. Du kan have det så sjovt.",Gut so. Hier ist ein kleiner Bonus. Meine Kumpel haben das hier von einem gefallenen Ordensritter abgerissen. Es sind die Teile seines Flammenwerfers. Jetzt kann Irale dir auch einen machen. Du kannst so viel Spaß damit haben...,,Bone. Jen aldonaĵo; miaj kamaradoj deŝiris ĝin de venkita Krucisto: ili estas partoj de flamĵetilo; Irale nun povos krei unu por vi. Vi vere amuziĝos.,Genial. Aquí tienes algo extra; mis compañeros lo arrancaron de un Cruzado caído: son las partes de un lanzallamas; ahora Irale puede hacer uno para ti. Te vas a divertir cantidad.,,"Hyvä. Tässä vielä jotain vähän lisäksi. Toverini repivät tämän kaatuneesta ristiretkeläisestä. Ne ovat liekinheittimen osia. Nyt Irale voi väsätä sinulle seillaisen. Ajattele sitä, kuinka hauskaa sinulla tulee olemaan.",Bien. Voilà un petit bonus. Mes amis ont arraché ceci à un croisé. C'est les pièces nécessaires à monter un lance-flammes. Irale peut en assembler un pour vous. Vous allez vraiment vous amuser.,"Helyes. Itt van egy kis érdekesség. Egyik bajtársam letörte ezeket az egyik keresztesről, igazából egy lángszórót lehetne összerakni belőle. Irale össze tudna rakni egyet neked. Tuti örömteli pörkölő pillanatokat fog okozni.","Eccellente. Ecco, ho qualcosa per te. I miei compagni hanno staccato questo da un Crociato distrutto, sono le parti che costituiscono il lanciafiamme. Adesso Irale ne può creare uno per te. Ti potrai divertire un sacco.","良し。礼は果たそう。 それと仲間が倒れたクルセイダーからこれを 奪ってきた、火炎放射器の部品らしい。 イラールに渡せば作り上げるはずだ。 -楽しみだろう。","아주 좋은 겨! 여기, 추가 보답을 받으라. 내 걸인 동료가 크루세이더의 잔해 속에서 이걸 구해냈다네에. 아주 좋은 화염방사기를 만들어낼 수 있을 거야. 이걸 들고 이롤리를 찾아가 바. 그리고... 요리를 즐기는 거쟈.","Goed. Hier is iets extra's. Mijn vrienden scheurden dit af van een gevallen kruisvaarder, het zijn de onderdelen die een vlammenwerper vormen. Nu kan Irale er een voor je maken. Je kunt zoveel plezier hebben.","Dobrze. Oto mały bonus dla ciebie. Moi koledzy wyciągnęli to ze zniszczonego Krzyżowca, są to części do miotacza ognia. Teraz Irale będzie mógł taki dla ciebie zrobić. Będziesz miał dużo frajdy.",Muito bom. Aqui tem um brinde. Meus companheiros arrancaram isso de um Cruzado destruído. São peças para lança-chamas. Agora o Irale vai poder montar um pra você. Vai se divertir bastante.,,,"Хорошо. Я могу предложить тебе кое-что сверх уговора. Мои приятели сняли это с подбитого крестоносца. Это детали огнемёта. Ирэйл соберёт его для тебя, и ты сможешь повеселиться от души.", -Where's the gate mechanism?,TXT_RPLY0_SCRIPT06_D7580_WHERE,,,,Kde je mechanismus brány?,Wo ist der Tormechanismus?,,,¿Dónde está el mecanismo de la puerta?,,,Où se trouve le mécanisme d'ouverture de la porte?,,,ゲートメカニズムは何処だ?,관리 장치는 이제 어디있지?,Waar is het poortmechanisme?,Gdzie jest mechanizm sterujący bramą?,Onde fica o mecanismo do portão?,,,Где механизм управления воротами?, -"You have to enter another part of the sewers. To get there you must enter the castle from a sewer maintenance door and drain the fluid reclamation tank. At the bottom is the hidden entrance to sewers, and right beyond that is the manual gate control.",TXT_DLG_SCRIPT06_D9096_YOUHA,,,,Musíš vejít do jiné části stok. Musíš se údržbovými dveřmi dostat do hradu a vypustit vodní nádrž. Na dně je schovaný vchod do stok a hned za ním je manuální ovládání brány.,"Du musst in einen anderen Teil der Kanalisation. Um dort hinzukommen, musst du durch einen Wartungsgang in die Burg und den Wasserrückgewinnungstank entleeren. Am Boden des Tanks ist der versteckte Eingang zur Kanalisation und gleich dahinter die manuelle Torkontrolle.",,,"Tienes que adentrarte en otra parte de las cloacas. Para llegar ahí debes entrar al castillo por la puerta de mantenimiento de las cloacas y drenar el tanque de recuperación de fluído. Al fondo está la entrada oculta a las cloacas, y justo más allá está el control manual de la puerta.",,,"Vous devez entrer dans une autre section des égouts. Quand vous y êtes, vous devez entrer dans le château à partir de la porte de maintenance des égouts, et drainer le réservoir de recyclage d'eau. Au fond se trouve l'entrée cachée des égouts, et juste après elle, les contrôles manuels de la porte.",,,"下水道の別の部分に入る必要がある。 +楽しみだろう。","아주 좋은 겨! 여기, 추가 보답을 받으라. 내 걸인 동료가 크루세이더의 잔해 속에서 이걸 구해냈다네에. 아주 좋은 화염방사기를 만들어낼 수 있을 거야. 이걸 들고 이롤리를 찾아가 바. 그리고... 요리를 즐기는 거쟈.","Goed. Hier is iets extra's. Mijn vrienden scheurden dit af van een gevallen kruisvaarder, het zijn de onderdelen die een vlammenwerper vormen. Nu kan Irale er een voor je maken. Je kunt zoveel plezier hebben.",Bra. Her er noe ekstra. Mine karer rev dette av en falne korsfarer. Det er delene til en flammekaster. Nå kan Irale lage en til deg. Du kan ha det så gøy.,"Dobrze. Oto mały bonus dla ciebie. Moi koledzy wyciągnęli to ze zniszczonego Krzyżowca, są to części do miotacza ognia. Teraz Irale będzie mógł taki dla ciebie zrobić. Będziesz miał dużo frajdy.",Muito bom. Aqui tem um brinde. Meus companheiros arrancaram isso de um Cruzado destruído. São peças para lança-chamas. Agora o Irale vai poder montar um pra você. Vai se divertir bastante.,,"Bun. Uite aici ceva în plus. Tovarășii mei au smuls asta de pe un Cruciat răpus, sunt părți ale unui aruncător de flăcări. Acum Irale îți poate construi unul. Te poți distra de minune.","Хорошо. Я могу предложить тебе кое-что сверх уговора. Мои приятели сняли это с подбитого крестоносца. Это детали огнемёта. Ирэйл соберёт его для тебя, и ты сможешь повеселиться от души.",,"Jag har den. Här är något extra. Mina kamrater slet av den här från en stupad korsriddare, det är delarna som utgör en flamkastare. Nu kan Irale göra en åt dig. Du kan ha så roligt.",Güzel. Burada ekstra bir şey var. Arkadaşlarım bunu düşmüş bir Haçlı'dan kopardılar. Alev silahını oluşturan parçalar. Şimdi İrale senin için bir tane yapabilir. Çok eğlenebilirsiniz. +Where's the gate mechanism?,TXT_RPLY0_SCRIPT06_D7580_WHERE,〃,,,Kde je mechanismus brány?,Hvor er portmekanismen?,Wo ist der Tormechanismus?,,Kie estas la mekanismo de la pordo de la kastelo?,¿Dónde está el mecanismo de la puerta?,,Missä portin koneisto on?,Où se trouve le mécanisme d'ouverture de la porte?,Hol van a kapu szerkezet?,Dov'è il meccanismo per il cancello?,ゲートメカニズムは何処だ?,관리 장치는 이제 어디있지?,Waar is het poortmechanisme?,Hvor er portmekanismen?,Gdzie jest mechanizm sterujący bramą?,Onde fica o mecanismo do portão?,,Unde e mecanismul de acționare al porții?,Где механизм управления воротами?,,Var är grindmekanismen?,Kapı mekanizması nerede? +"You have to enter another part of the sewers. To get there you must enter the castle from a sewer maintenance door and drain the fluid reclamation tank. At the bottom is the hidden entrance to sewers, and right beyond that is the manual gate control.",TXT_DLG_SCRIPT06_D9096_YOUHA,"〃 + +https://en.wikipedia.org/wiki/Reclaimed_water",,,Musíš vejít do jiné části stok. K tomu se potřebuješ údržbovými dveřmi dostat do hradu a vypustit záchytnou nádrž. Na dně je schovaný vchod do stok a hned za ním je manuální ovládání brány.,"Du skal ind i en anden del af kloakkerne. For at komme derhen skal du gå ind i slottet fra en dør til vedligeholdelse af kloakken og tømme væskegenvindingsbeholderen. Nederst er den skjulte indgang til kloakkerne, og lige bagved er den manuelle portkontrol.","Du musst in einen anderen Teil der Kanalisation. Um dort hinzukommen, musst du durch einen Wartungsgang in die Burg und den Wasserrückgewinnungstank entleeren. Am Boden des Tanks ist der versteckte Eingang zur Kanalisation und gleich dahinter die manuelle Torkontrolle.",,"Vi devas iri al alia parto de la kloako. Por atingi tien, vi devas eniri la kastelon tra pordo de ĉambro pri kloaka bontenado kaj dreni la rezervujon de akvoreuzo; en ĝia fundo estas kaŝita enirejo al la kloako, kaj ie tie estas la mana regilo de la pordo.",Tienes que adentrarte en otra parte de las cloacas. Para llegar ahí debes entrar en el castillo por la puerta de mantenimiento de las cloacas y drenar el tanque de recuperación de agua; al fondo está la entrada oculta a las cloacas y por ahí mismo el control manual de la puerta.,Tienes que ir a otra parte de las cloacas. Para llegar ahí debes entrar al castillo por la puerta de mantenimiento de las cloacas y drenar el tanque de recuperación de agua; al fondo está la entrada oculta a las cloacas y por ahí mismo el control manual de la puerta.,"Sinun on mentävä viemäreiden eri osioon. Päästäksesi sinne sinun on mentävä linnaan viemäreiden huolto-oven kautta ja tyhjennettävä nesteentalteenottoallas. Altaan pohjalla on viemärin salainen sisäänkäynti, ja suoraan sen jäljessä on portin käsiohjain.","Vous devez entrer dans une autre section des égouts. Quand vous y êtes, vous devez entrer dans le château à partir de la porte de maintenance des égouts, et drainer le réservoir de recyclage d'eau. Au fond se trouve l'entrée cachée des égouts, et juste après elle, les contrôles manuels de la porte.","A kanális egy másik részébe kell menned. Ehhez egy szervízajtón keresztül kell behatolnod a kastélyba, úgy hogy leereszted a szárító tartályból. Az alján található a titkos kanális bejárat, és rögtön utána a kézi kapu irányító.","Devi andare in un'altra sezione delle fogne. Per raggiungerla, devi entrare nel castello da una porta di manutenzione delle fogne e svuotare la vasca di recupero fluidi. Al fondo di questa vasca c'è l'uscita nascosta per le fogne, e subito dopo c'è il controllo manuale dei cancelli.","下水道の別の部分に入る必要がある。 そこへ行くには下水道の整備室から 城の浄水施設に入りタンクを排水する必要がある その下には隠された入り口があり、 その先に手動ゲートコントロールがあるはずだ。","하수도로 통하는 또 다른 입구로 가야 혀. 들어가려면 성안에 위치한 하수도 정비소에서 수조에 있는 오물을 배출해야 해. 그 수조 밑에는 하수도로 향하는 숨겨진 입구가 있고, 그곳으로 향하면, 정문의 장치를 찾을 수 있을 게야. - \cy또 하수도라... 끝내준다. 저 아래에 또 뭐가 살고 있을까?","Je moet een ander deel van de riolering betreden. Om daar te komen moet je het kasteel binnengaan via een deur voor het onderhoud van de riolering en de vloeistoftank aftappen. Onderaan is de verborgen toegang tot de riolering, en net daarachter is de handmatige poortbesturing.","Musisz wejść do innej części kanałów. Aby się tam dostać musisz wejść do zamku przez drzwi sekcji konserwacji ścieków i osuszyć zbiornik rekultywacyjny. Na dole znajduje się ukryte przejście do kanałów, a za nim jest mechanizm bramy.",Você precisa entrar em outra parte do esgoto. Para chegar até lá você deve entrar no castelo por uma porte de manutenção de esgoto e drenar o tanque de recuperação de fluído. Lá no fundo fica a entrada oculta do esgoto e logo adiante fica o controle manual do portão.,,,"Это в другой части канализации. Чтобы попасть туда, пройди в замок через дверь обслуживания канализации и слей жидкость из бака для переработки. На его дне есть скрытый вход в стоки, и прямо за ним — ручной механизм управления воротами.", -Anything else you can do?,TXT_RPLY0_SCRIPT06_D9096_ANYTH,,,,Mohl bys udělat ještě něco?,Kannst du sonst noch was für mich tun?,,,¿Algo más que puedas hacer?,,,Que pouvez vous faire d'autre?,,,他に出来ることは?,그 외에 당신이 할 수 있는 일은?,Kun je nog iets anders doen?,Czy coś jeszcze możesz zrobić?,Algo mais que você possa fazer?,,,Можешь помочь мне чем-нибудь ещё?, -"Good luck. I've opened several of our tunnels for you. It should make your task easier. Oh, size ten, perfect! ...But dreadful colors.",TXT_DLG_SCRIPT06_D10612_GOODL,,,,"Hodně štěstí. Otevřel jsem pro tebe několik našich tunelů. To by ti mělo tvůj úkol usnadnit. Ó, velikost deset, perfektní! ...Ale hrozné barvy.","Viel Glück. Ich habe mehrere von unseren Tunnels für dich geöffnet. Es sollte deine Aufgabe vereinfachen. Oh, Größe 10. Perfekt! Aber scheußliche Farben...",,,"Buena suerte. He abierto varios de nuestros tuneles para ti. Te debería hacer el trabajo más fácil. Oh, talla diez, ¡perfecto! ... Pero colores horribles.",,,"Bonne chance. J'ai ouvert plusieurs de nos tunnels pour vous. Ca devrait rendre votre travail plus facile. Oh! Taille dix? Parfait! Les couleurs sont immondes, par contre.",,,"頑張れよ。それとアンタの為に俺達は幾つか + \cy또 하수도라... 끝내준다. 저 아래에 또 뭐가 살고 있을까?","Je moet een ander deel van de riolering betreden. Om daar te komen moet je het kasteel binnengaan via een deur voor het onderhoud van de riolering en de vloeistoftank aftappen. Onderaan is de verborgen toegang tot de riolering, en net daarachter is de handmatige poortbesturing.","Du må gå inn i en annen del av kloakken. For å komme dit må du gå inn i slottet fra en kloakkvedlikeholdsdør og tømme væskegjenvinningstanken. Nederst er den skjulte inngangen til kloakken, og rett bortenfor den er den manuelle portkontrollen.","Musisz wejść do innej części kanałów. Aby się tam dostać musisz wejść do zamku przez drzwi sekcji konserwacji ścieków i osuszyć zbiornik rekultywacyjny. Na dole znajduje się ukryte przejście do kanałów, a za nim jest mechanizm bramy.",Você precisa entrar em outra parte do esgoto. Para chegar até lá você deve entrar no castelo por uma porte de manutenção de esgoto e drenar o tanque de recuperação de fluído. Lá no fundo fica a entrada oculta do esgoto e logo adiante fica o controle manual do portão.,,"Va trebui să intrăm pe altă parte a canalelor. Ca să ajungi acolo trebuie să intri în castel printr-o ușa de mentenanță a canalului și să drenezi rezervorul. La bază e intrarea în canale, și imediat după aceea e controlul manual al porții.","Это в другой части канализации. Чтобы попасть туда, пройди в замок через дверь обслуживания канализации и слей жидкость из бака для переработки. На его дне есть скрытый вход в стоки, и прямо за ним — ручной механизм управления воротами.",,"Du måste gå in i en annan del av kloakerna. För att komma dit måste du gå in i slottet från en dörr för underhåll av kloakerna och tömma vätskereklamationstanken. Längst ner finns den dolda ingången till kloakerna, och precis bakom den finns den manuella grindmekanismen.",Kanalizasyonun başka bir bölümüne girmelisin. Oraya ulaşmak için kaleye bir kanalizasyon bakım kapısından girmeli ve sıvı geri kazanım tankını boşaltmalısınız. En altta kanalizasyonun gizli girişi ve onun hemen ötesinde de manuel kapı kontrolü var. +Anything else you can do?,TXT_RPLY0_SCRIPT06_D9096_ANYTH,〃,,,Mohl bys udělat ještě něco?,"Er der andet, du kan gøre?",Kannst du sonst noch was für mich tun?,,"Ĉu estas io alia, kion vi povas fari?",¿Algo más que puedas hacer?,,Voitko olla vielä jotenkin muuten avuksi?,Que pouvez vous faire d'autre?,Tudsz még valamit tenni?,C'è qualcos'altro che puoi fare?,他に出来ることは?,그 외에 당신이 할 수 있는 일은?,Kun je nog iets anders doen?,Noe annet du kan gjøre?,Czy coś jeszcze możesz zrobić?,Algo mais que você possa fazer?,,Mai poți face altceva?,Можешь помочь мне чем-нибудь ещё?,,Finns det något annat du kan göra?,Yapabileceğin başka bir şey var mı? +"Good luck. I've opened several of our tunnels for you. It should make your task easier. Oh, size ten, perfect! ...But dreadful colors.",TXT_DLG_SCRIPT06_D10612_GOODL,〃,,,"Hodně štěstí. Otevřel jsem pro tebe několik našich tunelů. To by ti mělo tvůj úkol usnadnit. Ó, velikost deset, perfektní! ...Ale barva je hrozná.","Held og lykke. Jeg har åbnet flere af vores tunneler for dig. Det burde gøre din opgave lettere. Åh, størrelse ti, perfekt! ...Men forfærdelige farver.","Viel Glück. Ich habe mehrere von unseren Tunnels für dich geöffnet. Es sollte deine Aufgabe vereinfachen. Oh, Größe 10. Perfekt! Aber scheußliche Farben...",,"Ŝancon. Mi malfermis diversajn el niaj tuneloj. Tio devus faciligi la taskon por vi. +Ha, la uniformo havas M-an talion. Perfekte!... Sed aĉkolora.","Buena suerte. Te he abierto varios de nuestros túneles; eso debería facilitarte las cosas. +Ah, es de talla 40. ¡Perfecto!... Aunque de colores espantosos.","Buena suerte. Te abrimos varios de nuestros túneles; eso debería facilitarte las cosas. +Ah, es de talle M. ¡Perfecto!... Aunque de colores espantosos.","Lykkyä tykö. Olen aukaissut useita tunneleistamme sinulle, minkä pitäisi helpottaa tehtävääsi. Kas, kokoa kymmenen, prikulleen sopiva! ...Mutta aivan hirveän värinen.","Bonne chance. J'ai ouvert plusieurs de nos tunnels pour vous. Ca devrait rendre votre travail plus facile. Oh! Taille dix? Parfait! Les couleurs sont immondes, par contre.","Sok sikert. Kinyitottam számos alagutat neked. Meg kell, hogy könnyítse a dolgodat. Oh, tízes méret, tökéletes!...de milyen okádék színek.","Buona fortuna. Ho aperto diversi dei nostri tunnel per te. Così dovrebbe essere più facile per te. Ah, taglia dieci, perfetto! ...Ma pessimi colori.","頑張れよ。それとアンタの為に俺達は幾つか トンネルを開けといた。多少はやり易くなるだろ。 おぅ、サイズは10型か、ピッタリだ! -...だが、おっかねえ色してんな。","행운을 빈다. 지름길을 좀 열어놨어야. 덕분에 과제가 좀 쉬워질 거다. 오, 딱맞는 치수구먼! 완벽해... 그런데 색상이 별로다.","Veel succes. Ik heb een aantal van onze tunnels voor u geopend. Het moet uw taak gemakkelijker maken. Oh, maat tien, perfect! ...Maar vreselijke kleuren.","Powodzenia. Otworzyłem kilka naszych tuneli dla ciebie. To powinno ci ułatwić zadanie. Oh, rozmiar dziesięć, idealnie! ...Ale paskudne kolory.","Boa sorte. Eu abri alguns de nossos túneis pra você. Acho que vai facilitar o seu trabalho. Ah, tamanho dez, perfeito! ...Mas as cores são horríveis.",,,"Разве что пожелать удачи. Я открыл для тебя несколько наших туннелей, это может сделать твою задачу чуть проще. О, десятый размер! Как раз впору!.. Но ужасные цвета.", -Thanks for your help.,TXT_RPLY0_SCRIPT06_D10612_THANK,,,,Díky za pomoc.,Danke für deine Hilfe.,,,Gracias por tu ayuda.,,,Merci pour votre aide.,,,協力ありがとう。,도움 정말 고마워.,Bedankt voor je hulp.,Dzięki za twoją pomoc.,Obrigado pela ajuda.,,,Спасибо за помощь., -"You give me nothing, you get nothing.",TXT_DLG_SCRIPT06_D12128_YOUGI,,,,"Ty mi nic nedáš, já ti nic nedám.","Du gibst mir nichts, ich gebe dir nichts.",,,"No me das nada, no recibes nada.",,,"Vous ne me donnez rien, je ne vous donne rien.",,,何も無ければ、何も渡すモンは無い。,헤헤... 아무 일도 없는 거니 괜찮야!,"Je geeft me niets, je krijgt niets.","Nic mi nie dajesz, nic nie dostajesz.","Você não me dá nada, não ganha nada.",,,Ничего не даёшь — ничего не получаешь., -Weran will save us. He's never failed us yet.,TXT_DLG_SCRIPT06_D13644_WERAN,,,,Weran nás zachrání. Ještě nás nezklamal.,Weran wird uns retten. Er hat uns noch nie enttäuscht.,,,Weran nos salvará. Nunca nos ha fallado.,,,Weran nous sauvera. Il ne nous a jamais failli.,,,"ウェランは皆を保護してくれている。 -彼は誰も見捨てたことはない。",워렌이 우리들을 구원해 줄 겁니다. 그는 아직 믿어도 되니까요.,Weran zal ons redden. Hij heeft ons nog nooit teleurgesteld.,Weran nas uratuje. Jeszcze nigdy nas nie zawiódł.,Weran vai nos salvar. Ele nunca nos deixou na mão.,,,Уэран поможет нам. Он ещё ни разу не подводил нас., -"If you seek an answer to your problem, find Weran. ",TXT_DLG_SCRIPT06_D15160_IFYOU,,,,"Jestli hledáš odpověď na svou otázku, najdi Werana.","Wenn du Lösungen für deine Probleme suchst, frag Weran.",,,"Si buscas una respuesta a tú problema, encuentra a Weran.",,,"Si vous avez besoin d'une réponse à vos problèmes, allez voir Weran.",,,"君の問題の答えが欲しいなら、 -ウェランに会うといい。","문제를 해결할 해답을 찾고 계신다면, 워렌을 찾아가세요.","Als je een antwoord zoekt op je probleem, vind Weran.","Jeśli szukasz rozwiązania swojego problemu, poszukaj Werana.","Se você precisa de um resposta para o seu problema, procure Weran.",,,Тебе нужен ответ? Найди Уэрана., -Long live the Front? That's all crap. We're all just waiting to die. ,TXT_DLG_SCRIPT06_D16676_LONGL,,,,Ať žije Fronta? To je blbost. Všichni jen čekáme na smrt.,Lang lebe die Front? Was für ein Mist. Wir warten doch nur auf den Tod.,,,¿Larga vida al frente? Menuda mierda. Todos esperamos la muerte.,,,Longue vie au Front? Quelles conneries! On est tous en train d'attendre de mourir!,,,"フロントに入れ? 馬鹿げてる。 -死ねと言ってるようなもんだ。",프론트와 자유를 향하여... 는 개뿔. 때문에 우리들만 죽게 생겼어요.,Lang leve het Front? Dat is allemaal onzin. We wachten allemaal op de dood.,Niech żyje Front? To wszystko to gówno. My po prostu czekamy na śmierć.,Viva a Frente? Isso é besteira. Todos nós estamos esperando a morte.,,,Да здравствует Сопротивление? Это всё чушь. Мы все просто ждём смерти., -"With our passage to the surface sealed, we can't even feed ourselves.",TXT_DLG_SCRIPT06_D18192_WITHO,,,,"Když je cesta na povrch uzavřená, nemůžeme se ani nakrmit.","Da unser Zugang zur Oberfläche verschlossen ist, haben wir nichts mehr zu essen.",,,"Con nuestro pasaje a la superficie sellado, no podemos ni alimentarnos.",,,"Avec notre passage vers la surface scellé, on ne peut même plus se nourrir.",,,"外への出入口が封鎖されてるから、 +...だが、おっかねえ色してんな。","행운을 빈다. 지름길을 좀 열어놨어야. 덕분에 과제가 좀 쉬워질 거다. 오, 딱맞는 치수구먼! 완벽해... 그런데 색상이 별로다.","Veel succes. Ik heb een aantal van onze tunnels voor u geopend. Het moet uw taak gemakkelijker maken. Oh, maat tien, perfect! ...Maar vreselijke kleuren.","Lykke til. Jeg har åpnet flere av tunnelene våre for deg. Det burde gjøre oppgaven din lettere. Å, størrelse ti, perfekt! ...men forferdelige farger.","Powodzenia. Otworzyłem kilka naszych tuneli dla ciebie. To powinno ci ułatwić zadanie. Oh, rozmiar dziesięć, idealnie! ...Ale paskudne kolory.","Boa sorte. Eu abri alguns de nossos túneis pra você. Acho que vai facilitar o seu trabalho. Ah, tamanho M, perfeito! ...Mas as cores são um horror.",,"Noroc. Am deschis câteva canale pentru tine. Ar trebui să îți ușureze munca. Ah, mărimea zece, perfect! ...Dar cumplite culori.","Разве что пожелать удачи. Я открыл для тебя несколько наших туннелей, это может сделать твою задачу чуть проще. О, десятый размер! Как раз впору!.. Но остойные цвета.",,"Lycka till. Jag har öppnat flera av våra tunnlar åt dig. Det borde göra din uppgift lättare. Åh, storlek tio, perfekt! ...men hemska färger.","İyi şanslar. Sizin için birkaç tünelimizi açtım. İşinizi kolaylaştıracaktır. Oh, 10 numara, mükemmel! ...Ama korkunç renkler." +Thanks for your help.,TXT_RPLY0_SCRIPT06_D10612_THANK,〃,,,Díky za pomoc.,Tak for din hjælp.,Danke für deine Hilfe.,,Dankon pro la helpo.,Gracias por la ayuda.,,Kiitos avustasi.,Merci pour votre aide.,Köszi a segítséget.,Grazie del tuo aiuto.,協力ありがとう。,도움 정말 고마워.,Bedankt voor je hulp.,Takk for hjelpen.,Dzięki za twoją pomoc.,Obrigado pela ajuda.,,Merci de ajutor.,Спасибо за помощь.,,Tack för hjälpen.,Yardımınız için teşekkürler. +"You give me nothing, you get nothing.",TXT_DLG_SCRIPT06_D12128_YOUGI,〃,,,"Ty mi nic nedáš, já ti nic nedám.","Hvis du ikke giver mig noget, får du intet.","Du gibst mir nichts, ich gebe dir nichts.",,"Se vi donos nenion, vi ricevos nenion.","No me das nada, no recibes nada.",,"Jos et anna minulle mitään, et vastavuoroin mitään saakaan.","Vous ne me donnez rien, je ne vous donne rien.","Nem adsz semmit, nem kapsz semmit.","Se non mi dai niente, non ricevi niente!",何も無ければ、何も渡すモンは無い。,헤헤... 아무 일도 없는 거니 괜찮야!,"Je geeft me niets, je krijgt niets.","Du gir meg ingenting, du får ingenting.","Nic mi nie dajesz, nic nie dostajesz.","Você não me dá nada, não ganha nada.",,"Nu dai nimic, primești nimic.",Ничего не даёшь — ничего не получаешь.,,"Du ger mig inget, du får inget.","Bana bir şey vermezsen, hiçbir şey alamazsın." +Weran will save us. He's never failed us yet.,TXT_DLG_SCRIPT06_D13644_WERAN,MAP06: Beggar.,,,Weran nás zachrání. Ještě nás nezklamal.,Weran vil redde os. Han har aldrig svigtet os endnu.,Weran wird uns retten. Er hat uns noch nie enttäuscht.,,Weran savos nin: li neniam desapontis nin.,Weran nos salvará: nunca nos ha fallado.,Weran nos va a salvar: nunca nos ha fallado.,Weran pelastaa meidät. Hän ei ole vielä kertaakaan pettänyt meitä.,Weran nous sauvera. Il ne nous a jamais failli.,Weran majd megment minket. Eddig sosem hagyott minket cserben.,Weran ci salverà. Non ci ha mai deluso fin'ora.,"ウェランは皆を保護してくれている。 +彼は誰も見捨てたことはない。",워렌이 우리들을 구원해 줄 겁니다. 그는 아직 믿어도 되니까요.,Weran zal ons redden. Hij heeft ons nog nooit teleurgesteld.,Weran vil redde oss. Han har aldri sviktet oss før.,Weran nas uratuje. Jeszcze nigdy nas nie zawiódł.,Weran vai nos salvar. Ele nunca nos deixou na mão.,,Weran ne va salva. Nu ne-a dezamăgit până acum.,Уэран поможет нам. Он ещё ни разу не подводил нас.,,Weran kommer att rädda oss. Han har aldrig svikit oss än.,Weran bizi kurtaracak. Şimdiye kadar bizi hiç hayal kırıklığına uğratmadı. +"If you seek an answer to your problem, find Weran. ",TXT_DLG_SCRIPT06_D15160_IFYOU,〃,,,"Jestli hledáš odpověď na svou otázku, najdi Werana.","Hvis du søger et svar på dit problem, så find Weran.","Wenn du Lösungen für deine Probleme suchst, frag Weran.",,"Se vi serĉas respondon al via problemo, renkontu Weran-on.","Si buscas una respuesta a tu problema, ve con Weran.",,"Jos haet vastausta ongelmaasi, etsi Weran.","Si vous avez besoin d'une réponse à vos problèmes, allez voir Weran.","Ha választ keresel a problémádra, akkor keresd fel Werant.","Se cerchi una soluzione al tuo problema, torva Weran.","君の問題の答えが欲しいなら、 +ウェランに会うといい。","문제를 해결할 해답을 찾고 계신다면, 워렌을 찾아가세요.","Als je een antwoord zoekt op je probleem, vind Weran.","Hvis du søker et svar på problemet ditt, finn Weran.","Jeśli szukasz rozwiązania swojego problemu, poszukaj Werana.","Se você precisa de um resposta para o seu problema, procure Weran.",,"Dacă ești în căutarea unor răspunsuri, găsește-l pe Weran.",Тебе нужен ответ? Найди Уэрана.,,"Om du söker ett svar på ditt problem, hitta Weran.","Eğer sorununuza bir cevap arıyorsanız, Weran'ı bulun." +Long live the Front? That's all crap. We're all just waiting to die. ,TXT_DLG_SCRIPT06_D16676_LONGL,〃,,,Ať žije Fronta? To je blbost. Všichni jen čekáme na smrt.,Længe leve fronten? Det er alt sammen noget lort. Vi venter alle bare på at dø.,Lang lebe die Front? Was für ein Mist. Wir warten doch nur auf den Tod.,,Ĉu vivu la Fronto? Kia fekaĵo. Ni ĉiuj atendas morton.,¿Que viva el Frente? Menuda mierda. A todos nos espera la muerte.,¿Que viva el Frente? Pura mierda. A todos nos espera la muerte.,Kauan eläköön Rintama? Täyttä puppua. Me kaikki vain odotamme kuolemaa.,Longue vie au Front? Quelles conneries! On est tous en train d'attendre de mourir!,"Éljen a Front? Mekkora baromság. Csak arra várunk, hogy meghaljunk.",Lunga vita al Fronte? Sono tutte idiozie. Stiamo tutti in attesa di morire.,"フロントに入れ? 馬鹿げてる。 +死ねと言ってるようなもんだ。",프론트와 자유를 향하여... 는 개뿔. 때문에 우리들만 죽게 생겼어요.,Lang leve het Front? Dat is allemaal onzin. We wachten allemaal op de dood.,Lenge leve Fronten? Det er bare tull. Vi venter bare på å dø.,Niech żyje Front? To wszystko to gówno. My po prostu czekamy na śmierć.,Viva a Frente? Isso é besteira. Todos nós estamos esperando a morte.,,Să trăiască Frontul? Aiureli. Doar așteptăm să murim.,Да здравствует Сопротивление? Это всё чушь. Мы все просто ждём смерти.,,Länge leve fronten? Det är bara skit. Vi väntar bara på att dö.,Cephe çok yaşa mı? Bunların hepsi saçmalık. Hepimiz ölmeyi bekliyoruz. +"With our passage to the surface sealed, we can't even feed ourselves.",TXT_DLG_SCRIPT06_D18192_WITHO,〃,,,"Když je cesta na povrch uzavřená, nemůžeme se ani nakrmit.","Med vores passage til overfladen forseglet, kan vi ikke engang brødføde os selv.","Da unser Zugang zur Oberfläche verschlossen ist, haben wir nichts mehr zu essen.",,"Ĉar nia irado al la surfaco estas ŝlosita, ni eĉ ne povas nutri nin.","Con nuestro pasaje a la superficie cerrado, no podemos ni alimentarnos.",,Pääsymme maanpinnalle ollessa salvattuna emme voi edes ruokkia itseämme.,"Avec notre passage vers la surface scellé, on ne peut même plus se nourrir.","Mivel a felszínre vezető átjáró el van zárva, még ételhez sem jutunk.","Con il passaggio verso la superfice chiuso, non possiamo neanche mangiare.","外への出入口が封鎖されてるから、 飯が調達できないんだ。 -","오더가 지상으로 향하는 입구를 막은 이상, 우리는 굶어 죽어야 할 운명에 시달려야 해요.","Met onze doorgang naar de oppervlakte afgesloten, kunnen we onszelf niet eens voeden.",Z zamkniętą naszą drogą na powierzchnię nie możemy się nawet nakarmić.,"Com a nossa passagem para a superfície selada, não somos capazes nem de nos alimentar.",,,"Пока выход на поверхность закрыт, мы не можем даже прокормить себя.", -"Food, do you have any food? Please help us.",TXT_DLG_SCRIPT06_D19708_FOODD,,,,"Jídlo, nemáš nějaké jídlo? Pomoz nám, prosím.","Essen, hast du was zu essen? Bitte hilf uns.",,,"Comida, ¿Tienes algo de comida? Por favor ayúdanos.",,,"A manger, vous avez à manger? Aidez-nous, s'il vous plaît.",,,食い物、食い物を恵んでくれないか? 頼むよ。,굶어 죽을 것 같습니다... 부디 음식 찌꺼기라도 괜찮으니까 음식을...,"Eten, heb je eten? Help ons alstublieft.","Jedzenie, masz może jakieś jedzenie? Proszę pomóż nam.",Comida. Você tem alguma comida? Por favor nos ajude.,,,"Еда. У тебя есть еда? Пожалуйста, помоги нам.", -"This is my reward for letting prisoners escape, guarding the sewers. If I ever find the guy who broke them out, I'll slaughter him.",TXT_DLG_SCRIPT06_D21224_THISI,,,,"Tohle je má odměna za to, že jsem nechal utéct vězně: hlídání stok. Jestli někdy najdu toho hajzla, který je pustil, zabiju ho.","Das ist meine Belohnung dafür, dass ich die Gefangenen entkommen lassen habe. Jetzt darf ich die Kanalisation bewachen. Wenn ich jemals den Kerl finde, der das gemacht hat, mache ich Hackfleisch aus ihm!",,,"Ésta es mi recompensa por dejar a prisioneros escapar, vigilar las cloacas. Si encuentro al tipo que los liberó, me lo cargo.","Ésta es mi recompensa por dejar escapar a los prisioneros, vigilar las cloacas. Si encuentro al tipo que los liberó, lo mataré.",,"Voici ma récompense pour avoir laissé les prisonniers s'évader: garder les égouts. Si je trouve celui qui les a libéré, je l'étripe.",,,"この下水道から囚人を脱走させた奴を探す為、 +","오더가 지상으로 향하는 입구를 막은 이상, 우리는 굶어 죽어야 할 운명에 시달려야 해요.","Met onze doorgang naar de oppervlakte afgesloten, kunnen we onszelf niet eens voeden.","Nå som passasjen til overflaten er stengt, kan vi ikke engang få mat.",Z zamkniętą naszą drogą na powierzchnię nie możemy się nawet nakarmić.,"Com a nossa passagem para a superfície selada, não somos capazes nem de nos alimentar.",,"Cu calea spre suprafață sigilată, nici măcar nu ne putem hrănii.","Пока выход на поверхность закрыт, мы не можем даже прокормить себя.",,Med vår passage till ytan förseglad kan vi inte ens föda oss själva.,Yüzeye geçişimiz mühürlü olduğu için kendimizi bile besleyemiyoruz. +"Food, do you have any food? Please help us.",TXT_DLG_SCRIPT06_D19708_FOODD,〃,,,"Jídlo, nemáš nějaké jídlo? Pomoz nám, prosím.","Mad, har du noget mad? Vær sød at hjælpe os.","Essen, hast du was zu essen? Bitte hilf uns.",,Manĝaĵoj... Ĉu vi havas manĝaĵojn? Bonvolu helpi nin.,"Comida... ¿No tendrás algo de comida? Ayúdanos, por favor.",,"Ruokaa, onko sinulla yhtään ruokaa? Pyydän, auta meitä.","A manger, vous avez à manger? Aidez-nous, s'il vous plaît.","Étel, van nálad valami étel? Kérlek segíts nekünk.","Cibo, hai del cibo? Per favore aiutaci.",食い物、食い物を恵んでくれないか? 頼むよ。,굶어 죽을 것 같습니다... 부디 음식 찌꺼기라도 괜찮으니까 음식을...,"Eten, heb je eten? Help ons alstublieft.","Mat, har du noe mat? Vær så snill, hjelp oss.","Jedzenie, masz może jakieś jedzenie? Proszę pomóż nam.",Comida. Você tem alguma comida? Por favor nos ajude.,,"Mâncare, ai mâncare? Te rog ajută-ne.","Еда. У тебя есть еда? Пожалуйста, помоги нам.",,"Mat, har ni någon mat? Snälla, hjälp oss.","Yiyecek, hiç yiyeceğiniz var mı? Lütfen bize yardım edin." +"This is my reward for letting prisoners escape, guarding the sewers. If I ever find the guy who broke them out, I'll slaughter him.",TXT_DLG_SCRIPT06_D21224_THISI,MAP06: Gray acolyte.,,,"Tohle je má odměna za to, že jsem nechal utéct vězně: hlídání stok. Jestli někdy najdu toho hajzla, který je pustil, zabiju ho.","Dette er min belønning for at lade fanger flygte og bevogte kloakkerne. Hvis jeg nogensinde finder den fyr, der brød dem ud, vil jeg slagte ham.","Das ist meine Belohnung dafür, dass ich die Gefangenen entkommen lassen habe. Jetzt darf ich die Kanalisation bewachen. Wenn ich jemals den Kerl finde, der das gemacht hat, mache ich Hackfleisch aus ihm!",,"Jen mia rekompenco pro tio, ke mi ne evitis la liberigon de la ekskaptitoj: gardi la kloakon. Se mi iam trovas la liberiginton, mi mortigos lin.","Esta es mi recompensa por dejar escapar a los prisioneros: vigilar las cloacas. Si llego a encontrar al tío que los ha liberado, me lo cargo.","Esta es mi recompensa por dejar escapar a los prisioneros: vigilar las cloacas. Si llego a encontrar al tipo que los liberó, lo asesino.","Tämä on minun palkkani siitä hyvästä, että päästin vangit pakenemaan: viemäreiden vartiointi. Jos ikinä saan käsiini sen tyypin, joka päästi ne pakoon, lahtaan sen.","Voici ma récompense pour avoir laissé les prisonniers s'évader: garder les égouts. Si je trouve celui qui les a libéré, je l'étripe.","Ez a jutalmam amiért hagytam elszökni a foglyokat. Ha meglelem az ürgét aki kiszabadította őket, biztosan kicsinálom.","Ecco la mia ricompensa per aver fatto scappare i prigionieri, fare la guardia alle fogne. Se mai trovo chi li ha liberati, lo faccio a pezzi.","この下水道から囚人を脱走させた奴を探す為、 下水道を監視している。首謀者を見つけたら、 -その命を持って報いを受けてもらう。","수감자들의 탈옥을 막지 못해서 하수도를 지키게 되었어. 만약 탈옥하게 만든 녀석을 만난다면, 녀석이 죽을 때 까지 내장을 천천히 끄집어낼 거다.","Dit is mijn beloning voor het laten ontsnappen van gevangenen, het bewaken van de riolering. Als ik ooit de man vind die ze heeft uitgebroken, zal ik hem afslachten.","To moja nagroda za pozwolenie więźniom uciec, pilnowanie ścieków. Jeśli kiedyklowiek dorwę tego, kto pomógł im uciec, to go zamorduję.","Essa é a minha recompensa por deixar os prisioneiros escaparem. Vigiar o esgoto. Se algum dia eu encontrar o cara que soltou eles, eu vou arrancar os seus pedaços.",,,"Я отбываю наказание за то, что не остановил побег из тюрьмы: охраняю канализацию. Если я когда-нибудь найду того парня, что освободил пленников, я его на куски порву.", -"We've got those little beggars just where we want them. Few more days of this, and they'll have starved themselves into oblivion.",TXT_DLG_SCRIPT06_D22740_WEVEG,,,,"Máme ty žebráčky přesně tam, kde chceme. Ještě pár dní a vyhladoví se do zapomnění.","Wir haben diese armseligen Bettler doch genau da, wo wir sie haben wollen. Noch ein paar Tage und sie wären verhungert.",,,"Tenemos a esos indigentes justo donde los queremos. Unos cuantos días más así, y se habrán consumido por el hambre.",,,On a enfin ces sales clodos là où on veut qu'ils soient. Quelques jours de plus et il seront tous morts de faim.,,,"この辺の何処かに乞食共がいるはずだ。 -数日もすれば忘れ去られ飢え死するだろうな。",저 빌어먹을 거지들이 밖으로 나가지 못하게 우리들이 입구를 꼼꼼히 막아뒀지. 천천히 굶어 죽는 순간을 재밌게 즐기고 있을걸?,We hebben die kleine bedelaars precies waar we ze willen hebben. Nog maar een paar dagen en ze zullen zich in de vergetelheid hebben laten hongeren.,"Trzymamy tych małych żebraków tam gdzie chcemy, żeby byli. Jeszcze kilka dni i zagłodzą się na śmierć.",Esses mendigos estão bem onde a gente quer que estejam. Só mais alguns dias e eles vão morrer de fome.,,,"Мы загнали этих жалких нищих туда, где им самое место. Ещё несколько дней, и все они подохнут с голоду.", -What's your clearance? There's no unauthorized personnel allowed up here.,TXT_DLG_SCRIPT06_D24256_WHATS,,,,Máš oprávnění? Žádná nepovolená osoba tady nahoře nemá co dělat!,Wo ist deine Berechtigung? Unautorisiertes Personal darf hier nicht rein.,,,¿Qué permiso tienes? No se permite al personal no autorizado aquí.,,,Où est votre autorisation? Aucun personnel non autorisé ne peut venir ici.,,,"お前のクリアランスは何だ? -ここは許可の無い者は立入を禁じている。",승인을 받지 않은 것 같은데. 여긴 출입금지 구역이다.,Wat is uw toelating? Er is hier geen onbevoegd personeel toegestaan.,Gdzie twoje zezwolenie? Nieautoryzowany personel nie ma tu wstępu.,Onde está a sua permissão? Ninguém sem permissão pode ficar aqui.,,,Где твой пропуск? Здесь нечего делать неуполномоченному персоналу., -What the hell? Who opened the gates? Sound the alarm!!!,TXT_DLG_SCRIPT07_D0_WHATT,,,,Co to sakra? Kdo otevřel bránu? Volej na poplach!,Was zur Hölle? Wer hat die Tore geöffne? Alarm!,,,¿Qué demonios? ¿Quién ha abierto las puertas? ¡¡¡Activen la alarma!!!,,,Qu'est-ce que c'est que ce bordel? Qui a ouvert les portes? Faites sonner l'alarme!,,,"何をしやがった? -誰がゲートを開けた? 警報を鳴らせ!",누가 성문을 열어놨어? 경보! 알람을 울려라!,Wat de hel? Wie heeft de poorten geopend? Laat alarm slaan!!!,Co u diabła? Kto otworzył bramy? Włączyć alarm!!!,Mas que diabos? Quem abriu os portões? Ativem o alarme!!!,,,Что за чертовщина? Кто открыл ворота? Бейте тревогу!, -"There's another way into the sewers, throw that switch and then go up and purge the reclamation tank.",TXT_DLG_SCRIPT07_D1516_THERE,,,,"Do stok vede další cesta, zatáhni za tuhle páku a pak jdi nahoru a vypusť obnovnou nádrž.",Da ist ein anderer Weg in die Kanalisation. Drück den Schalter da und leere den Rückgewinnungstank.,,,"Hay otra entrada a las cloacas, activa ese interruptor y luego sube y purga el tanque de recuperación.",,,Il y a une autre entrée pour les égouts. Utilisez ce bouton et montez purger le réservoir de recyclage.,,,"下水道に別の入り口がある、スイッチを入れ -次に昇って浄水タンクを空にするんだ。",하수도로 향하는 또 다른 길이 있어. 저 스위치를 켜고 위로 올라가서 수조의 오물을 비워봐.,"Er is nog een andere weg in de riolering, gooi die schakelaar naar boven en ga dan naar boven om de terugwinnings tank te zuiveren.","Jest jeszcze inna droga do kanałów, wciśnij ten przełącznik, idź na górę i opróżnij zbiornik rekultywacyjny.","Há outra maneira de entrar no esgoto. Use esse interruptor, suba e esvazie o tanque de recuperação.",,,"Есть другой путь в канализацию. Переведи этот рычаг, затем иди наверх и слей жидность из бака для переработки.", -"What the hell's your problem. If the Programmer comes up from his audience chamber, you're dead.",TXT_DLG_SCRIPT07_D3032_WHATT,,,,"Co máš sakra za problém? Jestli Programátor vyjde ze svého sálu, jsi mrtvý.","Was, verdammt, ist dein Problem? Wenn der Programmierer seine Audienzkammer verläßt, bist du tot.",,,"¡Qué demonios te pasa! Si el Programador viene de su cámara de audición, estás muerto.",,,"C'est quoi votre problème? Si le Programmeur sort de sa chambre d'audience, vous êtes mort.",,,"一体何をしに来た。プログラマーが +その命を持って報いを受けてもらう。","수감자들의 탈옥을 막지 못해서 하수도를 지키게 되었어. 만약 탈옥하게 만든 녀석을 만난다면, 녀석이 죽을 때 까지 내장을 천천히 끄집어낼 거다.","Dit is mijn beloning voor het laten ontsnappen van gevangenen, het bewaken van de riolering. Als ik ooit de man vind die ze heeft uitgebroken, zal ik hem afslachten.","Dette er belønningen min for å la fanger rømme og vokte kloakken. Hvis jeg finner fyren som slapp dem ut, skal jeg slakte ham.","To moja nagroda za pozwolenie więźniom uciec, pilnowanie ścieków. Jeśli kiedyklowiek dorwę tego, kto pomógł im uciec, to go zamorduję.","Essa é a minha recompensa por deixar os prisioneiros escaparem. Vigiar o esgoto. Se algum dia eu encontrar o cara que soltou eles, eu vou arrancar os seus pedaços.",,"Asta e răsplata mea pentru că am lăsat prizonieri să scape, apărarea canalelor. Dacă îl prind pe cel care i-a lăsat să scape, îl masacrez.","Я отбываю наказание за то, что не остановил побег из тюрьмы: охраняю канализацию. Если я когда-нибудь найду того парня, что освободил пленников, я его на куски порву.",,Det här är min belöning för att jag lät fångarna rymma och vaktade kloakerna. Om jag någonsin hittar killen som bröt ut dem ska jag slakta honom.,"Mahkumların kaçmasına izin verip kanalizasyonları koruduğum için ödülüm bu. Eğer onları kaçıran adamı bulursam, onu katledeceğim." +"We've got those little beggars just where we want them. Few more days of this, and they'll have starved themselves into oblivion.",TXT_DLG_SCRIPT06_D22740_WEVEG,MAP06: Red acolyte.,,,"Máme ty žebráčky přesně tam, kde chceme. Ještě pár dní a vyhladoví se do zapomnění.","Vi har de små tiggere lige hvor vi vil have dem. Et par dage mere af dette, og de vil have sultet sig selv til ukendelighed.","Wir haben diese armseligen Bettler doch genau da, wo wir sie haben wollen. Noch ein paar Tage und sie wären verhungert.",,"Tiuj almozuloj estas precize tie, kie ni volas: ankoraŭ kelkajn tagojn en tia situo kaj ili ne plu eltenos la inanicion.",Tenemos a esos indigentes justo donde los queremos: unos cuantos días más así y se habrán consumido por el hambre.,Tenemos a esos mendigos justo donde los queremos: un par de días más así y ya no van a poder más del hambre.,"Olemme ajaneet ne pikku kerjäläiset juuri sinne, minne haluammekin. Vielä muutama päivä tätä, ja ovat varmaankin nääntyneet unholaan.",On a enfin ces sales clodos là où on veut qu'ils soient. Quelques jours de plus et il seront tous morts de faim.,"Pont ott vannak ezek a koldusok ahol akarjuk. Még néhány nap, és halálra fognak éhezni.","Abbiamo quei piccoli mendicanti proprio dove vogliamo. Un paio di altri giorni di questo trattamento, e saranno tutti morti di fame.","この辺の何処かに乞食共がいるはずだ。 +数日もすれば忘れ去られ飢え死するだろうな。",저 빌어먹을 거지들이 밖으로 나가지 못하게 우리들이 입구를 꼼꼼히 막아뒀지. 천천히 굶어 죽는 순간을 재밌게 즐기고 있을걸?,We hebben die kleine bedelaars precies waar we ze willen hebben. Nog maar een paar dagen en ze zullen zich in de vergetelheid hebben laten hongeren.,"Vi har de små tiggerne akkurat der vi vil ha dem. Et par dager til, så har de sultet seg selv i hjel.","Trzymamy tych małych żebraków tam gdzie chcemy, żeby byli. Jeszcze kilka dni i zagłodzą się na śmierć.",Esses mendigos estão bem onde a gente quer que estejam. Só mais alguns dias e eles vão morrer de fome.,,"Îi avem pe sărmanii ăștia exact acolo unde vrem. Încă câteva zile, și vor muri de foame.","Мы загнали этих жалких нищих туда, где им самое место. Ещё несколько дней, и все они подохнут с голоду.",,"Vi har de små tiggarna precis där vi vill ha dem. Några dagar till av detta, och de kommer att ha svultit sig själva till glömska.","O küçük dilencileri tam istediğimiz yere getirdik. Birkaç gün daha böyle devam ederlerse, kendilerini açlıktan öldürmüş olacaklar." +What's your clearance? There's no unauthorized personnel allowed up here.,TXT_DLG_SCRIPT06_D24256_WHATS,MAP06: Near storage.,,,Máš oprávnění? Žádná nepovolená osoba tady nahoře nemá co dělat!,Hvad er din tilladelse? Der er ingen uautoriseret personale tilladt heroppe.,Wo ist deine Berechtigung? Unautorisiertes Personal darf hier nicht rein.,,Kiun paspermeson vi havas? Nerajtigita personaro ne estas permesata ĉi tie.,¿Qué permiso tienes? No se permite al personal no autorizado aquí.,,Mikä on kulkuoikeutesi? Henkilöstöllä ei ole tänne pääsyä ilman lupaa.,Où est votre autorisation? Aucun personnel non autorisé ne peut venir ici.,Milyen engedélyed van? Nem léphet be engedély nélkül ide egy alkalmazott sem.,Hai l'autorizzazione per essere qui? Non è assolutamente permesso al personale non autorizzato di stare qua sopra.,"お前のクリアランスは何だ? +ここは許可の無い者は立入を禁じている。",승인을 받지 않은 것 같은데. 여긴 출입금지 구역이다.,Wat is uw toelating? Er is hier geen onbevoegd personeel toegestaan.,Hva er din klarering? Uautorisert personell er ikke tillatt her oppe.,Gdzie twoje zezwolenie? Nieautoryzowany personel nie ma tu wstępu.,Onde está a sua permissão? Ninguém sem permissão pode ficar aqui.,,Care e nivelul tău de acces? Niciun personal neautorizat nu are voie aici.,Где твой пропуск? Здесь нечего делать неуполномоченным лицам.,,Vad har du för tillstånd? Ingen obehörig personal tillåts här uppe.,Yetkiniz nedir? Buraya yetkisiz personel giremez. +What the hell? Who opened the gates? Sound the alarm!!!,TXT_DLG_SCRIPT07_D0_WHATT,MAP07: Red acolyte at the main entrance.,,,Co to sakra? Kdo otevřel bránu? Volej na poplach!,Hvad fanden? Hvem åbnede portene? Slå alarm!!!!,Was zur Hölle? Wer hat die Tore geöffne? Alarm!,,Kio diable? Kiu malfermis la pordojn? Sonorigu la alarmon!!!,¿Qué demonios? ¿Quién ha abierto las puertas? ¡¡¡Activad la alarma!!!,¿Qué carajo? ¿Quién abrió las puertas? ¡¡¡Activen la alarma!!!,Mitä helvettiä? Kuka avasi portit? Laukaise hälytys!!!,Qu'est-ce que c'est que ce bordel? Qui a ouvert les portes? Faites sonner l'alarme!,Mi a franc? Ki nyitotta ki a kaput? Indítsátok be a riasztót!,Ma che diavolo? Chi ha aperto i cancelli? Suonate l'allarme!!!,"何をしやがった? +誰がゲートを開けた? 警報を鳴らせ!",누가 성문을 열어놨어? 경보! 알람을 울려라!,Wat de hel? Wie heeft de poorten geopend? Laat alarm slaan!!!,Hva i helvete? Hvem åpnet porten? Slå alarm!,Co u diabła? Kto otworzył bramy? Włączyć alarm!!!,Mas que diabos? Quem abriu os portões? Ativem o alarme!!!,,Ce naiba? Cine a deschis porțile? Sună alarma!!!,Что за чертовщина? Кто открыл ворота? Бейте тревогу!,,Vad i helvete? Vem öppnade grindarna? Slå larm!,Ne oluyor be? Kapıları kim açtı? Alarmı çalın!!! +"There's another way into the sewers, throw that switch and then go up and purge the reclamation tank.",TXT_DLG_SCRIPT07_D1516_THERE,MAP07,,,"Do stok vede další cesta, zatáhni za tuhle páku a pak jdi nahoru a vypusť obnovnou nádrž.","Der er en anden vej ind i kloakkerne, smid kontakten og gå så op og tøm genvindingstanken.",Da ist ein anderer Weg in die Kanalisation. Drück den Schalter da und leere den Rückgewinnungstank.,,"Estas alia enirejo al la kloako: enŝaltu ĉi tiun ŝaltilon, tiam reiru supren laŭ la ŝtuparo kaj drenu la rezervujon de akvoreuzo.",Hay otra entrada a las cloacas: activa este interruptor y luego ve a drenar el tanque de recuperación de agua subiendo las escaleras.,,Viemäreihin on toinen reitti. Käännä tuota vipua ja mene sitten ylös tyhjentämään talteenottoallas.,Il y a une autre entrée pour les égouts. Utilisez ce bouton et montez purger le réservoir de recyclage.,"Van egy másik módja is bejutni a kanálisba. Kapcsold fel azt a kapcsolót, aztán menj fel és ereszd le a szárító tartályt.","C'è un altro ingresso per le fogne, attiva quella leva e poi sali per svuotare la vasca di recupero fluidi.","下水道に別の入り口がある、スイッチを入れ +次に昇って浄水タンクを空にするんだ。",하수도로 향하는 또 다른 길이 있어. 저 스위치를 켜고 위로 올라가서 수조의 오물을 비워봐.,"Er is nog een andere weg in de riolering, gooi die schakelaar naar boven en ga dan naar boven om de terugwinnings tank te zuiveren.","Det er en annen vei inn i kloakken, trykk på bryteren og gå opp og rens tanken.","Jest jeszcze inna droga do kanałów, wciśnij ten przełącznik, idź na górę i opróżnij zbiornik rekultywacyjny.","Há outra maneira de entrar no esgoto. Use esse interruptor, suba e esvazie o tanque de recuperação.",,"Mai e o cale de acces către canale, folosește butonul apoi du-te sus și scurge lichidul din rezervor.","Есть другой путь в канализацию. Переведи этот рычаг, затем иди наверх и слей жидность из бака для переработки.",,"Det finns en annan väg in i kloakerna, slå om den strömbrytaren och gå sedan upp och rensa återvinningstanken.","Kanalizasyona giden başka bir yol var, o düğmeyi at ve sonra yukarı çıkıp ıslah tankını temizle." +"What the hell's your problem. If the Programmer comes up from his audience chamber, you're dead.",TXT_DLG_SCRIPT07_D3032_WHATT,MAP07: Hospital.,,,"Co máš sakra za problém? Jestli Programátor vyjde ze svého sálu, jsi mrtvý.","Hvad fanden er dit problem? Hvis programmøren kommer op fra sit publikumskammer, er du død.","Was, verdammt, ist dein Problem? Wenn der Programmierer seine Audienzkammer verläßt, bist du tot.",,"Kion diable vi faras!? Se la Programisto revenos de sia juĝejo, vi mortos.","¿¡Qué demonios te pasa!? Si el Programador vuelve de su sala de audiencias, estás muerto.","¿¡Qué carajo te pasa!? Si el Programador vuelve de su sala de audiencias, estás muerto.","Mikä helvetti sinussa on vialla. Jos ohjelmoitsija tulee valtaistuinsaliltaan, olet mennyttä.","C'est quoi votre problème? Si le Programmeur sort de sa chambre d'audience, vous êtes mort.","Mi az isten bajod van? Ha a Programozó feljön a kihallgató kamrájábó, akkor neked annyi.","Ma quale diavolo è il tuo problema. Se il Programmatore arriva dalla sua camera delle udienze, sei morto.","一体何をしに来た。プログラマーが オーディエンスチャンバーから来たら -死んでいた所だ。","너희들 제정신이야? 프로그래머님이 알현실에서 뛰쳐나오는 순간, 네 놈은 죽게 될 거라고!","Wat de hel is jouw probleem? Als de programmeur uit zijn publiekskamer komt, ben je dood.",Jaki masz problem do diaska? Jeśli Programista wyjdzie ze swojej sali audiencji będziesz martwy.,"Qual é o seu problema? Se o Programador vier até aqui de sua câmara de audiências, você estará morto.",,,"Проклятье, что с тобой не так? Если Программист поднимется из приёмного зала, ты покойник!", -"Hey, you're not cleared to go down there.",TXT_DLG_SCRIPT07_D4548_HEYYO,,,,"Hej, nemáš povolení jít tam dolů.","He, du darfst da nicht runtergehen.",,,"Hey, no tienes permiso para bajar aquí.",,,"Hé, vous n'avez pas le droit d'être ici.",,,"おい、あんたはここを降りる事は -許可されてないぞ。",잠깐. 너는 밑으로 내려갈 허가를 받지 않았다.,"Hé, je hebt geen toestemming om naar beneden te gaan.","Hej, nie masz zgody na zejście tam.","Ei, você não tem permissão para descer aí.",,,"Эй, у тебя нет разрешения спускаться туда.", -Programmer? Who told you that? There is no Programmer. That story was spread ages ago. Don't tell me the Front actually believed that crap. Idiots.,TXT_DLG_SCRIPT07_D6064_PROGR,,,,"Programátor? Kdo ti to řekl? Není žádný Programátor. To je stará pověra. Neříkej mi, že tomu Fronta doopravdy věřila. Idioti.","Programmierer? Wer hat dir das erzählt? Es gibt keinen Programmierer. Das ist eine alte Legende. Sag mir nicht, dass die Front an diesen Blödsinn glaubt. Idioten.",,,¿Programador? ¿Quién te ha dicho eso? No hay Programador. Esa historia se ha extendido hace años. No me digas que el frente realmente se ha creído el cuento. Idiotas.,,,Programmeur? Qui vous a raconté ça? Il n'y a pas de Programmeur. Cette rumeur a commencé il y a des années. J'arrive pas à croire que ces abrutis du Front y croient. Idiots.,,,"プログラマー?誰ガそんなことヲ言った? +死んでいた所だ。","너희들 제정신이야? 프로그래머님이 알현실에서 뛰쳐나오는 순간, 네 놈은 죽게 될 거라고!","Wat de hel is jouw probleem? Als de programmeur uit zijn publiekskamer komt, ben je dood.","Hva i helvete er problemet ditt? Hvis programmereren kommer opp fra audiensrommet, er du død.",Jaki masz problem do diaska? Jeśli Programista wyjdzie ze swojej sali audiencji będziesz martwy.,"Qual é o seu problema? Se o Programador vier até aqui de sua câmara de audiências, você estará morto.",,"Care mai e problema ta? Dacă Programatorul vine sus din camera sa de audiență, ești mort.","Проклятье, что с тобой не так? Если Программист поднимется из приёмного зала, ты покойник!",,Vad i helvete är ditt problem. Om Programmeraren kommer upp från sin publikrum är du död.,"Senin sorunun ne? Eğer Programcı seyirci odasından çıkarsa, öldün demektir." +"Hey, you're not cleared to go down there.",TXT_DLG_SCRIPT07_D4548_HEYYO,,,,"Hej, nemáš povolení jít tam dolů.",Du har ikke tilladelse til at gå derned.,"He, du darfst da nicht runtergehen.",,"He, vi ne rajtas iri malsupren.","Oye, no tienes permiso para bajar aquí.",,"Hei, sinulla ei ole lupaa mennä alas sinne.","Hé, vous n'avez pas le droit d'être ici.","Héj, nincs engedélyed oda lemenni.","Ehi, non hai l'autorizzazione per andare laggiù.","おい、あんたはここを降りる事は +許可されてないぞ。",잠깐. 너는 밑으로 내려갈 허가를 받지 않았다.,"Hé, je hebt geen toestemming om naar beneden te gaan.","Hei, du er ikke klarert til å gå ned dit.","Hej, nie masz zgody na zejście tam.","Ei, você não tem permissão para descer aí.",,"Hei, n-ai acces să mergi acolo jos.","Эй, у тебя нет разрешения спускаться туда.",,Du har inte tillstånd att gå ner dit.,"Hey, oraya inme iznin yok." +Programmer? Who told you that? There is no Programmer. That story was spread ages ago. Don't tell me the Front actually believed that crap. Idiots.,TXT_DLG_SCRIPT07_D6064_PROGR,MAP07: Computer room (northwest building).,,,"Programátor? Kdo ti to řekl? Není žádný Programátor. To je stará pověra. Neříkej mi, že tomu Fronta doopravdy věřila. Idioti.","Programmør? Hvem har fortalt dig det? Der er ingen programmør. Den historie blev spredt for længe siden. Fortæl mig ikke, at fronten troede på det lort. Idioter.","Programmierer? Wer hat dir das erzählt? Es gibt keinen Programmierer. Das ist eine alte Legende. Sag mir nicht, dass die Front an diesen Blödsinn glaubt. Idioten.",,"Ĉu Programisto? Kie vi aŭdis tion? Ne estas Programisto; tiu storio ekdisvastiĝis antaŭ jaroj. Ne diru, ke la Fronto kredis tian fekaĵon. Kiel stultaj.",¿Programador? ¿De dónde sacas eso? No hay Programador; esa historia se ha extendido desde hace años. No me digas que el Frente realmente se ha creído el cuentito. Qué idiotas.,,"Ohjelmoitsija? Kuka sinulle on kertonut? Ei ole mitään Ohjelmoitsijaa. Tarina oli laitettu liikkeelle ajat sitten. Älä vain kerro, että Rintama oikeasti uskoi siihen höpöpuheeseen. Mitä idiootteja.",Programmeur? Qui vous a raconté ça? Il n'y a pas de Programmeur. Cette rumeur a commencé il y a des années. J'arrive pas à croire que ces abrutis du Front y croient. Idiots.,"Programozó? Ki mondta ezt neked? Nincs semmiféle programozó. Ez egy ezer éves történet. Azt ne mondd már, hogy a Front elhitte ezt a maszlagot. Idióták.",Programmatore? Ma chi te l'ha detto? Non c'è nessun Programmatore. Quella storia è stata diffusa un sacco di tempo fa. Non dirmi che il Fronte ha creduto a queste scempiaggini. Che idioti.,"プログラマー?誰ガそんなことヲ言った? ここにプログラマーハいない。 その噂ハ何年も前ニ広まったものダ。 そんな下らない事ヲ未だニ信じていたとは。 白痴モいいとこだ。","프로그래머? 누가 알려준 거야? 프로그래머 따위는 존재하지 않아. 이 소문이 몇 년 동안 계속 퍼졌다는 게 믿기지 않아. 프론트도 그 잡소문을 아직도 믿고 있던 모양이었고. 한심하네. - \cy여기가 아닌가 봐. 다른 곳을 찾아봐야겠어.",Programmeur? Wie heeft je dat verteld? Er is geen programmeur. Dat verhaal is eeuwen geleden verspreid. Vertel me niet dat het Front die onzin echt geloofde. Idioten.,"Programista? Kto ci to powiedział? Nie ma żadnego Programisty. Ta historia została wymyślona wiele lat temu. Tylko mi nie mów, że Front wierzy w te bzdury. Idioci.",Programador? Quem te disse isso? Não existe nenhum Programador. Essa história anda se espalhando desde muito tempo. Não me diga que a Frente acreditou mesmo nessa bobagem. Otários.,,,"Программист? Кто тебе это сказал? Нет никакого программиста. Этой байке уже сто лет. Только не говори мне, что Сопротивление и правда поверило в эту чушь. Идиоты.", -"Well, what's the truth then?",TXT_RPLY0_SCRIPT07_D6064_WELLW,,,,Pravda je tedy kde?,"Nun, was ist denn die Wahrheit?",,,"Bien, ¿Cuál es la verdad entonces?",,,"Quelle est la vérité, alors?",,,それなら、本当の事は何だ?,"그럼, 진실이 뭐야?","Nou, wat is de waarheid dan?",Więc co jest prawdą?,"Bem, qual é a verdade?",,,"Ладно, и что же тогда правда?", -I told you all I know. You are wasting your time.,TXT_DLG_SCRIPT07_D7580_ITOLD,,,,"Řekl jsem ti vše, co vím. Ztrácíš tu čas.","Ich habe alles gesagt, was ich weiß. Du verschwendest deine Zeit.",,,Te he dicho todo lo que sé. Estás perdiendo el tiempo.,,,Je t'ai dit tous ce que je sais. Tu perds ton temps.,,,"私ハ知っていることヲ教えた。 -これ以上ハ互いニ時間ノ無駄ダ。",다 알려줬어. 시간 낭비하지 마.,Ik heb je alles verteld wat ik weet. Je verspilt je tijd.,Powiedziałem ci wszystko co wiem. Marnujesz swój czas.,Eu já contei tudo o que eu sei. Você está perdendo tempo.,,,"Я рассказал всё, что знаю. Ты попусту тратишь время.", -"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D9096_FIGHT,,,,"Bojuj dál, my zvítězíme! Dnešek bude patřit nám!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,,"Luchad, triunfaremos. ¡Este día nos pertenece!",Luchemos y triunfaremos. ¡Este día nos pertenece!,,"Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",,,"我々は勝利を志し、戦う。 -この日は我々と共に在る!","같이 싸우자! 우리들이 이길 거고, 밝은 날이 찾아올 거야!","Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,,"Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!", -"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D10612_FIGHT,,,,"Bojuj dál, my zvítězíme! Dnešek bude patřit nám!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,,"Luchad, triunfaremos. ¡Este día nos pertenece!",Luchemos y triunfaremos. ¡Este día nos pertenece!,,"Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",,,"我々は勝利を志し、戦う。 -この日は我々と共に在る!",오늘이야말로 결전의 시간이야. 우리들이 바랬던 날을 위해!!,"Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,,"Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!", -"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D12128_FIGHT,,,,"Bojuj dál, my zvítězíme! Dnešek bude patřit nám!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,,"Luchad, triunfaremos. ¡Este día nos pertenece!",Luchemos y triunfaremos. ¡Este día nos pertenece!,,"Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",,,"我々は勝利を志し、戦う。 -この日は我々と共に在る!","우리들 중 한 명이 죽는다 해도, 승리는 확신해. 잃을 게 없어!","Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,,"Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!", -"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D13644_FIGHT,,,,"Bojuj dál, my zvítězíme! Dnešek bude patřit nám!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,,"Luchad, triunfaremos. ¡Este día nos pertenece!",Luchemos y triunfaremos. ¡Este día nos pertenece!,,"Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",,,"我々は勝利を志し、戦う。 -この日は我々と共に在る!","오더에 패배와 몰락을, 프론트에 인류와 영원한 자유를!","Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,,"Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!", -"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D15160_FIGHT,,,,"Bojuj dál, my zvítězíme! Dnešek bude patřit nám!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,,"Luchad, triunfaremos. ¡Este día nos pertenece!",Luchemos y triunfaremos. ¡Este día nos pertenece!,,"Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",,,"我々は勝利を志し、戦う。 -この日は我々と共に在る!",희망 한가닥 작전을 위해! 오더여! 내가 돌아왔다!!,"Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,,"Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!", -"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D16676_FIGHT,,,,"Bojuj dál, my zvítězíme! Dnešek bude patřit nám!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,,"Luchad, triunfaremos. ¡Este día nos pertenece!",Luchemos y triunfaremos. ¡Este día nos pertenece!,,"Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",,,"我々は勝利を志し、戦う。 -この日は我々と共に在る!","슬프지만, 이 것은 전쟁이잖아.","Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,,"Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!", -"You killed all the guards. Don't hurt me. I told him this was a dumb idea. The real Programmer's in the keep. Here, take this key.",TXT_DLG_SCRIPT08_D0_YOUKI,,,,"Tys zabil všechny stráže! Neubližuj mi. Já mu říkal, že to je hloupý nápad. Skutečný Programátor je v pevnosti. Tady, vem si tenhle klíč.","Du hast alle Wächter getötet. Bitte tu mir nichts. Ich habe ihm gesagt, es wäre eine dumme Idee. Der Programmierer ist in seiner Unterkunft. Hier nimm diesen Schlüssel.",,,"Has matado a todos los guardias. No me hagas daño. Le dije que era una idea estúpida. El verdadero Programador está en el torreón. Ten, toma esta llave.","Has matado a todos los guardias. No me hagas daño. Le dije que era una idea estúpida. El verdadero Programador está en la torre. Ten, toma esta llave.",,Vous avez tué tous les gardes. Ne me faites pas de mal. Je lui ai dit que c'était une idée stupide. Le vrai Programmeur se trouve dans le donjon. Prenez cette clé.,,,"君がガードを全員殺したノカ。 + \cy여기가 아닌가 봐. 다른 곳을 찾아봐야겠어.",Programmeur? Wie heeft je dat verteld? Er is geen programmeur. Dat verhaal is eeuwen geleden verspreid. Vertel me niet dat het Front die onzin echt geloofde. Idioten.,Programmerer? Hvem har sagt det? Det finnes ingen programmerer. Den historien ble spredt for lenge siden. Ikke fortell meg at Fronten faktisk trodde på den dritten. Idioter.,"Programista? Kto ci to powiedział? Nie ma żadnego Programisty. Ta historia została wymyślona wiele lat temu. Tylko mi nie mów, że Front wierzy w te bzdury. Idioci.",Programador? Quem te disse isso? Não existe nenhum Programador. Essa história anda se espalhando desde muito tempo. Não me diga que a Frente acreditou mesmo nessa bobagem. Otários.,,Programator? Cine ți-a spus asta? Nu e niciun Programator. Povestea asta a fost răspândită acum multă vreme. Nu-mi spune că Frontul chiar a crezut prostia asta. Idioți.,"Программист? Кто тебе это сказал? Нет никакого программиста. Этой байке уже сто лет. Только не говори мне, что Сопротивление и правда поверило в эту чушь. Идиоты.",,Programmerare? Vem har sagt det? Det finns ingen programmerare. Den historien spreds för länge sedan. Säg inte att fronten verkligen trodde på den skiten. Idioter.,Programcı mı? Bunu sana kim söyledi? Programcı diye biri yok. Bu hikaye yıllar önce yayıldı. Bana Cephe'nin bu saçmalığa gerçekten inandığını söyleme. Aptallar. +"Well, what's the truth then?",TXT_RPLY0_SCRIPT07_D6064_WELLW,〃,,,Kde je tedy pravda?,"Nå, hvad er sandheden så?","Nun, was ist denn die Wahrheit?",,"Tiuokaze, kiu estas la vero?",¿Entonces cuál es la verdad?,,"No, mikä totuus sitten on?","Quelle est la vérité, alors?","Nos, mi az igazság akkor?",E allora qual'è la verità?,それなら、本当の事は何だ?,"그럼, 진실이 뭐야?","Nou, wat is de waarheid dan?","Hva er sannheten, da?",Więc co jest prawdą?,"Bem, qual é a verdade?",,"Păi, care e adevărul atunci?","Ладно, и что же тогда правда?",,Vad är sanningen då?,"Peki, gerçek ne o zaman?" +I told you all I know. You are wasting your time.,TXT_DLG_SCRIPT07_D7580_ITOLD,〃,,,"Řekl jsem ti vše, co vím. Ztrácíš tu čas.","Jeg har fortalt dig alt, hvad jeg ved. Du spilder din tid.","Ich habe alles gesagt, was ich weiß. Du verschwendest deine Zeit.",,"Mi diris ĉion, kion mi scias. Vi perdas tempon.",Te he dicho todo lo que sé. Estás perdiendo el tiempo.,Ya te dije todo lo que sé. Estás perdiendo el tiempo.,"Minä kerroin jo kaiken, mitä tiedän. Tuhlaat aikaasi.",Je t'ai dit tous ce que je sais. Tu perds ton temps.,"Elmondtam mindent, amit tudtam. Csak az idődet vesztegeted.",Ti ho detto tutto quello che so. Stai sprecando il tuo tempo.,"私ハ知っていることヲ教えた。 +これ以上ハ互いニ時間ノ無駄ダ。",다 알려줬어. 시간 낭비하지 마.,Ik heb je alles verteld wat ik weet. Je verspilt je tijd.,Jeg har sagt alt jeg vet. Dere kaster bort tiden deres.,Powiedziałem ci wszystko co wiem. Marnujesz swój czas.,Eu já contei tudo o que eu sei. Você está perdendo tempo.,,"Ți-am spus tot ce știu, îți pierzi vremea.","Я рассказал всё, что знаю. Ты попусту тратишь время.",,Jag har berättat allt jag vet. Du slösar bort din tid.,Size tüm bildiklerimi anlattım. Zamanınızı boşa harcıyorsunuz. +"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D9096_FIGHT,MAP07: Font soldier.,,,"Bojuj dál, však my zvítězíme! Dnešek bude patřit nám!","Kæmp videre, vi vil triumfere. Denne dag vil tilhøre os!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,La batalo daŭru; ni venkos. Ĉi tiu tago estas nia!,"A seguir peleando, que hoy vamos a triunfar. ¡Este día es nuestro!",,"Jatkakaa taistoa, voitto on meidän. Tämä päivä kuuluu meille!","Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",Előre a győzelembe! Mi leszünk a nap győztesei!,"Continuate a combattere, trionferemo. Questo è il nostro giorno!","我々は勝利を志し、戦う。 +この日は我々と共に在る!","같이 싸우자! 우리들이 이길 거고, 밝은 날이 찾아올 거야!","Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Kjemp videre, vi vil seire. Denne dagen vil tilhøre oss!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,"Continuă lupta, vom triumfa. Ziua asta ne aparține!","Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!",,"Kämpa vidare, vi kommer att triumfera. Den här dagen kommer att tillhöra oss!","Savaşmaya devam edin, zafere ulaşacağız. Bu gün bize ait olacak!" +"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D10612_FIGHT,〃,,,"Bojuj dál, však my zvítězíme! Dnešek bude patřit nám!","Kæmp videre, vi vil triumfere. Denne dag vil tilhøre os!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,La batalo daŭru; ni venkos. Ĉi tiu tago estas nia!,"A seguir peleando, que hoy vamos a triunfar. ¡Este día es nuestro!",,"Jatkakaa taistoa, voitto on meidän. Tämä päivä kuuluu meille!","Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",Előre a győzelembe! Mi leszünk a nap győztesei!,"Continuate a combattere, trionferemo. Questo è il nostro giorno!","我々は勝利を志し、戦う。 +この日は我々と共に在る!",오늘이야말로 결전의 시간이야. 우리들이 바랬던 날을 위해!!,"Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Kjemp videre, vi vil seire. Denne dagen vil tilhøre oss!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,"Continuă lupta, vom triumfa. Ziua asta ne aparține!","Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!",,"Kämpa vidare, vi kommer att triumfera. Den här dagen kommer att tillhöra oss!","Savaşmaya devam edin, zafere ulaşacağız. Bu gün bize ait olacak!" +"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D12128_FIGHT,〃,,,"Bojuj dál, však my zvítězíme! Dnešek bude patřit nám!","Kæmp videre, vi vil triumfere. Denne dag vil tilhøre os!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,La batalo daŭru; ni venkos. Ĉi tiu tago estas nia!,"A seguir peleando, que hoy vamos a triunfar. ¡Este día es nuestro!",,"Jatkakaa taistoa, voitto on meidän. Tämä päivä kuuluu meille!","Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",Előre a győzelembe! Mi leszünk a nap győztesei!,"Continuate a combattere, trionferemo. Questo è il nostro giorno!","我々は勝利を志し、戦う。 +この日は我々と共に在る!","우리들 중 한 명이 죽는다 해도, 승리는 확신해. 잃을 게 없어!","Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Kjemp videre, vi vil seire. Denne dagen vil tilhøre oss!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,"Continuă lupta, vom triumfa. Ziua asta ne aparține!","Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!",,"Kämpa vidare, vi kommer att triumfera. Den här dagen kommer att tillhöra oss!","Savaşmaya devam edin, zafere ulaşacağız. Bu gün bize ait olacak!" +"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D13644_FIGHT,〃,,,"Bojuj dál, však my zvítězíme! Dnešek bude patřit nám!","Kæmp videre, vi vil triumfere. Denne dag vil tilhøre os!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,La batalo daŭru; ni venkos. Ĉi tiu tago estas nia!,"A seguir peleando, que hoy vamos a triunfar. ¡Este día es nuestro!",,"Jatkakaa taistoa, voitto on meidän. Tämä päivä kuuluu meille!","Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",Előre a győzelembe! Mi leszünk a nap győztesei!,"Continuate a combattere, trionferemo. Questo è il nostro giorno!","我々は勝利を志し、戦う。 +この日は我々と共に在る!","오더에 패배와 몰락을, 프론트에 인류와 영원한 자유를!","Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Kjemp videre, vi vil seire. Denne dagen vil tilhøre oss!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,"Continuă lupta, vom triumfa. Ziua asta ne aparține!","Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!",,"Kämpa vidare, vi kommer att triumfera. Den här dagen kommer att tillhöra oss!","Savaşmaya devam edin, zafere ulaşacağız. Bu gün bize ait olacak!" +"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D15160_FIGHT,〃,,,"Bojuj dál, však my zvítězíme! Dnešek bude patřit nám!","Kæmp videre, vi vil triumfere. Denne dag vil tilhøre os!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,La batalo daŭru; ni venkos. Ĉi tiu tago estas nia!,"A seguir peleando, que hoy vamos a triunfar. ¡Este día es nuestro!",,"Jatkakaa taistoa, voitto on meidän. Tämä päivä kuuluu meille!","Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",Előre a győzelembe! Mi leszünk a nap győztesei!,"Continuate a combattere, trionferemo. Questo è il nostro giorno!","我々は勝利を志し、戦う。 +この日は我々と共に在る!",희망 한가닥 작전을 위해! 오더여! 내가 돌아왔다!!,"Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Kjemp videre, vi vil seire. Denne dagen vil tilhøre oss!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,"Continuă lupta, vom triumfa. Ziua asta ne aparține!","Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!",,"Kämpa vidare, vi kommer att triumfera. Den här dagen kommer att tillhöra oss!","Savaşmaya devam edin, zafere ulaşacağız. Bu gün bize ait olacak!" +"Fight on, we will triumph. This day will belong to us!",TXT_DLG_SCRIPT07_D16676_FIGHT,〃,,,"Bojuj dál, však my zvítězíme! Dnešek bude patřit nám!","Kæmp videre, vi vil triumfere. Denne dag vil tilhøre os!","Lass uns kämpfen, wir werden gewinnen. Dieser Tag gehört uns!",,La batalo daŭru; ni venkos. Ĉi tiu tago estas nia!,"A seguir peleando, que hoy vamos a triunfar. ¡Este día es nuestro!",,"Jatkakaa taistoa, voitto on meidän. Tämä päivä kuuluu meille!","Continuez à vous battre, nous allons triompher! Ce jour nous appartient!",Előre a győzelembe! Mi leszünk a nap győztesei!,"Continuate a combattere, trionferemo. Questo è il nostro giorno!","我々は勝利を志し、戦う。 +この日は我々と共に在る!","슬프지만, 이 것은 전쟁이잖아.","Vecht verder, we zullen zegevieren. Deze dag zal van ons zijn!","Kjemp videre, vi vil seire. Denne dagen vil tilhøre oss!","Walcz dalej, i tak zwyciężymy. Dzień należy do nas!","Continue lutando, nós iremos triunfar. Este dia pertence a nós!",,"Continuă lupta, vom triumfa. Ziua asta ne aparține!","Сражайся, и нас ждёт триумф. Сегодняшний день будет нашим!",,"Kämpa vidare, vi kommer att triumfera. Den här dagen kommer att tillhöra oss!","Savaşmaya devam edin, zafere ulaşacağız. Bu gün bize ait olacak!" +"You killed all the guards. Don't hurt me. I told him this was a dumb idea. The real Programmer's in the keep. Here, take this key.",TXT_DLG_SCRIPT08_D0_YOUKI,MAP08: Northeast room.,,,"Tys zabil všechny stráže! Neubližuj mi. Já mu říkal, že to je hloupý nápad. Skutečný Programátor je v pevnosti. Tady, vem si tenhle klíč.","Du dræbte alle vagterne. Gør mig ikke noget. Jeg sagde til ham, at det var en dum idé. Den rigtige programmør er i tårnet. Her, tag denne nøgle.","Du hast alle Wächter getötet. Bitte tu mir nichts. Ich habe ihm gesagt, es wäre eine dumme Idee. Der Programmierer ist in seiner Unterkunft. Hier nimm diesen Schlüssel.",,"Vi mortigis ĉiujn gardistojn. Ne vundu min. Mi diris al li, ke ĉi tiu estas stulta ideo; la vera Programisto estas en la ĉefturo. Jen la ŝlosilo.","Has matado a todos los guardias. No me hagas nada. Le dije que era una idea estúpida; el verdadero Programador está en el torreón. Ten, toma esta llave.","Mataste a todos los guardias. No me hagas nada. Le dije que era una idea estúpida; el verdadero Programador está en el torreón. Ten, toma esta llave.","Tapoit kaikki vartijat. Älä satuta minua. Sanoin hänelle, että tämä oli tyhmä idea. Oikea Ohjelmoitsija on linnakkeessa. Tässä, ota tämä avain.",Vous avez tué tous les gardes. Ne me faites pas de mal. Je lui ai dit que c'était une idée stupide. Le vrai Programmeur se trouve dans le donjon. Prenez cette clé.,"Te ölted meg az összes őrt. Kérlek ne bánts. Én megmondtam, hogy ez egy rossz ötlet. Az igazi Programozó a vártoronyban van. Vidd ezt a kulcsot.","Hai ucciso tutte le guardie. Ho cercato di fargli capire che era un'idea stupida. Il vero Programmatore è nella fortezza. Ecco, prendi questa chiave.","君がガードを全員殺したノカ。 私ハ傷つけないでくれ。 私ハ望んでこんなふざけた事をしたワケではない。 本当のプログラマーはこのキーの場所ニいる。 -ほら、受け取れ。",경비들을 모조리 죽이시다니! 해치지 말아주세요. 제가 그분께 어리석은 짓이라고 제안을 했었는데... 진짜 프로그래머님은 성채에 있습니다. 이 열쇠를 쓰세요.,"Je hebt alle bewakers gedood. Doe me geen pijn. Ik zei hem dat dit een dom idee was. De echte programmeur is in de donjon. Hier, pak deze sleutel.","Zabiłeś wszystkich strażników. Nie krzywdź mnie. Mówiłem mu, że to głupi pomysł. Prawdziwy Programista jest w twierdzy. Masz, weź ten klucz.","Você matou todos os guardas. Não me machuque. Eu disse a ele que isso era uma idéia besta. O verdadeiro Programador está na fortaleza. Aqui, pegue esta chave.",,,"Ты убил всех стражников. Не трогай меня! Я говорил ему, что это глупая идея. Настоящий Программист в цитадели. Вот, возьми этот ключ.", -You're the Programmer!,TXT_RPLY0_SCRIPT08_D0_YOURE,,,,Ty jsi Programátor!,Du bist der Programmierer!,,,¡Tú eres el Programador!,,,Vous êtes le Programmeur!,,,アンタがプログラマーだろ!,넌 프로그래머잖아!,Jij bent de programmeur!,To ty jesteś Programistą!,Você é o Programador!,,,Ты программист!, -"Do I look like I wield ultimate power? The Order uses us all. Now go, I'm dead already.",TXT_DLG_SCRIPT08_D1516_DOILO,,,,"Vypadám snad jako bych se měl pyšnit nesmírnou mocí? Řád nás všechny využívá. Teď jdi, já jsem už teď mrtvý.","Sehe ich so aus, als ob ich unendliche Macht hätte? Der Orden benutzt uns alle. Nun geh, ich bin ohnehin schon tot.",,,"¿Te parece que posea el poder absoluto? La Orden nos usa a todos. Ahora ve, yo ya estoy muerto.","¿Te parece que posea el poder absoluto? La Orden nos usa a todos. Vete, yo ya estoy muerto.",,"Est-ce que j'ai l'air d'avoir le pouvoir suprême? L'Ordre nous utilise tous. Partez, je suis déjà mort.",,,"私ガそんな凄まじい力ヲ振舞っていると思うか? +ほら、受け取れ。",경비들을 모조리 죽이시다니! 해치지 말아주세요. 제가 그분께 어리석은 짓이라고 제안을 했었는데... 진짜 프로그래머님은 성채에 있습니다. 이 열쇠를 쓰세요.,"Je hebt alle bewakers gedood. Doe me geen pijn. Ik zei hem dat dit een dom idee was. De echte programmeur is in de donjon. Hier, pak deze sleutel.","Du drepte alle vaktene. Ikke gjør meg noe. Jeg sa at dette var en dum idé. Den virkelige programmereren er i borgen. Her, ta denne nøkkelen.","Zabiłeś wszystkich strażników. Nie krzywdź mnie. Mówiłem mu, że to głupi pomysł. Prawdziwy Programista jest w twierdzy. Masz, weź ten klucz.","Você matou todos os guardas. Não me machuque. Eu disse a ele que isso era uma idéia besta. O verdadeiro Programador está na fortaleza. Aqui, pegue esta chave.",,Ai omorât toți gardienii. Nu mă rănii. I-am spus că e o idee proastă. Adevăratul Programator e înăuntru. Ia cheia asta.,"Ты убил всех стражников. Не трогай меня! Я говорил ему, что это глупая идея. Настоящий Программист в цитадели. Вот, возьми этот ключ.",,"Du dödade alla vakter. Gör mig inte illa. Jag sa till honom att detta var en dum idé. Den riktiga programmeraren är i fängelset. Här, ta den här nyckeln.","Bütün muhafızları öldürdün. Bana zarar vermeyin. Ona bunun aptalca bir fikir olduğunu söyledim. Gerçek Programcı kalede. İşte, al şu anahtarı." +You're the Programmer!,TXT_RPLY0_SCRIPT08_D0_YOURE,〃,,,Ty jsi Programátor!,"Det er dig, der er programmøren!",Du bist der Programmierer!,,Vi estas la Programisto!,¡Tú eres el Programador!,,Sinä olet Ohjelmoitsija!,Vous êtes le Programmeur!,Te vagy a Programozó!,Sei tu il Programmatore!,アンタがプログラマーだろ!,넌 프로그래머잖아!,Jij bent de programmeur!,Du er programmereren!,To ty jesteś Programistą!,Você é o Programador!,,Tu ești Programatorul!,Ты Программист!,,Du är programmeraren!,Programcı sensin! +"Do I look like I wield ultimate power? The Order uses us all. Now go, I'm dead already.",TXT_DLG_SCRIPT08_D1516_DOILO,〃,,,"Vypadám snad jako bych se měl pyšnit nesmírnou mocí? Řád nás všechny využívá. Teď jdi, já jsem už teď mrtvý.","Ser jeg ud, som om jeg udøver den ultimative magt? Ordenen bruger os alle. Gå nu, jeg er allerede død.","Sehe ich so aus, als ob ich unendliche Macht hätte? Der Orden benutzt uns alle. Nun geh, ich bin ohnehin schon tot.",,"Ĉu mi aspektas kiel posedanto de absoluta povo? La Ordeno uzas nin ĉiujn. Foriru, mi jam estas mortinta.","¿Te parezco poseer el poder absoluto? La Orden nos usa a todos. Ya vete, que yo ya estoy muerto.",,"Näytänkö muka sellaiselta, joka pitää hallussaan täyttä valtaa? Veljeskunta käyttää hyväkseen meitä kaikkia. Mene, olen jo yhtä kuin kuollut.","Est-ce que j'ai l'air d'avoir le pouvoir suprême? L'Ordre nous utilise tous. Partez, je suis déjà mort.","Úgy nézek ki, mint aki mindenki felett erőt gyakorol? A Rend kihasznál mindannyiunkat. Menj tovább, Én már amúgyis halott vagyok.","Davvero ti sembro uno che possiede poteri sovrumani? L'Ordine ci usa tutti. Adesso vai, tanto io sono spacciato ormai.","私ガそんな凄まじい力ヲ振舞っていると思うか? オーダーハ私達全員を利用している。 -私ハもう死人同然だ。さあ行け。","제가 신적인 힘을 갖고 있다고 생각하나요? 오더는 어차피 모두를 부려먹습니다. 떠나세요, 전 이미 죽은 목숨이에요.","Zie ik eruit alsof ik de ultieme macht heb? De Orde gebruikt ons allemaal. Ga nu, ik ben al dood.","Czy wyglądam jakbym był we władaniu niesamowitej mocy? Zakon wykorzystuje nas wszystkich. Idź stąd, i tak już jestem martwy.",Você acha que eu pareço alguém que possui um poder tremendo? A Ordem manipula a todos nós. Agora vá. Eu já estou morto.,,,Разве я похож на обладателя невероятной мощи? Орден использует нас всех. Теперь иди. Я уже всё равно мёртв., -Power is the key!,TXT_DLG_SCRIPT08_D3032_POWER,,,,Moc je tím klíčem!,Macht ist der Schlüssel!,,,¡El poder es la clave!,,,Le pouvoir est la clé!,,,キーが力だ!,힘이 곧 열쇠다!,Kracht is de sleutel!,Moc jest kluczem!,O poder é a chave!,,,В силе — всё!, -"Good, you're conscious again. When you grabbed that item the Programmer dropped you let loose some terrible secrets.",TXT_DLG_SCRIPT10_D0_GOODY,,,,"Už jsi vzhůru, dobře. Když jsi sebral tu věc, kterou Programátor upustil, odhalil jsi děsivá tajemství.","Gut, du bist wieder wach. Als du das Ding, das der Programmierer fallengelassen hat, packtest, hast du einige schlimme Geheimnisse enthüllt.",,,"Bien, vuelves a estar consciente. Cuando agarraste ese objeto que el Programador soltó has dejado sueltos algunos secretos terribles.",,,"Bien. Vous êtes conscient. Quand vous avez pris ceci au Programmeur, vous avez libéré de terrible secrets.",,,"良し、意識が戻ったか。 +私ハもう死人同然だ。さあ行け。","제가 신적인 힘을 갖고 있다고 생각하나요? 오더는 어차피 모두를 부려먹습니다. 떠나세요, 전 이미 죽은 목숨이에요.","Zie ik eruit alsof ik de ultieme macht heb? De Orde gebruikt ons allemaal. Ga nu, ik ben al dood.","Ser jeg ut som om jeg har den ultimate makten? Ordenen bruker oss alle. Gå nå, jeg er allerede død.","Czy wyglądam jakbym był we władaniu niesamowitej mocy? Zakon wykorzystuje nas wszystkich. Idź stąd, i tak już jestem martwy.",Você acha que eu pareço alguém que possui um poder tremendo? A Ordem manipula a todos nós. Agora vá. Eu já estou morto.,,"Ți se pare că controlez puterea supremă? Ordinul ne folosește pe toți. Acum pleacă, sunt mort deja.",Разве я похож на обладателя невероятной мощи? Орден использует нас всех. Теперь иди. Я уже всё равно мёртв.,,"Ser jag ut som om jag har den ultimata makten? Orden använder oss alla. Gå nu, jag är redan död.","Nihai güce sahipmişim gibi mi görünüyorum? Tarikat hepimizi kullanır. Şimdi git, ben zaten ölüyüm." +Power is the key!,TXT_DLG_SCRIPT08_D3032_POWER,,,,Moc je tím klíčem!,Magt er nøglen!,Macht ist der Schlüssel!,,Povo estas la ŝlosilo!,¡El poder es la clave!,,Valta on avain!,Le pouvoir est la clé!,Az erő a kulcs!,Il potere è la chiave!,キーが力だ!,힘이 곧 열쇠다!,Kracht is de sleutel!,Makt er nøkkelen!,Moc jest kluczem!,O poder é a chave!,,Puterea e cheia!,В силе — всё!,,Makt är nyckeln!,Güç anahtardır! +"Good, you're conscious again. When you grabbed that item the Programmer dropped, you let loose some terrible secrets.",TXT_DLG_SCRIPT10_D0_GOODY,MAP10: Macil.,,,"Už jsi vzhůru, dobře. Když jsi sebral tu věc, kterou Programátor upustil, odhalil jsi děsivá tajemství.","Godt, du er ved bevidsthed igen. Da du greb den genstand, som programmøren tabte, slap du nogle frygtelige hemmeligheder løs.","Gut, du bist wieder wach. Als du das Ding, das der Programmierer fallengelassen hat, packtest, hast du einige schlimme Geheimnisse enthüllt.",,"Bone, vi jam rekonsciiĝis. Kelkaj teruraj sekretoj malkovriĝis kiam vi prenis tiun objekton, kiu elfalis el la Programisto.","Bien, ya has despertado. Se han revelado un par de secretos terribles en cuanto has cogido el objeto ese que se le ha caído al Programador.","Bien, ya despertaste. Se revelaron un par de secretos terribles en cuanto agarraste el objeto ese que se le cayó al Programador.","Hyvä, olet jälleen tajuissasi. Kaapattuasi esineen, jonka Ohjelmoitsija oli pudottanut, toit valoon kauhistuttavia salaisuuksia.","Bien. Vous êtes conscient. Quand vous avez pris ceci au Programmeur, vous avez libéré de terrible secrets.","Remek, magadhoz tértél. Amikor megmarkoltad a tárgyat amit a Programozó elejtett, elég sok titokra fény derült.","Meno male, sei di nuovo conscio. Quando hai preso quell'oggetto dal Programmatore, hai scoperchiato dei terribili segreti.","良し、意識が戻ったか。 君がプログラマーの遺品を拾った時に -恐ろしい秘密が解放されたのだ。","아, 드디어 깨어났군요. 프로그래머가 죽고 나서 얻은 저 물건을 쥐는 동안 우리는 그것에 대한 끔찍한 비밀을 밝혀냈습니다...","Goed, je bent weer bij bewustzijn. Toen je dat item pakte, liet de programmeur je een aantal vreselijke geheimen los.","Dobrze, znów jesteś przytomny. Kiedy podniosłeś ten przedmiot, który upuścił Programista, uwolnniłeś wiele strasznych sekretów.","Ótimo, já está consciente de novo. Quando você pegou o item que o Programador largou você deixou escapar alguns segredos terríveis.",,,"Хорошо, ты пришёл в себя. Взяв в руки артефакт, который выронил Программист, ты раскрыл страшные тайны.", -What kind of secrets. ,TXT_RPLY0_SCRIPT10_D0_WHATK,,,,Jaká tajemství?,Was für Geheimnisse?,,,¿Qué clase de secretos?,,,De quels secrets parlez-vous?,,,その秘密とは。,어떤 비밀인가요?,Wat voor geheimen.,Jakich sekretów?,Que tipos de segredos?,,,Какие тайны?, -"We have no idea where this weapon came from, but we must find out. You have wrested one from the Order, but we must have all five. We have reached the limits of my knowledge. Seek out the Oracle and ask it for help.",TXT_DLG_SCRIPT10_D1516_WEHAV,,,,"Nemáme tušení, odkud se tato zbraň vzala, ale musíme to zjistit. Jednu část jsi z rukou Řádu už umanul, ale musíme najít všech pět. Dosáhli jsme hranic mých vědomostí. Vyhledej Věštce a požádej jej o pomoc.","Wir haben keine Ahnung, wo diese Waffe herkommt, aber wir müssen es herausfinden. Du hast ein Teil dem Orden entrungen aber wir brauchen alle fünf. Wir haben die Grenzen meines Wissens erreicht. Suche das Orakel und frage es um Hilfe.",,,"No sabemos de donde ha venido esta arma, pero debemos averiguarlo. Has arrebatado una de la Orden, pero debemos tener las cinco. Hemos alcanzado el límite de mis conocimientos. Busca al Oráculo y pídele ayuda.",,,"Je n'ai aucune idée d'où vient cette arme, mais il faut que nous le découvrions. Vous en avez arraché une à l'Ordre, mais il faut trouver toutes les cinq. C'est tout ce que je sais pour l'instant. Allez voir l'Oracle et demandez son aide.",,,"この武器が何処で造られたかは分からないが、 +恐ろしい秘密が解放されたのだ。","아, 드디어 깨어났군요. 프로그래머가 죽고 나서 얻은 저 물건을 쥐는 동안 우리는 그것에 대한 끔찍한 비밀을 밝혀냈습니다...","Goed, je bent weer bij bewustzijn. Toen je dat item pakte, liet de programmeur je een aantal vreselijke geheimen los.","Bra, du er ved bevissthet igjen. Da du tok den gjenstanden programmereren mistet, slapp du løs noen forferdelige hemmeligheter.","Dobrze, znów jesteś przytomny. Kiedy podniosłeś ten przedmiot, który upuścił Programista, uwolnniłeś wiele strasznych sekretów.","Ótimo, já está consciente de novo. Quando você pegou o item que o Programador largou você deixou escapar alguns segredos terríveis.",,"Bun, ești conștient din nou. Când ai pus mâna pe obiectul ăla Programatorul ți-a dat drumul ca să elibereze niște secrete oribile.","Хорошо, ты пришёл в себя. Взяв в руки артефакт, который выронил Программист, ты раскрыл страшные тайны.",,"Bra, du är vid medvetande igen. När du tog tag i föremålet som programmeraren tappade släppte du lös några hemska hemligheter.","Güzel, tekrar kendine geldin. Programcı'nın düşürdüğü o eşyayı aldığında, bazı korkunç sırları açığa çıkardın." +What kind of secrets. ,TXT_RPLY0_SCRIPT10_D0_WHATK,〃,,,Jaká tajemství?,Hvilken slags hemmeligheder?,Was für Geheimnisse?,,Kiaj sekretoj?,¿Qué clase de secretos?,,Minkälaisia salaisuuksia?,De quels secrets parlez-vous?,Miféle titkok?,Che tipo di segreti.,その秘密とは。,어떤 비밀인가요?,Wat voor geheimen.,Hva slags hemmeligheter?,Jakich sekretów?,Que tipos de segredos?,,Ce fel de secrete?,Какие тайны?,,Vad för slags hemligheter.,Ne tür sırlar? +"We have no idea where this weapon came from, but we must find out. You have wrested one from the Order, but we must have all five. We have reached the limits of my knowledge. Seek out the Oracle and ask it for help.",TXT_DLG_SCRIPT10_D1516_WEHAV,〃,,,"Nemáme tušení, odkud se tato zbraň vzala, ale musíme to zjistit. Jednu část jsi z rukou Řádu už umanul, ale musíme najít všech pět. Dosáhli jsme hranic mých vědomostí. Vyhledej Věštce a požádej jej o pomoc.","Vi har ingen anelse om, hvor dette våben kommer fra, men vi må finde ud af det. Du har vristet en fra Ordenen, men vi skal have alle fem. Vi har nået grænserne for min viden. Opsøg Oraklet og bed det om hjælp.","Wir haben keine Ahnung, wo diese Waffe herkommt, aber wir müssen es herausfinden. Du hast ein Teil dem Orden entrungen aber wir brauchen alle fünf. Wir haben die Grenzen meines Wissens erreicht. Suche das Orakel und frage es um Hilfe.",,"Ni ne konas la originon de ĉi tiu armilo, sed ni devas malkovri ĝin. Vi jam prenis pecon el La Ordeno kaj ni bezonas la aliajn kvar. Ĝis ĉi tie ĉio, kion mi scias. Serĉu la Orakolon kaj petu lin pri helpo.","No sabemos de dónde habrá salido esta arma, pero hay que averiguarlo. Ya le has quitado una pieza a La Orden y nos estarían faltando las otras cuatro. Hasta ahí todo lo que sé. Busca al Oráculo y pídele ayuda.","No sabemos de dónde habrá salido esta arma, pero hay que averiguarlo. Ya le quitaste una pieza a La Orden y nos estarían faltando las otras cuatro. Hasta ahí todo lo que sé. Busca al Oráculo y pídele ayuda.","Meillä ei ole aavistustakaan tämän aseen alkuperästä, mutta se on selvitettävä. Olet nyt riistänyt Veljeskunnan käsistä yhden, mutta meidän on saatava kaikki viisi. Oma tietämykseni päättyy tähän. Etsi apua Oraakkelilta.","Je n'ai aucune idée d'où vient cette arme, mais il faut que nous le découvrions. Vous en avez arraché une à l'Ordre, mais il faut trouver toutes les cinq. C'est tout ce que je sais pour l'instant. Allez voir l'Oracle et demandez son aide.","Nem tudjuk mi ennek a fegyvernek az eredete, de ki kell derítenünk. Elcsentél egyet a Rendtől, de meg kell szereznünk mind az ötöt. Elértük a tudásom határát. Keresd fel az Orákulumot, és kérdd a segítségét.","Non abbiamo alcuna idea su dove quest'arma provenga, ma dobbiamo scoprirlo. Ne hai sottratto una all'Ordine, ma dobbiamo ottenerle tutte e cinque. E qui abbiamo raggiunto il limite della mia conoscienza. Devi raggiungere l'Oracolo e chiedergli aiuto.","この武器が何処で造られたかは分からないが、 我々はそれを突き止める必要がある様だ。 どうやら全部で5つあり、君はオーダーから 1つ手に入れている。我々の理解を超える存在だ -オラクルを探し何か情報を得なければ。","이 무기가 어디서 왔는지는 모르겠다만, 얼른 찾아내야만 합니다. 그 한 조각을 비롯한 나머지 '다섯' 조각도 필요합니다. 제가 알고 있는 건 이게 다입니다. 오라클이라는 자를 만나서 도움을 요청해보세요.","We hebben geen idee waar dit wapen vandaan komt, maar we moeten erachter komen. Je hebt er een uit de Orde weggehaald, maar we moeten ze alle vijf hebben. We hebben de grenzen van mijn kennis bereikt. Zoek het Orakel op en vraag het om hulp.","Nie mamy pojęcia skąd ta broń pochodzi, ale musimy się dowiedzieć. Wyrwałeś jedną z łap Zakonu, ale musimy zdobyć wszystkie pięć. Osiągnęliśmy szczyt tego co wiem. Poszukaj Wyroczni i poproś ją o pomoc.","Não fazemos idéia de onde esta arma veio, mas precisamos descobrir. Você conseguiu roubar um deles da Ordem, mas precisamos de todos os cinco. Já atingimos os limites do meu conhecimento. Procure o Oráculo e peça a ajuda dele.",,,"Мы понятия не имеем, откуда взялось это оружие, но обязаны выяснить. Ты отбил один фрагмент у Ордена, но нам нужны все пять. Я рассказал тебе всё, что знал. Найди Оракула и попроси его о помощи.", -I'm gonna need more supplies.,TXT_RPLY0_SCRIPT10_D1516_IMGON,,,,Budu potřebovat zásoby.,Ich brauche mehr Ausrüstung.,,,Voy a necesitar más suministros.,,,Il me faut de l'équipment.,,,それには補給がもっと必要だ。,물자가 좀 필요할 것 같은데.,Ik zal meer voorraden nodig hebben.,,Vou precisar de mais equipmento.,,,Мне потребуются ещё припасы., -"Here's some gold. Go visit the medic and the weapons trainer and then, move out!",TXT_DLG_SCRIPT10_D3032_HERES,,,,"Tady je nějaké zlato. Jdi navštívit zdravotníka a zbraňmistra, a pak odchod!",Hier ist etwas Gold. Geh zum Sanitäter und zum Waffentrainer und dann los!,,,"Aquí tienes algo de oro. Ve a ver al médico y al entrenador de armas y luego, ¡en marcha!",,,"Voilà de l'argent. Allez voir le médecin et le maître d'armes, puis partez!",,,"資金を提供しよう。 +オラクルを探し何か情報を得なければ。","이 무기가 어디서 왔는지는 모르겠다만, 얼른 찾아내야만 합니다. 그 한 조각을 비롯한 나머지 '다섯' 조각도 필요합니다. 제가 알고 있는 건 이게 다입니다. 오라클이라는 자를 만나서 도움을 요청해보세요.","We hebben geen idee waar dit wapen vandaan komt, maar we moeten erachter komen. Je hebt er een uit de Orde weggehaald, maar we moeten ze alle vijf hebben. We hebben de grenzen van mijn kennis bereikt. Zoek het Orakel op en vraag het om hulp.","Vi aner ikke hvor våpenet kom fra, men vi må finne det ut. Du har vristet ett fra Ordenen, men vi må ha alle fem. Vi har nådd grensen for min kunnskap. Oppsøk oraklet og be det om hjelp.","Nie mamy pojęcia skąd ta broń pochodzi, ale musimy się dowiedzieć. Wyrwałeś jedną z łap Zakonu, ale musimy zdobyć wszystkie pięć. Osiągnęliśmy szczyt tego co wiem. Poszukaj Wyroczni i poproś ją o pomoc.","Não fazemos idéia de onde esta arma veio, mas precisamos descobrir. Você conseguiu roubar um deles da Ordem, mas precisamos de todos os cinco. Já atingimos os limites do meu conhecimento. Procure o Oráculo e peça a ajuda dele.",,"Nu avem nicio idee în legătură cu proveniența armei, dar trebuie să aflăm. Ai luat una de la Ordin, dar avem nevoie de toate 5. Am ajuns la capătul cunoștiințelor mele. Mergi în căutarea Oracolului, și cere-i ajutorul.","Мы понятия не имеем, откуда взялось это оружие, но обязаны выяснить. Ты отбил один фрагмент у Ордена, но нам нужны все пять. Я рассказал тебе всё, что знал. Найди Оракула и попроси его о помощи.",,"Vi har ingen aning om var det här vapnet kom ifrån, men vi måste ta reda på det. Du har vridit en från Orden, men vi måste få alla fem. Vi har nått gränsen för min kunskap. Sök upp Oraklet och be det om hjälp.",Bu silahın nereden geldiğini bilmiyoruz ama öğrenmeliyiz. Tarikat'tan bir tane aldınız ama beşini de almalıyız. Bilgimin sınırlarına ulaştık. Kahin'i ara ve ondan yardım iste. +I'm gonna need more supplies.,TXT_RPLY0_SCRIPT10_D1516_IMGON,〃,,,Budu potřebovat zásoby.,Jeg får brug for flere forsyninger.,Ich brauche mehr Ausrüstung.,,Mi bezonos pliajn provizojn.,Voy a necesitar más suministros.,,Tarvitsen lisää varusteita.,Il me faut de l'équipment.,Szükségem lesz még felszerelésre.,Mi serviranno più provviste.,それには補給がもっと必要だ。,물자가 좀 필요할 것 같은데.,Ik zal meer voorraden nodig hebben.,Jeg trenger flere forsyninger.,Będę potrzebować więcej zaopatrzenia.,Vou precisar de mais equipmento.,,O să am nevoie de mai multe provizii.,Мне потребуются ещё припасы.,,Jag kommer att behöva mer förnödenheter.,Daha fazla malzemeye ihtiyacım olacak. +"Here's some gold. Go visit the medic and the weapons trainer and then, move out!",TXT_DLG_SCRIPT10_D3032_HERES,〃,,,"Tady je nějaké zlato. Jdi navštívit zdravotníka a zbraňmistra, a pak odchod!","Her er noget guld. Besøg lægen og våbentræneren, og så af sted!",Hier ist etwas Gold. Geh zum Sanitäter und zum Waffentrainer und dann los!,,"Jen iom da oro. Iru renkonti la kuraciston kaj la armilan trejniston, kaj tiam ekagu!","Aquí tienes algo de oro. Ve a ver al médico y al entrenador de armas y luego, ¡en marcha!",,"Tässä vähän kultaa. Tapaa lääkintämiestä ja asekouluttajaa, ja sen jälkeen lähde matkaan!","Voilà de l'argent. Allez voir le médecin et le maître d'armes, puis partez!","Itt van egy kis arany. Keresd fel a szanitécot és a fegyvermestert, aztán indulás!","Ecco dell'oro. Visita il dottore e l'istruttore d'armi, e poi, è tempo di muoversi!","資金を提供しよう。 そしてメディックと訓練士に会い装備を整えて、 -向かいたまえ!",골드를 좀 받으세요. 의무관이랑 무기 담당관을 찾아뵈시고 이동하시길!,Hier is wat goud. Ga naar de dokter en de wapentrainer en ga dan weg!,,Pegue este dinheiro. Vá ver o médico e o treinador de armas e depois parta para a missão.,,,"Вот немного золота. Посети медика и инструктора по стрельбе, и выдвигайся!", -Right!,TXT_RPLY0_SCRIPT10_D3032_RIGHT,,,,Ano!,Ja.,,,¡Claro!,,,Bien!,,,わかった!,네!,Juist!,,Certo!,,,Есть!, -Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT10_D4548_FIGHT,,,,Bojuj za Frontu a svobodu! Odchod.,Kämpfe für die Front und die Freiheit. Nun geh.,,,Lucha por el frente y la libertad. En marcha.,,,Battez vous pour le Front et pour la liberté. Repos.,,,フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het front en vrijheid. Verhuizen.,,Lute pela Frente e pela liberdade. Agora vá.,,,Сражайся за свободу и справедливость. Вперёд., -"What prompts your return? Are you hurt? There's no time to lose, continue with your mission. Complete the Sigil.",TXT_DLG_SCRIPT10_D6064_WHATP,,,,"Co přimělo tvůj návrát? Jsi zraněný? Není času nazbyt, pokračuj ve své misi. Dokonči Pečeť.","Warum kommst du zurück? Bist du verletzt? Wir haben keine Zeit zu verlieren, du musst deine Mission fortsetzen. Vervollständige das Sigil.",,,"¿A qué se debe tu retorno? ¿Estás herido? No hay tiempo que perder, continua con tu misión. Completa el Emblema.",,,"Qu'est ce qui vous amène? Vous avez mal? Il n'y a pas de temps à perdre. Continuez votre mission, complétez le Sigil.",,,"何が帰還を促した?怪我をしたのか? +向かいたまえ!",골드를 좀 받으세요. 의무관이랑 무기 담당관을 찾아뵈시고 이동하시길!,Hier is wat goud. Ga naar de dokter en de wapentrainer en ga dan weg!,"Her er litt gull. Gå til legen og våpentreneren, og så drar vi!","Masz tu trochę złota. Odwiedź medyka i trenera od broni, a potem wykonać!",Pegue este dinheiro. Vá ver o médico e o treinador de armas e depois parta para a missão.,,"Uite niște aur. Vizitează medicul și antrenorul de arme iar apoi, dă-i drumul!","Вот немного золота. Посети медика и инструктора по стрельбе, и выдвигайся!",,"Här är lite guld. Gå och besök läkaren och vapentränaren och sedan, sätt fart!",İşte biraz altın. Sıhhiyeciyi ve silah eğitmenini ziyaret et ve sonra yola çık! +Right!,TXT_RPLY0_SCRIPT10_D3032_RIGHT,〃,,,Ano!,Så går vi.,Ja.,,Kompreneble!,¡A la orden!,,Selvä!,Bien!,Igenis!,Sarà fatto!,わかった!,네!,Juist!,Skal bli!,Dobrze!,Certo!,,Într-adevăr!,Есть!,,Okej!,Tamamdır! +Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT10_D4548_FIGHT,〃,,,Bojuj za Frontu a svobodu! Odchod.,Kæmp for fronten og friheden. Af sted.,Kämpfe für die Front und die Freiheit. Nun geh.,,Bataladu pro la Fronto kaj libereco. Ekagu.,Pelea por el Frente y la libertad. En marcha.,,Taistele Rintaman ja vapauden puolesta. Liikkeelle mars.,Battez vous pour le Front et pour la liberté. Repos.,Együtt a Frontért és a szabadságért! Indulás!,"Lotta, per il Fronte e per la libertà! E ora, al lavoro.",フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het front en vrijheid. Verhuizen.,Kjemp for fronten og friheten. Av sted med dere.,Walcz dla Frontu i wolności. Wykonać.,Lute pela Frente e pela liberdade. Agora vá.,,Luptă pentru Front și libertate. Acum pleacă.,Сражайся за свободу и справедливость. Выдвигайся.,,Kämpa för fronten och friheten. Gå ut.,Cephe ve özgürlük için savaşın. Dışarı çıkın. +"What prompts your return? Are you hurt? There's no time to lose, continue with your mission. Complete the Sigil.",TXT_DLG_SCRIPT10_D6064_WHATP,MAP10: Macil → The Oracle said to kill him,,,"Co přimělo tvůj návrát? Jsi zraněný? Není času nazbyt, pokračuj ve své misi. Dokonči Pečeť.","Hvad får dig til at vende tilbage? Er du såret? Der er ingen tid at spilde, fortsæt med din mission. Færdiggør sigilet.","Warum kommst du zurück? Bist du verletzt? Wir haben keine Zeit zu verlieren, du musst deine Mission fortsetzen. Vervollständige das Sigil.",,"Kial vi revenis? Ĉu vi estas vundita? Ne estas perdinda tempo, reiru al via komisio: kompletigu la Sigelon.","¿A qué has vuelto?, ¿estás herido? No hay tiempo que perder, continúa con la misión: completa el Emblema.","¿A qué volviste?, ¿estás herido? No hay tiempo que perder, continúa con la misión: completa el Emblema.",Miksi olet palannut? Oletko loukkaantunut? Aikaa ei ole menetettävänä; jatka tehtävääsi. Kokoa Sinetti.,"Qu'est ce qui vous amène? Vous avez mal? Il n'y a pas de temps à perdre. Continuez votre mission, complétez le Sigil.","Hogyhogy ilyen hamar visszatértél? Megsebesültél? Nem vesztegethetjük az időt, folytasd a küldetésed. Fejezd be a pecsétet.","Come mai già di ritorno? Sei ferito? Non c'è tempo da perdere, continua la tua missione. Completa il Sigillo.","何が帰還を促した?怪我をしたのか? 屈している場合ではない。 -シジルを完成させる使命を果たすんだ。",돌아왔습니까? 상처라도 입었나요? 시간이 없으니 임무를 속행하고 시질 조각을 마저 모으시길 바랍니다.,"Wat zet je ertoe aan om terug te keren? Ben je gewond? Er is geen tijd te verliezen, ga verder met je missie. Voltooi de Sigil.",,O que fez você retornar? Você está ferido? Não há tempo a perder. Continue com a sua missão. Complete o Sigilo.,,,С какой целью ты вернулся? Ты ранен? Нельзя терять ни минуты. Продолжай выполнение задания. Собери Сигил!, -The Oracle says you must die!,TXT_RPLY0_SCRIPT10_D6064_THEOR,,,,"Věštec říká, že musíš zemřít!","Das Orakel sagt, du musst sterben.",,,¡El Oráculo dice que debes morir!,,,L'Oracle dit que vous devez mourir!,,,オラクルは死ぬべきだと言った!,오라클의 이름으로 넌 죽어야 해!,Het Orakel zegt dat je moet sterven!,,O Oráculo diz que você deve morrer!,,,"Оракул сказал, что я должен убить тебя!", -I have sworn myself to freedom. It is the Oracle who holds the third piece. There's your traitor.,TXT_DLG_SCRIPT10_D7580_IHAVE,,,,"Já jsem zapřísáhnut svobodě! Věštec je ten, kdo má u sebe třetí díl. On je ten zrádce.",Ich habe mich der Freiheit verpflichtet. Das Orakel besitzt das dritte Teilstück. Dort ist dein Verräter.,,,He hecho un juramento por la libertad. Es el Oráculo quien tiene la tercera pieza. Ahí tienes a tu traidor.,,,J'ai juré donner ma vie à la liberté. C'est l'Oracle qui porte la troisième pièce. Voilà votre traître.,,,"私は皆の自由を誓った。 +シジルを完成させる使命を果たすんだ。",돌아왔습니까? 상처라도 입었나요? 시간이 없으니 임무를 속행하고 시질 조각을 마저 모으시길 바랍니다.,"Wat zet je ertoe aan om terug te keren? Ben je gewond? Er is geen tijd te verliezen, ga verder met je missie. Voltooi de Sigil.","Hvorfor kommer du tilbake? Er du såret? Det er ingen tid å miste, fortsett med oppdraget ditt. Fullfør sigillet.","Co skłoniło cię do powrotu? Jesteś ranny? Nie ma czasu do stracenia, kontynuuj swą misję. Uzupełnij Pieczęć.",O que fez você retornar? Você está ferido? Não há tempo a perder. Continue com a sua missão. Complete o Sigilo.,,"Ce te aduce înapoi? Nu avem timp de pierdut, continuă-ți misiunea. Asamblează Sigiliul.",С какой целью ты вернулся? Ты ранен? Нельзя терять ни минуты. Продолжай выполнение задания. Собери Печать!,,"Vad föranleder din återkomst? Är du skadad? Det finns ingen tid att förlora, fortsätt med ditt uppdrag. Slutför Sigillet.","Geri dönmene ne sebep oldu? Yaralandın mı? Kaybedecek zaman yok, görevinize devam edin. Sigil'i tamamla." +The Oracle says you must die!,TXT_RPLY0_SCRIPT10_D6064_THEOR,〃,,,"Věštec říká, že musíš zemřít!","Oraklet siger, at du skal dø!","Das Orakel sagt, du musst sterben.",,"La Orakolo diras, ke vi devas morti!",¡El Oráculo dice que debes morir!,,"Oraakkeli sanoo, että sinun pitää kuoleman!",L'Oracle dit que vous devez mourir!,"Az Orákulum azt üzeni, hogy meg kell halnod!",L'Oracolo mi ha detto che devi morire!,オラクルは死ぬべきだと言った!,오라클의 이름으로 넌 죽어야 해!,Het Orakel zegt dat je moet sterven!,Oraklet sier at du må dø!,Wyrocznia mówi że musisz zginąć!,O Oráculo diz que você deve morrer!,,Oracolul spune că trebuie să mori!,"Оракул сказал, что я должен убить тебя!",,Oraklet säger att du måste dö!,Kahin ölmen gerektiğini söylüyor! +I have sworn myself to freedom. It is the Oracle who holds the third piece. There's your traitor.,TXT_DLG_SCRIPT10_D7580_IHAVE,〃,,,"Já jsem zapřísáhnut svobodě! Věštec je ten, kdo má u sebe třetí díl. On je ten zrádce.","Jeg har svoret mig selv til frihed. Det er Oraklet, der har den tredje del. Der er din forræder.",Ich habe mich der Freiheit verpflichtet. Das Orakel besitzt das dritte Teilstück. Dort ist dein Verräter.,,"Mi faris ĵuron de libereco. La Orakolo estas tiu, kiu havas la trian pecon: tie estas via perfidulo.",Hice un juramento por la libertad. Es el Oráculo quien tiene la tercera pieza: ahí está tu traidor.,,Olen vannonut itseni vapauteen. Kolmas osanen on Oraakkelin hallussa. Siinä on petturisi.,J'ai juré donner ma vie à la liberté. C'est l'Oracle qui porte la troisième pièce. Voilà votre traître.,Felesküdtem a szabadságra. Az Orákulumnál van a harmadik darab. Ő lesz az árulód.,Io ho dedicato tutto me stesso alla libertà. È l'Oracolo che tiene il terzo pezzo. Ecco chi è il traditore.,"私は皆の自由を誓った。 三つ目の部品を持つのはオラクルだ。 -君は裏切るつもりか。",전 자유를 지키겠다고 맹세했습니다. 오라클이 세 번째 조각을 가지고 있단 말입니다. 그자가 바로 배신자입니다!,Ik heb mezelf gezworen tot vrijheid. Het is het Orakel dat het derde deel vasthoudt. Daar is je verrader.,,Eu fiz um juramento à liberdade. É o Oráculo que possui a terceira peça. Ele é o seu traidor.,,,Я присягнул борьбе за свободу. Третий фрагмент хранится у Оракула. Так и кто же из нас предатель?, -The Oracle will die then!,TXT_RPLY0_SCRIPT10_D7580_THEOR,,,,Pak Věštec zemře!,Dann wird das Orakel sterben.,,,¡El Oráculo morirá entonces!,,,L'Oracle va donc mourir!,,,オラクルは後で仕留める!,그럼 오라클을 죽여야겠군.,Het Orakel zal dan sterven!,,O Oráculo morrerá então!,,,Тогда умрёт Оракул!, -I think you're the traitor!,TXT_RPLY1_SCRIPT10_D7580_ITHIN,,,,"Myslím, že ty jsi ten zrádce!","Ich denke, du bist der Verräter.",,,¡Creo que tú eres el traidor!,,,"Je pense que c'est vous, le traître!",,,裏切り者はお前の方だ!,배신자는 바로 당신이야!,Ik denk dat jij de verrader bent!,,Eu acho que você que é o traidor!,,,"Я думаю, что предатель — это ты!", -Spirit of the One God avenge me and turn this world into dust.,TXT_DLG_SCRIPT10_D9096_SPIRI,,,,Duše Jednoho boha nechť mě pomstí a promění tento svět v prach!,"Geist des einen Gottes, räche mich und verwandle diese Welt zu Staub.",,,Espíritu del Dios Único véngame y convierte este mundo en polvo.,,,Que le Saint Esprit du Seul Dieu me venge et brûle ce monde jusqu'au cendres.,,,"唯一神の魂が私を討てば -この世界を塵に変えるだろう。","유일신의 혼이여, 이 세계를 잿더미로 만듦으로써 저를 위해 복수하심이!!",De geest van de Ene God wreekt me en maakt deze wereld tot stof.,,"Ó, Espírito do Deus Único. Vingue-me e transforme este mundo em pó.",,,Дух Единого Бога отомстит за меня и обратит этот мир в прах., -You have made the right decision. Its clear that the Oracle is controlled by whatever evil is driving the Order. Return to it and claim the third piece of the Sigil.,TXT_DLG_SCRIPT10_D10612_YOUHA,,,,"Učinil jsi správné rozhodnutí. Je zřejmé, že Věštec je ovládán tím zlem, které vede Řád. Vrať se k němu a přivlastni si třetí díl Pečetě.","Du hast die richtige Wahl getroffen. Es ist offensichtlich, dass das Orakel von demselben Übel kontrolliert wird, das den Orden antreibt. Kehre zu ihm zurück und hol dir das dritte Teilstück.",,,Has tomado la decisión correcta. Está claro que el Oráculo está siendo controlado por el mal que está detras de la Orden. Vuelve ante él y reclama la tercera pieza del Emblema.,,,Vous avez fait le bon choix. Il est clair que l'Oracle est contrôlé par le mal qui est derrière l'Ordre. Retournez le voir et récupérez la troisième pièce du Sigil.,,,"君は正しい決断をした。 +君は裏切るつもりか。",전 자유를 지키겠다고 맹세했습니다. 오라클이 세 번째 조각을 가지고 있단 말입니다. 그자가 바로 배신자입니다!,Ik heb mezelf gezworen tot vrijheid. Het is het Orakel dat het derde deel vasthoudt. Daar is je verrader.,Jeg har sverget meg til frihet. Det er oraklet som har den tredje biten. Der er forræderen din.,Przysiągłem sobie wolność. To Wyrocznia ma trzeci fragment. Masz tu swego zdrajcę.,Eu fiz um juramento à liberdade. É o Oráculo que possui a terceira peça. Ele é o seu traidor.,,Am jurat pentru libertate. Oracolul deține a treia piesă. Iată trădătorul.,Я присягнул борьбе за свободу. Третий фрагмент хранится у Оракула. Он и есть предатель.,,Jag har svurit på frihet. Det är Oraklet som har den tredje delen. Där är din förrädare.,Özgürlük için yemin ettim. Üçüncü parça Kahin'de. İşte hainin. +The Oracle will die then!,TXT_RPLY0_SCRIPT10_D7580_THEOR,〃,,,Pak Věštec zemře!,Så dør Oraklet!,Dann wird das Orakel sterben.,,Tiuokaze la Orakolo mortos!,"¡El Oráculo morirá, entonces!","¡El Oráculo se muere, entonces!",Siinä tapauksessa Oraakkeli kuolkoon!,L'Oracle va donc mourir!,Akkor meghal az Orákulum!,E allora l'Oracolo morirà!,オラクルは後で仕留める!,그럼 오라클을 죽여야겠군.,Het Orakel zal dan sterven!,Da skal oraklet dø!,A więc to Wyrocznia zginie!,O Oráculo morrerá então!,,Oracolul va pieri atunci!,Тогда умрёт Оракул!,,Oraklet kommer att dö då!,O zaman Kahin ölecek! +I think you're the traitor!,TXT_RPLY1_SCRIPT10_D7580_ITHIN,〃,,,"Myslím, že ty jsi ten zrádce!","Jeg tror, du er forræderen!","Ich denke, du bist der Verräter.",,Eble vi estas la perfidulo!,¡Creo que tú eres el traidor!,,"Luulen, että petturi olet sinä!","Je pense que c'est vous, le traître!",Azt hiszem inkább te vagy az áruló!,Io penso che sia tu il traditore!,裏切り者はお前の方だ!,배신자는 바로 당신이야!,Ik denk dat jij de verrader bent!,Jeg tror du er forræderen!,Według mnie to ty jesteś zdrajcą!,Eu acho que você que é o traidor!,,Eu cred că tu ești trădătorul!,"Я думаю, что предатель — это ты!",,Jag tror att du är förrädaren!,Bence hain sensin! +Spirit of the One God avenge me and turn this world into dust.,TXT_DLG_SCRIPT10_D9096_SPIRI,MAP10: Macil → You chose to kill Macil,,,Duše Jednoho boha nechť mě pomstí a promění tento svět v prach!,Den ene Guds ånd hævner mig og gør denne verden til støv.,"Geist des einen Gottes, räche mich und verwandle diese Welt zu Staub.",,"Spirito de la Vera Dio, venĝu min kaj polvigu ĉi tiun mondon.","Espíritu del Dios Único, véngame y convierte este mundo en polvo.",,Yhden Ainoan Jumalan Henki kostakoon puolestani ja muuttakoon tämän maailman tuhaksi.,Que le Saint Esprit du Seul Dieu me venge et brûle ce monde jusqu'au cendres.,"Az egy igaz isten lelke bosszúljon meg, és zúzza porrá ezt a világot.","Spirito dell'Unico Dio, vendicami e trasforma questo mondo in cenere!","唯一神の魂が私を討てば +この世界を塵に変えるだろう。","유일신의 혼이여, 이 세계를 잿더미로 만듦으로써 저를 위해 복수하심이!!",De geest van de Ene God wreekt me en maakt deze wereld tot stof.,"Ånd av den ene Gud, hevn meg og gjør denne verden til støv.",Duchu Jedynego Boga pomścij mnie i zrównaj ten świat z ziemią.,"Ó, Espírito do Deus Único. Vingue-me e transforme este mundo em pó.",,Spiritul Adevăratului Zeu să mă răzbune și să facă lumea asta cenușă.,Дух Единого Бога отомстит за меня и обратит этот мир в прах.,,Den ende gudens ande hämnas mig och förvandlar den här världen till stoft.,Tek Tanrı'nın Ruhu intikamımı al ve bu dünyayı toza çevir. +You have made the right decision. Its clear that the Oracle is controlled by whatever evil is driving the Order. Return to it and claim the third piece of the Sigil.,TXT_DLG_SCRIPT10_D10612_YOUHA,MAP10: Macil → You chose to kill the Oracle,,,"Učinil jsi správné rozhodnutí. Je zřejmé, že Věštec je ovládán tím zlem, které vede Řád. Vrať se k němu a přivlastni si třetí díl Pečetě.","Du har truffet den rigtige beslutning. Det er tydeligt, at Oraklet er kontrolleret af den ondskab, der driver ordenen. Vend tilbage til det og hæv den tredje del af sigilet.","Du hast die richtige Wahl getroffen. Es ist offensichtlich, dass das Orakel von demselben Übel kontrolliert wird, das den Orden antreibt. Kehre zu ihm zurück und hol dir das dritte Teilstück.",,"Vi prenis la ĝustan decidon. Estas evidente, ke la Orakolo estas regata per ia malbono de La Ordeno. Reiru al ĝi kaj akiru la trian pecon de la Sigelo.",Has tomado la decisión correcta. Está claro que el Oráculo está siendo controlado por el mal que está detrás de La Orden. Vuelve ante él y reclama la tercera pieza del Emblema.,Tomaste la decisión correcta. Está claro que el Oráculo está siendo controlado por el mal que está detrás de La Orden. Vuelve ante él y reclama la tercera pieza del Emblema.,"Olet tehnyt oikean päätöksen. Mikä tahansa paha vallitseekaan Veljeskuntaa, selvästi myös hallitsee Oraakkelia. Palaa sen luokse ja lunasta Sinetti.",Vous avez fait le bon choix. Il est clair que l'Oracle est contrôlé par le mal qui est derrière l'Ordre. Retournez le voir et récupérez la troisième pièce du Sigil.,"A megfelelő döntést hoztad. Biztos, hogy az Orákulumot is az a gonosz hajtja, ami a Rendet. Térj vissza hozzá, és követeld tőle a Pecsét harmadik darabját.",Hai fatto la scelta giusta. È chiaro che l'Oracolo è controllato dallo stesso male che guida l'Ordine. Ritorna dall'Oracolo e reclama il terzo pezzo del Sigillo.,"君は正しい決断をした。 オラクルがオーダーに悪しき支配をしているのは 明白だ。戻って三番目のシジルを手に入れろ。","좋은 선택입니다. 아무래도 오더가 이끄는 악에서 오라클을 조종하는 것이 명백해졌으니, 녀석을 찾아가 시질의 세 번째 조각을 회수하세요. - \cy어서 가자, 나의 영웅. 그 못생긴 녀석에게 본때를 보여주자고.",Je hebt de juiste keuze gemaakt. Het is duidelijk dat het Orakel wordt beheerst door het kwaad dat de Orde drijft. Keer ernaar terug en claim het derde deel van de Sigil.,,Você fez a decisão certa. Está claro que o Oráculo está sendo controlado por alguma força maligna por trás da Ordem. Volte para lá e pegue a terceira peça do Sigilo.,,,"Ты сделал правильный выбор. Ясно, что Оракулом управляет то же самое зло, что стоит за Орденом. Вернись к Оракулу и потребуй отдать тебе третий фрагмент Сигила!", -"There seems no end to the horror we face. We have found out that the Order is not killing our people. It is transforming them, into bio-mechanical soldiers. Find the facility where this is being done and close it, permanently.",TXT_DLG_SCRIPT10_D12128_THERE,,,,"Zdá se, že zlo, kterému čelíme, nemá konce. Zjistili jsme, že Řád nezabíjí naše lidi, ale přeměňuje je na biomechanické vojáky. Najdi továrnu, kde se tohle děje, a zavři ji, natrvalo.","Der Horror, dem wir ausgesetzt sind, scheint kein Ende zu nehmen. Wir haben herausgefunden, dass der Orden unsere Leute nicht tötet, sondern sie transformiert - int biomechanische Soldaten.Finde die Einrichtung, wo dies passiert und schließe sie - endgültig.",,,"Parece que no hay fin para el horror al que nos enfrentamos. Hemos descubierto que la Orden no solo mata a nuestra gente. La está transformando, en soldados bio-mecánicos. Encuentra la instalación donde esto se hace y clausúrala, permanentemente.",,,"Il semble qu'il n'y ait pas de fin aux horreurs auxquelles nous devons faire face. Nous venons de découvrir que l'Ordre n'exécute pas notre peuple, il le transforme en soldats biomécaniques. Trouvez l'usine qui gère ce processus et fermez la pour toujours.",,,"どうやら我々の直面する恐怖は + \cy어서 가자, 나의 영웅. 그 못생긴 녀석에게 본때를 보여주자고.",Je hebt de juiste keuze gemaakt. Het is duidelijk dat het Orakel wordt beheerst door het kwaad dat de Orde drijft. Keer ernaar terug en claim het derde deel van de Sigil.,Du har tatt den rette avgjørelsen. Det er tydelig at oraklet styres av den ondskapen som driver ordenen. Vend tilbake til det og gjør krav på den tredje delen av sigillet.,"Postąpiłeś słusznie. To oczywiste, że Wyrocznia jest kontrolowana przez to zło które rządzi Zakonem. Wróć tam i odbierz jej trzeci fragment Pieczęci.",Você fez a decisão certa. Está claro que o Oráculo está sendo controlado por alguma força maligna por trás da Ordem. Volte para lá e pegue a terceira peça do Sigilo.,,Ai făcut alegerea corectă. E limpede că Oracolul e controlat de orice rău conduce și Ordinul. Întoarce-te la el și pune mâna pe cea de-a treia piesă a Sigiliului.,"Ты сделал правильный выбор. Ясно, что Оракулом управляет то же самое зло, что стоит за Орденом. Вернись к Оракулу и потребуй отдать тебе третий фрагмент Печати!",,Du har fattat rätt beslut. Det är uppenbart att Oraklet kontrolleras av den ondska som driver Orden. Återvänd till det och kräv den tredje delen av Sigillet.,"Doğru kararı verdin. Kahin'in, Düzen'i yönlendiren şeytan tarafından kontrol edildiği çok açık. Ona dön ve Sigil'in üçüncü parçasını al." +"There seems no end to the horror we face. We have found out that the Order is not killing our people. It is transforming them, into bio-mechanical soldiers. Find the facility where this is being done and close it, permanently.",TXT_DLG_SCRIPT10_D12128_THERE,MAP10: Macil → After killing the Oracle,,,"Zdá se, že zlo, kterému čelíme, nemá konce. Zjistili jsme, že Řád nezabíjí naše lidi, ale přeměňuje je na biomechanické vojáky. Najdi továrnu, kde se tohle děje, a zavři ji, natrvalo.","Der synes ikke at være nogen ende på den rædsel, vi står over for. Vi har fundet ud af, at ordenen ikke dræber vores folk. Den forvandler dem til biomekaniske soldater. Find det anlæg, hvor dette sker, og luk det for altid.","Der Horror, dem wir ausgesetzt sind, scheint kein Ende zu nehmen. Wir haben herausgefunden, dass der Orden unsere Leute nicht tötet, sondern sie transformiert - int biomechanische Soldaten.Finde die Einrichtung, wo dies passiert und schließe sie - endgültig.",,"Ŝajnas, ke la teruraĵo, kiun ni alfrontas, estas senlima. Ni malkovris, ke La Ordeno ne nur mortigas niajn homojn: ĝi transformas ilin en biomekanikajn soldatojn. Trovu la instalaĵon, kie tio okazas, kaj fermu ĝin por ĉiam.","Parece que no hay fin para el horror al que nos enfrentamos. Hemos descubierto que La Orden no solo mata a nuestra gente, sino que la está transformando en soldados biomecánicos. Encuentra la instalación donde hacen eso y clausúrala permanentemente.","Parece que no hay fin para el horror al que nos enfrentamos. Descubrimos que La Orden no solo mata a nuestra gente, sino que la está transformando en soldados biomecánicos. Encuentra la instalación donde hacen eso y clausúrala permanentemente.","Meitä kohdanneelle kauhulle ei näytä olevan loppua. Olemme saaneet selville, että Veljeskunta ei tapa meidän omiamme, vaan muuntelee heitä biomekaanisiksi sotilaiksi. Etsi laitos, jossa tätä tehdään, ja lakkauta se, pysyvästi.","Il semble qu'il n'y ait pas de fin aux horreurs auxquelles nous devons faire face. Nous venons de découvrir que l'Ordre n'exécute pas notre peuple, il le transforme en soldats biomécaniques. Trouvez l'usine qui gère ce processus et fermez la pour toujours.","Úgy néz ki, már soha nem lesz vége ennek a horrornak. Mint kiderült, a Rend nem megöli az embereinket, hanem bio-mechanikus robotokká alakítják át. Keresd meg a létesítményt, ahol ez folyik, és azonnal zárdd be.","Sembra che non ci sia limite agli orrori che affrontiamo. Abbiamo scoperto che l'Ordine non solo uccide la nostra gente, ma li trasforma anche in soldati bio-meccanici. Devi trovare lo stabilimento dove questo sta avvenendo e chiuderlo, permanentemente.","どうやら我々の直面する恐怖は まだ終わらない様だ。オーダーが民を無意味に 殺害しているだけではなく、サイボーグ兵へ改造 していることが解かった。その施設を探し出し 機能を停止させるのだ。永久的に。 ","우리가 마주하는 공포의 끝이 없는 것 같군요... 최근 오더가 우리를 학살하는 게 아닌 일종의 강화 인간으로 개조시키고 있었던 것이라고 소식을 들었습니다. 개조가 시행되고 있는 시설을 찾아가서 그곳을 영구적으로 정지시키세요. - \cy인간개조? 음, 이거 때문에 녀석들이 끊임없이 나오는 거였어! 녀석들 성질 더러운 것도 그렇고.","Er lijkt geen einde te komen aan de verschrikking waar we voor staan. We hebben ontdekt dat de Orde onze mensen niet doodt. Het transformeert hen, in bio-mechanische soldaten. Zoek de faciliteit waar dit gebeurt en sluit deze permanent.",,"Parece que os horrores que enfrentamos não têm fim. Descobrimos que a Ordem não está matando o nosso pessoal. Está os transformando em soldados biomecânicos. Ache a instalação onde isso é feito e feche-a, de uma vez por todas.",,,"Иногда кажется, что эти ужасы никогда не закончатся. Мы узнали, что Орден не убивает наших людей. Он перерабатывает их в биомеханических солдат. Найди фабрику, где происходит эта переработка, и закрой её раз и навсегда!", -Where is this located?,TXT_RPLY0_SCRIPT10_D12128_WHERE,,,,Kde ji najdu?,Wo finde ich sie?,,,¿Dónde se encuentra?,,,Où se trouve-elle?,,,手掛かりは何処にある?,이 장소는 어디에 있죠?,Waar bevindt deze faciliteit zich?,,Onde se encontra?,,,Где она находится?, -"One of our captains, Richter, is waiting for you by the waterfall in the commons. He has seen the facility and can guide you inside. Stop this atrocity, now.",TXT_DLG_SCRIPT10_D13644_ONEOF,,,,"Jeden z našich kapitánů, Richter, na tebe čeká u vodopádů na předměstí Řádu. Továrnu už viděl a může ti poradit, jak dovnitř. Zastav tuhle ohavnost, hned.","Einer unserer Anführer, Rickter warted auf dich, am Wasserfall bei der Mensa. Er hat es gesehen und kann dich dort hinführen. Stope dieses Gräuel - sofort.",,,"Uno de nuestros capitanes, Richter, está esperándote junto a la cascada en los comunes. Ha visto la instalación y puede guiarte dentro. Detén esta atrocidad, ahora.",,,"Un de nos capitaines, Richter, vous attend près de la cascade dans le réfectoire. Il a vu l'usine et peut vous guider jusqu'a l'intérieur. Arrêtez cette atrocité maintenant.",,,"キャプテンの一人、リヒターが + \cy인간개조? 음, 이거 때문에 녀석들이 끊임없이 나오는 거였어! 녀석들 성질 더러운 것도 그렇고.","Er lijkt geen einde te komen aan de verschrikking waar we voor staan. We hebben ontdekt dat de Orde onze mensen niet doodt. Het transformeert hen, in bio-mechanische soldaten. Zoek de faciliteit waar dit gebeurt en sluit deze permanent.","Det ser ikke ut til å være noen ende på skrekken vi står overfor. Vi har funnet ut at Ordenen ikke dreper folket vårt. Den forvandler dem til biomekaniske soldater. Finn anlegget der dette gjøres og steng det, permanent.","Wygląda na to, że naszym koszmarom nie ma końca. Dowiedzieliśmy się, że Zakon nie zabija naszych ludzi. Tylko zmienia ich w biomechanicznych żołnierzy. Znajdź ośrodek, w którym to robią i zamknij go na dobre.","Parece que os horrores que enfrentamos não têm fim. Descobrimos que a Ordem não está matando o nosso pessoal. Está os transformando em soldados biomecânicos. Ache a instalação onde isso é feito e feche-a, de uma vez por todas.",,"Pare să nu existe limite pentru răul pe care îl înfruntăm. Îi transformă, în soldați bio-mecanici. Găsește fabrica unde se întâmplă asta și închide-o, permanent.","Иногда кажется, что эти ужасы никогда не закончатся. Мы узнали, что Орден не убивает наших людей. Он перерабатывает их в биомеханических солдат. Найди фабрику, где происходит это, и закрой её раз и навсегда!",,Det verkar inte finnas något slut på den skräck vi står inför. Vi har fått reda på att Orden inte dödar vårt folk. Den förvandlar dem till biomekaniska soldater. Hitta anläggningen där detta sker och stäng den för gott.,Karşılaştığımız dehşetin sonu yok gibi görünüyor. Tarikat'ın insanlarımızı öldürmediğini öğrendik. Onları biyo-mekanik askerlere dönüştürüyor. Bunun yapıldığı tesisi bulun ve kalıcı olarak kapatın. +Where is this located?,TXT_RPLY0_SCRIPT10_D12128_WHERE,〃,,,Kde ji najdu?,Hvor er det placeret?,Wo finde ich sie?,,Kie ĝi estas?,¿Dónde queda?,,Missä se sijaitsee?,Où se trouve-elle?,Hol van ez?,Dove si trova?,手掛かりは何処にある?,이 장소는 어디에 있죠?,Waar bevindt deze faciliteit zich?,Hvor ligger det?,Gdzie się znajduje?,Onde se encontra?,,Unde este localizată?,Где она находится?,,Var finns den?,Burası nerede? +"One of our captains, Richter, is waiting for you by the waterfall in the commons. He has seen the facility and can guide you inside. Stop this atrocity, now.",TXT_DLG_SCRIPT10_D13644_ONEOF,〃,,,"Jeden z našich kapitánů, Richter, na tebe čeká u vodopádů na návsi. Továrnu už viděl a může ti poradit, jak dovnitř. Zastav tuhle ohavnost, ihned.","En af vores kaptajner, Richter, venter på dig ved vandfaldet i fællesrummet. Han har set anlægget og kan guide dig indenfor. Stop denne grusomhed, nu.","Einer unserer Anführer, Rickter warted auf dich, am Wasserfall bei der Mensa. Er hat es gesehen und kann dich dort hinführen. Stope dieses Gräuel - sofort.",,"Unu el niaj kapitanoj, Rikter, atendas vin en la komunumo en la limlando. Li vidis la instalaĵon kaj scias eniri ĝin. Ĉesu tuj ĉi tiun teruraĵon.","Uno de nuestros capitanes, Richter, está esperándote en la comuna de las tierras fronterizas. Ha visto la instalación y sabe como entrar. Detén esta atrocidad ahora.","Uno de nuestros capitanes, Richter, está esperándote en la comuna de las tierras fronterizas. Vio la instalación y sabe como entrar. Detén esta atrocidad ahora.","Richter, yksi kapteeneistamme, odottaa sinua messissä vesiputouksen äärellä. Hän on nähnyt laitoksen ja voi opastaa sinut sisälle. Lopeta tämä kauhistus, heti paikalla.","Un de nos capitaines, Richter, vous attend près de la cascade dans le réfectoire. Il a vu l'usine et peut vous guider jusqu'a l'intérieur. Arrêtez cette atrocité maintenant.","Richter - az egyik kapitányunk - a vízesés melletti étkezdénél fog várni rád. Ő látta ezt a létesítményt, és be tud vinni. Állítsd meg ezt a borzalmat azonnal.","Uno dei nostri capitani, Richter, ti sta aspettando vicino alla cascata nei comuni. Lui ha visto la fabbrica e ti può guidare dentro. Devi fermare quest'atrocità al più presto.","キャプテンの一人、リヒターが コモンズの滝で待っている。 彼は施設を発見し生還した者だ。 -早急にそのふざけた行為を止めさせろ。","우리 군의 한 대대장인 릭터가 식당가에 위치한 폭포 근처에서 당신을 기다리고 있습니다. 그는 그 끔찍한 시설을 보았다고 했으며, 침투할 수 있게 도와주고 싶다는군요. 부디 이 잔혹 행위를 멈출 수 있기를 바랍니다.","Een van onze kapiteins, Richter, wacht u op bij de waterval in het Lagerhuis. Hij heeft het gebouw gezien en kan je naar binnen leiden. Stop deze gruweldaad, nu.",,"Um dos nossos capitães, Richter, está te esperando perto da cascata próxima ao refeitório. Ele conhece a instalação e pode te ajudar a infiltrá-la. Detenha essa atrocidade o quanto antes.",,,"Один из наших капитанов, Рихтер, ожидает тебя возле водопада в поселении Ордена. Он уже проникал на фабрику, и он скажет тебе, как туда попасть. Положи конец этим зверствам, немедленно!", -They'll pay for this!,TXT_RPLY0_SCRIPT10_D13644_THEYL,,,,Za tohle budou pykat!,Dafür werden sie bezahlen.,,,¡Pagarán por esto!,,,Ils paieront pour cela!,,,奴等に対価を払わせてやるさ!,그놈들은 죗값을 치를 것입니다!,Zij zullen hiervoor betalen!,,Eles pagarão por isso!,,,Они за всё заплатят!, -Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT10_D15160_FIGHT,,,,Bojuj za Frontu a svobodu! Odchod.,Kämpfe für die Front und die Freiheit. Nun geh.,,,Lucha por el frente y la libertad. En marcha.,,,Battez vous pour le Front et pour la liberté. Repos.,,,フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het Front en vrijheid. Ga weg.,,Lute pela Frente e pela liberdade. Agora vá.,,,Сражайся за свободу и справедливость. Вперёд., -"I am the One God... I need his spirit to be free so that I can leave my body, and join him in flight. You have no idea what you possess... And what terror you face... The One God must be free... And he will reward me... I will be one...",TXT_DLG_SCRIPT10_D16676_IAMTH,,,,"Já jsem Jedním bohem... Potřebuju jeho duši abych se osvobodil a opustil své tělo a mohl se k němu připojit na nebesích. Nemáš ani tušení, co držíš v rukách... a jaké hrůze čelíš... Jeden bůh musí být svobodný... odmění mě... Budu jeden...","Ich bin der Eine Gott... Sein Geist muss frei sein so dass ich seinen Körper verlassen und mit ihm fliegen kann. Du hast keine Ahnung, was du besitzt... And welcher Terror die bevorsteht... Der Eine Gott muss frei sein... Und er wird mich belohnen... Ich werde eins...",,,"Soy el Dios Único... Necesito que su espíritu sea libre para poder abandonar mi cuerpo, y unirme a él en vuelo. No tienes ni idea de lo que posees... Y de el terror al que te enfrentas... El Dios Único debe ser libre... Y me recompensará... Seré uno...",,,"Je suis le Seul Dieu.. Il me faut libérer son esprit pour qu'il puisse sortir de mon corps, et le rejoindre dans sa fuite. Vous ne savez pas ce que vous possédez.. Et la terreur à laquelle vous devrez faire face... Le Seul Dieu doit être libre.. Et il me récompensera.. Je serais un avec lui..",,,"我が唯一神だ...我は己の肉体を離れ +早急にそのふざけた行為を止めさせろ。","우리 군의 한 대대장인 릭터가 식당가에 위치한 폭포 근처에서 당신을 기다리고 있습니다. 그는 그 끔찍한 시설을 보았다고 했으며, 침투할 수 있게 도와주고 싶다는군요. 부디 이 잔혹 행위를 멈출 수 있기를 바랍니다.","Een van onze kapiteins, Richter, wacht u op bij de waterval in het Lagerhuis. Hij heeft het gebouw gezien en kan je naar binnen leiden. Stop deze gruweldaad, nu.","En av våre kapteiner, Richter, venter på deg ved fossen i allmenningen. Han har sett anlegget og kan lede dere inn. Stopp denne grusomheten, nå.","Jeden z naszych kapitanów, Richter, czeka na ciebie przy wodospadzie przy błoniach. Widział ten ośrodek i pomoże ci się tam dostać. Skończ z tym okrucieństwem.","Um dos nossos capitães, Richter, está te esperando perto da cascata próxima ao refeitório. Ele conhece a instalação e pode te ajudar a infiltrá-la. Detenha essa atrocidade o quanto antes.",,"Unul dintre căpitanii noștri, Richter, te așteaptă lângă cascadă. A văzut fabrica și te poate conduce în interiorul ei. Încheie atrocitatea asta, acum.","Один из наших капитанов, Рихтер, ожидает тебя возле водопада в поселении Ордена. Он уже проникал на фабрику, и он скажет тебе, как туда попасть. Положи конец этим зверствам, немедленно!",,"En av våra kaptener, Richter, väntar på dig vid vattenfallet i allmänningen. Han har sett anläggningen och kan guida dig in. Stoppa denna grymhet, nu.","Kaptanlarımızdan biri, Richter, ortak kullanım alanındaki şelalenin yanında sizi bekliyor. Tesisi gördü ve size içeride rehberlik edebilir. Bu vahşeti durdurun, hemen." +They'll pay for this!,TXT_RPLY0_SCRIPT10_D13644_THEYL,〃,,,Za tohle budou pykat!,De vil betale for dette!,Dafür werden sie bezahlen.,,Ili pentos!,¡Se arrepentirán!,¡Se van a arrepentir!,Ne saavat maksaa tästä!,Ils paieront pour cela!,Megfizetnek ezért!,La pagheranno per questo!,奴等に対価を払わせてやるさ!,그놈들은 죗값을 치를 것입니다!,Zij zullen hiervoor betalen!,De skal få svi for dette!,Zapłacą za to!,Eles pagarão por isso!,,Vor plătii pentru asta!,Они за всё заплатят!,,De kommer att få betala för detta!,Bunun bedelini ödeyecekler! +Fight for the Front and freedom. Move out.,TXT_DLG_SCRIPT10_D15160_FIGHT,〃,,,Bojuj za Frontu a svobodu! Odchod.,Kæmp for fronten og friheden. Af sted.,Kämpfe für die Front und die Freiheit. Nun geh.,,Bataladu pro la Fronto kaj libereco. Ekagu.,Pelea por el Frente y la libertad. En marcha.,,Taistele Rintaman ja vapauden puolesta. Liikkeelle mars.,Battez vous pour le Front et pour la liberté. Repos.,Együtt a Frontért és a szabadságért! Indulás!,"Lotta, per il Fronte e per la libertà! E ora, al lavoro.",フロントと自由の為の闘争を。さあ向かえ。,"프론트와 자유를 향하여, 전진하세요!",Vecht voor het Front en vrijheid. Ga weg.,Kjemp for fronten og friheten. Av sted!,Walcz dla Frontu i wolności. Wykonać.,Lute pela Frente e pela liberdade. Agora vá.,,Luptă pentru Front și libertate. Acum pleacă.,Сражайся за свободу и справедливость. Выдвигайся.,,Kämpa för fronten och friheten. Gå ut.,Cephe ve özgürlük için savaşın. Dışarı çıkın. +"I am the One God... I need his spirit to be free so that I can leave my body, and join him in flight. You have no idea what you possess... And what terror you face... The One God must be free... And he will reward me... I will be one...",TXT_DLG_SCRIPT10_D16676_IAMTH,MAP10: Macil → After destroying the converter in MAP24.,,,"Já jsem Jedním bohem... Potřebuju jeho duši abych se osvobodil a opustil své tělo a mohl se k němu připojit na nebesích. Nemáš ani tušení, co držíš v rukách... a jaké hrůze čelíš... Jeden bůh musí být svobodný... odmění mě... Budu jeden...","Jeg er den eneste Gud... Jeg har brug for, at hans ånd bliver fri, så jeg kan forlade min krop og slutte mig til ham i flugten. Du har ingen idé om, hvad du besidder... Og hvilken terror du står over for... Den ene Gud skal være fri... Og han vil belønne mig... Jeg vil være én...","Ich bin der Eine Gott... Sein Geist muss frei sein so dass ich seinen Körper verlassen und mit ihm fliegen kann. Du hast keine Ahnung, was du besitzt... And welcher Terror die bevorsteht... Der Eine Gott muss frei sein... Und er wird mich belohnen... Ich werde eins...",,"Mi estas la Vera Dio. Mi bezonas liberigi lian spiriton, tiam mi povos forlasi mian korpon kaj aliĝi al li en la flugo! Vi ne havas ideon pri tio, kion vi posedas... nek pri la teruraĵo, kiun vi alfrontas. La Vera Dio devas esti libera! Kaj li rekompencos min... Ni estos la sama!",Soy el Dios Único. ¡Necesito liberar su espíritu para poder abandonar mi cuerpo y unirme a él en vuelo! No tienes ni idea de lo que posees... ni del terror al que te enfrentas. ¡El Dios Único debe ser libre! Y me recompensará... ¡Seremos el mismo!,Soy el Dios Único. ¡Necesito liberar su espíritu para poder abandonar mi cuerpo y unirme a él en vuelo! No tienes ni idea de lo que posees... ni del terror al que te enfrentas. ¡El Dios Único debe ser libre! Y me va a recompensar... ¡Vamos a ser el mismo!,"Minä olen Yksi Ainoa Jumala... Tarvitsen hänen henkeään ollakseni vapaa ja poistuakseni ruumiistani, jotta voisin paeta hänen kanssaan. Et käsitäkään, mitä omaat... ja mitä kauhua olet kohtaava... Yhden Ainoan Jumalan on päästävä vapaaksi... Ja hän palkitsee minut... Tulen olemaan yksi...","Je suis le Seul Dieu.. Il me faut libérer son esprit pour qu'il puisse sortir de mon corps, et le rejoindre dans sa fuite. Vous ne savez pas ce que vous possédez.. Et la terreur à laquelle vous devrez faire face... Le Seul Dieu doit être libre.. Et il me récompensera.. Je serais un avec lui..","Én vagyok az egy Igaz Isten...ki akarom szabadítani a lelkét, hogy elhagyhassam a testemet és társuljak mellé a harcban. Ötleted sincs miféle erővel rendelkezel...és miféle terroral nézel szemben...az egy Igaz Istennek szabadnak kell lennie...és majd megjutalmaz...eggyé válok majd...","Io sono l'Unico Dio... Ho bisogno che il suo spirito sia libero così che io possa lasciare il mio corpo, e unirmi a lui in volo. Non hai idea di cosa possiedi... E di quale terrore vai ad affrontare... L'Unico Dio deve essere libero... E mi ricompenserà... E sarò io...","我が唯一神だ...我は己の肉体を離れ 自由となり、神の魂と共に飛び立てる。 貴様には何も分かりもしないだろう... そして垣間見る恐怖もな... 唯一神は解放されるのだ... そして神は我を表彰するだろう... 我は一つとなる...","유일신... 그분의 영혼의 힘으로... 나의 육신을 버리고... 그분과 자유롭게 날아가리라... 그대가 소유한 것, 그대가 직면할 운명... 모두 모를 것이다... 유일신이 자유가 되면... 나에게 보답하시매, 그와 하나가 되리라!! - \cy역겨운 자식... 죽여버려!","Ik ben de enige God.... Ik heb zijn geest nodig om vrij te zijn, zodat ik mijn lichaam kan verlaten en met hem mee kan vliegen. Je hebt geen idee wat je bezit.... En welke terreur je onder ogen ziet.... De Ene God moet vrij zijn.... En hij zal mij belonen.... Ik zal er een zijn....",,"Eu sou o Deus Único... Eu preciso desse espírito para ser livre, poder abandonar este corpo e unir-me a ele na fuga. Você não tem idéia do que possui... E o horror que você enfrenta... O Deus Único deve ser livre... E ele me recompensará... Eu serei um...",,,"Я — Единый Бог... Я должен высвободить его дух, тогда я смогу покинуть бренную оболочку моего тела и воссоединиться с ним в полёте. Ты и понятия не имеешь, чем обладаешь... И с каким кошмаром столкнулся... Единый Бог должен быть освобождён... И он вознаградит меня... Это сделаю я!", -I will destroy you!,TXT_RPLY0_SCRIPT10_D16676_IWILL,,,,Zničím tě!,Ich werde dich zerstören!,,,¡Te destruiré!,,,L'heure est venue de vous détruire!,,,お前を滅ぼす!,당신을 처단하겠어!,Ik zal je vernietigen!,,Eu vou destruir você!,,,Я уничтожу тебя!, -Glad to see you made it. What do you need? ,TXT_DLG_SCRIPT10_D18192_GLADT,,,,"Jsem rád, žes to zvládnul. Co bys potřeboval?","Gut, dass du es geschafft hast. Was brauchst du?",,,Me alegro de verte de una pieza. ¿Qué necesitas?,,,Ravi de voir que vous vous en êtes sorti. Que puis-je faire pour vous?,,,お会いできて光栄です。何が必要ですか?,여기까지 오시다니 놀랍군요. 뭔가 필요한 게?,Blij te zien dat je het gehaald hebt. Wat heb je nodig?,,Que bom que você conseguiu. O que você precisa?,,,"Я рад, что ты справился. Чем могу помочь?", -Heal me.,TXT_RPLY0_SCRIPT10_D18192_HEALM,,,,Potřebuju ošetřit.,Mach mich gesund.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료해주세요.,Genees me.,,Me cure.,,,Подлечи меня., -"Well, lets get you fixed up.",TXT_RYES0_SCRIPT10_D18192_WELLL,,,,"Dobře, tak tě dáme dohromady.","Gut, das hier sollte helfen.",,,"Bien, vamos a hacerte unos arreglos.",,,"Allez, on va vous remettre sur pied.",,,では、すぐ治療しましょう。,그럼 긴급 치료하겠습니다.,"Nou, laten we je opknappen.",,"Ok, vamos dar um jeito em você.",,,"Ну, давай приведём тебя в порядок.", -You're fine.,TXT_RNO0_SCRIPT10_D18192_YOURE,,,,Jsi v pořádku.,Die geht es gut.,,,Estás bien.,,,Vous allez bien.,,,貴方は大丈夫です。,괜찮아 보이는데.,Je bent in orde.,,Você está bem.,,,Ты здоров., -Anything new?,TXT_RPLY1_SCRIPT10_D18192_ANYTH,,,,Něco nového?,Irgend etwas Neues?,,,¿Algo nuevo?,,,Quoi de neuf?,,,何か新しいのは?,특별한 거 없나요?,Iets nieuws?,,Alguma novidade?,,,Есть что-нибудь новое?, -"Yes, I've got some new hardware for you.",TXT_RYES1_SCRIPT10_D18192_YESIV,,,,"Ano, mám pro tebe novou mašinku.","Ja, ich habe neue Hardware für dich.",,,"Sí, tengo nuevo hardware para ti.",,,"Ah, j'ai du nouveau matériel pour vous.",,,貴方の為に幾つか新しいハードウェアを見つけました。,네! 사용 가능한 하드웨어가 하나 있습니다.,"Ja, ik heb wat nieuwe hardware voor je.",,"Sim, tenho equipamento novo pra você.",,,Да. Новая аппаратура для тебя., -"Nope, I'm working on it though.",TXT_RNO1_SCRIPT10_D18192_NOPEI,,,,"Ne, ale pracuju na tom.","Nein, ich arbeite noch daran.",,,"No, pero estoy trabajando en ello.",,,"Rien, mais j'y travaille.",,,いえ、只今探しています。,아뇨. 아직 작업 진행 중입니다.,"Nee, maar ik ben er wel mee bezig.",,"Não, mas estou trabalhando nisso.",,,"Нет, но я работаю над ним.", -"What can I do for you now? Feris is decrypting some really complex files, but it's all worth it. There's already some information that I'll be able to apply to the next version of the stamina implant.",TXT_DLG_SCRIPT10_D19708_WHATC,,,,"Co pro tebe můžu udělat teď? Feris pracuje na dešifrování hodně složitých souborů, ale bude to stát za to. Už teď máme informace, které budu moct použít v nové verzi tvého implantátu.","Was kann ich für dich tun? Feris entschlüsselt gerade einige sehr komplexe Dateien, aber es ist den Aufwand wert. Einige dieser Informationen kann ich für die nächste Version deines Implantats anwenden.",,,"¿Qué puedo hacer por ti? Feris está desencriptando unos archivos bastante complejos, pero valdrá la pena. Ya hay algo de información que puedo aplicar a la próxima version del implante de aguante.",,,"Que puis-je faire pour vous? Feris est en train de décrypter des fichiers très complexes, mais ça à l'air d'en valoir la peine. Il y a déjà des informations très intéressantes que l'on va pouvoir utiliser pour la prochaine version de l'implant d'endurance.",,,"何か御用かい?幾つかの複雑に複合化された + \cy역겨운 자식... 죽여버려!","Ik ben de enige God.... Ik heb zijn geest nodig om vrij te zijn, zodat ik mijn lichaam kan verlaten en met hem mee kan vliegen. Je hebt geen idee wat je bezit.... En welke terreur je onder ogen ziet.... De Ene God moet vrij zijn.... En hij zal mij belonen.... Ik zal er een zijn....","Jeg er den ene Gud... Jeg trenger hans ånd for å være fri, så jeg kan forlate kroppen min og bli med ham på flukt. Du aner ikke hva du besitter... Og hvilken skrekk du står overfor... Den ene Gud må være fri... Og han vil belønne meg... Jeg vil bli en...",Jam jest Jedyny Bóg... potrzebuję uwolnić jego duszę abym opuścił swe ciało i dołączył do niego. Nie masz pojęcia co ty posiadłeś... I z jakim terrorem się spotykasz... Jedyny Bóg musi być wolny... I on mnie nagrodzi... To ja będę tym jednym...,"Eu sou o Deus Único... Eu preciso desse espírito para ser livre, poder abandonar este corpo e unir-me a ele na fuga. Você não tem idéia do que possui... E o horror que você enfrenta... O Deus Único deve ser livre... E ele me recompensará... Eu serei um...",,"Eu sunt adevăratul Zeu.... Am nevoie de sufletul lui ca să pot să-mi părăsesc corpul, și să mă alătur lui în zbor. Nu ai idee despre ceea ce posezi... Și ce teroare înfrunți... Adevăratul Zeu trebuie să fie liber... Și mă va răsplătii... Voi fi unul...","Я Единый Бог... Я должен высвободить его дух, тогда я смогу покинуть бренную оболочку моего тела и воссоединиться с ним в полёте. Ты и понятия не имеешь, чем обладаешь... и с какому кошмару смотришь в лицо... Единый Бог должен быть освобождён... И он вознаградит меня... Это сделаю я!",,Jag är den ende guden... Jag behöver att hans ande är fri så att jag kan lämna min kropp och ansluta mig till honom i flykten. Du har ingen aning om vad du äger... Och vilken skräck ni står inför... Den ende guden måste vara fri... Och han kommer att belöna mig... Jag kommer att bli en...,"Ben Tek Tanrı'yım. Onun ruhunun özgür olmasına ihtiyacım var, böylece bedenimi terk edebilir ve uçuşta ona katılabilirim. Neye sahip olduğunuz hakkında hiçbir fikriniz yok. Ve nasıl bir dehşetle karşı karşıya olduğunuzu. Tek Tanrı özgür olmalı. Ve o beni ödüllendirecek. Ben bir olacağım." +I will destroy you!,TXT_RPLY0_SCRIPT10_D16676_IWILL,〃,,,Zničím tě!,Jeg vil ødelægge dig!,Ich werde dich zerstören!,,Mi detruos vin!,¡Te destruiré!,¡Te voy a destruir!,Tuhoan sinut!,L'heure est venue de vous détruire!,Megsemmisítelek!,Ti distruggerò!,お前を滅ぼす!,당신을 처단하겠어!,Ik zal je vernietigen!,Jeg skal tilintetgjøre deg!,Zniszczę cię!,Eu vou destruir você!,,Te voi distruge!,Я уничтожу тебя!,,Jag ska förgöra dig!,Seni yok edeceğim! +Glad to see you made it. What do you need? ,TXT_DLG_SCRIPT10_D18192_GLADT,MAP10: Gerald (no upgrade).,,,"Jsem rád, žes to zvládnul. Co bys potřeboval?","Godt at se, at du klarede den. Hvad har du brug for?","Gut, dass du es geschafft hast. Was brauchst du?",,Feliĉe vi supervivis. Kion vi bezonas?,Me alegra verte en una pieza. ¿Qué necesitas?,,"Hienoa, että selvisit. Mitä tarvitset?",Ravi de voir que vous vous en êtes sorti. Que puis-je faire pour vous?,"Örömmel látom, hogy túlélted. Miben segíthetek?",Lieto di vederti qui. Di che hai bisogno?,お会いできて光栄です。何が必要ですか?,여기까지 오시다니 놀랍군요. 뭔가 필요한 게?,Blij te zien dat je het gehaald hebt. Wat heb je nodig?,Godt å se at du kom. Hva trenger du?,"Dobrze widzieć, że udało ci się. Czego ci potrzeba?",Que bom que você conseguiu. O que você precisa?,,Mă bucur să văd că ai reușit. De ce ai nevoie?,"Я рад, что ты справился. Чем могу помочь?",,Det gläder mig att se att du klarade dig. Vad behöver du?,Gelebilmene sevindim. Neye ihtiyacın var? +Heal me.,TXT_RPLY0_SCRIPT10_D18192_HEALM,〃,,,Potřebuju ošetřit.,Helbrede mig.,Mach mich gesund.,,Kuracu min.,Cúrame.,,Hoida minua.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료해주세요.,Genees me.,Helbred meg.,Ulecz mnie.,Me cure.,,Bandajează-mă.,Подлечи меня.,,Laga mig.,İyileştir beni. +"Well, lets get you fixed up.",TXT_RYES0_SCRIPT10_D18192_WELLL,〃,,,"Dobře, tak tě dáme dohromady.","Nå, lad os få dig ordnet.","Gut, das hier sollte helfen.",,"Bone, mi pretigu vin.","Bueno, hora de +arreglarte un poco.",,"Selvä, pistetään sinut kuntoon.","Allez, on va vous remettre sur pied.","Na, akkor pofozzunk helyre.","Molto bene, ti darò una sistemata.",では、すぐ治療しましょう。,그럼 긴급 치료하겠습니다.,"Nou, laten we je opknappen.","Vel, la oss få deg fikset opp.","Dobra, pozbieram cię do kupy.","Ok, vamos dar um jeito em você.",,"Păi, să te aranjăm.","Ну, давай приведём тебя в порядок.",,Vi får fixa till dig.,"Pekala, seni iyileştirelim." +You're fine.,TXT_RNO0_SCRIPT10_D18192_YOURE,〃,,,Jsi v pořádku.,Du har det fint.,Die geht es gut.,,Vi estas en ordo.,Estás bien.,,Olet kunnossa.,Vous allez bien.,Rendben is vagy.,Stai bene.,貴方は大丈夫です。,괜찮아 보이는데.,Je bent in orde.,Det går bra med deg.,Jesteś zdrowy.,Você está bem.,,Ești în regulă.,Ты здоров.,,Du är okej.,İyisin. +Anything new?,TXT_RPLY1_SCRIPT10_D18192_ANYTH,〃,,,Něco nového?,Noget nyt?,Irgend etwas Neues?,,Ĉu io nova?,¿Algo nuevo?,,Onko mitään uutta?,Quoi de neuf?,Valami újdonság?,Novità?,何か新しいのは?,특별한 거 없나요?,Iets nieuws?,Noe nytt?,Coś nowego?,Alguma novidade?,,Ceva nou?,Есть что-нибудь новое?,,Något nytt?,Yeni bir şey var mı? +"Yes, I've got some new hardware for you.",TXT_RYES1_SCRIPT10_D18192_YESIV,〃,,,"Ano, mám pro tebe novou mašinku.","Ja, jeg har noget nyt hardware til dig.","Ja, ich habe neue Hardware für dich.",,"Jes, mi havas novan +aparataron por vi.","Sí, tengo nuevo +«hardware» para ti.",,"Kyllä, minulla on sinulle uutta rautaa.","Ah, j'ai du nouveau matériel pour vous.","Igen, van pár új fegyverem számodra.","Si, ho delle nuove attrezzature per te.",貴方の為に幾つか新しいハードウェアを見つけました。,네! 사용 가능한 하드웨어가 하나 있습니다.,"Ja, ik heb wat nieuwe hardware voor je.","Ja, jeg har noe nytt utstyr til deg.","Tak, mam dla ciebie nowe oprogramowanie.","Sim, tenho equipamento novo pra você.",,"Da, am ceva hardware nou pentru tine.",Да. Новая аппаратура для тебя.,,"Ja, jag har lite ny hårdvara till dig.","Evet, senin için yeni bir donanımım var." +"Nope, I'm working on it though.",TXT_RNO1_SCRIPT10_D18192_NOPEI,〃,,,"Ne, ale pracuju na tom.","Nej, men jeg arbejder på det.","Nein, ich arbeite noch daran.",,"Ne, sed mi +prilaboradas ĝin.","No, aunque estoy +trabajando en ello.",,Ei; on kyllä työn alla.,"Rien, mais j'y travaille.","Nem, de már dolgozom rajta.","No, ma ci sto lavorando.",いえ、只今探しています。,아뇨. 아직 작업 진행 중입니다.,"Nee, maar ik ben er wel mee bezig.","Nei, men jeg jobber med det.","Nie, jeszcze nad tym pracuję.","Não, mas estou trabalhando nisso.",,"Nu, încă lucrez la asta.","Нет, но я работаю над ним.",,"Nej, men jag jobbar på det.","Hayır, üzerinde çalışıyorum." +"What can I do for you now? Feris is decrypting some really complex files, but it's all worth it. There's already some information that I'll be able to apply to the next version of the stamina implant.",TXT_DLG_SCRIPT10_D19708_WHATC,〃 (one upgrade: Mission to talk to the Oracle),,,"Co pro tebe můžu udělat teď? Feris pracuje na dešifrování hodně složitých souborů, ale bude to stát za to. Už teď máme informace, které budu moct použít v nové verzi tvého implantátu.","Hvad kan jeg gøre for dig nu? Feris er ved at dekryptere nogle virkelig komplekse filer, men det er det hele værd. Der er allerede nogle oplysninger, som jeg vil kunne anvende til den næste version af udholdenhedsimplantatet.","Was kann ich für dich tun? Feris entschlüsselt gerade einige sehr komplexe Dateien, aber es ist den Aufwand wert. Einige dieser Informationen kann ich für die nächste Version deines Implantats anwenden.",,"Kion mi povas fari por vi? Feriso nun malĉifras kelkajn tre malsimplajn dosierojn, sed tio estos valora. Jam estas kelkaj informoj, kiujn mi povos apliki al la sekva versio de la energidona enplantaĵo.","¿Qué puedo hacer por ti? Feris está descifrando unos archivos bastante complejos, pero valdrá la pena. Ya hay algo de información que puedo aplicar a la próxima versión del implante de aguante.","¿Qué puedo hacer por ti? Feris está descifrando unos archivos bastante complejos, pero va a valer la pena. Ya hay algo de información que puedo aplicar a la próxima versión del implante de aguante.","Miten voin olla avuksi? Feris on purkamassa joidenkin todella monimutkaisten tiedostojen salausta, mutta se on sen vaivan väärti.","Que puis-je faire pour vous? Feris est en train de décrypter des fichiers très complexes, mais ça à l'air d'en valoir la peine. Il y a déjà des informations très intéressantes que l'on va pouvoir utiliser pour la prochaine version de l'implant d'endurance.","Mit tehetek érted most? Feris elég komplex fájlokat próbál épp dekódolni, de ha sikerül meg fogja érni. Már van pár információm, amit fel tudok használni az állóképesség implantátum fejlesztésére.","Che cosa posso fare per te ora? Feris sta decriptando alcuni file molto complessi, ma ne varrà la pena. Abbiamo già delle informazioni che potrò applicare nella prossima versione dell'impianto stamina.","何か御用かい?幾つかの複雑に複合化された フェリスのファイルにはそれだけの価値はあった スタミナインプラントの次期バージョンに -適用できる情報を少しばかり見つけたんだ。","무엇을 도와드릴까요? 페리스가 아주 복잡한 파일들을 천천히 해독하는 중입니다만, 기다리는 보람이 많이 있을 거예요. 나머지 정보를 다 해독한 뒤면 진보된 지구력 향상 이식을 받으실 수 있을 겁니다.","Wat kan ik nu voor je doen? Feris ontcijfert enkele zeer complexe bestanden, maar het is het allemaal de moeite waard. Er is al wat informatie die ik kan toepassen op de volgende versie van het stamina implantaat.",,"Como posso te ajudar no momento? Feris está decriptando uns arquivos bem complexos, mas valerá a pena. Já temos informações que vou poder usar na próxima versão do implante de resistência.",,,"Чем я могу тебе помочь? Ферис сейчас расшифровывает файлы Ордена. Это нелегко, но результат стоит того. Я уже получил кое-какие новые данные, которые помогут мне при разработке новой версии твоего импланта.", -Heal me.,TXT_RPLY0_SCRIPT10_D19708_HEALM,,,,Potřebuju ošetřit.,Mach mich gesund.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료해주세요.,Genees mij.,,Me cure.,,,Подлечи меня., -You should learn to be a little more careful.,TXT_RYES0_SCRIPT10_D19708_YOUSH,,,,Měl bys být trochu opatrnější.,Du solltest wirklich etwas vorsichtiger sein.,,,Deberías aprender a tener un poco más de cuidado.,,,Vous devriez faire plus attention à vous.,,,もう少し慎重にやるべきでは。,몸 간수 잘하시고 싸우세요.,Je moet leren om wat voorzichtiger te zijn.,,Você precisa aprender a tomar mais cuidado.,,,В следующий раз тебе стоит быть поосторожнее., -When will that be ready?,TXT_RPLY1_SCRIPT10_D19708_WHENW,,,,Kdy bude hotov?,Wann ist es soweit?,,,¿Cuándo estará eso listo?,,,Quand-est-ce que t'il sera prêt?,,,出来ているか?,이식 준비는 다 됐습니까?,Wanneer is dat klaar?,,Quando isso vai estar pronto?,,,Когда он будет готов?, -It's ready now. This won't take but a moment.,TXT_RYES1_SCRIPT10_D19708_ITSRE,,,,Už je hotový. Nepotrvá to ani chvilku.,"Es ist fertig. Einen kurzen Moment, bitte.",,,Ya está listo. Ésto solo tomará un momento.,,,"Il est déjà prêt, çe ne prendra qu'un moment.",,,用意出来ている。すぐ終わるさ。,다 됐습니다! 이제 이식을 시작하죠!,Het is nu klaar. Dit duurt niet langer dan een moment.,,Já está pronto. Isso não vai demorar.,,,Уже готово. Это не займёт много времени..., -Soon.,TXT_RNO1_SCRIPT10_D19708_SOON,,,,Brzy.,Bald.,,,Pronto.,,,Bientôt.,,,間もなくだ。,곧 완성되요.,Binnenkort.,,Logo logo.,,,Скоро., -I think I found a glitch in your implant hardware. Feris is helping me design a retrofit that will take care of it and boost the speed of your hardware a little. Is there something I can do for you?,TXT_DLG_SCRIPT10_D21224_ITHIN,,,,"Myslím, že jsem našel vadu v tvém implantátu. Feris mi pomáhá navrhnout dodatečné komponenty, které se o ni postarají a zvýší jeho výkon. Můžu pro tebe něco udělat?","Ich glaube ich habe eine Fehlfunktion in deinem Implantat gefunden. Feris hilft mir, einen Nachrüstsatz zu bauen und seine Funktion nochmal zu verbessern. Gibt es sonst etwas, das ich für dich tun kann?",,,Creo que he encontrado un defecto en el hardware de tu implante. Feris me está ayudando a diseñar un reequipamiento que se ocupará de él y aumentará la velocidad de tu hardware un poco. ¿Hay algo que pueda hacer por ti?,,,Je crois que j'ai découvert un bug dans votre implant. Feris m'aide à concevoir une mise à jour qui la corrigera et rendra le matériel encore plus rapide. Je peux faire quelque chose pour vous?,,,"インプラントハードウェアに不具合が見つかった +適用できる情報を少しばかり見つけたんだ。","무엇을 도와드릴까요? 페리스가 아주 복잡한 파일들을 천천히 해독하는 중입니다만, 기다리는 보람이 많이 있을 거예요. 나머지 정보를 다 해독한 뒤면 진보된 지구력 향상 이식을 받으실 수 있을 겁니다.","Wat kan ik nu voor je doen? Feris ontcijfert enkele zeer complexe bestanden, maar het is het allemaal de moeite waard. Er is al wat informatie die ik kan toepassen op de volgende versie van het stamina implantaat.","Hva kan jeg gjøre for deg nå? Feris dekrypterer noen komplekse filer, men det er verdt det. Jeg har allerede informasjon som jeg kan bruke i neste versjon av utholdenhetsimplantatet.","Co mogę dla ciebie teraz zrobić? Feris +rozszyfrowywuje jakieś skomplikowane +dokumenty, ale mówię ci... warto było. +Już mamy trochę informacji, które +będę mógł wykorzystać w nowszej +wersji implantu zwiększającego +wytrzymałość.","Como posso te ajudar no momento? Feris está decriptando uns arquivos bem complexos, mas valerá a pena. Já temos informações que vou poder usar na próxima versão do implante de resistência.",,"Ce pot face pentru tine acum? Feris decriptează niște fișiere extrem de complexe, dar merită. Deja avem niște informații care le voi putea aplica urmatoarei versiuni ale implantului tău pentru rezistență.","Чем я могу тебе помочь? Ферис сейчас расшифровывает файлы Ордена. Это нелегко, но результат стоит того. Я уже получил кое-какие новые данные, которые помогут мне при разработке новой версии твоего импланта.",,"Vad kan jag göra för dig nu? Feris dekrypterar några riktigt komplicerade filer, men det är värt det. Det finns redan en del information som jag kommer att kunna tillämpa på nästa version av uthållighetsimplantatet.",Şimdi senin için ne yapabilirim? Feris bazı karmaşık dosyaların şifresini çözüyor ama buna değer. Dayanıklılık implantının bir sonraki versiyonuna uygulayabileceğim bazı bilgiler var. +Heal me.,TXT_RPLY0_SCRIPT10_D19708_HEALM,〃,,,Potřebuju ošetřit.,Helbred mig.,Mach mich gesund.,,Kuracu min.,Cúrame.,,Hoida minua.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료해주세요.,Genees mij.,Helbred meg.,Ulecz mnie.,Me cure.,,Bandajează-mă.,Подлечи меня.,,Laga mig.,İyileştir beni. +You should learn to be a little more careful.,TXT_RYES0_SCRIPT10_D19708_YOUSH,〃,,,Měl bys být trochu opatrnější.,Du burde lære at være lidt mere forsigtig.,Du solltest wirklich etwas vorsichtiger sein.,,"Vi devus lerni esti +pli singardema.","Deberías aprender a tener +un poco más de cuidado.",,Sinun pitäisi oppia olemaan hieman varovaisempi.,Vous devriez faire plus attention à vous.,Meg kéne tanulnod óvatosabbnak lenni.,Dovresti imparare ad essere un po' più attento.,もう少し慎重にやるべきでは。,몸 간수 잘하시고 싸우세요.,Je moet leren om wat voorzichtiger te zijn.,Du burde lære deg å være litt mer forsiktig.,Powinieneś być bardziej ostrożny.,Você precisa aprender a tomar mais cuidado.,,Ar trebui să fii mai grijuliu.,В следующий раз тебе стоит быть поосторожнее.,,Du borde lära dig att vara lite mer försiktig.,Biraz daha dikkatli olmayı öğrenmelisin. +When will that be ready?,TXT_RPLY1_SCRIPT10_D19708_WHENW,〃,,,Kdy bude hotov?,Hvornår er den klar?,Wann ist es soweit?,,Kiam ĝi estos preta?,¿Cuándo estará listo?,¿Cuándo va a estar listo?,Milloin se on valmis?,Quand-est-ce que t'il sera prêt?,Mikor lesz kész?,Quando sarà pronto?,出来ているか?,이식 준비는 다 됐습니까?,Wanneer is dat klaar?,Når er det klart?,Kiedy to będzie gotowe?,Quando isso vai estar pronto?,,Când va fi gata?,Когда он будет готов?,,När kommer den att vara klar?,Ne zaman hazır olacak? +It's ready now. This won't take but a moment.,TXT_RYES1_SCRIPT10_D19708_ITSRE,〃,,,Už je hotový. Nepotrvá to ani chvilku.,Det er klar nu. Det vil kun tage et øjeblik.,"Es ist fertig. Einen kurzen Moment, bitte.",,"Mi jam finis. Atendu +nur unu momenton...","Ya lo está. Dame +solo un momento...",,Se on valmis nyt. Tähän ei mene kuin vain hetki.,"Il est déjà prêt, çe ne prendra qu'un moment.","Készen van, csak pár másodperc.",È pronto ora. Ci vorrà solo un momento.,用意出来ている。すぐ終わるさ。,다 됐습니다! 이제 이식을 시작하죠!,Het is nu klaar. Dit duurt niet langer dan een moment.,Det er klart nå. Dette tar bare et øyeblikk.,Już jest gotowe. To zajęło tylko chwilę.,Já está pronto. Isso não vai demorar.,,E gata. Va dura doar un moment.,Уже готово. Это не займёт много времени.,,Det är klart nu. Det här tar bara ett ögonblick.,Şimdi hazır. Bir dakika bile sürmez. +Soon.,TXT_RNO1_SCRIPT10_D19708_SOON,〃,,,Brzy.,Det er snart.,Bald.,,Baldaŭ.,Pronto.,,Pian.,Bientôt.,Hamarosan.,Presto.,間もなくだ。,곧 완성되요.,Binnenkort.,Snart.,Niedługo.,Logo logo.,,Curând.,Скоро.,,Snart.,Çok yakında. +I think I found a glitch in your implant hardware. Feris is helping me design a retrofit that will take care of it and boost the speed of your hardware a little. Is there something I can do for you?,TXT_DLG_SCRIPT10_D21224_ITHIN,〃 (two upgrades: Mission to decide between Macil or the Oracle),,,"Myslím, že jsem našel vadu v tvém implantátu. Feris mi pomáhá navrhnout doplněk, který se o ni postará a zvýší jeho výkon. Můžu pro tebe něco udělat?","Jeg tror, jeg har fundet en fejl i dit implantathardware. Feris hjælper mig med at designe en eftermontering, der vil løse problemet og øge hastigheden på din hardware en smule. Er der noget, jeg kan gøre for dig?","Ich glaube ich habe eine Fehlfunktion in deinem Implantat gefunden. Feris hilft mir, einen Nachrüstsatz zu bauen und seine Funktion nochmal zu verbessern. Gibt es sonst etwas, das ich für dich tun kann?",,"Ŝajnas, ke mi trovis cimeton en la aparataro de via enplantaĵo. Feriso helpas al mi dezajni modernigon por ripari ĝin kaj iomete pliigi ĝian rapidon. Ĉu mi povas fari ion por vi?",Creo haber encontrado un defecto en el «hardware» de tu implante. Feris me está ayudando a diseñar una modernización para arreglarlo y aumentarle un poco la velocidad. ¿Hay algo que pueda hacer por ti?,,"Luulen löytäneeni vian istutteesi laitteistossa. Feris auttaa minua kehittämään jälkiasennuskappaleen, joka korjaa vian ja nopeuttaa laitteistoasi vähäsen. Miten voin olla muuten avuksi?",Je crois que j'ai découvert un bug dans votre implant. Feris m'aide à concevoir une mise à jour qui la corrigera et rendra le matériel encore plus rapide. Je peux faire quelque chose pour vous?,"Azt hiszem találtam egy hibát az implantátumban. Feris segít nekem áttervezni, hogy kiküszöböljük a hibát, és kicsit fel is gyorsítsuk a hardvert. Segíthetek valami másban?",Credo di aver trovato un problema nel tuo impianto. Feris mi sta aiutando a creare un ammodernamento che lo sistemerà e migliorerà un poco la velocità del tuo impianto. C'è qualcosa che posso fare per te?,"インプラントハードウェアに不具合が見つかった フェリスがそれを修正してハードウェアの性能を 上げる為の後付け機能を手伝ってくれた。 -何か必要かい?","전에 이식한 지구력 향상 칩에 오류가 좀 발견되었더군요. 그 오류를 잡은 최근 버전을 페리스랑 같이 만드는 참입니다. 아무튼, 원하시는 게 있나요?",Ik denk dat ik een storing in uw implantaathardware heb gevonden. Feris helpt me bij het ontwerpen van een retrofit die de snelheid van uw hardware een beetje zal verhogen. Kan ik iets voor u doen?,,Acho que encontrei um defeito no seu implante. Feris está me ajudando a desenvolver um aprimoramento que resolverá esse problema e também vai aumentar um pouco a velocidade. Precisa de alguma coisa?,,,"Кажется, я обнаружил неполадку в устройстве твоего импланта. Ферис помогает мне в разработке модификации, которая исправит её и немного ускорит работу устройства. Чем я могу тебе помочь?", -Patch me up.,TXT_RPLY0_SCRIPT10_D21224_PATCH,,,,Potřebuju ošetřit.,Flick mich zusammen.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료가 필요합니다.,Verbind me met elkaar.,,Trate meus ferimentos.,,,"Вот, прямо как новенький.", -"There, as good as new I guess.",TXT_RYES0_SCRIPT10_D21224_THERE,,,,"Tak, a jsi jako nový.","So, fast wie neu, würde ich sagen.",,,"Ya está, como nuevo, supongo.",,,"Voilà, comme neuf, je crois.",,,ほら、新鮮な気分だろう。,"자, 갓 태어난 것처럼 멀쩡할 겁니다!","Daar, zo goed als nieuw denk ik.",,"Pronto. Novinho em folha, eu acho.",,,Ты в полном порядке., -Retrofit?,TXT_RPLY1_SCRIPT10_D21224_RETRO,,,,Dovybavení?,Nachrüstsatz?,,,¿Reequipamiento?,,,Mise à jour de l'implant?,,,後付け?,향상 칩 최근 버전?,Retrofit?,,Aprimoramento?,,,Модификация?, -"Ah, now we're cooking.",TXT_RYES1_SCRIPT10_D21224_AHNOW,,,,"Ahá, a už to jede.","Ah, jetzt bist du bei der Sache.",,,"Ah, ahora sí que sí.",,,"Ah, on va s'amuser.",,,ああ、早速取り掛かろう。,이제야 좀 멋져 보이는군요.,"Ah, nu zijn we aan het koken.",,"Ah, agora sim.",,,Да. Мы славно поработали над ней., -I'll have it as soon as Feris finishes it.,TXT_RNO1_SCRIPT10_D21224_ILLHA,,,,"Budu ho mít hned, co ho Feris dokončí.","Ich gebe es dir, sobald Feris fertig ist.",,,Lo tendré listo en cuanto Feris lo termine.,,,Je l'aurai dès que Feris l'a terminée.,,,完了次第フェリスから私が送ろう。,페리스가 작업을 마치는 순간 보여드리겠습니다.,Ik heb het zodra Feris het klaar heeft.,,Eu consigo ele assim que o Feris terminar.,,,"Я получу её, как только Ферис закончит.", -"How's it going? Man, some of this new technology is simply amazing. This should also help with your implant. I've got a couple ideas that I'm sketching out and I'll have them ready soon. What can I do for you, maybe some healing?",TXT_DLG_SCRIPT10_D22740_HOWSI,,,,"Jak se vede? Sakra, některé tychle nové technologie jsou prostě úžasné. Mělo by ti to taky pomoct s tvým implantátem. Mám už pár nápadů, teď je dávám na papír a brzy by měly být hotové. Co pro tebe mohu udělat, nějaké ošetření?","Wie läuft es? Mann, einiges von dieser Technologie ist einfach erstaunlich. Da sollte auch mit deinem Implantat helfen. Ich habe da schon einige Ideen, die ich noch ausarbeiten muss, aber sie werden bald fertig sein. Was kann ich sonst für dich tun?",,,"¿Cómo te va? Tío, algunas de estas nuevas tecnologías son realmente sorprendentes. Esto debería ayudar con tu implante. Tengo unas cuantas ideas que voy planeando y las tendré listas pronto. ¿Qué puedo hacer por ti?, ¿tal vez una cura?","¿Cómo te va? Hombre, algunas de estas nuevas tecnologías son realmente sorprendentes. Esto debería ayudar con tu implante. Tengo unas cuantas ideas que voy planeando y las tendré listas pronto. ¿Qué puedo hacer por ti?, ¿tal vez una curación?",,"Comment ça va? La vache, cete nouvelle technologie est simplement géniale. Elle devrait également aider pour le dévelopment de votre implant. J'ai quelques idées que je suis en train de tester et elles devraient être bientôt prêtes. Que puis-je faire pour vous? Des soins, peut être?",,,"調子はどうだ?この新技術は素晴らしいものだ。 +何か必要かい?","전에 이식한 지구력 향상 칩에 오류가 좀 발견되었더군요. 그 오류를 잡은 최근 버전을 페리스랑 같이 만드는 참입니다. 아무튼, 원하시는 게 있나요?",Ik denk dat ik een storing in uw implantaathardware heb gevonden. Feris helpt me bij het ontwerpen van een retrofit die de snelheid van uw hardware een beetje zal verhogen. Kan ik iets voor u doen?,Jeg tror jeg har funnet en feil i implantatets maskinvare. Feris hjelper meg med å designe en oppgradering som vil ta seg av det og øke hastigheten på maskinvaren din litt. Er det noe jeg kan gjøre for deg?,"Chyba znalazłem błąd w +oprogramowaniu twojego implantu. +Feris próbuje mi pomóc stworzyć +ulepszenie do niego, które naprawi +ten błąd i ulepszy trochę twoją +szybkość. Czy coś jeszcze mogę +dla ciebie zrobić?",Acho que encontrei um defeito no seu implante. Feris está me ajudando a desenvolver um aprimoramento que resolverá esse problema e também vai aumentar um pouco a velocidade. Precisa de alguma coisa?,,Cred că am găsit o problemă în implantul tău. Feris mă ajută la implementarea unor îmbunătățiri care vor avea grijă de el și vor crește viteza puțin. E ceva ce pot face pentru tine?,"Кажется, я обнаружил неполадку в устройстве твоего импланта. Ферис помогает мне в разработке модификации, которая исправит её и немного ускорит работу устройства. Чем я могу тебе помочь?",,Jag tror att jag har hittat ett glapp i din implantathårdvara. Feris hjälper mig att utforma en eftermontering som kommer att ta hand om det och öka hastigheten på din hårdvara lite. Finns det något jag kan göra för dig?,Sanırım implant donanımında bir hata buldum. Feris bunu halledecek ve donanımınızın hızını biraz artıracak bir güçlendirme tasarlamama yardım ediyor. Senin için yapabileceğim bir şey var mı? +Patch me up.,TXT_RPLY0_SCRIPT10_D21224_PATCH,〃,,,Potřebuju ošetřit.,Giv mig en besked.,Flick mich zusammen.,,Kuracu min.,Cúrame.,,Kasaa minut takaisin kokoon.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료가 필요합니다.,Verbind me met elkaar.,Lappe meg sammen.,Opatrz mnie.,Trate meus ferimentos.,,Bandajează-mă.,Подлатай меня.,,Laga mig.,Bana yama yap. +"There, as good as new I guess.",TXT_RYES0_SCRIPT10_D21224_THERE,〃,,,"Tak, a jsi jako nový.","Sådan, så god som ny, tror jeg.","So, fast wie neu, würde ich sagen.",,"Farite, kiel nova, mi kredas.","Ya está, como nuevo, supongo.",,"Kas niin, kuin uudenveroinen, luulisin.","Voilà, comme neuf, je crois.","Parancsolj, jobb mint új korában.","Ecco qua, come nuovo.",ほら、新鮮な気分だろう。,"자, 갓 태어난 것처럼 멀쩡할 겁니다!","Daar, zo goed als nieuw denk ik.","Sånn, så god som ny, antar jeg.",Proszę. Jak nowy. Chyba.,"Pronto. Novinho em folha, eu acho.",,"Gata, ca și nou bănuiesc.","Ну вот, прям как новенький.",,"Så där, så gott som ny antar jag.","İşte, yeni kadar iyi sanırım." +Retrofit?,TXT_RPLY1_SCRIPT10_D21224_RETRO,〃,,,Doplněk?,Eftermontering?,Nachrüstsatz?,,Ĉu modernigo?,¿Modernización?,,Jälkiasennuskappale?,Mise à jour de l'implant?,Áttervezni?,Ammodernamento?,後付け?,향상 칩 최근 버전?,Retrofit?,Oppgradering?,Ulepszenie?,Aprimoramento?,,Îmbunătățiri?,Модернизация?,,Eftermontering?,Güçlendirme mi? +"Ah, now we're cooking.",TXT_RYES1_SCRIPT10_D21224_AHNOW,〃 (during sad/bad ending),,,"Ahá, a už to jede.","Ah, nu er vi i gang.","Ah, jetzt bist du bei der Sache.",,"Ha, ĉi tio iĝas serioza.","Ah, ahora sí que sí.",,No nyt päästiin asiaan.,"Ah, on va s'amuser.",Ez a beszéd!,"Ah, ora ci siamo.",ああ、早速取り掛かろう。,이제야 좀 멋져 보이는군요.,"Ah, nu zijn we aan het koken.",Nå er vi i gang.,"Ah, no i to rozumiem.","Ah, agora sim.",,"Ah, acum discutăm.",Да. Мы славно поработали над ней.,,"Ah, nu börjar det bli spännande.",İşte şimdi pişiyoruz. +I'll have it as soon as Feris finishes it.,TXT_RNO1_SCRIPT10_D21224_ILLHA,〃,,,"Budu ho mít hned, co ho Feris dokončí.","Jeg får den, så snart Feris er færdig.","Ich gebe es dir, sobald Feris fertig ist.",,"Mi havos ĝin tuj +kiam Feriso finos.","La tendré lista en cuanto +Feris la termine.","La voy a tener lista +en cuanto Feris la termine.","Asennan sen heti, kun Feris saa sen valmiiksi.",Je l'aurai dès que Feris l'a terminée.,"Meglesz egyből, amikor Feris végez vele.",Te lo farò avere non appena Feris lo finisce.,完了次第フェリスから私が送ろう。,페리스가 작업을 마치는 순간 보여드리겠습니다.,Ik heb het zodra Feris het klaar heeft.,Jeg får den så snart Feris er ferdig.,Będzie gotowe jak Feris je skończy.,Eu consigo ele assim que o Feris terminar.,,Îl voi avea imediat ce termină Feris cu el.,"Она будет у меня, как только Ферис закончит.",,Jag har den så snart Feris är klar.,Feris bitirir bitirmez getireceğim. +"How's it going? Man, some of this new technology is simply amazing. This should also help with your implant. I've got a couple ideas that I'm sketching out and I'll have them ready soon. What can I do for you, maybe some healing?",TXT_DLG_SCRIPT10_D22740_HOWSI,〃 (three upgrades: Mission to kill the Loremaster with the Oracle alive).,,,"Jak se vede? Sakra, některé tychle nové technologie jsou prostě úžasné. Mělo by ti to taky pomoct s tvým implantátem. Mám už pár nápadů, teď je dávám na papír a brzy by měly být hotové. Co pro tebe mohu udělat, nějaké ošetření?","Hvordan går det? Mand, noget af denne nye teknologi er simpelthen fantastisk. Det burde også hjælpe med dit implantat. Jeg har et par idéer, som jeg skitserer, og jeg har dem snart klar. Hvad kan jeg gøre for dig? Måske noget healing?","Wie läuft es? Mann, einiges von dieser Technologie ist einfach erstaunlich. Da sollte auch mit deinem Implantat helfen. Ich habe da schon einige Ideen, die ich noch ausarbeiten muss, aber sie werden bald fertig sein. Was kann ich sonst für dich tun?",,"Kiel vi fartas? Ulo, kelkaj el ĉi tiuj novaj teknologioj estas nekredeblaj; ili devus helpi al via enplantaĵo. Mi havas kelkajn planatajn ideojn, kiuj baldaŭ estos pretaj. Kion mi povas fari por vi? Ĉu eble kuraci vin?","¿Cómo te va? Tío, algunas de estas nuevas tecnologías son realmente sorprendentes; deberían ayudar con tu implante. Tengo unas cuantas ideas que voy planeando y las tendré listas pronto. ¿Qué puedo hacer por ti?, ¿tal vez curarte?","¿Cómo te va? Hombre, algunas de estas nuevas tecnologías son realmente sorprendentes; deberían ayudar con tu implante. Tengo unas cuantas ideas que voy planeando y las voy a tener listas pronto. ¿Qué puedo hacer por ti?, ¿tal vez curarte?","Kuinka sujuu? Ei hitsi, osa tästä uudesta teknologiasta on yksinkertaisesti hämmästyttävää. Sen pitäisi auttaa myös istutteesi kanssa. Luonnostelen tässä paria ideaa, jotka saan toteutettua pian. Mutta, miten voisin olla avuksi; sairaanhoidon tarpeessa kenties?","Comment ça va? La vache, cete nouvelle technologie est simplement géniale. Elle devrait également aider pour le dévelopment de votre implant. J'ai quelques idées que je suis en train de tester et elles devraient être bientôt prêtes. Que puis-je faire pour vous? Des soins, peut être?","Hogy ityeg? Némely új technológia egyszerűen csodálatos. Ez kicsit feljavítja az implantátumodat is ha minden igaz. Van pár ötletem amit még most jegyzetelek ki, de hamarosan meglesz. Node mit tehetek érted, esetleg valami gyógyítás?","Come ti va? Te lo devo dire, alcune di queste nuove tecnologie sono semplicemente fantastiche. Questo dovrebbe anche aiutarti con il tuo impianto. Ho un paio di idee che sto elaborando e dovrei averle pronte presto. Cosa posso fare nel frattempo, hai bisogno di cure?","調子はどうだ?この新技術は素晴らしいものだ。 そちらのインプラントにも役立つ様な アイディアも幾つか思いついてあるぞ。 -すぐ準備しよう。それとも治療か何か必要かな?","별일 없으시죠? 세상에나, 오더의 과학력은 세계 제일이군요! 이식한 칩이랑 추가 설치가 가능한데, 성능을 향상해줄 거에요. 현재 부품을 더 설계하고 있습니다. 만약 준비가 되면 불러줄게요. 아무튼, 치료가 필요하신가요?","Hoe gaat het? Man, sommige van deze nieuwe technologie is gewoonweg verbazingwekkend. Dit zou ook moeten helpen bij uw implantaat. Ik heb een paar ideeën die ik aan het schetsen ben en ik zal ze binnenkort klaar hebben. Wat kan ik voor je doen, misschien wat genezing?",,"Qual é a boa? Cara, essa tecnologia nova é simplesmente incrível. Isto também deve ajudar com o seu implante. Estou projetando umas idéias novas e logo mais devo ter elas prontas. Precisa de alguma coisa? Talvez cura?",,,"Как дела? О, среди этих новых технологий есть просто изумительные! Их можно применить при усовершенствовании твоего импланта. У меня есть парочка идей, которые я сейчас воплощаю в жизнь, и скоро всё будет готово. Чем я могу тебе помочь? Перевязкой?", -"Yes, heal me.",TXT_RPLY0_SCRIPT10_D22740_YESHE,,,,"Ano, ošetři mě.","Ja, mach mich gesund.",,,"Sí, cúrame.",,,"Oui, soignez-moi.",,,ああ、治してくれ。,네. 치료해주세요.,"Ja, genees me.",,"Sim, me cure.",,,"Да, перевяжи меня.", -"All right, here you go.",TXT_RYES0_SCRIPT10_D22740_ALLRI,,,,"Dobře, to by bylo.",Alles klar soweit.,,,"Muy bien, ya está.",,,"Très bien, bous pouvez y aller.",,,了解、始めましょう。,더욱 더 건강하게 치료했습니다.,"Oké, alsjeblieft.",,"Ok, pronto.",,,Хорошо. Уже готово., -How about that new tech?,TXT_RPLY1_SCRIPT10_D22740_HOWAB,,,,Co ta nová technologie?,Was ist mit der neuen Technologie?,,,¿Qué tal la nueva tecnología?,,,Quoi de nouveau pour cette technologie?,,,その新しい技術はどうだ?,세계 제일의 부품은 어떻습니까?,Hoe zit het met die nieuwe technologie?,,Me fale sobre essa nova tecnologia.,,,Как там с новыми технологиями?, -Let me know how this works.,TXT_RYES1_SCRIPT10_D22740_LETME,,,,"Dej mi vědět, jak to funguje.","Erklär mir, wie es funktioniert.",,,Cuéntame que tal funciona.,,,Dites-moi si ça fonctionne.,,,これでどんな調子か教えてくれ。,잘 작동되면 알려주시길!,Laat me weten hoe dit werkt.,,Me conte como funciona.,,,"Дай мне знать, если будут неполадки.", -I'm not done designing it yet.,TXT_RNO1_SCRIPT10_D22740_IMNOT,,,,Ještě s ní nejsem hotový.,Ich bin noch nicht fertig damit.,,,Aún no he terminado de diseñarla.,,,Je n'ai pas fini mon concept pour l'instant.,,,まだ完成していない。,설계가 아직 끝나지 않았어요.,Ik ben nog niet klaar met het ontwerpen ervan.,,Ainda não terminei de desenvolvê-la.,,,Я ещё не закончил с ними., -"Back again, don't you ever tire of this? I've got some good news, Feris found a way to increase the output of your implant. He gave the specs to me and I'm trying to get it to blend with your physiology. I'm force growing some tissue, totally new stuff here, I hope it takes. Do you need healing?",TXT_DLG_SCRIPT10_D24256_BACKA,,,,"Zase zpátky, nezmáhá tě to? Mám pro tebe dobrou zprávu, Feris našel způsob, jak zvýšit výkon tvého implantátu. Dal mi specifikace a snažím se je teď seřídit s tvou fyziologií. Nechávám růst tkáně, je to úplně nová technologie, snad to zabere. Potřebuješ ošetřit?","Schon wieder zurück, wird das nicht langweilig? Ivh habe gute Nachrichten. Feris hat eine Methode gefunden, um dein Implantat zu optimieren. Er hat mir die Spezifikationen gegeben und ich versuche, sie mit deiner Physiologie zu kombinieren. Ich lasse hier etwas Gewebe wachsen, völlig neues Zeug. Brauchst du medizinische Versorgung?",,,"¿De vuelta otra vez?, ¿nunca te cansas de esto? Tengo buenas noticias, Feris ha encontrado una forma de potenciar la salida de tu implante. Me ha dado las especificaciones y estoy intentando que se mezcle con tu fisiología. Estoy forzando el crecimiento de algunos tejidos, totalmente nuevos, espero que sirva. ¿Necesitas una cura?",,,"Déjà de retour? Vous n'êtes jamais fatigué, hein? J'ai de bonnes nouvelles. Feris à trouvé un moyen d'augementer la capacité de votre implant. Il m'a donné les spécifications et j'essaie de les faire correspondre à votre physiologie. Je suis en train de forcer la croissance de tissus, quelque chose de totalement nouveau. J'espère que ça fonctionnera. Vous avez besoin de soins?",,,"戻ったか、まだ疲れてないか?なら幾らか +すぐ準備しよう。それとも治療か何か必要かな?","별일 없으시죠? 세상에나, 오더의 과학력은 세계 제일이군요! 이식한 칩이랑 추가 설치가 가능한데, 성능을 향상해줄 거에요. 현재 부품을 더 설계하고 있습니다. 만약 준비가 되면 불러줄게요. 아무튼, 치료가 필요하신가요?","Hoe gaat het? Man, sommige van deze nieuwe technologie is gewoonweg verbazingwekkend. Dit zou ook moeten helpen bij uw implantaat. Ik heb een paar ideeën die ik aan het schetsen ben en ik zal ze binnenkort klaar hebben. Wat kan ik voor je doen, misschien wat genezing?","Hvordan går det? Noe av denne nye teknologien er helt utrolig. Dette burde også hjelpe med implantatet ditt. Jeg har et par ideer som jeg skisserer, og de er snart klare. Hva kan jeg gjøre for deg, kanskje litt healing?","Jak się masz? Człowieku... Te nowe +technologie są po prostu zarąbiste. +To powinno poprawić twój implant. +Mam parę pomysłów w zanadrzu +i niedługo postaram się je zrealizować. +Co mogę dla ciebie zrobić? Może +trochę podleczyć?","Qual é a boa? Cara, essa tecnologia nova é simplesmente incrível. Isto também deve ajudar com o seu implante. Estou projetando umas idéias novas e logo mais devo ter elas prontas. Precisa de alguma coisa? Talvez cura?",,"Cum merge? Frate, noua tehnologie e pur și simplu uimitoare. Asta ar trebui să îți ajute și implantul. Am câteva idei pe hârtie și le voi pune în aplicare curând. Ce pot face pentru tine, poate să te bandajez?","Как дела? О, среди этих новых технологий есть просто изумительные! Их можно применить при усовершенствовании твоего импланта. Я сейчас воплощаю в жизнь парочку идей, и скоро всё будет готово. Чем я могу тебе помочь, лечением?",,"Hur går det? En del av den här nya tekniken är helt enkelt fantastisk. Det här borde också hjälpa dig med ditt implantat. Jag har några idéer som jag skissar på och jag har dem klara snart. Vad kan jag göra för dig, kanske lite healing?","Nasıl gidiyor? Dostum, bu yeni teknolojinin bazıları tek kelimeyle inanılmaz. Bu implantına da yardımcı olacaktır. Taslağını çizdiğim birkaç fikir var, yakında hazır ederim. Senin için ne yapabilirim, belki biraz şifa?" +"Yes, heal me.",TXT_RPLY0_SCRIPT10_D22740_YESHE,〃,,,"Ano, ošetři mě.","Ja, helbrede mig.","Ja, mach mich gesund.",,"Jes, kuracu min.","Sí, cúrame.",,"Kyllä, paranna minut.","Oui, soignez-moi.","Igen, gyógyíts fel.","Sì, curami.",ああ、治してくれ。,네. 치료해주세요.,"Ja, genees me.","Ja, helbrede meg.","Tak, ulecz mnie.","Sim, me cure.",,"Da, bandajează-mă.","Да, полечи меня.",,"Ja, bota mig.","Evet, iyileştir beni." +"All right, here you go.",TXT_RYES0_SCRIPT10_D22740_ALLRI,〃,,,"Dobře, to by bylo.","Okay, værsgo.",Alles klar soweit.,,"Bone, farite.","Muy bien, ya está.",,"Hyvä on, tästä se lähtee.","Très bien, bous pouvez y aller.","Rendben, parancsolj.","Va bene, ecco fatto.",了解、始めましょう。,더욱 더 건강하게 치료했습니다.,"Oké, alsjeblieft.","Greit, vær så god.",Proszę bardzo.,"Ok, pronto.",,Gata.,Хорошо. Уже готово.,,"Okej, varsågod.","Pekala, al bakalım." +How about that new tech?,TXT_RPLY1_SCRIPT10_D22740_HOWAB,〃,,,Co ta nová technologie?,Hvad med den nye teknologi?,Was ist mit der neuen Technologie?,,Kio pri la nova teknologio?,¿Qué tal la nueva tecnología?,,Miten olisi se uusi teknologia?,Quoi de nouveau pour cette technologie?,Mi újság azzal az új technológiával?,E riguardo queste nuove technologie?,その新しい技術はどうだ?,세계 제일의 부품은 어떻습니까?,Hoe zit het met die nieuwe technologie?,Hva med den nye teknologien?,Co z tymi nowymi technologiami?,Me fale sobre essa nova tecnologia.,,Ce zici de tehnologia aceea nouă?,Как там с новыми технологиями?,,Vad sägs om den nya tekniken?,Şu yeni teknolojiye ne dersin? +Let me know how this works.,TXT_RYES1_SCRIPT10_D22740_LETME,〃,,,"Dej mi vědět, jak to funguje.","Lad mig vide, hvordan den virker.","Erklär mir, wie es funktioniert.",,Sciigu min vi mem.,Cuéntame que tal funciona.,,"Kerro sitten, miten se toimii.",Dites-moi si ça fonctionne.,"Majd mondd meg, hogy hogyan szuperál.",Fammi sapere come funziona.,これでどんな調子か教えてくれ。,잘 작동되면 알려주시길!,Laat me weten hoe dit werkt.,Fortell meg hvordan den virker.,Daj znać czy działa.,Me conte como funciona.,,Să-mi spui cum funcționează asta.,"Дай мне знать, если будут неполадки.",,Låt mig veta hur den fungerar.,Nasıl çalıştığını bana anlat. +I'm not done designing it yet.,TXT_RNO1_SCRIPT10_D22740_IMNOT,〃,,,Ještě s ní nejsem hotový.,Jeg er ikke færdig med at designe den endnu.,Ich bin noch nicht fertig damit.,,"Mi ankoraŭ +ne finis dezajni ĝin.",Aún no termino de diseñarla.,,Se on vielä kehitteillä.,Je n'ai pas fini mon concept pour l'instant.,Még nem végeztem a tervezéssel.,Non ho ancora finito il progetto.,まだ完成していない。,설계가 아직 끝나지 않았어요.,Ik ben nog niet klaar met het ontwerpen ervan.,Jeg er ikke ferdig med å designe den ennå.,Skończyłem już projektować.,Ainda não terminei de desenvolvê-la.,,Încă nu am terminat să o construiesc.,Я ещё не закончил с ними.,,Jag är inte klar med designen än.,Henüz tasarlamayı bitirmedim. +"Back again, don't you ever tire of this? I've got some good news, Feris found a way to increase the output of your implant. He gave the specs to me and I'm trying to get it to blend with your physiology. I'm force growing some tissue, totally new stuff here, I hope it takes. Do you need healing?",TXT_DLG_SCRIPT10_D24256_BACKA,〃 (four upgrades).,,,"Zase zpátky, nezmáhá tě to? Mám pro tebe dobrou zprávu, Feris našel způsob, jak zvýšit výkon tvého implantátu. Dal mi specifikace a snažím se je teď seřídit s tvou fyziologií. Nechávám růst nějaké tkáně, je to úplně nová technologie, snad to zabere. Potřebuješ ošetřit?","Tilbage igen, bliver du aldrig træt af det her? Jeg har gode nyheder. Feris har fundet en måde at øge dit implantats effekt på. Han gav mig specifikationerne, og jeg forsøger at få det til at passe ind i din fysiologi. Jeg tvinger noget væv til at vokse, helt nye ting her, jeg håber, det virker. Har du brug for healing?","Schon wieder zurück, wird das nicht langweilig? Ivh habe gute Nachrichten. Feris hat eine Methode gefunden, um dein Implantat zu optimieren. Er hat mir die Spezifikationen gegeben und ich versuche, sie mit deiner Physiologie zu kombinieren. Ich lasse hier etwas Gewebe wachsen, völlig neues Zeug. Brauchst du medizinische Versorgung?",,"Ĉu denove ĉi tie? Ĉu vi ne estas laca pri ĉi tio? Mi havas bonajn novaĵojn: Feriso trovis manieron pliigi la eligon de via enplantaĵo; li donis al mi la specifojn kaj mi provas miksi ĝin kun via fiziologio. Mi forcas kelkajn histojn, io tute nova, tio espereble prosperos. Ĉu vi bezonas kuraci vin?","¿De vuelta otra vez?, ¿no te cansas de esto? Tengo buenas noticias: Feris ha encontrado una forma de potenciar la salida de tu implante; me ha dado las especificaciones y estoy intentando mezclarlo con tu fisiología. Estoy forzando el crecimiento de algunos tejidos, algo totalmente nuevo, a ver si sirve. ¿Necesitas curarte?","¿De vuelta otra vez?, ¿no te cansas de esto? Tengo buenas noticias: Feris encontró una forma de potenciar la salida de tu implante; me dio las especificaciones y estoy tratando de mezclarlo con tu fisiología. Estoy forzando el crecimiento de algunos tejidos, algo totalmente nuevo, a ver si sirve. ¿Necesitas curarte?","Täällä taas? Eikö tämä ala jo kyllästyttää? No, minulla on hyviä uutisia: Feris keksi keinon parantaa istutteesi tehoa. Hän antoi minulle tekniset määritelmät, jotka yritän sovittaa sinun fysiologiaasi. Tehokasvatan tässä vähän kudosta; ihan huipputekniikasta siis kyse. Toivottavasti toimii. Tarvitsetko sairaanhoitoa?","Déjà de retour? Vous n'êtes jamais fatigué, hein? J'ai de bonnes nouvelles. Feris à trouvé un moyen d'augementer la capacité de votre implant. Il m'a donné les spécifications et j'essaie de les faire correspondre à votre physiologie. Je suis en train de forcer la croissance de tissus, quelque chose de totalement nouveau. J'espère que ça fonctionnera. Vous avez besoin de soins?","Máris visszajöttél...nem fáradtál még bele? Van amúgy jó hírem, Feris kitalálta, hogyan növeljük az implantátum hatékonyságát. Ide adta a specifikációkat, és most próbálom a testformádra szabni. Épp próbálok mesterségesen szövetet növeszteni, elég új ez nekem, remélem működni fog. Kell valami gyógyítás?","Di nuovo qua, non ti stanchi mai? Ho delle buone notizie, Feris ha trovato un modo per migliorare la performance del tuo impianto. Mi ha dato le schematiche, adesso devo adattarle alla tua fisiologia. Sto creando del nuovo tessuto qua nel laboratorio, spero vada bene. Comunque, hai bisogno di cure?","戻ったか、まだ疲れてないか?なら幾らか 良いニュースが届いた、フェリスが君の インプラント機能を増幅させる方法を見つけた。 彼がそのスペックを見せてくれたが、 君の生体機能に適合し細胞組織を 成長させるそうだ、これは全く新しいぞ。 -ところで治療が必要かい?","지루하지 않으신가요? 그리고 좋은 소식이 있는데, 페리스가 드디어 지구력 칩의 출력을 높일 방법을 찾아냈답니다. 그가 저에게 사양을 알려줬고, 당신의 인체 비율에 맞춰서 조정하는 중입니다. 이것이 지금 유기 조직을 강제로 생성하고 있어요. 참 신기할 따름입니다. 치료 필요하신가요?","Weer terug, word je hier nooit moe van? Ik heb goed nieuws, Feris heeft een manier gevonden om de output van jouw implantaat te verhogen. Hij gaf de specificaties aan mij en ik probeer het te mengen met jouw fysiologie. Ik ben bezig met het kweken van wat weefsel, totaal nieuw spul hier, ik hoop dat het nodig is. Heb je genezing nodig?",,"De volta mais uma vez. Você não se cansa disso? Tenho boas novas, Feris acho um jeito de aumentar o rendimento do seu implante. Ele me passou as especificações e estou tentando fazer ele se mesclar com a sua fisiologia. Estou criando tecidos novos, novidade total. Espero que sirva bem. Precisa de cura?",,,"Ты снова ранен? Тебе самому ещё не надоело? У меня для тебя хорошие новости: Ферис нашёл способ увеличить эффективность твоего импланта. Он дал мне схемы, и я пытаюсь подогнать имплант под твою физиологию. Я сейчас выращиваю кое-какие ткани. Раньше я никогда этого не делал, но надеюсь, что это сработает. Итак, тебе нужно лечение?", -"Yes, heal me.",TXT_RPLY0_SCRIPT10_D24256_YESHE,,,,"Ano, ošetři mě.","Ja, mach mich gesund.",,,"Sí, cúrame.",,,"Oui, soignez-moi.",,,ああ、治してくれ。,네. 치료해주세요.,"Ja, genees me.",,"Sim, me cure.",,,"Да, подлатай меня.", -"Done, now take care of yourself.",TXT_RYES0_SCRIPT10_D24256_DONEN,,,,"Hotovo, dávej na sebe pozor.","Alles klar, und nun pass auf dich auf.",,,"Hecho, ahora ve con cuidado.",,,"Fini, faites attention à vous.",,,完了した、御気を付けて。,치료 끝. 이제 가까이서 불장난하지 마시길!,"Klaar, zorg nu voor jezelf.",,Pronto. Agora vê se toma cuidado.,,,Сделано. Береги себя., -When will you be done?,TXT_RPLY1_SCRIPT10_D24256_WHENW,,,,Kdy s tím budeš hotov?,Wann wird es fertig sein?,,,¿Cuándo habrás terminado?,,,Quand aurez-vous fini?,,,いつ増幅できる?,칩 조정이 언제 끝나는지요?,Wanneer ben je klaar?,,Quando você vai terminar?,,,Когда он будет готов?, -"Now. Hey great, it worked!",TXT_RYES1_SCRIPT10_D24256_NOWHE,,,,"Teď. No ne, funguje to skvěle!","Oh, klasse. Es funktioniert.",,,"Ahora. Mira que bien, ¡Ha funcionado!",,,"Maintenant. Hé, super, ça à fonctionné!",,,すぐにでも。素晴らしい、上手くいった!,"세상에나, 정말로 작동하는군요!","Nu. Hé, geweldig, het heeft gewerkt!",,"Agora. Opa, beleza! Funcionou!",,,"Секунду. Отлично, он работает!", -I'm waiting on the tissue to finish its growth cycle.,TXT_RNO1_SCRIPT10_D24256_IMWAI,,,,"Čekám, než dorostou ty tkáně.","Ich muss warten, bis das Gewebe fertig gewachsen ist. ",,,Estoy esperando a que los tejidos terminen su ciclo de desarrollo.,,,J'attends que le tissu ait fini son cycle de croissance.,,,生体組織が成長しきるまで待つんだ。,조직이 다 자라날 때까지 기다리는 중입니다.,Ik wacht op het weefsel om de groeicyclus af te ronden.,,Estou esperando que o tecido termine seu ciclo de desenvolvimento.,,,Подожди. Мне нужно проследить за циклом роста клеток ткани., -"Well, I'm back up to my old tricks again, I'm still working on your implants. Did you know that Macil has now authorized them for everyone? No, huh? It's because you turned out so well. Anything I can do for you?",TXT_DLG_SCRIPT10_D25772_WELLI,,,,"Zase dělám to, co mi jde nejlépe, pracuju na tvých implantátech. Slyšel jsi, že Macil povolil jejich použití na všech vojácích? Že ne? Je to protože u tebe fungují tak dobře. Můžu pro tebe něco udělat?","Ich arbeite immer noch an deinem Implantat. Wußtest du schon, dass Macil sie für alle autorisiert hat? Nein, was? Hat er getan, weil es bei dir so gut funktioniert hat. Kann ich sonst was für dich tun?",,,"Bueno, vuelvo a las andadas otra vez, sigo trabajando en tus implantes. ¿Sabías que Macil ahora los ha autorizado para todos? No, ¿eh? Es por lo bien que te ha salido. ¿Algo que pueda hacer por ti?",,,"Eh bien, je suis de retour à mes vieux violons, je suis toujours en train de travailler sur vos implants. Vous saviez que Macil les a autorisé pour tous les soldats? Non, hein? C'est parce que vous vous en êtes tellement bien sorti. Que puis-je faire pour vous?",,,"さて、私は古い技術をバックアップして、 +ところで治療が必要かい?","지루하지 않으신가요? 그리고 좋은 소식이 있는데, 페리스가 드디어 지구력 칩의 출력을 높일 방법을 찾아냈답니다. 그가 저에게 사양을 알려줬고, 당신의 인체 비율에 맞춰서 조정하는 중입니다. 이것이 지금 유기 조직을 강제로 생성하고 있어요. 참 신기할 따름입니다. 치료 필요하신가요?","Weer terug, word je hier nooit moe van? Ik heb goed nieuws, Feris heeft een manier gevonden om de output van jouw implantaat te verhogen. Hij gaf de specificaties aan mij en ik probeer het te mengen met jouw fysiologie. Ik ben bezig met het kweken van wat weefsel, totaal nieuw spul hier, ik hoop dat het nodig is. Heb je genezing nodig?","Tilbake igjen, blir du aldri lei av dette? Jeg har gode nyheter. Feris har funnet en måte å øke effekten på implantatet ditt. Han ga meg spesifikasjonene, og jeg prøver å få det til å passe med fysiologien din. Jeg tvangsdyrker litt vev, noe helt nytt. Jeg håper det virker. Trenger du helbredelse?","Widzę, że wróciłeś. Nie męczy cię to? +Mam dobre wieści. Feris znalazł +sposób, by ulepszyć twój implant. +Dał mi całą dokumentację i teraz +staram się dostosować go do twojej +fizjologii. Wymuszam tworzenie +nowej tkanki. To zupełnie nowa +technologia. Mam nadzieję, że +zadziała. Potrzebujesz leczenia?","De volta mais uma vez. Você não se cansa disso? Tenho boas novas, Feris acho um jeito de aumentar o rendimento do seu implante. Ele me passou as especificações e estou tentando fazer ele se mesclar com a sua fisiologia. Estou criando tecidos novos, novidade total. Espero que sirva bem. Precisa de cura?",,"Te-ai întors din nou, nu te plictisești niciodată? Am niște vești bune, Feris a descoperit o metodă de a îți îmbunătății implantul. Mi-a dat specificațiile și acum încerc să îl combin cu fizicul tău. Cresc forțat niște țesut, ceva complet nou. Ai nevoie de asistență?","Ты снова ранен? Тебе самому ещё не надоело? У меня для тебя хорошие новости: Ферис нашёл способ увеличить эффективность твоего импланта. Он дал мне схемы, и я пытаюсь подогнать имплант под твою физиологию. Я сейчас выращиваю кое-какие ткани. Раньше я никогда этого не делал, но надеюсь, что это сработает. Итак, тебе нужно лечение?",,"Tillbaka igen, tröttnar du aldrig på det här? Jag har goda nyheter, Feris har hittat ett sätt att öka effekten av ditt implantat. Han gav specifikationerna till mig och jag försöker få det att smälta in i din fysiologi. Jag tvångsodlar lite vävnad, helt nya saker här, jag hoppas att det fungerar. Behöver du läkning?","Yine başladık, bundan hiç bıkmadın mı? İyi haberlerim var. Feris implantının gücünü arttırmanın bir yolunu buldu. Özellikleri bana verdi ve ben de senin fizyolojinle uyumlu hale getirmeye çalışıyorum. Biraz doku büyütmeye zorluyorum, tamamen yeni şeyler, umarım tutar. İyileşmeye ihtiyacın var mı?" +"Yes, heal me.",TXT_RPLY0_SCRIPT10_D24256_YESHE,〃,,,"Ano, ošetři mě.","Ja, helbrede mig.","Ja, mach mich gesund.",,"Jes, kuracu min.","Sí, cúrame.",,"Kyllä, paranna minut.","Oui, soignez-moi.","Igen, gyógyíts fel.","Sì, curami.",ああ、治してくれ。,네. 치료해주세요.,"Ja, genees me.","Ja, helbred meg.","Tak, ulecz mnie.","Sim, me cure.",,"Da, bandajează-mă.","Да, полечи меня.",,"Ja, bota mig.","Evet, iyileştir beni." +"Done, now take care of yourself.",TXT_RYES0_SCRIPT10_D24256_DONEN,〃,,,"Hotovo, dávej na sebe pozor.",Færdig. Pas nu på dig selv.,"Alles klar, und nun pass auf dich auf.",,"Farite, nun estu singarda.","Hecho, ahora ve con cuidado.",,Noin. Pidä itsestäsi huoli.,"Fini, faites attention à vous.","Kész is, vigyázz magadra.","Fatto, abbi cura di te.",完了した、御気を付けて。,치료 끝. 이제 가까이서 불장난하지 마시길!,"Klaar, zorg nu voor jezelf.","Ferdig, ta vare på deg selv.",Gotowe. Uważaj na siebie.,Pronto. Agora vê se toma cuidado.,,"Gata, acum ai grijă de tine.",Сделано. Береги себя.,,"Klart, ta hand om dig själv nu.","Bitti, şimdi kendine iyi bak." +When will you be done?,TXT_RPLY1_SCRIPT10_D24256_WHENW,〃,,,Kdy s tím budeš hotov?,Hvornår er du færdig?,Wann wird es fertig sein?,,Kiam vi finos?,¿Cuándo habrás terminado?,,Milloin kudos on valmis?,Quand aurez-vous fini?,Mikor leszel kész?,Quando avrai finito?,いつ増幅できる?,칩 조정이 언제 끝나는지요?,Wanneer ben je klaar?,Når er du ferdig?,Kiedy skończysz?,Quando você vai terminar?,,Când vei fi gata?,Когда он будет готов?,,När är du klar?,İşin ne zaman bitecek? +"Now. Hey great, it worked!",TXT_RYES1_SCRIPT10_D24256_NOWHE,〃,,,"Teď. No ne, funguje to skvěle!","Når du er færdig? Nu. Hej, godt, det virkede!","Oh, klasse. Es funktioniert.",,"Nun. Bonege, +ĝi funkciis!","Ahora. Mira qué bien, +¡ha funcionado!","Ahora. Mira qué bien, +¡funcionó!","Nyt. Hei, sehän toimii; hienoa!","Maintenant. Hé, super, ça à fonctionné!","Épp most. Marha jó, működik!","Adesso. Ehi, fantastico, ha funzionato!",すぐにでも。素晴らしい、上手くいった!,"세상에나, 정말로 작동하는군요!","Nu. Hé, geweldig, het heeft gewerkt!","Nå. Flott, det virket!",Już. Hej! Udało się! Działa!,"Agora. Opa, beleza! Funcionou!",,"Acum. Hei grozav, a mers!","Секунду. Отлично, он работает!",,"Nu. Bra, det fungerade!","Şimdi. Hey harika, işe yaradı!" +I'm waiting on the tissue to finish its growth cycle.,TXT_RNO1_SCRIPT10_D24256_IMWAI,〃,,,"Čekám, než dorostou ty tkáně.","Jeg venter på, at vævet afslutter sin vækstcyklus.","Ich muss warten, bis das Gewebe fertig gewachsen ist. ",,"Mi atendas, ke la disvolviĝa +ciklo de la histoj finiĝos.","Estoy esperando a que los tejidos +terminen su ciclo de desarrollo.",,Odotan kudoksen kasvusyklin päättymistä.,J'attends que le tissu ait fini son cycle de croissance.,"Épp arra várok, hogy a szövet a növekedési ütemet elérje.",Sto aspettando che i tessuti finiscano la crescita per questo ciclo.,生体組織が成長しきるまで待つんだ。,조직이 다 자라날 때까지 기다리는 중입니다.,Ik wacht op het weefsel om de groeicyclus af te ronden.,Jeg venter på at vevet skal fullføre vekstsyklusen.,Czekam aż cykl odrastania tkanki się skończy.,Estou esperando que o tecido termine seu ciclo de desenvolvimento.,,Aștept ca țesutul să își continue ciclul de dezvoltare.,Подожди. Я жду коца цикла роста клеток ткани.,,Jag väntar på att vävnaden ska avsluta sin tillväxtcykel.,Dokunun büyüme döngüsünü tamamlamasını bekliyorum. +"Well, I'm back up to my old tricks again, I'm still working on your implants. Did you know that Macil has now authorized them for everyone? No, huh? It's because you turned out so well. Anything I can do for you?",TXT_DLG_SCRIPT10_D25772_WELLI,〃 (five upgrades).,,,"Zase dělám to, co mi jde nejlépe, pracuju na tvých implantátech. Slyšel jsi, že Macil povolil jejich použití na všech vojácích? Ne? Je to protože u tebe fungují tak dobře. Můžu pro tebe něco udělat?","Nå, jeg er tilbage til mine gamle tricks igen, jeg arbejder stadig på dine implantater. Vidste du, at Macil nu har godkendt dem til alle? Nej, hva'? Det er fordi du blev så godt. Er der noget, jeg kan gøre for dig?","Ich arbeite immer noch an deinem Implantat. Wußtest du schon, dass Macil sie für alle autorisiert hat? Nein, was? Hat er getan, weil es bei dir so gut funktioniert hat. Kann ich sonst was für dich tun?",,"Nu, mi refalas miajn malnovajn trompojn: mi ankoraŭ prilaboras viajn enplantaĵojn. Ĉu vi sciiĝis, ke Macil nun rajtigis ilian uzadon al ĉiuj? Ne, ĉu? Danke al viaj bonegaj rezultoj. Ĉu mi povas fari ion por vi?","Bueno, vuelvo a las andadas otra vez: sigo trabajando en tus implantes. ¿Sabías que Macil ahora los ha autorizado para todos? No, ¿eh? Es por lo bien que te ha salido. ¿Algo que pueda hacer por ti?","Bueno, vuelvo a las andadas otra vez: sigo trabajando en tus implantes. ¿Sabías que Macil ahora los autorizó para todos? No, ¿eh? Es por lo bien que te ha salido. ¿Algo que pueda hacer por ti?","Olen taas palannut kyhäilyjeni pariin; työstän edelleenkin istutteitasi. Tiesitkö muuten, että Macil on valtuuttanut ne nyt kaikille? Ai et? No, ihan sen takia, kun sinä satuit onnistumaan niin hyvin. Mutta, mitä saisi olla?","Eh bien, je suis de retour à mes vieux violons, je suis toujours en train de travailler sur vos implants. Vous saviez que Macil les a autorisé pour tous les soldats? Non, hein? C'est parce que vous vous en êtes tellement bien sorti. Que puis-je faire pour vous?","Visszatértem a régi kerékvágásba, és újból fejlesztgetem az implantátumodat. Tudtad, hogy Macil mindenki számára engedélyezte őket? Nem, mi? Azért mert a Te esetedben nagyon jól bevállt. Segíthetek még neked valamiben?","Ebbene, sono di nuovo alle prese con questi impianti, inclusi i tuoi. Lo sapevi che Macil adesso li ha autorizzati per tutti? No, eh? È poiché sei venuto fuori così bene. Posso fare qualcosa per te?","さて、私は古い技術をバックアップして、 インプラントに更なる取り組みを試している。 マシルがそれを全員に着けるのを承認したのは 聞いたか?まだ?君が上手くやってくれたからな。 -何か出来ることはあるかい?","오늘만큼은 구식으로 연구를 해야 할 것 같군요. 이식 칩의 숨겨진 비밀을 찾아냈거든요. 그나저나, 마실 사령관님이 모든 병력에 이 칩을 이식하라고 명령하셨는데, 아시나요? 당신 덕에 실험이 공인됐으니까요! 원하시는 게 있으신가요?","Nou, ik ben weer terug bij mijn oude trucs, ik ben nog steeds bezig met je implantaten. Wist je dat Macil ze nu voor iedereen heeft goedgekeurd? Nee, hè? Dat komt omdat je zo goed bent geworden. Kan ik iets voor u doen?",,"Bem, estou de volta aos meus velhos truques novamente. Ainda estou trabalhando nos seus implantes. Você sabia que Macil os autorizou pra todo mundo? Ah não? É porque eles funcionaram muito bem em você. Precisa de alguma coisa?",,,"Я снова вернулся к старым занятиям и по-прежнему работаю над твоим имплантом. Ты знаешь, что Мэйсил теперь всем разрешил использовать импланты? Нет? Это потому что ты так хорошо показал себя. Могу я чем-нибудь тебе помочь?", -Help me out here.,TXT_RPLY0_SCRIPT10_D25772_HELPM,,,,Pomoz mi.,Hilf mir mal.,,,Ayúdame.,,,Aidez moi.,,,ここで治してくれ。,나 좀 치료해줘요.,Help me hier.,,Preciso de uma ajuda aqui.,,,Помоги мне вот с этим., -That's all I can do.,TXT_RYES0_SCRIPT10_D25772_THATS,,,,"To je vše, co mohu udělat.","Da ist alles, was ich tun kann.",,,Eso es todo lo que puedo hacer.,,,C'est tout ce que je peux faire.,,,私が出来る事はここまでだ。,좀 치료해줬습니다. 이제 어떠신가요?,Dat is alles wat ik kan doen.,,Isso é tudo o que posso fazer.,,,"Это всё, что я могу сделать.", -New implant?,TXT_RPLY1_SCRIPT10_D25772_NEWIM,,,,Nový implantát?,Neues Implantat?,,,¿Nuevo implante?,,,Un nouvel implant?,,,新しいインプラントは?,새로운 이식 칩?,Een nieuw implantaat?,,Implante novo?,,,Новый имплант?, -"Yep, my best one yet.",TXT_RYES1_SCRIPT10_D25772_YEPMY,,,,"Jo, můj zatím nejlepší.","Ja, mein bestes bisher.",,,"Si, el mejor que tengo.",,,"Oui, le meilleur que j'ai jamais conçu.",,,よし、これは傑作だ。,있죠. 제 생각엔 아주 좋은 품질인 것 같아요.,"Ja, mijn beste tot nu toe.",,Isso mesmo. O melhor que já fiz até agora.,,,Да. Моё лучшее творение., -"Sorry, but you just have to wait.",TXT_RNO1_SCRIPT10_D25772_SORRY,,,,"Promiň, ještě budeš muset počkat.","Tut mir leid, du musst noch warten.",,,"Lo siento, pero tendrás que esperar.",,,"Désolé, il faudra attendre encore.",,,すまない、だがもうすぐ出来そうだ。,시간을 좀 더 주신다면...,"Sorry, maar je moet gewoon wachten.",,"Desculpe, mas você vai ter que esperar.",,,"Прости, но тебе придётся подождать.", -"This is it, Feris has managed to drain everything he could out of all the data we have, this will the best, and last implant upgrade. It will be sort of depressing, seeing my best creation reach its peak. Well, at least the rest of this crew will keep me occupied.",TXT_DLG_SCRIPT10_D27288_THISI,,,,"A je to, Feris vyždímal všechno, co mohl z dat, které máme. Tohle bude poslední a nejlepší implantátový upgrade. Bude to trochu smutné, vidět můj výtvor dosáhnout vrcholu. No, alespoň budu zaneprázdněný zbytkem posádky.","Das ist es, Feris hat aus den Daten alles herausgeholt, was möglich war. Das wird das beste und letzte Upgrade sein. Irgendwie deprimierend zu sehen, dass meine beste Erfindung ihren Höhepunkt erreicht hat. Nun ja, wenigstens wird der Rest dieser Truppe mich lange genug beschäftigen.",,,"Ya está, Feris ha conseguido exprimir todo lo que ha podido de los datos que tenemos, este va a ser la mejor, y última mejora del implante. Es un poco triste ver mi mejor creación llegar a su cima. Bueno, al menos el resto del personal me mantendrá ocupado.",,,"C'est fini, Feris a réussi à tirer tout ce qu'on pouvait des données que l'on a récupéré. Ce sera la dernière, et meilleure mise à jour. C'est un peu déprimant, de savoir que ma meilleure invention à déjà atteint son pinnacle.. Bon, au moins, le reste de l'équipe me gardera occupé.",,,"いよいよだ、フェリスが我々の保管していた +何か出来ることはあるかい?","오늘만큼은 구식으로 연구를 해야 할 것 같군요. 이식 칩의 숨겨진 비밀을 찾아냈거든요. 그나저나, 마실 사령관님이 모든 병력에 이 칩을 이식하라고 명령하셨는데, 아시나요? 당신 덕에 실험이 공인됐으니까요! 원하시는 게 있으신가요?","Nou, ik ben weer terug bij mijn oude trucs, ik ben nog steeds bezig met je implantaten. Wist je dat Macil ze nu voor iedereen heeft goedgekeurd? Nee, hè? Dat komt omdat je zo goed bent geworden. Kan ik iets voor u doen?","Vel, jeg er tilbake til mine gamle triks igjen, jeg jobber fortsatt med implantatene dine. Visste du at Macil nå har godkjent dem for alle? Ikke det? Det er fordi det gikk så bra med deg. Er det noe jeg kan gjøre for deg?","Cóż... wróciłem znów do starych +zwyczajów. Dalej pracuję nad +implantami dla ciebie. Wiedziałeś, że +Macil udostępnił je dla wszystkich? +Nie wiesz? Wszystko dzięki temu, że +sobie poradziłeś. Mogę coś jeszcze +dla ciebie zrobić? +","Bem, estou de volta aos meus velhos truques novamente. Ainda estou trabalhando nos seus implantes. Você sabia que Macil os autorizou pra todo mundo? Ah não? É porque eles funcionaram muito bem em você. Precisa de alguma coisa?",,"Păi, m-am întors la treburile mele vechi, încă lucrez la implanturile tale. Știi că Macil a vrut să le autorizeze pentru toată lumea? Nu, așa-i? E din cauză că ai ieșit prea bine. Pot face ceva pentru tine?","Я снова вернулся к старым занятиям и по-прежнему работаю над твоим имплантом. Ты знаешь, что Мэйсил теперь всем разрешил использовать импланты? Нет? Это потому, что ты так хорошо показал себя. Могу я чем-нибудь тебе помочь?",,"Jag är tillbaka till mina gamla tricks igen, jag jobbar fortfarande på dina implantat. Visste du att Macil nu har godkänt dem för alla? Nej, va? Det är för att du blev så bra. Är det något jag kan göra för dig?","Yine eski numaralarıma döndüm. Hâlâ implantların üzerinde çalışıyorum. Macil'in artık herkes için onay verdiğini biliyor muydun? Hayır, ha? Bu kadar iyi olduğun için. Senin için yapabileceğim bir şey var mı?" +Help me out here.,TXT_RPLY0_SCRIPT10_D25772_HELPM,〃,,,Pomoz mi.,Hjælp mig lige her.,Hilf mir mal.,,Helpu min.,Ayúdame.,,Autatko vähän.,Aidez moi.,Segíts nekem egy kicsit.,Aiutami.,ここで治してくれ。,나 좀 치료해줘요.,Help me hier.,Hjelp meg her.,Pomóż mi.,Preciso de uma ajuda aqui.,,Dă-mi o mână de ajutor.,Помоги мне вот с этим.,,Hjälp mig här.,Bana yardım et. +That's all I can do.,TXT_RYES0_SCRIPT10_D25772_THATS,〃,,,"To je vše, co mohu udělat.","Det er det eneste, jeg kan gøre.","Da ist alles, was ich tun kann.",,"Tio estas ĉio, +kion mi povas fari.","Eso es todo +lo que puedo hacer.",,"Tässä kaikki, mitä voin tehdä.",C'est tout ce que je peux faire.,Csak ennyit tudtam tenni.,È tutto quello che posso fare.,私が出来る事はここまでだ。,좀 치료해줬습니다. 이제 어떠신가요?,Dat is alles wat ik kan doen.,Det er alt jeg kan gjøre.,To wszystko co mogę zrobić.,Isso é tudo o que posso fazer.,,Asta e tot ceea ce pot face.,"Это всё, что я могу сделать.",,Det är allt jag kan göra.,Tek yapabileceğim bu. +New implant?,TXT_RPLY1_SCRIPT10_D25772_NEWIM,〃,,,Nový implantát?,Nyt implantat?,Neues Implantat?,,Ĉu nova enplantaĵo?,¿Nuevo implante?,,Uusi istute?,Un nouvel implant?,Új implantátum?,Nuovo impianto?,新しいインプラントは?,새로운 이식 칩?,Een nieuw implantaat?,Nytt implantat?,Nowy implant?,Implante novo?,,Implant nou?,Новый имплант?,,Nytt implantat?,Yeni implant mı? +"Yep, my best one yet.",TXT_RYES1_SCRIPT10_D25772_YEPMY,〃,,,"Jo, můj zatím nejlepší.","Ja, mit bedste endnu.","Ja, mein bestes bisher.",,"Jes, la plej bona, +kiun mi havas.","Sí, el mejor que tengo.",,"Jep, tähänastisista istutteistani paras.","Oui, le meilleur que j'ai jamais conçu.","Igen, az egyik legjobb változat eddig.","Si, il migliore che ho creato fin'ora.",よし、これは傑作だ。,있죠. 제 생각엔 아주 좋은 품질인 것 같아요.,"Ja, mijn beste tot nu toe.","Ja, mitt beste hittil.",Tak. Najlepszy jaki dotychczas zrobiłem.,Isso mesmo. O melhor que já fiz até agora.,,"Da, cel mai bun, momentan.",Да. Моё лучшее творение.,,"Japp, mitt bästa hittills.","Evet, şimdiye kadarki en iyisi." +"Sorry, but you just have to wait.",TXT_RNO1_SCRIPT10_D25772_SORRY,〃,,,"Promiň, ještě budeš muset počkat.","Beklager, men du må bare vente.","Tut mir leid, du musst noch warten.",,"Pardonon, sed +vi devas atendi.","Lo siento, pero +tendrás que esperar.","Lo siento, pero +vas a tener que esperar.","Pahoittelen, sinun täytyy vain vielä vähän odottaa.","Désolé, il faudra attendre encore.","Sajnálom, de várnod kell egy kicsit.","Mi spiace, ma devi attendere un poco.",すまない、だがもうすぐ出来そうだ。,시간을 좀 더 주신다면...,"Sorry, maar je moet gewoon wachten.","Beklager, men du må bare vente.","Wybacz, ale musisz poczekać.","Desculpe, mas você vai ter que esperar.",,"Scuze, dar trebuie să mai aștepți.","Прости, но тебе придётся подождать.",,"Ledsen, men du måste vänta.",Üzgünüm ama beklemek zorundasın. +"This is it, Feris has managed to drain everything he could out of all the data we have, this will be the best, and last implant upgrade. It will be sort of depressing, seeing my best creation reach its peak. Well, at least the rest of this crew will keep me occupied.",TXT_DLG_SCRIPT10_D27288_THISI,〃 (six upgrades).,,,"A je to, Feris vyždímal všechno, co mohl, z dat, která máme. Tohle bude poslední a nejlepší implantátový upgrade. Bude mi trochu smutno, vidět můj výtvor dosáhnout vrcholu. No, alespoň budu zaneprázdněný zbytkem armády.","Det er nu, Feris har formået at dræne alt hvad han kunne ud af alle de data vi har, dette bliver den bedste, og sidste implantatopgradering. Det bliver lidt deprimerende at se min bedste skabelse nå sit højdepunkt. I det mindste vil resten af besætningen holde mig beskæftiget.","Das ist es, Feris hat aus den Daten alles herausgeholt, was möglich war. Das wird das beste und letzte Upgrade sein. Irgendwie deprimierend zu sehen, dass meine beste Erfindung ihren Höhepunkt erreicht hat. Nun ja, wenigstens wird der Rest dieser Truppe mich lange genug beschäftigen.",,"Jen ĉio, Feriso jam ekspluatis kiel eble plej multe de niaj havataj datenoj: tiu estis la lasta kaj plej bona versio de la enplantaĵo. Estas iom malfeliĉige vidi, ke mia plej bona kreaĵo atingis la supron. Nu, almenaŭ la resto de la personaro tenos min okupata.","Ya está, Feris ya ha exprimido todo lo que se podía de los datos que tenemos: esa ha sido la mejor y última versión del implante. Es un poco triste ver mi mejor creación llegar a su cima. Bueno, al menos el resto del personal me mantendrá ocupado.","Ya está, Feris ya exprimió todo lo que se podía de los datos que tenemos: esa fue la mejor y última versión del implante. Es un poco triste ver mi mejor creación llegar a su cima. Bueno, al menos el resto del personal me va a mantener ocupado.","Tässä se nyt on; Feriksen on onnistunut puristaa kaiken ulos kaikesta käsissämme olevasta datasta. Tämä tulee olemaan istutteen paras ja viimeinen kehitysaskel. Vähän jotenkin masentavaa nähdä parhaan luomuksensa saavuttavan huippunsa. No, saanpahan sentään edes puuhaa lopuista tästä miehistöstä.","C'est fini, Feris a réussi à tirer tout ce qu'on pouvait des données que l'on a récupéré. Ce sera la dernière, et meilleure mise à jour. C'est un peu déprimant, de savoir que ma meilleure invention à déjà atteint son pinnacle.. Bon, au moins, le reste de l'équipe me gardera occupé.","Ez lesz a végkifejlett, Ferisnek sikerült kipréselni minden adatot, ez lesz a legjobb és egyben utolsó implantátum fejlesztés. Kicsit hervasztó érzés látni munkám gyümölcsének végkifejlettségét. Na de legalább a csapat többi része le fog foglalni.","Ecco qua, Feris è riuscito ad estrarre tutto quello che poteva dai dati che possediamo, e questo sarà il migliore, nonché l'ultimo, aggiornamento dell'impianto. In un certo senso sarà un po' deprimente, vedere la mia migliore creazione raggiungere l'apice. Se non altro, il resto di questa squadra mi terrà occupato.","いよいよだ、フェリスが我々の保管していた 全てのデータから全力を尽くして編み出した、 これが最高で最後のインプラント アップグレードだ。が、私にこれ以上の創造に 携われなくなるのは一種の憂鬱でもある。 -まあ、少なくとも隊員と私の休息は残っているな。","마무리가 다 됐습니다. 페리스가 젖 먹던 힘까지 정보란 정보를 다 긁어모아서 연구했습니다. 한마디로, 이게 마지막 향상 칩 연구일 거라는 거죠. 우리들의 최선을 벗어나지 못한 건 꽤 섭섭하지만, 연구하랴 이식하랴 바쁜 업무에 시달리지는 않을 테니 다행인 듯싶어요!","Dat is alles, Feris heeft alles uit de gegevens gehaald wat mogelijk was. Dit wordt de beste en laatste upgrade. Op de een of andere manier deprimerend om te zien dat mijn beste uitvinding zijn hoogtepunt heeft bereikt. Nou ja, de rest van deze groep zal me tenminste lang genoeg bezig houden.",,"É isso aí, Feris conseguiu tirar tudo que foi possível dos dados que temos. Este será a melhor e a última aprimoração do implante. Vai ser meio triste, vendo minha melhor criação chegar no seu ápice. Bom, pelo menos o resto do pessoal vai me manter ocupado.",,,"Вот и всё. Ферису удалось вытянуть всё, что только можно, из тех данных, которыми мы располагаем. Это лучшая и последняя модификация импланта. Немного грустно видеть, что твоё творение достигло своего предела. Ну, по крайней мере, я всё ещё нужен остальной части команды.", -Could you heal me?,TXT_RPLY0_SCRIPT10_D27288_COULD,,,,Mohl bys mě ošetřit?,Kannst du mich gesund machen?,,,¿Podrías curarme?,,,Vous pouvez me soigner?,,,治してくれるか?,절 치료해줄 수 있나요?,Kunt je me genezen?,,Poderia me curar?,,,Вылечишь меня?, -"There, you're all set now.",TXT_RYES0_SCRIPT10_D27288_THERE,,,,"Tak, a jsi hotov.","So, das wär's dann.",,,"Ya está, listo.",,,"Voilà, vous pouvez y aller.",,,これで、準備完了だ。,"자, 이제 안전할 겁니다.",Daar ben je nu helemaal klaar.,,Feito. Tudo certo agora.,,,Конечно. Теперь ты в норме., -It's the hero. Great job! What can I get for you? We've got a little larger selection now that we have all the ordinance from the castle. If you need to buy some ammo talk to Justin. He'll take care of you. ,TXT_DLG_SCRIPT10_D28804_ITSTH,,,,"Je to náš hrdina. Skvělá práce! Co ti můžu sehnat? Máme trochu větší výběr, když teď máme přístup ke všemu vybavení z hradu. Jestli potřebuješ munici, zeptej se Justina, on si s tebou poradí.","Das ist der Held. Guter Job! Was kann ich für dich tun. Wir haben jetzt eine größere Auswahl nachdem wir die Burg geplündert haben. Wenn du noch Munition brauchst, wende dich an Justin. Er kümmert sich darum.",,,Es el héroe. ¡Buen trabajo! ¿Qué puedo ofrecerte? Tenemos una selección un poco más amplia ahora que tenemos todo el arsenal del castillo. Si necesitas comprar municiones habla con Justin. Él se ocupará de ti.,,,"Voilà notre héros! Fantastique travail! Que puis-je faire pour vous? Nous avons étendu notre séléction maintenant que nous avons l'arsenal du château à notre disposition. Si vous avez besoin de munitions, parlez à Justin. Il s'occupera de vous.",,,"正に英雄、流石です! +まあ、少なくとも隊員と私の休息は残っているな。","마무리가 다 됐습니다. 페리스가 젖 먹던 힘까지 정보란 정보를 다 긁어모아서 연구했습니다. 한마디로, 이게 마지막 향상 칩 연구일 거라는 거죠. 우리들의 최선을 벗어나지 못한 건 꽤 섭섭하지만, 연구하랴 이식하랴 바쁜 업무에 시달리지는 않을 테니 다행인 듯싶어요!","Dat is alles, Feris heeft alles uit de gegevens gehaald wat mogelijk was. Dit wordt de beste en laatste upgrade. Op de een of andere manier deprimerend om te zien dat mijn beste uitvinding zijn hoogtepunt heeft bereikt. Nou ja, de rest van deze groep zal me tenminste lang genoeg bezig houden.",Feris har tappet alt han kunne ut av alle dataene vi har. Dette blir den beste og siste implantatoppgraderingen. Det blir deprimerende å se min beste skapelse nå sitt høydepunkt. Resten av mannskapet vil i det minste holde meg opptatt.,"To jest to. Ferisowi udało się zdobyć +wszystkie możliwe dane. To będzie +najlepsze i ostatnie ulepszenie +implantu. To trochę smutne, że moje +dzieło tak szybko osiągnęło szczyt +możliwości. Cóż... przynajmniej będę +mógł zająć się resztą załogi.","É isso aí, Feris conseguiu tirar tudo que foi possível dos dados que temos. Este será a melhor e a última aprimoração do implante. Vai ser meio triste, vendo minha melhor criação chegar no seu ápice. Bom, pelo menos o resto do pessoal vai me manter ocupado.",,"Asta e, Feris a reușit să stoarcă tot din datele pe care le avem, acesta e ultimul, și cel mai bun upgrade pentru implant. Va fi oarecum deprimant, să-mi văd creația ajungând în vârf. Măcar restul echipajului mă va ține ocupat.","Вот и всё. Из тех данных, которыми мы располагаем, Ферису удалось вытянуть всё, что только можно. Это лучшая и последняя модификация импланта. Немного грустно видеть, что твоё творение достигло своего предела. Ну, по крайней мере, я всё ещё нужен остальной части команды.",,"Det här är det, Feris har lyckats dränera allt han kunde ur all data vi har, det här kommer att bli den bästa, och sista implantatuppgraderingen. Det kommer att bli lite deprimerande att se min bästa skapelse nå sin höjdpunkt. Tja, resten av besättningen kommer åtminstone att hålla mig sysselsatt.","İşte bu, Feris elimizdeki tüm verilerden çekebildiği her şeyi çekmeyi başardı, bu en iyi ve son implant güncellemesi olacak. En iyi eserimin zirveye ulaştığını görmek biraz iç karartıcı olacak. En azından bu mürettebatın geri kalanı beni meşgul edecek." +Could you heal me?,TXT_RPLY0_SCRIPT10_D27288_COULD,〃,,,Mohl bys mě ošetřit?,Kan du helbrede mig?,Kannst du mich gesund machen?,,Ĉu vi kuracus min?,¿Podrías curarme?,,Voisitko hoitaa minua?,Vous pouvez me soigner?,Fel tudnál gyógyítani?,Puoi curarmi?,治してくれるか?,절 치료해줄 수 있나요?,Kunt je me genezen?,Kan du helbrede meg?,Możesz mnie uleczyć?,Poderia me curar?,,Mă poți bandaja?,Вылечишь меня?,,Kan du läka mig?,Beni iyileştirebilir misin? +"There, you're all set now.",TXT_RYES0_SCRIPT10_D27288_THERE,〃,,,"Tak, a jsi hotov.","Sådan, du er klar nu.","So, das wär's dann.",,"Farite, vi nun +estas en ordo.","Ya está, listo.",,"Siinä, kaikki kunnossa.","Voilà, vous pouvez y aller.","Parancsolj, harcra kész vagy.","Certo, ora sei apposto.",これで、準備完了だ。,"자, 이제 안전할 겁니다.",Daar ben je nu helemaal klaar.,"Sånn, nå er du klar.",Proszę. Wszystko gotowe.,Feito. Tudo certo agora.,,"Gata, ești pregătit.",Конечно. Теперь ты в норме.,,"Så där, du är redo nu.","İşte, şimdi hazırsın." +It's the hero. Great job! What can I get for you? We've got a little larger selection now that we have all the ordinance from the castle. If you need to buy some ammo talk to Justin. He'll take care of you. ,TXT_DLG_SCRIPT10_D28804_ITSTH,MAP10: Feris (no training).,,,"Je to náš hrdina. Skvělá práce! Co ti můžu sehnat? Máme trochu větší výběr, když teď máme přístup ke všemu vybavení z hradu. Jestli potřebuješ munici, zeptej se Justina, on si s tebou poradí.","Det er helten. Godt gået! Hvad kan jeg skaffe til dig? Vi har et lidt større udvalg nu, hvor vi har alle ordinationerne fra slottet. Hvis du har brug for at købe noget ammunition, så tal med Justin. Han vil tage sig af dig.","Das ist der Held. Guter Job! Was kann ich für dich tun. Wir haben jetzt eine größere Auswahl nachdem wir die Burg geplündert haben. Wenn du noch Munition brauchst, wende dich an Justin. Er kümmert sich darum.",,"La heroo. Bonege farite! Kion mi donu al vi? Estas elektaĵo iomete pli granda nun kiam ni havas la tutan arsenalon de la kastelo. Se vi bezonas plian municion, parolu kun Justin: li solvos tion.","Es el héroe. ¡Muy bien hecho! ¿Qué puedo ofrecerte? Hay una selección un poco más amplia ahora que tenemos todo el arsenal del castillo. Si necesitas comprar munición, habla con Justin: él se ocupará de ti.","Es el héroe. ¡Muy bien hecho! ¿Qué puedo ofrecerte? Hay una selección un poco más amplia ahora que tenemos todo el arsenal del castillo. Si necesitas comprar munición, habla con Justin: él se va a ocupar de ti.","Sankarimmehan se siinä; hyvää työtä! Miten voin olla avuksi? Meillä on hieman suurempi valikoima nyt, kun olemme saaneet käsiimme linnan kaikki asetarvikkeet. Jos sinun tarvitsee ostaa ammuksia, puhu Justinille. Hän hoitaa tarpeesi.","Voilà notre héros! Fantastique travail! Que puis-je faire pour vous? Nous avons étendu notre séléction maintenant que nous avons l'arsenal du château à notre disposition. Si vous avez besoin de munitions, parlez à Justin. Il s'occupera de vous.","Itt a hősünk. Kiváló munka! Mit adhatok? Kicsivel nagyobb a választék, most hogy megvan az összes leírás a kastélyból. Ha akarsz lőszert venni, beszélj Justinnal. Majd Ő gondoskodik rólad.","È l'eroe, ottimo lavoro! Che posso procurarti? Abbiamo una selezione un po' più grande dopo aver saccheggiato i depositi del castello. Se ti servono altre munizioni parla con Justin. Ci penserà lui a te.","正に英雄、流石です! 何か必要ですか?城の全兵器が揃っております。 -弾薬が必要ならジャスティンに頼めば大丈夫ですよ",그 프론트의 인기 많은 영웅 아닌가요? 잘하셨습니다! 무엇을 도와드릴까요? 성안에서 특이하고 질 좋은 보급물자들을 긁어모아 왔어요. 만약 탄약 보급을 위해서 오신 거라면 저스틴에게 물어보세요.,"Het is de held. Goed werk! Wat kan ik voor je halen? We hebben een iets grotere selectie nu we alle verordeningen van het kasteel hebben. Als je wat munitie moet kopen, praat dan met Justin. Hij zal voor je zorgen.",,Nosso herói. Bom trabalho! Como posso te ajudar? Temos uma seleção um pouco maior agora que conseguimos todo o equipamento do castelo. Se você precisar comprar munição é só falar com o Justin. Ele pode te ajudar.,,,"А вот и наш герой. Отлично сработано! Чем я могу тебе помочь? Теперь, когда мы заполучили всё оружие из замка, у нас чуть более богатый выбор. Если тебе нужны боеприпасы, обратись к Джастину. Он поможет тебе.", -I'm out of bullets.,TXT_RPLY0_SCRIPT10_D28804_IMOUT,,,,Došly mi náboje.,Ich habe keine Munition mehr.,,,No me quedan balas.,,,Je suis à cours de munitions.,,,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,,Estou sem munição.,,,У меня кончились патроны., -Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT10_D28804_HERES,,,,"Tady máš nějakou munici, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,Aquí tienes algo de munición. No la desperdicies.,,,Voilà des munitions. Ne les gaspillez pas.,,,この弾をどうぞ、無駄遣いしないように。,그렇게 계속 쏘아대면 탄약이 낭비됩니다. 여기 탄약이에요.,Hier is wat munitie voor je. Verspil het niet.,,Leve um pouco desta munição. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -Teach me.,TXT_RPLY1_SCRIPT10_D28804_TEACH,,,,Uč mě.,Unterrichte mich.,,,Enséñame.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,,Me ensine.,,,Обучи меня., -"Now, a few tips on the big guns.",TXT_RYES1_SCRIPT10_D28804_NOWAF,,,,"Tak jo, pár tipů, jak na velké zbraně.",Nun einige Ratschläge für die großen Waffen,,,"Ahora, unos cuantos consejos sobre las armas pesadas.",,,"Bon, voilà quelques conseils pour les armes plus grosses.",,,では、大きい銃の扱い方を教えます。,중화기 다루는 훈련을 시작하겠습니다!,"Nu, een paar tips over de grote geweren.",,"Ok, algumas dicas sobre as armas pesadas.",,,"А теперь, пара советов насчёт больших пушек.", -You're not ready yet.,TXT_RNO1_SCRIPT10_D28804_YOURE,,,,Ještě nejsi připraven.,Du bist noch nicht soweit,,,Aún no estás listo.,,,Vous n'êtes pas encore prêt.,,,貴方の準備がまだ整ってないように思えます。,준비가 아직 안됐습니다.,Je bent nog niet klaar.,,Você ainda não está preparado.,,,Ты ещё не готов., -"How's the war effort? Nevermind, if we're still here, it must be going fine. What can I do for you?",TXT_DLG_SCRIPT10_D30320_HOWST,,,,"Jak jde válečné úsilí? To je jedno, jestliže tu stále jsi, musí to jít dobře. Co pro tebe můžu udělat?","Wie geht der Krieg voran? Egal, solange wir noch hier sind, kann es nicht schlecht laufen. Was kann ich für dich tun?",,,"¿Cómo va la guerra? No importa, si seguimos aquí, debe de ir bien. ¿Qué puedo hacer por ti?",,,"Comment va l'effort de guerre? Non, oubliez. Si vous êtes ici, ça veut dire que tout va bien. Que puis-je faire pour vous?",,,"奮闘してますか?気にしないで、 +弾薬が必要ならジャスティンに頼めば大丈夫ですよ",그 프론트의 인기 많은 영웅 아닌가요? 잘하셨습니다! 무엇을 도와드릴까요? 성안에서 특이하고 질 좋은 보급물자들을 긁어모아 왔어요. 만약 탄약 보급을 위해서 오신 거라면 저스틴에게 물어보세요.,"Het is de held. Goed werk! Wat kan ik voor je halen? We hebben een iets grotere selectie nu we alle verordeningen van het kasteel hebben. Als je wat munitie moet kopen, praat dan met Justin. Hij zal voor je zorgen.","Det er helten. Bra jobbet! Hva vil du ha? Vi har et litt større utvalg nå som vi har alle ordrene fra slottet. Hvis du trenger å kjøpe ammunisjon, snakk med Justin. Han tar seg av deg.","Oto bohater. Dobra robota! Co mogę +dla ciebie zrobić? Mamy teraz większy +wybór towaru dzięki rozporządzeniu +z zamku. Jeśli potrzebujesz amunicji +to porozmawiaj z Justinem. Zajmie +się tobą.",Nosso herói. Bom trabalho! Como posso te ajudar? Temos uma seleção um pouco maior agora que conseguimos todo o equipamento do castelo. Se você precisar comprar munição é só falar com o Justin. Ele pode te ajudar.,,"E eroul. Bună treabă! Ce pot să-ți aduc? Avem o selecție mai largă acum, din moment ce am primit toate ordonanțele de la castel. Dacă ai nevoie de muniție vorbește cu Justin, se va ocupa de tine.","А вот и наш герой. Отлично сработано! Чем я могу тебе помочь? Теперь в нашем распоряжении всё оружие из замка, так что выбор стал побогаче. Если тебе нужны боеприпасы, обратись к Джастину: он тебе поможет.",,Det är hjälten. Bra jobbat! Vad kan jag ge dig? Vi har ett lite större urval nu när vi har alla ordinationer från slottet. Om du behöver köpa lite ammunition så prata med Justin. Han tar hand om dig.,Bu kahraman. İyi iş çıkardın! Size ne getireyim? Kaledeki tüm teçhizat elimizde olduğu için biraz daha geniş bir seçkimiz var. Cephane almak istersen Justin'le konuş. O seninle ilgilenir. +I'm out of bullets.,TXT_RPLY0_SCRIPT10_D28804_IMOUT,〃,,,Došly mi náboje.,Jeg er løbet tør for kugler.,Ich habe keine Munition mehr.,,Mi ne havas kuglojn.,No me quedan balas.,,Luodit on loppu.,Je suis à cours de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Jeg er tom for kuler.,Skończyły mi się naboje.,Estou sem munição.,,Nu mai am gloanțe.,У меня кончились патроны.,,Jag har slut på kulor.,Mermim bitti. +Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT10_D28804_HERES,〃,,,"Tady máš nějakou munici, neplýtvej s ní.",Her er noget ammunition til dig. Spild det ikke.,Hier hast du welche. Verschwende sie nicht.,,"Jen iom da municio. +Ne malŝparu ĝin.","Aquí tienes algo de munición. +No la desperdicies.",,Tässä sinulle vähän ammuksia. Älä tuhlaa niitä.,Voilà des munitions. Ne les gaspillez pas.,Itt van egy kis lőszer. Ne pazarold el.,Ecco un po' di munizioni per te. Non sprecarle.,この弾をどうぞ、無駄遣いしないように。,그렇게 계속 쏘아대면 탄약이 낭비됩니다. 여기 탄약이에요.,Hier is wat munitie voor je. Verspil het niet.,Her er litt ammunisjon til deg. Ikke sløs den bort.,Masz tu trochę amunicji. Tylko jej nie zmarnuj.,Leve um pouco desta munição. Não desperdice.,,Uite niște muniție. N-o risipi.,Можешь взять немного. Не трать их понапрасну.,,Här är lite ammunition till dig. Slösa inte bort den.,İşte sana biraz cephane. Ziyan etme. +Teach me.,TXT_RPLY1_SCRIPT10_D28804_TEACH,〃,,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Mutasd meg.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Naucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +"Now, a few tips on the big guns.",TXT_RYES1_SCRIPT10_D28804_NOWAF,〃,,,"Tak jo, pár tipů, jak na velké zbraně.",Nu et par tips om de store våben.,Nun einige Ratschläge für die großen Waffen,,"Nun kelkaj konsiloj +pri pezaj armiloj...","Ahora unos cuantos consejos +sobre las armas pesadas...",,Voin antaa muutamia vinkkejä isojen aseiden käyttöön.,"Bon, voilà quelques conseils pour les armes plus grosses.","És most, pár tipp a nagyobb fegyverekhez.",Ecco qui un paio di consigli sulle armi pesanti.,では、大きい銃の扱い方を教えます。,중화기 다루는 훈련을 시작하겠습니다!,"Nu, een paar tips over de grote geweren.","Nå, noen tips om de store kanonene.",Proszę. Kilka wskazówek dotyczących używania większych broni.,"Ok, algumas dicas sobre as armas pesadas.",,"Acum, niște sfaturi pentru armele mari.",А теперь пара советов насчёт больших пушек.,,"Nu, några tips om de stora vapnen.","Şimdi, büyük silahlar hakkında birkaç ipucu." +You're not ready yet.,TXT_RNO1_SCRIPT10_D28804_YOURE,〃,,,Ještě nejsi připraven.,Du er ikke klar endnu.,Du bist noch nicht soweit,,"Vi ankoraŭ +ne estas preta.",Aún no estás listo.,,Et ole vielä valmis.,Vous n'êtes pas encore prêt.,Nem állsz még készen.,Non sei ancora pronto.,貴方の準備がまだ整ってないように思えます。,준비가 아직 안됐습니다.,Je bent nog niet klaar.,Du er ikke klar ennå.,Nie jesteś jeszcze na to gotowy.,Você ainda não está preparado.,,Nu ești pregătit încă.,Ты ещё не готов.,,Du är inte redo än.,Henüz hazır değilsin. +"How's the war effort? Nevermind, if we're still here, it must be going fine. What can I do for you?",TXT_DLG_SCRIPT10_D30320_HOWST,〃 (one training),,,"Jak jde válečné úsilí? To je jedno, jestliže tu stále jsi, musí to jít dobře. Co pro tebe můžu udělat?","Hvordan går det med krigsindsatsen? Glem det, hvis vi stadig er her, må det gå fint. Hvad kan jeg gøre for dig?","Wie geht der Krieg voran? Egal, solange wir noch hier sind, kann es nicht schlecht laufen. Was kann ich für dich tun?",,"Kiel la milito iras? Nu, ne estas grave, ni estas ankoraŭ vivaj, do ĝi certe iras bone. Kion mi faru por vi?","¿Cómo va la guerra? Bueno, no importa, si seguimos aquí es porque debe de ir bien. ¿Qué puedo hacer por ti?",,"Kuinkas sotaponnistelut sujuvat? Tai ei mitään, varmaankin hyvin sujuvat, jos kerran vielä olemme tässä. Miten voin palvella?","Comment va l'effort de guerre? Non, oubliez. Si vous êtes ici, ça veut dire que tout va bien. Que puis-je faire pour vous?","Hogy áll a harc? Mindegyis, ha még mindig itt vagyunk, akkor jól haladunk. Mit tehetek érted?","Come sta procedendo la guerra? Vabbè, lascia stare, siamo ancora qua, quindi deve procedere bene. Cosa posso fare per te?","奮闘してますか?気にしないで、 ここにいるなら上手くやってるのは分かります。 -どういうご用件ですか?",전쟁상황은 어떻게 되어가나요? 상관은 없지만. 우리들이 아직 살아있는 한 물어볼 필요도 없죠. 무엇을 원하시나요?,"Hoe gaat het met de oorlogsinspanning? Maakt niet uit, als we hier nog steeds zijn, moet het wel goed gaan. Wat kan ik voor je doen?",,"Como está indo a guerra? Deixa pra lá, se nós ainda estamos aqui é porque deve estar indo bem. Como posso te ajudar?",,,"Как дела на фронте? Впрочем, неважно. Наверняка всё хорошо, раз мы ещё живы. Что я могу для тебя сделать?", -I ran out of bullets.,TXT_RPLY0_SCRIPT10_D30320_IRANO,,,,Došly mi náboje.,Mir ist die Munition ausgegangen.,,,Me he quedado sin balas.,,,Je suis à court de munitions.,,,弾を使い果たした。,탄약이 바닥났어요.,De kogels zijn op.,,Fiquei sem munição.,,,У меня кончились патроны., -That should help.,TXT_RYES0_SCRIPT10_D30320_THATS,,,,Tohle by mělo pomoci.,Das hier sollte helfen.,,,Esto debería ayudar.,,,Cela devrait aider.,,,これが助けになるでしょう。,좀 도움이 될 겁니다.,Dat zou moeten helpen.,,Isto deve ajudar.,,,"Вот, пожалуйста.", -You've got enough ammo.,TXT_RNO0_SCRIPT10_D30320_YOUVE,,,,Máš jich dost.,Du hast genug Munition.,,,Tienes suficiente munición.,,,Vous avez assez de munitions.,,,弾は十分に見えます。,탄약을 충분히 소지한 것 같은데.,Je hebt genoeg munitie.,,Você já tem munição suficiente.,,,Вполне достаточно., -Teach me.,TXT_RPLY1_SCRIPT10_D30320_TEACH,,,,Uč mě.,Unterrichte mich.,,,Enséñame.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,,Me ensine.,,,Обучи меня., -"Here, I'll show you a few tricks of the trade.",TXT_RYES1_SCRIPT10_D30320_HEREI,,,,Ukážu ti pár triků mého řemesla.,"Hier, ich zeige dir mal ein paar Geheimtricks.",,,"Bien, te mostraré algunos trucos de oficio.",,,Voilà quelques conseils dont vous pouvez faire usage.,,,では、幾つかのコツを教えましょう。,저항군의 참된 기술들을 좀 가르쳐드리죠!,Hier zal ik je een paar trucjes van het vak laten zien.,,"Certo, vou te mostrar alguns truques do ofício.",,,"Давай, я покажу тебе пару секретных приёмчиков.", -You're not ready yet.,TXT_RNO1_SCRIPT10_D30320_YOURE,,,,Ještě nejsi připraven.,Du bist noch nicht soweit,,,Aún no estás listo.,,,Vous n'êtes pas encore prêt.,,,貴方の準備がまだ整ってないように思えます。,당신은 아직 준비가 안됐어요.,Je bent nog niet klaar.,,Você ainda não está preparado.,,,Ты ещё не готов., -Well have you come for tutelage or is it some ammo you're looking for? Don't think that I'm done with you yet. I've still got a few tricks up my sleeve.,TXT_DLG_SCRIPT10_D31836_WELLH,,,,"Tak co, přišel jsi sem kvůli další lekci nebo potřebuješ náboje? Nemysli si, že jsme tu skončili. Ještě mám pár triků v rukávu.","Also, bist du zum Lernen gekommen, oder weil du mal wieder Munition brauchst? Denk bloß nicht, dass ich mit dir fertig bin. Ich habe noch ein paar Tricks auf Lager.",,,"Bien, ¿has venido a por tutela o buscas municiones? No creas que he terminado contigo. Aun tengo algunos trucos bajo la manga.",,,"Vous êtes venu pour des leçons ou avez-vous besoin de munitions? Je n'ai pas encore fini avec vous, ne vous inquiétez-pas. J'ai encore des tours dans mon sac.",,,"指導の受講か、弾薬の受け取りですか? +どういうご用件ですか?",전쟁 상황은 어떻게 되어가나요? 상관은 없지만. 우리들이 아직 살아있는 한 물어볼 필요도 없죠. 무엇을 원하시나요?,"Hoe gaat het met de oorlogsinspanning? Maakt niet uit, als we hier nog steeds zijn, moet het wel goed gaan. Wat kan ik voor je doen?","Hvordan går det med krigsinnsatsen? Glem det, hvis vi fortsatt er her, må det gå bra. Hva kan jeg gjøre for deg?","Jak tam wojna idzie? Nieważne. Jeśli +cały czas żyjemy to chyba dobrze. +Co mogę dla ciebie zrobić?","Como está indo a guerra? Deixa pra lá, se nós ainda estamos aqui é porque deve estar indo bem. Como posso te ajudar?",,"Cum merge efortul de război? Nu mai contează, dacă suntem încă aici înseamnă că e bine. Ce pot face pentru tine?","Как дела на фронте? Впрочем, неважно. Наверняка всё хорошо, раз мы ещё живы. Что я могу для тебя сделать?",,"Hur går det med krigsinsatsen? Strunt samma, om vi fortfarande är här måste det gå bra. Vad kan jag göra för dig?","Savaş çabaları nasıl gidiyor? Boşver, hala burada olduğumuza göre, iyi gidiyor olmalı. Senin için ne yapabilirim?" +I ran out of bullets.,TXT_RPLY0_SCRIPT10_D30320_IRANO,〃 (〃),,,Došly mi náboje.,Jeg er løbet tør for kugler.,Mir ist die Munition ausgegangen.,,Mi eluzis la kuglojn.,Me he quedado sin balas.,Me quedé sin balas.,Minulta loppuivat luodit.,Je suis à court de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾を使い果たした。,탄약이 바닥났어요.,De kogels zijn op.,Jeg gikk tom for kuler.,Skończyły mi się naboje.,Fiquei sem munição.,,Am rămas fără gloanțe.,У меня кончились патроны.,,Jag fick slut på kulor.,Mermim bitti. +That should help.,TXT_RYES0_SCRIPT10_D30320_THATS,〃 (〃),,,Tohle by mělo pomoci.,Det burde hjælpe.,Das hier sollte helfen.,,Ĉi tiom devus helpi.,A ver si esto ayuda.,,Tämän pitäisi auttaa.,Cela devrait aider.,Ez majd segít.,Questo dovrebbe aiutarti.,これが助けになるでしょう。,좀 도움이 될 겁니다.,Dat zou moeten helpen.,Det burde hjelpe.,To powinno pomóc.,Isto deve ajudar.,,Asta ar trebui să ajute.,"Вот, пожалуйста.",,Det borde hjälpa.,Bunun yardımı olur. +You've got enough ammo.,TXT_RNO0_SCRIPT10_D30320_YOUVE,〃 (〃),,,Máš jich dost.,Du har nok ammunition.,Du hast genug Munition.,,Vi havas sufiĉe da municio.,Tienes suficiente munición.,,Sinulla on riittävästi ammuksia.,Vous avez assez de munitions.,Van elég lőszered.,Ne hai a sufficienza.,弾は十分に見えます。,탄약을 충분히 소지한 것 같은데.,Je hebt genoeg munitie.,Du har nok ammunisjon.,Masz wystarczająco dużo amunicji.,Você já tem munição suficiente.,,Ai destulă.,Вполне достаточно.,,Du har tillräckligt med ammunition.,Yeterince cephanen var. +Teach me.,TXT_RPLY1_SCRIPT10_D30320_TEACH,〃 (〃),,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Mutasd meg.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Naucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +"Here, I'll show you a few tricks of the trade.",TXT_RYES1_SCRIPT10_D30320_HEREI,〃 (〃),,,Ukážu ti pár triků mého řemesla.,"Her, jeg skal vise dig et par tricks.","Hier, ich zeige dir mal ein paar Geheimtricks.",,"Nu, mi montros kelkajn +trompojn por spertuloj...","Bien, te mostraré +un par de trucos del oficio...","Bien, te voy a mostrar +un par de trucos del oficio.","No niin, valotan sinulle vähän alan saloja.",Voilà quelques conseils dont vous pouvez faire usage.,"Nézdd csak, mutatok neked pár trükköt.",Ora ti mostro un paio di trucchi del mestiere.,では、幾つかのコツを教えましょう。,저항군의 참된 기술들을 좀 가르쳐드리죠!,Hier zal ik je een paar trucjes van het vak laten zien.,Jeg skal vise deg noen triks.,Proszę. Oto kilka wskazówek o handlu.,"Certo, vou te mostrar alguns truques do ofício.",,"Iată, am să te învăț niște trucuri.","Давай, я покажу тебе пару секретных приёмчиков.",,"Här, jag ska visa dig några knep.",Sana işin birkaç püf noktasını göstereceğim. +You're not ready yet.,TXT_RNO1_SCRIPT10_D30320_YOURE,〃 (〃),,,Ještě nejsi připraven.,Du er ikke klar endnu.,Du bist noch nicht soweit,,"Vi ankoraŭ +ne estas preta.",Aún no estás listo.,,Et ole vielä valmis.,Vous n'êtes pas encore prêt.,Nem állsz még készen.,Non sei ancora pronto.,貴方の準備がまだ整ってないように思えます。,당신은 아직 준비가 안됐어요.,Je bent nog niet klaar.,Du er ikke klar ennå.,Nie jesteś jeszcze na to gotowy.,Você ainda não está preparado.,,Nu ești pregătit încă.,Ты ещё не готов.,,Du är inte redo än.,Henüz hazır değilsin. +Well have you come for tutelage or is it some ammo you're looking for? Don't think that I'm done with you yet. I've still got a few tricks up my sleeve.,TXT_DLG_SCRIPT10_D31836_WELLH,〃 (two trainings),,,"Tak co, přišel jsi sem kvůli další lekci nebo potřebuješ náboje? Nemysli si, že jsme tu skončili. Ještě mám pár triků v rukávu.","Er du kommet for at få undervisning, eller er det ammunition du leder efter? Du skal ikke tro, at jeg er færdig med dig endnu. Jeg har stadig et par tricks i ærmet.","Also, bist du zum Lernen gekommen, oder weil du mal wieder Munition brauchst? Denk bloß nicht, dass ich mit dir fertig bin. Ich habe noch ein paar Tricks auf Lager.",,"Nu, ĉu vi serĉas trejnadon aŭ municion? Ne kredu, ke mi finis kun vi: mi rezervas kelkajn sekretajn krizokazajn trompojn.","Bueno, ¿has venido a por tutela o por municiones? No creas que he terminado contigo: aún tengo un par de trucos bajo la manga.","Bueno, ¿viniste por tutela o por municiones? No creas que ya terminé contigo: aún tengo un par de trucos bajo la manga.","Oletko koulutuksen tarpeessa vai ammuksiako kaipaat? Älä luulekaan, etteikö hihassani olisi sinulle vielä muutamaa ässää jaettavana.","Vous êtes venu pour des leçons ou avez-vous besoin de munitions? Je n'ai pas encore fini avec vous, ne vous inquiétez-pas. J'ai encore des tours dans mon sac.","Valami kiképzés érdekel, vagy csak lőszerért jöttél? nehogy azt hidd, hogy végeztem veled. Még mindig rejt a tarsolyom új trükköket.","Allora, sei venuto per imparare qualcosa di nuovo o stai solo cercando munizioni? Non pensare che io abbia finito con te. Ho ancora qualche trucco da impartirti.","指導の受講か、弾薬の受け取りですか? まだ全て終わったわけではありません。 -私の袖口に若干技術を忍ばせております。","무엇을 원하시나요? 훈련? 아니면 탄약 보급? 그리고 훈련은 아직 끝난 게 아니니까 끝날 걱정도, 다칠 고민도 하지 마시길 바랍니다.",Ben je gekomen voor voogdij of ben je op zoek naar munitie? Denk niet dat ik nog niet klaar ben met jou. Ik heb nog een paar trucjes in mijn mouw.,,"Muito bem, você veio para aprender algo ou está precisando de munição? Não pense que aquilo é tudo, ainda tenho alguns truques na manga.",,,"Итак, ты пришёл за напутствием? Или тебе нужны боеприпасы? Не думай, что твоё обучение окончено. У меня ещё есть кое-какие козыри в рукаве!", -It's ammo for now.,TXT_RPLY0_SCRIPT10_D31836_ITSAM,,,,Teď jenom kvůli nábojům.,Im Moment ist es Munition.,,,Es munición por ahora.,,,Munitions pour l'instant.,,,今のところ弾薬だ。,탄약이 필요하겠네요.,Het is voorlopig munitie.,,No momento preciso de munição.,,,Мне нужны боеприпасы., -Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT10_D31836_HERES,,,,"Tady máš nějakou munici, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,Aquí tienes algo de munición. No la desperdicies.,,,Voilà des munitions. Ne les gaspillez pas.,,,この弾をどうぞ、無駄遣いしないように。,"좋은 병사에겐, 좋은 품질의 탄약을.",Hier is wat munitie voor je. Verspil het niet.,,Leve um pouco desta munição. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -You've got enough ammo.,TXT_RNO0_SCRIPT10_D31836_YOUVE,,,,Máš jich dost.,Du hast genug Munition.,,,Tienes suficiente munición.,,,Vous avez assez de munitions.,,,弾は十分に見えます。,아직 당신에게 탄약이 남아있는 것 같습니다만...,Je hebt genoeg munitie.,,Você já tem munição suficiente.,,,У тебя хватает патронов., -Teach me.,TXT_RPLY1_SCRIPT10_D31836_TEACH,,,,Uč mě.,Unterrichte mich.,,,Enséñame.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,,Me ensine.,,,Обучи меня., -Time for the advanced lessons.,TXT_RYES1_SCRIPT10_D31836_TIMEF,,,,Čas na pokročilé lekce.,Zeit für fortgeschrittene Lektionen.,,,Es hora de las lecciones avanzadas.,,,Il est temps de passer à des leçons plus avancées.,,,上級レッスンの時間です。,심화학습을 할 시간이군요!,Tijd voor de gevorderde lessen voor gevorderden.,,Hora das aulas avançadas.,,,Пришло время для углублённого изучения оружия!, -You're not ready yet.,TXT_RNO1_SCRIPT10_D31836_YOURE,,,,Ještě nejsi připraven.,Du bist noch nicht soweit.,,,Aún no estás listo.,,,Vous n'êtes pas encore prêt.,,,貴方の準備がまだ整ってないように思えます。,넌 아직 준비가 안됐어.,Je bent nog niet klaar.,,Você ainda não está preparado.,,,Ты ещё не готов., -"Well, what is it now? Don't you ever take a break? I'm glad that you're still breathing. I'd hate for my favorite student to come back looking out from the inside of a body bag.",TXT_DLG_SCRIPT10_D33352_WELLW,,,"Well, what is it now? Don't you ever take a break? I'm glad that you're still breathing. I'd hate for my favourite student to come back looking out from the inside of a body bag.","Tak, o co jde teď? Nechceš si někdy dát oraz? Jsem rád, že ještě dýcháš. Nechtěl bych, aby se mi můj oblíbený student vrátil v rakvi.","Also, was ist es dieses Mal? Machst du jemals eine Pause? Bin ich froh, dass du noch atmest.Gefiele mir nicht, meinen Lieblingschüler in einem Leichensack zurückkommen zu sehen.",,,"Bien, ¿Qué es ahora? ¿Es que nunca descansas? Me alegra que sigas respirando. Odiaría ver a mi estudiante favorito volver asomándose de dentro de una bolsa para cadáveres.",,,"Eh bien, comment allez vous? Vous prenez une pause de temps en temps? Je suis content de voir que vous êtes toujours vivant, çe me ferait mal de voir mon apprenti préféré dans un sac mortuaire.",,,"さて、調子はどうですか?休憩しませんか? +私の袖口に若干技術を忍ばせております。","무엇을 원하시나요? 훈련? 아니면 탄약 보급? 그리고 훈련은 아직 끝난 게 아니니까 끝날 걱정도, 다칠 고민도 하지 마시길 바랍니다.",Ben je gekomen voor voogdij of ben je op zoek naar munitie? Denk niet dat ik nog niet klaar ben met jou. Ik heb nog een paar trucjes in mijn mouw.,"Har du kommet for å få veiledning, eller er det ammunisjon du er ute etter? Ikke tro at jeg er ferdig med deg ennå. Jeg har fortsatt noen triks i ermet.","Chcesz się czegoś nauczyć czy raczej +przyszedłeś po trochę amunicji? +Nie myśl, że z tobą skończyłem. +Wciąż mam jeszcze parę sztuczek +w zanadrzu.","Muito bem, você veio para aprender algo ou está precisando de munição? Não pense que aquilo é tudo, ainda tenho alguns truques na manga.",,"Ai venit pentru a învăța ceva sau doar pentru muniție? Să nu crezi că am terminat cu tine, încă mai am niste ași în mânecă.","Итак, ты пришёл за напутствием? Или тебе нужны боеприпасы? Не думай, что твоё обучение окончено. У меня ещё есть кое-какие козыри в рукаве!",,Har du kommit för att få undervisning eller är det ammunition du letar efter? Tro inte att jag är klar med dig än. Jag har fortfarande några knep i ärmen.,Özel ders için mi geldin yoksa cephane mi arıyorsun? Seninle işimin bittiğini sanma. Hala birkaç numaram var. +It's ammo for now.,TXT_RPLY0_SCRIPT10_D31836_ITSAM,〃 (〃),,,Teď tu jsem jen pro náboje.,Det er ammunition for nu.,Im Moment ist es Munition.,,"Ĉi-momente, municion.","Por ahora, munición.",,Ammuksia tähän hätään.,Munitions pour l'instant.,Csak lőszer lesz most.,"Per il momento, solo munizioni.",今のところ弾薬だ。,탄약이 필요하겠네요.,Het is voorlopig munitie.,Det er ammunisjon for nå.,Tym razem chodzi o amunicję.,No momento preciso de munição.,,Muniție pentru moment.,Мне нужны боеприпасы.,,Det är ammunition för tillfället.,Şimdilik cephane. +Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT10_D31836_HERES,〃 (〃),,,"Tady nějaké máš, neplýtvej s nimi.",Her er lidt ammunition til dig. Spild det ikke.,Hier hast du welche. Verschwende sie nicht.,,"Jen iom da municio. +Ne malŝparu ĝin.","Aquí tienes algo de munición. +No la desperdicies.",,Tässä sinulle vähän kuteja. Älä haaskaa niitä.,Voilà des munitions. Ne les gaspillez pas.,Itt van egy kis lőszer. Ne pazarold el.,Ecco un po' di munizioni per te. Non sprecarle.,この弾をどうぞ、無駄遣いしないように。,"좋은 병사에겐, 좋은 품질의 탄약을.",Hier is wat munitie voor je. Verspil het niet.,Her er litt ammunisjon til deg. Ikke sløs den bort.,Masz tu trochę amunicji. Tylko jej nie zmarnuj.,Leve um pouco desta munição. Não desperdice.,,Uite niște muniție. N-o risipi.,Можешь взять немного. Не трать их понапрасну.,,Här är lite ammunition till dig. Slösa inte bort den.,İşte sana biraz cephane. Boşa harcama. +You've got enough ammo.,TXT_RNO0_SCRIPT10_D31836_YOUVE,〃 (〃),,,Máš jich dost.,Du har ammunition nok.,Du hast genug Munition.,,Vi havas sufiĉe da municio.,Tienes suficiente munición.,,Sinulla on riittävästi ammuksia.,Vous avez assez de munitions.,Van elég lőszered.,Ne hai a sufficienza.,弾は十分に見えます。,아직 당신에게 탄약이 남아있는 것 같습니다만...,Je hebt genoeg munitie.,Du har nok ammunisjon.,Masz wystarczająco dużo amunicji.,Você já tem munição suficiente.,,Ai destulă muniție.,У тебя хватает патронов.,,Du har tillräckligt med ammunition.,Yeterince cephanen var. +Teach me.,TXT_RPLY1_SCRIPT10_D31836_TEACH,〃 (〃),,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Mutasd meg.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Naucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +Time for the advanced lessons.,TXT_RYES1_SCRIPT10_D31836_TIMEF,〃 (〃),,,Čas na pokročilé lekce.,Tid til de avancerede lektioner.,Zeit für fortgeschrittene Lektionen.,,"Estas tempo por la +superaj lecionoj...","Hora de las +lecciones avanzadas...",,Aika aloittaa syventävät opinnot.,Il est temps de passer à des leçons plus avancées.,Jöjjön valami komolyabb lecke.,È arrivato il momento delle lezioni avanzate.,上級レッスンの時間です。,심화학습을 할 시간이군요!,Tijd voor de gevorderde lessen voor gevorderden.,På tide med de avanserte leksjonene.,Czas na lekcje dla zaawansowanych.,Hora das aulas avançadas.,,Timpul pentru lecțiile avansate.,Пришло время для углублённого изучения оружия!,,Dags för avancerade lektioner.,İleri seviye ders zamanı. +You're not ready yet.,TXT_RNO1_SCRIPT10_D31836_YOURE,〃 (〃),,,Ještě nejsi připraven.,Du er ikke klar endnu.,Du bist noch nicht soweit.,,"Vi ankoraŭ +ne estas preta.",Aún no estás listo.,,Et ole vielä valmis.,Vous n'êtes pas encore prêt.,Nem állsz még készen.,Non sei ancora pronto.,貴方の準備がまだ整ってないように思えます。,넌 아직 준비가 안됐어.,Je bent nog niet klaar.,Du er ikke klar ennå.,Nie jesteś jeszcze na to gotowy.,Você ainda não está preparado.,,Nu ești pregătit încă.,Ты ещё не готов.,,Du är inte redo än.,Henüz hazır değilsin. +"Well, what is it now? Don't you ever take a break? I'm glad that you're still breathing. I'd hate for my favorite student to come back looking out from the inside of a body bag.",TXT_DLG_SCRIPT10_D33352_WELLW,〃 (three trainings),,"Well, what is it now? Don't you ever take a break? I'm glad that you're still breathing. I'd hate for my favourite student to come back looking out from the inside of a body bag.","Tak, o co jde teď? Nechceš si někdy dát oraz? Jsem rád, že ještě dýcháš. Nechtěl bych, aby se mi můj oblíbený student vrátil v rakvi.","Hvad er det så nu? Tager du aldrig en pause? Jeg er glad for, at du stadig trækker vejret. Jeg ville hade, hvis min yndlingselev skulle komme tilbage og se ud fra en ligpose.","Also, was ist es dieses Mal? Machst du jemals eine Pause? Bin ich froh, dass du noch atmest.Gefiele mir nicht, meinen Lieblingschüler in einem Leichensack zurückkommen zu sehen.",,"Nu, kion ĉi-foje? Ĉu vi neniam ripozas? Ĝojigas min, ke vi ankoraŭ spiras; mi malamus, ke mia plej ŝatata studanto revenus en kadavro-sako.","Bueno, ¿qué es ahora?, ¿es que nunca descansas? Me alegra que sigas respirando; odiaría ver a mi estudiante favorito volver asomándose en una bolsa para cadáveres.",,Mikä nyt on? Etkö koskaan pidä taukoa? Onneksi henki vielä pihisee. En haluaisi lempioppilaani palaavan takaisin ruumissäkissä.,"Eh bien, comment allez vous? Vous prenez une pause de temps en temps? Je suis content de voir que vous êtes toujours vivant, çe me ferait mal de voir mon apprenti préféré dans un sac mortuaire.","Már megint mi van? Te sosem tartasz szünetet? Örülök, hogy még mindig lélegzel. Nem örülnék neki ha a kedvenc tanoncomat egy hullazsákban látnám viszont.","Ah, e adesso cosa c'è? Non ti prendi mai una pausa? Mi fa piacere vederti ancora respirare. Sarebbe tragico vedere il mio studente preferito ritornare in una sacca per cadaveri.","さて、調子はどうですか?休憩しませんか? 貴方がまだ息をしているのが喜ばしい事です。 お気に入りの生徒が死体袋から天を仰ぐ様に -なるのは嫌なのです。",이번엔 또 뭔가요? 휴식을 제대로 취하지 않는 성격인가요? 그래도 몸은 멀쩡히 움직이는 것 같군요! 그토록 가르침을 받던 우수한 제자가 사체로 돌아오면 정말 슬플 테니.,"Nou, wat is het nu? Neem je nooit een pauze? Ik ben blij dat je nog steeds ademt. Ik zou het vreselijk vinden als mijn favoriete student terug zou komen met het oog op de binnenkant van een lijkzak.",,"Bem, o que vai ser desta vez? Será que você não descansa nunca? Ainda bem que você ainda está respirando. Eu detestaria ver meu aluno favorito voltando num saco de cadáver.",,,"Итак, ты справился и даже ни разу не остановился передохнуть? Рад видеть, что ты всё ещё дышишь. Мне бы не хотелось, чтобы мой лучший ученик вернулся в мешке для трупов.", -I need some more bullets.,TXT_RPLY0_SCRIPT10_D33352_INEED,,,,Potřebuju nějaké další náboje.,Ich brauche mehr Munition.,,,Necesito más balas.,,,J'ai besoin de munitions.,,,もっと弾が必要だ。,총알이 좀 더 필요해.,Ik heb meer kogels nodig.,,Preciso de mais munição.,,,Мне нужны патроны., -"There, don't waste it.",TXT_RYES0_SCRIPT10_D33352_THERE,,,,"Tady máš, neplýtvej s nimi.","Hier, verschwende sie nicht.",,,"Toma, no las desperdicies.",,,"Voilà, ne les gaspillez pas.",,,大切にして下さいね。,여기 있습니다. 낭비하지 말고 아껴 쓰세요.,"Daar, verspil het niet.",,Pegue. Não desperdice.,,,Вот. Не трать их попусту., -You have enough.,TXT_RNO0_SCRIPT10_D33352_YOUHA,,,,Máš jich dost.,Du hast genug.,,,Tienes suficientes.,,,Vous en avez assez.,,,十分そうです。,지금도 충분한 것 같은데요.,Je hebt genoeg.,,Você já tem o suficiente.,,,Тебе хватает., -What can you teach me?,TXT_RPLY1_SCRIPT10_D33352_WHATC,,,,Co mě můžeš naučit?,Was kannst du mir beibringen?,,,¿Qué puedes enseñarme?,,,Que pouvez-vous m'apprendre.,,,何か教えてくれないか?,나에게 뭘 가르쳐 줄 수 있죠?,Wat kun je me leren?,,O que você tem pra me ensinar?,,,Чему ты можешь меня научить?, -"Don't get snippy, you've still some room to grow.",TXT_RYES1_SCRIPT10_D33352_DONTG,,,,"Nebuď moc domýšlivý, ještě se máš co učit.","Werd nicht leichtsinnig, du kannst noch einiges dazulernen.",,,"No seas insolente, aún tienes mucho que aprender.",,,"Ne faites pas l'orgeuilleux, vous avez encore de quoi apprendre.",,,ぶっきらぼうにならないで、まだ成長の余地はあります。,너무 자만하지 마세요. 아직 더 배울 게 많으니까.,"Wordt niet snipperig, je hebt nog wat ruimte om te groeien.",,"Vai devagar, rapaz. Você ainda tem muito o que aprender.",,,Не задирай нос. Тебе ещё есть куда расти., -Nothing until you're ready.,TXT_RNO1_SCRIPT10_D33352_NOTHI,,,,"Nic, dokud nebudeš připraven.","Nichts, bevor diu nicht bereit bist.",,,Nada hasta que estés listo.,,,Pas avant que vous ne soyez prêt.,,,準備が整うまで何も出来ません。,준비가 안 된 것 같으니 나중에 배웁시다.,Niets totdat je er klaar voor bent.,,Nada até que você esteja preparado.,,,"Ничему, пока ты не готов.", -"Look who's back, what's on your mind? I know it's been hard, but all of us appreciate your efforts, believe me.",TXT_DLG_SCRIPT10_D34868_LOOKW,,,,"No ne, kdopak to je? Jak se vede? Vím, že je to těžké, ale všichni si tě vážíme, věř mi.","Sieh mal an, wer zurück ist. Was gibt es? Ich weiß, es ist schwierig, aber wir alle wissen deine Arbeit zu würdigen, glaub mir.",,,"Mira quien ha vuelto, ¿Qué tienes en mente? Se que es duro, pero todos apreciamos tus esfuerzos, créeme.",,,"Regardez qui revient! Comment ça va? Je sais que les temps sont durs mais nous apprécions vos efforts, vraiment.",,,"誰が戻って来たかについて、貴方の考えとは? +なるのは嫌なのです。",이번엔 또 뭔가요? 휴식을 제대로 취하지 않는 성격인가요? 그래도 몸은 멀쩡히 움직이는 것 같군요! 그토록 가르침을 받던 우수한 제자가 사체로 돌아오면 정말 슬플 테니.,"Nou, wat is het nu? Neem je nooit een pauze? Ik ben blij dat je nog steeds ademt. Ik zou het vreselijk vinden als mijn favoriete student terug zou komen met het oog op de binnenkant van een lijkzak.",Hva er det nå? Tar du aldri en pause? Jeg er glad for at du fortsatt puster. Jeg vil ikke at yndlingseleven min skal komme tilbake og se ut fra innsiden av en likpose.,"Dobra. Co tym razem? Czy ty w ogóle +robisz sobie jakieś przerwy? Cieszę +się, że wciąż żyjesz. Przykro by mi się +zrobiło gdyby mój ulubiony uczeń +wrócił w trumnie.","Bem, o que vai ser desta vez? Será que você não descansa nunca? Ainda bem que você ainda está respirando. Eu detestaria ver meu aluno favorito voltando num saco de cadáver.",,Ce mai este? Nu iei niciodată pauză? Mă bucur că încă mai respiri. Ar fi păcat dacă cel mai bun student al meu ar veni într-un sac.,"Итак, ты справился? У тебя было время передохнуть? Рад видеть, что ты всё ещё дышишь. Мне бы не хотелось, чтобы мой лучший ученик вернулся в мешке для трупов.",,Vad är det nu då? Tar du aldrig en paus? Jag är glad att du fortfarande andas. Jag vill inte att min favoritelev ska komma tillbaka och titta ut från insidan av en liksäck.,"Peki, şimdi ne var? Hiç ara vermez misin? Hâlâ nefes alıyor olmana sevindim. En sevdiğim öğrencimin bir ceset torbasının içinden bakarak geri gelmesini istemem." +I need some more bullets.,TXT_RPLY0_SCRIPT10_D33352_INEED,〃 (〃),,,Potřebuju nějaké další náboje.,Jeg har brug for flere kugler.,Ich brauche mehr Munition.,,Mi bezonas pliajn kuglojn.,Necesito más balas.,,Tarvitsen lisää luoteja.,J'ai besoin de munitions.,Még több lőszerre lesz szükségem.,Ho bisogno di altre munizioni.,もっと弾が必要だ。,총알이 좀 더 필요해.,Ik heb meer kogels nodig.,Jeg trenger flere kuler.,Potrzebuję trochę naboi.,Preciso de mais munição.,,Am nevoie de niște gloanțe.,Мне нужны патроны.,,Jag behöver fler kulor.,Biraz daha mermiye ihtiyacım var. +"There, don't waste it.",TXT_RYES0_SCRIPT10_D33352_THERE,〃 (〃),,,"Tady máš, neplýtvej s nimi.","Sådan, lad være med at spilde den.","Hier, verschwende sie nicht.",,"Jen, ne malŝparu ĝin.","Toma, no las desperdicies.",,"Kas tässä, älä tuhlaa niitä.","Voilà, ne les gaspillez pas.","Parancsolj, ne pazarold el.","Ecco qua, non sprecarle.",大切にして下さいね。,여기 있습니다. 낭비하지 말고 아껴 쓰세요.,"Daar, verspil het niet.","Sånn, ikke sløs dem bort.",Proszę. Nie zmarnuj ich.,Pegue. Não desperdice.,,"Iată, n-o risipi.",Вот. Не трать их попусту.,,Slösa inte bort den.,"İşte, boşa harcama." +You have enough.,TXT_RNO0_SCRIPT10_D33352_YOUHA,〃 (〃),,,Máš jich dost.,Du har nok.,Du hast genug.,,Vi havas sufiĉe.,Tienes suficientes.,,Sinulla on tarpeeksi.,Vous en avez assez.,Már van elég.,Ne hai a sufficienza.,十分そうです。,지금도 충분한 것 같은데요.,Je hebt genoeg.,Du har nok.,Masz już ich wystarczająco dużo.,Você já tem o suficiente.,,Ai destulă.,Тебе хватает.,,Du har tillräckligt.,Sende yeterince var. +What can you teach me?,TXT_RPLY1_SCRIPT10_D33352_WHATC,〃 (〃),,,Co mě můžeš naučit?,Hvad kan du lære mig?,Was kannst du mir beibringen?,,Kion vi povas instrui al mi?,¿Qué puedes enseñarme?,,Mitä voit opettaa minulle?,Que pouvez-vous m'apprendre.,Mit tudsz tanítani?,Che cosa mi puoi insegnare?,何か教えてくれないか?,나에게 뭘 가르쳐 줄 수 있죠?,Wat kun je me leren?,Hva kan du lære meg?,Czego możesz mnie nauczyć?,O que você tem pra me ensinar?,,Ce mă poți învăța?,Чему ты можешь меня научить?,,Vad kan du lära mig?,Bana ne öğretebilirsin? +"Don't get snippy, you've still some room to grow.",TXT_RYES1_SCRIPT10_D33352_DONTG,〃 (〃),,,Nebuď moc domýšlivý; ještě se máš co učit.,"Du skal ikke blive snerpet, du har stadig plads til at vokse.","Werd nicht leichtsinnig, du kannst noch einiges dazulernen.",,"Paciencon, vi ankoraŭ +havas multajn lernotaĵojn.","Paciencia, que aún tienes +mucho que aprender.",,"Äläs rupea nokkavaksi, sinulla on vielä kasvun varaa.","Ne faites pas l'orgeuilleux, vous avez encore de quoi apprendre.","Ne hordd úgy fennt az orrod, van még mit tanulnod.","Non essere brusco, ci sono ancora cose che puoi imparare.",ぶっきらぼうにならないで、まだ成長の余地はあります。,너무 자만하지 마세요. 아직 더 배울 게 많으니까.,"Wordt niet snipperig, je hebt nog wat ruimte om te groeien.","Ikke vær frekk, du har fortsatt litt å gå på.",Nie wychylaj się. Przed tobą jeszcze długa droga.,"Vai devagar, rapaz. Você ainda tem muito o que aprender.",,"Nu fi impetinent, încă mai ai ce învăța.",Не задирай нос. Тебе ещё есть куда расти.,,"Bli inte snäsig, du har fortfarande utrymme att växa.","Kibirlenme, hala büyümek için yerin var." +Nothing until you're ready.,TXT_RNO1_SCRIPT10_D33352_NOTHI,〃 (〃),,,"Nic, dokud nebudeš připraven.","Intet, før du er klar.","Nichts, bevor diu nicht bereit bist.",,"Nenion ĝis +vi estos preta.",Nada hasta que estés listo.,,"Ei mitään, kunnes olet valmis.",Pas avant que vous ne soyez prêt.,"Semmi, míg nem állsz készen.","Nulla al momento, finché non sarai pronto",準備が整うまで何も出来ません。,준비가 안 된 것 같으니 나중에 배웁시다.,Niets totdat je er klaar voor bent.,Ingenting før du er klar.,Na razie nic póki nie jesteś gotowy.,Nada até que você esteja preparado.,,"Nimic, până nu ești pregătit.","Ничему, пока ты не готов.",,Ingenting förrän du är redo.,Hazır olana kadar hiçbir şey. +"Look who's back, what's on your mind? I know it's been hard, but all of us appreciate your efforts, believe me.",TXT_DLG_SCRIPT10_D34868_LOOKW,〃 (four trainings),,,"No ne, kdopak to je? Jak se vede? Vím, že je to těžké, ale všichni si tě vážíme, věř mi.","Se, hvem der er tilbage. Hvad har du på hjerte? Jeg ved, det har været svært, men vi sætter alle pris på din indsats, tro mig.","Sieh mal an, wer zurück ist. Was gibt es? Ich weiß, es ist schwierig, aber wir alle wissen deine Arbeit zu würdigen, glaub mir.",,"Vi revenis! Pri kio vi pensas? Mi scias, ke nenio estis facila, sed ni ĉiuj taksas viajn strebojn, kredu min.","Mira quien ha vuelto. ¿En qué estás pensando? Sé que son tiempos difíciles, pero todos apreciamos tus esfuerzos, créeme.","Mira quien volvió. ¿En qué estás pensando? Sé que son tiempos difíciles, pero todos apreciamos tus esfuerzos, créeme.","Kukas se siinä; mitä on mielessäsi? Tiedän, että sinulla on ollut rankkaa, mutta uskothan, että me kaikki arvostamme vaivannäköäsi.","Regardez qui revient! Comment ça va? Je sais que les temps sont durs mais nous apprécions vos efforts, vraiment.","Nézzenek oda kit látnak szemeim, mi újság van veled? Tudom, hogy nem könnyű, de hidd el mindannyian értékeljük a fáradozásaidat.","Guarda chi si vede, a cosa stai pensando? Lo so che son tempi duri, ma noi tutti apprezziamo i tuoi sforzi, credimi.","誰が戻って来たかについて、貴方の考えとは? 困難な事だとわかっています。しかし私達全員は -貴方の努力には感謝しています。","다시 돌아오다니. 어쩐 일이십니까? 견디기 힘든 고역이었겠지만, 지금 당신은 우리들을 위해 잘 싸우고 계십니다. 믿어주세요!","Kijk eens wie er terug is, waar denk je aan? Ik weet dat het moeilijk is geweest, maar we waarderen allemaal je inspanningen, geloof me.",,"Olha só quem voltou. Como vai? Eu sei que tem sido difícil, mas todos nós agradecemos pelos seus esforços, vai por mim.",,,"Посмотрите-ка, кто вернулся. Что у тебя стряслось? Я знаю, твои задания сложны, но мы все ценим твои усилия. Поверь мне.", -I've run out of bullets.,TXT_RPLY0_SCRIPT10_D34868_IVERU,,,,Došly mi náboje.,Mir ist die Munition ausgegangen.,,,Me he quedado sin balas.,,,Je suis à court de munitions.,,,弾が無くなった。,탄약이 바닥났어요.,Ik heb geen kogels meer.,,Fiquei sem munição.,,,Мне нужны патроны., -"What else is new, here you go.",TXT_RYES0_SCRIPT10_D34868_WHATE,,,,Něco jiného nového? Tady máš.,Kennen wir das nicht? Hier hast du welche.,,,"Que más es nuevo, aquí tienes.",,,"Rien de nouveau, voilà pour vous.",,,新しい試みですか、どうぞ。,여기 탄약. 그리고 더 필요한게?,"Wat is er nog meer nieuw, alsjeblieft.",,Que novidade. Aqui está.,,,"Знаю, знаю. Вот, держи!", -You have more than I can give you.,TXT_RNO0_SCRIPT10_D34868_YOUHA,,,,"Máš víc, než kolik ti můžu dát.","Du hast mehr, als ich dir geben könnte.",,,Tienes más de las que podría darte.,,,Vous avez plus que je ne suis autorisé à vous donner.,,,今渡せる以上に持ってますよ。,내가 줄 수 있는 탄약의 양보다 큰데?,Je hebt meer dan ik je kan geven.,,Você tem o suficiente.,,,"Да у тебя их больше, чем на нашем складе.", -Teach me what you can.,TXT_RPLY1_SCRIPT10_D34868_TEACH,,,,"Uč mě, co můžeš.",Zeig mir was du weißt.,,,Enseñame lo que puedas.,,,Enseignez-moi ce que vous pouvez.,,,可能な限り教えてくれ。,가르칠 수 있는 걸 가르쳐주세요.,Leer me wat je kunt.,,O que você pode me ensinar?,,,"Научи меня, чему можешь.", -"All right, here's some pointers.",TXT_RYES1_SCRIPT10_D34868_ALLRI,,,,"Dobře, tady je pár tipů.","Ok, ich erklär dir ein paar Tricks.",,,"Muy bien, aquí tienes unos consejos.",,,Voilà deux ou trois trucs.,,,わかりました、貴方に幾つかやり方を教ましょう。,알겠습니다. 여기 과녁을 보여주지.,"Oké, hier zijn wat aanwijzingen.",,"Tá legal, aqui vai algumas dicas.",,,Ну хорошо. Вот пара советов., -Not right now.,TXT_RNO1_SCRIPT10_D34868_NOTRI,,,,Zrovna teď ne.,Nicht jetzt.,,,Ahora no.,,,Pas maintenant.,,,今はまだです。,지금은 안 돼요.,Niet op dit moment.,,Agora não.,,,Не сейчас., -What is it you need? I hope that you're giving the Order a taste of the kind of pain that we have been feeling for years.,TXT_DLG_SCRIPT10_D36384_WHATI,,,,"Copak potřebuješ? Doufám, že oplácíš Řádu to, co nám za celé ty roky udělali.","Was brauchst du? Ich hoffe, du gibst dem Orden etwas von dem Schmerz zurück, den sie und allen haben zukommen lassen.",,,¿Qué necesitas? Espero que le estés dando a la Orden un poco del tipo de dolor que hemos estado sufriendo durante años.,,,De quoi avez-vous besoin? J'espère que vous donnez à l'Ordre une idée de la douleur que nous avons ressenti pendant des années.,,,"必要な物は何ですか?私達が何年も前から感じた +貴方の努力には感謝しています。","다시 돌아오다니. 어쩐 일이십니까? 견디기 힘든 고역이었겠지만, 지금 당신은 우리들을 위해 잘 싸우고 계십니다. 믿어주세요!","Kijk eens wie er terug is, waar denk je aan? Ik weet dat het moeilijk is geweest, maar we waarderen allemaal je inspanningen, geloof me.","Se hvem som er tilbake. Hva har du på hjertet? Jeg vet at det har vært vanskelig, men vi setter pris på innsatsen din, tro meg.","Patrzcie, kto wrócił, co wam chodzi po głowie? Wiem, że było ciężko, ale wszyscy doceniamy twoje wysiłki, uwierz mi.","Olha só quem voltou. Como vai? Eu sei que tem sido difícil, mas todos nós agradecemos pelos seus esforços, vai por mim.",,"Uite cine s-a întors? La ce te gândești? Știu că a fost greu, dar toți îți apreciem eforturile, crede-mă.","Посмотрите-ка, кто вернулся. Что у тебя стряслось? Я знаю, твои задания сложны, но, поверь, мы все ценим твои усилия.",,"Titta vem som är tillbaka, vad tänker du på? Jag vet att det har varit svårt, men alla uppskattar dina ansträngningar, tro mig.","Bak kim gelmiş, aklında ne var? Zor olduğunu biliyorum ama hepimiz çabalarını takdir ediyoruz, inan bana." +I've run out of bullets.,TXT_RPLY0_SCRIPT10_D34868_IVERU,〃 (〃),,,Došly mi náboje.,Jeg er løbet tør for kugler.,Mir ist die Munition ausgegangen.,,Mi eluzis la kuglojn.,Me he quedado sin balas.,Me quedé sin balas.,Minulta on luodit loppu.,Je suis à court de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾が無くなった。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Jeg er tom for kuler.,Skończyły mi się naboje.,Fiquei sem munição.,,Am rămas fără gloanțe.,Мне нужны патроны.,,Jag har slut på kulor.,Mermim bitti. +"What else is new, here you go.",TXT_RYES0_SCRIPT10_D34868_WHATE,〃 (〃),,,Něco jiného nového? Tady máš.,"Hvad er der ellers nyt, værsgo.",Kennen wir das nicht? Hier hast du welche.,,Nenio nova. Jen.,Qué novedad. Toma.,,Olipas uutinen; kas tässä.,"Rien de nouveau, voilà pour vous.","Már meg sem lepődök, parancsolj.","Nulla di nuovo sotto il sole, ecco qua.",新しい試みですか、どうぞ。,여기 탄약. 그리고 더 필요한게?,"Wat is er nog meer nieuw, alsjeblieft.",Vær så god.,"Co jeszcze jest nowe, proszę bardzo.",Que novidade. Aqui está.,,"Ce mai e nou, iată.","Знаю, знаю. Вот, держи!",,"Vad mer är nytt, här har du.","Başka yeni ne var, al bakalım." +You have more than I can give you.,TXT_RNO0_SCRIPT10_D34868_YOUHA,〃 (〃),,,"Máš víc, než kolik ti můžu dát.","Du har mere, end jeg kan give dig.","Du hast mehr, als ich dir geben könnte.",,"Vi havas pli ol tiom, +kiom mi povas doni.","Tienes más de +las que podría darte.",,Sinulla on enemmän kuin voin antaa.,Vous avez plus que je ne suis autorisé à vous donner.,"Több van nálad, mint amennyit tudnék adni.",Ne hai più di quante te ne possa dare.,今渡せる以上に持ってますよ。,내가 줄 수 있는 탄약의 양보다 큰데?,Je hebt meer dan ik je kan geven.,Du har mer enn jeg kan gi deg.,Masz więcej niż mogę ci dać.,Você tem o suficiente.,,Ai mai multe decât ți-aș putea oferi.,"Да у тебя их больше, чем на нашем складе.",,Du har mer än vad jag kan ge dig.,Sana verebileceğimden daha fazlasına sahipsin. +Teach me what you can.,TXT_RPLY1_SCRIPT10_D34868_TEACH,〃 (〃),,,"Uč mě, co můžeš.","Lær mig, hvad du kan.",Zeig mir was du weißt.,,Instruu ion ajn al mi.,Enséñame lo que puedas.,,"Opeta minulle, mitä voit.",Enseignez-moi ce que vous pouvez.,Tanítsd meg amit tudsz.,Potresti insegnarmi ciò che puoi.,可能な限り教えてくれ。,가르칠 수 있는 걸 가르쳐주세요.,Leer me wat je kunt.,Lær meg det du kan.,"Naucz mnie tego, co potrafisz.",O que você pode me ensinar?,,Învață-mă ce poți.,"Научи меня, чему можешь.",,Lär mig vad du kan.,Bana öğretebileceğin kadarını öğret. +"All right, here's some pointers.",TXT_RYES1_SCRIPT10_D34868_ALLRI,〃 (〃),,,"Dobře, tady je pár tipů.","Okay, her er nogle tips.","Ok, ich erklär dir ein paar Tricks.",,"Bone, jen kelkaj konsiloj...","Muy bien, ahí van +unos consejos...",,"Hyvä on, tässä muutama vinkki.",Voilà deux ou trois trucs.,"Rendben, itt van pár tanács.","Va bene, ecco qualche dritta.",わかりました、貴方に幾つかやり方を教ましょう。,알겠습니다. 여기 과녁을 보여주지.,"Oké, hier zijn wat aanwijzingen.","Greit, her har du noen tips.","W porządku, oto kilka wskazówek.","Tá legal, aqui vai algumas dicas.",,"În regulă, uite niște repere.",Ну хорошо. Вот пара советов.,,"Okej, här är några tips.","Pekala, işte birkaç ipucu." +Not right now.,TXT_RNO1_SCRIPT10_D34868_NOTRI,〃 (〃),,,Zrovna teď ne.,Ikke lige nu.,Nicht jetzt.,,Ne nun.,Ahora no.,,Ei juuri nyt.,Pas maintenant.,Most nem érek rá.,Non adesso.,今はまだです。,지금은 안 돼요.,Niet op dit moment.,Ikke akkurat nå.,Nie teraz.,Agora não.,,Nu chiar acum.,Не сейчас.,,Inte just nu.,Şimdi olmaz. +What is it you need? I hope that you're giving the Order a taste of the kind of pain that we have been feeling for years.,TXT_DLG_SCRIPT10_D36384_WHATI,〃 (five trainings),,,"Copak potřebuješ? Doufám, že oplácíš Řádu to, co nám celé ty roky dělali.","Hvad er det, du har brug for? Jeg håber, at du giver Ordenen en smagsprøve på den slags smerte, som vi har følt i årevis.","Was brauchst du? Ich hoffe, du gibst dem Orden etwas von dem Schmerz zurück, den sie und allen haben zukommen lassen.",,"Kion vi bezonas? Mi esperas, ke vi redonas al La Ordeno tian doloron, kian ni suferis dum jaroj.",¿Qué necesitas? Espero que le estés devolviendo a La Orden parte del dolor que hemos estado sufriendo durante años.,,"Mitä tarvitset? Toivottavasti annat Veljeskunnan maistaa sitä tuskaa, jota me olemme tunteneet vuosia.",De quoi avez-vous besoin? J'espère que vous donnez à l'Ordre une idée de la douleur que nous avons ressenti pendant des années.,"Miben segíthetek? Remélem megízlettetted a Rendet ugyanazzal a fájdalommal, amit mi éreztünk eddig.",Di che cosa hai bisogno? Spero che tu stia dando all'Ordine un assaggio del tipo di dolore che noi abbiamo tollerato per anni.,"必要な物は何ですか?私達が何年も前から感じた 多くの苦痛の味をオーダーに与えることを -願っています。",필요한 게 있습니까? 수 년 동안 고통을 안겨 온 오더 놈들에게 복수를 해줬으면 하는 바입니다. 끝날 때까지!,Wat heb je nodig? Ik hoop dat je de Orde een voorproefje geeft van het soort pijn dat we al jaren voelen.,,O que está precisando? Espero que você esteja fazendo a Ordem sentir um pouco do sofrimento que nós estivemos passando por anos.,,,"Что тебе нужно? Надеюсь, ты даёшь Ордену почувствовать ту боль, что мы терпели годами.", -Some ammo.,TXT_RPLY0_SCRIPT10_D36384_SOMEA,,,,Nějakou munici.,Etwas Munition.,,,Algo de munición.,,,Des munitions.,,,弾を幾つか。,탄약 좀...,Wat munitie.,,Um pouco de munição.,,,Боеприпасы., -"There you go, don't waste it.",TXT_RYES0_SCRIPT10_D36384_THERE,,,,"Tady máš, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,"Toma, no las desperdicies.",,,Voilà pour vous. Ne les gaspillez pas.,,,はいどうぞ、無駄にしないように。,전장을 자주 누비나 보군요. 여기 탄약!,"Daar ga je, verspil het niet.",,Aqui está. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -You've got enough ammo.,TXT_RNO0_SCRIPT10_D36384_YOUVE,,,,Máš jí dost.,Du hast genug Munition.,,,Tienes suficiente munición.,,,Vous avez assez de munitions.,,,弾は十分に見えます。,당신의 남은 탄약이 눈에 보이는군요. 줄 수 없습니다!,Je hebt genoeg munitie.,,Você tem munição suficiente.,,,У тебя хватает патронов., -Teach me.,TXT_RPLY1_SCRIPT10_D36384_TEACH,,,,Uč mě.,Unterrichte mich.,,,Enséñame.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,,Me ensine.,,,Обучи меня., -A few more lessons and you'll know all that I can teach.,TXT_RYES1_SCRIPT10_D36384_AFEWM,,,,"Pár dalších lekcí a budeš vědět všechno, co vím.","Ein paar mehr Lektionen, und du weißt alles, was ich weiß.",,,Unas cuantas lecciones más y sabrás todo lo que puedo enseñar.,,,Quelque leçons en plus et vous saurez tout ce que je peux vous enseigner.,,,もう少しで私の教えられる事が全てわかるはずです。,제가 가르칠 만한 훈련을 배우면 좀 똑똑해질 겁니다.,Nog een paar lessen en je weet alles wat ik je kan leren.,,Mais algumas aulas e você já saberá tudo o que consigo ensinar.,,,"Ещё немного, и ты будешь знать всё, что знаю я.", -You're not ready yet.,TXT_RNO1_SCRIPT10_D36384_YOURE,,,,Ještě nejsi připraven.,Du bist noch nicht soweit.,,,Aún no estás listo.,,,Vous n'êtes pas encore prêt.,,,貴方の準備がまだ整ってないように思えます。,훈련받기엔 가깝지만서도... 먼 것 같습니다.,Je bent er nog niet klaar voor.,,Você ainda não está preparado.,,,Ты ещё не готов., -"I can't believe that we're still around, you and I. There's just too many of us that have passed since the beginning. What can I do for you friend?",TXT_DLG_SCRIPT10_D37900_ICANT,,,,"Nemůžu uvěřit, že tu my dva stále ještě jsme. Hrozně moc z nás za tu dobu zahynulo. Co pro tebe mohu udělat, příteli?","Ich kann kaum glauben, dass wir immer noch da sind, du und ich. Es sind so viele, die uns verlassen haben, seit alles anfing. Was kann ich für dich tun, Freund?",,,"No puedo creer que sigamos aquí, tu y yo. Se han ido tantos como tú desde que todo empezó. ¿Qué puedo hacer por ti, amigo?",,,"J'arrive pas a croire que vous êtes toujours avec nous. Tellement de nos camarades ont disparu depuis que tout a commencé. Que puis-je faire pour vous, mon ami?",,,"私達はまだ貴方の護衛をし続けられるとは +願っています。",필요한 게 있습니까? 수 년 동안 고통을 안겨 온 오더 놈들에게 복수를 해줬으면 하는 바입니다. 끝날 때까지!,Wat heb je nodig? Ik hoop dat je de Orde een voorproefje geeft van het soort pijn dat we al jaren voelen.,Hva er det du trenger? Jeg håper du gir Ordenen en forsmak på den smerten vi har følt i årevis.,"Czego potrzebujesz? Mam nadzieję, że dajesz Zakonowi przedsmak bólu, który odczuwamy od lat.",O que está precisando? Espero que você esteja fazendo a Ordem sentir um pouco do sofrimento que nós estivemos passando por anos.,,De ce ai nevoie? Sper că îi dai Ordinului aceeași durere pe care și el ne-a oferit-o în toți acești ani.,"Что тебе нужно? Надеюсь, ты даёшь Ордену почувствовать ту боль, что мы терпели годами.",,Vad är det du behöver? Jag hoppas att du ger Orden en smak av den typ av smärta som vi har känt i åratal.,Neye ihtiyacın var? Umarım Tarikat'a yıllardır hissettiğimiz acıyı tattırıyorsundur. +Some ammo.,TXT_RPLY0_SCRIPT10_D36384_SOMEA,〃 (〃),,,Nějakou munici.,Lidt ammunition.,Etwas Munition.,,Iom da municio.,Algo de munición.,,Vähän ammuksia.,Des munitions.,Valamennyi lőszer.,Un poco di munizioni.,弾を幾つか。,탄약 좀...,Wat munitie.,Litt ammunisjon.,Trochę amunicji.,Um pouco de munição.,,Niște muniție.,Боеприпасы.,,Lite ammunition.,Biraz cephane. +"There you go, don't waste it.",TXT_RYES0_SCRIPT10_D36384_THERE,〃 (〃),,,"Tady máš, neplýtvej s ní.","Værsgo, lad være med at spilde den.",Hier hast du welche. Verschwende sie nicht.,,Jen. Ne malŝparu ĝin.,"Toma, no las desperdicies.",,"Ole hyvä, älä tuhlaa niitä.",Voilà pour vous. Ne les gaspillez pas.,"Parancsolj, ne pazarold el.","Ecco delle munizioni, non sprecarle.",はいどうぞ、無駄にしないように。,전장을 자주 누비나 보군요. 여기 탄약!,"Daar ga je, verspil het niet.","Vær så god, ikke sløs den bort.","Proszę bardzo, nie marnuj jej.",Aqui está. Não desperdice.,,"Iată, n-o risipi.",Вот. Не трать их попусту.,,"Varsågod, slösa inte bort den.","Al bakalım, boşa harcama." +You've got enough ammo.,TXT_RNO0_SCRIPT10_D36384_YOUVE,〃 (〃),,,Máš jí dost.,Du har nok ammunition.,Du hast genug Munition.,,Vi havas sufiĉe da municio.,Tienes suficiente munición.,,Sinulla on riittävästi ammuksia.,Vous avez assez de munitions.,Van elég lőszered.,Ne hai a sufficienza.,弾は十分に見えます。,당신의 남은 탄약이 눈에 보이는군요. 줄 수 없습니다!,Je hebt genoeg munitie.,Du har nok ammunisjon.,Masz wystarczająco dużo amunicji.,Você tem munição suficiente.,,Ai destulă muniție.,У тебя хватает патронов.,,Du har tillräckligt med ammunition.,Yeterince cephanen var. +Teach me.,TXT_RPLY1_SCRIPT10_D36384_TEACH,〃 (〃),,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Mutasd meg.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Naucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +A few more lessons and you'll know all that I can teach.,TXT_RYES1_SCRIPT10_D36384_AFEWM,〃 (〃),,,"Pár dalších lekcí a budeš vědět všechno, co vím.","Et par lektioner mere, og du vil vide alt, hvad jeg kan lære dig.","Ein paar mehr Lektionen, und du weißt alles, was ich weiß.",,"Ankoraŭ unu leciono kaj +vi lernis ĉion, kion mi scias.","Una lección más y +sabrás todo lo que sé.","Una lección más y +vas a saber todo lo que sé.","Enää vain muutama oppitunti ja tiedät kaiken, mitä voin opettaa.",Quelque leçons en plus et vous saurez tout ce que je peux vous enseigner.,"Még pár lecke, és mindent tudni fogsz amit Én.",Tra un paio di lezioni saprai tutto quello che conosco.,もう少しで私の教えられる事が全てわかるはずです。,제가 가르칠 만한 훈련을 배우면 좀 똑똑해질 겁니다.,Nog een paar lessen en je weet alles wat ik je kan leren.,"Et par leksjoner til, så vet du alt jeg kan lære deg.","Jeszcze kilka lekcji i będziesz wiedział wszystko, czego mogę nauczyć.",Mais algumas aulas e você já saberá tudo o que consigo ensinar.,,"Câteva lecții, și vei știi tot ce știu si eu.","Ещё немного, и ты будешь знать всё, что знаю я.",,Några lektioner till och du kommer att veta allt jag kan lära dig.,Birkaç ders daha ve öğretebileceğim her şeyi öğreneceksin. +You're not ready yet.,TXT_RNO1_SCRIPT10_D36384_YOURE,〃 (〃),,,Ještě nejsi připraven.,Du er ikke klar endnu.,Du bist noch nicht soweit.,,"Vi ankoraŭ +ne estas preta.",Aún no estás listo.,,Et ole vielä valmis.,Vous n'êtes pas encore prêt.,Nem állsz még készen.,Non sei ancora pronto.,貴方の準備がまだ整ってないように思えます。,훈련받기엔 가깝지만서도... 먼 것 같습니다.,Je bent er nog niet klaar voor.,Du er ikke klar ennå.,Nie jesteś jeszcze gotowy.,Você ainda não está preparado.,,Nu ești pregătit încă.,Ты ещё не готов.,,Du är inte redo än.,Henüz hazır değilsin. +"I can't believe that we're still around, you and I. There's just too many of us that have passed since the beginning. What can I do for you friend?",TXT_DLG_SCRIPT10_D37900_ICANT,〃 (six trainings),,,"Nemůžu uvěřit, že tu my dva stále ještě jsme. Hrozně moc z nás za tu dobu zahynulo. Co pro tebe mohu udělat, příteli?","Jeg kan ikke tro, at vi stadig er her, du og jeg. Der er bare for mange af os, der er gået siden begyndelsen. Hvad kan jeg gøre for dig, min ven?","Ich kann kaum glauben, dass wir immer noch da sind, du und ich. Es sind so viele, die uns verlassen haben, seit alles anfing. Was kann ich für dich tun, Freund?",,"Estas nekredeble, ke vi kaj ni estas ankoraŭ vivaj. Ni perdis tiom multe da homoj de kiam ĉio ekis... Kion mi povas fari por vi, amiko?","No puedo creer que sigamos aquí tú y yo. Hemos perdidos a tantos desde que todo empezó... ¿Qué puedo hacer por ti, amigo?",,"En voi uskoa, että olemme vielä kuvioissa, sinä ja minä. Aivan liian moni on poistunut keskuudestamme sitten, kun kaikki tämä alkoi. Miten voin olla avuksi, ystäväni?","J'arrive pas a croire que vous êtes toujours avec nous. Tellement de nos camarades ont disparu depuis que tout a commencé. Que puis-je faire pour vous, mon ami?","Nem hiszem el, hogy eddig túléltük ezt. Sokan vesztették életüket a kezdetek óta. Mit tehetek érted barátom?","Non posso credere che siamo ancora vivi, tu e io. Ce ne sono così tanti che sono morti da quando è iniziata questa faccenda. Che cosa posso fare per te, amico?","私達はまだ貴方の護衛をし続けられるとは 思えません。昔からの仲間は殆ど去って しまいました。貴方の友人の為に -何がしてあげられますか?",아직도 살아 숨 쉬고 있다니 믿기지 않네요... 당신이 싸우고 생존하는 동안 살아 돌아온 병사들은 그렇게 많지 않아요. 원하는 게 있습니까?,"Ik kan niet geloven dat we er nog steeds zijn, jij en ik. Er zijn er gewoon te veel van ons die sinds het begin zijn overleden. Wat kan ik voor je doen, vriend?",,"Mal consigo acreditar que ainda estamos vivos, você e eu. Perdemos muitos companheiros desde o início. O que posso fazer por você, meu amigo?",,,"Не могу поверить, что мы всё ещё живы, ты и я. За всё это время уже стольких из нас не стало. Что я могу сделать для тебя, дружище?", -I'm out of bullets.,TXT_RPLY0_SCRIPT10_D37900_IMOUT,,,,Došly mi náboje.,Ich habe keine Munition mehr.,,,Me he quedado sin balas.,,,Je suis à court de munitions.,,,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,,Estou sem munição.,,,У меня кончились патроны., -"Here, use them to keep you in good health.",TXT_RYES0_SCRIPT10_D37900_HEREU,,,,"Tady, používej je, abys zůstal ve zdraví.","Hier, benutze sie um gesund zu bleiben,",,,"Aquí tienes, úsalas para mantenerte en buena salud.",,,"Voilà, gardez vous en bonne santé.",,,どうぞ、これで体の調子を保って下さい。,건강하고 집중됬을 때 소모하시길.,"Hier, gebruik ze om je in goede gezondheid te houden.",,Pode pegar. Use essa munição para se manter saudável.,,,"Вот. Используй их, чтобы сохранить себя.", -You have enough.,TXT_RNO0_SCRIPT10_D37900_YOUHA,,,,Máš jich dost.,Du hast genug.,,,Tienes suficientes.,,,Vous en avez assez.,,,十分に持っています。,충분히 있으면 더 안 줘요.,Je hebt genoeg.,,Você tem o suficiente.,,,Тебе хватает., -Teach me.,TXT_RPLY1_SCRIPT10_D37900_TEACH,,,,Uč mě.,Unterrichte mich.,,,Enséñame.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,,Me ensine.,,,Обучи меня., -"Well, that's it, you're done. I can teach no more.",TXT_RYES1_SCRIPT10_D37900_WELLT,,,,"Tak, a je to, jsme hotovi. Víc tě naučit nemůžu.","So, das war's. Ich kann dir nicht mehr beibringen.",,,"Bueno, eso es todo, estás listo. No tengo más que enseñar.",,,"Eh bien, voilà. Vous savez tout. Je n'ai rien de plus pour vous!",,,これで全てです。これ以上は教える事がありません。,"흐음, 이게 다입니다. 훈련을 다 마쳤어요.","Nou, dat is het dan, je bent klaar. Ik kan geen les meer geven.",,"Bom, é isso. Você já sabe de tudo. Não consigo ensinar mais nada.",,,"Что ж, это всё. Твоё обучение закончено. Больше я ничему не могу тебя научить.", -Return after Macil tells you it's time.,TXT_RNO1_SCRIPT10_D37900_RETUR,,,,"Vrať se až ti Macil řekne, že je čas.","Komm wieder, wenn Macil sagt, dass es Zeit ist.",,,Vuelve cuando Macil diga que es la hora.,,,Revenez quand Macil vous dit qu'il est temps.,,,マシルに許可を貰わないとなりません。,사령관님의 말씀을 듣고 찾아와주시길.,Keer terug nadat Macil je vertelt dat het tijd is.,,Volte depois que Macil te disser que está na hora.,,,"Возвращайся, когда скажет Мэйсил.", -"I've taught you everything I can right now. I've given you all that you should ever need, unless you're out of bullets. Those I can still help you with.",TXT_DLG_SCRIPT10_D39416_IVETA,,,,"Naučil jsem tě vše, co teď můžu. Dal jsem ti vše, co bys měl potřebovat, ledaže by ti došly náboje. S těmi ti stále můžu pomoci.","Ich habe dir alles beigebracht, was ich weiß. Das sollte alles sein, was du brauchen wirst, es sei denn, du brauchst wieder mal Munition. Damit kann ich dir jederzeit helfen.",,,"Te he enseñado todo lo que puedo por ahora. Te he dado todo lo que puedas necesitar, a menos que te hayas quedado sin balas. Con eso si que te puedo ayudar todavía.",,,"Je vous ai enseigné tout ce que je sais, et tout ce qu'il vous faudra, sauf si n'avez plus de munitions.. Et je peux vous aider pour ça, aussi.",,,"私が教えられる事はもうありません。 +何がしてあげられますか?",아직도 살아 숨 쉬고 있다니 믿기지 않네요... 당신이 싸우고 생존하는 동안 살아 돌아온 병사들은 그렇게 많지 않아요. 원하는 게 있습니까?,"Ik kan niet geloven dat we er nog steeds zijn, jij en ik. Er zijn er gewoon te veel van ons die sinds het begin zijn overleden. Wat kan ik voor je doen, vriend?","Jeg kan ikke tro at vi fortsatt er her, du og jeg. Det er for mange av oss som har gått bort siden begynnelsen. Hva kan jeg gjøre for deg, min venn?","Nie mogę uwierzyć, że jeszcze żyjemy, ty i ja. Zbyt wielu z nas przeszło od początku. Co mogę dla ciebie zrobić, przyjacielu?","Mal consigo acreditar que ainda estamos vivos, você e eu. Perdemos muitos companheiros desde o início. O que posso fazer por você, meu amigo?",,"Nu-mi vine că cred că încă mai rezistăm, tu și eu. Sunt prea mulți cei care au murit de la început. Ce pot face pentru tine, prietene?","Не могу поверить, что мы всё ещё живы, ты и я. За всё это время уже стольких из нас не стало. Что я могу сделать для тебя, дружище?",,"Jag kan inte tro att vi fortfarande finns kvar, du och jag. Det är bara för många av oss som har passerat sedan början. Vad kan jag göra för dig, min vän?","Hala buralarda olduğumuza inanamıyorum, sen ve ben. Başlangıçtan bu yana çok fazla insan geçti. Senin için ne yapabilirim dostum?" +I'm out of bullets.,TXT_RPLY0_SCRIPT10_D37900_IMOUT,〃 (〃),,,Došly mi náboje.,Jeg er løbet tør for kugler.,Ich habe keine Munition mehr.,,Mi ne havas kuglojn.,No me quedan balas.,,Minulta on luodit loppu.,Je suis à court de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Jeg er tom for kuler.,Skończyły mi się kule.,Estou sem munição.,,Nu mai am gloanțe.,У меня кончились патроны.,,Jag har slut på kulor.,Mermim bitti. +"Here, use them to keep you in good health.",TXT_RYES0_SCRIPT10_D37900_HEREU,"〃 (〃) +(in good health = enjoy)",,,"Tady, používej je, abys zůstal ve zdraví.","Her, brug dem til at holde dig sund og rask.","Hier, benutze sie um gesund zu bleiben,",,"Jen iom da municio. +Ŝancon kaj ĝuu ĝin.","Aquí tienes algo de munición. +Suerte y disfrútala.",,"Tässä, pidä niillä itsesi terveenä.","Voilà, gardez vous en bonne santé.","Parancsolj, használd őket az egészséged érdekében.","Ecco qua, usale per tenerti in buona salute.",どうぞ、これで体の調子を保って下さい。,건강하고 집중됬을 때 소모하시길.,"Hier, gebruik ze om je in goede gezondheid te houden.","Her, bruk dem til å holde deg ved god helse.","Użyj ich, by utrzymać cię w dobrym zdrowiu.",Pode pegar. Use essa munição para se manter saudável.,,"Aici, folosește-le ca să te menții în formă.","Вот. Используй их, чтобы сохранить себя.",,"Här, använd dem för att hålla dig vid god hälsa.","Al, onları sağlığını korumak için kullan." +You have enough.,TXT_RNO0_SCRIPT10_D37900_YOUHA,〃 (〃),,,Máš jich dost.,Du har nok.,Du hast genug.,,Vi havas sufiĉe.,Tienes suficientes.,,Sinulla on tarpeeksi.,Vous en avez assez.,Van elég.,Ne hai a sufficienza.,十分に持っています。,충분히 있으면 더 안 줘요.,Je hebt genoeg.,Du har nok.,Masz wystarczająco dużo.,Você tem o suficiente.,,Ai destule.,Тебе хватает.,,Du har tillräckligt.,Sende yeterince var. +Teach me.,TXT_RPLY1_SCRIPT10_D37900_TEACH,〃 (〃),,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Mutasd meg.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Naucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +"Well, that's it, you're done. I can teach no more.",TXT_RYES1_SCRIPT10_D37900_WELLT,〃 (〃),,,"Tak, a je to, jsme hotovi. Víc tě naučit nemůžu.","Nå, det var det, du er færdig. Jeg kan ikke undervise mere.","So, das war's. Ich kann dir nicht mehr beibringen.",,"Nu, jen ĉio, vi estas preta. +Mi havas nenion alian por instrui.","Bueno, eso es todo, estás listo. +No tengo más que enseñar.",,"No, se oli siinä, olet valmis. Minulla ei ole sinulle enää opetettavaa.","Eh bien, voilà. Vous savez tout. Je n'ai rien de plus pour vous!","Elérkeztünk oda, hogy nem tudok többet tanítani neked.","Beh, ecco fatto, oramai hai concluso. Non c'è null'altro che ti possa insegnare.",これで全てです。これ以上は教える事がありません。,"흐음, 이게 다입니다. 훈련을 다 마쳤어요.","Nou, dat is het dan, je bent klaar. Ik kan geen les meer geven.","Vel, det var det, du er ferdig. Jeg kan ikke lære deg mer.","No cóż, to już koniec. Nie mogę więcej uczyć.","Bom, é isso. Você já sabe de tudo. Não consigo ensinar mais nada.",,"Asta e, gata, nu mai am ce să te învăț.","Что ж, это всё. Твоё обучение закончено. Больше я ничему не могу тебя научить.",,"Det var det, du är klar. Jag kan inte undervisa mer.","Pekala, bu kadar, işin bitti. Daha fazla öğretemem." +Return after Macil tells you it's time.,TXT_RNO1_SCRIPT10_D37900_RETUR,〃 (〃),,,"Vrať se až ti Macil řekne, že je čas.","Vend tilbage, når Macil siger, at det er tid.","Komm wieder, wenn Macil sagt, dass es Zeit ist.",,"Revenu kiam Macil diros, +ke vi estas preta.","Vuelve cuando Macil +diga que es la hora.",,"Palaa sitten, kun Macil kertoo sinulle ajan koittaneen.",Revenez quand Macil vous dit qu'il est temps.,"Ha Macil szól hogy idő van, akkor fordulj vissza.",Ritorna quando Macil dice che è arrivato il momento.,マシルに許可を貰わないとなりません。,사령관님의 말씀을 듣고 찾아와주시길.,Keer terug nadat Macil je vertelt dat het tijd is.,Kom tilbake når Macil sier det er på tide.,"Wróć, gdy Macil powie ci, że już czas.",Volte depois que Macil te disser que está na hora.,,Întoarce-te după ce Macil îți spune că e vremea.,"Возвращайся, когда скажет Мэйсил.",,Återvänd när Macil säger att det är dags.,Macil sana zamanın geldiğini söylediğinde geri dön. +"I've taught you everything I can right now. I've given you all that you should ever need, unless you're out of bullets. Those I can still help you with.",TXT_DLG_SCRIPT10_D39416_IVETA,〃 (seven trainings),,,"Naučil jsem tě vše, co teď můžu. Dal jsem ti vše, co bys měl potřebovat, ledaže by ti došly náboje. S těmi ti stále můžu pomoci.","Jeg har lært dig alt, hvad jeg kan lige nu. Jeg har givet dig alt, hvad du nogensinde skulle få brug for, medmindre du er løbet tør for kugler. Dem kan jeg stadig hjælpe dig med.","Ich habe dir alles beigebracht, was ich weiß. Das sollte alles sein, was du brauchen wirst, es sei denn, du brauchst wieder mal Munition. Damit kann ich dir jederzeit helfen.",,"Mi instruis ĉion, kion mi scias, kaj mi donis ĉion, kion vi povus bezoni, krom se vi ne plu havas municion: mi certe ankoraŭ povas helpi pri tio.","Te he enseñado todo lo que puedo y te he dado todo lo que podrías necesitar, a menos que te hayas quedado sin balas, claro: con eso sí te puedo seguir ayudando.","Ya te enseñé todo lo que puedo y te di todo lo que podrías necesitar, a menos que te hayas quedado sin balas, claro: con eso sí te puedo seguir ayudando.","Olen opettanut sinulle kaiken osaamani. Olen antanut sinulle kaiken, mitä ikinä voisit tarvita, ellei sinulta sitten ole luodit loppu. Niiden suhteen voin vielä olla avuksi.","Je vous ai enseigné tout ce que je sais, et tout ce qu'il vous faudra, sauf si n'avez plus de munitions.. Et je peux vous aider pour ça, aussi.","Megtanítottam neked mindent amire most képes vagyok. Mindent megadtam neked amire valaha szükséged lehet, kivétel persze ha kifogysz a golyókból. Azt még mindig tudok adni.","Ti ho insegnato tutto quello che conosco. Ti ho dato tutto ciò di cui avrai mai bisogno, a meno che non hai finito le munizioni. Con quelle ti posso ancora essere d'aiuto.","私が教えられる事はもうありません。 今後新しい武器は時間が掛かるが自分のペースで -学びなさい。弾切れでなければの話ですが。",모든 훈련을 배우고 마치셨잖아요. 당신이 알아둬야 할 건 그게 전부입니다. 그 외에는 탄약이 필요하신가요?,"Ik heb je nu alles geleerd wat ik kan. Ik heb je alles gegeven wat je ooit nodig zou moeten hebben, tenzij je geen kogels meer hebt. Degenen waarmee ik je nog steeds kan helpen.",,"Eu te ensinei tudo o que eu consigo neste momento. Já te passei tudo o que você pode precisar, a não ser que esteja sem munição. Ainda posso te ajudar com isso.",,,"Я обучил тебя всему, что умею сам. Всему, что тебе может когда-нибудь пригодиться. Больше я ничем не могу тебе помочь — если, конечно, у тебя не кончились патроны.", -Yes I am.,TXT_RPLY0_SCRIPT10_D39416_YESIA,,,,"Ano, došly.","Ja, bin ich.",,,"Si, eso es.",,,"Oui, j'en ai besoin.",,,ああ、そうだ。,알겠습니다. 그럼 탄약이라도?,"Ja, dat ben ik wel.",,Estou mesmo.,,,"Да, кончились.", -Here you go. ,TXT_RYES0_SCRIPT10_D39416_HEREY,,,,Tady máš.,Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,どうぞ。,탄약 대령이요!,Alsjeblieft.,,Aqui está.,,,Держи., -"Check out what's new, the teleporter beacon. When you use the beacon, we'll track the signal and send help. Is there something I can get you?",TXT_DLG_SCRIPT10_D40932_CHECK,,,,"Podívej se na tohle, teleportační maják. Když ho použiješ, vystopujeme jeho signál a pošleme pomoc. Co ti můžu nabídnout?","Sieh mal, was ich Neues habe, das Teleportersignal. Wenn du es benutzt können wir das Signal anpeilen und dir Hilfe schicken. Gibt es sonst was, was ich tun kann?",,,"Mira qué novedad, el faro de teletransporte. Cuando uses el faro, trazaremos la señal y enviaremos ayuda. ¿Hay algo que pueda ofrecerte?",,,"Regardez ce qu'on vient de sortir: L'antenne de téléporteur. Quand vous l'utilisez, on traque le signal et on envoie des renforts. Que puis-je faire pour vous?",,,"何を見つけたと思う、テレポータービーコンだ。 +学びなさい。弾切れでなければの話ですが。",모든 훈련을 배우고 마치셨잖아요. 당신이 알아둬야 할 건 그게 전부입니다. 그 외에는 탄약이 필요하신가요?,"Ik heb je nu alles geleerd wat ik kan. Ik heb je alles gegeven wat je ooit nodig zou moeten hebben, tenzij je geen kogels meer hebt. Degenen waarmee ik je nog steeds kan helpen.","Jeg har lært deg alt jeg kan akkurat nå. Jeg har gitt deg alt du trenger, med mindre du er tom for kuler. De kan jeg fortsatt hjelpe deg med.","Nauczyłem cię wszystkiego, co mogę teraz. Dałem ci wszystko, co powinno ci być potrzebne, chyba że zabraknie ci naboi. Z tymi mogę ci jeszcze pomóc.","Eu te ensinei tudo o que eu consigo neste momento. Já te passei tudo o que você pode precisar, a não ser que esteja sem munição. Ainda posso te ajudar com isso.",,"Te-am învățat tot ce știu pentru moment. Ți-am dat tot ceea ce ai putea avea avea nevoie vreodată, decât dacă nu ai rămas cumva fără gloanțe. Cu astea te pot ajuta încă.","Я обучил тебя всему, что умею сам. Всему, что тебе может когда-нибудь пригодиться. Больше я ничем не могу тебе помочь... если, конечно, у тебя патроны не кончились.",,"Jag har lärt dig allt jag kan just nu. Jag har gett dig allt du någonsin skulle behöva, om du inte har slut på kulor. De kan jag fortfarande hjälpa dig med.",Şu anda sana öğretebileceğim her şeyi öğrettim. Mermin bitmediği sürece ihtiyacın olan her şeyi verdim. Onlar için sana hala yardım edebilirim. +Yes I am.,TXT_RPLY0_SCRIPT10_D39416_YESIA,〃 (〃),,,"Ano, došly.","Ja, det er jeg.","Ja, bin ich.",,Vi trafis.,Has acertado.,Acertaste.,Kyllä on.,"Oui, j'en ai besoin.",Igen.,"Sì, ho bisogno di munizioni.",ああ、そうだ。,알겠습니다. 그럼 탄약이라도?,"Ja, dat ben ik wel.","Ja, det er jeg.","Tak, jestem.",Estou mesmo.,,Da sunt.,"Да, кончились.",,"Ja, det gör jag.","Evet, ediyorum." +Here you go. ,TXT_RYES0_SCRIPT10_D39416_HEREY,〃 (〃),,,Tady máš.,Værsgo.,Bitteschön.,,Jen.,Toma.,,Ole hyvä.,Voilà pour vous.,Parancsolj.,Ecco a te.,どうぞ。,탄약 대령이요!,Alsjeblieft.,Vær så god.,Proszę bardzo.,Aqui está.,,Iată.,Держи.,,Här har du.,Al bakalım. +"Check out what's new, the teleporter beacon. When you use the beacon, we'll track the signal and send help. Is there something I can get you?",TXT_DLG_SCRIPT10_D40932_CHECK,MAP10: Justin.,,,"Podívej se na tohle, teleportační maják. Když ho použiješ, vystopujeme jeho signál a pošleme pomoc. Co ti můžu nabídnout?","Se det nye, teleporterfyret. Når du bruger fyret, sporer vi signalet og sender hjælp. Er der noget, jeg kan skaffe dig?","Sieh mal, was ich Neues habe, das Teleportersignal. Wenn du es benutzt können wir das Signal anpeilen und dir Hilfe schicken. Gibt es sonst was, was ich tun kann?",,"Kia novaĵo: la teleportil-signalilo. Post kiam vi uzos ĝin, ni spuros la signalon kaj sendos helpotrupojn. Ĉu estas io, kion mi donu al vi?","Mira qué novedad: la baliza de teletransporte. Cuando la uses, rastrearemos la señal y enviaremos refuerzos. ¿Hay algo que pueda ofrecerte?","Mira qué novedad: la baliza de teletransporte. Cuando la uses, vamos a rastrear la señal y a mandarte refuerzos. ¿Hay algo que pueda ofrecerte?","Vilkaisepa tätä uutta kaukosiirrinmajakkaa. Kun käytät majakkaa, jäljitämme signaalin ja lähetämme apua. Saisiko sinulle olla jotain?","Regardez ce qu'on vient de sortir: L'antenne de téléporteur. Quand vous l'utilisez, on traque le signal et on envoie des renforts. Que puis-je faire pour vous?","Nézdd csak mit újítottunk be, egy teleport követőt. Amikor aktiválod, behatároljuk a jelet és kiküldjük a segítséget. Segítségedre lehetek még valamiben?","Guarda un po' questo nuovo aggeggio, il radiofaro per teletrasporto. Quando lo usi, identificheremo il tuo segnale e mandaremo rinforzi. C'è qualcosa che ti posso dare?","何を見つけたと思う、テレポータービーコンだ。 ビーコンを使用すると信号を追跡して増援を送る -ことができるぞ。必要な物はあるか?","이 녀석을 확인해보세요! 텔레포터 비컨이라는 건데, 사용해서 신호를 전송하면 병력을 보내겠습니다. 그 외에 원하는 게 있어요?","Kijk eens wat er nieuw is, het teleporterbaken. Als je het baken gebruikt, volgen we het signaal en sturen we hulp. Is er iets dat ik je kan krijgen?",,"Veja só esta novidade, o sinalizador de teletransporte. Quando você usa o sinalizador, nós rastreamos o sinal e enviamos reforços. Posso te ajudar com alguma coisa?",,,"Посмотри на эту новинку: телепортационный маяк. Когда ты его включишь, мы проследим сигнал и вышлем подмогу. Итак, что я могу тебе предложить?", -Box of rockets,TXT_RPLY0_SCRIPT10_D40932_BOXOF,,,,Bednu raket,Kiste Raketen.,,,Caja de cohetes.,,,Boîte de roquettes.,,,ロケット箱,미니 미사일 한 박스,Doos met raketten,,Caixa de foguetes,,,Коробку ракет, -There you go.,TXT_RYES0_SCRIPT10_D40932_THERE,,,,Tady máš.,Bitteschön.,,,Ahí tienes.,,,Voilà pour vous.,,,はい、どうぞ。,여기 있어!,Daar ga je.,,Aqui está.,,,Бери., -You can't afford that!,TXT_RNO0_SCRIPT10_D40932_YOUCA,,,,Tu si nemůžeš dovolit!,Das kannst du dir nicht leisten.,,,¡No puedes adquirir eso!,,,Vous n'avez pas assez d'argent.,,,買うだけの余裕が無い!,돈이 부족한 것 같은데!,Dat kan je je niet betalen!,,Você não pode comprar isto!,,,Ты не можешь себе этого позволить!, -H-E grenades.,TXT_RPLY1_SCRIPT10_D40932_HEGRE,,,,Výbušné granáty,HE-Granaten.,,,Granadas HE.,,,Grenades explosives.,,,HEグレネード,고폭 유탄,H-E-granaten.,,Granadas explosivas.,,,Осколочные гранаты, -Here you go.,TXT_RYES1_SCRIPT10_D40932_HEREY,,,,Tady máš.,Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,どうぞ。,거래 감사드립니다!,Alsjeblieft.,,Aqui está.,,,Держи., -Come back when you have enough money.,TXT_RNO1_SCRIPT10_D40932_COMEB,,,,Vrať se až budeš mít dost peněz.,"Komm wieder, wenn du genug Gold hast.",,,Vuelve cuando tengas suficiente dinero.,,,Revenez quand vous avez assez d'argent.,,,十分持ってたらまた来い。,돈이 충분할 때 다시와요.,Kom terug als je genoeg geld hebt.,,Volte quando tiver dinheiro suficiente.,,,"Возвращайся, когда у тебя будут деньги.", -Energy pod,TXT_RPLY2_SCRIPT10_D40932_ENERG,,,,Energetický kokón,Energiezelle.,,,Vaina de energía,,,Cellule énergétique.,,,エネルギーポッド,에너지 포드,Energiecapsule,,Célula de energia.,,,Энергоячейку, -Here's your energy pod,TXT_RYES2_SCRIPT10_D40932_HERES,,,,Tady ho máš.,Hier hast du deine Energiezele.,,,Aquí tienes tu vaina de energía,,,Voilà votre cellule.,,,これがエネルギーポッドだ。,에너지 포드 한 개 대령이요!,Hier is je energiecapsule...,,Aqui está a sua célula de energia.,,,Вот твоя энергоячейка., -You don't have enough for that.,TXT_RNO2_SCRIPT10_D40932_YOUDO,,,,Na ten nemáš dost.,"Nein, du hast nicht genug Gold dafür.",,,No tienes suficiente para eso.,,,Vous n'avez pas assez d'argent pour ça.,,,それでは足りない。,이 물품은 비싸죠. 저도 압니다.,Daar heb je niet genoeg voor.,,Você não tem o suficiente para isto.,,,У тебя недостаточно денег., -Teleporter beacon,TXT_RPLY3_SCRIPT10_D40932_TELEP,,,,Teleportační maják,Teleportersignal.,,,Faro de teletransporte,,,Antenne de téléporteur.,,,テレポータービーコン,텔레포터 비콘,Teleporter baken,,Sinalizador de teletransporte,,,Телепортационный маяк, -"Help, when and where you need it.",TXT_RYES3_SCRIPT10_D40932_HELPW,,,,Pomoc kdekoliv a kdykoliv je třeba.,"Hilfe, wenn und wo sie gebraucht wird.",,,"Ayuda, cuando y donde la necesites.",,,"De l'aide, quand il vous en faut.",,,助けが必要になったら使うんだ。,위급한 상황에서만 사용하시길.,"Help, waar en wanneer je het nodig hebt.",,"Reforços, quando e onde você precisar.",,,Теперь ты сможешь получить помощь всегда и везде., -"Sorry, no charity.",TXT_RNO3_SCRIPT10_D40932_SORRY,,,,"Promiň, nejsme charita.","Tut mir leid, wir sind keine Wohltätigkeitsveranstaltung.",,,"Lo siento, no es caridad.",,,"Désolé, on n'est pas une charité.",,,すまない、チャリティーじゃないんだ。,"미안하지만, 여긴 자선단체가 아니에요.","Sorry, geen liefdadigheid.",,"Sinto muito, mas não fazemos caridade.",,,Прости. Никакой благотворительности., -"Now that we actually have the castle under control, we have to be extra vigilant to keep it. The Order's probably getting ready to strike back right now.",TXT_DLG_SCRIPT10_D42448_NOWTH,,,,Teď když máme hrad pod kontrolou musíme s ním být ještě obezřetnější. Řád se pravděpodobně právě teď připravuje zaútočit.,"Jetzt, wo wir die Burg unter Kontrolle haben, müssen wir besonders wachsam sein, um sie nicht wieder zu verlieren. Der Orden bereitet womöglich gerade jetze einen Gegenschlag vor.",,,Ahora que realmente tenemos el castillo bajo control tenemos que estar bien alerta para guardarlo. La Orden probablemente se esté preparando para contraatacar ahora mismo.,,,"Maintenant que le château est sous notre contrôle, nous devons être très vigilants pour le conserver. L'Ordre se prépare sans doute à riposter maintenant.",,,"城が管理下に入った今、維持させるためには +ことができるぞ。必要な物はあるか?","이 녀석을 확인해보세요! 텔레포터 비컨이라는 건데, 사용해서 신호를 전송하면 병력을 보내겠습니다. 그 외에 원하는 게 있어요?","Kijk eens wat er nieuw is, het teleporterbaken. Als je het baken gebruikt, volgen we het signaal en sturen we hulp. Is er iets dat ik je kan krijgen?","Se hva som er nytt, teleportersignalet. Når du bruker den, sporer vi signalet og sender hjelp. Er det noe jeg kan hente til deg?","Zobaczcie, co nowego - teleporter. Kiedy użyjesz nadajnika, namierzymy sygnał i wyślemy pomoc. Czy jest coś, co mogę ci dać?","Veja só esta novidade, o sinalizador de teletransporte. Quando você usa o sinalizador, nós rastreamos o sinal e enviamos reforços. Posso te ajudar com alguma coisa?",,"Iată ce e nou, un far. Când folosești farul, ne ghidăm după el și trimitem întăriri. E ceva ce ți-aș putea aduce?","Посмотри на эту новинку: телепортационный маяк. Когда ты его включишь, мы проследим сигнал и вышлем подмогу. Итак, что я могу тебе предложить?",,"Kolla in vad som är nytt, teleporterfyren. När du använder fyren spårar vi signalen och skickar hjälp. Finns det något jag kan ge dig?","Yeni olan şeye bak, ışınlayıcı işaret. İşareti kullandığında, sinyali takip edip yardım göndereceğiz. Size getirebileceğim bir şey var mı?" +Box of rockets,TXT_RPLY0_SCRIPT10_D40932_BOXOF,〃,,,Bednu raket,En kasse med raketter,Kiste Raketen.,,Misilet-keston,Caja de minimisiles,,Rakettilaatikko.,Boîte de roquettes.,Egy doboz rakéta kellene.,Cassa di razzi,ロケット箱,미니 미사일 한 박스,Doos met raketten,En eske med raketter.,Pudełko z rakietami,Caixa de foguetes,,Cutie de rachete.,Коробку ракет,,En låda med raketer.,Roket kutusu +There you go.,TXT_RYES0_SCRIPT10_D40932_THERE,〃,,,Tady máš.,Værsgo.,Bitteschön.,,Jen.,Toma.,,Ole hyvä.,Voilà pour vous.,Parancsolj.,Ecco a te.,はい、どうぞ。,여기 있어!,Daar ga je.,Vær så god.,No i proszę.,Aqui está.,,Iată.,Бери.,,Här har du.,Al bakalım. +You can't afford that!,TXT_RNO0_SCRIPT10_D40932_YOUCA,〃,,,Tu si nemůžeš dovolit!,Det har du ikke råd til!,Das kannst du dir nicht leisten.,,Vi ne povas sen mono!,¡No te alcanza!,,Sinulla ei ole siihen varaa!,Vous n'avez pas assez d'argent.,Arra neked aztán nem tellik.,Non hai abbastanza soldi.,買うだけの余裕が無い!,돈이 부족한 것 같은데!,Dat kan je je niet betalen!,Det har du ikke råd til!,Nie stać cię na to!,Você não pode comprar isto!,,Nu-ți poți permite asta!,Ты не можешь себе этого позволить!,,Du har inte råd med det!,Bunu karşılayamazsın! +H-E grenades.,TXT_RPLY1_SCRIPT10_D40932_HEGRE,〃,,,Výbušné granáty,H-E granater.,HE-Granaten.,,Eksplodeg-povajn grenadojn,Granadas de conmoción,,Räjähdekranaatteja.,Grenades explosives.,Robbanó gránátot.,Granate ad alto potenziale esplosivo,HEグレネード,고폭 유탄,H-E-granaten.,H-E-granater.,Granaty H-E.,Granadas explosivas.,,Grenade.,Осколочные гранаты,,H-E-granater.,H-E el bombaları. +Here you go.,TXT_RYES1_SCRIPT10_D40932_HEREY,〃,,,Tady máš.,Værsgo.,Bitteschön.,,Jen.,Toma.,,Ole hyvä.,Voilà pour vous.,Parancsolj.,Eccole qua.,どうぞ。,거래 감사드립니다!,Alsjeblieft.,Vær så god.,Proszę bardzo.,Aqui está.,,Iată.,Держи.,,Varsågod.,Al bakalım. +Come back when you have enough money.,TXT_RNO1_SCRIPT10_D40932_COMEB,〃,,,Vrať se až budeš mít dost peněz.,"Kom tilbage, når du har penge nok.","Komm wieder, wenn du genug Gold hast.",,"Revenu kiam vi havos +sufiĉe da mono.","Vuelve cuando tengas +suficiente dinero.",,"Palataan asiaan sitten, kun sinulla on riittävästi rahaa.",Revenez quand vous avez assez d'argent.,"Gyere vissza, ha már van elég pénzed.",Ritorna quando avrai i soldi.,十分持ってたらまた来い。,돈이 충분할 때 다시와요.,Kom terug als je genoeg geld hebt.,Kom tilbake når du har nok penger.,"Wróć, gdy będziesz miał wystarczająco dużo pieniędzy.",Volte quando tiver dinheiro suficiente.,,Întoarce-te când ai destui bani.,"Возвращайся, когда у тебя будут деньги.",,Kom tillbaka när du har tillräckligt med pengar.,Yeterli paran olduğunda geri gel. +Energy pod,TXT_RPLY2_SCRIPT10_D40932_ENERG,〃,,,Energetický kokón,Energibælg,Energiezelle.,,Energi-kapsulon,Cápsula de energía,,Energia-akku.,Cellule énergétique.,Energia cella.,Nucleo energetico,エネルギーポッド,에너지 포드,Energiecapsule,Energikapsel,Statyw energetyczny.,Célula de energia.,,Capsulă energetică.,Энергоячейку,,Energipod.,Enerji kapsülü +Here's your energy pod,TXT_RYES2_SCRIPT10_D40932_HERES,〃,,,Tady ho máš.,Her er din energibælg.,Hier hast du deine Energiezele.,,Jen ĝi.,Aquí la tienes.,,Tässä energia-akkusi.,Voilà votre cellule.,Itt van az energia cellád.,Ecco il tuo nucleo energetico.,これがエネルギーポッドだ。,에너지 포드 한 개 대령이요!,Hier is je energiecapsule...,Her er energikapselen din.,Oto twój pojemnik na energię.,Aqui está a sua célula de energia.,,Iată capsula energetică.,Вот твоя энергоячейка.,,Här är din energipodd.,İşte enerji kapsülün. +You don't have enough for that.,TXT_RNO2_SCRIPT10_D40932_YOUDO,〃,,,Na ten nemáš dost.,Du har ikke nok til det.,"Nein, du hast nicht genug Gold dafür.",,"Vi ne havas +sufiĉe da mono.",No te alcanza para eso.,,Sinulla ei ole tarpeeksi sitä varten.,Vous n'avez pas assez d'argent pour ça.,"Nincs elég nálad, hogy megvedd.",Non hai abbastanza soldi per quello.,それでは足りない。,이 물품은 비싸죠. 저도 압니다.,Daar heb je niet genoeg voor.,Du har ikke nok til det.,Nie masz na to wystarczająco dużo.,Você não tem o suficiente para isto.,,Nu ai suficiente fonduri pentru asta.,У тебя недостаточно денег.,,Du har inte tillräckligt för det.,Bunun için yeterince paran yok. +Teleporter beacon,TXT_RPLY3_SCRIPT10_D40932_TELEP,〃,,,Teleportační maják,Teleportørfyr,Teleportersignal.,,Teleportil-signalilon,Baliza de teletransporte,,Kaukosiirrinmajakka,Antenne de téléporteur.,Teleport követő,Radiofaro per teletrasporto.,テレポータービーコン,텔레포터 비콘,Teleporter baken,Teleporteringssignal,Teleporter beacon,Sinalizador de teletransporte,,Far pentru teleportare.,Телепортационный маяк,,Teleporterfyren,Işınlayıcı işaretçisi +"Help, when and where you need it.",TXT_RYES3_SCRIPT10_D40932_HELPW,〃,,,Pomoc kdekoliv a kdykoliv je třeba.,"Hjælp, når og hvor du har brug for det.","Hilfe, wenn und wo sie gebraucht wird.",,"Helpo kiam kaj kie +vi bezonos ĝin.","Refuerzos cuando y +donde los necesites.",,"Apua, missä ja milloin ikinä tarvitsetkaan.","De l'aide, quand il vous en faut.","Segítség, amikor és ahol akarod.",Con questo riceverai aiuto dove e quando ti servirà.,助けが必要になったら使うんだ。,위급한 상황에서만 사용하시길.,"Help, waar en wanneer je het nodig hebt.","Hjelp, når og hvor du trenger det.","Pomoc, kiedy i gdzie jej potrzebujesz.","Reforços, quando e onde você precisar.",,"Ajutor, acolo și când ai nevoie de el.",Теперь ты сможешь получить помощь всегда и везде.,,"Hjälp, när och var du behöver den.",İhtiyacınız olduğu zaman ve yerde yardım. +"Sorry, no charity.",TXT_RNO3_SCRIPT10_D40932_SORRY,〃,,,"Promiň, nejsme charita.","Beklager, ingen velgørenhed.","Tut mir leid, wir sind keine Wohltätigkeitsveranstaltung.",,"Pardonon, ĉi tio +ne estas almozulejo.","Lo siento, no es caridad.",,"Valitan, ei hyväntekeväisyyttä.","Désolé, on n'est pas une charité.","Sajnálom, ez nem jótékonyság.","Mi spiace, ma niente beneficienza.",すまない、チャリティーじゃないんだ。,"미안하지만, 여긴 자선단체가 아니에요.","Sorry, geen liefdadigheid.","Beklager, ingen veldedighet.","Przykro mi, ale nie ma mowy o dobroczynności.","Sinto muito, mas não fazemos caridade.",,"Scuze, nu e caritate.",Прости. Никакой благотворительности.,,"Tyvärr, ingen välgörenhet.","Üzgünüm, hayırseverlik yok." +"Now that we actually have the castle under control, we have to be extra vigilant to keep it. The Order's probably getting ready to strike back right now.",TXT_DLG_SCRIPT10_D42448_NOWTH,MAP10: Rebels in Macil's room.,,,"Teď když máme hrad pod kontrolou, musíme být ještě obezřetnější. Řád se pravděpodobně právě teď připravuje zaútočit.","Nu hvor vi faktisk har slottet under kontrol, skal vi være ekstra opmærksomme for at holde det. Ordenen er sikkert ved at gøre sig klar til at slå tilbage lige nu.","Jetzt, wo wir die Burg unter Kontrolle haben, müssen wir besonders wachsam sein, um sie nicht wieder zu verlieren. Der Orden bereitet womöglich gerade jetze einen Gegenschlag vor.",,"Nun kiam ni regas la kastelon, ni devas esti duoble atentaj por konservi ĝin; La Ordeno verŝajne pretiĝas kontraŭataki iam ajn.",Ahora que ya tenemos el castillo bajo control hay que estar el doble de alertas para cuidarlo; La Orden de seguro se está preparando para contraatacar en cualquier momento.,,"Nyt, kun linna on todellakin meidän hallinnassamme, meidän on oltava erityisen valppaita pitääksemme sen. Veljeskunta on luultavasti parhaillaan valmistautumassa vastahyökkäykseen.","Maintenant que le château est sous notre contrôle, nous devons être très vigilants pour le conserver. L'Ordre se prépare sans doute à riposter maintenant.","Most, hogy már az egész kastély az irányításunk alatt van, még szemfülesebbnek kell lennünk, hogy megtarthassuk. A Rend valószínű, hogy a visszavételre készül.","Adesso che abbiamo il castello sotto controllo, dobbiamo essere ancora più vigili per tenerlo sotto controllo. L'Ordine sicuramente starà preparando un contrattacco.","城が管理下に入った今、維持させるためには 更なる警戒網が必要になるだろう。オーダーは -反撃の準備をしているはずだ。",성을 공격해 점령한 이후로 화력과 병력 등을 많이 증가시킬 수 있게 되었습니다. 오더 놈들은 분명히 이를 대비한 역습을 준비하고 있을 거예요.,"Nu we het kasteel daadwerkelijk onder controle hebben, moeten we extra waakzaam zijn om het onder controle te houden. De Orde maakt zich waarschijnlijk klaar om nu meteen terug te slaan.",,"Agora que temos o castelo sob controle, precisamos estar mais alertas para mantê-lo assim. A Ordem provavelmente está se preparando para contra-atacar neste momento.",,,"Теперь, когда мы захватили замок, нам нужно быть особенно бдительными, чтобы его удержать. Может быть, в этот самый момент Орден готовится контратаковать.", -Be careful out there.,TXT_DLG_SCRIPT10_D43964_BECAR,,,,Buď tam venku opatrný.,Sei vorsichtig da draußen.,,,Ten cuidado ahí fuera.,,,Faites attention à vous.,,,外は気を付けろ。,부디 조심하시길.,Wees voorzichtig daarbuiten.,,Tome cuidado.,,,Будь настороже., -"Keep up the great work, we couldn't have done it without you.",TXT_DLG_SCRIPT10_D45480_KEEPU,,,,"Jen tak dál, bez tebe bychom to nedokázali.","Großartige Arbeit, mach weiter so. Ohne dich hätten wir es nicht schaffen können.",,,"Sigue así, no podríamos haberlo logrado sin ti.",,,"Continuez votre magnifique travail, nous n'aurions jamais réussi sans vous.",,,"我々は貴方無くして成し遂げる事は出来なかった -素晴らしい働きをしてくれてます。",부디 건투를 빕니다. 당신 덕에 희망을 잃지 않는 거니까!,"Ga zo door, we hadden het zonder jou niet kunnen doen.",,Continue assim. Nós não teríamos conseguido sem você.,,,Продолжай в том же духе. Без тебя мы бы не справились., -I'm the keymaster.,TXT_DLG_SCRIPT11_D0_IMTHE,,,,Já jsem klíčníkem.,Ich bin der Schlüsselmeister.,,,Soy el amo de llaves.,,,Je suis le maître des clés.,,,僕がキーマスターだ。,전 열쇠지기에요.,Ik ben de sleutelbeheerder.,,Eu sou o mestre das chaves.,,,Я ключник., -"A lot of people would say this is a thankless and insignificant job. But it's not, in fact...",TXT_DLG_SCRIPT11_D1516_ALOTO,,,,"Většina lidí by řekla, že tohle je nevděčná a nedůležitá práce, ale není, naopak...","Eine Menge Leute würden sagen, dies sei eine undankbare Aufgabe, aber das ist es nicht, in Wirklichkeit...",,,"Mucha gente diría que éste es un trabajo ingrato e insignificante. Pero no, de hecho...",,,"Beaucoup de gens diraient que c'est un travail insignifiant et ingrat.. Mais en fait, ce n'est vraiment pas le cas.",,,"皆、この仕事が報われないと思っているが -実際はそうでもないんだ...",많은 사람이 이 직업을 감사해야 하고 놀라운 일이라 말하겠죠. 하지만 사실은 아니죠. 사실은...,"Veel mensen zouden zeggen dat dit een ondankbare en onbeduidende klus is. Maar dat is het niet, in feite....",,Muita gente diria que este é um trabalho ingrato e insignificante. Mas na verdade não é...,,,"Многие скажут, что это неблагодарная и незначительная работа, но это не так. На самом деле...", -Give me the key!,TXT_RPLY0_SCRIPT11_D1516_GIVEM,,,,Dej mi klíč!,Gib mir den Schlüssel.,,,¡Dame la llave!,,,Donne moi la clé!,,,鍵をくれ!,망할 열쇠를 줘!,Geef me de sleutel!,,Me dê a chave!,,,Дай мне ключ!, -"OK, but remember, I'm the keymaster.",TXT_DLG_SCRIPT11_D3032_OKBUT,,,,"Dobře, ale nezapomeň, já jsem klíčník.","Ok, aber vergiß nicht, dass ICH der Schlüsselmeister bin.",,,"Ok, pero recuerda, soy el amo de llaves.",,,"Ok, mais souviens-toi, je suis le maître des clés.",,,オーケー、なんせ僕は、キーマスターだしな。,"좋아요, 하지만 기억해요. 전 열쇠지기랍니다!","Oké, maar onthoud, ik ben de sleutelbeheerder.",,"Ok, mas lembre-se, eu sou o mestre das chaves.",,,"Держи, но помни — я ключник!", -"OK pal, whatever.",TXT_RPLY0_SCRIPT11_D3032_OKPAL,,,,"Jasně, kámo, klidně.","Was auch immer, Kumpel.",,,"Ok colega, lo que tú digas.",,,"Comme tu veux, mon ami.",,,わかった、何なりと。,"그래, 어쨌든 간에...","Oké, vriend, wat dan ook.",,"Ok, amigo. Que seja.",,,Ага. Без проблем., -I'm the keymaster.,TXT_DLG_SCRIPT11_D4548_IMTHE,,,,Já jsem klíčníkem.,Ich bin der Schlüsselmeister.,,,Soy el amo de llaves.,,,Je suis le maître des clés.,,,僕がキーマスターだ。,열쇠지기. 그게 바로 저죠!,Ik ben de sleutelbeheerder.,,Eu sou o mestre das chaves.,,,Я ключник., -Die traitor!,TXT_DLG_SCRIPT11_D6064_DIETR,,,,"Zemři, zrádče!","Stirb, Verräter.",,,"¡Muere, traidor!",,,"Meurs, traître!",,,死ね、反逆者!,"죽어라, 배신자!","Sterf, verrader.",,"Morra, traidor!",,,"Умри, предатель!", -Die traitor!,TXT_DLG_SCRIPT11_D7580_DIETR,,,,"Zemři, zrádče!","Stirb, Verräter.",,,"¡Muere, traidor!",,,"Meurs, traître!",,,死ね、反逆者!,"뒈져라, 배신자!","Sterf, verrader.",,"Morra, traidor!",,,"Умри, предатель!", -"Have you come to gloat? Even though we're behind these bars, as long as we hold on, you still lose.",TXT_DLG_SCRIPT11_D9096_HAVEY,,,,"Přišel ses vysmívat? I když jsme za mřížemi, dokud jsme na nohou, ty jsi poražený.","Bist du zum Glotzen gekommen? Auch wenn wir hinter Gittern sind, solange wir nicht aufgeben wirst du immer noch verlieren.",,,"¿Has venido a regodearte? Aunque estemos entre rejas, mientras sigamos en pie, has perdido.",,,"Vous êtes venu vous moquer de nous? Même si on est derrière les barreaux, du moment que l'on reste en vie, vous allez perdre.",,,"何睨んでるんだ?この棒が俺達を囲んでる限り、 -お前は未だに負けている。","거들먹거리러 온 거냐? 비록 우리가 이 철창에 갇히긴 했지만, 좀 버티기만 하면, 너는 질 거라고.","Ben je gekomen om je te verkneukelen? Ook al zitten we achter deze tralies, zolang we ons vasthouden, verlies je nog steeds.",,"Você veio se gabar? Mesmo que a gente esteja atrás destas grades, enquanto resistirmos, você ainda perde.",,,"Пришёл поглумиться? Пусть мы и за этими решётками, но пока мы живы, вам не победить.", -Let us out of here!,TXT_DLG_SCRIPT11_D10612_LETUS,,,,Pusť nás odsud!,Lass uns hier raus!,,,¡Sácanos de aquí!,,,Sortez nous de là!,,,ここから出してくれ!,우릴 여기서 내보내 줘!,Laat ons hier uit!,,Nos tire daqui!,,,Выпусти нас отсюда!, -Leave me alone!,TXT_DLG_SCRIPT11_D12128_LEAVE,,,,Nech mě být!,Lass mich in Ruhe!,,,¡Déjame en paz!,,,Foutez moi la paix!,,,ほっといてくれ!,날 좀 내버려 둬!,Laat me met rust!,,Me deixe em paz!,,,Оставь меня в покое!, -"What is the wisdom you seek, simple one?",TXT_DLG_SCRIPT12_D0_WHATI,,,,"Jaké moudro hledáš, jednoduchý?","Welche Weisheit suchst du, Menschling?",,,"¿Cuál es la sabiduría que buscas, simple criatura?",,,"Quelle est la sagesse que vous recherchez, simple humain?",,,迷える者よ、如何なる知識を求めに来た。,그대가 찾고 있는 지혜는 무엇인가? 평범한 자여?,"Wat is de wijsheid die je zoekt, eenvoudige wijsheid?",,"Qual é a sabedoria que você procura, simples criatura?",,,"Какой мудрости ты ищешь, непосвящённый?", -The Sigil of the One God.,TXT_RPLY0_SCRIPT12_D0_THESI,,,,Pečeť Jednoho boha.,Das Sigil des Einen Gottes.,,,El Emblema del Dios Único.,,,Le Sigil du Seul Dieu.,,,唯一神のシジルだ。,"유일신의 인장, 시질이다.",De Sigil van de Ene God.,,O Sigilo do Deus Único.,,,Сигил Единого Бога., -"I feel one fragment resonate within you. The second lies at the heart of the crimson and obsidian tower. There you must combat the Bishop, who is aware, and awaits you. You will find him by following his symbol of power. Take this token to the keymaster. Return to me after you have slain the beast.",TXT_DLG_SCRIPT12_D1516_IFEEL,,,,"Cítím z tebe rezonovat jeden díl. Druhý leží v srdci věže karmíno-obsidiánové. Tam musíš poraziti Biskupa, který si je tě vědom a očekává tě. Najdeš ho následováním symbolu jeho moci. Přijmi tuto známku pro klíčníka. Vrať se ke mě, až skolíš bestii.","Ich fühle, wie ein Fragment in dir pulsiert, Das zweite Teilstück des Sigils befindet sich im Herzen des Turms aus Purpur und Obsidian. Dort wartet der Bischof auf dich, den du bekämpfen musst. Er weiß von dir und wartet. Du findest ihn, wenn du seinem Symbol der Macht folgst. Nimm dieses Zeichen und gebe es dem Schlüsselmeister. Kehr zu mir zurück, nachdem du die Bestie vernichtet hast.",,,"Siento un fragmento resonar en ti. El segundo se encuentra en el corazón de la torre carmesí y obsidiana. Ahí debes combatir con el Obispo, quien sabe, y espera tu llegada. Lo encontrarás siguiendo su símbolo de poder. Lleva este vale al amo de llaves. Vuelve a mí tras haber matado a la bestia.",,,"Je sens un fragment résonner en toi. Le deuxième repose au cœur de la tour d'obsidienne et d'écarlate. Ici, vous devrez défaire l'évêque, qui connaît déjà votre statut, et vous attend patiemment. Vous le trouverez en suivant son symbole de pouvoir. Prenez ce jeton et amenez le au maître des clés. Retournez à moi après que vous ayez vaincu la bête.",,,"お主の持つ欠片が共鳴しているのを感受出来る。 +反撃の準備をしているはずだ。",성을 공격해 점령한 이후로 화력과 병력 등을 많이 증가시킬 수 있게 되었습니다. 오더 놈들은 분명히 이를 대비한 역습을 준비하고 있을 거예요.,"Nu we het kasteel daadwerkelijk onder controle hebben, moeten we extra waakzaam zijn om het onder controle te houden. De Orde maakt zich waarschijnlijk klaar om nu meteen terug te slaan.","Nå som vi faktisk har slottet under kontroll, må vi være ekstra årvåkne for å beholde det. Ordenen gjør seg nok klar til å slå tilbake nå.","Teraz, gdy mamy zamek pod kontrolą, musimy być bardzo czujni, by go utrzymać. Zakon pewnie szykuje się do ataku.","Agora que temos o castelo sob controle, precisamos estar mais alertas para mantê-lo assim. A Ordem provavelmente está se preparando para contra-atacar neste momento.",,"Acum că avem castelul sub control, va trebui să fim și mai vigilenți pentru a-l păstra. Ordinul probabil se pregătește pentru un atac de recuperare chiar acum.","Замок теперь наш, но если хотим его удержать, нужно не терять бдительности. Быть может, именно сейчас Орден готовит контратаку.",,Nu när vi faktiskt har slottet under kontroll måste vi vara extra vaksamma för att behålla det. Ordern gör sig förmodligen redo att slå tillbaka just nu.,"Artık kaleyi kontrol altına aldığımıza göre, onu korumak için daha dikkatli olmalıyız. Tarikat muhtemelen şu anda geri saldırmaya hazırlanıyor." +Be careful out there.,TXT_DLG_SCRIPT10_D43964_BECAR,MAP10: Castle's entrance.,,,Buď tam venku opatrný.,Vær forsigtig derude.,Sei vorsichtig da draußen.,,Agu singarde tie ekstere.,Ten cuidado ahí fuera.,Ten cuidado ahí afuera.,Pidä varasi siellä.,Faites attention à vous.,Vigyázz magadra odakinnt.,Sii cauto là fuori.,外は気を付けろ。,부디 조심하시길.,Wees voorzichtig daarbuiten.,Vær forsiktig der ute.,Bądźcie ostrożni.,Tome cuidado.,,Ai grijă afară.,Будь настороже.,,Var försiktig där ute.,Dışarıda dikkatli olun. +"Keep up the great work, we couldn't have done it without you.",TXT_DLG_SCRIPT10_D45480_KEEPU,MAP10: Rebel in Hospital.,,,"Jen tak dál, bez tebe bychom to nedokázali.","Fortsæt det gode arbejde, vi kunne ikke have gjort det uden jer.","Großartige Arbeit, mach weiter so. Ohne dich hätten wir es nicht schaffen können.",,"Daŭrigu tiel, ni ne estus sukcesintaj sen vi.","Sigue así, no podríamos haberlo logrado sin ti.",,Jatka samaan malliin; emme olisi pärjänneet näin hyvin ilman sinua.,"Continuez votre magnifique travail, nous n'aurions jamais réussi sans vous.","Csak így tovább, nélküled sosem tudtuk volna véghezvinni.","Continua così, non ce l'avremmo fatta senza di te.","我々は貴方無くして成し遂げる事は出来なかった +素晴らしい働きをしてくれてます。",부디 건투를 빕니다. 당신 덕에 희망을 잃지 않는 거니까!,"Ga zo door, we hadden het zonder jou niet kunnen doen.","Fortsett med det flotte arbeidet, vi kunne ikke ha gjort det uten deg.","Kontynuujcie wspaniałą pracę, bez was nie dalibyśmy rady.",Continue assim. Nós não teríamos conseguido sem você.,,"Continuă să faci treabă bună, n-am fi reușit fără tine.",Продолжай в том же духе. Без тебя мы бы не справились.,,"Fortsätt med ert fantastiska arbete, vi hade inte kunnat göra det utan er.","Harika iş çıkarmaya devam edin, siz olmadan bunu başaramazdık." +I'm the keymaster.,TXT_DLG_SCRIPT11_D0_IMTHE,MAP11: Commons (no token).,,,Já jsem tu klíčníkem.,Jeg er nøglemesteren.,Ich bin der Schlüsselmeister.,,Mi estas la ŝlosilestro.,Soy el amo de llaves.,,Olen avainmestari.,Je suis le maître des clés.,Én vagyok a kulcsmester.,Io sono il mastro delle chiavi.,僕がキーマスターだ。,전 열쇠지기에요.,Ik ben de sleutelbeheerder.,Jeg er nøkkelmesteren.,Jestem mistrzem kluczy.,Eu sou o mestre das chaves.,,Sunt stăpânul cheilor.,Я ключник.,,Jag är nyckelmästaren.,Ben anahtar yöneticisiyim. +"A lot of people would say this is a thankless and insignificant job. But it's not, in fact...",TXT_DLG_SCRIPT11_D1516_ALOTO,〃 (Oracle's token),,,"Většina lidí by řekla, že tohle je nevděčná a nedůležitá práce, ale není, naopak...","Mange ville sige, at det er et utaknemmeligt og ubetydeligt job. Men det er det ikke, faktisk...","Eine Menge Leute würden sagen, dies sei eine undankbare Aufgabe, aber das ist es nicht, in Wirklichkeit...",,"Multaj homoj dirus, ke ĉi tiu estas sendanka kaj sensignifa laboro, sed ne, fakte...","Mucha gente diría que este es un trabajo ingrato e insignificante, pero no, de hecho...",,Monet väittäisivät tehtäväni olevan epäkiitollinen ja vähäpätöinen. Mutta oikeasti se ei ole.,"Beaucoup de gens diraient que c'est un travail insignifiant et ingrat.. Mais en fait, ce n'est vraiment pas le cas.","Sokan azt mondják, hogy ez egy hálátlan és jelentéktelen munka. Ám nem is állhatnának messzebb az igazságtól...","Molte persone direbbero che questo è un lavoro ingrato e insignificante. Ma non lo è, infatti...","皆、この仕事が報われないと思っているが +実際はそうでもないんだ...","많은 사람이 이 직업을 감사해야 하고 놀라운 일이라 말하겠죠. 하지만 아닌데, 사실은...","Veel mensen zouden zeggen dat dit een ondankbare en onbeduidende klus is. Maar dat is het niet, in feite....",Mange vil si at dette er en utakknemlig og ubetydelig jobb. Men det er det faktisk ikke...,"Wielu ludzi powiedziałoby, że to niewdzięczna i mało znacząca praca. Ale tak nie jest, w rzeczywistości...",Muita gente diria que este é um trabalho ingrato e insignificante. Mas na verdade não é...,,"O grămadă de oameni ar spune că e o muncă fără mulțumiri și insignifiantă. În realitate, nu este...","Многие скажут, что это неблагодарная и незначительная работа, но это не так. На самом деле...",,"Många skulle säga att det är ett otacksamt och obetydligt jobb. Men det är det inte, i själva verket...","Birçok insan bunun nankör ve önemsiz bir iş olduğunu söyleyebilir. Ama değil, aslında..." +Give me the key!,TXT_RPLY0_SCRIPT11_D1516_GIVEM,〃,,,Dej mi klíč!,Giv mig nøglen!,Gib mir den Schlüssel.,,Donu al mi la ŝlosilon!,¡Dame la llave!,,Anna minulle avain!,Donne moi la clé!,Add ide a kulcsot!,Dammi la chiave!,鍵をくれ!,그냥 망할 열쇠를 줘!,Geef me de sleutel!,Gi meg nøkkelen!,Daj mi klucz!,Me dê a chave!,,Dă-mi cheia!,Дай мне ключ!,,Ge mig nyckeln!,Anahtarı bana ver! +"OK, but remember, I'm the keymaster.",TXT_DLG_SCRIPT11_D3032_OKBUT,〃,,,"Dobře, ale nezapomeň, že klíčník jsem já.","OK, men husk, jeg er nøglemesteren.","Ok, aber vergiß nicht, dass ICH der Schlüsselmeister bin.",,"Bone, sed memoru: mi estas la ŝlosilestro.","Bueno, pero recuerda: soy el amo de llaves.",,"Selvä, mutta muista: minä olen avainmestari.","Ok, mais souviens-toi, je suis le maître des clés.","OK, de emlékezz arra, hogy Én vagyok a kulcsmester.","OK, ma ricorda, io sono il mastro delle chiavi.",オーケー、なんせ僕は、キーマスターだしな。,"좋아요, 하지만 기억해요. 전 열쇠지기랍니다!","Oké, maar onthoud, ik ben de sleutelbeheerder.","OK, men husk at jeg er nøkkelmesteren.","OK, ale pamiętaj, że to ja jestem klucznikiem.","Ok, mas lembre-se, eu sou o mestre das chaves.",,"Bine, dar ține minte, eu sunt stăpânul cheilor.","Держи, но помни: я ключник!",,"Okej, men kom ihåg att jag är nyckelmästaren.","Tamam, ama unutma, anahtar ustası benim." +"OK pal, whatever.",TXT_RPLY0_SCRIPT11_D3032_OKPAL,〃,,,"Jasně, kámo, klidně.","Okay, kammerat.","Was auch immer, Kumpel.",,"Jes, ulo, mi kredas vin.","Sí, colega, lo que tú digas.","Sí, amigo, como tú digas.","Joo joo, ihan sama.","Comme tu veux, mon ami.","OK öreg, nem hat meg.","Sì, certo, come no.",わかった、何なりと。,"그래, 알 게 뭐야...","Oké, vriend, wat dan ook.","OK, kompis, samme det.","OK kolego, nieważne.","Ok, amigo. Que seja.",,"Bine amice, cum spui tu.",Ага. Без проблем.,,"Okej kompis, vad som helst.","Tamam dostum, her neyse." +I'm the keymaster.,TXT_DLG_SCRIPT11_D4548_IMTHE,〃,,,Já jsem tu klíčníkem.,Jeg er nøglemesteren.,Ich bin der Schlüsselmeister.,,Mi estas la ŝlosilestro.,Soy el amo de llaves.,,Minä olen avainmestari.,Je suis le maître des clés.,Én vagyok a kulcsmester.,Io sono il mastro delle chiavi.,僕がキーマスターだ。,열쇠지기. 그게 바로 저죠!,Ik ben de sleutelbeheerder.,Jeg er nøkkelmesteren.,Ja jestem klucznikiem.,Eu sou o mestre das chaves.,,Sunt stăpânul cheilor.,Я ключник.,,Jag är nyckelmästaren.,Anahtar ustası benim. +Die traitor!,TXT_DLG_SCRIPT11_D6064_DIETR,MAP11: Red acolyte at temple's entrance.,,,"Zemři, zrádče!","Dø, forræder!","Stirb, Verräter.",,"Mortu, perfidulo!","¡Muere, traidor!",,"Kuole, petturi!","Meurs, traître!",Halál rád áruló!,Muori traditore!,死ね、反逆者!,"죽어라, 배신자!","Sterf, verrader.",Dø forræder!,Giń zdrajco!,"Morra, traidor!",,Mori trădătorule!,"Умри, предатель!",,"Dö, förrädare!",Geber hain! +Die traitor!,TXT_DLG_SCRIPT11_D7580_DIETR,〃,,,"Zemři, zrádče!","Dø, forræder!","Stirb, Verräter.",,"Mortu, perfidulo!","¡Muere, traidor!",,"Kuole, petturi!","Meurs, traître!",Halál rád áruló!,Muori traditore!,死ね、反逆者!,"뒈져라, 배신자!","Sterf, verrader.",Dø forræder!,Giń zdrajco!,"Morra, traidor!",,Mori trădătorule!,"Умри, предатель!",,"Dö, förrädare!",Geber hain! +"Have you come to gloat? Even though we're behind these bars, as long as we hold on, you still lose.",TXT_DLG_SCRIPT11_D9096_HAVEY,MAP11: Prisoner.,,,"Přišel ses nám vysmívat? I když jsme za mřížemi, dokud jsme na nohou, ty zůstáváš poražený.","Er du kommet for at fryde dig? Selvom vi er bag disse tremmer, så længe vi holder fast, taber du stadig.","Bist du zum Glotzen gekommen? Auch wenn wir hinter Gittern sind, solange wir nicht aufgeben wirst du immer noch verlieren.",,"Ĉu vi venis rikani? Eĉ se ni estas malliberaj, dum ni eltenos, vi perdos.","¿Has venido a regodearte? Aunque estemos entre rejas, mientras sigamos en pie, vosotros perdéis.","¿Viniste a burlarte? Aunque estemos entre rejas, mientras sigamos en pie, ustedes pierden.","Oletko tullut meitä pilkkaamaan? Vaikka olemmekin näiden kaltereiden takansa, niin kunhan vain pidämme pintamme, sinä silti häviät.","Vous êtes venu vous moquer de nous? Même si on est derrière les barreaux, du moment que l'on reste en vie, vous allez perdre.","Dicsekedni jöttél ide? Habár itt rohadunk a rács mögött, amíg kitartunk miénk a győzelem.","Sei venuto a gongolare? Anche se siamo dietro queste sbarre, finché resisteremo, voi perderete.","何睨んでるんだ?この棒が俺達を囲んでる限り、 +お前は未だに負けている。","거들먹거리러 온 거냐? 비록 우리가 이 철창에 갇히긴 했지만, 계속 여기 있으면 넌 아직도 질 거라고.","Ben je gekomen om je te verkneukelen? Ook al zitten we achter deze tralies, zolang we ons vasthouden, verlies je nog steeds.","Har du kommet for å hovere? Selv om vi er bak gitteret, taper du så lenge vi holder fast.","Przyszliście się napawać? Nawet jeśli jesteśmy za tymi kratami, to dopóki się trzymamy, ty wciąż przegrywasz.","Você veio se gabar? Mesmo que a gente esteja atrás destas grades, enquanto resistirmos, você ainda perde.",,"Ai venit să te lauzi? Chiar dacă suntem în spatele gratilor, cât timp rezistăm, tu pierzi.","Пришёл поглумиться? Пусть мы и за этими решётками, но пока мы живы, вам не победить.",,"Har du kommit för att skryta? Även om vi är bakom dessa galler, så länge vi håller ut, förlorar du ändå.","Kına yakmaya mı geldin? Bu parmaklıkların arkasında olsak bile, biz dayandığımız sürece siz kaybedersiniz." +Let us out of here!,TXT_DLG_SCRIPT11_D10612_LETUS,〃,,,Pusť nás odsud!,Lad os komme ud herfra!,Lass uns hier raus!,,Liberigu nin!,¡Sácanos de aquí!,,Päästä meidät pois täältä!,Sortez nous de là!,Engedj ki minket!,Facci uscire da qua!,ここから出してくれ!,우릴 여기서 내보내 줘!,Laat ons hier uit!,Slipp oss ut herfra!,Wypuść nas stąd!,Nos tire daqui!,,Scoate-ne de aici!,Выпусти нас отсюда!,,Släpp ut oss härifrån!,Çıkarın bizi buradan! +Leave me alone!,TXT_DLG_SCRIPT11_D12128_LEAVE,〃,,,Nech mě být!,Lad mig være i fred!,Lass mich in Ruhe!,,Ne ĝenu min!,¡Déjame en paz!,,Jätä minut rauhaan!,Foutez moi la paix!,Hagyj békén!,Lasciami in pace!,ほっといてくれ!,날 좀 내버려 둬!,Laat me met rust!,La meg være i fred!,Zostawcie mnie w spokoju!,Me deixe em paz!,,Lasă-mă în pace!,Оставь меня в покое!,,Lämna mig ifred!,Beni yalnız bırakın! +"What is the wisdom you seek, simple one?",TXT_DLG_SCRIPT12_D0_WHATI,MAP12: Oracle.,,,"Jaké moudro hledáš, jednoduchý?","Hvad er det for en visdom du søger, simple en?","Welche Weisheit suchst du, Menschling?",,"Kiun saĝecon vi serĉas, simplulo?","¿Qué sabiduría buscas, simplón?",,"Mitä viisautta etsit, sinä tietämätön?","Quelle est la sagesse que vous recherchez, simple humain?","Miféle bölcsességet kutatsz, egyszerű barátom?","Qual è la saggezza che cerchi, ottenebrato ?",迷える者よ、如何なる知識を求めに来た。,그대가 찾고 있는 지혜는 어떤 것인가? 평범한 자여?,"Wat is de wijsheid die je zoekt, eenvoudige wijsheid?","Hva er visdommen du søker, enfoldige?","Jakiej mądrości szukasz, prosty?","Qual é a sabedoria que você procura, simples criatura?",,"Ce întelepciune cauți, om simplu?","Какой мудрости ты ищешь, непосвящённый?",,"Vad är det för visdom du söker, enkla man?","Aradığın bilgelik nedir, basit olan?" +The Sigil of the One God.,TXT_RPLY0_SCRIPT12_D0_THESI,〃,,,Pečeť Jednoho boha.,Sigilet af den ene Gud.,Das Sigil des Einen Gottes.,,La Sigelon de la Vera Dio.,El Emblema del Dios Único.,,Yhden Ainoan Jumalan Sinettiä.,Le Sigil du Seul Dieu.,Az egy Igaz Isten pecsétjét.,Il Sigillo dell'Unico Dio.,唯一神のシジルだ。,"유일신의 인장, 시질이다.",De Sigil van de Ene God.,Den ene Guds sigill.,Sigil Jedynego Boga.,O Sigilo do Deus Único.,,Sigiliul Adevăratului Zeu.,Печать Единого Бога.,,Den ende gudens signum.,Tek Tanrı'nın Mührü. +"I feel one fragment resonate within you. The second lies at the heart of the crimson and obsidian tower. There you must combat the Bishop, who is aware, and awaits you. You will find him by following his symbol of power. Take this token to the keymaster. Return to me after you have slain the beast.",TXT_DLG_SCRIPT12_D1516_IFEEL,〃,,,"Cítím z tebe rezonovat jeden díl. Druhý leží v srdci věže karmíno-obsidiánové. Tam musíš poraziti Biskupa, který si je tě vědom a očekává tě. Najdeš ho následováním symbolu jeho moci. Přijmi tuto známku pro klíčníka. Vrať se ke mě, až skolíš bestii.","Jeg føler et fragment resonere i dig. Det andet ligger i hjertet af det purpurfarvede og obsidian tårn. Der skal du bekæmpe biskoppen, som er klar over det og venter på dig. Du finder ham ved at følge hans symbol for magt. Tag dette symbol med til nøglemesteren. Vend tilbage til mig, når du har dræbt udyret.","Ich fühle, wie ein Fragment in dir pulsiert, Das zweite Teilstück des Sigils befindet sich im Herzen des Turms aus Purpur und Obsidian. Dort wartet der Bischof auf dich, den du bekämpfen musst. Er weiß von dir und wartet. Du findest ihn, wenn du seinem Symbol der Macht folgst. Nimm dieses Zeichen und gebe es dem Schlüsselmeister. Kehr zu mir zurück, nachdem du die Bestie vernichtet hast.",,"Mi sentas, ke fragmento resonas en vi. La dua situas en la koro de la turo karmezina kaj obsidiankolora: tie vi devas batali kontraŭ la Episkopo, kiu antaŭsciis ĉi tion kaj atendas vin; vi trovos lin sekvante lian povsimbolon. Donu ĉi tiun paspermeson al la ŝlosilestro. Mortiginte la beston, revenu ĉi tien.",Siento un fragmento resonar en ti. El segundo se encuentra en el corazón de la torre carmesí y obsidiana: ahí debes combatir con el Obispo que sabe y espera tu llegada; lo encontrarás siguiendo su símbolo de poder. Llévale este pase al amo de llaves. Vuelve a mí después de matar a la bestia.,Siento un fragmento resonar en ti. El segundo se encuentra en el corazón de la torre carmesí y obsidiana: ahí debes combatir con el Obispo que sabe y espera tu llegada; lo vas a encontrar siguiendo su símbolo de poder. Llévale este pase al amo de llaves. Vuelve a mí después de matar a la bestia.,"Minä tunnen yhden osasen väräjävän sisälläsi. Toinen piilee purppuranpunaisen laavalasisen tornin sydämessä. Siellä pitää sinun taisteleman Piispaa vastaan, joka on tietoinen ja sinua odottava. Löydät hänet seuraamalla hänen valtansa tunnuskuvaa. Toimita tämä merkki avainmestarille. Palaa tyköni surmattuasi pedon.","Je sens un fragment résonner en toi. Le deuxième repose au cœur de la tour d'obsidienne et d'écarlate. Ici, vous devrez défaire l'évêque, qui connaît déjà votre statut, et vous attend patiemment. Vous le trouverez en suivant son symbole de pouvoir. Prenez ce jeton et amenez le au maître des clés. Retournez à moi après que vous ayez vaincu la bête.","Érzem rajta az egyik darabot. A másodikat a karmazsin és obszidián toronyban találod meg. Ott viszont már várni fog rád a Püspök. Meg fogod lelni őt, ha követed a jelét. Vidd ezt a zálogot a kulcsmesterhez. Térj vissza hozzám, ha legyűrted a szörnyet.","Avverto che possiedi uno dei frammenti. Il secondo si trova nel cuore della torre cremisina e ossidiana. Lì dovrai combattere contro il Vescovo, che già ti attende. Lo troverai seguendo il suo simbolo del potere. Prendi questo gettone per il mastro delle chiavi. Ritorna da me dopo che avrai ucciso la bestia.","お主の持つ欠片が共鳴しているのを感受出来る。 二つ目の欠片は紅と黒曜の塔だ。 そこでお主を待ち構えているビショップと戦え。 その者が持つシンボルを辿れば見つかるだろう。 このトークンをキーマスターに渡せ。 -魔物を討伐した後、此処へ戻るのだ。",그대에게서 시질의 조각 중 하나가 느껴지는군. 두 번째 조각은 진홍빛 흑요석 탑의 심장부에 있다. 거기서 기다리고 있는 비숍과 싸워야 한다. 그 자의 권력을 상징하는 문양을 따라가면 만날 수 있을 것이다. 열쇠지기에게 이 통행증을 전해주어라. 그리고 괴물을 처치하면 다시 나에게로 오라.,"Ik voel een fragment in je resoneren. Het tweede fragment ligt in het hart van de karmozijnrode en obsidiaan toren. Daar moet je de bisschop bestrijden, die zich bewust is van de situatie en op je wacht. Je zult hem vinden door zijn machtssymbool te volgen. Neem dit teken mee naar de sleutelbeheerder. Keer naar mij terug nadat je het beest hebt gedood.",,"Posso sentir um fragmento ressoar de dentro de você. O segundo está na torre carmesim e obsidiana. Lá você deverá combater o Bispo, que está acordado e te aguarda. Você o encontrará seguindo o seu símbolo de poder. Leve esta ensígnia ao mestre das chaves. Volte depois de eliminar a besta.",,,"Я чувствую один фрагмент, настроенный на тебя. Второй лежит в сердце багрово-обсидиановой башни. Там тебе предстоит сразиться с Епископом — он знает о тебе и ждёт твоего появления. Его символ власти приведёт тебя прямо к нему. Отнеси этот жетон ключнику. Срази чудовище и возвращайся ко мне. -", -I'll be back.,TXT_RPLY0_SCRIPT12_D1516_ILLBE,,,,Vrátím se.,Ich werde zurückkommen.,,,Volveré.,,,Je reviendrai.,,,すぐ戻ってくる。,금방 돌아올게.,Ik kom terug.,,Eu voltarei.,,,Я вернусь., -"Although the Bishop is formidable, this quest is slight. Return to me when you possess the next fragment.",TXT_DLG_SCRIPT12_D3032_ALTHO,,,,"I přes Biskupovu hrozivost je tento úkol drobný. Vrať se, až budeš vlastnit další díl.","Auch wenn der Bischof ein schwerer Gegner ist, diese Aufgabe ist geringfügig. Komm zu mir zurück, wenn du das nächste Fragment besitzt.",,,"Aunque el Obispo es formidable, esta misión es leve. Vuelve a mí cuando poseas el siguiente fragmento.",,,"Bien que l'évêque soit un puissant adversaire, cette quête n'est qu'une courte aventure. Revenez à moi quand vous possédez le deuxième fragment.",,,"ビショップは手強く、この使命は困難であろう。 +魔物を討伐した後、此処へ戻るのだ。",그대에게서 시질의 조각 중 하나가 느껴지는군. 두 번째 조각은 진홍빛 흑요석 탑의 심장부에 있다. 거기서 기다리고 있는 비숍과 싸워야 한다. 그 자의 권력을 상징하는 문양을 따라가면 만날 수 있을 것이다. 열쇠지기에게 이 통행증을 전해주어라. 그리고 괴물을 처치하면 다시 나에게로 오라.,"Ik voel een fragment in je resoneren. Het tweede fragment ligt in het hart van de karmozijnrode en obsidiaan toren. Daar moet je de bisschop bestrijden, die zich bewust is van de situatie en op je wacht. Je zult hem vinden door zijn machtssymbool te volgen. Neem dit teken mee naar de sleutelbeheerder. Keer naar mij terug nadat je het beest hebt gedood.","Jeg føler et fragment resonere i deg. Det andre ligger i hjertet av det purpurfargede og obsidianske tårnet. Der må du bekjempe biskopen, som vet og venter på deg. Du finner ham ved å følge hans maktsymbol. Ta dette symbolet til nøkkelmesteren. Kom tilbake til meg etter at du har drept udyret.","Czuję, że jeden fragment rezonuje w tobie. Drugi leży w sercu karmazynowej i obsydianowej wieży. Tam musisz walczyć z Biskupem, który jest świadomy i czeka na ciebie. Znajdziesz go podążając za jego symbolem mocy. Zanieś ten żeton do klucznika. Wróć do mnie po zabiciu bestii.","Posso sentir um fragmento ressoar de dentro de você. O segundo está na torre carmesim e obsidiana. Lá você deverá combater o Bispo, que está acordado e te aguarda. Você o encontrará seguindo o seu símbolo de poder. Leve esta ensígnia ao mestre das chaves. Volte depois de eliminar a besta.",,"Simt un fragment care rezonează în tine. Al doilea e în inima turnului purpuriu, din obsidian. Acolo îl vei înfrunta pe Episcop, care e conștient, și în așteptare. Îl vei găsi urmându-i simbolul puterii. Du asta la stăpânul cheilor. Întoarce-te după ce ai înfrânt fiara.","Я чувствую один фрагмент, настроенный на тебя. Второй лежит в сердце багрово-обсидиановой башни. Там тебе предстоит сразиться с Епископом — он знает о тебе и ждёт твоего появления. Его символ власти приведёт тебя прямо к нему. Отнеси этот жетон ключнику. Срази чудовище и возвращайся ко мне. +",,"Jag känner ett fragment resonera inom dig. Det andra ligger i hjärtat av det karmosinröda och obsidianska tornet. Där måste du bekämpa biskopen, som är medveten och väntar på dig. Du hittar honom genom att följa hans maktsymbol. Ta den här symbolen till nyckelmästaren. Återvänd till mig när du har dödat odjuret.","Bir parçanın içinde yankılandığını hissediyorum. İkincisi kızıl ve obsidyen kulenin kalbinde yatıyor. Orada, farkında olan ve seni bekleyen Piskopos'la savaşmalısın. Onu güç sembolünü takip ederek bulacaksın. Bu simgeyi anahtar ustasına götür. Canavarı öldürdükten sonra bana dön." +I'll be back.,TXT_RPLY0_SCRIPT12_D1516_ILLBE,〃,,,Vrátím se.,Jeg kommer tilbage.,Ich werde zurückkommen.,,Mi revenos.,Volveré.,,Tulen takaisin.,Je reviendrai.,Visszatérek még.,Ritornerò.,すぐ戻ってくる。,금방 돌아올게.,Ik kom terug.,Jeg kommer tilbake.,Wrócę.,Eu voltarei.,,Mă voi întoarce.,Я вернусь.,,Jag kommer tillbaka.,Geri geleceğim. +"Although the Bishop is formidable, this quest is slight. Return to me when you possess the next fragment.",TXT_DLG_SCRIPT12_D3032_ALTHO,〃,,,"I přes Biskupovu hrozivost je tento úkol drobný. Vrať se, až budeš vlastnit další díl.","Selv om biskoppen er formidabel, er denne søgen let. Vend tilbage til mig, når du er i besiddelse af det næste fragment.","Auch wenn der Bischof ein schwerer Gegner ist, diese Aufgabe ist geringfügig. Komm zu mir zurück, wenn du das nächste Fragment besitzt.",,"Kvankam la Episkopo estas timindega, ĉi tiu tasko estas sensignifa. Revenu al mi kiam vi havos la sekvan fragmenton.","Aunque el Obispo es formidable, esta misión es leve. Vuelve a mí cuando poseas el siguiente fragmento.",,"Vaikka suuri onkin Piispa, pieni kuitenkin on tämä tehtävä. Palaa tyköni, kun seuraava osanen on hallussasi.","Bien que l'évêque soit un puissant adversaire, cette quête n'est qu'une courte aventure. Revenez à moi quand vous possédez le deuxième fragment.","Habár a Püspök méltó ellenfél lesz, a küldetésed könnyű. Térj vissza, ha megvan a következő darabka.","Anche se il Vescovo è formidabile, questa sfida è leggera. Ritorna da me non appena possiedi il prossimo frammento.","ビショップは手強く、この使命は困難であろう。 次の欠片を手にしたら此処へ戻るのだ。 -","비숍은 만만치 않은 상대지만, 이보다 더한 일들이 기다리고 있다. 두 번째 조각을 찾고 다시 돌아오라.","Hoewel de bisschop formidabel is, is deze zoektocht gering. Keer terug naar mij als je het volgende fragment bezit.",,"Embora o Bispo seja poderoso, esta missão é simples. Retorne para mim quando você possuir o próximo fragmento.",,,"Каким бы страшным Епископ ни был, это задание не доставит тебе хлопот. Достань следующий фрагмент и возвращайся ко мне.", -Your next challenge will test your spirit. The third piece is held by your own leader. He is the same as that which he sends you to kill.,TXT_DLG_SCRIPT12_D4548_YOURN,,,,"Tvá další výzva pokusí tvou vůli. Třetí díl je držen tvým vlastním vůdcem. Je stejný, jako ti, které tě posílá zabít.","Die nächste Herausforderung wird deinen Geist prüfen. Das dritte Teilstück wird von deinem eigenen Anführer, Macil, gehalten. Er ist das Gleiche, was er dich töten lässt.",,,Tu próximo desafío pondrá a prueba tu espíritu. El tercer fragmento está en manos de tu propio líder. Él es igual que aquello que te envía a matar.,,,Le prochain défi testera votre esprit. Le troisième fragment est possédé par votre leader. Il est le même que celui qu'il vous a envoyé tuer.,,,"次の挑戦はお主の精神が試されるだろう。 +","비숍은 만만치 않은 상대지만, 이보다 더한 일들이 기다리고 있다. 두 번째 조각을 찾고 다시 돌아오라.","Hoewel de bisschop formidabel is, is deze zoektocht gering. Keer terug naar mij als je het volgende fragment bezit.","Selv om biskopen er formidabel, er dette oppdraget lett. Kom tilbake til meg når du har det neste fragmentet.","Choć Biskup jest potężny, to zadanie jest niewielkie. Wróć do mnie, gdy posiądziesz kolejny fragment.","Embora o Bispo seja poderoso, esta missão é simples. Retorne para mim quando você possuir o próximo fragmento.",,"Deși Episocopul e formidabil, misiunea asta e ușoara. Întoarce-te când ai cel de-al doilea fragment.","Каким бы страшным Епископ ни был, это задание не доставит тебе хлопот. Достань следующий фрагмент и возвращайся ко мне.",,Även om biskopen är formidabel är detta uppdrag lätt. Återvänd till mig när du besitter nästa fragment.,"Piskopos zorlu olsa da, bu görev hafif. Bir sonraki parçayı ele geçirdiğinde bana geri dön." +Your next challenge will test your spirit. The third piece is held by your own leader. He is the same as that which he sends you to kill.,TXT_DLG_SCRIPT12_D4548_YOURN,MAP12: Oracle → After killing the Bishop,,,"Tvá další výzva pokusí tvou vůli. Třetí díl je držen tvým vlastním vůdcem. Je stejný, jako ti, které tě posílá zabít.","Din næste udfordring vil sætte din ånd på prøve. Det tredje stykke er i din egen leders besiddelse. Han er den samme som den, han sender dig ud for at dræbe.","Die nächste Herausforderung wird deinen Geist prüfen. Das dritte Teilstück wird von deinem eigenen Anführer, Macil, gehalten. Er ist das Gleiche, was er dich töten lässt.",,"Via sekva defio provos vian spiriton. Via propra estro posedas la trian pecon; li estas egala al tio, kion mortigi li sendas vin.",Tu próximo desafío pondrá a prueba tu espíritu. El tercer fragmento está en manos de tu propio líder; él es igual a aquello que te envía a matar.,Tu próximo desafío va a poner a prueba tu espíritu. El tercer fragmento está en manos de tu propio líder; él es igual a aquello que te manda a matar.,"Seuraava haasteesi koettelee sinua henkisesti. Kolmatta osasta pitää hallussaan oma päämiehesi. Hän on sama kuin se, jonka hän lähettää sinut surmaamaan.",Le prochain défi testera votre esprit. Le troisième fragment est possédé par votre leader. Il est le même que celui qu'il vous a envoyé tuer.,"A következő kihívás próbára fogja tenni a lelked. A harmadik darab a saját vezetődnél van. Ő maga ugyanaz, mint akiért elküldött.",La tua prossima sfida metterà alla prova il tuo spirito. Il terzo frammento è posseduto dal tuo stesso capo. Lui è uguale a quelli che ti manda ad uccidere.,"次の挑戦はお主の精神が試されるだろう。 三つ目の欠片はお主の指導者が所持している。 彼奴はお主の死を望むが為 -戦場へ送り込んでいるのだ。",다음 도전은 그대의 정신을 시험할 것이다. 세 번째 조각은 바로 그대의 지도자가 가지고 있다. 그는 그대를 시켜서 죽였던 괴물들과 마찬가지인 존재다.,Je volgende uitdaging zal je geest testen. Het derde stuk is in handen van je eigen leider. Hij is hetzelfde als wat hij je stuurt om te doden.,,Seu próximo desafio testará o seu espírito. A terceira peça está com o seu próprio líder. Ele é a mesma pessoa que ele quer que você mate.,,,"Следующее задание испытает силу твоего духа. Третий фрагмент у вашего лидера. Он сам — один из тех, кого вы убиваете по его приказу.", -Macil? A traitor?,TXT_RPLY0_SCRIPT12_D4548_MACIL,,,,Macil? Zrádce?,Macil? Ein Verräter?,,,¿Macil? ¿Un traidor?,,,Macil? Un traître?,,,マシル?彼が裏切者?,마실? 배신자?,Macil? Een verrader?,,Macil? Um traidor?,,,Мэйсил? Предатель?, -Your blind faith has allowed him to advance to his goals with each piece you gain. Confront him and resolve your fate.,TXT_DLG_SCRIPT12_D6064_YOURB,,,,"Tvá slepá víra mu dovolila přiblížit se k jeho cíli s každým dalším dílem, jenž získáš. Postav se mu a rozhodni svůj osud.","Deine blinde Treue hat es ihm erlaubt, seine eigenen Ziele voranzutreiben - mit jedem Fragment, das du findest. Konfrontiere ihn und kläre dein Schicksal.",,,Tu fé ciega le ha permitido avanzar en sus objetivos con cada pieza que ganas. Confróntalo y resuelve tu destino.,,,"Votre dévotion aveugle lui a permis d'avancer vers ses fins. Avec chaque fragment que vous récupérez, il s'en rapproche encore. Confrontez le et faites-face à votre destinée.",,,"彼を妄信するお主の活躍によって、 +戦場へ送り込んでいるのだ。",다음 도전은 그대의 정신을 시험할 것이다. 세 번째 조각은 바로 그대의 지도자가 가지고 있다. 그는 그대를 시켜서 죽였던 괴물들과 마찬가지인 존재다.,Je volgende uitdaging zal je geest testen. Het derde stuk is in handen van je eigen leider. Hij is hetzelfde als wat hij je stuurt om te doden.,Din neste utfordring vil sette din ånd på prøve. Den tredje brikken holdes av din egen leder. Han er den samme som han sender deg for å drepe.,"Twoje kolejne wyzwanie będzie testem dla twojego ducha. Trzeci kawałek jest w posiadaniu waszego przywódcy. Jest taki sam jak ten, którego wysyła, byś zabił.",Seu próximo desafio testará o seu espírito. A terceira peça está com o seu próprio líder. Ele é a mesma pessoa que ele quer que você mate.,,Următoarea provocare îți va testa spiritul. A treia piesă e deținută de liderul tău. A celași care te trimite să omori.,"Следующее задание испытает силу твоего духа. Третий фрагмент у вашего лидера. Он сам — один из тех, кого вы убиваете по его приказу.",,Din nästa utmaning kommer att sätta din själ på prov. Den tredje biten innehas av din egen ledare. Han är densamma som den som han skickar dig att döda.,Bir sonraki mücadeleniz ruhunuzu sınayacak. Üçüncü parça kendi lideriniz tarafından tutuluyor. Seni öldürmen için gönderdiğiyle aynı kişi. +Macil? A traitor?,TXT_RPLY0_SCRIPT12_D4548_MACIL,〃,,,Macil? Zrádce?,Macil? En forræder?,Macil? Ein Verräter?,,Ĉu Macil? Ĉu perfidulo?,"¿Macil?, ¿un traidor?",,Macil? Petturiko?,Macil? Un traître?,Macil? Egy áruló volna?,Macil? Un traditore?,マシル?彼が裏切者?,마실이 배신자라고?,Macil? Een verrader?,Macil? En forræder?,Macil? Zdrajca?,Macil? Um traidor?,,Macil? Un trădător?,Мэйсил? Предатель?,,Macil? En förrädare?,Macil mi? Bir hain mi? +Your blind faith has allowed him to advance to his goals with each piece you gain. Confront him and resolve your fate.,TXT_DLG_SCRIPT12_D6064_YOURB,〃,,,"Tvá slepá víra mu dovolila přiblížit se k jeho cíli s každým dalším dílem, jenž získáš. Postav se mu a rozhodni svůj osud.","Din blinde tro har gjort det muligt for ham at komme videre til sine mål med hver brik, du får. Konfronter ham, og afklar din skæbne.","Deine blinde Treue hat es ihm erlaubt, seine eigenen Ziele voranzutreiben - mit jedem Fragment, das du findest. Konfrontiere ihn und kläre dein Schicksal.",,"Via blinda fido ebligis al li progresi en siaj celoj per ĉiu peco, kiun vi gajnas. Alfrontu lin por solvi vian destinon.",Tu fe ciega le ha permitido avanzar en sus objetivos con cada pieza que ganas. Confróntalo y resuelve tu destino.,,Sokea uskosi on sallinut hänen edistää omia tavoitteitaan jokaisen saavuttamasi osasen myötä. Kohtaa hänet ja päätä kohtalosi.,"Votre dévotion aveugle lui a permis d'avancer vers ses fins. Avec chaque fragment que vous récupérez, il s'en rapproche encore. Confrontez le et faites-face à votre destinée.","A vakon belé vetett hited segített számára, hogy minden darabkával közelebb jusson a céljához. Szembesítsd vele, és tisztázd le magadban a hited.",La tua fede cieca gli ha permesso di raggiungere i suoi obiettivi con ogni pezzo che ottieni. Affrontalo e risolvi il tuo destino.,"彼を妄信するお主の活躍によって、 彼奴の目的が果たされる間近だ。 -彼奴に立ち向かい、運命を切り開くのだ。",그대의 맹목적인 믿음이 조각들을 하나하나 찾으면서 그자의 목표를 이뤄주고 있다. 그를 상대하고 구속된 운명에서 벗어나라.,Jouw blinde geloof heeft hem in staat gesteld om met elk stuk dat je wint zijn doelen te bereiken. Confronteer hem en los je lot op.,,Sua fé cega permitiu que ele avance em suas metas com cada peça que você adquire. Vá confrontá-lo e resolva o seu destino.,,,"Твоя слепая вера приближала его к цели каждый раз, как ты находил фрагмент. Сразись с ним и исполни своё предназначение.", -"All right, it is Macil.",TXT_RPLY0_SCRIPT12_D6064_ALLRI,,,,"Tak dobře, je to Macil.","Na gut, es ist Macil.",,,"Muy bien, es Macil.",,,Très bien. C'est le tour de Macil.,,,わかった、それがマシルか。,역시... 마실이였군.,"Oké, het is Macil.",,Certo. Então é o Macil.,,,Понятно. Я убью Мэйсила., -It's you I don't trust.,TXT_RPLY1_SCRIPT12_D6064_ITSYO,,,,Ale já nevěřím tobě.,"Du bist es, dem ich nicht vertraue.",,,Eres tú de quien no me fío.,,,C'est vous à qui je ne fais pas confiance.,,,信用できん。,내가 믿지 않는 건 그대이다.,Ik vertrouw jou niet.,,É você em quem eu não confio.,,,"Я думаю, что это ты лжешь!", -Whatever choice you make your kind shall perish under the will of the One God.,TXT_DLG_SCRIPT12_D7580_WHATE,,,,"Nehledě na tvé rozhodnutí, tvůj druh skoná vůlí Jednoho boha.","Welche Wahl du auch triffst, deine Spezies wird unter dem Willen des Einen Gottes zugrunde gehen.",,,Cualquiera que sea tu elección tu especie perecerá bajo la voluntad del Dios Único.,,,"Quel que soit le choix que vous faites, votre espèce périra par la volonté du Seul Dieu.",,,"如何なる選択でも、人類は大いなる神の元で -浄化されるだろう。","그대가 어떤 선택을 하더라도, 그대를 비롯한 종족은 유일신의 의지에 의해 멸망할 뿐이다.","Welke keuze je ook maakt, jouw soort zal vergaan onder de wil van de Ene God.",,"Seja qual for a escolha que você fizer, sua espécie irá perecer sob a vontade do Deus Único.",,,"Что бы ты ни выбрал, твой род исчезнет по воле Единого Бога.", -I'll be back when Macil's dead.,TXT_RPLY0_SCRIPT12_D7580_ILLBE,,,,"Vrátím se, až bude Macil mrtev.","Ich komme wieder, wenn Macil tot ist.",,,Volveré cuando Macil esté muerto.,,,Je reviendrai quand Macil sera mort.,,,マシルの死と共に戻る。,마실을 죽이고 돌아오겠다.,Ik kom terug als Macil dood is.,,Voltarei quando Macil estiver morto.,,,Я вернусь после смерти Мэйсила., -I can't let that happen.,TXT_RPLY1_SCRIPT12_D7580_ICANT,,,,To nemůžu dopustit.,Das darf nicht passieren.,,,No pienso permitirlo.,,,Je ne peux pas vous laisser faire ça.,,,そうはさせん。,그렇게 할 순 없어.,Dat kan ik niet laten gebeuren.,,Não posso deixar isso acontecer.,,,Я не могу этого допустить., -"The river of time moves forever onward, while you stand still.",TXT_DLG_SCRIPT12_D9096_THERI,,,,Řeka času plyne stále vpřed zatímco ty zůstáváš stát.,"Der Fluss der Zeit bewegt sich immer vorwärts, während du stillstehst.",,,"La corriente del tiempo sigue adelante, mientras tú sigues quieto.",,,"La rivière du temps continue à couler, tandis que vous restez immobile.",,,事を措いても、時の河は永遠の先に進む。,"그대가 가만히 있어도, 시간의 강은 계속 흐를 뿐이다.","De rivier van de tijd beweegt voor altijd verder, terwijl je stilstaat.",,"O corrente do tempo se movimenta sempre adiante, enquanto você fica imóvel.",,,"Река времени непрестанно течёт вперёд, в то время как ты стоишь без движения.", -"You have cut the cancer from your body, but your heart still beats. Next you must find the surgeon who butchers and controls your people, the Loremaster. Stop him, and the next piece will be yours.",TXT_DLG_SCRIPT12_D10612_YOUHA,,,,"Vyřízl jsi rakovinu ze svého těla, tvé srdce však stále bije. Dále musíš najít doktora, jenž vraždí a ovládá tvé druhy, Dějepisce. Učiň mu přítrž a další díl bude tvůj.","Du hast das Geschwür aus deinem Körper entferrnt, aber dein Herz schlägt noch. Als Nächstes musst du den Wissensmeister finden, der deine Leute kontrolliert und abschlachtet. Stoppe ihn und das nächste Teilstück ist Dein.",,,"Has cortado el cáncer de tu cuerpo, pero tu corazón aún late. Lo siguiente es encontrar al cirujano que destroza y controla a tu gente, el Maestro del Conocimiento. Deténlo, y la próxima pieza será tuya.",,,"Vous avez arraché le cancer de votre corps, mais le cœur bat encore. Vous devez maintenant trouver le chirurgien qui massacre votre peuple, le Maître des traditions. Arrètez-le, et le fragment suivant sera le vôtre.",,,"心に動揺が見られるな、だがお主は己の体から +彼奴に立ち向かい、運命を切り開くのだ。",그대의 맹목적인 믿음이 조각들을 하나하나 찾으면서 그자의 목표를 이뤄주고 있다. 그를 상대하고 구속된 운명에서 벗어나라.,Jouw blinde geloof heeft hem in staat gesteld om met elk stuk dat je wint zijn doelen te bereiken. Confronteer hem en los je lot op.,Din blinde tro har gjort det mulig for ham å nå sine mål for hver brikke du vinner. Konfronter ham og avgjør din skjebne.,Twoja ślepa wiara pozwoliła mu na osiągnięcie celu z każdym zdobytym kawałkiem. Skonfrontuj się z nim i rozstrzygnij swój los.,Sua fé cega permitiu que ele avance em suas metas com cada peça que você adquire. Vá confrontá-lo e resolva o seu destino.,,"Credința ta oarbă i-a permis să-și avanseze planurile, cu fiecare piesă pe care o obții. Înfruntă-l și împlinește-ți destinul.","Твоя слепая вера приближала его к цели каждый раз, как ты находил фрагмент. Сразись с ним и исполни своё предназначение.",,Din blinda tro har gjort det möjligt för honom att avancera mot sina mål med varje bit du vinner. Konfrontera honom och lös ditt öde.,"Kör inancınız, kazandığınız her parçayla hedeflerine ilerlemesine izin verdi. Onunla yüzleş ve kaderini çöz." +"All right, it is Macil.",TXT_RPLY0_SCRIPT12_D6064_ALLRI,〃,,,"Tak dobře, je to Macil.","Okay, det er Macil.","Na gut, es ist Macil.",,Komprenite: nun Macil.,"Muy bien, sigue Macil.",,"Niin se on, se on Macil.",Très bien. C'est le tour de Macil.,"Igazad volt, Macil az.","Va bene, è Macil.",わかった、それがマシルか。,역시... 마실이였군.,"Oké, het is Macil.","Greit, det er Macil.","W porządku, to Macil.",Certo. Então é o Macil.,,"Bine, Macil să fie.",Понятно. Я убью Мэйсила.,,"Okej, det är Macil.","Pekala, bu Macil." +It's you I don't trust.,TXT_RPLY1_SCRIPT12_D6064_ITSYO,〃,,,Ale já nevěřím tobě.,"Det er dig, jeg ikke stoler på.","Du bist es, dem ich nicht vertraue.",,"Vi estas tiu, kiun mi ne fidas.",Eres tú de quien no me fío.,Eres tú en quien no confío.,Sinuun en minä luota.,C'est vous à qui je ne fais pas confiance.,"Te vagy az, akiben nem bízok.",Sei tu quello di cui non mi fido.,信用できん。,내가 믿지 않는 건 네놈이다.,Ik vertrouw jou niet.,Det er deg jeg ikke stoler på.,To tobie nie ufam.,É você em quem eu não confio.,,Tu ești cel în care nu am încredere.,"Я думаю, что это ты лжешь!",,Det är dig jag inte litar på.,Güvenmediğim sensin. +Whatever choice you make your kind shall perish under the will of the One God.,TXT_DLG_SCRIPT12_D7580_WHATE,〃,,,"Nehledě na tvé rozhodnutí, tvůj druh skoná vůlí Jednoho boha.","Uanset hvilket valg du træffer, vil din slags gå under under den ene Guds vilje.","Welche Wahl du auch triffst, deine Spezies wird unter dem Willen des Einen Gottes zugrunde gehen.",,"Tio ajn, kion vi elektos, via specio malaperos laŭ la volo de la Vera Dio.",Cualquiera que sea tu elección tu especie perecerá bajo la voluntad del Dios Único.,Cualquiera que sea tu elección tu especie va a perecer bajo la voluntad del Dios Único.,"Teitpä minkä hyvänsä päätöksen, lajisi pitää hukkuman Yhden Ainoan Jumalan tahdon alle.","Quel que soit le choix que vous faites, votre espèce périra par la volonté du Seul Dieu.","Mindegy mire döntesz, az egy igaz isten szigora lesúlyt rád és fajtádra.","Qualunque scelta tu faccia, la tua specie perirà per il volere dell'Unico Dio.","如何なる選択でも、人類は大いなる神の元で +浄化されるだろう。","그대가 어떤 선택을 하더라도, 그대를 비롯한 종족은 유일신의 의지에 의해 멸망할 뿐이다.","Welke keuze je ook maakt, jouw soort zal vergaan onder de wil van de Ene God.","Uansett hvilket valg du tar, vil din art gå til grunne under den ene Guds vilje.","Jakiegokolwiek wyboru dokonasz, twój rodzaj zginie z woli Jedynego Boga.","Seja qual for a escolha que você fizer, sua espécie irá perecer sob a vontade do Deus Único.",,"Indiferent de alegerea ta, neamul tău va pieri sub voința Adevăratului Zeu.","Что бы ты ни выбрал, твой род исчезнет по воле Единого Бога.",,Vilket val du än gör kommer din sort att förgås under den ende Gudens vilja.,"Yaptığın seçim ne olursa olsun, türün Tek Tanrı'nın iradesi altında yok olacak." +I'll be back when Macil's dead.,TXT_RPLY0_SCRIPT12_D7580_ILLBE,MAP12: Choose to kill Macil.,,,"Vrátím se, až bude Macil mrtev.","Jeg kommer tilbage, når Macil er død.","Ich komme wieder, wenn Macil tot ist.",,Mi revenos kiam Macil estos mortinta.,Volveré cuando Macil esté muerto.,Voy a volver cuando Macil esté muerto.,"Tulen takaisin, kun Macil on kuollut.",Je reviendrai quand Macil sera mort.,"Visszajövök, ha Macil már halott.",Tornerò quando Macil sarà morto.,マシルの死と共に戻る。,마실을 죽이고 돌아오겠다.,Ik kom terug als Macil dood is.,Jeg kommer tilbake når Macil er død.,"Wrócę, gdy Macil będzie martwy.",Voltarei quando Macil estiver morto.,,Am să mă întorc odată ce Macil e mort.,Я вернусь после смерти Мэйсила.,,Jag kommer tillbaka när Macil är död.,Macil öldüğünde geri döneceğim. +I can't let that happen.,TXT_RPLY1_SCRIPT12_D7580_ICANT,MAP12: Choose to not kill Macil.,,,To nemůžu dopustit.,Jeg kan ikke lade det ske.,Das darf nicht passieren.,,Mi ne povas permesi tion.,No puedo permitirlo.,,En voi antaa sen tapahtua.,Je ne peux pas vous laisser faire ça.,Nem hagyhatom ezt.,Non posso permetterlo.,そうはさせん。,그렇게 할 순 없어.,Dat kan ik niet laten gebeuren.,Jeg kan ikke la det skje.,Nie mogę na to pozwolić.,Não posso deixar isso acontecer.,,Nu voi permite asta.,Я не могу этого допустить.,,Jag kan inte låta det hända.,Bunun olmasına izin veremem. +"The river of time moves forever onward, while you stand still.",TXT_DLG_SCRIPT12_D9096_THERI,MAP12: You chose to kill Macil.,,,Řeka času plyne stále vpřed zatímco ty zůstáváš stát.,"Tidens flod bevæger sig for evigt fremad, mens du står stille.","Der Fluss der Zeit bewegt sich immer vorwärts, während du stillstehst.",,La tempofluo eterne iras antaŭen dum vi restas senmova.,La corriente del tiempo sigue adelante mientras tú sigues quieto.,,"Ajan virta liikkuu alati eteenpäin, samalla kun itse pysyt aloillasi.","La rivière du temps continue à couler, tandis que vous restez immobile.","Az idő folyója folyamat halad tovább, miközben te csak álldogállsz.","Il fiume del tempo scorre inesorabilmente, mentre tu rimani fermo.",事を措いても、時の河は永遠の先に進む。,"그대가 가만히 있어도, 시간의 강은 계속 흐를 뿐이다.","De rivier van de tijd beweegt voor altijd verder, terwijl je stilstaat.","Tidens elv beveger seg evig videre, mens du står stille.","Rzeka czasu płynie wiecznie do przodu, podczas gdy ty stoisz w miejscu.","O corrente do tempo se movimenta sempre adiante, enquanto você fica imóvel.",,"Râul timpului curge în permanență, în timp ce tu stai pe loc.","Река времени непрестанно течёт вперёд, в то время как ты стоишь без движения.",,"Tidens flod rör sig för evigt framåt, medan du står stilla.","Sen dururken, zaman nehri sonsuza dek ilerliyor." +"You have cut the cancer from your body, but your heart still beats. Next you must find the surgeon who butchers and controls your people, the Loremaster. Stop him, and the next piece will be yours.",TXT_DLG_SCRIPT12_D10612_YOUHA,MAP12: Oracle → After killing Macil,,,"Vyřízl jsi rakovinu ze svého těla, tvé srdce však stále bije. Dále musíš najít doktora, jenž vraždí a ovládá tvé druhy, Dějepisce. Učiň mu přítrž a další díl bude tvůj.","Du har skåret kræften ud af din krop, men dit hjerte slår stadig. Nu skal du finde den kirurg, der slagter og kontrollerer dit folk, Loremesteren. Stop ham, og det næste stykke vil være dit.","Du hast das Geschwür aus deinem Körper entferrnt, aber dein Herz schlägt noch. Als Nächstes musst du den Wissensmeister finden, der deine Leute kontrolliert und abschlachtet. Stoppe ihn und das nächste Teilstück ist Dein.",,"Vi saniĝis de via kancero, sed via koro ankoraŭ batas. Vi nun devas trovi la kirurgon, kiu buĉas kaj regas viajn homojn: la Folkloristo; haltigu lin kaj la sekva peco estos via.","Te has curado del cáncer, pero tu corazón aún late. Ahora toca encontrar al cirujano que destroza y controla a tu gente: al Maestro del Conocimiento; detenlo y la próxima pieza será tuya.",,"Olet erottanut syövän ruumiistasi, mutta sydämesi silti sykkii. Seuraavaksi pitää sinun löytämän kirugin, joka teurastaa ja hallitsee kansaasi: Oppi-Isän. Pysäytä hänet, ja seuraava osanen on oleva sinun.","Vous avez arraché le cancer de votre corps, mais le cœur bat encore. Vous devez maintenant trouver le chirurgien qui massacre votre peuple, le Maître des traditions. Arrètez-le, et le fragment suivant sera le vôtre.","Kioperáltad a rákos sejteket a testedből, de a szíved még mindig ver. Most meg kell találnod azt a sebészt, aki lemészárolja és kontrollálja a néped. Ő nem más, mint a Tanmester. Állítsd meg, és a következő darabka a tied.","Hai eliminato il cancro dal tuo corpo, ma il tuo cuore batte ancora. Adesso devi trovare il chirurgo che macella e controlla la tua gente, il Sapiente. Fermalo e il prossimo pezzo sarà tuo.","心に動揺が見られるな、だがお主は己の体から 癌を取り除いた。次の欠片は 人々を虐殺で支配するロアマスター外科医が -所持している。彼奴を止め、欠片を得るのだ。","그대 몸 안의 암 덩어리를 잘라냈건만, 심장은 여전히 뛰고 있구나. 다음은 네 종족의 도살과 지배를 책임졌던 로어마스터다. 그를 막아내면, 다음 조각은 너의 것이다.","Je hebt de kanker uit je lichaam gesneden, maar je hart klopt nog steeds. Vervolgens moet je de chirurg vinden die je volk afslacht en controleert, de Loremaster. Stop hem, en het volgende stuk zal van jou zijn.",,"Você arrancou o câncer do seu corpo, mas seu coração ainda bate. Agora você deve encontrar o cirurgião que mutila e controla o seu povo, o Mestre do Conhecimento. Detenha-o e a próxima peça será sua.",,,"Ты вырезал опухоль из своего тела, но твоё сердце всё ещё бьётся. Теперь тебе предстоит найти вивисектора, который вскрывает твоих людей и управляет ими — Хранителя мудрости. Останови его, и следующий фрагмент твой.", -Where do I find him?,TXT_RPLY0_SCRIPT12_D10612_WHERE,,,,Kde ho najdu?,Wo finde ich ihn?,,,¿Dónde lo encuentro?,,,Où puis-je le trouver?,,,そいつはどうやって見つける?,어디를 가야 그를 발견할 수 있지?,Waar vind ik hem?,,Onde encontro ele?,,,Где мне искать его?, -"Use the teleporter behind the door I just opened to reach the Loremaster. When he is dead, use the same device to return to me.",TXT_DLG_SCRIPT12_D12128_USETH,,,,"Dostaň se k Dějepisci pomocí teleportéru za dveřmi, které jsem právě otevřel. Když je mrtev, použij stejné zařízení k návratu ke mě.","Benutze den Teleporter hinter der Tür, die ich gerade geöffnet habe. Wenn er tot ist, benutze dasselbe Gerät, um zu mir zurückzukehren.",,,"Usa el teleportador tras la puerta que he abierto para llegar hasta el Maestro del Conocimiento. Cuando esté muerto, usa el mismo dispositivo para volver a mí.",,,"Utilisez le téléporteur derrière la porte que je viens d'ouvrir pour trouver le Maître des traditions. Quand il sera mort, utilisez ce même téléporteur pour revenir ici.",,,"我の傍にあるテレポーターの扉を開いた。 +所持している。彼奴を止め、欠片を得るのだ。","그대 몸 안의 암 덩어리를 잘라냈건만, 심장은 여전히 뛰고 있구나. 다음은 네 종족의 도살과 지배를 책임졌던 로어마스터다. 그를 막아내면, 다음 조각은 너의 것이다.","Je hebt de kanker uit je lichaam gesneden, maar je hart klopt nog steeds. Vervolgens moet je de chirurg vinden die je volk afslacht en controleert, de Loremaster. Stop hem, en het volgende stuk zal van jou zijn.","Du har fjernet kreften fra kroppen din, men hjertet ditt slår fortsatt. Nå må du finne kirurgen som slakter og kontrollerer folket ditt, Loremesteren. Stopp ham, og det neste stykket blir ditt.","Wyciąłeś raka ze swojego ciała, ale twoje serce wciąż bije. Następnie musisz znaleźć chirurga, który rzeźbi i kontroluje twój lud, Loremastera. Powstrzymaj go, a następny kawałek będzie twój.","Você arrancou o câncer do seu corpo, mas seu coração ainda bate. Agora você deve encontrar o cirurgião que mutila e controla o seu povo, o Mestre do Conhecimento. Detenha-o e a próxima peça será sua.",,"Ai scăpat de cancerul din corp, dar inima ta încă bate. Mai departe, trebuie să îl găsești pe chirurgul care îți controlează și măcelărește oamenii, Stăpânul Învățăturilor. Oprește-l, și următoarea piesă va fi a ta.","Ты вырезал опухоль из своего тела, но твоё сердце всё ещё бьётся. Теперь тебе предстоит найти хирурга, который вскрывает твоих людей и управляет ими: Хранителя мудрости. Останови его, и следующий фрагмент твой.",,"Du har skurit bort cancern från din kropp, men ditt hjärta slår fortfarande. Nu måste du hitta kirurgen som slaktar och kontrollerar ditt folk, Läromästaren. Stoppa honom och nästa bit kommer att bli din.","Kanseri vücudunuzdan attınız ama kalbiniz hala atıyor. Şimdi halkını katleden ve kontrol eden cerrahı, Loremaster'ı bulmalısın. Onu durdurursan, bir sonraki parça senin olacak." +Where do I find him?,TXT_RPLY0_SCRIPT12_D10612_WHERE,〃,,,Kde ho najdu?,Hvor kan jeg finde ham?,Wo finde ich ihn?,,Kie mi trovos lin?,¿Dónde lo encuentro?,,Mistä löydän hänet?,Où puis-je le trouver?,Hol találom meg?,Dove lo trovo?,そいつはどうやって見つける?,어디를 가야 그를 발견할 수 있지?,Waar vind ik hem?,Hvor finner jeg ham?,Gdzie go znajdę?,Onde encontro ele?,,Unde îl găsesc?,Где мне искать его?,,Var hittar jag honom?,Onu nerede bulabilirim? +"Use the teleporter behind the door I just opened to reach the Loremaster. When he is dead, use the same device to return to me.",TXT_DLG_SCRIPT12_D12128_USETH,〃,,,"Dostaň se k Dějepisci pomocí teleportéru za dveřmi, které jsem právě otevřel. Když je mrtev, použij stejné zařízení k návratu ke mě.","Brug teleporteren bag den dør, jeg lige har åbnet, for at nå Loremesteren. Når han er død, skal du bruge den samme anordning til at vende tilbage til mig.","Benutze den Teleporter hinter der Tür, die ich gerade geöffnet habe. Wenn er tot ist, benutze dasselbe Gerät, um zu mir zurückzukehren.",,"Uzu la teleportilon tra la ĵus malfermita pordo maldekstre de vi por atingi la Folkloriston. Mortiginte lin, reuzu tiun aparaton por reveni ĉi tien.","Usa el teletransportador de la puerta que acabo de abrir a tu izquierda para llegar hasta el Maestro del Conocimiento. Una vez muerto, usa el mismo dispositivo para volver a mí.",,"Käytä juuri avaamani oven takana olevaa kaukosiirrintä tavoittaaksesi Oppi-Isän. Kun hän on kuollut, käytä samaa laitetta palataksesi tyköni.","Utilisez le téléporteur derrière la porte que je viens d'ouvrir pour trouver le Maître des traditions. Quand il sera mort, utilisez ce même téléporteur pour revenir ici.","Használd a kinyílt ajtó mögötti portált a Tanmesterhez. Ha meghalt, használd a visszaútra is.","Usa il teletrasporto dietro la porta che ho appena sbloccato per raggiungere il Sapiente. Quando è morto, usa lo stesso teletrasporto per tornare da me.","我の傍にあるテレポーターの扉を開いた。 それがロアマスターの元に通ずる。 彼奴に死を伝えた後、再び扉を通るがよい。","내가 로어마스터로 향하는 순간이동 장치를 열어두었다. 그 자가 죽으면, 똑같은 장치를 써서 다시 나에게 오라. - \cy못생기긴 했어도, 이 양반 우리 편인 것 같네.","Gebruik de teleporter achter de deur die ik net heb geopend om de Loremaster te bereiken. Als hij dood is, gebruik je hetzelfde apparaat om terug te keren naar mij.",,"Use o teletransportador atrás da porta que eu acabei de abrir para chegar até o Mestre do Conhecimento. Quando ele morrer, use o mesmo dispositivo e retorne a mim.",,,"Используй телепорт за той дверью, что я только что открыл, чтобы добраться до Хранителя. Когда он умрёт, найди другой телепорт, чтобы вернуться ко мне.", -"I'll be back, with his piece!",TXT_RPLY0_SCRIPT12_D12128_ILLBE,,,,Vrátím se s jeho dílem!,"Ich komme wieder, mit dem Teilstück.",,,"Volveré, ¡con su pieza!",,,"Je reviendrai, avec son fragment!",,,欠片を持ってすぐ戻る!,녀석의 조각을 가지고 다시 올게!,"Ik kom terug, met zijn stuk!",,"Eu voltarei, com a peça dele!",,,Я достану его фрагмент!, -"The river of time moves forever onward, while you stand still.",TXT_DLG_SCRIPT12_D13644_THERI,,,,Řeka času plyne stále vpřed zatímco ty zůstáváš stát.,"Der Fluss der Zeit bewegt sich immer vorwärts, während du stillstehst.",,,"La corriente del tiempo sigue adelante, mientras tú sigues quieto.",,,"La rivière du temps continue à couler, tandis que vous restez immobile.",,,事を措いても、時の河は永遠の先に進む。,"발버둥을 친다해도, 시간의 강은 계속 흐를 뿐.","De rivier van de tijd beweegt voor altijd verder, terwijl je stilstaat.",,"O corrente do tempo se movimenta sempre adiante, enquanto você fica imóvel.",,,"Река времени непрестанно течёт вперёд, в то время как ты стоишь без движения.", -"Pitiful man, you have done what thousands have failed to do... You bring me the power of the Sigil, the voice of the One God.",TXT_DLG_SCRIPT12_D15160_PITIF,,,,"Ubohý člověče, dokázal jsi to, co tisíce před tebou ne... Přinášíš mi moc Pečetě, hlas Jednoho boha.","Armseliger Wurm, du hast getan woran Tausende gescheitert sind... Du brachtest mir die Macht des Sigils, die Stimme des Einen Gottes.",,,"Despreciable humano, has hecho lo que miles no han podido... Traes ante mí el poder del Emblema, la voz del Dios Único.",,,"Pathétique mortel, vous avez réussi là où des milliers ont failli.. Vous m'amenez le pouvoir du Sigil, la voix du Seul Dieu.",,,"気の毒な者よ、お主は幾千の者達が + \cy못생기긴 했어도, 이 양반 우리 편인 것 같네.","Gebruik de teleporter achter de deur die ik net heb geopend om de Loremaster te bereiken. Als hij dood is, gebruik je hetzelfde apparaat om terug te keren naar mij.","Bruk teleporteren bak døren jeg nettopp åpnet for å nå Loremaster. Når han er død, bruk samme apparat for å komme tilbake til meg.","Użyj teleportera za drzwiami, które właśnie otworzyłem, aby dotrzeć do Loremastera. Gdy będzie martwy, użyj tego samego urządzenia, by wrócić do mnie.","Use o teletransportador atrás da porta que eu acabei de abrir para chegar até o Mestre do Conhecimento. Quando ele morrer, use o mesmo dispositivo e retorne a mim.",,"Folosește teleportoul din spatele ușii pe care tocmai am deschis-o. După ce e mort, folosește același dispozitiv pentru a te întoarce la mine.","Используй телепорт за той дверью, что я только что открыл, чтобы добраться до Хранителя. Когда он умрёт, найди другой телепорт, чтобы вернуться ко мне.",,Använd teleportern bakom dörren som jag just öppnade för att nå Läromästaren. När han är död använder du samma anordning för att återvända till mig.,"Loremaster'a ulaşmak için az önce açtığım kapının arkasındaki ışınlayıcıyı kullan. O öldüğünde, bana dönmek için aynı cihazı kullan." +"I'll be back, with his piece!",TXT_RPLY0_SCRIPT12_D12128_ILLBE,〃,,,Vrátím se s jeho dílem!,Jeg kommer tilbage med hans brik!,"Ich komme wieder, mit dem Teilstück.",,Mi revenos... kun lia peco!,Volveré... ¡con su pieza!,,Tulen takaisin hänen osasensa kanssa!,"Je reviendrai, avec son fragment!","Visszatérek, mégpedig a darabkájával!","Ritornerò, con il suo pezzo!",欠片を持ってすぐ戻る!,녀석의 조각을 가지고 다시 올게!,"Ik kom terug, met zijn stuk!","Jeg kommer tilbake, med hans del!",Wrócę z jego kawałkiem!,"Eu voltarei, com a peça dele!",,"Mă voi întoarce, cu piesa lui.",Я достану его фрагмент!,,Jag kommer tillbaka med hans pjäs!,Onun parçasıyla geri döneceğim! +"The river of time moves forever onward, while you stand still.",TXT_DLG_SCRIPT12_D13644_THERI,〃,,,Řeka času plyne stále vpřed zatímco ty zůstáváš stát.,"Tidens flod bevæger sig for evigt fremad, mens du står stille.","Der Fluss der Zeit bewegt sich immer vorwärts, während du stillstehst.",,La tempofluo eterne iras antaŭen dum vi restas senmova.,La corriente del tiempo sigue adelante mientras tú sigues quieto.,,"Ajan virta liikkuu alati eteenpäin, samalla kun itse pysyt aloillasi.","La rivière du temps continue à couler, tandis que vous restez immobile.","Az idő folyója folyamat halad tovább, miközben te csak álldogállsz.","Il fiume del tempo scorre inesorabilmente, mentre tu rimani fermo.",事を措いても、時の河は永遠の先に進む。,"발버둥을 친다해도, 시간의 강은 계속 흐를 뿐.","De rivier van de tijd beweegt voor altijd verder, terwijl je stilstaat.","Tidens elv beveger seg evig fremover, mens du står stille.","Rzeka czasu płynie wiecznie, podczas gdy ty stoisz w miejscu.","O corrente do tempo se movimenta sempre adiante, enquanto você fica imóvel.",,"Râul timpului curge în permanență, în timp ce tu stai pe loc.","Река времени непрестанно течёт вперёд, в то время как ты стоишь без движения.",,"Tidens flod rör sig för evigt framåt, medan du står stilla.",Zaman nehri sonsuza dek ilerlerken sen duruyorsun. +"Pitiful man, you have done what thousands have failed to do... You bring me the power of the Sigil, the voice of the One God.",TXT_DLG_SCRIPT12_D15160_PITIF,MAP12: Oracle → After killing the Loremaster with Macil dead.,,,"Ubohý člověče, dokázal jsi to, co tisíce před tebou ne... Přinášíš mi moc Pečetě, hlas Jednoho boha.","Ynkelige mand, du har gjort, hvad tusindvis af mennesker ikke har formået... Du bringer mig Sigilets kraft, den ene Guds stemme.","Armseliger Wurm, du hast getan woran Tausende gescheitert sind... Du brachtest mir die Macht des Sigils, die Stimme des Einen Gottes.",,"Malestiminda homo, vi faris tion, kion miloj ne povis: vi portas ĉe mi la povon de la Sigelo, la voĉo de la Vera Dio.","Despreciable humano, has hecho lo que miles no han podido: traes ante mí el poder del Emblema, la voz del Dios Único.","Despreciable humano, lograste lo que miles no han podido: traes ante mí el poder del Emblema, la voz del Dios Único.","Kurja ihminen, olet tehnyt sen, missä tuhannet ovat epäonnistuneet: Olet tuonut minulle Sinetin voiman, Yhden Ainoan Jumalan äänen.","Pathétique mortel, vous avez réussi là où des milliers ont failli.. Vous m'amenez le pouvoir du Sigil, la voix du Seul Dieu.","Szánalmas kis pondró, megtetted amit emberek ezrei sem tudtak megtenni...elhoztad számomra a Pecsét erejét, az egy igaz isten hangját.","Patetico umano, sei riuscito a fare ciò che in migliaia hanno fallito nel compiere... Mi hai portato il potere del Sigillo, la voce dell'Unico Dio.","気の毒な者よ、お主は幾千の者達が 遂げられなかった行いを果たした... -お主は我にシジルの力を、唯一神の声を届けた。","애처로운 자여, 지금껏 수천 명이 이루지 못했던 일을 해내었다... 나에게 시질의 힘을, 유일신의 목소리를 전해주는구나.","Jammer man, je hebt gedaan wat duizenden mensen niet hebben gedaan.... Je brengt me de kracht van de Sigil, de stem van de Ene God.",,"Que homem patético. Você fez o que milhares não conseguiram... Você me trouxe o poder do Sigilo, a voz do Deus Único.",,,"Ничтожный человечишка, тебе удалось сделать то, с чем не справились тысячи... Ты принёс мне мощь Сигила, глас Единого Бога.", -I don't understand.,TXT_RPLY0_SCRIPT12_D15160_IDONT,,,,Nerozumím ti.,Ich verstehe nicht.,,,No entiendo.,,,Je ne comprends pas.,,,わからないな。,이해 할 수 없어.,Ik begrijp het niet.,,Eu não entendo.,,,Я не понимаю., -The Sigil will open the door and free the spirit which will cleanse this planet and let me live forever. I will strip this world of its energies and find new worlds to conquer.,TXT_DLG_SCRIPT12_D16676_THESI,,,,"Pečeť otevře brány a uvolní duši, která očistí tuto planetu a dovolí mi žít navěky. Vysaju tento svět jeho sil a najdu další světy k podmanutí.","Das Sigil wird die Tür öffnen und den Geist befreien, den Planeten läutern und mich für immer leben lassen. Ich werde dieser Welt alle Energie entziehen und neue Welten finden, um sie zu erobern.",,,El Emblema abrirá la puerta y liberará el espíritu que limpiará éste planeta y me dejará vivir eternamente. Despojaré a este mundo de su energía y buscaré otros que conquistar.,,,Le Sigil ouvrira la porte et libérera l'âme qui purifiera cette planète et me donnera la vie éternelle. J'arracherai toutes les énergies de ce monde et en trouverai d'autres à conquérir.,,,"シジルは門を開き、この惑星の魂を浄化し +お主は我にシジルの力を、唯一神の声を届けた。","애처로운 자여, 지금껏 수천 명이 이루지 못했던 일을 해내었다... 나에게 시질의 힘을, 유일신의 목소리를 전해주는구나.","Jammer man, je hebt gedaan wat duizenden mensen niet hebben gedaan.... Je brengt me de kracht van de Sigil, de stem van de Ene God.","Stakkars mann, du har gjort det tusener har mislyktes med... Du gir meg sigillets kraft, stemmen til den ene guden.","Żałosny człowieku, dokonałeś tego, czego nie udało się zrobić tysiącom... Przynosisz mi moc Sigil, głos Jedynego Boga.","Que homem patético. Você fez o que milhares não conseguiram... Você me trouxe o poder do Sigilo, a voz do Deus Único.",,"Om jalnic, ai reușit ceea ce nu a reușit nimeni să facă.... Îmi aduci puterea Sigiliului, vocea Adevăratului Zeu.","Ничтожный человечишка, тебе удалось сделать то, с чем не справились тысячи... Ты принёс мне мощь Печати, глас Единого Бога.",,"Du har gjort vad tusentals har misslyckats med att göra... Du ger mig Sigillets kraft, den ende Gudens röst.","Zavallı adam, binlerce kişinin yapamadığını yaptın. Bana Sigil'in gücünü, Tek Tanrı'nın sesini getirdin." +I don't understand.,TXT_RPLY0_SCRIPT12_D15160_IDONT,〃,,,Nerozumím ti.,Jeg forstår ikke.,Ich verstehe nicht.,,Mi ne komprenas.,No entiendo.,,En ymmärrä.,Je ne comprends pas.,Nem értem.,Non capisco.,わからないな。,무슨 소리야?,Ik begrijp het niet.,Jeg forstår ikke.,Nie rozumiem.,Eu não entendo.,,Nu înțeleg.,Я не понимаю.,,Jag förstår inte.,Anlamıyorum. +The Sigil will open the door and free the spirit which will cleanse this planet and let me live forever. I will strip this world of its energies and find new worlds to conquer.,TXT_DLG_SCRIPT12_D16676_THESI,〃,,,"Pečeť otevře brány a uvolní duši, která očistí tuto planetu a dovolí mi žít navěky. Vysaju tento svět jeho sil a najdu další světy k podmanutí.","Sigilet vil åbne døren og frigøre ånden, som vil rense denne planet og lade mig leve for evigt. Jeg vil fratage denne verden dens energier og finde nye verdener at erobre.","Das Sigil wird die Tür öffnen und den Geist befreien, den Planeten läutern und mich für immer leben lassen. Ich werde dieser Welt alle Energie entziehen und neue Welten finden, um sie zu erobern.",,"La Sigelo malfermos la pordon kaj liberigos la spiriton, kiu elpurigos ĉi tiun planedon kaj ebligos al mi vivi eterne. Mi senigos ĉi tiun mondon je ĝia energio kaj mi trovos aliajn konkerotajn.",El Emblema abrirá la puerta y liberará al espíritu que limpiará este planeta y me dejará vivir eternamente. Despojaré este mundo de su energía y buscaré otros que conquistar.,El Emblema va a abrir la puerta y a liberar al espíritu que va a limpiar este planeta y a dejarme vivir eternamente. Voy a despojar este mundo de su energía y a buscar otros que conquistar.,"Sinetti aukaisee portin ja vapauttaa hengen, joka puhdistaa tämän planeetan ja antaa minun elää ikuisesti. Riisun tämän maailman sen energioista ja etsin uusia maailmoja vallattavaksi.",Le Sigil ouvrira la porte et libérera l'âme qui purifiera cette planète et me donnera la vie éternelle. J'arracherai toutes les énergies de ce monde et en trouverai d'autres à conquérir.,"A pecsét kinyitja az ajtót a lélek előtt, ami megtisztítja ezt a bolygót és örök életet biztosít számomra. Megfosztom ezt a világot az energiáitól, és továbblépek más világokba ha végeztem vele.",Il Sigillo aprirà la porta e libererà lo spirito che purificherà questo pianeta e mi lascerà vivere per sempre. Spoglierò questo mondo delle sue energie e troverò nuovi mondi da conquistare.,"シジルは門を開き、この惑星の魂を浄化し 我に永遠の命を授け給うのだ。我はこの世の 生命力を剥ぎ取り、新たなる星への征服に -駆り出すのだ。","시질은 잠겨저 있던 문을 열고, 이 세상을 정화할 혼령을 깨울 것이며, 나에게 영생을 선사할 것이다. 내가 이 세상의 기운을 모두 쓸어 담아 새로 정복할 세계를 찾아 나설 힘을 모을 것이다.",De Sigil zal de deur openen en de geest bevrijden die deze planeet zal reinigen en me voor altijd zal laten leven. Ik zal deze wereld van zijn energie ontdoen en nieuwe werelden vinden om te veroveren.,,O Sigilo abrirá a porta e libertará o espirito que purificará este planeta e permitirá que eu viva para sempre. Arrancarei as energias deste mundo e encontrar novos mundos para conquistar.,,,"Сигил распахнёт дверь и высвободит сущность, что очистит эту планету и дарует мне вечную жизнь. Я выкраду всю энергию этого мира и отправлюсь на завоевание следующих.", -I can't let you do that.,TXT_RPLY0_SCRIPT12_D16676_ICANT,,,,To ti nemůžu dovolit.,Ich kann das nicht erlauben.,,,No puedo dejarte hacer eso.,,,Je ne peux pas vous laisser faire ça.,,,そんな真似はさせられないな。,네 놈의 음모를 막겠다!,Dat kan ik je niet laten doen.,,Não vou deixar você fazer isso.,,,Я не могу этого допустить., -You can if you're dead.,TXT_DLG_SCRIPT12_D18192_YOUCA,,,,"Můžeš, když zemřeš.","Du kannst, wenn du tot bist.",,,"Puedes, si estás muerto.",,,"Vous pouvez, une fois que vous êtes mort.",,,お主の破滅は免れぬぞ。,네가 죽으면 될 것이다...,Dat kan je wel als je dood bent.,,Deixará se você estiver morto.,,,"Сможешь, когда умрёшь.", -"Are you here to free us? Because I've been good, they took my implant out. I still have to stay down here and wipe up the drool though.",TXT_DLG_SCRIPT14_D0_AREYO,,,,"Jsi tu, abys nás vysvobodil? Za dobré chování mi můj implantát vyndali. Stále tu ale musím zůstat a utírat sliny.","Bist du hier, um uns zu befreien? Ich war gut, sie haben mein Implasntat herasusgenommen. Ich muss aber hier bleiben und den Sabber aufwischen.",,,"¿Estás aquí para liberarnos? Porque he sido bueno, me han quitado el implante. Aunque aún tengo que quedarme aquí abajo y limpiar la saliva.",,,"Vous êtes venus nous libérer? Je me suis bien comporté! Il m'on retiré mon implant, il faut que je reste ici et que j'essuie la bave, par contre.",,,"俺達を解放しに来たのか?あいつらに +駆り出すのだ。","시질은 잠겨저 있던 문을 열고, 이 세상을 정화할 혼령을 깨울 것이며, 나에게 영생을 선사할 것이다. 내가 이 세상의 기운을 모두 쓸어 담아 새로 정복할 세계를 찾아 나설 힘을 모을 것이다.",De Sigil zal de deur openen en de geest bevrijden die deze planeet zal reinigen en me voor altijd zal laten leven. Ik zal deze wereld van zijn energie ontdoen en nieuwe werelden vinden om te veroveren.,Sigllet vil åpne døren og frigjøre ånden som vil rense denne planeten og la meg leve evig. Jeg vil strippe denne verden for dens energier og finne nye verdener å erobre.,"Sigil otworzy drzwi i uwolni ducha, który oczyści tę planetę i pozwoli mi żyć wiecznie. Pozbawię ten świat jego energii i znajdę nowe światy do podbicia.",O Sigilo abrirá a porta e libertará o espirito que purificará este planeta e permitirá que eu viva para sempre. Arrancarei as energias deste mundo e encontrar novos mundos para conquistar.,,Sigiuliul va deschide ușa și elibera spiritul care va curăța planeta și mă va face nemuritor. Voi stoarce energia din planetă iar apoi voi găsi alte lumi de cucerit.,"Печать распахнёт дверь и высвободит сущность, что очистит эту планету и дарует мне вечную жизнь. Я выкраду всю энергию этого мира и отправлюсь на завоевание следующих.",,Sigillet kommer att öppna dörren och frigöra anden som kommer att rena den här planeten och låta mig leva för evigt. Jag kommer att beröva den här världen dess energier och hitta nya världar att erövra.,Sigil kapıyı açacak ve bu gezegeni temizleyecek ruhu serbest bırakacak ve sonsuza dek yaşamama izin verecek. Bu dünyayı enerjilerinden arındırıp fethedecek yeni dünyalar bulacağım. +I can't let you do that.,TXT_RPLY0_SCRIPT12_D16676_ICANT,〃,,,To ti nemůžu dovolit.,Det kan jeg ikke lade dig gøre.,Ich kann das nicht erlauben.,,"Mi ne povas lasi, ke vi faru tion.",No puedo dejarte hacer eso.,,En voi antaa sinun tehdä sitä.,Je ne peux pas vous laisser faire ça.,Csak a holttestemen keresztül.,Non te lo posso permettere.,そんな真似はさせられないな。,네 놈의 음모를 막겠다!,Dat kan ik je niet laten doen.,Jeg kan ikke la deg gjøre det.,Nie mogę ci na to pozwolić.,Não vou deixar você fazer isso.,,Nu te pot lăsa să faci asta.,Я не могу этого допустить.,,Jag kan inte låta dig göra det.,Bunu yapmana izin veremem. +You can if you're dead.,TXT_DLG_SCRIPT12_D18192_YOUCA,MAP12: Oracle → Fight with the Oracle.,,,"Můžeš, když zemřeš.","Det kan du, hvis du er død.","Du kannst, wenn du tot bist.",,Vi povas... se vi estas mortinta.,Puedes... si estás muerto.,,"Kyllä voit, jos olet kuollut.","Vous pouvez, une fois que vous êtes mort.",Ez megoldható.,Puoi... se sei morto!,お主の破滅は免れぬぞ。,네가 죽으면 될 것이다...,Dat kan je wel als je dood bent.,Du kan hvis du er død.,"Możesz, jeśli będziesz martwy.",Deixará se você estiver morto.,,"Poți, dacă ești mort.","Сможешь, когда умрёшь.",,Det kan du om du är död.,Ölürsen izin verebilirsin. +"Are you here to free us? Because I've been good, they took my implant out. I still have to stay down here and wipe up the drool though.",TXT_DLG_SCRIPT14_D0_AREYO,MAP14: James,,,"Jsi tu, abys nás vysvobodil? Za dobré chování mi můj implantát vyndali. Stále tu ale musím zůstat a utírat sliny.","Er du her for at befri os? Fordi jeg har været god, tog de mit implantat ud. Jeg er dog stadig nødt til at blive hernede og tørre savlen op.","Bist du hier, um uns zu befreien? Ich war gut, sie haben mein Implasntat herasusgenommen. Ich muss aber hier bleiben und den Sabber aufwischen.",,"Ĉu vi venis liberigi nin? Ili forprenis la enplantaĵon de mi ĉar mi estis obeema. Malgraŭ tio, mi devas resti ĉi-malsupre purigi.","¿Has venido a liberarnos? Como he sido bueno, me quitaron el implante, pero aun así tengo que quedarme aquí abajo a limpiar.","¿Viniste a liberarnos? Como he sido bueno, me quitaron el implante, pero aun así tengo que quedarme aquí abajo a limpiar.","Oletko tullut vapauttamaan meidät? Koska olen käyttäytynyt kiltisti, he poistivat istutteeni. Minun kuitenkin on jäätävä tänne pyyhkimään kuolaa.","Vous êtes venus nous libérer? Je me suis bien comporté! Il m'on retiré mon implant, il faut que je reste ici et que j'essuie la bave, par contre.","Azért vagy itt, hogy felszabadíts minket? Jó voltam, és elvették az implantátumomat. Mégis itt kell rohadnom és takarítanom ezt a nyálkát.","Sei qui per liberarci? Dato che mi sono comportato bene, mi hanno tolto l'impianto. Però devo ancora restare quaggiù a pulire.","俺達を解放しに来たのか?あいつらに インプラントを外されたが、俺は大丈夫だ。 -まだ少し留まって涎を拭き取らないとならない。","저희를 구출하기 위해서 찾아오셨나요? 왜냐하면 그들이 제가 성실하게 일을 한 사례로 세뇌 장치를 때어갔어요. 그런데... 아직 안전하지도 않은 것 같고, 좀 흘린 침 자국을 좀 닦아야 할 것 같아요.","Ben je hier om ons te bevrijden? Omdat ik goed ben geweest, hebben ze mijn implantaat eruit gehaald. Ik moet nog steeds hier beneden blijven en de kwijl echter wegvegen.",,"Você está aqui para nos libertar? Por eu ter me comportado bem, eles tiraram o meu implante. Mas ainda tenho que ficar aqui para limpar a saliva.",,,"Ты пришёл спасти нас? Я был послушным, так что они вынули мой имплант. И всё равно я вынужден оставаться тут, внизу, и подтирать слюни за дронами.", -"Yes, I'm here to free you.",TXT_RPLY0_SCRIPT14_D0_YESIM,,,,"Ano, jsem tu, abych vás osvobodil.","Ja, ich werde eiuch befreien.",,,"Sí, estoy aquí para liberarte.",,,"Oui, je viens vous libérer.",,,そうだ、助けに来た。,"그래, 난 널 구하러 왔어.","Ja, ik ben hier om je te bevrijden.",,"Sim, estou aqui para libertar vocês.",,,"Да, я здесь, чтобы спасти вас.", -You mean it?,TXT_RYES0_SCRIPT14_D0_YOUME,,,,To myslíš doopravdy?,Wirklich?,,,¿En serio?,,,Vraiment?,,,そういう意味か?,정말인가요?,Je meent het?,,Sério mesmo?,,,Правда?, -I can't help nobody else. Not until you blow up the transmitter. That's what's behind the forcefield upstairs. My job is to check on the conveyors to make sure they aren't jammed. Not anymore!,TXT_DLG_SCRIPT14_D1516_ICANT,,,,"Nemůžu nikomu jinému pomoct, ne dokud neodpálíš vysílačku, to je ta věc nahoře za silovým polem. Já mám za úkol kontrolovat pásy a dávat pozor, aby se nezasekly. Ani náhodou!","Ich kann niemandem helfen. Nich bevor jemand den Transmitter hochjagt. Er ist hinter dem Kraftfeld da oben. Meine Aufgabe ist es, die Förderbänder zu prüfen um sicherzustellen, dass sie nicht blockieren. Jetzt nicht mehr!",,,No puedo ayudar a nadie más. No hasta que destruyas el transmisor. Eso es lo que está tras el campo de fuerza escaleras arriba. Mi trabajo es comprobar los transportadores para asegurarme de que no esten atascados. ¡Nunca más!,No puedo ayudar a nadie más. No hasta que destruyas el transmisor. Eso es lo que está detrás del campo de fuerza escaleras arriba. Mi trabajo es comprobar los transportadores para asegurarme de que no esten atascados. ¡Ya no más!,,"Je ne peux pas aider qui que ce soit d'autre, du moins pas avant que vous détruisez le transmetteur. C'est la chose derrière le champ de force à l'étage. Mon travail est de faire en sorte que les tapis roulants ne se coincent pas, mais plus maintenant!",,,"まだ俺は手伝うことが出来ない。 +まだ少し留まって涎を拭き取らないとならない。","저희를 구출하기 위해서 찾아오셨나요? 그들이 제가 성실하게 일을 한 사례로 세뇌 장치를 때어갔어요. 그런데... 아직도 위험한 것 같은데, 좀 흘린 침 자국을 좀 닦아야 할 것 같아요.","Ben je hier om ons te bevrijden? Omdat ik goed ben geweest, hebben ze mijn implantaat eruit gehaald. Ik moet nog steeds hier beneden blijven en de kwijl echter wegvegen.",Er du her for å befri oss? Fordi jeg har vært snill. De fjernet implantatet mitt. Men jeg må fortsatt bli her nede og tørke opp siklet.,"Jesteś tu, by nas uwolnić? Ponieważ byłem dobry, wyjęli mi implant. Ale nadal muszę tu zostać i wytrzeć ślinę.","Você está aqui para nos libertar? Por eu ter me comportado bem, eles tiraram o meu implante. Mas ainda tenho que ficar aqui para limpar a saliva.",,"Ai venit ca să ne eliberezi? Pentru că am fost cuminte, mi-au scos implantul. Dar tot trebuie să rămân aici și să fac curățenie însă.","Ты пришёл спасти нас? Я был послушным, так что они вынули мой имплант. И всё равно я вынужден оставаться тут, внизу, и подтирать слюни.",,Är du här för att befria oss? För att jag har varit snäll tog de bort mitt implantat. Jag måste ändå stanna här nere och torka upp dreglet.,Bizi özgür bırakmak için mi buradasın? İyi olduğum için implantımı çıkardılar. Yine de burada kalıp salyamı silmem gerekiyor. +"Yes, I'm here to free you.",TXT_RPLY0_SCRIPT14_D0_YESIM,〃,,,"Ano, jsem tu, abych vás osvobodil.","Ja, jeg er her for at befri jer.","Ja, ich werde eiuch befreien.",,"Jes, mi venis liberigi vin.","Sí, he venido a liberaros.","Sí, vine a liberarlos.","Kyllä, tulin vapauttamaan teidät.","Oui, je viens vous libérer.","Igen, azért jöttem hogy kiszabadítsalak.","Sì, sono qui per liberarvi.",そうだ、助けに来た。,"그래, 난 널 구하러 왔어.","Ja, ik ben hier om je te bevrijden.","Ja, jeg er her for å befri dere.","Tak, jestem tu, żeby was uwolnić.","Sim, estou aqui para libertar vocês.",,"Da, am venit să te eliberez.","Да, я здесь, чтобы спасти вас.",,"Ja, jag är här för att befria er.","Evet, sizi kurtarmak için buradayım." +You mean it?,TXT_RYES0_SCRIPT14_D0_YOUME,〃,,,To myslíš doopravdy?,Mener du det?,Wirklich?,,Ĉu vere?,¿En serio?,,Todellako?,Vraiment?,Tényleg?,Veramente?,そういう意味か?,정말인가요?,Je meent het?,Mener du det?,Mówisz poważnie?,Sério mesmo?,,Pe bune?,Правда?,,Menar du det?,Ciddi misin? +I can't help nobody else. Not until you blow up the transmitter. That's what's behind the forcefield upstairs. My job is to check on the conveyors to make sure they aren't jammed. Not anymore!,TXT_DLG_SCRIPT14_D1516_ICANT,"〃 +(conveyors = conveyor belts)",,,"Nemůžu nikomu jinému pomoct, ne dokud neodpálíš vysílačku, to je ta věc nahoře za silovým polem. Já mám za úkol kontrolovat pásy a dávat pozor, aby se nezasekly. Teď už ani náhodou!","Jeg kan ikke hjælpe nogen andre. Ikke før du sprænger senderen i luften. Det er det, der er bag kraftfeltet ovenpå. Mit job er at tjekke transportbåndene for at sikre mig, at de ikke er blokeret. Ikke længere!","Ich kann niemandem helfen. Nich bevor jemand den Transmitter hochjagt. Er ist hinter dem Kraftfeld da oben. Meine Aufgabe ist es, die Förderbänder zu prüfen um sicherzustellen, dass sie nicht blockieren. Jetzt nicht mehr!",,"Mi povas helpi neniun alian, ne dum la transmisiilo ne estos detruita; ĝi estas post la supretaĝa fortokampo. Mia laboro estas kontroli la transportajn bendojn por certiĝi, ke ili ne blokiĝis. Ne plu!","No puedo ayudar a nadie más, no hasta que destruyas el transmisor; eso es lo que está tras el campo de fuerza del piso de arriba. Mi trabajo es revisar las cintas transportadoras para asegurarme de que no estén atoradas. ¡Ya no más!",,"En voi auttaa ketään muuta. En, ennen kuin räjäytät lähettimen. Se se on, joka sijaitsee yläkerran voimakentän takana. Työni on pitää silmällä ja varmistaa, etteivät liukuhihnat jumiudu, enää!","Je ne peux pas aider qui que ce soit d'autre, du moins pas avant que vous détruisez le transmetteur. C'est la chose derrière le champ de force à l'étage. Mon travail est de faire en sorte que les tapis roulants ne se coincent pas, mais plus maintenant!","Nem tudok már másnak segíteni. Legalábbis nem amíg nem robbantod fel az adóállomást. Ez áll az erőpajzs mögött. Az Én feladatom, hogy ellenőrizzem a futószalagot nem akadt e be. Többé aztán nem!",Non posso aiutare nessun'altro. Non finché non fai saltare in aria il trasmettitore. È questo che c'è dietro il campo di forza di sopra. Il mio compito è asicurarmi che i nastri trasportatori non si intoppino. Non più!,"まだ俺は手伝うことが出来ない。 トランスミッターを壊さなければバレてしまう。 そいつは上の階のフォースフィールドを越えた所 にいる。コンベアーの詰まりをチェックする -だけの仕事だったが、もう辞任だな!",전송기를 파괴하기 전까지는 세뇌된 사람들을 도와줄 수가 없어요. 저 위층에 방어막에 보호받고 있는 채로 있습니다. 제 원래 업무는 광석이 끼지 않게 운반 벨트를 확인하는 거였어요... 이젠 일할 필요도 없지만!,Ik kan niemand anders helpen. Niet voordat je de zender hebt opgeblazen. Dat is wat er achter het krachtveld boven is. Het is mijn taak om de transportbanden te controleren om er zeker van te zijn dat ze niet vastzitten. Nu niet meer!,,Não posso ajudar mais ninguém. Não até que você detone o transmissor. É isso que mantém o campo de força lá em cima. Meu trabalho é conferir as esteiras para que não fiquem emperradas. Nunca mais!,,,"Я не могу помочь другим, пока ты не взорвёшь передатчик. Он находится за силовым полем наверху. Моя работа — проверять, не заклинило ли конвейеры. Теперь уже нет!", -"That's right, you're saved!",TXT_RPLY0_SCRIPT14_D1516_THATS,,,,"Ano, jsi zachráněn!","Das ist richtig, du bist in Sicherheit!",,,"Correcto, ¡estás salvado!",,,"C'est ça, vous êtes sauvé!",,,そうだ、救われたぞ!,당연하지. 너는 자유야!,"Dat klopt, je bent gered!",,Isso mesmo. Vocês estão salvos!,,,"Да, это так! Вы спасены!", -"Oh, thank you!",TXT_RYES0_SCRIPT14_D1516_OHTHA,,,,"Oh, děkuju!","Oh, danke sehr!",,,"Oh, ¡gracias!",,,"Oh, merci!",,,おう、ありがとよ!,"오, 고마워요!","Oh, dank je wel!",,"Ah, muito obrigado!",,,Ура! Спасибо тебе!, -We're free!! We're free!! We're free!!,TXT_DLG_SCRIPT14_D3032_WEREF,,,,Jsme volní! Jsme volní! Jsme volní!,Wir sind frei! Wir sind frei! Wir sind frei!,,,¡¡Somos libres!! ¡¡Somos libres!! ¡¡Somos libres!!,,,On est libres! Libres! Libres!,,,自由だ!!俺達は自由だ!!俺達は自由だ!!,우린 자유야! 우린 자유라고!,We zijn vrij!! We zijn vrij!! We zijn vrij!!,,Estamos livres!! Estamos livres!! Estamos livres!!,,,Мы свободны! Мы свободны! Мы свободны!, -Must mine more ore!,TXT_DLG_SCRIPT14_D4548_MUSTM,,,,Muset těžit další rudu!,Muss Erz abbauen.,,,¡Debo picar más mineral!,,,Faut que je trouve plus de minerai!,,,もっと掘らねえといけねえんだ!,광석을... 캐내야 해...,Moet erts meer of meer ontginnen!,,Preciso minerar mais!,,,Нужно добыть больше руды!, -We're free!! We're free!! We're free!!,TXT_DLG_SCRIPT14_D6064_WEREF,,,,Jsme volní! Jsme volní! Jsme volní!,Wir sind frei! Wir sind frei! Wir sind frei!,,,¡¡Somos libres!! ¡¡Somos libres!! ¡¡Somos libres!!,,,On est libres! Libres! Libres!,,,自由だ!!オレらは自由だ!!オレらは自由だ!!,프론트가 해냈다! 자유를 거의 되찾았어!,We zijn vrij!!! We zijn vrij!!! We zijn vrij!!!,,Estamos livres!! Estamos livres!! Estamos livres!!,,,Мы свободны! Мы свободны! Мы свободны!, -Must mine more ore!,TXT_DLG_SCRIPT14_D7580_MUSTM,,,,Muset těžit další rudu!,Muss Erz abbauen.,,,¡Debo picar más mineral!,,,Faut que je trouve plus de minerai!,,,鉱石がもっと必要なんだ!,광석... 데그닌... 캔다...,Moet meer erts ontginnen!,,Preciso minerar mais!,,,Нужно добыть больше руды!, -We're free!! We're free!! We're free!!,TXT_DLG_SCRIPT14_D9096_WEREF,,,,Jsme volní! Jsme volní! Jsme volní!,Wir sind frei! Wir sind frei! Wir sind frei!,,,¡¡Somos libres!! ¡¡Somos libres!! ¡¡Somos libres!!,,,On est libres! Libres! Libres!,,,自由だ!!私達は自由だ!!私達は自由だ!!,살았군요. 이제 저항군 기지로 향하는 일 밖엔 남지 않은 것 같아요.,We zijn vrij!!! We zijn vrij!!! We zijn vrij!!!,,Estamos livres!! Estamos livres!! Estamos livres!!,,,Мы свободны! Мы свободны! Мы свободны!, -Must mine more ore!,TXT_DLG_SCRIPT14_D10612_MUSTM,,,,Muset těžit další rudu!,Muss Erz abbauen.,,,¡Debo picar más mineral!,,,Faut que je trouve plus de minerai!,,,いつまで採掘しなければならない!,캐고... 캐고... 또 캔다...,Moet meer erts ontginnen!,,Preciso minerar mais!,,,Нужно добыть больше руды!, -We're free!! We're free!! We're free!!,TXT_DLG_SCRIPT14_D12128_WEREF,,,,Jsme volní! Jsme volní! Jsme volní!,Wir sind frei! Wir sind frei! Wir sind frei!,,,¡¡Somos libres!! ¡¡Somos libres!! ¡¡Somos libres!!,,,On est libres! Libres! Libres!,,,僕らは自由だ!!僕らは自由だ!!僕らは自由だ!!,살았다! 이제 그 놈들이 죽이기 전에 도망쳐야해요!,We zijn vrij!!! We zijn vrij!!! We zijn vrij!!!,,Estamos livres!! Estamos livres!! Estamos livres!!,,,Мы свободны! Мы свободны! Мы свободны!, -What are you doing here?,TXT_DLG_SCRIPT15_D0_WHATA,,,,Co tady děláš?,Was machst du hier?,,,¿Qué haces aquí?,,,Qu'est ce que vous faites ici?,,,ここで何をしている?,여기서 뭘 하는거지?,Wat doe je hier?,,O que você está fazendo aqui?,,,По какому делу ты здесь?, -Routine inspection.,TXT_RPLY0_SCRIPT15_D0_ROUTI,,,,Rutinní inspekce.,Eine Routineinspektion.,,,Inspección rutinaria.,,,Inspection de routine.,,,見回りだ。,정기적 검사요.,Routine-inspectie.,,Inspeção de rotina.,,,Плановая проверка., -"All right, carry on.",TXT_RYES0_SCRIPT15_D0_ALLRI,,,,"Dobře, pokračuj.","In Ordnung, mach weiter.",,,"Muy bien, continúa.",,,"D'accord, continuez.",,,わかった、続けろ。,"좋아, 계속해.","Oké, ga door.",,"Muito bem, continue.",,,Понятно. Продолжай., -"Nothing to report here. Everything is working fine. If anything goes wrong, I'll be sure to report it.",TXT_DLG_SCRIPT15_D1516_NOTHI,,,,"Tady nic k nahlášení není. Všechno funguje dobře. Pokud se něco pokazí, nahlásím to.","Keine besonderen Vorkommnisse. Alles funktioniert wie es soll. Wenn irgendetwas schief geht, werde ich es sofort melden.",,,"Nada que reportar aquí. Todo está funcionando bien. Si cualquier cosa sale mal, me aseguraré de reportarlo.",,,"Rien à signaler ici. Tout fonctionne comme prévu. Si quelque chose tombe en panne, je ferai un rapport.",,,"報告することはない。全て順調だ。 -何か問題が起きたら報告する。","보고할 게 전혀 없어. 모든 장치, 시설, 인력 모두 이상 무. 만약 하나라도 문제가 생기면 저에게 알려줘.","Hier valt niets te melden. Alles werkt prima. Als er iets misgaat, zal ik het zeker melden.",,"Não há nada de errado aqui. Tudo está funcionando perfeitamente. Se algo parar de funcionar, pode ter certeza que eu vou avisar.",,,"Тут не о чём докладывать. Всё работает превосходно. Если что-нибудь пойдёт не так, я обязательно доложу об этом.", -"Sir, there was a problem earlier, but it was taken care of.",TXT_DLG_SCRIPT15_D3032_SIRTH,,,,"Pane, předtím tu byl problém, ale vyřešili jsme jej.","Vor kurzem gab es ein Problem, aber das wurde bereits gelöst.",,,"Señor, hubo un problema antes, pero ha sido solucionado.",,,"Monsieur, il y a eu un problème récemment mais nous l'avons corrigé.",,,"上官殿、以前より問題があったが、 -もう心配はいらない。",안녕하십니까. 조금 전에 문제가 있었습니다만 경마한 문제였고 지금 해결됐습니다.,"Meneer, er was eerder een probleem, maar het is opgelost.",,"Senhor, havia um problema antes, mas já foi resolvido.",,,"Сэр, тут была одна неполадка, но её уже устранили.", -Move along or taste metal.,TXT_DLG_SCRIPT17_D0_MOVEA,,,,"Jdi dál, nebo okus ocel.",Beweg dich oder spüre meinen Stahl.,,,Sigue caminando o prueba metal.,,,Bougez ou préparez-vous à goûter de l'acier.,,,同行か鉄を味わうかだ。,탄창으로 맞고 싶지 않으면 움직여.,Ga verder of proef metaal.,,Vá embora ou vai tomar chumbo grosso.,,,"Прочь, или отведаешь металла.", -I.D. check.,TXT_DLG_SCRIPT17_D1516_IDCHE,,,,Kontrola dokladů.,Ausweisüberprüfung.,,,Comprobación de identificación.,,,Vérification de carte d'identité.,,,I.D.チェックだ。,신분증 확인.,I.D. check.,,Verificação de identidade.,,,Ваши документы., -"Here, I'm in a hurry.",TXT_RPLY0_SCRIPT17_D1516_HEREI,,,,"Tady, spěchám.","Hier, ich hab's eilig.",,,"Ten, tengo prisa.",,,"Voilà, je suis pressé.",,,ほら、急いでるんだ。,여기요. 급하니 빨리 확인해주세요.,Hier heb ik haast.,,"Pegue, estou com pressa.",,,Вот. Я тороплюсь., -Stop waving your ID in my face and go in.,TXT_DLG_SCRIPT17_D3032_STOPW,,,,Přestaň mi mávat svou kartou před obličejem a jdi dovnitř.,Hör auf mit deinem Ausweis vor meinem Gesicht herumzufuchteln und geh hinein.,,,Deja de agitar tu identificación en mi cara y entra.,,,Arrêtez de l'agiter dans ma figure et passez.,,,目前まで近づけるな、さっさと行け。,얼굴 앞에서 신분증 그만 흔들고 얼른 들어가.,Stop met je ID in mijn gezicht te zwaaien en ga naar binnen.,,Pare de sacudir a sua identificação e entre logo.,,,Прекрати махать своей карточкой перед моим лицом и проходи., -Nothing to see here. Move along.,TXT_DLG_SCRIPT17_D4548_NOTHI,,,,Nic k vidění. Jdi dál.,Hier gibt es nichts zu sehen. Geh weiter.,,,Nada que ver aquí. Sigue caminando.,,,Rien à voir ici. Bougez.,,,何事も無い。進め。,아무 일도 안 일어났다. 어서 움직여.,Hier is niets te zien. Ga verder.,,Nada pra ver aqui. Vá embora.,,,Тут не на что смотреть. Проваливай., -"What a healthy specimen. You don't need my help, do you?",TXT_DLG_SCRIPT17_D6064_WHATA,,,,"Jaký zdravý exemplář! Moji pomoc nepotřebuješ, že ne?","Was für ein schönes Exemplar. Du brauchst meine Hilfe nicht, oder?",,,"Que espécimen más saludable. No necesitas mi ayuda, ¿verdad?",,,"Quel magnifique spécimen! Vous n'avez pas besoin de mon aide, si?",,,"なんて活きの良い標本だ。 -手当なんて必要なさそうだな、で何だ?","정말 건강한 표본이군. 아마 넌 내 도움이 필요하지 않을 거야, 그렇지?","Wat een gezond exemplaar. Je hebt mijn hulp niet nodig, of wel?",,"Mas que espécime mais saudável. Você não precisa da minha ajuda, precisa?",,,"Какой прекрасный образец. Тебе не нужна моя помощь, или нужна?", -"Well, yes. Macil sent me.",TXT_RPLY0_SCRIPT17_D6064_WELLY,,,,"No, jo. Poslal mě Macil.","Nun, doch. Macil hat mich geschickt.",,,"Bueno, sí. Macil me ha enviado.",,,"Eh bien, si, Macil m'envoie.",,,そうだ。マシルの使者だ。,"뭐, 그렇지. 마실이 날 보냈으니까.","Nou, ja. Macil heeft me gestuurd.",,"Bem, sim. Macil me enviou.",,,"Ну, нужна. Я от Мэйсила.", -"Shhhh... Keep it quiet, unless you want us both killed. Now, what can I do for you?",TXT_DLG_SCRIPT17_D7580_SHHHH,,,,"Pššš... Buď potichu, leda že bys chtěl nás oba nechat popravit. Tak, co pro tebe můžu udělat?","Psst... sei leise, oder willst du uns beide umbringen? Nun, was kann ich für dich tun?",,,"Shhhh... No tan alto, a menos que quieras que nos maten a ambos. Bueno, ¿Qué puedo hacer por ti?",,,"Silence! Baissez de ton, sauf si vous voulez que l'on se fasse descendre tous le deux.. Que puis-je faire pour vous?",,,"シーッ...静かに、 -殺されるかもしれないんだぞ。それで何か用か?","쉿... 죽기 싫으면 조용히 해. 자, 내가 뭘 도와줄까?","Shhhhhh.... Hou het stil, tenzij je wilt dat we allebei gedood worden. Wat kan ik nu voor u doen?",,"Shhhh... Fale baixo, a não ser que queira que nos matem. Agora, como posso te ajudar?",,,"Тсс... Тише, если не хочешь, чтобы нас обоих убили. Итак, чем я могу тебе помочь?", -Tell me how to find the Bishop.,TXT_RPLY0_SCRIPT17_D7580_TELLM,,,,"Řekni mi, jak najít Biskupa.","Sage mir, wie ich den Bischof finde.",,,Dime como encontrar al Obispo.,,,Où puis-je trouver l'évêque?,,,ビショップは何処か聞きたい。,비숍을 어떻게 찾아야 하는지 알려줘.,Vertel me hoe ik de bisschop kan vinden.,,Diga onde eu encontro o Bispo.,,,"Скажи, как мне найти Епископа.", -"Ohhh, I knew you would ask me for that. Look behind you. That's the entrance to the Bishop's citadel. It's guarded by a force field that is only shut off for official visitors, not you.",TXT_DLG_SCRIPT17_D9096_OHHHI,,,,"Ohó, já věděl, že se mě na tohle zeptáš. Podívej se za sebe. To je vchod do Biskupovy citadely. Je střežená silovým polem, které se vypíná pouze kvůli oficiálním návštěvám, ne tobě.","Oh, hab ich's doch geahnt, dass du mich das fragen würdest. Schau mal hinter dich. Dort ist der Eingang zu der Festung des Bischofs. Er ist durch ein Kraftfeld geschützt, welches sich nur für offizielle Besucher abschaltet und nicht für dich.",,,"Ohhh, sabía que me preguntarías eso. Mira detrás de ti. Esa es la entrada a la ciudadela del Obispo. Está guardada por un campo de fuerza que solo se apaga para visitantes oficiales, no tú.",,,"Ohh, je savais que vous me demanderiez cela. Regardez derrière vous. C'est l'entrée de la citadelle de l'évêque. Elle est gardée par un champ de force qui ne s'ouvre que pour les visites officielles, pas vous.",,,"おおぅ、そういう事だろうと思った。 +だけの仕事だったが、もう辞任だな!",전송기를 파괴하기 전까지는 세뇌된 사람들을 도와줄 수가 없어요. 저 위층에 방어막에 보호받고 있는 채로 있습니다. 제 원래 업무는 광석이 끼지 않게 운반 벨트를 확인하는 거였어요... 이젠 일할 필요도 없지만!,Ik kan niemand anders helpen. Niet voordat je de zender hebt opgeblazen. Dat is wat er achter het krachtveld boven is. Het is mijn taak om de transportbanden te controleren om er zeker van te zijn dat ze niet vastzitten. Nu niet meer!,Jeg kan ikke hjelpe noen andre. Ikke før du sprenger senderen. Det er det som er bak kraftfeltet der oppe. Jobben min er å sjekke at transportbåndene ikke er blokkert. Ikke nå lenger!,"Nie mogę pomóc nikomu innemu. Nie, dopóki nie wysadzisz nadajnika. To jest to, co jest za polem siłowym na górze. Moim zadaniem jest sprawdzanie, czy przenośniki nie są zablokowane. Już nie!",Não posso ajudar mais ninguém. Não até que você detone o transmissor. É isso que mantém o campo de força lá em cima. Meu trabalho é conferir as esteiras para que não fiquem emperradas. Nunca mais!,,"Nu pot ajuta pe nimeni. Nu până ce transmițătorul nu e aruncat în aer. Asta e la etaj, în spatele scuturilor. Treaba mea e să mă uit după conveioare, să mă asigur că nu sunt defecte. Numai!","Я не могу помочь другим, пока ты не взорвёшь передатчик. Он находится за силовым полем наверху. Моя работа — проверять, не заклинило ли конвейеры. Теперь уже нет!",,Jag kan inte hjälpa någon annan. Inte förrän du spränger sändaren. Det är det som finns bakom kraftfältet på övervåningen. Mitt jobb är att kontrollera transportörerna så att de inte fastnar. Inte längre!,"Başka kimseye yardım edemem. Vericiyi patlatana kadar olmaz. Üst kattaki güç alanının arkasında bu var. Benim işim, sıkışmadıklarından emin olmak için konveyörleri kontrol etmek. Artık değil!" +"That's right, you're saved!",TXT_RPLY0_SCRIPT14_D1516_THATS,〃,,,"Ano, jsi zachráněn!","Det er rigtigt, du er reddet!","Das ist richtig, du bist in Sicherheit!",,"Ĝuste, vi estas savitaj!","Correcto, ¡estáis a salvo!","Correcto, ¡están a salvo!","Näin on, olet pelastettu!","C'est ça, vous êtes sauvé!","Így van, meg van mentve.","Esatto, sei salvo!",そうだ、救われたぞ!,당연하지. 너는 자유야!,"Dat klopt, je bent gered!","Det stemmer, du er reddet!","Tak jest, jesteś uratowany!",Isso mesmo. Vocês estão salvos!,,"Așa e, ești salvat!","Да, это так! Вы спасены!",,"Det stämmer, du är räddad!","Bu doğru, kurtuldun!" +"Oh, thank you!",TXT_RYES0_SCRIPT14_D1516_OHTHA,〃,,,"Oh, děkuju!","Åh, tak!","Oh, danke sehr!",,"Ho, dankon!","¡Ah, gracias!",,"Voi, kiitos!","Oh, merci!","Oh, köszönöm!","Oh, grazie!",おう、ありがとよ!,"오, 고마워요!","Oh, dank je wel!",Takk skal du ha!,"Och, dziękuję!","Ah, muito obrigado!",,"Oh, mulțumesc!",Ура! Спасибо тебе!,,"Åh, tack!","Oh, teşekkürler!" +We're free!! We're free!! We're free!!,TXT_DLG_SCRIPT14_D3032_WEREF,〃,,,Jsme volní! Jsme volní! Jsme volní!,Vi er fri!! Vi er fri!! Vi er fri!!!,Wir sind frei! Wir sind frei! Wir sind frei!,,Ni estas liberaj!! Liberaj!! Liberaj!!,¡¡Somos libres!! ¡¡Somos libres!! ¡¡Somos libres!!,,Olemme vapaat!! Olemme vapaat!! Olemme vapaat!!,On est libres! Libres! Libres!,Szabadok vagyunk!! Szabadok vagyunk!! Szabadok vagyunk!!,Siamo liberi!! Siamo liberi!! Siamo liberi!!,自由だ!!俺達は自由だ!!俺達は自由だ!!,우린 자유야! 우린 자유라고!,We zijn vrij!! We zijn vrij!! We zijn vrij!!,Vi er fri! Vi er fri!! Vi er fri!!,Jesteśmy wolni!!! Jesteśmy wolni!!! Jesteśmy wolni!!!,Estamos livres!! Estamos livres!! Estamos livres!!,,Suntem liberi!! Suntem liberi!! Suntem liberi!!,Мы свободны! Мы свободны! Мы свободны!,,Vi är fria!! Vi är fria! Vi är fria!!,Özgürüz! Özgürüz! Özgürüz! +Must mine more ore!,TXT_DLG_SCRIPT14_D4548_MUSTM,MAP14: Drone,,,Muset těžit další rudu!,Vi må udvinde mere malm!,Muss Erz abbauen.,,Mi elfosu pliajn minaĵojn!,¡Debo picar más mineral!,,Täytyy louhia lisää malmia!,Faut que je trouve plus de minerai!,Még több ércet kell bányászni!,Devo estrarre più minerale!,もっと掘らねえといけねえんだ!,광석을... 캐내야 해...,Moet erts meer of meer ontginnen!,Må utvinne mer malm!,Musimy wydobyć więcej rudy!,Preciso minerar mais!,,Mai trebuie să minez încă o bucată de minereu.,Нужно добыть больше руды!,,Måste bryta mer malm!,Daha fazla maden çıkarmalıyız! +We're free!! We're free!! We're free!!,TXT_DLG_SCRIPT14_D6064_WEREF,MAP14: Peasant (ex-drone),,,Jsme volní! Jsme volní! Jsme volní!,Vi er frie!! Vi er frie!!! Vi er frie!!,Wir sind frei! Wir sind frei! Wir sind frei!,,Ni estas liberaj!! Liberaj!! Liberaj!!,¡¡Somos libres!! ¡¡Somos libres!! ¡¡Somos libres!!,,Olemme vapaat!! Olemme vapaat!! Olemme vapaat!!,On est libres! Libres! Libres!,Szabadok vagyunk!! Szabadok vagyunk!! Szabadok vagyunk!!,Siamo liberi!! Siamo liberi!! Siamo liberi!!,自由だ!!オレらは自由だ!!オレらは自由だ!!,프론트가 해냈다! 자유를 거의 되찾았어!,We zijn vrij!!! We zijn vrij!!! We zijn vrij!!!,Vi er fri!! Vi er frie!! Vi er fri!!,Jesteśmy wolni! Jesteśmy wolni!!! Jesteśmy wolni!!!,Estamos livres!! Estamos livres!! Estamos livres!!,,Suntem liberi!! Suntem liberi!! Suntem liberi!!,Мы свободны! Мы свободны! Мы свободны!,,Vi är fria!! Vi är fria!! Vi är fria!!,Özgürüz! Özgürüz! Özgürüz! +Must mine more ore!,TXT_DLG_SCRIPT14_D7580_MUSTM,〃,,,Muset těžit další rudu!,Skal udvinde mere malm!,Muss Erz abbauen.,,Mi elfosu pliajn minaĵojn!,¡Debo picar más mineral!,,Täytyy louhia lisää malmia!,Faut que je trouve plus de minerai!,Még több ércet kell bányászni!,Devo estrarre più minerale!,鉱石がもっと必要なんだ!,광석... 데그닌... 캔다...,Moet meer erts ontginnen!,Må utvinne mer malm!,Musimy wydobyć więcej rudy!,Preciso minerar mais!,,Mai trebuie să minez încă o bucată de minereu.,Нужно добыть больше руды!,,Måste bryta mer malm!,Daha fazla maden çıkarmalıyız! +We're free!! We're free!! We're free!!,TXT_DLG_SCRIPT14_D9096_WEREF,〃,,,Jsme volní! Jsme volní! Jsme volní!,Vi er frie!!! Vi er frie!!! Vi er frie!!,Wir sind frei! Wir sind frei! Wir sind frei!,,Ni estas liberaj!! Liberaj!! Liberaj!!,¡¡Somos libres!! ¡¡Somos libres!! ¡¡Somos libres!!,,Olemme vapaat!! Olemme vapaat!! Olemme vapaat!!,On est libres! Libres! Libres!,Szabadok vagyunk!! Szabadok vagyunk!! Szabadok vagyunk!!,Siamo liberi!! Siamo liberi!! Siamo liberi!!,自由だ!!私達は自由だ!!私達は自由だ!!,살았군요. 이제 저항군 기지로 향하는 일 밖엔 남지 않은 것 같아요.,We zijn vrij!!! We zijn vrij!!! We zijn vrij!!!,Vi er fri!! Vi er frie!! Vi er fri!!,Jesteśmy wolni!!! Jesteśmy wolni!!! Jesteśmy wolni!!!,Estamos livres!! Estamos livres!! Estamos livres!!,,Suntem liberi!! Suntem liberi!! Suntem liberi!!,Мы свободны! Мы свободны! Мы свободны!,,Vi är fria!! Vi är fria!! Vi är fria!!,Özgürüz! Özgürüz! Özgürüz! +Must mine more ore!,TXT_DLG_SCRIPT14_D10612_MUSTM,〃,,,Muset těžit další rudu!,Skal udvinde mere malm!,Muss Erz abbauen.,,Mi elfosu pliajn minaĵojn!,¡Debo picar más mineral!,,Täytyy louhia lisää malmia!,Faut que je trouve plus de minerai!,Még több ércet kell bányászni!,Devo estrarre più minerale!,いつまで採掘しなければならない!,캐고... 캐고... 또 캔다...,Moet meer erts ontginnen!,Må utvinne mer malm!,Musimy wydobyć więcej rudy!,Preciso minerar mais!,,Mai trebuie să minez încă o bucată de minereu.,Нужно добыть больше руды!,,Måste bryta mer malm!,Daha fazla maden çıkarmalıyız! +We're free!! We're free!! We're free!!,TXT_DLG_SCRIPT14_D12128_WEREF,〃,,,Jsme volní! Jsme volní! Jsme volní!,Vi er frie!!! Vi er frie!!! Vi er frie!!,Wir sind frei! Wir sind frei! Wir sind frei!,,Ni estas liberaj!! Liberaj!! Liberaj!!,¡¡Somos libres!! ¡¡Somos libres!! ¡¡Somos libres!!,,Olemme vapaat!! Olemme vapaat!! Olemme vapaat!!,On est libres! Libres! Libres!,Szabadok vagyunk!! Szabadok vagyunk!! Szabadok vagyunk!!,Siamo liberi!! Siamo liberi!! Siamo liberi!!,僕らは自由だ!!僕らは自由だ!!僕らは自由だ!!,살았다! 이제 그 놈들이 죽이기 전에 도망쳐야해요!,We zijn vrij!!! We zijn vrij!!! We zijn vrij!!!,Vi er fri!! Vi er frie!! Vi er frie!!,Jesteśmy wolni!!! Jesteśmy wolni!!! Jesteśmy wolni!!!,Estamos livres!! Estamos livres!! Estamos livres!!,,Suntem liberi!! Suntem liberi!! Suntem liberi!!,Мы свободны! Мы свободны! Мы свободны!,,Vi är fria!! Vi är fria!! Vi är fria!!,Özgürüz! Özgürüz! Özgürüz! +What are you doing here?,TXT_DLG_SCRIPT15_D0_WHATA,MAP15: Red acolytes.,,,Co tady děláte?,Hvad laver du her?,Was machst du hier?,,Kial vi estas ĉi tie?,¿Qué haces aquí?,,Mitä teette täällä?,Qu'est ce que vous faites ici?,Mit csinálsz itt?,Che cosa fai qui?,ここで何をしている?,여기서 뭘 하는거지?,Wat doe je hier?,Hva gjør dere her?,Co ty tu robisz?,O que você está fazendo aqui?,,Ce cauți aici?,По какому делу ты здесь?,,Vad gör du här?,Ne yapıyorsunuz burada? +Routine inspection.,TXT_RPLY0_SCRIPT15_D0_ROUTI,〃,,,Rutinní kontrola.,Rutinemæssig inspektion.,Eine Routineinspektion.,,Rutina inspektado.,Inspección de rutina.,,Rutiinitarkastus.,Inspection de routine.,Rutin ellenőrzés.,Ispezione ordinaria.,見回りだ。,정기적 검사요.,Routine-inspectie.,Rutinemessig inspeksjon.,Rutynowa inspekcja.,Inspeção de rotina.,,Inspecție de rutină.,Плановая проверка.,,Rutininspektion.,Rutin teftiş. +"All right, carry on.",TXT_RYES0_SCRIPT15_D0_ALLRI,〃,,,"Dobře, pokračujte.","Okay, fortsæt.","In Ordnung, mach weiter.",,"Bone, daŭrigu.","Muy bien, continúa.",,"Selvä on, jatkakaa.","D'accord, continuez.","Renben, folytasd csak.","Va bene, vai pure avanti.",わかった、続けろ。,"좋아, 계속해.","Oké, ga door.","Greit, fortsett.","W porządku, kontynuuj.","Muito bem, continue.",,"Bine, mergi mai departe.",Понятно. Продолжай.,,"Okej, fortsätt.","Pekala, devam edin." +"Nothing to report here. Everything is working fine. If anything goes wrong, I'll be sure to report it.",TXT_DLG_SCRIPT15_D1516_NOTHI,MAP15: Red acolytes + Technician at the beginning.,,,"Tady nic k nahlášení není. Všechno funguje dobře. Pokud se něco pokazí, nahlásím to.","Der er intet at rapportere her. Alt fungerer fint. Hvis noget går galt, skal jeg nok rapportere det.","Keine besonderen Vorkommnisse. Alles funktioniert wie es soll. Wenn irgendetwas schief geht, werde ich es sofort melden.",,"Nenio raportinda ĉi tie; ĉio funkcias ĝuste. Se io ajn malsukcesos, mi certe raportos ĝin.","Nada que reportar aquí; todo está funcionando bien. Si algo sale mal, me aseguraré de reportarlo.","Nada que reportar aquí; todo está funcionando bien. Si algo sale mal, me voy a asegurar de reportarlo.","Ei mitään raportoitavaa. Kaikki toimii hyvin. Jo mikään menee vialle, raportoin siitä varmasti.","Rien à signaler ici. Tout fonctionne comme prévu. Si quelque chose tombe en panne, je ferai un rapport.","Nincs semmi bejelentenivaló. Minden prímán működik. Ha esetleg valami meghibásodik, rögtön jelezni fogom.","Nulla da riportare qua. Tutto funziona come dovrebbe. Se qualcosa non dovesse funzionare, lo riporterò subito.","報告することはない。全て順調だ。 +何か問題が起きたら報告する。","보고할 게 전혀 없어. 모든 장치, 시설, 인력 모두 이상 무. 만약 하나라도 문제가 생기면 나에게 알려줘.","Hier valt niets te melden. Alles werkt prima. Als er iets misgaat, zal ik het zeker melden.","Ingenting å rapportere her. Alt fungerer som det skal. Hvis noe går galt, skal jeg rapportere det.","Nie ma o czym mówić. Wszystko działa jak należy. Jeśli coś będzie nie tak, na pewno to zgłoszę.","Não há nada de errado aqui. Tudo está funcionando perfeitamente. Se algo parar de funcionar, pode ter certeza que eu vou avisar.",,"Nimic de raportat aici. Dacă e ceva, cu siguranță că voi da raportul.","Тут не о чём докладывать. Всё работает превосходно. Если что-нибудь пойдёт не так, я обязательно доложу об этом.",,Inget att rapportera här. Allt fungerar bra. Om något går fel ska jag rapportera det.,"Burada rapor edilecek bir şey yok. Her şey yolunda gidiyor. Eğer bir sorun çıkarsa, rapor edeceğimden emin olabilirsiniz." +"Sir, there was a problem earlier, but it was taken care of.",TXT_DLG_SCRIPT15_D3032_SIRTH,MAP15: Technician at the beginning.,,,"Pane, předtím tu byl problém, ale vyřešili jsme jej.","Sir, der var et problem tidligere, men det blev ordnet.","Vor kurzem gab es ein Problem, aber das wurde bereits gelöst.",,"Sinjoro, estis problemo, sed ni jam solvis ĝin.","Señor, ha habido un problema antes, pero ya lo hemos solucionado.","Señor, hubo un problema antes, pero ya lo solucionamos.","Tässä aiemmin oli ongelma, mutta se ratkaistiin.","Monsieur, il y a eu un problème récemment mais nous l'avons corrigé.","Uram, volt korábban egy probléma, de megoldásra került.","Signore, c'era un problema prima, ma è stato risolto.","上官殿、以前より問題があったが、 +もう心配はいらない。",안녕하십니까. 조금 전에 문제가 있었습니다만 경마한 문제였고 지금 해결됐습니다.,"Meneer, er was eerder een probleem, maar het is opgelost.","Sir, det var et problem tidligere, men det ble tatt hånd om.","Sir, wcześniej był problem, ale już się nim zajęto.","Senhor, havia um problema antes, mas já foi resolvido.",,"Domnule, a fost o problemă adineauri, dar s-a rezolvat.","Сэр, тут была одна неполадка, но её уже устранили.",,"Sir, det var ett problem tidigare, men det har tagits om hand.","Efendim, daha önce bir sorun vardı, ama halledildi." +Move along or taste metal.,TXT_DLG_SCRIPT17_D0_MOVEA,MAP17: Bailey (if you don't have Order's key),,,"Jdi dál, nebo okus ocel.",Fortsæt eller smag på metal.,Beweg dich oder spüre meinen Stahl.,,Plue movu vin aŭ gustumu kuglojn.,Esfúmate o come plomo.,,"Jatka matkaasi, tai maista metallia.",Bougez ou préparez-vous à goûter de l'acier.,"Haladj tovább, vagy ízleld meg a kardom.",Sparisci o ti finisce male.,同行か鉄を味わうかだ。,탄창으로 맞고 싶지 않으면 움직여.,Ga verder of proef metaal.,Gå videre eller smak på metall.,Ruszaj się albo skosztuj metalu.,Vá embora ou vai tomar chumbo grosso.,,Mișcă-te sau mănânci metal.,"Прочь, или отведаешь металла.",,Gå vidare eller smaka på metall.,İlerleyin ya da metalin tadına bakın. +I.D. check.,TXT_DLG_SCRIPT17_D1516_IDCHE,〃 (if you have it),,,Doklady.,ID-tjek.,Ausweisüberprüfung.,,Kontrolo de identigilo.,Comprobación de identificación.,,Henkilöllisyystarkastus.,Vérification de carte d'identité.,Igazolvány ellenőrzés.,Verifica d'identità.,I.D.チェックだ。,신분증 확인.,I.D. check.,Legitimasjonskontroll.,Sprawdzenie tożsamości.,Verificação de identidade.,,Verificare card de identitate.,Ваши документы.,,ID-kontroll.,Kimlik kontrolü. +"Here, I'm in a hurry.",TXT_RPLY0_SCRIPT17_D1516_HEREI,〃 (〃),,,"Tady, spěchám.","Her, jeg har travlt.","Hier, ich hab's eilig.",,"Jen, mi hastas.","Toma, que tengo prisa.","Toma, que estoy apurado.","Tässä, minulla on kiire.","Voilà, je suis pressé.","Nesze, nem érek rá.","Ecco qua, vado di fretta.",ほら、急いでるんだ。,여기요. 급하니 빨리 확인해주세요.,Hier heb ik haast.,"Her, jeg har dårlig tid.",Spieszę się.,"Pegue, estou com pressa.",,"Aici, mă grăbesc.",Вот. Я тороплюсь.,,"Här, jag har bråttom.","Al, acelem var." +Stop waving your ID in my face and go in.,TXT_DLG_SCRIPT17_D3032_STOPW,〃 (〃),,,Přestaň mi tu mávat tou kartou a jdi dovnitř.,Hold op med at vifte med dit ID i mit ansigt og gå ind.,Hör auf mit deinem Ausweis vor meinem Gesicht herumzufuchteln und geh hinein.,,Ĉesu skui vian identigilon super mia vizaĝo kaj eniru.,Ya deja de sacudirme la identificación en la cara y entra.,,Lakkaa heiluttelemasta tunnistettasi päin naamaa ja mene sisään.,Arrêtez de l'agiter dans ma figure et passez.,Ne lobogtasd az igazolványodat az arcomba és menj be.,Smettila di sventolarmela in faccia e vai avanti.,目前まで近づけるな、さっさと行け。,얼굴 앞에서 신분증 그만 흔들고 얼른 들어가.,Stop met je ID in mijn gezicht te zwaaien en ga naar binnen.,Slutt å vifte med legitimasjonen og gå inn.,Przestań machać mi przed nosem swoim dowodem i wejdź.,Pare de sacudir a sua identificação e entre logo.,,Nu mai flutura cardul în fața mea și intră.,Прекрати махать своей карточкой перед моим лицом и проходи.,,Sluta vifta med ditt ID-kort i ansiktet på mig och gå in.,Kimliğini yüzüme karşı sallamayı bırak ve içeri gir. +Nothing to see here. Move along.,TXT_DLG_SCRIPT17_D4548_NOTHI,MAP17: Green guards.,,,Nic k vidění. Jdi dál.,Der er intet at se her. Gå videre.,Hier gibt es nichts zu sehen. Geh weiter.,,Nenio vidinda ĉi tie. Plue movu vin.,Nada que ver aquí. Sigue caminando.,,Täällä ei ole mitään nähtävää. Jatkakaa matkaa.,Rien à voir ici. Bougez.,Nincs itt semmi látnivaló. Mozgás tovább.,Non c'è niente da vedere qui. Gira al largo.,何事も無い。進め。,아무 일도 안 일어났다. 어서 움직여.,Hier is niets te zien. Ga verder.,Ingenting å se her. Gå videre.,Nie ma tu nic do oglądania. Ruszaj się.,Nada pra ver aqui. Vá embora.,,Nimic aici. Mișcă.,Тут не на что смотреть. Проваливай.,,Det finns inget att se här. Gå vidare.,Burada görecek bir şey yok. İlerleyin. +"What a healthy specimen. You don't need my help, do you?",TXT_DLG_SCRIPT17_D6064_WHATA,MAP17: Hospital → Quincy,,,"Takový zdravý exemplář! Moji pomoc nepotřebujete, že ne?","Sikke et sundt eksemplar. Du har ikke brug for min hjælp, vel?","Was für ein schönes Exemplar. Du brauchst meine Hilfe nicht, oder?",,"Kia sana specimeno. Vi ne bezonas mian helpon, ĉu?","Que espécimen más saludable. No necesitarás mi ayuda, ¿verdad?",,No siinäpä vasta mallitapaus. Et sattumoisin ole avun tarpeessa?,"Quel magnifique spécimen! Vous n'avez pas besoin de mon aide, si?","Micsoda jó erőben levő példány. Neked nem kell segítség, ugye?","Che esemplare sano. Non hai bisogno del mio aiuto, vero?","なんて活きの良い標本だ。 +手当なんて必要なさそうだな、で何だ?","정말 건강한 표본이군. 아마 넌 내 도움이 필요하지 않을 거야, 그렇지?","Wat een gezond exemplaar. Je hebt mijn hulp niet nodig, of wel?",For et sunt eksemplar. Du trenger vel ikke min hjelp?,"Co za zdrowy okaz. Nie potrzebujesz mojej pomocy, prawda?","Mas que espécime mais saudável. Você não precisa da minha ajuda, precisa?",,"Ce specimen sănătos. Nu ai nevoie de ajutorul meu, nu?","Какой прекрасный образец. Тебе не нужна моя помощь, или нужна?",,"Vilket friskt exemplar. Du behöver inte min hjälp, eller hur?","Ne kadar sağlıklı bir örnek. Yardımıma ihtiyacın yok, değil mi?" +"Well, yes. Macil sent me.",TXT_RPLY0_SCRIPT17_D6064_WELLY,〃,,,Potřebuju. Poslal mě Macil.,"Jo, jo. Macil har sendt mig.","Nun, doch. Macil hat mich geschickt.",,"Nu, jes. Macil venigis min.","Bueno, sí. Macil me ha enviado.","Bueno, sí. Me manda Macil.","Itse asiassa, kyllä. Macil lähetti minut.","Eh bien, si, Macil m'envoie.","Nos, igen. Macil küldött.","Ecco, si. Mi ha mandato Macil.",そうだ。マシルの使者だ。,"뭐, 그렇지. 마실이 날 보냈으니까.","Nou, ja. Macil heeft me gestuurd.",Jo. Macil sendte meg.,No tak. Macil mnie przysłał.,"Bem, sim. Macil me enviou.",,Ba da. Macil m-a trimis.,"Ну, нужна. Я от Мэйсила.",,"Jo, jo. Macil skickade mig.","Evet, var. Beni Macil gönderdi." +"Shhhh... Keep it quiet, unless you want us both killed. Now, what can I do for you?",TXT_DLG_SCRIPT17_D7580_SHHHH,〃,,,"Pššš... Buď potichu, leda že bys nás oba chtěl nechat popravit. Tak, co pro tebe můžu udělat?","Shhhh... Hold det stille, medmindre du vil have os begge dræbt. Hvad kan jeg gøre for dig?","Psst... sei leise, oder willst du uns beide umbringen? Nun, was kann ich für dich tun?",,"Ŝŝ! Ne tiel laŭte se vi ne intencas, ke ni ambaŭ estu mortigitaj. Nu, kion mi faru por vi?","Shhhh... No tan alto, a menos que quieras que nos maten a ambos. Y bueno, ¿qué puedo hacer por ti?",,"Hyss, suuta soukemmalle, ellet halua tapattaa meitä molempia. No niin, miten voin auttaa?","Silence! Baissez de ton, sauf si vous voulez que l'on se fasse descendre tous le deux.. Que puis-je faire pour vous?","Shhhh...csak csendben, különben mindkettőnket megöletsz. Akkor, miben is segíthetek?","Shhhh... Fai piano, a meno che non vuoi farci ammazzare tutti e due. Ora, che posso fare per te?","シーッ...静かに、 +殺されるかもしれないんだぞ。それで何か用か?","쉿... 죽기 싫으면 조용히 해. 자, 내가 뭘 도와줄까?","Shhhhhh.... Hou het stil, tenzij je wilt dat we allebei gedood worden. Wat kan ik nu voor u doen?","Vær stille, hvis du ikke vil at vi begge skal bli drept. Hva kan jeg gjøre for deg?","Cicho, chyba że chcesz nas obu zabić. Co mogę dla ciebie zrobić?","Shhhh... Fale baixo, a não ser que queira que nos matem. Agora, como posso te ajudar?",,"Șhhhh... Mai încet, dacă nu vrei să murim amândoi. Acum, ce pot face pentru tine?","Тсс... Тише, если не хочешь, чтобы нас обоих убили. Итак, чем я могу тебе помочь?",,"Shhhh... Håll tyst, om du inte vill att vi båda ska dödas. Vad kan jag göra för dig?","İkimizin de ölmesini istemiyorsan sessiz ol. Şimdi, senin için ne yapabilirim?" +Tell me how to find the Bishop.,TXT_RPLY0_SCRIPT17_D7580_TELLM,〃,,,"Řekni mi, jak najít Biskupa.","Fortæl mig, hvordan jeg finder biskoppen.","Sage mir, wie ich den Bischof finde.",,Diru kiel mi trovu la Episkopon.,Dime como encontrar al Obispo.,,"Kerro, miten löydän Piispan.",Où puis-je trouver l'évêque?,"Áruld el, hol találom meg a Püspököt.",Dimmi dove trovare il Vescovo.,ビショップは何処か聞きたい。,비숍을 어떻게 찾아야 하는지 알려줘.,Vertel me hoe ik de bisschop kan vinden.,Fortell meg hvordan jeg finner biskopen.,Powiedz mi jak znaleźć biskupa.,Diga onde eu encontro o Bispo.,,Spune-mi cum găsesc Episcopul.,"Скажи, как мне найти Епископа.",,Berätta hur jag hittar biskopen.,Bana Piskopos'u nasıl bulacağımı söyle. +"Ohhh, I knew you would ask me for that. Look behind you. That's the entrance to the Bishop's citadel. It's guarded by a force field that is only shut off for official visitors, not you.",TXT_DLG_SCRIPT17_D9096_OHHHI,〃,,,"Ohó, já věděl, že se mě na tohle zeptáš. Podívej se za sebe. To je vchod do Biskupovy citadely. Je střežená silovým polem, které se vypíná pouze kvůli oficiálním návštěvám, ne tobě.","Jeg vidste, du ville spørge mig om det. Se bag dig. Det er indgangen til biskoppens citadel. Den er bevogtet af et kraftfelt, der kun er lukket for officielle besøgende, ikke dig.","Oh, hab ich's doch geahnt, dass du mich das fragen würdest. Schau mal hinter dich. Dort ist der Eingang zu der Festung des Bischofs. Er ist durch ein Kraftfeld geschützt, welches sich nur für offizielle Besucher abschaltet und nicht für dich.",,"Ho, mi sciis, ke vi estis petonta tion. Rigardu malantaŭen tra la fenestro: tie estas la enirejo al la citadelo de la Episkopo. Ĝin baras fortokampo malŝaltinda nur por oficialaj vizitantoj, ne vi, ekzemple.","Ah, imaginaba que me ibas a pedir eso. Mira detrás de ti por la ventana: ahí está la entrada a la ciudadela del Obispo. La bloquea un campo de fuerza que solo se apaga para visitas oficiales, no tú, por ejemplo.",,"Oo, arvasin, että kysyisit sitä minulta. Katso taaksesi. Siellä on sisäänkäynti Piispan linnoitukseen. Sitä turvaa voimakenttä, joka kytketään pois päältä ainoastaan virallisille vieraille, ei sinulle.","Ohh, je savais que vous me demanderiez cela. Regardez derrière vous. C'est l'entrée de la citadelle de l'évêque. Elle est gardée par un champ de force qui ne s'ouvre que pour les visites officielles, pas vous.","Ohhh, tudtam, hogy ezt fogod kérdezni. Nézz csak magad mögé. Ez a püspök fellegvárához a bejárat. Egy erőpajzs védi, és csak hivatalos látogatóknak nyitják ki, aminek valljuk be Te nem igazán felelsz meg.","Ohhh, sapevo che me l'avresti chiesto. Guarda dietro di te. Quello è l'ingresso per la cittadella del Vescovo. È protetta da un campo di forza che viene disattivato solo per le visite ufficiali, quindi non per la tua.","おおぅ、そういう事だろうと思った。 後ろを見ろ。そこがビショップの大聖堂だ。 しかし要人以外は入れないよう フォースフィールドが張ってある、 -君には通れないな。","호오오, 난 네가 그걸 물어볼 줄 알았어. 뒤를 돌아봐. 저건 비숍의 성채로 향하는 입구야. 방어막으로 덮여있는데 저걸 끌 수 있는 건 허가된 방문자뿐이야. 네가 아니라.","Ohhhh, ik wist dat je me dat zou vragen. Kijk achter je. Dat is de ingang van de bisschopsburcht. Het wordt bewaakt door een krachtveld dat alleen afgesloten is voor officiële bezoekers, niet voor jou.",,"Ahhh, eu sabia que você me perguntaria isso. Olhe atrás de você. Essa é a entrada para a cidadela do Bispo. Ela é protegida por um campo de força que é desligada somente para visitantes oficiais, para você não.",,,"А-а-а, я знал, что ты спросишь об этом. Оглянись. Это вход в цитадель Епископа. Он защищён силовым полем, которое отключается только для официальных посетителей, не для тебя.", -I must kill the Bishop.,TXT_RPLY0_SCRIPT17_D9096_IMUST,,,,Musím zabít Biskupa.,Ich muss den Bischof töten.,,,Debo matar al Obispo.,,,Je dois tuer l'évêque.,,,ビショップを殺さなければならないんだ。,난 비숍을 죽여야만 해.,Ik moet de bisschop vermoorden.,,Preciso matar o Bispo.,,,Я должен убить Епископа., -"Oh, sure you do. First, fight your way into the security complex and use the teleporter. And this might be more to your liking, destroy the computer in central administration. No computer, no force field.",TXT_DLG_SCRIPT17_D10612_OHSUR,,,,"No jistě že! Nejprve se probojuj do bezpečnostního komplexu a použij teleportér. A tohle by se ti mohlo více zamlouvat: Znič počítač v ústřední administraci. Žádný počítač, žádné pole.","Oh, aber klar doch. Erst kämpf dich bis zum Sicherheitskomplex durch und benutze den Teleporter. Und er nächste Schritt dürfte dir gefallen: zerstöre den Computer in der Hauptverwaltung. Kein Computer, kein Kraftfeld.",,,"Oh, seguro que sí. Primero, lucha camino adentro del complejo de seguridad y usa el teletransporte. Y esto puede que sea de tu agrado, destruye la computadora en administración central. Sin computadora, no hay campo de fuerza.","Oh, seguro que sí. Primero, pelea para entrar al complejo de seguridad y usa el teletransporte. Y esto puede que sea de tu agrado, destruye la computadora en administración central. Sin computadora, no hay campo de fuerza.",,"Oh, oui, bien sûr que vous devez. D'abord il faudra forcer le chemin vers le complexe de sécurité, puis utiliser le téléporteur. Ce qui vous plaira aussi, détruisez l'ordinateur dans le centre d'administration. Pas d'ordinateur, pas de champ de force.",,,"ああ、だろうな。先にまず複合警備施設を +君には通れないな。","호오오, 난 네가 그걸 물어볼 줄 알았어. 뒤를 돌아봐. 저건 비숍의 성채로 향하는 입구야. 방어막으로 덮여있는데 저걸 끌 수 있는 건 허가된 방문자뿐이야. 네가 아니라.","Ohhhh, ik wist dat je me dat zou vragen. Kijk achter je. Dat is de ingang van de bisschopsburcht. Het wordt bewaakt door een krachtveld dat alleen afgesloten is voor officiële bezoekers, niet voor jou.","Jeg visste du ville spørre om det. Se bak deg. Det er inngangen til biskopens citadell. Den er bevoktet av et kraftfelt som bare er stengt for offisielle besøkende, ikke deg.","Ohhh, wiedziałem, że mnie o to poprosisz. Spójrz za siebie. To wejście do cytadeli biskupa. Jest strzeżone przez pole siłowe, które jest wyłączane tylko dla oficjalnych gości, nie dla ciebie.","Ahhh, eu sabia que você me perguntaria isso. Olhe atrás de você. Essa é a entrada para a cidadela do Bispo. Ela é protegida por um campo de força que é desligada somente para visitantes oficiais, para você não.",,"Ohhh, știam eu că asta urma să mă întrebi. Aia e intrarea către citadela Episcopului. E apărată de un scut care se oprește numai pentru vizitatorii autorizați, nu pentru tine.","А-а-а, я знал, что ты спросишь об этом. Оглянись: это вход в цитадель Епископа. Он защищён силовым полем, которое отключается только для официальных посетителей, не для тебя.",,"Jag visste att du skulle be mig om det. Titta bakom dig. Det är ingången till biskopens citadell. Den är bevakad av ett kraftfält som bara stängs av för officiella besökare, inte för dig.","Benden bunu isteyeceğini biliyordum. Arkana bak. Bu Piskopos'un kalesinin girişi. Sadece resmi ziyaretçiler için kapatılan bir güç alanı tarafından korunuyor, sen değil." +I must kill the Bishop.,TXT_RPLY0_SCRIPT17_D9096_IMUST,〃,,,Musím zabít Biskupa.,Jeg må dræbe biskoppen.,Ich muss den Bischof töten.,,Mi devas mortigi la Episkopon.,Tengo que matar al Obispo.,,Minun on tapettava Piispa.,Je dois tuer l'évêque.,Meg kell ölnöm a Püspököt.,Devo uccidere il Vescovo.,ビショップを殺さなければならないんだ。,난 비숍을 죽여야만 해.,Ik moet de bisschop vermoorden.,Jeg må drepe biskopen.,Muszę zabić biskupa.,Preciso matar o Bispo.,,Trebuie să-l omor pe Episcop.,Я должен убить Епископа.,,Jag måste döda biskopen.,Piskoposu öldürmeliyim. +"Oh, sure you do. First, fight your way into the security complex and use the teleporter. And this might be more to your liking, destroy the computer in central administration. No computer, no force field.",TXT_DLG_SCRIPT17_D10612_OHSUR,〃,,,"No jistě že! Nejprve se probojuj do bezpečnostního komplexu a použij teleportér. A tohle by se ti mohlo více zamlouvat: Znič počítač v ústřední administraci. Žádný počítač, žádné pole.","Selvfølgelig skal du det. Først skal du kæmpe dig ind i sikkerhedskomplekset og bruge teleporteren. Og dette er måske mere efter din smag, ødelæg computeren i centraladministrationen. Ingen computer, intet kraftfelt.","Oh, aber klar doch. Erst kämpf dich bis zum Sicherheitskomplex durch und benutze den Teleporter. Und er nächste Schritt dürfte dir gefallen: zerstöre den Computer in der Hauptverwaltung. Kein Computer, kein Kraftfeld.",,"Ho, vi certe devas. Vi unue trabatu al vi la vojon en la sekurkomplekso kaj uzu la teleportilon. Vi eble pli ŝatos la duan parton: detruu la komputilon en la centra administrejo. Sen komputilo ne estas fortokampo.","Ah, seguro que sí. Primero ábrete camino por el complejo de seguridad y usa el teletransportador. Lo segundo puede que sea más de tu agrado: destruye el ordenador en la oficina de la administración central. Sin ordenador no hay campo de fuerza.","Ah, seguro que sí. Primero ábrete camino por el complejo de seguridad y usa el teletransportador. Lo segundo puede que sea más de tu agrado: destruye la computadora en la oficina de la administración central. Sin computadora no hay campo de fuerza.","Niinpä tietysti. Ensiksi taistele tiesi turvallisuuskeskukseen ja käytä kaukosiirrintä. Ja tämä saattaa olla ehkä enemmän sinun mieleesi: tuhoa tietokone keskushallinnossa. Ei tietokonetta, ei voimakenttää.","Oh, oui, bien sûr que vous devez. D'abord il faudra forcer le chemin vers le complexe de sécurité, puis utiliser le téléporteur. Ce qui vous plaira aussi, détruisez l'ordinateur dans le centre d'administration. Pas d'ordinateur, pas de champ de force.","Oh, persze persze. Előszöris, küzdd magad át a biztonsági komplexumig és használd a teleportert. Aztán - ami talán jobban fog tetszeni - tedd tönkre a számítógépet a központi adminisztráción. Ha nincs számítógép, nincs erőpajzs.","Oh, come no. Per cominciare, devi andare nel complesso di sicurezza e usare il teletrasporto là. E questo penso ti piacerà, devi distruggere il computer nell'amministrazione centrale. Niente computer, niente campo di forza.","ああ、だろうな。先にまず複合警備施設を 制圧してそこにあるテレポーターを使え。 君に合った方法だと思うが、テレポーター先の 中央管理部にあるコンピューターを潰せ。 コンピューターが無けれは、フォースも無しだ。 ","아, 그렇겠지. 먼저 보안단지에 들어가서 텔레포터를 이용해. 그리고 어쩌면 이건 네 취향일지도 모르겠군. 중앙 관리소에서 컴퓨터를 파괴해. 컴퓨터도 없애고, 방어막도 없애버리라고. - \cy최근 상황을 보건대, 잠입 작전은 힘들 것 같아.","Oh, zeker weten. Vecht je eerst een weg naar het veiligheidscomplex en gebruik de teleporter. En dit kan meer naar uw zin zijn, vernietig de computer in de centrale administratie. Geen computer, geen krachtveld.",,"Ah, mas é claro que precisa. Primeiro, lute até o complexo de segurança e use o teletransportador. E acho que você vai gostar disto: destrua o computador na administração central. Sem computador, sem campo de força.",,,"О, не сомневаюсь. Для начала, проберись в охранный комплекс и используй телепорт. И, что тебе должно больше понравиться, уничтожь компьютер в центральной администрации. Нет компьютера — нет силового поля.", -"Great, that sounds easy.",TXT_RPLY0_SCRIPT17_D10612_GREAT,,,,"Super, to zní snadně.","Großartig, das klingt doch einfach.",,,"Genial, suena fácil.",,,"Bien, ça à l'air facile.",,,そりゃいい、簡単そうだな。,"좋아, 쉬운 일인 것 같군.","Geweldig, dat klinkt gemakkelijk.",,Ótimo. Isso parece fácil.,,,"Здорово. Легче сказать, чем сделать.", -"There's an advantage to destroying the computer, that's where the plans to the tower are kept. Can you say, five finger discount? Heh heh!",TXT_DLG_SCRIPT17_D12128_THERE,,,,Zničení toho počítače má výhodu: Na tom samém místě jsou uschovány plány věže. Co říkáš na takovou koupi za pět prstů? Haha!,"Es hätte sein Gutes, den Computer zu zerstören, denn dort sind auch die Pläne für den Turm. Kannst du sagen: Mitgehen lassen? Hehe!",,,"Hay una ventaja al destruir la computadora, ahí se guardan los planos de la torre. Puedes decir... ¿descuento a cinco dedos? ¡je je!",,,Ce serait avantageux de détruire l'ordinateur car c'est là qu'ils gardent les plans de la tour. C'est facile d'avoir ça gratuitement quand on peut juste les prendre comme ça!,,,"コンピューターを潰す利点はな、 + \cy최근 상황을 보건대, 잠입 작전은 힘들 것 같아.","Oh, zeker weten. Vecht je eerst een weg naar het veiligheidscomplex en gebruik de teleporter. En dit kan meer naar uw zin zijn, vernietig de computer in de centrale administratie. Geen computer, geen krachtveld.","Klart du må. Først må du kjempe deg inn i sikkerhetskomplekset og bruke teleporteren. Og dette er kanskje mer etter din smak. Ødelegg datamaskinen i sentraladministrasjonen. Ingen datamaskin, intet kraftfelt.","Oczywiście, że tak. Najpierw pokonaj drogę do kompleksu bezpieczeństwa i użyj teleportera. A to może bardziej ci się spodoba, zniszcz komputer w centralnej administracji. Nie ma komputera, nie ma pola siłowego.","Ah, mas é claro que precisa. Primeiro, lute até o complexo de segurança e use o teletransportador. E acho que você vai gostar disto: destrua o computador na administração central. Sem computador, sem campo de força.",,"Oh, normal. Mai întâi, trebuie să te zbați să ajungi în complexul de securitate și să folosești teleportorul. Și asta s-ar putea să îți placă mai mult, distruge calculatorul din camera de administrare centrală. Niciun calculator, niciun câmp de forță.","О, не сомневаюсь. Для начала проберись в охранный комплекс и используй телепорт. И, что тебе должно больше понравиться, уничтожь компьютер в центральной администрации. Нет компьютера — нет силового поля.",,"Javisst, det måste du. Kämpa dig först in i säkerhetskomplexet och använd teleportern. Och det här kanske är mer till din smak, förstör datorn i centralförvaltningen. Ingen dator, inget kraftfält.","Tabii ki öldürmelisin. İlk olarak, güvenlik kompleksine girmek için savaş ve ışınlayıcıyı kullan. Ve bu daha çok hoşuna gidebilir, merkezi yönetimdeki bilgisayarı yok et. Bilgisayar yoksa, güç alanı da yok." +"Great, that sounds easy.",TXT_RPLY0_SCRIPT17_D10612_GREAT,〃,,,"Super, to zní snadně.","Fint, det lyder nemt.","Großartig, das klingt doch einfach.",,"Bonege, tio ŝajnas facila.","Genial, suena fácil.",,"Loistavaa, kuulostaa helpolta.","Bien, ça à l'air facile.","Remek, ez könnyűnek hangzik.","Ottimo, sembra facile.",そりゃいい、簡単そうだな。,"좋아, 쉬운 일인 것 같군.","Geweldig, dat klinkt gemakkelijk.","Flott, det høres enkelt ut.","Wspaniale, to brzmi łatwo.",Ótimo. Isso parece fácil.,,"Grozav, sună simplu.","Здорово, звучит легко.",,"Bra, det låter enkelt.","Harika, kulağa kolay geliyor." +"There's an advantage to destroying the computer, that's where the plans to the tower are kept. Can you say, five finger discount? Heh heh!",TXT_DLG_SCRIPT17_D12128_THERE,"〃 +(five-finger discount = theft)",,,Zničení toho počítače má výhodu: Na tom samém místě jsou uschovány plány věže. Co říkáš na takovou koupi za pět prstů? Haha!,"Der er en fordel ved at ødelægge computeren, det er der, hvor planerne til tårnet opbevares. Kan du sige, fem fingre rabat? Heh heh!","Es hätte sein Gutes, den Computer zu zerstören, denn dort sind auch die Pläne für den Turm. Kannst du sagen: Mitgehen lassen? Hehe!",,"Detrui la komputilon havas profiton: en ĝi estas konservitaj la planoj de la turo. Estus bedaŭrinde, ke ili malaperus... Ha ha!","Hay una ventaja al destruir el ordenador: ahí se guardan los planos de la torre. Suena ideal para gente con las manos largas... ¡Je, je!","Hay una ventaja al destruir la computadora: ahí se guardan los planos de la torre. Suena ideal para gente con las manos largas... ¡Je, je!","Tietokoneen tuhoamisessa on etunsa; siinä pidetään tornin piirustuksia. Sanottaisiinko, kaupanpäällisinä? Hehheh!",Ce serait avantageux de détruire l'ordinateur car c'est là qu'ils gardent les plans de la tour. C'est facile d'avoir ça gratuitement quand on peut juste les prendre comme ça!,"Van amúgy egy előnye a számítógép szobának, ott tartják ugyanis a torony terveit ott tárolják. Mi lenne mondjuk ha véletlen magaddal hoznád őket? heh heh!",Sarebbe vantaggioso distruggere il computer perché è lì che tengono i piani per la torre. È facile ottenerli gratuitamente quando puoi prenderli in questo modo! Heh heh!,"コンピューターを潰す利点はな、 奴等の塔へ送られる情報もそれに保管されている。 -それを万引き、とも言えるな?へヘッ!","컴퓨터를 파괴할 승산이 있을거야, 성채로 향하는 계획서가 있는 곳이니까. 물건 좀 빼돌려 본 적 있나? 헤헷!","Er is een voordeel aan het vernietigen van de computer, dat is waar de plannen om de toren te vernietigen worden bewaard. Kunt je zeggen, vijf vingers korting? Heh heh heh!",,"Há uma vantagem em destruir o computador. É nele onde ficam os planos da torre. É pegar e levar, hehehe!",,,"В уничтожении компьютера есть ещё один плюс: планы башни хранятся там. Можно сказать, скидка на все сто? Хе-хе!", -Anything else?,TXT_RPLY0_SCRIPT17_D12128_ANYTH,,,,Ještě něco dalšího?,Noch etwas?,,,¿Algo más?,,,Quoi d'autre?,,,他にあるか?,뭐 다른건 없나?,Nog iets anders?,,Mais alguma coisa?,,,Что-нибудь ещё?, -"Oh well, word has it that the bailey's warehouse received a shipment of maulers, that's the weapon that vaporizes.",TXT_DLG_SCRIPT17_D13644_OHWEL,,,,"No, špitá se, že skladiště v opevnění obdrželo zásilku trhačů. To je ta zbraň, která vypařuje.","Nun, man sagt, dass im Lagerhaus eine Ladung Vernichter abgeliefert wurde, die Waffe die verdampft.",,,"Oh bueno, se dice que el almacén de la muralla ha recibido un envío de trituradores, es el arma que vaporiza.",,,Oh. La rumeur court que le dépôt du mur d'enceinte a reçu une cargaison de broyeurs. C'est l'arme qui vaporise les gens.,,,"そうだな、中庭の倉庫にマウラーが納品されたと +それを万引き、とも言えるな?へヘッ!","컴퓨터를 파괴할 승산이 있을거야, 성채로 향하는 계획서가 있는 곳이니까. 물건 좀 빼돌려 본 적 있나? 헤헷!","Er is een voordeel aan het vernietigen van de computer, dat is waar de plannen om de toren te vernietigen worden bewaard. Kunt je zeggen, vijf vingers korting? Heh heh heh!","Det er en fordel med å ødelegge datamaskinen, det er der planene til tårnet er oppbevart. Kan du si, fem-finger-rabatt? Heh heh!","Jest jeszcze jedna zaleta zniszczenia komputera, to tam trzymane są plany wieży. Czy można powiedzieć, zniżka na pięć palców? Heh heh!","Há uma vantagem em destruir o computador. É nele onde ficam os planos da torre. É pegar e levar, hehehe!",,"Există un avantaj în distrugerea calculatorului, acolo sunt ținute schemele turnului. Poți spune, reducere la cinci degete? Ha ha!","В уничтожении компьютера есть ещё один плюс: планы башни хранятся там. Можно сказать, скидка на все сто? Хе-хе!",,"Det finns en fördel med att förstöra datorn, det är där ritningarna till tornet förvaras. Kan du säga femfingerrabatt? Heh heh!","Bilgisayarı yok etmenin bir avantajı var, kulenin planları orada tutuluyor. Beş parmak indirimi diyebilir misin? Heh heh!" +Anything else?,TXT_RPLY0_SCRIPT17_D12128_ANYTH,〃,,,Ještě něco dalšího?,Er der andet?,Noch etwas?,,Ĉu io alia?,¿Algo más?,,Onko jotain muuta?,Quoi d'autre?,Valami más még?,C'è dell'altro?,他にあるか?,뭐 다른건 없나?,Nog iets anders?,Noe annet?,Co jeszcze?,Mais alguma coisa?,,Altceva?,Что-нибудь ещё?,,Något annat?,Başka bir şey var mı? +"Oh well, word has it that the bailey's warehouse received a shipment of maulers, that's the weapon that vaporizes.",TXT_DLG_SCRIPT17_D13644_OHWEL,〃,,,"No, špitá se, že skladiště v opevnění obdrželo zásilku trhačů. To je ta zbraň, která vypařuje.","Nå ja, det siges, at Baileys lager har modtaget en sending maulers, det er det våben, der fordamper.","Nun, man sagt, dass im Lagerhaus eine Ladung Vernichter abgeliefert wurde, die Waffe die verdampft.",,"Nu, oni diras, ke la ĉi-loka magazeno ricevis mendon de polvigiloj, neniigaj armiloj.","Bueno, se dice que el almacén de por aquí ha recibido un envío de trituradores, que son unas armas que pulverizan.","Bueno, se dice que el almacén de por aquí recibió un envío de trituradores, que son unas armas que pulverizan.","No, tarina kertoo, että linnanpihan varastoon on saapunut erä moukareita; sitä asetta, joka haihduttaa.",Oh. La rumeur court que le dépôt du mur d'enceinte a reçu une cargaison de broyeurs. C'est l'arme qui vaporise les gens.,"Hát, az a hír járja, hogy érkezett pár közelharci fegyver a várfalnál levő raktárba. Ez az a fegyver ami rögtön elporlaszt.","Oh beh, ho sentito dire che il magazzino del bastione ha appena ricevuto un carico di Mauler, è l'arma che vaporizza.","そうだな、中庭の倉庫にマウラーが納品されたと 聞いた。その威力は相手を消滅させられる程だと。","음, 듣자 하니 성안 쪽 격납고에 마울러가 입고되었다더군. 뭐든지 날려버리는 무기 말이야. - \cy흠. 이유 없이 그런 소문이 났을 리는 없을 테고... 나도 그 무기 하나만 가져다줘.","Nou ja, er wordt gezegd dat het magazijn van de bailey een zending maulers heeft ontvangen, dat is het wapen dat verdampt.",,"Bem, dizem que o depósito recebeu um envio de desintegradores. Aquela arma que...desintegra.",,,"Скажем так: есть слух, что склад крепости получил партию Истязателей — оружия, которое «испепеляет».", -"Is that it, now?",TXT_RPLY0_SCRIPT17_D13644_ISTHA,,,,Je to už všechno?,War es das jetzt?,,,"Con que eso es, ¿eh?",,,Vraiment?,,,それはまだあるんだな?,이게 전부지?,"Is dat het, nu?",,Só isso?,,,Теперь всё?, -"Don't you know the meaning of the words ""get lost""?",TXT_DLG_SCRIPT17_D15160_DONTY,,,,Neznáš význam slova „zmizni“?,Sagen dir die Worte „Verzieh dich“ etwas?,,,¿No sabes lo que significa la palabra Piérdete?,,,Vous ne connaîssez pas le sens du mot: « Dégage?»,,,次の話はバレる前に'去れ'か?,"자네, “꺼져.”가 무슨 뜻인지는 알지?","Weet je niet wat de betekenis is van de woorden ""verdwalen""?",,"Você não sabe o que significa a expressão ""se manda""?",,,Ты не знаешь значения слова «исчезни»?, -Talk to Quincy first. I'm not allowed to help anyone unless he says it's ok.,TXT_DLG_SCRIPT17_D16676_TALKT,,,,Promluv si nejprve s Quincym. Já nemůžu nikomu pomáhat dokud to nepovolí.,"Rede erst mit Quincy. Ich darf mit niemanden reden, solange er nicht sein OK gegeben hat.",,,Habla con Quincy primero. No se me permite ayudar a nacie a menos que lo diga.,,,Parlez à Quincy d'abord. Je ne suis pas autorisé à aider qui que ce soit sans son autorisation.,,,"先にクインシーと話を。彼から許可を -得られない限りお助けすることは出来ません。",퀸시에게 먼저 물어보세요. 전 그가 괜찮다 하지 않는다면 아무것도 도울 수 없습니다.,"Praat eerst met Quincy. Ik mag niemand helpen, tenzij hij zegt dat het goed is.",,Fale com o Quincy primeiro. Não posso ajudar ninguém enquanto ele não autorizar.,,,"Сперва поговори с Куинси. Мне не позволено помогать кому-либо, пока он не разрешит.", -How how can I help you today?,TXT_DLG_SCRIPT17_D18192_HOWHO,,,,Jak ti mohu dnes pomoci?,Wie kann ich dir heute helfen?,,,¿Cómo puedo ayudarte hoy?,,,Comment puis-je vous aider aujourd'hui?,,,本日は何かお困りで?,오늘은 어떻게 도와드릴까요?,Hoe kan ik je vandaag helpen?,,Como posso ajudá-lo hoje?,,,Чем я могу помочь тебе сегодня?, -Med patch,TXT_RPLY0_SCRIPT17_D18192_MEDPA,,,,Obvazy,Medizinische Bandage,,,Parche médico.,,,Pansement.,,,医薬パッチ,의료 붕대,Med-patch,,Compressa médica,,,Бинтами, -Here's your patch.,TXT_RYES0_SCRIPT17_D18192_HERES,,,,Tady jsou.,Hier ist deine Bandage.,,,Aquí tienes tu parche.,,,Voilà votre pansement.,,,これをどうぞ。,"의료 붕대 하나, 여기 있습니다.",Hier is je patch.,,Aqui está sua compressa.,,,Вот твой набор бинтов., -That is 15 gold my friend.,TXT_RNO0_SCRIPT17_D18192_THATI,,,,"To je patnáct zlatých, příteli.","Das macht 15 Gold, mein Freund.",,,"Son 15 de oro, amigo mío.",,,"15 pièces pour ça, mon ami.",,,15 ゴールド必要です。,"그건 15 골드입니다, 친구.","Dat is 15 goud, mijn vriend.",,"Custa 15 moedas de ouro, meu amigo.",,,"Они стоят 15 золотых, друг.", -Medical kit,TXT_RPLY1_SCRIPT17_D18192_MEDIC,,,,Lékárničku,Verbandskasten,,,Kit médico,,,Kit médical.,,,医療用キット,구급 키트,Medische kit,,Kit médico,,,Аптечкой, -Here's your medical kit.,TXT_RYES1_SCRIPT17_D18192_HERES,,,,Tady je.,Hier ist dein Verbandskasten,,,Aquí tienes tu kit médico.,,,Voilà votre kit médical.,,,こちらが 医療用キットです。,구급 키트입니다. 잘 쓰시길.,Hier is je medische uitrusting.,,Aqui está o seu kit médico,,,Вот твоя аптечка., -You're a bit low on funds for that.,TXT_RNO1_SCRIPT17_D18192_YOURE,,,,Tu si nemůžeš dovolit.,Du hast zu wenig Geld dafür.,,,Estás un poco bajo de efectivo para eso.,,,Vous manquez d'argent pour ça.,,,その為の資金が少し足りません。,그거 사기엔 자금이 부족한 듯.,Je hebt daar een beetje weinig geld voor.,,Você está um pouco mal de dinheiro pra isso.,,,Тебе на это не хватает средств., -Field surgery kit,TXT_RPLY2_SCRIPT17_D18192_FIELD,,,,Chirurgickou soupravu,Erste-Hilfe-Kasten,,,Kit quirúrgico,,,Kit de chirurgie.,,,手術キット,수술 키트.,Veld chirurgie kit,,Kit de cirurgia,,,Медкомплектом, -"One field surgery kit, done.",TXT_RYES2_SCRIPT17_D18192_ONEFI,,,,"Jedna souprava, zde.","Eine Erste-Hilfe-Kasten, kommt sofort.",,,"Un kit quirúrgico, hecho.",,,"Un kit de chirurgie, voilà.",,,野外用手術キット一丁。,수술 키트 하나 여기있습니다.,"Eén veldoperatiekit, klaar.",,Um kit de cirurgia saindo,,,Один медкомплект. Держи., -Come back when you have money!,TXT_RNO2_SCRIPT17_D18192_COMEB,,,,"Vrať se, až budeš mít peníze!","Komm wieder, wenn du etwas Geld hast.",,,¡Vuelve cuando tengas dinero!,,,Revenez quand vous avez des sous!,,,余裕がある時にまたどうぞ!,돈이 좀 있을 때 돌아와요!,Kom terug als je geld hebt!,,Volte quando tiver dinheiro!,,,Возвращайся с деньгами!, -What is it?,TXT_DLG_SCRIPT18_D0_WHATI,,,,Co je?,Was gibt es?,,,¿Qué pasa?,,,Vous voulez quoi?,,,何事だ?,무슨 일이냐?,Wat is het?,,O que foi?,,,Что тебе нужно?, -Just looking around.,TXT_RPLY0_SCRIPT18_D0_JUSTL,,,,Jen se poohlížím.,Ich schaue mich bloß um.,,,Solo estoy mirando.,,,Je fais juste un tour.,,,見周りしている。,그냥 둘러보는 중이었습니다.,Gewoon rondkijken.,,Só dando uma olhada.,,,Просто осматриваюсь., -Just keep out of the way.,TXT_RYES0_SCRIPT18_D0_JUSTK,,,,Prostě se drž z cesty.,Sei einfach niemandem im Weg.,,,Mantente fuera de mi camino.,,,Restez hors du chemin.,,,この先は立入禁止だ。,그럼 방해하지마.,Blijf gewoon uit de weg.,,Apenas fique fora do caminho.,,,Просто не путайся под ногами., -The Templars will be here soon to pick up their new maulers. If you get in their way you're a dead man.,TXT_DLG_SCRIPT18_D1516_THETE,,,,"Templáři tu brzy budou vyzvednou si své nové trhače. Jestli se jim připleteš pod nohy, jsi mrtvý.","Die Templer werden bald hier sein, um ihre neuen Vernichter abzuholen. Wenn du ihnen im Weg bist, dann bist du ein toter Mann.",,,Los templarios estarán aquí pronto para recoger sus nuevos trituradores. Si te interpones en su camino eres hombre muerto.,,,"Les templiers vont venier chercher les nouveaux broyeurs. Si vous les gênez, vous êtes mort.",,,"新しいマウラーズを得たテンプル騎士団が + \cy흠. 이유 없이 그런 소문이 났을 리는 없을 테고... 나도 그 무기 하나만 가져다줘.","Nou ja, er wordt gezegd dat het magazijn van de bailey een zending maulers heeft ontvangen, dat is het wapen dat verdampt.",Ryktene sier at Borggårdens lager har fått en sending maulere. Det er våpenet som fordamper.,"Podobno do magazynu Bailey'a dotarła dostawa maulerów, czyli broni, która paruje.","Bem, dizem que o depósito recebeu um envio de desintegradores. Aquela arma que...desintegra.",,"Păi, vorba spune că depozitul din curtea interioară a primit un pachet de schiloditoare, asta e arma care vapozirează.","Скажем так: есть слух, что склад крепости получил партию Истязателей: оружия, которое «испепеляет».",,"Nåja, ryktet säger att Baileys lager har fått en leverans av maulers, det är vapnet som förångar.","Bailey'nin deposuna parçalayıcı sevkiyatı yapıldığı söyleniyor, buharlaştıran bir silah." +"Is that it, now?",TXT_RPLY0_SCRIPT17_D13644_ISTHA,〃,,,Je to už všechno?,Er det det nu?,War es das jetzt?,,"Temas pri tio, ĉu?","Conque eso es, ¿eh?",,Ja onko siinä nyt kaikki?,Vraiment?,Mi van már megint?,Tutto qui?,それはまだあるんだな?,이게 전부지?,"Is dat het, nu?",Er det alt?,"To wszystko, teraz?",Só isso?,,"Asta e, deci?",Теперь всё?,,Är det allt?,Bu kadar mı yani? +"Don't you know the meaning of the words ""get lost""?",TXT_DLG_SCRIPT17_D15160_DONTY,〃,,,Neznáš význam slova „zmizni“?,"Kender du ikke betydningen af ordene ""forsvind""?",Sagen dir die Worte „Verzieh dich“ etwas?,,Ĉu vi ne scias la signifon de «malaperu»?,¿No sabes lo que significa la palabra «esfúmate»?,,"Etkö tunne sanojen ""ala laputtaa"" merkitystä?",Vous ne connaîssez pas le sens du mot: « Dégage?»,"Melyik részét nem érted a ""húzz el""-nek?","Non conosci il significato delle parole, ""ora di andare""?",次の話はバレる前に'去れ'か?,"자네, “꺼져.”가 무슨 뜻인지는 알지?","Weet je niet wat de betekenis is van de woorden ""verdwalen""?","Vet du ikke hva som menes med ""stikk""?","Nie znasz znaczenia słowa ""zgubić się""?","Você não sabe o que significa a expressão ""se manda""?",,"Nu cunoști semnificația cuvântului ""dispari""?",Ты не знаешь значения слова «исчезни»?,,"Vet du inte vad ordet ""försvinna"" betyder?",Kaybol kelimesinin anlamını bilmiyor musun? +Talk to Quincy first. I'm not allowed to help anyone unless he says it's ok.,TXT_DLG_SCRIPT17_D16676_TALKT,MAP17: Hospital → Assistant,,,Promluvte si nejprve s Quincym. Já nemůžu nikomu pomáhat dokud to nepovolí.,"Tal med Quincy først. Jeg må ikke hjælpe nogen, medmindre han siger, at det er i orden.","Rede erst mit Quincy. Ich darf mit niemanden reden, solange er nicht sein OK gegeben hat.",,Vi unue parolu al Kvincio. Mi rajtas helpi neniun ĝis li aprobos tion.,Habla con Quincy primero. No se me permite ayudar a nadie a menos que él lo diga.,,"Puhu ensin Quincylle. En saa auttaa ketään, ellei hän anna siihen lupaa.",Parlez à Quincy d'abord. Je ne suis pas autorisé à aider qui que ce soit sans son autorisation.,"Beszélj Quincyvel először. Nem beszélhetek senkivel, amíg nem engedélyezi.",Parla con Quincy prima. Non sono autorizzato ad aiutare nessuno se prima lui non dà il permesso.,"先にクインシーと話を。彼から許可を +得られない限りお助けすることは出来ません。",퀸시에게 먼저 물어보세요. 전 그가 괜찮다 하지 않는다면 아무것도 도울 수 없습니다.,"Praat eerst met Quincy. Ik mag niemand helpen, tenzij hij zegt dat het goed is.",Snakk med Quincy først. Jeg har ikke lov til å hjelpe noen med mindre han sier det er ok.,"Najpierw porozmawiaj z Quincy. Nie wolno mi nikomu pomagać, dopóki on nie powie, że to jest w porządku.",Fale com o Quincy primeiro. Não posso ajudar ninguém enquanto ele não autorizar.,,Vorbește cu Quincy mai întâi. Nu am permisiunea să ajut pe nimeni până nu spune că e în regulă.,"Сперва поговори с Куинси. Мне не позволено помогать кому-либо, пока он не разрешит.",,Prata med Quincy först. Jag får inte hjälpa någon om inte han säger att det är okej.,Önce Quincy ile konuş. O izin vermedikçe kimseye yardım edemem. +How how can I help you today?,TXT_DLG_SCRIPT17_D18192_HOWHO,〃,,,Jak vám mohu dnes pomoci?,Hvordan kan jeg hjælpe dig i dag?,Wie kann ich dir heute helfen?,,Kiel mi helpu vin hodiaŭ?,¿Cómo puedo ayudarte hoy?,,Miten voin olla avuksi tänään?,Comment puis-je vous aider aujourd'hui?,Ma miben segíthetek?,Come posso aiutarti oggi?,本日は何かお困りで?,오늘은 어떻게 도와드릴까요?,Hoe kan ik je vandaag helpen?,Hvordan kan jeg hjelpe deg i dag?,Jak mogę ci dzisiaj pomóc?,Como posso ajudá-lo hoje?,,Cu ce te pot ajuta azi?,Чем могу быть полезен?,,Hur kan jag hjälpa dig idag?,Bugün sana nasıl yardım edebilirim? +Med patch,TXT_RPLY0_SCRIPT17_D18192_MEDPA,〃,,,Obvazy,Medicinsk plaster,Medizinische Bandage,,Kuracbendoj,Tiritas,Curitas,Sidekäärettä.,Pansement.,Ragtapasz,Bende,医薬パッチ,의료 붕대,Med-patch,Medisinplaster,Bandaż,Compressa médica,,Trusă de prim-ajutor.,Бинтами,,Medicinsk plåster,Med yama +Here's your patch.,TXT_RYES0_SCRIPT17_D18192_HERES,〃,,,Tady jsou.,Her er dit plaster.,Hier ist deine Bandage.,,Jen viaj kuracbendoj,Aquí tienes tus tiritas.,Aquí tienes tus curitas.,Tässä kääreesi.,Voilà votre pansement.,Itt a tapaszod.,Ecco le tue bende.,これをどうぞ。,"의료 붕대 하나, 여기 있습니다.",Hier is je patch.,Her er lappen din.,Oto twój bandaż.,Aqui está sua compressa.,,Aici e trusa.,Вот твой набор бинтов.,,Här är ditt plåster.,İşte yaman. +That is 15 gold my friend.,TXT_RNO0_SCRIPT17_D18192_THATI,〃,,,"To je patnáct zlatých, příteli.","Det er 15 guld, min ven.","Das macht 15 Gold, mein Freund.",,"Ili kostas dek kvin +da oro, amiko.","Son quince de oro, amigo.",,"Se saisi olla 15 kolikkoa, ystäväiseni.","15 pièces pour ça, mon ami.",Az bizony 15 arany lesz barátom.,Sono 15 pezzi d'oro amico mio.,15 ゴールド必要です。,"그건 15 골드입니다, 친구.","Dat is 15 goud, mijn vriend.","Det er 15 gull, min venn.","To jest 15 złota, mój przyjacielu.","Custa 15 moedas de ouro, meu amigo.",,Costă 15 monezi amice.,"Они стоят 15 золотых, друг.",,"Det är 15 guld, min vän.",Bu 15 altın dostum. +Medical kit,TXT_RPLY1_SCRIPT17_D18192_MEDIC,〃,,,Lékárničku,Medicinsk kit,Verbandskasten,,Sukurkesto,Botiquín,,Lääkintälaukku.,Kit médical.,Elsősegély doboz.,Kit medico,医療用キット,구급 키트,Medische kit,Medisinsk utstyr,Zestaw medyczny,Kit médico,,Kit de prim-ajutor.,Аптечкой,,Medicinsk utrustning,Tıbbi kit +Here's your medical kit.,TXT_RYES1_SCRIPT17_D18192_HERES,〃,,,Tady je.,Her er dit medicinske kit.,Hier ist dein Verbandskasten,,Jen via sukurkesto.,Aquí tienes tu botiquín.,,Tässä lääkintälaukkusi.,Voilà votre kit médical.,Itt az elsősegélydobozod.,Ecco il tuo kit medico.,こちらが 医療用キットです。,구급 키트입니다. 잘 쓰시길.,Hier is je medische uitrusting.,Her er førstehjelpsskrinet ditt.,Oto twój zestaw medyczny.,Aqui está o seu kit médico,,Aici e kitul.,Вот твоя аптечка.,,Här är ditt medicinska utrustning.,İşte tıbbi çantan. +You're a bit low on funds for that.,TXT_RNO1_SCRIPT17_D18192_YOURE,〃,,,Tu si nemůžete dovolit.,Du har lidt for få midler til det.,Du hast zu wenig Geld dafür.,,Mankas mono al vi.,Estás algo falto de dinero.,,Sinulla on varat hieman vähissä siihen.,Vous manquez d'argent pour ça.,Nincs elég pénzed ehhez.,Sei un po' a corto di fondi per quello.,その為の資金が少し足りません。,그거 사기엔 자금이 부족한 듯.,Je hebt daar een beetje weinig geld voor.,Du har litt lite penger til det.,Masz na to trochę mało funduszy.,Você está um pouco mal de dinheiro pra isso.,,Cam puțini bani pentru aia.,Тебе на это не хватает средств.,,Du har lite ont om pengar för det.,Bunun için biraz az paran var. +Field surgery kit,TXT_RPLY2_SCRIPT17_D18192_FIELD,〃,,,Chirurgickou soupravu,Kirurgisæt,Erste-Hilfe-Kasten,,Kirurgia kesto,Kit quirúrgico,,Kenttäkirurgilaukku.,Kit de chirurgie.,Harctéri műtéti felszerelés,Kit chirurgico,手術キット,수술 키트.,Veld chirurgie kit,Kirurgisett,Zestaw do chirurgii polowej,Kit de cirurgia,,Kit chirurgical de teren.,Медкомплектом,,Fältkirurgisk utrustning,Saha ameliyat kiti +"One field surgery kit, done.",TXT_RYES2_SCRIPT17_D18192_ONEFI,〃,,,"Jedna souprava, zde.","Et kirurgisæt, færdig.","Ein Erste-Hilfe-Kasten, kommt sofort.",,Kirurgia kesto. Farite.,Un kit quirúrgico. Listo.,,"Yksi kirurgilaukku, noin.","Un kit de chirurgie, voilà.",Egy műtő felszerelés itt is van.,"Un kit chirurgico, eccolo qua.",野外用手術キット一丁。,수술 키트 하나 여기있습니다.,"Eén veldoperatiekit, klaar.","Ett kirurgisk sett, ferdig.","Jeden zestaw do chirurgii polowej, zrobione.",Um kit de cirurgia saindo,,"Un kit chirurgical de teren, gata.",Один медкомплект. Держи.,,"Ett fältkirurgiskt utrustning, klart.","Bir saha ameliyat kiti, tamamdır." +Come back when you have money!,TXT_RNO2_SCRIPT17_D18192_COMEB,〃,,,"Vrať se, až budeš mít peníze!","Kom tilbage, når du har penge!","Komm wieder, wenn du etwas Geld hast.",,"Revenu kiam vi +havos monon!","¡Vuelve cuando +tengas dinero!",,"Tule takaisin, kun sinulla on rahaa!",Revenez quand vous avez des sous!,"Gyere vissza, ha már van elég pénzed.",Torna quando avrai del denaro!,余裕がある時にまたどうぞ!,돈이 좀 있을 때 돌아와요!,Kom terug als je geld hebt!,Kom tilbake når du har penger!,"Wróć, gdy będziesz miał pieniądze!",Volte quando tiver dinheiro!,,Întoarce-te când ai destui bani!,Возвращайся с деньгами!,,Kom tillbaka när du har pengar!,Paran olduğunda geri gel! +What is it?,TXT_DLG_SCRIPT18_D0_WHATI,MAP18: Yellow guard,,,Co je?,Hvad er det?,Was gibt es?,,Kio okazas?,¿Qué pasa?,,Mikä on?,Vous voulez quoi?,Az meg mi?,Che cos'è?,何事だ?,무슨 일이냐?,Wat is het?,Hva er det?,Co to jest?,O que foi?,,Ce e?,Что тебе нужно?,,Vad är det för nåt?,Ne oldu? +Just looking around.,TXT_RPLY0_SCRIPT18_D0_JUSTL,〃,,,Jen se poohlížím.,Jeg kigger bare rundt.,Ich schaue mich bloß um.,,Mi nur pririgardas.,Solo estoy mirando.,,Ihan vain katselen.,Je fais juste un tour.,Csak nézelődök.,Sto soltando guardando.,見周りしている。,그냥 둘러보는 중이었습니다.,Gewoon rondkijken.,Jeg ser meg bare rundt.,Rozglądam się.,Só dando uma olhada.,,Doar mă uit împrejur.,Просто осматриваюсь.,,Jag tittar bara runt.,Sadece etrafa bakıyorum. +Just keep out of the way.,TXT_RYES0_SCRIPT18_D0_JUSTK,〃,,,Prostě se drž z cesty.,Bare hold dig ude af vejen.,Sei einfach niemandem im Weg.,,Vi nur ne ĝenu nin.,Pero no nos estorbes.,,Kunhan vain pysyt pois tieltä.,Restez hors du chemin.,Csak ne legyél láb alatt.,Basta che non ti metti in mezzo.,この先は立入禁止だ。,그럼 방해하지마.,Blijf gewoon uit de weg.,Bare hold deg unna.,Trzymaj się z dala od drogi.,Apenas fique fora do caminho.,,Doar nu sta în cale.,Просто не путайся под ногами.,,Håll dig bara ur vägen.,Yoldan uzak dur. +The Templars will be here soon to pick up their new maulers. If you get in their way you're a dead man.,TXT_DLG_SCRIPT18_D1516_THETE,〃,,,"Templáři tu brzy budou vyzvednout si své nové trhače. Jestli se jim připleteš pod nohy, jsi mrtvý.","Tempelridderne kommer snart og henter deres nye maulere. Hvis du kommer i vejen for dem, er du en død mand.","Die Templer werden bald hier sein, um ihre neuen Vernichter abzuholen. Wenn du ihnen im Weg bist, dann bist du ein toter Mann.",,"La templanoj baldaŭ venos por ricevi siajn novajn polvigilojn; se vi miksos vin, vi mortos.",Los templarios estarán aquí pronto para recibir sus nuevos trituradores; si los molestas eres hombre muerto.,Los templarios van a estar aquí pronto para recibir sus nuevos trituradores; si los molestas eres hombre muerto.,"Temppeliherrat tulevat tänne pian noutamaan uudet moukarinsa. Jos menet heidän tielleen, olet mennyttä.","Les templiers vont venier chercher les nouveaux broyeurs. Si vous les gênez, vous êtes mort.","A Keresztesek rögtön itt lesznek a kézi fegyvereikért. Ha az utukba állsz, halál fia vagy.",I Templari arriveranno presto qui a prendere i loro nuovi Mauler. Se ti trovano qui sei un uomo morto.,"新しいマウラーズを得たテンプル騎士団が すぐにでもここに来る。長生きしたければ -邪魔をしようと思わない方がいい。",템플러가 곧 새 마울러를 가지러 올 거야. 그들을 방해하면 넌 죽은 목숨이야.,"De Tempeliers zullen hier binnenkort zijn om hun nieuwe maulers op te halen. Als je hen in de weg staat, ben je een dode man.",,"Os Templários estarão aqui logo para pegar seus novos desintegradores. Se você se meter no caminho deles, você é um homem morto.",,,Храмовники скоро придут сюда забрать свои новые истязатели. Если попадёшься им на пути — станешь покойником., -Maulers?,TXT_RPLY0_SCRIPT18_D1516_MAULE,,,,Trhače?,Vernichter?,,,¿Trituradores?,,,Des broyeurs?,,,マウラーズ?,마울러?,Maulers?,,Desintegradores?,,,Истязатели?, -The Templar's favorite weapon.,TXT_RYES0_SCRIPT18_D1516_THETE,,,The templar's favourite weapon.,Oblíbená zbraň templářů.,Die Lieblingswaffe der Templer.,,,El arma favorita de los templarios.,,,L'arme favorite du templier.,,,騎士団に人気の兵器だ。,템플러가 제일 좋아하는 무기야.,Het favoriete wapen van de Tempeliers.,,A arma favorita dos Templários.,,,Их любимое оружие., -They came in earlier. That's what all the security's about. I got a chance to look at them when I locked up. Nobody's supposed to go in or out of there until the rest of the platoon comes to claim their weapons.,TXT_DLG_SCRIPT18_D3032_THEYC,,,,"Přišly sem už předtím, proto ta ochranka. Měl jsem možnost se na ně podívat, když jsem zamykal. Nikdo nesmí vejít dovnitř ani ven dokud si zbytek čety nepřijde pro zbraně.","Die sind heute früh hier eingetroffen. Daher all die Wachen. Ich konnte aber mal einen Blick darauf werfen. Niemand darf da rein, bevor die Waffen an die Truppen verteilt worden sind.",,,Vinieron antes. Para eso toda esta seguridad. Tuve una oportunidad de verlos cuando cerraba. Se supone que nadie puede entrar o salir hasta que el resto del pelotón venga a pedir sus armas.,,,Ils sont passés plus tôt. C'est pour ça qu'il y a autant de personnel de sécurité. J'ai eu l'opportunité de les voire quand je suis parti verouiller les accès. Personne n'est sensé entrer ou sortir tant que la section n'a pas fini de récupérer leur armes.,,,"以前所属したばかりだ。 +邪魔をしようと思わない方がいい。",템플러가 곧 새 마울러를 가지러 올 거야. 그들을 방해하면 넌 죽은 목숨이야.,"De Tempeliers zullen hier binnenkort zijn om hun nieuwe maulers op te halen. Als je hen in de weg staat, ben je een dode man.","Tempelridderne kommer snart for å hente sine nye maulere. Kommer du i veien for dem, er du en død mann.","Templariusze będą tu niedługo po swoje nowe maulery. Jeśli wejdziesz im w drogę, będziesz martwy.","Os Templários estarão aqui logo para pegar seus novos desintegradores. Se você se meter no caminho deles, você é um homem morto.",,Templierii vor fi curând aici pentru a ridica schiloditoarele. Dacă le stai în cale ești mort.,"Храмовники скоро придут сюда забрать свои новые истязатели. Если попадёшься им на пути, станешь покойником.",,Templarna kommer snart att vara här för att hämta sina nya maulers. Om du kommer i deras väg är du en död man.,Tapınakçılar yeni parçalayıcılarını almak için yakında burada olacaklar. Eğer yollarına çıkarsan ölürsün. +Maulers?,TXT_RPLY0_SCRIPT18_D1516_MAULE,〃,,,Trhače?,Maulers?,Vernichter?,,Ĉu polvigiloj?,¿Trituradores?,,Moukarit?,Des broyeurs?,Kézi fegyver?,Mauler?,マウラーズ?,마울러?,Maulers?,Maulere?,Maulery?,Desintegradores?,,Schiloditoare?,Истязатели?,,Maulers?,Parçalayıcılar? +The Templar's favorite weapon.,TXT_RYES0_SCRIPT18_D1516_THETE,〃,,The templar's favourite weapon.,Oblíbená zbraň templářů.,Tempelriddernes yndlingsvåben.,Die Lieblingswaffe der Templer.,,"La preferata armilo +de la templanoj.","El arma favorita +de los templarios.",,Temppeliherrojen lempiase.,L'arme favorite du templier.,A keresztesek kedvenc fegyvere.,È l'arma preferita dei Templari.,騎士団に人気の兵器だ。,템플러가 제일 좋아하는 무기야.,Het favoriete wapen van de Tempeliers.,Tempelriddernes favorittvåpen.,Ulubiona broń Templariuszy.,A arma favorita dos Templários.,,Arma preferată a Templierilor.,Их любимое оружие.,,Tempelriddarens favoritvapen.,Tapınakçıların en sevdiği silah. +They came in earlier. That's what all the security's about. I got a chance to look at them when I locked up. Nobody's supposed to go in or out of there until the rest of the platoon comes to claim their weapons.,TXT_DLG_SCRIPT18_D3032_THEYC,〃,,,"Dorazily už dřív, proto ta ochranka. Měl jsem možnost se na ně podívat, když jsem zamykal. Nikdo nesmí vejít dovnitř ani ven dokud si zbytek čety nepřijde pro zbraně.","De kom ind tidligere. Det er derfor, der er så meget sikkerhed. Jeg fik en chance for at se dem, da jeg låste af. Ingen må gå ind eller ud derfra, før resten af delingen kommer for at hente deres våben.","Die sind heute früh hier eingetroffen. Daher all die Wachen. Ich konnte aber mal einen Blick darauf werfen. Niemand darf da rein, bevor die Waffen an die Truppen verteilt worden sind.",,"Ili alvenis antaŭ nelonge, tial estas ĉi tiom da sekureco; mi havis la ŝancon vidi ilin kiam mi enŝlosis ilin. Neniu supozeble devas iri nek en tiun deponejon nek el ĝi ĝis la resto de la plotono venos peti siajn armilojn.","Han llegado hace poco, para eso toda esta seguridad; he tenido la oportunidad de verlos al cerrar el depósito. Se supone que nadie puede entrar o salir hasta que el resto del pelotón venga a pedir sus armas.","Llegaron hace poco, para eso toda esta seguridad; tuve la oportunidad de verlos al cerrar el depósito. Se supone que nadie puede entrar o salir hasta que el resto del pelotón venga a pedir sus armas.","He kävivät aiemmin. Siitä näissä kaikissa turvatoimissa on kyse. Sain mahdollisuuden vilkaista niitä, kun lukitsin paikkoja. Kukaan ei saa kulkea sisään eikä ulos, ennen kuin loput joukkueesta tulee noutamaan aseensa.",Ils sont passés plus tôt. C'est pour ça qu'il y a autant de personnel de sécurité. J'ai eu l'opportunité de les voire quand je suis parti verouiller les accès. Personne n'est sensé entrer ou sortir tant que la section n'a pas fini de récupérer leur armes.,"Most hamarabb jöttek. Emiatt van akkora biztonsági cécó. Jó megnéztem magamnak őket amikor bezártam. Senki nem mehet se ki se be, míg a szakasz be nem megy a fegyvereiért.",Sono arrivati da poco. Ecco perché c'è così tanta sicurezza. Ho avuto l'opportunità di vederli quando sono uscito per bloccare gli accessi. Nessuno dovrebbe entrare o uscire finché il plotone non ha finito di raccogliere le armi.,"以前所属したばかりだ。 彼等は全て警備に周るだろう。 門を閉める時に見る機会があったからな。 残りの小隊が兵器を請求するまで -誰も入れる事はできない。","최신 에너지 무기지. 이 무기를 보호하기 위해서 경비가 아주 삼엄하다고. 다만 시간 날 때 맨눈으로 보기는 했지만. 모든 템플러 분대가 이것들을 집어가기 전까지는 그 누구도 절대로 만질 수도, 볼 수도 없어.",Ze kwamen eerder binnen. Dat is waar de beveiliging over gaat. Ik kreeg de kans om naar ze te kijken toen ik ze opsloot. Niemand wordt verondersteld daar naar binnen of buiten te gaan totdat de rest van het peloton zijn wapens komt halen.,,Eles vieram aqui antes. Por isso toda essa segurança. Tive a oportunidade de dar uma olhada neles quando eu estava fechando. Ninguém pode entrar ou sair até que o resto do pelotão venha pegar suas armas.,,,"Его привезли раньше, поэтому здесь столько охраны. Я заглянул в хранилище, когда запирал его. Никому не позволено входить или выходить, пока весь отряд храмовников не получит своё оружие.", -This is where you get the plans for the central administration.,TXT_DLG_SCRIPT19_D0_THISI,"Appears in MAP19 and is supposed to be spoken by the Peasant1 actor (named “Security Comple”). However, no such actor is spawned in the map, rendering this line unused.",,,Tady se nachází plány pro ústřední administraci.,Dort bekommst du die Pläne für die Hauptverwaltung.,,,Aquí es donde obtienes los planos de la administración central.,,,C'est ici que vous pouvez récuperer les plans du centre d'administration.,,,,이곳은 중앙 관리소에 전술이나 계획을 보고하기 위한 곳이야.,Hier krijg je de plannen voor de centrale administratie.,,É aqui onde você pega os planos da administração central.,,,Здесь ты добудешь схему центральной администрации., -"I run this place. My job is to build the raw parts needed for the Loremaster's robot designs. If you're not here on official business, then I'm afraid I don't have time to talk.",TXT_DLG_SCRIPT22_D0_IRUNT,,,,"Já jsem ten, kdo to tu řídí. Mým úkolem je konstruovat části pro Dějepiscovy návrhy robotů. Jestli tu nejsi kvůli oficiálním záležitostem, pak se obávám, že nemám čas s tebou mluvit.","Ich leite dieses Unternehmen. Meine Aufgabe ist es, die Teile für die neuen Roboterdesigns des Wissensmeisters zu konstruieren. Wenn du hier nicht dienstlich hier bist, habe ich keine Zeit für dich.",,,"Yo manejo este sitio. Mi trabajo es contruir las partes necesarias para los diseños de robot del Maestro del Conocimiento. Si no estás aquí por asuntos oficiales, entonces me temo que no tengo tiempo para hablar.",,,"Je suis le chef de cet endroit. Mon travail est de faire fabriquer les pièces brutes utilisées pour les robots du Maître des traditions. Si vous n'êtes pas ici en visite officielle, je n'ai pas le temps de vous parler.",,,"私がこの場所の主任者だ。 +誰も入れる事はできない。","최신 에너지 무기지. 이 무기를 보호하기 위해서 경비가 아주 삼엄하다고. 다만 시간 날 때 맨눈으로 보기는 했지만. 모든 템플러 분대가 이것들을 집어가기 전까지는 그 누구도 절대로 만질 수도, 볼 수도 없어.",Ze kwamen eerder binnen. Dat is waar de beveiliging over gaat. Ik kreeg de kans om naar ze te kijken toen ik ze opsloot. Niemand wordt verondersteld daar naar binnen of buiten te gaan totdat de rest van het peloton zijn wapens komt halen.,De kom inn tidligere. Det er det all sikkerheten handler om. Jeg fikk en sjanse til å se på dem da jeg låste meg inn. Ingen skal gå inn eller ut før resten av troppen kommer for å hente våpnene sine.,"Przyszły wcześniej. To o to chodzi w tej całej ochronie. Miałem okazję przyjrzeć się im przy zamykaniu. Nikt nie może tam wchodzić ani wychodzić, dopóki reszta plutonu nie przyjdzie po swoją broń.",Eles vieram aqui antes. Por isso toda essa segurança. Tive a oportunidade de dar uma olhada neles quando eu estava fechando. Ninguém pode entrar ou sair até que o resto do pelotão venha pegar suas armas.,,Au venit mai devreme. Asta e treaba cu toată securitatea. Am avut șansa să îi privesc când închideam. Nimeni nu intră sau iese până ce tot platonul vine să își ia armele.,"Его привезли раньше, поэтому здесь столько охраны. Я заглянул в хранилище, когда запирал его. Пока весь отряд храмовников не получит своё оружие, никому не позволено входить или выходить.",,De kom in tidigare. Det är det som är orsaken till all säkerhet. Jag fick en chans att titta på dem när jag låste in dem. Ingen får gå in eller ut därifrån förrän resten av plutonen kommer för att hämta sina vapen.,Daha erken geldiler. Bütün güvenlik bunun için. Kapıyı kilitlediğimde onlara bakma şansım oldu. Müfrezenin geri kalanı silahlarını almaya gelene kadar kimsenin oraya girip çıkmaması gerekiyor. +This is where you get the plans for the central administration.,TXT_DLG_SCRIPT19_D0_THISI,"Appears in MAP19 and is supposed to be spoken by the Peasant1 actor (named “Security Comple”). However, no such actor is spawned in the map, rendering this line unused.",,,Tady se nachází plány pro ústřední administraci.,"Det er her, du får planerne for den centrale administration.",Dort bekommst du die Pläne für die Hauptverwaltung.,,Ĉi tie oni akiras la planojn de la centra administrejo.,Aquí es donde se consiguen los planos de la administración central.,,Täältä saat keskushallinnon piirustukset.,C'est ici que vous pouvez récuperer les plans du centre d'administration.,"Ez az a rész, ahol megszerezheted a terveket a központi irányításhoz.",Qui è dove prendi i piani per l'amministrazione centrale,,이곳은 중앙 관리소에 전술이나 계획을 보고하기 위한 곳이야.,Hier krijg je de plannen voor de centrale administratie.,Det er her du får planene for sentraladministrasjonen.,To tutaj dostajecie plany dla administracji centralnej.,É aqui onde você pega os planos da administração central.,,De aici vei lua schemele pentru camera de administrare centrală.,Здесь ты добудешь схему центральной администрации.,,Det är här du får planerna för den centrala administrationen.,Burası merkezi yönetimin planlarını aldığınız yer. +"I run this place. My job is to build the raw parts needed for the Loremaster's robot designs. If you're not here on official business, then I'm afraid I don't have time to talk.",TXT_DLG_SCRIPT22_D0_IRUNT,"SVE.WAD +MAP22: C-shaped building → Master Smithy.",,,"Já jsem ten, kdo to tu řídí. Mým úkolem je konstruovat části pro Dějepiscovy návrhy robotů. Jestli tu nejsi kvůli oficiálním záležitostem, pak se obávám, že nemám čas s tebou mluvit.","Jeg styrer stedet her. Mit job er at bygge de rådele, der er nødvendige for Loremesterens robotdesigns. Hvis du ikke er her i officielt ærinde, så har jeg desværre ikke tid til at tale.","Ich leite dieses Unternehmen. Meine Aufgabe ist es, die Teile für die neuen Roboterdesigns des Wissensmeisters zu konstruieren. Wenn du hier nicht dienstlich hier bist, habe ich keine Zeit für dich.",,"Mi estras ĉi tiun lokon. Mia laboro estas konstrui la necesajn partojn por la dezajnoj de la robotoj de la Folkloristo. Se vi ne venis por oficialaj aferoj, mi timas, ke mi ne havas tempon babili.","Yo manejo este sitio. Mi trabajo es contruir las partes necesarias para los diseños de los robots del Maestro del Conocimiento. Si no estás aquí por asuntos oficiales, entonces me temo que no tengo tiempo para hablar.",,"Minä vedän tätä paikkaa. Työni on valmistaa osat, joita tarvitaan Oppi-Isän robottikehitelmiin. Jos et ole täällä virallisilla asioilla, sitten minulla valitettavasti ei ole aikaa puhua.","Je suis le chef de cet endroit. Mon travail est de faire fabriquer les pièces brutes utilisées pour les robots du Maître des traditions. Si vous n'êtes pas ici en visite officielle, je n'ai pas le temps de vous parler.","Én vezetem ezt a kócerájt. Az én feladatom, hogy a Tanmester robotjának alkatrészeit összerakjam. Ha nem hivatalos ügyben jöttél, akkor sajnos nincs időm rád.","Sono io a gestire questo posto. Il mio lavoro è costruire i materiali necessari per i progetti dei robot del Sapiente. A meno che tu non sia qua per discutere affari, mi spiace ma non ho tempo per parlare.","私がこの場所の主任者だ。 私の仕事は、ロアマスターのロボットの デザインに必要な原料パーツを生産することだ。 もしあなたが公用で来たのではないのなら、 -申し訳ないが話すための時間はないのだ。","난 이곳의 책임자야. 로어마스터님의 로봇 설계를 돕기 위해 일하고 있지. 만약 공식 업무 외에 온 거라면, 바쁘니까 돌아가 줘야 되겠는걸?","Ik run deze plek. Mijn taak is om de ruwe onderdelen te bouwen die nodig zijn voor de robotontwerpen van de Kennismeester. Als je hier niet bent voor officiële zaken, dan ben ik bang dat ik geen tijd heb om te praten.",,"Eu sou o chefe daqui deste lugar. Meu trabalho é construir as peças necessárias para os robôs do Mestre do Conhecimento. Se você não está aqui para assuntos oficiais, então receio que não temos tempo para conversa.",,,"Я здесь главный. Моя работа — изготавливать детали роботов для Хранителя мудрости. Если ты здесь не по служебным делам, то, боюсь, мне некогда с тобой болтать.", -I am on official business.,TXT_RPLY0_SCRIPT22_D0_IAMON,,,,Jsem tu kvůli oficiálním záležitostem.,Ich bin dienstlich hier.,,,Estoy por asuntos oficiales.,,,Je suis en visite officielle.,,,私は公用で来た。,공식 업무로 왔어.,Ik ben voor officiële zaken.,,Estou aqui para tratar de assuntos oficiais.,,,Я по служебным делам., -"So you've spoken with Timothy, I see. He and I have worked together to try to unravel the mysteries of the Order, before it's too late for us all. Maybe you can help us. I've opened the door to the production sector.",TXT_DLG_SCRIPT22_D1516_SOYOU,,,,"Vidím, že sis promluvil s Timothym. Pracovali jsme spolu na odkrytí tajemství Řádu, dřív, než pro nás bude pozdě. Možná nám můžeš pomoct. Otevřel jsem dveře do výrobního sektoru.","Du hast mit Timothy gesprochen, ich verstehe. Er und ich haben zusammengearbeitet und versucht die Mysterien des Ordens ergründen, bevor es für uns alle zu spät ist. Vielleicht kannst du uns helfen. Ich habe die Tür zum Produktionsektor geöffnet.",,,"Así que has ablado con Timothy, ya veo. Él y yo hemos trabajado juntos para intentar desenredar los misterios de la Orden, antes de que sea demasiado tarde para todos nosotros. Tal vez puedas ayudarnos. He abierto la puerta al sector de producción.",,,Je vois que vous avez parlé à Timothy. Nous avons travaillé ensemble pour dénouer les mystères de l'Ordre avant qu'il soit trop tard. Peut être que vous pouvez nous aider. J'ai ouvert l'accès vers le secteur de production.,,,"ということは、ティモシーと話したのだな。 +申し訳ないが話すための時間はないのだ。","난 이곳의 책임자야. 로어마스터님의 로봇 설계를 돕기 위해 일하고 있지. 만약 공식 업무 외에 온 거라면, 바쁘니까 돌아가 줘야 되겠는걸?","Ik run deze plek. Mijn taak is om de ruwe onderdelen te bouwen die nodig zijn voor de robotontwerpen van de Kennismeester. Als je hier niet bent voor officiële zaken, dan ben ik bang dat ik geen tijd heb om te praten.","Jeg driver dette stedet. Min jobb er å bygge rådelene som trengs til Loremesterens robotdesign. Hvis du ikke er her i offisielt ærend, har jeg ikke tid til å snakke.","Ja prowadzę to miejsce. Moim zadaniem jest budowanie części potrzebnych do projektów robotów Loremastera. Jeśli nie jesteś tu w oficjalnej sprawie, to obawiam się, że nie mam czasu na rozmowę.","Eu sou o chefe daqui deste lugar. Meu trabalho é construir as peças necessárias para os robôs do Mestre do Conhecimento. Se você não está aqui para assuntos oficiais, então receio que não temos tempo para conversa.",,"Eu conduc locul ăsta. Treaba mea e să produc materia primă pentru designul roboților Stăpânului Cunoștiințelor. Dacă nu ești aici cu treabă oficială, atunci nu am timp de vorbă.","Я здесь главный. Моя работа — изготавливать детали роботов для Хранителя мудрости. Если ты здесь не по служебным делам, то, боюсь, мне некогда с тобой болтать.",,Jag styr det här stället. Mitt jobb är att bygga de rådelar som behövs för Läromästarens robotkonstruktioner. Om du inte är här i officiellt ärende har jag tyvärr inte tid att prata.,"Burayı ben yönetiyorum. Benim işim Loremaster'ın robot tasarımları için gereken ham parçaları üretmek. Eğer resmi bir iş için burada değilseniz, korkarım ki konuşacak vaktim yok." +I am on official business.,TXT_RPLY0_SCRIPT22_D0_IAMON,〃,,,Jsem tu kvůli oficiálním záležitostem.,Jeg er i officielt ærinde.,Ich bin dienstlich hier.,,Mi venis por oficialaj aferoj.,Estoy por asuntos oficiales.,,Olen virallisilla asioilla.,Je suis en visite officielle.,Hivatalos ügyben jöttem.,Sono qua per discutere affari.,私は公用で来た。,공식 업무로 왔어.,Ik ben voor officiële zaken.,Jeg er her i offisielt ærend.,Jestem w oficjalnej sprawie.,Estou aqui para tratar de assuntos oficiais.,,Sunt cu treburi oficiale.,Я по служебным делам.,,Jag är i officiellt ärende.,Resmi bir iş için buradayım. +"So you've spoken with Timothy, I see. He and I have worked together to try to unravel the mysteries of the Order, before it's too late for us all. Maybe you can help us. I've opened the door to the production sector.",TXT_DLG_SCRIPT22_D1516_SOYOU,〃 (After giving the blue chalice to Timothy).,,,"Vidím, že sis promluvil s Timothym. Pracovali jsme spolu na odkrytí tajemství Řádu, dřív, než pro nás bude pozdě. Možná nám můžeš pomoct. Otevřel jsem dveře do výrobního sektoru.","Så du har talt med Timothy, kan jeg se. Han og jeg har arbejdet sammen for at forsøge at løse ordenens mysterier, før det er for sent for os alle. Måske kan du hjælpe os. Jeg har åbnet døren til produktionssektoren.","Du hast mit Timothy gesprochen, ich verstehe. Er und ich haben zusammengearbeitet und versucht die Mysterien des Ordens ergründen, bevor es für uns alle zu spät ist. Vielleicht kannst du uns helfen. Ich habe die Tür zum Produktionsektor geöffnet.",,Do vi parolis kun Timoteo. Li kaj mi kunlaboris kun la intenco penetri la misterojn de La Ordeno. Vi eble povas helpi nin; mi malfermis la pordon de la produktejo.,"Así que has hablado con Timothy, ya veo. Él y yo hemos trabajado juntos para intentar desentrañar los misterios de La Orden antes de que sea demasiado tarde para todos nosotros. Tal vez puedas ayudarnos; he abierto la puerta al sector de producción.","Así que hablaste con Timothy, ya veo. Él y yo hemos trabajado juntos para tratar de descifrar los misterios de La Orden antes de que sea demasiado tarde para todos nosotros. Tal vez puedas ayudarnos; acabo de abrir la puerta al sector de producción.","Olet siis näköjään puhunut Timothyn kanssa. Olemme yhteistyössä koettaneet ratkoa Veljeskunnan saloja, ennen kuin on liian myöhäistä meidän kaikkien kannalta. Ehkä voit auttaa meitä. Avasin oven tuotantolaitokselle.",Je vois que vous avez parlé à Timothy. Nous avons travaillé ensemble pour dénouer les mystères de l'Ordre avant qu'il soit trop tard. Peut être que vous pouvez nous aider. J'ai ouvert l'accès vers le secteur de production.,"Úgy látom már beszéltél Timothyval. Ő és Én már korábban is próbáltuk felderíteni a Rend rejtélyét, mielőtt még mindannyiunknak túl késő nem lesz. Talán tudsz segíteni. Kinyitottam az ajtót a gyártó részleghez.",Vedo che hai parlato con Timothy. Io e lui abbiamo lavorato insieme per cercare di svelare i misteri dell'Ordine prima che sia troppo tardi per tutti noi. Forse ci puoi aiutare. Ho aperto la porta che conduce al settore di produzione.,"ということは、ティモシーと話したのだな。 彼と私は、取り返しのつかない事態に陥る前に オーダーの秘密を解き明かすために 一緒に働いてきた。もしかすると、 君は私達に手を貸せるかもしれない。 -私は今、生産セクターへの扉を開いたぞ。","티모시와 이야기를 나눴구나, 그렇지? 티모시랑 같이 한발 늦기 전에 오더의 비밀을 파헤치려고 열심히 노력했지. 아마도 우리들을 도와줄 수 있을 것 같은데 말이야. 방금 제조 공간의 문을 열어놨어.","Dus je hebt met Timothy gesproken, zie ik. Hij en ik hebben samengewerkt om te proberen de mysteries van de Orde te ontrafelen, voordat het voor ons allemaal te laat is. Misschien kunt u ons helpen. Ik heb de deur geopend naar de productiesector.",,"Então você andou falando com o Timothy, pelo visto. Eu e ele trabalhamos juntos para tentar desvendar os mistérios da Ordem antes que seja tarde para todos nós. Talvez você possa nos ajudar. Eu abri a porta para o setor de produção.",,,"Итак, ты уже поговорил с Тимоти. Мы с ним вместе пытаемся раскрыть тайны Ордена, пока не стало слишком поздно. Возможно, ты сможешь помочь нам. Я открыл дверь в производственный сектор.", -Do you know what's inside?,TXT_RPLY0_SCRIPT22_D1516_DOYOU,,,,"Víš, co je uvnitř?",Weißt du was da drin ist?,,,¿Sabes que hay adentro?,,,Vous savez ce qu'il y à dedans?,,,中に何があるのかを知っているのか?,그 안에 무엇이 있는지 아나?,Weet je wat er in zit?,,Você sabe o que tem lá dentro?,,,"Ты знаешь, что там?", -"It's a top secret area. Not only is the Order breeding some kind of... creature in there, I've seen with my own eyes a strange artifact called a Talisman. nobody's allowed near it. Rumor is that it holds great power if united with two others of its kind.",TXT_DLG_SCRIPT22_D3032_ITSAT,,,,"Je to přísně tajná oblast. Nejenže se tam Řád snaží zplodit nějakou... příšeru, ale na vlastní oči jsem tam viděl zvláštní artefakt jménem Talisman. Nikdo k němu nesmí. Říká se, že skrývá nesmírnou moc pokud se spojí s dalšími dvěma svého druhu.","Das ist alles streng geheim. Dort wird nicht nur irgendeine Art von... Kreatur vom Orden gezüchtet, sondern es gibt dort auch ein merkwürdiges Artefakt, ein Talisman. Keiner darf in auch nur in die Nähe davon. Gerüchten zufolge erhält man große Macht, wenn man es mit zwei anderen vereint.",,,"Es un área de alto secreto. No solo está la Orden criando una especie de... Criatura ahí, he visto con mis propios ojos un extraño artefacto llamado Talismán. No se permite a nadie acercarse a él. Se rumorea que posee un gran poder si se reune con otros dos de su tipo.",,,C'est une zone top secrète. L'Ordre essaie de.. faire une sorte de créature là dedans. J'ai vu avec mes yeux un artéfact étrange qu'ils appellent un Talisman. Personne n'a le droit de l'approcher. Les rumeurs disent qu'il contient un pouvoir phénoménal si il est réuni avec deux autres du même type.,,,"あの場所は極秘エリアだ。 +私は今、生産セクターへの扉を開いたぞ。","티모시와 이야기를 나눴구나, 그렇지? 티모시랑 같이 한발 늦기 전에 오더의 비밀을 파헤치려고 열심히 노력했지. 아마도 우리들을 도와줄 수 있을 것 같은데 말이야. 방금 제조 공간의 문을 열어놨어.","Dus je hebt met Timothy gesproken, zie ik. Hij en ik hebben samengewerkt om te proberen de mysteries van de Orde te ontrafelen, voordat het voor ons allemaal te laat is. Misschien kunt u ons helpen. Ik heb de deur geopend naar de productiesector.","Så du har snakket med Timothy, ser jeg. Han og jeg har jobbet sammen for å løse Ordenens mysterier før det er for sent for oss alle. Kanskje du kan hjelpe oss. Jeg har åpnet døren til produksjonssektoren.","Widzę, że rozmawiałaś z Timothym. Razem z nim próbujemy rozwikłać tajemnice Zakonu, zanim będzie za późno dla nas wszystkich. Może ty możesz nam pomóc. Otworzyłem drzwi do sektora produkcyjnego.","Então você andou falando com o Timothy, pelo visto. Eu e ele trabalhamos juntos para tentar desvendar os mistérios da Ordem antes que seja tarde para todos nós. Talvez você possa nos ajudar. Eu abri a porta para o setor de produção.",,"Ai vorbit cu Timotei, să înțeleg. Noi am lucrat împreună în încercarea de a descoperii misterele Ordinului, înainte să fie prea târziu pentru noi toți. Poate ne poți ajuta. Am deschis ușa la sectorul de producție.","Итак, ты уже поговорил с Тимоти. Мы с ним вместе пытаемся раскрыть тайны Ордена, пока не стало слишком поздно. Возможно, ты сможешь нам помочь. Я открыл дверь в производственный сектор.",,"Så du har talat med Timothy, ser jag. Han och jag har arbetat tillsammans för att försöka lösa Ordens mysterier innan det är för sent för oss alla. Du kanske kan hjälpa oss. Jag har öppnat dörren till produktionssektorn.","Gördüğüm kadarıyla Timothy ile konuşmuşsunuz. O ve ben, hepimiz için çok geç olmadan Tarikat'ın gizemlerini çözmeye çalışmak için birlikte çalıştık. Belki bize yardım edebilirsin. Üretim sektörünün kapısını açtım." +Do you know what's inside?,TXT_RPLY0_SCRIPT22_D1516_DOYOU,〃,,,"Víš, co je uvnitř?","Ved du, hvad der er indenfor?",Weißt du was da drin ist?,,"Ĉu vi scias, kio estas en ĝi?",¿Sabes qué hay dentro?,¿Sabes qué hay adentro?,"Tiedätkö, mitä sisällä on?",Vous savez ce qu'il y à dedans?,Tudod mi van bent?,Che cosa c'è oltre la porta?,中に何があるのかを知っているのか?,그 안에 무엇이 있는지 아나?,Weet je wat er in zit?,Vet du hva som er der inne?,"Wiesz, co jest w środku?",Você sabe o que tem lá dentro?,,Știi cumva ce e înăuntru?,"Ты знаешь, что там?",,Vet du vad som finns där inne?,İçeride ne olduğunu biliyor musun? +"It's a top secret area. Not only is the Order breeding some kind of... creature in there, I've seen with my own eyes a strange artifact called a Talisman. nobody's allowed near it. Rumor is that it holds great power if united with two others of its kind.",TXT_DLG_SCRIPT22_D3032_ITSAT,〃,,,"Je to přísně tajná oblast. Nejenže se tam Řád snaží zplodit nějakou... příšeru, ale na vlastní oči jsem tam viděl zvláštní artefakt jménem Talisman. Nikdo k němu nesmí. Říká se, že skrývá nesmírnou moc pokud se spojí s dalšími dvěma svého druhu.","Det er et tophemmeligt område. Ikke alene avler Ordenen en slags... væsen derinde, jeg har også set med mine egne øjne en mærkelig artefakt kaldet en Talisman. Ingen må komme i nærheden af den. Rygterne siger, at den har stor magt, hvis den forenes med to andre af sin slags.","Das ist alles streng geheim. Dort wird nicht nur irgendeine Art von... Kreatur vom Orden gezüchtet, sondern es gibt dort auch ein merkwürdiges Artefakt, ein Talisman. Keiner darf in auch nur in die Nähe davon. Gerüchten zufolge erhält man große Macht, wenn man es mit zwei anderen vereint.",,"Ĝi estas tute konfidenca sektoro. Ne nur La Ordeno estigas specon de... vivaĵo tie, mi vidis per miaj propraj okuloj strangan artefakton nomatan talismano. Neniu rajtas aliri ĝin. Oni diras, ke ĝi posedas grandan povon se ĝi estas proksime de aliaj du el sia speco.","Es un área de alto secreto. No solo está La Orden criando a una especie de... criatura ahí, he visto con mis propios ojos un artefacto extraño llamado talismán. No se le permite a nadie acercarse a él. Se rumorea que posee un gran poder si se reúne con otros dos de su especie.",,"Se on huippusalainen alue. Vielä sen lisäksi, että Veljeskunta on luomassa siellä jonkinlaista... oliota, olen omin silmin nähnyt oudon esineen, jota kutsutaan Talismaaniksi. Ketään ei sallita sen lähelle. Huhutaan, että sen sisällä piilee suuri voima, jos sen yhdistää kahden toisen sen kaltaisen kanssa.",C'est une zone top secrète. L'Ordre essaie de.. faire une sorte de créature là dedans. J'ai vu avec mes yeux un artéfact étrange qu'ils appellent un Talisman. Personne n'a le droit de l'approcher. Les rumeurs disent qu'il contient un pouvoir phénoménal si il est réuni avec deux autres du même type.,"Egy totál titkos terület. Nem elég hogy valamiféle...lényeket tenyésztenek odabent, láttam valamiféle leletet is, amit Talizmán néven emlegettek. Senkit se engednek a közelébe. A legenda szerint hatalmas erő birtokosa lehet, aki egyesíti még két másik darabbal.","È un'area a cui quasi nessuno è permesso entrare. L'Ordine non solo sta crescendo una specie di... creatura là dentro, ma inoltre ho anche visto uno strano artefatto che chiamano Talismano. Nessuno ci si può avvicinare. Dicono che se unito a due altri talismani, sprigioni un enorme potere.","あの場所は極秘エリアだ。 オーダーはある種の生物のようなものを そこで繁殖させているし、それだけではなく 私はタリスマンと呼ばれる奇妙な アーティファクトをこの目で見た。 誰もそれには近づくことが許されていないのだ。 噂では、タリスマンはほかの2つのタリスマンと -つながることで強大なパワーを発揮できるらしい。",아주 중요한 기밀 공간이야. 난 오더가 거기에서 각종... 생물들을 만드는 거랑 부적이라는 희한한 유물을 보호하는 모습을 봤지. 그런 이유로 그 누구도 못 들어가. 그리고 이와 똑같은 다른 유물을 합치면 초월한 힘을 발휘한다는 소문도 들었어.,"Het is een topgeheim gebied. Niet alleen is de Orde daar een soort.... schepsel aan het kweken, ik heb met mijn eigen ogen een vreemd artefact gezien dat een Talisman wordt genoemd. niemand mag er in de buurt komen. Het gerucht gaat dat hij grote macht heeft als hij zich verenigt met twee anderen van zijn soort.",,"É uma área ultrassecreta. Não só a Ordem está criando um tipo de...criatura lá dentro, eu vi com meus próprios olhos um artefato estranho chamado de Talismã. Ninguém tem permissão para chegar perto. Dizem que ele tem um grande poder ao se unir com outros dois do mesmo tipo.",,,"Это совершенно секретно. Во-первых, Орден разводит там каких-то... существ. Во-вторых, я своими глазами видел странный артефакт, «Талисман». К нему никого и близко не подпускают. Говорят, что можно получить огромную силу, если объединить его с двумя другими.", -I suppose you want this thing?,TXT_RPLY0_SCRIPT22_D3032_ISUPP,,,,"Předpokládám, že jej chceš?","Ich denke mal, du willst dieses Ding haben?",,,¿Supongo que quieres esto?,,,Je suppose que vous le voulez?,,,それが欲しいということか?,내 생각엔 그걸 원하나 보지?,Ik neem aan dat je dit ding wilt?,,Imagino que você quer essa coisa?,,,"Похоже, ты и сам хочешь этот артефакт?", -"No! If you can find it, it's yours to keep. Maybe you can use it to help free us from our oppression. I'd wish you luck, but you're going to need a lot more than that if you go in there...",TXT_DLG_SCRIPT22_D4548_NOIFY,,,,"Ne! Jestli ho najdeš, je tvůj. Možná by ti mohl pomoct osvobodit nás od nadvlády. Přál bych ti štěstí, ale jestli tam půjdeš, budeš potřebovat mnohem víc než to...","Nein! Wenn du es findest, darfst du es behalten. Vielleicht kannst du es benutzen, um uns von unserer Unterdrückung zu befreien. Ich würde dir Glück wünschen, aber du wirst viel mehr brauchen, wenn du dort hinein gehst.",,,"¡No! Si lo encuentras, quédatelo. Tal vez puedas usarlo para ayudar a librarnos de nuestra opresión. Te desearía suerte, pero vas a necesitar más que eso si vas ahí...",,,"Non! Si vous le trouvez, gardez le pour vous. Peut être qu'il vous aidera à nous débarasser de nos oppresseurs.. Je vous souhaiterais bonne chance, mais vous allez avoir besoin de beaucoup plus que ça si vous y entrez..",,,"そうではない!もし見つけたら +つながることで強大なパワーを発揮できるらしい。",아주 중요한 기밀 공간이야. 난 오더가 거기에서 각종... 생물들을 만드는 거랑 부적이라는 희한한 유물을 보호하는 모습을 봤지. 그런 이유로 그 누구도 못 들어가. 그리고 이와 똑같은 다른 유물을 합치면 초월한 힘을 발휘한다는 소문도 들었어.,"Het is een topgeheim gebied. Niet alleen is de Orde daar een soort.... schepsel aan het kweken, ik heb met mijn eigen ogen een vreemd artefact gezien dat een Talisman wordt genoemd. niemand mag er in de buurt komen. Het gerucht gaat dat hij grote macht heeft als hij zich verenigt met twee anderen van zijn soort.","Det er et topphemmelig område. Ikke bare avler Ordenen en slags... skapning der inne, jeg har selv sett en merkelig gjenstand kalt en Talisman. Ingen får komme nær den. Ryktene sier at den har stor makt hvis den forenes med to andre av sitt slag.","To ściśle tajny obszar. Nie dość, że Zakon hoduje tam jakieś... stworzenia, to na własne oczy widziałem dziwny artefakt zwany Talizmanem. nikomu nie wolno się do niego zbliżać. Plotka głosi, że posiada on wielką moc, jeśli połączy się go z dwoma innymi tego rodzaju.","É uma área ultrassecreta. Não só a Ordem está criando um tipo de...criatura lá dentro, eu vi com meus próprios olhos um artefato estranho chamado de Talismã. Ninguém tem permissão para chegar perto. Dizem que ele tem um grande poder ao se unir com outros dois do mesmo tipo.",,"E o zonă secretă. Nu numai că Ordinul crește un fel de... creatură acolo, am văzut cu proprii mei ochi un fel de artefact numit Talisman, nimeni nu e lăsat să se apropie.. Zvonurile zic că e un artefact de o putere imensă dacă e unit cu celelalte două părți ale lui.","Это совершенно секретно. Во-первых, Орден разводит там каких-то... существ. Во-вторых, я своими глазами видел странный артефакт — «Талисман». К нему никого и близко не подпускают. Говорят, если объединить его с двумя другими, можно получить огромную силу.",,"Det är ett topphemligt område. Inte nog med att Orden föder upp någon sorts... varelse där inne, jag har med egna ögon sett en märklig artefakt som kallas för en Talisman. Ingen får komma i närheten av den. Ryktet säger att den har stor kraft om den förenas med två andra av samma slag.","Çok gizli bir bölge. Tarikat orada bir tür yaratık yetiştirmekle kalmıyor, Tılsım denen garip bir eseri kendi gözlerimle gördüm. Kimsenin ona yaklaşmasına izin verilmiyor. Söylentiye göre türünün diğer iki örneğiyle birleştiğinde büyük bir güce sahip oluyormuş." +I suppose you want this thing?,TXT_RPLY0_SCRIPT22_D3032_ISUPP,〃,,,"Předpokládám, že jej chceš?","Jeg formoder, at du vil have denne tingest?","Ich denke mal, du willst dieses Ding haben?",,"Mi supozas, ke vi volas ĝin.",Y supongo que lo quieres.,,Sinä varmaankin haluat tämän esineen?,Je suppose que vous le voulez?,Gondolom kell neked az a tárgy.,Immagino tu voglia questo?,それが欲しいということか?,내 생각엔 그걸 원하나 보지?,Ik neem aan dat je dit ding wilt?,Jeg antar at du vil ha den?,"Przypuszczam, że chcesz tego czegoś?",Imagino que você quer essa coisa?,,Presupun că vrei chestia asta?,"Похоже, ты и сам хочешь этот артефакт?",,Jag antar att du vill ha den här?,Sanırım bu şeyi istiyorsun? +"No! If you can find it, it's yours to keep. Maybe you can use it to help free us from our oppression. I'd wish you luck, but you're going to need a lot more than that if you go in there...",TXT_DLG_SCRIPT22_D4548_NOIFY,〃,,,"Ne! Jestli ho najdeš, je tvůj. Možná by ti mohl pomoct osvobodit nás od nadvlády. Přál bych ti štěstí, ale jestli tam půjdeš, budeš potřebovat mnohem víc než to...","Nej! Hvis du kan finde den, kan du beholde den. Måske kan du bruge den til at hjælpe os med at befri os fra vores undertrykkelse. Jeg ville ønske dig held og lykke, men du får brug for meget mere end det, hvis du går derind...","Nein! Wenn du es findest, darfst du es behalten. Vielleicht kannst du es benutzen, um uns von unserer Unterdrückung zu befreien. Ich würde dir Glück wünschen, aber du wirst viel mehr brauchen, wenn du dort hinein gehst.",,"Ne! Se vi trovos ĝin, konservu ĝin. Ĝi eble estos utila por ke vi liberigu nin ĉiujn de ĉi tiu opresado. Mi dezirus bonŝancon, sed vi bezonos multe pli ol tion se vi iros tien...","¡No! Si lo encuentras, quédatelo. Quizá te sirva para intentar librarnos de esta opresión. Te desearía suerte, pero necesitarás mucho más que eso si vas ahí...","¡No! Si lo encuentras, quédatelo. Puede que te sirva para tratar de librarnos de esta opresión. Te desearía suerte, pero vas a necesitar mucho más que eso si vas ahí...","Ei! Jos löydät sen, saat pitää omanasi. Voit ehkä käyttää sitä auttaaksesi vapauttamaan meidät sorrostamme. Toivottaisin sinulle onnea, mutta tarvitset paljon enemmän kuin sitä, jos menet sinne.","Non! Si vous le trouvez, gardez le pour vous. Peut être qu'il vous aidera à nous débarasser de nos oppresseurs.. Je vous souhaiterais bonne chance, mais vous allez avoir besoin de beaucoup plus que ça si vous y entrez..","Dehogyis! Ha megleled, a tied lehet. Talán fel tudod használni annak érdekében, hogy felszabadíts minket az elnyomás alól. Szerencsét kívánnék, de annál sokkal többre lesz szükséged odabent...","No! Se lo trovi, te lo puoi tenere. Forse lo puoi utilizzare per liberarci dalla nostra oppressione. Ti augurerei buona fortuna, ma ti servirebbe molto più che fortuna se vai là dentro...","そうではない!もし見つけたら それは自分のものにしてくれ。もしかすれば、 それを私達をオーダーから解放するために 使えるかもしれない。幸運を祈ってはいるが、 もしあの場所に行こうとしているなら、 -もっと多くの力が必要となるぞ...","아니야! 만약 네가 가질 수만 있다면, 그건 네 거야. 아마도 우리들을 탄압으로부터 구해줄 수 있겠네. 부디 행운을 빌어. 왜냐하면 많은 걸 준비 한 뒤 각오하고 들어가야 하거든.","Nee, als je het kunt vinden, is het aan jou om het te houden. Misschien kunt je het gebruiken om ons te bevrijden van onze onderdrukking. Ik zou je veel geluk wensen, maar je zult veel meer nodig hebben als je daar naar binnen gaat....",,"Não! Se você conseguir achá-lo, fique com ele. Talvez você possa usá-lo para nos libertar dessa opressão. Eu te desejaria sorte, mas você vai precisar de muito mais do que isso se você entrar lá dentro...",,,"Нет! Если ты его найдёшь, он твой. Может быть, он поможет тебе освободить нас от гнёта. Я бы пожелал тебе удачи, но, если ты пойдёшь туда, простой удачи будет недостаточно...", -What's all this about the past?,TXT_RPLY0_SCRIPT22_D4548_WHATS,,,,Cos to říkal o minulosti?,Was ist dieses ganze Gerede über die Vergangenheit?,,,¿Qué es todo esto sobre el pasado?,,,Qu'est-ce que j'entends au sujet du passé?,,,過去に何があったというんだ?,그 과거에 대해서 뭐가 어떻길레?,Wat is dit alles over het verleden?,,Que história é essa sobre o passado?,,,Что такого творилось здесь в прошлом?, -"You've surely seen the other ruins nearby. It seems that the Comet which crashed on our planet is actually a space ship, and believe it or not, it originated on this very world a long time ago.",TXT_DLG_SCRIPT22_D6064_YOUVE,,,,"Určitě jsi zahlédnul ty zříceniny tady v okolí. Zdá se, že ta kometa, která narazila do naší planety, je ve skutečnosti vesmírná loď, která, věř nebo ne, pochází z tohoto světa, velmi dávno.","Du hast doch sicherlich die Ruinen hier in der Nähe gesehen. Es scheint als wäre der Komet, der hier auf dem Planeten aufgeschlagen ist, eigentlich ein Raumschiff, und ob du es glaubst oder nicht, aber es kam vor langer Zeit sogar von dieser Welt.",,,"Seguramente has visto las otras ruinas cercanas. Al parecer el cometa que se estrelló sobre nuestro planeta es en realidad una nave espacial, y lo creas o no, es originaria de este mundo hace mucho tiempo.",,,"Vous avez sans doute vu toutes ces ruines aux alentours. Il semble que la comète qui s'est écrasée sur notre planète était en fait un vaisseau spatial, et.. du moins si vous y croyez, venait aussi de notre planète, il y a très, très longtemps.",,,"君はこの周りの廃墟群を見てきたはずだ。 +もっと多くの力が必要となるぞ...","아니야! 만약 네가 가질 수만 있다면, 그건 네 거야. 아마도 우리들을 탄압으로부터 구해줄 수 있겠네. 부디 행운을 빌어. 왜냐하면 많은 걸 준비 한 뒤 각오하고 들어가야 하거든.","Nee, als je het kunt vinden, is het aan jou om het te houden. Misschien kunt je het gebruiken om ons te bevrijden van onze onderdrukking. Ik zou je veel geluk wensen, maar je zult veel meer nodig hebben als je daar naar binnen gaat....","Nei! Hvis du finner den, kan du beholde den. Kanskje du kan bruke den til å frigjøre oss fra undertrykkelsen. Jeg skulle ønske deg lykke til, men du trenger mer enn det hvis du går inn dit...","Nie! Jeśli go znajdziesz, zatrzymasz go dla siebie. Może użyjesz jej, by pomóc nam uwolnić się od ucisku. Życzyłbym ci szczęścia, ale będziesz potrzebował o wiele więcej, jeśli tam wejdziesz...","Não! Se você conseguir achá-lo, fique com ele. Talvez você possa usá-lo para nos libertar dessa opressão. Eu te desejaria sorte, mas você vai precisar de muito mais do que isso se você entrar lá dentro...",,"Nu! Dacă o găsești, e a ta. Poate o poți folosi ca să ne ajuți să scăpăm de oprimare. Ți-aș ura noroc, dar o să ai noroc de mult mai mult decât atât dacă mergi acolo...","Нет! Если ты его найдёшь, он твой. Может быть, он поможет тебе освободить нас от гнёта. Я бы пожелал тебе удачи, но, если ты пойдёшь туда, простой удачи будет недостаточно...",,"Nej! Om du kan hitta den, får du behålla den. Du kanske kan använda den för att befria oss från vårt förtryck. Jag skulle önska dig lycka till, men du kommer att behöva mycket mer än så om du går in där...","Hayır! Eğer onu bulabilirsen, sende kalabilir. Belki onu bizi zulmümüzden kurtarmak için kullanabilirsin. Sana şans dilerdim, ama oraya girersen bundan çok daha fazlasına ihtiyacın olacak..." +What's all this about the past?,TXT_RPLY0_SCRIPT22_D4548_WHATS,〃,,,Cos to říkal o minulosti?,Hvad er alt det her med fortiden?,Was ist dieses ganze Gerede über die Vergangenheit?,,"Kio pri tiuj misteroj, kiujn vi menciis?",¿Qué hay de esos misterios que has mencionado?,¿Qué hay de esos misterios que mencionaste?,Mistä tässä kaikessa menneessä oikein on kyse?,Qu'est-ce que j'entends au sujet du passé?,És mi köze ennek a múlthoz?,E che mi dici riguardo a tutte ste storie del passato?,過去に何があったというんだ?,그 과거에 대해서 뭐가 어떻길레?,Wat is dit alles over het verleden?,Hva er alt dette om fortiden?,O co chodzi z tą przeszłością?,Que história é essa sobre o passado?,,Care e treaba cu trecutul ăsta?,Что такого творилось здесь в прошлом?,,Vad är allt det här om det förflutna?,Geçmişle ilgili tüm bu şeyler de ne? +"You've surely seen the other ruins nearby. It seems that the Comet which crashed on our planet is actually a space ship, and believe it or not, it originated on this very world a long time ago.",TXT_DLG_SCRIPT22_D6064_YOUVE,〃,,,"Určitě jsi zahlédnul ty zříceniny tady v okolí. Zdá se, že ta kometa, která narazila do naší planety, je ve skutečnosti vesmírná loď, která, věř nebo ne, kdysi dávno pocházela z tohoto světa.","Du har sikkert set de andre ruiner i nærheden. Det ser ud til, at den komet, der styrtede ned på vores planet, faktisk er et rumskib, og tro det eller ej, men det stammer fra denne verden for længe siden.","Du hast doch sicherlich die Ruinen hier in der Nähe gesehen. Es scheint als wäre der Komet, der hier auf dem Planeten aufgeschlagen ist, eigentlich ein Raumschiff, und ob du es glaubst oder nicht, aber es kam vor langer Zeit sogar von dieser Welt.",,"Vi eble vidis la proksimajn ruinojn. Ŝajnas, ke la kometo, kiu koliziis kontraŭ nia planedo, fakte estas kosmoŝipo, kaj kredeble aŭ ne, ĝi originis en ĉi tiu sama mondo antaŭ longe.","De seguro habrás visto las ruinas cerca de aquí. Al parecer el cometa que se estrelló en nuestro planeta es en realidad una nave espacial, y lo creas o no, se originó en este mismo mundo hace mucho.",,"Olet varmastikin nähnyt lähistön muut rauniot. Vaikuttaa siltä, että komeetta, joka törmäsi planeettaamme, on oikeasti avaruusalus; ja usko tai älä, se on alkuaan peräisin tästä samaisesta maailmasta kauan sitten.","Vous avez sans doute vu toutes ces ruines aux alentours. Il semble que la comète qui s'est écrasée sur notre planète était en fait un vaisseau spatial, et.. du moins si vous y croyez, venait aussi de notre planète, il y a très, très longtemps.","Bizonyára láttad a többi romot is. Úgy néz ki, a lehulló üstökös valójában egy űrhajó volt, és hiszed vagy sem, eredetileg erről a bolygóról indult sok évvel ezelőtt.","Sicuramente avrai visto le rovine qua vicino. Sembra che la cometa dell'impatto verso il nostro pianeta fosse in realtà una navicella spaziale, e so che può sembrare incredibile, ma la nave è originaria di questo mondo, di molto tempo fa.","君はこの周りの廃墟群を見てきたはずだ。 この星に衝突した彗星は、実は宇宙船だったのだ 信じられないかもしれないが、 -それは遥か前のこの乱世の始まりとも言える。","주변을 돌아다니면서 각종 폐허를 봤을 거야. 믿기지는 않겠지만, 하늘에서 갑자기 추락한 혜성은 정말로 혜성이 아니라 외계인들이 타고 내려온 우주선이라는 거야. 그리고 더 놀라운 사실은, 이 녀석들은 다 이곳에서 태어났데.","Je hebt zeker de andere ruïnes in de buurt gezien. Het lijkt erop dat de komeet die op onze planeet is neergestort, eigenlijk een ruimteschip is, en geloof het of niet, het is al lang geleden op deze wereld ontstaan.",,"Você certamente viu as outras ruínas aqui perto. Parece que o Cometa que caiu neste planeta é na verdade uma espaçonave e, acredite se quiser, ela veio deste nosso mundo há muito tempo atrás.",,,"Скорее всего, ты уже видел эти руины. Тот метеорит, который упал на нашу планету, — на самом деле это космический корабль. Веришь или нет, его построили на этой самой планете, давным-давно.", -"So the spectres, the One God...",TXT_RPLY0_SCRIPT22_D6064_SOTHE,,,,"Takže přízraky, Jeden bůh...","Also die Schemen, der Eine Gott...",,,"O sea que los espectros, el Dios Único...",,,"Donc, les Spectres, le Seul Dieu..",,,だから霊の、唯一神...,그래서 그 스펙터들과 유일신이...,"Dus de schrikbeelden, de Ene God....",,"Então os espectros, o Deus Único...",,,Так фантомы и Единый Бог..., -"They are creatures who once ruled this world and are bent on consuming its life. The ancients managed to seal them away, but gave their lives in the process. I'm afraid that's all I know.",TXT_DLG_SCRIPT22_D7580_THEYA,,,,"Jsou stvoření, která dříve vládla tomuto světu a teď usilují o zničení všeho živého. Kdosi před námi byl schopen je zapečetit a přišel během toho o život. To je vše, co vím.","Das sind Wesen, die einst diese Welt regiert haben und sie ausbeuten wollen. Die Alten haben es geschafft, sie wegzusperren aber verloren ihr Leben dabei. Tut mir leid, das ist alles, was ich weiß",,,"Son criaturas que una vez dominaron este mundo e insisten en consumir su vida. Los antiguos consiguieron sellarlos, pero dieron sus vidas en el proceso. Me temo que eso es todo lo que sé.",,,"Ce sont des créatures qui régnaient sur cette planète il y a longtemps, et étaient bornées à détruire toute vie sur sa surface, mais les anciens ont réussi à les sceller. Ils sont morts pour cela, j'ai peur que ce soit tout ce que je sais.",,,"奴等はかつてこの世界を支配していた生物で +それは遥か前のこの乱世の始まりとも言える。","주변을 돌아다니면서 각종 폐허를 봤을 거야. 믿기지는 않겠지만, 하늘에서 갑자기 추락한 혜성은 정말로 혜성이 아니라 외계인들이 타고 내려온 우주선이라는 거야. 그리고 더 놀라운 사실은, 이 녀석들은 다 이곳에서 태어났데.","Je hebt zeker de andere ruïnes in de buurt gezien. Het lijkt erop dat de komeet die op onze planeet is neergestort, eigenlijk een ruimteschip is, en geloof het of niet, het is al lang geleden op deze wereld ontstaan.","Du har sikkert sett de andre ruinene i nærheten. Det ser ut til at kometen som krasjet på planeten vår faktisk er et romskip, og tro det eller ei, det kom fra denne verdenen for lenge siden.","Na pewno widziałeś inne ruiny w pobliżu. Wygląda na to, że Kometa, która rozbiła się na naszej planecie jest tak naprawdę statkiem kosmicznym i wierzcie lub nie, pochodziła z tego właśnie świata dawno temu.","Você certamente viu as outras ruínas aqui perto. Parece que o Cometa que caiu neste planeta é na verdade uma espaçonave e, acredite se quiser, ela veio deste nosso mundo há muito tempo atrás.",,"Cu siguranță ai vazut ruinele din apropiere. Se pare că Cometa care a căzut e de fapt o navă spațială, și crezi sau nu, e originară din lumea asta, de acum mult timp.","Скорее всего, ты уже видел эти руины. Тот метеорит, который упал на нашу планету, — на самом деле это космический корабль. Веришь или нет, его построили на этой самой планете, давным-давно.",,"Du har säkert sett de andra ruinerna i närheten. Det verkar som om kometen som kraschade på vår planet faktiskt är ett rymdskepp, och tro det eller ej, den härstammar från just den här världen för länge sedan.","Yakındaki diğer kalıntıları görmüşsünüzdür. Görünüşe göre gezegenimize çarpan Kuyruklu Yıldız aslında bir uzay gemisi ve ister inanın ister inanmayın, uzun zaman önce tam da bu dünyada ortaya çıkmış." +"So the spectres, the One God...",TXT_RPLY0_SCRIPT22_D6064_SOTHE,〃,,,"Takže přízraky, Jeden bůh...","Så spøgelserne, den ene gud...","Also die Schemen, der Eine Gott...",,"Do la fantomoj, la Vera Dio...","O sea que los espectros, el Dios Único...",,"Joten aaveet, Yksi Ainoa Jumala...","Donc, les Spectres, le Seul Dieu..","Szóval a kísértetek, az egy isten...","Quindi gli spettri, l'Unico Dio..",だから霊の、唯一神...,그래서 그 스펙터들과 유일신이...,"Dus de schrikbeelden, de Ene God....","Så spøkelsene, den ene Gud...","Więc widma, Jedyny Bóg...","Então os espectros, o Deus Único...",,"Deci spectrele, Adevăratul Zeu...",Так фантомы и Единый Бог...,,"Så spökena, den enda guden...","Yani hayaletler, Tek Tanrı." +"They are creatures who once ruled this world and are bent on consuming its life. The ancients managed to seal them away, but gave their lives in the process. I'm afraid that's all I know.",TXT_DLG_SCRIPT22_D7580_THEYA,〃,,,"Jsou stvoření, která dříve vládla tomuto světu a teď usilují o zničení všeho živého. Kdosi před námi byl schopen je zapečetit a přišel během toho o život. To je vše, co vím.","De er væsener, der engang herskede over denne verden og er opsat på at fortære dens liv. Det lykkedes de gamle at forsegle dem, men de gav deres liv i processen. Jeg er bange for, at det er alt, hvad jeg ved.","Das sind Wesen, die einst diese Welt regiert haben und sie ausbeuten wollen. Die Alten haben es geschafft, sie wegzusperren aber verloren ihr Leben dabei. Tut mir leid, das ist alles, was ich weiß",,"Ili estas estaĵoj, kiuj iam dominis la mondon kaj insistas pri detrui ĝian vivon. La antikvuloj sukcese sigelfermis ilin koste de siaj vivoj. Mi timas, ke mi scias nenion plian.",Son criaturas que alguna vez dominaron el mundo e insisten en destruir toda forma de vida. Los antiguos lograron sellarlos a costa de sus vidas. Me temo que ya no sé más.,,"Ne ovat olentoja, jotka kerran hallitsivat tätä maailmaa ja ovat nyt päättäneet hävittää sen elämästä. Muinaisten onnistui teljetä heidät ulos, mutta siinä samassa uhrasivat henkensä. Valitettavasti en tiedä tämän enempää.","Ce sont des créatures qui régnaient sur cette planète il y a longtemps, et étaient bornées à détruire toute vie sur sa surface, mais les anciens ont réussi à les sceller. Ils sont morts pour cela, j'ai peur que ce soit tout ce que je sais.","Ezek olyan lények, akik korábban a világot uralták, és mindenek felett meg akarják enni a világ életerejét. Az ősöknek sikerült őket elzárni, de bele is pusztultak a procedúrába. Attól félek, csak ennyit tudok mondani.","Sono tutte creature che una volta controllavano questo mondo e hanno come obiettivo consumarne la vita. Gli antichi riuscirono a isolarli, al costo della loro vita. Purtroppo è tutto quello che so.","奴等はかつてこの世界を支配していた生物で 生命力をひたすら吸収する存在だった。 古代人が辛うじて封印したが、 その過程で彼らの命は奪われた。 -私が知っているのはそれだけだ。","한때 이 생물들은 이 세상을 지배했던 존재였어. 초월한 힘을 계속 유지하기 위해 온갖 생명력을 빨아먹어 왔던 거지. 태초의 사람들이 어떻게든 이 들을 봉인하긴 했지만, 많은 희생이 뒤따라야만 했지... 이게 내가 알고 있는 전부야.","Het zijn wezens die ooit over deze wereld heersten en die er op uit zijn om haar leven te consumeren. De Ouden slaagden erin om ze af te sluiten, maar gaven hun leven in het proces. Ik ben bang dat dat alles is wat ik weet.",,"São criaturas que uma vez dominavam este mundo e querem consumir toda a vida daqui. Os antigos conseguiram selá-los, mas deram suas vidas no processo. Infelizmente isso é tudo o que eu sei.",,,"Эти существа когда-то правили этим миром и стремились выжать из него все соки. Древние смогли запечатать и изгнать их, пожертвовав своими жизнями. Больше, боюсь, я ничего не знаю.", -Thanks... I'll do what I can.,TXT_RPLY0_SCRIPT22_D7580_THANK,,,,"Díky... Uvidím, co budu moct.",Danke. Ich werde tun was ich kann.,,,Gracias... Haré lo que pueda.,,,Merci.. Je vais faire ce que je peux.,,,ありがとう...精一杯の事をしよう。,고... 고마워. 내가 할 수 있는 것을 찾아보지.,Bedankt... Ik zal doen wat ik kan.,,Obrigado... Farei o possível.,,,"Спасибо... Я сделаю всё, что смогу.", -"Godspeed, friend.",TXT_DLG_SCRIPT22_D9096_GODSP,,,,"Zlom vaz, příteli.","Viel Erfolg, Freund.",,,"Buena suerte, amigo.",,,"Bonne chance, mon ami.",,,急ぎたまえ、同志よ。,"행운을 비네, 친구.","Goeie reis, vriend.",,"Boa sorte, amigo.",,,"Удачи, друг.", -Talk to the master smithy if you have questions. All I do is put labels on the crates.,TXT_DLG_SCRIPT22_D10612_TALKT,,,,"Promluv si s mistrem kovářem, jestli se chceš na něco zeptat. Já jenom dávám štítky na krabice.","Sprich mit dem Meister Smithy, wenn du Fragen hast. Ich versehe die Kisten nur mit Etiketten.",,,Habla con el maestro herrero si tienes preguntas. Todo lo que hago yo es etiquetar las cajas.,,,"Parlez au maître forgeron si vous avez des questions. Tout ce que je fais, c'est mettre des étiquettes sur des caisses.",,,"相談がある場合は鍛冶屋のマスターに仰って -下さい。私は箱にラベルを張っているだけです。",궁금한 게 있으면 스미시 제조장관님에게 물어봐. 내 업무는 상자에 표를 붙이는 것밖엔 없어.,Praat met de meestersmidij als je vragen hebt. Het enige wat ik doe is etiketten op de kratten plakken.,,Fale com o ferreiro-mestre se tiver dúvidas. Tudo o que eu faço aqui é colocar etiquetas nas caixas.,,,"Если у тебя есть какие-то вопросы, обратись к мастеру. Я просто подписываю ящики.", -"What can I get you, citizen?",TXT_DLG_SCRIPT23_D0_WHATC,,,,"Co ti mohu nabídnout, občane?","Was darf es sein, Bürger?",,,"¿Qué puedo ofrecerte, ciudadano?",,,"Qu'est-ce que je peux faire pour vous, citoyen?",,,何が入り用だ、お客さん?,"무엇을 줄까요, 형씨?","Wat kan ik voor je halen, burger?",,"Como posso ajudá-lo, cidadão?",,,"Что я могу тебе предложить, гражданин?", -Ammo box,TXT_RPLY0_SCRIPT23_D0_AMMOB,,,,Krabici nábojů,Munitionsschachtel,,,Caja de municiones,,,Boîte de munitions.,,,銃弾倉,돌격소총 탄약 박스,Munitiedoos,,Caixa de munição,,,Коробку патронов, -Here's your ammo.,TXT_RYES0_SCRIPT23_D0_HERES,,,,Tady je.,Hier ist deine Munition.,,,Aquí tienes tus municiones.,,,Voilà vos munitions.,,,これでソチラのブツだ。,탄약을 구매해줘서 고마워요.,Hier is je munitie.,,Aqui está a sua munição.,,,Вот твои патроны., -You don't have enough for that!,TXT_RNO0_SCRIPT23_D0_YOUDO,,,,Na tu nemáš dost peněz!,Du hast nich genug Gold!,,,¡No tienes suficiente para eso!,,,Vous n'avez pas assez d'argent.,,,そんだけの金持ってないぞ!,가격에 맞게 돈을 가져오세요!,Daar heb je niet genoeg voor!,,Você não tem o suficiente para isto.,,,У тебя недостаточно денег!, -Crate of missiles,TXT_RPLY1_SCRIPT23_D0_CRATE,,,,Bednu raket,Raketenkiste,,,Caja de misiles,,,Caisse de missiles.,,,ミサイル箱,미니 미사일 박스,Krat van raketten,,Caixa de mísseis,,,Коробку ракет, -"Here, citizen.",TXT_RYES1_SCRIPT23_D0_HEREC,,,,"Tady, občane.","Hier, Bürger.",,,"Toma, ciudadano.",,,"Voilà, citoyen.",,,どうぞ、お客さん。,여기 있습니다.,"Hier, burger.",,"Aqui, cidadão.",,,"Вот, гражданин.", -"It's 85 gold, citizen!",TXT_RNO1_SCRIPT23_D0_ITS85,,,,"Ta stojí 85 zlatých, občane!","Das macht 85 Gold, Bürger!",,,"¡Son 85 de oro, ciudadano!",,,"Cela coûte 85 pièces, citoyen!",,,85ゴールドだぜ、お客さん!,그건 85골드입니다.,"Het is 85 goud, burger!",,"Custa 85 moedas de ouro, cidadão!",,,"Это стоит 85 золотых, гражданин!", -H-E grenades,TXT_RPLY2_SCRIPT23_D0_HEGRE,,,,Výbušné granáty,HE-Granaten,,,Granadas HE,,,Grenades explosives.,,,HEグレネード,고폭 유탄,H-E-granaten,,Granadas explosivas,,,Осколочные гранаты, -Here are your grenades.,TXT_RYES2_SCRIPT23_D0_HEREA,,,,Tady jsou.,Hier sind deine Granaten.,,,Aquí tienes tus granadas.,,,Voilà vos grenades.,,,これでソチラのブツだ。,여기 유탄입니다.,Hier zijn je granaten.,,Aqui estão as suas granadas,,,Забирай свои гранаты., -"They are 100 gold, friend.",TXT_RNO2_SCRIPT23_D0_THEYA,,,,"Ty stojí sto zlatých, příteli.","Sie kosten 100 Gold, mein Freund.",,,"Son 100 de oro, amigo.",,,"Cela coûte 100 pièces, mon ami.",,,100ゴールドだぜ、旦那!,"그건 100 골드야, 친구.","Ze zijn 100 goud, vriend.",,"Custam 100 moedas, amigo.",,,"Они по 100 золотых, друг.", -Energy pod,TXT_RPLY3_SCRIPT23_D0_ENERG,,,,Energetický kokón,Energiezelle.,,,Vaina de energía,,,Cellule énergetique.,,,エネルギーポッド,에너지 포드,Energiecapsule,,Célula de energia.,,,Энергоячейку, -Here you are.,TXT_RYES3_SCRIPT23_D0_HEREY,,,,Tady je.,Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,どうぞ。,여기 있습니다.,Hier ben je dan.,,Aqui está.,,,Получай., -"That's 135 gold, sorry.",TXT_RNO3_SCRIPT23_D0_THATS,,,,"Ten stojí 135 zlatých, je mi líto.","Entschuldigung, aber das macht 135 Gold.",,,"Son 135 de oro, lo siento.",,,"Cela coûte 135 pièces, désolé.",,,135ゴールドなんだ、ワリィ!,"미안하지만, 그건 135 골드입니다.","Dat is 135 goud, sorry.",,Custa 135 moedas. Sinto muito.,,,Она стоит 135 золотых. Извини., -What can I assist you with?,TXT_DLG_SCRIPT23_D1516_WHATC,,,,S čím ti mohu pomoci?,Wie kann ich dir behilflich sein?,,,¿Con qué puedo ayudarte?,,,Commen puis-je vous assister?,,,何か手伝いましょうか?,어떤 걸 도와드릴까요?,Waarmee kan ik je helpen?,,Como posso ajudá-lo?,,,Чем я могу тебе помочь?, -Leather armor,TXT_RPLY0_SCRIPT23_D1516_LEATH,,,Leather armour,Kožené brnění,Lederrüstung,,,Armadura de cuero,,,Armure de cuir.,,,レザーアーマー,가죽 갑옷,Leren harnas,,Armadura de couro,,,Кожаной бронёй, -Here it is citizen.,TXT_RYES0_SCRIPT23_D1516_HEREI,,,,"Tady je, občane.","Hier ist sie, Bürger.",,,"Aquí está, ciudadano.",,,"Voilà pour vous, citoyen.",,,どうぞ、お客さん。,"여기 있어요, 형씨.",Hier is het een burger.,,"Aqui está, cidadão.",,,"Вот она, гражданин.", -There's no charity given here!,TXT_RNO0_SCRIPT23_D1516_THERE,,,,Nejsme charita!,Hier gibt es nichts umsonst!,,,¡Aquí no damos limosna!,,,On n'est pas une charité ici.,,,これはチャリティーじゃない!,돈이 부족하면 다른 곳을 알아봐! 여긴 자선단체가 아니라고!,Er wordt hier geen liefdadigheid gegeven!,,Aqui não é local de caridade!,,,Я благотворительностью не занимаюсь!, -Metal armor,TXT_RPLY1_SCRIPT23_D1516_METAL,,,Metal armour,Kovové brnění,Metallrüstung,,,Armadura de metal,,,Armure de métal.,,,メタルアーマー,강철 갑옷,Metalen harnas,,Armadura de metal,,,Металлической бронёй, -An excellent choice citizen.,TXT_RYES1_SCRIPT23_D1516_ANEXC,,,,"Výborná volba, občane.","Eine exzellente Wahl, Bürger.",,,"Excelente elección, ciudadano.",,,"Un excellent choix, citoyen.",,,良い選択です。,"탁월한 선택이십니다, 형씨.","Een uitstekende keuze, burger.",,"Excelente escolha, cidadão.",,,"Отличный выбор, гражданин.", -You don't have enough for this!,TXT_RNO1_SCRIPT23_D1516_YOUDO,,,,Na to nemáš dost peněz!,Du hast nich genug Gold dafür!,,,¡No tienes suficiente para esto!,,,Vous n'avez pas assez d'argent.,,,これでは足りない!,이것을 구입하기엔 돈이 부족합니다!,Je hebt hier niet genoeg voor!,,Você não tem o suficiente para isto!,,,У тебя недостаточно денег!, -Environmental suit,TXT_RPLY2_SCRIPT23_D1516_ENVIR,,,,Ochranný oděv,Schutzanzug.,,,Traje ambiental,,,Combinaison Hazmat.,,,耐環境スーツ,환경 방호복,Beschermend Pak,,Traje de proteção,,,Защитным костюмом, -Here you are.,TXT_RYES2_SCRIPT23_D1516_HEREY,,,,Tady máš.,Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,どうぞ。,여기 있습니다.,Hier ben je dan.,,Aqui está.,,,Держи., -"No money, no suit.",TXT_RNO2_SCRIPT23_D1516_NOMON,,,,Bez peněz pro oděvy nelez.,"Kein Geld, kein Anzug.",,,Sin dinero no hay traje.,,,"Pas d'argent, pas de combi.",,,金が無いならスーツは無しだ。,돈이 없다면 방호복을 줄 수 없습니다.,"Geen geld, geen pak.",,"Sem dinheiro, sem traje.",,,"Нет денег, нет костюма.", -Something different?,TXT_RPLY3_SCRIPT23_D1516_SOMET,,,,Něco jiného?,Irgendetwas anderes?,,,¿Algo distinto?,,,Quelque chose d'autre?,,,何か別のやつは?,뭔가 다른 거는?,Iets anders?,,Algo diferente?,,,Что-нибудь ещё?, -Go through the door down the hall.,TXT_RYES3_SCRIPT23_D1516_GOTHR,,,,Projdi dveřmi dole na chodbě.,Geh durch die Tür zur Halle.,,,Ve por la puerta pasillo abajo.,,,"Passez par la porte, vers le hall.",,,ホールのドアを通るんだ。,복도를 따라 문을 향해 가보세요.,Ga door de deur aan het einde van de gang.,,Passe pela porta lá no salão.,,,"Дальше по коридору, за дверью.", -You must pay if you want to play.,TXT_RNO3_SCRIPT23_D1516_YOUMU,,,,"Musíš zaplatit, jestli si chceš hrát.","Du musst bezahlen, wenn du spielen willst.",,,Debes pagar si quieres jugar.,,,Vous devez payer si vous voulez jouer.,,,プレイするなら支払うべきだ。,할려면 돈을 먼저 주세요.,Je moet betalen als je wilt spelen.,,Você precisa pagar se quiser jogar.,,,"Любишь играть, люби и платить!", -What can I get you?,TXT_DLG_SCRIPT23_D3032_WHATC,,,,Co ti mohu nabídnout?,Was darf es sein?,,,¿Qué puedo ofrecerte?,,,Que puis-je pour vous?,,,何をお求めで?,무엇을 드릴까요?,Wat kan ik voor je halen?,,O que gostaria?,,,Что я могу тебе предложить?, -Leather armor,TXT_RPLY0_SCRIPT23_D3032_LEATH,,,Leather armour,Kožené brnění,Lederrüstung,,,Armadura de cuero,,,Armure de cuir.,,,レザーアーマー,가죽 갑옷,Leren harnas,,Armadura de couro,,,Кожаную броню, -"Here it is, citizen.",TXT_RYES0_SCRIPT23_D3032_HEREI,,,,"Tady je, občane.","Hier ist sie, Bürger.",,,"Aquí está, ciudadano.",,,"Voilà pour vous, citoyen.",,,どうぞ、お客さん。,"적절히 입으세요, 시민.","Hier is het, burger.",,"Aqui está, cidadão.",,,"Вот она, гражданин.", -There's no charity given here!,TXT_RNO0_SCRIPT23_D3032_THERE,,,,Nejsme charita!,Hier gibt es nichts umsonst!,,,¡Aquí no damos limosna!,,,On n'est pas une charité ici.,,,これはチャリティーじゃない!,딴 데 가서 구걸하세요!,Er wordt hier geen liefdadigheid gegeven!,,Aqui não é local de caridade!,,,Я благотворительностью не занимаюсь!, -Metal armor,TXT_RPLY1_SCRIPT23_D3032_METAL,,,Metal armour,Kovové brnění,Metallrüstung,,,Armadura de metal,,,Armure de métal.,,,メタルアーマー,강철 갑옷,Metalen harnas,,Armadura de metal,,,Металлическую броню, -An excellent choice citizen.,TXT_RYES1_SCRIPT23_D3032_ANEXC,,,,"Výborná volba, občane.","Eine exzellente Wahl, Bürger.",,,"Excelente elección, ciudadano.",,,"Un excellent choix, citoyen.",,,良い選択だ。,탄탄한 게 잘 보호해준답니다.,Een uitstekende keuze voor de burger.,,"Excelente escolha, cidadão.",,,"Отличный выбор, гражданин.", -You don't have enough for this!,TXT_RNO1_SCRIPT23_D3032_YOUDO,,,,Na to nemáš dost peněz!,Du hast nich genug Gold dafür!,,,¡No tienes suficiente para esto!,,,Vous n'avez pas assez d'argent.,,,これでは足りない!,돈이 부족합니다. 다른 건 어떠신가요?,Je hebt hier niet genoeg voor!,,Você não tem o suficiente para isto!,,,У тебя недостаточно денег!, -Environmental suit,TXT_RPLY2_SCRIPT23_D3032_ENVIR,,,,Ochranný oděv,Schutzanzug.,,,Traje ambiental,,,Combinaison Hazmat.,,,耐環境スーツ,환경 방호복,Beschermend Pak,,Traje de proteção,,,Защитный костюм, -Here you are.,TXT_RYES2_SCRIPT23_D3032_HEREY,,,,Tady máš.,Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,どうぞ。,여기 받으세요!,Hier ben je dan.,,Aqui está.,,,Держи., -"No money, no suit.",TXT_RNO2_SCRIPT23_D3032_NOMON,,,,Bez peněz pro oděvy nelez.,"Kein Geld, kein Anzug.",,,Sin dinero no hay traje.,,,"Pas d'argent, pas de combi.",,,金が無いならスーツは無しだ。,방호복을 사기엔 돈이 부족합니다.,"Geen geld, geen pak.",,"Sem dinheiro, sem traje.",,,"Нет денег, нет костюма.", -How can I help you today?,TXT_DLG_SCRIPT23_D4548_HOWCA,,,,S čím ti mohu dnes pomoci?,Wie kann ich dir heute weiterhelfen?,,,¿Cómo puedo ayudarte hoy?,,,Comment puis-je vous aider aujourd'hui?,,,本日は何の用で?,환영합니다. 뭔가 필요하신지요?,Hoe kan ik u vandaag helpen?,,Como posso ajudá-lo hoje?,,,Чем я могу тебе помочь сегодня?, -Med patch,TXT_RPLY0_SCRIPT23_D4548_MEDPA,,,,Obvazy,Medizinische Bandage,,,Parche médico.,,,Pansement.,,,医薬パッチ,의료 붕대,Med-patch,,Compressa médica,,,Бинтами, -Here's your patch.,TXT_RYES0_SCRIPT23_D4548_HERES,,,,Tady jsou.,Hier ist deine Bandage.,,,Aquí tienes tu parche.,,,Voilà votre pansement.,,,これが貴方のパッチです。,의료 붕대 하나. 경마한 부상에 쓰시길.,Hier is je patch.,,Aqui está sua compressa.,,,Вот твой набор бинтов., -That is 15 gold my friend.,TXT_RNO0_SCRIPT23_D4548_THATI,,,,"Ty stojí patnáct zlatých, příteli.","Das macht 15 Gold, mein Freund.",,,"Son 15 de oro, amigo mío.",,,"15 pièces pour ça, mon ami.",,,これは15ゴールドですよ。,15 골드가 없습니까? 유감이군요.,"Dat is 15 goud, mijn vriend.",,"Custa 15 moedas de ouro, meu amigo.",,,"Они стоят 15 монет, друг.", -Medical kit,TXT_RPLY1_SCRIPT23_D4548_MEDIC,,,,Lékárničku,Verbandskasten,,,Kit médico,,,Kit médical.,,,医療用キット,구급 키트,Medische kit,,Kit médico,,,Аптечкой, -Here's your medical kit.,TXT_RYES1_SCRIPT23_D4548_HERES,,,,Tady je.,Hier ist dein Verbandskasten,,,Aquí tienes tu kit médico.,,,Voilà votre kit médical.,,,これが貴方のキットです。,구급 키트는 아주 유용하죠. 잘 쓰시길!,Hier is je medische uitrusting.,,Aqui está o seu kit médico,,,Вот твоя аптечка., -Your a bit low on funds for that.,TXT_RNO1_SCRIPT23_D4548_YOURA,,,,Na tu teď nemáš dost.,Du hast zu wenig Geld dafür.,,,Estás un poco bajo de efectivo para eso.,,,Vous manquez d'argent pour ça.,,,お金が少し足りませんよ。,돈이 부족하군요. 못 줍니다!,Je hebt daar een beetje weinig geld voor.,,Você está um pouco mal de dinheiro pra isso.,,,Тебе на это не хватает средств., -Field surgery kit,TXT_RPLY2_SCRIPT23_D4548_FIELD,,,,Chirurgickou soupravu,Erste-Hilfe-Kasten,,,Kit quirúrgico,,,Kit de chirurgie.,,,手術キット,수술 키트,Veld chirurgie kit,,Kit de cirurgia,,,Медкомплектом, -One field surgery kit.,TXT_RYES2_SCRIPT23_D4548_ONEFI,,,,Jedna souprava.,"Eine Erste-Hilfe-Kasten, kommt sofort.",,,Un kit quirúrgico.,,,"Un kit de chirurgie, voilà.",,,手術キット一丁。,아주 위박한 상황에 쓰시길. 여기 수술 키트입니다!,Een veldoperatiekit.,,Um kit de cirurgia.,,,Один медкомплект. Держи., -Come back when you have money!,TXT_RNO2_SCRIPT23_D4548_COMEB,,,,"Vrať se, až budeš mít peníze!","Komm wieder, wenn du etwas Geld hast.",,,¡Vuelve cuando tengas dinero!,,,Revenez quand vous avez des sous?,,,お金が有る時にまた!,"돈이 많이 있으면 모를까, 살 수 없을겁니다!",Kom terug als je geld hebt!,,Volte quando tiver dinheiro!,,,Возвращайся с деньгами!, -"Hello friend, what can I get you?",TXT_DLG_SCRIPT23_D6064_HELLO,,,,"Zdravím, příteli, co pro tebe mohu udělat?","Hallo Freund, was darf es sein?",,,"Hola amigo, ¿Qué puedo ofrecerte?",,,"Bienvenu, l'ami, que puis-je pour vous?",,,よう旦那、何が必要だ?,좋은 하루! 뭐 필요한거라도?,"Hallo vriend, wat kan ik voor je halen?",,"Olá amigo, como posso te ajudar?",,,"Привет, друг. Могу я тебе что-нибудь предложить?", -Information,TXT_RPLY0_SCRIPT23_D6064_INFOR,,,,Informace,Informationen,,,Información,,,Des infos.,,,情報,정보 있습니까?,Informatie,,Informações,,,Информацию, -"I've never seen anyone go in or out of the factory, the forcefield's always up.",TXT_RYES0_SCRIPT23_D6064_IVENE,,,,"Nikdy jsem nikoho neviděl vcházet do ani vycházet z továrny, silové pole je vždycky zapnuté.","Ich habe noch niemanden gesehen, der die Fabrik betreten oder verlassen hat. Das Kraftfeld ist immer aktiv.",,,"Nunca he visto a nadie entrar o salir de la fábrica, el campo de fuerza siempre está encendido.",,,Je n'ai jamais vu quelqu'un rentrer dans l'usine. Les champs de force sont toujours en ligne.,,,"誰も工場を出入りしている所を見ていない、 -フォースフィールドがずっと付いてる。",공장에서 나오는 사람들을 전혀 못 봤어. 방어막이 꺼지는 일이 없었으니까.,"Ik heb nog nooit iemand in of uit de fabriek zien gaan, het krachtveld is altijd in orde.",,Nunca vi alguém entrar ou sair da fábrica. O campo de força está sempre ativado.,,,"Никогда не видел, чтобы кто-нибудь приходил на фабрику или уходил с неё. Поле всегда включено.", -"No money, no info.",TXT_RNO0_SCRIPT23_D6064_NOMON,,,,"Žádné peníze, žádné informace.","Kein Geld, keine Informationen.",,,Sin dinero no hay información.,,,"Pas d'argent, pas d'infos.",,,金が無いなら情報は無しだ。,"돈 없으면, 정보도 없다네.","Geen geld, geen informatie.",,"Sem grana, nada de informações.",,,"Нет денег, нет сведений.", -"Yes, what would you like?",TXT_DLG_SCRIPT23_D7580_YESWH,,,,"Ano, co by sis přál?","Ja, was darf es sein?",,,"Sí, ¿Qué quieres?",,,"Oui, que voulez-vous?",,,はい、どうしたい?,"아, 무엇을 원하는가?","Ja, wat wil je graag?",,"Sim, o que você gostaria?",,,Да? Что ты хотел?, -More info.,TXT_RPLY0_SCRIPT23_D7580_MOREI,,,,Další informace.,Mehr Informationen.,,,Más información.,,,Plus d'infos.,,,更なる情報,정보가 필요해요.,Meer info.,,Mais informações.,,,Ещё сведений., -The factory's built on the comet's impact site. I don't think it's by chance.,TXT_RYES0_SCRIPT23_D7580_THEFA,,,,"Továrna je postavená na místě dopadu komety. Nemyslím si, že to je náhoda.","Die Fabrik wurde dort gebaut, wo der Komet eingeschlagen ist. Ich denke nicht, dass das Zufall ist.",,,La fábrica está construida sobre el lugar de impacto del cometa. No creo que sea casualidad.,,,L'usine est construite sur le site d'impact de la comète. Je ne crois pas que c'est une coïncidence.,,,"工場は彗星の衝突地点に建っている。 -これは偶然だと思えない。",공장은 혜성이 충돌한 지점에서 건설되었다네. 우연으로 건설된 게 아니라고 생각해.,De fabriek is gebouwd op de impact van de komeet site. Ik denk niet dat het toeval is.,,A fábrica foi construída no local de impacto do cometa. Não acho que tenha sido por acaso.,,,"Фабрика была построена в кратере от падения метеорита. Не думаю, что это случайность.", -"Come on, it's a measly 5 gold.",TXT_RNO0_SCRIPT23_D7580_COMEO,,,,"No tak, je to jen pět zlatých.","Komm schon, es sind doch nur 5 mickrige Goldstücke.",,,"Venga, solo 5 míseras monedas de oro.",,,"Allez, ça ne coûte que 5 pièces!",,,頼むぜ、たった5ゴールドだぞ。,5 골드 정도 하는데 말이지.,"Kom op, het is een miezerige 5 goud.",,"Vamos lá, custa só 5 moedinhas.",,,"Ну же, всего-то 5 золотых.", -"Hello again, what'll it be?",TXT_DLG_SCRIPT23_D9096_HELLO,,,,"Opět ahoj, co to bude?",Willkommen zurück. Was darf es sein?,,,"Hola otra vez, ¿Qué va a ser?",,,"Rebonjour, que puis-je pour vous?",,,また来たな、何か頼むか?,다시 만났군. 오늘은 어떤 걸?,"Hallo nogmaals, wat zal het zijn?",,Olá de novo. O que vai ser desta vez?,,,И снова привет. Что на этот раз?, -More info.,TXT_RPLY0_SCRIPT23_D9096_MOREI,,,,Další informace.,Mehr Informationen.,,,Más información.,,,Plus d'infos.,,,更なる情報,더 많은 정보를 원해요.,Meer info.,,Mais informações.,,,Ещё информацию., -The factory closed when the Order unveiled its new horror: the Inquisitor.,TXT_RYES0_SCRIPT23_D9096_THEFA,,,,Továrnu zavřeli když Řád odkryl svou novou hrůzu: Inkvizitora.,"Die Fabrik wurde geschlossen, als der Orden seinen neuesten Horror enthült hat: Den Inquisitor.",,,La fábrica cerró cuando la Orden desveló su nuevo horror: el inquisidor.,,,"L'usine a été fermée quand l'Ordre a révélé sa nouvelle atrocité, L'inquisiteur.",,,"工場はオーダーの「新審問官」が来てから -恐ろしい雰囲気を纏った。",오더가 획기적이고 무서운 병기들을 생산한 후 공장의 문을 닫았다네. 그 것들의 이름은 '인퀴지터'지.,De fabriek werd gesloten toen de Orde haar nieuwe horror onthulde: de inquisiteur.,,A fábrica fechou quando a Ordem revelou o seu novo horror: o Inquisidor.,,,"Фабрика закрылась, когда Орден показал своё новое страшилище — инквизитора.", -5 gold please.,TXT_RNO0_SCRIPT23_D9096_5GOLD,,,,"Pět zlatých, prosim.","5 Gold, bitte.",,,5 de oro por favor.,,,"5 pièces, s'il vous plaît.",,,5ゴールドかかるぜ。,먼저 5 골드를 주게나.,5 goud alsjeblieft.,,5 moedas por favor.,,,"5 золотых, пожалуйста.", -"That's all I know. Even bartenders run out of stuff to say, sorry.",TXT_DLG_SCRIPT23_D10612_THATS,,,,"To je vše, co vím. I barmani občas nemají, co dál říct, promiň.","Das ist alles was ich weiß. Selbst ein Barkeeper hat irgendwann keine Neugikeiten mehr, tut mir Leid.",,,"Eso es todo lo que sé. Incluso los taberneros se quedan sin cosas que decir, lo siento.",,,"C'est tout ce que je sais. Même les barmans peuvent arriver à court d'infos, désolé.",,,"知ってることはこれで全部だ。 -バーテンダーの噂は売切れだ、すまない。",이 바텐더는 꺼낼 수 있는 모든 조언을 꺼냈다네. 미안.,"Dat is alles wat ik weet. Zelfs de barmannen hebben niet veel meer te zeggen, sorry.",,"Isso é tudo o que eu sei. Até donos de bar acabam ficando sem algo pra dizer uma hora, sinto muito.",,,"Это всё, что я знаю. Даже у хозяев таверн заканчиваются темы для болтовни, увы.", -Hello.,TXT_DLG_SCRIPT23_D12128_HELLO,,,,Ahoj.,Hallo.,,,Hola.,,,Bonjour.,,,こんにちは。,안녕하세요.,Hallo.,,Olá.,,,Привет., -What are you doing?,TXT_RPLY0_SCRIPT23_D12128_WHATA,,,,Co tady děláš?,Was machst du?,,,¿Qué estás haciendo?,,,Qu'est-ce que vous faites?,,,何してるんだ?,뭐하는 거죠?,Wat ben je aan het doen?,,O que você está fazendo?,,,Чем ты занимаешься?, -"I'm doing stuff, go away!",TXT_RYES0_SCRIPT23_D12128_IMDOI,,,,"Dělám věci, vypadni!","Ich mach' halt was, geh weg!",,,"Estoy haciendo cosas, ¡Lárgate!",,,"Je suis occupé, laissez-moi tranquille!",,,今は立て込んでる、離れなさい!,별거 아닙니다. 방해하지 말고 저리 가세요!,"Ik doe dingen, ga weg!",,"Estou fazendo coisas, vá embora!",,,Ерундой всякой. Отвали!, -"Now, what can I help you with?",TXT_DLG_SCRIPT23_D13644_NOWWH,,,,"Tak, s čím ti mohu pomoci?","Nun, wie kann ich dir weiterhelfen?",,,"Ahora, ¿En qué puedo ayudarte?",,,"Bon, que puis-je pour vous?",,,今手伝ってくれるか?,"자, 제가 뭘 도와드릴까요?","Nu, waar kan ik je mee helpen?",,"Então, como posso ajudá-lo?",,,"Итак, чем я могу быть тебе полезен?", -Shadow armor?,TXT_RPLY0_SCRIPT23_D13644_SHADO,,,Shadow armour?,Stínové brnění?,Schattenrüstung?,,,¿Armadura de sombra?,,,Armure des ombres?,,,シャドウアーマー?,그림자 갑옷?,Schaduw harnas?,,Armadura das sombras?,,,Теневой бронёй?, -"Ahh, to be heard, but not seen!",TXT_RYES0_SCRIPT23_D13644_AHHTO,,,,"Áha, být slyšen, ne viděn!","Ah, um gehört zu werden, aber ungesehen zu bleiben.",,,"Ah, ¡para ser oído, pero no visto!",,,"Ah, pour se faire entendre, sans se faire voir!",,,ああ、声はすれど姿は見えず。,하하하... 아주 조용하고 보이지 않는 도구죠!,"Ahhh, om gehoord, maar niet gezien te worden!",,"Ahh, ser ouvido mas não ser visto!",,,"Ах, чтобы быть услышанным, но не увиденным!", -"Get out of here, come back when you have some cash.",TXT_RNO0_SCRIPT23_D13644_GETOU,,,,"Vypadni a vrať se, když budeš mít peníze.","Verzieh dich, komm wieder, wenn du etwas Geld hast.",,,"Vete de aquí, vuelve cuando tengas algo de efectivo.",,,"Sortez de là, revenez quand vous avez de l'argent!",,,ここを出て、稼いでからまた来てくれ!,"저리 가, 돈이 있을 때나 여길 찾으라고요.","Ga hier weg, kom terug als je wat geld hebt.",,Vá embora daqui. Volte quando tiver dinheiro.,,,"Выметайся вон. Вернёшься, когда раздобудешь наличности.", -"Thank Deus you got here. To enter the factory you need a key. We stole it but our agent is missing in the web of catacombs under the Order's stronghold. I have sent ten good men into those tunnels to find him, and none have returned. Something is down there!",TXT_DLG_SCRIPT23_D15160_THANK,,,,"Díky bohu, žes přišel. Aby ses dostal do továrny, potřebuješ klíč. Ten jsme ukradli, ale náš agent se ztratil v sítí katakomb pod pevností Řádu. Poslal jsem do těch tunelů deset dobrých mužů a žádný se nevrátil. Něco tam dole je!","Deus sei dank bist du hier. Um die Fabrik zu betreten, brauchst du einen Schlüssel. Wir haben ihn gestohlen, aber unser Agent ist in den Irrwegen der Katakomben unter der Festung des Ordens verschollen. Ich habe zehn gute Männer da hinunter geschickt um ihn zu finden, aber niemand ist zurückgekehrt. Irgendetwas ist da unten!",,,"Gracias a deus que estás aquí. Para entrar en la fábrica necesitas una llave. La robamos, pero nuestro agente está perdido en la red de catacumbas debajo de la fortaleza de la Orden. He enviado diez buenos hombres a esos túneles para encontrarlo, y ninguno ha regresado. ¡Hay algo ahí abajo!",,,"Merci Dieu, vous êtes là. Pour entrer dans l'usine, il vous faut une clé. On l'a volé, mais notre agent a disparu dans le dédale de catacombes sous la forteresse de l'Ordre. On a envoyé dix hommes dans ces tunnels pour le retrouver mais personne n'est revenu. Il doit y avoir quelque chose, là dedans!",,,"ようやく来てくれたか。 +私が知っているのはそれだけだ。","한때 이 생물들은 이 세상을 지배했던 존재였어. 초월한 힘을 계속 유지하기 위해 온갖 생명력을 빨아먹어 왔던 거지. 태초의 사람들이 어떻게든 이 들을 봉인하긴 했지만, 많은 희생이 뒤따라야만 했지... 이게 내가 알고 있는 전부야.","Het zijn wezens die ooit over deze wereld heersten en die er op uit zijn om haar leven te consumeren. De Ouden slaagden erin om ze af te sluiten, maar gaven hun leven in het proces. Ik ben bang dat dat alles is wat ik weet.","De er vesener som en gang styrte denne verden og er oppsatt på å fortære dens liv. De gamle klarte å stenge dem inne, men ga sine liv i prosessen. Jeg er redd det er alt jeg vet.","To istoty, które kiedyś rządziły tym światem i mają zamiar pochłonąć jego życie. Starożytni zdołali je zapieczętować, ale oddali za to życie. Obawiam się, że to wszystko, co wiem.","São criaturas que uma vez dominavam este mundo e querem consumir toda a vida daqui. Os antigos conseguiram selá-los, mas deram suas vidas no processo. Infelizmente isso é tudo o que eu sei.",,"Sunt creaturi care au condus cândva lumea asta și sunt determinați să-i consume toată viața. Cei antici au reușit să-i alunge, dar și-au dat viața pentru a reuși. Mă tem că asta e tot ce știu.","Эти существа когда-то правили этим миром и стремились выжать из него все соки. Древние смогли запечатать и изгнать их, пожертвовав своими жизнями. Больше, боюсь, я ничего не знаю.",,"De är varelser som en gång styrde den här världen och är fast beslutna att förtära dess liv. De gamla lyckades försegla dem, men gav sina liv i processen. Jag är rädd att det är allt jag vet.",Onlar bir zamanlar bu dünyaya hükmetmiş ve yaşamı tüketmeye kararlı yaratıklar. Eskiler onları mühürlemeyi başardılar ama bu süreçte canlarını verdiler. Korkarım tüm bildiğim bu. +Thanks... I'll do what I can.,TXT_RPLY0_SCRIPT22_D7580_THANK,〃,,,"Díky... Uvidím, co budu moct.","Tak... Jeg vil gøre, hvad jeg kan.",Danke. Ich werde tun was ich kann.,,Dankon... Mi faros ĉion eblan.,Gracias... Haré lo que pueda.,Gracias... Voy a hacer lo que pueda.,"Kiitos; teen, minkä pystyn.",Merci.. Je vais faire ce que je peux.,Kösz...megteszem amit tudok.,Grazie... farò il possibile.,ありがとう...精一杯の事をしよう。,고... 고마워. 내가 할 수 있는 것을 찾아보지.,Bedankt... Ik zal doen wat ik kan.,Takk skal du ha... Jeg skal gjøre hva jeg kan.,"Dzięki... Zrobię, co w mojej mocy.",Obrigado... Farei o possível.,,Merci... O să fac ce pot.,"Спасибо... Я сделаю всё, что смогу.",,Tack... Jag ska göra vad jag kan.,Teşekkürler. Elimden geleni yapacağım. +"Godspeed, friend.",TXT_DLG_SCRIPT22_D9096_GODSP,〃,,,"Zlom vaz, příteli.","Held og lykke, min ven.","Viel Erfolg, Freund.",,"Ŝancon, amiko.","Buena suerte, amigo.",,"Onnea matkaan, ystävä.","Bonne chance, mon ami.","Isten veled, barátom.","Ti auguro davvero di farcela, amico mio.",急ぎたまえ、同志よ。,"행운을 비네, 친구.","Goeie reis, vriend.","Lykke til, min venn.","Powodzenia, przyjacielu.","Boa sorte, amigo.",,"Noroc, prietene.","Удачи, друг.",,"Lycka till, min vän.","Yolun açık olsun, dostum." +Talk to the master Smithy if you have questions. All I do is put labels on the crates.,TXT_DLG_SCRIPT22_D10612_TALKT,"SVE.WAD +MAP22: C-shaped building → Apprentice.",,,"Promluv si s mistrem Smithym, jestli se chceš na něco zeptat. Já jenom dávám štítky na krabice.","Tal med mester Smithy, hvis du har spørgsmål. Jeg sætter bare etiketter på kasserne.","Sprich mit dem Meister Smithy, wenn du Fragen hast. Ich versehe die Kisten nur mit Etiketten.",,Parolu kun la majstro Smithy se vi havas demandojn. Mi limas min etiketi skatolojn.,Habla con el maestro Smithy si tienes preguntas. Lo único que hago yo es etiquetar las cajas.,,"Puhu pajamestarin kanssa, jos sinulla on kysyttävää. Minä vain leimaan laatikoita.","Parlez au maître Smithy si vous avez des questions. Tout ce que je fais, c'est mettre des étiquettes sur des caisses.",Beszélj Smithy mesterrel ha van kérdésed. Én csak címkéket rakok a hordókra.,Parla con il mastro Smithy se hai delle domande. Il mio unico compito è catalogare gli scatoli.,"相談がある場合は鍛冶屋のマスターに仰って +下さい。私は箱にラベルを張っているだけです。",궁금한 게 있으면 스미시 제조장관님에게 물어봐. 내 업무는 상자에 표를 붙이는 것밖엔 없어.,Praat met meester Smithy als je vragen hebt. Het enige wat ik doe is etiketten op de kratten plakken.,"Snakk med smedmesteren hvis du har spørsmål. Alt jeg gjør, er å sette etiketter på kassene.","Porozmawiaj z mistrzem Smithy, jeśli masz pytania. Ja tylko naklejam etykiety na skrzyniach.",Fale com o mestre Smithy se tiver dúvidas. Tudo o que eu faço aqui é colocar etiquetas nas caixas.,,Vorbește cu maestrul Smithy dacă ai întrebări. Tot ce fac eu e să pun embleme pe cutii.,"Если у тебя есть какие-то вопросы, обратись к мастеру-кузнецу. Я просто клею ярлыки на ящики.",,Prata med mästersmeden om du har frågor. Allt jag gör är att sätta etiketter på lådorna.,Sorunuz olursa Demirci Usta ile konuşun. Tek yaptığım kasaların üzerine etiket yapıştırmak. +"What can I get you, citizen?",TXT_DLG_SCRIPT23_D0_WHATC,MAP23: Weapons,,,"Co vám mohu nabídnout, občane?","Hvad kan jeg skaffe dig, borger?","Was darf es sein, Bürger?",,"Kion mi donu al vi, civitano?","¿Qué puedo ofrecerte, ciudadano?",,"Mitä saisi olla, kansalainen?","Qu'est-ce que je peux faire pour vous, citoyen?","Miben segíthetek, polgártárs?","Che ti serve, cittadino?",何が入り用だ、お客さん?,"무엇을 줄까요, 형씨?","Wat kan ik voor je halen, burger?","Hva vil du ha, borger?","Co mogę ci dać, obywatelu?","Como posso ajudá-lo, cidadão?",,"Ce pot să-ți aduc, cetățeanule?","Что я могу тебе предложить, гражданин?",,"Vad vill du ha, medborgare?","Sana ne verebilirim, vatandaş?" +Ammo box,TXT_RPLY0_SCRIPT23_D0_AMMOB,〃,,,Krabici nábojů,Ammo kasse,Munitionsschachtel,,Munici-keston,Caja de municiones,,Ammuslaatikko,Boîte de munitions.,Lőszer doboz,Scatola di munizioni,銃弾倉,돌격소총 탄약 박스,Munitiedoos,En ammunisjonskasse.,Skrzynia z amunicją,Caixa de munição,,Cutie cu muniție,Коробку патронов,,Ammunitionslåda,Cephane kutusu +Here's your ammo.,TXT_RYES0_SCRIPT23_D0_HERES,〃,,,Tady je.,Her er din ammunition.,Hier ist deine Munition.,,Jen via municio.,Aquí está tu munición.,,Tässä ammuksesi.,Voilà vos munitions.,Itt a lőszered.,Ecco le tue munizioni.,これでソチラのブツだ。,탄약을 구매해줘서 고마워요.,Hier is je munitie.,Her er ammunisjonen din.,To twoja amunicja.,Aqui está a sua munição.,,Aici e muniția.,Вот твои патроны.,,Här är din ammunition.,İşte cephanen. +You don't have enough for that!,TXT_RNO0_SCRIPT23_D0_YOUDO,〃,,,Na tu nemáš dost peněz!,Du har ikke nok til det!,Du hast nich genug Gold!,,"Vi ne havas +sufiĉe da mono!",¡No te alcanza para eso!,,Sinulla ei riitä rahat sitä varten!,Vous n'avez pas assez d'argent.,Nincs elég ehhez nálad!,Non hai abbastanza soldi per quello!,そんだけの金持ってないぞ!,가격에 맞게 돈을 가져오세요!,Daar heb je niet genoeg voor!,Du har ikke nok til det!,Nie masz na to dość!,Você não tem o suficiente para isto.,,Nu ai suficiente fonduri pentru asta.,У тебя недостаточно денег!,,Du har inte tillräckligt med ammunition för det!,Bunun için yeterince cephanen yok! +Crate of missiles,TXT_RPLY1_SCRIPT23_D0_CRATE,〃,,,Bednu raket,Kasse med missiler,Raketenkiste,,Misilet-keston,Caja de minimisiles,,Ohjuslaatikko,Caisse de missiles.,Ládányi rakéta,Cassa di razzi,ミサイル箱,미니 미사일 박스,Krat van raketten,Kasse med raketter,Skrzynia z pociskami,Caixa de mísseis,,Cutie de rachete.,Коробку ракет,,Låda med missiler,Füze sandığı +"Here, citizen.",TXT_RYES1_SCRIPT23_D0_HEREC,〃,,,"Tady, občane.","Her, borger.","Hier, Bürger.",,"Jen, civitano.","Toma, ciudadano.",,"Tässä, kansalainen.","Voilà, citoyen.","Parancsolj, polgártárs.","Ecco qua, cittadino",どうぞ、お客さん。,여기 있습니다.,"Hier, burger.","Her, borger.","Proszę, obywatelu.","Aqui, cidadão.",,"Aici, orășene.","Вот, гражданин.",,"Här, medborgare.","Buyur, vatandaş." +"It's 85 gold, citizen!",TXT_RNO1_SCRIPT23_D0_ITS85,〃,,,"Ta stojí 85 zlatých, občane!","Det koster 85 guld, borger!","Das macht 85 Gold, Bürger!",,"Ĝi kostas 85 da oro, +civitano!","¡Son 85 de oro, ciudadano!",,"Se maksaa 85 kolikkoa, kansalainen!","Cela coûte 85 pièces, citoyen!","85 arany lesz, polgártárs.","Sono 85 pezzi d'oro, cittadino!",85ゴールドだぜ、お客さん!,그건 85골드입니다.,"Het is 85 goud, burger!","Det er 85 gull, borger!","To 85 złotych, obywatelu!","Custa 85 moedas de ouro, cidadão!",,"E 85 de monezi, orășene!","Гражданин, это стоит 85 золотых!",,"Det är 85 guld, medborgare!","85 altın, vatandaş!" +H-E grenades,TXT_RPLY2_SCRIPT23_D0_HEGRE,〃,,,Výbušné granáty,H-E granater,HE-Granaten,,Eksplodeg-povajn grenadojn,Granadas de conmoción,,Räjähdekranaatteja,Grenades explosives.,Robbanó gránátok,Granate ad alto potenziale esplosivo,HEグレネード,고폭 유탄,H-E-granaten,H-E-granater,Granaty H-E,Granadas explosivas,,Grenade.,Осколочные гранаты,,H-E-granater,H-E el bombaları +Here are your grenades.,TXT_RYES2_SCRIPT23_D0_HEREA,〃,,,Tady jsou.,Her er dine granater.,Hier sind deine Granaten.,,Jen viaj grenadoj.,Aquí tienes tus granadas.,,Tässä kranaattisi.,Voilà vos grenades.,Itt vannak a gránátaid.,Ecco le tue granate.,これでソチラのブツだ。,여기 유탄입니다.,Hier zijn je granaten.,Her er granatene dine.,Oto twoje granaty.,Aqui estão as suas granadas,,Aici sunt grenadele.,Забирай свои гранаты.,,Här är dina granater.,İşte el bombaların. +"They are 100 gold, friend.",TXT_RNO2_SCRIPT23_D0_THEYA,〃,,,"Ty stojí sto zlatých, příteli.","De koster 100 guld, ven.","Sie kosten 100 Gold, mein Freund.",,"Ili kostas cent da oro, +amiko!","Son cien de oro, amigo.",,"Ne maksavat 100 kolikkoa, ystäväiseni.","Cela coûte 100 pièces, mon ami.",100 aranyba kerülnek polgártársam.,"Ti servono 100 pezzi d'oro, amico.",100ゴールドだぜ、旦那!,"그건 100 골드야, 친구.","Ze zijn 100 goud, vriend.","De koster 100 gull, min venn.","Kosztują 100 złota, przyjacielu.","Custam 100 moedas, amigo.",,"Costă 100 de monezi, prietene.","Они по 100 золотых, друг.",,"De kostar 100 guld, vän.","Onlar 100 altın, dostum." +Energy pod,TXT_RPLY3_SCRIPT23_D0_ENERG,〃,,,Energetický kokón,Energibælg,Energiezelle.,,Energi-kapsulon,Cápsula de energía,,Energia-akku,Cellule énergetique.,Energia cella,Nucleo energetico,エネルギーポッド,에너지 포드,Energiecapsule,Energikapsel,Strąk energii,Célula de energia.,,Capsulă energetică.,Энергоячейку,,Energipod,Enerji kapsülü +Here you are.,TXT_RYES3_SCRIPT23_D0_HEREY,〃,,,Tady je.,Værsgo.,Bitteschön.,,Jen.,Toma.,,"Tässä, ole hyvä.",Voilà pour vous.,Parancsolj.,Eccolo qua.,どうぞ。,여기 있습니다.,Hier ben je dan.,Vær så god.,Proszę bardzo.,Aqui está.,,Aici este.,Получай.,,Här är den.,Buyurun. +"That's 135 gold, sorry.",TXT_RNO3_SCRIPT23_D0_THATS,〃,,,"Ten stojí 135 zlatých, je mi líto.","Den koster 135 guld, beklager.","Entschuldigung, aber das macht 135 Gold.",,"Ĝi kostas 135 da oro. +Pardonon.","Son 135 de oro, lo siento.",,"Se 135 kolikkoa, valitan.","Cela coûte 135 pièces, désolé.","Sajnálom, de az 135 arany.","Mi spiace, ma costa 135 pezzi d'oro.",135ゴールドなんだ、ワリィ!,"미안하지만, 그건 135 골드입니다.","Dat is 135 goud, sorry.","Det er 135 gull, beklager.","To 135 złota, przepraszam.",Custa 135 moedas. Sinto muito.,,"Costă 135 de monezi, scuze.",Она стоит 135 золотых. Извини.,,"Den kostar 135 guld, tyvärr.","Bu 135 altın, üzgünüm." +What can I assist you with?,TXT_DLG_SCRIPT23_D1516_WHATC,MAP23: Armory (with Tevick locked).,,,S čím vám mohu pomoci?,Hvad kan jeg hjælpe dig med?,Wie kann ich dir behilflich sein?,,Kion vi bezonas?,¿Con qué puedo ayudarte?,,Miten voin auttaa?,Commen puis-je vous assister?,Miben segíthetek?,Come posso esserti utile?,何か手伝いましょうか?,어떤 걸 도와드릴까요?,Waarmee kan ik je helpen?,Hva kan jeg hjelpe deg med?,W czym mogę ci pomóc?,Como posso ajudá-lo?,,Cu ce te pot ajuta?,Чем я могу тебе помочь?,,Vad kan jag hjälpa dig med?,Size nasıl yardımcı olabilirim? +Leather armor,TXT_RPLY0_SCRIPT23_D1516_LEATH,〃,,Leather armour,Kožené brnění,Læder rustning,Lederrüstung,,Ledan armaĵon,Armadura de cuero,,Nahkasuojus,Armure de cuir.,Bőr vért,Armatura di cuoio,レザーアーマー,가죽 갑옷,Leren harnas,Skinnrustning.,Skórzana zbroja.,Armadura de couro,,Armură de piele,Кожаной бронёй,,Läderrustning,Deri zırh +Here it is citizen.,TXT_RYES0_SCRIPT23_D1516_HEREI,〃,,,"Tady je, občane.","Her er den, borger.","Hier ist sie, Bürger.",,"Jen, civitano.","Toma, ciudadano.",,"Tässä on, kansalainen.","Voilà pour vous, citoyen.",Parancsolj.,"Ecco qua, cittadino.",どうぞ、お客さん。,"여기 있어요, 형씨.",Hier is het een burger.,"Her er den, borger.","Oto ona, obywatelu.","Aqui está, cidadão.",,Aici e orășene.,"Вот она, гражданин.",,"Här är den, medborgare.",İşte vatandaş. +There's no charity given here!,TXT_RNO0_SCRIPT23_D1516_THERE,〃,,,Nejsme charita!,Der gives ingen velgørenhed her!,Hier gibt es nichts umsonst!,,"Ĉi tio ne estas +almozulejo!",¡Aquí no damos limosna!,,Täällä ei harrasteta hyväntekeväisyyttä!,On n'est pas une charité ici.,"Sajnálom, ez nem jótékonyság.",Non facciamo beneficienza!,これはチャリティーじゃない!,돈이 부족하면 다른 곳을 알아봐! 여긴 자선단체가 아니라고!,Er wordt hier geen liefdadigheid gegeven!,Det er ingen veldedighet her!,Nie ma tu żadnej dobroczynności!,Aqui não é local de caridade!,,Nu facem caritate aici!,Я благотворительностью не занимаюсь!,,Det finns ingen välgörenhet här!,Burada sadaka verilmez! +Metal armor,TXT_RPLY1_SCRIPT23_D1516_METAL,〃,,Metal armour,Kovové brnění,Metal rustning,Metallrüstung,,Metalan armaĵon,Armadura de metal,,Metallihaarniska,Armure de métal.,Fém vért,Armatura di metallo,メタルアーマー,강철 갑옷,Metalen harnas,Metall rustning,Metalowa zbroja.,Armadura de metal,,Armură de metal,Металлической бронёй,,Metall rustning,Metal zırh +An excellent choice citizen.,TXT_RYES1_SCRIPT23_D1516_ANEXC,〃,,,"Výborná volba, občane.","Et glimrende valg, borger.","Eine exzellente Wahl, Bürger.",,"Bonega elekto, civitano.","Excelente elección, +ciudadano.",,"Erinomainen valinta, kansalainen.","Un excellent choix, citoyen.",Kiváló választás polgártárs.,"Ottima scelta, cittadino.",良い選択です。,"탁월한 선택이십니다, 형씨.","Een uitstekende keuze, burger.","Et utmerket valg, borger.","Doskonały wybór, obywatelu.","Excelente escolha, cidadão.",,Excelentă alegere orășene.,"Отличный выбор, гражданин.",,"Ett utmärkt val, medborgare.",Mükemmel bir seçim vatandaş. +You don't have enough for this!,TXT_RNO1_SCRIPT23_D1516_YOUDO,〃,,,Na to nemáte dost peněz!,Du har ikke nok til dette!,Du hast nich genug Gold dafür!,,"Vi ne havas +sufiĉe da mono!",¡No te alcanza!,,Rahasi ei riitä siihen!,Vous n'avez pas assez d'argent.,Nincs elég ehhez nálad!,Non hai abbastanza soldi per questo!,これでは足りない!,이것을 구입하기엔 돈이 부족합니다!,Je hebt hier niet genoeg voor!,Du har ikke nok til dette!,Nie masz na to dość!,Você não tem o suficiente para isto!,,Nu ai suficiente fonduri pentru asta!,У тебя недостаточно денег!,,Du har inte tillräckligt för detta!,Bunun için yeterli değilsin! +Environmental suit,TXT_RPLY2_SCRIPT23_D1516_ENVIR,〃,,,Ochranný oblek,Miljødragt,Schutzanzug.,,Medi-ŝirman veston,Traje NBQ,,Ympäristösuojapuku,Combinaison Hazmat.,Védőruha,Tuta ambientale,耐環境スーツ,환경 방호복,Beschermend Pak,Miljødrakt,Kombinezon ekologiczny,Traje de proteção,,Costum de Protecție împotriva Mediului,Защитным костюмом,,Miljödräkt,Çevre kıyafeti +Here you are.,TXT_RYES2_SCRIPT23_D1516_HEREY,〃,,,Tady máte.,Værsgo.,Bitteschön.,,Jen.,Toma.,,Kas tässä.,Voilà pour vous.,"Itt van, parancsolj.",Eccola qua.,どうぞ。,여기 있습니다.,Hier ben je dan.,Vær så god.,Proszę bardzo.,Aqui está.,,Aici este.,Держи.,,Här är du.,İşte buradasın. +"No money, no suit.",TXT_RNO2_SCRIPT23_D1516_NOMON,〃,,,Bez peněz pro oděvy nelez.,"Ingen penge, ingen dragt.","Kein Geld, kein Anzug.",,"Sen mono +ne estas vesto.",Sin dinero no hay traje.,,"Ei rahaa, ei pukua.","Pas d'argent, pas de combi.","Ha nincs pénz, nincs védőruha.","Niente denaro, niente completo.",金が無いならスーツは無しだ。,돈이 없다면 방호복을 줄 수 없습니다.,"Geen geld, geen pak.","Ingen penger, ingen drakt.","Nie ma pieniędzy, nie ma kombinezonu.","Sem dinheiro, sem traje.",,"Niciun ban, niciun costum.","Нет денег, нет костюма.",,"Inga pengar, ingen dräkt.","Para yok, takım elbise yok." +Something different?,TXT_RPLY3_SCRIPT23_D1516_SOMET,〃,,,Něco jiného?,Noget andet?,Irgendetwas anderes?,,Ion alian...?,¿Algo distinto?,,Jotain erilaista?,Quelque chose d'autre?,Valami mást esetleg?,Qualcos'altro?,何か別のやつは?,뭔가 다른 거는?,Iets anders?,Noe annet?,Coś innego?,Algo diferente?,,Ceva diferit?,Что-нибудь ещё?,,Något annat?,Farklı bir şey mi var? +Go through the door down the hall.,TXT_RYES3_SCRIPT23_D1516_GOTHR,〃,,,Jděte dveřmi dole na chodbě.,Gå gennem døren nede ad gangen.,Geh durch die Tür zur Halle.,,"Iru ĉe Tevick en la +dekstra ĉambro.","Con Tevick en la +habitación a la derecha.",,Mene ovesta käytävän päässä.,"Passez par la porte, vers le hall.",Menj át a csarnok végén levő ajtón.,Vai oltre la porta alla fine della stanza.,ホールのドアを通るんだ。,복도를 따라 문을 향해 가보세요.,Ga door de deur aan het einde van de gang.,Gå gjennom døren i gangen.,Przejdź przez drzwi na końcu korytarza.,Passe pela porta lá no salão.,,Intră pe ușa din josul holului.,"Дальше по коридору, за дверью.",,Gå genom dörren i korridoren.,Koridorun sonundaki kapıdan geç. +You must pay if you want to play.,TXT_RNO3_SCRIPT23_D1516_YOUMU,〃,,,Chceš si hrát? Zaplať.,"Du skal betale, hvis du vil spille.","Du musst bezahlen, wenn du spielen willst.",,Nenio estas senpaga.,Nada es gratis.,,"Ken leikkiin ryhtyy, se leikistä maksakoon.",Vous devez payer si vous voulez jouer.,Fizetned kell hogy játszhass.,Devi pagare se vuoi giocare.,プレイするなら支払うべきだ。,할려면 돈을 먼저 주세요.,Je moet betalen als je wilt spelen.,Du må betale hvis du vil spille.,"Musisz zapłacić, jeśli chcesz grać.",Você precisa pagar se quiser jogar.,,Trebuie să plătești dacă vrei să joci.,"Любишь играть, люби и платить!",,Du måste betala om du vill spela.,Oynamak istiyorsan ödeme yapmalısın. +What can I get you?,TXT_DLG_SCRIPT23_D3032_WHATC,MAP23: Armory (with Tevick unlocked).,,,Co vám mohu nabídnout?,Hvad kan jeg give dig?,Was darf es sein?,,Kion mi donu al vi?,¿Qué puedo ofrecerte?,,Mitä teille saisi olla?,Que puis-je pour vous?,Mit adhatok?,Cosa ti porto?,何をお求めで?,무엇을 드릴까요?,Wat kan ik voor je halen?,Hva vil du ha?,Co mogę ci dać?,O que gostaria?,,Ce pot să-ți aduc?,Что я могу тебе предложить?,,Vad kan jag ge dig?,Sana ne verebilirim? +Leather armor,TXT_RPLY0_SCRIPT23_D3032_LEATH,〃,,Leather armour,Kožené brnění,En læderrustning,Lederrüstung,,Ledan armaĵon,Armadura de cuero,,Nahkasuojus,Armure de cuir.,Bőr vért,Armatura di cuoio,レザーアーマー,가죽 갑옷,Leren harnas,En skinnrustning.,Skórzaną zbroję.,Armadura de couro,,Armură de piele,Кожаную броню,,En läderrustning,Deri zırh. +"Here it is, citizen.",TXT_RYES0_SCRIPT23_D3032_HEREI,〃,,,"Tady je, občane.","Her er den, borger.","Hier ist sie, Bürger.",,"Jen, civitano.","Toma, ciudadano.",,"Tästä saat, kansalainen.","Voilà pour vous, citoyen.","Parancsolj, polgártárs.","Ecco qua, cittadino.",どうぞ、お客さん。,"적절히 입으세요, 시민.","Hier is het, burger.","Vær så god, borger.","Oto ona, obywatelu.","Aqui está, cidadão.",,"Aici este, orășene.","Вот она, гражданин.",,"Här är den, medborgare.","İşte burada, vatandaş." +There's no charity given here!,TXT_RNO0_SCRIPT23_D3032_THERE,〃,,,Nejsme charita!,Der gives ingen velgørenhed her!,Hier gibt es nichts umsonst!,,"Ĉi tio ne estas +almozulejo!",¡Aquí no damos limosna!,,Tämä ei ole mikään hyväntekeväisyyspulju!,On n'est pas une charité ici.,"Sajnálom, ez nem jótékonyság.",Non facciamo beneficienza!,これはチャリティーじゃない!,딴 데 가서 구걸하세요!,Er wordt hier geen liefdadigheid gegeven!,Det er ingen veldedighet her!,Nie ma tu dobroczynności!,Aqui não é local de caridade!,,Nu facem caritate aici!,Я благотворительностью не занимаюсь!,,Det finns ingen välgörenhet här!,Burada sadaka verilmez! +Metal armor,TXT_RPLY1_SCRIPT23_D3032_METAL,〃,,Metal armour,Kovové brnění,Metal rustning,Metallrüstung,,Metalan armaĵon,Armadura de metal,,Metallihaarniska,Armure de métal.,Fém vért,Armatura di metallo,メタルアーマー,강철 갑옷,Metalen harnas,Metall rustning,Metalowa zbroja.,Armadura de metal,,Armură de metal,Металлическую броню,,Metallrustning,Metal zırh +An excellent choice citizen.,TXT_RYES1_SCRIPT23_D3032_ANEXC,〃,,,"Výborná volba, občane.","Et fremragende valg, borger.","Eine exzellente Wahl, Bürger.",,"Bonega elekto, civitano.","Excelente elección, +ciudadano.",,"Erinomainen valinta, kansalainen.","Un excellent choix, citoyen.",Kiváló választás polgártárs.,"Ottima scelta, cittadino.",良い選択だ。,탄탄한 게 잘 보호해준답니다.,Een uitstekende keuze voor de burger.,"Et utmerket valg, borger.",Doskonały wybór obywatelu.,"Excelente escolha, cidadão.",,Excelentă alegere orășene.,"Отличный выбор, гражданин.",,"Ett utmärkt val, medborgare.",Mükemmel bir seçim vatandaş. +You don't have enough for this!,TXT_RNO1_SCRIPT23_D3032_YOUDO,〃,,,Na to nemáte dost peněz!,Du har ikke nok til dette!,Du hast nich genug Gold dafür!,,"Vi ne havas +sufiĉe da mono!",¡No te alcanza!,,Sinulla ei rahat riitä siihen!,Vous n'avez pas assez d'argent.,Nincs elég ehhez nálad!,Non hai abbastanza soldi per questo!,これでは足りない!,돈이 부족합니다. 다른 건 어떠신가요?,Je hebt hier niet genoeg voor!,Du har ikke nok til dette!,Nie masz na to dość!,Você não tem o suficiente para isto!,,Nu ai suficiente fonduri pentru asta!,У тебя недостаточно денег!,,Du har inte tillräckligt för detta!,Bunun için yeterli değilsin! +Environmental suit,TXT_RPLY2_SCRIPT23_D3032_ENVIR,〃,,,Ochranný oblek,Miljødragt,Schutzanzug.,,Medi-ŝirman veston,Traje NBQ,,Ympäristösuojapuku,Combinaison Hazmat.,Védő ruha,Tuta ambientale,耐環境スーツ,환경 방호복,Beschermend Pak,Miljødrakt,Kombinezon ekologiczny,Traje de proteção,,Costum de Protecție împotriva Mediului,Защитный костюм,,Miljödräkt,Çevre kıyafeti +Here you are.,TXT_RYES2_SCRIPT23_D3032_HEREY,〃,,,Tady máte.,Her er du.,Bitteschön.,,Jen.,Toma.,,Olkaa hyvä.,Voilà pour vous.,Parancsolj.,Eccoti qui.,どうぞ。,여기 받으세요!,Hier ben je dan.,Vær så god.,Proszę bardzo.,Aqui está.,,Aici este.,Держи.,,Här är du.,İşte buradasın. +"No money, no suit.",TXT_RNO2_SCRIPT23_D3032_NOMON,〃,,,Bez peněz pro oděvy nelez.,"Ingen penge, ingen dragt.","Kein Geld, kein Anzug.",,"Sen mono +ne estas vesto.",Sin dinero no hay traje.,,"Ei rahaa, ei pukua.","Pas d'argent, pas de combi.","Ha nincs pénz, nincs védőruha.","Niente denaro, niente completo.",金が無いならスーツは無しだ。,방호복을 사기엔 돈이 부족합니다.,"Geen geld, geen pak.","Ingen penger, ingen drakt.","Nie ma pieniędzy, nie ma kombinezonu.","Sem dinheiro, sem traje.",,"Niciun ban, niciun costum.","Нет денег, нет костюма.",,"Inga pengar, ingen dräkt.","Para yok, takım elbise yok." +How can I help you today?,TXT_DLG_SCRIPT23_D4548_HOWCA,MAP23: Hospital,,,S čím vám mohu dnes pomoci?,Hvordan kan jeg hjælpe dig i dag?,Wie kann ich dir heute weiterhelfen?,,Kiel mi helpu vin hodiaŭ?,¿Cómo puedo ayudarte hoy?,,Miten voin tänään olla avuksi?,Comment puis-je vous aider aujourd'hui?,Miben segíthetek ezen a szép napon?,Come posso aiutarti oggi?,本日は何の用で?,환영합니다. 뭔가 필요하신지요?,Hoe kan ik u vandaag helpen?,Hvordan kan jeg hjelpe deg i dag?,Jak mogę ci dziś pomóc?,Como posso ajudá-lo hoje?,,Cu ce te pot ajuta azi?,Чем я могу тебе помочь сегодня?,,Hur kan jag hjälpa dig i dag?,Bugün size nasıl yardımcı olabilirim? +Med patch,TXT_RPLY0_SCRIPT23_D4548_MEDPA,〃,,,Obvazy,Medicinsk plaster,Medizinische Bandage,,Kuracbendoj,Tiritas,Curitas,Sidekäärettä,Pansement.,Ragtapasz,Bende,医薬パッチ,의료 붕대,Med-patch,Medisinplaster,Bandaż,Compressa médica,,Bandaj medical,Бинтами,,Medicinsk plåster,İlaç yaması +Here's your patch.,TXT_RYES0_SCRIPT23_D4548_HERES,〃,,,Tady jsou.,Her er dit plaster.,Hier ist deine Bandage.,,Jen viaj kuracbendoj,Aquí tienes tus tiritas.,Aquí tienes tus curitas.,Tässä kääreesi.,Voilà votre pansement.,Itt a tapaszod.,Ecco le tue bende.,これが貴方のパッチです。,의료 붕대 하나. 경마한 부상에 쓰시길.,Hier is je patch.,Her er plasteret ditt.,Oto twój bandaż.,Aqui está sua compressa.,,Aici e bandajul.,Вот твой набор бинтов.,,Här är ditt plåster.,İşte yaman. +That is 15 gold my friend.,TXT_RNO0_SCRIPT23_D4548_THATI,〃,,,"Ty stojí patnáct zlatých, příteli.","Det er 15 guld, min ven.","Das macht 15 Gold, mein Freund.",,"Ili kostas dek kvin +da oro, amiko.","Son quince de oro, amigo.",,"Se maksaa 15 kolikkoa, ystäväiseni.","15 pièces pour ça, mon ami.",15 arany lesz barátocskám.,Sono 15 pezzi d'oro amico mio.,これは15ゴールドですよ。,15 골드가 없습니까? 유감이군요.,"Dat is 15 goud, mijn vriend.","Det er 15 gull, min venn.","To jest 15 złota, mój przyjacielu.","Custa 15 moedas de ouro, meu amigo.",,E 15 monezi prietene.,"Они стоят 15 монет, друг.",,"Det är 15 guld, min vän.",Bu 15 altın dostum. +Medical kit,TXT_RPLY1_SCRIPT23_D4548_MEDIC,〃,,,Lékárničku,Medicinsk kit,Verbandskasten,,Sukurkesto,Botiquín,,Lääkintälaukku,Kit médical.,Elsősegély doboz,Kit medico,医療用キット,구급 키트,Medische kit,Medisinsk utstyr,Zestaw medyczny,Kit médico,,Kit medical,Аптечкой,,Medicinsk utrustning,Tıbbi kit +Here's your medical kit.,TXT_RYES1_SCRIPT23_D4548_HERES,〃,,,Tady je.,Her er dit medicinske kit.,Hier ist dein Verbandskasten,,Jen via sukurkesto.,Aquí tienes tu botiquín.,,Tässä lääkintälaukkusi.,Voilà votre kit médical.,Itt az elsősegély dobozod.,Ecco il tuo kid medico.,これが貴方のキットです。,구급 키트는 아주 유용하죠. 잘 쓰시길!,Hier is je medische uitrusting.,Her er medisinskrinet ditt.,Oto twój zestaw medyczny.,Aqui está o seu kit médico,,Aici e kitul medical.,Вот твоя аптечка.,,Här är ditt medicinska utrustning.,İşte tıbbi çantan. +Your a bit low on funds for that.,TXT_RNO1_SCRIPT23_D4548_YOURA,〃,,,Na tu nemáte dost.,Du har lidt for få midler til det.,Du hast zu wenig Geld dafür.,,Mankas mono al vi.,Estás algo falto de dinero.,,Rahasi eivät ihan riitä siihen.,Vous manquez d'argent pour ça.,Kevés lesz a pénzed ehhez most.,Sei un po' a corto di fondi per quello.,お金が少し足りませんよ。,돈이 부족하군요. 못 줍니다!,Je hebt daar een beetje weinig geld voor.,Du har litt lite penger til det.,Trochę brakuje ci na to funduszy.,Você está um pouco mal de dinheiro pra isso.,,Cam puțini bani pentru aia.,Тебе на это не хватает средств.,,Du har inte så mycket pengar för det.,Bunun için biraz az paran var. +Field surgery kit,TXT_RPLY2_SCRIPT23_D4548_FIELD,〃,,,Chirurgickou soupravu,Kirurgisæt,Erste-Hilfe-Kasten,,Kirurgia kesto,Kit quirúrgico,,Kenttäkirurgilaukku,Kit de chirurgie.,Harctéri műtéti felszerelés,Kit chirurgico,手術キット,수술 키트,Veld chirurgie kit,Kirurgisett,Zestaw do chirurgii polowej,Kit de cirurgia,,Kit chirurgical de teren.,Медкомплектом,,Fältkirurgisk utrustning,Saha ameliyat kiti +One field surgery kit.,TXT_RYES2_SCRIPT23_D4548_ONEFI,〃,,,Jedna souprava.,Et kirurgisæt.,"Eine Erste-Hilfe-Kasten, kommt sofort.",,Kirurgia kesto. Farite.,Un kit quirúrgico. Listo.,,"Yksi kirurgilaukku, tässä.","Un kit de chirurgie, voilà.","Parancsolj, egy műtéti felszerelés.","Un kit chirurgico, eccolo qua.",手術キット一丁。,아주 위박한 상황에 쓰시길. 여기 수술 키트입니다!,Een veldoperatiekit.,Ett kirurgisk sett.,Jeden zestaw do chirurgii polowej.,Um kit de cirurgia.,,"Un kit chirurgical de teren, gata.",Один медкомплект. Держи.,,Ett fältkirurgiskt utrustning.,Bir saha ameliyat kiti. +Come back when you have money!,TXT_RNO2_SCRIPT23_D4548_COMEB,〃,,,"Vrať se, až budeš mít peníze!","Kom tilbage, når du har penge!","Komm wieder, wenn du etwas Geld hast.",,"Revenu kiam vi +havos monon!","¡Vuelve cuando +tengas dinero!",,"Tule takaisin, kun sinulla on rahaa!",Revenez quand vous avez des sous?,"Akkor gyere vissza, ha pénzed is lesz!",Torna quando avrai del denaro!,お金が有る時にまた!,"돈이 많이 있으면 모를까, 살 수 없을겁니다!",Kom terug als je geld hebt!,Kom tilbake når du har penger!,"Wróć, gdy będziesz miał pieniądze!",Volte quando tiver dinheiro!,,Revino când o să ai bani!,Возвращайся с деньгами!,,Kom tillbaka när du har pengar!,Paran olduğunda geri gel! +"Hello friend, what can I get you?",TXT_DLG_SCRIPT23_D6064_HELLO,MAP23: Barkeep.,,,"Zdravím, příteli, co pro vás mohu udělat?","Hej ven, hvad kan jeg give dig?","Hallo Freund, was darf es sein?",,"Saluton, amiko. Kion mi donu al vi?","Hola, amigo. ¿Qué puedo ofrecerte?",,"Tervehdys, ystävä; miten voin olla avuksi?","Bienvenu, l'ami, que puis-je pour vous?","Szevasz barátom, miben segíthetek?","Salve amico, cosa posso darti?",よう旦那、何が必要だ?,좋은 하루! 뭐 필요한거라도?,"Hallo vriend, wat kan ik voor je halen?","Hei venn, hva kan jeg gi deg?","Witaj przyjacielu, co mogę ci dać?","Olá amigo, como posso te ajudar?",,"Bună prietene, ce pot să-ți aduc?","Привет, друг. Могу я тебе что-нибудь предложить?",,"Hej vän, vad vill du ha?","Merhaba arkadaşım, sana ne getirebilirim?" +Information,TXT_RPLY0_SCRIPT23_D6064_INFOR,〃,,,Informace,,Informationen,,Informojn,Información,,Tietoa.,Des infos.,Információ,Informazioni,情報,정보 있습니까?,Informatie,Informasjon.,Informacje,Informações,,Informație,Информацию,,,Bilgi +"I've never seen anyone go in or out of the factory, the forcefield's always up.",TXT_RYES0_SCRIPT23_D6064_IVENE,〃,,,Nikdy jsem nikoho neviděl vcházet do ani vycházet z továrny. Silové pole je vždycky zapnuté.,"Jeg har aldrig set nogen gå ind eller ud af fabrikken, kraftfeltet er altid oppe.","Ich habe noch niemanden gesehen, der die Fabrik betreten oder verlassen hat. Das Kraftfeld ist immer aktiv.",,"Mi neniam vidis, ke iu iris en la fabrikon +aŭ el ĝi: la fortokampo ĉiam estas ŝaltita.","Jamás he visto a nadie entrar o salir +de la fábrica: nunca apagan la barrera.",,En ole nähnyt kenenkään koskaan menevän tai tulevan tehtaasta; voimakenttä on aina päällä.,Je n'ai jamais vu quelqu'un rentrer dans l'usine. Les champs de force sont toujours en ligne.,"Nem láttam még senkit ki- vagy be menni a gyárból, az erőpajzs mindig be van kapcsolva.","Non ho mai visto nessuno entrare o uscire dalla fabbrica, il campo di forza è sempre attivo.","誰も工場を出入りしている所を見ていない、 +フォースフィールドがずっと付いてる。",공장에서 나오는 사람들을 전혀 못 봤어. 방어막이 꺼지는 일이 없었으니까.,"Ik heb nog nooit iemand in of uit de fabriek zien gaan, het krachtveld is altijd in orde.","Jeg har aldri sett noen gå inn eller ut av fabrikken, kraftfeltet er alltid oppe.","Nigdy nie widziałem nikogo wchodzącego ani wychodzącego z fabryki, pole siłowe jest zawsze podniesione.",Nunca vi alguém entrar ou sair da fábrica. O campo de força está sempre ativado.,,"N-am văzut niciodată pe cineva intrând sau ieșind din fabrică, câmpul de forță e mereu activ.","Никогда не видел, чтобы кто-нибудь приходил или уходил с фабрики. Поле всегда включено.",,"Jag har aldrig sett någon gå in eller ut ur fabriken, kraftfältet är alltid uppe.","Kimsenin fabrikaya girip çıktığını görmedim, güç alanı her zaman açık." +"No money, no info.",TXT_RNO0_SCRIPT23_D6064_NOMON,〃,,,"Žádné peníze, žádné informace.","Ingen penge, ingen info.","Kein Geld, keine Informationen.",,Sen mono ne estas informoj,Sin dinero no hay información.,,"Ei tuohta, ei tietoa.","Pas d'argent, pas d'infos.","Ha nincs pénz, nincs infó.","Niente denaro, niente informazioni.",金が無いなら情報は無しだ。,"돈 없으면, 정보도 없다네.","Geen geld, geen informatie.","Ingen penger, ingen informasjon.","Nie ma pieniędzy, nie ma informacji.","Sem grana, nada de informações.",,"Niciun ban, nicio informație.",Нет денег — нет сведений.,,"Inga pengar, ingen information.","Para yok, bilgi yok." +"Yes, what would you like?",TXT_DLG_SCRIPT23_D7580_YESWH,〃,,,"Ano, co byste si přál?","Ja, hvad vil du gerne have?","Ja, was darf es sein?",,"Jes, kion vi ŝatus?","Sí, ¿qué quieres?",,"Niin, mitä saisi olla?","Oui, que voulez-vous?","Igen, milyen érdekelne?","Sì, che posso darti?",はい、どうしたい?,"아, 무엇을 원하는가?","Ja, wat wil je graag?","Ja, hva vil du ha?","Tak, czego chcesz?","Sim, o que você gostaria?",,"Da, ce ai dori?",Да? Что ты хотел?,,"Ja, vad vill du ha?","Evet, ne istiyorsunuz?" +More info.,TXT_RPLY0_SCRIPT23_D7580_MOREI,〃 (dot not recommended),,,Další informace.,Mere info.,Mehr Informationen.,,Pliajn informojn,Más información,,Lisää tietoa.,Plus d'infos.,Több információ.,Più informazioni.,更なる情報,정보가 필요해요.,Meer info.,Mer informasjon.,Więcej informacji.,Mais informações.,,Mai multă informație.,Ещё сведений.,,Mer information.,Daha fazla bilgi. +The factory's built on the comet's impact site. I don't think it's by chance.,TXT_RYES0_SCRIPT23_D7580_THEFA,〃,,,"Továrnu postavili na místě dopadu komety. Nemyslím si, že to je náhoda.","Fabrikken er bygget på kometens nedslagssted. Jeg tror ikke, det er tilfældigt.","Die Fabrik wurde dort gebaut, wo der Komet eingeschlagen ist. Ich denke nicht, dass das Zufall ist.",,"Ili konstruis la fabrikon en la kometa +kratero, kvazaŭ tio estis hazarda koincido.","Construyeron la fábrica en el cráter +que dejó el cometa. No puede ser casualidad.",,"Tehdas on rakennettu komeetan törmäyspaikalle; enkä usko, että sattumalta.",L'usine est construite sur le site d'impact de la comète. Je ne crois pas que c'est une coïncidence.,A gyár a becsapódott üstökösre épült. Biztosan nem lehet véletlen.,La fabbrica è stata costruita sopra il sito d'impatto della cometa. Non credo sia una coincidenza.,"工場は彗星の衝突地点に建っている。 +これは偶然だと思えない。",공장은 혜성이 충돌한 지점에서 건설되었다네. 우연으로 건설된 게 아니라고 생각해.,De fabriek is gebouwd op de impact van de komeet site. Ik denk niet dat het toeval is.,Fabrikken er bygget på kometens nedslagssted. Jeg tror ikke det er tilfeldig.,"Fabryka została zbudowana na miejscu uderzenia komety. Nie sądzę, żeby to był przypadek.",A fábrica foi construída no local de impacto do cometa. Não acho que tenha sido por acaso.,,Fabrica e construită pe locul de prăbușire al cometei. Nu cred că e o coincidență.,"Фабрика была построена в кратере от падения метеорита. Не думаю, что это случайность.",,Fabriken är byggd på kometens nedslagsplats. Jag tror inte att det är en slump.,Fabrika kuyruklu yıldızın çarpma alanına inşa edildi. Bunun tesadüf olduğunu sanmıyorum. +"Come on, it's a measly 5 gold.",TXT_RNO0_SCRIPT23_D7580_COMEO,〃,,,"No tak, chci pouhých pět zlatých.","Kom nu, det er sølle 5 guld.","Komm schon, es sind doch nur 5 mickrige Goldstücke.",,"Ulo, mi petas nur kvin +mizerajn monerojn.","Venga, solo cinco míseras +monedas de oro.","Vamos, solo cinco míseras +monedas de oro.","Hei, antaisit nyt vaivaiset viisi kolikkoa.","Allez, ça ne coûte que 5 pièces!","Nemár, francos 5 arany.","Andiamo, sono solo 5 pezzi d'oro.",頼むぜ、たった5ゴールドだぞ。,5 골드 정도 하는데 말이지.,"Kom op, het is een miezerige 5 goud.","Kom igjen, det er sølle fem gull.","Daj spokój, to marne 5 złotych.","Vamos lá, custa só 5 moedinhas.",,"Haide, sunt 5 bănuți amărâți.","Ну же, всего-то 5 золотых.",,"Kom igen, det är bara 5 guld.","Hadi ama, sadece 5 altın." +"Hello again, what'll it be?",TXT_DLG_SCRIPT23_D9096_HELLO,〃,,,"Opět zdravím, co to bude?","Hej igen, hvad bliver det?",Willkommen zurück. Was darf es sein?,,Saluton denove. Kion vi petos?,Hola otra vez. ¿Qué va a ser?,,"Hei taas, mitä kaipaat?","Rebonjour, que puis-je pour vous?","Üdv újra itt, mit kérsz?","Chi si rivede, che cosa c'è?",また来たな、何か頼むか?,다시 만났군. 오늘은 어떤 걸?,"Hallo nogmaals, wat zal het zijn?","Hallo igjen, hva skal det være?","Witam ponownie, co to będzie?",Olá de novo. O que vai ser desta vez?,,"Bună din nou, ce dorești?",И снова привет. Что на этот раз?,,"Hej igen, vad vill du ha?","Tekrar merhaba, ne alırdınız?" +More info.,TXT_RPLY0_SCRIPT23_D9096_MOREI,〃 (dot not recommended),,,Další informace.,Mere info.,Mehr Informationen.,,Pliajn informojn,Más información,,Lisää tietoa.,Plus d'infos.,Több információ.,Altre informazioni,更なる情報,더 많은 정보를 원해요.,Meer info.,Mer informasjon.,Więcej informacji.,Mais informações.,,Mai multă informație.,Ещё информацию.,,Mer information.,Daha fazla bilgi. +The factory closed when the Order unveiled its new horror: the Inquisitor.,TXT_RYES0_SCRIPT23_D9096_THEFA,〃,,,Továrnu zavřeli když Řád odkryl svou novou hrůzu: Inkvizitora.,"Fabrikken lukkede, da Ordenen afslørede sin nye rædsel: Inquisitoren.","Die Fabrik wurde geschlossen, als der Orden seinen neuesten Horror enthült hat: Den Inquisitor.",,"La fabriko fermis post la malkaŝo de la lasta +teruraĵo de La Ordeno: la Inkvizitoro.","La fábrica cerró cuando La Orden +reveló su nuevo horror: el Inquisidor.",,"Tehdas suljettiin, kun Veljeskunta paljasti sen uuden kauhistuksen: inkvisiittorin.","L'usine a été fermée quand l'Ordre a révélé sa nouvelle atrocité, L'inquisiteur.","A gyár bezárt, amikor a Rend leleplezte a nagyközönség előtt az új horrorát: az Inkvizítort.",La fabbrica è stata chiusa quando l'Ordine ha rivelato il suo nuovo orrore: l'Inquisitore,"工場はオーダーの「新審問官」が来てから +恐ろしい雰囲気を纏った。",오더가 획기적이고 무서운 병기들을 생산한 후 공장의 문을 닫았다네. 그것들의 이름은 '인퀴지터'지.,De fabriek werd gesloten toen de Orde haar nieuwe horror onthulde: de inquisiteur.,Fabrikken stengte da Ordenen avduket sin nye skrekk: Inkvisitoren.,"Fabryka została zamknięta, gdy Zakon zaprezentował swój nowy horror: Inkwizytora.",A fábrica fechou quando a Ordem revelou o seu novo horror: o Inquisidor.,,Fabrica s-a închis când Ordinul a dezvăluit noua sa oroare: Inchizitorul.,"Фабрика закрылась, когда Орден показал своё новое страшилище — инквизитора.",,Fabriken stängdes när Orden presenterade sin nya skräck: Inkvisitorn.,"Fabrika, Tarikat yeni dehşeti Cezacı'yı tanıttığında kapandı." +5 gold please.,TXT_RNO0_SCRIPT23_D9096_5GOLD,〃,,,"Pět zlatých, prosim.","5 guld, tak.","5 Gold, bitte.",,"Kvin da oro, bonvolu.","Cinco de oro, por favor.",,"5 kolikkoa, kiitos.","5 pièces, s'il vous plaît.",5 arany lesz.,"Sono 5 pezzi d'oro, prego.",5ゴールドかかるぜ。,먼저 5 골드를 주게나.,5 goud alsjeblieft.,"5 gull, takk.",Proszę o 5 sztuk złota.,5 moedas por favor.,,5 bani te rog.,"5 золотых, пожалуйста.",,"5 guld, tack.",5 altın lütfen. +"That's all I know. Even bartenders run out of stuff to say, sorry.",TXT_DLG_SCRIPT23_D10612_THATS,"STRIFE1.WAD +MAP23: Barkeep",,,"To je vše, co vím. I barmani občas nemají, co dál říct, promiňte.","Det er alt, hvad jeg ved. Selv bartendere løber tør for ting at sige, undskyld.","Das ist alles was ich weiß. Selbst ein Barkeeper hat irgendwann keine Neugikeiten mehr, tut mir Leid.",,Mi scias nenion plian. Eĉ drinkejestroj restas sen dirindaĵoj. Pardonon.,Eso es todo lo que sé. Incluso los taberneros se quedan sin cosas que decir. Lo siento.,,"Siinä kaikki, mitä tiedän. Jopa baarimikoilta loppuvat jutun aiheet, pahoittelen.","C'est tout ce que je sais. Même les barmans peuvent arriver à court d'infos, désolé.","Ennyit tudok. Még a bárpultos tudása sem végtelen, sajnálom.","È tutto ciò che so. Anche i baristi hanno un limite alla loro conoscienza, mi spiace.","知ってることはこれで全部だ。 +バーテンダーの噂は売切れだ、すまない。",이 바텐더는 꺼낼 수 있는 모든 조언을 꺼냈다네. 미안.,"Dat is alles wat ik weet. Zelfs de barmannen hebben niet veel meer te zeggen, sorry.","Det er alt jeg vet. Selv bartendere går tom for ting å si, beklager.","To wszystko, co wiem. Nawet barmanom kończy się to, co można powiedzieć, przepraszam.","Isso é tudo o que eu sei. Até donos de bar acabam ficando sem algo pra dizer uma hora, sinto muito.",,"Asta e tot ce știu, până și barmanii rămân fără chestii de zis.","Это всё, что я знаю. Даже у хозяев таверн заканчиваются темы для болтовни, увы.",,"Det är allt jag vet. Till och med bartender får slut på saker att säga, tyvärr.","Tek bildiğim bu. Barmenlerin bile söyleyecek bir şeyleri kalmadı, üzgünüm." +Hello.,TXT_DLG_SCRIPT23_D12128_HELLO,"STRIFE1.WAD +MAP23: Timothy",,,Ahoj.,Hej.,Hallo.,,Saluton.,Hola.,,Hei.,Bonjour.,Helló.,Ciao.,こんにちは。,안녕하세요.,Hallo.,Hallo.,Witam.,Olá.,,Salut.,Привет.,,Hej.,Merhaba. +What are you doing?,TXT_RPLY0_SCRIPT23_D12128_WHATA,〃,,,Co tady děláš?,Hvad laver du?,Was machst du?,,Kion vi faras?,¿Qué estás haciendo?,,Mitä teet?,Qu'est-ce que vous faites?,Mit csinálsz?,Che cosa stai facendo?,何してるんだ?,뭐하는 거죠?,Wat ben je aan het doen?,Hva driver du med?,Co robisz?,O que você está fazendo?,,Ce faci?,Чем ты занимаешься?,,Vad gör du?,Ne yapıyorsun? +"I'm doing stuff, go away!",TXT_RYES0_SCRIPT23_D12128_IMDOI,〃,,,"Dělám věci, vypadni!","Jeg laver noget, gå væk!","Ich mach' halt was, geh weg!",,Mi umas. Foriru!,Cosas. ¡Ya vete!,,"Teen juttuja, mene pois!","Je suis occupé, laissez-moi tranquille!","Épp elfoglalt vagyok, tünj innen!","Sto sbrigando delle cose, vattene!",今は立て込んでる、離れなさい!,별거 아닙니다. 방해하지 말고 저리 가세요!,"Ik doe dingen, ga weg!","Jeg gjør ting, gå vekk!","Robię różne rzeczy, odejdź!","Estou fazendo coisas, vá embora!",,"Am treabă, pleacă!",Ерундой всякой. Отвали!,,"Jag gör saker, försvinn!","Bir şeyler yapıyorum, git başımdan!" +"Now, what can I help you with?",TXT_DLG_SCRIPT23_D13644_NOWWH,"STRIFE1.WAD +MAP23: Tevick.",,,"Tak, s čím ti mohu pomoci?",Hvad kan jeg hjælpe dig med?,"Nun, wie kann ich dir weiterhelfen?",,"Nu, kion mi povas doni al vi?","Y bueno, ¿en qué puedo ayudarte?",,"No niin, miten voin palvella?","Bon, que puis-je pour vous?","Na, miben segíthetek?","E ora, come posso aiutarti?",今手伝ってくれるか?,"자, 제가 뭘 도와드릴까요?","Nu, waar kan ik je mee helpen?",Hva kan jeg hjelpe deg med?,"A teraz, w czym mogę ci pomóc?","Então, como posso ajudá-lo?",,"Acum, cu ce te pot ajuta?","Итак, чем я могу быть тебе полезен?",,Vad kan jag hjälpa dig med?,"Şimdi, sana nasıl yardımcı olabilirim?" +Shadow armor?,TXT_RPLY0_SCRIPT23_D13644_SHADO,〃,,Shadow armour?,Stínové brnění?,Skygge rustning?,Schattenrüstung?,,Ĉu ombran armaĵon?,¿Armadura de sombra?,,Varjohaarniska?,Armure des ombres?,Árnyék vért?,Armatura Ombra?,シャドウアーマー?,그림자 갑옷?,Schaduw harnas?,Skyggepanser?,Zbroja cieni?,Armadura das sombras?,,Armura umbrei?,Теневой бронёй?,,Skuggarmering?,Gölge zırhı mı? +"Ahh, to be heard, but not seen!",TXT_RYES0_SCRIPT23_D13644_AHHTO,〃,,,"Áha, být slyšen, ne viděn!","Ahh, at blive hørt, men ikke set!","Ah, um gehört zu werden, aber ungesehen zu bleiben.",,"Ha, por esti aŭdata, +sed ne vidata!","Ah, ¡para ser oído, +pero no visto!",,"Aah, tulla kuulluksi, muttei nähdyksi!","Ah, pour se faire entendre, sans se faire voir!","Csak hallani, de nem látni.","Ahh, per essere sentiti, ma non visti!",ああ、声はすれど姿は見えず。,하하하... 아주 조용하고 보이지 않는 도구죠!,"Ahhh, om gehoord, maar niet gezien te worden!","Å bli hørt, men ikke sett!","Ahh, być słyszanym, ale nie widzianym!","Ahh, ser ouvido mas não ser visto!",,"Ahh, să fii auzit, dar nu văzut!","Ах, чтобы быть услышанным, но не увиденным!",,"Ahh, att höras men inte ses!","Ahh, duyulmak ama görülmemek!" +"Get out of here, come back when you have some cash.",TXT_RNO0_SCRIPT23_D13644_GETOU,〃,,,"Vypadni a vrať se, když budeš mít peníze.","Forsvind herfra, kom tilbage når du har nogle penge.","Verzieh dich, komm wieder, wenn du etwas Geld hast.",,"Foriru. Revenu kiam +vi havos monon.","Vete. Vuelve cuando +tengas efectivo.",,"Antaa vetää; tule takaisin, kun sinulla on käteistä.","Sortez de là, revenez quand vous avez de l'argent!","Na kotródj innen, csak akkor lássalak ha van nálad pénz is.","Fuori di qui, ritorna quando avrai del denaro.",ここを出て、稼いでからまた来てくれ!,"저리 가, 돈이 있을 때나 여길 찾으라고요.","Ga hier weg, kom terug als je wat geld hebt.","Kom deg ut herfra, kom tilbake når du har penger.","Wynoś się stąd, wróć jak będziesz miał trochę kasy.",Vá embora daqui. Volte quando tiver dinheiro.,,"Cară-te, întoarce-te când ai bani.","Выметайся вон. Вернёшься, когда раздобудешь наличности.",,"Försvinn härifrån, kom tillbaka när du har lite pengar.","Git buradan, biraz paran olduğunda geri gel." +"Thank Deus you got here. To enter the factory you need a key. We stole it but our agent is missing in the web of catacombs under the Order's stronghold. I have sent ten good men into those tunnels to find him, and none have returned. Something is down there!",TXT_DLG_SCRIPT23_D15160_THANK,"STRIFE1.WAD +MAP23: Richter.",,,"Díky bohu, žes přišel. Aby ses dostal do továrny, potřebuješ klíč. Ten jsme ukradli, ale náš agent se ztratil v sítí katakomb pod pevností Řádu. Poslal jsem do těch tunelů deset dobrých mužů a žádný se nevrátil. Něco tam dole je!","Tak Deus for at du kom her. For at komme ind på fabrikken skal du bruge en nøgle. Vi stjal den, men vores agent er forsvundet i katakomberne under ordenens højborg. Jeg har sendt ti gode mænd ned i disse tunneller for at finde ham, men ingen er vendt tilbage. Der er noget dernede!","Deus sei dank bist du hier. Um die Fabrik zu betreten, brauchst du einen Schlüssel. Wir haben ihn gestohlen, aber unser Agent ist in den Irrwegen der Katakomben unter der Festung des Ordens verschollen. Ich habe zehn gute Männer da hinunter geschickt um ihn zu finden, aber niemand ist zurückgekehrt. Irgendetwas ist da unten!",,"Danke al Dio vi alvenis. Ŝlosilo estas necesa por eniri la fabrikon; ni ŝtelis ĝin, sed nia agento estas perdita en la katakomba sistemo sub la fortreso de La Ordeno. Mi sendis dek bonajn virojn al tiuj tuneloj por serĉi lin kaj neniu revenis. Estas io tie malsupre!","Gracias a Dios, has llegado. Para entrar en la fábrica se necesita una llave; la hemos robado, pero nuestro agente está perdido en la red de catacumbas debajo de la fortaleza de La Orden. He enviado a diez buenos hombres a esos túneles a buscarlo y ninguno ha regresado. ¡Hay algo ahí abajo!","Gracias a Dios, llegaste. Para entrar a la fábrica se necesita una llave; la robamos, pero nuestro agente se perdió en la red de catacumbas debajo de la fortaleza de La Orden. Mandé a diez buenos hombres a esos túneles a buscarlo y ninguno volvió. ¡Hay algo ahí abajo!","Luojan kiitos, että selvisit perille. Päästäksesi sisälle tehtaaseen tarvitset avaimen. Varastimme sen, mutta vakoojamme on eksynyt Veljeskunnan linnakkeen alapuolella sijaitsevaan katakombiverkostoon. Olen lähettänyt tunneleihin 10 kelpoa miestä etsimään häntä, eikä kukaan ole palannut. Jokin on siellä alla!","Merci Dieu, vous êtes là. Pour entrer dans l'usine, il vous faut une clé. On l'a volé, mais notre agent a disparu dans le dédale de catacombes sous la forteresse de l'Ordre. On a envoyé dix hommes dans ces tunnels pour le retrouver mais personne n'est revenu. Il doit y avoir quelque chose, là dedans!","Hála Deusnak, ideértél.Ahhoz, hogy bejuthass a gyárba kell majd egy kulcs. Habár sikerült ellopnunk a kulcsot, az ügynökünk elveszett a katakombák sűrűjében a Rend erődítménye alatt. Leküldtem tíz jó emberemet utána, de egyikük sem tért vissza. Valami borzasztó lehet ott lent!","Grazie a Dio sei arrivato. Per entrare nella fabbrica ti servirà una chiave. L'abbiamo rubata ma l'agente che l'ha presa è sparito nelle catacombe sotto la fortezza dell'Ordine. Ho mandato dieci uomini in quei tunnel a trovarlo, e nessuno è ritornato. C'è qualcosa là sotto!","ようやく来てくれたか。 工場に入るためには鍵が必要だ。 鍵は盗んだのだが、我々の密偵が砦地下にある 地下墓所で行方不明になった。 彼を探すため10名派遣したのだが、 誰一人帰ってこなかった。 -地下墓地で何か異変が起こっているに違いない。","데우스님 감사합니다, 지원군이 왔군! 공장에 들어가려면 열쇠가 필요합니다. 그 열쇠를 가진 한 요원이 오더의 요새가 있는 고대 무덤에서 길을 잃었습니다. 지원군 10 명을 보내긴 했으나 돌아오지 못했습니다. 그곳에 무언가가 있는 것 같아요!","Bedankt Deus dat je hier bent gekomen. Om de fabriek binnen te komen heb je een sleutel nodig. We hebben het gestolen maar onze agent ontbreekt in het web van de catacomben onder het bolwerk van de Orde. Ik heb tien goede mannen in die tunnels gestuurd om hem te vinden, en niemand is teruggekomen. Er is daar beneden iets!",,Graças a Deus que você está aqui. Para entrar na fábrica você precisa de uma chave. Nós a roubamos mas nosso agente desapareceu na rede de catacumbas debaixo da fortaleza da Ordem. Mandei dez homens capazes pra dentro desses túneis para encontrá-lo e ninguém retornou. Tem alguma coisa lá embaixo!,,,"Хвала господу, ты добрался сюда. Тебе нужен ключ, чтобы проникнуть на фабрику. Мы выкрали его, но наш агент пропал в сети катакомб под крепостью Ордена. Чтобы разыскать его, я послал в эти туннели десять хороших бойцов, и ни один не вернулся. Там внизу что-то есть!", -What is it? Human or... ?,TXT_RPLY0_SCRIPT23_D15160_WHATI,,,,"Co to je? Člověk, nebo...?",Was ist es? Mensch oder...?,,,¿Qué es? ¿Humano o...?,,,"Qu'est-ce que c'est? Un humain, où...",,,それは一体?人間か...?,그게 뭐죠? 사람? 아니면... ?,Wat is het? Menselijk of.... ?,,O que é? É humano ou... ?,,,Что это? Человек или...?, -"Not. Definitely not. Whatever it is, you must fight it to retrieve the key. I'll open the catacombs' entrance. When you've got it, the factory is next to the mines. Hurry, each second counts.",TXT_DLG_SCRIPT23_D16676_NOTDE,,,,"Ne. Rozhodně ne. Ať je to cokoliv, musíš se s tím utkat, abys získal ten klíč zpět. Otevřu ti vchod do katakomb. Až ho budeš mít, továrna je vedle dolů. Pospěš, každá vteřina se počítá.","Nein. Definitiv nicht. Was auch immer es ist, du musst es bekämpfen, um an den Schlüssel zu kommen. Ich werde den Eingang zu den Katakomben öffnen. Wenn du ihn hast, die Fabrik ist direkt neben den Minen. Beeil dich, jede Sekunde zählt.",,,"No. Definitivamente no. Sea lo que sea, debes luchar contra eso para recuperar la llave. Abriré la entrada a las catacumbas. Cuando la tengas, la fábrica está junto a las minas. Date prisa, cada segundo cuenta.",,,"Non, absolument pas. Je ne sais pas ce que c'est, mais il faudra s'en débarasser pour récupérer la clé. Je vais ouvrir l'entrée des catacombes. Quand vous êtes à l'intérieur, l'usine est près des ruines. Vite, chaque seconde compte.",,,"いや。人間の仕業だとはとても思えない。 +地下墓地で何か異変が起こっているに違いない。","데우스님 감사합니다, 지원군이 왔군! 공장에 들어가려면 열쇠가 필요합니다. 그 열쇠를 가진 한 요원이 오더의 요새가 있는 고대 무덤에서 길을 잃었습니다. 지원군 10 명을 보내긴 했으나 돌아오지 못했습니다. 그곳에 무언가가 있는 것 같아요!","Bedankt Deus dat je hier bent gekomen. Om de fabriek binnen te komen heb je een sleutel nodig. We hebben het gestolen maar onze agent ontbreekt in het web van de catacomben onder het bolwerk van de Orde. Ik heb tien goede mannen in die tunnels gestuurd om hem te vinden, en niemand is teruggekomen. Er is daar beneden iets!","Takk Gud for at du kom hit. For å komme inn i fabrikken trenger du en nøkkel. Vi stjal den, men agenten vår er forsvunnet i katakombene under Ordenens festning. Jeg har sendt ti gode menn ned i tunnelene for å finne ham, men ingen har kommet tilbake. Det er noe der nede!","Dziękuję Deusowi, że tu trafiłeś. Aby wejść do fabryki potrzebny jest klucz. Ukradliśmy go, ale nasz agent zaginął w sieci katakumb pod twierdzą Zakonu. Wysłałem dziesięciu dobrych ludzi do tych tuneli, by go znaleźli, ale żaden nie wrócił. Coś jest tam na dole!",Graças a Deus que você está aqui. Para entrar na fábrica você precisa de uma chave. Nós a roubamos mas nosso agente desapareceu na rede de catacumbas debaixo da fortaleza da Ordem. Mandei dez homens capazes pra dentro desses túneis para encontrá-lo e ninguém retornou. Tem alguma coisa lá embaixo!,,"Slavă Domnului că ești aici. Ca să intri în fabrică ai nevoie de o cheie. Am furat-o dar agentul nostru a dispărut în rețeaua catacombelor fortăreței Ordinului. Am trimis zece oameni pricepuți după el, dar niciunul nu s-a întors. Ceva se întâmplă acolo!","Хвала господу, ты добрался сюда. Тебе нужен ключ, чтобы проникнуть на фабрику. Мы выкрали его, но наш агент пропал в сети катакомб под крепостью Ордена. Чтобы разыскать его, я послал в эти туннели десять хороших бойцов, и ни один не вернулся. Там внизу что-то есть!",,"Tacka Deus för att du kom hit. För att komma in i fabriken behöver du en nyckel. Vi stal den, men vår agent saknas i katakomberna under Ordensfästet. Jag har skickat tio goda män in i tunnlarna för att hitta honom, men ingen har återvänt. Något finns där nere!",Buraya geldiğin için Deus'a şükret. Fabrikaya girmek için bir anahtara ihtiyacınız var. Onu çaldık ama ajanımız Tarikat'ın kalesinin altındaki yeraltı mezarlarında kayıp. Onu bulmaları için o tünellere on iyi adam gönderdim ama hiçbiri geri dönmedi. Aşağıda bir şey var! +What is it? Human or... ?,TXT_RPLY0_SCRIPT23_D15160_WHATI,〃,,,"Co to je? Člověk, nebo...?",Hvad er det? Menneske eller... ?,Was ist es? Mensch oder...?,,Kia ĝi estas? Ĉu homa aŭ...?,"¿Qué es?, ¿humano o...?",,Mikä se on? Ihminen vai...,"Qu'est-ce que c'est? Un humain, où...",Mi lehet? Ember vagy...?,Che cosa è? Umano o... ?,それは一体?人間か...?,그게 뭐죠? 사람? 아니면... ?,Wat is het? Menselijk of.... ?,Hva er det? Menneskelig eller... ?,Co to jest? Człowiek czy... ?,O que é? É humano ou... ?,,Ce e? Uman sau... ?,Что это? Человек или...?,,Vad är det? Mänskligt eller... ?,Ne var orada? İnsan mı yoksa... ? +"Not. Definitely not. Whatever it is, you must fight it to retrieve the key. I'll open the catacombs' entrance. When you've got it, the factory is next to the mines. Hurry, each second counts.",TXT_DLG_SCRIPT23_D16676_NOTDE,〃,,,"Ne. Rozhodně ne. Ať je to cokoliv, musíš se s tím utkat, abys získal ten klíč zpět. Otevřu ti vchod do katakomb. Až ho budeš mít, továrna je vedle dolů. Pospěš si, každá vteřina se počítá.","Nej. Helt sikkert ikke. Uanset hvad det er, skal du kæmpe mod det for at få nøglen tilbage. Jeg åbner katakombernes indgang. Når du har fået den, er fabrikken ved siden af minerne. Skynd dig, hvert sekund tæller.","Nein. Definitiv nicht. Was auch immer es ist, du musst es bekämpfen, um an den Schlüssel zu kommen. Ich werde den Eingang zu den Katakomben öffnen. Wenn du ihn hast, die Fabrik ist direkt neben den Minen. Beeil dich, jede Sekunde zählt.",,"Ne, neniel. Tio ajn, kio ĝi estas, vi devas batali kontraŭ ĝi por rekuperi la ŝlosilon. Farinte tion, la fabriko estas flanke de la minejo. Hastu, ĉiu sekundo estas gravega.","No, definitivamente no. Sea lo que sea, debes pelear contra eso para recuperar la llave; abriré la entrada a las catacumbas. Cuando la tengas, la fábrica está junto a la mina. Date prisa, que cada segundo cuenta.","No, definitivamente no. Sea lo que sea, debes pelear contra eso para recuperar la llave; voy a abrir la entrada a las catacumbas. Cuando la tengas, la fábrica está junto a la mina. Apúrate, que cada segundo cuenta.","Ei, ei varmana. Mikä ikinä se onkaan, sinun on kohdattava se noutaaksesi avaimen. Avaan katakombien sisäänkäynnin. Kun se on hallussasi, tehdas on kaivoksen vieressä. Pidä kiirettä, jokainen sekunti merkitsee.","Non, absolument pas. Je ne sais pas ce que c'est, mais il faudra s'en débarasser pour récupérer la clé. Je vais ouvrir l'entrée des catacombes. Quand vous êtes à l'intérieur, l'usine est près des ruines. Vite, chaque seconde compte.","Nem. Biztos, hogy nem. Akármi is az, meg kell majd küzdened vele a kulcsért. Kinyitom a katakomba bejáratát. Ha megszerezted, a gyár ott lesz a bánya mellett. Siess, minden másodperc számít.","No. Sicuramente no. Qualsiasi cosa sia, dovrai lottare per riavere la chiave. Adesso aprirò l'entrata per le catacombe. Quando avrai ripreso la chiave, potrai accedere alla fabbrica, che si trova accanto alle miniere. Sbrigati, ogni secondo può fare la differenza.","いや。人間の仕業だとはとても思えない。 それが何であれ君は鍵を取り戻せ。 地下墓所への入り口は開けておこう。 鍵を手に入れたら、工場は採掘所の隣にある。 -時間はあまり無いから急ぐのだ。","아냐. 사람 같은 건 절대로 아니라고. 그게 무엇이든, 당신은 어떻게든 싸워서 열쇠를 돌려받아야 합니다. 고대 무덤의 입구를 열어두겠습니다. 만약 열쇠를 얻으셨다면, 광산 옆에 있는 공장으로 향하시길 바랍니다. 시간이 얼마 남지 않았습니다!","Niet. Zeker niet. Wat het ook is, je moet ertegen vechten om de sleutel terug te krijgen. Ik zal de ingang van de catacomben openen. Als je hem hebt, staat de fabriek naast de mijnen. Schiet op, elke seconde telt.",,"Não. Definitivamente não é. Seja lá o que for, você deve enfrentá-lo para recuperar a chave. Vou abrir a entrada das catacumbas. Quando você pegar a chave, vá para a fábrica próxima às minas. Depressa, cada segundo é importante.",,,"Нет. Определённо нет. Что бы это ни было, ты должен сразиться с ним, чтобы заполучить ключ. Я открою вход в катакомбы. Когда добудешь его, направляйся на фабрику — она находится рядом со входом в шахты. Торопись! Дорога каждая секунда!", -"Something inhuman, eh?, great.",TXT_RPLY0_SCRIPT23_D16676_SOMET,,,,"Něco nelidského, co? Skvělý.",Irgendetwas unmenschliches? Na großartig.,,,"Algo inhumano, ¿eh?, genial.",,,"Quelque chose d'inhumain, hein? Parfait.",,,非人道的な何か?流石だな。,비인간적인 녀석인가요? 좋군요.,"Iets onmenselijks, eh?, geweldig.",,"Algo não-humano, é? Que ótimo.",,,Что-то иное? Просто отлично., -You're wasting time and lives! Move!,TXT_DLG_SCRIPT23_D18192_YOURE,,,,Plýtváš časem i životy! Jdi!,Du verschwendest Zeit und Leben! Beweg dich!,,,¡Estás perdiendo tiempo y vidas! ¡Muévete!,,,Vous perdez votre temps et des vies! Bougez!,,,"こうしてる間にも君は時間と人命を -無駄にしている。行け!",시간과 생명이 위협받고 있다고! 서두르세요!!,Je verspilt tijd en levens! Vooruit!,,Você está desperdiçando tempo e vidas! Ande logo!,,,Ты тратишь время и жизни! Шевелись!, -Can I be of more help?,TXT_DLG_SCRIPT23_D10612_CANIB,,,,Můžu ti dál pomocI?,Kann ich dir sonst noch irgendwie helfen?,,,¿Puedo ser de más ayuda?,,,Je peux vous aider?,,,何かお困りでも?,당신의 도움이 더 되어줄 수 있겠습니까?,Kan ik meer hulp bieden?,,Posso ajudar com mais alguma coisa?,,,Могу ли я чем-нибудь помочь?, -More info.,TXT_RPLY0_SCRIPT23_D10612_MOREI,,,,Další informace.,Mehr Informationen.,,,Más información.,,,Plus d'infos.,,,更なる情報。,정보 더 있습니까?,Meer info.,,Mais informações.,,,Информацией., -Look for Timothy. I've heard he knows some of the Order's secrets.,TXT_RYES0_SCRIPT23_D10612_LOOKF,,,,"Najdi Timothyho. Slyšel jsem, že ví nějaká tajemství Řádu.","Suche Timothy. Ich habe gehört, das er etwas über die Geheimnisse des Ordens weiß.",,,Busca a Timothy. He oído que sabe algo sobre los secretos de la Orden.,,,"Cherchez Timothy, j'entends qu'il sait des secrets de l'Ordre.",,,"ティモシーを探せ。彼がオーダーの秘密を -知っていると聞いた。",티모시를 찾아보세요. 제가 듣기론 그가 오더의 비밀들을 알고 있다던데.,Zoek Timothy. Ik heb gehoord dat hij enkele van de geheimen van de Orde kent.,,Procure por Timothy. Fiquei sabendo que ele conhece alguns segredos da Ordem.,,,"Найди Тимоти. Я слышал, он знает какие-то секреты Ордена.", -Just another 5 gold.,TXT_RNO0_SCRIPT23_D10612_JUSTA,,,,Jen dalších pět zlatých.,Nur 5 weitere Goldstücke.,,,Solo otros 5 de oro.,,,Juste 5 pièces.,,,たった5ゴールドだぞ。,5 골드만 주세요.,Gewoon nog eens 5 goud.,,Só mais 5 moedas.,,,Всего лишь ещё 5 золотых!, -"That's all I know. Even bartenders run out of stuff to say, sorry.",TXT_DLG_SCRIPT23_D12128_THATS,,,,"To je vše, co vím. I barmani občas nemají, co dál říct, promiň.","Das ist alles was ich weiß. Selbst ein Wirt hat irgendwann keine Neugikeiten mehr, tut mir Leid.",,,"Eso es todo lo que sé. Incluso los taberneros se quedan sin cosas que decir, lo siento.",,,"C'est tout ce que je sais. Même les barmans peuvent arriver à court d'infos, désolé.",,,"知ってることはこれで全部だ。 -バーテンダーの噂は売切れだ、すまない。",내가 아는 건 그것뿐입니다. 바텐더라도 할 말이 떨어질 수 있다고. 미안해요.,"Dat is alles wat ik weet. Zelfs de barmannen hebben niet veel meer te zeggen, sorry.",,"Isso é tudo o que eu sei. Até donos de bar acabam ficando sem algo pra dizer uma hora, sinto muito.",,,"Это всё, что я знаю. Даже у хозяев таверн заканчиваются темы для болтовни, увы.", -Hello.,TXT_DLG_SCRIPT23_D13644_HELLO,,,,Ahoj.,Hallo.,,,Hola.,,,Bonjour.,,,どうも。,안녕하세요.,Hallo.,,Olá.,,,Привет., -What are you doing?,TXT_RPLY0_SCRIPT23_D13644_WHATA,,,,Co tady děláš?,Was machst du?,,,¿Qué estás haciendo?,,,Qu'est-ce que vous faites?,,,何してるんだ?,무슨 일을 하고 있는거죠?,Wat ben je aan het doen?,,O que você está fazendo?,,,Чем ты занимаешься?, -"I'm doing stuff, go away!",TXT_RYES0_SCRIPT23_D13644_IMDOI,,,,"Dělám věci, vypadni!","Ich mach' halt was, geh weg!",,,"Estoy haciendo cosas, ¡Lárgate!",,,"Je suis occupé, laissez-moi tranquille!",,,今は立て込んでる、離れろ!,그냥 뭘 하고 있습니다. 저리가세요!,"Ik doe dingen, ga weg!",,"Estou fazendo coisas, vá embora!",,,Ерундой всякой. Отвали!, -"If you have this much time to waste, see if you can find the blue chalice. My studies on the Order suggest they have hidden it somewhere in the manufacturing sector of the factory. This artifact would be of great value to me, so, bring it to me, and I'll help you out.",TXT_DLG_SCRIPT23_D15160_IFYOU,,,,"Jestli máš takového volného času, zkus najít modrý kalich. Má pátraní o Řádu naznačují, že je schovaný někde ve výrobním sektoru továrny. Tenhle artifakt by pro mě byl nesmírně cenný, takže jestli mi ho přineseš, pomůžu ti.","Wenn du so viel Zeit zu verschwenden hast, dann sieh zu, dass du den blauen Kelch finden kannst. Meine Studien über den Orden deuten an, dass er irgendwo im Produktionssektor der Fabrik versteckt sein muss. Dieses Artefakt würde mir viel bedeuten, also bring es mir, und ich werde dir weiterhelfen.",,,"Si tienes tanto tiempo que perder, ve si puedes encontrar el cáliz azul. Mis estudios sobre la Orden sugieren que lo tienen oculto en alguna parte del sector de producción de la fábrica. Este artefacto sería de gran valor para mi, así que, tráemelo, y te ayudaré.",,,"Si vous avez autant de temps à perdre, allez voir si vous pouvez récupérer le Calice Bleu. Mes études sur l'Ordre suggèrent qu'ils l'ont caché dans le secteur de manufacture de l'usine. Cet artéfact serait de grande valeur pour moi, amenez-le moi et je vous aiderai.",,,"アンタがもし時間を浪費するつもりじゃないなら +時間はあまり無いから急ぐのだ。","아냐. 사람 같은 건 절대로 아니라고. 그게 무엇이든, 당신은 어떻게든 싸워서 열쇠를 돌려받아야 합니다. 고대 무덤의 입구를 열어두겠습니다. 만약 열쇠를 얻으셨다면, 광산 옆에 있는 공장으로 향하시길 바랍니다. 시간이 얼마 남지 않았습니다!","Niet. Zeker niet. Wat het ook is, je moet ertegen vechten om de sleutel terug te krijgen. Ik zal de ingang van de catacomben openen. Als je hem hebt, staat de fabriek naast de mijnen. Schiet op, elke seconde telt.","Nei. Definitivt ikke. Uansett hva det er, må du kjempe mot det for å få tak i nøkkelen. Jeg åpner inngangen til katakombene. Når du har den, er fabrikken ved siden av gruvene. Skynd deg, hvert sekund teller.","Nie. Zdecydowanie nie. Cokolwiek to jest, musisz z tym walczyć, aby odzyskać klucz. Ja otworzę wejście do katakumb. Gdy go zdobędziesz, fabryka jest obok kopalni. Spiesz się, liczy się każda sekunda.","Não. Definitivamente não é. Seja lá o que for, você deve enfrentá-lo para recuperar a chave. Vou abrir a entrada das catacumbas. Quando você pegar a chave, vá para a fábrica próxima às minas. Depressa, cada segundo é importante.",,"Nu. Cu siguranță nu. Orice ar fi, va trebui să o înfrunți pentru a recupera cheia. Voi deschide intrarea catacombelor. Când o ai, fabrica e vizavi de mine. Grăbește-te, orice secundă contează.","Нет. Определённо нет. Что бы это ни было, ты должен сразиться с ним, чтобы заполучить ключ. Я открою вход в катакомбы. Когда добудешь его, направляйся на фабрику: она находится рядом со входом в шахты. Торопись! Дорога каждая секунда!",,"Inte. Definitivt inte. Vad det än är måste du slåss mot det för att få tag på nyckeln. Jag öppnar katakombernas ingång. När du har fått den är fabriken bredvid gruvorna. Skynda dig, varje sekund räknas.","İnsan değil. Kesinlikle değil. O her neyse, anahtarı almak için onunla savaşmalısın. Yeraltı mezarlarının girişini açacağım. Anahtarı aldığında, fabrika madenlerin yanında. Acele et, her saniye önemli." +"Something inhuman, eh?, great.",TXT_RPLY0_SCRIPT23_D16676_SOMET,〃,,,"Něco nelidského, co? Skvělý.","Noget umenneskeligt, hva'?, fedt.",Irgendetwas unmenschliches? Na großartig.,,"Nehomaĵo, ĉu? Bonege.","Algo inhumano, ¿eh? Genial.",,"Jotain epäinhimillistä, vai? Hienoa.","Quelque chose d'inhumain, hein? Parfait.","Valami nem emberi, mi? Csodás.","Qualcosa di inumano, eh? Fantastico.",非人道的な何か?流石だな。,비인간적인 녀석인가요? 좋군요.,"Iets onmenselijks, eh?, geweldig.","Noe umenneskelig, hva? Flott!","Coś nieludzkiego, ech, świetnie.","Algo não-humano, é? Que ótimo.",,"Ceva inuman, ei? Grozav.",Что-то иное? Просто отлично.,,"Något omänskligt, va?, bra.","İnsanlık dışı bir şey, ha? Harika." +You're wasting time and lives! Move!,TXT_DLG_SCRIPT23_D18192_YOURE,〃,,,Plýtváš časem i životy! Jdi!,Du spilder tid og liv! Af sted!,Du verschwendest Zeit und Leben! Beweg dich!,,Vi perdas tempon kaj vivojn! Agu!,¡Estás perdiendo tiempo y vidas! ¡Muévete!,,Haaskaat aikaa ja henkiä! Liikkuu jo!,Vous perdez votre temps et des vies! Bougez!,Időt és életeket pazarolsz! Mozgás!,"Stai sprecando tempo, e vite. Sbrigati!","こうしてる間にも君は時間と人命を +無駄にしている。行け!",시간과 생명이 위협받고 있다고! 서두르세요!!,Je verspilt tijd en levens! Vooruit!,Du kaster bort tid og liv! Skynd dere!,Marnujesz czas i życie! Ruszać się!,Você está desperdiçando tempo e vidas! Ande logo!,,"Pierzi timp și vieți, mișcă-te!",Ты тратишь время и жизни! Шевелись!,,Du slösar tid och liv! Flytta på dig!,Zamanınızı ve hayatlarınızı boşa harcıyorsunuz! Çekilin! +Can I be of more help?,TXT_DLG_SCRIPT23_D10612_CANIB,"SVE.WAD +MAP23: Barkeep.",,,Můžu vám dál pomocI?,Kan jeg være til mere hjælp?,Kann ich dir sonst noch irgendwie helfen?,,Ĉu mi povas esti pli helpa?,¿Puedo ser de más ayuda?,,Voinko vielä olla avuksi?,Je peux vous aider?,Lehetek még a segítségedre?,Posso aiutarti ancora?,何かお困りでも?,당신의 도움이 더 되어줄 수 있겠습니까?,Kan ik meer hulp bieden?,Kan jeg være til mer hjelp?,Czy mogę być bardziej pomocny?,Posso ajudar com mais alguma coisa?,,Pot fi mai de ajutor?,Могу ли я чем-нибудь помочь?,,Kan jag vara till mer hjälp?,Daha fazla yardımcı olabilir miyim? +More info.,TXT_RPLY0_SCRIPT23_D10612_MOREI,〃 (dot not recommended),,,Další informace.,Mere info.,Mehr Informationen.,,Pliajn informojn,Más información,,Lisää tietoa.,Plus d'infos.,Több információ.,Più informazioni.,更なる情報。,정보 더 있습니까?,Meer info.,Mer informasjon.,Więcej informacji.,Mais informações.,,Mai multă informație.,Информацией.,,Mer information.,Daha fazla bilgi. +Look for Timothy. I've heard he knows some of the Order's secrets.,TXT_RYES0_SCRIPT23_D10612_LOOKF,〃,,,"Najděte Timothyho. Slyšel jsem, že ví nějaká tajemství Řádu.","Kig efter Timothy. Jeg har hørt, at han kender nogle af Ordenens hemmeligheder.","Suche Timothy. Ich habe gehört, das er etwas über die Geheimnisse des Ordens weiß.",,"Serĉu Timoteon. Mi aŭdis, +ke li scias ion pri La Ordeno.","Busca a Timothy. Oí que +sabe algo sobre La Orden.",,Etsi Timothy. Hän kuulemma tietää joitain Veljeskunnan salaisuuksia.,"Cherchez Timothy, j'entends qu'il sait des secrets de l'Ordre.","Keresd Timothyt. Azt hallotam, Ő tud pár Rend titkot.",Cerca Timothy. Ho sentito che conosce alcuni dei segreti dell'Ordine.,"ティモシーを探せ。彼がオーダーの秘密を +知っていると聞いた。",티모시를 찾아보세요. 제가 듣기론 그가 오더의 비밀들을 알고 있다던데.,Zoek Timothy. Ik heb gehoord dat hij enkele van de geheimen van de Orde kent.,Se etter Timothy. Jeg har hørt at han kjenner noen av Ordenens hemmeligheter.,"Poszukaj Timothy'ego. Słyszałem, że zna niektóre sekrety Zakonu.",Procure por Timothy. Fiquei sabendo que ele conhece alguns segredos da Ordem.,,Uită-te după Timotei. Am auzit că ar cunoaște mai multe secrete ale Ordinului.,"Найди Тимоти. Я слышал, он знает какие-то секреты Ордена.",,Leta efter Timothy. Jag har hört att han känner till några av ordens hemligheter.,Timothy'i ara. Tarikat'ın bazı sırlarını bildiğini duydum. +Just another 5 gold.,TXT_RNO0_SCRIPT23_D10612_JUSTA,〃,,,Jen dalších pět zlatých.,Bare 5 guld mere.,Nur 5 weitere Goldstücke.,,"Nur ankoraŭ +kvin da oro.",Solo otros cinco de oro.,,Vain 5 kolikkoa lisää.,Juste 5 pièces.,Még 5 arany kell.,Giusto altri 5 pezzi d'oro.,たった5ゴールドだぞ。,5 골드만 주세요.,Gewoon nog eens 5 goud.,Bare fem gull til.,Jeszcze tylko 5 złotych.,Só mais 5 moedas.,,Alte 5 monezi.,Всего лишь ещё 5 золотых!,,Bara ytterligare 5 guld.,Sadece 5 altın daha. +"That's all I know. Even bartenders run out of stuff to say, sorry.",TXT_DLG_SCRIPT23_D12128_THATS,〃,,,"To je vše, co vím. I barmani občas nemají, co dál říct, promiňte.","Det er alt, hvad jeg ved. Selv bartendere løber tør for ting at sige, undskyld.","Das ist alles was ich weiß. Selbst ein Wirt hat irgendwann keine Neugikeiten mehr, tut mir Leid.",,Mi scias nenion plian. Eĉ drinkejestroj restas sen dirindaĵoj. Pardonon.,Eso es todo lo que sé. Incluso los taberneros se quedan sin cosas que decir. Lo siento.,,"Siinä kaikki tietämäni. Jopa baarimikkojen sanaiset arkut ehtyvät, valitan.","C'est tout ce que je sais. Même les barmans peuvent arriver à court d'infos, désolé.","Ennyit tudok. Még a bárpultos tudása sem végtelen, sajnálom.","È tutto ciò che so. Anche i baristi hanno un limite alla loro conoscienza, mi spiace.","知ってることはこれで全部だ。 +バーテンダーの噂は売切れだ、すまない。",내가 아는 건 그것뿐입니다. 바텐더라도 할 말이 떨어질 수 있다고. 미안해요.,"Dat is alles wat ik weet. Zelfs de barmannen hebben niet veel meer te zeggen, sorry.","Det er alt jeg vet. Selv bartendere går tom for ting å si, beklager.","To wszystko, co wiem. Nawet barmanom kończą się rzeczy do powiedzenia, przepraszam.","Isso é tudo o que eu sei. Até donos de bar acabam ficando sem algo pra dizer uma hora, sinto muito.",,"Asta e tot ce știu, până și barmanii rămân fără chestii de zis.","Это всё, что я знаю. Даже у хозяев таверн заканчиваются темы для болтовни, увы.",,"Det är allt jag vet. Till och med bartender får slut på saker att säga, tyvärr.","Tüm bildiğim bu. Barmenlerin bile söyleyecek şeyleri bitiyor, üzgünüm." +Hello.,TXT_DLG_SCRIPT23_D13644_HELLO,"SVE.WAD +MAP23: Timothy (Talking with him for the very first time without the chalice).",,,Ahoj.,Hej.,Hallo.,,Saluton.,Hola.,,Hei.,Bonjour.,Helló.,Salve.,どうも。,안녕하세요.,Hallo.,Hallo.,Witam.,Olá.,,Salut.,Привет.,,Hej.,Merhaba. +What are you doing?,TXT_RPLY0_SCRIPT23_D13644_WHATA,〃,,,Co tady děláš?,Hvad laver du?,Was machst du?,,Kion vi faras?,¿Qué estás haciendo?,,Mitä teet?,Qu'est-ce que vous faites?,Mit művelsz?,Cosa stai facendo?,何してるんだ?,무슨 일을 하고 있는거죠?,Wat ben je aan het doen?,Hva holder du på med?,Co robisz?,O que você está fazendo?,,Ce faci?,Чем ты занимаешься?,,Vad gör du?,Ne yapıyorsun? +"I'm doing stuff, go away!",TXT_RYES0_SCRIPT23_D13644_IMDOI,〃,,,"Dělám věci, vypadni!","Jeg laver noget, gå væk!","Ich mach' halt was, geh weg!",,Mi umas. Foriru!,Cosas. ¡Ya vete!,,"Teen juttuja, mene pois!","Je suis occupé, laissez-moi tranquille!","Csinálom a dolgom, menj innen!","Sto sbrigando delle cose, vattene!",今は立て込んでる、離れろ!,그냥 뭘 하고 있습니다. 저리가세요!,"Ik doe dingen, ga weg!","Jeg gjør ting, gå vekk!","Robię różne rzeczy, odejdź!","Estou fazendo coisas, vá embora!",,"Am treabă, pleacă!",Ерундой всякой. Отвали!,,"Jag gör saker, försvinn!","Bir şeyler yapıyorum, git başımdan!" +"If you have this much time to waste, see if you can find the blue chalice. My studies on the Order suggest they have hidden it somewhere in the manufacturing sector of the factory. This artifact would be of great value to me, so, bring it to me, and I'll help you out.",TXT_DLG_SCRIPT23_D15160_IFYOU,〃,,,"Jestli máš takového volného času, zkus najít modrý kalich. Má pátraní o Řádu naznačují, že je schovaný někde ve výrobním sektoru továrny. Tenhle artifakt by pro mě byl nesmírně cenný, takže jestli mi ho přineseš, pomůžu ti.","Hvis du har så meget tid at spilde, så se om du kan finde den blå bæger. Mine undersøgelser af Ordenen tyder på, at de har gemt den et sted i fabrikkens produktionssektor. Denne artefakt ville være af stor værdi for mig, så bring den til mig, og jeg vil hjælpe dig.","Wenn du so viel Zeit zu verschwenden hast, dann sieh zu, dass du den blauen Kelch finden kannst. Meine Studien über den Orden deuten an, dass er irgendwo im Produktionssektor der Fabrik versteckt sein muss. Dieses Artefakt würde mir viel bedeuten, also bring es mir, und ich werde dir weiterhelfen.",,"Se vi estas tiel senokupa, provu trovi la bluan kalikon. Miaj studoj pri La Ordeno sugestas, ke ili kaŝis ĝin ien en la manufakturo de la fabriko. Tiu artefakto estus tre valora por mi, do alportu ĝin kaj mi helpos vin.","Si tan aburrido estás, ve a ver si puedes encontrar el cáliz azul. Mis estudios sobre La Orden sugieren que está oculto en alguna parte del sector de manufactura de la fábrica. Ese artefacto me sería de gran valor, así que tráemelo y te ayudaré.","Si tan aburrido estás, ve a ver si puedes encontrar el cáliz azul. Mis estudios sobre La Orden sugieren que está oculto en alguna parte del sector de manufactura de la fábrica. Ese artefacto me sería de gran valor, así que tráemelo y te voy a ayudar.","Jos sinulla on näin paljon aikaa tuhlattavana, pidä silmäsi auki sinisen uhrimaljan varalta. Tutkimukseni Veljeskunnasta viittaavat siihen, että he ovat kätkeneet sen jonnekin tehtaan tuotanto-osastolla. Esine olisi minulle hyvin arvokas, joten tuo se minulle, ja autan sinua.","Si vous avez autant de temps à perdre, allez voir si vous pouvez récupérer le Calice Bleu. Mes études sur l'Ordre suggèrent qu'ils l'ont caché dans le secteur de manufacture de l'usine. Cet artéfact serait de grande valeur pour moi, amenez-le moi et je vous aiderai.","Ha ilyen őrülten sok időd van, akkor próbáld megkeresni a kék serleget. A kutatásaim azt mutatják, hogy a gyár gyártósoránál van elrejtve. Ez az ereklye nagyon fontos lenne számomra, ha elhozod nekem segítek rajtad.","Se proprio hai così tanto tempo da perdere, vedi se riesci a trovare il calice blu. I miei studi sull'Ordine indiano che lo hanno nascosto da qualche parte del settore manufatturiero della Fabbrica. Questo artifatto mi sarebbe molto utile, quindi se me lo porti, ti potrò aiutare.","アンタがもし時間を浪費するつもりじゃないなら 青の聖杯を見つけられるかどうかを確かめる。 その骨董品は俺にとって非常に価値がある。 -持ってきたら協力しよう。","만약 시간이 남아돈다면, 푸른 성배를 찾아보러 가시는 게 어떤가요? 오더에 대한 제 연구가 맞아떨어진다면, 그것은 분명히 공장의 조립시설에 숨겨져 있을 겁니다. 그 보물은 더 할 말 없이 아주 진귀할 거에요. 그걸 찾아주면, 딱 맞는 보답을 해주지요.","Als je zoveel tijd te verliezen hebt, kijk dan of je de blauwe kelk kunt vinden. Mijn studies over de Orde suggereren dat ze het ergens in de productiesector van de fabriek verborgen hebben. Dit artefact zou van grote waarde zijn voor mij, dus, breng het naar mij, en ik zal je helpen.",,"Se você tem tanto tempo livre assim, veja se você consegue achar o cálice azul. Pelo que pesquisei sobre a Ordem, eles o esconderam em algum lugar no setor de manufatura da fábrica. Esse artefato seria de grande valor pra mim, então traga ele para mim e eu te ajudarei.",,,"Если тебе не жаль времени, найди синюю чашу. Я изучал Орден и узнал, что они спрятали её где-то в обрабатывающем секторе фабрики. Мне очень нужен этот артефакт. Принеси его мне, и я помогу тебе.", -"You found the blue chalice! OK, give it to me first, and we'll trade.",TXT_DLG_SCRIPT23_D16676_YOUFO,,,,"Tys našel modrý kalich! Dobře, nejprv mi ho dej a vyrovnáme se.","Du hast den blauen Kelch gefunden! Ok, erst gibst du ihn mir, dann handeln wir.",,,"¡Has encontrado el cáliz azul! Ok, dámelo primero, y negociamos.",,,"Vous avez le Calice Bleu! Ok, donnez le moi et nous échangerons.",,,"青の聖杯を見つけたのか! -良し、それをくれたら取引に応じよう。",푸른 성배를 정말로 찾으셨군요! 저에게 주세요. 그럼 거래를 시작하죠!,"Je hebt de blauwe kelk gevonden! Oké, geef hem eerst aan mij, dan ruilen we hem.",,"Você achou o cálice azul! Ok, me dê ele primeiro e aí a gente negocia.",,,"Ты нашёл синюю чашу! Отдай её мне, и я исполню свою часть договора.", -"Take it, it's bad luck anyway.",TXT_RPLY0_SCRIPT23_D16676_TAKEI,,,,"Vem si ho, stejně přináší jen smůlu.","Nimm ihn, er bringt sowieso Unglück.",,,"Toma, de todos modos da mala suerte.",,,"Gardez le, je parie qu'il file malchance.",,,渡そう、兎に角運が悪かった。,여기 받아요. 재수 없어 보이니까.,"Neem het, het is toch al pech.",,Pode pegar. Isso atrai azar de qualquer forma.,,,Держи. Она всё равно приносит несчастье., -"Screw you, I'm keeping it.",TXT_RPLY1_SCRIPT23_D16676_SCREW,,,,"Jdi se vycpat, nechám si ho.","Ach, was soll's. Ich behalte ihn.",,,"Que te zurzan, me lo quedo.","Al diablo, me lo quedo.",,"Allez vous faire voir, il est à moi maintenant.",,,ふざけるな、俺の物だ。,"배 째시지, 이건 이제 제거에요.","Krijg de klere, ik hou het.",,"Vá se ferrar, ele é meu.",,,Пошёл ты! Я оставлю её себе., -Then I'm not giving you anything. Get lost!,TXT_RYES1_SCRIPT23_D16676_THENI,,,,Pak ti nic nedám. Zmizni!,Dann bekommst du auch nichts von mir. Verzieh dich!,,,Entonces no te voy a dar nada. ¡Piérdete!,,,"Rien pour vous, alors, dégagez!",,,何もやるモンは無いぞ。失せな!,이런 식으로 나가시겠다? 그럼 거래를 취소하죠. 사라지세요!,Dan geef ik je niets. Donder op!,,Então não te darei nada. Se manda!,,,Тогда я тебе ничего не скажу. Убирайся!, -Locate the forge. The information I just gave you should help you enter a secretive sector of the factory. One of the forge workers can open the door.,TXT_DLG_SCRIPT23_D18192_LOCAT,,,,"Najdi kovárnu. Informace, které jsem ti právě dal, ti pomůžou vstoupit do tajného sektoru továrny. Jeden z pracovníků kovárny ti otevře dveře.","Finde die Schmiede. Die Informationen, die ich dir gegeben habe, sollten dir helfen einen geheimen Sektor der Fabrik zu betreten. Einer der Schmiedearbeiter kann dir helfen die Tür zu öffnen.",,,Localiza la forja. La información que te he dado debería ayudarte a entrar a un sector secreto de la fábrica. Uno de los trabajadores de la forja puede abrir la puerta.,,,Localisez la forge. L'information que je vous ai donnée devrait vous aider à entrer dans une section secrète de l'usine. L'un des travailleurs de la forge peut ouvrir la porte pour vous.,,,"工場の鉄工所を探せ。俺が与えた情報は +持ってきたら協力しよう。","만약 시간이 남아돈다면, 푸른 성배를 찾아보러 가시는 게 어떤가요? 오더에 대한 제 연구가 맞아떨어진다면, 그것은 분명히 공장의 조립시설에 숨겨져 있을 겁니다. 그 보물은 더 할 말 없이 아주 진귀할 거에요. 그걸 찾아주면, 딱 맞는 보답을 해주지요.","Als je zoveel tijd te verliezen hebt, kijk dan of je de blauwe kelk kunt vinden. Mijn studies over de Orde suggereren dat ze het ergens in de productiesector van de fabriek verborgen hebben. Dit artefact zou van grote waarde zijn voor mij, dus, breng het naar mij, en ik zal je helpen.","Hvis du har så mye tid å kaste bort, se om du kan finne det blå begeret. Mine studier om Ordenen tyder på at de har gjemt det et sted i fabrikkens produksjonssektor. Denne gjenstanden vil være av stor verdi for meg, så ta den med til meg, så skal jeg hjelpe deg.","Jeśli masz tyle czasu do stracenia, sprawdź, czy znajdziesz niebieski kielich. Moje badania nad Zakonem sugerują, że ukryli go gdzieś w sektorze produkcyjnym fabryki. Ten artefakt miałby dla mnie ogromną wartość, więc, przynieś go do mnie, a pomogę ci.","Se você tem tanto tempo livre assim, veja se você consegue achar o cálice azul. Pelo que pesquisei sobre a Ordem, eles o esconderam em algum lugar no setor de manufatura da fábrica. Esse artefato seria de grande valor pra mim, então traga ele para mim e eu te ajudarei.",,"Dacă ai atât de mult timp de pierdut, vezi dacă poți găsi pocalul albastru. Studiile mele indică faptul că Ordinul l-a ascuns undeva în sectorul de manufactură al fabricii. Artefactul mi-ar fi de mare folos, așa că, adu-mi-l, și o să te ajut.","Если тебе не жаль времени, найди синюю чашу. Я изучал Орден и узнал, что они спрятали её где-то в обрабатывающем секторе фабрики. Мне очень нужен этот артефакт. Принеси его мне, и я помогу тебе.",,"Om du har så mycket tid att slösa, se om du kan hitta den blå bägaren. Mina studier om orden tyder på att de har gömt den någonstans i fabrikens tillverkningssektor. Denna artefakt skulle vara av stort värde för mig, så, ta med den till mig så ska jag hjälpa dig.","Kaybedecek bu kadar zamanın varsa, mavi kadehi bulmaya çalış. Tarikat üzerine yaptığım çalışmalar, onu fabrikanın üretim bölümünde bir yere sakladıklarını gösteriyor. Bu obje benim için çok değerli, bu yüzden onu bana getir, ben de sana yardım edeyim." +"You found the blue chalice! OK, give it to me first, and we'll trade.",TXT_DLG_SCRIPT23_D16676_YOUFO,〃,,,"Tys našel modrý kalich! Dobře, nejprv mi ho dej a vyrovnáme se.","Du har fundet den blå bæger! OK, giv mig den først, så kan vi bytte.","Du hast den blauen Kelch gefunden! Ok, erst gibst du ihn mir, dann handeln wir.",,"Vi trovis la bluan kalikon! Bone, vi unue donu ĝin kaj tiam ni interkonsentos.","¡Has encontrado el cáliz azul! Bueno, dámelo primero y negociamos.","¡Encontraste el cáliz azul! Bueno, dámelo primero y negociamos.","Löysit sinisen maljan! No niin, anna se ensin minulle, niin tehdään vaihtokaupat.","Vous avez le Calice Bleu! Ok, donnez le moi et nous échangerons.","Megszerezted a kék serleget! OK, add ide gyorsan először, aztán üzletelhetünk.","Hai trovato il calice blu! OK, dammelo, e poi possiamo trattare.","青の聖杯を見つけたのか! +良し、それをくれたら取引に応じよう。",푸른 성배를 정말로 찾으셨군요! 저에게 주세요. 그럼 거래를 시작하죠!,"Je hebt de blauwe kelk gevonden! Oké, geef hem eerst aan mij, dan ruilen we hem.","Du fant det blå begeret! OK, gi det til meg først, så bytter vi.","Znalazłeś niebieski kielich! OK, daj mi go najpierw, a wymienimy się.","Você achou o cálice azul! Ok, me dê ele primeiro e aí a gente negocia.",,"Ai găsit pocalul albastru! OK, dă-mi-l, și o să facem schimb.","Ты нашёл синюю чашу! Отдай её мне, и я исполню свою часть договора.",,"Du har hittat den blå bägaren! Okej, ge den till mig först så byter vi.","Mavi kadehi bulmuşsun! Tamam, önce onu bana ver, sonra takas ederiz." +"Take it, it's bad luck anyway.",TXT_RPLY0_SCRIPT23_D16676_TAKEI,〃,,,"Vem si ho, stejně přináší jen smůlu.","Tag den, den bringer alligevel uheld.","Nimm ihn, er bringt sowieso Unglück.",,"Havu, ĝi alportas misfortunon.","Toma, de todos modos da mala suerte.",,"Ota se, epäonnenkalu se kuitenkin on.","Gardez le, je parie qu'il file malchance.","Vidd nyugodtan, rossz szerencsét hoz amúgyis.","Prendilo, tanto porta sfortuna.",渡そう、兎に角運が悪かった。,여기 받아요. 재수 없어 보이니까.,"Neem het, het is toch al pech.","Ta det, det bringer ulykke uansett.","Weź go, to i tak przynosi pecha.",Pode pegar. Isso atrai azar de qualquer forma.,,"Ia-l, poartă ghinion oricum.",Держи. Она всё равно приносит несчастье.,,"Ta den, den betyder ändå otur.","Al, zaten kötü şans getirir." +"Screw you, I'm keeping it.",TXT_RPLY1_SCRIPT23_D16676_SCREW,〃,,,"Jdi se vycpat, nechám si ho.","Rend mig, jeg beholder den.","Ach, was soll's. Ich behalte ihn.",,"Al la diablo, mi konservos ĝin.","Que te zurzan, me lo quedo.","Al diablo, me lo quedo.","Vedä käteen, pidän sen itselläni.","Allez vous faire voir, il est à moi maintenant.","Nagy francot, inkább megtartom.",E invece me lo tengo!,ふざけるな、俺の物だ。,"배 째시지, 이건 이제 제거에요.","Krijg de klere, ik hou het.","Faen ta deg, jeg beholder det.","Wal się, zatrzymuję go.","Vá se ferrar, ele é meu.",,"Du-te naibi, îl păstrez.",Пошёл ты! Я оставлю её себе.,,"Dra åt helvete, jag behåller den.","Siktir git, bende kalacak." +Then I'm not giving you anything. Get lost!,TXT_RYES1_SCRIPT23_D16676_THENI,〃 (If you keep the chalice),,,Pak ti nic nedám. Zmizni!,Så giver jeg dig ikke noget. Forsvind!,Dann bekommst du auch nichts von mir. Verzieh dich!,,"Tiuokaze mi donos +nenion al vi. Foriru!","Entonces +no te doy nada. ¡Vete!",,Sitten en anna sinulle mitään. Antaa vetää!,"Rien pour vous, alors, dégagez!",Akkor meg tudod mikor adok neked bármit is. Húzzál elfelé!,E allora non ti darò niente. Sparisci!,何もやるモンは無いぞ。失せな!,이런 식으로 나가시겠다? 그럼 거래를 취소하죠. 사라지세요!,Dan geef ik je niets. Donder op!,Da gir jeg deg ingenting. Forsvinn!,Więc nic ci nie dam. Spadaj!,Então não te darei nada. Se manda!,,Atunci nu îți dau nimic. Valea!,Тогда я тебе ничего не скажу. Убирайся!,,Då ger jag dig ingenting. Försvinn!,O zaman sana hiçbir şey vermiyorum. Kaybol! +Locate the forge. The information I just gave you should help you enter a secretive sector of the factory. One of the forge workers can open the door.,TXT_DLG_SCRIPT23_D18192_LOCAT,〃 (If you give the chalice away),,,"Najdi slévárnu. Informace, které jsem ti právě dal, ti pomůžou vstoupit do tajného sektoru továrny. Jeden z pracovníků slévárny ti otevře dveře.","Find smedjen. De oplysninger, jeg lige har givet dig, skulle hjælpe dig med at komme ind i en hemmelig sektor af fabrikken. En af smediearbejderne kan åbne døren.","Finde die Schmiede. Die Informationen, die ich dir gegeben habe, sollten dir helfen einen geheimen Sektor der Fabrik zu betreten. Einer der Schmiedearbeiter kann dir helfen die Tür zu öffnen.",,"Iru al la forĝejo. La informoj, kiujn mi donis, devus permesi al vi eniri sekretan sektoron en la fabriko. Unu el la laboristoj en la forĝejo povas malfermi la pordon.",Ve a la forja. La información que te he dado debería permitirte entrar en un sector secreto de la fábrica. Uno de los trabajadores de la forja puede abrir la puerta.,Ve a la forja. La información que te di debería permitirte entrar a un sector secreto de la fábrica. Uno de los trabajadores de la forja puede abrir la puerta.,Suunnista pajalle. Juuri antamani tiedon pitäisi auttaa sinua pääsemään salamyhkäiseen osastoon tehtaalla. Yksi pajan työntekijöistä voi avata oven.,Localisez la forge. L'information que je vous ai donnée devrait vous aider à entrer dans une section secrète de l'usine. L'un des travailleurs de la forge peut ouvrir la porte pour vous.,"Keresd meg a kohót. Az információ amit adtam, segíteni fog abban, hogy megleld a gyár titkos részét. Az egyik kohóban dolgozó ki tudja nyitni az ajtót.",Trova la fucina. Le informazioni che ti ho appena dato ti dovrebbero aiutare a trovare una sezione segreta della Fabbrica. Uno dei lavoratori della fucina ti potrà aprire la porta.,"工場の鉄工所を探せ。俺が与えた情報は そこの隠された区域に入る為に必要だ。 -偽の作業員がドアを開けるだろう。",공장의 제련소로 찾아가세요. 제가 제공한 정보만 있으면 그곳으로 향하는 비밀구역을 쉽게 찾을 수 있을 겁니다. 제련소 직원 중 한 명이 그곳으로 향하는 문을 열 수 있어요.,Zoek de smederij. De informatie die ik je net heb gegeven zou je moeten helpen om een geheime sector van de fabriek te betreden. Een van de smidsewerkers kan de deur openen.,,Localize a forja. A informação que acabei de te passar deve ajudar para entrar em um setor secreto da fábrica. Um dos operários da forja pode abrir a porta.,,,"Найди кузню. Сведения, которые я передал тебе, помогут тебе пройти в секретный сектор фабрики. Один из работников в кузне откроет тебе дверь.", -What can I find there?,TXT_RPLY0_SCRIPT23_D18192_WHATC,,,,Co tam můžu najít?,Was kann ich dort finden?,,,¿Qué puedo encontrar allí?,,,Qu'est ce que je peux y trouver?,,,そこには何がある?,그곳을 어떻게 찾을 수 있죠?,Wat kan ik daar vinden?,,O que vou encontrar lá?,,,Что там находится?, -My research suggests that some dark power from the ancient past is hidden there. Be careful!,TXT_DLG_SCRIPT23_D19708_MYRES,,,,"Můj výzkum naznačuje, že se tam schovává nějaká starověká temná síla. Buď opatrný!","Meine Nachforschungen lassen vermuten, dass dort eine dunkle Macht aus längst vergangenen Zeiten versteckt ist. Sei vorsichtig!",,,Mi investigación sugiere que algún poder oscuro de la antigüedad se oculta allí. ¡Ten cuidado!,,,Mes recherches suggèrent qu'il y a un pouvoir sombre ancien qui s'y cache. Faites attention!,,,"俺の調査では、古代の災厄がそこに隠されている -という話だ。注意しろよ!","제가 연구를 좀 더 해봤는데, 그곳에서 사악한 고대의 기운이 솟아난다는군요. 조심하시길!",Mijn onderzoek suggereert dat daar een duistere kracht uit het oude verleden verborgen ligt. Wees voorzichtig!,,Minha pesquisa sugere que há algum poder sombrio do passado antigo escondido naquele lugar. Tome cuidado!,,,Судя по результатам исследования — какая-то тёмная сила из далёкого прошлого. Будь осторожен!, -"That blue chalice, how'd you come by it? I've been researching the Order and their links to the distant past, and that artifact would help me. Let's make a deal. Give me the chalice, and I'll give you some info.",TXT_DLG_SCRIPT23_D21224_THATB,,,,"Ten modrý kalich, jak jsi k němu přišel? Zkoumal jsem Řád a jeho pojítka k dávné minulosti a ten artefakt by mi pomohl. Udělejme dohodu: Ty mi dáš ten kalich a já ti dám nějaké informace.","Dieser blaue Kelch, wie bist du da ran gekommen? Ich habe bereits über den Orden und deren Verbindung zur fernen Vergangenheit recherchiert, und dieses Artefakt könnte mir weiterhelfen. Ich schlage dir etwas vor: Gib mir den Kelch und ich gebe dir Informationen.",,,"Ese cáliz azul, ¿Cómo lo has encontrado? He estado investigando a la Orden y sus conexiones con el pasado distante, y ese artefacto me ayudaría. Hagamos un trato. Dame el cáliz, y te daré algo de información.",,,"Ce calice bleu, comment l'avez vous trouvé? Je fais des recherches sur l'Ordre et leurs liens avec le passé. Cet artéfact m'aiderait beaucoup. Faisons affaires: donnez le moi et je vous aiderai.",,,"その青い聖杯はどうした? +偽の作業員がドアを開けるだろう。",공장의 제련소로 찾아가세요. 제가 제공한 정보만 있으면 그곳으로 향하는 비밀구역을 쉽게 찾을 수 있을 겁니다. 제련소 직원 중 한 명이 그곳으로 향하는 문을 열 수 있어요.,Zoek de smederij. De informatie die ik je net heb gegeven zou je moeten helpen om een geheime sector van de fabriek te betreden. Een van de smidsewerkers kan de deur openen.,Finn smia. Informasjonen jeg nettopp ga deg bør hjelpe deg å komme inn i en hemmelig sektor av fabrikken. En av smiearbeiderne kan åpne døren.,"Zlokalizuj kuźnię. Informacje, które przed chwilą podałem, powinny pomóc ci wejść do tajnego sektora fabryki. Jeden z pracowników kuźni może otworzyć drzwi.",Localize a forja. A informação que acabei de te passar deve ajudar para entrar em um setor secreto da fábrica. Um dos operários da forja pode abrir a porta.,,Găsește forja. Informațiile pe care ți le-am oferit ar trebui să te ajute să intri într-un sector secret al fabricii. Unul dintre făurari poate deschide ușa.,"Найди кузню. Сведения, которые я передал тебе, помогут тебе пройти в секретный сектор фабрики. Один из работников в кузне откроет тебе дверь.",,Leta upp smedjan. Informationen jag just gav dig ska hjälpa dig att komma in i en hemlig sektor av fabriken. En av smidesarbetarna kan öppna dörren.,Demirhaneyi bulun. Sana verdiğim bilgiler fabrikanın gizli bir bölümüne girmene yardımcı olacaktır. Demirci işçilerinden biri kapıyı açabilir. +What can I find there?,TXT_RPLY0_SCRIPT23_D18192_WHATC,〃,,,Co tam můžu najít?,Hvad kan jeg finde der?,Was kann ich dort finden?,,Kion mi trovos tien?,¿Qué puedo encontrar allí?,,Mitä löydän sieltä?,Qu'est ce que je peux y trouver?,Mit fogok ott találni?,Che cosa troverò là?,そこには何がある?,그곳을 어떻게 찾을 수 있죠?,Wat kan ik daar vinden?,Hva kan jeg finne der?,Co mogę tam znaleźć?,O que vou encontrar lá?,,Ce pot găsi acolo?,Что там находится?,,Vad kan jag hitta där?,Orada ne bulabilirim? +My research suggests that some dark power from the ancient past is hidden there. Be careful!,TXT_DLG_SCRIPT23_D19708_MYRES,〃,,,"Můj výzkum naznačuje, že se tam schovává nějaká starověká temná síla. Buď opatrný!","Min forskning tyder på, at der er gemt en mørk magt fra den gamle fortid der. Vær forsigtig!","Meine Nachforschungen lassen vermuten, dass dort eine dunkle Macht aus längst vergangenen Zeiten versteckt ist. Sei vorsichtig!",,"Mia esplorado sugestas, ke malluma povo de la antikveco estas kaŝita tie. Gardu vin!",Mi investigación sugiere que un poder oscuro de la antigüedad se oculta allí. ¡Ten cuidado!,,"Tutkimukseni viittaa siihen, että jokin pimeä voima muinaismenneisyydestä on kätketty sinne. Ole varuillasi!",Mes recherches suggèrent qu'il y a un pouvoir sombre ancien qui s'y cache. Faites attention!,"A kutatásaim azt mutatják, hogy az ősidőkből maradt sötét erő bújik meg ott. Légy óvatos!","Dopo attente ricerche sul materiale che ho, ho stabilito che un oscuro e antico potere è nascosto lì. Fai attenzione!","俺の調査では、古代の災厄がそこに隠されている +という話だ。注意しろよ!","제가 연구를 좀 더 해봤는데, 그곳에서 사악한 고대의 기운이 솟아난다는군요. 조심하시길!",Mijn onderzoek suggereert dat daar een duistere kracht uit het oude verleden verborgen ligt. Wees voorzichtig!,Forskningen min tyder på at en mørk kraft fra fortiden er skjult der. Vær forsiktig!,"Moje badania sugerują, że ukryta jest tam jakaś mroczna moc z zamierzchłej przeszłości. Bądź ostrożny!",Minha pesquisa sugere que há algum poder sombrio do passado antigo escondido naquele lugar. Tome cuidado!,,Investigațiile mele indică faptul că ceva putere întunecată din trecutul antic e ascunsă acolo. Ai grijă!,"Судя по результатам исследования, какая-то тёмная сила из далёкого прошлого. Будь осторожен!",,Min forskning tyder på att någon mörk kraft från det forntida förflutna är gömd där. Var försiktig!,"Araştırmalarım, kadim geçmişten gelen karanlık bir gücün orada saklı olduğunu gösteriyor. Dikkatli ol!" +"That blue chalice, how'd you come by it? I've been researching the Order and their links to the distant past, and that artifact would help me. Let's make a deal. Give me the chalice, and I'll give you some info.",TXT_DLG_SCRIPT23_D21224_THATB,"SVE.WAD +MAP23: Timothy (Talking with him for the very first time with the chalice).",,,"Ten modrý kalich, jak jsi k němu přišel? Zkoumal jsem Řád a jeho pojítka k dávné minulosti a ten artefakt by mi pomohl. Udělejme dohodu: Ty mi dáš ten kalich a já ti dám nějaké informace.","Den blå bæger, hvordan er du kommet til den? Jeg har forsket i Ordenen og deres forbindelser til den fjerne fortid, og denne artefakt ville hjælpe mig. Lad os lave en aftale. Giv mig bægeret, og jeg giver dig nogle oplysninger.","Dieser blaue Kelch, wie bist du da ran gekommen? Ich habe bereits über den Orden und deren Verbindung zur fernen Vergangenheit recherchiert, und dieses Artefakt könnte mir weiterhelfen. Ich schlage dir etwas vor: Gib mir den Kelch und ich gebe dir Informationen.",,"Tiu blua kaliko, kiel vi trovis ĝin? Mi esploradis La Ordenon kaj ĝiajn rilatojn kun la fora pasinteco, kaj tiu artefakto helpus min. Ni intertraktu: donu al mi la kalikon kaj mi donos informojn al vi.","Ese cáliz azul, ¿de dónde lo has sacado? He estado investigando a La Orden y sus conexiones con el pasado lejano, y ese artefacto me serviría. Hagamos un trato: dame el cáliz y te daré algo de información.","Ese cáliz azul, ¿de dónde lo sacaste? He estado investigando a La Orden y sus conexiones con el pasado lejano, y ese artefacto me serviría. Hagamos un trato: dame el cáliz y te doy algo de información.","Tuo sininen uhrimalja, miten onnistuit saamaan sen? Olen tutkinut Veljeskuntaa ja sen kytköksiä kaukaiseen menneisyyteen, ja tuo esine auttaisi minua. Tehdäänpä kauppa: Sinä annat minulle maljan, ja minä annan sinulle tietoa.","Ce calice bleu, comment l'avez vous trouvé? Je fais des recherches sur l'Ordre et leurs liens avec le passé. Cet artéfact m'aiderait beaucoup. Faisons affaires: donnez le moi et je vous aiderai.","Hogyan sikerült megszerened azt a kék serleget? Kutattam a Rendet és kapcsolatukat a messzi múlttal, és ez az ereklye nagy segítség lenne. Kössünk üzletet. Add ide a serleget, és cserébe kapsz információt.","Quel calice blu, come lo hai trovato? Ho passato molto tempo a ricercare l'Ordine e i suoi legami con il lontano passato, e quell'artifatto mi aiuterebbe. Facciamo una cosa. Se mi dai il calice, io ti darò delle informazioni.","その青い聖杯はどうした? 私はオーダーの遥か過去の関係について調査 していた、その骨董品が手掛かりになりそうだ。 -取引しよう、聖杯をくれれば幾つか情報を渡す。","저 푸른 성배... 어떻게 찾으신 거죠? 오더와 그들의 과거를 좀 조사하던 참이었습니다. 저 보물만 있으면 아주 커다란 도움이 될 것입니다. 그 성배를 주신다면, 좋은 정보를 알려주겠습니다.","Die blauwe kelk, hoe kom je eraan? Ik heb de Orde en hun verbanden met het verre verleden onderzocht, en dat artefact zou me helpen. Laten we een deal sluiten. Geef me de kelk en ik zal je wat informatie geven.",,"Esse cálice azul, como você o encontrou? Estive pesquisando sobre a Ordem e o seu vínculo com o passado distante e esse artefato me ajudaria. Vamos fazer um trato. Me dê o cálice e eu te dou informações.",,,"Эта синяя чаша, откуда она у тебя? Мои исследования Ордена связаны с событиями далёкого прошлого, и мне очень нужен этот артефакт. Давай заключим сделку. Ты мне чашу, а я тебе — информацию.", -"Take it, it's bad luck anyway.",TXT_RPLY0_SCRIPT23_D21224_TAKEI,,,,"Vem si ho, stejně přináší jen smůlu.","Nimm ihn, er bringt sowieso Unglück.",,,"Toma, de todos modos da mala suerte.",,,"Gardez le, je parie qu'il file malchance.",,,渡そう、兎に角運が悪かった。,"값어치도 없을 것 같은데, 그냥 가져가세요.","Neem het, het is toch al pech.",,Pode pegar. Isso atrai azar de qualquer forma.,,,Держи. Она всё равно приносит несчастье., -"Screw you, I'm keeping it.",TXT_RPLY1_SCRIPT23_D21224_SCREW,,,,"Jdi se vycpat, nechám si ho.","Ach, was soll's. Ich behalte ihn.",,,"Que te zurzan, me lo quedo.","Al diablo, me lo quedo.",,"Allez vous faire voir, il est à moi maintenant.",,,ふざけるな、俺の物だ。,뭔 개소리야? 이제 이건 내 것이라고!,"Krijg de klere, ik hou hem.",,"Vá se ferrar, ele é meu.",,,Пошёл ты! Я оставлю её себе., -Then I'm not giving you anything. Get lost!,TXT_RYES1_SCRIPT23_D21224_THENI,,,,Pak ti nic nedám. Zmizni!,Dann bekommst du auch nichts von mir. Verzieh dich!,,,Entonces no te voy a dar nada. ¡Piérdete!,,,"Rien pour vous, alors, dégagez!",,,何もやるモンは無いぞ。失せな!,아주 좋은 기회를 다 날려버리시는군. 꺼져요!,Dan geef ik je niets. Donder op!,,Então não te darei nada. Se manda!,,,Тогда я тебе ничего не скажу. Убирайся!, -"Now, what can I help you with?",TXT_DLG_SCRIPT23_D22740_NOWWH,,,,"Tak, s čím ti mohu pomoci?","Nun, wie kann ich dir weiterhelfen?",,,"Ahora, ¿En qué puedo ayudarte?",,,"Bon, que puis-je pour vous?",,,今手伝ってくれるか?,"그럼, 뭘 더 도와드릴까요?","Nu, waar kan ik je mee helpen?",,"Então, como posso ajudá-lo?",,,"Итак, чем я могу быть тебе полезен?", -Shadow armor?,TXT_RPLY0_SCRIPT23_D22740_SHADO,,,Shadow armour?,Stínové brnění?,Schattenrüstung?,,,¿Armadura de sombra?,,,Armure des ombres?,,,シャドウアーマー?,그림자 갑옷?,Schaduw pantser?,,Armadura das sombras?,,,Теневой бронёй?, -"Ahh, to be heard, but not seen!",TXT_RYES0_SCRIPT23_D22740_AHHTO,,,,"Áha, být slyšen, ne viděn!","Ah, um gehört zu werden, aber ungesehen zu bleiben.",,,"Ahh, ¡Para ser oído, pero no visto!",,,"Ah, pour se faire entendre, sans se faire voir!",,,ああ、声はすれど姿は見えず。,들켜도 당신을 계속 맞추진 못할 거요!,"Ahhh, om gehoord, maar niet gezien te worden!",,"Ahh, ser ouvido mas não ser visto!",,,"Ах, чтобы быть услышанным, но не увиденным!", -"Get out of here, come back when you have some cash.",TXT_RNO0_SCRIPT23_D22740_GETOU,,,,"Vypadni a vrať se, když budeš mít peníze.","Verzieh dich, komm wieder, wenn du etwas Geld hast.",,,"Vete de aquí, vuelve cuando tengas algo de efectivo.",,,"Sortez de là, revenez quand vous avez de l'argent!",,,ここを出て、稼いでからまた来てくれ!,이 유용한 도구를 공짜로 주기엔 영 그렇군요.,"Ga hier weg, kom terug als je wat geld hebt.",,Vá embora daqui. Volte quando tiver dinheiro.,,,"Выметайся вон. Вернёшься, когда раздобудешь наличности.", -"Thank deus you got here. To enter the factory you need a key. We stole it but our agent is missing in the web of catacombs under the Order's stronghold. I have sent ten good men into those tunnels to find him, and none have returned. Something is down there!",TXT_DLG_SCRIPT23_D24256_THANK,,,,"Díky bohu, žes přišel. Aby ses dostal do továrny, potřebuješ klíč. Ten jsme ukradli, ale náš agent se ztratil v sítí katakomb pod pevností Řádu. Poslal jsem do těch tunelů deset dobrých mužů a žádný se nevrátil. Něco tam dole je!","Deus sei dank bist du hier. Um die Fabrik zu betreten, brauchst du einen Schlüssel. Wir haben ihn gestohlen, aber unser Agent ist in den Irrwegen der Katakomben unter Festung des Ordens verschwunden. Ich habe zehn gute Männer da hinunter geschickt um ihn zu finden, aber niemand ist zurückgekehrt. Irgendetwas ist da unten!",,,"Gracias a deus que estás aquí. Para entrar en la fábrica necesitas una llave. La robamos, pero nuestro agente está perdido en la red de catacumbas debajo de la fortaleza de la Orden. He enviado diez buenos hombres a esos túneles para encontrarlo, y ninguno ha regresado. ¡Hay algo ahí abajo!",,,"Merci Dieu, vous êtes là. Pour entrer dans l'usine, il vous faut une clé. On l'a volé, mais notre agent a disparu dans le dédale de catacombes sous la forteresse de l'Ordre. On a envoyé dix hommes dans ces tunnels pour le retrouver mais personne n'est revenu. Il doit y avoir quelque chose, là dedans!",,,"ようやく来てくれたか。 +取引しよう、聖杯をくれれば幾つか情報を渡す。","저 푸른 성배... 어떻게 찾으신 거죠? 오더와 그들의 과거를 좀 조사하던 참이었습니다. 저 보물만 있으면 아주 커다란 도움이 될 것입니다. 그 성배를 주신다면, 좋은 정보를 알려주겠습니다.","Die blauwe kelk, hoe kom je eraan? Ik heb de Orde en hun verbanden met het verre verleden onderzocht, en dat artefact zou me helpen. Laten we een deal sluiten. Geef me de kelk en ik zal je wat informatie geven.","Det blå begeret, hvordan fikk du tak i det? Jeg har forsket på Ordenen og deres forbindelser til en fjern fortid, og den gjenstanden kan hjelpe meg. La oss gjøre en avtale. Gi meg begeret, så gir jeg deg informasjon.","Ten niebieski kielich, skąd go masz? Badałem Zakon i ich powiązania z odległą przeszłością, a ten artefakt mógłby mi pomóc. Zawrzyjmy układ. Daj mi kielich, a ja dam ci trochę informacji.","Esse cálice azul, como você o encontrou? Estive pesquisando sobre a Ordem e o seu vínculo com o passado distante e esse artefato me ajudaria. Vamos fazer um trato. Me dê o cálice e eu te dou informações.",,"Acel potir albastru, cum l-ai găsit? Am cercetat Ordinul și legăturile lor cu trecutul, iar acel artefact mă poate ajuta. Să facem un târg, Îmi dai potirul, iar eu îți dau informații.","Эта синяя чаша... откуда она у тебя? Мои исследования Ордена связаны с событиями далёкого прошлого, и мне очень нужен этот артефакт. Давай заключим сделку: ты мне чашу, а я тебе — информацию.",,"Den blå kalken, hur kom du över den? Jag har forskat om orden och deras kopplingar till det förflutna, och den artefakten skulle hjälpa mig. Låt oss göra en överenskommelse. Ge mig bägaren, så ger jag dig lite information.","O mavi kadehi nereden buldun? Tarikat'ı ve uzak geçmişle bağlantılarını araştırıyordum ve bu eser bana yardımcı olabilir. Bir anlaşma yapalım. Kadehi bana ver, ben de sana biraz bilgi vereyim." +"Take it, it's bad luck anyway.",TXT_RPLY0_SCRIPT23_D21224_TAKEI,〃,,,"Vem si ho, stejně přináší jen smůlu.","Tag den, den bringer alligevel uheld.","Nimm ihn, er bringt sowieso Unglück.",,"Havu, ĝi alportas misfortunon.","Toma, de todos modos da mala suerte.",,"Ota se, epäonnenkalu se kuitenkin on.","Gardez le, je parie qu'il file malchance.","Vidd nyugodtan, rossz szerencsét hoz amúgyis.","Prendilo, tanto porta sfortuna.",渡そう、兎に角運が悪かった。,"값어치도 없을 것 같은데, 그냥 가져가세요.","Neem het, het is toch al pech.","Ta det, det bringer ulykke uansett.","Weź go, to i tak przynosi pecha.",Pode pegar. Isso atrai azar de qualquer forma.,,"Ia-l, poartă ghinion oricum.",Держи. Она всё равно приносит несчастье.,,"Ta den, den betyder ändå otur.","Al, zaten kötü şans getirir." +"Screw you, I'm keeping it.",TXT_RPLY1_SCRIPT23_D21224_SCREW,〃,,,"Jdi se vycpat, nechám si ho.","Rend mig, jeg beholder den.","Ach, was soll's. Ich behalte ihn.",,"Al la diablo, mi konservos ĝin.","Que te zurzan, me lo quedo.","Al diablo, me lo quedo.","Vedä käteen, pidän sen itselläni.","Allez vous faire voir, il est à moi maintenant.","Nagy francot, inkább megtartom.",E invece me lo tengo!,ふざけるな、俺の物だ。,뭔 개소리야? 이제 이건 내 것이라고!,"Krijg de klere, ik hou hem.","Faen ta deg, jeg beholder det.","Wal się, zatrzymam go.","Vá se ferrar, ele é meu.",,"Du-te naibi, îl păstrez.",Пошёл ты! Я оставлю её себе.,,"Dra åt helvete, jag behåller den.","Siktir git, bende kalacak." +Then I'm not giving you anything. Get lost!,TXT_RYES1_SCRIPT23_D21224_THENI,〃,,,Pak ti nic nedám. Zmizni!,Så giver jeg dig ikke noget. Forsvind!,Dann bekommst du auch nichts von mir. Verzieh dich!,,"Tiuokaze mi donos +nenion al vi. Foriru!","Entonces +no te doy nada. ¡Vete!",,Sitten en anna sinulle mitään. Antaa vetää!,"Rien pour vous, alors, dégagez!",Akkor meg tudod mikor adok neked bármit is. Húzzál elfelé!,E allora non ti darò niente. Sparisci!,何もやるモンは無いぞ。失せな!,아주 좋은 기회를 다 날려버리시는군. 꺼져요!,Dan geef ik je niets. Donder op!,Da gir jeg deg ingenting. Forsvinn!,Więc nic ci nie dam. Spadaj!,Então não te darei nada. Se manda!,,Atunci nu îți dau nimic. Valea!,Тогда я тебе ничего не скажу. Убирайся!,,Då ger jag dig ingenting. Försvinn!,O zaman sana hiçbir şey vermiyorum. Kaybol! +"Now, what can I help you with?",TXT_DLG_SCRIPT23_D22740_NOWWH,"SVE.WAD +MAP23: Tevick.",,,"Tak, s čím ti mohu pomoci?",Hvad kan jeg hjælpe dig med?,"Nun, wie kann ich dir weiterhelfen?",,"Nu, kion mi povas doni al vi?","Y bueno, ¿en qué puedo ayudarte?",,"No niin, miten voin palvella?","Bon, que puis-je pour vous?",Akkor miben segíthetek?,"E ora, come posso aiutarti?",今手伝ってくれるか?,"그럼, 뭘 더 도와드릴까요?","Nu, waar kan ik je mee helpen?",Hva kan jeg hjelpe deg med?,"A teraz, w czym mogę ci pomóc?","Então, como posso ajudá-lo?",,"Acum, cu ce te pot ajuta?","Итак, чем я могу быть тебе полезен?",,Vad kan jag hjälpa dig med?,"Şimdi, sana nasıl yardım edebilirim?" +Shadow armor?,TXT_RPLY0_SCRIPT23_D22740_SHADO,〃,,Shadow armour?,Stínové brnění?,Skygge rustning?,Schattenrüstung?,,Ĉu ombran armaĵon?,¿Armadura de sombra?,,Varjohaarniska?,Armure des ombres?,Árnyék vért?,Armatura Ombra?,シャドウアーマー?,그림자 갑옷?,Schaduw pantser?,Skyggepanser?,Zbroja cieni?,Armadura das sombras?,,Armura umbrei?,Теневой бронёй?,,Skuggarmering?,Gölge zırhı mı? +"Ahh, to be heard, but not seen!",TXT_RYES0_SCRIPT23_D22740_AHHTO,〃,,,"Áha, být slyšen, ne viděn!","Ahh, at blive hørt, men ikke set!","Ah, um gehört zu werden, aber ungesehen zu bleiben.",,"Ha, por esti aŭdata, +sed ne vidata!","Ah, ¡para ser oído, +pero no visto!",,"Aah, tulla kuulluksi, muttei nähdyksi!","Ah, pour se faire entendre, sans se faire voir!","Csak hallani, de nem látni.","Ahh, per essere sentiti, ma non visti!",ああ、声はすれど姿は見えず。,들켜도 당신을 계속 맞추진 못할 거요!,"Ahhh, om gehoord, maar niet gezien te worden!","Å bli hørt, men ikke sett!","Ahh, być słyszanym, ale nie widzianym!","Ahh, ser ouvido mas não ser visto!",,"Ahh, să fii auzit, dar nu văzut!","Ах, чтобы быть услышанным, но не увиденным!",,"Ahh, att höras men inte ses!","Ahh, duyulmak ama görülmemek!" +"Get out of here, come back when you have some cash.",TXT_RNO0_SCRIPT23_D22740_GETOU,〃,,,"Vypadni a vrať se, když budeš mít peníze.","Forsvind herfra, og kom tilbage, når du har nogle penge.","Verzieh dich, komm wieder, wenn du etwas Geld hast.",,"Foriru. Revenu kiam +vi havos monon.","Vete. Vuelve cuando +tengas efectivo.",,"Antaa vetää; tule takaisin, kun sinulla on käteistä.","Sortez de là, revenez quand vous avez de l'argent!","Na kotródj innen, csak akkor lássalak ha van nálad pénz is.","Fuori di qui, ritorna quando avrai del denaro.",ここを出て、稼いでからまた来てくれ!,이 유용한 도구를 공짜로 주기엔 영 그렇군요.,"Ga hier weg, kom terug als je wat geld hebt.","Kom deg ut herfra, og kom tilbake når du har penger.","Wynoś się stąd, wróć jak będziesz miał trochę kasy.",Vá embora daqui. Volte quando tiver dinheiro.,,"Cară-te, întoarce-te când ai bani.","Выметайся вон. Вернёшься, когда раздобудешь наличности.",,Stick härifrån och kom tillbaka när du har pengar.,"Git buradan, biraz paran olduğunda geri gel." +"Thank Deus you got here. To enter the factory you need a key. We stole it but our agent is missing in the web of catacombs under the Order's stronghold. I have sent ten good men into those tunnels to find him, and none have returned. Something is down there!",TXT_DLG_SCRIPT23_D24256_THANK,"SVE.WAD +MAP23: Richter.",,,"Díky bohu, žes přišel. Aby ses dostal do továrny, potřebuješ klíč. Ten jsme ukradli, ale náš agent se ztratil v sítí katakomb pod pevností Řádu. Poslal jsem do těch tunelů deset dobrých mužů a žádný se nevrátil. Něco tam dole je!","Tak Deus for at du kom her. For at komme ind på fabrikken skal du bruge en nøgle. Vi stjal den, men vores agent er forsvundet i katakomberne under ordenens højborg. Jeg har sendt ti gode mænd ned i disse tunneller for at finde ham, men ingen er vendt tilbage. Der er noget dernede!","Deus sei dank bist du hier. Um die Fabrik zu betreten, brauchst du einen Schlüssel. Wir haben ihn gestohlen, aber unser Agent ist in den Irrwegen der Katakomben unter Festung des Ordens verschwunden. Ich habe zehn gute Männer da hinunter geschickt um ihn zu finden, aber niemand ist zurückgekehrt. Irgendetwas ist da unten!",,"Danke al Dio vi alvenis. Ŝlosilo estas necesa por eniri la fabrikon; ni ŝtelis ĝin, sed nia agento estas perdita en la katakomba sistemo sub la fortreso de La Ordeno. Mi sendis dek bonajn virojn al tiuj tuneloj por serĉi lin kaj neniu revenis. Estas io tie malsupre!","Gracias a Dios, has llegado. Para entrar en la fábrica se necesita una llave; la hemos rodado, pero nuestro agente está perdido en la red de catacumbas debajo de la fortaleza de La Orden. He enviado a diez buenos hombres a esos túneles a buscarlo y ninguno ha regresado. ¡Hay algo ahí abajo!","Gracias a Dios, llegaste. Para entrar a la fábrica se necesita una llave; la robamos, pero nuestro agente está perdido en la red de catacumbas debajo de la fortaleza de La Orden. Mandé a diez buenos hombres a esos túneles a buscarlo y ninguno volvió. ¡Hay algo ahí abajo!","Luojan kiitos, että selvisit perille. Päästäksesi sisälle tehtaaseen tarvitset avaimen. Varastimme sen, mutta vakoojamme on eksynyt Veljeskunnan linnakkeen alapuolella sijaitsevaan katakombiverkostoon. Olen lähettänyt tunneleihin 10 kelpoa miestä etsimään häntä, eikä kukaan ole palannut. Jokin on siellä alla!","Merci Dieu, vous êtes là. Pour entrer dans l'usine, il vous faut une clé. On l'a volé, mais notre agent a disparu dans le dédale de catacombes sous la forteresse de l'Ordre. On a envoyé dix hommes dans ces tunnels pour le retrouver mais personne n'est revenu. Il doit y avoir quelque chose, là dedans!","Hála Deusnak, ideértél.Ahhoz, hogy bejuthass a gyárba kell majd egy kulcs. Habár sikerült ellopnunk a kulcsot, az ügynökünk elveszett a katakombák sűrűjében a Rend erődítménye alatt. Leküldtem tíz jó emberemet utána, de egyikük sem tért vissza. Valami borzasztó lehet ott lent!","Grazie a Dio sei arrivato. Per entrare nella fabbrica ti servirà una chiave. L'abbiamo rubata ma l'agente che l'ha presa è sparito nelle catacombe sotto la fortezza dell'Ordine. Ho mandato dieci uomini in quei tunnel a trovarlo, e nessuno è ritornato. C'è qualcosa là sotto!","ようやく来てくれたか。 工場に入るためには鍵が必要だ。 鍵は盗んだのだが、我々の密偵が砦地下にある 地下墓所で行方不明になった。 彼を探すため10名派遣したのだが、 誰一人帰ってこなかった。 -地下墓地で何か異変が起こっているに違いない。","데우스님 감사합니다, 지원군이 왔군! 공장에 들어가려면 열쇠가 필요합니다. 그 열쇠를 가진 한 요원이 오더의 요새가 있는 고대 무덤에서 길을 잃었습니다. 지원군 10 명을 보내긴 했으나 돌아오지 못했습니다. 그곳에 무언가가 있는 것 같아요!","Bedankt deus dat je hier bent gekomen. Om de fabriek binnen te komen heb je een sleutel nodig. We hebben het gestolen maar onze agent ontbreekt in het web van de catacomben onder het bolwerk van de Orde. Ik heb tien goede mannen in die tunnels gestuurd om hem te vinden, en niemand is teruggekomen. Er is daar beneden iets!",,Graças a Deus que você está aqui. Para entrar na fábrica você precisa de uma chave. Nós a roubamos mas nosso agente desapareceu na rede de catacumbas debaixo da fortaleza da Ordem. Mandei dez homens capazes pra dentro desses túneis para encontrá-lo e ninguém retornou. Tem alguma coisa lá embaixo!,,,"Хвала господу, ты добрался сюда. Тебе нужен ключ, чтобы проникнуть на фабрику. Мы выкрали его, но наш агент пропал в сети катакомб под крепостью Ордена. Чтобы разыскать его, я послал в эти туннели десять хороших бойцов, и ни один не вернулся. Там внизу что-то есть!", -What is it? Human or... ?,TXT_RPLY0_SCRIPT23_D24256_WHATI,,,,"Co to je? Člověk, nebo...?",Was ist es? Mensch oder...?,,,¿Qué es? ¿Humano ó...?,,,"Qu'est-ce que c'est? Un humain, où...",,,それは一体?人間か...?,이게 뭐지? 사람? 아니면... ?,Wat is het? Menselijk of.... ?,,O que é? É humano ou... ?,,,Что это? Человек или...?, -"Not. Definitely not. Whatever it is, you must fight it to retrieve the key. I'll open the catacombs' entrance. When you've got it, the factory is next to the mines. Hurry, each second counts.",TXT_DLG_SCRIPT23_D25772_NOTDE,,,,"Ne. Rozhodně ne. Ať je to cokoliv, musíš se s tím utkat, abys získal ten klíč zpět. Otevřu ti vchod do katakomb. Až ho budeš mít, továrna je vedle dolů. Pospěš, každá vteřina se počítá.","Nein. Definitiv nicht. Was auch immer es ist, du musst es bekämpfen, um an den Schlüssel zu kommen. Ich werde den Eingang zu den Katakomben öffnen. Wenn du ihn hast, die Fabrik ist direkt neben den Minen. Beeil dich, jede Sekunde zählt.",,,"No. Definitivamente no. Sea lo que sea, debes luchar contra eso para recuperar la llave. Abriré la entrada a las catacumbas. Cuando la tengas, la fábrica está junto a las minas. Date prisa, cada segundo cuenta.",,,"Non, absolument pas. Je ne sais pas ce que c'est, mais il faudra s'en débarasser pour récupérer la clé. Je vais ouvrir l'entrée des catacombes. Quand vous êtes à l'intérieur, l'usine est près des ruines. Vite, chaque seconde compte.",,,"いや。人間の仕業だとはとても思えない。 +地下墓地で何か異変が起こっているに違いない。","데우스님 감사합니다, 지원군이 왔군! 공장에 들어가려면 열쇠가 필요합니다. 그 열쇠를 가진 한 요원이 오더의 요새가 있는 고대 무덤에서 길을 잃었습니다. 지원군 10 명을 보내긴 했으나 돌아오지 못했습니다. 그곳에 무언가가 있는 것 같아요!","Bedankt deus dat je hier bent gekomen. Om de fabriek binnen te komen heb je een sleutel nodig. We hebben het gestolen maar onze agent ontbreekt in het web van de catacomben onder het bolwerk van de Orde. Ik heb tien goede mannen in die tunnels gestuurd om hem te vinden, en niemand is teruggekomen. Er is daar beneden iets!","Takk Gud for at du kom hit. For å komme inn i fabrikken trenger du en nøkkel. Vi stjal den, men agenten vår er forsvunnet i katakombene under Ordenens festning. Jeg har sendt ti gode menn ned i tunnelene for å finne ham, men ingen har kommet tilbake. Det er noe der nede!","Dzięki Deusowi, że tu trafiłeś. Aby wejść do fabryki potrzebny jest klucz. Ukradliśmy go, ale nasz agent zaginął w sieci katakumb pod twierdzą Zakonu. Wysłałem dziesięciu dobrych ludzi do tych tuneli, by go znaleźli, ale żaden nie wrócił. Coś jest tam na dole!",Graças a Deus que você está aqui. Para entrar na fábrica você precisa de uma chave. Nós a roubamos mas nosso agente desapareceu na rede de catacumbas debaixo da fortaleza da Ordem. Mandei dez homens capazes pra dentro desses túneis para encontrá-lo e ninguém retornou. Tem alguma coisa lá embaixo!,,"Slavă Domnului că ești aici. Ca să intri în fabrică ai nevoie de o cheie. Am furat-o dar agentul nostru a dispărut în rețeaua catacombelor fortăreței Ordinului. Am trimis zece oameni pricepuți după el, dar niciunul nu s-a întors. Ceva se întâmplă acolo!","Хвала господу, ты добрался сюда. Тебе нужен ключ, чтобы проникнуть на фабрику. Мы выкрали его, но наш агент пропал в сети катакомб под крепостью Ордена. Чтобы разыскать его, я послал в эти туннели десять хороших бойцов, и ни один не вернулся. Там внизу что-то есть!",,"Tacka Deus för att du kom hit. För att komma in i fabriken behöver du en nyckel. Vi stal den, men vår agent saknas i katakomberna under Ordensfästet. Jag har skickat tio goda män in i tunnlarna för att hitta honom, men ingen har återvänt. Något finns där nere!",Buraya geldiğin için Deus'a şükret. Fabrikaya girmek için bir anahtara ihtiyacınız var. Onu çaldık ama ajanımız Tarikat'ın kalesinin altındaki yeraltı mezarlarında kayıp. Onu bulmaları için o tünellere on iyi adam gönderdim ama hiçbiri geri dönmedi. Aşağıda bir şey var! +What is it? Human or... ?,TXT_RPLY0_SCRIPT23_D24256_WHATI,〃,,,"Co to je? Člověk, nebo...?",Hvad er det? Menneske eller... ?,Was ist es? Mensch oder...?,,Kia ĝi estas? Ĉu homa aŭ...?,"¿Qué es?, ¿humano o...?",,Mikä se on? Ihminen vai...,"Qu'est-ce que c'est? Un humain, où...",Mi lehet? Ember vagy...?,Che cosa è? Umano o... ?,それは一体?人間か...?,이게 뭐지? 사람? 아니면... ?,Wat is het? Menselijk of.... ?,Hva er det? Menneskelig eller... ?,Co to jest? Człowiek czy... ?,O que é? É humano ou... ?,,Ce e? Uman sau... ?,Что это? Человек или...?,,Vad är det? Människor eller... ?,Ne var orada? İnsan mı yoksa... ? +"Not. Definitely not. Whatever it is, you must fight it to retrieve the key. I'll open the catacombs' entrance. When you've got it, the factory is next to the mines. Hurry, each second counts.",TXT_DLG_SCRIPT23_D25772_NOTDE,〃,,,"Ne. Rozhodně ne. Ať je to cokoliv, musíš se s tím utkat, abys získal ten klíč zpět. Otevřu ti vchod do katakomb. Až ho budeš mít, továrna je vedle dolů. Pospěš si, každá vteřina se počítá.","Nej. Helt sikkert ikke. Uanset hvad det er, skal du kæmpe mod det for at få nøglen tilbage. Jeg åbner katakombernes indgang. Når du har fået den, er fabrikken ved siden af minerne. Skynd dig, hvert sekund tæller.","Nein. Definitiv nicht. Was auch immer es ist, du musst es bekämpfen, um an den Schlüssel zu kommen. Ich werde den Eingang zu den Katakomben öffnen. Wenn du ihn hast, die Fabrik ist direkt neben den Minen. Beeil dich, jede Sekunde zählt.",,"Ne, neniel. Tio ajn, kio ĝi estas, vi devas batali kontraŭ ĝi por rekuperi la ŝlosilon. Farinte tion, la fabriko estas flanke de la minejo. Hastu, ĉiu sekundo estas gravega.","No, definitivamente no. Sea lo que sea, debes pelear contra eso para recuperar la llave; abriré la entrada a las catacumbas. Cuando la tengas, la fábrica está junto a la mina. Date prisa, que cada segundo cuenta.","No, definitivamente no. Sea lo que sea, debes pelear contra eso para recuperar la llave; voy a abrir la entrada a las catacumbas. Cuando la tengas, la fábrica está junto a la mina. Apúrate, que cada segundo cuenta.","Ei, ei varmana. Mikä ikinä se onkaan, sinun on kohdattava se noutaaksesi avaimen. Avaan katakombien sisäänkäynnin. Kun se on hallussasi, tehdas on kaivoksen vieressä. Pidä kiirettä, jokainen sekunti merkitsee.","Non, absolument pas. Je ne sais pas ce que c'est, mais il faudra s'en débarasser pour récupérer la clé. Je vais ouvrir l'entrée des catacombes. Quand vous êtes à l'intérieur, l'usine est près des ruines. Vite, chaque seconde compte.","Nem. Biztos, hogy nem. Akármi is az, meg kell majd küzdened vele a kulcsért. Kinyitom a katakomba bejáratát. Ha megszerezted, a gyár ott lesz a bánya mellett. Siess, minden másodperc számít.","No. Sicuramente no. Qualsiasi cosa sia, dovrai lottare per riavere la chiave. Adesso aprirò l'entrata per le catacombe. Quando avrai ripreso la chiave, potrai accedere alla fabbrica, che si trova accanto alle miniere. Sbrigati, ogni secondo può fare la differenza.","いや。人間の仕業だとはとても思えない。 それが何であれ君は鍵を取り戻せ。 地下墓所への入り口は開けておこう。 鍵を手に入れたら、工場は採掘所の隣にある。 -時間はあまり無いから急ぐのだ。","아냐. 사람 같은 건 절대로 아니라고. 그게 무엇이든, 당신은 어떻게든 싸워서 열쇠를 돌려받아야 합니다. 고대 무덤의 입구를 열어두겠습니다. 만약 열쇠를 얻으셨다면, 광산 옆에 있는 공장으로 향하시길 바랍니다. 시간이 얼마 남지 않았습니다!","Niet. Zeker niet. Wat het ook is, je moet ertegen vechten om de sleutel terug te krijgen. Ik zal de ingang van de catacomben openen. Als je hem hebt, staat de fabriek naast de mijnen. Schiet op, elke seconde telt.",,"Não. Definitivamente não é. Seja lá o que for, você deve enfrentá-lo para recuperar a chave. Vou abrir a entrada das catacumbas. Quando você pegar a chave, vá para a fábrica próxima às minas. Depressa, cada segundo é importante.",,,"Нет. Определённо нет. Что бы это ни было, ты должен сразиться с ним, чтобы заполучить ключ. Я открою вход в катакомбы. Когда добудешь его, направляйся на фабрику — она находится рядом со входом в шахты. Торопись! Дорога каждая секунда!", -"Something inhuman, eh?, great.",TXT_RPLY0_SCRIPT23_D25772_SOMET,,,,"Něco nelidského, co? Skvělý.",Irgendetwas unmenschliches? Na großartig.,,,"Algo inhumano, ¿eh?, genial.",,,"Quelque chose d'inhumain, hein? Parfait.",,,非人道的な何か?流石だな。,비인간적인 녀석인가요? 좋군요.,"Iets onmenselijks, eh?, geweldig.",,"Algo não-humano, é? Que ótimo.",,,Что-то иное? Просто отлично., -You're wasting time and lives! Move!,TXT_DLG_SCRIPT23_D27288_YOURE,,,,Plýtváš časem i životy! Jdi!,Du verschwendest Zeit und Leben! Beweg dich!,,,¡Estás perdiendo tiempo y vidas! ¡Muévete!,,,Vous perdez votre temps et des vies! Bougez!,,,"こうしてる間にも君は時間と人命を -無駄にしている。行け!",시간과 생명이 위협받고 있다고! 서두르세요!!,Je verspilt tijd en levens! Vooruit!,,Você está desperdiçando tempo e vidas! Ande logo!,,,Ты тратишь время и жизни! Вперёд!, -"The master doesn't like visitors. He likes all of his work to remain undisturbed. I've got to go get fresh parts from the storage room. I think he said a leg and an arm. Oh, well no time to talk anymore. I'd leave before he finds you.",TXT_DLG_SCRIPT27_D0_THEMA,,,,"Pán nemá rád návštěvy. Má rád, když ho nic neruší od práce. Musím dojít pro čerstvé části ze skladu. Myslím, že chtěl nohu a ruku. Tak, na mluvení není čas. Být tebou, odešel bych dřív, než tě najde.","Der Meister mag keine Besucher. Er hat es gern, wenn er bei der Arbeit nicht gestört wird. Ich muss gehen und neue Teile aus dem Lagerraum holen. Ich glaube er sagte ein Bein und eine Arm. Naja, keine Zeit mehr zum Reden. Du solltest gehen, bevor er dich findet.",,,"Al maestro no le gustan las visitas. Le gusta que su trabajo permanezca ininterrumpido. Tengo que ir a recoger partes frescas del almacén. Creo que dijo una pierna y un brazo. Oh, bueno, no queda tiempo para hablar. Yo me iría antes de que te encuentre.",,,"Le Maître n'aime pas les visiteurs. Il préfère que son travail se déroule dans le calme. Il faut que j'aille chercher des pièces dans la salle de stockage. Il m'a demandé une jambe et un bras, je crois. Bon, plus de temps pour parler. Je partirais si j'étais vous.",,,"マスターは訪問者ヲ嫌っている。 +時間はあまり無いから急ぐのだ。","아냐. 사람 같은 건 절대로 아니라고. 그게 무엇이든, 당신은 어떻게든 싸워서 열쇠를 돌려받아야 합니다. 고대 무덤의 입구를 열어두겠습니다. 만약 열쇠를 얻으셨다면, 광산 옆에 있는 공장으로 향하시길 바랍니다. 시간이 얼마 남지 않았습니다!","Niet. Zeker niet. Wat het ook is, je moet ertegen vechten om de sleutel terug te krijgen. Ik zal de ingang van de catacomben openen. Als je hem hebt, staat de fabriek naast de mijnen. Schiet op, elke seconde telt.","Nei. Definitivt ikke. Uansett hva det er, må du kjempe mot det for å få tak i nøkkelen. Jeg åpner inngangen til katakombene. Når du har den, er fabrikken ved siden av gruvene. Skynd deg, hvert sekund teller.","Nie. Zdecydowanie nie. Cokolwiek to jest, musisz z tym walczyć, aby odzyskać klucz. Ja otworzę wejście do katakumb. Gdy go zdobędziesz, fabryka jest obok kopalni. Spiesz się, liczy się każda sekunda.","Não. Definitivamente não é. Seja lá o que for, você deve enfrentá-lo para recuperar a chave. Vou abrir a entrada das catacumbas. Quando você pegar a chave, vá para a fábrica próxima às minas. Depressa, cada segundo é importante.",,"Nu. Cu siguranță nu. Orice ar fi, va trebui să o înfrunți pentru a recupera cheia. Voi deschide intrarea catacombelor. Când o ai, fabrica e vizavi de mine. Grăbește-te, orice secundă contează.","Нет. Определённо нет. Что бы это ни было, ты должен сразиться с ним, чтобы заполучить ключ. Я открою вход в катакомбы. Когда добудешь его, направляйся на фабрику: она находится рядом со входом в шахты. Торопись! Дорога каждая секунда!",,"Inte. Definitivt inte. Vad det än är måste du slåss mot det för att få tag på nyckeln. Jag öppnar katakombernas ingång. När du har fått den är fabriken bredvid gruvorna. Skynda dig, varje sekund räknas.","İnsan değil. Kesinlikle değil. O her neyse, anahtarı almak için onunla savaşmalısın. Yeraltı mezarlarının girişini açacağım. Anahtarı aldığında, fabrika madenlerin yanında. Acele et, her saniye önemli." +"Something inhuman, eh?, great.",TXT_RPLY0_SCRIPT23_D25772_SOMET,〃,,,"Něco nelidského, co? Skvělý.","Noget umenneskeligt, hva'?, fantastisk.",Irgendetwas unmenschliches? Na großartig.,,"Nehomaĵo, ĉu? Bonege.","Algo inhumano, ¿eh? Genial.",,"Jotain epäinhimillistä, vai? Hienoa.","Quelque chose d'inhumain, hein? Parfait.","Valami nem emberi, mi? Csodás.","Qualcosa di inumano, eh? Fantastico.",非人道的な何か?流石だな。,비인간적인 녀석인가요? 좋군요.,"Iets onmenselijks, eh?, geweldig.","Noe umenneskelig, hva? Flott!","Coś nieludzkiego, ech, świetnie.","Algo não-humano, é? Que ótimo.",,"Ceva inuman, ei? Grozav.",Что-то иное? Просто отлично.,,"Något omänskligt, va?, bra.","İnsanlık dışı bir şey, ha? Harika." +You're wasting time and lives! Move!,TXT_DLG_SCRIPT23_D27288_YOURE,〃,,,Plýtváš časem i životy! Jdi!,Du spilder tid og liv! Af sted!,Du verschwendest Zeit und Leben! Beweg dich!,,Vi perdas tempon kaj vivojn! Agu!,¡Estás perdiendo tiempo y vidas! ¡Muévete!,,Haaskaat aikaa ja henkiä! Liikkuu jo!,Vous perdez votre temps et des vies! Bougez!,Időt és életeket pazarolsz! Mozgás!,"Stai sprecando tempo, e vite. Sbrigati!","こうしてる間にも君は時間と人命を +無駄にしている。行け!",시간과 생명이 위협받고 있다고! 서두르세요!!,Je verspilt tijd en levens! Vooruit!,Du kaster bort tid og liv! Skynd dere!,Marnujesz czas i życie! Ruszać się!,Você está desperdiçando tempo e vidas! Ande logo!,,"Pierzi timp și vieți, mișcă-te!",Ты тратишь время и жизни! Вперёд!,,Du slösar bort tid och liv! Flytta på dig!,Zamanınızı ve hayatlarınızı boşa harcıyorsunuz! Çekilin! +"The master doesn't like visitors. He likes all of his work to remain undisturbed. I've got to go get fresh parts from the storage room. I think he said a leg and an arm. Oh, well no time to talk anymore. I'd leave before he finds you.",TXT_DLG_SCRIPT27_D0_THEMA,MAP27: Peasant → Northeastern room (after the lift).,,,"Pán nemá rád návštěvy. Má rád, když ho nic neruší od práce. Musím dojít pro čerstvé části ze skladu. Myslím, že chtěl nohu a ruku. Tak, na mluvení není čas. Být tebou, odešel bych dřív, než tě najde.","Mesteren kan ikke lide besøgende. Han kan lide, at alt hans arbejde forbliver uforstyrret. Jeg skal hente nye dele fra lagerrummet. Jeg tror, han sagde et ben og en arm. Nå, men vi har ikke tid til at snakke mere. Jeg ville gå, før han finder dig.","Der Meister mag keine Besucher. Er hat es gern, wenn er bei der Arbeit nicht gestört wird. Ich muss gehen und neue Teile aus dem Lagerraum holen. Ich glaube er sagte ein Bein und eine Arm. Naja, keine Zeit mehr zum Reden. Du solltest gehen, bevor er dich findet.",,"La majstro ne ŝatas vizitantojn; li ŝatas, ke ĉiu laboro estu seninterrompa. Mi devas serĉi freŝajn partojn en la deponejo: kruron kaj brakon laŭ tio, kion mi memoras. Ho, bone, ne estas tempo paroli. Se mi estus vi, mi forirus por ne esti trovita.","Al maestro no le gustan las visitas; le gusta que su trabajo permanezca ininterrumpido. Tengo que ir a buscar partes frescas al almacén: una pierna y un brazo, creo que ha dicho. Ah, bueno, no hay tiempo para hablar. Yo que tú me iría antes de que te encuentre.","Al maestro no le gustan las visitas; le gusta que su trabajo permanezca ininterrumpido. Tengo que ir a buscar partes frescas al almacén: una pierna y un brazo, creo que dijo. Ah, bueno, no hay tiempo para hablar. Yo que tú me iría antes de que te encuentre.","Mestari ei pidä vieraista. Hän haluaa kaikkien töittensä säilyä koskemattomina. Minun on mentävä noutamaan tuoreita osia varastosta. Hän taisi puhua jalasta ja käsivarresta. No, ei enempää aikaa puhua. Sinuna lähtisin, ennen kuin hän löytää sinut.","Le Maître n'aime pas les visiteurs. Il préfère que son travail se déroule dans le calme. Il faut que j'aille chercher des pièces dans la salle de stockage. Il m'a demandé une jambe et un bras, je crois. Bon, plus de temps pour parler. Je partirais si j'étais vous.","A gazda nem szereti a látogatókat. Úgy szereti, ha nem zavarja senki a munkájában. Mennem kell új darabokért a tárolóba. Azt hiszem egy lábat és egy kart említett. Hát, sajnos nincs időm beszélgetni már. A helyedben elmennék, mielőtt megtalál.","Al padrone non piacciono i visitatori. Vuole che tutto il suo lavoro rimanga indisturbato. Ho qua le parti nuove dal magazzino. Mi pare abbia detto una gamba e un braccio. Ah, non ho più tempo per parlare. Io me ne andrei prima che si accorga che tu sei qui.","マスターは訪問者ヲ嫌っている。 彼ハ自分ノ仕事ヲ邪魔されないノガ良いからダ。 私ハこれカラ倉庫に新品の部品を取りに行かねば 腕と足だったカナ。オット、モウ話ス時間ハ無イ -マスターが君を見つける前ニ出発しなけれバ。","주인님은 방문자들을 싫어해. 반대로 그는 남들의 방해 없이 혼자서 일을 하는 걸 아주 좋아하지. 저장고에서 재료를 꺼내서 가져다주는 나 같은 사람들을 제외하면. 한 쌍의 팔다리가 필요하다고 들었는데... 오, 이런. 이제 이야기할 시간도 없어졌네. 그가 널 찾기 전에 도망치는 게 좋을걸?","De meester houdt niet van bezoekers. Hij houdt ervan dat al zijn werk ongestoord blijft. Ik moet verse onderdelen uit de opslagruimte halen. Ik denk dat hij een been en een arm zei. Oh, nou geen tijd meer om te praten. Ik zou weggaan voordat hij je vindt.",,"O mestre não gosta de visitantes. Ele gosta que seu trabalho não seja perturbado. Tenho que ir buscar peças novas no depósito. Bom, não tenho mais tempo para conversa. Eu iria embora antes que ele te ache.",,,"Хранитель не любит гостей — он предпочитает, чтобы его никто не отвлекал от работы. Он послал меня на склад за свежими частями. Рукой и ногой, кажется... Ох, нет времени на разговоры. Лучше бы тебе уйти, пока он не вернулся.", -Why's that.,TXT_RPLY0_SCRIPT27_D0_WHYST,,,,A proč?,Wieo das?,,,¿Por qué?,,,Pourquoi donc?,,,何故そんなことを。,그건 왜지?,Waarom is dat.,,Por quê?,,,Почему так?, -"Because, I told you he doesn't like visitors!",TXT_RYES0_SCRIPT27_D0_BECAU,,,,"Protože, jak už jsem řekl, nemá rád návštěvy!","Ich habe dir doch gesagt, dass er keine Besucher mag!",,,"Porque, ¡Te he dicho que no le gustan las visitas!",,,"Je vous ai dit, il n'aime pas les visiteurs!",,,ナゼなら、マスターは訪問されたくナイからダ!,"왜냐하면, 그가 방문자들을 싫어한다고 내가 말했으니까!","Omdat hij niet van bezoekers houdt, zei ik toch!",,"Porque, como eu já te falei, ele não gosta de visitantes!",,,"Потому что, как я уже сказал тебе, он не любит посетителей!", -"You know, you're about the right size for one of the acolyte's uniforms.",TXT_DLG_SCRIPT27_D1516_YOUKN,,,,"Hele, ty vypadáš, že by ti dobře sedla unforma akolytů.","Weißt du, du hast genau die richtige Größe für die Uniform eines Missionars.",,,"Sabes, tienes la talla justa para uno de los uniformes de acólito.",,,"Vous savez, vous avez juste la taille qu'il faut pour un uniforme d'acolyte.",,,"知ッテるハズだ、アンタに合う -アコライトの制服一着のサイズについてサ。","어디보자... 당신의 치수, 경비 전투복 크기에 적당히 딱 맞는 것 같군!","Weet je, je bent ongeveer de juiste maat voor een van de uniformen van de acoliet.",,"Sabe, você tem a altura perfeita para um dos uniformes de acólito.",,,"Знаешь, тебе бы как раз впору пошла униформа служителя.", -"Oh no, I'm not the real Programmer, he's hiding. Continue past the guard training area, very tough. If you survive, you might be able to talk to him. Or kill him.",TXT_DLG_SCRIPT31_D0_OHNOI,,,,"Kdepak, já nejsem skutečný Programátor. Ten se schovává. Ale pokračuj skrz tréninkovou oblast, je velmi obtížná. Jestli přežiješ, mohl by sis s ním i promluvit. Nebo ho zabít.","O nein, ich bin nicht der echte Programmierer. Er versteckt sich. Ich glaube irgendwo jenseits des Trainingsbereichs für die Wächter. verdammt schwierig. Wenn du überlebst könntest du in finden. Oder töten.",,,"Oh no, no soy el verdadero Programador, él está escondido. Continúa a traves del área de entrenamiento de guardias, muy difícil. Si sobrevives, tal vez puedas hablar con él. O matarlo.","Oh no, no soy el verdadero Programador, él está escondido. Continúa a traves del área de entrenamiento de guardias, muy duro. Si sobrevives, tal vez puedas hablar con él. O matarlo.",,"Oh non, je ne suis pas le vrai Programmeur. Il se cache. Continuez après la zone d'entraînement des gardes. C'est dangereux, mais si vous y arrivez, vous devriez pouvoir lui parler.. Ou le tuer.",,,"イヤイヤ、私ハ真ノプログラマーではない、 +マスターが君を見つける前ニ出発しなけれバ。","주인님은 방문자들을 싫어해. 반대로 그는 남들의 방해 없이 혼자서 일을 하는 걸 아주 좋아하지. 저장고에서 재료를 꺼내서 가져다주는 나 같은 사람들을 제외하면. 한 쌍의 팔다리가 필요하다고 들었는데... 오, 이런. 이제 이야기할 시간도 없어졌네. 그가 널 찾기 전에 도망치는 게 좋을걸?","De meester houdt niet van bezoekers. Hij houdt ervan dat al zijn werk ongestoord blijft. Ik moet verse onderdelen uit de opslagruimte halen. Ik denk dat hij een been en een arm zei. Oh, nou geen tijd meer om te praten. Ik zou weggaan voordat hij je vindt.",Mesteren liker ikke besøkende. Han vil ha arbeidet sitt uforstyrret. Jeg må gå og hente nye deler fra lageret. Jeg tror han sa et bein og en arm. Jeg har ikke tid til å prate mer. Jeg ville dratt før han finner deg.,"Mistrz nie lubi gości. Lubi, gdy cała jego praca pozostaje niezakłócona. Muszę iść po świeże części z magazynu. Chyba powiedział noga i ręka. Nie ma czasu na gadanie. Wyszedłbym, zanim cię znajdzie.","O mestre não gosta de visitantes. Ele gosta que seu trabalho não seja perturbado. Tenho que ir buscar peças novas no depósito. Bom, não tenho mais tempo para conversa. Eu iria embora antes que ele te ache.",,"Stăpânului nu îi plac vizitatorii. Îi place ca toată muncă să fie nederanjată. Trebuie să aduc părți noi din depozit. Cred că a zis un braț și un picior. Of, nu mai e timp de vorbă. O să plec înainte să te găsească.","Хранитель не любит гостей — он предпочитает, чтобы его никто не отвлекал от работы. Он послал меня на склад за свежими частями. Рукой и ногой, кажется... Ох, нет времени на разговоры. Лучше бы тебе уйти, пока он не вернулся.",,Mästaren gillar inte besökare. Han vill att allt arbete ska förbli ostört. Jag måste hämta nya delar från lagret. Jag tror att han sa ett ben och en arm. Vi har inte tid att prata längre. Jag skulle gå innan han hittar dig.,Efendi ziyaretçileri sevmez. Tüm çalışmalarının rahatsız edilmeden kalmasını ister. Gidip depodan yeni parçalar almalıyım. Sanırım bir bacak ve bir kol dedi. Artık konuşacak vakit yok. Ben olsam o seni bulmadan giderdim. +Why's that.,TXT_RPLY0_SCRIPT27_D0_WHYST,〃,,,A proč?,Hvorfor det?,Wieo das?,,Kial mi forirus?,¿Irme por qué?,,Miksi?,Pourquoi donc?,Miért tennék olyat?,E perché mai?,何故そんなことを。,그건 왜지?,Waarom is dat.,Hvorfor det?,Dlaczego tak jest?,Por quê?,,De ce.,Почему так?,,Varför det?,Nedenmiş o? +"Because, I told you he doesn't like visitors!",TXT_RYES0_SCRIPT27_D0_BECAU,〃,,,"Protože, jak už jsem řekl, nemá rád návštěvy!","Fordi jeg sagde jo, at han ikke kan lide besøgende!","Ich habe dir doch gesagt, dass er keine Besucher mag!",,"Mi diris, ke li +ne ŝatas vizitantojn!","¡He dicho que no +le gustan las visitas!","¡Te estoy diciendo que +no le gustan las visitas!","Koska minähän sanoin, ettei hän pidä vieraista!","Je vous ai dit, il n'aime pas les visiteurs!","Most mondtam, hogy nem szereti a látogatókat!","Perché, come ti ho appena detto, non gli piacciono i visitatori!",ナゼなら、マスターは訪問されたくナイからダ!,"왜냐하면, 그가 방문자들을 싫어한다고 내가 말했으니까!","Omdat hij niet van bezoekers houdt, zei ik toch!",Jeg sa jo at han ikke liker besøk!,"Bo mówiłem ci, że nie lubi gości!","Porque, como eu já te falei, ele não gosta de visitantes!",,"Pentru că, ți-am spus, nu-i plac vizitatorii!","Потому что, как я уже сказал тебе, он не любит посетителей!",,För att jag sa ju att han inte gillar besökare!,Çünkü sana ziyaretçileri sevmediğini söylemiştim! +"You know, you're about the right size for one of the acolyte's uniforms.",TXT_DLG_SCRIPT27_D1516_YOUKN,〃,,,"Hele, ty vypadáš, že by ti dobře sedla unforma akolytů.",Du har den rette størrelse til en af acolyternes uniformer.,"Weißt du, du hast genau die richtige Größe für die Uniform eines Missionars.",,"Interese, vi havas la ĝustan talion por surhavi akolitan uniformon.",¿Sabes? Tienes la talla justa para alguno de los uniformes de acólito.,¿Sabes? Tienes el talle justo para alguno de los uniformes de acólito.,"Hei kuules, olet suurin piirtein sopivan kokoinen akoluutin univormuun.","Vous savez, vous avez juste la taille qu'il faut pour un uniforme d'acolyte.","Tudod-e, hogy ránézésre pont jó rád a ministráns egyenruha.","Sai che ti dico, sei proprio della taglia perfetta per una delle uniforme degli accoliti.","知ッテるハズだ、アンタに合う +アコライトの制服一着のサイズについてサ。","어디보자... 당신의 치수, 경비 전투복 크기에 적당히 딱 맞는 것 같군!","Weet je, je bent ongeveer de juiste maat voor een van de uniformen van de acoliet.","Vet du, du har omtrent riktig størrelse for en av akolyttenes uniformer.","Wiesz, masz odpowiedni rozmiar na jeden z mundurków akolitów.","Sabe, você tem a altura perfeita para um dos uniformes de acólito.",,"Știi, eși marimea potrivită pentru o uniformă de acolit.","Знаешь, тебе бы как раз впору пошла униформа служителя.",,"Du vet, du är ungefär rätt storlek för en av akolyternas uniformer.","Biliyor musun, yardımcı üniformalarından biri için doğru bedensin." +"Oh no, I'm not the real Programmer, he's hiding. Continue past the guard training area, very tough. If you survive, you might be able to talk to him. Or kill him.",TXT_DLG_SCRIPT31_D0_OHNOI,MAP31: Programmer.,,,"Kdepak, já nejsem skutečný Programátor. Ten se schovává. Ale pokračuj skrz tréninkovou oblast, je velmi obtížná. Jestli přežiješ, mohl by sis s ním i promluvit. Nebo ho zabít.","Åh nej, jeg er ikke den rigtige programmør. Han gemmer sig. Fortsæt forbi vagttræningsområdet, meget hårdt. Hvis du overlever, kan du måske tale med ham. Eller slå ham ihjel.","O nein, ich bin nicht der echte Programmierer. Er versteckt sich. Ich glaube irgendwo jenseits des Trainingsbereichs für die Wächter. verdammt schwierig. Wenn du überlebst könntest du in finden. Oder töten.",,"Ha ha! Ne, mi ne estas la Programisto; la reala estas kaŝita. Daŭrigu trans la trejnejo por gardistoj; tre malfacila. Se vi supervivos, vi eble povos paroli kun li... aŭ mortigi lin.","¡Je, je! No, no soy el Programador; el verdadero está escondido. Continúa a traves del área de entrenamiento de guardias; muy difícil. Si sobrevives, tal vez puedas hablar con él... o matarlo.",,"Ehei, en ole oikea Ohjelmoitsija; hän piilottelee. Jatka vartijoiden koulutusalueen läpi; tulee olemaan haastavaa. Jos selviydyt, saatat ehkä pystyä puhumaan hänen kanssaan; tai tappaa hänet.","Oh non, je ne suis pas le vrai Programmeur. Il se cache. Continuez après la zone d'entraînement des gardes. C'est dangereux, mais si vous y arrivez, vous devriez pouvoir lui parler.. Ou le tuer.","Oh dehogy, nem Én vagyok az igazi Programozó, Ő most elbújt. Ha túléled az őrképző részleget, akkor rögtön utána megtalálod őt. Vagy éppen meg is ölheted.","Oh no, io non sono il vero Programmatore, lui si sta nascondendo. Procedi oltre l'area di addestramento delle guardie, molto tosta. Se sopravvivi, potresti riuscire a parlargli. O magari ad ucciderlo.","イヤイヤ、私ハ真ノプログラマーではない、 彼ハ隠れている。非常ニタフなガードノ 訓練場にダ、もし生き残れたら会えるだろう 或いハ彼を殺せるだろう。","하하. 아, 난 프로그래머님이 아니야. 그는 지금 숨고 있어. 경비 훈련소를 한번 체험해봐. 어렵겠지만, 한번 통과하면 너에게 말을 걸어줄지도 몰라. 아니면 널 죽이던가! - \cy내가 사람들 죽이는 걸 지겨워할 것 같지만, 이 일이 모두 끝나면 아마 그리워할 거야.","Oh nee, ik ben niet de echte programmeur, hij verstopt zich. Ga verder langs de bewakingsopleiding, heel moeilijk. Als je het overleeft, kun je misschien met hem praten. Of dood hem.",,"Ah não, eu não sou o verdadeiro Programador. Ele está escondido. Continue pela área de treinamento de guardas. É bem difícil. Se você sobreviver, talvez você possa falar com ele. Ou matar ele.",,,"О, нет. Я не настоящий Программист. Он прячется. На твоём пути лежит зона тренировки стражи. Пройти её очень непросто. Если уцелеешь, то сможешь поговорить с ним... или убить его.", -Who are you?,TXT_RPLY0_SCRIPT31_D0_WHOAR,,,,Kdo jsi?,Wer bist du?,,,¿Quién eres?,,,Qui êtes vous?,,,お前は誰だ?,당신은 누구죠?,Wie ben jij?,,Quem é você?,,,Кто ты?, -You'll never find anything if you hang around here.,TXT_DLG_SCRIPT31_D1516_YOULL,,,,"Nic nenajdeš, když se tu budeš potloukat.","Du wirst niemals etwas finden, wenn du hier herumhängst.",,,Nunca encontrarás nada si permaneces aquí.,,,Vous ne découvrerez rien si vous traînez ici.,,,アンタがここをふらついても何も無いよ。,여기에 계속 머무르고 있으면 다 알지도 못할걸.,Je zult nooit iets vinden als je hier rondhangt.,,Você nunca vai descobrir nada se ficar por aqui.,,,"Ты ничего не добьёшься, если будешь ошиваться тут.", -Piss off peasant!,TXT_DLG_SCRIPT32_D0_PISSO,,,,"Odprejskni, poddaný!","Verpiss dich, du Bauer!",,,"¡Esfúmate, campesino!",,,"Dégage, paysan!",,"Sparisci, contadino!",イラつかせるな、田吾作が!,"저리 꺼져라, 시민!",Boer boer kwaad maken!,,"Suma daqui, plebeu!",,,"Вали отсюда, рабочий!", -Die little man!,TXT_DLG_SCRIPT32_D1516_DIELI,"Appears in MAP32 and is supposed to be spoken by the AcolyteRust actor (named “Interrogator”). However, no such actor is spawned in the map, rendering this line unused.",,,"Zemři, mužíčku!","Stirb, kleiner Mann!",,,"¡Muere, enano!",,,"Meurs, petite frappe!",,"Muori, piccolo uomo!",,죽어라. 나약한 것!,Sterf kleine man!,,"Morra, insignificante!",,,"Сдохни, человечишка!", -Finally I can get out of this cell.,TXT_DLG_SCRIPT32_D3032_FINAL,,,,Konečně se můžu z téhle cely dostat.,Endlich kann ich aus dieser Zelle raus.,,,Por fin puedo salir de esta celda.,,,"Enfin, je peux sortir de cette cellule.",,,遂に、この独房から抜け出せる。,드디어 이 감옥에서 벗어나는구나...,Eindelijk kan ik uit deze cel komen.,,Finalmente eu posso sair desta cela.,,,Наконец-то я могу сбежать из этой камеры!, -Why are you in here?,TXT_RPLY0_SCRIPT32_D3032_WHYAR,,,,Proč tu jsi?,Warum bist du da drin?,,,¿Por que estás aquí?,,,Pourquoi êtes vous ici?,,,何でここにいる?,너가 왜 여기있지?,Waarom ben je hier binnen?,,Por que você está aqui?,,,Как ты здесь оказался?, -I was framed.,TXT_RYES0_SCRIPT32_D3032_IWASF,,,,Podvedli mě.,Ich wurde hereingelegt.,,,Fui incriminado.,,,J'ai été victime d'un coup monté.,,,私は無実だ。,저는 누명을 썼어요.,Ik werd erin geluisd.,,Eu caí numa cilada.,,,Меня подставили., -Harris said that I was plotting to kill the Governor. I would never harm a soul.,TXT_DLG_SCRIPT32_D4548_HARRI,,,,"Harris řekl, že jsem prý měl v plánu zavraždit guvernéra. Ani mouše bych neublížil.","Harris hat erzählt, das ich plante den Gouverneur zu ermorden. Ich könnte keiner Menschenseele etwas antun.",,,Harris dijo que estaba planeando matar al Gobernador. Yo nunca le haría daño a nadie.,,,Harris a dit que j'avais un plan pour tuer le gouverneur. Je ne ferais pas de mal à qui que ce soit.,,,"ハリスに知事の暗殺を企てていると言われた。 -そんなこと心にも思ったことは無いのに。","해리스가 말하길, 내가 총독 암살을 꾀했데요. 난 파리 한마리도 못 죽이는데...",Harris zei dat ik van plan was om de gouverneur te vermoorden. Ik zou nooit een ziel kwaad doen.,,O Harris disse que eu estava planejando matar o Governador. Eu nunca faria mal a qualquer pessoa.,,,"Харрис сказал, что я замышлял убийство губернатора. А я и мухи не обижу!", -Be careful out there.,TXT_DLG_SCRIPT33_D0_BECAR,,,,Buď tam venku opatrný.,Sei vorsichtig dort draußen.,,,Ten cuidado ahí fuera.,,,Faites attention à vous.,,,外は気をつけろ。,조심해.,Wees voorzichtig daarbuiten.,,Tome cuidado por aí.,,,Будь поосторожнее., -"Say friend, I'll help you, if you help me. Give me 5 gold and I'll tell you what I know.",TXT_DLG_SCRIPT33_D1516_SAYFR,,,,"Poslyš, příteli, pomůžu ti, když ti pomůžeš mě. Dej mi pět zlatých a já ti řeknu, co vím.","Sag, mein Freund. Ich helfe dir, wenn du mir hilst. Gib mir 5 Gold und ich sage dir was ich weiß.",,,"Dime, amigo, te ayudo, si tú me ayudas. Dame 5 de oro y te digo todo lo que sé.",,,"Dites, l'ami. Je vous aide si vous m'aidez. Donnez moi 5 pièces et je vous dirais ce que je sais.",,,"助けてくれるなら援助する。 -5ゴールドで知っている情報を全て教えよう","친구, 나는 너를 도와주고 싶어. 그러기 전에 나에게 5 골드를 줘. 그럼 내가 아는 걸 알려줄게.","Zeg vriend, ik zal je helpen, als je me helpt. Geef me 5 goud en ik zal je vertellen wat ik weet.",,"Que tal, eu te ajudo se você me ajudar. Me dê 5 moedas de ouro e eu te digo o que eu sei.",,,"Дружище, я помогу тебе, если ты поможешь мне. Пять золотых, и я расскажу тебе всё, что знаю!", -Here's the gold.,TXT_RPLY0_SCRIPT33_D1516_HERES,,,,Tady máš to zlato.,Hier ist das Gold.,,,Aquí tienes el oro.,,,Voilà votre argent.,,,金はこれだ。,여기 골드입니다.,Hier is het goud.,,Tome estas moedas.,,,Вот монеты., -"If you punch someone, you won't set off the alarms.",TXT_RYES0_SCRIPT33_D1516_IFYOU,,,,"Když někoho praštíš, nespustíš alarmy.","Wenn du jemanden schlägst, wirst du keinen Alarm auslösen.",,,"Si golpeas a alguien, no activarás las alarmas.",,,"Si vous plantez quelqu'un avec votre dague de poing, vous n'activez pas les alarmes.",,,パンチならアラームを鳴らせることはない。,"만약 네가 누군가를 주먹으로 때린다면, 알람은 울리지 않을 거야.","Als je iemand slaat, zal je het alarm niet afgaan.",,"Se você der um soco em alguém, você não ativará os alarmes.",,,"Убивай холодным оружием, тогда ты не поднимешь тревогу.", -I won't tell you anything for free!,TXT_RNO0_SCRIPT33_D1516_IWONT,,,,Zadarmo ti nic říkat nebudu!,Umsonst werde ich dir nichts sagen.,,,¡No te voy a decir nada gratis!,,,Je ne vous dirai rien gratuitement!,,,タダでは教えられないな!,무료로는 말 못 해!,Ik zal je niets gratis vertellen!,,Não te direi nada de graça!,,,Бесплатно я не скажу ничего!, -I've already told you what I know.,TXT_DLG_SCRIPT33_D3032_IVEAL,,,,"Už jsem ti řekl, co vím.","Ich habe dir alles gesagt, was ich weiß.",,,Ya te he dicho lo que sé.,,,Je vous ai dit tout ce que je sais.,,,俺が知っていることはこれで全部だ。,난 이미 내가 아는 걸 말해 줬어!,Ik heb je al verteld wat ik weet.,,Já te disse o que eu sei.,,,"Я уже сказал тебе всё, что знал.", -Hello friend. What can I get for you?,TXT_DLG_SCRIPT33_D4548_HELLO,,,,"Zdravím, příteli, co ti mohu nabídnout?","Hallo, Freund, was kann ich dir geben?",,,"Hola amigo, ¿Qué puedo ofrecerte?",,,"Bonjour, l'ami, que puis-je pour vous?",,,どうも同士よ。何か必要か?,"안녕하십니까, 친구여. 구매하고 싶은 게 있습니까?",Hallo vriend. Wat kan ik voor je halen?,,"Olá amigo, como posso te ajudar?",,,Здравствуй. Что-нибудь интересует?, -Electric bolts,TXT_RPLY0_SCRIPT33_D4548_ELECT,,,,Elektrické šípy,Elektrische Pfeile,,,Saetas eléctricas.,,,Carreaux électriques.,,,エレクトリック ボルト,전격 볼트,Elektrische bouten,,Setas elétricas,,,Электрические болты, -One quarrel it is.,TXT_RYES0_SCRIPT33_D4548_ONEQU,,,,Jeden toulec.,Hier hast du sie.,,,Marchando unas flechas.,,,Un carquois pour vous.,,,クォーレル一本だ。,잔소리 없이 주겠습니다.,Eén ruzie is het.,,Está na mão.,,,Один колчан., -You're broke!,TXT_RNO0_SCRIPT33_D4548_YOURE,,,,Jseš na mizině!,Du bist pleite!,,,¡Estás sin blanca!,¡Estás quebrado!,,Vous êtes à sec!,,,スッカラカンじゃないか!,돈이 한 푼도 없는 것 같은데.,Je bent blut!,,Você está sem grana!,,,"Друг, да ты на мели!", -Clip of bullets,TXT_RPLY1_SCRIPT33_D4548_10ROU,,,,Zásobník nábojů,10-Kugeln-Magazin,,,Cargador de balas,,,Chargeur de 10 cartouches.,,,銃弾倉,돌격소총 탄창,Klem van kogels,,Carregador de balas,,,Обойма патронов, -Here's your ammo,TXT_RYES1_SCRIPT33_D4548_HERES,,,,Tady je tvá munice.,Hier ist deine Munition.,,,Aquí tienes tu munición.,,,Voilà vos balles.,,,これでアンタのブツだ。,여기 탄약입니다.,Hier is je munitie....,,Aqui está a sua munição.,,,Вот твои патроны., -"Sorry, no money, no bullets.",TXT_RNO1_SCRIPT33_D4548_SORRY,,,,"Promiň, žádné peníze, žádné náboje.","Tut mir leid. Kein Geld, keine Munition.",,,"Lo siento, sin dinero, no hay balas.",,,"Désolé, pas d'argent, pas de munitions.",,,悪いが、金が無ければブツも無しだ。,돈 없으면 거래 못 합니다.,"Sorry, geen geld, geen kogels.",,"Desculpe. Sem grana, sem balas.",,,"Извини, нет денег — нет патронов!", -Ammo box,TXT_RPLY2_SCRIPT33_D4548_50ROU,,,,Krabici nábojů,50-Kugeln-Schachtel,,,Caja de municiones,,,Boîte de 50 balles.,,,銃弾倉箱,돌격소총 탄약 박스,Munitiedoos,,Caixa de munição,,,Коробка патронов, -Here you go,TXT_RYES2_SCRIPT33_D4548_HEREY,,,,Tu máš.,Bitteschön.,,,Aquí tienes,,,Voilà pour vous.,,,どうぞ。,거래 감사드립니다.,Alsjeblieft,,Aqui está,,,Держи., -You don't have enough gold!,TXT_RNO2_SCRIPT33_D4548_YOUDO,,,,Nemáš dost zlata!,Du hast nicht genug Gold.,,,¡No tienes suficiente oro!,,,Vous n'avez pas assez d'argent.,,,十分な額じゃない,골드가 충분치 않군요!,Je hebt niet genoeg goud!,,Você não tem ouro suficiente!,,,У тебя недостаточно золота!, -Ammo satchel,TXT_RPLY3_SCRIPT33_D4548_AMMOS,,,,Brašnu na munici,Munitionstasche.,,,Mochila de municiones,,,Sacoche de munitions.,,,弾薬鞄,탄약 배낭,Munitie tasje,,Mochila de munição,,,Ранец для боеприпасов, -"Thank you, anything else?",TXT_RYES3_SCRIPT33_D4548_THANK,,,,Děkuji. Něco dalšího?,"Danke, sonst noch was?",,,"Gracias, ¿algo más?",,,"Merci, quelque chose d'autre?",,,ありがとう。 他に何か?,좋습니다! 더 필요한 거라도?,"Bedankt, nog iets anders?",,Obrigado. Mais alguma coisa?,,,Благодарю. Что-нибудь ещё?, -"You can't afford that, good day.",TXT_RNO3_SCRIPT33_D4548_YOUCA,,,,"To si nemůžeš dovolit, přeji hezký den.",Das kannst du dir nicht leisten. Guten Tag.,,,"No puedes permitirte eso, buen día.","No puedes pagar eso, buen día.",,Vous ne pouvez pas l'acheter. Au revoir.,,,それを買える余裕は無い、また今度。,제공할 수 없습니다. 유감이군요.,"Dat kan je je niet betalen, goede dag.",,Você não pode comprar isto. Tenha um bom dia.,,,У тебя не хватает денег. Всего доброго!, -Welcome. What may I show you?,TXT_DLG_SCRIPT33_D6064_WELCO,,,,Vítej. Co bych ti mohl nabídnout?,Willkommen. Was darf ich dir zeigen?,,,Bienvenido. ¿Qué puedo mostrarte?,,,"Bienvenue, comment puis-je vous servir?",,,ようこそ、何を見ていきますか?,어서 오세요! 무엇이 필요한지?,Welkom. Wat kan ik je laten zien?,,Seja bem-vindo. O que posso lhe mostrar?,,,Здравствуй. Что-нибудь интересует?, -Environmental suit,TXT_RPLY0_SCRIPT33_D6064_ENVIR,,,,Ochranný oblek,Schutzanzug.,,,Traje ambiental,,,Combinaison Hazmat.,,,耐環境スーツ,환경 방호복,Beschermend Pak,,Traje de proteção,,,Защитный костюм, -Here you are.,TXT_RYES0_SCRIPT33_D6064_HEREY,,,,"Tak, tady to je.",Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,はい、これをどうぞ。,받으세요!,Hier ben je dan.,,Aqui está.,,,"Хорошо, бери.", -You don't have enough money for that.,TXT_RNO0_SCRIPT33_D6064_YOUDO,,,,Na to nemáš dost peněz.,Dafür hast du nicht genug Geld.,,,No tienes suficiente dinero para eso.,,,Vous n'avez pas assez d'argent.,,,すみませんが、貴方は十分なお金を持っていません。,돈이 충분치 않아요.,Daar heb je niet genoeg geld voor.,,Você não tem dinheiro o suficiente para isto.,,,"Извини, но у тебя не хватает денег.", -Leather armor.,TXT_RPLY1_SCRIPT33_D6064_LEATH,,,Leather armour,Kožené brnění,Lederrüstung,,,Armadura de cuero.,,,Armure de cuir.,,,レザーアーマー,가죽 갑옷,Leren harnas,,Armadura de couro.,,,Кожаная броня, -Here you are.,TXT_RYES1_SCRIPT33_D6064_HEREY,,,,Tady máš.,Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,これをどうぞ。,딱 맞는 치수의 갑옷이죠.,Hier ben je dan.,,Aqui está.,,,Держи., -Perhaps some other time?,TXT_RNO1_SCRIPT33_D6064_PERHA,,,,Možná někdy jindy?,Vielleicht ein anderes Mal?,,,¿Tal vez en otro momento?,,,Peut être une autre fois?,,,また別の機会に?,아마 나중에 사야겠는데요?,Misschien een andere keer?,,Talvez outra hora?,,,"Может, в следующий раз?", -Metal armor,TXT_RPLY2_SCRIPT33_D6064_METAL,,,Metal armour,Kovové brnění,Metallrüstung,,,Armadura de metal,,,Armure de métal.,,,メタルアーマー,강철 갑옷,Metalen harnas,,Armadura de metal,,,Металлическая броня, -Wear it in good health.,TXT_RYES2_SCRIPT33_D6064_WEARI,,,,Nes ho ve zdraví.,Trage sie und bleib gesund.,,,Llévala en buena salud.,,,Portez-la en bonne santé.,,,着ると安心しますよ。,건강하게 착용하십시오.,Draag het in goede gezondheid.,,Vista com orgulho.,,,Носи на здоровье., -Come back when you can afford it.,TXT_RNO2_SCRIPT33_D6064_COMEB,,,,"Vrať se, až si to budeš moct dovolit.","Komme wieder, wenn du dir sie leisten kannst.",,,Vuelve cuando puedas permitírtela.,Vuelve cuando puedas pagarlo.,,Revenez quand vous pouvez l'acheter.,,,余裕がある時にまた。,돈이 좀 있을때 다시 찾아와주세요.,Kom terug wanneer je het je kunt veroorloven.,,Volte quando puder comprar.,,,"Вернёшься, когда поднакопишь на то, что хочешь!", -How may I assist you?,TXT_DLG_SCRIPT33_D7580_HOWMA,,,,Jak ti mohu pomoci?,Womit kann ich dienen?,,,¿Cómo puedo ayudarte?,,,Comment puis-je vous aider aujourd'hui?,,,何かお困りですか?,반갑습니다. 어떻게 도와드릴까요?,Hoe kan ik u helpen?,,Como posso ajudá-lo?,,,Чем могу помочь?, -Med patch,TXT_RPLY0_SCRIPT33_D7580_MEDPA,,,,Obvazy,Medizinische Bandage,,,Parche médico.,,,Pansement.,,,医薬パッチ,의료 붕대,Med-patch,,Compressa médica,,,Бинтами, -Here's your patch kit.,TXT_RYES0_SCRIPT33_D7580_HERES,,,,Tady je tvůj obvaz.,Hier ist deine Bandage.,,,Aquí tienes tu kit de parches.,,,Voilà votre pansement.,,,これをどうぞ。,저렴한 가격의 의료 붕대입니다.,Hier is je patch.,,Aqui está a sua compressa,,,Вот они., -You need 10 gold for that.,TXT_RNO0_SCRIPT33_D7580_YOUNE,,,,Na ty potřebuješ deset zlatých.,Dafür brauchst du 10 Gold.,,,Necesitas 10 de oro para eso.,,,Il vous faut 10 pièces pour ça.,,,10 ゴールド必要です。,10 골드입니다. 설마 이 만한 양의 돈이 없으신가요?,Daar heb je 10 goud voor nodig.,,Você precisa de 10 moedas para isto.,,,Тебе не хватает 10 золотых., -Field surgery kit,TXT_RPLY1_SCRIPT33_D7580_FIELD,,,,Lékárničku,Erste-Hilfe-Kasten,,,Kit quirúrgico,,,Kit de chirurgie.,,,手術キット,수술 키트,Veld chirurgie kit,,Kit de cirurgia,,,Аптечкой, -Thank you.,TXT_RYES1_SCRIPT33_D7580_THANK,,,,Děkuji.,Danke.,,,Gracias.,,,Merci.,,,ありがとうございます。,말 없이 주겠습니다. 거래 고마워요!,Bedankt.,,Obrigado.,,,Спасибо., -"I wish I could give them away, but they cost 25 gold.",TXT_RNO1_SCRIPT33_D7580_IWISH,,,,"Přál bych si je dávat zadarmo, ale stojí 25 zlatých.","Ich wünschte, ich könnte sie verschenken, aber sie kosten 25 Gold.",,,"Ojalá pudiera regalarlos, pero cuestan 25 de oro.",,,"J'adorerais les donner gratuitement, mais non, ça coûte 25 pièces.",,,譲渡したい所ですが、25 ゴールド必要です。,25 골드만 있으면 잔소리 말고 주겠습니다.,"Ik wou dat ik ze kon weggeven, maar ze kosten 25 goud.",,"Bem que eu queria doar de graça, mas custa 25 moedas de ouro.",,,"С радостью бы отдал, но они по 25 золотых.", -Healing,TXT_RPLY2_SCRIPT33_D7580_HEALI,,,,Ošetření,Heilung,,,Curación,,,Des soins.,,,治療だ,치료 중.,Genezing,,Cura,,,Медкомплектом, -There you go. Take care now.,TXT_RYES2_SCRIPT33_D7580_THERE,,,,A je to. Buď opatrný.,Bitteschön. Aber sei vorsichtiger.,,,Aquí tienes. Cúidate.,,,"Voilà pour vous, portez-vous-bien.",,,こちらになります、お気をつけて。,치료가 끝났어. 몸 조심하라고.,Daar ga je. Pas goed op jezelf.,,Pronto. Se cuida.,,,Пожалуйста. Береги себя!, -"Well, maybe you can afford some med patches?",TXT_RNO2_SCRIPT33_D7580_WELLM,,,,Možná si můžeš dovolit nějaké obvazy?,"Naja, vielleicht kannst du dir ein paar Bandagen leisten?",,,"Bueno, ¿tal vez puedas permitirte algunos parches médicos?","Bueno, ¿tal vez puedas comprar algunos parches médicos?",,"Eh bien, peut être pouvez-vous vous acheter quelques pansements?",,,ところで、医薬パッチを買う余裕はありますか?,의료 붕대는 어떠신가요? 이 건 저렴한데.,"Nou ja, misschien kunt u zich wat medische patches veroorloven?",,"Bem, talvez você possa comprar algumas compressas?",,,"Тогда, может быть, купишь несколько бинтов?", -"Hello friend, I haven't seen you around here before. All I can say is that I'd be careful if I were you, there's a lot going on and it's better if you don't get in the way.",TXT_DLG_SCRIPT33_D9096_HELLO,,,,"Ahoj, příteli, ještě jsem tě tady neviděl. Jediné, co můžu říct, je: Být tebou, byl bych opatrný. Děje se toho hodně a je lepší nepříplést se tomu do cesty.","Hallo, Freund, ich habe dich hier noch nicht gesehen. Ich kann nur sagen, sei vorsichtig und wenn ich du wäre, würde ich es vorziehen, niemandem im Weg zu stehen.",,,"Hola amigo, no te he visto antes por aquí. Todo lo que puedo decir es que tendría cuidado si fuera tú, están pasando muchas cosas y es mejor que no te entrometas.",,,"Bienvenue, l'ami. Je ne vous ai pas vu ici avant. Tout ce que peux vous dire, c'est de faire attention à vous. Il se passe beaucoup de choses ici, et je pense que vous ne voulez pas vous en mêler.",,,"どうも余所者、この辺では見かけない顔だな。 + \cy내가 사람들 죽이는 걸 지겨워할 것 같지만, 이 일이 모두 끝나면 아마 그리워할 거야.","Oh nee, ik ben niet de echte programmeur, hij verstopt zich. Ga verder langs de bewakingsopleiding, heel moeilijk. Als je het overleeft, kun je misschien met hem praten. Of dood hem.","Å nei, jeg er ikke den ekte programmereren. Han gjemmer seg. Fortsett forbi vaktenes treningsområde, veldig tøft. Hvis du overlever, kan du kanskje snakke med ham. Eller drepe ham.","O nie, nie jestem prawdziwym Programistą, on się ukrywa. Kontynuuj obok obszaru szkolenia strażników, bardzo trudnego. Jeśli przeżyjesz, może uda ci się z nim porozmawiać. Albo go zabić.","Ah não, eu não sou o verdadeiro Programador. Ele está escondido. Continue pela área de treinamento de guardas. É bem difícil. Se você sobreviver, talvez você possa falar com ele. Ou matar ele.",,"Oh nu, nu sunt adevăratul Programator. Continuă până dincolo de câmpul de antrenament. Dacă supraviețuiești, vei putea vorbi cu el. Sau să îl omori.","О, нет. Я не настоящий Программист. Он прячется. На твоём пути лежит зона тренировки стражи. Пройти её очень непросто. Если уцелеешь, то сможешь поговорить с ним... или убить его.",,"Åh nej, jag är inte den riktiga programmeraren, han gömmer sig. Fortsätt förbi vakternas träningsområde, mycket tufft. Om du överlever kanske du kan prata med honom. Eller döda honom.","Oh hayır, ben gerçek Programcı değilim, o saklanıyor. Muhafız eğitim alanını geçmeye devam et, çok zorlu. Eğer hayatta kalırsan, onunla konuşabilirsin. Ya da onu öldürebilirsin." +Who are you?,TXT_RPLY0_SCRIPT31_D0_WHOAR,〃,,,Kdo jsi?,Hvem er du?,Wer bist du?,,Kiu vi estas?,¿Quién eres?,,Kuka sinä olet?,Qui êtes vous?,Ki vagy te?,E tu chi sei?,お前は誰だ?,당신은 누구죠?,Wie ben jij?,Hvem er du?,Kim jesteś?,Quem é você?,,Cine ești?,Кто ты?,,Vem är du?,Kimsin sen? +You'll never find anything if you hang around here.,TXT_DLG_SCRIPT31_D1516_YOULL,〃,,,"Nic nenajdeš, když se tu budeš potloukat.","Du finder aldrig noget, hvis du bliver hængende her.","Du wirst niemals etwas finden, wenn du hier herumhängst.",,Vi trovos nenion se vi restas ĉi tie.,No encontrarás nada si sigues aquí.,No vas a encontrar nada si sigues aquí.,"Et saa ikinä mitään selville, jos jäät tänne oleilemaan.",Vous ne découvrerez rien si vous traînez ici.,"Nem fogsz semmit se találni, ha csak itt bóklászol.",Non troverai nulla se rimani fermo qui.,アンタがここをふらついても何も無いよ。,여기에 계속 머무르고 있으면 다 알지도 못할걸.,Je zult nooit iets vinden als je hier rondhangt.,Du finner aldri noe hvis du blir her.,"Nic nie znajdziesz, jeśli będziesz się tu kręcił.",Você nunca vai descobrir nada se ficar por aqui.,,N-o să aflii nimic dacă pierzi timpul aici.,"Ты ничего не добьёшься, если будешь ошиваться тут.",,Du kommer aldrig att hitta något om du hänger kvar här.,Buralarda takılırsan asla bir şey bulamazsın. +Piss off peasant!,TXT_DLG_SCRIPT32_D0_PISSO,MAP32: Red acolyte.,,,"Odprejskni, poddaný!",Pis af bonde!,"Verpiss dich, du Bauer!",,"Foriru, kampulo!","¡Esfúmate, campesino!",,"Suksi suohon, maallikko!","Dégage, paysan!",Takarodj a színem elől paraszt!,"Fuori dai piedi, cittadino!",イラつかせるな、田吾作が!,"저리 꺼져라, 시민!",Boer boer kwaad maken!,"Dra til helvete, bonde!",Odwal się chłopie!,"Suma daqui, plebeu!",,"Valea, sărmanule!","Вали отсюда, рабочий!",,Dra åt helvete bonde!,Defol köylü! +Die little man!,TXT_DLG_SCRIPT32_D1516_DIELI,"Appears in MAP32 and is supposed to be spoken by the AcolyteRust actor (named “Interrogator”). However, no such actor is spawned in the map, rendering this line unused.",,,"Zemři, mužíčku!","Dø, lille mand!","Stirb, kleiner Mann!",,"Mortu, nano!","¡Muere, enano!",,"Kuole, pikku mies!","Meurs, petite frappe!","Halál rád, te jöttment!","Muori, piccolo uomo!",,죽어라. 나약한 것!,Sterf kleine man!,"Dø, lille mann!",Giń mały człowieku!,"Morra, insignificante!",,"Mori, mititelule!","Сдохни, человечишка!",,"Dö, lilla man!",Geber küçük adam! +Finally I can get out of this cell.,TXT_DLG_SCRIPT32_D3032_FINAL,MAP32: Cell.,,,Konečně se můžu z téhle cely dostat.,Endelig kan jeg komme ud af denne celle.,Endlich kann ich aus dieser Zelle raus.,,Mi finfine estas libera.,Por fin puedo salir de esta celda.,,"Vihdoinkin, voin päästä pois tästä sellistä.","Enfin, je peux sortir de cette cellule.",Végre kiszabadulhatok ebből a cellából.,Finalmente posso uscire da questa cella.,遂に、この独房から抜け出せる。,드디어 이 감옥에서 벗어나는구나...,Eindelijk kan ik uit deze cel komen.,Endelig kan jeg komme ut av denne cella.,Wreszcie mogę się wydostać z tej celi.,Finalmente eu posso sair desta cela.,,În sfârșit pot părăsi celula asta.,Наконец-то я могу сбежать из этой камеры!,,Äntligen kan jag komma ut ur den här cellen.,Sonunda bu hücreden çıkabilirim. +Why are you in here?,TXT_RPLY0_SCRIPT32_D3032_WHYAR,〃,,,Proč tu jsi?,Hvorfor er du herinde?,Warum bist du da drin?,,Kial vi estas ĉi tie?,¿Y por que estás aquí?,,Miksi olet täällä?,Pourquoi êtes vous ici?,Miért vagy itt bent?,Perché ti trovi qui?,何でここにいる?,너가 왜 여기있지?,Waarom ben je hier binnen?,Hvorfor er du her?,Dlaczego tu jesteś?,Por que você está aqui?,,De ce ești închis?,Как ты здесь оказался?,,Varför är du här inne?,Sen neden buradasın? +I was framed.,TXT_RYES0_SCRIPT32_D3032_IWASF,〃,,,Podvedli mě.,Jeg er blevet snydt.,Ich wurde hereingelegt.,,Mi estis akuzita.,Me incriminaron.,,Minut lavastettiin.,J'ai été victime d'un coup monté.,Meggyanúsítottak.,Mi hanno incastrato.,私は無実だ。,저는 누명을 썼어요.,Ik werd erin geluisd.,Jeg ble lurt i en felle.,Zostałem wrobiony.,Eu caí numa cilada.,,Am fost înscenat.,Меня подставили.,,Jag blev lurad.,Bana komplo kuruldu. +Harris said that I was plotting to kill the Governor. I would never harm a soul.,TXT_DLG_SCRIPT32_D4548_HARRI,〃,,,"Harris řekl, že jsem prý měl v plánu zavraždit guvernéra. Ani mouše bych neublížil.","Harris sagde, at jeg planlagde at dræbe guvernøren. Jeg ville aldrig skade nogen.","Harris hat erzählt, das ich plante den Gouverneur zu ermorden. Ich könnte keiner Menschenseele etwas antun.",,"Harriso diris, ke mi planas mortigi la registon. Mi neniam vundus iun.","Harris dijo que yo estaba planeando matar al gobernador, y yo no podría hacerle nada a nadie.",,Harris väitti minun juonineen kuvernöörin salamurhaa. En ikinä satuttaisi ketään.,Harris a dit que j'avais un plan pour tuer le gouverneur. Je ne ferais pas de mal à qui que ce soit.,"Harris azt nyilatkozta, hogy a kormányzó életére akarok törni. Egy légynek sem ártanék.",Harris ha detto che progettavo di uccidere il governatore. Ma io non farei mai del male a nessuno.,"ハリスに知事の暗殺を企てていると言われた。 +そんなこと心にも思ったことは無いのに。","해리스가 말하길, 제가 총독 암살을 꾀했데요. 난 파리 한마리도 못 죽이는데...",Harris zei dat ik van plan was om de gouverneur te vermoorden. Ik zou nooit een ziel kwaad doen.,Harris sa at jeg planla å drepe guvernøren. Jeg ville aldri skade noen.,"Harris powiedział, że spiskowałem, by zabić gubernatora. Nigdy nie skrzywdziłbym żadnej duszy.",O Harris disse que eu estava planejando matar o Governador. Eu nunca faria mal a qualquer pessoa.,,Harris a spus că plănuiam să-l omor pe Guvernator. N-aș răni un suflet niciodată.,"Харрис сказал, что я замышлял убийство губернатора. А я и мухи не обижу!",,Harris sa att jag planerade att döda guvernören. Jag skulle aldrig skada en själ.,"Harris, Vali'yi öldürmeyi planladığımı söyledi. Kimseye zarar vermem." +Be careful out there.,TXT_DLG_SCRIPT33_D0_BECAR,,,,Buď tam venku opatrný.,Vær forsigtig derude.,Sei vorsichtig dort draußen.,,Agu singarde tie ekstere.,Ten cuidado ahí fuera.,Ten cuidado ahí afuera.,Pidä itsestäsi huoli.,Faites attention à vous.,Légy óvatos odakint.,Stai attento là fuori.,外は気をつけろ。,조심해.,Wees voorzichtig daarbuiten.,Vær forsiktig der ute.,Bądź ostrożny.,Tome cuidado por aí.,,Ai grijă pe-acolo.,Будь поосторожнее.,,Var försiktig där ute.,Dışarıda dikkatli ol. +"Say friend, I'll help you, if you help me. Give me 5 gold and I'll tell you what I know.",TXT_DLG_SCRIPT33_D1516_SAYFR,MAP33: Guy next to Norwall Prison.,,,"Poslyš, příteli, pomůžu ti, když ti pomůžeš mě. Dej mi pět zlatých a já ti řeknu, co vím.","Sig ven, jeg vil hjælpe dig, hvis du hjælper mig. Giv mig 5 guld, så fortæller jeg dig, hvad jeg ved.","Sag, mein Freund. Ich helfe dir, wenn du mir hilst. Gib mir 5 Gold und ich sage dir was ich weiß.",,"Nu, amiko, mi helpos vin se vi helpas min. Donu 5 da oro kaj mi diros tion, kion mi scias.","A ver, amigo, te ayudo si tú me ayudas. Dame 5 de oro y te digo lo que sé.",,"Hei kuule; voin auttaa sinua, jos autat minua. Viidestä kultakolikosta kerron sinulle, mitä tiedän.","Dites, l'ami. Je vous aide si vous m'aidez. Donnez moi 5 pièces et je vous dirais ce que je sais.","Figyelj barátom, segítek rajtad ha te is segítesz. Adj szépen 5 aranyat és elárulom amit tudok.","Senti qua, amico, io aiuterò te se tu aiuterai me. Dammi 5 pezzi d'oro e ti dirò tutto quello che so.","助けてくれるなら援助する。 +5ゴールドで知っている情報を全て教えよう","친구, 나는 너를 도와주고 싶어. 그러기 전에 나에게 5 골드를 줘. 그럼 내가 아는 걸 알려줄게.","Zeg vriend, ik zal je helpen, als je me helpt. Geef me 5 goud en ik zal je vertellen wat ik weet.","Jeg skal hjelpe deg, hvis du hjelper meg. Gi meg fem gull, så forteller jeg hva jeg vet.","Powiedz przyjacielu, pomogę ci, jeśli ty pomożesz mi. Daj mi 5 złotych, a powiem ci, co wiem.","Que tal, eu te ajudo se você me ajudar. Me dê 5 moedas de ouro e eu te digo o que eu sei.",,"Să zicem prietene, că te ajut, dacă și tu m-ajuți. Dă-mi 5 monezi și îți voi spune ce știu.","Дружище, я помогу тебе, если ты поможешь мне. Пять золотых, и я расскажу тебе всё, что знаю!",,"Säg vän, jag hjälper dig om du hjälper mig. Ge mig fem guld så berättar jag vad jag vet.","Dostum, sen bana yardım edersen ben de sana yardım ederim. Bana 5 altın ver, ben de sana bildiklerimi anlatayım." +Here's the gold.,TXT_RPLY0_SCRIPT33_D1516_HERES,〃,,,Tady máš to zlato.,Her er guldet.,Hier ist das Gold.,,Jen la oro.,Aquí tienes el oro.,,Tässä kulta.,Voilà votre argent.,Itt az arany.,Ecco l'oro.,金はこれだ。,여기 골드입니다.,Hier is het goud.,Her er gullet.,Oto złoto.,Tome estas moedas.,,Aici e aurul.,Вот монеты.,,Här är guldet.,İşte altın. +"If you punch someone, you won't set off the alarms.",TXT_RYES0_SCRIPT33_D1516_IFYOU,〃,,,"Když někoho praštíš, nespustíš alarmy.","Hvis du slår nogen, vil du ikke udløse alarmen.","Wenn du jemanden schlägst, wirst du keinen Alarm auslösen.",,Piki iun ne ekagigas alarmojn.,"Acuchillar a alguien +no activa las alarmas.",,"Jos lyöt jotakuta nyrkillä, et laukaise hälyttimiä.","Si vous plantez quelqu'un avec votre dague de poing, vous n'activez pas les alarmes.","Ha behúzol valakinek, még nem indul be a riasztó.","Se usi i pugni, non attiverai l'allarme.",パンチならアラームを鳴らせることはない。,"만약 네가 누군가를 주먹으로 때린다면, 알람은 울리지 않을 거야.","Als je iemand slaat, zal je het alarm niet afgaan.","Hvis du slår noen, utløser du ikke alarmen.","Jeśli kogoś uderzysz, nie uruchomisz alarmów.","Se você der um soco em alguém, você não ativará os alarmes.",,"Dacă îi tragi un pumn cuiva, nu vei declanșa alarma.","Убивай холодным оружием, тогда ты не поднимешь тревогу.",,Om du slår någon så kommer du inte att utlösa larmet.,"Eğer birine yumruk atarsan, alarmları çalıştırmazsın." +I won't tell you anything for free!,TXT_RNO0_SCRIPT33_D1516_IWONT,〃,,,Zadarmo ti nic říkat nebudu!,Jeg vil ikke fortælle dig noget gratis!,Umsonst werde ich dir nichts sagen.,,Mi diros nenion senpage!,¡No te diré nada gratis!,¡No te voy a decir nada gratis!,En kerro mitään ilmaiseksi!,Je ne vous dirai rien gratuitement!,Nem árulok el ingyen semmit se!,Non ti dirò nulla se prima non vedo l'oro!,タダでは教えられないな!,무료로는 말 못 해!,Ik zal je niets gratis vertellen!,Jeg forteller deg ikke noe gratis!,Nie powiem ci nic za darmo!,Não te direi nada de graça!,,Nu-ți voi spune nimic pe gratis.,Бесплатно я не скажу ничего!,,Jag kommer inte att berätta något gratis!,Sana bedavaya bir şey söylemeyeceğim! +I've already told you what I know.,TXT_DLG_SCRIPT33_D3032_IVEAL,〃,,,"Už jsem ti řekl, co vím.","Jeg har allerede fortalt dig, hvad jeg ved.","Ich habe dir alles gesagt, was ich weiß.",,"Mi jam diris tion, kion mi scias.",Ya te he dicho lo que sé.,Ya te dije lo que sé.,"Olen jo kertonut sinulle, mitä tiedän.",Je vous ai dit tout ce que je sais.,Már elmondtam amit tudtam.,Ti ho già detto ciò che so.,俺が知っていることはこれで全部だ。,난 이미 내가 아는 걸 말해 줬어!,Ik heb je al verteld wat ik weet.,Jeg har allerede fortalt deg det jeg vet.,"Już ci powiedziałem, co wiem.",Já te disse o que eu sei.,,Ți-am spus deja tot ce știu.,"Я уже сказал тебе всё, что знал.",,Jag har redan berättat vad jag vet.,Sana bildiklerimi anlattım zaten. +Hello friend. What can I get for you?,TXT_DLG_SCRIPT33_D4548_HELLO,MAP33: Weapons.,,,"Zdravím, příteli, co ti mohu nabídnout?","Hej, min ven. Hvad kan jeg få for dig?","Hallo, Freund, was kann ich dir geben?",,"Saluton, amiko. Kion mi donu al vi?","Hola, amigo. ¿Qué puedo ofrecerte?",,"Terve, ystävä; miten voin olla avuksi?","Bonjour, l'ami, que puis-je pour vous?",Üdvözöllek barátom. Mit tehetek érted?,"Salve, amico. Cosa posso procurarti?",どうも同士よ。何か必要か?,"안녕하십니까, 친구여. 구매하고 싶은 게 있습니까?",Hallo vriend. Wat kan ik voor je halen?,"Hei, min venn. Hva vil du ha?",Witaj przyjacielu. Co mogę dla ciebie zdobyć?,"Olá amigo, como posso te ajudar?",,"Bună prietene, ce pot să-ți aduc?",Здравствуй. Что-нибудь интересует?,,"Hej, min vän. Vad kan jag få för dig?",Merhaba dostum. Senin için ne yapabilirim? +Electric bolts,TXT_RPLY0_SCRIPT33_D4548_ELECT,〃,,,Elektrické šípy,Elektriske bolte,Elektrische Pfeile,,Elektrajn sagojn,Flechas eléctricas,,Sähkönuolia,Carreaux électriques.,Elektromos nyilak,Dardi elettrificati ,エレクトリック ボルト,전격 볼트,Elektrische bouten,Elektriske bolter.,Elektryczne śruby.,Setas elétricas,,Bolțuri electrice,Электрические болты,,Elektriska bultar,Elektrikli cıvata. +One quarrel it is.,TXT_RYES0_SCRIPT33_D4548_ONEQU,〃,,,Jeden toulec.,Et skænderi bliver det.,Hier hast du sie.,,Jen sagoj.,Salen unas flechas.,,"Tässä, olkaa hyvä.",Un carquois pour vous.,Itt is van.,Eccoli qua.,クォーレル一本だ。,잔소리 없이 주겠습니다.,Eén ruzie is het.,En krangel blir det.,Jedna kłótnia to jest.,Está na mão.,,Aici sunt.,Один колчан.,,Ett gräl blir det.,Tek bir tartışma. +You're broke!,TXT_RNO0_SCRIPT33_D4548_YOURE,〃,,,Jseš švorc!,Du er flad!,Du bist pleite!,,Vi ne havas monon!,¡Estás sin blanca!,¡No traes dinero!,Olet peeaa!,Vous êtes à sec!,Nincs is nálad pénz!,Sei sul lastrico!,スッカラカンじゃないか!,돈이 한 푼도 없는 것 같은데.,Je bent blut!,Du er blakk!,Jesteście spłukani!,Você está sem grana!,,Ești falit!,"Друг, да ты на мели!",,Du är pank!,Beş parasızsın! +Clip of bullets,TXT_RPLY1_SCRIPT33_D4548_10ROU,〃,,,Zásobník s náboji,Et patron-klip,10-Kugeln-Magazin,,Magazenon,Un cargador,,Luotilipas,Chargeur de 10 cartouches.,Egy tárnyi töltény,Un caricatore di proiettili,銃弾倉,돌격소총 탄창,Klem van kogels,Et magasin med kuler,Klips z kulami.,Carregador de balas,,Cartuș de gloanțe,Обойма патронов,,Klockan med kulor.,Mermi şarjörü +Here's your ammo,TXT_RYES1_SCRIPT33_D4548_HERES,〃,,,Tady je tvá munice.,Her er din ammunition,Hier ist deine Munition.,,Jen via municio.,Aquí tienes tu munición.,,Tässä panoksesi.,Voilà vos balles.,Itt a töltényed.,Ecco le tue munizioni.,これでアンタのブツだ。,여기 탄약입니다.,Hier is je munitie....,Her er ammunisjonen din,Oto twoja amunicja.,Aqui está a sua munição.,,Aici e.,Вот твои патроны.,,Här är din ammunition.,İşte cephaneniz. +"Sorry, no money, no bullets.",TXT_RNO1_SCRIPT33_D4548_SORRY,〃,,,"Promiň. Žádné peníze, žádné náboje.","Beklager, ingen penge, ingen kugler.","Tut mir leid. Kein Geld, keine Munition.",,"Pardonon. Sen mono +ne estas kugloj.","Lo siento, sin dinero +no hay balas.",,"Valitan, ei rahaa, ei luoteja.","Désolé, pas d'argent, pas de munitions.","Ha nincs pénz, nincs töltény.","Mi spiace, niente soldi, niente munizioni.",悪いが、金が無ければブツも無しだ。,돈 없으면 거래 못 합니다.,"Sorry, geen geld, geen kogels.","Beklager, ingen penger, ingen kuler.","Niestety, nie ma pieniędzy, nie ma naboi.","Desculpe. Sem grana, sem balas.",,"Scuze, niciun ban, niciun glonț.","Извини, нет денег — нет патронов!",,"Tyvärr, inga pengar, inga kulor.","Üzgünüm, para yoksa mermi de yok." +Ammo box,TXT_RPLY2_SCRIPT33_D4548_50ROU,〃,,,Krabici nábojů,Ammo kasse,50-Kugeln-Schachtel,,Munici-keston,Caja de municiones,,Luotilaatikko,Boîte de 50 balles.,Töltény doboz,Scatola di munizioni,銃弾倉箱,돌격소총 탄약 박스,Munitiedoos,Ammunisjonsboks,Skrzynka z amunicją.,Caixa de munição,,Cutie cu muniție,Коробка патронов,,Ammunitionslåda,Cephane kutusu +Here you go,TXT_RYES2_SCRIPT33_D4548_HEREY,〃,,,Tu máš.,Værsgo.,Bitteschön.,,Jen,Aquí tienes,,Ole hyvä.,Voilà pour vous.,Parancsolj.,Ecco a te.,どうぞ。,거래 감사드립니다.,Alsjeblieft,Vær så god.,Proszę bardzo.,Aqui está,,Aici este,Держи.,,Varsågod.,Al bakalım. +You don't have enough gold!,TXT_RNO2_SCRIPT33_D4548_YOUDO,〃,,,Nemáš dost zlaťáků!,Du har ikke nok guld!,Du hast nicht genug Gold.,,Vi ne havas sufiĉe da oro!,¡No tienes suficiente oro!,,Sinulla ei ole riittävästi kultaa!,Vous n'avez pas assez d'argent.,Nincs elég aranyad.,Non hai abbastanza oro!,十分な額じゃない,골드가 충분치 않군요!,Je hebt niet genoeg goud!,Du har ikke nok gull!,Nie masz wystarczająco dużo złota!,Você não tem ouro suficiente!,,Nu ai suficient aur!,У тебя недостаточно золота!,,Du har inte tillräckligt med guld!,Yeterince altının yok! +Ammo satchel,TXT_RPLY3_SCRIPT33_D4548_AMMOS,〃,,,Brašnu na munici,Ammotaske,Munitionstasche.,,Munici-sakon,Mochila de municiones,,Ammuslaukku,Sacoche de munitions.,Lőszeres hátizsák,Sacca di munizioni,弾薬鞄,탄약 배낭,Munitie tasje,Ammunisjonsveske,Torba na amunicję,Mochila de munição,,Sac cu muniție,Ранец боеприпасов,,Ammunitionsväska,Cephane çantası +"Thank you, anything else?",TXT_RYES3_SCRIPT33_D4548_THANK,〃,,,Děkuji. Něco dalšího?,"Tak, er der andet?","Danke, sonst noch was?",,Dankon. Ĉu ion alian?,Gracias. ¿Algo más?,,Kiitos; vielä jotain muuta?,"Merci, quelque chose d'autre?","Köszönöm, még valami esetleg?","Grazie, serve qualcos'altro?",ありがとう。 他に何か?,좋습니다! 더 필요한 거라도?,"Bedankt, nog iets anders?","Takk, noe mer?","Dziękuję, coś jeszcze?",Obrigado. Mais alguma coisa?,,"Merci, altceva?",Благодарю. Что-нибудь ещё?,,"Tack, något annat?","Teşekkürler, başka bir şey var mı?" +"You can't afford that, good day.",TXT_RNO3_SCRIPT33_D4548_YOUCA,〃,,,"To si nemůžeš dovolit, přeji hezký den.","Det har du ikke råd til, god dag.",Das kannst du dir nicht leisten. Guten Tag.,,"Vi ne povas sen mono. +Havu bonan tagon!","No te alcanza. +¡Ten un buen día!",,Sinulla ei ole siihen varaa; hyvää päivänjatkoa.,Vous ne pouvez pas l'acheter. Au revoir.,"Erre neked nem tellik, szép napot.","Non te la puoi permettere, buona giornata.",それを買える余裕は無い、また今度。,제공할 수 없습니다. 유감이군요.,"Dat kan je je niet betalen, goede dag.",Det har du ikke råd til. Adjø.,"Nie stać cię na to, dzień dobry.",Você não pode comprar isto. Tenha um bom dia.,,"Nu ai bani, ziua bună.",У тебя не хватает денег. Всего доброго!,,"Du har inte råd med det, god dag.","Bunu karşılayamazsın, iyi günler." +Welcome. What may I show you?,TXT_DLG_SCRIPT33_D6064_WELCO,MAP33: Armory,,,Vítej. Co bych ti mohl nabídnout?,Velkommen. Hvad må jeg vise dig?,Willkommen. Was darf ich dir zeigen?,,Bonvenon. Kion mi montru al vi?,Bienvenido. ¿Qué puedo mostrarte?,,Tervetuloa. Mitä voin teille esitellä?,"Bienvenue, comment puis-je vous servir?",Üdvözöllek barátom. Mit tehetek érted?,Benvenuto. Cosa posso farti vedere?,ようこそ、何を見ていきますか?,어서 오세요! 무엇이 필요한지?,Welkom. Wat kan ik je laten zien?,Velkommen. Hva kan jeg vise deg?,Witam. Co mogę ci pokazać?,Seja bem-vindo. O que posso lhe mostrar?,,Bună. Cu ce te pot ajuta?,Здравствуй. Что-нибудь интересует?,,Välkommen. Vad får jag visa dig?,Hoş geldiniz. Size ne gösterebilirim? +Environmental suit,TXT_RPLY0_SCRIPT33_D6064_ENVIR,〃,,,Ochranný oblek,Miljødragt,Schutzanzug.,,Medi-ŝirman veston,Traje NBQ,,Ympäristösuojapuku,Combinaison Hazmat.,Védő ruha,Tuta ambientale,耐環境スーツ,환경 방호복,Beschermend Pak,Miljødrakt,Kombinezon ekologiczny,Traje de proteção,,Costum de Protecție împotriva Mediului,Защитный костюм,,Miljödräkt,Çevre kıyafeti. +Here you are.,TXT_RYES0_SCRIPT33_D6064_HEREY,〃,,,"Tak, tady to je.",Værsgo.,Bitteschön.,,Jen.,Toma.,,"Tässä, olkaa hyvä.",Voilà pour vous.,Parancsolj.,Ecco a te.,はい、これをどうぞ。,받으세요!,Hier ben je dan.,Vær så god.,Proszę bardzo.,Aqui está.,,Aici e.,"Хорошо, бери.",,Varsågod.,Al bakalım. +You don't have enough money for that.,TXT_RNO0_SCRIPT33_D6064_YOUDO,〃,,,Na to nemáš dost peněz.,Du har ikke penge nok til det.,Dafür hast du nicht genug Geld.,,Vi ne havas sufiĉe da mono.,No tienes suficiente dinero.,,Teillä ei ole tarpeeksi rahaa sitä varten.,Vous n'avez pas assez d'argent.,"Sajnálom, de Önnek nem áll módjában kifizetni ezt.",Non hai abbastanza soldi per questo.,すみませんが、貴方は十分なお金を持っていません。,돈이 충분치 않아요.,Daar heb je niet genoeg geld voor.,Du har ikke nok penger til det.,Nie masz na to pieniędzy.,Você não tem dinheiro o suficiente para isto.,,N-ai suficienți bani.,"Извини, но у тебя не хватает денег.",,Du har inte tillräckligt med pengar för det.,Bunun için yeterli paran yok. +Leather armor.,TXT_RPLY1_SCRIPT33_D6064_LEATH,〃,,Leather armour,Kožené brnění,Læder rustning.,Lederrüstung,,Ledan armaĵon.,Armadura de cuero.,,Nahkasuojus,Armure de cuir.,Bőr vért.,Armatura di cuoio,レザーアーマー,가죽 갑옷,Leren harnas,Lær rustning,Skórzana zbroja.,Armadura de couro.,,Armură de piele.,Кожаная броня,,Läderrustning.,Deri zırh. +Here you are.,TXT_RYES1_SCRIPT33_D6064_HEREY,〃,,,Tady máš.,Værsgo.,Bitteschön.,,Jen.,Toma.,,Olkaa hyvä.,Voilà pour vous.,Parancsolj.,Ecco a te.,これをどうぞ。,딱 맞는 치수의 갑옷이죠.,Hier ben je dan.,Vær så god.,Proszę bardzo.,Aqui está.,,Aici e.,Держи.,,Här är den.,Al bakalım. +Perhaps some other time?,TXT_RNO1_SCRIPT33_D6064_PERHA,〃,,,Možná někdy jindy?,Måske en anden gang?,Vielleicht ein anderes Mal?,,Ĉu eble alian fojon?,¿Quizás en otra ocasión?,¿Tal vez en otra ocasión?,Ehkä jokin toinen kerta?,Peut être une autre fois?,Talán később?,Magari un'altra volta?,また別の機会に?,아마 나중에 사야겠는데요?,Misschien een andere keer?,Kanskje en annen gang?,Może innym razem?,Talvez outra hora?,,Poate altădată?,"Может, в следующий раз?",,Kanske en annan gång?,Belki başka bir zaman? +Metal armor,TXT_RPLY2_SCRIPT33_D6064_METAL,〃,,Metal armour,Kovové brnění,Metal rustning,Metallrüstung,,Metalan armaĵon,Armadura de metal,,Metallihaarniska,Armure de métal.,Fém vért,Armatura di metallo,メタルアーマー,강철 갑옷,Metalen harnas,Metallrustning.,Metalowa zbroja,Armadura de metal,,Armură de metal,Металлическая броня,,Metallrustning.,Metal zırh. +Wear it in good health.,TXT_RYES2_SCRIPT33_D6064_WEARI,〃,,,Nos ho ve zdraví.,Bær den ved godt helbred.,Trage sie und bleib gesund.,,Ĝuu ĝin.,Disfrútala.,,Pitäköön asu teidät terveenä.,Portez-la en bonne santé.,Használd egészséggel.,Che possa esserti utile!,着ると安心しますよ。,건강하게 착용하십시오.,Draag het in goede gezondheid.,Bruk den ved god helse.,Noś ją w dobrym zdrowiu.,Vista com orgulho.,,Să o porți sănătos.,Носи на здоровье.,,Bär den vid god hälsa.,Sağlıkla giy. +Come back when you can afford it.,TXT_RNO2_SCRIPT33_D6064_COMEB,〃,,,"Vrať se, až si to budeš moct dovolit.","Kom tilbage, når du har råd til det.","Komme wieder, wenn du dir sie leisten kannst.",,"Revenu kiam vi +povos aĉeti ĝin.","Vuelve cuando +puedas comprarla.",,"Palataan asiaa, kun teillä on siihen varaa.",Revenez quand vous pouvez l'acheter.,Gyere vissza ha tellik rá.,Ritorna quando potrai permettertela.,余裕がある時にまた。,돈이 좀 있을때 다시 찾아와주세요.,Kom terug wanneer je het je kunt veroorloven.,Kom tilbake når du har råd.,"Wróć, gdy będzie cię na to stać.",Volte quando puder comprar.,,Întoarce-te când ai destui bani!,"Вернёшься, когда поднакопишь на то, что хочешь!",,Kom tillbaka när du har råd.,Paranız yettiğinde geri gelin. +How may I assist you?,TXT_DLG_SCRIPT33_D7580_HOWMA,MAP33: Hospital,,,Jak ti mohu pomoci?,Hvordan kan jeg hjælpe dig?,Womit kann ich dienen?,,Kiel mi helpu vin?,¿Cómo puedo ayudarte?,,Miten voin teitä avustaa?,Comment puis-je vous aider aujourd'hui?,Miben lehetek a segítségedre?,Come posso aiutarti?,何かお困りですか?,반갑습니다. 어떻게 도와드릴까요?,Hoe kan ik u helpen?,Hvordan kan jeg hjelpe deg?,Jak mogę ci pomóc?,Como posso ajudá-lo?,,Cu ce te pot ajuta?,Чем могу помочь?,,Hur kan jag hjälpa dig?,Size nasıl yardımcı olabilirim? +Med patch,TXT_RPLY0_SCRIPT33_D7580_MEDPA,〃,,,Obvazy,Medicinsk plaster,Medizinische Bandage,,Kuracbendoj,Tiritas,Curitas,Sidekääre,Pansement.,Ragtapasz,Bende,医薬パッチ,의료 붕대,Med-patch,Medisinplaster,Bandaż,Compressa médica,,Bandaj medical,Бинтами,,Medicinsk plåster,Tıbbi yama +Here's your patch kit.,TXT_RYES0_SCRIPT33_D7580_HERES,〃,,,Tady je tvůj obvaz.,Her er dit patch-kit.,Hier ist deine Bandage.,,Jen viaj kuracbendoj,Aquí tienes tus tiritas.,Aquí tienes tus curitas.,Tässä käärepakettisi.,Voilà votre pansement.,Itt a tapaszod.,Ecco le tue bende.,これをどうぞ。,저렴한 가격의 의료 붕대입니다.,Hier is je patch.,Her er lappesettet ditt.,Oto twój bandaż.,Aqui está a sua compressa,,Aici este.,Вот они.,,Her er dit plaster.,İşte yama setiniz. +You need 10 gold for that.,TXT_RNO0_SCRIPT33_D7580_YOUNE,〃,,,Na ty potřebuješ deset zlatých.,Du skal bruge 10 guld for det.,Dafür brauchst du 10 Gold.,,Vi bezonas dek da oro.,Necesitas diez de oro.,,Tarvitset sitä varten 10 kolikkoa.,Il vous faut 10 pièces pour ça.,10 aranyba kerül.,Ti servono 10 pezzi d'oro per quello.,10 ゴールド必要です。,10 골드입니다. 설마 이 만한 양의 돈이 없으신가요?,Daar heb je 10 goud voor nodig.,Du trenger 10 gull for det.,Potrzebujesz na to 10 złota.,Você precisa de 10 moedas para isto.,,Ai nevoie de 10 monezi pentru aia.,Тебе не хватает 10 золотых.,,Du behöver 10 guld för den.,Bunun için 10 altına ihtiyacın var. +Field surgery kit,TXT_RPLY1_SCRIPT33_D7580_FIELD,〃,,,Lékárničku,Kirurgisæt,Erste-Hilfe-Kasten,,Kirurgia kesto,Kit quirúrgico,,Kenttäkirurgilaukku,Kit de chirurgie.,Harctéri műtéti felszerelés,Kit chirurgico,手術キット,수술 키트,Veld chirurgie kit,Kirurgisett,Zestaw do chirurgii polowej,Kit de cirurgia,,Kit chirurgical de teren.,Аптечкой,,Fältkirurgisk utrustning,Saha ameliyat kiti +Thank you.,TXT_RYES1_SCRIPT33_D7580_THANK,〃,,,Děkuji.,Tak.,Danke.,,Dankon.,Gracias.,,Kiitoksia,Merci.,Köszönöm.,Grazie.,ありがとうございます。,말 없이 주겠습니다. 거래 고마워요!,Bedankt.,Takk skal du ha.,Dziękuję.,Obrigado.,,Merci.,Спасибо.,,Tack.,Teşekkür ederim. +"I wish I could give them away, but they cost 25 gold.",TXT_RNO1_SCRIPT33_D7580_IWISH,〃,,,"Přál bych si je dávat zadarmo, ale stojí 25 zlatých.","Jeg ville ønske, jeg kunne give dem væk, men de koster 25 guld.","Ich wünschte, ich könnte sie verschenken, aber sie kosten 25 Gold.",,"Mi donacus ĝin, sed +ĝi kostas 25 da oro.","Ojalá pudiera regalarlo, +pero cuesta 25 de oro.",,"Kunpa voisinkin antaa niitä lahjaksi, mutta ne maksavat 25 kolikkoa.","J'adorerais les donner gratuitement, mais non, ça coûte 25 pièces.","Bárcsak ingyen osztogathatnám, de 25 aranyba kerül.","Mi piacerebbe darli via, ma costano 25 pezzi d'oro.",譲渡したい所ですが、25 ゴールド必要です。,25 골드만 있으면 잔소리 말고 주겠습니다.,"Ik wou dat ik ze kon weggeven, maar ze kosten 25 goud.","Jeg skulle ønske jeg kunne gi dem bort, men de koster 25 gull.","Chciałbym móc je rozdać, ale kosztują 25 złota.","Bem que eu queria doar de graça, mas custa 25 moedas de ouro.",,"Aș vrea să le pot da pe gratis, dar costă 25 de monezi.","С радостью бы отдал, но они по 25 золотых.",,"Jag önskar att jag kunde ge bort dem, men de kostar 25 guld.",Keşke onları verebilseydim ama 25 altına mal oluyorlar. +Healing,TXT_RPLY2_SCRIPT33_D7580_HEALI,〃,,,Ošetření,Healing,Heilung,,Kuracado,Curación,,Sairaanhoitoa,Des soins.,Gyógyítás,Ho bisogno di essere curato.,治療だ,치료 중.,Genezing,Helbredelse,Uzdrawianie,Cura,,Vindecă-mă.,Медкомплектом,,Helande,Şifa +There you go. Take care now.,TXT_RYES2_SCRIPT33_D7580_THERE,〃,,,A je to. Buď opatrný.,Værsgo. Pas godt på dig selv nu.,Bitteschön. Aber sei vorsichtiger.,,Jen. Estu atenta.,Toma. Cuídate.,,Olkaa hyvä. Pitäkäähän nyt huoli itsestänne.,"Voilà pour vous, portez-vous-bien.",Meg is oldottam. Vigyázz magadra.,"Ecco fatto, stammi bene.",こちらになります、お気をつけて。,치료가 끝났어. 몸 조심하라고.,Daar ga je. Pas goed op jezelf.,Vær så god. Ta vare på deg selv.,No i proszę. Dbaj o siebie.,Pronto. Se cuida.,,Gata. Ai grijă acum.,Пожалуйста. Береги себя!,,Här har du. Ta hand om dig nu.,Al bakalım. Kendine iyi bak. +"Well, maybe you can afford some med patches?",TXT_RNO2_SCRIPT33_D7580_WELLM,〃,,,Možná si můžeš dovolit nějaké obvazy?,Måske har du råd til nogle medicinske plastre?,"Naja, vielleicht kannst du dir ein paar Bandagen leisten?",,"Nu, ĉu vi eble povas +aĉeti kuracbendojn?","Bueno, ¿quizás tengas +para comprar tiritas?","Bueno, ¿tal vez tengas +para comprar curitas?",Ehkä teillä olisi kuitenkin sidekääreisiin varaa?,"Eh bien, peut être pouvez-vous vous acheter quelques pansements?",Talán tellik pár tapaszra is?,"Beh, forse puoi permetterti delle bende?",ところで、医薬パッチを買う余裕はありますか?,의료 붕대는 어떠신가요? 이 건 저렴한데.,"Nou ja, misschien kunt u zich wat medische patches veroorloven?",Kanskje du har råd til noen medisinplaster?,Może stać cię na plastry?,"Bem, talvez você possa comprar algumas compressas?",,"Păi, poate îți permiți niște truse medicale?","Тогда, может быть, купишь несколько бинтов?",,Du kanske har råd med några medicinska plåster?,Belki birkaç ilaç yamasını karşılayabilirsin? +"Hello friend, I haven't seen you around here before. All I can say is that I'd be careful if I were you, there's a lot going on and it's better if you don't get in the way.",TXT_DLG_SCRIPT33_D9096_HELLO,MAP33: Barkeep.,,,"Ahoj, příteli, ještě jsem tě tady neviděl. Jediné, co můžu říct, je: Být tebou, byl bych opatrný. Děje se toho hodně a je lepší neplést se věcem do cesty.","Hej ven, jeg har ikke set dig her før. Alt jeg kan sige er, at jeg ville være forsigtig, hvis jeg var dig, der sker meget, og det er bedre, hvis du ikke kommer i vejen.","Hallo, Freund, ich habe dich hier noch nicht gesehen. Ich kann nur sagen, sei vorsichtig und wenn ich du wäre, würde ich es vorziehen, niemandem im Weg zu stehen.",,"Saluton, amiko, mi ne vidis vin ĉi tie antaŭe. Mi povas nur diri, ke mi estus atenta se mi estus vi: okazas multaj aferoj kaj estas pli bone, ke vi ne miksu vin.","Hola, amigo, no te he visto por aquí antes. Todo lo que puedo decir es que tendría cuidado si fuera tú: están pasando muchas cosas y es mejor que no te entrometas.","Hola, amigo, es la primera vez que te veo por aquí. Todo lo que puedo decir es que tendría cuidado si fuera tú: están pasando muchas cosas y es mejor que no te entrometas.","Tervehdys. En ole teitä täällä ennen nähnytkään. Teidän saappaissanne olisin varuillani. Paljon on meneillään, ja on parempi pysyä poissa tieltä.","Bienvenue, l'ami. Je ne vous ai pas vu ici avant. Tout ce que peux vous dire, c'est de faire attention à vous. Il se passe beaucoup de choses ici, et je pense que vous ne voulez pas vous en mêler.","Szervusz barátom, nem láttalak még itt eddig. Csak annyi jó tanácsot tudok adni, hogy légy óvatos. Felpörögtek az események az utóbbi időben, és a helydben nem keverednék bele.","Salve amico, non ti ho mai visto da queste parti prima. Posso solo dirti che farei molta attenzione se fossi in te. Stanno succedendo diverse cose, ed è meglio non immischiarsi.","どうも余所者、この辺では見かけない顔だな。 では一杯アドバイスをおごろう。 この付近が自由な発言を 許さないからって下手な真似をするなよ。 -オーダーという自警団がすぐに駆けつけてくるぞ。","반갑네, 친구. 낯선 사람인 것 같은데, 조심하고 걸어 다니게나. 지금 이곳에서 꽤 많은 일이 일어났거든. 내가 하는 말을 들으면 이해가 될 걸세.","Hallo vriend, ik heb je hier nog niet eerder gezien. Ik kan alleen maar zeggen dat ik voorzichtig zou zijn als ik jou was, er is veel aan de hand en het is beter als je niet in de weg staat.",,Olá amigo. Acho que não te vi por aqui antes. Tudo o que posso dizer é que eu tomaria cuidado se eu fosse você. Há muita coisa acontecendo e é melhor não se envolver.,,,"Привет, дружище. Что-то я не видел тебя тут раньше. Дам тебе один совет — я бы на твоём месте был поосторожнее. Сейчас здесь такое творится, что лучше не высовываться.", -Information,TXT_RPLY0_SCRIPT33_D9096_INFOR,,,,Informace,Informationen,,,Información,,,Des infos.,,,情報,정보를 줘.,Informatie,,Informações,,,Есть новости?, -The sewers hold more than just rats and robots.,TXT_RYES0_SCRIPT33_D9096_THESE,,,,Stoky ukrývají víc než jen krysy a roboty.,Die Kanalisation hat mehr zu bieten als Ratten und Roboter.,,,Las alcantarillas tienen más que ratas y robots.,,,Les égouts contiennent plus que des rats et des robots.,,,他は...下水道には鼠やロボが沢山だ。,"하수도엔 쥐도 있고, 오물도 있고, 그 중 위험한 로봇들도 있다네.",In het riool zijn meer dan alleen ratten en robots te vinden.,,Os esgotos abrigam mais do que ratos e robôs.,,,В канализации водятся не только крысы и роботы., -Hey a guy's got to make some money. You think these jokers tip well?,TXT_RNO0_SCRIPT33_D9096_HEYAG,,,,"Hele, nějak si vydělávat musím. Myslíš, že tihle šašci dávají dobré spropitné?","Hey, mann muss auch sein Auskommen haben, glaubst du, diese Witzbolde geben einem Trinkgeld?",,,Hey un servidor tiene que ganar algo de dinero. ¿Crees que estos payasos dan buena propina?,,,"Hé, j'ai besoin de me faire de l'argent, vous savez? Vous croyez que ces salauds me paient bien?",,,"ちょっと男はお金を稼ぐんだ。 +オーダーという自警団がすぐに駆けつけてくるぞ。","반갑네, 친구. 낯선 사람인 것 같은데, 조심하고 걸어 다니게나. 지금 이곳에서 꽤 많은 일이 일어났거든. 내가 하는 말을 들으면 이해가 될 걸세.","Hallo vriend, ik heb je hier nog niet eerder gezien. Ik kan alleen maar zeggen dat ik voorzichtig zou zijn als ik jou was, er is veel aan de hand en het is beter als je niet in de weg staat.","Hei, min venn. Jeg har ikke sett deg her tidligere. Alt jeg kan si er at jeg ville vært forsiktig hvis jeg var deg, det er mye som skjer, og det er bedre om du ikke kommer i veien.","Witaj przyjacielu, nie widziałem cię tu wcześniej. Mogę tylko powiedzieć, że na twoim miejscu uważałbym, dużo się dzieje i lepiej, żebyś nie wchodził w drogę.",Olá amigo. Acho que não te vi por aqui antes. Tudo o que posso dizer é que eu tomaria cuidado se eu fosse você. Há muita coisa acontecendo e é melhor não se envolver.,,"Bună prietene, nu te-am mai văzut pe-aici. Tot ce spune e că aș avea grijă pe unde merg, se întâmplă multe prin jur și e mai bine să nu te amesteci.","Привет, дружище. Что-то я не видел тебя тут раньше. Дам тебе один совет: я бы на твоём месте был поосторожнее. Сейчас здесь такое творится, что лучше не высовываться.",,"Hej vän, jag har inte sett dig här förut. Allt jag kan säga är att jag skulle vara försiktig om jag var du, det är mycket på gång och det är bättre om du inte kommer i vägen.","Merhaba dostum, seni daha önce buralarda görmemiştim. Tek söyleyebileceğim, yerinde olsam dikkatli olurdum, çok şey oluyor ve yoluna çıkmazsan daha iyi olur." +Information,TXT_RPLY0_SCRIPT33_D9096_INFOR,〃,,,Informace,,Informationen,,Informoj,Información,,Tietoa.,Des infos.,Információ.,Informazioni,情報,정보를 줘.,Informatie,Informasjon,Informacje,Informações,,Informație,Есть новости?,,,Bilgi +The sewers hold more than just rats and robots.,TXT_RYES0_SCRIPT33_D9096_THESE,〃,,,Stoky ukrývají víc než jen krysy a roboty.,Kloakkerne rummer mere end bare rotter og robotter.,Die Kanalisation hat mehr zu bieten als Ratten und Roboter.,,"En la kloako ne estas +nur ratoj kaj robotoj.","En las alcantarillas hay más +que solo ratas y robots.",,Viemärit pitävät sisällään muutakin kuin vain rottia ja robotteja.,Les égouts contiennent plus que des rats et des robots.,A kanális nem csak patkányokat és robotokat rejteget.,Le fogne contengono molto di più che ratti e robot.,他は...下水道には鼠やロボが沢山だ。,"하수도엔 쥐도 있고, 오물도 있고, 그 중 위험한 로봇들도 있다네.",In het riool zijn meer dan alleen ratten en robots te vinden.,Kloakken rommer mer enn bare rotter og roboter.,Kanały kryją w sobie coś więcej niż tylko szczury i roboty.,Os esgotos abrigam mais do que ratos e robôs.,,Canalele găzduiesc mai mult decât roboți și șobolani.,В канализации водятся не только крысы и роботы.,,Kloakerna rymmer mer än bara råttor och robotar.,Lağımlarda fareler ve robotlardan daha fazlası var. +Hey a guy's got to make some money. You think these jokers tip well?,TXT_RNO0_SCRIPT33_D9096_HEYAG,〃,,,"Hele, nějak si vydělávat musím. Myslíš, že tihle šašci dávají dobré spropitné?","Hey en fyr skal jo tjene nogle penge. Tror du, at de spassere giver gode drikkepenge?","Hey, mann muss auch sein Auskommen haben, glaubst du, diese Witzbolde geben einem Trinkgeld?",,"Homoj bezonas monon. +Ĉu vi atendas bonajn +trinkmonojn el ĉi tiaj klaŭnoj?","La gente tiene que comer, +¿o acaso crees que estos +bufones dan buena propina?",,"Hei, jollakin tavalla sitä pitää leipänsä ansaita. Luuletko, että nämä pellet antavat hyvin juomarahaa?","Hé, j'ai besoin de me faire de l'argent, vous savez? Vous croyez que ces salauds me paient bien?","Figyelj, nekem is élni kell valamiből. Azt hiszed ezek a pacákok sok borravalót hagynak itt?","Ehi, devo pure riuscire a mettere qualcosa da parte. Pensi che i clienti qua diano laute mance?","ちょっと男はお金を稼ぐんだ。 あなたはこれらのジョーカーがうまく傾くと -思いますか?",먹고 살려면 돈이 필요하다네. 이 손님들은 팁도 안 준다니까!,"Hé, een man moet wat geld verdienen. Denk je dat deze grappenmakers een goede fooi geven?",,"Ei, preciso ganhar uma grana. Você acha que esses palhaços dão bastante gorjeta?",,,"Заработай немного денег, парень. Или ты думаешь, что все эти шутники щедро платят?", -"Back again huh? Well, at least you know enough to keep your own skin intact. What can I do for you now?",TXT_DLG_SCRIPT33_D10612_BACKA,,,,"Zase zpátky, co? No, aspoň víš, jak si udržet kožich netknutý. Co pro tebe mohu udělat?","Schon wieder zurück, was? Na, wenigstens weißt du inzwischen, wie du das mit heiler Haut hinkriegst. Was kann ich jetzt für dich tun?",,,"¿De vuelta otra vez, eh? Bueno, al menos sabes suficiente para mantener tu pellejo intacto. ¿Qué puedo ofrecerte ahora?",,,"Déjà de retour, hein? Au moins vous savez sauver votre peau. Que puis-je faire pour vous?",,,"また戻ってね? +思いますか?",먹고 살려면 돈이 필요하다네. 이 손님들은 팁도 안 준다니까!,"Hé, een man moet wat geld verdienen. Denk je dat deze grappenmakers een goede fooi geven?","Hei, en fyr må tjene litt penger. Tror du disse jokerne gir bra med tips?","Hej facet musi zarobić trochę pieniędzy. Myślisz, że ci żartownisie dobrze dają napiwki?","Ei, preciso ganhar uma grana. Você acha que esses palhaços dão bastante gorjeta?",,Hei un om are nevoie și de bani. Crezi că glumeții ăștia au sfaturi bune?,"Заработай немного денег, парень. Или ты думаешь, что все эти шутники щедро платят?",,Hej en kille måste ju tjäna lite pengar. Tror du att de här skojarna ger bra dricks?,"Hey, bir adam biraz para kazanmalı. Bu şakacıların iyi bahşiş verdiğini mi düşünüyorsun?" +"Back again huh? Well, at least you know enough to keep your own skin intact. What can I do for you now?",TXT_DLG_SCRIPT33_D10612_BACKA,〃,,,"Zase zpátky, co? No, aspoň víš, jak si udržet kožich netknutý. Co pro tebe mohu udělat?","Tilbage igen, hva'? I det mindste ved du nok til at holde din egen hud intakt. Hvad kan jeg gøre for dig nu?","Schon wieder zurück, was? Na, wenigstens weißt du inzwischen, wie du das mit heiler Haut hinkriegst. Was kann ich jetzt für dich tun?",,"Do vi revenis. Nu, vi almenaŭ scias sufiĉe por eviti, ke vi estu vundita. Kion mi nun faru por vi?","De vuelta otra vez, ¿eh? Bueno, al menos sabes lo suficiente para mantener tu pellejo intacto. ¿Qué puedo ofrecerte ahora?",,"Kas, tulit takaisin? Näköjään sen verran älliä päässä, että kykenet itsesi hengissä pitämään. Mutta mitä saisi nyt olla?","Déjà de retour, hein? Au moins vous savez sauver votre peau. Que puis-je faire pour vous?","Már visszatértél, mi? Legalább tudsz vigyázni az irhádra. Mit tehetek érted?","Già di ritorno, eh? Beh, almeno ciò che sai ti sta tornando utile per rimanere vivo. Cosa posso fare per te ora?","また戻ってね? まあ、少なくともあなたは自分の肌を 損なわないようにするのに十分知っています。 -私は今あなたのために何ができますか?","다시 돌아온 건가? 뭐, 자기 몸 간수 잘하고 살아 돌아왔기에 망정이지. 뭘 원하나?","Weer terug, hè? Nou ja, je weet tenminste genoeg om je eigen huid intact te houden. Wat kan ik nu voor je doen?",,"Já voltou, é? Bom, pelo menos você sabe o suficiente para manter sua pele intacta. O que mais posso fazer por você?",,,"Снова ты? Ну что ж, ты хотя бы знаешь, как сберечь свою шкуру. Что я могу тебе предложить?", -More info,TXT_RPLY0_SCRIPT33_D10612_MOREI,,,,Další informace,Mehr Informationen.,,,Más información,,,Plus d'infos.,,,話のネタ。,그 외의 정보를 줘.,Meer info,,Mais informações.,,,Расскажи больше, -The governor is a simple reminder of the Order's influence.,TXT_RYES0_SCRIPT33_D10612_THEGO,,,,Guvernér je jednoduchou připomínkou vlivu Řádu.,Der Gouverneur ist eine einfache Erinnering an die Macht des Ordens.,,,El gobernador es un simple recordatorio de la influencia de la Orden,,,Le gouverneur d'est qu'un rappel de l'influence de l'ordre.,,,知事は俺達に自由はないと思い出させる象徴さ。,모렐 총독은 부정하고 짜증 나는 오더의 정권의 예야.,De gouverneur is een eenvoudige herinnering aan de invloed van de Orde.,,O governador é um simples lembrete da influência da Ordem.,,,Губернатор — живое напоминание о власти Ордена., -Come back if you change your mind.,TXT_RNO0_SCRIPT33_D10612_COMEB,,,,"Vrať se, pokud změníš názor.","Komm zurück, wenn du deine Meinung geändert hast.",,,Vuelve si cambias de idea.,,,Revenez si vous changez d'avis.,,,気が変わったら戻ってきな。,마음이 바뀌면 돌아와주게나.,Kom terug als u van gedachten verandert.,,Volte quando mudar de idéia.,,,Передумаешь — возвращайся., -"Well, you're sure asking a lot of questions for someone who's lived this long. That's ok though, I'd rather talk to someone like you than most of this lot.",TXT_DLG_SCRIPT33_D12128_WELLY,,,,"Na někoho, kdo přežil takhle dlouho, se ptáš docela hodně. To je v pořádku, radši bych se bavil s tebou než s většinou těhle lidí.","Du stellst eine Menge Fragen für jemanden, der schon so lange überlebt hat. Das ist ok, ich rede lieber mit jemandem wie dir als mit dem Rest der Typen da.",,,"Bueno, ciertamente estás haciendo muchas preguntas para alguien que ha vivido tanto. Aunque eso es bueno, preferiría hablar con alquien como tú que con la mayoría de esta gente.",,,"Vous posez beacoup de questions pour quelqu'un qui a survécu aussi longtemps. Ca me convient, je préfère parler à quelqu'un comme vous qu'a la majorité de ces idiots.",,,"所で、アンタは死に行かない人達に +私は今あなたのために何ができますか?","다시 돌아온 건가? 뭐, 자기 몸 간수 잘하고 살아 돌아왔기에 망정이지. 뭘 원하나?","Weer terug, hè? Nou ja, je weet tenminste genoeg om je eigen huid intact te houden. Wat kan ik nu voor je doen?","Tilbake igjen, hva? Du vet i det minste nok til å holde ditt eget skinn intakt. Hva kan jeg gjøre for deg nå?","Znowu to samo? Przynajmniej wiesz wystarczająco dużo, aby zachować własną skórę w nienaruszonym stanie. Co mogę dla ciebie zrobić?","Já voltou, é? Bom, pelo menos você sabe o suficiente para manter sua pele intacta. O que mais posso fazer por você?",,"Te-ai întors din nou, hă? Păi, măcar cunoști destule cât să rămâi întreg. Ce pot face pentru tine?","Снова ты? Ну что ж, ты хотя бы знаешь, как шкуру сберечь. Что я могу тебе предложить?",,"Tillbaka igen, va? Du vet åtminstone tillräckligt för att hålla ditt eget skinn intakt. Vad kan jag göra för dig nu?",Yine mi döndün? En azından kendi derini sağlam tutacak kadar biliyorsun. Şimdi senin için ne yapabilirim? +More info,TXT_RPLY0_SCRIPT33_D10612_MOREI,〃,,,Další informace,Mere info,Mehr Informationen.,,Pliaj informoj,Más información,,Lisää tietoa.,Plus d'infos.,Több információ.,Altre informazioni,話のネタ。,그 외의 정보를 줘.,Meer info,Mer info,Więcej informacji,Mais informações.,,Mai multă informație,Расскажи больше,,Mer information,Daha fazla bilgi +The Governor is a simple reminder of the Order's influence.,TXT_RYES0_SCRIPT33_D10612_THEGO,〃,,,Guvernér je jednoduchou připomínkou vlivu Řádu.,Guvernøren er en simpel påmindelse om Ordenens indflydelse.,Der Gouverneur ist eine einfache Erinnering an die Macht des Ordens.,,"La registo estas nur simbolo +pri la influo de La Ordeno.","El gobernador solo es un +símbolo de la influencia +de La Orden.",,Kuvernööri on selvä muistutus Veljeskunnan vaikutusvallasta.,Le gouverneur d'est qu'un rappel de l'influence de l'ordre.,A Kormányzó csak a Rend hatalmának bábja.,Il governatore è solo un simbolo dell'influenza dell'Ordine.,知事は俺達に自由はないと思い出させる象徴さ。,모렐 총독은 부정하고 짜증 나는 오더의 정권의 예야.,De gouverneur is een eenvoudige herinnering aan de invloed van de Orde.,Guvernøren er en enkel påminnelse om ordenens innflytelse.,Gubernator to proste przypomnienie o wpływach Zakonu.,O governador é um simples lembrete da influência da Ordem.,,Guvernatorul e o simplă reamintire a influenței Ordinului.,Губернатор — живое напоминание о власти Ордена.,,Guvernören är en enkel påminnelse om ordens inflytande.,"Vali, Tarikat'ın etkisinin basit bir hatırlatıcısıdır." +Come back if you change your mind.,TXT_RNO0_SCRIPT33_D10612_COMEB,〃,,,"Vrať se, pokud změníš názor.","Kom tilbage, hvis du skifter mening.","Komm zurück, wenn du deine Meinung geändert hast.",,"Revenu kiam +vi ŝanĝos ideon.",Vuelve si cambias de idea.,,"Puhutaan taas, jos tulet toisiin aatoksiin.",Revenez si vous changez d'avis.,Gyere vissza ha változik a véleményed.,Torna pure se cambi idea.,気が変わったら戻ってきな。,마음이 바뀌면 돌아와주게나.,Kom terug als u van gedachten verandert.,Kom tilbake hvis du ombestemmer deg.,"Wróć, jeśli zmienisz zdanie.",Volte quando mudar de idéia.,,Întoarce-te dacă te răzgândești.,Передумаешь — возвращайся.,,Kom tillbaka om du ändrar dig.,Fikrini değiştirirsen geri gel. +"Well, you're sure asking a lot of questions for someone who's lived this long. That's ok though, I'd rather talk to someone like you than most of this lot.",TXT_DLG_SCRIPT33_D12128_WELLY,〃,,,"Na někoho, kdo přežil takhle dlouho, se ptáš docela hodně. To je v pořádku, radši bych se bavil s tebou než s většinou těhle lidí.","Du stiller virkelig mange spørgsmål af en, der har levet så længe. Det er dog ok, jeg vil hellere tale med en som dig end med de fleste af dem her.","Du stellst eine Menge Fragen für jemanden, der schon so lange überlebt hat. Das ist ok, ich rede lieber mit jemandem wie dir als mit dem Rest der Typen da.",,"Nu, vi sendube faras multe da demandoj, kvankam vi vivis tiel longe. Mi ne plendas, mi preferus paroli kun iu kiel vi anstataŭ la ĉi-tiea plimulto.","Bueno, ciertamente estás haciendo muchas preguntas para alguien que ha vivido tanto. Aunque eso es bueno, preferiría hablar con alquien como tú que con la mayoría de esta gente.",,"No, kyllläpä paljon kyselet sellaiseksi, joka näin pitkään on hengissä säilynyt. Mutta ei se mitään; mieluummin puhun jonkun sinun kaltaisesi kuin suurimman osan kanssa tätä porukkaa.","Vous posez beacoup de questions pour quelqu'un qui a survécu aussi longtemps. Ca me convient, je préfère parler à quelqu'un comme vous qu'a la majorité de ces idiots.","Ahhoz képest, hogy eddig éltél, elég sok kédést teszel fel. Igazából nem probléma, szívesebben beszélek veled mint mással itt.","Beh, fai davvero tante domande, per uno che è ancora vivo. Ma a me sta bene, molto meglio parlare con te rispetto agli altri che stanno qui...","所で、アンタは死に行かない人達に 聞き回ってる様だが。悪いことは言わねえ、 -あんまし死に急ぐんじゃねえぞ。","아주 오래 살아서 배짱이 두둑한가, 다시 돌아와 줬구먼! 나야말로 괜찮다네. 이 주정부리들 보다 자네랑 대화하는 게 그나마 낫지.","Nou, je stelt zeker veel vragen aan iemand die zo lang heeft geleefd. Maar dat is niet erg, ik praat liever met iemand zoals jij dan met de meeste van deze mensen.",,"Bem, para alguém que conseguiu viver bastante você certamente faz muitas perguntas. Mas tudo bem, eu prefiro conversar com alguém como você do que com a maioria destes caras.",,,"Да, для человека, который прожил так долго, ты задаёшь многовато вопросов. Впрочем, это неплохо: я бы скорее предпочёл говорить с кем-то вроде тебя, чем с местными.", -More info.,TXT_RPLY0_SCRIPT33_D12128_MOREI,,,,Další informace,Mehr Informationen.,,,Más información.,,,Plus d'infos.,,,話のネタ。,더 많은 정보를 줘.,Meer info.,,Mais informações.,,,Говори дальше., -There's more to the Order than what goes on around here.,TXT_RYES0_SCRIPT33_D12128_THERE,,,,"Za Řádem se toho skrývá víc, než tady vidíš.","Hinter dem Orden steckt mehr, als es den Anschein hat.",,,Hay más de la Orden que lo que pasa por aquí.,,,L'Ordre cache beaucoup plus que ce qui ne se passe ici.,,,オーダーは見えてる以上に強大だ。,여기저기 퍼지는 소문보다 오더가 지키는 비밀이 더 깊숙하다네.,De Orde heeft meer te bieden dan wat er hier gebeurt.,,Há mais sobre a Ordem do que acontece por aqui.,,,"Орден — нечто большее, чем кажется.", -Come back if you change your mind.,TXT_RNO0_SCRIPT33_D12128_COMEB,,,,"Vrať se, pokud změníš názor.","Komm zurück, wenn du deine Meinung geändert hast.",,,Vuelve si cambias de idea.,,,Revenez si vous changez d'avis.,,,気が変わったら戻ってきな。,생각이 바뀌면 다시 돌아오게나.,Kom terug als je van gedachten verandert.,,Volte quando mudar de idéia.,,,Передумаешь — возвращайся., -"That's it friend, the well of knowledge has been tapped. I've told you more than I should have anyway.",TXT_DLG_SCRIPT33_D13644_THATS,,,,"A to je vše, příteli, studnice mé moudrosti vyschla. Stejně jsem ti řekl víc, než jsem měl.","Das ist es, Freund, der Brunnen des Wissens ist versiegt. Ich habe dir schon mehr gesagt, als ich eigentlich sollte.",,,"Ya está amigo, el pozo del conocimiento se ha secado. Te he dicho más de lo que debería, de todos modos.",,,"C'est tout, mon ami. Le puits de la sagesse s'est tari. Je vous en ai trop dit de toutes manières.",,,"これはこれは親友、心得の瓶は切らしてるぞ。 -とにかく俺が知ってる話はこれで全部だ。",이게 다일세. 내가 친히 줄 수 있는 조언이라는 이름의 술은 다 줬다네.,"Dat is het vriend, de bron van kennis is aangeboord. Ik heb je meer verteld dan ik toch al zou moeten hebben.",,"É isso, amigo. O poço de conhecimento já secou. Já te contei mais do que eu deveria, de qualquer forma.",,,"Это всё, дружище. Кладезь мудрости исчерпан. Я и так рассказал тебе больше, чем следовало.", -Hard to shop for new toys... when you're broke. Run a little errand for me and you'll get more than you could ever spend. I'll make you a rich man.,TXT_DLG_SCRIPT33_D15160_HARDT,,,,"Nové hračky se shánějí jen těžko... když jsi švorc. Udělej pro mě malou prácičku a dostaneš víc, než kolik bys mohl kdy utratit. Udělám z tebe boháče.","Ist es nicht schwierig, an neue Sachen zu kommen, wenn du pleite bist? Tu mir einen Gefallen und du kannst mehr Gold kriegen, als du jemals ausgeben kannst. Ich mache dich reich.",,,Difícil comprarse nuevos jugetes... cuando estás sin blanca. Haz algunos recados para mi y conseguirás más de lo que puedas gastarte. Te haré un hombre rico.,Difícil comprarse nuevos jugetes... cuando estás quebrado. Haz algunos encargos para mi y conseguirás más de lo que puedas gastarte. Te haré un hombre rico.,,Difficile de s'acheter de nouveaux joujous quand on n'a plus de sous. Faites-moi une petite course et vous aurez plus que vous ne pourrez jamais dépenser. Je vous rendrai riche.,,,"新しい玩具も買えないぐらい...貧しそうだな +あんまし死に急ぐんじゃねえぞ。","아주 오래 살아서 배짱이 두둑한가, 다시 돌아와 줬구먼! 나야말로 괜찮다네. 이 주정부리들 보다 자네랑 대화하는 게 그나마 낫지.","Nou, je stelt zeker veel vragen aan iemand die zo lang heeft geleefd. Maar dat is niet erg, ik praat liever met iemand zoals jij dan met de meeste van deze mensen.","Du stiller mange spørsmål til å være en som har levd så lenge. Men det er greit, jeg vil heller snakke med en som deg enn de fleste av disse.","Zadajesz dużo pytań jak na kogoś, kto żyje tak długo. W porządku. Wolę rozmawiać z kimś takim jak ty niż z większością tych ludzi.","Bem, para alguém que conseguiu viver bastante você certamente faz muitas perguntas. Mas tudo bem, eu prefiro conversar com alguém como você do que com a maioria destes caras.",,"Păi, cu sigranță pui multe întrebări pentru cineva care a trăit atât. E în regulă însă, prefer să vorbesc cu cineva ca tine decât cu grămada asta.","Да, для человека, который прожил так долго, ты задаёшь многовато вопросов. Впрочем, это неплохо: я бы скорее предпочёл говорить с кем-то вроде тебя, чем с местными.",,"Du ställer verkligen många frågor för någon som har levt så här länge. Men det är okej, jag pratar hellre med någon som dig än med de flesta av de här.","Bu kadar uzun yaşamış biri için çok fazla soru soruyorsun. Yine de sorun değil, buradakilerin çoğuyla konuşmaktansa senin gibi biriyle konuşmayı tercih ederim." +More info.,TXT_RPLY0_SCRIPT33_D12128_MOREI,〃,,,Další informace,Mere info.,Mehr Informationen.,,Pliaj informoj.,Más información.,,Lisää tietoa.,Plus d'infos.,Több információ.,Altre informazioni,話のネタ。,더 많은 정보를 줘.,Meer info.,Mer informasjon.,Więcej informacji.,Mais informações.,,Mai multă informație.,Говори дальше.,,Mer information.,Daha fazla bilgi. +There's more to the Order than what goes on around here.,TXT_RYES0_SCRIPT33_D12128_THERE,〃,,,"Za Řádem se toho skrývá víc, než tady vidíš.","Der er mere i Ordenen end det, der foregår her.","Hinter dem Orden steckt mehr, als es den Anschein hat.",,"Estas pli pri La Ordeno +ol tio, kio okazas ĉi tie.","Hay más de La Orden +que lo que pasa por aquí.",,"Veljeskunnan toiminta ei rajoitu vain siihen, mitä täällä tapahtuu.",L'Ordre cache beaucoup plus que ce qui ne se passe ici.,"A Rend mögött több áll, mint amit az emberek pletykálnak.",C'è sotto molto di più sull'Ordine rispetto a quello che succede qua.,オーダーは見えてる以上に強大だ。,여기저기 퍼지는 소문보다 오더가 지키는 비밀이 더 깊숙하다네.,De Orde heeft meer te bieden dan wat er hier gebeurt.,Ordenen er mer enn bare det som foregår her.,"Zakon to coś więcej niż to, co dzieje się tutaj.",Há mais sobre a Ordem do que acontece por aqui.,,Sunt mai multe lucruri care țin de Ordin decât ceea ce se petrece în jur.,"Орден — нечто большее, чем кажется.",,Det finns mer i Orden än vad som händer här.,Tarikat'ta burada olanlardan daha fazlası var. +Come back if you change your mind.,TXT_RNO0_SCRIPT33_D12128_COMEB,〃,,,"Vrať se, pokud změníš názor.","Kom tilbage, hvis du skifter mening.","Komm zurück, wenn du deine Meinung geändert hast.",,"Revenu kiam +vi ŝanĝos ideon.",Vuelve si cambias de idea.,,"Jos muutat mielesi, palataan asiaan.",Revenez si vous changez d'avis.,"Gyere vissza, ha meggondoltad magad.",Ritorna semmai cambi idea.,気が変わったら戻ってきな。,생각이 바뀌면 다시 돌아오게나.,Kom terug als je van gedachten verandert.,Kom tilbake hvis du ombestemmer deg.,"Wróć, jeśli zmienisz zdanie.",Volte quando mudar de idéia.,,Întoarce-te dacă te răzgândești.,Передумаешь — возвращайся.,,Kom tillbaka om du ändrar dig.,Fikrini değiştirirsen geri gel. +"That's it friend, the well of knowledge has been tapped. I've told you more than I should have anyway.",TXT_DLG_SCRIPT33_D13644_THATS,〃,,,"A to je vše, příteli, studnice mé moudrosti vyschla. Stejně jsem ti řekl víc, než jsem měl.","Det var det, min ven, vidensbrønden er blevet tappet. Jeg har alligevel fortalt dig mere, end jeg burde have gjort.","Das ist es, Freund, der Brunnen des Wissens ist versiegt. Ich habe dir schon mehr gesagt, als ich eigentlich sollte.",,"Jen ĉio, amiko, la fonto de scio sekiĝis. Malgraŭ tio, mi diris al vi pli ol tiom, kiom mi devus.","Ya está, amigo, el pozo del conocimiento ya se ha secado. De todas formas ya te he dicho más de lo que debería.","Ya está, amigo, el pozo del conocimiento ya se secó. De todas formas ya te dije más de lo que debería.","Siinä kaikki, ystävä. Tiedon lähde on ehtynyt. Olen kertonut sinulle joka tapauksessa enemmän kuin olisi pitänytkään.","C'est tout, mon ami. Le puits de la sagesse s'est tari. Je vous en ai trop dit de toutes manières.","Ennyi volt barátom, a tudás forrása elapadt. Már így is többet mondtam a kelleténél.","È tutto, amico, ho esaurito le cose che avevo da dirti. Ti ho già detto più di quanto avrei dovuto.","これはこれは親友、心得の瓶は切らしてるぞ。 +とにかく俺が知ってる話はこれで全部だ。",이게 다일세. 내가 친히 줄 수 있는 조언이라는 이름의 술은 다 줬다네.,"Dat is het vriend, de bron van kennis is aangeboord. Ik heb je meer verteld dan ik toch al zou moeten hebben.","Det var det, min venn. Kunnskapens brønn er tappet. Jeg har fortalt deg mer enn jeg burde uansett.","To wszystko przyjacielu, studnia wiedzy została wyczerpana. I tak powiedziałem ci więcej niż powinienem.","É isso, amigo. O poço de conhecimento já secou. Já te contei mais do que eu deveria, de qualquer forma.",,"Gata prietene, fântâna a secat. Ți-am spus mai multe decât ar fi trebuit oricum.","Это всё, дружище. Кладезь мудрости исчерпан. Я и так рассказал тебе больше, чем следовало.",,"Det var allt, min vän, kunskapens källa har blivit tömd. Jag har berättat mer än jag borde ha gjort i alla fall.","Bu kadar dostum, bilgi kuyusu doldu. Zaten sana söylemem gerekenden fazlasını söyledim." +Hard to shop for new toys... when you're broke. Run a little errand for me and you'll get more than you could ever spend. I'll make you a rich man.,TXT_DLG_SCRIPT33_D15160_HARDT,MAP33: Harris (beginning).,,,"Nové hračky se shánějí jen těžko... když jsi švorc. Udělej pro mě malou prácičku a dostaneš víc, než kolik bys mohl kdy utratit. Udělám z tebe boháče.","Det er svært at købe nyt legetøj, når man er flad. Gør et lille ærinde for mig, og du vil få mere, end du nogensinde vil kunne bruge. Jeg vil gøre dig til en rig mand.","Ist es nicht schwierig, an neue Sachen zu kommen, wenn du pleite bist? Tu mir einen Gefallen und du kannst mehr Gold kriegen, als du jemals ausgeben kannst. Ich mache dich reich.",,"Estas malfacile aĉeti novajn ludilojn... kiam oni estas senmona. Plenumu simplan komision por mi kaj vi gajnos pli ol tiom, kiom oni povus eĉ elspezi: mi faros vin riĉulo.",Difícil comprarse nuevos juguetes... cuando se está sin blanca. Haz un recado para mí y ganarás más de lo que puedas gastarte: te haré un hombre rico.,Difícil comprarse nuevos juguetes... cuando se está pobre. Haz un encargo para mí y vas a ganar más de lo que puedas gastarte: te voy a hacer un hombre rico.,"Vaikea ostaa uusia leluja, kun on peeaa. Käytkö hoitamassa minulle yhden asian, niin tienaat enemmän kuin pystyt ikinä kuluttamaan. Teen sinusta kroisoksen.",Difficile de s'acheter de nouveaux joujous quand on n'a plus de sous. Faites-moi une petite course et vous aurez plus que vous ne pourrez jamais dépenser. Je vous rendrai riche.,"Nehéz úgy új játékszereket beszerezni, ha ennyire nincs pénzed. Viszont ha megteszel nekem egy szívességet, annyi pénzed lesz amit el se tudsz költeni. Gazdaggá teszlek.","È difficile comprare nuovi giocattoli... quando non hai la grana. Se fai un piccolo favore per me, potrai avere così tanti soldi da non sapere come spenderli. Ti renderò un uomo molto ricco.","新しい玩具も買えないぐらい...貧しそうだな アンタ。良い儲け話があるぜ。 -俺のちょっとした仕事でガッポガポだぞ。",여기저기 장난감을 살려면 돈이 필요하지. 세상에 공짜가 어디 있나? 내 심부름을 좀 하다 보면 용돈도 생기고 부자가 될 걸세. 어떤가?,Moeilijk om nieuw speelgoed te kopen.... als je blut bent. Doe een kleine boodschap voor me en je krijgt meer dan je ooit zou kunnen uitgeven. Ik zal je een rijk man maken.,,"É difícil comprar brinquedos novos... quando você está duro. Se você fizer um favor pra mim, você vai ganhar mais do que jamais conseguiria gastar. Vou fazer de você um homem rico.",,,"Трудновато покупать игрушки, когда нет и гроша за душой... Выполни одно заданьице для меня, и ты заработаешь столько, сколько в твоих карманах сроду не водилось. Ты будешь богатым!", -I got nothing better to do.,TXT_RPLY0_SCRIPT33_D15160_IGOTN,,,,Nemám nic lepšího na práci.,Ich habe nichts besseres zu tun.,,,No tengo nada mejor que hacer.,,,Je n'ai rien de mieux à faire.,,,何もしないよりはいいか。,저는 할 것이 아무것도 없어요.,Ik heb niets beters te doen.,,Não tenho nada melhor pra fazer.,,,Заманчивое предложение., -No thanks.,TXT_RPLY1_SCRIPT33_D15160_NOTHA,,,,"Ne, díky.","Nein, danke.",,,No gracias.,,,Non merci.,,,いらない。,아뇨 괜찮습니다.,"Nee, bedankt.",,Não obrigado.,,,"Нет, спасибо.", -Nobody walks away from me!,TXT_RYES1_SCRIPT33_D15160_NOBOD,,,,Ode mě nikdo neodchází!,Niemand sagt Nein zu mir.,,,¡Nadie pasa de mí!,¡Nadie se aleja de mí!,,Personne ne se barre après mon offre!,,,俺から逃げられると思ってるのか!,그 누구도 나를 거절할 수 없어!,Niemand loopt weg van mij!,,Ninguém me ignora!,,,От меня ещё никто не уходил!, -"Good choice. The Order's sanctuary by the river is their unofficial torture chamber. Hidden inside there's a golden chalice. You swipe it, you meet me at the tavern, and reap your reward.",TXT_DLG_SCRIPT33_D16676_GOODC,,,,"Dobrá volba. Svatyně Řádu u řeky je jejich neoficiální mučírna. Uvnitř je skrytý zlatý kalich. Sebereš ho, sejdeš se se mnou v taverně a vyzvedneš si svou odměnu.",Gute Wahl. Das Heiligtum des Ordens bei dem Fluss ist ihre inoffiziele Folterkammer. Darin versteckt ist ein goldener Kelch. Du klaust ihn und erntest deinen Lohn.,,,"Buena elección. El santuario de la Orden junto al río es su cámara de tortura no oficial. Oculto adentro hay un cáliz de oro. Lo robas, me vienes a ver a la taberna, y consigues tu recompensa.",,,Bon choix. Le sanctuaire de l'ordre près de la rivière est leur chambre torture.. officieusement. A l'intérieur se trouve un calice en or. Récupérez le et venez prendre votre récompense.,,,"良い判断だ。川沿いにある オーダーの聖域 は +俺のちょっとした仕事でガッポガポだぞ。",여기저기 장난감을 살려면 돈이 필요하지. 세상에 공짜가 어디 있나? 내 심부름을 좀 하다 보면 용돈도 생기고 부자가 될 걸세. 어떤가?,Moeilijk om nieuw speelgoed te kopen.... als je blut bent. Doe een kleine boodschap voor me en je krijgt meer dan je ooit zou kunnen uitgeven. Ik zal je een rijk man maken.,"Vanskelig å kjøpe nye leker... når man er blakk. Gjør et lite ærend for meg, så får du mer enn du kan bruke. Jeg skal gjøre deg rik.","Trudno jest kupować nowe zabawki... kiedy jest się spłukanym. Zrób dla mnie małe zlecenie, a dostaniesz więcej niż mógłbyś kiedykolwiek wydać. Zrobię z ciebie bogatego człowieka.","É difícil comprar brinquedos novos... quando você está duro. Se você fizer um favor pra mim, você vai ganhar mais do que jamais conseguiria gastar. Vou fazer de você um homem rico.",,Greu să cumperi jucarii noi... când ești falit. Dar faci o mică treabă pentru mine și o să fii putred de bogat.,"Трудновато покупать игрушки, когда нет и гроша за душой... Выполни одно заданьице для меня, и ты заработаешь столько, сколько в твоих карманах сроду не водилось. Ты будешь богатым!",,Svårt att handla nya leksaker när man är pank. Gör ett litet ärende åt mig och du får mer än du någonsin kan spendera. Jag gör dig till en rik man.,"Beş parasızken yeni oyuncaklar için alışveriş yapmak zor. Benim için ufak bir iş yaparsan, harcayabileceğinden fazlasını alırsın. Seni zengin bir adam yapacağım." +I got nothing better to do.,TXT_RPLY0_SCRIPT33_D15160_IGOTN,〃,,,Nemám nic lepšího na práci.,Jeg har intet bedre at lave.,Ich habe nichts besseres zu tun.,,Mi havas nenian farindaĵon.,No tengo nada mejor que hacer.,,Ei minulla parempaakaan tekemistä ole.,Je n'ai rien de mieux à faire.,Nincs jobb dolgom úgy sem.,Non ho di meglio da fare.,何もしないよりはいいか。,저는 할 것이 아무것도 없어요.,Ik heb niets beters te doen.,Jeg har ikke noe bedre å gjøre.,Nie mam nic lepszego do roboty.,Não tenho nada melhor pra fazer.,,N-am nimic mai bun de făcut.,Заманчивое предложение.,,Jag har inget bättre att göra.,Yapacak daha iyi bir işim yok. +No thanks.,TXT_RPLY1_SCRIPT33_D15160_NOTHA,〃,,,"Ne, díky.",Nej tak.,"Nein, danke.",,"Ne, dankon.","No, gracias.",,Ei kiitos.,Non merci.,Nem kösz.,No grazie.,いらない。,아뇨 괜찮습니다.,"Nee, bedankt.",Ellers takk.,"Nie, dziękuję.","Não, obrigado.",,Nu merci.,"Нет, спасибо.",,Jag har inget bättre för mig.,"Hayır, teşekkürler." +Nobody walks away from me!,TXT_RYES1_SCRIPT33_D15160_NOBOD,〃,,,Ode mě nikdo neodchází!,Ingen går væk fra mig!,Niemand sagt Nein zu mir.,,Neniu preterpasas min!,¡Nadie pasa de mí!,,Kukaan ei käännä selkäänsä minulle!,Personne ne se barre après mon offre!,Senki sem sétál el előlem!,Nessuno fa l'impertinente con me!,俺から逃げられると思ってるのか!,그 누구도 나를 거절할 수 없어!,Niemand loopt weg van mij!,Ingen går fra meg!,Nikt ode mnie nie odchodzi!,Ninguém me ignora!,,Nimeni nu scapă de mine!,От меня ещё никто не уходил!,,Ingen går ifrån mig!,Kimse benden kaçamaz! +"Good choice. The Order's sanctuary by the river is their unofficial torture chamber. Hidden inside there's a golden chalice. You swipe it, you meet me at the tavern, and reap your reward.",TXT_DLG_SCRIPT33_D16676_GOODC,〃,,,"Dobrá volba. Svatyně Řádu u řeky je jejich neoficiální mučírna. Uvnitř je skrytý zlatý kalich. Sebereš ho, sejdeš se se mnou v taverně a vyzvedneš si svou odměnu.","Godt valg. Ordenens fristed ved floden er deres uofficielle torturkammer. Der er en gylden bæger gemt derinde. Du tager den, du møder mig på kroen og høster din belønning.",Gute Wahl. Das Heiligtum des Ordens bei dem Fluss ist ihre inoffiziele Folterkammer. Darin versteckt ist ein goldener Kelch. Du klaust ihn und erntest deinen Lohn.,,Bona elekto. La sanktejo de La Ordeno ĉe la rojo estas ĝia neoficiala torturejo. En ĝi estas kaŝita ora kaliko. Portu ĝin al mi en la taverno kaj vi havos rekompencon.,"Buena elección. El santuario de La Orden junto al arroyo es su cámara de tortura extraoficial. Dentro hay un cáliz dorado escondido. Cógelo, llévamelo a la taberna y tendrás tu recompensa.","Buena elección. El santuario de La Orden junto al río es su cámara de tortura extraoficial. Adentro hay un cáliz dorado escondido. Si lo tomas y me lo llevas a la taberna, tu recompensa.","Viisas päätös. Veljeskunnan pyhäkkö joen varrella on heidän epävirallinen kidutuskammionsa, jonka kätköissä piilee kultakalkki. Kähvellä se ja saat vaivannäöstäsi palkan.",Bon choix. Le sanctuaire de l'ordre près de la rivière est leur chambre torture.. officieusement. A l'intérieur se trouve un calice en or. Récupérez le et venez prendre votre récompense.,"Jó választás. A Rend folyó melletti szentélye valójában a nem hivatalos kínzó kamrájuk. Elrejtve belül található egy arany serleg. Csend el szépen, és a kocsmánál találkozunk, lepasszolom a jutalmad.",Ottima scelta. Il santuario dell'Ordine vicino al fiume è la loro camera della tortura. Vi è un calice d'oro nascosto là dentro. Prendilo e avrai una lauta ricompensa.,"良い判断だ。川沿いにある オーダーの聖域 は あいつらの非公式の拷問室だ。 中には黄金の聖杯が隠してある。 そいつを持ってくれば報酬をやるぜ。 -",좋은 선택이야. 강가 근처에 있는 성소가 바로 오더의 비공식적인 고문실이야. 그리고 그 안에는 숨겨진 금색 성배가 있지. 넌 그것을 훔치고 여기 선술집으로 와서 보상을 받으면 돼.,"Goede keuze. Het heiligdom van de Orde bij de rivier is hun onofficiële martelkamer. Verborgen in de kelk zit een gouden kelk. Je haalt hem weg, je komt me tegen in de herberg, en plukt je beloning.",,"Boa escolha. O santuário da Ordem próximo ao rio é a câmara de tortura não oficial deles. Dentro dele há um cálice dourado. Pegue-o, me encontre na taverna e pegue sua recompensa.",,,"Правильный выбор. В святилище Ордена у реки — там у них негласная камера пыток — спрятана золотая чаша. Ты крадёшь её, возвращаешься ко мне в таверну и получаешь свою награду.", -How am I supposed to do that?,TXT_RPLY0_SCRIPT33_D16676_HOWAM,,,,Jak to mám udělat?,Wie soll ich das anstellen?,,,¿Cómo se supone que hago eso?,,,Comment est-ce que je suis sensé faire ça?,,,どうすればいいんだ?,어떻게 하면 되나요?,Hoe moet ik dat doen?,,Como vou conseguir fazer isso?,,,Как мне это сделать?, -Let me think about it.,TXT_RPLY1_SCRIPT33_D16676_LETME,,,,Nech mě o tom popřemýšlet.,Lass mich darüber nachdenken.,,,Déjame pensarlo.,,,Laissez-moi y réfléchir.,,,ちょっと考えとく。,좀 생각해 보겠습니다.,Laat me erover nadenken.,,Vou pensar sobre isso.,,,Я подумаю над твоим предложением., -"Sorry, no second chances. Oh, guards, kill him!",TXT_RYES1_SCRIPT33_D16676_SORRY,,,,"Promiň, žádné druhé šance. A, stráže, zabte ho!","Keine zweite Chance. Oh Wachen, tötet ihn.",,,"Lo siento, no hay segundas oportunidades. Oh, guardias, ¡Mátenlo!",,,"Pas de deuxième chance. Gardes, tuez-le.",,,"残念、次はねえよ。おぅガードの旦那、 -やっちゃってくだせえ。","유감. 두 번째 기회는 없어. 경비원, 저놈을 죽여.","Sorry, geen tweede kans. Oh, bewakers, dood hem!",,"Sinto muito, nada de segundas chances. Ah, guardas, matem-no!",,,"Нет, никакого второго шанса. Эй, стража, убейте его.", -"Here's a crossbow, just aim straight and -- splat!--. Remember, grab the fancy cup and meet me at the tavern.",TXT_DLG_SCRIPT33_D18192_HERES,,,,"Tady je kuše, prostě rovně zamiř a --plesk!--. Nezapomeň, vem fešný hrnek a najdi mě v taverně.","Hier ist eine Armbust, einfach gerade zielen und --Platsch--. Denk dran, schnapp dir den schicken Kelch und dann ab zur Taverne.",,,"Toma una ballesta, solo apunta derecho y -- ¡splat! --. Recuerda, toma la copa bonita y ven a verme a la taberna.",,,Voilà une arbalète. Vous avez juste à viser droit et paf! Souvenez-vous. Prenez le goblet et ramenez le à la taverne.,,,"このクロスボウを使いな、狙いを定めて +",좋은 선택이야. 강가 근처에 있는 성소가 바로 오더의 비공식적인 고문실이야. 그리고 그 안에는 숨겨진 금색 성배가 있지. 넌 그것을 훔치고 여기 선술집으로 와서 보상을 받으면 돼.,"Goede keuze. Het heiligdom van de Orde bij de rivier is hun onofficiële martelkamer. Verborgen in de kelk zit een gouden kelk. Je haalt hem weg, je komt me tegen in de herberg, en plukt je beloning.","Godt valg. Ordenens helligdom ved elven er deres uoffisielle torturkammer. Gjemt der inne er det et gyllent beger. Du stjeler det, møter meg på vertshuset og høster belønningen din.","Dobry wybór. Sanktuarium Zakonu nad rzeką jest ich nieoficjalną salą tortur. W środku jest ukryty złoty kielich. Machniesz nim, spotkasz się ze mną w tawernie i odbierzesz swoją nagrodę.","Boa escolha. O santuário da Ordem próximo ao rio é a câmara de tortura não oficial deles. Dentro dele há um cálice dourado. Pegue-o, me encontre na taverna e pegue sua recompensa.",,"Bună alegere. Sanctuarul Ordinului de lângă râu e lagărul lor neoficial. Ascuns înăuntru e un potir. Îl înșfaci, mă găsești la tavernă, și îți iei răsplata.","Правильный выбор. В святилище Ордена у реки — там у них негласная камера пыток — спрятана золотая чаша. Ты крадёшь её, возвращаешься ко мне в таверну и получаешь свою награду.",,"Bra val. Ordens helgedom vid floden är deras inofficiella tortyrkammare. Gömd inuti finns en gyllene bägare. Du tar den, möter mig på tavernan och skördar din belöning.","İyi seçim. Tarikat'ın nehir kenarındaki sığınağı onların gayri resmi işkence odası. İçinde altın bir kadeh saklı. Onu çalacaksın, benimle tavernada buluşacaksın ve ödülünü alacaksın." +How am I supposed to do that?,TXT_RPLY0_SCRIPT33_D16676_HOWAM,〃,,,Jak to mám udělat?,Hvordan skal jeg gøre det?,Wie soll ich das anstellen?,,Kiel mi supozeble faru tion?,¿Cómo se supone que debo hacer eso?,,Miten minä muka sen teen?,Comment est-ce que je suis sensé faire ça?,Hogyan kéne ezt véghezvinnem?,E come posso fare tutto ciò?,どうすればいいんだ?,어떻게 하면 되나요?,Hoe moet ik dat doen?,Hvordan skal jeg gjøre det?,Jak mam to zrobić?,Como vou conseguir fazer isso?,,Cum ar trebui să fac asta?,Как мне это сделать?,,Hur ska jag göra det?,Bunu nasıl yapacağım? +Let me think about it.,TXT_RPLY1_SCRIPT33_D16676_LETME,〃,,,Nech mě o tom popřemýšlet.,Lad mig tænke over det.,Lass mich darüber nachdenken.,,Mi pensu.,Déjame pensarlo.,,Anna minun pohtia asiaa.,Laissez-moi y réfléchir.,Hadd gondolkozzak.,Ci penso un po' su e poi ti farò sapere.,ちょっと考えとく。,좀 생각해 보겠습니다.,Laat me erover nadenken.,La meg tenke på det.,Pozwól mi się zastanowić.,Vou pensar sobre isso.,,Lasă-mă să mă gândesc.,Я подумаю над твоим предложением.,,Låt mig tänka på det.,Bir düşüneyim. +"Sorry, no second chances. Oh, guards, kill him!",TXT_RYES1_SCRIPT33_D16676_SORRY,〃,,,"Promiň, žádné druhé šance. A, stráže, zabte ho!","Beklager, ingen anden chance. Åh, vagter, dræb ham!","Keine zweite Chance. Oh Wachen, tötet ihn.",,"Pardonon, ne estas alia ŝanco. Gardistoj, mortigu lin!","Lo siento, no hay otra oportunidad. ¡Guardias, matadlo!","Lo siento, no hay otra oportunidad. ¡Guardias, mátenlo!","Pahoittelut, ei toista mahdollisuutta. Vartijat, tappakaa hänet.","Pas de deuxième chance. Gardes, tuez-le.","Bocs, de második esély már nincs. Őrök, végezzétek ki!","Nessuna seconda chance. Guardie, uccidetelo.","残念、次はねえよ。おぅガードの旦那、 +やっちゃってくだせえ。","유감. 두 번째 기회는 없어. 경비원, 저놈을 죽여.","Sorry, geen tweede kans. Oh, bewakers, dood hem!","Beklager, ingen nye sjanser. Vakter, drep ham!","Przykro mi, nie ma drugiej szansy. Och, strażnicy, zabijcie go!","Sinto muito, nada de segundas chances. Ah, guardas, matem-no!",,"Oh, nicio altă șansă. Gardienilor, omorâți-l.","Нет, никакого второго шанса. Эй, стража, убейте его.",,"Tyvärr, inga andra chanser. Vakter, döda honom!","Üzgünüm, ikinci bir şans yok. Muhafızlar, öldürün onu!" +"Here's a crossbow, just aim straight and -- splat!--. Remember, grab the fancy cup and meet me at the tavern.",TXT_DLG_SCRIPT33_D18192_HERES,〃,,,"Tady je kuše, prostě rovně zamiř a --plesk!--. Nezapomeň, vem fešný hrnek a najdi mě v taverně.","Her er en armbrøst, bare sigt lige ud og -- splat!--. Husk, tag den fine kop og mød mig på kroen.","Hier ist eine Armbust, einfach gerade zielen und --Platsch--. Denk dran, schnapp dir den schicken Kelch und dann ab zur Taverne.",,Jen arbalesto. Vi nur celu laŭ rekta linio kaj «pum». Ne forgesu preni la belan pokalon kaj tiam renkonti min en la taverno.,Aquí tengo una ballesta. Solo apunta en línea recta y «plaf». Recuerda: toma la bonita copa y luego ve a verme a la taberna.,,"Tässä sinulle jousipyssy; tähtää vain eteenpäin ja ""pläts""! Tärkeintä vain, että muistat kahmaista fiinin maljan ja sitten palata kapakkaan.",Voilà une arbalète. Vous avez juste à viser droit et paf! Souvenez-vous. Prenez le goblet et ramenez le à la taverne.,"Itt egy íj, csak célozz egyenesen és -- bumm!--. És emlékezz: hozdd el a díszes serleget nekem a kocsmába.","Ecco una balestra, basta mirare e --splat--. Ricorda, prendi il calice e ritorna alla taverna.","このクロスボウを使いな、狙いを定めて --シュッとな。覚えておけ、 -ファンシーなカップを持ってここに戻ってくると。","여기 석궁이야, 똑바로 겨냥해, 그리고... '철퍼덕'. 기억해, 멋진 컵을 들고 이 곳으로 다시 와.","Hier is een kruisboog, richt gewoon recht en -- splat! --. Vergeet niet, pak de mooie beker en ontmoet me in de herberg.",,"Pegue esta besta. Só mirar direito e splat! Lembre-se, pegue o copo bonitinho e me encontre na taverna.",,,Вот арбалет — просто прицеливаешься и «шлеп!» Запомни — хватаешь чашку и возвращаешься в таверну., -I'll see you there.,TXT_RPLY0_SCRIPT33_D18192_ILLSE,,,,Uvidíme se tam.,Wir sehen uns dort.,,,Te veré allí.,,,Je vous y verrais.,,,また会おう。,거기서 보자고.,Ik zie je daar.,,Te vejo lá.,,,Я вернусь с чашей., -"What are you waiting for? Don't worry, I'll clean up the bodies, just bring me that chalice!",TXT_DLG_SCRIPT33_D19708_WHATA,,,,"Na co čekáš? Neboj, mrtvol se zbavím já, prostě mi přines ten kalich!","Worauf wartest du noch? Keine Sorge, ich kümmere mich um die Leichen. Bring mir den Kelch.",,,"¿Qué estás esperando? No te preocupes, me desharé de los cuerpos, ¡solo tráeme ese cáliz!",,,"Qu'attendez vous? Je m'occuperai des corps, ne vous inquiétez pas. Apportez-moi le calice!",,,"何ボーっとしてんだ? 心配すんな、 -チャッチャと片付けて聖杯を持ってこい!","뭘 기다리는 거야? 걱정하지 마, 내가 시체들을 치워줄 테니. 그냥 성배를 가져와!","Waar wacht je nog op? Maak je geen zorgen, ik ruim de lichamen op, breng me gewoon die kelk!",,"O que está esperando? Não se preocupe, eu limpo os corpos. Apenas me traga aquele cálice!",,,Чего ты ждёшь? Не беспокойся — я сам избавлюсь от трупов. Просто принеси мне чашу!, -Guards! Kill the traitor!,TXT_DLG_SCRIPT33_D21224_GUARD,,,,Stráže! Zabte toho zrádce!,Wächter! Tötet den Verräter!,,,¡Guardias! ¡Maten al traidor!,,,Gardes! Tuez ce traître!,,,ガード! 裏切者を殺せ!,경비! 반역자를 죽여라!,Bewakers! Dood de verrader!,,Guardas! Matem esse traidor!,,,Стража! Убейте предателя!, -"Hey, I know what you're thinking, kinda looks like a setup, I would never do that to such a killing machine, I mean it. Whew, all this fuss over a cup, weird. Now get ready, gold and glory, like I promised. Take this key and the Governor himself will reward you.",TXT_DLG_SCRIPT33_D22740_HEYIK,,,,"Hej, vím co si myslíš, tohle vypadá jako bouda. Takovému stroji na zabíjení bych nic takového neudělal, vážně! Páni, takový povyk kvůli hrnečku, divný. Tak teď se připrav, zlato a sláva, jak jsem slíbil. Vem si tenhle klíč a sám guvernér tě odmění.","Hey, ich weiß, es sieht anscheinend wie eine Falle aus, aber so etwas würde ich einer so großeartigen Tötungsmaschine nicht antun. Hast du ddas Ding? Großartig! Nun mach dich bereit, Geld und Ruhm, genau wie ich es dir versprochen habe. Nimm diesen Schlüssel und der Gouverneur wird dich belohnen.",,,"Hey, sé lo que estás pensando, parece un timo, pero nunca haría algo así a tal máquina de matar, lo juro. Uf, todo este lío por una copa, que raro. Ahora prepárate, oro y gloria, tal y como prometí. Toma esta llave y el mismísimo gobernador te recompensará.",,,"Hé, je sais que ça à l'air d'être un coup monté, mais je ne ferais jamais ça à une aussi bonne machine à tuer. Tellement de bruit pour une coupe, franchement.. Préparez vous, l'or et la gloire vous attend, comme promis. Prenez cette clé et le gouverneur vous récompensera.",,,"よう。アンタが何を考えてるかわかるぜ、 +ファンシーなカップを持ってここに戻ってくると。","여기 석궁이야, 똑바로 겨냥해, 그리고... '철퍼덕'. 기억해, 멋진 컵을 들고 이 곳으로 다시 와.","Hier is een kruisboog, richt gewoon recht en -- splat! --. Vergeet niet, pak de mooie beker en ontmoet me in de herberg.","Her er en armbrøst, bare sikt rett og... plask! Husk, ta den fine koppen og møt meg på tavernaen.","Tu jest kusza, wyceluj prosto i... splat! Pamiętajcie, weźcie elegancki puchar i spotkajmy się w tawernie.","Pegue esta besta. Só mirar direito e splat! Lembre-se, pegue o copo bonitinho e me encontre na taverna.",,"Aici e o arbaletă, doar țintești și -- pleoșc! --. Ține minte, pune mâna pe potir și găsește-mă la tavernă.",Вот арбалет — просто прицеливаешься и «шлеп!» Запомни — хватаешь чашку и возвращаешься в таверну.,,"Här är ett armborst, sikta rakt och -- splat!--. Kom ihåg, ta den fina koppen och möt mig på tavernan.","İşte yaylı tüfek. Düz nişan al ve patlat! Unutma, süslü kupayı al ve benimle tavernada buluş." +I'll see you there.,TXT_RPLY0_SCRIPT33_D18192_ILLSE,〃,,,Uvidíme se tam.,Vi ses der.,Wir sehen uns dort.,,Mi estos tie.,Allí estaré.,Ahí voy a estar.,Tapaan sinut siellä.,Je vous y verrais.,Ott találkozunk.,Ci vediamo lì.,また会おう。,거기서 보자고.,Ik zie je daar.,Vi ses der.,Do zobaczenia.,Te vejo lá.,,Ne vedem acolo.,Я вернусь с чашей.,,Vi ses där.,Orada görüşürüz. +"What are you waiting for? Don't worry, I'll clean up the bodies, just bring me that chalice!",TXT_DLG_SCRIPT33_D19708_WHATA,〃,,,"Na co čekáš? Neboj, mrtvol se zbavím já, prostě mi přines ten kalich!","Hvad venter du på? Bare rolig, jeg skal nok rydde op efter ligene, bare giv mig bægeret!","Worauf wartest du noch? Keine Sorge, ich kümmere mich um die Leichen. Bring mir den Kelch.",,Kion vi atendas? Mi mem kaŝos la kadavrojn. Vi nur alportu tiun kalikon!,"¿A qué estás esperando? Yo me deshago de los cuerpos, así que tranquilo. ¡Tú solo tráeme ese cáliz!","¿Qué estás esperando? Yo me deshago de los cuerpos, así que tranquilo. ¡Tú solo tráeme ese cáliz!","Mitä oikein odottelet? Älä huoli, siivoan kyllä ruumiit. Tuo vaan minulle se kalkki.","Qu'attendez vous? Je m'occuperai des corps, ne vous inquiétez pas. Apportez-moi le calice!","Mire vársz? Ne aggódj, majd feltakarítom a hullákat, csak hozdd el a serleget.","Che cosa stai aspettando? Non ti preoccupare, ci penserò io a far sparire i corpi, tu pensa solo a portarmi quel calice!","何ボーっとしてんだ? 心配すんな、 +チャッチャと片付けて聖杯を持ってこい!","뭘 기다리는 거야? 걱정하지 마, 내가 시체들을 치워줄 테니. 그냥 성배를 가져와!","Waar wacht je nog op? Maak je geen zorgen, ik ruim de lichamen op, breng me gewoon die kelk!","Hva venter du på? Slapp av, jeg skal rydde opp i likene, bare gi meg begeret!","Na co czekasz? Nie martw się, posprzątam ciała, tylko przynieś mi ten kielich!","O que está esperando? Não se preocupe, eu limpo os corpos. Apenas me traga aquele cálice!",,"Ce mai aștepți? Nu te teme, voi curăța eu cadavrele, tu doar adu-mi potirul.",Чего ты ждёшь? Не беспокойся: я сам избавлюсь от трупов. Просто принеси мне чашу!,,"Vad väntar du på? Oroa dig inte, jag städar upp kropparna, ge mig bara kalken!","Neyi bekliyorsun? Merak etme, cesetleri temizleyeceğim, sadece kadehi bana getir!" +Guards! Kill the traitor!,TXT_DLG_SCRIPT33_D21224_GUARD,〃,,,Stráže! Zabte toho zrádce!,Vagter! Dræb forræderen!,Wächter! Tötet den Verräter!,,Gardistoj! Mortigu la perfidulon!,¡Guardias! ¡Matad al traidor!,¡Guardias! ¡Maten al traidor!,Vartijat! Tappakaa petturi!,Gardes! Tuez ce traître!,Őrök! Öljétek meg az árulót!,Guardie! Uccidete il traditore!,ガード! 裏切者を殺せ!,경비! 반역자를 죽여라!,Bewakers! Dood de verrader!,Vakter! Drep forræderen!,Strażnicy! Zabić zdrajcę!,Guardas! Matem esse traidor!,,"Gardieni, omorâți trădătorul!",Стража! Убейте предателя!,,Vakter! Döda förrädaren!,Muhafızlar! Haini öldürün! +"Hey, I know what you're thinking, kinda looks like a setup, I would never do that to such a killing machine, I mean it. Whew, all this fuss over a cup, weird. Now get ready, gold and glory, like I promised. Take this key and the Governor himself will reward you.",TXT_DLG_SCRIPT33_D22740_HEYIK,MAP33: Harris (tavern).,,,"Hej, vím co si myslíš, tohle vypadá jako bouda. Takovému stroji na zabíjení bych nic takového neudělal, vážně! Páni, takový povyk kvůli hrnečku, divný. Tak teď se připrav, zlato a sláva, jak jsem slíbil. Vem si tenhle klíč a sám guvernér tě odmění.","Hey, jeg ved hvad du tænker, det ligner en fælde, jeg ville aldrig gøre det mod sådan en dræbermaskine, jeg mener det. Alt dette postyr over en kop, underligt. Gør dig klar, guld og ære, som jeg lovede. Tag denne nøgle, og guvernøren selv vil belønne dig.","Hey, ich weiß, es sieht anscheinend wie eine Falle aus, aber so etwas würde ich einer so großeartigen Tötungsmaschine nicht antun. Hast du ddas Ding? Großartig! Nun mach dich bereit, Geld und Ruhm, genau wie ich es dir versprochen habe. Nimm diesen Schlüssel und der Gouverneur wird dich belohnen.",,"Jes, mi scias, vi certe pensas, ke ĉi tio estas trompo, sed mi neniam farus tion al bonega mortig-maŝino, mi ĵuras tion. Ve, ĉi tiom da malordo pro pokalo, strange. Vi nun pretiĝu: oro kaj gloro, tiel, kiel mi promesis. Prenu ĉi tiun ŝlosilon kaj la registo mem rekompencos vin.","Sí, sé lo que estás pensando: esto parece un timo, pero nunca le haría eso una tal máquina de matar, lo juro. Uf, todo este lío por una copa, qué raro. Ahora prepárate: oro y gloria, tal y como he prometido. Toma esta llave y el mismísimo gobernador te recompensará.","Sí, sé lo que estás pensando: esto parece una estafa, pero nunca le haría eso una tal máquina de matar, lo juro. Uf, todo este lío por una copa, que raro. Ahora prepárate: oro y gloria, tal y como prometí. Toma esta llave y el mismísimo gobernador te va a recompensar.","Joo joo, tiedän, mitä ajattelet: vähän tuntuu väijytykseltä. En kuitenkaan ikinä tekisi sellaista niin kovalle tappokoneelle. Tarkoitan sitä. Huhhuh, kaikki tämä vouhotus yhdestä kupista; kummallista. No niin, valmistaudu kultaan ja kunniaan, niin kuin lupasinkin. Ota tämä avain ja itse kuvernööri palkitsee sinut.","Hé, je sais que ça à l'air d'être un coup monté, mais je ne ferais jamais ça à une aussi bonne machine à tuer. Tellement de bruit pour une coupe, franchement.. Préparez vous, l'or et la gloire vous attend, comme promis. Prenez cette clé et le gouverneur vous récompensera.","Tudom mire gondolsz, olyan ez mintha egy csapda lenne, de esküszöm soha nemm tennék ilyet egy jó gyilkológéppel. Nahát, ennyi hűhó egy francos serleg miatt. Node, állj aztán készen, eljön az a bizonyos pénz és hírnév mint ahogy ígértem. Tedd el ezt a kulcsot, és maga a kormányzó fog megjutalmazni.","Ehi, so che può sembrare una trappola. Ma io non tradirei mai a un killer abile come te. Mah, tutto questo per una coppa, che strano. Adesso preparati, oro e gloria, come ti avevo promesso. Prendi questa chiave e il governatore in persona ti ricompenserà.","よう。アンタが何を考えてるかわかるぜ、 まるで罠だと。 俺には暴れん坊みたいな芸当出来ねえしな。 おう、カップを巡って大騒ぎだろうなこりゃ、 怖い怖い。 だったら準備しな、金と名誉は、約束通り。 -この鍵を取ったら知事が報酬を与えるだろうな。","이봐, 무슨 생각을 하는지 알겠어. 확실히 뭔가 꾸며 놓은 것 같다는 거. 난 훌륭한 학살 기계에게 그런 짓을 할 사람이 아니야. 휴... 그깟 컵 가지고. 이상해. 아무튼 준비해, 골드와 영광을. 이 열쇠를 총독에게 가져다주면 보상해 줄 거야.","Hé, ik weet wat je denkt, het lijkt een beetje op een valstrik, dat zou ik nooit met zo'n moordmachine doen, ik meen het. Whew, al deze ophef over een kopje, vreemd. Maak je nu klaar, goud en glorie, zoals ik heb beloofd. Neem deze sleutel en de Gouverneur zelf zal je belonen.",,"Olha, eu sei o que você está pensando, que parece uma cilada. Eu nunca faria isso com uma máquina mortífera como você, sério mesmo. Nossa, todo esse escândalo por causa de um cálice, que esquisito. Agora se prepare, ouro e glória conforme prometido. Pegue esta chave e o governador vai te recompensar.",,,"Слушай, я знаю, о чём ты думаешь. Ты думаешь, что это подстава. Но я бы никогда не сделал этого с такой машиной для убийств, как ты, правда-правда. Тем более, ради какой-то чаши. А теперь, тебя ждут золото и слава, как я и обещал. Возьми этот ключ, губернатор лично наградит тебя.", -"Great, I can't wait!",TXT_RPLY0_SCRIPT33_D22740_GREAT,,,,"Skvělý, nemůžu se dočkat!","Toll, ich kann es kaum erwarten!",,,"Genial, ¡no puedo esperar!",,,"Parfait, je ne peux pas attendre!",,,そりゃいいな、待ち遠しい!,좋았어! 기다릴 수 없는걸?,"Geweldig, ik kan niet wachten!",,"Ótimo, mal posso esperar!",,,Прекрасно. Мне уже не терпится!, -"No chalice, no money!",TXT_RNO0_SCRIPT33_D22740_NOCHA,,,,"Žádný kalich, žádný prachy!","Kein Kelch, kein Geld.",,,¡Sin cáliz no hay dinero!,,,"Pas de calice, pas d'argent!",,,聖杯が無いなら、金も無しだ!,성배가 없다면 돈도 없어!,"Geen kelk, geen geld!",,"Sem cálice, sem dinheiro!",,,Нет чаши — нет денег!, -"I'll keep the chalice, thanks.",TXT_RPLY1_SCRIPT33_D22740_ILLKE,,,,"Nechám si ten kalich, díky.","Ich behalte den Kelch, danke.",,,"Me quedaré el caliz, gracias.",,,"Je le garde, merci.",,,聖杯は頂く、じゃあな。,"내가 성배를 가지고 있을게, 고마워.","Ik bewaar de kelk, bedankt.",,"Vou ficar com o cálice, obrigado.",,,"Спасибо, но я оставлю чашу себе.", -Keep it? I think not!,TXT_RYES1_SCRIPT33_D22740_KEEPI,,,,Necháš? Nemyslím si!,"Behalten? Ich glaube, nicht.",,,¿Quedártelo? ¡Me parece que no!,,,Le garder? Je ne pense pas!,,,頂く? 有り得ねえな!,가지고 있겠다고? 내 생각은 아닌데?,Bewaren? Ik denk van niet!,,Ficar com o cálice? Acho que não!,,,Оставишь себе? Ещё чего!, -What are you waiting for? The governor himself will reward you.,TXT_DLG_SCRIPT33_D24256_WHATA,,,,Na co čekáš? Sám guvernér tě odmění.,Worauf wartest du? Der Gouverneur wird dich belohnen.,,,¿Qué estás esperando? El mismísimo gobernador te recompensará.,,,Qu'attendez-vous? Le gouverneur vous récompensera lui même.,,,何突っ立ってんだ? 知事に報酬を受けて来いよ。,꾸물거리지 말고 총독을 만나. 그가 너를 보답해줄 거야.,Waar wacht je nog op? De gouverneur zelf zal je belonen.,,O que você está esperando? O governador em pessoa vai te recompensar.,,,Чего ты ждёшь? Губернатор лично наградит тебя., -Die traitor! ,TXT_DLG_SCRIPT33_D25772_DIETR,,,,"Zemři, zrádče!","Stirb, Verräter!",,,"¡Muere, traidor!",,,"Meurs, traître!",,,くたばれ裏切者が!,죽어라. 배신자!,Sterf de verrader!,,"Morra, traidor!",,,"Умри, предатель!", -So you're the fool who stole the chalice? I'm going to have you arrested as a rebel thief... Thereby enhancing my position with the Order. How does it feel to be an unwitting pawn? ,TXT_DLG_SCRIPT33_D27288_SOYOU,,,,"Tak ty jsi ten blázen, který ukradl kalich? Teď tě nechám zatknout jako rebelského zloděj... a tím si upevním svou pozici s Řádem. Jaký je to pocit, být bezděčnou figurkou?","So, du bist also der Narr der den Kelch gestohlen hat? Ich werde dich als Dieb der Rebellen verhaften lassen und dadurch meine Position im Orden verbessern. Wie fühlt es sich an als ahnungslose Schachfigur?",,,¿Así que tú eres el necio que robó el cáliz? Voy a arrestarte como ladrón rebelde... Mejorando así mí posición con la Orden. ¿Cómo se siente ser un inconsciente peón?,,,"Vous êtes l'abruti qui a volé le calice? Maintenant il faut que je vous arrète comme voleur rebelle.. Ca va aider ma position dans l'Ordre. Comment ça fait d'être un pion ignorant? Petite idée, ça va faire mal.",,,"それで、お前が聖杯を盗んだ愚か者か? +この鍵を取ったら知事が報酬を与えるだろうな。","이봐, 무슨 생각을 하는지 알겠어. 확실히 뭔가 꾸며 놓은 것 같다는 거. 난 훌륭한 학살 기계에게 그런 짓을 할 사람이 아니야. 휴... 그깟 컵 가지고. 이상해. 아무튼 준비해, 골드와 영광을. 이 열쇠를 총독에게 가져다주면 보상해 줄 거야.","Hé, ik weet wat je denkt, het lijkt een beetje op een valstrik, dat zou ik nooit met zo'n moordmachine doen, ik meen het. Whew, al deze ophef over een kopje, vreemd. Maak je nu klaar, goud en glorie, zoals ik heb beloofd. Neem deze sleutel en de Gouverneur zelf zal je belonen.","Jeg vet hva du tenker. Det ser ut som en felle. Jeg ville aldri gjort det mot en slik drapsmaskin. Alt dette oppstyret for en kopp. Merkelig. Gjør deg klar, gull og ære, som jeg lovet. Ta denne nøkkelen, så vil guvernøren selv belønne deg.","Hej, wiem co myślisz, wygląda to na ustawkę, nigdy nie zrobiłbym tego takiej maszynie do zabijania, mówię poważnie. Całe to zamieszanie z powodu kubka, dziwne. A teraz przygotuj się, złoto i chwała, jak obiecałem. Weź ten klucz, a sam gubernator cię nagrodzi.","Olha, eu sei o que você está pensando, que parece uma cilada. Eu nunca faria isso com uma máquina mortífera como você, sério mesmo. Nossa, todo esse escândalo por causa de um cálice, que esquisito. Agora se prepare, ouro e glória conforme prometido. Pegue esta chave e o governador vai te recompensar.",,"Hei, știu la ce te gândești, pare o capcană, dar nu aș face asta niciodată unei mașini ucigașe, serios. Atâta harababură pentru un potir, . Acum pregătește-te, aur și glorie, dupa cum ți-am promis. Ia cheia asta și însuși Guvernatorul te va răsplătii.","Слушай, я знаю, о чём ты думаешь. Ты думаешь, что это подстава. Но я бы никогда не сделал этого с такой машиной для убийств, как ты, правда-правда. Тем более, ради какой-то чаши. А теперь, тебя ждут золото и слава, как я и обещал. Возьми этот ключ, губернатор лично наградит тебя.",,"Jag vet vad du tänker, det ser ut som en fälla, jag skulle aldrig göra det mot en sådan dödsmaskin, jag menar det. Allt detta ståhej för en kopp, konstigt. Gör dig nu redo, guld och ära, som jag lovade. Ta den här nyckeln och guvernören själv kommer att belöna dig.","Hey, ne düşündüğünü biliyorum, biraz tuzak gibi görünüyor, böyle bir ölüm makinesine bunu asla yapmam, ciddiyim. Tüm bu yaygara bir fincan için, garip. Şimdi hazır ol, altın ve şan, söz verdiğim gibi. Bu anahtarı al ve Vali'nin kendisi seni ödüllendirecek." +"Great, I can't wait!",TXT_RPLY0_SCRIPT33_D22740_GREAT,〃,,,"Skvělý, nemůžu se dočkat!","Fedt, jeg kan ikke vente!","Toll, ich kann es kaum erwarten!",,"Bonege, mi sopire atendas!","Genial, ¡no puedo esperar!",,"Mahtavaa, en malta odottaa!","Parfait, je ne peux pas attendre!","Remek, már alig várom!","Ottimo, non vedo l'ora!",そりゃいいな、待ち遠しい!,좋았어! 기다릴 수 없는걸?,"Geweldig, ik kan niet wachten!","Flott, jeg gleder meg!","Świetnie, nie mogę się doczekać!","Ótimo, mal posso esperar!",,"Grozav, abia aștept.",Прекрасно. Мне уже не терпится!,,"Toppen, jag kan inte vänta!","Harika, sabırsızlanıyorum!" +"No chalice, no money!",TXT_RNO0_SCRIPT33_D22740_NOCHA,〃 (if accepting without having the chalice),,,"Žádný kalich, žádný prachy!","Ingen bæger, ingen penge!","Kein Kelch, kein Geld.",,Sen kaliko ne estas mono!,¡Sin cáliz no hay dinero!,,"Ei kalkkia, ei rahaa!","Pas de calice, pas d'argent!","Ha nincs serleg, nincs pénz!","Niente calice, niente soldi!",聖杯が無いなら、金も無しだ!,성배가 없다면 돈도 없어!,"Geen kelk, geen geld!","Ingen kalk, ingen penger!","Nie ma kielicha, nie ma pieniędzy!","Sem cálice, sem dinheiro!",,"Niciun potir, niciun ban!",Нет чаши — нет денег!,,"Ingen bägare, inga pengar!",Kadeh yoksa para da yok! +"I'll keep the chalice, thanks.",TXT_RPLY1_SCRIPT33_D22740_ILLKE,〃,,,"Nechám si ten kalich, díky.","Jeg beholder bægeret, tak.","Ich behalte den Kelch, danke.",,Mi konservos la kalikon. Dankon.,Me quedo con el cáliz. Gracias.,,"Pidän kalkin, kiitos.","Je le garde, merci.","Inkább megtartom a serleget, kösz.","Il calice lo terrò io, grazie.",聖杯は頂く、じゃあな。,"내가 성배를 가지고 있을게, 고마워.","Ik bewaar de kelk, bedankt.","Jeg beholder begeret, takk.","Zatrzymam kielich, dzięki.","Vou ficar com o cálice, obrigado.",,"Păstrez potirul, merci.","Спасибо, но я оставлю чашу себе.",,"Jag behåller bägaren, tack.","Kadeh bende kalsın, teşekkürler." +Keep it? I think not!,TXT_RYES1_SCRIPT33_D22740_KEEPI,〃,,,Necháš? Nemyslím si!,Beholde den? Det tror jeg ikke!,"Behalten? Ich glaube, nicht.",,"Ĉu konservi ĝin? +Mi kredas, ke ne!","¿Quedártelo? +¡Me parece que no!",,Pidät sen? Enpä usko!,Le garder? Je ne pense pas!,Megtartod? Nem hinném öreg!,Davvero intendi tenerlo tu? Mi spiace ma non funziona così!,頂く? 有り得ねえな!,가지고 있겠다고? 내 생각은 아닌데?,Bewaren? Ik denk van niet!,Beholde det? Jeg tror ikke det!,Zatrzymać? Chyba nie!,Ficar com o cálice? Acho que não!,,Păstrezi? Ba nu cred!,Оставишь себе? Ещё чего!,,Behålla den? Jag tror inte det!,Saklamak mı? Hiç sanmıyorum! +What are you waiting for? The governor himself will reward you.,TXT_DLG_SCRIPT33_D24256_WHATA,〃,,,Na co čekáš? Sám guvernér tě odmění.,Hvad venter du på? Guvernøren selv vil belønne dig.,Worauf wartest du? Der Gouverneur wird dich belohnen.,,Kion vi atendas? La registo mem rekompencos vin.,¿A qué estás esperando? El mismísimo gobernador te recompensará.,¿Qué estás esperando? El mismísimo gobernador te va a recompensar.,Mitä oikein odotat? Kuvernööri itse palkitsee sinut.,Qu'attendez-vous? Le gouverneur vous récompensera lui même.,Mire vársz? Maga a kormányzó fog megjutalmazni.,Che cosa stai aspettando? Il governatore in persona ti ricompenserà.,何突っ立ってんだ? 知事に報酬を受けて来いよ。,꾸물거리지 말고 총독을 만나. 그가 너를 보답해줄 거야.,Waar wacht je nog op? De gouverneur zelf zal je belonen.,Hva venter du på? Guvernøren selv vil belønne deg.,Na co czekasz? Sam gubernator cię nagrodzi.,O que você está esperando? O governador em pessoa vai te recompensar.,,Ce mai aștepți? Guvernatorul însuși te va răsplătii.,Чего ты ждёшь? Губернатор лично наградит тебя.,,Vad väntar du på? Guvernören själv kommer att belöna dig.,Neyi bekliyorsun? Valinin kendisi seni ödüllendirecek. +Die traitor! ,TXT_DLG_SCRIPT33_D25772_DIETR,〃,,,"Zemři, zrádče!","Dø, forræder!","Stirb, Verräter!",,"Mortu, perfidulo!","¡Muere, traidor!",,"Kuole, petturi!","Meurs, traître!",Halál rád áruló!,Muori traditore!,くたばれ裏切者が!,죽어라. 배신자!,Sterf de verrader!,"Dø, forræder!",Giń zdrajco!,"Morra, traidor!",,Mori trădătorule!,"Умри, предатель!",,Dö förrädare!,Geber hain! +So you're the fool who stole the chalice? I'm going to have you arrested as a rebel thief... Thereby enhancing my position with the Order. How does it feel to be an unwitting pawn? ,TXT_DLG_SCRIPT33_D27288_SOYOU,MAP33: Mourel.,,,"Tak ty jsi ten blázen, který ukradl kalich? Teď tě nechám zatknout jako rebelského zloděj... a tím si upevním svou pozici s Řádem. Jaký je to pocit, být bezděčnou figurkou?","Så du er det fjols, der stjal bægeret? Jeg vil få dig arresteret som en oprørsk tyv... og derved forbedre min position i ordenen. Hvordan føles det at være en uvidende brik?","So, du bist also der Narr der den Kelch gestohlen hat? Ich werde dich als Dieb der Rebellen verhaften lassen und dadurch meine Position im Orden verbessern. Wie fühlt es sich an als ahnungslose Schachfigur?",,"Vi do estas la stultulo, kiu ŝtelis la kalikon, ĉu? Mi kaptos vin kiel ribelan ŝteliston, tiel mi plibonigos mian statuson kun La Ordeno. Kiel vi sentas, ke vi estas nevola marioneto?","¿Así que tú eres el necio que ha robado el cáliz? Te capturaré como ladrón rebelde, mejorando así mi posición con La Orden. ¿Qué se siente ser un peón involuntario?","¿Así que tú eres el tonto que se robó el cáliz? Te voy a capturar como ladrón rebelde, mejorando así mi posición con La Orden. ¿Qué se siente ser un peón involuntario?","Vai sinä olet se houkka, joka varasti kalkin? Pidätytän sinut kapinallisvarkaana, siten parantaen asemaani Veljeskunnassa. Miltäpä tuntuu olla tahaton pelinappula?","Vous êtes l'abruti qui a volé le calice? Maintenant il faut que je vous arrète comme voleur rebelle.. Ca va aider ma position dans l'Ordre. Comment ça fait d'être un pion ignorant? Petite idée, ça va faire mal.",Szóval te vagy az isten barma aki ellopta a kelyhet? Jól letartóztatlak mint lázadó tolvaj...ezzel megerősítve a pozíciómat a Rendben. Milyen érzés egy tudatlan parasztnak lenni?,Quindi sei tu il folle che ha rubato il calice? Ti farò arrestare come un ladro ribelle... E così facendo salirò nei ranghi dell'Ordine. Come ci si sente ad essere un'inconsapevole pedina?,"それで、お前が聖杯を盗んだ愚か者か? 私は反賊としてお前を逮捕するつもりだ... そうすればオーダーでの地位が上がる。 無意味な駒だと思うか? -",그래서 네가 그 성배를 훔친 바보로군? 반군 절도범으로 체포해주지... 오더에서의 내 위치도 올리는 겸. 모르는 사이에 장물아비가 된 기분이 어떤가?,Dus jij bent de dwaas die de kelk heeft gestolen? Ik ga je laten arresteren als rebelse dief.... Daardoor verbeter ik mijn positie bij de Orde. Hoe voelt het om een onwetende pion te zijn?,,Então você é o idiota que roubou o cálice? Eu vou prender você por ser um ladrão rebelde... E assim vou melhorar minha posição com a Ordem. Como se sente sendo um plebeu ignorante?,,,"Так это ты тот недоумок, что украл чашу? Я передам тебя Ордену, как вора повстанцев... Это укрепит мои отношения с ним. Каково чувствовать себя безмозглой пешкой?", -It sucks!,TXT_RPLY0_SCRIPT33_D27288_ITSUC,,,,Je to na hovno!,Scheiße!,,,¡Apesta!,,,Quelle merde!,,,クソが!,기분이 아주 좆같아.,Het is klote!,,É uma merda!,,,Чтоб ты сдох!, -For you it does.,TXT_RYES0_SCRIPT33_D27288_FORYO,,,,Pro tebe určitě.,Du steckst ganz tief drin.,,,"Para ti, sí.",,,"Pour vous, en effet.",,,私もそう思う。,더한 기분이 들게 해주지.,Voor jou wel.,,"Pra você, é mesmo.",,,Скоро сдохнешь ты., -Harris promised me money!,TXT_RPLY1_SCRIPT33_D27288_HARRI,,,,Harris mi slíbil peníze!,Harris hat mir Geld versprochen!,,,¡Harris me prometió dinero!,,,Harris m'a promis de l'argent!,,,ハリスは俺に金を渡すと約束したのに!,해리스가 날 배신했어... 이 새끼!,Harris beloofde me geld!,,O Harris prometeu me pagar!,,,Харрис обещал мне деньги!, -Too bad. The only thing you're getting is death!,TXT_RYES1_SCRIPT33_D27288_TOOBA,,,,"Smůla. Jediné, co dostaneš, je smrt!",Jammerschade. Das Einzige was du bekommen wirst ist der Tod!,,,Una pena. ¡Lo único que tendrás es la muerte!,,,"Dommage. Tout ce que vous allez recevoir, c'est votre mort!",,,残念だな、お前にやれるものは死のみだ!,안됐네. 넌 여기서 죽게 될테니까!,Jammer. Het enige wat je krijgt is de dood!,,Que pena. A única coisa que você vai receber é a morte!,,,"Увы. Всё, что ты получишь, — это смерть!", -We're going to kill you!,TXT_DLG_SCRIPT33_D28804_WEREG,,,,Zabijeme tě!,Wir werden euch töten!,,,¡Vamos a matarte!,,,On va te buter!,,,お前をぶっ殺す!,우린 널 죽일 거야!,We gaan je vermoorden!,,Nós vamos te matar!,,,Готовься к смерти!, -Get out of here!,TXT_DLG_SCRIPT33_D30320_GETOU,,,,Vypadni odsud!,Verschwinde von hier!,,,¡Sal de aquí!,,,Sortez de là!,,,ここから立ち去れ!,여길 나가!,Maak dat je hier wegkomt!,,Saia daqui!,,,Убирайся отсюда!, -We're going to kill you!,TXT_DLG_SCRIPT33_D31836_WEREG,,,,Zabijeme tě!,Wir werden euch töten!,,,¡Vamos a matarte!,,,On va te buter!,,,お前をぶっ殺す!,널 죽이는걸 즐길테다.,We gaan je vermoorden!,,Nós vamos te matar!,,,Готовься к смерти!, -Get out of here!,TXT_DLG_SCRIPT33_D33352_GETOU,,,,Vypadni odsud!,Verschwinde von hier!,,,¡Sal de aquí!,,,Sortez de là!,,,ここから立ち去れ!,여기서 뭐하는 거야? 꺼져!,Maak dat je wegkomt!,,Saia daqui!,,,Убирайся отсюда!, -"What a perfect place for us, under the old town hall. The Order thinks they've wiped us out, but all it was is a reminder to us of what can happen when you become careless. ",TXT_DLG_SCRIPT34_D0_WHATA,,,,"Tady pod starou radnicí to je pro nás ideální místo. Řád si myslí, že nás vyhladil, ale pouze nám připomněl, co se může stát, když jsi neopatrný.","Was für ein Perfekter Ort für uns, unter dem alten Rathaus. Der Orden glaubt, er hätte uns vernichtet, aber es war nur ein Denkzettel für uns, was passieren kann wenn man unaufmerksam ist.",,,"Que lugar tan perfecto para nosotros, bajo el antiguo ayuntamiento. La Orden cree que nos ha aniquilado, pero todo lo que ha sido es un recordatorio para nosotros de lo que puede pasar cuando te descuidas.",,,"Quel endroit parafait pour nous, sous la mairie. L'Ordre pense qu'ils nous ont tous tués, mais ça leur servira de leçon, ils verront se qu'il se passe quand on ne fait pas attention..",,,"旧市庁舎の下で、 +",그래서 네가 그 성배를 훔친 바보로군? 반군 절도범으로 체포해주지... 오더에서의 내 위치도 올리는 겸. 모르는 사이에 장물아비가 된 기분이 어떤가?,Dus jij bent de dwaas die de kelk heeft gestolen? Ik ga je laten arresteren als rebelse dief.... Daardoor verbeter ik mijn positie bij de Orde. Hoe voelt het om een onwetende pion te zijn?,Så du er tosken som stjal begeret? Jeg skal få deg arrestert som en opprørsk tyv... Og dermed styrke min posisjon i Ordenen. Hvordan føles det å være en uvitende brikke?,"Więc to ty jesteś tym głupcem, który ukradł kielich? Każę cię aresztować jako buntowniczego złodzieja... Tym samym wzmocnię swoją pozycję w Zakonie. Jakie to uczucie być nieświadomym pionkiem?",Então você é o idiota que roubou o cálice? Eu vou prender você por ser um ladrão rebelde... E assim vou melhorar minha posição com a Ordem. Como se sente sendo um plebeu ignorante?,,Deci tu ești tolomacul care a furat potirul? Am să te arestez drept un hoț rebel... Prin urmare crescând in rangurile Ordinului. Cum e să fii un pion?,"Так это ты тот недоумок, что украл чашу? Я передам тебя Ордену, как вора повстанцев... Это укрепит мои отношения с ним. Каково чувствовать себя безмозглой пешкой?",,Så du är dåren som stal kalken? Jag kommer att låta arrestera dig som en upprorisk tjuv... och därmed förbättra min ställning i orden. Hur känns det att vara en ovetande bricka?,Demek kadehi çalan aptal sensin? Seni asi bir hırsız olarak tutuklatacağım. Böylece Tarikat'taki konumumu güçlendireceğim. Farkında olmadan bir piyon olmak nasıl bir duygu? +It sucks!,TXT_RPLY0_SCRIPT33_D27288_ITSUC,〃,,,Je to na hovno!,Det stinker!,Scheiße!,,Tio estas aĉa!,¡Apesta!,,Ihan perseestä!,Quelle merde!,Ez szopás!,È uno schifo!,クソが!,기분이 아주 좆같아.,Het is klote!,Det suger!,Do dupy!,É uma merda!,,Nașpa!,Чтоб ты сдох!,,Det suger!,Berbat! +For you it does.,TXT_RYES0_SCRIPT33_D27288_FORYO,〃,,,Pro tebe určitě.,For dig gør det.,Du steckst ganz tief drin.,,Por vi ja.,Para ti sí.,,"Kyllä, sinun tilanteesi.","Pour vous, en effet.",...és a bráner rossz végén vagy.,Ti faccio vedere io!,私もそう思う。,더한 기분이 들게 해주지.,Voor jou wel.,For deg gjør det det.,Dla ciebie tak.,"Pra você, é mesmo.",,"Pentru tine, într-adevăr este.",Скоро сдохнешь ты.,,För dig gör det det.,Senin için öyle. +Harris promised me money!,TXT_RPLY1_SCRIPT33_D27288_HARRI,〃,,,Harris mi slíbil peníze!,Harris lovede mig penge!,Harris hat mir Geld versprochen!,,Harris promesis monon al mi!,¡Harris me prometió dinero!,,Harris lupasi minulle rahaa!,Harris m'a promis de l'argent!,Harris pénzt ígért nekem.,Harris mi ha promesso dei soldi!,ハリスは俺に金を渡すと約束したのに!,해리스가 날 배신했어... 이 새끼!,Harris beloofde me geld!,Harris lovet meg penger!,Harris obiecał mi pieniądze!,O Harris prometeu me pagar!,,Harris mi-a promis bani!,Харрис обещал мне деньги!,,Harris lovade mig pengar!,Harris bana para sözü verdi! +Too bad. The only thing you're getting is death!,TXT_RYES1_SCRIPT33_D27288_TOOBA,〃,,,"Smůla. Jediné, co dostaneš, je smrt!","Det var ærgerligt. Det eneste, du får, er døden!",Jammerschade. Das Einzige was du bekommen wirst ist der Tod!,,"Kiel domaĝe. Ĉio, kion +vi havos estas morto!","Qué mal. ¡Lo único que +tendrás es la muerte!","Qué mal. ¡Lo único que +vas a tener es la muerte!","Voi voi. Sen kyllä voin sinulle luvata, että kuolet!","Dommage. Tout ce que vous allez recevoir, c'est votre mort!","Így jártál. Az egyetlen dolog amit kapsz, az a halál.",Peccato. L'unica cosa che otterrai è la morte.,残念だな、お前にやれるものは死のみだ!,안됐네. 넌 여기서 죽게 될테니까!,Jammer. Het enige wat je krijgt is de dood!,"Synd for deg. Det eneste du får, er døden!",Szkoda. Jedyne co dostaniesz to śmierć!,Que pena. A única coisa que você vai receber é a morte!,,Păcat. Tot ce vei primi e moarte!,"Увы. Всё, что ты получишь, — это смерть!",,Det var synd. Det enda du får är döden!,Çok yazık. Alacağın tek şey ölüm! +We're going to kill you!,TXT_DLG_SCRIPT33_D28804_WEREG,,,,Zabijeme tě!,Vi slår dig ihjel!,Wir werden euch töten!,,Ni mortigos vin!,¡Te vamos a matar!,,Tapamme sinut!,On va te buter!,Megölünk!,Adesso ti ammazziamo!,お前をぶっ殺す!,우린 널 죽일 거야!,We gaan je vermoorden!,Vi skal drepe deg!,Zabijemy cię!,Nós vamos te matar!,,Te vom omorâ!,Готовься к смерти!,,Vi ska döda dig!,Seni öldüreceğiz! +Get out of here!,TXT_DLG_SCRIPT33_D30320_GETOU,,,,Vypadni odsud!,Forsvind herfra!,Verschwinde von hier!,,Foriru!,¡Sal de aquí!,,Häivy täältä!,Sortez de là!,Pusztulj innen!,Fuori di qui!,ここから立ち去れ!,여길 나가!,Maak dat je hier wegkomt!,Forsvinn herfra!,Wynoś się stąd!,Saia daqui!,,Valea!,Убирайся отсюда!,,Stick härifrån!,Defolun buradan! +We're going to kill you!,TXT_DLG_SCRIPT33_D31836_WEREG,MAP33: Green acolytes (beginning).,,,Zabijeme tě!,Vi slår dig ihjel!,Wir werden euch töten!,,Ni mortigos vin!,¡Te vamos a matar!,,Tapamme sinut!,On va te buter!,Megölünk!,Adesso ti ammazziamo!,お前をぶっ殺す!,널 죽이는걸 즐길테다.,We gaan je vermoorden!,Vi skal drepe deg!,Zabijemy cię!,Nós vamos te matar!,,Te vom omorâ!,Готовься к смерти!,,Vi ska döda dig!,Seni öldüreceğiz! +Get out of here!,TXT_DLG_SCRIPT33_D33352_GETOU,MAP33: Yellow acolytes.,,,Vypadni odsud!,Kom ud herfra!,Verschwinde von hier!,,Foriru!,¡Sal de aquí!,,Häivy täältä!,Sortez de là!,Pusztulj innen!,Fuori di qui!,ここから立ち去れ!,여기서 뭐하는 거야? 꺼져!,Maak dat je wegkomt!,Forsvinn herfra!,Wynoś się stąd!,Saia daqui!,,Valea!,Убирайся отсюда!,,Stick härifrån!,Defolun buradan! +"What a perfect place for us, under the old town hall. The Order thinks they've wiped us out, but all it was is a reminder to us of what can happen when you become careless. ",TXT_DLG_SCRIPT34_D0_WHATA,MAP34: Barracks.,,,"Tady pod starou radnicí to je pro nás ideální místo. Řád si myslí, že nás vyhladil, ale pouze nám připomněl, co se může stát, když jsi neopatrný.","Sikke et perfekt sted for os, under det gamle rådhus. Ordenen tror, at de har udryddet os, men det var blot en påmindelse til os om, hvad der kan ske, når man bliver uforsigtig.","Was für ein Perfekter Ort für uns, unter dem alten Rathaus. Der Orden glaubt, er hätte uns vernichtet, aber es war nur ein Denkzettel für uns, was passieren kann wenn man unaufmerksam ist.",,"Kia perfekta kaŝejo por ni: sub la antikva urbodomo. La Ordeno kredas, ke ĝi ekstermis nin, sed ĉi tio estis nur memoraĵo pri tio, kio povas okazi kiam ni estas senatentaj.","Qué lugar tan perfecto para nosotros: bajo el antiguo ayuntamiento. La Orden cree habernos aniquilado, pero solo ha sido un recordatorio de lo que puede pasar al descuidarnos.",,"Tämähän on täydellinen paikka meille, vanhan kaupungintalon alla. Veljeskunta luulee hävittäneensä meidät, mutta se toimi meille ainoastaan muistutuksena siitä, mitä voi tapahtua, kun tulee varomattomaksi.","Quel endroit parafait pour nous, sous la mairie. L'Ordre pense qu'ils nous ont tous tués, mais ça leur servira de leçon, ils verront se qu'il se passe quand on ne fait pas attention..","A városháza alatt, micsoda tökéletes hely. A Rend azt hiszi kiírtott mindőnket, de ez csak egy emlékeztető volt arra, hogy mi történik ha felelőtlenek vagyunk.","È davvero un posto perfetto per noi, sotto il vecchio municipio. L'Ordine pensa di averci spazzato via, ma è stato solo un avvertimento di cosa può succederci se siamo troppo incauti.","旧市庁舎の下で、 私たちにとって何という完璧な場所です。 秩序は彼らが私たちを消滅させたと考 えていますが、それがすべてだったのは あなたが不注意になったときに起こり得ることを -私たちに思い出させるものです。","정말 경치 좋지? 이 박살 난 시청 주변에서. 오더 놈들이 우리들을 전멸했다고 자랑하는데, 우리들이 힘을 모아서 복수하기 전까진 그렇게 놓아두는 게 좋을 것 같아.","Wat een perfecte plek voor ons, onder het oude stadhuis. De Orde denkt dat ze ons hebben weggevaagd, maar het enige wat ons eraan herinnert is wat er kan gebeuren als je onzorgvuldig wordt.",,"Que lugar perfeito para nós, abaixo da antiga prefeitura. A Ordem pensa que nos aniquilou, mas aquilo tudo foi para lembrarmos do que pode acontecer quando você não é cauteloso.",,,"Здесь, под городской ратушей, такое чудесное место для нашей базы! Орден думает, что мы разгромлены, но мы всего лишь усвоили урок о цене беспечности.", -"Talk to Macil, he'll be able to help you.",TXT_DLG_SCRIPT34_D1516_TALKT,,,,Promluv si s Macilem. On ti pomůže.,Rede mit Macil. Er kann dir helfen.,,,"Habla con Macil, él podrá ayudarte.",,,Parlez à Macil. Il pourra vous aider.,,,マシルと話すんだ。彼から援助が得られるはず。,"마실 사령관님에게 말해, 그가 널 도울 수 있을 거야.","Praat met Macil, hij zal je kunnen helpen.",,Fale com o Macil. Ele vai poder te ajudar.,,,Обратись к Мэйсилу. Он поможет тебе., -I've heard that Macil's going to start something again soon. We need a big hit after the last fiasco. One more like that and we'll be too weak to continue.,TXT_DLG_SCRIPT34_D3032_IVEHE,,,,"Slyšel jsem, že Macil má v plánu brzy něco znovu podniknout. Potřebujeme něco velkého po posledním fiasku. Ještě jednou něco takového a budeme příliš slabí pokračovat.","Ich habe gehört, Macil hätte einen Plan um den Orden zu unterwandern. Ich hoffe mal, er taugt was. Noch ein Fehlschlag und wir können uns gleich begraben lassen.",,,He oído que Macil va a empezar algo nuevo pronto. Necesitamos un buen golpe después del último fiasco. Uno más como ese y seremos demasiado débiles para continuar.,,,J'entends que Macil va essayer de faire quelque chose bientôt. Il nous faut frapper un grand coup après le dernier fiasco. Encore un comme celui-ci et on sera trop affaibli pour continuer.,,,"私はマシルがオーダーを転覆させる計画を +私たちに思い出させるものです。","정말 경치 좋지? 이 박살 난 시청 주변에서. 오더 놈들이 우리들을 전멸했다고 자랑하는데, 우리들이 힘을 모아서 복수하기 전까진 그렇게 놓아두는 게 좋을 것 같아.","Wat een perfecte plek voor ons, onder het oude stadhuis. De Orde denkt dat ze ons hebben weggevaagd, maar het enige wat ons eraan herinnert is wat er kan gebeuren als je onzorgvuldig wordt.","For et perfekt sted for oss, under det gamle rådhuset. Ordenen tror de har utslettet oss, men det var bare en påminnelse om hva som kan skje når man er uforsiktig.","Co za idealne miejsce dla nas, pod starym ratuszem. Zakon myśli, że nas wymazał, ale to było tylko przypomnienie nam, co może się stać, gdy staniesz się nieostrożny.","Que lugar perfeito para nós, abaixo da antiga prefeitura. A Ordem pensa que nos aniquilou, mas aquilo tudo foi para lembrarmos do que pode acontecer quando você não é cauteloso.",,"Ce loc perfect pentru noi, exact sub vechea hală a orașului. Oridnul crede că ne-a ras pe toți, dar a fost doar o amintire pentru ceea ce se poate întâmpla când devi neglijent.","Здесь, под городской ратушей, такое чудесное место для нашей базы! Орден думает, что мы разгромлены, но мы всего лишь усвоили урок о цене беспечности.",,"Vilken perfekt plats för oss, under det gamla stadshuset. Orden tror att de har utplånat oss, men det var bara en påminnelse för oss om vad som kan hända när man blir oförsiktig.","Bizim için ne mükemmel bir yer, eski belediye binasının altı. Tarikat bizi yok ettiklerini sanıyor ama bu bize dikkatsiz davrandığımızda neler olabileceğini hatırlattı." +"Talk to Macil, he'll be able to help you.",TXT_DLG_SCRIPT34_D1516_TALKT,MAP34,,,Promluv si s Macilem. On ti pomůže.,"Tal med Macil, han vil kunne hjælpe dig.",Rede mit Macil. Er kann dir helfen.,,Parolu kun Macil. Li povos helpi vin.,Habla con Macil. Él te podrá ayudar.,Habla con Macil. Él te va a poder ayudar.,Puhu Macilille. Hän pystyy auttamaan sinua.,Parlez à Macil. Il pourra vous aider.,"Beszélj Macillal, majd ő segít.","Parla con Macil, lui sarà in grado di aiutarti.",マシルと話すんだ。彼から援助が得られるはず。,"마실 사령관님에게 말해, 그가 널 도울 수 있을 거야.","Praat met Macil, hij zal je kunnen helpen.",Snakk med Macil. Han kan hjelpe deg.,"Porozmawiaj z Macil, on będzie w stanie ci pomóc.",Fale com o Macil. Ele vai poder te ajudar.,,"Vorbește cu Macil, el te poate ajuta.",Обратись к Мэйсилу. Он поможет тебе.,,"Prata med Macil, han kommer att kunna hjälpa dig.","Macil'le konuş, sana yardım edebilir." +I've heard that Macil's going to start something again soon. We need a big hit after the last fiasco. One more like that and we'll be too weak to continue.,TXT_DLG_SCRIPT34_D3032_IVEHE,MAP34: Barracks.,,,"Slyšel jsem, že Macil má v plánu brzy něco znovu podniknout. Potřebujeme něco velkého po posledním fiasku. Ještě jednou něco takového a budeme příliš slabí pokračovat.","Jeg har hørt, at Macil snart vil starte noget igen. Vi har brug for et stort hit efter den sidste fiasko. En mere af den slags, og vi vil være for svage til at fortsætte.","Ich habe gehört, Macil hätte einen Plan um den Orden zu unterwandern. Ich hoffe mal, er taugt was. Noch ein Fehlschlag und wir können uns gleich begraben lassen.",,"Mi aŭdis, ke Macil baldaŭ komencos ion novan. Ni bezonas grandan trafon post la lasta fiasko: ankoraŭ unu kaj ni estos sufiĉe malfortaj por daŭrigi.",He oído que Macil va a empezar algo nuevo pronto. Necesitamos algo bueno después del último fiasco: uno más así y seremos demasiado débiles para continuar.,Oí que Macil va a empezar algo nuevo pronto. Necesitamos algo bueno después del último fracaso: uno más así y vamos a ser demasiado débiles para continuar.,"Kuulin, että Macil alkaa taas viritellä jotain. Tarvitsemme jättionnistumisen edellisen fiaskon jälkeen. Vielä yksikin samanlainen, ja olemme liian heikkoja jatkamaan.",J'entends que Macil va essayer de faire quelque chose bientôt. Il nous faut frapper un grand coup après le dernier fiasco. Encore un comme celui-ci et on sera trop affaibli pour continuer.,"Az a hír járja, hogy Macil újra készül valamire. Kell egy nagy fogás a múltkori fiaskó után. Még egy ilyen, és túl gyengék leszünk a folytatáshoz.",Ho sentito che Macil ha intenzione di partire all'attacco molto presto. Abbiamo bisogno di un grosso colpo dopo l'ultimo disastro. Se subiamo un'altra sconfitta del genere saremo troppo deboli per continuare.,"私はマシルがオーダーを転覆させる計画を 持っていると聞いた。そうだと良かったが。 -我々は一度大敗し全滅しかけた。",마실 사령관이 또 다른 작전을 준비한데. 그전에 일어났던 대참사보다 훨씬 나은 작전이었으면 좋겠는데. 운이 나쁘면 많은 병력을 잃어버릴 것 같아.,Ik heb gehoord dat Macil binnenkort weer met iets gaat beginnen. We hebben een grote hit nodig na het laatste fiasco. Nog zo'n hit en dan zijn we te zwak om verder te gaan.,,Fiquei sabendo que o Macil planeja começar algo logo. Precisamos acertar um grande golpe depois do último fiasco. Se aquilo se repetir nós não teremos força para continuar.,,,"Я слышал, что Мэйсил готовит новую операцию после провала предыдущей. Она должна быть крайне успешной. После второго такого провала мы уже не оправимся.", -A few of these barrels dumped into their water supply should even the odds a little. ,TXT_DLG_SCRIPT34_D4548_AFEWO,,,,Pár těhle sudů v jejich zásobách vody by nám mělo alespoň trochu pomoct.,"Wenn wir ein paar von diesen Fässern in die Wasserversorgung kippen, sollte das unsere Chancen etwas verbessern.",,,Unos cuantos de estos barriles arrojados a su suministro de agua debería igualar las probabilidades un poco.,,,Quelques tonneaux vidés dans leur réserve d'eau devrait aplanir le terrain de jeu.,,,"ここの樽は捨てられていた物で -彼らの給水を補っている。","놈들의 상수도에서 내려온 이 통들, 이상하지 않아? 뭔가 승산이 있을 것 같아.","Een paar van deze vaten die in hun watertoevoer gedumpt worden, zullen de kans op een beetje gelijk zijn.",,Alguns desses barris despejados no estoque de água deles deve melhorar um pouco as nossas chances.,,,"Несколько таких бочек, сброшенных в их водоснабжение, причинят немало неприятностей.", -I'm working on something that will give us an edge. It will increase your stamina and completely jack you up. I've almost got all the bugs worked out. Can I do something for you? ,TXT_DLG_SCRIPT34_D6064_IMWOR,,,,"Pracuju na něčem, co by nám mělo pomoci. Přidá ti to výdrž a naprosto tě to napumpuje. Už jsem skoro vychytal všechny mouchy. Co pro tebe mohu udělat?","Ich arbeite an etwas, das uns einen Vorteil verschaffen kann. Es würde deine Ausdauer erhöhen und dir Superkräfte verleihen. Kann ich was für dich tun?",,,Estoy trabajando en algo que nos dará una ventaja. Aumentará tu aguante y te pondrá a tope. Casi tengo todos los fallos corregidos. ¿Puedo hacer algo por ti?,,,Je travaille sur quelque chose qui nous donnera un peu d'avance. Ca devrait augmenter votre endurance et vous donner un sacré coup de jus. Je crois que j'ai corrigé presque tous les bugs. Je peux vous aider?,,,"私は研究にも取り組んでいる。貴方のスタミナを +我々は一度大敗し全滅しかけた。",마실 사령관이 또 다른 작전을 준비한데. 그전에 일어났던 대참사보다 훨씬 나은 작전이었으면 좋겠는데. 운이 나쁘면 많은 병력을 잃어버릴 것 같아.,Ik heb gehoord dat Macil binnenkort weer met iets gaat beginnen. We hebben een grote hit nodig na het laatste fiasco. Nog zo'n hit en dan zijn we te zwak om verder te gaan.,"Jeg har hørt at Macil skal starte noe igjen snart. Vi trenger en stor hit etter den siste fiaskoen. En til, så er vi for svake til å fortsette.","Słyszałem, że Macil ma zamiar wkrótce znowu coś zacząć. Potrzebujemy dużego uderzenia po ostatnim fiasku. Jeszcze jedno takie i będziemy zbyt słabi, by kontynuować.",Fiquei sabendo que o Macil planeja começar algo logo. Precisamos acertar um grande golpe depois do último fiasco. Se aquilo se repetir nós não teremos força para continuar.,,Am auzit că Macil va începe ceva curând. Trebuie să dăm lovitura după ultimul fiasco. Încă unul și vom fi prea slabi să continuăm.,"Я слышал, что Мэйсил готовит новую операцию после провала предыдущей. Она должна быть крайне успешной. После второго такого провала мы уже не оправимся.",,Jag har hört att Macil snart ska starta något igen. Vi behöver en stor succé efter det senaste fiaskot. En sån där till och vi blir för svaga för att fortsätta.,Macil'in yakında yeniden bir şeyler başlatacağını duydum. Son fiyaskodan sonra büyük bir vuruşa ihtiyacımız var. Bir daha böyle bir şey olursa devam edemeyecek kadar zayıf düşeriz. +A few of these barrels dumped into their water supply should even the odds a little. ,TXT_DLG_SCRIPT34_D4548_AFEWO,〃,,,Pár těhle sudů v jejich zásobách vody by nám mělo alespoň trochu pomoct.,Et par af disse tønder dumpet i deres vandforsyning burde udligne oddsene lidt.,"Wenn wir ein paar von diesen Fässern in die Wasserversorgung kippen, sollte das unsere Chancen etwas verbessern.",,Ĵeti kelkajn el ĉi tiuj bareloj en ilian akvo-provizadon devus egaligi iomete la eblojn.,Tirar unos cuantos de estos barriles a su suministro de agua debería igualar un poco las probabilidades.,,Muutaman tällaisen tynnyrin kaataminen heidän vedenjakeluunsa varmaankin hieman tasoittaisi tilannetta.,Quelques tonneaux vidés dans leur réserve d'eau devrait aplanir le terrain de jeu.,Kicsit kiegyenlíti az erőviszonyokat ha ezt a pár hordót beleöntjük a víztározójukba.,Un paio di questi barili rovesciati dentro la loro fornitura d'acqua dovrebbero bilanciare un po' le cose.,"ここの樽は捨てられていた物で +彼らの給水を補っている。","놈들의 상수도에서 내려온 이 통들, 이상하지 않아? 뭔가 승산이 있을 것 같아.","Een paar van deze vaten die in hun watertoevoer gedumpt worden, zullen de kans op een beetje gelijk zijn.",Et par av disse tønnene dumpet i vannforsyningen deres burde jevne ut oddsene litt.,Kilka tych beczek wrzuconych do ich wodociągów powinno trochę wyrównać szanse.,Alguns desses barris despejados no estoque de água deles deve melhorar um pouco as nossas chances.,,Câteva butoaie aruncate în rezerva lor de apă ar trebui să egaleze șansele.,"Несколько таких бочек, сброшенных в их водоснабжение, причинят немало неприятностей.",,Några av de här tunnorna dumpade i deras vattenförsörjning borde jämna ut oddsen lite.,Bu varillerden birkaçını su kaynaklarına boşaltmak olasılıkları biraz olsun eşitler. +I'm working on something that will give us an edge. It will increase your stamina and completely jack you up. I've almost got all the bugs worked out. Can I do something for you? ,TXT_DLG_SCRIPT34_D6064_IMWOR,"MAP34: Gerald. +(Except for row 1335, everything in rows 1323-1343 is identical to 725-745)",,,"Pracuju na něčem, co by nám mělo pomoci. Přidá ti to výdrž a naprosto tě to napumpuje. Už jsem skoro vychytal všechny mouchy. Co pro tebe mohu udělat?","Jeg arbejder på noget, der vil give os en fordel. Det vil øge din udholdenhed og gøre dig helt oppe at køre. Jeg har næsten fået styr på alle fejlene. Må jeg gøre noget for dig?","Ich arbeite an etwas, das uns einen Vorteil verschaffen kann. Es würde deine Ausdauer erhöhen und dir Superkräfte verleihen. Kann ich was für dich tun?",,"Mi laboras super io, kio donos avantaĝon al ni: ĝi pliigos vian energion kaj korpan forton. Mi jam korektis la plimulton de la cimoj. Ĉu mi povas fari ion por vi?",Estoy trabajando en algo que nos dará una ventaja: aumentará tu aguante y fuerza física. Ya casi tengo todos los fallos corregidos. ¿Puedo hacer algo por ti?,Estoy trabajando en algo que nos va a dar una ventaja: va a aumentar tu aguante y fuerza física. Ya casi tengo todos los fallos corregidos. ¿Puedo hacer algo por ti?,"Olen paraikaa työstämässä jotain, joka antaa meille etulyöntiaseman. Se kasvattaa kuntoasi ja täydellisesti virittää lihaksesi. Olen melkein saanut hiottua kaikki viat. Voinko olla jotenkin avuksi?",Je travaille sur quelque chose qui nous donnera un peu d'avance. Ca devrait augmenter votre endurance et vous donner un sacré coup de jus. Je crois que j'ai corrigé presque tous les bugs. Je peux vous aider?,"Dolgozok valamin, ami egy jelentősebb előnyhöz juttat minket. Megerősíti az állóképességedet és teljesen felpumpálja a tested. Már majdnem kiküszöböltem a hibákat. Amúgy tudok valamiben segíteni?",Sto lavorando a qualcosa che ci darà un notevole vantaggio. Aumenterà la tua resistenza e ti farà sentire molto più forte. Ho quasi risolto tutti gli effetti collaterali. Posso fare qualcosa per te?,"私は研究にも取り組んでいる。貴方のスタミナを 増強し完璧な体にすることも可能だ。 そのインプラントのバグも殆ど取り除かれている -ところで何か必要かい?","아주 유용하고 승패를 가릴 수 있는 비장의 카드를 연구 중입니다. 바로 지구력 향상 이식 칩이죠. 이것만 있으면 체력과 힘을 증가시킵니다. 거의 완성되었어요. 이제, 뭘 도와드릴까요?",Ik werk aan iets dat ons een voorsprong geeft. Het zal je uithoudingsvermogen verhogen en je helemaal opkrikken. Ik heb bijna alle bugs uitgewerkt. Kan ik iets voor u doen?,,Estou trabalhando em algo que vai nos dar um impulso. É algo que vai aumentar sua resistência e te deixar bem mais forte. Estou com quase todos os bugs resolvidos. Posso te ajudar com algo?,,,"Я работаю кое над чем, что может нам пригодиться. Оно увеличит твою выносливость и улучшит самочувствие. Я уже исправил почти все дефекты. Или тебе нужно что-то ещё?", -Patch me up.,TXT_RPLY0_SCRIPT34_D6064_PATCH,,,,Dej mě do hromady.,Flick mich zusammen.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료가 필요합니다.,Patch me op.,,Trate meus ferimentos.,,,Перебинтуй меня., -"Boy, you're a real mess. I'll see what I can do.",TXT_RYES0_SCRIPT34_D6064_BOYYO,,,,"Tebe teda zřídili, kluku. Uvidím, co s tebou.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,,"Chico, estás hecho un desastre. Veré que puedo hacer.",,,"Mon petit, vous êtes dans un sale état. Je vais voir ce que je peux faire.",,,君、滅茶苦茶だな。なんとかしよう。,가능한 한 아프지 않게 치료하겠습니다.,"Jongen, je bent een echte puinhoop. Ik zal zien wat ik kan doen.",,"Rapaz, você está arrebentado. Verei o que posso fazer.",,,"Ты просто месиво. Посмотрим, что я смогу сделать.", -Stamina implant?,TXT_RPLY1_SCRIPT34_D6064_STAMI,,,,Implantát pro výdrž?,Ausdauerimplantat?,,,¿Implante de aguante?,,,Implant d'endurance?,,,スタミナインプラント?,지구력 향상 이식?,Stamina implantaat?,,Implante de resistência?,,,Выносливостный имплант?, -All right this won't take but a moment.,TXT_RYES1_SCRIPT34_D6064_ALLRI,,,,"Dobře, tohle potrvá jen chvilku.","Alles klar, das haben wir sofort.",,,"Muy bien, esto solo tomará un momento.",,,"Pas de problème, ça ne prendra qu'un moment.",,,大丈夫、すぐ終わります。,많이 걸리진 않을거에요...,"Oké, dit duurt maar een momentje.",,"Ok, isso não vai demorar.",,,"Отлично, это займёт всего пару секунд.", -It's not done yet.,TXT_RNO1_SCRIPT34_D6064_ITSNO,,,,Ještě není hotový.,Es ist noch nicht soweit.,,,Aún no está listo.,,,Ce n'est pas encore terminé.,,,まだ完成していません。,연구가 진행중입니다. 나중에.,Het is nog niet klaar.,,Ainda não terminei.,,,Он ещё не готов., -"Hey, I'm working on an updated version of your implant. Is there anything else I can do?",TXT_DLG_SCRIPT34_D7580_HEYIM,,,,"Hej, pracuju na vylepšené verzi tvého implantátu. Můžu pro tebe udělat něco jiného?","He, ich arbeite an einer verbesserten Version deines Implantats. Gibt es sonst etwas, das ich für dich tun kann?",,,"Hey, estoy trabajando en una versión actualizada de tu implante. ¿Hay algo que pueda hacer por ti?",,,"Hé, je travaille sur une version améliorée de l'implant. Qu'est-ce que je peux faire pour vous?",,,"どうも、私は今最新版のインプラントに -取り組んでいる。何か用かな?","여어! 이식 칩을 향상할 개조를 받고 싶으신가요? 아니라면, 뭐가 필요합니까?","Hé, ik ben bezig met een bijgewerkte versie van je implantaat. Is er nog iets anders dat ik kan doen?",,E aí. Estou trabalhando numa versão aprimorada do seu implante. Posso te ajudar com mais alguma coisa?,,,"Я работаю над улучшенной версией твоего импланта. А пока, что-нибудь ещё?", -Patch me up.,TXT_RPLY0_SCRIPT34_D7580_PATCH,,,,Dej mě do hromady.,Flick mich zusammen.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료가 필요합니다.,Patch me op.,,Trate meus ferimentos.,,,Перебинтуй меня., -Well at least you're seeing action.,TXT_RYES0_SCRIPT34_D7580_WELLA,,,,"No, alespoň jsi v akci.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,,"Bueno, al menos ves algo de acción.",,,"Eh bien, au moins vous en voyez, de l'action.",,,少なくとも行動を起こしているのです。,이제 마음껏 움직여보세요.,"Nou ja, je ziet in ieder geval actie.",,"Bem, pelo menos está tendo um pouco de ação.",,,"Что ж, зато ты участвуешь в операциях.", -Implant upgrade?,TXT_RPLY1_SCRIPT34_D7580_IMPLA,,,,Vylepšení implantátu?,Implantatsupgrade?,,,¿Mejora de implante?,,,Mise à jour de l'implant?,,,インプラント アップグレード?,지구력 업그레이드?,Implantaat upgrade?,,Versão aprimorada do implante?,,,Улучшение импланта?, -"Good thing, never can be too safe.",TXT_RYES1_SCRIPT34_D7580_GOODT,,,,"Dobrá věcička, nikdy si nemůžeš být moc jistý.","Alles klar, das haben wir sofort.",,,"Cosa buena, nunca se puede estar seguro del todo.",,,Bonne idée. On ne peut jamais être trop sûr.,,,良いことだ、安全すぎることはない。,위험 할 때도 있으니 지금 고치겠습니다.,"Goede zaak, kan nooit te veilig zijn.",,Boa ideia. Segurança nunca é demais.,,,"Очень советую, ни в чём нельзя быть уверенным до конца.", -"I'm almost finished, but not quite.",TXT_RNO1_SCRIPT34_D7580_IMALM,,,,"Už je skoro hotový, ale ne úplně.",Es ist noch nicht soweit.,,,"Casi he terminado, pero no del todo.",,,"Presque fini, mais pas encore.",,,もうすぐ出来上がる、それほど掛からない。,거의 완성했는데... 아마도 다음 시간에?,"Ik ben bijna klaar, maar niet helemaal.",,Está quase pronto.,,,Я почти закончил. Ещё немного., -"All right, this is it. I've almost got everything working perfectly. There were a few problems left to fix, do you need anything else? ",TXT_DLG_SCRIPT34_D9096_ALLRI,,,,"Tak dobře, už mi skoro všechno perfektně funguje. Ještě tam bylo pár problémů. Potřebuješ ještě něco?","He, ich arbeite an einer verbesserten Version deines Implantats. Gibt es sonst etwas, das ich für dich tun kann?",,,"Muy bien, esto es todo. Casi tengo todo funcionando perfectamente. Hubo algunos problemas restantes para arreglar, ¿necesitas alguna otra cosa?",,,"Très bien, je crois que j'ai réussi à tout faire marcher parfaitement. Il y avait quelques problèmes dont je devais me débarrasser. Vous voulez quelque chose?",,,"大丈夫、全て順調だ。残っていた問題も -全て取り除かれた。他に何が必要かな?","정말 힘든 시간이었어요. 이식 칩의 문제들의 거의 다 고쳐가고 있습니다. 기다리는 동안, 무엇을 도와드릴까요?","Goed, dit is het. Ik heb bijna alles perfect werkend. Er waren nog een paar problemen op te lossen, heb je nog iets anders nodig?",,"Ok, é isso aí. Está quase tudo funcionando perfeitamente. Faltavam alguns problemas pra consertar. Precisa de mais algo?",,,"Итак, тут оставалась пара проблем, но теперь всё работает почти идеально. Что-нибудь ещё?", -Patch me up.,TXT_RPLY0_SCRIPT34_D9096_PATCH,,,,Dej mě do hromady.,Flick mich zusammen.,,,Cúrame.,,,Soignez moi.,,,治療してほしい。,치료가 필요합니다.,Patch me op.,,Trate meus ferimentos.,,,Перебинтуй меня., -What have you been trying to do? Go head to head with a Crusader?,TXT_RYES0_SCRIPT34_D9096_WHATH,,,,Co jsi dělal? Šel zmlátit Křižáka?,"Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,,¿Qué has intentado hacer? ¿Encabezonarte con un cruzado?,¿Qué has intentado hacer? ¿Pelear cabeza a cabeza contra un cruzado?,,Qu'est-ce que vous avez fait? Vous avez essayé de faire ami avec un Croisé?,,,"今度は何を始めるんだ? -クルセイダーと向かい合うのか?",아콜라이트와 근접전을 펼친 것 같군요... 아마도.,Wat heb je geprobeerd te doen? Hoofd aan hoofd gaan met een kruisvaarder?,,O que andou tentando fazer? Sair na porrada com um Cruzado?,,,"Ты что, бился один на один с крестоносцем?", -Implant upgrade?.,TXT_RPLY1_SCRIPT34_D9096_IMPLA,,,,Vylepšení implantátu?,Implantatsupgrade?,,,¿Mejora de implante?,,,Mise à jour de l'implant?,,,インプラント アップグレード?,지구력 업그레이드?,Implantaat upgrade?.,,Aprimoramento de implante?,,,Улучшение импланта?, -That should do it for you.,TXT_RYES1_SCRIPT34_D9096_THATS,,,,Tohle by mělo fungovat.,"Alles klar, das haben wir sofort.",,,Esto te debería servir.,,,Ca devrait faire l'affaire.,,,今取り掛かっている。,도움이 좀 될 거에요.,Dat zou het voor je moeten doen.,,Isso deve funcionar pra você.,,,Вот оно., -Let me run some more tests first.,TXT_RNO1_SCRIPT34_D9096_LETME,,,,Ještě ho musím dál otestovat.,Es ist noch nicht soweit.,,,Déjame hacer algunas pruebas primero.,,,Laissez moi faire quelques tests d'abord.,,,もう少しテストしてからにしよう。,시험단계를 좀 거치고 예기할게요.,Laat me eerst nog wat testen doen.,,Só deixa eu fazer mais alguns testes.,,,Дай мне ещё времени на тесты., -That's all I can do on the implant right now. Maybe some healing?,TXT_DLG_SCRIPT34_D10612_THATS,,,,"Tak, to je všechno co teď můžu s tím implantátem udělat. Potřebuješ léčení?","Das ist alles, was ich im Moment mit dem Implantat machen kann. Vielleicht etwas medizinische Versorgung?",,,Eso es todo lo que puedo hacer con el implante por ahora. ¿Qué tal una cura?,,,C'est tout ce que je peux faire pour l'implant. Vous voulez que je vous soigne?,,,"インプラントはこれ以上ない程完成した。 -それとも治療か?",이식 칩에 관한 모든 걸 해줬습니다. 더 필요한 게 있나요?,Dat is alles wat ik nu kan doen op het implantaat. Misschien wat genezing?,,Isso é tudo o que posso fazer com o implante no momento. Vai uma cura aí?,,,Пока что я больше ничего не могу сделать с имплантом. Как насчёт лечения?, -Yeah.,TXT_RPLY0_SCRIPT34_D10612_YEAH,,,,Jo.,Ja.,,Jes.,Sí.,,,Ouais.,,,ああ。,그래.,Ja.,,Sim.,,,Давай., -"Boy, you're a real mess. I'll see what I can do.",TXT_RYES0_SCRIPT34_D10612_BOYYO,,,,"Tebe teda zřídili, kluku. Uvidím, co s tebou.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,,"Chico, estás hecho un desastre. Veré que puedo hacer.",,,"Mon petit, vous êtes dans un sale état. Je vais voir ce que je peux faire.",,,君、滅茶苦茶だな。なんとかしよう。,치료가 다 끝났습니다. 다 의료기술 덕입니다.,"Jongen, je bent een echte puinhoop. Ik zal zien wat ik kan doen.",,"Rapaz, você está arrebentado. Verei o que posso fazer.",,,"Ты просто месиво. Посмотрим, что я смогу сделать.", -What can I do for you?,TXT_DLG_SCRIPT34_D12128_WHATC,,,,Co pro tebe můžu udělat?,Was kann ich für dich tun?,,,¿Qué puedo hace por ti?,,,Que puis-je faire pour vous?,,,それで何か用か?,무엇을 도와줄까.,Wat kan ik voor je doen?,,Como posso te ajudar?,,,Чем я могу тебе помочь?, -I'm out of bullets.,TXT_RPLY0_SCRIPT34_D12128_IMOUT,,,,Došly mi náboje.,Ich habe keine Munition mehr.,,,No me quedan balas.,,,Je suis à cours de munitions.,,,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,,Estou sem munição.,,,У меня кончились патроны., -Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT34_D12128_HERES,,,,"Tady máš nějakou munici, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,Aquí tienes un poco de munición. No la desperdicies.,,,"En voilà pour vous, ne les gaspillez pas.",,,無駄遣いするなよ。,조금만 주겠습니다. 재고가 모자라거든요.,Hier is wat munitie voor je. Verspil het niet.,,Leve esta munição. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -Teach me.,TXT_RPLY1_SCRIPT34_D12128_TEACH,,,,Uč mě.,Unterrichte mich.,,,Enséñame.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,,Me ensine.,,,Обучи меня., -"All right, I'll just show you a few little pointers.",TXT_RYES1_SCRIPT34_D12128_ALLRI,,,,"Dobře, ukážu ti pár rad.","Alles klar, ich zeige dir ein paar Kniffe.",,,"Muy bien, te daré algunos pequeños consejos.",,,Pas de problème. Laissez moi vous montrer quelques trucs.,,,わかった、幾つかやり方を教えよう。,좋습니다. 움직이는 과녁을 쏘세요!,"Oké, ik zal je gewoon een paar kleine tips laten zien.",,"Ok, vou te dar algumas dicas.",,,Хорошо. Покажу тебе пару приёмов., -You're not ready yet.,TXT_RNO1_SCRIPT34_D12128_YOURE,,,,Ještě nejsi připravený.,Du bist noch nicht so weit.,,,Aún no estás listo.,,,Vous n'êtes pas encore prêt.,,,そっちの準備がまだ整ってないようだな。,당신은 아직 준비가 안됐어요.,Je bent nog niet klaar.,,Você não está preparado ainda.,,,Ты ещё не готов., -Back again? What do you need?,TXT_DLG_SCRIPT34_D13644_BACKA,,,,Zase zpátky? Co potřebuješ?,Scxhon zurück? Was brauchst du?,,,¿De vuelta otra vez? ¿Qué necesitas?,,,Déjà de retour? De quoi avez-vous besoin?,,,もう戻ったか?何が必要だ?,다시 왔군요. 무엇이 필요하죠?,Weer terug? Wat heb je nodig?,,Já voltou? O que precisa?,,,Ты вернулся? Что тебе нужно?, -I'm out of bullets.,TXT_RPLY0_SCRIPT34_D13644_IMOUT,,,,Došly mi náboje.,Ich habe keine Munition mehr.,,,No me quedan balas.,,,Je suis à cours de munitions.,,,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,,Estou sem munição.,,,У меня кончились патроны., -Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT34_D13644_HERES,,,,"Tady máš nějakou munici, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,Aquí tienes un poco de munición. No la gastes.,,,"En voilà pour vous, ne les gaspillez pas.",,,この弾を使え、無駄遣いするなよ。,"적을 사살하려면, 역시 탄약을 소진해야만 하죠. 여기 탄약입니다.",Hier is wat munitie voor je. Verspil het niet.,,Leve esta munição. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -You've got enough ammo.,TXT_RNO0_SCRIPT34_D13644_YOUVE,,,,Vždyť jich máš dost.,Du hast genug.,,,Tienes suficiente munición.,,,Vous avez assez de munitions.,,,もう十分に弾を持ってるようだぞ。,충분한 탄약을 가졌어. 다 소진하고 찾아오세요.,Je hebt genoeg munitie.,,Você já tem munição suficiente.,,,У тебя их достаточно., -Teach me.,TXT_RPLY1_SCRIPT34_D13644_TEACH,,,,Uč mě.,Unterrichte mich.,,,Enséñame.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,,Me ensine.,,,Обучи меня., -"All right, this should keep you going for a while.",TXT_RYES1_SCRIPT34_D13644_ALLRI,,,,"Dobře, tohle by ti mělo pomoct.","Alles klar, das sollte fürs erste reichen.",,,"Muy bien, esto te mantendrá a punto durante un tiempo.",,,"Bien, ça devrait vous suffir pour un bon moment.",,,わかった、これで長くやり合えるだろう。,"여기, 적병 일부를 충분히 죽일 수 있을 만큼의 탄약입니다.","Oké, dit zou je een tijdje op de been moeten houden.",,"Ok, isso deve te ajudar por enquanto.",,,"Хорошо, это не раз спасёт тебе жизнь.", -"Sorry, can't. I'm just following Macil's orders.",TXT_RNO1_SCRIPT34_D13644_SORRY,,,,"Promiň, nemůžu. Řídím se rozkazy od Macila.","Tut mir leid, aber ich kann nicht. Ich folge nur Macils Befehlen.",,,"Lo siento, no puedo. Solo sigo órdenes de Macil.",,,"Désolé, pas possible. Je ne fais que suivre les ordres de Macil.",,,すまないが、できない。マシルの命令だ。,마실 사령관님의 명령입니다. 그럴 수는 없어요.,"Sorry, dat kan niet. Ik volg gewoon de orders van Macil op.",,Desculpe mas não posso. Só estou seguindo as ordens do Macil.,,,"Увы, не могу. Я подчиняюсь Мэйсилу.", -"Well which is it, bullets or training? I can't wait to get my hands on those new weapons we captured. Once I get done with them, I'll be able to begin training everyone else.",TXT_DLG_SCRIPT34_D15160_WELLW,,,,"Tak co to bude, náboje nebo trénink? Nemůžu se dočkat, až se dostanu k těm novým zbraním, které jsme zabavili. Trocha cvičení a pak hodně odplaty.","Also, was willst du? Munition oder Training? Ich kann kaum erwarten, diese neuen Waffen, die wir erbeutet haben, in die Finger zu kriegen. ein bisschen Training und dann jede Menge Vergeltung.",,,"Bueno ¿qué va a ser?, ¿balas o entrenamiento? No puedo esperar a tener en mis manos esas nuevas armas que hemos capturado. En cuanto termine con ellas, podré empezar a entrenar al resto.",,,"Qu'est-ce qu'il vous faut? Des munitions ou de l'entraînement? J'ai hâte d'essayer ces nouvelles armes que l'on a capturé. Quand j'en aurai fini avec elles, je pourrai entraîner tout le monde.",,,"弾薬と訓練、どっちの用件だ? +ところで何か必要かい?","아주 유용하고 승패를 가릴 수 있는 비장의 카드를 연구 중입니다. 바로 지구력 향상 이식 칩이죠. 이것만 있으면 체력과 힘을 증가시킵니다. 거의 완성되었어요. 이제, 뭘 도와드릴까요?",Ik werk aan iets dat ons een voorsprong geeft. Het zal je uithoudingsvermogen verhogen en je helemaal opkrikken. Ik heb bijna alle bugs uitgewerkt. Kan ik iets voor u doen?,Jeg jobber med noe som vil gi oss en fordel. Det vil øke utholdenheten din og løfte deg helt opp. Jeg har nesten løst alle problemene. Kan jeg gjøre noe for deg?,"Pracuję nad czymś, co da nam przewagę. Zwiększy to twoją wytrzymałość i całkowicie cię podnieci. Mam już prawie dopracowane wszystkie błędy. Mogę coś dla ciebie zrobić?",Estou trabalhando em algo que vai nos dar um impulso. É algo que vai aumentar sua resistência e te deixar bem mais forte. Estou com quase todos os bugs resolvidos. Posso te ajudar com algo?,,Lucrez la ceva ce ne va da un avantaj. Îți va crește rezistența și forța. Am rezolvat aproape toate problemele. Pot să te ajut cu ceva acum?,"Я работаю кое над чем, что может нам пригодиться. Оно увеличит твою выносливость и улучшит самочувствие. Я уже исправил почти все дефекты. Или тебе нужно что-то ещё?",,Jag arbetar på något som kommer att ge oss en fördel. Det kommer att öka din uthållighet och göra dig helt upprymd. Jag har nästan löst alla buggar. Kan jag göra något för dig?,Bize avantaj sağlayacak bir şey üzerinde çalışıyorum. Dayanıklılığınızı arttıracak ve sizi tamamen güçlendirecek. Neredeyse tüm hataları çözdüm. Senin için bir şey yapabilir miyim? +Patch me up.,TXT_RPLY0_SCRIPT34_D6064_PATCH,〃,,,Dej mě do hromady.,Løs mig op.,Flick mich zusammen.,,Kuracu min.,Cúrame.,,Hoida minut kuntoon.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료가 필요합니다.,Patch me op.,Lappe meg sammen.,Załataj mnie.,Trate meus ferimentos.,,Bandajează-mă.,Перебинтуй меня.,,Laga mig.,Beni yamala. +"Boy, you're a real mess. I'll see what I can do.",TXT_RYES0_SCRIPT34_D6064_BOYYO,〃,,,"Tebe teda zřídili, kluku. Uvidím, co s tebou.","Mand, du er et rigtigt rod. Jeg skal se, hvad jeg kan gøre.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,"Ulo, vi estas iomege en malordo. +Mi vidos tion, kion mi faru.","Tío, estás hecho un desastre. +A ver qué puedo hacer.","Chico, estás hecho un desastre. +A ver qué puedo hacer.","Voi pojat, oletpa hajalla. Katsotaan, mihin pystyn.","Mon petit, vous êtes dans un sale état. Je vais voir ce que je peux faire.","Öregem, elég ramaty állapotban vagy. Megnézem mit tehetek.","Ragazzo, sei messo proprio male. Vediamo cosa posso fare.",君、滅茶苦茶だな。なんとかしよう。,가능한 한 아프지 않게 치료하겠습니다.,"Jongen, je bent een echte puinhoop. Ik zal zien wat ik kan doen.","Jøss, du ser forferdelig ut. Jeg skal se hva jeg kan gjøre.","Chłopcze, jesteś w niezłym stanie. Zobaczę, co da się zrobić.","Rapaz, você está arrebentado. Verei o que posso fazer.",,"Băiete, ești un dezastru. O să văd ce pot face.","Ты просто месиво. Посмотрим, что я смогу сделать.",,Du är en riktig röra. Jag ska se vad jag kan göra.,"Evlat, gerçekten berbat durumdasın. Ne yapabileceğime bir bakayım." +Stamina implant?,TXT_RPLY1_SCRIPT34_D6064_STAMI,〃,,,Implantát pro výdrž?,Udholdenhedsimplantat?,Ausdauerimplantat?,,Ĉu energidona enplantaĵo?,¿Implante de aguante?,,Kuntoistute?,Implant d'endurance?,Állóképesség implantátum?,Impianto stamina?,スタミナインプラント?,지구력 향상 이식?,Stamina implantaat?,Utholdenhetsimplantat?,Implant wytrzymałościowy?,Implante de resistência?,,Implant de rezistență?,Выносливостный имплант?,,Ett uthållighetsimplantat?,Dayanıklılık implantı mı? +"All right, this won't take but a moment.",TXT_RYES1_SCRIPT34_D6064_ALLRI,〃,,,"Dobře, tohle potrvá jen chvilku.","Okay, det tager kun et øjeblik.","Alles klar, das haben wir sofort.",,"Bonege, ĉi tio +estos rapidega.","Muy bien, solo +tomará un momento.","Muy bien, solo va a +tomar un momento.","Hyvä on, tähän ei mene hetkeä pidempään.","Pas de problème, ça ne prendra qu'un moment.","Rendben, nem vesz igénybe többet pár másodpercnél.","Va bene, ci vorrà solo un momento.",大丈夫、すぐ終わります。,많이 걸리진 않을거에요...,"Oké, dit duurt maar een momentje.",Dette tar bare et øyeblikk.,"Dobra, to zajmie tylko chwilę.","Ok, isso não vai demorar.",,"În regulă, va dura doar un moment.","Отлично, это займёт всего пару секунд.",,"Okej, det här tar bara ett ögonblick.","Pekala, bu bir dakikadan fazla sürmez." +It's not done yet.,TXT_RNO1_SCRIPT34_D6064_ITSNO,〃,,,Ještě není hotový.,Det er ikke færdigt endnu.,Es ist noch nicht soweit.,,"Mi ankoraŭ +prilaboras ĝin.",Aún no está listo.,,Se ei ole valmis vielä.,Ce n'est pas encore terminé.,Még nincs kész.,Non è ancora pronto.,まだ完成していません。,연구가 진행중입니다. 나중에.,Het is nog niet klaar.,Det er ikke ferdig ennå.,Jeszcze nie skończyłem.,Ainda não terminei.,,Încă nu e gata.,Он ещё не готов.,,Det är inte klart än.,Henüz bitmedi. +"Hey, I'm working on an updated version of your implant. Is there anything else I can do?",TXT_DLG_SCRIPT34_D7580_HEYIM,〃,,,"Hej, pracuju na vylepšené verzi tvého implantátu. Můžu pro tebe udělat něco jiného?","Jeg arbejder på en opdateret version af dit implantat. Er der andet, jeg kan gøre?","He, ich arbeite an einer verbesserten Version deines Implantats. Gibt es sonst etwas, das ich für dich tun kann?",,"Mi laboras super plibonigita versio de via enplantaĵo. Ĉu estas io alia, kion mi povas fari por vi?",Estoy trabajando en una versión mejorada de tu implante. ¿Hay algo más que pueda hacer?,,"Hei, olen työstämässä päivitettyä versiota istutteestasi. Voinko olla muuten avuksi?","Hé, je travaille sur une version améliorée de l'implant. Qu'est-ce que je peux faire pour vous?",Az implantátum újabb verzióján dolgozok. Tudok még valamiben segíteni?,"Ehi, sto lavorando ad un aggiornamento per l'impianto stamina. Posso fare qualcos'altro per te?","どうも、私は今最新版のインプラントに +取り組んでいる。何か用かな?","여어! 이식 칩을 향상할 개조를 받고 싶으신가요? 아니라면, 뭐가 필요합니까?","Hé, ik ben bezig met een bijgewerkte versie van je implantaat. Is er nog iets anders dat ik kan doen?",Jeg jobber med en oppdatert versjon av implantatet ditt. Er det noe annet jeg kan gjøre?,"Hej, pracuję nad unowocześnioną wersją twojego implantu. Czy mogę zrobić coś jeszcze?",E aí. Estou trabalhando numa versão aprimorada do seu implante. Posso te ajudar com mais alguma coisa?,,"Hei, lucrez la o variantă îmbunătățită a implantului tău. E ceva cu care pot să te ajut?","Я работаю над улучшенной версией твоего импланта. А пока, что-нибудь ещё?",,Jag jobbar på en uppdaterad version av ditt implantat. Finns det något annat jag kan göra?,"Hey, implantının güncellenmiş bir versiyonu üzerinde çalışıyorum. Yapabileceğim başka bir şey var mı?" +Patch me up.,TXT_RPLY0_SCRIPT34_D7580_PATCH,〃,,,Dej mě do hromady.,Gør mig klar.,Flick mich zusammen.,,Kuracu min.,Cúrame.,,Pistä minut kuntoon.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료가 필요합니다.,Patch me op.,Lappe meg sammen.,Załataj mnie.,Trate meus ferimentos.,,Bandajează-mă.,Перебинтуй меня.,,Laga mig.,Bana yama yap. +Well at least you're seeing action.,TXT_RYES0_SCRIPT34_D7580_WELLA,〃,,,"No, alespoň jsi v akci.",I det mindste er du i gang.,"Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,"Nu, almenaŭ vi ne havas +enuigajn komisiojn.","Bueno, al menos estás +teniendo algo de acción.",,"No, ainakin näet toimintaa.","Eh bien, au moins vous en voyez, de l'action.",Legalább ér valami izgalom.,"Beh, almeno ti stai dando da fare.",少なくとも行動を起こしているのです。,이제 마음껏 움직여보세요.,"Nou ja, je ziet in ieder geval actie.",Det skjer i det minste noe.,"Przynajmniej widzisz, że coś się dzieje.","Bem, pelo menos está tendo um pouco de ação.",,"Pă, măcar tu ai parte de niște acțiune.","Что ж, зато ты участвуешь в операциях.",,Du ser åtminstone till att det händer något.,En azından hareket görüyorsun. +Implant upgrade?,TXT_RPLY1_SCRIPT34_D7580_IMPLA,〃,,,Vylepšení implantátu?,Implantatopgradering?,Implantatsupgrade?,,Ĉu plibonigo de enplantaĵo?,¿Mejora de implante?,,Istutteen päivitys?,Mise à jour de l'implant?,Implantátum fejlesztés?,Aggiornamento dell'impianto?,インプラント アップグレード?,지구력 업그레이드?,Implantaat upgrade?,Implantatoppgradering?,Aktualizacja implantu?,Versão aprimorada do implante?,,Upgrade la implant?,Улучшение импланта?,,Implantatuppgradering?,İmplant güncellemesi mi? +"Good thing, never can be too safe.",TXT_RYES1_SCRIPT34_D7580_GOODT,〃,,,"Dobrá věcička, nikdy si nemůžeš být moc jistý.","Godt, man kan aldrig være for sikker.","Alles klar, das haben wir sofort.",,"Bone. Neniam estas +sufiĉe da sekureco.","Bien. Nunca se puede +estar del todo seguro.",,"Hyvä, koskaan ei voi olla liian turvallista.",Bonne idée. On ne peut jamais être trop sûr.,"Még jó, soha nem lehetsz túl nagy biztonságban.","Ottimo, non si può mai essere troppo al sicuro.",良いことだ、安全すぎることはない。,위험 할 때도 있으니 지금 고치겠습니다.,"Goede zaak, kan nooit te veilig zijn.","Bra, man kan aldri være for sikker.","To dobrze, nigdy nie można być zbyt bezpiecznym.",Boa ideia. Segurança nunca é demais.,,"Bine zis, nu poți fi niciodată prea sigur.","Очень советую, ни в чём нельзя быть уверенным до конца.",,"Bra, man kan aldrig vara för säker.","İyi bir şey, asla çok güvenli olamaz." +"I'm almost finished, but not quite.",TXT_RNO1_SCRIPT34_D7580_IMALM,〃,,,"Už je skoro hotový, ale ne úplně.","Jeg er næsten færdig, men ikke helt.",Es ist noch nicht soweit.,,"Mi preskaŭ finis, +sed ne tute.","Casi he terminado, +pero no del todo.",,"Olen melkein valmis, mutten ihan vielä.","Presque fini, mais pas encore.","Majdnem végeztem, de még nem teljesen","Ho quasi finito, ma non ancora.",もうすぐ出来上がる、それほど掛からない。,거의 완성했는데... 아마도 다음 시간에?,"Ik ben bijna klaar, maar niet helemaal.","Jeg er nesten ferdig, men ikke helt.","Prawie skończyłem, ale nie do końca.",Está quase pronto.,,"Sunt aproape gata, dar nu chiar.",Я почти закончил. Ещё немного.,,"Jag är nästan klar, men inte riktigt.",Neredeyse bitirdim ama tam değil. +"All right, this is it. I've almost got everything working perfectly. There were a few problems left to fix, do you need anything else? ",TXT_DLG_SCRIPT34_D9096_ALLRI,〃,,,"Tak dobře, už mi skoro všechno perfektně funguje. Ještě tam bylo pár problémů. Potřebuješ ještě něco?","Okay, det er det. Jeg har næsten fået det hele til at fungere perfekt. Der var et par problemer tilbage at løse, har du brug for andet?","He, ich arbeite an einer verbesserten Version deines Implantats. Gibt es sonst etwas, das ich für dich tun kann?",,"Bone, jen ĉio; preskaŭ ĉio funkcias perfekte. Restis nur kelkaj korektindaj problemoj. Ĉu vi bezonas ion alian?","Muy bien, ya está; tengo casi todo funcionando a la perfección. Solo quedaban algunos problemas que corregir. ¿Necesitas algo más?",,"No niin, olen melkein saanut kaiken toimimaan täydellisesti. Vain muutamia vikoja oli enää jäljellä. Tarvitsetko mitään muuta?","Très bien, je crois que j'ai réussi à tout faire marcher parfaitement. Il y avait quelques problèmes dont je devais me débarrasser. Vous voulez quelque chose?","Rendben, ez lesz az. Már majdnem mindent tökéletesre kidolgoztam. Már csak pár lehetőség van hátra, kell még valami esetleg?","Allora, sono riuscito a far funzionare quasi tutto benissimo. C'erano giusto un paio di problemi rimasti da risolvere. Ti serve qualcos'altro?","大丈夫、全て順調だ。残っていた問題も +全て取り除かれた。他に何が必要かな?","정말 힘든 시간이었어요. 이식 칩의 문제들의 거의 다 고쳐가고 있습니다. 기다리는 동안, 무엇을 도와드릴까요?","Goed, dit is het. Ik heb bijna alles perfect werkend. Er waren nog een paar problemen op te lossen, heb je nog iets anders nodig?","Greit, nå gjelder det. Jeg har nesten fått alt til å fungere perfekt. Det var noen problemer igjen å fikse, trenger du noe mer?","W porządku, to jest to. Prawie wszystko działa idealnie. Zostało kilka problemów do naprawienia, potrzebujesz czegoś jeszcze?","Ok, é isso aí. Está quase tudo funcionando perfeitamente. Faltavam alguns problemas pra consertar. Precisa de mais algo?",,"În regulă, asta e tot. Acum aproape totul merge perfect. Au mai fost câteva probleme de rezolvat, mai ai nevoie de ceva?","Итак, тут оставалась пара проблем, но теперь всё работает почти идеально. Что-нибудь ещё?",,"Okej, nu är det dags. Jag har nästan fått allt att fungera perfekt. Det fanns några problem kvar att fixa, behöver du något mer?","Pekala, işte bu. Neredeyse her şey mükemmel çalışıyor. Düzeltmem gereken birkaç sorun kaldı, başka bir şeye ihtiyacın var mı?" +Patch me up.,TXT_RPLY0_SCRIPT34_D9096_PATCH,〃,,,Dej mě do hromady.,Lav mig om.,Flick mich zusammen.,,Kuracu min.,Cúrame.,,Paikkaa minut.,Soignez moi.,Gyógyíts fel.,Curami.,治療してほしい。,치료가 필요합니다.,Patch me op.,Lapp meg sammen.,Załataj mnie.,Trate meus ferimentos.,,Bandajează-mă.,Перебинтуй меня.,,Laga mig.,Beni yamala. +What have you been trying to do? Go head to head with a Crusader?,TXT_RYES0_SCRIPT34_D9096_WHATH,〃,,,Co jsi dělal? Šel zmlátit Křižáka?,Hvad har du forsøgt at gøre? Gå hoved mod hoved med en korsfarer?,"Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,"Kion vi intencis fari? +Ĉu piki Kruciston?","¿Qué has intentado hacer? +¿Ir cara a cara con un Cruzado?","¿Qué anduviste haciendo? +¿Ir cara a cara con un Cruzado?",Mitä olet oikein yrittänyt tehdä? Mennä nokittain ristiretkeläisen kanssa?,Qu'est-ce que vous avez fait? Vous avez essayé de faire ami avec un Croisé?,Mit akartál tenni? Nekimenni egymagad egy keresztesnek?,Ma cosa hai cercato di fare? Lottare da solo contro un Crociato?,"今度は何を始めるんだ? +クルセイダーと向かい合うのか?",아콜라이트와 근접전을 펼친 것 같군요... 아마도.,Wat heb je geprobeerd te doen? Hoofd aan hoofd gaan met een kruisvaarder?,Hva har du prøvd å gjøre? Kjempe mot en korsfarer?,Co ty próbowałeś zrobić? Walczyć oko w oko z Krzyżowcem?,O que andou tentando fazer? Sair na porrada com um Cruzado?,,Ce ai încercat să faci? Dai cap în cap cu un Cruciat?,"Ты что, бился один на один с крестоносцем?",,Vad har du försökt göra? Gå mot en korsriddare?,Ne yapmaya çalışıyordun? Bir Haçlı ile kafa kafaya mı? +Implant upgrade?,TXT_RPLY1_SCRIPT34_D9096_IMPLA,〃,,,Vylepšení implantátu?,Implantatopgradering?,Implantatsupgrade?,,Ĉu plibonigo de enplantaĵo?,¿Mejora de implante?,,Istutteen päivitys?,Mise à jour de l'implant?,Implantátum fejlesztés?,Aggiornamento dell'impianto?,インプラント アップグレード?,지구력 업그레이드?,Implantaat upgrade?.,Implantatoppgradering?,Ulepszenie implantu?,Aprimoramento de implante?,,Upgrade la implant?,Улучшение импланта?,,Implantatuppgradering?,İmplant yükseltmesi mi? +That should do it for you.,TXT_RYES1_SCRIPT34_D9096_THATS,〃,,,Tohle by mělo fungovat.,Det burde gøre det for dig.,"Alles klar, das haben wir sofort.",,Ĉi tio devus esti sufiĉa.,Con esto debería estar.,,Eiköhän tällä ala tepsiä.,Ca devrait faire l'affaire.,Ez szerintem megteszi.,Questo dovrebbe andare.,今取り掛かっている。,도움이 좀 될 거에요.,Dat zou het voor je moeten doen.,Det burde gjøre det for deg.,To powinno ci wystarczyć.,Isso deve funcionar pra você.,,Asta ar trebui să fie suficient.,Вот оно.,,Det borde göra det för dig.,Bu senin işini görür. +Let me run some more tests first.,TXT_RNO1_SCRIPT34_D9096_LETME,〃,,,Ještě ho musím dál otestovat.,Lad mig køre nogle flere tests først.,Es ist noch nicht soweit.,,"Unue mi faru +kelkajn provojn.","Déjame hacer algunas +pruebas primero.",,Anna minun ajaa muutamia kokeita ensin.,Laissez moi faire quelques tests d'abord.,Hadd futtassak pár tesztet.,Devo fare ancora qualche test.,もう少しテストしてからにしよう。,시험단계를 좀 거치고 예기할게요.,Laat me eerst nog wat testen doen.,La meg kjøre noen flere tester først.,Pozwól mi najpierw przeprowadzić kilka testów.,Só deixa eu fazer mais alguns testes.,,Lasă-mă să fac niște teste mai întâi.,Дай мне ещё времени на тесты.,,Låt mig köra några fler tester först.,Önce birkaç test daha yapayım. +That's all I can do on the implant right now. Maybe some healing?,TXT_DLG_SCRIPT34_D10612_THATS,〃,,,"Tak, to je všechno co teď můžu s tím implantátem udělat. Potřebuješ léčení?","Det er alt, hvad jeg kan gøre på implantatet lige nu. Måske noget healing?","Das ist alles, was ich im Moment mit dem Implantat machen kann. Vielleicht etwas medizinische Versorgung?",,"Tio estas ĉio, kion mi momente povas fari super la enplantaĵo. Ĉu vi bezonas kuracon?",Eso es todo lo que puedo hacer con el implante por ahora. ¿Necesitas curarte?,,Tätä enempää en voi istutteelle enää juuri nyt tehdä. Mutta oletko hoidon tarpeessa?,C'est tout ce que je peux faire pour l'implant. Vous voulez que je vous soigne?,Ennyit tudtam kezdeni most az implantátummal. Esetleg valami gyógyítás?,È tutto per quanto riguarda l'impianto. Però posso sempre curarti.,"インプラントはこれ以上ない程完成した。 +それとも治療か?",이식 칩에 관한 모든 걸 해줬습니다. 더 필요한 게 있나요?,Dat is alles wat ik nu kan doen op het implantaat. Misschien wat genezing?,Det er alt jeg kan gjøre med implantatet akkurat nå. Kanskje litt helbredelse?,"To wszystko, co mogę zrobić z implantem w tej chwili. Może trochę uzdrowienia?",Isso é tudo o que posso fazer com o implante no momento. Vai uma cura aí?,,Asta e tot ce pot face implantului acum. Poate niște bandaje?,Пока что я больше ничего не могу сделать с имплантом. Как насчёт лечения?,,Det är allt jag kan göra med implantatet just nu. Kanske lite läkning?,Şu anda implant üzerinde yapabileceğim tek şey bu. Belki biraz iyileşme? +Yeah.,TXT_RPLY0_SCRIPT34_D10612_YEAH,〃,,,Jo.,Ja.,Ja.,,Jes.,Sí.,,Kyllä.,Ouais.,Igen.,Sì.,ああ。,그래.,Ja.,Ja.,Tak.,Sim.,,Da.,Давай.,,"Ja, det är det.",Evet. +"Boy, you're a real mess. I'll see what I can do.",TXT_RYES0_SCRIPT34_D10612_BOYYO,〃,,,"Tebe teda zřídili, kluku. Uvidím, co s tebou.","Mand, du er et rigtigt rod. Jeg skal se, hvad jeg kan gøre.","Mann, du siehst aber gar nicht gut aus. Mal sehen, was ich machen kann.",,"Ulo, vi estas iomege en malordo. +Mi vidos tion, kion mi faru.","Tío, estás hecho un desastre. +A ver qué puedo hacer.","Chico, estás hecho un desastre. +A ver qué puedo hacer.","Kylläpä olet huonossa jamassa. Katsotaan, mitä voin tehdä.","Mon petit, vous êtes dans un sale état. Je vais voir ce que je peux faire.","Öregem, elég ramaty állapotban vagy. Megnézem mit tehetek.","Ragazzo, sei messo proprio male. Vediamo cosa posso fare.",君、滅茶苦茶だな。なんとかしよう。,치료가 다 끝났습니다. 다 의료기술 덕입니다.,"Jongen, je bent een echte puinhoop. Ik zal zien wat ik kan doen.","Jøss, du er et skikkelig rot. Jeg skal se hva jeg kan gjøre.","Chłopcze, masz niezły bałagan. Zobaczę, co da się zrobić.","Rapaz, você está arrebentado. Verei o que posso fazer.",,"Băiete, ești un dezastru. O să văd ce pot face.","Ты просто месиво. Посмотрим, что я смогу сделать.",,Du är en riktig röra. Jag ska se vad jag kan göra.,Gerçekten berbat durumdasın. Ne yapabileceğime bakacağım. +What can I do for you?,TXT_DLG_SCRIPT34_D12128_WHATC,"MAP34: Feris (identical to rows 746-768, except for row 1357).",,,Co pro tebe můžu udělat?,Hvad kan jeg gøre for dig?,Was kann ich für dich tun?,,Kion mi faru por vi?,¿Qué puedo hacer por ti?,,Mitä voin tehdä sinulle?,Que puis-je faire pour vous?,Mit tehetek érted?,Cosa posso fare per te?,それで何か用か?,무엇을 도와줄까.,Wat kan ik voor je doen?,Hva kan jeg gjøre for deg?,Co mogę zrobić dla ciebie?,Como posso te ajudar?,,Ce pot face pentru tine?,Чем я могу тебе помочь?,,Vad kan jag göra för dig?,Senin için ne yapabilirim? +I'm out of bullets.,TXT_RPLY0_SCRIPT34_D12128_IMOUT,〃,,,Došly mi náboje.,Jeg er løbet tør for kugler.,Ich habe keine Munition mehr.,,Mi ne havas kuglojn.,No me quedan balas.,,Minulta on luodit loppu.,Je suis à cours de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Jeg er tom for kuler.,Skończyły mi się naboje.,Estou sem munição.,,Nu mai am gloanțe.,У меня кончились патроны.,,Jag har slut på kulor.,Mermim bitti. +Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT34_D12128_HERES,〃,,,"Tady máš nějakou munici, neplýtvej s ní.",Her er lidt ammunition til dig. Spild det ikke.,Hier hast du welche. Verschwende sie nicht.,,"Jen iom da municio. +Ne malŝparu ĝin.","Aquí tienes algo de munición. +No la desperdicies.",,Tässä sinulle panoksia. Älä tuhlaa niitä.,"En voilà pour vous, ne les gaspillez pas.",Itt van valamennyi lőszer. Ne pazarold el.,Ecco un po' di munizioni per te. Non sprecarle.,無駄遣いするなよ。,조금만 주겠습니다. 재고가 모자라거든요.,Hier is wat munitie voor je. Verspil het niet.,Her er litt ammunisjon til deg. Ikke sløs den bort.,Tu jest trochę amunicji dla ciebie. Nie marnuj jej.,Leve esta munição. Não desperdice.,,Iată niște muniție. N-o irosi.,Можешь взять немного. Не трать их понапрасну.,,Här är lite ammunition till dig. Slösa inte bort den.,Al sana biraz mermi. Boşa harcama. +Teach me.,TXT_RPLY1_SCRIPT34_D12128_TEACH,〃,,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Taníts.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Naucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +"All right, I'll just show you a few little pointers.",TXT_RYES1_SCRIPT34_D12128_ALLRI,〃,,,"Dobře, ukážu ti pár rad.","Okay, jeg vil bare vise dig et par små tips.","Alles klar, ich zeige dir ein paar Kniffe.",,"Bone, jen kelkaj konsiletoj...","Muy bien, aquí van +un par de consejos...",,"Hyvä on, annan sinulle vain muutamia pikkuvinkkejä.",Pas de problème. Laissez moi vous montrer quelques trucs.,Akkor addok pár hasznos tanácsot.,"Va bene, ti darò un paio di dritte molto utili.",わかった、幾つかやり方を教えよう。,좋습니다. 움직이는 과녁을 쏘세요!,"Oké, ik zal je gewoon een paar kleine tips laten zien.","Greit, jeg skal bare vise deg noen små tips.","W porządku, pokażę ci tylko kilka małych wskazówek.","Ok, vou te dar algumas dicas.",,"În regulă, am să-ți arăt niște repere.",Хорошо. Покажу тебе пару приёмов.,,"Okej, jag ska bara visa dig några små tips.","Pekala, sana birkaç küçük ipucu göstereceğim." +You're not ready yet.,TXT_RNO1_SCRIPT34_D12128_YOURE,〃,,,Ještě nejsi připravený.,Du er ikke klar endnu.,Du bist noch nicht so weit.,,"Vi ankoraŭ +ne estas preta.",Aún no estás listo.,,Et ole vielä valmis.,Vous n'êtes pas encore prêt.,Nem állsz még készen.,Non sei ancora pronto.,そっちの準備がまだ整ってないようだな。,당신은 아직 준비가 안됐어요.,Je bent nog niet klaar.,Du er ikke klar ennå.,Nie jesteś jeszcze gotowy.,Você não está preparado ainda.,,Nu ești pregătit încă.,Ты ещё не готов.,,Du är inte redo än.,Henüz hazır değilsin. +Back again? What do you need?,TXT_DLG_SCRIPT34_D13644_BACKA,〃,,,Zase zpátky? Co potřebuješ?,Tilbage igen? Hvad har du brug for?,Scxhon zurück? Was brauchst du?,,Do vi revenis. Kion vi bezonas?,¿Ya de vuelta? ¿Qué necesitas?,,Täällä taas? Mitä tarvitset?,Déjà de retour? De quoi avez-vous besoin?,Már vissza is tértél? Mire van szükséged?,Già di ritorno? Che cosa ti serve?,もう戻ったか?何が必要だ?,다시 왔군요. 무엇이 필요하죠?,Weer terug? Wat heb je nodig?,Tilbake igjen? Hva trenger du?,Znowu? Czego potrzebujesz?,Já voltou? O que precisa?,,Te-ai întors? Ce mai dorești?,Ты вернулся? Что тебе нужно?,,Tillbaka igen? Vad behöver du?,Yine mi? Neye ihtiyacın var? +I'm out of bullets.,TXT_RPLY0_SCRIPT34_D13644_IMOUT,〃,,,Došly mi náboje.,Jeg er løbet tør for kugler.,Ich habe keine Munition mehr.,,Mi ne havas kuglojn.,No me quedan balas.,,Minulta on ammukset loppu.,Je suis à cours de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾切れだ。,탄약이 바닥났어요.,Ik heb geen kogels meer.,Jeg er tom for kuler.,Skończyły mi się naboje.,Estou sem munição.,,Nu mai am gloanțe.,У меня кончились патроны.,,Jag har slut på kulor.,Mermim bitti. +Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT34_D13644_HERES,〃,,,"Tady máš nějakou munici, neplýtvej s ní.",Her er lidt ammunition til dig. Spild det ikke.,Hier hast du welche. Verschwende sie nicht.,,"Jen iom da municio. +Ne malŝparu ĝin.","Aquí tienes algo de munición. +No la desperdicies.",,Tässä vähän lisää. Älä haaskaa niitä.,"En voilà pour vous, ne les gaspillez pas.",Itt van valamennyi lőszer. Ne pazarold el.,Ecco un po' di munizioni per te. Non sprecarle.,この弾を使え、無駄遣いするなよ。,"적을 사살하려면, 역시 탄약을 소진해야만 하죠. 여기 탄약입니다.",Hier is wat munitie voor je. Verspil het niet.,Her er litt ammunisjon til deg. Ikke sløs den bort.,Tu jest trochę amunicji dla ciebie. Nie marnuj jej.,Leve esta munição. Não desperdice.,,Iată niște muniție. N-o irosi.,Можешь взять немного. Не трать их понапрасну.,,Här är lite ammunition till dig. Slösa inte bort den.,İşte sana biraz cephane. Boşa harcama. +You've got enough ammo.,TXT_RNO0_SCRIPT34_D13644_YOUVE,〃,,,Vždyť jich máš dost.,Du har ammunition nok.,Du hast genug.,,Vi havas sufiĉe da municio.,Tienes suficiente munición.,,Sinulla on riittävästi ammuksia.,Vous avez assez de munitions.,Van elég lőszered.,Ma veramente ne hai a sufficienza.,もう十分に弾を持ってるようだぞ。,충분한 탄약을 가졌어. 다 소진하고 찾아오세요.,Je hebt genoeg munitie.,Du har nok ammunisjon.,Masz wystarczająco dużo amunicji.,Você já tem munição suficiente.,,Ai suficientă muniție.,У тебя их достаточно.,,Du har tillräckligt med ammunition.,Yeterince mermin var. +Teach me.,TXT_RPLY1_SCRIPT34_D13644_TEACH,〃,,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Taníts.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Naucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +"All right, this should keep you going for a while.",TXT_RYES1_SCRIPT34_D13644_ALLRI,〃,,,"Dobře, tohle by ti mělo pomoct.","Okay, det her burde holde dig i gang et stykke tid.","Alles klar, das sollte fürs erste reichen.",,"Bone, ĉi tio devus esti +sufiĉe utila nuntempe.","Muy bien, esto debería +servirte por el momento.",,"Selvä on, tällä sinun pitäisi pötkiä aika pitkälle.","Bien, ça devrait vous suffir pour un bon moment.","Rendben van, ezzel el leszel egy darabig.","Va bene, con questo dovresti andare sul sicuro per un po'.",わかった、これで長くやり合えるだろう。,"여기, 적병 일부를 충분히 죽일 수 있을 만큼의 탄약입니다.","Oké, dit zou je een tijdje op de been moeten houden.","Greit, dette burde holde deg gående en stund.","W porządku, to powinno ci wystarczyć na jakiś czas.","Ok, isso deve te ajudar por enquanto.",,"Bine, asta ar trebui să te ajute o vreme.","Хорошо, это не раз спасёт тебе жизнь.",,"Okej, det här borde hålla dig igång ett tag.","Pekala, bu seni bir süre idare eder." +"Sorry, can't. I'm just following Macil's orders.",TXT_RNO1_SCRIPT34_D13644_SORRY,〃,,,"Promiň, nemůžu. Řídím se rozkazy od Macila.","Beklager, jeg kan ikke. Jeg følger bare Macils ordrer.","Tut mir leid, aber ich kann nicht. Ich folge nur Macils Befehlen.",,"Pardonon, mi ne rajtas. +Mi nur observas Macil-on.","Lo siento, no puedo. +Solo sigo órdenes de Macil.",,Valitettavasti en voi. Noudatan vain Macilin käskyjä.,"Désolé, pas possible. Je ne fais que suivre les ordres de Macil.","Sajnálom, de nem tehetem. Macil utasítása.","Mi spiace, ma non posso. Ordini dall'alto.",すまないが、できない。マシルの命令だ。,마실 사령관님의 명령입니다. 그럴 수는 없어요.,"Sorry, dat kan niet. Ik volg gewoon de orders van Macil op.","Beklager, jeg kan ikke. Jeg følger bare Macils ordre.","Przepraszam, nie mogę. Wykonuję tylko rozkazy Macila.",Desculpe mas não posso. Só estou seguindo as ordens do Macil.,,"Scuze, nu pot. Eu doar umez ordinele lui Macil.","Увы, не могу. Я подчиняюсь Мэйсилу.",,"Tyvärr, jag kan inte. Jag följer bara Macils order.","Üzgünüm, yapamam. Macil'in emirlerini uyguluyorum." +"Well which is it, bullets or training? I can't wait to get my hands on those new weapons we captured. Once I get done with them, I'll be able to begin training everyone else.",TXT_DLG_SCRIPT34_D15160_WELLW,〃,,,"Tak co to bude, náboje nebo trénink? Nemůžu se dočkat, až se dostanu k těm novým zbraním, které jsme zabavili. Trocha cvičení a pak hodně odplaty.","Nå, hvad er det, kugler eller træning? Jeg kan ikke vente med at få fingrene i de nye våben, vi har taget til fange. Når jeg er færdig med dem, kan jeg begynde at træne alle de andre.","Also, was willst du? Munition oder Training? Ich kann kaum erwarten, diese neuen Waffen, die wir erbeutet haben, in die Finger zu kriegen. ein bisschen Training und dann jede Menge Vergeltung.",,"Nu, ĉu kugloj aŭ trejnado ĉi-foje? Mi sopire atendas provi tiujn novajn kaptitajn armilojn. Fininte tion, mi povos ektrejni la aliajn.","Bueno, ¿qué va a ser?, ¿balas o entrenamiento? No puedo esperar a poner mis manos en esas nuevas armas que hemos capturado. En cuanto termine, podré empezar a entrenar al resto.","Bueno, ¿qué va a ser?, ¿balas o entrenamiento? No puedo esperar a poner mis manos en esas nuevas armas que capturamos. En cuanto termine, voy a poder empezar a entrenar al resto.","No niin, kumpaa saisi olla: luoteja vai koulutusta? En voi malttaa olla tarttumasta vasta kaappaamiimme aseisiin. Hieman perehdytystä, ja sitten paljon kostamista.","Qu'est-ce qu'il vous faut? Des munitions ou de l'entraînement? J'ai hâte d'essayer ces nouvelles armes que l'on a capturé. Quand j'en aurai fini avec elles, je pourrai entraîner tout le monde.","Akkor mi lesz, ólom vagy tréning? Már alig várom, hogy kipróbáljam az újonnan zsákmányolt fegyvereket. Ha végeztem velük, mindenki mást is fel tudok készíteni.","Bene, che cosa ti serve, munizioni o addestramento? Non vedo l'ora di mettere le mani su quelle nuove armi che abbiamo preso. Un po' di addestramento e poi molta vendetta.","弾薬と訓練、どっちの用件だ? 奪った新しい武器が届くのを待ち切れないです。 -少しの訓練でデカい復讐を。",탄약보급? 훈련? 가능하면 모두 다 가능합니다! 그리고 방금 수송된 무기들을 만져보고 싶습니다. 조사가 끝난 뒤에는 모두가 특수 훈련을 받을 수 있을 거에요.,"Wat is het dan wel, kogels of training? Ik kan niet wachten om die nieuwe wapens in handen te krijgen die we gevangen genomen hebben. Als ik er klaar mee ben, kan ik beginnen met het trainen van alle anderen.",,"Bem, o que vai ser? Munição ou treinamento? Mal posso esperar pra pegar nessas novas armas que capturamos. Depois que eu terminar com eles, vou poder começar a treinar todo o pessoal.",,,"Что теперь, патроны или тренировка? Мне не терпится опробовать это новое трофейное оружие. Чуть-чуть тренировки, и они за всё заплатят.", -I'm out of ammo.,TXT_RPLY0_SCRIPT34_D15160_IMOUT,,,,Došly mi náboje.,Ich habe keine Munition mehr.,,,No me queda minicion.,,,Je suis à cours de munitions.,,,弾切れだ。,탄약이 떨어졌어요.,Ik heb geen munitie meer.,,Estou sem munição.,,,У меня кончились боеприпасы., -Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT34_D15160_HERES,,,,"Tady máš nějakou munici, neplýtvej s ní.",Hier hast du welche. Verschwende sie nicht.,,,Aquí tienes un poco de munición. No la desperdicies.,,,"En voilà pour vous, ne les gaspillez pas.",,,この弾をどうぞ、無駄遣いしないように。,조금 나눠주도록 하겠습니다. 부디 낭비하지 마시길.,Hier is wat munitie voor je. Verspil het niet.,,Leve esta munição. Não desperdice.,,,Можешь взять немного. Не трать их понапрасну., -You've got enough ammo.,TXT_RNO0_SCRIPT34_D15160_YOUVE,,,,Vždyť jich máš dost.,Du hast genug.,,,Tienes suficiente munición.,,,Vous avez assez de munitions.,,,もう十分に弾を持ってるようだぞ。,충분한 탄약을 가졌군...,Je hebt genoeg munitie.,,Você já tem munição suficiente.,,,У тебя хватает патронов., -Teach me.,TXT_RPLY1_SCRIPT34_D15160_TEACH,,,,Uč mě.,Unterrichte mich.,,,Enséñame.,,,Apprenez-moi.,,,教えてくれ。,가르쳐 줘.,Leer het me.,,Me ensine.,,,Обучи меня., -O.K. Take what you've learned and show those Order bastards the way to hell.,TXT_RYES1_SCRIPT34_D15160_OKTAK,,,,"Oukej. Pamatuj, co ses tady naučil, a ukaž těm hajzlům z Řádu cestu do pekla.","OK. Nutze, was du hier gelernt hast um diesen Tölpeln vom Orden den Weg in die Hölle zu zeigen.",,,OK. Toma lo que has aprendido y muéstrales a los de la Orden el camino al infierno.,,,OK. Utilisez ce que vous avez appris et envoyez ces abrutis de l'Ordre en enfer.,,,"オーケー、ここで学んだ事を生かして -オーダー共を地獄に送って上げなさい。",이제 당신은 더 똑똑해졌습니다. 저 멍청한 오더 놈들에게 쓴맛을 보여주세요!,"Oké, neem wat je geleerd hebt en laat die ordeklootzakken de weg naar de hel zien.",,Ok. Use o que você aprendeu e mostre o caminho pro inferno para esses desgraçados da Ordem.,,,"Запоминай внимательно, покажешь этим прихвостням Ордена быструю дорогу в ад.", -"Come back later, when Macil says it's time.",TXT_RNO1_SCRIPT34_D15160_COMEB,,,,"Přijď někdy jindy, až řekne Macil.","Komm wieder, wenn Macil dir Bescheid gibt.",,,"Vuelve más tarde, cuando Macil diga que es hora.",,,Revenez plus tard quand Macil décide qu'il est temps.,,,マシルの命令を受けてから、また来い。,마실 사령관님이 준비되었다고 말했을 때 와주세요.,"Kom later terug, als Macil zegt dat het tijd is.",,"Volte mais tarde, quando o Macil disser que é hora.",,,"Приходи позже, когда прикажет Мэйсил.", -I've taught you everything I can right now. Give me some time to put the new weapons through their paces. That is unless you're out of bullets.,TXT_DLG_SCRIPT34_D16676_IVETA,,,,"Naučil jsem tě vše, co teď můžu. Dej mi nějaký čas, abych vyzkoušel ty nové zbraně. Jedině, že bys potřeboval náboje.","Ich habe dir alles gezeigt, was ich momentan kann. Gib mir etwas Zeit um die neuen Waffen zu testen. Munition kriegst du natürlich auch so.",,,"Te he enseñado todo lo que puedo de momento. Dame algo de tiempo para poner esas nuevas armas a punto. Eso es, a menos que estés sin balas.",,,"Je vous ai enseigné tout ce que je sais. Laissez moi un peu de temps pour tester ces nouvelles armes. Sauf si vous n'avez plus de munitions, bien sûr.",,,"私が教えられる事はもう無い。 +少しの訓練でデカい復讐を。",탄약보급? 훈련? 가능하면 모두 다 가능합니다! 그리고 방금 수송된 무기들을 만져보고 싶습니다. 조사가 끝난 뒤에는 모두가 특수 훈련을 받을 수 있을 거에요.,"Wat is het dan wel, kogels of training? Ik kan niet wachten om die nieuwe wapens in handen te krijgen die we gevangen genomen hebben. Als ik er klaar mee ben, kan ik beginnen met het trainen van alle anderen.","Hva er det, kuler eller trening? Jeg gleder meg til å få tak i de nye våpnene vi tok. Når jeg er ferdig med dem, kan jeg begynne å trene alle de andre.","Więc co to jest, kule czy trening? Nie mogę się doczekać, aż dostanę w swoje ręce tę nową broń, którą zdobyliśmy. Jak już się z nimi uporam, będę mógł zacząć szkolić wszystkich innych.","Bem, o que vai ser? Munição ou treinamento? Mal posso esperar pra pegar nessas novas armas que capturamos. Depois que eu terminar com eles, vou poder começar a treinar todo o pessoal.",,"Deci care e, gloanțe sau instruire? Abia aștept să pun mâna pe armele pe care le-am capturat. Odată ce termin cu ele îi voi putea instrui și pe ceilalți.","Что теперь, патроны или тренировка? Мне не терпится опробовать это новое трофейное оружие. Чуть-чуть тренировки, и они за всё заплатят.",,"Vad är det, kulor eller träning? Jag kan inte vänta på att få ta del av de nya vapnen som vi tog till fånga. När jag är klar med dem kan jag börja träna alla andra.","Hangisi, mermi mi eğitim mi? Yakaladığımız şu yeni silahları elime almak için sabırsızlanıyorum. Onlarla işim bittiğinde, diğer herkesi eğitmeye başlayabileceğim." +I'm out of ammo.,TXT_RPLY0_SCRIPT34_D15160_IMOUT,〃,,,Došly mi náboje.,Jeg er løbet tør for ammunition.,Ich habe keine Munition mehr.,,Mi estas sen municio.,No me queda munición.,,Minulta on panokset loppu.,Je suis à cours de munitions.,Kifogytam a lőszerből.,Ho finito le munizioni.,弾切れだ。,탄약이 떨어졌어요.,Ik heb geen munitie meer.,Jeg er tom for ammunisjon.,Skończyła mi się amunicja.,Estou sem munição.,,Nu mai am gloanțe.,У меня кончились боеприпасы.,,Jag har slut på ammunition.,Mermim bitti. +Here's some ammo for you. Don't waste it.,TXT_RYES0_SCRIPT34_D15160_HERES,〃,,,"Tady máš nějakou munici, neplýtvej s ní.",Her er noget ammunition til dig. Spild det ikke.,Hier hast du welche. Verschwende sie nicht.,,"Jen iom da municio. +Ne malŝparu ĝin.","Aquí tienes algo de munición. +No la desperdicies.",,Tässä ammuksia. Älä tuhlaa niitä.,"En voilà pour vous, ne les gaspillez pas.",Itt van valamennyi lőszer. Ne pazarold el.,Ecco un po' di munizioni per te. Non sprecarle.,この弾をどうぞ、無駄遣いしないように。,조금 나눠주도록 하겠습니다. 부디 낭비하지 마시길.,Hier is wat munitie voor je. Verspil het niet.,Her er litt ammunisjon til deg. Ikke sløs den bort.,Tu jest trochę amunicji dla ciebie. Nie marnuj jej.,Leve esta munição. Não desperdice.,,Iată niște muniție. N-o irosi.,Можешь взять немного. Не трать их понапрасну.,,Här är lite ammunition till dig. Slösa inte bort den.,Al sana biraz cephane. Boşa harcama. +You've got enough ammo.,TXT_RNO0_SCRIPT34_D15160_YOUVE,〃,,,Vždyť jich máš dost.,Du har ammunition nok.,Du hast genug.,,Vi havas sufiĉe da municio.,Tienes suficiente munición.,,Sinulla on riittävästi ammuksia.,Vous avez assez de munitions.,Van elég lőszered.,Ma veramente ne hai a sufficienza.,もう十分に弾を持ってるようだぞ。,충분한 탄약을 가졌군...,Je hebt genoeg munitie.,Du har nok ammunisjon.,Masz wystarczającą ilość amunicji.,Você já tem munição suficiente.,,Ai suficientă muniție.,У тебя хватает патронов.,,Du har tillräckligt med ammunition.,Yeterince cephanen var. +Teach me.,TXT_RPLY1_SCRIPT34_D15160_TEACH,〃,,,Uč mě.,Lær mig det.,Unterrichte mich.,,Trejnu min.,Entréname.,,Kouluta minua.,Apprenez-moi.,Taníts.,Dammi dell'altro addestramento.,教えてくれ。,가르쳐 줘.,Leer het me.,Lær meg det.,Naucz mnie.,Me ensine.,,Învață-mă.,Обучи меня.,,Lär mig.,Öğret bana. +O.K. Take what you've learned and show those Order bastards the way to hell.,TXT_RYES1_SCRIPT34_D15160_OKTAK,〃,,,"Oukej. Pamatuj, co ses tady naučil, a ukaž těm hajzlům z Řádu cestu do pekla.",O.K. Tag det du har lært og vis de ordens-svin vejen til helvede.,"OK. Nutze, was du hier gelernt hast um diesen Tölpeln vom Orden den Weg in die Hölle zu zeigen.",,"Bone. Uzu ĉi tion por gvidi tiujn +aĉulojn de La Ordeno al la infero.","Bien. Usa lo aprendido para guiar a esos +majaderos de La Orden al infierno.","Bien. Usa lo aprendido para guiar a esos +desgraciados de La Orden al infierno.","OK. Hyödynnä täällä oppimaasi, ja näytä niille Veljeskunnan valopäille tie helvettiin.",OK. Utilisez ce que vous avez appris et envoyez ces abrutis de l'Ordre en enfer.,"Rendben is vagyunk, mutasd meg a Rend kutyáknak a pokolba vezető utat!",O.K. Usa ciò che hai imparato qua per mostrare all'Ordine la via dell'Inferno.,"オーケー、ここで学んだ事を生かして +オーダー共を地獄に送って上げなさい。",이제 당신은 더 똑똑해졌습니다. 저 멍청한 오더 놈들에게 쓴맛을 보여주세요!,"Oké, neem wat je geleerd hebt en laat die ordeklootzakken de weg naar de hel zien.",OK. Ta det du har lært og vis de jævlene fra Ordenen veien til helvete.,"Weź to, czego się nauczyłeś i pokaż tym draniom z Zakonu drogę do piekła.",Ok. Use o que você aprendeu e mostre o caminho pro inferno para esses desgraçados da Ordem.,,"O.K. Cu ceea ce ai învățat, trimite-i pe nemernicii Ordinului către infern.","Запоминай внимательно, покажешь этим прихвостням Ордена быструю дорогу в ад.",,Okej. Ta det du lärt dig och visa de där orderjävlarna vägen till helvetet.,Tamam. Öğrendiklerini al ve o Tarikat piçlerine cehennemin yolunu göster. +"Come back later, when Macil says it's time.",TXT_RNO1_SCRIPT34_D15160_COMEB,〃,,,"Přijď někdy jindy, až řekne Macil.","Kom tilbage senere, når Macil siger, det er tid.","Komm wieder, wenn Macil dir Bescheid gibt.",,"Revenu post kiam +Macil ordonis tion.","Vuelve más tarde cuando +Macil diga que ya es la hora.",,"Palaa asiaan myöhemmin, kun Macil näyttää vihreää valoa.",Revenez plus tard quand Macil décide qu'il est temps.,"Gyere vissza akkor, ha azt mondja Macil hogy ideje van.","Ritorna più tardi, quando Macil dirà che è il momento.",マシルの命令を受けてから、また来い。,마실 사령관님이 준비되었다고 말했을 때 와주세요.,"Kom later terug, als Macil zegt dat het tijd is.","Kom tilbake senere, når Macil sier det er på tide.","Wróć później, kiedy Macil powie, że już czas.","Volte mais tarde, quando o Macil disser que é hora.",,"Revin-o mai încolo, când Macil zice că e timpul.","Приходи позже, когда прикажет Мэйсил.",,"Kom tillbaka senare, när Macil säger att det är dags.",Macil zamanı geldiğini söylediğinde geri gel. +I've taught you everything I can right now. Give me some time to put the new weapons through their paces. That is unless you're out of bullets.,TXT_DLG_SCRIPT34_D16676_IVETA,〃,,,"Naučil jsem tě vše, co teď můžu. Dej mi nějaký čas, abych vyzkoušel ty nové zbraně. Jedině, že bys potřeboval náboje.","Jeg har lært dig alt, hvad jeg kan lige nu. Giv mig lidt tid til at sætte de nye våben på prøve. Medmindre du er løbet tør for kugler.","Ich habe dir alles gezeigt, was ich momentan kann. Gib mir etwas Zeit um die neuen Waffen zu testen. Munition kriegst du natürlich auch so.",,"Mi instruis al vi ĉion, kion mi ĉi-momente povas. Donu tempon al mi por elprovi la novajn armilojn... krom se vi nur bezonas pliajn kuglojn.","Te he enseñado todo lo que puedo por ahora. Dame tiempo para probar al 100% las nuevas armas... a menos que solo necesites más balas, claro.","Ya te enseñé todo lo que puedo por ahora. Dame tiempo para probar al 100% las nuevas armas... a menos que solo necesites más balas, claro.","Olen opettanut sinulle kaiken, mitä itse juuri nyt osaan. Anna minulle vähän aikaa käydä läpi uusien aseiden askelkuvioita. Ellei sinulla sitten ole luodit lopussa.","Je vous ai enseigné tout ce que je sais. Laissez moi un peu de temps pour tester ces nouvelles armes. Sauf si vous n'avez plus de munitions, bien sûr.","Megtanítottam mindent amit jelenleg tudtam. Adj egy kis időt, hogy leteszteljem a fegyvereket. Kivétel persze ha lőszer kell.",Ti ho insegnato tutto quello che potevo per ora. Dammi dell'altro tempo per mettere le nuove armi alla prova. A meno che non ti servano altre munizioni.,"私が教えられる事はもう無い。 今後新しい武器は時間が掛かるが 自分のペースで学んだ方がいい。 -弾切れでなければの話だが。","배울 수 있는 모든 것들을 배우셨습니다. 이제 보급할 시간을 좀 주세요. 말이 나와서 하는 말인데, 탄약이 필요하십니까?",Ik heb je alles geleerd wat ik nu kan. Geef me wat tijd om de nieuwe wapens op de proef te stellen. Tenzij je geen kogels meer hebt.,,Te ensinei tudo o que eu posso no momento. Me dê um tempo para testar as novas armas. A não ser que você esteja sem munição.,,,Пока что я не могу научить тебя ничему новому. Дай мне время разобраться в этом новом оружии. Или у тебя закончились патроны?, -Yes I am.,TXT_RPLY0_SCRIPT34_D16676_YESIA,,,,"Ano, potřebuju.","Ja, bin ich.",,,Eso mismo.,,,"En effet, je le suis.",,,ああ、そうだ。,알겠습니다. 그럼 탄약이라도?,"Ja, dat ben ik wel.",,"Sim, eu estou.",,,"Да, закончились.", -Here you go.,TXT_RYES0_SCRIPT34_D16676_HEREY,,,,Tady máš.,Bitteschön.,,,Aquí tienes.,,,Voilà pour vous.,,,どうぞ。,여기요!,Alsjeblieft.,,Aqui está.,,,Держи., -"Don't get trigger happy in the town, you'll set off the alarm and they will start sending in guards from the castle.",TXT_DLG_SCRIPT34_D18192_DONTG,,,,Ať tě nenapadne střílet ve městě. Spustil bys poplach a přivolal stráže z hradu.,"Fang nicht an, hier in der Stadt herumzuballern. Wenn du hier den Alarm auslöst, senden sie gleich die Truppen aus der Burg.",,,"No te lies a tiros en el pueblo, activarás las alarmas y empezarán a enviar guardias desdel el castillo.",,,Ne tirez pas partout en ville. Vous risquez de déclencher l'alarme et ils enverront tous les gardes du château à vos trousses.,,,"街の中で銃をバンバン撃ったりするんじゃないぞ +弾切れでなければの話だが。","배울 수 있는 모든 것들을 배우셨습니다. 이제 보급할 시간을 좀 주세요. 말이 나와서 하는 말인데, 탄약이 필요하십니까?",Ik heb je alles geleerd wat ik nu kan. Geef me wat tijd om de nieuwe wapens op de proef te stellen. Tenzij je geen kogels meer hebt.,Jeg har lært deg alt jeg kan for øyeblikket. Gi meg litt tid til å teste de nye våpnene. Med mindre du er tom for kuler.,"Nauczyłem cię wszystkiego, co mogę teraz. Dajcie mi trochę czasu, żeby przetestować nową broń. Chyba, że skończyły ci się naboje.",Te ensinei tudo o que eu posso no momento. Me dê um tempo para testar as novas armas. A não ser que você esteja sem munição.,,Te-am învâțat tot ce știu. Dă-mi niște timp să învăț noile arme. Asta în cazul în care nu ai nevoie de gloanțe.,Пока что я не могу научить тебя ничему новому. Дай мне время разобраться в этом новом оружии. Или у тебя закончились патроны?,,Jag har lärt dig allt jag kan just nu. Ge mig lite tid att sätta de nya vapnen på prov. Det vill säga om du inte har slut på kulor.,Şu anda sana öğretebileceğim her şeyi öğrettim. Yeni silahları denemem için bana biraz zaman ver. Tabii mermin bitmediyse. +Yes I am.,TXT_RPLY0_SCRIPT34_D16676_YESIA,〃,,,"Ano, potřebuju.","Ja, det er jeg.","Ja, bin ich.",,Ĝuste.,Eso mismo.,,Kyllä on.,"En effet, je le suis.",Igen.,Sì che mi servono.,ああ、そうだ。,알겠습니다. 그럼 탄약이라도?,"Ja, dat ben ik wel.","Jo, det har jeg.",Tak.,"Sim, eu estou.",,Da sunt.,"Да, закончились.",,"Ja, det är jag.","Evet, bitti." +Here you go.,TXT_RYES0_SCRIPT34_D16676_HEREY,〃,,,Tady máš.,Værsgo.,Bitteschön.,,Jen.,Toma.,,"Tässä, ole hyvä.",Voilà pour vous.,Parancsolj.,Ecco qua.,どうぞ。,여기요!,Alsjeblieft.,Vær så god.,Proszę bardzo.,Aqui está.,,Aici sunt.,Держи.,,Här har du.,Al bakalım. +"Don't get trigger happy in the town, you'll set off the alarm and they will start sending in guards from the castle.",TXT_DLG_SCRIPT34_D18192_DONTG,"MAP34: Upstairs. +(Identical to row 769)",,,Ať tě nenapadne střílet ve městě. Spustil bys poplach a přivolal stráže z hradu.,"Bliv ikke skydeglad i byen, du vil udløse alarmen, og de vil begynde at sende vagter ind fra slottet.","Fang nicht an, hier in der Stadt herumzuballern. Wenn du hier den Alarm auslöst, senden sie gleich die Truppen aus der Burg.",,Ne uzu pafilon en la urbo; vi ekagigus la alarmon kaj ili eksendus gardistojn el la kastelo.,"No te líes a tiros en el pueblo, que activarás la alarma y empezarán a enviar guardias desde el castillo.","No andes a los tiros en el pueblo, que vas a activar la alarma y van a empezar a mandar guardias desde el castillo.","Älä ala turhan liipaisinherkäksi kaupungilla. Aiheutat vielä hälytyksen, ja ne alkavat lähettää linnasta vartijoita.",Ne tirez pas partout en ville. Vous risquez de déclencher l'alarme et ils enverront tous les gardes du château à vos trousses.,"Ne keresd a bajt a városban. Beindítod a riasztót, és kiküldik érted a kastély őröket.",Non ti consiglio di avere il grilletto facile in città. Finiresti per attivare l'allarme e inizierebbero a mandare guardie dal castello.,"街の中で銃をバンバン撃ったりするんじゃないぞ 警報を鳴らしてしまえば、奴等が衛兵共を -城から送り込んでくるぞ。",무턱대고 마을에서 총질하지 마세요. 경보가 울림과 동시에 당신을 잡기 위해서 모든 병력을 보낼 겁니다.,"Laat de trekker niet gelukkig worden in de stad, je laat de wekker afgaan en ze sturen bewakers van het kasteel naar binnen.",,"Não saia atirando pela cidade, você vai ativar o alarme e vão mandar os guardas do castelo.",,,"Когда будешь в городе, не стреляй направо и налево. Если ты поднимешь тревогу, они вызовут подкрепление из замка.", -"Welcome, we can always use more help.",TXT_DLG_SCRIPT34_D19708_WELCO,,,,"Vítej, pomoc se nám vždycky hodí.","Willkommen, wir können immer etwas Hilfe gebrauchen.",,,"Bienvenido, siempre nos viene bien algo de ayuda.",,,Bienvenue. Nous apprécions toute l'aide que nous pouvons recevoir.,,,ようこそ、我々が貴方の助けに成ります。,어서 오세요. 당신 같은 사람에게는 많은 도움이 필요합니다!,"Welkom, we kunnen altijd meer hulp gebruiken.",,Seja bem-vindo. Qualquer ajuda também é sempre bem-vinda.,,,Добро пожаловать. Нам всегда пригодится помощь., -"When I was still in action we had the chance to examine an acolyte before the reinforcements arrived, they're not human I tell you.",TXT_DLG_SCRIPT34_D21224_WHENI,,,,"Když jsem byl ještě v akci, měli jsme možnost prozkoumat mrtvého akolytu předtím, než přišly posily. Poslouchej, nejsou to lidé.","Als ich noch aktiv war, hatten wir mal die Möglichkeit, einen der Ministranten zu untersuchen, bevor Verstärkung eintraf. Hör zu, sie sind nicht menschlich!",,,"Cuando aún estaba en acción tuvimos la oportunidad de examinar un acólito antes de que llegaran los refuerzos, te digo que no son humanos.",,,"Quand j'étais encore en service, j'ai eu l'opportunité d'examiner un acolyte avant que les renforts n'arrivent. Vous savez, ils ne sont pas humains.",,,"私がまだ活動していた時、我々が増援に +城から送り込んでくるぞ。",무턱대고 마을에서 총질하지 마세요. 경보가 울림과 동시에 당신을 잡기 위해서 모든 병력을 보낼 겁니다.,"Laat de trekker niet gelukkig worden in de stad, je laat de wekker afgaan en ze sturen bewakers van het kasteel naar binnen.","Ikke bli skyteglad i byen, da går alarmen, og de sender inn vakter fra slottet.","Nie daj się sprowokować w mieście, bo podniesiesz alarm i zaczną wysyłać strażników z zamku.","Não saia atirando pela cidade, você vai ativar o alarme e vão mandar os guardas do castelo.",,"Nu deveni prea entuziasmat în oraș, vei declanșa alarma și vor trimite gardieni din castel.","Когда будешь в городе, не стреляй направо и налево. Если ты поднимешь тревогу, они вызовут подкрепление из замка.",,"Bli inte skjutglad i staden, du sätter igång larmet och de börjar skicka in vakter från slottet.","Kasabada tetiğe basma, alarmı çalıştırırsın ve kaleden muhafızlar göndermeye başlarlar." +"Welcome, we can always use more help.",TXT_DLG_SCRIPT34_D19708_WELCO,"〃 +(Identical to row 770)",,,"Vítej, pomoc se nám vždycky hodí.","Velkommen, vi kan altid bruge mere hjælp.","Willkommen, wir können immer etwas Hilfe gebrauchen.",,Bonvenon. Plia helpo ĉiam estas utilega.,"Bienvenido, siempre nos viene bien algo más de ayuda.",,Tervetuloa; voisimme aina kaivata lisää apua.,Bienvenue. Nous apprécions toute l'aide que nous pouvons recevoir.,"Üdv nálunk, mindig jól jön a segítség.","Benvenuto, ci serve tutto l'aiuto che possiamo ottenere.",ようこそ、我々が貴方の助けに成ります。,어서 오세요. 당신 같은 사람에게는 많은 도움이 필요합니다!,"Welkom, we kunnen altijd meer hulp gebruiken.","Velkommen, vi kan alltid trenge mer hjelp.","Witamy, zawsze przyda nam się więcej pomocy.",Seja bem-vindo. Qualquer ajuda também é sempre bem-vinda.,,"Bun-venit, ajutorul e bine-venit oricând.",Добро пожаловать. Нам всегда пригодится помощь.,,"Välkommen, vi kan alltid behöva mer hjälp.","Hoş geldiniz, her zaman daha fazla yardıma ihtiyacımız olabilir." +"When I was still in action we had the chance to examine an acolyte before the reinforcements arrived, they're not human I tell you.",TXT_DLG_SCRIPT34_D21224_WHENI,"〃 +(Similar to row 771)",,,"Když jsem byl ještě v akci, měli jsme možnost prozkoumat mrtvého akolytu předtím, než přišly posily. Poslouchej, nejsou to lidé.","Da jeg stadig var i aktion havde vi mulighed for at undersøge en akolyt før forstærkningerne ankom, de er ikke menneskelige siger jeg jer.","Als ich noch aktiv war, hatten wir mal die Möglichkeit, einen der Ministranten zu untersuchen, bevor Verstärkung eintraf. Hör zu, sie sind nicht menschlich!",,"Kiam mi ankoraŭ estis en misio, ni havis okazon ekzameni akoliton antaŭ ol pliaj malamikoj alvenis, kaj ni malkovris, ke ili ne estas homoj.",Cuando aún estaba en acción tuvimos la oportunidad de examinar a un acólito antes de que llegaran los refuerzos y te digo que no son humanos.,,"Kun itse olin vielä mukana taistelemassa, saimme tilaisuuden tutkia akoluuttia ennen lisäjoukkojen saapumista. Ja kuule tarkkaan, ne eivät ole ihmisiä.","Quand j'étais encore en service, j'ai eu l'opportunité d'examiner un acolyte avant que les renforts n'arrivent. Vous savez, ils ne sont pas humains.","Amikor épp harcoltunk, alkalmunk adódott megvizsgálni egy ministránst amíg az erősítés meg nem érkezett volna. Bizony mondom neked, ezek nem emberek.","Quando ero ancora sul campo di battaglia, abbiamo avuto l'occasione di esaminare uno degli accoliti prima che arrivassero i rinforzi. Ascoltami, non sono umani.","私がまだ活動していた時、我々が増援に 囲まれる前にアコライトを調べる機会が あったんだ。聞いてくれ、奴等は人間では -なかったんだ。",제가 밖에서 근무했을 때 사살한 아콜라이트들을 자세히 들여다본 적이 있었어요. 그 들은 인간이 아니었습니다. 기억하세요.,"Toen ik nog in actie was hadden we de kans om een acoliet te onderzoeken voordat de versterkingen arriveerden, ze zijn niet menselijk, zeg ik je.",,"Quando eu ainda estava na ativa nós tivemos a oportunidade de examinar um acólito antes dos reforços chegarem. Vai por mim, eles não são humanos.",,,"Пока я был в оперативной группе, нам удалось вскрыть одного из служителей, прежде чем прибыло подкрепление. Так вот, они не люди.", -"We're trying to find where the castle gate mechanisms are, but so far we've had no luck.",TXT_DLG_SCRIPT34_D22740_WERET,,,,"Snažíme se zjistit, kde jsou mechanismy hradní brány, ale zatím jsme nic nenašli.","Wir versuchen herauszufinden, von wo das Burgtor kontrolliert wird, aber bisher hatten wir kein Glück.",,,"Estamos intentando encontrar donde están los mecanismos de la puerta del castillo, pero por ahora no hemos tenido suerte.",,,"On essaie de trouver où se trouvent les contrôles de la porte du château, mais pour l'instant, on les a pas encore localisés.",,,"我々は城門のメカニズムが何処にあるか -探し続けているが、あまり良い結果は出ていない","성문을 열려고 열심히 분석을 해보았습니다만, 결국엔 해답을 찾지 못했습니다.","We proberen te vinden waar de mechanismen van de kasteelpoort zich bevinden, maar tot nu toe hebben we geen geluk gehad.",,"Estamos tentando localizar os mecanismos do portão do castelo, mas até agora não tivemos sorte.",,,"Мы пытаемся найти механизм управления воротами замка, но пока безуспешно. -", -"Don't get caught. I've heard horror stories about what they do to our people after they're imprisoned. They just disappear, no traces, nothing. ",TXT_DLG_SCRIPT34_D24256_DONTG,,,,"Nenech se chytit. Slyšel jsem děsivé příběhy o tom, co dělají našim lidem, když je uvězní. Prostě zmizí... beze stopy.","Lass dich nicht erwischen. Ich habe Horrorgeschichten darüber gehört, was sie unseren Leuten antun, die sie gefangengenommen haben. Sie verschwinden einfach... ohne jede Spur.",,,"Que no te atrapen. He oído historias de terror sobre lo que hacen con nuestra gente despues de estar encarcelados. Símplemente desaparecen, ni rastro, nada.",,,Ne vous faites pas avoir. J'ai entendu des choses horribles sur ce qu'ils font à ceux qu'ils emprisonnent. Ils disparaîssent... Sans laisser de trace.,,,"決して捕まるな。投獄されると奴等が +なかったんだ。",제가 밖에서 근무했을 때 사살한 아콜라이트들을 자세히 들여다본 적이 있었어요. 그 들은 인간이 아니었습니다. 기억하세요.,"Toen ik nog in actie was hadden we de kans om een acoliet te onderzoeken voordat de versterkingen arriveerden, ze zijn niet menselijk, zeg ik je.","Da jeg fortsatt var i aksjon, fikk vi sjansen til å undersøke en akolytt før forsterkningene ankom. De er ikke menneskelige, sier jeg.","Kiedy byłem jeszcze w akcji, mieliśmy okazję zbadać akolitę przed przybyciem posiłków, nie są ludźmi, mówię wam.","Quando eu ainda estava na ativa nós tivemos a oportunidade de examinar um acólito antes dos reforços chegarem. Vai por mim, eles não são humanos.",,"Când încă luam parte la acțiune am avut ocazia să examinez un acolit. înaintă să ajungă întăririle, nu sunt umani.","Пока я был в оперативной группе, нам удалось вскрыть одного из служителей, прежде чем прибыло подкрепление. Так вот, они не люди.",,"När jag fortfarande var i aktion hade vi chansen att undersöka en akolyt innan förstärkningarna kom, de är inte mänskliga säger jag er.","Ben hala görevdeyken, takviye kuvvetler gelmeden önce bir yardımcı kişiyi inceleme şansımız oldu, size söylüyorum onlar insan değil." +"We're trying to find where the castle gate mechanisms are, but so far we've had no luck.",TXT_DLG_SCRIPT34_D22740_WERET,"MAP34: Downstairs. +(Identical to row 772)",,,"Snažíme se zjistit, kde jsou mechanismy hradní brány, ale zatím jsme nic nenašli.","Vi prøver at finde ud af hvor slottets portmekanismer er, men indtil videre har vi ikke haft held.","Wir versuchen herauszufinden, von wo das Burgtor kontrolliert wird, aber bisher hatten wir kein Glück.",,"Ni provas malkovri, kie troviĝas la mekanismoj de la pordo de la kastelo, sed ni ankoraŭ ne sukcesis.","Estamos intentando descubrir la ubicación de los mecanismos de la puerta del castillo, pero de momento no ha habido suerte.","Estamos tratando de descubrir la ubicación de los mecanismos de la puerta del castillo, pero por ahora no hubo suerte.","Yritämme löytää linnanportin koneistoa, mutta toistaiseksi laihoin tuloksin.","On essaie de trouver où se trouvent les contrôles de la porte du château, mais pour l'instant, on les a pas encore localisés.","Próbáljuk megtalálni a kastély kapu irányító mechanikáját, de eddig nem jártunk sikerrel.","Stiamo cercando di capire dove si trovano i meccanismi di apertura dell'entrata del castello, ma ancora niente.","我々は城門のメカニズムが何処にあるか +探し続けているが、あまり良い結果は出ていない","성문을 열려고 열심히 분석을 해보았습니다만, 결국엔 해답을 찾지 못했습니다.","We proberen te vinden waar de mechanismen van de kasteelpoort zich bevinden, maar tot nu toe hebben we geen geluk gehad.","Vi prøver å finne ut hvor slottets portmekanismer er, men så langt har vi ikke hatt noe hell.","Próbujemy znaleźć gdzie są mechanizmy bramy zamkowej, ale jak na razie nie mamy szczęścia.","Estamos tentando localizar os mecanismos do portão do castelo, mas até agora não tivemos sorte.",,"Încercăm să găsim unde sunt mecanismele castelului, dar n-am avut noroc până acum.","Мы пытаемся найти механизм управления воротами замка, но пока безуспешно. +",,"Vi försöker ta reda på var mekanismerna för slottets portar finns, men hittills har vi inte haft någon tur.",Kale kapısı mekanizmalarının nerede olduğunu bulmaya çalışıyoruz ama şu ana kadar şansımız yaver gitmedi. +"Don't get caught. I've heard horror stories about what they do to our people after they're imprisoned. They just disappear, no traces, nothing. ",TXT_DLG_SCRIPT34_D24256_DONTG,"〃 +(Similar to row 773)",,,"Nenech se chytit. Slyšel jsem děsivé příběhy o tom, co dělají našim lidem, když je uvězní. Prostě zmizí... beze stopy.","Bliv ikke fanget. Jeg har hørt skrækhistorier om, hvad de gør ved vores folk, efter de er blevet fængslet. De forsvinder bare, ingen spor, ingenting.","Lass dich nicht erwischen. Ich habe Horrorgeschichten darüber gehört, was sie unseren Leuten antun, die sie gefangengenommen haben. Sie verschwinden einfach... ohne jede Spur.",,"Oni ne kaptu vin. Mi aŭdis terurajn historiojn pri tio, kio okazas al niaj homoj post ilia aresto: ili simple malaperas, nek restaĵoj nek io ajn.",Que no te atrapen. He oído historias terroríficas de lo que hacen con nuestros hombres una vez detenidos: simplemente desaparecen sin rastros ni nada.,,"Älä jää kiinni. Olen kuullut kauhukertomuksia siitä, mitä ne tekevät meidän omillemme, kun he jäävät vangiksi. He yksinkertaisesti katoavat, jälkeä jättämättä.",Ne vous faites pas avoir. J'ai entendu des choses horribles sur ce qu'ils font à ceux qu'ils emprisonnent. Ils disparaîssent... Sans laisser de trace.,"Csak ne kapjanak el. Borzasztó történeteket hallottam azokról akiket bebörtönöztek. Csak úgy nyomuk vész, semmi nyom, konkrétan semmi.","Non farti prendere. Ho sentito storie orribili su quello che fanno alle persone dopo che le catturano. Spariscono completamente, senza tracce, niente di niente.","決して捕まるな。投獄されると奴等が 何をしでかすか怪談として聞く程だ。 -跡形もなく...消される。",오더에게 잡혀가면 절대로 안 됩니다. 수감자들에게 온갖 끔찍한 짓을 저지른다는 이야기를 들은 적이 있었으니까요. 흔적없이 조용히 끌고 간다네요...,"Laat je niet vangen. Ik heb horrorverhalen gehoord over wat ze onze mensen na hun gevangenschap aandoen. Ze verdwijnen gewoon, geen sporen, niets.",,"Não deixe eles te pegarem. Ouvi histórias de terror sobre o que eles fazem com o nosso pessoal depois que são aprisionados. Eles desaparecem, sem deixar rastros.",,,"Не дай себя схватить. Я слышал ужасные истории о том, что они делают с арестованными. Те просто исчезают... без следа.", -"Here's some advice, if you ever see any of the Order's tin soldiers, run the other way. I especially don't like the Reavers, those things are just damned fast!",TXT_DLG_SCRIPT34_D25772_HERES,,,,"Dám ti radu: Jestli někdy uvidíš jednoho z plecháčků Řádu, otoč se a jdi. Jsou rychlí a suroví.","Hier ist ein guter Rat, falls du jemals einen dieser Zinnsoldaten des Ordens vorbeigehen siehst. Sie sind schnell und brutal. ",,,"Un consejo, si ves algún soldadito de la Orden, da la vuelta y corre. En especial no me gustan los Saqueadores, ¡esas cosas son jodidamente rápidas!",,,"Voilà un conseil. Si vous voyez un des soldats mécanisés de l'Ordre, retournez vous et courez. Ils sont rapides et brutaux. J'aime surtout pas les Reavers, ces satanés trucs vont trop vite!",,,"伝えておく、オーダーの錫兵は +跡形もなく...消される。",오더에게 잡혀가면 절대로 안 됩니다. 수감자들에게 온갖 끔찍한 짓을 저지른다는 이야기를 들은 적이 있었으니까요. 흔적없이 조용히 끌고 간다네요...,"Laat je niet vangen. Ik heb horrorverhalen gehoord over wat ze onze mensen na hun gevangenschap aandoen. Ze verdwijnen gewoon, geen sporen, niets.","Ikke bli tatt. Jeg har hørt skrekkhistorier om hva de gjør med folket vårt etter at de blir fengslet. De bare forsvinner, ingen spor, ingenting.","Nie daj się złapać. Słyszałem przerażające historie o tym, co robią z naszymi ludźmi po uwięzieniu. Po prostu znikają, żadnych śladów, nic.","Não deixe eles te pegarem. Ouvi histórias de terror sobre o que eles fazem com o nosso pessoal depois que são aprisionados. Eles desaparecem, sem deixar rastros.",,Nu fii prins. Am auzit povești de groază legate de ce tratament primesc oamenii odată ce sunt închiși. Pur și simplu dispar fără niciun fel de urmă.,"Не дай себя схватить. Я слышал ужасные истории о том, что они делают с арестованными. Те просто исчезают... без следа.",,"Bli inte ertappad. Jag har hört skräckhistorier om vad de gör med vårt folk efter att de blivit fängslade. De bara försvinner, inga spår, ingenting.","Sakın yakalanmayın. Hapsedildikten sonra insanlarımıza ne yaptıklarına dair korku hikayeleri duydum. Öylece ortadan kayboluyorlar, ne bir iz ne de başka bir şey." +"Here's some advice, if you ever see any of the Order's tin soldiers, run the other way. I especially don't like the Reavers, those things are just damned fast!",TXT_DLG_SCRIPT34_D25772_HERES,"〃 +(Similar to row 774)",,,"Dám ti radu: Jestli někdy uvidíš jednoho z plecháčků Řádu, otoč se a jdi. Jsou rychlí a suroví.","Her er et godt råd: Hvis du nogensinde ser nogen af Ordenens tinsoldater, så løb den anden vej. Jeg kan især ikke lide Reavers, de er bare forbandet hurtige!","Hier ist ein guter Rat, falls du jemals einen dieser Zinnsoldaten des Ordens vorbeigehen siehst. Sie sind schnell und brutal. ",,Jen konsilo: estu ĉiam fore de la artefaritaj soldatoj de La Ordeno. Mi plej malŝatas Lertulojn; ili estas rapidegaj!,Un consejo: mantente siempre alejado de los soldados artificiales de La Orden. Los Saqueadores son los peores; ¡esas cosas son jodidamente rápidas!,Un consejo: mantente siempre alejado de los soldados artificiales de La Orden. Los Saqueadores son los peores; ¡esos desgraciados son rápidos!,"Annan pienen vinkin: Jos koskaan näet Veljeskunnan tinasotilaita, juokse toiseen suuntaan. Inhoan varsinkin raastajia; ne ovat vaan niin pirun nopeita!","Voilà un conseil. Si vous voyez un des soldats mécanisés de l'Ordre, retournez vous et courez. Ils sont rapides et brutaux. J'aime surtout pas les Reavers, ces satanés trucs vont trop vite!","Az a tanácsom számodra, hogy ha meglátod a Rend ólomkatonáit, vedd az utad az ellentétes irányba. Különösen igaz ez a fosztogatókra, piszkosul gyorsak.","Ecco un consiglio. Se vedi uno dei soldatini di latta dell'Ordine, vai nella direzione opposta. In particolare temo i Reaver, quei dannati robot sono davvero veloci!","伝えておく、オーダーの錫兵は 他方から呼び出され押し寄せてくる。 -奴等は素早く残忍だ。","충고 하나 해주죠. 오더의 로봇 병사들을 발견한다면, 조용히 피해가세요. 특히나 성가신 놈 중 하나가 리버인데, 그놈의 산탄총은 장난 아니에요!","Hier is een advies, als je ooit een van de tinnen soldaten van de Orde ziet, ren dan de andere kant op. Ik hou vooral niet van de Reavers, die dingen zijn gewoon verdomd snel!",,"Um conselho pra você: se você ver algum desses soldados de lata da Ordem, fuja para o lado oposto. Eu particularmente detesto os Saqueadores. Eles são rapidos pra caramba!",,,"Небольшой совет: если увидишь «оловянных солдатиков» Ордена, сворачивай в другую сторону. Я особенно не люблю похитителей — эти твари довольно быстрые!", -"Welcome to the last flicker of hope. Only we have the free will to oppose the Order. We have the sharpest scientific minds, and many able bodies. But we lack that one real problem solver, who will give us the edge we need.",TXT_DLG_SCRIPT34_D27288_WELCO,,,,"Vítej u posledního plamínku naděje. Jen my máme svobodnou vůli vzdorovat Řádu. Máme sice nejčilejší vědecké génie a mnoho schopných vojáků, ale chybí nám ten jeden řešitel problémů, který by nás posunul vpřed.","Wilkommen beim letzten Hoffnungsschimmer. Nur wir haben noch den freien Willen, um gegen den Orden zu arbeiten. Wir haben die besten Wissenschaftler und viele fähige Kämpfer aber was uns fehlt ist ein spezieller Problemlöser, der uns den nötigen Vorteil verschafft.",,,"Bienvenido al último destello de esperanza. Solo nosotros tenemos el libre albedrío para oponernos a la Orden. Tenemos las mentes científicas más brillantes, y muchos cuerpos capaces. Pero nos falta un verdadero solucionador de problemas, alguien que nos de la ventaja que necesitamos.",,,"Bienvenue au dernier lieu d'espoir. Nous seuls avons la liberté d'esprit pour opposer l'Ordre. Nous avons les esprits scientifiques les plus aiguisés et de nombreux hommes habiles et sains.. Mais il nous manque quelqu'un qui pourrait.. résoudre nos problèmes. Nous donner un peu d'aide, nous permettre de prendre l'avantage.",,,"ようこそ、ここは我々の僅かな希望が集まる +奴等は素早く残忍だ。","충고 하나 해주죠. 오더의 로봇 병사들을 발견한다면, 조용히 피해가세요. 특히나 성가신 놈 중 하나가 리버인데, 그놈의 산탄총은 장난 아니에요!","Hier is een advies, als je ooit een van de tinnen soldaten van de Orde ziet, ren dan de andere kant op. Ik hou vooral niet van de Reavers, die dingen zijn gewoon verdomd snel!","Hvis du ser noen av Ordenens tinnsoldater, så løp den andre veien. Jeg liker spesielt ikke Reavers, de er så jævla raske!","Oto rada, jeśli kiedykolwiek zobaczysz któregoś z blaszanych żołnierzy Zakonu, uciekaj w drugą stronę. Szczególnie nie lubię Łupieżców, te rzeczy są cholernie szybkie!","Um conselho pra você: se você ver algum desses soldados de lata da Ordem, fuja para o lado oposto. Eu particularmente detesto os Saqueadores. Eles são rapidos pra caramba!",,"Iată un sfat, dacă vezi vreodată un soldat al Ordinului, fugi în direcția opusă. Îmi displac mai ales Războinicii, ăștia sunt pur și simplu rapizi!","Небольшой совет: если увидишь «оловянных солдатиков» Ордена, сворачивай в другую сторону. Я особенно не люблю похитителей — эти твари довольно быстрые!",,"Här är ett råd, om du någonsin ser någon av ordens tennsoldater, spring åt andra hållet. Jag gillar särskilt inte Reavers, de där sakerna är förbannat snabba!","Size bir tavsiye, Tarikat'ın teneke askerlerinden birini görürseniz, diğer tarafa kaçın. Özellikle Yağmacıları sevmiyorum, o şeyler çok hızlı!" +"Welcome to the last flicker of hope. Only we have the free will to oppose the Order. We have the sharpest scientific minds, and many able bodies. But we lack that one real problem solver, who will give us the edge we need.",TXT_DLG_SCRIPT34_D27288_WELCO,MAP34: Macil.,,,"Vítej u posledního plamínku naděje. Jen my máme svobodnou vůli vzdorovat Řádu. Máme sice nejčilejší vědecké génie a mnoho schopných vojáků, ale chybí nám ten jeden řešitel problémů, který by nás posunul vpřed.","Velkommen til det sidste lille håb. Kun vi har den frie vilje til at modsætte os Ordenen. Vi har de skarpeste videnskabelige hjerner og mange dygtige kroppe. Men vi mangler den ene rigtige problemløser, som vil give os den fordel, vi har brug for.","Wilkommen beim letzten Hoffnungsschimmer. Nur wir haben noch den freien Willen, um gegen den Orden zu arbeiten. Wir haben die besten Wissenschaftler und viele fähige Kämpfer aber was uns fehlt ist ein spezieller Problemlöser, der uns den nötigen Vorteil verschafft.",,"Bonvenon en la lasta fajrero da espero. Nur ni havas liberan volon por kontraŭstari al La Ordeno. Ni havas la plej inteligentajn mensojn kaj multe da kapablaj homoj, sed mankas tiu... tiu, kiu estus vera problem-solvanto, por ke li donu al ni la necesan avantaĝon.","Bienvenido al último destello de esperanza. Solo nosotros tenemos el libre albedrío para oponernos a La Orden. Tenemos las mentes científicas más brillantes y muchas personas capaces, pero nos falta el que... el que sería todo un solucionador de problemas para que nos dé la ventaja que necesitamos.",,"Tervetuloa viimeisen toivonpilkahduksen äärelle. Ainoastaan meillä on vapaa tahto vastustaa Veljeskuntaa. Meillä on tieteen terävimmät mielet ja monia ruumiiltaan vahvoja, mutta meiltä puuttuu se yksi todellinen ongelmanratkoja, joka antaisi meille kaipaamamme etulyöntiaseman.","Bienvenue au dernier lieu d'espoir. Nous seuls avons la liberté d'esprit pour opposer l'Ordre. Nous avons les esprits scientifiques les plus aiguisés et de nombreux hommes habiles et sains.. Mais il nous manque quelqu'un qui pourrait.. résoudre nos problèmes. Nous donner un peu d'aide, nous permettre de prendre l'avantage.","Köszöntelek a remény utolsó pislákoló fényénél. Már csak mi merünk szembeszállni a Renddel. Itt vannak a legélesebb elmék, életerős emberek, de hiányzik egy igazi...probléma megoldó, aki előnyt szerez számunkra. Segíts nekünk!","Benenuto nell'ultimo barlume di speranza. Noi siamo i soli ad avere la determinazione per combattere l'Ordine. Abbiamo brillanti scienziati e molti soldati capaci, ma ci manca quel vero e proprio risolutore di problemi, che ci può dare quel vantaggio che cerchiamo.","ようこそ、ここは我々の僅かな希望が集まる 最後の場所だ。オーダーへと立ち向かう意思を 持っているのは我々くらいだ。 ここには素晴らしい頭脳を持つ学者たち、 そして丈夫な体を持った戦士たちがいる。 だがしかし、我々には問題解決に優れた者、 つまり私達の力となる者が足りていないんだ。 -我々に手を貸してくれ。","희미한 희망에 빛에 온 것을 환영합니다. 우리만이 오더를 처치할 자유의지를 가지고 있지요. 우수한 과학력에, 뛰어난 실력을 소유한 부대도 있으니까 말입니다. 하지만, 우리들에게도 부족한 게 하나 있습니다. 바로 시련을 해결해 줄 해결사죠. 부디 도와주세요.","Welkom bij het laatste sprankje hoop. Alleen wij hebben de vrije wil om ons te verzetten tegen de Orde. We hebben de scherpste wetenschappelijke geesten en veel bekwame lichamen. Maar we missen die ene echte probleemoplosser, die ons de voorsprong zal geven die we nodig hebben.",,"Seja bem-vindo à última ponta de esperança. Somos os únicos que têm o livre arbítrio para combater a Ordem. Temos as mentes científicas mais afiadas e muitas pessoas capazes. Mas ainda nos falta aquele verdadeiro quebra-galho, que nos dará o impulso que precisamos.",,,"Добро пожаловать в последний оплот надежды. Только мы обладаем свободной волей, чтобы противостоять Ордену. С нами лучшие учёные умы, и у нас есть много толковых людей, но нам не хватает одного-единственного, э... «разрешителя проблем», который поможет нам получить необходимое преимущество.", -What will I need to do? ,TXT_RPLY0_SCRIPT34_D27288_WHATW,,,,Co budu muset udělat?,Was muss ich tun?,,,¿Qué necesito hacer?,,,Que dois-je faire?,,,何をしたらいい?,무엇을 해야하죠?,Wat moet ik doen?,,O que preciso fazer?,,,Что я должен сделать?, -Help us. Help us steal their technology. Free our comrades. Fight these twisted psychopaths to the death. I'm asking you to risk your life for the truth.,TXT_DLG_SCRIPT34_D28804_HELPU,,,,Pomoz nám. Pomoz nám ukrást jejich technologie. Osvobodit naše druhy. Bojovat s těmi šílenými psychopaty na smrt. Chci po tobě riskovat svůj život kvůli pravdě.,"Hilf uns. Hilf uns ihre Technologie zu stehlen. Befreie unsere Kameraden. Bekämpfe diese verwirrten Psychopathen bis zum Tod. Ich bitte dich, dein Leben zu riskieren um die Wahrheit zu verteidigen.",,,Ayúdanos. Ayúdanos a robar su tecnología. Libera a nuestros camaradas. Lucha contra estos retorcidos psicópatas hasta la muerte. Te estoy pidiendo que arriesgues tu vida por la verdad.,,,Aidez nous. Aidez nous à voler leur technologie. Libérer nos camarades. Combattre ces psychopathes jusqu'à la mort. Je vous demande de risquer votre vie pour la vérité.,,,"我々の援護だ。我々が奴等のテクノロジーを +我々に手を貸してくれ。","희미한 희망에 빛에 온 것을 환영합니다. 우리만이 오더를 처치할 자유의지를 가지고 있지요. 우수한 과학력에, 뛰어난 실력을 소유한 부대도 있으니까 말입니다. 하지만, 우리들에게도 부족한 게 하나 있습니다. 바로 시련을 해결해 줄 해결사죠. 부디 도와주세요.","Welkom bij het laatste sprankje hoop. Alleen wij hebben de vrije wil om ons te verzetten tegen de Orde. We hebben de scherpste wetenschappelijke geesten en veel bekwame lichamen. Maar we missen die ene echte probleemoplosser, die ons de voorsprong zal geven die we nodig hebben.","Velkommen til det siste glimt av håp. Bare vi har den frie viljen til å motsette oss Ordenen. Vi har de skarpeste vitenskapelige hodene, og mange dyktige kropper. Men vi mangler den ene virkelige problemløseren, som vil gi oss det forspranget vi trenger.","Witamy w ostatniej iskierce nadziei. Tylko my mamy wolną wolę, by przeciwstawić się Zakonowi. Mamy najbystrzejsze umysły naukowe i wiele sprawnych ciał. Ale brakuje nam tego jednego prawdziwego rozwiązania problemu, które da nam przewagę, której potrzebujemy.","Seja bem-vindo à última ponta de esperança. Somos os únicos que têm o livre arbítrio para combater a Ordem. Temos as mentes científicas mais afiadas e muitas pessoas capazes. Mas ainda nos falta aquele verdadeiro quebra-galho, que nos dará o impulso que precisamos.",,"Bun-venit la ultima speranță. Numai noi avem voința de a ne opune Ordinului. Avem cele mai strălucite minți științifice și multe corpuri capabile. Dar ne lipsește acea persoană capabilă să rezolve probleme, care o să ne dea avantajul de care avem nevoie.","Добро пожаловать в последний оплот надежды. Только мы обладаем свободной волей, чтобы противостоять Ордену. С нами лучшие учёные умы, и у нас есть много толковых людей, но нам не хватает одного-единственного, э... «разрешителя проблем», который поможет нам получить необходимое преимущество.",,Välkommen till den sista gnistan av hopp. Endast vi har den fria viljan att motsätta oss Orden. Vi har de skarpaste vetenskapliga hjärnorna och många dugliga kroppar. Men vi saknar en riktig problemlösare som kan ge oss det övertag vi behöver.,Son umut ışığına hoş geldiniz. Tarikat'a karşı çıkacak özgür irade sadece bizde var. En keskin bilimsel zihinlere ve birçok yetenekli bedene sahibiz. Ama bize ihtiyacımız olan avantajı sağlayacak gerçek bir sorun çözücüden yoksunuz. +What will I need to do? ,TXT_RPLY0_SCRIPT34_D27288_WHATW,〃,,,Co budu muset udělat?,Hvad skal jeg gøre?,Was muss ich tun?,,Kion mi bezonas fari?,¿Qué necesito hacer?,,Mitä minun tarvitsee tehdä?,Que dois-je faire?,Mit kell tennem?,Che cosa devo fare?,何をしたらいい?,무엇을 해야하죠?,Wat moet ik doen?,Hva må jeg gjøre?,Co będę musiał zrobić?,O que preciso fazer?,,Ce trebuie să fac?,Что я должен сделать?,,Vad måste jag göra?,Ne yapmam gerekecek? +Help us. Help us steal their technology. Free our comrades. Fight these twisted psychopaths to the death. I'm asking you to risk your life for the truth.,TXT_DLG_SCRIPT34_D28804_HELPU,〃,,,Pomoz nám. Pomoz nám ukrást jejich technologie. Osvobodit naše druhy. Bojovat s těmi šílenými psychopaty na smrt. Chci po tobě riskovat svůj život kvůli pravdě.,Hjælp os. Hjælp os med at stjæle deres teknologi. Befri vores kammerater. Bekæmp disse forvredne psykopater til døden. Jeg beder dig om at sætte dit liv på spil for sandheden.,"Hilf uns. Hilf uns ihre Technologie zu stehlen. Befreie unsere Kameraden. Bekämpfe diese verwirrten Psychopathen bis zum Tod. Ich bitte dich, dein Leben zu riskieren um die Wahrheit zu verteidigen.",,"Helpu nin: helpu al ni ŝteli ilian teknologion, liberigu niajn kamaradojn, bataladu ĝismorte kontraŭ tiuj malicaj psikopatoj. Mi petas, ke vi risku vian vivon pro la vero.","Ayúdanos: ayúdanos a robar su tecnología, libera a nuestros camaradas, pelea contra esos retorcidos psicopáticos hasta la muerte. Te estoy pidiendo que arriesgues la vida por la verdad.",,Auta meitä. Auta meitä kaappaamaan heidän teknologiaansa. Vapauta meidän toverimme. Taistele näitä kieroituneita psykopaatteja vastaan kuoloon asti. Pyydän sinua antamaan henkesi alttiiksi totuuden nimessä.,Aidez nous. Aidez nous à voler leur technologie. Libérer nos camarades. Combattre ces psychopathes jusqu'à la mort. Je vous demande de risquer votre vie pour la vérité.,"Segíts nekünk. Abban, hogy ellophassuk a technológiájukat. Kiszabadítani a társainkat. Halálunkig harcolni ezek a pszihopaták ellen. Azt kell kérjem tőled, hogy tedd kockára az életed az igazságérrt.",Aiutaci. Aiutaci a rubare la loro tecnologia. Libera i nostri compagni. Combatti questi maledetti psicopatici fino alla morte. Ti sto chiedendo di rischiare la tua vita per la verità.,"我々の援護だ。我々が奴等のテクノロジーを 盗むのを手伝って欲しい。同胞の解放の為だ。 イカレた奴等と戦闘する必要がある。 正義を取り戻すため君には危険の伴う任務を -受けてほしいのだ。","우릴 도와주세요. 놈들의 기술을 훔치고, 붙잡힌 동료들을 구출하고, 오더의 미치광이들을 타도하기 위해서 말이죠. 그리고 진실 어린 희망을 위해서 이렇게 묻는 겁니다.",Help ons. Help ons hun technologie te stelen. Bevrijd onze kameraden. Bestrijd deze verdraaide psychopaten tot de dood toe. Ik vraag je om je leven te riskeren voor de waarheid.,,Nos ajudar. Ajude-nos a roubar a tecnologia deles. Liberte nossos companheiros. Lute contra esses psicopatas insanos até a morte. Estou te pedindo para arriscar a sua vida pela verdade.,,,Помочь нам. Помочь нам украсть их технологии. Освободить наших товарищей. Сразиться с этими извращёнными психопатами и убить их. Рискнуть своей жизнью ради правого дела., -I'm with you!,TXT_RPLY0_SCRIPT34_D28804_IMWIT,,,,Jsem s tebou!,Ich bin dabei.,,,¡Estoy contigo!,,,Je suis avec vous!,,,同意した!,함께 하겠습니다!,Ik sta achter je!,,Estou com vocês!,,,Хорошо! Я с вами!, -"Good. Blackbird will continue to be your guide. She's taken quite a shine to you. Together, you've got to unlock the secrets of the Order and their inhuman servants. There's a presence that lurks just outside our understanding which guides their terror. Get inside and take them down. ",TXT_DLG_SCRIPT34_D30320_GOODB,,,,"Dobře, Straka ti bude dále dávat pokyny. Docela ses jí zalíbil. Společně budete muset odkrýt tajemství Řádu a jeho nelidských služebníků. Někde mimo naše chápání je něco, co ovládá jejich řádění. Pronikněte dovnitř a sejměte je.","Gut so! Blackbird wird weiter deine Leiterin sein, sie scheint dich zu mögen. Zusammen müsst ihr die Geheimnisse des Ordens und ihrer unmenschlichen Diener ergründen. Dann haben wir eine Chance, sie niederzuringen. Da ist eine Präsenz außerhalb unseres Vorstellungsvermögens, das diesen Terror leitet. Wir müssen sie unterwandern und dann vernichten.",,,"Bien. Blackbird continuará siendo tu guía. Le caes bastante bien. Juntos, teneis que desvelar los secretos de la Orden y sus sirvientes inhumanos. Hay una presencia que acecha más allá de nuestro conocimiento que guía su terror. Adéntrate y derríbalos.","Bien. Blackbird continuará siendo tu guía. Le caes bastante bien. Juntos, deberán desvelar los secretos de la Orden y sus sirvientes inhumanos. Hay una presencia que acecha más allá de nuestro conocimiento que guía su terror. Adéntrate y derríbalos.",,"Parfait. Blackbird continuera à être votre guide. Elle semble vous apprécier. Ensemble, vous allez découvrir les secrets de l'Ordre et leurs servants inhumains. Il existe une présece qui rôde juste au dehors de notre compréhension qui guide cette terreur. Infiltrez-les et détruisez-les.",,,"いいぞ、今後もブラックバードが君のガイドを +受けてほしいのだ。","우릴 도와주세요. 놈들의 기술을 훔치고, 붙잡힌 동료들을 구출하고, 오더의 미치광이들을 타도하기 위해서 말이죠. 그리고 진실 어린 희망을 위해서 이렇게 묻는 겁니다.",Help ons. Help ons hun technologie te stelen. Bevrijd onze kameraden. Bestrijd deze verdraaide psychopaten tot de dood toe. Ik vraag je om je leven te riskeren voor de waarheid.,Hjelpe oss. Hjelp oss med å stjele teknologien deres. Befri kameratene våre. Kjemp mot disse forskrudde psykopatene til døden. Jeg ber deg om å risikere livet for sannheten.,"Pomóc nam. Pomóż nam wykraść ich technologię. Uwolnić naszych towarzyszy. Walczyć z tymi pokręconymi psychopatami na śmierć. Proszę cię, abyś zaryzykował swoje życie dla prawdy.",Nos ajudar. Ajude-nos a roubar a tecnologia deles. Liberte nossos companheiros. Lute contra esses psicopatas insanos até a morte. Estou te pedindo para arriscar a sua vida pela verdade.,,Ajută-ne. Ajută-ne să le furăm tehnologia. Să ne eliberăm compatrioții. Să luptăm cu acești psihopați suciți până la moarte. Îți cer să îți riști viața pentru adevăr.,Помочь нам. Помочь нам украсть их технологии. Освободить наших товарищей. Сразиться с этими извращёнными психопатами и убить их. Рискнуть своей жизнью ради правого дела.,,Hjälp oss. Hjälp oss att stjäla deras teknologi. Befria våra kamrater. Kämpa mot de här förvridna psykopaterna in i döden. Jag ber dig riskera ditt liv för sanningen.,Bize yardım et. Teknolojilerini çalmamıza yardım et. Yoldaşlarımızı serbest bırak. Bu sapkın psikopatlarla ölümüne savaş. Senden gerçek için hayatını riske atmanı istiyorum. +I'm with you!,TXT_RPLY0_SCRIPT34_D28804_IMWIT,〃,,,Jsem s tebou!,Jeg er med dig!,Ich bin dabei.,,Mi aliĝos al vi!,¡Estoy contigo!,,Olen kanssanne!,Je suis avec vous!,Veletek vagyok!,Sono con te!,同意した!,함께 하겠습니다!,Ik sta achter je!,Jeg er med deg!,Jestem z tobą!,Estou com vocês!,,Sunt cu tine!,Хорошо! Я с вами!,,Jag är med dig!,Seninleyim! +"Good. Blackbird will continue to be your guide. She's taken quite a shine to you. Together, you've got to unlock the secrets of the Order and their inhuman servants. There's a presence that lurks just outside our understanding which guides their terror. Get inside and take them down. ",TXT_DLG_SCRIPT34_D30320_GOODB,〃,,,"Dobře, Straka ti bude dále dávat pokyny. Docela ses jí zalíbil. Společně budete muset odkrýt tajemství Řádu a jeho nelidských služebníků. Někde mimo naše chápání je něco, co ovládá jejich řádění. Pronikněte dovnitř a sejměte je.","Jeg er med dig. Blackbird vil fortsat være din guide. Hun er blevet ret glad for dig. Sammen skal I løse hemmelighederne om Ordenen og deres umenneskelige tjenere. Der er en tilstedeværelse, der lurer lige uden for vores forståelse, som styrer deres terror. Kom ind og nedkæmp dem.","Gut so! Blackbird wird weiter deine Leiterin sein, sie scheint dich zu mögen. Zusammen müsst ihr die Geheimnisse des Ordens und ihrer unmenschlichen Diener ergründen. Dann haben wir eine Chance, sie niederzuringen. Da ist eine Präsenz außerhalb unseres Vorstellungsvermögens, das diesen Terror leitet. Wir müssen sie unterwandern und dann vernichten.",,"Bone. Merlo plue estos via gvidanto; ŝajnas, ke ŝi jam simpatias vin. Vi kune devas malkaŝi la sekretojn de La Ordeno kaj de ĝiaj nehomaj servantoj. Estas estaĵo trans homa kompreno, kiu gvatas kaj gvidas iliajn teruraĵojn. Enŝoviĝu kaj detruu ilin.",Bien. Blackbird seguirá siendo tu guía; parece que ya le caes bien. Juntos debéis descubrir los secretos de La Orden y de sus sirvientes inhumanos. Hay una presencia ultramundana observando y guiando su terror desde las sombras. Infiltraos y acabad con ellos.,Bien. Blackbird va a seguir siendo tu guía; parece que ya le caes bien. Juntos deben descubrir los secretos de La Orden y de sus sirvientes inhumanos. Hay una presencia ultramundana observando y guiando su terror desde las sombras. Infíltrense y destrúyanlos.,"Hyvä; Blackbird jatkaa opastajanasi. Hän vaikuttaa pitävän sinusta. Teidän on yhdessä paljastettava Veljeskunnan ja heidän epäinhimillisten palvelijoinsa salat. Heidän hirmuvaltaansa ohjaa läsnäolo, joka ylittää ymmärryksemme. Murtaudu sisään ja aja heidät alas.","Parfait. Blackbird continuera à être votre guide. Elle semble vous apprécier. Ensemble, vous allez découvrir les secrets de l'Ordre et leurs servants inhumains. Il existe une présece qui rôde juste au dehors de notre compréhension qui guide cette terreur. Infiltrez-les et détruisez-les.","Helyes, Feketerigó továbbra is az irányítód lesz. Eléggé megtetszettél neki. Együtt meg fogjátok fejteni a Rend és kegyetlen szolgáinak titkait. Egyfajta emberi ésszel fel nem fogható jelenlét kényszeríti őket a terrorizálásra. Hatoljatok be és intézzétek el őket.","Bene. Blackbird continuerà ad essere la tua guida. Sembra ti abbia preso in simpatia. Insieme dovrete scoprire i segreti dell'Ordine e dei loro servi inumani. C'è qualcosa di malefico, oltre la nostra comprensione, che guida il loro terrore. Bisognerà infiltrarlo e distruggerlo.","いいぞ、今後もブラックバードが君のガイドを 務める。彼女は君に感心しているようだぞ。 君たちの二人で、オーダーと その人間離れした手下たちが持っている秘密を 暴いてもらいたい。 -奴等の基地に潜り込んで、倒すんだ。","감사드립니다! 블랙버드가 당신을 위해 계속 안내를 할 것입니다. 같이 행동한다면 오더의 흉측한 비밀들을 밝혀내고, 그들의 잔혹한 존재들을 응징할 수 있을 겁니다. 우리들의 이해심 밑에 공포를 인도하는 그들의 숨겨진 존재가 있죠. 그곳으로 들어가서, 물리치세요.",Goed. Blackbird zal je gids blijven. Ze heeft je een behoorlijke glans gegeven. Samen moeten jullie de geheimen van de Orde en hun onmenselijke dienaren ontrafelen. Er is een aanwezigheid die net buiten ons begrip schuilt en die hun angst leidt. Ga naar binnen en neem ze mee naar beneden.,,"Ótimo. Blackbird continuará sendo a sua guia. Ela parece que vai com a sua cara. Juntos, vocês desvendarão os segredos da Ordem e seus discípulos desumanos. Há uma presença que está além do nosso entendimento que guia todo esse terror. Vá infiltrar a Ordem e elimine-os.",,,Хорошо. Чёрный дрозд останется твоим проводником. Она тебе несколько симпатизирует. Вместе вы раскроете секреты Ордена и его бесчеловечных слуг. За этим ужасом стоит нечто лежащее далеко за пределами нашего понимания. Проникни на их территорию и ударь по ним как следует!, -Let me at 'em!,TXT_RPLY0_SCRIPT34_D30320_LETME,,,,Pusť mě na ně!,Lass mich das nur machen.,,,¡Voy a por ellos!,¡Voy por ellos!,,Laissez moi m'en occuper!,,,任せろ!,저만 믿으세요!,Laat me naar ze toe!,,Pode deixar!,,,Я им покажу!, -That's the spirit.,TXT_RYES0_SCRIPT34_D30320_THATS,,,,Tak se mi to líbí.,Das ist die richtige Einstellung.,,,Ese es el espíritu.,,,J'aime entendre ça.,,,良い心掛けだ。,좋은 마음가짐입니다.,Dat is de geest.,,Esse é o espírito.,,,Правильный настрой., -Welcome friend!,TXT_DLG_SCRIPT34_D31836_WELCO,,,,"Vítej, příteli!","Wilkommen, Freund.",,"Bonvenon, amiko!",¡Bienvenido amigo!,,,"Bievenue, notre ami!",,,よく来た、同志!,"어서오세요, 친구여!",Welkom vriend!,,"Seja bem-vindo, amigo!",,,"Добро пожаловать, друг!", -,,Random dialogue,,,,,,,,,,,,,,,,,,,,, -Please don't hurt me.,TXT_RANDOM_PEASANT_01,,,,"Neubližuj mi, prosím.",Bitte tu mir nicht weh.,,,Por favor no me haga daño.,,,"S'il vous plaît, laissez-moi tranquille.",Kérlek ne bánts!,Ti prego non farmi male.,私を傷つけないでくれ。,목숨만은 살려줘.,Doe me alsjeblieft geen pijn.,,"Por favor, não me machuque.",,,"Пожалуйста, не трогай меня.", -"If you're looking to hurt me, I'm not really worth the effort.",TXT_RANDOM_PEASANT_02,,,,"Jestli mi chceš ublížit, fakt za to nestojím.","Falls du mir was antun willst, ich bin den Aufwand nicht wert.",,,"Si está tratando de hacerme daño, no vale la pena realmente.",,,"Si vous cherchez à me faire mal, Je n'en mérite pas l'effort.","Ha bántani akarsz, nem éri meg a fáradozást.","Sembra che tu voglia farmi del male, ma davvero, non ne valgo lo sforzo.","もしお前が私に暴力を振るいたいなら間違いだ、 -私を殴る価値はないから。","날 괴롭히려고 여기까지 왔다면, 넌 헛수고를 한 거야.","Als je me pijn wilt doen, ben ik de moeite niet echt waard.",,"Se pretende me machucar, te digo que não valerá a pena.",,,"Если ты хочешь ударить меня, то я не стою твоих усилий.", -I don't know anything.,TXT_RANDOM_PEASANT_03,,,,O ničem nevím.,Ich weiß nichts.,,,No se nada.,,,Je ne sais rien.,Én semmit sem tudok.,Non so nulla.,私は何も知らないんだ。,난 정말 아무것도 몰라.,Ik weet niets.,,Eu não sei de nada.,,,Я ничего не знаю., -Go away or I'll call the guards!,TXT_RANDOM_PEASANT_04,,,,"Jdi pryč, nebo zavolám stráže!",Hau ab oder ich rufe die Wachen!,,,¡Vete o llamaré a los guardias!,,,Allez vous en ou j'appelle les gardes!,"Tűnj innen, vagy hívom az őröket!",Vattene o chiamo le guardie!,離れろ、さもなくば衛兵を呼ぶぞ!,경비병 부르기 전에 얼른 사라져!,Ga weg of ik roep de bewakers!,,Vá embora antes que eu chame os guardas!,,,"Уходи, или я позову стражу!", -I wish sometimes that all these rebels would just learn their place and stop this nonsense.,TXT_RANDOM_PEASANT_05,,,,"Občas si přeju, aby si ti rebelové uvědomili, kde jsou, a skončili s těmi svými nesmysly.","Manchmal wünsche ich mir, dass diese Rebellen ihren Unsinn stoppen würden.",,,A veces deseo que todos los rebeldes simplemente aprendieran a vivir y se dejaran de tonterías.,A veces deseo que todos los rebeldes simplemente aprendan a vivir y parar con este absurdo.,,"Je voudrais qu'a un moment, ces rebelles apprennent quelle est leur place et arrètent cette idiotie.","Néha azt kívánom, hogy ezek a lázadók bár megtanulnák, hol a helyük, és felhagynának ezzel az eszeveszett dologgal.",A volte vorrei che tutti questi ribelli imparassero semplicemente a stare al loro posto e la smettessero con tutte queste fesserie.,"反乱軍がこんな出鱈目な状態をひっくり返すのを -切に願うよ。",저 저항군들이 가망이 없다는 걸 빨리 눈치챘으면 정말 좋겠군.,Ik wou soms dat al die rebellen gewoon hun plaats zouden leren kennen en deze onzin zouden stoppen.,,Às vezes eu queria que esses rebeldes cuidassem de suas próprias vidas e parassem com esse absurdo.,,,"Иногда мне хочется, чтобы все эти повстанцы просто поняли своё место и прекратили эту пустую возню.", -"Just leave me alone, OK?",TXT_RANDOM_PEASANT_06,,,,"Prostě mě nech být, jasný?","Lass mich bitte in Ruhe, ok?",,,"Déjame en paz, ¿vale?","Déjame solo, ¿de acuerdo?",,"Laissez moi seul, OK?","Csak hagyj magamra, jó?","Lasciami in pace e basta, OK?",私に構わないでくれよ、頼むぞ?,그냥 날 내버려 둬. 부탁이야.,"Laat me gewoon met rust, oké?",,"Apenas me deixe em paz, ok?",,,"Просто оставь меня в покое, хорошо?", -"I'm not sure, but sometimes I think that I know some of the acolytes.",TXT_RANDOM_PEASANT_07,,,,"Nejsem si jistý, ale občas se mi zdá, že znám některé z akolytů.","Ich bin nicht ganz sicher, aber manchmal kommt es mir vor, als kenne ich diese Ministranten.",,,"No estoy seguro, pero a veces creo que reconozco a algunos de los acólitos.","No estoy seguro, pero a veces creo que ya conozco a algunos de los acólitos.",,"Je ne suis pas sûr, mais quelque fois je pense reconnaître certains des acolytes.","Nem vagyok benne bizonyos, de néha mintha ismerném némelyik ministránst.","Non ne sono sicuro, ma volte mi sembra di conoscere alcuni degli accoliti.","何か、アコライトの中で見覚えのある顔したのが -いたんだが。","자세히는 모르지만, 내가 본 아콜라이트들 중에 아는 사람이 있는 것 같아.","Ik weet het niet zeker, maar soms denk ik dat ik sommige van de acolieten ken.",,"Eu não tenho bem certeza, mas acho que conheco alguns dos acólitos.",,,"Я не уверен, но порой мне кажется, что я узнаю некоторых служителей.", -The Order's got everything around here pretty well locked up tight.,TXT_RANDOM_PEASANT_08,,,,Řád to tu má všechno pod hodně přísným dohledem.,Der Orden hat hier alles ziemlich gut unter Kontrolle.,,,La orden tiene todo por aquí fuertemente bloqueado.,,,L'ordre maintient la sûreté aux alentours.,A Rend mindent jól elzárt előlünk.,L'Ordine si è dato parecchio da fare per chiudere e sbarrare un po' tutto qui in giro.,オーダー達はここいらを厳しく取り締まってる。,오더가 치안유지도 그렇고 단속을 아주 실감 나게 잘하던데?,De Orde heeft alles hier in de buurt vrij goed afgesloten.,,A Ordem mantém tudo trancado a sete chaves.,,,Орден держит тут всё под замком., -There's no way that this is just a security force.,TXT_RANDOM_PEASANT_09,,,,"Není možné, aby tohle byly jen bezpečnostní složky.",Das sind niemals nur Sicherheitskräfte.,,,No hay manera de que esto sea sólo una fuerza de seguridad.,,,Ca ne peut pas être juste une escouade de sécurité...,Na ez már tutira nem lehet csak a biztonsági szolgálat.,"E' impossibile che questa sia solo una ""Forza di Sicurezza"".",お前がただの警備兵なんてことはなさそうだな。,저 녀석들은 단순히 치안을 유지하기 위해 온 게 아니라고 생각해.,Er is geen sprake van dat dit gewoon een veiligheidsdienst is.,,Não tem como isso ser apenas um força de segurança.,,,Без разрешения стражей порядка и шагу ступить нельзя., -I've heard that the Order is really nervous about the Front's actions around here.,TXT_RANDOM_PEASANT_10,,,,"Slyšel jsem, že je Řád prý dost nervózní z toho, co tu Fronta dělá.","Ich habe gehört, dass der Orden sehr beunruhigt über die Aktionen der Front ist.",,,He oído que la orden está realmente nerviosa por las acciones del frente en los alrededores.,,,J'ai entendu dire que l'ordre était sur les nerfs à cause des actions du front.,Úgy hírlik A Rend nagyon ideges a Front munkálkodásai miatt mostanság.,Ho sentito che l'Ordine è parecchio nervoso riguardo le azioni del Fronte nei dintorni.,"私はオーダーがこの辺での反乱軍の行動を -本当に厄介がってると聞いたぞ。",오더가 프론트 저항군의 공작에 정말 불안해하고 있더라고.,Ik heb gehoord dat de Orde echt nerveus is over de acties van het Front hier in de buurt.,,Ouvi falar que a Ordem anda bem nervosa por causa das ações da Frente por aqui.,,,"Я слыхал, что Орден серьёзно обеспокоен действиями повстанцев в этом районе.", -There's no way the Order will stand against us.,TXT_RANDOM_REBEL_01,,,,Řád se nám v žádném případě nemůže postavit.,Niemals wird sich der Orden gegen uns stellen!,,,No hay forma de que la orden aguante contra nosotros.,No hay forma de que la orden se levante contra nosotros.,,L'ordre n'a aucune chance contre nous.,A Rend labdába sem rúghat ellenünk!,Non esiste che l'Ordine possa mettersi contro di noi.,オーダーが私達に立ち向かえるはずはない。,오더 녀석들이 우리를 이길 가능성은 전혀 없어.,De Orde zal op geen enkele manier tegen ons ingaan.,,Nao ha como a Ordem ficar contra a gente.,,,Ордену никак не устоять против нас., -We're almost ready to strike. Macil's plans are falling in place.,TXT_RANDOM_REBEL_02,,,,Jsme téměř připraveni zaútočit. Macilovy plány do sebe začínají zapadat.,Wir sind zum großen Schlag bereit. Macils Plane werden bald umgesetzt.,,,Estamos casi listos para atacar. Los planes de Macil están cayendo en su lugar.,Estamos casi listos para atacar. Los planes de Macil se están cayendo en su lugar.,,Nous sommes presque prêts à agir. Les plans de Macil se déroulent comme prévu.,"Már majdnem készen állunk, hogy lecsapjunk. Macil tervei kezdenek bejönni.",Siamo quasi pronti a colpire. I piani di Macil stanno andando lisci come l'olio.,"攻撃の準備は殆ど整った。 -マシルの計画は所定の位置に下す。",반격할 준비가 거의 다 돼가고 있어. 마실 사령관님의 계획이 잘 진행되고 있으니까.,We zijn bijna klaar om toe te slaan. Macil's plannen vallen op zijn plaats.,,Estamos quase prontos para o ataque. Os planos de Macil estão fazendo efeito.,,,Мы почти готовы атаковать. Планы Мэйсила становятся ясны., -"We're all behind you, don't worry.",TXT_RANDOM_REBEL_03,,,,"Všichni stojíme za tebou, neboj.","Wir stehen zu dir, keine Sorge.",,,"Todos estamos detrás de ti, no te preocupes.",,,"On couvre tes arrières, t'inquiète pas.","Mind itt vagyunk mögötted, ne aggódj!","Non preoccuparti, ti copriamo tutti le spalle.",後ろは見ているぞ、気にするな。,걱정 마. 무슨 일이 있어도 우리가 지켜줄게!,"We staan allemaal achter je, maak je geen zorgen.",,"Estamos todos te protegendo, não se preocupe.",,,Не беспокойся. Мы сразу за тобой., -Don't get too close to any of those big robots. They'll melt you down for scrap!,TXT_RANDOM_REBEL_04,,,,Nepřibližuj se k těm velkým robotům. Roztaví tě na šrot!,Komm diesen großen Robotern nicht zu nahe. Die schmelzen dich zu Schrott ein.,,,No te acerques tanto a uno de esos robots grandes. ¡Podrían derretirte para chatarra!,,,Ne vous approchez pas trop des gros robots. Ils vous brûleront jusqu'à l'os!,Azokhoz a nagy robotokhoz ne nagyon menj közel. Felaprítanak tüzifának!,Non stare troppo vicino a uno di quei grossi robot. Ti potrebbero sciogliere per i rottami!,"デカブツには近づくなよ。スクラップみたいに -踏みつぶされるぞ!",저 커다란 로봇들에게 다가갈 생각은 하지 마. 너를 완전 발끝까지 녹여버릴 거라고.,Kom niet te dicht bij een van die grote robots. Ze zullen je laten smelten voor de schroothoop!,,Nem pense em ficar perto daqueles robôs. Vão te transformar em ferro velho num instante!,,,Держись подальше от этих больших роботов. Они и мокрого места от тебя не оставят!, -"The day of our glory will soon come, and those who oppose us will be crushed!",TXT_RANDOM_REBEL_05,,,,"Naše dny slávy brzy nadejdou a ti, kdo se nám postaví, budou rozdrceni!","Der Tag des Triumphes ist nahe, und die, die gegen uns sind, werden vernichtet.",,,"¡El día de nuestra gloria llegará pronto, y aquellos que se opusieron a nosotros serán destruidos!",,,"Le jour de gloire arrivera bientôt, et ceux qui s'opposeront a nous seront écrasés!","Dicsőségünk napja hamarosan eljön, és akik ellenünk szegülnek, elkárhoznak.","Il giorno della nostra gloria verrà presto, e quelli che si oppongono a noi sarà schiacciato!","栄光の日は我々に訪れる、 -そして反逆する者達は潰す!",영광스러운 새벽이 오고있어. 우리를 탄압한 녀석들에게 징벌을 내릴 새벽이!,"De dag van onze glorie zal snel komen, en degenen die zich tegen ons verzetten zullen worden verpletterd!",,"O dia de nossa glória chegará, e aqueles que se opuserem contra nós serão destruídos!",,,Близок день нашего триумфа. Скоро наши враги будут уничтожены!, -Don't get too comfortable. We've still got our work cut out for us.,TXT_RANDOM_REBEL_06,,,,"Neusínej na vavřínech, stále máme před sebou hodně práce.","Werd nicht leichtsinnig, es gibt noch eine Menge zu tun.",,,No te pongas muy cómodo. Ya tenemos nuestro propio trabajo asignado a cada uno.,,,Ne vous reposez pas sur vos lauriers. Du travail nous attend encore.,Annyira azért ne érezd otthon magad. Nekünk még van némi munka kiosztva idelenn.,Non metterti troppo comodo. Ci sta ancora il nostro lavoro ritagliato per noi.,"あまり気楽でいるな。 -我々にはまだやるべき事があるんだ。",게으름 피울 생각하지는 마. 아직 일이 잘 안 풀렸으니까.,Maak het je niet al te comfortabel. We hebben nog steeds werk voor de boeg.,,Não fique muito confortável. Ainda temos trabalho a fazer.,,,Не расслабляйся. У нас по-прежнему хватает дел., -Macil says that you're the new hope. Bear that in mind.,TXT_RANDOM_REBEL_07,,,,"Macil říká, že jsi naše nová naděje. Pamatuj na to.",Macil nennt dich unsere neue Hoffnung. Vergiss das nicht.,,,Macil dice que eres la nueva esperanza. Ten eso en mente.,,,Macil nous dit que tu es notre nouvel espoir. Garde ça à l'esprit.,Macil szerint te vagy az új reményünk. Ezt sose feledd!,Macil dice che tu sei la nuova speranza. Tienilo a mente.,"マシルは貴方が新しい希望だと言っている。 -心に留めておいてくれ。",마실 사령관님이 말하기를 네가 우리들의 유일한 희망이래. 명심해 둬.,Macil zegt dat jij de nieuwe hoop bent. Houd dat in gedachten.,,Macil disse que você é a nova esperança. Lembre-se disso.,,,"Мэйсил говорит, что на тебя сейчас вся надежда. Имей это в виду.", -"Once we've taken these charlatans down, we'll be able to rebuild this world as it should be.",TXT_RANDOM_REBEL_08,,,,"Jakmile sesadíme ty šarlatány, budeme moci znovu vybudovat svět tak, jaký by měl být.","Wenn wir diese Scharlatane entmachtet haben, können wir unsere Welt endlich neu aufbauen.",,,"Una vez que hayamos eliminado a estos charlatanes, podremos reconstruir este mundo como debe ser.","Una vez que hayamos bajado a estos charlatanes, podremos reconstruir este mundo como debe ser.",,"Une fois que nous nous serons débarassés de ces charlatans, nous serons capable de rebâtir le monde tel qu'il devrait être.","Amint lenyomtuk ezeket a sarlatánokat, végre újjáépíthetjük ezt a világot olyanra, amilyennek lennie kéne.","Una volta che eliminiamo questi ciarlatani, potremo ricostruire questo mondo a come dovrebbe essere.","我々が一度こんな酷いハッタリを負かせば、 -世界を本来の状態に建て直せるだろう。","저 허풍쟁이들을 다 물리칠 수만 있다면, 우리가 바랬던 평화로운 세상을 재건할 수 있을 거야.","Als we deze charlatans eenmaal hebben verwijderd, kunnen we deze wereld weer opbouwen zoals het hoort.",,"Assim que derrubarmos esses charlatões, poderemos reconstruir o mundo do jeito certo.",,,"Когда мы свергнем этих шарлатанов, то сможем воссоздать этот мир таким, каким он должен быть.", -"Remember that you aren't fighting just for yourself, but for everyone here and outside.",TXT_RANDOM_REBEL_09,,,,"Nezapomeň, že nebojuješ jen kvůli sobě, ale kvůli všem tady a tam venku.","Vergiß nicht, dass du nicht nur für dich selbst kämpfst, sondern für alle von uns da draußen.",,,"Recuerda que no estás peleando solo por ti, sino por todos aquí y afuera.",,,"Souviens-toi, tu ne te bats pas seulement pour toi, mais pour tous le monde ici et ailleurs.","Ne feledd, nem csak magadért harcolsz, hanem mindnyájunkért idebent, és odakint.","Ricordati che non stai combattendo solo per te stesso, ma per tutti quelli che sono qui e fuori.","貴方は自分自身だけでなく、 -国中の人の為に戦っている事を忘れないでくれよ。",너 혼자 위해서 싸우는 게 아니라 인류를 위해서 싸우고 있다는 걸 잊지 마.,"Onthoud dat je niet alleen voor jezelf vecht, maar voor iedereen hier en daarbuiten.",,"Lembre-se que você não está lutando só por si mesmo, mas por todos nós.",,,"Помни, ты сражаешься не только за себя, но и за каждого здесь и снаружи.", -"As long as one of us still stands, we will win.",TXT_RANDOM_REBEL_10,,,,"Dokud je alespoň jeden z nás na nohou, vyhrajeme!","Solange nur einer von uns steht, werden wir gewinnen.",,,"Mientras uno de nosotros siga en pie, ganaremos.",,,"Aussi longtemps qu'un de nous est vivant, nous vaincrons.","Ha csak egy is marad meg közülünk, nyerni fogunk.","Finché ci sarà uno di noi in piedi, vinceremo.",我々が一人でも立っていれば、それが勝利。,"우리 중 한 명이 남아있는 한, 이길 수 있어.","Zolang één van ons nog staat, zullen we winnen.",,"Enquanto um de nós ainda estiver de pé, teremos chance de vencer.",,,"Пока хотя бы один из нас ещё дышит, мы непобедимы.", -"Move along, peasant.",TXT_RANDOM_AGUARD_01,,,,"Jdi dál, poddaný.","Beweg dich, Bauer!",,,"Muévete, plebeyo.",,,"Barre-toi, paysan!","Mozgás, paraszt. Egy kettő.","Spostati, contadino.",立ち去れ、百姓。,"어서 움직여, 이 자식아.","Ga verder, boer.",,"Continue andando, plebeu.",,,"Проходи, рабочий.","Мрдај одавде, сироче." -"Follow the true faith, only then will you begin to understand.",TXT_RANDOM_AGUARD_02,,,,"Následuj pravou víru, jen tak začneš chápat.",Folge dem wahren Glauben und du wirst verstehen.,,,"Sigue la fe verdadera, sólo entonces empezarás a entender.",,,"Suis la vraie foi, tu commençeras a comprendre.","Csak ha az igaz hitet követed, csakis akkor kezded majd megérteni.","Segui la vera fede, solo allora comincerai a capire.",真の信仰を求めよ、それしか理解に至る道はない。,참된 신앙이야말로 자기 자신을 깨우칠 수 있지.,"Volg het ware geloof, pas dan zul je het begrijpen.",,Siga a verdadeira fé. Só então você começará a entender.,,,Следуй истинной вере. Только тогда ты начнёшь понимать., -Only through death can one be truly reborn.,TXT_RANDOM_AGUARD_03,,,,Pouze skrz smrt lze dosáhnout znovuzrození.,Nur durch den Tod kann man wirklich wiedergeboren werden.,,,Sólo a través de la muerte uno puede realmente renacer.,,,C'est seulement a travers la mort que quelqu'un peut renaître.,Csak a halál útján lehet igazán újjászületni.,Solo attraverso la morte uno può rinascere per davvero.,人が真の意味で生まれ変われる方法は、死のみだ,죽음을 통해서만이 진정하게 환생할 수 있는 거다.,Alleen door de dood kan men echt herboren worden.,,Somente através da morte que alguem poderá renascer de verdade.,,,Истинное перерождение возможно только через смерть., -I'm not interested in your useless drivel.,TXT_RANDOM_AGUARD_04,,,,Nezajímají mě tvoje žvásty.,Dein nutzloses Geschwafel interessiert mich nicht.,,,No estoy interesado en tu charlatanería.,No estoy interesado en tus inútiles tonterías.,,Je ne suis pas intéressé par tes idioties inutiles.,Nem érdekel az értelmetlen hablatyolásod.,Non sono interessato alle tue ciance inutili.,お前の無益な戯言なぞ興味は無い。,네 잡담 따위는 듣고 싶지 않아.,Ik ben niet geïnteresseerd in je nutteloze gewauwel.,,Não estou interessado em ouvir as suas bobagens inúteis.,,,Мне неинтересна твоя пустая болтовня., -If I had wanted to talk to you I would have told you so.,TXT_RANDOM_AGUARD_05,,,,"Kdybych s tebou chtěl mluvit, nařídil bych ti to.","Wenn ich mich mit dir unterhalten wollte, hätte ich dir das gesagt.",,,Si hubiera querido hablar contigo te lo habría dicho.,,,Si j'avais voulu te parler je te l'aurais dit.,"Ha beszélni akartam volna veled, azt mondtam volna.","Se avessi voluto parlarti, lo avrei fatto.",話があったらこちらからする。,대화하고 싶었으면 내가 먼저 말을 걸었겠지. 안 그래?,"Als ik met je had willen praten, had ik je dat gezegd.",,"Se eu quisesse falar com você, eu teria te dito.",,,"Если бы я хотел поговорить с тобой, то сказал бы об этом.", -Go and annoy someone else!,TXT_RANDOM_AGUARD_06,,,,Jdi otravovat někoho jiného!,Bitte nerve jemand anderen.,,,¡Ve a molestar a otro!,,,Va ennuyer quelqu'un d'autre!,Menj és idegesíts valaki mást!,Vattene a scocciare qualcun altro!,あまりイライラさせるな!,귀찮게 하지 말고 가서 딴 녀석이랑 놀아!,Ga iemand anders irriteren!,,Vá incomodar outra pessoa!,,,Иди и надоедай кому-нибудь другому!, -Keep moving!,TXT_RANDOM_AGUARD_07,,,,Nezastavuj se!,Beweg dich!,,,¡Sigue tu camino!,,,Bouge!,Mozgás!,Continua a muoverti!,立ち去れ!,여어 움직여라!,Blijf in beweging!,,Continue andando!,,,Иди куда шёл!, -"If the alarm goes off, just stay out of our way!",TXT_RANDOM_AGUARD_08,,,,"Jestli se vyhlásí poplach, jdi nám z cesty!","Wenn der Alarm losgeht, steh uns nicht im Weg!",,,"¡Si la alarma se activa, sólo quítate de nuestro camino!",,,"Si l'alarme s'enclenche, reste en dehors de notre chemin!","Ha beindul a riasztó, csak ne állj az utunkba.","Se scatta l'allarme, stattene fuori dai piedi!",警報を鳴らされたくないなら、邪魔をするな!,"만약 알람이 작동된다면, 기도하고 도망치기나 해!","Als het alarm afgaat, blijf dan gewoon uit de weg!",,"Se o alarme disparar, não fique no nosso caminho!",,,"Если поднимется тревога, не попадайся нам под ноги!", -The order will cleanse the world and usher it into the new era.,TXT_RANDOM_AGUARD_09,,,,Řád pročistí náš svět a navede ho do nového věku.,Der Orden wird die Welt läutern und in eine neue Ära führen.,,,La orden limpiará el mundo y marcará el inicio de la nueva era.,,,L'ordre nettoira le monde et le conduira dans une nouvelle ère.,"A Rend megtisztítja a világot, és egy új korszakba vezeti.",L'ordine ripulirà questo mondo e lo porterà verso una nuova era.,"オーダーは世界を浄化し、 -我々を新しい時代へ導いてくれる。",우리 오더는 언젠간 이 세상을 정화하고 새로운 시대를 만들 것이다.,De orde zal de wereld zuiveren en het nieuwe tijdperk inluiden.,,A Ordem purificará o mundo e o conduzirá para a nova era.,,,"Орден очистит этот мир и положит начало новой эре! -", -"Problem? No, I thought not.",TXT_RANDOM_AGUARD_10,,,,"Nějaký problém? Ne, není.","Hast du Probleme? Nein, ich glaube nicht.",,,"¿Algún problema? No, no lo creo.",,,Un problème? Je pense que non.,Baj van? Nem? Én is így gondoltam.,Un problema? Non ci ho pensato.,問題か? そうは思わないが。,문제가 있다고? 자. 이제 없지?,"Probleem? Nee, ik dacht van niet.",,Algum problema? Imaginei que não.,,,Что-то не так? Нет? Я так и думал., -Alms for the poor?,TXT_RANDOM_BEGGAR_01,,,,Almužnu pro chudáka?,Almosen für die Armen.,,,¿Limosnas para los pobres?,,,L'aumône pour les pauvres?,Alamizsna a szegényeknek?,Elemosina per i poveri?,貧民に何か恵んでくれるのか?,부디 빈민에게 구호를...,Aalmoezen voor de armen?,,Uma ajuda para os pobres?,,,У тебя не найдётся мелочи для бедняка?, -"What are you looking at, surfacer?",TXT_RANDOM_BEGGAR_02,,,,"Na co koukáš, nadzemníku?","Wonach suchst du, Oberflächler?",,,"¿Que estas mirando, prejuicioso?",,,"Tu regarde qui, habitant de la surface?","Mit nézel, felszínlakó?","Cosa stai guardando, essere di superficie?",何ジロジロ見てる、地上人。,"어딜 보고 있는 겁니까, 지상인씨?","Waar kijk je naar, oppervlaktebewoner? ",,"Tá olhando o quê, habitante da superfície?",,,"Что уставился, незнакомец?", -"You wouldn't have any extra food, would you?",TXT_RANDOM_BEGGAR_03,,,,Neměl bys náhodou něco navíc k snědku?,"Du hast nichts zu Essen übrig, oder?",,,"¿No tendría algo de comida, verdad?",,,Aurais-tu de la nourriture en trop sur toi?,"Nincs egy kis felesleges ételed, ugye?","Tu non avresti del cibo avanzato, giusto?",余ってる食べ物とかはないよな?,남은 식량 가지고 있습니까? 부디 있다고 말해주세요... 제발...,"Je zou toch geen extra eten hebben, of wel?",,"Por acaso você não tem comida sobrando, tem?",,,У тебя случайно не найдётся немного лишней еды?, -You surface people will never understand us.,TXT_RANDOM_BEGGAR_04,,,,Vy lidi z povrchu nás nikdy nepochopíte.,Ihr Oberflächenleute werdet uns nie verstehen.,,,Ustedes gente de la superficie nunca podrán entendernos.,,,"Vous, les gens de la surface, vous ne comprendrez jamais.",Ti felszíniek sosem fogtok megérteni minket.,Poi persone di superficie non ci comprenderete mai.,"お前みたいな地上の連中には俺らのことなんて -わかりゃしない。",당신 같은 지상인들은 우리를 아예 도와주지도 않죠. 그렇지 않나요?,Je zult mensen ons nooit begrijpen.,,Vocês da superfície nunca nos entenderão.,,,"Вы, люди с поверхности, никогда не поймёте нас.", -"Ha, the guards can't find us. Those idiots don't even know we exist.",TXT_RANDOM_BEGGAR_05,,,,"Ha, stráže nás nenajdou. Ti idioti ani neví, že existujeme.","Ha, die Wächter können uns nicht finden. Die Idioten ahnen nicht mal, dass wir existieren.",,,"Ja, los guardias no nos encontrarán. Esos idiotas ni siquiera saben que existimos.",,,"Ha, les gardes ne nous trouveront jamais, ces idiots ne savent même pas qu'on existe!","Ha! Az őrök az életben nem találnak meg minket. Azok a barmok azt sem tudják, hogy létezünk.","Ha, le guardie non ci trovano. Quegli idioti non sanno neppure della nostra esistenza.","衛兵共は俺らを見つけられない。 +奴等の基地に潜り込んで、倒すんだ。","감사드립니다! 블랙버드가 당신을 위해 계속 안내를 할 것입니다. 같이 행동한다면 오더의 흉측한 비밀들을 밝혀내고, 그들의 잔혹한 존재들을 응징할 수 있을 겁니다. 우리들의 이해심 밑에 공포를 인도하는 그들의 숨겨진 존재가 있죠. 그곳으로 들어가서, 물리치세요.",Goed. Blackbird zal je gids blijven. Ze heeft je een behoorlijke glans gegeven. Samen moeten jullie de geheimen van de Orde en hun onmenselijke dienaren ontrafelen. Er is een aanwezigheid die net buiten ons begrip schuilt en die hun angst leidt. Ga naar binnen en neem ze mee naar beneden.,Bra. Blackbird vil fortsette å være din guide. Hun har blitt ganske betatt av deg. Sammen må dere avsløre hemmelighetene til Ordenen og deres umenneskelige tjenere. Det er en tilstedeværelse som lurer like utenfor vår forståelse som styrer deres terror. Gå inn og ta dem.,"Dobrze. Blackbird nadal będzie twoim przewodnikiem. Polubiła cię. Razem musicie odkryć tajemnice Zakonu i ich nieludzkich sług. Istnieje obecność, która czai się poza naszym rozumieniem, która kieruje ich terrorem. Dostań się do środka i zdejmij ich.","Ótimo. Blackbird continuará sendo a sua guia. Ela parece que vai com a sua cara. Juntos, vocês desvendarão os segredos da Ordem e seus discípulos desumanos. Há uma presença que está além do nosso entendimento que guia todo esse terror. Vá infiltrar a Ordem e elimine-os.",,"Bun. Blackbird va continua să fie ghidul tău. A început să ia un interes asupra ta. Împreună, va trebui să aflați secretele Ordinului și servitorilor lor inumani. Există o prezență care se târăște la marginea capacității noastre de înțelegere care le ghidează teroarea. Infiltrează-te și pune-i la pământ.",Хорошо. «Чёрный дрозд» останется твоим проводником. Она тебе несколько симпатизирует. Вместе вы раскроете секреты Ордена и его бесчеловечных слуг. За этим ужасом стоит нечто лежащее далеко за пределами нашего понимания. Проникни на их территорию и ударь по ним как следует!,,Jag är med dig. Blackbird kommer att fortsätta att vara din guide. Hon har blivit ganska förtjust i dig. Tillsammans måste ni avslöja hemligheterna om Orden och deras omänskliga tjänare. Det finns en närvaro som lurar utanför vår förståelse och som styr deras terror. Ta dig in och ta ner dem.,Güzel. Karatavuk rehberin olmaya devam edecek. Senden oldukça hoşlandı. Birlikte Tarikat'ın ve insanlık dışı hizmetkârlarının sırlarını açığa çıkarmalısınız. Anlayışımızın hemen dışında gizlenen ve onların terörüne rehberlik eden bir varlık var. İçeri gir ve onları alaşağı et. +Let me at 'em!,TXT_RPLY0_SCRIPT34_D30320_LETME,〃,,,Pusť mě na ně!,Lad mig tage dem!,Lass mich das nur machen.,,Mi faros tion!,¡Voy a por ellos!,¡Voy por ellos!,Päästä minut heidän kimppuunsa!,Laissez moi m'en occuper!,Szétcincálom mind!,Lasciali a me!,任せろ!,저만 믿으세요!,Laat me naar ze toe!,La meg ta dem!,Pozwól mi na nich!,Pode deixar!,,Lasă-mă să pun mâna pe ei!,Я им покажу!,,Låt mig ta dem!,Bırakın ben halledeyim! +That's the spirit.,TXT_RYES0_SCRIPT34_D30320_THATS,〃,,,Tak se mi to líbí.,Sådan er ånden.,Das ist die richtige Einstellung.,,Tiu estas la spirito.,Ese es el espíritu.,,Niin sitä pitää.,J'aime entendre ça.,Ez a beszéd!,Questo è lo spirito giusto.,良い心掛けだ。,좋은 마음가짐입니다.,Dat is de geest.,Sånn skal det låte.,To jest duch.,Esse é o espírito.,,Ăsta e spiritul.,Правильный настрой.,,Så ska det låta.,İşte ruh bu. +Welcome friend!,TXT_DLG_SCRIPT34_D31836_WELCO,〃,,,"Vítej, příteli!","Velkommen, min ven!","Wilkommen, Freund.",,"Bonvenon, amiko!","¡Bienvenido, amigo!",,"Tervetuloa, ystävä!","Bievenue, notre ami!",Üdvözöllek barátom.,Benvenuto amico!,よく来た、同志!,"어서오세요, 친구여!",Welkom vriend!,"Velkommen, min venn!",Witaj przyjacielu!,"Seja bem-vindo, amigo!",,Bun-venit prietene!,"Добро пожаловать, друг!",,"Välkommen, min vän!",Hoş geldin dostum! +,,Random dialogue,,,,,,,,,,,,,,,,,,,,,,,,, +Please don't hurt me.,TXT_RANDOM_PEASANT_01,,,,"Neubližuj mi, prosím.",Du må ikke gøre mig noget.,Bitte tu mir nicht weh.,,Bonvolu ne vundi min.,"No me hagas nada, por favor.",,"Pyydän, älä vahingoita minua.","S'il vous plaît, laissez-moi tranquille.",Kérlek ne bánts!,"Ti prego, non farmi del male.",私を傷つけないでくれ。,목숨만은 살려줘.,Doe me alsjeblieft geen pijn.,"Vær så snill, ikke skad meg.","Proszę, nie rób mi krzywdy.","Por favor, não me machuque.",,Te rog nu mă răni.,"Пожалуйста, не трогай меня.",,"Snälla, gör mig inte illa.",Lütfen bana zarar verme. +"If you're looking to hurt me, I'm not really worth the effort.",TXT_RANDOM_PEASANT_02,,,,"Jestli mi chceš ublížit, fakt za to nestojím.","Hvis du er ude på at såre mig, er jeg ikke rigtig besværet værd.","Falls du mir was antun willst, ich bin den Aufwand nicht wert.",,"Se vi intencas vundi min, vi vere gajnos nenion.","Si estás tratando de hacerme algo, no valdrá la pena, la verdad.","Si estás tratando de hacerme algo, no va a valer la pena, la verdad.","Jos aikomuksenasi on vahingoittaa minua, en todellakaan ole sen vaivan väärti.","Si vous cherchez à me faire mal, Je n'en mérite pas l'effort.","Ha bántani akarsz, nem éri meg a fáradozást.","Se hai intenzione di farmi del male, ti assicuro che non ne valgo la pena.","もしお前が私に暴力を振るいたいなら間違いだ、 +私を殴る価値はないから。","날 괴롭히려고 여기까지 왔다면, 넌 헛수고를 한 거야.","Als je me pijn wilt doen, ben ik de moeite niet echt waard.","Hvis du er ute etter å skade meg, er jeg ikke verdt det.","Jeśli chcesz mnie skrzywdzić, nie jestem wart wysiłku.","Se pretende me machucar, te digo que não valerá a pena.",,"Dacă vrei să mă rănești, nu merit efortul.","Если ты хочешь ударить меня, то я не стою твоих усилий.",,Om du är ute efter att skada mig är jag inte värd besväret.,"Eğer beni incitmek istiyorsan, bu çabaya değmem." +I don't know anything.,TXT_RANDOM_PEASANT_03,,,,O ničem nevím.,Jeg ved ikke noget.,Ich weiß nichts.,,Mi scias nenion.,No sé nada.,,En tiedä mitään.,Je ne sais rien.,Én semmit sem tudok.,Non so niente.,私は何も知らないんだ。,난 정말 아무것도 몰라.,Ik weet niets.,Jeg vet ingenting.,Nic nie wiem.,Eu não sei de nada.,,Nu știu nimic.,Я ничего не знаю.,,Jag vet ingenting.,Ben bir şey bilmiyorum. +Go away or I'll call the guards!,TXT_RANDOM_PEASANT_04,,,,"Jdi pryč, nebo zavolám stráže!","Gå væk, eller jeg tilkalder vagterne!",Hau ab oder ich rufe die Wachen!,,Foriĝu aŭ mi vokos la gardistojn!,¡Vete o llamo a los guardias!,,"Mene pois, tai kutsun vartijat!",Allez vous en ou j'appelle les gardes!,"Tűnj innen, vagy hívom az őröket!",Vattene o chiamo le guardie!,離れろ、さもなくば衛兵を呼ぶぞ!,경비병 부르기 전에 얼른 사라져!,Ga weg of ik roep de bewakers!,"Gå vekk, ellers tilkaller jeg vaktene!",Odejdź albo zawołam strażników!,Vá embora antes que eu chame os guardas!,,Pleacă sau voi chema gardienii!,"Уходи, или я позову стражу!",,Gå härifrån eller så kallar jag på vakterna!,Git buradan yoksa muhafızları çağırırım! +I wish sometimes that all these rebels would just learn their place and stop this nonsense.,TXT_RANDOM_PEASANT_05,,,,"Občas si přeju, aby si ti rebelové uvědomili, kde jsou, a skončili s těmi svými nesmysly.","Nogle gange ville jeg ønske, at alle disse oprørere bare ville lære deres plads og stoppe dette nonsens.","Manchmal wünsche ich mir, dass diese Rebellen ihren Unsinn stoppen würden.",,"Mi iufoje deziras, ke ĉiu ribelanto simple lernu vivi kaj haltigu sian absurdon.",A veces deseo que todos los rebeldes simplemente aprendan a vivir y que paren con sus estupideces.,,Kunpa joskus kaikki nämä kapinalliset vain oppisivat paikkansa ja lopettaisivat tämän mielettömyyden.,"Je voudrais qu'a un moment, ces rebelles apprennent quelle est leur place et arrètent cette idiotie.","Néha azt kívánom, hogy ezek a lázadók bár megtanulnák, hol a helyük, és felhagynának ezzel az eszeveszett dologgal.",A volte vorrei solo che i ribelli imparassero a stare al loro posto e la smettessero con tutte queste follie.,"反乱軍がこんな出鱈目な状態をひっくり返すのを +切に願うよ。",저 저항군들이 가망이 없다는 걸 빨리 눈치챘으면 정말 좋겠군.,Ik wou soms dat al die rebellen gewoon hun plaats zouden leren kennen en deze onzin zouden stoppen.,Noen ganger skulle jeg ønske at alle disse opprørerne kunne lære seg sin plass og slutte med dette tullet.,"Chciałbym czasem, żeby ci wszyscy buntownicy nauczyli się, gdzie ich miejsce i skończyli z tymi bzdurami.",Às vezes eu queria que esses rebeldes cuidassem de suas próprias vidas e parassem com esse absurdo.,,Uneori îmi doresc ca rebelii ăștia să își vadă de treaba lor și să înceteze cu tâmpeniile.,"Иногда мне хочется, чтобы все эти повстанцы просто поняли своё место и прекратили эту пустую возню.",,Jag önskar ibland att alla dessa rebeller bara skulle lära sig sin plats och sluta med detta nonsens.,Bazen tüm bu isyancıların hadlerini bilmelerini ve bu saçmalığa bir son vermelerini diliyorum. +"Just leave me alone, OK?",TXT_RANDOM_PEASANT_06,,,,"Prostě mě nech být, jasný?","Bare lad mig være i fred, okay?","Lass mich bitte in Ruhe, ok?",,"Lasu min sola, ĉu?","Déjame en paz, ¿vale?","Déjame en paz, ¿sí?","Jätä minut vain rauhaan, onko selvä?","Laissez moi seul, OK?","Csak hagyj magamra, jó?","Lasciami in pace e basta, OK?",私に構わないでくれよ、頼むぞ?,그냥 날 내버려 둬. 부탁이야.,"Laat me gewoon met rust, oké?","Bare la meg være i fred, OK?","Zostaw mnie w spokoju, dobrze?","Apenas me deixe em paz, ok?",,"Doar lasă-mă în pace, OK?","Просто оставь меня в покое, хорошо?",,"Lämna mig bara ifred, okej?","Beni yalnız bırak, tamam mı?" +"I'm not sure, but sometimes I think that I know some of the acolytes.",TXT_RANDOM_PEASANT_07,,,,"Nejsem si jistý, ale občas se mi zdá, že znám některé z akolytů.","Jeg er ikke sikker, men nogle gange tror jeg, at jeg kender nogle af akolytterne.","Ich bin nicht ganz sicher, aber manchmal kommt es mir vor, als kenne ich diese Ministranten.",,"Mi ne estas certa, sed mi iufoje sentas, ke mi konas iujn el la akolitoj.","No estoy seguro, pero a veces siento que ya conozco a algunos de los acólitos.",,"En ole varma, mutta toisinaan jotkut akoluutit vaikuttavat tutuilta.","Je ne suis pas sûr, mais quelque fois je pense reconnaître certains des acolytes.","Nem vagyok benne bizonyos, de néha mintha ismerném némelyik ministránst.","Non ne sono sicuro, ma volte mi sembra di conoscere alcuni degli accoliti.","何か、アコライトの中で見覚えのある顔したのが +いたんだが。","자세히는 모르지만, 내가 본 아콜라이트들 중에 아는 사람이 있는 것 같아.","Ik weet het niet zeker, maar soms denk ik dat ik sommige van de acolieten ken.","Jeg er ikke sikker, men noen ganger tror jeg at jeg kjenner noen av akolyttene.","Nie jestem pewien, ale czasem wydaje mi się, że znam niektórych akolitów.","Eu não tenho bem certeza, mas acho que conheco alguns dos acólitos.",,"Nu sunt sigur, dar uneori am impresia că cunosc pe unii acoliți.","Я не уверен, но порой мне кажется, что я узнаю некоторых служителей.",,"Jag är inte säker, men ibland tror jag att jag känner några av akoliterna.",Emin değilim ama bazen bazı yardımcıları tanıdığımı düşünüyorum. +The Order's got everything around here pretty well locked up tight.,TXT_RANDOM_PEASANT_08,,,,Řád to tu má všechno pod hodně přísným dohledem.,Ordenen har alting her omkring temmelig godt låst godt inde.,Der Orden hat hier alles ziemlich gut unter Kontrolle.,,La Ordeno havas ĉion tie ĉi sufiĉe bone blokita.,La Orden tiene todo por aquí fuertemente bloqueado.,,Veljeskunnalla on täällä aika lailla kaikki tiukassa otteessaan.,L'ordre maintient la sûreté aux alentours.,A Rend mindent jól elzárt előlünk.,L'Ordine si è dato parecchio da fare per chiudere e sbarrare un po' tutto qui in giro.,オーダー達はここいらを厳しく取り締まってる。,오더가 치안유지도 그렇고 단속을 아주 실감 나게 잘하던데?,De Orde heeft alles hier in de buurt vrij goed afgesloten.,Ordenen har alt her ganske godt låst.,Zakon ma tu wszystko pod ścisłą kontrolą.,A Ordem mantém tudo trancado a sete chaves.,,Ordinul a încuiat cam tot ce se poate pe aici.,Орден держит тут всё под замком.,,Ordern har allting här omkring ganska väl låst in ordentligt.,Tarikat buradaki her şeyi oldukça iyi kilitlemiş. +There's no way that this is just a security force.,TXT_RANDOM_PEASANT_09,,,,"Není možné, aby tohle byly jen bezpečnostní složky.","Det er umuligt, at det bare er en sikkerhedsstyrke.",Das sind niemals nur Sicherheitskräfte.,,"Ne estas maniero, ke ĉi tio estas nur «sekureca forto».",No hay manera de que esto sea solo una fuerza de seguridad.,,Ei tämä mitenkään voi olla pelkkä turvallisuusjoukko.,Ca ne peut pas être juste une escouade de sécurité...,Na ez már tutira nem lehet csak a biztonsági szolgálat.,"E' impossibile che questa sia solo una ""forza di sicurezza"".",お前がただの警備兵なんてことはなさそうだな。,저 녀석들은 단순히 치안을 유지하기 위해 온 게 아니라고 생각해.,Er is geen sprake van dat dit gewoon een veiligheidsdienst is.,Det er ikke mulig at dette bare er en sikkerhetsstyrke.,"Nie ma mowy, żeby to była tylko ochrona.",Não tem como isso ser apenas um força de segurança.,,Sub nicio formă nu e asta doar o forță de securitate.,Без разрешения стражей порядка и шагу ступить нельзя.,,Det är inte möjligt att det här bara är en säkerhetsstyrka.,Bunun sadece bir güvenlik gücü olmasına imkan yok. +I've heard that the Order is really nervous about the Front's actions around here.,TXT_RANDOM_PEASANT_10,,,,"Slyšel jsem, že je Řád prý dost nervózní z toho, co tu Fronta dělá.","Jeg har hørt, at Ordenen er meget nervøs over Frontens handlinger her.","Ich habe gehört, dass der Orden sehr beunruhigt über die Aktionen der Front ist.",,"Mi aŭdis, ke La Ordeno estas tre nervoza pro la agoj de la ĉirkaŭa Fronto.",He oído que La Orden está realmente nerviosa por las acciones del Frente en los alrededores.,,Veljeskunta on kuulemma tosi huolissaan Rintaman toimista täällä.,J'ai entendu dire que l'ordre était sur les nerfs à cause des actions du front.,Úgy hírlik A Rend nagyon ideges a Front munkálkodásai miatt mostanság.,Ho sentito che l'Ordine è parecchio nervoso riguardo le azioni del Fronte nei dintorni.,"私はオーダーがこの辺での反乱軍の行動を +本当に厄介がってると聞いたぞ。",오더가 프론트 저항군의 공작에 정말 불안해하고 있더라고.,Ik heb gehoord dat de Orde echt nerveus is over de acties van het Front hier in de buurt.,Jeg har hørt at Ordenen er veldig nervøs for Frontens handlinger her.,"Słyszałem, że Zakon jest bardzo zdenerwowany działaniami Frontu w tym miejscu.",Ouvi falar que a Ordem anda bem nervosa por causa das ações da Frente por aqui.,,Am auzit că Ordinul e destul de stresat dorită acțiunilor Frontului pe-aici.,"Я слыхал, что Орден серьёзно обеспокоен действиями повстанцев в этом районе.",,Jag har hört att Orden är riktigt nervös över Fronts agerande här.,Tarikat'ın Cephe'nin buradaki eylemleri konusunda gerçekten gergin olduğunu duydum. +There's no way the Order will stand against us.,TXT_RANDOM_REBEL_01,,,,Řád se nám v žádném případě nemůže postavit.,Ordenen vil på ingen måde stå imod os.,Niemals wird sich der Orden gegen uns stellen!,,La Ordeno neniel povos rezisti al ni.,No hay forma de que La Orden aguante contra nosotros.,,Veljeskunta ei voi millään kestää meitä vastaan.,L'ordre n'a aucune chance contre nous.,A Rend labdába sem rúghat ellenünk!,Non è possibile che l'Ordine possa mettersi contro di noi.,オーダーが私達に立ち向かえるはずはない。,오더 녀석들이 우리를 이길 가능성은 전혀 없어.,De Orde zal op geen enkele manier tegen ons ingaan.,Det er ingen sjanse for at Ordenen vil gå imot oss.,"Nie ma mowy, by Zakon stanął przeciwko nam.",Nao ha como a Ordem ficar contra a gente.,,Nicio șansă ca Ordinul să ni se opună.,Ордену никак не устоять против нас.,,Det finns inte en chans att Orden kommer att stå emot oss.,Düzen'in bize karşı durmasına imkan yok. +We're almost ready to strike. Macil's plans are falling in place.,TXT_RANDOM_REBEL_02,,,,Jsme téměř připraveni zaútočit. Macilovy plány do sebe začínají zapadat.,Vi er næsten klar til at slå til. Macils planer er ved at falde på plads.,Wir sind zum großen Schlag bereit. Macils Plane werden bald umgesetzt.,,Ni estas preskaŭ pretaj ekataki. La planoj de Macil sukcesas perfekte.,Estamos casi listos para atacar. Los planes de Macil están saliendo a la perfección.,,Olemme melkein valmiit hyökkäämään. Macilin suunnitelmat loksahtavat paikalleen.,Nous sommes presque prêts à agir. Les plans de Macil se déroulent comme prévu.,"Már majdnem készen állunk, hogy lecsapjunk. Macil tervei kezdenek bejönni.",Siamo quasi pronti a colpire. I piani di Macil stanno andando lisci come l'olio.,"攻撃の準備は殆ど整った。 +マシルの計画は所定の位置に下す。",반격할 준비가 거의 다 돼가고 있어. 마실 사령관님의 계획이 잘 진행되고 있으니까.,We zijn bijna klaar om toe te slaan. Macil's plannen vallen op zijn plaats.,Vi er nesten klare til å slå til. Macils planer faller på plass.,Jesteśmy prawie gotowi do uderzenia. Plany Macila są coraz lepsze.,Estamos quase prontos para o ataque. Os planos de Macil estão fazendo efeito.,,Suntem aproape gata să dăm lovitura. Planurile lui Macil încep să se lege.,Мы почти готовы атаковать. Планы Мэйсила становятся ясны.,,Vi är nästan redo att slå till. Macils planer faller på plats.,Saldırmaya neredeyse hazırız. Macil'in planları yerine oturuyor. +"We're all behind you, don't worry.",TXT_RANDOM_REBEL_03,,,,"Všichni stojíme za tebou, neboj.","Vi står alle bag dig, bare rolig.","Wir stehen zu dir, keine Sorge.",,"Ni gardos vin dorse, vi do estu trankvila.","Nosotros te cubrimos la espalda, así que tranquilo.",,"Olemme kaikki tukenasi, älä huoli.","On couvre tes arrières, t'inquiète pas.","Mind itt vagyunk mögötted, ne aggódj!","Non preoccuparti, noi tutti ti copriamo le spalle.",後ろは見ているぞ、気にするな。,걱정 마. 무슨 일이 있어도 우리가 지켜줄게!,"We staan allemaal achter je, maak je geen zorgen.","Vi står bak deg, ikke vær redd.","Wszyscy jesteśmy za tobą, nie martw się.","Estamos todos te protegendo, não se preocupe.",,"Suntem toți în spatele tău, nu te teme.",Не беспокойся. Мы сразу за тобой.,,"Vi står alla bakom dig, oroa dig inte.","Hepimiz arkandayız, merak etme." +Don't get too close to any of those big robots. They'll melt you down for scrap!,TXT_RANDOM_REBEL_04,,,,Nepřibližuj se k těm velkým robotům. Usmaží tě na kaši!,Kom ikke for tæt på nogen af de store robotter. De vil smelte dig ned til skrot!,Komm diesen großen Robotern nicht zu nahe. Die schmelzen dich zu Schrott ein.,,Ne proksimiĝu tiel multe al tiuj robotegoj. Ili povus disigi vin je rubo!,No te acerques tanto a uno de esos robots grandes. ¡Podrían convertirte en chatarra!,,Älä mene liian lähelle mitään noista isoista roboteista. Ne sulattavat sinut kuonaksi.,Ne vous approchez pas trop des gros robots. Ils vous brûleront jusqu'à l'os!,Azokhoz a nagy robotokhoz ne nagyon menj közel. Felaprítanak tüzifának!,Non avvicinarti troppo a uno di quei grossi robot. Ti ridurrebbero in rottami!,"デカブツには近づくなよ。スクラップみたいに +踏みつぶされるぞ!",저 커다란 로봇들에게 다가갈 생각은 하지 마. 너를 완전 발끝까지 녹여버릴 거라고.,Kom niet te dicht bij een van die grote robots. Ze zullen je laten smelten voor de schroothoop!,Ikke kom for nær noen av de store robotene. De smelter deg om til skrap!,Nie zbliżaj się zbytnio do tych wielkich robotów. Przetopią cię na złom!,Nem pense em ficar perto daqueles robôs. Vão te transformar em ferro velho num instante!,,Nu te apropia de roboți. Te vor topii!,Держись подальше от этих больших роботов. Они и мокрого места от тебя не оставят!,,Kom inte för nära någon av de stora robotarna. De kommer att smälta ner dig till skrot!,O büyük robotlara fazla yaklaşma. Sizi hurda için eritirler! +"The day of our glory will soon come, and those who oppose us will be crushed!",TXT_RANDOM_REBEL_05,,,,"Naše dny slávy brzy nadejdou a ti, kdo se nám postaví, budou rozdrceni!","Vores storhedsdag vil snart komme, og de, der modsætter sig os, vil blive knust!","Der Tag des Triumphes ist nahe, und die, die gegen uns sind, werden vernichtet.",,Nia glora tago baldaŭ alvenos kaj niaj kontraŭstarantoj estos detruitaj!,¡El día de nuestra gloria llegará pronto y aquellos que se opusieron a nosotros serán destruidos!,¡El día de nuestra gloria va a llegar pronto y aquellos que se opusieron a nosotros van a ser destruidos!,"Kunnian päivämme häämöttää, ja kaikki meitä vastustavat vihittäkööt tuhon omiksi!","Le jour de gloire arrivera bientôt, et ceux qui s'opposeront a nous seront écrasés!","Dicsőségünk napja hamarosan eljön, és akik ellenünk szegülnek, elkárhoznak.","Il giorno della nostra gloria verrà presto, e quelli che si oppongono a noi verranno schiacciati!","栄光の日は我々に訪れる、 +そして反逆する者達は潰す!",영광스러운 새벽이 오고있어. 우리를 탄압한 녀석들에게 징벌을 내릴 새벽이!,"De dag van onze glorie zal snel komen, en degenen die zich tegen ons verzetten zullen worden verpletterd!","Dagen for vår herlighet vil snart komme, og de som motsetter seg oss vil bli knust!","Dzień naszej chwały wkrótce nadejdzie, a ci, którzy się nam sprzeciwią, zostaną zmiażdżeni!","O dia de nossa glória chegará, e aqueles que se opuserem contra nós serão destruídos!",,Ziua în care noi vom avea gloria va veni curând și toti vor fi striviți.,Близок день нашего триумфа. Скоро наши враги будут уничтожены!,,"Vår härlighets dag kommer snart, och de som motsätter sig oss kommer att krossas!",Zafer günümüz yakında gelecek ve bize karşı çıkanlar ezilecek! +Don't get too comfortable. We've still got our work cut out for us.,TXT_RANDOM_REBEL_06,,,,"Neusínej na vavřínech, stále máme před sebou hodně práce.",Lad være med at sætte dig for godt til rette. Vi har stadig vores arbejde foran os.,"Werd nicht leichtsinnig, es gibt noch eine Menge zu tun.",,"Ne agu tre pigre, ni ankoraŭ havas multe da laboro.","No te pongas muy cómodo, que aún queda un montón por hacer.",,Ei parane levätä laakereillaan; meillä on vielä paljon työsarkaa edessämme.,Ne vous reposez pas sur vos lauriers. Du travail nous attend encore.,Annyira azért ne érezd otthon magad. Nekünk még van némi munka kiosztva idelenn.,Non prendertela troppo comoda. Abbiamo ancora un sacco di lavoro da fare.,"あまり気楽でいるな。 +我々にはまだやるべき事があるんだ。",게으름 피울 생각하지는 마. 아직 일이 잘 안 풀렸으니까.,Maak het je niet al te comfortabel. We hebben nog steeds werk voor de boeg.,Ikke bli for komfortabel. Vi har fortsatt en jobb å gjøre.,Nie czuj się zbyt komfortowo. Wciąż mamy przed sobą zadanie do wykonania.,Não fique muito confortável. Ainda temos trabalho a fazer.,,Nu te fă prea comfortabil. Încă mai avem treabă de făcut.,Не расслабляйся. У нас по-прежнему хватает дел.,,Gör det inte för bekvämt. Vi har fortfarande vårt arbete framför oss.,Fazla rahatlamayın. İşimiz hala bizim için biçilmiş kaftan. +Macil says that you're the new hope. Bear that in mind.,TXT_RANDOM_REBEL_07,,,,"Macil říká, že jsi naše nová naděje. Pamatuj na to.","Macil siger, at du er det nye håb. Husk det.",Macil nennt dich unsere neue Hoffnung. Vergiss das nicht.,,"Macil diras, ke vi estas la nova espero. Memoru tion.",Macil dice que eres la nueva esperanza. Ten eso en mente.,,Macil sanoo sinun olevan uusi toivomme. Pidä se mielessäsi.,Macil nous dit que tu es notre nouvel espoir. Garde ça à l'esprit.,Macil szerint te vagy az új reményünk. Ezt sose feledd!,Macil dice che tu sei la nuova speranza. Tienilo a mente.,"マシルは貴方が新しい希望だと言っている。 +心に留めておいてくれ。",마실 사령관님이 말하기를 네가 우리들의 유일한 희망이래. 명심해 둬.,Macil zegt dat jij de nieuwe hoop bent. Houd dat in gedachten.,Macil sier at du er det nye håpet. Husk det.,"Macil mówi, że jesteś nową nadzieją. Pamiętajcie o tym.",Macil disse que você é a nova esperança. Lembre-se disso.,,Macil spune că tu ești speranța. Ține minte asta.,"Мэйсил говорит, что на тебя сейчас вся надежда. Имей это в виду.",,Macil säger att du är det nya hoppet. Tänk på det.,Macil senin yeni umut olduğunu söylüyor. Bunu aklınızdan çıkarmayın. +"Once we've taken these charlatans down, we'll be able to rebuild this world as it should be.",TXT_RANDOM_REBEL_08,,,,"Jakmile sesadíme ty šarlatány, budeme moci znovu vybudovat svět tak, jaký by měl být.","Når vi først har nedlagt disse charlataner, vil vi kunne genopbygge denne verden, som den skal være.","Wenn wir diese Scharlatane entmachtet haben, können wir unsere Welt endlich neu aufbauen.",,"Foriginte tiujn ridindulojn, ni povos ĝuste rekonstrui ĉi tiun mondon.","Una vez eliminados esos charlatanes, podremos reconstruir este mundo como debe ser.","Una vez eliminados esos charlatanes, vamos a poder reconstruir este mundo como debe ser.","Sen jälkeen, kun olemme nujertaneet nämä puoskarit, voimme jälleenrakentaa tämän maailman sellaiseksi kuin pitääkin.","Une fois que nous nous serons débarassés de ces charlatans, nous serons capable de rebâtir le monde tel qu'il devrait être.","Amint lenyomtuk ezeket a sarlatánokat, végre újjáépíthetjük ezt a világot olyanra, amilyennek lennie kéne.","Una volta eliminati questi ciarlatani, potremo ricostruire questo mondo per come dovrebbe essere.","我々が一度こんな酷いハッタリを負かせば、 +世界を本来の状態に建て直せるだろう。","저 허풍쟁이들을 다 물리칠 수만 있다면, 우리가 바랬던 평화로운 세상을 재건할 수 있을 거야.","Als we deze charlatans eenmaal hebben verwijderd, kunnen we deze wereld weer opbouwen zoals het hoort.","Når vi har tatt disse sjarlatanene, kan vi gjenoppbygge verden slik den burde være.","Kiedy obalimy tych szarlatanów, będziemy mogli odbudować ten świat tak, jak powinien być.","Assim que derrubarmos esses charlatões, poderemos reconstruir o mundo do jeito certo.",,"Dupa ce îi vom răpune pe șarlatanii ăștia, vom putea reconstrui lumea în ceea ce trebuie să fie.","Когда мы свергнем этих шарлатанов, то сможем воссоздать этот мир таким, каким он должен быть.",,När vi väl har slagit ner dessa charlataner kommer vi att kunna återuppbygga den här världen som den borde vara.,"Bu şarlatanları alaşağı ettikten sonra, bu dünyayı olması gerektiği gibi yeniden inşa edebileceğiz." +"Remember that you aren't fighting just for yourself, but for everyone here and outside.",TXT_RANDOM_REBEL_09,,,,"Nezapomeň, že nebojuješ jen kvůli sobě, ale kvůli všem tady a tam venku.","Husk, at du ikke kun kæmper for dig selv, men for alle her og udenfor.","Vergiß nicht, dass du nicht nur für dich selbst kämpfst, sondern für alle von uns da draußen.",,"Memoru, ke vi ne batalas nur por vi, sed por ĉiuj ĉi-ene kaj ele.","Recuerda que no estás peleando solo por ti, sino por todos aquí y fuera.","Recuerda que no estás peleando solo por ti, sino por todos aquí y afuera.","Muista, ettet taistele vain itsesi, vaan kaikkien täällä olevien sekä ulkopuolisten puolesta.","Souviens-toi, tu ne te bats pas seulement pour toi, mais pour tous le monde ici et ailleurs.","Ne feledd, nem csak magadért harcolsz, hanem mindnyájunkért idebent, és odakint.","Ricordati che non stai combattendo solo per te stesso, ma per tutti quelli che sono qui e fuori.","貴方は自分自身だけでなく、 +国中の人の為に戦っている事を忘れないでくれよ。",너 혼자 위해서 싸우는 게 아니라 인류를 위해서 싸우고 있다는 걸 잊지 마.,"Onthoud dat je niet alleen voor jezelf vecht, maar voor iedereen hier en daarbuiten.","Husk at du ikke bare kjemper for deg selv, men for alle her og utenfor.","Pamiętaj, że nie walczysz tylko dla siebie, ale dla wszystkich tu i na zewnątrz.","Lembre-se que você não está lutando só por si mesmo, mas por todos nós.",,"Ține minte că nu lupți doar pentru tine, ci pentru toți de aici și de afară.","Помни, ты сражаешься не только за себя, но и за каждого здесь и снаружи.",,"Kom ihåg att du inte bara kämpar för dig själv, utan för alla här och utanför.","Sadece kendiniz için değil, buradaki ve dışarıdaki herkes için savaştığınızı unutmayın." +"As long as one of us still stands, we will win.",TXT_RANDOM_REBEL_10,,,,"Dokud je alespoň jeden z nás na nohou, vyhrajeme!","Så længe en af os stadig står tilbage, vil vi vinde.","Solange nur einer von uns steht, werden wir gewinnen.",,"Dum iu ajn el ni ankoraŭ povos stari, ni venkos.","Mientras uno de nosotros siga en pie, ganaremos.","Mientras uno de nosotros siga en pie, vamos a ganar.","Niin kauan kuin yksikin meistä vielä seisoo, voitto on meidän.","Aussi longtemps qu'un de nous est vivant, nous vaincrons.","Ha csak egy is marad meg közülünk, nyerni fogunk.","Finché uno di noi rimarrà in piedi, vinceremo.",我々が一人でも立っていれば、それが勝利。,"우리 중 한 명이 남아있는 한, 이길 수 있어.","Zolang één van ons nog staat, zullen we winnen.","Så lenge en av oss fortsatt står, vil vi vinne.","Tak długo jak jeden z nas nadal będzie stał, tak długo będziemy wygrywać.","Enquanto um de nós ainda estiver de pé, teremos chance de vencer.",,"Atâta timp cât unul din noi trăiește, vom triumfa.","Пока хотя бы один из нас ещё дышит, мы непобедимы.",,Så länge en av oss fortfarande står kvar kommer vi att vinna.,İçimizden biri ayakta kaldığı sürece kazanacağız. +"Move along, peasant.",TXT_RANDOM_AGUARD_01,,,,"Jdi dál, poddaný.","Gå videre, bonde.","Beweg dich, Bauer!",,"Ne haltu, kampulo.","No te detengas, campesino.",,"Jatka matkaa, maallikko.","Barre-toi, paysan!","Mozgás, paraszt. Egy kettő.","Muoviti, cittadino.",立ち去れ、百姓。,"어서 움직여, 이 자식아.","Ga verder, boer.","Gå videre, bonde.","Ruszaj w drogę, chłopie.","Continue andando, plebeu.",,"Mișcă, sărmanule.","Проходи, рабочий.",,"Gå vidare, bonde.",İlerle köylü. +"Follow the true faith, only then will you begin to understand.",TXT_RANDOM_AGUARD_02,,,,"Následuj pravou víru, jen tak začneš chápat.","Følg den sande tro, først da vil du begynde at forstå.",Folge dem wahren Glauben und du wirst verstehen.,,"Sekvu la veran kredon, nur tiel vi ekkomprenos.","Sigue la fe verdadera, solo entonces empezarás a entender.","Sigue la fe verdadera, solo así vas a entender.",Seuraa totista uskoa; vasta silloin alat käsittää.,"Suis la vraie foi, tu commençeras a comprendre.","Csak ha az igaz hitet követed, csakis akkor kezded majd megérteni.","Segui la vera fede, solo allora comincerai a capire.",真の信仰を求めよ、それしか理解に至る道はない。,참된 신앙이야말로 자기 자신을 깨우칠 수 있지.,"Volg het ware geloof, pas dan zul je het begrijpen.","Følg den sanne troen, først da vil du begynne å forstå.","Podążaj za prawdziwą wiarą, tylko wtedy zaczniesz rozumieć.",Siga a verdadeira fé. Só então você começará a entender.,,"Urmează crezul adevărat, doar atunci vei începe să înțelegi.",Следуй истинной вере. Только тогда ты начнёшь понимать.,,"Följ den sanna tron, först då kommer du att börja förstå.","Gerçek inancı takip et, ancak o zaman anlamaya başlarsın." +Only through death can one be truly reborn.,TXT_RANDOM_AGUARD_03,,,,Pouze skrz smrt lze dosáhnout znovuzrození.,Kun gennem døden kan man virkelig blive genfødt.,Nur durch den Tod kann man wirklich wiedergeboren werden.,,Nur per morto oni povas vere renaskiĝi.,Solo a través de la muerte uno puede realmente renacer.,,Vain kuoleman kautta voi totisesti uudestisyntyä.,C'est seulement a travers la mort que quelqu'un peut renaître.,Csak a halál útján lehet igazán újjászületni.,Solo attraverso la morte uno può rinascere per davvero.,人が真の意味で生まれ変われる方法は、死のみだ,죽음을 통해서만이 진정하게 환생할 수 있는 거다.,Alleen door de dood kan men echt herboren worden.,Bare gjennom døden kan man virkelig bli gjenfødt.,Tylko przez śmierć można się naprawdę odrodzić.,Somente através da morte que alguem poderá renascer de verdade.,,Doar prin moarte poate cineva să fie renăscut cu adevărat.,Истинное перерождение возможно только через смерть.,,Endast genom döden kan man verkligen återfödas.,İnsan ancak ölümle gerçekten yeniden doğabilir. +I'm not interested in your useless drivel.,TXT_RANDOM_AGUARD_04,,,,Nezajímají mě tvoje žvásty.,Jeg er ikke interesseret i dit ubrugelige sludder.,Dein nutzloses Geschwafel interessiert mich nicht.,,Ne interesas min aŭdi viajn sensencaĵojn.,No me interesa tu charlatanería.,No me interesa oír tus estupideces.,Joutava hölynpölysi ei minua kiinnosta.,Je ne suis pas intéressé par tes idioties inutiles.,Nem érdekel az értelmetlen hablatyolásod.,Non sono interessato alle tue ciance inutili.,お前の無益な戯言なぞ興味は無い。,네 잡담 따위는 듣고 싶지 않아.,Ik ben niet geïnteresseerd in je nutteloze gewauwel.,Jeg er ikke interessert i det unyttige vrøvlet ditt.,Nie interesują mnie twoje bezużyteczne brednie.,Não estou interessado em ouvir as suas bobagens inúteis.,,Nu sunt interesat de lipsa ta de sens.,Мне неинтересна твоя пустая болтовня.,,Jag är inte intresserad av ditt värdelösa dravel.,İşe yaramaz saçmalıklarınla ilgilenmiyorum. +If I had wanted to talk to you I would have told you so.,TXT_RANDOM_AGUARD_05,,,,"Kdybych s tebou chtěl mluvit, nařídil bych ti to.","Hvis jeg havde ønsket at tale med dig, ville jeg have sagt det til dig.","Wenn ich mich mit dir unterhalten wollte, hätte ich dir das gesagt.",,"Se mi volus paroli kun vi, mi unue dirus tion al vi.",Si quisiera hablar contigo te lo hubiera dicho.,,"Jos olisin halunnut puhua kanssasi, olisin sen sinulle ilmaissut.",Si j'avais voulu te parler je te l'aurais dit.,"Ha beszélni akartam volna veled, azt mondtam volna.","Se avessi voluto parlarti, te lo avrei detto.",話があったらこちらからする。,대화하고 싶었으면 내가 먼저 말을 걸었겠지. 안 그래?,"Als ik met je had willen praten, had ik je dat gezegd.","Hadde jeg villet snakke med deg, hadde jeg sagt det.","Gdybym chciał z tobą rozmawiać, powiedziałbym ci to.","Se eu quisesse falar com você, eu teria te dito.",,Dacă voiam să vorbim ți-aș fi spus.,"Если бы я хотел поговорить с тобой, то сказал бы об этом.",,Om jag hade velat prata med dig hade jag sagt det till dig.,"Seninle konuşmak isteseydim, bunu sana söylerdim." +Go and annoy someone else!,TXT_RANDOM_AGUARD_06,,,,Jdi otravovat někoho jiného!,Gå ud og irriter en anden!,Bitte nerve jemand anderen.,,Ĝenu aliulon!,¡Ve a molestar a otro!,,Mene ärsyttämään jotakuta toista!,Va ennuyer quelqu'un d'autre!,Menj és idegesíts valaki mást!,Vai a scocciare qualcun altro!,あまりイライラさせるな!,귀찮게 하지 말고 가서 딴 녀석이랑 놀아!,Ga iemand anders irriteren!,Gå og plag noen andre!,Idź i denerwuj kogoś innego!,Vá incomodar outra pessoa!,,Du-te și enervează pe altul.,Иди и надоедай кому-нибудь другому!,,Gå och irriter någon annan!,Git ve başkasını rahatsız et! +Keep moving!,TXT_RANDOM_AGUARD_07,,,,Nezastavuj se!,Fortsæt med at bevæge dig!,Beweg dich!,,Plue piediru!,¡Sigue caminando!,,Ala laputtaa!,Bouge!,Mozgás!,Continua a muoverti!,立ち去れ!,여어 움직여라!,Blijf in beweging!,Gå videre!,Ruszaj się!,Continue andando!,,Continuă să mergi!,Иди куда шёл!,,Fortsätt att röra på dig!,Yürümeye devam et! +"If the alarm goes off, just stay out of our way!",TXT_RANDOM_AGUARD_08,,,,"Jestli je vyhlášen poplach, jdi nám z cesty!","Hvis alarmen går i gang, så hold dig bare væk fra os!","Wenn der Alarm losgeht, steh uns nicht im Weg!",,"Se la alarmo eksonas, vi nur foriĝu de antaŭ ni!","¡Si la alarma se activa, solo quítate de nuestra vista!",,"Jos hälytys laukeaa, pysy vain pois meidät tieltämme!","Si l'alarme s'enclenche, reste en dehors de notre chemin!","Ha beindul a riasztó, csak ne állj az utunkba.","Se scatta l'allarme, stattene fuori dai piedi!",警報を鳴らされたくないなら、邪魔をするな!,"만약 알람이 작동된다면, 기도하고 도망치기나 해!","Als het alarm afgaat, blijf dan gewoon uit de weg!","Hvis alarmen går, bare hold deg unna oss!","Jeśli włączy się alarm, po prostu zejdź nam z drogi!","Se o alarme disparar, não fique no nosso caminho!",,"Dacă alarma e declanșată, pur și simplu nu ne sta în cale.","Если поднимется тревога, не попадайся нам под ноги!",,"Om larmet går, håll dig bara ur vägen!","Alarm çalarsa, yolumuzdan çekilin!" +The Order will cleanse the world and usher it into the new era.,TXT_RANDOM_AGUARD_09,,,,Řád pročistí náš svět a navede ho do nového věku.,Ordenen vil rense verden og føre den ind i den nye æra.,Der Orden wird die Welt läutern und in eine neue Ära führen.,,La Ordeno elpurigos la mondon kaj gvidos ĝin al la nova epoko.,La Orden limpiará el mundo y marcará el inicio de la nueva era.,La Orden va a limpiar el mundo y marcar el inicio de la nueva era.,Veljeskunta puhdistaa tämän maailman ja johdattaa sen uudelle aikakaudelle.,L'ordre nettoira le monde et le conduira dans une nouvelle ère.,"A Rend megtisztítja a világot, és egy új korszakba vezeti.",L'ordine ripulirà questo mondo e lo porterà verso una nuova era.,"オーダーは世界を浄化し、 +我々を新しい時代へ導いてくれる。",우리 오더는 언젠간 이 세상을 정화하고 새로운 시대를 만들 것이다.,De orde zal de wereld zuiveren en het nieuwe tijdperk inluiden.,Ordenen vil rense verden og føre den inn i en ny æra.,Zakon oczyści świat i wprowadzi go w nową erę.,A Ordem purificará o mundo e o conduzirá para a nova era.,,Ordinul va curăța lumea și ne va propulsa într-o nouă eră.,"Орден очистит этот мир и положит начало новой эре! +",,Orden kommer att rena världen och föra in den i den nya eran.,Tarikat dünyayı temizleyecek ve yeni bir çağ başlatacak. +"Problem? No, I thought not.",TXT_RANDOM_AGUARD_10,,,,"Nějaký problém? Ne, není.","Problemer? Nej, det troede jeg ikke.","Hast du Probleme? Nein, ich glaube nicht.",,"Ĉu ia problemo? Ne, tiel, kiel mi jam pensis.","¿Algún problema? No, como ya me imaginaba.",,"Jokin ongelma? Ei, niin arvelinkin.",Un problème? Je pense que non.,Baj van? Nem? Én is így gondoltam.,"Qualche problema? No, come pensavo.",問題か? そうは思わないが。,문제가 있다고? 자. 이제 없지?,"Probleem? Nee, ik dacht van niet.","Problemer? Nei, jeg trodde ikke det.","Problem? Nie, nie sądziłem.",Algum problema? Imaginei que não.,,"Probleme? Nu, așa credeam și eu.",Что-то не так? Нет? Я так и думал.,,"Problem? Nej, det trodde jag inte.","Sorun mu var? Hayır, ben de öyle düşünmüştüm." +Alms for the poor?,TXT_RANDOM_BEGGAR_01,,,,Almužnu pro chudáka?,Almisser til de fattige?,Almosen für die Armen.,,Ĉu vi havas almozon por malriĉuloj?,¿Limosna para los pobres?,,Almuja köyhälle?,L'aumône pour les pauvres?,Alamizsna a szegényeknek?,Elemosina per i poveri?,貧民に何か恵んでくれるのか?,부디 빈민에게 구호를...,Aalmoezen voor de armen?,Almisser til de fattige?,Jałmużna dla biednych?,Uma ajuda para os pobres?,,Ceva pentru ce-i sărmani?,У тебя не найдётся мелочи для бедняка?,,Almosor till de fattiga?,Fakirler için sadaka mı? +"What are you looking at, surfacer?",TXT_RANDOM_BEGGAR_02,,,,"Na co koukáš, nadzemníku?","Hvad kigger du på, overfladeklipper?","Wonach suchst du, Oberflächler?",,"Kion vi rigardas, surfaco-loĝanto?","¿Que estás mirando, habitante de la superficie?",,"Mitä tuijotat, maanpintalainen?","Tu regarde qui, habitant de la surface?","Mit nézel, felszínlakó?","Cosa stai guardando, abitante della superficie?",何ジロジロ見てる、地上人。,"어딜 보고 있는 겁니까, 지상인씨?","Waar kijk je naar, oppervlaktebewoner? ","Hva glor du på, overflatebehandler?","Na co się patrzysz, surferze?","Tá olhando o quê, habitante da superfície?",,La ce te uiți?,"Что уставился, незнакомец?",,"Vad tittar du på, ytmänniska?","Neye bakıyorsun, sörfçü?" +"You wouldn't have any extra food, would you?",TXT_RANDOM_BEGGAR_03,,,,Neměl bys náhodou něco navíc k snědku?,"Du har vel ikke noget ekstra mad, vel?","Du hast nichts zu Essen übrig, oder?",,"Vi ne havas iom da restaj manĝaĵoj, ĉu?","No tendrás algo de comida que te sobre, ¿no?",,Ei sinulla sattuisi olemaan ylimääräistä ruokaa?,Aurais-tu de la nourriture en trop sur toi?,"Nincs egy kis felesleges ételed, ugye?",Tu non avresti del cibo avanzato da darci?,余ってる食べ物とかはないよな?,남은 식량 가지고 있습니까? 부디 있다고 말해주세요... 제발...,"Je zou toch geen extra eten hebben, of wel?",Du har vel ikke noe ekstra mat?,"Nie mielibyście żadnego dodatkowego jedzenia, prawda?","Por acaso você não tem comida sobrando, tem?",,"Nu ai mâncare în plus, nu-i așa?",У тебя случайно не найдётся немного лишней еды?,,"Du skulle inte ha någon extra mat, eller hur?","Fazladan yiyeceğin olmazdı, değil mi?" +You surface people will never understand us.,TXT_RANDOM_BEGGAR_04,,,,Vy lidi z povrchu nás nikdy nepochopíte.,I overflademennesker vil aldrig forstå os.,Ihr Oberflächenleute werdet uns nie verstehen.,,"Vi, surfaco-loĝantoj, neniam komprenos nin.","Vosotros, gente de la superficie, jamás nos entenderéis.","Ustedes, gente de la superficie, jamás nos van a entender.",Te maanpinnan asukit ette meitä koskaan tule ymmärtämään.,"Vous, les gens de la surface, vous ne comprendrez jamais.",Ti felszíniek sosem fogtok megérteni minket.,Voi abitanti della superficie non ci comprenderete mai.,"お前みたいな地上の連中には俺らのことなんて +わかりゃしない。",당신 같은 지상인들은 우리를 아예 도와주지도 않죠. 그렇지 않나요?,Je zult mensen ons nooit begrijpen.,Dere overflatefolk vil aldri forstå oss.,"Wy, ludzie powierzchni, nigdy nas nie zrozumiecie.",Vocês da superfície nunca nos entenderão.,,Voi oamenii de la suprafață nu veți înțelege niciodată.,"Вы, люди с поверхности, никогда не поймёте нас.",,Ni ytliga människor kommer aldrig att förstå oss.,Siz yüzey insanları bizi asla anlamayacaksınız. +"Ha, the guards can't find us. Those idiots don't even know we exist.",TXT_RANDOM_BEGGAR_05,,,,"Ha, stráže nás nenajdou. Ti idioti ani neví, že existujeme.","Ha, vagterne kan ikke finde os. De idioter ved ikke engang, at vi eksisterer.","Ha, die Wächter können uns nicht finden. Die Idioten ahnen nicht mal, dass wir existieren.",,"Ha, gardistoj ne trovas nin. Tiuj stultuloj eĉ ne scias, ke ni ekzistas.","Ja, los guardias no nos encuentran. Esos idiotas ni siquiera saben que existimos.",,"Hah, vartijat eivät pysty löytämään meitä. Ne idiootit eivät edes tiedä olemassaolostamme.","Ha, les gardes ne nous trouveront jamais, ces idiots ne savent même pas qu'on existe!","Ha! Az őrök az életben nem találnak meg minket. Azok a barmok azt sem tudják, hogy létezünk.","Ha, le guardie non ci trovano. Quegli idioti non sanno neppure della nostra esistenza.","衛兵共は俺らを見つけられない。 あのバカどもは俺らがここに居ることすら -知らないんだぞ。","하, 저 멍청한 경비들은 우리가 이 밑에 숨어있다는 걸 모르죠!","Ha, de bewakers kunnen ons niet vinden. Die idioten weten niet eens dat we bestaan.",,"Hah, os guardas não conseguem nos achar. Esses idiotas nem sabem que a gente existe.",,,"Ха! Эта глупая стража никогда не найдёт нас. Они даже не знают, что мы существуем.", -One day everyone but those who serve the Order will be forced to join us.,TXT_RANDOM_BEGGAR_06,,,,"Jednoho dne se všichni, kdo neslouží Řádu, budou muset přidat k nám.","Eines Tages werden alle, die nicht dem Orden dienen, sich uns anschließen.",,,"Un día, todos excepto aquellos que sirvan a la Orden serán forzados a unirse a nosotros.",,,"Un jour, tous sauf les membres de l'ordre seront forcés de nous rejoindre.","Egy nap mindenki, kivéve a Rend szolgálói arra kényszerülnek majd, hogy hozzánk tartozzanak.","Un giorno tutti, salvo chi serve l'Ordine, sarà costretto a partecipare.","そのうち、オーダーに仕える者を除いて +知らないんだぞ。","하, 저 멍청한 경비들은 우리가 이 밑에 숨어있다는 걸 모르죠!","Ha, de bewakers kunnen ons niet vinden. Die idioten weten niet eens dat we bestaan.",Vaktene kan ikke finne oss. De idiotene vet ikke engang at vi eksisterer.,"Strażnicy nie mogą nas znaleźć. Ci idioci nawet nie wiedzą, że istniejemy.","Hah, os guardas não conseguem nos achar. Esses idiotas nem sabem que a gente existe.",,"Ha, gardienii nu ne pot găsi. Idioții ăștia nici măcar nu știu de existența noastră.","Ха! Эта глупая стража никогда не найдёт нас. Они даже не знают, что мы существуем.",,"Ha, vakterna kan inte hitta oss. De idioterna vet inte ens att vi finns.","Ha, muhafızlar bizi bulamaz. O aptallar varlığımızdan bile haberdar değiller." +One day everyone but those who serve the Order will be forced to join us.,TXT_RANDOM_BEGGAR_06,,,,"Jednoho dne se všichni, kdo neslouží Řádu, budou muset přidat k nám.","En dag vil alle undtagen dem, der tjener ordenen, blive tvunget til at slutte sig til os.","Eines Tages werden alle, die nicht dem Orden dienen, sich uns anschließen.",,"Ian tagon ĉiuj, krom la servantoj de La Ordeno, estos devigataj aliĝi al ni.","Algún día todos, excepto aquellos que sirven a La Orden, se verán forzados a unirse a nosotros.","Algún día todos, menos aquellos que le sirven a La Orden, se van a ver obligados a unirse a nosotros.",Jonain päivänä kaikkien paitsi Veljeskuntaa palvelevien on liityttävä meihin.,"Un jour, tous sauf les membres de l'ordre seront forcés de nous rejoindre.","Egy nap mindenki, kivéve a Rend szolgálói arra kényszerülnek majd, hogy hozzánk tartozzanak.","Un giorno tutti, salvo chi serve l'Ordine, sarà costretto ad unirsi a noi.","そのうち、オーダーに仕える者を除いて 全ての人間が私達のようになることを -強いられるだろう。",언젠가는 순종하는 사람들을 제외하고는 모두가 오더에 강제병합될지도 몰라요...,"Op een dag zal iedereen, behalve degenen die de Orde dienen, gedwongen worden om zich bij ons aan te sluiten.",,Um dia todos exceto aqueles que servem à Ordem serão forçados a se juntarem a nós.,,,"Однажды всем, кто не служит Ордену, придётся присоединиться к нам.", -"Stare now, but you know that this will be your own face one day.",TXT_RANDOM_BEGGAR_07,,,,"Teď zíráš, ale věz, že tohle bude jednou tvá tvář.","Glotz nur, aber irgendwann wirst du auch so aussehen.",,,"Observe ahora, pero esté seguro que esta podría ser su propia cara algún día.",,,"Moque nous si tu veux, mais tu sais que ceci sera aussi ton sort un jour.","Bámulj csak, de tudd, hogy egy nap ez az arc a sajátod lesz.","Guardaci pure, ma lo sai che un giorno questa sarà la tua faccia.","今ジロジロ見てたみたいだが、 -お前もいつかこんな顔になるだろうな。",배꼽 잡고 웃으시구려. 결국엔 당신도 이 모양 이 꼴이 될 테니까.,"Staar nu, maar je weet dat dit op een dag je eigen gezicht zal zijn.",,"Pode ficar olhando, mas você sabe que este será o seu próprio rosto um dia.",,,"Смотри сколько влезет, но знай, что когда-нибудь так будет выглядеть и твоё лицо.", -There's nothing more annoying than a surfacer with an attitude!,TXT_RANDOM_BEGGAR_08,,,,Není nic otravnějšího než nadzemník s dobrou náladou!,Es gibt nichts nervigeres als einen Oberflächler mit Gesinnung.,,,¡No hay nada más irritante que una persona de la superficie con mala actitud!,,,Il n'y rien de plus barbant qu'un type de la surface et son orgeuil!,Nincs bosszantóbb egy felszíninél ilyen hozzáállással.,Non c'è nulla di più scocciante di un essere di superficie con un attitudine!,腹立たしい地上人の態度は悩みの種だ!,버릇없는 지상인 보다 더 짜증 나는 건 없을 거예요!,Er is niets vervelender dan een verharder met een houding!,,Não há nada mais irritante do que alguém da superfície cheio de si!,,,"Ничто так не выводит из себя, как болтун с поверхности!", -The Order will make short work of your pathetic Front.,TXT_RANDOM_BEGGAR_09,,,,Řád s tou vaší patetickou Frontou udělá krátký proces.,Der Orden wird eure armselige Front auseinandernehmen.,,,La Orden acabará fácilmente con su patético Frente.,,,L'ordre se débarrassera de vos soldats pathétiques.,A Rendnek gyerekjáték lesz a szánalmas kis Frontotok.,L'Ordine farà facilmente fuori il vostro patetico Fronte.,"オーダーはアンタの哀れなフロントに近付いてる -ってさ。",오더가 당신을 비롯한 한심한 프론트 저항군을 싹슬이할 겁니다.,De Orde zal kort werk maken van je zielige Front.,,A Ordem vai dar um jeito em vocês da Frente.,,,Орден быстро расправится с твоим бессильным сопротивлением., -"Watch yourself, surfacer. We know our enemies!",TXT_RANDOM_BEGGAR_10,,,,"Dávej si pozor, nadzemníku. Známe své nepřátele!","Pass nur auf, Oberflächler. Wir kennen unsere Feinde.",,,"Mírese a si mismo, superficial. ¡Conocemos a nuestros enemigos!",,,"Prend guarde a toi, habitant de la surface. Nous connaîssons nos ennemis!","Óvakodj, felszíni! Ismerjük az ellenségeinket!","Stai attento, essere di superficie. Conosciamo i nostri nemici!",気を付けろ、地上人。敵はアンタを知ってるぞ。,"조심하시오, 지상인. 우리는 적이 누군지 알고 있으니!","Let op jezelf, surfacer. Wij kennen onze vijanden!",,"Cuidado, ô da superficie. Nós sabemos quem são os nossos inimigos!",,,"Поосторожнее, человек с поверхности. Мы знаем, кто наш враг!", -We are the hands of fate. To earn our wrath is to find oblivion!,TXT_RANDOM_PGUARD_01,,,,Jsme rukami osudu. Získat si náš hněv je jako upadnout v zapomnění!,Wir sind die Hände des Schicksals. Wer sich unseren Zorn verdient wird vernichtet!,,,Somos las manos del destino. ¡Encontrar nuestra ira es encontrar el olvido!,,,Nous sommes les mains du destin. Apprendre notre colère est l'égal de trouver l'oubli!,"Mi vagyunk a sors keze. Kárhozatra ítéltetett, ki haragunkat elnyeri.",Siamo le mani del destino. Farci infuriare significa trovare l'oblio!,"運命は我々の手の中だ。 -あまり歯向かわない方がいいぞ。","우리는 긍휼의 손길이며, 불신자들을 심판하는 검일지니!",Wij zijn de handen van het lot. Om onze toorn te verdienen is het vinden van de vergetelheid!,,Somos as mãos do destino. Quem despertar a nossa ira será destruído!,,,Мы длани судьбы. Прогневить нас означает встретить забвение!, -The Order will cleanse the world of the weak and corrupt!,TXT_RANDOM_PGUARD_02,,,,Řád vyčistí svět od slabých a zkažených!,Der Orden wird die Welt von allem Schwachen und Korrupten säubern.,,,¡La orden limpiará el mundo de los débiles y los corruptos!,,,L'ordre nettoira le monde des faibles et corrompus!,A Rend megtisztítja a világot a gyengéktől és a korruptaktól!,"L'Ordine ripulirà il mondo dai deboli e corrotti! +強いられるだろう。",언젠가는 순종하는 사람들을 제외하고는 모두가 오더에 강제병합될지도 몰라요...,"Op een dag zal iedereen, behalve degenen die de Orde dienen, gedwongen worden om zich bij ons aan te sluiten.",En dag vil alle unntatt de som tjener Ordenen bli tvunget til å slutte seg til oss.,"Pewnego dnia wszyscy poza tymi, którzy służą Zakonowi, będą zmuszeni do przyłączenia się do nas.",Um dia todos exceto aqueles que servem à Ordem serão forçados a se juntarem a nós.,,Într-o bună zi toți în afară de cei care slujesc Ordinul vor fi nevoiți să ni se alăture.,"Однажды всем, кто не служит Ордену, придётся присоединиться к нам.",,En dag kommer alla utom de som tjänar Orden att tvingas ansluta sig till oss.,Bir gün Tarikat'a hizmet edenler dışında herkes bize katılmak zorunda kalacak. +"Stare now, but you know that this will be your own face one day.",TXT_RANDOM_BEGGAR_07,,,,"Teď zíráš, ale věz, že tohle bude jednou tvá tvář.","Stir nu, men du ved, at dette vil være dit eget ansigt en dag.","Glotz nur, aber irgendwann wirst du auch so aussehen.",,"Rigardu nun, sed vi scias, ke iam ĉi tiu estos via propra vizaĝo.","Observa ahora, pero ya sabes que esta será tu propia cara algún día.","Observa ahora, pero ya sabes que esta va a ser tu propia cara algún día.","Tuijotat nyt, mutta tiedä, että jonain päivänä nämä ovat sinun kasvosi.","Moque nous si tu veux, mais tu sais que ceci sera aussi ton sort un jour.","Bámulj csak, de tudd, hogy egy nap ez az arc a sajátod lesz.","Osservaci pure, ma tu sai bene che un giorno questa sarà la tua faccia.","今ジロジロ見てたみたいだが、 +お前もいつかこんな顔になるだろうな。",배꼽 잡고 웃으시구려. 결국엔 당신도 이 모양 이 꼴이 될 테니까.,"Staar nu, maar je weet dat dit op een dag je eigen gezicht zal zijn.","Stirr nå, men du vet at dette vil bli ditt eget ansikt en dag.","Gap się teraz, ale wiesz, że to będzie kiedyś twoja własna twarz.","Pode ficar olhando, mas você sabe que este será o seu próprio rosto um dia.",,"Te holbezi acum, dar asta va fi soarta ta într-o zi.","Смотри сколько влезет, но знай, что когда-нибудь так будет выглядеть и твоё лицо.",,"Stirra nu, men du vet att detta kommer att vara ditt eget ansikte en dag.","Şimdi bak, ama biliyorsun ki bu bir gün senin de yüzün olacak." +There's nothing more annoying than a surfacer with an attitude!,TXT_RANDOM_BEGGAR_08,,,,Není nic otravnějšího než nadzemník s dobrou náladou!,Der er ikke noget mere irriterende end en overfladebeboer med en attitude!,Es gibt nichts nervigeres als einen Oberflächler mit Gesinnung.,,Estas nenio pli malagrabla ol surfaco-loĝanto kun tia sintenado!,¡No hay nada más irritante que una persona de la superficie con mala actitud!,,Ei ole mitään ärsyttävämpää kuin töykeä maanpintalainen!,Il n'y rien de plus barbant qu'un type de la surface et son orgeuil!,Nincs bosszantóbb egy felszíninél ilyen hozzáállással.,Non c'è nulla di più seccante di un abitante della superficie saccente!,腹立たしい地上人の態度は悩みの種だ!,버릇없는 지상인 보다 더 짜증 나는 건 없을 거예요!,Er is niets vervelender dan een verharder met een houding!,Det er ikke noe mer irriterende enn en overflatebehandler med en holdning!,Nie ma nic bardziej irytującego niż surfer z nastawieniem!,Não há nada mais irritante do que alguém da superfície cheio de si!,,Nu e nimic mai enervant decât o persoană de la suprafață cu fițe!,"Ничто так не выводит из себя, как болтун с поверхности!",,Det finns inget mer irriterande än en ytmänniska med attityd!,Tavırlı bir sörfçüden daha sinir bozucu bir şey yoktur! +The Order will make short work of your pathetic Front.,TXT_RANDOM_BEGGAR_09,,,,Řád s tou vaší patetickou Frontou udělá krátký proces.,Ordenen vil gøre kort proces med din patetiske front.,Der Orden wird eure armselige Front auseinandernehmen.,,La Ordeno detruos senprobleme vian ridindan Fronton.,La Orden acabará fácilmente con vuestro patético Frente.,La Orden va a destruir como si nada su patético Frente.,Veljeskunta tekee nopeasti selvän säälittävästä Rintamastanne.,L'ordre se débarrassera de vos soldats pathétiques.,A Rendnek gyerekjáték lesz a szánalmas kis Frontotok.,L'Ordine farà facilmente fuori il vostro patetico Fronte.,"オーダーはアンタの哀れなフロントに近付いてる +ってさ。",오더가 당신을 비롯한 한심한 프론트 저항군을 싹슬이할 겁니다.,De Orde zal kort werk maken van je zielige Front.,Ordenen vil gjøre kort prosess med din patetiske Front.,Zakon szybko rozprawi się z twoim żałosnym frontem.,A Ordem vai dar um jeito em vocês da Frente.,,Ordinul va face preș din Frontul tău.,Орден быстро расправится с твоим бессильным сопротивлением.,,Orden kommer att göra processen kort med din patetiska front.,Tarikat senin acınası cepheni kısa sürede halledecektir. +"Watch yourself, surfacer. We know our enemies!",TXT_RANDOM_BEGGAR_10,,,,"Dávej si pozor, nadzemníku. Známe své nepřátele!","Pas på dig selv, overfladebeboer. Vi kender vores fjender!","Pass nur auf, Oberflächler. Wir kennen unsere Feinde.",,"Atentu, surfaco-loĝanto. Ni konas niajn malamikojn!","Cuidado, habitante de la superficie. ¡Nosotros conocemos a nuestros enemigos!",,"Pidä varasi, maanpintalainen. Tunnemme vihollisemme!","Prend guarde a toi, habitant de la surface. Nous connaîssons nos ennemis!","Óvakodj, felszíni! Ismerjük az ellenségeinket!","Stai attento, abitante della superficie. Conosciamo i nostri nemici!",気を付けろ、地上人。敵はアンタを知ってるぞ。,"조심하시오, 지상인. 우리는 적이 누군지 알고 있으니!","Pas op, oppervlaktebewoner. We kennen onze vijanden!","Pass deg, overflatebehandler. Vi kjenner våre fiender!","Uważaj na siebie, surferze. Znamy naszych wrogów!","Cuidado, ô da superficie. Nós sabemos quem são os nossos inimigos!",,"Ai grijă, omule de la suprafață! Ne cunoaștem inamicii.","Поосторожнее, человек с поверхности. Мы знаем, кто наш враг!",,"Se upp, ytmänniska. Vi känner våra fiender!","Kendine dikkat et, sörfçü. Düşmanlarımızı tanıyoruz!" +We are the hands of fate. To earn our wrath is to find oblivion!,TXT_RANDOM_PGUARD_01,,,,Jsme rukama osudu. Získat si náš hněv je jako upadnout v zapomnění!,Vi er skæbnens hænder. At gøre sig fortjent til vores vrede er at finde glemsel!,Wir sind die Hände des Schicksals. Wer sich unseren Zorn verdient wird vernichtet!,,Ni estas la manoj de la destino. Furiozigi nin estas trovi forgeson!,Somos las manos del destino. ¡Despertar nuestra ira es encontrar el olvido!,,"Olemme kohtalon käsi. Joka yllyttää meidät vihaan, etsii turmiotaan.",Nous sommes les mains du destin. Apprendre notre colère est l'égal de trouver l'oubli!,"Mi vagyunk a sors keze. Kárhozatra ítéltetett, ki haragunkat elnyeri.",Siamo le mani del destino. Farci infuriare significa trovare l'oblio!,"運命は我々の手の中だ。 +あまり歯向かわない方がいいぞ。","우리는 긍휼의 손길이며, 불신자들을 심판하는 검일지니!",Wij zijn de handen van het lot. Om onze toorn te verdienen is het vinden van de vergetelheid!,Vi er i skjebnens hender. Å fortjene vår vrede er å finne glemsel!,Jesteśmy rękami losu. Zasłużyć na nasz gniew to znaleźć zapomnienie!,Somos as mãos do destino. Quem despertar a nossa ira será destruído!,,Suntem mâinile destinului. Să ne câștigi furia e să găsești vidul!,Мы длани судьбы. Прогневить нас означает встретить забвение!,,Vi är ödets händer. Att förtjäna vår vrede är att finna glömska!,"Bizler kaderin elleriyiz. Gazabımızı kazanmak, unutulmayı bulmaktır!" +The Order will cleanse the world of the weak and corrupt!,TXT_RANDOM_PGUARD_02,,,,Řád vyčistí svět od slabých a zkažených!,Ordenen vil rense verden for de svage og korrupte!,Der Orden wird die Welt von allem Schwachen und Korrupten säubern.,,La Ordeno elpurigos la mondon je malfortuloj kaj koruptitoj!,¡La Orden limpiará el mundo de los débiles y los corruptos!,,Veljeskunta puhdistaa tämän maailman sen heikoista ja turmeltuneista!,L'ordre nettoira le monde des faibles et corrompus!,A Rend megtisztítja a világot a gyengéktől és a korruptaktól!,"L'Ordine ripulirà il mondo dai deboli e corrotti! ","オーダーは浅ましく腐敗した世界を -浄化するだろう!",유일신님은 반드시 이 나약하고 부패한 세상을 정화할 것이니라!,De Orde zal de wereld zuiveren van de zwakken en corrupten!,,A Ordem purificará o mundo dos fracos e corruptos!,,,Орден очистит мир от слабых и порочных!, -Obey the will of the masters!,TXT_RANDOM_PGUARD_03,,,,Podrob se vůli svých pánů!,Gehorche dem Willen der Meister.,,,¡Obedece la voluntad de los maestros!,,,Obéissez à la volonté de vos maîtres!,Engedelmeskedj mestereink akaratának!,Obbedisci al volere dei maestri!,主の意志に従うのだ。,스승님들께서 너희에게 명령하신 도를 행하라!,Gehoorzaam de wil van de meesters!,,Obedeça a lei dos mestres!,,,Подчинись воле хозяев!, -Long life to the brothers of the Order!,TXT_RANDOM_PGUARD_04,,,,Nechť žijí naši bratři Řádu!,Lang lebe die Brüder des Ordens.,,,¡Larga vida a los hermanos de la Orden!,,,Longue vie aux membres de l'Ordre!,Éljenek sokáig a Rend testvérei!,Lunga vita ai fratelli dell'Ordine.,オーダーの友に永久の命を!,"오더와 그의 동포들을 따르라, 그럼 영생을 얻을 지니!",Een lang leven voor de broeders van de Orde!,,Vida longa aos irmãos da Ordem!,,,Да здравствуют братья Ордена!, -Free will is an illusion that binds the weak minded.,TXT_RANDOM_PGUARD_05,,,,"Svobodná vůle je jen iluze, která váže ruce slabomyslným.",Freier Wille ist eine Illusion die die Schwachen fesselt.,,,El libre albedrio es una ilusión que une a los débiles de mente.,,,La liberté de penser est l'illusion qui aveugle les faibles d'esprit.,"A Szabad akarat egy illúzió, ami csupán a gyengéknek mentsvára.",Il libero arbitrio è un'illusione che tiene legati i deboli di mente.,自由意志など、弱者を縛る幻想に過ぎぬ。,"자유의지는 나약함의 상징이요, 필멸의 꾐이라.",De vrije wil is een illusie die de zwakkeren bindt.,,Livre arbítrio é uma ilusão para os fracos.,,,"Свободная воля — лишь иллюзия, созданная для управления слабыми духом.", -Power is the path to glory. To follow the Order is to walk that path!,TXT_RANDOM_PGUARD_06,,,,Moc je cesta ke slávě. Následovat Řád je chodit po té cestě!,"Macht ist der Weg zum Ruhm. Dem Orden zu folgen bedeutet, diesen Weg zu gehen.",,,El poder es el camino a la gloria. ¡Seguir a la Orden es alcanzar ese camino!,,,le pouvoir est le chemin de la gloire. Suivre l'ordre c'est suivre ce chemin!,"A dicsőéghez vezető út az erő. Aki A Rendet követi, ezt az utat járja.",Il potere è il percorso verso la gloria. Seguire l'Ordine è come camminare quel percorso!,"力は栄光への道だ。 -オーダーに従えばその道を歩めるだろう。","힘은 영광이자 희망이며, 이를 간구함으로써 축복받을지어다!",Macht is de weg naar glorie. De Orde volgen is dat pad bewandelen!,,O poder é o caminho para a glória. Siga a Ordem e andará por esse caminho!,,,Сила — путь к величию. Вступить в ряды Ордена означает пойти этим путём!, -"Take your place among the righteous, join us!",TXT_RANDOM_PGUARD_07,,,,"Najdi své místo mezi spravedlivými, přidej se k nám!",Nimm deinen Platz unter den Gerechten ein. ,,,"Tome su lugar entre los justos, ¡Únase a nosotros!",,,"Prend ta place parmi les justes, rejoins nous!","Foglalj helyet az igazak között, csatlakozz hozzánk!","Prendi il tuo posto tra i giusti, entra con noi!",正義は我等と共に在る、参加せよ!,"우리는 참됐으며 구원을 받았느니라, 함께 기도하면 두려울 것이 없을지니!","Neem je plaats in tussen de rechtvaardigen, sluit je aan bij ons!",,Tenha o seu lugar entre os justos. Junte-se a nós!,,,Займи своё место среди праведных. Присоединись к нам!, -The Order protects its own.,TXT_RANDOM_PGUARD_08,,,,Řád si své lidi chrání.,Der Orden beschützt seine Jünger.,,,La Orden protege a los suyos.,La Orden se protege a los suyos.,,L'ordre protège les siens.,A Rend a magáét védi.,L'ordine protegge se stesso.,オーダーは我々を守護している。,오더는 신들을 향한 기도로 거룩하여짐이니라.,De Orde beschermt zijn discipelen. ,,A Ordem protege os seus discípulos.,,,Орден защищает своих., -Acolytes? They have yet to see the full glory of the Order.,TXT_RANDOM_PGUARD_09,,,,Akolyté? Ti ještě neviděli Řád v celé své kráse.,Ministranten? Die müssen erst noch die volle Macht des Ordens erfahren.,,,¿Acólitos? Ellos aún no han visto la gloria de nuestra Orden.,,,Les Acolytes? Ils n'ont pas encore été témoins de la vraie gloire de l'ordre.,Ministránsok? Még nem látták A Rend igazi dicsőségét.,Gli accoliti? Devono ancora vedere la gloria piena dell'Ordine.,"アコライト? -奴等はオーダーの爛漫なる未来を見ていない。",아콜라이트들이라... 애석하게도 이 들은 믿음이 아직 부족하다고 생각함이라.,Acolieten? Zij moeten de volle glorie van de Orde nog zien.,,Acólitos? Eles ainda não viram toda a glória da Ordem.,,,Служители? Им ещё только предстоит узреть подлинное величие Ордена., -"If there is any honor inside that pathetic shell of a body, you'll enter into the arms of the Order.",TXT_RANDOM_PGUARD_10,,,"If there is any honour inside that pathetic shell of a body, you'll enter into the arms of the Order.","Jestli ta tvoje žalostná tělesná schránka má v sobě kousek cti, dáš se do rukou Řádu.","Wenn du noch einen Hauch von Ehre hast, wirst du dem Orden beitreten.",,,"Si hay algo de honor dentro de esa patética cáscara de cuerpo, podrás entrar a los brazos de la Orden.",,,"Si il y a une once de gloire dans ce corps pathétique, ceux de l'ordre te prendront parmi les leurs.","Ha csak egy csipetnyi becsület is van testednek szánalmas páncéljában, A Rend katonáinak sorába fogsz beállni.","Se c'è ancora un onore dentro quel guscio patetico di corpo, entrerai nelle braccia dell'Ordine.","その哀れな肉体の殻でも名誉の為ならば、 -オーダーの兵器を携える事が出来るだろう。",육체라는 나약한 껍질에 갇힌 운명을 참회하는 자들이야말로 오더와 함께할 수 있을지어다. ,"Als er enige eer in dat zielige omhulsel van een lichaam zit, zul je in de armen van de Orde binnengaan.",,"Se ainda existe honra dentro da sua carne patética, você entrará para os braços da Ordem.",,,"Если внутри этой бренной телесной оболочки есть хоть капля чести, ты присоединишься к Ордену.", -Bye!,TXT_RANDOMGOODBYE_1,,,,Tak ahoj!,Tschüss!,,,¡Adiós!,,,Au revoir!,Szervusz!,Ciao!,じゃあな!,안녕!,Dag!,,Tchau!,,,Пока!,Довиђења! -"Thanks, bye!",TXT_RANDOMGOODBYE_2,,,,"Díky, ahoj!","Danke, tschüss!",,,"Gracias, ¡Adiós!",,,"Merci, au revoir!","Köszi, szia!","Grazie, ciao!",どうも、じゃあ!,그렇군요. 그럼 안녕히!,"Bedankt, tot ziens!",,Obrigado. Até mais!,,,"Спасибо, пока!","Хвала, довиђења!" -See you later!,TXT_RANDOMGOODBYE_3,,,,Uvidíme se později!,Bis später!,,,¡Nos vemos!,,,A plus tard!,Később találkozunk!,Ci vediamo dopo!,また今度!,다음에 봐요!,Tot ziens!,,Até logo!,,,До встречи!,Видимо се! -,,Strife logs,,,,,,,,,,,,,,,,,,,,, -"Hello? Command, a com unit has just been activated... Am receiving visuals and sound from... somebody... Hey you, get out of there now... and drop the chalice!",TXT_ILOG1,,,,"Haló? Velení, právě byl aktivován komunikátor... příjimám obraz a zvuk od... někoho... Hej, ty, dostaň se odtaď... a zahoď ten kalich!","Hallo, Kommandozentrale, eine Kommunikationseinheit wurde gerade aktiviert.... Ich empfange Bilder und Ton von... irgend jemandem... Hey, du, verschwinde da sofort... Und schmeiß den Kelch weg!",,,"¿Hola? Comando, una unidad de comunicación acaba de ser activada... Recibo visuales y sonido de... Alguien... Eh tú, sal de ahí ahora mismo... ¡Y tira el cáliz!",,,"Allô? Central, un communicateur à été activé.. Je recois visuel et son de.. quelqu'un.. Hé, vous, sortez de là! Et lâchez le calice!",,,"もしもし? 司令部、comユニットが起動されました。 -…からビジュアルとサウンドを受け取っています -…誰かが…ちょっと、今そこから出て行ってください -…そして聖杯を捨ててください!","여보세요? 본부, 통신기가 막 작동되기 시작했다... 지금 어떤... 사람의 모습이 보이는데... 이봐, 거기서 당장 나와... 그리고 성배를 버려!","Hallo? Commando, een com-unit is zojuist geactiveerd.... Ontvang ik beelden en geluid van.... iemand... Hé jij, ga daar nu weg.... en laat de kelk vallen!",,"Alô? Comando, um comunicador acabou de ser ativado... Estou recebendo imagens e som de... alguém... Ei você, saia daí agora... e solte o cálice!",,,"Алло? Штаб, передатчик только что включился... Я принимаю звук и картинку от... кого-то... Эй, ты, беги оттуда, сейчас же... и брось чашу!", -"Listen, this com unit tells me that you're 100% human. I've been ordered to bring you in, we're talking trust here. Betray me and pay. Oh, and by the way, you can call me Blackbird.",TXT_ILOG2,,,,"Poslyš, tento komunikátor mi říká, že jsi na sto procent člověkem. Dostala jsem rozkaz tě přivést te k nám, jde o důvěryhodnou záležitost. Zraď mě a zaplatíš. Jo, a mimochodem, můžeš mi říkat Straka.","Hör zu, dieser Kommunikator sagt mit, dass du noch 100% menschlich bist. Mir wurde aufgetragen, dich zu unserer Zentrale zu führen. Wir reden über Vertrauen, wenn du mich verrätst, wirst du bezahlen. Übrigens, du kannst mich Blackbird nennen.",,,"Escucha, esta unidad de comunicación me dice que eres 100% humano. Se me ha ordenado hacerte entrar, hablamos en confianza. Traicióname y paga. Oh, por cierto, puedes llamarme Blackbird.",,,"Ecoute, ce communicateur me dit que tu est 100% humain. On m'a ordonnée de te ramener, c'est une question de confiance. Trahis-moi et tu paieras. Oh, et tu peux m'appeler Blackbird.",,,"聞こえるか、この無線機がアナタは100%人間だと判断した。 +浄化するだろう!",유일신님은 반드시 이 나약하고 부패한 세상을 정화할 것이니라!,De Orde zal de wereld zuiveren van de zwakken en corrupten!,Ordenen vil rense verden for de svake og korrupte!,Zakon oczyści świat ze słabych i skorumpowanych!,A Ordem purificará o mundo dos fracos e corruptos!,,Ordinul va curăța lumea de slabi și corupți!,Орден очистит мир от слабых и порочных!,,Orden kommer att rensa världen från de svaga och korrupta!,"Düzen, dünyayı zayıf ve yozlaşmış olanlardan temizleyecek!" +Obey the will of the masters!,TXT_RANDOM_PGUARD_03,,,,Podrob se vůli svých pánů!,Adlyd mændenes vilje!,Gehorche dem Willen der Meister.,,Obeu la volon de la mastroj!,¡Obedece la voluntad de los maestros!,,Tottele mestareiden tahtoa!,Obéissez à la volonté de vos maîtres!,Engedelmeskedj mestereink akaratának!,Obbedisci al volere dei maestri!,主の意志に従うのだ。,스승님들께서 너희에게 명령하신 도를 행하라!,Gehoorzaam de wil van de meesters!,Adlyd mesternes vilje!,Bądźcie posłuszni woli mistrzów!,Obedeça a lei dos mestres!,,Supune-te voinței stăpânilor!,Подчинись воле хозяев!,,Lyd mästarnas vilja!,Efendilerin iradesine itaat edin! +Long life to the brothers of the Order!,TXT_RANDOM_PGUARD_04,,,,Nechť žijí naši bratři Řádu!,Langt liv til ordenens brødre!,Lang lebe die Brüder des Ordens.,,Vivu la fratoj de La Ordeno!,¡Vivan los hermanos de La Orden!,,Pitkä ikä Veljeskunnan veljille!,Longue vie aux membres de l'Ordre!,Éljenek sokáig a Rend testvérei!,Lunga vita ai fratelli dell'Ordine.,オーダーの友に永久の命を!,"오더와 그의 동포들을 따르라, 그럼 영생을 얻을 지니!",Een lang leven voor de broeders van de Orde!,Lenge leve ordenens brødre!,Niech żyją bracia Zakonu!,Vida longa aos irmãos da Ordem!,,Viață lungă fraților Ordinului!,Да здравствуют братья Ордена!,,Länge liv till ordensbröderna!,Tarikat'ın kardeşlerine uzun ömürler! +Free will is an illusion that binds the weak minded.,TXT_RANDOM_PGUARD_05,,,,"Svobodná vůle je jen iluze, která váže ruce slabomyslným.","Den frie vilje er en illusion, der binder de svage sind.",Freier Wille ist eine Illusion die die Schwachen fesselt.,,"Libera volo estas iluzio, kiu ligas debiluloj.",El libre albedrío es una ilusión que une a los débiles de mente.,,"Vapaa tahto on harha, joka sitoo heikkomieliset.",La liberté de penser est l'illusion qui aveugle les faibles d'esprit.,"A Szabad akarat egy illúzió, ami csupán a gyengéknek mentsvára.",Il libero arbitrio è un'illusione che tiene legati i deboli di mente.,自由意志など、弱者を縛る幻想に過ぎぬ。,"자유의지는 나약함의 상징이요, 필멸의 꾐이라.",De vrije wil is een illusie die de zwakkeren bindt.,Fri vilje er en illusjon som binder de svake.,"Wolna wola to iluzja, która wiąże słabe umysły.",Livre arbítrio é uma ilusão para os fracos.,,Voința liberă e o iluzie care leagă mințile slabe.,"Свободная воля — лишь иллюзия, созданная для управления слабыми духом.",,Fri vilja är en illusion som binder de svaga sinnena.,"Özgür irade, zayıf zihinleri bağlayan bir yanılsamadır." +Power is the path to glory. To follow the Order is to walk that path!,TXT_RANDOM_PGUARD_06,,,,Moc je cesta ke slávě. Následovat Řád je chodit po té cestě!,Magt er vejen til ære. At følge Ordenen er at gå denne vej!,"Macht ist der Weg zum Ruhm. Dem Orden zu folgen bedeutet, diesen Weg zu gehen.",,Povo estas la vojo al gloro. Sekvi La Ordenon estas iri laŭ tiu vojo!,El poder es el camino a la gloria. ¡Seguir a La Orden es alcanzar ese camino!,,Valta on tie kunniaan. Veljeskunnan seuraaminen on vaeltaa sitä tietä!,le pouvoir est le chemin de la gloire. Suivre l'ordre c'est suivre ce chemin!,"A dicsőéghez vezető út az erő. Aki A Rendet követi, ezt az utat járja.",Il potere è il percorso verso la gloria. Seguire l'Ordine è come attraversare quel percorso!,"力は栄光への道だ。 +オーダーに従えばその道を歩めるだろう。","힘은 영광이자 희망이며, 이를 간구함으로써 축복받을지어다!",Macht is de weg naar glorie. De Orde volgen is dat pad bewandelen!,Makt er veien til ære. Å følge Ordenen er å gå den veien!,Władza jest drogą do chwały. Podążanie za Zakonem to podążanie tą ścieżką!,O poder é o caminho para a glória. Siga a Ordem e andará por esse caminho!,,Puterea e calea spre glorie. Să urmezi Ordinul e să urmezi acea cale!,Сила — путь к величию. Вступить в ряды Ордена означает пойти этим путём!,,Makt är vägen till ära. Att följa Orden är att gå den vägen!,"Güç, zafere giden yoldur. Tarikat'ı takip etmek o yolda yürümektir!" +"Take your place among the righteous, join us!",TXT_RANDOM_PGUARD_07,,,,"Najdi své místo mezi spravedlivými, přidej se k nám!","Tag din plads blandt de retfærdige, slut dig til os!",Nimm deinen Platz unter den Gerechten ein. ,,Havu vian postenon inter ĝustuloj. Aliĝu al ni!,Toma tu lugar entre los justos. ¡Únete a nosotros!,,Ota paikkasi hurskaitten joukossa; liity meihin!,"Prend ta place parmi les justes, rejoins nous!","Foglalj helyet az igazak között, csatlakozz hozzánk!","Prendi il tuo posto tra i giusti, unisciti a noi!",正義は我等と共に在る、参加せよ!,"우리는 참됐으며 구원을 받았느니라, 함께 기도하면 두려울 것이 없을지니!","Neem je plaats in tussen de rechtvaardigen, sluit je aan bij ons!","Ta din plass blant de rettferdige, bli med oss!","Zajmij swoje miejsce wśród sprawiedliwych, dołącz do nas!",Tenha o seu lugar entre os justos. Junte-se a nós!,,Alătură-te celor drepți!,Займи своё место среди праведных. Присоединись к нам!,,"Ta din plats bland de rättfärdiga, anslut dig till oss!","Doğruların arasında yerinizi alın, bize katılın!" +The Order protects its own.,TXT_RANDOM_PGUARD_08,,,,Řád si své lidi chrání.,Ordenen beskytter sine egne.,Der Orden beschützt seine Jünger.,,La Ordeno defendas siajn anojn.,La Orden defiende a los suyos.,,Veljeskunta puolustaa omiaan.,L'ordre protège les siens.,A Rend a magáét védi.,L'Ordine protegge i suoi.,オーダーは我々を守護している。,오더는 신들을 향한 기도로 거룩하여짐이니라.,De Orde beschermt zijn discipelen. ,Ordenen beskytter sine egne.,Zakon chroni swoich.,A Ordem protege os seus discípulos.,,Ordinul îi protejează pe cei loiali.,Орден защищает своих.,,Orden skyddar sina egna.,Tarikat kendine ait olanları korur. +Acolytes? They have yet to see the full glory of the Order.,TXT_RANDOM_PGUARD_09,,,,Akolyté? Ti ještě neviděli Řád v celé své kráse.,Acolytes? De har endnu ikke set Ordenens fulde herlighed.,Ministranten? Die müssen erst noch die volle Macht des Ordens erfahren.,,Ĉu akolitoj? Ili ankoraŭ ne vidis la tutan gloron de La Ordeno.,¿Acólitos? Aún no han visto toda la gloria de La Orden.,¿Acólitos? Aún no vieron toda la gloria de La Orden.,Akoluutit? He eivät ole vielä nähneet Veljeskunnan täyttä kirkkautta.,Les Acolytes? Ils n'ont pas encore été témoins de la vraie gloire de l'ordre.,Ministránsok? Még nem látták A Rend igazi dicsőségét.,Gli accoliti? Devono ancora conoscere la vera gloria dell'Ordine.,"アコライト? +奴等はオーダーの爛漫なる未来を見ていない。",아콜라이트들이라... 애석하게도 이 들은 믿음이 아직 부족하다고 생각함이라.,Acolieten? Zij moeten de volle glorie van de Orde nog zien.,Akolytter? De har ennå ikke sett Ordenens fulle herlighet.,Akolitów? Oni jeszcze nie widzieli pełnej chwały Zakonu.,Acólitos? Eles ainda não viram toda a glória da Ordem.,,Acoliți? Încă nu au văzut gloria Ordinului.,Служители? Им ещё только предстоит узреть подлинное величие Ордена.,,Acolytes? De har ännu inte sett ordens fulla ära.,Yardımcıları mı? Henüz Tarikat'ın tüm ihtişamını görmediler. +"If there is any honor inside that pathetic shell of a body, you'll enter into the arms of the Order.",TXT_RANDOM_PGUARD_10,,,"If there is any honour inside that pathetic shell of a body, you'll enter into the arms of the Order.","Jestli ta tvoje žalostná tělesná schránka má v sobě kousek cti, dáš se do rukou Řádu.","Hvis der er nogen ære inden i denne ynkelige skal af en krop, vil du gå ind i Ordenens arme.","Wenn du noch einen Hauch von Ehre hast, wirst du dem Orden beitreten.",,"Se restas iom da honoro en tiu ridinda ŝelo nomata «korpo», vi iĝos unu el la brakoj de La Ordeno.","Si hay algo de honor dentro de ese patético cascarón llamado «cuerpo», La Orden te espera con los brazos abiertos.",,"Jos tuon säälittävän ruumiinhylyn sisällä on yhtään kunniakkuutta, otat itsesi Veljeskunnan huomaan.","Si il y a une once de gloire dans ce corps pathétique, ceux de l'ordre te prendront parmi les leurs.","Ha csak egy csipetnyi becsület is van testednek szánalmas páncéljában, A Rend katonáinak sorába fogsz beállni.","Se c'è un po' di onore rimasto dentro quel guscio patetico che chiami corpo, entrerai nelle braccia dell'Ordine.","その哀れな肉体の殻でも名誉の為ならば、 +オーダーの兵器を携える事が出来るだろう。",육체라는 나약한 껍질에 갇힌 운명을 참회하는 자들이야말로 오더와 함께할 수 있을지어다. ,"Als er enige eer in dat zielige omhulsel van een lichaam zit, zul je in de armen van de Orde binnengaan.","Hvis det er noe ære i det patetiske skallet av en kropp, vil du gå inn i Ordenens armer.","Jeśli w tej żałosnej skorupie ciała jest choć odrobina honoru, wejdziesz w ramiona Zakonu.","Se ainda existe honra dentro da sua carne patética, você entrará para os braços da Ordem.",,"Dacă e o fărâmă de onoare în acel corp jalnic, vei putea intra în brațele Ordinului.","Если внутри этой бренной телесной оболочки есть хоть капля чести, ты присоединишься к Ордену.",,"Om det finns någon heder i det patetiska skalet av en kropp, kommer du att gå in i Ordens armar.","Eğer o zavallı bedenin içinde biraz onur varsa, Tarikat'ın kollarına gireceksin." +Bye!,TXT_RANDOMGOODBYE_1,,,,Tak ahoj!,Farvel!,Tschüss!,,Ĝis!,¡Adiós!,,Näkemiin!,Au revoir!,Szervusz!,Ciao!,じゃあな!,안녕!,Dag!,Adjø!,Pa!,Tchau!,,Pa!,Пока!,,Hej då!,Güle güle! +"Thanks, bye!",TXT_RANDOMGOODBYE_2,,,,"Díky, ahoj!","Tak, farvel!","Danke, tschüss!",,Dankon. Ĝis!,Gracias. ¡Adiós!,,"Kiitos, hei!","Merci, au revoir!","Köszi, szia!","Grazie, ciao!",どうも、じゃあ!,그렇군요. 그럼 안녕히!,"Bedankt, tot ziens!","Takk, ha det!","Dzięki, pa!",Obrigado. Até mais!,,"Merci, pa!","Спасибо, пока!",,"Tack, hej då!","Teşekkürler, güle güle!" +See you later!,TXT_RANDOMGOODBYE_3,,,,Uvidíme se později!,Vi ses senere!,Bis später!,,Ĝis la revido!,¡Nos vemos!,,Nähdään!,A plus tard!,Később találkozunk!,Ci vediamo dopo!,また今度!,다음에 봐요!,Tot ziens!,Vi ses senere!,Do zobaczenia później!,Até logo!,,Ne vedem mai încolo!,До встречи!,,Vi ses senare!,Sonra görüşürüz! +,,Strife logs,,,,,,,,,,,,,,,,,,,,,,,,, +"Hello? Command, a com unit has just been activated... Am receiving visuals and sound from... somebody... Hey you, get out of there now... and drop the chalice!",TXT_ILOG1,MAP33: After getting the hidden com unit in the tavern.,,,"Haló? Velení, právě byl aktivován komunikátor... příjimám obraz a zvuk od... někoho... Hej, ty, dostaň se odtaď... a zahoď ten kalich!","Hallo? Kommando, en kommunikationsenhed er lige blevet aktiveret... Jeg modtager billeder og lyd fra... en eller anden... Hey du, kom ud derfra nu... og smid bægeret!","Hallo, Kommandozentrale, eine Kommunikationseinheit wurde gerade aktiviert.... Ich empfange Bilder und Ton von... irgend jemandem... Hey, du, verschwinde da sofort... Und schmeiß den Kelch weg!",,Saluton?... Komandanto! Interfono ekagiĝis: mi ricevas bildojn kaj sonon el... iu. Hola! Eliru tuj el tie... kaj forĵetu la kalikon!,"¿Hola?... Comando, un intercomunicador acaba de ser activado: recibo imágenes y sonido de... alguien. Eh, tú, sal de ahí ahora mismo... ¡Y tira ese cáliz!",,"Haloo? Komentokeskus, äsken juuri kytkettiin päälle viestintälaite... Poimin... jonkun... videota ja ääntä... Hei sinä, häivy täältä heti paikalla... ja pudota kalkki!","Allô? Central, un communicateur à été activé.. Je recois visuel et son de.. quelqu'un.. Hé, vous, sortez de là! Et lâchez le calice!","Haló Központ! Egy jeladót aktiváltak...kép és hang jeleket veszek...valakitől...Hé Te ott, húzz ki onnan...és rakd le a serleget!","Pronto? Comando, un'unità di comunicazione è appena stata attivata... Sto ricevendo segnali audiovisivi da... qualcuno... Hey, tu, esci da là subito, e lascia stare quel calice!","もしもし? 司令部、comユニットが起動されました。 +...からビジュアルとサウンドを受け取っています +...誰かが...ちょっと、今そこから出て行ってください +...そして聖杯を捨ててください!","여보세요? 본부, 통신기가 막 작동되기 시작했다... 지금 어떤... 사람의 모습이 보이는데... 이봐, 거기서 당장 나와... 그리고 성배를 버려!","Hallo? Commando, een com-unit is zojuist geactiveerd.... Ontvang ik beelden en geluid van.... iemand... Hé jij, ga daar nu weg.... en laat de kelk vallen!","Hallo? Kommando, en kommunikasjonsenhet har nettopp blitt aktivert... Mottar bilder og lyd fra... noen... Hei du, kom deg ut derfra nå... og slipp begeret!","Halo? Dowództwo, jednostka komunikacyjna właśnie została aktywowana... Odbieram obraz i dźwięk od... kogoś... Hej ty, uciekaj stamtąd natychmiast... i rzuć kielich!","Alô? Comando, um comunicador acabou de ser ativado... Estou recebendo imagens e som de... alguém... Ei você, saia daí agora... e solte o cálice!",,"Alo? Centrul de comandă, o unitate tocmai a fost activată.... Primesc imagini și audio de la... cineva... Hei tu,pleacă de acolo și lasă potirul!","Алло? Штаб, передатчик только что включился... Я принимаю звук и картинку от... кого-то... Эй, ты, беги оттуда, сейчас же... и брось чашу!",,"Hallå? Kommando, en kom-enhet har just aktiverats... Får bild och ljud från... någon... Hallå där, kom ut därifrån nu... och släpp kalken!","Alo? Komuta, bir iletişim birimi az önce aktive edildi. Birinden görüntü ve ses alıyorum. Hey sen, hemen oradan çık... ve kadehi bırak!" +"Listen, this com unit tells me that you're 100% human. I've been ordered to bring you in, we're talking trust here. Betray me and pay. Oh, and by the way, you can call me Blackbird.",TXT_ILOG2,MAP02: After getting the com unit from Rowan and leaving his room.,,,"Poslyš, tento komunikátor mi říká, že jsi na sto procent člověkem. Dostala jsem rozkaz přivést tě k nám, jde o důvěryhodnou záležitost. Zraď mě a zaplatíš. Jo, a mimochodem, můžeš mi říkat Straka.","Hør, denne com-enhed fortæller mig, at du er 100% menneskelig. Jeg er blevet beordret til at bringe dig ind. Vi taler om tillid her. Forråd mig og betal. Åh, og forresten, du kan kalde mig Blackbird.","Hör zu, dieser Kommunikator sagt mit, dass du noch 100% menschlich bist. Mir wurde aufgetragen, dich zu unserer Zentrale zu führen. Wir reden über Vertrauen, wenn du mich verrätst, wirst du bezahlen. Übrigens, du kannst mich Blackbird nennen.",,"Nu, ĉi tiu interfono diras, ke vi estas centelcente homa. Mi estis ordonita lasi vin eniri, mi do fidos vin. Se vi perfidos min, vi pentos. Ha, parenteze, vi rajtas nomi min Merlo.","A ver, este intercomunicador me dice que eres 100% humano. Se me ha ordenado dejarte entrar, así que hablamos con confianza. Traicióname y te arrepentirás. Ah, por cierto, puedes llamarme Blackbird (Mirlo).","A ver, este intercomunicador me dice que eres 100% humano. Se ordenadó dejarte entrar, así que hablamos con confianza. Traicióname y te vas a arrepentir. Ah, por cierto, puedes llamarme Blackbird (Mirlo).","Kuule, tämä viestintälaite ilmaisee sinun olevan sataprosenttisesti ihminen. Minut on määrätty tuomaan sinut meidän joukkoomme; puhumme luottamuksellisesti. Petä minut ja saat luvan maksaa. Ja muuten, voit kutsua minua Blackbirdiksi.","Ecoute, ce communicateur me dit que tu est 100% humain. On m'a ordonnée de te ramener, c'est une question de confiance. Trahis-moi et tu paieras. Oh, et tu peux m'appeler Blackbird.","Figyelj, azt jelzi a jeladó, hogy 100%-ban ember vagy. Azt az utasítást kaptam ,hogy vigyelek be, de a bizalmammal játszol. Átversz és megfizetsz. Ja, és hívhatsz feketerigónak.","Ascolta, questa unità di comunicazione mi dice che sei 100% umano. Ho l'ordine di farti arrivare da noi, e quindi stiamo parlando di fiducia. Se mi tradisci la pagherai cara. Comunque, mi puoi chiamare Blackbird.","聞こえるか、この無線機がアナタは100%人間だと判断した。 私はアナタを信頼して良いとみて連れて来るよう命じられた、 -反乱への報酬は期待して良いわ。ああ、それと、私の名はブラックバードよ。","잘 들어, 이 통신기에 따르면 넌 100% 인간이야. 너를 믿어도 될 거 같으니 우리 편으로 끌어모으라는 지시를 받았어. 배신했다간 대가를 치를 거야. 아, 그리고, 날 블랙버드라고 불러줘.","Luister, deze com-unit vertelt me dat je 100% menselijk bent. Ik heb opdracht gekregen om je binnen te halen, we hebben het hier over vertrouwen. Verraad me en betaal. Oh, en trouwens, je mag me Blackbird noemen.",,"Ouça, este comunicador me diz que você é 100% humano. Recebi ordens para te trazer até aqui. É melhor você ser de confiança. Se você me trair, você me paga. Ah, a propósito, pode me chamar de Blackbird.",,,"Слушай — судя по этому передатчику, ты на сто процентов человек. Я получила приказ показать тебе дорогу к нам. Как видишь, тебе доверяют, но если предашь меня — пожалеешь. И да, обращайся ко мне «Чёрный дрозд». ", -"Listen, this com-unit tells me that you're 100% human. You might be one of us, and maybe we can try and trust each other. Consider this test, there's a flamethrower in the Governor's mansion. Get it, and I'll lead you to us",TXT_ILOG2,,strifeteaser,,"Poslyš, tento komunikátor mi říká, že jsi na sto procent člověkem. Mohl bys být jedním z nás a možná se můžeme pokusit navzájem si věřit. Ber tohle jako test: V guvernérově sídle je plamenomet. Najdi ho a zavedu tě k nám.","Hör zu, dieser Kommunikator sagt mit, dass du noch 100% menschlich bist. Du magst einer von uns sein und vielleicht können wir einander vertrauen. Betrachte dies als einen Test, da ist ein Flammenwerfer in der Villa des Gouverneurs. Hole ihn und ich führe dich zu uns.",,,"Escucha, esta unidad de comunicación me dice que eres 100% humano. Podrías ser uno de nosotros, y tal vez podamos intentar confiar el uno en el otro. Considera esto una prueba, hay un lanzallamas en la mansión del gobernador. Tómalo, y te llevará a nosotros",,,"Ecoute, ce communicateur me dit que tu est 100% humain. Il se peut que tu est l'un des nôtres, on pourrait se faire confiance. Considère cela comme un test. Il y a un lance-flammes dans le manoir du gouverneur. Récupère le et je te mènerai à nous.",,,"聞いて、このcom-unitはあなたが100%人間だということを教えてくれます。 +反乱への報酬は期待して良いわ。ああ、それと、私の名はブラックバードよ。","잘 들어, 이 통신기에 따르면 넌 100% 인간이야. 너를 믿어도 될 거 같으니 우리 편으로 끌어모으라는 지시를 받았어. 배신했다간 대가를 치를 거야. 아, 그리고, 날 블랙버드라고 불러줘.","Luister, deze com-unit vertelt me dat je 100% menselijk bent. Ik heb opdracht gekregen om je binnen te halen, we hebben het hier over vertrouwen. Verraad me en betaal. Oh, en trouwens, je mag me Blackbird noemen.","Hør her, denne kommunikasjonsenheten forteller meg at du er 100% menneskelig. Jeg har fått ordre om å hente deg inn, vi snakker om tillit her. Forråd meg og betal. Og forresten, du kan kalle meg Blackbird.","Słuchaj, to urządzenie mówi mi, że jesteś w 100% człowiekiem. Dostałem rozkaz, żeby cię sprowadzić, mówimy tu o zaufaniu. Zdradź mnie i zapłać. Aha, i przy okazji, możesz mi mówić Blackbird.","Ouça, este comunicador me diz que você é 100% humano. Recebi ordens para te trazer até aqui. É melhor você ser de confiança. Se você me trair, você me paga. Ah, a propósito, pode me chamar de Blackbird.",,"Ascultă, unitatea asta îmi spune că ești 100% uman. Am primit ordin să te arestez. Trădează-mă și plătești. Oh, apropo, îmi poți spune Blackbird.","Слушай — судя по этому передатчику, ты на сто процентов человек. Я получила приказ показать тебе дорогу к нам. Как видишь, тебе доверяют, но если предашь меня — пожалеешь. И да, обращайся ко мне «Чёрный дрозд». ",,"Lyssna, den här kommunikationsenheten säger mig att du är 100% mänsklig. Jag har blivit beordrad att ta in dig, vi pratar om förtroende här. Förråda mig och betala. Och förresten, du kan kalla mig Blackbird.","Dinle, bu iletişim ünitesi bana senin %100 insan olduğunu söylüyor. Seni buraya getirmem emredildi, burada güvenden bahsediyoruz. Bana ihanet edersen bedelini ödersin. Bu arada, bana Karatavuk diyebilirsin." +"Listen, this com-unit tells me that you're 100% human. You might be one of us, and maybe we can try and trust each other. Consider this test, there's a flamethrower in the Governor's mansion. Get it, and I'll lead you to us.",TXT_ILOG2,MAP33: After getting the hidden com unit in the tavern.,strifeteaser,,"Poslyš, tento komunikátor mi říká, že jsi na sto procent člověkem. Mohl bys být jedním z nás a možná se můžeme pokusit navzájem si věřit. Ber tohle jako test: V guvernérově sídle je plamenomet. Najdi ho a zavedu tě k nám.","Hør, denne com-enhed fortæller mig, at du er 100% menneskelig. Du er måske en af os, og måske kan vi prøve at stole på hinanden. Overvej denne test: Der er en flammekaster i guvernørens palæ. Hent den, så fører jeg dig til os.","Hör zu, dieser Kommunikator sagt mit, dass du noch 100% menschlich bist. Du magst einer von uns sein und vielleicht können wir einander vertrauen. Betrachte dies als einen Test, da ist ein Flammenwerfer in der Villa des Gouverneurs. Hole ihn und ich führe dich zu uns.",,"Nu, ĉi tiu interfono diras, ke vi estas centelcente homa. Vi eble estas unu el ni, tial ni povus fidi nin reciproke. Mi provos vin: estas flamĵetilo en la domego de la registo; prenu ĝin kaj mi gvidos vin al ni.","A ver, este intercomunicador me dice que eres 100% humano. Podrías ser uno de nosotros y tal vez podamos intentar confiar el uno en el otro. Te pondré a prueba: hay un lanzallamas en la mansión del gobernador; cógelo y te guiaré a nosotros.","A ver, este intercomunicador me dice que eres 100% humano. Podrías ser uno de nosotros y tal vez podamos intentar confiar el uno en el otro. Te pongo a prueba: hay un lanzallamas en la mansión del gobernador; agárralo y te voy a guiar a nosotros.","Kuule, tämä viestintälaite ilmaisee sinun olevan sataprosenttisesti ihminen. Saatat olla yksi meistä, ja ehkä voimme yrittää luottaa toisiimme. Voit pitää tätä testinä: Kuvernöörin kartanossa on liekinheitin. Hanki se, ja johdatan sinut luoksemme.","Ecoute, ce communicateur me dit que tu est 100% humain. Il se peut que tu est l'un des nôtres, on pourrait se faire confiance. Considère cela comme un test. Il y a un lance-flammes dans le manoir du gouverneur. Récupère le et je te mènerai à nous.","Figyelj, azt jelzi a jeladó, hogy 100%-ban ember vagy. Talán tényleg egy vagy közülünk, és megpróbálhatunk bízni egymásban. Vedd a következőt tesztnek: kapj fel egy lángszórót a Kormányzó kúriájából. Ha megszerzed, elvezetlek hozzánk.","Ascolta, questa unità di comunicazione mi dice che sei 100% umano. Potresti essere uno di noi, e forse possiamo fidarci l'uno dell'altro. Ti metterò alla prova, c'è un lanciafiamme nel palazzo del governatore. Prendilo, e ti condurrò da noi.","聞いて、このcom-unitはあなたが100%人間だということを教えてくれます。 あなたは私たちのうちの一人であるかもしれません、 そしておそらく私たちは互いに試みて信頼することができます。 このテストを考えてください、知事の邸宅に火炎放射器があります。 -それを手に入れてください","잘 들어, 이 통신기에 따르면 넌 100% 인간이야. 우리들은 너를 적극적으로 믿으니까 너도 같이 이해하고 신뢰했으면 좋겠어. 그러기 위해선 시험을 치러야 하는데, 총독의 건물 안에 화염방사기가 있어. 얻으면 우리들이 있는 곳을 알려줄게. ","Luister, deze com-unit vertelt me dat je 100% menselijk bent. Misschien bent u een van ons, en misschien kunnen we elkaar proberen te vertrouwen. Overweeg deze test, er is een vlammenwerper in het landhuis van de gouverneur. Haal het, en ik zal je naar ons toe leiden....",,"Ouça, este comunicador me diz que você é 100% humano. Pode ser que você seja um de nós e talvez possamos tentar confiar um no outro. Considere isto um teste, há um lança-chamas na mansão do Governador. Entre lá e eu te guiarei até nós.",,,"Слушай — судя по этому передатчику, ты на сто процентов человек. Ты можешь присоединиться к нам, и мы должны доверять друг другу. Небольшое тебе испытание: в особняке губернатора есть огнемёт. Достань его, и я покажу тебе дорогу к нам.", -Head over to the old town hall. Macil had a tunnel built that lets us get in and out without the acolytes' knowledge.,TXT_ILOG3,,,,"Zamiř ke staré radnici. Macil nechal postavit tunel, který nám dovoluje se dostat dovnitř a ven bez vědomí akolytů.","Geh zum alten Rathaus. Macil hat einen Tunnel bauen lassen, durch den wir dort reinkommen, ohne dass die Ministranten das mitbekommen.",,,Dirígete al antiguo ayuntamiento. Macil hizo construir un túnel que nos permite entrar y salir sin que los acólitos lo sepan.,,,Dirige-toi vers l'ancienne mairie. Macil a fait construire un tunnel qui nous permet d'y entrer sans que l'Ordre nous remarque.,,,"旧市庁舎に入る。そこにはマシルがアコライトに関わる者を欺く為の -抜け道を用意している。",구 시청으로 향해. 오더가 이곳을 폭격한 후에 마실이 그곳에 아콜라이트들이 모르는 통행로를 만들어놨어.,Ga naar het oude stadhuis. Macil heeft een tunnel laten bouwen die ons zonder medeweten van de acolieten in en uit kan stappen.,,Vá até a antiga prefeitura. Macil construiu um túnel que permite que a gente entre e saia sem os acólitos perceberem.,,,"Отправляйся к старой ратуше. Мэйсил построил там туннель, который позволяет нам входить и выходить без ведома служителей.", -"Go through the door on your left, then the one on the right. The guard's name is Geoff. Tell him you need gold.",TXT_ILOG4,,,,"Projdi dveřmi nalevo a pak napravo. Hlídač se jmenuje Geoff. Řekni mu, že potřebuješ zlato.","Geh durch die linke Tür, dann durch die rechte. Der Wächter heißt Geoff. Sag ihm du brauchst Gold.",,,"Ve por la puerta a tu izquierda, y luego a tu derecha. El guardia se llama Geoff. Dile que necesitas oro.",,,Passe par la porte à gauche puis celle à droite. Le garde s'appelle Geoff. Dis-lui que tu as besoin d'argent.,,,"すぐ左のドアを通り、右のドアから小部屋に入るんだ。 -見張りの名はジェフ。金が必要だ と言えば通じる。","네 왼쪽의 문으로 들어간 후, 다시 오른쪽의 문으로 가. 경비의 이름은 제프야. 그에게 골드가 필요하다고 얘기해.","Ga door de deur links van je, dan de deur rechts. De bewaker heet Geoff. Zeg hem dat je goud nodig hebt.",,Vá pela porta à sua esquerda e depois a da direita. O nome do guarda é Geoff. Diga a ele que você precisa de ouro.,,,"Пройди за левую дверь, затем иди направо. Стражника зовут Джефф. Скажи ему, что тебе нужно золото.", -"Don't enter the town hall. It's not safe anymore, our cover's been blown. Kill all the big robots, the ""Crusaders"" and I'll guide you to us.",TXT_ILOG5,,strifeteaser,,"Nechoď do radnice, už není bezpečná. Byli jsme odhaleni. Zabij všechny ty velké roboty, Křižáky, a pak tě nasměruju k Macilovi.","Geh nicht ins Rathaus. Da ist es nicht mehr sicher, unsere Tarnung ist aufgeflogen. Erledige die großen Roboter, die „Ordensritter“ und ich führe dich zu uns.",,,"No entres en el ayuntamiento. Ya no es seguro, nos han descubierto. Mata a todos los robots grandes, los 'Cruzados' y te guiaré a nosotros.","No entres en el ayuntamiento. Ya no es seguro, fuimos descubiertos. Mata a los robots gigantes, los 'Cruzados' y te guiaré a nosotros.",,"N'entre pas dans la mairie, ce n'est plus sûr. Notre couverture ne marche plus. Détruis tous les gros robots, les « Croisés » et je te mènerai à nous.",,,"町にいるフロントへの武器供給者であるイラールの元を訪ねる。 -彼は武器屋の隣のドアに居る。それで、知事と会う為にマシルから貰ったキーを使う。",아직 시청으로 가지 마. 우리가 발각된 상태라 위험하다고. 거대한 '크루세이더' 로봇들을 먼저 처리해. 그다음에 내가 안내해줄게.,"Ga het stadhuis niet binnen. Het is niet meer veilig, onze dekmantel is opgeblazen. Dood alle grote robots, de ""Kruisvaarders"" en ik zal je naar ons toe leiden.",,"Não entre na prefeitura. Não é mais seguro, fomos descobertos. Mate esses robozões, os ""Cruzados"" e eu te guiarei até nós.",,,"Не ходи к ратуше. Наше убежище было разгромлено, теперь там небезопасно. Перебей этих больших роботов, «крестоносцев», и я покажу тебе дорогу к нам. ", -"The door next to the weapons shop will open once all the Crusaders are dead. Inside the store room there's a teleporter, use it, and it'll bring you to us",TXT_ILOG6,,strifeteaser,,"Dveře vedle obchodu se zbraněmi se otevřou když budou všichni Křižáci zničeni. Uvnitř je teleportér, použij ho a dostaneš se k nám.","Die Tür neben dem Waffengeschäft wird sich öffnen, wenn alle Ordensritter tot sind. Dahinter ist ein Teleporter. Benutze ihn, er bringt dich zu uns.",,,"La puerta junto a la tienda de armas se abrirá en cuanto todos los cruzados estén muertos. Dentro del almacén hay un teletransporte, úsalo, y te traerá a nosotros.","La puerta junto a la tienda de armamento se abrirá una vez que todos los cruzados estén muertos. Adentro hay un teleporte, úsalo y te traerá a nosotros",,"La porte à côté du magasin d'armes s'ouvrira quand tous les croisés seront détruits. A l'intérieur de la salle de stockage se trouve un téléporteur, utilise-le pour nous rejoindre.",,,"私が知事について知っていることは、町の中央で双方を遊ばせてる様だ。 -ソイツがここいらを'マンション'と呼んでいる。",크루세이더들을 전부 처리하면 무기상 옆의 문이 열릴 거야. 그 안에 우리 기지로 통하는 텔레포터가 있으니 그걸 타.,"De deur naast de wapenwinkel gaat open als alle kruisvaarders dood zijn. In de opslagruimte staat een teleporter, gebruik die, en die brengt je naar ons toe.",,A porta próxima à loja de armas abrirá assim que todos os Cruzados estiverem mortos. Dentro do depósito tem um teletransportador. Entre nele e ele o levará até nós.,,,"Дверь возле оружейного магазина откроется, когда все крестоносцы будут уничтожены. На складе ты найдёшь телепорт. Используй его — он доставит тебя к нам.", -"The door next to the weapons shop will open once all the Crusaders are dead. Inside the store room there's a teleporter, use it, and it'll bring you to us",TXT_ILOG7,,strifeteaser,,"Dveře vedle obchodu se zbraněmi se otevřou když budou všichni Křižáci zničeni. Uvnitř je teleportér, použij ho a dostaneš se k nám.","Die Tür neben dem Waffengeschäft wird sich öffnen, wenn alle Ordensritter tot sind. Dahinter ist ein Teleporter. Benutze ihn, er bringt dich zu uns.",,,"La puerta junto a la tienda de armas se abrirá en cuanto todos los cruzados estén muertos. Dentro del almacén hay un teletransporte, úsalo, y te traerá a nosotros.","La puerta junto a la tienda de armamento se abrirá una vez que todos los cruzados estén muertos. Adentro hay un teleporte, úsalo y te traerá a nosotros",,"La porte à côté du magasin d'armes s'ouvrira quand tous les croisés seront détruits. A l'intérieur de la salle de stockage se trouve un téléporteur, utilise-le pour nous rejoindre.",,,"私が知事について知っていることは、町の中央で双方を遊ばせてる様だ。 -ソイツがここいらを'マンション'と呼んでいる。",크루세이더들을 전부 처리하면 무기상 옆의 문이 열릴 거야. 그 안에 우리 기지로 통하는 텔레포터가 있으니 그걸 타.,"De deur naast de wapenwinkel gaat open als alle kruisvaarders dood zijn. In de opslagruimte staat een teleporter, gebruik die, en die brengt je naar ons toe.",,A porta próxima à loja de armas abrirá assim que todos os Cruzados estiverem mortos. Dentro do depósito tem um teletransportador. Entre nele e ele o levará até nós.,,,"Дверь возле оружейного магазина откроется, когда все крестоносцы будут уничтожены. На складе ты найдёшь телепорт. Используй его — он доставит тебя к нам.", -"Kill as many of the big robots, Crusaders, as you can. When you're done, I'll guide you to Macil",TXT_ILOG8,,strifeteaser,,"Znič tolik těch velkých robotů, Křižáků, kolik dokážeš. Až budeš hotov, dovedu tě k Macilovi.","Erledige so viele von den großen Robotern - „Ordensrittern“, wie möglich. Wann das erledigt ist, führe ich dich zu Macil.",,,"Mata a tantos de los robots grandes, los cruzados, que puedas. Cuando termines, te guiaré hasta Macil.","Mata a tantos robots gigantes como puedas. Cuando termines, te guiaré a Macil",,"Détruis autant des gros robots, les croisés, que tu peux, et je te mènerai à Macil.",,,,"저 거대한 '크루세이더' 로봇들을 최대한 처리해. 상황이 정리되면, 내가 너를 마실에게 데려다줄게.","Dood zoveel mogelijk van de grote robots, kruisvaarders, als je kunt. Als je klaar bent, begeleid ik je naar Macil...",,"Mate o máximo desses robos possível. Quando terminar, eu te guiarei ao Macil.",,,"Убей столько больших роботов, — крестоносцев, — сколько сможешь. Когда закончишь, я приведу тебя к Мэйсилу.", -"Go through the door, and talk to Macil.",TXT_ILOG9,,strifeteaser,,Projdi dveřmi a promluv si s Macilem.,Geh durch die Tür und rede mit Macil.,,,"Ve por la puerta, y habla con Macil.",Ve por la puerta y habla con Macil.,,Traverse cette porte et va parler à Macil.,,,ダーウィンを始末したら耳を知事に渡す。,저 문을 지나서 마실하고 대화를 해봐.,"Ga door de deur, en praat met Macil.",,Passe pela porta e fale com o Macil.,,,Обратись к Мэйсилу. Он за этой дверью., -"Find the power tap on the mains, and shut it off. Bring something back to the Governor as proof. Find MacGuffin, and talk to him.",TXT_ILOG10,,,,Najdi stáčedlo energie na elektrické síti a vypni jej. Přines něco guvernérovi jako důkaz. Najdi MacGuffina a promluv s ním.,Finde die Stromanzapfung und schalte sie ab. Bringe einen Beweis zum Gouverneur. Finde MacGuffin und rede mit ihm. ,,,"Encuentra la intervención eléctrica en la red principal, y apágala. Trae algo de vuelta al gobernador como prueba. Encuentra a MacGuffin, y habla con él.",Encuentra la intervención eléctrica de la red principal y elimínala. Trae una prueba de vuelta al gobernador. Encuentra a MacGuffin y habla con él.,,Trouve la connection pirate sur le transformateur et désactive la. Amène quelque chose au gouverneur comme preuve. Trouve MacGuffin et parle-lui.,,,"電力盗用の場所を見つけ、それを止める。 -知事に渡す証拠も必要だ。マクガフィンと話をつける。",주 동력선 어딘가에 있는 추출기를 처리해. 총독에게 전할 증거물도 챙기고. 맥거핀을 찾아서 대화해 봐.,Zoek het stopcontact op het lichtnet en zet het uit. Breng iets terug naar de gouverneur als bewijs. Zoek MacGuffin en praat met hem.,,Encontre a ligação pirata no transformador e desligue ela. Traga algo de volta para o Governador como prova. Encontre o MacGuffin e fale com ele.,,,Найди нелегальное подключение к линии электропередачи и выведи его из строя. Принеси что-нибудь губернатору в качестве доказательства. Найди МакГаффина и поговори с ним., -"Find the power tap on the mains, and shut it off. Bring something back to the Governor as proof. Find MacGuffin, and talk to him. He's up by the sewage treatment plant, in the ""bum hole"", down the stairs.",TXT_ILOG11,,,,"Najdi stáčedlo energie na elektrické síti a vypni jej. Přines něco guvernérovi jako důkaz. Najdi MacGuffina a promluv s ním. Je u čističky, v „zadnici“ pod schody.","Finde die Stromanzapfung und schalte sie ab. Bringe einen Beweis zum Gouverneur. Finde MacGuffin und rede mit ihm. Er ist in der Nähe der Kläranlage im „Pennerloch“, die Treppe runter.",,,"Encuentra la intervención eléctrica en la red principal, y apágala. Trae algo de vuelta al gobernador como prueba. Encuentra a MacGuffin, y habla con él. Está arriba junto a la planta de tratamiento de aguas residuales, en el 'hoyo vagabundo', bajando las escaleras.","Encuentra la intervención eléctrica de la red principal y elimínala. Trae una prueba de vuelta al gobernador. Encuentra a MacGuffin y habla con él. Se encuentra en la planta de tratamiento de aguas residuales, en el 'agujero vagabundo', bajando las escaleras.",,"Trouve la connection pirate sur le transformateur et désactive la. Amène quelque chose au gouverneur comme preuve. Trouve MacGuffin et parle-lui. Il se trouve dans la centrale de traitement des eaux, dans le « trou à rats » en bas des escaliers.",,,"電力盗用の場所を見つけ、それを止める。 +それを手に入れてください","잘 들어, 이 통신기에 따르면 넌 100% 인간이야. 우리들은 너를 적극적으로 믿으니까 너도 같이 이해하고 신뢰했으면 좋겠어. 그러기 위해선 시험을 치러야 하는데, 총독의 건물 안에 화염방사기가 있어. 얻으면 우리들이 있는 곳을 알려줄게. ","Luister, deze com-unit vertelt me dat je 100% menselijk bent. Misschien bent u een van ons, en misschien kunnen we elkaar proberen te vertrouwen. Overweeg deze test, er is een vlammenwerper in het landhuis van de gouverneur. Haal het, en ik zal je naar ons toe leiden....","Denne kommunikasjonsenheten forteller meg at du er 100 % menneskelig. Du kan være en av oss, og kanskje vi kan prøve å stole på hverandre. Tenk på denne testen, det er en flammekaster i guvernørens hus. Ta den, så fører jeg deg til oss.","Słuchaj, ta jednostka mówi mi, że jesteś w 100% człowiekiem. Może jesteś jednym z nas i możemy spróbować sobie zaufać. Rozważ ten test, w rezydencji gubernatora jest miotacz ognia. Weź go, a zaprowadzę cię do nas.","Ouça, este comunicador me diz que você é 100% humano. Pode ser que você seja um de nós e talvez possamos tentar confiar um no outro. Considere isto um teste, há um lança-chamas na mansão do Governador. Entre lá e eu te guiarei até nós.",,"Ascultă, unitatea asta îmi spune că ești 100% uman. Poate putem avea încredere unii în ceilalți. Consideră acest test, e un aruncător de flăcări în complexul Guvernatorului. Ia-l, te va duce la noi.","Слушай — судя по этому передатчику, ты на сто процентов человек. Ты можешь присоединиться к нам, и мы должны доверять друг другу. Небольшое тебе испытание: в особняке губернатора есть огнемёт. Достань его, и я покажу тебе дорогу к нам.",,"Den här kommunikationsenheten säger mig att du är 100 procent mänsklig. Du kanske är en av oss och vi kanske kan försöka lita på varandra. Tänk på det här testet: Det finns en flamkastare i guvernörens herrgård. Hämta den, så leder jag dig till oss.","Dinle, bu iletişim birimi bana senin %100 insan olduğunu söylüyor. Bizden biri olabilirsin ve belki birbirimize güvenmeyi deneyebiliriz. Bu testi düşün, Vali'nin malikanesinde bir alev makinesi var. Onu al, ben de seni bize götüreyim." +Head over to the old town hall. Macil had a tunnel built that lets us get in and out without the acolytes' knowledge.,TXT_ILOG3,MAP02: On the bridge with the com unit.,,,"Zamiř ke staré radnici. Macil nechal postavit tunel, který nám dovoluje se dostat dovnitř a ven bez vědomí akolytů.","Gå over til det gamle rådhus. Macil har fået bygget en tunnel, der lader os komme ind og ud uden acolytes' viden.","Geh zum alten Rathaus. Macil hat einen Tunnel bauen lassen, durch den wir dort reinkommen, ohne dass die Ministranten das mitbekommen.",,Iru al la antikva urbodomo (Town Hall): Macil ordonis konstrui tunelon por kaj eniri kaj eliri senscie de la akolitoj.,Dirígete al antiguo ayuntamiento (Town Hall): Macil hizo construir un túnel para entrar y salir sin que los acólitos se enteren.,,"Suuntaa kohti vanhaa kaupungintaloa. Macil oli rakennuttanut tunnelin, jonka avulla voimme päästä sisään ja ulos akoluuttien tietämättä.",Dirige-toi vers l'ancienne mairie. Macil a fait construire un tunnel qui nous permet d'y entrer sans que l'Ordre nous remarque.,"Vedd az utad a régi városfalhoz. Macil épített egy föld alatti alagutat, amin keresztül a ministránsok tudta nélkül tudunk ki és be járkálni.",Raggiungi il vecchio Municipio. Macil ha fatto costruire un tunnel che ci fa entrare ed uscire senza che gli accoliti lo sappiano.,"旧市庁舎に入る。そこにはマシルがアコライトに関わる者を欺く為の +抜け道を用意している。",구 시청으로 향해. 오더가 이곳을 폭격한 후에 마실이 그곳에 아콜라이트들이 모르는 통행로를 만들어놨어.,Ga naar het oude stadhuis. Macil heeft een tunnel laten bouwen die ons zonder medeweten van de acolieten in en uit kan stappen.,Gå til det gamle rådhuset. Macil fikk bygget en tunnel som lar oss komme inn og ut uten at akolyttene vet om det.,"Udaj się do starego ratusza. Macil kazał wybudować tunel, który pozwoli nam wejść i wyjść bez wiedzy akolitów.",Vá até a antiga prefeitura. Macil construiu um túnel que permite que a gente entre e saia sem os acólitos perceberem.,,Du-te în vechia hală a orașului. Macil a construit un tunel care ne permite să ne deplasăm fără ca acoliții să știe.,"Отправляйся к старой ратуше. Мэйсил построил там туннель, который позволяет нам входить и выходить без ведома служителей.",,Gå till det gamla stadshuset. Macil lät bygga en tunnel som gör att vi kan ta oss in och ut utan acolytternas vetskap.,"Eski belediye binasına gidin. Macil, yardımcıların haberi olmadan girip çıkmamızı sağlayan bir tünel inşa ettirdi." +"Go through the door on your left, then the one on the right. The guard's name is Geoff. Tell him you need gold.",TXT_ILOG4,MAP02: In town hall with the com unit.,,,"Projdi dveřmi nalevo a pak napravo. Hlídač se jmenuje Geoff. Řekni mu, že potřebuješ zlato.","Gå gennem døren til venstre og derefter gennem den til højre. Vagtens navn er Geoff. Sig til ham, at du har brug for guld.","Geh durch die linke Tür, dann durch die rechte. Der Wächter heißt Geoff. Sag ihm du brauchst Gold.",,"Iru tra la maldekstra pordo kaj poste tra la dekstra. La nomo de la gardisto estas Geoff; diru al li, ke vi bezonas oron.",Ve por la puerta izquierda y luego por la derecha. El guardia se llama Geoff; dile que necesitas oro.,,"Kulje sinusta katsottuna vasemmalla puolella olevan oven läpi, sitten oikeanpuoleisesta ovesta. Vartijan nimi on Geoff. Kerro hänelle tarvitsevasi kultaa.",Passe par la porte à gauche puis celle à droite. Le garde s'appelle Geoff. Dis-lui que tu as besoin d'argent.,"Menj át a bal oldali ajtón, majd a jobb oldalin. Az őr neve Geoff. Mondd neki, hogy aranyra van szükséged.","Vai oltre la porta alla tua sinistra, e poi la porta alla tua destra. Il nome della guardia è Geoff. Digli che ti serve dell'oro.","すぐ左のドアを通り、右のドアから小部屋に入るんだ。 +見張りの名はジェフ。金が必要だ と言えば通じる。","네 왼쪽의 문으로 들어간 후, 다시 오른쪽의 문으로 가. 경비의 이름은 제프야. 그에게 골드가 필요하다고 얘기해.","Ga door de deur links van je, dan de deur rechts. De bewaker heet Geoff. Zeg hem dat je goud nodig hebt.","Gå gjennom døren til venstre, så den til høyre. Vakten heter Geoff. Si at du trenger gull.","Przejdź przez drzwi po lewej, a następnie te po prawej. Strażnik ma na imię Geoff. Powiedz mu, że potrzebujesz złota.",Vá pela porta à sua esquerda e depois a da direita. O nome do guarda é Geoff. Diga a ele que você precisa de ouro.,,"Intră pe ușa din stânga, apoi cea din dreapta. Numele paznicului e Geoff. Spune-i că-ți trebuie aur.","Пройди за левую дверь, затем иди направо. Стражника зовут Джефф. Скажи ему, что тебе нужно золото.",,Gå genom dörren till vänster och sedan genom dörren till höger. Vaktens namn är Geoff. Säg till honom att du behöver guld.,"Solundaki kapıdan geç, sonra sağdakinden. Muhafızın adı Geoff. Ona altına ihtiyacın olduğunu söyle." +"Don't enter the town hall. It's not safe anymore, our cover's been blown. Kill all the big robots, the ""Crusaders"" and I'll guide you to us.",TXT_ILOG5,,strifeteaser,,"Nechoď do radnice, už není bezpečná. Byli jsme odhaleni. Zabij všechny ty velké roboty, Křižáky, a pak tě nasměruju k Macilovi.","Gå ikke ind på rådhuset. Det er ikke sikkert længere, vores dække er blevet afsløret. Dræb alle de store robotter, ""korsfarerne"", så viser jeg dig vej til os.","Geh nicht ins Rathaus. Da ist es nicht mehr sicher, unsere Tarnung ist aufgeflogen. Erledige die großen Roboter, die „Ordensritter“ und ich führe dich zu uns.",,"Ne eniru la urbodomon: ili detruis niajn kovrilojn, ĝi do ne plu estas sekura. Detruu ĉiujn robotegojn, alinome Krucistojn, kaj mi gvidos vin al ni.","No entres en el ayuntamiento: nos han descubierto, o sea que ya no es seguro. Mata a todos los robots grandes, o sea, a los Cruzados, y te guiaré a nosotros.","No entres al ayuntamiento: nos descubrieron, o sea que ya no es seguro. Mata a todos los robots grandes, o sea, a los Cruzados, y te guío a nosotros.","Älä mene kaupungintaloon. Se ei ole enää turvallista; olemme paljastuneet. Tuhoa kaikki isot robotit, ""ristiretkeläiset"", ja opastan sinut luoksemme.","N'entre pas dans la mairie, ce n'est plus sûr. Notre couverture ne marche plus. Détruis tous les gros robots, les « Croisés » et je te mènerai à nous.","Ne menj be a városházába. Már nem biztonságos, lelepleződtünk. Öldd meg az összes nagy robotot, a Kereszteseket, és elvezetlek hozzánk.","Non entrare nel municipio. Non è più sicuro, la nostra copertura è saltata. Distruggi tutti i grossi robot, i ""Crociati"", e ti condurrò a noi.","町にいるフロントへの武器供給者であるイラールの元を訪ねる。 +彼は武器屋の隣のドアに居る。それで、知事と会う為にマシルから貰ったキーを使う。",아직 시청으로 가지 마. 우리가 발각된 상태라 위험하다고. 거대한 '크루세이더' 로봇들을 먼저 처리해. 그다음에 내가 안내해줄게.,"Ga het stadhuis niet binnen. Het is niet meer veilig, onze dekmantel is opgeblazen. Dood alle grote robots, de ""Kruisvaarders"" en ik zal je naar ons toe leiden.","Ikke gå inn i rådhuset. Det er ikke trygt lenger. Vi er avslørt. Drep alle de store robotene, ""korsfarerne"", så skal jeg lede dere til oss.","Nie wchodź do ratusza. To już nie jest bezpieczne, nasza przykrywka została zdmuchnięta. Zabij wszystkie duże roboty, ""krzyżowców"", a ja zaprowadzę cię do nas.","Não entre na prefeitura. Não é mais seguro, fomos descobertos. Mate esses robozões, os ""Cruzados"" e eu te guiarei até nós.",,"Nu intra în hala orașului. Nu mai e sigură, s-a dus acoperirea noastră. Distruge toți roboții mari, Cruciații te vor conduce la noi.","Не ходи к ратуше. Наше убежище было разгромлено, теперь там небезопасно. Перебей этих больших роботов, «крестоносцев», и я покажу тебе дорогу к нам. ",,"Gå inte in i stadshuset. Det är inte säkert längre, vår täckmantel har avslöjats. Döda alla stora robotar, ""Korsriddarna"", så ska jag guida dig till oss.","Belediye binasına girme. Artık güvenli değil, kimliğimiz açığa çıktı. Bütün büyük robotları, ""Haçlıları"" öldürün, ben de sizi bize yönlendireyim." +"The door next to the weapons shop will open once all the Crusaders are dead. Inside the store room there's a teleporter, use it, and it'll bring you to us",TXT_ILOG6,"MAP33: In front of ""Irale's shop"" with the com unit and the Crusaders dead.",strifeteaser,,"Dveře vedle obchodu se zbraněmi se otevřou když budou všichni Křižáci zničeni. Uvnitř je teleportér, použij ho a dostaneš se k nám.","Døren ved siden af våbenbutikken vil åbne sig, når alle korsfarerne er døde. Inde i lagerrummet er der en teleporter, brug den, og den vil føre dig til os.","Die Tür neben dem Waffengeschäft wird sich öffnen, wenn alle Ordensritter tot sind. Dahinter ist ein Teleporter. Benutze ihn, er bringt dich zu uns.",,Detrui la Krucistojn malfermis la pordon apud la armilvendejo. Estas teleportilo en tiu stokejo; uzu ĝin.,La puerta junto a la armería se ha abierto al matar a los cruzados. Dentro de ese almacén hay un teletransporte; úsalo.,La puerta junto a la armería se abrió al matar a los cruzados. Adentro de ese almacén hay un teletransporte; úsalo.,"Asekaupan viereinen ovi aukeaa, kun kaikki ristiretkeläiset on tuhottu. Varastohuoneessa on kaukosiirrin. Sitä käyttämällä pääset luoksemme.","La porte à côté du magasin d'armes s'ouvrira quand tous les croisés seront détruits. A l'intérieur de la salle de stockage se trouve un téléporteur, utilise-le pour nous rejoindre.","A fegyverbolt melletti ajtó ki fog nyílni, miután az összes Kresztes meghalt. Találsz a raktáron belül egy teleportot, ami ide fog hozni hozzánk.","La porta accanto al negozio delle armi si aprirà non appena tutti i Crociati sono distrutti. Oltre quella porta c'è un teletrasporto, usalo e ti porterà da noi.","私が知事について知っていることは、町の中央で双方を遊ばせてる様だ。 +ソイツがここいらを'マンション'と呼んでいる。",크루세이더들을 전부 처리하면 무기상 옆의 문이 열릴 거야. 그 안에 우리 기지로 통하는 텔레포터가 있으니 그걸 타.,"De deur naast de wapenwinkel gaat open als alle kruisvaarders dood zijn. In de opslagruimte staat een teleporter, gebruik die, en die brengt je naar ons toe.","Døren ved siden av våpenbutikken åpnes når alle korsfarerne er døde. Inne i lagerrommet er det en teleporter, bruk den, og den vil føre deg til oss...","Drzwi obok sklepu z bronią otworzą się, gdy wszyscy krzyżowcy będą martwi. Wewnątrz pomieszczenia ze sklepem jest teleporter, użyj go, a zaprowadzi cię do nas",A porta próxima à loja de armas abrirá assim que todos os Cruzados estiverem mortos. Dentro do depósito tem um teletransportador. Entre nele e ele o levará até nós.,,"Ușa de lângă magazinul de arme se va deschide odată ce toți Cruciații sunt morți. Înăuntru e un teleportor, ia-l, te va duce la noi.","Дверь возле оружейного магазина откроется, когда все крестоносцы будут уничтожены. На складе ты найдёшь телепорт. Используй его — он доставит тебя к нам.",,"Dörren bredvid vapenbutiken öppnas när alla korsriddare är döda. Inne i butiksrummet finns det en teleporter, använd den och den för dig till oss.","Tüm Haçlılar öldüğünde silah dükkanının yanındaki kapı açılacak. Dükkanın içinde bir ışınlayıcı var, onu kullan ve seni bize getirecek" +"The door next to the weapons shop will open once all the Crusaders are dead. Inside the store room there's a teleporter, use it, and it'll bring you to us.",TXT_ILOG7,"MAP33: In front of ""Irale's shop"" with the com unit and the Crusaders alive.",strifeteaser,,"Dveře vedle obchodu se zbraněmi se otevřou když budou všichni Křižáci zničeni. Uvnitř je teleportér, použij ho a dostaneš se k nám.","Døren ved siden af våbenbutikken åbnes, når alle korsfarerne er døde. Inde i lagerrummet er der en teleporter, brug den, og den vil bringe dig til os.","Die Tür neben dem Waffengeschäft wird sich öffnen, wenn alle Ordensritter tot sind. Dahinter ist ein Teleporter. Benutze ihn, er bringt dich zu uns.",,Detrui la Krucistojn malfermos la pordon apud la armilvendejo. Estas teleportilo en tiu stokejo; uzu ĝin.,La puerta junto a la armería se abrirá al matar a los cruzados. Dentro de ese almacén hay un teletransporte; úsalo.,La puerta junto a la armería se va a abrir al matar a los cruzados. Adentro de ese almacén hay un teletransporte; úsalo.,"Asekaupan viereinen ovi aukeaa, kun kaikki ristiretkeläiset on tuhottu. Varastohuoneessa on kaukosiirrin. Sitä käyttämällä pääset luoksemme.","La porte à côté du magasin d'armes s'ouvrira quand tous les croisés seront détruits. A l'intérieur de la salle de stockage se trouve un téléporteur, utilise-le pour nous rejoindre.","A fegyverbolt melletti ajtó ki fog nyílni, miután az összes Kresztes meghalt. Találsz a raktáron belül egy teleportot, ami ide fog hozni hozzánk.","La porta accanto al negozio delle armi si aprirà non appena tutti i Crociati sono distrutti. Oltre quella porta c'è un teletrasporto, usalo e ti porterà da noi.","私が知事について知っていることは、町の中央で双方を遊ばせてる様だ。 +ソイツがここいらを'マンション'と呼んでいる。",크루세이더들을 전부 처리하면 무기상 옆의 문이 열릴 거야. 그 안에 우리 기지로 통하는 텔레포터가 있으니 그걸 타.,"De deur naast de wapenwinkel gaat open als alle kruisvaarders dood zijn. In de opslagruimte staat een teleporter, gebruik die, en die brengt je naar ons toe.","Døren ved siden av våpenbutikken åpnes når alle korsfarerne er døde. Inne i lagerrommet er det en teleporter, bruk den, og den vil bringe deg til oss.","Drzwi obok sklepu z bronią otworzą się po śmierci wszystkich krzyżowców. Wewnątrz pomieszczenia sklepowego znajduje się teleporter, użyj go, a przeniesie cię do nas.",A porta próxima à loja de armas abrirá assim que todos os Cruzados estiverem mortos. Dentro do depósito tem um teletransportador. Entre nele e ele o levará até nós.,,"Ușa de lângă magazinul de arme se va deschide odată ce toți Cruciații sunt morți. Înăuntru e un teleportor, ia-l, te va duce la noi.","Дверь возле оружейного магазина откроется, когда все крестоносцы будут уничтожены. На складе ты найдёшь телепорт. Используй его — он доставит тебя к нам.",,"Dörren bredvid vapenbutiken öppnas när alla korsfarare är döda. Inne i butiksrummet finns en teleporter, använd den och den tar dig till oss.","Tüm Haçlılar öldüğünde silah dükkanının yanındaki kapı açılacak. Dükkanın içinde bir ışınlayıcı var, onu kullanın ve sizi bize getirecek." +"Kill as many of the big robots, Crusaders, as you can. When you're done, I'll guide you to Macil",TXT_ILOG8,MAP33: Room with the flamethrower.,strifeteaser,,"Znič tolik těch velkých robotů, Křižáků, kolik dokážeš. Až budeš hotov, dovedu tě k Macilovi.","Dræb så mange af de store robotter, korsfarerne, som du kan. Når du er færdig, vil jeg guide dig til Macil","Erledige so viele von den großen Robotern - „Ordensrittern“, wie möglich. Wann das erledigt ist, führe ich dich zu Macil.",,"Detruu tiom da robotegoj, alinome Krucistoj, kiom vi povas. Tiam mi gvidos vin al Macil.","Mata a tantos de los robots grandes, o sea, a los Cruzados, como puedas. Cuando termines, te guiaré hasta Macil.","Mata a tantos de los robots grandes, o sea, a los Cruzados, como puedas. Cuando termines, te guío hasta Macil.","Tuhoa jättiroboteista, ristiretkeläisistä, niin monta kuin pystyt. Kun olet valmis, opastan sinut Macilin luokse.","Détruis autant des gros robots, les croisés, que tu peux, et je te mènerai à Macil.","Ölj meg annyi nagy robotot és keresztest amennyit csak tudsz. Ha kész vagy, elvezetlek Macilhoz.","Distruggi tutti i Crociati che vedi. Non appena hai finito, ti condurrò da Macil.",,"저 거대한 '크루세이더' 로봇들을 최대한 처리해. 상황이 정리되면, 내가 너를 마실에게 데려다줄게.","Dood zoveel mogelijk van de grote robots, kruisvaarders, als je kunt. Als je klaar bent, begeleid ik je naar Macil...","Drep så mange av de store robotene, korsfarerne, som du kan. Når du er ferdig, skal jeg vise deg veien til Macil.","Zabij jak najwięcej dużych robotów, ""krzyżowców"", jak tylko możesz. Gdy skończysz, zaprowadzę cię do Macila","Mate o máximo desses robos possível. Quando terminar, eu te guiarei ao Macil.",,"Distruge cât mai mulți roboți, Cruciați, pe cât poți. Când ești gata, te voi duce la Macil.","Убей столько больших роботов, — крестоносцев, — сколько сможешь. Когда закончишь, я приведу тебя к Мэйсилу.",,"Döda så många av de stora robotarna, korsriddarna, som du kan. När du är klar kommer jag att guida dig till Macil.","Büyük robotlardan, Haçlılardan, öldürebildiğin kadarını öldür. İşiniz bittiğinde, sizi Macil'e götüreceğim." +"Go through the door, and talk to Macil.",TXT_ILOG9,MAP34: After leaving the teleporter.,strifeteaser,,Projdi dveřmi a promluv si s Macilem.,"Gå gennem døren, og tal med Macil.",Geh durch die Tür und rede mit Macil.,,Iru tra la pordo kaj parolu kun Macil.,Ve por la puerta y habla con Macil.,,Kulje ovesta ja puhu Macilille.,Traverse cette porte et va parler à Macil.,"Az ajtó mögött már vár Macil, beszélj vele.","Attraversa la porta, e vai a parlare con Macil.",ダーウィンを始末したら耳を知事に渡す。,저 문을 지나서 마실하고 대화를 해봐.,"Ga door de deur, en praat met Macil.",Gå gjennom døren og snakk med Macil.,Przejdź przez drzwi i porozmawiaj z Macil.,Passe pela porta e fale com o Macil.,,Intră pe ușă și du-te la Macil.,Обратись к Мэйсилу. Он за этой дверью.,,Gå in genom dörren och prata med Macil.,Kapıdan geçin ve Macil ile konuşun. +"Find the power tap on the mains, and shut it off. Bring something back to the Governor as proof. Find MacGuffin, and talk to him.",TXT_ILOG10,"MAP02: After accepting ""messy"" chore and leaving Mourel's room.",,,Najdi stáčedlo energie na elektrické síti a vypni jej. Přines něco guvernérovi jako důkaz. Najdi MacGuffina a promluv s ním.,"Find strømhanen på hovedledningen, og luk den. Tag noget med tilbage til guvernøren som bevis. Find MacGuffin, og tal med ham.",Finde die Stromanzapfung und schalte sie ab. Bringe einen Beweis zum Gouverneur. Finde MacGuffin und rede mit ihm. ,,"Trovu la konektilon en la elektriza sistemo, detruu ĝin kaj portu pruvon al la registo. Konsilo: Trovu Makgufinon kaj parolu kun li.","Encuentra la toma en la red eléctrica, destrúyela y llévale algo al gobernador como prueba. Para eso encuentra a MacGuffin y habla con él.",,Etsi verkkovirran piilokytkentä ja katkaise se. Tuo kuvernöörille jotain todisteeksi. Etsi MacGuffin ja puhu hänen kanssaan.,Trouve la connection pirate sur le transformateur et désactive la. Amène quelque chose au gouverneur comme preuve. Trouve MacGuffin et parle-lui.,"Keresd meg a fővonalon az áramkapcsolót, és kapcsold ki. Hozz vissza valamit a kormányzótól bizonyítékként. Keresd meg MacGuffint, és beszélj vele.","Trova l'aggeggio che sta venendo usato per rubare energia alla rete, e distruggilo. Porta dei resti al governatore come prova. Trova e parla con MacGuffin.","電力盗用の場所を見つけ、それを止める。 +知事に渡す証拠も必要だ。マクガフィンと話をつける。",주 동력선 어딘가에 있는 추출기를 처리해. 총독에게 전할 증거물도 챙기고. 맥거핀을 찾아서 대화해 봐.,Zoek het stopcontact op het lichtnet en zet het uit. Breng iets terug naar de gouverneur als bewijs. Zoek MacGuffin en praat met hem.,"Finn strømkranen på strømnettet, og slå den av. Ta med noe tilbake til guvernøren som bevis. Finn MacGuffin, og snakk med ham.",Znajdź kurek z prądem w sieci i wyłącz go. Przynieś coś gubernatorowi jako dowód. Znajdź MacGuffina i porozmawiaj z nim.,Encontre a ligação pirata no transformador e desligue ela. Traga algo de volta para o Governador como prova. Encontre o MacGuffin e fale com ele.,,"Găsește comutatorul de energie, și oprește-l. Du ceva înapoi la Guvernator drept dovadă. Găsește-l pe MacGuffin, și vorbește cu el.",Найди нелегальное подключение к линии электропередачи и выведи его из строя. Принеси что-нибудь губернатору в качестве доказательства. Найди Макгаффина и поговори с ним.,,Leta reda på strömkranen på elnätet och stäng av den. Ta med dig något tillbaka till guvernören som bevis. Hitta MacGuffin och prata med honom.,Şebekedeki güç musluğunu bulun ve kapatın. Kanıt olarak Vali'ye bir şey getirin. MacGuffin'i bul ve onunla konuş. +"Find the power tap on the mains, and shut it off. Bring something back to the Governor as proof. Find MacGuffin, and talk to him. He's up by the sewage treatment plant, in the ""bum hole"", down the stairs.",TXT_ILOG11,"MAP02: After accepting ""messy"" chore and leaving Mourel's mansion.",,,"Najdi stáčedlo energie na elektrické síti a vypni jej. Přines něco guvernérovi jako důkaz. Najdi MacGuffina a promluv s ním. Je u čističky, v „zadnici“ pod schody.","Find strømhanen på hovedledningen, og luk den. Tag noget med tilbage til guvernøren som bevis. Find MacGuffin, og tal med ham. Han er oppe ved rensningsanlægget, i ""bum-hullet"", nede ad trappen.","Finde die Stromanzapfung und schalte sie ab. Bringe einen Beweis zum Gouverneur. Finde MacGuffin und rede mit ihm. Er ist in der Nähe der Kläranlage im „Pennerloch“, die Treppe runter.",,"Trovu la konektilon en la elektriza sistemo, detruu ĝin kaj portu pruvon al la registo. Konsilo: Trovu Makgufinon kaj parolu kun li. Li estas malsupre laŭ ŝtuparo en «la groto de la vagulo» en la purigejo de kloaka akvo.","Encuentra la toma en la red eléctrica, destrúyela y llévale algo al gobernador como prueba. Para eso encuentra a MacGuffin y habla con él. Está donde se depuran las aguas residuales en «la cueva del vagabundo» bajando unas escaleras.",,"Etsi verkkovirran piilokytkentä ja katkaise se. Tuo kuvernöörille jotain todisteeksi. Etsi MacGuffin ja puhu hänen kanssaan. Hän majailee jätelaitoksella ""pepunreiässä"" rappuset alas.","Trouve la connection pirate sur le transformateur et désactive la. Amène quelque chose au gouverneur comme preuve. Trouve MacGuffin et parle-lui. Il se trouve dans la centrale de traitement des eaux, dans le « trou à rats » en bas des escaliers.","Keresd meg a fővonalon az áramkapcsolót, és kapcsold ki. Hozz vissza valamit a kormányzótól bizonyítékként. Keresd fel MacGuffint és beszélj vele. Ott van a szennyvíz tisztítónál, ha lemész a lépcsőn, lent a ""kotorékban"".","Trova il marchingegno che sta venendo usato per rubare energia alla rete, e distruggilo. Porta dei resti al governatore come prova. Trova e parla con MacGuffin. Lui bazzica dalle parti dell'impianto fognario, oltre delle scale.","電力盗用の場所を見つけ、それを止める。 知事に渡す証拠も必要だ。マクガフィンと話をつける。 -彼は下水処理場の傍にある'物乞いの巣'と呼ばれる場所にいる。",주 동력선 어딘가에 있는 추출기를 처리해. 총독에게 전할 증거물도 챙기고. 맥거핀을 찾아서 대화해 봐. 그는 하수처리장 근처 계단 밑 개구멍에 있어.,"Zoek het stopcontact op het lichtnet en zet het uit. Breng iets terug naar de gouverneur als bewijs. Zoek MacGuffin en praat met hem. Hij is boven bij de rioolwaterzuiveringsinstallatie, in het ""zwerfgat"", de trap af.",,"Encontre a ligação pirata no transformador e desligue ela. Traga algo de volta para o Governador como prova. Encontre o MacGuffin e fale com ele. Ele está na usina de tratamento, na ""toca de rato"" descendo as escadas.",,,"Найди нелегальное подключение к линии электропередачи и выведи его из строя. Принеси что-нибудь губернатору в качестве доказательства. Найди МакГаффина и поговори с ним. Он возле очистного сооружения, в «бомжевой норе», вниз по лестнице.", -"You idiot! You've shut off the power to the jamming circuits we use to conceal our base from the Order. Head to the town hall and take out the scanning crew, now! Then, go back to the Governor and give him the broken coupling.",TXT_ILOG13,,,,"Ty debile! Odstřihnul jsi přívod proudu do rušiček, které používáme, abychom ukryli naší základnu před Řádem. Okamžitě si to zamiř k radnici a vybij průzkumnou četu! Pak se vrať ke guvernérovi a dej mu rozbitou spojku.","Du Idiot! Du hast die Energie für unsere Störsender unterbrochen, mit denen wir unsere Basis vor dem Orden verborgen haben. Geh schnell zum Rathaus und schalte den Suchtrupp aus. Geh danach zum Gouverneur und gib ihm den zerstörten Stromabnehmer.",,,"¡Idiota! Has apagado la energía a los circuitos de interferencia que usamos para ocultar nuestra base a la Orden. Dirígete al ayuntamiento y elimina al equipo de escaneo, ¡ahora! Luego, vuelve con el gobernador y dale el acoplador roto.","¡Idiota! Quitaste la energía a los circuitos de interferencia que utilizamos para que la Orden no vea nuestra base. Dirígete al ayuntamiento y saca al equipo de escaneo. Luego, ve con el gobernador y dale el acoplador roto.",,Idiot! Tu as désactivé les circuits brouilleurs qui cachaient notre base des senseurs de l'Ordre. Retourne vite à la mairie et tue l'équipe de scan maintenant! Retourne ensuite au gouverneur et donne lui le coupleur cassé.,,,"馬鹿者! お前はオーダーから我々の基地を隠す妨害回路を +彼は下水処理場の傍にある'物乞いの巣'と呼ばれる場所にいる。",주 동력선 어딘가에 있는 추출기를 처리해. 총독에게 전할 증거물도 챙기고. 맥거핀을 찾아서 대화해 봐. 그는 하수처리장 근처 계단 밑 개구멍에 있어.,"Zoek het stopcontact op het lichtnet en zet het uit. Breng iets terug naar de gouverneur als bewijs. Zoek MacGuffin en praat met hem. Hij is boven bij de rioolwaterzuiveringsinstallatie, in het ""zwerfgat"", de trap af.","Finn strømbryteren på strømnettet, og slå den av. Ta med noe tilbake til guvernøren som bevis. Finn MacGuffin og snakk med ham. Han er oppe ved kloakkrenseanlegget, i ""rumpehullet"", ned trappen.","Znajdź kurek z prądem w sieci i wyłącz go. Zanieś coś gubernatorowi jako dowód. Znajdź MacGuffina i porozmawiaj z nim. Jest przy oczyszczalni ścieków, w ""dziurze"", po schodach.","Encontre a ligação pirata no transformador e desligue ela. Traga algo de volta para o Governador como prova. Encontre o MacGuffin e fale com ele. Ele está na usina de tratamento, na ""toca de rato"" descendo as escadas.",,"Găsește comutatorul de energie, și oprește-l. Du ceva înapoi la Guvernator drept dovadă. Găsește-l pe MacGuffin, și vorbește cu el, e lângă fabrica de tratament, în josul scărilor.","Найди нелегальное подключение к линии электропередачи и выведи его из строя. Принеси что-нибудь губернатору в качестве доказательства. Найди Макгаффина и поговори с ним. Он возле очистного сооружения, в «бомжевой норе», вниз по лестнице.",,"Leta reda på eluttaget på elnätet och stäng av det. Ta med dig något tillbaka till guvernören som bevis. Hitta MacGuffin och prata med honom. Han är uppe vid reningsverket, i ""bum-hålet"", nerför trappan.","Şebekedeki güç musluğunu bulun ve kapatın. Kanıt olarak Vali'ye bir şey getir. MacGuffin'i bul ve onunla konuş. Kanalizasyon arıtma tesisinin yanında, merdivenlerin aşağısındaki ""serseri deliğinde""." +"You idiot! You've shut off the power to the jamming circuits we use to conceal our base from the Order. Head to the town hall and take out the scanning crew, now! Then, go back to the Governor and give him the broken coupling.",TXT_ILOG13,MAP02: After destroying Front's power coupling.,,,"Ty debile! Odstřihnul jsi přívod proudu do rušiček, které používáme, abychom ukryli naší základnu před Řádem. Okamžitě si to zamiř k radnici a vybij průzkumnou četu! Pak se vrať ke guvernérovi a dej mu rozbitou spojku.","Din idiot! Du har slukket for strømmen til de støjkredsløb, som vi bruger til at skjule vores base for Ordenen. Gå hen til rådhuset og udryd scanningsholdet, nu! Gå derefter tilbage til guvernøren og giv ham den ødelagte kobling.","Du Idiot! Du hast die Energie für unsere Störsender unterbrochen, mit denen wir unsere Basis vor dem Orden verborgen haben. Geh schnell zum Rathaus und schalte den Suchtrupp aus. Geh danach zum Gouverneur und gib ihm den zerstörten Stromabnehmer.",,"Vi rompis la kuplilon, kiu kaŝis nian bazon de La Ordeno. Reiru al la urbodomo kaj mortigu la skoltojn. Tiam reiru ĉe la registo kaj donu al li la kuplilon, kiun vi rompis.",Has roto el acoplador que le ocultaba nuestra base a La Orden. Dirígete al ayuntamiento y elimina a la tropa de reconocimiento. Luego vuelve con el gobernador y dale el acoplador que has roto.,Rompiste el acoplador que le ocultaba nuestra base a La Orden. Dirígete al ayuntamiento y elimina a la tropa de reconocimiento. Luego vuelve con el gobernador y dale el acoplador que rompiste.,"Sinä idiootti! Olet katkaissut virran häirintäpiireihin, joilla piilotamme sijaintimme Veljeskunnalta. Suuntaa kaupungintalolle ja hoitele tiedusteluryhmä, heti paikalla! Palaa sitten kuvernöörin luo ja anna rikkinäinen virtaliitin hänelle.",Idiot! Tu as désactivé les circuits brouilleurs qui cachaient notre base des senseurs de l'Ordre. Retourne vite à la mairie et tue l'équipe de scan maintenant! Retourne ensuite au gouverneur et donne lui le coupleur cassé.,"Te idióta! Leállítottad a zavaró áramellátását, amivel lerejtjük magunkat a Rend elől. Menj azonnal a városházára, és iktasd ki a felderítő brigádot! Aztán menj vissza a kormányzóhoz, és add át az elrontott kapcsolóművet.","Idiota! Hai interrotto il flusso di energia dei circuiti che usavamo per nascondere la nostra base dall'Ordine. Ritorna subito al municipio e fai fuori il gruppo venuto a perlustare la zona, ora! Poi, torna dal governatore e dagli questo pezzo di ferraglia.","馬鹿者! お前はオーダーから我々の基地を隠す妨害回路を 壊してしまった!市庁舎に調査隊が向かった、今すぐ片付けろ! -",이 멍청이야! 우리 기지를 오더로부터 은폐시켜주는 교란 장치의 동력을 끊어버렸잖아. 당장 시청으로 가서 탐색반들을 쓸어버려! 그다음에 총독에게 부서진 장치를 전해줘.,Idioot! Je hebt de stroom naar de stoorcircuits die we gebruiken om onze basis te verbergen voor de orde uitgeschakeld. Ga naar het stadhuis en haal de scanploeg er nu uit! Ga dan terug naar de Gouverneur en geef hem de kapotte koppeling.,,Seu idiota! Você desligou a energia para os circuitos de interferência que usamos para esconder a nossa base dos sensores da Ordem. Vá até a prefeitura e tire a equipe de busca de lá imediatamente! Depois disso volte para o Governador e passe pra ele a conexão quebrada.,,,"Идиот! Ты обесточил генератор радиопомех, с помощью которого мы скрывали местоположение нашей базы от Ордена. Возвращайся к ратуше и уничтожь разведывательную группу как можно скорее! Затем вернись к губернатору и отдай ему повреждённую муфту.", -"OK, ""Trust no one"" is the name of the game! Let's get that prison pass from the Governor. Take the broken coupling to him.",TXT_ILOG14,,,,"Dobře, „Nevěř nikomu“ je motto hry! Pojďme od guvernéra dostat tu propustku a osvoboďme ty vězně. Přines mu rozbitou spojku.","Ok, „Trau keinem“ heißt dieses Spiel. Lass uns den Gefängnispass vom Gouverneur holen. Bring ihm den Stromabnehmer.",,,"OK, ¡'no te fies de nadie' es el nombre del juego! Consigamos ese pase de la prisión del gobernador. Llévale el acoplador roto.","OK, ¡'no confíes en nadie' es el nombre del juego! Consigamos ese pase de la prision del gobernador. Llévale el acoplador roto.",,"Ok, « ne fais confiance à personne » est notre nouveau slogan. On va récupérer le passe de la prison chez le gouverneur. Amène lui le coupleur cassé.",,,"よし、'信用しない'のが最も重要なことだ! -壊れた配電機を渡して刑務所の許可証を知事から貰うんだ。","좋아, '아무도 믿지 말라'가 이 게임의 이름이겠군! 어서 총독에게 감옥 통행증이나 받자. 이 부서진 장치를 그에게 전해줘.","OK, ""Vertrouw niemand"" is de naam van het spel! Laten we die gevangenispas van de Gouverneur halen. Pak de kapotte koppeling naar hem toe.",,"Ok, ""não confie em ninguém"" é o nome do jogo! Vamos pegar do Governador aquele passe da prisão. Leve a conexão quebrada a ele.",,,"Что ж, эта игра называется «не верь никому»! Давай получим у губернатора пропуск в тюрьму. Отнеси ему повреждённую муфту.", -Good move! The Governor is a liar. That's our power coupling. We're using it to hide the base from the Order. Take this broken coupling back to him and let's get that pass.,TXT_ILOG15,,,,"Dobrý tah! Guvernér je lhář, tohle je naše spojka. Používáme ji k ukrytí základny před Řádem. Přines mu tuhle rozbitou spojku a vezmi si od něj tu propustku.",Das war klasse! Der Gouverneur ist ein verdammter Lügner. Das war unsere Anzapfung. Wir benutzen sie um unsere Basis vor dem Orden zu verstecken. Und nun bring ihm den Stromabnehmer und hol den Gefängnispass.,,,¡Buen paso! El gobernador es un mentiroso. Ese es nuestro acoplador de energía. Lo estamos usando para ocultar nuestra base a la Orden. Llévale de vuelta este acoplador roto y consigamos ese pase.,¡Buena movida! El gobernador es un mentiroso. Ese es nuestro acoplador de energía. Lo estamos utilizando para esconder nuestra base de la Orden. Llévale este acoplador roto y consigamos ese pase.,,Bonne idée! Le gouverneur est un menteur. Voilà notre coupleur. On l'utilise pour dissimuler notre présence à l'Ordre. Amène ce coupleur cassé à lui et récupère le passe.,,,"良い判断だ! 知事は嘘を付いている。 +",이 멍청이야! 우리 기지를 오더로부터 은폐시켜주는 교란 장치의 동력을 끊어버렸잖아. 당장 시청으로 가서 탐색반들을 쓸어버려! 그다음에 총독에게 부서진 장치를 전해줘.,Idioot! Je hebt de stroom naar de stoorcircuits die we gebruiken om onze basis te verbergen voor de orde uitgeschakeld. Ga naar het stadhuis en haal de scanploeg er nu uit! Ga dan terug naar de Gouverneur en geef hem de kapotte koppeling.,"Din idiot! Du har slått av strømmen til blokkeringskretsene vi bruker for å skjule basen vår for Ordenen. Dra til rådhuset og drep skannermannskapet, nå! Gå tilbake til guvernøren og gi ham den ødelagte koblingen.","Ty idioto! Wyłączyłeś zasilanie obwodów zagłuszających, których używamy do ukrycia naszej bazy przed Zakonem. Idź do ratusza i zlikwiduj ekipę skanującą, natychmiast! Potem wróć do gubernatora i daj mu zepsute złącze.",Seu idiota! Você desligou a energia para os circuitos de interferência que usamos para esconder a nossa base dos sensores da Ordem. Vá até a prefeitura e tire a equipe de busca de lá imediatamente! Depois disso volte para o Governador e passe pra ele a conexão quebrada.,,"Idiotule! Ai oprit curentul circuitelor noastre care ne mascau prezența. Du-te în hala orașului și elimină echipajul! Apoi, du-te la Guvernator și dă-i cuplajul!","Идиот! Ты обесточил генератор радиопомех, с помощью которого мы скрывали местоположение нашей базы от Ордена. Возвращайся к ратуше и уничтожь разведывательную группу как можно скорее! Затем вернись к губернатору и отдай ему повреждённую муфту.",,"Din idiot! Du har stängt av strömmen till de störningskretsar som vi använder för att dölja vår bas för Orden. Gå till stadshuset och ta ut skanningspersonalen, nu! Gå sedan tillbaka till guvernören och ge honom den trasiga kopplingen.","Seni aptal! Üssümüzü Tarikat'tan gizlemek için kullandığımız sinyal bozucu devrelerin gücünü kestin. Belediye binasına git ve tarama ekibini yok et, hemen! Sonra Vali'ye geri dön ve ona kırık bağlantıyı ver." +"OK, ""Trust no one"" is the name of the game! Let's get that prison pass from the Governor. Take the broken coupling to him.",TXT_ILOG14,MAP02: After destroying Front's power coupling and killing all blue acolytes in the town hall.,,,"Dobře, „Nevěř nikomu“ je motto hry! Pojďme od guvernéra dostat tu propustku a osvoboďme ty vězně. Přines mu rozbitou spojku.","Okay, ""Stol ikke på nogen"" er spillets navn! Lad os få det fængselskort fra guvernøren. Tag den ødelagte kobling med til ham.","Ok, „Trau keinem“ heißt dieses Spiel. Lass uns den Gefängnispass vom Gouverneur holen. Bring ihm den Stromabnehmer.",,"Bone, la ludo estas «Fidu neniun»! Ni akiru la enirpermeson al la malliberejo: donu la rompitan kuplilon al la registo.","Vale, ¡«No te fies de nadie» se llama el juego! Ya es hora de conseguir el pase a la prisión: llévale el acoplador roto al gobernador.","Bueno, ¡«No confíes en nadie» se llama el juego! Ya es hora de conseguir el pase a la prisión: llévale el acoplador roto al gobernador.","Selvä, ""Älä luota kehenkään"" on näköjään pelin nimi! Hankitaan vankilan pääsylupa kuvernööriltä. Vie rikkinäinen virtaliitin hänelle.","Ok, « ne fais confiance à personne » est notre nouveau slogan. On va récupérer le passe de la prison chez le gouverneur. Amène lui le coupleur cassé.","Készülj fel, hogy senkiben sem bízhatsz. Gyerünk, szerezzük meg a kormányzótól a börtön belépőt. Vidd el hozzá az elrontott kapcsolóművet.","OK, ""Non fidarti di nessuno"" è il gioco che stiamo giocando qua! Prendiamo quel pass per la prigione dal governatore. Portagli quel pezzo di ferraglia.","よし、'信用しない'のが最も重要なことだ! +壊れた配電機を渡して刑務所の許可証を知事から貰うんだ。","좋아, '아무도 믿지 말라'가 이 게임의 이름이겠군! 어서 총독에게 감옥 통행증이나 받자. 이 부서진 장치를 그에게 전해줘.","OK, ""Vertrouw niemand"" is de naam van het spel! Laten we die gevangenispas van de Gouverneur halen. Pak de kapotte koppeling naar hem toe.","OK, ""Stol ikke på noen"" er navnet på spillet! La oss få fengselspasset fra guvernøren. Gi ham den ødelagte koblingen.","OK, ""Nie ufaj nikomu"" to nazwa gry! Zdobądźmy tę przepustkę od Gubernatora. Zanieś mu zepsute złącze.","Ok, ""não confie em ninguém"" é o nome do jogo! Vamos pegar do Governador aquele passe da prisão. Leve a conexão quebrada a ele.",,"OK, 'Încrede-te în nimeni' e numele jocului. Să luam permisul închisorii de la Guvernator. Ia cuplajul defect și du-l lui.","Что ж, эта игра называется «не верь никому»! Давай получим у губернатора пропуск в тюрьму. Отнеси ему повреждённую муфту.",,"Okej, ""Lita inte på någon"" är vad som gäller! Låt oss få fängelsepasset från guvernören. Ta den trasiga kopplingen till honom.","Tamam, ""Kimseye güvenme"" oyunun adı! Vali'den şu hapishane kartını alalım. Kırık bağlantıyı ona götür." +Good move! The Governor is a liar. That's our power coupling. We're using it to hide the base from the Order. Take this broken coupling back to him and let's get that pass.,TXT_ILOG15,MAP02: After finding the broken power coupling.,,,"Dobrý tah! Guvernér je lhář, tohle je naše spojka. Používáme ji k ukrytí základny před Řádem. Přines mu tuhle rozbitou spojku a vezmi si od něj tu propustku.","Godt træk! Guvernøren er en løgner. Det er vores kraftkobling. Vi bruger den til at skjule basen for Ordenen. Tag den ødelagte kobling med tilbage til ham, og lad os få det pas.",Das war klasse! Der Gouverneur ist ein verdammter Lügner. Das war unsere Anzapfung. Wir benutzen sie um unsere Basis vor dem Orden zu verstecken. Und nun bring ihm den Stromabnehmer und hol den Gefängnispass.,,"La registo estas mensogema: tiu estis la kuplilo, kiu kaŝas nian bazon de La Ordeno. Donu al li la rompitan kuplilon por akiri la enirpermeson.",El gobernador es un mentiroso: ese era el acoplador de energía que le oculta nuestra base a La Orden. Llévale el acoplador roto para conseguir ese pase.,,"Hyvä veto! Kuvernööri on valehtelija. Se on meidän virtaliittimemme. Käytämme sitä piillottamaan tukikohtamme Veljeskunnalta. Toimita tämä rikkinäinen virtaliitin takaisin hänelle, ja hankitaan se pääsylupa.",Bonne idée! Le gouverneur est un menteur. Voilà notre coupleur. On l'utilise pour dissimuler notre présence à l'Ordre. Amène ce coupleur cassé à lui et récupère le passe.,"Ügyes lépés! A kormányzó egy hazug senkiházi. Ez a mi kapcsolóművünk. Arra használjuk, hogy elrejtsük a bázisunkat a Rend elől. Vidd vissza neki a tönkrevágott kapcsolóművet, és irány megszerezni a belépőt.","Ottima mossa! Il governatore è un bugiardo. Eravamo noi a utilizzare questo marchingegno collegato alla rete. Lo stiamo usando per nascondere la posizione della nostra base dall'Ordine. Prendi quest'altro rotto e vecchio e portalo da lui, e prendiamoci quel pass.","良い判断だ! 知事は嘘を付いている。 あれはオーダーから基地を隠す為に使用している我々の配電機だ。 -この壊れた配電機を渡して奴を騙し返せ。",참 잘했어! 총독이 거짓말을 했군. 이건 우리의 동력 장치야. 이걸 써서 우리 기지를 오더로부터 은폐시켜주지. 여기 있는 고장 난 장치를 전해주고 통행증이나 받자.,Goede zet! De Gouverneur is een leugenaar. Dat is onze stroomkoppeling. We gebruiken het om de basis te verbergen voor de Orde. Neem deze kapotte koppeling terug naar hem en laten we die pass pakken.,,Boa! O Governador é um mentiroso . Essa é a nossa conexão. Vamos usá-la para esconder a base da Ordem. Leve esta conexão danificada de volta a ele e vamos pegar o passe.,,,"Отличный ход! Губернатор — лжец. Это наше подключение к силовой линии. Мы используем его, чтобы скрывать местоположение нашей базы от Ордена. Отнеси повреждённую муфту губернатору и получи пропуск.", -Use the Warden's key to get into the prison cell blocks and find a way to free the prisoners.,TXT_ILOG18,,,,"Použij dozorcův klíč k dostání se do bloku s celami a najdi způsob, jak osvobodit vězně.","Benutze den Schlüssel des Direktors um in die Zellenblöcke zu kommen und finde heraus, wie man die Gefangenen befreien kann.",,,Usa la llave del Carcelero para entrar en los bloques de celdas y encuentra una forma de liberar a los prisioneros.,Usa la llave del Director para entrar a los bloques de celdas y encontrar una manera de liberar a los prisioneros.,,Utilise la clé du gardien pour entrer dans le bloc de cellules et trouver une manière de libérer les prisonniers.,,,"ワーデンの鍵で刑務所の独房区域に入って -囚人を解放する方法を見つける。","간수장의 열쇠를 써서 감옥 안으로 진입하고, 수감자들을 풀어줄 방법을 찾아봐.",Gebruik de sleutel van de bewaker om in de celblokken van de gevangenis te komen en een manier te vinden om de gevangenen te bevrijden.,,Use a chave do Carcereiro para entrar nos blocos de celas e ache uma maneira de libertar os prisioneiros.,,,"Используй ключ тюремщика, чтобы пройти к камерам. Найди способ освободить пленников.", -Find a way to free the prisoners. Find a way to open the hand scanner switch.,TXT_ILOG19,,,,"Najdi způsob, jak osvobodit vězně. Najdi způsob, jak aktivovat skener otisků ruky.","Finde heraus, wie man die Gefangenen befreien kann und wie du den Handscanner umgehen kannst.",,,Encuentra una forma de liberar a los prisioneros. Encuentra una forma de abrir el interruptor de escáner de mano.,Encuentra una manera de liberar a los prisioneros. Encuentra una forma de abrir el switch de escaneo de manos.,,Trouve un moyen de libérer les prisonniers. Trouve une manière d'activer le scanner à empreinte digitale.,,,"囚人を解放する方法を見つける。 - ハンドスキャナーを開く方法を見つける。",수감자들을 풀어줄 방법을 찾자. 지문인식장치를 통과할 방법을 찾아봐.,Zoek een manier om de gevangenen te bevrijden. Zoek een manier om de handscanner schakelaar te openen.,,Encontre uma maneira de libertar os prisioneiros. Ache uma maneira de abrir o scanner de mão.,,,Найди способ освободить пленников. Найди способ открыть замок со сканером отпечатка руки., -Find a way to free the prisoners. Use the judge's hand to operate the hand scanner switch.,TXT_ILOG20,,,,"Najdi způsob, jak osvobodit vězně. Použij soudcovu ruku k aktivaci skeneru otisků ruky.","Finde heraus, wie man die Gefangenen befreien kann. Benutze die Hand des Richters um den Handscannerschalter zu betätigen.",,,Encuentra una forma de liberar a los prisioneros. Usa la mano del juez para operar el interruptor de escáner de mano.,Encuentra una manera de liberar a los prisioneros. Utiliza la mano del juez para operar el switch de escaneo de manos.,,Trouve un moyen de libérer les prisonniers. Utilise la main du juge pour activer le scanner à empreinte digitale.,,,"囚人を解放する方法を見つける。 -裁判官の手を使用してハンドスキャナースイッチを操作する。",수감자들을 풀어줄 방법을 찾자. 판사의 손을 써서 지문인식장치를 통과하는 거야.,Zoek een manier om de gevangenen te bevrijden. Gebruik de hand van de rechter om de handscanner schakelaar te bedienen.,,Encontre uma maneira de libertar os prisioneiros. Use a mão do juiz para operar o scanner.,,,"Найди способ освободить пленников. Используй руку судьи, чтобы открыть замок со сканером отпечатка руки.", -Way to go my friend. Good work freeing the prisoners. Jump on one of the teleporters and it will bring you back to base.,TXT_ILOG21,,,,"Jen tak dál, příteli, dobrá práce. Skoč na teleportér, dostane tě to zpět na základnu.","Das war gute Arbeit, wie du die Gefangenen befreit hast. Benutze einen der Teleporter um zur Basis zurückzugelangen.",,,Así se hace amigo. Buen trabajo liberando a los prisioneros. Ponte en uno de los teletransportes y te traerá de vuelta a la base.,Que forma de avanzar amigo mío. Buen trabajo liberando a los prisioneros. Entra en alguno de los teleportes y te traerá de vuelta a la base.,,Bien joué mon ami! Bon travail avec ces prisonniers. Utilise l'un des téléporteurs pour revenir à la base.,,,"よくやった相棒。囚人を解放できたのは良い働きだ。 -いずれかのテレポーターに飛び込むと基地に戻る。","잘했어, 친구. 수감자들을 풀어주느라 고생했어. 저 텔레포터들 중 하나를 타면 우리 기지로 복귀할 수 있을 거야.","Goed gedaan, mijn vriend. Goed werk om de gevangenen te bevrijden. Spring op een van de teleporters en die brengt je terug naar de basis.",,"Boa, meu amigo. Bom trabalho ao libertar os prisioneiros. Entre num desses teletransportadores e você voltará pra base.",,,"Так держать, дружище. Ты отлично поработал и освободил пленников. Прыгай в любой телепорт, и он вернёт тебя на базу.", -"Destroy the power crystal that runs the power grid which drives the Order's shields. Go visit Worner, a spy we recruited in the warehouse of the power station.",TXT_ILOG22,,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Jdi navštívit Wornera, špióna, kterého jsme najali ve skladu elektrárny.","Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Suche Worner auf, einen Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben. ",,,"Destruye el cristal de poder que impulsa la red eléctrica que alimenta los escudos de la Orden. Ve a visitar a Worner, un espía que reclutamos en el almacén de la estación eléctrica.","Destruye el cristal de poder que impulsa la red eléctrica que abastece los escudos de la Orden. Visita a Worner, un espía que reclutamos en el almacén de la Estación Eléctrica.",,"Détruis le cristal qui contrôle la grille énergétique des boucliers de l'Ordre. Va voir Worner, un espion que l'on a recruté dans l'entrepôt de la centrale.",,,"送電網を動かしているパワークリスタルを破壊してオーダーのシールドを止めろ。 -発電所の倉庫に潜らせたスパイ、ワーナーを訪ねよ。","오더의 방어막을 유지하는 동력 망의 전력원인 수정체를 파괴하자. 우선, 발전소 창고에 있는 우리 쪽 첩자인 워너에게 찾아가 보자.","Vernietig het energiekristal dat het stroomnet dat de schilden van de Orde aandrijft. Ga op bezoek bij Worner, een spion die we gerekruteerd hebben in het magazijn van de centrale.",,"Destrua o cristal de energia que alimenta a rede elétrica por trás dos escudos da Ordem. Visite o Worner, um espião que recrutamos no depósito da usina de energia.",,,"Уничтожь кристалл, питающий энергосеть Ордена, от которой работают их щиты. Встреться с Уорнэром, нашим шпионом, на складе электростанции.", -Let's get lost. There's more fun to come.,TXT_ILOG24,,,,"Ztraťme se, za chvíli tu bude víc srandy.",Lass uns verschwinden. Hier wird's gleich ungemütlich.,,,Perdámonos. Hay más diversion por venir.,Vamos a perdernos. Aún hay más diversión por venir.,,"Partons d'ici, il y a encore de quoi s'amuser.",,,迷子になったら、もっと楽しめるぞ。,어서 여길 떠나자. 녀석들이 오기 전에 말이야.,Laten we verdwalen. Er komt nog meer plezier.,,Então se manda. Tem mais diversão por vir.,,,Давай-ка исчезнем отсюда. Скоро начнётся веселье., -"One more adventure before command feels it's safe to attack the castle. Macil's arranged for Irale to give you gold and some training. After you visit him, see the medic in town for strength.",TXT_ILOG25,,,,"Ještě jedno dobrodružství, než se velení rozhodne zaútočit. Macil sjednal u Iraleho zlato a trénink. Pak navštiv městského lékaře pro sílu.","Eine weitere Aufgabe noch, bevor Macil es für sicher hält, die Burg anzugreifen. Macil hat Irale gebeten, dir Gold zu geben und Training zu organisieren. Nachdem du bei ihm warst, lass dir vom Sanitäter in der Stadt deine Ausdauer erhöhen.",,,"Una aventura más antes de que el comando sienta que es seguro atacar el castillo. Macil ha acordado con Irale que te de oro y algo de entrenamiento. Despues de visitarlo, ve al médico en el pueblo para ganar fuerza.","Una aventura más antes de que el comando se sienta listo para atacar el castillo. Macil le dijo a Irale que te de algo de oro y entrenamiento. Después de visitarlo, ve al médico en el pueblo para obtener fuerza.",,"Encore une aventure avant que le commandement ne pense qu'il soit bon temps d'attaquer le château. Macil s'est arrangé pour qu'Irale te donne de l'argent et qu'il t'entraîne. Une fois que tu en as fini avec lui, va visiter le médecin en ville pour qu'il te rende des forces.",,,"もう一つの任務をこなす前に戦力の増強が必要と考えられる。 +この壊れた配電機を渡して奴を騙し返せ。",참 잘했어! 총독이 거짓말을 했군. 이건 우리의 동력 장치야. 이걸 써서 우리 기지를 오더로부터 은폐시켜주지. 여기 있는 고장 난 장치를 전해주고 통행증이나 받자.,Goede zet! De Gouverneur is een leugenaar. Dat is onze stroomkoppeling. We gebruiken het om de basis te verbergen voor de Orde. Neem deze kapotte koppeling terug naar hem en laten we die pass pakken.,Godt trekk! Guvernøren er en løgner. Det er kraftkoblingen vår. Vi bruker den til å skjule basen for Ordenen. Ta denne ødelagte koblingen tilbake til ham og la oss få det passet.,"Dobry ruch! Gubernator to kłamca. To jest nasze sprzęgło mocy. Używamy go, by ukryć bazę przed Zakonem. Zabierz mu to zepsute sprzęgło i zdobądźmy tę przepustkę.",Boa! O Governador é um mentiroso . Essa é a nossa conexão. Vamos usá-la para esconder a base da Ordem. Leve esta conexão danificada de volta a ele e vamos pegar o passe.,,"Bună mutare! Guvernatorul e un mincins. Acela e cuplajul nostru. Îl folosim pentru a ne ascunde baza de Ordin. Ia cuplajul ăsta defect și du-l înapoi lui, să luăm permisul.","Отличный ход! Губернатор — лжец. Это наше подключение к силовой линии. Мы используем его, чтобы скрывать местоположение нашей базы от Ордена. Отнеси повреждённую муфту губернатору и получи пропуск.",,Bra gjort! Guvernören är en lögnare. Det är vår kraftkoppling. Vi använder den för att dölja basen för orden. Ta tillbaka den trasiga kopplingen till honom och låt oss få det där passet.,İyi hamle! Vali bir yalancı. Bu bizim güç bağlantımız. Üssü Tarikat'tan saklamak için kullanıyoruz. Bu kırık bağlantıyı ona geri götür ve şu geçiş iznini alalım. +Use the Warden's key to get into the prison cell blocks and find a way to free the prisoners.,TXT_ILOG18,MAP05: After crossing the alarm green door.,,,"Použij dozorcův klíč k dostání se do bloku s celami a najdi způsob, jak osvobodit vězně.",Brug fængselsdirektørens nøgle til at komme ind i fængselscelleblokkene og find en måde at befri fangerne på.,"Benutze den Schlüssel des Direktors um in die Zellenblöcke zu kommen und finde heraus, wie man die Gefangenen befreien kann.",,Uzu la ŝlosilon de la provoso por atingi la ĉelaron kaj trovu manieron liberigi la kaptitojn.,Usa la llave del carcelero para llegar a la galería y encuentra una forma de liberar a los prisioneros.,,Käytä vankilanjohtajan avainta päästäksesi vankilan selliosastoille ja keksi keino vapauttaa vangit.,Utilise la clé du gardien pour entrer dans le bloc de cellules et trouver une manière de libérer les prisonniers.,"Használd az igazgató kulcsát, hogy bejuss a börtön részlegbe, és kiszíbadíts mindenkit.",Usa la chiave del direttore per entrare nella sezione delle celle e trovare un modo per liberare i prigionieri.,"ワーデンの鍵で刑務所の独房区域に入って +囚人を解放する方法を見つける。","간수장의 열쇠를 써서 감옥 안으로 진입하고, 수감자들을 풀어줄 방법을 찾아봐.",Gebruik de sleutel van de bewaker om in de celblokken van de gevangenis te komen en een manier te vinden om de gevangenen te bevrijden.,Bruk direktørens nøkkel til å komme inn i fengselsblokkene og finn en måte å befri fangene på.,"Użyj klucza naczelnika, aby dostać się do bloków więziennych i znajdź sposób na uwolnienie więźniów.",Use a chave do Carcereiro para entrar nos blocos de celas e ache uma maneira de libertar os prisioneiros.,,Folosește cheia Directorului pentru a intra în blocurile celulelor și găsește o cale să eliberezi prizonierii.,"Используй ключ тюремщика, чтобы пройти к камерам. Найди способ освободить пленников.",,Använd direktörens nyckel för att ta dig in i fängelsecellblocken och hitta ett sätt att befria fångarna.,Hapishane hücre bloklarına girmek için Müdür'ün anahtarını kullan ve mahkumları serbest bırakmanın bir yolunu bul. +Find a way to free the prisoners. Find a way to open the hand scanner switch.,TXT_ILOG19,MAP05: After getting to Main Control.,,,"Najdi způsob, jak osvobodit vězně. Najdi způsob, jak aktivovat skener otisků ruky.",Find en måde at befri fangerne på. Find en måde at åbne håndscannerkontakten.,"Finde heraus, wie man die Gefangenen befreien kann und wie du den Handscanner umgehen kannst.",,Trovu manieron agigi la manskanilon por liberigi la kaptitojn.,Encuentra como activar el escáner de mano para liberar a los prisioneros.,,Etsi keino vapauttaa vangit. Ratkaise tapa avata kädenjälkilukijan lukitus.,Trouve un moyen de libérer les prisonniers. Trouve une manière d'activer le scanner à empreinte digitale.,"Találd meg a módját, hogyan szabadíthatjuk ki a rabokat, és hogyan játszhatjuk ki a kézlenyomat olvasót.",Trova un modo per liberare i prigionieri. Trova un modo per attivare lo scanner della mano.,"囚人を解放する方法を見つける。 + ハンドスキャナーを開く方法を見つける。",수감자들을 풀어줄 방법을 찾자. 지문인식장치를 통과할 방법을 찾아봐.,Zoek een manier om de gevangenen te bevrijden. Zoek een manier om de handscanner schakelaar te openen.,Finn en måte å befri fangene på. Finn en måte å åpne håndskannerbryteren på.,Znajdź sposób na uwolnienie więźniów. Znajdź sposób na otwarcie przełącznika skanera ręcznego.,Encontre uma maneira de libertar os prisioneiros. Ache uma maneira de abrir o scanner de mão.,,Găsește o cale să eliberezi prizonierii. Găsește o cale să deschizi comutatorul scanner-ului de mâini.,Найди способ освободить пленников. Найди способ открыть замок со сканером отпечатка руки.,,Hitta ett sätt att befria fångarna. Hitta ett sätt att öppna handskanneromkopplaren.,Mahkûmları serbest bırakmanın bir yolunu bul. El tarayıcı anahtarını açmanın bir yolunu bulun. +Find a way to free the prisoners. Use the judge's hand to operate the hand scanner switch.,TXT_ILOG20,MAP05: After cutting Wolenick's hand off.,,,"Najdi způsob, jak osvobodit vězně. Použij soudcovu ruku k aktivaci skeneru otisků ruky.",Find en måde at befri fangerne på. Brug dommerens hånd til at betjene håndscannerkontakten.,"Finde heraus, wie man die Gefangenen befreien kann. Benutze die Hand des Richters um den Handscannerschalter zu betätigen.",,Uzu la manon de la juĝisto por agigi la skanilon kaj liberigi la kaptitojn.,Usa la mano del juez para activar el escáner y liberar a los prisioneros.,,Etsi keino vapauttaa vangit. Käytä tuomarin kättä kädenjälkilukijaan.,Trouve un moyen de libérer les prisonniers. Utilise la main du juge pour activer le scanner à empreinte digitale.,"Találd meg a módját, hogyan szabadíthatjuk ki a rabokat, használd a bíró kezét a kézleolvasóhoz.",Trova un modo per liberare i prigionieri. Usa la mano del giudice per operare lo scanner.,"囚人を解放する方法を見つける。 +裁判官の手を使用してハンドスキャナースイッチを操作する。",수감자들을 풀어줄 방법을 찾자. 판사의 손을 써서 지문인식장치를 통과하는 거야.,Zoek een manier om de gevangenen te bevrijden. Gebruik de hand van de rechter om de handscanner schakelaar te bedienen.,Finn en måte å befri fangene på. Bruk dommerens hånd til å betjene håndskannerbryteren.,"Znajdź sposób na uwolnienie więźniów. Użyj ręki sędziego, aby uruchomić przełącznik skanera ręcznego.",Encontre uma maneira de libertar os prisioneiros. Use a mão do juiz para operar o scanner.,,Găsește o cale să eliberezi prizonierii. Folosește mâna judecătorului să operezi scanner-ul de mâini.,"Найди способ освободить пленников. Используй руку судьи, чтобы открыть замок со сканером отпечатка руки.",,Hitta ett sätt att befria fångarna. Använd domarens hand för att använda handskannern.,Mahkûmları serbest bırakmanın bir yolunu bulun. El tarayıcı anahtarını çalıştırmak için yargıcın elini kullan. +Way to go my friend. Good work freeing the prisoners. Jump on one of the teleporters and it will bring you back to base.,TXT_ILOG21,MAP05: After setting the prisoners free.,,,"Jen tak dál, příteli, dobrá práce. Skoč na teleportér, dostane tě to zpět na základnu.","Godt gået, min ven. Godt arbejde med at befri fangerne. Hop på en af teleportørerne, så kommer du tilbage til basen.","Das war gute Arbeit, wie du die Gefangenen befreit hast. Benutze einen der Teleporter um zur Basis zurückzugelangen.",,Danke al vi niaj kamaradoj estas liberaj. Uzu la teleportilon en la ĉelaro por reiri al la bazo.,Buen trabajo liberando a los prisioneros. Usa el teletransportador de la galería para volver a la base.,,"Niin sitä pitää, ystäväni. Hyvin toimittu vankien vapauttamisessa. Hyppää johonkin kaukosiirtimistä, ja se tuo sinut takaisin tukikohtaan.",Bien joué mon ami! Bon travail avec ces prisonniers. Utilise l'un des téléporteurs pour revenir à la base.,"Remek volt. Szép munka volt a rabok kiszabadítása. Ugorj be valamelyik teleportba, és visszavisz a bázisba.","Ottimo lavoro, amico. Grazie a te i prigionieri sono stati liberati. Prendi uno dei teletrasporti e ti riporteremo alla base.","よくやった相棒。囚人を解放できたのは良い働きだ。 +いずれかのテレポーターに飛び込むと基地に戻る。","잘했어, 친구. 수감자들을 풀어주느라 고생했어. 저 텔레포터들 중 하나를 타면 우리 기지로 복귀할 수 있을 거야.","Goed gedaan, mijn vriend. Goed werk om de gevangenen te bevrijden. Spring op een van de teleporters en die brengt je terug naar de basis.","Sånn skal det gjøres, min venn. Godt jobbet med å befri fangene. Hopp på en av teleporterne, så kommer du tilbake til basen.","Brawo mój przyjacielu. Dobra robota z uwolnieniem więźniów. Wskocz na jeden z teleporterów, a przeniesie cię on z powrotem do bazy.","Boa, meu amigo. Bom trabalho ao libertar os prisioneiros. Entre num desses teletransportadores e você voltará pra base.",,Bună treabă prietene. Sari într-un teleportor și te va duce la baza noastră.,"Так держать, дружище. Ты отлично поработал и освободил пленников. Прыгай в любой телепорт, и он вернёт тебя на базу.",,"Bra jobbat, min vän. Bra jobbat med att befria fångarna. Hoppa på en av teleporterna så tar den dig tillbaka till basen.",Aferin dostum. Mahkûmları serbest bırakarak iyi iş çıkardın. Işınlayıcılardan birine atla ve seni üsse geri getirsin. +"Destroy the power crystal that runs the power grid which drives the Order's shields. Go visit Worner, a spy we recruited in the warehouse of the power station.",TXT_ILOG22,,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Jdi navštívit Wornera, špióna, kterého jsme najali ve skladu elektrárny.","Ødelæg energikrystallen, der driver det strømnet, som driver Ordenens skjolde. Besøg Worner, en spion, som vi rekrutterede i lageret på kraftværket.","Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Suche Worner auf, einen Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben. ",,"Detruu la energian kristalon, kiu impulsas la elektrizan sistemon, kiu tenas la ŝildon de la kastelo. Renkontu nian spionon Worner en la magazeno (Warehouse) de la centralo (Power Station).","Destruye el cristal de poder que impulsa la red eléctrica que mantiene los escudos del castillo. Busca a Worner, un espía nuestro, en el almacén (Warehouse) de la central eléctrica (Power Station).",,"Tuhoa kaupungin sähköverkon voimanlähteenä toimiva voimakristalli, jonka voimaa Veljeskunnan kilvet käyttävät. Mene tapaamaan Worneria, vakoojaa, jonka värväsimme voimalaitoksen varastolta.","Détruis le cristal qui contrôle la grille énergétique des boucliers de l'Ordre. Va voir Worner, un espion que l'on a recruté dans l'entrepôt de la centrale.","Semmisítsd meg az erő kristályt, ami a Rend külső védőpajzsát hajtja az elektromos hálózaton keresztül. Keresd fel az erőműtől betoborzott kémünket, Wornert.","Distruggi il cristallo che fornisce energia agli scudi dell'Ordine. Trova Worner, una spia che abbiamo reclutato nel magazzino della centrale energetica.","送電網を動かしているパワークリスタルを破壊してオーダーのシールドを止めろ。 +発電所の倉庫に潜らせたスパイ、ワーナーを訪ねよ。","오더의 방어막을 유지하는 동력 망의 전력원인 수정체를 파괴하자. 우선, 발전소 창고에 있는 우리 쪽 첩자인 워너에게 찾아가 보자.","Vernietig het energiekristal dat het stroomnet dat de schilden van de Orde aandrijft. Ga op bezoek bij Worner, een spion die we gerekruteerd hebben in het magazijn van de centrale.","Ødelegg kraftkrystallen som driver kraftnettet som driver Ordenens skjold. Besøk Worner, en spion vi rekrutterte i kraftstasjonens lager.","Zniszcz kryształ mocy, który zasila sieć energetyczną napędzającą tarcze Zakonu. Idź odwiedzić Wornera, szpiega, którego zwerbowaliśmy w magazynie elektrowni.","Destrua o cristal de energia que alimenta a rede elétrica por trás dos escudos da Ordem. Visite o Worner, um espião que recrutamos no depósito da usina de energia.",,"Distruge cristalul de energie care alimentează scuturile Ordinului. Vizitează-l pe Worner, un spion recrutat în depozitul stației de energie.","Уничтожь кристалл, питающий энергосеть Ордена, от которой работают их щиты. Встреться с Уорнэром, нашим шпионом, на складе электростанции.",,"Förstör kraftkristallen som driver kraftnätet som driver Ordens sköldar. Gå och besök Worner, en spion som vi rekryterade i kraftverkets lager.",Tarikat'ın kalkanlarını çalıştıran güç şebekesini çalıştıran güç kristalini yok edin. Güç istasyonunun deposunda işe aldığımız casus Worner'ı ziyaret et. +Let's get lost. There's more fun to come.,TXT_ILOG24,MAP04: After leaving Reactor Core.,,,"Ztraťme se, za chvíli tu bude víc srandy.",Lad os fare vild. Der er mere sjov på vej.,Lass uns verschwinden. Hier wird's gleich ungemütlich.,,Ni devas eliri: la alarmo eksonis.,Hay que irse: la central está alerta.,,Häivytään. Lisää hupia on luvassa.,"Partons d'ici, il y a encore de quoi s'amuser.",Húzzunk innen. Most jön még az izgi rész.,Leviamoci di torno. C'è ancora da divertirsi.,迷子になったら、もっと楽しめるぞ。,어서 여길 떠나자. 녀석들이 오기 전에 말이야.,Laten we verdwalen. Er komt nog meer plezier.,La oss stikke. Det er mer moro i vente.,Zgubmy się. Czeka nas jeszcze więcej zabawy.,Então se manda. Tem mais diversão por vir.,,Să ne pierdem. O să mai fie distracții.,Давай-ка исчезнем отсюда. Скоро начнётся веселье.,,Låt oss gå vilse. Det finns mer kul att göra.,Hadi kaybolalım. Daha çok eğlence var. +"One more adventure before command feels it's safe to attack the castle. Macil's arranged for Irale to give you gold and some training. After you visit him, see the medic in town for strength.",TXT_ILOG25,MAP02: After destroying the crystal in the Power Station.,,,"Ještě jedno dobrodružství, než se velení rozhodne zaútočit. Macil sjednal u Iraleho zlato a trénink. Pak navštiv městského lékaře pro sílu.","Et eventyr mere, før kommandoen føler, at det er sikkert at angribe slottet. Macil har sørget for, at Irale giver dig guld og noget træning. Når du har besøgt ham, skal du gå til lægen i byen for at få styrke.","Eine weitere Aufgabe noch, bevor Macil es für sicher hält, die Burg anzugreifen. Macil hat Irale gebeten, dir Gold zu geben und Training zu organisieren. Nachdem du bei ihm warst, lass dir vom Sanitäter in der Stadt deine Ausdauer erhöhen.",,"Ankoraŭ unu komisio por ke la Fronto sentu, ke sturmi la kastelon estas sekure. Macil diris al Irale, ke li donu oron kaj trejnadon al vi. Post tio, iru ĉe la kuracisto (Hospital) de la urbo pro la enplantaĵo.","Una misión más para que el comando sienta que es seguro asaltar el castillo. Macil le ha dicho a Irale que te dé oro y entrenamiento. Tras visitarlo, ve con el médico del pueblo para cambiar el implante.","Una misión más para que el comando sienta que es seguro asaltar el castillo. Macil le dijo a Irale que te dé oro y entrenamiento. Tras visitarlo, ve con el médico del pueblo para cambiar el implante.","Vielä yksi seikkailu, ennen kuin komentokeskus katsoo tilanteen hyväksi hyökätä linnaa vastaan. Macil on järjestänyt Iralen antamaan sinulle kultaa ja koulutusta. Kun olet tavannut häntä, tapaa kaupungilla lääkintämiestä vahvistusta varten.","Encore une aventure avant que le commandement ne pense qu'il soit bon temps d'attaquer le château. Macil s'est arrangé pour qu'Irale te donne de l'argent et qu'il t'entraîne. Une fois que tu en as fini avec lui, va visiter le médecin en ville pour qu'il te rende des forces.","Még egy kaland, mielőtt az irányítás hatékony támadást indíthat a kastély ellen. Macil elintézte, hogy Irale ellásson arannyal és kiképzéssel. Utána keresd fel a szanitécet, hogy kicsit kipofozzon.","Un'ultima avventura prima dell'assedio al castello. Macil ha parlato ad Irale per farti avere dell'oro e un po' di addestramento. Dopo che gli hai fatto visita, parla anche dal medico in città per una marcia in più.","もう一つの任務をこなす前に戦力の増強が必要と考えられる。 マシルがイラールを介して資金と訓練の手配をしてくれるので会いなさい。 -それと近所のメディックも支援してくれるわ。",본부가 공성전을 진행하기 전에 한 가지 해야 할 일이 있어. 마실이 이롤리에게 골드랑 훈련을 제공해달라고 부탁했대. 그리고 마을 병원에 가서 근력을 키워달라고 해.,"Nog een avontuur voor het commando het gevoel heeft dat het veilig is om het kasteel aan te vallen. Macil heeft geregeld dat Irale je goud en wat training geeft. Nadat je hem hebt bezocht, ga je naar de dokter in de stad voor kracht.",,"Mais uma aventura antes que o comando ache que é seguro o bastante para atacar o castelo. Macil instruiu Irale a te passar ouro e treinamento. Após visitá-lo, vá ao médico para te dar uma força.",,,"Ещё одно приключение, и штаб будет уверен в успешности атаки на замок. Мэйсил поручил Ирэйлу выплатить тебе награду и дать пару уроков. После встречи с ним, посети городского медика.", -"Visit Irale and the medic in town for gold and training, then find the sewers. Head along the river across from the Governor's mansion.",TXT_ILOG26,,,,"Navštiv Iraleho a doktora pro zlato a trénink, pak najdi stoky. Jdi podél řeky naproti guvernérově sídlu.","Geh zu Irale und dem Sanitäter in der Stadt, um etwas Gold und Training zu bekommen, dann finde die Kanalisation. Folge dem Fluss auf der gegenüberliegenden Seite der Villa des Gouverneurs.",,,"Visita a Irale y al médico en el pueblo para oro y entrenamiento, luego encuentra las alcantarillas. Dirígete a través del río junto a la mansión del governador.","Visita a Irale y al médico del pueblo para obtener oro y entrenamiento, luego encuentra las alcantarillas. Dirígete a través del río enfrente de la mansión del gobernador.",,"Visite Irale et le médecin en ville pour de l'argent et de l'entraînement, puis trouve l'entrée des égouts. Descend le long de la rivière de l'autre côté du manoir du gouverneur.",,,"イラールとメディックを尋ねて資金と訓練を受け、下水道に向かうんだ。 -入り口は知事のマンションの川を挟んだ向かい側だ。","이롤리와 마을 의무관에게 가서 골드와 훈련을 받고, 하수구를 찾아. 총독의 관저 건너편의 강을 따라서 가봐.","Bezoek Irale en de dokter in de stad voor goud en training, en zoek dan de riolen. Loop langs de rivier tegenover het landhuis van de gouverneur.",,Visite o Irale e o médico na cidade para ouro e treinamento. Depois encontre o esgoto. Vá para o rio do outro lado da mansão do Governador.,,,"Зайди к Ирэйлу и городскому медику за золотом и обучением, потом спустись в канализацию. Иди вдоль берега реки, спуск прямо напротив особняка губернатора.", -"We're looking for Weran, who calls himself the Rat King. I'm sure it's descriptive as well as colorful.",TXT_ILOG28,,,,"Hledáma Werana, který si říká Krysí král. Jsem si jistá, že to je jak barvité, tak přesné.","Wir suchen Weran, den man auch den Rattenkönig nennt. Ich bin sicher, dass dies ihn sehr anschaulich beschreibt.",,,"Estamos buscando a Weran, quien se autoproclama el Rey de las Ratas. Estoy segura de que es tanto descriptivo como vistoso.","Buscamos a Weran, quién se llama a sí mismo el Rey de las Ratas. Estoy segura que es descriptivo y colorido.",,"Cherche Weran, il se fait appeler le Roi des Rats. Je suis sur que c'est aussi descriptif que flatteur.",,,"誰が呼んだかラットキングのウェランを探すんだ。 -それが叙述的でもあり派手な呼び名なのも定かだ。",우리는 자신을 시궁쥐 왕이라고 부르는 워렌을 찾아야 해. 알록달록해서 눈에 잘 띌 것 같은데 말이야.,"We zijn op zoek naar Weran, die zichzelf de rattenkoning noemt. Ik weet zeker dat het zowel beschrijvend als kleurrijk is.",,"Estamos procurando pelo Weran, que se autodenomina o Rato Rei. Imagino que isso seja tão descritivo quanto gracioso.",,,"Нам нужен Уэран — он называет себя Крысиным королём. Уверена, прозвище так же емко, как и красочно.", -"Take the flamethrower parts to Irale. Drain the reclamation tank. At the bottom is a hidden entrance to the sewers. The gate controls are down there, somewhere. Destroy them.",TXT_ILOG33,,,,Vezmi části plamenometu k Iralemu. Vypusť obnovovací nádrž. Na dně je skrytý vchod do stok. Někde tam je ovládání bran. Znič jej.,Bringe dir Flammenwerferteile zu Irale. Leere den Sammeltank. Am Boden ist ein versteckter Eingang zur Kanalisation. Dort ist die Steuerung für die Tore. Zerstöre sie.,,,"Llévale las partes de lanzallamas a Irale. Drena el tanque de recuperación. Al fondo hay una entrada secreta a las alcantarillas. Los controles de la puerta están ahí abajo, en algún lugar. Destrúyelos.","Llévale las partes del lanzallamas a Irale. Drena el tanque de recuperación. En la parte inferior hay una entrada oculta a las alcantarillas. Los controles de la puerta están ahí abajo, en alguna parte. Destruyelos.",,Amène les pièces du lance-flamme à Irale. Fais vider le réservoir de recyclage. Au fond se trouve une entrée cachée vers les égouts. Les contrôles de la porte s'y trouvent. Détruis-les.,,,"火炎放射器の部品をイラールに持っていく。 +それと近所のメディックも支援してくれるわ。",본부가 공성전을 진행하기 전에 한 가지 해야 할 일이 있어. 마실이 이롤리에게 골드랑 훈련을 제공해달라고 부탁했대. 그리고 마을 병원에 가서 근력을 키워달라고 해.,"Nog een avontuur voor het commando het gevoel heeft dat het veilig is om het kasteel aan te vallen. Macil heeft geregeld dat Irale je goud en wat training geeft. Nadat je hem hebt bezocht, ga je naar de dokter in de stad voor kracht.","Ett eventyr til før kommandoen mener det er trygt å angripe slottet. Macil har sørget for at Irale gir deg gull og litt trening. Etter at du har besøkt ham, gå til legen i byen for å få styrke.","Jeszcze jedna przygoda, zanim dowództwo uzna, że można bezpiecznie zaatakować zamek. Macil umówił się z Irale, że da ci złoto i trochę treningu. Po wizycie u niego, udaj się do medyka w mieście po siłę.","Mais uma aventura antes que o comando ache que é seguro o bastante para atacar o castelo. Macil instruiu Irale a te passar ouro e treinamento. Após visitá-lo, vá ao médico para te dar uma força.",,"Încă o aventură până ce comanda e încrezătoare în atacarea castelului. Macil a aranjat ca Irale să îți ofere bani și antrenament. Dupa ce îț vizitezi, mergi la medicul din oraș pentru forță.","Ещё одно приключение, и штаб будет уверен в успешности атаки на замок. Мэйсил поручил Ирэйлу выплатить тебе награду и дать пару уроков. После встречи с ним, посети городского медика.",,Ett äventyr till innan kommandot känner att det är säkert att attackera slottet. Macil har ordnat så att Irale ger dig guld och lite träning. Efter att du besökt honom ska du gå till läkaren i staden för att få styrka.,"Komutanlık kaleye saldırmanın güvenli olduğunu düşünmeden önce bir macera daha. Macil, İrale'nin sana altın ve biraz eğitim vermesini ayarladı. Onu ziyaret ettikten sonra, güç için kasabadaki doktoru gör." +"Visit Irale and the medic in town for gold and training, then find the sewers. Head along the river across from the Governor's mansion.",TXT_ILOG26,〃,,,"Navštiv Iraleho a doktora pro zlato a trénink, pak najdi stoky. Jdi podél řeky naproti guvernérově sídlu.","Besøg Irale og lægen i byen for at få guld og træning, og find derefter kloakkerne. Gå langs floden over for guvernørens palæ.","Geh zu Irale und dem Sanitäter in der Stadt, um etwas Gold und Training zu bekommen, dann finde die Kanalisation. Folge dem Fluss auf der gegenüberliegenden Seite der Villa des Gouverneurs.",,"Iru ĉe Irale kaj ĉe la kuracisto (Hospital) de la urbo, tiam trovu la kloakon: serĉu enirejon inter la rojo kaj la urbodomo.","Visita a Irale y al médico del pueblo, luego encuentra las alcantarillas: busca una entrada entre el arroyo y el ayuntamiento.",,"Tapaa Iralea ja lääkintämiestä kaupungilla kultaa ja koulutusta varten, minkä jälkeen löydä viemärit. Kulje joen vartta kuvernöörin kartanoa vastapäätä.","Visite Irale et le médecin en ville pour de l'argent et de l'entraînement, puis trouve l'entrée des égouts. Descend le long de la rivière de l'autre côté du manoir du gouverneur.","Keresd fel Iralet és a szanitécet a városban egy kis aranyért és kiképzésért, aztán irány a kanáris. Menj a folyón ami átszeli a kormányzó kúriáját.","Visita Irale e il medico in città per oro e addestramento, dopodiché trova le fogne. Vi puoi accedere dal fiume vicino alla dimora del governatore.","イラールとメディックを尋ねて資金と訓練を受け、下水道に向かうんだ。 +入り口は知事のマンションの川を挟んだ向かい側だ。","이롤리와 마을 의무관에게 가서 골드와 훈련을 받고, 하수구를 찾아. 총독의 관저 건너편의 강을 따라서 가봐.","Bezoek Irale en de dokter in de stad voor goud en training, en zoek dan de riolen. Loop langs de rivier tegenover het landhuis van de gouverneur.","Besøk Irale og legen i byen for gull og trening, og finn deretter kloakken. Gå langs elven overfor guvernørens hus.","Odwiedź Irale i medyka w mieście po złoto i trening, a następnie znajdź kanały. Skieruj się wzdłuż rzeki naprzeciwko rezydencji gubernatora.",Visite o Irale e o médico na cidade para ouro e treinamento. Depois encontre o esgoto. Vá para o rio do outro lado da mansão do Governador.,,"Vizitează pe Irale și medicul din oraș pentru aur și antrenament, apoi găsește canalele. Urmează râul de lângă complexul Guvernatorului.","Зайди к Ирэйлу и городскому медику за золотом и обучением, потом спустись в канализацию. Иди вдоль берега реки, спуск прямо напротив особняка губернатора.",,Besök Irale och läkaren i staden för att få guld och träning och hitta sedan kloakerna. Gå längs floden mittemot guvernörens herrgård.,"Altın ve eğitim için İrale'yi ve kasabadaki doktoru ziyaret edin, ardından kanalizasyonları bulun. Valinin konağının karşısındaki nehir boyunca ilerleyin." +"We're looking for Weran, who calls himself the Rat King. I'm sure it's descriptive as well as colorful.",TXT_ILOG28,MAP06: Entrance.,,,"Hledáma Werana, který si říká Krysí král. Jsem si jistá, že to je jak barvité, tak přesné.","Vi leder efter Weran, som kalder sig selv Rottekongen. Det er sikkert både beskrivende og farverigt.","Wir suchen Weran, den man auch den Rattenkönig nennt. Ich bin sicher, dass dies ihn sehr anschaulich beschreibt.",,"Ni serĉas Weran-on, kiu proklamas sin mem la Rat-reĝo. Mi estas certa, ke tio estas tre fidela priskribo.","Estamos buscando a Weran, quien se autoproclama el Rey de las Ratas. Estoy segura de que es fielmente descriptivo.",,"Etsimme Werania, joka kutsuu itseään Rottakuninkaaksi. Varmastikin kuvaava titteli, mutta myös väritetty.","Cherche Weran, il se fait appeler le Roi des Rats. Je suis sur que c'est aussi descriptif que flatteur.","Werant keressük, aki magát csak a Patkány Királyként emlegeti. Biztos vagyok, hogy nem csak színes név, de valszeg hasonlít is hozzá.","Stiamo cercando Weran, che si fa chiamare il Re dei Ratti. Sono sicura che lo descrive appieno.","誰が呼んだかラットキングのウェランを探すんだ。 +それが叙述的でもあり派手な呼び名なのも定かだ。",우리는 자신을 시궁쥐 왕이라고 부르는 워렌을 찾아야 해. 알록달록해서 눈에 잘 띌 것 같은데 말이야.,"We zijn op zoek naar Weran, die zichzelf de rattenkoning noemt. Ik weet zeker dat het zowel beschrijvend als kleurrijk is.","Vi leter etter Weran, som kaller seg Rottekongen. Det er sikkert både beskrivende og fargerikt.","Szukamy Werana, który nazywa siebie Królem Szczurów. Na pewno jest to opisowe, jak i barwne.","Estamos procurando pelo Weran, que se autodenomina o Rato Rei. Imagino que isso seja tão descritivo quanto gracioso.",,"Îl căutam pe Weran, care ăși spune Regele Șobolanilor. Sunt sigur că e descriptiv și colorat.","Нам нужен Уэран — он называет себя Крысиным королём. Уверена, прозвище так же емко, как и красочно.",,Vi letar efter Weran som kallar sig för råttkungen. Jag är säker på att det är både beskrivande och färgstarkt.,Kendisine Fare Kral diyen Weran'ı arıyoruz. Renkli olduğu kadar açıklayıcı da olduğuna eminim. +"Take the flamethrower parts to Irale. Drain the reclamation tank. At the bottom is a hidden entrance to the sewers. The gate controls are down there, somewhere. Destroy them.",TXT_ILOG33,MAP06: After giving the guard's uniform to Weran.,,,Vezmi části plamenometu k Iralemu. Vypusť obnovovací nádrž. Na dně je skrytý vchod do stok. Někde tam je ovládání bran. Znič jej.,Tag flammekasterdelene med til Irale. Tøm genvindingstanken. I bunden er der en skjult indgang til kloakkerne. Kontrolelementerne til porten er dernede et sted. Ødelæg dem.,Bringe dir Flammenwerferteile zu Irale. Leere den Sammeltank. Am Boden ist ein versteckter Eingang zur Kanalisation. Dort ist die Steuerung für die Tore. Zerstöre sie.,,"Portu la partojn de la flamĵetilo al Irale. Drenu la rezervujon en la kastelo: en ĝia fundo estas kaŝita enirejo al la kloako, kaj ie tie estas la regilo de la pordo; detruu ĝin.",Llévale las partes del lanzallamas a Irale. Drena el tanque de recuperación del castillo: al fondo hay una entrada secreta a las alcantarillas y por ahí mismo el control de la puerta; destrúyelo.,,Toimita liekinheittimen osat Iralelle. Tyhjennä nesteentalteenottoallas. Sen pohjalla on viemärin salainen sisäänkäynti. Portin ohjaimet sijaitsevat jossakin siellä. Tuhoa ne.,Amène les pièces du lance-flamme à Irale. Fais vider le réservoir de recyclage. Au fond se trouve une entrée cachée vers les égouts. Les contrôles de la porte s'y trouvent. Détruis-les.,Vidd a lángszóró darabokat Iralehez. Ereszd le a szárító tartályt. Az alján megtalálod a titkos lejáratot a kanárisba. A kapu vezérlése ott van lent valahol. Semmisítsd meg őket.,"Porta i pezzi del lanciafiamme da Irale. Svuota la vasca di recupero fluidi. Nel fondo c'è un'entrata nascosta per le fogne. I controlli dei cancelli sono laggiù, da qualche parte. Distruggili.","火炎放射器の部品をイラールに持っていく。 浄化タンクを排水せよ。その下層に下水道への隠された入り口がある。 -ゲートコントロールを探し出し、破壊せよ。",이 화염방사기 부품을 가지고 이롤리에게 말 걸어봐. 수조에 있는 물을 비우면 밑에 하수도로 향하는 비밀 입구가 보일 거야. 성문의 관리 장치가 여기 어딘가에 있을 거야. 찾으면 파괴해.,"Neem de vlammenwerperonderdelen mee naar Irale. Laat de terugwinnings tank leeglopen. Onderaan is een verborgen ingang naar de riolering. De poortbediening is daar beneden, ergens. Vernietig ze.",,Leve as peças do lança-chamas ao Irale. Drene o tanque de recuperação. No fundo há uma entrada oculta para o esgoto. Os controles do portão estão lá embaixo em algum lugar. Destrua-os.,,,"Отнеси детали огнемёта Ирэйлу. Слей жидкость из бака для переработки. На его дне скрытый вход в канализацию. Механизм управления воротами где-то там, внизу. Сломай его.", -"Command, he's done it! The gates are open. Send in the shock troops and tell Macil we're coming in! Let's get back to the Front base.",TXT_ILOG37,,,,"Velení, dokázal to! Brány jsou otevřené. Pošlete tam úderníky a řekněte Macilovi, že přicházíme! Vrať se na základnu Fronty.",Kommandozentrale: Er hat's geschafft! Die Tore sind offen. Schickt die Schocktruppen hinein und sagt Macil das wir auf dem Weg sind! Lass uns zur Frontbasis zurückkehren.,,,"Comando, ¡Lo ha hecho! Las puertas están abiertas. ¡Enviad a las tropas de choque y decidle a Macil que venimos adentro! Volvamos a la base del Frente.","Comando, ¡Lo ha hecho! Las puertas están abiertas. ¡Envíen las tropas de choque y díganel a Macil que estamos entrando! Regresemos a la base del Frente.",,"C'est bon, commandement, il a réussi! Les portes sont ouvertes, envoyez les soldats de choc et dites à Macil que l'on arrive! Retournons à la base du Front.",,,"司令官、彼はやったぞ! -ゲートが開いた。突撃部隊を送って我々も続くとマシルに伝えてくれ!",본부! 그가 해냈습니다! 성문이 열렸습니다. 공습부대를 성문으로 이동시키고 사령관님께 우리들도 따라올 거라고 전해주세요. 이제 프론트 기지로 돌아가!,"Commando, hij heeft het gedaan! De poorten zijn open. Stuur de stoottroepen naar binnen en zeg Macil dat we binnenkomen! Laten we teruggaan naar de voorste basis.",,"Comando, ele conseguiu! Os portões estão abertos. Mande as tropas de choque e diga ao Macil que estamos entrando! Vamos voltar pra base da Frente.",,,"Штаб, он выполнил задание! Ворота открыты. Посылайте ударный отряд и доложите Мэйсилу, что мы пробились! Возвращайся на базу Сопротивления.", -"Join the assault on the castle. Find and take out the Programmer. We have conflicting reports about his location. One says he in a computer room, another hiding in a sub-level temple, and yet another at the end of a long hallway.",TXT_ILOG38,,,,"Připoj se k útoku na hrad. Najdi a zabij Programátora. Informace o jeho pozici se různí. Jedna mluví o místnosti s počítači, druhá o podzemním chrámu a třetí o konci dlouhé chodby.","Schließe dich dem Angriff auf die Burg an. Finde den Programmierer und schalte ihn aus. Wir haben widersprüchliche Angaben über seinen Aufenthaltsort. Eine sagt, in einem Computerraum, ein anderer, dass er sich in einem Tempelkeller versteckt und noch ein anderer sagt was vom Ende eines langen Flurs.",,,"Únete al asalto en el castillo. Encuentra y elimina al Programador. Tenemos informes contradictorios sobre su ubicación. Uno dice que está en una sala de computadoras, otro que escondido en un templo en el subnivel, y también otro que al final de un largo pasillo.","Únete al asalto en el castillo. Encuentra y saca al programador. Tenemos informes contradictorios sobre su ubicación. Uno dice que está en una sala de computadora, otro que se esconde en un templo en el sub-nivel y uno más que está al final de un largo pasillo.",,"Rejoins l'assaut sur le château. Trouve et élimine le Programmeur. On a des rapports en conflit sur sa position. L'un d'entre eux nous dit qu'il se trouve dans la salle des ordinateurs, l'autre nous dit qu'il se cache dans un temple en sous sol, et un autre encore au bout d'un long couloir.",,,"城に向かう突撃部隊に参加してプログラマーを探し出せ。 +ゲートコントロールを探し出し、破壊せよ。",이 화염방사기 부품을 가지고 이롤리에게 말 걸어봐. 수조에 있는 물을 비우면 밑에 하수도로 향하는 비밀 입구가 보일 거야. 성문의 관리 장치가 여기 어딘가에 있을 거야. 찾으면 파괴해.,"Neem de vlammenwerperonderdelen mee naar Irale. Laat de terugwinnings tank leeglopen. Onderaan is een verborgen ingang naar de riolering. De poortbediening is daar beneden, ergens. Vernietig ze.","Ta flammekasterdelene til Irale. Tøm utvinningstanken. Nederst er det en skjult inngang til kloakken. Portkontrollene er der nede, et sted. Ødelegg dem.",Zabierz części miotacza ognia do Irale. Opróżnij zbiornik rekultywacyjny. Na dole jest ukryte wejście do kanałów. Sterowniki bramy są gdzieś tam na dole. Zniszcz je.,Leve as peças do lança-chamas ao Irale. Drene o tanque de recuperação. No fundo há uma entrada oculta para o esgoto. Os controles do portão estão lá embaixo em algum lugar. Destrua-os.,,"Du bucățiile aruncătorului la Irale. Drenează rezervorul recuperării. La fund e o intrare secretă către canale. Controlul porții e jos, undeva. Distruge-l.","Отнеси детали огнемёта Ирэйлу. Слей жидкость из бака для переработки. На его дне скрытый вход в канализацию. Механизм управления воротами где-то там, внизу. Сломай его.",,Ta med dig flamethrowerdelarna till Irale. Töm återvinningstanken. I botten finns en dold ingång till kloakerna. Grindkontrollerna finns där nere någonstans. Förstör dem.,Alev makinesi parçalarını İrale'ye götür. Islah tankını boşaltın. En altta kanalizasyona gizli bir giriş var. Kapı kontrolleri aşağıda bir yerde. Onları yok et. +"Command, he's done it! The gates are open. Send in the shock troops and tell Macil we're coming in! Let's get back to the Front base.",TXT_ILOG37,MAP06: After destroying the gate controls.,,,"Velení, dokázal to! Brány jsou otevřené. Pošlete tam úderníky a řekněte Macilovi, že přicházíme! Vrať se na základnu Fronty.","Kommando, han har gjort det! Portene er åbne. Send choktropperne ind og fortæl Macil, at vi kommer ind! Lad os komme tilbage til frontbasen.",Kommandozentrale: Er hat's geschafft! Die Tore sind offen. Schickt die Schocktruppen hinein und sagt Macil das wir auf dem Weg sind! Lass uns zur Frontbasis zurückkehren.,,"Fronto, li sukcesis! Li malfermis la pordojn. Sendu la sturmantojn kaj diru al Macil, ke estas tempo eniri! Ni reiru al la bazo de la Fronto.","¡Comando, lo ha conseguido! Las puertas ya están abiertas. ¡Enviad a las tropas de choque y decidle a Macil que ya es hora de entrar! Volvamos a la base del Frente.","¡Comando, lo logró! Las puertas ya están abiertas. ¡Manden a las tropas de choque y díganle a Macil que ya es hora de entrar! Volvamos a la base del Frente.","Komentokeskus, hän teki sen! Portit ovat auki; lähettäkää iskujoukot ja kertokaa Macilille, että vyörymme sisään! Palataan Rintaman tukikohtaan.","C'est bon, commandement, il a réussi! Les portes sont ouvertes, envoyez les soldats de choc et dites à Macil que l'on arrive! Retournons à la base du Front.","Irányítás, megcsinálta! A kpuk kinyíltak. Küldjétek be az elektromos egységeket, és értesítsd Macilt hogy jövünk! Irány vissza a homlokfronthoz.","Comando, ce l'ha fatta! I cancelli sono aperti. Mandate avanti le truppe e dite a Macil che stiamo arrivando! Torniamo alla base del Fronte.","司令官、彼はやったぞ! +ゲートが開いた。突撃部隊を送って我々も続くとマシルに伝えてくれ!",본부! 그가 해냈습니다! 성문이 열렸습니다. 공습부대를 성문으로 이동시키고 사령관님께 우리들도 따라올 거라고 전해주세요. 이제 프론트 기지로 돌아가!,"Commando, hij heeft het gedaan! De poorten zijn open. Stuur de stoottroepen naar binnen en zeg Macil dat we binnenkomen! Laten we teruggaan naar de voorste basis.","Kommando, han har klart det! Portene er åpne. Send inn sjokktroppene og si til Macil at vi kommer inn! La oss dra tilbake til frontbasen.","Dowództwo, udało mu się! Wrota są otwarte. Wyślij oddziały uderzeniowe i powiedz Macilowi, że wchodzimy! Wracajmy do bazy frontowej.","Comando, ele conseguiu! Os portões estão abertos. Mande as tropas de choque e diga ao Macil que estamos entrando! Vamos voltar pra base da Frente.",,"Comandă, a reușit! Porțile sunt deschise. Trimite trupele de șoc și spune-i lui Macil că intrăm! Să ne întoarcem la baza Frontului.","Штаб, он выполнил задание! Ворота открыты. Посылайте ударный отряд и доложите Мэйсилу, что мы пробились! Возвращайся на базу Сопротивления.",,"Kommando, han har gjort det! Portarna är öppna. Skicka in chocktrupperna och säg till Macil att vi kommer in! Låt oss återvända till Frontbasen.","Komuta, başardı! Kapılar açıldı. Şok birliklerini gönderin ve Macil'e geldiğimizi söyleyin! Cephe üssüne geri dönelim." +"Join the assault on the castle. Find and take out the Programmer. We have conflicting reports about his location. One says he in a computer room, another hiding in a sub-level temple, and yet another at the end of a long hallway.",TXT_ILOG38,MAP07: Entrace.,,,"Připoj se k útoku na hrad. Najdi a zabij Programátora. Informace o jeho pozici se různí. Jedna mluví o místnosti s počítači, druhá o podzemním chrámu a třetí o konci dlouhé chodby.","Deltag i angrebet på slottet. Find og udslæt programmøren. Vi har modstridende rapporter om hans placering. En siger, at han er i et computerrum, en anden, at han gemmer sig i et tempel på et underliggende niveau, og endnu en anden for enden af en lang korridor.","Schließe dich dem Angriff auf die Burg an. Finde den Programmierer und schalte ihn aus. Wir haben widersprüchliche Angaben über seinen Aufenthaltsort. Eine sagt, in einem Computerraum, ein anderer, dass er sich in einem Tempelkeller versteckt und noch ein anderer sagt was vom Ende eines langen Flurs.",,Trovu kaj mortigu la Programiston. Estas kontraŭdiraj informoj pri lia pozicio: en komputila ĉambro aŭ en la subtera etaĝo de templo aŭ ĉe la fundo de longa koridoro.,"Encuentra y elimina al Programador. Tenemos informes contradictorios sobre su ubicación: uno que está en una sala de ordenadores, otro en el sótano de un templo y otro al final de un largo pasillo.","Encuentra y elimina al Programador. Tenemos informes contradictorios sobre su ubicación: uno que está en una sala de computadoras, otro en el sótano de un templo y otro al final de un largo pasillo.","Osallistu hyökkäykseen linnaa vastaan. Etsi ja kukista Ohjelmoitsija. Meillä on hänen sijainnistaan eriäviä tietoja: Yhden mukaan hän on tietokonehuoneessa, toisen mukaan maanalaisessa temppelissä ja vielä kolmannen mukaan pitkän käytävän päässä.","Rejoins l'assaut sur le château. Trouve et élimine le Programmeur. On a des rapports en conflit sur sa position. L'un d'entre eux nous dit qu'il se trouve dans la salle des ordinateurs, l'autre nous dit qu'il se cache dans un temple en sous sol, et un autre encore au bout d'un long couloir.","Csatlakozz a kastély ostromához. Keresd meg és iktasd ki a Programozót. Ellentmondó információink vannak a hollétéről. Az egyik szerint a számítógép szobában van, másik szerint egy föld alatti templomban, harmadik szerint egy hosszú folyosó végén.","Unisciti all'assalto sul castello. Trova e fai fuori il Programmatore. I rapporti che abbiamo sulla sua posizione si contraddicono. Uno lo piazza in una stanza di computer, un altro in un tempio di sottolivello, e un altro ancora alla fine di un lungo corridoio.","城に向かう突撃部隊に参加してプログラマーを探し出せ。 プログラマーの居場所について矛盾する報告もある。 ある人はコンピューター室にいる、別の人は保管室にいる、 -また別の人は長い廊下にいるとも言っていた。","성을 공략할 공성전에 참여해. 침투해서 프로그래머를 죽일 수 있게. 그의 장소와 관련된 보고들이 뭔가 혼란스러운데, 컴퓨터실에 있다고 하고, 낮은 층 신전에 숨어 있다고 하고, 다른 한 명은 긴 복도 맨 끝에 서 있대.","Doe mee aan de aanval op het kasteel. Zoek en schakel de Programmeur uit. We hebben tegenstrijdige berichten over zijn locatie. De ene zegt dat hij in een computerkamer zit, de andere verstopt zich in een tempel op subniveau, en nog een andere aan het einde van een lange gang.",,"Junte-se ao ataque no castelo. Ache e elimine o Programador. Temos relatos conflitantes sobre onde ele se encontra. Um deles diz que ele está na sala de informática, outro que ele está escondido num templo no subsolo e mais outro diz que ele está no fim de um longo corredor.",,,"Присоединись к атаке на замок. Найди и уничтожь Программиста. Наши сведения о его местонахождении противоречивы. Одни говорят, что он в компьютерной комнате, другие — что он укрывается в подземном храме, а третьи — что он в конце длинного коридора.", -Find the Programmer and kill him.,TXT_ILOG45,,,,Najdi Programátora a zabij ho.,Finde den Programmierer und töte ihn.,,,Encuentra al Programador y mátalo.,,,Trouve le Programmeur et tue-le.,,,プログラマーを見つけて殺せ。,프로그래머를 찾아서 죽여.,Zoek de Programmeur en vermoord hem.,,Encontre o Programador e mate-o.,,,Найди Программиста и убей его., -"Seek out the Oracle and ask it about the other Sigil pieces. The Oracle resides in the borderlands, just outside of town. Cross the river, head towards the castle and go left through the archway.",TXT_ILOG46,,,,"Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Věštec přebývá v pohraničí, hned za městem. Překroč řeku, zamiř k hradu a jdi vlevo pod obloukem.","Suche das Orakel auf und befrage es bezüglich der anderen Teile des Sigils. Das Orakel ist in den Grenzgebieten zu finden, außerhalb der Stadt. Überquere den Fluss, gehe zur Burg und dann links durch das Tor.",,,"Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. El Oráculo reside en las fronteras, justo fuera del pueblo. Cruza el río, dirígete hacia el castillo y gira a la izquierda a través del arco.","Busca al Oráculo y pregúntale acerca de las otras piezas del Emblema. El Oráculo reside en las fronteras, en las afueras de la ciudad. Cruza el río, dirígete hacia el castillo y gira a la izquierda a través del arco.",,"Trouve l'Oracle et demande lui où se trouvent les autres pièces du Sigil. L'Oracle se trouve dans les terrains vagues à l'extérieur de la ville. Traverse la rivière, va vers le château puis à gauche après l'arche.",,,"オラクルに会いシジルの欠片の場所を尋ねろ。 +また別の人は長い廊下にいるとも言っていた。","성을 공략할 공성전에 참여해. 침투해서 프로그래머를 죽일 수 있게. 그의 장소와 관련된 보고들이 뭔가 혼란스러운데, 컴퓨터실에 있다고 하고, 낮은 층 신전에 숨어 있다고 하고, 다른 한 명은 긴 복도 맨 끝에 서 있대.","Doe mee aan de aanval op het kasteel. Zoek en schakel de Programmeur uit. We hebben tegenstrijdige berichten over zijn locatie. De ene zegt dat hij in een computerkamer zit, de andere verstopt zich in een tempel op subniveau, en nog een andere aan het einde van een lange gang.","Bli med på angrepet på slottet. Finn og drep programmereren. Vi har motstridende rapporter om hvor han befinner seg. En sier at han er i et datarom, en annen at han gjemmer seg i et underjordisk tempel, og en tredje at han er i enden av en lang gang.","Dołącz do szturmu na zamek. Znajdźcie i zlikwidujcie Programistę. Mamy sprzeczne raporty na temat jego lokalizacji. Jeden mówi, że w sali komputerowej, inny, że ukrywa się w podpoziomowej świątyni, a jeszcze inny, że na końcu długiego korytarza.","Junte-se ao ataque no castelo. Ache e elimine o Programador. Temos relatos conflitantes sobre onde ele se encontra. Um deles diz que ele está na sala de informática, outro que ele está escondido num templo no subsolo e mais outro diz que ele está no fim de um longo corredor.",,"Alăturăte asaltului asupra castelului. Găsește-l și elimină-l pe Programator. Avem rapoarte diferite în ceea ce privește locația lui. Unul spune că e într-o sală de calculatoare, iar altul că se ascunde într-un subnivel al templului, și încă unul care spune că e în capătul unui coridor lung.","Присоединись к атаке на замок. Найди и уничтожь Программиста. Наши сведения о его местонахождении противоречивы. Одни говорят, что он в компьютерной комнате, другие — что он укрывается в подземном храме, а третьи — что он в конце длинного коридора.",,"Gå med i anfallet mot slottet. Hitta och ta ut programmeraren. Vi har motstridiga rapporter om var han befinner sig. En säger att han befinner sig i ett datorrum, en annan gömmer sig i ett tempel på en underliggande nivå och ytterligare en annan i slutet av en lång korridor.","Kaleye yapılan saldırıya katılın. Programcıyı bulup çıkarın. Yeri hakkında çelişkili raporlarımız var. Biri bilgisayar odasında, diğeri alt kattaki bir tapınakta, bir başkası da uzun bir koridorun sonunda saklandığını söylüyor." +Find the Programmer and kill him.,TXT_ILOG45,MAP09: Entrance.,,,Najdi Programátora a zabij ho.,Find programmøren og dræb ham.,Finde den Programmierer und töte ihn.,,Trovu la Programiston kaj mortigu lin.,Encuentra al Programador y mátalo.,,Etsi ja tapa Ohjelmoitsija.,Trouve le Programmeur et tue-le.,Keresd meg a Programozót és öld meg.,Trova il Programmatore e fallo fuori.,プログラマーを見つけて殺せ。,프로그래머를 찾아서 죽여.,Zoek de Programmeur en vermoord hem.,Finn programmereren og drep ham.,Znajdź Programistę i zabij go.,Encontre o Programador e mate-o.,,Găsește Programatorul și ucide-l.,Найди Программиста и убей его.,,Hitta programmeraren och döda honom.,Programcıyı bulun ve öldürün. +"Seek out the Oracle and ask it about the other Sigil pieces. The Oracle resides in the borderlands, just outside of town. Cross the river, head towards the castle and go left through the archway.",TXT_ILOG46,,,,"Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Věštec přebývá v pohraničí, hned za městem. Překroč řeku, zamiř k hradu a jdi vlevo pod obloukem.","Opsøg Oraklet og spørg det om de andre Sigil-stykker. Oraklet befinder sig i grænselandet, lige uden for byen. Kryds floden, gå mod slottet og gå til venstre gennem buegangen.","Suche das Orakel auf und befrage es bezüglich der anderen Teile des Sigils. Das Orakel ist in den Grenzgebieten zu finden, außerhalb der Stadt. Überquere den Fluss, gehe zur Burg und dann links durch das Tor.",,Serĉu la Orakolon kaj demandu al li pri la aliaj pecoj de la Sigelo. Li loĝas ekster la urbo en la limlando; ĝi estas apud la pordo de la kastelo.,Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Reside fuera del pueblo en las tierras fronterizas que están justo al lado de la puerta del castillo.,Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Reside afuera del pueblo en las tierras fronterizas que están justo al lado de la puerta del castillo.,"Etsi Oraakkeli ja kysy häneltä muista Sinetin osista. Oraakkeli asuu rajamailla aivan kaupungin liepeillä. Ylitä joki, kulje kohti linnaa ja mene vasemmalle kaarikäytävän läpi.","Trouve l'Oracle et demande lui où se trouvent les autres pièces du Sigil. L'Oracle se trouve dans les terrains vagues à l'extérieur de la ville. Traverse la rivière, va vers le château puis à gauche après l'arche.","Keresd fel az Orákulumot, és kérdezd ki a többi pecsét darabról. Az Orákulum a peremvidéken lakik, rögtön a város után. Elhagyva a folyót, vedd az utad a kastély felé, és balra a boltíves folyosónál.","Raggiungi l'Oracolo e chiedigli degli altri pezzi del Sigillo. L'Oracolo risiede nelle terre di confine, subito dopo la città. Attraversa il fiume, vai nella direzione del castello e poi a sinistra oltre l'arco.","オラクルに会いシジルの欠片の場所を尋ねろ。 オラクルは町外れの国境地帯にいる。 -川の向こうにある城を目指しアーチウェイを左に曲がるのだ。","오라클을 찾아서 다른 시질 조각이 어디에 있는지 물어봐. 오라클은 도시 외곽에 있는 접경지 근처에 있어. 강을 넘은 뒤, 성 쪽으로 향하고 아치 밑의 통로를 통해 왼쪽으로 이동해.","Zoek het Orakel op en vraag het over de andere Sigil stukken. Het Orakel woont in de grensgebieden, net buiten de stad. Steek de rivier over, loop naar het kasteel en ga linksaf door de poort.",,"Procure pelo Oráculo e pergunte a ele sobre as outras peças do Sigilo. O Oráculo mora nas fronteiras, no lado de fora da cidade. Atravesse o rio, vá em direção ao castelo e vá pela esquerda através do arco.",,,"Найди Оракула и спроси его про другие фрагменты Сигила. Резиденция Оракула находится в пограничье, сразу за городской чертой. Пересеки реку, иди в сторону крепости и сверни налево, пройдя через арку.", -"Seek out the Oracle and ask it about the other Sigil pieces. The Oracle's temple is in the borderlands, on the outskirts of town.",TXT_ILOG47,,,,"Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Věštcův chrám je v pohraničí, na okraji města.","Suche das Orakel auf und befrage es bezüglich der anderen Teile des Sigils. Der Tempel des Orakels ist in den Grenzgebieten zu finden, in den Außenbezirken der Stadt.",,,"Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. El templo del Oráculo está en las fronteras, en las afueras del pueblo.","Busca al Oráculo y pregúntale acerca de las otras piezas del Emblema. El Oráculo reside en las fronteras, en las afueras de la ciudad.",,Trouve l'Oracle et demande lui où se trouvent les autres pièces du Sigil. Le temple de l'Oracle se trouve dans les terrains vagues à l'extérieur de la ville. ,,,"オラクルに会いシジルの欠片の場所を尋ねろ。 -オラクルは町外れの国境地帯にいる。",오라클을 찾고 다른 시질 조각에 관해 물어봐. 오라클의 신전은 도시 외곽의 접경지 근처에 있어.,"Zoek het Orakel op en vraag het over de andere Sigil stukken. De tempel van het Orakel ligt in het grensgebied, aan de rand van de stad.",,"Procure pelo Oráculo e pergunte a ele sobre as outras peças do Sigilo. Seu tempo está nas fronteiras, no lado de fora da cidade.",,,"Найди Оракула и спроси его про другие фрагменты Сигила. Храм Оракула расположен в пограничье, на окраине города.", -"Seek out the Oracle and ask it about the other Sigil pieces. Take your reward and go across to the medic and weapons trainer for health and training. The Oracle's temple is in the borderlands, on the outskirts of town.",TXT_ILOG48,,,,"Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Převezmi si svou odměnu a navštiv zdravotníka a učitele střelby pro zdraví a výcvik. Věštcův chrám je v pohraničí, na okraji města.","Suche das Orakel auf und befrage es bezüglich der anderen Teile des Sigils. Nimm deine Belohnung und suche den Sanitäter und den Waffentrainer auf. Der Tempel des Orakels ist in den Grenzgebieten zu finden, in den Außenbezirken der Stadt.",,,"Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Toma tu recompensa y ve al médico y al entrenador de armas para salud y entrenamiento. El templo del Oráculo está en las fronteras, en las afueras del pueblo.","Busca al Oráculo y pregúntale acerca de las otras piezas del Emblema. Obtén tu recompensa y ve con el médico y el entrenador de armas para obtener salúd y entrenamiento. El templo del Oráculo está en las fronteras, a las afueras de la ciudad.",,Trouve l'Oracle et demande lui où se trouvent les autres pièces du Sigil. Va chercher ta récompense chez le médecin et le maître d'armes pour de la santé et de l'entraînement. Le temple de l'Oracle se trouve dans les terrains vagues à l'extérieur de la ville. ,,,"オラクルに会いシジルの欠片の場所を尋ねろ。 +川の向こうにある城を目指しアーチウェイを左に曲がるのだ。","오라클을 찾아서 다른 시질 조각이 어디에 있는지 물어봐. 오라클은 도시 외곽에 있는 접경지 근처에 있어. 강을 넘은 뒤, 성 쪽으로 향하고 아치 밑의 통로를 통해 왼쪽으로 이동해.","Zoek het Orakel op en vraag het over de andere Sigil stukken. Het Orakel woont in de grensgebieden, net buiten de stad. Steek de rivier over, loop naar het kasteel en ga linksaf door de poort.","Oppsøk Orakelet og spør det om de andre Sigil-brikkene. Oraklet holder til i grenselandet, like utenfor byen. Kryss elven, gå mot slottet og gå til venstre gjennom buegangen.","Poszukaj Wyroczni i zapytaj ją o pozostałe kawałki Sigila. Wyrocznia rezyduje na pograniczu, tuż za miastem. Przejdź przez rzekę, skieruj się w stronę zamku i przejdź w lewo przez łuki.","Procure pelo Oráculo e pergunte a ele sobre as outras peças do Sigilo. O Oráculo mora nas fronteiras, no lado de fora da cidade. Atravesse o rio, vá em direção ao castelo e vá pela esquerda através do arco.",,"Găsește Oracolul și întreabă-l de piesele Sigiliului. Oracolul are reședința în mărginime, chiar la ieșirea din oraș. Trece râul, du-te spre castel și ia-o la stânga prin arcadă.","Найди Оракула и спроси его про другие фрагменты Печати. Резиденция Оракула находится в пограничье, сразу за городской чертой. Пересеки реку, иди в сторону крепости и сверни налево, пройдя через арку.",,"Sök upp Oraklet och fråga det om de andra Sigilbitarna. Oraklet befinner sig i gränslandet, strax utanför staden. Korsa floden, gå mot slottet och gå till vänster genom valvet.","Kahin'i bulun ve ona diğer Sigil parçalarını sorun. Kahin, şehrin hemen dışındaki sınır bölgelerinde bulunur. Nehri geçin, kaleye doğru gidin ve kemerden sola dönün." +"Seek out the Oracle and ask it about the other Sigil pieces. The Oracle's temple is in the borderlands, on the outskirts of town.",TXT_ILOG47,,,,"Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Věštcův chrám je v pohraničí, na okraji města.","Opsøg Oraklet og spørg det om de andre Sigil stykker. Oraklets tempel ligger i grænselandet, i udkanten af byen.","Suche das Orakel auf und befrage es bezüglich der anderen Teile des Sigils. Der Tempel des Orakels ist in den Grenzgebieten zu finden, in den Außenbezirken der Stadt.",,Serĉu la Orakolon kaj demandu al li pri la aliaj pecoj de la Sigelo. Li loĝas ekster la urbo en la limlando; ĝi estas apud la pordo de la kastelo.,Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Reside fuera del pueblo en las tierras fronterizas que están justo al lado de la puerta del castillo.,Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Reside afuera del pueblo en las tierras fronterizas que están justo al lado de la puerta del castillo.,Etsi Oraakkeli ja kysy häneltä muista Sinetin osista. Oraakkelin temppeli sijaitsee rajaseudulla kaupungin laitamilla.,Trouve l'Oracle et demande lui où se trouvent les autres pièces du Sigil. Le temple de l'Oracle se trouve dans les terrains vagues à l'extérieur de la ville. ,"Keresd fel az Orákulumot, és kérdezd ki a többi pecsét darabról. Az Orákulum a peremvidéken lakik, rögtön a város után.","Raggiungi l'Oracolo e chiedigli degli altri pezzi del Sigillo. Il tempio dell'Oracolo è nelle terre di confine, fuori città.","オラクルに会いシジルの欠片の場所を尋ねろ。 +オラクルは町外れの国境地帯にいる。",오라클을 찾고 다른 시질 조각에 관해 물어봐. 오라클의 신전은 도시 외곽의 접경지 근처에 있어.,"Zoek het Orakel op en vraag het over de andere Sigil stukken. De tempel van het Orakel ligt in het grensgebied, aan de rand van de stad.","Oppsøk oraklet og spør det om de andre Sigil-brikkene. Orakelets tempel ligger i grenselandet, i utkanten av byen.","Odszukaj Wyrocznię i zapytaj ją o inne kawałki Sigila. Świątynia Wyroczni znajduje się na pograniczu, na obrzeżach miasta.","Procure pelo Oráculo e pergunte a ele sobre as outras peças do Sigilo. Seu tempo está nas fronteiras, no lado de fora da cidade.",,"Găsește Oracolul și întreabă-l de piesele Sigiliului. Oracolul are reședința în mărginime, la ieșirea din oraș.","Найди Оракула и спроси его про другие фрагменты Печати. Храм Оракула расположен в пограничье, на окраине города.",,"Sök upp Oraklet och fråga det om de andra Sigilbitarna. Oraklets tempel ligger i gränslandet, i utkanten av staden.","Kahin'i bul ve ona diğer Sigil parçalarını sor. Kahin'in tapınağı sınır bölgelerinde, şehrin eteklerinde." +"Seek out the Oracle and ask it about the other Sigil pieces. Take your reward and go across to the medic and weapons trainer for health and training. The Oracle's temple is in the borderlands, on the outskirts of town.",TXT_ILOG48,"MAP10: After killing the Programmer, talking to Macil and moving a bit.",,,"Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Převezmi si svou odměnu a navštiv zdravotníka a učitele střelby pro zdraví a výcvik. Věštcův chrám je v pohraničí, na okraji města.","Opsøg Oraklet og spørg det om de andre Sigilstykker. Tag din belønning og gå over til lægen og våbentræneren for at få sundhed og træning. Oraklets tempel ligger i grænselandet, i udkanten af byen.","Suche das Orakel auf und befrage es bezüglich der anderen Teile des Sigils. Nimm deine Belohnung und suche den Sanitäter und den Waffentrainer auf. Der Tempel des Orakels ist in den Grenzgebieten zu finden, in den Außenbezirken der Stadt.",,Parolu kun la kuracisto kaj la armila trejnisto en la malsanulejo (Hospital). Serĉu la Orakolon kaj demandu al li pri la aliaj pecoj de la Sigelo: lia templo estas ekster la urbo en la limlando.,Habla con el médico y el entrenador de armas en el hospital. Busca al Oráculo y pregúntale sobre las otras piezas del Emblema: su templo está fuera del pueblo en las tierras fronterizas.,,Etsi Oraakkeli ja kysy häneltä muista Sinetin osista. Kerää palkkiosi ja hakeudu lääkintämiehen ja asekouluttajan luo terveydenhoitoa ja koulutusta varten. Oraakkelin temppeli sijaitsee rajaseudulla kaupungin laitamilla.,Trouve l'Oracle et demande lui où se trouvent les autres pièces du Sigil. Va chercher ta récompense chez le médecin et le maître d'armes pour de la santé et de l'entraînement. Le temple de l'Oracle se trouve dans les terrains vagues à l'extérieur de la ville. ,"Keresd fel az Orákulumot, és kérdezd ki a többi pecsét darabról. Vedd fel a jutalmad, majd ugorj át a szanitéchez és kiképzőhöz. Az Orákulum temploma a peremvidéken található, a város külvárosában.","Raggiungi l'Oracolo e chiedigli degli altri pezzi del Sigillo. Prendi la tua ricompensa e visita il dottore e l'addestratore di armi. Il tempio dell'Oracolo è nelle terre di confine, fuori città.","オラクルに会いシジルの欠片の場所を尋ねろ。 メディックと武器トレーナーに会い訓練と体力を強化せよ。 -オラクルは町外れの国境地帯にいる。",오라클을 찾아서 다른 시질 조각이 어디에 있는지 물어봐. 보상을 받고 치료와 훈련을 위해 의무관과 무기 담당관에게로 가. 오라클은 도시 외곽에 있는 접경지 근처에 있어.,"Zoek het Orakel op en vraag het over de andere Sigil stukken. Pak je beloning en ga naar de dokter en wapentrainer voor gezondheid en training. De tempel van het Orakel staat in de grensgebieden, aan de rand van de stad.",,"Procure pelo Oráculo e pergunte a ele sobre as outras peças do Sigilo. Pegue a sua recompensa e visite o médico e o treinador de armas para saúde e treinamento. O templo do Oráculo se encontra nas fronteiras, do lado de fora da cidade.",,,"Найди Оракула и спроси его про другие фрагменты Сигила. Возьми свою награду и зайди к медику и инструктору по стрельбе. Храм Оракула находится в пограничье, на окраине города.", -Seek out the Oracle's temple and ask it about the other Sigil pieces. Here it is. I'm recording everything. It's not that I don't have faith that you'll survive. It's just that we can't let the Order control the Sigil.,TXT_ILOG50,,,,"Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Tady to je. Nahrávám všechno, ne že bych neměla důvěru v tvé přežití, ale prostě nemůžeme dovolit Řádu ovládat Pečeť.","Suche das Orakel auf und befrage es bezüglich der anderen Teile des Sigils. Ich protokolliere alles. Ich glaube zwar schon daran, dass du überleben wirst, aber wir können es halt nicht zulassen, dass der Orden das Sigil kontrolliert.",,,Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Aquí está. Lo estoy grabando todo. No es que no tenga fe en tu supervivencia. Es solo que no podemos dejar que la Orden controle el Emblema.,Busca al Oráculo y pregúntale acerca de las otras piezas del Emblema. Aquí está. Estoy grabando todo. No es que no tenga fé en que vas a sobrevivir. Solo es que no podemos dejar que la Orden controle el Emblema.,,"Trouve l'Oracle et demande lui où se trouvent les autres pièces du Sigil. Le voilà. J'enregistre tout, ce n'est pas que je n'ai pas confiance en ta capacité de survie, c'est juste que je ne peux pas laisser l'Ordre contrôler le Sigil.",,,"オラクルに会いシジルの欠片の場所を尋ねろ。 +オラクルは町外れの国境地帯にいる。",오라클을 찾아서 다른 시질 조각이 어디에 있는지 물어봐. 보상을 받고 치료와 훈련을 위해 의무관과 무기 담당관에게로 가. 오라클은 도시 외곽에 있는 접경지 근처에 있어.,"Zoek het Orakel op en vraag het over de andere Sigil stukken. Pak je beloning en ga naar de dokter en wapentrainer voor gezondheid en training. De tempel van het Orakel staat in de grensgebieden, aan de rand van de stad.","Oppsøk oraklet og spør det om de andre Sigil-brikkene. Ta belønningen din og gå over til medisineren og våpentreneren for helse og trening. Orakelets tempel ligger i grenselandet, i utkanten av byen.","Poszukaj Wyroczni i zapytaj ją o inne kawałki Sigila. Weź nagrodę i udaj się do medyka i trenera broni po zdrowie i trening. Świątynia Wyroczni znajduje się na pograniczu, na obrzeżach miasta.","Procure pelo Oráculo e pergunte a ele sobre as outras peças do Sigilo. Pegue a sua recompensa e visite o médico e o treinador de armas para saúde e treinamento. O templo do Oráculo se encontra nas fronteiras, do lado de fora da cidade.",,Găsește Oracolul și întreabă-l de piesele Sigiliului. Ia-ți recompensa ți du-te la medic și antrenorul de arme. Templul Oracolului e în mărginimea orașului.,"Найди Оракула и спроси его про другие фрагменты Печати. Возьми свою награду и зайди к медику и инструктору по стрельбе. Храм Оракула находится в пограничье, на окраине города.",,"Sök upp Oraklet och fråga det om de andra Sigilbitarna. Ta din belöning och gå över till läkaren och vapentränaren för hälsa och träning. Oraklets tempel ligger i gränslandet, i utkanten av staden.","Kahin'i bul ve ona diğer Sigil parçalarını sor. Ödülünüzü alın ve sağlık ve eğitim için sıhhiyeciye ve silah eğitmenine gidin. Kahin'in tapınağı sınır bölgelerinde, kasabanın eteklerinde." +Seek out the Oracle's temple and ask it about the other Sigil pieces. Here it is. I'm recording everything. It's not that I don't have faith that you'll survive. It's just that we can't let the Order control the Sigil.,TXT_ILOG50,MAP11: Entrance to cave.,,,"Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Tady to je. Nahrávám všechno, ne že bych neměla důvěru v tvé přežití, ale prostě nemůžeme dovolit Řádu ovládat Pečeť.","Søg ud til Oraklets tempel og spørg det om de andre Sigil stykker. Her er det. Jeg optager alt. Det er ikke fordi jeg ikke tror på, at du vil overleve. Vi kan bare ikke lade Ordenen kontrollere Sigil.","Suche das Orakel auf und befrage es bezüglich der anderen Teile des Sigils. Ich protokolliere alles. Ich glaube zwar schon daran, dass du überleben wirst, aber wir können es halt nicht zulassen, dass der Orden das Sigil kontrolliert.",,"Serĉu la Orakolon kaj demandu al li pri la aliaj pecoj de la Sigelo. Jen la enirejo. Mi videoregistras ĉion; mi ne malfidas pri via supervivado, sed ni ne devas ebligi, ke La Ordeno regu la Sigelon.","Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Aquí está la entrada. Lo estoy grabando todo; no es que no tenga fe en tu supervivencia, es solo que no podemos dejar que La Orden controle el Emblema.",,"Etsi Oraakkeli ja kysy häneltä muista Sinetin osista. Tässä se on. Tallennan kaiken. Tässä ei ole kyse siitä, etteikö minulla olisi täysi luotto, että selviäisit. Emme vain voi antaa Veljeskunnan hallita Sinettiä.","Trouve l'Oracle et demande lui où se trouvent les autres pièces du Sigil. Le voilà. J'enregistre tout, ce n'est pas que je n'ai pas confiance en ta capacité de survie, c'est juste que je ne peux pas laisser l'Ordre contrôler le Sigil.","Keresd fel az Orákulumot a templomában, és kérdezd meg a pecsét többi darabjáról. Itt is van. Felveszek mindent. Nem mintha nem bíznék meg benned, csak nem akarom, hogy a Rend kezébe kerüljön a pecsét.",Raggiungi l'Oracolo e chiedigli degli altri pezzi del Sigillo. Ecco qua. Sto registrando tutto. Non è che non penso che sopravviverai. È solo che non possiamo lasciare che l'Ordine controlli il Sigillo.,"オラクルに会いシジルの欠片の場所を尋ねろ。 オラクルはこの場所にいる。私は全部記録している。 私は貴方が生き残る確証がないというわけではなく、 オーダーはシジルを操る事が出来ないというだけだ。 -","오라클의 신전을 찾아서 시질 조각이 어디에 있는지 물어봐. 그리고 지금 난 모든 걸 녹음하고 있어. 네가 살아남을 거라는 믿음을 버린게 아니라, 오더가 시질을 손에 잡게 내버려 둘 수가 없어서 말이야.",Zoek de tempel van het Orakel op en vraag het over de andere Sigil stukken. Hier is het. Ik ben alles aan het opnemen. Niet dat ik er niet op vertrouw dat je het zult overleven. Het is gewoon dat we de Orde de Sigil niet kunnen laten controleren door de Orde.,,"Procure pelo Oráculo e pergunte a ele sobre as outras peças do Sigilo. Certo, estou gravando tudo. Não é que eu não tenha fé de que você vá sobreviver. É só que não podemos deixar a Ordem controlar o Sigilo.",,,"Найди храм Оракула и спроси его про другие фрагменты Сигила. Так. Я всё записываю на плёнку. Это не потому, что я не верю, что ты уцелеешь. Просто мы не можем позволить Ордену заполучить Сигил.", -The second piece lies at the heart of the crimson and obsidian tower. There you will find the Bishop. The Bishop is the Order's military leader. We off him and we score twice. Take the Oracle's token to the key master in the borderlands.,TXT_ILOG56,,,,"Druhý díl leží v srdci věže karmínoobsidiánové. Tam najdeš Biskupa. Biskup je armádní vůdce Řádu. Plánuje jejich taktiky, velí jejich špiónům a má za úkol ovládat nás. Odděláme ho a zaskórujeme dvakrát.","Das zweite Stück liegt im Zentrum des Turms aus Purpur und Obsidian. Dort wirst du den Bischof, den militärischen Anführer des Ordens, finden. Wenn wir ihn kalt machen, können wir zwei Fliegen mit einer Klappe schlagen. Nimm das Zeichen des Orakels und bringe es zum Schlüsselmeister in den Grenzgebieten.",,,La segunda pieza se encuentra en el corazón e la torre carmesí y obsidiana. Ahí encontrarás al Obispo. El Obispo es el líder militar de la Orden. Nos lo cargamos y marcamos dos puntos. Lleva el vale del Oráculo al amo de llaves en las fronteras.,La segunda pieza está en el corazón de la torre carmesí y obsidiana. Ahí deberás encontrar al Obispo. El Obispo es el líder militar de la Orden. Acabamos con él y anotamos doble. Lleva el símbolo del Oráculo al Amo de Llaves en las fronteras.,,"La deuxième pièce se trouve au cœur de la tour d'obsidienne et d'écarlate. Tu y trouvera l'évêque. L'évêque est le chef militaire de l'Ordre. Si on le tue, on marque deux points. Prends le jeton de l'Oracle et amène le au Mâitre des Clés dans les terrains vagues. ",,,"二つ目の欠片は深紅と黒曜石の塔にある。そこでビショップを見つけろ。 +","오라클의 신전을 찾아서 시질 조각이 어디에 있는지 물어봐. 그리고 지금 난 모든 걸 녹음하고 있어. 네가 살아남을 거라는 믿음을 버린게 아니라, 오더가 시질을 손에 잡게 내버려 둘 수가 없어서 말이야.",Zoek de tempel van het Orakel op en vraag het over de andere Sigil stukken. Hier is het. Ik ben alles aan het opnemen. Niet dat ik er niet op vertrouw dat je het zult overleven. Het is gewoon dat we de Orde de Sigil niet kunnen laten controleren door de Orde.,Oppsøk Orakelets tempel og spør det om de andre seglbitene. Her er det. Jeg tar opp alt. Det er ikke det at jeg ikke har tro på at du overlever. Men vi kan ikke la Ordenen kontrollere seglet.,"Poszukaj świątyni Wyroczni i zapytaj ją o inne kawałki Sigila. Oto on. Nagrywam wszystko. Nie chodzi o to, że nie wierzę, że przeżyjesz. Po prostu nie możemy pozwolić Zakonowi kontrolować Sigilu.","Procure pelo Oráculo e pergunte a ele sobre as outras peças do Sigilo. Certo, estou gravando tudo. Não é que eu não tenha fé de que você vá sobreviver. É só que não podemos deixar a Ordem controlar o Sigilo.",,"Găsește Oracolul și întreabă de celelalte piese ale Sigiliului. Aici este. Înregistrez totul. Nu e vorba că nu am încredere că vei supraviețui, dar nu putem lăsa Ordinul ca ia Sigiliul.","Найди храм Оракула и спроси его про другие фрагменты Печати. Так. Я всё записываю на плёнку. Это не потому, что я не верю, что ты уцелеешь. Просто мы не можем позволить Ордену заполучить Печать.",,Sök upp Orakelns tempel och fråga det om de andra Sigillbitarna. Här är den. Jag spelar in allting. Det är inte så att jag inte tror att du kommer att överleva. Det är bara det att vi inte kan låta Orden kontrollera Sigillet.,Kahin'in tapınağını bulun ve ona diğer Sigil parçalarını sorun. İşte burada. Her şeyi kaydediyorum. Hayatta kalacağınıza inanmadığımdan değil. Sadece Düzen'in Sigil'i kontrol etmesine izin veremeyiz. +The second piece lies at the heart of the crimson and obsidian tower. There you will find the Bishop. The Bishop is the Order's military leader. We off him and we score twice. Take the Oracle's token to the key master in the borderlands.,TXT_ILOG56,MAP12: After talking to the Oracle.,,,"Druhý díl leží v srdci věže karmínoobsidiánové. Tam najdeš Biskupa. Biskup je armádní vůdce Řádu. Plánuje jejich taktiky, velí jejich špiónům a má za úkol ovládat nás. Odděláme ho a zaskórujeme dvakrát.","Den anden del ligger i hjertet af det purpurfarvede og obsidianske tårn. Der vil du finde biskoppen. Biskoppen er ordenens militære leder. Hvis vi dræber ham, scorer vi to gange. Tag Oraklets token til nøglemesteren i grænselandet.","Das zweite Stück liegt im Zentrum des Turms aus Purpur und Obsidian. Dort wirst du den Bischof, den militärischen Anführer des Ordens, finden. Wenn wir ihn kalt machen, können wir zwei Fliegen mit einer Klappe schlagen. Nimm das Zeichen des Orakels und bringe es zum Schlüsselmeister in den Grenzgebieten.",,La dua peco situas en la koro de la turo karmezina kaj obsidiankolora: tie estas la Episkopo la militestro. Ni mortigu lin: du poentojn. Portu la paspermeson de la Orakolo al la ŝlosilestro en la limlando.,La segunda pieza está en el corazón de la torre carmesí y obsidiana: allí está el Obispo el líder militar de La Orden. Nos lo cargamos y marcamos dos puntos. Lleva el pase del Oráculo al amo de llaves en las tierras fronterizas.,La segunda pieza está en el corazón de la torre carmesí y obsidiana: allá está el Obispo el líder militar de La Orden. Lo matamos y premios dobles. Llévale el pase del Oráculo al amo de llaves en las tierras fronterizas.,"Toinen osanen piilee purppuranpunaisen laavalasisen tornin sydämessä. Löydät sieltä Piispan, Veljeskunnan sotapäällikön. Teemme hänestä lopun ja pokkaamme kaksi pistettä. Toimita Oraakkelin merkki avainmestarille rajaseudulla.","La deuxième pièce se trouve au cœur de la tour d'obsidienne et d'écarlate. Tu y trouvera l'évêque. L'évêque est le chef militaire de l'Ordre. Si on le tue, on marque deux points. Prends le jeton de l'Oracle et amène le au Mâitre des Clés dans les terrains vagues. ","A második darab a karmazsin és obszidián torony szívében található. Ott fogod megtalálni a Püspököt. A Püspök a Rend katonai vezetője. Ha kiiktatjuk, duplán nyerünk. Vidd az Orákulum zálogát a kulcsmesterhez, aki a peremvidéken van.",Il secondo pezzo si trova nel cuore della torre cremisina e ossidiana. Lì troverai il Vescovo. Il Vescovo è il capo militare dell'Ordine. Farlo fuori sarebbe un enorme vantaggio. Raggiungi il mastro delle chiavi nelle terre di confine con il pass che ti ha dato l'Oracolo.,"二つ目の欠片は深紅と黒曜石の塔にある。そこでビショップを見つけろ。 ビショップはオーダーの軍事指揮官だ。奴を討ち破り欠片を手に入れろ。 -国境地帯のキーマスターにオラクルのトークンを見せよ。",두 번째 시질 조각은 진홍빛 흑요석 탑에 숨어있는 비숍에게 있어. 비숍은 그들의 잔혹한 군사 지도자이지. 거기에 녀석이 있을 거야. 그를 죽이면 두 배로 이득이 갈 거야. 이 통행증을 들고 접경지 안의 열쇠지기에게로 가봐.,Het tweede stuk ligt in het hart van de karmozijnrode en obsidiaan toren. Daar vindt u de bisschop. De bisschop is de militaire leider van de Orde. We gaan van hem af en we scoren twee keer. Neem de orakels van de Orakel mee naar de sleutelmeester in de grensgebieden.,,A segunda peça está no coração da torre carmesin e obsidiana. Lá você encontrará o Bispo. Ele é o líder militar da Ordem. Nós apagamos ele e serão dois coelhos numa tacada só. Leve o emblema do Oráculo para o mestre das chaves nas fronteiras.,,,Второй фрагмент лежит в сердце багрово-обсидиановой башни. Там ты сразишься с Епископом. Епископ — военный лидер Ордена. От его убийства мы выигрываем вдвойне. Отнеси жетон Оракула ключнику в пограничье., -"The Bishop is going to be heavily guarded, so why don't we swipe a uniform and blend in? Locate the Bishop. Once you have destroyed him, return to the Oracle.",TXT_ILOG57,,,,"Biskup bude silně strážen, co takhle sebrat uniformu a splynout s davem? Najdi Biskupa. Až ho zabiješ, vrať se k Věštci.","Der Bischof wird schwer bewacht sein, also warum besorgen wir uns nicht eine Uniform und mischen uns unter seine Leute? Finde den Bischof. Wenn du ihn vernichtet hast, kehre zum Orakel zurück.",,,"El Obispo estará fuertemente protegido, así que ¿por qué no robamos un uniforme y nos mezclamos? Localiza al Obispo. Una vez lo hayas destruído, vuelve con el Oráculo.","El Obispo estará fuertemente resguardado, así que, ¿Porque no robamos el uniforme de un guardia y nos mezclamos? Localiza al Obispo. Una vez que lo destruyas, regresa con el Oráculo.",,"L'évêque sera lourdement protégé. Pourquoi ne pas faire une entrée discrète avec un uniforme? Trouve l'évêque, une fois qu'il est mort, retourne à l'Oracle.",,,"ビショップのいる場所の警備は厳重なので、 +国境地帯のキーマスターにオラクルのトークンを見せよ。",두 번째 시질 조각은 진홍빛 흑요석 탑에 숨어있는 비숍에게 있어. 비숍은 그들의 잔혹한 군사 지도자이지. 거기에 녀석이 있을 거야. 그를 죽이면 두 배로 이득이 갈 거야. 이 통행증을 들고 접경지 안의 열쇠지기에게로 가봐.,Het tweede stuk ligt in het hart van de karmozijnrode en obsidiaan toren. Daar vindt u de bisschop. De bisschop is de militaire leider van de Orde. We gaan van hem af en we scoren twee keer. Neem de orakels van de Orakel mee naar de sleutelmeester in de grensgebieden.,"Den andre biten ligger i hjertet av det purpurfargede og obsidianske tårnet. Der finner du biskopen. Biskopen er Ordenens militære leder. Dreper vi ham, scorer vi to ganger. Ta oraklets symbol til nøkkelmesteren i grenselandene.",Drugi kawałek leży w sercu karmazynowej i obsydianowej wieży. Znajdziesz tam Biskupa. Biskup jest przywódcą wojskowym Zakonu. Wyłączamy go i zdobywamy dwa razy punkty. Zabierz żeton Wyroczni do mistrza kluczy na pograniczu.,A segunda peça está no coração da torre carmesin e obsidiana. Lá você encontrará o Bispo. Ele é o líder militar da Ordem. Nós apagamos ele e serão dois coelhos numa tacada só. Leve o emblema do Oráculo para o mestre das chaves nas fronteiras.,,A doua piesă e în inima turnului stăveziu din obsidian. Episcopul e liderul miltar ar Ordinului. Îl omorâm și înscriem de două ori. Ia semnul Oracolului la stăpânul cheii în mărginime.,Второй фрагмент лежит в сердце багрово-обсидиановой башни. Там ты сразишься с Епископом. Епископ — военный лидер Ордена. От его убийства мы выигрываем вдвойне. Отнеси жетон Оракула ключнику в пограничье.,,Den andra delen ligger i hjärtat av det karmosinröda och obsidianska tornet. Där hittar du biskopen. Biskopen är ordens militära ledare. Om vi dödar honom gör vi två poäng. Ta Orakelns token till nyckelmästaren i gränslandet.,İkinci parça kızıl ve obsidyen kulenin kalbinde yatıyor. Orada Piskopos'u bulacaksın. Piskopos Tarikat'ın askeri lideri. Onu yok edersek iki puan alırız. Kahin'in simgesini sınır bölgelerindeki anahtar ustasına götürün. +"The Bishop is going to be heavily guarded, so why don't we swipe a uniform and blend in? Locate the Bishop. Once you have destroyed him, return to the Oracle.",TXT_ILOG57,MAP11: Officer's uniform room.,,,"Biskup bude silně strážen, co takhle sebrat uniformu a splynout s davem? Najdi Biskupa. Až ho zabiješ, vrať se k Věštci.","Biskoppen vil være stærkt bevogtet, så hvorfor stjæler vi ikke en uniform og blander os i mængden? Find biskoppen. Når du har udslettet ham, vender du tilbage til Oraklet.","Der Bischof wird schwer bewacht sein, also warum besorgen wir uns nicht eine Uniform und mischen uns unter seine Leute? Finde den Bischof. Wenn du ihn vernichtet hast, kehre zum Orakel zurück.",,"La Episkopo havas multe da sekureco. Kio pri ŝteli uniformon kaj miksiĝi? Trovu la Episkopon, mortigu lin kaj reiru al la Orakolo.","El Obispo tiene mucha seguridad. ¿Y si robamos un uniforme y nos mezclamos? Encuentra al Obispo, mátalo y vuelve con el Oráculo.",,"Piispa on tarkoin vartioitu, joten kähvellettäisiinkö univormu ja sulauduttaisiin joukkoon? Paikallista Piispa. Tuhottuasi hänet palaa Oraakkelin luo.","L'évêque sera lourdement protégé. Pourquoi ne pas faire une entrée discrète avec un uniforme? Trouve l'évêque, une fois qu'il est mort, retourne à l'Oracle.","A Püspököt elég erősen védik, ezért ajánlott, hogy szerválj magadnak egy uniformist a beolvadás végett. Találd meg a Püspököt. Ha megölted, térj vissza az Orákulumhoz.","Il Vescovo sarà sicuramente ben protetto, quindi perché non camuffarsi con un'uniforme? Trova il Vescovo. Dopo averlo distrutto, ritorna dall'Oracolo.","ビショップのいる場所の警備は厳重なので、 奴等の制服を盗み紛れ込む方が良いのでは? -ビショップを探し、始末したらオラクルの元へ戻ろう。","비숍은 군사 지도자니까, 삼엄한 경비에 의해 지켜질 거야. 그러니 전투복을 입고 잠입하는 게 어때? 비숍을 찾아서, 그를 파괴하고 오라클에게 찾아가 봐.","De bisschop zal zwaar bewaakt worden, dus waarom vegen we er niet een uniform overheen en mengen we ons in de bisschop? Zoek de bisschop. Als je hem hebt vernietigd, keer je terug naar het Orakel.",,"O Bispo estará protegido por vários guardas, então que tal roubar um uniforme e se mesclar a eles? Localize o Bispo. Assim que você destruí-lo, volte ao Oráculo.",,,"Похоже, что Епископа неплохо охраняют, так что почему бы нам не стянуть униформу и прокрасться внутрь? Найди Епископа. После того, как ты уничтожишь его, возвращайся к Оракулу.", -"I just got word that we have an informer inside the fortress. Let's head for the hospital. He works there. After that, locate the Bishop and destroy him. Once he's dead return to the Oracle.",TXT_ILOG59,,,,"Právě jsem dostala zprávu, že máme v pevnosti informátora. Měli bychom zamířit k nemocnici, pracuje tam. Poté najdi Biskupa. Až ho zabiješ, vrať se k Věštci.","Mir ist gerade zu Ohren gekommen, dass wir einen Informanten in der Festung haben. Lasst uns zum Krankenhaus gehen, er arbeitet dort. Danach finde den Bischof unz vernichte ihn. Sobald er tot ist kehre zum Orakel zurück.",,,"Acaban de decirme que tenemos un informante dentro de la fortaleza. Vayamos al hospital. Trabaja allí. Después, localiza al Obispo y destrúyelo. Una vez muerto, vuelve con el Oráculo.","Acaban de decirme que tenemos un informante adentro de la fortaleza. Dirijámonos al hospital. Él trabaja ahí. Después, localiza al Obispo y destruyelo. Cuando esté muerto, regresa con el Oráculo.",,"Je viens d'avoir vent que l'on a un informant dans la forteresse. Allons à l'hôpital, il y travaille. Après ça, trouve l'évêque et tue-le, puis retourne à l'Oracle.",,,"要塞の中に情報提供者がいるという話を聞いた。 -奴等が病院と呼んでいる場所に勤めているので向かいましょう。","요새 안에 우리들을 도울 정보원이 있다는 보고를 들었어. 그는 병원 안에 있는데, 그곳으로 찾아가 봐. 만난 뒤엔 비숍을 찾은 뒤 그를 파괴하고 오라클에게 찾아가 봐.","Ik heb net vernomen dat we een informant in het fort hebben. Laten we naar het ziekenhuis gaan. Hij werkt daar. Zoek daarna de bisschop en vernietig hem. Als hij dood is, ga dan terug naar het Orakel.",,"Acabei de saber que temos um informante dentro da fortaleza. Vamos ao hospital. Ele trabalha lá. Após isso, localize o Bispo e destrua-o. Assim que ele morrer retorne ao Oráculo.",,,"Мне только что сказали, что у нас есть информатор внутри крепости. Идём к госпиталю — он работает там. Затем найди Епископа и убей его. После его смерти вернись к Оракулу.", -"Don't give up. This is it. Straight ahead. Jump on the teleporter to central administration and destroy the computer core. This will kill the force field on the entrance to the Bishop's tower. Once he's dead, return to the Oracle.",TXT_ILOG64,,,,"Nevzdávej se, tohle je ono. Jdi rovně. Skoč na teleportér do centrálního velení a znič počítačové jádro. To zruší silové pole u vchodu do Biskupovy věže. Až ho zabiješ, vrať se k Věštci.",Nicht aufgeben. Da ist es. Direkt voraus. Springe auf den Teleporter zur Zentralverwaltung und zerstöre den Kern des Computers. Das wird das Kraftfeld zum Eingang des Turms des Bischofs lahmlegen. Sobald er tot ist kehre zum Orakel zurück.,,,"No te rindas. Aquí es. Justo de frente. Entra al teletransporte a la administración central y destruye el núcleo de la computadora. Esto apagará el campo de fuerza en la entrada a la torre del Obispo. Una vez muerto, vuelve con el Oráculo.","No re rindas. Aquí está. Justo enfrente. Entra al teleporte a la Administración Central y destruye el núcleo de la computadora. Esto quitará el campo de fuerza a la entrada de la torre del Obispo. Cuando esté muerto, regresa con el Oráculo.",,"N'abandonne pas, on y est bientôt. Utilise le téléporteur vers le centre d'administration et détruis le cœur informatique. Cela désactivera le champ de force et l'entrée vers la tour de l'évêque. Une fois qu'il est mort, retourne voir l'Oracle.",,,"諦めないで。これでいいんだ。真っ直ぐ行こう。 +ビショップを探し、始末したらオラクルの元へ戻ろう。","비숍은 군사 지도자니까, 삼엄한 경비에 의해 지켜질 거야. 그러니 전투복을 입고 잠입하는 게 어때? 비숍을 찾아서, 그를 파괴하고 오라클에게 찾아가 봐.","De bisschop zal zwaar bewaakt worden, dus waarom vegen we er niet een uniform overheen en mengen we ons in de bisschop? Zoek de bisschop. Als je hem hebt vernietigd, keer je terug naar het Orakel.","Biskopen kommer til å være tungt bevoktet, så hvorfor tar vi ikke en uniform og smelter inn? Finn biskopen. Når du har tilintetgjort ham, gå tilbake til oraklet.","Biskup będzie pilnie strzeżony, więc może weźmiemy mundur i wtopimy się w tłum? Zlokalizuj Bishopa. Kiedy już go zniszczysz, wróć do Wyroczni.","O Bispo estará protegido por vários guardas, então que tal roubar um uniforme e se mesclar a eles? Localize o Bispo. Assim que você destruí-lo, volte ao Oráculo.",,"Episcopul o să fie extrem de bine înarmat, deci de ce nu strecurăm o uniformă ca să ne camuflăm? Găsește Episcopul. Odată ce l-ai distrus, întoarce-te la Oracol.","Похоже, что Епископа неплохо охраняют, так что почему бы нам не стянуть униформу и прокрасться внутрь? Найди Епископа. После того, как ты уничтожишь его, возвращайся к Оракулу.",,"Biskopen kommer att vara tungt bevakad, så varför inte sno en uniform och smälta in? Leta upp biskopen. När du har förintat honom återvänder du till oraklet.","Piskopos çok sıkı korunuyor olacak, o yüzden neden bir üniforma çalıp aralarına karışmıyoruz? Piskoposu bulun. Onu yok ettikten sonra Kahin'e dönün." +"I just got word that we have an informer inside the fortress. Let's head for the hospital. He works there. After that, locate the Bishop and destroy him. Once he's dead return to the Oracle.",TXT_ILOG59,MAP17: Bailey → Upstairs.,,,"Právě jsem dostala zprávu, že máme v pevnosti informátora. Měli bychom zamířit k nemocnici, pracuje tam. Poté najdi Biskupa. Až ho zabiješ, vrať se k Věštci.","Jeg har lige fået at vide, at vi har en stikker inde i fæstningen. Lad os tage til hospitalet. Han arbejder der. Derefter skal du finde biskoppen og ødelægge ham. Når han er død, skal du vende tilbage til Oraklet.","Mir ist gerade zu Ohren gekommen, dass wir einen Informanten in der Festung haben. Lasst uns zum Krankenhaus gehen, er arbeitet dort. Danach finde den Bischof unz vernichte ihn. Sobald er tot ist kehre zum Orakel zurück.",,"Mi ĵus estis sciigita, ke ni havas informanton en la fortreso: ni iru al la malsanulejo (Hospital) lia laborejo. Vi tiam trovu la Episkopon, mortigu lin kaj reiru al la Orakolo.","Acaban de decirme que tenemos un informante dentro de la fortaleza: vayamos al hospital, que es donde trabaja. Luego encuentra al Obispo, mátalo y vuelve con el Oráculo.","Acaban de decirme que tenemos un informante adentro de la fortaleza: vayamos al hospital, que es donde trabaja. Luego encuentra al Obispo, mátalo y vuelve con el Oráculo.","Sain juuri tiedon ilmiantajasta linnoituksessa. Matkataan sairaalaan; hän työskentelee siellä. Sen jälkeen löydä Piispa ja tuhoa hänet. Kun hän on kuollut, palaa Oraakkelin luo.","Je viens d'avoir vent que l'on a un informant dans la forteresse. Allons à l'hôpital, il y travaille. Après ça, trouve l'évêque et tue-le, puis retourne à l'Oracle.","Most kaptam a hírt, hogy van egy belső emberünk az erődítményben. Menjünk a kórházba. Ott dolgozik. Azután találd meg a Püspököt, és öld meg. Ha meghalt, menj az Orákulumhoz.","Ho appena scoperto che abbiamo un informatore dentro la fortezza. Rechiamoci all'ospedale. Lui lavora là. Dopodiché, trova il Vescovo e distruggilo. Non appena è morto, torna dall'Oracolo.","要塞の中に情報提供者がいるという話を聞いた。 +奴等が病院と呼んでいる場所に勤めているので向かいましょう。","요새 안에 우리들을 도울 정보원이 있다는 보고를 들었어. 그는 병원 안에 있는데, 그곳으로 찾아가 봐. 만난 뒤엔 비숍을 찾은 뒤 그를 파괴하고 오라클에게 찾아가 봐.","Ik heb net vernomen dat we een informant in het fort hebben. Laten we naar het ziekenhuis gaan. Hij werkt daar. Zoek daarna de bisschop en vernietig hem. Als hij dood is, ga dan terug naar het Orakel.","Jeg fikk nettopp beskjed om at vi har en informant inne i festningen. La oss dra til sykehuset. Han jobber der. Etter det, finn biskopen og drep ham. Når han er død, gå tilbake til Orakelet.","Właśnie dostałem wiadomość, że mamy informatora w twierdzy. Jedźmy do szpitala. On tam pracuje. Po tym zlokalizuj Bishopa i zniszcz go. Gdy będzie martwy, wróć do Wyroczni.","Acabei de saber que temos um informante dentro da fortaleza. Vamos ao hospital. Ele trabalha lá. Após isso, localize o Bispo e destrua-o. Assim que ele morrer retorne ao Oráculo.",,"Tocmai am primit informație că avem un informator în fortăreață. Să mergem către spital. Acolo lucrează. După aceea, să îl găsim pe Episcop și să-l eliminăm. Odată ce e mort întoarce-te la Oracol.","Мне только что сказали, что у нас есть информатор внутри крепости. Идём к госпиталю — он работает там. Затем найди Епископа и убей его. После его смерти вернись к Оракулу.",,Jag fick just veta att vi har en informatör inne i fästningen. Vi går till sjukhuset. Han jobbar där. Efter det ska du lokalisera biskopen och förgöra honom. När han är död återvänder du till oraklet.,"Az önce kalenin içinde bir muhbirimiz olduğu haberini aldım. Hastaneye gidelim. Orada çalışıyor. Ondan sonra, Piskoposu bulun ve onu yok edin. O öldükten sonra Kahin'e dönün." +"Don't give up. This is it. Straight ahead. Jump on the teleporter to central administration and destroy the computer core. This will kill the force field on the entrance to the Bishop's tower. Once he's dead, return to the Oracle.",TXT_ILOG64,MAP19: Last room (southwestern).,,,"Nevzdávej se, tohle je ono. Jdi rovně. Skoč na teleportér do centrálního velení a znič počítačové jádro. To zruší silové pole u vchodu do Biskupovy věže. Až ho zabiješ, vrať se k Věštci.","Du må ikke give op. Nu gælder det. Lige fremad. Hop på teleporteren til centraladministrationen og ødelæg computerkernen. Dette vil dræbe kraftfeltet ved indgangen til Bishop's tårn. Når han er død, skal du vende tilbage til Oraklet.",Nicht aufgeben. Da ist es. Direkt voraus. Springe auf den Teleporter zur Zentralverwaltung und zerstöre den Kern des Computers. Das wird das Kraftfeld zum Eingang des Turms des Bischofs lahmlegen. Sobald er tot ist kehre zum Orakel zurück.,,"Uzu la teleportilon al la centra administrejo kaj detruu la kernon de la komputilo, kiu tenas la fortokampon ĉe la enirejo de la turo de la Episkopo. Mortiginte lin, reiru al la Orakolo.","Entra en el teletransportador a la administración central y destruye el núcleo del ordenador que mantiene el campo de fuerza en la entrada de la torre del Obispo. Una vez muerto, vuelve con el Oráculo.","Entra al teletransportador a la administración central y destruye el núcleo de la computadora que mantiene el campo de fuerza en la entrada de la torre del Obispo. Una vez muerto, vuelve con el Oráculo.","Älä luovuta. Se on nyt tässä, suoraan edessä. Astu keskushallintoon johtavaan kaukosiirtimeen ja tuhoa keskustietokone. Se sammuttaa Piispan tornin voimakentän. Kun hän on kuollut, palaa Oraakkelin luo.","N'abandonne pas, on y est bientôt. Utilise le téléporteur vers le centre d'administration et détruis le cœur informatique. Cela désactivera le champ de force et l'entrée vers la tour de l'évêque. Une fois qu'il est mort, retourne voir l'Oracle.","Ne add fel. Már a célegyenesben vagyunk, rögtön előttünk van. A teleportot használva menj a központi irányításhoz és semmisítsd meg a számítógép magot. Ez majd kikapcsolja a Püspök tornyának bejárati erőpajzsát. Ha megölted, térj vissza az Orákulumhoz.","Non arrenderti. Siamo arrivati. Dritto in fronte a te. Entra in questo teletrasporto per l'amministrazione centrale e distruggi il nucleo del computer. Questo disattiverà il campo di forza per l'ingresso della torre del Vescovo. Non appena è morto, torna dall'Oracolo","諦めないで。これでいいんだ。真っ直ぐ行こう。 中央管理室のテレポーターに入りコンピューターコアを破壊せよ。 それはビショップのフォースフィールドを殺せる。 -ビショップも殺したらオラクルの元へ戻れ。",포기하지 마. 이제 거의 다 왔어. 저 텔레포터를 올라타서 관리소로 가서 컴퓨터 중심부를 파괴해. 방어막을 완전히 꺼버리고 비숍을 죽일 수 있을 거야. 그를 파괴하고 오라클에게 찾아가 봐.,"Geef niet op. Dit is het. Rechtdoor. Spring op de teleporter naar de centrale administratie en vernietig de computerkern. Dit zal het krachtveld op de ingang van de Bisschopstoren doden. Als hij dood is, keer je terug naar het Orakel.",,Não desista. A hora é agora. Siga reto adiante. Entre no teletransportador para a administração central e destrua o núcleo de computação. Isso vai derrubar o campo de força na entrada da torre do Bispo. Assim que ele morrer retorne ao Oráculo.,,,"Не падай духом. Вот оно. Прямо впереди. Прыгай в телепорт к центральной администрации и уничтожь центральный компьютер. Это отключит силовое поле на входе в башню Епископа. После его смерти, возвращайся к Оракулу.", -"Very impressive. Lets blow it up. That should take care of the force field. Let's get back to the bailey, then off to the tower and the Bishop.",TXT_ILOG70,,,,Velmi působivé. Co to nechat vybouchnout? To by se mělo postarat o silové pole. Vraťme se zpět do opevnění a tam do věže a k Biskupovi.,"Sehr eindrucksvoll. Lass es uns in die Luft jagen. Damit sollte das Kraftfeld ausgeschaltet sein. Lass uns zum Vorhof zurückkehren, dann zum Turm und dem Bischof.",,,"Muy impresionante. Vamos a volarlo. Eso debería ocuparse del campo de fuerza. Volvamos a la muralla, luego derechos a la torre y al Obispo.","Muy Impresionante. Vamos a volarlo. Eso debería de encargárse del campo de fuerza. Luego regresemos al Patio, luego a la torre y al Obispo.",,"Excellent, maintenant, faisons tout sauter. Cela devrait nous débarasser du cœur informatique. Retourne au mur d'enceinte puis rentre dans la tour de l'évêque.",,,"あら、見事な物ね。是非とも火薬を献上しましょう。 -それでベイリーに戻ってフォースフィールドが守っていたビショップの塔へ向かおう。",아주 인상 깊은데? 어서 파괴하자고. 그러면 방어막을 끌 수 있을 거야. 그 후에 안뜰로 향해서 성으로 찾아가. 그리고 비숍을 죽여버려.,"Zeer indrukwekkend. Laten we het opblazen. Dat zou voor het krachtveld moeten zorgen. Laten we teruggaan naar de bailey, dan naar de toren en de bisschop.",,Impressionante mesmo. Vamos detoná-lo. Isso deve dar um jeito no campo de força. Volte para a fortaleza e depois vá para a torre encontrar o Bispo.,,,"Очень впечатляюще. Давай взорвём. Это должно избавить нас от проблем с силовым полем. Возвращаемся во внутренний двор, затем к башне и Епископу.", -"Bravo, another piece of the Sigil! Did you see that weird spectre that came out of the Bishop's body? Where have I seen that before? Let's get back to the Oracle.",TXT_ILOG74,,,,"Bravo, další díl Pečetě! Viděl jsi ten divný přízrak, který vyšel z Biskupova těla? Kde jsem ho jen předtím viděla? Vraťme se k Věštci.","Gratulation, ein weiteres Teil des Sigils! Hast du den merkwürdigen Schemen gesehen, der aus dem Körper des Bischofs herauskam? Wo habe ich ihn bloß schon einmal gesehen? Lass uns zum Orakel zurückkehren.",,,"¡Bravo, otra pieza del Emblema! ¿Viste ese extraño espectro que salió del cuerpo del Obispo? ¿Donde he visto eso antes? Volvamos con el Oráculo.","¡Bravo, otra pieza del Emblema! ¿Viste ese extraño espectro que salió del cuerpo del Obispo? ¿Dónde he visto eso antes? Regresemos con el Oráculo.",,"Bravo, encore une pièce du Sigil! Tu a vu ce spectre étrange qui est sorti du corps de l'évêque? Je crois l'avoir vu avant, retournons à l'Oracle.",,,"ブラボー!新たなるシジルの欠片だ! +ビショップも殺したらオラクルの元へ戻れ。",포기하지 마. 이제 거의 다 왔어. 저 텔레포터를 올라타서 관리소로 가서 컴퓨터 중심부를 파괴해. 방어막을 완전히 꺼버리고 비숍을 죽일 수 있을 거야. 그를 파괴하고 오라클에게 찾아가 봐.,"Geef niet op. Dit is het. Rechtdoor. Spring op de teleporter naar de centrale administratie en vernietig de computerkern. Dit zal het krachtveld op de ingang van de Bisschopstoren doden. Als hij dood is, keer je terug naar het Orakel.","Ikke gi opp. Her er det. Rett frem. Hopp på teleporteren til sentraladministrasjonen og ødelegg datakjernen. Dette vil drepe kraftfeltet ved inngangen til biskopens tårn. Når han er død, gå tilbake til Oraklet.","Nie poddawaj się. To jest to. Prosto przed siebie. Wskocz na teleporter do centralnej administracji i zniszcz rdzeń komputera. To zabije pole siłowe przy wejściu do wieży biskupa. Gdy będzie już martwy, wróć do Oracle.",Não desista. A hora é agora. Siga reto adiante. Entre no teletransportador para a administração central e destrua o núcleo de computação. Isso vai derrubar o campo de força na entrada da torre do Bispo. Assim que ele morrer retorne ao Oráculo.,,"Nu te da bătut. Drept în față. Sari pe teleportorul către administrația centrală și distruge nucleul calculatoarelor. Asta va distruge câmpul de forță la intrarea în turnul Episcopului. Odată ce e mort, întoarce-te la Oracol.","Не падай духом. Вот оно. Прямо впереди. Прыгай в телепорт к центральной администрации и уничтожь центральный компьютер. Это отключит силовое поле на входе в башню Епископа. После его смерти, возвращайся к Оракулу.",,Ge inte upp. Det här är det. Rakt fram. Hoppa på teleportern till centraladministrationen och förstör datorkärnan. Detta kommer att döda kraftfältet vid ingången till biskopens torn. När han är död återvänder du till oraklet.,"Sakın pes etmeyin. İşte burası. Dümdüz ilerleyin. Merkezi yönetime giden ışınlayıcıya atla ve bilgisayar çekirdeğini yok et. Bu, Piskopos'un kulesinin girişindeki güç alanını yok edecek. O öldükten sonra Kahin'e dönün." +"Very impressive. Lets blow it up. That should take care of the force field. Let's get back to the bailey, then off to the tower and the Bishop.",TXT_ILOG70,MAP15: After pressing the switch to reveal the computer.,,,Velmi působivé. Co to nechat vybouchnout? To by se mělo postarat o silové pole. Vraťme se zpět do opevnění a tam do věže a k Biskupovi.,Meget imponerende. Lad os sprænge det i luften. Det burde tage sig af kraftfeltet. Lad os komme tilbage til borggården og derefter hen til tårnet og biskoppen.,"Sehr eindrucksvoll. Lass es uns in die Luft jagen. Damit sollte das Kraftfeld ausgeschaltet sein. Lass uns zum Vorhof zurückkehren, dann zum Turm und dem Bischof.",,"Detruu la komputilon; tio devus forigi la fortokampon. Reiru al la korto, eniru la turon kaj serĉu la Episkopon.","Destruye el ordenador; eso debería deshacerse del campo de fuerza. Volvamos al patio, luego directo a la torre y al Obispo.","Destruye la computadora; eso debería deshacerse del campo de fuerza. Volvamos al patio, luego directo a la torre y al Obispo.","Aika vaikuttava. Posautetaan se. Sillä voimakentän pitäisi hoitua. Palataan linnanpihaan, josta sitten torniin Piispan luo.","Excellent, maintenant, faisons tout sauter. Cela devrait nous débarasser du cœur informatique. Retourne au mur d'enceinte puis rentre dans la tour de l'évêque.","Felettébb lenyűgöző. Robbantsuk is fel. Ez majd gondoskodik az erőpajzsról. Menjünk vissza a várfalhoz, majd a toronyhoz és magához a Püspökhöz.",Davvero impressionante. Facciamolo saltare in aria. Ora il campo di forza dovrebbe essere disattivato. Ora raggiungiamo la torre e facciamo fuori il Vescovo.,"あら、見事な物ね。是非とも火薬を献上しましょう。 +それでベイリーに戻ってフォースフィールドが守っていたビショップの塔へ向かおう。",아주 인상 깊은데? 어서 파괴하자고. 그러면 방어막을 끌 수 있을 거야. 그 후에 안뜰로 향해서 성으로 찾아가. 그리고 비숍을 죽여버려.,"Zeer indrukwekkend. Laten we het opblazen. Dat zou voor het krachtveld moeten zorgen. Laten we teruggaan naar de bailey, dan naar de toren en de bisschop.","Veldig imponerende. La oss sprenge det. Det burde ta seg av kraftfeltet. La oss gå tilbake til borggården, og så til tårnet og biskopen.","Bardzo efektowne. Wysadźmy ją w powietrze. To powinno załatwić sprawę pola siłowego. Wracajmy na podzamcze, a potem do wieży i biskupa.",Impressionante mesmo. Vamos detoná-lo. Isso deve dar um jeito no campo de força. Volte para a fortaleza e depois vá para a torre encontrar o Bispo.,,"Foarte impresionant. Să-l aruncăm în aer. Asta va rezolva problema câmpului de forță. Să ne întoarcem la alee, apoi către turn și Episcop.","Очень впечатляюще. Давай взорвём. Это должно избавить нас от проблем с силовым полем. Возвращаемся во внутренний двор, затем к башне и Епископу.",,Mycket imponerande. Låt oss spränga det i luften. Det borde ta hand om kraftfältet. Vi går tillbaka till borggården och sedan vidare till tornet och biskopen.,"Çok etkileyici. Hadi onu havaya uçuralım. Bu güç alanının icabına bakacaktır. Dış avluya geri dönelim, sonra kuleye ve Piskopos'a gidelim." +"Bravo, another piece of the Sigil! Did you see that weird spectre that came out of the Bishop's body? Where have I seen that before? Let's get back to the Oracle.",TXT_ILOG74,MAP16: After killing the Bishop.,,,"Bravo, další díl Pečetě! Viděl jsi ten divný přízrak, který vyšel z Biskupova těla? Kde jsem ho jen předtím viděla? Vraťme se k Věštci.","Bravo, endnu et stykke af Sigil! Så du det underlige spøgelse, der kom ud af biskoppens krop? Hvor har jeg set det før? Lad os gå tilbage til Oraklet.","Gratulation, ein weiteres Teil des Sigils! Hast du den merkwürdigen Schemen gesehen, der aus dem Körper des Bischofs herauskam? Wo habe ich ihn bloß schon einmal gesehen? Lass uns zum Orakel zurückkehren.",,"Brave, alia peco de la Sigelo! Kia stranga fantomo eliris el la korpo de la Episkopo. De kie ĝi ŝajnis konata al mi? Reiru al la Orakolo.","¡Bravo, otra pieza del Emblema! ¿Has visto ese extraño espectro que había salido del cuerpo del Obispo?, ¿de dónde me sonará? Volvamos con el Oráculo.","¡Bravo, otra pieza del Emblema! ¿Viste ese extraño espectro que había salido del cuerpo del Obispo?, ¿de dónde me sonará? Volvamos con el Oráculo.","Bravo, toinen Sinetin osanen! Näitkö tuon oudon aaveen, joka nousi Piispan ruumiista? Missä olen nähnyt sen aiemmin? Palataan Oraakkelin luokse.","Bravo, encore une pièce du Sigil! Tu a vu ce spectre étrange qui est sorti du corps de l'évêque? Je crois l'avoir vu avant, retournons à l'Oracle.","Bravó, egy újabb pecsét darab! Láttad azt a fura kísértetet ami a Püspök teteméből eltávozott? Hol is láttam hasonlót? Menjünk vissza az Orákulumhoz.","Bravo, un altro pezzo del Sigillo! Hai visto quello strano spettro che è uscito dal corpo del Vescovo? Dove l'ho già visto prima? Torniamo dall'Oracolo.","ブラボー!新たなるシジルの欠片だ! ビショップの体から出てきたあの奇妙な幽体を見た? -以前に何処かで見た気がするけど?",브라보! 두 번째 시질 조각을 얻었어! 그나저나 비숍 몸에서 튀어나왔던 검은 물체 봤어? 전에 본 적이 있나? 오라클에게 돌아가자.,"Bravo, nog een stukje van de Sigil! Zag je dat rare spook dat uit het lichaam van de bisschop kwam? Waar heb ik dat eerder gezien? Laten we teruggaan naar het Orakel.",,Bravo! Outra peça do Sigilo! Você viu aquele espectro estranho que saiu do corpo do Bispo? Onde foi que eu já vi aquilo antes? Vamos voltar para o Oráculo.,,,"Браво, ещё один фрагмент Сигила! Видел тот странный фантом, вышедший из тела Епископа? Где я могла видеть такое раньше? Давай вернёмся к Оракулу.", -"I have a report that the spectral energy we found near the Bishop is also present by the Oracle, let's be careful",TXT_ILOG76,,,,"Mám hlašení, že stejná přízračná energie, kterou jsme našli u Biskupa, se nachází také u Věštce, měli bychom být opatrní.","Ich habe einen Report, dass die spektrale Energie, die wir beim Bischof vorfanden, auch in der Nähe des Orakels vorhanden ist. Wir sollten vorsichtig sein.",,,"Tengo un informe de que la energía espectral que encontramos cerca del Obispo también está presente junto al Oráculo, tengamos cuidado","Tengo reportes de que la energía espectral que encontramos cerca del Obispo también está presente en el Oráculo, tengamos cuidado",,"Je recois un rapport que l'énergie spectrale qui possédait l'évêque se trouve aussi aux alentours de l'Oracle, fais attention.",,,"ビショップにもあったスペクトラルエネルギーがオラクルにも宿っているという -報告があるわ、気を付けて。","지금 보고를 받았는데, 비숍을 죽인 뒤에 나온 혼령의 기운이 오라클에게도 있데. 조심하자.","Ik heb een bericht dat de spectrale energie die we in de buurt van de bisschop vonden ook aanwezig is bij het Orakel, laten we voorzichtig zijn.",,Recebi um relatório de que a energia espectral que encontramos perto do Bispo também está presente pelo Oráculo. Precisamos tomar cuidado.,,,"Мне доложили, что спектральная энергия, найденная нами возле Епископа, также исходит от Оракула. Будь начеку.", -Richter has taken over command of our forces. It looks like Macil has been deceiving us all along. His true allegiance was to the Order. What a snake. Let's get back to the Oracle.,TXT_ILOG79,,,,"Richter převzal velení našich sil. Zdá se, že nás Macil celou dobu klamal. Ve skutečnosti byl věrný Řádu. Slizák jeden. Vraťme se k Věštci.",Richter hat das Kommando über unsere Streitkräfte übernommen. Es scheint als hätte Macil uns die ganze Zeit über getäuscht. Sein wahre Loyalität gehörte dem Orden. Was für eine Ratte. Lass uns zum Orakel zurückkehren.,,,Richter ha tomado el mando de nuestras fuerzas. Parece que Macil nos ha estado engañando todo este tiempo. Su verdadera lealtad era a la Orden. Qué serpiente. Volvamos con el Oráculo.,Richter ha tomado el mando de nuestras fuerzas. Parece que Macil nos ha estado engañando todo el tiempo. Su verdadera lealtad fue a la Orden. Que serpiente. Volvamos con el Oráculo.,,"Richter a pris le contrôle de nos forces. Il semble que Macil nous a menti tout du long. Sa vraie allégiance était avec l'Ordre, quel serpent! Retournous à l'Oracle.",,,"リヒターが指揮官の任を引き継いだ。マシルはずっと私達を騙していたなんて。 -あの人がオーダーに真の忠誠を誓っていたなんて、とんだ蛇神憑きだわ。",릭터가 저항군의 새로운 지도자가 될 거야. 내 생각엔 마실이 오랫동안 우리들을 속인 것 같아... 뱀 같은 자식. 오라클에게 돌아가자.,Richter heeft het bevel over onze troepen overgenomen. Het lijkt erop dat Macil ons al die tijd heeft bedrogen. Zijn ware trouw was aan de Orde. Wat een slang. Laten we teruggaan naar het Orakel.,,O Richter assumiu o comando de nossas forças. Parece que o Macil esteve nos enganando durante todo esse tempo. Sua verdadeira lealdade era à Ordem. Que traíra! Vamos voltar para o Oráculo.,,,"Рихтер принял на себя командование нашими силами. Похоже, что Мэйсил обманывал всех нас с самого начала. На самом деле он был предан Ордену. Подлец. Давай вернёмся к Оракулу.", -Another Sigil peice. We are one step closer to freedom. And you are one step closer to me. Let's get back to the Oracle!,TXT_ILOG83,,,,Další díl Pečeti. Jsme o krok blíž ke svobodě. A ty jsi o krok blíž ke mě. Vraťme se k Věštci.,Ein weiteres Teilstück des Sigils. Wir sind der Freiheit einen Schritt näher gekommen. Lass uns zurückgehen zum Orakel.,,,Otra pieza del Emblema. Estamos un paso más cerca de la libertad. Y estás un paso más cerca de mí. ¡Volvamos con el Oráculo!,Otra pieza del Emblema. Estamos un paso más cerca de la libertad. Y estás un paso más cerca de mí. ¡Regresemos con el Oráculo!,,"Encore une pièce du Sigil. Nous nous rapprochons de la liberté, et tu te rapproche aussi de moi. Retournons à l'Oracle!",,,"更なるシジルの欠片だ。私達の自由にまた一歩近づいたわ。 -そして私にも一歩近づいている。",또 다른 시질 조각이야. 자유로 향하는 길이 거의 얼마 남지 않았어. 그리고 나와 만날 순간도 얼마 남지 않았고. 오라클을 만나러 가자!,Nog een Sigil-peijsje. We zijn een stap dichter bij de vrijheid. En je bent een stap dichter bij mij. Laten we teruggaan naar het Orakel!,,Outra peça do Sigilo. Estamos nos aproximando da liberdade. E você está ficando mais próximo de mim. Vamos voltar para o Oráculo!,,,Очередной фрагмент Сигила. Теперь мы ещё на шаг ближе к освобождению. А ты — ещё на шаг ближе ко мне. Давай возвращаться к Оракулу!, -You wield the power of the complete Sigil. What do you say we get some closure. Let's see what the Loremaster's been protecting.,TXT_ILOG85,,,,"Vládneš mocí složené Pečetě. Co říkáš na to, jít s tím vším skončit? Pojďme se podívat, co to Dějepisec bránil.","Du hältst die Kraft des kompletten Sigils in deinen Händen. Meinst du nicht auch, wir sollten die Sache jetzt zu Ende bringen? Lass und nachsehen, was der Wissensmeister beschützt hat.",,,Empuñas el poder del Emblema completo. Que te parece si conseguimos algo de clausura. Vamos a ver lo que el Maestro del Conocimiento ha estado protegiendo.,Manejas el poder completo del Emblema. ¿Qué dices si conseguimos algún cierre? Veamos qué ha estado protegiendo el Maestro del Conocimiento.,,Tu as maintenant le plein pouvoir du Sigil. Je pense qu'il est l'heure d'en finir. Allons voir ce que le Maître des Traditions cachait.,,,"貴方はもはや完全なシジルの力を行使できるわけね。 -後は言いがかりでもしてここを閉鎖させましょう。",시질의 완전한 힘은 이제 네 손에 있어. 종지부를 찍을 준비 됐어? 로어마스터가 그토록 지키던 게 무엇인지 확인하자고.,Je gebruikt de kracht van de volledige Sigil. Wat zeg je ervan als we de zaak afsluiten. Laten we eens kijken wat de Kennismeester heeft beschermd.,,Você tem o poder do Sigilo completo nas suas mãos. O que acha de termos um desfecho? Vamos ver o que o Mestre do Conhecimento andou protegendo.,,,"Теперь ты владеешь мощью завершённого Сигила. Мы уже близко — давай покончим с этим. Посмотрим, что же охранял Хранитель мудрости.", -"Well, so much for prognostication. Hold it, Macil is calling us back. Let's get out of here in one piece.",TXT_ILOG87,,,,"No, tak to by bylo pro předpovědi. Počkej, Macil nás volá zpět. Vypadněme odsud vcelku.","Soviel zum Thema Vorhersagen. Warte, Macil ruft uns zurück. Lass uns hier heile herauskommen.",,,"Bueno, tanto por un presentimiento. Espera, Macil nos reclama. Salgamos de aquí de una pieza.","Bueno, tanto para el pronóstico. Espera, Macil nos está llamando de vuelta. Salgamos de aquí en una pieza.",,"Bon, je pense que l'heure n'est plus au pronostics.. Attends, Macil nous appelle. Sortons d'ici en vie, si possible.",,,"まあ予言なんてそんなものでしょ。 -ちょっと待って、マシルが帰還するように言ったわ。ここから抜け出しましょう。","웃기네. 이딴 예언 따위. 잠깐만, 마실이 우리들을 부르고 있어. 이제 안전하게 기지로 돌아가자.","Nou, tot zover de prognose. Wacht even, Macil belt ons terug. Laten we hier heelhuids weggaan.",,"Bem, acho que ainda não é hora de previsões. Espera, o Macil está nos chamando de volta. Vamos tentar sair daqui inteiros.",,,"Да, это превзошло все наши ожидания. Успокойся, Мэйсил вызывает нас назад. Давай выбираться отсюда.", -"The factory is next to the mines. Richter must mean the mines of Degnin. The Degnin ore is magnetic and explosive, just the thing for shutting down force fields. Let's get that key from the catacombs, and then off to the mines for some ore.",TXT_ILOG89,,,,"Továrna je vedle dolů. Richter musí mít na mysli doly degninu. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole. Pojďme z katakomb dostat ten klíč a pak do dolů pro trochu rudy.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Dasa Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten. Lass uns den Schlüssel aus den Katakomben holen, und dann ab in die Minen für etwas Erz.",,,"La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magético y explosivo, justo para apagar campos de fuerza. Obtengamos esa llave de las catacumbas, y luego derechos a las minas a por algo de mineral.","La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magnético y explosivo, justo para apagar campos de fuerza. Obtengamos esa llave de las Catacumbas y luego vayamos a las minas por algo de mineral.",,"L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. Récupérons la clé dans les catacombes, puis partons pour les mines pour récupérer du minerai.",,,"工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 +以前に何処かで見た気がするけど?",브라보! 두 번째 시질 조각을 얻었어! 그나저나 비숍 몸에서 튀어나왔던 검은 물체 봤어? 전에 본 적이 있나? 오라클에게 돌아가자.,"Bravo, nog een stukje van de Sigil! Zag je dat rare spook dat uit het lichaam van de bisschop kwam? Waar heb ik dat eerder gezien? Laten we teruggaan naar het Orakel.","Bravo, enda en bit av sigillet! Så du det rare spøkelset som kom ut av biskopens kropp? Hvor har jeg sett det før? La oss gå tilbake til oraklet.","Brawo, kolejny kawałek Sigilu! Widziałeś to dziwne widmo, które wyszło z ciała biskupa? Gdzie ja to już widziałem? Wróćmy do Wyroczni.",Bravo! Outra peça do Sigilo! Você viu aquele espectro estranho que saiu do corpo do Bispo? Onde foi que eu já vi aquilo antes? Vamos voltar para o Oráculo.,,"Bravo, încă o bucată din Sigiliu! Ai văzut spectrul ciudat ce a ieșit din corpul Episcopului? Unde am mai văzut asta oare? Să ne întoarcem la Oracol.","Браво, ещё один фрагмент Печати! Видел тот странный фантом, вышедший из тела Епископа? Где я могла видеть такое раньше? Давай вернёмся к Оракулу.",,"Bravo, ännu en del av Sigillet! Såg du det konstiga spöket som kom ut ur biskopens kropp? Var har jag sett det förut? Låt oss gå tillbaka till oraklet.","Bravo, Sigil'in bir parçası daha! Piskopos'un bedeninden çıkan garip hayaleti gördün mü? Bunu daha önce nerede görmüştüm? Kahin'e geri dönelim." +"I have a report that the spectral energy we found near the Bishop is also present by the Oracle, let's be careful.",TXT_ILOG76,MAP11: After killing the Bishop and going to MAP12's entrance.,,,"Mám hlašení, že stejná přízračná energie, kterou jsme našli u Biskupa, se nachází také u Věštce, měli bychom být opatrní.","Jeg har en rapport om, at den spektrale energi, vi fandt nær biskoppen, også er til stede ved Oraklet, lad os være forsigtige.","Ich habe einen Report, dass die spektrale Energie, die wir beim Bischof vorfanden, auch in der Nähe des Orakels vorhanden ist. Wir sollten vorsichtig sein.",,"Laŭ informo, la fantoma energio trovita proksime de la Episkopo estas ankaŭ apud la Orakolo. Ni estu atentaj.",Tengo un informe de que la energía espectral que habíamos encontrado cerca del Obispo también está junto al Oráculo. Tengamos cuidado.,,"Sain tiedon, että aave-energiaa, jota löysimme Piispan läheltä, on läsnä myös Oraakkelin luona. Ollaan varovaisia.","Je recois un rapport que l'énergie spectrale qui possédait l'évêque se trouve aussi aux alentours de l'Oracle, fais attention.","Kaptam egy jelentést, hogy a Püspök körül érzékelt kísérteties energia észlelhető az Orákulum körül is. Vigyázzunk vele.","Ho qua un rapporto che ci informa che l'energia spettrale che abbiamo trovato vicino il Vescovo è anche presente vicino l'Oracolo, dobbiamo essere attenti.","ビショップにもあったスペクトラルエネルギーがオラクルにも宿っているという +報告があるわ、気を付けて。","지금 보고를 받았는데, 비숍을 죽인 뒤에 나온 혼령의 기운이 오라클에게도 있데. 조심하자.","Ik heb een bericht dat de spectrale energie die we in de buurt van de bisschop vonden ook aanwezig is bij het Orakel, laten we voorzichtig zijn.","Jeg har en rapport om at den spektrale energien vi fant nær biskopen også er til stede ved oraklet, la oss være forsiktige.","Mam raport, że energia widmowa, którą znaleźliśmy w pobliżu Bishopa, jest również obecna przy Wyroczni, bądźmy ostrożni.",Recebi um relatório de que a energia espectral que encontramos perto do Bispo também está presente pelo Oráculo. Precisamos tomar cuidado.,,"Am un raport care spune că energia spectrală a Episcopului a prezentă și în Oracol, s-avem grijă.","Мне доложили, что спектральная энергия, найденная нами возле Епископа, также исходит от Оракула. Будь начеку.",,"Jag har en rapport om att den spektrala energin som vi hittade nära biskopen också finns vid oraklet, låt oss vara försiktiga.","Piskoposun yanında bulduğumuz spektral enerjinin Kahin tarafından da mevcut olduğuna dair bir rapor aldım, dikkatli olalım." +Richter has taken over command of our forces. It looks like Macil has been deceiving us all along. His true allegiance was to the Order. What a snake. Let's get back to the Oracle.,TXT_ILOG79,MAP10: After killing Macil (Spectre) without having destroyed the converter in MAP24.,,,"Richter převzal velení našich sil. Zdá se, že nás Macil celou dobu klamal. Ve skutečnosti byl věrný Řádu. Slizák jeden. Vraťme se k Věštci.","Richter har overtaget kommandoen over vores styrker. Det ser ud til, at Macil har bedraget os hele tiden. Hans sande loyalitet var over for ordenen. Sikke en slange. Lad os gå tilbage til Oraklet.",Richter hat das Kommando über unsere Streitkräfte übernommen. Es scheint als hätte Macil uns die ganze Zeit über getäuscht. Sein wahre Loyalität gehörte dem Orden. Was für eine Ratte. Lass uns zum Orakel zurückkehren.,,"Rikter iĝis la nova frontestro. Ŝajnas, ke Macil trompis nin de la komenco: lia vera fidelo estis al La Ordeno. Kia serpento. Reiru al la Orakolo.",Richter ha tomado el mando del Frente. Parece que Macil nos ha estado engañando todo este tiempo: su verdadera lealtad era a La Orden. Menuda víbora. Volvamos con el Oráculo.,Richter tomó el mando del Frente. Parece que Macil nos ha estado engañando todo este tiempo: su verdadera lealtad era a La Orden. Tremenda víbora. Volvamos con el Oráculo.,"Richter on ottanut joukkomme komentoonsa. Näyttää siltä, että Macil on pettänyt meitä alusta alkaen. Hänen todellinen uskollisuutensa on ollut Veljeskunnalle; mikä käärme. Palataan Oraakkelin luokse.","Richter a pris le contrôle de nos forces. Il semble que Macil nous a menti tout du long. Sa vraie allégiance était avec l'Ordre, quel serpent! Retournous à l'Oracle.",Richter átvette az írányítást a csapataink fölött. Úgy tűnik Macil mindvégig megtévesztett minket. Valójában mindvégig a Rend oldalán volt. micsoda kígyó. Menjünk vissza az Orákulumhoz.,Richter ha assunto il comando delle nostre forze. Sembra che Macil ci avesse ingannato fin dall'inizio. In realtà è sempre stato alleato con l'Ordine. Che serpente. Ritorniamo dall'Oracolo.,"リヒターが指揮官の任を引き継いだ。マシルはずっと私達を騙していたなんて。 +あの人がオーダーに真の忠誠を誓っていたなんて、とんだ蛇神憑きだわ。",릭터가 저항군의 새로운 지도자가 될 거야. 내 생각엔 마실이 오랫동안 우리들을 속인 것 같아... 뱀 같은 자식. 오라클에게 돌아가자.,Richter heeft het bevel over onze troepen overgenomen. Het lijkt erop dat Macil ons al die tijd heeft bedrogen. Zijn ware trouw was aan de Orde. Wat een slang. Laten we teruggaan naar het Orakel.,Richter har overtatt kommandoen over styrkene våre. Det ser ut til at Macil har lurt oss hele tiden. Hans sanne lojalitet var til Ordenen. For en slange. La oss gå tilbake til orakelet.,"Richter przejął dowodzenie nad naszymi siłami. Wygląda na to, że Macil cały czas nas zwodził. Jego prawdziwa wierność była dla Zakonu. Co za wąż. Wracajmy do Wyroczni.",O Richter assumiu o comando de nossas forças. Parece que o Macil esteve nos enganando durante todo esse tempo. Sua verdadeira lealdade era à Ordem. Que traíra! Vamos voltar para o Oráculo.,,Richter a preluat controlul asupra forțelor noastre. Se pare că Macil ne-a mințit tot timpul. A fost loial cu adevărat doar Ordinului. Ce șarpe. Să ne întoarcem la Oracol.,"Рихтер принял на себя командование нашими силами. Похоже, что Мэйсил обманывал всех нас с самого начала. На самом деле он был предан Ордену. Подлец. Давай вернёмся к Оракулу.",,Richter har tagit över befälet över våra styrkor. Det verkar som om Macil har lurat oss hela tiden. Hans sanna lojalitet var till Orden. Vilken orm. Låt oss gå tillbaka till Oraklet.,Richter kuvvetlerimizin komutasını devraldı. Görünüşe göre Macil başından beri bizi kandırıyormuş. Gerçek bağlılığı Tarikat'a imiş. Ne yılan ama. Kahin'e geri dönelim. +Another Sigil piece. We are one step closer to freedom. And you are one step closer to me. Let's get back to the Oracle!,TXT_ILOG83,MAP27: After killing the Loremaster with either Macil or the Oracle alive.,,,Další díl Pečeti. Jsme o krok blíž ke svobodě. A ty jsi o krok blíž ke mě. Vraťme se k Věštci.,Endnu et Sigil-stykke. Vi er et skridt nærmere friheden. Og du er et skridt tættere på mig. Lad os komme tilbage til Oraklet!,Ein weiteres Teilstück des Sigils. Wir sind der Freiheit einen Schritt näher gekommen. Lass uns zurückgehen zum Orakel.,,Alia peco de la Sigelo. Ni estas unu paŝo pli proksime de la libereco... kaj ankaŭ vi de mi. Reiru al la Orakolo!,Otra pieza del Emblema. Estamos a un paso más cerca de la libertad... y también tú de mí. ¡Volvamos con el Oráculo!,,Jälleen uusi Sinetin osanen. Olemme taas askeleen lähempänä vapautta. Ja sinä askeleen lähempänä minua. Palataan Oraakkelin luo!,"Encore une pièce du Sigil. Nous nous rapprochons de la liberté, et tu te rapproche aussi de moi. Retournons à l'Oracle!",Még egy pecsét darab. Egy lépéssel közelebb állunk a szabadsághoz. Te pedig egy lépéssel közelebb vagy hozzám. menjünk vissza az orákulumhoz.,Un altro pezzo del Sigillo. Siamo ancora più vicini alla libertà. E tu sei ancora più vicino a me. Ritorniamo all'Oracolo!,"更なるシジルの欠片だ。私達の自由にまた一歩近づいたわ。 +そして私にも一歩近づいている。",또 다른 시질 조각이야. 자유로 향하는 길이 거의 얼마 남지 않았어. 그리고 나와 만날 순간도 얼마 남지 않았고. 오라클을 만나러 가자!,Nog een Sigil-peijsje. We zijn een stap dichter bij de vrijheid. En je bent een stap dichter bij mij. Laten we teruggaan naar het Orakel!,Enda en Sigil-brikke. Vi er ett skritt nærmere friheten. Og du er ett skritt nærmere meg. La oss gå tilbake til Orakelet!,Kolejny kawałek Sigil. Jesteśmy o krok bliżej wolności. A ty jesteś o krok bliżej mnie. Wracajmy do Wyroczni!,Outra peça do Sigilo. Estamos nos aproximando da liberdade. E você está ficando mais próximo de mim. Vamos voltar para o Oráculo!,,Altă piesă din Sigiliu. Suntem cu un pas mai aproape de libertate. Și tu ești cu un pas mai aproape de mne. Să ne întoarcem la Oracol.,Очередной фрагмент Печати. Теперь мы ещё на шаг ближе к освобождению. А ты — ещё на шаг ближе ко мне. Давай возвращаться к Оракулу!,,Ännu en Sigil-bit. Vi är ett steg närmare friheten. Och du är ett steg närmare mig. Låt oss gå tillbaka till Oraklet!,Başka bir Sigil parçası. Özgürlüğe bir adım daha yaklaştık. Ve sen de bana bir adım daha yaklaştın. Kahin'e geri dönelim! +You wield the power of the complete Sigil. What do you say we get some closure. Let's see what the Loremaster's been protecting.,TXT_ILOG85,MAP27/MAP12: Remark at TXT_SUB_LOG85,,,"Vládneš mocí složené Pečetě. Co říkáš na to, jít s tím vším skončit? Pojďme se podívat, co to Dějepisec bránil.","Du har magten af det komplette Sigil. Hvad siger du til, at vi får en afslutning? Lad os se, hvad Loremesteren har beskyttet.","Du hältst die Kraft des kompletten Sigils in deinen Händen. Meinst du nicht auch, wir sollten die Sache jetzt zu Ende bringen? Lass und nachsehen, was der Wissensmeister beschützt hat.",,"Vi tenas la povon de la tuta Sigelo. Kio pri fini ĉi tiun ĉapitron? Ni vidu tion, kion la Folkloristo kaŝadis.",Empuñas el poder del Emblema completo. ¿Que te parece ponerle un cierre a todo? Vamos a ver lo que el Maestro del Conocimiento se ha estado guardando.,,"Täyden Sinetin voima on hallussasi. Mitäpä jos hakisimme päätöstä. Katsotaan, mitä Oppi-Isä oikein on varjellut.",Tu as maintenant le plein pouvoir du Sigil. Je pense qu'il est l'heure d'en finir. Allons voir ce que le Maître des Traditions cachait.,"A kompett pecsét hatalma a kezedben van. Mit szólsz ahhoz, hogy lezárjuk végleg ezt a harcot. Nézzük meg mit is védelmez a Tanmester valójában.",Hai il potere del Sigillo completo. Che ne dici di finire questa storia. Vediamo un po' cosa il Sapiente stava proteggendo.,"貴方はもはや完全なシジルの力を行使できるわけね。 +後は言いがかりでもしてここを閉鎖させましょう。",시질의 완전한 힘은 이제 네 손에 있어. 종지부를 찍을 준비 됐어? 로어마스터가 그토록 지키던 게 무엇인지 확인하자고.,Je gebruikt de kracht van de volledige Sigil. Wat zeg je ervan als we de zaak afsluiten. Laten we eens kijken wat de Kennismeester heeft beschermd.,Du har makten til hele sigillet. Hva sier du til at vi får en avslutning? La oss se hva Loremaster har beskyttet.,"Władasz mocą kompletnego Sigilu. Co powiesz na to, żebyśmy się zamknęli. Zobaczmy, co Loremaster chronił.",Você tem o poder do Sigilo completo nas suas mãos. O que acha de termos um desfecho? Vamos ver o que o Mestre do Conhecimento andou protegendo.,,Ai puterea întregului Sigiliu. Ce zici dacă avem parte de un sfârșit. Să vedem ce poate prezice Maestrul Cunoștiințelor.,"Теперь ты владеешь мощью завершённой Печати. Мы уже близко — давай покончим с этим. Посмотрим, что же охранял Хранитель мудрости.",,Du har makten över hela Sigil. Vad sägs om att vi får ett avslut. Låt oss se vad Läromästaren har skyddat.,"Sigil'in tamamının gücüne sahipsin. Ne dersin, biraz kapanış yapalım mı? Loremaster'ın neyi koruduğunu görelim." +"Well, so much for prognostication. Hold it, Macil is calling us back. Let's get out of here in one piece.",TXT_ILOG87,MAP12: After killing the Oracle with Macil alive.,,,"No, tak to by bylo pro předpovědi. Počkej, Macil nás volá zpět. Vypadněme odsud vcelku.","Nå, så meget for prognoser. Vent, Macil kalder os tilbage. Lad os komme ud herfra i ét stykke.","Soviel zum Thema Vorhersagen. Warte, Macil ruft uns zurück. Lass uns hier heile herauskommen.",,"Nu, kia antaŭsento. Atendu, Macil vokas nin; ni eliru el ĉi tie senvundaj.","Vaya con los presentimientos. Momento, Macil nos está llamando; salgamos de aquí de una pieza.",,"No, se siitä ennustelusta. Odota, Macil kutsuu meitä takaisin. Häivytään täältä ehjin nahoin.","Bon, je pense que l'heure n'est plus au pronostics.. Attends, Macil nous appelle. Sortons d'ici en vie, si possible.","Hát, ennyit a jóslatról. Várj, Macil visszahív minket. Húzzunk innen míg egy darabban vagyunk.","Alla faccia dei prognostici... Aspetta, Macil ci sta richiamando. Meglio uscire da qua tutti interi.","まあ予言なんてそんなものでしょ。 +ちょっと待って、マシルが帰還するように言ったわ。ここから抜け出しましょう。","웃기네. 이딴 예언 따위. 잠깐만, 마실이 우리들을 부르고 있어. 이제 안전하게 기지로 돌아가자.","Nou, tot zover de prognose. Wacht even, Macil belt ons terug. Laten we hier heelhuids weggaan.","Så mye for spådommer. Vent, Macil kaller oss tilbake. La oss komme oss helskinnet ut herfra.","Cóż, to tyle jeśli chodzi o prognozowanie. Czekajcie, Macil nas wzywa. Wydostańmy się stąd w jednym kawałku.","Bem, acho que ainda não é hora de previsões. Espera, o Macil está nos chamando de volta. Vamos tentar sair daqui inteiros.",,"Atât a fost cu prognoza. Stai, Macil ne sună înapoi. Să ieșim de aici întregi.","Да, это превзошло все наши ожидания. Успокойся, Мэйсил вызывает нас назад. Давай выбираться отсюда.",,"Tja, så mycket för prognoser. Vänta, Macil kallar oss tillbaka. Låt oss komma härifrån i ett stycke.","Kehanet için çok fazla. Durun, Macil bizi geri çağırıyor. Buradan tek parça halinde çıkalım." +"The factory is next to the mines. Richter must mean the mines of Degnin. The Degnin ore is magnetic and explosive, just the thing for shutting down force fields. Let's get that key from the catacombs, and then off to the mines for some ore.",TXT_ILOG89,MAP23: After talking with Richter and leaving his room.,,,"Továrna je vedle dolů. Richter musí mít na mysli doly degninu. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole. Pojďme z katakomb dostat ten klíč a pak do dolů pro trochu rudy.","Fabrikken ligger ved siden af minerne. Richter må mene Degnin-minerne. Degnin malmen er magnetisk og eksplosiv, lige til at lukke kraftfelter ned med. Lad os hente nøglen fra katakomberne og så til minerne efter malm.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Dasa Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten. Lass uns den Schlüssel aus den Katakomben holen, und dann ab in die Minen für etwas Erz.",,"La fabriko estas apud la minejo de Degnin; ĝiaj minaĵoj estas magnetaj kaj eksplodpovaj, sufiĉe por detrui fortokampojn. Ni rekuperu tiun ŝlosilon en la katakombo kaj tiam ni serĉu tiajn minaĵojn en la minejo.","La fábrica está junto a la mina de Degnin; su mineral es magnético y explosivo, justo como para destruir campos de fuerza. A recuperar esa llave en las catacumbas y luego a la mina a buscar de ese mineral.",,"Tehdas on kaivoksen vieressä. Richter varmastikin tarkoittaa Degninin kaivosta. Degnin-malmi on magneettista ja räjähdysherkkää, juuri omiaan purkamaan voimakenttiä. Noudetaan avain katakombeista ja sitten matkataan kaivokselle hakemaan malmia.","L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. Récupérons la clé dans les catacombes, puis partons pour les mines pour récupérer du minerai.","A gyár a bánya mellett van. Richter valószínűleg Degnin bányáira gondolt. A degnini érc mágneses és robbanékony, pont tökéletes lesz az erőpajzs kiiktatásához. Menjünk és szerezzük meg azt a kulcsot a katakombákból, és aztán a bányába egy kis ércért.","La Fabbrica si trova accanto alle miniere. Richter starà parlando delle miniere di Degnin. I minerali di Degnin sono magnetici ed esplosivi, giusto ciò che ci serve per disattivare i campi di forza. Prendiamo quella chiave dalle catacombe, e poi andiamo alle miniere a prendere un po' di quei minerali.","工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 デグニン石は綺麗だが可燃性で、フォースフィールドを消すにはうってつけよ。 -そこへのキーを地下墓所から取り、鉱山に向かおう。","공장은 광산 옆에 있어. 아마도 릭터는 데그닌 갱도를 예기한 것 같아. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지. 고대 무덤에서 그 열쇠를 얻고, 광석을 얻을 광산으로 향하자.","De fabriek ligt naast de mijnen. Richter moet de mijnen van Degnin bedoelen. Het Degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden. Laten we die sleutel uit de catacomben halen, en dan naar de mijnen gaan voor wat erts.",,"A fábrica fica próxima às minas. O Richter deve estar se referindo às minas de Degnin. O minério de Degnin é magnético e explosivo, o ideal para derrubar campos de força. Vamos pegar aquela chave das catacumbas e depois vamos para as minas pegar esse minério.",,,"Вход на фабрику — рядом со спуском в шахты. Рихтер, должно быть, имел в виду шахты Дегнина. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. Достань ключ из катакомб, а потом спустись в шахты за рудой.", -"The factory is next to the mines. The Degnin ore is magnetic and explosive, just the thing for shutting down force fields. Let's get that key from the catacombs, and then we go down for some ore. This must be the ruins Richter's agents were searching for, be careful.",TXT_ILOG93,,,,"Továrna je vedle dolů. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole. Pojďme z katakomb dostat ten klíč a pak do dolů pro trochu rudy. Tohle musí být ty ruiny, které Richterovi agenti hledali, buď opatrný.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Dasa Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten. Lass uns den Schlüssel aus den Katakomben holen, und dann ab in die Minen für etwas Erz. Dies müssen die Ruinen sein, die Richters Agenten gesucht haben. Sei vorsichtig.",,,"La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magético y explosivo, justo para apagar campos de fuerza. Obtengamos esa llave de las catacumbas, y luego derechos a las minas a por algo de mineral. Estas deben de ser las ruínas que los agentes de Richter estaban buscando, ten cuidado.","La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magnético y explosivo, justo para apagar campos de fuerza. Obtengamos esa llave de las Catacumbas y luego vayamos a las minas por algo de mineral. Estas deben ser las ruinas que los agentes de Richter estaban buscando, ten cuidado.",,"L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. Récupérons la clé dans les catacombes, puis partons pour les mines pour récupérer du minerai. Cela doit être les ruines que les agent de Richter cherchaient. Fais attention.",,,"工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 +そこへのキーを地下墓所から取り、鉱山に向かおう。","공장은 광산 옆에 있어. 아마도 릭터는 데그닌 갱도를 예기한 것 같아. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지. 고대 무덤에서 그 열쇠를 얻고, 광석을 얻을 광산으로 향하자.","De fabriek ligt naast de mijnen. Richter moet de mijnen van Degnin bedoelen. Het Degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden. Laten we die sleutel uit de catacomben halen, en dan naar de mijnen gaan voor wat erts.","Fabrikken ligger ved siden av gruvene. Richter må mene gruvene i Degnin. Degnin-malmen er magnetisk og eksplosiv, akkurat det som skal til for å slå ut kraftfelt. La oss hente nøkkelen fra katakombene, og så dra til gruvene etter malm.","Fabryka jest obok kopalni. Richter musi mieć na myśli kopalnie w Degnin. Ruda Degnin jest magnetyczna i wybuchowa, w sam raz do wyłączania pól siłowych. Zdobądźmy ten klucz z katakumb, a potem ruszajmy do kopalni po rudę.","A fábrica fica próxima às minas. O Richter deve estar se referindo às minas de Degnin. O minério de Degnin é magnético e explosivo, o ideal para derrubar campos de força. Vamos pegar aquela chave das catacumbas e depois vamos para as minas pegar esse minério.",,"Fabrica e lângă mine, Richter se referă la minele din Degnin. Minereul de Degni e magnetic și exploziv, exact ceea ce ne trebuie pentru a opri câmpul de forță. Să luăm cheia aceea din catacombe și să ne îndreptăm înspre mine.","Вход на фабрику — рядом со спуском в шахты. Рихтер, должно быть, имел в виду шахты Дегнина. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. Достань ключ из катакомб, а потом спустись в шахты за рудой.",,"Fabriken ligger bredvid gruvorna. Richter måste mena Degnins gruvor. Degninmalmen är magnetisk och explosiv, precis vad man behöver för att stänga av kraftfält. Låt oss hämta nyckeln från katakomberna och sedan iväg till gruvorna för att hämta malm.","Fabrika madenlerin yanında. Richter, Degnin madenlerini kastediyor olmalı. Degnin cevheri manyetik ve patlayıcıdır, tam da güç alanlarını kapatmak için. Hadi şu anahtarı yeraltı mezarlarından alalım, sonra da biraz cevher için madenlere gidelim." +"The factory is next to the mines. The Degnin ore is magnetic and explosive, just the thing for shutting down force fields. Let's get that key from the catacombs, and then we go down for some ore. This must be the ruins Richter's agents were searching for, be careful.",TXT_ILOG93,MAP25: Entrance.,,,"Továrna je vedle dolů. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole. Pojďme z katakomb dostat ten klíč a pak do dolů pro trochu rudy. Tohle musí být ty ruiny, které Richterovi agenti hledali, buď opatrný.","Fabrikken ligger ved siden af minerne. Degnin-malmen er magnetisk og eksplosiv og er lige til at lukke kraftfelter ned med. Lad os hente nøglen fra katakomberne, og så går vi ned efter noget malm. Dette må være ruinerne, som Richters agenter ledte efter, vær forsigtig.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Dasa Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten. Lass uns den Schlüssel aus den Katakomben holen, und dann ab in die Minen für etwas Erz. Dies müssen die Ruinen sein, die Richters Agenten gesucht haben. Sei vorsichtig.",,"La fabriko estas apud la minejo de Degnin; ĝiaj minaĵoj estas magnetaj kaj eksplodpovaj, sufiĉe por detrui fortokampojn. Ĉi tiuj verŝajne estas la ruinoj, kie malaperis la agentoj de Rikter dum ili serĉis la ŝlosilon de la minejo.","La fábrica está junto a la mina de Degnin; su mineral es magnético y explosivo, justo como para destruir campos de fuerza. Estas deben de ser las ruinas donde los agentes de Richter han desaparecido al buscar al llave de la mina.","La fábrica está junto a la mina de Degnin; su mineral es magnético y explosivo, justo como para destruir campos de fuerza. Estas deben de ser las ruinas donde los agentes de Richter desaparecieron al buscar al llave de la mina.","Tehdas on kaivoksen vieressä. Degnin-malmi on magneettista ja räjähdysherkkää, juuri omiaan purkamaan voimakenttiä. Noudetaan avain katakombeista ja mennään sitten alas hakemaan malmia. Nämä ovat varmaankin ne rauniot, joita Richterin joukot olivat etsineet; ole varovainen.","L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. Récupérons la clé dans les catacombes, puis partons pour les mines pour récupérer du minerai. Cela doit être les ruines que les agent de Richter cherchaient. Fais attention.","A gyár a bánya mellett van. A degnini érc mágneses és robbanékony, pont tökéletes lesz az erőpajzs kiiktatásához. Menjünk és szerezzük meg azt a kulcsot a katakombákból, és aztán a bányába egy kis ércért. Valószínű, hogy ezek azok a romok, amelyeket Richter ügynökei kerestek, légy óvatos.","La Fabbrica si trova accanto alle miniere. I minerali di Degnin sono magnetici ed esplosivi, giusto ciò che ci serve per disattivare i campi di forza. Prendiamo quella chiave dalle catacombe, e poi andiamo alle miniere a prendere un po' di quei minerali. Devono essere queste le rovine che gli agenti di Richter stavano esplorando, fai attenzione.","工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 デグニン石は綺麗だが可燃性で、フォースフィールドを消すにはうってつけよ。 そこへのキーを地下墓所から取り、鉱山に向かおう。 -ここがリヒターのエージェントが探していた遺跡のはず。気を付けて。",공장은 광산 옆에 있어. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지. 고대 묘지에 가서 열쇠를 얻고 광석을 좀 구하자. 릭터의 요원들이 정찰하다 사라진 폐허인 것 같아. 조심해.,"De fabriek is naast de mijnen. Het Degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden. Laten we die sleutel uit de catacomben halen, en dan gaan we naar beneden voor wat erts. Dit moeten de ruïnes zijn waar Richter's agenten naar op zoek waren, wees voorzichtig.",,"A fábrica fica próxima às minas. O minério de Degnin é magnético e explosivo, o ideal para derrubar campos de força. Vamos pegar aquela chave das catacumbas e ir atrás desse minério. Essas devem ser as ruínas que os agentes do Richter estavam procurando. Tome cuidado.",,,"Вход на фабрику — рядом со спуском в шахты. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. Достань ключ в катакомбах, а потом спустись за рудой. Должно быть, именно эти руины искали агенты Рихтера. Будь осторожен.", -"The factory is next to the mines. The Degnin ore is magnetic and explosive, just the thing for shutting down force fields. My friend, whatever it is we're fighting, it's more than just the Order. Back to the commons then off to the mines. We need ore.",TXT_ILOG95,,,,"Továrna je vedle dolů. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole. Příteli, ať už bojujeme s čímkoliv, jde o víc než jen Řád. Zpátky na předměstí a pak do dolů. Potřebujeme rudu.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Dasa Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten. Mein Freund, was immer wir hier bekämpfen, es ist mehr als der Orden. Zurück zur Mensa, und dann ab in die Minen. Wir brauchen Erz.",,,"La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magético y explosivo, justo para apagar campos de fuerza. Amigo, lo que sea contra lo que estamos luchando, es más que sólo la Orden. Volvamos a los comunes y luego derechos a las minas. Necesitamos mineral.","La Fábrica está junto a las minas. El mineral Degnin es magnético y explosivo, justo para apagar campos de fuerza. Amigo mío, sea lo que sea con lo que estamos pelando, es algo más que solo la Orden. Regresemos a los comunes, luego vayamos a las minas. Necesitamos mineral.",,"L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. Mon ami, c'est clair que l'on se bat contre plus que juste l'Ordre. Retournons au réfectoire puis aux mines. Il nous faut du minerai.",,,"工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 +ここがリヒターのエージェントが探していた遺跡のはず。気を付けて。",공장은 광산 옆에 있어. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지. 고대 묘지에 가서 열쇠를 얻고 광석을 좀 구하자. 릭터의 요원들이 정찰하다 사라진 폐허인 것 같아. 조심해.,"De fabriek is naast de mijnen. Het Degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden. Laten we die sleutel uit de catacomben halen, en dan gaan we naar beneden voor wat erts. Dit moeten de ruïnes zijn waar Richter's agenten naar op zoek waren, wees voorzichtig.","Fabrikken ligger ved siden av gruvene. Degnin-malmen er magnetisk og eksplosiv, akkurat tingen for å stenge ned kraftfelt. Vi henter nøkkelen i katakombene, og så går vi ned etter malm. Dette må være ruinene Richters agenter lette etter. Vær forsiktig.","Fabryka jest obok kopalni. Ruda Degnin jest magnetyczna i wybuchowa, idealna do wyłączania pól siłowych. Zdobądźmy ten klucz z katakumb, a potem zejdźmy na dół po rudę. To muszą być ruiny, których szukali agenci Richtera, bądźcie ostrożni.","A fábrica fica próxima às minas. O minério de Degnin é magnético e explosivo, o ideal para derrubar campos de força. Vamos pegar aquela chave das catacumbas e ir atrás desse minério. Essas devem ser as ruínas que os agentes do Richter estavam procurando. Tome cuidado.",,"Fabrica e lângă mine, Richter se referă la minele din Degnin. Minereul de Degni e magnetic și exploziv, exact ceea ce ne trebuie pentru a opri câmpul de forță. Să luăm cheia aceea din catacombe și să ne îndreptăm înspre mine.","Вход на фабрику — рядом со спуском в шахты. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. Достань ключ в катакомбах, а потом спустись за рудой. Должно быть, именно эти руины искали агенты Рихтера. Будь осторожен.",,"Fabriken ligger bredvid gruvorna. Degninmalmen är magnetisk och explosiv, precis vad man behöver för att stänga av kraftfält. Vi hämtar nyckeln från katakomberna och går sedan ner för att hämta malm. Detta måste vara ruinerna som Richters agenter sökte efter, var försiktig.","Fabrika madenlerin yanında. Degnin cevheri manyetik ve patlayıcıdır, güç alanlarını kapatmak için birebirdir. Hadi şu anahtarı yeraltı mezarlarından alalım, sonra da biraz cevher için aşağı inelim. Burası Richter'in ajanlarının aradığı kalıntılar olmalı, dikkatli ol." +"The factory is next to the mines. The Degnin ore is magnetic and explosive, just the thing for shutting down force fields. My friend, whatever it is we're fighting, it's more than just the Order. Back to the commons then off to the mines. We need ore.",TXT_ILOG95,MAP25: After killing the Spectre.,,,"Továrna je vedle dolů. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole. Příteli, ať už bojujeme s čímkoliv, jde o víc než jen Řád. Zpátky na náves a pak do dolů. Potřebujeme rudu.","Fabrikken ligger ved siden af minerne. Degnin-malmen er magnetisk og eksplosiv, lige til at lukke kraftfelter ned med. Min ven, hvad det end er, vi kæmper imod, er det mere end bare Ordenen. Tilbage til fællesrummet og så til minerne. Vi har brug for malm.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Dasa Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten. Mein Freund, was immer wir hier bekämpfen, es ist mehr als der Orden. Zurück zur Mensa, und dann ab in die Minen. Wir brauchen Erz.",,"Tio ajn, kion ni alfrontas, es pli ol La Ordeno. La fabriko estas apud la minejo de Degnin; ĝiaj minaĵoj estas magnetaj kaj eksplodpovaj, sufiĉe por detrui fortokampojn. Ni reiru al la komunumo kaj tiam ni serĉu tiajn minaĵojn en la minejo.","Lo que sea a los que nos enfrentamos es más que solo La Orden. La fábrica está junto a la mina de Degnin; su mineral es magnético y explosivo, justo como para destruir campos de fuerza. Volvamos a la comuna y luego a la mina a buscar de ese mineral.",,"Tehdas on kaivoksen vieressä. Degnin-malmi on magneettista ja räjähdysherkkää, juuri omiaan purkamaan voimakenttiä. Ystäväni, mitä vastaan me taistelemmekaan, se on suurempi kuin pelkkä Veljeskunta. Palatkaamme messiin, josta sitten kaivokseen. Tarvitsemme malmia.","L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. Mon ami, c'est clair que l'on se bat contre plus que juste l'Ordre. Retournons au réfectoire puis aux mines. Il nous faut du minerai.","A gyár a bánya mellett van. A degnini érc mágneses és robbanékony, pont tökéletes lesz az erőpajzs kiiktatásához. Barátom, akármi ellen is harcolunk, több mint a Rend maga. Irány vissza a menzára, aztán a bánya. Szükségünk van ércre.","La Fabbrica si trova accanto alle miniere. I minerali di Degnin sono magnetici ed esplosivi, giusto ciò che ci serve per disattivare i campi di forza. Amico mio, qualsiasi cosa stiamo combattendo, è molto di più del solo Ordine. Ritorniamo ai comuni e poi alle miniere. Ci serve quel minerale.","工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 デグニン石は綺麗だが可燃性で、フォースフィールドを消すにはうってつけよ。 友よ、私達が戦う相手が何であろうとも、オーダー以上のものはない。 -鉱山から離れましょう!","공장은 광산 옆에 있어. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지. 싸우는 상대가 무엇인지는 모르겠지만, 오더보다 더한 존재인 것 같아. 식당가로 향한 뒤 광산으로 들어가. 광석이 필요하니까.","De fabriek ligt naast de mijnen. Het Degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden. Mijn vriend, wat het ook is waar we tegen vechten, het is meer dan alleen de Orde. Terug naar de commons en dan naar de mijnen. We hebben erts nodig.",,"A fábrica fica próxima às minas. O minério de Degnin é magnético e explosivo, o ideal para derrubar campos de força. Meu amigo, seja lá o que estiver combatendo, é mais do que somente a Ordem. Volte ao refeitório e depois vá para as minas. Precisamos desse minério.",,,"Вход на фабрику — рядом со спуском в шахты. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. Друг мой, с чем бы мы не сражались, это нечто большее, чем просто Орден. Вернись назад в поселение и спустись в шахты. Нам нужна руда.", -"The factory is next to the mines. The degnin ore is magnetic and explosive, just the thing for shutting down force fields. Without letting down your guard, look for deposits of ore.",TXT_ILOG96,,,,"Továrna je vedle dolů. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole. Opatrně se podívej po ložiscích rudy.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Dasa Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten. Lass uns nach Erz suchen, aber wir müssen vorsichtig sein.",,,"La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magético y explosivo, justo para apagar campos de fuerza. Sin bajar la guardia, busca depósitos de mineral.","La Fábrica está junto a las minas. El mineral Degnin es magnético y explosivo, justo para apagar campos de fuerza. Sin bajar la guardia, busca depósitos de mineral.",,"L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. Cherche des veines de minerai, mais fais attention.",,,"工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 +鉱山から離れましょう!","공장은 광산 옆에 있어. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지. 싸우는 상대가 무엇인지는 모르겠지만, 오더보다 더한 존재인 것 같아. 식당가로 향한 뒤 광산으로 들어가. 광석이 필요하니까.","De fabriek ligt naast de mijnen. Het Degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden. Mijn vriend, wat het ook is waar we tegen vechten, het is meer dan alleen de Orde. Terug naar de commons en dan naar de mijnen. We hebben erts nodig.","Fabrikken ligger ved siden av gruvene. Degnin-malmen er magnetisk og eksplosiv, perfekt til å slå ut kraftfelt. Min venn, hva det enn er vi kjemper mot, er det mer enn bare Ordenen. Tilbake til allmenningen, og så til gruvene. Vi trenger malm.","Fabryka znajduje się obok kopalni. Ruda Degnin jest magnetyczna i wybuchowa. Nadaje się do wyłączania pól siłowych. Mój przyjacielu, cokolwiek to jest, z czym walczymy, to nie tylko Zakon. Wracamy do komnat, a potem do kopalni. Potrzebujemy rudy.","A fábrica fica próxima às minas. O minério de Degnin é magnético e explosivo, o ideal para derrubar campos de força. Meu amigo, seja lá o que estiver combatendo, é mais do que somente a Ordem. Volte ao refeitório e depois vá para as minas. Precisamos desse minério.",,"Fabrica e lângă mine, Richter se referă la minele din Degnin. Minereul de Degni e magnetic și exploziv, exact ceea ce ne trebuie pentru a opri câmpul de forță. Prietene, orice ar fi, ne luptăm cu ceva mai mult decât Ordinul. Înapoi la comune și dupaia, mine. Ne trebuie minereu.","Вход на фабрику — рядом со спуском в шахты. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. Друг мой, с чем бы мы не сражались, это нечто большее, чем просто Орден. Вернись назад в поселение и спустись в шахты. Нам нужна руда.",,"Fabriken ligger bredvid gruvorna. Degninmalmen är magnetisk och explosiv, precis vad man behöver för att stänga av kraftfält. Min vän, vad det än är vi slåss mot så är det mer än bara Orden. Tillbaka till allmänningen och sedan till gruvorna. Vi behöver malm.","Fabrika madenlerin yanında. Degnin cevheri manyetik ve patlayıcıdır, tam da güç alanlarını kapatmak için. Dostum, savaştığımız şey her neyse, Düzen'den daha fazlası. Avam kamarasına dönüp madenlere gidelim. Cevhere ihtiyacımız var." +"The factory is next to the mines. The degnin ore is magnetic and explosive, just the thing for shutting down force fields. Without letting down your guard, look for deposits of ore.",TXT_ILOG96,MAP14: Entrance.,,,"Továrna je vedle dolů. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole. Opatrně se podívej po ložiscích rudy.","Fabrikken ligger ved siden af minerne. Degninmalmen er magnetisk og eksplosiv, lige det rigtige til at lukke kraftfelter. Uden at sænke din vagt, skal du lede efter forekomster af malm.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Dasa Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten. Lass uns nach Erz suchen, aber wir müssen vorsichtig sein.",,"La fabriko estas apud la minejo de Degnin; ĝiaj minaĵoj estas magnetaj kaj eksplodpovaj, sufiĉe por detrui fortokampojn. Serĉu kolektojn de tiaj minaĵoj.","La fábrica está junto a la mina de Degnin; su mineral es magnético y explosivo, justo como para destruir campos de fuerza. Busca depósitos de ese mineral.",,"Tehdas on kaivoksen vieressä. Degnin-malmi on magneettista ja räjähdysherkkää, juuri omiaan purkamaan voimakenttiä. Etsi malmiesiintymiä varuillasi pysyen.","L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. Cherche des veines de minerai, mais fais attention.","A gyár a bánya mellett van. A degnini érc mágneses és robbanékony, pont tökéletes lesz az erőpajzs kiiktatásához. Figyelj az érc lerakódásokra, de közben figyelj magadra is.","La Fabbrica si trova accanto alle miniere. I minerali di Degnin sono magnetici ed esplosivi, giusto ciò che ci serve per disattivare i campi di forza. Senza abbassare la guardia, cerca di trovare alcuni depositi di minerali.","工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 デグニン石は綺麗だが可燃性で、フォースフィールドを消すにはうってつけよ。 -警戒を緩めることなく、鉱石の堆積所を探しましょう。","공장은 광산 옆에 있어. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지. 자신을 지킬 준비 단단히 하고, 캔 광석을 두는 곳을 찾아.","De fabriek ligt naast de mijnen. Het degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden. Zonder je waakzaamheid te laten verslappen, zoek je naar ertsafzettingen.",,"A fábrica fica próxima às minas. O minério de Degnin é magnético e explosivo, o ideal para derrubar campos de força. Não baixe a sua guarda e procure pelos depósitos de minério.",,,"Вход на фабрику — рядом со спуском в шахты. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. Поищи залежи руды, но не теряй бдительности!", -"Without letting down your guard, look for deposits of ore. These poor souls are drones. Their synaptic functions are being jammed by RC implants. We destroy the transmitter, and they're free.",TXT_ILOG97,,,,"Opatrně se podívej po ložiscích rudy. Tihle chudáci jsou trubcové, jejich synaptické funkce jsou narušené na dálku ovládanými implantáty. Když zničíme vysílačku, budou svobodní!","Lass uns nach Erz suchen, aber wir müssen vorsichtig sein. Diese armen Seelen sind wie Drohnen. Ihre Gehirnfunktionen werden von Implantaten blockiert. Wir müssen den Transmitter ausschalten, dann sind sie befreit.",,,"Sin bajar la guardia, busca depósitos de mineral. Estas pobres almas son zánganos. Sus funciones sinápticas están bloqueadas por implantes de control remoto. Destruimos el transmisor, y son libres.","Sin bajar la guardia, busca depósitos de mineral. Estas pobres almas son drones. Sus funciones sinápticas están siendo bloqueadas por implantes rc. Debemos destruir el transmisor y serán libres.",,"Cherche des veines de minerai, mais fais attention. Ces pauvres esclaves sont des drones. Leurs fonctions synaptiques sont brouillées par des implants radiocommandés. Détruisons le transmetteur pour les libérer.",,,"警戒を緩めることなく、鉱石の堆積所を探しましょう。 +警戒を緩めることなく、鉱石の堆積所を探しましょう。","공장은 광산 옆에 있어. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지. 자신을 지킬 준비 단단히 하고, 캔 광석을 두는 곳을 찾아.","De fabriek ligt naast de mijnen. Het degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden. Zonder je waakzaamheid te laten verslappen, zoek je naar ertsafzettingen.","Fabrikken er ved siden av gruvene. Degnin-malmen er magnetisk og eksplosiv, akkurat det vi trenger for å slå ut kraftfeltene. Uten å senke guarden, se etter forekomster av malm.","Fabryka jest obok kopalni. Ruda degnin jest magnetyczna i wybuchowa, w sam raz do wyłączania pól siłowych. Nie tracąc czujności, szukajcie złóż rudy.","A fábrica fica próxima às minas. O minério de Degnin é magnético e explosivo, o ideal para derrubar campos de força. Não baixe a sua guarda e procure pelos depósitos de minério.",,"Fabrica e lângă mine. Minereul de Degnin e magnetic și exploziv, exact ceea ce ne trebuie pentru câmpul de forță. Fără a lăsa garda jos, uită-te după depozite de minereu.","Вход на фабрику — рядом со спуском в шахты. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. Поищи залежи руды, но не теряй бдительности!",,"Fabriken ligger bredvid gruvorna. Degninmalmen är magnetisk och explosiv, precis vad vi behöver för att stänga av kraftfält. Utan att sänka garden, leta efter malmfyndigheter.","Fabrika madenlerin yanında. Degnin cevheri manyetik ve patlayıcıdır, tam da güç alanlarını kapatmak için. Gardınızı düşürmeden, cevher yataklarını arayın." +"Without letting down your guard, look for deposits of ore. These poor souls are drones. Their synaptic functions are being jammed by RC implants. We destroy the transmitter, and they're free.",TXT_ILOG97,"MAP14: After crossing the entrance yard. +(drone ≈ slave)",,,"Opatrně se podívej po ložiscích rudy. Tihle chudáci jsou trubcové, jejich synaptické funkce jsou narušené na dálku ovládanými implantáty. Když zničíme vysílačku, budou svobodní!","Uden at sænke paraderne, skal du lede efter malmforekomster. Disse stakkels sjæle er droner. Deres synaptiske funktioner bliver blokeret af RC-implantater. Vi ødelægger senderen, og så er de frie.","Lass uns nach Erz suchen, aber wir müssen vorsichtig sein. Diese armen Seelen sind wie Drohnen. Ihre Gehirnfunktionen werden von Implantaten blockiert. Wir müssen den Transmitter ausschalten, dann sind sie befreit.",,Serĉu kolektojn de degninaj minaĵoj. Estas sklavigitaj elfosantoj kun siaj sinapsoj barataj de teleregataj enplantaĵoj. Detrui la transmisiilon liberigos ilin.,Busca depósitos del mineral de Degnin. Hay mineros esclavizados con sus funciones sinápticas bloqueadas con implantes por mando a distancia. Destruir el transmisor los liberará.,Busca depósitos del mineral de Degnin. Hay mineros esclavizados con sus funciones sinápticas bloqueadas con implantes a control remoto. Destruir el transmisor los va a liberar.,"Etsi malmiesiintymiä, kuitenkin valppautesi säilyttäen. Nämä sieluparat ovat kuhnureita: Heidän synaptisia toimintojaan häiritään radio-ohjattavilla istutteilla. Me tuhoamme lähettimen, ja he ovat vapaat.","Cherche des veines de minerai, mais fais attention. Ces pauvres esclaves sont des drones. Leurs fonctions synaptiques sont brouillées par des implants radiocommandés. Détruisons le transmetteur pour les libérer.","Figyelj az érc lerakódásokra, de közben figyelj magadra is. Ezek a szerencsétlen lelkek csak drónok. A szinaptikus funkcióikat zavarják távolról irányítható implantátumokkal. Szétromboljuk a jeladókat, és szabaddá vállnak.","Senza abbassare la guardia, cerca di trovare alcuni depositi di minerali. Questi poveracci sono degli schiavi. Le loro funzioni cerebrali stanno venendo bloccate da degli impianti. Se distruggiamo il trasmettitore, saranno liberi.","警戒を緩めることなく、鉱石の堆積所を探しましょう。 ここの精神の乏しい労働者達は、RCインプラントでシナプス機能を妨害している。 -私達が送信機を破壊し、皆を解放しよう。","자신을 지킬 준비 단단히 하고, 캔 광석을 두는 곳을 찾아. 저 사람들은 불쌍한 광산의 노예들이야. 오더가 이식한 세뇌 장치 때문에 정상적인 뇌 기능을 잃었지. 전송기만 파괴한다면, 그들은 자유를 되찾을 수 있을 거야.","Zonder je waakzaamheid te laten verslappen, zoek je naar ertsafzettingen. Deze arme zielen zijn drones. Hun synaptische functies worden geblokkeerd door RC-implantaten. We vernietigen de zender en ze zijn vrij.",,Não baixe a sua guarda e procure por depósitos de minério. Esses pobres coitados são zangões. Suas funções sinápticas estão sendo bloqueadas por implantes de controle remoto. Se destruirmos o transmissor eles estarão livres.,,,"Поищи залежи руды, но не теряй бдительности. Эти несчастные души — дроны. Сигнал, поступающий на импланты, полностью подавляет их сознание. Если мы уничтожим передатчик, они свободны.", -"The factory is next to the mines. Without letting down your guard, look for deposits of ore. My suggestion is, toss the ore at the force field and then blast it, the resulting compression should create a magnetic blanket and turn off the lights.",TXT_ILOG99,,,,"Továrna je vedle dolů. Opatrně se podívej po ložiscích rudy. Můj návrh je, hoď rudu na to silové pole a pak ji odstřel. Výsledná komprese by měla vytvořit magnetický povlak a vypnout pole.","Die Fabrik liegt neben den Minen. Lass uns nach Erz suchen, aber wir müssen vorsichtig sein. Ich schlage vor, wir werfen das Erz vor das Krsftfeld und sprengen es dann. Die Druckwelle sollte einen Magnetpuls erzeugen, und die Lichter ausschalten.",,,"La fábrica está junto a las minas. Sin bajar la guardia, busca depósitos de mineral. Mi sugerencia es, tirar el mineral hacia el campo de fuerza y luego reventarlo, la presión resultante debería crear un manto magnético y apagar las luces.","La Fábrica está junto a las minas. Sin bajar la guardia, busca depósitos de mineral. Mi sugerencia es, aventar el mineral al campo de fuerza y luego hacerlo estallar, la compresión que resulte debería crear una manta magnética y apagar las luces.",,"L'usine est près des mines. Cherche des veines de minerai, mais fais attention. Je suggère que tu lance du minerai sur le champ de force et que tu tire dessus. Le champ magnétique que l'explosion causera désactivera les lumières.",,,"工場は鉱山の隣にあるわ。警戒を緩めることなく、鉱石の堆積所を探しましょう。 +私達が送信機を破壊し、皆を解放しよう。","자신을 지킬 준비 단단히 하고, 캔 광석을 두는 곳을 찾아. 저 사람들은 불쌍한 광산의 노예들이야. 오더가 이식한 세뇌 장치 때문에 정상적인 뇌 기능을 잃었지. 전송기만 파괴한다면, 그들은 자유를 되찾을 수 있을 거야.","Zonder je waakzaamheid te laten verslappen, zoek je naar ertsafzettingen. Deze arme zielen zijn drones. Hun synaptische functies worden geblokkeerd door RC-implantaten. We vernietigen de zender en ze zijn vrij.","Uten å senke guarden, se etter malmforekomster. Disse stakkarene er droner. Deres synaptiske funksjoner blokkeres av RC-implantater. Vi ødelegger senderen, og de er fri.","Nie opuszczając gardy, szukaj złóż rudy. Te biedne dusze to drony. Ich funkcje synaptyczne są zagłuszane przez implanty RC. Zniszczymy nadajnik, a oni będą wolni.",Não baixe a sua guarda e procure por depósitos de minério. Esses pobres coitados são escravos. Suas funções sinápticas estão sendo bloqueadas por implantes de controle remoto. Se destruirmos o transmissor eles estarão livres.,,"Fără a lăsa garda jos, uită-te după minereu. Sufletele ăstea sărmane sunt drone. Funcțiile lor sinaptice primesc interferență de la implanturile RC. Distrugem transmițătoarele și sunt libere.","Поищи залежи руды, но не теряй бдительности. Эти несчастные души — дроны. Сигнал, поступающий на импланты, полностью подавляет их сознание. Если мы уничтожим передатчик, они свободны.",,Utan att sänka garden letar du efter malmfyndigheter. Dessa stackars själar är drönare. Deras synaptiska funktioner blockeras av RC-implantat. Vi förstör sändaren och de är fria.,"Gardınızı düşürmeden, cevher yataklarını arayın. Bu zavallı ruhlar dron. Sinaptik fonksiyonları RC implantları tarafından engelleniyor. Vericiyi yok edersek özgür kalırlar." +"The factory is next to the mines. Without letting down your guard, look for deposits of ore. My suggestion is, toss the ore at the force field and then blast it, the resulting compression should create a magnetic blanket and turn off the lights.",TXT_ILOG99,MAP14: After James's room.,,,"Továrna je vedle dolů. Opatrně se podívej po ložiscích rudy. Můj návrh je, hoď rudu na to silové pole a pak ji odstřel. Výsledná komprese by měla vytvořit magnetický povlak a vypnout pole.","Fabrikken ligger ved siden af minerne. Uden at sænke din vagt, skal du lede efter malmforekomster. Mit forslag er, at kaste malmen mod kraftfeltet og derefter sprænge det, den resulterende kompression skulle skabe et magnetisk tæppe og slukke lyset.","Die Fabrik liegt neben den Minen. Lass uns nach Erz suchen, aber wir müssen vorsichtig sein. Ich schlage vor, wir werfen das Erz vor das Krsftfeld und sprengen es dann. Die Druckwelle sollte einen Magnetpuls erzeugen, und die Lichter ausschalten.",,Serĉu kolektojn de degninaj minaĵoj. Mi sugestus meti minaĵon ĉe la fortokampo kaj tiam pafi al ĝi: la rezultinta premo devus krei magnetan kampon kaj malŝalti ĝin.,Busca depósitos del mineral de Degnin. Yo diría de poner un mineral junto al campo de fuerza y luego dispararle: la presión resultante debería crear un campo magnético que lo desactive.,,"Tehdas on kaivoksen vieressä. Etsi malmiesiintymiä, kuitenkin valppautesi säilyttäen. Ehdotukseni on, että heität malmin voimakentään ja sitten posautat sen. Syntyvän paineaallon pitäisi muodostaa magneettinen peitto ja sammuttaa valot.","L'usine est près des mines. Cherche des veines de minerai, mais fais attention. Je suggère que tu lance du minerai sur le champ de force et que tu tire dessus. Le champ magnétique que l'explosion causera désactivera les lumières.","A gyár a bánya mellett van. Figyelj az érc lerakódásokra, de közben figyelj magadra is. Azt javaslom, hogy dobd az ércet az erőpajzsra, és robbantsd fel. A robbanástól létrejött kompresszió létre kell hogy hozzon egy mágneses palástot, és ezáltal kikapcsolja a lámpákat.","La Fabbrica si trova accanto alle miniere. Senza abbassare la guardia, cerca di trovare alcuni depositi di minerali. Il mio consiglio è, lancia uno dei minerali al campo di forza e poi fallo saltare in aria. Questo dovrebbe sprigionare l'energia sufficiente a disattivare il campo di forza.","工場は鉱山の隣にあるわ。警戒を緩めることなく、鉱石の堆積所を探しましょう。 私の案はフォースフィールドの近くに鉱石を置き撃って爆発させる方法よ。 -その結果、圧縮されていた磁場の反動で光を打ち消すわ。","공장은 광산 옆에 있어. 자신을 지킬 준비 단단히 하고, 캔 광석을 두는 곳을 찾아. 조언을 찾는다면, 광석을 방어막에 가까이 놔둔 뒤 쏴봐. 광석이 커다란 자기장을 만들 테고, 방어막을 완전히 무력화 시킬 거야.","De fabriek ligt naast de mijnen. Zonder je waakzaamheid te laten verslappen, zoek je naar ertsafzettingen. Mijn suggestie is om het erts naar het krachtveld te gooien en het vervolgens op te blazen, de resulterende compressie zou een magnetische deken moeten creëren en de lichten uit moeten doen.",,A fábrica fica próxima às minas. Não baixe a sua guarda e procure pelos depósitos de minério. Sugiro que você arremesse o minério ao campo de força e detone ele. A explosão deve gerar um campo magnético que vai apagar as luzes.,,,"Вход на фабрику — рядом со спуском в шахты. Поищи залежи руды, но не теряй бдительности. Мой план: бросить руду поближе к силовому полю и взорвать её. Взрыв создаст магнитное поле, которое накроет электронику и отрубит её.", -Now on to the factory. Exit the mines and you can't miss it. Let's find that machine and shut it down!,TXT_ILOG100,,,,A teď do továrny. Vyjdi z dolů a nemůžeš to minout. Pojďme najít ten stroj a vypnout ho!,"Und jetzt zur Fabrik. Verlasse die Minen, du kannst sie nicht verpassen. Lass uns die Maschine finden und abschalten.",,,Ahora vamos a la fábrica. Sal de las minas y no puedes perderlo. ¡Encontremos esa máquina y desactivémosla!,Ahora vamos a la Fábrica. Sal de las minas y no puedes perderla. ¡Encontremos esa máquina y desactivémosla!,,"C'est parti pour l'usine. Sors des mines, tu ne peux pas la rater. Trouvons cette machine et détruisons-la!",,,"工場へ今すぐ入ろう。鉱山の出口はすぐわかる。 -機械を探してシャットダウンさせろ!",이제 공장으로 향하자. 광산을 나가봐. 이 순간을 놓치면 안 돼. 얼른 그 기계를 찾아서 작동을 멈추자!,Nu naar de fabriek. Verlaat de mijnen en je kunt het niet missen. Laten we die machine vinden en hem uitschakelen!,,"Agora vá para a fábrica. Ao sair das minas você vai encontrá-la, não tem como errar. Vamos achar essa máquina e desligá-la de vez!",,,"Теперь — на фабрику. Выйди из шахты, и ты сразу увидишь вход. Найди эту машину и останови её!", -I'm reading massive neural wave distortions from straight ahead. I think we've found it. Let's get in there and shut it down!,TXT_ILOG102,,,,"Detekuju obří rušení nervových vln přímo před námi. Myslím, že jsme to našli. Pojďme tam a vypněme to!","Ich empfange massive neurale Verzerrungen direkt voraus. Ich denke, wir haben sie gefunden. Lass uns reingehen und sie abschalten.",,,Estoy leyendo distorsiones de ondas neuronales masivas adelante. Creo que la hemos encontrado. ¡Entremos ahí y destruyámosla!,Estoy leyendo distorsiones neuronales masivas adelante. Creo que la hemos encontrado. ¡Entremos y desactivémosla!,,Je recois des distorsions neurales colossales devant nous. Je crois que nous l'avons trouvé. Détruisons-la!,,,重い神経波歪曲が直に届いたわ。私達はそれを見つけたという事よ。,앞쪽에서 거대한 신경교란 파장이 감지되고 있어. 우리가 찾아낸 것 같아. 어서 들어가서 꺼버리자!,Ik lees enorme neurale golfvervormingen van rechtdoor. Ik denk dat we hem gevonden hebben. Laten we naar binnen gaan en de machine stilleggen!,,Estou vendo distorções enormes de ondas neurais. Acho que encontramos. Vamos entrar lá e desligar!,,,"Я вижу мощный источник помех прямо по курсу. Похоже, мы нашли конвертер. Войди и останови его!", -Just when I think we've seen it all! They go in human and come out... I dont even want to think about it. Destroy this horror!,TXT_ILOG103,,,,"Zrovna, když jsem myslela, že jsme to všechno viděli! Dovnitř jdou jako lidé a vyjdou... ani na to nechci myslet. Znič tu hrůzu!","Und da denkt man, man hätte schon alles gesehen. Die kommen als Menschen rein und kommen raus als... Ich möchte gar nicht drüber nachdenken. Zerstöre diesen Horror.",,,¡Justo cuando creía haberlo visto todo! Entran humanos y salen... No quiero ni pensarlo. ¡Destruye este horror!,¡Justo cuando creía haberlo visto todo! Entran humanos y salen... No quiero ni pensarlo. ¡Destruye este horror!,,"Et quand je pense avoir tout vu.. Des humains entrent, et puis.. Non, je ne veux pas y penser. Détruis cette horreur!",,,"今まで見てきたことについて考えている! +その結果、圧縮されていた磁場の反動で光を打ち消すわ。","공장은 광산 옆에 있어. 자신을 지킬 준비 단단히 하고, 캔 광석을 두는 곳을 찾아. 조언을 찾는다면, 광석을 방어막에 가까이 놔둔 뒤 쏴봐. 광석이 커다란 자기장을 만들 테고, 방어막을 완전히 무력화 시킬 거야.","De fabriek ligt naast de mijnen. Zonder je waakzaamheid te laten verslappen, zoek je naar ertsafzettingen. Mijn suggestie is om het erts naar het krachtveld te gooien en het vervolgens op te blazen, de resulterende compressie zou een magnetische deken moeten creëren en de lichten uit moeten doen.","Fabrikken ligger ved siden av gruvene. Uten å senke garden, se etter malmforekomster. Mitt forslag er å kaste malmen mot kraftfeltet og deretter sprenge den, den resulterende kompresjonen bør skape et magnetisk teppe og slå av lysene.","Fabryka jest obok kopalni. Nie spuszczając gardy, szukajcie złóż rudy. Moja propozycja to, podrzuć rudę na pole siłowe, a następnie wysadź je, powstała kompresja powinna stworzyć koc magnetyczny i wyłączyć światła.",A fábrica fica próxima às minas. Não baixe a sua guarda e procure pelos depósitos de minério. Sugiro que você arremesse o minério ao campo de força e detone ele. A explosão deve gerar um campo magnético que vai apagar as luzes.,,"Fabrica e lăngă mine. Fără a lăsa garda jos uită-te dupa depozite de minereu. Sugestia mea e, aruncă minereul la câmpul de forță și aruncă-l în aer, comprimarea ce va rezulta în urma ei ar trebui să creeze o încărcătură magnetică care va distruge luminile.","Вход на фабрику — рядом со спуском в шахты. Поищи залежи руды, но не теряй бдительности. Мой план: бросить руду поближе к силовому полю и взорвать её. Взрыв создаст магнитное поле, которое накроет электронику и отрубит её.",,"Fabriken ligger bredvid gruvorna. Utan att sänka garden, leta efter malmfyndigheter. Mitt förslag är att kasta malmen mot kraftfältet och sedan spränga det, den resulterande kompressionen bör skapa en magnetisk filt och släcka ljuset.","Fabrika madenlerin yanında. Gardınızı düşürmeden, cevher yataklarını arayın. Benim önerim, cevheri güç alanına fırlatın ve sonra patlatın, ortaya çıkan sıkıştırma manyetik bir örtü oluşturmalı ve ışıkları kapatmalıdır." +Now on to the factory. Exit the mines and you can't miss it. Let's find that machine and shut it down!,TXT_ILOG100,MAP14: After destroying the transmitter.,,,A teď do továrny. Vyjdi z dolů a nemůžeš to minout. Pojďme najít ten stroj a vypnout ho!,"Nu videre til fabrikken. Forlad minerne, og du kan ikke undgå at se den. Lad os finde den maskine og lukke den ned!","Und jetzt zur Fabrik. Verlasse die Minen, du kannst sie nicht verpassen. Lass uns die Maschine finden und abschalten.",,"Nun al la fabriko, tuj tra la elirejo de la minejo. Trovu kaj malŝaltu tiun maŝinon!","Ahora a la fábrica, justo saliendo de la mina. ¡Encontremos esa máquina y apaguémosla!",,"Nyt sitten tehtaaseen. Poistu kaivoksesta, ja löydät sen varmasti. Etsitään ja sammutetaan se kone!","C'est parti pour l'usine. Sors des mines, tu ne peux pas la rater. Trouvons cette machine et détruisons-la!","Most pedig a gyár. Rögtön szembe van veled ahogy kilépsz a bányából, nem tudod eltéveszteni. Keressük meg azt a gépet, és állítsuk le!",Ora entriamo nella Fabbrica. Uscendo dalle miniere non puoi sbagliare. Troviamo quella macchina e disattiviamola!,"工場へ今すぐ入ろう。鉱山の出口はすぐわかる。 +機械を探してシャットダウンさせろ!",이제 공장으로 향하자. 광산을 나가봐. 이 순간을 놓치면 안 돼. 얼른 그 기계를 찾아서 작동을 멈추자!,Nu naar de fabriek. Verlaat de mijnen en je kunt het niet missen. Laten we die machine vinden en hem uitschakelen!,"Nå videre til fabrikken. Gå ut av gruvene, og du kan ikke gå glipp av den. La oss finne den maskinen og slå den av!",Teraz przejdź do fabryki. Wyjdź z kopalni i nie możesz jej przegapić. Znajdźmy tę maszynę i wyłączmy ją!,"Agora vá para a fábrica. Ao sair das minas você vai encontrá-la, não tem como errar. Vamos achar essa máquina e desligá-la de vez!",,"Acum înspre fabrică. Ieși din mine, nu o poți rata. Să găsim mașina aia și să o oprim!","Теперь — на фабрику. Выйди из шахты, и ты сразу увидишь вход. Найди эту машину и останови её!",,Nu fortsätter vi till fabriken. Gå ut ur gruvorna och du kan inte missa den. Låt oss hitta den där maskinen och stänga av den!,Şimdi fabrikaya gidelim. Madenlerden çıkın ve onu kaçırmayın. Hadi şu makineyi bulup kapatalım! +I'm reading massive neural wave distortions from straight ahead. I think we've found it. Let's get in there and shut it down!,TXT_ILOG102,"MAP20: Path to Conversion Chapel (MAP24). +(""neural oscillation"" or ""brainwave"")",,,"Detekuju obří rušení nervových vln přímo před námi. Myslím, že jsme to našli. Pojďme tam a vypněme to!","Jeg kan se massive neurale bølgeforvrængninger lige forude. Jeg tror, vi har fundet den. Lad os komme ind og lukke den ned!","Ich empfange massive neurale Verzerrungen direkt voraus. Ich denke, wir haben sie gefunden. Lass uns reingehen und sie abschalten.",,"Mi legas amasajn distordojn de cerbaj ondoj antaŭ vi. Ŝajnas, ke ni trovis ĝin. Ni eniru kaj malŝaltu ĝin!",Estoy leyendo distorsiones masivas de ondas cerebrales delante. Parece que la hemos encontrado. ¡Entremos ahí y apaguémosla!,Estoy leyendo distorsiones masivas de ondas cerebrales adelante. Parece que la encontramos. ¡Entremos ahí y apaguémosla!,Havaitsen massivisia hermoaaltovääristymiä suoraan edessä. Luulen löytäneemme sen. Mennään sisään ja sammutetaan se!,Je recois des distorsions neurales colossales devant nous. Je crois que nous l'avons trouvé. Détruisons-la!,Erős ideghullám zavaró jeleket fogok. Azt hiszem megtaláltuk. Menjünk be és állítsuk le!,Sto ricevendo potenti segnali distorti proprio davanti a te. Penso che l'abbiamo trovata. Entriamo e spegnamo questa macchina!,重い神経波歪曲が直に届いたわ。私達はそれを見つけたという事よ。,앞쪽에서 거대한 신경교란 파장이 감지되고 있어. 우리가 찾아낸 것 같아. 어서 들어가서 꺼버리자!,Ik lees enorme neurale golfvervormingen van rechtdoor. Ik denk dat we hem gevonden hebben. Laten we naar binnen gaan en de machine stilleggen!,Jeg leser massive nevrale bølgeforvrengninger rett fram. Jeg tror vi har funnet den. La oss gå inn og slå den av!,Odczytuję potężne zniekształcenia fal neuronowych z prostej drogi. Chyba ją znaleźliśmy. Wejdźmy tam i wyłączmy ją!,Estou vendo distorções enormes de ondas neurais. Acho que encontramos. Vamos entrar lá e desligar!,,"Citesc distorsiune neurale masive drept din față, cred că am găsit-o. Să intrăm și să o oprim.","Я вижу мощный источник помех прямо по курсу. Похоже, мы нашли конвертер. Войди и останови его!",,Jag läser massiva neurala vågförvrängningar från rakt fram. Jag tror att vi har hittat den. Låt oss gå in där och stänga av den!,Tam karşıdan büyük sinir dalgası bozulmaları okuyorum. Sanırım onu bulduk. Oraya girelim ve onu kapatalım! +Just when I think we've seen it all! They go in human and come out... I dont even want to think about it. Destroy this horror!,TXT_ILOG103,MAP24: Converter room.,,Just when I think we've seen it all! They go in human and come out... I don't even want to think about it. Destroy this horror!,"Zrovna, když jsem myslela, že jsme to všechno viděli! Dovnitř jdou jako lidé a vyjdou... ani na to nechci myslet. Znič tu hrůzu!","Lige når jeg tror, vi har set det hele! De går ind i et menneske og kommer ud... Jeg vil ikke engang tænke på det. Ødelæg denne rædsel!","Und da denkt man, man hätte schon alles gesehen. Die kommen als Menschen rein und kommen raus als... Ich möchte gar nicht drüber nachdenken. Zerstöre diesen Horror.",,"Kaj mi kredis, ke mi jam vidis ĉiajn aferojn! Ili eniras kiel homojn kaj eliras... Mi eĉ ne volas pensi pri tio. Haltigu ĉi tiun teruraĵon!",¡Justo cuando creía haberlo visto todo! Entran humanos y salen... No quiero ni pensarlo. ¡Detén este horror!,,Juuri kun luulen nähneemme kaiken! He menevät sisään ihmisinä ja tulevat ulos... En halua edes ajatellakaan sitä. Tuhoa tämä kauhistus!,"Et quand je pense avoir tout vu.. Des humains entrent, et puis.. Non, je ne veux pas y penser. Détruis cette horreur!","Amikor azt hittem, hogy mindent láttunk. Emberként mennek be, és úgy jönnek ki mint egy...nem is akarok rá gondolni. Semmisítsd meg ezt a horrort!",E io che pensavo di averle viste tutte! Entrano umani ed escono fuori... Non ci voglio neanche pensare. Distruggi questo orrore!,"今まで見てきたことについて考えている! 奴は人の内部から出てくる...それについて考えたくないわ。 -この恐怖を打ち消すんだ!",이렇게 끔찍한 모습을 보게 되다니! 멀쩡한 사람이 저곳에 들어갔다 나온 모습을... 차마 생각하기도 싫어. 저 경악스러운 것을 파괴해!,Net nu ik denk dat we alles hebben gezien! Ze gaan menselijk naar binnen en komen eruit.... Ik wil er niet eens over nadenken. Vernietig deze verschrikking!,,E eu pensei que já tinha visto de tudo! Eles entram humanos e saem... Eu não quero nem pensar nisso. Destrua essa coisa horripilante!,,,"А я-то думала, что хуже уже не будет! Они входят людьми, а выходят... Не хочу даже думать об этом. Покончи с этим кошмаром!", -Macil's gone nuts. He just knowingly sent 200 men to their deaths. I want vengeance! For the dead and for the living dead! Let's get back and find out what's going on.,TXT_ILOG104,,,,"Macil zešílel. Jen tak poslal dvě stě mužů na smrt. Chci odplatu - za mrtvé i živé mrtvé! Vraťme se a pojďme zjistit, co se stalo.","Macil hat den Verstand verloren. Er hat gerade absichtlich 200 unserer Leute in den Tod geschickt. Ich will Rache! Für die Toten und für die lebenden Toten. Lass uns zurückgehen und herausfinden, was da los ist.",,,Macil se ha vuelto loco. Conscientemente ha enviado 200 hombres a su muerte. ¡Quiero venganza! ¡Por los muertos y los muertos vivientes! Regresemos y descubramos que está pasando.,Macil se ha vuelto loco. Conscientemente envió a 200 hombres a su muerte. ¡Quiero venganza! Por los muertos y por los muertos vivientes! Regresemos y veamos que está pasando.,,"Macil a complètement perdu les pédales! Il a envoyé 200 hommes se faire tuer, et il le savait! Il faut les venger, pour eux et pour leurs camarades! On retourne à la base et on va trouver ce qu'il se passe.",,,"オラクルが正しかった。マシルはイカれていたなんて。 +この恐怖を打ち消すんだ!",이렇게 끔찍한 모습을 보게 되다니! 멀쩡한 사람이 저곳에 들어갔다 나온 모습을... 차마 생각하기도 싫어. 저 경악스러운 것을 파괴해!,Net nu ik denk dat we alles hebben gezien! Ze gaan menselijk naar binnen en komen eruit.... Ik wil er niet eens over nadenken. Vernietig deze verschrikking!,Akkurat når jeg tror vi har sett alt! De går inn som mennesker og kommer ut... Jeg vil ikke engang tenke på det. Ødelegg denne grusomheten!,"Właśnie wtedy, gdy myślę, że widzieliśmy już wszystko! Wchodzą w człowieka i wychodzą... Nie chcę nawet o tym myśleć. Zniszczyć ten horror!",E eu pensei que já tinha visto de tudo! Eles entram humanos e saem... Eu não quero nem pensar nisso. Destrua essa coisa horripilante!,,Exact când credeam că am văzut tot. Intră oameni și ies...Nici nu vreau să mă gândesc. Distruge-o!,"А я-то думала, что хуже уже не будет! Они входят людьми, а выходят... Не хочу даже думать об этом. Покончи с этим кошмаром!",,Precis när jag tror att vi har sett allt! De går in som människor och kommer ut... Jag vill inte ens tänka på det. Förstör denna skräck!,Tam da her şeyi gördüğümüzü düşündüğüm anda! İnsana giriyorlar ve çıkıyorlar. Bunu düşünmek bile istemiyorum. Bu dehşeti yok edin! +Macil's gone nuts. He just knowingly sent 200 men to their deaths. I want vengeance! For the dead and for the living dead! Let's get back and find out what's going on.,TXT_ILOG104,MAP24: After destroying the converter.,,,"Macil zešílel. Jen tak poslal dvě stě mužů na smrt. Chci odplatu - za mrtvé i živé mrtvé! Vraťme se a pojďme zjistit, co se stalo.","Macil er blevet skør. Han har lige bevidst sendt 200 mænd i døden. Jeg vil have hævn! For de døde og for de levende døde! Lad os tage tilbage og finde ud af, hvad der foregår.","Macil hat den Verstand verloren. Er hat gerade absichtlich 200 unserer Leute in den Tod geschickt. Ich will Rache! Für die Toten und für die lebenden Toten. Lass uns zurückgehen und herausfinden, was da los ist.",,Macil freneziĝis: li intence sendis 200 homojn al la morto. Reiru al li por malkaŝi la veron.,Macil se ha vuelto loco: ha enviado intencionalmente a 200 hombres directo a la muerte. Regresemos a ver que está pasando.,Macil se volvió loco: mandó intencionalmente a 200 hombres directo a la muerte. Regresemos a ver qué está pasando.,"Macil on tullut hulluksi: Hän juuri lähetti tietoisesti 200 miestä surmaansa. Vaadin kostoa, sekä kuolleitten että elävien kuolleitten puolesta! Palataan ja selvitetään, mitä oikein on meneillään.","Macil a complètement perdu les pédales! Il a envoyé 200 hommes se faire tuer, et il le savait! Il faut les venger, pour eux et pour leurs camarades! On retourne à la base et on va trouver ce qu'il se passe.","Macil megőrült. 200 embert küldött a halálába szándékosan. Bosszút akarok! A halottakért, és az élőhalottakért! Húzzunk vissza és derítsük ki mi folyik.",Macil deve essere impazzito. Ha mandato consciamente 200 uomini verso la morte. Voglio vendetta! Per i morti e per i morti viventi! Ritorniamo alla base e scopriamo cosa sta succedendo.,"オラクルが正しかった。マシルはイカれていたなんて。 彼は故意に200人以上の人々を死に追いやっていた。 復讐しなくては。死んだ人達の為、そして今生きている人達の為にも! -戻って何が起きているかも調べるんだ。",마실이 정신 나갔나 봐. 모든 것을 알면서도 200 명이나 되는 병력을 보내서 죽게 했어. 과부들과 망령들을 위한 복수를 할 시간이야! 기지로 돌아가서 한번 그에게 여쭤봐.,Macil is gek geworden. Hij heeft net bewust 200 mannen naar hun dood gestuurd. Ik wil wraak! Voor de doden en voor de levende doden! Laten we teruggaan en uitzoeken wat er aan de hand is.,,O Macil enlouqueceu. Ele acabou de mandar 200 homens para as suas mortes e ele sabia disso. Eu quero vingança! Pelos mortos e pelos mortos-vivos! Vamos voltar e descobrir o que está acontecendo.,,,"Мэйсил озверел. Он намеренно послал двести человек на верную смерть. Я жажду мести! За убитых и за живых мертвецов! Давай вернёмся и выясним, что происходит.", -"The factory leads to a ""lab"", and they're getting a Sigil piece power signature from within. Back to the factory and our next step to freedom.",TXT_ILOG106,,,,"Továrna vede do „laboratoře“, a z ní detekují energii Pečeťe. Zpátky do továrny a našemu dalšímu kroku ke svobodě.","In der Fabrik gibt es ein „Labor“, und dort gibt es eine Sigil-Signatur. Zurück zur Fabrik und dem nächsten Schritt zu unserer Freiheit.",,,"La fábrica conduce a un 'laboratorio', y están obteniendo una señal de poder del Emblema desde dentro. De vuelta a la fábrica y nuestro siguiente paso a la libertad.",La Fábrica conduce a un Laboratorio y tiene una firma de poder del Emblema desde adentro. Regresemos a la Fábrica y a nuestro siguiente paso a la libertad.,,"L'usine mène à un « laboratoire », et je reçois le signal d'une pièce du Sigil à l'intérieur. Retournons à l'usine pour prendre le prochain pas vers la liberté.",,,"リヒターの報告では我々が破壊した工場は'研究所'に繋がっていて、 -奴等はシジルの調印を内部から得ている。工場に戻って自由への次の段階に進みましょう",이 공장은 '연구소'로 연결돼. 그리고 지금 오더가 그 안에서 시질의 힘을 빌릴 조짐이 보여. 공장으로 돌아가서 자유 투쟁을 계속 진행해!,"De fabriek leidt naar een ""lab"", en ze krijgen een Sigil stuk macht handtekening van binnenuit. Terug naar de fabriek en onze volgende stap naar vrijheid.",,"A fábrica leva a um ""laboratório"" e é de lá de onde eles estão recebendo um sinal da energia de uma peça do Sigilo. De volta à fábrica e ao próximo passo à liberdade.",,,"За фабрикой находится «лаборатория», и мы засекли характерную энергию фрагмента Сигила, исходящую оттуда. Вернись на фабрику и сделай ещё один шаг к нашему освобождению.", -"Find the Bishop and destroy him! Once he's dead, return to the Oracle.",TXT_ILOG120,,,,"Najdi Biskupa a znič ho! Až ho zabiješ, vrať se k Věštci.","Finde den Bischof und vernichte ihn. Sobald er tot ist, kehre zum Orakel zurück.",,,"¡Encuentra al Obispo y destrúyelo! En cuanto esté muerto, regresa con el Oráculo.","¡Encuentra al Obispo y destruyelo! Cuando esté muerto, regresa con el Oráculo.",,"Trouve l'évêque et tues-le! Une fois qu'il est mort, retourne à l'Oracle.",,,ビショップを見つけて殺したらオラクルの元へ戻れ。,비숍을 찾아서 그를 파괴해! 시질 조각을 얻은 뒤 오라클에게 돌아가.,"Vind de bisschop en vernietig hem! Als hij dood is, keer je terug naar het Orakel.",,Encontre o Bispo e destrua ele! Assim que ele morrer volte ao Oráculo.,,,"Найди Епископа и уничтожь его! После, вернись к Оракулу.", -The Loremaster's lab is beyond the teleporter that just opened. Let's go find out what he was just yapping about.And our next step to freedom.,TXT_ILOG122,,,,"Dějepiscova laboratoř je za teleportérem, který se právě otevřel. Pojďme se podívat, o čem to blábolil. A k našemu dalšímu kroku ke svobodě.","Das Labor des Wissensmeisters ist jenseits des Teleporters, der gerade geöffnet wurde. Lass uns herausfinden, worüber er da gerade geschwafelt hat. Und zum nächsten Schritt für unsere Freiheit.",,,El laboratorio del Maestro del Conocimiento está al otro lado del teletransporte que acaba de abrirse. Vayamos a ver de qué tanto parloteaba. Y nuestro siguiente paso a la libertad.,El laboratorio del Maestro del Conocimiento está más allá del teleporte que se ha abierto. Vamos a encontrar de qué tanto balbucea. Y nuestro siguiente paso a la libertad.,,"Le laboratoire du Maître des Traditions est de l'autre côté du téléporteur que nous venons d'ouvrir. Allons voir pourquoi il était en train de brailler, et prendre le prochain pas vers la liberté.",,,"ロアマスター研究所は開いたばかりのテレポーターを越えた先だ。 -奴が何をやらかしているか調べろ。次の自由を解放するために。",로어마스터의 연구소는 방금 열린 텔레포터를 통해서 입장이 가능해. 어떤 예언을 지껄이는지 한번 확인하러 가봐. 그리고 자유 투쟁을 계속 진행해!,Het lab van de Kennismeester is voorbij de teleporter die net geopend is. Laten we gaan uitzoeken waar hij net over aan het zeuren was. En onze volgende stap naar vrijheid.,,O laboratório do Mestre do Conhecimento está depois desse teletransportador que acaba de abrir. Vamos lá descobrir sobre o que ele estava tagarelando. E ao nosso próximo passo à liberdade.,,,"Телепорт, который ты нашёл, приведёт тебя в лабораторию Хранителя мудрости. Давай узнаем, о чём он там бормотал, и сделаем ещё один шаг к освобождению.", -"Come on, let's get the hell out of here. The force field is down, off to the Bishop's tower. Once he's dead, get back to the Oracle.",TXT_ILOG211,,,,"No tak, dostaňme se sakra odsud. Silové pole je kaput, jdeme do Biskupovy věže. Až ho zabiješ, vrať se k Věštci.","Komm schon, lass uns von hier verschwinden. Das Kraftfeld ist abgeschaltet, also ab zum Turm des Bischofs. Sobald er tot ist, geht es zurück zum Orakel",,,"Venga, larguémonos de aquí. El campo de fuerza está desactivado, derechos a la torre del Obispo. En cuanto esté muerto, regresa con el Oráculo.","Vamos, larguémonos de aquí. El campo de fuerza fue desactivado, vamos a la torre del Obispo. Cuando esté muerto, regresa con el Oráculo.",,"Allez, il faut qu'on se barre d'ici. Le champ de force est hors-ligne. Entre dans la tour de l'évêque. Quand il sera mort, retourne à l'Oracle.",,,"頼むからこんな所さっさと出よう。 +戻って何が起きているかも調べるんだ。",마실이 정신 나갔나 봐. 모든 것을 알면서도 200 명이나 되는 병력을 보내서 죽게 했어. 과부들과 망령들을 위한 복수를 할 시간이야! 기지로 돌아가서 한번 그에게 여쭤봐.,Macil is gek geworden. Hij heeft net bewust 200 mannen naar hun dood gestuurd. Ik wil wraak! Voor de doden en voor de levende doden! Laten we teruggaan en uitzoeken wat er aan de hand is.,Macil har gått fra vettet. Han sendte 200 menn i døden med viten og vilje. Jeg vil ha hevn! For de døde og for de levende døde! La oss dra tilbake og finne ut hva som foregår.,"Macilowi odbiło. Właśnie świadomie wysłał 200 ludzi na śmierć. Chcę zemsty! Za zmarłych i za żywych zmarłych! Wracajmy i dowiedzmy się, co się dzieje.",O Macil enlouqueceu. Ele acabou de mandar 200 homens para as suas mortes e ele sabia disso. Eu quero vingança! Pelos mortos e pelos mortos-vivos! Vamos voltar e descobrir o que está acontecendo.,,Macil a înnebunit. A trimis intenționat 200 oameni la moarte. Vreau răzbunare! Pentru morți și morții vii! Să ne întoarcem și să vedem despre ce e vorba.,"Мэйсил озверел. Он намеренно послал двести человек на верную смерть. Я жажду мести! За убитых и за живых мертвецов! Давай вернёмся и выясним, что происходит.",,Macil har blivit galen. Han skickade just medvetet 200 män i döden. Jag vill ha hämnd! För de döda och för de levande döda! Låt oss återvända och ta reda på vad som pågår.,Macil çıldırdı. Bile bile 200 adamı ölüme gönderdi. İntikam istiyorum! Ölüler ve yaşayan ölüler için! Geri dönüp neler olduğunu öğrenelim. +"The factory leads to a ""lab"", and they're getting a Sigil piece power signature from within. Back to the factory and our next step to freedom.",TXT_ILOG106,MAP10: After killing Macil while having destroyed the converter in MAP24.,,,"Továrna vede do „laboratoře“, a z ní detekují energii Pečeťe. Zpátky do továrny a našemu dalšímu kroku ke svobodě.","Fabrikken fører til et ""laboratorium"", og de får en signatur af en Sigil-styks kraft fra det indre. Tilbage til fabrikken og vores næste skridt mod frihed.","In der Fabrik gibt es ein „Labor“, und dort gibt es eine Sigil-Signatur. Zurück zur Fabrik und dem nächsten Schritt zu unserer Freiheit.",,"La fabriko kondukas al «laboratorio» de kie ni malkovris signon de la povo de la Sigelo. Reiru al la fabriko, nia sekva paŝo al la libereco.","La fábrica lleva a un «laboratorio» en donde detectamos una señal del poder del Emblema. De vuelta a la fábrica, nuestro siguiente paso a la libertad.",,"Tehdas johtaa ""laboratorioon"", ja he lukevat sisältä Sinettiosasen energiajälkiä. Takaisin tehtaaseen ja kohti seuraavaa askeltamme vapauteen.","L'usine mène à un « laboratoire », et je reçois le signal d'une pièce du Sigil à l'intérieur. Retournons à l'usine pour prendre le prochain pas vers la liberté.","A gyár egy laboratúriumba vezet, és pecsét erő sugárzást észlelünk belülről. Forduljunk vissza a gyárhoz, ezzel közelebb kerülve a szabadsághoz.","La Fabbrica porta a un ""laboratorio"", ed al suo interno è stato identificato un segnale di un pezzo del Sigillo. Ritorniamo alla fabbrica e il nostro prossimo passo per la libertà.","リヒターの報告では我々が破壊した工場は'研究所'に繋がっていて、 +奴等はシジルの調印を内部から得ている。工場に戻って自由への次の段階に進みましょう",이 공장은 '연구소'로 연결돼. 그리고 지금 오더가 그 안에서 시질의 힘을 빌릴 조짐이 보여. 공장으로 돌아가서 자유 투쟁을 계속 진행해!,"De fabriek leidt naar een ""lab"", en ze krijgen een Sigil stuk macht handtekening van binnenuit. Terug naar de fabriek en onze volgende stap naar vrijheid.","Fabrikken fører til et ""laboratorium"", og de får en Sigil-kraftsignatur fra innsiden. Tilbake til fabrikken og vårt neste skritt mot frihet.","Fabryka prowadzi do ""laboratorium"", a z jego wnętrza wydobywa się sygnatura mocy kawałka Sigil. Powrót do fabryki i nasz kolejny krok do wolności.","A fábrica leva a um ""laboratório"" e é de lá de onde eles estão recebendo um sinal da energia de uma peça do Sigilo. De volta à fábrica e ao próximo passo à liberdade.",,"Fabrica duce înspre un laborator, și primesc putere de la o piesă din Sigiliu. Înapoi la fabrică și încă un pas spre libertate.","За фабрикой находится «лаборатория», и мы засекли характерную энергию фрагмента Печати, исходящую оттуда. Вернись на фабрику и сделай ещё один шаг к нашему освобождению.",,"Fabriken leder till ett ""labb"", och de får en Sigil piece power signatur inifrån. Tillbaka till fabriken och vårt nästa steg mot frihet.","Fabrika bir ""laboratuvara"" açılıyor ve içeriden bir Sigil parçası güç imzası alıyorlar. Fabrikaya geri dönelim ve özgürlüğe bir sonraki adımımızı atalım." +"Find the Bishop and destroy him! Once he's dead, return to the Oracle.",TXT_ILOG120,MAP16: Entrance → Central door.,,,"Najdi Biskupa a znič ho! Až ho zabiješ, vrať se k Věštci.","Find biskoppen og ødelæg ham! Når han er død, skal du vende tilbage til Oraklet.","Finde den Bischof und vernichte ihn. Sobald er tot ist, kehre zum Orakel zurück.",,Trovu kaj mortigu la Episkopon! Tiam reiru al la Orakolo.,¡Encuentra al Obispo y mátalo! Luego regresa con el Oráculo.,,"Löydä Piispa ja tuhoa hänet! Kun hän on kuollut, palaa Oraakkelin luokse.","Trouve l'évêque et tues-le! Une fois qu'il est mort, retourne à l'Oracle.","Találd meg a Püspököt és öld meg! Ha meghalt, menj az Orákulumhoz.","Trova il Vescovo e distruggilo! Una volta ucciso, ritorna dall'Oracolo.",ビショップを見つけて殺したらオラクルの元へ戻れ。,비숍을 찾아서 그를 파괴해! 시질 조각을 얻은 뒤 오라클에게 돌아가.,"Vind de bisschop en vernietig hem! Als hij dood is, keer je terug naar het Orakel.","Finn biskopen og tilintetgjør ham! Når han er død, gå tilbake til Oraklet.","Znajdź Bishopa i zniszcz go! Gdy już będzie martwy, wróć do Oracle.",Encontre o Bispo e destrua ele! Assim que ele morrer volte ao Oráculo.,,"Găsește Episcopul și distruge-l! Odată ce e mort, întoarce-te la Oracol.","Найди Епископа и уничтожь его! После, вернись к Оракулу.",,Hitta biskopen och förgöra honom! När han är död återvänder du till oraklet.,Piskoposu bulun ve onu yok edin! O öldükten sonra Kahin'e dönün. +The Loremaster's lab is beyond the teleporter that just opened. Let's go find out what he was just yapping about. And our next step to freedom.,TXT_ILOG122,MAP12?,,,"Dějepiscova laboratoř je za teleportérem, který se právě otevřel. Pojďme se podívat, o čem to blábolil. A k našemu dalšímu kroku ke svobodě.","Loremesterens laboratorium ligger bag teleporteren, der lige er åbnet. Lad os finde ud af, hvad han lige pludrede om. Og vores næste skridt til frihed.","Das Labor des Wissensmeisters ist jenseits des Teleporters, der gerade geöffnet wurde. Lass uns herausfinden, worüber er da gerade geschwafelt hat. Und zum nächsten Schritt für unsere Freiheit.",,"La ĵus malfermiĝinta teleportilo kondukas al la laboratorio de la Folkloristo. Ni iru malkaŝi tion, pri kio li blablais.",El teletransportador que acaba de abrirse lleva al laboratorio del Maestro del Conocimiento. Vayamos a ver de qué tanto parloteaba.,,"Oppi-Isän laboratorio on juuri avautuneen kaukosiirtimen tuolla puolen. Mennään ottamaan selvää, mistä hän juuri oikein pälätti, ja kohti seuraavaa askeltamme vapauteen.","Le laboratoire du Maître des Traditions est de l'autre côté du téléporteur que nous venons d'ouvrir. Allons voir pourquoi il était en train de brailler, et prendre le prochain pas vers la liberté.",A Tanmester laborja a most megnyílt teleport túloldalán van. Derítsük ki miről is hadovált az imént. Még egy lépés a szabadság irányába.,Il laboratorio del Sapiente si trova giusto oltre questo teletrasporto. Andiamo a vedere di cosa stava blaterando. E verso il nostro prossimo passo per la libertà.,"ロアマスター研究所は開いたばかりのテレポーターを越えた先だ。 +奴が何をやらかしているか調べろ。次の自由を解放するために。",로어마스터의 연구소는 방금 열린 텔레포터를 통해서 입장이 가능해. 어떤 예언을 지껄이는지 한번 확인하러 가봐. 그리고 자유 투쟁을 계속 진행해!,Het lab van de Kennismeester is voorbij de teleporter die net geopend is. Laten we gaan uitzoeken waar hij net over aan het zeuren was. En onze volgende stap naar vrijheid.,Loremesterens laboratorium er bortenfor teleporteren som nettopp åpnet seg. La oss finne ut hva han snakket om. Og vårt neste skritt mot frihet.,"Laboratorium Loremastera jest za teleporterem, który właśnie się otworzył. Dowiedzmy się, o czym on właśnie gadał. I nasz następny krok do wolności.",O laboratório do Mestre do Conhecimento está depois desse teletransportador que acaba de abrir. Vamos lá descobrir sobre o que ele estava tagarelando. E ao nosso próximo passo à liberdade.,,Laboratorul Maestrului Cunoștiințelor e dincolo de teleportorul care tocmai s-a deschis. Să mergem și să vedem despre ce tot bolborosea. Și următorul nostru pas spre libertate.,"Телепорт, который ты нашёл, приведёт тебя в лабораторию Хранителя мудрости. Давай узнаем, о чём он там бормотал, и сделаем ещё один шаг к освобождению.",,Läromästarens labb ligger bortom teleportern som just öppnades. Nu går vi och tar reda på vad han just babblade om. Och vårt nästa steg till frihet.,Loremaster'ın laboratuvarı az önce açılan ışınlayıcının ötesinde. Gidip neden bahsettiğini öğrenelim. Ve özgürlüğe giden bir sonraki adımımızı. +"Come on, let's get the hell out of here. The force field is down, off to the Bishop's tower. Once he's dead, get back to the Oracle.",TXT_ILOG211,MAP15: Computer destroyed + Room 1,,,"No tak, dostaňme se sakra odsud. Silové pole je kaput, jdeme do Biskupovy věže. Až ho zabiješ, vrať se k Věštci.","Kom nu, lad os komme væk herfra. Kraftfeltet er nede, af sted til biskoppens tårn. Når han er død, så gå tilbage til Oraklet.","Komm schon, lass uns von hier verschwinden. Das Kraftfeld ist abgeschaltet, also ab zum Turm des Bischofs. Sobald er tot ist, geht es zurück zum Orakel",,"Nu, ni eliru. Vi malŝaltis la fortokampon ĉe la turo de la Episkopo. Mortiginte lin, reiru al la Orakolo.","Venga, larguémonos de aquí. Ya se ha desactivado el campo de fuerza en la torre del Obispo. En cuanto lo mates, vuelve con el Oráculo.","Vamos, salgamos de aquí. Ya se desactivó el campo de fuerza en la torre del Obispo. En cuanto lo mates, vuelve con el Oráculo.","Mennään, häivytään täältä hittoon. Voimakenttä on nurin; suunnatkaamme siis kohti Piispan tornia. Kun hän on kuollut, palaa Oraakkelin luokse.","Allez, il faut qu'on se barre d'ici. Le champ de force est hors-ligne. Entre dans la tour de l'évêque. Quand il sera mort, retourne à l'Oracle.","Na gyerünk, húzzunk innen. Az erőpajzs deaktiválva, irány a Püspök tornya. Ha meghalt menj vissza az Orákulumhoz.","Avanti, andiamo via da qui. Il campo di forza è disattivato, quindi andiamo alla torre del Vescovo. Una volta che è morto, ritorna dall'Oracolo.","頼むからこんな所さっさと出よう。 フォースフィールドは切った、ビショップの塔へ向かおう。 ビショップを殺したらオラクルの元へ戻れ。 -","이제 이곳을 당장 떠나. 방어막이 꺼졌으니! 비숍의 성으로 이동해서 비숍을 죽이고, 오라클을 만나러 가.","Kom op, laten we hier als de sodemieter weggaan. Het krachtveld is naar beneden, op weg naar de bisschopstoren. Als hij dood is, ga dan terug naar het Orakel.",,"Vamos dar o fora daqui. O campo de força está desligado. Vamos para a torre do Bispo. Assim que ele morrer, volte ao oráculo.",,,"Ну же, двигаем отсюда. Силовое поле отключено, пора двигаться к башне Епископа. Когда он умрёт, возвращайся к Оракулу.", -Find the sanctuary by the river. Steal the chalice from inside. Bring it to Harris in the tavern.,TXT_ILOG1001,,,,Najdi svatyni u řeky. Zevnitř ukradni kalich. Přines ho Harrisovi do taverny.,"Finde das Heiligtum am Fluss. Stehle den Kelch, der dort aufbewahrt wird und bringe ihn zu Harris in der Taverne.",,,Encuentra el santuario junto al río. Roba el cáliz de adentro. Tráeselo a Harris en la taberna.,Encuentra el santuario por el río. Roba el Cáliz de adentro. Tráelo con Harris a la taverna.,,Trouve le sanctuaire près de la rivière. Prends le Calice qui s'y trouve et amène le à Harris dans la taverne.,,,"川沿いの 聖域 を探し、中にある聖杯を盗む。 -酒場にいるハリスに渡す。",강 근처에 있는 성소를 찾아서 안에 보관되어있는 성배를 훔치고 선술집으로 향해.,Zoek het heiligdom bij de rivier. Steel de kelk van binnenuit. Breng het naar Harris in de herberg.,,Encontre o santuário perto do rio. Roube o cálice que está lá dentro. Leve-o para o Harris na taverna.,,,Найди святилище возле реки. Проникни туда и выкради чашу. Принеси её Харрису в таверну., -Find the Governor. Talk to him about your reward.,TXT_ILOG1002,,,,Najdi guvernéra. Promluv si s ním o své odměně.,Finde den Gouverneur. Rede mit ihm über deine Belohnung.,,,Encuentra al Gobernador. Háblale sobre tu recompensa.,Encuentra al gobernador. Habla con él acerca de tú recompensa.,,Trouve le gouverneur et demande ta récompense.,,,知事を探せ。彼と話して報酬を貰う。,총독을 만나서 보상에 대해 예기해.,Vind de Gouverneur. Spreek met hem over je beloning.,,Encontre o Governador. Fale com ele sobre a sua recompensa.,,,Найди губернатора. Обсуди с ним свою награду., -"Find the sanctuary by the river. Inside someone called Beldin is being held. Shut him up, and bring his ring back to Rowan as proof.",TXT_ILOG1003,,,,Najdi svatyni u řeky. Uvnitř je držen jakýsi Beldin. Umlč ho a přines Rowanovi jeho prsten jako důkaz.,Finde das Heiligtum am Fluss. Dort drinnen wird jemand namens Beldin festgehalten. Bringe ihn zum Schweigen und gebe Rowan seinen Ring als Beweis.,,,"Encuentra el santuario junto al río. Dentro alguien llamado Beldin está retenido. Siléncialo, y tráe de vuelta su anillo a Rowan como prueba.",Encuentra el santuario por el río. Adentro alguien llamado Beldin está retenido. Cállalo y tráele su anillo a Rowan como prueba.,,"Trouve le sanctuaire près de la rivière. Quelqu'un qui s'appelle Beldin s'y trouve emprisonné. Cloue-lui le bec, et ramène son anneau à Rowan comme preuve.",,,"川沿いの 聖域 を探せ。中にいるベルディンと +","이제 이곳을 당장 떠나. 방어막이 꺼졌으니! 비숍의 성으로 이동해서 비숍을 죽이고, 오라클을 만나러 가.","Kom op, laten we hier als de sodemieter weggaan. Het krachtveld is naar beneden, op weg naar de bisschopstoren. Als hij dood is, ga dan terug naar het Orakel.","Kom igjen, la oss komme oss vekk herfra. Kraftfeltet er nede, av gårde til biskopens tårn. Når han er død, gå tilbake til oraklet.","Chodź, wynośmy się stąd. Pole siłowe wyłączone, idziemy do wieży biskupa. Kiedy będzie martwy, wróć do Wyroczni.","Vamos dar o fora daqui. O campo de força está desligado. Vamos para a torre do Bispo. Assim que ele morrer, volte ao oráculo.",,"Hai, să ieșim de aici. Câmpul de forță e la pământ, către turnul Episcopului. Odată ce e mort, întoarce-te la Oracol.","Ну же, двигаем отсюда. Силовое поле отключено, пора двигаться к башне Епископа. Когда он умрёт, возвращайся к Оракулу.",,"Kom igen, vi sticker härifrån. Kraftfältet är nere, vi går till biskopens torn. När han är död, återvänder vi till Oraklet.","Hadi, buradan defolup gidelim. Güç alanı kapandı, Piskopos'un kulesine gidiyoruz. O öldüğünde, Kahin'e geri dönün." +Find the sanctuary by the river. Steal the chalice from inside. Bring it to Harris in the tavern.,TXT_ILOG1001,MAP33?,,,Najdi svatyni u řeky. Zevnitř ukradni kalich. Přines ho Harrisovi do taverny.,Find helligdommen ved floden. Stjæl bægeret indefra. Bring den til Harris på tavernaen.,"Finde das Heiligtum am Fluss. Stehle den Kelch, der dort aufbewahrt wird und bringe ihn zu Harris in der Taverne.",,"Trovu la sanktejon apud la rojo, ŝtelu la kalikon kaj portu ĝin al Harriso en la taverno.","Encuentra el santuario junto al arroyo, roba el cáliz de dentro y llévaselo a Harris en la taberna (Tavern).","Encuentra el santuario junto al arroyo, roba el cáliz de adentro y llévaselo a Harris a la taberna (Tavern).",Löydä pyhäkkö joen varrella. Varasta kalkki sisältä. Vie se Harrisille kapakkaan.,Trouve le sanctuaire près de la rivière. Prends le Calice qui s'y trouve et amène le à Harris dans la taverne.,A szentély a folyó mellett van. Lopd el a serleget bentről. Vidd travishez a kocsmába.,Trova il santuario accanto al fiume. Ruba il calice al suo interno. Portalo ad Harris nella taverna.,"川沿いの 聖域 を探し、中にある聖杯を盗む。 +酒場にいるハリスに渡す。",강 근처에 있는 성소를 찾아서 안에 보관되어있는 성배를 훔치고 선술집으로 향해.,Zoek het heiligdom bij de rivier. Steel de kelk van binnenuit. Breng het naar Harris in de herberg.,Finn helligdommen ved elven. Stjel begeret fra innsiden. Ta det med til Harris i vertshuset.,Znajdź sanktuarium nad rzeką. Ukradnij ze środka kielich. Zanieś go Harrisowi w tawernie.,Encontre o santuário perto do rio. Roube o cálice que está lá dentro. Leve-o para o Harris na taverna.,,Găsește sanctuarul de lângă râu. Fură potirul din interior. Du-l la Harris în tavernă.,Найди святилище возле реки. Проникни туда и выкради чашу. Принеси её Харрису в таверну.,,Hitta helgedomen vid floden. Stjäl kalken från insidan. Ta med den till Harris i tavernan.,Nehir kenarındaki tapınağı bulun. İçeriden kadehi çalın. Tavernadaki Harris'e götür. +Find the Governor. Talk to him about your reward.,TXT_ILOG1002,MAP33?,,,Najdi guvernéra. Promluv si s ním o své odměně.,Find guvernøren. Tal med ham om din belønning.,Finde den Gouverneur. Rede mit ihm über deine Belohnung.,,Trovu la registon kaj parolu al li pri via rekompenco.,Encuentra al Gobernador y háblale de tu recompensa.,,Löydä kuvernööri. Puhu hänen kanssaan palkkiostasi.,Trouve le gouverneur et demande ta récompense.,Keresd meg a Kormányzót. Beszélj vele a jutalomról.,Trova il governatore. Parlargli della tua ricompensa.,知事を探せ。彼と話して報酬を貰う。,총독을 만나서 보상에 대해 예기해.,Vind de Gouverneur. Spreek met hem over je beloning.,Finn guvernøren. Snakk med ham om belønningen din.,Znajdź gubernatora. Porozmawiaj z nim o swojej nagrodzie.,Encontre o Governador. Fale com ele sobre a sua recompensa.,,Găsește Guvernatorul. Vorbește cu el despre recompensa ta.,Найди губернатора. Обсуди с ним свою награду.,,Hitta guvernören. Prata med honom om din belöning.,Vali'yi bul. Onunla ödülün hakkında konuş. +"Find the sanctuary by the river. Inside someone called Beldin is being held. Shut him up, and bring his ring back to Rowan as proof.",TXT_ILOG1003,MAP02: After accepting Rowan's chore.,,,Najdi svatyni u řeky. Uvnitř je držen jakýsi Beldin. Umlč ho a přines Rowanovi jeho prsten jako důkaz.,"Find helligdommen ved floden. Indenfor bliver en person ved navn Beldin holdt fanget. Få ham til at lukke munden på ham, og giv Rowan hans ring tilbage som bevis.",Finde das Heiligtum am Fluss. Dort drinnen wird jemand namens Beldin festgehalten. Bringe ihn zum Schweigen und gebe Rowan seinen Ring als Beweis.,,Trovu la sanktejon apud la rojo. Iu nomata Beldin estas retenita en ĝi. Silentigu lin kaj donu lian ringon kiel pruvon al Rowan.,Encuentra el santuario junto al arroyo. Alguien llamado Beldin está retenido dentro. Siléncialo y dale su anillo a Rowan como prueba.,Encuentra el santuario junto al arroyo. Alguien llamado Beldin está retenido adentro. Siléncialo y dale su anillo a Rowan como prueba.,"Löydä pyhäkkö joen varrella. Sisällä on vangittuna joku nimeltään Beldin. Vaienna hänet, ja tuo hänen sormuksensa takaisin Rowanille todisteena.","Trouve le sanctuaire près de la rivière. Quelqu'un qui s'appelle Beldin s'y trouve emprisonné. Cloue-lui le bec, et ramène son anneau à Rowan comme preuve.","Megtalálod a szentélyt a folyó mellett. Egy Beldin nevű figurát tartanak fogva. Halgattasd el örökre, és hozd vissza a gyűrűjét Rowannak bizonyítékként.","Trova il santuario accanto al fiume. Dentro, qualcuno chiamato Beldin è sotto chiave. Fallo tacere per sempre, e riporta il suo anello a Rowan come prova.","川沿いの 聖域 を探せ。中にいるベルディンと 呼ばれている捕獲された者を見つけ彼を黙らせる。 -指輪をロワンに渡す。","강 근처에 있는 성소를 찾아서 벨딘이라는 사람을 찾고, 입을 다물게 해. 그 후에 그의 반지를 얻어서 로완에게 그를 죽였다고 증명해.","Zoek het heiligdom bij de rivier. Binnenin wordt iemand met de naam Beldin vastgehouden. Laat hem zwijgen, en breng zijn ring terug naar Rowan als bewijs.",,Encontre o santuário perto do rio. Dentro há alguém chamado Beldin sendo detido. Cale a boca dele e traga o seu anel de volta ao Rowan como prova.,,,"Найди святилище возле реки. Внутри содержится пленник по имени Белдин. Заставь его замолчать, и принеси его кольцо Роуэну в качестве доказательства.", -Find the location of the Front and talk to Macil.,TXT_ILOG1004,,,,Najdi umístění Fronty a promluv si s Macilem.,Finde die Basis der Front und rede mit Macil.,,,Encuentra la localización del Frente y habla con Macil.,Encuentra la localización del Frente y habla con Macil.,,Trouve où se cache le Front et parle à Macil.,,,フロントの場所を見つけ、マシルと会話する。,프론트의 기지를 찾아서 마실과 대화해봐.,Zoek de locatie van het Front en praat met Macil.,,Ache a localização da Frente e fale com o Macil.,,,Найди базу Сопротивления и поговори с Мэйсилом., -"Go down the stairs, find and talk to Macil.",TXT_ILOG1005,,,,Jdi dolů po schodech a najdi a promluv si s Macilem.,Geh die Treppe runter und rede mit Macil.,,,"Baja por las escaleras, encuentra y habla con Macil.","Baja las escaleras, encuentra y habla con Macil.",,"Descends les escaliers, trouve et parle à Macil.",,,階段を降り、マシルと会話する。,계단 밑으로 내려가서 마실과 대화해봐.,"Ga de trap af, zoek en praat met Macil.",,"Desça as escadas, encontre e fale com o Macil.",,,"Спустись на этаж ниже, найди Мэйсила и поговори с ним.", -"Visit Irale, the Front's weapons supplier in town. He's behind the door next to the weapons shop. Then, use the key Macil gave you to talk to the Governor.",TXT_ILOG1006,,,,"Navštiv Iraleho, dodavatele zbraní pro Frontu ve městě. Je za dveřmi vedle obchodu se zbraněmi. Pak použij klíč od Macila, aby sis promluvil s guvernérem.","Suche Irale auf, den Waffenbeschaffer der Front in der Stadr. Er hält sich in dem Gebäude neben dem Waffengeschäft auf. Danach benutze den Schlüssel, den Macil dir gegeben hat, um mit dem Gouverneur zu reden",,,"Visita a Irale, el proveedor de armamento del Frente. Está detrás de la puerta junto a la tienda de armas. Luego, usa la llave que te dió Macil para hablar con el Gobernador.","Visita a Irale, el proveedor de armamento del Frente. Está detrás de la puerta junto a la tienda de armas. Luego, usa la llave que te dió Macil para hablar con el Gobernador.",,"Va voir Irale, le chef de l'arsenal du Front, en ville. Il se trouve derrière la porte à côté du marchand d'armes. Utilise la clé que Macil t'a donné pour parler au gouverneur.",,,"町にいるフロントへの武器供給者であるイラールの元を訪ねる。 -彼は武器屋の隣のドアに居る。それで、知事と会う為にマシルから貰ったキーを使う。","프론트의 무기상인 이롤리를 마을에서 찾아. 무기 상점 근처에 문이 있을 거야. 마실이 준 열쇠로 문을 열고 방문한 뒤, 총독과 대화해.","Bezoek Irale, de wapenleverancier van het Front in de stad. Hij zit achter de deur naast de wapenwinkel. Gebruik dan de sleutel die Macil je gaf om met de Gouverneur te praten.",,"Visite o Irale, o fornecedor de armas da Frente. Ele está atrás da porta perto da loja de armas. Depois, use a chave que o Macil te deu para falar com o Governador.",,,"Посети Ирэйла, поставщика оружия Сопротивления в городе. Он за следующей после оружейного магазина дверью. Затем, воспользуйся ключом, который тебе дал Мэйсил, чтобы поговорить с губернатором.", -"Find the power tap on the mains, and shut it off. Bring something back to the Governor as proof.",TXT_ILOG1007,,,,Najdi stáčedlo energie na síti a vypni jej. Přines guvernérovi něco zpět jako důkaz.,Finde die Energieanzapfung und schalte sie aus. Bringe dem Gouverneur irgend etwas als Beweis.,,,Encuentra la intervención de la red principal y desactívala. Trae algo de vuelta al Gobernador como prueba.,Encuentra la intervención de la red principal y desactívala. Regresa con una prueba con el Gobernador.,,Trouve la connection pirate sur le transformateur et enlève la. Amène quelque chose au gouverneur comme preuve.,,,"電力盗用の場所を見つけ、それを止める。 -知事に渡す証拠も必要だ。",주 동력선 어딘가에 있는 추출기를 처리해. 그 잔해를 총독에게 들고 가서 증명해.,"Zoek het kraantje op het lichtnet, en zet het uit. Breng iets terug naar de Gouverneur als bewijs.",,Encontre a ligação clandestina no transformador e desligue-a. Traga algo de volta para o Governador como prova.,,,Найди нелегальное подключение к энергосети и выведи его из строя. Принеси что-нибудь губернатору в качестве доказательства., -"Find Derwin in the warehouse of the power station. Kill him, and bring Mourel his ear.",TXT_ILOG1008,,,,Najdi Derwina ve skladu elektrárny. Zabij ho a přines Mourelovi jeho ucho.,Finde Derwin im Lagerhaus des Kraftwerks. Töte ihn und bringe Mourel sein Ohr.,,,"Encuentra a Derwin en el almacén de la estación eléctrica. Mátalo, y tráele su oreja a Mourel.",Encuentra a Derwin en el almacén de la Estación Eléctrica. Mátalo y táele a Mourel su oreja.,,"Trouve Derwin dans l'entrepôt de la centrale électrique. Tue-le, et amène son oreille à Mourel.",,,"発電所の倉庫にいるダーウィンを見つける。 -始末したら、そいつの耳をモーレルに渡す。",발전소 창고 주변에 있는 더윈을 찾아. 그를 죽인 뒤 귀를 뜯어서 모렐 총독에게 건네줘.,"Vind Derwin in het magazijn van de centrale. Dood hem, en breng Mourel zijn oor.",,Encontre o Derwin no depósito da usina elétrica. Mate-o e leve a sua orelha para o Mourel.,,,Найди Дервина на складе электростанции. Убей его и принеси Морелу его ухо., -"Use the pass Mourel gave you to get into the prison. Once inside, talk to Warden Montag. Find a way to free the prisoners.",TXT_ILOG1009,,,,"Použij propustku od Mourela pro vstup do vězení. Uvnitř si promluv s dozorčím Montagem. Najdi způsob, jak vysvobodit vězně.","Benutze den Pass, den Mourel dir gegeben hat um in das Gefängnis hereinzukommen. Wenn du drin bist, rede mit Direktor Montag. Finde einen Weg um die Gefangenen zu befreien.",,,"Usa el pase que Mourel te dió para entrar en la prisión. Una vez dentro, habla con el Carcelero Montag. Encuentra una forma de liberar a los prisioneros.","Usa el pase que Mourel te dió para entrar en la prisión. Una vez dentro, habla con el Director Montag. Encuentra una manera de liberar a los prisioneros.",,"Utilise le passe que Mourel t'a donné pour entrer dans la prison. Une fois à l'intérieur, parle au gardien Montag. Trouve un moyen de libérer les prisonniers.",,,"モーレルからもらった刑務所の許可証を使って入る。 +指輪をロワンに渡す。","강 근처에 있는 성소를 찾아서 벨딘이라는 사람을 찾고, 입을 다물게 해. 그 후에 그의 반지를 얻어서 로완에게 그를 죽였다고 증명해.","Zoek het heiligdom bij de rivier. Binnenin wordt iemand met de naam Beldin vastgehouden. Laat hem zwijgen, en breng zijn ring terug naar Rowan als bewijs.","Finn helligdommen ved elven. Der inne holdes en som heter Beldin fanget. Få ham til å holde kjeft, og ta med ringen hans tilbake til Rowan som bevis.",Znajdź sanktuarium nad rzeką. W środku przetrzymywany jest ktoś o imieniu Beldin. Ucisz go i przynieś jego pierścień Rowanowi jako dowód.,Encontre o santuário perto do rio. Dentro há alguém chamado Beldin sendo detido. Cale a boca dele e traga o seu anel de volta ao Rowan como prova.,,Găsește sanctuarul de lângă râu. Înăuntru cineva numit Beldin e reținut. Redu-l la tăcere și întoarce-te cu inelul la Rowan drept dovadă.,"Найди святилище возле реки. Внутри содержится пленник по имени Белдин. Заставь его замолчать, и принеси его кольцо Роуэну в качестве доказательства.",,Hitta helgedomen vid floden. Där inne hålls någon som heter Beldin fången. Få tyst på honom och ta med dig hans ring tillbaka till Rowan som bevis.,Nehir kenarındaki sığınağı bul. İçeride Beldin adında biri tutuluyor. Onu susturun ve yüzüğünü kanıt olarak Rowan'a geri getirin. +Find the location of the Front and talk to Macil.,TXT_ILOG1004,MAP02: After getting the com unit from Rowan.,,,Najdi umístění Fronty a promluv si s Macilem.,Find placeringen af fronten og tal med Macil.,Finde die Basis der Front und rede mit Macil.,,,Encuentra la localización del Frente y habla con Macil.,,Löydä Rintaman olinpaikka ja keskustele Macilin kanssa.,Trouve où se cache le Front et parle à Macil.,"Keresd meg a Front központját, és beszélj Macillal.",Trova il quartier generale del Fronte e parla a Macil.,フロントの場所を見つけ、マシルと会話する。,프론트의 기지를 찾아서 마실과 대화해봐.,Zoek de locatie van het Front en praat met Macil.,Finn plasseringen til Fronten og snakk med Macil.,Znajdź lokalizację Frontu i porozmawiaj z Macil.,Ache a localização da Frente e fale com o Macil.,,Găsește locația Frontului și vorbește cu Macil.,Найди базу Сопротивления и поговори с Мэйсилом.,,Hitta platsen för fronten och prata med Macil.,Cephe'nin yerini bulun ve Macil ile konuşun. +"Go down the stairs, find and talk to Macil.",TXT_ILOG1005,MAP02?,,,Jdi dolů po schodech a najdi a promluv si s Macilem.,"Gå ned ad trappen, find og tal med Macil.",Geh die Treppe runter und rede mit Macil.,,,Baja por las escaleras. Encuentra y habla con Macil.,,"Kulje portaat alas, löydä Macil ja keskustele hänen kanssaan.","Descends les escaliers, trouve et parle à Macil.","Menj le a lépcsőn, és keresd meg Macilt.","Scendi le scale, e trova e parla con Macil.",階段を降り、マシルと会話する。,계단 밑으로 내려가서 마실과 대화해봐.,"Ga de trap af, zoek en praat met Macil.","Gå ned trappene, finn og snakk med Macil.","Zejdź na dół po schodach, znajdź i porozmawiaj z Macil.","Desça as escadas, encontre e fale com o Macil.",,"Du-te în josul scărilor, găsește-l și vorbește cu Macil.","Спустись на этаж ниже, найди Мэйсила и поговори с ним.",,"Gå ner för trapporna, hitta och prata med Macil.","Merdivenlerden aşağı inin, Macil'i bulun ve onunla konuşun." +"Visit Irale, the Front's weapons supplier in town. He's behind the door next to the weapons shop. Then, use the key Macil gave you to talk to the Governor.",TXT_ILOG1006,MAP03: After joining the Front.,,,"Navštiv Iraleho, dodavatele zbraní pro Frontu ve městě. Je za dveřmi vedle obchodu se zbraněmi. Pak použij klíč od Macila, aby sis promluvil s guvernérem.","Besøg Irale, Frontens våbenleverandør i byen. Han befinder sig bag døren ved siden af våbenbutikken. Brug derefter den nøgle, som Macil gav dig, til at tale med guvernøren.","Suche Irale auf, den Waffenbeschaffer der Front in der Stadr. Er hält sich in dem Gebäude neben dem Waffengeschäft auf. Danach benutze den Schlüssel, den Macil dir gegeben hat, um mit dem Gouverneur zu reden",,,"Visita a Irale, el proveedor de armamento del Frente; está pasando la puerta junto a la tienda de armas (Weapons). Luego usa la llave que te dio Macil para hablar con el Gobernador.",,"Tapaa Iralea, joka on Rintaman asetoimittaja kaupungissa. Hän on asekaupan viereisen oven takana. Käytä sen jälkeen Macilin antamaa avainta puhuaksesi kuvernöörin kanssa.","Va voir Irale, le chef de l'arsenal du Front, en ville. Il se trouve derrière la porte à côté du marchand d'armes. Utilise la clé que Macil t'a donné pour parler au gouverneur.","Keresd fel Iralet, a Front fegyver beszállítóját a városban. A fegyverbolt melletti ajtó mögött vár rád. Utána használd a maciltól kapott kulcsot, hogy tudj beszélni a Kormányzóval.","Visita Irale, il fornitore di armi del Fronte in città. Si trova dietro la porta accanto al negozio di armi. Dopodiché, usa la chiave che Macil ti ha dato per andare a parlare al governatore.","町にいるフロントへの武器供給者であるイラールの元を訪ねる。 +彼は武器屋の隣のドアに居る。それで、知事と会う為にマシルから貰ったキーを使う。","프론트의 무기상인 이롤리를 마을에서 찾아. 무기 상점 근처에 문이 있을 거야. 마실이 준 열쇠로 문을 열고 방문한 뒤, 총독과 대화해.","Bezoek Irale, de wapenleverancier van het Front in de stad. Hij zit achter de deur naast de wapenwinkel. Gebruik dan de sleutel die Macil je gaf om met de Gouverneur te praten.","Besøk Irale, Frontens våpenleverandør i byen. Han er bak døren ved siden av våpenbutikken. Bruk nøkkelen Macil ga deg til å snakke med guvernøren.","Odwiedź w mieście Irale, dostawcę broni dla Frontu. Jest on za drzwiami obok sklepu z bronią. Następnie użyj klucza, który dał ci Macil, by porozmawiać z gubernatorem.","Visite o Irale, o fornecedor de armas da Frente. Ele está atrás da porta perto da loja de armas. Depois, use a chave que o Macil te deu para falar com o Governador.",,"Vizitează pe Irale, distribuitorul de arme alFrontului în oraș. E dincolo de ușa de lângă magazinul de arme. Apoi, folosește cheia pe care Macil ți-a dat-o și vorbește cu Guvernatorul.","Посети Ирэйла, поставщика оружия Сопротивления в городе. Он за следующей после оружейного магазина дверью. Затем, воспользуйся ключом, который тебе дал Мэйсил, чтобы поговорить с губернатором.",,"Besök Irale, frontens vapenleverantör i staden. Han befinner sig bakom dörren bredvid vapenbutiken. Använd sedan nyckeln som Macil gav dig för att prata med guvernören.","Kasabada Cephe'nin silah tedarikçisi İrale'yi ziyaret edin. Silah dükkanının yanındaki kapının arkasında. Sonra, Vali ile konuşmak için Macil'in size verdiği anahtarı kullanın." +"Find the power tap on the mains, and shut it off. Bring something back to the Governor as proof.",TXT_ILOG1007,"MAP02: After accepting ""messy"" chore.",,,Najdi stáčedlo energie na síti a vypni jej. Přines guvernérovi něco zpět jako důkaz.,"Find elhanen på hovedledningen, og luk den. Tag noget med tilbage til guvernøren som bevis.",Finde die Energieanzapfung und schalte sie aus. Bringe dem Gouverneur irgend etwas als Beweis.,,,Encuentra la toma en la red eléctrica y destrúyela. Tráele algo al Gobernador como prueba.,,Etsi verkkovirran piilokytkentä ja katkaise se. Tuo kuvernöörille jotain todisteeksi.,Trouve la connection pirate sur le transformateur et enlève la. Amène quelque chose au gouverneur comme preuve.,"Keresd meg a fővonalon az áramkapcsolót, és kapcsold ki. Hozz vissza valamit a kormányzótól bizonyítékként.","Trova il marchingegno che sta venendo usato per rubare energia alla rete, e distruggilo. Porta dei resti al governatore come prova.","電力盗用の場所を見つけ、それを止める。 +知事に渡す証拠も必要だ。",주 동력선 어딘가에 있는 추출기를 처리해. 그 잔해를 총독에게 들고 가서 증명해.,"Zoek het kraantje op het lichtnet, en zet het uit. Breng iets terug naar de Gouverneur als bewijs.","Finn strømbryteren på strømnettet, og slå den av. Ta med noe tilbake til guvernøren som bevis.",Znajdź kurek z prądem w sieci i wyłącz go. Przynieś coś gubernatorowi jako dowód.,Encontre a ligação clandestina no transformador e desligue-a. Traga algo de volta para o Governador como prova.,,Găsește cuplul de putere și oprește-l. Adu ceva drept dovadă Guvernatorului.,Найди нелегальное подключение к энергосети и выведи его из строя. Принеси что-нибудь губернатору в качестве доказательства.,,Leta reda på strömkranen på elnätet och stäng av den. Ta med dig något tillbaka till guvernören som bevis.,Şebekedeki güç musluğunu bulun ve kapatın. Kanıt olarak Vali'ye bir şey getirin. +"Find Derwin in the warehouse of the power station. Kill him, and bring Mourel his ear.",TXT_ILOG1008,"MAP02: After accepting ""bloody"" chore.",,,Najdi Derwina ve skladu elektrárny. Zabij ho a přines Mourelovi jeho ucho.,"Find Derwin i lageret på kraftværket. Dræb ham, og giv Mourel hans øre.",Finde Derwin im Lagerhaus des Kraftwerks. Töte ihn und bringe Mourel sein Ohr.,,,Encuentra a Derwin en el almacén (Warehouse) de la central eléctrica (Power Station). Mátalo y llévale su oreja a Mourel.,,"Etsi Derwin voimalaitoksen varastolta. Tapa hänet, ja tuo Mourelille hänen korvansa.","Trouve Derwin dans l'entrepôt de la centrale électrique. Tue-le, et amène son oreille à Mourel.","Keresd meg Derwint az erőmű raktárjában. öld meg, és vidd vissza Mourelnek a fülét.","Trova Derwin nel magazzino della centrale energetica. Uccidilo, e porta il suo orecchio a Mourel.","発電所の倉庫にいるダーウィンを見つける。 +始末したら、そいつの耳をモーレルに渡す。",발전소 창고 주변에 있는 더윈을 찾아. 그를 죽인 뒤 귀를 뜯어서 모렐 총독에게 건네줘.,"Vind Derwin in het magazijn van de centrale. Dood hem, en breng Mourel zijn oor.","Finn Derwin i lageret på kraftstasjonen. Drep ham, og gi Mourel øret hans.",Znajdź Derwina w magazynie elektrowni. Zabij go i przynieś Mourelowi jego ucho.,Encontre o Derwin no depósito da usina elétrica. Mate-o e leve a sua orelha para o Mourel.,,Găsește-l pe Derwin în depozit. Omoară-l și adu-i urechea lui Mourel.,Найди Дервина на складе электростанции. Убей его и принеси Морелу его ухо.,,Hitta Derwin i lagret i kraftverket. Döda honom och ge Mourel hans öra.,Elektrik santralinin deposunda Derwin'i bulun. Onu öldürün ve Mourel'e kulağını getirin. +"Use the pass Mourel gave you to get into the prison. Once inside, talk to Warden Montag. Find a way to free the prisoners.",TXT_ILOG1009,MAP03: After completing Mourel's chore.,,,"Použij propustku od Mourela pro vstup do vězení. Uvnitř si promluv s dozorčím Montagem. Najdi způsob, jak vysvobodit vězně.","Brug det adgangskort, som Mourel gav dig, til at komme ind i fængslet. Når du er inde, skal du tale med direktør Montag. Find en måde at befri fangerne på.","Benutze den Pass, den Mourel dir gegeben hat um in das Gefängnis hereinzukommen. Wenn du drin bist, rede mit Direktor Montag. Finde einen Weg um die Gefangenen zu befreien.",,,"Usa el pase que Mourel te dió para entrar en la prisión. Una vez dentro, habla con el Carcelero Montag. Encuentra una forma de liberar a los prisioneros.",,Käytä Mourelin antamaa pääsylupaa päästäksesi vankilaan. Päästyäsi sisälle puhu vankilanjohtaja Montagin kanssa. Keksi keino vapauttaa vangit.,"Utilise le passe que Mourel t'a donné pour entrer dans la prison. Une fois à l'intérieur, parle au gardien Montag. Trouve un moyen de libérer les prisonniers.","Használd a Mourel által adott belépőt, hogy bejuss a börtönbe. Ha bent vagy, beszélj Montag börtön igazgatóval. Találd meg a módját, hogy kiszabadítsd a rabokat.","Usa il tesserino che Mourel ti ha dato per entrare nella prigione. Una volta dentro, parla con il direttore Montag. Trova un modo per liberare i prigionieri.","モーレルからもらった刑務所の許可証を使って入る。 入ったらモンターグと話し、囚人を解放する方法を探す。 -",총독이 준 감옥 통행증을 이용해서 감옥으로 들어가. 들어간 후에 수감자들을 해방하기 위해 몬탕 간수장과 대화해. ,"Gebruik de pas die Mourel je gaf om in de gevangenis te komen. Eenmaal binnen, praat je met Warden Montag. Zoek een manier om de gevangenen te bevrijden.",,"Use o passe que o Mourel te deu para entrar na prisão. Após entrar, fale com o Carcereiro Montag. Encontre uma maneira de libertar os prisioneiros.",,,"Используй пропуск, полученный у Морела, чтобы пройти в тюрьму. Когда ты будешь внутри, поговори с тюремщиком Монтагом. Найди способ освободить пленников.", -Use the Warden's key to get into the prison cell blocks and find a way to free the prisoners.,TXT_ILOG1010,,,,"Použij dozorčího klíč k dostání se do vězeňského bloku s celami a najdi způsob, jak vysvobodit vězně.","Benutze den Schlüssel des Direktors um in die Zellenblöcke zu kommen und finde heraus, wie man die Gefangenen befreien kann.",,,Usa la llave del Carcelero para entrar en los bloques de celdas y encuentra una forma de liberar a los prisioneros.,Usa la llave del Director para entrar en los bloques de celdas y encuentra una manera de liberar a los prisioneros.,,Utilisé la clé du Gardien pour entrer dans les blocs de cellules et trouve un moyen de libérer les prisonners.,,,ワーデンから鍵を奪って内部に入れ。,"간수장의 열쇠를 써서 감옥 안으로 진입하고, 수감자들을 풀어줄 방법을 찾아봐.",Gebruik de sleutel van de bewaker om in de celblokken van de gevangenis te komen en een manier te vinden om de gevangenen te bevrijden.,,Use a chave do Carcereiro para entrar nos blocos de celas e ache uma maneira de libertar os prisioneiros.,,,"Используй ключ тюремщика, чтобы пройти к камерам, и найди способ освободить пленников.", -"Destroy the power crystal that runs the power grid which drives the Order's shields. Go visit Worner, a spy we recruited in the warehouse of the power station. Don't forget to visit the medic and the weapons trainer before you go",TXT_ILOG1011,,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Jdi navštívit Wornera, špióna, kterého jsme najali ve skladu elektrárny. Nezapomeň navštívit zdravotníka a učitele střelby, než půjdeš.","Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Suche Worner auf, einen Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben. Vergiß nicht, den Sanitäter und den Waffentrainer aufzusuchen, bevor du gehst.",,,"Destruye el cristal de poder que impulsa la red eléctrica que alimenta los escudos de la Orden. Ve a visitar a Worner, un espía que reclutamos en el almacén de la estación eléctrica. No te olvides de visitar al médico y el entrenador de armas antes de irte","Destruye el cristal de poder que impulsa la red eléctrica que abastece los escudos de la Orden. Visita a Worner, un espía que reclutamos en el almacén de la Estación Eléctrica. No olvides visitar al médico y el entrenador de armas antes de irte.",,"Détruis le cristal qui alimente la grille énergétique des boucliers de l'Ordre. Va voir Worner, un espion que nous avons recruté dans l'entrepôt de la centrale éléctrique. N'oublie pas d'aller voir le maître d'armes et le médecin avant d'y aller.",,,"送電網を動かしているパワークリスタルを破壊してオーダーのシールドを止める。 +",총독이 준 감옥 통행증을 이용해서 감옥으로 들어가. 들어간 후에 수감자들을 해방하기 위해 몬탕 간수장과 대화해. ,"Gebruik de pas die Mourel je gaf om in de gevangenis te komen. Eenmaal binnen, praat je met Warden Montag. Zoek een manier om de gevangenen te bevrijden.","Bruk passet Mourel ga deg for å komme inn i fengselet. Når du er inne, snakk med fengselsdirektør Montag. Finn en måte å befri fangene på.","Użyj przepustki, którą dał ci Mourel, aby dostać się do więzienia. Po wejściu do środka porozmawiaj z naczelnikiem Montagiem. Znajdź sposób na uwolnienie więźniów.","Use o passe que o Mourel te deu para entrar na prisão. Após entrar, fale com o Carcereiro Montag. Encontre uma maneira de libertar os prisioneiros.",,"Folosește parola pe care ți-a dat-o Mourel pentru a intra în închisoare. Odată înăuntru, vorbește cu Directorul Montag. Găsește o cale să eliberezi prizonierii.","Используй пропуск, полученный у Морела, чтобы пройти в тюрьму. Когда ты будешь внутри, поговори с тюремщиком Монтагом. Найди способ освободить пленников.",,Använd passet som Mourel gav dig för att komma in i fängelset. När du väl är inne pratar du med fängelsedirektör Montag. Hitta ett sätt att befria fångarna.,Hapishaneye girmek için Mourel'in size verdiği kartı kullanın. İçeri girdikten sonra Müdür Montag ile konuşun. Mahkûmları serbest bırakmanın bir yolunu bulun. +Use the Warden's key to get into the prison cell blocks and find a way to free the prisoners.,TXT_ILOG1010,MAP05,,,"Použij dozorčího klíč k dostání se do vězeňského bloku s celami a najdi způsob, jak vysvobodit vězně.",Brug fængselsdirektørens nøgle til at komme ind i fængselscelleblokkene og find en måde at befri fangerne på.,"Benutze den Schlüssel des Direktors um in die Zellenblöcke zu kommen und finde heraus, wie man die Gefangenen befreien kann.",,,Usa la llave del Carcelero para entrar en los bloques de celdas y encuentra una forma de liberar a los prisioneros.,Usa la llave del Carcelero para entrar a los bloques de celdas y encuentra una forma de liberar a los prisioneros.,Käytä vankilanjohtajan avainta päästäksesi vankilan selliosastoille ja keksi keino vapauttaa vangit.,Utilisé la clé du Gardien pour entrer dans les blocs de cellules et trouve un moyen de libérer les prisonners.,"Használd a börtön igazgató kulcsát, hogy bejuss a cella blokkba, és szabadítsd ki a foglyokat.",Usa la chiave del direttore per entrare nella sezione delle celle e trovare un modo per liberare i prigionieri.,ワーデンから鍵を奪って内部に入れ。,"간수장의 열쇠를 써서 감옥 안으로 진입하고, 수감자들을 풀어줄 방법을 찾아봐.",Gebruik de sleutel van de bewaker om in de celblokken van de gevangenis te komen en een manier te vinden om de gevangenen te bevrijden.,Bruk fengselsdirektørens nøkkel for å komme deg inn i fengselsblokkene og finn en måte å befri fangene på.,"Użyj klucza naczelnika, aby dostać się do bloków więziennych i znajdź sposób na uwolnienie więźniów.",Use a chave do Carcereiro para entrar nos blocos de celas e ache uma maneira de libertar os prisioneiros.,,Folosește cheia pe care ți-a dat-o Guvernatorul și găsește o cale să eliberezi prizonierii.,"Используй ключ тюремщика, чтобы пройти к камерам, и найди способ освободить пленников.",,Använd fängelsedirektörens nyckel för att ta dig in i fängelsets cellblock och hitta ett sätt att befria fångarna.,Hapishane hücre bloklarına girmek için Müdürün anahtarını kullanın ve mahkûmları serbest bırakmanın bir yolunu bulun. +"Destroy the power crystal that runs the power grid which drives the Order's shields. Go visit Worner, a spy we recruited in the warehouse of the power station. Don't forget to visit the medic and the weapons trainer before you go.",TXT_ILOG1011,MAP03: After accepting Macil's second mission.,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Jdi navštívit Wornera, špióna, kterého jsme najali ve skladu elektrárny. Nezapomeň navštívit zdravotníka a učitele střelby, než půjdeš.","Ødelæg energikrystallen, der driver det strømnet, som driver Ordenens skjolde. Besøg Worner, en spion, som vi rekrutterede i lageret på kraftværket. Glem ikke at besøge lægen og våbentræneren, før du går.","Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Suche Worner auf, einen Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben. Vergiß nicht, den Sanitäter und den Waffentrainer aufzusuchen, bevor du gehst.",,,"Destruye el cristal de poder que impulsa la red eléctrica que alimenta los escudos de La Orden. Busca a Worner, un espía que reclutamos en el almacén de la central eléctrica. Recuerda visitar al médico y al entrenador de armas.",,"Tuhoa kaupungin sähköverkon voimanlähteenä toimiva voimakristalli, jonka voimaa Veljeskunnan kilvet käyttävät. Mene tapaamaan Worneria, vakoojaa, jonka värväsimme voimalaitoksen varastolta. Älä unohda vierailla lääkintämiehen ja asekouluttajan luona, ennen kuin lähdet.","Détruis le cristal qui alimente la grille énergétique des boucliers de l'Ordre. Va voir Worner, un espion que nous avons recruté dans l'entrepôt de la centrale éléctrique. N'oublie pas d'aller voir le maître d'armes et le médecin avant d'y aller.","Semmisítsd meg az erő kristályt, ami a Rend külső védőpajzsát hajtja az elektromos hálózaton keresztül. Keresd fel az erőműtől betoborzott kémünket, Wornert. Ne felejtsd el meglátogatni a szanitécet és a fegyvermestert mielőtt nekiindulsz.","Distruggi il cristallo che fornisce energia agli scudi dell'Ordine. Trova Worner, una spia che abbiamo reclutato nel magazzino della centrale energetica. Non scordarti di passare dal medico e dall'addestratore di armi prima di andare.","送電網を動かしているパワークリスタルを破壊してオーダーのシールドを止める。 発電所の倉庫に潜らせたスパイ、ワーナーを訪ねる。 -その前にメディックと武器トレーナーに会うのを忘れるな。","오더의 방어막을 유지하는 동력 망의 전력원인 수정체를 파괴하자. 우선, 발전소 창고에 있는 우리 쪽 첩자인 워너에게 찾아가 보자. 가기 전에 의무관이랑 무기 담당관을 만나는 것도 잊지 말고!","Vernietig het energiekristal dat het stroomnet dat de schilden van de Orde aandrijft. Ga naar Worner, een spion die we in het magazijn van de centrale hebben gerekruteerd. Vergeet niet om de dokter en de wapentrainer te bezoeken voor je vertrekt.",,"Destrua o cristal de energia que alimenta a rede elétrica por trás dos escudos da Ordem. Visite o Worner, um espião que recrutamos no depósito da usina de energia. Não se esqueça de visitar o médico e o treinador de armas antes de ir.",,,"Уничтожь кристалл, питающий энергосеть, от которой работают щиты Ордена. Поговори с Уорнэром, шпионом Сопротивления, на складе электростанции. Не забудь перед уходом посетить медика и инструктора по стрельбе.", -Destroy the power crystal that runs the power grid which drives the Order's shields. Use the I.D. to get into the power station. You may want to check out the storeroom above Worner.,TXT_ILOG1012,,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Použij získanou legitimaci pro přístup do elektrárny. Možná by stálo za to podívat se do skladištní místnosti nad Wornerem.",Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Benutze die Identitätskarte. um in das Kraftwerk zu gelangen. Du solltest den Abstellraum beim Lagerhaus mal inspizieren.,,,Destruye el cristal de poder que impulsa la rede eléctrica que alimenta los escudos de la Orden. Usa la identificación para entrar a la estación eléctrica. Quizas quieras comprobar el cuarto de almacenamiento encima de Worner.,Destruye el cristal de poder que impulsa la red eléctrica que abastece los escudos de la Orden. Usa la Identificación para entrar a la Estación Eléctrica. Quizás quieras revisar el cuarto de almacenaje arriba de Worner.,,Détruis le cristal qui alimente la grille énergétique des boucliers de l'Ordre. Utilise la carte d'identité pour entrer dans la centrale. Il faudrait que tu aille voir la salle de stockage au dessus de Worner.,,,"送電網を動かしているパワークリスタルを破壊してオーダーのシールドを止める。 +その前にメディックと武器トレーナーに会うのを忘れるな。","오더의 방어막을 유지하는 동력 망의 전력원인 수정체를 파괴하자. 우선, 발전소 창고에 있는 우리 쪽 첩자인 워너에게 찾아가 보자. 가기 전에 의무관이랑 무기 담당관을 만나는 것도 잊지 말고!","Vernietig het energiekristal dat het stroomnet dat de schilden van de Orde aandrijft. Ga naar Worner, een spion die we in het magazijn van de centrale hebben gerekruteerd. Vergeet niet om de dokter en de wapentrainer te bezoeken voor je vertrekt.","Ødelegg kraftkrystallen som driver kraftnettet som driver ordenens skjold. Besøk Worner, en spion vi rekrutterte i lageret til kraftstasjonen. Ikke glem å besøke medisineren og våpentreneren før du går.","Zniszcz kryształ mocy, który zasila sieć energetyczną napędzającą tarcze Zakonu. Idź odwiedzić Wornera, szpiega, którego zwerbowaliśmy w magazynie elektrowni. Nie zapomnij przed wyjściem odwiedzić medyka i trenera broni.","Destrua o cristal de energia que alimenta a rede elétrica por trás dos escudos da Ordem. Visite o Worner, um espião que recrutamos no depósito da usina de energia. Não se esqueça de visitar o médico e o treinador de armas antes de ir.",,"Distruge cristalul de nergie care alimentează câmpurile Ordinului. Vizitează pe Worner, un spion recrutat în depozitul stației. Nu uita să vorbești cu medicul și antrenorul de arme înainte.","Уничтожь кристалл, питающий энергосеть, от которой работают щиты Ордена. Поговори с Уорнэром, шпионом Сопротивления, на складе электростанции. Не забудь перед уходом посетить медика и инструктора по стрельбе.",,"Förstör kraftkristallen som driver kraftnätet som driver ordens sköldar. Gå och besök Worner, en spion som vi rekryterade i kraftverkets lager. Glöm inte att besöka läkaren och vapentränaren innan du går.",Tarikat'ın kalkanlarını çalıştıran güç şebekesini çalıştıran güç kristalini yok edin. Güç istasyonunun deposunda işe aldığımız casus Worner'ı ziyaret edin. Gitmeden önce sıhhiyeciyi ve silah eğitmenini ziyaret etmeyi unutmayın. +Destroy the power crystal that runs the power grid which drives the Order's shields. Use the I.D. to get into the power station. You may want to check out the storeroom above Worner.,TXT_ILOG1012,MAP04: After talking to Worner.,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Použij získanou legitimaci pro přístup do elektrárny. Možná by stálo za to podívat se do skladištní místnosti nad Wornerem.","Ødelæg energikrystallen, der driver det kraftnet, som driver Ordenens skjolde. Brug identifikationskortet til at komme ind i kraftværket. Du kan tjekke lagerrummet over Worner.",Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Benutze die Identitätskarte. um in das Kraftwerk zu gelangen. Du solltest den Abstellraum beim Lagerhaus mal inspizieren.,,,Destruye el cristal de poder que impulsa la red eléctrica que alimenta los escudos de La Orden. Usa la identificación para entrar a la central eléctrica. Quizás quieras revisar el cuarto de almacenamiento encima de Worner.,,"Tuhoa kaupungin sähköverkon voimanlähteenä toimiva voimakristalli, jonka voimaa Veljeskunnan kilvet käyttävät. Käytä henkilötunnistetta päästäksesi voimalaitokselle. Saatat haluta vilkaista varastohuonetta Wornerin yläpuolella.",Détruis le cristal qui alimente la grille énergétique des boucliers de l'Ordre. Utilise la carte d'identité pour entrer dans la centrale. Il faudrait que tu aille voir la salle de stockage au dessus de Worner.,"Semmisítsd meg az erő kristályt, ami a Rend külső védőpajzsát hajtja az elektromos hálózaton keresztül. Használd az igazolványt, hogy bejuss az erőműbe. Jobban jársz, ha benézel a Worner fölötti tárolószobába.",Distruggi il cristallo che fornisce energia agli scudi dell'Ordine. Usa il tesserino d'identificazione per entrare nella centrale energetica. Ti conviene controllare il deposito che si trova sopra Worner.,"送電網を動かしているパワークリスタルを破壊してオーダーのシールドを止める。 手に入れたI.D.を使って発電所に入る。 -ワーナーの言う上階の部屋も余裕があったら調べる。",오더의 방어막을 유지하는 동력 망의 전력원인 수정체를 파괴하자. 신분증을 이용해서 발전소 안으로 들어가. 그리고 워너 위에 창고도 확인하는 거 잊지 마!,Vernietig het energiekristal dat het elektriciteitsnet dat de schilden van de Orde aandrijft. Gebruik de I.D. om in de centrale te komen. Je kunt het magazijn boven Worner bekijken.,,Destrua o cristal de energia que alimenta a rede elétrica por trás dos escudos da Ordem. Use a identificação para infiltrar a usina de energia. Você pode querer dar uma olhada no depósito acima do Worner.,,,"Уничтожь кристалл, питающий энергосеть, от которой работают щиты Ордена. Пройди на электростанцию по удостоверению. Возможно, ты захочешь проверить склад на втором этаже, о котором говорил Уорнэр.", -Destroy the power crystal that runs the power grid which drives the Order's shields. Go talk to Ketrick in the core area.,TXT_ILOG1013,,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Jdi za Ketrickem u jádra.","Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Suche Worner auf, einen Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben. Vergiß nicht, den Sanitäter und den Waffentrainer aufzusuchen, bevor du gehst.",,,Destruye el cristal de poder que impulsa la rede eléctrica que alimenta los escudos de la Orden. Habla con Ketrick en el área del núcleo.,Destruye el cristal de poder que impulsa la red eléctrica que abastece los escudos de la Orden. Ve a hablar con Ketrick en el área del núcleo.,,Détruis le cristal qui alimente la grille énergétique des boucliers de l'Ordre. Va parler à Ketrick dans la zone du cœur.,,,"送電網を動かしているパワークリスタルを破壊してオーダーのシールドを止める。 -コアエリアでケトリックと話す。",오더의 방어막을 유지하는 동력 망의 전력원인 수정체를 파괴하자. 중심부에 있는 케트릭과 대화해.,Vernietig het energiekristal dat het elektriciteitsnet dat de schilden van de Orde aandrijft. Ga in het kerngebied met Ketrick praten.,,Destrua o cristal de energia que alimenta a rede elétrica por trás dos escudos da Ordem. Fale com o Ketrick na área do núcleo.,,,"Уничтожь кристалл, питающий энергосеть Ордена и их щиты. Поговори с Кетриком возле реактора.", -"Destroy the power crystal. Go talk to Ketrick, bring the walkway up using the switches, then use this id for the elevator.",TXT_ILOG1014,,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Jdi si promluvit s Ketrickem, vyzvedni schodiště pomocí tlačítek a pak ve výtahu použij tuhle kartu.",Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Gehe zu Ketrick im Reaktorkern.,,,"Destruye el cristal de poder. Habla con Ketrick, alza la pasarela usando los interruptores, luego usa esta identificación para el ascensor.","Destruye el cristal de poder. Ve a hablar con Ketrick, levanta el pasaje usando los switches, luego, usa está identificación para el elevador.",,"Détruis le cristal. Va parler à Ketrick. Fais monter la coursive en utilisant les boutons, puis utilise ta carte d'identité pour accéder à l'ascenseur.",,,"パワークリスタルを破壊してオーダーのシールドを止める。 -ケトリックと話し、スイッチを動かし通路を上げ、エレベーターにIDを使う。",수정체를 파괴해. 케트릭과 대화하고 나서 스위치를 눌러서 진입로를 작동시켜. 그리고 이 신분증을 이용해서 승강기를 올라타.,"Vernietig het energiekristal. Ga met Ketrick praten, breng de gang naar boven met behulp van de schakelaars, gebruik dan deze id voor de lift.",,"Destrua o cristal de energia. Fale com o Ketrick, faça a passarela subir usando os interruptores e depois use esta identificação para o elevador.",,,"Уничтожь кристалл. Поговори с Кетриком, пройди наверх с помощью переключателей, затем используй удостоверение для доступа к лифту.", -Find the town entrance that the Order has guarded. Open the door and bring the guard's uniform back to Weran.,TXT_ILOG1015,,,,"Najdi vchod do města, který Řád hlídá. Otevři dveře a přines hlídačovu uniformu Weranovi.","Finde den Ausgang zur Stadt, der vom Orden bewacht wird. Öffne dir Tür und bringe die Uniform des Wächters zu Weran.",,,Encuentra la entrada al pueblo que la Orden tiene guardada. Abre la puerta y trae de vuelta a Weran el uniforme del guardia.,Encuentra la entrada al pueblo que la Orden ha guardado. Abre la puerta y trae el uniforme del guardia de regreso a Weran.,,Trouve l'entrée de la ville que L'Ordre garde fermée. Ouvre-la et amène l'uniforme du garde à Weran.,,,"オーダーが封鎖している町への入り口を見つける。 -ドアを開け、ガードの制服をウェランに持って帰る。",오더의 경비가 지키고 있는 마을의 입구를 찾아. 문을 연 뒤 그 경비의 전투복을 챙겨서 워렌에게 전해줘.,Zoek de stadstoegang die de Orde heeft bewaakt. Open de deur en breng het uniform van de bewaker terug naar Weran.,,Encontre a entrada da cidade que a Ordem está vigiando. Abra a porta e leve o uniforme do guarda de volta para o Weran.,,,"Найди выход в город, охраняемый Орденом. Открой дверь и принеси униформу стражника Уэрану.", -"Take the flamethrower parts to Irale. Find the sewer maintenance door. Find and drain the reclamation tank inside the castle. At the bottom is a hidden entrance to the sewers. Down that entrance is where the gate controls are, somewhere.",TXT_ILOG1016,,,,Přines součásti plamenometu k Iralemu. Najdi kanálové údržbové dveře. Najdi a vypusť vodní nádrž uvnitř hradu. Na dně je skrytý vchod do dalších stok. Někde uvnitř je ovládání bran.,Bringe dir Flammenwerferteile zu Irale. Finde die Wartungstür in der Kanalisation. Finde und leere den Sammeltank in der Burg. Am Boden ist ein versteckter Eingang zur Kanalisation. Dort ist die Steuerung für die Tore. Zerstöre sie.,,,"Llévale las partes de lanzallamas a Irale. Encuentra la puerta de mantenimiento de las alcantarillas. Encuentra y drena el tanque de reclamación dentro del castillo. Al fondo hay una entrada oculta a las alcantarillas. Bajando por esa entrada es donde se encuentran los controles de la puerta, en algún lugar.","Llévale las partes del lanzallamas a Irale. Encuentra la puerta de mantenimiento de la alcantarilla. Encuentra y drena el tanque de recuperación adentro del castillo. En el fondo de esa entrada están los controles de las puertas, en algún lugar.",,Amène les pièces du lance-flamme à Irale. Trouve l'entrée de maintenance des égouts. Fais vider le réservoir de recyclage du château. Au fond se trouve une entrée cachée vers les égouts. Les contrôles de la porte s'y trouvent.,,,"火炎放射器の部品をイラールに持っていく。 +ワーナーの言う上階の部屋も余裕があったら調べる。",오더의 방어막을 유지하는 동력 망의 전력원인 수정체를 파괴하자. 신분증을 이용해서 발전소 안으로 들어가. 그리고 워너 위에 창고도 확인하는 거 잊지 마!,Vernietig het energiekristal dat het elektriciteitsnet dat de schilden van de Orde aandrijft. Gebruik de I.D. om in de centrale te komen. Je kunt het magazijn boven Worner bekijken.,Ødelegg kraftkrystallen som driver kraftnettet som driver Ordenens skjold. Bruk I.D. for å komme inn i kraftstasjonen. Det kan være lurt å sjekke ut lagerrommet over Worner.,"Zniszcz kryształ mocy, który zasila sieć energetyczną napędzającą tarcze Zakonu. Użyj I.D., aby dostać się do elektrowni. Możesz chcieć sprawdzić magazyn nad Wornerem.",Destrua o cristal de energia que alimenta a rede elétrica por trás dos escudos da Ordem. Use a identificação para infiltrar a usina de energia. Você pode querer dar uma olhada no depósito acima do Worner.,,Distruge critalul energetic care alimentează scuturile Ordinului. Folosește cardul pentru a intra în stația de alimentare. Ai putea verifica și depozitul de deasupra lui Worner.,"Уничтожь кристалл, питающий энергосеть, от которой работают щиты Ордена. Пройди на электростанцию по удостоверению. Возможно, ты захочешь проверить склад на втором этаже, о котором говорил Уорнэр.",,Förstör kraftkristallen som driver kraftnätet som driver Ordens sköldar. Använd ID-kortet för att ta dig in i kraftstationen. Du kanske vill kolla in förrådet ovanför Worner.,Tarikat'ın kalkanlarını çalıştıran güç şebekesini çalıştıran güç kristalini yok edin. Güç istasyonuna girmek için kimliği kullanın. Worner'ın üstündeki depoyu kontrol etmek isteyebilirsiniz. +Destroy the power crystal that runs the power grid which drives the Order's shields. Go talk to Ketrick in the core area.,TXT_ILOG1013,"MAP04: After talking to ""Mr. Crispy"".",,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Jdi za Ketrickem u jádra.","Ødelæg kraftkrystallen, der driver det kraftnet, som driver Ordenens skjolde. Gå hen og tal med Ketrick i kerneområdet.","Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Suche Worner auf, einen Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben. Vergiß nicht, den Sanitäter und den Waffentrainer aufzusuchen, bevor du gehst.",,,Destruye el cristal de poder que impulsa la red eléctrica que alimenta los escudos de La Orden. Habla con Ketrick en el área del núcleo.,,"Tuhoa kaupungin sähköverkon voimanlähteenä toimiva voimakristalli, jonka voimaa Veljeskunnan kilvet käyttävät. Puhu Ketrickin kanssa reaktorisydämen alueella.",Détruis le cristal qui alimente la grille énergétique des boucliers de l'Ordre. Va parler à Ketrick dans la zone du cœur.,"Semmisítsd meg az erő kristályt, ami a Rend külső védőpajzsát hajtja az elektromos hálózaton keresztül. Megleled Ketricket a mag térségben.",Distruggi il cristallo che fornisce energia agli scudi dell'Ordine. Vai a parlare con Ketrick nell'area del nucleo.,"送電網を動かしているパワークリスタルを破壊してオーダーのシールドを止める。 +コアエリアでケトリックと話す。",오더의 방어막을 유지하는 동력 망의 전력원인 수정체를 파괴하자. 중심부에 있는 케트릭과 대화해.,Vernietig het energiekristal dat het elektriciteitsnet dat de schilden van de Orde aandrijft. Ga in het kerngebied met Ketrick praten.,Ødelegg kraftkrystallen som driver kraftnettet som driver Ordenens skjold. Snakk med Ketrick i kjerneområdet.,"Zniszcz kryształ mocy, który uruchamia sieć energetyczną napędzającą tarcze Zakonu. Idź porozmawiać z Ketrickiem w obszarze rdzenia.",Destrua o cristal de energia que alimenta a rede elétrica por trás dos escudos da Ordem. Fale com o Ketrick na área do núcleo.,,Distruge cristalul de energie care alimentează scuturile Ordinului. Vorbește cu Ketrick în zona nucleului.,"Уничтожь кристалл, питающий энергосеть Ордена и их щиты. Поговори с Кетриком возле реактора.",,Förstör kraftkristallen som driver kraftnätet som driver ordens sköldar. Gå och prata med Ketrick i kärnområdet.,Tarikat'ın kalkanlarını çalıştıran güç şebekesini çalıştıran güç kristalini yok edin. Çekirdek alanda Ketrick ile konuş. +"Destroy the power crystal. Go talk to Ketrick, bring the walkway up using the switches, then use this id for the elevator.",TXT_ILOG1014,MAP04: After talking to Sammis.,,,"Znič energetický krystal, který napájí elektrickou síť, kterou jsou poháněné štíty Řádu. Jdi si promluvit s Ketrickem, vyzvedni schodiště pomocí tlačítek a pak ve výtahu použij tuhle kartu.","Ødelæg kraftkrystallen. Gå hen og tal med Ketrick, bring gangbroen op ved hjælp af kontakterne, og brug derefter dette id til elevatoren.",Zerstöre den Energiekristall der die Energieversorgung für die Kraftschilde kontrolliert. Gehe zu Ketrick im Reaktorkern.,,,"Destruye el cristal de poder. Habla con Ketrick, alza la pasarela usando los interruptores, luego usa esta identificación para el ascensor.",,Tuhoa voimakristalli. Mene puhumaan Ketrickin kanssa. Tuo kulkusilta vivuilla ylös ja sitten käytä tätä tunnistetta hissiin.,"Détruis le cristal. Va parler à Ketrick. Fais monter la coursive en utilisant les boutons, puis utilise ta carte d'identité pour accéder à l'ascenseur.","Semmisítsd meg az erő kristályt. Menj és beszélj Kedrickkel, a kapcsolóval emeld meg a hidat, aztán használd az igazolványt a lifthez.","Distruggi il cristallo. Parla con Ketrick, fai alzare la passerella con i pulsanti, e poi usa questo tesserino per l'ascensore.","パワークリスタルを破壊してオーダーのシールドを止める。 +ケトリックと話し、スイッチを動かし通路を上げ、エレベーターにIDを使う。",수정체를 파괴해. 케트릭과 대화하고 나서 스위치를 눌러서 진입로를 작동시켜. 그리고 이 신분증을 이용해서 승강기를 올라타.,"Vernietig het energiekristal. Ga met Ketrick praten, breng de gang naar boven met behulp van de schakelaars, gebruik dan deze id voor de lift.","Ødelegg kraftkrystallen. Snakk med Ketrick, få gangbroen opp ved hjelp av bryterne, og bruk denne id-en til heisen.","Zniszcz kryształ mocy. Idź porozmawiać z Ketrickiem, podnieś chodnik używając przełączników, a następnie użyj tego id do windy.","Destrua o cristal de energia. Fale com o Ketrick, faça a passarela subir usando os interruptores e depois use esta identificação para o elevador.",,"Distruge cristalul energetic. Vorbește cu Ketrick, redă pasarela folosind butoanele, apoi folosește cardul pentru lift.","Уничтожь кристалл. Поговори с Кетриком, пройди наверх с помощью переключателей, затем используй удостоверение для доступа к лифту.",,"Förstör kraftkristallen. Gå och prata med Ketrick, ta upp gångvägen med hjälp av brytarna och använd sedan denna id för hissen.","Güç kristalini yok et. Ketrick ile konuşun, anahtarları kullanarak geçidi yukarı getirin, sonra asansör için bu kimliği kullanın." +Find the town entrance that the Order has guarded. Open the door and bring the guard's uniform back to Weran.,TXT_ILOG1015,,,,"Najdi vchod do města, který Řád hlídá. Otevři dveře a přines hlídačovu uniformu Weranovi.","Find byens indgang, som Ordenen har bevogtet. Åbn døren og bring vagtens uniform tilbage til Weran.","Finde den Ausgang zur Stadt, der vom Orden bewacht wird. Öffne dir Tür und bringe die Uniform des Wächters zu Weran.",,,Encuentra la entrada al pueblo que La Orden tiene guardada. Abre la puerta y tráele de vuelta a Weran el uniforme del guardia.,,Löydä Veljeskunnan vartioima kaupungin sisäänkäynti. Avaa ovi ja tuo vartijan univormu Weranille.,Trouve l'entrée de la ville que L'Ordre garde fermée. Ouvre-la et amène l'uniforme du garde à Weran.,"Keresd meg a város bejáratot, amit a Rend őrzött. Nyisd ki az ajtót, és vidd vissza az uniformist Weranhoz.",Trova l'entrata verso la città che l'Ordine ha chiuso. Apri l'ingresso e riporta l'uniforme della guardia a Weran.,"オーダーが封鎖している町への入り口を見つける。 +ドアを開け、ガードの制服をウェランに持って帰る。",오더의 경비가 지키고 있는 마을의 입구를 찾아. 문을 연 뒤 그 경비의 전투복을 챙겨서 워렌에게 전해줘.,Zoek de stadstoegang die de Orde heeft bewaakt. Open de deur en breng het uniform van de bewaker terug naar Weran.,Finn inngangen til byen som Ordenen har bevoktet. Åpne døren og ta med vaktens uniform tilbake til Weran.,"Znajdź wejście do miasta, którego pilnuje Zakon. Otwórz drzwi i przynieś Weranowi mundur strażnika.",Encontre a entrada da cidade que a Ordem está vigiando. Abra a porta e leve o uniforme do guarda de volta para o Weran.,,Găsește intrarea orașului pe care Ordinul a păzit-o. Deschide ușa și du uniforma paznicului la Weran.,"Найди выход в город, охраняемый Орденом. Открой дверь и принеси униформу стражника Уэрану.",,Hitta stadens ingång som ordern har bevakat. Öppna dörren och ta med dig vaktuniformen tillbaka till Weran.,Tarikatın koruduğu kasaba girişini bulun. Kapıyı açın ve muhafız üniformasını Weran'a geri getirin. +"Take the flamethrower parts to Irale. Find the sewer maintenance door. Find and drain the reclamation tank inside the castle. At the bottom is a hidden entrance to the sewers. Down that entrance is where the gate controls are, somewhere.",TXT_ILOG1016,,,,Přines součásti plamenometu k Iralemu. Najdi kanálové údržbové dveře. Najdi a vypusť vodní nádrž uvnitř hradu. Na dně je skrytý vchod do dalších stok. Někde uvnitř je ovládání bran.,"Tag flammekasterens dele med til Irale. Find døren til vedligeholdelse af kloakken. Find og tøm genvindingstanken inde på slottet. I bunden er der en skjult indgang til kloakkerne. Nede ved denne indgang er der et sted, hvor kontrolelementerne til porten er.",Bringe dir Flammenwerferteile zu Irale. Finde die Wartungstür in der Kanalisation. Finde und leere den Sammeltank in der Burg. Am Boden ist ein versteckter Eingang zur Kanalisation. Dort ist die Steuerung für die Tore. Zerstöre sie.,,,"Llévale las partes de lanzallamas a Irale. Encuentra la puerta de mantenimiento de las alcantarillas. Encuentra y drena el tanque de reclamación dentro del castillo. Al fondo hay una entrada oculta a las alcantarillas. Bajando por esa entrada es donde se encuentran los controles de la puerta, en algún lugar.","Llévale las partes del lanzallamas a Irale. Encuentra la puerta de mantenimiento de la alcantarilla. Encuentra y drena el tanque de recuperación adentro del castillo. En el fondo de esa entrada están los controles de las puertas, en algún lugar.","Toimita liekinheittimen osat Iralelle. Etsi viemärin huolto-ovi. Etsi ja tyhjennä nesteentalteenottoallas linnan sisällä. Sen pohjalla on viemärin salainen sisäänkäynti, jonka sisältä portin ohjaimet jostakin löytyvät.",Amène les pièces du lance-flamme à Irale. Trouve l'entrée de maintenance des égouts. Fais vider le réservoir de recyclage du château. Au fond se trouve une entrée cachée vers les égouts. Les contrôles de la porte s'y trouvent.,Vidd a lángszóró darabokat Iralehez. Keresd meg a kanális szervíz ajtaját. Keresd meg a lefolyót és szárító tartályt a kastélyban. Az alján található egy titkos bejárat a kanálishoz. Túl ezen a bejáraton fogod megtalálni a kapu irányítópultot.,"Porta i pezzi del lanciafiamme da Irale. Trova l'entrata di manutenzione per le fogne. Svuota la vasca di recupero fluidi. Nel fondo c'è un'entrata nascosta per le fogne. I controlli dei cancelli sono laggiù, da qualche parte.","火炎放射器の部品をイラールに持っていく。 下水道のメンテナンス室を見つけ、 城内の貯水タンクを見つけて排水。 -その下には下水道への隠された入り口があり、その奥にゲートコントロールがある。","이 화염방사기 부품을 들고 이롤리에게 가져가. 하수도 정비소로 향하는 문을 찾은 뒤, 성안에 있는 수조를 찾고 내용물을 배출해. 그 밑에는 하수도로 향하는 숨겨진 통로가 있어. 그 안에는 분명히 성문 관리 장치가 있을 거야.","Neem de vlammenwerper delen naar Irale. Zoek de deur voor het rioolonderhoud. Zoek en laat de inpolderingstank in het kasteel leeglopen. Onderin is een verborgen ingang naar de riolering. Onderaan die ingang is waar de poortbediening is, ergens.",,Leve as peças do lança-chamas ao Irale. Ache a porta de manutenção do esgoto. Encontre e drene o tanque de recuperação dentro do castelo. No fundo há uma entrada oculta para o esgoto. Entre lá e encontre os controles do portão.,,,Отнеси детали огнемёта Ирэйлу. Найди дверь техобслуживания канализации. Найди бак для переработки и слей из него жидкость. На его дне находится потайной вход в стоки. Где-то за ним находится механизм управления воротами., -Join the assault on the castle. Find and take out the Programmer. See the medic and the weapons trainer. Spend everything you've got. This is going to be a hell of a fight.,TXT_ILOG1017,,,,"Připoj se k útoku na hrad. Najdi a zabij Programátora. Zajdi si ke zdravotníkovi a učiteli střelby. Utrať vše, co máš. Tohle bude tvrdý boj.","Schließe dich dem Angriff auf die Burg an. Finde den Programmierer und schalte ihn aus. Suche den Sanitäter und den Waffentrainer auf. Kaufe was immer du kannst, das wird ein höllischer Kampf.",,,Únete al asalto en el castillo. Encuentra y elimina al Programador. Ve a ver al médico y entrenador de armas. Gasta todo lo que tengas. Esto va a ser una batalla tremenda.,Únete al asalto en el castillo. Encuentra y elimina al Programador. Ve al médico y al entrenador de armas. Gasta todo lo que tengas. Esta será una tremenda batalla.,,"Rejoins l'assaut sur le château. Trouve et tue le Programmeur. Va voir le médecin et le maître d'armes. Dépense tout ce que tu as, ça va être un sacré bain de sang!",,,"城内への突撃部隊に加入し、プログラマーを探す。 +その下には下水道への隠された入り口があり、その奥にゲートコントロールがある。","이 화염방사기 부품을 들고 이롤리에게 가져가. 하수도 정비소로 향하는 문을 찾은 뒤, 성안에 있는 수조를 찾고 내용물을 배출해. 그 밑에는 하수도로 향하는 숨겨진 통로가 있어. 그 안에는 분명히 성문 관리 장치가 있을 거야.","Neem de vlammenwerper delen naar Irale. Zoek de deur voor het rioolonderhoud. Zoek en laat de inpolderingstank in het kasteel leeglopen. Onderin is een verborgen ingang naar de riolering. Onderaan die ingang is waar de poortbediening is, ergens.","Ta flammekasterdelene til Irale. Finn vedlikeholdsdøren til kloakken. Finn og tøm gjenvinningstanken inne i slottet. Nederst er det en skjult inngang til kloakken. Ned den inngangen er hvor portkontrollene er, et eller annet sted.",Zabierz części miotacza ognia do Irale. Znajdź drzwi do konserwacji kanałów. Znajdź i osusz zbiornik rekultywacyjny wewnątrz zamku. Na dole jest ukryte wejście do kanałów. Na dole tego wejścia jest gdzieś sterowanie bramą.,Leve as peças do lança-chamas ao Irale. Ache a porta de manutenção do esgoto. Encontre e drene o tanque de recuperação dentro do castelo. No fundo há uma entrada oculta para o esgoto. Entre lá e encontre os controles do portão.,,"Du bucățiile aruncătorului de flăcări la Irale. Găsește ușa de mentenanță de la canale. Găsește și drenează rezervorul de recuperare din interiorul castelului. La fund e o intrare secretă către canale. Jos, se pot acționa porțiile, de undeva.",Отнеси детали огнемёта Ирэйлу. Найди дверь техобслуживания канализации. Найди бак для переработки и слей из него жидкость. На его дне находится потайной вход в стоки. Где-то за ним находится механизм управления воротами.,,Ta med dig flamethrowerdelarna till Irale. Hitta dörren till underhållet av kloakerna. Hitta och töm återvinningstanken inne i slottet. I botten finns en dold ingång till avloppen. Nere vid den ingången finns portkontrollerna någonstans.,Alev makinesi parçalarını İrale'ye götürün. Kanalizasyon bakım kapısını bulun. Kalenin içindeki ıslah tankını bulun ve boşaltın. En altta kanalizasyona giden gizli bir giriş var. O girişin aşağısında kapı kontrollerinin olduğu yer var. +Join the assault on the castle. Find and take out the Programmer. See the medic and the weapons trainer. Spend everything you've got. This is going to be a hell of a fight.,TXT_ILOG1017,MAP03: After destroying the gate controls and talking to Macil.,,,"Připoj se k útoku na hrad. Najdi a zabij Programátora. Zajdi si ke zdravotníkovi a učiteli střelby. Utrať vše, co máš. Tohle bude tvrdý boj.","Deltag i angrebet på slottet. Find og dræb programmøren. Se lægen og våbentræneren. Brug alt, hvad du har. Dette bliver en helvedes kamp.","Schließe dich dem Angriff auf die Burg an. Finde den Programmierer und schalte ihn aus. Suche den Sanitäter und den Waffentrainer auf. Kaufe was immer du kannst, das wird ein höllischer Kampf.",,,Únete al asalto en el castillo. Encuentra y elimina al Programador. Ve a ver al médico y entrenador de armas. Gasta todo lo que tengas. Esto va a ser una batalla tremenda.,Únete al asalto en el castillo. Encuentra y elimina al Programador. Ve al médico y al entrenador de armas. Gasta todo lo que tengas. Esta será una tremenda batalla.,Osallistu hyökkäykseen linnaa vastaan. Etsi ja kukista Ohjelmoitsija. Tapaa lääkintämiestä ja asekouluttajaa. Käytä kaikki varasi; tästä tulee hitonmoinen taistelu.,"Rejoins l'assaut sur le château. Trouve et tue le Programmeur. Va voir le médecin et le maître d'armes. Dépense tout ce que tu as, ça va être un sacré bain de sang!",Csatlakozz a kastély ostromához. Keresd meg és iktasd ki a Programozót. Menj a szanitéchoz és a fegyver kiképzőhöz. Költs el mindent amit csak tudsz. Gigászi csata előtt állunk.,"Unisciti all'assalto sul castello. Trova e fai fuori il Programmatore. Passa dal medico e dall'addestratore di armi. Ti conviene spendere più che puoi, sarà una dura battaglia.","城内への突撃部隊に加入し、プログラマーを探す。 メディックと武器トレーナーに会っておく。 -この戦いは激しいものになるだろう、使えるものは全て使うつもりで行け。",성을 공략할 공성전에 참여해. 침투해서 프로그래머를 죽일 수 있게. 의무관이랑 무기 담당관을 만나고 네가 살 수 있는 걸 충분히 사. 왜냐하면 이 교전은 끔찍할 테니까.,Doe mee aan de aanval op het kasteel. Zoek en haal de Programmeur eruit. Zie de dokter en de wapentrainer. Geef alles uit wat je hebt. Dit wordt een hels gevecht.,,Junte-se ao ataque no castelo. Ache e elimine o Programador. Visite o médico e o treinador de armas. Gaste tudo o que você tem. Essa vai ser uma briga das grandes.,,,Присоединись к атаке на замок. Найди и убей Программиста. Посети медика и инструктора по стрельбе. Не жалей золота — битва будет чертовски жаркой., -Use the key the false Programmer gave you to open an entrance to the Programmer's keep. It has to be where he's hiding. Find the Programmer and kill him.,TXT_ILOG1018,,,,Použij klíč od falešného Programátora pro otevření vchodu do Programátorova doupěte. Tam se musí nacházet. Najdi Programátora a zabij ho.,"Benutze den Schlüssel des falschen Programmierers um in die Unterkunft des Programmierers einzudringen. Das ist der Ort, wo er sich verstecken dürfte. Finde und töte ihn.",,,Usa la llave que el falso Programador te dió para abrir una entrada a la guarida del Programador. Tiene que ser ahí donde se oculta. Encuentra al Programador y mátalo.,Usa la llave que el falso Programador te dió para abrir la entrada a la güarida del Programador. Debe ser donde está escondido. Encuentra al Programador y mátalo.,,Utilise la clé que le faux Programmeur t'a donné pour entrer dans le donjon du Programmeur. Il doit s'y cacher. Trouve-le et tues-le.,,,"偽プログラマーから貰ったキーを使って本物がいるはずの砦を開く。 -奴はそこに隠れなければならないはず。プログラマーを見つけて殺す。","프로그래머 더미가 준 열쇠를 이용해서 프로그래머의 거주지로 향하는 문을 열어. 안에는 분명히 그가 있을 거야. 프로그래머를 찾으면, 일이 더 나빠지기 전에 죽여.",Gebruik de sleutel die de valse Programmer je gaf om een ingang te openen naar de wacht van de Programmeur. Het moet zijn waar hij zich verbergt. Zoek de Programmeur en vermoord hem.,,Use a chave que o falso Programador te deu para abrir uma entrada à fortaleza do Programador. Tem que ser onde ele está escondido. Encontre o Programador e mate-o.,,,"Используй ключ, полученный от фальшивого Программиста, чтобы открыть вход в цитадель. Скорее всего, именно там прячется настоящий Программист. Найди и убей его.", -Seek out the Oracle and ask it about the other Sigil pieces. Take your reward and go across to the medic and weapons trainer for health and training.,TXT_ILOG1019,,,,Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Převezmi si svou odměnu a navštiv zdravotníka a učitele střelby pro zdraví a výcvik.,Suche das Orakel auf und frage es nach den anderen Sigil-Teilen. Nimm deine Belohnung und suche den Sanitäter und den Waffentrainer auf.,,,Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Toma tu recompensa y ve al médico y al entrenador de armas para salud y entrenamiento.,Busca al Oráculo y pregúntale acerca de las otras piezas del Emblema. Toma tú recompensa y dirígete con el médico y el entrenador de armas por salúd y entrenamiento.,,"Trouve l'Oracle et demande lui où se trouve les autres pièces du Sigil. Récupère ta récompense, et va voir le médecin et le maître d'armes pour te soigner et t'entraîner.",,,"オラクルに会いシジルの欠片について尋ねる。 -強化のためメディックと武器トレーナーに会っておく。",오라클을 찾아서 다른 시질 조각이 어디에 있는지 물어봐. 보상을 받고 치료와 훈련을 위해 의무관과 무기 담당관에게로 가.,Zoek het Orakel op en vraag het over de andere Sigil stukken. Pak je beloning en ga naar de dokter en wapentrainer voor gezondheid en training.,,Procure o Oráculo e pergunte o sobre as outras peças do Sigilo. Pegue a sua recompensa e visite o médico e o treinador de armas para recuperar saúde e receber treinamento.,,,Найди Оракула и спроси у него про другие фрагменты Сигила. Возьми свою награду и посети медика и инструктора по стрельбе., -"The second piece lies at the heart of the crimson and obsidian tower. There you must find the Bishop, who awaits you. Take the Oracle's token to the key master in the borderlands. Once you have destroyed the Bishop, return to the Oracle.",TXT_ILOG1020,,,,"Druhý díl leží v srdci věže karmíno-obsidiánové. Tam musíš najít Biskupa, který tě očekává. Vezmi Věštcův pas ke klíčníkovi v pohraničí. Až zabiješ Biskupa, vrať se k Věštci.","Das zweite Teilstück befindet sich im Turm aus Purpur und Obsidian. Dort musst du den Bischof finden, der dich erwartet. Bringe das Symbol des Orakels zum Schlüsselmeister in den Grenzgebieten. Wenn der Bischof ausgeschaltet ist, kehre zum Orakel zurück.",,,"La segunda pieza se encuentra en el corazón e la torre carmesí y obsidiana. Ahí debes encontrar al Obispo, quien espera por ti. Lleva el vale del Oráculo al amo de llaves en las fronteras. En cuanto hayas destruido al Obispo, regresa con el Oráculo.","La segunda pieza está en el corazón de la torre carmesí y obsidiana. Ahí deberás encontrar al Obispo, que te está esperando. Lleva el símbolo del Oráculo al Amo de Llaves en las fronteras. Cuando hayas destruido al Obispo, regresa con el Oráculo.",,"La deuxième pièce se trouve au cœur de la tour d'obsidienne et d'écarlate. Tu y trouveras l'évêque, qui t'attend. Amène le jeton de l'Oracle au maître des clés dans les terrains vagues. Quand tu as tué l'évêque, retourne voir l'Oracle.",,,"二つ目の欠片は深紅と黒曜石の塔の中心部にある。そこのビショップを討伐せよ。 +この戦いは激しいものになるだろう、使えるものは全て使うつもりで行け。",성을 공략할 공성전에 참여해. 침투해서 프로그래머를 죽일 수 있게. 의무관이랑 무기 담당관을 만나고 네가 살 수 있는 걸 충분히 사. 왜냐하면 이 교전은 끔찍할 테니까.,Doe mee aan de aanval op het kasteel. Zoek en haal de Programmeur eruit. Zie de dokter en de wapentrainer. Geef alles uit wat je hebt. Dit wordt een hels gevecht.,Bli med i angrepet på slottet. Finn og drep programmereren. Gå til legen og våpentreneren. Bruk alt du har. Dette kommer til å bli litt av en kamp.,"Dołącz do szturmu na zamek. Znajdź i zlikwiduj Programistę. Zobacz medyka i trenera broni. Wydaj wszystko, co masz. To będzie piekielnie trudna walka.",Junte-se ao ataque no castelo. Ache e elimine o Programador. Visite o médico e o treinador de armas. Gaste tudo o que você tem. Essa vai ser uma briga das grandes.,,Alătură-te asaltului asupra castelului. Vezi medicul și antrenorul de arme. Cheltuie tot ce ai. O să fie o luptă pe cnste.,Присоединись к атаке на замок. Найди и убей Программиста. Посети медика и инструктора по стрельбе. Не жалей золота: битва будет чертовски жаркой.,,Gå med i anfallet mot slottet. Hitta och ta ut programmeraren. Se till sjukvårdaren och vapentränaren. Spendera allt du har. Det här kommer att bli en jäkla kamp.,Kaleye yapılan saldırıya katıl. Programcıyı bul ve etkisiz hale getir. Sıhhiyeciyi ve silah eğitmenini gör. Elinizdeki her şeyi harcayın. Bu cehennem gibi bir savaş olacak. +Use the key the false Programmer gave you to open an entrance to the Programmer's keep. It has to be where he's hiding. Find the Programmer and kill him.,TXT_ILOG1018,,,,Použij klíč od falešného Programátora pro otevření vchodu do Programátorova doupěte. Tam se musí nacházet. Najdi Programátora a zabij ho.,"Brug den nøgle, som den falske programmør gav dig, til at åbne en indgang til programmørens tårn. Det må være der, hvor han gemmer sig. Find programmøren og dræb ham.","Benutze den Schlüssel des falschen Programmierers um in die Unterkunft des Programmierers einzudringen. Das ist der Ort, wo er sich verstecken dürfte. Finde und töte ihn.",,,Usa la llave que el falso Programador te dió para abrir una entrada a la guarida del Programador. Tiene que ser ahí donde se oculta. Encuentra al Programador y mátalo.,Usa la llave que el falso Programador te dió para abrir la entrada a la güarida del Programador. Debe ser donde está escondido. Encuentra al Programador y mátalo.,Käytä Valeohjelmoitsijan antamaa avainta avataksesi sisäänkäynnin Ohjelmoitsijan linnakkeeseen. Siellä hän varmastikin piilottelee. Etsi Ohjelmoitsija ja tapa hänet.,Utilise la clé que le faux Programmeur t'a donné pour entrer dans le donjon du Programmeur. Il doit s'y cacher. Trouve-le et tues-le.,"Használd az ál-programozótól kapott kulcsot, hogy bejuss a Programozó tornyába. Minden bizonnyal ott bújkál. Keresd meg a Programozót, és öld meg.",Usa la chiave che il falso Programmatore ti ha dato per entrare nella fortezza del Programmatore. Deve essere là che si nasconde. Trova il Programmatore e uccidilo.,"偽プログラマーから貰ったキーを使って本物がいるはずの砦を開く。 +奴はそこに隠れなければならないはず。プログラマーを見つけて殺す。","프로그래머 더미가 준 열쇠를 이용해서 프로그래머의 거주지로 향하는 문을 열어. 안에는 분명히 그가 있을 거야. 프로그래머를 찾으면, 일이 더 나빠지기 전에 죽여.",Gebruik de sleutel die de valse Programmer je gaf om een ingang te openen naar de wacht van de Programmeur. Het moet zijn waar hij zich verbergt. Zoek de Programmeur en vermoord hem.,Bruk nøkkelen den falske programmereren ga deg til å åpne en inngang til programmererens borg. Det må være der han gjemmer seg. Finn programmereren og drep ham.,"Użyj klucza, który dał ci fałszywy Programista, aby otworzyć wejście do kryjówki Programisty. To musi być miejsce, gdzie on się ukrywa. Znajdź Programistę i zabij go.",Use a chave que o falso Programador te deu para abrir uma entrada à fortaleza do Programador. Tem que ser onde ele está escondido. Encontre o Programador e mate-o.,,Folosește cheia pe care Programator fals ți-a dat-o pentru a deschide intrarea către curtea Programatorului. Trebuie să fie locul în care se ascunde. Găsește Programatorul și ucide-l.,"Используй ключ, полученный от фальшивого Программиста, чтобы открыть вход в цитадель. Скорее всего, именно там прячется настоящий Программист. Найди и убей его.",,Använd nyckeln som den falska programmeraren gav dig för att öppna en ingång till programmerarens borg. Det måste vara där han gömmer sig. Hitta Programmeraren och döda honom.,Sahte Programcı'nın size verdiği anahtarı kullanarak Programcı'nın kalesine bir giriş açın. Saklandığı yer orası olmalı. Programcıyı bul ve öldür. +Seek out the Oracle and ask it about the other Sigil pieces. Take your reward and go across to the medic and weapons trainer for health and training.,TXT_ILOG1019,MAP10: After killing the Programmer and talking to Macil.,,,Najdi Věštce a zeptej se ho na ostatní díly Pečetě. Převezmi si svou odměnu a navštiv zdravotníka a učitele střelby pro zdraví a výcvik.,Opsøg Oraklet og spørg det om de andre Sigil stykker. Tag din belønning og gå over til lægen og våbentræneren for at få sundhed og træning.,Suche das Orakel auf und frage es nach den anderen Sigil-Teilen. Nimm deine Belohnung und suche den Sanitäter und den Waffentrainer auf.,,,Busca al Oráculo y pregúntale sobre las otras piezas del Emblema. Ve al médico y al entrenador de armas para salud y entrenamiento.,,Etsi Oraakkeli ja kysy häneltä muista Sinetin osista. Vastaanota palkkiosi ja käy lääkintämiehen ja asekouluttajan luona terveydenhoitoa ja koulutusta varten.,"Trouve l'Oracle et demande lui où se trouve les autres pièces du Sigil. Récupère ta récompense, et va voir le médecin et le maître d'armes pour te soigner et t'entraîner.","Kutasd fel az Orákulumot, és érdeklődj a Pecsét további darabjairól. Zsebeld be a jutalmad, és költsd is el szépen a szanitécnál és a fegyvermesternél.",Raggiungi l'Oracolo e chiedigli degli altri pezzi del Sigillo. Prendi la tua ricompensa e visita il dottore e l'addestratore di armi.,"オラクルに会いシジルの欠片について尋ねる。 +強化のためメディックと武器トレーナーに会っておく。",오라클을 찾아서 다른 시질 조각이 어디에 있는지 물어봐. 보상을 받고 치료와 훈련을 위해 의무관과 무기 담당관에게로 가.,Zoek het Orakel op en vraag het over de andere Sigil stukken. Pak je beloning en ga naar de dokter en wapentrainer voor gezondheid en training.,Oppsøk oraklet og spør det om de andre sigil-brikke. Ta belønningen din og gå over til medisineren og våpentreneren for helse og trening.,Poszukaj Wyroczni i zapytaj ją o pozostałe kawałki Sigila. Odbierz nagrodę i przejdź do medyka i trenera broni po zdrowie i trening.,Procure o Oráculo e pergunte o sobre as outras peças do Sigilo. Pegue a sua recompensa e visite o médico e o treinador de armas para recuperar saúde e receber treinamento.,,Caută Oracolul și întreabă de celelalte piese de Sigiliu. Ia-ți recompensa și du-te la medic și antrenorul de arme.,Найди Оракула и спроси у него про другие фрагменты Печати. Возьми свою награду и посети медика и инструктора по стрельбе.,,Sök upp Oraklet och fråga det om de andra Sigilbitarna. Ta din belöning och gå över till läkaren och vapentränaren för hälsa och träning.,Kahin'i bulun ve ona diğer Sigil parçalarını sorun. Ödülünüzü alın ve sağlık ve eğitim için sıhhiyeciye ve silah eğitmenine gidin. +"The second piece lies at the heart of the crimson and obsidian tower. There you must find the Bishop, who awaits you. Take the Oracle's token to the key master in the borderlands. Once you have destroyed the Bishop, return to the Oracle.",TXT_ILOG1020,,,,"Druhý díl leží v srdci věže karmíno-obsidiánové. Tam musíš najít Biskupa, který tě očekává. Vezmi Věštcův pas ke klíčníkovi v pohraničí. Až zabiješ Biskupa, vrať se k Věštci.","Den anden brik ligger i hjertet af det purpurfarvede og obsidianske tårn. Der skal du finde biskoppen, som venter på dig. Tag Oraklets token til nøglemesteren i grænselandet. Når du har udslettet biskoppen, skal du vende tilbage til Oraklet.","Das zweite Teilstück befindet sich im Turm aus Purpur und Obsidian. Dort musst du den Bischof finden, der dich erwartet. Bringe das Symbol des Orakels zum Schlüsselmeister in den Grenzgebieten. Wenn der Bischof ausgeschaltet ist, kehre zum Orakel zurück.",,,"La segunda pieza se encuentra en el corazón e la torre carmesí y obsidiana. Ahí debes encontrar al Obispo, quien espera por ti. Lleva el vale del Oráculo al amo de llaves en las fronteras. En cuanto hayas destruido al Obispo, regresa con el Oráculo.","La segunda pieza está en el corazón de la torre carmesí y obsidiana. Ahí deberás encontrar al Obispo, que te está esperando. Lleva el símbolo del Oráculo al Amo de Llaves en las fronteras. Cuando hayas destruido al Obispo, regresa con el Oráculo.","Toinen osanen piilee purppuranpunaisen laavalasisen tornin sydämessä. Sieltä sinun on löydettävä Piispa, joka odottaa sinua. Toimita Oraakkelin merkki avainmestarille rajaseudulla. Tuhottuasi Piispan palaa Oraakkelin luokse.","La deuxième pièce se trouve au cœur de la tour d'obsidienne et d'écarlate. Tu y trouveras l'évêque, qui t'attend. Amène le jeton de l'Oracle au maître des clés dans les terrains vagues. Quand tu as tué l'évêque, retourne voir l'Oracle.","A második darab a karmazsin és obszidián torony szívében található. Ott fogsz találkozni a már rád váró Püspökre. Vidd az Orákulum zálogát a peremvidéken élő kulcsmesterhez. Amint megölted a Püspököt, irány vissza az orákulumhoz.","Il secondo pezzo si trova nel cuore della torre cremisina e ossidiana. Lì troverai il Vescovo, che ti sta aspettando. Raggiungi il mastro delle chiavi nelle terre di confine. Quando hai distrutto il Vescovo, ritorna dall'Oracolo.","二つ目の欠片は深紅と黒曜石の塔の中心部にある。そこのビショップを討伐せよ。 国境地帯のコモンズ側にいるキーマスターにオラクルのトークンを見せる。 -ビショップを仕留めたらオラクルの元に戻る。","두 번째 시질 조각은 진홍빛 흑요석 탑에 숨어있는 비숍에게 있어. 거기에서 너를 기다리고 있는 비숍을 찾아내야만 해. 오라클의 통행증을 들고 접경지 안의 열쇠지기에게로 가봐. 비숍을 파괴했다면, 오라클에게 돌아가.","Het tweede stuk ligt in het hart van de karmozijnrode en obsidiaan toren. Daar moet je de bisschop vinden, die op je wacht. Breng de orakels naar de belangrijkste meester in de grensgebieden. Als je de bisschop hebt vernietigd, keer je terug naar het Orakel.",,"A segunda peça está no coração da torre carmesim e obsidiana. Lá você encontrará o Bispo, que está te aguardando. Leve o emblema do Oráculo para o mestre das chaves nas fronteiras. Após destruir o Bispo, volte ao Oráculo.",,,"Второй фрагмент лежит в сердце багрово-обсидиановой башни. Там ты встретишь Епископа, который ожидает тебя. Отнеси жетон Оракула ключнику в пограничье. Когда уничтожишь Епископа, возвращайся к Оракулу.", -"Find the crimson and obsidian tower. Use the id key the key master gave you to enter the tower. Once inside you must locate the Bishop. Once you have destroyed the Bishop, return to the Oracle.",TXT_ILOG1021,,,,"Najdi karmíno-obsidiánovou věž. Použij legitimaci, kterou ti dal klíčník, pro vstup do věže. Uvnitř musíš najít Biskupa. Až zabiješ Biskupa, vrať se k Věštci.","Finde den Turm aus Purpur und Obsidian. Benutze den Schlüssel des Schlüsselmeisters um in den Turm hereinzukommen. In seinem Inneren musst du den Bischof finden. Wenn er ausgeschaltet ist, kehre zum Orakel zurück.",,,"Encuentra la torre carmesí y obsidiana. Usa la llabe que te dio el amo de llaves para entrar en la torre. Una vez dentro debes localizar al Obispo. Una vez hayas destruido al Obispo, regresa con el Oráculo.","Encuentra la torre carmesí y obsidiana. Usa la llave que te dio el Amo de Llaves para entrar en la torre. Una vez adentro localiza al Obispo. Una vez destruido el Obispo, regresa con el Oráculo.",,"Trouve la tour d'obsidienne et d'écarlate. Utilise la carte magnétique que le maître des clés t'a donnée pour y entrer. A l'intérieur, trouve et tue l'évêque, puis retourne à l'Oracle.",,,"二つ目の欠片は深紅と黒曜石の塔の中心部にある。そこのビショップを討伐せよ。 +ビショップを仕留めたらオラクルの元に戻る。","두 번째 시질 조각은 진홍빛 흑요석 탑에 숨어있는 비숍에게 있어. 거기에서 너를 기다리고 있는 비숍을 찾아내야만 해. 오라클의 통행증을 들고 접경지 안의 열쇠지기에게로 가봐. 비숍을 파괴했다면, 오라클에게 돌아가.","Het tweede stuk ligt in het hart van de karmozijnrode en obsidiaan toren. Daar moet je de bisschop vinden, die op je wacht. Breng de orakels naar de belangrijkste meester in de grensgebieden. Als je de bisschop hebt vernietigd, keer je terug naar het Orakel.","Den andre brikken ligger i hjertet av det purpurfargede og obsidianske tårnet. Der må du finne biskopen, som venter på deg. Ta orakelets symbol til nøkkelmesteren i grenselandene. Når du har tilintetgjort biskopen, gå tilbake til oraklet.","Drugi kawałek leży w sercu karmazynowej i obsydianowej wieży. Musisz tam odnaleźć biskupa, który czeka na Ciebie. Zabierz żeton wyroczni do mistrza kluczy na pograniczu. Po zniszczeniu Biskupa wróć do Wyroczni.","A segunda peça está no coração da torre carmesim e obsidiana. Lá você encontrará o Bispo, que está te aguardando. Leve o emblema do Oráculo para o mestre das chaves nas fronteiras. Após destruir o Bispo, volte ao Oráculo.",,A doua piesă e în inima turnului stăveziu din obsidian. Episcopul te va aștepta. Ia semnul Oracolului la stăpânul cheii în mărginime. După ce ai eliminat Episcopul întoarce-te la Oracol.,"Второй фрагмент лежит в сердце багрово-обсидиановой башни. Там ты встретишь Епископа, который ожидает тебя. Отнеси жетон Оракула ключнику в пограничье. Когда уничтожишь Епископа, возвращайся к Оракулу.",,Den andra biten finns i hjärtat av det karmosinröda och obsidianiska tornet. Där måste du hitta biskopen som väntar på dig. Ta Orakelns token till nyckelmästaren i gränslandet. När du har förintat biskopen ska du återvända till oraklet.,İkinci parça kızıl ve obsidyen kulenin kalbinde yatıyor. Orada sizi bekleyen Piskopos'u bulmalısınız. Kahin'in jetonunu sınır bölgelerindeki anahtar ustasına götürün. Piskoposu yok ettikten sonra Kahin'e geri dönün. +"Find the crimson and obsidian tower. Use the id key the key master gave you to enter the tower. Once inside you must locate the Bishop. Once you have destroyed the Bishop, return to the Oracle.",TXT_ILOG1021,MAP11: After getting the Military ID from the keymaster.,,,"Najdi karmíno-obsidiánovou věž. Použij legitimaci, kterou ti dal klíčník, pro vstup do věže. Uvnitř musíš najít Biskupa. Až zabiješ Biskupa, vrať se k Věštci.","Find det purpurfarvede og obsidianske tårn. Brug den id-nøgle, som nøglemesteren gav dig, til at komme ind i tårnet. Når du er inde, skal du finde biskoppen. Når du har ødelagt biskoppen, skal du vende tilbage til Oracle.","Finde den Turm aus Purpur und Obsidian. Benutze den Schlüssel des Schlüsselmeisters um in den Turm hereinzukommen. In seinem Inneren musst du den Bischof finden. Wenn er ausgeschaltet ist, kehre zum Orakel zurück.",,,"Encuentra la torre carmesí y obsidiana. Usa la llabe que te dio el amo de llaves para entrar en la torre. Una vez dentro debes localizar al Obispo. Una vez hayas destruido al Obispo, regresa con el Oráculo.","Encuentra la torre carmesí y obsidiana. Usa la llave que te dio el Amo de Llaves para entrar en la torre. Una vez adentro localiza al Obispo. Una vez destruido el Obispo, regresa con el Oráculo.",Löydä purppuranpunainen laavalasinen torni. Käytä avainmestarin luovuttamaa tunnusta päästäksesi torniin. Sisään päästyäsi sinun on paikallistettava Piispa. Tuhottuasi hänet palaa Oraakkelin luokse.,"Trouve la tour d'obsidienne et d'écarlate. Utilise la carte magnétique que le maître des clés t'a donnée pour y entrer. A l'intérieur, trouve et tue l'évêque, puis retourne à l'Oracle.","Keresd fel a karamzsin és obszidián tornyot. A bejutáshoz használd az igazolványt amit a kulcsmester adott. Ha bejutottál, kutasd fel a Püspököt. Ha kiiktattad a Püspököt, menj vissza az Orákulumhoz.","Trova la torre cremisina e ossidiana. Con la chiave che ti ha dato il mastro delle chiavi, entra nella torre. Quando sei dentro, devi trovare il Vescovo. Dopo averlo distrutto, ritorna dall'Oracolo.","二つ目の欠片は深紅と黒曜石の塔の中心部にある。そこのビショップを討伐せよ。 キーマスターから貰ったIDキーを使って塔に入る。 -ビショップを仕留めたらオラクルの元に戻る。","진홍빛 흑요석 탑을 찾아. 열쇠지기가 준 신분증을 이용해서 탑으로 들어가. 탑 안으로 들어가서 비숍을 찾아야 해. 비숍을 파괴했다면, 오라클에게 돌아가.","Vind de karmozijnrode en obsidiaan toren. Gebruik de id-toets die de sleutelmeester je gaf om de toren te betreden. Eenmaal binnen moet je de bisschop lokaliseren. Als je de bisschop hebt vernietigd, ga je terug naar het Orakel.",,"Encontre a torre carmesim e obsidiana. Use a chave de identificação que o mestre da chaves te deu para entrar na torre. Após entrar, você deve localizar o Bispo. Após destruir o Bispo, volte ao Oráculo.",,,"Найди багрово-обсидиановую башню. Используй пропуск, полученный у ключника, чтобы войти внутрь. Там ты должен найти Епископа. Когда уничтожишь его, возвращайся к Оракулу.", -"Find the security complex, fight through there and use the teleporter to central administration. Destroy the computer core in central administration. This will kill the force field on the Bishop's tower. Once the Bishop's dead, return to the Oracle.",TXT_ILOG1022,,,,"Najdi bezpečnostní komplex, probij se skrz a použij teleportér do ústřední administrace. Znič počítačové jádro v ústřední administraci. To zničí silové pole v Biskupově věži. Až zabiješ Biskupa, vrať se k Věštci.","Finde den Sicherheitskomplex, kämpfe dich durch und benutze den Teleporter zur Zentralverwaltung. Zerstöre den Computer in der Verwaltung. Das wird alle Kraftfelder am Turm des Bischofs ausschalten. Wenn der Bischof ausgeschaltet ist, kehre zum Orakel zurück.",,,"Encuentra el complejo de seguridad, pelea a través de ahí y usa el teletransporte a administración central. Destruye el núcleo de la computadora en administración central. Esto apagará el campo de fuerza en la torre del Obispo. En cuanto el Obispo esté muerto, regresa con el Oráculo.","Encuentra el complejo de seguridad, pelea através de ahí y usa el teleporte a la Central de Administración. Destruye el núcleo en la Central de Administración. Esto desactivará el campo de fuerza en la torre del Obispo. Una vez que el Obispo esté muerto, regresa con el Oráculo.",,"Trouve le complexe de sécurité. Bats-toi pour atteindre le téléporteur vers le centre d'administration. Détruis le cœur informatique qui s'y trouve. Cela désactivera le chap de force de la tour de l'évêque. Un fois qu'il est mort, retourne voir l'Oracle.",,,"複合警備所を見つけ、そこを制圧し中央管理所へのテレポーターを使う。 +ビショップを仕留めたらオラクルの元に戻る。","진홍빛 흑요석 탑을 찾아. 열쇠지기가 준 신분증을 이용해서 탑으로 들어가. 탑 안으로 들어가서 비숍을 찾아야 해. 비숍을 파괴했다면, 오라클에게 돌아가.","Vind de karmozijnrode en obsidiaan toren. Gebruik de id-toets die de sleutelmeester je gaf om de toren te betreden. Eenmaal binnen moet je de bisschop lokaliseren. Als je de bisschop hebt vernietigd, ga je terug naar het Orakel.","Finn det purpurfargede og obsidianske tårnet. Bruk id-nøkkelen nøkkelmesteren ga deg for å komme inn i tårnet. Når du er inne, må du finne biskopen. Når du har ødelagt biskopen, gå tilbake til oraklet.","Znajdź wieżę z karmazynu i obsydianu. Użyj klucza id, który dał ci mistrz kluczy, aby wejść do wieży. Po wejściu do środka musisz zlokalizować Bishopa. Po zniszczeniu Bishopa wróć do Oracle.","Encontre a torre carmesim e obsidiana. Use a chave de identificação que o mestre da chaves te deu para entrar na torre. Após entrar, você deve localizar o Bispo. Após destruir o Bispo, volte ao Oráculo.",,"Găsește turnul străveziu din obsidian. Folosește cardul pe care ți l-a dat stăpânul cheilor pentru a intra. După aceea, găsește-l pe Episcop. Odată ce l-ai distrus, întoarce-te la Oracol.","Найди багрово-обсидиановую башню. Используй пропуск, полученный у ключника, чтобы войти внутрь. Там ты должен найти Епископа. Когда уничтожишь его, возвращайся к Оракулу.",,Hitta det karmosinröda och obsidianska tornet. Använd id-nyckeln som nyckelmästaren gav dig för att komma in i tornet. När du väl är inne måste du lokalisera biskopen. När du har förstört biskopen återvänder du till oraklet.,Kızıl ve obsidyen kuleyi bulun. Kuleye girmek için anahtar ustasının size verdiği kimlik anahtarını kullanın. İçeri girdikten sonra Piskoposu bulmalısınız. Piskoposu yok ettikten sonra Kahin'e geri dönün. +"Find the security complex, fight through there and use the teleporter to central administration. Destroy the computer core in central administration. This will kill the force field on the Bishop's tower. Once the Bishop's dead, return to the Oracle.",TXT_ILOG1022,MAP17: After talking to Quincy.,,,"Najdi bezpečnostní komplex, probij se skrz a použij teleportér do ústřední administrace. Znič počítačové jádro v ústřední administraci. To zničí silové pole v Biskupově věži. Až zabiješ Biskupa, vrať se k Věštci.","Find sikkerhedskomplekset, kæmp dig igennem der og brug teleporteren til centraladministrationen. Ødelæg computerkernen i centraladministrationen. Dette vil dræbe kraftfeltet på Bishop's tårn. Når biskoppen er død, skal du vende tilbage til Oracle.","Finde den Sicherheitskomplex, kämpfe dich durch und benutze den Teleporter zur Zentralverwaltung. Zerstöre den Computer in der Verwaltung. Das wird alle Kraftfelder am Turm des Bischofs ausschalten. Wenn der Bischof ausgeschaltet ist, kehre zum Orakel zurück.",,,"Encuentra el complejo de seguridad, pelea a través de ahí y usa el teletransporte a administración central. Destruye el núcleo de la computadora en administración central. Esto apagará el campo de fuerza en la torre del Obispo. En cuanto el Obispo esté muerto, regresa con el Oráculo.",,"Löydä turvallisuuskeskus, taistele sen läpi ja kulje kaukosiirtimellä keskushallintoon. Tuhoa siellä keskustietokone. Se sammuttaa Piispan tornin voimakentän. Kun Piispa on kuollut, palaa Oraakkelin luo.","Trouve le complexe de sécurité. Bats-toi pour atteindre le téléporteur vers le centre d'administration. Détruis le cœur informatique qui s'y trouve. Cela désactivera le chap de force de la tour de l'évêque. Un fois qu'il est mort, retourne voir l'Oracle.","Keresd meg a biztonsági központot, harcold magad keresztül rajta, és használd a teleportot a központi adminisztrációhoz. Semmisítsd meg a számítógép magot a központi adminisztrációnál. Ez majd deaktiválja a Püspök tornyának az erőpajzsát. Ha meghalt a Püspök térj vissza az Orákulumhoz.","Trova il complesso di sicurezza, elimina chiunque ti sbarri la strada e trova il teletrasporto per l'amministrazione centrale. Distruggi il nucleo del computer nell'amministrazione centrale. Questo disattiverà il campo di forza nella torre del Vescovo. Quando il Vescovo sarà morto, ritorna dall'Oracolo.","複合警備所を見つけ、そこを制圧し中央管理所へのテレポーターを使う。 そして管理所のコンピューターコアを破壊する。 そうすればビショップの塔へのフォースフィールドを消せる。 -ビショップを仕留めたらオラクルの元に戻る。","보안 담당 기지를 찾고, 경비와 싸워가면서 중앙 처리 본부로 향하는 텔레포터를 사용해. 그곳에서 컴퓨터 중심부를 파괴해. 그러면 비숍의 탑의 보호막을 끌 수 있을 거야. 비숍을 죽이면, 오라클에게 돌아가.","Vind het veiligheidscomplex, vecht daar doorheen en gebruik de teleporter om de centrale administratie te besturen. Vernietig de computerkern in de centrale administratie. Dit zal het krachtveld op de Bisschopstoren doden. Zodra de bisschop dood is, keer je terug naar het Orakel.",,"Encontre o complexo de segurança, lute através de lá e use o teletransportador na administração central. Destrua o núcleo de computação na administração central. Isso vai derrubar o campo de força na torre do Bispo. Após matar o Bispo, volte ao Oráculo.",,,"Найди охранный комлекс, пробейся внутрь и используй телепорт до центральной администрации. Уничтожь компьютер. Это должно отключить силовое поле башни Епископа. Когда убьёшь Епископа, возвращайся к Оракулу.", -Your next challenge will test your spirit. The third piece is held by your own leader. He is the same as that which he sends you to kill. Confront him and resolve your fate.,TXT_ILOG1023,,,,"Tvá další výzva pokusí tvou vůli. Třetí díl je držen tvým vlastním vůdcem. Je stejný, jako ti, které tě posílá zabít. Postav se mu a rozhodni svůj osud.","Die nächste Herausforderung wird deinen Geist prüfen. Das dritte Teilstück wird von deinem eigenen Anführer, Macil, gehalten. Er ist das Gleiche, was er dich töten lässt. Konfrontiere ihn und kläre dein Schicksal.",,,Tu siguiente desafío pondrá a prueba tu espíritu. La tercera pieza está en manos de tu propio líder. Él es lo mismo que te envía a matar. Confróntalo y resuelve tu destino.,Tú siguiente desafío probará tú espíritu. La tercera pieza la tiene tú propio líder. Él es igual que aquello que te envía a matar. Confróntalo y resuelve tú destino.,,Le prochain défi testera votre esprit. Le troisième fragment est possédé par votre leader. Il est le même que celui qu'il vous a envoyé tuer. Confrontez-le et faites face à votre destinée.,,,"次の挑戦は己の精神が試される。三つ目の欠片は我々のリーダーが保持している。 -彼は貴方を殺すために送ったのと同等だと。彼に立ち向かい、己の運命を決断せよ。",다음 도전은 너의 정신을 시험할 거야. 세 번째 조각은 바로 우리의 지도자가 가지고 있어. 그는 너를 시켜서 죽였던 괴물들과 마찬가지인 존재지.,Je volgende uitdaging zal je geest testen. Het derde stuk wordt vastgehouden door je eigen leider. Hij is dezelfde die hij je stuurt om te doden. Confronteer hem en los je lot op.,,Seu próximo desafio testará o seu espírito. A terceira peça está com o seu próprio líder. Ele é a mesma pessoa que ele quer que você mate. Confronte-o e resolva o seu destino.,,,"Следующее задание испытает силу твоего духа. Третий фрагмент у вашего лидера. Он сам — один из тех, кого вы убиваете по его приказу. Сразись с ним и исполни своё предназначение.", -"It is the Oracle who holds the third piece. There's your traitor. Return to the Oracle, and take him down. Return to me when it's dead.",TXT_ILOG1024,,,,"Věštec je ten, kdo má u sebe třetí díl. On je ten zrádce. Vrať se k němu a zabij ho. Vrať se ke mě, až bude mrtvý.","Es ist das Orakel, das das dritte Teilstück besitzt. Es ist der Verräter. Kehre zu ihm zurück und schalte es aus. Kehre zurück, wenn es tot ist.",,,Es el Oráculo quien tiene la tercera pieza. Ahí está tu traidor. Regresa al Oráculo y acaba con él. Regresa a mí cuando esté muerto.,Es el Oráculo el que tiene la tercera pieza. Ahí está tú traidor. Regresa con el Oráculo y acaba con él. Regresa a mí cuando esté muerto.,,"C'est l'Oracle qui détient la troisième pièce, est c'est lui qui est le traître. Retourne le voir et détruis-le. Retourne à la base quand il est mort.",,,"三つ目の欠片を持つのはオラクルだ。あいつが裏切者だ。 -オラクルの所に戻り討ち倒せ。終わったらマシルの元に戻る。",오라클이 세 번째 조각을 가지고 있어. 그가 배신자야! 오라클을 찾아서 혼쭐을 낸 뒤 마실에게 돌아와.,"Het is het Orakel dat het derde deel vasthoudt. Daar is je verrader. Ga terug naar het Orakel, en neem hem mee naar beneden. Keer terug naar mij als het dood is.",,É o Oráculo que possui a terceira peça. Esse é o seu traidor. Volte ao Oráculo e elimine-o. Volte para mim quando ele estiver morto.,,,Третий фрагмент хранится у Оракула. Так и кто же из нас предатель? Вернись к Оракулу и убей его. Доложи мне о его смерть., -"You have cut the cancer from your body, but your heart still beats. Next you must find the surgeon who butchers and controls your people.... The Loremaster. Stop him, and the next piece will be yours.",TXT_ILOG1025,,,,"Vyřízl jsi rakovinu ze svého těla, tvé srdce však stále bije. Dále musíš najít doktora, jenž vraždí a ovládá tvé druhy, Dějepisce. Učiň mu přítrž a další díl bude tvůj.","Du hast das Geschwür aus deinem Körper entferrnt, aber dein Herz schlägt noch. Als Nächstes musst du den Wissensmeister finden, der deine Leute kontrolliert und abschlachtet. Stoppe ihn und das nächste Teilstück ist Dein.",,,"Has cortado el cáncer de tu cuerpo, pero tu corazón aún late. Ahora debes encontrar al cirujano que destroza y controla a tu gente... El Maestro del Conocimiento. Detenlo, y la siguiente pieza será tuya.","Haz cortado el cáncer de tu cuerpo, pero tú corazón todavía late. Ahora debes encontrar al cirujano que encarniza y controla a tú gente... El Maestro del Conocimiento. Deténlo y la siguiente pieza será tuya.",,"Vous avez arraché le cancer de votre corps, mais le cœur bat encore. Vous devez maintenant trouver le chirurgien qui massacre votre peuple, le Maître des traditions. Arrètez-le, et le fragment suivant sera le vôtre.",,,"己の癌は切除したが動揺は隠せないままだ。 +ビショップを仕留めたらオラクルの元に戻る。","보안 담당 기지를 찾고, 경비와 싸워가면서 중앙 처리 본부로 향하는 텔레포터를 사용해. 그곳에서 컴퓨터 중심부를 파괴해. 그러면 비숍의 탑의 보호막을 끌 수 있을 거야. 비숍을 죽이면, 오라클에게 돌아가.","Vind het veiligheidscomplex, vecht daar doorheen en gebruik de teleporter om de centrale administratie te besturen. Vernietig de computerkern in de centrale administratie. Dit zal het krachtveld op de Bisschopstoren doden. Zodra de bisschop dood is, keer je terug naar het Orakel.","Finn sikkerhetskomplekset, kjemp deg gjennom der og bruk teleporteren til sentraladministrasjonen. Ødelegg datakjernen i sentraladministrasjonen. Dette vil drepe kraftfeltet på biskopens tårn. Når biskopen er død, gå tilbake til Orakelet.","Znajdź kompleks bezpieczeństwa, walcz tam i użyj teleportera do centralnej administracji. Zniszcz rdzeń komputera w centralnej administracji. To zabije pole siłowe na wieży Bishopa. Gdy Bishop będzie już martwy, wróć do Oracle.","Encontre o complexo de segurança, lute através de lá e use o teletransportador na administração central. Destrua o núcleo de computação na administração central. Isso vai derrubar o campo de força na torre do Bispo. Após matar o Bispo, volte ao Oráculo.",,"Găsește complexul de securitate, intră în luptă, și folosește teleportorul către administrația centrală. Distruge nucleul calculatorului. Asta va distruge scutul din turnul Episcopului. Odată ce e mort, întoarce-te la Oracol.","Найди охранный комлекс, пробейся внутрь и используй телепорт до центральной администрации. Уничтожь компьютер. Это должно отключить силовое поле башни Епископа. Когда убьёшь Епископа, возвращайся к Оракулу.",,"Hitta säkerhetskomplexet, kämpa dig igenom där och använd teleportern till centraladministrationen. Förstör datorkärnan i centralförvaltningen. Detta kommer att döda kraftfältet på biskopens torn. När biskopen är död återvänder du till oraklet.","Güvenlik kompleksini bulun, orada savaşın ve merkezi yönetime giden ışınlayıcıyı kullanın. Merkezi yönetimdeki bilgisayar çekirdeğini yok edin. Bu, Piskopos'un kulesindeki güç alanını öldürecektir. Piskopos öldükten sonra Kahin'e geri dönün." +Your next challenge will test your spirit. The third piece is held by your own leader. He is the same as that which he sends you to kill. Confront him and resolve your fate.,TXT_ILOG1023,,,,"Tvá další výzva pokusí tvou vůli. Třetí díl je držen tvým vlastním vůdcem. Je stejný, jako ti, které tě posílá zabít. Postav se mu a rozhodni svůj osud.","Din næste udfordring vil teste din ånd. Den tredje brik holdes af din egen leder. Han er den samme som den, som han sender dig til at dræbe. Konfronter ham og løser din skæbne.","Die nächste Herausforderung wird deinen Geist prüfen. Das dritte Teilstück wird von deinem eigenen Anführer, Macil, gehalten. Er ist das Gleiche, was er dich töten lässt. Konfrontiere ihn und kläre dein Schicksal.",,,Tu siguiente desafío pondrá a prueba tu espíritu. La tercera pieza está en manos de tu propio líder. Él es lo mismo que te envía a matar. Confróntalo y resuelve tu destino.,Tú siguiente desafío probará tú espíritu. La tercera pieza la tiene tú propio líder. Él es igual que aquello que te envía a matar. Confróntalo y resuelve tú destino.,"Seuraava haasteesi koettelee sinua henkisesti. Kolmatta osasta pitää hallussaan oma päämiehesi. Hän on sama kuin se, jonka hän lähettää sinut surmaamaan. Kohtaa hänet ja päätä kohtalosi.",Le prochain défi testera votre esprit. Le troisième fragment est possédé par votre leader. Il est le même que celui qu'il vous a envoyé tuer. Confrontez-le et faites face à votre destinée.,"A következő próbatétel próbára teszi a lelkedet. A harmadik darab a saját vezérednél található. Egy és ugyanazon személy akit meg akar öletni veled. Szembesítsd vele, és dönts a sorsod felett.",La tua prossima sfida metterà alla prova il tuo spirito. Il terzo frammento è posseduto dal tuo stesso capo. Lui è uguale a quelli che ti manda ad uccidere. Affrontalo e risolvi il tuo destino.,"次の挑戦は己の精神が試される。三つ目の欠片は我々のリーダーが保持している。 +彼は貴方を殺すために送ったのと同等だと。彼に立ち向かい、己の運命を決断せよ。",다음 도전은 너의 정신을 시험할 거야. 세 번째 조각은 바로 우리의 지도자가 가지고 있어. 그는 너를 시켜서 죽였던 괴물들과 마찬가지인 존재지.,Je volgende uitdaging zal je geest testen. Het derde stuk wordt vastgehouden door je eigen leider. Hij is dezelfde die hij je stuurt om te doden. Confronteer hem en los je lot op.,Din neste utfordring vil sette din ånd på prøve. Den tredje brikken holdes av din egen leder. Han er den samme som han sender deg for å drepe. Konfronter ham og avgjør skjebnen din.,"Twoje kolejne wyzwanie przetestuje twojego ducha. Trzeci element jest w posiadaniu twojego własnego przywódcy. Jest on taki sam jak ten, którego wysyła do zabicia. Zmierz się z nim i rozstrzygnij swój los.",Seu próximo desafio testará o seu espírito. A terceira peça está com o seu próprio líder. Ele é a mesma pessoa que ele quer que você mate. Confronte-o e resolva o seu destino.,,Următoarea provocare îți va testa spiritul. A treia pieșă e ținută de propriul vostru lider. E același ca cel care vă trimite să ucideți. Înfruntă-l și împlinește-ți destinul.,"Следующее задание испытает силу твоего духа. Третий фрагмент у вашего лидера. Он сам — один из тех, кого вы убиваете по его приказу. Сразись с ним и исполни своё предназначение.",,Din nästa utmaning kommer att sätta din anda på prov. Den tredje biten innehas av din egen ledare. Han är densamma som den som han skickar dig att döda. Konfrontera honom och lös ditt öde.,Bir sonraki göreviniz ruhunuzu sınayacak. Üçüncü parça kendi lideriniz tarafından tutuluyor. Sizi öldürmeniz için gönderdiği kişiyle aynı. Onunla yüzleşin ve kaderinizi belirleyin. +"It is the Oracle who holds the third piece. There's your traitor. Return to the Oracle, and take him down. Return to me when it's dead.",TXT_ILOG1024,MAP10: You chose to kill the Oracle.,,,"Věštec je ten, kdo má u sebe třetí díl. On je ten zrádce. Vrať se k němu a zabij ho. Vrať se ke mě, až bude mrtvý.","Det er Oraklet, der har den tredje brik. Der er din forræder. Vend tilbage til Oraklet, og nedlæg ham. Vend tilbage til mig, når det er dødt.","Es ist das Orakel, das das dritte Teilstück besitzt. Es ist der Verräter. Kehre zu ihm zurück und schalte es aus. Kehre zurück, wenn es tot ist.",,,Es el Oráculo quien tiene la tercera pieza. Ahí está tu traidor. Regresa al Oráculo y acaba con él. Regresa a mí cuando esté muerto.,,Kolmas osanen on Oraakkelin hallussa. Siinä on petturisi. Palaa Oraakkelin luo ja poista hänet päiväjärjestyksestä. Palaa luokseni hänen kuoltuaan.,"C'est l'Oracle qui détient la troisième pièce, est c'est lui qui est le traître. Retourne le voir et détruis-le. Retourne à la base quand il est mort.","Az Orákulumnál található a harmadik darab. Ő lesz az árulód. Térj vissza az Orákulumhoz, és tedd el láb alól. Ha megtörtént, gyere vissza.","È l'Oracolo che tiene il terzo pezzo. Ecco chi è il traditore. Ritorna dall'Oracolo, e fallo fuori. Ritorna da me quando lo hai ucciso.","三つ目の欠片を持つのはオラクルだ。あいつが裏切者だ。 +オラクルの所に戻り討ち倒せ。終わったらマシルの元に戻る。",오라클이 세 번째 조각을 가지고 있어. 그가 배신자야! 오라클을 찾아서 혼쭐을 낸 뒤 마실에게 돌아와.,"Het is het Orakel dat het derde deel vasthoudt. Daar is je verrader. Ga terug naar het Orakel, en neem hem mee naar beneden. Keer terug naar mij als het dood is.",Det er oraklet som har den tredje brikken. Der er forræderen din. Gå tilbake til oraklet og drep ham. Kom tilbake til meg når den er død.,"To Wyrocznia jest w posiadaniu trzeciego kawałka. Oto twój zdrajca. Wróć do Wyroczni i załatw go. Wróć do mnie, gdy będzie martwy.",É o Oráculo que possui a terceira peça. Esse é o seu traidor. Volte ao Oráculo e elimine-o. Volte para mim quando ele estiver morto.,,"E Oracolul cel care deține ultima piesă. Acolo e trădătorul. Întoarce-te la Oracol, și răpune-l. Întoarce-te la mine când ai terminat.",Третий фрагмент хранится у Оракула. Так и кто же из нас предатель? Вернись к Оракулу и расправься с ним. Доложи мне о его смерть.,,Det är oraklet som innehar den tredje biten. Där har du din förrädare. Återvänd till Oraklet och ta ner honom. Återvänd till mig när den är död.,Üçüncü parçayı elinde tutan Kahin. İşte haininiz. Kahin'e dön ve onu indir. Öldüğünde bana geri dön. +"You have cut the cancer from your body, but your heart still beats. Next you must find the surgeon who butchers and controls your people.... The Loremaster. Stop him, and the next piece will be yours.",TXT_ILOG1025,,,,"Vyřízl jsi rakovinu ze svého těla, tvé srdce však stále bije. Dále musíš najít doktora, jenž vraždí a ovládá tvé druhy, Dějepisce. Učiň mu přítrž a další díl bude tvůj.","Du har fjernet kræften fra din krop, men dit hjerte slår stadig. Nu skal du finde den kirurg, der slagter og kontrollerer dit folk.... Loremesteren. Stop ham, og det næste stykke vil blive dit.","Du hast das Geschwür aus deinem Körper entferrnt, aber dein Herz schlägt noch. Als Nächstes musst du den Wissensmeister finden, der deine Leute kontrolliert und abschlachtet. Stoppe ihn und das nächste Teilstück ist Dein.",,,"Has cortado el cáncer de tu cuerpo, pero tu corazón aún late. Ahora debes encontrar al cirujano que destroza y controla a tu gente... El Maestro del Conocimiento. Detenlo, y la siguiente pieza será tuya.","Haz cortado el cáncer de tu cuerpo, pero tú corazón todavía late. Ahora debes encontrar al cirujano que encarniza y controla a tú gente... El Maestro del Conocimiento. Deténlo y la siguiente pieza será tuya.","Olet erottanut syövän ruumiistasi, mutta sydämesi silti sykkii. Seuraavaksi pitää sinun löytämän kirugin, joka teurastaa ja hallitsee kansaasi: Oppi-Isän. Pysäytä hänet, ja seuraava osanen on oleva sinun.","Vous avez arraché le cancer de votre corps, mais le cœur bat encore. Vous devez maintenant trouver le chirurgien qui massacre votre peuple, le Maître des traditions. Arrètez-le, et le fragment suivant sera le vôtre.","Kivágtad a rákos részt a szívedből, de az még mindig ver. A következő lépés, hogy felkutatod a sebészt aki lemészárolja és irányítja a néped...a Tanmestert. Állítsd meg , és a következő darab a tied.","Hai eliminato il cancro dal tuo corpo, ma il tuo cuore batte ancora. Adesso devi trovare il chirurgo che macella e controlla la tua gente, il Sapiente. Fermalo e il prossimo pezzo sarà tuo.","己の癌は切除したが動揺は隠せないままだ。 次の欠片は人々を虐殺で支配する外科医... -ロアマスターが所持している。奴を止め、欠片を自分の物にする。","네 몸 안의 암 덩어리를 잘라냈지만, 심장은 여전히 뛰고 있네. 다음은 우리를 향한 도살과 지배를 책임졌던 과학자, 로어마스터를 찾아내야 해. 그를 막아내면, 다음 조각을 얻을 수 있을 거야.","Je hebt de kanker uit je lichaam gesneden, maar je hart klopt nog steeds. Vervolgens moet je de chirurg vinden die je mensen afmaakt en controleert....... De Kennismeester. Stop hem, en het volgende stuk zal van jou zijn.",,"Você arrancou o câncer do seu corpo, mas seu coração ainda bate. Agora você deve encontrar o cirurgião que mutila e controla o seu povo... o Mestre do Conhecimento. Detenha-o e a próxima peça será sua.",,,"Ты вырезал опухоль из своего тела, но твоё сердце всё ещё бьётся. Теперь тебе предстоит найти вивисектора, который вскрывает твоих людей и управляет ими — Хранителя мудрости. Останови его, и следующий фрагмент твой.", -"Next you must find the surgeon who butchers and controls your people.... The Loremaster. Stop him, and the next piece will be yours. Use the teleporter I opened to reach him. When he's dead, use the same device to return to me.",TXT_ILOG1026,,,,"Vyřízl jsi rakovinu ze svého těla, tvé srdce však stále bije. Dále musíš najít doktora, jenž vraždí a ovládá tvé druhy, Dějepisce. Učiň mu přítrž a další díl bude tvůj. Použij teleportér, který jsem otevřel, aby ses k němu dostal. Když je mrtev, použij stejné zařízení k návratu ke mě.","Als Nächstes musst du den Wissensmeister finden, der deine Leute kontrolliert und abschlachtet. Stoppe ihn und das nächste Teilstück ist Dein. Benutze den Teleporter, den ich geöffnet habe, um zu ihm zu gelangen. Wenn er tot ist kehre auf dem gleichen Weg zurück.",,,"Ahora debes encontrar al cirujano que destroza y controla a tu gente... El Maestro del Conocimiento. Detenlo, y la siguiente pieza será tuya. Usa el teletransporte que he abierto para alcanzarlo. Cuando esté muerto, usa el mismo dispositivo para regresar a mí.","Ahora debes encontrar al cirujano que encarniza y controla a tú gente... El Maestro del Conocimiento. Deténlo y la siguiente pieza será tuya. Usa el teleporte que he abierto para alcanzarlo. Cuando esté muerto, usa el mismo dispositivo para regresar conmigo.",,"Vous devez maintenant trouver le chirurgien qui massacre votre peuple, le Maître des traditions. Arrètez-le, et le fragment suivant sera le vôtre. Utilisez le téléporter qui s'est ouvert pour l'atteindre. Quand il est mort, utilisez le même téléporteur pour retourner à l'Oracle.",,,"次の欠片は人々を虐殺で支配する外科医... +ロアマスターが所持している。奴を止め、欠片を自分の物にする。","네 몸 안의 암 덩어리를 잘라냈지만, 심장은 여전히 뛰고 있네. 다음은 우리를 향한 도살과 지배를 책임졌던 과학자, 로어마스터를 찾아내야 해. 그를 막아내면, 다음 조각을 얻을 수 있을 거야.","Je hebt de kanker uit je lichaam gesneden, maar je hart klopt nog steeds. Vervolgens moet je de chirurg vinden die je mensen afmaakt en controleert....... De Kennismeester. Stop hem, en het volgende stuk zal van jou zijn.","Du har fjernet kreften fra kroppen din, men hjertet ditt slår fortsatt. Nå må du finne kirurgen som slakter og kontrollerer folket ditt...... .... Loremesteren. Stopp ham, og det neste stykket blir ditt.","Wyciąłeś raka ze swojego ciała, ale twoje serce wciąż bije. Następnie musisz znaleźć chirurga, który rzeźbi i kontroluje twoich ludzi.... Loremaster. Powstrzymaj go, a następny kawałek będzie twój.","Você arrancou o câncer do seu corpo, mas seu coração ainda bate. Agora você deve encontrar o cirurgião que mutila e controla o seu povo... o Mestre do Conhecimento. Detenha-o e a próxima peça será sua.",,"Ai tăiat cancerul din corp, dar inima ta încă bate. Mai departe trebuie să găsești pe chirurgul care vă masacrează oamenii.... Maestrul Cunoștiințelor. Oprește-l, și următoarea piesă va fii a ta.","Ты вырезал опухоль из своего тела, но твоё сердце всё ещё бьётся. Теперь тебе предстоит найти вивисектора, который вскрывает твоих людей и управляет ими — Хранителя мудрости. Останови его, и следующий фрагмент твой.",,"Du har skurit bort cancern från din kropp, men ditt hjärta slår fortfarande. Nu måste du hitta kirurgen som slaktar och kontrollerar ditt folk.... Läromästaren. Stoppa honom och nästa del blir din.","Kanseri vücudundan attın ama kalbin hala atıyor. Şimdi insanlarını kesen ve kontrol eden cerrahı bulmalısın.... Loremaster. Onu durdurursan, bir sonraki parça senin olacak." +"Next you must find the surgeon who butchers and controls your people.... The Loremaster. Stop him, and the next piece will be yours. Use the teleporter I opened to reach him. When he's dead, use the same device to return to me.",TXT_ILOG1026,,,,"Vyřízl jsi rakovinu ze svého těla, tvé srdce však stále bije. Dále musíš najít doktora, jenž vraždí a ovládá tvé druhy, Dějepisce. Učiň mu přítrž a další díl bude tvůj. Použij teleportér, který jsem otevřel, aby ses k němu dostal. Když je mrtev, použij stejné zařízení k návratu ke mě.","Dernæst skal du finde den kirurg, der slagter og kontrollerer dit folk.... Loremesteren. Stop ham, og den næste del bliver din. Brug teleporteren, som jeg åbnede for at nå ham. Når han er død, skal du bruge den samme anordning til at vende tilbage til mig.","Als Nächstes musst du den Wissensmeister finden, der deine Leute kontrolliert und abschlachtet. Stoppe ihn und das nächste Teilstück ist Dein. Benutze den Teleporter, den ich geöffnet habe, um zu ihm zu gelangen. Wenn er tot ist kehre auf dem gleichen Weg zurück.",,,"Ahora debes encontrar al cirujano que destroza y controla a tu gente... El Maestro del Conocimiento. Detenlo, y la siguiente pieza será tuya. Usa el teletransporte que he abierto para alcanzarlo. Cuando esté muerto, usa el mismo dispositivo para regresar a mí.","Ahora debes encontrar al cirujano que encarniza y controla a tú gente... El Maestro del Conocimiento. Deténlo y la siguiente pieza será tuya. Usa el teleporte que he abierto para alcanzarlo. Cuando esté muerto, usa el mismo dispositivo para regresar conmigo.","Seuraavaksi pitää sinun löytämän kirugin, joka teurastaa ja hallitsee kansaasi: Oppi-Isän. Pysäytä hänet, ja seuraava osanen on oleva sinun. Käytä avaamaani kaukosiirrintä tavoittaaksesi hänet. Kun hän on kuollut, käytä samaa laitetta palataksesi tyköni.","Vous devez maintenant trouver le chirurgien qui massacre votre peuple, le Maître des traditions. Arrètez-le, et le fragment suivant sera le vôtre. Utilisez le téléporter qui s'est ouvert pour l'atteindre. Quand il est mort, utilisez le même téléporteur pour retourner à l'Oracle.","A következő lépés, hogy felkutatod a sebészt aki lemészárolja és irányítja a néped...a Tanmestert. Állítsd meg és a következő darab a tied. Most nyitottam ki ezt a teleportot, használd hogy eljuss hozzá. Ha meghalt, használd ugyanezt a visszaútra is.","Adesso devi trovare il chirurgo che macella e controlla la tua gente, il Sapiente. Fermalo e il prossimo pezzo sarà tuo. Usa il teletrasporto che ho sbloccato per raggiungere il Sapiente. Quando è morto, usa lo stesso teletrasporto per tornare da me.","次の欠片は人々を虐殺で支配する外科医... ロアマスターが所持している。奴を止め、欠片を自分の物にする。 -近辺へのテレポーターを使い、奴が死んだら再びテレポーターから戻る。","우리를 향한 도살과 지배를 책임졌던 과학자, 로어마스터를 찾아내야 해. 그를 막아내면, 다음 조각을 얻을 수 있을 거야. 오라클이 열어준 텔레포터를 이용해서 그를 찾아. 그가 죽으면 같은 장치를 이용해서 오라클에게 돌아와.","Vervolgens moet u de chirurg vinden die uw mensen afslacht en onder controle heeft....... De Kennismeester. Stop hem, en het volgende stuk zal van jou zijn. Gebruik de teleporter die ik geopend heb om hem te bereiken. Als hij dood is, gebruik dan hetzelfde apparaat om terug te keren naar mij.",,"Agora você deve encontrar o cirurgião que mutila e controla o seu povo... o Mestre do Conhecimento. Detenha-o e a próxima peça será sua. Use o teletransportador que eu abri para chegar até ele. Quando ele estiver morto, use o mesmo dispositivo e volte até mim.",,,"Тебе предстоит найти вивисектора, который вскрывает твоих людей и управляет ими — Хранителя мудрости. Останови его, и следующий фрагмент твой. Используй открытый мной телепорт, чтобы добраться до него. Когда он умрёт, найди другой телепорт, чтобы вернуться ко мне.", -You have chosen wisely. The third piece is held by your own leader. Destroy that which hides within your heart and return to me.,TXT_ILOG1027,,,,"Rozhodl ses moudře. Třetí díl je držen tvým vlastním vůdcem. Znič to, co se skrývá v tvém srdci, a vrať se ke mně.","Du hast weise entschieden. as dritte Teilstück wird von deinem eigenen Anführer, Macil, gehalten. Vernichte, was sich in eurem Herzen versteckt und kehre zu mir zurück.",,,Has elegido sabiamente. La tercera pieza está en manos de tu propio líder. Destroye lo que se esconde en tu corazón y regresa a mí.,Haz escogido sabiamente. La tercera pieza la tiene tú propio líder. Destruye aquello que se oculta en tú corazón y regresa conmigo.,,Vous avez sagement choisi. La troisième pièce est détenue par votre propre leader. Détruisez ce qui se tapit dans son cœur et revenez à moi.,,,"貴方は賢い判断をした。三つ目の欠片は我々のリーダーが保持している。 +近辺へのテレポーターを使い、奴が死んだら再びテレポーターから戻る。","우리를 향한 도살과 지배를 책임졌던 과학자, 로어마스터를 찾아내야 해. 그를 막아내면, 다음 조각을 얻을 수 있을 거야. 오라클이 열어준 텔레포터를 이용해서 그를 찾아. 그가 죽으면 같은 장치를 이용해서 오라클에게 돌아와.","Vervolgens moet u de chirurg vinden die uw mensen afslacht en onder controle heeft....... De Kennismeester. Stop hem, en het volgende stuk zal van jou zijn. Gebruik de teleporter die ik geopend heb om hem te bereiken. Als hij dood is, gebruik dan hetzelfde apparaat om terug te keren naar mij.","Deretter må du finne kirurgen som slakter og kontrollerer folket ditt.... Loremesteren. Stopp ham, og den neste brikken blir din. Bruk teleporteren jeg åpnet for å nå ham. Når han er død, bruk samme apparat for å komme tilbake til meg.","Następnie musisz znaleźć chirurga, który rzeźbi i kontroluje twoich ludzi.... Loremaster. Zatrzymaj go, a następny kawałek będzie twój. Użyj teleportera, który otworzyłem, aby do niego dotrzeć. Gdy będzie martwy, użyj tego samego urządzenia, by wrócić do mnie.","Agora você deve encontrar o cirurgião que mutila e controla o seu povo... o Mestre do Conhecimento. Detenha-o e a próxima peça será sua. Use o teletransportador que eu abri para chegar até ele. Quando ele estiver morto, use o mesmo dispositivo e volte até mim.",,"Mai departe trebuie să găsești chirurgul care vă masacrează oameni.... Maestrul Cunoștiințelor. Oprește-l, și următoarea piesă va fii a ta.","Тебе предстоит найти вивисектора, который вскрывает твоих людей и управляет ими — Хранителя мудрости. Останови его, и следующий фрагмент твой. Используй открытый мной телепорт, чтобы добраться до него. Когда он умрёт, найди другой телепорт и вернись ко мне.",,Nästa steg är att hitta kirurgen som slaktar och kontrollerar ditt folk.... Läromästaren. Stoppa honom och nästa del blir din. Använd teleportern som jag öppnade för att nå honom. När han är död använder du samma apparat för att återvända till mig.,"Şimdi halkını katleden ve kontrol eden cerrahı bulmalısın.... Loremaster. Onu durdurun ve bir sonraki parça sizin olsun. Ona ulaşmak için açtığım ışınlayıcıyı kullan. O öldüğünde, bana dönmek için aynı cihazı kullan." +You have chosen wisely. The third piece is held by your own leader. Destroy that which hides within your heart and return to me.,TXT_ILOG1027,MAP12: You chose to kill Macil.,,,"Rozhodl ses moudře. Třetí díl je držen tvým vlastním vůdcem. Znič to, co se skrývá v tvém srdci, a vrať se ke mně.","Du har truffet et klogt valg. Den tredje brik er i hænderne på din egen leder. Ødelæg det, der gemmer sig i dit hjerte, og vend tilbage til mig.","Du hast weise entschieden. as dritte Teilstück wird von deinem eigenen Anführer, Macil, gehalten. Vernichte, was sich in eurem Herzen versteckt und kehre zu mir zurück.",,,Has elegido sabiamente. La tercera pieza está en manos de tu propio líder. Destroye lo que se esconde en tu corazón y regresa a mí.,,"Olet valinnut viisaasti. Kolmatta osasta pitää hallussaan oma päämiehesi. Tuhoa se, mikä piilee sisällä sydämessäsi ja palaa tyköni.",Vous avez sagement choisi. La troisième pièce est détenue par votre propre leader. Détruisez ce qui se tapit dans son cœur et revenez à moi.,"Bölcsen döntöttél. A harmadik darab a saját vezérednél található. Semmisítsd meg a szíved mélyén megbúvó sötétséget, és térj vissza.",Hai fatto la scelta giusta. Il terzo pezzo è in possesso del tuo stesso capo. Distruggi ciò che si nasconde dentro il tuo cuore e ritorna da me.,"貴方は賢い判断をした。三つ目の欠片は我々のリーダーが保持している。 貴方の胸中に隠れているものを払い彼の元に戻る。 -",좋은 판단이야. 세 번째 시질 조각은 마실이 가지고 있어. 그를 죽여서 조각을 얻은 뒤 오라클에게 돌아와.,Je hebt verstandig gekozen. Het derde stuk wordt vastgehouden door je eigen leider. Vernietig datgene wat zich in je hart verbergt en keer terug naar mij.,,Você escolheu sabiamente. A terceira peça está com o seu próprio líder. Destrua aquilo que se esconde em seu coração e volte a mim.,,,"Мудрый выбор. Третий фрагмент у вашего лидера. Уничтожь то, что закралось в твоё сердце, и возвращайся ко мне.", -"We've found out that the Order is transforming our people into bio-mechanical soldiers. Find the facility where this is being done and close it, permanently! Find Richter in the commons, near the waterfall and he'll tell you how to stop this atrocity.",TXT_ILOG1028,,,,"Zjistili jsme, že Řád přeměňuje naše lidi na biomechanické vojáky. Najdi továrnu, kde se tohle odehrává, a zavři ji, natrvalo. Najdi Richtera na předměstí u vodopádů. Řekne ti, jak zastavit tuto ohavnost.","Wir haben herausgefunden, dass der Orden unsere Leute nicht tötet, sondern sie transformiert - int biomechanische Soldaten.Finde die Einrichtung, wo dies passiert und schließe sie - endgültig. Suche Richter beim Wasserfall bei der Mensa. Er wird dir sagen, wie du diese Abscheulichkeit abschaklten kannst.",,,"Hemos descubierto que la Orden está transformando a nuestra gente en soldados biomecánicos. Encuentra la instalación donde esto se está haciendo y ciérrala, ¡Permanentemente! Encuentra a Richter en los comunes, junto a la cascada y te dirá como detener esta atrocidad.","Hemos descubierto que la Orden está transformando a nuestra gente en soldado bio-mecánicos. ¡Encuentra la facilidad donde se está realizando esto y cierrala permanentemente! Encuentra a Richter en los comunes, cerca de la cascada y él te dirá como detener esta atrocidad.",,Nous avons découvert que l'Ordre transforme notre peuple en soldats biomécaniques. Trouve l'usine où cela se déroule et détruis-la pour toujours! Trouve Richter dans le Réfectoire près de la cascade et il t'expliquera comment stopper cette atrocité.,,,"我等はオーダーが人々をサイボーグ兵に改造しつつある事を発見した。 +",좋은 판단이야. 세 번째 시질 조각은 마실이 가지고 있어. 그를 죽여서 조각을 얻은 뒤 오라클에게 돌아와.,Je hebt verstandig gekozen. Het derde stuk wordt vastgehouden door je eigen leider. Vernietig datgene wat zich in je hart verbergt en keer terug naar mij.,"Du har valgt klokt. Den tredje brikken holdes av din egen leder. Ødelegg det som skjuler seg i hjertet ditt, og vend tilbake til meg.","Mądrze wybrałeś. Trzeci kawałek jest w posiadaniu twojego własnego przywódcy. Zniszcz to, co kryje się w twoim sercu i wróć do mnie.",Você escolheu sabiamente. A terceira peça está com o seu próprio líder. Destrua aquilo que se esconde em seu coração e volte a mim.,,Ai ales înțelept. A treia piesă e deținută de liderul vostru. Distruge ceea ce se ascunde în inima ta și întoarce-te la mine.,"Мудрый выбор. Третий фрагмент у вашего лидера. Уничтожь то, что закралось в твоё сердце, и возвращайся ко мне.",,Du har valt klokt. Den tredje biten innehas av din egen ledare. Förstör det som gömmer sig i ditt hjärta och återvänd till mig.,Akıllıca bir seçim yaptın. Üçüncü parça kendi liderinizin elinde. Kalbinde sakladığın şeyi yok et ve bana dön. +"We've found out that the Order is transforming our people into bio-mechanical soldiers. Find the facility where this is being done and close it, permanently! Find Richter in the commons, near the waterfall and he'll tell you how to stop this atrocity.",TXT_ILOG1028,MAP10: After killing the Oracle and talking to Macil.,,,"Zjistili jsme, že Řád přeměňuje naše lidi na biomechanické vojáky. Najdi továrnu, kde se tohle odehrává, a zavři ji, natrvalo. Najdi Richtera na návsi u vodopádů. Řekne ti, jak zastavit tuto ohavnost.","Vi har fundet ud af, at Ordenen forvandler vores folk til biomekaniske soldater. Find det sted, hvor det sker, og luk det for altid! Find Richter i fællesarealerne, nær vandfaldet, og han vil fortælle dig, hvordan du kan stoppe denne grusomhed.","Wir haben herausgefunden, dass der Orden unsere Leute nicht tötet, sondern sie transformiert - int biomechanische Soldaten.Finde die Einrichtung, wo dies passiert und schließe sie - endgültig. Suche Richter beim Wasserfall bei der Mensa. Er wird dir sagen, wie du diese Abscheulichkeit abschaklten kannst.",,,"Hemos descubierto que la Orden está transformando a nuestra gente en soldados biomecánicos. Encuentra la instalación donde esto se está haciendo y ciérrala, ¡Permanentemente! Encuentra a Richter en los comunes, junto a la cascada y te dirá como detener esta atrocidad.",,"Olemme saaneet selville, että Veljeskunta muuntelee meidän omiamme biomekaanisiksi sotilaiksi. Etsi laitos, jossa tätä tehdään, ja lakkauta se, pysyvästi! Etsi Richter messistä vesiputouksen läheltä, ja hän kertoo sinulle, miten lopettaa tämä kauhistus.",Nous avons découvert que l'Ordre transforme notre peuple en soldats biomécaniques. Trouve l'usine où cela se déroule et détruis-la pour toujours! Trouve Richter dans le Réfectoire près de la cascade et il t'expliquera comment stopper cette atrocité.,"Kiderítettük, hogy a Rend bio-mechanikus katonákká alakítja az embertársainkat. Keresd meg a létesítményt ahol ezt csinálják, és zárd be örökre! Keresd fel Richtert a vízesés melletti étkezdénél, Ő majd elmondja hogyan tudod megállítani ezt a borzalmat.","Abbiamo scoperto che l'Ordine sta trasformando la nostra gente in soldati bio-meccanici. Trova lo stabilimento dove questo sta avvenendo e chiuderlo, permanentemente. Trova Richter nei comuni, accanto alla cascata, e ti spiegherà come fermare questa atrocità.","我等はオーダーが人々をサイボーグ兵に改造しつつある事を発見した。 これが行われている施設を見つけ永久に停止させる。 -コモンズの滝近くにいるリヒターに会い、この残虐な行為を止める方法を聞く。","오더가 우리 사람들을 생체병기로 개조한다는 사실을 알았어. 끔찍한 일이 일어나는 이 시설을 찾아서 작동을 중단시켜, 영원히! 폭포와 가까운 식당가에 있는 릭터를 찾아서 어떻게 하면 중단시킬 수 있는지를 물어봐.","We hebben ontdekt dat de Orde onze mensen transformeert in bio-mechanische soldaten. Vind de faciliteit waar dit gebeurt en sluit deze permanent! Vind Richter in de commons, vlakbij de waterval, en hij zal je vertellen hoe je deze gruweldaad kunt stoppen.",,"Descobrimos que a Ordem está transformando o nosso pessoal em soldados biomecânicos. Encontre a instalação onde isso está sendo feito e feche-a, de uma vez por todas! Encontre o Richter no refeitório próximo à cascata e ele te dirá como parar com essa atrocidade.",,,"Мы выяснили, что Орден превращает наших людей в биомеханических солдат. Найди фабрику, где это происходит, и закрой её, навсегда! Найди Рихтера в поселении Ордена, возле водопада — он расскажет тебе, как остановить эти зверства.", -"To enter the factory, you need a key. We stole one, but the agent who had it is missing in the catacombs underneath the commons. There's something down there taking our men. Whatever it is, you have to find it and retrieve the key. When you've got it, the factory is next to the mines.",TXT_ILOG1029,,,,"Aby ses dostal do továrny, potřebuješ klíč. Ten jsme ukradli, ale náš agent se ztratil v sítí katakomb pod předměstím. Něco je tam dole a zabíjí to naše lidi. Ať je to cokoliv, musíme to najít a získat ten klíč. Až ho získáš, továrna je vedle dolů.","Um die Fabrik zu betreten, brauchst du einen Schlüssel. Wir haben ihn gestohlen, aber unser Agent ist in den Irrwegen der Katakomben unter der Festung des Ordens verschollen. Irgendetwas ist da unten, das unsere Leute ausschaltet. Was auch immer es ist, du musst es finden und den Schlüssel zurückholen. Wenn du ihn hast - die Fabrik ist direkt neben den Minen.",,,"Para entrar en la fábrica, necesitas una llave. Robamos una, pero el agente que la tiene está perdido en las catacumbas bajo los comunes. Hay algo ahí abajo tomando a nuestros hombres. Sea lo que sea, tienes que encontrarlo y recuperar la llave. Cuando la tengas, la fábrica está junto a las minas.","Para entrar en la Fábrica, necesitas una llave. Robamos una, pero el agente que la tenía está perdido en las catacumbas debajo de los comunes. Hay algo ahí abajo que está tomando nuestros hombres. Sea lo que sea, deberás encontrarlo y recuperar la llave. Cuando la tengas, la Fábrica está junto a las minas.",,"Pour entrer dans l'usine, il te faura une clé. On en a volé une, mais l'agent qui la possède a disparu dans les catacombes sous le réfectoire. Il y a quelque chose à l'intérieur qui tue nos hommes. Trouve la et récupère la clé. Quand tu l'as, l'usine est près des mines.",,,"工場に入るにはキーが必要だ。持っていた代理人はコモンズの地下墓所にはいない。 +コモンズの滝近くにいるリヒターに会い、この残虐な行為を止める方法を聞く。","오더가 우리 사람들을 생체병기로 개조한다는 사실을 알았어. 끔찍한 일이 일어나는 이 시설을 찾아서 작동을 중단시켜, 영원히! 폭포와 가까운 식당가에 있는 릭터를 찾아서 어떻게 하면 중단시킬 수 있는지를 물어봐.","We hebben ontdekt dat de Orde onze mensen transformeert in bio-mechanische soldaten. Vind de faciliteit waar dit gebeurt en sluit deze permanent! Vind Richter in de commons, vlakbij de waterval, en hij zal je vertellen hoe je deze gruweldaad kunt stoppen.","Vi har funnet ut at Ordenen forvandler vårt folk til biomekaniske soldater. Finn anlegget der dette gjøres og steng det, permanent! Finn Richter i allmenningen, nær fossen, og han vil fortelle deg hvordan du kan stoppe denne grusomheten.","Odkryliśmy, że Zakon przekształca naszych ludzi w bio-mechanicznych żołnierzy. Znajdźcie placówkę, w której to się odbywa i zamknijcie ją, na stałe! Znajdź Richtera w komnatach, w pobliżu wodospadu, a on powie ci, jak powstrzymać to okrucieństwo.","Descobrimos que a Ordem está transformando o nosso pessoal em soldados biomecânicos. Encontre a instalação onde isso está sendo feito e feche-a, de uma vez por todas! Encontre o Richter no refeitório próximo à cascata e ele te dirá como parar com essa atrocidade.",,"Am aflat că Ordinul ne transformă oamenii în soldați bio-mecanici. Găsește fabrica unde se întâmplă asta și închide-o, permanent! Găsește-l pe Richter la comune, lângă cascadă și îți va spune cum să oprești atrocitatea.","Мы выяснили, что Орден превращает наших людей в биомеханических солдат. Найди фабрику, где это происходит, и закрой её, навсегда! Найди Рихтера в поселении Ордена, возле водопада — он расскажет тебе, как остановить эти зверства.",,"Vi har fått reda på att Orden förvandlar vårt folk till biomekaniska soldater. Hitta anläggningen där detta görs och stäng den, för gott! Hitta Richter i allmänningen, nära vattenfallet, så berättar han hur du ska stoppa denna grymhet.","Tarikat'ın insanlarımızı biyo-mekanik askerlere dönüştürdüğünü öğrendik. Bunun yapıldığı tesisi bulun ve kalıcı olarak kapatın! Ortak alanda, şelalenin yanında Richter'i bulun ve size bu vahşeti nasıl durduracağınızı anlatsın." +"To enter the factory, you need a key. We stole one, but the agent who had it is missing in the catacombs underneath the commons. There's something down there taking our men. Whatever it is, you have to find it and retrieve the key. When you've got it, the factory is next to the mines.",TXT_ILOG1029,MAP23: After talking with Richter.,,,"Aby ses dostal do továrny, potřebuješ klíč. Ten jsme ukradli, ale náš agent se ztratil v sítí katakomb pod návsí. Něco je tam dole a zabíjí to naše lidi. Ať je to cokoliv, musíme to najít a získat ten klíč. Až ho získáš, továrna je vedle dolů.","For at komme ind på fabrikken skal du bruge en nøgle. Vi stjal en, men agenten, der havde den, er forsvundet i katakomberne under fællesarealerne. Der er noget dernede, der tager vores mænd. Uanset hvad det er, skal du finde det og hente nøglen. Når du har den, er fabrikken ved siden af minerne.","Um die Fabrik zu betreten, brauchst du einen Schlüssel. Wir haben ihn gestohlen, aber unser Agent ist in den Irrwegen der Katakomben unter der Festung des Ordens verschollen. Irgendetwas ist da unten, das unsere Leute ausschaltet. Was auch immer es ist, du musst es finden und den Schlüssel zurückholen. Wenn du ihn hast - die Fabrik ist direkt neben den Minen.",,,"Para entrar en la fábrica, necesitas una llave. Robamos una, pero el agente que la tiene está perdido en las catacumbas bajo los comunes. Hay algo ahí abajo tomando a nuestros hombres. Sea lo que sea, tienes que encontrarlo y recuperar la llave. Cuando la tengas, la fábrica está junto a las minas.",,"Päästäksesi sisälle tehtaaseen tarvitset avaimen. Varastimme sellaisen, mutta vakooja, joka sen sai, on kadoksissa katakombeissa messin alapuolella. Jokin siellä alla vie miehiämme. Mikä ikinä se onkaan, sinun on löydettävä se ja noudettava avain. Kun se on hallussasi, tehdas on kaivoksen vieressä.","Pour entrer dans l'usine, il te faura une clé. On en a volé une, mais l'agent qui la possède a disparu dans les catacombes sous le réfectoire. Il y a quelque chose à l'intérieur qui tue nos hommes. Trouve la et récupère la clé. Quand tu l'as, l'usine est près des mines.","Ahhoz, hogy bejuss a gyárba, kell szerezned egy kulcsot. Sikerült lopnunk egyet, de az ügynökünk akinél volt eltünt az étkezde alatti katakombákban. Van valami lent, ami sorra öli a katonáinkat. Akármi is vár lent, meg kell szerezned a kulcsot. Ha végeztél a gyárat megleled a bánya mellett.","Per entrare nella fabbrica ti servirà una chiave. L'abbiamo rubata ma l'agente che l'ha presa è sparito nelle catacombe sotto i comuni. C'è qualcosa là sotto che sta prendendo i nostri uomini. Qualsiasi cosa sia, devi andare laggiù e recuperare la chiave. Quando l'hai presa, la Fabbrica si trova accanto le miniere.","工場に入るにはキーが必要だ。持っていた代理人はコモンズの地下墓所にはいない。 何処かへ連れて行かれたと思われる。それが何であれキーを見つけなければならない。 -キーを手に入れたら工場の隣の鉱山に向かう。","공장으로 들어가기 위해서는 열쇠가 필요해. 열쇠를 훔치기는 했지만, 소유했던 요원이 식당가 밑 고대 무덤 안에서 행방불명 되었데. 우리 병사들을 끌고 가는 무언가가 있는 것 같아. 그게 무엇이든, 파괴해서 열쇠를 얻어. 그리고 광산 옆에 있는 공장을 열쇠로 열어서 들어가.","Om de fabriek binnen te komen, heb je een sleutel nodig. We hebben er een gestolen, maar de agent die hem had, wordt vermist in de catacomben onder de commons. Er is daar beneden iets dat onze mannen meeneemt. Wat het ook is, je moet het vinden en de sleutel ophalen. Als je hem hebt, staat de fabriek naast de mijnen.",,"Para entrar na fábrica você precisa de uma chave. Nós roubamos uma, mas o agente que tinha ela desapareceu nas catacumbas sob o refeitório. Há algo lá embaixo que está pegando os nossos homens. Seja lá o que for, você precisa achar e recuperar a chave. Quando conseguir, a fábrica fica próxima às minas.",,,"Тебе нужен ключ, чтобы проникнуть на фабрику. Мы украли один, но наш агент пропал без вести в катакомбах под поселением. Там, внизу, сидит что-то, что убивает наших людей. Что бы это ни было, тебе придётся сразиться с ним. Когда заполучишь ключ, вход на фабрику рядом со спуском в шахты.", -Find the chalice in the sanctuary chapel and bring it to Harris upstairs in the tavern.,TXT_ILOG1101,,,,Najdi kalich v kapli svatyně a přines ho Harrisovi v patře taverny.,Finde den Kelch im Heiligtum und bringe ihn zu Harris im Obergeschoss der Taverne.,,,Encuentra el cáliz en la capilla del santuario y tráeselo a Harris arriba en la taberna.,Encuentra el Cáliz en la capilla del santuario y tráeselo a Harris arriba en la taberna.,,Trouve le calice dans la chapelle du sanctuaire et amène la à Harris à l'étage de la taverne.,,,聖域でチャリスを探しバーの二階にいるハリスに渡す,"성소에 있는 성배를 찾은 뒤, 선술집에 있는 헤리스에게 전달해.",Vind de kelk in de kapel van het heiligdom en breng hem naar Harris boven in de taverne.,,Encontre o cálice na capela do santuário e leve ao Harris no andar de cima da taverna.,,,Найди чашу в святилище и принеси её Харрису на второй этаж таверны., -Find the Governor's mansion and talk to the Governor to get your reward,TXT_ILOG1102,,,,Najdi guvernérovo sídlo a promluv si s ním pro svou odměnu.,Finde die Villa des Gouverneurs und rede mit ihm über deine Belohnung.,,,Encuentra la mansión del Gobernador y habla con el Gobernador para obtener tu recompensa,Encuentra la mansión del Gobernador y habla con él para obtener tú recompensa.,,Trouve le manoir du Gouverneur et parle-lui pour réclamer ta récompense.,,,知事のマンションで知事と話し報酬を得る,총독의 거주지를 찾은 뒤 총독을 만나서 보상에 대해 예기해.,Zoek het herenhuis van de Gouverneur en praat met de Gouverneur om je beloning te krijgen.,,Encontre a mansão do Governador e fale com ele para pegar a sua recompensa.,,,Пройди в особняк губернатора и обсуди с Морелом своё вознаграждение., -Congratulations! You have earned our gratitude. Visit the medic and weapons trainer and they will get you ready for what lies ahead. Feel free to wander around within the base.,TXT_ILOG1201,,,,"Gratulujeme! Získal sis naši vděčnost. Navštiv lékaře a učitele střelby a oni tě připraví na to, co číhá dál. Klidně se potloukej po základně.","Gratulation. Du hast dir unsere Dankbarkeit verdient. Suche den Sanitäter und den Waffentrainer auf, sie werden dich auf das was vor dir liegt, vorbereiten. Wenn du willst, schau dich in der Basis um.",,,¡Enhorabuena! Te has ganado nuestra gratitud. Visita al médico y al entrenador de armas y te prepararán para lo que viene en adelante. Sé libre de dar un paseo por la base.,¡Felicitaciones! Te haz ganado nuestra gratitud. Visita al médico y al entrenador de armas y ellos te dejarán listo para lo que sigue. Sientete libre de andar através de la base.,,Félicitations! Vous méritez notre gratitude. Allez voir le médecin et le maître d'armes et ils pourront vous préparer pour ce qu'il va suivre. Vous pouvez faire le tour de la base si vous le souhaitez.,,,"おめでとう!私達は貴方に感謝している。 +キーを手に入れたら工場の隣の鉱山に向かう。","공장으로 들어가기 위해서는 열쇠가 필요해. 열쇠를 훔치기는 했지만, 소유했던 요원이 식당가 밑 고대 무덤 안에서 행방불명 되었데. 우리 병사들을 끌고 가는 무언가가 있는 것 같아. 그게 무엇이든, 파괴해서 열쇠를 얻어. 그리고 광산 옆에 있는 공장을 열쇠로 열어서 들어가.","Om de fabriek binnen te komen, heb je een sleutel nodig. We hebben er een gestolen, maar de agent die hem had, wordt vermist in de catacomben onder de commons. Er is daar beneden iets dat onze mannen meeneemt. Wat het ook is, je moet het vinden en de sleutel ophalen. Als je hem hebt, staat de fabriek naast de mijnen.","For å komme inn i fabrikken trenger du en nøkkel. Vi stjal en, men agenten som hadde den er savnet i katakombene under allmenningen. Det er noe der nede som tar våre menn. Hva det enn er, må du finne det og hente nøkkelen. Når du har den, er fabrikken ved siden av gruvene.","Aby wejść do fabryki, potrzebujesz klucza. Ukradliśmy jeden, ale agent, który go miał, zaginął w katakumbach pod commons. Coś tam jest, co zabiera naszych ludzi. Cokolwiek to jest, musisz to znaleźć i odzyskać klucz. Gdy go zdobędziesz, fabryka znajduje się obok kopalni.","Para entrar na fábrica você precisa de uma chave. Nós roubamos uma, mas o agente que tinha ela desapareceu nas catacumbas sob o refeitório. Há algo lá embaixo que está pegando os nossos homens. Seja lá o que for, você precisa achar e recuperar a chave. Quando conseguir, a fábrica fica próxima às minas.",,"Pentru a intra în fabrică ai nevoie de cheie. Noi am furat una, dar agentul care a luat-o e undeva în caverne, sub comune. E ceva acolo care ne răpește oamenii. Orice ar fi, găsește-l și ia cheia. Când o ai, fabrica e lângă mine.","Тебе нужен ключ, чтобы проникнуть на фабрику. Мы украли один, но наш агент пропал без вести в катакомбах под поселением. Там, внизу, сидит что-то, что убивает наших людей. Что бы это ни было, тебе придётся сразиться с ним. Когда заполучишь ключ, вход на фабрику рядом со спуском в шахты.",,"För att komma in i fabriken behöver du en nyckel. Vi stal en, men agenten som hade den är försvunnen i katakomberna under allmänningen. Det är något där nere som tar våra män. Vad det än är måste du hitta det och hämta nyckeln. När du har fått den är fabriken bredvid gruvorna.","Fabrikaya girmek için bir anahtara ihtiyacınız var. Bir tane çaldık, ama anahtarı alan ajan avlunun altındaki yeraltı mezarlarında kayıp. Aşağıda adamlarımızı kaçıran bir şey var. O her neyse, onu bulup anahtarı almalısın. Anahtarı aldığında, fabrika madenlerin yanında olacak." +Find the chalice in the sanctuary chapel and bring it to Harris upstairs in the tavern.,TXT_ILOG1101,,,,Najdi kalich v kapli svatyně a přines ho Harrisovi v patře taverny.,Find bægeret i helligkapellet og bring det til Harris ovenpå i tavernaen.,Finde den Kelch im Heiligtum und bringe ihn zu Harris im Obergeschoss der Taverne.,,,Encuentra el cáliz en la capilla del santuario y tráeselo a Harris arriba en la taberna.,,Löydä kalkki pyhäkön kappelista ja tuo se Harrisille kapakan yläkertaan.,Trouve le calice dans la chapelle du sanctuaire et amène la à Harris à l'étage de la taverne.,"Keresd meg a serleget a szent kápolnánál, és vidd Harrishez a kocsma emeletére.",Trova il calice nella cappella del santuario e portalo ad Harris al piano di sopra della Taverna.,聖域でチャリスを探しバーの二階にいるハリスに渡す,"성소에 있는 성배를 찾은 뒤, 선술집에 있는 헤리스에게 전달해.",Vind de kelk in de kapel van het heiligdom en breng hem naar Harris boven in de taverne.,Finn kalken i helligdomskapellet og ta den med til Harris oppe i tavernaen.,Znajdź kielich w kaplicy sanktuarium i zanieś go Harrisowi na górę w tawernie.,Encontre o cálice na capela do santuário e leve ao Harris no andar de cima da taverna.,,Găsește potirul în sanctuarul capelei și du-l lui Harris sus în tavernă.,Найди чашу в святилище и принеси её Харрису на второй этаж таверны.,,Hitta kalken i helgedomens kapell och ta med den till Harris uppe i tavernan.,Kutsal şapeldeki kadehi bul ve tavernanın üst katındaki Harris'e getir. +Find the Governor's mansion and talk to the Governor to get your reward,TXT_ILOG1102,,,,Najdi guvernérovo sídlo a promluv si s ním pro svou odměnu.,Find guvernørens palæ og tal med guvernøren for at få din belønning,Finde die Villa des Gouverneurs und rede mit ihm über deine Belohnung.,,,Encuentra la mansión del Gobernador y habla con él para obtener tu recompensa,,Löydä kuvernöörin kartano ja puhu kuvernöörin kanssa saadaksesi palkkiosi.,Trouve le manoir du Gouverneur et parle-lui pour réclamer ta récompense.,"Keresd fel a Kormányzót a kúriájában, hogy megkapd a jutalmad.",Trova la dimora del governatore e parlagli della tua ricompensa.,知事のマンションで知事と話し報酬を得る,총독의 거주지를 찾은 뒤 총독을 만나서 보상에 대해 예기해.,Zoek het herenhuis van de Gouverneur en praat met de Gouverneur om je beloning te krijgen.,Finn guvernørens herskapshus og snakk med guvernøren for å få belønningen.,"Znajdź rezydencję gubernatora i porozmawiaj z nim, aby otrzymać nagrodę",Encontre a mansão do Governador e fale com ele para pegar a sua recompensa.,,Găsește complexul Guvernatorului și vorbește cu el pentru a-ți lua recompensa.,Пройди в особняк губернатора и обсуди с Морелом своё вознаграждение.,,Hitta guvernörens herrgård och prata med guvernören för att få din belöning.,Vali'nin konağını bulun ve ödülünüzü almak için Vali ile konuşun +Congratulations! You have earned our gratitude. Visit the medic and weapons trainer and they will get you ready for what lies ahead. Feel free to wander around within the base.,TXT_ILOG1201,,,,"Gratulujeme! Získal sis naši vděčnost. Navštiv lékaře a učitele střelby a oni tě připraví na to, co číhá dál. Klidně se potloukej po základně.","Tillykke med det! Du har fortjent vores taknemmelighed. Besøg lægen og våbentræneren, og de vil gøre dig klar til det, der venter forude. Du er velkommen til at vandre rundt i basen.","Gratulation. Du hast dir unsere Dankbarkeit verdient. Suche den Sanitäter und den Waffentrainer auf, sie werden dich auf das was vor dir liegt, vorbereiten. Wenn du willst, schau dich in der Basis um.",,,¡Enhorabuena! Te has ganado nuestra gratitud. Visita al médico y al entrenador de armas y te prepararán para lo que viene en adelante. Sé libre de dar un paseo por la base.,¡Felicitaciones! Te ganaste nuestra gratitud. Visita al médico y al entrenador de armas y ellos te dejarán listo para lo que sigue. Sientete libre de andar através de la base.,"Onneksi olkoon! Olet ansainnut kiitollisuutemme. Vieraile lääkintämiehen ja asekouluttajan luona, ja he valmistavat sinut tuleviin koitoksiin. Saat vapaasti kulkea tukikohdan sisällä.",Félicitations! Vous méritez notre gratitude. Allez voir le médecin et le maître d'armes et ils pourront vous préparer pour ce qu'il va suivre. Vous pouvez faire le tour de la base si vous le souhaitez.,"Gratulálok! Kiérdemled a hálánkat! keresd fel a szanitécet és a fegyvermestert, és felkészítenek az előtted álló harcra. Nyugodtan nézz körbe a bázisban.",Congratulazioni! Meriti appieno la nostra gratitudine. Visita il medico e l'addestratore di armi e ti prepareranno per ciò che ci aspetta. Sii anche libero di andare in giro per la base.,"おめでとう!私達は貴方に感謝している。 メディックと武器トレーナーに訪れれば手助けを施せる。 -基地内部も自由に回ってよい。",축하해! 우리 모두 너에게 고마워하고 있어. 의무관과 무기 담당관을 찾아가면 너에게 보답을 할 준비를 할 거야. 그 후엔 기지를 마음껏 돌아다녀 봐!,Gefeliciteerd! Je hebt onze dankbaarheid verdiend. Bezoek de medicus- en wapentrainer en zij zullen je klaarstomen voor wat je te wachten staat. Voel je vrij om rond te dwalen in de basis.,,Parabéns! Você conquistou a nossa gratidão. Visite o médico e o treinador de armas e eles vão te preparar para o que vem adiante. Sinta-se livre para passear pela base.,,,"Поздравляем! Ты заслужил нашу благодарность. Зайди к медику и инструктору по стрельбе, и они подготовят тебя к тому, что ждёт тебя впереди. Теперь ты можешь свободно передвигаться по нашей базе.", -,,Strife characters,,,,,,,,,,,,,,,,,,,,, -Order Sergeant,TXT_SPEAKER_ORDER_SERGEANT,,,,Seržant Řádu,Soldat des Ordens,,,Sargento de La Orden,Sargento de La Orden,Veljeskunnan kersantti,Sergeant de l'Ordre,,Sergente dell'Ordine,オーダー軍曹,오더 장교,Soldaat van de orde,Sierżant Zakonu,Sargento da Ordem,,,Сержант Ордена, -Rowan,TXT_SPEAKER_ROWAN,,,,,,,,,,,,,,ロワン,로언,,,,,,Роуэн, -Feris,TXT_SPEAKER_FERIS,,,,,,,,,,,,,,フェリス,페리스,,,,,,Ферис, -Prison Guard,TXT_SPEAKER_PRISON_GUARD,,,,Vězeňská stráž,Gefängniswache,,,Guardia de la Prisión,Guardia de la Prisión,Vanginvartija,Garde de la Prison,,Guardia della Prigione,刑務官,간수,Gevangenisbewaker,Strażnik Więzienny,Guarda da Prisão,,,"Страж тюрьмы -", -Justin,TXT_SPEAKER_JUSTIN,,,,,,,,,,,,,,ジャスティン,저스틴,,,,,,Джастин, -Macil,TXT_SPEAKER_MACIL,,,,,,,,,,,,,,マシル,마실,,,,,,Мэйсил, -Assistant,TXT_SPEAKER_ASSISTANT,,,,Asistent,Assistent,,,Asistente,Asistente,Avustaja,,,Assistente,アシスタント,조수,Assistent,Asystent,Assistente,,,Ассистент, -Key Master,TXT_SPEAKER_KEY_MASTER,,,,Klíčník,Schlüsselmeister,,,Amo de Llaves,Maestro de Llaves,Avainmestari,Maître des Clés,,Maestro di chiavi,キーマスター,열쇠지기,Zeer belangrijke Meester,Klucznik,Mestre das Chaves,,,Ключник, -Bodyguard,TXT_SPEAKER_BODYGUARD,,,,Osobní stráž,Leibwächter,,,Guardaespaldas,Guardaespaldas,Henkivartija,Garde du corps,,Guardia del corpo,ボディガード,경호원,Lijfwacht,Ochroniarz,Guarda-costas,,,Телохранитель, -Interrogator,TXT_SPEAKER_INTERROGATOR,"Intended to appear in MAP01 of the Strife teaser, but does not spawn.",,,Vyslýchač,Befrager,,,Interrogador,Interrogador,Kuulustelija,Interrogateur,,Interrogatore,,심문자,Ondervrager,Śledczy,Interrogador,,,Дознаватель, -Warden Montag,TXT_SPEAKER_WARDEN_MONTAG,,,,Dozorce Montag,Direktor Montag,,,Carcelero Montag,Director Montag,Vankilanjohtaja Montag,Gardien Montag,,Guardiano Montag,モンターグ刑務所長,몬탕 간수장,Directeur Montag,Naczelnik Montag,Carcereiro Montag,,,Тюремщик Монтаг, -Richter,TXT_SPEAKER_RICHTER,,,,,,,,,,,,,,リヒター,릭터,,,,,,Рихтер, -Macil's Advisor,TXT_SPEAKER_MACIL_S_ADVISOR,,,,Macilův rádce,Macils Berater,,,Consejero de Macil,Consejero de Macil,Macilin neuvonantaja,Conseiller de Macil,,Consigliere di Macil,マシルの補佐官,마실의 조언자,Macil's adviseur,Doradca Macila,Conselheiro de Macil,,,Советник Мэйсила, -Judge Wolenick,TXT_SPEAKER_JUDGE_WOLENICK,,,,Soudce Wolenick,Richter Wolenick,,,Juez Wolenick,Juez Wolenick,Tuomari Wolenick,Juge Wolenick,,Giudice Wolenick,ウォレニック裁判官,울레닉 판사,Rechter Wolenick,Sędzia Wolenick,Juiz Wolenick,,,Судья Уолник, -Tevick,TXT_SPEAKER_TEVICK,,,,,,,,,,,,,,テビック,테빅,,,,,,Тевик, -Harris,TXT_SPEAKER_HARRIS,,,,,,,,,,,,,,ハリス,해리스,,,,,,Харрис, -Foreman,TXT_SPEAKER_FOREMAN,,,,Předák,Vormann,,,Capataz,Capataz,Työnjohtaja,Contremaître,,Caposquadra,フォアマン,감시원,Voorman,Brygadzista,Capataz,,,Бригадир, -Prisoner,TXT_SPEAKER_PRISONER,,,,Vězeň,Gefangener,,,Prisionero,Prisionero,Vanki,Prisonnier,,Prigioniero,囚人,죄수,Gevangene,Więzień,Prisioneiro,,,Пленник, -Sammis,TXT_SPEAKER_SAMMIS,,,,,,,,,,,,,,サムミス,새미스,,,,,,Сэммис, -Weapon Smith,TXT_SPEAKER_WEAPON_SMITH,,,,Zbrojíř,Waffenschmied,,,Forjador de Armas,Forjador de Armas,Aseseppä,Armurier,,Fabbro d'Armi,武器工,무기제조인,Wapen Smith,Wytwórca Broni,Armeiro,,,Оружейник, -Reactor Guard,TXT_SPEAKER_REACTOR_GUARD,,,,Stráž reaktoru,Reaktorwache,,,Guardia del Reactor,Guardia del Reactor,Reaktorinvartija,Garde du réacteur,,Guardia del Reattore,リアクターガード,발전소 경비원,Reactor bewaker,Strażnik Reaktora,Guarda do Reator,,,Страж реактора, -Apprentice,TXT_SPEAKER_APPRENTICE,,,,Učeň,Lehrling,,,Aprendiz,Aprendiz,Kisälli,Apprenti,,Apprendista,見習い,도제,Leerling,Uczeń,Aprendiz,,,Подмастерье, -Door Guard,TXT_SPEAKER_DOOR_GUARD,,,,Dveřní stráž,Türwache,,,Guarda de la Puerta,Guarda de la Puerta,Ovenvartija,Garde de la porte,,Guardia della Porta,ドアガード,문지기,Deurwacht,Strażnik Drzwi,Guarda da Porta,,,Страж входа, -Master Smithy,TXT_SPEAKER_MASTER_SMITHY,,,,Mistr kovář,Meister Smithy,,,Maestro Herrero,Maestro Herrero,Mestari Smithy,Maîre Forgeron,,Maestro della Fucina,マスター スミシー,스미시 제조장관,Meester Smithy,Kowal,Ferreiro-Mestre,,,Мастер-кузнец, -Warehouse Guard,TXT_SPEAKER_WAREHOUSE_GUARD,,,,Stráž skladu,Lagerhaus-Wache,,,Guardia del Almacén,Guardia del Almacén,Varastonvartija,Garde de l'entrepôt,,Guardia del Magazzino,倉庫のガード,격납고 감시장,Magazijnwachter,Strażnik Magazynu,Guarda do Depósito,,,Охранник склада, -Barkeep,TXT_SPEAKER_BARKEEP,,,,Barman,Wirt,,,Tabernero,Barman,Baarimikko,Barman,,Barman,バーテンダー,바텐더,Barman,Barman,Taberneiro,,,Хозяин таверны, -Timothy,TXT_SPEAKER_TIMOTHY,,,,,,,,,,,,,,ティモシー,티모시,,,,,,Тимоти, -James,TXT_SPEAKER_JAMES,,,,,,,,,,,,,,ジェームス,제임스,,,,,,Джеймс, -Worner,TXT_SPEAKER_WORNER,,,,,,,,,,,,,,ワーナー,워너,,,,,,Уорнэр, -Bailey Guard,TXT_SPEAKER_BAILEY_GUARD,,,,Stráž opevnění,Vorhof-Wache,,,Guardia de la Muralla,Guardia Bailey,Ulkomuurinvartija,Garde d'enceinte,,Guardia del Bastione,ベイリー ガード,외벽 파수병,Bailey Guard,Strażnik Murów,Guarda da Fortaleza,,,Страж крепости, -Drone,TXT_SPEAKER_DRONE,,,,Trubec,Drohne,,,Dron,Dron,Kuhnuri,,,,労働者,노예,Drone,Dron,Zangão,,,Дрон, -Front Guard,TXT_SPEAKER_FRONT_GUARD,,,,Stráž Fronty,Frontwache,,,Guardia del Frente,Guardia del Frente,Rintaman vartija,Garde du Front,,Guardia del Fronte,フロント ガード,프론트 파수꾼,Voorwacht,Strażnik Frontu,Guarda da Frente,,,Повстанец, -Quincy,TXT_SPEAKER_QUINCY,,,,,,,,,,,,,,クインシー,퀸시,,,,,,Куинси, -Sergeant,TXT_SPEAKER_SERGEANT,,,,Seržant,Feldwebel,,,Sargento,Sargento,Kersantti,Sergeant,,Sergente,軍曹,하사관,Sergeant,Sierżant,Sargento,,,Сержант, -Temple Guard,TXT_SPEAKER_TEMPLE_GUARD,,,,Stráž chrámu,Tempelwache,,,Guardia del Templo,Guardia del Templo,Temppelinvartija,Garde du Temple,,Guardia del Tempio,テンプル ガード,신전 파수병,Tempelwacht,Strażnik Świątyni,Guarda do Templo,,,Страж храма, -Oracle,TXT_SPEAKER_ORACLE,,,,Věštec,Orakel,,,Oráculo,Oráculo,Oraakkeli,,,Oracolo,オラクル,오라클,Orakel,Wyrocznia,Oráculo,,,Оракул, -Ulaine,TXT_SPEAKER_ULAINE,,,,,,,,,,,,,,ウレーヌ,울레인,,,,,,Улейн, -Front Soldier,TXT_SPEAKER_FRONT_SOLDIER,,,,Voják Fronty,Front-Soldat,,,Soldado del Frente,Soldado del Frente,Rintaman sotilas,Soldat du Front,,Soldato del Fronte,フロント ソルジャー,프론트 저항군,Front Soldier,Żołnierz Frontu,Soldado da Frente,,,Повстанец, -Programmer,TXT_SPEAKER_PROGRAMMER,,,,Programátor,Programmierer,,,Programador,Programador,Ohjelmoija,Programmeur,,Programmatore,プログラマー,프로그래머,Programmeur,Programista,Programador,,,Программист, -Medic,TXT_SPEAKER_MEDIC,,,,Zdravotník,Sanitäter,,,Médico,Médico,Lääkintämies,Médecin,,Medico,メディック,의무병,Paramedicus,Medyk,Médico,,,Медик, -Watchman,TXT_SPEAKER_WATCHMAN,,,,Hlídač,Wächter,,,Celador,Celador,Vahti,Vigie,,Vigilante,警備員,감시병,Waker,Stróż,Vigia,,,Караульный, -Ketrick,TXT_SPEAKER_KETRICK,,,,,,,,,,,,,,ケトリック,케트릭,,,,,,Кетрик, -Weran,TXT_SPEAKER_WERAN,,,,,,,,,,,,,,ウェラン,워렌,,,,,,Уэран, -Advisor,TXT_SPEAKER_ADVISOR,,,,Rádce,Berater,,,Consejero,Consejero,Neuvonantaja,Conseiller,,Consigliere,補佐官,조언자,Adviseur,Doradca,Conselheiro,,,Советник, -Geoff,TXT_SPEAKER_GEOFF,,,,,,,,,,,,,,ジェフ,제프,,,,,,Джефф, -Overseer,TXT_SPEAKER_OVERSEER,,,,Dozorčí,Aufseher,,,Superintendente,Superintendente,Valvoja,Superviseur,,Supervisore,監視人,현장 감독,Opziener,Nadzorca,Supervisor,,,Надсмотрщик, +基地内部も自由に回ってよい。",축하해! 우리 모두 너에게 고마워하고 있어. 의무관과 무기 담당관을 찾아가면 너에게 보답을 할 준비를 할 거야. 그 후엔 기지를 마음껏 돌아다녀 봐!,Gefeliciteerd! Je hebt onze dankbaarheid verdiend. Bezoek de medicus- en wapentrainer en zij zullen je klaarstomen voor wat je te wachten staat. Voel je vrij om rond te dwalen in de basis.,"Gratulerer! Du har fortjent vår takknemlighet. Besøk medisineren og våpentreneren, og de vil gjøre deg klar for det som ligger foran deg. Føl deg fri til å vandre rundt i basen.","Gratulacje!!! Zasłużyłeś na naszą wdzięczność. Odwiedź medyka i trenera broni, a oni przygotują Cię na to, co Cię czeka. Możesz swobodnie poruszać się po bazie.",Parabéns! Você conquistou a nossa gratidão. Visite o médico e o treinador de armas e eles vão te preparar para o que vem adiante. Sinta-se livre para passear pela base.,,Felicitări! Ne-ai câștigat recunoștiința. Vizitează medicul și antrenorul de arme și te vor pregătii pentru ceea ce urmează mai departe. Simte-te liber să te plimbi prin bază.,"Поздравляем! Ты заслужил нашу благодарность. Зайди к медику и инструктору по стрельбе, и они подготовят тебя к тому, что ждёт тебя впереди. Теперь ты можешь свободно передвигаться по нашей базе.",,Gratulerar! Du har förtjänat vår tacksamhet. Besök sjukvårdaren och vapentränaren och de kommer att göra dig redo för vad som väntar dig. Du får gärna vandra runt i basen.,"Tebrikler! Minnettarlığımızı kazandınız. Sıhhiyeyi ve silah eğitmenini ziyaret edin, onlar sizi ileride olacaklara hazırlayacaktır. Üs içinde dolaşmaktan çekinmeyin." +,,Strife characters,,,,,,,,,,,,,,,,,,,,,,,,, +Order Sergeant,TXT_SPEAKER_ORDER_SERGEANT,,,,Seržant Řádu,Ordenens sergent,Soldat des Ordens,,Serĝento de La Ordeno,Sargento de La Orden,,Veljeskunnan kersantti,Sergeant de l'Ordre,Rendi Törzsőrmester,Sergente dell'Ordine,オーダー軍曹,오더 장교,Soldaat van de orde,Ordenssersjant,Sierżant Zakonu,Sargento da Ordem,,Sergent al Ordinului,Сержант Ордена,,Sergeant på orden,Emir Çavuşu +Rowan,TXT_SPEAKER_ROWAN,,,,,,,,,,,,,,,ロワン,로언,,,,,,,Роуэн,,, +Feris,TXT_SPEAKER_FERIS,,,,,,,,Feriso,,,,,,,フェリス,페리스,,,,,,,Ферис,,, +Prison Guard,TXT_SPEAKER_PRISON_GUARD,,,,Vězeňská stráž,Fængselsbetjent,Gefängniswache,,Mallibereja gardisto,Guardia de la prisión,,Vanginvartija,Garde de la Prison,Börtönőr,Guardia della Prigione,刑務官,간수,Gevangenisbewaker,Fengselsvakt,Strażnik Więzienny,Guarda da Prisão,,Gardian Închisoare,"Страж тюрьмы +",,Fångvakt,Hapishane Gardiyanı +Justin,TXT_SPEAKER_JUSTIN,,,,,,,,,,,,,,,ジャスティン,저스틴,,,,,,,Джастин,,, +Macil,TXT_SPEAKER_MACIL,,,,,,,,,,,,,,,マシル,마실,,,,,,,Мэйсил,,, +Assistant,TXT_SPEAKER_ASSISTANT,,,,Asistent,Assistent,Assistent,,Asistanto,Asistente,,Avustaja,,Asszisztens,Assistente,アシスタント,조수,Assistent,Assistent,Asystent,Assistente,,Asistent,Ассистент,,Assistent,Asistan +Key Master,TXT_SPEAKER_KEY_MASTER,,,,Klíčník,Nøglemester,Schlüsselmeister,,Ŝlosilestro,Amo de llaves,,Avainmestari,Maître des Clés,Kulcsmester,Mastro delle chiavi,キーマスター,열쇠지기,Zeer belangrijke Meester,Nøkkelmester,Klucznik,Mestre das Chaves,,Stăpân al Cheilor,Ключник,,Nyckelmästare,Anahtar Ustası +Bodyguard,TXT_SPEAKER_BODYGUARD,,,,Osobní stráž,Livvagt,Leibwächter,,Korpogardisto,Guardaespaldas,,Henkivartija,Garde du corps,Testőr,Guardia del corpo,ボディガード,경호원,Lijfwacht,Livvakt,Ochroniarz,Guarda-costas,,Gardă de Corp,Телохранитель,,Livvakt, +Interrogator,TXT_SPEAKER_INTERROGATOR,"Intended to appear in MAP01 of the Strife teaser, but does not spawn.",,,Vyslýchač,Forhørsleder,Befrager,,Pridemandisto,Interrogador,,Kuulustelija,Interrogateur,Kihallgató,Interrogatore,,심문자,Ondervrager,Avhører,Śledczy,Interrogador,,Interogator,Дознаватель,,Förhörsledare,Sorgulayıcı +Warden Montag,TXT_SPEAKER_WARDEN_MONTAG,,,,Dozorce Montag,Direktør Montag,Direktor Montag,,Provoso Montag,Carcelero Montag,,Vankilanjohtaja Montag,Gardien Montag,Montag börtönigazgató,Direttore Montag,モンターグ刑務所長,몬탕 간수장,Directeur Montag,Direktør Montag,Naczelnik Montag,Carcereiro Montag,,Directorul Montag,Тюремщик Монтаг,,Direktör Montag,Müdür Montag +Richter,TXT_SPEAKER_RICHTER,,,,,,,,Rikter,,,,,,,リヒター,릭터,,,,,,,Рихтер,,, +Macil's Advisor,TXT_SPEAKER_MACIL_S_ADVISOR,,,Macil's Adviser,Macilův rádce,Macils rådgiver,Macils Berater,,Konsilisto de Macil,Consejero de Macil,,Macilin neuvonantaja,Conseiller de Macil,Macil tanácsosa,Consigliere di Macil,マシルの補佐官,마실의 조언자,Macil's adviseur,Macils rådgiver,Doradca Macila,Conselheiro de Macil,,Sfetnicul lui Macil,Советник Мэйсила,,Macils rådgivare,Macil'in Danışmanı +Judge Wolenick,TXT_SPEAKER_JUDGE_WOLENICK,,,,Soudce Wolenick,Dommer Wolenick,Richter Wolenick,,Juĝisto Wolenick,Juez Wolenick,,Tuomari Wolenick,Juge Wolenick,Wolenick bíró,Giudice Wolenick,ウォレニック裁判官,울레닉 판사,Rechter Wolenick,Dommer Wolenick,Sędzia Wolenick,Juiz Wolenick,,Judecătorul Wolenick,Судья Уолник,,Domare Wolenick,Yargıç Wolenick +Tevick,TXT_SPEAKER_TEVICK,,,,,,,,,,,,,,,テビック,테빅,,,,,,,Тевик,,,Tevak +Harris,TXT_SPEAKER_HARRIS,,,,,,,,Harriso,,,,,,,ハリス,해리스,,,,,,,Харрис,,, +Foreman,TXT_SPEAKER_FOREMAN,,,,Předák,Formand,Vormann,,Submastro,Capataz,,Työnjohtaja,Contremaître,Művezető,Caposquadra,フォアマン,감시원,Voorman,Formann,Brygadzista,Capataz,,,Бригадир,,Förman,Ustabaşı +Prisoner,TXT_SPEAKER_PRISONER,,,,Vězeň,Fange,Gefangener,,Kaptito,Prisionero,,Vanki,Prisonnier,Rab,Prigioniero,囚人,죄수,Gevangene,Fange,Więzień,Prisioneiro,,Prizonier,Пленник,,Fånge,Mahkum +Sammis,TXT_SPEAKER_SAMMIS,,,,,,,,,,,,,,,サムミス,새미스,,,,,,,Сэммис,,, +Weapon Smith,TXT_SPEAKER_WEAPON_SMITH,,,,Zbrojíř,Våbensmed,Waffenschmied,,Armilforĝisto,Forjador de armas,,Aseseppä,Armurier,Fegyverkovács,Fabbro d'Armi,武器工,무기제조인,Wapen Smith,Våpensmed,Wytwórca Broni,Armeiro,,Făurar Arme,Оружейник,,Vapen Smith,Silah Ustası +Reactor Guard,TXT_SPEAKER_REACTOR_GUARD,,,,Stráž reaktoru,Reaktorvagt,Reaktorwache,,Reaktora gardisto,Guardia del reactor,,Reaktorinvartija,Garde du réacteur,Reaktor Őr,Guardia del Reattore,リアクターガード,발전소 경비원,Reactor bewaker,Reaktorvakt,Strażnik Reaktora,Guarda do Reator,,Gardian Reactor,Страж реактора,,Reaktorvakt,Reaktör Muhafızı +Apprentice,TXT_SPEAKER_APPRENTICE,,,,Učeň,Lærling,Lehrling,,Komencanto,Aprendiz,,Kisälli,Apprenti,Tanonc,Apprendista,見習い,도제,Leerling,Lærling,Uczeń,Aprendiz,,Ucenic,Подмастерье,,Lärling,Çırak +Door Guard,TXT_SPEAKER_DOOR_GUARD,,,,Dveřní stráž,Dørvagt,Türwache,,Pordisto,Portero,,Ovenvartija,Garde de la porte,Ajtónálló,Guardia della Porta,ドアガード,문지기,Deurwacht,Dørvakt,Strażnik Drzwi,Guarda da Porta,,Paznic,Страж входа,,Dörrvakt,Kapı Koruması +Master Smithy,TXT_SPEAKER_MASTER_SMITHY,,,,Mistr Smithy,Mester Smithy,Meister Smithy,,Majstro Smithy,Maestro Smithy,,Pajamestari,Maître Forgeron,Smithy mester,Maestro Smithy,マスター スミシー,스미시 제조장관,Meester Smithy,Mester Smithy,Mistrz Smithy,Mestre Smithy,,Maestrul Smithy,Мастер-кузнец,,Mästersmeden,Demirci Usta +Warehouse Guard,TXT_SPEAKER_WAREHOUSE_GUARD,,,,Stráž skladu,Lagervagt,Lagerhaus-Wache,,Magazena gardisto,Guardia del almacén,,Varastonvartija,Garde de l'entrepôt,Raktár Őr,Guardia del Magazzino,倉庫のガード,격납고 감시장,Magazijnwachter,Lagervakt,Strażnik Magazynu,Guarda do Depósito,,Paznic Depozit,Охранник склада,,Lagervakt,Depo Görevlisi +Barkeep,TXT_SPEAKER_BARKEEP,,,,Barman,Bartender,Wirt,,Drinkejestro,Tabernero,,Baarimikko,Barman,Bárpultos,Barman,バーテンダー,바텐더,Barman,Bartender,Barman,Taberneiro,,Barman,Хозяин таверны,,Bartender,Barmen +Timothy,TXT_SPEAKER_TIMOTHY,,,,,,,,Timoteo,,,,,,,ティモシー,티모시,,,,,,Timotei,Тимоти,,,Timothy +James,TXT_SPEAKER_JAMES,,,,,,,,,,,,,,,ジェームス,제임스,,,,,,,Джеймс,,, +Worner,TXT_SPEAKER_WORNER,,,,,,,,,,,,,,,ワーナー,워너,,,,,,,Уорнэр,,, +Bailey Guard,TXT_SPEAKER_BAILEY_GUARD,,,,Stráž opevnění,Bailey-vagt,Vorhof-Wache,,Gardisto de la fortresa korto,Guardia del patio cerrado,,Ulkomuurinvartija,Garde d'enceinte,Várfal Őr,Guardia del Bastione,ベイリー ガード,외벽 파수병,,Borggården vakt,Strażnik Murów,Guarda da Fortaleza,,Gardian Bailey,Страж крепости,,Bailey-vakt,Dış avlu bekçisi +Drone,TXT_SPEAKER_DRONE,drone ≈ slave,,,Trubec,,Drohne,,Sklavo,Esclavo,,Kuhnuri,,Drón,Schiavo,労働者,노예,,,Dron,Escravo,,Dronă,Дрон,,Drönare, +Front Guard,TXT_SPEAKER_FRONT_GUARD,,,,Stráž Fronty,Front vagt,Frontwache,,Gardisto de la Fronto,Guardia del Frente,,Rintaman vartija,Garde du Front,Front Őr,Guardia del Fronte,フロント ガード,프론트 파수꾼,Voorwacht,,Strażnik Frontu,Guarda da Frente,,Gandian Front,Повстанец,,Frontvakt,Ön Koruma +Quincy,TXT_SPEAKER_QUINCY,,,,,,,,Kvincio,,,,,,,クインシー,퀸시,,,,,,,Куинси,,,Quincy +Sergeant,TXT_SPEAKER_SERGEANT,,,,Seržant,Sergent,Feldwebel,,Serĝento,Sargento,,Kersantti,,Törzsőrmester,Sergente,軍曹,하사관,,Sersjant,Sierżant,Sargento,,Sergent,Сержант,,Sergeant,Çavuş +Temple Guard,TXT_SPEAKER_TEMPLE_GUARD,,,,Stráž chrámu,Tempelvagt,Tempelwache,,Gardisto de la templo,Guardia del templo,,Temppelinvartija,Garde du Temple,Templom Őr,Guardia del Tempio,テンプル ガード,신전 파수병,Tempelwacht,Tempelvakten,Strażnik Świątyni,Guarda do Templo,,Gardian Templu,Страж храма,,Tempelvakt,Tapınak Muhafızı +Oracle,TXT_SPEAKER_ORACLE,,,,Věštec,Orakel,Orakel,,Orakolo,Oráculo,,Oraakkeli,,Orákulum,Oracolo,オラクル,오라클,Orakel,Orakel,Wyrocznia,Oráculo,,Oracol,Оракул,,Orakel,Kahin +Ulaine,TXT_SPEAKER_ULAINE,,,,,,,,,,,,,,,ウレーヌ,울레인,,,,,,,Улейн,,,Ulane +Front Soldier,TXT_SPEAKER_FRONT_SOLDIER,,,,Voják Fronty,Frontsoldat,Front-Soldat,,Soldato de la Fronto,Soldado del Frente,,Rintaman sotilas,Soldat du Front,Front Katona,Soldato del Fronte,フロント ソルジャー,프론트 저항군,,Frontsoldat,Żołnierz Frontu,Soldado da Frente,,Soldat Front,Повстанец,,Frontsoldat,Ön Asker +Programmer,TXT_SPEAKER_PROGRAMMER,,,,Programátor,Programmør,Programmierer,,Programisto,Programador,,Ohjelmoitsija,Programmeur,Programozó,Programmatore,プログラマー,프로그래머,Programmeur,Programmerer,Programista,Programador,,Programator,Программист,,Programmerare,Programcı +Medic,TXT_SPEAKER_MEDIC,,,,Zdravotník,Læge,Sanitäter,,Kuracisto,Médico,,Lääkintämies,Médecin,Szanitéc,Medico,メディック,의무병,Paramedicus,Sanitetssoldat,Medyk,Médico,,,Медик,,Sjukvårdare, +Watchman,TXT_SPEAKER_WATCHMAN,,,,Hlídač,Vagtmand,Wächter,,Gardisto,Guardia,,Vahti,Vigie,Őrszem,Vigilante,警備員,감시병,Waker,Vaktmann,Stróż,Vigia,,Străjer,Караульный,,Väktare,Bekçi +Ketrick,TXT_SPEAKER_KETRICK,,,,,,,,,,,,,,,ケトリック,케트릭,,,,,,,Кетрик,,, +Weran,TXT_SPEAKER_WERAN,,,,,,,,,,,,,,,ウェラン,워렌,,,,,,,Уэран,,, +Advisor,TXT_SPEAKER_ADVISOR,,,Adviser,Rádce,Rådgiver,Berater,,Konsilisto,Consejero,,Neuvonantaja,Conseiller,Tanácsadó,Consigliere,補佐官,조언자,Adviseur,Rådgiver,Doradca,Conselheiro,,Sfetnic,Советник,,Rådgivare,Danışman +Geoff,TXT_SPEAKER_GEOFF,,,,,,,,,,,,,,,ジェフ,제프,,,,,,,Джефф,,,Geoff +Overseer,TXT_SPEAKER_OVERSEER,,,,Dozorčí,Tilsynsførende,Aufseher,,Inspektisto,Supervisor,,Valvoja,Superviseur,Munkavezető,Supervisore,監視人,현장 감독,Opziener,Oppsynsmann,Nadzorca,Supervisor,,Supraveghetor,Надсмотрщик,,Övervakare,Gözetmen Security Comple,TXT_SPEAKER_SECURITY_COMPLE,"Intended to appear in MAP19, but does not spawn. -",,,,Wache,,,Vigía,Vigía,Turvamies,Sécurité,,Guardia del Complesso di Sicurezza,,경비원,Bewaker,Ochroniarz Kompleksu,Vigia,,,Охранник комплекса, -Computer Tech,TXT_SPEAKER_COMPUTER_TECH,,,,Počítačový technik,Computertechniker,,,Ingeniero Informático,Ingeniero Informático,Tietokoneteknikko,Technicien Informatique,,Tecnico Informatico,機械技術者,컴퓨터 기술자,Computertechniek,Technik Komputerowy,Técnico de Informática,,,Компьютерный техник, -MacGuffin,TXT_SPEAKER_MACGUFFIN,,,,,,,,,,,,,,マクガフィン,맥거핀,,,,,,МакГаффин, -Arion,TXT_SPEAKER_ARION,,,,,,,,,,,,,,アリオン,아리온,,,,,,Арион, -Dock Worker,TXT_SPEAKER_DOCK_WORKER,,,,Dělník v docích,Dockarbeiter,,,Trabajador del Muelle,Trabajador del Muelle,Ahtaaja,Docker,,Operaio Portuale,港湾労働者,항구 일꾼,Dokwerker,Pracownik Doku,Operário da Doca,,,Рабочий дока, -Irale,TXT_SPEAKER_IRALE,,,,,,,,,,,,,,イラール,이롤리,,,,,,Ирэйл, -Core Guard,TXT_SPEAKER_CORE_GUARD,,,,Stráž jádra,Wache,,,Guardia del Núcleo,Guardia del Núcleo,Ytimenvartija,Garde du cœur,,Guardia del Cuore,コア ガード,코어 경비병,Kernwacht,Strażnik Rdzenia,Guarda do Núcleo,,,Страж ядра, -Sewer Guard,TXT_SPEAKER_SEWER_GUARD,,,,Stráž stok,Kanalisationswächter,,,Guardia de la Alcantarilla,Guardia de la Alcantarilla,Viemärinvartija,Garde des égouts,,Guardia della Fogna,下水道ガード,하수도 보초병,Rioolwacht,Strażnik Kanałów,Guarda do Esgoto,,,Страж канализации, -Technician,TXT_SPEAKER_TECHNICIAN,,,,Technik,Techniker,,,Técnico,Técnico,Teknikko,Technicien,,Tecnico,技術者,기술자,Technicus,Technik,Técnico,,,Техник, -Guard,TXT_SPEAKER_GUARD,,,,Stráž,Wache,,,Guardia,Guardia,Vartija,Garde,,Guardia,ガード,경비병,Bewaker,Strażnik,Guarda,,,Стражник, -Peasant,TXT_SPEAKER_PEASANT,,,,Rolník,Einwohner,,,Campesino,Campesino,Asukas,Paysan,,Contadino,庶民,민간인,Boer,Kmiot,Cidadão,,,Работник, -Armorer,TXT_SPEAKER_ARMORER,,,Armourer,Kovář,Waffenmeister,,,Armero,Armero,Asemestari,Armurier,,Armiere,兵器係,병기공,Pantser,Płatnerz,Forjador de Armaduras,,,Бронник, -Beldin,TXT_SPEAKER_BELDIN,,,,,,,,,,,,,,ベルディン,벨딘,,,,,,Белдин, -Gerard,TXT_SPEAKER_GERARD,,,,,,,,,,,,,,ジェラルド,제랄드,,,,,,Джерард, -Governor Mourel,TXT_SPEAKER_GOVERNOR_MOUREL,,,,Guvernér Mourel,Gouverneur Mourel,,,Gobernador Mourel,Gobernador Mourel,Kuvernööri Mourel,Gouverneur Mourel,,Governatore Mourel,モーレル知事,모렐 총독,Gouverneur Mourel,Gubernator Mourel,Governador Mourel,,,Губернатор Морел, -Bowyer,TXT_SPEAKER_BOWYER,,,,,,,,,,,,,,ボウヤー,보여,,,,,,Лучник, -Derwin,TXT_SPEAKER_DERWIN,,,,,,,,,,,,,,ダーウィン,더윈,,,,,,Дервин, -,,Strife subtitles,,,,,,,,,,,,,,,,,,,,, -The comet struck our planet without warning. We lost our paradise in a single violent stroke.,TXT_SUB_INTRO1,,,,"Kometa bez varování narazila do naší planety. Ztratili jsme svůj ráj během jediného, brutálního úderu.",Der Komet hat unsen Planeten ohne Vorwarnung getroffen. Wir haben unser Paradies in einem einzelnen brutalen Schlag verloren.,,,El cometa se estrelló en nuestro planeta sin previo aviso. Perdimos nuestro paraíso en un único y violento golpe.,,,"La comète frappa notre monde sans prévenir. En un seul moment de violence, nous avons perdu notre paradis.",,"La cometa colpì il nostro pianeta senza preavviso. Perdemmo il nostro paradiso, in un solo violento colpo.",彗星がこの星に突然衝突した。私達の楽園はこの一撃で失われた。,혜성 하나가 아무런 경고도 없이 우리 행성에 충돌했다. 그 강력한 한 방으로 우리의 낙원을 잃어버렸다.,De komeet raakte onze planeet zonder waarschuwing. We verloren ons paradijs in een enkele gewelddadige beroerte.,,"O cometa atingiu o nosso planeta sem aviso prévio. Num único e violento golpe, nós perdemos o nosso paraíso.",,,"Никто не ожидал, что на нашу планету обрушится метеорит. Земной рай был разрушен единственным безжалостным ударом.", -"The impact released a virus, which swept through the land and killed millions. They turned out to be the lucky ones.",TXT_SUB_INTRO2,,,,"Náraz vypustil virus, který se začal šířit krajem a zabil milióny lidí. Ukázalo se, že to byli ti šťastnější.","Der Einschlag setzte einen Virus frei, der durch das Land fegte und Millionen tötete. Sie hatten Glück.",,,"El impacto liberó un virus, el cual barrió la tierra y mató a millones. Resultaron ser los más afortunados.",,,"L'impact libéra un virus, qui traversa les contrées et tua des millions. Ceux qui moururent furent les plus chanceux.",,"L'impatto rilasciò un virus, spargendosi ovunque e uccidendo milioni. Quelli che morirono furono i più fortunati.","彗星の衝突によりウィルスが世界中に放たれ、数えきれないほどの人々が死んだ。 -今から考えれば、彼らはまだ運がいい方だった。","충돌의 여파로 바이러스가 사방에 퍼졌고, 이로 인해 수백만명이 목숨을 잃었다. 죽은 자들은 운이 좋은 자들이었다.","Door de inslag kwam er een virus vrij, dat door het land veegde en miljoenen doden veroorzaakte. Zij bleken de gelukkigen te zijn.",,"O impacto liberou um vírus, que se espalhou pela terra e matou milhões. Esses foram os que tiveram sorte.",,,"Удар метеорита выпустил вирус, который пронёсся по землям и истребил миллионы людей. Умершие оказались счастливчиками.", -"For those who did not die became mutations of humanity. Some became fanatics who heard the voice of a malignant god in their heads and called themselves ""the Order"".",TXT_SUB_INTRO3,,,,"Protože ti, kteří nezemřeli, se stali lidskými mutanty. Někteří se proměnili ve fanatiky, kteří v hlavě slyšeli hlas zlého boha, a začali si říkat „Řád“.","Diejenigen, die nicht starben, wurden zu Mutanten der Menschheit. Einige wurden Fanatiker, die die Stimme eines bösartigen Gottes in ihrem Kopf hörten und sie nannten sich „Der Orden“.",,,"Ya que aquellos que no murieron se convirtieron en mutaciones de humanidad. Algunos se volvieron fanáticos que oían la voz de un dios maligno en sus cabezas y se hicieron llamar ""la Orden"".",,,"Ceux qui survécurent devinrent les mutants de l'humanité. Certains devinrent des fanatiques qui écoutent la voix d'un dieu maléfique dans leur tête, et se nommèrent « L'Ordre ».",,"Coloro che sopravvissero divennero i mutanti dell'umanità. Alcuni sono diventati fanatici che hanno ascoltato la voce di un dio malvagio nelle loro teste e si sono fatti chiamare ""L'Ordine"".","死ななかった人々は、人間から変異して別の物となった。 +",,,,Sikkerhedskomplet,Wache,,Gardisto de la sekurkomplekso,Guardia del complejo,,Turvamies,Sécurité,Védelmi Kvártély,Guardia del Complesso di Sicurezza,,경비원,Bewaker,Security Comple,Ochroniarz Kompleksu,Vigia,,Paznic Complex de Securitate,Охранник комплекса,,Säkerhetskompetens,Güvenlik Comple +Computer Tech,TXT_SPEAKER_COMPUTER_TECH,,,,Počítačový technik,,Computertechniker,,Komputilisto,Técnico de sistemas,,Tietokoneteknikko,Technicien Informatique,Számítógép Tech,Tecnico Informatico,機械技術者,컴퓨터 기술자,Computertechniek,Datatekniker,Technik Komputerowy,Técnico de Informática,,Tehnician Calculatoare,Компьютерный техник,,Datortekniker,Bilgisayar Teknolojisi +MacGuffin,TXT_SPEAKER_MACGUFFIN,,,,,,,,Makgufino,,,,,,,マクガフィン,맥거핀,,,,,,,Макгаффин,,, +Arion,TXT_SPEAKER_ARION,,,,,,,,,,,,,,,アリオン,아리온,,,,,,,Арион,,,Aron +Dock Worker,TXT_SPEAKER_DOCK_WORKER,,,,Přístavní dělník,Dokarbejder,Dockarbeiter,,Stivisto,Estibador,,Ahtaaja,Docker,Dokk munkás,Operaio Portuale,港湾労働者,항구 일꾼,Dokwerker,Havnearbeider,Pracownik Doku,Operário da Doca,,Muncitor Docuri,Рабочий дока,,Hamnarbetare,Liman İşçisi +Irale,TXT_SPEAKER_IRALE,,,,,,,,,,,,,,,イラール,이롤리,,,,,,,Ирэйл,,,İrale +Core Guard,TXT_SPEAKER_CORE_GUARD,,,,Stráž jádra,Kernevagt,Wache,,Gardisto de la kerno,Guardia del núcleo,,Ytimenvartija,Garde du cœur,Mag Őr,Guardia del Cuore,コア ガード,코어 경비병,Kernwacht,Kjernevakt,Strażnik Rdzenia,Guarda do Núcleo,,Gardian Nucleu,Страж ядра,,Kärnvårdsvakt,Çekirdek Koruma +Sewer Guard,TXT_SPEAKER_SEWER_GUARD,,,,Kanální stráž,Kloakvagt,Kanalisationswächter,,Gardisto de la kloako,Guardia de las alcantarillas,,Viemärinvartija,Garde des égouts,Kanális Őr,Guardia della Fogna,下水道ガード,하수도 보초병,Rioolwacht,Kloakkvakt,Strażnik Kanałów,Guarda do Esgoto,,Gardian Canal,Страж канализации,,Avloppsvakt,Kanalizasyon Görevlisi +Technician,TXT_SPEAKER_TECHNICIAN,,,,Technik,Tekniker,Techniker,,Teknikisto,Técnico,,Teknikko,Technicien,Technikus,Tecnico,技術者,기술자,Technicus,Tekniker,Technik,Técnico,,Tehnician,Техник,,Tekniker,Teknisyen +Guard,TXT_SPEAKER_GUARD,,,,Stráž,Vagt,Wache,,Gardisto,Guardia,,Vartija,Garde,Őr,Guardia,ガード,경비병,Bewaker,Vakt,Strażnik,Guarda,,Gardian,Стражник,,Väktare,Muhafız +Peasant,TXT_SPEAKER_PEASANT,,,,Rolník,Bonde,Einwohner,,Kamparano,Campesino,,Maallikko,Paysan,Jobbágy,Cittadino,庶民,민간인,Boer,Bonde,Kmiot,Cidadão,,Sărman,Работник,,Bonde,Köylü +Armorer,TXT_SPEAKER_ARMORER,,,Armourer,Kovář,Våbenmekaniker,Waffenmeister,,Armilisto,Armero,,Asemestari,Armurier,Fegyverkovács,Armiere,兵器係,병기공,Pantser,Væpner,Płatnerz,Forjador de Armaduras,,Armurier,Бронник,,Rusthållare,Zırhçı +Beldin,TXT_SPEAKER_BELDIN,,,,,,,,,,,,,,,ベルディン,벨딘,,,,,,,Белдин,,, +Gerard,TXT_SPEAKER_GERARD,,,,,,,,Gerardo,,,,,,,ジェラルド,제랄드,,,,,,,Джерард,,, +Governor Mourel,TXT_SPEAKER_GOVERNOR_MOUREL,,,,Guvernér Mourel,Guvernør Mourel,Gouverneur Mourel,,Registo Mourel,Gobernador Mourel,,Kuvernööri Mourel,Gouverneur Mourel,Mourel kormányzó,Governatore Mourel,モーレル知事,모렐 총독,Gouverneur Mourel,Guvernør Mourel,Gubernator Mourel,Governador Mourel,,Guvernatorul Mourel,Губернатор Морел,,Guvernör Mourel,Vali Mourel +Bowyer,TXT_SPEAKER_BOWYER,,,,,,,,,,,,,,,ボウヤー,보여,,,,,,,Лучник,,, +Derwin,TXT_SPEAKER_DERWIN,,,,,,,,,,,,,,,ダーウィン,더윈,,,,,,,Дервин,,, +,,Strife subtitles,,,,,,,,,,,,,,,,,,,,,,,,, +The comet struck our planet without warning. We lost our paradise in a single violent stroke.,TXT_SUB_INTRO1,Menu's intro.,,,"Kometa bez varování narazila do naší planety. Jediným, brutálním úderem jsme přišli o náš ráj.",Kometen ramte vores planet uden varsel. Vi mistede vores paradis i et enkelt voldsomt slag.,Der Komet hat unsen Planeten ohne Vorwarnung getroffen. Wir haben unser Paradies in einem einzelnen brutalen Schlag verloren.,,,El cometa se estrelló en nuestro planeta sin previo aviso. Perdimos nuestro paraíso en un único y violento golpe.,,Komeetta iski planeettaamme varoittamatta. Menetimme paratiisimme rajulla kertarysäyksellä.,"La comète frappa notre monde sans prévenir. En un seul moment de violence, nous avons perdu notre paradis.",Egy üstökös csapódott be a bolygónkba minden előjel nélkül. Egy heves vágással elveszítettük az addigi paradicsomi életünket.,"La cometa colpì il nostro pianeta senza preavviso. Perdemmo il nostro paradiso, in un solo violento colpo.",彗星がこの星に突然衝突した。私達の楽園はこの一撃で失われた。,혜성 하나가 아무런 경고도 없이 우리 행성에 충돌했다. 그 강력한 한 방으로 우리의 낙원을 잃어버렸다.,De komeet raakte onze planeet zonder waarschuwing. We verloren ons paradijs in een enkele gewelddadige beroerte.,Kometen traff planeten vår uten forvarsel. Vi mistet paradiset vårt med ett voldsomt slag.,Kometa uderzyła w naszą planetę bez ostrzeżenia. Straciliśmy nasz raj w jednym gwałtownym uderzeniu.,"O cometa atingiu o nosso planeta sem aviso prévio. Num único e violento golpe, nós perdemos o nosso paraíso.",,Cometa ne-a izbit planeta în mod violent. Ne-am pierdut paradisul într-o clipă.,"Никто не ожидал, что на нашу планету обрушится метеорит. Земной рай был разрушен единственным безжалостным ударом.",,Kometen träffade vår planet utan förvarning. Vi förlorade vårt paradis i ett enda våldsamt slag.,Kuyruklu yıldız gezegenimize uyarı vermeden çarptı. Cennetimizi tek bir şiddetli darbeyle kaybettik. +"The impact released a virus, which swept through the land and killed millions. They turned out to be the lucky ones.",TXT_SUB_INTRO2,〃,,,"Náraz vypustil virus, který se začal šířit krajem a zabil miliony lidí. Ukázalo se, že to byli ti šťastnější.","Sammenstødet frigjorde en virus, som fejede gennem landet og dræbte millioner af mennesker. De viste sig at være de heldige.","Der Einschlag setzte einen Virus frei, der durch das Land fegte und Millionen tötete. Sie hatten Glück.",,,"El impacto liberó un virus, el cual barrió la tierra y mató a millones. Resultaron ser los más afortunados.",,"Törmäys päästi valloilleen viruksen, joka pyyhkäisi halki maan ja tappoi miljoonia. He osoittautuivat kuuluneensa onnekkaiden joukkoon.","L'impact libéra un virus, qui traversa les contrées et tua des millions. Ceux qui moururent furent les plus chanceux.","A becsapódás egy vírust eresztett a világra, mely milliókat ölt meg. Ők voltak a szerencsésebbek.","L'impatto rilasciò un virus, spargendosi ovunque e uccidendo milioni. Quelli che morirono furono i più fortunati.","彗星の衝突によりウィルスが世界中に放たれ、数えきれないほどの人々が死んだ。 +今から考えれば、彼らはまだ運がいい方だった。","충돌의 여파로 바이러스가 사방에 퍼졌고, 이로 인해 수백만명이 목숨을 잃었다. 죽은 자들은 운이 좋은 자들이었다.","Door de inslag kwam er een virus vrij, dat door het land veegde en miljoenen doden veroorzaakte. Zij bleken de gelukkigen te zijn.",Nedslaget utløste et virus som feide gjennom landet og drepte millioner. De viste seg å være de heldige.,"Uderzenie uwolniło wirusa, który przetoczył się przez ziemię i zabił miliony. Okazało się, że byli to ci, którzy mieli szczęście.","O impacto liberou um vírus, que se espalhou pela terra e matou milhões. Esses foram os que tiveram sorte.",,"Impactul a lansat un virus, care a măturat pământul și omorât milioane. Aparent ei au fost cei norocoși.","Удар метеорита выпустил вирус, который пронёсся по землям и истребил миллионы людей. Умершие оказались счастливчиками.",,Genom nedslaget frigjordes ett virus som svepte genom landet och dödade miljontals människor. De visade sig vara de lyckligt lottade.,Çarpışmanın etkisiyle bir virüs salındı ve bu virüs tüm dünyayı kasıp kavurarak milyonları öldürdü. Onlar şanslı olanlardı. +"For those who did not die became mutations of humanity. Some became fanatics who heard the voice of a malignant god in their heads and called themselves ""the Order"".",TXT_SUB_INTRO3,〃,,,"Ti, kteří nezemřeli, se totiž stali lidskými mutanty. Někteří se proměnili ve fanatiky, kteří v hlavě začali slyšet hlas zlého boha, a začali si říkat „Řád“.","For de, der ikke døde, blev til mutationer af menneskeheden. Nogle blev fanatikere, der hørte en ondskabsfuld guds stemme i deres hoveder og kaldte sig selv ""Ordenen"".","Diejenigen, die nicht starben, wurden zu Mutanten der Menschheit. Einige wurden Fanatiker, die die Stimme eines bösartigen Gottes in ihrem Kopf hörten und sie nannten sich „Der Orden“.",,,"Ya que aquellos que no murieron se convirtieron en mutaciones de humanidad. Algunos se volvieron fanáticos que oían la voz de un dios maligno en sus cabezas y se hicieron llamar ""la Orden"".",,"Sillä niistä, jotka eivät kuolleet, tuli ihmiskunnan mutaatioita. Joistakin tuli kiihkoilijoita, jotka kuulivat päässään pahansuovan jumalan äänen ja kutsuivat itseään ""Veljeskunnaksi"".","Ceux qui survécurent devinrent les mutants de l'humanité. Certains devinrent des fanatiques qui écoutent la voix d'un dieu maléfique dans leur tête, et se nommèrent « L'Ordre ».","Akik nem haltak meg, emberi mutánsokká válltak. Voltak akik fanatikussá válltak, fejükbe hallották egy gonosz isten szavait, és a ""Rend"" néven hívták magukat.","Coloro che sopravvissero divennero i mutanti dell'umanità. Alcuni sono diventati fanatici che hanno ascoltato la voce di un dio malvagio nelle loro teste e si sono fatti chiamare ""L'Ordine"".","死ななかった人々は、人間から変異して別の物となった。 一部の人々は、頭の中に邪悪な神の声を伝えられた狂信者となり、 -自らの集団を'オーダー'と呼んだ。","죽지 않은 자들에겐 큰 변화가 일어났다. 몇몇은 머릿속으로 악독한 신의 목소리를 듣기 시작했고, 이 광신도들은 그들 자신을 “오더”라고 지칭했다.","Voor degenen die niet stierven werden mutaties van de mensheid. Sommigen werden fanatiekelingen die de stem van een kwaadaardige god in hun hoofd hoorden en zichzelf ""de Orde"" noemden.",,"Aqueles que sobreviveram se tornaram mutações de humanidade. Alguns se tornaram fanáticos que ouviam em suas cabeças a voz de um deus malígno e passaram a se chamar ""a Ordem"".",,,"Выжившие сформировали уродливое подобие прежнего общества. Некоторые услышали голос зловещего бога и стали фанатиками, называющими себя «Орденом».", -Those of us who are deaf to this voice suffer horribly and are forced to serve these ruthless psychotics who wield weapons more powerful than anything we can muster.,TXT_SUB_INTRO4,,,,"Ti z nás, kdo jsou vůči tomuto hlasu hluší příšerně trpí a jsou nuceni sloužit těmto bezcitným šílencům, kteří vládnou zbraněmi, proti kterým nemáme šanci se bránit.","Jene, die dieser Stimme gegenüber taub sind, leiden schrecklich und sind gezwungen diesen unbarmherzigen Irren zu dienen. Sie haben Waffen die stärker sind als das, was wir aufbringen können.",,,Aquellos de nosotros sordos a esta voz sufrimos horriblemente y somos forzados a servir a estos psicópatas despiadados que poseen armas más poderosas que cualesquiera que podamos conseguir.,,,Ceux sourds à sa voix souffrent horriblement et sont forcés à vivre au services de ces vicieux psychopathes qui utilisent des armes plus puissantes que tout ce que nous avons.,,Quelli sordi alla sua voce soffrono orribilmente e sono costretti a vivere al servizio di questi malvagi psicopatici che usano armi più potenti di ogni cosa che noi abbiamo.,"その神の声を聞き取れなかった私達は苦しんだ挙げ句、 +自らの集団を'オーダー'と呼んだ。","죽지 않은 자들에겐 큰 변화가 일어났다. 몇몇은 머릿속으로 악독한 신의 목소리를 듣기 시작했고, 이 광신도들은 그들 자신을 “오더”라고 지칭했다.","Voor degenen die niet stierven werden mutaties van de mensheid. Sommigen werden fanatiekelingen die de stem van een kwaadaardige god in hun hoofd hoorden en zichzelf ""de Orde"" noemden.","For de som ikke døde, ble mutasjoner av menneskeheten. Noen ble fanatikere som hørte stemmen til en ondartet gud i hodet og kalte seg ""Ordenen"".","Ci bowiem, którzy nie zginęli, stali się mutacjami ludzkości. Niektórzy stali się fanatykami, którzy słyszeli w swoich głowach głos złośliwego boga i nazywali siebie ""Zakonem"".","Aqueles que sobreviveram se tornaram mutações de humanidade. Alguns se tornaram fanáticos que ouviam em suas cabeças a voz de um deus malígno e passaram a se chamar ""a Ordem"".",,"Pentru că cei care nu au murit au ajuns mutanți. Unii au devenit fanatici care au auzit vocea unui zeu perfid în capul lor și s-au numit ""Ordinul"".","Выжившие сформировали уродливое подобие прежнего общества. Некоторые услышали голос зловещего бога и стали фанатиками, называющими себя «Орденом».",,"För de som inte dog blev mutationer av mänskligheten. Några blev fanatiker som hörde en ondskefull guds röst i sina huvuden och kallade sig själva för ""Orden"".","Ölmeyenler ise insanlığın mutasyonları oldular. Bazıları kafalarının içinde kötücül bir tanrının sesini duyan ve kendilerine ""Düzen"" diyen fanatikler haline geldi." +Those of us who are deaf to this voice suffer horribly and are forced to serve these ruthless psychotics who wield weapons more powerful than anything we can muster.,TXT_SUB_INTRO4,〃,,,"Ti z nás, kdo jsou vůči tomuto hlasu hluší, příšerně trpí a jsou nuceni sloužit těmto bezcitným šílencům, kteří vládnou zbraněmi, proti kterým nemáme šanci se bránit.","De af os, der er døve for denne stemme, lider forfærdeligt og er tvunget til at tjene disse hensynsløse psykopater, der svinger våben, der er stærkere end alt, hvad vi kan mønstre.","Jene, die dieser Stimme gegenüber taub sind, leiden schrecklich und sind gezwungen diesen unbarmherzigen Irren zu dienen. Sie haben Waffen die stärker sind als das, was wir aufbringen können.",,,Aquellos incapaces de oír esa voz sufrimos horriblemente y somos forzados a servir a estos psicopáticos despiadados que poseen armas más poderosas que cualesquiera que podamos conseguir.,,"Meistä ne, jotka ovat kuuroja tälle äänelle, kärsivät valtavasti ja joutuvat palvelemaan näitä häikäilemättömiä sekopäitä, jotka pitävät hallussaan voimakkaampia aseita kuin me ikinä kykenemme käsiimme saamaan.",Ceux sourds à sa voix souffrent horriblement et sont forcés à vivre au services de ces vicieux psychopathes qui utilisent des armes plus puissantes que tout ce que nous avons.,"Azok akik nem hallják ezeket a hangokat megszenvedik azt, és arra vannak kárhoztatva, hogy ezeket az isten feletti fegyverekkel rendelkező kegyetlen elmebetegeket szolgálják.",Quelli sordi alla sua voce soffrono orribilmente e sono costretti a vivere al servizio di questi malvagi psicopatici che usano armi più potenti di ogni cosa che noi abbiamo.,"その神の声を聞き取れなかった私達は苦しんだ挙げ句、 この無慈悲な狂人どもに仕えるのを強いられた。 -そして奴等は、私達のどんな武器とも比べ物にならないほど強力な兵器を持っているのだ。","신의 목소리를 듣지 못하는 자들은 끔찍한 고통에 시달렸고, 우리가 가진 어떤 무기들보다 강력한 무장을 한 이 무자비한 광신도들을 강제로 섬기게 되었다.","Degenen onder ons die doof zijn voor deze stem lijden vreselijk en worden gedwongen om deze meedogenloze psychoten te dienen, die wapens gebruiken die krachtiger zijn dan alles wat we kunnen verzamelen.",,Nós que não ouvimos essa voz sofremos terrívelmente e somos forçados a servir a esses psicopatas impiedosos que possuem armas mais poderosas do que qualquer coisa ao nosso alcance.,,,"Другие — те, кто не слышал этого голоса, — терпели лишения. Их заставили прислуживать этим безжалостным психопатам, чьё оружие превосходило любое наше.", -They destroy our women and children so that we must hide them underground and live like animals in constant fear for our lives.,TXT_SUB_INTRO5,,,,"Zabíjí naše ženy a děti, takže je musíme ukrývat v podzemí a nechat je žít jako zvířata v neutrvajícím strachu o naše životy.","Sie zerstören unsere Frauen und Kinder, sodass wir uns im Untergrund verstecken müssen, wie die Tiere leben und ständig um unser Leben zu bangen.",,,Destruyen a nuestras mujeres y niños por lo que debemos esconderlos bajo tierra y vivir como animales temiendo constantemente por nuestras vidas.,,,"Ils ont anéanti nos femmes et nos enfants et nous ont forcés à vivre sous terre comme des animaux, terrifiés de perdre nos vies.",,"Distruggono le nostre donne e bambini, per cui li dobbiamo nascondere nel sottosuolo e vivere come animali in una paura costante per le nostre vite.","奴等は女性や子供を殺害していくため、私達はそういった人々を地下に隠さなければならなかった。 -我々は動物のように暮らすのを強いられ、命は常に危険に晒されている。","그들은 우리의 여자와 아이들을 죽였고, 우리는 살아남은 자들을 지하로 대피시켜 죽음의 공포 속에서 짐승처럼 살아가야 했다.",Ze vernietigen onze vrouwen en kinderen zodat we ze ondergronds moeten verbergen en als dieren moeten leven in voortdurende angst voor ons leven.,,"Eles destroem nossas mulheres e crianças e por isso nós temos que escondê-las no subterrâneo e viver como animais, temendo constantemente por nossas vidas.",,,"Они истребляют наших женщин и детей, и нам приходится прятать их в подземелье. Мы живём в постоянном страхе за свою жизнь, как животные.", -"But there are whispers of discontent. If we organize, can we defeat our masters? Weapons are being stolen, soldiers are being trained. A movement is born: born of lifelong strife!",TXT_SUB_INTRO6,,,,"Objevují se však nesouhlasné šepoty. Pokud se uspořádáme, můžeme porazit naše pány? Kradou se zbraně, cvičí se vojáci. Zrodilo se hnutí: Zrodilo se z věčného sváru!","Aber es gibt Zeichen der Unzufriedenheit. Wenn wir uns organisieren, können wir unsere Meister besiegen? Waffen werden gestohlen, Soldaten ausgebildet. Eine Bewegung wurde geboren: Geboren aus dem ewigen Konflikt!",,,"Pero hay susurros de descontento. Si nos organizamos, ¿podemos derrotar a nuestros maestros? Se están robando armas, se entrenan soldados. Un movimiento nace - ¡nacido de una lucha de por vida!",,,"Mais il y a des murmures de colère qui subsistent. Si nous nous organisons, pouvons nous nous défaire de nos maîtres? Des armes sont volées, des soldats entraînés. Un mouvement est né, né d'un combat sans fin!",,"Ma ci sono voci di discontento. Se ci organizzassimo, potremmo sconfiggere i nostri padroni? Vengono rubate le armi, vengono allenati i soldati. È nato un movimento: nato da un eterno conflitto!","だが不満のささやきは常にある。もし私達が力を合わせれば、 +そして奴等は、私達のどんな武器とも比べ物にならないほど強力な兵器を持っているのだ。","신의 목소리를 듣지 못하는 자들은 끔찍한 고통에 시달렸고, 우리가 가진 어떤 무기들보다 강력한 무장을 한 이 무자비한 광신도들을 강제로 섬기게 되었다.","Degenen onder ons die doof zijn voor deze stem lijden vreselijk en worden gedwongen om deze meedogenloze psychoten te dienen, die wapens gebruiken die krachtiger zijn dan alles wat we kunnen verzamelen.","De av oss som er døve for denne stemmen, lider forferdelig og er tvunget til å tjene disse hensynsløse psykotiske som bruker våpen som er kraftigere enn noe vi kan mønstre.","Ci z nas, którzy są głusi na ten głos, cierpią okropnie i są zmuszeni służyć tym bezwzględnym psychotom, którzy władają bronią potężniejszą niż wszystko, co jesteśmy w stanie zebrać.",Nós que não ouvimos essa voz sofremos terrívelmente e somos forçados a servir a esses psicopatas impiedosos que possuem armas mais poderosas do que qualquer coisa ao nosso alcance.,,Noi cei care suntem surzi și nu auzim vocea suferim oribil și suntem forțați să servin pe acești psihopați care cârmuie arme mai puternice decat orice avem.,"Другие — те, кто не слышал этого голоса, — терпели лишения. Их заставили прислуживать этим безжалостным психопатам, чьё оружие превосходило любое наше.",,De av oss som är döva för denna röst lider fruktansvärt och tvingas tjäna dessa hänsynslösa psykopater som svingar vapen som är kraftfullare än allt vi kan uppbåda.,Bu sese kulaklarını tıkayan bizler ise korkunç acılar çekiyor ve ellerinde toplayabileceğimiz her şeyden daha güçlü silahlar olan bu acımasız psikopatlara hizmet etmek zorunda kalıyoruz. +They destroy our women and children so that we must hide them underground and live like animals in constant fear for our lives.,TXT_SUB_INTRO5,〃,,,"Zabíjí naše ženy a děti, takže je musíme ukrývat v podzemí a nechávat je žít jako zvířata v neutrvajícím strachu o naše životy.","De ødelægger vores kvinder og børn, så vi må gemme dem under jorden og leve som dyr i konstant frygt for vores liv.","Sie zerstören unsere Frauen und Kinder, sodass wir uns im Untergrund verstecken müssen, wie die Tiere leben und ständig um unser Leben zu bangen.",,,Destruyen a nuestras mujeres y niños por lo que debemos esconderlos bajo tierra y vivir como animales temiendo constantemente por nuestras vidas.,,"He tuhoavat naisemme ja lapsemme, niin että joudumme kätkemään heidät maan alle ja elämään kuin elukat jatkuvassa pelossa henkemme puolesta.","Ils ont anéanti nos femmes et nos enfants et nous ont forcés à vivre sous terre comme des animaux, terrifiés de perdre nos vies.","Megölik a nőinket és gyermekeinket, ezért a föld alatt kell rejtegetnünk őket, és úgy kell élnünk mint az életét féltő állatoknak.","Distruggono le nostre donne e bambini, per cui li dobbiamo nascondere nel sottosuolo e vivere come animali in una paura costante per le nostre vite.","奴等は女性や子供を殺害していくため、私達はそういった人々を地下に隠さなければならなかった。 +我々は動物のように暮らすのを強いられ、命は常に危険に晒されている。","그들은 우리의 여자와 아이들을 죽였고, 우리는 살아남은 자들을 지하로 대피시켜 죽음의 공포 속에서 짐승처럼 살아가야 했다.",Ze vernietigen onze vrouwen en kinderen zodat we ze ondergronds moeten verbergen en als dieren moeten leven in voortdurende angst voor ons leven.,De ødelegger våre kvinner og barn slik at vi må gjemme dem under jorden og leve som dyr i konstant frykt for våre liv.,"Niszczą nasze kobiety i dzieci tak, że musimy ukrywać je pod ziemią i żyć jak zwierzęta w ciągłym strachu o nasze życie.","Eles destroem nossas mulheres e crianças e por isso nós temos que escondê-las no subterrâneo e viver como animais, temendo constantemente por nossas vidas.",,"Ne distrug femeile și copiii pentru ca noi să ne ascundem sub pământ și să trăim ca animalele, constant în teamă pentru virțiile noastre.","Они истребляют наших женщин и детей, и нам приходится прятать их в подземелье. Мы живём в постоянном страхе за свою жизнь, как животные.",,De förstör våra kvinnor och barn så att vi måste gömma dem under jorden och leva som djur i ständig rädsla för våra liv.,"Kadınlarımızı ve çocuklarımızı yok ediyorlar, böylece onları yeraltına saklamak ve hayatlarımız için sürekli korku içinde hayvanlar gibi yaşamak zorunda kalıyoruz." +"But there are whispers of discontent. If we organize, can we defeat our masters? Weapons are being stolen, soldiers are being trained. A movement is born: born of lifelong strife!",TXT_SUB_INTRO6,〃,,,"Vynořují se však nesouhlasná šeptání. Pokud se seskupíme, můžeme porazit naše pány? Kradou se zbraně, cvičí se vojáci. Zrodilo se hnutí, zrozené z věčného sváru!","Men der er hvisken af utilfredshed. Hvis vi organiserer os, kan vi så besejre vores herrer? Våben bliver stjålet, soldater bliver uddannet. En bevægelse er født: født af livslange stridigheder!","Aber es gibt Zeichen der Unzufriedenheit. Wenn wir uns organisieren, können wir unsere Meister besiegen? Waffen werden gestohlen, Soldaten ausgebildet. Eine Bewegung wurde geboren: Geboren aus dem ewigen Konflikt!",,,"Pero hay susurros de descontento. Si nos organizamos, ¿podemos derrotar a nuestros maestros? Se están robando armas, se entrenan soldados. Un movimiento nace - ¡nacido de una lucha de por vida!",,"Mutta tyytymättömyyden äänet kuiskailevat. Jos järjestäydymme, kykenemmekö päihittämään valtiaamme? Aseita anastetaan, sotilaita koulutetaan. Liike on syntynyt, syntynyt elinikäisestä taistelusta!","Mais il y a des murmures de colère qui subsistent. Si nous nous organisons, pouvons nous nous défaire de nos maîtres? Des armes sont volées, des soldats entraînés. Un mouvement est né, né d'un combat sans fin!","Azonban zúgolódó sutyorgásokat hallani. Ha összefogunk vajon legyőzhetjük elnyomóinkat? Fegyvereket lopkodunk, katonákat képzünk. Egy mozgalom születik: az emberöltőnyi küzdelem születik!","Ma ci sono voci di discontento. Se ci organizzassimo, potremmo sconfiggere i nostri padroni? Vengono rubate le armi, vengono addestrati i soldati. È nato un movimento: nato da un eterno conflitto!","だが不満のささやきは常にある。もし私達が力を合わせれば、 支配者たちを倒すことができるだろうか? 奴等の武器は盗まれ続けていて、 我らの兵士たちは訓練され続けている。 -革命への動きは生まれたのだ- 終わりなき闘争(Strife)から!","그러나 불만의 목소리가 커졌다. 우리가 단결하면, 우리의 주인을 물리칠 수 있을까? 그들의 무기를 훔치고, 병사들을 훈련해서 우리의 평생을 바칠 투쟁이 시작된 것이다!","Maar er wordt gefluisterd van ontevredenheid. Als we ons organiseren, kunnen we dan onze meesters verslaan? Wapens worden gestolen, soldaten worden getraind. Een beweging is geboren: geboren uit levenslange strijd!",,"Mas há sussurros de descontentamento. Se nós nos organizarmos, será que podemos derrotar os nossos mestres? Armas estão sendo roubadas, soldados estão sendo treinados. Um movimento está nascendo. Nascendo por meio de um conflito sem fim!",,,"Но шёпот недовольства растёт. Сможем ли мы свергнуть их господство, если объединимся? Мы крадём их оружие, и наши бойцы проходят подготовку. Движение родилось — родилось из борьбы длиною в жизнь!", -"Attention, all troops of the Front: he's done it! It's over. Blackbird's soldier has killed the Evil. The Order is no more. Blackbird, do you read me?",TXT_SUB_GOOD1,,,,"Pozor, všechny jednotky Fronty: On to dokázal! Je konec. Straččin voják zabil Zlo. Řád už není. Strako, slyšíš mě?","Achtung, alle Truppen der Front: Er hat es getan! Es ist vorbei.Blackbirds Soldat hat das Böse vernichtet. Den Orden gibt es nicht mehr. Blackbird, kannst du mich hören?",,,"Atención, todas las tropas del Frente: ¡lo ha hecho! Se acabó. El soldado de Blackbird ha matado al Mal. Es el fin de la Orden. Blackbird, ¿me recibes?",,,"Attention à toutes les troupes du Front: Nous avons réussi! C'est fini, le soldat de Blackbird a anéanti le mal. L'Ordre est sur le point de s'effondrer. Blackbird, me recevez-vous?",,"Attenzione a tutte le truppe del Fronte: ce l'ha fatta! È finita. Il soldato di Blackbird ha ucciso il Male. L'Ordine non esiste più. Blackbird, mi leggi?","フロントの兵士たちよ、聞きたまえ! 彼がすべてを終わらせたのだ。 +革命への動きは生まれたのだ- 終わりなき闘争(Strife)から!","그러나 불만의 목소리가 커졌다. 우리가 단결하면, 우리의 주인을 물리칠 수 있을까? 그들의 무기를 훔치고, 병사들을 훈련해서 우리의 평생을 바칠 투쟁이 시작된 것이다!","Maar er wordt gefluisterd van ontevredenheid. Als we ons organiseren, kunnen we dan onze meesters verslaan? Wapens worden gestolen, soldaten worden getraind. Een beweging is geboren: geboren uit levenslange strijd!","Men det hviskes om misnøye. Hvis vi organiserer oss, kan vi beseire våre herrer? Våpen blir stjålet, soldater blir trent. En bevegelse er født: født av livslang strid!","Ale są szepty niezadowolenia. Jeśli się zorganizujemy, czy uda nam się pokonać naszych panów? Broń jest kradziona, żołnierze są szkoleni. Rodzi się ruch: zrodzony z życiowej walki!","Mas há sussurros de descontentamento. Se nós nos organizarmos, será que podemos derrotar os nossos mestres? Armas estão sendo roubadas, soldados estão sendo treinados. Um movimento está nascendo. Nascendo por meio de um conflito sem fim!",,"Dar există șoapte ale neliniștii. Dacă ne organizam, am putea să ne înfrângem stăpânii? Armele sunt furate, soldații antrenați. O mișcare se naște: născută din suferința de o viață!","Но шёпот недовольства растёт. Сможем ли мы свергнуть их господство, если объединимся? Мы крадём их оружие, и наши бойцы проходят подготовку. Движение родилось — родилось из борьбы длиною в жизнь!",,"Men det finns viskningar av missnöje. Om vi organiserar oss kan vi besegra våra herrar? Vapen stjäls, soldater utbildas. En rörelse är född: född av livslång strid!","Ama hoşnutsuzluk fısıltıları var. Eğer örgütlenirsek, efendilerimizi yenebilir miyiz? Silahlar çalınıyor, askerler eğitiliyor. Bir hareket doğuyor: yaşam boyu süren mücadeleden doğuyor!" +"Attention, all troops of the Front: he's done it! It's over. Blackbird's soldier has killed the Evil. The Order is no more. Blackbird, do you read me?",TXT_SUB_GOOD1,Best ending.,,,"Pozor, všechny jednotky Fronty: On to dokázal! Je konec. Straččin voják zabil Zlo. Řád už není. Strako, slyšíš mě?","Hør efter, alle fronttropper: Han har gjort det! Det er slut. Blackbird's soldat har dræbt Ondskaben. Ordenen er ikke mere. Blackbird, kan du høre mig?","Achtung, alle Truppen der Front: Er hat es getan! Es ist vorbei.Blackbirds Soldat hat das Böse vernichtet. Den Orden gibt es nicht mehr. Blackbird, kannst du mich hören?",,,"Atención, todas las tropas del Frente: ¡lo ha hecho! Se acabó. El soldado de Blackbird ha matado al Mal. Es el fin de la Orden. Blackbird, ¿me recibes?",,"Huomio, kaikki Rintaman joukot: Hän teki sen! Se on ohi; Blackbirdin sotilas on tappanut Pahan. Veljeskuntaa ei enää ole. Blackbird, kuuletko minua?","Attention à toutes les troupes du Front: Nous avons réussi! C'est fini, le soldat de Blackbird a anéanti le mal. L'Ordre est sur le point de s'effondrer. Blackbird, me recevez-vous?","Figyelem a Front összes katonájának: megcsinálta! Vége van. Feketerigó katonája megölte magát a gonoszt. A rend nincs többé. Feketerigó, veszed az adást?","Attenzione a tutte le truppe del Fronte: ce l'ha fatta! È finita. Il soldato di Blackbird ha ucciso il Male. L'Ordine non esiste più. Blackbird, mi senti?","フロントの兵士たちよ、聞きたまえ! 彼がすべてを終わらせたのだ。 もうこれで何もかも終わりだ。ブラックバードの兵士が悪を滅ぼしたのだ。 -オーダーはもう存在しない。ブラックバード、聞こえるか?","프론트의 모든 병사는 주목하라. 그가 해냈다! 모든 것이 끝났다. 블랙버드의 병사가 악을 물리치고, 오더는 끝장이 났다. 블랙버드, 내 말 듣고 있나?","Opgelet, alle troepen van het Front: hij heeft het gedaan! Het is voorbij. Blackbird's soldaat heeft het Kwaad gedood. De Orde is niet meer. Blackbird, hoort jou mij?",,"Atenção, todas as tropas da Frente: ele conseguiu! Está tudo acabado. O soldado de Blackbird matou o Mal. A Ordem não existe mais. Blackbird, consegue me ouvir?",,,"Внимание, всем войскам Фронта! Он справился! Всё кончено! Солдат Чёрного дрозда покончил со злом! Ордена больше нет! Чёрный дрозд, как слышите?", -"I knew you would win, my gallant hero. All fighting has stopped. Your victory will allow us to create a vaccine to purge the virus from our bodies.",TXT_SUB_GOOD2,,,,"Já věděla, že vyhraješ, můj statečný hrdino. Všechen boj ustal. Tvé vítězství nám umožní vyrobit vakcínu, která naše těla vyčistí od viru.","Ich wusste, dass du gewinnen würdest, mein edler Held. Die Kämpfe haben aufgehört. Dein Sieg wird es uns erlauben einen Impfstoff herzustellen, mit dem wir den Virus in unseren Körper bekämpfen können.",,,"Sabía que ganarías, my valiente héroe. La lucha ha terminado. Tu victoria nos permitirá crear una vacuna para purgar el virus de nuestros cuerpos.",,,"Je savais que tu gagnerais, mon vaillant héros. Les combats ont cessé, ta victoire nous permettrera de créer un vaccin et purger le virus de nos corps.",,"Lo sapevo che potevi vincere, mio eroe galante. Tutto il combattimento è cessato. La tua vittoria ci consentirà di creare un vaccino per estirpare il virus dai nostri corpi.","あなたが勝つことは分かっていたわ、私の勇敢なヒーロー。 +オーダーはもう存在しない。ブラックバード、聞こえるか?","프론트의 모든 병사는 주목하라. 그가 해냈다! 모든 것이 끝났다. 블랙버드의 병사가 악을 물리치고, 오더는 끝장이 났다. 블랙버드, 내 말 듣고 있나?","Opgelet, alle troepen van het Front: hij heeft het gedaan! Het is voorbij. Blackbird's soldaat heeft het Kwaad gedood. De Orde is niet meer. Blackbird, hoort jou mij?","Oppmerksomhet, alle tropper fra fronten: han har gjort det! Det er over. Blackbirds soldat har drept Ondskapen. Ordenen eksisterer ikke lenger. Blackbird, hører du meg?","Uwaga, wszystkie oddziały Frontu: udało mu się! To już koniec. Żołnierz Blackbird zabił Zło. Nie ma już Zakonu. Blackbird, czy mnie słyszysz?","Atenção, todas as tropas da Frente: ele conseguiu! Está tudo acabado. O soldado de Blackbird matou o Mal. A Ordem não existe mais. Blackbird, consegue me ouvir?",,"Atenție, toate trupele Frontului: e gata! S-a terminat. Soldatul lui Blackbird a distrus Răul. Ordinul nu mai există. Blackbird, m-auzi?","Внимание, всем войскам Фронта! Он справился! Всё кончено! Солдат «Чёрного дрозда» покончил со злом! Ордена больше нет! «Чёрный дрозд», как слышите?",,"Lystring, alla fronttrupper: han har gjort det! Det är över. Blackbirds soldat har dödat ondskan. Orden finns inte längre. Blackbird, hör du mig?","Cephe'nin tüm askerlerinin dikkatine: Başardı! Her şey bitti. Karabatak'ın askeri Şeytan'ı öldürdü. Tarikat artık yok. Karatavuk, beni duyuyor musun?" +"I knew you would win, my gallant hero. All fighting has stopped. Your victory will allow us to create a vaccine to purge the virus from our bodies.",TXT_SUB_GOOD2,〃,,,"Já věděla, že vyhraješ, můj statečný hrdino. Všechen boj ustal. Tvé vítězství nám umožní vyrobit vakcínu, která naše těla vyčistí od viru.","Jeg vidste, du ville vinde, min tapper helt. Alle kampe er stoppet. Din sejr vil give os mulighed for at skabe en vaccine, der kan rense vores kroppe for virussen.","Ich wusste, dass du gewinnen würdest, mein edler Held. Die Kämpfe haben aufgehört. Dein Sieg wird es uns erlauben einen Impfstoff herzustellen, mit dem wir den Virus in unseren Körper bekämpfen können.",,,"Sabía que ganarías, mi valiente héroe. La lucha ha terminado. Tu victoria nos permitirá crear una vacuna para purgar el virus de nuestros cuerpos.",,"Tiesin, että voittaisit, uljas sankarini. Kaikki taistelu on tauonnut. Voittosi myötä meidän on mahdollista luoda rokote viruksen poistamiseksi kehoistamme.","Je savais que tu gagnerais, mon vaillant héros. Les combats ont cessé, ta victoire nous permettrera de créer un vaccin et purger le virus de nos corps.","Tudtam, hogy nyerni fogsz vitéz hősöm. Megszűntek a csaták. A győzelmed lehetővé fogja tenni, hogy egy vakcinával kiírtsuk a testünkből ezt a vírust.","Lo sapevo che potevi vincere, mio galante eroe. Tutto il combattimento è cessato. La tua vittoria ci consentirà di creare un vaccino per estirpare il virus dai nostri corpi.","あなたが勝つことは分かっていたわ、私の勇敢なヒーロー。 全ての戦いは終結した。あなたがもたらした勝利のおかげで、 -私達の体からウィルスを根絶するためのワクチンを作ることができる。","나의 용감한 영웅이 이길 줄 알았어. 모든 싸움이 끝이 났고, 당신의 승리 덕분에 우리 몸에 남은 바이러스를 퇴치할 백신을 만들 수 있을 거야.","Ik wist dat je zou winnen, mijn dappere held. Alle gevechten zijn gestopt. Uw overwinning zal ons in staat stellen om een vaccin te creëren om het virus uit ons lichaam te zuiveren.",,"Eu sabia que você conseguiria vencer, meu herói valente. Todo esse conflito chegou ao fim. Sua vitória nos permitirá que criemos uma vacina para eliminar o vírus de nossos corpos.",,,"Я знала, что ты победишь, мой отважный герой. Война окончена. Твоя победа позволила нам создать вакцину против вируса.", -"You have saved our planet and set us free. Now I'd like to thank you... personally. Oh, and by the way: the name is Shauna.",TXT_SUB_GOOD3,,,,Zachránil jsi naši planetu a osvobodil nás. Teď bych ti chtěla poděkovat... osobně. A mimochodem: Mé jméno je Shauna.,"Du hast unseren Planeten gerettet und uns befreit. Nun würde ich mich gerne bei dir bedanken... persönlich. Oh, so nebenbei: Mein Name ist Shauna.",,,"Has salvado nuestro planeta y nos has hecho libres. Ahora me gustaría agradecértelo... personalmente. Oh, y por cierto: mi nombre es Shauna.",,,"Tu as sauvé notre planète et tu nous as tous libérés. Je veux te récompenser.. Personellement. Oh, et je m'appelle Shauna.",,"Hai salvato il nostro pianeta e ci hai reso liberi. Ora vorrei ringraziarti ... di persona. Ah, comunque: mi chiamo Shauna.","あなたはこの星を救い、そして自由を取り戻した。さあ、 -あなたにお礼をするときが来たわね、個人的な意味で… -ああ、それはそうと、私の本名はシャウナよ。","당신이 우리의 행성을 구하고 우리를 자유롭게 해줬어. 이제... 개인적으로 당신에게 감사하고 싶어. 아, 그리고... 내 이름은 샤나야.","Jullie hebben onze planeet gered en ons bevrijd. Nu wil ik je persoonlijk bedanken.... persoonlijk. Oh, en trouwens: de naam is Shauna.",,"Você salvou o nosso planeta e nos libertou. Agora, eu gostaria de te agradecer...pessoalmente. Ah, a propósito: meu nome é Shauna.",,,"Ты спас нашу планету и освободил нас. Так что я бы хотела поблагодарить тебя... лично. Кстати, меня зовут Шона.", -"Yes, the evil was gone, but our future was uncertain and clouded with doubt.",TXT_SUB_SAD1,,,,"Ano, zlo bylo pryč, ale naše budoucnost byla nejistá a zahalená pochybami.","Ja, das Böse war fort, aber unsere Zukunft war ungewiss und von Zweifeln getrübt.",,,"Sí, el mal desapareció, pero nuestro futuro fue incierto y oscurecido por dudas.",,,"Oui, le mal a disparu, mais notre futur reste incertain et le doute pèse sur nous.",,"Si, il male fu sconfitto, ma il nostro futuro fu incerto e offuscato dal dubbio.","ええ、悪は消え去ったわ。だけども私達の未来は -まだ不安と疑念に満ちている。","그래, 악은 이제 사라졌어. 하지만 우리의 불확실한 앞날은 여전히 근심의 먹구름으로 가득 찼어.","Ja, het kwaad was weg, maar onze toekomst was onzeker en vertroebeld met twijfel.",,"Sim, o mal se foi, mas o nosso futuro ainda era incerto e coberto de dúvidas.",,,"Да, зло было повержено, но наше будущее было туманно и омрачено тенью сомнений...", -It would take generations to purge the virus from our people. If we survived that long.,TXT_SUB_SAD2,,,,"Trvalo by to věky, než bychom virus z našeho lidu vypudili. Pokud bychom tak dlouho přežili.","Es würde Generationen dauern, bis wir unser Volk von dem Virus befreien können. Wenn wir so lange überleben...",,,Llevaría generaciones purgar el virus de nuestra gente. Si sobrevivieramos tanto tiempo.,,,"Il faudra des générations pour purger le virus de nos corps, si nous survivons suffisament longtemps.",,Ci sarebbero volute generazioni per eliminare il virus dalle nostre persone. Se fossimo sopravvissuti così a lungo.,"人間たちからウィルスを根絶するには、あと何世代もかかって -しまうはず。私達がそこまで生き延びられたとしても。",우리 몸속의 바이러스를 퇴치하려면 수 세대의 시간이 걸릴 거야. 우리가 그때까지 살아남는다면 말이지.,Het zou generaties vergen om het virus uit ons volk te zuiveren. Als we het zo lang zouden overleven.,,Levaria gerações para eliminar o vírus de nosso povo. Se sobrevivessemos por todo esse tempo.,,,"Десятилетия потребуются, чтобы исцелить наших людей от вируса... если нам удастся просуществовать так долго.", -"Whatever the evil wanted, it drained from us the one thing we needed: it left us without hope.",TXT_SUB_SAD3,,,,"Ať chtělo zlo cokoliv, vysálo z nás tu jednu věc, kterou jsme potřebovali: Nechalo nás bez naděje.","Was auch immer das Böse wollte, es hat uns das genommen, was wir am meisten brauchten: Es hat uns ohne Hoffnung gelassen.",,,"Sea lo que sea que quisiera el mal, nos despojó de aquello que necesitábamos: nos dejó sin esperanza.",,,"Quel que soit ce que le mal voulait de nous, il a tout de même pris la dernière chose qui nous restait: notre espoir.",,"Qualunque cosa il male volesse, ci ha drenato l'unica cosa che volevamo: ci ha lasciato senza speranza.","あの邪悪な存在が何を求めていたかはともかく、 -奴は人間たちから一番大切な物、希望を奪い去った。","악이 원한 것이 무엇이었든, 그들은 우리에게 필요한 한 가지를 뺏어갔어: 희망이라는 미래지...","Wat het kwaad ook wilde, het heeft ons datgene ontnomen wat we nodig hadden: het heeft ons zonder hoop achtergelaten.",,"Seja lá o que o mal queria, conseguiu tirar de nós algo que precisávamos: nossas esperanças.",,,"Чего бы зло ни желало, оно отняло у нас то, в чём мы нуждались больше всего — оно лишило нас надежды.", -"The sentient virus hit us like a tidal wave, driving us all mad. We heard the siren's song of death and we danced.",TXT_SUB_BAD1,,,,"Žijící virus nás ochromil jako povodeň, ze které jsme všichni zešíleli. Uslyšeli jsme síreninu píseň smrti a začali tančit.",Der Virus traf uns wie eine Flutwelle und machte uns verrückt. Wir hörten den Sirenengesang des Todes - und wir tanzten.,,,"El virus consciente nos golpeó como una marea, volviéndonos a todos locos. Escuchamos la canción de sirena de la muerte y bailamos.",,,"Le virus devenu intelligent nous a emporté comme un tsunami, nous plongeant dans la folie. Entendant le doux chant de la mort, nous dancions en choeur.",,"Il virus intelligente ci ha colpito come uno tsunami, immergendoci nella follia. Sentimmo il canto delle sirene mortale, portandoci a ballare assieme.","センティエント・ウィルスは私達を津波のように襲い、 +私達の体からウィルスを根絶するためのワクチンを作ることができる。","나의 용감한 영웅이 이길 줄 알았어. 모든 싸움이 끝이 났고, 당신의 승리 덕분에 우리 몸에 남은 바이러스를 퇴치할 백신을 만들 수 있을 거야.","Ik wist dat je zou winnen, mijn dappere held. Alle gevechten zijn gestopt. Uw overwinning zal ons in staat stellen om een vaccin te creëren om het virus uit ons lichaam te zuiveren.","Jeg visste at du ville vinne, min tapre helt. Alle kampene er over. Din seier vil tillate oss å lage en vaksine for å fjerne viruset fra kroppene våre.","Wiedziałem, że wygrasz, mój dzielny bohaterze. Wszystkie walki zostały przerwane. Twoje zwycięstwo pozwoli nam stworzyć szczepionkę, która usunie wirusa z naszych ciał.","Eu sabia que você conseguiria vencer, meu herói valente. Todo esse conflito chegou ao fim. Sua vitória nos permitirá que criemos uma vacina para eliminar o vírus de nossos corpos.",,"Știam că vei câștiga, eroul meu galant. Lupta a încetat. Vitoria ta ne permite să creăm un vaccin care va elimina virusul din corpul nostru.","Я знала, что ты победишь, мой отважный герой. Война окончена. Твоя победа позволила нам создать вакцину против вируса.",,"Jag visste att du skulle vinna, min tappre hjälte. Alla strider har upphört. Din seger kommer att göra det möjligt för oss att skapa ett vaccin för att rensa ut viruset från våra kroppar.","Kazanacağını biliyordum, benim cesur kahramanım. Tüm savaşlar durdu. Zaferin, virüsü vücutlarımızdan temizlemek için bir aşı yaratmamızı sağlayacak." +"You have saved our planet and set us free. Now I'd like to thank you... personally. Oh, and by the way: the name is Shauna.",TXT_SUB_GOOD3,〃,,,Zachránil jsi naši planetu a osvobodil nás. Teď bych ti chtěla poděkovat... osobně. A mimochodem: Mé jméno je Shauna.,"Du har reddet vores planet og befriet os. Nu vil jeg gerne takke dig... personligt. Åh, og forresten: Navnet er Shauna.","Du hast unseren Planeten gerettet und uns befreit. Nun würde ich mich gerne bei dir bedanken... persönlich. Oh, so nebenbei: Mein Name ist Shauna.",,,"Has salvado nuestro planeta y nos has hecho libres. Ahora me gustaría agradecértelo... personalmente. Oh, y por cierto: mi nombre es Shauna.",,"Olet pelastanut planeettamme ja vapauttanut meidät. Tahtoisin nyt kiittää sinua... henkilökohtaisesti. Ja muuten, nimeni on Shauna.","Tu as sauvé notre planète et tu nous as tous libérés. Je veux te récompenser.. Personellement. Oh, et je m'appelle Shauna.","Megmentetted a bolygót, és felszabadítottál minket. Meg akarom ezt köszönni...személyesen. Ja, és a nevem Shauna.","Hai salvato il nostro pianeta e ci hai reso liberi. Ora vorrei ringraziarti ... di persona. Ah, comunque: mi chiamo Shauna.","あなたはこの星を救い、そして自由を取り戻した。さあ、 +あなたにお礼をするときが来たわね、個人的な意味で... +ああ、それはそうと、私の本名はシャウナよ。","당신이 우리의 행성을 구하고 우리를 자유롭게 해줬어. 이제... 개인적으로 당신에게 감사하고 싶어. 아, 그리고... 내 이름은 샤나야.","Jullie hebben onze planeet gered en ons bevrijd. Nu wil ik je persoonlijk bedanken.... persoonlijk. Oh, en trouwens: de naam is Shauna.",Du har reddet planeten vår og satt oss fri. Nå vil jeg takke deg... personlig. Og forresten: navnet er Shauna.,"Uratowałeś naszą planetę i uwolniłeś nas. Teraz chciałbym ci podziękować... osobiście. Aha, i przy okazji: mam na imię Shauna.","Você salvou o nosso planeta e nos libertou. Agora, eu gostaria de te agradecer...pessoalmente. Ah, a propósito: meu nome é Shauna.",,"Ai salvat planeta și ne-ai eliberat. Aș vrea să îți mulțumesc, personal... Oh, și apropo: numele e Shauna.","Ты спас нашу планету и освободил нас. Так что я бы хотела поблагодарить тебя... лично. Кстати, меня зовут Шона.",,"Du har räddat vår planet och befriat oss. Nu vill jag tacka dig... personligen. Åh, och förresten: namnet är Shauna.",Gezegenimizi kurtardın ve bizi özgür bıraktın. Şimdi size şahsen teşekkür etmek istiyorum. Bu arada adım Shauna. +"Yes, the evil was gone, but our future was uncertain and clouded with doubt.",TXT_SUB_SAD1,Sad ending.,,,"Ano, zlo bylo pryč, ale naše budoucnost byla nejistá a zahalená pochybami.","Ja, ondskaben var væk, men vores fremtid var usikker og omgærdet af tvivl.","Ja, das Böse war fort, aber unsere Zukunft war ungewiss und von Zweifeln getrübt.",,,"Sí, el mal desapareció, pero nuestro futuro fue incierto y oscurecido por dudas.",,"Niin, paha oli kyllä mennyttä, mutta tulevaisuutemme oli epävarma ja hämärän peitossa.","Oui, le mal a disparu, mais notre futur reste incertain et le doute pèse sur nous.","Habár a gonosz eltávozott, a jövőnk mégis bizonytalan és ködös.","Si, il male fu sconfitto, ma il nostro futuro fu incerto e offuscato dal dubbio.","ええ、悪は消え去ったわ。だけども私達の未来は +まだ不安と疑念に満ちている。","그래, 악은 이제 사라졌어. 하지만 우리의 불확실한 앞날은 여전히 근심의 먹구름으로 가득 찼지.","Ja, het kwaad was weg, maar onze toekomst was onzeker en vertroebeld met twijfel.","Ja, ondskapen var borte, men fremtiden vår var usikker og full av tvil.","Tak, zło zniknęło, ale nasza przyszłość była niepewna i spowita wątpliwościami.","Sim, o mal se foi, mas o nosso futuro ainda era incerto e coberto de dúvidas.",,"Da, răul s-a dus dar viitorul nostru era în ceață și neclar.","Да, зло было повержено, но наше будущее было туманно и омрачено тенью сомнений...",,"Ja, ondskan var borta, men vår framtid var osäker och grumlad av tvivel.","Evet, kötülük gitmişti ama geleceğimiz belirsizdi ve şüpheyle doluydu." +It would take generations to purge the virus from our people. If we survived that long.,TXT_SUB_SAD2,〃,,,"Trvalo by to věky, než bychom virus z našeho lidu vypudili. Pokud bychom tak dlouho přežili.",Det ville tage generationer at udrense virussen fra vores folk. Hvis vi overlevede så længe.,"Es würde Generationen dauern, bis wir unser Volk von dem Virus befreien können. Wenn wir so lange überleben...",,,Llevaría generaciones purgar el virus de nuestra gente. Si sobrevivieramos tanto tiempo.,,"Kestäisi sukupolvia hävittää virus keskuudestamme, jos selviäisimme niin pitkälle.","Il faudra des générations pour purger le virus de nos corps, si nous survivons suffisament longtemps.","Generációkba fog kerülni, hogy teljesen kiírtsuk a vírust. Márha élünk addig.",Ci sarebbero volute generazioni per eliminare il virus dalle nostre persone. Se fossimo sopravvissuti così a lungo.,"人間たちからウィルスを根絶するには、あと何世代もかかって +しまうはず。私達がそこまで生き延びられたとしても。",우리 몸속의 바이러스를 퇴치하려면 수 세대의 시간이 걸릴 거야. 우리가 그때까지 살아남는다면.,Het zou generaties vergen om het virus uit ons volk te zuiveren. Als we het zo lang zouden overleven.,Det ville ta generasjoner å fjerne viruset fra folket vårt. Hvis vi overlevde så lenge.,"Potrzeba było pokoleń, by oczyścić nasz lud z wirusa. Jeśli przeżyjemy tak długo.",Levaria gerações para eliminar o vírus de nosso povo. Se sobrevivessemos por todo esse tempo.,,Va dura generații până vom elimina virusul din oamenii noștri. Dacă vom trăi suficient.,"Десятилетия потребуются, чтобы исцелить наших людей от вируса... если нам удастся просуществовать так долго.",,Det skulle ta generationer att rensa ut viruset från vårt folk. Om vi överlevde så länge.,Virüsü insanlarımızdan temizlemek nesiller alacaktı. Tabii o kadar uzun süre hayatta kalabilirsek. +"Whatever the evil wanted, it drained from us the one thing we needed: it left us without hope.",TXT_SUB_SAD3,〃,,,"Ať chtělo zlo cokoliv, vysálo z nás tu jednu věc, kterou jsme potřebovali: Nechalo nás bez naděje.","Uanset hvad ondskaben ville, drænede den os for den eneste ting, vi havde brug for: den efterlod os uden håb.","Was auch immer das Böse wollte, es hat uns das genommen, was wir am meisten brauchten: Es hat uns ohne Hoffnung gelassen.",,,"Sea lo que sea que quisiera el mal, nos despojó de aquello que necesitábamos: la esperanza.",,"Mitä tahansa paha halusikaan, se riisti meiltä sen yhden ainoan asian, jota tarvitsimme: se jätti meidät ilman toivoa.","Quel que soit ce que le mal voulait de nous, il a tout de même pris la dernière chose qui nous restait: notre espoir.",A gonosz megkaparintotta amit akart: megfosztott minket a reményünktől.,"Qualunque cosa il male volesse, ci ha drenato dell'unica cosa di cui avevamo bisogno: ci ha lasciato senza speranza.","あの邪悪な存在が何を求めていたかはともかく、 +奴は人間たちから一番大切な物、希望を奪い去った。","악이 원한 것이 무엇이었든, 그들은 우리에게 필요한 한 가지를 뺏어갔어: 희망이라는 미래지...","Wat het kwaad ook wilde, het heeft ons datgene ontnomen wat we nodig hadden: het heeft ons zonder hoop achtergelaten.","Uansett hva ondskapen ville, tok den fra oss det eneste vi trengte: Den etterlot oss uten håp.","Cokolwiek chciało zło, wyssało z nas jedyną rzecz, której potrzebowaliśmy: pozostawiło nas bez nadziei.","Seja lá o que o mal queria, conseguiu tirar de nós algo que precisávamos: nossas esperanças.",,"Orice ar fi vrut răul, ne-a stors de ceea ce am avut cea mai mare nevoie: speranță.","Чего бы зло ни желало, оно отняло у нас то, в чём мы нуждались больше всего — оно лишило нас надежды.",,Vad ondskan än ville så tog den från oss det enda vi behövde: den lämnade oss utan hopp.,"Kötülük her ne istediyse, ihtiyacımız olan tek şeyi bizden çekip aldı: bizi umutsuz bıraktı." +"The sentient virus hit us like a tidal wave, driving us all mad. We heard the siren's song of death and we danced.",TXT_SUB_BAD1,Worst ending.,,,"Žijící virus nás ochromil jako povodeň, ze které jsme všichni zešíleli. Uslyšeli jsme siréninu píseň smrti a začali tančit.","Den følende virus ramte os som en flodbølge og drev os alle til vanvid. Vi hørte sirenens sang om døden, og vi dansede.",Der Virus traf uns wie eine Flutwelle und machte uns verrückt. Wir hörten den Sirenengesang des Todes - und wir tanzten.,,,"El virus consciente nos golpeó como una marea, volviéndonos a todos locos. Escuchamos la canción de sirena de la muerte y bailamos.",,Tietoinen virus iski meihin kuin hyökyaalto syösten meidät hulluuteen. Kuulimme seireenin kuoleman veisuun ja tanssimme sen tahtiin.,"Le virus devenu intelligent nous a emporté comme un tsunami, nous plongeant dans la folie. Entendant le doux chant de la mort, nous dancions en choeur.","A tudatára ébredt vírus hullámként verte le népünket és őrjített meg minket. Hallottuk a szirének tébolyító halál énekét, és táncolni kezdtünk.","Il virus intelligente ci ha colpito come uno tsunami, immergendoci nella follia. Sentimmo il canto delle sirene della morte, e ci misimo a ballare.","センティエント・ウィルスは私達を津波のように襲い、 全ての人間を狂気に陥れた。セイレーンの死の歌声を聞いたように -なり、死ぬまで踊り続けたのだ。","자각심을 가진 바이러스가 온 땅을 휩쓸었고, 우리 모두를 미치게 했다. 우리는 악이 들려주는 죽음의 노래에 맞춰 춤을 추었다.","Het virus met gevoel raakte ons als een vloedgolf, waardoor we allemaal gek werden. We hoorden het lied van de sirene van de dood en we dansten.",,"O vírus senciente nos atingiu como uma onda gigante, deixando todos nós loucos. Ouviamos a canção da morte da sirene e dançávamos.",,,"Эпидемия захлестнула нас подобно гигантской волне, лишив рассудка каждого. Мы услышали сладкую песнь смерти и подчинились ей.", -"This evil drained us of all human life and, scornful of procreation, recycled our families.",TXT_SUB_BAD2,,,,"Toto zlo z nás vysálo všechen život a, bez rozmnožování, vyhladilo naše rodiny.",Das Böse entzog uns alles menschliche und als Verhöhnung der Fortpflanzung recycelte es unsere Familien.,,,"Este mal nos despojó de nuestra humanidad y despreciando la procreación, recicló nuestras familias.",,,"La mal nous a drainé de toute vie et haïssant toute procréation, recycla nos familles.",,"Questo male ci ha drenato di tutta la vita umana e, sprezzante della procreazione, riciclò le nostre famiglie.","この邪悪な存在は人間たちの命と繁殖能力を奪い去り、 -我々の家族を再利用した。","악은 우리에게서 인간적인 삶을 빼앗았고, 우리 인류를 유지해온 생식을 억제하였다.","Dit kwaad heeft ons van alle mensenlevens ontdaan en, verachtelijk van voortplanting, onze families gerecycled.",,"O mal tirou de nós toda a vida humana e, deprezando a procriação, reciclou nossas famílias.",,,"Зло истребляло в нас всё человеческое. Не задумываясь о завтрашнем дне, оно перерабатывало целые семьи.", -"Then one day, the evil left. There was simply nothing for it to feed on. We were extinct.",TXT_SUB_BAD3,,,,"A pak, jednoho dne, zlo odešlo. Nemělo se prostě už na čem pást. Vyhynuli jsme.","Dann, eines Tages, war das Böse fort. Es war nichts mehr da, wovon es zehren konnte. Wir waren ausgestorben.",,,"Entonces un día, el mal se fue. Simplemente no quedaba nada con que alimentarse. Nos extinguimos.",,,"Puis, un jour, le mal disparut. Il ne restait plus rien d'utile pour lui, nous nous sommes éteints.",,"Così un giorno, il male se ne andò. Semplicemente non rimase nulla su cui cibarsi. Noi siamo estinti.","そしてある時、邪悪な存在はこの星を後にした。単に、 -奴の糧となる者が一人もいなくなったからだ。我々は滅びたのだ。","그리고 어느 날, 악은 사라졌다. 그들에게 먹을 것이 없었기 때문이다. 우리들이 멸종했기에...",Op een dag vertrok het kwaad. Er was gewoonweg niets om zich op te voeden. We waren uitgestorven.,,"E então um dia, o mal foi embora. Não sobrou mais nada para ele consumir. Estávamos extintos.",,,"Настал день, когда зло ушло. Не осталось ничего, чем оно могло бы питаться. Мы вымерли.", -"The genetic mutations caused by the virus not only warped the psyches of the Order, but caused their bodies to decay.",TXT_SUB_MAP03_1,,,,"Genetické mutace způsobené virem nejenže pokřivily mysli Řádu, ale také způsobily rozklad jejich těl.","Die genetischen Mutationen, die durch den Virus verursacht wurden, haben nicht nur die Psyche des Ordens beeinflusst, sondern brachten auch ihre Körper zum Verfallen.",,,"Las mutaciones genéticas causadas por el virus no solo retorcieron las mentes de la Orden, sino que también causaron el deterioro de sus cuerpos.",,,"Les mutations géntiques du virus ont non seulement tordu l'esprit de L'Ordre, mais a aussi rendu leur corps invivables.",,"Le mutazioni genetiche causate dal virus non solo turbava la psiche dell'Ordine, ma portava i loro corpi a decomporre.","ウィルスからもたらされた遺伝子変異はオーダーの者たちの精神だけではなく、 -肉体すらも蝕んだ。","바이러스로 인한 유전적 변화는 오더의 광신도들을 만들었을 뿐만 아니라, 그들의 육신을 썩어 문드러지게 했습니다.","De genetische mutaties die door het virus werden veroorzaakt, vervormden niet alleen de psyche van de Orde, maar veroorzaakten ook het verval van hun lichaam.",,"As mutações genéticas causadas pelo vírus não somente distorceu as mentes da Ordem, mas também deterioraram nossos corpos.",,,"Генетические мутации, которые возникали из-за вируса, не только извращали психику членов Ордена, но и вызывали гниение их тел.", -"Without procreation, the Order found that biomechanical enhancements were the only way to maintain their strengths and numbers.",TXT_SUB_MAP03_2,,,,"Řádu došlo, že bez rozmnožování jsou biomechanická vylepšení jediná možnost, jak zachovat své počty a sílu.","Ohne die Möglichkeit der Fortpflanzung fand der Orden heraus, dass biomechanische Erweiterungen der einzige Weg waren, um ihre Kräfe und eine hohe Anzahl beizubehalten.",,,"Sin procreación, la Orden se encontró con que las mejoras biomecánicas eran la única forma de mantener sus fuerzas y números.",,,"Sans procréation, l'Ordre découvrirent que les modifications bioméchaniques était leur seule chance de conserver leur force et leur nombre.",,"Senza la procreazione, l'Ordine trovò che gli apparati biomeccanici erano l'unico modo per mantenere la loro forza e i loro numeri.","繁殖行為という選択肢がないオーダーは、 -彼らのパワーと数を保つには生体工学による人体改造しかないと判断したのだ。","생식능력이 사라지자, 오더에게 남은 존속 방법은 생체에 기계를 접목한 기술을 발전시키는 것 뿐이었죠.","Zonder voortplanting, vond de Orde dat biomechanische verbeteringen de enige manier waren om hun sterke punten en aantallen te behouden.",,"Sem procriação, a Ordem descobriu que as modificações biomecânicas eram a única maneira de manter sua força e seus números.",,,"Орден обнаружил, что биомеханические улучшения — единственный способ поддержания их численного превосходства при отсутствии деторождения.", -The decay has advanced so that most of the troops we face are more machine than man but we believe that their collective consciousness is controlled by one source...,TXT_SUB_MAP03_3,,,,"Rozklad pokročil tak daleko, že většina nepřátel, kterým čelíme, jsou spíše stroje než lidi, ale věříme, že jejich kolektivní vědomí je řízené z jednoho zdroje...","Der Verfall ist so weit fortgeschritten, dass die meisten Truppen, denen wir begegnen mehr Maschine als Mensch sind, aber wir glauben, dass ihr kollektives Bewusstsein von einer Quelle kontrolliert wird...",,,El deterioro ha avanzado tanto que la mayoría de tropas a las que nos enfrentamos son más máquina que hombre pero creemos que su consciencia colectiva es controlada por una única fuente...,,,"Les dégradations étaient si avancées que les troupes auxquelles nous faisions face étaient plus machine qu'humains, mais nous pensons que leur conscience collective est contrôlée par une seule source..",,"La decomposizione è avanzata così tanto che molte delle truppe che vediamo sono più macchine che uomini, ma noi crediamo che la loro coscienza collettiva è controllata da una sola fonte...","彼らの肉体へのダメージは深刻で、我らが遭遇した兵士たちは人間と言うよりは +なり、死ぬまで踊り続けたのだ。","자각심을 가진 바이러스가 온 땅을 휩쓸었고, 우리 모두를 미치게 했다. 우리는 악이 들려주는 죽음의 노래에 맞춰 춤을 추었다.","Het virus met gevoel raakte ons als een vloedgolf, waardoor we allemaal gek werden. We hoorden het lied van de sirene van de dood en we dansten.",Det følende viruset traff oss som en flodbølge og gjorde oss alle gale. Vi hørte sirenenes dødssang og vi danset.,"Czujący wirus uderzył w nas jak fala pływowa, doprowadzając nas wszystkich do szaleństwa. Słyszeliśmy syreni śpiew śmierci i tańczyliśmy.","O vírus senciente nos atingiu como uma onda gigante, deixando todos nós loucos. Ouviamos a canção da morte da sirene e dançávamos.",,"Virusul viu ne-a lovit ca un val, făcându-ne să o luăm razna. Am auzit cântecul de moarte al sirenelor și am dansat.","Эпидемия захлестнула нас подобно гигантской волне, лишив рассудка каждого. Мы услышали сладкую песнь смерти и подчинились ей.",,Det kännande viruset drabbade oss som en flodvåg och drev oss alla till vansinne. Vi hörde sirenens sång av döden och vi dansade.,Duyarlı virüs bizi bir gelgit dalgası gibi vurdu ve hepimizi delirtti. Sirenin ölüm şarkısını duyduk ve dans ettik. +"This evil drained us of all human life and, scornful of procreation, recycled our families.",TXT_SUB_BAD2,〃,,,"Toto zlo z nás vysálo všechen život a, bez možnosti se rozmnožovat, vyhladilo naše rodiny.","Denne ondskab drænede os for alt menneskeligt liv, og foragtede for forplantning og genbrugte vores familier.",Das Böse entzog uns alles menschliche und als Verhöhnung der Fortpflanzung recycelte es unsere Familien.,,,"Este mal nos despojó de nuestra humanidad y despreciando la procreación, recicló nuestras familias.",,Paha imi meistä kaiken ihmiselämän ja lisääntymistä ylenkatsoen kierrätti perheemme.,"La mal nous a drainé de toute vie et haïssant toute procréation, recycla nos familles.","Ez a gonosz tömegével csapolta le az emberi életeket, és egyfajta gúnyos teremtőként újrahasznosította családainkat.","Questo male ci ha drenato di tutta la vita umana e, sprezzante della procreazione, riciclò le nostre famiglie.","この邪悪な存在は人間たちの命と繁殖能力を奪い去り、 +我々の家族を再利用した。","악은 우리에게서 인간적인 삶을 빼앗았고, 우리 인류를 유지해온 생식을 억제했다.","Dit kwaad heeft ons van alle mensenlevens ontdaan en, verachtelijk van voortplanting, onze families gerecycled.",Denne ondskapen tømte oss for alt menneskelig liv og resirkulerte familiene våre med forakt for forplantning.,"To zło pozbawiało nas wszelkiego ludzkiego życia, a gardząc prokreacją, utylizowało nasze rodziny.","O mal tirou de nós toda a vida humana e, deprezando a procriação, reciclou nossas famílias.",,"Acest rău ne-a stors de toată viața umană, detestând procreerea, reciclandu-ne familiile.","Зло истребляло в нас всё человеческое. Не задумываясь о завтрашнем дне, оно перерабатывало целые семьи.",,"Denna ondska tömde oss på allt mänskligt liv och, med förakt för fortplantning, återanvände våra familjer.",Bu kötülük bizi tüm insan yaşamından mahrum bıraktı ve üremeyi küçümseyerek ailelerimizi geri dönüştürdü. +"Then one day, the evil left. There was simply nothing for it to feed on. We were extinct.",TXT_SUB_BAD3,〃,,,"A pak, jednoho dne, zlo odešlo. Nemělo se prostě už na čem pást. Vyhynuli jsme.",Så en dag forlod ondskaben os. Der var simpelthen ikke noget for den at spise. Vi var uddøde.,"Dann, eines Tages, war das Böse fort. Es war nichts mehr da, wovon es zehren konnte. Wir waren ausgestorben.",,,"Entonces un día, el mal se fue. Simplemente ya no quedaba nada con que alimentarse: nos extinguimos.",,"Sitten eräänä päivänä paha kaikkosi; mitään yksinkertaisesti ei enää ollut, mistä elää. Olimme kuolleet sukupuuttoon.","Puis, un jour, le mal disparut. Il ne restait plus rien d'utile pour lui, nous nous sommes éteints.",Egy napon a gonosz eltűnt. Nem tudott már min táplálkozni. Kipusztultunk.,"Così un giorno, il male se ne andò. Semplicemente non rimase nulla su cui cibarsi. Noi siamo estinti.","そしてある時、邪悪な存在はこの星を後にした。単に、 +奴の糧となる者が一人もいなくなったからだ。我々は滅びたのだ。","그리고 어느 날, 악은 사라졌다. 그들에게 먹을 것이 없었기 때문이다. 우리들이 멸종했기에...",Op een dag vertrok het kwaad. Er was gewoonweg niets om zich op te voeden. We waren uitgestorven.,Så en dag forsvant ondskapen. Det fantes rett og slett ikke noe å livnære seg på. Vi var utryddet.,"Pewnego dnia, zło odeszło. Nie było nic, czym mogłoby się żywić. Wyginęliśmy.","E então um dia, o mal foi embora. Não sobrou mais nada para ele consumir. Estávamos extintos.",,"Apoi, într-o zi, răul a plecat. Pur și simplu nu a mai rămas nimic din care să se hrănească. Eram dispăruți.","Настал день, когда зло ушло. Не осталось ничего, чем оно могло бы питаться. Мы вымерли.",,En dag lämnade ondskan oss. Det fanns helt enkelt ingenting för den att livnära sig på. Vi var utdöda.,"Sonra bir gün, kötülük gitti. Beslenebileceği hiçbir şey kalmamıştı. Neslimiz tükenmişti." +"The genetic mutations caused by the virus not only warped the psyches of the Order, but caused their bodies to decay.",TXT_SUB_MAP03_1,MAP03: After destroying the gate controls.,,,"Genetické mutace způsobené virem nejenže pokřivily mysli Řádu, ale také způsobily rozklad jejich těl.","De genetiske mutationer forårsaget af virussen forvrængede ikke kun ordensmændenes psyke, men fik også deres kroppe til at forfalde.","Die genetischen Mutationen, die durch den Virus verursacht wurden, haben nicht nur die Psyche des Ordens beeinflusst, sondern brachten auch ihre Körper zum Verfallen.",,,"Las mutaciones genéticas causadas por el virus no solo retorcieron las mentes de la Orden, sino que también causaron el deterioro de sus cuerpos.",,Viruksen aiheuttamat geneettiset mutaatiot eivät vain vääristäneet Veljeskunnan mieliä vaan myös rappeuttivat heidän ruumiitaan.,"Les mutations géntiques du virus ont non seulement tordu l'esprit de L'Ordre, mais a aussi rendu leur corps invivables.","A vírus genetikai mutációi nem csak a Rend tagjainak elméjét rontotta meg, de testüket is bomlásnak indította.","Le mutazioni genetiche causate dal virus non solo turbavano la psiche dei seguaci dell'Ordine, ma portava i loro corpi a decomporre.","ウィルスからもたらされた遺伝子変異はオーダーの者たちの精神だけではなく、 +肉体すらも蝕んだ。","바이러스로 인한 유전적 변화는 오더의 광신도들을 만들었을 뿐만 아니라, 그들의 육신을 썩어 문드러지게 했습니다.","De genetische mutaties die door het virus werden veroorzaakt, vervormden niet alleen de psyche van de Orde, maar veroorzaakten ook het verval van hun lichaam.","De genetiske mutasjonene forårsaket av viruset forvrengte ikke bare ordenens psyke, men fikk kroppene deres til å forfalle.","Mutacje genetyczne spowodowane przez wirusa nie tylko wypaczyły psychikę Zakonu, ale spowodowały rozkład ich ciał.","As mutações genéticas causadas pelo vírus não somente distorceu as mentes da Ordem, mas também deterioraram nossos corpos.",,"Mutațiile genetice nu numai că au sucit psihicul Ordinului, dar le-a făcut corpul să se deterioreze.","Генетические мутации, которые возникали из-за вируса, не только извращали психику членов Ордена, но и вызывали гниение их тел.",,"De genetiska mutationer som viruset orsakade förvrängde inte bara ordens psykiska tillstånd, utan fick deras kroppar att förfalla.","Virüsün neden olduğu genetik mutasyonlar sadece Tarikat'ın psikolojisini bozmakla kalmadı, aynı zamanda bedenlerinin de çürümesine neden oldu." +"Without procreation, the Order found that biomechanical enhancements were the only way to maintain their strengths and numbers.",TXT_SUB_MAP03_2,〃,,,"Řádu došlo, že bez rozmnožování jsou biomechanická vylepšení jediná možnost, jak zachovat své počty a sílu.","Uden forplantning fandt Ordenen ud af, at biomekaniske forbedringer var den eneste måde at bevare deres styrke og antal på.","Ohne die Möglichkeit der Fortpflanzung fand der Orden heraus, dass biomechanische Erweiterungen der einzige Weg waren, um ihre Kräfe und eine hohe Anzahl beizubehalten.",,,"Sin procreación, la Orden se encontró con que las mejoras biomecánicas eran la única forma de mantener sus fuerzas y números.",,Ilman lisääntymistä Veljeskunta katsoi biomekaanisen parantelun ainoaksi tavakseen ylläpitää vahvuuttaan.,"Sans procréation, l'Ordre découvrirent que les modifications bioméchaniques était leur seule chance de conserver leur force et leur nombre.",A szaporodás nélkül a Rendnek csak egyetlen esélye volt az erejük és számuk megtartására: a biomechanikus testi tuningolás.,"Senza la procreazione, l'Ordine trovò che gli apparati biomeccanici erano l'unico modo per mantenere la loro forza e i loro numeri.","繁殖行為という選択肢がないオーダーは、 +彼らのパワーと数を保つには生体工学による人体改造しかないと判断したのだ。","생식능력이 사라지자, 오더에게 남은 존속 방법은 생체에 기계를 접목한 기술을 발전시키는 것 뿐이었죠.","Zonder voortplanting, vond de Orde dat biomechanische verbeteringen de enige manier waren om hun sterke punten en aantallen te behouden.",Uten forplantning fant ordenen ut at biomekaniske forbedringer var den eneste måten å opprettholde sin styrke og antall på.,"Bez prokreacji Zakon odkrył, że biomechaniczne ulepszenia są jedynym sposobem na utrzymanie siły i liczebności.","Sem procriação, a Ordem descobriu que as modificações biomecânicas eram a única maneira de manter sua força e seus números.",,"Fără procreere, Ordinul a descoperit că îmbunătățirile lor bio-mecanice erau tot ce îi ținea.","Орден обнаружил, что биомеханические улучшения — единственный способ поддержания их численного превосходства при отсутствии деторождения.",,Utan fortplantning fann orden att biomekaniska förbättringar var det enda sättet att behålla sin styrka och sitt antal.,"Üreme olmadan, Düzen güçlerini ve sayılarını korumanın tek yolunun biyomekanik geliştirmeler olduğunu gördü." +The decay has advanced so that most of the troops we face are more machine than man but we believe that their collective consciousness is controlled by one source...,TXT_SUB_MAP03_3,〃,,,"Rozklad pokročil tak daleko, že většina nepřátel, kterým čelíme, jsou spíše stroje než lidé, ale věříme, že jejich kolektivní vědomí je řízené z jednoho zdroje...","Forfaldet er fremskredet, så de fleste af de tropper, vi står over for, er mere maskiner end mennesker, men vi tror, at deres kollektive bevidsthed styres af én kilde...","Der Verfall ist so weit fortgeschritten, dass die meisten Truppen, denen wir begegnen mehr Maschine als Mensch sind, aber wir glauben, dass ihr kollektives Bewusstsein von einer Quelle kontrolliert wird...",,,El deterioro ha avanzado tanto que la mayoría de tropas a las que nos enfrentamos son más máquina que hombre pero creemos que su consciencia colectiva es controlada por una única fuente...,,"Rappeutuminen on edennyt niin pitkälle, että suurin osa kohtaamistamme joukoista on enemmän koneita kuin ihmisiä, mutta me uskomme, että heidän yhteistä tietoisuuttaan ohjaa yksi lähde...","Les dégradations étaient si avancées que les troupes auxquelles nous faisions face étaient plus machine qu'humains, mais nous pensons que leur conscience collective est contrôlée par une seule source..","A bomlás annyira előrehaladott, hogy a harctéren látott egységek nagyobb részben robotok mint emberek, de úgy gondoljuk hogy az elméjüket egy központi tudat irányítja...","La decomposizione è avanzata a tal punto che molte delle truppe che vediamo sono più macchine che uomini, ma noi crediamo che la loro coscienza collettiva sia controllata da un'unica fonte...","彼らの肉体へのダメージは深刻で、我らが遭遇した兵士たちは人間と言うよりは もはや機械に近いと言える。だが、彼らの集合意識はたった一人によってコントロールされていると -我々は考えている。","부패가 많이 진행되었기에 우리는 사람보다 기계에 가까운 적들과 싸웠고, 우리는 그들의 집단의식이 어떤 하나의 존재가 통제하는 것이라고 생각하고 있습니다...","Het verval is zo ver gevorderd dat de meeste van de troepen die we tegenkomen meer machine zijn dan de mens, maar we geloven dat hun collectieve bewustzijn wordt gecontroleerd door één bron....",,A deterioração avançou de tal forma que a maioria dos soldados que enfrentamos são mais máquina do que humano. Mas acreditamos que a consciência coletiva deles é controlada por uma só fonte... ,,,"Гниение распространялось, поэтому большинство их солдат скорее машины, чем люди. Но мы полагаем, что их коллективное сознание управляется из единого центра...", -"...the Programmer: creator of the AI which controls the Acolytes. Destroy the Programmer, and we may cripple the Order's troops with a single blow. But caution: we have reports he can vaporize attackers.",TXT_SUB_MAP03_4,,,,"...Programátor: tvůrce umělé inteligence, která ovládá akolyty. Znič Programátora a dost možná zasadíme vojskům Řádu mocnou ránu. Ale buď opatrný: Máme zprávy, že umí nechat své útočníky vypařit.","...der Programmierer: Entwickler der KI, die die Ministranten kontrolliert. Vernichte den Programmierer, und wir könnten die Truppen des Ordens mit einem einzigen Schlag lahmlegen. Aber sieh dich vor. Wir haben Meldungen, dass er Angreifer vaporisieren kann.",,,... el Programador - creador de la IA que controla a los Acólitos. Destruye al Programador y podremos herir a las tropas de la Orden de un solo golpe. Pero cuidado: tenemos informes de que puede vaporizar a atacantes.,,,Le Programmeur: Créateur de l'IA qui contrôle les Acolytes. Détruisez le Programmeur et nous pourrons paralyser les troupes de l'Ordre d'un seul coup. Faites attentions: des rapports nous disent qu'il peut vaporiser ceux qui l'attaquent.,,"...il Programmatore: creatore dell'Intelligenza Artificiale che controlla gli Acoliti. Distruggi il Programmatore, e noi potremmo rendere inefficiente i soldati dell'Ordine con un colpo solo. Ma attento: rapporti nostri dicono che può vaporizzare gli aggressori.","その者の名はプログラマーだ。 +我々は考えている。","부패가 많이 진행되었기에 우리는 사람보다 기계에 가까운 적들과 싸웠고, 우리는 그들의 집단의식이 어떤 하나의 존재가 통제하는 것이라고 생각하고 있습니다...","Het verval is zo ver gevorderd dat de meeste van de troepen die we tegenkomen meer machine zijn dan de mens, maar we geloven dat hun collectieve bewustzijn wordt gecontroleerd door één bron....","Forfallet har gått så langt at de fleste av troppene vi står overfor er mer maskin enn menneske, men vi tror at deres kollektive bevissthet styres av én kilde...","Rozkład postępuje tak, że większość oddziałów, z którymi mamy do czynienia, to bardziej maszyny niż ludzie, ale wierzymy, że ich zbiorowa świadomość jest kontrolowana przez jedno źródło...",A deterioração avançou de tal forma que a maioria dos soldados que enfrentamos são mais máquina do que humano. Mas acreditamos que a consciência coletiva deles é controlada por uma só fonte... ,,Deteriorarea a avansat în așa fel încăt majoritatea soldațiilor pe care îi înfruntăm să fie mai mult mașini decât oameni dar credem că subconștientul lor colectiv e controlat de o singură sursă...,"Гниение распространялось, поэтому большинство их солдат скорее машины, чем люди. Но мы полагаем, что их коллективное сознание управляется из единого центра...",,"Förfallet har gått framåt så att de flesta av de trupper vi möter är mer maskiner än människor, men vi tror att deras kollektiva medvetande styrs av en enda källa...","Çürüme o kadar ilerledi ki, karşılaştığımız birliklerin çoğu insandan çok makine ama biz onların kolektif bilincinin tek bir kaynak tarafından kontrol edildiğine inanıyoruz..." +"...the Programmer: creator of the AI which controls the Acolytes. Destroy the Programmer, and we may cripple the Order's troops with a single blow. But caution: we have reports he can vaporize attackers.",TXT_SUB_MAP03_4,〃,,,"...Programátor: tvůrce umělé inteligence, která ovládá akolyty. Znič Programátora a dost možná zasadíme vojskům Řádu mocnou ránu. Ale buď opatrný: Máme zprávy, že umí nechat své útočníky vypařit.","...programmøren: Skaberen af den AI, der styrer akolytterne. Hvis vi ødelægger programmøren, kan vi lamme ordenens tropper med et enkelt slag. Men pas på: Vi har rapporter om, at han kan fordampe angribere.","...der Programmierer: Entwickler der KI, die die Ministranten kontrolliert. Vernichte den Programmierer, und wir könnten die Truppen des Ordens mit einem einzigen Schlag lahmlegen. Aber sieh dich vor. Wir haben Meldungen, dass er Angreifer vaporisieren kann.",,,... el Programador - creador de la IA que controla a los Acólitos. Destruye al Programador y podremos herir a las tropas de la Orden de un solo golpe. Pero cuidado: tenemos informes de que puede vaporizar a atacantes.,,"Ohjelmoitsija: akoluutteja ohjaavan tekoälyn luoja. Tuhoa Ohjelmoitsija, ja saatamme rampauttaa Veljeskunnan joukot yhdellä iskulla. Mutta ole varovainen: tietojemme mukaan hän kykenee haihduttamaan vastustajansa.",Le Programmeur: Créateur de l'IA qui contrôle les Acolytes. Détruisez le Programmeur et nous pourrons paralyser les troupes de l'Ordre d'un seul coup. Faites attentions: des rapports nous disent qu'il peut vaporiser ceux qui l'attaquent.,...maga a Programozó: a ministránsokat irányító MI megalkotója. A Programozót megölve megbéníthatjuk a Rend seregét egy csapással. Azonban vigyázz: a jelentések szerint instant el tudja porlasztani támadóit.,"...il Programmatore: creatore dell'Intelligenza Artificiale che controlla gli Accoliti. Distruggi il Programmatore, e noi potremmo rendere inefficienti i soldati dell'Ordine con un colpo solo. Ma attento: i nostri rapporti indicano che può vaporizzare gli aggressori.","その者の名はプログラマーだ。 彼はアコライト達を操作している人工知能の作成者だ。 プログラマーを殺害すれば、それによってオーダーの兵士たちを無力化できるはずだ。 -だが気をつけておけ、ヤツは熱で敵を蒸発させられるとの報告があるからな。",".. 프로그래머 - 아콜라이트들을 통제하는 인공지능의 창조자 말입니다. 그를 파괴하면 일격으로 오더의 군대를 무력화시킬 수 있을 겁니다. 하지만 조심하세요, 보고에 의하면 그는 자기 상대를 가루로 만들어 버린다는군요.","...de programmeur: maker van de AI die de Acolieten bestuurt. Vernietig de programmeur, en we kunnen de troepen van de Orde met een enkele klap verlammen. Maar opgelet: we hebben meldingen dat hij aanvallers kan verdampen.",,"...o Programador: o criador da inteligência artificial que controla os Acólitos. Destrua o programador e, assim, poderemos prejudicar as tropas da Ordem com um único golpe. Mas cuidado: temos relatos de que ele pode vaporizar aqueles que atacam.",,,"...Программистом — создателем ИИ, контролирующего служителей. Уничтожь Программиста, и мы разделаемся с войсками Ордена одним ударом. Но осторожнее — нам докладывали, что он умеет... испепелять нападающих.", -"Fragments assembled from the Programmers files tell us that the Order is worshipping an intelligent weapon. They call it ""the Sigil"".",TXT_SUB_MAP10_1,,,,"Útržky poskládané z Programátorových souborů nám říkají, že Řád uctívá inteligentní zbraň. Říkají jí „Pečeť“.","Fragmente, zusammengestellt aus den Dateien des Programmierers, sagen uns, dass der Orden eine intelligente Waffe verehrt. Sie nennen sie „Das Sigil“.",,,"Fragmentos reunidos de los archivos del Programador nos dicen que la Orden adora un arma inteligente. La llaman ""el Emblema"".",,,"Des fragments des fichiers du Programmeur que nous avons assemblés nous disent que l'Ordre vénère une arme intelligente. Ils l'appelent le ""Sigil"".",,"Frammenti dei file del Programmatore che abbiamo assemblato ci dicono che l'Ordine venera un'arma intelligente. La chiamano ""il Sigillo"".","プログラマーの資料を要約するとその欠片はオーダー達が崇拝する知性を持った武器、 -'シジル'だ。","프로그래머의 파괴된 기록들을 복원해보니, 오더가 자아를 가진 한 무기를 숭배하고 있다는군요. 그들은 이걸 “시질”이라고 부릅니다.","Fragmenten uit de Programmers bestanden vertellen ons dat de Orde een intelligent wapen aanbidt. Ze noemen het ""de Sigil"".",,"Os fragmentos dos relatórios sobre o Programador que conseguimos juntar dizem que a Ordem está venerando uma arma inteligente. Eles a chamam de ""Sigilo"".",,,"Мы собирали информацию по крупицам из обрывков файлов Программиста и выяснили, что Орден поклоняется разумному оружию. Они называют его «Сигилом».", -"The piece you touched and recovered is one of five. It wields power drawn from the user's own life force. While you live, you control its power.",TXT_SUB_MAP10_2,,,,"Díl, kterého jsi se dotknul a ponechal si, je jeden z pěti. Mocní se silou, napájenou ze životní energie jejího majitele. Dokud žiješ, ovládáš jeho sílu.","Das Teil, das du berührt und gefunden hast, ist eines von fünf. Es bezieht die Kraft von der Lebensenergie des Benutzers. So lange du lebst, kontrollierst du seine Kraft.",,,"La pieza que has tocado y recuperado es una de cinco. Esgrime poder tomado de la propia fuerza de vida del usuario. Mientras vivas, controlas su poder.",,,"La pièce que vous avez touché et récupéré n'est qu'une parmi cinq. Elle utilise la force vitale de son utilisateur. Tant que vous êtes en vie, vous son pouvoir sous votre contrôle.",,"Il pezzo che hai toccato e recuperato è solo uno di cinque. Utilizza la forza vitale dell'utilizzatore. Finchè sei vivo, hai il potere sotto il tuo controllo.","君が欠片を取り戻したがそれは5つある内の1つだ。 +だが気をつけておけ、ヤツは熱で敵を蒸発させられるとの報告があるからな。","... 프로그래머: 아콜라이트들을 통제하는 인공지능의 창조자 말입니다. 그를 파괴하면 일격으로 오더의 군대를 무력화시킬 수 있을 겁니다. 하지만 조심하세요, 보고에 의하면 그는 자기 상대를 가루로 만들어 버린다는군요.","...de programmeur: maker van de AI die de Acolieten bestuurt. Vernietig de programmeur, en we kunnen de troepen van de Orde met een enkele klap verlammen. Maar opgelet: we hebben meldingen dat hij aanvallers kan verdampen.","...programmereren: skaperen av AI-en som kontrollerer akolyttene. Ødelegger vi Programmereren, kan vi lamme Ordenens tropper med ett slag. Men forsiktighet: Vi har rapporter om at han kan pulverisere angripere.","...Programista: twórca SI, która kontroluje Akolitów. Zniszcz Programistę, a możemy sparaliżować wojska Zakonu jednym uderzeniem. Ale uwaga: mamy doniesienia, że potrafi on wyparować napastników.","...o Programador: o criador da inteligência artificial que controla os Acólitos. Destrua o programador e, assim, poderemos prejudicar as tropas da Ordem com um único golpe. Mas cuidado: temos relatos de que ele pode vaporizar aqueles que atacam.",,"...Programatorul: creatorul inteligenței artificiale care controlează Acoliții. Distruge-l, și vom nimicii trupele Ordinului cu o singură lovitură: avem rapoarte care spun că poate vaporiza atacatorii.","...Программистом — создателем ИИ, контролирующего служителей. Уничтожь Программиста, и мы разделаемся с войсками Ордена одним ударом. Но осторожнее — нам докладывали, что он умеет... испепелять нападающих.",,...Programmeraren: skaparen av den intelligenta intelligens som kontrollerar akoliterna. Förstör Programmeraren och vi kan lamslå ordens trupper med ett enda slag. Men var försiktig: vi har rapporterat att han kan förånga angripare.,"...Programcı: Yardımcıları kontrol eden yapay zekanın yaratıcısı. Programcı'yı yok edersek, Tarikat'ın birliklerini tek bir darbeyle etkisiz hale getirebiliriz. Ama dikkat: Saldırganları buharlaştırabildiğine dair raporlarımız var." +"Fragments assembled from the Programmers files tell us that the Order is worshipping an intelligent weapon. They call it ""the Sigil"".",TXT_SUB_MAP10_1,MAP10: Macil.,,,"Útržky poskládané z Programátorových souborů nám říkají, že Řád uctívá inteligentní zbraň. Říkají jí „Pečeť“.","Fragmenter, der er samlet fra Programmerens filer, fortæller os, at Ordenen tilbeder et intelligent våben. De kalder det ""Sigil"".","Fragmente, zusammengestellt aus den Dateien des Programmierers, sagen uns, dass der Orden eine intelligente Waffe verehrt. Sie nennen sie „Das Sigil“.",,,"Fragmentos reunidos de los archivos del Programador nos dicen que la Orden adora un arma inteligente. La llaman ""el Emblema"".",,Ohjelmoitsijan tiedostoista kerättyjen pirstaleiden mukaan Veljeskunta palvoo älykästä asetta. He kutsuvat sitä Sinetiksi.,"Des fragments des fichiers du Programmeur que nous avons assemblés nous disent que l'Ordre vénère une arme intelligente. Ils l'appelent le ""Sigil"".","A Programozó fájljainak töredékeiből kiderítettük, hogy a Rend egy intelligens fegyverhez imádkozik. Csak ""Pecsét"" néven említik.","Frammenti dei file del Programmatore che abbiamo assemblato ci dicono che l'Ordine venera un'arma intelligente. La chiamano ""il Sigillo"".","プログラマーの資料を要約するとその欠片はオーダー達が崇拝する知性を持った武器、 +'シジル'だ。","프로그래머의 파괴된 기록들을 복원해보니, 오더가 자아를 가진 한 무기를 숭배하고 있다는군요. 그들은 이걸 “시질”이라고 부릅니다.","Fragmenten uit de Programmers bestanden vertellen ons dat de Orde een intelligent wapen aanbidt. Ze noemen het ""de Sigil"".","Fragmenter fra Programmererens filer forteller oss at Ordenen tilber et intelligent våpen. De kaller det ""Sigil"".","Fragmenty zebrane z akt Programistów mówią nam, że Zakon czci inteligentną broń. Nazywają ją ""Sigil"".","Os fragmentos dos relatórios sobre o Programador que conseguimos juntar dizem que a Ordem está venerando uma arma inteligente. Eles a chamam de ""Sigilo"".",,"Fragmentele asamblate din fișierele Programatorului ne spun că Ordinul venerează o armă inteligentă. O numesc ""Sigiliul"".","Мы собирали информацию по крупицам из обрывков файлов Программиста и выяснили, что Орден поклоняется разумному оружию. Они называют его «Печатью».",,"Fragment som samlats ihop från Programmerarens filer säger oss att Orden dyrkar ett intelligent vapen. De kallar det ""Sigil"".","Programcıların dosyalarından toplanan parçalar bize Tarikat'ın akıllı bir silaha taptığını söylüyor. Ona ""Sigil"" diyorlar." +"The piece you touched and recovered is one of five. It wields power drawn from the user's own life force. While you live, you control its power.",TXT_SUB_MAP10_2,〃,,,"Díl, kterého jsi se dotknul a ponechal si je jeden z pěti. Mocní se silou, napájenou ze životní energie jejího majitele. Dokud žiješ, ovládáš jeho sílu.","Det stykke, du rørte og fandt, er et af fem. Det udøver kraft fra brugerens egen livskraft. Mens du lever, kontrollerer du dens kraft.","Das Teil, das du berührt und gefunden hast, ist eines von fünf. Es bezieht die Kraft von der Lebensenergie des Benutzers. So lange du lebst, kontrollierst du seine Kraft.",,,"La pieza que has tocado y recuperado es una de cinco. Esgrime poder tomado de la propia fuerza de vida del usuario. Mientras vivas, controlas su poder.",,"Koskettamasi osanen, jonka otit talteen, on yksi viidestä. Se saa voimansa käyttäjänsä omasta elämänvoimasta. Niin kauan kuin sinä elät, hallitset sen voimaa.","La pièce que vous avez touché et récupéré n'est qu'une parmi cinq. Elle utilise la force vitale de son utilisateur. Tant que vous êtes en vie, vous son pouvoir sous votre contrôle.","A darabka amit megérintettél és visszaszereztél csak egy az ötből. Erejét a hordozója életerejéből meríti. Amíg tehát élsz, tudod irányítani.","Il pezzo che hai toccato e recuperato è solo uno di cinque. Utilizza la forza vitale dell'utilizzatore. Finchè sei vivo, hai il potere sotto il tuo controllo.","君が欠片を取り戻したがそれは5つある内の1つだ。 使用者の生命を吸い上げ激しい力を引き出す。 -ただ制御下におけるのは生きている間だけだ。","당신이 건져낸 조각은 다섯 개의 조각 중 하나입니다. 이것은 사용자의 생명력을 빨아들여 위력을 발휘합니다. 당신이 살아있는 동안, 녀석의 힘은 당신의 것입니다.","Het stuk dat je hebt aangeraakt en teruggevonden is een van de vijf. Het heeft kracht die getrokken wordt uit de eigen levenskracht van de gebruiker. Terwijl je leeft, heb je de macht ervan in handen.",,"A peça que você tocou e recuperou é uma das cinco peças. Seu poder vem da própria energia de vida de quem a usa. Enquanto você viver, você controla o poder dela.",,,"Тот фрагмент, что ты подобрал и активировал, — один из пяти. Он использует мощь, которую черпает из жизненных сил владельца. Пока ты жив, она подвластна тебе.", -"The shock which knocked you out was the Sigil piece tuning itself to you, your pulse and brain waves. You can wield it, but at a cost: it will drain you dry.",TXT_SUB_MAP10_3,,,,"Ránu, která tě uspala, způsobil ten díl Pečeti, ladící sám sebe k tobě, tvému pulzu a mozkovým vlnám. Můžeš jej používat, ale za určitou cenu: Vysaje tě to.","Der Schock, durch den du das Bewusstsein verloren hast, wurde verursacht, als das Sigilteil sich auf dich, deinen Puls und deine Gehirnwellen eingestellt hat. Du kannst es benutzen, aber es wird dich austrocknen.",,,"El choque que te derribó fue la pieza del Emblema sintonizándose contigo, con tu pulso y ondas cerebrales. Puedes empuñarla, pero con un precio: Te dejará seco.",,,"Le choc qui vous a rendu inconscient venait de la pièce du Sigil qui s'est alignée sur votre énergie vitale, votre pouls et vos ondes cérébrales. Vous pouvez l'utiliser, mais au coût de votre vie.",,"Lo schock che ti ha fatto perdere i sensi era un pezzo del Sigillo che si è allineato con la tua energia vitale, il tuo polso e le tue onde cerebrali. Puoi usarlo, ma ad un costo: ti prosciugherà in pieno.","君を気絶させた衝撃は、シジルの欠片が脈拍と脳波を同期させた際に起こした様だ。 -それを振り回す時は気を付けろ、代償で体が干上がってしまうらしい。","당신을 기절시킨 충격은 시질이 당신의 심박과 뇌파와 반응하면서 비롯되었습니다. 이 무기를 써도 되지만, 조심하세요: 당신을 말려 죽일 수도 있으니까.","De schok die je bewusteloos maakte, was de Sigil die zich op jou, je pols en hersengolven, afstemde. Je kunt het gebruiken, maar tegen een prijs: het zal je droog laten vallen.",,"O choque que te derrubou foi da peça do Sigilo se calibrando a você, com o seu pulso e suas ondas cerebrais. Você pode usá-la, mas tem um custo: ela vai te drenar por completo.",,,"Ты потерял сознание, потому что фрагмент Сигила подстраивался под тебя, под твоё сердцебиение и мозговые ритмы. Теперь ты сможешь им пользоваться, но он будет взымать свою плату, иссушая тебя.", -One piece constitutes awesome power. Possession of all five pieces would be devastating and would give the user total control of the planet.,TXT_SUB_MAP10_4,,,,Jen jeden díl obsahuje ohromnou sílu. Vlastnictví všech pěti dílů by bylo devastující a jeho majitel by byl schopen ovládat celou planetu.,"Ein Teil stellt große Macht dar. Der Besitz aller fünf Teile wäre verheerend, und der Nutzer hätte die totale Kontrolle über den Planeten.",,,"Una pieza constituye un poder impresionante, poseer las cinco piezas sería devastador y daría al usuario control total del planeta.",,,Une pièce représente un pouvoir phénoménal. Posséder toutes les cinq serait dévastateur: cela donnerait à l'utilisateur le contrôle total sur la planète.,,Un pezzo costituisce un potere fenomenale. Il possesso di tutti i cinque pezzi sarebbe devastante: darebbe all'utilizzatore il controllo totale sul pianeta.,"だがたった一つでも相当な力を放つ。 -それが5つ揃った時は圧倒的な力で世界をも支配下に置けるだろう。","하나의 조각으로도 엄청난 위력을 가지게 되고, 다섯 조각 모두를 얻으면 이 세상을 평정할 만큼 강력한 위력을 발휘할 것입니다.",Een stuk vormt ontzagwekkende kracht. Het bezit van alle vijf de stukken zou verwoestend zijn en zou de gebruiker de volledige controle over de planeet geven.,,Uma das peças possui um poder tremendo. Possuir todas as cinco peças seria devastador e daria controle total do planeta ao utilizador.,,,Один фрагмент — уже немалая сила. Пять фрагментов будут опустошающей силой. Их владелец получит полную власть над планетой., -"Listen, this com unit tells me that you're 100% human. I've been ordered to bring you in, we're talking trust here. Betray me and pay. Oh, and by the way, you can call me Blackbird.",TXT_SUB_LOG2,STRIFE1.WAD: MAP02,,,"Poslyš, tento komunikátor mi říká, že jsi na sto procent člověkem. Dostala jsem rozkaz tě přivést te k nám, jde o důvěryhodnou záležitost. Zraď mě a zaplatíš. Jo, a mimochodem, můžeš mi říkat Straka.","Hör zu, dieser Kommunikator sagt mit, dass du noch 100% menschlich bist. Mir wurde aufgetragen, dich zu unserer Zentrale zu führen. Wir reden über Vertrauen, wenn du mich verrätst, wirst du bezahlen. Übrigens, du kannst mich Blackbird nennen.",,,"Escucha, esta unidad de comunicación me dice que eres 100% humano. Se me ha ordenado hacerte entrar, hablamos en confianza. Traicióname y paga. Oh, por cierto, puedes llamarme Blackbird.",,,"Ecoute, ce communicateur me dit que tu est 100% humain. On m'a ordonnée de te ramener, c'est une question de confiance. Trahis-moi et tu paieras. Oh, et tu peux m'appeler Blackbird.",,,"聞こえるか、この無線機がアナタは100%人間だと判断した。 +ただ制御下におけるのは生きている間だけだ。","당신이 건져낸 조각은 다섯 개의 조각 중 하나입니다. 이것은 사용자의 생명력을 빨아들여 위력을 발휘합니다. 당신이 살아있는 동안, 녀석의 힘은 당신의 것입니다.","Het stuk dat je hebt aangeraakt en teruggevonden is een van de vijf. Het heeft kracht die getrokken wordt uit de eigen levenskracht van de gebruiker. Terwijl je leeft, heb je de macht ervan in handen.","Brikken du berørte og gjenopprettet er en av fem. Den har kraft hentet fra brukerens egen livskraft. Mens du lever, kontrollerer du dens kraft.","Kawałek, który dotknąłeś i odzyskałeś, jest jednym z pięciu. Włada mocą czerpaną z własnej siły życiowej użytkownika. Póki żyjesz, kontrolujesz jego moc.","A peça que você tocou e recuperou é uma das cinco peças. Seu poder vem da própria energia de vida de quem a usa. Enquanto você viver, você controla o poder dela.",,"Piesa pe care ai atins-o și recuperat-o e una din cinci. Își trage puterea din deținător. Cât trăiești, o controlezi.","Тот фрагмент, что ты подобрал и активировал, — один из пяти. Он использует мощь, которую черпает из жизненных сил владельца. Пока ты жив, она подвластна тебе.",,Den bit som du rörde vid och återfann är en av fem. Den använder kraft som hämtas från användarens egen livskraft. Så länge du lever kontrollerar du dess kraft.,"Dokunduğunuz ve kurtardığınız parça beş taneden biri. Kullanıcının kendi yaşam gücünden alınan gücü kullanıyor. Yaşadığın sürece, onun gücünü kontrol ediyorsun." +"The shock which knocked you out was the Sigil piece tuning itself to you, your pulse and brain waves. You can wield it, but at a cost: it will drain you dry.",TXT_SUB_MAP10_3,〃,,,"Ránu, která tě uspala, způsobil ten díl Pečeti, ladící sám sebe k tobě, tvému pulzu a mozkovým vlnám. Můžeš jej používat, ale za určitou cenu: Bude tě vysilovat.","Det chok, der slog dig bevidstløs, var Sigilstykket, der indstillede sig på dig, din puls og dine hjernebølger. Du kan bruge det, men det har en pris: det vil dræne dig for energi.","Der Schock, durch den du das Bewusstsein verloren hast, wurde verursacht, als das Sigilteil sich auf dich, deinen Puls und deine Gehirnwellen eingestellt hat. Du kannst es benutzen, aber es wird dich austrocknen.",,,"El choque que te derribó fue la pieza del Emblema sintonizándose contigo, con tu pulso y ondas cerebrales. Puedes empuñarla, pero con un precio: Te dejará seco.",,"Kokemasi sysäys, joka tyrmäsi sinut, oli Sinetin virittäytymistä sinuun, sinun sykkeeseesi ja aivoaaltoihisi. Hallitset sitä, mutta sillä hinnalla, että se imee sinut kuiviin.","Le choc qui vous a rendu inconscient venait de la pièce du Sigil qui s'est alignée sur votre énergie vitale, votre pouls et vos ondes cérébrales. Vous pouvez l'utiliser, mais au coût de votre vie.","A sokk ami kiütött nem volt más, mint maga a Pecsét ráhangolódása a pulzusodra és agyhullámodra. Forgathatod mint egy kardot, de ára van: kiszívja az életerődet.","Lo schock che ti ha fatto perdere i sensi era un pezzo del Sigillo che si è allineato con la tua energia vitale, il tuo polso e le tue onde cerebrali. Puoi utilizzarlo, ma ad un costo: ti prosciugherà in pieno.","君を気絶させた衝撃は、シジルの欠片が脈拍と脳波を同期させた際に起こした様だ。 +それを振り回す時は気を付けろ、代償で体が干上がってしまうらしい。","당신을 기절시킨 충격은 시질이 당신의 심박과 뇌파와 반응하면서 비롯되었습니다. 이 무기를 써도 되지만, 조심하세요: 당신을 말려 죽일 수도 있으니까.","De schok die je bewusteloos maakte, was de Sigil die zich op jou, je pols en hersengolven, afstemde. Je kunt het gebruiken, maar tegen een prijs: het zal je droog laten vallen.","Sjokket som slo deg ut var Sigil-brikken som innstilte seg på deg, pulsen din og hjernebølgene dine. Du kan bruke det, men det koster: det vil tappe deg for krefter.","Wstrząs, który cię znokautował, to kawałek Sigilu, który dostroił się do ciebie, twojego pulsu i fal mózgowych. Możesz nim władać, ale za pewną cenę: wyczerpie cię do cna.","O choque que te derrubou foi da peça do Sigilo se calibrando a você, com o seu pulso e suas ondas cerebrais. Você pode usá-la, mas tem um custo: ela vai te drenar por completo.",,"Șocul care te-a lăsat inconștient a fost piesa care s-a întors asupra ta. O controlezi, dar cu un preț: o să te sece.","Ты потерял сознание, потому что фрагмент Печати подстраивался под тебя, под твоё сердцебиение и мозговые ритмы. Теперь ты сможешь им пользоваться, но он будет взымать свою плату, иссушая тебя.",,"Den chock som slog dig medvetslös var att Sigilstycket anpassade sig till dig, din puls och dina hjärnvågor. Du kan använda den, men till ett pris: den kommer att tömma dig på vatten.","Sizi bayıltan şok, Sigil parçasının kendisini size, nabzınıza ve beyin dalgalarınıza göre ayarlamasıydı. Onu kullanabilirsin ama bir bedeli var: Seni kurutacak." +One piece constitutes awesome power. Possession of all five pieces would be devastating and would give the user total control of the planet.,TXT_SUB_MAP10_4,〃,,,Jen jeden díl obsahuje ohromnou sílu. Vlastnictví všech pěti dílů by bylo devastující a jeho majitel by byl schopen ovládat celou planetu.,Et stykke udgør en fantastisk kraft. Besiddelse af alle fem stykker ville være ødelæggende og ville give brugeren total kontrol over planeten.,"Ein Teil stellt große Macht dar. Der Besitz aller fünf Teile wäre verheerend, und der Nutzer hätte die totale Kontrolle über den Planeten.",,,"Una pieza constituye un poder impresionante, poseer las cinco piezas sería devastador y daría al usuario control total del planeta.",,Jo yhdessä osasessa piilee valtava mahti. Kaikkien viiden osasen hallitseminen olisi tuhoisaa ja antaisi käyttäjälleen täydellisen otteen planeetasta.,Une pièce représente un pouvoir phénoménal. Posséder toutes les cinq serait dévastateur: cela donnerait à l'utilisateur le contrôle total sur la planète.,"Egy darab nagy hatalmat biztosít hordozójának. Azonban mind az öt darabka együtt emberfeletti erővel ruházná fel, és az egész bolygó felett átvenné a hatalmat.",Un pezzo costituisce un potere fenomenale. Il possesso di tutti i cinque pezzi sarebbe devastante: darebbe all'utilizzatore il controllo totale sul pianeta.,"だがたった一つでも相当な力を放つ。 +それが5つ揃った時は圧倒的な力で世界をも支配下に置けるだろう。","하나의 조각으로도 엄청난 위력을 가지게 되고, 다섯 조각 모두를 얻으면 이 세상을 평정할 만큼 강력한 위력을 발휘할 것입니다.",Een stuk vormt ontzagwekkende kracht. Het bezit van alle vijf de stukken zou verwoestend zijn en zou de gebruiker de volledige controle over de planeet geven.,Ett stykke utgjør en fantastisk kraft. Besittelse av alle fem brikkene ville være ødeleggende og gi brukeren total kontroll over planeten.,Jeden kawałek stanowi niesamowitą moc. Posiadanie wszystkich pięciu kawałków byłoby niszczące i dałoby użytkownikowi całkowitą kontrolę nad planetą.,Uma das peças possui um poder tremendo. Possuir todas as cinco peças seria devastador e daria controle total do planeta ao utilizador.,,O piesă constituie putere uimitoare. Posesiunea tuturor pieselor ar fi devastatore și ar da deținătorului control asupra întregii planete.,Один фрагмент — уже немалая сила. Пять фрагментов будут опустошающей силой. Их владелец получит полную власть над планетой.,,Ett stycke utgör en fantastisk kraft. Att äga alla fem delar skulle vara förödande och ge användaren total kontroll över planeten.,Tek bir parça müthiş bir güç demektir. Beş parçaya birden sahip olmak yıkıcı olur ve kullanıcıya gezegenin kontrolünü tamamen verir. +"Listen, this com unit tells me that you're 100% human. I've been ordered to bring you in, we're talking trust here. Betray me and pay. Oh, and by the way, you can call me Blackbird.",TXT_SUB_LOG2,MAP02: After getting the com unit from Rowan and leaving his room.,,,"Poslyš, tento komunikátor mi říká, že jsi na sto procent člověkem. Dostala jsem rozkaz tě přivést tě k nám; jde o důvěryhodnou záležitost - zraď mě a zaplatíš. Jo, a mimochodem, můžeš mi říkat Straka.","Hør, denne com-enhed fortæller mig, at du er 100 % menneskelig. Jeg er blevet beordret til at bringe dig ind, vi taler om tillid her. Forråd mig og betal. Og forresten, du kan kalde mig Blackbird.","Hör zu, dieser Kommunikator sagt mit, dass du noch 100% menschlich bist. Mir wurde aufgetragen, dich zu unserer Zentrale zu führen. Wir reden über Vertrauen, wenn du mich verrätst, wirst du bezahlen. Übrigens, du kannst mich Blackbird nennen.",,,"Escucha, este intercomunicador me dice que eres 100% humano. Se me ha ordenado dejarte entrar, así que hablamos en confianza. Traicióname y pagarás. Ah, por cierto, puedes llamarme BlackBird.","Escucha, este intercomunicador me dice que eres 100% humano. Se ordenadó dejarte entrar, así que hablamos en confianza. Traicióname y te vas a arrepentir. Ah, por cierto, puedes llamarme BlackBird.","Kuule, tämä viestintälaite ilmaisee sinun olevan sataprosenttisesti ihminen. Minut on määrätty tuomaan sinut meidän joukkoomme; puhumme luottamuksellisesti. Petä minut ja saat luvan maksaa. Ja muuten, voit kutsua minua Blackbirdiksi.","Ecoute, ce communicateur me dit que tu est 100% humain. On m'a ordonnée de te ramener, c'est une question de confiance. Trahis-moi et tu paieras. Oh, et tu peux m'appeler Blackbird.","Figyelj csak, azt mutatja ez a kommunikációs egység hogy 100%-ban ember vagy. Azt az utasítást kaptam, hogy hozzalak be. Vakon beléd vetjük a bizalmunkat, de tudd, hogy ha elárulsz minket meglakolsz. Ja, és hívhatsz Feketerigónak.","Ascolta, questa unità di comunicazione mi dice che sei 100% umano. Ho l'ordine di farti arrivare da noi, e quindi stiamo parlando di fiducia. Se mi tradisci la pagherai cara. Comunque, mi puoi chiamare Blackbird.","聞こえるか、この無線機がアナタは100%人間だと判断した。 私はアナタを信頼して良いとみて連れて来るよう命じられた、 -反乱への報酬は期待して良いわ。ああ、それと、私の名はブラックバードよ。","잘 들어, 이 통신기에 따르면 넌 100% 인간이야. 너를 믿어도 될 거 같으니 우리 편으로 끌어모으라는 지시를 받았어. 배신했다간 대가를 치를 거야. 아, 그리고, 날 블랙버드라고 불러줘.","Luister, deze com-unit zegt me dat je 100% menselijk bent. Ik heb opdracht gekregen om je binnen te halen, we hebben het hier over vertrouwen. Verraad me en betaal. Oh, en trouwens, je mag me Blackbird noemen.",,"Ouça, este comunicador me diz que você é 100% humano. Recebi ordens para te trazer até aqui. É melhor você ser de confiança. Se você me trair, você me paga. Ah, a propósito, pode me chamar de Blackbird.",,,"Слушай — судя по этому передатчику, ты на сто процентов человек. Я получила приказ показать тебе дорогу к нам. Как видишь, тебе доверяют, но если предашь меня — пожалеешь. И да, обращайся ко мне «Чёрный дрозд». ", -"Head over to the old town hall. After the Order bombed it, Macil had a tunnel built that lets us get in and out without the acolytes' knowledge.",TXT_SUB_LOG3,STRIFE1.WAD: MAP02,,,"Zamiř ke staré radnici. Když ji Řád vybombardoval, Macil nechal postavit tunel, který nám dovoluje se dostat dovnitř a ven bez vědomí akolytů.","Geh zum alten Rathaus. Macil hat einen Tunnel bauen lassen, durch den wir dort reinkommen, ohne dass die Ministranten das mitbekommen.",,,"Dirígete al antiguo ayuntamiento. Después de que lo bombardeara la Orden, Macil hizo construir un túnel que nos permite entrar y salir sin que los acólitos lo sepan.",,,Dirige-toi vers l'ancienne mairie. Macil a fait construire un tunnel après que L'Ordre l'ait bombardée. Il nous permet d'y entrer sans que l'Ordre nous remarque.,,,"旧市庁舎に向かうんだ。オーダーに爆撃された後 -そこにマシルがアコライトに関わる者を欺く為の抜け道を用意している。",구 시청으로 향해. 오더가 이곳을 폭격한 후에 마실이 그곳에 아콜라이트들이 모르는 통행로를 만들어놨어.,"Ga naar het oude stadhuis. Nadat de Orde het gebombardeerd had, liet Macil een tunnel bouwen die ons in en uit laat stappen zonder dat de acolieten het wisten.",,"Vá até à antiga prefeitura. Depois que a Ordem a bombardeou, Macil mandou construir um túnel que nos leva e tira de lá sem os acólitos perceberem.",,,"Отправляйся к старой ратуше. После того, как Орден взорвал её, Мэйсил построил там туннель, который позволяет нам входить и выходить без ведома служителей.", -"Go through the door on your left, then the one on the right. The guard's name is Geoff. Tell him you need gold.",TXT_SUB_LOG4,STRIFE1.WAD: MAP02,,,"Projdi dveřmi nalevo a pak napravo. Hlídač se jmenuje Geoff. Řekni mu, že potřebuješ zlato.","Geh durch die linke Tür, dann durch die rechte. Der Wächter heißt Geoff. Sag ihm du brauchst Gold.",,,"Ve por la puerta a tu izquierda, y luego a tu derecha. El guardia se llama Geoff. Dile que necesitas oro.",,,Passe par la porte à gauche puis celle à droite. Le garde s'appelle Geoff. Dis-lui que tu as besoin d'argent.,,,"すぐ左のドアを通り、右のドアから小部屋に入るんだ。 -見張りの名はジェフ。金が必要だ と言えば通じる。","네 왼쪽의 문으로 들어간 후, 다시 오른쪽의 문으로 가. 경비의 이름은 제프야. 그에게 골드가 필요하다고 얘기해.","Ga door de deur links van je, dan die rechts van je. De bewaker heet Geoff. Zeg hem dat je goud nodig hebt.",,Vá pela porta à sua esquerda e depois a da direita. O nome do guarda é Geoff. Diga a ele que você precisa de ouro.,,,"Пройди за левую дверь, затем иди направо. Стражника зовут Джефф. Скажи ему, что тебе нужно золото.", -"Irale is the Front's ""fixer"". He's behind the unmarked door next to the weapons shop.",TXT_SUB_LOG5,STRIFE1.WAD: MAP03,,,Irale je „dealer“ Fronty. Je za neoznačenými dveřmi vedle obchodu se zbraněmi.,Irale ist der „Bastler“ der Front. Er ist hinter der unmarkierten Tür neben dem Waffengeschäft.,,,"Irale es el ""apañador"" del Frente. Está detrás de la puerta sin marcar junto a la tienda de armas.",,,Irale est le receleur du front. Il est derrière la porte non marquée à côté du magasin d'armes.,,,"イラールとはフロントの'仲介者'よ。彼は武器屋の隣のマークされてないドアに居る。 -発電所に近い所だ。",이롤리는 프론트의 수리공이기도 해. 무기상점 근처에 그의 가게로 향하는 문이 있을 거야.,"Irale is de ""fixer"" van de Front. Hij zit achter de ongemarkeerde deur naast de wapenwinkel.",,"Irale é o ""quebra-galho"" da Frente. Ele está atrás da porta desmarcada próxima ao depósito de armas.",,,Ирэйл — «наладчик» Сопротивления. Ты найдёшь его за дверью без вывески возле оружейного магазина., -Remember: kill with stealth instead of force. You won't set off the alarms.,TXT_SUB_LOG6,STRIFE1.WAD: MAP02,,,Pamatuj: Zabíjej potichu. Nespustíš poplach.,Denk daran: Töte lautlos und du wirst den Alarm nicht auslösen.,,,"Recuerda: mata con sigilo, no con fuerza, y no activarás las alarmas.",,,"Souviens-toi: Tue avec discrétion, pas avec force, et tu n'activeras pas les alarmes.",,,覚えておいて:静かに殺す時はナイフか毒矢だ。警報を鳴らすと厄介なことになる。,기억해: 소음 없이 조용히 죽여. 그럼 경보를 울리지 않을 테니까.,Onthoud: dood met heimelijke in plaats van met geweld. Je laat de alarmen niet afgaan.,,Lembre-se: mate com cautela ao invés de força. Assim você não ativará os alarmes.,,,"Запомни: убивай бесшумно, не лезь на рожон, и ты не поднимешь тревогу.", -"All I know about the governor is that he's playing both sides to the middle. Here's his so-called ""mansion.""",TXT_SUB_LOG7,STRIFE1.WAD: MAP02,,,"O guvernérovi vím jen to, že sympatizuje s oběma stranami. Tady je jeho rádoby „sídlo“.","Vom Gouverneur weiß ich nur, dass er beide Seiten gegeneinander ausspielt. Hier ist seine sogenannte „Villa.“",,,"Todo lo que sé del gobernador es que juega entre ambos bandos. Aquí está su supesta ""mansión"".",,,"Tout ce que je sais au sujet du gouverneur est qu'il est un agent double de chaque côté. Voilà son soi-disant ""manoir"".",,,"私が知事について知っていることは、町の中央で双方を遊ばせてる様だ。 -ソイツがここいらを'マンション'と呼んでいる。",내가 알기로는 모렐 총독은 두 세력을 가지고 노는 걸 좋아한대. 여기는 그의 '저택'이라는 곳이야.,"Het enige wat ik van de gouverneur weet is dat hij beide kanten van de gouverneur naar het midden speelt. Hier is zijn zogenaamde ""herenhuis"".",,"Tudo o que eu sei sobre o governador é que ele está jogando entre dois lados. Aqui fica a sua suposta ""mansão"".",,,"Я знаю о губернаторе только то, что он пытается подыграть обеим сторонам, оставаясь посередине. Вот его так называемый «особняк».", -Ugh. The dregs of humanity have certainly found a home.,TXT_SUB_LOG8,,,,Fuj. Spodina lidstva si rozhodně našla domov.,Ugh. Der Bodensatz der Menschheit hat definitiv ein Zuhause gefunden.,,,Ugh. La basura humana ciertamente ha encontrado un hogar.,,,"Eugh, les loques de l'humanité ont trouvé leur maison, on dirait.",,,,"으윽, 우리 중 나쁜 놈들만 보금자리를 구한 것 같네.",Ugh. De bezinksels van de mensheid hebben zeker een thuis gevonden.,,Urgh. A escória da humanidade certamente encontrou um lar.,,,Фу. Самое место для отбросов человечества., -Calling Mourel sleazy is paying him a compliment. He's mongrel turd on a stick.,TXT_SUB_LOG9,STRIFE1.WAD: MAP02,,,"Nazývat Mourela slizákem by mu lichotilo, svinský parchant jeden podělaný.","Mourel als 'verschlagen' zu bezeichnen wäre, ihm ein Kompliment zu machen. Er ist ein Haufen Hundescheiße.",,,Llamar a Mourel sucio es un halago. Es mierda de perro callejero en un palo.,,,Appeler Mourel un rat serait être gentil. Il est une sacrée brochette de merde.,,,"モーレルにとって汚職議員は誉め言葉だ。 -ソイツはクソを漏らした'駄犬'でしかないからな。",모렐에게 행실이 지저분하다고 말하는 건 칭찬에 불과해. 저놈은 이기적인 똥개새끼라고.,Mourel slordig noemen is een compliment voor hem. Hij is een bastaard op een stokje.,,Chamar o Mourel de picareta é elogio. Ele é um total desgraçado de merda.,,,"Назвать Моурела подлым, значит сделать ему комплимент. Кусок дерьма на палочке...", -We need to speak with someone who knows the old town and where this coupling is. Command says: find MacGuffin. ,TXT_SUB_LOG10,STRIFE1.WAD: MAP02,,,"Musíme si promluvit s někým, kdo zná staré město a kde se tahle spojka nalézá. Vedení říká najít MacGuffina.","Wir müssen mit jemandem reden, der die alte Stadt kennt und weiß, wo diese Anzapfung it. Die Kommandozentrale sagt, finde MacGuffin.",,,Necesitamos hablar con alguien que conozca el viejo pueblo y donde se encuentra el acoplamiento. El Comando dice: encuentra a MacGuffin.,,,On doit parler à quelqu'un qui connaît la vieille ville et où se trouve le coupleur. Le commandement me dit qu'il faut trouver MacGuffin.,,,"我々は何処にあるかについてはオールドタウンに知っている者がいる。 -指令が言うには マクガフィンに会え。",동력선의 위치를 알 수 있을 만한 토박이 주민과 이야기해봐. 본부가 말하길: 맥거핀을 찾으래.,We moeten met iemand spreken die de oude stad kent en waar deze koppeling is. Het commando zegt: zoek MacGuffin.,,Precisamos falar com alguém que conheça a velha cidade e onde fica essa conexão. O comando diz: encontre MacGuffin.,,,"Нам нужен кто-то, кто знает старый город и может подсказать, где эта муфта. В штабе говорят, что тебе поможет МакГаффин.", -"He's in what's politely called the ""bum hole"". Take the walkway by the sewage plant and head down the stairs.",TXT_SUB_LOG11,STRIFE1.WAD: MAP02,,,"Najdeš ho na místě, kterému zdvořile říkají „zadnice“. Jdi přes chodník u čističky a sejdi schody.","Er ist, was höflich gesagt, das „Pennerloch“ genannt wird. Gehe zum Weg zur Kläranlage und von dort die Treppe herunter.",,,"Está en lo que educadamente se llama el ""hoyo vagabundo"". Toma la pasarela junto a la planta de aguas residuales y baja por las escaleras.",,,"Il se trouve dans ce qu'on appelle poliment le ""trou à rats"", suis la coursive près de la centrale de traitement des égouts et descend les escaliers.",,,"彼は行儀よく'バムホール'と呼ばれる場所に居る。 -下水処理場の側の階段を下りた小さい部屋だ。",겸손하게 말하자면 그는 “노숙자 굴”에 살아. 하수도에서 보도를 지나간 뒤 계단을 건너.,"Hij zit in wat beleefd het ""kontje"" wordt genoemd. Neem de loopbrug bij de rioolwaterzuiveringsinstallatie en ga de trap af.",,"Ele está num lugar chamado ""toca de rato"". Vá pela passarela perto da usina de tratamento e desça as escadas.",,,"Он в том месте, что вежливо называют «бомжевая нора». Пройди к очистным сооружениям и спустись по лестнице.", -Take your time with this mission. I can't get intel on this from Command.,TXT_SUB_LOG12,STRIFE1.WAD: MAP02,,,Dej si s touhle misí na čas. Nemůžu z velení dostat žádné informace.,Nimm dir Zeit für diese Mission. Ich erhalte keine Informationen aus der Kommandozentrale.,,,Tómate tu tiempo en esta misión. No puedo obtener inteligencia en esto del Comando.,,,"Prends ton temps, le commandement n'a rien à me donner au niveau informations.",,,この任務は時間が掛かりそうだ。私は司令部からこれ以上の情報は得る事は出来ない。,느긋하게 수행해도 좋아. 본부에도 이 정보를 모으는 데 문제가 있데.,Neem je tijd met deze missie. Ik kan hier geen informatie over krijgen van de Commandant.,,Não tenha pressa nesta missão. Não estou conseguindo obter inteligência sobre isso pelo Comando.,,,Не торопись с выполнением этого задания. Я не могу получить разведданные от штаба., -"You idiot! You've shut off the power to the jamming circuits we use to conceal our base from the Order. Head over to the town hall and take out the scanning crew, now!",TXT_SUB_LOG13,"STRIFE1.WAD: MAP02 - -(If the player destroys the Front’s power coupling)",,,"Ty debile! Odstřihnul jsi přívod proudu do rušiček, které používáme, abychom ukryli naší základnu před Řádem. Okamžitě si to zamiř k radnici a vybij průzkumnou četu!","Du Idiot! Du hast die Energie für unsere Störsender unterbrochen, mit denen wir unsere Basis vor dem Orden verborgen haben. Geh schnell zum Rathaus und schalte den Suchtrupp aus. ",,,"¡Idiota! Has apagado la energía a los circuitos de interferencia que usamos para ocultar nuestra base a la Orden. Dirígete al ayuntamiento y elimina al equipo de escaneo, ¡ahora!",¡Idiota! Quitaste la energía a los circuitos de interferencia que utilizamos para que la Orden no vea nuestra base. Dirígete al ayuntamiento y saca al equipo de escaneo.,,Idiot! Tu as désactivé les circuits brouilleurs qui cachaient notre base des senseurs de l'Ordre. Retourne vite à la mairie et tue l'équipe de scan maintenant!,,,"馬鹿者!お前はオーダーから我々の基地を隠す妨害回路を壊してしまった! -市庁舎に調査隊が向かった、今すぐ片付けろ!",이 멍청이야! 우리 기지를 오더로부터 은폐시켜주는 교란 장치의 동력을 끊어버렸잖아. 당장 시청으로 가서 탐색반들을 쓸어버려! 그다음에 총독에게 부서진 장치를 전해. 당장!,"Idioot! Je hebt de stroom naar de stoorcircuits die we gebruiken om onze basis te verbergen voor de Orde uitgeschakeld. Ga naar het stadhuis en haal de scannende bemanning eruit, nu!",,Seu idiota! Você desligou a energia para os circuitos de interferência que usamos para esconder a nossa base dos sensores da Ordem. Vá até a prefeitura e tire a equipe de busca de lá imediatamente!,,,"Идиот! Ты обесточил генератор радиопомех, с помощью которого мы скрывали местоположение нашей базы от Ордена. Возвращайся к ратуше и уничтожь разведывательную группу как можно скорее!", -"OK, ""Trust no one"" is the name of the game! Let's get that pass from the Governor and free those prisoners.",TXT_SUB_LOG14,"STRIFE1.WAD: MAP02 - -(If all blue acolytes in the town hall that appear after destroying the Front’s power coupling are killed)",,,"Dobře, „Nevěř nikomu“ je motto hry! Pojďme od guvernéra dostat tu propustku a osvoboďme ty vězně.","Ok, „Trau keinem“ heißt dieses Spiel. Lass uns den Gefängnispass vom Gouverneur holen und die Gefangenen befreien.",,,"OK, ¡""no te fies de nadie"" es el nombre del juego! Consigamos ese pase del Gobernador y liberemos esos prisioneros.",,,"Ok, ""ne fais confiance à personne"" est le thème du jour. Récupérons le passe du gouverneur et libérons les prisonniers.",,,よし、'信用しない'のが最も重要なことだ!壊れた配電機を渡して囚人を解放するんだ。,"좋아, '아무도 믿지 말라'가 이 게임의 이름이겠군! 그냥 총독과 대화하고 수감자들을 구출하자.","OK, ""Vertrouw niemand"" is de naam van het spel! Laten we die pas van de gouverneur halen en die gevangenen vrijlaten.",,"Ok, ""não confie em ninguém"" é o nome do jogo! Vamos pegar aquele passe do Governador e libertar esses prisioneiros.",,,"Что ж, эта игра называется «не верь никому»! Давай получим у губернатора пропуск в тюрьму и освободим пленников.", -Good move! The Governor is a lousy liar. That's our power coupling. Now let's get that pass.,TXT_SUB_LOG15,STRIFE1.WAD: MAP02,,,"Dobrý tah! Guvernér je mizerný lhář, tohle je naše spojka. Pojďme si pro tu propustku.",Das war klasse! Der Gouverneur ist ein lausiger Lügner. Das war unsere Anzapfung. Nun lass uns den Pass holen.,,,¡Buen paso! El gobernador es un mentiroso. Ese es nuestro acoplador de energía. Ahora consigamos ese pase.,,,Bien joué! Le gouverneur est un menteur. Voilà notre coupleur. Allons récupérer le passe.,,,"良い判断よ!知事は粗末な嘘を付いている。 +反乱への報酬は期待して良いわ。ああ、それと、私の名はブラックバードよ。","잘 들어, 이 통신기에 따르면 넌 100% 인간이야. 너를 믿어도 될 거 같으니 우리 편으로 끌어모으라는 지시를 받았어. 배신했다간 대가를 치를 거야. 아, 그리고, 날 블랙버드라고 불러줘.","Luister, deze com-unit zegt me dat je 100% menselijk bent. Ik heb opdracht gekregen om je binnen te halen, we hebben het hier over vertrouwen. Verraad me en betaal. Oh, en trouwens, je mag me Blackbird noemen.","Denne kommunikasjonsenheten forteller meg at du er 100 % menneskelig. Jeg har fått ordre om å hente deg inn, vi snakker om tillit her. Forråd meg og betal. Og forresten, du kan kalle meg Blackbird.","Słuchaj, to urządzenie mówi mi, że jesteś w 100% człowiekiem. Otrzymałem rozkaz sprowadzenia cię, mówimy tu o zaufaniu. Zdradzisz mnie i zapłacisz. Aha, i przy okazji, możesz mi mówić Blackbird.","Ouça, este comunicador me diz que você é 100% humano. Recebi ordens para te trazer até aqui. É melhor você ser de confiança. Se você me trair, você me paga. Ah, a propósito, pode me chamar de Blackbird.",,"Ascultă, unitatea asta îmi spune că ești 100% uman. Am primit ordin să te aduc, vorbim de încredere aici. Trădează-mă și plătești. Oh, și apropo, îmi poți spune Blackbird.","Слушай — судя по этому передатчику, ты на сто процентов человек. Я получила приказ показать тебе дорогу к нам. Как видишь, тебе доверяют, но если предашь меня — пожалеешь. И да, обращайся ко мне «Чёрный дрозд». ",,"Lyssna, den här kommunikationsenheten säger mig att du är 100 % mänsklig. Jag har fått order att ta in dig, vi pratar om förtroende här. Förråda mig och betala. Och förresten, du kan kalla mig Blackbird.","Dinle, bu iletişim birimi bana senin %100 insan olduğunu söylüyor. Seni getirmem emredildi, burada güvenden bahsediyoruz. Bana ihanet edersen bedelini ödersin. Bu arada bana Karatavuk diyebilirsin." +"Head over to the old town hall. After the Order bombed it, Macil had a tunnel built that lets us get in and out without the acolytes' knowledge.",TXT_SUB_LOG3,MAP02: On the bridge with the com unit.,,,"Zamiř ke staré radnici. Když ji Řád vybombardoval, Macil nechal postavit tunel, který nám umožňuje bez vědomí akolytů dostat se dovnitř a ven.","Gå over til det gamle rådhus. Efter at Ordenen bombede det, fik Macil bygget en tunnel, som lader os komme ind og ud uden acolytes' viden.","Geh zum alten Rathaus. Macil hat einen Tunnel bauen lassen, durch den wir dort reinkommen, ohne dass die Ministranten das mitbekommen.",,,"Dirígete al antiguo ayuntamiento. Después de que lo bombardeara La Orden, Macil hizo construir un túnel que nos permite entrar y salir sin que los acólitos lo sepan.",,"Suuntaa kohti vanhaa kaupungintaloa. Sen jälkeen kun Veljeskunta oli pommittanut sen, Macil rakennutti tunnelin, jonka avulla voimme päästä sisään ja ulos akoluuttien tietämättä.",Dirige-toi vers l'ancienne mairie. Macil a fait construire un tunnel après que L'Ordre l'ait bombardée. Il nous permet d'y entrer sans que l'Ordre nous remarque.,"Menj a régi városközpontba. Miután a Rend lebombázta, Macil építtetett egy titkos alagutat, amin észrevétlenül tudunk ki- és bemenni a ministránsok tudta nélkül.",Raggiungi il vecchio Municipio. Macil ha fatto costruire un tunnel che ci fa entrare ed uscire senza che gli accoliti lo sappiano.,"旧市庁舎に向かうんだ。オーダーに爆撃された後 +そこにマシルがアコライトに関わる者を欺く為の抜け道を用意している。",구 시청으로 향해. 오더가 이곳을 폭격한 후에 마실이 그곳에 아콜라이트들이 모르는 통행로를 만들어놨어.,"Ga naar het oude stadhuis. Nadat de Orde het gebombardeerd had, liet Macil een tunnel bouwen die ons in en uit laat stappen zonder dat de acolieten het wisten.","Dra til det gamle rådhuset. Etter at Ordenen bombet det, fikk Macil bygget en tunnel som lar oss komme inn og ut uten at akolyttene vet om det.","Udaj się do starego ratusza. Po zbombardowaniu go przez Zakon, Macil kazał wybudować tunel, który pozwala nam wejść i wyjść bez wiedzy akolitów.","Vá até à antiga prefeitura. Depois que a Ordem a bombardeou, Macil mandou construir um túnel que nos leva e tira de lá sem os acólitos perceberem.",,"Du-te la vechea hală a orașului, Macil a construit un tunel care permite trecerea fără a fi detectat.","Отправляйся к старой ратуше. После того, как Орден взорвал её, Мэйсил построил там туннель, который позволяет нам входить и выходить без ведома служителей.",,Gå till det gamla stadshuset. Efter att Orden bombade det lät Macil bygga en tunnel som gör att vi kan ta oss in och ut utan acolytternas vetskap.,"Eski belediye binasına git. Tarikat orayı bombaladıktan sonra Macil, yardımcıların haberi olmadan girip çıkmamızı sağlayan bir tünel inşa ettirdi." +"Go through the door on your left, then the one on the right. The guard's name is Geoff. Tell him you need gold.",TXT_SUB_LOG4,MAP02: In hall town with the com unit.,,,"Projdi dveřmi nalevo a pak napravo. Hlídač se jmenuje Geoff. Řekni mu, že potřebuješ zlato.","Gå gennem døren til venstre og derefter gennem den til højre. Vagtens navn er Geoff. Sig til ham, at du har brug for guld.","Geh durch die linke Tür, dann durch die rechte. Der Wächter heißt Geoff. Sag ihm du brauchst Gold.",,"Iru tra la maldekstra pordo kaj poste tra la dekstra. La nomo de la gardisto estas Geoff; diru al li «Saluton, mi bezonas oron».","Ve por la puerta izquierda y luego por la derecha. El guardia se llama Geoff; dile «Buenas, necesito oro».",,"Kulje sinusta katsottuna vasemmalla puolella olevan oven läpi, sitten oikeanpuoleisesta ovesta. Vartijan nimi on Geoff. Kerro hänelle tarvitsevasi kultaa.",Passe par la porte à gauche puis celle à droite. Le garde s'appelle Geoff. Dis-lui que tu as besoin d'argent.,"Menj át a bal oldali ajtón, majd a jobb oldalin. Az őr neve Geoff. Mond neki, hogy aranyra van szükséged.","Vai oltre la porta alla tua sinistra, e poi la porta alla tua destra. Il nome della guardia è Geoff. Digli che ti serve dell'oro.","すぐ左のドアを通り、右のドアから小部屋に入るんだ。 +見張りの名はジェフ。金が必要だ と言えば通じる。","네 왼쪽의 문으로 들어간 후, 다시 오른쪽의 문으로 가. 경비의 이름은 제프야. 그에게 골드가 필요하다고 얘기해.","Ga door de deur links van je, dan die rechts van je. De bewaker heet Geoff. Zeg hem dat je goud nodig hebt.","Gå gjennom døren til venstre, så den til høyre. Vakten heter Geoff. Si at du trenger gull.","Przejdź przez drzwi po lewej, a potem przez te po prawej. Strażnik ma na imię Geoff. Powiedz mu, że potrzebujesz złota.",Vá pela porta à sua esquerda e depois a da direita. O nome do guarda é Geoff. Diga a ele que você precisa de ouro.,,"Du-te prin ușa la stânga, apoi dreapta. Numele gardianului e Geoff. Spune-i că ai nevoie de aur.","Пройди за левую дверь, затем иди направо. Стражника зовут Джефф. Скажи ему, что тебе нужно золото.",,Gå genom dörren till vänster och sedan genom dörren till höger. Vaktens namn är Geoff. Säg till honom att du behöver guld.,"Solundaki kapıdan geç, sonra sağdakinden. Muhafızın adı Geoff. Ona altına ihtiyacın olduğunu söyle." +"Irale is the Front's ""fixer"". He's behind the unmarked door next to the weapons shop.",TXT_SUB_LOG5,MAP03: After joining the Front.,,,Irale je „kutil“ Fronty. Je za neoznačenými dveřmi vedle obchodu se zbraněmi.,"Irale er frontens ""fixer"". Han befinder sig bag den umærkede dør ved siden af våbenbutikken.",Irale ist der „Bastler“ der Front. Er ist hinter der unmarkierten Tür neben dem Waffengeschäft.,,,Irale es el «apañador» del Frente. Está pasando la puerta sin cartel junto a la tienda de armas.,Irale es el «soluccionador» del Frente. Está pasando la puerta sin cartel junto a la tienda de armas.,"Irale on Rintaman ""järkkäri"". Hänet löytää merkkaamattoman oven takaa asekaupan vierestä.",Irale est le receleur du front. Il est derrière la porte non marquée à côté du magasin d'armes.,"Irale a Front ""ezermestere"". A jelöletlen ajtó mögött lesz a fegyverbolt mellett.",Irale è un fornitore di armi per il Fronte. Si trova dietro la porta accanto al negozio di armi.,"イラールとはフロントの'仲介者'よ。彼は武器屋の隣のマークされてないドアに居る。 +発電所に近い所だ。",이롤리는 프론트의 수리공이기도 해. 무기상점 근처에 그의 가게로 향하는 문이 있을 거야.,"Irale is de ""fixer"" van de Front. Hij zit achter de ongemarkeerde deur naast de wapenwinkel.","Irale er Frontens ""fikser"". Han er bak den umerkede døren ved siden av våpenbutikken.","Irale to ""załatwiacz"" Frontu. Jest za nieoznakowanymi drzwiami obok sklepu z bronią.","Irale é o ""quebra-galho"" da Frente. Ele está atrás da porta desmarcada próxima ao depósito de armas.",,"Irale e ""reparatorul"" Frontului. E în spatele ușii fără însemn lângă magazinul de arme.",Ирэйл — «наладчик» Сопротивления. Ты найдёшь его за дверью без вывески возле оружейного магазина.,,"Irale är frontens ""fixare"". Han finns bakom den omärkta dörren bredvid vapenbutiken.","İrale, Cephe'nin ""iş bitiricisi"". Silah dükkanının yanındaki işaretlenmemiş kapının arkasında." +Remember: kill with stealth instead of force. You won't set off the alarms.,TXT_SUB_LOG6,MAP02,,,Pamatuj: Zabíjej potichu. Nespustíš poplach.,Husk: Dræb med list i stedet for med magt. Du vil ikke udløse alarmen.,Denk daran: Töte lautlos und du wirst den Alarm nicht auslösen.,,,Recuerda: mata con sigilo y no con fuerza para no activar las alarmas.,,Muista: tapa huomaamattomasti voiman sijasta. Niin vältät hälytyksen.,"Souviens-toi: Tue avec discrétion, pas avec force, et tu n'activeras pas les alarmes.","Figyelj arra, hogy lopakodva ölj, ne erővel. Így nem indítod be a riasztót.",Ricorda: uccidi silenziosamente invece di usare la forza. Così facendo non attiverai gli allarmi.,覚えておいて:静かに殺す時はナイフか毒矢だ。警報を鳴らすと厄介なことになる。,기억해: 소음 없이 조용히 죽여. 그럼 경보를 울리지 않을 테니까.,Onthoud: dood met heimelijke in plaats van met geweld. Je laat de alarmen niet afgaan.,"Husk: drep i det skjulte, ikke med makt. Du vil ikke utløse alarmen.","Pamiętaj: zabijaj ukradkiem, a nie siłą. Nie uruchomisz w ten sposób alarmów.",Lembre-se: mate com cautela ao invés de força. Assim você não ativará os alarmes.,,Ține minte: ucide subtil în loc de forță brută. Nu vei declanșa alarma.,"Запомни: убивай бесшумно, не лезь на рожон, и ты не поднимешь тревогу.",,Kom ihåg: döda med smygande i stället för med våld. Du kommer inte att utlösa larmen.,Unutmayın: güç yerine gizlilikle öldürün. Alarmları çalıştırmazsın. +"All I know about the governor is that he's playing both sides to the middle. Here's his so-called ""mansion.""",TXT_SUB_LOG7,MAP03: After joining the Front and going to Mourel's mansion.,,,"O guvernérovi vím jen to, že se snaží uhrávat sympatie obou stran. Tohle je jeho rádoby „sídlo“.","Alt jeg ved om guvernøren er, at han spiller begge sider til midten. Her er hans såkaldte ""palæ"".","Vom Gouverneur weiß ich nur, dass er beide Seiten gegeneinander ausspielt. Hier ist seine sogenannte „Villa.“",,,Todo lo que sé del gobernador es que juega entre ambos bandos. Aquí está su supesta «mansión».,,"Tiedän kuvernööristä vain sen, että hän pelaa keskellä molemmilla puolilla. Tässä on hänen niin sanottu ""kartanonsa"".","Tout ce que je sais au sujet du gouverneur est qu'il est un agent double de chaque côté. Voilà son soi-disant ""manoir"".","Csak annyit tudok a kormányzóról, hogy mindenkét oldalnak dolgozik. Itt az úgynevezett ""kúriája"".",Tutto ciò che so sul governatore è che cerca di mettere gli uni contro gli altri per beneficio personale. Ecco la sua cosidetta dimora.,"私が知事について知っていることは、町の中央で双方を遊ばせてる様だ。 +ソイツがここいらを'マンション'と呼んでいる。",내가 알기로는 모렐 총독은 두 세력을 가지고 노는 걸 좋아한대. 여기는 그의 '저택'이라는 곳이야.,"Het enige wat ik van de gouverneur weet is dat hij beide kanten van de gouverneur naar het midden speelt. Hier is zijn zogenaamde ""herenhuis"".","Alt jeg vet om guvernøren, er at han spiller på begge sider. Her er hans såkalte ""herskapshus"".","O gubernatorze wiem tylko tyle, że gra na dwie strony. Oto jego tak zwana ""rezydencja"".","Tudo o que eu sei sobre o governador é que ele está jogando entre dois lados. Aqui fica a sua suposta ""mansão"".",,"Tot ce știu despre Guvernator e că plătește ambele tabere. Aici e așa-zisul lui ""complex"".","Я знаю о губернаторе только то, что он пытается подыграть обеим сторонам, оставаясь посередине. Вот его так называемый «особняк».",,"Allt jag vet om guvernören är att han spelar båda sidor till mitten. Här är hans så kallade ""herrgård"".","Vali hakkında bildiğim tek şey, iki tarafı da ortada oynaması. İşte onun sözde ""malikanesi""." +Ugh. The dregs of humanity have certainly found a home.,TXT_SUB_LOG8,,,,Fuj. Spodina lidstva si rozhodně našla domov.,Ugh. Menneskehedens bundfald har bestemt fundet et hjem.,Ugh. Der Bodensatz der Menschheit hat definitiv ein Zuhause gefunden.,,,Ugh. La basura humana ciertamente ha encontrado un hogar.,,"Yöh, ihmiskunnan pohjasakka on selvästikin löytänyt kodin.","Eugh, les loques de l'humanité ont trouvé leur maison, on dirait.",Fúj. Az emberiség söpredéke csak talált magának egy otthont.,Ugh. La feccia dell'umanità ha certamente trovato una casa adatta.,,"으윽, 우리 중 나쁜 놈들만 보금자리를 구한 것 같네.",Ugh. De bezinksels van de mensheid hebben zeker een thuis gevonden.,Ugh. Menneskehetens bunnfall har virkelig funnet et hjem.,Ugh. Resztki ludzkości na pewno znalazły dom.,Urgh. A escória da humanidade certamente encontrou um lar.,,Ugh. Scursurile umanității și-au găsit o casă cu siguranță.,Фу. Самое место для отбросов человечества.,,Usch. Mänsklighetens avskum har verkligen hittat ett hem.,Ugh. İnsanlığın tortuları kesinlikle bir yuva bulmuş. +Calling Mourel sleazy is paying him a compliment. He's mongrel turd on a stick.,TXT_SUB_LOG9,"MAP02: After accepting ""bloody"" chore.",,,"Nazývat Mourela slizákem by mu lichotilo, svinský parchant jeden prohnilý.",At kalde Mourel sleazy er at give ham en kompliment. Han er en mongolsk lort på en pind.,"Mourel als 'verschlagen' zu bezeichnen wäre, ihm ein Kompliment zu machen. Er ist ein Haufen Hundescheiße.",,,Decirle «sucio» a Mourel es un halago. Es mierda de perro callejero en un palo.,,"Viheliäiseksi nimitteleminen olisi Mourelille vain kohteliaisuus. Hän on kapinen koira, iljettävä paskiainen.",Appeler Mourel un rat serait être gentil. Il est une sacrée brochette de merde.,Mourelt mocskosnak hívni egyfajta bók. Én egy alávaló pálcára húzott szarnak hívnám.,Chiamare Mourel squallido significa fargli un complimento. È uno stronzo bastardo su un palo.,"モーレルにとって汚職議員は誉め言葉だ。 +ソイツはクソを漏らした'駄犬'でしかないからな。",모렐에게 행실이 지저분하다고 말하는 건 칭찬에 불과해. 저놈은 이기적인 똥개새끼라고.,Mourel slordig noemen is een compliment voor hem. Hij is een bastaard op een stokje.,Å kalle Mourel snuskete er å gi ham en kompliment. Han er en kjøterbæsj på en pinne.,Nazwanie Mourela obskurnym to komplement. On jest kundlem na patyku.,Chamar o Mourel de picareta é elogio. Ele é um total desgraçado de merda.,,Numindu-l pe Mourel zgârcit e un compliment. E o corcitură de rahat pe băț.,"Назвать Моурела подлым, значит сделать ему комплимент. Кусок дерьма на палочке...",,Att kalla Mourel sliskig är en komplimang. Han är en mongolisk skit på en pinne.,Mourel'e adi demek ona iltifat etmektir. O bir sopa üzerindeki melez bok. +We need to speak with someone who knows the old town and where this coupling is. Command says: find MacGuffin. ,TXT_SUB_LOG10,"MAP02: After accepting ""messy"" chore and leaving Mourel's room.",,,"Musíme si promluvit s někým, kdo zná staré město a ví, kde se tahle spojka nalézá. Vedení říká najít MacGuffina.","Vi må tale med nogen, der kender den gamle by og ved, hvor denne kobling er. Kommandoen siger: Find MacGuffin.","Wir müssen mit jemandem reden, der die alte Stadt kennt und weiß, wo diese Anzapfung it. Die Kommandozentrale sagt, finde MacGuffin.",,,Necesitamos hablar con alguien que conozca el viejo pueblo y donde se encuentra el acoplamiento. El Comando dice: encuentra a MacGuffin.,,"Meidän täytyy puhua jollekulle, joka tietää vanhan kaupungin ja missä tämä liitin on. Komentokeskus käskee etsiä MacGuffinia.",On doit parler à quelqu'un qui connaît la vieille ville et où se trouve le coupleur. Le commandement me dit qu'il faut trouver MacGuffin.,"Beszélnünk kell valakivel aki ismeri a régi várost, és tudja hol ez az elágazás. A központ szerint fel kell keresnünk MacGuffin-t.",Dobbiamo parlare con qualcuno che conosce la vecchia città e sa dove poter trovare questo aggeggio. Il comando dice: trovate MacGuffin.,"我々は何処にあるかについてはオールドタウンに知っている者がいる。 +指令が言うには マクガフィンに会え。",동력선의 위치를 알 수 있을 만한 토박이 주민과 이야기해봐. 본부가 말하길: 맥거핀을 찾으래.,We moeten met iemand spreken die de oude stad kent en waar deze koppeling is. Het commando zegt: zoek MacGuffin.,Vi må snakke med noen som kjenner gamlebyen og vet hvor koblingen er. Kommandoen sier: Finn MacGuffin.,"Musimy porozmawiać z kimś, kto zna stare miasto i wie, gdzie jest to sprzęgło. Rozkaz mówi: znaleźć MacGuffina.",Precisamos falar com alguém que conheça a velha cidade e onde fica essa conexão. O comando diz: encontre MacGuffin.,,Avem nevoie să vorbim cu cineva care cunoaște vechiul oraș și unde e cuplajul. Centrul de comandă zice: găsește-l pe MacGuffin.,"Нам нужен кто-то, кто знает старый город и может подсказать, где эта муфта. В штабе говорят, что тебе поможет Макгаффин.",,Vi måste tala med någon som känner till den gamla staden och vet var den här kopplingen finns. Kommandot säger: hitta MacGuffin.,Eski şehri ve bu kuplajın nerede olduğunu bilen biriyle konuşmalıyız. Komuta diyor ki: MacGuffin'i bulun. +"He's in what's politely called the ""bum hole"". Take the walkway by the sewage plant and head down the stairs.",TXT_SUB_LOG11,"MAP02: After accepting ""messy"" chore and leaving Mourel's mansion.",,,"Najdeš ho na místě, kterému zdvořile říkají „zadnice“. Jdi přes chodník u čističky a sejdi schody.","Han er i det, der høfligt kaldes ""bumshullet"". Tag gangen ved kloakanlægget og gå ned ad trappen.","Er ist, was höflich gesagt, das „Pennerloch“ genannt wird. Gehe zum Weg zur Kläranlage und von dort die Treppe herunter.",,,Está en lo que se conoce educadamente como «la cueva del vagabundo». Toma la pasarela junto a la planta de aguas residuales y baja por las escaleras.,,"Hän majailee kiltisti sanottuna ""pepunreiässä"". Kulje jätelaitoksen viereistä kulkukäytävää pitkin ja portaat alas.","Il se trouve dans ce qu'on appelle poliment le ""trou à rats"", suis la coursive près de la centrale de traitement des égouts et descend les escaliers.","Ott van az udvariasan csak ""kotoréknak"" nevezett helyen. Gyalogolj végig a szennyvíz tisztító hídján, majd le a lépcsőkön.","Si trova in quello che viene affeziosamente chiamato ""il buco dei barboni"". Prendi la passerella dell'impianto fognario e vai sotto le scale.","彼は行儀よく'バムホール'と呼ばれる場所に居る。 +下水処理場の側の階段を下りた小さい部屋だ。",겸손하게 말하자면 그는 “노숙자 굴”에 살아. 하수도에서 보도를 지나간 뒤 계단을 건너.,"Hij zit in wat beleefd het ""kontje"" wordt genoemd. Neem de loopbrug bij de rioolwaterzuiveringsinstallatie en ga de trap af.","Han er i det som høflig kalles ""rumpehullet"". Ta gangveien ved kloakkanlegget og gå ned trappene.","Jest w miejscu, które grzecznie nazywa się ""bum hole"". Skorzystaj z przejścia przy oczyszczalni ścieków i skieruj się w dół po schodach.","Ele está num lugar chamado ""toca de rato"". Vá pela passarela perto da usina de tratamento e desça as escadas.",,"E în ceea ce se cheamă politicos ""groapa de ardere"". Ia pasarela de lângă fabrica de deșeuri și coboară scările.","Он в том месте, что вежливо называют «бомжевая нора». Пройди к очистным сооружениям и спустись по лестнице.",,"Han är i det som artigt kallas ""bum-hålet"". Ta gången vid avloppsanläggningen och gå ner för trapporna.","Kibarca ""serseri deliği"" denilen yerde. Lağım tesisinin yanındaki geçidi kullanın ve merdivenlerden aşağı inin." +Take your time with this mission. I can't get intel on this from Command.,TXT_SUB_LOG12,"MAP02: During ""messy"" chore.",,,Dej si s touhle misí na čas. Nemůžu z velení dostat žádné informace.,Tag dig god tid med denne mission. Jeg kan ikke få oplysninger om dette fra Command.,Nimm dir Zeit für diese Mission. Ich erhalte keine Informationen aus der Kommandozentrale.,,,Tómate tu tiempo en esta misión. No consigo información de esto con el Comando.,,Ei mitään kiirettä tämän tehtävän kanssa; komentokeskuksella ei ole antaa tiedustelutietoja.,"Prends ton temps, le commandement n'a rien à me donner au niveau informations.",Ne siesd el a küldetést. Nem tudtam kideríteni semmi érdemlegeset az Irányítástól.,Prenditi il tempo che ti serve per questa missione. Non mi stanno dando molte informazioni dal comando.,この任務は時間が掛かりそうだ。私は司令部からこれ以上の情報は得る事は出来ない。,느긋하게 수행해도 좋아. 본부에도 이 정보를 모으는 데 문제가 있데.,Neem je tijd met deze missie. Ik kan hier geen informatie over krijgen van de Commandant.,Ta deg god tid med dette oppdraget. Jeg kan ikke få informasjon om dette fra kommandoen.,Nie spiesz się z tą misją. Nie mogę uzyskać informacji na ten temat od dowództwa.,Não tenha pressa nesta missão. Não estou conseguindo obter inteligência sobre isso pelo Comando.,,Poți să petreci mai mult timp cu misiunea. Nu pot găsi mai multe informații de la Centru.,Не торопись с выполнением этого задания. Я не могу получить разведданные от штаба.,,Ta god tid på dig med det här uppdraget. Jag kan inte få information om detta från kommandot.,Bu görevde acele etmeyin. Komuta'dan bu konuda bilgi alamıyorum. +"You idiot! You've shut off the power to the jamming circuits we use to conceal our base from the Order. Head over to the town hall and take out the scanning crew, now!",TXT_SUB_LOG13,MAP02: After destroying Front's power coupling.,,,"Ty debile! Odstřihnul jsi přívod proudu do rušiček, které používáme, abychom ukryli naší základnu před Řádem. Okamžitě si to zamiř k radnici a vybij průzkumnou četu!","Din idiot! Du har slukket for strømmen til de jamming-kredsløb, vi bruger til at skjule vores base for Ordenen. Gå over til rådhuset og udryd scanningsholdet, nu!","Du Idiot! Du hast die Energie für unsere Störsender unterbrochen, mit denen wir unsere Basis vor dem Orden verborgen haben. Geh schnell zum Rathaus und schalte den Suchtrupp aus. ",,,"¡Idiota! Has apagado la energía de los circuitos de interferencia que usamos para ocultarle nuestra base a La Orden. Dirígete al ayuntamiento y elimina al equipo de escaneo, ¡ya!","¡Idiota! Apagaste la energía de los circuitos de interferencia que usamos para ocultarle nuestra base a La Orden. Dirígete al ayuntamiento y elimina al equipo de escaneo, ¡ya!","Sinä idiootti! Olet katkaissut virran häirintäpiireihin, joilla piilotamme sijaintimme Veljeskunnalta. Suuntaa kaupungintalolle ja hoitele tiedusteluryhmä, heti paikalla!",Idiot! Tu as désactivé les circuits brouilleurs qui cachaient notre base des senseurs de l'Ordre. Retourne vite à la mairie et tue l'équipe de scan maintenant!,"Te idióta! Lelőtted az áramot a zavaró áramkörökhöz, amivel a Rend elől rejtettük el a bázist. Menj a városházára, és iktasd ki a szkennelő legénységet azonnal!","Idiota! Hai interrotto il flusso di energia dei circuiti che usavamo per nascondere la nostra base dall'Ordine. Ritorna subito al municipio e fai fuori il gruppo venuto a perlustare la zona, ora!","馬鹿者!お前はオーダーから我々の基地を隠す妨害回路を壊してしまった! +市庁舎に調査隊が向かった、今すぐ片付けろ!",이 멍청이야! 우리 기지를 오더로부터 은폐시켜주는 교란 장치의 동력을 끊어버렸잖아. 당장 시청으로 가서 탐색반들을 쓸어버려! 그다음에 총독에게 부서진 장치를 전해. 당장!,"Idioot! Je hebt de stroom naar de stoorcircuits die we gebruiken om onze basis te verbergen voor de Orde uitgeschakeld. Ga naar het stadhuis en haal de scannende bemanning eruit, nu!","Din idiot! Du har slått av strømmen til blokkeringskretsene vi bruker for å skjule basen vår for Ordenen. Dra til rådhuset og drep skannerne, nå!","Ty idioto! Wyłączyłeś zasilanie obwodów zagłuszających, których używamy do ukrycia naszej bazy przed Zakonem. Idź do ratusza i zdejmij ekipę skanującą, natychmiast!",Seu idiota! Você desligou a energia para os circuitos de interferência que usamos para esconder a nossa base dos sensores da Ordem. Vá até a prefeitura e tire a equipe de busca de lá imediatamente!,,"Idiotule! Ai oprit energia către circuitele noastre care ne permiteau să ne ascundem de Ordin. Du-te în hala vechiului oraș și elimină echipajul, acum!","Идиот! Ты обесточил генератор радиопомех, с помощью которого мы скрывали местоположение нашей базы от Ордена. Возвращайся к ратуше и уничтожь разведывательную группу как можно скорее!",,"Din idiot! Du har stängt av strömmen till störningskretsarna som vi använder för att dölja vår bas för Orden. Gå över till stadshuset och ta ut skanningspersonalen, nu!","Seni salak! Üssümüzü Düzen'den gizlemek için kullandığımız sinyal bozucu devrelerin gücünü kesmişsin. Belediye binasına git ve tarama ekibini indir, hemen!" +"OK, ""Trust no one"" is the name of the game! Let's get that pass from the Governor and free those prisoners.",TXT_SUB_LOG14,MAP02: After destroying Front's power coupling and killing all blue acolytes in the town hall.,,,"Dobře, „Nevěř nikomu“ je motto hry! Pojďme od guvernéra dostat tu propustku a osvoboďme ty vězně.","Okay, ""Stol ikke på nogen"" er det, der gælder! Lad os få den tilladelse fra guvernøren og befri de fanger.","Ok, „Trau keinem“ heißt dieses Spiel. Lass uns den Gefängnispass vom Gouverneur holen und die Gefangenen befreien.",,,"Vale, ¡«No te fies de nadie» se llama el juego! Ya es hora de conseguir ese pase del Gobernador y liberar a esos prisioneros.","Bueno, ¡«No confíes en nadie» se llama el juego! Ya es hora de conseguir ese pase del Gobernador y liberar a esos prisioneros.","Selvä, ""Älä luota kehenkään"" on näköjään pelin nimi! Hankitaan pääsylupa kuvernööriltä ja vapautetaan ne vangit.","Ok, ""ne fais confiance à personne"" est le thème du jour. Récupérons le passe du gouverneur et libérons les prisonniers.","Rendben, a ""ne bízz senkiben"" elv szerint játszunk. Akkor vegyük el a kormányzótól a belépőt, és szabadítsuk ki a rabokat.","OK, ""Non fidarti di nessuno"" è il gioco che stiamo giocando qua! Prendiamo quel pass per la prigione dal governatore.",よし、'信用しない'のが最も重要なことだ!壊れた配電機を渡して囚人を解放するんだ。,"좋아, '아무도 믿지 말라'가 이 게임의 이름이겠군! 그냥 총독과 대화하고 수감자들을 구출하자.","OK, ""Vertrouw niemand"" is de naam van het spel! Laten we die pas van de gouverneur halen en die gevangenen vrijlaten.","OK, ""Stol ikke på noen"" er navnet på spillet! La oss få det passet fra guvernøren og befri fangene.","OK, ""Nie ufaj nikomu"" to nazwa gry! Zdobądźmy tę przepustkę od gubernatora i uwolnijmy tych więźniów.","Ok, ""não confie em ninguém"" é o nome do jogo! Vamos pegar aquele passe do Governador e libertar esses prisioneiros.",,"OK, ""N-ai încredere în nimeni"" e numele jocului. Să luăm acea parolă de la guvernator și să eliberăm prizonierii.","Что ж, эта игра называется «не верь никому»! Давай получим у губернатора пропуск в тюрьму и освободим пленников.",,"Okej, ""Lita inte på någon"" är vad som gäller! Låt oss få det där passet från guvernören och befria fångarna.","Tamam, ""Kimseye güvenme"" oyunun adı! Vali'den o izni alalım ve mahkumları serbest bırakalım." +Good move! The Governor is a lousy liar. That's our power coupling. Now let's get that pass.,TXT_SUB_LOG15,MAP02: After finding the broken power coupling.,,,"Dobrý tah! Guvernér je mizerný lhář, tohle je naše spojka. Tak si pojďme pro tu propustku.",Godt gået! Guvernøren er en elendig løgner. Det er vores kraftkobling. Lad os nu få fat i det pas.,Das war klasse! Der Gouverneur ist ein lausiger Lügner. Das war unsere Anzapfung. Nun lass uns den Pass holen.,,,¡Buen ojo! El gobernador es un mentiroso: ese era nuestro acoplador de energía. Ahora consigamos ese pase.,,Hyvä veto! Kuvernööri on surkea valehtelija. Se on meidän virtaliittimemme. Nyt sitten hankitaan se pääsylupa.,Bien joué! Le gouverneur est un menteur. Voilà notre coupleur. Allons récupérer le passe.,Jól tetted! A Kormányzó egy hazug disznó. Az a mi áramcsatolónk. Most pedig irány a belépő.,Ottima mossa! Il governatore è un bugiardo. Eravamo noi a utilizzare questo marchingegno collegato alla rete. Ora andiamo a prendere quel pass.,"良い判断よ!知事は粗末な嘘を付いている。 あれはオーダーから基地を隠す為に使用している我々の配電機だ。 -この壊れた配電機を渡して彼を騙し返そう。",참 잘했어! 총독이 거짓말을 했군. 이건 우리의 동력 장치야. 어서 전해주자!,Goede zet! De Gouverneur is een slechte leugenaar. Dat is onze krachtkoppeling. Laten we nu die pas pakken.,,"Boa! O Governador é um mentiroso desgraçado. Esse é a nossa conexão. Agora, vamos pegar aquele passe.",,,Отличный ход! Губернатор — мерзкий лжец. Это наше подключение к силовой линии. Теперь получи пропуск., -The warehouse is in the power station. Let's make this short and sweet.,TXT_SUB_LOG16,STRIFE1.WAD: MAP02,,,Skladiště je uvnitř elektrárny. Pojďme to udělat čistě a krátce.,Das Lagerhaus ist im Kraftwerk. Lass uns das schnell erledigen.,,,El almacén está en la estación eléctrica. Hagamos esto bien rápido.,,,L'entrepôt se trouve dans la centrale électrique. On va faire ça rapidement et proprement.,,,倉庫は発電所にある。さっさと済ませよう。,창고는 발전소 근처에 있어. 어서 신속하고 죽여주게 끝내자.,Het magazijn is in de energiecentrale. Laten we dit kort en bondig houden.,,O depósito fica na usina de energia. Vamos fazer isso bem rápido.,,,Речь идёт о складе в электростанции. Давай сделаем это быстро и с огоньком., -I never thought I'd break into prison...,TXT_SUB_LOG17,STRIFE1.WAD: MAP02,,,"Nikdy by mě nenapadlo, že se budu vkrádat do vězení...","Ich hätte nie gedacht, in ein Gefängnis einzubrechen...",,,Nunca pensé que me fugaría adentro de prisión...,,,J'aurais jamais cru entrer de force dans une prison..,,,刑務所にお勤めになるなぞ考えた事もないぞ...,"감옥을 뚫고 들어가다니, 생각도 못 했는데?",Ik had nooit gedacht dat ik zou inbreken in de gevangenis....,,Nunca achei que eu invadiria uma prisão...,,,"Никогда не думала, что приду в тюрьму добровольно...", -Guess there's no free lunch. Time to lock and load.,TXT_SUB_LOG18,STRIFE1.WAD: MAP05,,,Holt nic není zadarmo. Nabij zbraň a jdi do toho.,Es gibt wohl keine freie Mahlzeit. Ran an die Action.,,,Supongo que no hay comida gratis. Tiempo para la acción.,,,"On dirait qu'il n'y a pas de repas gratuit, il est temps de se préparer au combat.",,,まあタダでは済まないか。派手に暴れてやれ。,급식 먹을 시간은 없겠네. 요리할 시간이야.,Ik denk dat er geen gratis lunch is. Tijd om te sluiten en te laden.,,Parece que não existe almoço grátis. É hora da ação.,,,"Что ж, бесплатный сыр бывает только в мышеловке. Оружие к бою! ", -"OK. You've pleased the Governor, splattered the Warden... Now it looks like we got to have to do a little surgery.",TXT_SUB_LOG19,STRIFE1.WAD: MAP05,,,"Dobrá. Uspokojil jsi guvernéra, rozmetal dozorčího... Vypadá to, že teď budeme muset provést menší chirurgický zákrok.","Ok, du hast den Gouverneur zufriedengestellt, den Direktor abgemetzelt... Und jetzt sieht es aus als ob eine kleine Operation nötig ist.",,,"OK. Has satisfecho al Gobernador, despedazado al Carcelero... Ahora parece que tendremos que hacer algo de cirugía.",,,"OK. Le gouverneur est satisfait, le gardien est en bouillie... Maintenant il va falloir faire un peu de chirurgie.",,,"よし、知事は喜ばせ刑務所長はぶちのめした... -私達が少々手術を施す必要が出来たわ。","좋아, 총독과 놀았고, 간수장도 죽었으니... 이제 관련 인간을 손 좀 봐 줘야겠네!","Oké. Je hebt de gouverneur tevreden gesteld, de directeur verpletterd... Nu lijkt het erop dat we een kleine operatie moeten doen.",,"Ok, você agradou o Governador, estourou os miolos do carcereiro... Agora parece que temos que fazer uma pequena cirurgia.",,,"Хорошо. Ты доставил удовольствие губернатору, забрызгал стены мозгами тюремщика... Теперь нам предстоит небольшое хирургическое вмешательство.", -Oh you cut off his hand! And I thought you were a nice guy... kinda. Let's go.,TXT_SUB_LOG20,STRIFE1.WAD: MAP05,,,"Oh, tys mu uříznul ruku! A já myslela že jsi hodný chlap... jakž takž. Pojďme.","Oh, du hast seine Hand abgeschnitten! Und ich dachte du wärest ein netter Typ... oder so. Lass uns gehen.",,,¡Oh le cortaste la mano! Y yo creía que eras un buen tío... más o menos. Vamos.,,,"Oh, tu a coupé sa main? Je croyais que tu étais un type sympa.. Plus où moins. Allons-y.",,,"おいおい手を切り取ったのかよ! -ただのナイスガイってわけじゃないのね...まあいい、行こうか。","손을 뜯어버리다니! 아주 좋은 사람인 줄 알았는데... 귀엽네! 후훗, 가자구.","Oh, je hebt zijn hand eraf gesneden! En ik vond je een aardige kerel.... een beetje. Laten we gaan.",,"Ai, você cortou fora a mão dele! Eu achava que você era um cara bonzinho... talvez. Vamos lá.",,,"О ч-чёрт, ты отрезал ему руку! Я думала, ты добрый парень... в некотором роде. Ладно, не бери в голову.","Осекао си му руку! И мислила сам да си добар човек... онако. Настављамо. -" -"Way to go, my friend. Jump on one of the teleporters and it will bring you back to base.",TXT_SUB_LOG21,STRIFE1.WAD: MAP05,,,"Jen tak dál, příteli. Skoč na teleportér, dostane tě zpět na základnu.",Das war gute Arbeit. Benutze einen der Teleporter um zur Basis zurückzugelangen.,,,Así se hace amigo. Ponte en uno de los teletransportes y te traerá de vuelta a la base.,Que forma de avanzar amigo mío. Entra en alguno de los teleportes y te traerá de vuelta a la base.,,Bien joué mon ami! Utilise l'un des téléporteurs pour revenir à la base.,,,行きましょう、相棒。牢屋奥のテレポーターに飛び込めば基地にすぐ着くわ。,"정말 잘했어, 친구. 저 텔레포터들 중 하나를 타면 기지로 복귀할 수 있을 거야.","Goed gedaan, mijn vriend. Spring op een van de teleporters en het brengt je terug naar de basis.",,"Boa, meu amigo. Entre num desses teletransportadores e você voltará para a base.",,,"Так держать, дружище. Прыгай в любой телепорт, и он вернёт тебя на базу.", -Worner is a spy we recruited in the warehouse of the power station.,TXT_SUB_LOG22,,,,"Worner je špión, kterého jsme najali ve skladišti elektrárny.","Worner ist ein Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben.",,,Worner es un espía que reclutamos en el almacén de la estación eléctrica.,,,Worner est un espion que nous avons recruté dans l'entrepôt de la centrale éléctrique.,,,,워너는 우리가 모집한 첩자야. 그는 발전소 창고에 있어.,Worner is een spion die we in het magazijn van de centrale hebben gerekruteerd.,,Worner é um espião que recrutamos no depósito da usina de energia.,,,"Уорнэр — шпион, которого мы завербовали на складе электростанции.", -"Word from the boss is stand back when you whack the crystal, or else you'll end up mesquite-flavored too.",TXT_SUB_LOG23,STRIFE1.WAD: MAP04,,,"Velení radí, aby ses držel dál až rozbiješ krystal, jinak taky skončíš jako pečínka.","Der Ratschlag vom Boss ist, in Deckung zu gehen, wenn du den Kristall plattmachst. Andernfalls könntest du als Omelett enden.",,,"Dice el jefe que te eches atrás cuando le des al cristal, o si no también acabaras frito.",,,"Le boss me raconte que tu as intérêt à prendre tes distances avant de péter le cristal, sinon tu va aussi te retrouver cuit à la sauce barbecue au plasma.",,,"上司が言うには、クリスタルを破壊する瞬間には隠れる必要があるな、 -でないと唐揚げになるわ。",대장 말로는 수정체를 부술 때 멀리 피해있으라고 했어. 너도 노릇노릇하게 구워지기 싫다면 말이지.,"Het woord van de baas is een stapje terug als je het kristal slaat, of anders kom je ook nog eens met een mesquite-smaakje terecht.",,"A chefe me contou que você deve manter distância quando você arrebentar o cristal, senão você vira churrasco.",,,"Босс говорит, чтобы ты держался подальше от кристалла, когда он рванёт. Иначе тебя тоже прожарит до хрустящей корочки.", -One more adventure before command feels it's safe to attack. Macil's arranged for Irale to give you gold and some training. And visit the medic for strength.,TXT_SUB_LOG25,STRIFE1.WAD: MAP02,,,"Ještě jedno dobrodružství, než se velení rozhodne zaútočit. Macil sjednal u Iraleho zlato a trénink. Taky navštiv lékaře kvůli síle.","Eine weitere Aufgabe noch, bevor Macil es für sicher hält, anzugreifen. Macil hat Irale gebeten, dir Gold zu geben und Training zu organisieren. Und lass dir vom Sanitäter deine Ausdauer erhöhen.",,,Una aventura más antes de que el comando sienta que es seguro atacar el castillo. Macil ha acordado con Irale que te de oro y algo de entrenamiento. Y ver al médico en el pueblo para ganar fuerza.,,,Encore une aventure avant le commandement pense qu'il soit l'heure d'attaquer. Macil s'est arrangé pour qu'Irale te donne de l'argent et un peu d'entraînement en plus. Va voir le médecin pour plus de forces.,,,"もう一つの任務をこなす前に戦力の増強が必要と考えられる。 +この壊れた配電機を渡して彼を騙し返そう。",참 잘했어! 총독이 거짓말을 했군. 이건 우리의 동력 장치야. 어서 전해주자!,Goede zet! De Gouverneur is een slechte leugenaar. Dat is onze krachtkoppeling. Laten we nu die pas pakken.,Godt trekk! Guvernøren er en elendig løgner. Det er kraftkoblingen vår. La oss få tak i passet.,Dobry ruch! Gubernator to kiepski kłamca. To nasze połączenie sił. Teraz zdobądźmy tę przepustkę.,"Boa! O Governador é um mentiroso desgraçado. Esse é a nossa conexão. Agora, vamos pegar aquele passe.",,Bună mutare! Gvuvernatorul e un mincinos prost. Acela e cuplajul nostru. Acum să luăm parola.,Отличный ход! Губернатор — мерзкий лжец. Это наше подключение к силовой линии. Теперь получи пропуск.,,Bra gjort! Guvernören är en usel lögnare. Det är vår maktkoppling. Nu ska vi få det där passet.,İyi hamle! Vali berbat bir yalancı. Bu bizim güç birleşimimiz. Şimdi şu izni alalım. +The warehouse is in the power station. Let's make this short and sweet.,TXT_SUB_LOG16,"MAP02: After accepting ""bloody"" chore.",,,"Skladiště je uvnitř elektrárny. Pojďme na to, ať to máme rychle za sebou.",Lageret er i kraftværket. Lad os gøre det kort og godt.,Das Lagerhaus ist im Kraftwerk. Lass uns das schnell erledigen.,,,El almacén está en la central eléctrica. Hagamos esto bien rápido.,,Varasto on voimalaitoksella. Hoidetaan tämä nätisti ja pikaisesti.,L'entrepôt se trouve dans la centrale électrique. On va faire ça rapidement et proprement.,A raktár egy erőmű. Oldjuk meg gyorsan és hatékonyan.,Il magazzino si trova nella centrale energetica. Cerchiamo di essere rapidi e puliti.,倉庫は発電所にある。さっさと済ませよう。,창고는 발전소 근처에 있어. 어서 신속하고 죽여주게 끝내자.,Het magazijn is in de energiecentrale. Laten we dit kort en bondig houden.,Lageret er i kraftstasjonen. La oss gjøre det kort og godt.,Magazyn jest w elektrowni. Niech to będzie krótkie i słodkie.,O depósito fica na usina de energia. Vamos fazer isso bem rápido.,,Depozitul e în stația de energie. Scurt și dulce.,Речь идёт о складе в электростанции. Давай сделаем это быстро и с огоньком.,,Magasinet finns i kraftstationen. Låt oss göra det här kort och gott.,Depo elektrik santralinde. Bunu kısa ve tatlı tutalım. +I never thought I'd break into prison...,TXT_SUB_LOG17,MAP02: About to enter Norwall Prison.,,,"Nikdy by mě nenapadlo, že se budu vkrádat do vězení...","Jeg troede aldrig, at jeg skulle bryde ind i et fængsel...","Ich hätte nie gedacht, in ein Gefängnis einzubrechen...",,"Mi neniam pensis, ke mi invadus malliberejon...",Nunca imaginé que irrumpiría en una prisión...,,En olisi ikinä uskonut murtautuvani vankilaan...,J'aurais jamais cru entrer de force dans une prison..,"Sosem gondoltam volna, hogy betörök egy börtönbe...",Non avrei mai pensato di entrare in prigione...,刑務所にお勤めになるなぞ考えた事もないぞ...,"감옥을 뚫고 들어가다니, 생각도 못 했는데?",Ik had nooit gedacht dat ik zou inbreken in de gevangenis....,Jeg trodde aldri jeg skulle bryte meg inn i et fengsel...,"Nigdy nie sądziłem, że włamię się do więzienia...",Nunca achei que eu invadiria uma prisão...,,N-am crezut că o să intru într-o închisoare...,"Никогда не думала, что приду в тюрьму добровольно...",,Jag trodde aldrig att jag skulle bryta mig in i ett fängelse...,Hapishaneye gireceğimi hiç düşünmemiştim. +Guess there's no free lunch. Time to lock and load.,TXT_SUB_LOG18,MAP05: After crossing the alarm green door.,,,Holt nic není zadarmo. Nabij zbraň a jdi do toho.,Der er vist ingen gratis frokost. Tid til at låse og læsse.,Es gibt wohl keine freie Mahlzeit. Ran an die Action.,,,Supongo que no hay comida gratis. Hora de la acción.,,Ilmaista lounasta ei kai olekaan. Aika laittaa kovat piippuun.,"On dirait qu'il n'y a pas de repas gratuit, il est temps de se préparer au combat.",Úgy néz ki nincs ingyen ebéd. Akkor idő felfegyverkezni.,Immagino non ci sia del pranzo gratuito. È ora di dargli una lezione.,まあタダでは済まないか。派手に暴れてやれ。,급식 먹을 시간은 없겠네. 요리할 시간이야.,Ik denk dat er geen gratis lunch is. Tijd om te sluiten en te laden.,Man får visst ikke noe gratis. På tide å låse og laste.,Chyba nie ma darmowego lunchu. Czas zamknąć i załadować.,Parece que não existe almoço grátis. É hora da ação.,,Presupun că nu e niciun prânz gratuit. Timpul să ne pregătim.,"Что ж, бесплатный сыр бывает только в мышеловке. Оружие к бою! ",,Det finns ingen gratis lunch. Dags att låsa och ladda.,Sanırım bedava öğle yemeği yok. Kilitleme ve yükleme zamanı. +"OK. You've pleased the Governor, splattered the Warden... Now it looks like we got to have to do a little surgery.",TXT_SUB_LOG19,MAP05: After getting to Main Control.,,,"Dobrá. Uspokojil jsi guvernéra, rozmetal dozorčího... Vypadá to, že teď budeme muset provést menší operaci.","OKAY. Du har tilfredsstillet guvernøren, plettet fængselsinspektøren... Nu ser det ud til, at vi må foretage en lille operation.","Ok, du hast den Gouverneur zufriedengestellt, den Direktor abgemetzelt... Und jetzt sieht es aus als ob eine kleine Operation nötig ist.",,,"Bueno, has satisfecho al Gobernador, despedazado al Carcelero... Y ahora parece que tendremos que hacer algo de cirugía.",,"No niin, olet tehnyt kuvernöörille mieliksi: suolannut vankilanjohtajan... Mutta näyttää siltä, että meidän täytyy harrastaa vähän kirurgiaa.","OK. Le gouverneur est satisfait, le gardien est en bouillie... Maintenant il va falloir faire un peu de chirurgie.","Ok. Elégedetté tetted a Kormányzót, kiloccsantottad az Igazgató fejét...Úgy tűnik ideje végezni egy kis műtétet.","OK. Hai reso il governatore contento, hai fatto a pezzi il direttore... Adesso sembra che ci toccherà fare un po' di chirurgia.","よし、知事は喜ばせ刑務所長はぶちのめした... +私達が少々手術を施す必要が出来たわ。","좋아, 총독과 놀았고, 간수장도 죽었으니... 이제 관련 인간을 손 좀 봐 줘야겠네!","Oké. Je hebt de gouverneur tevreden gesteld, de directeur verpletterd... Nu lijkt het erop dat we een kleine operatie moeten doen.","GREIT. Du har tilfredsstilt guvernøren, skjemt ut direktøren... Nå ser det ut til at vi må gjøre en liten operasjon.","W PORZĄDKU. Zadowoliłeś gubernatora, sponiewierałeś naczelnika... Teraz wygląda na to, że będziemy musieli przeprowadzić małą operację.","Ok, você agradou o Governador, estourou os miolos do carcereiro... Agora parece que temos que fazer uma pequena cirurgia.",,"OK. L-ai mulțumit pe Guvernator, împrăștiat pe Director... acum se pare că trebuie să faci niște chirurgie.","Хорошо. Ты доставил удовольствие губернатору, забрызгал стены мозгами тюремщика... Теперь нам предстоит небольшое хирургическое вмешательство.",,"OKEJ, DÅ ÄR DET DAGS ATT LÅSA OCH LÅSA. Du har nöjt guvernören, kladdat på fängelsedirektören... Nu ser det ut som om vi måste göra en liten operation.","TAMAMDIR. Vali'yi memnun ettiniz, Müdür'ün canına okudunuz. Şimdi küçük bir ameliyat yapmamız gerekecek gibi görünüyor." +Oh you cut off his hand! And I thought you were a nice guy... kinda. Let's go.,TXT_SUB_LOG20,MAP05: After cutting Wolenick's hand off.,,,"Oh, tys mu uříznul ruku! A já myslela že jsi hodný chlap... jakž takž. Pojďme.","Du skar hans hånd af! Og jeg troede, du var en flink fyr... på en måde. Lad os gå.","Oh, du hast seine Hand abgeschnitten! Und ich dachte du wärest ein netter Typ... oder so. Lass uns gehen.",,,"¡Uh, le cortaste la mano! Y yo pensaba que eras un buen tío... más o menos. Bueno, vamos.","¡Uh, le cortaste la mano! Y yo creía que eras una buena persona... más o menos. Bueno, vamos.","Jaa, sinä katkaisit hänen kätensä! Ja minä kun luulin, että olit kiva kundi... jokseenkin. Mennään.","Oh, tu a coupé sa main? Je croyais que tu étais un type sympa.. Plus où moins. Allons-y.","Oh, levágtad a kezét! És azt hittem egy jó fiú vagy...vagy olyasmi. Na menjünk.","Ah, gli hai tagliato la mano! E io che pensavo fossi un bravo ragazzo... più o meno. Andiamo.","おいおい手を切り取ったのかよ! +ただのナイスガイってわけじゃないのね...まあいい、行こうか。","손을 뜯어버리다니! 아주 좋은 사람인 줄 알았는데... 귀엽네! 후훗, 가자구.","Oh, je hebt zijn hand eraf gesneden! En ik vond je een aardige kerel.... een beetje. Laten we gaan.",Du kappet av ham hånden! Og jeg som trodde du var en hyggelig fyr... på en måte. La oss gå.,"Odciąłeś mu rękę! A ja myślałam, że jesteś miłym facetem... w pewnym sensie. Chodźmy.","Ai, você cortou fora a mão dele! Eu achava que você era um cara bonzinho... talvez. Vamos lá.",,Oh i-ai tăiat mâna! Și credeam că ești de treabă... oarecum. Să mergem.,"О ч-чёрт, ты отрезал ему руку! Я думала, ты добрый парень... в некотором роде. Ладно, не бери в голову.",,"Åh, du skar av hans hand! Och jag som trodde att du var en trevlig kille... typ. Nu går vi.",Elini kesmişsin! Ben de senin iyi bir adam olduğunu sanıyordum. Hadi gidelim. +"Way to go, my friend. Jump on one of the teleporters and it will bring you back to base.",TXT_SUB_LOG21,MAP05: After setting the prisoners free.,,,"Jen tak dál, příteli. Skoč na teleportér, dostane tě zpět na základnu.","Godt gået, min ven. Hop på en af teleportørerne, og den bringer dig tilbage til basen.",Das war gute Arbeit. Benutze einen der Teleporter um zur Basis zurückzugelangen.,,,Así se hace amigo. Ponte en uno de los teletransportes y te traerá de vuelta a la base.,,"Niin sitä pitää, ystäväni. Hyppää johonkin kaukosiirtimistä, ja se tuo sinut takaisin tukikohtaan.",Bien joué mon ami! Utilise l'un des téléporteurs pour revenir à la base.,"Szép munka barátom. Ugorj bele az egyik teleportba, és visszavisz a bázisra.","Ben fatto, amico mio. Recati in uno dei teletrasporti e ti riporterà alla base.",行きましょう、相棒。牢屋奥のテレポーターに飛び込めば基地にすぐ着くわ。,"정말 잘했어, 친구. 저 텔레포터들 중 하나를 타면 기지로 복귀할 수 있을 거야.","Goed gedaan, mijn vriend. Spring op een van de teleporters en het brengt je terug naar de basis.","Sånn skal det gjøres, min venn. Hopp på en av teleporterne, så kommer du tilbake til basen.","Dobra robota, przyjacielu. Wskocz na jeden z teleporterów, a przeniesie cię do bazy.","Boa, meu amigo. Entre num desses teletransportadores e você voltará para a base.",,Bună treabă prietene. Sari într-unul din teleportoare și ne vom întoarce acasă.,"Так держать, дружище. Прыгай в любой телепорт, и он вернёт тебя на базу.",,"Bra jobbat, min vän. Hoppa på en av teleporterna så kommer du tillbaka till basen.","Aferin dostum. Işınlayıcılardan birine atla, seni üsse geri getirecek." +Worner is a spy we recruited in the warehouse of the power station.,TXT_SUB_LOG22,,,,"Worner je špión, kterého jsme najali ve skladišti elektrárny.","Worner er en spion, som vi rekrutterede i lageret på kraftværket.","Worner ist ein Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben.",,,Worner es un espía que reclutamos en el almacén de la estación eléctrica.,,Worner on värväämämme vakooja voimalaitoksen varastolta.,Worner est un espion que nous avons recruté dans l'entrepôt de la centrale éléctrique.,Worner egy spion akit az erőmű raktárjában toboroztunk.,Worner è una spia che abbiamo reclutato nel magazzino della centrale energetica.,,워너는 우리가 모집한 첩자야. 그는 발전소 창고에 있어.,Worner is een spion die we in het magazijn van de centrale hebben gerekruteerd.,Worner er en spion vi rekrutterte i lageret på kraftstasjonen.,"Worner to szpieg, którego zwerbowaliśmy w magazynie elektrowni.",Worner é um espião que recrutamos no depósito da usina de energia.,,Worner e un spion pe care l-am recrutat în depozitul stației de energie.,"Уорнэр — шпион, которого мы завербовали на складе электростанции.",,Worner är en spion som vi rekryterade i kraftverkets lager.,"Worner, güç istasyonunun deposunda işe aldığımız bir casus." +"Word from the boss is stand back when you whack the crystal, or else you'll end up mesquite-flavored too.",TXT_SUB_LOG23,MAP04: After entering Ketrick's room.,,,"Velení radí, aby ses držel dál až rozbiješ krystal, jinak taky skončíš jako pečínka.","Ordet fra chefen er, at du skal holde dig tilbage, når du slår krystallen, ellers ender du også som mesquite-flavored.","Der Ratschlag vom Boss ist, in Deckung zu gehen, wenn du den Kristall plattmachst. Andernfalls könntest du als Omelett enden.",,,"Dice el jefe que te eches atrás cuando le des al cristal, o si no también acabaras frito.",,"Viesti pomolta, että pysy loitolla, kun suolaat kristallin, tai muuten alat itse maistua suolalta.","Le boss me raconte que tu as intérêt à prendre tes distances avant de péter le cristal, sinon tu va aussi te retrouver cuit à la sauce barbecue au plasma.","Ha hihetünk a főnök szavainak, akkor érdemes tisztes távolból szétverni a kristályt, ha nem akarunk elszenesedni.","Il capo dice di tenersi lontani quando fai esplodere il cristallo, altrimenti rischi di saltare in aria pure tu.","上司が言うには、クリスタルを破壊する瞬間には隠れる必要があるな、 +でないと唐揚げになるわ。",대장 말로는 수정체를 부술 때 멀리 피해있으라고 했어. 너도 노릇노릇하게 구워지기 싫다면 말이지.,"Het woord van de baas is een stapje terug als je het kristal slaat, of anders kom je ook nog eens met een mesquite-smaakje terecht.","Ordet fra sjefen er stå tilbake når du slår krystallen, ellers vil du også ende opp med mesquite-smak.","Szef powiedział, żebyś się odsunął, gdy będziesz walił w kryształ, bo inaczej też skończysz z mesquitem.","A chefe me contou que você deve manter distância quando você arrebentar o cristal, senão você vira churrasco.",,"Vorba de la șef e să stai deoparte când spargi cristalul, altfel o să te faci terci.","Босс говорит, чтобы ты держался подальше от кристалла, когда он рванёт. Иначе тебя тоже прожарит до хрустящей корочки.",,"Ord från chefen är att hålla sig undan när du slår kristallen, annars slutar du också med mesquite-smak.","Patronun söylediğine göre kristale vururken geri çekilin, yoksa siz de mesquite aromalı olursunuz." +One more adventure before command feels it's safe to attack. Macil's arranged for Irale to give you gold and some training. And visit the medic for strength.,TXT_SUB_LOG25,MAP02: After destroying the crystal in the Power Station.,,,"Ještě jedno dobrodružství, než se velení rozhodne zaútočit. Macil sjednal u Iraleho zlato a trénink. Taky navštiv lékaře nabrat síly.","Et eventyr mere, før kommandoen føler, at det er sikkert at angribe. Macil har sørget for, at Irale giver dig guld og noget træning. Og besøg lægen for at få styrke.","Eine weitere Aufgabe noch, bevor Macil es für sicher hält, anzugreifen. Macil hat Irale gebeten, dir Gold zu geben und Training zu organisieren. Und lass dir vom Sanitäter deine Ausdauer erhöhen.",,,Una aventura más antes de que el comando sienta que es seguro atacar el castillo. Macil ha acordado con Irale que te dé oro y algo de entrenamiento. Y ver al médico en el pueblo para ganar fuerza.,,"Vielä yksi seikkailu, ennen kuin komentokeskus katsoo tilanteen hyväksi hyökätä. Macil on järjestänyt Iralen antamaan sinulle kultaa ja koulutusta. Ja tapaa lääkintämiestä vahvistusta varten.",Encore une aventure avant le commandement pense qu'il soit l'heure d'attaquer. Macil s'est arrangé pour qu'Irale te donne de l'argent et un peu d'entraînement en plus. Va voir le médecin pour plus de forces.,"Még egy kaland mielőtt az irányítás biztonságosnak érzi az tusoló rohamot. Macil elintézte, hogy kapj Iraletől aranyat és kiképzést. Keresd fel a szanitácet is, hogy felgyógyítson.","Un'ultima avventura prima dell'assedio al castello. Macil ha parlato ad Irale per farti avere dell'oro e un po' di addestramento. Dopo che gli hai fatto visita, parla anche dal medico in città per una marcia in più.","もう一つの任務をこなす前に戦力の増強が必要と考えられる。 マシルがイラールを介して資金と訓練の手配をしてくれるので会いなさい。 -それと近所のメディックも支援してくれるわ。","본부가 공성전을 진행하기 전에 한 가지 해야 할 일이 있어. 마실이 이롤리에게 골드랑 훈련을 제공해달라고 부탁했대. 그다음에는, 마을 병원에 가서 근력을 키워달라고 해.",Nog één avontuur voordat het commando het gevoel heeft dat het veilig is om aan te vallen. Macil heeft ervoor gezorgd dat Irale je goud en wat training kan geven. En bezoek de dokter voor kracht.,,Mais uma aventura antes do comando achar que é seguro o suficiente para atacar. Macil deu instruções para o Irale te passar ouro e um pouco de treinamento. E visite o médico para te dar uma força.,,,"Ещё одно приключение, и штаб будет уверен в успешности атаки на замок. Мэйсил поручил Ирэйлу выплатить тебе награду и дать пару уроков. И зайди на всякий случай к медику.", -"The Order thinks it's secure in its castle. Wrong! If you open the gates, they'll be easy pickings. And for that, you'll have to go down into the sewers. Head along the river across the Governor's mansion. ",TXT_SUB_LOG26,STRIFE1.WAD: MAP02,,,"Řád si myslí, že je uvnitř hradu v bezpečí. Špatně! Pokud otevřeš brány, nebudou proti nám mít šanci. A kvůli tomu musíme do stok. Zamiř si to podél řeky naproti guvernérově sídlu.","Der Orden glaubt, er sei in seiner Burg sicher. Falsch! Wenn du die Tore öffnest werden sie ein leichtes Ziel sein. Und dafür müssen wir in die Kanalisation runter. Geh runter zum Fluss, auf der anderen Seite von der Villa des Gouverneurs.",,,"La Orden cree que está segura en su castillo. ¡Se equivocan! Si abres las puertas, serán cosecha fácil. Y para eso, tienes que bajar a las alcantarillas. Dirígete por el río al lado de la mansión del Gobernador.",,,"L'Ordre se pense en sécurité dans son château, faux! Si tu ouvre les portes, il seront faciles à flinguer. Oh, et pour ça il faut que tu descende dans les égouts. Suis la rivière de l'autre côté du manoir du gouverneur.",,,"オーダーは封鎖した城内が安全だと思っている。大した自信だな! +それと近所のメディックも支援してくれるわ。","본부가 공성전을 진행하기 전에 한 가지 해야 할 일이 있어. 마실이 이롤리에게 골드랑 훈련을 제공해달라고 부탁했대. 그다음에는, 마을 병원에 가서 근력을 키워달라고 해.",Nog één avontuur voordat het commando het gevoel heeft dat het veilig is om aan te vallen. Macil heeft ervoor gezorgd dat Irale je goud en wat training kan geven. En bezoek de dokter voor kracht.,Ett eventyr til før kommandoen mener det er trygt å angripe. Macil har sørget for at Irale gir deg gull og litt trening. Og besøk legen for å få styrke.,"Jeszcze jedna przygoda, zanim dowództwo uzna, że można bezpiecznie zaatakować. Macil załatwił, że Irale da ci złoto i trochę treningu. I odwiedź medyka, żeby nabrać sił.",Mais uma aventura antes do comando achar que é seguro o suficiente para atacar. Macil deu instruções para o Irale te passar ouro e um pouco de treinamento. E visite o médico para te dar uma força.,,Încă o aventură înainte de atacarea centrului de comandă. Macil a aranjat cu Irale ca tu să primești aur și niște antrenament. Și vizitează medicul pentru forță.,"Ещё одно приключение, и штаб будет уверен в успешности атаки на замок. Мэйсил поручил Ирэйлу выплатить тебе награду и дать пару уроков. И зайди на всякий случай к медику.",,Ett äventyr till innan befälet känner att det är säkert att attackera. Macil har ordnat så att Irale ger dig guld och lite träning. Och besök läkaren för att få styrka.,"Komuta saldırmanın güvenli olduğunu düşünmeden önce bir macera daha. Macil, İrale'nin sana altın ve biraz eğitim vermesini ayarladı. Ve güç için doktoru ziyaret et." +"The Order thinks it's secure in its castle. Wrong! If you open the gates, they'll be easy pickings. And for that, you'll have to go down into the sewers. Head along the river across the Governor's mansion. ",TXT_SUB_LOG26,〃,,,"Řád si myslí, že je uvnitř hradu v bezpečí. Špatně! Pokud otevřeš brány, nebudou proti nám mít šanci. A kvůli tomu musíme do stok. Zamiř si to podél řeky naproti guvernérově sídlu.","Ordenen tror, at den er sikker i sit slot. Det er forkert! Hvis du åbner portene, bliver de et let bytte. Og til det skal du ned i kloakkerne. Gå langs floden over for guvernørens palæ.","Der Orden glaubt, er sei in seiner Burg sicher. Falsch! Wenn du die Tore öffnest werden sie ein leichtes Ziel sein. Und dafür müssen wir in die Kanalisation runter. Geh runter zum Fluss, auf der anderen Seite von der Villa des Gouverneurs.",,,"La Orden cree que está segura en su castillo. ¡Se equivocan! Si abres las puertas, serán cosecha fácil. Y para eso, tienes que bajar a las alcantarillas. Dirígete por el río al lado de la mansión del Gobernador.",,"Veljeskunta luulee olevansa turvassa linnassaan. Väärin! Jos avaat portit, he ovat helppoa saalista. Ja sitä varten sinun on mentävä alas viemäreihin. Kulje joen vartta kuvernöörin kartanoa vastapäätä.","L'Ordre se pense en sécurité dans son château, faux! Si tu ouvre les portes, il seront faciles à flinguer. Oh, et pour ça il faut que tu descende dans les égouts. Suis la rivière de l'autre côté du manoir du gouverneur.",A Rend azt hiszi biztonságban vannak a kastélyban. Tévedés! Ha sikerül kinyitni a kaput könnyen le tudjuk őket szedni. Ezért azonban le kell menni a kanálisba. Menj a folyó nyomán a kormányzó kúriájával szemben.,"L'Ordine pensa di essere al sicuro dentro il suo castello. Sbagliato! Se apri i cancelli, saranno facili bersagli. E per aprirli, dovremo scendere nelle fogne. L'ingresso si trova vicino al fiume verso dove c'è la dimora del governatore.","オーダーは封鎖した城内が安全だと思っている。大した自信だな! 容易く侵入を許すとも知らずに。それでゲートを開けるには下水道を通る必要がある。 -知事邸の川を挟んだ所にその入り口がある。","오더는 성안 쪽에 지켜져 있는 거로 알겠지만, 틀렸어! 성문을 열기만 한다면 나머지는 쉬운 일일 거야. 일단 그러려면, 하수구 아래로 내려가야 해. 총독 관저 너머의 강을 지나가 봐.","De Orde denkt dat het veilig is in zijn kasteel. Fout! Als je de poorten opent, zijn het gemakkelijke keuzes. En daarvoor moet je de riolering in. Loop langs de rivier over het landhuis van de gouverneur.",,"A Ordem acha que está segura dentro do castelo. Se enganaram! Se você abrir os portões, vai ser fácil pegá-los. E, para isso, você terá que ir até o esgoto. Vá pelo rio do outro lado da mansão do Governador.",,,"Орден думает, что замок неприступен. Большая ошибка! Он будет лёгкой добычей, когда ты откроешь врата. Спустись в канализацию, чтобы найти механизм. Иди вдоль берега реки — спуск прямо напротив особняка губернатора.", -"OK, duck in here. The sewer dwellers are horrible mutants, but their network of tunnels gives them access to secrets. Hold your nose... We're going down.",TXT_SUB_LOG27,STRIFE1.WAD: MAP02,,,"Dobře, skoč tady dolů. Obyvatelé kanálů jsou příšerní mutanti, ale pomocí jejich sítě tunelů mají přístup k informacím. Podrž si nos... Jdeme dolů.","OK, kriech hier rein. Die Kanalisationsbewohner sind fürchterliche Mutanten, aber ihr Tunnelnetzwerk gibt ihnen Zugang zu Geheimräumen. Halt die Nase zu, wir gehen runter.",,,"OK, agáchate por aquí. La gente de las alcantarillas son mutantes horribles, pero su red de túneles les da acceso a secretos. Tápate la nariz... Vamos abajo.",,,"Ok, accroupis-toi ici. Les habitants des égouts sont d'affreux mutants mais leur réseau de tunnels leur donne accès à beaucoup de secrets. Retient ton souffle, par contre.. On va descendre.",,,"下水道の住民は恐ろしい変異体だ。だが彼らのトンネル網には秘密の通路も含まれる。 -良し、ここから降りる前に鼻はつまんどけよ...","좋아, 바로 여기야. 하수구 거주민들은 끔찍한 돌연변이들이지만, 그들의 땅굴 망이 숨겨진 장소들로 인도할 거야. 숨 잘 참아... 아래로 내려간다.","Oké, bukken hier naar binnen. De rioolbewoners zijn verschrikkelijke mutanten, maar hun netwerk van tunnels geeft hen toegang tot geheimen. Hou je neus vast.... We gaan naar beneden.",,"Ok, fique abaixado aqui. Os habitantes do esgoto são mutantes horríveis, mas a sua rede de túneis os dá acesso para áreas secretas. Segure a respiração... Vamos descer.",,,"Да, это здесь. Обитатели канализации — жуткие уроды, но они знают все секреты благодаря своим системам туннелей. Зажми нос — мы спускаемся!", -"We're looking for Weran, who calls himself the Rat King. I'm sure it's descriptive as well as colorful.",TXT_SUB_LOG28,STRIFE1.WAD: MAP06,,,"Hledáma Werana, který si říká Krysí král. Jsem si jistá, že to je jak barvité, tak přesné.",,,,,,,,,,"ウェランを探すんだ、誰が呼んだかラットキングでもある。 -私はそれが叙述的でもあり派手な呼び名なのも定かだ。",우리는 자신을 시궁쥐 왕이라고 부르는 워렌을 찾아야 해. 알록달록해서 눈에 잘 띌 것 같은데 말이야.,"We zijn op zoek naar Weran, die zichzelf de rattenkoning noemt. Ik weet zeker dat het zowel beschrijvend als kleurrijk is.",,,,,"Нам нужен Уэран — он называет себя Крысиным королём. Уверена, прозвище так же емко, как и красочно.", -"Oh, yuck. I don't even want to think about what you are stepping in!",TXT_SUB_LOG29,STRIFE1.WAD: MAP06,,,"Ó, fuj, nechci ani pomýšlet na to, do čeho teď šlapeš!","Igitt! Ich möchte gar nicht darüber nachdenken, wo du gerade durchwatest.",,,"Oh, puaj. ¡No quiero ni pensar en lo que estás pisando!",,,"Oh, beurk! J'ai pas envie de savoir dans quoi tu marche!",,,オェッ。君が足を踏み入れてるモノの事など考えたくないわ!,웩. 네가 밟고 있는 게 뭔지 상상조차 하기 싫어!,"Oh, ja. Ik wil er niet eens aan denken wat je doet!",,"Argh, eca. Não quero nem saber no que você está pisando!",,,"Ох, фу. Даже знать не хочу, во что ты наступил!", -Just what I need. More brown goo!,TXT_SUB_LOG30,STRIFE1.WAD: MAP06,,,"Přesně, co potřebuju. Další hnědá břečka!","Genau das, was ich brauchte. Mehr brauner Schlamm!",,,Justo lo que necesito. ¡Más lodo marrón!,,,"Juste ce qu'il me fallait, encore de la crasse marron!",,,万事休すだ。更に茶色いモノだ!,"또 시궁창이라니, 정말 보기 좋네!",Precies wat ik nodig heb. Meer bruine drab!,,Justo o que eu precisava. Mais meleca marrom!,,,"То, что надо. Ещё больше коричневой жижи!", -"Hey, look! I think that's the door Weran wants ajar!",TXT_SUB_LOG31,,,,"Hele, podívej! Myslím, že to jsou ty dveře, které chce Weran nechat otevřené!","Sieh dort! Ich glaube, das ist die Tür, die Weran geöffnet haben möchte.",,,"¡Eh, mira! ¡Creo que esa es la puerta que Weran quiere entreabierta!",,,"Hé, regarde! On dirait que c'est la porte que Weran veut qu'on coince!",,,,저기야! 저게 워렌이 열어줬으면 하는 문일 거야.,"Hé, kijk! Ik denk dat dat de deur is die Weran op een kier wil hebben!",,"Ei, veja! Acho que essa é a porta que o Weran quer que fique aberta!",,,"О, смотри! Похоже, это та самая дверь, которую хочет приоткрыть Уэран!", -"Shut your eyes! I don't wanna see! Oh, too late... Yuck. That doesn't look like a human body. What has the Order done? I gotta report this to command.",TXT_SUB_LOG32,,,,"Zavři oči! Nechci to vidět! Ah, moc pozdě... Fuj. To ani nevypadá jako lidské tělo. Co to Řád provedl? Musím tohle nahlásit velení.","Mach die Augen zu! Ich will das nicht sehen. Zu spät... Igitt, das sieht gar nicht aus wie ein menschlicher Körper. Was hat der Orden getan? Ich muss das an die Kommandozentrale weitergeben.",,,"¡Cierra los ojos! ¡No quiero ver! Oh, demasiado tarde... Puaj. Eso no parece un cuerpo humano. ¿Que ha hecho la Orden? Tengo que reportar esto al comando.",,,"Ferme tes yeux, je ne veux pas voire ça! Oh, trop tard.. Beurk, on dirait pas un corps humain, qu'est-ce que l'ordre à fait? Il faut que je rapporte ça au commandement.",,,,"눈 감아! 보고 싶지 않아! 오, 너무 늦었네... 역겨워. 전혀 사람 몸 같지 않던데, 대체 오더가 무슨 짓을 한 거지? 본부에 이걸 보고해야겠어.","Sluit je ogen! Ik wil het niet zien! Oh, te laat.... Yuck. Dat ziet er niet uit als een menselijk lichaam. Wat heeft de Orde gedaan? Ik moet dit aan het commando melden.",,"Feche os olhos! Eu não quero ver! Ai, tarde demais... Eca. Isso não parece um corpo humano. O que a Ordem fez? Preciso relatar isso ao comando.",,,"Зажмурься! Я не хочу это видеть! Ох, уже поздно... Какая дрянь. Это даже не выглядит как человеческое тело. Что творит этот Орден! Я немедленно доложу в штаб.", -Why can't we do a mission in a field of flowers for once?,TXT_SUB_LOG33,STRIFE1.WAD: MAP06,,,Nemůžeme někdy mít misi na poli plném kvítí?,Warum können wir nicht mal eine Mission in einem Blumenfeld haben? ,,,¿Por que no podemos hacer una misión en un campo de flores por una vez?,,,"Pourquoi est-ce qu'on ne peut pas avoir une mission dans un champ de fleurs, pour une fois?",,,どうして私達は綺麗な場所で一度でも任務遂行が出来ないんだ?,왜 우리는 딱 한 번이라도 꽃밭에서 작전을 수행할 수 없는 걸까?,Waarom kunnen we niet een keer een missie doen in een bloemenveld?,,Por que é que a gente não faz uma missão num campo florido pelo menos uma vez?,,,Ну почему наши задания не могут разворачиваться на цветочном лугу?, -I hate to say it but this reminds me of home. I'm underground not that far from here.,TXT_SUB_LOG34,STRIFE1.WAD: MAP06,,,"Říká se mi to těžko, ale tohle mi připomíná domov. Jsem v podzemí ne tak daleko odsud.","Ich sage es nicht gerne, aber das erinnert mich an Zuhause. Ich bin auch im Untergrund, nicht weit von hier.",,,Odio decirlo pero esto me recuerda a mi hogar. Estoy bajo tierra no muy lejos de aquí.,,,"J'ai vraiment pas envie de l'admettre, mais ça me rappelle ma maison.. Je suis sous terre pas loin d'ici.",,,"言いたくないが私の家の事を思い出させるわ。 -私はこの地下から遠くない場所にいたのよ。","말하긴 싫지만, 여긴 꼭 내 집을 보는 것 같아... 난 여기서 멀지 않은 지하에 있어.","Ik haat het om het te zeggen, maar dit doet me denken aan thuis. Ik ben niet zo ver van hier ondergronds.",,Odeio dizer isso mas isso lembra a minha casa. Estou sob o solo não muito longe daqui.,,,"Не хотела говорить, но это место напоминает мне о доме. Сейчас я в подземелье, которое не так уж далеко отсюда.", -"Don't ask me where we are. I'm lost, too. Sorry.",TXT_SUB_LOG35,STRIFE1.WAD: MAP06,,,"Neptej se mě, kde jsme. Taky jsem ztracená. Promiň.","Frag mich nicht, wo wir sind, ich habe keine Ahnung. Tut mir leid.",,,No me preguntes donde estamos. Yo también me he perdido. Lo siento.,,,"Me demande pas où on est, je suis aussi perdue que toi, désolée..",,,今いる場所について私に聞かないでくれ。私も迷った。すまない。,"여기가 어딘지 묻지 마. 나도 길을 잃었거든, 미안해.",Vraag me niet waar we zijn. Ik ben ook verdwaald. Sorry.,,Não me pergunte onde estamos. Já me perdi. Desculpe.,,,"Даже не спрашивай, где мы. Я сама не знаю, извини.", -That brick... Didn't we pass that brick? No...,TXT_SUB_LOG36,STRIFE1.WAD: MAP06,,,Ta cihla... Neminuli jsme tamtu cihlu? Ne...,Der Stein... Sind wir nicht an dem Stein vorbeigekommen? Nein...,,,Ese ladrillo... ¿No pasamos por ese ladrillo? No...,,,Cette brique.. On n'a pas passé cette brique avant? Non..,,,あの煉瓦...前通ったレンガか?いや...,저 벽... 아까 저 벽을 지나가지 않았던가? 아닌데...,Die steen.... Hebben we die steen niet gepasseerd? Nee....,,Aquele tijolo... Já não passamos daquele tijolo? Não...,,,Этот кирпич... Разве мы здесь не были? Нет..., -"Command, he's done it! The gates are open. Send in the shock troops and tell Macil we're coming in! ",TXT_SUB_LOG37,STRIFE1.WAD: MAP06,,,"Velení, dokázal to! Brány jsou otevřené. Pošlete tam úderníky a řekněte Macilovi, že přicházíme!",Kommandozentrale: Er hat's geschafft! Die Tore sind offen. Schickt die Schocktruppen hinein und sagt Macil das wir auf dem Weg sind! Lass uns zur Frontbasis zurückkehren.,,,"Comando, ¡Lo ha hecho! Las puertas están abiertas. ¡Enviad a las tropas de choque y decidle a Macil que venimos adentro!","Comando, ¡Lo ha hecho! Las puertas están abiertas. ¡Envíen las tropas de choque y díganel a Macil que estamos entrando!",,"C'est bon, commandement, il a réussi! Les portes sont ouvertes, envoyez les soldats de choc et dites à Macil que l'on arrive!",,,"司令官、彼はやったぞ! -ゲートが開いた。突撃部隊を送って我々も続くとマシルに伝えてくれ!","본부, 그가 해냈습니다! 성문이 열렸습니다. 공습부대를 성문으로 이동시키고 사령관님께 우리들도 따라올 거라고 전해주세요.","Commando, hij heeft het gedaan! De poorten zijn open. Stuur de stoottroepen naar binnen en zeg Macil dat we binnenkomen!",,"Comando, ele conseguiu! Os portões estão abertos. Enviem as tropas de choque e digam ao Macil que estamos entrando!",,,"Штаб, он выполнил задание! Ворота открыты. Посылайте ударный отряд и доложите Мэйсилу, что мы пробились!", -"We have conflicting reports about the Programmer's location. One say he's in a computer room, another that he's in a keep and yet another that mentions a long hallway. Sorry. ",TXT_SUB_LOG38,STRIFE1.WAD: MAP07,,,"Máme rozcházející se zprávy o Programátorově pozici. Jedna mluví o místnosti s počítači, druhá, že je v nějaké pevnosti a třetí zmiňuje dlouhou chodbu. Promiň.","Wir haben widersprüchliche Angaben über seinen Aufenthaltsort. Eine sagt, in einem Computerraum, ein anderer, dass er sich in einem Tempelkeller versteckt und noch ein anderer sagt was vom Ende eines langen Flurs.",,,"Tenemos informes contradictorios sobre la ubicación del Programador. Uno dice que está en una sala de computadoras, otro que está en un torreón y otro más menciona un pasillo largo. Lo siento.",,,"On a des rapports contradictoires au sujet d'où se trouve le programmeur. On me dit d'un côté qu'il est dans une salle des ordinateurs, un autre me dit qu'il est dans un donjon, et un autre me dit qu'il est dans un long couloir.. Désolé.",,,"プログラマーの居場所について矛盾する報告もあるわ。 +知事邸の川を挟んだ所にその入り口がある。","오더는 성안 쪽에 지켜져 있는 거로 알겠지만, 틀렸어! 성문을 열기만 한다면 나머지는 쉬운 일일 거야. 일단 그러려면, 하수구 아래로 내려가야 해. 총독 관저 너머의 강을 지나가 봐.","De Orde denkt dat het veilig is in zijn kasteel. Fout! Als je de poorten opent, zijn het gemakkelijke keuzes. En daarvoor moet je de riolering in. Loop langs de rivier over het landhuis van de gouverneur.","Ordenen tror den er trygg i sitt slott. Feil! Hvis du åpner portene, blir de et lett bytte. Og da må du gå ned i kloakken. Gå langs elven på den andre siden av guvernørens hus.","Zakon myśli, że jest bezpieczny w swoim zamku. Mylisz się! Jeśli otworzysz bramy, będą łatwym łupem. A w tym celu będziesz musiał zejść do kanałów. Kieruj się wzdłuż rzeki, naprzeciwko rezydencji gubernatora.","A Ordem acha que está segura dentro do castelo. Se enganaram! Se você abrir os portões, vai ser fácil pegá-los. E, para isso, você terá que ir até o esgoto. Vá pelo rio do outro lado da mansão do Governador.",,"Ordinul crede că e în siguranță în castel. Greșit! Dacă deschizi porțile, vor fi victime ușoare. Pentru asta, va trebui să mergi în canale. Urmează râul până la complexul Guvernatorului.","Орден думает, что замок неприступен. Большая ошибка! Он будет лёгкой добычей, когда ты откроешь врата. Спустись в канализацию, чтобы найти механизм. Иди вдоль берега реки — спуск прямо напротив особняка губернатора.",,Orden tror att den är säker i sitt slott. Fel! Om du öppnar portarna blir de lätta att plocka. Och för det måste du gå ner i kloakerna. Gå längs floden över guvernörens herrgård.,"Tarikat kalesinde güvende olduğunu düşünüyor. Yanılıyorlar! Eğer kapıları açarsanız, kolay lokma olacaklar. Bunun için de kanalizasyona inmeniz gerekecek. Valinin konağının karşısındaki nehir boyunca ilerleyin." +"OK, duck in here. The sewer dwellers are horrible mutants, but their network of tunnels gives them access to secrets. Hold your nose... We're going down.",TXT_SUB_LOG27,〃,,,"Dobře, zalez sem. Obyvatelé kanálů jsou příšerní mutanti, ale pomocí své sítě tunelů mají přístup k informacím. Drž si nos... Jdeme dolů.","OK, duk dig herind. Kloakbeboerne er forfærdelige mutanter, men deres netværk af tunneler giver dem adgang til hemmeligheder. Hold dig for næsen... Vi går ned.","OK, kriech hier rein. Die Kanalisationsbewohner sind fürchterliche Mutanten, aber ihr Tunnelnetzwerk gibt ihnen Zugang zu Geheimräumen. Halt die Nase zu, wir gehen runter.",,,"Hay un interrumptor por aquí abajo. La gente de las alcantarillas son mutantes horribles, pero su red de túneles les da acceso a secretos. Tápate la nariz... Vamos abajo.",,"No niin, kumarru tässä. Viemärin asukit ovat kauhistuttavia mutantteja, mutta heidän tunneliverkkonsa antaa heille pääsyn salaisiin paikkoihin. Pidä kiinni nenästäsi, menemme alas.","Ok, accroupis-toi ici. Les habitants des égouts sont d'affreux mutants mais leur réseau de tunnels leur donne accès à beaucoup de secrets. Retient ton souffle, par contre.. On va descendre.","Ok, gugolj itt le. A kanális lakók szörnyű mutánsok, de az általuk kiépített alagút hálózat mindenféle titokhoz hozzásegíti őket. Fogd be az orrod...lemerülünk.","OK, entra qua dentro. Gli abitanti delle fogne sono orribili mutanti, ma la serie di tunnel che gestiscono permette di raggiungere diversi segreti. Tappati il naso... Stiamo scendendo.","下水道の住民は恐ろしい変異体だ。だが彼らのトンネル網には秘密の通路も含まれる。 +良し、ここから降りる前に鼻はつまんどけよ...","좋아, 바로 여기야. 하수구 거주민들은 끔찍한 돌연변이들이지만, 그들의 땅굴 망이 숨겨진 장소들로 인도할 거야. 숨 잘 참아... 아래로 내려간다.","Oké, bukken hier naar binnen. De rioolbewoners zijn verschrikkelijke mutanten, maar hun netwerk van tunnels geeft hen toegang tot geheimen. Hou je neus vast.... We gaan naar beneden.","OK, dukk her inne. Kloakkboerne er fæle mutanter, men deres nettverk av tunneler gir dem tilgang til hemmeligheter. Hold for nesen... Vi går ned.","Dobra, schowaj się tutaj. Mieszkańcy kanałów to straszne mutanty, ale ich sieć tuneli daje im dostęp do sekretów. Trzymaj się... Schodzimy na dół.","Ok, fique abaixado aqui. Os habitantes do esgoto são mutantes horríveis, mas a sua rede de túneis os dá acesso para áreas secretas. Segure a respiração... Vamos descer.",,"OK, ghemuiește-te aici. Locuitorii canalelor sunt mutanți oribili, dar rețeaua lor de tunele le dă acces la secrete.... Mergem înăuntru.","Да, это здесь. Обитатели канализации — жуткие уроды, но они знают все секреты благодаря своим системам туннелей. Зажми нос — мы спускаемся!",,"Okej, ducka in här. Kloakborna är hemska mutanter, men deras nätverk av tunnlar ger dem tillgång till hemligheter. Håll dig för näsan... Vi går ner.","Tamam, buraya gir. Lağım sakinleri korkunç mutantlardır, ama tünel ağları onlara sırlara erişim sağlar. Burnunu tut. Aşağı iniyoruz." +"We're looking for Weran, who calls himself the Rat King. I'm sure it's descriptive as well as colorful.",TXT_SUB_LOG28,MAP06: Entrance.,,,"Hledáma Werana, který si říká Krysí král. Jsem si jistá, že je to jak barvité, tak přesné.","Vi leder efter Weran, som kalder sig rottekongen. Jeg er sikker på, at det er både beskrivende og farverigt.",,,,"Estamos buscando a Weran, quien se autoproclama el Rey de las Ratas. Estoy segura de que es tanto descriptivo como vistoso.",,"Etsimme Werania, joka kutsuu itseään Rottakuninkaaksi. Varmastikin kuvaava titteli, mutta myös väritetty.",,"Werant keressük, aki csak Patkány Királyként emlegeti magát. Minden bizonnyal találó a név.","Stiamo cercando Weran, che si fa chiamare il Re dei Ratti. Sono sicura che lo descrive appieno.","ウェランを探すんだ、誰が呼んだかラットキングでもある。 +私はそれが叙述的でもあり派手な呼び名なのも定かだ。",우리는 자신을 시궁쥐 왕이라고 부르는 워렌을 찾아야 해. 알록달록해서 눈에 잘 띌 것 같은데 말이야.,"We zijn op zoek naar Weran, die zichzelf de rattenkoning noemt. Ik weet zeker dat het zowel beschrijvend als kleurrijk is.","Vi leter etter Weran, som kaller seg Rottekongen. Det er sikkert både beskrivende og fargerikt.","Szukamy Werana, który nazywa siebie Królem Szczurów. Jestem pewien, że jest to opisowe jak i barwne.","Estamos procurando pelo Weran, que se autodenomina o Rato Rei. Imagino que isso seja tão descritivo quanto gracioso.",,"Îl căutăm pe Weran, care-și spune Regele Sobolanilor. Sunt sigur că e și descripti și colorat.","Нам нужен Уэран — он называет себя Крысиным королём. Уверена, прозвище так же емко, как и красочно.",,"Vi letar efter Weran, som kallar sig för råttkungen. Jag är säker på att det är både beskrivande och färgstarkt.",Kendine Fare Kral diyen Weran'ı arıyoruz. Renkli olduğu kadar açıklayıcı da olduğuna eminim. +"Oh, yuck. I don't even want to think about what you are stepping in!",TXT_SUB_LOG29,MAP06: Down → Left.,,,"Ó, fuj, nechci ani pomýšlet na to, do čeho teď šlapeš!","Åh, føj. Jeg vil ikke engang tænke på, hvad du træder i!","Igitt! Ich möchte gar nicht darüber nachdenken, wo du gerade durchwatest.",,,"Oh, puaj. ¡No quiero ni pensar en lo que estás pisando!",,"Äh, yäk. En halua edes kuvitella, missä oikein astelet!","Oh, beurk! J'ai pas envie de savoir dans quoi tu marche!","Oh, fúj. Nem is akarom tudni miben lépkedsz.","Oh, dannazione... Non voglio neanche pensare a cosa stai calpestando!",オェッ。君が足を踏み入れてるモノの事など考えたくないわ!,웩. 네가 밟고 있는 게 뭔지 상상조차 하기 싫어!,"Oh, ja. Ik wil er niet eens aan denken wat je doet!","Å, æsj. Jeg vil ikke engang tenke på hva du tråkker i!","Oh, fuj. Nawet nie chcę myśleć, w co wdepniesz!","Argh, eca. Não quero nem saber no que você está pisando!",,"Oh, yuck. Nu vreau să știu în ce calci!","Ох, фу. Даже знать не хочу, во что ты наступил!",,"Åh, äckligt. Jag vill inte ens tänka på vad du trampar i!","Oh, iğrenç. Neye bastığınızı düşünmek bile istemiyorum!" +Just what I need. More brown goo!,TXT_SUB_LOG30,MAP06: Down → Left → Upstairs → Left.,,,"Přesně, co potřebuju. Další hnědá břečka!",Lige hvad jeg har brug for. Mere brunt klamphug!,"Genau das, was ich brauchte. Mehr brauner Schlamm!",,,Justo lo que necesito. ¡Más lodo marrón!,,"Juuri, mitä tarvitsen: lisää ruskeaa mönjää!","Juste ce qu'il me fallait, encore de la crasse marron!",Pont ez hiányzott. Még több barna trutymák.,Proprio quello che volevo vedere. Altro liquido marrone!,万事休すだ。更に茶色いモノだ!,"또 시궁창이라니, 정말 보기 좋네!",Precies wat ik nodig heb. Meer bruine drab!,Akkurat det jeg trenger. Mer brunt gjørme!,Właśnie tego mi trzeba. Więcej brązowej mazi!,Justo o que eu precisava. Mais meleca marrom!,,Exact ce îmi trebuie. Mai multă mâzgă maro!,"То, что надо. Ещё больше коричневой жижи!",,Precis vad jag behöver. Mer brunt kladd!,Tam da ihtiyacım olan şey. Daha fazla kahverengi yapışkan! +"Hey, look! I think that's the door Weran wants ajar!",TXT_SUB_LOG31,,,,"Hele, podívej! Myslím, že to jsou ty dveře, které chce Weran nechat otevřené!","Hey, se! Jeg tror, det er døren, som Weran vil have på klem!","Sieh dort! Ich glaube, das ist die Tür, die Weran geöffnet haben möchte.",,,"¡Eh, mira! ¡Creo que esa es la puerta que Weran quiere entreabierta!",,"Hei, katso! Tuo on varmaankin se ovi, jonka Weran haluaa raolleen!","Hé, regarde! On dirait que c'est la porte que Weran veut qu'on coince!",Nézz oda! Azt hiszem ez az az ajtó amit félig ki akar nyitni Weran.,"Ehi, guarda! Credo quella sia la porta che Weran vuole aprire!",,저기야! 저게 워렌이 열어줬으면 하는 문일 거야.,"Hé, kijk! Ik denk dat dat de deur is die Weran op een kier wil hebben!","Hei, se! Jeg tror det er døra Weran vil ha på gløtt!","Hej, patrzcie! To chyba te drzwi, które Weran chce uchylić!",Olha! Acho que essa é a porta que o Weran quer que fique aberta!,,"Hei, uite! Acolo cred că e ușa pe care o vrea Weran!","О, смотри! Похоже, это та самая дверь, которую хочет приоткрыть Уэран!",,Titta! Jag tror att det är dörren som Weran vill ha på glänt!,"Hey, bakın! Sanırım Weran'ın aralık kalmasını istediği kapı bu!" +"Shut your eyes! I don't wanna see! Oh, too late... Yuck. That doesn't look like a human body. What has the Order done? I gotta report this to command.",TXT_SUB_LOG32,,,,"Zavři oči! Nechci to vidět! Ah, moc pozdě... Fuj. To ani nevypadá jako lidské tělo. Co to Řád provedl? Musím tohle nahlásit velení.","Luk øjnene! Jeg vil ikke se! Åh, for sent... Yuck. Det ligner ikke et menneskeligt lig. Hvad har Ordenen gjort? Jeg må rapportere det til kommandoen.","Mach die Augen zu! Ich will das nicht sehen. Zu spät... Igitt, das sieht gar nicht aus wie ein menschlicher Körper. Was hat der Orden getan? Ich muss das an die Kommandozentrale weitergeben.",,,"¡Cierra los ojos! ¡No quiero ver! Oh, demasiado tarde... Puaj. Eso no parece un cuerpo humano. ¿Que ha hecho la Orden? Tengo que reportar esto al comando.",,"Sulje silmäsi! En halua nähdä! Äh, myöhäistä... yäk. Tuo ei näytä ihmisruumiilta. Mitä Veljeskunta oikein on tehnyt? Minun on ilmoitettava tästä komentokeskukselle.","Ferme tes yeux, je ne veux pas voire ça! Oh, trop tard.. Beurk, on dirait pas un corps humain, qu'est-ce que l'ordre à fait? Il faut que je rapporte ça au commandement.",Csukd be a szemed! Nem akarom látni! Ó túl késő...fúj. Ez nem úgy néz ki mint egy emberi tetem. Mit tett a Rend? Ezt jeleznem kell az irányításnak.,"Chiudi gli occhi! Non voglio vedere! Ah, troppo tardi... Non sembra un corpo umano. Che cosa ha fatto l'Ordine? Devo riportare questo al comando.",,"눈 감아! 보고 싶지 않아! 오, 너무 늦었네... 역겨워. 전혀 사람 몸 같지 않던데, 대체 오더가 무슨 짓을 한 거지? 본부에 이걸 보고해야겠어.","Sluit je ogen! Ik wil het niet zien! Oh, te laat.... Yuck. Dat ziet er niet uit als een menselijk lichaam. Wat heeft de Orde gedaan? Ik moet dit aan het commando melden.","Lukk øynene! Jeg vil ikke se! Å, for sent... Æsj. Det ser ikke ut som en menneskekropp. Hva har Ordenen gjort? Jeg må rapportere dette til kommandoen.","Zamknij oczy! Nie chcę widzieć! Och, za późno... Fuj. To nie wygląda jak ludzkie ciało. Co zrobił Zakon? Muszę to zgłosić do dowództwa.","Feche os olhos! Eu não quero ver! Ai, tarde demais... Eca. Isso não parece um corpo humano. O que foi que a Ordem fez? Preciso relatar isso ao comando.",,Închide ochii! Nu vreau să văd! Oh... prea târziu... Yuck. Nu pare un cadavru uman. Ce a făcut Ordinul? Trebuie să raportez asta.,"Зажмурься! Я не хочу это видеть! Ох, уже поздно... Какая дрянь. Это даже не выглядит как человеческое тело. Что творит этот Орден! Я немедленно доложу в штаб.",,"Håll ögonen! Jag vill inte se! Åh, för sent... Usch. Det ser inte ut som en människokropp. Vad har Orden gjort? Jag måste rapportera det här till befälet.","Kapa gözlerini! Görmek istemiyorum! Oh, çok geç... İğrenç. Bu bir insan vücuduna benzemiyor. Tarikat ne yaptı? Bunu komutaya rapor etmeliyim." +Why can't we do a mission in a field of flowers for once?,TXT_SUB_LOG33,MAP06: After giving the guard's uniform.,,,Nemůžeme někdy mít misi na poli plném kvítí?,Hvorfor kan vi ikke for en gangs skyld udføre en mission i en blomstermark?,Warum können wir nicht mal eine Mission in einem Blumenfeld haben? ,,,¿Por que no podemos hacer una misión en un campo de flores por una vez?,,Miksei meillä kerrankin voisi olla tehtävä kukkakedolla?,"Pourquoi est-ce qu'on ne peut pas avoir une mission dans un champ de fleurs, pour une fois?",Miért nem mehetünk legalább egyszer egy virágmezős misszióra?,Perché non possiamo fare una missione in un campo di fiori per una volta?,どうして私達は綺麗な場所で一度でも任務遂行が出来ないんだ?,왜 우리는 딱 한 번이라도 꽃밭에서 작전을 수행할 수 없는 걸까?,Waarom kunnen we niet een keer een missie doen in een bloemenveld?,Hvorfor kan vi ikke gjøre et oppdrag i en blomstereng for en gangs skyld?,Dlaczego nie możemy choć raz wykonać misji na polu kwiatów?,Por que é que a gente não faz uma missão num campo florido pelo menos uma vez?,,De ce nu putem avea o misiune pe un câmp de flori măcar odată?,Ну почему наши задания не могут разворачиваться на цветочном лугу?,,Varför kan vi inte göra ett uppdrag på ett blomsterfält för en gångs skull?,Neden bir kez olsun çiçek tarlasında görev yapamıyoruz? +I hate to say it but this reminds me of home. I'm underground not that far from here.,TXT_SUB_LOG34,MAP06: Weran's hideout.,,,"Říká se mi to těžko, ale tohle mi připomíná domov. Jsem v podzemí ne tak daleko odsud.","Jeg hader at sige det, men det her minder mig om mit hjem. Jeg er under jorden ikke så langt herfra.","Ich sage es nicht gerne, aber das erinnert mich an Zuhause. Ich bin auch im Untergrund, nicht weit von hier.",,,Odio decirlo pero esto me recuerda a mi hogar. Estoy bajo tierra no muy lejos de aquí.,,"Inhottaa sanoa, mutta tästä tulee koti mieleen: Olen maan alla, en niin kaukana täältä.","J'ai vraiment pas envie de l'admettre, mais ça me rappelle ma maison.. Je suis sous terre pas loin d'ici.","Nem szívesen mondom ezt, de ez az otthonomra emlékeztet. Föld alatt van az is nem túl messze innen.","Mi duole dirlo, ma tutto ciò mi ricorda casa. Anche io mi trovo sottoterra, non troppo lontano da qui.","言いたくないが私の家の事を思い出させるわ。 +私はこの地下から遠くない場所にいたのよ。","말하긴 싫지만, 여긴 꼭 내 집을 보는 것 같아... 난 여기서 멀지 않은 지하에 있어.","Ik haat het om het te zeggen, maar dit doet me denken aan thuis. Ik ben niet zo ver van hier ondergronds.","Jeg hater å si det, men dette minner meg om hjemme. Jeg er under jorden ikke så langt herfra.","Nie chcę tego mówić, ale to przypomina mi dom. Jestem pod ziemią, nie tak daleko stąd.",Odeio dizer isso mas isso lembra a minha casa. Estou sob o solo não muito longe daqui.,,Îmi pare rău s-o spun dar asta îmi aduce aminte de casă. Stau sub pământ nu departe de aici.,"Не хотела говорить, но это место напоминает мне о доме. Сейчас я в подземелье, которое не так уж далеко отсюда.",,"Jag hatar att säga det, men det här påminner mig om mitt hem. Jag är underjordisk inte så långt härifrån.","Bunu söylemekten nefret ediyorum ama bu bana evimi hatırlatıyor. Yeraltındayım, buradan çok uzakta değilim." +"Don't ask me where we are. I'm lost, too. Sorry.",TXT_SUB_LOG35,MAP06: Exit of the secret entrance.,,,"Neptej se mě, kde jsme. Taky jsem ztracená. Promiň.","Spørg mig ikke, hvor vi er. Jeg er også faret vild. Jeg er også fortabt. Undskyld.","Frag mich nicht, wo wir sind, ich habe keine Ahnung. Tut mir leid.",,,"No me preguntes en dónde estamos, que yo también estoy perdida. Perdón.",,"Älä kysy minulta, missä olemme. Olen myös eksyksissä; pahoittelut.","Me demande pas où on est, je suis aussi perdue que toi, désolée..","Ne kérdezd hol vagyunk. Én is el vagyok veszve, sajnálom.",Non chiedermi dove siamo. Mi sono persa anche io. Mi spiace...,今いる場所について私に聞かないでくれ。私も迷った。すまない。,"여기가 어딘지 묻지 마. 나도 길을 잃었거든, 미안해.",Vraag me niet waar we zijn. Ik ben ook verdwaald. Sorry.,Ikke spør meg hvor vi er. Jeg har også gått meg vill. Unnskyld meg.,"Nie pytaj mnie, gdzie jesteśmy. Ja też się zgubiłem. Przepraszam.",Não me pergunte onde estamos. Já me perdi. Desculpe.,,"Numă întreba unde suntem, și eu sunt pierdut. Scuze.","Даже не спрашивай, где мы. Я сама не знаю, извини.",,Fråga mig inte var vi är. Jag är också vilse. Jag är också vilse.,Bana nerede olduğumuzu sorma. Ben de kayboldum. Özür dilerim. +That brick... Didn't we pass that brick? No...,TXT_SUB_LOG36,MAP06: Secret entrance from the castle.,,,Ta cihla... Neminuli jsme tamtu cihlu? Ne...,Den mursten... Har vi ikke passeret den mursten? Nej...,Der Stein... Sind wir nicht an dem Stein vorbeigekommen? Nein...,,,"Ese ladrillo... ¿No habíamos pasado ya por ese ladrillo? Ah, no...",,Tuo tiilenmurikka... Emmekö jo menneet sen ohitse? Ei kun...,Cette brique.. On n'a pas passé cette brique avant? Non..,Az a tégla...Nem hagytuk már el azt a téglát egyszer? Nem...,Quel mattone... Abbiamo già superato quel mattone? No...,あの煉瓦...前通ったレンガか?いや...,저 벽... 아까 저 벽을 지나가지 않았던가? 아닌데...,Die steen.... Hebben we die steen niet gepasseerd? Nee....,Den mursteinen... Passerte vi ikke den mursteinen? Nei...,Ta cegła... Czy nie minęliśmy tej cegły? Nie...,Aquele tijolo... Já não passamos daquele tijolo? Não...,,Cărpmida aceea... Nu am trecut de ea? Nu...,Этот кирпич... Разве мы здесь не были? Нет...,,Den där tegelstenen... Passerade vi inte den stenen? Nej...,Şu tuğla. O tuğlayı geçmemiş miydik? Hayır. +"Command, he's done it! The gates are open. Send in the shock troops and tell Macil we're coming in! ",TXT_SUB_LOG37,MAP06: After destroying the gate controls.,,,"Velení, dokázal to! Brány jsou otevřené. Pošlete tam úderníky a řekněte Macilovi, že přicházíme!","Kommando, han har gjort det! Portene er åbne. Send choktropperne ind og fortæl Macil, at vi kommer ind!",Kommandozentrale: Er hat's geschafft! Die Tore sind offen. Schickt die Schocktruppen hinein und sagt Macil das wir auf dem Weg sind! Lass uns zur Frontbasis zurückkehren.,,"Fronto, li sukcesis! Li malfermis la pordojn. Sendu la sturmantojn kaj diru al Macil, ke estas tempo eniri!","¡Comando, lo ha conseguido! Las puertas ya están abiertas. ¡Enviad a las tropas de choque y decidle a Macil que ya es hora de entrar!","¡Comando, lo logró! Las puertas ya están abiertas. ¡Manden a las tropas de choque y díganle a Macil que ya es hora de entrar!","Komentokeskus, hän teki sen! Portit ovat auki; lähettäkää iskujoukot ja kertokaa Macilille, että vyörymme sisään!","C'est bon, commandement, il a réussi! Les portes sont ouvertes, envoyez les soldats de choc et dites à Macil que l'on arrive!","Irányítás, sikerült neki! A kapuk nyitva állnak. Küldjétek be a sokkolós egységeket, és mondjátok meg Macilnak, hogy behatolunk!","Comando, ce l'ha fatta! I cancelli sono aperti. Mandate avanti le truppe e dite a Macil che stiamo arrivando!","司令官、彼はやったぞ! +ゲートが開いた。突撃部隊を送って我々も続くとマシルに伝えてくれ!","본부, 그가 해냈습니다! 성문이 열렸습니다. 공습부대를 성문으로 이동시키고 사령관님께 우리들도 따라올 거라고 전해주세요.","Commando, hij heeft het gedaan! De poorten zijn open. Stuur de stoottroepen naar binnen en zeg Macil dat we binnenkomen!","Kommando, han har klart det! Portene er åpne. Send inn sjokktroppene og si til Macil at vi kommer inn!","Dowództwo, on to zrobił! Brama jest otwarta. Wyślijcie oddziały uderzeniowe i powiedzcie Macilowi, że wchodzimy!","Comando, ele conseguiu! Os portões estão abertos. Enviem as tropas de choque e digam ao Macil que estamos entrando!",,"Centru, am reușit! Porțile sunt deschise. Trimite trupele de șoc si spune-i lui Macil că intrăm!","Штаб, он выполнил задание! Ворота открыты. Посылайте ударный отряд и доложите Мэйсилу, что мы пробились!",,"Kommando, han har gjort det! Portarna är öppna. Skicka in chocktrupperna och säg till Macil att vi kommer in!","Komuta, başardı! Kapılar açıldı. Şok birliklerini gönderin ve Macil'e geldiğimizi söyleyin!" +"We have conflicting reports about the Programmer's location. One say he's in a computer room, another that he's in a keep and yet another that mentions a long hallway. Sorry. ",TXT_SUB_LOG38,MAP07: Entrace.,,,"Máme rozcházející se zprávy o Programátorově pozici. Jedna mluví o místnosti s počítači, druhá, že je v nějaké pevnosti a třetí zmiňuje dlouhou chodbu. Promiň.","Vi har modstridende rapporter om programmørens placering. En siger, at han er i et computerrum, en anden, at han er i et tårn og endnu en anden, der nævner en lang gang. Undskyld.","Wir haben widersprüchliche Angaben über seinen Aufenthaltsort. Eine sagt, in einem Computerraum, ein anderer, dass er sich in einem Tempelkeller versteckt und noch ein anderer sagt was vom Ende eines langen Flurs.",,,"Tenemos informes contradictorios sobre la ubicación del Programador: uno dice que está en una sala de ordenadores, otro que está en un torreón y otro más menciona un pasillo largo. Perdón.","Tenemos informes contradictorios sobre la ubicación del Programador: uno dice que está en una sala de computadoras, otro que está en un torreón y otro más menciona un pasillo largo. Perdón.","Meillä eriäviä tietoja Ohjelmoitsijan sijainnista: Yhden mukaan hän on tietokonehuoneessa, toisen mukaan linnakkeessa ja vielä kolmas, joka mainitsee pitkän käytävän. Valitan.","On a des rapports contradictoires au sujet d'où se trouve le programmeur. On me dit d'un côté qu'il est dans une salle des ordinateurs, un autre me dit qu'il est dans un donjon, et un autre me dit qu'il est dans un long couloir.. Désolé.","Ellentmondásos jelentéseink vannak a Programozó hollétéről. Egy szerint a számítógép szobában van, másik szerint a vártoronyban, harmadik egy hosszú folyosót említ. Sajnálom.","I rapporti che abbiamo sulla sua posizione si contraddicono. Uno lo piazza in una stanza di computer, un altro in un tempio di sottolivello, e un altro ancora alla fine di un lungo corridoio.","プログラマーの居場所について矛盾する報告もあるわ。 ある人はコンピューター室にいる、別の人は保管室にいる、 -また別の人は長い廊下にいるとも言っていたわ。何とも言えない。","프로그래머의 위치에 관한 보고들이 전부 제각각이야. 하나는 컴퓨터실에, 또 하나는 성채에, 다른 하나는 긴 복도에 있대. 정말 유감이야.","We hebben tegenstrijdige berichten over de locatie van de programmeur. De een zegt dat hij in een computerkamer is, de ander dat hij in een donjon zit en weer een ander die een lange gang noemt. Sorry.",,"Temos relatos conflitantes sobre onde o Programador se encontra. Um deles diz que ele está na sala de informática, outro que ele está na fortaleza e outro diz que ele está no fim de um longo corredor. Desculpe.",,,"Наши сведения о местонахождении Программиста противоречивы. Одни говорят, что он в компьютерной комнате, другие, что он укрывается в цитадели, а третьи, что он в конце длинного коридора. Извини.", -"Ah, it's good to be on the offensive again. Give 'em hell, guys!",TXT_SUB_LOG39,STRIFE1.WAD: MAP07,,,"Á, je to fajn být zase na straně ofenzívy. Jen jim dejte, chlapi!","Ah, es ist gut, wieder in der Offensive zu sein. Macht sie fertig, Leute!",,,"Ah, sienta bien estar a la ofensiva de nuevo. ¡Dadles caña, chicos!",,,"Ah, ça fait du bien d'être sur l'offensive une fois de plus! Foutez leur la misère, les gars!",,,再襲撃するには良い機会だ。地獄に送ってやれ、皆!,"아, 이렇게 다시 공격적으로 나가니 좋다. 맛 좀 보여줘, 얘들아!","Ah, het is goed om weer in de aanval te zijn. Geef ze de hel, jongens!",,"Ah, é bom estar na ofensiva mais uma vez. Chumbo neles, pessoal!",,,"Наконец-то, мы снова переходим в наступление! Всыпьте им как следует, парни!", -This looks good. Computers... Programmer... What do you think?,TXT_SUB_LOG40,STRIFE1.WAD: MAP07,,,Tohle vypadá dobře. Počítače... Programátor... Co myslíš?,Das sieht gut aus. Computer... Programmierer... Was denkst du?,,,Esto pinta bien. Computadoras... Programador... ¿Tú que crees?,,,"Tout à l'air bien. Ordinateurs, Programmeur, tu en pense quoi?",,,"これは良い。コンピューター... -プログラマー...アンタはどう思う?",이거 괜찮아 보이네. 컴퓨터들과... 프로그래머... 어떻게 생각해?,Dit ziet er goed uit. Computers.... Programmeur.... Wat vind je ervan?,,Isto parece bom. Computadores... Programador... O que você acha?,,,"Похоже, это здесь. Компьютеры… Программист… Что скажешь?", -This must be the long hallway. Either that or my sense of scale is shot to hell.,TXT_SUB_LOG41,STRIFE1.WAD: MAP07,,,"Tohle musí být ta dlouhá chodba. Buď, a nebo už špatně vidím.","Das muss der lange Flur sein. Entweder das, oder mein Sinn für Größe ist nicht in Ordnung.",,,Este debe ser el pasillo largo. O es eso o mi sentido de la escala está fastidiado.,,,"Ca doit être le long couloir, ça où ma perception des choses est un peu foutue..",,,この長い廊下に違いない。それか私のスケール感とどちらかが撃ち落されるな。,"여기가 바로 긴 복도겠네. 아주 길다고 생각해, 아니면 내 머리가 이상하겠지.",Dit moet de lange gang zijn. Of dat of mijn gevoel voor schaalvergroting is naar de hel geschoten.,,Esse deve ser o longo corredor. Ou isso ou o meu senso de escala foi pro saco.,,,"Должно быть, длинный коридор — это здесь. Ну или у меня всё плохо с глазомером.", -"This is all the hallmarks of a temple of evil. Severe architecture, big banner... I'd say bingo!",TXT_SUB_LOG42,STRIFE1.WAD: MAP07,,,"Tohle jsou všechno puncy chrámu zla - hrubá architektura, velký prapor... řekla bych, že bingo!","Das sind alles die Zeichen für einen Tempel des Bösen. Strenge Architektur, große Banner... Ich würde sagen: „Bingo!“",,,"Esto tiene toda la pinta de un templo maligno. Arquitectura austera, gran estandarte... ¡Yo diría bingo!",,,"Ca a le décor d'un temple maléfique.. Architecture sinistre, énorme bannière, je dis bingo!",,,"これら全部悪の神殿の特徴だ。重苦しい建築物、デカいバナー... -ビンゴだわ!","악당 같은 요소가 모인 건물이네! 엄격한 건물 구조, 커다란 기... 완전 만장일치야.","Dit zijn alle kenmerken van een tempel van het kwaad. Strenge architectuur, grote spandoeken.... Ik zou zeggen bingo!",,"Isso tem bem cara de templo malígno. Arquitetura sinístra, estandarte grande... Acho que acertamos na mosca!",,,"Всё это очень похоже на зловещий храм. Строгая архитектура, огромное знамя... Да, это определённо он!", -This is the almighty Programmer? No way!,TXT_SUB_LOG43,,,,Tohle je ten všemocný Programátor? To není možné!,Das ist der allmächtige Programmierer? Niemals!,,,¿Este es el todopoderoso Programador? ¡Ni hablar!,,,Ca c'est le surpuissant Programmeur? Vraiment?,,,,저게 위대한 프로그래머라고? 말도 안 돼!,Dit is de almachtige programmeur? Echt niet!,,Esse é o Programador todo-poderoso? Tá de sacanagem comigo!,,,Вот это — всемогущий Программист? Быть не может!, -"I don't know what to believe anymore. The only thing that says ""keep"" to me is that huge monstrosity to the left. But I have no idea how to get in. ",TXT_SUB_LOG44,,,,"Už nevím, čemu věřit. Jediné, co mi říká „pevnost“, je tamta obří hrůza nalevo. Ale nemám tušení, jak se dostat dovnitř.","Ich weiß nicht mehr, was ich glauben soll. Das einzige, was ein „Tempel“ sein könnte, ist diese riesige Monströsität da drüben links. Aber ich wüßte nicht wie wir da rein kämen. ",,,"Ya no sé lo que creer. Lo único que me dice ""torreón"" es esa monstruosidad enorme a la izquierda. Pero no tengo ni idea de como entrar.",,,"Je ne sais pas quoi penser maintenant. Le seul truc qui sonne comme ""donjon"" pour moi c'est l'énorme monstrosité à gauche, mais je ne sais pas comment y entrer.",,,,이젠 누가 맞는 건지 생각이 전혀 안나. “성채”라고 말하는 곳은 분명히 저 왼쪽에 있는 커다란 건물일 거야. 그런데 그곳으로 어떻게 들어가야 하지?,"Ik weet niet meer wat ik moet geloven. Het enige dat tegen mij zegt ""houd"" is dat grote gedrocht aan de linkerkant. Maar ik heb geen idee hoe ik binnen kan komen.",,Eu não sei mais no que acreditar. A única coisa que parece uma fortaleza pra mim é aquela monstrosidade à esquerda. Mas não faço a menor idéia de como entrar.,,,"Не знаю, кому и верить. По-моему, «Цитаделью» можно назвать только ту уродливую громадину слева. Но как туда попасть, я понятия не имею.", -"When the going gets weird, the weird get going. Watch yourself.",TXT_SUB_LOG45,"STRIFE1.WAD: MAP09 - -(Appears to be a reference to Hunter S. Thompson’s quote, “When the going gets weird, the weird turn pro.”)",,,"Když to chce jít divně, divno jde dál. Dávej si na sebe pozor.",Die ganze Sache kommt mir spanisch vor. Pass auf dich auf.,,,La cosa se está poniendo fea. Ten cuidado.,,,"Quand les choses tournent au pire, le pire se tourne vers nous.. Fais attention à toi.",,,怪しい状況では怪しい影が映る。気を付けて。,"상황이 이상해지면, 이상한 일이 계속 일어난다니까... 부디 조심해.","Als het gaat raar wordt, gaat het vreemde aan de slag. Kijk uit.",,A coisa tá ficando feia. Toma cuidado.,,,"Если видишь, что что-то не так, остановись и подумай. Будь осторожен.", -"The Oracle resides in the borderlands, just outside of town. Cross the river, head towards the castle and go left through the archway.",TXT_SUB_LOG46,,,,"Věštec přebývá v pohraničí, hned za městem. Překroč řeku, zamiř k hradu a jdi vlevo pod obloukem.","Das Orakel hält sich in den Grenzgebieten auf, direkt vor der Stadt. Überquere den Fluss, gehe in Richtung Burg und dann links durchs Tor.",,,"El Oráculo reside en las fronteras, justo fuera del pueblo. Cruza el río, dirígete al castillo y ve a la izquierda a través del arco.",,,"L'Oracle se trouve dans les terrains vagues, à l'extérieur de la ville. Traverse la rivière, va vers le château et à gauche à travers l'arche.",,,,"오라클은 도시 외곽에 있는 접경지 근처에 있어. 강을 넘은 뒤, 성 쪽으로 향하고 아치 밑의 통로를 통해 왼쪽으로 이동해.","Het Orakel woont in de grensgebieden, net buiten de stad. Steek de rivier over, ga naar het kasteel en ga linksaf door de poort.",,"O Oráculo reside nas fronteiras do lado de fora da cidade. Atravesse o rio, vá em direção ao catelo e vá para a esquerda através do arco.",,,"Резиденция Оракула находится в пограничье, сразу за городской чертой. Пересеки реку, иди в сторону крепости и сверни налево, пройдя через арку.", -The Oracle is a supposedly sympathetic high priest who operates outside the Order.,TXT_SUB_LOG47,STRIFE1.WAD: MAP02,,,"Věštec je údajně sympatizující velekněz, operující mimo samotný Řád.","Das Orakel ist ein angeblich verständnisvoller Hohepriester, der außerhalb des Ordens tätig ist.",,,El Oráculo es supuestamente un amable alto sacerdote que opera fuera de la Orden.,,,L'Oracle est supposément un grand prêtre bienveillant qui opère hors du domaine de l'Ordre.,,,オラクルはオーダーとは別の活動をしている同情的な大司祭よ。,"오라클은 인류에 동정을 가지고 있다고 하고, 오더의 바깥에서 활동하는 대사제야.",Het Orakel is een zogenaamd sympathieke hogepriester die buiten de Orde opereert.,,O Oráculo é supostamente um grande sacerdote benevolente que opera fora da Ordem.,,,"Похоже, этот Оракул — сочувствующий Сопротивлению верховный жрец, который действует без ведома Ордена.", -"The Oracle's temple is in the Borderlands, on the outskirts of town.",TXT_SUB_LOG48,STRIFE1.WAD: MAP10,,,"Věštcův chrám je v pohraničí, na okraji města.","Der Tempel des Orakels ist in den Grenzgebieten, direkt vor der Stadt.",,,"El templo del Oráculo está en las Fronteras, a las afueras del pueblo.",,,Le temple de l'Oracle se trouve dans les terrains vagues à l'extérieur de la ville.,,,オラクルの寺院は町の郊外にある国境地帯の西側にあるわ。,오라클은 도시 외곽에 있는 접경지 근처에 있어.,"De tempel van het Orakel staat in de grensstreek van Nederland, aan de rand van de stad.",,"O tempo do Oráculo está nas fronteiras, fora da cidade.",,,"Храм Оракула находится в пограничье, на окраине города.", -The Order has taken our beautiful planet and turned it into a dump.,TXT_SUB_LOG49,STRIFE1.WAD: MAP11,,,Řád vzal naši krásnou planetu a proměnil ji ve skládku.,Der Orden hat unseren schönen Planeten in einen Müllplatz verwandelt.,,,La Orden ha tomado nuestro bello planeta y lo ha convertido en un vertedero.,,,L'Ordre a pris notre belle planète et la transformée en dépotoir.,,,オーダーは我々の立つこの惑星を奪い、それをゴミへと変えた。,오더가 이 이쁘고 푸른 행성을 완전 쓰레기장으로 만들어버렸어...,De Orde heeft onze mooie planeet in beslag genomen en er een vuilnisbelt van gemaakt.,,A Ordem transformou este lindo planeta em um depósito de lixo.,,,Орден превратил нашу прекрасную планету в помойку., -"Here it is. I'm recording everything, it's not that I don't have faith that you'll survive, it's just that we can't let the Order control the Sigil.",TXT_SUB_LOG50,STRIFE1.WAD: MAP11,,,"Tady to je. Všechno nahrávám, ne že bych neměla důvěru v tvé přežití, ale prostě nemůžeme dovolit Řádu ovládat Pečeť.","Hier ist es. Ich zeichne alles auf, nicht dass ich kein Vertrauen in dich habe, aber wir können nicht erlauben, dass der Orden das Sigil kontrolliert.",,,"Aquí está. Lo estoy grabando todo, no es que tenga fe en que sobrevivas, es solo que no puedo dejar que la Orden controle el Emblema.",,,"Voilà, j'enregistre tout. C'est pas qu'on a pas confiance en toi, c'est juste que on ne peut pas laisser l'Ordre contrôler le Sigil.",,,"ここよ。私は全て記録している、貴方が生き残れる可能性が無いわけではなく、 -オーダー如きにシジルを制御できるわけがないという事だ。","여기야. 난 지금 모든 걸 녹음하고 있어. 네가 살아남을 거라는 믿음을 버린게 아니라, 오더가 시질을 손에 잡게 내버려 둘 수가 없어서 말이야.","Hier is het. Ik ben alles aan het opnemen, het is niet dat ik geen vertrouwen heb dat je het zult overleven, maar het is gewoon dat we de Orde de Sigil niet kunnen laten controleren door de Orde.",,"Certo, estou gravando tudo. Não é que eu não tenha fé de que você vá sobreviver, mas não podemos deixar a Ordem controlar o Sigilo.",,,"Так. Я всё записываю на плёнку. Это не потому, что я не верю, что ты уцелеешь. Просто мы не можем позволить Ордену заполучить Сигил.", -"You are brave, my comrade. I'm proud to be along for the ride.",TXT_SUB_LOG51,STRIFE1.WAD: MAP12,,,"Jsi statečný, můj příteli. Jsem pyšná, že u tohohle můžu být.","Du bist tapfer, mein Kamerad. Ich bin stolz darauf, mit von der Partie zu sein.",,,"Eres valiente, mi camarada. Estoy orgullosa de acompañarte.",,,"Tu est courageux, mon camarade, je suis fière de te suivre.",,,貴方は勇敢で、私の同志。貴方に就けた事を私は誇りに思ってるわ。,"넌 정말 용맹해, 동지. 너랑 같이 일할 수 있는 게 정말 자랑스러워.","Je bent dapper, mijn kameraad. Ik ben er trots op dat ik meega voor de rit.",,"Você é corajoso, meu companheiro. Tenho orgulho de estar junto com você.",,,"Я хотела сказать тебе, что ты очень храбрый. Я так счастлива, что мне с тобой по пути.", +また別の人は長い廊下にいるとも言っていたわ。何とも言えない。","프로그래머의 위치에 관한 보고들이 전부 제각각이야. 하나는 컴퓨터실에, 또 하나는 성채에, 다른 하나는 긴 복도에 있대. 정말 유감이야.","We hebben tegenstrijdige berichten over de locatie van de programmeur. De een zegt dat hij in een computerkamer is, de ander dat hij in een donjon zit en weer een ander die een lange gang noemt. Sorry.","Vi har motstridende rapporter om hvor programmereren befinner seg. En sier at han er i et datarom, en annen at han er i en borg og en tredje nevner en lang korridor. Unnskyld.","Mamy sprzeczne raporty na temat lokalizacji Programisty. Jeden mówi, że jest w sali komputerowej, inny, że w magazynie, a jeszcze inny, że wspomina o długim korytarzu. Przepraszam.","Temos relatos conflitantes sobre onde o Programador se encontra. Um deles diz que ele está na sala de informática, outro que ele está na fortaleza e outro diz que ele está no fim de um longo corredor. Desculpe.",,"Avem rapoarte conflictuale în privința locației Programatorului. Unul zice că e într-o sală de calculatoare, altul într-o curte, iar altul că e intr-un hol lung. Scuze.","Наши сведения о местонахождении Программиста противоречивы. Одни говорят, что он в компьютерной комнате, другие, что он укрывается в цитадели, а третьи, что он в конце длинного коридора. Извини.",,"Vi har motstridiga rapporter om var programmeraren befinner sig. En säger att han är i ett datorrum, en annan att han är i ett torn och ytterligare en annan nämner en lång korridor. Jag är ledsen.","Programcının yeri hakkında çelişkili raporlarımız var. Biri bir bilgisayar odasında olduğunu söylüyor, diğeri bir mahzende ve bir başkası da uzun bir koridordan bahsediyor. Özür dilerim." +"Ah, it's good to be on the offensive again. Give 'em hell, guys!",TXT_SUB_LOG39,MAP07: Near the crusaders.,,,"Á, je to fajn být zase na straně ofenzívy. Jen jim dejte, chlapi!","Ah, det er godt at være i offensiven igen. Giv dem en røvfuld, gutter!","Ah, es ist gut, wieder in der Offensive zu sein. Macht sie fertig, Leute!",,,"Ah, sienta bien estar a la ofensiva de nuevo. ¡Dadles caña, chicos!",,"Aah, tekeepä hyvää olla taas vaihteeksi hyökkäävänä osapuolena. Hakkaa päälle, pojat!","Ah, ça fait du bien d'être sur l'offensive une fois de plus! Foutez leur la misère, les gars!","Áh, jó újra támadásba lendülni. Leckéztessétek meg őket!","Ah, che bello essere di nuovo all'offensiva! Mostrategli la via per l'inferno, ragazzi!",再襲撃するには良い機会だ。地獄に送ってやれ、皆!,"아, 이렇게 다시 공격적으로 나가니 좋다. 맛 좀 보여줘, 얘들아!","Ah, het is goed om weer in de aanval te zijn. Geef ze de hel, jongens!","Ah, det er godt å være på offensiven igjen. Gi dem helvete, folkens!","Dobrze jest być znowu w ofensywie. Zróbcie im piekło, chłopaki!","Ah, é bom estar na ofensiva mais uma vez. Chumbo neles, pessoal!",,"Ah, e bine că mă regăsesc din nou pe partea ofensivă. Dați-le bătaie!","Наконец-то, мы снова переходим в наступление! Всыпьте им как следует, парни!",,"Ah, det är skönt att vara på offensiven igen. Ge dem ett helvete, killar!",Tekrar saldırıya geçmek güzel. Canlarına okuyun çocuklar! +This looks good. Computers... Programmer... What do you think?,TXT_SUB_LOG40,MAP07: Computer room.,,,Tohle vypadá dobře. Počítače... Programátor... Co myslíš?,Det ser godt ud. Computere... Programmør... Hvad synes du?,Das sieht gut aus. Computer... Programmierer... Was denkst du?,,,Esto pinta bien. Computadoras... Programador... ¿Tú que crees?,,"Tämä näyttää hyvältä. Tietokoneita, ohjelmoitsija... Mitä tuumit?","Tout à l'air bien. Ordinateurs, Programmeur, tu en pense quoi?",Ez jól néz ki. Számítógépek... Programozó... Mit gondolsz?,Promette bene. Computer... Programmatore... Che ne pensi?,"これは良い。コンピューター... +プログラマー...アンタはどう思う?",이거 괜찮아 보이네. 컴퓨터들과... 프로그래머... 어떻게 생각해?,Dit ziet er goed uit. Computers.... Programmeur.... Wat vind je ervan?,Dette ser bra ut. Datamaskiner... Programmerer... Hva syns du?,To wygląda dobrze. Komputery... Programista... Co o tym sądzisz?,Isto parece bom. Computadores... Programador... O que você acha?,,Arată bine. Calculatoare... Programator... Ce zici?,"Похоже, это здесь. Компьютеры... Программист... Что скажешь?",,Det här ser bra ut. Datorer... Programmerare... Vad tycker du?,Bu iyi görünüyor. Bilgisayarlar. Programcı. Ne düşünüyorsun? +This must be the long hallway. Either that or my sense of scale is shot to hell.,TXT_SUB_LOG41,MAP07: Building before the brigde.,,,"Tohle musí být ta dlouhá chodba. Buď, a nebo už špatně vidím.","Dette må være den lange gang. Enten det, eller også er min fornemmelse for skalaer skudt ad helvede til.","Das muss der lange Flur sein. Entweder das, oder mein Sinn für Größe ist nicht in Ordnung.",,,Este debe ser el pasillo largo. O es eso o mi sentido de la escala está fastidiado.,,"Tämä on varmaankin se pitkä käytävä. Joko niin, tai sitten olen ihan pihalla mittasuhteista.","Ca doit être le long couloir, ça où ma perception des choses est un peu foutue..","Ez lehet a hosszú folyosó. Vagy ez, vagy a térérzékem tropára ment.",Questo deve essere il lungo corridoio. Oppure il mio senso della prospettiva è proprio andato a farsi benedire.,この長い廊下に違いない。それか私のスケール感とどちらかが撃ち落されるな。,"여기가 바로 긴 복도겠네. 아주 길다고 생각해, 아니면 내 머리가 이상하겠지.",Dit moet de lange gang zijn. Of dat of mijn gevoel voor schaalvergroting is naar de hel geschoten.,"Dette må være den lange gangen. Enten det, eller så er målestokkfølelsen min ødelagt.","To musi być ten długi korytarz. Albo to, albo moje wyczucie skali jest do dupy.",Esse deve ser o longo corredor. Ou isso ou o meu senso de escala foi pro saco.,,"Ăsta trebuie să fie holul lung. Fie asta, fie capacitatea mea de a aprecia scara e varză.","Должно быть, длинный коридор — это здесь. Ну или у меня всё плохо с глазомером.",,Det här måste vara den långa korridoren. Antingen det eller så är min skalförståelse helt borta.,Burası uzun koridor olmalı. Ya öyle ya da benim ölçek algım cehenneme döndü. +"This is all the hallmarks of a temple of evil. Severe architecture, big banner... I'd say bingo!",TXT_SUB_LOG42,MAP07: Northeast bulding.,,,"Tohle jsou všechno puncy chrámu zla - hrubá architektura, velký prapor... řekla bych, že bingo!","Dette er alle kendetegnene på et ondskabens tempel. Alvorlig arkitektur, stort banner... Jeg ville sige bingo!","Das sind alles die Zeichen für einen Tempel des Bösen. Strenge Architektur, große Banner... Ich würde sagen: „Bingo!“",,,"Esto tiene toda la pinta de un templo maligno. Arquitectura austera, gran estandarte... ¡Yo diría bingo!",,"Tämä täyttää pahuuden temppelin kaikki tunnusmerkit: tuima arkkitehtuuri, suuri tunnuslippu... Sanoisin, että bingo!","Ca a le décor d'un temple maléfique.. Architecture sinistre, énorme bannière, je dis bingo!","Ha gonosz templom lennék, így néznék ki. Kimért architektúra, óriási lobogó... amondó vagyok megleltük.","Questo ha proprio tutti i tratti di un tempio del male. Architettura minacciosa, grosso stemma... Io direi che abbiamo fatto centro!","これら全部悪の神殿の特徴だ。重苦しい建築物、デカいバナー... +ビンゴだわ!","악당 같은 요소가 모인 건물이네! 엄격한 건물 구조, 커다란 기... 완전 만장일치야.","Dit zijn alle kenmerken van een tempel van het kwaad. Strenge architectuur, grote spandoeken.... Ik zou zeggen bingo!","Dette er alle kjennetegnene på et ondskapens tempel. Streng arkitektur, stort banner... Jeg vil si bingo!","To wszystko ma znamiona świątyni zła. Surowa architektura, wielki baner... Powiedziałbym, że bingo!","Isso tem bem cara de templo malígno. Arquitetura sinístra, estandarte grande... Acho que acertamos na mosca!",,"Ăsta e însemnul unui templu malefic. Arhitectura, steagurile... Eu zic bingo!","Всё это очень похоже на зловещий храм. Строгая архитектура, огромное знамя... Да, это определённо он!",,"Det här har alla kännetecken på ett ondskans tempel. Stark arkitektur, stora banderoller... Jag skulle säga bingo!","Burası bir şeytan tapınağının tüm özelliklerini taşıyor. Sert mimari, büyük afiş. Bingo derdim!" +This is the almighty Programmer? No way!,TXT_SUB_LOG43,,,,Tohle je ten všemocný Programátor? To není možné!,Er dette den almægtige programmør? Det kan ikke passe!,Das ist der allmächtige Programmierer? Niemals!,,,¿Este es el todopoderoso Programador? ¡Ni hablar!,,Tämäkö muka kaikkivoipa Ohjelmoitsija? Ei todellakaan!,Ca c'est le surpuissant Programmeur? Vraiment?,Ez a hírhedt Progamozó? Nincs az az isten!,Sarebbe questo il potente Programmatore? Non è possibile!,,저게 위대한 프로그래머라고? 말도 안 돼!,Dit is de almachtige programmeur? Echt niet!,Er dette den allmektige programmereren? Aldri i livet!,To jest wszechmocny Programista? Nie ma mowy!,Esse é o Programador todo-poderoso? Tá de sacanagem comigo!,,Ăsta e marele Programator? Nici vorbă!,Вот это — всемогущий Программист? Быть не может!,,Är detta den allsmäktige programmeraren? Inte en chans!,Bu yüce Programcı mı? Yok artık! +"I don't know what to believe anymore. The only thing that says ""keep"" to me is that huge monstrosity to the left. But I have no idea how to get in. ",TXT_SUB_LOG44,,,,"Už nevím, čemu věřit. Jediné, co mi říká „pevnost“, je tamta obří hrůza nalevo. Ale nemám tušení, jak se dostat dovnitř.","Jeg ved ikke længere, hvad jeg skal tro. Det eneste, der siger mig ""beholde"", er det store uhyre til venstre. Men jeg har ingen idé om, hvordan jeg kommer ind.","Ich weiß nicht mehr, was ich glauben soll. Das einzige, was ein „Tempel“ sein könnte, ist diese riesige Monströsität da drüben links. Aber ich wüßte nicht wie wir da rein kämen. ",,,"Ya no sé qué creer. Lo único que me dice ""torreón"" es esa monstruosidad enorme a la izquierda. Pero no tengo ni idea de como entrar.",,"En tiedä enää, mitä uskoa. Ainoa asia, joka näyttäytyy minulle ""linnakkeena"", on tuo valtava rumilus vasemmalla. Mutta minulla ei ole aavistustakaan, miten päästä sisään.","Je ne sais pas quoi penser maintenant. Le seul truc qui sonne comme ""donjon"" pour moi c'est l'énorme monstrosité à gauche, mais je ne sais pas comment y entrer.",Nem tudom mit kéne hinnem már. Az egyetlen vártorony szerűség a bal oldalt levő szörnyűség. Ötletem sincs hogy juthatnánk be.,"Non so più a cosa credere. L'unica cosa che mi dice ""fortezza"" è quell'enorme mostruosità alla sinistra, ma non so come entrarvi.",,이젠 누가 맞는 건지 생각이 전혀 안나. “성채”라고 말하는 곳은 분명히 저 왼쪽에 있는 커다란 건물일 거야. 그런데 그곳으로 어떻게 들어가야 하지?,"Ik weet niet meer wat ik moet geloven. Het enige dat tegen mij zegt ""houd"" is dat grote gedrocht aan de linkerkant. Maar ik heb geen idee hoe ik binnen kan komen.","Jeg vet ikke hva jeg skal tro lenger. Det eneste som sier ""hold"" til meg er den enorme monstrøsiteten til venstre. Men jeg aner ikke hvordan jeg skal komme meg inn.","Już nie wiem, w co wierzyć. Jedyne co mówi mi ""trzymaj"" to ta ogromna potworność po lewej stronie. Ale nie mam pojęcia, jak się tam dostać.",Eu não sei mais no que acreditar. A única coisa que parece uma fortaleza pra mim é aquela monstrosidade à esquerda. Mas não faço a menor idéia de como entrar.,,"Nu știu ce să mai cred. Singurul lucru care îmi spune ""curte"" e acea monstruozitate la stânga. Dar n-am idee cum să intrăm.","Не знаю, кому и верить. По-моему, «Цитаделью» можно назвать только ту уродливую громадину слева. Но как туда попасть, я понятия не имею.",,"Jag vet inte vad jag ska tro längre. Det enda som säger ""behåll"" för mig är det enorma monstret till vänster. Men jag har ingen aning om hur jag ska ta mig in.","Artık neye inanacağımı bilmiyorum. Bana ""kalsın"" diyen tek şey soldaki devasa canavar. Ama nasıl gireceğimi bilmiyorum." +"When the going gets weird, the weird get going. Watch yourself.",TXT_SUB_LOG45,"MAP09: Entrance. +(Probably a reference to Hunter S. Thompson’s quote, “When the going gets weird, the weird turn pro.”)",,,Divné klima lahodí podivínům. Dávej si na sebe pozor.,"Når det bliver mærkeligt, så bliver det mærkelige også mærkeligt. Pas på dig selv.",Die ganze Sache kommt mir spanisch vor. Pass auf dich auf.,,,La cosa se está poniendo fea. Ten cuidado.,Esto se va a poner feo. Ve con cuidado.,"Kun meininki muuttuu kummaksi, kummat alkavat meinata. Pidä varasi.","Quand les choses tournent au pire, le pire se tourne vers nous.. Fais attention à toi.",Egy fura világban furának kell lenned. Vigyázz magadra.,"Quando il gioco si fa strano, quelli strani si mettono in gioco. Fai attenzione.",怪しい状況では怪しい影が映る。気を付けて。,"상황이 이상해지면, 이상한 일이 계속 일어난다니까... 부디 조심해.","Als het gaat raar wordt, gaat het vreemde aan de slag. Kijk uit.","Når det blir merkelig, blir det merkelige merkelig. Vær forsiktig.","Kiedy robi się dziwnie, dziwacy zaczynają się ruszać. Uważaj na siebie.",A coisa tá ficando feia. Toma cuidado.,,"Cand lucrurile devin ciudate, ai grija.","Если видишь, что что-то не так, остановись и подумай. Будь осторожен.",,"När det blir konstigt, blir det konstiga som går. Se upp för dig själv.","İşler garipleştiğinde, garipler de gider. Kendine dikkat et." +"The Oracle resides in the borderlands, just outside of town. Cross the river, head towards the castle and go left through the archway.",TXT_SUB_LOG46,,,,"Věštec přebývá v pohraničí, hned za městem. Překroč řeku, zamiř k hradu a jdi vlevo pod obloukem.","Oraklet befinder sig i grænselandet, lige uden for byen. Kryds floden, gå mod slottet og gå til venstre gennem buegangen.","Das Orakel hält sich in den Grenzgebieten auf, direkt vor der Stadt. Überquere den Fluss, gehe in Richtung Burg und dann links durchs Tor.",,,"El Oráculo reside en las fronteras, justo fuera del pueblo. Cruza el río, dirígete al castillo y ve a la izquierda a través del arco.",,"Oraakkeli asuu rajamailla aivan kaupungin liepeillä. Ylitä joki, kulje kohti linnaa ja mene vasemmalle kaarikäytävän läpi.","L'Oracle se trouve dans les terrains vagues, à l'extérieur de la ville. Traverse la rivière, va vers le château et à gauche à travers l'arche.","Az Orákulum a peremvidéken tartózkodik, rögtön a városhatárokon túl. Elhagyva a folyót, menj a kastély irányába és fordulj balra a boltívnél.","L'Oracolo risiede nelle terre di confine, subito dopo la città. Attraversa il fiume, vai nella direzione del castello e poi a sinistra oltre l'arco.",,"오라클은 도시 외곽에 있는 접경지 근처에 있어. 강을 넘은 뒤, 성 쪽으로 향하고 아치 밑의 통로를 통해 왼쪽으로 이동해.","Het Orakel woont in de grensgebieden, net buiten de stad. Steek de rivier over, ga naar het kasteel en ga linksaf door de poort.","Orakelet ligger i grenselandet, like utenfor byen. Kryss elven, gå mot slottet og gå til venstre gjennom buegangen.","Wyrocznia mieszka na pograniczu, tuż za miastem. Przejdź przez rzekę, skieruj się w stronę zamku i przejdź w lewo przez łuki.","O Oráculo reside nas fronteiras do lado de fora da cidade. Atravesse o rio, vá em direção ao catelo e vá para a esquerda através do arco.",,"Oracolul locuiește în mărginime, chiar la ieșirea orașului. Treci râul, du-te spre castle, și treci prin arcadă.","Резиденция Оракула находится в пограничье, сразу за городской чертой. Пересеки реку, иди в сторону крепости и сверни налево, пройдя через арку.",,"Oraklet bor i gränslandet, strax utanför staden. Korsa floden, gå mot slottet och gå till vänster genom valvet.","Kahin, kasabanın hemen dışındaki sınır bölgesinde bulunuyor. Nehri geç, kaleye doğru git ve kemerden sola dön." +The Oracle is a supposedly sympathetic high priest who operates outside the Order.,TXT_SUB_LOG47,MAP02: Castle's entrance (MAP10).,,,"Věštec je údajně sympatizující velekněz, operující mimo samotný Řád.","Oraklet er en formodet sympatisk ypperstepræst, der opererer uden for ordenen.","Das Orakel ist ein angeblich verständnisvoller Hohepriester, der außerhalb des Ordens tätig ist.",,,El Oráculo es supuestamente un amable alto sacerdote que opera fuera de la Orden.,,"Oraakkeli on tiettävästi aatteellemme myötämielinen ylipappi, joka toimii Veljeskunnan vaikutuspiirin ulkopuolella.",L'Oracle est supposément un grand prêtre bienveillant qui opère hors du domaine de l'Ordre.,"Az Orákulum állítólag egy megértő főpap, aki nem tartozik a Rend rendjéhez.",L'Oracolo è un alto sacerdote apparentemente approciabile che opera al di fuori dell'Ordine.,オラクルはオーダーとは別の活動をしている同情的な大司祭よ。,"오라클은 인류에 동정을 가지고 있다고 하고, 오더의 바깥에서 활동하는 대사제야.",Het Orakel is een zogenaamd sympathieke hogepriester die buiten de Orde opereert.,Oraklet er en angivelig sympatisk yppersteprest som opererer utenfor ordenen.,"Wyrocznia jest rzekomo sympatycznym arcykapłanem, który działa poza Zakonem.",O Oráculo é supostamente um grande sacerdote benevolente que opera fora da Ordem.,,"Oracolul e un preot care simpatizează cu noi, și care se spune că operează din afara Ordinului.","Похоже, этот Оракул — сочувствующий Сопротивлению верховный жрец, который действует без ведома Ордена.",,Oraklet är en förmodat sympatisk överstepräst som verkar utanför orden.,"Kahin, Düzen'in dışında faaliyet gösteren sözde sempatik bir baş rahiptir." +"The Oracle's temple is in the Borderlands, on the outskirts of town.",TXT_SUB_LOG48,MAP10: After talking to Macil and moving a bit.,,,"Věštcův chrám je v pohraničí, na okraji města.","Oraklets tempel ligger i grænselandet, i udkanten af byen.","Der Tempel des Orakels ist in den Grenzgebieten, direkt vor der Stadt.",,,"El templo del Oráculo está en las Fronteras, a las afueras del pueblo.",,Oraakkelin temppeli sijaitsee rajaseudulla kaupungin laitamilla.,Le temple de l'Oracle se trouve dans les terrains vagues à l'extérieur de la ville.,Az Orákulum temploma a határvidéken található a külvárosban.,"Il tempio dell'Oracolo è nelle terre di confine, fuori città.",オラクルの寺院は町の郊外にある国境地帯の西側にあるわ。,오라클은 도시 외곽에 있는 접경지 근처에 있어.,"De tempel van het Orakel staat in de grensstreek van Nederland, aan de rand van de stad.","Orakelets tempel ligger i Grenselandene, i utkanten av byen.","Świątynia Wyroczni znajduje się na Kresach, na obrzeżach miasta.","O tempo do Oráculo está nas fronteiras, fora da cidade.",,"Templul Oracolului e în Mărginime, la ieșirea din oraș.","Храм Оракула находится в пограничье, на окраине города.",,"Oraklets tempel ligger i gränslandet, i utkanten av staden.","Kahin'in tapınağı Sınır Toprakları'nda, şehrin eteklerinde." +The Order has taken our beautiful planet and turned it into a dump.,TXT_SUB_LOG49,MAP11: Entrance.,,,Řád vzal naši krásnou planetu a proměnil ji ve skládku.,Ordenen har taget vores smukke planet og forvandlet den til en losseplads.,Der Orden hat unseren schönen Planeten in einen Müllplatz verwandelt.,,,La Orden ha tomado nuestro bello planeta y lo ha convertido en un vertedero.,,Veljeskunta on riistänyt planeettamme ja tehnyt siitä kaatopaikan.,L'Ordre a pris notre belle planète et la transformée en dépotoir.,"A Rend kizsigerelte ezt a gyönyörű bolygót, és egy lepratelepet csinált belőle.",L'Ordine ha preso il nostro bellissimo pianeta e l'ha trasformato in una discarica.,オーダーは我々の立つこの惑星を奪い、それをゴミへと変えた。,오더가 이 이쁘고 푸른 행성을 완전 쓰레기장으로 만들어버렸어...,De Orde heeft onze mooie planeet in beslag genomen en er een vuilnisbelt van gemaakt.,Ordenen har tatt vår vakre planet og gjort den til en søppelplass.,Zakon zabrał naszą piękną planetę i zamienił ją w wysypisko śmieci.,A Ordem transformou este lindo planeta em um depósito de lixo.,,Ordinul ne-a luat planeta minunată și a transformat-o într-o groapă de gunoi.,Орден превратил нашу прекрасную планету в помойку.,,Orden har tagit vår vackra planet och förvandlat den till en soptipp.,Tarikat güzel gezegenimizi aldı ve onu bir çöplüğe çevirdi. +"Here it is. I'm recording everything, it's not that I don't have faith that you'll survive, it's just that we can't let the Order control the Sigil.",TXT_SUB_LOG50,MAP11: Entrance to cave.,,,"Tady to je. Všechno nahrávám, ne že bych neměla důvěru v tvé přežití, ale prostě nemůžeme dovolit Řádu ovládat Pečeť.","Her er den. Jeg optager alt, det er ikke fordi jeg ikke tror på, at I vil overleve, men vi kan ikke lade Ordenen kontrollere Sigil.","Hier ist es. Ich zeichne alles auf, nicht dass ich kein Vertrauen in dich habe, aber wir können nicht erlauben, dass der Orden das Sigil kontrolliert.",,,"Aquí está. Lo estoy grabando todo, no es que tenga fe en que sobrevivas, es solo que no puedo dejar que la Orden controle el Emblema.",,"Tässä se on. Tallennan kaiken. Tässä ei ole kyse siitä, etteikö minulla olisi täysi luotto, että selviäisit. Emme vain voi antaa Veljeskunnan hallita Sinettiä.","Voilà, j'enregistre tout. C'est pas qu'on a pas confiance en toi, c'est juste que on ne peut pas laisser l'Ordre contrôler le Sigil.","Itt is van. Minden felveszek, nem azért mert nem bíznék benned, csak ne kerüljön a Rend kezébe a pecsét.",Ecco qua. Sto registrando tutto. Non è che non penso che sopravviverai. È solo che non possiamo lasciare che l'Ordine controlli il Sigillo.,"ここよ。私は全て記録している、貴方が生き残れる可能性が無いわけではなく、 +オーダー如きにシジルを制御できるわけがないという事だ。","여기야. 난 지금 모든 걸 녹음하고 있어. 네가 살아남을 거라는 믿음을 버린게 아니라, 오더가 시질을 손에 잡게 내버려 둘 수가 없어서 말이야.","Hier is het. Ik ben alles aan het opnemen, het is niet dat ik geen vertrouwen heb dat je het zult overleven, maar het is gewoon dat we de Orde de Sigil niet kunnen laten controleren door de Orde.","Her er det. Jeg tar opp alt, det er ikke det at jeg ikke har tro på at du vil overleve, men vi kan ikke la Ordenen kontrollere sigillet.","Oto ona. Nagrywam wszystko, to nie tak, że nie mam wiary, że przeżyjesz, po prostu nie możemy pozwolić, by Zakon kontrolował Sigil.","Certo, estou gravando tudo. Não é que eu não tenha fé de que você vá sobreviver, mas não podemos deixar a Ordem controlar o Sigilo.",,"Aici e. Înregistrez totul. Nu e vorba c nu vei supraviețui, dar nu putem permite Ordinului să controleze Sigiliul.","Так. Я всё записываю на плёнку. Это не потому, что я не верю, что ты уцелеешь. Просто мы не можем позволить Ордену заполучить Печать.",,"Här är den. Jag spelar in allting, det är inte så att jag inte tror på att du kommer att överleva, det är bara det att vi inte kan låta Orden kontrollera Sigil.","İşte burası. Her şeyi kaydediyorum, hayatta kalacağınıza inanmadığımdan değil, sadece Düzen'in Sigil'i kontrol etmesine izin veremeyiz." +"You are brave, my comrade. I'm proud to be along for the ride.",TXT_SUB_LOG51,MAP12: Bridge to sanctum's normal entrance.,,,"Jsi statečný, můj příteli. Jsem pyšná, že u tohohle můžu být.","Du er modig, min kammerat. Jeg er stolt af at være med på turen.","Du bist tapfer, mein Kamerad. Ich bin stolz darauf, mit von der Partie zu sein.",,,"Eres valiente, mi camarada. Estoy orgullosa de acompañarte.",,"Olet urhea, toverini. Olen ylpeä, että saan olla matkassa mukana.","Tu est courageux, mon camarade, je suis fière de te suivre.","Felettébb bátor vagy bajtárs. Büszke vagyok, hogy veled harcolhatok.","Sei coraggioso, compagno. Sono orgogliosa di essere insieme a te in questo viaggio.",貴方は勇敢で、私の同志。貴方に就けた事を私は誇りに思ってるわ。,"넌 정말 용맹해, 동지. 너랑 같이 일할 수 있는 게 정말 자랑스러워.","Je bent dapper, mijn kameraad. Ik ben er trots op dat ik meega voor de rit.","Du er modig, min kamerat. Jeg er stolt over å være med på turen.","Jesteś odważny, mój towarzyszu. Jestem dumny, że mogę być przy tobie.","Você é corajoso, meu companheiro. Tenho orgulho de estar junto com você.",,"Ești viteaz, soldatul meu. Sunt mândru să lupt alături de tne.","Я хотела сказать тебе, что ты очень храбрый. Я так счастлива, что мне с тобой по пути.",,"Du är modig, min kamrat. Jag är stolt över att vara med på resan.","Cesursun, yoldaşım. Seninle birlikte olmaktan gurur duyuyorum." Could you pause for a second? I'm getting a little sick.,TXT_SUB_LOG52,"(Strife: Veteran Edition) -Random comment when the player dies with Classic Mode turned off",,,Mohl by ses na chvíli zastavit? Bude mi zle.,Kannst du mal kurz warten? Mir wird etwas übel.,,,¿Puedes parar un segundo? Me estoy mareando un poco.,,,Tu peux t'arrêter pour un moment? J'ai l'impression d'avoir la nausée.,,,ちょっと待ってもらえる?少しばかりうんざりしてるわ。,잠깐만 멈춰줄래? 속이 울렁거려...,Kun je even pauzeren? Ik word een beetje ziek.,,Pode parar por um minuto? Estou ficando com enjôo.,,,Мы можем остановиться на секунду? Что-то мне дурно., -Why do we have to spend so much time underground? I've seen underground.,TXT_SUB_LOG53,STRIFE1.WAD: MAP12,,,Proč musíme tolik času strávit v podzemí? Podzemí jsem viděla.,Warum müssen wir so viel Zeit im Untergrund verbringen.? Ich kenne den Untergrund.,,,¿Por que tenemos que pasar tanto tiempo bajo tierra? Lo tengo muy visto.,,,Pourquoi on passe tout notre temps sous terre? J'ai déja tout vu sous terre.,,,何故私達は地下に長居せねばならないの?地下はもうわかったから。,왜 지하에서 시간을 낭비해야 되는 거지? 난 이미 지하에 있다고.,Waarom moeten we zoveel tijd onder de grond doorbrengen? Ik heb ondergronds gezien.,,Por que a gente tem que ficar tanto tempo no subterrâneo? Já vi bastante do subterrâneo.,,,Почему нам приходится проводить кучу времени под землёй? Я на десять лет вперед насмотрелась на подземелья., -Are we really supposed to trust a guy whose inner sanctum is green?,TXT_SUB_LOG54,STRIFE1.WAD: MAP12,,,"Fakt máme věřit chlápkovi, jehož svatyně je zelená?","Sollen wir wirklich einem Typen vertrauen, dessen Räume grün sind?",,,¿Realmente tenemos que fiarnos de un tipo cuyo gran santuario es verde?,,,On est vraiment obligé de faire confiance à un type qui a un sanctuaire peint en vert?,,,聖域内部と全身が緑色の者を信用するべきなの?,성소가 더럽게 초록색인데 이 녀석을 정말 믿어야 해?,Moeten we echt vertrouwen hebben in een man wiens innerlijke heiligdom groen is?,,Será que a gente deve mesmo confiar num cara cujo grande santuário é verde?,,,"Мы точно можем доверять парню, чьи внутренние покои зелёного цвета?", -Crimson and Obsidian? Why can't he say red and black.,TXT_SUB_LOG55,STRIFE1.WAD: MAP12,,,Karmíno-obsidiánová? Proč nemůže říct černo-červená?,Purpur und Obsidian? Warum kann er nicht Rot und Schwarz sagen?,,,¿Carmesí y obsidiana? Por que no puede decir roja y negra.,,,Cramoisi et obsidienne? Il peut pas dire juste rouge et noir?,,,深紅と黒曜石?何故彼は赤と黒と言わないの。,진홍빛 흑요석? 빨간 검은색이라고 말하면 어디 덧나나?,Crimson en Obsidian? Waarom kan hij niet rood en zwart zeggen.,,Carmesim e Obsidiana? Por que ele não diz logo vermelho e preto?,,,Багрово-обсидиановая? Почему бы не сказать просто — «красно-чёрная»!, -"The Bishop is the Order's military leader. He plots their tactics, runs their spies and is charged with controlling us. We off him and we score twice.",TXT_SUB_LOG56,STRIFE1.WAD: MAP11,,,"Biskup je armádní vůdce Řádu. Plánuje jejich taktiky, velí jejich špiónům a má za úkol ovládat nás. Odděláme ho a zaskórujeme dvakrát.","Der Bischof ist der militärische Anführer des Ordens. Er plant die Strategien, beaufsichtigt die Spione und ist beauftragt, uns zu kontrollieren. Wenn wir ihn ausschalten, gewinnen wir doppelt.",,,"El Obispo es el líder militar de la Orden. Planea sus tácticas, maneja sus espías y está al cargo de controlarnos. Nos lo cargamos y ganamos dos puntos.",,,"L'évèque est le leader militaire de l'Ordre. C'est lui qui s'occupe de leur tactiques, gère leurs espions, et est en charge de nous contrôler. On l'élimine, on marque deux points.",,,"ビショップはオーダーの軍事指揮官よ。 +Random comment when the player dies with Classic Mode turned off",,,Mohl by ses na chvíli zastavit? Bude mi zle.,Kan du holde en pause et øjeblik? Jeg er ved at få det lidt dårligt.,Kannst du mal kurz warten? Mir wird etwas übel.,,,¿Puedes parar un segundo? Que me estoy mareando.,,Voisitko pysähtyä hetkeksi? Alan voida hieman pahoin.,Tu peux t'arrêter pour un moment? J'ai l'impression d'avoir la nausée.,Meg tudnál állni egy pillanatra? Elég rosszul vagyok.,Puoi fermarti per un secondo? Mi sento un po' nauseata.,ちょっと待ってもらえる?少しばかりうんざりしてるわ。,잠깐만 멈춰줄래? 속이 울렁거려...,Kun je even pauzeren? Ik word een beetje ziek.,Kan du ta en pause? Jeg begynner å bli litt kvalm.,Możesz się zatrzymać na chwilę? Robi mi się trochę niedobrze.,Pode parar por um minuto? Estou ficando com enjôo.,,Poți să te opreși un moment? Mi se face rău.,Мы можем остановиться на секунду? Что-то мне дурно.,,Kan du stanna upp en stund? Jag börjar bli lite sjuk.,Bir saniye durabilir misin? Biraz midem bulanıyor. +Why do we have to spend so much time underground? I've seen underground.,TXT_SUB_LOG53,MAP12: Downstairs.,,,Proč musíme tolik času strávit v podzemí? Podzemí jsem viděla.,Hvorfor skal vi tilbringe så meget tid under jorden? Jeg har set under jorden.,Warum müssen wir so viel Zeit im Untergrund verbringen.? Ich kenne den Untergrund.,,,¿Por que tenemos que pasar tanto tiempo bajo tierra? Ya lo tengo muy visto.,,Miksi olemme niin paljon maan alla? Nähty juttu.,Pourquoi on passe tout notre temps sous terre? J'ai déja tout vu sous terre.,Miért kell ilyen sok időt föld alatt töltenünk? Már láttam elég föld alatti részt.,Ma perché passiamo così tanto tempo sotto terra? Già conosco molto bene posti come questo.,何故私達は地下に長居せねばならないの?地下はもうわかったから。,왜 지하에서 시간을 낭비해야 되는 거지? 난 이미 지하에 있다고.,Waarom moeten we zoveel tijd onder de grond doorbrengen? Ik heb ondergronds gezien.,Hvorfor må vi tilbringe så mye tid under jorden? Jeg har sett undergrunnen.,Dlaczego musimy spędzać tyle czasu pod ziemią? Widziałem już podziemia.,Por que a gente tem que ficar tanto tempo no subterrâneo? Já vi bastante do subterrâneo.,,De ce trebuie să petrecem atâta timp sub pământ? Am văzut subteranul.,Почему нам приходится проводить кучу времени под землёй? Я на десять лет вперед насмотрелась на подземелья.,,Varför måste vi tillbringa så mycket tid under jord? Jag har sett underjorden.,Neden yeraltında bu kadar çok vakit geçirmek zorundayız? Yeraltını gördüm. +Are we really supposed to trust a guy whose inner sanctum is green?,TXT_SUB_LOG54,MAP12: Sanctum's normal entrance.,,,"Fakt máme věřit chlápkovi, jehož svatyně je zelená?","Skal vi virkelig stole på en fyr, hvis indre helligdom er grøn?","Sollen wir wirklich einem Typen vertrauen, dessen Räume grün sind?",,"Ĉu ni vere devas fidi al iu, kies sekreta templo estas verda?",¿En serio hay que fiarse de un tío cuyo templo secreto es verde?,¿En serio hay que confiar en un tipo cuyo templo secreto es verde?,"Tuleeko meidän todella luottaa kaveriin, jolla on vihreä pyhäkkö?",On est vraiment obligé de faire confiance à un type qui a un sanctuaire peint en vert?,"Egy olyan ürgében kéne megbíznunk, akinek zöld színű a szentélye?",Davvero dovremmo fidarci di qualcuno che ha un santuario verde?,聖域内部と全身が緑色の者を信用するべきなの?,성소가 더럽게 초록색인데 이 녀석을 정말 믿어야 해?,Moeten we echt vertrouwen hebben in een man wiens innerlijke heiligdom groen is?,Skal vi virkelig stole på en fyr hvis indre er grønt?,"Czy naprawdę mamy ufać facetowi, którego wewnętrzne sanktuarium jest zielone?",Será que a gente deve mesmo confiar num cara cujo grande santuário é verde?,,Chiar ar trebui să avem încredere în cineva în cineva al cărui sanctuar e verde?,"Мы точно можем доверять парню, чьи внутренние покои зелёного цвета?",,Är det verkligen meningen att vi ska lita på en kille vars inre helgedom är grön?,Kutsal alanı yeşil olan bir adama gerçekten güvenmemiz mi gerekiyor? +Crimson and Obsidian? Why can't he say red and black.,TXT_SUB_LOG55,MAP12: After talking to the Oracle.,,,Karmíno-obsidiánová? Proč nemůže říct červeno-černá?,Purpur og Obsidian? Hvorfor kan han ikke sige rød og sort.,Purpur und Obsidian? Warum kann er nicht Rot und Schwarz sagen?,,Ĉu «karmezina kaj obsidiankolora»? Ĉu li ne scias diri «ruĝa kaj nigra»?,"¿«Carmesí y obsidiana»?, ¿tanto le cuesta decir «roja y negra»?",,Purppuranpunainen ja laavalasinen? Miksei hän voi sanoa punainen ja musta?,Cramoisi et obsidienne? Il peut pas dire juste rouge et noir?,"Karmazsin és obszidián? Miért nem tudja azt mondani, hogy piros és fekete.",Cremisina e ossidiana? Non bastava dire rossa e nera?,深紅と黒曜石?何故彼は赤と黒と言わないの。,진홍빛 흑요석? 빨간 검은색이라고 말하면 어디 덧나나?,Crimson en Obsidian? Waarom kan hij niet rood en zwart zeggen.,Purpur og Obsidian? Hvorfor kan han ikke si rødt og svart?,Karmazyn i Obsydian? Dlaczego nie może powiedzieć: czerwony i czarny.,Carmesim e Obsidiana? Por que ele não diz logo vermelho e preto?,,Străveziu și Obsidian? De ce nu poate spune roșu și negru.,Багрово-обсидиановая? Почему бы не сказать просто — «красно-чёрная»!,,Karminrött och Obsidian? Varför kan han inte säga röd och svart.,Crimson ve Obsidian? Neden kırmızı ve siyah diyemiyor? +"The Bishop is the Order's military leader. He plots their tactics, runs their spies and is charged with controlling us. We off him and we score twice.",TXT_SUB_LOG56,MAP11: Afther talking to the Oracle and leaving the cave.,,,"Biskup velí armádě Řádu. Plánuje jejich taktiky, velí jejich špiónům a má za úkol ovládat nás. Odděláme ho a zabodujeme dvakrát.","Biskoppen er ordenens militære leder. Han udtænker deres taktik, leder deres spioner og har til opgave at kontrollere os. Hvis vi dræber ham, scorer vi to gange.","Der Bischof ist der militärische Anführer des Ordens. Er plant die Strategien, beaufsichtigt die Spione und ist beauftragt, uns zu kontrollieren. Wenn wir ihn ausschalten, gewinnen wir doppelt.",,,"El Obispo es el líder militar de La Orden: planea sus tácticas, maneja a sus espías y está al cargo de controlarnos. Nos lo cargamos y ganamos dos puntos.","El Obispo es el líder militar de La Orden: planea sus tácticas, maneja a sus espías y está al cargo de controlarnos. Lo matamos y premios dobles.","Piispa on Veljeskunnan sotapäällikkö. Hän laatii heidän taktiikkansa, johtaa heidän vakoojiaan ja vastaa meidän hallinnasta. Teemme hänestä lopun ja pokkaamme kaksi pistettä. ","L'évèque est le leader militaire de l'Ordre. C'est lui qui s'occupe de leur tactiques, gère leurs espions, et est en charge de nous contrôler. On l'élimine, on marque deux points.","A Püspök a Rend katonai vezetője. Ő agyalja ki a taktikákat, irányítja a kémeket, és rá van bízva a mi irányításunk is. A kiiktatásával két legyet ütünk egy csapásra.",Il Vescovo è il capo militare dell'Ordine. È lui a pianificare le loro tattiche e gestire le loro spie al fine di controllarci tutti. Farlo fuori sarebbe un enorme vantaggio.,"ビショップはオーダーの軍事指揮官よ。 奴等の戦術を企てスパイを駆り立て私達の支配が管轄だ。 -奴を仕留めれば得点は倍額でしょう。","비숍은 그들의 잔혹한 군사 지도자이지. 그는 전술을 획책하고, 첩자를 부리고, 우리들을 통제하고 있어. 그를 죽이면 두 배로 이득이 갈 거야.","De bisschop is de militaire leider van de Orde. Hij zet hun tactiek uit, leidt hun spionnen en heeft de opdracht ons te controleren. We gaan van hem af en we scoren twee keer.",,"O Bispo é o líder militar da Ordem. Ele planeja suas táticas, comanda seus espiões e é encarregado de nos controlar. Eliminamos ele e é dois coelhos numa tacada só.",,,"Епископ — военный лидер Ордена. Он обучает их тактике, управляет их шпионами и жаждет контроля над нами. От его убийства мы выигрываем вдвойне.", -The Bishop is going to be heavily guarded so why don't we swipe a uniform and blend in?,TXT_SUB_LOG57,STRIFE1.WAD: MAP11,,,"Biskup bude silně strážen, co takhle sebrat uniformu a splynout s davem?","Der Bischof wird schwer bewacht sein, so warum stibitzen wir nicht eine Uniform um uns besser anzupassen?",,,El Obispo estará bien guardado asi que ¿por que no pillamos un uniforme y nos mezclamos?,,,"L'évèque sera lourdement protégé, pourquoi ne pas trouver un uniforme et se mêler à la foule?",,,ビショップのいる場所の警備は厳重なので、奴等の制服を盗み紛れ込む方が良いのでは?,"비숍은 군사 지도자니까, 삼엄한 경비에 의해 지켜질 거야. 그러니 전투복을 입고 잠입하는 게 어때?","De bisschop zal zwaar bewaakt worden, dus waarom vegen we er niet een uniform overheen en mengen we ons in de bisschop?",,"O Bispo está protegido por vários guardas, então que tal roubar um uniforme e se mesclar?",,,"Похоже, что Епископа неплохо охраняют. Предлагаю стянуть униформу и прокрасться внутрь.", -"Remind me, we win this thing and I'll call in a decorator.",TXT_SUB_LOG58,,,,"Připomeň mi až vyhrajeme, abych zavolala malíře.","Bittr erinnere mich daran, dass wir einen Dekorateur bestellen, nachdem wir gewonnen haben.",,,"Recuérdame, nos ganamos esto y llamo a un decorador.",,,"Rappelle-moi, quand on a fini, il faut que j'appelle un décorateur.",,,,"우리가 이길 수만 있다면, 축제 분위기 나게 장식할 사람을 부를 거야.","Herinner me eraan, we winnen dit ding en ik zal een decorateur inschakelen.",,"Não deixa eu esquecer, depois de vencermos vou chamar um decorador.",,,"Напомни мне позвать декоратора после того, как мы победим.", -"I just got word we got an informer inside the fortress. Let's head toward what they call the hospital, he works there.",TXT_SUB_LOG59,STRIFE1.WAD: MAP17,,,"Právě jsem dostala zprávu, že máme v pevnosti informátora. Měli bychom zamířit k nemocnici, pracuje tam.","Ich habe gerade gehört, dass wir einen Informanten in der Festung haben. Geh rüber um Hospital, dort arbeitet er.",,,"Acaban de decirme que tenemos un informante dentro de la fortaleza. Vayamos a lo que llaman el hospital, trabaja allí.",,,"J'entends qu'un de nos informants se trouve dans la forteresse. Allons dans ce qu'ils appellent l'hôpital, il y travaille.",,,"要塞の中に情報提供者がいるという話を聞いた。 -奴等が病院と呼んでいる場所に勤めているので向かいましょう。","요새 안에 우리들을 도울 정보원이 있다는 보고를 들었어. 그는 오더가 병원이라고 부르는 곳 안에 있는데, 그곳으로 찾아가 봐.","Ik heb net gehoord dat we een informant in het fort hebben. Laten we naar wat ze het ziekenhuis noemen gaan, hij werkt daar.",,"Acabei de receber a informação de que temos um informante dentro da fortaleza. Vamos para onde eles chamam de ""hospital"". Ele trabalha lá.",,,"Мне только что сказали, что у нас есть информатор внутри крепости. Нам нужно место, которое они называют госпиталем — он работает там.", -"Grab the plans and knock out the computer, ok?",TXT_SUB_LOG60,STRIFE1.WAD: MAP17,,,"Seber plány a znič počítač, dobře?","Nimm die Plane und schalte den Computer aus, ok?",,,"Recoge los planos y derriba la computadora, ¿ok?",,,"Récupère les plans et détruis l'ordinateur, ok?",,,計画を奪いにコンピューターを破壊する、いけるわね?,계획서를 집고 컴퓨터를 파괴해. 간단하지?,"Pak de plannen en sla de computer eruit, oké?",,"Pegue os planos e destrua o computador, ok?",,,"Хватаем планы и ломаем компьютер, лады?", +奴を仕留めれば得点は倍額でしょう。","비숍은 그들의 잔혹한 군사 지도자이지. 그는 전술을 획책하고, 첩자를 부리고, 우리들을 통제하고 있어. 그를 죽이면 두 배로 이득이 갈 거야.","De bisschop is de militaire leider van de Orde. Hij zet hun tactiek uit, leidt hun spionnen en heeft de opdracht ons te controleren. We gaan van hem af en we scoren twee keer.","Biskopen er ordenens militære leder. Han planlegger taktikken deres, styrer spionene deres og har ansvaret for å kontrollere oss. Dreper vi ham, scorer vi to ganger.","Biskup jest przywódcą wojskowym Zakonu. Tworzy ich taktykę, prowadzi ich szpiegów i ma za zadanie kontrolować nas. Zdejmiemy go i zdobędziemy dwa punkty.","O Bispo é o líder militar da Ordem. Ele planeja suas táticas, comanda seus espiões e é encarregado de nos controlar. Eliminamos ele e é dois coelhos numa tacada só.",,"Episcopul e liderul militar al Ordinului. Le planifică schemele, tacticile, spionează, și ne controlează. Îl eliminăm și înscriem de două ori.","Епископ — военный лидер Ордена. Он обучает их тактике, управляет их шпионами и жаждет контроля над нами. От его убийства мы выигрываем вдвойне.",,"Biskopen är ordens militära ledare. Han planerar deras taktik, leder deras spioner och har till uppgift att kontrollera oss. Om vi dödar honom får vi två poäng.","Piskopos, Tarikat'ın askeri lideridir. Taktiklerini planlar, casuslarını yönetir ve bizi kontrol etmekle görevlidir. Ondan kurtulursak iki kere kazanırız." +The Bishop is going to be heavily guarded so why don't we swipe a uniform and blend in?,TXT_SUB_LOG57,MAP11: Officer's uniform room.,,,"Biskup bude silně strážen, co takhle sebrat uniformu a splynout s davem?","Biskoppen vil være stærkt bevogtet, så hvorfor tager vi ikke en uniform og falder ind i mængden?","Der Bischof wird schwer bewacht sein, so warum stibitzen wir nicht eine Uniform um uns besser anzupassen?",,,El Obispo estará bien guardado asi que ¿por que no pillamos un uniforme y nos mezclamos?,,"Piispa on taatusti tarkoin vartioitu, joten miksemme kähveltäisi univormua ja sulautuisi joukkoon?","L'évèque sera lourdement protégé, pourquoi ne pas trouver un uniforme et se mêler à la foule?","A Püspök elég izmos védelmet élvez, érdemes lesz lopnunk egy uniformist a beilleszkedés jegyében.","Il Vescovo sarà sicuramente ben protetto, quindi perché non camuffarsi con un'uniforme?",ビショップのいる場所の警備は厳重なので、奴等の制服を盗み紛れ込む方が良いのでは?,"비숍은 군사 지도자니까, 삼엄한 경비에 의해 지켜질 거야. 그러니 전투복을 입고 잠입하는 게 어때?","De bisschop zal zwaar bewaakt worden, dus waarom vegen we er niet een uniform overheen en mengen we ons in de bisschop?","Biskopen kommer til å være tungt bevoktet, så hvorfor tar vi ikke en uniform og smelter inn?","Biskup będzie pilnie strzeżony, więc czemu nie weźmiemy munduru i nie wtopimy się w tłum?","O Bispo está protegido por vários guardas, então que tal roubar um uniforme e se mesclar?",,Episcopul o să fie extrem de bine păzit deci de ce nu luăm o uniformă și ne camuflăm?,"Похоже, что Епископа неплохо охраняют. Предлагаю стянуть униформу и прокрасться внутрь.",,Biskopen kommer att vara tungt bevakad så varför tar vi inte en uniform och smälter in?,"Piskopos çok sıkı korunuyor olacak, neden bir üniforma çalıp aralarına karışmıyoruz?" +"Remind me, we win this thing and I'll call in a decorator.",TXT_SUB_LOG58,,,,"Připomeň mi až vyhrajeme, abych zavolala malíře.","Mind mig om, at hvis vi vinder det her, så tilkalder jeg en dekoratør.","Bitte erinnere mich daran, dass wir einen Dekorateur bestellen, nachdem wir gewonnen haben.",,,"Recuérdame, nos ganamos esto y llamo a un decorador.",,"Muistuta minua, että jos voitamme tämän, niin kutsun paikalle sisustussuunnittelijan.","Rappelle-moi, quand on a fini, il faut que j'appelle un décorateur.","Emlékeztess rá, hogy ha túlvagyunk ezen hívjak egy szobafestőt.","Ricordamelo, appena vinciamo questa battaglia bisogna chiamare qualcuno per ridecorare.",,"우리가 이길 수만 있다면, 축제 분위기 나게 장식할 사람을 부를 거야.","Herinner me eraan, we winnen dit ding en ik zal een decorateur inschakelen.","Minn meg på at hvis vi vinner, ringer jeg etter en dekoratør.","Przypomnij mi, że jak wygramy to wezwę dekoratora.","Não deixa eu esquecer, depois de vencermos vou chamar um decorador.",,"Adu-mi aminte, câștigăm și chem să ne decoreze.","Напомни мне позвать декоратора после того, как мы победим.",,Påminn mig om att om vi vinner det här så ska jag kalla in en dekoratör.,"Hatırlat bana, bu şeyi kazanırsak bir dekoratör çağıracağım." +"I just got word we got an informer inside the fortress. Let's head toward what they call the hospital, he works there.",TXT_SUB_LOG59,MAP17: Bailey → Upstairs.,,,"Právě jsem dostala zprávu, že máme v pevnosti informátora. Měli bychom zamířit k nemocnici, pracuje tam.","Jeg har lige hørt, at vi har en stikker inde i fæstningen. Lad os gå mod det, de kalder hospitalet. Han arbejder der.","Ich habe gerade gehört, dass wir einen Informanten in der Festung haben. Geh rüber um Hospital, dort arbeitet er.",,"Mi ĵus estis sciigita, ke ni havas informanton en la fortreso. Ni iru al tio, kion ili nomas «la malsanulejo» lia laborejo.","Acaban de decirme que tenemos un informante dentro de la fortaleza. Vayamos a lo que llaman «el hospital», que es donde trabaja.","Acaban de decirme que tenemos un informante adentro de la fortaleza. Vayamos a lo que le dicen «el hospital», que es donde trabaja.","Sain juuri tiedon ilmiantajasta linnoituksessa. Suunnataan kohti paikkaa, jota he kutsuvat sairaalaksi; hän työskentelee siellä.","J'entends qu'un de nos informants se trouve dans la forteresse. Allons dans ce qu'ils appellent l'hôpital, il y travaille.","Most kaptam a hírt, hogy van egy besúgónk az erődítményben. Menjünk a kórháznak nevezett részlegbe, ott dolgozik.","Ho appena scoperto che abbiamo un informatore dentro la fortezza. Rechiamoci verso ciò che chiamano l'ospedale, lui lavora là.","要塞の中に情報提供者がいるという話を聞いた。 +奴等が病院と呼んでいる場所に勤めているので向かいましょう。","요새 안에 우리들을 도울 정보원이 있다는 보고를 들었어. 그는 오더가 병원이라고 부르는 곳 안에 있는데, 그곳으로 찾아가 봐.","Ik heb net gehoord dat we een informant in het fort hebben. Laten we naar wat ze het ziekenhuis noemen gaan, hij werkt daar.",Jeg hørte nettopp at vi har en informant inne i festningen. La oss dra til det de kaller sykehuset. Han jobber der.,"Właśnie dostałem wiadomość, że mamy informatora w twierdzy. Kierujmy się w stronę tego, co nazywają szpitalem, on tam pracuje.","Acabei de receber a informação de que temos um informante dentro da fortaleza. Vamos para onde eles chamam de ""hospital"". Ele trabalha lá.",,"Tocmai am primit ceva de la un informator din interiorul fortăreței. Să merge înspre ceea ce ei numesc spital, lucrează acolo.","Мне только что сказали, что у нас есть информатор внутри крепости. Нам нужно место, которое они называют госпиталем — он работает там.",,"Jag fick just höra att vi har en informatör inne i fästningen. Vi går mot det som de kallar sjukhuset, han arbetar där.","Az önce kalenin içinde bir muhbirimiz olduğu haberini aldım. Hastane dedikleri yere doğru gidelim, orada çalışıyor." +"Grab the plans and knock out the computer, ok?",TXT_SUB_LOG60,MAP17: Security Complex,,,"Seber plány a znič počítač, dobře?","Tag tegningerne og slå computeren ud, okay?","Nimm die Plane und schalte den Computer aus, ok?",,,"Coge los planos y destruye el ordenador, ¿sí?","Toma los planos y destruye la computadora, ¿sí?","Nappaa suunnitelmat ja hajota tietokone, eikö niin?","Récupère les plans et détruis l'ordinateur, ok?","Kapd fel a terveket, és nyírd ki a számítógépet, rendben?","Prendi i piani e distruggi il computer, ok?",計画を奪いにコンピューターを破壊する、いけるわね?,계획서를 집고 컴퓨터를 파괴해. 간단하지?,"Pak de plannen en sla de computer eruit, oké?","Ta tegningene og slå ut datamaskinen, ok?","Weź plany i wywal komputer, ok?","Pegue os planos e destrua o computador, ok?",,"Ia planurile și distruge calculatorul, ok?","Хватаем планы и ломаем компьютер, лады?",,"Ta ritningarna och slå ut datorn, okej?","Planları al ve bilgisayarı devre dışı bırak, tamam mı?" "Alright, I'm not complaining, but next time we might try the way that isn't buckets of blood.",TXT_SUB_LOG61,"(Strife: Veteran Edition) -Random comment when the player dies with Classic Mode turned off",,,"Dobře, nestěžuju si, ale příště bychom mohli zkusit způsob, po kterém nezůstanou kýble krve.","Ok, ich will nicht meckern, aber beim nächsten Mal sollte das mit weniger Blutvergießen vonstatten gehen.",,,"Muy bien, no me quejo, pero la próxima vez deberíamos probar el método que no sea una masacre.",,,"Bon, je ne me plains pas, mais la prochaine fois, essayons de faire sans foutre du sang partout?",,,大丈夫、次は血のバケツをぶち撒けない方法を試した方がいい。,"이런... 비꼬는 건 아닌데, 다음번엔 유혈사태를 일으키지 않고 일을 해결해보자.","Oké, ik klaag niet, maar de volgende keer kunnen we misschien de manier proberen waarop dat geen emmers bloed is.",,"Tá bem, não estou reclamando. Mas da próxima vez vamos tentar de um jeito que não seja sangue jorrando pra tudo que é lado.",,,"Я не жалуюсь, но, может, в следующий раз попробуем не проливать реки крови?", -"We've been through endless hallways before, but I swear, these walls are moving as we pass.",TXT_SUB_LOG62,STRIFE1.WAD: MAP19,,,"Už jsme předtím byli v nekonečných chodbách, ale přísahám, že tyhle stěny se hýbou.","Wir sind ja schon durch endlose Flure gegangen, aber ich könnte schwören, dass sich die Wände hier bewegen.",,,"Hemos pasado por pasillos sin fin otras veces, pero juro que estas paredes se están moviendo a nuestro paso.",,,"J'ai déja fais un tour dans un couloir sans fin comme ça, mais je jure que les murs bougent avec nous.",,,"以前に私達は無限へ通じる玄関を通ったかと思うが、誓おう、 -通り過ぎた時に壁が動いていたからだと。","난감한 곳들을 다녀갔지만, 여기는 뭔가 새로워. 걸어갈 때마다 벽이 움직이는 것 같거든...","We zijn al eens door eindeloze gangen geweest, maar ik zweer het, deze muren bewegen zich in de loop van de tijd.",,"Já passamos por inúmeros corredores antes, mas eu juro, essas paredes ficam se mexendo enquanto a gente passa.",,,"Мы уже повидали достаточно бесконечных коридоров, но я готова поклясться: эти стены передвигаются, когда мы на них не смотрим.", -"Well, you gotta figure. Military leader equals lots of bad guys.",TXT_SUB_LOG63,STRIFE1.WAD: MAP16,,,"No, mělo by ti to dojít. Armádní vůdce rovná se hodně padouchů.",Das war ja klar. Militärischer Anführer bedeutet jede Menge Bösewichte.,,,"Bueno, quien lo iba a pensar. Líder militar equivale a muchos tipos malos.",,,"Bon, fallait y penser. Chef militaire, ça veut dire beaucoup de types armés.",,,さて、貴方はフィギュアを得た。軍隊指揮者は大勢の悪人に匹敵するわ。,이거 정말 뻔하네. 군대 우두머리의 심복들은 다 난폭하고 둔하지.,"Nou ja, je moet het wel beseffen. Militair leider is gelijk aan veel slechteriken.",,"Olha só, quem diria. Líder militar é igual a um monte de caras malvados.",,,Сам понимаешь. Военный лидер — всё равно что куча плохих парней., -Don't give up. This is it. Straight ahead.,TXT_SUB_LOG64,STRIFE1.WAD: MAP19,,,"Nevzdávej se, tohle je ono. Jdi rovně.",Gib nicht auf. Direkt voraus.,,,No te rindas. Esto es. Justo adelante.,,,"Abandonne pas, on y est. Juste devant.",,,諦めないで。これでいいんだ。真っ直ぐ行こう。,포기하지 마. 거의 다 왔어. 가까이 왔다고.,Geef niet op. Dit is het. Rechtdoor.,,Não desista. Esta é a hora. Siga reto adiante.,,,Не падай духом. Вот оно. Впереди., -"Next time, we stop at a gas station and ask for directions.",TXT_SUB_LOG65,,,,Příště se zastavíme na benzince a zeptáme se na cestu.,Nächstes Mal halten wir an einer Tankstelle und fragen nach der Richtung.,,,A la próxima paramos en una gasolinera y preguntamos la dirección.,,,"La prochaine fois, on s'arrète à une station-service et on demande notre chemin.",,,,다음엔 편의점 같은 건물에 들러서 그냥 방향을 묻자.,De volgende keer stoppen we bij een tankstation en vragen we de weg.,,Da próxima vez vamos parar num posto de gasolina e perguntar onde fica.,,,В следующий раз остановимся на заправке и спросим дорогу., -Oh no! More bells and whistles and nasty guys chasing us.,TXT_SUB_LOG66,STRIFE1.WAD: MAP19,,,"Ale ne! Další fešné vymoženosti a padouši, co nás pronásledují.",Oh nein. Noch mehr Lärm und Bösewichte auf unseren Fersen.,,,Oh no! Más bombos y platillos y tipos malos persiguiéndonos.,,,Oh non! Encore des trucs et des choses et des sales types qui nous prennent en chasse.,,,あーらら!鐘と笛で更に厄介な奴等を呼び込んできたな。,"오, 안 돼! 삼엄한 경비에 피할 수도 없는 선택지라니.",Oh nee! Nog meer toeters en bellen en vervelende jongens die ons achterna zitten.,,Ai não! Mais bugigangas e capangas vindo atrás de nós.,,,"О, нет! Ещё больше свистелок, перделок и плохих парней, которые за нами гонятся.", -"You know, from the outside, this place looks tiny.",TXT_SUB_LOG67,STRIFE1.WAD: MAP15,,,Zvenku tohle místo vypadalo drobounké.,Von außen sieht das hier irgendwie mickrig aus.,,,"Sabes, por fuera, este sitio parece enano.",,,"Tu sais, de l'extérieur, cet endroit à l'air super petit.",,,外から見ると、此処は小さいみたいね。,"궁금한 게 있는데, 왜 안에 들어가면 커지는 걸까?","Weet je, van buitenaf ziet deze plek er klein uit.",,"Sabe, vendo de longe esse lugar parece minúsculo.",,,"Знаешь, снаружи это место кажется крошечным.","Знаш, напољу, ово место изгледа веома мало." -"I'm getting a new enemy reading. Don't stop and stare, just waste 'em.",TXT_SUB_LOG68,,,,Zaznamenávám nového nepřítele. Nestůj tam a znič ho!,"Ich habe eine neue Feindortung. Warum wartest du, mach sie alle!",,,"Tengo señales de un nuevo enemigo. No te pares a mirar, solo cárgatelo.",,,"J'ai un ping ennemi sur mon radar. Ne t'arrète pas, flingue-les.",,,,네 주변에 적이 포착됐어. 그냥 쳐다보지 말고 어떻게든 해봐.,"Ik krijg een nieuwe vijandelijke lezing. Niet stoppen en staren, maar ze gewoon verspillen.",,"Estou recebendo sinais de um novo inimigo. Nâo fique parado olhando, mete bala neles.",,,"Вижу врагов. Не стой столбом, мочи их!", -"I hate these forcefields. Look for the shut-off switch, it's gotta be nearby.",TXT_SUB_LOG69,STRIFE1.WAD: MAP15,,,"Nesnáším tahle silová pole. Porozhlédni se po nějakém vypínači, měl by být nablízko.","Ich hasse diese Kraftfelder. Such nach einem Schalter, er müsste in der Nähe sein.",,,"Odio estos campos de fuerza. Busca el interruptor de apagado, tiene que estar cerca.",,,"Je déteste les champs de force. Trouve leur commandes, elles ne doivent pas être loin.",,,私はフォースフィールドが憎いわ。遮断させるスイッチが近くにあるはずだわ。,이런 방어막들 정말 싫다니까. 저걸 끌 스위치를 찾아봐. 가까이에 있을 거야.,"Ik haat deze krachtvelden. Zoek naar de afsluitschakelaar, die moet in de buurt zijn.",,"Odeio esses campos de força. Procure pelo interruptor de desligar, deve estar por perto.",,,"Ненавижу эти силовые поля. Поищи выключатель, он где-то неподалёку.", -"Ooh, very impressive. Let's blow it up!",TXT_SUB_LOG70,"STRIFE1.WAD: MAP15 - -(After pressing the switch to reveal the computer)",,,"Ó, velmi působivé. Co to nechat vybouchnout?","Oh, sehr imposant. Jag ihn hoch!",,,"Ooh, muy impresionante. Vamos a volarlo!",,,"Oooh, très impressionant! Faisons tout péter!",,,あら、見事な物ね。是非とも火薬を献上しましょう。,"오우, 정말 이쁘네! 이제 터뜨리자!","Ooh, heel indrukwekkend. Laten we hem opblazen!",,"Oohh, que impressionante! Vamos detoná-lo.",,,Очень впечатляюще. Давай взорвём!, -"Jump on the teleporter, let's blow this pop stand.",TXT_SUB_LOG71,,,,Skoč na teleportér a odpalme tenhle stánek se zmrzlinou.,Spring in den Teleporter und jag das Ding hoch.,,,"Súbete al teletransporte, carguémonos este tinglado.",,,"Saute dans le téléporteur, cassons nous d'ici.",,,,텔레포터를 타고 이 놀이터를 벗어나자.,"Spring op de teleporter, laten we deze popstandaard opblazen.",,"Entre no teletransportador, vamos explodir este muquifo.",,,Прыгай в телепорт. Пора валить отсюда., -"Wait, the Oracle said we would know him by his symbol of power. Are you thinking what I'm thinking?",TXT_SUB_LOG72,STRIFE1.WAD: MAP16,,,"Počkat, Věštec říkal, že ho poznáme podle jeho symbolu moci. Myslíš na to samé, co já?","Warte, das Orakel sagte wir würden ihn an seinem Machtsymbol erkennen. Denkst du, was ich denke?",,,"Espera, el Oráculo dice que lo reconoceríamos por su símbolo de poder. ¿Piensas lo mismo que yo?",,,"Attend, l'Oracle nous a dit qu'on le reconnaitrerait de par son symbole de pouvoir.. Tu pense à la même chose que moi?",,,"ちょっと待って、オラクルは私達に彼のシンボルを辿ればわかると述べたか。 -貴方今、私と同じ事考えてる?","잠깐, 오라클이 전에 권력을 상징하는 문양을 따라가면 만날 수 있다고 했지? 너 나랑 같은 생각 하고 있지?","Wacht, het Orakel zei dat we hem zouden kennen aan zijn machtssymbool. Denk jij wat ik denk?",,"Peraí, o Oráculo disse que reconheceríamos ele pelo seu símbolo de poder. Você está pensando o mesmo que eu?",,,"Подожди — Оракул сказал, что мы найдём его по символу власти. Ты думаешь о том же, о чём и я?", -"These guys got a decorating idea that works, and they just beat it to death.",TXT_SUB_LOG73,,,,Tihle lidi dostali dobrý nápad na výzdobu a pak ho zadupali do země.,"Diese Typen haben ein Design das funktioniert, aber sie haben es total übertrieben.",,,"Estos tipos tuvieron una idea de decoración que funciona, y la han matado a palos.",,,Cest types avaient une super bonne idée déco et ils ont fait n'importe quoi avec.,,,,"저놈들은 도움이 되는 생각을 가지고 있기는 한데, 다 쓸데없이 망치고 있어.","Deze jongens hebben een decoratief idee dat werkt, en ze hebben het gewoon doodgeslagen.",,Esses caras tinham uma idéia de decoração que funcionava e depois mandaram tudo pro saco.,,,"У этих ребят была отличная идея декора, но они загубили её на корню.", -Did you see that weird spectre that came out of the Bishop's body? Where have I seen that before?,TXT_SUB_LOG74,"STRIFE1.WAD: MAP16 - -(After defeating the Bishop)",,,"Viděl jsi ten divný přízrak, který vyšel z Biskupova těla? Kde jsem ho jen předtím viděla?","Hast du diesen seltsamen Schemen gesehen, der aus seinem Körper herauskam? Wo haben wir das schonmal gesehen?",,,¿Viste ese extraño espectro que salió del cuerpo del Obispo? ¿Donde lo he visto antes?,,,Tu a vu ce spectre bizarre qui est sorti du corps de l'évèque? On a pas vu ça quelque part avant?,,,"ビショップの体から出てきたあの奇妙な幽体を見た? -以前に何処かで見た気がするけど?",그나저나 비숍 몸에서 튀어나왔던 검은 물체 봤어? 전에 본 적이 있나?,Zag je dat rare spook dat uit het lichaam van de bisschop kwam? Waar heb ik dat eerder gezien?,,Você viu aquele espectro estranho que saiu do corpo do BIspo? Onde foi que eu já vi isso antes?,,,"Видел тот странный фантом, вышедший из тела Епископа? Где я могла видеть такое раньше?", -Judgment call time. Now that we got two pieces we might wanna return to base. What does your instinct tell you?,TXT_SUB_LOG75,,,,"Čas se rozhodnout. Teď, když máme dva díly, bychom se možná měli vrátit na základnu. Co ti říkají tvoje instinkty?","Zeit für eine Gewissensentscheidung. Jetzt wo wir zwei Teile haben, sollten wir zur Basis zurückkehren. Was denkst du?",,,Hora del Juicio. Ahora que tienes dos piezas podríamos regresar a la base. ¿Qué te dice tú instinto?,,,"C'est l'heure du jugement, on a deux pièce, il est temps de retourner à la base. Que te dit ton instinct?",,,,심판의 시간이야. 시질 두 조각을 모았으니 본부로 돌아가자. 이제 너의 본능은 무슨 해답을 내놓을까?,"Oordeel roep tijd. Nu we twee stukken hebben, willen we misschien terug naar de basis. Wat zegt je instinct je?",,"Hora do julgamento. Agora que temos duas peças, talvez a gente queira voltar pra base. O que o seu instinto diz?",,,, -"I have a report that the spectral energy we found near the Bishop is also present by the Oracle, let's be careful.",TXT_SUB_LOG76,STRIFE1.WAD: MAP11,,,"Mám hlašení, že stejná přízračná energie, kterou jsme našli u Biskupa, se nachází také u Věštce. Měli bychom být opatrní.","Ich habe einen Report, dass die spektrale Energie, die wir beim Bischof gefunden haben, auch beim Orakel präsent ist. Sei vorsichtig.",,,"Tengo un informe de que la energía espectral que encontramos cerca del Obispo también está presente junto al Oráculo, vayamos con cuidado",,,J'ai un rapport que l'énergie spectrale que l'on a trouvé près de l'évèque est aussi près de l'Oracle. Faisons attention.,,,"ビショップにもあったスペクトラルエネルギーがオラクルにも宿っているという -報告があるわ、気を付けて。","지금 보고를 받았는데, 비숍을 죽인 뒤에 나온 혼령의 기운이 오라클에게도 있데. 조심하자.","Ik heb een verslag dat de spectrale energie die we in de buurt van de bisschop vonden ook aanwezig is bij het Orakel, laten we voorzichtig zijn.",,Tenho relatos de que a energia espectral que encontramos perto do Bispo também está presente pelo Oráculo. Vamos com cuidado.,,,"Мне доложили, что от Оракула исходит та же энергия, что и от того фантома, которого мы видели у Епископа. Будь начеку!", -Macil? Part of this mess? I don't know what to think. I hope you make the right decision.,TXT_SUB_LOG77,,,,"Macil? Částí tohohle bordelu? Nevím, co si o tom mám myslet. Doufám, že se rozhodneš správně.","Macil? Ein Teil dieser Schweinerei? Ich weiß nicht, was ich denken soll. Hoffentlich triffst du die richtige Entscheidung.",,,¿Macil? ¿Parte de este lío? No sé que pensar. Espero que tomes la decisión correcta.,,,"Macil fait partie de tout ce bordel? Je ne sais pas quoi penser, j'espère que tu feras le bon choix..",,,,마실? 이 문제의 장본인 중 한 명이라고? 정말이지 모르겠어. 부디 현명한 판단을 내리길 바래.,Macil? Een deel van deze puinhoop? Ik weet niet wat ik moet denken. Ik hoop dat je de juiste beslissing neemt.,,O Macil? Fazendo parte dessa confusão toda? Eu não sei o que pensar. Espero que você tome a decisão certa.,,,"Мэйсил? Замешан в этом дерьме? Я даже не знаю, что и думать. Я надеюсь, ты сделаешь правильный выбор.", -"Do I trust Macil, who has risked his life for the Front, or some ugly spook? I don't know. But you I trust.",TXT_SUB_LOG78,,,,"Mám věřit Macilovi, který riskoval svůj život kvůli Frontě, nebo nějakému ošklivovi? Já nevím. Ale tobě věřím.","Ob ich Macil vertraue, der sein Leben für die Front riskiert hat, oder einer hässlichen Schreckgestalt? Ich weiß nicht - aber dir vertraue ich. ",,,"¿Confío en Macil, que ha arriesgado su vida por el Frente, o en un espectro feo? No lo sé. Pero en ti sí confío.",,,"Et ce que je fais confiance à Macil qui a risqué sa vie pour le Front, où un affreux jojo? J'en sais rien, mais je fais confiance à toi.",,,,"마실은 프론트를 위해 싸워온 사람이라 의심할 수가 없어. 저 못난이가 거짓말을 하는 걸까? 모르지만, 난 너 만을 믿어.","Vertrouw ik Macil, die zijn leven heeft geriskeerd voor het Front, of een lelijke spook? Ik weet het niet. Maar jij vertrouw ik.",,"Se eu confio no Macil, que arriscou a sua vida pela Frente, ou num fantasma horroroso? Eu não sei, mas eu você eu confio.",,,"Кому верить: Мэйсилу, который не щадил своей жизни ради Сопротивления, или какому-то уродливому пугалу? Не знаю. Но я доверяю тебе. ", -Richter has taken over command of our forces. It looks like Macil has been deceiving us all along. His true allegiance was to the Order. What a snake.,TXT_SUB_LOG79,"STRIFE1.WAD: MAP10 - -(After killing Macil without having destroyed the converter in MAP24)",,,"Richter převzal velení našich sil. Zdá se, že nás Macil celou dobu klamal. Ve skutečnosti byl věrný Řádu. Slizák jeden.","Richter hat das Kommando über unsere Truppen übernommen. Es sieh aus, als ob Macil uns alle hintergangen hat und die ganze Zeit für den Orden arbeitete. Was für eine Ratte.",,,Richter ha tomado el mando de nuestras fuerzas. Parece que Macil nos ha estado engañando todo este tiempo. Su verdadera lealtad era a la Orden. Menuda serpiente.,,,"Richter à pris le contrôle de nos forces. Il semble que Macil nous a trompé tout ce temps. Sa vraie allégiance appartenait à l'Ordre, quel ordure..",,,"リヒターが指揮官の任を引き継いだ。マシルはずっと私達を騙していたなんて。 -あの人がオーダーに真の忠誠を誓っていたなんて、とんだ蛇神憑きだわ。",릭터가 저항군의 새로운 지도자가 될 거야. 내 생각엔 마실이 오랫동안 우리들을 속인 것 같아... 뱀 같은 자식.,Richter heeft het bevel over onze troepen overgenomen. Het lijkt erop dat Macil ons de hele tijd heeft bedrogen. Zijn ware trouw was aan de Orde. Wat een slang.,,O Richter assumiu o comando de nossas forças. Parece que o Macil nos enganou esse tempo todo. Sua verdadeira lealdade era à Ordem. Que traíra!,,,"Рихтер принял на себя командование нашими силами. Похоже, что Мэйсил обманывал всех нас с самого начала. На самом деле он был предан Ордену. Подлец.", -Damned impressing entranceway. But what we are searching for is on another level. Head down.,TXT_SUB_LOG80,STRIFE1.WAD: MAP26,,,"Zatraceně působivý vchod. Ale to, co hledáme, je na jiném patře. Jdi dolů.",Verdammt eindrucksvoller Eingang. Aber was wir suchen ist woanders. Lass uns runtergehen.,,,Una entrada tremendamente impresionante. Pero lo que buscamos está en otro nivel. Ve abajo.,,,"Une entrée sérieusement impressionante. Ce que l'on cherche est à un autre étage, descends.",,,威風堂々とした玄関ね。でも私達が調べるのは別の階よ。慎重にね。,또 전형적인 멋진 입구네. 하지만 우리가 찾는 것은 또 다른 구역에 있어. 밑으로 향해.,Vervloekt indrukwekkende toegangsweg. Maar wat we zoeken is op een ander niveau. Hoofd naar beneden.,,Que entrada bem impressionante. Mas o que procuramos está em outro nível. Desça.,,,Этот чёртов фасад впечатляет! Но нам нужно на другой этаж. Не высовывайся!, -What a shame. Our technology is being wasted on torture instead of life.,TXT_SUB_LOG81,STRIFE1.WAD: MAP24,,,Taková škoda. Naše technologie je plýtvána na mučení místo života.,Was für eine Schande. Unsere Technologie wird für Folter anstatt für Leben verschwendet.,,,Que pena. Nuestra tecnología se está desperdiciando en tortura en vez de vida.,,,"C'est tellement dommage. Notre technologie est gâchée, utilisée pour la torture plutôt que sauver des vies.",,,残念だな。我々の技術が拷問の為だけに浪費されるとは。,비극적이야. 우리 기술이 생명을 살리는 데 쓰이기는 커녕 고문하는 데 쓰이고 있잖아.,Wat jammer. Onze technologie wordt verspild aan marteling in plaats van leven.,,É uma pena. Nossa tecnologia sendo desperdiçada com tortura ao invés de salvar vidas.,,,"Какой кошмар. Наша технология используется для пыток, а не для жизни.", -"Being vain as hell, they mark their temples with big banners.",TXT_SUB_LOG82,STRIFE1.WAD: MAP21,,,"S takovou ješitností není divu, že si své chrámy značí velkými prapory.","Eitel wie sie sind, markieren sie ihre Tempel mit riesigen Bannern.",,,"Siendo tan malditamente engreídos, marcan sus templos con grandes estandartes.",,,"Avec leur orgeuil à la noix, je me ne doutais pas un instant qu'ils allaient mettre d'énormes bannières partout.",,,うぬぼれが酷いな、あいつらの寺院はデカいバナーが目に付く。,"고통을 더하자면, 자기네 신전에 커다란 기를 세웠어.","Tevergeefs als de hel, markeren ze hun tempels met grote spandoeken.",,Esses caras são vaidosos pra caramba. Eles marcam os seus templos com esses grandes estandartes.,,,"Они спесивы до ужаса, раз украшают свои храмы большими флагами.", -Another Sigil piece. We are one step closer to freedom. And you are one step closer to me.,TXT_SUB_LOG83,"STRIFE1.WAD: MAP27 - -(After defeating the Loremaster and collecting the fourth Sigil piece with either Macil or the Oracle alive)",,,Další díl Pečeti. Jsme o krok blíž ke svobodě. A ty jsi o krok blíž ke mě.,Noch ein Sigil-Teil. Wir sind der Freiheit einen Schritt näher. Und du bist mir einen Schritt näher.,,,Otra pieza del emblema. Estamos un paso más cerca de la libertad. Y tú un paso más cerca de mí.,,,"Encore une pièce du Sigil. Un pas de plus vers la liberté, et un pas de plus vers moi.",,,"更なるシジルの欠片だ。私達の自由にまた一歩近づいたわ。 -そして私にも一歩近づいている。",또 다른 시질 조각이야. 자유를 향한 길이 거의 얼마 안 남았어. 나와 만나는 길도 얼마 안 남았고.,Nog een Sigil stuk. We zijn een stap dichter bij de vrijheid. En jij bent een stap dichter bij mij.,,Mais uma peça do Sigilo. Estamos cada vez mais próximos da liberdade. E você cada vez mais próximo de mim.,,,Очередной фрагмент Сигила. Теперь мы ещё на шаг ближе к освобождению. А ты — ещё на шаг ближе ко мне., -"From the looks of it, we need the full Sigil to unlock this puppy. Something tells me this is the end of the rainbow.",TXT_SUB_LOG84,STRIFE1.WAD: MAP27,,,"Vypadá to, že tohohle mazlíčka jde otevřít pouze s úplnou Pečetí. Něco mi říká, že jsme našli konec duhy.","Wie es aussieht brauchen wir das komplette Sigil um das Ding hier zu öffnen. Etwas sagt mir, dass wir am Ende unserer Reise angekommen sind.",,,Parece que necesitamos el Emblema completo para abrir este pequeñín. Algo me dice que este es el final del arcoiris.,,,On dirait qu'il nous faut toutes les pièces du Sigil pour ouvrir ce joujou. Quelque chose me dit que c'est là que l'arc-en-ciel finit.,,,"この形状を見た所、解除するには完成したシジルを持って、ちっこい台座に乗るんだわ。 -誰もが雨上がりの虹を見るために。","열쇠 구멍의 모습을 보아하니, 완성된 시질이 있어야만 열 수 있는 것 같아. 이 모든 모험의 도착지점인 것 같기도 하고.","Zoals het er nu uitziet, hebben we de volledige Sigil nodig om deze pup te ontgrendelen. Iets zegt me dat dit het einde van de regenboog is.",,"Pelo que parece, precisamos do Sigilo completo para destrancar essa belezinha. Algo me diz que este é o fim do arco-íris.",,,"Судя по всему, открыть этот замок сможет только завершённый Сигил. Что-то мне подсказывает, что мы достигли конца радуги!", +Random comment when the player dies with Classic Mode turned off",,,"Dobře, nestěžuju si, ale příště bychom mohli zkusit způsob, po kterém nezůstanou kýble krve.","Okay, jeg klager ikke, men næste gang kan vi måske prøve den måde, der ikke er spandevis af blod.","Ok, ich will nicht meckern, aber beim nächsten Mal sollte das mit weniger Blutvergießen vonstatten gehen.",,,"Muy bien, no me quejo, pero la próxima vez deberíamos probar el método que no sea una masacre.",,"Hyvä on, en minä mitään valita, mutta ensi kerralla voisimme kokeilla tapaa, joka ei sisällä ämpärikaupalla verta.","Bon, je ne me plains pas, mais la prochaine fois, essayons de faire sans foutre du sang partout?","Igazából nem akarok panaszkodni, de legközelebb próbáljunk meg egy kevsébé véres módszert.","Va bene, non che voglia lamentarmi, ma magari la prossima volta ",大丈夫、次は血のバケツをぶち撒けない方法を試した方がいい。,"이런... 비꼬는 건 아닌데, 다음번엔 유혈사태를 일으키지 않고 일을 해결해보자.","Oké, ik klaag niet, maar de volgende keer kunnen we misschien de manier proberen waarop dat geen emmers bloed is.","Greit, jeg klager ikke, men neste gang kan vi prøve en vei som ikke er bøtter med blod.","Dobra, nie narzekam, ale następnym razem może spróbujemy drogi, która nie jest wiadrami krwi.","Tá bem, não estou reclamando. Mas da próxima vez vamos tentar de um jeito que não seja sangue jorrando pra tudo que é lado.",,"În regulă, nu mă plâng, dar data viitoare încercăm calea care nu duce la găleți de sânge.","Я не жалуюсь, но, может, в следующий раз попробуем не проливать реки крови?",,"Okej, jag klagar inte, men nästa gång kanske vi ska försöka på det sätt som inte innebär hinkar med blod.","Pekala, şikayet etmiyorum ama bir dahaki sefere kova kova kan olmayan yolu deneyebiliriz." +"We've been through endless hallways before, but I swear, these walls are moving as we pass.",TXT_SUB_LOG62,MAP19: Cross-shaped room at the beginning.,,,"Už jsme předtím byli v nekonečných chodbách, ale přísahám, že tyhle stěny se hýbou.","Vi har været igennem endeløse gange før, men jeg sværger, at disse vægge bevæger sig, mens vi passerer.","Wir sind ja schon durch endlose Flure gegangen, aber ich könnte schwören, dass sich die Wände hier bewegen.",,,"Ya hemos pasado por pasillos sin fin otras veces, pero juro que estas paredes se están moviendo a nuestro paso.",,"Olemme ennenkin kulkeneet loputtomia käytäviä pitkin, mutta voisin melkein vannoa näiden seinien liikkuvan sitä mukaa kun läpi käymme.","J'ai déja fais un tour dans un couloir sans fin comme ça, mais je jure que les murs bougent avec nous.","Volt már dolgunk végtelen hosszú folyosóval, de esküszöm olyan érzésem van, mintha velünk együtt mozognának a falak.","Abbiamo superato chissà quanti corridoi fino ad ora, ma ti giuro, questi muri si muovono mentre camminiamo.","以前に私達は無限へ通じる玄関を通ったかと思うが、誓おう、 +通り過ぎた時に壁が動いていたからだと。","난감한 곳들을 다녀갔지만, 여기는 뭔가 새로워. 걸어갈 때마다 벽이 움직이는 것 같거든...","We zijn al eens door eindeloze gangen geweest, maar ik zweer het, deze muren bewegen zich in de loop van de tijd.","Vi har gått gjennom endeløse korridorer før, men disse veggene beveger seg når vi går forbi.","Przechodziliśmy już przez nieskończone korytarze, ale przysięgam, że te ściany się ruszają, gdy przechodzimy.","Já passamos por inúmeros corredores antes, mas eu juro, essas paredes ficam se mexendo enquanto a gente passa.",,Am mai fost prin holuri nesfârșite dar jur că zidurile ăstea se mișcă odată cu noi.,"Мы уже повидали достаточно бесконечных коридоров, но я готова поклясться: эти стены передвигаются, когда мы на них не смотрим.",,"Vi har gått igenom ändlösa korridorer förut, men jag svär att de här väggarna rör sig när vi passerar.","Daha önce de sonsuz koridorlardan geçtik, ama yemin ederim, bu duvarlar biz geçerken hareket ediyor." +"Well, you gotta figure. Military leader equals lots of bad guys.",TXT_SUB_LOG63,MAP16,,,"No, dává to smysl. Armádní vůdce rovná se hodně padouchů.",Det må man regne ud. Militær leder er lig med masser af skurke.,Das war ja klar. Militärischer Anführer bedeutet jede Menge Bösewichte.,,"Nu, ĉi tio estis divenebla: «Militestro» estas egala al multaj malbonuloj.","Bueno, era de imaginar: «Líder militar» equivale a muchos tipos malos.",,Mietipä sitä; sotapäällikkö vastaa monta pahista.,"Bon, fallait y penser. Chef militaire, ça veut dire beaucoup de types armés.","Ki gondolta volna, hogy egy katonai vezetőt egy rakás rossz fiú fog védeni.","Beh, c'era da aspettarselo. Capo militare significa un sacco di cattivi.",さて、貴方はフィギュアを得た。軍隊指揮者は大勢の悪人に匹敵するわ。,이거 정말 뻔하네. 군대 우두머리의 심복들은 다 난폭하고 둔하지.,"Nou ja, je moet het wel beseffen. Militair leider is gelijk aan veel slechteriken.","Vel, du må skjønne. Militærleder er lik mange skurker.","No cóż, trzeba to sobie wyobrazić. Przywódca wojskowy równa się wielu złym ludziom.","Olha só, quem diria. Líder militar é igual a um monte de caras malvados.",,"Ei, dă-ți seama. Lider militar înseamnă mulți băieți răi.",Сам понимаешь. Военный лидер — всё равно что куча плохих парней.,,Det måste man räkna ut. Militär ledare är lika med många skurkar.,Bunu anlamalısın. Askeri lider eşittir bir sürü kötü adam. +Don't give up. This is it. Straight ahead.,TXT_SUB_LOG64,MAP19: Last room (southwestern).,,,"Nevzdávej se, tohle je ono. Jdi rovně.",Du må ikke give op. Det er nu. Lige fremad.,Gib nicht auf. Direkt voraus.,,,No te rindas. Vas bien: justo adelante.,,"Älä luovuta. So nyt tässä, suoraan edessä.","Abandonne pas, on y est. Juste devant.",Ne add fel. Ez lesz az. Éppen előttünk.,Non arrenderti. Siamo arrivati. Dritto in fronte a te.,諦めないで。これでいいんだ。真っ直ぐ行こう。,포기하지 마. 거의 다 왔어. 가까이 왔다고.,Geef niet op. Dit is het. Rechtdoor.,Ikke gi opp. Her er det. Rett fram.,Nie poddawaj się. To jest to. Prosto przed siebie.,Não desista. Esta é a hora. Siga reto adiante.,,Nu te da bătut. Asta e. Drept înainte.,Не падай духом. Вот оно. Впереди.,,Ge inte upp. Det här är det. Rakt fram.,Sakın pes etme. İşte burası. Dümdüz ilerle. +"Next time, we stop at a gas station and ask for directions.",TXT_SUB_LOG65,,,,Příště se zastavíme na benzince a zeptáme se na cestu.,Næste gang stopper vi ved en tankstation og spørger om vej.,Nächstes Mal halten wir an einer Tankstelle und fragen nach der Richtung.,,,A la próxima paramos en una gasolinera y preguntamos la dirección.,,Ensi kerralla pysähdytään huoltoasemalle kysymään suuntaneuvoja.,"La prochaine fois, on s'arrète à une station-service et on demande notre chemin.","Legközelebb amikor megállunk egy benzinkútnál, körbekérdezünk az irányzékkal kapcsolatban.","La prossima volta, ci fermiamo ad una stazione di servizio per chiedere indicazioni.",,다음엔 편의점 같은 건물에 들러서 그냥 방향을 묻자.,De volgende keer stoppen we bij een tankstation en vragen we de weg.,Neste gang stopper vi på en bensinstasjon og spør om veien.,Następnym razem zatrzymamy się na stacji benzynowej i zapytamy o drogę.,Da próxima vez vamos parar num posto de gasolina e perguntar onde fica.,,Data viitoare ne oprim la o benzinărie și întrebăm despre repere.,В следующий раз остановимся на заправке и спросим дорогу.,,Nästa gång stannar vi vid en bensinstation och frågar efter vägen.,Bir dahaki sefere benzin istasyonunda durup yol sorarız. +Oh no! More bells and whistles and nasty guys chasing us.,TXT_SUB_LOG66,MAP19: After coming across an alarm green door.,,,"Ale ne! Další fešné vymoženosti a zmetci, co nás pronásledují.","Åh nej! Flere klokker og fløjter og grimme fyre, der jagter os.",Oh nein. Noch mehr Lärm und Bösewichte auf unseren Fersen.,,,¡No puede ser! Más bombos y platillos y tipos malos persiguiéndonos.,,Voi ei! Lisää härpäkkeitä ja pahiksia jahtaamassa meitä.,Oh non! Encore des trucs et des choses et des sales types qui nous prennent en chasse.,"Jaj ne! Még több csicsás rész, és még annál is több gonosz a nyomunkban.",Oh no! Campane e fischietti e altri cattivi che ci inseguono.,あーらら!鐘と笛で更に厄介な奴等を呼び込んできたな。,"오, 안 돼! 삼엄한 경비에 피할 수도 없는 선택지라니.",Oh nee! Nog meer toeters en bellen en vervelende jongens die ons achterna zitten.,"Å, nei! Flere bjeller og fløyter og ekle fyrer som jager oss.","O nie! Więcej dzwonków i gwizdków i wrednych facetów, którzy nas gonią.",Ai não! Mais bugigangas e capangas vindo atrás de nós.,,Oh nu! Mai mulți băieți răi ne urmăresc!,"О, нет! Ещё больше свистелок, перделок и плохих парней, которые за нами гонятся.",,Åh nej! Fler klockor och visselpipor och otäcka killar som jagar oss.,Olamaz! Daha fazla zil ve düdük ve bizi kovalayan kötü adamlar. +"You know, from the outside, this place looks tiny.",TXT_SUB_LOG67,MAP15: After using a big lift next to a Reaver.,,,Zvenku tohle místo vypadalo drobounké.,Udefra ser det her sted lille ud.,Von außen sieht das hier irgendwie mickrig aus.,,"Nu, ĉi tiu loko aspektis malgranda de ekstere.","O sea, este lugar se veía enano desde fuera.","O sea, este lugar se veía enano desde afuera.","Oletko muuten huomannut, että ulkopuolelta katsottuna tämä paikka näyttää tosi pieneltä.","Tu sais, de l'extérieur, cet endroit à l'air super petit.","Azt hinné az ember, hogy sokkal kisebb ez a hely a kinti kinézet alapján.","Lo sai, da fuori, questo posto sembra piccolo.",外から見ると、此処は小さいみたいね。,"궁금한 게 있는데, 왜 안에 들어가면 커지는 걸까?","Weet je, van buitenaf ziet deze plek er klein uit.","Du vet, fra utsiden ser dette stedet lite ut.","Wiesz, z zewnątrz to miejsce wygląda na malutkie.","Sabe, vendo de longe esse lugar parece minúsculo.",,"Știi, din afară, locul ăsta arată mărunt.","Знаешь, снаружи это место кажется крошечным.",,"Du vet, från utsidan ser det här stället pyttelitet ut.",Dışarıdan bakınca burası çok küçük görünüyor. +"I'm getting a new enemy reading. Don't stop and stare, just waste 'em.",TXT_SUB_LOG68,,,,Zaznamenávám nového nepřítele. Nestůj tam a znič ho!,"Jeg får en ny fjendeudlæsning. Lad være med at stoppe op og stirre, bare smadr dem.","Ich habe eine neue Feindortung. Warum wartest du, mach sie alle!",,,"Tengo señales de un nuevo enemigo. No te pares a mirar, solo cárgatelo.",,Saan uuden lukeman vihollisista. Älä siihen jää töllöttämään; listi ne!,"J'ai un ping ennemi sur mon radar. Ne t'arrète pas, flingue-les.","Új ellenséget észlelek. Ne állj meg nézelődni, hanem nyírd ki őket.","Sto ricevendo segnali di altri nemici. Non fermarti a guardare, distruggili.",,네 주변에 적이 포착됐어. 그냥 쳐다보지 말고 어떻게든 해봐.,"Ik krijg een nieuwe vijandelijke lezing. Niet stoppen en staren, maar ze gewoon verspillen.","Jeg får en ny fiende på skjermen. Ikke stopp og stir, bare skyt dem.","Dostaję nowy odczyt wroga. Nie zatrzymuj się i nie gap, po prostu je zmarnuj.","Estou recebendo sinais de um novo inimigo. Nâo fique parado olhando, mete bala neles.",,"Citesc inamici în apropiere. Nu te oprii și holba, fă-i bucăți.","Вижу врагов. Не стой столбом, мочи их!",,"Jag får en ny fiende som läser av. Stanna inte och stirra, bara döda dem.","Yeni bir düşman okuması alıyorum. Durup bakma, sadece harca onları." +"I hate these forcefields. Look for the shut-off switch, it's gotta be nearby.",TXT_SUB_LOG69,STRIFE1.WAD: MAP15,,,"Nesnáším tahle silová pole. Porozhlédni se po nějakém vypínači, měl by být nablízku.",Jeg hader disse kraftfelter. Se efter slukkontakten. Den må være i nærheden.,"Ich hasse diese Kraftfelder. Such nach einem Schalter, er müsste in der Nähe sein.",,,"Odio estos campos de fuerza. Busca el interruptor de apagado, tiene que estar cerca.",,Vihaan näitä voimakenttiä. Etsi virtakatkaisinta; sen on pakko olla jossain lähettyvillä.,"Je déteste les champs de force. Trouve leur commandes, elles ne doivent pas être loin.","Utálom ezket az erőpajzsokat. Keresd egy kikapcsoló gombot, itt kell lennie valahol.","Odio questi campi di forza. Cerca il pulsante per disattivarlo, deve essere vicino.",私はフォースフィールドが憎いわ。遮断させるスイッチが近くにあるはずだわ。,이런 방어막들 정말 싫다니까. 저걸 끌 스위치를 찾아봐. 가까이에 있을 거야.,"Ik haat deze krachtvelden. Zoek naar de afsluitschakelaar, die moet in de buurt zijn.",Jeg hater disse kraftfeltene. Se etter bryteren. Den må være i nærheten.,"Nienawidzę tych pól siłowych. Szukajcie wyłącznika, musi być w pobliżu.","Odeio esses campos de força. Procure pelo interruptor de desligar, deve estar por perto.",,"Urăsc compurile de forță. Uită-te după un buton de oprire, trebuie să fie în apropiere.","Ненавижу эти силовые поля. Поищи выключатель, он где-то неподалёку.",,"Jag hatar de här kraftfälten. Leta efter avstängningsknappen, den måste vara i närheten.","Bu güç alanlarından nefret ediyorum. Kapatma düğmesini ara, yakında olmalı." +"Ooh, very impressive. Let's blow it up!",TXT_SUB_LOG70,MAP15: Pressing the switch to reveal the PC.,,,"Ó, velmi působivé. Co to nechat vybouchnout?",Meget imponerende. Lad os sprænge den i luften!,"Oh, sehr imposant. Jag ihn hoch!",,,Muy impresionante. ¡Destruyámoslo!,Muy impresionante. ¡Vamos a destruirla!,"Oo, aika vaikuttava. Posautetaan se!","Oooh, très impressionant! Faisons tout péter!",Felettébb lenyűgöző. Robbantsuk is fel!,"Aah, molto impressionante! Facciamolo saltare in aria!",あら、見事な物ね。是非とも火薬を献上しましょう。,"오우, 정말 이쁘네! 이제 터뜨리자!","Ooh, heel indrukwekkend. Laten we hem opblazen!",Veldig imponerende. La oss sprenge den!,"Ooh, bardzo imponujące. Wysadźmy to w powietrze!","Oohh, que impressionante! Vamos detoná-lo.",,"ooh, foarte impresionant. Să-l aruncăm în aer!",Очень впечатляюще. Давай взорвём!,,"Ooh, väldigt imponerande. Vi spränger den!","Ooh, çok etkileyici. Hadi havaya uçuralım!" +"Jump on the teleporter, let's blow this pop stand.",TXT_SUB_LOG71,,,,Skoč na teleportér a odpalme tenhle stánek se zmrzlinou.,"Hop på teleporteren, lad os sprænge denne popstand.",Spring in den Teleporter und jag das Ding hoch.,,,"Súbete al teletransporte, carguémonos este tinglado.",,Loikkaa kaukosiirtimelle; häivytään tästä mestasta.,"Saute dans le téléporteur, cassons nous d'ici.","Ugrás a teleportba, és robbantsuk az égig ezt a kuplerájt.","Salta sul teletrasporto, facciamo esplodere questo mortorio.",,텔레포터를 타고 이 놀이터를 벗어나자.,"Spring op de teleporter, laten we deze popstandaard opblazen.","Hopp på teleporteren, la oss sprenge denne kiosken.","Wskakuj do teleportera, wysadźmy to stoisko z popem.","Entre no teletransportador, vamos explodir este muquifo.",,"Sari în teleportor, să aruncăm în aer totul.",Прыгай в телепорт. Пора валить отсюда.,,"Hoppa på teleportern, låt oss spränga det här popståndet.","Işınlayıcıya atla, hadi şu pop standını havaya uçuralım." +"Wait, the Oracle said we would know him by his symbol of power. Are you thinking what I'm thinking?",TXT_SUB_LOG72,MAP16: Entrance.,,,"Počkat, Věštec říkal, že ho poznáme podle jeho symbolu moci. Myslíš na to samé, co já?","Vent, Oraklet sagde, at vi ville kende ham på hans kraftsymbol. Tænker du det samme som mig?","Warte, das Orakel sagte wir würden ihn an seinem Machtsymbol erkennen. Denkst du, was ich denke?",,,"Momento, el Oráculo ha dicho que lo reconoceríamos por su símbolo de poder. ¿Estás pensando lo mismo que yo?","Momento, el Oráculo dijo que lo reconoceríamos por su símbolo de poder. ¿Estás pensando lo mismo que yo?","Odota; Oraakkeli sanoi, että tunnistaisimme hänet hänen valtansa merkistä. Mietitkö samaa mitä minäkin?","Attend, l'Oracle nous a dit qu'on le reconnaitrerait de par son symbole de pouvoir.. Tu pense à la même chose que moi?","Várjunk csak, azt mondta az Orákulum, hogy felismerjük a jeléről. Te is arra gondolsz amire Én?","Aspetta, l'Oracolo aveva detto che lo avremmo riconosciuto tramite il suo simbolo del potere. Stai pensando quello che penso io?","ちょっと待って、オラクルは私達に彼のシンボルを辿ればわかると述べたか。 +貴方今、私と同じ事考えてる?","잠깐, 오라클이 전에 권력을 상징하는 문양을 따라가면 만날 수 있다고 했지? 너 나랑 같은 생각 하고 있지?","Wacht, het Orakel zei dat we hem zouden kennen aan zijn machtssymbool. Denk jij wat ik denk?","Vent, oraklet sa at vi ville kjenne ham igjen på maktsymbolet hans. Tenker du det samme som meg?","Czekaj, Wyrocznia powiedziała, że poznamy go po symbolu mocy. Myślisz o tym, co ja myślę?","Peraí, o Oráculo disse que reconheceríamos ele pelo seu símbolo de poder. Você está pensando o mesmo que eu?",,"Stai, Oracolul zicea că îl vom cunoaște după însemnul lui. Te gândeștila același lucru?","Подожди — Оракул сказал, что мы найдём его по символу власти. Ты думаешь о том же, о чём и я?",,"Vänta, Oraklet sa att vi skulle känna igen honom på hans kraftsymbol. Tänker du samma sak som jag?","Bekle, Kahin onu güç sembolünden tanıyacağımızı söylemişti. Sen de benim düşündüğümü mü düşünüyorsun?" +"These guys got a decorating idea that works, and they just beat it to death.",TXT_SUB_LOG73,,,,Tihle lidi dostali dobrý nápad na výzdobu a pak ho zadupali do země.,"Disse fyre har en dekorativ idé, som virker, og de slår den bare ihjel.","Diese Typen haben ein Design das funktioniert, aber sie haben es total übertrieben.",,,"Estos tipos tuvieron una idea de decoración que funciona, y la han matado a palos.",,"Näille tyypeille välähti yksi toimiva sisustusidea, ja he vain kuluttivat sen loppuun.",Cest types avaient une super bonne idée déco et ils ont fait n'importe quoi avec.,"Ezeknek az embereknek volt egy jó dekorációs ötlete, csak némileg túlzásba vitték.","Questi qua hanno avuto una buona idea di come decorare, e poi ci sono andati ben troppo oltre.",,"저놈들은 도움이 되는 생각을 가지고 있기는 한데, 다 쓸데없이 망치고 있어.","Deze jongens hebben een decoratief idee dat werkt, en ze hebben het gewoon doodgeslagen.","De har en dekorasjonsidé som funker, og så slår de den i hjel.","Ci kolesie mają pomysł na wystrój, który działa, a oni go po prostu zepsuli na śmierć.",Esses caras tinham uma idéia de decoração que funcionava e depois mandaram tudo pro saco.,,Tipii ăștia au o idee despre decorații în aplicare.,"У этих ребят была отличная идея декора, но они загубили её на корню.",,"De här killarna har en dekorationsidé som fungerar, och de bara slår ihjäl den.",Bu adamların işe yarayan bir dekorasyon fikri var ve onu öldüresiye dövüyorlar. +Did you see that weird spectre that came out of the Bishop's body? Where have I seen that before?,TXT_SUB_LOG74,MAP16: After killing the Bishop,,,"Viděl jsi ten divný přízrak, který vyšel z Biskupova těla? Kde jsem ho jen předtím viděla?","Så du det underlige spøgelse, der kom ud af biskoppens krop? Hvor har jeg set det før?","Hast du diesen seltsamen Schemen gesehen, der aus seinem Körper herauskam? Wo haben wir das schonmal gesehen?",,,¿Viste ese extraño espectro que salió del cuerpo del Obispo? ¿Donde lo he visto antes?,,"Näitkö tuon oudon aaveen, joka nousi Piispan ruumiista? Missä olen nähnyt sen aiemmin?",Tu a vu ce spectre bizarre qui est sorti du corps de l'évèque? On a pas vu ça quelque part avant?,Láttad azt a fura szellemet ami kijött a Püspök teteméből? Hol láttam én már azt?,Hai visto quello strano spettro che è uscito dal corpo del Vescovo? Dove l'ho già visto prima?,"ビショップの体から出てきたあの奇妙な幽体を見た? +以前に何処かで見た気がするけど?",그나저나 비숍 몸에서 튀어나왔던 검은 물체 봤어? 전에 본 적이 있나?,Zag je dat rare spook dat uit het lichaam van de bisschop kwam? Waar heb ik dat eerder gezien?,Så du det rare spøkelset som kom ut av biskopens kropp? Hvor har jeg sett det før?,"Widziałeś to dziwne widmo, które wyszło z ciała biskupa? Gdzie ja to już widziałem?",Você viu aquele espectro estranho que saiu do corpo do BIspo? Onde foi que eu já vi isso antes?,,Ai văzut acel spectru ieșind din Episcop? Unde am mai văzut asta?,"Видел тот странный фантом, вышедший из тела Епископа? Где я могла видеть такое раньше?",,Såg du det konstiga spöket som kom ut ur biskopens kropp? Var har jag sett det förut?,Piskoposun bedeninden çıkan o garip hayaleti gördün mü? Bunu daha önce nerede görmüştüm? +Judgment call time. Now that we got two pieces we might wanna return to base. What does your instinct tell you?,TXT_SUB_LOG75,,,,"Čas se rozhodnout. Teď, když máme dva díly, bychom se možná měli vrátit na základnu. Co ti říká intuice?","Det er tid til at dømme. Nu hvor vi har to stykker, bør vi måske vende tilbage til basen. Hvad siger dit instinkt dig?","Zeit für eine Gewissensentscheidung. Jetzt wo wir zwei Teile haben, sollten wir zur Basis zurückkehren. Was denkst du?",,,Hora del Juicio. Ahora que tienes dos piezas podríamos regresar a la base. ¿Qué te dice tú instinto?,,"Aika tehdä päätös: Nyt, kun meillä on kaksi osasta, saattaisimme haluta palata tukikohtaan. Mitä vaistosi sanoo?","C'est l'heure du jugement, on a deux pièce, il est temps de retourner à la base. Que te dit ton instinct?","Kupaktanács. Most, hogy megszereztün két darabot, vissza is térhetünk a bázisba. mit mond az ösztönöd?",È l'ora di decidere. Adesso che abbiamo due pezzi sarebbe il caso di tornare alla base. Cosa dice il tuo istinto?,,심판의 시간이야. 시질 두 조각을 모았으니 본부로 돌아가자. 이제 너의 본능은 무슨 해답을 내놓을까?,"Oordeel roep tijd. Nu we twee stukken hebben, willen we misschien terug naar de basis. Wat zegt je instinct je?","Tid for domsavsigelse. Nå som vi har to stykker, bør vi kanskje dra tilbake til basen. Hva sier instinktet ditt?","Czas na osąd. Teraz, kiedy mamy dwa kawałki, możemy chcieć wrócić do bazy. Co mówi ci twój instynkt?","Hora do julgamento. Agora que temos duas peças, talvez a gente queira voltar pra base. O que o seu instinto diz?",,Timpul să judecăm. Acum că avem două piese ne putem întoarce la bază. Ce-ți zice instinctul?,"Время решать. Теперь, когда у нас есть две части, мы можем вернуться на базу. Что твоя интуиция подсказывает тебе?",,Det är dags att döma. Nu när vi har två delar kanske vi borde återvända till basen. Vad säger din instinkt dig?,Karar verme zamanı. Elimizde iki parça olduğuna göre üsse dönmek isteyebiliriz. İçgüdülerin sana ne söylüyor? +"I have a report that the spectral energy we found near the Bishop is also present by the Oracle, let's be careful.",TXT_SUB_LOG76,MAP11: After killing the Bishop and going to MAP12's entrance,,,"Mám hlášení, že stejná přízračná energie, kterou jsme našli u Biskupa, se nachází také u Věštce. Měli bychom být opatrní.","Jeg har en rapport om, at den spektrale energi, vi fandt i nærheden af biskoppen, også er til stede ved oraklet, så lad os være forsigtige.","Ich habe einen Report, dass die spektrale Energie, die wir beim Bischof gefunden haben, auch beim Orakel präsent ist. Sei vorsichtig.",,,"Tengo un informe de que la energía espectral que encontramos cerca del Obispo también está presente junto al Oráculo, vayamos con cuidado",,"Sain tiedon, että aave-energiaa, jota löysimme Piispan läheltä, on läsnä myös Oraakkelin luona. Ollaan varovaisia.",J'ai un rapport que l'énergie spectrale que l'on a trouvé près de l'évèque est aussi près de l'Oracle. Faisons attention.,Egy beszámoló szerint az Orákulum körülötti lelki színkép megegyezik a Püspökével. Legyünk tehát óvatosak.,"Ho qua un rapporto che ci informa che l'energia spettrale che abbiamo trovato vicino il Vescovo è anche presente vicino l'Oracolo, dobbiamo essere attenti.","ビショップにもあったスペクトラルエネルギーがオラクルにも宿っているという +報告があるわ、気を付けて。","지금 보고를 받았는데, 비숍을 죽인 뒤에 나온 혼령의 기운이 오라클에게도 있데. 조심하자.","Ik heb een verslag dat de spectrale energie die we in de buurt van de bisschop vonden ook aanwezig is bij het Orakel, laten we voorzichtig zijn.","Jeg har en rapport om at den spektrale energien vi fant nær biskopen også er til stede ved oraklet, la oss være forsiktige.","Mam raport, że energia widmowa, którą znaleźliśmy przy Bishopie, jest również obecna przy Wyroczni. Bądźmy ostrożni.",Tenho relatos de que a energia espectral que encontramos perto do Bispo também está presente pelo Oráculo. Vamos com cuidado.,,"Am un raport care spune că energia spectrală a Episcopului e aceeași de pe Oracol, să fim atenți.","Мне доложили, что от Оракула исходит та же энергия, что и от того фантома, которого мы видели у Епископа. Будь начеку!",,"Jag har en rapport om att den spektrala energin som vi hittade nära biskopen också finns hos oraklet, vi måste vara försiktiga.","Piskopos'un yanında bulduğumuz spektral enerjinin Kahin'de de olduğuna dair bir rapor aldım, dikkatli olalım." +Macil? Part of this mess? I don't know what to think. I hope you make the right decision.,TXT_SUB_LOG77,,,,"Macil? Částí tohohle bordelu? Nevím, co si o tom mám myslet. Doufám, že se rozhodneš správně.","Macil? En del af dette rod? Jeg ved ikke, hvad jeg skal tro. Jeg håber, du træffer den rigtige beslutning.","Macil? Ein Teil dieser Schweinerei? Ich weiß nicht, was ich denken soll. Hoffentlich triffst du die richtige Entscheidung.",,,¿Macil? ¿Parte de este lío? No sé que pensar. Espero que tomes la decisión correcta.,,"Macil osa tätä sotkua? En tiedä, mitä ajatella. Toivon, että teet oikean päätöksen.","Macil fait partie de tout ce bordel? Je ne sais pas quoi penser, j'espère que tu feras le bon choix..",Macil? Benne lenne ebben a zűrzavarban? nem tudom mit higgyek. Remélem a jó döntést fogod hozni.,Macil? Parte di questa follia? Non so cosa pensare. Spero farai la decisione giusta.,,마실? 이 문제의 장본인 중 한 명이라고? 정말이지 모르겠어. 부디 현명한 판단을 내리길 바래.,Macil? Een deel van deze puinhoop? Ik weet niet wat ik moet denken. Ik hoop dat je de juiste beslissing neemt.,Macil? En del av dette rotet? Jeg vet ikke hva jeg skal tro. Jeg håper du tar den rette avgjørelsen.,"Macil? Część tego bałaganu? Nie wiem, co myśleć. Mam nadzieję, że podejmiesz właściwą decyzję.",O Macil? Fazendo parte dessa confusão toda? Eu não sei o que pensar. Espero que você tome a decisão certa.,,Macil? Parte la dezastrul ăsta? Nu știu ce să cred. Sper să iei decizia bună.,"Мэйсил? Замешан в этом дерьме? Я даже не знаю, что и думать. Я надеюсь, ты сделаешь правильный выбор.",,Macil? En del av den här röran? Jag vet inte vad jag ska tro. Jag hoppas att du fattar rätt beslut.,Macil mi? Bu karmaşanın bir parçası mı? Ne düşüneceğimi bilmiyorum. Umarım doğru kararı verirsiniz. +"Do I trust Macil, who has risked his life for the Front, or some ugly spook? I don't know. But you I trust.",TXT_SUB_LOG78,,,,"Mám věřit Macilovi, který riskoval svůj život kvůli Frontě, nebo nějakému ošklivovi? Já nevím. Ale tobě věřím.","Skal jeg stole på Macil, som har risikeret sit liv for fronten, eller på en grim spøgelse? Jeg ved det ikke. Men jeg stoler på dig.","Ob ich Macil vertraue, der sein Leben für die Front riskiert hat, oder einer hässlichen Schreckgestalt? Ich weiß nicht - aber dir vertraue ich. ",,,"¿Confío en Macil, que ha arriesgado su vida por el Frente, o en un espectro feo? No lo sé. Pero en ti sí confío.",,"Luotanko Maciliin, joka on antanut henkensä alttiiksi Rintamalle, vai johonkin rumaan kummitukseen? En tiedä. Mutta sinuun minä luotan.","Et ce que je fais confiance à Macil qui a risqué sa vie pour le Front, où un affreux jojo? J'en sais rien, mais je fais confiance à toi.","Macilnak hiszek aki kockára tette az életét a Frontért, vagy egy semmirekellőnek? Nem is tudom...de neked biztosan hiszek.","Di chi mi posso fidare, di Macil, che ha rischiato la vita per il Fronte, o di questo essere spettrale? Non lo so. Ma di te mi fido.",,"마실은 프론트를 위해 싸워온 사람이라 의심할 수가 없어. 저 못난이가 거짓말을 하는 걸까? 모르지만, 난 너 만을 믿어.","Vertrouw ik Macil, die zijn leven heeft geriskeerd voor het Front, of een lelijke spook? Ik weet het niet. Maar jij vertrouw ik.","Stoler jeg på Macil, som har risikert livet for Fronten, eller et stygt spøkelse? Jeg vet ikke. Men deg stoler jeg på.","Czy ufać Macilowi, który ryzykował życie dla Frontu, czy jakiemuś brzydkiemu upiorowi? Nie wiem. Ale tobie ufam.","Se eu confio no Macil, que arriscou a sua vida pela Frente, ou num fantasma horroroso? Eu não sei, mas eu você eu confio.",,"Dacă îl cred pe Macil, care și-a riscat viața pentru Front, sau un tip în armură? Nu știu. Dar în tine, cred.","Кому верить: Мэйсилу, который не щадил своей жизни ради Сопротивления, или какому-то уродливому пугалу? Не знаю. Но я доверяю тебе. ",,"Ska jag lita på Macil, som har riskerat sitt liv för fronten, eller på något fult spöke? Jag vet inte. Men dig litar jag på.","Cephe için hayatını riske atan Macil'e mi güveneyim, yoksa çirkin bir hortlağa mı? Bilmiyorum. Ama sana güveniyorum." +Richter has taken over command of our forces. It looks like Macil has been deceiving us all along. His true allegiance was to the Order. What a snake.,TXT_SUB_LOG79,MAP10: After killing Macil (Spectre) without having destroyed the converter in MAP24.,,,"Richter převzal velení našich sil. Zdá se, že nás Macil celou dobu klamal. Ve skutečnosti byl věrný Řádu. Slizák jeden.","Richter har overtaget kommandoen over vores styrker. Det ser ud til, at Macil har bedraget os hele tiden. Hans sande loyalitet var over for Ordenen. Sikke en slange.","Richter hat das Kommando über unsere Truppen übernommen. Es sieh aus, als ob Macil uns alle hintergangen hat und die ganze Zeit für den Orden arbeitete. Was für eine Ratte.",,,Richter ha tomado el mando de nuestras fuerzas. Parece que Macil nos ha estado engañando todo este tiempo. Su verdadera lealtad era a la Orden. Menuda víbora.,,"Richter on ottanut joukkomme komentoonsa. Näyttää siltä, että Macil on pettänyt meitä alusta alkaen. Hänen todellinen uskollisuutensa on ollut Veljeskunnalle; mikä käärme.","Richter à pris le contrôle de nos forces. Il semble que Macil nous a trompé tout ce temps. Sa vraie allégiance appartenait à l'Ordre, quel ordure..",Richter átvette az irányítást az egységeink felett. Úgy néz ki Macil mindvégig átvert minket. Igazából a Rend embere volt. Micsoda álnok kígyó.,Richter ha assunto il comando delle nostre forze. Sembra che Macil ci avesse ingannato fin dall'inizio. In realtà è sempre stato alleato con l'Ordine. Che serpente.,"リヒターが指揮官の任を引き継いだ。マシルはずっと私達を騙していたなんて。 +あの人がオーダーに真の忠誠を誓っていたなんて、とんだ蛇神憑きだわ。",릭터가 저항군의 새로운 지도자가 될 거야. 내 생각엔 마실이 오랫동안 우리들을 속인 것 같아... 뱀 같은 자식.,Richter heeft het bevel over onze troepen overgenomen. Het lijkt erop dat Macil ons de hele tijd heeft bedrogen. Zijn ware trouw was aan de Orde. Wat een slang.,Richter har overtatt kommandoen over styrkene våre. Det ser ut til at Macil har lurt oss hele tiden. Hans sanne lojalitet var til Ordenen. For en slange.,"Richter przejął dowodzenie nad naszymi siłami. Wygląda na to, że Macil cały czas nas zwodził. Jego prawdziwa wierność była dla Zakonu. Co za wąż.",O Richter assumiu o comando de nossas forças. Parece que o Macil nos enganou esse tempo todo. Sua verdadeira lealdade era à Ordem. Que traíra!,,Richter a preluat controlul asupra forțelor noastre. Se pare că Macil ne-a înșelat în tot acest timp. Aderărata lui loialitate era față de Ordin. Ce șarpe.,"Рихтер принял на себя командование нашими силами. Похоже, что Мэйсил обманывал всех нас с самого начала. На самом деле он был предан Ордену. Подлец.",,Richter har tagit över befälet över våra styrkor. Det verkar som om Macil har lurat oss hela tiden. Hans sanna lojalitet var till Orden. Vilken orm.,Richter kuvvetlerimizin komutasını devraldı. Görünüşe göre Macil başından beri bizi kandırıyormuş. Onun gerçek bağlılığı Tarikat'a imiş. Ne yılan ama. +Damned impressing entranceway. But what we are searching for is on another level. Head down.,TXT_SUB_LOG80,MAP26: Entrance.,,,"Zatraceně působivý vchod. Ale to, co hledáme, je na jiném patře. Jdi dolů.","Forbandede imponerende indgang. Men det, vi leder efter, er på et andet niveau. Hovedet nedad.",Verdammt eindrucksvoller Eingang. Aber was wir suchen ist woanders. Lass uns runtergehen.,,,Una entrada tremendamente impresionante. Pero lo que buscamos está en otro nivel. Ve abajo.,,Pahuksen vaikuttava sisäänkäynti. Mutta etsimämme on eri kerroksessa. Suuntaa alas.,"Une entrée sérieusement impressionante. Ce que l'on cherche est à un autre étage, descends.","Elég menő bejárat. Azonban másik emeleten van, amit keresünk. Irány lefelé.",Come ingresso è davvero notevole. Ma quello che cerchiamo si trova su un altro piano. Vai giù.,威風堂々とした玄関ね。でも私達が調べるのは別の階よ。慎重にね。,또 전형적인 멋진 입구네. 하지만 우리가 찾는 것은 또 다른 구역에 있어. 밑으로 향해.,Vervloekt indrukwekkende toegangsweg. Maar wat we zoeken is op een ander niveau. Hoofd naar beneden.,Imponerende inngangsparti. Men det vi leter etter er på et annet nivå. Ned med hodet.,"Cholernie imponujące wejście. Ale to, czego szukamy, jest na innym poziomie. Głowa w dół.",Que entrada bem impressionante. Mas o que procuramos está em outro nível. Desça.,,Impresionantă intrare. Dar ceea ce căutăm e la alt nivel. Mergi jos.,Этот чёртов фасад впечатляет! Но нам нужно на другой этаж. Не высовывайся!,,Jävligt imponerande entré. Men det vi söker är på en annan nivå. Huvudet neråt.,Etkileyici bir giriş yolu. Ama aradığımız şey başka bir seviyede. Baş aşağı. +What a shame. Our technology is being wasted on torture instead of life.,TXT_SUB_LOG81,MAP24: Hall to converter room.,,,Taková škoda. Naše technologie je plýtvána na mučení místo života.,Sikke en skam. Vores teknologi bliver spildt på tortur i stedet for liv.,Was für eine Schande. Unsere Technologie wird für Folter anstatt für Leben verschwendet.,,,Que pena. Nuestra tecnología se está desperdiciando en tortura en vez de vida.,,"Mikä häpeä: Teknologiaamme tuhlataan kidutukseen, sen sijaan että parantaisimme elämää.","C'est tellement dommage. Notre technologie est gâchée, utilisée pour la torture plutôt que sauver des vies.",Milyen kár. A technológiánkat kínzásra pazarolják az élet helyett.,Che peccato. La nostra tecnologia viene sprecata per la tortura invece che per la vita.,残念だな。我々の技術が拷問の為だけに浪費されるとは。,비극적이야. 우리 기술이 생명을 살리는 데 쓰이기는 커녕 고문하는 데 쓰이고 있잖아.,Wat jammer. Onze technologie wordt verspild aan marteling in plaats van leven.,For en skam. Teknologien vår kastes bort på tortur i stedet for liv.,Co za wstyd. Nasza technologia jest marnowana na tortury zamiast na życie.,É uma pena. Nossa tecnologia sendo desperdiçada com tortura ao invés de salvar vidas.,,Ce rușine. Tehnologia noastră e risipită pentru tortură în loc de a crea viață.,"Какой кошмар. Наша технология используется для пыток, а не для жизни.",,Vilken skam. Vår teknik slösas bort på tortyr i stället för liv.,Ne utanç verici. Teknolojimiz yaşam yerine işkence için harcanıyor. +"Being vain as hell, they mark their temples with big banners.",TXT_SUB_LOG82,MAP21: Entrance to MAP26 near to an Inquisitor's banner.,,,"S takovou ješitností není divu, že si své chrámy značí velkými prapory.","Fordi de er forfængelige som helvede, markerer de deres templer med store bannere.","Eitel wie sie sind, markieren sie ihre Tempel mit riesigen Bannern.",,,"Siendo tan malditamente engreídos, marcan sus templos con grandes estandartes.",,"Läpeensä turhamaisia kun ovat, he vuoraavat temppelinsä suurin tunnuslipuin.","Avec leur orgeuil à la noix, je me ne doutais pas un instant qu'ils allaient mettre d'énormes bannières partout.","Miután felettébb hiúk, ezért hatalmas zászlókkal díszítik a templomaikat.","Essendo vanitosi come pochi, marchiano i loro templi con degli stemmi.",うぬぼれが酷いな、あいつらの寺院はデカいバナーが目に付く。,"고통을 더하자면, 자기네 신전에 커다란 기를 세웠어.","Tevergeefs als de hel, markeren ze hun tempels met grote spandoeken.","Forfengelige som faen, markerer de templene sine med store bannere.","Próżni jak diabli, oznaczają swoje świątynie wielkimi transparentami.",Esses caras são vaidosos pra caramba. Eles marcam os seus templos com esses grandes estandartes.,,"Vanitate la maxim, își marchează templele cu steaguri imense.","Они спесивы до ужаса, раз украшают свои храмы большими флагами.",,Eftersom de är fåfänga som fan markerar de sina tempel med stora banderoller.,"Cehennem kadar kibirli oldukları için, tapınaklarını büyük pankartlarla işaretliyorlar." +Another Sigil piece. We are one step closer to freedom. And you are one step closer to me.,TXT_SUB_LOG83,MAP27: After killing the Loremaster with either Macil or the Oracle alive.,,,Další díl Pečeti. Jsme o krok blíž ke svobodě. A ty jsi o krok blíž ke mě.,Endnu et Sigil-stykke. Vi er et skridt nærmere friheden. Og du er et skridt tættere på mig.,Noch ein Sigil-Teil. Wir sind der Freiheit einen Schritt näher. Und du bist mir einen Schritt näher.,,,Otra pieza del emblema. Estamos un paso más cerca de la libertad. Y tú un paso más cerca de mí.,,Jälleen uusi Sinetin osanen. Olemme taas askeleen lähempänä vapautta. Ja sinä askeleen lähempänä minua.,"Encore une pièce du Sigil. Un pas de plus vers la liberté, et un pas de plus vers moi.",Egy másik pecsét darab. Egy lépéssel közelebb vagyunk a szabadsághoz. Te pedig egy lépéssel közelebb hozzám.,Un altro pezzo del Sigillo. Siamo ancora più vicini alla libertà. E tu sei ancora più vicino a me.,"更なるシジルの欠片だ。私達の自由にまた一歩近づいたわ。 +そして私にも一歩近づいている。",또 다른 시질 조각이야. 자유를 향한 길이 거의 얼마 안 남았어. 나와 만나는 길도 얼마 안 남았고.,Nog een Sigil stuk. We zijn een stap dichter bij de vrijheid. En jij bent een stap dichter bij mij.,Enda en Sigil-brikke. Vi er ett skritt nærmere friheten. Og du er ett skritt nærmere meg.,Kolejny kawałek Sigil. Jesteśmy o krok bliżej wolności. A ty jesteś o krok bliżej mnie.,Mais uma peça do Sigilo. Estamos cada vez mais próximos da liberdade. E você cada vez mais próximo de mim.,,Altă piesă de Sigiul. Suntem cu un pas mai aproape de libertate. Și tu ești cu un pas mai aproape de mine.,Очередной фрагмент Печати. Теперь мы ещё на шаг ближе к освобождению. А ты — ещё на шаг ближе ко мне.,,Ännu ett Sigil-stycke. Vi är ett steg närmare friheten. Och du är ett steg närmare mig.,Başka bir Sigil parçası. Özgürlüğe bir adım daha yaklaştık. Ve sen de bana bir adım daha yaklaştın. +"From the looks of it, we need the full Sigil to unlock this puppy. Something tells me this is the end of the rainbow.",TXT_SUB_LOG84,MAP27: Button to MAP28.,,,"Vypadá to, že tohohle mazlíčka jde otevřít pouze s úplnou Pečetí. Něco mi říká, že jsme našli konec duhy.","Som det ser ud nu, skal vi bruge hele Sigil'en for at låse denne hvalp op. Noget siger mig, at dette er enden af regnbuen.","Wie es aussieht brauchen wir das komplette Sigil um das Ding hier zu öffnen. Etwas sagt mir, dass wir am Ende unserer Reise angekommen sind.",,,Parece que necesitamos el Emblema completo para abrir este pequeñín. Algo me dice que este es el final del arcoiris.,,"Näyttää siltä, että tarvitsemme täyden Sinetin tämän veijarin avaamiseksi. Jotenkin tuntuu siltä, että sateenkaari päätyy tänne.",On dirait qu'il nous faut toutes les pièces du Sigil pour ouvrir ce joujou. Quelque chose me dit que c'est là que l'arc-en-ciel finit.,"Úgy néz ki az egész pecsét kell, hogy bejussunk itt. Azt sugallja nekem, hogy ez lesz valószínűleg a végkifejlett.","Da quel che sembra, abbiamo bisogno del Sigillo intero per accedere qua. Qualcosa mi dice che siamo alla fine del tunnel.","この形状を見た所、解除するには完成したシジルを持って、ちっこい台座に乗るんだわ。 +誰もが雨上がりの虹を見るために。","열쇠 구멍의 모습을 보아하니, 완성된 시질이 있어야만 열 수 있는 것 같아. 이 모든 모험의 도착지점인 것 같기도 하고.","Zoals het er nu uitziet, hebben we de volledige Sigil nodig om deze pup te ontgrendelen. Iets zegt me dat dit het einde van de regenboog is.",Det ser ut til at vi trenger hele sigillet for å låse opp denne valpen. Noe sier meg at dette er enden på regnbuen.,"Wygląda na to, że potrzebujemy pełnego Sigilu, aby odblokować tego szczeniaka. Coś mi mówi, że to koniec tęczy.","Pelo que parece, precisamos do Sigilo completo para destrancar essa belezinha. Algo me diz que este é o fim do arco-íris.",,"Din câte se pare, aven nevoie de întreg Sigiliul pentru a deschide puiul. Ceva îmi spune că ăsta e capătul curcubeului.","Судя по всему, открыть этот замок сможет только завершённая Печать. Что-то мне подсказывает, что мы достигли конца радуги!",,Som det ser ut nu behöver vi hela Sigil för att låsa upp den här valpen. Något säger mig att det här är slutet på regnbågen.,"Görünüşe göre, bu yavruyu açmak için Sigil'in tamamına ihtiyacımız var. İçimden bir ses bunun gökkuşağının sonu olduğunu söylüyor." You wield the power of the complete Sigil. What do you say we go get some closure.,TXT_SUB_LOG85,"STRIFE1.WAD: MAP12 (After killing the Oracle and collecting the final Sigil piece with both Macil and the Loremaster dead) @@ -10354,169 +12744,193 @@ OR MAP27 -(After defeating the Loremaster and collecting the final Sigil piece with Macil and the Oracle dead)",,,"Vládneš mocí složené Pečetě. Co říkáš na to, jít s tím vším skončit?","Du hast die Macht des kompletten Sigils. Was hälst du davon, wenn wir das hier beenden?",,,Empuñas el poder del Emblema completo. Que te parece si conseguimos algo de clausura.,,,Tu possède le pouvoir du Sigil complet. Ca te dit qu'on aille finir tout ça?,,,"貴方はもはや完全なシジルの力を行使できるわけね。 +(After defeating the Loremaster and collecting the final Sigil piece with Macil and the Oracle dead)",,,"Vládneš mocí složené Pečetě. Co říkáš na to, završit to tady?","Du har magten af det komplette sigil. Hvad siger du til, at vi får en afslutning?","Du hast die Macht des kompletten Sigils. Was hälst du davon, wenn wir das hier beenden?",,,Empuñas el poder del Emblema completo. Que te parece si conseguimos algo de clausura.,,Täyden Sinetin voima on hallussasi. Mitäpä jos hakisimme päätöstä. ,Tu possède le pouvoir du Sigil complet. Ca te dit qu'on aille finir tout ça?,"Tied a Pecsét teljes ereje. Mit szólnál ahhoz, ha rövidre zárnánk a dolgokat.",Hai il potere del Sigillo completo. Che ne dici di mettere fine a questa faccenda.,"貴方はもはや完全なシジルの力を行使できるわけね。 後は言いがかりでもしてここを閉鎖させましょう。 -",시질의 완전한 힘은 이제 네 손에 있어. 종지부를 찍을 준비 됐어?,Je gebruikt de kracht van de hele Sigil. Wat zeg je ervan als we de zaak gaan afsluiten.,,Você tem o poder do Sigilo completo em suas mãos. Que tal a gente ir atrás de um desfecho?,,,Теперь ты владеешь мощью завершённого Сигила. Мы уже близко — давай покончим с этим., -"High noon, my hero. Prepare to embrace glory.",TXT_SUB_LOG86,,,,"Souboj v pravé poledne, můj hrdino. Připrav se přijmout slávu.","Die Stunde ist gekommen, mein Held. Bereite dich auf Ruhm vor.",,,"Es la hora final, mi héroe. Prepárate para la gloria.",,,"Le soleil est au zénith, mon héros. Prépare toi à rencontrer ta gloire.",,,いい気分でしょ、私の英雄。栄光を受け入れる準備をしなさい。,"석양이 지고 있어, 나의 영웅. 영광을 누릴 준비해!","Hoog middaguur, mijn held. Bereid je voor om de glorie te omarmen.",,"Chegou a hora, meu herói. Se prepare para abraçar a glória.",,,"Самое время, мой герой! Ты будешь купаться в славе.", -"Well, so much for prognostication. Hold it, Macil is calling us back. Let's get out of here in one piece.",TXT_SUB_LOG87,"STRIFE1.WAD: MAP12 - -(After killing the Oracle with Macil alive)",,,"No, to by bylo pro předpovědi. Počkat, Macil nás volá zpět. Vypadněme odsud vcelku.","Nun, so viel zu Vorraussagungen. Moment, Macil ruft uns zurück. Lass uns hier heile heraus kommen.",,,"Bueno, tanto por un presentimiento. Espera, Macil nos reclama. Salgamos de aquí de una pieza.",,,"Bon, tant pis pour les pronostics. Attends, Macil nous demande de revenir. Rentrons un seul morceau.",,,"まあ予言なんてそんなものでしょ。 -ちょっと待って、マシルが帰還するように言ったわ。ここから抜け出しましょう。","웃기네. 이딴 예언 따위. 잠깐만, 마실이 우리들을 부르고 있어. 이제 여기를 나가자.","Nou, tot zover de prognose. Wacht even, Macil roept ons terug. Laten we hier heelhuids weggaan.",,"Bem, parece que não é hora de previsões. Peraí, o Macil está nos chamando de volta. Vamos tentar sair daqui inteiros.",,,"Да, это превзошло все наши ожидания. Подожди — Мэйсил вызывает нас назад. Давай выбираться отсюда.", -"I'm sorry, after up to my hips in blood I can't think of anything witty to say right now. Let's get back to Macil.",TXT_SUB_LOG88,,,,"Je mi líto, když jsem po boky v krvi, nemám nic co vtipného říct. Vraťme se k Macilovi.","Tut mir leid, aber bei so viel Blut fällt mir nicht Flapsiges mehr ein. Lass uns zu Macil zurückgehen.",,,,,,"Désolée, après m'être retrouvée jusqu'au hanches dans le sang, je n'ai rien de malin à dire. Rentrons voir Macil.",,,,미안. 피칠갑을 한 너의 모습을 보느라 할 말을 잃었어. 그냥 마실에게로 돌아가자.,"Het spijt me, na tot aan mijn heupen in bloed kan ik nu niets geestigs bedenken om te zeggen. Laten we teruggaan naar Macil.",,Desculpa. Após ficar coberta de sangue não consigo pensar em nada interessante pra dizer agora. Vamos voltar pro Macil.,,,, -"The factory is next to the mines. Richter must mean the mines of Degnin. The Degnin ore is magnetic and explosive, just the thing for shutting down force fields.",TXT_SUB_LOG89,STRIFE1.WAD: MAP23,,,"Továrna je vedle dolů. Richter musí mít na mysli doly degninu. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Das Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten.",,,"La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magético y explosivo, justo para apagar campos de fuerza. ","La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magnético y explosivo, justo para apagar campos de fuerza. ",,"L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. ",,,"工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 -デグニン石は綺麗だが可燃性で、フォースフィールドを消すにはうってつけよ。",공장은 광산 옆에 있어. 릭터가 데그닌 광산을 이야기한 것 같아. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지.,"De fabriek ligt naast de mijnen. Richter moet de mijnen van Degnin bedoelen. Het Degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden.",,"A fábrica fica próxima às minas. O Richter provavelmente se refere às minas de Degnin. O minério de Degnin é magnético e explosivo, perfeito para derrubar os campos de força.",,,"Вход на фабрику — рядом со спуском в шахты. Рихтер, должно быть, имел в виду шахты Дегнина. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. ", -"Mines, catacombs, sewers... What a first date!",TXT_SUB_LOG90,STRIFE1.WAD: MAP13,,,"Doly, kobky, stoky... skvělé první rande!","Minen, Katakomben, Kanalisationen... was für ein erstes Date!",,,"Minas, catacumbas, alcantarillas... ¡Menuda primera cita!",,,"Mines, catacombes, égouts.. Super premier rendez-vous!",,,鉱山、地下墓所、下水道...とんだ初デートだな!,"광산, 고대 묘지, 하수도. 데이트하기엔 딱 맞는 장소들이네!","Mijnen, catacomben, rioleringen.... Wat een eerste afspraakje!",,"Minas, catacumbas, esgotos... Que belo primeiro encontro!",,,"Шахты, катакомбы, канализации... Замечательное первое свидание!", -"I wish Richter had been a touch more specific. Hm, let's try over here.",TXT_SUB_LOG91,STRIFE1.WAD: MAP13,,,"Přála bych si, aby byl Richter trochu přesnější. Hm, zkusme to tadyhle.","Ich wünschte mir, dass Richter etwas präziser gewesen wäre. Hmm, lass es uns mal hier versuchen.",,,"Ojalá Richter hubiera sido un pelín más específico. Hm, probemos por aquí.",,,J'aurais bien voulu que Richter soit un peu plus spécifique. Hm.. Essayons ici.,,,"リヒターがもっと具体的な部分に触れてくれて欲しいが。 -あー、私らが試してみようか。","릭터가 좀 더 자세히 설명해 줬으면 좋았을 텐데. 흠, 여기서 해보자.","Ik wou dat Richter een beetje specifieker was geweest. Hm, laten we het hier eens proberen.",,"Bem que o Richter podia ter sido um pouco mais específico. Hmm, vamos tentar por alí.",,,"Я надеялась, что Рихтер будет чуть более конкретным. Ладно, давай посмотрим, что там.", -"I think we're... Oh, crap. I have no idea where we are.",TXT_SUB_LOG92,STRIFE1.WAD: MAP13,,,"Myslím že jsme... sakra. Nemám tušení, kde jsme.","Ich glaube wir sind... Oh, Mist. Ich habe keine Ahnung wo wir sind.",,,"Creo que estamos... Oh, mierda. No tengo ni idea de donde estamos.",,,"Je crois que.. Non, merde, j'ai aucune idée d'où on est!",,,"私が思うに...ああ、クソ。 -何処にあるかさっぱりわからないわ。",우리는 지금... 이런 제길. 여기가 어딘지 모르겠어.,"Ik denk dat we.... Oh, shit. Ik heb geen idee waar we zijn.",,"Acho que estamos... Ah, merda. Não faço a menor idéia onde estamos.",,,"Я думаю, мы... О, чёрт. Я понятия не имею, где мы.", -"This must be the ruins Richter's agents were searching for. Oh, watch out! Crusaders!",TXT_SUB_LOG93,STRIFE1.WAD: MAP25,,,"Tohle musí být ty ruiny, které Richterovi agenti hledali. A, bacha! Křižáci!","Dies müssen die Ruinen sein, die Richters Agent gesucht hat. Oh, aufpassen! Ordensritter!",,,"Estas deben ser las ruinas que el agente de Richter estaba buscando. Oh, ¡cuidado! ¡Cruzados!",,,"Ca doit être les ruines que les agents de Richter cherchaient. Attention, des croisés!",,,"ここがリヒターのエージェントが探していた遺跡のはず。 -あっと、気を付けて!クルセイダーよ!","릭터의 요원이 수색하던 유적지인가봐... 잠깐, 조심해! 크루세이더야!","Dit moet de ruïnes zijn waar de agenten van Richter naar op zoek waren. Oh, kijk uit! Kruisvaarders!",,"Estas devem ser as ruínas que o agente de Richter estava procurando. Ah, cuidado! Cruzados!",,,"Возможно, это те самые руины, которые искали агенты Рихтера... Осторожно! Крестоносцы!", -"Ugh, it's trying to regenerate. Blast it before I throw up!",TXT_SUB_LOG94,,,,"Fuj, snaží se to oživit. Odstřel to, než začnu zvracet!","Ugh, es versucht, sich zu regenerieren. Mach es fertig, bevor ich anfange zu kotzen.",,,"Ugh, está intentando regenerarse. ¡Reviéntalo antes de que vomite!",,,"Beurk, il essaie de se régénérer, incinère le avant que je ne vomisse!",,,,"으윽, 이게 재생하기 시작했어. 내가 토하기 전에 파괴해!","Ugh, het probeert te regenereren. Blast het voordat ik overgeven!",,"Argh, está tentando se regenerar. Detona essa coisa antes que eu vomite!",,,"О-о, оно пытается восстановиться. Добей его, пока меня не стошнило!", -"My friend, whatever it is we're fighting, it's more than the Order. Off to the mines!",TXT_SUB_LOG95,STRIFE1.WAD: MAP25,,,"Příteli, ať už bojujeme s čímkoliv, jde o víc než jen Řád. Do dolů!","Mein Freund, was auch immer es ist, dass wir bekämpfen, es ist mehr als der Orden. Ab zu den Minen!",,,"Amigo mío, lo que sea contra que estemos luchando, es más que la Orden. ¡A las minas!",,,"Mon ami, je ne sais ce contre quoi on se bat, mais c'est plus que l'Ordre. Allons dans les mines!",,,"友よ、私達が戦う相手が何であろうとも、オーダー以上のものはない。 -鉱山から離れましょう!","친구야, 우리가 싸우는 상대가 무엇인지는 모르겠지만, 오더보다 더한 존재인 것 같아. 광산으로 향하자!","Mijn vriend, wat het ook is waar we tegen vechten, het is meer dan de Orde. Naar de mijnen!",,"Meu amigo, seja lá o que estamos combatendo, é mais do que somente a Ordem. Vamos para as minas!",,,"Друг мой, с чем бы мы ни сражались, это нечто большее, чем просто Орден. К шахтам!", -"Without letting down your guard, look for deposits of ore.",TXT_SUB_LOG96,STRIFE1.WAD: MAP14,,,Opatrně se zkus podívat po ložiscích rudy.,Sei vorsichtig und halte Ausschau nach Erzvorkommen.,,,"Sin bajar la guardia, busca depósitos de mineral.",,,"Sans arrêter de faire attention, cherche des veines de minerai.",,,警戒を緩めることなく、鉱石の堆積所を探しましょう。,"조심해가면서, 그들이 캔 광석을 두는 곳을 찾아.","Zonder je waakzaamheid te laten verslappen, zoek je naar ertsafzettingen.",,Não baixe a sua guarda. Vamos procurar por depósitos de minério.,,,"Поищи залежи руды, но не теряй бдительности!", -"These poor souls are drones, their synaptic functions are jammed by RC implants. We destroy the transmitter and they are free!",TXT_SUB_LOG97,STRIFE1.WAD: MAP14,,,"Tihle chudáci jsou trubcové, jejich synaptické funkce jsou narušené na dálku ovládanými implantáty. Když zničíme vysílačku, budou svobodní!","Diese armen Seelen sind Drohnen, ihre synaptischen Funktionen werden von Implantaten blockiert. Wenn wir den Transmitter zerstören, sind sie frei.",,,"Estas pobres almas son zánganos. Sus funciones sinápticas están bloqueadas por implantes de control remoto. ¡Destruimos el transmisor, y son libres!",,,"Ces pauvres âmes sont des drones, leurs fonctions synaptiques sont brouillées par des implants radiocommandés. On détruit le transmetteur et ils sont libres!",,,"これら精神の乏しい労働者達は、シナプス機能をRCインプラントで妨害している。 -私達が送信機を破壊し皆を解放するんだ!","저 사람들은 불쌍한 광산의 노예들이야. 오더가 이식한 세뇌 장치 때문에 정상적인 뇌 기능을 잃었지. 전송기만 파괴한다면, 그들은 자유를 되찾을 수 있을 거야!","Deze arme zielen zijn drones, hun synaptische functies worden verstoord door RC-implantaten. We vernietigen de zender en ze zijn vrij!",,Esses pobres coitados são zangões. Suas funções sinápticas estão sendo bloqueadas por implantes de controle remoto. Se destruirmos o transmissor eles estarão livres!,,,"Эти несчастные души — дроны. Сигнал, поступающий на импланты, полностью подавляет их сознание. Давай уничтожим передатчик и освободим их!", -"Command says the transmitter is shielded by a force field. So two birds, one stone, free the drones and practice with the ore.",TXT_SUB_LOG98,STRIFE1.WAD: MAP14,,,"Velení říká, že vysílačka je chráněná silovým polem. Dvě mouchy jednou ranou: osvobodíme vězně a vyzkoušíme si, jak s tou rudou.","Die Kommandozentale sagt, der Transmitter sei von einem Kraftfeld geschützt. So, zwei Fliegen, eine Klatsche, befreie die Drohnen und übe mit dem Erz.",,,"El Comando dice que el transmisor está protegido por un campo de fuerza. Dos pájaros de un tiro, libera a los zánganos y practica con el mineral.",,,"La commandement me dit que le transmetteur est protégé par un champ de force. Ca fait d'une pierre de coups. On libère les drones, et on s'entraîne avec le minerai.",,,"司令官は送信機がフォースフィールドに守られていると言っていた。 -そこを潰せば鉱山と労働者を解放、一石二鳥だな。",본부가 말하길 전송기는 방어막에 의해 보호받고 있대. 광석을 사용하는 방법을 연습하면서 노예들을 해방한다면 일석이조일 거야.,"Het commando zegt dat de zender is afgeschermd door een krachtveld. Dus twee vogels, een steen, bevrijden de drones en oefenen met het erts.",,O comando diz que o transmissor está protegido por um campo de força. Dois coelhos numa tacada só. Liberte os zangões e teste o minério.,,,"Штаб говорит, что передатчик защищён силовым полем. Ты освободишь дронов и испытаешь руду — одним выстрелом двух зайцев!", -"My suggestion is, toss the ore at the forcefield and then blast it. The resulting compression should create a magnetic blanket and turn off the lights.",TXT_SUB_LOG99,STRIFE1.WAD: MAP14,,,"Můj návrh je, hoď rudu na to silové pole a pak ji odstřel. Výsledná komprese by měla vytvořit magnetický povlak a vypnout pole.","Mein Vorschlag wäre, das Erz vor das Kraftfeld zu legen und dann explodieren zu lassen. Die resultierende Kompression sollte ein Magnetfeld erzeugen und die Lichter ausgehen lassen.",,,"Mi sugerencia es, tirar el mineral hacia el campo de fuerza y luego reventarlo, la presión resultante debería crear un manto magnético y apagar las luces.",,,Ma suggestion: jette le minerai sur le champ de force puis tire dessus. La compression qui en résulte devrait créer un champ magnétique qui va désactiver les lumières.,,,"私の案はフォースフィールドの近くに鉱石を置き撃って爆発させる方法よ。 -その結果、圧縮されていた磁場の反動で光を打ち消すわ。","조언을 찾는다면, 광석을 방어막에 가까이 놔둔 뒤 쏴봐. 광석이 커다란 자기장을 만들 테고, 방어막을 완전히 무력화 시킬 거야. 불 끄는거지!",Mijn suggestie is om het erts naar het krachtveld te gooien en het vervolgens op te blazen. De resulterende compressie zou een magnetische deken moeten creëren en de lichten moeten doven.,,Minha sugestão é que você arremesse o minério no campo de força e o detone. A explosão vai criar um campo magnético e apagar as luzes.,,,"Мой план: бросить руду поближе к силовому полю и взорвать её. Взрыв создаст магнитное поле, которое накроет электронику и отрубит её.", -Now on to the factory. Exit the mines and you can't miss it!,TXT_SUB_LOG100,STRIFE1.WAD: MAP16,,,A teď do továrny. Vyjdi z dolů a nemůžeš to minout.,Und nun zur Fabrik. Verlasse die Minen und du kannst sie nicht verpassen.,,,Ahora vamos a la fábrica. ¡Sal de las minas y no puedes perderlo!,,,"Bon, maintenant, l'usine! Sors des mines et tu peux pas la rater!",,,今すぐ工場へ向かおう。鉱山を出たら見逃すなよ!,이제 공장으로 향하자. 광산을 나가면 더 재밌는 모험이 펼쳐질 거야!,Nu naar de fabriek. Verlaat de mijnen en je kunt het niet missen!,,"Agora, para a fábrica. Saia das minas e não vai ter como errar.",,,"Теперь — на фабрику. Выйди из шахты, и ты сразу увидишь вход!", -"Sorry, hero, this is all new to me.",TXT_SUB_LOG101,STRIFE1.WAD: MAP20,,,"Promiň, hrdino, tohle všechno je pro mě nové.","Entschuldigung, mein Held, das ist alles neu für mich.",,,"Lo siento, héroe, esto es nuevo para mí.",,,"Désolé, héros, tout cela est nouveau pour moi.",,,ごめんなさい、これは初耳なの。,"미안, 영웅 친구... 이런 곳은 처음 봐.","Sorry, held, dit is allemaal nieuw voor mij.",,"Foi mal, meu herói, tudo isso é novo pra mim.",,,"Извини, герой. Для меня это всё в новинку.", -I'm reading massive neural wave distortions from straight ahead. I think we've found it.,TXT_SUB_LOG102,STRIFE1.WAD: MAP20,,,"Detekuju obří rušení nervových vln přímo před námi. Myslím, že jsme to našli.","Ich empfange massive neurale Verzerrungen direkt voraus. Ich denke, wir haben sie gefunden.",,,Estoy leyendo distorsiones de ondas neuronales masivas adelante. Creo que la hemos encontrado.,Estoy leyendo distorsiones neuronales masivas adelante. Creo que la hemos encontrado.,,Je recois des distorsions neurales colossales devant nous. Je crois que nous l'avons trouvé. ,,,重い神経波の歪曲が直に届いたわ。私達はそれを見つけたという事よ。,앞쪽에서 거대한 신경교란 파장이 감지되고 있어. 우리가 찾아낸 것 같아.,Ik lees enorme neurale golfvervormingen van rechtdoor. Ik denk dat we het gevonden hebben.,,Estou captando enormes distorções de rede neural mais adiante. Acho que encontramos.,,,"Я вижу мощный источник помех прямо по курсу. Похоже, мы нашли конвертер.", -Just when I think we've seen it all! They go in human and come out... I dont even want to think about it.,TXT_SUB_LOG103,STRIFE1.WAD: MAP24,,,"Zrovna, když jsem myslela, že jsme to všechno viděli! Dovnitř jdou jako lidé a vyjdou... ani na to nechci myslet.","Und da denkt man, man hätte schon alles gesehen. Die kommen als Menschen rein und kommen raus als... Ich möchte gar nicht drüber nachdenken.",,,¡Justo cuando creía haberlo visto todo! Entran humanos y salen... No quiero ni pensarlo. ,¡Justo cuando creía haberlo visto todo! Entran humanos y salen... No quiero ni pensarlo.,,"Et quand je pense avoir tout vu.. Des humains entrent, et puis.. Non, je ne veux pas y penser. ",,,"今まで見てきたことについて考えている! -奴は人の内部から出てくる...それについて考えたくないわ。",이렇게 끔찍한 모습을 보게 되다니! 멀쩡한 사람이 저곳에 들어갔다 나온 모습을... 차마 생각하기도 싫어.,Net nu ik denk dat we het allemaal hebben gezien! Ze gaan in de mens en komen eruit.... Ik wil er niet eens over nadenken.,,E eu achei que já tinha visto de tudo! Eles entram humanos e saem... eu não quero nem pensar nisso.,,,"А я-то думала, что хуже уже не будет! Они входят людьми, а выходят... Не хочу даже думать об этом.", -The Oracle was right. Macil's gone nuts. He just knowingly sent 200 men to their death. I want vengeance. For the dead and for the living dead!,TXT_SUB_LOG104,STRIFE1.WAD: MAP24,,,Věštec měl pravdu. Macil zešílel. Jen tak poslal dvě stě mužů na smrt. Chci odplatu - za mrtvé i živé mrtvé!,Das Orakel hatte Recht. Macil hat den Verstand verloren. Er hat gerade absichtlich 200 unserer Leute in den Tod geschickt. Ich will Rache! Für die Toten und für die lebenden Toten.,,,Macil se ha vuelto loco. Conscientemente ha enviado 200 hombres a su muerte. ¡Quiero venganza! ¡Por los muertos y los muertos vivientes!,Macil se ha vuelto loco. Conscientemente envió a 200 hombres a su muerte. ¡Quiero venganza! Por los muertos y por los muertos vivientes!,,"Macil a complètement perdu les pédales! Il a envoyé 200 hommes se faire tuer, et il le savait! Il faut les venger, pour eux et pour leurs camarades!",,,"オラクルが正しかった。マシルはイカれていたなんて。 +",시질의 완전한 힘은 이제 네 손에 있어. 종지부를 찍을 준비 됐어?,Je gebruikt de kracht van de hele Sigil. Wat zeg je ervan als we de zaak gaan afsluiten.,"Du har kraften til hele sigillet, og du kan bruke det. Hva sier du til å få en avslutning?","Władasz mocą kompletnego Sigilu. Co powiesz na to, żebyśmy się zamknęli.",Você tem o poder do Sigilo completo em suas mãos. Que tal a gente ir atrás de um desfecho?,,Ai puterea întregului Sigiliu. Ce zici dacă primim o încheiere?,Теперь ты владеешь мощью завершённой Печати. Мы уже близко — давай покончим с этим.,,Du har makten över hela Sigil. Vad sägs om att vi går och avslutar det hela.,"Sigil'in tamamının gücüne sahipsin. Ne dersin, gidip biraz kapanış yapalım mı?" +"High noon, my hero. Prepare to embrace glory.",TXT_SUB_LOG86,,,,"Souboj v pravé poledne, můj hrdino. Připrav se přijmout slávu.","Klokken tolv, min helt. Gør dig klar til at omfavne æren.","Die Stunde ist gekommen, mein Held. Bereite dich auf Ruhm vor.",,,"Es la hora final, mi héroe. Prepárate para la gloria.",,"Ratkaisun hetki, sankarini. Valmistaudu pukeutumaan kunniaan.","Le soleil est au zénith, mon héros. Prépare toi à rencontrer ta gloire.",Eljött az idő hősöm. Ragadd meg a lehetőséget.,"Mezzogiorno di fuoco, mio eroe. Preparati ad abbracciare la gloria.",いい気分でしょ、私の英雄。栄光を受け入れる準備をしなさい。,"석양이 지고 있어, 나의 영웅. 영광을 누릴 준비해!","Hoog middaguur, mijn held. Bereid je voor om de glorie te omarmen.","Klokka er tolv, min helt. Forbered deg på å omfavne æren.","W samo południe, mój bohaterze. Przygotuj się na przyjęcie chwały.","Chegou a hora, meu herói. Se prepare para abraçar a glória.",,"Timpul pentru glorie, eroul meu.","Самое время, мой герой! Ты будешь купаться в славе.",,"Klockan tolv, min hjälte. Förbered dig på att omfamna ära.","Öğle vakti, kahramanım. Zaferi kucaklamaya hazırlan." +"Well, so much for prognostication. Hold it, Macil is calling us back. Let's get out of here in one piece.",TXT_SUB_LOG87,MAP12: After killing the Oracle with Macil alive.,,,"No, to by bylo pro prorokování. Počkat, Macil nás volá zpět. Vypadněme odsud vcelku.","Så meget for prognoser. Vent, Macil kalder os tilbage. Lad os komme ud herfra i ét stykke.","Nun, so viel zu Vorraussagungen. Moment, Macil ruft uns zurück. Lass uns hier heile heraus kommen.",,,"Bueno, tanto por un presentimiento. Espera, Macil nos reclama. Salgamos de aquí de una pieza.",,"No, se siitä ennustelusta. Odota, Macil kutsuu meitä takaisin. Häivytään täältä ehjin nahoin.","Bon, tant pis pour les pronostics. Attends, Macil nous demande de revenir. Rentrons un seul morceau.","Ennyit az előrejelzésről. Várj, Macil visszahív minket. Húzzunk el, míg egy darabban vagyunk.","Alla faccia dei prognostici... Aspetta, Macil ci sta richiamando. Meglio uscire da qua tutti interi.","まあ予言なんてそんなものでしょ。 +ちょっと待って、マシルが帰還するように言ったわ。ここから抜け出しましょう。","웃기네. 이딴 예언 따위. 잠깐만, 마실이 우리들을 부르고 있어. 이제 여기를 나가자.","Nou, tot zover de prognose. Wacht even, Macil roept ons terug. Laten we hier heelhuids weggaan.","Så mye for spådommer. Vent, Macil kaller oss tilbake. La oss komme oss helskinnet ut herfra.","Cóż, to tyle jeśli chodzi o prognozowanie. Czekajcie, Macil nas wzywa. Wynośmy się stąd w jednym kawałku.","Bem, parece que não é hora de previsões. Peraí, o Macil está nos chamando de volta. Vamos tentar sair daqui inteiros.",,"Atât a fost cu prognosticul. Stai, Macil ne sună înapoi. Să ieșim întregi de aici.","Да, это превзошло все наши ожидания. Подожди — Мэйсил вызывает нас назад. Давай выбираться отсюда.",,"Så mycket för prognoser. Vänta, Macil kallar oss tillbaka. Låt oss komma härifrån i ett stycke.","Kehanet buraya kadarmış. Durun, Macil bizi geri çağırıyor. Buradan tek parça halinde çıkalım." +"I'm sorry, after up to my hips in blood I can't think of anything witty to say right now. Let's get back to Macil.",TXT_SUB_LOG88,,,,"Je mi líto; když jsem po boky v krvi, nemám nic co vtipného říct. Vraťme se k Macilovi.","Jeg er ked af det, men efter at have stået op til hofterne i blod kan jeg ikke finde på noget vittigt at sige lige nu. Lad os gå tilbage til Macil.","Tut mir leid, aber bei so viel Blut fällt mir nicht Flapsiges mehr ein. Lass uns zu Macil zurückgehen.",,,,,Anteeksi; oltuani lanteitani myöten veressä en keksi juuri nyt mitään nokkelaa sanottavaa. Palataan Macilin luokse.,"Désolée, après m'être retrouvée jusqu'au hanches dans le sang, je n'ai rien de malin à dire. Rentrons voir Macil.","Bocs, de miután nyakig vérben úsztam, semmi szellemes nem jut az eszembe. Irány vissza Macilhoz.","Mi spiace, ma dopo essere nel sangue fino alle caviglie non ho in mente nulla di interessante di dire al momento. Ritorniamo da Macil.",,미안. 피칠갑을 한 너의 모습을 보느라 할 말을 잃었어. 그냥 마실에게로 돌아가자.,"Het spijt me, na tot aan mijn heupen in bloed kan ik nu niets geestigs bedenken om te zeggen. Laten we teruggaan naar Macil.","Beklager, etter å ha stått i blod til hoftene kommer jeg ikke på noe vittig å si akkurat nå. La oss gå tilbake til Macil.","Przepraszam, ale po tym, jak jestem po biodra we krwi, nie mam teraz nic dowcipnego do powiedzenia. Wracajmy do Macil.",Desculpa. Após ficar coberta de sangue não consigo pensar em nada interessante pra dizer agora. Vamos voltar pro Macil.,,"Îmi pare rău, dar nu mă pot gândi să zic nimic acum. Să ne întoarcem la Macil.","Извини, после того, как я по бёдра в крови, я не могу придумать ничего остроумного, чтобы сказать сейчас. Давай вернёмся к Мэйсилу.",,"Jag är ledsen, men efter att ha varit upp till höfterna i blod kan jag inte komma på något roligt att säga just nu. Vi återvänder till Macil.","Üzgünüm, kalçalarıma kadar kana bulandıktan sonra şu anda söyleyecek esprili bir şey bulamıyorum. Macil'e geri dönelim." +"The factory is next to the mines. Richter must mean the mines of Degnin. The Degnin ore is magnetic and explosive, just the thing for shutting down force fields.",TXT_SUB_LOG89,MAP23: After talking with Richter and leaving his room.,,,"Továrna je vedle dolů. Richter musí mít na mysli doly degninu. Degninská ruda je magnetická a výbušná, perfektní pro vypnutí silového pole.","Fabrikken ligger ved siden af minerne. Richter må mene Degnin-minerne. Degnin-malmen er magnetisk og eksplosiv, lige til at lukke kraftfelter ned med.","Die Fabrik liegt neben den Minen. Richter muss von den Degnin-Minen reden. Das Degnin-Erz ist magnetisch und explosiv., genau das, was wir brauchen, um die Kraftfelder auszuschalten.",,,"La fábrica está junto a las minas. Richter debe referirse a las minas de Degnin. El mineral Degnin es magnético y explosivo, justo para apagar campos de fuerza. ",,"Tehdas on kaivoksen vieressä. Richter varmastikin tarkoittaa Degninin kaivosta. Degnin-malmi on magneettista ja räjähdysherkkää, juuri omiaan purkamaan voimakenttiä.","L'usine est près des mines. Richter doit parler des mines de degnin. Le minérai de degnin est magnétisé et explosif, c'est parfait pour désactiver les champs de force. ","A gyár a bánya mellett van. Richter valószínűleg a Degnin bányákra utalt. A degnini érc mágneses és robbanékony, egy tökéletes megoldás az erőpajzs kiiktatására.","La Fabbrica si trova accanto alle miniere. Richter starà parlando delle miniere di Degnin. I minerali di Degnin sono magnetici ed esplosivi, giusto ciò che ci serve per disattivare i campi di forza.","工場は鉱山の隣にあるわ。リヒターはデグニン鉱山とも呼んでいる。 +デグニン石は綺麗だが可燃性で、フォースフィールドを消すにはうってつけよ。",공장은 광산 옆에 있어. 릭터가 데그닌 광산을 이야기한 것 같아. 데그닌 광석은 폭발성이 있는 자기력이 감도는 물질이야. 방어막을 끌 중요한 도구이기도 하지.,"De fabriek ligt naast de mijnen. Richter moet de mijnen van Degnin bedoelen. Het Degnin-erts is magnetisch en explosief, precies het ding voor het afsluiten van krachtvelden.","Fabrikken ligger ved siden av gruvene. Richter må mene gruvene i Degnin. Degnin-malmen er magnetisk og eksplosiv, som skapt for å slå ut kraftfelt.","Fabryka jest obok kopalni. Richter musi mieć na myśli kopalnie w Degnin. Ruda Degnin jest magnetyczna i wybuchowa, w sam raz do wyłączania pól siłowych.","A fábrica fica próxima às minas. O Richter provavelmente se refere às minas de Degnin. O minério de Degnin é magnético e explosivo, perfeito para derrubar os campos de força.",,"Fabrica e lângă mine. Richter probabil s-a referit la minele de Degnin. Mineralul de Degnin e magnetic și exploziv, exact ce ne trebuie pentru scuturi.","Вход на фабрику — рядом со спуском в шахты. Рихтер, должно быть, имел в виду шахты Дегнина. Дегнинская руда магнитна и взрывоопасна — то, что надо, если хочешь отключить силовое поле. ",,"Fabriken ligger bredvid gruvorna. Richter måste mena Degnins gruvor. Degninmalmen är magnetisk och explosiv, precis vad man behöver för att stänga av kraftfält.","Fabrika madenlerin yanında. Richter, Degnin madenlerini kastediyor olmalı. Degnin cevheri manyetik ve patlayıcıdır, tam da güç alanlarını kapatmak için." +"Mines, catacombs, sewers... What a first date!",TXT_SUB_LOG90,MAP13: Entrance.,,,"Doly, kobky, stoky... skvělé první rande!","Minerne, katakomberne, kloakkerne... Sikke en første date!","Minen, Katakomben, Kanalisationen... was für ein erstes Date!",,,"Minas, catacumbas, alcantarillas... ¡Menuda primera cita!",,"Kaivoksia, katakombeja, viemäreitä... Mitkä ensitreffit!","Mines, catacombes, égouts.. Super premier rendez-vous!","Bányák, katakombák, kanálisok... Micsoda első randi!","Miniere, catacombe, fogne... Che primo appuntamento!",鉱山、地下墓所、下水道...とんだ初デートだな!,"광산, 고대 묘지, 하수도. 데이트하기엔 딱 맞는 장소들이네!","Mijnen, catacomben, rioleringen.... Wat een eerste afspraakje!","Gruver, katakomber, kloakker... For en første date!","Kopalnie, katakumby, kanały... Co za pierwsza randka!","Minas, catacumbas, esgotos... Que belo primeiro encontro!",,"Mine, catacombe, canale... Ce întâlnire!","Шахты, катакомбы, канализации... Замечательное первое свидание!",,"Gruvor, katakomber, kloaker... Vilken första träff!","Madenler, yeraltı mezarları, kanalizasyonlar. Ne ilk randevu ama!" +"I wish Richter had been a touch more specific. Hm, let's try over here.",TXT_SUB_LOG91,MAP13: West (entrance with parkour to the northwest).,,,"Přála bych si, aby byl Richter trochu přesnější. Hm, zkusme to tadyhle.","Jeg ville ønske, Richter havde været lidt mere specifik. Hm, lad os prøve herovre.","Ich wünschte mir, dass Richter etwas präziser gewesen wäre. Hmm, lass es uns mal hier versuchen.",,,"Ojalá Richter hubiera sido un pelín más específico. Hm, probemos por aquí.",,"Kunpa Richter olisi ollut hivenen tarkempi. Hm, kokeillaan täältä.",J'aurais bien voulu que Richter soit un peu plus spécifique. Hm.. Essayons ici.,"Nem bántam volna, ha Richter egy csöppnyivel pontosabb leírást ad. Hm, próbáljuk meg itt.","Vorrei che Richter fosse stato un poco più preciso. Mh, vediamo di là.","リヒターがもっと具体的な部分に触れてくれて欲しいが。 +あー、私らが試してみようか。","릭터가 좀 더 자세히 설명해 줬으면 좋았을 텐데. 흠, 여기서 해보자.","Ik wou dat Richter een beetje specifieker was geweest. Hm, laten we het hier eens proberen.","Skulle ønske Richter hadde vært litt mer spesifikk. Hm, la oss prøve her borte.","Szkoda, że Richter nie był bardziej konkretny. Hm, spróbujmy tutaj.","Bem que o Richter podia ter sido um pouco mais específico. Hmm, vamos tentar por alí.",,Îmi doresc ca Richter să fii fost mai specific. Să încercăm acolo.,"Я надеялась, что Рихтер будет чуть более конкретным. Ладно, давай посмотрим, что там.",,"Jag önskar att Richter hade varit lite mer specifik. Hm, vi försöker här borta.",Keşke Richter biraz daha spesifik olsaydı. Şurayı deneyelim. +"I think we're... Oh, crap. I have no idea where we are.",TXT_SUB_LOG92,MAP13: Northwest (hall to the parkour room).,,,"Myslím, že jsme... sakra. Nemám tušení, kde jsme.","Jeg tror, vi er... Åh, pis. Jeg har ingen idé om, hvor vi er.","Ich glaube wir sind... Oh, Mist. Ich habe keine Ahnung wo wir sind.",,,"Creo que estamos... Oh, mierda. No tengo ni idea de donde estamos.",,"Luulen, että olemme... Perhana, minulla ei ole aavistustakaan, missä olemme.","Je crois que.. Non, merde, j'ai aucune idée d'où on est!","Azt hiszem éppen...Oh, franc. Ötletem sincs hol vagyunk.","Credo che siamo... Ah, merda, non ne ho proprio idea.","私が思うに...ああ、クソ。 +何処にあるかさっぱりわからないわ。",우리는 지금... 이런 제길. 여기가 어딘지 모르겠어.,"Ik denk dat we.... Oh, shit. Ik heb geen idee waar we zijn.","Jeg tror vi... Å, pokker. Jeg aner ikke hvor vi er.","Chyba jesteśmy... O, cholera. Nie mam pojęcia, gdzie jesteśmy.","Acho que estamos... Ah, merda. Não faço a menor idéia onde estamos.",,"Cred că suntem... Oh, la naiba. Nu știu unde suntem.","Я думаю, мы... О, чёрт. Я понятия не имею, где мы.",,"Jag tror att vi är... Åh, skit. Jag har ingen aning om var vi är.","Sanırım biz... Oh, kahretsin. Nerede olduğumuz hakkında hiçbir fikrim yok." +"This must be the ruins Richter's agents were searching for. Oh, watch out! Crusaders!",TXT_SUB_LOG93,MAP25: Entrance.,,,"Tohle musí být ty ruiny, které Richterovi agenti hledali. A, bacha! Křižáci!","Det må være ruinerne, som Richters agenter ledte efter. Åh, pas på! Korsfarere!","Dies müssen die Ruinen sein, die Richters Agent gesucht hat. Oh, aufpassen! Ordensritter!",,,"Estas deben ser las ruinas que el agente de Richter estaba buscando. Oh, ¡cuidado! ¡Cruzados!",,"Nämä ovat varmaankin ne rauniot, joita Richterin joukot olivat etsineet. Oho, varo: ristiretkeläisiä!","Ca doit être les ruines que les agents de Richter cherchaient. Attention, des croisés!","Ezek lehetnek a romok, amit Richter ügynökei kerestek. Vigyázz! Keresztesek!","Queste devono essere le rovine che gli agenti di Richter stavano cercando. Ah, attento! Crociati!","ここがリヒターのエージェントが探していた遺跡のはず。 +あっと、気を付けて!クルセイダーよ!","릭터의 요원이 수색하던 유적지인가봐... 잠깐, 조심해! 크루세이더야!","Dit moet de ruïnes zijn waar de agenten van Richter naar op zoek waren. Oh, kijk uit! Kruisvaarders!",Dette må være ruinene Richters agenter lette etter. Se opp! Korsfarere!,"To muszą być ruiny, których szukali agenci Richtera. Och, uważaj! Krzyżowcy!","Estas devem ser as ruínas que o agente de Richter estava procurando. Ah, cuidado! Cruzados!",,Ăstea ar trebui să fie ruinele pe care le căutau agenții lui Richter. Ai grijă! Cruciați!,"Возможно, это те самые руины, которые искали агенты Рихтера... Осторожно! Крестоносцы!",,"Det här måste vara ruinerna som Richters agenter sökte efter. Åh, se upp! Korsfarare!","Richter'in ajanlarının aradığı harabeler burası olmalı. Oh, dikkat et! Haçlılar!" +"Ugh, it's trying to regenerate. Blast it before I throw up!",TXT_SUB_LOG94,,,,"Fuj, snaží se to oživit. Odstřel to, než začnu zvracet!","Ugh, den prøver at regenerere. Skyd den, før jeg kaster op!","Ugh, es versucht, sich zu regenerieren. Mach es fertig, bevor ich anfange zu kotzen.",,,"Ugh, está intentando regenerarse. ¡Reviéntalo antes de que vomite!",,"Yöh, se yrittää uusiutua. Posauta se, ennen kuin laattaan!","Beurk, il essaie de se régénérer, incinère le avant que je ne vomisse!","Fúj, regenerálódni próbál. Lődd szét mielőtt ide hányok!","Dannazione, sta cercando di rigenerarsi! Distruggilo prima che mi venga da vomitare.",,"으윽, 이게 재생하기 시작했어. 내가 토하기 전에 파괴해!","Ugh, het probeert te regenereren. Blast het voordat ik overgeven!",Den prøver å regenerere. Spreng den før jeg spyr!,"Ugh, próbuje się zregenerować. Rozwal to, zanim zwymiotuję!","Argh, está tentando se regenerar. Detona essa coisa antes que eu vomite!",,"Ugh, încearcă să se regenereze. Aruncă-l în aer înainte să vomit.","О-о, оно пытается восстановиться. Добей его, пока меня не стошнило!",,"Ugh, den försöker att regenerera. Skjut den innan jag spyr!",Yenilenmeye çalışıyor. Kusmadan önce patlat şunu! +"My friend, whatever it is we're fighting, it's more than the Order. Off to the mines!",TXT_SUB_LOG95,MAP25: After killing the Spectre.,,,"Příteli, ať už bojujeme s čímkoliv, jde o víc než jen Řád. Do dolů!","Min ven, hvad det end er, vi kæmper imod, er det mere end Ordenen. Af sted til minerne!","Mein Freund, was auch immer es ist, dass wir bekämpfen, es ist mehr als der Orden. Ab zu den Minen!",,,"Amigo mío, lo que sea contra que estemos luchando, es más que la Orden. ¡A las minas!",,"Ystäväni, mitä vastaan me taistelemmekaan, se on suurempi kuin Veljeskunta. Matkatkaamme kaivokselle!","Mon ami, je ne sais ce contre quoi on se bat, mais c'est plus que l'Ordre. Allons dans les mines!","Nos barátom, bármivel is állunk szemben, több az mint maga a Rend. Irány a bánya!","Amico mio, qualsiasi cosa stiamo combattendo, è molto più dell'Ordine. Alle miniere!","友よ、私達が戦う相手が何であろうとも、オーダー以上のものはない。 +鉱山から離れましょう!","친구야, 우리가 싸우는 상대가 무엇인지는 모르겠지만, 오더보다 더한 존재인 것 같아. 광산으로 향하자!","Mijn vriend, wat het ook is waar we tegen vechten, het is meer dan de Orde. Naar de mijnen!","Min venn, hva det enn er vi kjemper mot, så er det mer enn Ordenen. Av sted til gruvene!","Mój przyjacielu, cokolwiek to jest, z czym walczymy, to coś więcej niż Zakon. Do kopalni!","Meu amigo, seja lá o que estamos combatendo, é mais do que somente a Ordem. Vamos para as minas!",,"Prietene, orice ar fi ceea ce înfruntăm, e mai mult decât Ordinul. Către mine!","Друг мой, с чем бы мы ни сражались, это нечто большее, чем просто Орден. К шахтам!",,"Min vän, vad det än är vi slåss mot, så är det mer än Orden. Iväg till gruvorna!","Dostum, savaştığımız şey her neyse, Tarikat'tan daha fazlası. Madenlere!" +"Without letting down your guard, look for deposits of ore.",TXT_SUB_LOG96,MAP14: Entrance.,,,Opatrně se zkus podívat po ložiscích rudy.,"Uden at sænke din vagt, skal du lede efter malmforekomster.",Sei vorsichtig und halte Ausschau nach Erzvorkommen.,,,"Sin bajar la guardia, busca depósitos de mineral.",,"Etsi malmiesiintymiä, kuitenkin valppautesi säilyttäen.","Sans arrêter de faire attention, cherche des veines de minerai.","Keress érceket, de figyelj a hátad mögé közben.","Senza abbassare la guardia, cerca di trovare alcuni depositi di minerali.",警戒を緩めることなく、鉱石の堆積所を探しましょう。,"조심해가면서, 그들이 캔 광석을 두는 곳을 찾아.","Zonder je waakzaamheid te laten verslappen, zoek je naar ertsafzettingen.","Uten å senke garden, let etter malmforekomster.","Nie spuszczając gardy, szukajcie złóż rudy.",Não baixe a sua guarda. Vamos procurar por depósitos de minério.,,"Fără a lăsa garda jos, uită-te dupa depozite de minereu.","Поищи залежи руды, но не теряй бдительности!",,"Utan att sänka garden, leta efter malmfyndigheter.","Gardınızı düşürmeden, maden yataklarını arayın." +"These poor souls are drones, their synaptic functions are jammed by RC implants. We destroy the transmitter and they are free!",TXT_SUB_LOG97,MAP14: After crossing the entrance's yard.,,,"Tihle chudáci jsou trubci, jejich synaptické funkce jsou narušené na dálku ovládanými implantáty. Když zničíme vysílačku, budou svobodní!","Disse stakkels sjæle er droner, deres synaptiske funktioner er blokeret af RC-implantater. Vi ødelægger senderen, og de er frie!","Diese armen Seelen sind Drohnen, ihre synaptischen Funktionen werden von Implantaten blockiert. Wenn wir den Transmitter zerstören, sind sie frei.",,,"Estas pobres almas son zánganos. Sus funciones sinápticas están bloqueadas por implantes de control remoto. ¡Destruimos el transmisor, y son libres!",,"Nämä sieluparat ovat kuhnureita: Heidän synaptisia toimintojaan häiritään radio-ohjattavilla istutteilla. Me tuhoamme lähettimen, ja he ovat vapaat!","Ces pauvres âmes sont des drones, leurs fonctions synaptiques sont brouillées par des implants radiocommandés. On détruit le transmetteur et ils sont libres!","Ezek a szerencsétlen lelkek csak drónok. A szinaptikus funkcióikat zavarják távolról irányítható implantátumokkal. Szétromboljuk a jeladókat, és szabaddá vállnak.","Questi poveracci sono degli schiavi. Le loro funzioni cerebrali stanno venendo bloccate da degli impianti. Se distruggiamo il trasmettitore, saranno liberi!","これら精神の乏しい労働者達は、シナプス機能をRCインプラントで妨害している。 +私達が送信機を破壊し皆を解放するんだ!","저 사람들은 불쌍한 광산의 노예들이야. 오더가 이식한 세뇌 장치 때문에 정상적인 뇌 기능을 잃었지. 전송기만 파괴한다면, 그들은 자유를 되찾을 수 있을 거야!","Deze arme zielen zijn drones, hun synaptische functies worden verstoord door RC-implantaten. We vernietigen de zender en ze zijn vrij!","Disse stakkarene er droner, deres synaptiske funksjoner er blokkert av RC-implantater. Vi ødelegger senderen, og de er fri!","Te biedne dusze są dronami, ich funkcje synaptyczne są zagłuszane przez implanty RC. Zniszczymy nadajnik i są wolne!",Esses pobres coitados são escravos. Suas funções sinápticas estão sendo bloqueadas por implantes de controle remoto. Se destruirmos o transmissor eles estarão livres!,,Sufletele ăstea sărmane sunt drone. Funcțiile lor sinaptice sunt întrerupte de implanturi RC. Distrugem transmițătorul și sunt libere!,"Эти несчастные души — дроны. Сигнал, поступающий на импланты, полностью подавляет их сознание. Давай уничтожим передатчик и освободим их!",,"Dessa stackars själar är drönare, deras synaptiska funktioner är blockerade av RC-implantat. Vi förstör sändaren och de är fria!","Bu zavallı ruhlar dron, sinaptik fonksiyonları RC implantları tarafından engellenmiş. Vericiyi yok edersek özgür kalırlar!" +"Command says the transmitter is shielded by a force field. So two birds, one stone, free the drones and practice with the ore.",TXT_SUB_LOG98,MAP14: After the entrance's yard and before going down.,,,"Velení říká, že vysílačka je chráněná silovým polem. Dvě mouchy jednou ranou: osvobodíme vězně a vyzkoušíme si, jak s tou rudou.","Kommandocentralen siger, at senderen er beskyttet af et kraftfelt. Så to fluer i et smæk, befri dronerne og øv dig med malmen.","Die Kommandozentale sagt, der Transmitter sei von einem Kraftfeld geschützt. So, zwei Fliegen, eine Klatsche, befreie die Drohnen und übe mit dem Erz.",,,"El Comando dice que el transmisor está protegido por un campo de fuerza. Dos pájaros de un tiro, libera a los zánganos y practica con el mineral.",,"Komentokeskus sanoo, että lähetin on voimakentän suojaama. Siispä kaksi kärpästä yhdellä iskulla: vapautamme kuhnurit ja samalla harjoittelemme malmilla.","La commandement me dit que le transmetteur est protégé par un champ de force. Ca fait d'une pierre de coups. On libère les drones, et on s'entraîne avec le minerai.",Az irányítás szerint a jeladó el van szeparálva egy erőpajzzsal. Tehát két légy és egy csapás: szabadítsuk ki a drónokat és gyakoroljunk az érccel.,"Il comando dice che il trasmettitore è protetto da un campo di forza. Quindi, due piccioni con una fava. Liberiamo gli schiavi e facciamo pratica con il minerale.","司令官は送信機がフォースフィールドに守られていると言っていた。 +そこを潰せば鉱山と労働者を解放、一石二鳥だな。",본부가 말하길 전송기는 방어막에 의해 보호받고 있대. 광석을 사용하는 방법을 연습하면서 노예들을 해방한다면 일석이조일 거야.,"Het commando zegt dat de zender is afgeschermd door een krachtveld. Dus twee vogels, een steen, bevrijden de drones en oefenen met het erts.","Kommandoen sier at senderen er beskyttet av et kraftfelt. Så to fluer i en smekk, frigjør dronene og øv med malmen.","Dowództwo mówi, że nadajnik jest osłonięty przez pole siłowe. Więc dwie pieczenie na jednym ogniu, uwolnić drony i poćwiczyć z rudą.",O comando diz que o transmissor está protegido por um campo de força. Dois coelhos numa tacada só. Liberte os escravos e teste o minério.,,"Centrul de comandă e prtejat de un câmp de forță. Deci, două păsări, o piatră.","Штаб говорит, что передатчик защищён силовым полем. Ты освободишь дронов и испытаешь руду — одним выстрелом двух зайцев!",,"Ledningen säger att sändaren är skyddad av ett kraftfält. Så två flugor i en smäll, frigör drönarna och öva med malmen.","Komuta vericinin bir güç alanı tarafından korunduğunu söylüyor. Yani bir taşla iki kuş, dronları serbest bırak ve cevherle pratik yap." +"My suggestion is, toss the ore at the forcefield and then blast it. The resulting compression should create a magnetic blanket and turn off the lights.",TXT_SUB_LOG99,MAP14: After James's room.,,,"Můj návrh je, hoď rudu na to silové pole a pak ji odstřel. Výsledná komprese by měla vytvořit magnetický povlak a vypnout pole.","Mit forslag er, at kaste malmen mod kraftfeltet og derefter sprænge det. Den resulterende kompression skulle skabe et magnetisk tæppe og slukke lyset.","Mein Vorschlag wäre, das Erz vor das Kraftfeld zu legen und dann explodieren zu lassen. Die resultierende Kompression sollte ein Magnetfeld erzeugen und die Lichter ausgehen lassen.",,,"Mi sugerencia es, tirar el mineral hacia el campo de fuerza y luego reventarlo, la presión resultante debería crear un manto magnético y apagar las luces.",,"Ehdotukseni on, että heität malmin voimakentään ja sitten posautat sen. Syntyvän paineaallon pitäisi muodostaa magneettinen peitto ja sammuttaa valot.",Ma suggestion: jette le minerai sur le champ de force puis tire dessus. La compression qui en résulte devrait créer un champ magnétique qui va désactiver les lumières.,"Az a tanácsom, hogy dobd az ércet az erőpajzsra, és robbantsd fel. A keletkező kompresszió egy mágneses takarót kéne hogy képezzen, így kikapcsolva a fényeket.","Il mio consiglio è, lancia uno dei minerali al campo di forza e poi fallo saltare in aria. Questo dovrebbe sprigionare l'energia sufficiente a disattivare il campo di forza.","私の案はフォースフィールドの近くに鉱石を置き撃って爆発させる方法よ。 +その結果、圧縮されていた磁場の反動で光を打ち消すわ。","조언을 찾는다면, 광석을 방어막에 가까이 놔둔 뒤 쏴봐. 광석이 커다란 자기장을 만들 테고, 방어막을 완전히 무력화 시킬 거야. 불 끄는거지!",Mijn suggestie is om het erts naar het krachtveld te gooien en het vervolgens op te blazen. De resulterende compressie zou een magnetische deken moeten creëren en de lichten moeten doven.,Mitt forslag er å kaste malmen mot kraftfeltet og sprenge det. Den resulterende kompresjonen bør skape et magnetisk teppe og slå av lysene.,Proponuję rzucić rudę w pole siłowe i wysadzić je. Powstała kompresja powinna stworzyć koc magnetyczny i wyłączyć światła.,Minha sugestão é que você arremesse o minério no campo de força e o detone. A explosão vai criar um campo magnético e apagar as luzes.,,"Sugstia mea e, aruncă minereul în scut și aruncă-l în aer. Comprimarea rezultată ar trebui să creeze un câmp magnetic care sp oprească luminile.","Мой план: бросить руду поближе к силовому полю и взорвать её. Взрыв создаст магнитное поле, которое накроет электронику и отрубит её.",,Mitt förslag är att kasta malmen mot kraftfältet och sedan spränga det. Den resulterande kompressionen bör skapa ett magnetiskt täcke och släcka ljuset.,"Benim önerim, cevheri güç alanına fırlatın ve sonra patlatın. Ortaya çıkan sıkıştırma manyetik bir örtü oluşturmalı ve ışıkları kapatmalı." +Now on to the factory. Exit the mines and you can't miss it!,TXT_SUB_LOG100,MAP14: After destroying the transmitter.,,,A teď do továrny. Vyjdi z dolů a nemůžeš to minout.,"Nu videre til fabrikken. Gå ud af minerne, og du kan ikke undgå at se den!",Und nun zur Fabrik. Verlasse die Minen und du kannst sie nicht verpassen.,,,Ahora vamos a la fábrica. ¡Sal de las minas y no puedes perderlo!,,"Nyt sitten tehtaaseen. Poistu kaivoksesta, ja löydät sen varmasti!","Bon, maintenant, l'usine! Sors des mines et tu peux pas la rater!",Most pedig irány a gyár. Kilépve a bányából nem tudod eltéveszteni.,Ora entriamo nella Fabbrica. Uscendo dalle miniere non puoi sbagliare.,今すぐ工場へ向かおう。鉱山を出たら見逃すなよ!,이제 공장으로 향하자. 광산을 나가면 더 재밌는 모험이 펼쳐질 거야!,Nu naar de fabriek. Verlaat de mijnen en je kunt het niet missen!,"Nå videre til fabrikken. Gå ut av gruvene, og du kan ikke gå glipp av den!",Teraz przejdź do fabryki. Wyjdź z kopalni i nie możesz jej przegapić!,"Agora, para a fábrica. Saia das minas e não vai ter como errar.",,Acum către fabrică. Ieși din mine și nu o poți rata.,"Теперь — на фабрику. Выйди из шахты, и ты сразу увидишь вход!",,Nu till fabriken. Gå ut ur gruvorna och du kan inte missa den!,Şimdi fabrikaya gidelim. Madenlerden çıkın ve onu kaçırmayın! +"Sorry, hero, this is all new to me.",TXT_SUB_LOG101,MAP20: Exit to Commons (MAP23).,,,"Promiň, hrdino, tohle všechno je pro mě nové.","Undskyld, helt, det er alt sammen nyt for mig.","Entschuldigung, mein Held, das ist alles neu für mich.",,,"Lo siento, héroe, esto es nuevo para mí.",,"Pahoittelut, sankari; tämä kaikki on uutta minulle.","Désolé, héros, tout cela est nouveau pour moi.","Sajnálom hősöm, ez mind rendkívűl új számomra.","Mi spiace, eroe, ma tutto ciò è nuovo per me.",ごめんなさい、これは初耳なの。,"미안, 영웅 친구... 이런 곳은 처음 봐.","Sorry, held, dit is allemaal nieuw voor mij.","Beklager, helt, dette er nytt for meg.","Wybacz, bohaterze, to wszystko jest dla mnie nowe.","Foi mal, meu herói, tudo isso é novo pra mim.","Desculpa, meu herói, tudo isto é novo para mim.","Scuze, eroule, asta e nou pentru mine.","Извини, герой. Для меня это всё в новинку.",,"Ledsen, hjälte, allt detta är nytt för mig.","Üzgünüm kahraman, bunların hepsi benim için yeni." +I'm reading massive neural wave distortions from straight ahead. I think we've found it.,TXT_SUB_LOG102,MAP20: Path to Conversion Chapel (MAP24).,,,"Detekuju obří rušení nervových vln přímo před námi. Myslím, že jsme to našli.","Jeg læser massive neurale bølgeforvridninger lige forude. Jeg tror, vi har fundet det.","Ich empfange massive neurale Verzerrungen direkt voraus. Ich denke, wir haben sie gefunden.",,,Estoy leyendo distorsiones de ondas neuronales masivas adelante. Creo que la hemos encontrado.,Estoy leyendo distorsiones neuronales masivas adelante. Creo que la hemos encontrado.,Havaitsen massivisia hermoaaltovääristymiä suoraan edessä. Luulen löytäneemme sen.,Je recois des distorsions neurales colossales devant nous. Je crois que nous l'avons trouvé. ,Erős ideghullám zavaró jeleket fogok. Azt hiszem megtaláltuk.,Sto ricevendo potenti segnali distorti proprio davanti a te. Penso che l'abbiamo trovata.,重い神経波の歪曲が直に届いたわ。私達はそれを見つけたという事よ。,앞쪽에서 거대한 신경교란 파장이 감지되고 있어. 우리가 찾아낸 것 같아.,Ik lees enorme neurale golfvervormingen van rechtdoor. Ik denk dat we het gevonden hebben.,Jeg leser massive nevrale bølgeforvrengninger rett fram. Jeg tror vi har funnet den.,Odczytuję masywne zakłócenia fal neuronowych z prostej drogi. Chyba to znaleźliśmy.,Estou captando enormes distorções de rede neural mais adiante. Acho que encontramos.,,Citesc distorsiuni neurale masive drept din față. Cred că am găsit-o.,"Я вижу мощный источник помех прямо по курсу. Похоже, мы нашли конвертер.",,Jag läser massiva neurala vågförvrängningar rakt fram. Jag tror att vi har hittat den.,Tam karşıdan büyük sinirsel dalga bozulmaları okuyorum. Sanırım onu bulduk. +Just when I think we've seen it all! They go in human and come out... I dont even want to think about it.,TXT_SUB_LOG103,MAP24: Converter room.,,,"Zrovna, když jsem myslela, že jsme už viděli všechno! Dovnitř jdou jako lidé a ven vyjdou... ani na to nechci myslet.","Lige når jeg tror, vi har set det hele! De går ind i et menneske og kommer ud... Jeg vil ikke engang tænke på det.","Und da denkt man, man hätte schon alles gesehen. Die kommen als Menschen rein und kommen raus als... Ich möchte gar nicht drüber nachdenken.",,,¡Justo cuando creía haberlo visto todo! Entran humanos y salen... No quiero ni pensarlo. ,,Juuri kun luulen nähneemme kaiken! He menevät sisään ihmisinä ja tulevat ulos... En halua edes ajatellakaan sitä.,"Et quand je pense avoir tout vu.. Des humains entrent, et puis.. Non, je ne veux pas y penser. ","Amikor azt hittem, hogy mindent láttunk. Emberként mennek be, és úgy jönnek ki mint egy...nem is akarok rá gondolni.",E io che pensavo di averle viste tutte! Entrano umani ed escono fuori... Non ci voglio neanche pensare.,"今まで見てきたことについて考えている! +奴は人の内部から出てくる...それについて考えたくないわ。",이렇게 끔찍한 모습을 보게 되다니! 멀쩡한 사람이 저곳에 들어갔다 나온 모습을... 차마 생각하기도 싫어.,Net nu ik denk dat we het allemaal hebben gezien! Ze gaan in de mens en komen eruit.... Ik wil er niet eens over nadenken.,Akkurat når jeg tror vi har sett alt! De går inn som mennesker og kommer ut... Jeg vil ikke engang tenke på det.,"Właśnie wtedy, gdy myślałem, że widzieliśmy już wszystko! Wchodzą w człowieka i wychodzą... Nawet nie chcę o tym myśleć.",E eu achei que já tinha visto de tudo! Eles entram humanos e saem... eu não quero nem pensar nisso.,,Tocmai când credeam că am văzut tot! Intră oameni și ies... nici nu vreau să mă gândesc.,"А я-то думала, что хуже уже не будет! Они входят людьми, а выходят... Не хочу даже думать об этом.",,Precis när jag tror att vi har sett allt! De går in i en människa och kommer ut... Jag vill inte ens tänka på det.,Tam da her şeyi gördüğümüzü düşündüğüm anda! İnsana giriyorlar ve çıkıyorlar. Bunu düşünmek bile istemiyorum. +The Oracle was right. Macil's gone nuts. He just knowingly sent 200 men to their death. I want vengeance. For the dead and for the living dead!,TXT_SUB_LOG104,MAP24: After destroying the converter.,,,Věštec měl pravdu. Macil zešílel. Vědomě poslal dvě stě mužů na smrt. Chci odplatu - za mrtvé i živé mrtvé!,Oraklet havde ret. Macil er blevet skør. Han har lige bevidst sendt 200 mænd i døden. Jeg vil have hævn. For de døde og for de levende døde!,Das Orakel hatte Recht. Macil hat den Verstand verloren. Er hat gerade absichtlich 200 unserer Leute in den Tod geschickt. Ich will Rache! Für die Toten und für die lebenden Toten.,,,"El Oráculo tenía razón. Macil se ha vuelto loco: ha enviado intencionalmente a 200 hombres directo a la muerte. Quiero venganza, ¡por los muertos y los muertos vivientes!","El Oráculo tenía razón. Macil se volvió loco: mandó intencionalmente a 200 hombres directo a la muerte. Quiero venganza, ¡por los muertos y los muertos vivientes!","Oraakkeli oli oikeassa: Macil on tullut hulluksi. Hän juuri lähetti tietoisesti 200 miestä surmaansa. Vaadin kostoa, sekä kuolleitten että elävien kuolleitten puolesta!","Macil a complètement perdu les pédales! Il a envoyé 200 hommes se faire tuer, et il le savait! Il faut les venger, pour eux et pour leurs camarades!",Az Orákulumnak igaza volt. macil megőrült. Szándékosan küldött 200 emberünket a halálába. Meg akarom bosszúlni a halottak és az élő halottak nevében!,L'Oracolo aveva ragione. Macil deve essere impazzito. Ha mandato consciamente 200 uomini verso la morte. Voglio vendetta! Per i morti e per i morti viventi!,"オラクルが正しかった。マシルはイカれていたなんて。 彼は故意に200人以上の人々を死に追いやっていた。 -復讐しなくては。死んだ人達の為、そして今生きている人達の為にも!",마실이 정신 나갔나 봐. 모든 것을 알면서도 200 명이나 되는 병력을 보내서 죽게 했어. 과부들과 망령들을 위한 복수를 할 시간이야!,Het Orakel had gelijk. Macil is gek geworden. Hij stuurde gewoon bewust 200 mannen naar hun dood. Ik wil wraak. Voor de doden en voor de levende doden!,,O Oráculo estava certo. O Macil enlouqueceu. Ele mandou 200 homens para as suas mortes sabendo disso. Eu quero vingança. Pelos mortos e pelos mortos-vivos!,,,Оракул сказал правду: Мэйсил озверел. Он намеренно послал двести человек на верную смерть. Я жажду мести! За убитых и за живых мертвецов!, -"Macil? Infected and with a Sigil piece. All these years of believing in him, in the cause. And for what?",TXT_SUB_LOG105,,,,"Macil? Nakažený a s dílem Pečeti? Všechny ty roky, kdy jsme mu a naší věci důvěřovali. A k čemu?","Macil? Infiziert und mit einen Sigli-Teil? All diese Jahre, die ich an ihn geglaubt habe - an die Sache. Und für was?",,,"¿Macil? Infectado con una pieza del Emblema. Todos estos años de creer en el, en la causa. ¿Y para que?",,,Macil? Infecté par une pièce du Sigil. Toutes ces années où je lui ai fait confiance.. à la cause.. Et pour quoi à la fin?,,,,마실? 시질 조각에 의해 오염됬어. 수 년 동안 믿어온 우리가 바보인가? 아니면 이 운명을 피할 수 없었던 걸까?,"Macil? Geïnfecteerd en met een Sigil stuk. Al die jaren van geloof in hem, in de oorzaak. En waarvoor?",,"Macil? Infectado e com uma peça do Sigilo. Todos esses anos acreditando nele, acreditando na causa. E pra quê?",,,"Мэйсил? Заражённый... И у него фрагмент Сигила. Всё эти годы я верила ему, верила в нашу миссию. А теперь?", -"Richter reports that the factory we destroyed leads to a ""lab"", and they're getting a Sigil power signature from within. Back to the factory and our next step to freedom.",TXT_SUB_LOG106,"STRIFE1.WAD: MAP10 - -(After killing Macil while having destroyed the converter in MAP24)",,,"Richter hlásí, že továrna, kterou jsme zničili, vede do „laboratoře“ a detekují z ní energii Pečetě. Zpátky do továrny a našemu dalšímu kroku ke svobodě.","Richter sagt, in der Fabrik, die wir zerstört haben, gäbe es ein „Labor“, und dort gibt es eine Sigil-Signatur. Zurück zur Fabrik und dem nächsten Schritt zu unserer Freiheit.",,,"Richter informa de que la fábrica que destruimos conduce a un ""laboratorio"", y están recibiendo una señal de poder del Emblema de adentro. De vuelta a la fábrica y nuestro siguiente paso a la libertad.",,,"Richter rapporte que l'usine que l'on a détruit mène à un ""laboratoire"" et qu'il s'y trouve une signature de pièce du Sigil à l'intérieur. Retourne à l'usine et on fera un autre pas vers la liberté.",,,"リヒターの報告では我々が破壊した工場は'研究所'に繋がっていて、 -奴等はシジルの調印を内部から得ている。工場に戻って自由への次の段階に進みましょう",릭터가 말하길 우리가 파괴한 공장은 연구소로 향하는 길이 있대. 그리고 그곳에는 시질 특유의 힘이 감지됐어. 공장으로 돌아가서 자유를 위해 계속 투쟁을 하자.,"Richter meldt dat de fabriek die we vernietigd hebben, leidt naar een ""lab"", en ze krijgen een Sigil power signatuur van binnenuit. Terug naar de fabriek en onze volgende stap naar vrijheid.",,"O Richter disse que a fábrica que destruímos leva a um ""laboratório"" e eles estão captando um sinal de energia lá de dentro. De volta à fábrica e ao nosso próximo passo à liberdade.",,,"Рихтер сообщает, что за разрушенной нами фабрикой лежит «лаборатория», и мы засекли характерную энергию фрагмента Сигила, исходящую оттуда. Возвращайся на фабрику — сделаем ещё один шаг к нашему освобождению.", -Who dares to defy me and enter my fortress? A worthless human? Face me and die!,TXT_SUB_LOG120,STRIFE1.WAD: MAP16,,,Kdo se to opovažuje mi vzdorovat a vkročit do mé pevnosti? Bezcenný člověk? Postav se mi a zemři!,Wer wagt es mir zu trotzen und meine Festung zu betreten? Ein wertloser Mensch? Stelle dich mir und stirb!,,,¿Quien se atreve a desafiarme y entrar en mi fortaleza? ¿Un insignificante humano? ¡Enfréntate a mí y muere!,,,Qui ose me défier et pénétrer ma forteresse? Un humain sans valeur? Faites face à moi et mourrez!,,,"我に歯向かう為に敢えて私の要塞に来たのか?無価値な人間よ? -死をくれてやろう!",감히 어떤 자가 이 몸을 반역하고 요새를 침입한 것이더냐? 나약한 인간이구나. 이 몸의 의해 소멸당해라.,Wie durft mij uit te dagen en mijn vesting binnen te gaan? Een waardeloos mens? Kijk me aan en sterf!,,Quem ousa me desafiar e entrar na minha fortaleza? Um humano insignificante? Enfrente-me e morra!,,,Кто смеет бросать мне вызов и вторгаться в мою крепость? Жалкий человечишка? Сразись со мной и умри!, -You cannot kill me. You are just human. And I am more than human.,TXT_SUB_LOG121,STRIFE1.WAD: MAP16,,,Nemůžeš mě zabít. Jsi jen člověk a já jsem víc než člověk.,Du kannst mich nicht töten. Du bist nur ein Mensch. Und ich bin mehr als das.,,,No puedes matarme. Eres solo humano. Y yo soy más que humano.,,,Vous ne pouvez me tuer. Vous n'êtes qu'un humain. Je suis plus qu'un humain.,,,我を殺すことはできまい。貴様は人間。そして私は人間を超えし者だ。,"이 몸은 너에게 사살 당할 수 없다. 이 몸은 초월한 존재, 인간 따위를 넘었기에!",Je kunt me niet doden. Je bent gewoon een mens. En ik ben meer dan een mens.,,Você não pode me matar. Você é apenas humano. E eu sou mais do que humano.,,,"Тебе не убить меня. Ты всего лишь человек. А я — нечто большее, чем человек!", +復讐しなくては。死んだ人達の為、そして今生きている人達の為にも!",마실이 정신 나갔나 봐. 모든 것을 알면서도 200 명이나 되는 병력을 보내서 죽게 했어. 과부들과 망령들을 위한 복수를 할 시간이야!,Het Orakel had gelijk. Macil is gek geworden. Hij stuurde gewoon bewust 200 mannen naar hun dood. Ik wil wraak. Voor de doden en voor de levende doden!,Oraklet hadde rett. Macil har gått fra vettet. Han sendte 200 menn i døden med viten og vilje. Jeg vil ha hevn. For de døde og for de levende døde!,Wyrocznia miała rację. Macilowi odbiło. Właśnie świadomie wysłał 200 ludzi na śmierć. Chcę zemsty. Za zmarłych i za żywych zmarłych!,O Oráculo estava certo. O Macil enlouqueceu. Ele mandou 200 homens para as suas mortes sabendo disso. Eu quero vingança. Pelos mortos e pelos mortos-vivos!,,Oracolul avea dreptate. Macil a înnebunit. A trimis în mod voit 200 oameni la moarte. Vreau răzbunare! Pentru morți și morții vii!,Оракул сказал правду: Мэйсил озверел. Он намеренно послал двести человек на верную смерть. Я жажду мести! За убитых и за живых мертвецов!,,Oraklet hade rätt. Macil har blivit galen. Han skickade just medvetet 200 män i döden. Jag vill ha hämnd. För de döda och för de levande döda!,Kahin haklıydı. Macil delirmiş. Bile bile 200 adamı ölüme gönderdi. İntikam istiyorum. Ölüler ve yaşayan ölüler için! +"Macil? Infected and with a Sigil piece. All these years of believing in him, in the cause. And for what?",TXT_SUB_LOG105,,,,"Macil? Nakažený a s dílem Pečeti? Všechny ty roky, kdy jsme mu a naší věci důvěřovali. A k čemu?","Macil? Inficeret og med et Sigil stykke. I alle disse år har jeg troet på ham, på sagen. Og for hvad?","Macil? Infiziert und mit einen Sigli-Teil? All diese Jahre, die ich an ihn geglaubt habe - an die Sache. Und für was?",,,¿Macil infectado con una pieza del Emblema? Y todos estos años de creer en el... en la causa... ¿Y todo para qué?,,"Macil, tartunnan saanut ja pitää hallussaan Sinetin osasta? Kaikki nämä vuodet uskoen häneen, aatteeseen. Ja minkä tähden?",Macil? Infecté par une pièce du Sigil. Toutes ces années où je lui ai fait confiance.. à la cause.. Et pour quoi à la fin?,"Macil? Meg van fertőzve, és van nála egy Pecsét darab is. Én pedig hittem neki évekig, hittem az ügyben. És miért?","Macil? Infettato e con un pezzo del Sigillo. Tutti questi anni passati a credere in lui, e alla causa. E per cosa?",,마실? 시질 조각에 의해 오염됬어. 수 년 동안 믿어온 우리가 바보인가? 아니면 이 운명을 피할 수 없었던 걸까?,"Macil? Geïnfecteerd en met een Sigil stuk. Al die jaren van geloof in hem, in de oorzaak. En waarvoor?","Macil? Infisert og med en Sigil-brikke. I alle disse årene har jeg trodd på ham, på saken... Og for hva?","Macil? Zainfekowany i z kawałkiem Sigil. Przez te wszystkie lata wierzyłem w niego, w sprawę. I po co?","Macil? Infectado e com uma peça do Sigilo. Todos esses anos acreditando nele, acreditando na causa. E pra quê?",,"Macil? Infectat și cu o bucată de Sigiliu. Toți anii crezând în cauza lui, și pentru ce?","Мэйсил? Заражённый... И у него фрагмент Печати. Все эти годы я верила ему, верила в нашу миссию. А теперь?",,"Macil? Infekterad och med en Sigil-bit. Under alla dessa år har jag trott på honom, på saken. Och för vad?","Macil mi? Enfekte olmuş ve bir Sigil parçasıyla. Bunca yıl ona inandım, davaya inandım. Peki ne için?" +"Richter reports that the factory we destroyed leads to a ""lab"", and they're getting a Sigil power signature from within. Back to the factory and our next step to freedom.",TXT_SUB_LOG106,MAP10: After killing Macil while having destroyed the converter in MAP24.,,,"Richter hlásí, že továrna, kterou jsme zničili, vede do „laboratoře“ a detekují z ní energii Pečetě. Zpátky do továrny a našemu dalšímu kroku ke svobodě.","Richter rapporterer, at den fabrik, vi ødelagde, fører til et ""laboratorium"", og at de får en Sigil-kraftsignatur derindefra. Tilbage til fabrikken og vores næste skridt mod frihed.","Richter sagt, in der Fabrik, die wir zerstört haben, gäbe es ein „Labor“, und dort gibt es eine Sigil-Signatur. Zurück zur Fabrik und dem nächsten Schritt zu unserer Freiheit.",,,"Richter informa de que la fábrica que destruimos conduce a un ""laboratorio"", y están recibiendo una señal de poder del Emblema de adentro. De vuelta a la fábrica y nuestro siguiente paso a la libertad.",,"Richter ilmoittaa, että tuhoamamme tehdas johtaa ""laboratorioon"", ja he lukevat sisältä Sinettiosasen energiajälkiä. Takaisin tehtaaseen ja kohti seuraavaa askeltamme vapauteen.","Richter rapporte que l'usine que l'on a détruit mène à un ""laboratoire"" et qu'il s'y trouve une signature de pièce du Sigil à l'intérieur. Retourne à l'usine et on fera un autre pas vers la liberté.","Richter jelentése szerint a felrobbantott gyár egy ""laboratóriumba"" vezet, és a Pecsét jelét sugározza belülről. Tehát a szabadságunk felé teendő következő lépés a gyárnál kezdődik.","Richter ci comunica che la Fabbrica che abbiamo distrutto porta a un ""laboratorio"", ed al suo interno è stato identificato un segnale di un pezzo del Sigillo. Ritorniamo alla fabbrica e il nostro prossimo passo per la libertà.","リヒターの報告では我々が破壊した工場は'研究所'に繋がっていて、 +奴等はシジルの調印を内部から得ている。工場に戻って自由への次の段階に進みましょう",릭터가 말하길 우리가 파괴한 공장은 연구소로 향하는 길이 있대. 그리고 그곳에는 시질 특유의 힘이 감지됐어. 공장으로 돌아가서 자유를 위해 계속 투쟁을 하자.,"Richter meldt dat de fabriek die we vernietigd hebben, leidt naar een ""lab"", en ze krijgen een Sigil power signatuur van binnenuit. Terug naar de fabriek en onze volgende stap naar vrijheid.","Richter rapporterer at fabrikken vi ødela fører til en ""lab"", og at de får en Sigil-kraftsignatur innenfra. Tilbake til fabrikken og vårt neste skritt mot frihet.","Richter donosi, że zniszczona przez nas fabryka prowadzi do ""laboratorium"", a oni otrzymują z niego sygnaturę mocy Sigil. Wracamy do fabryki i naszego kolejnego kroku do wolności.","O Richter disse que a fábrica que destruímos leva a um ""laboratório"" e eles estão captando um sinal de energia lá de dentro. De volta à fábrica e ao nosso próximo passo à liberdade.",,"Richter raportează că fabrica duce către un laborator, și sunt alimentați e puterea unui Sigiliu din interior. Înapoi la fabrică și următorul pas spre libertate.","Рихтер сообщает, что за разрушенной нами фабрикой лежит «лаборатория», и мы засекли характерную энергию фрагмента Печати, исходящую оттуда. Возвращайся на фабрику — сделаем ещё один шаг к нашему освобождению.",,"Richter rapporterar att fabriken som vi förstörde leder till ett ""labb"" och att de får en Sigil-kraftsignatur därifrån. Tillbaka till fabriken och vårt nästa steg mot frihet.","Richter, yok ettiğimiz fabrikanın bir laboratuvara çıktığını ve oradan Sigil gücü sinyali aldıklarını bildirdi. Fabrikaya ve özgürlüğe giden bir sonraki adımımıza dönelim." +Who dares to defy me and enter my fortress? A worthless human? Face me and die!,TXT_SUB_LOG120,MAP16: Entrance → Central door.,,,Kdo se to opovažuje mi vzdorovat a vkročit do mé pevnosti? Bezcenný člověk? Postav se mi a zemři!,Hvem vover at trodse mig og gå ind i min fæstning? Et værdiløst menneske? Se mig i øjnene og dø!,Wer wagt es mir zu trotzen und meine Festung zu betreten? Ein wertloser Mensch? Stelle dich mir und stirb!,,,¿Quién se atreve a desafiarme y entrar en mi fortaleza? ¿Un insignificante humano? ¡Enfréntate a mí y muere!,¿Quién se atreve a desafiarme y entrar a mi fortaleza? ¿Un insignificante humano? ¡Enfréntate a mí y muere!,Kuka kehtaa uhmata minua ja astua sisään linnoitukseeni? Arvoton ihminen? Kohtaa minut ja kuole!,Qui ose me défier et pénétrer ma forteresse? Un humain sans valeur? Faites face à moi et mourrez!,"Ki mer belépni az erődítményebe és ellenszegülni nekem? Egy jelentéktelen ember? Gyere állj ki ellenem, had szedjelek szét!",Chi osa sfidarmi ed entrare nella mia fortezza? Un inutile umano? Affrontami e muori!,"我に歯向かう為に敢えて私の要塞に来たのか?無価値な人間よ? +死をくれてやろう!",감히 어떤 자가 이 몸을 반역하고 요새를 침입한 것이더냐? 나약한 인간이구나. 이 몸의 의해 소멸당해라.,Wie durft mij uit te dagen en mijn vesting binnen te gaan? Een waardeloos mens? Kijk me aan en sterf!,Hvem våger å trosse meg og gå inn i festningen min? Et verdiløst menneske? Møt meg og dø!,Kto ośmieli się przeciwstawić mi i wejść do mojej twierdzy? Bezwartościowy człowiek? Zmierz się ze mną i zgiń!,Quem ousa me desafiar e entrar na minha fortaleza? Um humano insignificante? Enfrente-me e morra!,,Cine îndrăznește să mă înfrunte? Un om jalnic? Înfruntă-mă și mori!,Кто смеет бросать мне вызов и вторгаться в мою крепость? Жалкий человечишка? Сразись со мной и умри!,,Vem vågar trotsa mig och gå in i min fästning? En värdelös människa? Ställ dig inför mig och dö!,Kim bana meydan okuyup kaleme girmeye cüret eder? Değersiz bir insan mı? Benimle yüzleş ve öl! +You cannot kill me. You are just human. And I am more than human.,TXT_SUB_LOG121,MAP16: Boss room unlocked → Bishop,,,Nemůžeš mě zabít. Jsi jen člověk a já jsem víc než člověk.,Du kan ikke dræbe mig. Du er bare et menneske. Og jeg er mere end et menneske.,Du kannst mich nicht töten. Du bist nur ein Mensch. Und ich bin mehr als das.,,,No puedes matarme. Eres solo humano. Y yo soy más que humano.,,"Et voi tappaa minua. Sinä olet vain ihminen, ja minä olen enemmän kuin ihminen.",Vous ne pouvez me tuer. Vous n'êtes qu'un humain. Je suis plus qu'un humain.,Nem tudsz megölni. Csak egy ember vagy. Én pedig már több vagyok mint ember.,Non puoi uccidermi. Tu sei solo umano. E io sono più che umano.,我を殺すことはできまい。貴様は人間。そして私は人間を超えし者だ。,"이 몸은 너에게 사살 당할 수 없다. 이 몸은 초월한 존재, 인간 따위를 넘었기에!",Je kunt me niet doden. Je bent gewoon een mens. En ik ben meer dan een mens.,Du kan ikke drepe meg. Du er bare et menneske. Og jeg er mer enn et menneske.,Nie możesz mnie zabić. Jesteś tylko człowiekiem. A ja jestem czymś więcej niż człowiekiem.,Você não pode me matar. Você é apenas humano. E eu sou mais do que humano.,,"Nu mă poți ucide. Ești doar un om, iar eu sunt mai mult decât atât.","Тебе не убить меня. Ты всего лишь человек. А я нечто большее, чем человек!",,Du kan inte döda mig. Du är bara en människa. Och jag är mer än människa.,Beni öldüremezsin. Sen sadece insansın. Ve ben insandan daha fazlasıyım. "No death, eternal life and more. Much more! This is my task: cyborgs, half flesh, half steel, all to serve the One God. You do not serve? You die! -This putz has another piece of the Sigil.",TXT_SUB_LOG122,"Strife: Veteran Edition: MAP12 - -(If the player first kills Macil and then the Oracle’s spectre before killing the Loremaster with Classic Mode turned off)",,,"- Žádná smrt, nekonečný život a více, mnohem více! To je mé poslání: kyborgové, napůl tělo, napůl ocel, obojí sloužící Jednomu bohu. Nesloužíš? Zemřeš! -- Ten hajzl má další díl Pečeti.","Kein Tod, ewiges Leben und mehr. Viel mehr! Dies ist meine Aufgabe: Cyborgs, halb Fleisch, halb Stahl, alle um einen Gott zu dienen. Du dienst nicht? Du stirbst! -Dieser Idiot hat ein weiteres Teil des Sigils.",,,"No muerte, vida eterna y más. ¡Mucho más! Esta es mi tarea: cyborgs, mitad carne, mitad acero, todo para servir al Dios Único. ¿Tú no lo sirves? ¡Tú mueres! Este zoquete tiene otra pieza del emblema.",,,"Pas de mort: la vie éternelle et plus, bien plus! Cela est mon but: cyborgs, moitié chair, moitié acier, un tout pour servir le Seul Dieu. Vous ne servez pas? Vous mourrez! Ce dégénéré a une autre pièce du Sigil.",,,"不死、更に永遠の命なぞない! +This putz has another piece of the Sigil.",TXT_SUB_LOG122,"SVE.WAD +MAP12: If the player first kills Macil and then the Oracle's spectre before killing the Loremaster with Classic Mode turned off. It talks the Loremaster and BlackBird.",,,"- Žádná smrt, nekonečný život a více, mnohem více! To je mé poslání: kyborgové, napůl tělo, napůl ocel, obojí sloužící Jednomu bohu. Nesloužíš? Zemřeš! +- Ten hajzl má další díl Pečeti.","Ingen død, evigt liv og mere. Meget mere! Dette er min opgave: Cyborgs, halvt kød, halvt stål, alt sammen for at tjene den ene Gud. Du tjener ikke? Du dør! +Denne idiot har endnu et stykke af sigilet.","Kein Tod, ewiges Leben und mehr. Viel mehr! Dies ist meine Aufgabe: Cyborgs, halb Fleisch, halb Stahl, alle um einen Gott zu dienen. Du dienst nicht? Du stirbst! +Dieser Idiot hat ein weiteres Teil des Sigils.",,,"No muerte, vida eterna y más. ¡Mucho más! Esta es mi tarea: cyborgs, mitad carne, mitad acero, todo para servir al Dios Único. ¿Tú no lo sirves? ¡Tú mueres! Este zoquete tiene otra pieza del emblema.",,"Ei kuolemaa, vaan ikuinen elämä ja enemmän, paljon enemmän! Tämä on tehtäväni: Kyborgit, puoliksi lihaa, puoliksi terästä; kaikkien tehtävänä palvellla Yhtä Jumalaa. Et palvele? Kuolet! +Tällä kahjolla on toinen Sinetin osanen.","Pas de mort: la vie éternelle et plus, bien plus! Cela est mon but: cyborgs, moitié chair, moitié acier, un tout pour servir le Seul Dieu. Vous ne servez pas? Vous mourrez! Ce dégénéré a une autre pièce du Sigil.","Semmi halál, halhatatlanság és még sok más. Sok-sok más! A következő a feladatom: kiborgok gyártása, félig ember félig gép aki az Egy Igaz Istent szolgálja. Te nem Őt szolgálod? Akkor meglakolsz! Ennél a pancsernél van egy pecsét darab.","Nessuna morte, vita eterna ed altro ancora. Molto altro! Questo è il mio compito: cyborg, metà carne, metà acciaio, tutti per servire l'Unico Dio. Tu non lo servi! Tu muori! Questo imbecille ha un altro pezzo del Sigillo.","不死、更に永遠の命なぞない! これが私の任務だ:サイボーグ達、半人間半機械、全ては唯一神に従うため。 お前は従わないと?では死ね!この愚か者がシジルの欠片を持っている。","영생, 불사, 뛰어난 지능, 이 몸은 많은 걸 지니고 있소! 강화인간, 생채병기, 반신반체, 오더를 위하여 더욱이 연구해야 하오. 이 몸의 의지에 반역하는 것이라면, 사라지시오! \cy이 미친놈은 시질 조각을 가지고 있어.","Geen dood, eeuwig leven en meer. Veel meer! Dit is mijn taak: cyborgs, half vlees, half staal, half staal, allemaal om de Ene God te dienen. Jullie dienen niet? Je sterft! -Deze putz heeft nog een ander stuk van de Sigil.",,"Nada de morte. Vida eterna e mais, muito mais! Essa é a minha tarefa: cibórgues, metade carne, metade aço, todos servindo ao Deus Único. Se você não serve, você morre! -Esse imbecil possui outra peça do Sigilo.",,,"Никакой смерти. Вечная жизнь, и не только. Гораздо большее. И всё это — моя работа. Киборги — наполовину из плоти, наполовину из стали — всецело служат Единому Богу. Следуй истинной вере или умри! - -— У этого мудака следующий фрагмент Сигила. -", -"Ha ha! Welcome. I have waited for this moment. I have waited for a fool like you to bring me my freedom. Your tiny planet is mine, and you will wish you were never born! ",TXT_SUB_LOG128,"STRIFE1.WAD: MAP29 - -(If the player is progressing through the mediocre ending)",,,"Ha há! Vítej. Čekala jsem na tento okamžik. Čekala jsem na blázna jako ty, který by mi přinesl svobodu. Tvá drobná planeta je moje a ty si budeš přát, že ses nikdy nenarodil!","Ha ha! Willkommen. Ich habe auf diesen Moment gewartet, dass ein Narr wie du mir meine Freiheit bringt. Dein kleiner Planet ist mein, und du wirst dir wünschen nie geboren worden zu sein!",,,"¡Ha ha! Bienvenido. He estado esperando este momento. He estado esperando a un necio como tú para traerme mi libertad. ¡Tu pequeño planeta es mío, y desearás no haber nacido!",,,"Ha ha! Bienvenue, j'ai attendu ce moment. J'ai attendu qu'un idiot comme vous me rende ma liberté. Votre pathétique planète m'appartient, et bientôt, vous allez tous regretter d'être nés!",,"Ha ha! Benvenuto, ho aspettato questo momento. Ho aspettato un idiota come te per ridarmi la libertà. Il tuo patetico pianeta è nelle mie mani, e tu presto rimpiangerai di essere nato.","ハッハッハ!ようこそ。私はこの瞬間を待ってイタ。 +Deze putz heeft nog een ander stuk van de Sigil.","Ingen død, evig liv og mer. Mye mer! Dette er min oppgave: kyborger, halvt kjøtt, halvt stål, alt for å tjene den ene Gud. Du tjener ikke? Da dør du! +Denne tosken har enda en bit av sigillet.","Nie ma śmierci, życie wieczne i jeszcze więcej. O wiele więcej! Oto moje zadanie: cyborgi, pół ciała, pół stali, wszystko po to, by służyć Jedynemu Bogu. Nie służysz? Umrzesz! +Ten pajac ma kolejny kawałek Sigilu.","Nada de morte. Vida eterna e mais, muito mais! Essa é a minha tarefa: cibórgues, metade carne, metade aço, todos servindo ao Deus Único. Se você não serve, você morre! +Esse imbecil possui outra peça do Sigilo.",,"Nu moarte, viață eternă, și mai mult decât atât. Mult mai mult! Asta e misiunea mea: oameni cibernetici, jumătate oțel, jumătate carne, toți servind Adevăratul Zeu. Nu serviți? Muriți! Am altă bucată de Sigiliu.","— Никакой смерти. Вечная жизнь, и не только. Гораздо большее. И всё это — моя работа. Киборги — наполовину из плоти, наполовину из стали — всецело служат Единому Богу. Следуй истинной вере или умри! +— У этого мудака следующий фрагмент Печати. +",,"Ingen död, evigt liv och mycket mer. Mycket mer! Detta är min uppgift: cyborgs, halvt kött, halvt stål, allt för att tjäna den ende Guden. Du tjänar inte? Du dör! +Den här idioten har ytterligare en bit av Sigillet.","Ölüm yok, sonsuz yaşam ve daha fazlası. Çok daha fazlası! Benim görevim bu: Cyborglar, yarı et, yarı çelik, hepsi Tek Tanrı'ya hizmet etmek için. Hizmet etmiyor musun? Ölürsünüz! +Bu salakta Sigil'in bir parçası daha var." +"Ha ha! Welcome. I have waited for this moment. I have waited for a fool like you to bring me my freedom. Your tiny planet is mine, and you will wish you were never born! ",TXT_SUB_LOG128,MAP29: Entity (If the player is progressing through the mediocre ending),,,"Ha há! Vítej. Čekala jsem na tento okamžik. Čekala jsem na blázna jako ty, který by mi přinesl svobodu. Tvá drobná planeta je moje a ty si budeš přát, že ses nikdy nenarodil!","Ha ha! Velkommen. Jeg har ventet på dette øjeblik. Jeg har ventet på at et fjols som dig skulle bringe mig min frihed. Din lille planet er min, og du vil ønske, at du aldrig var blevet født!","Ha ha! Willkommen. Ich habe auf diesen Moment gewartet, dass ein Narr wie du mir meine Freiheit bringt. Dein kleiner Planet ist mein, und du wirst dir wünschen nie geboren worden zu sein!",,,"¡Ha ha! Bienvenido. He estado esperando este momento. He estado esperando a un necio como tú para traerme mi libertad. ¡Tu pequeño planeta es mío, y desearás no haber nacido!",,"Hahaa! Tervetuloa, olen odottanut tätä hetkeä. Olen odottanut kaltaistasi hölmöä tuomaan minulle minun vapauteni. Pikkuinen planeettanne on minun, ja tulet toivomaan, ettet olisi ikinä syntynytkään!","Ha ha! Bienvenue, j'ai attendu ce moment. J'ai attendu qu'un idiot comme vous me rende ma liberté. Votre pathétique planète m'appartient, et bientôt, vous allez tous regretter d'être nés!","Há há! Nincs mit. Erre a pillanatra vágytam. Arra vártom, hogy egy bolond elhozza nekem a szabadságot. A kicsike bolygód immáron az enyém, és azt fogod kívánni hogy bárcsak meg se születtél volna.","Ha ha! Benvenuto. Ho aspettato questo momento. Ho aspettato uno stolto come te per ridarmi la libertà. Il tuo patetico pianeta è nelle mie mani, e tu presto rimpiangerai di essere nato.","ハッハッハ!ようこそ。私はこの瞬間を待ってイタ。 自由を得る為、アンタの様な愚か者を待っていたノダ。 キサマのワクセイはワタシのモノだ、ソシテ生マレタコトニ後悔スルデアロウ。 -","하하, 이 순간만을 기다리고 있었노라. 그대와 같은 어리석은 자가 짐을 풀어줄 순간을. 그대의 조그만 행성은 이제 짐의 것이고, 그대는 태어난 것을 후회하게 될 것이니라!","Ha ha! Welkom. Ik heb op dit moment gewacht. Ik heb gewacht op een dwaas als jij om mij mijn vrijheid te brengen. Jouw kleine planeet is de mijne, en je zult wensen dat je nooit geboren was!",,Ha ha! Bem-vindo. Eu esperei por este momento. Esperei por um tolo como você trazer a minha liberdade. O seu planeta insignificante é meu e você vai desejar nunca ter nascido!,,,"Ха-ха! Приветствую. Я так долго ждала! Я ждала, что идиот вроде тебя освободит меня. Эта крошечная планета моя, и сейчас ты пожалеешь, что родился на свет!","Ха ха! Добродошао. Чекао сам овај тренутак. Чекао сам будалу као ти да ми донесе слободу. Твоја мала планета је моја, и пожељећеш да ниси рођен! " +","하하, 이 순간만을 기다리고 있었노라. 그대와 같은 어리석은 자가 짐을 풀어줄 순간을. 그대의 조그만 행성은 이제 짐의 것이고, 그대는 태어난 것을 후회하게 될 것이니라!","Ha ha! Welkom. Ik heb op dit moment gewacht. Ik heb gewacht op een dwaas als jij om mij mijn vrijheid te brengen. Jouw kleine planeet is de mijne, en je zult wensen dat je nooit geboren was!","Ha ha! Velkommen. Jeg har ventet på dette øyeblikket. Jeg har ventet på dette øyeblikket. Jeg har ventet på at en tosk som deg skulle gi meg min frihet. Din lille planet er min, og du vil ønske at du aldri ble født!","Ha ha! Witam. Czekałem na tę chwilę. Czekałem, aż taki głupiec jak ty przyniesie mi wolność. Twoja mała planeta jest moja, a ty będziesz żałował, że się nie urodziłeś!",Ha ha! Bem-vindo. Eu esperei por este momento. Esperei por um tolo como você trazer a minha liberdade. O seu planeta insignificante é meu e você vai desejar nunca ter nascido!,,"Ha ha! Bun-venit. Am așteptat momentul. Am așteptat pentru un prost ca tine să îmi aducă libertatea. Planeta la minusculă e a mea, și tu îți vei dori să nu te fii născut!","Ха-ха! Приветствую. Я так долго ждала! Я ждала, что идиот вроде тебя освободит меня. Эта крошечная планета моя, и сейчас ты пожалеешь, что родился на свет!",,"Ha ha! Välkommen. Jag har väntat på det här ögonblicket. Jag har väntat på att en idiot som du ska ge mig min frihet. Din lilla planet är min, och du kommer att önska att du aldrig föddes!",Ha ha! Hoş geldiniz. Bu anı bekledim. Senin gibi bir aptalın bana özgürlüğümü getirmesini bekledim. Küçük gezegenin benim olacak ve sen hiç doğmamış olmayı dileyeceksin! "The truth can only be found in universal will. You will fall on your knees in front of the True God, the One Light. Join me and I will complete the Sigil. -I'm sick of this mystical double talk.",TXT_SUB_LOG129,STRIFE1.WAD: MAP27,,,"- Pravda může být nalezena jedině v přání jsoucna. Padneš na kolena před Pravým bohem, Jedním světlem. Připoj se ke mě a já složím Pečeť. -- Tenhle tajemný dvojhlas už mi leze krkem.","Die Warheit kann nur universell gefunden werden. Du wirst im Angesicht des Einen Gottes, des Einen Lichtes auf die Knie fallen. Folge mir und ich werde das Sigil komplettieren. +I'm sick of this mystical double talk.",TXT_SUB_LOG129,MAP27: Entrance (It talks the Loremaster and BlackBird).,,,"- Pravda může být nalezena jedině v přání jsoucna. Padneš na kolena před Pravým bohem, Jedním světlem. Připoj se ke mě a já složím Pečeť. +- Tenhle tajemný dvojhlas už mi leze krkem.","Sandheden kan kun findes i den universelle vilje. Du vil falde på knæ foran den sande Gud, det ene lys. Slut dig til mig, og jeg vil fuldende sigilet. +Jeg er træt af denne mystiske dobbelttale.","Die Warheit kann nur universell gefunden werden. Du wirst im Angesicht des Einen Gottes, des Einen Lichtes auf die Knie fallen. Folge mir und ich werde das Sigil komplettieren. Ich habe genug von diesem mystischen Rumgeschwafel.",,,"La verdad solo puede ser encontrada en la voluntad universal. Te arrodillarás en frente del Dios Único, la Luz Única. Únete a mi y completaré el Emblema. -Estoy cansado de habladuría mística.",,,"La vérité se trouve seulement dans la volonté universelle. Vous allez vous prosterner devant le Seul Dieu, la Seule Lumière. Rejoins-moi et je complèterai le Sigil. -J'en ai eu assez de ce charabia mystique.",,"La verità è solo nella volontà universale. Ti inchinerai all'unico Dio, la sola luce. Vieni con me e io completerò il Sigillo. +Estoy cansado de habladuría mística.",,"Totuus löytyy ainoastaan maailmankaikkeuden yleistahdosta. Lankeat polvillesi Totisen Jumalan, Yhden Valon, edessä. Liity minuun, ja täytän Sinetin. +Olen korviani myöten täynnä tätä mystistä hölynpölyä.","La vérité se trouve seulement dans la volonté universelle. Vous allez vous prosterner devant le Seul Dieu, la Seule Lumière. Rejoins-moi et je complèterai le Sigil. +J'en ai eu assez de ce charabia mystique.","Az igazság az univerzum akaratától függ. Térdre fogsz rogyni az Egy Igaz isten, az Egy Fény előtt. Csatlakozz hozzám, és összerakjuk a Pecsétet. Elegem van a misztikus dupla értelmű tanmesékből.","La verità è solo nella volontà universale. Ti inchinerai all'Unico Dio, la sola luce. Vieni con me e io completerò il Sigillo. Ne ho abbastanza di questo mistico messaggio senza senso.","真実は普遍的な意志でしか見つけられない。 お前は唯一神の前に跪くのだ、希望の光よ。 私の元に着き、シジルを完成させるのだ。この神秘的な戯言もうんざりする。","초월적인 힘을 가짐으로써 진정한 진실을 찾을 수가 있소. 당신은 이 세계의 유일신, 진정한 빛의 막강함에 의해 무릎을 꿇을 것이오. 종지부를 피하려면 시질을 건네고, 우리를 따르시오! \cy이런 맹신적인 하오체가 정말 싫더라!","De waarheid kan alleen worden gevonden in de universele wil. Je zult op je knieën vallen voor de Ware God, het Ene Licht. Sluit je aan bij mij en ik zal de Sigil voltooien. -Ik ben deze mystieke dubbelzinnigheid beu.",,"A verdade só pode ser encontrada na vontade universal. Você cairá de joelhos na frente do Deus Único, a Luz Única. Junte-se a mim e completarei o Sigilo. -Já estou cansada de toda essa ladainha mística.",,,"Истина одна — она в единой воле. Ты упадёшь на колени пред Истинным Богом, Единым Светом. Присоединись ко мне, и я соберу Сигил! - -— Меня тошнит от этой таинственной двуличной болтовни!", -"You... You have crushed my Order, torn through my ruses and threatened centuries of desire. But I will prevail, I will infect you and twist you to my will...",TXT_SUB_LOG130,"STRIFE1.WAD: MAP29 - -(If the player is progressing through the good ending)",,,"Ty... Tys rozdrtil můj Řád, proskočil mými lstmi a ohrozil staletí chtíče. Ale já přetrvám. Já tě nakazím a zkazím, tak, jak chci...","Du... du hast meinen Orden zerstört, meine Fallen überwunden und jahrelange Wünsche gefährdet. Aber ich werde siegen, ich werde dich infizieren und dich meinem Willen beugen...",,,"Tú... Tú has aplastado mi Orden, destrozado mis engaños y amenazado siglos de deseo. Pero yo prevareceré, te infectaré y retorceré a mi voluntad...",,,"Vous.. Vous avez anéanti mon Ordre, percé à travers le voile de mes ruses et menacé des siècle de désirs. Mais je gagnerai, je vous infecterai et vous plierai à ma volonté...",,"Tu... hai schiacciato il mio Ordine, hai rovinato i miei piani e minacciato secoli di desideri. Ma io vincerò, ti infetterò e ti piegherò alla mia volontà...","キサマ...キサマハ我ガオーダーヲ破壊シニシタ、 +Ik ben deze mystieke dubbelzinnigheid beu.","Sannheten kan bare finnes i den universelle viljen. Du vil falle på knærne foran den sanne Gud, det ene lyset. Bli med meg, og jeg vil fullføre sigillet. +Jeg er lei av denne mystiske dobbeltkommunikasjonen.","Prawda może być znaleziona tylko w powszechnej woli. Padniesz na kolana przed Prawdziwym Bogiem, Jedynym Światłem. Dołącz do mnie, a ja uzupełnię Sigil. +Mam dość tego mistycznego gadania.","A verdade só pode ser encontrada na vontade universal. Você cairá de joelhos na frente do Deus Único, a Luz Única. Junte-se a mim e completarei o Sigilo. +Já estou cansada de toda essa ladainha mística.",,"Adevărul poate fi găsit doar în voința universală. Vei cădea în genunchi în fața Adevăratului Zeu, Singura Lumină. Alătură-mi-te și voi completa Sigiliul. M-am săturat de vorbitul ăsta mistic duplicitar.","— Истина одна — она в единой воле. Ты упадёшь на колени пред Истинным Богом, единым светом. Присоединись ко мне, и я соберу Печать! +— Меня тошнит от этой таинственной двуличной болтовни!",,"Sanningen kan bara hittas i den universella viljan. Ni kommer att falla på knä framför den sanna guden, det enda ljuset. Gör mig sällskap och jag kommer att fullborda Sigillet. +Jag är trött på detta mystiska dubbelprat.","Gerçek sadece evrensel iradede bulunabilir. Gerçek Tanrı'nın, Tek Işık'ın önünde diz çökeceksin. Bana katılın ve ben de Sigil'i tamamlayayım. +Bu mistik ikili konuşmalardan bıktım." +"You... You have crushed my Order, torn through my ruses and threatened centuries of desire. But I will prevail, I will infect you and twist you to my will...",TXT_SUB_LOG130,MAP29: Entity (If the player is progressing through the good ending),,,"Ty... Tys rozdrtil můj Řád, proskočil mými lstmi a ohrozil staletí chtíče. Ale já přetrvám. Já tě nakazím a zkazím, tak, jak chci...","Du... Du har knust min orden, revet mine kneb igennem og truet århundreders begær. Men jeg vil sejre, jeg vil inficere dig og dreje dig til min vilje...","Du... du hast meinen Orden zerstört, meine Fallen überwunden und jahrelange Wünsche gefährdet. Aber ich werde siegen, ich werde dich infizieren und dich meinem Willen beugen...",,,"Tú... Tú has aplastado mi Orden, destrozado mis engaños y amenazado siglos de deseo. Pero yo prevareceré, te infectaré y retorceré a mi voluntad...",,"Sinä... Sinä olet murskannut Veljeskuntani, tunkenut läpi ansojeni ja uhannut vuosisatoja palanutta halua. Mutta olen vielä voittava; tartutan sinut ja väännän sinut tahtooni...","Vous.. Vous avez anéanti mon Ordre, percé à travers le voile de mes ruses et menacé des siècle de désirs. Mais je gagnerai, je vous infecterai et vous plierai à ma volonté...","Te...Te voltál aki szétmorzsolta a Rendemet, letépted a trükkök palástyát, és évszázadok kívánatát borítottad fel. Akkor is győzedelmeskedni fogok, megferzőzlek és az akaratomnak megfelelően foglak torzítani...","Tu... hai schiacciato il mio Ordine, hai rovinato i miei piani e minacciato secoli di desideri. Ma io vincerò, ti infetterò e ti piegherò alla mia volontà...","キサマ...キサマハ我ガオーダーヲ破壊シニシタ、 我ノ詭謀ヲ截チ何世紀ニモワタル望ミヲ脅カシタ。 ダガマダ終ワリデハナイ、キサマニ憑キ意志ヲヒネリ出セバ... -","그대... 짐의 명령을 거부하고, 많은 것을 빼앗았고, 수 백 년 동안의 욕망을 위협했느니라. 그러나 짐은, 그대를 침식하여 짐의 의지에 복종하도록 만들 것이니라...","Jullie hebben mijn Orde verpletterd, door mijn listen heen gescheurd en eeuwen van verlangen bedreigd. Maar ik zal zegevieren, ik zal je besmetten en je naar mijn wil draaien....",,"Você... você destruiu a minha Ordem, destroçou meus truques e ameaçou séculos de desejo. Mas eu vou prevalecer. Infectarei você e vou manipulá-lo à minha vontade...",,,"Ты... Ты разгромил мой Орден, прорвался через мои ловушки и сделал столетия ожидания напрасными. Но тебе не победить — я заражу тебя и подчиню своей воле!", -"Sounds like a dream job, doesn't it?",TXT_SUB_LOG200,,,,"Zní jako práce snů, ne?","Hört sich wie ein Traumjob an, nicht wahr?",,,"¿Parece un trabajo ideal, verdad?",,,"Le job de vos rêves, non?",,,,바라던 일 같네. 그렇지 않아?,"Klinkt als een droombaan, nietwaar?",,"Parece ser o emprego ideal, não é mesmo?",,,, -"You've seen too much. Ice him, Macil!",TXT_SUB_LOG201,,,,"Viděl jsi moc. Zab ho, Macile!","Du hast genug gesehen. Mach ihn kalt, Macil!",,,"Has visto demasiado. ¡Acaba con él, Macil!",,,"Vous en avez trop vu. Descend-le, Macil!",,,,"넌 많은 걸 봤어. 얼려버려, 마실!","Je hebt te veel gezien. Ijs hem, Macil!",,"Você já viu demais. Acaba com ele, Macil!",,,, +","그대... 짐의 명령을 거부하고, 많은 것을 빼앗았고, 수 백 년 동안의 욕망을 위협했느니라. 그러나 짐은, 그대를 침식하여 짐의 의지에 복종하도록 만들 것이니라...","Jullie hebben mijn Orde verpletterd, door mijn listen heen gescheurd en eeuwen van verlangen bedreigd. Maar ik zal zegevieren, ik zal je besmetten en je naar mijn wil draaien....","Du... Du har knust min Orden, gjennomskuet mine knep og truet århundrer av begjær. Men jeg vil seire, jeg vil infisere deg og vri deg til min vilje...","Ty... Zmiażdżyłeś mój Zakon, przedarłeś się przez moje podstępy i zagroziłeś wiekom pożądania. Ale ja zwyciężę, zainfekuję cię i zmienię na swoją wolę...","Você... você destruiu a minha Ordem, destroçou meus truques e ameaçou séculos de desejo. Mas eu vou prevalecer. Infectarei você e vou manipulá-lo à minha vontade...",,"Tu... Tu mi-ai strivit Ordinul, și mi-ai amenințat secole de dorință. Dar voi învinge, te voi infecta și îți voi pervertii voința...","Ты... Ты разгромил мой Орден, прорвался через мои ловушки и сделал столетия ожидания напрасными. Но тебе не победить — я заражу тебя и подчиню своей воле!",,"Du... Du har krossat min ordning, slitit igenom mina knep och hotat århundraden av begär. Men jag kommer att segra, jag kommer att infektera dig och vrida dig till min vilja...","Sen... Düzenimi yıktın, hilelerimi parçaladın ve yüzyıllardır süren arzularımı tehdit ettin. Ama ben galip geleceğim, sana bulaşacağım ve seni kendi isteğime dönüştüreceğim." +"Sounds like a dream job, doesn't it?",TXT_SUB_LOG200,,,,"Zní jako práce snů, ne?","Det lyder som et drømmejob, ikke sandt?","Hört sich wie ein Traumjob an, nicht wahr?",,,"Suena a un trabajo ideal, ¿no?",,Eikö kuulostakin unelmapestiltä?,"Le job de vos rêves, non?","Úgy tűnik mint egy álam meló, ugye?","Sembra un lavoro da sogno, no?",,바라던 일 같네. 그렇지 않아?,"Klinkt als een droombaan, nietwaar?","Høres ut som en drømmejobb, ikke sant?","Brzmi jak praca marzeń, prawda?","Parece ser o emprego ideal, não é mesmo?",,"Sună a vis, nu?","Звучит как работа мечты, не так ли?",,"Låter som ett drömjobb, eller hur?","Rüya gibi bir iş, değil mi?" +"You've seen too much. Ice him, Macil!",TXT_SUB_LOG201,,,,"Viděl jsi moc. Zab ho, Macile!","Du har set for meget. Islæg ham, Macil!","Du hast genug gesehen. Mach ihn kalt, Macil!",,,"Has visto demasiado. ¡Acaba con él, Macil!",,"Olet nähnyt liikaa. Murskaa hänet, Macil!","Vous en avez trop vu. Descend-le, Macil!",Túl sokat láttál. öld meg Macil!,"Hai visto troppo. Fallo fuori, Macil!",,"넌 많은 걸 봤어. 얼려버려, 마실!","Je hebt te veel gezien. Ijs hem, Macil!","Du har sett for mye. Legg ham på is, Macil!","Widziałeś już zbyt wiele. Lód, Macil!","Você já viu demais. Acaba com ele, Macil!",,"Ai văzut prea mult. Îngheață-l, Macil!","Ты слишком много видел. Заморозь его, Мэйсил!",,"Du har sett för mycket. Isa honom, Macil!","Çok fazla şey gördün. Buzla onu, Macil!" "Next time, you'll listen to me.",TXT_SUB_LOG202,"(Strife: Veteran Edition) -Random comment when the player dies with Classic Mode turned off",,,Příště budeš poslouchat mě.,Nächstes Mal hörst du auf mich.,,,"La próxima vez, me harás caso.",,,"La prochaine fois, tu m'écouteras.",,,今度は、私の言う事を聞きなさいよ。,"다음번엔, 내 말을 좀 들어. ",Volgende keer luister je naar me.,,"Da próxima vez, você vai me ouvir.",,,,"Следећи пут, слушаћеш ме." -"Ugh, these post-apocalyptic prices...",TXT_SUB_LOG203,,,,"Uf, tyhle postapokalyptické ceny...","Ugh, diese postapokalyptischen Preise...",,,"Ugh, estos precios post-apocalípticos...",,,"Eugh, ces prix post-apocalyptiques..",,,,"으윽, 세기말 가격이네.","Ugh, deze post-apocalyptische prijzen....",,"Urgh, esses preços pós-apocalípticos...",,,, -Take the big one. He won't stop you.,TXT_SUB_LOG204,,,,Vem si toho velkého. Nezastaví tě.,"Nimm das große, Er wird dich nicht stoppen.",,,Toma el grande. No te detendrá.,,,"Prends le gros, il ne t'arrètera pas.",,,,커다란 놈을 막아. 둔하니까.,Neem de grote. Hij zal je niet tegenhouden.,,Leve o grandão. Ele não vai te deter.,,,, -Don't dawdle. Straight ahead!,TXT_SUB_LOG205,,,,Neloudej se. Jdi rovně!,Trödel nicht rum. Direkt voraus!,,,No te pares. ¡Sigue adelante!,,,"Ne traîne pas, tout devant!",,,,꾸물거리지 말고 빨리 움직여야 해! ,Niet treuzelen. Rechtdoor!,,Não pare. Siga adiante!,,,, -You ever notice how these corridors look the same?,TXT_SUB_LOG206,,,,"Všimnul sis, jak všechny to chodby vypadají stejně?","Ist dir schon mal aufgefallen, dass diese Flure alle gleich aussehen?",,,¿Alguna vez te has fijado en como estos pasillos parecen iguales?,,,T'as pas l'impression que ces couloirs ont tous la même tête?,,,,갈 때마다 보이는 복도가 다 똑같다고 생각해본 적 있어? ,Heb je ooit gemerkt hoe deze gangen er hetzelfde uitzien?,,Você já reparou como esses corredores parecem todos iguais?,,,, -"Hey, sometimes I have to guess too!",TXT_SUB_LOG207,,,,"Hej, já taky musím někdy hádat!","Hey, manchmal muss auch ich raten!",,,"¡Eh, a veces tambien tengo que adivinar!",,,"Hé, il y a des fois où il faut aussi que je devine!",,,,"야, 어쩔 때는 나도 추측을 해본다고! ","Hé, soms moet ik ook raden!",,"Ei, as vezes tenho que adivinhar também!",,,, -"Oh, and watch out for the alarm.",TXT_SUB_LOG208,,,,"Oh, a dávej pozor na alarm.","Oh, und achte auf den Alarm.",,,"Oh, y ten cuidado con la alarma.",,,"Oh, et fais attention à l'alarme.",,,,"오, 그리고 경보를 조심해.","Oh, en kijk uit voor het alarm.",,"Ah, e cuidado com o alarme.",,,, +Random comment when the player dies with Classic Mode turned off",,,Příště budeš poslouchat mě.,Næste gang vil du lytte til mig.,Nächstes Mal hörst du auf mich.,,,"La próxima vez, me harás caso.",,Ensi kerralla saat luvan kuunnella minua.,"La prochaine fois, tu m'écouteras.",Majd legközelebb hallgatsz rám.,"La prossima volta, mi ascolterai.",今度は、私の言う事を聞きなさいよ。,"다음번엔, 내 말을 좀 들어. ",Volgende keer luister je naar me.,Neste gang hører du på meg.,Następnym razem mnie posłuchasz.,"Da próxima vez, você vai me ouvir.",,"Data viitoare, o să mă asculți.","Будешь знать, как меня не слушать.",,Nästa gång lyssnar du på mig.,Bir dahaki sefere beni dinlersin. +"Ugh, these post-apocalyptic prices...",TXT_SUB_LOG203,,,,"Uf, tyhle postapokalyptické ceny...",Disse post-apokalyptiske priser...,"Ugh, diese postapokalyptischen Preise...",,,"Ugh, estos precios post-apocalípticos...",,"Ääh, näitä maailmanlopun jälkeisiä hintoja...","Eugh, ces prix post-apocalyptiques..","Fú, ezek az apokalipszis utáni árak...","Ugh, questi prezzi post-apocalittici...",,"으윽, 세기말 가격이네.","Ugh, deze post-apocalyptische prijzen....",Disse postapokalyptiske prisene...,"Ugh, te postapokaliptyczne ceny...","Urgh, esses preços pós-apocalípticos...",,"Ugh, prețurile ăstea post-apocaliptice...","Ух, эти цены после апокалипсиса...",,De här postapokalyptiska priserna...,Bu kıyamet sonrası fiyatları. +Take the big one. He won't stop you.,TXT_SUB_LOG204,,,,Rozdej si to s tím velkým. Nezastaví tě.,Tag den store. Han vil ikke stoppe dig.,"Nimm das große, Er wird dich nicht stoppen.",,,Toma el grande. No te detendrá.,,Ota iso. Hän ei estä sinua.,"Prends le gros, il ne t'arrètera pas.",Vidd el a nagyot. Nem fog beléd kötni.,Prendi quello più grande. Non ti fermerà.,,커다란 놈을 막아. 둔하니까.,Neem de grote. Hij zal je niet tegenhouden.,Ta den store. Han vil ikke stoppe deg.,Weź dużą. Nie zatrzyma cię.,Leve o grandão. Ele não vai te deter.,,"Ia-l pe cel mare, nu te va opri.",Бери самую крупную. Он тебя не остановит.,,Ta den stora. Han kommer inte att stoppa dig.,Büyük olanı al. Seni durdurmayacak. +Don't dawdle. Straight ahead!,TXT_SUB_LOG205,,,,Neloudej se. Jdi rovně!,Du skal ikke tøve. Lige fremad!,Trödel nicht rum. Direkt voraus!,,,No te pares. ¡Sigue adelante!,,Älä vitkastele. Suoraan eteenpäin!,"Ne traîne pas, tout devant!",Ne vesztegesd az időt. Csak egyenesen!,Non indulgiare. Vai avanti!,,꾸물거리지 말고 빨리 움직여야 해! ,Niet treuzelen. Rechtdoor!,Ikke somle. Rett fram!,Nie ociągaj się. Prosto przed siebie!,Não pare. Siga adiante!,,Nu te lenevi. Drept în față!,Не мешкай. Прямо вперёд!,,Tröna inte. Rakt fram!,Oyalanma. Dümdüz ilerle! +You ever notice how these corridors look the same?,TXT_SUB_LOG206,,,,"Všimnul sis, jak všechny to chodby vypadají stejně?","Har du nogensinde lagt mærke til, at disse korridorer ser ens ud?","Ist dir schon mal aufgefallen, dass diese Flure alle gleich aussehen?",,,¿Alguna vez te has fijado en como estos pasillos parecen iguales?,,"Oletko koskaan huomannut, miten samanlaisilta nämä käyttävät näyttävät?",T'as pas l'impression que ces couloirs ont tous la même tête?,"Feltűnt, hogy minden folyosó ugyanúgy néz ki?",Ti sei mai accorto come tutti questi corridoi si assomiglino?,,갈 때마다 보이는 복도가 다 똑같다고 생각해본 적 있어? ,Heb je ooit gemerkt hoe deze gangen er hetzelfde uitzien?,Har du lagt merke til at korridorene ser like ut?,"Zauważyłeś, że te korytarze wyglądają tak samo?",Você já reparou como esses corredores parecem todos iguais?,,Nu observi cum coridoarele ăstea arată mereu la fel?,"Ты когда-нибудь замечал, что эти коридоры выглядят одинаково?",,Har du någonsin lagt märke till att korridorerna ser likadana ut?,Bu koridorların nasıl aynı göründüğünü hiç fark ettin mi? +"Hey, sometimes I have to guess too!",TXT_SUB_LOG207,,,,"Hej, já taky musím někdy hádat!",Nogle gange er jeg også nødt til at gætte!,"Hey, manchmal muss auch ich raten!",,,"¡Eh, a veces tambien tengo que adivinar!",,"Hei, joskus minunkin täytyy arvata!","Hé, il y a des fois où il faut aussi que je devine!",Nekem is néha találgatnom kell.,"Ehi, a volte anche io devo tirare a indovinare!",,"야, 어쩔 때는 나도 추측을 해본다고! ","Hé, soms moet ik ook raden!",Noen ganger må jeg også gjette!,"Hej, czasami ja też muszę zgadywać!","Ei, as vezes tenho que adivinhar também!",,"Hei, uneori și eu ghicesc!","Эй, иногда мне тоже приходится угадывать!",,Ibland måste jag också gissa!,"Hey, bazen ben de tahmin etmek zorunda kalıyorum!" +"Oh, and watch out for the alarm.",TXT_SUB_LOG208,,,,"Oh, a dávej pozor na alarm.","Åh, og pas på alarmen.","Oh, und achte auf den Alarm.",,,"Ah, y ten cuidado con la alarma.",,"Ja muuten, varo hälytystä.","Oh, et fais attention à l'alarme.","Ja, és vigyázz a riasztóval.","Oh, e fai attenzione all'allarme.",,"오, 그리고 경보를 조심해.","Oh, en kijk uit voor het alarm.",Se opp for alarmen.,"Aha, i uważaj na alarm.","Ah, e cuidado com o alarme.",,"Oh, și ai grijă la alarmă!",И остерегайся сигнализации.,,"Åh, och se upp för larmet.","Oh, ve alarma dikkat et." "Oh, jeez. Now look what you've done!",TXT_SUB_LOG209,"(Strife: Veteran Edition) -Random comment when the player dies with Classic Mode turned off",,,"No sakra. Koukej, cos udělal!","Oh je. Sieh nur, was du getan hast.",,,"Oh, cielos. ¡Mira lo que has hecho!",,,"Oh, zut, regarde ce que tu as fait!",,,ああ、そうね。今貴方の仕出かした事を見直しなさい。,"맙소사, 무슨 짓을 저질렀는지 알기나 해?","Oh, jeez. Kijk nu wat je hebt gedaan!",,"Ai, caramba. Olha só o que você fez!",,,, +Random comment when the player dies with Classic Mode turned off",,,"No sakra. Koukej, cos udělal!","Åh, for pokker. Se nu, hvad du har gjort!","Oh je. Sieh nur, was du getan hast.",,,Joder. ¡Mira lo que has hecho!,Dios. ¡Mira lo que hiciste!,"Voi hemmetti. Katso nyt, mitä olet tehnyt!","Oh, zut, regarde ce que tu as fait!","Jézusom, nézd mit műveltél!","Ah, dannazione. Guarda che cosa hai fatto!",ああ、そうね。今貴方の仕出かした事を見直しなさい。,"맙소사, 무슨 짓을 저질렀는지 알기나 해?","Oh, jeez. Kijk nu wat je hebt gedaan!","Å, jøss. Se hva du har gjort!","Oh, jeezu. Zobacz, co zrobiłeś!","Ai, caramba. Olha só o que você fez!",,"Oh, vai. Ia uite ce ai făcut.","Ну блин. Только посмотри, что ты наделал!",,"Åh, herregud. Se vad du har gjort!","Oh, Tanrım. Bak ne yaptın!" Shit. Now you've blown it!,TXT_SUB_LOG210,"(Strife: Veteran Edition) -Random comment when the player dies with Classic Mode turned off",,,Do prdele. Teď jsi to podělal!,"Mist, du hast es verbockt.",,,Mierda. ¡Ya la has liado!,,,"Merde, t'as vraiment tout foutu en l'air!",,,クソが。アンタ今、台無しにしたぞ!,"제길, 다 망쳐 놓았네!",Shit. Nu heb je het verpest!,,Merda. Agora você ferrou tudo!,,,, -Come on! Let's get the hell out of here.,TXT_SUB_LOG211,STRIFE1.WAD: MAP15,,,No tak! Dostaňme se sakra odsud.,Komm schon! Lass uns auf der Stelle von hier verschwinden.,,,¡Venga! Larguémonos de aquí.,,,Allez! Sortons d'ici!,,,頼むぞ!こっからとっとと失せろ!,빨리! 여길 어서 벗어나야 해!,Kom op! Laten we hier als de sodemieter weggaan.,,Vem! Vamos vazar daqui.,,,Ну же! Двигаем отсюда!, -Ooh. You don't mess around.,TXT_SUB_LOG212,,,,"Hmm, ty se nepáráš.",Oh. Du lässt nichts anbrennen.,,,Ooh. No pierdes el tiempo.,,,"Oooh, tu n'y va pas de main morte.",,,,"오, 너 이 일에 정말 진지하구나?",Ooh. Je rotzooit niet.,,Oooh. Você não perde tempo mesmo.,,,, -You're going to mount them on the wall! Keep going!,TXT_SUB_LOG213,,,,Přišpendlíš je ke zdi! Jdi dál!,Willst du sie an der Wand anmontieren? Geh weiter!,,,¡Vas a montarlos en la pared! ¡Sigue!,,,Tu vas les clouer au mur! Continue!,,,,저 녀석들을 모두 벽에 처박아놓자. 힘내! ,Je gaat ze aan de muur bevestigen! Ga door!,,Você vai montá-los na parede! Continua!,,,, -Mm. You are a brute.,TXT_SUB_LOG214,,,,"Mhm, ty jsi ale surovec.",Hm. Du bist aber ein Rohling.,,,Mm. Eres un bruto.,,,"Mm, tu est une brute.",,,,"음, 넌 괴물이야.",Mm. Je bent een bruut.,,"Hmm, seu brutamontes.",,,, -Got a nice rhythm going here.,TXT_SUB_LOG215,,,,Máme tu teď hezký rytmus.,Wir haben hier einen netten Rhythmus drauf.,,,Estás siguiendo un buen ritmo.,,,On a un bon rythme là.,,,,생각보다 박자가 잘 맞는데?,Ik heb hier een mooi ritme.,,Tá rolando um rítmo bom.,,,, -Ooh. Love that boom-boom stick.,TXT_SUB_LOG216,,,,"Oh, pěkná brokáda.",Ooh. Tolles Schießeisen.,,,Ooh. Me encanta.,,,"Ooh, j'adore ce truc qui fait boum.",,,,저 빵야-빵야 막대기 너무나도 좋은걸? ,Ooh. Ik hou van die boom-boom stok.,,"Oooh, adoro.",,,, -Mm. I like the way you carry yourself.,TXT_SUB_LOG217,,,,"Mhm, líbí se mi neseš.","Hm. Ich finde es toll, wie du dich präsentierst.",,,Mm. Me gusta como te lo montas.,,,"Mm, j'aime comment tu te porte.",,,,너 스스로 챙기는 모습이 정말 보기 좋아. ,Mm. Ik hou van de manier waarop je jezelf draagt.,,"Hmm, estou gostando de como você está indo.",,,, -Blast away! They're not human!,TXT_SUB_LOG218,,,,Jen střílej! Nejsou to lidé!,Mach sie alle! Das sind keine Menschen!,,,¡Reviéntalos! ¡No son humanos!,,,"Eclate-les, ils ne sont pas humains!",,,,날려버려! 저놈들은 인간이 아니야! ,Blast away! Ze zijn niet menselijk!,,Arrebenta neles! Eles não são humanos!,,,, +Random comment when the player dies with Classic Mode turned off",,,Do prdele. Teď jsi to podělal!,Pis. Nu har du ødelagt det!,"Mist, du hast es verbockt.",,,Mierda. ¡Ya la has liado!,Carajo. ¡Ya metiste la pata!,"Vittu, nyt meni ihan reisille!","Merde, t'as vraiment tout foutu en l'air!",Francba. Lebuktattál minket!,Merda. Ora hai davvero rovinato tutto!,クソが。アンタ今、台無しにしたぞ!,"제길, 다 망쳐 놓았네!",Shit. Nu heb je het verpest!,Pokker... Nå har du ødelagt det!,Cholera. Teraz to spieprzyłeś!,Merda. Agora você ferrou tudo!,,Rahat. Acum ai distrus totul!,"Чёрт, ты всё испортил!",,Fan också. Nu har du förstört det!,Kahretsin. Şimdi de sen mahvettin! +Come on! Let's get the hell out of here.,TXT_SUB_LOG211,MAP15: Computer destroyed + Room 1,,,No tak! Dostaňme se sakra odsud.,Kom nu! Lad os komme væk herfra.,Komm schon! Lass uns auf der Stelle von hier verschwinden.,,,¡Venga! Larguémonos de aquí.,¡Vamos! Vayámonos de aquí.,Mennään! Häivytään täältä hittoon.,Allez! Sortons d'ici!,Gyerünk húzzunk innen a francba!,Avanti! Andiamocene da qui!,頼むぞ!こっからとっとと失せろ!,빨리! 여길 어서 벗어나야 해!,Kom op! Laten we hier als de sodemieter weggaan.,Nå har du ødelagt det! Kom igjen! La oss komme oss til helvete ut herfra.,No dalej! Wynośmy się stąd.,Vem! Vamos vazar daqui.,,"Haide, să ieșim de aici.",Ну же! Двигаем отсюда!,,Kom igen! Nu sticker vi härifrån.,"Hadi, hadi! Buradan defolup gidelim." +Ooh. You don't mess around.,TXT_SUB_LOG212,,,,"Hmm, ty se nepáráš.",Ooh. Du laver ikke sjov.,Oh. Du lässt nichts anbrennen.,,,Ooh. No pierdes el tiempo.,,"Ooh, et turhia pelleile.","Oooh, tu n'y va pas de main morte.","Ajaj, látom nem tökölsz.",Ooh. Non sei uno che scherza.,,"오, 너 이 일에 정말 진지하구나?",Ooh. Je rotzooit niet.,Ooh. Du tuller ikke.,Ooh. Nie wygłupiaj się.,Oooh. Você não perde tempo mesmo.,,Ooh. Nu te joci.,Ооо. Ты знаешь своё дело.,,Ooh. Du är inte en sån jävel.,Ooh. Hiç oyalanmıyorsun. +You're going to mount them on the wall! Keep going!,TXT_SUB_LOG213,,,,Takhle je přišpendlíš ke zdi! Pokračuj a jdi dál!,Du skal montere dem på væggen! Fortsæt!,Willst du sie an der Wand anmontieren? Geh weiter!,,,¡Vas a montarlos en la pared! ¡Sigue!,,Ripustat heidät seinälle! Jatka vain!,Tu vas les clouer au mur! Continue!,Majd szépen kirakod a fejüket trófeának. Csak így tovább!,Li incollerai al muro! Continua così!,,저 녀석들을 모두 벽에 처박아놓자. 힘내! ,Je gaat ze aan de muur bevestigen! Ga door!,Du skal montere dem på veggen! Fortsett!,Zamierzasz je zamontować na ścianie! Dalej!,Você vai montá-los na parede! Continua!,,O să le pună pe zid! Continuă să mergi!,Тебе нужно закрепить их на стене! Продолжай в том же духе!,,Du ska montera dem på väggen! Fortsätt!,Onları duvara monte edeceksin! Devam et! +Mm. You are a brute.,TXT_SUB_LOG214,,,,"Mhm, ty jsi ale surovec.",Mm. Du er en brutal mand.,Hm. Du bist aber ein Rohling.,,,Mm. Eres un bruto.,,"Mm, olet julma peto.","Mm, tu est une brute.",Hm. Egy állat vagy.,Mm. Sei un bruto.,,"음, 넌 괴물이야.",Mm. Je bent een bruut.,Mm. Du er et råskinn.,Mm. Jesteś brutalem.,"Hmm, seu brutamontes.",,Mm. Ești o brută.,Мм. Ты грубиян.,,Mm. Du är ett vilddjur.,Mm. Sen bir hayvansın. +Got a nice rhythm going here.,TXT_SUB_LOG215,,,,Máme tu teď hezký rytmus.,Du har en god rytme her.,Wir haben hier einen netten Rhythmus drauf.,,,Estás siguiendo un buen ritmo.,,Ehti kiva rytmi muodostua.,On a un bon rythme là.,Jó ütemben haladunk.,Siamo entrati in un bel ritmo qua.,,생각보다 박자가 잘 맞는데?,Ik heb hier een mooi ritme.,Har en fin rytme her.,Mamy tu ładny rytm.,Tá rolando um rítmo bom.,,Mișto ritm.,У тебя хороший ритм.,,Du har en bra rytm.,Burada güzel bir ritim var. +Ooh. Love that boom-boom stick.,TXT_SUB_LOG216,,,,"Oh, pěkná brokáda.",Ooh. Jeg elsker den boom-boom-pind.,Ooh. Tolles Schießeisen.,,,Ooh. Me encanta.,,"Ooh, rakastan tuota tussaria.","Ooh, j'adore ce truc qui fait boum.","Áhh, imádom a söri-sörétest.",Ooh. Adoro quel fucile.,,저 빵야-빵야 막대기 너무나도 좋은걸? ,Ooh. Ik hou van die boom-boom stok.,Ooh. Elsker den boom-boom pinnen.,Ooh. Kocham ten boom-boom stick.,"Oooh, adoro.",,Ooh. Îmi place arma aceea nimicitoare.,О. Обожаю эту палку-взрывалку.,,Ooh. Jag älskar den där boom-boom-pinnen.,Ooh. Bu bum-bum sopasını seviyorum. +Mm. I like the way you carry yourself.,TXT_SUB_LOG217,,,,"Mhm, líbí se mi, jak se neseš.","Jeg elsker denne boom-boom-boom. Jeg kan godt lide den måde, du bærer dig selv på.","Hm. Ich finde es toll, wie du dich präsentierst.",,,Mm. Me gusta como te lo montas.,,"Mm, pidän käytöksestäsi.","Mm, j'aime comment tu te porte.",Hm. Tetszik a magabiztosságod.,Mi piace il modo in cui ti comporti.,,너 스스로 챙기는 모습이 정말 보기 좋아. ,Mm. Ik hou van de manier waarop je jezelf draagt.,Mm. Jeg liker måten du bærer deg selv på.,"Mm. Lubię sposób, w jaki się nosisz.","Hmm, estou gostando de como você está indo.",,Ooh. Îmi place cum te descuri.,"Мм. Мне нравится, как ты ведёшь дело.",,Jag gillar den här bommen. Jag gillar ditt sätt att bära dig själv.,Mm. Kendini taşıma şeklini seviyorum. +Blast away! They're not human!,TXT_SUB_LOG218,,,,Jen střílej! Nejsou to lidé!,Blast away! De er ikke menneskelige!,Mach sie alle! Das sind keine Menschen!,,,¡Reviéntalos! ¡No son humanos!,,Antaa palaa! Ne eivät ole ihmisiä!,"Eclate-les, ils ne sont pas humains!",Meghalsz! Nem is vagy ember!,Falli fuori! Non sono umani!,,날려버려! 저놈들은 인간이 아니야! ,Blast away! Ze zijn niet menselijk!,Skyt i vei! De er ikke mennesker!,Do dzieła! To nie są ludzie!,Arrebenta neles! Eles não são humanos!,,La naiba! Nu sunt umane!,Взрывай! Они не люди!,,Blast away! De är inte mänskliga!,Patlat! Onlar insan değil! Wow! Blackened Acolyte! The new taste sensation...,TXT_SUB_LOG219,"(Strife: Veteran Edition) -When obtaining the “Spontaneous Combustion” achievement",,,Wow! Zčernalý akolyta! Nové kulinářské šílenství...,Wow! Geschmorter Ministrant! Neue Geschmackssensation...,,,¡Guau! ¡Acólito ennegrecido! La nueva sensación de sabor...,,,Wow! Acolyte noirci! Goûte à la nouvelle saveur sensationelle!,,,うぉう!黒ずんだアコライト!新しい趣味に目覚めそうだわ...,숯 빛깔 아콜라이트라! 맛과 감각을 잘 살렸는데? ,Wow! Zwarte acoliet! De nieuwe smaaksensatie....,,Uau! Acólito assado! Uma nova sensação de sabor...,,,, -Keep doing that and you'll go blind... but I like it.,TXT_SUB_LOG220,,,,Pokračuj s tím a oslepneš... ale líbí se mi to.,Mach so weiter und du wirst blind... aber ich finde es toll.,,,Sigue haciendo eso y te quedarás ciego... pero me gusta.,,,Continue et tu vas te rendre aveugle.. j'aime bien par contre.,,,,이 걸 하다보면 네 눈이 좀 멀겠지만... 아찔하고 재밌는 것 같아.,Blijf dat doen en je wordt blind.... maar ik vind het leuk.,,Continua fazendo isso e você ficará cego... mas eu gosto.,,,, -Guess they won't be inviting us back to dinner!,TXT_SUB_LOG221,,,,"Hádám, že tihle nás už na večeři zvát nebudou!","Ich glaube nicht, dass sie uns nochmal einladen werden...",,,¡Supongo que no nos invitarán a cenar!,,,Je pense qu'ils ne vont pas nous inviter à diner!,,,,보답으로 저녁에 초대하지 않을 것 같아서 아쉽네! ,Ik denk dat ze ons niet meer zullen uitnodigen om terug te komen eten!,,Acho que não vão nos convidar para jantar!,,,, -We need to get to the top floor.,TXT_SUB_LOG222,,,,Musíme se dostat na vrchní podlaží.,Wir müssen in die oberste Etage gelangen.,,,Necesitamos llegar a la planta más alta.,,,Il faut que l'on aille au dernier étage.,,,,최상층으로 올라가야 해. ,We moeten naar de bovenste verdieping.,,Precisamos chegar até o último andar.,,,, -Wait... This looks interesting. Check it out.,TXT_SUB_LOG223,,,,Počkej... Tohle vypadá zajímavě. Pojďme to omrknout.,Warte... Das sieht interessant aus. Sieh mal nach.,,,Espera... Esto parece interesante. Échale un vistazo.,,,"Attends.. Ca à l'air intéressant, va voir.",,,,잠깐... 저거 뭔가 흥미로워. 확인해보자.,Wacht..... Dit ziet er interessant uit. Kijk maar eens.,,Peraí.... Isso parece interessante. Dá só uma olhada.,,,, -Ugh. That guy gives me the creeps. Let's steer clear.,TXT_SUB_LOG224,,,,"Brr, z toho chlápka mi mrazí v zádech. Radši se mu vyhněme.",Ugh. da kriegt man ja 'ne Gänsehaut. ,,,Ugh. Ese tipo me da mala espina. Alejémonos.,,,"Eugh, ce type me fout les jetons. Evite le.",,,,"윽, 정말 혐오스러운 녀석들. 청소할 준비를 하자.",Ugh. Die kerel geeft me de kriebels. Laten we wegblijven.,,Urgh. Esse cara me dá arrepios. Vamos passar longe.,,,, -"Left! Turn left!... Oh, other left!",TXT_SUB_LOG225,,,,"Doleva! Jdi doleva...! Aha, další doleva!",Links! Geh nach links... Zur anderen Seite - links!,,,"¡Izquierda! ¡Gira a la izquierda!... Oh, ¡la otra izquierda!",,,Gauche! A Gauche... L'autre gauche!,,,,"왼쪽! 왼쪽으로 이동해!... 잠깐, 다른 왼쪽!","Links! Sla linksaf!...... Oh, andere links!",,"Esquerda! Vira à esquerda!... Ai, a outra esquerda!",,,, -Typical stubborn pig-headed male!... Unless you're a girl.,TXT_SUB_LOG226,,,,"Typický, tvrdohlavý, paličatý muž! ...Leda že bys byla holka.",Typischer sturer Mann... Sofern du kein Mädchen bist.,,,Típico hombre cabezotan con cara de cerdo!... A menos que seas chica.,,,"Typique d'un mec borné comme un porc- Sauf si tu est une fille, bien entendu.",,,,"뻔뻔한 고집불통 남충 놈!... 걱정 마, 너 말고.",Typisch koppig koppig mannetje!...... Tenzij je een meisje bent.,,Típico macho teimoso com cara de porco!... A não ser que você seja menina.,,,, -"Strong, brutal and silent. My kind of partner.",TXT_SUB_LOG227,,,,"Silný, tvrdý a tichý. Přesně můj typ.","Stark, brutal und leise. Mein Typ von Partner.",,,"Fuerte, brutal y callado. Mi tipo de compañero.",,,"Fort, brutal et silencieux. Mon type préféré.",,,,"크고, 아름답고, 과묵하네. 같이 있고 싶은 타입이야.","Sterk, wreed en stil. Mijn soort partner.",,"Forte, bruto e silencioso. Meu tipo de parceiro.",,,, -Okay! I was wrong!,TXT_SUB_LOG228,,,,Dobře! Mýlila jsem se!,"Ok, ich habe mich geirrt.",,,¡OK! ¡Estaba equivocada!,,,"Ok, j'avais tort!",,,,아마도 아니었던 것 같네! ,Oké! Ik had het mis!,,Ok! Eu estava errada!,,,, +When obtaining the “Spontaneous Combustion” achievement",,,Wow! Zčernalý akolyta! Nové kulinářské šílenství...,Wow! Sorte Acolyt! Den nye smagsoplevelse...,Wow! Geschmorter Ministrant! Neue Geschmackssensation...,,,¡Guau! ¡Acólito ennegrecido! La nueva sensación de sabor...,,Vau! Mustaa akoluuttia! Uutuusmakuelämys!,Wow! Acolyte noirci! Goûte à la nouvelle saveur sensationelle!,Wow! Pörkölt ministráns! A szezon új íze...,Wow! Accolito scuro! Il nuovo sensazionale sapore!,うぉう!黒ずんだアコライト!新しい趣味に目覚めそうだわ...,숯 빛깔 아콜라이트라! 맛과 감각을 잘 살렸는데? ,Wow! Zwarte acoliet! De nieuwe smaaksensatie....,Jøss! Svertet akolytt! Den nye smakssensasjonen...,Wow! Czarnoskóry akolita! Nowe doznanie smakowe...,Uau! Acólito assado! Uma nova sensação de sabor...,,"Wow, Acolit Înegrit! Noua senzație...","Ух ты, обугленный служитель! Совсем другое ощущение...",,Wow! Svartklädd akolyt! Den nya smaksensationen...,Vay canına! Karartılmış yardımcı! Yeni tat hissi... +Keep doing that and you'll go blind... but I like it.,TXT_SUB_LOG220,,,,Pokračuj s tím a oslepneš... ale líbí se mi to.,"Bliv ved med det, og du bliver blind... men jeg kan lide det.",Mach so weiter und du wirst blind... aber ich finde es toll.,,,Sigue haciendo eso y te quedarás ciego... pero me gusta.,,Jatka tuota samaan malliin ja sokeudut... mutta pidän siitä.,Continue et tu vas te rendre aveugle.. j'aime bien par contre.,Ha tovább csinálod megvakulsz...mondjuk bejön.,Se continui così diventerai cieco... ma a me piace.,,이 걸 하다보면 네 눈이 좀 멀겠지만... 아찔하고 재밌는 것 같아.,Blijf dat doen en je wordt blind.... maar ik vind het leuk.,"Fortsett med det, og du blir blind... men jeg liker det.","Rób tak dalej, a oślepniesz... ale mi się podoba.",Continua fazendo isso e você ficará cego... mas eu gosto.,,Continuă să faci asta și o să orbești... dar îmi place.,Продолжай в том же духе и ты ослепнешь... но мне это нравится.,,Fortsätt med det där och du blir blind... men jag gillar det.,Bunu yapmaya devam edersen kör olacaksın... ama hoşuma gitti. +Guess they won't be inviting us back to dinner!,TXT_SUB_LOG221,,,,"Hádám, že tihle nás už na večeři zvát nebudou!","Jeg tror ikke, de inviterer os tilbage til middag!","Ich glaube nicht, dass sie uns nochmal einladen werden...",,,¡Supongo que no nos invitarán a cenar!,,Eivät varmaankaan kutsu meitä takaisin illalliselle!,Je pense qu'ils ne vont pas nous inviter à diner!,Szerintem nem hívnak vissza vacsorára.,Mi sa che non ci riinviteranno per cena!,,보답으로 저녁에 초대하지 않을 것 같아서 아쉽네! ,Ik denk dat ze ons niet meer zullen uitnodigen om terug te komen eten!,Antar de ikke vil invitere oss på middag igjen!,Chyba nie zaproszą nas z powrotem na kolację!,Acho que não vão nos convidar para jantar!,,Cred că n-o să ne invite la cină!,"Думаю, они не пригласят нас на ужин!",,Jag antar att de inte kommer att bjuda oss på middag igen!,Sanırım bizi tekrar yemeğe davet etmeyecekler! +We need to get to the top floor.,TXT_SUB_LOG222,,,,Musíme se dostat na vrchní podlaží.,Vi må op på øverste etage.,Wir müssen in die oberste Etage gelangen.,,,Necesitamos llegar a la planta más alta.,,Meidän tarvitsee päästä ylimmälle kerrokselle.,Il faut que l'on aille au dernier étage.,Fel kell jutnunk a legfelső szintre.,Dobbiamo andare al piano di sopra.,,최상층으로 올라가야 해. ,We moeten naar de bovenste verdieping.,Vi må komme oss til øverste etasje.,Musimy dostać się na ostatnie piętro.,Precisamos chegar até o último andar.,,Trebuie să ajungem la ultimul etaj.,Нам нужно попасть на верхний этаж.,,Vi måste ta oss till översta våningen.,En üst kata çıkmalıyız. +Wait... This looks interesting. Check it out.,TXT_SUB_LOG223,,,,Počkej... Tohle vypadá zajímavě. Pojďme to omrknout.,Vent... Det her ser interessant ud. Tjek det ud.,Warte... Das sieht interessant aus. Sieh mal nach.,,,Espera... Esto parece interesante. Échale un vistazo.,,Odota... Tämä näyttää mielenkiintoiselta. Vilkaisepa.,"Attends.. Ca à l'air intéressant, va voir.",Várjunk csak... érdekesen néz ki. Nézd csak meg.,Aspetta... Questo sembra interessante. Guarda qua.,,잠깐... 저거 뭔가 흥미로워. 확인해보자.,Wacht..... Dit ziet er interessant uit. Kijk maar eens.,Vent litt... Dette ser interessant ut. Sjekk det ut.,Czekaj... To wygląda ciekawie. Sprawdźcie to.,Peraí.... Isso parece interessante. Dá só uma olhada.,,"Stai, asta pare interesant. Ia uite.",Подожди... Выглядит интересно. Проверь.,,Vänta lite... Det här ser intressant ut. Kolla in det.,Bekle. Bu ilginç görünüyor. Şuna bir bak. +Ugh. That guy gives me the creeps. Let's steer clear.,TXT_SUB_LOG224,,,,"Brr, z toho chlápka mi mrazí v zádech. Radši se mu vyhněme.",Ugh. Den fyr giver mig myrekryb. Lad os holde os væk.,Ugh. da kriegt man ja 'ne Gänsehaut. ,,,Ugh. Ese tipo me da mala espina. Alejémonos.,,"Yöh, onpa puistattava kaveri. Pysytään loitolla.","Eugh, ce type me fout les jetons. Evite le.",Rámjön a frász attól az ürgétől. Húzzunk innen.,Ugh. Quel tizio mi fa venire la pelle d'oca. Stiamogli alla larga.,,"윽, 정말 혐오스러운 녀석들. 청소할 준비를 하자.",Ugh. Die kerel geeft me de kriebels. Laten we wegblijven.,Æsj. Den fyren gir meg frysninger. La oss holde oss unna.,Ugh. Ten facet przyprawia mnie o dreszcze. Odsuńmy się od niego.,Urgh. Esse cara me dá arrepios. Vamos passar longe.,,Ugh. Tipul ăla mă sperie.,Ух. У меня от этого парня мурашки по коже. Давай держаться от него подальше.,,Usch. Den killen ger mig kalla kårar. Vi håller oss undan.,Ugh. Bu adam beni ürpertiyor. Uzak duralım. +"Left! Turn left!... Oh, other left!",TXT_SUB_LOG225,,,,"Doleva! Jdi doleva...! Aha, další doleva!","Til venstre! Drej til venstre!... Åh, anden venstre!",Links! Geh nach links... Zur anderen Seite - links!,,,"¡Izquierda! ¡Gira a la izquierda!... Oh, ¡la otra izquierda!",,"Vasemmalle! Käänny vasemmalle! Aa, toinen vasen!",Gauche! A Gauche... L'autre gauche!,"Balra! Fordulj balra!... Áh, a másik balra!","Sinistra! Vai a sinistra!... Oh, l'altra sinistra!",,"왼쪽! 왼쪽으로 이동해!... 잠깐, 다른 왼쪽!","Links! Sla linksaf!...... Oh, andere links!","Til venstre! Sving til venstre!... Å, andre venstre!","W lewo! Skręć w lewo!... Och, inna lewa!","Esquerda! Vira à esquerda!... Ai, a outra esquerda!",,"Stânga! Stânga!... Oh, cealaltă stânga!","Налево! Поверни налево!... Ой, другое лево!",,"Vänster! Sväng vänster!... Åh, en annan vänster!","Sola dön! Sola dön!... Oh, diğer sol!" +Typical stubborn pig-headed male!... Unless you're a girl.,TXT_SUB_LOG226,,,,"Typický, tvrdohlavý, paličatý muž! ...Leda že bys byla holka.","Typisk stædig, stædig mand!... Medmindre du er en pige.",Typischer sturer Mann... Sofern du kein Mädchen bist.,,,Típico hombre cabezotan con cara de cerdo!... A menos que seas chica.,,Tyypillinen itsepäinen uppiniskainen mies! Ellet sitten ole tyttö.,"Typique d'un mec borné comme un porc- Sauf si tu est une fille, bien entendu.",Tipikus csökönyös férfi!... Kivétel ha nő vagy.,Tipico testardo maschio dalla testa di maiale!... A meno che tu non sia una ragazza.,,"뻔뻔한 고집불통 남충 놈!... 걱정 마, 너 말고.",Typisch koppig koppig mannetje!...... Tenzij je een meisje bent.,Typisk sta og sta mann!.... Med mindre du er en jente.,"Typowy uparty świniopas!... Chyba, że jesteś dziewczyną.",Típico macho teimoso com cara de porco!... A não ser que você seja menina.,,Bărbat încăpățânat tipic... Asta dacă nu ești femeie.,Типичный упрямый свинопас!... Если только ты не девушка.,,Typiskt en envis svinhuvudman!... Om du inte är en tjej.,Tipik inatçı domuz kafalı erkek!... Tabii kız değilsen. +"Strong, brutal and silent. My kind of partner.",TXT_SUB_LOG227,,,,"Silný, hrubý a tichý. Přesně můj typ.","Stærk, brutal og tavs. Min type partner.","Stark, brutal und leise. Mein Typ von Partner.",,,"Fuerte, brutal y callado. Mi tipo de compañero.",,"Vahva, raaka ja hiljainen. Mieleiseni kumppani.","Fort, brutal et silencieux. Mon type préféré.","Erős , brutális és csendes. Nekem való partner.","Forte, brutale e silenzioso. Il mio tipo di partner.",,"크고, 아름답고, 과묵하네. 같이 있고 싶은 타입이야.","Sterk, wreed en stil. Mijn soort partner.","Sterk, brutal og stille. Min type partner.","Silny, brutalny i milczący. Mój typ partnera.","Forte, bruto e silencioso. Meu tipo de parceiro.",,"Puternic, brutal și silențios. Genul meu de partener.","Сильный, брутальный и молчаливый. Мой типаж.",,"Stark, brutal och tyst. Min typ av partner.","Güçlü, acımasız ve sessiz. Tam bana göre bir partner." +Okay! I was wrong!,TXT_SUB_LOG228,,,,Dobře! Mýlila jsem se!,Okay! Jeg tog fejl!,"Ok, ich habe mich geirrt.",,,¡OK! ¡Estaba equivocada!,,"Okei, olin väärässä!","Ok, j'avais tort!",Jólvan na! Tévedtem!,Okay! Mi sbagliavo!,,아마도 아니었던 것 같네! ,Oké! Ik had het mis!,Okay! Jeg tok feil!,Dobra! Myliłem się!,Ok! Eu estava errada!,,Bine! Am greșit!,Хорошо! Я была неправа!,,Okej! Jag hade fel!,"Tamam, tamam! Yanılmışım!" Too bad we never met... face-to-face.,TXT_SUB_LOG229,"(Strife: Veteran Edition) -Random comment when the player dies with Classic Mode turned off",,,"Škoda, že jsme se nikdy nepotkali... tváří v tvář.","Schade, dass wir uns noch nie begegnet sind...",,,Una pena que nunca nos conocieramos... cara a cara.,,,C'est dommage qu'on s'est jamais rencontré.. En face à face.,,,私達はもう会えなくなったわ...面と向かって。,만나지 못한 게 유감스럽네... 가까이서. ,Jammer dat we elkaar nooit ontmoet hebben..... persoonlijk.,,Pena que nunca nos encontramos... cara a cara.,,,,Жао ми је што се никад нисмо упознали... лице-у-лице. +Random comment when the player dies with Classic Mode turned off",,,"Škoda, že jsme se nikdy nepotkali... tváří v tvář.",Ærgerligt at vi aldrig mødtes... ansigt til ansigt.,"Schade, dass wir uns noch nie begegnet sind...",,,Una pena que nunca nos conocieramos... cara a cara.,,"Sääli, ettemme koskaan tavanneet... kasvokkain.",C'est dommage qu'on s'est jamais rencontré.. En face à face.,"Kár, hogy sohasem találkoztunk... szemtől szembe.",Peccato che non ci siamo mai incontrati... faccia a faccia.,私達はもう会えなくなったわ...面と向かって。,만나지 못한 게 유감스럽네... 가까이서. ,Jammer dat we elkaar nooit ontmoet hebben..... persoonlijk.,Synd vi aldri møttes... ansikt til ansikt.,"Szkoda, że nigdy nie spotkaliśmy się... twarzą w twarz.",Pena que nunca nos encontramos... cara a cara.,,Păcat că nu ne-am întâlnit... față în față.,"Жаль, мы раньше не встречались... лицом к лицу.",,Synd att vi aldrig träffades... ansikte mot ansikte.,Hiç tanışmamış olmamız çok kötü... yüz yüze. I had dreams for you... Tough shit.,TXT_SUB_LOG230,"(Strife: Veteran Edition) -Random comment when the player dies with Classic Mode turned off",,,Snila jsem o tobě... Kurva.,Ich hatte Träume für dich. Scheiße.,,,Tenía sueños para ti... Lástima.,,,J'avais des grands rêves pour toi.. Franchement dommage.,,,私は貴方に希望を抱いていた...クソ世知辛いわ。,너를 꿈꿔왔어... 꿈은 꿈이였나봐.,Ik had dromen voor je.... Moeilijke shit.,,Eu tinha uma grande expectativa sobre você... Que merda.,,,, -"No. Don't enter the town hall. It's not safe anymore. Our cover's been blown. That's why it's raining heavy metal. Kill as many of those big boys as you can. They're called ""Crusaders"". When you're done, I'll guide you to Macil.",TXT_SUB_LOG231,,,,"Ne. Nechoď do radnice, už není bezpečná. Byli jsme odhaleni, proto nám prší kov na hlavu. Zabij kolik těch velkých kluků můžeš. Říká se jim Křižáci. Když jsi hotový, nasměruju tě k Macilovi.","Nein, betrete das Rathaus nicht. Es ist nicht mehr sicher. Unsere Tarnung ist aufgeflogen. Darum regnet es Schwermetall. Erledige so viele von den großen Robotern, wie du kannst. Sie werden „Ordensritter“ genannt. Wenn du das erledigt hast führe ich dich zu Macil.",,,"No. No entres en el ayuntamiento. Ya no es seguro. Nuestra tapadera ha sido descubierta. Por eso está lloviendo metal. Mata a tantos de esos grandotes como puedas. Se llaman ""Cruzados"". Cuando hayas terminado, te guiaré hasta Macil.",,,"Non, n'entre pas dans la mairie, notre couverture est foutue. C'est pour ça que tout est en train de péter. Détruis tous les gros machins que tu croise, on les appelle les ""Croisés"". Quand tu as fini, je te dirais où se trouve Macil.",,,,"잠깐, 시청으로 가지 마. 이미 발각되어서 이젠 안전하지 않아. 아마도 총알의 비가 내리는 유일한 이유일 거야. 최선을 다해서 저 커다란 친구들을 격파해봐. 저놈들은 ""크루세이더"" 라고 해. 이 일을 끝마치면, 마실이 있는 곳으로 안내해줄게. ","Nee. Ga het stadhuis niet binnen. Het is niet meer veilig. Onze dekmantel is opgeblazen. Daarom regent het zwaar metaal. Dood zoveel mogelijk van die grote jongens als je kunt. Ze worden ""Kruisvaarders"" genoemd. Als je klaar bent, begeleid ik je naar Macil.",,"Não. Não entre na prefeitura. Não é mais seguro. Fomos descobertos. É por isso que está vindo chumbo grosso pra todo lado. Mate o máximo possível desses grandalhões. São chamados de ""Cruzados"". Quando você terminar, eu te levo pro Macil.",,,, -"Good work, friend! It's time to bring you inside.",TXT_SUB_LOG232,,,,"Dobrá práce, kamaráde! Je čas přivést tě dovnitř.","Gute Arbeit, mein Freund. Es ist Zeit dich hereinzubringen.",,,"¡Buen trabajo, amigo! Es hora de traerte adentro.",,,"Bien joué, mon ami! Il est temps de te faire rentrer.",,,,"건투를 빌어, 친구! 안으로 들여보내 줄게. ","Goed werk, vriend! Het is tijd om je binnen te brengen.",,"Bom trabalho, amigo! Hora de trazê-lo pra dentro.",,,, -"Watch out for those Crusaders. They're big, hunking robots, and mean as hell. We don't know jack about their weapons, but odds are... you're outmatched. Careful.",TXT_SUB_LOG233,,,,"Pozor na ty Křižáky. Jsou to velcí, mohutní roboti a zatraceně zlí. Nevíme nic o jejich zbraních. Vypadá to že... jsou v přesile. Opatrně.",Sieh dich vor den Ordensrittern vor. Das sind große und mächtige Roboter und höllisch gefährlich. Wir wissen nichts über ihre Waffen aber sie übertreffen deine bei weitem. Vorsicht!,,,"Ten cuidado con esos Cruzados. Son unos robots enormes y despiadados. No sabemos nada sobre sus armas, pero lo probable es... que te lleven ventaja. Cuidado.",,,"Fais attention aux croisés, ce sont des sacrément grosses machines, et salement méchantes, aussi. On ne sait pas quelles armes ils utilisent, mais il est probable qu'ils en ont.. Plus que toi. Fais attention.",,,,"크루세이더를 조심해. 저놈들은 커다랗고 강력한 기동 병기야. 난폭하기도 하지. 놈들의 무장이 뭔지 모르지만, 중요한 점은 넌 포위됐다는 거지. 조심해. ","Kijk uit voor die kruisvaarders. Het zijn grote, hangende robots, en gemeen als de hel. We weten niet hoe het met hun wapens zit, maar de kans is groot dat je niet bij elkaar past. Voorzichtig.",,"Cuidado com esses Cruzados. São robôs grandes e perigosos pra caramba. Não sabemos merda nenhuma sobre as suas armas, mas as chances são de que... você está em desvantagem. Cuidado.",,,, -"Great job. You're my idea of a good time. Now, without anyone seeing you, go through the door on the right, head on upstairs and meet the man.",TXT_SUB_LOG234,,,,"Skvělá práce. Vypadáš jako člověk do nepohody. A teď, bez toho, aby tě někdo uviděl, projdi dveřmi napravo, jdi po schodech nahoru a setkej se s ním.","Gute Arbeit. Das macht mir richtig Freude. Nun gehe - ohne dass man dich sieht - durch die Tür da rechts, und treffe den Mann.",,,"Buen trabajo. Eres mi idea de una buena juerga. Ahora, sin que te vean, ve por la puerta a la derecha, sube las escaleras y conoce al hombre.",,,"Bien joué, tu connaîs bien mon idée d'une bonne fête. Maintenant, sans que personne ne te voie, passe par la porte à droite, monte à l'étage et rencontre le type.",,,,"잘 싸웠어. 내가 생각지도 못한 기발한 생각을 많이 하네. 이제, 모두가 너를 보지 않는 동안 오른쪽 문으로 들어가서 계단을 올라가고 남자를 만나.","Goed werk. Jij bent mijn idee van een goede tijd. Nu, zonder dat iemand je ziet, ga door de deur aan de rechterkant, ga naar boven en ontmoet de man.",,"Muito bom. Você sabe mesmo como entreter alguém. Agora, sem ninguém te ver, entre pela porta à direita, suba as escadas e encontre o cara.",,,, -"You let anyone see you, we'll have your head.",TXT_SUB_LOG235,,,,"Dovolíš, aby tě někdo uviděl, a budeme mít tvou hlavu.","Wenn man dich sieht, machen wir dich alle.",,,"Si dejas que te vean, tomaremos tu cabeza.",,,"Si qui que ce soit te voit, on aura ta tête.",,,,결국엔 사람들이 너를 보았네. 사적인 건 아니지만 넌 죽어줘야겠어. ,"Als je iemand je laat zien, hebben we je hoofd.",,"Se você deixar alguém te ver, a sua cabeça é nossa.",,,, -"You stupid, stumbling, club-footed hunchback imbecile! You've given us away!",TXT_SUB_LOG236,,,,"Ty hloupý, klopýtavý, těžkopádný idiotský hrbáči! Prozradils nás!","Du dummer, ungeschickter, klumpfüßiger, buckliger Trottel. Du hast uns verraten.",,,¡Estúpido patán! ¡Nos has traicionado!,,,"Espèce d'abruti, crétin bossu pas foutu de marcher droit! Tu fait foirer notre couverture!",,,,"이 어리석은, 멍청한, 짜리몽땅한 말미잘 얼간이! 우리 곁을 떠나다니!","Jij stomme, struikelende, knotsvoetige bochelende imbeciel! Je hebt ons weggegeven!",,Seu imbecil idiota estúpido duma figa! Você nos entregou!,,,, -"I wish I was waiting for you behind that door... but I've got to stay underground. It's time for you to meet our leader, Macil.",TXT_SUB_LOG237,,,,"Přála bych si, abych to byla já, kdo bude čekat za těmi dveřmi... ale musím zůstat v podzemí. Je čas setkat se s naším vůdcem, Macilem.","Ich wünschte, ich würde hinter der Tür dort warten... aber ich muss im Untergrund bleiben. Es ist Zeit, unseren Anführer, Macil, zu treffen.",,,"Ojalá fuera yo esperando tras esa puerta... Pero debo mantenerme bajo tierra. Es hora de que conozcas a nuestro lider, Macil.",,,"J'aurais adoré être de l'autre côté de cette porte.. Mais il faut que je reste sous terre. Il est temps que tu rencontre notre leader, Macil.",,"Speravo di aspettarti da dietro la porta... ma sono dovuto stare nel sottosuolo. È tempo per te di incontrare il nostro leader, Macil.",,저 문 앞에서 내가 기다리고 있었으면 얼마나 좋을까... 하지만 난 지하에서 임무를 수행해야 해. 마실 사령관을 만날 준비를 해.,Ik wou dat ik achter die deur op je zat te wachten.... maar ik moet ondergronds blijven. Het is tijd om onze leider Macil te ontmoeten.,,"Eu queria estar te esperando por trás daquela porta... mas eu tenho que ficar no subterrâneo. É hora de você conhecer o nosso líder, Macil.",,,, -,,Blackbird's remarks embedded in other conversations,,,,,,,,,,,,,,,,,,,,, -"Bloated pig. I know nothing about this so-called power coupling, so let's go slow.",TXT_BBSUB_SCRIPT02_D57608_IFIKN,,,,"Zatracený sviňák. O téhle jakési spojce nic nevím, takže na to pojďme pomalu.",Aufgeblasener Mistkerl. Ich weiß nichts über diese sogenannte Anzapfung so lass uns vorsichtig sein.,,,"Cerdo hinchado. No sé nada sobre este tal acoplamiento de energía, así que vayamos con calma.",,,"Quel porc. Je ne sais rien sur ce coupleur énergétique, allons-y doucement.",,"Che pallone gonfiato. Non so nulla sul cosiddetto ""accoppiamento elettrico"", quindi andiamoci piano.","慢心してた。私はこの配電機と言われている物について何も知らない。 -まあゆっくりやろう。",배부른 돼지 같은 녀석. 난 이 추출기에 대해서 아무것도 몰라. 너무 급하게 하지 말자.,"Opgeblazen varken. Ik weet niets van deze zogenaamde stroomkoppeling, dus laten we langzaam gaan.",,"Que porco nojento. Eu não sei nada sobre essa tal ligação de energia, então vamos devagar.",,,Жирная свинья. Я ничего не знаю об этой «соединительной муфте». Давай не будем торопиться., -"Sounds like a dream job, doesn't it?",TXT_BBSUB_SCRIPT03_D4548_GOODB,,,,"Zní jako práce snů, ne?","Hört sich an wie ein Traumjob, nicht wahr?",,,"¿Suena como un trabajo ideal, verdad?",,,"On dirait que c'est le boulot idéal, non?",,"Sembra un lavoro da sogno, no?",夢の様な仕事ね、そう思わない?,"듣기만 해도 꿈에 그리던 일만 같네, 그렇지?","Klinkt als een droombaan, nietwaar?",,"Parece ser o emprego dos sonhos, não é mesmo?",,,"Это же работа мечты, разве нет?","Звучи као посао из снова, је ли тако?" -And I'll be right there with you.,TXT_BBSUB_SCRIPT03_D7580_TAKET,,,,A já tam budu s tebou.,Und ich werde bei deiner Seite sein.,,,Y estaré justo ahí contigo.,,,Et je serais là pour toi.,,E io sarò lì con te.,それで貴方のすぐ傍にいるわ。,그리고 내가 너와 함께 있어 줄께.,En ik zal er zo bij je zijn.,,E eu vou estar bem alí do seu lado.,,,А я буду рядом с тобой., -Worner's a spy we recruited in the warehouse of the power station.,TXT_BBSUB_SCRIPT03_D12128_ASING,,,,"Worner je špión, kterého jsme najali ve skladišti elektrárny.","Worner ist ein Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben.",,,Worner es un espía que reclutamos en el almacén de la estación eléctrica.,,,Worner est un espion que l'on a recruté dans l'entrepôt de la centrale électrique.,,Worner è una spia che noi avevamo reclutato nel magazzino della centrale elettrica.,ワーナーは発電所の倉庫に送った我々のスパイよ。,워너는 우리가 모집한 첩자야. 그는 발전소 창고에 있어.,Worner is een spion die we in het magazijn van de centrale hebben gerekruteerd.,,O Worner é um espião que recrutamos no depósito da usina elétrica.,,,"Уорнэр — шпион, которого мы завербовали на складе электростанции.", -Make sure you're ready for the fight of your life. No scrimping. Spend everything you've got.,TXT_BBSUB_SCRIPT03_D16676_THEPR,,,,"Ujisti se, že jsi připraven na souboj svého života. Žádné škudlení. Utrať všechno, co máš.","Bereite dich auf den Kampf deines Lebens vor. Kein falsche Sparsamkeit, benutze alles, was du hast.",,,Asegúrate de estar preparado para la pelea de tu vida. No escatimes. Gástate todo lo que tengas.,,,"Sois sûr que tu est prêt pour le combat le plus brutal de ta vie. Pas d'avarice, dépense tout ce que tu as.",,Preparati per la lotta della tua vita. Non risparmiare. Spendi tutto ciò che hai.,"己の命の為に戦う準備が出来ているか確認して。 -ケチケチせずに。持ってる物全て使うのよ。",일생일대의 격전에 대비해. 돈 아끼지 말고 있는 대로 다 써.,Zorg ervoor dat je klaar bent voor de strijd van je leven. Geen krassen. Besteed alles wat je hebt.,,Tenha certeza de que você estará preparado para lutar pela sua vida. Não poupa nada. Vai com tudo.,,,Приготовься к главному бою в своей жизни. Не скупись. Потрать на подготовку всё золото., -"Excuse me, I'm gonna be sick.",TXT_BBSUB_SCRIPT04_D21224_BUSIN,,,,"Omluv mě, budu zvracet.","Entschuldige, aber mir wird übel.",,,"Perdona, me voy a poner mala.",,,"Pardon, je crois que je vais vomir.",,"Scusami, sto per sentirmi male.",失礼ながら、しゃくに障るわ。,"실례지만, 이거 좀 골때리겠는데?","Excuseer me, ik word ziek.",,"Desculpa, estou passando mal.",,,"Прости, меня сейчас вырвет.", -Mmm. Sounds like weapons. We can always use more firepower.,TXT_BBSUB_SCRIPT04_D25772_TELLW,,,,"Mhmm, to zní jako zbraně. Palebná síla se nám vždycky hodí.",Hm... Klingt wie Waffen. Mehr Feuerkraft können wir immer gebrauchen.,,,Mmm. Suena a armas. Siempre nos viene bien más potencia de fuego.,,,Mmmh. On dirait des armes. On peut toujours faire avec plus de puissance de feu.,,Mm. Sembrano le armi. Possiamo sempre usare più potenza di fuoco.,フーム。聞く限り武器の様ね。いつも以上の火力を出せそうだ。,으음. 왠지 무기 같은데. 화력이야 더 많으면 좋지.,Mmm. Klinkt als wapens. We kunnen altijd meer vuurkracht gebruiken.,,Hmmm. Sinto cheiro de armas. Poder de fogo a mais é sempre bem-vindo.,,,"М-м-м. Похоже, там оружие. Лишняя огневая мощь не помешает.", -"This sounds too easy, but let's give it a shot.",TXT_BBSUB_SCRIPT04_D31836_WHATD,,,,"To zní moc snadno, ale zkusme to.","Das klingt zu einfach, aber lass es uns versuchen.",,,"Esto suena muy fácil, pero intentémoslo.",,,Ca à l'air trop facile mais ça vaut le coup d'essayer.,,"Sembra troppo facile, ma proviamoci.",簡単すぎるけど、一発かましてみましょうか。,"쉬운 일 같지만, 일단 한번 해보자고.","Dit klinkt te gemakkelijk, maar laten we het eens proberen.",,"Tá parecendo fácil demais, mas vamos tentar.",,,Слишком уж заманчиво. Хотя давай попытаемся., -Who cares. Nobody listens to programmers anyway.,TXT_BBSUB_SCRIPT04_D40932_LETME,,,,"Koho to zajímá, programátory stejně nikdo neposlouchá.",Egal! Wer hört schon auf Programmierer.,,,A quien le importa. Nadie escucha a los programadores de todos modos.,,,"On s'en fout, personne n'écoute les programmeurs de toute manières.",,A chi importa. Tanto nessuno sta a sentire i programmatori.,面倒ね。プログラマーについて知ってるのは誰もいないわ。,어쩌라고. 아무도 프로그래머들 이야기는 안 듣는데.,Wat maakt het uit. Niemand luistert sowieso naar programmeurs.,,Quem liga? Ninguém dá bola pros programadores mesmo.,,,Какая разница? Программистов всё равно никто не слушает.,Кога брига. Нико не слуша програмере ионако. -"Ooh. Glad I'm in hiding, if you know what I mean.",TXT_BBSUB_SCRIPT04_D54576_ITSAS,,,,"Oh, jsem ráda, že se schovávám, jestli víš, co tím myslím.","Uh. Wie gut, dass ich mich verstecke - du weißt schon was ich meine.",,,"Ooh. Menos mal que estoy escondida, si sabes a lo que me refiero.",,,"Ooh, je suis contente d'être cachée, si tu vois ce que je veux dire.",,"Ooh. Per fortuna che sono nascosta, se capisci cosa intendo.",オオゥ。私が言わなくてもわかるけど、隠れた方がいいわね。,"오, 내가 숨어있어서 다행이야. 무슨 뜻인지 알겠지?","Ooh. Blij dat ik ondergedoken zit, als je begrijpt wat ik bedoel.",,"Oooh. Ainda bem que estou escondida, se é que você me entende.",,,"Ой. Хорошо, что я в укрытии, если ты понимаешь, о чём я.", -What a grouch. I hope you get to kill him later.,TXT_BBSUB_SCRIPT05_D1516_OKBUT,,,,"Takový mrzout. Doufám, že ho pak zabijeme.",Was für ein Ekel. Hoffentlich kannst du ihn später mal erledigen.,,,Qué gruñón. Espero que lo mates luego.,,,Quel grincheux. J'espère qu'on va le buter plus tard.,,Che brontolone. Spero che ti ritrovi a ucciderlo dopo.,なに拗ねてるの。後で彼を殺すのを期待してるわ。,뭐가 이리 불만이야. 나중에 얘 좀 꼭 처리해줘.,Wat een humeur. Ik hoop dat je hem later kunt vermoorden.,,Que rabugento! Espero que você mate ele depois.,,,"Ну и зануда. Может, ты потом вернёшься и убьёшь его?", -"""This area's off limits!"" Pompous so-and-so.",TXT_BBSUB_SCRIPT05_D3032_DOILO,,,,„Do této oblasti je vstup zakázán!“ Pompézní hajzl.,„Zutritt verboten!“ Elendiger Wichtigtuer.,,,"""¡Esta área está fuera de limite!"" Que estirado.",,,"""Cette zone est à accès restreint!"" Pompeux anonyme, va.",,"""Quest'area è off limits!"" Pomposo miserabile.",この区域は立入禁止!'そんなワザとらしい。,“이곳은 통행 금지야!” 웃기고 앉아있네.,Dit gebied is verboden terrein! Pompous zo-en-zo.,,"""Proibido entrar nessa área!"" Que miserável prepotente.",,,«Здесь закрытая территория!» Надутый индюк., -What an up guy.,TXT_BBSUB_SCRIPT05_D4548_THEOR,,,,Takový veselý chlapík!,Was für ein Blödmann.,,,Menudo idiota.,,,Quel type honnête.,,Che idiota.,あら、いい男。,아주 들떠있는 녀석이네.,Wat een geweldige kerel.,,Que imbecil.,,,Какой хороший мальчик!, -"Maybe it's because you didn't say ""please"".",TXT_BBSUB_SCRIPT05_D7580_OVERM,,,,"Možná to je tím, žes neřekl „prosím“.",Vielleicht hättest du „Bitte“ sagen sollen.,,,"A lo mejor es porque no dijiste ""por favor"".",,,"Peut être, c'est parce que tu n'a pas dit ""s'il vous plaît.""",,"Forse perché non hai detto ""per favore"".",多分貴方が'お願いします'と言わなかったからよ。,아마 네가 “부탁”을 안 해서 이러나 봐.,"Misschien is het omdat je niet ""alsjeblieft"" hebt gezegd.",,"Deve ser porque você não disse ""por favor"".",,,"Наверное, ты забыл сказать «пожалуйста»?", +Random comment when the player dies with Classic Mode turned off",,,Snila jsem o tobě... Kurva.,Jeg havde drømme om dig... Det er sgu hårdt.,Ich hatte Träume für dich. Scheiße.,,,Tenía sueños para ti... Lástima.,,Elättelin toiveita sinusta... Paska mäihä.,J'avais des grands rêves pour toi.. Franchement dommage.,Álmodtam számodra valamit... Szar ügy.,Ho fatto sogni per te... Che peccato.,私は貴方に希望を抱いていた...クソ世知辛いわ。,너를 꿈꿔왔어... 꿈은 꿈이였나봐.,Ik had dromen voor je.... Moeilijke shit.,Jeg hadde drømmer for deg... Synd for deg.,Miałem dla ciebie marzenia... Twarde gówno.,Eu tinha uma grande expectativa sobre você... Que merda.,,Aveam visuri pentru tine... Rahatule...,Я так надеялся на тебя... Упрямый засранец.,,Jag hade drömmar om dig... Det är jobbigt.,Senin için hayallerim vardı. Zor iş. +"No. Don't enter the town hall. It's not safe anymore. Our cover's been blown. That's why it's raining heavy metal. Kill as many of those big boys as you can. They're called ""Crusaders"". When you're done, I'll guide you to Macil.",TXT_SUB_LOG231,,,,"Ne. Nechoď do radnice, už není bezpečná. Byli jsme odhaleni, proto nám prší olovo na hlavu. Zabij kolik těch velkých kluků můžeš. Říká se jim Křižáci. Když jsi hotový, nasměruju tě k Macilovi.","Nej. Du må ikke gå ind på rådhuset. Det er ikke sikkert længere. Vores dække er blevet afsløret. Det er derfor, det regner heavy metal. Dræb så mange af de store drenge, som du kan. De kaldes ""korsfarere"". Når I er færdige, fører jeg jer til Macil.","Nein, betrete das Rathaus nicht. Es ist nicht mehr sicher. Unsere Tarnung ist aufgeflogen. Darum regnet es Schwermetall. Erledige so viele von den großen Robotern, wie du kannst. Sie werden „Ordensritter“ genannt. Wenn du das erledigt hast führe ich dich zu Macil.",,,"No. No entres en el ayuntamiento. Ya no es seguro. Nuestra tapadera ha sido descubierta. Por eso está lloviendo metal. Mata a tantos de esos grandotes como puedas. Se llaman ""Cruzados"". Cuando hayas terminado, te guiaré hasta Macil.",,"Ei, älä mene kaupungintaloon. Se ei ole enää turvallista; olemme paljastuneet. Sen takia sataa metallia. Tapa noita isoja poikia niin monta kuin pysyt. Niitä kutsutaan ""ristiretkeläisiksi"". Kun olet valmis, johdatan sinut Macilin luokse.","Non, n'entre pas dans la mairie, notre couverture est foutue. C'est pour ça que tout est en train de péter. Détruis tous les gros machins que tu croise, on les appelle les ""Croisés"". Quand tu as fini, je te dirais où se trouve Macil.","Ne menj be a városházára. Már nem biztonságos. Lelepleződtünk. Ezért ennyire sűrű az ólomeső. Ölj meg annyi nagy fiút, amennyit csak tudsz. ""Keresztes"" névre hallgatnak. Ha kész vagy, elvezetlek macilhoz.","No. Non entrare nel municipio. Non è più sicuro. La nostra copertura è saltata. È per questo che sta piovendo piombo. Distruggi più di questi grossi robot che puoi. Si chiamano ""Crociati"". Quando hai finito, di guiderò da Macil.",,"잠깐, 시청으로 가지 마. 이미 발각되어서 이젠 안전하지 않아. 아마도 총알의 비가 내리는 유일한 이유일 거야. 최선을 다해서 저 커다란 친구들을 격파해봐. 저놈들은 ""크루세이더"" 라고 해. 이 일을 끝마치면, 마실이 있는 곳으로 안내해줄게. ","Nee. Ga het stadhuis niet binnen. Het is niet meer veilig. Onze dekmantel is opgeblazen. Daarom regent het zwaar metaal. Dood zoveel mogelijk van die grote jongens als je kunt. Ze worden ""Kruisvaarders"" genoemd. Als je klaar bent, begeleid ik je naar Macil.","Nei. Ikke gå inn i rådhuset. Det er ikke trygt lenger. Vi er avslørt. Det er derfor det regner heavy metal. Drep så mange av de store gutta du kan. De kalles ""korsfarere"". Når du er ferdig, viser jeg deg veien til Macil.","Nie. Nie wchodź do ratusza. To już nie jest bezpieczne. Nasza przykrywka została zdmuchnięta. To dlatego pada heavy metal. Zabij jak najwięcej tych wielkich chłopców. Nazywają się ""krzyżowcami"". Kiedy skończysz, zaprowadzę cię do Macil.","Não. Não entre na prefeitura. Não é mais seguro. Fomos descobertos. É por isso que está vindo chumbo grosso pra todo lado. Mate o máximo possível desses grandalhões. São chamados de ""Cruzados"". Quando você terminar, eu te levo pro Macil.",,"Nu. Nu intra în oraș. Ni s-a dus acoperirea. De asta plouă cu metale grele. Omoară cât de mulți băieți duri poți. Se cheamă ""Cruciați"". Când ești gata o să te îndrum spre Macil.","Нет. Не входи в ратушу. Там небезопасно. Наше прикрытие сорвано. Вот почему идёт дождь из тяжёлого металла. Убей как можно больше этих здоровяков. Они называются «Крестоносцы». Когда закончишь, я отведу тебя к Мэйсилу.",,"Nej. Gå inte in i stadshuset. Det är inte säkert längre. Vår täckmantel är avslöjad. Det är därför det regnar heavy metal. Döda så många av de stora pojkarna som du kan. De kallas ""korsfarare"". När du är klar guidar jag dig till Macil.","Hayır. Belediye binasına girme. Artık güvenli değil. Kimliğimiz açığa çıktı. Bu yüzden heavy metal yağıyor. O koca oğlanlardan öldürebildiğiniz kadarını öldürün. Onlara ""Haçlılar"" deniyor. İşiniz bittiğinde, sizi Macil'e götüreceğim." +"Good work, friend! It's time to bring you inside.",TXT_SUB_LOG232,,,,"Dobrá práce, kamaráde! Je čas přivést tě dovnitř.","Godt arbejde, min ven! Det er tid til at bringe dig indenfor.","Gute Arbeit, mein Freund. Es ist Zeit dich hereinzubringen.",,,"¡Buen trabajo, amigo! Es hora de traerte adentro.",,"Hyvää työtä, ystävä! On aika tuoda sinut sisälle.","Bien joué, mon ami! Il est temps de te faire rentrer.",Szép munka barátom! Ideje bevinnelek.,"Ottimo lavoro, amico! È ora di farti entrare.",,"건투를 빌어, 친구! 안으로 들여보내 줄게. ","Goed werk, vriend! Het is tijd om je binnen te brengen.","Godt jobbet, min venn! Det er på tide å få deg inn.","Dobra robota, przyjacielu! Czas wprowadzić cię do środka.","Bom trabalho, amigo! Hora de trazê-lo pra dentro.",,"Bună treabă, prietene! E timpul să te aduc înăuntru!","Хорошая работа, друг! Пришло время впустить тебя внутрь.",,"Bra jobbat, min vän! Det är dags att ta in dig.","İyi iş, dostum! Seni içeri götürme vakti geldi." +"Watch out for those Crusaders. They're big, hunking robots, and mean as hell. We don't know jack about their weapons, but odds are... you're outmatched. Careful.",TXT_SUB_LOG233,,,,"Pozor na ty Křižáky. Jsou to velcí, mohutní roboti a zatraceně zlí. Nevíme nic o jejich zbraních. Vypadá to že... jsou v přesile. Opatrně.","Pas på de korsfarere. De er store, store robotter, og onde som bare fanden. Vi ved ikke noget om deres våben, men oddsene er... at I er underlegne. Pas på.",Sieh dich vor den Ordensrittern vor. Das sind große und mächtige Roboter und höllisch gefährlich. Wir wissen nichts über ihre Waffen aber sie übertreffen deine bei weitem. Vorsicht!,,,"Ten cuidado con esos Cruzados. Son unos robots enormes y despiadados. No sabemos nada sobre sus armas, pero lo probable es... que te lleven ventaja. Cuidado.",,"Varo noita ristiretkeläisiä. Ne ovat isoja järkälemäisiä robotteja ja helvetin häijyjä. Emme tiedä yhtikäs mitään niiden aseista, mutta todennäköisyys on... että olet heikoilla. Varovaisesti.","Fais attention aux croisés, ce sont des sacrément grosses machines, et salement méchantes, aussi. On ne sait pas quelles armes ils utilisent, mais il est probable qu'ils en ont.. Plus que toi. Fais attention.","Vigyázz azokkal a keresztesekkel. Nagy, testes robotok, és morcosok is. nem sokat tudunk a fegyvereikről, de az esélyied... nem túl fényesek. Vigyázz magadra.","Attento a questi Crociati. Sono grossi, potenti robot e davvero pericolosi. Non sappiamo nulla sulle loro armi ma è molto probabile... che tu sia surclassato. Attento.",,"크루세이더를 조심해. 저놈들은 커다랗고 강력한 기동 병기야. 난폭하기도 하지. 놈들의 무장이 뭔지 모르지만, 중요한 점은 넌 포위됐다는 거지. 조심해. ","Kijk uit voor die kruisvaarders. Het zijn grote, hangende robots, en gemeen als de hel. We weten niet hoe het met hun wapens zit, maar de kans is groot dat je niet bij elkaar past. Voorzichtig.","Se opp for korsfarerne. De er store, kjekke roboter, og slemme som faen. Vi vet ingenting om våpnene deres, men det er sannsynlig at dere er underlegne. Forsiktig.","Uważaj na tych Krzyżowców. To wielkie, potężne roboty i wredne jak diabli. Nie wiemy nic o ich broni, ale prawdopodobnie... nie macie szans. Ostrożnie.","Cuidado com esses Cruzados. São robôs grandes e perigosos pra caramba. Não sabemos merda nenhuma sobre as suas armas, mas as chances são de que... você está em desvantagem. Cuidado.",,"Ai grijă la Cruciați. Sunt roboți imenși, și duri ca naiba. Nu știm absolut nimic despre armamentul lor, dar șansele sunt... nu ești pe măsura lor. Grijă.","Остерегайся крестоносцев. Они большие, громадные роботы, и чертовски злые. Мы не знаем ничего об их оружии, но, скорее всего... ты не справишься. Будь осторожен.",,"Se upp för de där korsfararna. De är stora, jättelika robotar och elaka som fan. Vi vet inget om deras vapen, men oddsen är... att ni är underlägsna. Var försiktig.","Şu Haçlılara dikkat et. Onlar büyük, iri robotlar ve çok acımasızlar. Silahları hakkında bir şey bilmiyoruz, ama ihtimaller... rakibiniz yok. Dikkatli olun." +"Great job. You're my idea of a good time. Now, without anyone seeing you, go through the door on the right, head on upstairs and meet the man.",TXT_SUB_LOG234,,,,"Skvělá práce. Vypadáš jako člověk do nepohody. A teď, bez toho, aby tě někdo uviděl, projdi dveřmi napravo, jdi po schodech nahoru a setkej se s ním.","Godt gået. Du er min idé om en god tid. Gå nu, uden at nogen ser dig, gennem døren til højre, gå op ad trappen og mød manden.","Gute Arbeit. Das macht mir richtig Freude. Nun gehe - ohne dass man dich sieht - durch die Tür da rechts, und treffe den Mann.",,,"Buen trabajo. Eres mi idea de una buena juerga. Ahora, sin que te vean, ve por la puerta a la derecha, sube las escaleras y conoce al hombre.",,"Hyvää työtä. Vastaat mielikuvaani hyvästä ajanvietteestä. Mene nyt kenenkään näkemättä oikeanpuoleisen oven läpi, kulje yläkertaan ja tapaa mies.","Bien joué, tu connaîs bien mon idée d'une bonne fête. Maintenant, sans que personne ne te voie, passe par la porte à droite, monte à l'étage et rencontre le type.","Remek munka. Te vagy a jól eltöltött idő definíciója. Most pedig anélkül, hogy bárki meglátna, menj a jobb oldalon levő ajtóhoz, majd az emeleten találkozz az emberünkkel.","Ottimo lavoro. Tu si che mi fai divertire. Ora, senza che nessuno ti veda, attraversa la porta alla tua destra, vai di sopra e incontralo.",,"잘 싸웠어. 내가 생각지도 못한 기발한 생각을 많이 하네. 이제, 모두가 너를 보지 않는 동안 오른쪽 문으로 들어가서 계단을 올라가고 남자를 만나.","Goed werk. Jij bent mijn idee van een goede tijd. Nu, zonder dat iemand je ziet, ga door de deur aan de rechterkant, ga naar boven en ontmoet de man.","Bra jobbet. Du er min idé om en god tid. Nå, uten at noen ser deg, gå gjennom døren til høyre, gå ovenpå og møt mannen.","Świetna robota. Jesteś moim pomysłem na dobrą zabawę. Przejdź przez drzwi po prawej, wejdź na górę i spotkaj się z tym człowiekiem.","Muito bom. Você sabe mesmo como entreter alguém. Agora, sem ninguém te ver, entre pela porta à direita, suba as escadas e encontre o cara.",,"Bună treabă. Acum, fără nimeni care să te vadă, du-te prin ușa de la dreapta, la etaj, și întâlnește-l.","Отличная работа. Ты - мой способ хорошо провести время. Теперь, чтобы никто тебя не увидел, пройди через дверь справа, поднимись наверх и встреться с мужчиной.",,"Bra jobbat. Du är min idé om att ha roligt. Nu, utan att någon ser dig, gå genom dörren till höger, gå upp på övervåningen och möt mannen.","İyi iş çıkardın. Sen benim iyi vakit geçirme anlayışımsın. Şimdi, kimse seni görmeden, sağdaki kapıdan geç, yukarı çık ve adamla buluş." +"You let anyone see you, we'll have your head.",TXT_SUB_LOG235,,,,"Dovolíš, aby tě někdo uviděl, a budeme mít tvou hlavu.","Hvis du lader nogen se dig, får vi dit hoved.","Wenn man dich sieht, machen wir dich alle.",,,"Si dejas que te vean, tomaremos tu cabeza.",,"Jos annat kenenkään nähdä sinut, pääsi on vadilla.","Si qui que ce soit te voit, on aura ta tête.","Ha bárki meglát, levesszük a fejed.","Se ti vede qualcuno, avremo la tua testa.",,결국엔 사람들이 너를 보았네. 사적인 건 아니지만 넌 죽어줘야겠어. ,"Als je iemand je laat zien, hebben we je hoofd.","Hvis noen ser deg, tar vi hodet ditt.","Jeśli ktoś cię zobaczy, dostaniesz głowę.","Se você deixar alguém te ver, a sua cabeça é nossa.",,Lași pe cineva să te vadă și-ți luăm capul.,"Если ты позволишь кому-нибудь увидеть себя, мы получим твою голову.",,"Om någon ser dig, så tar vi ditt huvud.","Birinin seni görmesine izin verirsen, kelleni alırız." +"You stupid, stumbling, club-footed hunchback imbecile! You've given us away!",TXT_SUB_LOG236,,,,"Ty hloupý, klopýtavý, těžkopádný idiotský hrbáči! Prozradils nás!","Din dumme, snublende, klumpfodede, pukkelryggede idiot! Du har afsløret os!","Du dummer, ungeschickter, klumpfüßiger, buckliger Trottel. Du hast uns verraten.",,,¡Estúpido patán! ¡Nos has traicionado!,,"Sinä typerä, kömpelö, kampurajalkainen imbesilli! Olet paljastanut meidät!","Espèce d'abruti, crétin bossu pas foutu de marcher droit! Tu fait foirer notre couverture!",Te hülye botladozó kétballábú púpos állat! Észrevettek minket miattad!,"Stupido, impiastro, gobbo imbecille! Ci hai fatto scoprire!",,"이 어리석은, 멍청한, 짜리몽땅한 말미잘 얼간이! 우리 곁을 떠나다니!","Jij stomme, struikelende, knotsvoetige bochelende imbeciel! Je hebt ons weggegeven!","Din dumme, klumpfotete, pukkelryggede idiot! Du har avslørt oss!","Ty głupi, potykający się, garbaty imbecylu! Wydałeś nas!",Seu imbecil idiota estúpido duma figa! Você nos entregou!,,Imbecilule! Ne-ai dat de gol!,"Ты тупой, неуклюжий, косолапый горбатый имбецил! Ты нас выдал!",,"Din dumma, snubblande, klumpfotade puckelryggiga idiot! Du har avslöjat oss!","Seni aptal, tökezleyen, sopa ayaklı, kambur embesil! Bizi ele verdin!" +"I wish I was waiting for you behind that door... but I've got to stay underground. It's time for you to meet our leader, Macil.",TXT_SUB_LOG237,,,,"Přála bych si, abych to byla já, kdo bude čekat za těmi dveřmi... ale musím zůstat v podzemí. Je čas setkat se s naším vůdcem, Macilem.","Jeg ville ønske, jeg ventede på dig bag den dør ... men jeg må blive under jorden. Det er tid til at du skal møde vores leder, Macil.","Ich wünschte, ich würde hinter der Tür dort warten... aber ich muss im Untergrund bleiben. Es ist Zeit, unseren Anführer, Macil, zu treffen.",,,"Ojalá fuera yo esperando tras esa puerta... Pero debo mantenerme bajo tierra. Es hora de que conozcas a nuestro lider, Macil.",,"Kunpa olisin voinut olla sinua ovella vastassa, mutta minun on pysyttävä maan alla. Sinun on aika tavata johtajamme, Macilin.","J'aurais adoré être de l'autre côté de cette porte.. Mais il faut que je reste sous terre. Il est temps que tu rencontre notre leader, Macil.","Bárcsak Én várhatnálak az ajtó mögött... de a föld alatt kell maradnom. Itt az ideje, hogy megismerd a vezetőnket, Macilt.","Vorrei esserci io ad attenderti dietro la porta... ma devo rimanere sottoterra. È tempo per te di incontrare il nostro leader, Macil.",,저 문 앞에서 내가 기다리고 있었으면 얼마나 좋을까... 하지만 난 지하에서 임무를 수행해야 해. 마실 사령관을 만날 준비를 해.,Ik wou dat ik achter die deur op je zat te wachten.... maar ik moet ondergronds blijven. Het is tijd om onze leider Macil te ontmoeten.,"Jeg skulle ønske jeg ventet på deg bak den døra, men jeg må holde meg under jorden. Det er på tide at du møter lederen vår, Macil.","Chciałbym czekać na ciebie za tymi drzwiami... ale muszę zostać pod ziemią. Czas, byś poznał naszego przywódcę, Macila.","Eu queria estar te esperando por trás daquela porta... mas eu tenho que ficar no subterrâneo. É hora de você conhecer o nosso líder, Macil.",,"Speram ca eu să te aștept în spatele ușii... dar trebuie să rămân în subteran. E timpul să ne cunoști liderul, Macil.","Хотела бы я ждать тебя за этой дверью... но я должна оставаться под землёй. Пришло время познакомить тебя с нашим лидером, Мэйсилом.",,"Jag önskar att jag väntade på er bakom den dörren... men jag måste stanna under jorden. Det är dags för dig att träffa vår ledare, Macil.",Keşke o kapının arkasında seni bekliyor olsaydım... ama yeraltında kalmalıyım. Liderimiz Macil ile tanışma vaktin geldi. +,,Blackbird's remarks embedded in other conversations,,,,,,,,,,,,,,,,,,,,,,,,, +"Bloated pig. I know nothing about this so-called power coupling, so let's go slow.",TXT_BBSUB_SCRIPT02_D57608_IFIKN,MAP02: Mourel.,,,"Prohnilá svině. O téhle jakési spojce nic nevím, tak na to pojďme pomalu.","Oppustet gris. Jeg ved intet om denne såkaldte kraftkobling, så lad os gå langsomt frem.",Aufgeblasener Mistkerl. Ich weiß nichts über diese sogenannte Anzapfung so lass uns vorsichtig sein.,,,"Qué cerdo hinchado. No sé nada sobre ese supuesto acoplamiento de energía, así que vayamos con calma.",,"Pöhöttynyt sika. En tiedä mitään tästä niin sanotusta virtaliittimestä, joten otetaan rauhallisesti.","Quel porc. Je ne sais rien sur ce coupleur énergétique, allons-y doucement.","Te dagadt disznó. Nem tudok semmit erről az úgynevezett áramelosztóról, szóval menjünk csak lassan.","Che pallone gonfiato. Non so nulla su questo aggeggio, quindi andiamoci piano.","慢心してた。私はこの配電機と言われている物について何も知らない。 +まあゆっくりやろう。",배부른 돼지 같은 녀석. 난 이 추출기에 대해서 아무것도 몰라. 일단 성급하지 말자.,"Opgeblazen varken. Ik weet niets van deze zogenaamde stroomkoppeling, dus laten we langzaam gaan.","Oppblåste gris. Jeg vet ingenting om denne såkalte kraftkoblingen, så la oss ta det rolig.","Nadęta świnia. Nie wiem nic o tym tak zwanym sprzężeniu mocy, więc chodźmy powoli.","Que porco nojento. Eu não sei nada sobre essa tal ligação de energia, então vamos devagar.",,"Porcule. Nu știu nimic despre așa-zisul cuplaj de putere, așa că să mergem încet.",Жирная свинья. Я ничего не знаю об этой «соединительной муфте». Давай не будем торопиться.,,"Uppblåsta gris. Jag vet inget om den här så kallade maktkopplingen, så vi går långsamt fram.","Şişirilmiş domuz. Bu sözde güç birleşmesi hakkında hiçbir şey bilmiyorum, o yüzden yavaş gidelim." +"Sounds like a dream job, doesn't it?",TXT_BBSUB_SCRIPT03_D4548_GOODB,MAP03: Macil.,,,"To zní jako práce snů, ne?","Det lyder som et drømmejob, ikke sandt?","Hört sich an wie ein Traumjob, nicht wahr?",,,"Suena a un trabajo ideal, ¿no?",,Eikö kuulostakin unelmapestiltä?,"On dirait que c'est le boulot idéal, non?","Olyan mint egy álom meló, ugye?","Sembra un lavoro da sogno, no?",夢の様な仕事ね、そう思わない?,"듣기만 해도 꿈에 그리던 일만 같네, 그렇지?","Klinkt als een droombaan, nietwaar?","Høres ut som en drømmejobb, ikke sant?","Brzmi jak praca marzeń, prawda?","Parece ser o emprego dos sonhos, não é mesmo?",,"Sună ca un vis, nu?","Это же работа мечты, разве нет?",,"Låter som ett drömjobb, eller hur?","Rüya gibi bir iş, değil mi?" +And I'll be right there with you.,TXT_BBSUB_SCRIPT03_D7580_TAKET,〃,,,A já tam budu s tebou.,Og jeg vil være lige der sammen med dig.,Und ich werde bei deiner Seite sein.,,,Y estaré justo ahí contigo.,,Ja olen kanssasi koko ajan.,Et je serais là pour toi.,Mindig ott leszek neked.,E io sarò lì con te.,それで貴方のすぐ傍にいるわ。,그리고 내가 너와 함께 있어 줄께.,En ik zal er zo bij je zijn.,Og jeg blir med deg.,A ja będę tam z tobą.,E eu vou estar bem alí do seu lado.,,O să fie alături de tine.,А я буду рядом с тобой.,,Och jag kommer att vara där med dig.,Ben de senin yanında olacağım. +Worner's a spy we recruited in the warehouse of the power station.,TXT_BBSUB_SCRIPT03_D12128_ASING,〃,,,"Worner je špión, kterého jsme najali ve skladišti elektrárny.","Worner er en spion, som vi rekrutterede i lageret på kraftværket.","Worner ist ein Spion, den wir im Lagerhaus des Kraftwerks rekrutiert haben.",,,Worner es un espía que reclutamos en el almacén de la central eléctrica.,,Worner on värväämämme vakooja voimalaitoksen varastolta.,Worner est un espion que l'on a recruté dans l'entrepôt de la centrale électrique.,"Worner egy spion, akit átállítottunk az oldalunkra az erőmű raktárjában.",Worner è una spia che noi avevamo reclutato nel magazzino della centrale elettrica.,ワーナーは発電所の倉庫に送った我々のスパイよ。,워너는 우리가 모집한 첩자야. 그는 발전소 창고에 있어.,Worner is een spion die we in het magazijn van de centrale hebben gerekruteerd.,Worner er en spion vi rekrutterte på lageret til kraftstasjonen.,"Worner to szpieg, którego zwerbowaliśmy w magazynie elektrowni.",O Worner é um espião que recrutamos no depósito da usina elétrica.,,Worner e un spion pe care l-am recrutat în depozitul stației de energie.,"Уорнэр — шпион, которого мы завербовали на складе электростанции.",,Worner är en spion som vi rekryterade i kraftverkets lager.,"Worner, güç istasyonunun deposunda işe aldığımız bir casus." +Make sure you're ready for the fight of your life. No scrimping. Spend everything you've got.,TXT_BBSUB_SCRIPT03_D16676_THEPR,〃,,,"Ujisti se, že jsi připraven na souboj svého života. Žádné škudlení. Utrať všechno, co máš.","Sørg for, at du er klar til dit livs kamp. Ingen spareøvelser. Brug alt, hvad du har.","Bereite dich auf den Kampf deines Lebens vor. Kein falsche Sparsamkeit, benutze alles, was du hast.",,,Asegúrate de estar preparado para la pelea de tu vida. No escatimes. Gástate todo lo que tengas.,,"Pidä huoli, että olet valmis taisteluun elämästäsi. Ei pihistelyä, käytä kaikki varasi.","Sois sûr que tu est prêt pour le combat le plus brutal de ta vie. Pas d'avarice, dépense tout ce que tu as.","Remélem készen állsz életed harcára. Ne kicsinyeskedj, költsd el minden pénzed.",Preparati per la lotta della tua vita. Non risparmiare. Spendi tutto ciò che hai.,"己の命の為に戦う準備が出来ているか確認して。 +ケチケチせずに。持ってる物全て使うのよ。",일생일대의 격전에 대비해. 돈 아끼지 말고 있는 대로 다 써.,Zorg ervoor dat je klaar bent voor de strijd van je leven. Geen krassen. Besteed alles wat je hebt.,Sørg for at du er klar for ditt livs kamp. Ikke spar på noe. Bruk alt du har.,"Upewnij się, że jesteś gotowy na walkę swojego życia. Nie oszczędzaj. Wydajcie wszystko, co macie.",Tenha certeza de que você estará preparado para lutar pela sua vida. Não poupa nada. Vai com tudo.,,Pregătește-te pentru lupta vieții tale. Cheltuie tot ce ai.,Приготовься к главному бою в своей жизни. Не скупись. Потрать на подготовку всё золото.,,Se till att du är redo för ditt livs kamp. Ingen snålhet. Spendera allt du har.,Hayatının savaşına hazır olduğundan emin ol. Cimrilik yok. Sahip olduğun her şeyi harca. +"Excuse me, I'm gonna be sick.",TXT_BBSUB_SCRIPT04_D21224_BUSIN,MAP04: Derwin.,,,"Omluv mě, budu zvracet.","Undskyld mig, jeg bliver syg.","Entschuldige, aber mir wird übel.",,,"Disculpa, pero me voy a poner mala.","Disculpa, pero me voy a enfermar.","Suo anteeksi, kohta lentää laatta.","Pardon, je crois que je vais vomir.","Bocs, de mindjárt rosszul leszek.","Scusami, sto per sentirmi male.",失礼ながら、しゃくに障るわ。,"실례지만, 이거 좀 골때리겠는데?","Excuseer me, ik word ziek.","Unnskyld meg, jeg må kaste opp.","Przepraszam, będę chory.","Desculpa, estou passando mal.",,"Scuză-mă, o să mi se facă rău.","Прости, меня сейчас вырвет.",,"Ursäkta mig, jag måste spy.","Affedersiniz, hasta olacağım." +Mmm. Sounds like weapons. We can always use more firepower.,TXT_BBSUB_SCRIPT04_D25772_TELLW,MAP04: Worner.,,,"Mhmm, to zní jako zbraně. Palebná síla se nám vždycky hodí.",Jeg er syg. Lyder som våben. Vi kan altid bruge mere ildkraft.,Hm... Klingt wie Waffen. Mehr Feuerkraft können wir immer gebrauchen.,,,Mmm. Suena a armas. Siempre nos viene bien más potencia de fuego.,,"Mmm, kuulostaa aseilta. Lisätulivoima aina kelpaa.",Mmmh. On dirait des armes. On peut toujours faire avec plus de puissance de feu.,Hmmm. Még több fegyvernek hangzik. Sosem lehet elég fegyverünk.,Mm. Sembrano delle armi. Ci fanno sempre comodo armi pesanti.,フーム。聞く限り武器の様ね。いつも以上の火力を出せそうだ。,으음. 왠지 무기 같은데. 화력이야 더 많으면 좋지.,Mmm. Klinkt als wapens. We kunnen altijd meer vuurkracht gebruiken.,Mmm. Høres ut som våpen. Vi kan alltids bruke mer ildkraft.,Mmm. Brzmi jak broń. Zawsze możemy użyć więcej siły ognia.,Hmmm. Sinto cheiro de armas. Poder de fogo a mais é sempre bem-vindo.,,Mmm. Sună a arme. Putem folosi mai multă putere de foc oricând.,"М-м-м. Похоже, там оружие. Лишняя огневая мощь не помешает.",,"Jag är sjuk, jag måste bli sjuk. Låter som vapen. Vi kan alltid behöva mer eldkraft.",Mmm. Silahlara benziyor. Her zaman daha fazla ateş gücü kullanabiliriz. +"This sounds too easy, but let's give it a shot.",TXT_BBSUB_SCRIPT04_D31836_WHATD,MAP04: Reactor Core → Northern alarm door,,,"To zní až moc snadně, ale zkusme to.","Det lyder for nemt, men lad os prøve.","Das klingt zu einfach, aber lass es uns versuchen.",,,"Esto suena muy fácil, pero intentémoslo.",,"Kuulostaa liian helpolta, mutta yritetään.",Ca à l'air trop facile mais ça vaut le coup d'essayer.,"Túl könnyűnek hangzik, de próbálkozzunk meg vele.","Sembra troppo facile, ma proviamoci.",簡単すぎるけど、一発かましてみましょうか。,"쉬운 일 같지만, 일단 한번 해보자고.","Dit klinkt te gemakkelijk, maar laten we het eens proberen.","Dette høres for enkelt ut, men la oss prøve.","To brzmi zbyt łatwo, ale spróbujmy.","Tá parecendo fácil demais, mas vamos tentar.",,"Sună ușor, dar să încercăm.",Слишком уж заманчиво. Хотя давай попытаемся.,,"Det här låter för enkelt, men vi gör ett försök.",Kulağa çok kolay geliyor ama bir deneyelim. +Who cares. Nobody listens to programmers anyway.,TXT_BBSUB_SCRIPT04_D40932_LETME,MAP04: Reactor Core → Southern alarm door,,,"Koho to zajímá, programátory stejně nikdo neposlouchá.",Det er ligegyldigt. Ingen lytter til programmører alligevel.,Egal! Wer hört schon auf Programmierer.,,,¿A quién le importa? Si nadie escucha a los programadores.,,Mitä väliä. Kukaan ei muutenkaan kuuntele ohjelmoijia.,"On s'en fout, personne n'écoute les programmeurs de toute manières.",Kit érdekel. Senki sem hallgat a programozókra.,A chi importa. Tanto nessuno sta a sentire i programmatori.,面倒ね。プログラマーについて知ってるのは誰もいないわ。,어쩌라고. 아무도 프로그래머들 이야기는 안 듣는데.,Wat maakt het uit. Niemand luistert sowieso naar programmeurs.,Hvem bryr seg? Ingen hører på programmerere uansett.,Kogo to obchodzi. I tak nikt nie słucha programistów.,Quem liga? Ninguém dá bola pros programadores mesmo.,,Cui îi pasă. Nimeni nu ascultă de programatori oricum.,Какая разница? Программистов всё равно никто не слушает.,,Vem bryr sig? Ingen lyssnar på programmerare ändå.,Kimin umurunda. Kimse programcıları dinlemiyor zaten. +"Ooh. Glad I'm in hiding, if you know what I mean.",TXT_BBSUB_SCRIPT04_D54576_ITSAS,〃,,,"Ou, jsem ráda, že se schovávám, jestli víš, co tím myslím.","Ooh. Jeg er glad for, at jeg gemmer mig, hvis du forstår, hvad jeg mener.","Uh. Wie gut, dass ich mich verstecke - du weißt schon was ich meine.",,,"Ooh. Menos mal que estoy escondida, si sabes a lo que me refiero.",,"Oo, onneksi olen piilossa, tiedätkö.","Ooh, je suis contente d'être cachée, si tu vois ce que je veux dire.","Óh. Még jó hogy ebújtam, már ha érted mire gondolok.","Ooh. Per fortuna che sono nascosta, se capisci cosa intendo.",オオゥ。私が言わなくてもわかるけど、隠れた方がいいわね。,"오, 내가 숨어있어서 다행이야. 무슨 뜻인지 알겠지?","Ooh. Blij dat ik ondergedoken zit, als je begrijpt wat ik bedoel.","Ooh. Jeg er glad jeg er i skjul, hvis du skjønner hva jeg mener.","Ooh. Cieszę się, że się ukrywam, jeśli wiesz, co mam na myśli.","Oooh. Ainda bem que estou escondida, se é que você me entende.",,"Ooh. Mă bucur că mă ascund, dacă știi ce zic.","Ой. Хорошо, что я в укрытии, если ты понимаешь, о чём я.",,"Ooh. Jag är glad att jag gömmer mig, om du förstår vad jag menar.","Ooh. Saklandığıma sevindim, ne demek istediğimi anlıyorsan." +What a grouch. I hope you get to kill him later.,TXT_BBSUB_SCRIPT05_D1516_OKBUT,MAP05: Door Guard.,,,"Takový mrzout. Doufám, že ho pak zabijeme.","Sikke en gnavpot. Jeg håber, du får lov til at dræbe ham senere.",Was für ein Ekel. Hoffentlich kannst du ihn später mal erledigen.,,"Kiel grumblema. Mi esperas, ke vi mortigos lin poste.",Qué gruñón. Espero que lo mates luego.,,Mikä hapannaama. Toivottavasti pääset tappamaan hänet myöhemmin.,Quel grincheux. J'espère qu'on va le buter plus tard.,Micsoda mogorva barom. Remélem később lehetőséged lesz megölni.,Che brontolone. Spero che ti ritrovi a ucciderlo dopo.,なに拗ねてるの。後で彼を殺すのを期待してるわ。,뭐가 이리 불만이야. 나중에 얘 좀 꼭 처리해줘.,Wat een humeur. Ik hoop dat je hem later kunt vermoorden.,For en grinebiter. Jeg håper du får drepe ham senere.,"Co za zrzęda. Mam nadzieję, że będziesz mógł go później zabić.",Que rabugento! Espero que você mate ele depois.,,Ce dobitoc. Sper să îl omori mai târziu.,"Ну и зануда. Надеюсь, ты потом вернёшься и снесёшь ему башку.",,Vilken gnällspik. Jag hoppas att du får döda honom senare.,Ne huysuz. Umarım onu daha sonra öldürürsün. +"""This area's off limits!"" Pompous so-and-so.",TXT_BBSUB_SCRIPT05_D3032_DOILO,〃,,,„Do této oblasti je vstup zakázán!“ Pompézní hajzl.,Dette område er forbudt område! Opblæste sådan-og-så.,„Zutritt verboten!“ Elendiger Wichtigtuer.,,,«Istí firi di lis límitis». Pero qué estirado.,«Istí firi di lis límitis». Pero qué creído.,"""Alueeseen on pääsy kielletty!"" Tärkeilevä mitäänsanomattomuus.","""Cette zone est à accès restreint!"" Pompeux anonyme, va.","""Tiltott a belépés!"" Persze már.","""Quest'area è ad accesso riservato!"" Pomposo miserabile.",この区域は立入禁止!'そんなワザとらしい。,“이곳은 통행 금지야!” 웃기고 앉아있네.,Dit gebied is verboden terrein! Pompous zo-en-zo.,Dette området er forbudt område! Pompøse så-og-så.,Ten teren jest niedostępny! Nadęty taki i taki.,"""Proibido entrar nessa área!"" Que miserável prepotente.",,"""Zona asta e interzisă!"" Pompos așa-și-așa.",«Здесь закрытая территория!» Надутый индюк.,,Det här området är förbjudet område! Pompösa sån och sån.,Burası yasak bölge! Kendini beğenmiş herif. +What an up guy.,TXT_BBSUB_SCRIPT05_D4548_THEOR,MAP05: Prison Guard.,,,Takový veselý chlapík!,Sikke en opblæst fyr.,Was für ein Blödmann.,,,Menudo idiota.,Qué «agradable» sujeto.,Mikä höhlä.,Quel type honnête.,De egy hülye.,Che idiota.,あら、いい男。,아주 들떠있는 녀석이네.,Wat een geweldige kerel.,For en oppblåst fyr.,Co za gość.,Que imbecil.,,Ce tip.,Какой хороший мальчик!,,Vilken uppkäftig kille.,Ne adam ama. +"Maybe it's because you didn't say ""please"".",TXT_BBSUB_SCRIPT05_D7580_OVERM,MAP05: Montag.,,,"Možná to je tím, žes neřekl „prosím“.","Måske er det fordi du ikke sagde ""tak"".",Vielleicht hättest du „Bitte“ sagen sollen.,,Eble ĉar vi ne diris «bonvole».,Habrá sido porque no has dicho «por favor».,Habrá sido porque no dijiste «por favor».,"Ehkä, koska et pyytänyt riittävän nätisi.","Peut être, c'est parce que tu n'a pas dit ""s'il vous plaît.""","Lehet mert nem mondtad hogy ""kérem szépen"".","Forse perché non hai detto ""per favore"".",多分貴方が'お願いします'と言わなかったからよ。,아마 네가 “부탁”을 안 해서 이러나 봐.,"Misschien is het omdat je niet ""alsjeblieft"" hebt gezegd.","Kanskje det er fordi du ikke sa ""vær så snill""?","Może to dlatego, że nie powiedziałeś ""proszę"".","Deve ser porque você não disse ""por favor"".",,"Poate pentru nu ai spus ""te rog"".","Наверное, ты забыл сказать «пожалуйста»?",,"Kanske är det för att du inte sa ""snälla"".","Belki de ""lütfen"" demediğin içindir." "Everybody is so needy. -",TXT_BBSUB_SCRIPT06_D1516_DOMYF,,,,Každý toho tolik potřebuje.,Jeder hier ist so bedürftig!,,,Todo el mundo es tan necesitado.,,,Tout le monde est tellement demandant.,,Tutti sono così bisognosi.,誰もがとても貧しいのよ。,다들 참 궁색하게 사네.,Iedereen is zo behoeftig.,,Por que todo mundo é tão mimimizento?,,,Тут все такие нуждающиеся!, -Great. Now we're shopping for the Rat King.,TXT_BBSUB_SCRIPT06_D3032_BRING,,,,"Super, teď máme nakupovat pro Krysího krále.","Klasse, jetzt machen wir die Arbeit für den Rattenkönig.",,,Genial. Ahora vamos de compras para el Rey de las Ratas.,,,"Parfait, maintenant on fait du shopping pour le roi des rats.",,Grandioso. Adesso stiamo facendo shopping con il re dei ratti.,素敵ね。私達がラットキングのために買い物とか。,끝내준다. 이제 시궁쥐 왕의 심부름도 해야 한다니.,Geweldig. Nu zijn we aan het winkelen voor de rattenkoning.,,Que beleza. Agora estamos fazendo comprinhas pro Rato-Rei.,,,Классно. Мы идём за покупками для Крысиного Короля., -"I bet this guy smells really bad, too.",TXT_BBSUB_SCRIPT06_D4548_OPENT,,,,"Hádám, že tenhle chlápek taky pěkně smrdí.","Ich wette, dieser Kerl riecht auch übel.",,,"Apuesto a que este tipo huele muy mal, también.",,,"Je parie que ce type sent salement mauvais, aussi.",,Scommetto che questo ragazzo ha pure un cattivo odore.,この男も酷い悪臭がすると賭けるわ。,얘도 분명 냄새 하나는 죽여줄 거야.,Ik durf te wedden dat deze kerel ook heel erg stinkt.,,Aposto que esse cara fede pra caramba também.,,,"Уверена, этот парень воняет особенно ужасно.",Кладим се да овај човек смрди лоше такође. -More sewers... Great. Wonder what lives down there.,TXT_BBSUB_SCRIPT06_D9096_YOUHA,,,,"Další stoky... skvělý. Zajímalo by mě, co tam dole žije.","Mehr Kanäle, toll... Ich frage mich, was da unten lebt.",,,Más alcantarillas... Genial. Me pregunto que vivirá ahí abajo.,,,Plus d'égouts.. Youpi. Je me demande qui vit là dedans.,,Altre fogne... fantastico. Mi domando cosa vive qua giù.,更なる下水道...ヤッバ。下に何が住んでるのか不思議に思うわ。,또 하수도라... 끝내준다. 저 아래에 또 뭐가 살고 있을까?,Meer riolering.... Geweldig. Ik vraag me af wat daar beneden leeft.,,Mais esgotos... Que legal. O que será que vive lá embaixo?,,,"Снова канализация... Замечательно. Интересно, кого мы там встретим?", -Dead end here. We'd better keep looking.,TXT_BBSUB_SCRIPT07_D6064_PROGR,,,,Tudy cesta nevede. Měli bychom se dívat dál.,Sackgasse. Wir sollten es woanders versuchen.,,,Un callejón sin salida. Deberíamos seguir buscando.,,,"Une impasse. Bon, on continue de chercher.",,Qui c'è un vicolo cieco. Meglio continuare a guardare.,行き止まりだ。私達はまだこの景色を楽しめるわ。,여기가 아닌가 봐. 다른 곳을 찾아봐야겠어.,Doodlopend hier. We kunnen maar beter blijven zoeken.,,Sem saída aqui. Melhor seguirmos procurando.,,,Тупик. Давай продолжать поиски., +",TXT_BBSUB_SCRIPT06_D1516_DOMYF,MAP06: Weran.,,,Každý toho tolik potřebuje.,"Alle er så trængende. +",Jeder hier ist so bedürftig!,,Ĉiuj estas tiel tropetemaj.,Cuánta gente interesada.,,Kylläpä sitä nyt ollaan niin kaiken tarpeessa.,Tout le monde est tellement demandant.,Mindenkinek kell valami.,Tutti sono così bisognosi.,誰もがとても貧しいのよ。,다들 참 궁색하게 사네.,Iedereen is zo behoeftig.,"Alle er så trengende. +","Wszyscy są tacy potrzebujący. +",Por que todo mundo é tão mimimizento?,,Toată lumea e așa neajutorată!,Тут все такие нуждающиеся!,,"Alla är så behövande. +","Herkes çok muhtaç. +" +Great. Now we're shopping for the Rat King.,TXT_BBSUB_SCRIPT06_D3032_BRING,〃,,,"Super, teď máme nakupovat pro Krysího krále.",Alle er så trængende. Nu skal vi købe ind til rottekongen.,"Klasse, jetzt machen wir die Arbeit für den Rattenkönig.",,,Genial. Ahora vamos de compras para el Rey de las Ratas.,,"Loistavaa, hoidamme nyt Rottakuninkaan ostoksia.","Parfait, maintenant on fait du shopping pour le roi des rats.",Kiváló. A Patkány Király bevásárlói lettünk.,Grandioso. Adesso stiamo facendo shopping con il re dei ratti.,素敵ね。私達がラットキングのために買い物とか。,끝내준다. 이제 시궁쥐 왕의 심부름도 해야 한다니.,Geweldig. Nu zijn we aan het winkelen voor de rattenkoning.,Flott. Nå handler vi til Rottekongen.,Świetnie. Teraz robimy zakupy dla Króla Szczurów.,Que beleza. Agora estamos fazendo comprinhas pro Rato-Rei.,,Grozav. Acum facem cumpărături pentru Regele Șobolanilor.,Классно. Мы идём за покупками для Крысиного короля.,,Toppen. Nu ska vi shoppa för råttkungen.,Harika. Şimdi de Fare Kral için alışveriş yapıyoruz. +"I bet this guy smells really bad, too.",TXT_BBSUB_SCRIPT06_D4548_OPENT,〃,,,"Hádám, že tenhle chlápek taky pěkně smrdí.","Jeg vil vædde med, at han også lugter rigtig dårligt.","Ich wette, dieser Kerl riecht auch übel.",,,"Apuesto a que este tipo huele muy mal, también.",,"Lyön vetoa, että tämä tyyppi myös haisee tosi pahalta.","Je parie que ce type sent salement mauvais, aussi.","Le merném fogadni, hogy ez a pacák is büdös.",Scommetto che questo tizio ha pure un cattivo odore.,この男も酷い悪臭がすると賭けるわ。,얘도 분명 냄새 하나는 죽여줄 거야.,Ik durf te wedden dat deze kerel ook heel erg stinkt.,Jeg vedder på at denne fyren også lukter fælt.,"Założę się, że ten facet też bardzo śmierdzi.",Aposto que esse cara fede pra caramba também.,,Pun pariu că tipul ăsta mai și pute.,"Уверена, этот парень воняет особенно ужасно.",,Jag slår vad om att den här killen luktar riktigt illa också.,Eminim bu adam da çok kötü kokuyordur. +More sewers... Great. Wonder what lives down there.,TXT_BBSUB_SCRIPT06_D9096_YOUHA,〃,,,"Další stoky... skvělý. Zajímalo by mě, co tam dole žije.",Flere kloakker... Fedt. Gad vide hvad der bor dernede.,"Mehr Kanäle, toll... Ich frage mich, was da unten lebt.",,,Más alcantarillas... Genial. Me pregunto qué vivirá ahí abajo.,,Lisää viemäreitä... Mahtavaa. Kukakohan elää täällä alhaalla.,Plus d'égouts.. Youpi. Je me demande qui vit là dedans.,Még több kanális... kiváló. Mi lakhat odalent?,Altre fogne... fantastico. Mi domando cosa vive qua giù.,更なる下水道...ヤッバ。下に何が住んでるのか不思議に思うわ。,또 하수도라... 끝내준다. 저 아래에 또 뭐가 살고 있을까?,Meer riolering.... Geweldig. Ik vraag me af wat daar beneden leeft.,Mer kloakk... Flott. Lurer på hva som bor der nede.,Więcej kanałów... Świetnie. Ciekawe co tam mieszka.,Mais esgotos... Que legal. O que será que vive lá embaixo?,,Mai multe canale... Grozav. Mă întreb ce-o mai trăi jos aici.,"Снова канализация... Замечательно. Интересно, кого мы там встретим?",,Mer kloaker... Toppen. Undrar vad som bor där nere.,Daha fazla kanalizasyon. Harika. Acaba orada ne yaşıyor? +Dead end here. We'd better keep looking.,TXT_BBSUB_SCRIPT07_D6064_PROGR,MAP07: Computer room.,,,Tudy cesta nevede. Měli bychom se podívat dál.,Det er en blindgyde her. Vi må hellere lede videre.,Sackgasse. Wir sollten es woanders versuchen.,,,Un callejón sin salida. Deberíamos seguir buscando.,,Umpikuja tässä. Parasta jatkaa etsintää.,"Une impasse. Bon, on continue de chercher.",Zsákutca. Folytatnunk kell a keresést.,Qui c'è un vicolo cieco. Meglio continuare a guardare.,行き止まりだ。私達はまだこの景色を楽しめるわ。,여기가 아닌가 봐. 다른 곳을 찾아봐야겠어.,Doodlopend hier. We kunnen maar beter blijven zoeken.,Blindvei her. Vi får lete videre.,Tu jest ślepy zaułek. Lepiej szukajmy dalej.,Sem saída aqui. Melhor seguirmos procurando.,,Capăt de linie. Mai bine ne mai uităm împrejur.,Тупик. Давай продолжать поиски.,,Det är en återvändsgränd här. Det är bäst att fortsätta leta.,Burası çıkmaz sokak. Aramaya devam etsek iyi olur. "Onward, my champion. Let's make Mr. Ugly twist and shout. -",TXT_BBSUB_SCRIPT10_D10612_YOUHA,,,,"Kupředu, můj šampióne. Pojďme pana Ošklivu hezky nakopat.",Und weiter gehts. Lass die Hackfresse zittern!,,,"Adelante, mi campeón. Hagamos al Sr. Feo retorcerse y gritar.",,,Allons-y mon champion. Allons tordre de douleur Monsieur Sale-geule.,,"Vai avanti, mio campione. Facciamo agitare e urlare al sig. Brutto.",進み出よ、わがチャンピオン。ミスター生塵を捻りつぶしてやれ。,"어서 가자, 나의 영웅. 그 못생긴 녀석에게 본때를 보여주자고.","Vooruit, mijn kampioen. Laten we Mr. Ugly aan het draaien en schreeuwen zetten.",,"Vai em frente, meu campeão. Vamos fazer o Sr. Feioso soltar a franga.",,,"Вперёд, мой защитник. Заставим Г-на Урода сплясать и спеть.", +",TXT_BBSUB_SCRIPT10_D10612_YOUHA,MAP10: Macil (Possible reference to a song of The Beatles).,,,"Kupředu, můj šampióne. Pojďme pana Ošklivu hezky nakopat.","Fremad, min mester. Lad os få hr. Grimme til at vride sig og skrige. +",Und weiter gehts. Lass die Hackfresse zittern!,,,"Adelante, mi campeón. Hagamos al Sr. Feo retorcerse y gritar.",,"Eteenpäin, sotaurhoni. Pannaan Herra Rumilus vääntelehtimään ja huutamaan.",Allons-y mon champion. Allons tordre de douleur Monsieur Sale-geule.,Gyerünk bajnokom. Ne várakoztassuk meg Ocsmány urat.,"Vai avanti, mio campione. Facciamo agitare e urlare il signor Brutto.",進み出よ、わがチャンピオン。ミスター生塵を捻りつぶしてやれ。,"어서 가자, 나의 영웅. 그 못생긴 녀석에게 본때를 보여주자고.","Voorwaarts, mijn kampioen. Laten we Mr Lelijk laten draaien en schreeuwen.","Fremad, min mester. La oss få herr Stygg til å vri seg og rope.","Naprzód, mój mistrzu. Sprawmy, by Pan Brzydki skręcał się i krzyczał. +","Vai em frente, meu campeão. Vamos fazer o Sr. Feioso soltar a franga.",,"Drept în față, campionul meu. Să-l facem pe dl. Urât să țipe.","Вперёд, мой защитник. Заставим Г-на Урода сплясать и спеть.",,"Framåt, min mästare. Låt oss få herr Ful att vrida sig och skrika.","İleri, şampiyonum. Bay Çirkin'i döndürelim ve bağırtalım. +" "Biomechanical? Well, that explains their seemingly endless supply of troops! And their bad attitude. -",TXT_BBSUB_SCRIPT10_D12128_THERE,,,,Biomechanické? Tak to vysvětluje jejich zdánlivě nekonečné zásoby vojáků! A jejich špatnou náladu.,Biomechanisch? Das erklärt ihren anscheinend endlosen Nachschub an Truppen. Und ihre miese Gesinnung.,,,"¿Biomecánico? Bueno, ¡eso explica su aparentemente infinito suministro de tropas! Y su mala actitud.",,,"Biomécanique? Et bien, ça explique pourquoi ils en ont une infinité, de troupes! Ca, et leur sale heumeur.",,"Biomeccanici? Beh, questo spiegherebbe la fornitura apparentemente infinita di truppe! Ed il brutto carattere.","生体工学'?どうやら奴等は軍隊を無限供給しているという訳だ! +",TXT_BBSUB_SCRIPT10_D12128_THERE,,,,Biomechanické? Tak to vysvětluje jejich zdánlivě nekonečné zásoby vojáků! A jejich špatnou náladu.,"Biomekanisk? Nå, det forklarer deres tilsyneladende uendelige forsyning af tropper! Og deres dårlige indstilling. +",Biomechanisch? Das erklärt ihren anscheinend endlosen Nachschub an Truppen. Und ihre miese Gesinnung.,,,"¿Biomecánicos? Bueno, ¡eso explicaría su suministro de tropas aparentemente infinito! Y su mal carácter.",,Biomekaanisia? No se selittää heidän joukkojensa näennäisen ehtymättömän lähteen! Ja heidän pahan asenteensa.,"Biomécanique? Et bien, ça explique pourquoi ils en ont une infinité, de troupes! Ca, et leur sale heumeur.","Biomechanikus? Nos, ez megmagyarázza a majdnem végtelen számukat. És a viselkedésüket is.","Biomeccanici? Beh, questo spiegherebbe la fornitura apparentemente infinita di truppe! Ed il loro brutto carattere.","生体工学'?どうやら奴等は軍隊を無限供給しているという訳だ! それと態度が悪いことも。 -","인간개조? 음, 이거 때문에 녀석들이 끊임없이 나오는 거였어! 녀석들 성질 더러운 것도 그렇고.","Biomechanisch? Nou, dat verklaart hun schijnbaar eindeloze voorraad aan troepen! En hun slechte houding.",,"Biomecânicos? Bom, deve ser por isso que o número de soldados parece não ter fim! Deve explicar os péssimos comportamentos também.",,,"Биомеханических? Что ж, теперь ясно, почему их солдаты не заканчиваются! И почему они так отвратительно себя ведут.", -Sick fuck... Waste him!,TXT_BBSUB_SCRIPT10_D16676_IAMTH,,,,Podlý sráč... Zab ho!,Der Typ ist doch krank. Mach ihn alle.,,,Maldito enfermo... ¡Cárgatelo!,,,"Quel salaud, bute le!",,È malato marcio... Fallo fuori!,クソ腹立つ...!野郎を消せ!,역겨운 자식... 죽여버려!,Zieke klootzakken.... Verspil hem!,,Doente do caralho... Acaba com ele!,,,Больной ублюдок... Мочи его!, -"He may be ugly, but it seems like he's on our side.",TXT_BBSUB_SCRIPT12_D12128_USETH,,,,"Možná je ošklivý, ale zdá se, že je na naší straně.","Er mag ja hässlich sein, aber es sieht aus als ob er auf unserer Seite sei.",,,"Puede que sea feo, pero parece que está de nuestro lado.",,,"Il est hideux, mais il semble qu'il soit de notre côté.",,"Può essere brutto, ma sembra che lui sia dalla nostra parte.",彼は醜いだろうが、我々に味方している。,"이 양반 못생기긴 했어도, 우리 편인 것 같네.","Hij is misschien lelijk, maar het lijkt erop dat hij aan onze kant staat.",,"Ele pode ser feio, mas parece que ele está no nosso lado.",,,"Пусть он и урод, но, похоже, он на нашей стороне.","Можда је он ружан, али је на нашој страни." -"Judging by recent history, I guess stealth is out.",TXT_BBSUB_SCRIPT17_D10612_OHSUR,,,,"Soudě podle naší nedávné historie hádám, že pokradmu to nepůjde.","Nach den jüngsten Geschehnissen zu urteilen, ist Tarnung nicht drin.",,,"Juzgando por nuestro historial reciente, supongo que el sigilo queda descartado.",,,"En se basant sur ce qui vient de se passer, je pense que la discrétion n'est pas une option.",,"A giudicare dalla storia recente, suppongo che lo stealth sia da scartare.",最近の記録から判断すると、秘密は公になると私は思う。,"최근 상황을 보건대, 잠입 작전은 힘들 것 같아.","Te oordelen naar de recente geschiedenis, denk ik dat heimelijkheid uit is.",,"Julgando pelo nosso histórico recente, acho que cautela está fora de questão.",,,"Судя по недавним событиям, можно больше не прятаться.", +","인간개조? 음, 이거 때문에 녀석들이 끊임없이 나오는 거였어! 녀석들 성질 더러운 것도 그렇고.","Biomechanisch? Nou, dat verklaart hun schijnbaar eindeloze voorraad aan troepen! En hun slechte houding.","Biomekanisk? Vel, det forklarer deres tilsynelatende endeløse tilførsel av tropper! Og den dårlige holdningen deres. +","Biomechaniczne? To wyjaśnia ich pozornie nieskończoną ilość żołnierzy! I ich złe nastawienie. +","Biomecânicos? Bom, deve ser por isso que o número de soldados parece não ter fim! Deve explicar os péssimos comportamentos também.",,Biomecanic? Asta explică rezerva lor de trupe aproape infinită! Și atitudinea lor oribilă.,"Биомеханических? Что ж, теперь ясно, почему их солдаты не заканчиваются! И почему они так отвратительно себя ведут.",,"Biomekaniskt? Det förklarar deras till synes oändliga tillgång på trupper! Och deras dåliga attityd. +","Biyomekanik mi? Bu onların görünüşte sonsuz asker kaynağını açıklıyor! Ve kötü tutumlarını. +" +Sick fuck... Waste him!,TXT_BBSUB_SCRIPT10_D16676_IAMTH,,,,Podlý sráč... Zab ho!,Syge svin... Smid ham ud!,Der Typ ist doch krank. Mach ihn alle.,,,Maldito enfermo... ¡Cárgatelo!,,Sairas kusipää... Listi hänet!,"Quel salaud, bute le!",Beteg állat... Nyírd ki!,È malato marcio... Fallo fuori!,クソ腹立つ...!野郎を消せ!,역겨운 자식... 죽여버려!,Zieke klootzakken.... Verspil hem!,Syke jævel... Drep ham!,Chory skurwiel... Zmarnuj go!,Doente do caralho... Acaba com ele!,,Dobitoc bolnav... Nimicește-l!,Больной ублюдок... Мочи его!,,Sjuka jävlar... Slå honom ihjäl!,Hasta herif. Harca onu! +"He may be ugly, but it seems like he's on our side.",TXT_BBSUB_SCRIPT12_D12128_USETH,,,,"Možná je ošklivý, ale zdá se, že je na naší straně.","Han er måske grim, men det ser ud til, at han er på vores side.","Er mag ja hässlich sein, aber es sieht aus als ob er auf unserer Seite sei.",,,"Podrá ser feo, pero parece estar de nuestro lado.",,"Hän on ehkä ruma, mutta hän vaikuttaa olevan meidän puolellamme.","Il est hideux, mais il semble qu'il soit de notre côté.","Lehet hogy igen ronda szegény, de legalább a mi oldalunkon áll.","Può essere brutto, ma sembra che sia dalla nostra parte.",彼は醜いだろうが、我々に味方している。,"이 양반 못생기긴 했어도, 우리 편인 것 같네.","Hij is misschien lelijk, maar het lijkt erop dat hij aan onze kant staat.","Han er kanskje stygg, men det virker som om han er på vår side.","Może i jest brzydki, ale wygląda na to, że jest po naszej stronie.","Ele pode ser feio, mas parece que ele está no nosso lado.",,"O fi urât, dar pare să fie de partea noastră.","Пусть он и урод, но, похоже, он на нашей стороне.",,"Han må vara ful, men det verkar som om han är på vår sida.",Çirkin olabilir ama bizim tarafımızda gibi görünüyor. +"Judging by recent history, I guess stealth is out.",TXT_BBSUB_SCRIPT17_D10612_OHSUR,,,,"Soudě podle naší nedávné historie hádám, že pokradmu to nepůjde.","At dømme ud fra den seneste historie, så er det vist ikke muligt at gå i smug.","Nach den jüngsten Geschehnissen zu urteilen, ist Tarnung nicht drin.",,,"Juzgando nuestro historial reciente, supongo que el sigilo queda descartado.",,Lähimenneisyyden perusteella hiiviskely ei varmaankaan tule kysymykseen.,"En se basant sur ce qui vient de se passer, je pense que la discrétion n'est pas une option.",A rövidmúltból kiindulva a lopakodás nem lehetőség.,"A giudicare dalla storia recente, suppongo che essere furtivi sia da scartare.",最近の記録から判断すると、秘密は公になると私は思う。,"최근 상황을 보건대, 잠입 작전은 힘들 것 같아.","Te oordelen naar de recente geschiedenis, denk ik dat heimelijkheid uit is.","Å dømme etter det som har skjedd, er det visst slutt på å snike.","Sądząc po ostatniej historii, chyba nie ma mowy o ukrywaniu się.","Julgando pelo nosso histórico recente, acho que cautela está fora de questão.",,"Uitându-ne la istoria recentă, cred că silențiozitatea iese din ecuație.","Судя по недавним событиям, можно больше не прятаться.",,"Att döma av den senaste historien, antar jag att smygande är uteslutet.","Yakın geçmişe bakılırsa, sanırım gizlilik devre dışı." "Hmm. No fuss, no muss, nothing for mom to clean up... Get me one, please. -",TXT_BBSUB_SCRIPT17_D13644_OHWEL,This remark is for information about the maulers in the warehouse.,,,"Hmm. Žádný rámus, žádný bordel, maminka nemusí nic uklízet... Taky mi jeden kup, prosím!",Hmm. Lass nichts anbrennen. Hol mir bitte so ein Ding.,,,"Hmm. Sin dejar restos, nada que mamá tenga que limpiar... Dame uno, por favor.",,,"Hmm. Pas de boucan, pas de bordel, rien que maman à besoin de nettoyer après.. Récupère en un pour moi, s'il te plaît.",,"Mm. Non protesta, fa zero residui, nulla da far pulire a mamma... Dammene uno, per favore.","うーむ。慌てず、騒がず、ママの掃除も無し... -何か一杯お願い。",흠. 이유 없이 그런 소문이 났을 리는 없을 테고... 나도 그 무기 하나만 가져다줘.,"Hmm. Geen gedoe, geen muss, niets voor mama om op te ruimen... Haal me er een, alsjeblieft.",,"Hmm. Sem frescura, sem sujeira, nada pra mamãe ter que limpar... Pega um pra mim, por favor.",,,"Хм-м. Ни шума, ни пыли, мама не заставит убираться... Достань мне одно такое, пожалуйста!", +",TXT_BBSUB_SCRIPT17_D13644_OHWEL,This remark is for information about the maulers in the warehouse.,,,"Hmm. Žádný rámus, žádný bordel, maminka nemusí nic uklízet... Taky mi jeden vem, prosím!","Hmm. Ingen ballade, ingen ballade, intet for mor at rydde op... Giv mig en, tak. +",Hmm. Lass nichts anbrennen. Hol mir bitte so ein Ding.,,,"Hmm. Sin dejar restos, nada que mamá tenga que limpiar... Dame uno, por favor.",,"Hmm, pulinat pois, ei jätetä äidille mitään siivottavaa... Saisinko yhden, kiitos.","Hmm. Pas de boucan, pas de bordel, rien que maman ait besoin de nettoyer après.. Récupère en un pour moi, s'il te plaît.",Hmm. Könnyen ment mint az ágybavizelés... Hozz nekem egyet kérlek.,"Mm. Non protesta, fa zero residui, nulla da far pulire a mamma... Dammene uno, per favore.","うーむ。慌てず、騒がず、ママの掃除も無し... +何か一杯お願い。",흠. 이유 없이 그런 소문이 났을 리는 없을 테고... 나도 그 무기 하나만 가져다줘.,"Hmm. Geen gedoe, geen muss, niets voor mama om op te ruimen... Haal me er een, alsjeblieft.","Ikke noe oppstyr, ikke noe for mamma å rydde opp... Gi meg en, er du snill. +","Hmm. Żadnego zamieszania, żadnego bałaganu, nic dla mamy do sprzątania... Daj mi jeden, proszę. +","Hmm. Sem choradeira, nem sujeira, nada pra mamãe ter que limpar... Pega um pra mim, por favor.",,"Hmm. Nu-i deranj, nu mizerie, nu nimic... Adu-mi unul, te rog.","Хм-м. Ни шума, ни пыли, мама не заставит убираться... Достань мне одно такое, пожалуйста!",,"Hmm. Inget krångel, inget krångel, inget för mamma att städa upp... Ge mig en, tack. +","Hmm. Yaygara yok, karışıklık yok, annemin temizleyeceği bir şey yok... Bana bir tane getir, lütfen. +" "You think I'd get tired of all this killing everyone stuff, but I know I'm going to miss it when it's over. -",TXT_BBSUB_SCRIPT31_D0_OHNOI,,,,"Řekl bys, že by mě tohle zabíjení všech začalo unavovat, ale vím, že mi to bude chybět, až tohle všechno skončí.","Man könnte denken, dass man von dieser „alle töten“-Sache müde wird, aber ich weiß, ich werde es vermissen, wenn alles vorbei ist.",,,"Pensarás que me cansaría de esto de matar a todo el mundo, pero sé que lo echaré de menos cuando se acabe.",,,"On pensrai que j'en aurai marre de cette routine de ""tue tout le monde"", mais je crois que ça va me manquer quand on en aura fini.",,"Potresti pensare che io mi stanchi di questa cosa di ""uccidere tutti"", ma io so già che mi mancherà quando tutto sarà finito.","貴方は全ての人々が殺害される事にうんざりしていると思うわ、 -でも私は全てが終わったら見逃すと知っている。","내가 사람들 죽이는 걸 지겨워할 것 같지만, 이 일이 모두 끝나면 아마 그리워할 거야.","Je denkt dat ik moe zou worden van al deze moorden, maar ik weet dat ik het ga missen als het voorbij is.",,"Você deve achar que fico cansada de toda essa matança, mas sei que vou sentir falta disso quando acabar.",,,"Ты думаешь, что я устану от всех этих убийств? Нет, на самом деле мне их будет не хватать.","Мислиш да би ми досадило овај убити свакога ствар, али ће ми недостајати када се заврши." \ No newline at end of file +",TXT_BBSUB_SCRIPT31_D0_OHNOI,MAP31,,,"Řekl bys, že by mě všechno tohle zabíjení začalo unavovat, ale stejně vím, že mi to bude chybět, až tohle všechno skončí.","Man skulle tro, at jeg ville blive træt af alt det her med at dræbe alle, men jeg ved, at jeg kommer til at savne det, når det er slut. +","Man könnte denken, dass man von dieser „alle töten“-Sache müde wird, aber ich weiß, ich werde es vermissen, wenn alles vorbei ist.",,,"Pensarás que me cansaría de esto de matar a todo el mundo, pero sé que lo echaré de menos cuando se acabe.",,"Sitä luulisi, että kyllästyisin tähän ""tapan kaikki""-touhuun, mutta tiedän, että jään kaipaamaan sitä, kun tämä on ohi.","On pensrai que j'en aurai marre de cette routine de ""tue tout le monde"", mais je crois que ça va me manquer quand on en aura fini.","Azt hinné az ember, hogy belefáradok ebbe a gyilkolászósdiba, de tudom hogy hiányozni fog ha mind ennek vége.","Potresti pensare che io mi stia stancando di questa routine di ""uccidere tutti"", ma so già che mi mancherà quando tutto sarà finito.","貴方は全ての人々が殺害される事にうんざりしていると思うわ、 +でも私は全てが終わったら見逃すと知っている。","내가 사람들 죽이는 걸 지겨워할 것 같지만, 이 일이 모두 끝나면 아마 그리워할 거야.","Je denkt dat ik moe zou worden van al deze moorden, maar ik weet dat ik het ga missen als het voorbij is.","Man skulle tro jeg ville bli lei av å drepe alle, men jeg kommer til å savne det når det er over. +","Myślisz, że znudzi mnie to całe zabijanie wszystkich, ale wiem, że będzie mi tego brakowało, kiedy to się skończy. +","Você deve achar que fico cansada de toda essa matança, mas sei que vou sentir falta disso quando acabar.",,"Crezi că m-am săturat de toată chestia asta de a ucide totul, dar îmi va lipsi odată ce totul se va termina.","Ты думаешь, что я устану от всех этих убийств? Нет, на самом деле мне их будет не хватать.",,"Man tror att jag skulle tröttna på allt det här med att döda alla, men jag vet att jag kommer att sakna det när det är över. +","Tüm bu herkesi öldürme işinden yorulacağımı sanıyorsunuz ama bittiğinde özleyeceğimi biliyorum. +" \ No newline at end of file diff --git a/wadsrc_lights/CMakeLists.txt b/wadsrc_lights/CMakeLists.txt index 92f89314a74..57a493dcdd4 100644 --- a/wadsrc_lights/CMakeLists.txt +++ b/wadsrc_lights/CMakeLists.txt @@ -1,3 +1 @@ -cmake_minimum_required( VERSION 2.4 ) - add_pk3(lights.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static) diff --git a/wadsrc_lights/static/filter/doom.freedoom/gldefs.txt b/wadsrc_lights/static/filter/doom.freedoom/gldefs.txt index 457ae8a00fc..9cf9bc45fac 100644 --- a/wadsrc_lights/static/filter/doom.freedoom/gldefs.txt +++ b/wadsrc_lights/static/filter/doom.freedoom/gldefs.txt @@ -337,7 +337,7 @@ object ExplosiveBarrel // Floor lamp pointlight LAMP { - color 0.6 1.0 0.6 + color 1.0 1.0 0.6 size 84 offset 0 44 0 attenuate 1 @@ -365,19 +365,36 @@ object TechLamp2 } // Tall tech lamp -pulselight BIGLAMP +pointlight BIGLAMP1 { - color 1.0 1.0 0.7 - size 96 - secondarySize 99 - interval 0.4 + color 1.0 0.9 0.4 + size 100 + offset 0 72 0 + attenuate 1 +} + +pointlight BIGLAMP2 +{ + color 0.97 0.87 0.37 + size 99 + offset 0 72 0 + attenuate 1 +} + +pointlight BIGLAMP3 +{ + color 0.94 0.84 0.34 + size 98 offset 0 72 0 attenuate 1 } object TechLamp { - frame TLMP { light BIGLAMP } + frame TLMPA { light BIGLAMP1 } + frame TLMPB { light BIGLAMP2 } + frame TLMPC { light BIGLAMP3 } + frame TLMPD { light BIGLAMP2 } } // Tall red torch @@ -479,7 +496,7 @@ object ShortBlueTorch // Burning barrel flickerlight2 FIREBARREL { - color 0.6 0.6 0.9 + color 1.0 0.9 0.4 size 72 secondarySize 81 interval 0.1 @@ -522,6 +539,21 @@ object Candlestick frame CAND { light CANDLE } } +// Floating Skull Rock +pulselight SKULLROCK +{ + color 0.5 0.4 0.1 + offset 0 5 0 + size 60 + secondarysize 40 + interval 0.6 + attenuate 1 +} +object FloatingSkull +{ + frame FSKU { light SKULLROCK } +} + // ---------------- // -- Doom Items -- // ---------------- @@ -529,7 +561,7 @@ object Candlestick // Soul Sphere pulselight SOULSPHERE { - color 0.3 0.3 1.0 + color 1.0 1.0 0.3 size 60 secondarySize 63 interval 2.0 @@ -545,7 +577,7 @@ object SoulSphere // Soul Sphere pulselight MEGASPHERE { - color 0.4 1.0 0.4 + color 1.0 0.8 0.4 size 60 secondarySize 63 interval 2.0 @@ -561,7 +593,7 @@ object MegaSphere // Invulnerability Sphere pulselight INVULN { - color 1.0 0.6 1.0 + color 0.6 1.0 0.6 size 60 secondarySize 63 interval 2.0 @@ -575,64 +607,29 @@ object InvulnerabilitySphere } // Blur Sphere -pointlight BLURSPHERE1 -{ - color 1.0 0.0 0.0 - size 60 - offset 0 16 0 - attenuate 1 -} - -pointlight BLURSPHERE2 +pulselight BLURSPHERE1 { - color 0.0 0.0 1.0 - size 48 - offset 0 16 0 - attenuate 1 -} - -pointlight BLURSPHERE3 -{ - color 0.0 0.0 1.0 - size 36 - offset 0 16 0 - attenuate 1 -} - -pointlight BLURSPHERE4 -{ - color 0.0 0.0 1.0 - size 24 - offset 0 16 0 - attenuate 1 -} - -pointlight BLURSPHERE5 -{ - color 0.0 0.0 1.0 - size 12 + color 0.6 0.6 0.6 + size 40 + secondarysize 35 offset 0 16 0 + subtractive 1 attenuate 1 + interval 0.3 } object BlurSphere { frame PINS { light BLURSPHERE1 } - - frame PINSA { light BLURSPHERE2 } - frame PINSB { light BLURSPHERE3 } - frame PINSC { light BLURSPHERE4 } - frame PINSD { light BLURSPHERE5 } } -// Armour Helmet +// Armour Shield pulselight ARMORBONUS { color 0.3 0.1 0.1 size 16 secondarySize 20 interval 1.0 - dontlightself 1 attenuate 1 offset 0 10 0 } @@ -643,14 +640,23 @@ object ArmorBonus } // Blue Keys +pulselight BLUEKEY +{ + color 0.2 0.2 0.8 + size 15 + secondarySize 27 + interval 2.0 + attenuate 1 + offset 0 10 0 +} object BlueCard { - frame BKEY { light HEALTHPOTION } + frame BKEY { light BLUEKEY } } object BlueSkull { - frame BSKU { light HEALTHPOTION } + frame BSKU { light BLUEKEY } } // Yellow Keys @@ -695,17 +701,40 @@ object RedSkull frame RSKU { light REDKEY } } + +// Both armor pickups have a big red blinking light in the middle pointlight GREENARMOR2 { - color 0.4 0.0 0.0 + color 0.1 0.2 0.0 size 40 attenuate 1 offset 0 10 0 } +pointlight REDARMOR +{ + color 0.2 0.0 0.0 + size 40 + attenuate 1 + offset 0 10 0 +} +pointlight ARMORLITE +{ + color 0.4 0.0 0.0 + size 10 + attenuate 1 + offset 0 20 0 +} object GreenArmor { - frame ARM1B { light GREENARMOR2 } + frame ARM1 { light GREENARMOR2 } + frame ARM1B { light ARMORLITE } +} + +object BlueArmor +{ + frame ARM2 { light REDARMOR } + frame ARM2B { light ARMORLITE } } @@ -749,7 +778,7 @@ object DoomPlayer // Doom Imp Fireball pointlight IMPBALL { - color 1.0 0.7 0.4 + color 0.8 0.7 0.4 size 96 attenuate 1 } @@ -757,7 +786,7 @@ pointlight IMPBALL // Doom imp fireball explosion flickerlight IMPBALL_X1 { - color 0.7 0.7 0.25 + color 0.9 0.7 0.25 size 120 secondarySize 132 chance 0.25 @@ -766,7 +795,7 @@ flickerlight IMPBALL_X1 flickerlight IMPBALL_X2 { - color 0.4 0.4 0.1 + color 0.5 0.4 0.1 size 144 secondarySize 156 chance 0.25 @@ -775,7 +804,7 @@ flickerlight IMPBALL_X2 flickerlight IMPBALL_X3 { - color 0.2 0.2 0.0 + color 0.3 0.2 0.0 size 168 secondarySize 180 chance 0.25 @@ -901,12 +930,20 @@ object BaronBall } // Lost Soul -flickerlight LOSTSOUL +pulselight LOSTSOUL +{ + color 0.4 0.4 0.2 + size 64 + secondarysize 44 + interval 0.9 + attenuate 1 +} +flickerlight HATCHLING_ATK { - color 1.0 0.6 0.3 + color 0.8 0.8 0.5 size 84 secondarysize 64 - chance 0.1 + chance 0.3 attenuate 1 } @@ -950,8 +987,8 @@ object LostSoul { frame SKULA { light LOSTSOUL } frame SKULB { light LOSTSOUL } - frame SKULC { light LOSTSOUL } - frame SKULD { light LOSTSOUL } + frame SKULC { light HATCHLING_ATK } + frame SKULD { light HATCHLING_ATK } frame SKULE { light LOSTSOUL } frame SKULF { light LOSTSOUL } frame SKULG { light LOSTSOUL } diff --git a/wadsrc_lights/static/filter/harmony/gldefs.txt b/wadsrc_lights/static/filter/harmony/gldefs.txt index 662bb3bc6d4..3907c4934ef 100644 --- a/wadsrc_lights/static/filter/harmony/gldefs.txt +++ b/wadsrc_lights/static/filter/harmony/gldefs.txt @@ -131,7 +131,7 @@ object Soldier frame CPOSF { light ZOMBIEATK } } -object Echida +object Echidna { frame SPIDG { light ZOMBIEATK } } diff --git a/wadsrc_lights/static/filter/heretic/gldefs.txt b/wadsrc_lights/static/filter/heretic/gldefs.txt index f96ffe59cd7..4bf6f0d7ff3 100644 --- a/wadsrc_lights/static/filter/heretic/gldefs.txt +++ b/wadsrc_lights/static/filter/heretic/gldefs.txt @@ -1663,7 +1663,7 @@ object VolcanoBlast } // Small volcano fireball -flickerlight VOLCANOBALL1 +flickerlight VOLCANOBALL2 { color 1.0 0.5 0.0 size 60 @@ -1674,7 +1674,7 @@ flickerlight VOLCANOBALL1 object VolcanoTBlast { - frame VTFB { light VOLCANOBALL1 } + frame VTFB { light VOLCANOBALL2 } } // Blue Key Statue @@ -1733,7 +1733,7 @@ flickerlight TIMEBOMB_X1 attenuate 1 } -flickerlight TIMEBOMB_X1 +flickerlight TIMEBOMB_X2 { color 0.8 0.4 0.3 size 88 @@ -1742,7 +1742,7 @@ flickerlight TIMEBOMB_X1 attenuate 1 } -flickerlight TIMEBOMB_X1 +flickerlight TIMEBOMB_X3 { color 0.6 0.3 0.2 size 96 @@ -1751,7 +1751,7 @@ flickerlight TIMEBOMB_X1 attenuate 1 } -flickerlight TIMEBOMB_X1 +flickerlight TIMEBOMB_X4 { color 0.4 0.2 0.1 size 108 @@ -1760,7 +1760,7 @@ flickerlight TIMEBOMB_X1 attenuate 1 } -flickerlight TIMEBOMB_X1 +flickerlight TIMEBOMB_X5 { color 0.2 0.1 0.0 size 120 diff --git a/wadsrc_lights/static/filter/strife/gldefs.txt b/wadsrc_lights/static/filter/strife/gldefs.txt index 7474486ba0a..25fe78149d4 100644 --- a/wadsrc_lights/static/filter/strife/gldefs.txt +++ b/wadsrc_lights/static/filter/strife/gldefs.txt @@ -9,89 +9,100 @@ flickerlight SPUFF1 { color 1.0 1.0 0.0 - size 6 - secondarySize 8 + size 9 + secondarySize 12 chance 0.8 + attenuate 1 } flickerlight SPUFF2 { color 1.0 0.8 0.0 - size 5 - secondarySize 6 + size 7 + secondarySize 9 chance 0.8 + attenuate 1 } flickerlight SPUFF3 { color 1.0 0.6 0.0 - size 8 - secondarySize 10 + size 12 + secondarySize 15 chance 0.8 + attenuate 1 } flickerlight SPUFF4 { color 0.8 0.8 1.0 - size 2 - secondarySize 4 + size 3 + secondarySize 6 chance 0.8 + attenuate 1 } flickerlight SPUFF5 { color 0.8 0.8 1.0 - size 4 - secondarySize 6 + size 6 + secondarySize 9 chance 0.8 + attenuate 1 } flickerlight SPUFF6 { color 0.6 0.6 1.0 - size 6 - secondarySize 8 + size 9 + secondarySize 12 chance 0.8 + attenuate 1 } flickerlight SPUFF7 { color 0.4 0.4 0.8 - size 7 - secondarySize 9 + size 10 + secondarySize 14 chance 0.8 + attenuate 1 } flickerlight SPUFF8 { color 1.0 1.0 0.0 - size 2 - secondarySize 4 + size 3 + secondarySize 6 chance 0.8 + attenuate 1 } flickerlight SPUFF9 { color 1.0 0.8 0.0 - size 3 - secondarySize 4 + size 4 + secondarySize 6 chance 0.8 + attenuate 1 } flickerlight SPUFF10 { color 1.0 0.6 0.0 - size 5 - secondarySize 6 + size 7 + secondarySize 9 chance 0.8 + attenuate 1 } flickerlight SPUFF11 { color 1.0 0.4 0.0 - size 7 - secondarySize 8 + size 10 + secondarySize 12 chance 0.8 + attenuate 1 } object StrifePuff @@ -113,41 +124,46 @@ object StrifePuff flickerlight SSPARK1 { color 0.5 0.5 1.0 - size 4 - secondarySize 6 + size 6 + secondarySize 9 chance 0.8 + attenuate 1 } flickerlight SSPARK2 { color 0.5 0.5 1.0 - size 6 - secondarySize 8 + size 9 + secondarySize 12 chance 0.8 + attenuate 1 } flickerlight SSPARK3 { color 0.4 0.4 1.0 - size 8 - secondarySize 10 + size 12 + secondarySize 15 chance 0.8 + attenuate 1 } flickerlight SSPARK4 { color 0.3 0.3 1.0 - size 6 - secondarySize 8 + size 9 + secondarySize 12 chance 0.8 + attenuate 1 } flickerlight SSPARK5 { color 0.2 0.2 1.0 - size 4 - secondarySize 6 + size 6 + secondarySize 9 chance 0.8 + attenuate 1 } object StrifeSpark @@ -172,49 +188,55 @@ object StrifeSpark flickerlight ARROWZAP1 { color 0.4 0.4 1.0 - size 8 - secondarySize 16 + size 12 + secondarySize 24 chance 0.4 + attenuate 1 } flickerlight ARROWZAP2 { color 0.45 0.45 1.0 - size 16 - secondarySize 24 + size 24 + secondarySize 36 chance 0.4 + attenuate 1 } flickerlight ARROWZAP3 { color 0.5 0.5 1.0 - size 24 - secondarySize 30 + size 36 + secondarySize 45 chance 0.4 + attenuate 1 } flickerlight ARROWZAP4 { color 0.6 0.6 1.0 - size 30 - secondarySize 36 + size 45 + secondarySize 54 chance 0.4 + attenuate 1 } flickerlight ARROWZAP5 { color 0.7 0.7 1.0 - size 36 - secondarySize 40 + size 54 + secondarySize 60 chance 0.4 + attenuate 1 } flickerlight ARROWZAP6 { color 0.8 0.8 1.0 - size 40 - secondarySize 42 + size 60 + secondarySize 43 chance 0.4 + attenuate 1 } object ElectricBolt @@ -231,64 +253,72 @@ object ElectricBolt pointlight MISSILE { color 1.0 0.7 0.0 - size 56 + size 84 offset -40 0 0 + attenuate 1 } flickerlight MISSILE_X1 { color 1.0 0.7 0.0 - size 56 - secondarySize 60 + size 84 + secondarySize 90 chance 0.3 + attenuate 1 } flickerlight MISSILE_X2 { color 1.0 0.65 0.0 - size 60 - secondarySize 64 + size 90 + secondarySize 96 chance 0.3 + attenuate 1 } flickerlight MISSILE_X3 { color 1.0 0.6 0.0 - size 64 - secondarySize 68 + size 96 + secondarySize 102 chance 0.3 + attenuate 1 } flickerlight MISSILE_X4 { color 1.0 0.6 0.0 - size 68 - secondarySize 72 + size 102 + secondarySize 108 chance 0.3 + attenuate 1 } flickerlight MISSILE_X5 { color 1.0 0.6 0.0 - size 72 - secondarySize 76 + size 108 + secondarySize 114 chance 0.3 + attenuate 1 } flickerlight MISSILE_X6 { color 1.0 0.6 0.0 - size 76 - secondarySize 80 + size 114 + secondarySize 120 chance 0.3 + attenuate 1 } flickerlight MISSILE_X7 { color 1.0 0.6 0.0 - size 80 - secondarySize 88 + size 120 + secondarySize 132 chance 0.3 + attenuate 1 } object MiniMissile @@ -308,37 +338,43 @@ object MiniMissile pointlight FLMMISSILE { color 1.0 0.7 0.0 - size 56 + size 84 + attenuate 1 } pointlight FLMMSL_X1 { color 1.0 0.7 0.0 - size 52 + size 78 + attenuate 1 } pointlight FLMMSL_X2 { color 0.8 0.56 0.0 - size 46 + size 69 + attenuate 1 } pointlight FLMMSL_X3 { color 0.6 0.42 0.0 - size 38 + size 57 + attenuate 1 } pointlight FLMMSL_X4 { color 0.4 0.28 0.0 - size 24 + size 36 + attenuate 1 } pointlight FLMMSL_X5 { color 0.2 0.14 0.0 - size 16 + size 24 + attenuate 1 } object FlameMissile @@ -358,49 +394,55 @@ object FlameMissile flickerlight MPUFFG { color 0.0 1.0 0.0 - size 6 - secondarySize 8 + size 9 + secondarySize 12 chance 0.8 + attenuate 1 } flickerlight MPUFF1 { color 1.0 1.0 1.0 - size 6 - secondarySize 8 + size 9 + secondarySize 12 chance 0.8 + attenuate 1 } flickerlight MPUFF2 { color 1.0 1.0 1.0 - size 8 - secondarySize 10 + size 12 + secondarySize 15 chance 0.8 + attenuate 1 } flickerlight MPUFF3 { color 1.0 1.0 1.0 - size 10 - secondarySize 12 + size 15 + secondarySize 18 chance 0.8 + attenuate 1 } flickerlight MPUFF4 { color 1.0 1.0 1.0 - size 12 - secondarySize 14 + size 18 + secondarySize 21 chance 0.8 + attenuate 1 } flickerlight MPUFF5 { color 1.0 1.0 1.0 - size 14 - secondarySize 16 + size 21 + secondarySize 24 chance 0.8 + attenuate 1 } object MaulerPuff @@ -417,47 +459,53 @@ object MaulerPuff pointlight MTORPEDO { color 0.0 1.0 0.0 - size 80 + size 120 + attenuate 1 } flickerlight MTORP_X1 { color 0.5 1.0 0.5 - size 80 - secondarySize 84 + size 120 + secondarySize 126 chance 0.3 + attenuate 1 } flickerlight MTORP_X2 { color 0.4 1.0 0.4 - size 84 - secondarySize 88 + size 126 + secondarySize 132 chance 0.3 + attenuate 1 } flickerlight MTORP_X3 { color 0.2 1.0 0.2 - size 88 - secondarySize 92 + size 132 + secondarySize 138 chance 0.3 + attenuate 1 } flickerlight MTORP_X4 { color 0.125 0.5 0.125 - size 92 - secondarySize 96 + size 138 + secondarySize 144 chance 0.3 + attenuate 1 } flickerlight MTORP_X5 { color 0.0 0.25 0.0 - size 96 - secondarySize 100 + size 144 + secondarySize 150 chance 0.3 + attenuate 1 } object MaulerTorpedo @@ -474,25 +522,28 @@ object MaulerTorpedo flickerlight MWAVE_X1 { color 0.0 1.0 0.0 - size 112 - secondarySize 128 + size 168 + secondarySize 192 chance 0.3 + attenuate 1 } flickerlight MWAVE_X2 { color 0.0 0.75 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 + attenuate 1 } flickerlight MWAVE_X3 { color 0.0 0.5 0.0 - size 24 - secondarySize 32 + size 36 + secondarySize 48 chance 0.3 + attenuate 1 } object MaulerTorpedoWave @@ -561,89 +612,100 @@ object HEGrenade flickerlight PHFIRE_FX1 { color 1.0 0.75 0.0 - size 28 - secondarySize 32 + size 42 + secondarySize 48 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX2 { color 1.0 0.7 0.0 - size 40 - secondarySize 48 + size 60 + secondarySize 72 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX3 { color 1.0 0.65 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX4 { color 1.0 0.55 0.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX5 { color 1.0 0.5 0.0 - size 66 - secondarySize 72 + size 99 + secondarySize 108 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX6 { color 1.0 0.55 0.0 - size 66 - secondarySize 72 + size 99 + secondarySize 108 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX7 { color 1.0 0.6 0.0 - size 66 - secondarySize 72 + size 99 + secondarySize 108 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX8 { color 1.0 0.5 0.0 - size 60 - secondarySize 68 + size 90 + secondarySize 102 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX9 { color 1.0 0.4 0.0 - size 48 - secondarySize 52 + size 72 + secondarySize 78 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX10 { color 1.0 0.45 0.0 - size 44 - secondarySize 48 + size 66 + secondarySize 72 chance 0.3 + attenuate 1 } flickerlight PHFIRE_FX11 { color 1.0 0.3 0.0 - size 36 - secondarySize 40 + size 54 + secondarySize 60 chance 0.3 + attenuate 1 } object PhosphorousFire @@ -670,65 +732,73 @@ object PhosphorousFire flickerlight DEGORE_X1 { color 1.0 0.6 0.0 - size 32 - secondarySize 40 + size 48 + secondarySize 60 chance 0.3 + attenuate 1 } flickerlight DEGORE_X2 { color 1.0 0.8 0.0 - size 40 - secondarySize 48 + size 60 + secondarySize 72 chance 0.3 + attenuate 1 } flickerlight DEGORE_X3 { color 1.0 0.8 0.0 - size 44 - secondarySize 52 + size 66 + secondarySize 78 chance 0.3 + attenuate 1 } flickerlight DEGORE_X4 { color 1.0 0.75 0.0 - size 48 - secondarySize 56 + size 72 + secondarySize 84 chance 0.3 + attenuate 1 } flickerlight DEGORE_X5 { color 1.0 0.7 0.0 - size 52 - secondarySize 60 + size 78 + secondarySize 90 chance 0.3 + attenuate 1 } flickerlight DEGORE_X6 { color 1.0 0.5 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 + attenuate 1 } flickerlight DEGORE_X7 { color 0.5 0.125 0.0 - size 60 - secondarySize 68 + size 90 + secondarySize 102 chance 0.3 + attenuate 1 } flickerlight DEGORE_X8 { color 0.25 0.05 0.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 + attenuate 1 } object DegninOre @@ -747,13 +817,15 @@ object DegninOre pointlight POWCOUP1 { color 0.5 0.5 1.0 - size 24 + size 36 + attenuate 1 } pointlight POWCOUP2 { color 0.7 0.7 1.0 - size 32 + size 48 + attenuate 1 } object PowerCoupling @@ -766,13 +838,15 @@ object PowerCoupling pointlight ENERGY1 { color 0.4 1.0 0.4 - size 16 + size 24 + attenuate 1 } pointlight ENERGY2 { color 0.4 1.0 0.4 - size 32 + size 48 + attenuate 1 } object EnergyPod @@ -793,10 +867,11 @@ object EnergyPack flickerlight2 HUMNDATK { color 1.0 0.8 0.2 - size 48 - secondarySize 56 + size 72 + secondarySize 84 interval 1 offset 0 40 0 + attenuate 1 } object Acolyte @@ -926,64 +1001,71 @@ object StrifePlayer flickerlight2 CTURRETATK1 { color 1.0 0.8 0.2 - size 40 - secondarySize 48 + size 60 + secondarySize 72 interval 1 offset 0 0 0 + attenuate 1 } flickerlight2 CTURRETATK2 { color 1.0 0.8 0.2 - size 48 - secondarySize 56 + size 72 + secondarySize 84 interval 1 offset 0 0 0 + attenuate 1 } flickerlight2 CTURRETDTH1 { color 1.0 1.0 1.0 - size 32 - secondarySize 36 + size 48 + secondarySize 54 interval 1 offset 0 0 0 + attenuate 1 } flickerlight2 CTURRETDTH2 { color 0.9 0.9 0.9 - size 36 - secondarySize 40 + size 54 + secondarySize 60 interval 1 offset 0 0 0 + attenuate 1 } flickerlight2 CTURRETDTH3 { color 0.7 0.7 0.7 - size 42 - secondarySize 46 + size 63 + secondarySize 69 interval 1 offset 0 0 0 + attenuate 1 } flickerlight2 CTURRETDTH4 { color 0.5 0.5 0.5 - size 48 - secondarySize 52 + size 72 + secondarySize 78 interval 1 offset 0 0 0 + attenuate 1 } flickerlight2 CTURRETDTH5 { color 0.3 0.3 0.3 - size 52 - secondarySize 56 + size 78 + secondarySize 84 interval 1 offset 0 0 0 + attenuate 1 } object CeilingTurret @@ -1002,91 +1084,101 @@ object CeilingTurret flickerlight2 STLKATK { color 1.0 0.8 0.2 - size 48 - secondarySize 56 + size 73 + secondarySize 84 interval 1 offset 0 10 0 + attenuate 1 } flickerlight STLKDTH1 { color 0.2 1.0 0.2 - size 32 - secondarySize 36 + size 48 + secondarySize 54 chance 0.3 offset 0 15 0 + attenuate 1 } flickerlight STLKDTH2 { color 0.3 1.0 0.3 - size 36 - secondarySize 40 + size 54 + secondarySize 60 chance 0.3 offset 0 15 0 + attenuate 1 } flickerlight STLKDTH3 { color 0.2 1.0 0.2 - size 40 - secondarySize 48 + size 60 + secondarySize 72 chance 0.3 offset 0 15 0 + attenuate 1 } flickerlight STLKDTH4 { color 0.35 1.0 0.35 - size 44 - secondarySize 52 + size 66 + secondarySize 78 chance 0.3 offset 0 15 0 + attenuate 1 } flickerlight STLKDTH5 { color 0.5 1.0 0.2 - size 40 - secondarySize 44 + size 60 + secondarySize 66 chance 0.3 offset 0 15 0 + attenuate 1 } flickerlight STLKDTH6 { color 1.0 0.2 0.0 - size 32 - secondarySize 40 + size 48 + secondarySize 60 chance 0.3 offset 0 15 0 + attenuate 1 } flickerlight STLKDTH7 { color 0.7 0.3 0.0 - size 40 - secondarySize 48 + size 60 + secondarySize 72 chance 0.3 offset 0 15 0 + attenuate 1 } flickerlight STLKDTH8 { color 0.5 0.15 0.0 - size 36 - secondarySize 44 + size 54 + secondarySize 66 chance 0.3 offset 0 15 0 + attenuate 1 } flickerlight STLKDTH9 { color 0.35 0.05 0.0 - size 32 - secondarySize 36 + size 48 + secondarySize 54 chance 0.3 offset 0 15 0 + attenuate 1 } object Stalker @@ -1110,19 +1202,21 @@ object Stalker flickerlight SNTNLDTH1 { color 1.0 0.4 0.0 - size 24 - secondarySize 36 + size 36 + secondarySize 54 chance 0.3 offset 0 12 0 + attenuate 1 } flickerlight SNTNLDTH2 { color 1.0 0.6 0.0 - size 48 - secondarySize 56 + size 72 + secondarySize 84 chance 0.3 offset 0 12 0 + attenuate 1 } object Sentinel @@ -1134,43 +1228,50 @@ object Sentinel pointlight SNTNL_FX1 { color 1.0 0.0 0.0 - size 16 + size 24 + attenuate 1 } pointlight SNTNL_FX2 { color 0.5 0.0 0.0 - size 16 + size 24 + attenuate 1 } pointlight SNTNL_FX3 { color 1.0 0.0 0.0 - size 18 + size 27 + attenuate 1 } pointlight SNTNL_FX4 { color 0.8 0.0 0.0 - size 20 + size 30 + attenuate 1 } pointlight SNTNL_FX5 { color 0.6 0.0 0.0 - size 22 + size 33 + attenuate 1 } pointlight SNTNL_FX6 { color 0.4 0.0 0.0 - size 24 + size 36 + attenuate 1 } pointlight SNTNL_FX7 { color 0.2 0.0 0.0 - size 28 + size 42 + attenuate 1 } object SentinelFX1 @@ -1201,46 +1302,51 @@ object SentinelFX2 flickerlight CRSDRDTH1 { color 1.0 0.5 0.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 offset 0 80 0 + attenuate 1 } flickerlight CRSDRDTH2 { color 1.0 0.8 0.0 - size 68 - secondarySize 74 + size 102 + secondarySize 111 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight CRSDRDTH3 { color 1.0 0.8 0.0 - size 72 - secondarySize 76 + size 108 + secondarySize 114 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight CRSDRDTH4 { color 1.0 0.9 0.0 - size 76 - secondarySize 80 + size 114 + secondarySize 120 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight CRSDRDTH5 { color 1.0 0.6 0.0 - size 80 - secondarySize 84 + size 120 + secondarySize 126 chance 0.3 offset 0 40 0 + attenuate 1 } object Crusader @@ -1285,64 +1391,71 @@ object CrusaderMissile flickerlight REAV_X1 { color 1.0 0.3 0.0 - size 16 - secondarySize 20 + size 24 + secondarySize 30 chance 0.3 offset 0 16 16 + attenuate 1 } flickerlight REAV_X2 { color 1.0 0.2 0.0 - size 32 - secondarySize 40 + size 48 + secondarySize 60 chance 0.3 offset 0 32 -16 + attenuate 1 } flickerlight REAV_X3 { color 1.0 0.6 0.0 - size 40 - secondarySize 44 + size 60 + secondarySize 66 chance 0.3 offset 0 12 16 + attenuate 1 } flickerlight REAV_X4 { color 1.0 0.5 0.0 - size 20 - secondarySize 24 + size 30 + secondarySize 36 chance 0.3 offset 0 10 0 + attenuate 1 } flickerlight REAV_X5 { color 1.0 0.8 0.0 - size 28 - secondarySize 32 + size 42 + secondarySize 48 chance 0.3 offset 0 18 0 + attenuate 1 } flickerlight REAV_X6 { color 1.0 0.7 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 offset 0 20 0 + attenuate 1 } flickerlight REAV_X7 { color 0.5 0.05 0.0 - size 52 - secondarySize 56 + size 78 + secondarySize 84 chance 0.3 offset 0 20 0 + attenuate 1 } object Reaver @@ -1362,64 +1475,71 @@ object Reaver flickerlight2 TEMPATK { color 0.2 1.0 0.2 - size 48 - secondarySize 56 + size 72 + secondarySize 84 interval 1 offset 20 40 0 + attenuate 1 } flickerlight TEMP_X1 { color 1.0 0.8 0.2 - size 8 - secondarySize 12 + size 12 + secondarySize 18 chance 0.3 offset 0 20 32 + attenuate 1 } flickerlight TEMP_X2 { color 1.0 0.5 0.0 - size 32 - secondarySize 36 + size 48 + secondarySize 54 chance 0.3 offset 0 20 24 + attenuate 1 } flickerlight TEMP_X3 { color 1.0 0.75 0.1 - size 24 - secondarySize 28 + size 36 + secondarySize 42 chance 0.3 offset 0 20 24 + attenuate 1 } flickerlight TEMP_X4 { color 1.0 0.65 0.1 - size 28 - secondarySize 32 + size 42 + secondarySize 48 chance 0.3 offset 0 20 16 + attenuate 1 } flickerlight TEMP_X5 { color 1.0 0.6 0.0 - size 30 - secondarySize 34 + size 45 + secondarySize 51 chance 0.3 offset 0 20 8 + attenuate 1 } flickerlight TEMP_X6 { color 1.0 0.5 0.0 - size 32 - secondarySize 36 + size 48 + secondarySize 54 chance 0.3 offset 0 20 0 + attenuate 1 } object Templar @@ -1438,163 +1558,181 @@ object Templar flickerlight2 INQATK1 { color 1.0 0.6 0.0 - size 88 - secondarySize 96 + size 132 + secondarySize 144 interval 1 offset 20 72 -40 + attenuate 1 } flickerlight2 INQATK2 { color 1.0 0.6 0.0 - size 88 - secondarySize 96 + size 132 + secondarySize 144 interval 1 offset 20 96 0 + attenuate 1 } flickerlight2 INQFLY1 { color 0.5 0.5 1.0 - size 80 - secondarySize 84 + size 120 + secondarySize 126 interval 1 offset -40 36 0 + attenuate 1 } flickerlight2 INQFLY2 { color 0.33 0.33 1.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 interval 1 offset -40 36 0 + attenuate 1 } flickerlight INQDTH1 { color 1.0 0.4 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 offset 0 72 0 + attenuate 1 } flickerlight INQDTH2 { color 1.0 0.7 0.0 - size 84 - secondarySize 96 + size 126 + secondarySize 144 chance 0.3 offset 0 64 0 + attenuate 1 } flickerlight INQDTH3 { color 1.0 0.6 0.0 - size 92 - secondarySize 100 + size 138 + secondarySize 150 chance 0.3 offset 0 56 0 + attenuate 1 } flickerlight INQDTH4 { color 0.7 0.07 0.0 - size 72 - secondarySize 80 + size 108 + secondarySize 120 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight INQDTH5 { color 0.3 0.0 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight INQDTH6 { color 0.5 0.3 0.0 - size 32 - secondarySize 40 + size 48 + secondarySize 60 chance 0.3 offset 0 32 0 + attenuate 1 } flickerlight INQDTH7 { color 1.0 0.6 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 offset 0 32 0 + attenuate 1 } flickerlight INQDTH8 { color 1.0 0.7 0.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 offset 0 32 0 + attenuate 1 } flickerlight INQDTH9 { color 1.0 0.7 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 offset 0 56 0 + attenuate 1 } flickerlight INQDTH10 { color 1.0 0.6 0.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 offset 0 56 0 + attenuate 1 } flickerlight INQDTH11 { color 1.0 0.5 0.0 - size 100 - secondarySize 128 + size 150 + secondarySize 192 chance 0.3 offset 0 32 0 + attenuate 1 } flickerlight INQDTH12 { color 1.0 0.4 0.0 - size 80 - secondarySize 96 + size 120 + secondarySize 144 chance 0.3 offset 0 32 0 + attenuate 1 } flickerlight INQDTH13 { color 1.0 0.3 0.0 - size 60 - secondarySize 72 + size 90 + secondarySize 108 chance 0.3 offset 0 24 0 + attenuate 1 } flickerlight INQDTH14 { color 0.5 0.15 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 offset 0 18 0 + attenuate 1 } object Inquisitor @@ -1630,73 +1768,82 @@ object Inquisitor flickerlight INQSHOT_X1 { color 1.0 0.8 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 + attenuate 1 } flickerlight INQSHOT_X2 { color 1.0 0.7 0.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 + attenuate 1 } flickerlight INQSHOT_X3 { color 0.8 0.45 0.0 - size 72 - secondarySize 80 + size 108 + secondarySize 120 chance 0.3 + attenuate 1 } flickerlight INQSHOT_X4 { color 0.5 0.3 0.0 - size 80 - secondarySize 84 + size 120 + secondarySize 126 chance 0.3 + attenuate 1 } flickerlight INQSHOT_X5 { color 1.0 0.6 0.0 - size 56 - secondarySize 60 + size 84 + secondarySize 90 chance 0.3 + attenuate 1 } flickerlight INQSHOT_X6 { color 1.0 0.7 0.0 - size 60 - secondarySize 64 + size 90 + secondarySize 96 chance 0.3 + attenuate 1 } flickerlight INQSHOT_X7 { color 1.0 0.7 0.0 - size 64 - secondarySize 68 + size 96 + secondarySize 102 chance 0.3 + attenuate 1 } flickerlight INQSHOT_X8 { color 1.0 0.6 0.0 - size 40 - secondarySize 48 + size 60 + secondarySize 72 chance 0.3 + attenuate 1 } flickerlight INQSHOT_X9 { color 1.0 0.4 0.0 - size 24 - secondarySize 32 + size 36 + secondarySize 48 chance 0.3 + attenuate 1 } object InquisitorShot @@ -1716,46 +1863,51 @@ object InquisitorShot flickerlight PROGATK1 { color 0.5 0.5 1.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 offset 0 60 0 + attenuate 1 } flickerlight PROGATK2 { color 0.6 0.6 1.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 offset 0 60 0 + attenuate 1 } flickerlight PROGATK3 { color 0.8 0.8 1.0 - size 80 - secondarySize 96 + size 120 + secondarySize 144 chance 0.3 offset 0 60 0 + attenuate 1 } flickerlight PROGDTH1 { color 1.0 0.4 0.0 - size 112 - secondarySize 128 + size 168 + secondarySize 192 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight PROGDTH2 { color 1.0 0.6 0.0 - size 128 - secondarySize 140 + size 192 + secondarySize 210 chance 0.3 offset 0 40 0 + attenuate 1 } object Programmer @@ -1771,28 +1923,31 @@ object Programmer flickerlight BASE_X1 { color 1.0 0.55 0.0 - size 96 - secondarySize 112 + size 144 + secondarySize 168 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight BASE_X2 { color 1.0 0.50 0.0 - size 80 - secondarySize 96 + size 120 + secondarySize 144 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight BASE_X3 { color 0.5 0.2 0.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 offset 0 32 0 + attenuate 1 } object ProgrammerBase @@ -1806,10 +1961,11 @@ object ProgrammerBase flickerlight BISHOP { color 1.0 1.0 1.0 - size 96 - secondarySize 108 + size 144 + secondarySize 162 chance 0.3 offset 0 120 0 + attenuate 1 } object StrifeBishop @@ -1838,35 +1994,40 @@ object BishopMissile pointlight LIGHT1 { color 1.0 1.0 1.0 - size 56 + size 84 offset 0 30 0 + attenuate 1 } pointlight LIGHT2 { color 1.0 1.0 1.0 - size 40 + size 60 offset 0 72 0 + attenuate 1 } pointlight LIGHT3 { color 1.0 1.0 1.0 - size 64 + size 96 + attenuate 1 } pointlight LIGHT4 { color 1.0 1.0 1.0 - size 64 + size 96 offset 0 80 0 + attenuate 1 } pointlight LIGHT5 { color 1.0 1.0 1.0 - size 56 + size 84 offset 0 72 0 + attenuate 1 } pointlight CLIGHT1 @@ -1874,96 +2035,108 @@ pointlight CLIGHT1 color 1.0 1.0 0.0 size 24 offset 0 12 0 + attenuate 1 } pulselight CLIGHT2 { color 1.0 1.0 0.0 - size 48 - secondarySize 50 + size 72 + secondarySize 75 interval 8.0 offset 0 64 0 + attenuate 1 } pulselight LLIGHT { color 1.0 0.5 0.0 - size 24 - secondarySize 32 + size 42 + secondarySize 54 interval 12.0 offset 0 76 0 + attenuate 1 } pulselight TLLIGHT1 { color 0.9 0.9 1.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 interval 3.0 offset 0 48 0 + attenuate 1 } pointlight TLLIGHT2 { color 1.0 1.0 0.5 - size 80 - offset 0 56 0 + size 120 + offset 0 40 0 + attenuate 1 } flickerlight HTECH { color 0.3 1.0 0.3 - size 96 - secondarySize 104 + size 144 + secondarySize 156 chance 0.5 offset 0 80 0 + attenuate 1 } pulselight BCOLUMN { color 0.5 1.0 0.5 - size 120 - secondarySize 128 + size 180 + secondarySize 192 interval 10.0 offset 0 64 0 + attenuate 1 } pulselight FBUBBLE { color 0.5 1.0 0.5 - size 60 - secondarySize 64 + size 90 + secondarySize 96 interval 10.0 offset 0 32 0 + attenuate 1 } pulselight CBUBBLE { color 0.5 1.0 0.5 - size 60 - secondarySize 64 + size 90 + secondarySize 96 interval 10.0 + attenuate 1 } pointlight SPIDLGHT1 { color 0.5 1.0 0.5 - size 64 + size 96 offset 0 10 0 + attenuate 1 } pointlight SPIDLGHT2 { color 0.2 0.75 0.2 - size 56 + size 84 offset 0 10 0 + attenuate 1 } pointlight SPIDLGHT3 { color 0.0 0.25 0.0 - size 48 + size 72 offset 0 10 0 + attenuate 1 } object LightSilverFluorescent @@ -2052,64 +2225,71 @@ object AlienSpiderLight flickerlight BBARREL { color 1.0 0.6 0.0 - size 32 - secondarySize 40 + size 48 + secondarySize 60 chance 0.8 offset 0 32 0 + attenuate 1 } flickerlight BBOWL { color 1.0 0.7 0.0 - size 24 - secondarySize 32 + size 36 + secondarySize 48 chance 0.5 offset 0 10 0 + attenuate 1 } flickerlight BBRAZIER { color 1.0 0.8 0.0 - size 40 - secondarySize 48 + size 60 + secondarySize 66 chance 0.2 offset 0 32 0 + attenuate 1 } pulselight STORCH { color 1.0 0.6 0.0 - size 28 - secondarySize 32 - interval 5.0 + size 48 + secondarySize 54 + interval 5.0 offset 0 56 0 + attenuate 1 } pulselight MTORCH { color 1.0 0.6 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 interval 5.0 offset 0 64 0 + attenuate 1 } pulselight LTORCH { color 1.0 0.8 0.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 interval 2.0 offset 0 64 0 + attenuate 1 } pulselight HTORCH { color 1.0 0.6 0.0 - size 72 - secondarySize 76 + size 108 + secondarySize 114 interval 3.0 offset 0 72 0 + attenuate 1 } object StrifeBurningBarrel @@ -2226,15 +2406,7 @@ flickerlight POWCRYS_X5 { color 1.0 0.7 0.27 size 114 - secondarySize 113 - chance 0.3 -} - -flickerlight POWCRYS_X6 -{ - color 1.0 0.65 0.24 - size 113 - secondarySize 115 + secondarySize 116 chance 0.3 } @@ -2298,7 +2470,7 @@ flickerlight POWCRYS_X13 { color 1.0 0.48 0.10 size 105 - secondarySize 106 + secondarySize 107 chance 0.3 } @@ -2306,37 +2478,21 @@ flickerlight POWCRYS_X14 { color 1.0 0.46 0.08 size 103 - secondarySize 104 + secondarySize 105 chance 0.3 } flickerlight POWCRYS_X15 { color 1.0 0.44 0.06 - size 102 - secondarySize 104 - chance 0.3 -} - -flickerlight POWCRYS_X16 -{ - color 1.0 0.42 0.04 size 101 secondarySize 103 chance 0.3 } -flickerlight POWCRYS_X15 -{ - color 1.0 0.4 0.02 - size 100 - secondarySize 102 - chance 0.3 -} - flickerlight POWCRYS_X16 { - color 1.0 0.38 0.0 + color 1.0 0.42 0.04 size 99 secondarySize 101 chance 0.3 @@ -2344,7 +2500,7 @@ flickerlight POWCRYS_X16 flickerlight POWCRYS_X17 { - color 1.0 0.36 0.02 + color 1.0 0.40 0.02 size 98 secondarySize 100 chance 0.3 @@ -2352,65 +2508,65 @@ flickerlight POWCRYS_X17 flickerlight POWCRYS_X18 { - color 1.0 0.34 0.0 + color 1.0 0.38 0.0 size 97 - secondarySize 100 + secondarySize 99 chance 0.3 } flickerlight POWCRYS_X19 { - color 1.0 0.32 0.0 + color 1.0 0.36 0.0 size 96 - secondarySize 99 + secondarySize 98 chance 0.3 } flickerlight POWCRYS_X20 { - color 1.0 0.3 0.0 + color 1.0 0.34 0.0 size 95 - secondarySize 98 + secondarySize 97 chance 0.3 } flickerlight POWCRYS_X21 { - color 1.0 0.28 0.0 + color 1.0 0.32 0.0 size 94 - secondarySize 93 + secondarySize 96 chance 0.3 } flickerlight POWCRYS_X22 { - color 1.0 0.26 0.0 + color 1.0 0.3 0.0 size 93 - secondarySize 92 + secondarySize 95 chance 0.3 } flickerlight POWCRYS_X23 { - color 1.0 0.24 0.0 + color 1.0 0.28 0.0 size 92 - secondarySize 91 + secondarySize 94 chance 0.3 } flickerlight POWCRYS_X24 { - color 1.0 0.22 0.0 - size 90 + color 1.0 0.26 0.0 + size 89 secondarySize 92 chance 0.3 } flickerlight POWCRYS_X25 { - color 1.0 0.2 0.0 + color 1.0 0.24 0.0 size 86 - secondarySize 90 + secondarySize 89 chance 0.3 } @@ -2455,10 +2611,11 @@ object PowerCrystal pulselight COMPUTER { color 0.25 1.0 0.25 - size 112 - secondarySize 128 + size 168 + secondarySize 192 interval 0.25 offset 0 64 0 + attenuate 1 } object Computer @@ -2473,76 +2630,85 @@ object Computer flickerlight BARREL_X1 { color 1.0 0.6 0.1 - size 48 - secondarySize 56 + size 72 + secondarySize 84 chance 0.3 + attenuate 1 } flickerlight BARREL_X2 { color 1.0 0.8 0.0 - size 56 - secondarySize 64 + size 84 + secondarySize 96 chance 0.3 + attenuate 1 } flickerlight BARREL_X3 { color 1.0 0.7 0.0 - size 72 - secondarySize 80 + size 108 + secondarySize 120 chance 0.3 + attenuate 1 } flickerlight BARREL_X4 { color 1.0 0.6 0.0 - size 80 - secondarySize 88 + size 120 + secondarySize 132 chance 0.3 + attenuate 1 } flickerlight BARREL_X5 { color 1.0 0.5 0.0 - size 72 - secondarySize 76 + size 108 + secondarySize 114 chance 0.3 + attenuate 1 } flickerlight BARREL_X6 { color 1.0 0.45 0.0 - size 56 - secondarySize 60 + size 84 + secondarySize 90 chance 0.3 + attenuate 1 } flickerlight BARREL_X7 { color 1.0 0.4 0.0 - size 52 - secondarySize 56 + size 78 + secondarySize 84 chance 0.3 offset 0 24 0 + attenuate 1 } flickerlight BARREL_X8 { color 1.0 0.35 0.0 - size 36 - secondarySize 40 + size 54 + secondarySize 60 chance 0.3 offset 0 40 0 + attenuate 1 } flickerlight BARREL_X9 { color 1.0 0.3 0.0 - size 16 - secondarySize 24 + size 24 + secondarySize 36 chance 0.3 offset 0 56 0 + attenuate 1 } object ExplosiveBarrel2 @@ -2562,7 +2728,8 @@ object ExplosiveBarrel2 pointlight KLAXON { color 1.0 0.0 0.0 - size 24 + size 36 + attenuate 1 } object KlaxonWarningLight @@ -2606,49 +2773,55 @@ object FireDroplet flickerlight ZAPBALL1 { color 0.8 0.8 1.0 - size 64 - secondarySize 72 + size 96 + secondarySize 108 chance 0.3 + attenuate 1 } flickerlight ZAPBALL2 { color 0.8 0.8 1.0 - size 128 - secondarySize 144 + size 192 + secondarySize 216 chance 0.5 + attenuate 1 } flickerlight LIGHTNING1 { color 0.8 0.8 1.0 - size 72 - secondarySize 80 + size 108 + secondarySize 120 chance 0.8 + attenuate 1 } flickerlight LIGHTNING2 { color 0.8 0.8 1.0 - size 80 - secondarySize 96 + size 120 + secondarySize 144 chance 0.8 + attenuate 1 } flickerlight LIGHT_SPT { color 0.8 0.8 1.0 - size 24 - secondarySize 32 + size 36 + secondarySize 48 chance 0.8 + attenuate 1 } flickerlight LGNTAIL { color 0.4 0.4 0.5 - size 72 - secondarySize 80 + size 108 + secondarySize 120 chance 0.8 + attenuate 1 } object SpectralLightningBase @@ -2814,43 +2987,49 @@ object SpectralLightningBigV2 pointlight TFOG1 { color 0.5 0.5 0.25 - size 32 + size 48 offset 0 40 0 + attenuate 1 } pointlight TFOG2 { color 0.5 0.5 0.25 - size 40 + size 60 offset 0 40 0 + attenuate 1 } pointlight TFOG3 { color 0.5 0.5 0.25 - size 48 + size 72 offset 0 40 0 + attenuate 1 } pointlight TFOG4 { color 0.5 0.5 0.25 - size 56 + size 84 offset 0 40 0 + attenuate 1 } pointlight TFOG5 { color 0.5 0.5 0.25 - size 64 + size 96 offset 0 40 0 + attenuate 1 } pointlight TFOG6 { color 0.5 0.5 0.25 - size 72 + size 108 offset 0 40 0 + attenuate 1 } object TeleportFog diff --git a/wadsrc_widepix/CMakeLists.txt b/wadsrc_widepix/CMakeLists.txt new file mode 100644 index 00000000000..8151a60d3dc --- /dev/null +++ b/wadsrc_widepix/CMakeLists.txt @@ -0,0 +1 @@ +add_pk3(game_widescreen_gfx.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static) diff --git a/wadsrc_widepix/static/credits.txt b/wadsrc_widepix/static/credits.txt new file mode 100644 index 00000000000..a1ace0888f6 --- /dev/null +++ b/wadsrc_widepix/static/credits.txt @@ -0,0 +1,76 @@ +WidePix v1.3 +------------- + +Made by Nash Muhandes + +(C) 2020 - 2021 Nash Muhandes + +Widescreen (16:9 and 21:9) graphical extensions. + +Supported games: +- Doom +- Heretic +- Hexen +- Strife +- Chex Quest +- Hacx +- Harmony + +Please see license.md for licensing info. + +-------------------------------------------------------------------------------- + +NOTE: +----- + +WidePix was conceived on March 15, 2020, before there was any public knowledge +about the widescreen images that shipped with the September 2020 update of the +Unity port of Doom. + +Differences between WidePix and Doom Unity: + +- Completely built from the ground up (not based off Doom Unity's graphics) +- The original 4:3 portion is left completely unaltered where possible* +- Ultrawide (21:9) aspect ratio support +- Custom animation for Doom 1 Episode 3 +- Weapon sprite extensions (both horizontally/vertically, where applicable) + +* I generally avoid changing the center image as I feel it's important to +preserve the original artwork. However, that said, there are some cases where +alterations were unavoidable because not doing so would've made it impossible +to extend the images. I have documented such cases below: + +TNT INTERPIC: There was a solid-black, 1-pixel border around the image. + +Hexen TITLEPIC and INTERPIC: There were what appeared to be anti-aliasing +artifacts on the left and right borders. + +Strife SS4F3, SS5F1, SS5F3, SS6F2, SS6F3, VELLOGO: Weird artifacts at the +borders made the images impossible to extend. + +Chex Quest WIMAP0: There's a bright 1-pixel-wide sliver to the left. + +CREDITS: +-------- + +id Software: For making Doom. + +Nash Muhandes: For making WidePix. + +Gez: For telling me the exact dimensions needed for the 21:9 graphics, and tips +on how to handle Wadsmoosh. + +Kinsie: For providing the unaltered Doom 1 Registered TITLEPIC. + +Rachael Alexanderson: Github maintenance help. + +------------------------------------------------------------------------------- + +Some high resolution images were used as a source to create the widescreen +extensions. They are listed below. + +Don Ivan Punchatz - Doom 1 cover artwork. + +Gerald Brom - Doom 2 cover artwork. + +Simon "fragglet" Howard: High res versions of the original cover artwork. diff --git a/wadsrc_widepix/static/filter/chex.chex1/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/chex.chex1/graphics/titlepic.lmp new file mode 100644 index 00000000000..cb973d5c080 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex1/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex1/graphics/wimap0.lmp b/wadsrc_widepix/static/filter/chex.chex1/graphics/wimap0.lmp new file mode 100644 index 00000000000..5e11a03a0b2 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex1/graphics/wimap0.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex2/graphics/credit.lmp b/wadsrc_widepix/static/filter/chex.chex2/graphics/credit.lmp new file mode 100644 index 00000000000..0b5f0b7490c Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex2/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex2/graphics/pfub1.lmp b/wadsrc_widepix/static/filter/chex.chex2/graphics/pfub1.lmp new file mode 100644 index 00000000000..0b5f0b7490c Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex2/graphics/pfub1.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex2/graphics/pfub2.lmp b/wadsrc_widepix/static/filter/chex.chex2/graphics/pfub2.lmp new file mode 100644 index 00000000000..0b5f0b7490c Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex2/graphics/pfub2.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex2/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/chex.chex2/graphics/titlepic.lmp new file mode 100644 index 00000000000..16b827c85f3 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex2/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex2/graphics/victory2.lmp b/wadsrc_widepix/static/filter/chex.chex2/graphics/victory2.lmp new file mode 100644 index 00000000000..0b5f0b7490c Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex2/graphics/victory2.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/endpic.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/endpic.lmp new file mode 100644 index 00000000000..cb973d5c080 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/endpic.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/interpic.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/interpic.lmp new file mode 100644 index 00000000000..315e46f6ec1 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/interpic.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/pfub1.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/pfub1.lmp new file mode 100644 index 00000000000..d3a871ed119 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/pfub1.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/pfub2.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/pfub2.lmp new file mode 100644 index 00000000000..05a28a49d6e Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/pfub2.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/titlepic.lmp new file mode 100644 index 00000000000..af4f5ed2a66 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/victory2.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/victory2.lmp new file mode 100644 index 00000000000..16b827c85f3 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/victory2.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap0.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap0.lmp new file mode 100644 index 00000000000..5e11a03a0b2 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap0.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap1.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap1.lmp new file mode 100644 index 00000000000..88737462b1a Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap1.lmp differ diff --git a/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap2.lmp b/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap2.lmp new file mode 100644 index 00000000000..d294e9e9d86 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex.chex3/graphics/wimap2.lmp differ diff --git a/wadsrc_widepix/static/filter/chex/graphics/credit.lmp b/wadsrc_widepix/static/filter/chex/graphics/credit.lmp new file mode 100644 index 00000000000..8bdfb3841dd Binary files /dev/null and b/wadsrc_widepix/static/filter/chex/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/chex/graphics/help1.lmp b/wadsrc_widepix/static/filter/chex/graphics/help1.lmp new file mode 100644 index 00000000000..5134aab81d4 Binary files /dev/null and b/wadsrc_widepix/static/filter/chex/graphics/help1.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom1.registered/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/doom.id.doom1.registered/graphics/titlepic.lmp new file mode 100644 index 00000000000..85290afe43d Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom1.registered/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom1.shareware/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/doom.id.doom1.shareware/graphics/titlepic.lmp new file mode 100644 index 00000000000..bc66b6d5959 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom1.shareware/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/graphics/credit.lmp b/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/graphics/credit.lmp new file mode 100644 index 00000000000..7e2b7fd84a6 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/graphics/titlepic.lmp new file mode 100644 index 00000000000..64ca500e934 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/textures.txt b/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/textures.txt new file mode 100644 index 00000000000..e3df9e54e29 --- /dev/null +++ b/wadsrc_widepix/static/filter/doom.id.doom1.ultimate/textures.txt @@ -0,0 +1,5 @@ +graphic INTERPIC, 560, 200 +{ + patch INTER_E4, 0, 0 { } +} + diff --git a/wadsrc_widepix/static/filter/doom.id.doom1/graphics/credit.lmp b/wadsrc_widepix/static/filter/doom.id.doom1/graphics/credit.lmp new file mode 100644 index 00000000000..cad25112c1e Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom1/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom1/graphics/help1.lmp b/wadsrc_widepix/static/filter/doom.id.doom1/graphics/help1.lmp new file mode 100644 index 00000000000..79940526958 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom1/graphics/help1.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom1/graphics/help2.lmp b/wadsrc_widepix/static/filter/doom.id.doom1/graphics/help2.lmp new file mode 100644 index 00000000000..15057a476e8 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom1/graphics/help2.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom2.plutonia/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/doom.id.doom2.plutonia/graphics/titlepic.lmp new file mode 100644 index 00000000000..efe18b099d2 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom2.plutonia/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom2.plutonia/textures.txt b/wadsrc_widepix/static/filter/doom.id.doom2.plutonia/textures.txt new file mode 100644 index 00000000000..859de2161c7 --- /dev/null +++ b/wadsrc_widepix/static/filter/doom.id.doom2.plutonia/textures.txt @@ -0,0 +1,10 @@ +graphic BOSSBACK, 560, 200 +{ + patch PLUBOSS, 0, 0 { } +} + +graphic INTERPIC, 560, 200 +{ + patch PLUINTER, 0, 0 { } +} + diff --git a/wadsrc_widepix/static/filter/doom.id.doom2.tnt/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/doom.id.doom2.tnt/graphics/titlepic.lmp new file mode 100644 index 00000000000..76f553c669c Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom2.tnt/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom2.tnt/textures.txt b/wadsrc_widepix/static/filter/doom.id.doom2.tnt/textures.txt new file mode 100644 index 00000000000..91ce45d6556 --- /dev/null +++ b/wadsrc_widepix/static/filter/doom.id.doom2.tnt/textures.txt @@ -0,0 +1,10 @@ +graphic BOSSBACK, 560, 200 +{ + patch TNTBOSS, 0, 0 { } +} + +graphic INTERPIC, 560, 200 +{ + patch TNTINTER, 0, 0 { } +} + diff --git a/wadsrc_widepix/static/filter/doom.id.doom2/graphics/credit.lmp b/wadsrc_widepix/static/filter/doom.id.doom2/graphics/credit.lmp new file mode 100644 index 00000000000..c37a81aaa52 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom2/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom2/graphics/help.lmp b/wadsrc_widepix/static/filter/doom.id.doom2/graphics/help.lmp new file mode 100644 index 00000000000..d731765003a Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom2/graphics/help.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom2/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/doom.id.doom2/graphics/titlepic.lmp new file mode 100644 index 00000000000..130afaecf00 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom2/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.doom2/sprites/SHT2E0.lmp b/wadsrc_widepix/static/filter/doom.id.doom2/sprites/SHT2E0.lmp new file mode 100644 index 00000000000..b73a84fcb47 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.doom2/sprites/SHT2E0.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id.wadsmoosh/sprites/SHT2E0.lmp b/wadsrc_widepix/static/filter/doom.id.wadsmoosh/sprites/SHT2E0.lmp new file mode 100644 index 00000000000..b73a84fcb47 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id.wadsmoosh/sprites/SHT2E0.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/bossback.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/bossback.lmp new file mode 100644 index 00000000000..03b69dfd377 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/bossback.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/credit.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/credit.lmp new file mode 100644 index 00000000000..c37a81aaa52 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/endpic.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/endpic.lmp new file mode 100644 index 00000000000..9d5715c5485 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/endpic.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/help.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/help.lmp new file mode 100644 index 00000000000..d731765003a Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/help.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/inter_e4.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/inter_e4.lmp new file mode 100644 index 00000000000..4ec7c50abbc Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/inter_e4.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/interpic.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/interpic.lmp new file mode 100644 index 00000000000..412866c5339 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/interpic.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/pfub1.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/pfub1.lmp new file mode 100644 index 00000000000..d5033db15d1 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/pfub1.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/pfub2.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/pfub2.lmp new file mode 100644 index 00000000000..0d9a346e1cf Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/pfub2.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/pluboss.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/pluboss.lmp new file mode 100644 index 00000000000..aa03f569762 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/pluboss.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/pluinter.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/pluinter.lmp new file mode 100644 index 00000000000..65c594d97d6 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/pluinter.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/tntboss.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/tntboss.lmp new file mode 100644 index 00000000000..a2f0a124319 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/tntboss.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/tntinter.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/tntinter.lmp new file mode 100644 index 00000000000..6f9cc91eba3 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/tntinter.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/victory2.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/victory2.lmp new file mode 100644 index 00000000000..de4c6e34a5a Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/victory2.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20000.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20000.lmp new file mode 100644 index 00000000000..21322a51e18 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20000.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20001.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20001.lmp new file mode 100644 index 00000000000..b63f5c22023 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20001.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20002.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20002.lmp new file mode 100644 index 00000000000..dbde244c8f7 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20002.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20400.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20400.lmp new file mode 100644 index 00000000000..99608a5b9d3 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20400.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20401.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20401.lmp new file mode 100644 index 00000000000..93ff8beb672 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20401.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20402.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20402.lmp new file mode 100644 index 00000000000..124d7185426 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20402.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20500.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20500.lmp new file mode 100644 index 00000000000..b64d9496e4e Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20500.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20501.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20501.lmp new file mode 100644 index 00000000000..7f4fc54f56d Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20501.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wia20502.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wia20502.lmp new file mode 100644 index 00000000000..77a42af76d4 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wia20502.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wimap0.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wimap0.lmp new file mode 100644 index 00000000000..1ea794438d6 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wimap0.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wimap1.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wimap1.lmp new file mode 100644 index 00000000000..470e9e37698 Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wimap1.lmp differ diff --git a/wadsrc_widepix/static/filter/doom.id/graphics/wimap2.lmp b/wadsrc_widepix/static/filter/doom.id/graphics/wimap2.lmp new file mode 100644 index 00000000000..88cf4f6376c Binary files /dev/null and b/wadsrc_widepix/static/filter/doom.id/graphics/wimap2.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/graphics/credit.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/graphics/credit.lmp new file mode 100644 index 00000000000..95a943c89a2 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/graphics/help.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/graphics/help.lmp new file mode 100644 index 00000000000..869984c4253 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/graphics/help.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/graphics/interpic.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/graphics/interpic.lmp new file mode 100644 index 00000000000..3a10c941cf1 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/graphics/interpic.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/graphics/titlepic.lmp new file mode 100644 index 00000000000..8c7df03dbb0 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGA0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGA0.lmp new file mode 100644 index 00000000000..613ea007ea7 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGA0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGB0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGB0.lmp new file mode 100644 index 00000000000..c92cea7919a Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGC0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGC0.lmp new file mode 100644 index 00000000000..41721311357 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGC0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGD0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGD0.lmp new file mode 100644 index 00000000000..52c2550250d Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGD0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGE0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGE0.lmp new file mode 100644 index 00000000000..d7a7fd3c2cc Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGE0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGF0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGF0.lmp new file mode 100644 index 00000000000..3891a78794b Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGF0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGG0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGG0.lmp new file mode 100644 index 00000000000..fa4b2681fdf Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGG0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGH0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGH0.lmp new file mode 100644 index 00000000000..f4395515339 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGH0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGI0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGI0.lmp new file mode 100644 index 00000000000..22d7951085b Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGI0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGJ0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGJ0.lmp new file mode 100644 index 00000000000..783cfceebeb Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/CRYGJ0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFA0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFA0.lmp new file mode 100644 index 00000000000..cb449e6dc79 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFA0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFB0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFB0.lmp new file mode 100644 index 00000000000..8970d3dc275 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFC0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFC0.lmp new file mode 100644 index 00000000000..1d03808a512 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFC0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFD0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFD0.lmp new file mode 100644 index 00000000000..d4aa4a641ac Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISFD0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISGA0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISGA0.lmp new file mode 100644 index 00000000000..52d583d39ae Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISGA0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISGB0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISGB0.lmp new file mode 100644 index 00000000000..9b950cff3d7 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/MISGB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/PISGE0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/PISGE0.lmp new file mode 100644 index 00000000000..6ed3359f5a8 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/PISGE0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/PLSGB0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/PLSGB0.lmp new file mode 100644 index 00000000000..4d932447058 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/PLSGB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2A0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2A0.lmp new file mode 100644 index 00000000000..96c7e629ec5 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2A0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2B0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2B0.lmp new file mode 100644 index 00000000000..9b35238aee7 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2B0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2C0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2C0.lmp new file mode 100644 index 00000000000..06982377acb Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2C0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2D0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2D0.lmp new file mode 100644 index 00000000000..87166cb9672 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2D0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2E0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2E0.lmp new file mode 100644 index 00000000000..2c10e45a9bb Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2E0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2F0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2F0.lmp new file mode 100644 index 00000000000..c305bfb8d4f Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2F0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2G0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2G0.lmp new file mode 100644 index 00000000000..ffb8739782d Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2G0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2H0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2H0.lmp new file mode 100644 index 00000000000..70f39e7e5a2 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2H0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2I0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2I0.lmp new file mode 100644 index 00000000000..a3f6d671e97 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2I0.lmp differ diff --git a/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2J0.lmp b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2J0.lmp new file mode 100644 index 00000000000..3d0f9a69ff1 Binary files /dev/null and b/wadsrc_widepix/static/filter/hacx.hacx1/sprites/SHT2J0.lmp differ diff --git a/wadsrc_widepix/static/filter/harmony/graphics/bossback.lmp b/wadsrc_widepix/static/filter/harmony/graphics/bossback.lmp new file mode 100644 index 00000000000..e9a3f8ebca9 Binary files /dev/null and b/wadsrc_widepix/static/filter/harmony/graphics/bossback.lmp differ diff --git a/wadsrc_widepix/static/filter/harmony/graphics/credit.lmp b/wadsrc_widepix/static/filter/harmony/graphics/credit.lmp new file mode 100644 index 00000000000..a4873f1030d Binary files /dev/null and b/wadsrc_widepix/static/filter/harmony/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/harmony/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/harmony/graphics/titlepic.lmp new file mode 100644 index 00000000000..2f1a36899be Binary files /dev/null and b/wadsrc_widepix/static/filter/harmony/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic.shadow/graphics/title.lmp b/wadsrc_widepix/static/filter/heretic.shadow/graphics/title.lmp new file mode 100644 index 00000000000..89dfe2f80e9 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic.shadow/graphics/title.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/barback.lmp b/wadsrc_widepix/static/filter/heretic/graphics/barback.lmp new file mode 100644 index 00000000000..639c10278c0 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/barback.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/credit.lmp b/wadsrc_widepix/static/filter/heretic/graphics/credit.lmp new file mode 100644 index 00000000000..be1071daa63 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/e2end.png b/wadsrc_widepix/static/filter/heretic/graphics/e2end.png new file mode 100644 index 00000000000..33cd6a25b7a Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/e2end.png differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/final1.lmp b/wadsrc_widepix/static/filter/heretic/graphics/final1.lmp new file mode 100644 index 00000000000..0fd8b2acec6 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/final1.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/final2.lmp b/wadsrc_widepix/static/filter/heretic/graphics/final2.lmp new file mode 100644 index 00000000000..80783e9ed7d Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/final2.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/help1.lmp b/wadsrc_widepix/static/filter/heretic/graphics/help1.lmp new file mode 100644 index 00000000000..f39927173ca Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/help1.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/help2.lmp b/wadsrc_widepix/static/filter/heretic/graphics/help2.lmp new file mode 100644 index 00000000000..6a5efa2251c Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/help2.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/ltfctop.lmp b/wadsrc_widepix/static/filter/heretic/graphics/ltfctop.lmp new file mode 100644 index 00000000000..0fc4ad5dfaa Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/ltfctop.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/mape1.lmp b/wadsrc_widepix/static/filter/heretic/graphics/mape1.lmp new file mode 100644 index 00000000000..e114ff02cf8 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/mape1.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/mape2.lmp b/wadsrc_widepix/static/filter/heretic/graphics/mape2.lmp new file mode 100644 index 00000000000..02e09d58379 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/mape2.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/mape3.lmp b/wadsrc_widepix/static/filter/heretic/graphics/mape3.lmp new file mode 100644 index 00000000000..4a224075f16 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/mape3.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/rtfctop.lmp b/wadsrc_widepix/static/filter/heretic/graphics/rtfctop.lmp new file mode 100644 index 00000000000..78e7be3498d Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/rtfctop.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/graphics/title.lmp b/wadsrc_widepix/static/filter/heretic/graphics/title.lmp new file mode 100644 index 00000000000..5c72e774183 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/graphics/title.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/CRBWA0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/CRBWA0.lmp new file mode 100644 index 00000000000..6881c4e2693 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/CRBWA0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/CRBWB0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/CRBWB0.lmp new file mode 100644 index 00000000000..7a2343ab49c Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/CRBWB0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/CRBWC0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/CRBWC0.lmp new file mode 100644 index 00000000000..a7b7e6454d5 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/CRBWC0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/CRBWD0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/CRBWD0.lmp new file mode 100644 index 00000000000..0863f3a422e Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/CRBWD0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/CRBWE0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/CRBWE0.lmp new file mode 100644 index 00000000000..9c3341efd54 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/CRBWE0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/CRBWF0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/CRBWF0.lmp new file mode 100644 index 00000000000..87520ec71c9 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/CRBWF0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/CRBWG0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/CRBWG0.lmp new file mode 100644 index 00000000000..1439d61712c Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/CRBWG0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/CRBWH0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/CRBWH0.lmp new file mode 100644 index 00000000000..05b29e2ec69 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/CRBWH0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/HRODA0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/HRODA0.lmp new file mode 100644 index 00000000000..4688ba5ce0b Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/HRODA0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/HRODC0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/HRODC0.lmp new file mode 100644 index 00000000000..d9815f65042 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/HRODC0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/HRODD0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/HRODD0.lmp new file mode 100644 index 00000000000..4eba97c24a4 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/HRODD0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/HRODE0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/HRODE0.lmp new file mode 100644 index 00000000000..23fd7f26b06 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/HRODE0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/HRODF0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/HRODF0.lmp new file mode 100644 index 00000000000..969b55b33f1 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/HRODF0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/PHNXA0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/PHNXA0.lmp new file mode 100644 index 00000000000..272b445cdff Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/PHNXA0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/PHNXB0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/PHNXB0.lmp new file mode 100644 index 00000000000..ba8cd6d6de0 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/PHNXB0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/STFFC0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/STFFC0.lmp new file mode 100644 index 00000000000..20ffebef7a3 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/STFFC0.lmp differ diff --git a/wadsrc_widepix/static/filter/heretic/sprites/STFFH0.lmp b/wadsrc_widepix/static/filter/heretic/sprites/STFFH0.lmp new file mode 100644 index 00000000000..378d1b87b83 Binary files /dev/null and b/wadsrc_widepix/static/filter/heretic/sprites/STFFH0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen.deathkings/graphics/credit.lmp b/wadsrc_widepix/static/filter/hexen.deathkings/graphics/credit.lmp new file mode 100644 index 00000000000..27a446ac8d0 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen.deathkings/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen.deathkings/graphics/help1.lmp b/wadsrc_widepix/static/filter/hexen.deathkings/graphics/help1.lmp new file mode 100644 index 00000000000..d28d2c51bb3 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen.deathkings/graphics/help1.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen.deathkings/graphics/help2.lmp b/wadsrc_widepix/static/filter/hexen.deathkings/graphics/help2.lmp new file mode 100644 index 00000000000..d957968fe6c Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen.deathkings/graphics/help2.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen.deathkings/graphics/title.lmp b/wadsrc_widepix/static/filter/hexen.deathkings/graphics/title.lmp new file mode 100644 index 00000000000..02bd6bce038 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen.deathkings/graphics/title.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/credit.lmp b/wadsrc_widepix/static/filter/hexen/graphics/credit.lmp new file mode 100644 index 00000000000..6e860ab0117 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/finale1.lmp b/wadsrc_widepix/static/filter/hexen/graphics/finale1.lmp new file mode 100644 index 00000000000..ad59e666a5b Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/finale1.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/finale2.lmp b/wadsrc_widepix/static/filter/hexen/graphics/finale2.lmp new file mode 100644 index 00000000000..323a38e5a11 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/finale2.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/finale3.lmp b/wadsrc_widepix/static/filter/hexen/graphics/finale3.lmp new file mode 100644 index 00000000000..252f68444f6 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/finale3.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/h2bar.lmp b/wadsrc_widepix/static/filter/hexen/graphics/h2bar.lmp new file mode 100644 index 00000000000..1f3b38a0c86 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/h2bar.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/h2top.lmp b/wadsrc_widepix/static/filter/hexen/graphics/h2top.lmp new file mode 100644 index 00000000000..06b2c25e998 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/h2top.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/help1.lmp b/wadsrc_widepix/static/filter/hexen/graphics/help1.lmp new file mode 100644 index 00000000000..d28d2c51bb3 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/help1.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/help2.lmp b/wadsrc_widepix/static/filter/hexen/graphics/help2.lmp new file mode 100644 index 00000000000..d957968fe6c Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/help2.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/interpic.lmp b/wadsrc_widepix/static/filter/hexen/graphics/interpic.lmp new file mode 100644 index 00000000000..dcdb3d872f8 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/interpic.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/graphics/title.lmp b/wadsrc_widepix/static/filter/hexen/graphics/title.lmp new file mode 100644 index 00000000000..1aec7dfda3f Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/graphics/title.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CFLME0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CFLME0.lmp new file mode 100644 index 00000000000..29cc9a41b2c Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CFLME0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CFLMF0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CFLMF0.lmp new file mode 100644 index 00000000000..9b3dfe1c055 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CFLMF0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CMCEB0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CMCEB0.lmp new file mode 100644 index 00000000000..6389718e455 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CMCEB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CMCEC0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CMCEC0.lmp new file mode 100644 index 00000000000..7ac402de4da Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CMCEC0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CMCED0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CMCED0.lmp new file mode 100644 index 00000000000..41bbd4aeced Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CMCED0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CMCEE0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CMCEE0.lmp new file mode 100644 index 00000000000..3834a6c88e8 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CMCEE0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CONEA0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CONEA0.lmp new file mode 100644 index 00000000000..d9f4eacea69 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CONEA0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CONEB0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CONEB0.lmp new file mode 100644 index 00000000000..d8ad45f5a28 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CONEB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CONEC0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CONEC0.lmp new file mode 100644 index 00000000000..0a36799ce69 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CONEC0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CONED0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CONED0.lmp new file mode 100644 index 00000000000..675c63ddb77 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CONED0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CONEE0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CONEE0.lmp new file mode 100644 index 00000000000..8c5cd2df02a Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CONEE0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CONEF0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CONEF0.lmp new file mode 100644 index 00000000000..3848b559a78 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CONEF0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/CONEG0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/CONEG0.lmp new file mode 100644 index 00000000000..de3784184ac Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/CONEG0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FAXEB0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FAXEB0.lmp new file mode 100644 index 00000000000..ae0835312e3 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FAXEB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FAXEC0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FAXEC0.lmp new file mode 100644 index 00000000000..2087d2cf8c6 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FAXEC0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FAXEN0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FAXEN0.lmp new file mode 100644 index 00000000000..5b3b0d3f2ff Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FAXEN0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FAXEO0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FAXEO0.lmp new file mode 100644 index 00000000000..a656f64a282 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FAXEO0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FHMRB0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FHMRB0.lmp new file mode 100644 index 00000000000..2ab8828cdc7 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FHMRB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FHMRC0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FHMRC0.lmp new file mode 100644 index 00000000000..f18080d73d8 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FHMRC0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FPCHB0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FPCHB0.lmp new file mode 100644 index 00000000000..87142eb0153 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FPCHB0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FPCHC0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FPCHC0.lmp new file mode 100644 index 00000000000..bb1fc2e0eed Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FPCHC0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FPCHD0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FPCHD0.lmp new file mode 100644 index 00000000000..abd1a992eea Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FPCHD0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FPCHE0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FPCHE0.lmp new file mode 100644 index 00000000000..40a626d7cfd Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FPCHE0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FSRDD0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FSRDD0.lmp new file mode 100644 index 00000000000..2bb9bb299ea Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FSRDD0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FSRDE0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FSRDE0.lmp new file mode 100644 index 00000000000..2c272b587e5 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FSRDE0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FSRDH0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FSRDH0.lmp new file mode 100644 index 00000000000..a56f8f70390 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FSRDH0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/FSRDI0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/FSRDI0.lmp new file mode 100644 index 00000000000..e7cd485b2ec Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/FSRDI0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/MLNGG0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/MLNGG0.lmp new file mode 100644 index 00000000000..9b01f8d5d30 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/MLNGG0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/MLNGH0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/MLNGH0.lmp new file mode 100644 index 00000000000..fb1f2ae0d50 Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/MLNGH0.lmp differ diff --git a/wadsrc_widepix/static/filter/hexen/sprites/MLNGI0.lmp b/wadsrc_widepix/static/filter/hexen/sprites/MLNGI0.lmp new file mode 100644 index 00000000000..2d843d127ed Binary files /dev/null and b/wadsrc_widepix/static/filter/hexen/sprites/MLNGI0.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/credit.lmp b/wadsrc_widepix/static/filter/strife/graphics/credit.lmp new file mode 100644 index 00000000000..9cf9f8fff0e Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/credit.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/help0.lmp b/wadsrc_widepix/static/filter/strife/graphics/help0.lmp new file mode 100644 index 00000000000..69af199f0d0 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/help0.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/help1.lmp b/wadsrc_widepix/static/filter/strife/graphics/help1.lmp new file mode 100644 index 00000000000..0f5c4fa48ca Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/help1.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/help2.lmp b/wadsrc_widepix/static/filter/strife/graphics/help2.lmp new file mode 100644 index 00000000000..978cf824759 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/help2.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/help3.lmp b/wadsrc_widepix/static/filter/strife/graphics/help3.lmp new file mode 100644 index 00000000000..a13204e1396 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/help3.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/invback.lmp b/wadsrc_widepix/static/filter/strife/graphics/invback.lmp new file mode 100644 index 00000000000..cb0a7f12f59 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/invback.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/invtop.lmp b/wadsrc_widepix/static/filter/strife/graphics/invtop.lmp new file mode 100644 index 00000000000..9a2095c29de Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/invtop.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/panel0.lmp b/wadsrc_widepix/static/filter/strife/graphics/panel0.lmp new file mode 100644 index 00000000000..94bd40a9573 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/panel0.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/panel1.lmp b/wadsrc_widepix/static/filter/strife/graphics/panel1.lmp new file mode 100644 index 00000000000..d902ffa33a6 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/panel1.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/panel2.lmp b/wadsrc_widepix/static/filter/strife/graphics/panel2.lmp new file mode 100644 index 00000000000..fe9743c8049 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/panel2.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/panel3.lmp b/wadsrc_widepix/static/filter/strife/graphics/panel3.lmp new file mode 100644 index 00000000000..1e28761010f Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/panel3.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/panel4.lmp b/wadsrc_widepix/static/filter/strife/graphics/panel4.lmp new file mode 100644 index 00000000000..d2f7ab23f92 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/panel4.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/panel5.lmp b/wadsrc_widepix/static/filter/strife/graphics/panel5.lmp new file mode 100644 index 00000000000..8affe4cf1d9 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/panel5.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/panel6.lmp b/wadsrc_widepix/static/filter/strife/graphics/panel6.lmp new file mode 100644 index 00000000000..968175e525e Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/panel6.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/panel7.lmp b/wadsrc_widepix/static/filter/strife/graphics/panel7.lmp new file mode 100644 index 00000000000..5e7d5cf8a36 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/panel7.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/rgelogo.lmp b/wadsrc_widepix/static/filter/strife/graphics/rgelogo.lmp new file mode 100644 index 00000000000..666fb766706 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/rgelogo.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss2f1.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss2f1.lmp new file mode 100644 index 00000000000..aa1b4cb53bf Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss2f1.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss2f2.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss2f2.lmp new file mode 100644 index 00000000000..339ae5098be Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss2f2.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss2f3.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss2f3.lmp new file mode 100644 index 00000000000..a12eb8cec2e Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss2f3.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss2f4.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss2f4.lmp new file mode 100644 index 00000000000..84775498a9f Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss2f4.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss3f1.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss3f1.lmp new file mode 100644 index 00000000000..59652567f9b Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss3f1.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss3f2.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss3f2.lmp new file mode 100644 index 00000000000..efdcc26ae58 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss3f2.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss3f3.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss3f3.lmp new file mode 100644 index 00000000000..44b1df69d40 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss3f3.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss3f4.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss3f4.lmp new file mode 100644 index 00000000000..b9e129a6f37 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss3f4.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss4f1.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss4f1.lmp new file mode 100644 index 00000000000..a4708e44a9d Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss4f1.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss4f2.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss4f2.lmp new file mode 100644 index 00000000000..5a8374aaa80 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss4f2.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss4f3.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss4f3.lmp new file mode 100644 index 00000000000..ede711bf0c1 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss4f3.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss4f4.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss4f4.lmp new file mode 100644 index 00000000000..a464d62684b Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss4f4.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss5f1.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss5f1.lmp new file mode 100644 index 00000000000..92b03b7ae8b Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss5f1.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss5f2.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss5f2.lmp new file mode 100644 index 00000000000..7166b74d286 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss5f2.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss5f3.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss5f3.lmp new file mode 100644 index 00000000000..9b7eabf8fb0 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss5f3.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss6f1.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss6f1.lmp new file mode 100644 index 00000000000..e50980f87c0 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss6f1.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss6f2.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss6f2.lmp new file mode 100644 index 00000000000..cf20db05aab Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss6f2.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/ss6f3.lmp b/wadsrc_widepix/static/filter/strife/graphics/ss6f3.lmp new file mode 100644 index 00000000000..7e59d49b8a7 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/ss6f3.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/titlepic.lmp b/wadsrc_widepix/static/filter/strife/graphics/titlepic.lmp new file mode 100644 index 00000000000..fd99edcd1d3 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/titlepic.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/graphics/vellogo.lmp b/wadsrc_widepix/static/filter/strife/graphics/vellogo.lmp new file mode 100644 index 00000000000..deac65cc84a Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/graphics/vellogo.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/sprites/PNCHB0.lmp b/wadsrc_widepix/static/filter/strife/sprites/PNCHB0.lmp new file mode 100644 index 00000000000..6a915911249 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/sprites/PNCHB0.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/sprites/PNCHC0.lmp b/wadsrc_widepix/static/filter/strife/sprites/PNCHC0.lmp new file mode 100644 index 00000000000..481d511b715 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/sprites/PNCHC0.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/sprites/WAVEA0.lmp b/wadsrc_widepix/static/filter/strife/sprites/WAVEA0.lmp new file mode 100644 index 00000000000..288dfa6347e Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/sprites/WAVEA0.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/sprites/WAVEB0.lmp b/wadsrc_widepix/static/filter/strife/sprites/WAVEB0.lmp new file mode 100644 index 00000000000..2da58f7b94f Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/sprites/WAVEB0.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/sprites/WAVEC0.lmp b/wadsrc_widepix/static/filter/strife/sprites/WAVEC0.lmp new file mode 100644 index 00000000000..c915c80f2e3 Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/sprites/WAVEC0.lmp differ diff --git a/wadsrc_widepix/static/filter/strife/sprites/WAVED0.lmp b/wadsrc_widepix/static/filter/strife/sprites/WAVED0.lmp new file mode 100644 index 00000000000..15d5f498f9b Binary files /dev/null and b/wadsrc_widepix/static/filter/strife/sprites/WAVED0.lmp differ diff --git a/wadsrc_widepix/static/license.md b/wadsrc_widepix/static/license.md new file mode 100644 index 00000000000..04b9cedf9b2 --- /dev/null +++ b/wadsrc_widepix/static/license.md @@ -0,0 +1,13 @@ +WidePix + +© 2020 - 2021 Nash Muhandes + +LICENSE: + +You MAY use, copy, modify, merge, publish, distribute, and/or sublicense this work - HOWEVER: + +- You may not sell this work + +- Your work must comply with id Software's original licenses (i.e. they must only work on the game from which they originated) + +- All derivative works must credit the original authors (id Software (Doom), Raven Software (Hexen/Heretic), Rogue Software (Strife), Digital Café (Chex), Nash Muhandes)